commit 52a380120846174213ccce9c4aab0dda17c72083 Author: ejakowatz Date: Tue Jul 9 12:24:59 2002 +0000 It is accomplished ... git-svn-id: file:///srv/svn/repos/haiku/trunk/current@10 a95241bf-73f2-0310-859d-f6bbb57e9c96 diff --git a/Jamfile b/Jamfile new file mode 100644 index 0000000000..00af14db81 --- /dev/null +++ b/Jamfile @@ -0,0 +1,4 @@ +SubDir OBOS_TOP ; + +SubInclude OBOS_TOP sources ; + diff --git a/Jamrules b/Jamrules new file mode 100644 index 0000000000..c1dd7e0762 --- /dev/null +++ b/Jamrules @@ -0,0 +1,735 @@ +# Include BuildConfig +{ + local buildConfig = [ GLOB $(OBOS_TOP) : BuildConfig ] ; + if ! $(buildConfig) + { + EXIT "No BuildConfig!" + "Run ./configure in the source tree's root directory first!" ; + } + include $(buildConfig) ; +} + +# Determine if we're building on PPC or x86 +# Determine mimetype of executable +# Cross compiling can come later + +if $(METROWERKS) { + OBOS_TARGET ?= "ppc.R5" ; + OBOS_TARGET_TYPE ?= "application/x-be-executable" ; + OBOS_ARCH ?= "ppc" ; + OBOS_TARGET_DEFINE ?= "ARCH_ppc" ; +} else { + OBOS_TARGET ?= "x86.R5" ; + OBOS_TARGET_TYPE ?= "application/x-vnd.Be-elfexecutable" ; + OBOS_ARCH ?= "x86" ; + OBOS_TARGET_DEFINE ?= "ARCH_x86" ; + OBOS_TARGET_DIR ?= "x86" ; +} + +KERNEL_CCFLAGS ?= "-Wall -Wno-multichar -Wmissing-prototypes -finline -nostdinc" ; +KERNEL_CCFLAGS += "-fno-builtin -D$(OBOS_TARGET_DEFINE) " ; + +AR = ar r ; +OPTIM = -O2 ; + +# If no OBOS_OBJECT_TARGET is not defined yet, use our default directory and +# include our "OBOS_TARGET" as subdirectory in there (to prevent different +# builds mixing objects from different targets). +if ! $(OBOS_OBJECT_TARGET) { + OBOS_OBJECT_TARGET ?= [ FDirName $(OBOS_TOP) objects $(OBOS_TARGET) ] ; +} + +# If no OBOS_DISTRO_TARGET is not defined yet, use our default directory and +# include our "OBOS_TARGET" as subdirectory in there (to prevent different +# builds mixing executables from different targets). +if ! $(OBOS_DISTRO_TARGET) { + OBOS_DISTRO_TARGET ?= [ FDirName $(OBOS_TOP) distro $(OBOS_TARGET) ] ; +} + +# Set our version number if not already set and mark it as a developer build +if ! $(OBOS_BUILD_VERSION) { + OBOS_BUILD_VERSION ?= "1 0 0 a 1" ; + OBOS_BUILD_DESCRIPTION ?= "Developer Build" ; +} + +# If OBOS_BUILD_VERSION is set, but OBOS_BUILD_DESCRIPTION isn't, mark it as +# an unknown build. +if ! $(OBOS_BUILD_DESCRIPTION) { + OBOS_BUILD_DESCRIPTION ?= "Unknown Build" ; +} + +# Relative subdirs for distro dir (these are for *INTERNAL* use by the following rules only!) +OBOS_PREFS_DIR ?= [ FDirName $(OBOS_DISTRO_TARGET) beos preferences ] ; +OBOS_SERVER_DIR ?= [ FDirName $(OBOS_DISTRO_TARGET) beos system servers ] ; +OBOS_ADDON_DIR ?= [ FDirName $(OBOS_DISTRO_TARGET) beos system add-ons ] ; +OBOS_SHLIB_DIR ?= [ FDirName $(OBOS_DISTRO_TARGET) beos system lib ] ; +OBOS_STLIB_DIR ?= [ FDirName $(OBOS_DISTRO_TARGET) beos system lib ] ; +OBOS_KERNEL_DIR ?= [ FDirName $(OBOS_DISTRO_TARGET) beos system ] ; +OBOS_TEST_DIR ?= [ FDirName $(OBOS_TOP) tests ] ; + +OBOS_KERNEL_CONFIG = config.$(OBOS_ARCH).ini ; +OBOS_KERNEL = kernel.$(OBOS_ARCH) ; +OBOS_FLOPPY = floppy.$(OBOS_ARCH) ; + +rule SetupIncludes +{ + OBOS_INCLUDES ?= . add-ons app be_apps device drivers game interface kernel mail media midi midi2 net opengl storage support translation ; + UsePublicHeaders $(OBOS_INCLUDES) ; +} + +#------------------------------------------------------------------------------- +# Things Jam needs in order to work :) +#------------------------------------------------------------------------------- + +rule UserObject +{ + switch $(2) + { + case *.S : assemble $(1) : $(2) ; + case * : ECHO "unknown suffix on" $(2) ; + } +} + +# Override the default to give "prettier" command lines. +actions Cc +{ + $(CC) -c $(2) $(CCFLAGS) $(CCDEFS) $(CCHDRS) -o $(1) ; +} + +actions C++ +{ + $(C++) -c $(2) $(C++FLAGS) $(CCDEFS) $(CCHDRS) -o $(1) ; +} + + +#------------------------------------------------------------------------------- +# General High-level OBOS target rules +#------------------------------------------------------------------------------- + +rule Preference +{ + # Preference : ; +# SetupIncludes ; + SetupObjectsDir ; + Main $(<) : $(>) ; + MakeLocate $(<) : $(OBOS_PREFS_DIR) ; +} + +rule Server +{ + # Server : ; + + SetupIncludes ; + SetupObjectsDir ; + Main $(<) : $(>) ; + MakeLocate $(<) : $(OBOS_SERVER_DIR) ; +} + +# test pseudo targets +NOTFILE obostests ; +NOTFILE r5tests ; + +rule CommonUnitTest +{ + # CommonUnitTest : : : + # : : ; + # Builds a unit test for both OBOS and R5 modules. + # The name of the target. + # The list of sources. + # The directory for the target (as passed to FDirName). + # A list of link libraries for the OBOS tests (as passed + # to LinkSharedOSLibs). + # A list of link libraries for the R5 tests (as passed + # to LinkSharedOSLibs). + # A list of public header dirs (as passed to + # UsePublicHeaders). + + UnitTest $(1) : $(2) : $(3) : $(4) : $(6) ; + R5UnitTest $(1) : $(2) : $(3) : $(5) ; +} + +rule UnitTest +{ + # UnitTest : : : : + # Builds a unit test for an OBOS module. + # The name of the target. + # The list of sources. + # The directory for the target (as passed to FDirName). + # A list of link libraries (as passed to LinkSharedOSLibs). + # A list of public header dirs (as passed to + # UsePublicHeaders). + + local target = $(1) ; + local sources = $(2) ; + local dest = $(3) ; + local libraries = $(4) ; + local headerDirs = $(5) ; + +# SetupIncludes ; + UseCppUnitHeaders ; + SetupObjectsDir ; + MakeLocateObjects $(sources) ; + Main $(target) : $(sources) ; + MakeLocate $(target) : [ FDirName $(OBOS_TEST_DIR) $(dest) ] ; + DEPENDS $(target) : libcppunit.so ; + DEPENDS obostests : $(target) ; + LinkSharedOSLibs $(target) : libcppunit.so $(libraries) ; + UsePublicHeaders $(headerDirs) : $(sources) ; + ObjectDefines $(sources) : TEST_OBOS ; + + # Turn debugging on. That is usually desired for test code. + ObjectCcFlags $(sources) : "-g" ; + ObjectC++Flags $(sources) : "-g" ; +} + +rule R5UnitTest +{ + # R5UnitTest : : : + # Builds a unit test for an R5 module. "_r5" is appended to the object + # and the target name. + # The name of the target. + # The list of sources. + # The directory for the target (as passed to FDirName). + # A list of link libraries (as passed to LinkSharedOSLibs). + + local target = $(1)_r5 ; + local sources = $(2) ; + local dest = $(3) ; + local libraries = $(4) ; + local objects = [ R5ObjectNames $(sources) ] ; + + UseCppUnitHeaders ; + SetupObjectsDir ; + MakeLocateObjects $(objects) ; + + # Our Main replacement. + MainFromObjects $(target) : $(objects) ; + local source ; + for source in [ FGristFiles $(sources) ] + { + local object = [ R5ObjectNames $(source) ] ; + Object $(object) : $(source) ; + Depends obj : $(object) ; + } + + MakeLocate $(target) : [ FDirName $(OBOS_TEST_DIR) $(dest) ] ; + DEPENDS $(target) : libcppunit.so ; + DEPENDS r5tests : $(target) ; + LinkSharedOSLibs $(target) : libcppunit.so $(libraries) ; + ObjectDefines $(objects) : TEST_R5 ; + + # Turn debugging on. That is usually desired for test code. + ObjectCcFlags $(objects) : "-g" ; + ObjectC++Flags $(objects) : "-g" ; +} + +rule R5ObjectNames +{ + # R5ObjectNames ; + # Returns a list of gristed object names given a list of source file names. + # Moreover each object names gets "_r5" inserted before the object suffix. + local objects = $(1:S=)_r5 ; + return [ FGristFiles $(objects:S=$(SUFOBJ)) ] ; +} + +rule Addon +{ + # Addon : : ; + + SetupIncludes ; + SetupObjectsDir ; + Main $(1) : $(3) ; + + # Create output dir path for addon + local targetdir; + targetdir = [ FDirName $(OBOS_ADDON_DIR) $(2) ] ; + + MakeLocate $(1) : $(targetdir) ; + LINKFLAGS on $(1) = $(LINKFLAGS) -nostart -Xlinker -soname=\"$(1)\" ; +} + +rule MakeLocateObjects +{ + # MakeLocateObjects ; + + local _objs = $(1:S=$(SUFOBJ)) ; + + for o in $(_objs) + { + local dir = $(o:D) ; + if $(dir) { + MakeLocate $(o) : [ FDirName $(LOCATE_TARGET) $(dir) ] ; + } else { + MakeLocate $(o) : $(LOCATE_TARGET) ; + } + } +} + +rule StaticLibrary +{ + # StaticLibrary : ; + + SetupIncludes ; + SetupObjectsDir ; + MakeLocateObjects $(2) ; + Library lib$(<).a : $(>) ; + MakeLocate lib$(<).a : $(OBOS_STLIB_DIR) ; +} + +rule SharedLibrary +{ + # SharedLibrary : ; + local _lib = lib$(1).so ; + +# SetupIncludes ; + SetupObjectsDir ; + MakeLocateObjects $(2) ; + Main $(_lib) : $(2) ; + MakeLocate $(_lib) : $(OBOS_SHLIB_DIR) ; + LINKFLAGS on $(_lib) = $(LINKFLAGS) -nostart -Xlinker -soname=\"$(_lib)\" ; +} + +rule LinkSharedOSLibs +{ + # LinkSharedOSLibs : ; + # Valid elements for are e.g. "be" or "libopenbeos.so" or + # "/boot/.../libfoo.so". If the basename starts with "lib", it is added + # to the NEEDLIBS variable (i.e. the file will be bound!), otherwise it is + # prefixed "-l" and added to LINKLIBS. + + for i in $(>) + { + switch $(i:B) + { + case lib* : NEEDLIBS on $(1) += $(i) ; DEPENDS $(1) : $(i) ; + case * : LINKLIBS on $(1) += -l$(i) ; + } + } +} + +rule LinkStaticOSLibs +{ + # LinkStaticOSLibs : ; + + for i in $(>) + { + LINKLIBS on $(<) = $(LINKLIBS) -l $(i) ; + } +} + +rule AddResources +{ + # AddResources : ; + + local dir; + + dir = [ FDirName $(OBOS_TOP) $(SUBDIR_TOKENS) ] ; + + for i in $(>) + { + RESFILES on $(<) = [ FDirName $(dir) $(i) ] ; + DEPENDS $(<) : [ FDirName $(dir) $(i) ] ; + } +} + +rule UsePublicHeaders +{ + # UsePublicHeaders [ ] ; + # + # Adds the public C header dirs given by to the header search + # dirs of the subdirectory or of , if given. + # NOTE: Currently the latter doesn't work, since Cc seems to be + # buggy: It sets the HDRS variable to $(SUBDIRHDRS) instead of adding it. + + local list = $(1) ; + local targets = $(2) ; + + local headers ; + + for i in $(list) { + headers += [ FDirName $(OBOS_TOP) headers obos public $(i) ] ; + } + + UseHeaders $(headers) : $(targets) ; +} + +rule UsePrivateHeaders +{ + # UsePrivateHeaders [ ] ; + # + # Adds the private C header dirs given by to the header search + # dirs of the subdirectory or of , if given. + # NOTE: Currently the latter doesn't work, since Cc seems to be + # buggy: It sets the HDRS variable to $(SUBDIRHDRS) instead of adding it. + + local list = $(1) ; + local targets = $(2) ; + + local headers ; + + for i in $(list) { + headers += [ FDirName $(OBOS_TOP) headers obos private $(i) ] ; + } + + UseHeaders $(headers) : $(targets) ; +} + +rule UseHeaders +{ + # UseHeaders [ ] ; + # + # Adds the C header dirs to the header search + # dirs of the subdirectory or of , if given. + # NOTE: Currently the latter doesn't work, since Cc seems to be + # buggy: It sets the HDRS variable to $(SUBDIRHDRS) instead of adding it. + + local headers = $(1) ; + local targets = $(2) ; + + if $(targets) { + ObjectHdrs $(targets) : $(headers) ; + } else { + # Note: Unlike ObjectHdrs SubDirHdrs expects only one dir given as + # path component list. + for header in $(headers) { + SubDirHdrs $(header) ; + } + } +} + +rule UseCppUnitHeaders +{ + local opt = -I [ FDirName $(OBOS_TOP) headers tools cppunit ] ; + + SubDirCcFlags $(opt) ; + SubDirC++Flags $(opt) ; +} + +rule UseArchHeaders +{ + # usage: UseArchHeaders + # specifies the architecture (e.g. x86). + local opt = -D$(OBOS_TARGET_DEFINE) ; + SubDirCcFlags $(opt) ; + SubDirC++Flags $(opt) ; + SubDirHdrs [ FDirName $(OBOS_TOP) headers obos private kernel arch $(1) ] ; +} + +#------------------------------------------------------------------------------- +# Low-level OBOS utility rules +#------------------------------------------------------------------------------- +rule SetupObjectsDir +{ + local rel_objectsdir; + + # Copy subdir tokens except the first, as that will be "sources", and we + # do not want to include that :) + rel_objectsdir = [ FDirName $(SUBDIR_TOKENS[2-]) ] ; + LOCATE_TARGET = [ FDirName $(OBOS_OBJECT_TARGET) $(rel_objectsdir) ] ; +} + +#------------------------------------------------------------------------------- +# Link rule/action are overwritten as they don't handle linking files who's name +# contain spaces very well. Also adds resources and version to executable. +#------------------------------------------------------------------------------- +rule Link +{ + # Note: RESFILES must be set before invocation. + MODE on $(<) = $(EXEMODE) ; + on $(1) XRes $(1) : $(RESFILES) ; + SetVersion $(1) ; + Chmod $(<) ; + SetType $(1) ; + MimeSet $(1) ; +} + +actions Link bind NEEDLIBS +{ + $(LINK) $(LINKFLAGS) -o "$(1)" $(UNDEFS) $(2) $(NEEDLIBS) $(LINKLIBS) ; +} + +# BeOS specific rules + +rule XRes +{ + # XRes : + if $(2) + { + DEPENDS $(1) : $(2) ; + XRes1 $(1) : $(2) ; + } +} + +rule XRes1 { } + +rule SetVersion +{ + # SetVersion +} + +rule SetType +{ + # SetType +} + +rule MimeSet +{ + # SetType +} + + +if $(OS) = BEOS +{ + +actions XRes1 +{ + xres -o "$(1)" $(2) ; +} + +actions SetVersion +{ + setversion "$(1)" -system $(OBOS_BUILD_VERSION) -short "$(OBOS_BUILD_DESCRIPTION)" ; +} + +actions SetType +{ + settype -t $(OBOS_TARGET_TYPE) "$(1)" ; +} + +actions MimeSet +{ + mimeset -f "$(1)" ; +} + +} # if BEOS + + +rule assemble +{ + DEPENDS $(1) : $(2) ; + Clean clean : $(1) ; +} + +actions assemble +{ +$(CC) -c $(2) -O2 $(KERNEL_CCFLAGS) -o $(1) ; +} + +## Kernel stuff! + +rule SetupKernel +{ + # Usage SetupKernel : ; + + local _objs = $(1:S=$(SUFOBJ)) ; + + UsePublicHeaders kernel ; + UsePrivateHeaders kernel ; + UseArchHeaders $(OBOS_ARCH) ; + + SetupObjectsDir ; + + CCFLAGS on $(_objs) = $(KERNEL_CCFLAGS) $(2) ; + C++FLAGS on $(_objs) = $(KERNEL_CCFLAGS) $(2) ; +} + +rule KernelObjects +{ + SetupKernel $(1) : $(2) ; + + Objects $(1) ; +} + +rule KernelLd +{ + # KernelLd : : : : ; + + SetupKernel $(2) ; + LINK on $(1) = ld ; + + LINKFLAGS on $(1) = $(4) ; + if $(3) { LINKFLAGS on $(1) += --script=$(3) ; } + + # Remove any preset LINKLIBS + LINKLIBS on $(1) = ; + + # Show that we depend on the libraries we need + Clean clean : $(1) ; + Depends all : $(1) ; + Depends $(1) : $(2) ; + + if $(6) { + Depends $(OBOS_KERNEL_CONFIG) : $(1) ; + for i in $(6) { + SECTIONS on $(OBOS_KERNEL_CONFIG) += ":" $(i) elf32 [ FDirName $(LOCATE_TARGET) $(1) ] ; + } + } + + MakeLocate $(1) : $(LOCATE_TARGET) ; + + # Add libgcc.a - NB this should be detected not hard coded! + if ! $(5) { + LINKLIBS on $(1) += "-L $(GCC_PATH) -lgcc" ; + } +} + +actions KernelLd +{ +$(LINK) $(LINKFLAGS) -o $(1) $(2) $(LINKLIBS) ; +} + +rule KernelStaticLibrary +{ + # Usage KernelStaticLibrary : : ; + # This is designed to take a set of sources and libraries and create + # a file called lib.a + + SetupKernel $(2) : $(3) ; + + MakeLocateObjects $(2) ; + Library $(1) : $(2) ; +} + +rule KernelStaticLibraryObjects +{ + # Usage KernelStaticLibrary : ; + # This is designed to take a set of sources and libraries and create + # a file called + + SetupKernel $(2) ; + + # Show that we depend on the libraries we need + Clean clean : $(1) ; + Depends all : $(1) ; + Depends $(1) : $(2) ; + + MakeLocate $(1) : $(LOCATE_TARGET) ; +} + +actions KernelStaticLibraryObjects +{ +ar -r $(1) $(2) ; +} + +rule SystemMain +{ + # Usage SystemMain : : ; + SetupObjectsDir ; + + CCFLAGS on $(1) = $(OPTIM) ; + C++FLAGS on $(1) = $(OPTIM) ; + LINKLIBS = ; + + # This allows us to preset certain commands we use + # for building. + if $(3) { + for obj in $(3) { + BUILD_CMD on $(obj) = [ FDirName $(LOCATE_TARGET) $(1) ] ; + } + } + + Main $(1) : $(2) ; +} + +rule KernelConfigSection +{ + # KernelConfigSection
: : ; + SECTIONS on $(OBOS_KERNEL_CONFIG) += ":" $(1) $(2) $(3) ; +} + +rule WriteKernelConfig +{ + # usage: WriteKernelConfig ; + + Depends files : $(1) ; + + LOCATE on $(1) = $(LOCATE_TARGET) ; + + MakeLocate $(1) : $(LOCATE_TARGET) ; + + Clean clean : $(1) ; +} + +actions WriteKernelConfig +{ + target=$(1) + echo "# OpenBeOS Kernel Config File" > $target + echo "# Automatically generated - do not edit!" >> $target + issection="0" + section= + for i in "$(SECTIONS)" ; do + if [ $issection == 1 ]; then + section=$i + issection=2 + echo "["$section"]" >> $target + elif [ $issection == 2 ]; then + type=$i + issection=3 + echo "type="$type >> $target + else + if [ $i == ":" ]; then + issection=1 + echo "" >> $target + else + file=$i + case $file in + /*) ;; + *) file=`pwd`/$file;; + esac + echo "file="$file >> $target + fi + fi + done +} + +rule BuildKernel +{ + # Usage BuildKernel : ; + + Depends all : $(1) ; + Depends $(1) : $(2) ; + Clean clean : $(1) ; + + MakeLocate $(1) : $(LOCATE_TARGET) ; +} + +actions BuildKernel +{ + $(BUILD_CMD) --strip-debug --strip-binary strip $(2) -o $(1) ; + echo "" + echo "Kernel linked!" + echo "" +} + +# At present I don't bother moving the final location for +# the floppy image as it makes copying it onto a floppy easier if it's +# where you did the build. This is easy enough changed. +rule KernelFloppyImage +{ + # Usage KernelFloppyImage : : ; + + Depends all : $(1) ; + Depends $(1) : $(2) ; + Clean clean : $(1) ; + + BOOT_BLOCK on $(1) = $(3) ; +} + +# This may be a bit verbose, but I think it's useful to show what's +# going on, at least in this early stage of development. +actions KernelFloppyImage +{ + $(BUILD_CMD) $(BOOT_BLOCK) $(2) $(1) ; + echo "" + echo "*************************************************" + echo "* Kernel build completed! *" + echo "* Boot image for a 1.44M floppy created *" + echo "*************************************************" + echo "" + echo "Floppy image is $(OBOS_FLOPPY)" + echo "The following command will write it to a floppy on BeOS" + echo " dd if=$(OBOS_FLOPPY) of=/dev/disk/floppy/raw bs=18k" + echo "" +} + + diff --git a/ReadMe b/ReadMe new file mode 100644 index 0000000000..704a170cf3 --- /dev/null +++ b/ReadMe @@ -0,0 +1,102 @@ +Building +-------- + +The build system uses Jam/MR (http://www.perforce.com/jam/jam.html). +A BeOS executable of Jam 2.3.1 is available at: + + http://open-beos.sf.net/misc/jam.zip + +Unzip the executable and copy it to /boot/home/config/bin. + +To build the whole source tree, launch a Terminal, cd into the openbeos root +directory and just type: + + $ ./configure + $ jam + +The configure script generates a file named BuildConfig. As long as configure +is not modified (!), there is no need to call it again. That is for +re-building you only need to invoke Jam. If you don't update the source tree +very frequently, you may want to execute configure after each update just to +be on the safe side. + +NOTE: If you have checked out the latest CVS version, it is not unlikely that +some parts of the tree won't build. + + +Running +------- + +If the build went fine, a file named floppy.x86 had been created in the +root directory of the source tree. What you want to do now, is to boot from +this floppy image. Therefore you either write the image onto a real floppy +disk and restart you computer, or you write it onto a "virtual floppy disk" +emulated by a x86 PC emulator and just start this emulator. + +1. Real Floppy + +Put in the disk and type in the source tree's root dir: + + $ dd if=floppy.x86 of=/dev/disk/floppy/raw bs=18k + + +2. Emulated Floppy (Bochs) + +Type: + + $ dd if=floppy.x86 of= bs=18k + +where has to be replaced with the filename of the floppy +image Bochs has been told to use (e.g. /tmp/obos.img). + + +Bochs +----- + +Version 1.4 of Bochs for BeOS (BeBochs) can be downloaded from BeBits: + + http://www.bebits.com/app/2902 + +The package installs to: /boot/apps/BeBochs1.4 + +You have to set up a configuration for Bochs. A relatively short and +painless procedure follows: + +Lauch a Terminal: + + $ cd /tmp + $ /boot/apps/BeBochs1.4/bximage + +Answer with "fd", RETURN (for 1.44) and "obos.img", and a floppy image +/tmp/obos.img will be created. +Open folder /boot/apps/BeBochs1.4 and backup .bochsrc. Open .bochsrc with +your favorite text editor, remove the complete contents and paste the +following instead (you may as well take the original file and insert/replace/ +keep the respective lines): + +romimage: file=bios/BIOS-bochs-latest, address=0xf0000 +megs: 32 +vgaromimage: bios/VGABIOS-elpin-2.40 +floppya: 1_44=/tmp/obos.img, status=inserted +boot: a +log: /var/log/bochs-obos.log +panic: action=ask +error: action=report +info: action=report +debug: action=ignore +vga_update_interval: 300000 +keyboard_serial_delay: 250 +keyboard_paste_delay: 100000 +floppy_command_delay: 500 +ips: 2000000 + +Now put the OBOS boot image onto you "virtual" floppy and start Bochs: + + $ cd + $ dd if=floppy.x86 of=/tmp/obos.img bs=18k + $ cd /boot/apps/BeBochs1.4 + $ ./bochs + +Answer three times with RETURN and with some patience you will see OBOS +booting. + diff --git a/configure b/configure new file mode 100755 index 0000000000..4e606a1711 --- /dev/null +++ b/configure @@ -0,0 +1,37 @@ +#!/bin/sh +# +# configure +# +# No parameters for now. + +platform=`uname` + +# BeOS +if [ "${platform}" == "BeOS" ] ; then + # GGC_PATH + if [ "x${GCC_PATH}" == "x" ] ; then + gcclib=`gcc -print-libgcc-file-name` + GCC_PATH=`dirname ${gcclib}` + fi + +# Linux +else if [ "${platform}" == "Linux" ] ; then + # GGC_PATH + if [ "x${GCC_PATH}" == "x" ] ; then + gcclib=`gcc -print-libgcc-file-name` + GCC_PATH=`dirname ${gcclib}` + fi + +# Unknown platform +else + echo Unsupported platform: ${platform} + exit 1 +fi; fi + +# Generate BuildConfig +cat << EOF > BuildConfig +# BuildConfig +# Note: This file has been automatically generated by configure. + +GCC_PATH = ${GCC_PATH} ; +EOF diff --git a/docs/develop/app/usecases/BMessageQueueUseCases.html b/docs/develop/app/usecases/BMessageQueueUseCases.html new file mode 100644 index 0000000000..11a8f8d93b --- /dev/null +++ b/docs/develop/app/usecases/BMessageQueueUseCases.html @@ -0,0 +1,147 @@ + + + +BMessageQueue Use Cases and Implementation Details + + + + + + +

BMessageQueue Use Cases and Implementation Details:

+ +

This document describes the BMessageQueue interface and some basics of how it is implemented. +The document has the following sections:

+ +
    +
  1. BMessageQueue Interface
  2. +
  3. BMessageQueue Use Cases
  4. +
  5. BMessageQueue Implementation
  6. +
+ +

BMessageQueue Interface:

+ +

The BMessageQueue class is a simple class for managing a queue of BMessages. The best +source of information for the BMessageQueue interface can be found +here in the Be Book. +

+ +

BMessageQueue Use Cases:

+ +

The following use cases cover the BMessageQueue functionality:

+ +
    +
  1. Construction: A BMessageQueue does not take any arguments when it is constructed. +After construction, the queue is empty.

  2. + +
  3. Destruction: When a BMessageQueue is deconstructed, all BMessages on the queue are +deleted. This implies that all BMessages added to a BMessageQueue must be allocated on the heap +with the new operation. The BMessageQueue is locked before performing the delete to ensure +that the queue doesn't change while it is being deleted. The lock is never released from the +destructor to ensure that any AddMessage() or other members blocking for the lock never +succeed in getting the lock. They will fail once the BMessageQueue is completely deleted.

  4. + +
  5. Add Message 1: When AddMessage() is used to put a BMessage on the queue, the +BMessageQueue takes ownership of the BMessage. The BMessage should be created on the heap but +there is no checking to ensure that has happened. The BMessageQueue records the order in +which the BMessages are added to the queue.

  6. + +
  7. Add Message 2: No check is performed to see if the BMessage is already part of that +BMessageQueue or any other when AddMessage() is used to put a BMessage on a queue. An attempt to +add a BMessage to a BMessageQueue which already has that same BMessage in it (where equality is +based on the address of the BMessage) will corrupt the queue. An attempt to add a BMessage to a +BMessageQueue when that BMessage is already in another BMessageQueue will corrupt the original +BMessageQueue. It is up to the caller of AddMessage() to use RemoveMessage() to prevent +queue corruption.

  8. + +
  9. Add Message 3: BMessage's can be added using AddMessage() from multiple threads +at the same time with no risk of queue corruption. Similarly, RemoveMessage() or NextMessage() +can be executing from another thread while an AddMessage() is started without corrupting the queue. +An AddMessage() attempt will block if another thread has used the Lock() member to lock the +BMessageQueue.

  10. + +
  11. Remove Message 1: The RemoveMessage() member takes a BMessage pointer. The +BMessageQueue is searched for this BMessage pointer. If that pointer is in the queue, then it +is removed from the queue. The BMessage is not deleted (note the BeBook implies it is but in +fact it is not). If the BMessage pointer is not on this BMessageQueue, this call has no affect. +After this call completes successfully, it is as though AddMessage() was never called for +this BMessage pointer.

  12. + +
  13. Remove Message 2: BMessage's can be removed using RemoveMessage() from multiple +threads at the same time with no risk of queue corruption. Similarly, AddMessage() or +NextMessage() can be executing from another thread while a RemoveMessage() is started without +corrupting the queue. A RemoveMessage() attempt will block if another thread has used the Lock() +member to lock the BMessageQueue.

  14. + +
  15. Count Messages: The CountMessages() member function returns the number of BMessage's +in the BMessageQueue. If there are no messages on the queue (an example of this situation is just +after construction), the member returns 0. Note, it is possible for the count to become corrupted +if the situation in Add Message 2 occurs.

  16. + +
  17. Is Empty: The IsEmpty() member function returns true if there are no BMessages on the +BMessageQueue. If there are one or more BMessages on the BMessageQueue, it returns false.

  18. + +
  19. Find Message 1: The FindMessage() member function is overloaded. If the member +function takes a single int32 argument, it is used to return the BMessage on the queue at a +particular index as indicated by the argument. The first message is at index 0, the second +at index 1 etc. If no message is at that index, NULL is returned.

  20. + +
  21. Find Message 2: The other FindMessage() member function takes a single uint32 +argument and an optional int32 argument. The first mandatory argument specifies the "what" code +for the BMessage being searched for. The second optional argument specifies what occurance of +that "what" code in a BMessage on the queue should be returned. If the second argument is not +provided, it is assumed to be 0. If the second argument is 0, the first BMessage that has the +what code provided is returned. If the second argument is 1, the second BMessage that has the +what code provided is returned, etc. If no match is found, NULL is returned.

  22. + +
  23. Lock 1: The Lock() member function blocks until this thread can acquire exclusive +access to the BMessageQueue. Only one thread can hold the lock at any one time. A thread can +acquire the Lock() multiple times but release it the same number of times. While a thread holds +the lock, other threads will not be able to perform AddMessage(), RemoveMessage() or NextMessage(). +Any threads attempting to do so will block until the BMessageQueue is unlocked.

  24. + +
  25. Lock 2: The Lock() member function returns true if the lock has successfully been +acquired. It will return false if an unrecoverable error has occurred. An example of such an +error would be deleting the BMessageQueue.

  26. + +
  27. Unlock: The Unlock() member function releases a lock on the BMessageQueue. If the +thread no longer holds any locks on the BMessageQueue, other threads are free to acquire the +BMessageQueue lock or call member functions like AddMessage(), RemoveMessage(), NextMessage() or +delete the BMessageQueue.

  28. + +
  29. Next Message 1: The NextMessage() member function removes the BMessage which is the +oldest on the queue. It returns that BMessage to the caller. After the call completes, the +BMessage is no longer on the queue and the next oldest BMessage is at the front of the queue +(ie next to be returned by NextMessage()).

  30. + +
  31. Next Message 2: BMessage's can be removed using NextMessage() from multiple +threads at the same time with no risk of queue corruption. Similarly, AddMessage() or +RemoveMessage() can be executing from another thread while a NextMessage() is started without +corrupting the queue. A NextMessage() attempt will block if another thread has used the Lock() +member to lock the BMessageQueue.

  32. + +
+ +

BMessageQueue Implementation:

+ +

Internally, the BMessageQueue uses a BLocker to ensure that member functions like AddMessage(), +RemoveMessage() and NextMessage() do not corrupt the queue when used from multiple threads. The +same BLocker is used to implemented the Lock() and Unlock() members.

+ +

Testing with a debugger shows that the queue is implemented using a "link" pointer in the +BMessage class itself. Each BMessage is also a singly linked list which represents the queue. +All the BMessageQueue needs is a pointer to the BMessage which starts the list. For performance +reasons, it is worth maintaining a pointer to the BMessage at the end of the list and the count +of the number of elements in the list. If these are not maintained, adding an element to the +list will get slower as the number of elements grows and the cost to determine the number of +elements in the list will be high.

+ +

Because the BMessageQueue uses the link pointer which is a private part of the BMessage class, +the BMessageQueue must be a friend class of BMessage. Checking the headers, this is in fact the +case in Be's implementation. Although friendship in classes can cause some pretty serious long +term headaches if abused (and I am not convinced that this is an abuse), the OpenBeOS +implementation will follow the same implementation for now.

+ + + + diff --git a/docs/develop/app/usecases/PortLinkUseCases.htm b/docs/develop/app/usecases/PortLinkUseCases.htm new file mode 100644 index 0000000000..84bb66a0ef --- /dev/null +++ b/docs/develop/app/usecases/PortLinkUseCases.htm @@ -0,0 +1,48 @@ + + +PortLink Use Cases and Implementation Details + + + + + + +

PortLink Use Cases:

+ +

This document describes the PortLink interface and some basics of how it is implemented. +The document has the following sections:

+ +
    +
  1. PortLink Interface
  2. +
  3. PortLink Use Cases
  4. +
+ +

PortLink Interface:

+

The PortLink class is a lightweight class designed to ease the pain of sending a message to a port. Normal use boils down to creating a PortLink object, setting the message code, attaching any extra data via Attach(), and calling Flush() to send it. +

+

While this class is designed to facilitate port-based messaging, it does not devise any protocols for such. The recipient will need to know if data is included in a message, for example. Likewise, all extra data must be freed by the recipient. +

+ +

PortLink Use Cases:

+

The following use cases cover the PortLink functionality:

+ +
    +
  1. Construction: A PortLink is created by passing it a port ID. Error-checking is not performed on the port itself, so be sure it is a valid port. +

  2. + +
  3. Destruction: When a PortLink is destroyed, any data which is currently attached to a pending message is freed.

  4. + +
  5. Creating a message: Creating a message can be as simple as setting the message code (similar to BMessage's what member). Extra data is not required.

  6. + +
  7. Attaching Data: Adding extra data is as simple as calling the member function Attach(), which makes a copy of the parameter passed to it.

  8. + +
  9. Sending a message: Call Flush(). Whatever opcode has been set will be sent to the target. Optionally, a timeout (in microseconds) of type bigtime_t can be specified. This can be useful in preventing deadlocks if the target has crashed and its port fills up.

  10. + +
  11. Synchronous Messaging: This one requires a little more care in order to prevent deadlocks. Attachments may be used as with Flush(), but FlushWithReply() will wait until the target replies unless a timeout value is specified in microseconds of type bigtime_t. A return code of B_ERROR indicates an internal data error and your message is intact. If a reply times out, it will return B_TIMED_OUT. Otherwise, it returns B_OK. +

    +Reply Protocol: The target will receive the message with all attached data with one slight modification to the otherwise chosen message protocol - the first item will be a port_id which is the port to which the sender is to reply. All other attached data (if any) immediately follows this port id. +

  12. +
+
HTML Documentation Format by Jeremy Rand
+ + diff --git a/docs/develop/befs/resources.html b/docs/develop/befs/resources.html new file mode 100644 index 0000000000..c2d7f48960 --- /dev/null +++ b/docs/develop/befs/resources.html @@ -0,0 +1,54 @@ + + + Documentation and Resources for writing BeOS File Systems + + + + +

Hints for BeOS File System Authors

+ +

Besides the example DOS file system that comes with the BeOS developers +stuff, there's also a CD-ROM file system example. If you installed the +optional stuff on the BeOS 5.0 Pro CD-ROM (or the developer's kit from the free +site), it's at: /boot/optional/sample-code/add-ons/iso9660 + +

On BeBits you can get source code +examples from a few programs, such as AtheOS FS (app 2028 on BeBits). There used to +be a copy of NTFS too with source (app +620 on BeBits), but the site seems to be down. There are also other file +systems there, but source is not included (some have it available on request). + +

Another useful source of information is the BeOS developer library +web site. It has some articles on file systems, the most relevant being +the One +File Network File System, which shows one way of combining a user space +program with a kernel file system stub. Another good one is about +the FSP (file system protocol). The prior issue describes what features +the BFS supports. There are lots of other tangentially related articles, +such as ones on device drivers, programming in kernel mode, debugging, etc. + +

There's also the very good Practical File System Design book +by Dominic Giampaolo, from Morgan Kaufmann +Publishers, read their catalog +entry for more info about the book. + +

Finally, there's Alexander G. +M. Smith's ongoing documentation of the file system API, condensed from all +these sources and from his continuing experiences with trying to write a RAM +file system. You can get the StyledEdit text file with the October +18 2001 version or check the BeOS directory on his site +for newer versions. + +

Last updated November 11, 2001 by AGMS. + + + diff --git a/docs/develop/drivesetup/DesDoc.txt b/docs/develop/drivesetup/DesDoc.txt new file mode 100644 index 0000000000..86fcac0a02 --- /dev/null +++ b/docs/develop/drivesetup/DesDoc.txt @@ -0,0 +1,165 @@ +Drive Setup Design Document + +Contents +-------- +1 General +2 Display View +3 Menus +3.1 Mount +3.2 Unmount +3.3 Setup +3.4 Options +3.5 Rescan +4 Partition View +4.1 Intel +4.2 Apple + +1: General +---------- + + - When the app starts up, it pops up a dialog while scanning for devices. + - The window is resizeable. + - There doesn't seem to be any way to get the information that I need + easily: I suspect that some direct reading of the partition map is + needed. For now, a fake struct with the info I need will suffice. + +2: Display View +--------------- + +The display view displays information about the drives that the system knows +about. The following information is shown: + - Device: Where the device is mounted on the system. For example, my floppy + drive is at /dev/disk/floppy. + - Map Style: Either apple or intel, depending on which type the media is. + - Partition type: Empty for a drive. + - File System: Comma seperated list of the File Systems on the selected + device. + - Volume Name: Comma seperated list of the Volume Names of the partitions on + the selected device. + - Mounted At: Comma seperated list of the mount points of the partitions on + the selected device. + - Size: Total size of the media at the selected device. +Selecting a drop down arrow on a device shows a list of partitions on the media +in the device. The following information is shown: + - Device: Empty for a partition. + - Map Style: Empty for a partition. + - Partition type: The type of the partition. + - File System: The file system on that partition. + - Volume Name: The name of the partition. + - Mounted At: The mount point of the partition. + - Size: The size of the partition. + +3: Menus +-------- + +Mount + - Only available when there is a partition available to mount on the selected + drive. + + *Mount All Partitions + - Shortcut: Alt-M + - Action: Mounts all unmounted partitions on the selected drive. + + *[List of partitions on the selected drive, with mounted partitions greyed + out and unmounted partitions selectable] + - Action: Mounts the selected partition on the selected drive. + +Unmount + - Only available when there is a mounted partition on the selected drive. + + *[List of mounted partitions on the selected drive, with all mounted partitions + selectable except /boot] + - Action: Unmounts the selected partition. + +Setup + - Only available when the selected drive has valid media in it: example, a + hard drive, or a floppy drive with a disk in. + + *Format + - Shortcut: Alt-F + - Action: Formats the drive. + + *Partition + - Action: Opens sub menu. + + *apple... + - Action: Allows partitioning of apple hard drives, using an apple-like + interface. + + *intel... + - Action: Allows partitioning of intel hard drives. + + *Initialize + - Action: Opens sub menu. + + *[List of partitions on the selected drive, with unmounted partitions + selectable] + - Action: Opens sub menu. + + *[List of supported formats to initialize the drive to.] + - Current list of formats: + - Be File System... + - cdda... + - cifs... + - DOS/FAT... + - ext2... + - Mac HFS... + - iso9660... + - NTFS... + - Old Be File System... + - uspacefs... + - Possibly this section should be dynamically created, with initializing + code done in a plug-in type way, so other formats can be easily added. + - Action: Initializes the selected partition. + +Options + - Only available when the selected drive has valid media in it: example, a + hard drive, or a floppy drive with a disk in. + + *Eject + - Only available if the selected drive has removable media. + - Shortcut: Alt-E + - Action: Ejects the media. + + *Surface Test + - Shortcut: Alt-T + - Action: Performs a surface test on the media. + +Rescan + + *IDE + - Action: Rescans the IDE chain for new media/devices/whatever. + + *SCSI + - Action: Rescans the SCSI chain for new media/devices/whatever. + +Context Sensitive Right Click Menu + - Available by right clicking on a drive in the display view. + - Allows access to the Mount, Unmount, Setup, and Options menus, with the + same "selectability" as above - if the menu is not selectable on the main' + menu bar, it is not selectable on this context menu. + +4: Partition View +----------------- + + - The partition view is brought up when "Partition" is chose from the Setup + menu. + - If the selected drive has partitions that are currently mounted, a dialog + is brought up explaining that the partition map can not be modified, only + viewed, and offering a choice to cancel or proceed. If the user proceeds, + all of the UI components are set to an inactive state, except for the + Cancel and Ok buttons. + +Intel + - The top part of the view shows the device path. + - The middle section of the view shows the partitions, the type (in a text + box), a readable explanation of the type number in a drop down menu, and + a checkbox indicating the state of the Active flag. + - The bottom section of the view consists of a slide bar for each partition, + allowing the user to set the size of the partitions. Each slide bar can + be locked or unlocked, which disallows or allows movement of the slide bar. + - The button actions are Revert, Cancel, and Ok. + +Apple + - (I have no apple partitions available, help needed!!) + \ No newline at end of file diff --git a/docs/develop/drivesetup/todo.txt b/docs/develop/drivesetup/todo.txt new file mode 100644 index 0000000000..bf262b3688 --- /dev/null +++ b/docs/develop/drivesetup/todo.txt @@ -0,0 +1,5 @@ +TODO: + + * make the unmount menu build off of the selected drive, + rather than all mounted partitions + diff --git a/docs/develop/fontprefs/readme b/docs/develop/fontprefs/readme new file mode 100644 index 0000000000..fb8629b66f --- /dev/null +++ b/docs/develop/fontprefs/readme @@ -0,0 +1,16 @@ +Font Pref App + +ISSUES + +* Rescanning fonts causes the bold font to lose its boldness. +* Fixed width font selector should only show fixed width fonts + +TODO + +* When a style is selected, the font menu label needs to be updated to reflect this +* make a cache panel function that updates the slider labels with an int as a parameter +* Add the VMSettings code so that the panel uses the settings file for position/size + +Matt McMinn +melfinadev@earthlink.net + diff --git a/docs/develop/fontprefs/readme.xml b/docs/develop/fontprefs/readme.xml new file mode 100644 index 0000000000..fc5f6871c0 --- /dev/null +++ b/docs/develop/fontprefs/readme.xml @@ -0,0 +1,112 @@ + + + Fonts + + 0.8 + + + + Matt McMinn + melfinadev@earthlink.net + http://home.earthlink.net/~melfina/ + + + + + + It's just a copy of the fonts preferences app that comes with BeOS. + + + + + + + + 1 + + + Rescanning fonts causes the bold font to lose its boldness. + + + + + + + + 2 + + + Fixed width font selector should only show fixed width fonts. + + + + + + + Should be relatively easy - just filter the fonts. + + + + + + + + + + + + + + 1 + 0.9 + + + When a style is selected, the font menu label needs to be + updated to reflect this. + + + + + + + + 2 + 0.9 + + + Make a cache panel function that updates the slider labels with + an int as a parameter. + + + + + + + + 3 + 0.9 + + + Add the VMSettings code so that the panel uses the settings + file for position/size. + + + + + + + + 4 + 0.9 + + + Update the default fonts on close. + + + + + + + + + \ No newline at end of file diff --git a/docs/develop/ikteam/BinCompat.html b/docs/develop/ikteam/BinCompat.html new file mode 100644 index 0000000000..6048e871c8 --- /dev/null +++ b/docs/develop/ikteam/BinCompat.html @@ -0,0 +1,181 @@ + +

+ Maintaining Binary Compatibility +
+ +

Binary Compatibility in 3 Easy Steps!

+ +

An Introduction

+In the early days of the OpenBeOS project, a debate raged concerning one of the projects +primary goals: maintaining binary compatibility with BeOS R5. The idea was that the +only way an effort to rewrite BeOS would be successful was if folks could continue +running the apps they already had. Certainly, a lot of software available for BeOS is +open source or actively maintained -- these apps could just be recompiled if necessary. +Others -- PostMaster, gobe's Productive suite and a few other crucial apps -- weren't +likely to get rebuilt, either because the original author had stopped maintainance +without being kind enough to release the source, or because it just wouldn't be +commercially feasible.

+Some said that we were crazy; that it couldn't be done. Thankfully, cooler heads +prevailed and we're well on our way to a binary compatible clone of R5.

+ +"But wait!" you cry. "How did the cooler heads which prevailed know that the holy grail +of binary compatibility was achievable?" I'm so glad you asked! Keeping reading and be +enlightened, Grasshopper.

+ +

The Issues

+There are three basic issues that have to be addressed to ensure binary compatibility: +
    +
  • + Names must be identical
    + This includes class and structure names as well as public, protected and global + function and variable names. +
  • +
  • + Object sizes must be identical
    + Classes must contain the same number of bytes of data; global variables must + be the same size. Maybe BGlobalVar should've been an int32 + instead of an int16, but we're stuck with it now. +
  • +
  • + Virtual function table layout must be identical
    + The most cryptic and confusing aspect of maintaining binary compatibility. + The issue essentially boils down to this: for any given class, there must + be the same number of virtual functions, declared in the same order as the + original. +
  • +
+ +

The Nitty Gritty

+"Good grief!" you say. "How on earth do I keep all this stuff straight?" Ah, +Grasshopper, it is easier that you might imagine. Just follow these steps, and you +should be binary compatible in no time! +
    +
  1. + Make a copy of the appropriate Be header file
    + This is now your header file. You may need to change a thing or two, but what + you can (or will need to) change is quite limited, and discussed below. +
  2. +
  3. + Implement public, protected and virtual functions
    + In the course of doing this, you may discover that there are some private + non-virtual function declarations that you just don't use. Feel free to axe + them! Since they're private, nobody using the class will miss them, and + because they're not virtual, they don't effect the vtable layout. Conversely, + if you find a need to add some private, non-virtual functions, go right ahead + (for the very same reasons). +
  4. +
  5. + Make sure you don't change the number of bytes used for data
    + There are two situations that can make this seem difficult. First, there + may be data members that you don't use in your reimplementation. You can + just leave them (safe, but a little messy) or you can add the extra members' + bytes to the class's "unused" data array. An example will make this clear.
    + Let's say we have a class BFoo:
    + +
    +	class BFoo {
    +	    public:
    +	        BFoo();
    +	        void SomeFunc();
    +	    private:
    +	        int32 fBar;
    +	        char  fZig;
    +	        int32 fQux;
    +	        int32 fUnused[2];
    +	};
    +		
    +
    + The Be engineers that originally wrote this BFoo purposely added some data + padding in the form of an array of 2 int32s (they did this with + most classes in the API). Now let's suppose in your implementation, you + really didn't need fQux. You can add fQux's bytes + into fUnused:
    + +
    +	class BFoo
    +	{
    +	    ...
    +	    private:
    +	        int32 fBar;
    +	        char  fZig;
    +	        int32 fUnused[3];
    +	};
    +		
    +
    + Nothing could be easier! An additional twist that should be noted is that + data member order must also be preserved. In much the same way as existing + apps will "look" for virtual functions in a specific place in the vtable, + so will they "look" for data members in a specific place in an object.
    + "But what if I don't need fZig, either?" you wonder. "It's only + one byte, not four like an int32!" Have no fear! Just rename it + "fUnusedChar" and be done with it.

    + + The second situation that can make preserving object size tricky is if there + aren't enough bytes of data available. Building on our cheesy BFoo + example, let's suppose that rather than getting rid of fQux and + fZig, you actually needed to add another 4 + int32s worth of data: fNewData1 through + fNewData4. The original implementation of BFoo has two extra + int32s which we can use, but that leaves us two int32s + short. What to do? The easiest thing to do is create a data structure to hold + your new data and convert one of the fUnused items into a pointer + to that structure: + +

    +	// Foo.h
    +	struct _BFooData_;
    +	class BFoo
    +	{
    +	    public:
    +	        BFoo();
    +	        ~BFoo();
    +	        void SomeFunc();
    +	    private:
    +	       int32 fBar;
    +	       char  fZig;
    +	       _BFooData_* fNewData;
    +	       int32 fUnused[1];
    +	};
    +
    +	// Foo.cpp
    +	struct _BFooData_
    +	{
    +		int32 fNewData1;
    +		int32 fNewData2;
    +		int32 fNewData3;
    +		int32 fNewData4;
    +	};
    +	BFoo::BFoo()
    +	{
    +		fNewData = new _BFooData_;
    +	}
    +	BFoo::~BFoo()
    +	{
    +		delete fNewData;
    +	}
    +		
    + + Voila! More data without making the class bigger. Notice the added + destructor; make sure you're cleaning up your new (dynamically allocated) data. +
  6. +
+ + And there you have it: Binary Compatibility in 3 Easy Steps!
+ Questions, comments, or corrections? Please let + me know!
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + diff --git a/docs/develop/ikteam/IK_Process.html b/docs/develop/ikteam/IK_Process.html new file mode 100644 index 0000000000..b780536848 --- /dev/null +++ b/docs/develop/ikteam/IK_Process.html @@ -0,0 +1,140 @@ + +Interface Kit Team Process + +

Interface Kit Team Process

+

+This paper deals with the set of requirements for reimplementing any portion of the BeOS +covered by the Interface Kit team's charter; namely, the Interface Kit, the Application +Kit, the app_server, and related preferences applets.   This team's resposibilities +may broaden later to include more areas of the OS which are related (the input_server +comes to mind as a possibility).   Since the mandate of the group covers such a +large and public (from a 3rd party developer's perspective) portion of BeOS -- a portion +that is central to the user and developer experience of BeOS -- it is vital that our work +be done in a scrupulously documented and tested fashion.   This paper lays out the +process which, when adhered to, aims to ensure this high standard of documentation and +testability. +

+First, a definition of "module" as it pertains to this paper. +

+Module: +A function, class, kit, application or related set of functions, classes, kits or +applications is refered to as a "module" in this paper, the implication being that +there can be modules within modules.   A module is any specifiable and testable +entity -- which may or may not rely on other modules to accomplish its functionality. +

+

+Process Requirements +
+

+ +Each module in this project shall have the following items: +
    +
  • Complete interface specification.   For kits, this will mostly come + from the BeBook, but in many cases the specification will have to elaborate + on what the BeBook provides or even be created entirely (app_server internals + are a good example).
  • +
  • Complete use case specification.   For those not familiar with use cases, + they consist of the following: +
      +
    • A list of ways in which a module is expected to be used
    • +
    • Sublists of assumptions/prerequisites for each of those cases.   + This should include items such as state of an object instance at the + time of method invocation, the state of parameters passed to functions, + etc.
    • +
    • Sublists of error conditions and handling for each case where + assumptions/prerequisites are not properly met.   This list should + not attempt to be all inclusive:   circumstances that do not + directly bear upon the assumptions/prerequisites do not need to be + considered unless clearly necessary.
    • +
  • +
  • A set of unit tests which verify that the module performs correctly in expected + use cases as well as under error conditions as described in the use case + specification.
  • +
  • A plain-english discussion of how the module implements its functionality:   + what algorithms are to be used, what other modules are relied upon, the general + design rationale, execution flow, etc.
  • +
  • The actual reimplementation.
  • +
+ +Each of the above items is to be completed roughly in the order listed.   In other +words, a given module should have a complete interface specification, etc., before it is +reimplemented.   Prototyping is encouraged, of course.   For existing APIs, the +recommended course is to write the interface spec, use case spec and unit tests to the +API.   Unit tests, in particular, should perform as expected when run against the +existing API.   When they do not, changes may need to be made to the specifications. +  Our goal is to reimplement the APIs as they are, not necessarily as they're +documented -- and then ensure that the docs accurately reflect the reimplementation. +  Thorough testing of the existing implementation will show us where the +documentation is wrong, misleading or absent, thereby helping to ensure that our +reimplementation is functionaly identical to the existing one. +

+ +CppTest +is the test framework we will be using.   By using this framework for all our unit +tests, we can easily build large test suites which will verify the codebase in a single +executed run.   An excellent short discussion of the value of unit tests is here:
+ + +http://www.extremeprogramming.org/rules/unittests.html + +

+A Suggestion +
+

+ +Although the interface specification for each module should be completed first, I have a +suggestion for how to proceed from there which should make the remainder of the process +less boring.   Rather than following the interface specification with a full set of +use cases followed by a full set of tests, a more productive and enjoyable way to go is +to take each module in turn, write one of the use cases/error conditions for it and +immediately write the test for that use case/error condition.   This will break up +the tedious process of specifying all the use cases and error conditions with a bit of +coding -- not implementation code, but code nonetheless. + +

+Some Final Thoughts +
+

+ +This process is a very rigorous approach to take.   Given that our goal is to produce +the most stable, robust and professional desktop operating system available, this sort of +thoroughness is justifiable and necessary.   Our understanding of the system will be +greatly increased and the task of coming up to speed on the system will be made much +easier for outsiders and newcomers to the project. +

+This approach is also not the most "fun":   sitting down and hacking out code has the +attraction of instant gratification that design work does not.   It is important to +understand, however, that proper design work done up front makes the task of +implementation easier, the chore of integration much less onerous and testing and +code verification a snap.   Provided we do not get locked in "analysis paralysis" +and attack the design work as vigorously as the coding work, the entire project will +actually move more quickly -- usually quite a bit more quickly -- than if we had simply +started coding.   Thrown away versions of the codebase should be just that: +  quick prototypes intended to be disposable, rather than full-blown implementation +attempts which fail or are mysterious blackboxes because we don't really understand the +module.   Following this process makes it far more likely that when we sit down to +do a module implementation, the first try will be the last (bug fixes not withstanding, +of course ;). +

+To ensure the process is followed and we produce the highest quality code we can, code +will not be accepted for release until all of the process items are covered.   If +this seems like a hardline stance to take, remember:   every single app which +utilizes the Application and Interface Kits relies on our code to be rock solid -- +totally predictable and completely reliable.   Let's strive to be engineers, not +h4X0rz. +

+
+ +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + \ No newline at end of file diff --git a/docs/develop/ikteam/UnitTestingInfo.html b/docs/develop/ikteam/UnitTestingInfo.html new file mode 100644 index 0000000000..c5d246eb3a --- /dev/null +++ b/docs/develop/ikteam/UnitTestingInfo.html @@ -0,0 +1,391 @@ + + + +Unit Testing Information + + + + + +

Unit Testing Information:

+ +

This document describes the "why's" and "how's" of unit testing for the AppKit team of the +OpenBeOS project. Although it is intended for the AppKit team, there is no reason other teams +couldn't use this information to develop a similar unit testing strategy.

+ +

The document has the following sections:

+ +
    +
  1. What is unit testing?
  2. +
  3. Why is unit testing important?
  4. +
  5. When should I write my unit tests?
  6. +
  7. What kinds of tests should be in a unit test?
  8. +
  9. What framework is being used to do unit testing for the AppKit?
  10. +
  11. What AppKit specific modifications have been made to this framework?
  12. +
  13. What framework modifications might be required in the future?
  14. +
  15. How do I build the framework and current tests for the AppKit?
  16. +
  17. How do I run tests?
  18. +
  19. How do I write tests for my component?
  20. +
  21. Are there example tests to base mine on?
  22. +
  23. How do I write a test with multiple threads?
  24. +
+ +

What is unit testing?

+ +

Unit testing is the process of showing that a part of a software system works as far as the +requirements created for that part of the system. Unit testing is best if it has the following +characteristics:

+ +
    +
  • The software component is tested in isolation with as little interaction with other software +components as possible.
  • +
  • The software component is tested using automated tools so that unit tests can be run with +every build of the software if required.
  • +
  • All requirements of the software component are tested as part of the unit tests.
  • +
+ +

Unit testing is not the only type of testing but is definitely a very important part of any +testing strategy. Following unit testing, software should go through "integration testing" to +show that the components work as expected when put together.

+ +

Why is unit testing important?

+ +

A basic concept of software engineering is that the cost of fixing a bug goes up by a factor +of 2-10x (depending on the source of the information) the later in the development process it is +found. Unit testing is critical to finding implementation bugs within a particular component as +quickly as possible.

+ +

Unit testing will also help to find requirements problems also. If you write the requirements +(or use cases) for your component from the BeBook, hopefully the BeBook and your use cases will +match the actual Be implementation. A good way to confirm that the BeBook documentation matches +Be's implementation is to write your unit tests and run them against the original Be code.

+ +

Unit tests will also continue to be maintained and run in the future also. As the mailing +lists obviously show, many people are looking forward to OpenBeOS post-R1 when new features +will be introduced above and beyond BeOS R5. These unit tests will be critical to ensuring that +any new feature or even just a bug fix doesn't break existing functionality.

+ +

Speaking of bug fixes, consider adding unit tests for any bugs you identify that slipped +through your original unit test suite. This will ensure that this bug or a similar one is not +re-introduced in the future.

+ +

Finally, unit testing is not the be all, end all of testing. As mentioned above, integration +testing must be done to show that software components work together. If all unit tests cover +all requirements and have run successfully against all components, then a failure has to be +due to a bug in the interaction of two or more known working software components.

+ +

When should I write my unit tests?

+ +

As the AppKit process document describes the recommended order for implementing a component +is:

+ +
    +
  1. Write an interface specification
  2. +
  3. Write the use case specifications
  4. +
  5. Write the unit tests
  6. +
  7. Write an implementation plan
  8. +
  9. Write the code
  10. +
+ +

Please see the AppKit process document for more details about the entire sequence. The unit +test are to be written once the use cases are written and before any implementation work is +done. The use cases must be done because they determine what the tests will be. You need to +write as many tests are required so that all use cases for that component are tested. The use +cases should be detailed enough that you can write your unit tests from them.

+ +

The unit tests are to be done before implementation for a very good reason. You should be able +to run these unit tests against the Be implementation and confirm that they all pass. If they do +not pass, then either there is a bug in the unit test itself or you have found a difference +between your use cases and the actual implementation. Even if your use cases match the BeBook, +if that is not how the actual Be implementation works, we must match the current implementation and +not the BeBook. You should go back and modify the use case. Change the use case so that it +matches Be's implementation and consider adding a note indicating this doesn't match the +BeBook.

+ +

Imagine if you completed the implementation and then wrote and ran the unit tests. If you run +the tests against your implementation and Be's implementation, you will notice the test passes +for your code but fails on Be's. At this point, you will have to change the implementation, change +the unit test and change the use case which is more work that if you write the unit tests before +the implementation. Worse, if you only ran the unit tests against your implementation and not +Be's, you may not notice the problem at all.

+ +

What kinds of tests should be in a unit test?

+ +

The unit tests you write should cover all the functionality of your software module. That +means your unit tests should include:

+ +
    +
  • All standard expected functionality of the software component
  • +
  • All error conditions handled by the software component
  • +
  • Interaction with software components which cannot be decoupled from the target software +component
  • +
  • Concurrency tests to show that a software component which is expected to be thread safe (most +things are under BeOS) is safe and free from deadlocks.
  • +
+ +

What framework is being used to do unit testing for the AppKit?

+ +

The AppKit team has chosen to use CppUnit version 1.5 as the basis of all of our unit tests. +This framework provides very useful features and ensures that all unit tests for AppKit code +are consistent and can be executed from a single environment.

+ +

There are two key components to the framework. First, there is a library called libCppUnit.so +which provides all the C++ classes for defining your own testcases. Secondly, there is an +executable called "TestRunner" which is capable of executing a set of testcases.

+ +

For more information on CppUnit, please refer to +this website + +

What AppKit specific modifications have been made to this framework?

+ +

The following are the modifications that have been introduced into the CppUnit v1.5 +framework:

+ +
    +
  • A makefile has been added for the library and the TestRunner.
  • +
  • Some "bugs" in CppUnit v1.5 which lead to it not compiling under BeOS v5.
  • +
  • The TestRunner has been modified to support BeOS based addons. Each test which you can +select from the TestRunner is found in the "add-ons" directory at runtime. The original +TestRunner required you to change the TestRunner when new tests were added to it.
  • +
  • Changed the output from TestRunner. The output includes a name of the test being run and +a run time for the test in microseconds.
  • +
  • Changed the arguments of the assert functions in the TestCase class from std::string to +const char *'s due to apparent concurrency problems with std::string under BeOS when testing +threaded tests.
  • +
  • Added locking to the TestResults class so that multiple threads can safely add result +information at the same time for a single test.
  • +
  • The ThreadedTestCaller class was written to allow us to write tests which contain multiple +threads. This is an important class because many BeOS components are thread safe and we need +to confirm that the OpenBeOS implementation is also thread safe.
  • +
+ +

This is the list of the important modifications done to CppUnit v1.5 at the time this document +is being written. For the latest information about modifications to CppUnit, check the code +which can be found in the OpenBeOS CVS repository.

+ +

What framework modifications might be required in the future?

+ +

This framework will have to evolve as our needs grow. The main issues I think we need to +solve are:

+ +
    +
  • The format of the test name is an encoded string representing the class definition of the +test class from gcc. It is not a very readable format but given that the test class is often +a template class and you would like different names for different instances of the template, +this seemed the best compromise. Suggestions welcome.
  • + +
  • The threaded test support added into CppUnit forces you to specify the entry point for each +thread in your test. If you are doing a test with a BLooper or a BWindow, these classes start +a thread of their own. This thread will not be started through the standard entry point so +doing "assert's" from one of these threads will not work. Perhaps we need TestBLooper and +TestBWindow classes which will work with the assert's.
  • +
+ +

If you find you need some other features, feel free to add them to CppUnit.

+ +

How do I build the framework and current tests for the AppKit?

+ +

As of writing this document, you can build the framework and all the current AppKit tests +by performing the following steps:

+ +
    + +
  1. Checkout the "app_kit" sources or the entire repository from the OpenBeOS CVS repository. +There is information at the OpenBeOS site about how to access the CVS repository.
  2. + +
  3. In a terminal, "cd" into the "app_kit" directory in the CVS files you checked out.
  4. + +
  5. Type "make".
  6. + +
+ +

Note that the build system for OpenBeOS is moving to jam so these steps may become obsolete. +When you the make has finished, you should find the following files:

+ +
    + +
  • app_kit/test/CppUnit/TestRunner - this is the executable to use to execute +tests.
  • +
  • app_kit/test/CppUnit/lib/libCppUnit.so - this is CppUnit library which your tests +must link against.
  • +
  • app_kit/test/CppUnit/lib/libopenbeos.so - this is library which contains OpenBeOS +implementation of some Be classes (usually found in libbe.so, called libopenbeos.so to avoid a name +clash at runtime).
  • +
  • app_kit/test/add-ons/BAutolockTests - this is the addon which contains the tests +which are run against the Be and OpenBeOS implementation of BAutolock.
  • +
  • app_kit/test/add-ons/BLockerTests - this is the addon which contains the tests +which are run against the Be and OpenBeOS implementation of BLocker.
  • +
  • app_kit/test/add-ons/BMessageQueueTests - this is the addon which contains the tests +which are run against the Be and OpenBeOS implementation of BMessageQueue.
  • + +
+ +

These are the key files which ensure that the tests can be run.

+ +

How do I run tests?

+ +

You have a few different options for how you run a test or a series of tests. Before you start +however, you must build the code as describe in this section. Once +it is built, you can run tests any of these ways:

+ +
    +
  • Run "make test" from the app_kit directory. This will lead to all of the tests defined in +app_kit/test/add-ons directory to be run.
  • +
  • From the "app_kit/test" directory, execute the command "CppUnit/TestRunner -all". This will +lead to all of the tests defined in the app_kit/test/add-ons directory to be run and is the same +as what happens in the "make" example above. However, recompile any code that has changed in the +process.
  • +
  • From the "app_kit/test" directory, execute the command "CppUnit/TestRunner <TestName>" +where <TestName> is one of the addons found in the "app_kit/test/add-ons" directory. Only +the tests defined in that add-on will be run.
  • +
+ +

How do I write tests for my component?

+ +

The first step to writing your tests is to develop a plan for how you will test the +functionality. For ideas of the kinds of tests you may want to consider, you should reference +this section.

+ +

Once you know the kinds of tests you want, you need to:

+ +
    + +
  • For every test you want, define a class which derives from the "TestCase" class in the +CppUnit framework.

  • + +
  • Within each test class you define, create a "void setUp(void)" and "void tearDown(void)" +member function if required. If before executing your test, you need to perform some actions, +put those actions in the "setUp()" member. If you need to cleanup after your test, put those +actions in the "tearDown()" member.

  • + +
  • Within each test class you define, create a member function which takes "void" and +returns "void". Within this member function, write the code to execute the test. Whenever you +want to ensure that some condition is true during your test, add a line within the member function +that looks like "assert(condition)". For example, if the variable "result" must have the value +B_OK at a particular point in your test, you should add a line which reads +"assert(result = B_OK)".

  • + +
  • Create a constructor for all of your test classes that takes a "std::string name" argument +and pass that onto the TestCase parent class. Add whatever actions you need to take in the +constructor.

  • + +
  • Create a destructor for all of your test classes and take whatever actions are +appropriate.

  • + +
  • Within each test class you define, create a member with the signature +"static Test *suite(void)". For a simple test where only one test needs to be run for this class, +the contents of this member should look like:

    + +
    +return(new TestCaller<ClassName>("", &ClassName::MemberName));
    +
    + +

    Replace "ClassName" with the name of your test class and "MemberName" with the name +of the member function you defined your test in. If you need to define more than one test to run +from this class, refer to instructions below on how to use the TestSuite class of CppUnit. If you +are creating a threaded test, refer to this section.

  • + +
  • Create one ".cpp" file for defining the "addonTestFunc()" function. This function must +exist in global scope within your test addon. The contents of this ".cpp" file will look something +like:

    + +
    +#include "TestAddon.h"
    +
    +Test *addonTestFunc(void)
    +{
    +	TestSuite *testSuite = new TestSuite("<TestSuiteName>");
    +
    +	testSuite->addTest(<ClassName1>::suite());
    +	testSuite->addTest(<ClassName2>::suite());
    +	/* etc */
    +
    +	return(testSuite);
    +}
    +
    + +

    In the above example, replace <TestSuiteName> with an appropriate name for the group of +tests and <ClassName1> and <ClassName2> with the names of the test classes you have +defined.

  • + +
  • Create a build system around a BeIDE project, Makefile or preferrably a jam file which +builds all the necessary code you have written into an addon.

  • + +
  • Put this addon into the app_kit/test/add-ons directory and follow the above instructions +for how to run your tests.

  • + +
+ +

Are there example tests to base mine on?

+ +

There are example tests which you can find in the following directories:

+ +
    +
  • app_kit/test/lib/application/BMessageQueue
  • +
  • app_kit/test/lib/support/BAutolock
  • +
  • app_kit/test/lib/support/BLocker
  • +
+ +

There are some things done in these tests which make things a bit more complex, but you may +want to do similar things:

+ +
    + +
  • Most tests use a ThreadedTestCaller class even in some situations when there aren't actually +more than one thread in the test.
  • + +
  • All tests are defined as a template class. The test class is a template of the class to test +(if that makes sense to you). For example, to test both the Be and OpenBeOS BLocker and not +end up with a symbol conflict, the OpenBeOS implementation of BLocker is actually in a namespace +called "OpenBeOS". So, the tests must be run against the classes "::BLocker" and +"OpenBeOS::BLocker". The easiest way to do this was to make the class to be tested a template +and define it for both "::BLocker" and "OpenBeOS::BLocker".
  • + +
+ +

Even with the complexity, I think this code provides a pretty good example of how to write +your tests.

+ +

How do I write a test with multiple threads?

+ +

If you have a test which you want to define that requires more than one thread of execution +(most likely a concurrency test of you code), you need to use the ThreadedTestCaller class. +The steps which differ from the above description on how to write a test case are:

+ +
    + +
  • In your test class, define a member function for each thread you will be starting. All of +these member functions must take "void" and return "void". If all the threads in your test +perform the exact same actions, it is OK to just define one member function. Usually in the +tests I have written, I have called these member functions "TestThread1()", "TestThread2()", +etc.

  • + +
  • If your "static Test *suite()" function for your test class, you must return a +ThreadedTestCaller. Imagine that the test class name is "MyTestClass" and you want two threads +which run member functions "TestThread1()" and "TestThread2()". That code would look like:

    + +
    +Test *MyTestClass::suite(void)
    +{
    +	MyTestClass *theTest = new MyTestClass("");
    +	ThreadedTestCaller<MyTestClass> *threadedTest = new TreadedTestCaller<MyTestClass>("", theTest);
    +
    +	threadedTest->addThread(":Thread1", &MyTestClass::TestThread1);
    +	threadedTest->addThread(":Thread2", &MyTestClass::TestThread2);
    +
    +	return(threadedTest);
    +}
    +
    + +

    If you need to, you can put a number of ThreadedTestCaller instances into a TestSuite and return +them in the suite() member function. Examples of this can be found in the BLocker and +BMessageQueue test examples.

  • + +
+ +

Otherwise the steps are the same as for other tests. The code gets much more complex if you +define your test classes as templates as the examples do.

+ +
+ + diff --git a/docs/develop/ikteam/images/Check.gif b/docs/develop/ikteam/images/Check.gif new file mode 100644 index 0000000000..e0be2405b9 Binary files /dev/null and b/docs/develop/ikteam/images/Check.gif differ diff --git a/docs/develop/ikteam/images/DocumentDraw.gif b/docs/develop/ikteam/images/DocumentDraw.gif new file mode 100644 index 0000000000..74409764ee Binary files /dev/null and b/docs/develop/ikteam/images/DocumentDraw.gif differ diff --git a/docs/develop/ikteam/images/GoalFlag.gif b/docs/develop/ikteam/images/GoalFlag.gif new file mode 100644 index 0000000000..bc06bfccdf Binary files /dev/null and b/docs/develop/ikteam/images/GoalFlag.gif differ diff --git a/docs/develop/ikteam/images/Hammer.gif b/docs/develop/ikteam/images/Hammer.gif new file mode 100644 index 0000000000..8c091865b9 Binary files /dev/null and b/docs/develop/ikteam/images/Hammer.gif differ diff --git a/docs/develop/ikteam/images/Help.gif b/docs/develop/ikteam/images/Help.gif new file mode 100644 index 0000000000..51c325ead9 Binary files /dev/null and b/docs/develop/ikteam/images/Help.gif differ diff --git a/docs/develop/ikteam/images/User.gif b/docs/develop/ikteam/images/User.gif new file mode 100644 index 0000000000..36fe2eba80 Binary files /dev/null and b/docs/develop/ikteam/images/User.gif differ diff --git a/docs/develop/ikteam/images/blank-20.gif b/docs/develop/ikteam/images/blank-20.gif new file mode 100644 index 0000000000..63e63111aa Binary files /dev/null and b/docs/develop/ikteam/images/blank-20.gif differ diff --git a/docs/develop/ikteam/index.html b/docs/develop/ikteam/index.html new file mode 100644 index 0000000000..46d598bf6c --- /dev/null +++ b/docs/develop/ikteam/index.html @@ -0,0 +1,43 @@ + + + Interface Kit Team Central + + +

Welcome to Interface Kit Team Central!

+

+This is the IK Team's public face, where OpenBeOS folk and intrepid members of the +BeOS community can find such goodies as: + +

+With more sure to come. +
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + \ No newline at end of file diff --git a/docs/develop/ikteam/schedule/Discussion.html b/docs/develop/ikteam/schedule/Discussion.html new file mode 100644 index 0000000000..a308c28025 --- /dev/null +++ b/docs/develop/ikteam/schedule/Discussion.html @@ -0,0 +1,71 @@ + +Schedule Rationale + +

Schedule Rationale

+Below is an informal discussion of the rationale behind the Interface Kit team's +behemoth schedule. Various details may not reflect the current form of the schedule, +but the basic gist is what's really important here. +
+
+

+First, let me head off the suggestion that we formally split into 3 or 4 stand-alone +projects:   the Interface Kit, Application Kit and app_server are completely +dependent on one another in a way that no other set of system components is. Each +without the others can accomplish almost *nothing*; I think the existence of Integration +highlights this fact. +

+Each milestone listed has a number of tasks associated with it; these need to be listed +and the time for each estimated. These tasks should be as fine grained as possible. +Taking BView as an example, I would expect each method on BView to have its own entry +under milestones 1, 2, 3, 4 and 8 with entries added as necessary to milestones 18 to +22. "Why so detailed?" you say. I'm glad you asked. ;) +

+First off, the finer the schedule's granularity, the more realistic estimate you have for +the project as a whole. Asked to implement BView, one might be tempted to say "Oh, about +3 weeks," whereas an estimate of the time needed for each method might yield a total of +two to three times that. While the more realistic overall estimate may be more depressing +initially, being able to hit goals on or near the estimated date is much better for +morale in the long run than constantly being behind because all the estimates were too +low. Trust me on this, I've worked on *way* too many projects that went south because of +scheduling that was too broad -- usually because the project manager doesn't want to +"distress" the client by making them pay for the time to schedule correctly. Or design +correctly, but that's a different rant. =) +

+Second, a fine-grained schedule helps to ensure that nothing gets missed. You might +think it would be hard to forget to implement a BView method, but if you don't expressly +schedule for that method, there will be no interface, use case or technical specifications +or unit tests to fail because the method isn't doing anything. In fact, we might not +notice the missing functionality until some app that uses it dies a horrible death and +we have to figure out why. +

+Third, it helps us figure out what functionality is dependent on what -- which helps us +schedule our tasks in a logical sequence. +

+Fourth, it makes it much easier for someone that doesn't have a lot of time available or +much experience to pick something that they can tackle and know that they will be making +a meaningful contribution. It also makes it easier for us to keep track of who is doing +what on large items like BView: instead of saying "there's a bunch of stuff on BView +that needs doing," we can say "BView::StrokeEllipse() needs to be implemented" and know +that a specific person is responsible for that deliverable. +

+Fifth, as daunting as a detailed schedule looks like out of the gate, tasks are getting +completed *constantly* and it's very satisfying to see progress get made on a regular +basis. Ideally, one would like to be able to check on the progress each week and find +several items completed since the last time it was checked. +

+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + \ No newline at end of file diff --git a/docs/develop/ikteam/schedule/Tasks.xml b/docs/develop/ikteam/schedule/Tasks.xml new file mode 100644 index 0000000000..2a8bf90bcd --- /dev/null +++ b/docs/develop/ikteam/schedule/Tasks.xml @@ -0,0 +1,7540 @@ + + + +
+ + + BInvoker(); + + + BInvoker(BMessage* message, const BHandler* handler, const BLooper* looper = NULL); + + + BInvoker(BMessage* message, BMessenger target); + + + virtual ~BInvoker(); + + + virtual status_t SetMessage(BMessage* message); + + + BMessage* Message() const; + + + uint32 Command() const; + + + virtual status_t SetTarget(const BHandler* h, const BLooper* loop = NULL); + + + virtual status_t SetTarget(BMessenger messenger); + + + bool IsTargetLocal() const; + + + BHandler* Target(BLooper** looper = NULL) const; + + + BMessenger Messenger() const; + + + virtual status_t SetHandlerForReply(BHandler* handler); + + + BHandler* HandlerForReply() const; + + + virtual status_t Invoke(BMessage* msg = NULL); + + + status_t InvokeNotify(BMessage* msg, uint32 kind = B_CONTROL_INVOKED); + + + status_t SetTimeout(bigtime_t timeout); + + + bigtime_t Timeout() const; + + + uint32 InvokeKind(bool* notify = NULL); + + + void BeginInvokeNotify(uint32 kind = B_CONTROL_INVOKED); + + + void EndInvokeNotify(); + + + + + BMessage(); + + + BMessage(uint32 what); + + + BMessage(const BMessage& a_message); + + + virtual ~BMessage(); + + + BMessage& operator=(const BMessage& msg); + + + status_t GetInfo(type_code typeRequested, int32 which, char** name, type_code* typeReturned, int32* count = NULL) const; + + + status_t GetInfo(const char* name, type_code* type, int32* c = 0) const; + + + status_t GetInfo(const char* name, type_code* type, bool* fixed_size) const; + + + int32 CountNames(type_code type) const; + + + bool IsEmpty() const; + + + bool IsSystem() const; + + + bool IsReply() const; + + + void PrintToStream() const; + + + status_t Rename(const char* old_entry, const char* new_entry); + + + bool WasDelivered() const; + + + bool IsSourceWaiting() const; + + + bool IsSourceRemote() const; + + + BMessenger ReturnAddress() const; + + + const BMessage* Previous() const; + + + bool WasDropped() const; + + + BPoint DropPoint(BPoint* offset = NULL) const; + + + status_t SendReply(uint32 command, BHandler* reply_to = NULL); + + + status_t SendReply(BMessage* the_reply, BHandler* reply_to = NULL, bigtime_t timeout = B_INFINITE_TIMEOUT); + + + status_t SendReply(BMessage* the_reply, BMessenger reply_to, bigtime_t timeout = B_INFINITE_TIMEOUT); + + + status_t SendReply(uint32 command, BMessage* reply_to_reply); + + + status_t SendReply(BMessage* the_reply, BMessage* reply_to_reply, bigtime_t send_timeout = B_INFINITE_TIMEOUT, bigtime_t reply_timeout = B_INFINITE_TIMEOUT); + + + ssize_t FlattenedSize() const; + + + status_t Flatten(char* buffer, ssize_t size) const; + + + status_t Flatten(BDataIO* stream, ssize_t* size = NULL) const; + + + status_t Unflatten(const char* flat_buffer); + + + status_t Unflatten(BDataIO* stream); + + + status_t AddSpecifier(const char* property); + + + status_t AddSpecifier(const char* property, int32 index); + + + status_t AddSpecifier(const char* property, int32 index, int32 range); + + + status_t AddSpecifier(const char* property, const char* name); + + + status_t AddSpecifier(const BMessage* specifier); + + + status_t SetCurrentSpecifier(int32 index); + + + status_t GetCurrentSpecifier(int32* index, BMessage* specifier = NULL, int32* form = NULL, const char** property = NULL) const; + + + bool HasSpecifiers() const; + + + status_t PopSpecifier(); + + + status_t AddRect(const char* name, BRect a_rect); + + + status_t AddPoint(const char* name, BPoint a_point); + + + status_t AddString(const char* name, const char* a_string); + + + status_t AddString(const char* name, const BString& a_string); + + + status_t AddInt8(const char* name, int8 val); + + + status_t AddInt16(const char* name, int16 val); + + + status_t AddInt32(const char* name, int32 val); + + + status_t AddInt64(const char* name, int64 val); + + + status_t AddBool(const char* name, bool a_boolean); + + + status_t AddFloat(const char* name, float a_float); + + + status_t AddDouble(const char* name, double a_double); + + + status_t AddPointer(const char* name, const void* ptr); + + + status_t AddMessenger(const char* name, BMessenger messenger); + + + status_t AddRef(const char* name, const entry_ref* ref); + + + status_t AddMessage(const char* name, const BMessage* msg); + + + status_t AddFlat(const char* name, BFlattenable* obj, int32 count = 1); + + + status_t AddData(const char* name, type_code type, const void* data, ssize_t numBytes, bool is_fixed_size = true, int32 count = 1); + + + status_t RemoveData(const char* name, int32 index = 0); + + + status_t RemoveName(const char* name); + + + status_t MakeEmpty(); + + + status_t FindRect(const char* name, BRect* rect) const; + + + status_t FindRect(const char* name, int32 index, BRect* rect) const; + + + status_t FindPoint(const char* name, BPoint* pt) const; + + + status_t FindPoint(const char* name, int32 index, BPoint* pt) const; + + + status_t FindString(const char* name, const char** str) const; + + + status_t FindString(const char* name, int32 index, const char** str) const; + + + status_t FindString(const char* name, BString* str) const; + + + status_t FindString(const char* name, int32 index, BString* str) const; + + + status_t FindInt8(const char* name, int8* value) const; + + + status_t FindInt8(const char* name, int32 index, int8* val) const; + + + status_t FindInt16(const char* name, int16* value) const; + + + status_t FindInt16(const char* name, int32 index, int16* val) const; + + + status_t FindInt32(const char* name, int32* value) const; + + + status_t FindInt32(const char* name, int32 index, int32* val) const; + + + status_t FindInt64(const char* name, int64* value) const; + + + status_t FindInt64(const char* name, int32 index, int64* val) const; + + + status_t FindBool(const char* name, bool* value) const; + + + status_t FindBool(const char* name, int32 index, bool* value) const; + + + status_t FindFloat(const char* name, float* f) const; + + + status_t FindFloat(const char* name, int32 index, float* f) const; + + + status_t FindDouble(const char* name, double* d) const; + + + status_t FindDouble(const char* name, int32 index, double* d) const; + + + status_t FindPointer(const char* name, void** ptr) const; + + + status_t FindPointer(const char* name, int32 index, void** ptr) const; + + + status_t FindMessenger(const char* name, BMessenger* m) const; + + + status_t FindMessenger(const char* name, int32 index, BMessenger* m) const; + + + status_t FindRef(const char* name, entry_ref* ref) const; + + + status_t FindRef(const char* name, int32 index, entry_ref* ref) const; + + + status_t FindMessage(const char* name, BMessage* msg) const; + + + status_t FindMessage(const char* name, int32 index, BMessage* msg) const; + + + status_t FindFlat(const char* name, BFlattenable* obj) const; + + + status_t FindFlat(const char* name, int32 index, BFlattenable* obj) const; + + + status_t FindData(const char* name, type_code type, const void** data, ssize_t* numBytes) const; + + + status_t FindData(const char* name, type_code type, int32 index, const void** data, ssize_t* numBytes) const; + + + status_t ReplaceRect(const char* name, BRect a_rect); + + + status_t ReplaceRect(const char* name, int32 index, BRect a_rect); + + + status_t ReplacePoint(const char* name, BPoint a_point); + + + status_t ReplacePoint(const char* name, int32 index, BPoint a_point); + + + status_t ReplaceString(const char* name, const char* string); + + + status_t ReplaceString(const char* name, int32 index, const char* string); + + + status_t ReplaceString(const char* name, const BString& string); + + + status_t ReplaceString(const char* name, int32 index, const BString& string); + + + status_t ReplaceInt8(const char* name, int8 val); + + + status_t ReplaceInt8(const char* name, int32 index, int8 val); + + + status_t ReplaceInt16(const char* name, int16 val); + + + status_t ReplaceInt16(const char* name, int32 index, int16 val); + + + status_t ReplaceInt32(const char* name, int32 val); + + + status_t ReplaceInt32(const char* name, int32 index, int32 val); + + + status_t ReplaceInt64(const char* name, int64 val); + + + status_t ReplaceInt64(const char* name, int32 index, int64 val); + + + status_t ReplaceBool(const char* name, bool a_bool); + + + status_t ReplaceBool(const char* name, int32 index, bool a_bool); + + + status_t ReplaceFloat(const char* name, float a_float); + + + status_t ReplaceFloat(const char* name, int32 index, float a_float); + + + status_t ReplaceDouble(const char* name, double a_double); + + + status_t ReplaceDouble(const char* name, int32 index, double a_double); + + + status_t ReplacePointer(const char* name, const void* ptr); + + + status_t ReplacePointer(const char* name,int32 index,const void* ptr); + + + status_t ReplaceMessenger(const char* name, BMessenger messenger); + + + status_t ReplaceMessenger(const char* name, int32 index, BMessenger msngr); + + + status_t ReplaceRef( const char* name,const entry_ref* ref); + + + status_t ReplaceRef( const char* name, int32 index, const entry_ref* ref); + + + status_t ReplaceMessage(const char* name, const BMessage* msg); + + + status_t ReplaceMessage(const char* name, int32 index, const BMessage* msg); + + + status_t ReplaceFlat(const char* name, BFlattenable* obj); + + + status_t ReplaceFlat(const char* name, int32 index, BFlattenable* obj); + + + status_t ReplaceData(const char* name, type_code type, const void* data, ssize_t data_size); + + + status_t ReplaceData(const char* name, type_code type, int32 index, const void* data, ssize_t data_size); + + + void* operator new(size_t size); + + + void operator delete(void* ptr, size_t size); + + + bool HasRect(const char* , int32 n = 0) const; + + + bool HasPoint(const char* , int32 n = 0) const; + + + bool HasString(const char* , int32 n = 0) const; + + + bool HasInt8(const char* , int32 n = 0) const; + + + bool HasInt16(const char* , int32 n = 0) const; + + + bool HasInt32(const char* , int32 n = 0) const; + + + bool HasInt64(const char* , int32 n = 0) const; + + + bool HasBool(const char* , int32 n = 0) const; + + + bool HasFloat(const char* , int32 n = 0) const; + + + bool HasDouble(const char* , int32 n = 0) const; + + + bool HasPointer(const char* , int32 n = 0) const; + + + bool HasMessenger(const char* , int32 n = 0) const; + + + bool HasRef(const char* , int32 n = 0) const; + + + bool HasMessage(const char* , int32 n = 0) const; + + + bool HasFlat(const char* , const BFlattenable* ) const; + + + bool HasFlat(const char* ,int32 ,const BFlattenable* ) const; + + + bool HasData(const char* , type_code , int32 n = 0) const; + + + BRect FindRect(const char* , int32 n = 0) const; + + + BPoint FindPoint(const char* , int32 n = 0) const; + + + const char* FindString(const char* , int32 n = 0) const; + + + int8 FindInt8(const char* , int32 n = 0) const; + + + int16 FindInt16(const char* , int32 n = 0) const; + + + int32 FindInt32(const char* , int32 n = 0) const; + + + int64 FindInt64(const char* , int32 n = 0) const; + + + bool FindBool(const char* , int32 n = 0) const; + + + float FindFloat(const char* , int32 n = 0) const; + + + double FindDouble(const char* , int32 n = 0) const; + + + BMessage(BMessage* a_message); + + + NOTE: Add convenience functions for struct rgb_color + + + + + BMessageFilter(uint32 what, filter_hook func = NULL); + + + BMessageFilter(message_delivery delivery, message_source source, filter_hook func = NULL); + + + BMessageFilter(message_delivery delivery, message_source source, uint32 what, filter_hook func = NULL); + + + BMessageFilter(const BMessageFilter& filter); + + + BMessageFilter(const BMessageFilter* filter); + + + virtual ~BMessageFilter(); + + + BMessageFilter& operator=(const BMessageFilter &from); + + + virtual filter_result Filter(BMessage* message, BHandler** target); + + + message_delivery MessageDelivery() const; + + + message_source MessageSource() const; + + + uint32 Command() const; + + + bool FiltersAnyCommand() const; + + + BLooper* Looper() const; + + + + + BMessageQueue(); + + + virtual ~BMessageQueue(); + + + void AddMessage(BMessage* an_event); + + + bool RemoveMessage(BMessage* an_event); + + + BMessage* NextMessage(); + + + BMessage* FindMessage(int32 index) const; + + + BMessage* FindMessage(uint32 what, int32 index = 0) const; + + + int32 CountMessages() const; + + + bool IsEmpty() const; + + + bool Lock(); + + + void Unlock(); + + + + + BMessageRunner(BMessenger target, const BMessage* msg, bigtime_t interval, int32 count = -1); + + + BMessageRunner(BMessenger target, const BMessage* msg, bigtime_t interval, int32 count, BMessenger reply_to); + + + virtual ~BMessageRunner(); + + + status_t InitCheck() const; + + + status_t SetInterval(bigtime_t interval); + + + status_t SetCount(int32 count); + + + status_t GetInfo(bigtime_t* interval, int32* count) const; + + + + + BMessenger(); + + + BMessenger(const char* mime_sig, team_id team = -1, status_t* perr = NULL); + + + BMessenger(const BHandler* handler, const BLooper* looper = NULL, status_t* perr = NULL); + + + BMessenger(const BMessenger& from); + + + ~BMessenger(); + + + bool IsTargetLocal() const; + + + BHandler* Target(BLooper** looper) const; + + + bool LockTarget() const; + + + status_t LockTargetWithTimeout(bigtime_t timeout) const; + + + status_t SendMessage(uint32 command, BHandler* reply_to = NULL) const; + + + status_t SendMessage(BMessage* a_message, BHandler* reply_to = NULL, bigtime_t timeout = B_INFINITE_TIMEOUT) const; + + + status_t SendMessage(BMessage* a_message, BMessenger reply_to, bigtime_t timeout = B_INFINITE_TIMEOUT) const; + + + status_t SendMessage(uint32 command, BMessage* reply) const; + + + status_t SendMessage(BMessage* a_message, BMessage* reply, bigtime_t send_timeout = B_INFINITE_TIMEOUT, bigtime_t reply_timeout = B_INFINITE_TIMEOUT) const; + + + BMessenger& operator=(const BMessenger &from); + + + bool operator==(const BMessenger &other) const; + + + bool IsValid() const; + + + team_id Team() const; + + + + + bool operator<(const BMessenger & a, const BMessenger & b); + + + bool operator!=(const BMessenger & a, const BMessenger & b); + + +
+
+ + + BHandler(const char* name = NULL); + + + BHandler(BMessage* data); + + + virtual ~BHandler(); + + + static BArchivable* Instantiate(BMessage* data); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + virtual void MessageReceived(BMessage* message); + + + BLooper* Looper() const; + + + void SetName(const char* name); + + + const char* Name() const; + + + virtual void SetNextHandler(BHandler* handler); + + + BHandler* NextHandler() const; + + + virtual void AddFilter(BMessageFilter* filter); + + + virtual bool RemoveFilter(BMessageFilter* filter); + + + virtual void SetFilterList(BList* filters); + + + BList* FilterList(); + + + bool LockLooper(); + + + status_t LockLooperWithTimeout(bigtime_t timeout); + + + void UnlockLooper(); + + + virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); + + + virtual status_t GetSupportedSuites(BMessage* data); + + + status_t StartWatching(BMessenger, uint32 what); + + + status_t StartWatchingAll(BMessenger); + + + status_t StopWatching(BMessenger, uint32 what); + + + status_t StopWatchingAll(BMessenger); + + + status_t StartWatching(BHandler* , uint32 what); + + + status_t StartWatchingAll(BHandler* ); + + + status_t StopWatching(BHandler* , uint32 what); + + + status_t StopWatchingAll(BHandler* ); + + + virtual void SendNotices(uint32 what, const BMessage* = 0); + + + bool IsWatched() const; + + +
+
+ + + BLooper(const char* name = NULL, int32 priority = B_NORMAL_PRIORITY, int32 port_capacity = B_LOOPER_PORT_DEFAULT_CAPACITY); + + + BLooper(BMessage* data); + + + virtual ~BLooper(); + + + static BArchivable* Instantiate(BMessage* data); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + status_t PostMessage(uint32 command); + + + status_t PostMessage(BMessage* message); + + + status_t PostMessage(uint32 command, BHandler* handler, BHandler* reply_to = NULL); + + + status_t PostMessage(BMessage* message, BHandler* handler, BHandler* reply_to = NULL); + + + virtual void DispatchMessage(BMessage* message, BHandler* handler); + + + virtual void MessageReceived(BMessage* msg); + + + BMessage* CurrentMessage() const; + + + BMessage* DetachCurrentMessage(); + + + BMessageQueue* MessageQueue() const; + + + bool IsMessageWaiting() const; + + + void AddHandler(BHandler* handler); + + + bool RemoveHandler(BHandler* handler); + + + int32 CountHandlers() const; + + + BHandler* HandlerAt(int32 index) const; + + + int32 IndexOf(BHandler* handler) const; + + + BHandler* PreferredHandler() const; + + + void SetPreferredHandler(BHandler* handler); + + + virtual thread_id Run(); + + + virtual void Quit(); + + + virtual bool QuitRequested(); + + + bool Lock(); + + + void Unlock(); + + + bool IsLocked() const; + + + status_t LockWithTimeout(bigtime_t timeout); + + + thread_id Thread() const; + + + team_id Team() const; + + + static BLooper* LooperForThread(thread_id tid); + + + thread_id LockingThread() const; + + + int32 CountLocks() const; + + + int32 CountLockRequests() const; + + + sem_id Sem() const; + + + virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); + + + virtual status_t GetSupportedSuites(BMessage* data); + + + virtual void AddCommonFilter(BMessageFilter* filter); + + + virtual bool RemoveCommonFilter(BMessageFilter* filter); + + + virtual void SetCommonFilterList(BList* filters); + + + BList* CommonFilterList() const; + + + BMessage* MessageFromPort(bigtime_t = B_INFINITE_TIMEOUT); + + + virtual void task_looper(); + + +
+
+ + + BRoster(); + + + ~BRoster(); + + + bool IsRunning(const char* mime_sig) const; + + + bool IsRunning(entry_ref* ref) const; + + + team_id TeamFor(const char* mime_sig) const; + + + team_id TeamFor(entry_ref* ref) const; + + + void GetAppList(BList* team_id_list) const; + + + void GetAppList(const char* sig, BList* team_id_list) const; + + + status_t GetAppInfo(const char* sig, app_info* info) const; + + + status_t GetAppInfo(entry_ref* ref, app_info* info) const; + + + status_t GetRunningAppInfo(team_id team, app_info* info) const; + + + status_t GetActiveAppInfo(app_info* info) const; + + + status_t FindApp(const char* mime_type, entry_ref* app) const; + + + status_t FindApp(entry_ref* ref, entry_ref* app) const; + + + status_t Broadcast(BMessage* msg) const; + + + status_t Broadcast(BMessage* msg, BMessenger reply_to) const; + + + status_t StartWatching(BMessenger target, uint32 event_mask = B_REQUEST_LAUNCHED | B_REQUEST_QUIT) const; + + + status_t StopWatching(BMessenger target) const; + + + status_t ActivateApp(team_id team) const; + + + status_t Launch(const char* mime_type, BMessage* initial_msgs = NULL, team_id* app_team = NULL) const; + + + status_t Launch(const char* mime_type, BList* message_list, team_id* app_team = NULL) const; + + + status_t Launch(const char* mime_type, int argc, char** args, team_id* app_team = NULL) const; + + + status_t Launch(const entry_ref* ref, const BMessage* initial_message = NULL, team_id* app_team = NULL) const; + + + status_t Launch(const entry_ref* ref, const BList* message_list, team_id* app_team = NULL) const; + + + status_t Launch(const entry_ref* ref, int argc, const char* const* args, team_id* app_team = NULL) const; + + + void GetRecentDocuments(BMessage* refList, int32 maxCount, const char* ofType = NULL, const char* openedByAppSig = NULL) const; + + + void GetRecentDocuments(BMessage* refList, int32 maxCount, const char* ofTypeList[], int32 ofTypeListCount, const char* openedByAppSig = NULL) const; + + + void GetRecentFolders(BMessage* refList, int32 maxCount, const char* openedByAppSig = NULL) const; + + + void GetRecentApps(BMessage* refList, int32 maxCount) const; + + + void AddToRecentDocuments(const entry_ref* doc, const char* appSig = NULL) const; + + + void AddToRecentFolders(const entry_ref* folder,const char* appSig = NULL) const; + + +
+
+ + + BClipboard(const char* name, bool transient = false); + + + virtual ~BClipboard(); + + + const char* Name() const; + + + uint32 LocalCount() const; + + + uint32 SystemCount() const; + + + status_t StartWatching(BMessenger target); + + + status_t StopWatching(BMessenger target); + + + bool Lock(); + + + void Unlock(); + + + bool IsLocked() const; + + + status_t Clear(); + + + status_t Commit(); + + + status_t Revert(); + + + BMessenger DataSource() const; + + + BMessage* Data() const; + + +
+
+ + + BCursor(const void* cursorData); + + + BCursor(BMessage* data); + + + virtual ~BCursor(); + + + virtual status_t Archive(BMessage* into, bool deep = true) const; + + + static BArchivable* Instantiate(BMessage* data); + + +
+
+ + + BPropertyInfo(property_info* p = NULL, value_info* ci = NULL, bool free_on_delete = false); + + + virtual ~BPropertyInfo(); + + + virtual int32 FindMatch(BMessage* msg, int32 index, BMessage* spec, int32 form, const char* prop, void* data = NULL) const; + + + virtual bool IsFixedSize() const; + + + virtual type_code TypeCode() const; + + + virtual ssize_t FlattenedSize() const; + + + virtual status_t Flatten(void* buffer, ssize_t size) const; + + + virtual bool AllowsTypeCode(type_code code) const; + + + virtual status_t Unflatten(type_code c, const void* buf, ssize_t s); + + + const property_info* Properties() const; + + + const value_info* Values() const; + + + int32 CountProperties() const; + + + int32 CountValues() const; + + + void PrintToStream() const; + + + static bool FindCommand(uint32, int32, property_info* ); + + + static bool FindSpecifier(uint32, property_info* ); + + +
+
+ +
+ + + BPoint(); + + + BPoint(float X, float Y); + + + BPoint(const BPoint& pt); + + + BPoint& operator=(const BPoint& from); + + + void Set(float X, float Y); + + + void ConstrainTo(BRect rect); + + + void PrintToStream() const; + + + BPoint operator+(const BPoint&) const; + + + BPoint operator-(const BPoint&) const; + + + BPoint& operator+=(const BPoint&); + + + BPoint& operator-=(const BPoint&); + + + bool operator!=(const BPoint&) const; + + + bool operator==(const BPoint&) const; + + + + + BPolygon(const BPoint* ptArray, int32 numPoints); + + + BPolygon(); + + + BPolygon(const BPolygon* poly); + + + virtual ~BPolygon(); + + + BPolygon& operator=(const BPolygon& from); + + + BRect Frame() const; + + + void AddPoints(const BPoint* ptArray, int32 numPoints); + + + int32 CountPoints() const; + + + void MapTo(BRect srcRect, BRect dstRect); + + + void PrintToStream() const; + + + + + BRect(); + + + BRect(const BRect &); + + + BRect(float l, float t, float r, float b); + + + BRect(BPoint leftTop, BPoint rightBottom); + + + BRect& operator=(const BRect &from); + + + void Set(float l, float t, float r, float b); + + + void PrintToStream() const; + + + BPoint LeftTop() const; + + + BPoint RightBottom() const; + + + BPoint LeftBottom() const; + + + BPoint RightTop() const; + + + void SetLeftTop(const BPoint); + + + void SetRightBottom(const BPoint); + + + void SetLeftBottom(const BPoint); + + + void SetRightTop(const BPoint); + + + void InsetBy(BPoint); + + + void InsetBy(float dx, float dy); + + + void OffsetBy(BPoint); + + + void OffsetBy(float dx, float dy); + + + void OffsetTo(BPoint); + + + void OffsetTo(float x, float y); + + + BRect& InsetBySelf(BPoint); + + + BRect& InsetBySelf(float dx, float dy); + + + BRect InsetByCopy(BPoint); + + + BRect InsetByCopy(float dx, float dy); + + + BRect& OffsetBySelf(BPoint); + + + BRect& OffsetBySelf(float dx, float dy); + + + BRect OffsetByCopy(BPoint); + + + BRect OffsetByCopy(float dx, float dy); + + + BRect& OffsetToSelf(BPoint); + + + BRect& OffsetToSelf(float dx, float dy); + + + BRect OffsetToCopy(BPoint); + + + BRect OffsetToCopy(float dx, float dy); + + + bool operator==(BRect) const; + + + bool operator!=(BRect) const; + + + BRect operator&(BRect) const; + + + BRect operator|(BRect) const; + + + bool Intersects(BRect r) const; + + + bool IsValid() const; + + + float Width() const; + + + int32 IntegerWidth() const; + + + float Height() const; + + + int32 IntegerHeight() const; + + + bool Contains(BPoint) const; + + + bool Contains(BRect) const; + + + + + BRegion(); + + + BRegion(const BRegion ®ion); + + + BRegion(const BRect rect); + + + virtual ~BRegion(); + + + BRegion& operator=(const BRegion &from); + + + BRect Frame() const; + + + clipping_rect FrameInt() const; + + + BRect RectAt(int32 index); + + + clipping_rect RectAtInt(int32 index); + + + int32 CountRects(); + + + void Set(BRect newBounds); + + + void Set(clipping_rect newBounds); + + + bool Intersects(BRect r) const; + + + bool Intersects(clipping_rect r) const; + + + bool Contains(BPoint pt) const; + + + bool Contains(int32 x, int32 y); + + + void PrintToStream() const; + + + void OffsetBy(int32 dh, int32 dv); + + + void MakeEmpty(); + + + void Include(BRect r); + + + void Include(clipping_rect r); + + + void Include(const BRegion*); + + + void Exclude(BRect r); + + + void Exclude(clipping_rect r); + + + void Exclude(const BRegion*); + + + void IntersectWith(const BRegion*); + + +
+
+ + + BPicture(); + + + BPicture(const BPicture &original); + + + BPicture(BMessage* data); + + + virtual ~BPicture(); + + + static BArchivable* Instantiate(BMessage* data); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + virtual status_t Perform(perform_code d, void* arg); + + + status_t Play(void* *callBackTable, int32 tableEntries, void* userData); + + + status_t Flatten(BDataIO* stream); + + + status_t Unflatten(BDataIO* stream); + + + + + BScreen(screen_id id = B_MAIN_SCREEN_ID); + + + BScreen(BWindow* win); + + + ~BScreen(); + + + bool IsValid(); + + + status_t SetToNext(); + + + color_space ColorSpace(); + + + BRect Frame(); + + + screen_id ID(); + + + status_t WaitForRetrace(); + + + status_t WaitForRetrace(bigtime_t timeout); + + + uint8 IndexForColor(rgb_color rgb); + + + uint8 IndexForColor(uint8 r, uint8 g, uint8 b, uint8 a = 255); + + + rgb_color ColorForIndex(const uint8 index); + + + uint8 InvertIndex(uint8 index); + + + const color_map* ColorMap(); + + + status_t GetBitmap(BBitmap** screen_shot, bool draw_cursor = true, BRect* bound = NULL); + + + status_t ReadBitmap(BBitmap* buffer, bool draw_cursor = true, BRect* bound = NULL); + + + rgb_color DesktopColor(); + + + rgb_color DesktopColor(uint32 index); + + + void SetDesktopColor(rgb_color rgb, bool stick = true); + + + void SetDesktopColor(rgb_color rgb, uint32 index, bool stick = true); + + + status_t ProposeMode(display_mode* target, const display_mode* low, const display_mode* high); + + + status_t GetModeList(display_mode** mode_list, uint32* count); + + + status_t GetMode(display_mode* mode); + + + status_t GetMode(uint32 workspace, display_mode* mode); + + + status_t SetMode(display_mode* mode, bool makeDefault = false); + + + status_t SetMode(uint32 workspace, display_mode* mode, bool makeDefault = false); + + + status_t GetDeviceInfo(accelerant_device_info* adi); + + + status_t GetPixelClockLimits(display_mode* mode, uint32* low, uint32* high); + + + status_t GetTimingConstraints(display_timing_constraints* dtc); + + + status_t SetDPMS(uint32 dpms_state); + + + uint32 DPMSState(void); + + + uint32 DPMSCapabilites(void); + + + BPrivateScreen* private_screen(); + + + + + BShape(); + + + BShape(const BShape& copyFrom); + + + BShape(BMessage* data); + + + virtual ~BShape(); + + + virtual status_t Archive(BMessage* into, bool deep = true) const; + + + static BArchivable* Instantiate(BMessage* data); + + + void Clear(); + + + BRect Bounds() const; + + + status_t AddShape(const BShape* other); + + + status_t MoveTo(BPoint point); + + + status_t LineTo(BPoint linePoint); + + + status_t BezierTo(BPoint controlPoints[3]); + + + status_t Close(); + + + + + BShapeIterator(); + + + virtual ~BShapeIterator(); + + + virtual status_t IterateMoveTo(BPoint* point); + + + virtual status_t IterateLineTo(int32 lineCount, BPoint* linePts); + + + virtual status_t IterateBezierTo(int32 bezierCount, BPoint* bezierPts); + + + virtual status_t IterateClose(); + + + status_t Iterate(BShape* shape); + + + + + const color_map* system_colors(); + + + status_t set_screen_space(int32 index, uint32 res, bool stick = true); + + +
+
+ + + BBitmap(BRect bounds, uint32 flags, color_space depth, int32 bytesPerRow=B_ANY_BYTES_PER_ROW, screen_id screenID=B_MAIN_SCREEN_ID); + + + BBitmap(BRect bounds, color_space depth, bool accepts_views = false, bool need_contiguous = false); + + + BBitmap(const BBitmap* source, bool accepts_views = false, bool need_contiguous = false); + + + BBitmap(BMessage* data); + + + virtual ~BBitmap(); + + + static BArchivable* Instantiate(BMessage* data); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + status_t InitCheck() const; + + + bool IsValid() const; + + + status_t LockBits(uint32* state=NULL); + + + void UnlockBits(); + + + area_id Area() const; + + + void* Bits() const; + + + int32 BitsLength() const; + + + int32 BytesPerRow() const; + + + color_space ColorSpace() const; + + + BRect Bounds() const; + + + void SetBits(const void* data, int32 length, int32 offset, color_space cs); + + + status_t GetOverlayRestrictions(overlay_restrictions* restrict) const; + + + virtual void AddChild(BView* view); + + + virtual bool RemoveChild(BView* view); + + + int32 CountChildren() const; + + + BView* ChildAt(int32 index) const; + + + BView* FindView(const char* view_name) const; + + + BView* FindView(BPoint point) const; + + + bool Lock(); + + + void Unlock(); + + + bool IsLocked() const; + + + + + BFont(); + + + BFont(const BFont &font); + + + BFont(const BFont* font); + + + status_t SetFamilyAndStyle(const font_family family, + + + void SetFamilyAndStyle(uint32 code); + + + status_t SetFamilyAndFace(const font_family family, uint16 face); + + + void SetSize(float size); + + + void SetShear(float shear); + + + void SetRotation(float rotation); + + + void SetSpacing(uint8 spacing); + + + void SetEncoding(uint8 encoding); + + + void SetFace(uint16 face); + + + void SetFlags(uint32 flags); + + + void GetFamilyAndStyle(font_family* family, font_style* style) const; + + + uint32 FamilyAndStyle() const; + + + float Size() const; + + + float Shear() const; + + + float Rotation() const; + + + uint8 Spacing() const; + + + uint8 Encoding() const; + + + uint16 Face() const; + + + uint32 Flags() const; + + + font_direction Direction() const; + + + bool IsFixed() const; + + + bool IsFullAndHalfFixed() const; + + + BRect BoundingBox() const; + + + unicode_block Blocks() const; + + + font_file_format FileFormat() const; + + + int32 CountTuned() const; + + + void GetTunedInfo(int32 index, tuned_font_info* info) const; + + + void TruncateString(BString* in_out, uint32 mode, float width) const; + + + void GetTruncatedStrings(const char* stringArray[], int32 numStrings, uint32 mode, float width, BString resultArray[]) const; + + + void GetTruncatedStrings(const char* stringArray[], int32 numStrings, uint32 mode, float width, char* resultArray[]) const; + + + float StringWidth(const char* string) const; + + + float StringWidth(const char* string, int32 length) const; + + + void GetStringWidths(const char* stringArray[], const int32 lengthArray[], int32 numStrings, float widthArray[]) const; + + + void GetEscapements(const char charArray[], int32 numChars, float escapementArray[]) const; + + + void GetEscapements(const char charArray[], int32 numChars, escapement_delta* delta, float escapementArray[]) const; + + + void GetEscapements(const char charArray[], int32 numChars, escapement_delta* delta, BPoint escapementArray[]) const; + + + void GetEscapements(const char charArray[], int32 numChars, escapement_delta* delta, BPoint escapementArray[], BPoint offsetArray[]) const; + + + void GetEdges(const char charArray[], int32 numBytes, edge_info edgeArray[]) const; + + + void GetHeight(font_height* height) const; + + + void GetBoundingBoxesAsGlyphs(const char charArray[], int32 numChars, font_metric_mode mode, BRect boundingBoxArray[]) const; + + + void GetBoundingBoxesAsString(const char charArray[], int32 numChars, font_metric_mode mode, escapement_delta* delta, BRect boundingBoxArray[]) const; + + + void GetBoundingBoxesForStrings(const char* stringArray[], int32 numStrings, font_metric_mode mode, escapement_delta deltas[], BRect boundingBoxArray[]) const; + + + void GetGlyphShapes(const char charArray[], int32 numChars, BShape* glyphShapeArray[]) const; + + + void GetHasGlyphs(const char charArray[], int32 numChars, bool hasArray[]) const; + + + BFont& operator=(const BFont &font); + + + bool operator==(const BFont &font) const; + + + bool operator!=(const BFont &font) const; + + + void PrintToStream() const; + + + + + int32 count_font_families(); + + + status_t get_font_family(int32 index, font_family* name, uint32* flags = NULL); + + + int32 count_font_styles(font_family name); + + + status_t get_font_style(font_family family, int32 index, font_style* name, uint32* flags = NULL); + + + status_t get_font_style(font_family family, int32 index, font_style* name, uint16* face, uint32* flags = NULL); + + + bool update_font_families(bool check_only); + + + status_t get_font_cache_info(uint32 id, void* set); + + + status_t set_font_cache_info(uint32 id, void* set); + + +
+
+ + + BControl(BRect frame, const char* name, const char* label, BMessage* message, uint32 resizeMask, uint32 flags); + + + BControl(BMessage* data); + + + virtual ~BControl(); + + + static BArchivable* Instantiate(BMessage* data); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + virtual void WindowActivated(bool state); + + + virtual void AttachedToWindow(); + + + virtual void MessageReceived(BMessage* msg); + + + virtual void MakeFocus(bool state = true); + + + virtual void KeyDown(const char* bytes, int32 numBytes); + + + virtual void MouseDown(BPoint pt); + + + virtual void MouseUp(BPoint pt); + + + virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg); + + + virtual void DetachedFromWindow(); + + + virtual void SetLabel(const char* text); + + + const char* Label() const; + + + virtual void SetValue(int32 value); + + + int32 Value() const; + + + virtual void SetEnabled(bool on); + + + bool IsEnabled() const; + + + virtual void GetPreferredSize(float* width, float* height); + + + virtual void ResizeToPreferred(); + + + virtual status_t Invoke(BMessage* msg = NULL); + + + virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); + + + virtual status_t GetSupportedSuites(BMessage* data); + + + virtual void AllAttached(); + + + virtual void AllDetached(); + + + bool IsFocusChanging() const; + + + bool IsTracking() const; + + + void SetTracking(bool state); + + + void SetValueNoUpdate(int32 value); + + + + + BButton(BRect frame, const char* name, const char* label, BMessage* message, uint32 resizeMask = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW | B_NAVIGABLE); + + + BButton(BMessage* data); + + + virtual ~BButton(); + + + static BArchivable* Instantiate(BMessage* data); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + virtual void Draw(BRect updateRect); + + + virtual void MouseDown(BPoint where); + + + virtual void AttachedToWindow(); + + + virtual void KeyDown(const char* bytes, int32 numBytes); + + + virtual void MakeDefault(bool state); + + + virtual void SetLabel(const char* text); + + + bool IsDefault() const; + + + virtual void MessageReceived(BMessage* msg); + + + virtual void WindowActivated(bool state); + + + virtual void MouseUp(BPoint pt); + + + virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg); + + + virtual void DetachedFromWindow(); + + + virtual void SetValue(int32 value); + + + virtual void GetPreferredSize(float* width, float* height); + + + virtual void ResizeToPreferred(); + + + virtual status_t Invoke(BMessage* msg = NULL); + + + virtual void FrameMoved(BPoint new_position); + + + virtual void FrameResized(float new_width, float new_height); + + + virtual void MakeFocus(bool state = true); + + + virtual void AllAttached(); + + + virtual void AllDetached(); + + + virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); + + + virtual status_t GetSupportedSuites(BMessage* data); + + + + + BCheckBox(BRect frame, const char* name, const char* label, BMessage* message, uint32 resizeMask = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW | B_NAVIGABLE); + + + BCheckBox(BMessage* data); + + + virtual ~BCheckBox(); + + + static BArchivable* Instantiate(BMessage* data); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + virtual void Draw(BRect updateRect); + + + virtual void AttachedToWindow(); + + + virtual void MouseDown(BPoint where); + + + virtual void MessageReceived(BMessage* msg); + + + virtual void WindowActivated(bool state); + + + virtual void KeyDown(const char* bytes, int32 numBytes); + + + virtual void MouseUp(BPoint pt); + + + virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg); + + + virtual void DetachedFromWindow(); + + + virtual void SetValue(int32 value); + + + virtual void GetPreferredSize(float* width, float* height); + + + virtual void ResizeToPreferred(); + + + virtual status_t Invoke(BMessage* msg = NULL); + + + virtual void FrameMoved(BPoint new_position); + + + virtual void FrameResized(float new_width, float new_height); + + + virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); + + + virtual status_t GetSupportedSuites(BMessage* data); + + + virtual void MakeFocus(bool state = true); + + + virtual void AllAttached(); + + + virtual void AllDetached(); + + + + + BColorControl(BPoint start, color_control_layout layout, float cell_size, const char *name, BMessage *message = NULL, bool use_offscreen = false); + + + BColorControl(BMessage *data); + + + virtual ~BColorControl(); + + + static BArchivable *Instantiate(BMessage *data); + + + virtual status_t Archive(BMessage *data, bool deep = true) const; + + + virtual void SetValue(int32 color_value); + + + void SetValue(rgb_color color); + + + rgb_color ValueAsColor(); + + + virtual void SetEnabled(bool state); + + + virtual void AttachedToWindow(); + + + virtual void MessageReceived(BMessage *msg); + + + virtual void Draw(BRect updateRect); + + + virtual void MouseDown(BPoint where); + + + virtual void KeyDown(const char *bytes, int32 numBytes); + + + virtual void SetCellSize(float size); + + + float CellSize() const; + + + virtual void SetLayout(color_control_layout layout); + + + color_control_layout Layout() const; + + + virtual void WindowActivated(bool state); + + + virtual void MouseUp(BPoint pt); + + + virtual void MouseMoved(BPoint pt, uint32 code, const BMessage *msg); + + + virtual void DetachedFromWindow(); + + + virtual void GetPreferredSize(float *width, float *height); + + + virtual void ResizeToPreferred(); + + + virtual status_t Invoke(BMessage *msg = NULL); + + + virtual void FrameMoved(BPoint new_position); + + + virtual void FrameResized(float new_width, float new_height); + + + virtual BHandler *ResolveSpecifier(BMessage *msg, int32 index, BMessage *specifier, int32 form, const char *property); + + + virtual status_t GetSupportedSuites(BMessage *data); + + + virtual void MakeFocus(bool state = true); + + + virtual void AllAttached(); + + + virtual void AllDetached(); + + + + + BPictureButton(BRect frame, const char* name, BPicture* off, BPicture* on, BMessage* message, uint32 behavior = B_ONE_STATE_BUTTON, uint32 resizeMask = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flgs = B_WILL_DRAW | B_NAVIGABLE); + + + BPictureButton(BMessage* data); + + + virtual ~BPictureButton(); + + + static BArchivable* Instantiate(BMessage* data); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + virtual void Draw(BRect updateRect); + + + virtual void MouseDown(BPoint where); + + + virtual void KeyDown(const char* bytes, int32 numBytes); + + + virtual void SetEnabledOn(BPicture* on); + + + virtual void SetEnabledOff(BPicture* off); + + + virtual void SetDisabledOn(BPicture* on); + + + virtual void SetDisabledOff(BPicture* off); + + + BPicture* EnabledOn() const; + + + BPicture* EnabledOff() const; + + + BPicture* DisabledOn() const; + + + BPicture* DisabledOff() const; + + + virtual void SetBehavior(uint32 behavior); + + + uint32 Behavior() const; + + + virtual void MessageReceived(BMessage* msg); + + + virtual void MouseUp(BPoint pt); + + + virtual void WindowActivated(bool state); + + + virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg); + + + virtual void AttachedToWindow(); + + + virtual void DetachedFromWindow(); + + + virtual void SetValue(int32 value); + + + virtual status_t Invoke(BMessage* msg = NULL); + + + virtual void FrameMoved(BPoint new_position); + + + virtual void FrameResized(float new_width, float new_height); + + + virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); + + + virtual status_t GetSupportedSuites(BMessage* data); + + + virtual void ResizeToPreferred(); + + + virtual void GetPreferredSize(float* width, float* height); + + + virtual void MakeFocus(bool state = true); + + + virtual void AllAttached(); + + + virtual void AllDetached(); + + + + + BRadioButton(BRect frame, const char* name, const char* label, BMessage* message, uint32 resizMask = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW | B_NAVIGABLE); + + + BRadioButton(BMessage* data); + + + virtual ~BRadioButton(); + + + static BArchivable* Instantiate(BMessage* data); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + virtual void Draw(BRect updateRect); + + + virtual void MouseDown(BPoint where); + + + virtual void AttachedToWindow(); + + + virtual void KeyDown(const char* bytes, int32 numBytes); + + + virtual void SetValue(int32 value); + + + virtual void GetPreferredSize(float* width, float* height); + + + virtual void ResizeToPreferred(); + + + virtual status_t Invoke(BMessage* msg = NULL); + + + virtual void MessageReceived(BMessage* msg); + + + virtual void WindowActivated(bool state); + + + virtual void MouseUp(BPoint pt); + + + virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg); + + + virtual void DetachedFromWindow(); + + + virtual void FrameMoved(BPoint new_position); + + + virtual void FrameResized(float new_width, float new_height); + + + virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); + + + virtual void MakeFocus(bool state = true); + + + virtual void AllAttached(); + + + virtual void AllDetached(); + + + virtual status_t GetSupportedSuites(BMessage* data); + + + + + BSlider(BRect frame, const char* name, const char* label, BMessage* message, int32 minValue, int32 maxValue, thumb_style thumbType = B_BLOCK_THUMB, uint32 resizingMode = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_NAVIGABLE | B_WILL_DRAW | B_FRAME_EVENTS); + + + BSlider(BRect frame, const char* name, const char* label, BMessage* message, int32 minValue, int32 maxValue, orientation posture /*= B_HORIZONTAL*/, thumb_style thumbType = B_BLOCK_THUMB, uint32 resizingMode = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_NAVIGABLE | B_WILL_DRAW | B_FRAME_EVENTS); + + + BSlider(BMessage* data); + + + virtual ~BSlider(); + + + static BArchivable* Instantiate(BMessage* data); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + virtual status_t Perform(perform_code d, void* arg); + + + virtual void WindowActivated(bool state); + + + virtual void AttachedToWindow(); + + + virtual void AllAttached(); + + + virtual void AllDetached(); + + + virtual void DetachedFromWindow(); + + + virtual void MessageReceived(BMessage* msg); + + + virtual void FrameMoved(BPoint new_position); + + + virtual void FrameResized(float w,float h); + + + virtual void KeyDown(const char* bytes, int32 n); + + + virtual void MouseDown(BPoint); + + + virtual void MouseUp(BPoint pt); + + + virtual void MouseMoved(BPoint pt, uint32 c, const BMessage* m); + + + virtual void Pulse(); + + + virtual void SetLabel(const char* label); + + + virtual void SetLimitLabels(const char* minLabel, const char* maxLabel); + + + const char* MinLimitLabel() const; + + + const char* MaxLimitLabel() const; + + + virtual void SetValue(int32); + + + virtual int32 ValueForPoint(BPoint) const; + + + virtual void SetPosition(float); + + + float Position() const; + + + virtual void SetEnabled(bool on); + + + void GetLimits(int32* minimum, int32* maximum); + + + virtual void Draw(BRect); + + + virtual void DrawSlider(); + + + virtual void DrawBar(); + + + virtual void DrawHashMarks(); + + + virtual void DrawThumb(); + + + virtual void DrawFocusMark(); + + + virtual void DrawText(); + + + virtual char* UpdateText() const; + + + virtual BRect BarFrame() const; + + + virtual BRect HashMarksFrame() const; + + + virtual BRect ThumbFrame() const; + + + virtual void SetFlags(uint32 flags); + + + virtual void SetResizingMode(uint32 mode); + + + virtual void GetPreferredSize( float* width, float* height); + + + virtual void ResizeToPreferred(); + + + virtual status_t Invoke(BMessage* msg=NULL); + + + virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); + + + virtual status_t GetSupportedSuites(BMessage* data); + + + virtual void SetModificationMessage(BMessage* message); + + + BMessage* ModificationMessage() const; + + + virtual void SetSnoozeAmount(int32); + + + int32 SnoozeAmount() const; + + + virtual void SetKeyIncrementValue(int32 value); + + + int32 KeyIncrementValue() const; + + + virtual void SetHashMarkCount(int32 count); + + + int32 HashMarkCount() const; + + + virtual void SetHashMarks(hash_mark_location where); + + + hash_mark_location HashMarks() const; + + + virtual void SetStyle(thumb_style s); + + + thumb_style Style() const; + + + virtual void SetBarColor(rgb_color); + + + rgb_color BarColor() const; + + + virtual void UseFillColor(bool, const rgb_color* c=NULL); + + + bool FillColor(rgb_color*) const; + + + BView* OffscreenView() const; + + + orientation Orientation() const; + + + virtual void SetOrientation(orientation); + + + float BarThickness() const; + + + virtual void SetBarThickness(float thickness); + + + virtual void SetFont(const BFont* font, uint32 properties = B_FONT_ALL); + + + + + BTab(BView* contents=NULL); + + + BTab(BMessage* data); + + + virtual ~BTab(); + + + static BArchivable* Instantiate(BMessage* data); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + virtual status_t Perform(uint32 d, void* arg); + + + const char* Label() const; + + + virtual void SetLabel(const char* label); + + + bool IsSelected() const; + + + virtual void Select(BView* owner); + + + virtual void Deselect(); + + + virtual void SetEnabled(bool on); + + + bool IsEnabled() const; + + + void MakeFocus(bool infocus=true); + + + bool IsFocus() const; + + + virtual void SetView(BView* contents); + + + BView* View() const; + + + virtual void DrawFocusMark(BView* owner, BRect tabFrame); + + + virtual void DrawLabel(BView* owner, BRect tabFrame); + + + virtual void DrawTab(BView* owner, BRect tabFrame, tab_position, bool full=true); + + + + + BTabView(BRect frame, const char* name, button_width width = B_WIDTH_AS_USUAL, uint32 resizingMode = B_FOLLOW_ALL, uint32 flags = B_FULL_UPDATE_ON_RESIZE | B_WILL_DRAW | B_NAVIGABLE_JUMP | B_FRAME_EVENTS | B_NAVIGABLE); + + + BTabView(BMessage*); + + + virtual ~BTabView(); + + + static BArchivable* Instantiate(BMessage*); + + + virtual status_t Archive(BMessage*, bool deep=true) const; + + + virtual status_t Perform(perform_code d, void* arg); + + + virtual void WindowActivated(bool state); + + + virtual void AttachedToWindow(); + + + virtual void AllAttached(); + + + virtual void AllDetached(); + + + virtual void DetachedFromWindow(); + + + virtual void MessageReceived(BMessage* msg); + + + virtual void FrameMoved(BPoint new_position); + + + virtual void FrameResized(float w,float h); + + + virtual void KeyDown(const char* bytes, int32 n); + + + virtual void MouseDown(BPoint); + + + virtual void MouseUp(BPoint); + + + virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg); + + + virtual void Pulse(); + + + virtual void Select(int32 tabIndex); + + + int32 Selection() const; + + + virtual void MakeFocus(bool focusState = true); + + + virtual void SetFocusTab(int32 tabIndex, bool focusState); + + + int32 FocusTab() const; + + + virtual void Draw(BRect); + + + virtual BRect DrawTabs(); + + + virtual void DrawBox(BRect selectedTabFrame); + + + virtual BRect TabFrame(int32 tabIndex) const; + + + virtual void SetFlags(uint32 flags); + + + virtual void SetResizingMode(uint32 mode); + + + virtual void GetPreferredSize( float* width, float* height); + + + virtual void ResizeToPreferred(); + + + virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); + + + virtual status_t GetSupportedSuites(BMessage* data); + + + virtual void AddTab(BView* tabContents, BTab* tab=NULL); + + + virtual BTab* RemoveTab(int32 tabIndex); + + + virtual BTab* TabAt(int32 tabIndex) const; + + + virtual void SetTabWidth(button_width s); + + + button_width TabWidth() const; + + + virtual void SetTabHeight(float height); + + + float TabHeight() const; + + + BView* ContainerView() const; + + + int32 CountTabs() const; + + + BView* ViewForTab(int32 tabIndex) const; + + +
+
+ + + BBox(BRect bounds, const char* name = NULL, uint32 resizeFlags = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP, border_style border = B_FANCY_BORDER); + + + BBox(BMessage* data); + + + virtual ~BBox(void); + + + static BArchivable* Instantiate(BMessage* data); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + virtual void SetBorder(border_style style); + + + border_style Border() const; + + + void SetLabel(const char* label); + + + status_t SetLabel(BView* view_label); + + + const char* Label() const; + + + BView* LabelView() const; + + + virtual void Draw(BRect bounds); + + + virtual void AttachedToWindow(); + + + virtual void DetachedFromWindow(); + + + virtual void AllAttached(); + + + virtual void AllDetached(); + + + virtual void FrameResized(float new_width, float new_height); + + + virtual void MessageReceived(BMessage* msg); + + + virtual void MouseDown(BPoint pt); + + + virtual void MouseUp(BPoint pt); + + + virtual void WindowActivated(bool state); + + + virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg); + + + virtual void FrameMoved(BPoint new_position); + + + virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); + + + virtual void ResizeToPreferred(); + + + virtual void GetPreferredSize(float* width, float* height); + + + virtual void MakeFocus(bool state = true); + + + virtual status_t GetSupportedSuites(BMessage* data); + + + + + BStringView(BRect bounds, const char* name, const char* text, uint32 resizeFlags = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW); + + + BStringView(BMessage* data); + + + virtual ~BStringView(); + + + static BArchivable* Instantiate(BMessage* data); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + void SetText(const char* text); + + + const char* Text() const; + + + void SetAlignment(alignment flag); + + + alignment Alignment() const; + + + virtual void AttachedToWindow(); + + + virtual void Draw(BRect bounds); + + + virtual void MessageReceived(BMessage* msg); + + + virtual void MouseDown(BPoint pt); + + + virtual void MouseUp(BPoint pt); + + + virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg); + + + virtual void DetachedFromWindow(); + + + virtual void FrameMoved(BPoint new_position); + + + virtual void FrameResized(float new_width, float new_height); + + + virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); + + + virtual void ResizeToPreferred(); + + + virtual void GetPreferredSize(float* width, float* height); + + + virtual void MakeFocus(bool state = true); + + + virtual void AllAttached(); + + + virtual void AllDetached(); + + + virtual status_t GetSupportedSuites(BMessage* data); + + + + + BStatusBar(BRect frame, const char* name, const char* label = NULL, const char* trailing_label = NULL); + + + BStatusBar(BMessage* data); + + + virtual ~BStatusBar(); + + + static BArchivable* Instantiate(BMessage* data); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + virtual void AttachedToWindow(); + + + virtual void MessageReceived(BMessage* msg); + + + virtual void Draw(BRect updateRect); + + + virtual void SetBarColor(rgb_color color); + + + virtual void SetBarHeight(float height); + + + virtual void SetText(const char* str); + + + virtual void SetTrailingText(const char* str); + + + virtual void SetMaxValue(float max); + + + virtual void Update(float delta, const char* main_text = NULL, const char* trailing_text = NULL); + + + virtual void Reset(const char* label = NULL, const char* trailing_label = NULL); + + + float CurrentValue() const; + + + float MaxValue() const; + + + rgb_color BarColor() const; + + + float BarHeight() const; + + + const char* Text() const; + + + const char* TrailingText() const; + + + const char* Label() const; + + + const char* TrailingLabel() const; + + + virtual void MouseDown(BPoint pt); + + + virtual void MouseUp(BPoint pt); + + + virtual void WindowActivated(bool state); + + + virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg); + + + virtual void DetachedFromWindow(); + + + virtual void FrameMoved(BPoint new_position); + + + virtual void FrameResized(float new_width, float new_height); + + + virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); + + + virtual void ResizeToPreferred(); + + + virtual void GetPreferredSize(float* width, float* height); + + + virtual void MakeFocus(bool state = true); + + + virtual void AllAttached(); + + + virtual void AllDetached(); + + + virtual status_t GetSupportedSuites(BMessage* data); + + +
+
+ + + BScrollBar(BRect frame, const char* name, BView* target, float min, float max, orientation direction); + + + BScrollBar(BMessage* data); + + + virtual ~BScrollBar(); + + + static BArchivable* Instantiate(BMessage* data); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + virtual void AttachedToWindow(); + + + void SetValue(float value); + + + float Value() const; + + + void SetProportion(float); + + + float Proportion() const; + + + virtual void ValueChanged(float newValue); + + + void SetRange(float min, float max); + + + void GetRange(float* min, float* max) const; + + + void SetSteps(float smallStep, float largeStep); + + + void GetSteps(float* smallStep, float* largeStep) const; + + + void SetTarget(BView* target); + + + void SetTarget(const char* targetName); + + + BView* Target() const; + + + orientation Orientation() const; + + + virtual void MessageReceived(BMessage* msg); + + + virtual void MouseDown(BPoint pt); + + + virtual void MouseUp(BPoint pt); + + + virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg); + + + virtual void DetachedFromWindow(); + + + virtual void Draw(BRect updateRect); + + + virtual void FrameMoved(BPoint new_position); + + + virtual void FrameResized(float new_width, float new_height); + + + virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); + + + virtual void ResizeToPreferred(); + + + virtual void GetPreferredSize(float* width, float* height); + + + virtual void MakeFocus(bool state = true); + + + virtual void AllAttached(); + + + virtual void AllDetached(); + + + virtual status_t GetSupportedSuites(BMessage* data); + + + + + BScrollView(const char* name, BView* target, uint32 resizeMask = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = 0, bool horizontal = false, bool vertical = false, border_style border = B_FANCY_BORDER); + + + BScrollView(BMessage* data); + + + virtual ~BScrollView(); + + + static BArchivable* Instantiate(BMessage* data); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + virtual void Draw(BRect updateRect); + + + virtual void AttachedToWindow(); + + + BScrollBar* ScrollBar(orientation flag) const; + + + virtual void SetBorder(border_style border); + + + border_style Border() const; + + + virtual status_t SetBorderHighlighted(bool state); + + + bool IsBorderHighlighted() const; + + + void SetTarget(BView* new_target); + + + BView* Target() const; + + + virtual void MessageReceived(BMessage* msg); + + + virtual void MouseDown(BPoint pt); + + + virtual void WindowActivated(bool state); + + + virtual void MouseUp(BPoint pt); + + + virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg); + + + virtual void DetachedFromWindow(); + + + virtual void AllAttached(); + + + virtual void AllDetached(); + + + virtual void FrameMoved(BPoint new_position); + + + virtual void FrameResized(float new_width, float new_height); + + + virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); + + + virtual void ResizeToPreferred(); + + + virtual void GetPreferredSize(float* width, float* height); + + + virtual void MakeFocus(bool state = true); + + + virtual status_t GetSupportedSuites(BMessage* data); + + + + + status_t get_scroll_bar_info(scroll_bar_info* info); + + + status_t set_scroll_bar_info(scroll_bar_info* info); + + +
+
+ + + BMenu(const char* title, menu_layout layout = B_ITEMS_IN_COLUMN); + + + BMenu(const char* title, float width, float height); + + + BMenu(BMessage* data); + + + virtual ~BMenu(); + + + static BArchivable* Instantiate(BMessage* data); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + virtual void AttachedToWindow(); + + + virtual void DetachedFromWindow(); + + + bool AddItem(BMenuItem* item); + + + bool AddItem(BMenuItem* item, int32 index); + + + bool AddItem(BMenuItem* item, BRect frame); + + + bool AddItem(BMenu* menu); + + + bool AddItem(BMenu* menu, int32 index); + + + bool AddItem(BMenu* menu, BRect frame); + + + bool AddList(BList* list, int32 index); + + + bool AddSeparatorItem(); + + + bool RemoveItem(BMenuItem* item); + + + BMenuItem* RemoveItem(int32 index); + + + bool RemoveItems(int32 index, int32 count, bool del = false); + + + bool RemoveItem(BMenu* menu); + + + BMenuItem* ItemAt(int32 index) const; + + + BMenu* SubmenuAt(int32 index) const; + + + int32 CountItems() const; + + + int32 IndexOf(BMenuItem* item) const; + + + int32 IndexOf(BMenu* menu) const; + + + BMenuItem* FindItem(uint32 command) const; + + + BMenuItem* FindItem(const char* name) const; + + + virtual status_t SetTargetForItems(BHandler* target); + + + virtual status_t SetTargetForItems(BMessenger messenger); + + + virtual void SetEnabled(bool state); + + + virtual void SetRadioMode(bool state); + + + virtual void SetTriggersEnabled(bool state); + + + virtual void SetMaxContentWidth(float max); + + + void SetLabelFromMarked(bool on); + + + bool IsLabelFromMarked(); + + + bool IsEnabled() const; + + + bool IsRadioMode() const; + + + bool AreTriggersEnabled() const; + + + bool IsRedrawAfterSticky() const; + + + float MaxContentWidth() const; + + + BMenuItem* FindMarked(); + + + BMenu* Supermenu() const; + + + BMenuItem* Superitem() const; + + + virtual void MessageReceived(BMessage* msg); + + + virtual void KeyDown(const char* bytes, int32 numBytes); + + + virtual void Draw(BRect updateRect); + + + virtual void GetPreferredSize(float* width, float* height); + + + virtual void ResizeToPreferred(); + + + virtual void FrameMoved(BPoint new_position); + + + virtual void FrameResized(float new_width, float new_height); + + + void InvalidateLayout(); + + + virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); + + + virtual status_t GetSupportedSuites(BMessage* data); + + + virtual status_t Perform(perform_code d, void* arg); + + + virtual void MakeFocus(bool state = true); + + + virtual void AllAttached(); + + + virtual void AllDetached(); + + + BMenu(BRect frame, const char* viewName, uint32 resizeMask, uint32 flags, menu_layout layout, bool resizeToFit); + + + virtual BPoint ScreenLocation(); + + + void SetItemMargins(float left, float top, float right, float bottom); + + + void GetItemMargins(float* left, float* top, float* right,float* bottom) const; + + + menu_layout Layout() const; + + + virtual void Show(); + + + void Show(bool selectFirstItem); + + + void Hide(); + + + BMenuItem* Track(bool start_opened = false, BRect* special_rect = NULL); + + + virtual bool AddDynamicItem(add_state s); + + + virtual void DrawBackground(BRect update); + + + void SetTrackingHook(menu_tracking_hook func, void* state); + + + + + BMenuBar(BRect frame, const char* title, uint32 resizeMask = B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP, menu_layout layout = B_ITEMS_IN_ROW, bool resizeToFit = true); + + + BMenuBar(BMessage* data); + + + virtual ~BMenuBar(); + + + static BArchivable* Instantiate(BMessage* data); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + virtual void SetBorder(menu_bar_border border); + + + menu_bar_border Border() const; + + + virtual void Draw(BRect updateRect); + + + virtual void AttachedToWindow(); + + + virtual void DetachedFromWindow(); + + + virtual void MessageReceived(BMessage* msg); + + + virtual void MouseDown(BPoint where); + + + virtual void WindowActivated(bool state); + + + virtual void MouseUp(BPoint where); + + + virtual void FrameMoved(BPoint new_position); + + + virtual void FrameResized(float new_width, float new_height); + + + virtual void Show(); + + + virtual void Hide(); + + + virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); + + + virtual status_t GetSupportedSuites(BMessage* data); + + + virtual void ResizeToPreferred(); + + + virtual void GetPreferredSize(float* width, float* height); + + + virtual void MakeFocus(bool state = true); + + + virtual void AllAttached(); + + + virtual void AllDetached(); + + + virtual status_t Perform(perform_code d, void* arg); + + + + + BMenuItem(const char* label, BMessage* message, char shortcut = 0, uint32 modifiers = 0); + + + BMenuItem(BMenu* menu, BMessage* message = NULL); + + + BMenuItem(BMessage* data); + + + virtual ~BMenuItem(); + + + static BArchivable* Instantiate(BMessage* data); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + virtual void SetLabel(const char* name); + + + virtual void SetEnabled(bool state); + + + virtual void SetMarked(bool state); + + + virtual void SetTrigger(char ch); + + + virtual void SetShortcut(char ch, uint32 modifiers); + + + const char* Label() const; + + + bool IsEnabled() const; + + + bool IsMarked() const; + + + char Trigger() const; + + + char Shortcut(uint32* modifiers = NULL) const; + + + BMenu* Submenu() const; + + + BMenu* Menu() const; + + + BRect Frame() const; + + + virtual void GetContentSize(float* width, float* height); + + + virtual void TruncateLabel(float max, char* new_label); + + + virtual void DrawContent(); + + + virtual void Draw(); + + + virtual void Highlight(bool on); + + + bool IsSelected() const; + + + BPoint ContentLocation() const; + + + virtual status_t Invoke(BMessage* msg = NULL); + + + + + BSeparatorItem(); + + + BSeparatorItem(BMessage* data); + + + virtual ~BSeparatorItem(); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + static BArchivable* Instantiate(BMessage* data); + + + virtual void SetEnabled(bool state); + + + virtual void GetContentSize(float* width, float* height); + + + virtual void Draw(); + + + + + BMenuField(BRect frame, const char* name, const char* label, BMenu* menu, uint32 resize = B_FOLLOW_LEFT|B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW | B_NAVIGABLE); + + + BMenuField(BRect frame, const char* name, const char* label, BMenu* menu, bool fixed_size, uint32 resize = B_FOLLOW_LEFT|B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW | B_NAVIGABLE); + + + BMenuField(BMessage* data); + + + virtual ~BMenuField(); + + + static BArchivable* Instantiate(BMessage* data); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + virtual void Draw(BRect update); + + + virtual void AttachedToWindow(); + + + virtual void AllAttached(); + + + virtual void MouseDown(BPoint where); + + + virtual void KeyDown(const char* bytes, int32 numBytes); + + + virtual void MakeFocus(bool state); + + + virtual void MessageReceived(BMessage* msg); + + + virtual void WindowActivated(bool state); + + + virtual void MouseUp(BPoint pt); + + + virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg); + + + virtual void DetachedFromWindow(); + + + virtual void AllDetached(); + + + virtual void FrameMoved(BPoint new_position); + + + virtual void FrameResized(float new_width, float new_height); + + + BMenu* Menu() const; + + + BMenuBar* MenuBar() const; + + + BMenuItem* MenuItem() const; + + + virtual void SetLabel(const char* label); + + + const char* Label() const; + + + virtual void SetEnabled(bool on); + + + bool IsEnabled() const; + + + virtual void SetAlignment(alignment label); + + + alignment Alignment() const; + + + virtual void SetDivider(float dividing_line); + + + float Divider() const; + + + void ShowPopUpMarker(); + + + void HidePopUpMarker(); + + + virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); + + + virtual status_t GetSupportedSuites(BMessage* data); + + + virtual void ResizeToPreferred(); + + + virtual void GetPreferredSize(float* width, float* height); + + + virtual status_t Perform(perform_code d, void* arg); + + + + + BPopUpMenu(const char* title, bool radioMode = true, bool autoRename = true, menu_layout layout = B_ITEMS_IN_COLUMN); + + + BPopUpMenu(BMessage* data); + + + virtual ~BPopUpMenu(); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + static BArchivable* Instantiate(BMessage* data); + + + BMenuItem* Go(BPoint where, bool delivers_message = false, bool open_anyway = false, bool async = false); + + + BMenuItem* Go(BPoint where, bool delivers_message, bool open_anyway, BRect click_to_open, bool async = false); + + + virtual void MessageReceived(BMessage* msg); + + + virtual void MouseDown(BPoint pt); + + + virtual void MouseUp(BPoint pt); + + + virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg); + + + virtual void AttachedToWindow(); + + + virtual void DetachedFromWindow(); + + + virtual void FrameMoved(BPoint new_position); + + + virtual void FrameResized(float new_width, float new_height); + + + virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); + + + virtual status_t GetSupportedSuites(BMessage* data); + + + virtual status_t Perform(perform_code d, void* arg); + + + virtual void ResizeToPreferred(); + + + virtual void GetPreferredSize(float* width, float* height); + + + virtual void MakeFocus(bool state = true); + + + virtual void AllAttached(); + + + virtual void AllDetached(); + + + void SetAsyncAutoDestruct(bool state); + + + bool AsyncAutoDestruct() const; + + + virtual BPoint ScreenLocation(); + + + + + status_t set_menu_info(menu_info* info); + + + status_t get_menu_info(menu_info* info); + + +
+
+ + + BListItem(uint32 outlineLevel = 0, bool expanded = true); + + + BListItem(BMessage* data); + + + virtual ~BListItem(); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + float Height() const; + + + float Width() const; + + + bool IsSelected() const; + + + void Select(); + + + void Deselect(); + + + virtual void SetEnabled(bool on); + + + bool IsEnabled() const; + + + void SetHeight(float height); + + + void SetWidth(float width); + + + virtual void DrawItem(BView* owner, BRect bounds, bool complete = false) = 0; + + + virtual void Update(BView* owner, const BFont* font); + + + virtual status_t Perform(perform_code d, void* arg); + + + bool IsExpanded() const; + + + void SetExpanded(bool expanded); + + + uint32 OutlineLevel() const; + + + bool IsItemVisible() const; + + + void SetItemVisible(bool); + + + + + BStringItem(const char* text, uint32 outlineLevel = 0, bool expanded = true); + + + virtual ~BStringItem(); + + + BStringItem(BMessage* data); + + + static BArchivable* Instantiate(BMessage* data); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + virtual void DrawItem(BView* owner, BRect frame, bool complete = false); + + + virtual void SetText(const char* text); + + + const char* Text() const; + + + virtual void Update(BView* owner, const BFont* font); + + + virtual status_t Perform(perform_code d, void* arg); + + + + + BListView(BRect frame, const char *name, list_view_type type = B_SINGLE_SELECTION_LIST, uint32 resizeMask = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE); + + + BListView(BMessage *data); + + + virtual ~BListView(); + + + static BArchivable *Instantiate(BMessage *data); + + + virtual status_t Archive(BMessage *data, bool deep = true) const; + + + virtual void Draw(BRect updateRect); + + + virtual void MessageReceived(BMessage *msg); + + + virtual void MouseDown(BPoint where); + + + virtual void KeyDown(const char *bytes, int32 numBytes); + + + virtual void MakeFocus(bool state = true); + + + virtual void FrameResized(float newWidth, float newHeight); + + + virtual void TargetedByScrollView(BScrollView *scroller); + + + void ScrollTo(float x, float y); + + + virtual void ScrollTo(BPoint where); + + + virtual bool AddItem(BListItem *item); + + + virtual bool AddItem(BListItem *item, int32 atIndex); + + + virtual bool AddList(BList *newItems); + + + virtual bool AddList(BList *newItems, int32 atIndex); + + + virtual bool RemoveItem(BListItem *item); + + + virtual BListItem *RemoveItem(int32 index); + + + virtual bool RemoveItems(int32 index, int32 count); + + + virtual void SetSelectionMessage(BMessage *message); + + + virtual void SetInvocationMessage(BMessage *message); + + + BMessage *SelectionMessage() const; + + + uint32 SelectionCommand() const; + + + BMessage *InvocationMessage() const; + + + uint32 InvocationCommand() const; + + + virtual void SetListType(list_view_type type); + + + list_view_type ListType() const; + + + BListItem *ItemAt(int32 index) const; + + + int32 IndexOf(BPoint point) const; + + + int32 IndexOf(BListItem *item) const; + + + BListItem *FirstItem() const; + + + BListItem *LastItem() const; + + + bool HasItem(BListItem *item) const; + + + int32 CountItems() const; + + + virtual void MakeEmpty(); + + + bool IsEmpty() const; + + + void DoForEach(bool (*func)(BListItem *)); + + + void DoForEach(bool (*func)(BListItem *, void *), void *); + + + const BListItem **Items() const; + + + void InvalidateItem(int32 index); + + + void ScrollToSelection(); + + + void Select(int32 index, bool extend = false); + + + void Select(int32 from, int32 to, bool extend = false); + + + bool IsItemSelected(int32 index) const; + + + int32 CurrentSelection(int32 index = 0) const; + + + virtual status_t Invoke(BMessage *msg = NULL); + + + void DeselectAll(); + + + void DeselectExcept(int32 except_from, int32 except_to); + + + void Deselect(int32 index); + + + virtual void SelectionChanged(); + + + void SortItems(int (*cmp)(const void *, const void *)); + + + bool SwapItems(int32 a, int32 b); + + + bool MoveItem(int32 from, int32 to); + + + bool ReplaceItem(int32 index, BListItem * item); + + + virtual void AttachedToWindow(); + + + virtual void FrameMoved(BPoint new_position); + + + BRect ItemFrame(int32 index); + + + virtual BHandler *ResolveSpecifier(BMessage *msg, int32 index, BMessage *specifier, int32 form, const char *property); + + + virtual status_t GetSupportedSuites(BMessage *data); + + + virtual status_t Perform(perform_code d, void *arg); + + + virtual void WindowActivated(bool state); + + + virtual void MouseUp(BPoint pt); + + + virtual void MouseMoved(BPoint pt, uint32 code, const BMessage *msg); + + + virtual void DetachedFromWindow(); + + + virtual bool InitiateDrag(BPoint pt, int32 itemIndex, bool initialySelected); + + + virtual void ResizeToPreferred(); + + + virtual void GetPreferredSize(float *width, float *height); + + + virtual void AllAttached(); + + + virtual void AllDetached(); + + + virtual bool DoMiscellaneous(MiscCode code, MiscData * data); + + + virtual void DrawItem(BListItem *item, BRect itemRect, bool complete = false); + + + + + BOutlineListView(BRect frame, const char* name, list_view_type type = B_SINGLE_SELECTION_LIST, uint32 resizeMask = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE); + + + BOutlineListView(BMessage* data); + + + virtual ~BOutlineListView(); + + + static BArchivable* Instantiate(BMessage* data); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + virtual void MouseDown(BPoint where); + + + virtual void KeyDown(const char* bytes, int32 numBytes); + + + virtual void FrameMoved(BPoint new_position); + + + virtual void FrameResized(float new_width, float new_height); + + + virtual void MouseUp(BPoint where); + + + virtual bool AddUnder(BListItem* item, BListItem* underItem); + + + virtual bool AddItem(BListItem* item); + + + virtual bool AddItem(BListItem* item, int32 fullListIndex); + + + virtual bool AddList(BList* newItems); + + + virtual bool AddList(BList* newItems, int32 fullListIndex); + + + virtual bool RemoveItem(BListItem* item); + + + virtual BListItem* RemoveItem(int32 fullListIndex); + + + virtual bool RemoveItems(int32 fullListIndex, int32 count); + + + BListItem* FullListItemAt(int32 fullListIndex) const; + + + int32 FullListIndexOf(BPoint point) const; + + + int32 FullListIndexOf(BListItem* item) const; + + + BListItem* FullListFirstItem() const; + + + BListItem* FullListLastItem() const; + + + bool FullListHasItem(BListItem* item) const; + + + int32 FullListCountItems() const; + + + int32 FullListCurrentSelection(int32 index = 0) const; + + + virtual void MakeEmpty(); + + + bool FullListIsEmpty() const; + + + void FullListDoForEach(bool (*func)(BListItem* )); + + + void FullListDoForEach(bool (*func)(BListItem* , void* ), void*); + + + BListItem* Superitem(const BListItem* item); + + + void Expand(BListItem* item); + + + void Collapse(BListItem* item); + + + bool IsExpanded(int32 fullListIndex); + + + virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); + + + virtual status_t GetSupportedSuites(BMessage* data); + + + virtual status_t Perform(perform_code d, void* arg); + + + virtual void ResizeToPreferred(); + + + virtual void GetPreferredSize(float* width, float* height); + + + virtual void MakeFocus(bool state = true); + + + virtual void AllAttached(); + + + virtual void AllDetached(); + + + virtual void DetachedFromWindow(); + + + void FullListSortItems(int (*compareFunc)(const BListItem* , const BListItem* )); + + + void SortItemsUnder(BListItem* underItem, bool oneLevelOnly, int (*compareFunc)(const BListItem* , const BListItem*)); + + + int32 CountItemsUnder(BListItem* under, bool oneLevelOnly) const; + + + BListItem* EachItemUnder(BListItem* underItem, bool oneLevelOnly, BListItem* (*eachFunc)(BListItem* , void* ), void* ); + + + BListItem* ItemUnderAt(BListItem* underItem, bool oneLevelOnly, int32 index) const; + + + virtual bool DoMiscellaneous(MiscCode code, MiscData* data); + + + virtual void MessageReceived(BMessage* ); + + + virtual void ExpandOrCollapse(BListItem* underItem, bool expand); + + +
+
+ + + BTextView(BRect frame, const char* name, BRect textRect, uint32 resizeMask, uint32 flags = B_WILL_DRAW | B_PULSE_NEEDED); + + + BTextView(BRect frame, const char* name, BRect textRect, const BFont* initialFont, const rgb_color* initialColor, uint32 resizeMask, uint32 flags); + + + BTextView(BMessage* data); + + + virtual ~BTextView(); + + + static BArchivable* Instantiate(BMessage* data); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + virtual void AttachedToWindow(); + + + virtual void DetachedFromWindow(); + + + virtual void Draw(BRect inRect); + + + virtual void MouseDown(BPoint where); + + + virtual void MouseUp(BPoint where); + + + virtual void MouseMoved(BPoint where, uint32 code, const BMessage* message); + + + virtual void WindowActivated(bool state); + + + virtual void KeyDown(const char* bytes, int32 numBytes); + + + virtual void Pulse(); + + + virtual void FrameResized(float width, float height); + + + virtual void MakeFocus(bool focusState = true); + + + virtual void MessageReceived(BMessage* message); + + + virtual BHandler* ResolveSpecifier(BMessage* message, int32 index, BMessage* specifier, int32 form, const char* property); + + + virtual status_t GetSupportedSuites(BMessage* data); + + + virtual status_t Perform(perform_code d, void* arg); + + + void SetText(const char* inText, const text_run_array* inRuns = NULL); + + + void SetText(const char* inText, int32 inLength, const text_run_array* inRuns = NULL); + + + void SetText(BFile* inFile, int32 startOffset, int32 inLength, const text_run_array* inRuns = NULL); + + + void Insert(const char* inText, const text_run_array* inRuns = NULL); + + + void Insert(const char* inText, int32 inLength, const text_run_array* inRuns = NULL); + + + void Insert(int32 startOffset, const char* inText, int32 inLength, const text_run_array* inRuns = NULL); + + + void Delete(); + + + void Delete(int32 startOffset, int32 endOffset); + + + const char* Text() const; + + + int32 TextLength() const; + + + void GetText(int32 offset, int32 length, char* buffer) const; + + + uchar ByteAt(int32 offset) const; + + + int32 CountLines() const; + + + int32 CurrentLine() const; + + + void GoToLine(int32 lineNum); + + + virtual void Cut(BClipboard* clipboard); + + + virtual void Copy(BClipboard* clipboard); + + + virtual void Paste(BClipboard* clipboard); + + + void Clear(); + + + virtual bool AcceptsPaste(BClipboard* clipboard); + + + virtual bool AcceptsDrop(const BMessage* inMessage); + + + virtual void Select(int32 startOffset, int32 endOffset); + + + void SelectAll(); + + + void GetSelection(int32* outStart, int32* outEnd) const; + + + void SetFontAndColor(const BFont* inFont, uint32 inMode = B_FONT_ALL, const rgb_color* inColor = NULL); + + + void SetFontAndColor(int32 startOffset, int32 endOffset, const BFont* inFont, uint32 inMode = B_FONT_ALL, const rgb_color* inColor = NULL); + + + void GetFontAndColor(int32 inOffset, BFont* outFont, rgb_color* outColor = NULL) const; + + + void GetFontAndColor(BFont* outFont, uint32* outMode, rgb_color* outColor = NULL, bool* outEqColor = NULL) const; + + + void SetRunArray(int32 startOffset, int32 endOffset, const text_run_array* inRuns); + + + text_run_array* RunArray(int32 startOffset, int32 endOffset, int32* outSize = NULL) const; + + + int32 LineAt(int32 offset) const; + + + int32 LineAt(BPoint point) const; + + + BPoint PointAt(int32 inOffset, float* outHeight = NULL) const; + + + int32 OffsetAt(BPoint point) const; + + + int32 OffsetAt(int32 line) const; + + + virtual void FindWord(int32 inOffset, int32* outFromOffset, int32* outToOffset); + + + virtual bool CanEndLine(int32 offset); + + + float LineWidth(int32 lineNum = 0) const; + + + float LineHeight(int32 lineNum = 0) const; + + + float TextHeight(int32 startLine, int32 endLine) const; + + + void GetTextRegion(int32 startOffset, int32 endOffset, BRegion* outRegion) const; + + + virtual void ScrollToOffset(int32 inOffset); + + + void ScrollToSelection(); + + + void Highlight(int32 startOffset, int32 endOffset); + + + void SetTextRect(BRect rect); + + + BRect TextRect() const; + + + void SetStylable(bool stylable); + + + bool IsStylable() const; + + + void SetTabWidth(float width); + + + float TabWidth() const; + + + void MakeSelectable(bool selectable = true); + + + bool IsSelectable() const; + + + void MakeEditable(bool editable = true); + + + bool IsEditable() const; + + + void SetWordWrap(bool wrap); + + + bool DoesWordWrap() const; + + + void SetMaxBytes(int32 max); + + + int32 MaxBytes() const; + + + void DisallowChar(uint32 aChar); + + + void AllowChar(uint32 aChar); + + + void SetAlignment(alignment flag); + + + alignment Alignment() const; + + + void SetAutoindent(bool state); + + + bool DoesAutoindent() const; + + + void SetColorSpace(color_space colors); + + + color_space ColorSpace() const; + + + void MakeResizable(bool resize, BView* resizeView = NULL); + + + bool IsResizable() const; + + + void SetDoesUndo(bool undo); + + + bool DoesUndo() const; + + + void HideTyping(bool enabled); + + + bool IsTypingHidden(void) const; + + + virtual void ResizeToPreferred(); + + + virtual void GetPreferredSize(float* width, float* height); + + + virtual void AllAttached(); + + + virtual void AllDetached(); + + + static void* FlattenRunArray(const text_run_array* inArray, int32* outSize = NULL); + + + static text_run_array* UnflattenRunArray(const void *data, int32* outSize = NULL); + + + virtual void InsertText(const char* inText, int32 inLength, int32 inOffset, const text_run_array* inRuns); + + + virtual void DeleteText(int32 fromOffset, int32 toOffset); + + + virtual void Undo(BClipboard* clipboard); + + + undo_state UndoState(bool* isRedo) const; + + + virtual void GetDragParameters(BMessage* drag, BBitmap** bitmap, BPoint* point, BHandler** handler); + + + + + BTextControl(BRect frame, const char* name, const char* label, const char* initial_text, BMessage* message, uint32 rmask = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW | B_NAVIGABLE); + + + BTextControl(BMessage* data); + + + virtual ~BTextControl(); + + + static BArchivable* Instantiate(BMessage* data); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + virtual void SetText(const char* text); + + + const char* Text() const; + + + virtual void SetValue(int32 value); + + + virtual status_t Invoke(BMessage* msg = NULL); + + + BTextView* TextView() const; + + + virtual void SetModificationMessage(BMessage* message); + + + BMessage* ModificationMessage() const; + + + virtual void SetAlignment(alignment label, alignment text); + + + void GetAlignment(alignment* label, alignment* text) const; + + + virtual void SetDivider(float dividing_line); + + + float Divider() const; + + + virtual void Draw(BRect updateRect); + + + virtual void MouseDown(BPoint where); + + + virtual void AttachedToWindow(); + + + virtual void MakeFocus(bool focusState = true); + + + virtual void SetEnabled(bool state); + + + virtual void FrameMoved(BPoint new_position); + + + virtual void FrameResized(float new_width, float new_height); + + + virtual void WindowActivated(bool active); + + + virtual void GetPreferredSize(float* width, float* height); + + + virtual void ResizeToPreferred(); + + + virtual void MessageReceived(BMessage* msg); + + + virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); + + + virtual void MouseUp(BPoint pt); + + + virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg); + + + virtual void DetachedFromWindow(); + + + virtual void AllAttached(); + + + virtual void AllDetached(); + + + virtual status_t GetSupportedSuites(BMessage* data); + + + virtual void SetFlags(uint32 flags); + + +
+
+ + + BAlert(const char *title, const char *text, const char *button1, const char *button2 = NULL, const char *button3 = NULL, button_width width = B_WIDTH_AS_USUAL, alert_type type = B_INFO_ALERT); + + + BAlert(const char *title, const char *text, const char *button1, const char *button2, const char *button3, button_width width, button_spacing spacing, alert_type type = B_INFO_ALERT); + + + BAlert(BMessage *data); + + + ~BAlert(); + + + static BArchivable *Instantiate(BMessage *data); + + + virtual status_t Archive(BMessage *data, bool deep = true) const; + + + void SetShortcut(int32 button_index, char key); + + + char Shortcut(int32 button_index) const; + + + int32 Go(); + + + status_t Go(BInvoker *invoker); + + + virtual void MessageReceived(BMessage *an_event); + + + virtual void FrameResized(float new_width, float new_height); + + + BButton* ButtonAt(int32 index) const; + + + BTextView* TextView() const; + + + virtual BHandler* ResolveSpecifier(BMessage *msg, int32 index, BMessage* specifier, int32 form, const char* property); + + + virtual status_t GetSupportedSuites(BMessage* data); + + + virtual void DispatchMessage(BMessage* msg, BHandler* handler); + + + virtual void Quit(); + + + virtual bool QuitRequested(); + + + static BPoint AlertPosition(float width, float height); + + + + + BDeskbar(); + + + ~BDeskbar(); + + + BRect Frame() const; + + + deskbar_location Location(bool* isExpanded=NULL) const; + + + status_t SetLocation(deskbar_location location, bool expanded=false); + + + bool IsExpanded() const; + + + status_t Expand(bool yn); + + + status_t GetItemInfo(int32 id, const char** name) const; + + + status_t GetItemInfo(const char* name, int32* id) const; + + + bool HasItem(int32 id) const; + + + bool HasItem(const char* name) const; + + + uint32 CountItems() const; + + + status_t AddItem(BView* archivableView, int32* id=NULL); + + + status_t AddItem(entry_ref* addon, int32* id=NULL); + + + status_t RemoveItem(int32 id); + + + status_t RemoveItem(const char* name); + + + + + unicode_block(); + + + unicode_block(uint64 block2, uint64 block1); + + + bool Includes(const unicode_block &block) const; + + + unicode_block operator&(const unicode_block &block) const; + + + unicode_block operator|(const unicode_block &block) const; + + + unicode_block& operator=(const unicode_block &block); + + + bool operator==(const unicode_block &block) const; + + + bool operator!=(const unicode_block &block) const; + + + + + status_t get_deskbar_frame(BRect* frame); + + + + + status_t get_mouse_type(int32* type); + + + status_t set_mouse_type(int32 type); + + + status_t get_mouse_map(mouse_map* map); + + + status_t set_mouse_map(mouse_map* map); + + + status_t get_click_speed(bigtime_t* speed); + + + status_t set_click_speed(bigtime_t speed); + + + status_t get_mouse_speed(int32* speed); + + + status_t set_mouse_speed(int32 speed); + + + status_t get_mouse_acceleration(int32* speed); + + + status_t set_mouse_acceleration(int32 speed); + + + void set_focus_follows_mouse(bool follow); + + + bool focus_follows_mouse(); + + + void set_mouse_mode(mode_mouse mode); + + + mode_mouse mouse_mode(); + + + + + int32 count_workspaces(); + + + void set_workspace_count(int32 count); + + + int32 current_workspace(); + + + void activate_workspace(int32 workspace); + + + + + status_t get_key_repeat_rate(int32* rate); + + + status_t set_key_repeat_rate(int32 rate); + + + status_t get_key_repeat_delay(bigtime_t* delay); + + + status_t set_key_repeat_delay(bigtime_t delay); + + + uint32 modifiers(); + + + status_t get_key_info(key_info* info); + + + void get_key_map(key_map** map, char** key_buffer); + + + status_t get_keyboard_id(uint16* id); + + + void set_modifier_key(uint32 modifier, uint32 key); + + + void set_keyboard_locks(uint32 modifiers); + + + + + rgb_color keyboard_navigation_color(); + + + rgb_color ui_color(color_which which); + + + rgb_color tint_color(rgb_color color, float tint); + + + + + bigtime_t idle_time(); + + + void run_select_printer_panel(); + + + void run_add_printer_panel(); + + + void run_be_about(); + + + status_t _init_interface_kit_(); + + + void _ReservedShelf1__6BShelfFv(BShelf* const, int32, const BMessage*, const BView*); + + + uint32 _rule_(uint32 r1, uint32 r2, uint32 r3, uint32 r4); + + +
+
+ + + BDragger(BRect bounds, BView* target, uint32 rmask = B_FOLLOW_NONE, uint32 flags = B_WILL_DRAW); + + + BDragger(BMessage* data); + + + virtual ~BDragger(); + + + static BArchivable* Instantiate(BMessage* data); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + virtual void AttachedToWindow(); + + + virtual void DetachedFromWindow(); + + + virtual void Draw(BRect update); + + + virtual void MouseDown(BPoint where); + + + virtual void MouseUp(BPoint pt); + + + virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg); + + + virtual void MessageReceived(BMessage* msg); + + + virtual void FrameMoved(BPoint new_position); + + + virtual void FrameResized(float new_width, float new_height); + + + static status_t ShowAllDraggers(); /* system wide!*/ + + + static status_t HideAllDraggers(); /* system wide!*/ + + + static bool AreDraggersDrawn(); + + + virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); + + + virtual status_t GetSupportedSuites(BMessage* data); + + + virtual status_t Perform(perform_code d, void* arg); + + + virtual void ResizeToPreferred(); + + + virtual void GetPreferredSize(float* width, float* height); + + + virtual void MakeFocus(bool state = true); + + + virtual void AllAttached(); + + + virtual void AllDetached(); + + + status_t SetPopUp(BPopUpMenu* context_menu); + + + BPopUpMenu* PopUp() const; + + + bool InShelf() const; + + + BView* Target() const; + + + virtual BBitmap* DragBitmap(BPoint* offset, drawing_mode* mode); + + + bool IsVisibilityChanging() const; + + + + + BShelf(BView* view, bool allow_drags = true, const char* shelf_type = NULL); + + + BShelf(const entry_ref* ref, BView* view, bool allow_drags = true, const char* shelf_type = NULL); + + + BShelf(BDataIO* stream, BView* view, bool allow_drags = true, const char* shelf_type = NULL); + + + BShelf(BMessage* data); + + + virtual ~BShelf(); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + static BArchivable* Instantiate(BMessage* data); + + + virtual void MessageReceived(BMessage* msg); + + + status_t Save(); + + + virtual void SetDirty(bool state); + + + bool IsDirty() const; + + + virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); + + + virtual status_t GetSupportedSuites(BMessage* data); + + + virtual status_t Perform(perform_code d, void* arg); + + + bool AllowsDragging() const; + + + void SetAllowsDragging(bool state); + + + bool AllowsZombies() const; + + + void SetAllowsZombies(bool state); + + + bool DisplaysZombies() const; + + + void SetDisplaysZombies(bool state); + + + bool IsTypeEnforced() const; + + + void SetTypeEnforced(bool state); + + + status_t SetSaveLocation(BDataIO* data_io); + + + status_t SetSaveLocation(const entry_ref* ref); + + + BDataIO* SaveLocation(entry_ref* ref) const; + + + status_t AddReplicant(BMessage* data, BPoint location); + + + status_t DeleteReplicant(BView* replicant); + + + status_t DeleteReplicant(BMessage* data); + + + status_t DeleteReplicant(int32 index); + + + int32 CountReplicants() const; + + + BMessage* ReplicantAt(int32 index, BView** view = NULL, uint32* uid = NULL, status_t* perr = NULL) const; + + + int32 IndexOf(const BView* replicant_view) const; + + + int32 IndexOf(const BMessage* archive) const; + + + int32 IndexOf(uint32 id) const; + + + virtual bool CanAcceptReplicantMessage(BMessage*) const; + + + virtual bool CanAcceptReplicantView(BRect, BView*, BMessage*) const; + + + virtual BPoint AdjustReplicantBy(BRect, BMessage*) const; + + + virtual void ReplicantDeleted(int32 index, const BMessage* archive, const BView* replicant); + + +
+
+ + + BChannelControl(BRect frame, const char * name, const char * label, BMessage * model, int32 channel_count = 1, uint32 resize = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW); + + + BChannelControl(BMessage* from); + + + virtual ~BChannelControl(); + + + virtual status_t Archive(BMessage* into, bool deep = true) const; + + + virtual void Draw(BRect area) = 0; + + + virtual void MouseDown(BPoint where) = 0; + + + virtual void KeyDown(const char* bytes, int32 size) = 0; + + + virtual void FrameResized(float width, float height); + + + virtual void SetFont(const BFont* font, uint32 mask = B_FONT_ALL); + + + virtual void AttachedToWindow(); + + + virtual void DetachedFromWindow(); + + + virtual void ResizeToPreferred(); + + + virtual void GetPreferredSize(float* width, float* height) = 0; + + + virtual void MessageReceived(BMessage* message); + + + virtual BHandler *ResolveSpecifier(BMessage *msg, int32 index, BMessage *specifier, int32 form, const char *property); + + + virtual status_t GetSupportedSuites(BMessage *data); + + + virtual void SetModificationMessage(BMessage *message); + + + BMessage *ModificationMessage() const; + + + virtual status_t Invoke(BMessage *msg = NULL); + + + virtual status_t InvokeChannel(BMessage *msg = NULL, int32 from_channel = 0, int32 channel_count = -1, const bool* in_mask = NULL); + + + status_t InvokeNotifyChannel(BMessage *msg = NULL, uint32 kind = B_CONTROL_INVOKED, int32 from_channel = 0, int32 channel_count = -1, const bool* in_mask = NULL); + + + virtual voidSetValue(int32 value); + + + virtual status_t SetCurrentChannel(int32 channel); + + + int32 CurrentChannel() const; + + + virtual int32 CountChannels() const; + + + virtual int32 MaxChannelCount() const = 0; + + + virtual status_t SetChannelCount(int32 channel_count); + + + int32 ValueFor(int32 channel) const; + + + virtual int32 GetValue(int32* out_values, int32 from_channel, int32 channel_count) const; + + + status_t SetValueFor(int32 channel, int32 value); + + + virtual status_t SetValue(int32 from_channel, int32 channel_count, const int32* in_values); + + + status_t SetAllValue(int32 values); + + + status_t SetLimitsFor(int32 channel, int32 minimum, int32 maximum); + + + status_t GetLimitsFor(int32 channel, int32* minimum, int32* maximum) const ; + + + virtual status_t SetLimitsFor(int32 from_channel, int32 channel_count, const int32* minimum, const int32* maximum); + + + virtual status_t GetLimitsFor(int32 from_channel, int32 channel_count, int32* minimum, int32* maximum) const; + + + status_t SetLimits(int32 minimum, int32 maximum); + + + status_t GetLimits(int32* outMinimum, int32* outMaximum) const; + + + virtual bool SupportsIndividualLimits() const = 0; + + + virtual status_t SetLimitLabels(const char* min_label, const char* max_label); + + + const char* MinLimitLabel() const; + + + const char* MaxLimitLabel() const; + + + virtual status_t SetLimitLabelsFor(int32 channel, const char* minLabel, const char* maxLabel); + + + virtual status_t SetLimitLabelsFor(int32 from_channel, int32 channel_count, const char* minLabel, const char* maxLabel); + + + const char* MinLimitLabelFor(int32 channel) const; + + + const char* MaxLimitLabelFor(int32 channel) const; + + + + + BChannelSlider(BRect area, const char* name, const char* label, BMessage* model, int32 channels = 1, uint32 resize = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW); + + + BChannelSlider(BRect area, const char* name, const char* label, BMessage* model, orientation o, int32 channels = 1, uint32 resize = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW); + + + BChannelSlider(BMessage* from); + + + virtual ~BChannelSlider(); + + + static BArchivable* Instantiate(BMessage* from); + + + virtual status_t Archive(BMessage* into, bool deep = true) const; + + + virtual orientation Orientation() const; + + + void SetOrientation(orientation o); + + + virtual int32 MaxChannelCount() const; + + + virtual bool SupportsIndividualLimits() const; + + + virtual void AttachedToWindow(); + + + virtual void AllAttached(); + + + virtual void DetachedFromWindow(); + + + virtual void AllDetached(); + + + virtual void MessageReceived(BMessage* msg); + + + virtual void Draw(BRect area); + + + virtual void MouseDown(BPoint where); + + + virtual void MouseUp(BPoint pt); + + + virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* message); + + + virtual void WindowActivated(bool state); + + + virtual void KeyDown(const char* bytes, int32 numBytes); + + + virtual void KeyUp(const char* bytes, int32 numBytes); + + + virtual void FrameResized(float width, float height); + + + virtual void SetFont(const BFont* font, uint32 mask = B_FONT_ALL); + + + virtual void MakeFocus(bool focusState = true); + + + virtual void SetEnabled(bool on); + + + virtual void GetPreferredSize(float* width, float* height); + + + virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); + + + virtual status_t GetSupportedSuites(BMessage* data); + + + virtual void DrawChannel(BView* into, int32 channel, BRect area, bool pressed); + + + virtual void DrawGroove(BView* into, int32 channel, BPoint tl, BPoint br); + + + virtual void DrawThumb(BView* into, int32 channel, BPoint where, bool pressed ); + + + virtual const BBitmap* ThumbFor(int32 channel, bool pressed); + + + virtual BRect ThumbFrameFor(int32 channel); + + + virtual float ThumbDeltaFor(int32 channel); + + + virtual float ThumbRangeFor(int32 channel); + + + + + BMultiChannelControl(BRect frame, const char* name, const char* label, BMessage* model, int32 channel_count = 1, uint32 resize = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW); + + + BMultiChannelControl(BMessage* from); + + + virtual ~BMultiChannelControl(); + + + virtual status_t Archive(BMessage* into, bool deep = true) const; + + + virtual void Draw(BRect area) = 0; + + + virtual void MouseDown(BPoint where) = 0; + + + virtual void KeyDown(const char* bytes, int32 size) = 0; + + + virtual void FrameResized(float width, float height); + + + virtual void SetFont(const BFont* font, uint32 mask = B_FONT_ALL); + + + virtual void AttachedToWindow(); + + + virtual void DetachedFromWindow(); + + + virtual void ResizeToPreferred(); + + + virtual void GetPreferredSize(float* width, float* height) = 0; + + + virtual void MessageReceived(BMessage* message); + + + virtual void SetValue(int32 value); + + + virtual status_t SetCurrentChannel(int32 channel); + + + int32 CurrentChannel() const; + + + virtual int32 CountChannels() const; + + + virtual int32 MaxChannelCount() const = 0; + + + virtual status_t SetChannelCount(int32 channel_count); + + + int32 ValueFor(int32 channel) const; + + + virtual int32 GetValues(int32* out_values, int32 from_channel, int32 channel_count) const; + + + status_t SetValueFor(int32 channel, int32 value); + + + virtual status_t SetValues(int32 from_channel, int32 channel_count, const int32* in_values); + + + status_t SetAllValues(int32 values); + + + status_t SetLimitsFor(int32 channel, int32 minimum, int32 maximum); + + + status_t GetLimitsFor(int32 channel, int32* minimum, int32* maximum) const ; + + + virtual status_t SetLimits(int32 from_channel, int32 channel_count, const int32* minimum, const int32* maximum); + + + virtual status_t GetLimits(int32 from_channel, int32 channel_count, int32* minimum, int32* maximum) const; + + + status_t SetAllLimits(int32 minimum, int32 maximum); + + + virtual status_t SetLimitLabels(const char* min_label, const char* max_label); + + + const char* MinLimitLabel() const; + + + const char* MaxLimitLabel() const; + + + + + BOptionControl(BRect frame, const char* name, const char* label, BMessage* message, uint32 resize = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW); + + + virtual ~BOptionControl(); + + + virtual void MessageReceived(BMessage* message); + + + status_t AddOption(const char* name, int32 value); + + + virtual boolGetOptionAt(int32 index, const char** out_name, int32* out_value) = 0; + + + virtual void RemoveOptionAt(int32 index) = 0; + + + virtual int32 CountOptions() const = 0; + + + virtual status_tAddOptionAt(const char* name, int32 value, int32 index) = 0; + + + virtual int32 SelectedOption(const char** name = 0, int32* value = 0) const = 0; + + + virtual status_t SelectOptionFor(int32 value); + + + virtual status_t SelectOptionFor(const char *name); + + + BMessage* MakeValueMessage(int32 value); + + + + + BOptionPopUp(BRect frame, const char* name, const char* label, BMessage* message, uint32 resize = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW); + + + BOptionPopUp(BRect frame, const char* name, const char* label, BMessage* message, bool fixed, uint32 resize = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW); + + + ~BOptionPopUp(); + + + BMenuField* MenuField(); + + + virtual bool GetOptionAt(int32 index, const char** out_name, int32* out_value); + + + virtual void RemoveOptionAt(int32 index); + + + virtual int32 CountOptions() const; + + + virtual status_t AddOptionAt(const char* name, int32 value, int32 index); + + + virtual void AllAttached(); + + + virtual void MessageReceived(BMessage* message); + + + virtual void SetLabel(const char* text); + + + virtual void SetValue(int32 value); + + + virtual voidSetEnabled(bool on); + + + virtual void GetPreferredSize(float* width, float* height); + + + virtual void ResizeToPreferred(); + + + virtual int32 SelectedOption(const char** outName = 0, int32* outValue = 0) const; + + +
+
+ +
+ + + BArchivable(); + + + BArchivable(BMessage* from); + + + ~BArchivable(); + + + virtual status_t Archive(BMessage* into, bool deep = true) const; + + + static BArchivable* Instantiate(BMessage* from); + + + virtual status_t Perform(perform_code d, void* arg); ??? + + + + + BArchivable* instantiate_object(BMessage* from, image_id* id); + + + BArchivable* instantiate_object(BMessage* from); + + + bool validate_instantiation(BMessage* from, const char* class_name); + + + instantiation_func find_instantiation_func(const char* class_name, const char* sig); + + + instantiation_func find_instantiation_func(const char* class_name); + + + instantiation_func find_instantiation_func(BMessage* archive_data); + + +
+
+ + + BApplication(const char* signature); + + + BApplication(const char* signature, status_t* error); + + + BApplication(BMessage* data); + + + virtual ~BApplication(); + + + static BArchivable* Instantiate(BMessage* data); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + status_t InitCheck() const; + + + virtual thread_id Run(); + + + virtual void Quit(); + + + virtual bool QuitRequested(); + + + virtual void Pulse(); + + + virtual void ReadyToRun(); + + + virtual void MessageReceived(BMessage* msg); + + + virtual void ArgvReceived(int32 argc, char** argv); + + + virtual void AppActivated(bool active); + + + virtual void RefsReceived(BMessage* a_message); + + + virtual void AboutRequested(); + + + virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); + + + void ShowCursor(); + + + void HideCursor(); + + + void ObscureCursor(); + + + bool IsCursorHidden() const; + + + void SetCursor(const void* cursor); + + + void SetCursor(const BCursor* cursor, bool sync=true); + + + int32 CountWindows() const; + + + BWindow* WindowAt(int32 index) const; + + + int32 CountLoopers() const; + + + BLooper* LooperAt(int32 index) const; + + + bool IsLaunching() const; + + + status_t GetAppInfo(app_info* info) const; + + + static BResources* AppResources(); + + + virtual void DispatchMessage(BMessage* an_event, BHandler* handler); + + + void SetPulseRate(bigtime_t rate); + + + virtual status_t GetSupportedSuites(BMessage* data); + + +
+
+ + + BWindow(BRect frame, const char* title, window_type type, uint32 flags, uint32 workspace = B_CURRENT_WORKSPACE); + + + BWindow(BRect frame, const char* title, window_look look, window_feel feel, uint32 flags, uint32 workspace = B_CURRENT_WORKSPACE); + + + BWindow(BMessage* data); + + + virtual ~BWindow(); + + + static BArchivable* Instantiate(BMessage* data); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + virtual void Quit(); + + + void Close(); + + + void AddChild(BView* child, BView* before = NULL); + + + bool RemoveChild(BView* child); + + + int32 CountChildren() const; + + + BView* ChildAt(int32 index) const; + + + virtual void DispatchMessage(BMessage* message, BHandler* handler); + + + virtual void MessageReceived(BMessage* message); + + + virtual void FrameMoved(BPoint new_position); + + + virtual void WorkspacesChanged(uint32 old_ws, uint32 new_ws); + + + virtual void WorkspaceActivated(int32 ws, bool state); + + + virtual void FrameResized(float new_width, float new_height); + + + virtual void Minimize(bool minimize); + + + virtual void Zoom(BPoint rec_position, float rec_width, float rec_height); + + + void Zoom(); + + + void SetZoomLimits(float max_h, float max_v); + + + virtual void ScreenChanged(BRect screen_size, color_space depth); + + + void SetPulseRate(bigtime_t rate); + + + bigtime_t PulseRate() const; + + + void AddShortcut(uint32 key, uint32 modifiers, BMessage* msg); + + + void AddShortcut(uint32 key, uint32 modifiers, BMessage* msg, BHandler* target); + + + void RemoveShortcut(uint32 key, uint32 modifiers); + + + void SetDefaultButton(BButton* button); + + + BButton* DefaultButton() const; + + + virtual void MenusBeginning(); + + + virtual void MenusEnded(); + + + bool NeedsUpdate() const; + + + void UpdateIfNeeded(); + + + BView* FindView(const char* view_name) const; + + + BView* FindView(BPoint) const; + + + BView* CurrentFocus() const; + + + void Activate(bool = true); + + + virtual void WindowActivated(bool state); + + + void ConvertToScreen(BPoint* pt) const; + + + BPoint ConvertToScreen(BPoint pt) const; + + + void ConvertFromScreen(BPoint* pt) const; + + + BPoint ConvertFromScreen(BPoint pt) const; + + + void ConvertToScreen(BRect* rect) const; + + + BRect ConvertToScreen(BRect rect) const; + + + void ConvertFromScreen(BRect* rect) const; + + + BRect ConvertFromScreen(BRect rect) const; + + + void MoveBy(float dx, float dy); + + + void MoveTo(BPoint); + + + void MoveTo(float x, float y); + + + void ResizeBy(float dx, float dy); + + + void ResizeTo(float width, float height); + + + virtual void Show(); + + + virtual void Hide(); + + + bool IsHidden() const; + + + bool IsMinimized() const; + + + void Flush() const; + + + void Sync() const; + + + status_t SendBehind(const BWindow* window); + + + void DisableUpdates(); + + + void EnableUpdates(); + + + void BeginViewTransaction(); + + + void EndViewTransaction(); + + + BRect Bounds() const; + + + BRect Frame() const; + + + const char* Title() const; + + + void SetTitle(const char* title); + + + bool IsFront() const; + + + bool IsActive() const; + + + void SetKeyMenuBar(BMenuBar* bar); + + + BMenuBar* KeyMenuBar() const; + + + void SetSizeLimits(float min_h, float max_h, float min_v, float max_v); + + + void GetSizeLimits(float* min_h, float* max_h, float* min_v, float* max_v); + + + uint32 Workspaces() const; + + + void SetWorkspaces(uint32); + + + BView* LastMouseMovedView() const; + + + virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); + + + virtual status_t GetSupportedSuites(BMessage* data); + + + status_t AddToSubset(BWindow* window); + + + status_t RemoveFromSubset(BWindow* window); + + + virtual status_t Perform(perform_code d, void* arg); + + + status_t SetType(window_type type); + + + window_type Type() const; + + + status_t SetLook(window_look look); + + + window_look Look() const; + + + status_t SetFeel(window_feel feel); + + + window_feel Feel() const; + + + status_t SetFlags(uint32); + + + uint32 Flags() const; + + + bool IsModal() const; + + + bool IsFloating() const; + + + status_t SetWindowAlignment(window_alignment mode, int32 h, int32 hOffset = 0, int32 width = 0, int32 widthOffset = 0, int32 v = 0, int32 vOffset = 0, int32 height = 0, int32 heightOffset = 0); + + + status_t GetWindowAlignment(window_alignment* mode = NULL, int32* h = NULL, int32* hOffset = NULL, int32* width = NULL, int32* widthOffset = NULL, int32* v = NULL, int32* vOffset = NULL, int32* height = NULL, int32* heightOffset = NULL) const; + + + virtual bool QuitRequested(); + + + virtual thread_id Run(); + + + virtual void task_looper(); + + +
+
+ + + BView(BRect frame, const char* name, uint32 resizeMask, uint32 flags); + + + BView(BMessage* data); + + + virtual ~BView(); + + + static BArchivable* Instantiate(BMessage* data); + + + virtual status_t Archive(BMessage* data, bool deep = true) const; + + + virtual void AttachedToWindow(); + + + virtual void AllAttached(); + + + virtual void DetachedFromWindow(); + + + virtual void AllDetached(); + + + virtual void MessageReceived(BMessage* msg); + + + void AddChild(BView* child, BView* before = NULL); + + + bool RemoveChild(BView* child); + + + int32 CountChildren() const; + + + BView* ChildAt(int32 index) const; + + + BView* NextSibling() const; + + + BView* PreviousSibling() const; + + + bool RemoveSelf(); + + + BWindow* Window() const; + + + virtual void Draw(BRect updateRect); + + + virtual void MouseDown(BPoint where); + + + virtual void MouseUp(BPoint where); + + + virtual void MouseMoved(BPoint where, uint32 code, const BMessage* a_message); + + + virtual void WindowActivated(bool state); + + + virtual void KeyDown(const char* bytes, int32 numBytes); + + + virtual void KeyUp(const char* bytes, int32 numBytes); + + + virtual void Pulse(); + + + virtual void FrameMoved(BPoint new_position); + + + virtual void FrameResized(float new_width, float new_height); + + + virtual void TargetedByScrollView(BScrollView* scroll_view); + + + void BeginRectTracking(BRect startRect, uint32 style = B_TRACK_WHOLE_RECT); + + + void EndRectTracking(); + + + void GetMouse(BPoint* location, uint32* buttons, bool checkMessageQueue = true); + + + void DragMessage(BMessage* aMessage, BRect dragRect, BHandler* reply_to = NULL); + + + void DragMessage(BMessage* aMessage, BBitmap* anImage, BPoint offset, BHandler* reply_to = NULL); + + + void DragMessage(BMessage* aMessage, BBitmap* anImage, drawing_mode dragMode, BPoint offset, BHandler* reply_to = NULL); + + + BView* FindView(const char* name) const; + + + BView* Parent() const; + + + BRect Bounds() const; + + + BRect Frame() const; + + + void ConvertToScreen(BPoint* pt) const; + + + BPoint ConvertToScreen(BPoint pt) const; + + + void ConvertFromScreen(BPoint* pt) const; + + + BPoint ConvertFromScreen(BPoint pt) const; + + + void ConvertToScreen(BRect* r) const; + + + BRect ConvertToScreen(BRect r) const; + + + void ConvertFromScreen(BRect* r) const; + + + BRect ConvertFromScreen(BRect r) const; + + + void ConvertToParent(BPoint* pt) const; + + + BPoint ConvertToParent(BPoint pt) const; + + + void ConvertFromParent(BPoint* pt) const; + + + BPoint ConvertFromParent(BPoint pt) const; + + + void ConvertToParent(BRect* r) const; + + + BRect ConvertToParent(BRect r) const; + + + void ConvertFromParent(BRect* r) const; + + + BRect ConvertFromParent(BRect r) const; + + + BPoint LeftTop() const; + + + void GetClippingRegion(BRegion* region) const; + + + virtual void ConstrainClippingRegion(BRegion* region); + + + void ClipToPicture(BPicture* picture, BPoint where = B_ORIGIN, bool sync = true); + + + void ClipToInversePicture(BPicture* picture, BPoint where = B_ORIGIN, bool sync = true); + + + virtual void SetDrawingMode(drawing_mode mode); + + + drawing_mode DrawingMode() const; + + + void SetBlendingMode(source_alpha srcAlpha, alpha_function alphaFunc); + + + void GetBlendingMode(source_alpha* srcAlpha, alpha_function* alphaFunc) const; + + + virtual void SetPenSize(float size); + + + float PenSize() const; + + + void SetViewCursor(const BCursor* cursor, bool sync=true); + + + virtual void SetViewColor(rgb_color c); + + + void SetViewColor(uchar r, uchar g, uchar b, uchar a = 255); + + + rgb_color ViewColor() const; + + + void SetViewBitmap(const BBitmap* bitmap, BRect srcRect, BRect dstRect, uint32 followFlags=B_FOLLOW_TOP|B_FOLLOW_LEFT, uint32 options = B_TILE_BITMAP); + + + void SetViewBitmap(const BBitmap* bitmap, uint32 followFlags = B_FOLLOW_TOP|B_FOLLOW_LEFT, uint32 options = B_TILE_BITMAP); + + + void ClearViewBitmap(); + + + status_t SetViewOverlay(const BBitmap* overlay, BRect srcRect, BRect dstRect, rgb_color* colorKey, uint32 followFlags = B_FOLLOW_TOP|B_FOLLOW_LEFT, uint32 options = 0); + + + status_t SetViewOverlay(const BBitmap* overlay, rgb_color* colorKey, uint32 followFlags = B_FOLLOW_TOP|B_FOLLOW_LEFT, uint32 options = 0); + + + void ClearViewOverlay(); + + + virtual void SetHighColor(rgb_color a_color); + + + void SetHighColor(uchar r, uchar g, uchar b, uchar a = 255); + + + rgb_color HighColor() const; + + + virtual void SetLowColor(rgb_color a_color); + + + void SetLowColor(uchar r, uchar g, uchar b, uchar a = 255); + + + rgb_color LowColor() const; + + + void SetLineMode(cap_mode lineCap, join_mode lineJoin, float miterLimit = B_DEFAULT_MITER_LIMIT); + + + join_mode LineJoinMode() const; + + + cap_mode LineCapMode() const; + + + float LineMiterLimit() const; + + + void SetOrigin(BPoint pt); + + + void SetOrigin(float x, float y); + + + BPoint Origin() const; + + + void PushState(); + + + void PopState(); + + + void MovePenTo(BPoint pt); + + + void MovePenTo(float x, float y); + + + void MovePenBy(float x, float y); + + + BPoint PenLocation() const; + + + void StrokeLine(BPoint toPt, pattern p = B_SOLID_HIGH); + + + void StrokeLine(BPoint pt0, BPoint pt1, pattern p = B_SOLID_HIGH); + + + void BeginLineArray(int32 count); + + + void AddLine(BPoint pt0, BPoint pt1, rgb_color col); + + + void EndLineArray(); + + + void StrokePolygon(const BPolygon* aPolygon, bool closed = true, pattern p = B_SOLID_HIGH); + + + void StrokePolygon(const BPoint* ptArray, int32 numPts, bool closed = true, pattern p = B_SOLID_HIGH); + + + void StrokePolygon(const BPoint* ptArray, int32 numPts, BRect bounds, bool closed = true, pattern p = B_SOLID_HIGH); + + + void FillPolygon(const BPolygon* aPolygon, pattern p = B_SOLID_HIGH); + + + void FillPolygon(const BPoint* ptArray, int32 numPts, pattern p = B_SOLID_HIGH); + + + void FillPolygon(const BPoint* ptArray, int32 numPts, BRect bounds, pattern p = B_SOLID_HIGH); + + + void StrokeTriangle(BPoint pt1, BPoint pt2, BPoint pt3, BRect bounds, pattern p = B_SOLID_HIGH); + + + void StrokeTriangle(BPoint pt1, BPoint pt2, BPoint pt3, pattern p = B_SOLID_HIGH); + + + void FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3, pattern p = B_SOLID_HIGH); + + + void FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3, BRect bounds,pattern p = B_SOLID_HIGH); + + + void StrokeRect(BRect r, pattern p = B_SOLID_HIGH); + + + void FillRect(BRect r, pattern p = B_SOLID_HIGH); + + + void FillRegion(BRegion* a_region, pattern p= B_SOLID_HIGH); + + + void InvertRect(BRect r); + + + void StrokeRoundRect(BRect r, float xRadius, float yRadius, pattern p = B_SOLID_HIGH); + + + void FillRoundRect(BRect r, float xRadius, float yRadius, pattern p = B_SOLID_HIGH); + + + void StrokeEllipse(BPoint center, float xRadius, float yRadius, pattern p = B_SOLID_HIGH); + + + void StrokeEllipse(BRect r, pattern p = B_SOLID_HIGH); + + + void FillEllipse(BPoint center, float xRadius, float yRadius, pattern p = B_SOLID_HIGH); + + + void FillEllipse(BRect r, pattern p = B_SOLID_HIGH); + + + void StrokeArc(BPoint center, float xRadius, float yRadius, float start_angle, float arc_angle, pattern p = B_SOLID_HIGH); + + + void StrokeArc(BRect r, float start_angle, float arc_angle, pattern p = B_SOLID_HIGH); + + + void FillArc(BPoint center, float xRadius, float yRadius, float start_angle, float arc_angle, pattern p = B_SOLID_HIGH); + + + void FillArc(BRect r, float start_angle, float arc_angle, pattern p = B_SOLID_HIGH); + + + void StrokeBezier(BPoint* controlPoints, pattern p = B_SOLID_HIGH); + + + void FillBezier( BPoint* controlPoints, pattern p = B_SOLID_HIGH); + + + void StrokeShape(BShape* shape, pattern p = B_SOLID_HIGH); + + + void FillShape(BShape* shape, pattern p = B_SOLID_HIGH); + + + void CopyBits(BRect src, BRect dst); + + + void DrawBitmapAsync(const BBitmap* aBitmap, BRect srcRect, BRect dstRect); + + + void DrawBitmapAsync(const BBitmap* aBitmap); + + + void DrawBitmapAsync(const BBitmap* aBitmap, BPoint where); + + + void DrawBitmapAsync(const BBitmap* aBitmap, BRect dstRect); + + + void DrawBitmap(const BBitmap* aBitmap, BRect srcRect, BRect dstRect); + + + void DrawBitmap(const BBitmap* aBitmap); + + + void DrawBitmap(const BBitmap* aBitmap, BPoint where); + + + void DrawBitmap(const BBitmap* aBitmap, BRect dstRect); + + + void DrawChar(char aChar); + + + void DrawChar(char aChar, BPoint location); + + + void DrawString(const char* aString, escapement_delta* delta = NULL); + + + void DrawString(const char* aString, BPoint location, escapement_delta* delta = NULL); + + + void DrawString(const char* aString, int32 length, escapement_delta* delta = NULL); + + + void DrawString(const char* aString, int32 length, BPoint location, escapement_delta* delta = 0L); + + + virtual void SetFont(const BFont* font, uint32 mask = B_FONT_ALL); + + + void GetFont(BFont* font) const; + + + void TruncateString(BString* in_out, uint32 mode, float width) const; + + + float StringWidth(const char* string) const; + + + float StringWidth(const char* string, int32 length) const; + + + void GetStringWidths(char* stringArray[], int32 lengthArray[], int32 numStrings, float widthArray[]) const; + + + void SetFontSize(float size); + + + void ForceFontAliasing(bool enable); + + + void GetFontHeight(font_height* height) const; + + + void Invalidate(BRect invalRect); + + + void Invalidate(const BRegion* invalRegion); + + + void Invalidate(); + + + void SetDiskMode(char* filename, long offset); + + + void BeginPicture(BPicture* a_picture); + + + void AppendToPicture(BPicture* a_picture); + + + BPicture* EndPicture(); + + + void DrawPicture(const BPicture* a_picture); + + + void DrawPicture(const BPicture* a_picture, BPoint where); + + + void DrawPicture(const char* filename, long offset, BPoint where); + + + void DrawPictureAsync(const BPicture* a_picture); + + + void DrawPictureAsync(const BPicture* a_picture, BPoint where); + + + void DrawPictureAsync(const char* filename, long offset, BPoint where); + + + status_t SetEventMask(uint32 mask, uint32 options=0); + + + uint32 EventMask(); + + + status_t SetMouseEventMask(uint32 mask, uint32 options=0); + + + virtual void SetFlags(uint32 flags); + + + uint32 Flags() const; + + + virtual void SetResizingMode(uint32 mode); + + + uint32 ResizingMode() const; + + + void MoveBy(float dh, float dv); + + + void MoveTo(BPoint where); + + + void MoveTo(float x, float y); + + + void ResizeBy(float dh, float dv); + + + void ResizeTo(float width, float height); + + + void ScrollBy(float dh, float dv); + + + void ScrollTo(float x, float y); + + + virtual void ScrollTo(BPoint where); + + + virtual void MakeFocus(bool focusState = true); + + + bool IsFocus() const; + + + virtual void Show(); + + + virtual void Hide(); + + + bool IsHidden() const; + + + bool IsHidden(const BView* looking_from) const; + + + void Flush() const; + + + void Sync() const; + + + virtual void GetPreferredSize(float* width, float* height); + + + virtual void ResizeToPreferred(); + + + BScrollBar* ScrollBar(orientation posture) const; + + + virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); + + + virtual status_t GetSupportedSuites(BMessage* data); + + + bool IsPrinting() const; + + + void SetScale(float scale) const; + + + virtual status_t Perform(perform_code d, void* arg); + + + virtual void DrawAfterChildren(BRect r); + + +
+
+ +
+ + + BDataIO + + + virtual ~BDataIO(); + + + + + BMallocIO(); + + + virtual ~BMallocIO(); + + + virtual ssize_t ReadAt(off_t pos, void *buffer, size_t size); + + + virtual ssize_t WriteAt(off_t pos, const void *buffer, size_t size); + + + virtual off_t Seek(off_t pos, uint32 seek_mode); + + + virtual off_t Position() const; + + + virtual status_t SetSize(off_t size); + + + void SetBlockSize(size_t blocksize); + + + const void* Buffer() const; + + + size_t BufferLength() const; + + + + + BMemoryIO(void *p, size_t len); + + + BMemoryIO(const void *p, size_t len); + + + virtual ~BMemoryIO(); + + + virtual ssize_t ReadAt(off_t pos, void *buffer, size_t size); + + + virtual ssize_t WriteAt(off_t pos, const void *buffer, size_t size); + + + virtual off_t Seek(off_t pos, uint32 seek_mode); + + + virtual off_t Position() const; + + + virtual status_t SetSize(off_t size); + + + + + BPositionIO(); + + + virtual ~BPositionIO(); + + + virtual ssize_t Read(void *buffer, size_t size); + + + virtual ssize_t Write(const void *buffer, size_t size); + + + virtual status_t SetSize(off_t size); + + +
+
+ + + convert_from_utf8 + + + convert_to_utf8 + + + + + bool operator<(const char *, const BString &); + + + bool operator<=(const char *, const BString &); + + + bool operator==(const char *, const BString &); + + + bool operator>(const char *, const BString &); + + + bool operator>=(const char *, const BString &); + + + bool operator!=(const char *, const BString &); + + + int Compare(const BString &, const BString &); + + + int ICompare(const BString &, const BString &); + + + int Compare(const BString *, const BString *); + + + int ICompare(const BString *, const BString *); + + + + + BList(int32 itemsPerBlock = 20); + + + BList(const BList&); + + + virtual ~BList(); + + + BList& operator=(const BList &from); + + + bool AddItem(void *item); + + + bool AddItem(void *item, int32 atIndex); + + + bool AddList(BList *newItems); + + + bool AddList(BList *newItems, int32 atIndex); + + + bool RemoveItem(void *item); + + + void* RemoveItem(int32 index); + + + bool RemoveItems(int32 index, int32 count); + + + bool ReplaceItem(int32 index, void *newItem); + + + void MakeEmpty(); + + + void SortItems(int (*cmp)(const void *, const void *)); + + + bool SwapItems(int32 indexA, int32 indexB); + + + bool MoveItem(int32 fromIndex, int32 toIndex); + + + void* ItemAt(int32) const; + + + void* ItemAtFast(int32) const; + + + void* FirstItem() const; + + + void* LastItem() const; + + + void* Items() const; + + + bool HasItem(void *item) const; + + + int32 IndexOf(void *item) const; + + + int32 CountItems() const; + + + bool IsEmpty() const; + + + void DoForEach(bool (*func)(void *)); + + + void DoForEach(bool (*func)(void *, void *), void *); + + + + + BString(); + + + BString(const char *); + + + BString(const BString &); + + + BString(const char *, int32 maxLength); + + + ~BString(); + + + const char* String() const; + + + int32 Length() const; + + + int32 CountChars() const; + + + BString& operator=(const BString &); + + + BString& operator=(const char *); + + + BString& operator=(char); + + + BString& SetTo(const char *); + + + BString& SetTo(const char *, int32 length); + + + BString& SetTo(const BString &from); + + + BString& Adopt(BString &from); + + + BString& SetTo(const BString &, int32 length); + + + BString& Adopt(BString &from, int32 length); + + + BString& SetTo(char, int32 count); + + + BString& CopyInto(BString &into, int32 fromOffset, int32 length) const; + + + void CopyInto(char *into, int32 fromOffset, int32 length) const; + + + BString& operator+=(const BString &); + + + BString& operator+=(const char *); + + + BString& operator+=(char); + + + BString& Append(const BString &); + + + BString& Append(const char *); + + + BString& Append(const BString &, int32 length); + + + BString& Append(const char *, int32 length); + + + BString& Append(char, int32 count); + + + BString& Prepend(const char *); + + + BString& Prepend(const BString &); + + + BString& Prepend(const char *, int32); + + + BString& Prepend(const BString &, int32); + + + BString& Prepend(char, int32 count); + + + BString& Insert(const char *, int32 pos); + + + BString& Insert(const char *, int32 length, int32 pos); + + + BString& Insert(const char *, int32 fromOffset, int32 length, int32 pos); + + + BString& Insert(const BString &, int32 pos); + + + BString& Insert(const BString &, int32 length, int32 pos); + + + BString& Insert(const BString &, int32 fromOffset, int32 length, int32 pos); + + + BString& Insert(char, int32 count, int32 pos); + + + BString& Truncate(int32 newLength, bool lazy = true); + + + BString& Remove(int32 from, int32 length); + + + BString& RemoveFirst(const BString &); + + + BString& RemoveLast(const BString &); + + + BString& RemoveAll(const BString &); + + + BString& RemoveFirst(const char *); + + + BString& RemoveLast(const char *); + + + BString& RemoveAll(const char *); + + + BString& RemoveSet(const char *setOfCharsToRemove); + + + BString& MoveInto(BString &into, int32 from, int32 length); + + + void MoveInto(char *into, int32 from, int32 length); + + + bool operator<(const BString &) const; + + + bool operator<=(const BString &) const; + + + bool operator==(const BString &) const; + + + bool operator>=(const BString &) const; + + + bool operator>(const BString &) const; + + + bool operator!=(const BString &) const; + + + bool operator<(const char *) const; + + + bool operator<=(const char *) const; + + + bool operator==(const char *) const; + + + bool operator>=(const char *) const; + + + bool operator>(const char *) const; + + + bool operator!=(const char *) const; + + + int Compare(const BString &) const; + + + int Compare(const char *) const; + + + int Compare(const BString &, int32 n) const; + + + int Compare(const char *, int32 n) const; + + + int ICompare(const BString &) const; + + + int ICompare(const char *) const; + + + int ICompare(const BString &, int32 n) const; + + + int ICompare(const char *, int32 n) const; + + + int32 FindFirst(const BString &) const; + + + int32 FindFirst(const char *) const; + + + int32 FindFirst(const BString &, int32 fromOffset) const; + + + int32 FindFirst(const char *, int32 fromOffset) const; + + + int32 FindFirst(char) const; + + + int32 FindFirst(char, int32 fromOffset) const; + + + int32 FindLast(const BString &) const; + + + int32 FindLast(const char *) const; + + + int32 FindLast(const BString &, int32 beforeOffset) const; + + + int32 FindLast(const char *, int32 beforeOffset) const; + + + int32 FindLast(char) const; + + + int32 FindLast(char, int32 fromOffset) const; + + + int32 IFindFirst(const BString &) const; + + + int32 IFindFirst(const char *) const; + + + int32 IFindFirst(const BString &, int32 fromOffset) const; + + + int32 IFindFirst(const char *, int32 fromOffset) const; + + + int32 IFindLast(const BString &) const; + + + int32 IFindLast(const char *) const; + + + int32 IFindLast(const BString &, int32 beforeOffset) const; + + + int32 IFindLast(const char *, int32 beforeOffset) const; + + + BString& ReplaceFirst(char replaceThis, char withThis); + + + BString& ReplaceLast(char replaceThis, char withThis); + + + BString& ReplaceAll(char replaceThis, char withThis, int32 fromOffset = 0); + + + BString& Replace(char replaceThis, char withThis, int32 maxReplaceCount, int32 fromOffset = 0); + + + BString& ReplaceFirst(const char *replaceThis, const char *withThis); + + + BString& ReplaceLast(const char *replaceThis, const char *withThis); + + + BString& ReplaceAll(const char *replaceThis, const char *withThis, int32 fromOffset = 0); + + + BString& Replace(const char *replaceThis, const char *withThis, int32 maxReplaceCount, int32 fromOffset = 0); + + + BString& IReplaceFirst(char replaceThis, char withThis); + + + BString& IReplaceLast(char replaceThis, char withThis); + + + BString& IReplaceAll(char replaceThis, char withThis, int32 fromOffset = 0); + + + BString& IReplace(char replaceThis, char withThis, int32 maxReplaceCount, int32 fromOffset = 0); + + + BString& IReplaceFirst(const char *replaceThis, const char *withThis); + + + BString& IReplaceLast(const char *replaceThis, const char *withThis); + + + BString& IReplaceAll(const char *replaceThis, const char *withThis, int32 fromOffset = 0); + + + BString& IReplace(const char *replaceThis, const char *withThis, int32 maxReplaceCount, int32 fromOffset = 0); + + + BString& ReplaceSet(const char *setOfChars, char with); + + + BString& ReplaceSet(const char *setOfChars, const char *with); + + + char operator[](int32 index) const; + + + char& operator[](int32 index); + + + char ByteAt(int32 index) const; + + + char* LockBuffer(int32 maxLength); + + + BString& UnlockBuffer(int32 length = -1); + + + BString& ToLower(); + + + BString& ToUpper(); + + + BString& Capitalize(); + + + BString& CapitalizeEachWord(); + + + BString& CharacterEscape(const char* original, const char* setOfCharsToEscape, char escapeWith); + + + BString& CharacterEscape(const char *setOfCharsToEscape, char escapeWith); + + + BString& CharacterDeescape(const char *original, char escapeChar); + + + BString& CharacterDeescape(char escapeChar); + + + BString& operator<<(const char *); + + + BString& operator<<(const BString &); + + + BString& operator<<(char); + + + BString& operator<<(int); + + + BString& operator<<(unsigned int); + + + BString& operator<<(uint32); + + + BString& operator<<(int32); + + + BString& operator<<(uint64); + + + BString& operator<<(int64); + + + BString& operator<<(float); + + + + + BBlockCache(size_t cache_size, size_t block_size, uint32 type); + + + virtual ~BBlockCache(); + + + void* Get(size_t block_size); + + + void Save(void *pointer, size_t block_size); + + + + + BStopWatch(const char *name, bool silent = false); + + + virtual ~BStopWatch(); + + + void Suspend(); + + + void Resume(); + + + bigtime_t Lap(); + + + bigtime_t ElapsedTime() const; + + + void Reset(); + + + const char* Name() const; + + +
+
+ + + BAutolock(BLocker *lock); + + + BAutolock(BLocker &lock); + + + BAutolock(BLooper *looper); + + + ~BAutolock(); + + + bool IsLocked(); + + + + + BLocker(); + + + BLocker(const char *name); + + + BLocker(bool benaphore_style); + + + BLocker(const char *name, bool benaphore_style); + + + BLocker(const char *name, bool benaphore_style, bool); + + + virtual ~BLocker(); + + + bool Lock(void); + + + status_t LockWithTimeout(bigtime_t timeout); + + + void Unlock(void); + + + thread_id LockingThread(void) const; + + + bool IsLocked(void) const; + + + int32 CountLocks(void) const; + + + int32 CountLockRequests(void) const; + + + sem_id Sem(void) const; + + +
+
+
diff --git a/docs/develop/ikteam/schedule/applicationkit/ApplicationKitMilestones.html b/docs/develop/ikteam/schedule/applicationkit/ApplicationKitMilestones.html new file mode 100644 index 0000000000..7f74a1d97c --- /dev/null +++ b/docs/develop/ikteam/schedule/applicationkit/ApplicationKitMilestones.html @@ -0,0 +1,165 @@ + + + Application Kit Milestones + + + +

Application Kit Milestones

+ +
    +
  1. + Interface specs completed for all classes, functions, structs + + + + + + + + + + + + + +
    2%
    +

    + + +
  2. +
  3. + Use cases completed for all classes, functions, structs + + + + + + + + + + + + + +
    2%
    +

    + + +
  4. +
  5. + Unit tests completed for all classes, functions, structs + + + + + + + + + + + + + +
    2%
    +

    + + +
  6. +
  7. + Design discussions completed for all classes, functions, structs + + + + + + + + + + + + + +
    2%
    +

    + + +
  8. +
  9. + Messaging complete + + + + + + + + + + + + + +
    19%
    +

    + +
  10. + BHandler complete + +
  11. + BLooper complete + +
  12. + Roster complete + +
  13. + Clipboard complete + +
  14. + BCursor complete + +
  15. + Scripting Support complete + +
  16. + +
  17. + Alpha +
  18. +
  19. + Beta 1 +
  20. +
  21. + Beta 2 +
  22. +
  23. + Release Candidate 1 +
  24. +
  25. + 1.0! +
  26. +
+ +
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + + diff --git a/docs/develop/ikteam/schedule/applicationkit/BCursor.html b/docs/develop/ikteam/schedule/applicationkit/BCursor.html new file mode 100644 index 0000000000..c1f912e66a --- /dev/null +++ b/docs/develop/ikteam/schedule/applicationkit/BCursor.html @@ -0,0 +1,305 @@ + + + BCursor Tasks + + +

BCursor Tasks

+ + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task SummaryOwner
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BCursor + + Gabe Yoder +
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task Details
BCursor Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BCursor(const void* cursorData); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BCursor(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BCursor(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* into, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ +

+
+

+ + + + + + + + + + +
Legend
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Functional SpecFunctional Spec
Use CasesUse Cases
Unit TestsUnit Tests
Technical SpecTechnical Spec
ImplementationImplementation
CompletedCompleted
+
+
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + diff --git a/docs/develop/ikteam/schedule/applicationkit/BHandler.html b/docs/develop/ikteam/schedule/applicationkit/BHandler.html new file mode 100644 index 0000000000..49798e06ab --- /dev/null +++ b/docs/develop/ikteam/schedule/applicationkit/BHandler.html @@ -0,0 +1,930 @@ + + + BHandler Tasks + + +

BHandler Tasks

+ + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task SummaryOwner
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BHandler + + Erik Jaesler +
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task Details
BHandler Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BHandler(const char* name = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BHandler(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BHandler(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage* message); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BLooper* Looper() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetName(const char* name); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const char* Name() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetNextHandler(BHandler* handler); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BHandler* NextHandler() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AddFilter(BMessageFilter* filter); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool RemoveFilter(BMessageFilter* filter); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetFilterList(BList* filters); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BList* FilterList(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool LockLooper(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t LockLooperWithTimeout(bigtime_t timeout); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void UnlockLooper(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetSupportedSuites(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t StartWatching(BMessenger, uint32 what); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t StartWatchingAll(BMessenger); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t StopWatching(BMessenger, uint32 what); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t StopWatchingAll(BMessenger); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t StartWatching(BHandler* , uint32 what); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t StartWatchingAll(BHandler* ); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t StopWatching(BHandler* , uint32 what); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t StopWatchingAll(BHandler* ); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SendNotices(uint32 what, const BMessage* = 0); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsWatched() const; +
+ +

+
+

+ + + + + + + + + + +
Legend
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Functional SpecFunctional Spec
Use CasesUse Cases
Unit TestsUnit Tests
Technical SpecTechnical Spec
ImplementationImplementation
CompletedCompleted
+
+
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + diff --git a/docs/develop/ikteam/schedule/applicationkit/BLooper.html b/docs/develop/ikteam/schedule/applicationkit/BLooper.html new file mode 100644 index 0000000000..f8628d935f --- /dev/null +++ b/docs/develop/ikteam/schedule/applicationkit/BLooper.html @@ -0,0 +1,1280 @@ + + + BLooper Tasks + + +

BLooper Tasks

+ + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task SummaryOwner
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BLooper + + Erik Jaesler +
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task Details
BLooper Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BLooper(const char* name = NULL, int32 priority = B_NORMAL_PRIORITY, int32 port_capacity = B_LOOPER_PORT_DEFAULT_CAPACITY); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BLooper(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BLooper(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t PostMessage(uint32 command); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t PostMessage(BMessage* message); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t PostMessage(uint32 command, BHandler* handler, BHandler* reply_to = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t PostMessage(BMessage* message, BHandler* handler, BHandler* reply_to = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DispatchMessage(BMessage* message, BHandler* handler); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessage* CurrentMessage() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessage* DetachCurrentMessage(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessageQueue* MessageQueue() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsMessageWaiting() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void AddHandler(BHandler* handler); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool RemoveHandler(BHandler* handler); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 CountHandlers() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BHandler* HandlerAt(int32 index) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 IndexOf(BHandler* handler) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BHandler* PreferredHandler() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetPreferredHandler(BHandler* handler); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual thread_id Run(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Quit(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool QuitRequested(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool Lock(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Unlock(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsLocked() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t LockWithTimeout(bigtime_t timeout); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ thread_id Thread() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ team_id Team() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BLooper* LooperForThread(thread_id tid); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ thread_id LockingThread() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 CountLocks() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 CountLockRequests() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ sem_id Sem() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetSupportedSuites(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AddCommonFilter(BMessageFilter* filter); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool RemoveCommonFilter(BMessageFilter* filter); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetCommonFilterList(BList* filters); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BList* CommonFilterList() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessage* MessageFromPort(bigtime_t = B_INFINITE_TIMEOUT); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void task_looper(); +
+ +

+
+

+ + + + + + + + + + +
Legend
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Functional SpecFunctional Spec
Use CasesUse Cases
Unit TestsUnit Tests
Technical SpecTechnical Spec
ImplementationImplementation
CompletedCompleted
+
+
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + diff --git a/docs/develop/ikteam/schedule/applicationkit/Clipboard.html b/docs/develop/ikteam/schedule/applicationkit/Clipboard.html new file mode 100644 index 0000000000..17743bea2e --- /dev/null +++ b/docs/develop/ikteam/schedule/applicationkit/Clipboard.html @@ -0,0 +1,555 @@ + + + Clipboard Tasks + + +

Clipboard Tasks

+ + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task SummaryOwner
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BClipboard + + Gabe Yoder +
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task Details
BClipboard Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BClipboard(const char* name, bool transient = false); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BClipboard(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const char* Name() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ uint32 LocalCount() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ uint32 SystemCount() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t StartWatching(BMessenger target); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t StopWatching(BMessenger target); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool Lock(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Unlock(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsLocked() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t Clear(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t Commit(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t Revert(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessenger DataSource() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessage* Data() const; +
+ +

+
+

+ + + + + + + + + + +
Legend
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Functional SpecFunctional Spec
Use CasesUse Cases
Unit TestsUnit Tests
Technical SpecTechnical Spec
ImplementationImplementation
CompletedCompleted
+
+
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + diff --git a/docs/develop/ikteam/schedule/applicationkit/Messaging.html b/docs/develop/ikteam/schedule/applicationkit/Messaging.html new file mode 100644 index 0000000000..e36b49de9c --- /dev/null +++ b/docs/develop/ikteam/schedule/applicationkit/Messaging.html @@ -0,0 +1,6153 @@ + + + Messaging Tasks + + +

Messaging Tasks

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task SummaryOwner
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BInvoker + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessage + + William Bull +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessageFilter + + Erik Jaesler +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessageQueue + + Jeremy Rand +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessageRunner + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessenger + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessenger Support + + +
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task Details
BInvoker Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BInvoker(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BInvoker(BMessage* message, const BHandler* handler, const BLooper* looper = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BInvoker(BMessage* message, BMessenger target); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BInvoker(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t SetMessage(BMessage* message); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessage* Message() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ uint32 Command() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t SetTarget(const BHandler* h, const BLooper* loop = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t SetTarget(BMessenger messenger); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsTargetLocal() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BHandler* Target(BLooper** looper = NULL) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessenger Messenger() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t SetHandlerForReply(BHandler* handler); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BHandler* HandlerForReply() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Invoke(BMessage* msg = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t InvokeNotify(BMessage* msg, uint32 kind = B_CONTROL_INVOKED); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetTimeout(bigtime_t timeout); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bigtime_t Timeout() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ uint32 InvokeKind(bool* notify = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void BeginInvokeNotify(uint32 kind = B_CONTROL_INVOKED); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void EndInvokeNotify(); +
BMessage Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessage(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessage(uint32 what); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessage(const BMessage& a_message); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BMessage(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessage& operator=(const BMessage& msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t GetInfo(type_code typeRequested, int32 which, char** name, type_code* typeReturned, int32* count = NULL) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t GetInfo(const char* name, type_code* type, int32* c = 0) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t GetInfo(const char* name, type_code* type, bool* fixed_size) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 CountNames(type_code type) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsEmpty() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsSystem() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsReply() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void PrintToStream() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t Rename(const char* old_entry, const char* new_entry); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool WasDelivered() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsSourceWaiting() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsSourceRemote() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessenger ReturnAddress() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const BMessage* Previous() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool WasDropped() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPoint DropPoint(BPoint* offset = NULL) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SendReply(uint32 command, BHandler* reply_to = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SendReply(BMessage* the_reply, BHandler* reply_to = NULL, bigtime_t timeout = B_INFINITE_TIMEOUT); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SendReply(BMessage* the_reply, BMessenger reply_to, bigtime_t timeout = B_INFINITE_TIMEOUT); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SendReply(uint32 command, BMessage* reply_to_reply); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SendReply(BMessage* the_reply, BMessage* reply_to_reply, bigtime_t send_timeout = B_INFINITE_TIMEOUT, bigtime_t reply_timeout = B_INFINITE_TIMEOUT); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ ssize_t FlattenedSize() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t Flatten(char* buffer, ssize_t size) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t Flatten(BDataIO* stream, ssize_t* size = NULL) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t Unflatten(const char* flat_buffer); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t Unflatten(BDataIO* stream); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t AddSpecifier(const char* property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t AddSpecifier(const char* property, int32 index); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t AddSpecifier(const char* property, int32 index, int32 range); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t AddSpecifier(const char* property, const char* name); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t AddSpecifier(const BMessage* specifier); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetCurrentSpecifier(int32 index); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t GetCurrentSpecifier(int32* index, BMessage* specifier = NULL, int32* form = NULL, const char** property = NULL) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool HasSpecifiers() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t PopSpecifier(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t AddRect(const char* name, BRect a_rect); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t AddPoint(const char* name, BPoint a_point); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t AddString(const char* name, const char* a_string); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t AddString(const char* name, const BString& a_string); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t AddInt8(const char* name, int8 val); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t AddInt16(const char* name, int16 val); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t AddInt32(const char* name, int32 val); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t AddInt64(const char* name, int64 val); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t AddBool(const char* name, bool a_boolean); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t AddFloat(const char* name, float a_float); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t AddDouble(const char* name, double a_double); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t AddPointer(const char* name, const void* ptr); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t AddMessenger(const char* name, BMessenger messenger); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t AddRef(const char* name, const entry_ref* ref); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t AddMessage(const char* name, const BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t AddFlat(const char* name, BFlattenable* obj, int32 count = 1); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t AddData(const char* name, type_code type, const void* data, ssize_t numBytes, bool is_fixed_size = true, int32 count = 1); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t RemoveData(const char* name, int32 index = 0); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t RemoveName(const char* name); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t MakeEmpty(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindRect(const char* name, BRect* rect) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindRect(const char* name, int32 index, BRect* rect) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindPoint(const char* name, BPoint* pt) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindPoint(const char* name, int32 index, BPoint* pt) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindString(const char* name, const char** str) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindString(const char* name, int32 index, const char** str) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindString(const char* name, BString* str) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindString(const char* name, int32 index, BString* str) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindInt8(const char* name, int8* value) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindInt8(const char* name, int32 index, int8* val) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindInt16(const char* name, int16* value) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindInt16(const char* name, int32 index, int16* val) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindInt32(const char* name, int32* value) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindInt32(const char* name, int32 index, int32* val) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindInt64(const char* name, int64* value) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindInt64(const char* name, int32 index, int64* val) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindBool(const char* name, bool* value) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindBool(const char* name, int32 index, bool* value) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindFloat(const char* name, float* f) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindFloat(const char* name, int32 index, float* f) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindDouble(const char* name, double* d) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindDouble(const char* name, int32 index, double* d) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindPointer(const char* name, void** ptr) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindPointer(const char* name, int32 index, void** ptr) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindMessenger(const char* name, BMessenger* m) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindMessenger(const char* name, int32 index, BMessenger* m) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindRef(const char* name, entry_ref* ref) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindRef(const char* name, int32 index, entry_ref* ref) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindMessage(const char* name, BMessage* msg) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindMessage(const char* name, int32 index, BMessage* msg) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindFlat(const char* name, BFlattenable* obj) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindFlat(const char* name, int32 index, BFlattenable* obj) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindData(const char* name, type_code type, const void** data, ssize_t* numBytes) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindData(const char* name, type_code type, int32 index, const void** data, ssize_t* numBytes) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplaceRect(const char* name, BRect a_rect); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplaceRect(const char* name, int32 index, BRect a_rect); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplacePoint(const char* name, BPoint a_point); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplacePoint(const char* name, int32 index, BPoint a_point); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplaceString(const char* name, const char* string); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplaceString(const char* name, int32 index, const char* string); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplaceString(const char* name, const BString& string); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplaceString(const char* name, int32 index, const BString& string); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplaceInt8(const char* name, int8 val); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplaceInt8(const char* name, int32 index, int8 val); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplaceInt16(const char* name, int16 val); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplaceInt16(const char* name, int32 index, int16 val); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplaceInt32(const char* name, int32 val); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplaceInt32(const char* name, int32 index, int32 val); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplaceInt64(const char* name, int64 val); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplaceInt64(const char* name, int32 index, int64 val); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplaceBool(const char* name, bool a_bool); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplaceBool(const char* name, int32 index, bool a_bool); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplaceFloat(const char* name, float a_float); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplaceFloat(const char* name, int32 index, float a_float); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplaceDouble(const char* name, double a_double); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplaceDouble(const char* name, int32 index, double a_double); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplacePointer(const char* name, const void* ptr); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplacePointer(const char* name,int32 index,const void* ptr); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplaceMessenger(const char* name, BMessenger messenger); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplaceMessenger(const char* name, int32 index, BMessenger msngr); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplaceRef( const char* name,const entry_ref* ref); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplaceRef( const char* name, int32 index, const entry_ref* ref); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplaceMessage(const char* name, const BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplaceMessage(const char* name, int32 index, const BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplaceFlat(const char* name, BFlattenable* obj); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplaceFlat(const char* name, int32 index, BFlattenable* obj); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplaceData(const char* name, type_code type, const void* data, ssize_t data_size); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReplaceData(const char* name, type_code type, int32 index, const void* data, ssize_t data_size); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void* operator new(size_t size); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void operator delete(void* ptr, size_t size); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool HasRect(const char* , int32 n = 0) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool HasPoint(const char* , int32 n = 0) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool HasString(const char* , int32 n = 0) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool HasInt8(const char* , int32 n = 0) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool HasInt16(const char* , int32 n = 0) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool HasInt32(const char* , int32 n = 0) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool HasInt64(const char* , int32 n = 0) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool HasBool(const char* , int32 n = 0) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool HasFloat(const char* , int32 n = 0) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool HasDouble(const char* , int32 n = 0) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool HasPointer(const char* , int32 n = 0) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool HasMessenger(const char* , int32 n = 0) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool HasRef(const char* , int32 n = 0) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool HasMessage(const char* , int32 n = 0) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool HasFlat(const char* , const BFlattenable* ) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool HasFlat(const char* ,int32 ,const BFlattenable* ) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool HasData(const char* , type_code , int32 n = 0) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect FindRect(const char* , int32 n = 0) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPoint FindPoint(const char* , int32 n = 0) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const char* FindString(const char* , int32 n = 0) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int8 FindInt8(const char* , int32 n = 0) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int16 FindInt16(const char* , int32 n = 0) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 FindInt32(const char* , int32 n = 0) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int64 FindInt64(const char* , int32 n = 0) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool FindBool(const char* , int32 n = 0) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ float FindFloat(const char* , int32 n = 0) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ double FindDouble(const char* , int32 n = 0) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessage(BMessage* a_message); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ NOTE: Add convenience functions for struct rgb_color +
BMessageFilter Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessageFilter(uint32 what, filter_hook func = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessageFilter(message_delivery delivery, message_source source, filter_hook func = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessageFilter(message_delivery delivery, message_source source, uint32 what, filter_hook func = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessageFilter(const BMessageFilter& filter); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessageFilter(const BMessageFilter* filter); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BMessageFilter(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessageFilter& operator=(const BMessageFilter &from); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual filter_result Filter(BMessage* message, BHandler** target); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ message_delivery MessageDelivery() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ message_source MessageSource() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ uint32 Command() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool FiltersAnyCommand() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BLooper* Looper() const; +
BMessageQueue Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessageQueue(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BMessageQueue(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void AddMessage(BMessage* an_event); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool RemoveMessage(BMessage* an_event); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessage* NextMessage(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessage* FindMessage(int32 index) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessage* FindMessage(uint32 what, int32 index = 0) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 CountMessages() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsEmpty() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool Lock(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Unlock(); +
BMessageRunner Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessageRunner(BMessenger target, const BMessage* msg, bigtime_t interval, int32 count = -1); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessageRunner(BMessenger target, const BMessage* msg, bigtime_t interval, int32 count, BMessenger reply_to); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BMessageRunner(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t InitCheck() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetInterval(bigtime_t interval); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetCount(int32 count); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t GetInfo(bigtime_t* interval, int32* count) const; +
BMessenger Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessenger(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessenger(const char* mime_sig, team_id team = -1, status_t* perr = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessenger(const BHandler* handler, const BLooper* looper = NULL, status_t* perr = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessenger(const BMessenger& from); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ ~BMessenger(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsTargetLocal() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BHandler* Target(BLooper** looper) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool LockTarget() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t LockTargetWithTimeout(bigtime_t timeout) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SendMessage(uint32 command, BHandler* reply_to = NULL) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SendMessage(BMessage* a_message, BHandler* reply_to = NULL, bigtime_t timeout = B_INFINITE_TIMEOUT) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SendMessage(BMessage* a_message, BMessenger reply_to, bigtime_t timeout = B_INFINITE_TIMEOUT) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SendMessage(uint32 command, BMessage* reply) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SendMessage(BMessage* a_message, BMessage* reply, bigtime_t send_timeout = B_INFINITE_TIMEOUT, bigtime_t reply_timeout = B_INFINITE_TIMEOUT) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessenger& operator=(const BMessenger &from); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool operator==(const BMessenger &other) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsValid() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ team_id Team() const; +
BMessenger Support Functions
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool operator<(const BMessenger & a, const BMessenger & b); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool operator!=(const BMessenger & a, const BMessenger & b); +
+ +

+
+

+ + + + + + + + + + +
Legend
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Functional SpecFunctional Spec
Use CasesUse Cases
Unit TestsUnit Tests
Technical SpecTechnical Spec
ImplementationImplementation
CompletedCompleted
+
+
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + diff --git a/docs/develop/ikteam/schedule/applicationkit/Roster.html b/docs/develop/ikteam/schedule/applicationkit/Roster.html new file mode 100644 index 0000000000..eeeec8c2d2 --- /dev/null +++ b/docs/develop/ikteam/schedule/applicationkit/Roster.html @@ -0,0 +1,955 @@ + + + Roster Tasks + + +

Roster Tasks

+ + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task SummaryOwner
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRoster + + Joe Banafato +
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task Details
BRoster Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRoster(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ ~BRoster(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsRunning(const char* mime_sig) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsRunning(entry_ref* ref) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ team_id TeamFor(const char* mime_sig) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ team_id TeamFor(entry_ref* ref) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetAppList(BList* team_id_list) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetAppList(const char* sig, BList* team_id_list) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t GetAppInfo(const char* sig, app_info* info) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t GetAppInfo(entry_ref* ref, app_info* info) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t GetRunningAppInfo(team_id team, app_info* info) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t GetActiveAppInfo(app_info* info) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindApp(const char* mime_type, entry_ref* app) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t FindApp(entry_ref* ref, entry_ref* app) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t Broadcast(BMessage* msg) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t Broadcast(BMessage* msg, BMessenger reply_to) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t StartWatching(BMessenger target, uint32 event_mask = B_REQUEST_LAUNCHED | B_REQUEST_QUIT) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t StopWatching(BMessenger target) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ActivateApp(team_id team) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t Launch(const char* mime_type, BMessage* initial_msgs = NULL, team_id* app_team = NULL) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t Launch(const char* mime_type, BList* message_list, team_id* app_team = NULL) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t Launch(const char* mime_type, int argc, char** args, team_id* app_team = NULL) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t Launch(const entry_ref* ref, const BMessage* initial_message = NULL, team_id* app_team = NULL) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t Launch(const entry_ref* ref, const BList* message_list, team_id* app_team = NULL) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t Launch(const entry_ref* ref, int argc, const char* const* args, team_id* app_team = NULL) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetRecentDocuments(BMessage* refList, int32 maxCount, const char* ofType = NULL, const char* openedByAppSig = NULL) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetRecentDocuments(BMessage* refList, int32 maxCount, const char* ofTypeList[], int32 ofTypeListCount, const char* openedByAppSig = NULL) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetRecentFolders(BMessage* refList, int32 maxCount, const char* openedByAppSig = NULL) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetRecentApps(BMessage* refList, int32 maxCount) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void AddToRecentDocuments(const entry_ref* doc, const char* appSig = NULL) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void AddToRecentFolders(const entry_ref* folder,const char* appSig = NULL) const; +
+ +

+
+

+ + + + + + + + + + +
Legend
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Functional SpecFunctional Spec
Use CasesUse Cases
Unit TestsUnit Tests
Technical SpecTechnical Spec
ImplementationImplementation
CompletedCompleted
+
+
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + diff --git a/docs/develop/ikteam/schedule/applicationkit/ScriptingSupport.html b/docs/develop/ikteam/schedule/applicationkit/ScriptingSupport.html new file mode 100644 index 0000000000..e67d0fa404 --- /dev/null +++ b/docs/develop/ikteam/schedule/applicationkit/ScriptingSupport.html @@ -0,0 +1,580 @@ + + + Scripting Support Tasks + + +

Scripting Support Tasks

+ + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task SummaryOwner
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPropertyInfo + + Jeremy Rand +
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task Details
BPropertyInfo Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPropertyInfo(property_info* p = NULL, value_info* ci = NULL, bool free_on_delete = false); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BPropertyInfo(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual int32 FindMatch(BMessage* msg, int32 index, BMessage* spec, int32 form, const char* prop, void* data = NULL) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool IsFixedSize() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual type_code TypeCode() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ssize_t FlattenedSize() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Flatten(void* buffer, ssize_t size) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool AllowsTypeCode(type_code code) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Unflatten(type_code c, const void* buf, ssize_t s); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const property_info* Properties() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const value_info* Values() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 CountProperties() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 CountValues() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void PrintToStream() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static bool FindCommand(uint32, int32, property_info* ); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static bool FindSpecifier(uint32, property_info* ); +
+ +

+
+

+ + + + + + + + + + +
Legend
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Functional SpecFunctional Spec
Use CasesUse Cases
Unit TestsUnit Tests
Technical SpecTechnical Spec
ImplementationImplementation
CompletedCompleted
+
+
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + diff --git a/docs/develop/ikteam/schedule/assignments.html b/docs/develop/ikteam/schedule/assignments.html new file mode 100644 index 0000000000..047746b224 --- /dev/null +++ b/docs/develop/ikteam/schedule/assignments.html @@ -0,0 +1,789 @@ + + + Interface Kit Team Assignments + + +

+ Interface Kit Team Assignments and Open Tasks +
+

+ +

+ Assignments: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Erik Jaesler +
+ + BMessageFilter +
+ + BHandler +
+ + BLooper +
+ + BAlert +
+ + BArchivable +
+ + BArchivable +
+ + BApplication +
+ Gabe Yoder +
+ + BClipboard +
+ + BCursor +
+ Graham Gilmore +
+ + BBlockCache +
+ Graham Macdonald +
+ + BPictureButton +
+ Greg Gelfond +
+ + BPoint +
+ + BShape +
+ + BStringItem +
+ Issac Yonemoto +
+ + BRect +
+ + BRegion +
+ + BList +
+ Jeremy Rand +
+ + BMessageQueue +
+ + BPropertyInfo +
+ + BDeskbar +
+ + BAutoLock +
+ + BLocker +
+ Joe Banafato +
+ + BRoster +
+ Justin Gasper +
+ + BMenu +
+ + BMenuBar +
+ + BMenuItem +
+ Marc Flerackers +
+ + BControl +
+ + BButton +
+ + BCheckBox +
+ + BRadioButton +
+ + BTab +
+ + BTabView +
+ + BBox +
+ + BStatusBar +
+ Staffan Hellstrom +
+ + BPolygon +
+ + BSlider +
+ Steve Vallee +
+ + BDataIO +
+ + BMallocIO +
+ + BMemoryIO +
+ + BPositionIO +
+ + Misc +
+ + BString Utility +
+ + BString +
+ + BStopWatch +
+ Ulrich Wimboeck +
+ + BListItem +
+ + BListView +
+ + BOutlineListView +
+ William Bull +
+ + BMessage +
+ Xavier Castellan +
+ + BBitmap +
+ + +

+ Open Tasks: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Application Kit +
+ + BInvoker +
+ + BMessageRunner +
+ + BMessenger +
+ + BMessenger Support +
+ Integration +
+ + BWindow +
+ + BView +
+ Interface Kit +
+ + BPicture +
+ + BScreen +
+ + BShapeIterator +
+ + Screen Support +
+ + BFont +
+ + Font Support +
+ + BColorControl +
+ + BStringView +
+ + BScrollBar +
+ + BScrollView +
+ + Scrollbar Config +
+ + BSeparatorItem +
+ + BMenuField +
+ + BPopUpMenu +
+ + Menu Config +
+ + BTextView +
+ + BTextControl +
+ + unicode_block +
+ + Deskbar Support +
+ + Mouse Config +
+ + Workspace Support +
+ + Keyboard Config +
+ + UI Color Info +
+ + Miscellaneous +
+ + BDragger +
+ + BShelf +
+ + BChannelControl +
+ + BChannelSlider +
+ + BMultiChannelControl +
+ + BOptionControl +
+ + BOptionPopUp +
+
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + \ No newline at end of file diff --git a/docs/develop/ikteam/schedule/index.html b/docs/develop/ikteam/schedule/index.html new file mode 100644 index 0000000000..c822e0810a --- /dev/null +++ b/docs/develop/ikteam/schedule/index.html @@ -0,0 +1,147 @@ + + + Interface Kit Team Schedule + + +

Interface Kit Team Schedule

+

+Here is the schedule for the Interface Kit Team. To help organize our work, +tasks have been broken into 4 general areas: +

+

+Organizationally, it's best to consider these as separate projects within the +scope of the IK Team's charter. As such, core contributors should pick a +project and stick with it -- it will make things a lot easier to keep track of, +and losing track of stuff would be a bad thing. =) +

+DarkWyrm is the technical lead for the app_server; he has done an enormous amount +of research and he is currently in the best position to lead the effort. +

+Erik Jakowatz will continue in his capacity as overall project lead, as well as +being directly involved in Integration as technical lead. +

+A word of warning: this schedule is downright huge because of the sheer number of +items to be completed. There is a paper available in which the rationale behind the +schedule is discussed. +

+
+

Current Status

+Here are some fuzzy indicators of what progress the team has made base on the number of +outstanding tasks completed. No warranty is made concerning the accuracy of these +graphs. =) +

+ + + + + + + + + +
Overall
+ + + + + + + + + +
12%
+ + + + +

Application Kit
+ + + + + + + + + + + + +
2%
+ + + +

Interface Kit
+ + + + + + + + + + + + +
4%
+ + + +

Integration
+ + + + + + + + + + + + +
25%
+ + + +

Support Kit
+ + + + + + + + + + + + +
20%
+ + + +
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + \ No newline at end of file diff --git a/docs/develop/ikteam/schedule/integration/BApplication.html b/docs/develop/ikteam/schedule/integration/BApplication.html new file mode 100644 index 0000000000..7ed1d7bf05 --- /dev/null +++ b/docs/develop/ikteam/schedule/integration/BApplication.html @@ -0,0 +1,1030 @@ + + + BApplication Tasks + + +

BApplication Tasks

+ + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task SummaryOwner
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BApplication + + Erik Jaesler +
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task Details
BApplication Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BApplication(const char* signature); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BApplication(const char* signature, status_t* error); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BApplication(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BApplication(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t InitCheck() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual thread_id Run(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Quit(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool QuitRequested(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Pulse(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ReadyToRun(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ArgvReceived(int32 argc, char** argv); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AppActivated(bool active); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void RefsReceived(BMessage* a_message); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AboutRequested(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void ShowCursor(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void HideCursor(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void ObscureCursor(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsCursorHidden() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetCursor(const void* cursor); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetCursor(const BCursor* cursor, bool sync=true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 CountWindows() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BWindow* WindowAt(int32 index) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 CountLoopers() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BLooper* LooperAt(int32 index) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsLaunching() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t GetAppInfo(app_info* info) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BResources* AppResources(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DispatchMessage(BMessage* an_event, BHandler* handler); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetPulseRate(bigtime_t rate); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetSupportedSuites(BMessage* data); +
+ +

+
+

+ + + + + + + + + + +
Legend
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Functional SpecFunctional Spec
Use CasesUse Cases
Unit TestsUnit Tests
Technical SpecTechnical Spec
ImplementationImplementation
CompletedCompleted
+
+
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + diff --git a/docs/develop/ikteam/schedule/integration/BArchivable.html b/docs/develop/ikteam/schedule/integration/BArchivable.html new file mode 100644 index 0000000000..3dd64e1dc8 --- /dev/null +++ b/docs/develop/ikteam/schedule/integration/BArchivable.html @@ -0,0 +1,513 @@ + + + BArchivable Tasks + + +

BArchivable Tasks

+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task SummaryOwner
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BArchivable + + Erik Jaesler +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BArchivable + + Erik Jaesler +
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task Details
BArchivable Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BArchivable(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BArchivable(BMessage* from); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ ~BArchivable(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* into, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* from); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Perform(perform_code d, void* arg); ??? +
BArchivable Functions
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BArchivable* instantiate_object(BMessage* from, image_id* id); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BArchivable* instantiate_object(BMessage* from); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool validate_instantiation(BMessage* from, const char* class_name); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ instantiation_func find_instantiation_func(const char* class_name, const char* sig); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ instantiation_func find_instantiation_func(const char* class_name); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ instantiation_func find_instantiation_func(BMessage* archive_data); +
+ +

+
+

+ + + + + + + + + + +
Legend
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Functional SpecFunctional Spec
Use CasesUse Cases
Unit TestsUnit Tests
Technical SpecTechnical Spec
ImplementationImplementation
CompletedCompleted
+
+
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + diff --git a/docs/develop/ikteam/schedule/integration/BView.html b/docs/develop/ikteam/schedule/integration/BView.html new file mode 100644 index 0000000000..996c008b86 --- /dev/null +++ b/docs/develop/ikteam/schedule/integration/BView.html @@ -0,0 +1,5105 @@ + + + BView Tasks + + +

BView Tasks

+ + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task SummaryOwner
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BView + + +
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task Details
BView Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BView(BRect frame, const char* name, uint32 resizeMask, uint32 flags); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BView(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BView(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AttachedToWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllAttached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DetachedFromWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllDetached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void AddChild(BView* child, BView* before = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool RemoveChild(BView* child); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 CountChildren() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BView* ChildAt(int32 index) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BView* NextSibling() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BView* PreviousSibling() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool RemoveSelf(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BWindow* Window() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Draw(BRect updateRect); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseDown(BPoint where); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseUp(BPoint where); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseMoved(BPoint where, uint32 code, const BMessage* a_message); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void WindowActivated(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void KeyDown(const char* bytes, int32 numBytes); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void KeyUp(const char* bytes, int32 numBytes); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Pulse(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameMoved(BPoint new_position); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameResized(float new_width, float new_height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void TargetedByScrollView(BScrollView* scroll_view); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void BeginRectTracking(BRect startRect, uint32 style = B_TRACK_WHOLE_RECT); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void EndRectTracking(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetMouse(BPoint* location, uint32* buttons, bool checkMessageQueue = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void DragMessage(BMessage* aMessage, BRect dragRect, BHandler* reply_to = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void DragMessage(BMessage* aMessage, BBitmap* anImage, BPoint offset, BHandler* reply_to = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void DragMessage(BMessage* aMessage, BBitmap* anImage, drawing_mode dragMode, BPoint offset, BHandler* reply_to = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BView* FindView(const char* name) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BView* Parent() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect Bounds() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect Frame() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void ConvertToScreen(BPoint* pt) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPoint ConvertToScreen(BPoint pt) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void ConvertFromScreen(BPoint* pt) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPoint ConvertFromScreen(BPoint pt) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void ConvertToScreen(BRect* r) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect ConvertToScreen(BRect r) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void ConvertFromScreen(BRect* r) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect ConvertFromScreen(BRect r) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void ConvertToParent(BPoint* pt) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPoint ConvertToParent(BPoint pt) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void ConvertFromParent(BPoint* pt) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPoint ConvertFromParent(BPoint pt) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void ConvertToParent(BRect* r) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect ConvertToParent(BRect r) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void ConvertFromParent(BRect* r) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect ConvertFromParent(BRect r) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPoint LeftTop() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetClippingRegion(BRegion* region) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ConstrainClippingRegion(BRegion* region); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void ClipToPicture(BPicture* picture, BPoint where = B_ORIGIN, bool sync = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void ClipToInversePicture(BPicture* picture, BPoint where = B_ORIGIN, bool sync = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetDrawingMode(drawing_mode mode); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ drawing_mode DrawingMode() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetBlendingMode(source_alpha srcAlpha, alpha_function alphaFunc); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetBlendingMode(source_alpha* srcAlpha, alpha_function* alphaFunc) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetPenSize(float size); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ float PenSize() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetViewCursor(const BCursor* cursor, bool sync=true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetViewColor(rgb_color c); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetViewColor(uchar r, uchar g, uchar b, uchar a = 255); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ rgb_color ViewColor() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetViewBitmap(const BBitmap* bitmap, BRect srcRect, BRect dstRect, uint32 followFlags=B_FOLLOW_TOP|B_FOLLOW_LEFT, uint32 options = B_TILE_BITMAP); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetViewBitmap(const BBitmap* bitmap, uint32 followFlags = B_FOLLOW_TOP|B_FOLLOW_LEFT, uint32 options = B_TILE_BITMAP); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void ClearViewBitmap(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetViewOverlay(const BBitmap* overlay, BRect srcRect, BRect dstRect, rgb_color* colorKey, uint32 followFlags = B_FOLLOW_TOP|B_FOLLOW_LEFT, uint32 options = 0); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetViewOverlay(const BBitmap* overlay, rgb_color* colorKey, uint32 followFlags = B_FOLLOW_TOP|B_FOLLOW_LEFT, uint32 options = 0); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void ClearViewOverlay(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetHighColor(rgb_color a_color); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetHighColor(uchar r, uchar g, uchar b, uchar a = 255); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ rgb_color HighColor() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetLowColor(rgb_color a_color); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetLowColor(uchar r, uchar g, uchar b, uchar a = 255); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ rgb_color LowColor() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetLineMode(cap_mode lineCap, join_mode lineJoin, float miterLimit = B_DEFAULT_MITER_LIMIT); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ join_mode LineJoinMode() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ cap_mode LineCapMode() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ float LineMiterLimit() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetOrigin(BPoint pt); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetOrigin(float x, float y); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPoint Origin() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void PushState(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void PopState(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void MovePenTo(BPoint pt); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void MovePenTo(float x, float y); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void MovePenBy(float x, float y); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPoint PenLocation() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void StrokeLine(BPoint toPt, pattern p = B_SOLID_HIGH); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void StrokeLine(BPoint pt0, BPoint pt1, pattern p = B_SOLID_HIGH); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void BeginLineArray(int32 count); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void AddLine(BPoint pt0, BPoint pt1, rgb_color col); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void EndLineArray(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void StrokePolygon(const BPolygon* aPolygon, bool closed = true, pattern p = B_SOLID_HIGH); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void StrokePolygon(const BPoint* ptArray, int32 numPts, bool closed = true, pattern p = B_SOLID_HIGH); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void StrokePolygon(const BPoint* ptArray, int32 numPts, BRect bounds, bool closed = true, pattern p = B_SOLID_HIGH); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void FillPolygon(const BPolygon* aPolygon, pattern p = B_SOLID_HIGH); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void FillPolygon(const BPoint* ptArray, int32 numPts, pattern p = B_SOLID_HIGH); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void FillPolygon(const BPoint* ptArray, int32 numPts, BRect bounds, pattern p = B_SOLID_HIGH); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void StrokeTriangle(BPoint pt1, BPoint pt2, BPoint pt3, BRect bounds, pattern p = B_SOLID_HIGH); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void StrokeTriangle(BPoint pt1, BPoint pt2, BPoint pt3, pattern p = B_SOLID_HIGH); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3, pattern p = B_SOLID_HIGH); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3, BRect bounds,pattern p = B_SOLID_HIGH); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void StrokeRect(BRect r, pattern p = B_SOLID_HIGH); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void FillRect(BRect r, pattern p = B_SOLID_HIGH); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void FillRegion(BRegion* a_region, pattern p= B_SOLID_HIGH); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void InvertRect(BRect r); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void StrokeRoundRect(BRect r, float xRadius, float yRadius, pattern p = B_SOLID_HIGH); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void FillRoundRect(BRect r, float xRadius, float yRadius, pattern p = B_SOLID_HIGH); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void StrokeEllipse(BPoint center, float xRadius, float yRadius, pattern p = B_SOLID_HIGH); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void StrokeEllipse(BRect r, pattern p = B_SOLID_HIGH); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void FillEllipse(BPoint center, float xRadius, float yRadius, pattern p = B_SOLID_HIGH); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void FillEllipse(BRect r, pattern p = B_SOLID_HIGH); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void StrokeArc(BPoint center, float xRadius, float yRadius, float start_angle, float arc_angle, pattern p = B_SOLID_HIGH); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void StrokeArc(BRect r, float start_angle, float arc_angle, pattern p = B_SOLID_HIGH); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void FillArc(BPoint center, float xRadius, float yRadius, float start_angle, float arc_angle, pattern p = B_SOLID_HIGH); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void FillArc(BRect r, float start_angle, float arc_angle, pattern p = B_SOLID_HIGH); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void StrokeBezier(BPoint* controlPoints, pattern p = B_SOLID_HIGH); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void FillBezier( BPoint* controlPoints, pattern p = B_SOLID_HIGH); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void StrokeShape(BShape* shape, pattern p = B_SOLID_HIGH); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void FillShape(BShape* shape, pattern p = B_SOLID_HIGH); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void CopyBits(BRect src, BRect dst); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void DrawBitmapAsync(const BBitmap* aBitmap, BRect srcRect, BRect dstRect); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void DrawBitmapAsync(const BBitmap* aBitmap); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void DrawBitmapAsync(const BBitmap* aBitmap, BPoint where); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void DrawBitmapAsync(const BBitmap* aBitmap, BRect dstRect); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void DrawBitmap(const BBitmap* aBitmap, BRect srcRect, BRect dstRect); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void DrawBitmap(const BBitmap* aBitmap); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void DrawBitmap(const BBitmap* aBitmap, BPoint where); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void DrawBitmap(const BBitmap* aBitmap, BRect dstRect); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void DrawChar(char aChar); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void DrawChar(char aChar, BPoint location); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void DrawString(const char* aString, escapement_delta* delta = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void DrawString(const char* aString, BPoint location, escapement_delta* delta = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void DrawString(const char* aString, int32 length, escapement_delta* delta = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void DrawString(const char* aString, int32 length, BPoint location, escapement_delta* delta = 0L); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetFont(const BFont* font, uint32 mask = B_FONT_ALL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetFont(BFont* font) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void TruncateString(BString* in_out, uint32 mode, float width) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ float StringWidth(const char* string) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ float StringWidth(const char* string, int32 length) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetStringWidths(char* stringArray[], int32 lengthArray[], int32 numStrings, float widthArray[]) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetFontSize(float size); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void ForceFontAliasing(bool enable); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetFontHeight(font_height* height) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Invalidate(BRect invalRect); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Invalidate(const BRegion* invalRegion); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Invalidate(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetDiskMode(char* filename, long offset); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void BeginPicture(BPicture* a_picture); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void AppendToPicture(BPicture* a_picture); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPicture* EndPicture(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void DrawPicture(const BPicture* a_picture); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void DrawPicture(const BPicture* a_picture, BPoint where); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void DrawPicture(const char* filename, long offset, BPoint where); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void DrawPictureAsync(const BPicture* a_picture); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void DrawPictureAsync(const BPicture* a_picture, BPoint where); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void DrawPictureAsync(const char* filename, long offset, BPoint where); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetEventMask(uint32 mask, uint32 options=0); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ uint32 EventMask(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetMouseEventMask(uint32 mask, uint32 options=0); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetFlags(uint32 flags); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ uint32 Flags() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetResizingMode(uint32 mode); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ uint32 ResizingMode() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void MoveBy(float dh, float dv); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void MoveTo(BPoint where); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void MoveTo(float x, float y); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void ResizeBy(float dh, float dv); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void ResizeTo(float width, float height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void ScrollBy(float dh, float dv); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void ScrollTo(float x, float y); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ScrollTo(BPoint where); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MakeFocus(bool focusState = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsFocus() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Show(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Hide(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsHidden() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsHidden(const BView* looking_from) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Flush() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Sync() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void GetPreferredSize(float* width, float* height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ResizeToPreferred(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BScrollBar* ScrollBar(orientation posture) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetSupportedSuites(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsPrinting() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetScale(float scale) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Perform(perform_code d, void* arg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DrawAfterChildren(BRect r); +
+ +

+
+

+ + + + + + + + + + +
Legend
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Functional SpecFunctional Spec
Use CasesUse Cases
Unit TestsUnit Tests
Technical SpecTechnical Spec
ImplementationImplementation
CompletedCompleted
+
+
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + diff --git a/docs/develop/ikteam/schedule/integration/BWindow.html b/docs/develop/ikteam/schedule/integration/BWindow.html new file mode 100644 index 0000000000..70147aef75 --- /dev/null +++ b/docs/develop/ikteam/schedule/integration/BWindow.html @@ -0,0 +1,2580 @@ + + + BWindow Tasks + + +

BWindow Tasks

+ + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task SummaryOwner
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BWindow + + +
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task Details
BWindow Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BWindow(BRect frame, const char* title, window_type type, uint32 flags, uint32 workspace = B_CURRENT_WORKSPACE); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BWindow(BRect frame, const char* title, window_look look, window_feel feel, uint32 flags, uint32 workspace = B_CURRENT_WORKSPACE); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BWindow(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Quit(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Close(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void AddChild(BView* child, BView* before = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool RemoveChild(BView* child); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 CountChildren() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BView* ChildAt(int32 index) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DispatchMessage(BMessage* message, BHandler* handler); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage* message); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameMoved(BPoint new_position); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void WorkspacesChanged(uint32 old_ws, uint32 new_ws); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void WorkspaceActivated(int32 ws, bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameResized(float new_width, float new_height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Minimize(bool minimize); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Zoom(BPoint rec_position, float rec_width, float rec_height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Zoom(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetZoomLimits(float max_h, float max_v); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ScreenChanged(BRect screen_size, color_space depth); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetPulseRate(bigtime_t rate); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bigtime_t PulseRate() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void AddShortcut(uint32 key, uint32 modifiers, BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void AddShortcut(uint32 key, uint32 modifiers, BMessage* msg, BHandler* target); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void RemoveShortcut(uint32 key, uint32 modifiers); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetDefaultButton(BButton* button); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BButton* DefaultButton() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MenusBeginning(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MenusEnded(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool NeedsUpdate() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void UpdateIfNeeded(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BView* FindView(const char* view_name) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BView* FindView(BPoint) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BView* CurrentFocus() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Activate(bool = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void WindowActivated(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void ConvertToScreen(BPoint* pt) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPoint ConvertToScreen(BPoint pt) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void ConvertFromScreen(BPoint* pt) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPoint ConvertFromScreen(BPoint pt) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void ConvertToScreen(BRect* rect) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect ConvertToScreen(BRect rect) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void ConvertFromScreen(BRect* rect) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect ConvertFromScreen(BRect rect) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void MoveBy(float dx, float dy); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void MoveTo(BPoint); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void MoveTo(float x, float y); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void ResizeBy(float dx, float dy); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void ResizeTo(float width, float height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Show(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Hide(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsHidden() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsMinimized() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Flush() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Sync() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SendBehind(const BWindow* window); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void DisableUpdates(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void EnableUpdates(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void BeginViewTransaction(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void EndViewTransaction(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect Bounds() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect Frame() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const char* Title() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetTitle(const char* title); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsFront() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsActive() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetKeyMenuBar(BMenuBar* bar); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenuBar* KeyMenuBar() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetSizeLimits(float min_h, float max_h, float min_v, float max_v); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetSizeLimits(float* min_h, float* max_h, float* min_v, float* max_v); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ uint32 Workspaces() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetWorkspaces(uint32); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BView* LastMouseMovedView() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetSupportedSuites(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t AddToSubset(BWindow* window); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t RemoveFromSubset(BWindow* window); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Perform(perform_code d, void* arg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetType(window_type type); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ window_type Type() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetLook(window_look look); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ window_look Look() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetFeel(window_feel feel); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ window_feel Feel() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetFlags(uint32); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ uint32 Flags() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsModal() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsFloating() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetWindowAlignment(window_alignment mode, int32 h, int32 hOffset = 0, int32 width = 0, int32 widthOffset = 0, int32 v = 0, int32 vOffset = 0, int32 height = 0, int32 heightOffset = 0); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t GetWindowAlignment(window_alignment* mode = NULL, int32* h = NULL, int32* hOffset = NULL, int32* width = NULL, int32* widthOffset = NULL, int32* v = NULL, int32* vOffset = NULL, int32* height = NULL, int32* heightOffset = NULL) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool QuitRequested(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual thread_id Run(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void task_looper(); +
+ +

+
+

+ + + + + + + + + + +
Legend
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Functional SpecFunctional Spec
Use CasesUse Cases
Unit TestsUnit Tests
Technical SpecTechnical Spec
ImplementationImplementation
CompletedCompleted
+
+
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + diff --git a/docs/develop/ikteam/schedule/integration/IntegrationMilestones.html b/docs/develop/ikteam/schedule/integration/IntegrationMilestones.html new file mode 100644 index 0000000000..2c8b328a85 --- /dev/null +++ b/docs/develop/ikteam/schedule/integration/IntegrationMilestones.html @@ -0,0 +1,156 @@ + + + Integration Milestones + + + +

Integration Milestones

+ +
    +
  1. + Interface specs completed for all classes, functions, structs + + + + + + + + + + + + + +
    25%
    +

    + + +
  2. +
  3. + Use cases completed for all classes, functions, structs + + + + + + + + + + + + + +
    25%
    +

    + + +
  4. +
  5. + Unit tests completed for all classes, functions, structs + + + + + + + + + + + + + +
    25%
    +

    + + +
  6. +
  7. + Design discussions completed for all classes, functions, structs + + + + + + + + + + + + + +
    25%
    +

    + + +
  8. +
  9. + BArchivable complete + + + + + + + + + + + + + +
    100%
    +

    + +
  10. + BApplication complete + +
  11. + BWindow complete + +
  12. + BView complete + +
  13. + +
  14. + Alpha +
  15. +
  16. + Beta 1 +
  17. +
  18. + Beta 2 +
  19. +
  20. + Release Candidate 1 +
  21. +
  22. + 1.0! +
  23. +
+ +
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + + diff --git a/docs/develop/ikteam/schedule/interfacekit/AdvancedControlWidgets.html b/docs/develop/ikteam/schedule/interfacekit/AdvancedControlWidgets.html new file mode 100644 index 0000000000..d81e07b947 --- /dev/null +++ b/docs/develop/ikteam/schedule/interfacekit/AdvancedControlWidgets.html @@ -0,0 +1,3887 @@ + + + Advanced Control Widgets Tasks + + +

Advanced Control Widgets Tasks

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task SummaryOwner
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BChannelControl + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BChannelSlider + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMultiChannelControl + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BOptionControl + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BOptionPopUp + + +
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task Details
BChannelControl Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BChannelControl(BRect frame, const char * name, const char * label, BMessage * model, int32 channel_count = 1, uint32 resize = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BChannelControl(BMessage* from); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BChannelControl(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* into, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Draw(BRect area) = 0; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseDown(BPoint where) = 0; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void KeyDown(const char* bytes, int32 size) = 0; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameResized(float width, float height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetFont(const BFont* font, uint32 mask = B_FONT_ALL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AttachedToWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DetachedFromWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ResizeToPreferred(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void GetPreferredSize(float* width, float* height) = 0; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage* message); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BHandler *ResolveSpecifier(BMessage *msg, int32 index, BMessage *specifier, int32 form, const char *property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetSupportedSuites(BMessage *data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetModificationMessage(BMessage *message); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessage *ModificationMessage() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Invoke(BMessage *msg = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t InvokeChannel(BMessage *msg = NULL, int32 from_channel = 0, int32 channel_count = -1, const bool* in_mask = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t InvokeNotifyChannel(BMessage *msg = NULL, uint32 kind = B_CONTROL_INVOKED, int32 from_channel = 0, int32 channel_count = -1, const bool* in_mask = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual voidSetValue(int32 value); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t SetCurrentChannel(int32 channel); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 CurrentChannel() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual int32 CountChannels() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual int32 MaxChannelCount() const = 0; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t SetChannelCount(int32 channel_count); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 ValueFor(int32 channel) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual int32 GetValue(int32* out_values, int32 from_channel, int32 channel_count) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetValueFor(int32 channel, int32 value); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t SetValue(int32 from_channel, int32 channel_count, const int32* in_values); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetAllValue(int32 values); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetLimitsFor(int32 channel, int32 minimum, int32 maximum); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t GetLimitsFor(int32 channel, int32* minimum, int32* maximum) const ; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t SetLimitsFor(int32 from_channel, int32 channel_count, const int32* minimum, const int32* maximum); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetLimitsFor(int32 from_channel, int32 channel_count, int32* minimum, int32* maximum) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetLimits(int32 minimum, int32 maximum); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t GetLimits(int32* outMinimum, int32* outMaximum) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool SupportsIndividualLimits() const = 0; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t SetLimitLabels(const char* min_label, const char* max_label); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const char* MinLimitLabel() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const char* MaxLimitLabel() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t SetLimitLabelsFor(int32 channel, const char* minLabel, const char* maxLabel); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t SetLimitLabelsFor(int32 from_channel, int32 channel_count, const char* minLabel, const char* maxLabel); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const char* MinLimitLabelFor(int32 channel) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const char* MaxLimitLabelFor(int32 channel) const; +
BChannelSlider Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BChannelSlider(BRect area, const char* name, const char* label, BMessage* model, int32 channels = 1, uint32 resize = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BChannelSlider(BRect area, const char* name, const char* label, BMessage* model, orientation o, int32 channels = 1, uint32 resize = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BChannelSlider(BMessage* from); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BChannelSlider(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* from); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* into, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual orientation Orientation() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetOrientation(orientation o); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual int32 MaxChannelCount() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool SupportsIndividualLimits() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AttachedToWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllAttached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DetachedFromWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllDetached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Draw(BRect area); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseDown(BPoint where); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseUp(BPoint pt); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* message); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void WindowActivated(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void KeyDown(const char* bytes, int32 numBytes); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void KeyUp(const char* bytes, int32 numBytes); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameResized(float width, float height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetFont(const BFont* font, uint32 mask = B_FONT_ALL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MakeFocus(bool focusState = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetEnabled(bool on); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void GetPreferredSize(float* width, float* height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetSupportedSuites(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DrawChannel(BView* into, int32 channel, BRect area, bool pressed); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DrawGroove(BView* into, int32 channel, BPoint tl, BPoint br); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DrawThumb(BView* into, int32 channel, BPoint where, bool pressed ); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual const BBitmap* ThumbFor(int32 channel, bool pressed); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BRect ThumbFrameFor(int32 channel); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual float ThumbDeltaFor(int32 channel); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual float ThumbRangeFor(int32 channel); +
BMultiChannelControl Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMultiChannelControl(BRect frame, const char* name, const char* label, BMessage* model, int32 channel_count = 1, uint32 resize = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMultiChannelControl(BMessage* from); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BMultiChannelControl(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* into, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Draw(BRect area) = 0; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseDown(BPoint where) = 0; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void KeyDown(const char* bytes, int32 size) = 0; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameResized(float width, float height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetFont(const BFont* font, uint32 mask = B_FONT_ALL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AttachedToWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DetachedFromWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ResizeToPreferred(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void GetPreferredSize(float* width, float* height) = 0; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage* message); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetValue(int32 value); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t SetCurrentChannel(int32 channel); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 CurrentChannel() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual int32 CountChannels() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual int32 MaxChannelCount() const = 0; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t SetChannelCount(int32 channel_count); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 ValueFor(int32 channel) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual int32 GetValues(int32* out_values, int32 from_channel, int32 channel_count) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetValueFor(int32 channel, int32 value); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t SetValues(int32 from_channel, int32 channel_count, const int32* in_values); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetAllValues(int32 values); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetLimitsFor(int32 channel, int32 minimum, int32 maximum); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t GetLimitsFor(int32 channel, int32* minimum, int32* maximum) const ; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t SetLimits(int32 from_channel, int32 channel_count, const int32* minimum, const int32* maximum); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetLimits(int32 from_channel, int32 channel_count, int32* minimum, int32* maximum) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetAllLimits(int32 minimum, int32 maximum); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t SetLimitLabels(const char* min_label, const char* max_label); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const char* MinLimitLabel() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const char* MaxLimitLabel() const; +
BOptionControl Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BOptionControl(BRect frame, const char* name, const char* label, BMessage* message, uint32 resize = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BOptionControl(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage* message); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t AddOption(const char* name, int32 value); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual boolGetOptionAt(int32 index, const char** out_name, int32* out_value) = 0; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void RemoveOptionAt(int32 index) = 0; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual int32 CountOptions() const = 0; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_tAddOptionAt(const char* name, int32 value, int32 index) = 0; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual int32 SelectedOption(const char** name = 0, int32* value = 0) const = 0; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t SelectOptionFor(int32 value); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t SelectOptionFor(const char *name); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessage* MakeValueMessage(int32 value); +
BOptionPopUp Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BOptionPopUp(BRect frame, const char* name, const char* label, BMessage* message, uint32 resize = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BOptionPopUp(BRect frame, const char* name, const char* label, BMessage* message, bool fixed, uint32 resize = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ ~BOptionPopUp(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenuField* MenuField(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool GetOptionAt(int32 index, const char** out_name, int32* out_value); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void RemoveOptionAt(int32 index); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual int32 CountOptions() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t AddOptionAt(const char* name, int32 value, int32 index); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllAttached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage* message); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetLabel(const char* text); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetValue(int32 value); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual voidSetEnabled(bool on); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void GetPreferredSize(float* width, float* height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ResizeToPreferred(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual int32 SelectedOption(const char** outName = 0, int32* outValue = 0) const; +
+ +

+
+

+ + + + + + + + + + +
Legend
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Functional SpecFunctional Spec
Use CasesUse Cases
Unit TestsUnit Tests
Technical SpecTechnical Spec
ImplementationImplementation
CompletedCompleted
+
+
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + diff --git a/docs/develop/ikteam/schedule/interfacekit/ControlWidgets.html b/docs/develop/ikteam/schedule/interfacekit/ControlWidgets.html new file mode 100644 index 0000000000..39b13e59ee --- /dev/null +++ b/docs/develop/ikteam/schedule/interfacekit/ControlWidgets.html @@ -0,0 +1,8194 @@ + + + Control Widgets Tasks + + +

Control Widgets Tasks

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task SummaryOwner
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BControl + + Marc Flerackers +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BButton + + Marc Flerackers +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BCheckBox + + Marc Flerackers +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BColorControl + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPictureButton + + Graham Macdonald +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRadioButton + + Marc Flerackers +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BSlider + + Staffan Hellstrom +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BTab + + Marc Flerackers +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BTabView + + Marc Flerackers +
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task Details
BControl Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BControl(BRect frame, const char* name, const char* label, BMessage* message, uint32 resizeMask, uint32 flags); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BControl(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BControl(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void WindowActivated(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AttachedToWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MakeFocus(bool state = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void KeyDown(const char* bytes, int32 numBytes); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseDown(BPoint pt); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseUp(BPoint pt); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DetachedFromWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetLabel(const char* text); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const char* Label() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetValue(int32 value); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 Value() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetEnabled(bool on); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsEnabled() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void GetPreferredSize(float* width, float* height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ResizeToPreferred(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Invoke(BMessage* msg = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetSupportedSuites(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllAttached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllDetached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsFocusChanging() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsTracking() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetTracking(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetValueNoUpdate(int32 value); +
BButton Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BButton(BRect frame, const char* name, const char* label, BMessage* message, uint32 resizeMask = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW | B_NAVIGABLE); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BButton(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BButton(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Draw(BRect updateRect); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseDown(BPoint where); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AttachedToWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void KeyDown(const char* bytes, int32 numBytes); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MakeDefault(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetLabel(const char* text); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsDefault() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void WindowActivated(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseUp(BPoint pt); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DetachedFromWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetValue(int32 value); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void GetPreferredSize(float* width, float* height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ResizeToPreferred(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Invoke(BMessage* msg = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameMoved(BPoint new_position); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameResized(float new_width, float new_height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MakeFocus(bool state = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllAttached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllDetached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetSupportedSuites(BMessage* data); +
BCheckBox Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BCheckBox(BRect frame, const char* name, const char* label, BMessage* message, uint32 resizeMask = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW | B_NAVIGABLE); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BCheckBox(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BCheckBox(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Draw(BRect updateRect); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AttachedToWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseDown(BPoint where); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void WindowActivated(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void KeyDown(const char* bytes, int32 numBytes); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseUp(BPoint pt); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DetachedFromWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetValue(int32 value); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void GetPreferredSize(float* width, float* height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ResizeToPreferred(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Invoke(BMessage* msg = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameMoved(BPoint new_position); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameResized(float new_width, float new_height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetSupportedSuites(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MakeFocus(bool state = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllAttached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllDetached(); +
BColorControl Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BColorControl(BPoint start, color_control_layout layout, float cell_size, const char *name, BMessage *message = NULL, bool use_offscreen = false); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BColorControl(BMessage *data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BColorControl(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable *Instantiate(BMessage *data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage *data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetValue(int32 color_value); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetValue(rgb_color color); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ rgb_color ValueAsColor(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetEnabled(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AttachedToWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage *msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Draw(BRect updateRect); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseDown(BPoint where); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void KeyDown(const char *bytes, int32 numBytes); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetCellSize(float size); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ float CellSize() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetLayout(color_control_layout layout); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ color_control_layout Layout() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void WindowActivated(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseUp(BPoint pt); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseMoved(BPoint pt, uint32 code, const BMessage *msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DetachedFromWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void GetPreferredSize(float *width, float *height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ResizeToPreferred(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Invoke(BMessage *msg = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameMoved(BPoint new_position); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameResized(float new_width, float new_height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BHandler *ResolveSpecifier(BMessage *msg, int32 index, BMessage *specifier, int32 form, const char *property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetSupportedSuites(BMessage *data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MakeFocus(bool state = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllAttached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllDetached(); +
BPictureButton Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPictureButton(BRect frame, const char* name, BPicture* off, BPicture* on, BMessage* message, uint32 behavior = B_ONE_STATE_BUTTON, uint32 resizeMask = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flgs = B_WILL_DRAW | B_NAVIGABLE); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPictureButton(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BPictureButton(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Draw(BRect updateRect); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseDown(BPoint where); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void KeyDown(const char* bytes, int32 numBytes); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetEnabledOn(BPicture* on); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetEnabledOff(BPicture* off); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetDisabledOn(BPicture* on); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetDisabledOff(BPicture* off); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPicture* EnabledOn() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPicture* EnabledOff() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPicture* DisabledOn() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPicture* DisabledOff() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetBehavior(uint32 behavior); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ uint32 Behavior() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseUp(BPoint pt); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void WindowActivated(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AttachedToWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DetachedFromWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetValue(int32 value); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Invoke(BMessage* msg = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameMoved(BPoint new_position); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameResized(float new_width, float new_height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetSupportedSuites(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ResizeToPreferred(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void GetPreferredSize(float* width, float* height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MakeFocus(bool state = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllAttached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllDetached(); +
BRadioButton Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRadioButton(BRect frame, const char* name, const char* label, BMessage* message, uint32 resizMask = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW | B_NAVIGABLE); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRadioButton(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BRadioButton(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Draw(BRect updateRect); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseDown(BPoint where); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AttachedToWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void KeyDown(const char* bytes, int32 numBytes); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetValue(int32 value); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void GetPreferredSize(float* width, float* height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ResizeToPreferred(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Invoke(BMessage* msg = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void WindowActivated(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseUp(BPoint pt); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DetachedFromWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameMoved(BPoint new_position); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameResized(float new_width, float new_height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MakeFocus(bool state = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllAttached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllDetached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetSupportedSuites(BMessage* data); +
BSlider Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BSlider(BRect frame, const char* name, const char* label, BMessage* message, int32 minValue, int32 maxValue, thumb_style thumbType = B_BLOCK_THUMB, uint32 resizingMode = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_NAVIGABLE | B_WILL_DRAW | B_FRAME_EVENTS); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BSlider(BRect frame, const char* name, const char* label, BMessage* message, int32 minValue, int32 maxValue, orientation posture /*= B_HORIZONTAL*/, thumb_style thumbType = B_BLOCK_THUMB, uint32 resizingMode = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_NAVIGABLE | B_WILL_DRAW | B_FRAME_EVENTS); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BSlider(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BSlider(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Perform(perform_code d, void* arg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void WindowActivated(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AttachedToWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllAttached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllDetached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DetachedFromWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameMoved(BPoint new_position); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameResized(float w,float h); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void KeyDown(const char* bytes, int32 n); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseDown(BPoint); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseUp(BPoint pt); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseMoved(BPoint pt, uint32 c, const BMessage* m); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Pulse(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetLabel(const char* label); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetLimitLabels(const char* minLabel, const char* maxLabel); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const char* MinLimitLabel() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const char* MaxLimitLabel() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetValue(int32); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual int32 ValueForPoint(BPoint) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetPosition(float); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ float Position() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetEnabled(bool on); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetLimits(int32* minimum, int32* maximum); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Draw(BRect); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DrawSlider(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DrawBar(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DrawHashMarks(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DrawThumb(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DrawFocusMark(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DrawText(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual char* UpdateText() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BRect BarFrame() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BRect HashMarksFrame() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BRect ThumbFrame() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetFlags(uint32 flags); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetResizingMode(uint32 mode); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void GetPreferredSize( float* width, float* height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ResizeToPreferred(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Invoke(BMessage* msg=NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetSupportedSuites(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetModificationMessage(BMessage* message); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessage* ModificationMessage() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetSnoozeAmount(int32); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 SnoozeAmount() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetKeyIncrementValue(int32 value); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 KeyIncrementValue() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetHashMarkCount(int32 count); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 HashMarkCount() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetHashMarks(hash_mark_location where); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ hash_mark_location HashMarks() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetStyle(thumb_style s); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ thumb_style Style() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetBarColor(rgb_color); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ rgb_color BarColor() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void UseFillColor(bool, const rgb_color* c=NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool FillColor(rgb_color*) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BView* OffscreenView() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ orientation Orientation() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetOrientation(orientation); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ float BarThickness() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetBarThickness(float thickness); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetFont(const BFont* font, uint32 properties = B_FONT_ALL); +
BTab Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BTab(BView* contents=NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BTab(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BTab(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Perform(uint32 d, void* arg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const char* Label() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetLabel(const char* label); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsSelected() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Select(BView* owner); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Deselect(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetEnabled(bool on); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsEnabled() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void MakeFocus(bool infocus=true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsFocus() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetView(BView* contents); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BView* View() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DrawFocusMark(BView* owner, BRect tabFrame); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DrawLabel(BView* owner, BRect tabFrame); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DrawTab(BView* owner, BRect tabFrame, tab_position, bool full=true); +
BTabView Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BTabView(BRect frame, const char* name, button_width width = B_WIDTH_AS_USUAL, uint32 resizingMode = B_FOLLOW_ALL, uint32 flags = B_FULL_UPDATE_ON_RESIZE | B_WILL_DRAW | B_NAVIGABLE_JUMP | B_FRAME_EVENTS | B_NAVIGABLE); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BTabView(BMessage*); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BTabView(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage*); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage*, bool deep=true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Perform(perform_code d, void* arg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void WindowActivated(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AttachedToWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllAttached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllDetached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DetachedFromWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameMoved(BPoint new_position); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameResized(float w,float h); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void KeyDown(const char* bytes, int32 n); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseDown(BPoint); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseUp(BPoint); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Pulse(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Select(int32 tabIndex); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 Selection() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MakeFocus(bool focusState = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetFocusTab(int32 tabIndex, bool focusState); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 FocusTab() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Draw(BRect); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BRect DrawTabs(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DrawBox(BRect selectedTabFrame); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BRect TabFrame(int32 tabIndex) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetFlags(uint32 flags); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetResizingMode(uint32 mode); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void GetPreferredSize( float* width, float* height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ResizeToPreferred(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetSupportedSuites(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AddTab(BView* tabContents, BTab* tab=NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BTab* RemoveTab(int32 tabIndex); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BTab* TabAt(int32 tabIndex) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetTabWidth(button_width s); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ button_width TabWidth() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetTabHeight(float height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ float TabHeight() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BView* ContainerView() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 CountTabs() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BView* ViewForTab(int32 tabIndex) const; +
+ +

+
+

+ + + + + + + + + + +
Legend
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Functional SpecFunctional Spec
Use CasesUse Cases
Unit TestsUnit Tests
Technical SpecTechnical Spec
ImplementationImplementation
CompletedCompleted
+
+
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + diff --git a/docs/develop/ikteam/schedule/interfacekit/Group1Support.html b/docs/develop/ikteam/schedule/interfacekit/Group1Support.html new file mode 100644 index 0000000000..d9dc32b18b --- /dev/null +++ b/docs/develop/ikteam/schedule/interfacekit/Group1Support.html @@ -0,0 +1,2629 @@ + + + Group 1 Support Tasks + + +

Group 1 Support Tasks

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task SummaryOwner
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPoint + + Greg Gelfond +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPolygon + + Staffan Hellstrom +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect + + Issac Yonemoto +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRegion + + Issac Yonemoto +
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task Details
BPoint Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPoint(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPoint(float X, float Y); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPoint(const BPoint& pt); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPoint& operator=(const BPoint& from); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Set(float X, float Y); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void ConstrainTo(BRect rect); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void PrintToStream() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPoint operator+(const BPoint&) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPoint operator-(const BPoint&) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPoint& operator+=(const BPoint&); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPoint& operator-=(const BPoint&); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool operator!=(const BPoint&) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool operator==(const BPoint&) const; +
BPolygon Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPolygon(const BPoint* ptArray, int32 numPoints); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPolygon(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPolygon(const BPolygon* poly); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BPolygon(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPolygon& operator=(const BPolygon& from); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect Frame() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void AddPoints(const BPoint* ptArray, int32 numPoints); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 CountPoints() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void MapTo(BRect srcRect, BRect dstRect); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void PrintToStream() const; +
BRect Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect(const BRect &); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect(float l, float t, float r, float b); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect(BPoint leftTop, BPoint rightBottom); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect& operator=(const BRect &from); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Set(float l, float t, float r, float b); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void PrintToStream() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPoint LeftTop() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPoint RightBottom() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPoint LeftBottom() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPoint RightTop() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetLeftTop(const BPoint); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetRightBottom(const BPoint); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetLeftBottom(const BPoint); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetRightTop(const BPoint); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void InsetBy(BPoint); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void InsetBy(float dx, float dy); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void OffsetBy(BPoint); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void OffsetBy(float dx, float dy); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void OffsetTo(BPoint); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void OffsetTo(float x, float y); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect& InsetBySelf(BPoint); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect& InsetBySelf(float dx, float dy); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect InsetByCopy(BPoint); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect InsetByCopy(float dx, float dy); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect& OffsetBySelf(BPoint); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect& OffsetBySelf(float dx, float dy); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect OffsetByCopy(BPoint); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect OffsetByCopy(float dx, float dy); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect& OffsetToSelf(BPoint); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect& OffsetToSelf(float dx, float dy); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect OffsetToCopy(BPoint); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect OffsetToCopy(float dx, float dy); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool operator==(BRect) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool operator!=(BRect) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect operator&(BRect) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect operator|(BRect) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool Intersects(BRect r) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsValid() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ float Width() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 IntegerWidth() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ float Height() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 IntegerHeight() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool Contains(BPoint) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool Contains(BRect) const; +
BRegion Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRegion(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRegion(const BRegion ®ion); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRegion(const BRect rect); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BRegion(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRegion& operator=(const BRegion &from); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect Frame() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ clipping_rect FrameInt() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect RectAt(int32 index); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ clipping_rect RectAtInt(int32 index); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 CountRects(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Set(BRect newBounds); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Set(clipping_rect newBounds); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool Intersects(BRect r) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool Intersects(clipping_rect r) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool Contains(BPoint pt) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool Contains(int32 x, int32 y); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void PrintToStream() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void OffsetBy(int32 dh, int32 dv); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void MakeEmpty(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Include(BRect r); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Include(clipping_rect r); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Include(const BRegion*); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Exclude(BRect r); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Exclude(clipping_rect r); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Exclude(const BRegion*); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void IntersectWith(const BRegion*); +
+ +

+
+

+ + + + + + + + + + +
Legend
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Functional SpecFunctional Spec
Use CasesUse Cases
Unit TestsUnit Tests
Technical SpecTechnical Spec
ImplementationImplementation
CompletedCompleted
+
+
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + diff --git a/docs/develop/ikteam/schedule/interfacekit/Group2Support.html b/docs/develop/ikteam/schedule/interfacekit/Group2Support.html new file mode 100644 index 0000000000..7abfae7f40 --- /dev/null +++ b/docs/develop/ikteam/schedule/interfacekit/Group2Support.html @@ -0,0 +1,1962 @@ + + + Group 2 Support Tasks + + +

Group 2 Support Tasks

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task SummaryOwner
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPicture + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BScreen + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BShape + + Greg Gelfond +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BShapeIterator + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ Screen Support + + +
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task Details
BPicture Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPicture(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPicture(const BPicture &original); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPicture(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BPicture(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Perform(perform_code d, void* arg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t Play(void* *callBackTable, int32 tableEntries, void* userData); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t Flatten(BDataIO* stream); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t Unflatten(BDataIO* stream); +
BScreen Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BScreen(screen_id id = B_MAIN_SCREEN_ID); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BScreen(BWindow* win); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ ~BScreen(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsValid(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetToNext(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ color_space ColorSpace(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect Frame(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ screen_id ID(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t WaitForRetrace(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t WaitForRetrace(bigtime_t timeout); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ uint8 IndexForColor(rgb_color rgb); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ uint8 IndexForColor(uint8 r, uint8 g, uint8 b, uint8 a = 255); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ rgb_color ColorForIndex(const uint8 index); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ uint8 InvertIndex(uint8 index); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const color_map* ColorMap(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t GetBitmap(BBitmap** screen_shot, bool draw_cursor = true, BRect* bound = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ReadBitmap(BBitmap* buffer, bool draw_cursor = true, BRect* bound = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ rgb_color DesktopColor(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ rgb_color DesktopColor(uint32 index); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetDesktopColor(rgb_color rgb, bool stick = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetDesktopColor(rgb_color rgb, uint32 index, bool stick = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t ProposeMode(display_mode* target, const display_mode* low, const display_mode* high); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t GetModeList(display_mode** mode_list, uint32* count); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t GetMode(display_mode* mode); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t GetMode(uint32 workspace, display_mode* mode); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetMode(display_mode* mode, bool makeDefault = false); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetMode(uint32 workspace, display_mode* mode, bool makeDefault = false); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t GetDeviceInfo(accelerant_device_info* adi); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t GetPixelClockLimits(display_mode* mode, uint32* low, uint32* high); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t GetTimingConstraints(display_timing_constraints* dtc); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetDPMS(uint32 dpms_state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ uint32 DPMSState(void); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ uint32 DPMSCapabilites(void); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPrivateScreen* private_screen(); +
BShape Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BShape(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BShape(const BShape& copyFrom); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BShape(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BShape(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* into, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Clear(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect Bounds() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t AddShape(const BShape* other); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t MoveTo(BPoint point); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t LineTo(BPoint linePoint); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t BezierTo(BPoint controlPoints[3]); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t Close(); +
BShapeIterator Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BShapeIterator(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BShapeIterator(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t IterateMoveTo(BPoint* point); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t IterateLineTo(int32 lineCount, BPoint* linePts); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t IterateBezierTo(int32 bezierCount, BPoint* bezierPts); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t IterateClose(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t Iterate(BShape* shape); +
Screen Support Functions
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const color_map* system_colors(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t set_screen_space(int32 index, uint32 res, bool stick = true); +
+ +

+
+

+ + + + + + + + + + +
Legend
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Functional SpecFunctional Spec
Use CasesUse Cases
Unit TestsUnit Tests
Technical SpecTechnical Spec
ImplementationImplementation
CompletedCompleted
+
+
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + diff --git a/docs/develop/ikteam/schedule/interfacekit/Group3Support.html b/docs/develop/ikteam/schedule/interfacekit/Group3Support.html new file mode 100644 index 0000000000..37090d0996 --- /dev/null +++ b/docs/develop/ikteam/schedule/interfacekit/Group3Support.html @@ -0,0 +1,2421 @@ + + + Group 3 Support Tasks + + +

Group 3 Support Tasks

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task SummaryOwner
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BBitmap + + Xavier Castellan +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BFont + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ Font Support + + +
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task Details
BBitmap Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BBitmap(BRect bounds, uint32 flags, color_space depth, int32 bytesPerRow=B_ANY_BYTES_PER_ROW, screen_id screenID=B_MAIN_SCREEN_ID); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BBitmap(BRect bounds, color_space depth, bool accepts_views = false, bool need_contiguous = false); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BBitmap(const BBitmap* source, bool accepts_views = false, bool need_contiguous = false); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BBitmap(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BBitmap(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t InitCheck() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsValid() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t LockBits(uint32* state=NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void UnlockBits(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ area_id Area() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void* Bits() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 BitsLength() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 BytesPerRow() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ color_space ColorSpace() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect Bounds() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetBits(const void* data, int32 length, int32 offset, color_space cs); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t GetOverlayRestrictions(overlay_restrictions* restrict) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AddChild(BView* view); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool RemoveChild(BView* view); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 CountChildren() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BView* ChildAt(int32 index) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BView* FindView(const char* view_name) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BView* FindView(BPoint point) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool Lock(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Unlock(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsLocked() const; +
BFont Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BFont(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BFont(const BFont &font); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BFont(const BFont* font); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetFamilyAndStyle(const font_family family, +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetFamilyAndStyle(uint32 code); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetFamilyAndFace(const font_family family, uint16 face); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetSize(float size); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetShear(float shear); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetRotation(float rotation); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetSpacing(uint8 spacing); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetEncoding(uint8 encoding); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetFace(uint16 face); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetFlags(uint32 flags); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetFamilyAndStyle(font_family* family, font_style* style) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ uint32 FamilyAndStyle() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ float Size() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ float Shear() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ float Rotation() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ uint8 Spacing() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ uint8 Encoding() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ uint16 Face() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ uint32 Flags() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ font_direction Direction() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsFixed() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsFullAndHalfFixed() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect BoundingBox() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ unicode_block Blocks() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ font_file_format FileFormat() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 CountTuned() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetTunedInfo(int32 index, tuned_font_info* info) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void TruncateString(BString* in_out, uint32 mode, float width) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetTruncatedStrings(const char* stringArray[], int32 numStrings, uint32 mode, float width, BString resultArray[]) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetTruncatedStrings(const char* stringArray[], int32 numStrings, uint32 mode, float width, char* resultArray[]) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ float StringWidth(const char* string) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ float StringWidth(const char* string, int32 length) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetStringWidths(const char* stringArray[], const int32 lengthArray[], int32 numStrings, float widthArray[]) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetEscapements(const char charArray[], int32 numChars, float escapementArray[]) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetEscapements(const char charArray[], int32 numChars, escapement_delta* delta, float escapementArray[]) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetEscapements(const char charArray[], int32 numChars, escapement_delta* delta, BPoint escapementArray[]) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetEscapements(const char charArray[], int32 numChars, escapement_delta* delta, BPoint escapementArray[], BPoint offsetArray[]) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetEdges(const char charArray[], int32 numBytes, edge_info edgeArray[]) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetHeight(font_height* height) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetBoundingBoxesAsGlyphs(const char charArray[], int32 numChars, font_metric_mode mode, BRect boundingBoxArray[]) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetBoundingBoxesAsString(const char charArray[], int32 numChars, font_metric_mode mode, escapement_delta* delta, BRect boundingBoxArray[]) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetBoundingBoxesForStrings(const char* stringArray[], int32 numStrings, font_metric_mode mode, escapement_delta deltas[], BRect boundingBoxArray[]) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetGlyphShapes(const char charArray[], int32 numChars, BShape* glyphShapeArray[]) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetHasGlyphs(const char charArray[], int32 numChars, bool hasArray[]) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BFont& operator=(const BFont &font); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool operator==(const BFont &font) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool operator!=(const BFont &font) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void PrintToStream() const; +
Font Support Functions
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 count_font_families(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t get_font_family(int32 index, font_family* name, uint32* flags = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 count_font_styles(font_family name); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t get_font_style(font_family family, int32 index, font_style* name, uint32* flags = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t get_font_style(font_family family, int32 index, font_style* name, uint16* face, uint32* flags = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool update_font_families(bool check_only); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t get_font_cache_info(uint32 id, void* set); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t set_font_cache_info(uint32 id, void* set); +
+ +

+
+

+ + + + + + + + + + +
Legend
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Functional SpecFunctional Spec
Use CasesUse Cases
Unit TestsUnit Tests
Technical SpecTechnical Spec
ImplementationImplementation
CompletedCompleted
+
+
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + diff --git a/docs/develop/ikteam/schedule/interfacekit/InterfaceKitMilestones.html b/docs/develop/ikteam/schedule/interfacekit/InterfaceKitMilestones.html new file mode 100644 index 0000000000..3212236db4 --- /dev/null +++ b/docs/develop/ikteam/schedule/interfacekit/InterfaceKitMilestones.html @@ -0,0 +1,195 @@ + + + Interface Kit Milestones + + + +

Interface Kit Milestones

+ +
    +
  1. + Interface specs completed for all classes, functions, structs + + + + + + + + + + + + + +
    3%
    +

    + + +
  2. +
  3. + Use cases completed for all classes, functions, structs + + +
  4. +
  5. + Unit tests completed for all classes, functions, structs + + + + + + + + + + + + + +
    2%
    +

    + + +
  6. +
  7. + Design discussions completed for all classes, functions, structs + + +
  8. +
  9. + Group 1 Support complete + + + + + + + + + + + + + +
    25%
    +

    + +
  10. + Group 2 Support complete + +
  11. + Group 3 Support complete + +
  12. + Control Widgets complete + + + + + + + + + + + + + +
    8%
    +

    + +
  13. + Non-Control Widgets complete + + + + + + + + + + + + + +
    13%
    +

    + +
  14. + Scrolling Support complete + +
  15. + Menuing Support complete + +
  16. + ListView Support complete + +
  17. + TextView Support complete + +
  18. + Miscellaneous complete + + + + + + + + + + + + + +
    4%
    +

    + +
  19. + Replicant Support complete + +
  20. + Advanced Control Widgets complete + +
  21. + +
  22. + Alpha +
  23. +
  24. + Beta 1 +
  25. +
  26. + Beta 2 +
  27. +
  28. + Release Candidate 1 +
  29. +
  30. + 1.0! +
  31. +
+ +
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + + diff --git a/docs/develop/ikteam/schedule/interfacekit/ListViewSupport.html b/docs/develop/ikteam/schedule/interfacekit/ListViewSupport.html new file mode 100644 index 0000000000..464a6e7a8e --- /dev/null +++ b/docs/develop/ikteam/schedule/interfacekit/ListViewSupport.html @@ -0,0 +1,4154 @@ + + + ListView Support Tasks + + +

ListView Support Tasks

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task SummaryOwner
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BListItem + + Ulrich Wimboeck +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BStringItem + + Greg Gelfond +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BListView + + Ulrich Wimboeck +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BOutlineListView + + Ulrich Wimboeck +
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task Details
BListItem Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BListItem(uint32 outlineLevel = 0, bool expanded = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BListItem(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BListItem(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ float Height() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ float Width() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsSelected() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Select(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Deselect(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetEnabled(bool on); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsEnabled() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetHeight(float height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetWidth(float width); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DrawItem(BView* owner, BRect bounds, bool complete = false) = 0; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Update(BView* owner, const BFont* font); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Perform(perform_code d, void* arg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsExpanded() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetExpanded(bool expanded); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ uint32 OutlineLevel() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsItemVisible() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetItemVisible(bool); +
BStringItem Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BStringItem(const char* text, uint32 outlineLevel = 0, bool expanded = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BStringItem(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BStringItem(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DrawItem(BView* owner, BRect frame, bool complete = false); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetText(const char* text); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const char* Text() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Update(BView* owner, const BFont* font); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Perform(perform_code d, void* arg); +
BListView Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BListView(BRect frame, const char *name, list_view_type type = B_SINGLE_SELECTION_LIST, uint32 resizeMask = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BListView(BMessage *data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BListView(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable *Instantiate(BMessage *data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage *data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Draw(BRect updateRect); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage *msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseDown(BPoint where); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void KeyDown(const char *bytes, int32 numBytes); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MakeFocus(bool state = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameResized(float newWidth, float newHeight); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void TargetedByScrollView(BScrollView *scroller); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void ScrollTo(float x, float y); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ScrollTo(BPoint where); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool AddItem(BListItem *item); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool AddItem(BListItem *item, int32 atIndex); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool AddList(BList *newItems); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool AddList(BList *newItems, int32 atIndex); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool RemoveItem(BListItem *item); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BListItem *RemoveItem(int32 index); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool RemoveItems(int32 index, int32 count); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetSelectionMessage(BMessage *message); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetInvocationMessage(BMessage *message); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessage *SelectionMessage() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ uint32 SelectionCommand() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessage *InvocationMessage() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ uint32 InvocationCommand() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetListType(list_view_type type); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ list_view_type ListType() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BListItem *ItemAt(int32 index) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 IndexOf(BPoint point) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 IndexOf(BListItem *item) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BListItem *FirstItem() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BListItem *LastItem() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool HasItem(BListItem *item) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 CountItems() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MakeEmpty(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsEmpty() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void DoForEach(bool (*func)(BListItem *)); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void DoForEach(bool (*func)(BListItem *, void *), void *); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const BListItem **Items() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void InvalidateItem(int32 index); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void ScrollToSelection(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Select(int32 index, bool extend = false); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Select(int32 from, int32 to, bool extend = false); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsItemSelected(int32 index) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 CurrentSelection(int32 index = 0) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Invoke(BMessage *msg = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void DeselectAll(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void DeselectExcept(int32 except_from, int32 except_to); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Deselect(int32 index); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SelectionChanged(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SortItems(int (*cmp)(const void *, const void *)); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool SwapItems(int32 a, int32 b); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool MoveItem(int32 from, int32 to); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool ReplaceItem(int32 index, BListItem * item); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AttachedToWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameMoved(BPoint new_position); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect ItemFrame(int32 index); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BHandler *ResolveSpecifier(BMessage *msg, int32 index, BMessage *specifier, int32 form, const char *property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetSupportedSuites(BMessage *data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Perform(perform_code d, void *arg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void WindowActivated(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseUp(BPoint pt); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseMoved(BPoint pt, uint32 code, const BMessage *msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DetachedFromWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool InitiateDrag(BPoint pt, int32 itemIndex, bool initialySelected); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ResizeToPreferred(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void GetPreferredSize(float *width, float *height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllAttached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllDetached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool DoMiscellaneous(MiscCode code, MiscData * data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DrawItem(BListItem *item, BRect itemRect, bool complete = false); +
BOutlineListView Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BOutlineListView(BRect frame, const char* name, list_view_type type = B_SINGLE_SELECTION_LIST, uint32 resizeMask = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BOutlineListView(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BOutlineListView(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseDown(BPoint where); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void KeyDown(const char* bytes, int32 numBytes); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameMoved(BPoint new_position); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameResized(float new_width, float new_height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseUp(BPoint where); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool AddUnder(BListItem* item, BListItem* underItem); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool AddItem(BListItem* item); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool AddItem(BListItem* item, int32 fullListIndex); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool AddList(BList* newItems); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool AddList(BList* newItems, int32 fullListIndex); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool RemoveItem(BListItem* item); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BListItem* RemoveItem(int32 fullListIndex); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool RemoveItems(int32 fullListIndex, int32 count); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BListItem* FullListItemAt(int32 fullListIndex) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 FullListIndexOf(BPoint point) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 FullListIndexOf(BListItem* item) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BListItem* FullListFirstItem() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BListItem* FullListLastItem() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool FullListHasItem(BListItem* item) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 FullListCountItems() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 FullListCurrentSelection(int32 index = 0) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MakeEmpty(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool FullListIsEmpty() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void FullListDoForEach(bool (*func)(BListItem* )); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void FullListDoForEach(bool (*func)(BListItem* , void* ), void*); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BListItem* Superitem(const BListItem* item); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Expand(BListItem* item); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Collapse(BListItem* item); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsExpanded(int32 fullListIndex); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetSupportedSuites(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Perform(perform_code d, void* arg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ResizeToPreferred(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void GetPreferredSize(float* width, float* height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MakeFocus(bool state = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllAttached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllDetached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DetachedFromWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void FullListSortItems(int (*compareFunc)(const BListItem* , const BListItem* )); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SortItemsUnder(BListItem* underItem, bool oneLevelOnly, int (*compareFunc)(const BListItem* , const BListItem*)); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 CountItemsUnder(BListItem* under, bool oneLevelOnly) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BListItem* EachItemUnder(BListItem* underItem, bool oneLevelOnly, BListItem* (*eachFunc)(BListItem* , void* ), void* ); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BListItem* ItemUnderAt(BListItem* underItem, bool oneLevelOnly, int32 index) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool DoMiscellaneous(MiscCode code, MiscData* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage* ); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ExpandOrCollapse(BListItem* underItem, bool expand); +
+ +

+
+

+ + + + + + + + + + +
Legend
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Functional SpecFunctional Spec
Use CasesUse Cases
Unit TestsUnit Tests
Technical SpecTechnical Spec
ImplementationImplementation
CompletedCompleted
+
+
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + diff --git a/docs/develop/ikteam/schedule/interfacekit/MenuingSupport.html b/docs/develop/ikteam/schedule/interfacekit/MenuingSupport.html new file mode 100644 index 0000000000..fe83ef1a58 --- /dev/null +++ b/docs/develop/ikteam/schedule/interfacekit/MenuingSupport.html @@ -0,0 +1,5278 @@ + + + Menuing Support Tasks + + +

Menuing Support Tasks

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task SummaryOwner
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenu + + Justin Gasper +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenuBar + + Justin Gasper +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenuItem + + Justin Gasper +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BSeparatorItem + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenuField + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPopUpMenu + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ Menu Config + + +
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task Details
BMenu Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenu(const char* title, menu_layout layout = B_ITEMS_IN_COLUMN); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenu(const char* title, float width, float height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenu(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BMenu(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AttachedToWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DetachedFromWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool AddItem(BMenuItem* item); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool AddItem(BMenuItem* item, int32 index); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool AddItem(BMenuItem* item, BRect frame); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool AddItem(BMenu* menu); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool AddItem(BMenu* menu, int32 index); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool AddItem(BMenu* menu, BRect frame); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool AddList(BList* list, int32 index); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool AddSeparatorItem(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool RemoveItem(BMenuItem* item); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenuItem* RemoveItem(int32 index); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool RemoveItems(int32 index, int32 count, bool del = false); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool RemoveItem(BMenu* menu); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenuItem* ItemAt(int32 index) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenu* SubmenuAt(int32 index) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 CountItems() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 IndexOf(BMenuItem* item) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 IndexOf(BMenu* menu) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenuItem* FindItem(uint32 command) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenuItem* FindItem(const char* name) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t SetTargetForItems(BHandler* target); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t SetTargetForItems(BMessenger messenger); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetEnabled(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetRadioMode(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetTriggersEnabled(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetMaxContentWidth(float max); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetLabelFromMarked(bool on); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsLabelFromMarked(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsEnabled() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsRadioMode() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool AreTriggersEnabled() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsRedrawAfterSticky() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ float MaxContentWidth() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenuItem* FindMarked(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenu* Supermenu() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenuItem* Superitem() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void KeyDown(const char* bytes, int32 numBytes); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Draw(BRect updateRect); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void GetPreferredSize(float* width, float* height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ResizeToPreferred(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameMoved(BPoint new_position); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameResized(float new_width, float new_height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void InvalidateLayout(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetSupportedSuites(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Perform(perform_code d, void* arg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MakeFocus(bool state = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllAttached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllDetached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenu(BRect frame, const char* viewName, uint32 resizeMask, uint32 flags, menu_layout layout, bool resizeToFit); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BPoint ScreenLocation(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetItemMargins(float left, float top, float right, float bottom); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetItemMargins(float* left, float* top, float* right,float* bottom) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ menu_layout Layout() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Show(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Show(bool selectFirstItem); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Hide(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenuItem* Track(bool start_opened = false, BRect* special_rect = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool AddDynamicItem(add_state s); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DrawBackground(BRect update); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetTrackingHook(menu_tracking_hook func, void* state); +
BMenuBar Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenuBar(BRect frame, const char* title, uint32 resizeMask = B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP, menu_layout layout = B_ITEMS_IN_ROW, bool resizeToFit = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenuBar(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BMenuBar(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetBorder(menu_bar_border border); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ menu_bar_border Border() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Draw(BRect updateRect); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AttachedToWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DetachedFromWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseDown(BPoint where); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void WindowActivated(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseUp(BPoint where); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameMoved(BPoint new_position); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameResized(float new_width, float new_height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Show(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Hide(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetSupportedSuites(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ResizeToPreferred(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void GetPreferredSize(float* width, float* height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MakeFocus(bool state = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllAttached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllDetached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Perform(perform_code d, void* arg); +
BMenuItem Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenuItem(const char* label, BMessage* message, char shortcut = 0, uint32 modifiers = 0); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenuItem(BMenu* menu, BMessage* message = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenuItem(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BMenuItem(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetLabel(const char* name); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetEnabled(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetMarked(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetTrigger(char ch); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetShortcut(char ch, uint32 modifiers); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const char* Label() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsEnabled() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsMarked() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ char Trigger() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ char Shortcut(uint32* modifiers = NULL) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenu* Submenu() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenu* Menu() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect Frame() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void GetContentSize(float* width, float* height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void TruncateLabel(float max, char* new_label); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DrawContent(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Draw(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Highlight(bool on); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsSelected() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPoint ContentLocation() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Invoke(BMessage* msg = NULL); +
BSeparatorItem Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BSeparatorItem(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BSeparatorItem(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BSeparatorItem(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetEnabled(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void GetContentSize(float* width, float* height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Draw(); +
BMenuField Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenuField(BRect frame, const char* name, const char* label, BMenu* menu, uint32 resize = B_FOLLOW_LEFT|B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW | B_NAVIGABLE); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenuField(BRect frame, const char* name, const char* label, BMenu* menu, bool fixed_size, uint32 resize = B_FOLLOW_LEFT|B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW | B_NAVIGABLE); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenuField(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BMenuField(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Draw(BRect update); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AttachedToWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllAttached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseDown(BPoint where); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void KeyDown(const char* bytes, int32 numBytes); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MakeFocus(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void WindowActivated(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseUp(BPoint pt); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DetachedFromWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllDetached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameMoved(BPoint new_position); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameResized(float new_width, float new_height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenu* Menu() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenuBar* MenuBar() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenuItem* MenuItem() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetLabel(const char* label); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const char* Label() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetEnabled(bool on); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsEnabled() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetAlignment(alignment label); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ alignment Alignment() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetDivider(float dividing_line); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ float Divider() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void ShowPopUpMarker(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void HidePopUpMarker(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetSupportedSuites(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ResizeToPreferred(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void GetPreferredSize(float* width, float* height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Perform(perform_code d, void* arg); +
BPopUpMenu Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPopUpMenu(const char* title, bool radioMode = true, bool autoRename = true, menu_layout layout = B_ITEMS_IN_COLUMN); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPopUpMenu(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BPopUpMenu(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenuItem* Go(BPoint where, bool delivers_message = false, bool open_anyway = false, bool async = false); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMenuItem* Go(BPoint where, bool delivers_message, bool open_anyway, BRect click_to_open, bool async = false); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseDown(BPoint pt); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseUp(BPoint pt); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AttachedToWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DetachedFromWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameMoved(BPoint new_position); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameResized(float new_width, float new_height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetSupportedSuites(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Perform(perform_code d, void* arg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ResizeToPreferred(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void GetPreferredSize(float* width, float* height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MakeFocus(bool state = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllAttached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllDetached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetAsyncAutoDestruct(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool AsyncAutoDestruct() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BPoint ScreenLocation(); +
Menu Config Functions
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t set_menu_info(menu_info* info); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t get_menu_info(menu_info* info); +
+ +

+
+

+ + + + + + + + + + +
Legend
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Functional SpecFunctional Spec
Use CasesUse Cases
Unit TestsUnit Tests
Technical SpecTechnical Spec
ImplementationImplementation
CompletedCompleted
+
+
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + diff --git a/docs/develop/ikteam/schedule/interfacekit/Miscellaneous.html b/docs/develop/ikteam/schedule/interfacekit/Miscellaneous.html new file mode 100644 index 0000000000..d5c9e07e14 --- /dev/null +++ b/docs/develop/ikteam/schedule/interfacekit/Miscellaneous.html @@ -0,0 +1,2519 @@ + + + Miscellaneous Tasks + + +

Miscellaneous Tasks

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task SummaryOwner
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BAlert + + Erik Jaesler +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BDeskbar + + Jeremy Rand +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ unicode_block + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ Deskbar Support + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ Mouse Config + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ Workspace Support + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ Keyboard Config + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ UI Color Info + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ Miscellaneous + + +
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task Details
BAlert Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BAlert(const char *title, const char *text, const char *button1, const char *button2 = NULL, const char *button3 = NULL, button_width width = B_WIDTH_AS_USUAL, alert_type type = B_INFO_ALERT); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BAlert(const char *title, const char *text, const char *button1, const char *button2, const char *button3, button_width width, button_spacing spacing, alert_type type = B_INFO_ALERT); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BAlert(BMessage *data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ ~BAlert(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable *Instantiate(BMessage *data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage *data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetShortcut(int32 button_index, char key); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ char Shortcut(int32 button_index) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 Go(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t Go(BInvoker *invoker); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage *an_event); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameResized(float new_width, float new_height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BButton* ButtonAt(int32 index) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BTextView* TextView() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BHandler* ResolveSpecifier(BMessage *msg, int32 index, BMessage* specifier, int32 form, const char* property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetSupportedSuites(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DispatchMessage(BMessage* msg, BHandler* handler); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Quit(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool QuitRequested(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BPoint AlertPosition(float width, float height); +
BDeskbar Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BDeskbar(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ ~BDeskbar(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect Frame() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ deskbar_location Location(bool* isExpanded=NULL) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetLocation(deskbar_location location, bool expanded=false); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsExpanded() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t Expand(bool yn); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t GetItemInfo(int32 id, const char** name) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t GetItemInfo(const char* name, int32* id) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool HasItem(int32 id) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool HasItem(const char* name) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ uint32 CountItems() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t AddItem(BView* archivableView, int32* id=NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t AddItem(entry_ref* addon, int32* id=NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t RemoveItem(int32 id); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t RemoveItem(const char* name); +
unicode_block Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ unicode_block(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ unicode_block(uint64 block2, uint64 block1); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool Includes(const unicode_block &block) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ unicode_block operator&(const unicode_block &block) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ unicode_block operator|(const unicode_block &block) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ unicode_block& operator=(const unicode_block &block); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool operator==(const unicode_block &block) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool operator!=(const unicode_block &block) const; +
Deskbar Support Functions
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t get_deskbar_frame(BRect* frame); +
Mouse Config Functions
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t get_mouse_type(int32* type); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t set_mouse_type(int32 type); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t get_mouse_map(mouse_map* map); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t set_mouse_map(mouse_map* map); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t get_click_speed(bigtime_t* speed); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t set_click_speed(bigtime_t speed); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t get_mouse_speed(int32* speed); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t set_mouse_speed(int32 speed); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t get_mouse_acceleration(int32* speed); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t set_mouse_acceleration(int32 speed); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void set_focus_follows_mouse(bool follow); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool focus_follows_mouse(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void set_mouse_mode(mode_mouse mode); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ mode_mouse mouse_mode(); +
Workspace Support Functions
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 count_workspaces(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void set_workspace_count(int32 count); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 current_workspace(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void activate_workspace(int32 workspace); +
Keyboard Config Functions
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t get_key_repeat_rate(int32* rate); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t set_key_repeat_rate(int32 rate); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t get_key_repeat_delay(bigtime_t* delay); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t set_key_repeat_delay(bigtime_t delay); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ uint32 modifiers(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t get_key_info(key_info* info); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void get_key_map(key_map** map, char** key_buffer); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t get_keyboard_id(uint16* id); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void set_modifier_key(uint32 modifier, uint32 key); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void set_keyboard_locks(uint32 modifiers); +
UI Color Info Functions
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ rgb_color keyboard_navigation_color(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ rgb_color ui_color(color_which which); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ rgb_color tint_color(rgb_color color, float tint); +
Miscellaneous Functions
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bigtime_t idle_time(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void run_select_printer_panel(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void run_add_printer_panel(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void run_be_about(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t _init_interface_kit_(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void _ReservedShelf1__6BShelfFv(BShelf* const, int32, const BMessage*, const BView*); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ uint32 _rule_(uint32 r1, uint32 r2, uint32 r3, uint32 r4); +
+ +

+
+

+ + + + + + + + + + +
Legend
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Functional SpecFunctional Spec
Use CasesUse Cases
Unit TestsUnit Tests
Technical SpecTechnical Spec
ImplementationImplementation
CompletedCompleted
+
+
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + diff --git a/docs/develop/ikteam/schedule/interfacekit/Non-ControlWidgets.html b/docs/develop/ikteam/schedule/interfacekit/Non-ControlWidgets.html new file mode 100644 index 0000000000..e9575867cf --- /dev/null +++ b/docs/develop/ikteam/schedule/interfacekit/Non-ControlWidgets.html @@ -0,0 +1,2496 @@ + + + Non-Control Widgets Tasks + + +

Non-Control Widgets Tasks

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task SummaryOwner
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BBox + + Marc Flerackers +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BStringView + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BStatusBar + + Marc Flerackers +
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task Details
BBox Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BBox(BRect bounds, const char* name = NULL, uint32 resizeFlags = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP, border_style border = B_FANCY_BORDER); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BBox(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BBox(void); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetBorder(border_style style); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ border_style Border() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetLabel(const char* label); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetLabel(BView* view_label); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const char* Label() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BView* LabelView() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Draw(BRect bounds); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AttachedToWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DetachedFromWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllAttached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllDetached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameResized(float new_width, float new_height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseDown(BPoint pt); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseUp(BPoint pt); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void WindowActivated(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameMoved(BPoint new_position); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ResizeToPreferred(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void GetPreferredSize(float* width, float* height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MakeFocus(bool state = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetSupportedSuites(BMessage* data); +
BStringView Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BStringView(BRect bounds, const char* name, const char* text, uint32 resizeFlags = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BStringView(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BStringView(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetText(const char* text); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const char* Text() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetAlignment(alignment flag); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ alignment Alignment() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AttachedToWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Draw(BRect bounds); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseDown(BPoint pt); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseUp(BPoint pt); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DetachedFromWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameMoved(BPoint new_position); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameResized(float new_width, float new_height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ResizeToPreferred(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void GetPreferredSize(float* width, float* height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MakeFocus(bool state = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllAttached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllDetached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetSupportedSuites(BMessage* data); +
BStatusBar Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BStatusBar(BRect frame, const char* name, const char* label = NULL, const char* trailing_label = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BStatusBar(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BStatusBar(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AttachedToWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Draw(BRect updateRect); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetBarColor(rgb_color color); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetBarHeight(float height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetText(const char* str); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetTrailingText(const char* str); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetMaxValue(float max); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Update(float delta, const char* main_text = NULL, const char* trailing_text = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Reset(const char* label = NULL, const char* trailing_label = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ float CurrentValue() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ float MaxValue() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ rgb_color BarColor() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ float BarHeight() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const char* Text() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const char* TrailingText() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const char* Label() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const char* TrailingLabel() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseDown(BPoint pt); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseUp(BPoint pt); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void WindowActivated(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DetachedFromWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameMoved(BPoint new_position); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameResized(float new_width, float new_height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ResizeToPreferred(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void GetPreferredSize(float* width, float* height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MakeFocus(bool state = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllAttached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllDetached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetSupportedSuites(BMessage* data); +
+ +

+
+

+ + + + + + + + + + +
Legend
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Functional SpecFunctional Spec
Use CasesUse Cases
Unit TestsUnit Tests
Technical SpecTechnical Spec
ImplementationImplementation
CompletedCompleted
+
+
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + diff --git a/docs/develop/ikteam/schedule/interfacekit/ReplicantSupport.html b/docs/develop/ikteam/schedule/interfacekit/ReplicantSupport.html new file mode 100644 index 0000000000..5b22b10cd2 --- /dev/null +++ b/docs/develop/ikteam/schedule/interfacekit/ReplicantSupport.html @@ -0,0 +1,1938 @@ + + + Replicant Support Tasks + + +

Replicant Support Tasks

+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task SummaryOwner
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BDragger + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BShelf + + +
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task Details
BDragger Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BDragger(BRect bounds, BView* target, uint32 rmask = B_FOLLOW_NONE, uint32 flags = B_WILL_DRAW); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BDragger(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BDragger(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AttachedToWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DetachedFromWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Draw(BRect update); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseDown(BPoint where); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseUp(BPoint pt); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameMoved(BPoint new_position); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameResized(float new_width, float new_height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static status_t ShowAllDraggers(); /* system wide!*/ +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static status_t HideAllDraggers(); /* system wide!*/ +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static bool AreDraggersDrawn(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetSupportedSuites(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Perform(perform_code d, void* arg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ResizeToPreferred(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void GetPreferredSize(float* width, float* height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MakeFocus(bool state = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllAttached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllDetached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetPopUp(BPopUpMenu* context_menu); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPopUpMenu* PopUp() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool InShelf() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BView* Target() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BBitmap* DragBitmap(BPoint* offset, drawing_mode* mode); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsVisibilityChanging() const; +
BShelf Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BShelf(BView* view, bool allow_drags = true, const char* shelf_type = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BShelf(const entry_ref* ref, BView* view, bool allow_drags = true, const char* shelf_type = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BShelf(BDataIO* stream, BView* view, bool allow_drags = true, const char* shelf_type = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BShelf(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BShelf(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t Save(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetDirty(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsDirty() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetSupportedSuites(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Perform(perform_code d, void* arg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool AllowsDragging() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetAllowsDragging(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool AllowsZombies() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetAllowsZombies(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool DisplaysZombies() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetDisplaysZombies(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsTypeEnforced() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetTypeEnforced(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetSaveLocation(BDataIO* data_io); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t SetSaveLocation(const entry_ref* ref); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BDataIO* SaveLocation(entry_ref* ref) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t AddReplicant(BMessage* data, BPoint location); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t DeleteReplicant(BView* replicant); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t DeleteReplicant(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t DeleteReplicant(int32 index); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 CountReplicants() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessage* ReplicantAt(int32 index, BView** view = NULL, uint32* uid = NULL, status_t* perr = NULL) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 IndexOf(const BView* replicant_view) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 IndexOf(const BMessage* archive) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 IndexOf(uint32 id) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool CanAcceptReplicantMessage(BMessage*) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool CanAcceptReplicantView(BRect, BView*, BMessage*) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BPoint AdjustReplicantBy(BRect, BMessage*) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ReplicantDeleted(int32 index, const BMessage* archive, const BView* replicant); +
+ +

+
+

+ + + + + + + + + + +
Legend
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Functional SpecFunctional Spec
Use CasesUse Cases
Unit TestsUnit Tests
Technical SpecTechnical Spec
ImplementationImplementation
CompletedCompleted
+
+
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + diff --git a/docs/develop/ikteam/schedule/interfacekit/ScrollingSupport.html b/docs/develop/ikteam/schedule/interfacekit/ScrollingSupport.html new file mode 100644 index 0000000000..2c875367ff --- /dev/null +++ b/docs/develop/ikteam/schedule/interfacekit/ScrollingSupport.html @@ -0,0 +1,1871 @@ + + + Scrolling Support Tasks + + +

Scrolling Support Tasks

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task SummaryOwner
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BScrollBar + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BScrollView + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ Scrollbar Config + + +
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task Details
BScrollBar Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BScrollBar(BRect frame, const char* name, BView* target, float min, float max, orientation direction); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BScrollBar(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BScrollBar(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AttachedToWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetValue(float value); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ float Value() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetProportion(float); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ float Proportion() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ValueChanged(float newValue); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetRange(float min, float max); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetRange(float* min, float* max) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetSteps(float smallStep, float largeStep); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetSteps(float* smallStep, float* largeStep) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetTarget(BView* target); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetTarget(const char* targetName); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BView* Target() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ orientation Orientation() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseDown(BPoint pt); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseUp(BPoint pt); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DetachedFromWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Draw(BRect updateRect); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameMoved(BPoint new_position); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameResized(float new_width, float new_height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ResizeToPreferred(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void GetPreferredSize(float* width, float* height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MakeFocus(bool state = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllAttached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllDetached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetSupportedSuites(BMessage* data); +
BScrollView Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BScrollView(const char* name, BView* target, uint32 resizeMask = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = 0, bool horizontal = false, bool vertical = false, border_style border = B_FANCY_BORDER); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BScrollView(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BScrollView(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Draw(BRect updateRect); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AttachedToWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BScrollBar* ScrollBar(orientation flag) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetBorder(border_style border); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ border_style Border() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t SetBorderHighlighted(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsBorderHighlighted() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetTarget(BView* new_target); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BView* Target() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseDown(BPoint pt); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void WindowActivated(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseUp(BPoint pt); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DetachedFromWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllAttached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllDetached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameMoved(BPoint new_position); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameResized(float new_width, float new_height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ResizeToPreferred(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void GetPreferredSize(float* width, float* height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MakeFocus(bool state = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetSupportedSuites(BMessage* data); +
Scrollbar Config Functions
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t get_scroll_bar_info(scroll_bar_info* info); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t set_scroll_bar_info(scroll_bar_info* info); +
+ +

+
+

+ + + + + + + + + + +
Legend
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Functional SpecFunctional Spec
Use CasesUse Cases
Unit TestsUnit Tests
Technical SpecTechnical Spec
ImplementationImplementation
CompletedCompleted
+
+
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + diff --git a/docs/develop/ikteam/schedule/interfacekit/TextViewSupport.html b/docs/develop/ikteam/schedule/interfacekit/TextViewSupport.html new file mode 100644 index 0000000000..342cbae98f --- /dev/null +++ b/docs/develop/ikteam/schedule/interfacekit/TextViewSupport.html @@ -0,0 +1,3688 @@ + + + TextView Support Tasks + + +

TextView Support Tasks

+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task SummaryOwner
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BTextView + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BTextControl + + +
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task Details
BTextView Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BTextView(BRect frame, const char* name, BRect textRect, uint32 resizeMask, uint32 flags = B_WILL_DRAW | B_PULSE_NEEDED); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BTextView(BRect frame, const char* name, BRect textRect, const BFont* initialFont, const rgb_color* initialColor, uint32 resizeMask, uint32 flags); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BTextView(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BTextView(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AttachedToWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DetachedFromWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Draw(BRect inRect); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseDown(BPoint where); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseUp(BPoint where); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseMoved(BPoint where, uint32 code, const BMessage* message); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void WindowActivated(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void KeyDown(const char* bytes, int32 numBytes); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Pulse(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameResized(float width, float height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MakeFocus(bool focusState = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage* message); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BHandler* ResolveSpecifier(BMessage* message, int32 index, BMessage* specifier, int32 form, const char* property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetSupportedSuites(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Perform(perform_code d, void* arg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetText(const char* inText, const text_run_array* inRuns = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetText(const char* inText, int32 inLength, const text_run_array* inRuns = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetText(BFile* inFile, int32 startOffset, int32 inLength, const text_run_array* inRuns = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Insert(const char* inText, const text_run_array* inRuns = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Insert(const char* inText, int32 inLength, const text_run_array* inRuns = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Insert(int32 startOffset, const char* inText, int32 inLength, const text_run_array* inRuns = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Delete(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Delete(int32 startOffset, int32 endOffset); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const char* Text() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 TextLength() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetText(int32 offset, int32 length, char* buffer) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ uchar ByteAt(int32 offset) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 CountLines() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 CurrentLine() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GoToLine(int32 lineNum); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Cut(BClipboard* clipboard); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Copy(BClipboard* clipboard); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Paste(BClipboard* clipboard); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Clear(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool AcceptsPaste(BClipboard* clipboard); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool AcceptsDrop(const BMessage* inMessage); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Select(int32 startOffset, int32 endOffset); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SelectAll(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetSelection(int32* outStart, int32* outEnd) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetFontAndColor(const BFont* inFont, uint32 inMode = B_FONT_ALL, const rgb_color* inColor = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetFontAndColor(int32 startOffset, int32 endOffset, const BFont* inFont, uint32 inMode = B_FONT_ALL, const rgb_color* inColor = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetFontAndColor(int32 inOffset, BFont* outFont, rgb_color* outColor = NULL) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetFontAndColor(BFont* outFont, uint32* outMode, rgb_color* outColor = NULL, bool* outEqColor = NULL) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetRunArray(int32 startOffset, int32 endOffset, const text_run_array* inRuns); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ text_run_array* RunArray(int32 startOffset, int32 endOffset, int32* outSize = NULL) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 LineAt(int32 offset) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 LineAt(BPoint point) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPoint PointAt(int32 inOffset, float* outHeight = NULL) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 OffsetAt(BPoint point) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 OffsetAt(int32 line) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FindWord(int32 inOffset, int32* outFromOffset, int32* outToOffset); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual bool CanEndLine(int32 offset); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ float LineWidth(int32 lineNum = 0) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ float LineHeight(int32 lineNum = 0) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ float TextHeight(int32 startLine, int32 endLine) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetTextRegion(int32 startOffset, int32 endOffset, BRegion* outRegion) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ScrollToOffset(int32 inOffset); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void ScrollToSelection(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Highlight(int32 startOffset, int32 endOffset); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetTextRect(BRect rect); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BRect TextRect() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetStylable(bool stylable); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsStylable() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetTabWidth(float width); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ float TabWidth() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void MakeSelectable(bool selectable = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsSelectable() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void MakeEditable(bool editable = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsEditable() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetWordWrap(bool wrap); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool DoesWordWrap() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetMaxBytes(int32 max); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 MaxBytes() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void DisallowChar(uint32 aChar); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void AllowChar(uint32 aChar); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetAlignment(alignment flag); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ alignment Alignment() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetAutoindent(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool DoesAutoindent() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetColorSpace(color_space colors); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ color_space ColorSpace() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void MakeResizable(bool resize, BView* resizeView = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsResizable() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetDoesUndo(bool undo); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool DoesUndo() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void HideTyping(bool enabled); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsTypingHidden(void) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ResizeToPreferred(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void GetPreferredSize(float* width, float* height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllAttached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllDetached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static void* FlattenRunArray(const text_run_array* inArray, int32* outSize = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static text_run_array* UnflattenRunArray(const void *data, int32* outSize = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void InsertText(const char* inText, int32 inLength, int32 inOffset, const text_run_array* inRuns); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DeleteText(int32 fromOffset, int32 toOffset); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Undo(BClipboard* clipboard); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ undo_state UndoState(bool* isRedo) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void GetDragParameters(BMessage* drag, BBitmap** bitmap, BPoint* point, BHandler** handler); +
BTextControl Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BTextControl(BRect frame, const char* name, const char* label, const char* initial_text, BMessage* message, uint32 rmask = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW | B_NAVIGABLE); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BTextControl(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BTextControl(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ static BArchivable* Instantiate(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Archive(BMessage* data, bool deep = true) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetText(const char* text); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const char* Text() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetValue(int32 value); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t Invoke(BMessage* msg = NULL); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BTextView* TextView() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetModificationMessage(BMessage* message); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMessage* ModificationMessage() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetAlignment(alignment label, alignment text); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void GetAlignment(alignment* label, alignment* text) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetDivider(float dividing_line); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ float Divider() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void Draw(BRect updateRect); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseDown(BPoint where); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AttachedToWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MakeFocus(bool focusState = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetEnabled(bool state); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameMoved(BPoint new_position); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void FrameResized(float new_width, float new_height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void WindowActivated(bool active); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void GetPreferredSize(float* width, float* height); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void ResizeToPreferred(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MessageReceived(BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseUp(BPoint pt); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void DetachedFromWindow(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllAttached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void AllDetached(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t GetSupportedSuites(BMessage* data); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual void SetFlags(uint32 flags); +
+ +

+
+

+ + + + + + + + + + +
Legend
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Functional SpecFunctional Spec
Use CasesUse Cases
Unit TestsUnit Tests
Technical SpecTechnical Spec
ImplementationImplementation
CompletedCompleted
+
+
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + diff --git a/docs/develop/ikteam/schedule/supportkit/BStopWatch.html b/docs/develop/ikteam/schedule/supportkit/BStopWatch.html new file mode 100644 index 0000000000..3ddcd13134 --- /dev/null +++ b/docs/develop/ikteam/schedule/supportkit/BStopWatch.html @@ -0,0 +1,339 @@ + + + BStopWatch Tasks + + +

BStopWatch Tasks

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
TaskOwner
Class BStopWatch
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BStopWatch(const char *name, bool silent = false); + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BStopWatch(); + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Suspend(); + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Resume(); + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bigtime_t Lap(); + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bigtime_t ElapsedTime() const; + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Reset(); + + +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const char* Name() const; + + +
+ +

+
+

+ + + + + + + + + + +
Legend
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Functional SpecFunctional Spec
Use CasesUse Cases
Unit TestsUnit Tests
Technical SpecTechnical Spec
ImplementationImplementation
CompletedCompleted
+
+
+
+ + +
+Hosted by:
+ +SourceForge Logo + +

+ +Copyright © 2001-2002 OpenBeOS Project +

+ + + diff --git a/docs/develop/ikteam/schedule/supportkit/IO.html b/docs/develop/ikteam/schedule/supportkit/IO.html new file mode 100644 index 0000000000..4e71f8a097 --- /dev/null +++ b/docs/develop/ikteam/schedule/supportkit/IO.html @@ -0,0 +1,904 @@ + + + IO Tasks + + +

IO Tasks

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task SummaryOwner
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BDataIO + + Steve Vallee +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMallocIO + + Steve Vallee +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMemoryIO + + Steve Vallee +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPositionIO + + Steve Vallee +
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task Details
BDataIO Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BDataIO +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BDataIO(); +
BMallocIO Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMallocIO(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BMallocIO(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ssize_t ReadAt(off_t pos, void *buffer, size_t size); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ssize_t WriteAt(off_t pos, const void *buffer, size_t size); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual off_t Seek(off_t pos, uint32 seek_mode); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual off_t Position() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t SetSize(off_t size); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SetBlockSize(size_t blocksize); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const void* Buffer() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ size_t BufferLength() const; +
BMemoryIO Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMemoryIO(void *p, size_t len); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BMemoryIO(const void *p, size_t len); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BMemoryIO(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ssize_t ReadAt(off_t pos, void *buffer, size_t size); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ssize_t WriteAt(off_t pos, const void *buffer, size_t size); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual off_t Seek(off_t pos, uint32 seek_mode); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual off_t Position() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t SetSize(off_t size); +
BPositionIO Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BPositionIO(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BPositionIO(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ssize_t Read(void *buffer, size_t size); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ssize_t Write(const void *buffer, size_t size); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual status_t SetSize(off_t size); +
+ +

+
+

+ + + + + + + + + + +
Legend
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Functional SpecFunctional Spec
Use CasesUse Cases
Unit TestsUnit Tests
Technical SpecTechnical Spec
ImplementationImplementation
CompletedCompleted
+
+
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + diff --git a/docs/develop/ikteam/schedule/supportkit/SupportKitMilestones.html b/docs/develop/ikteam/schedule/supportkit/SupportKitMilestones.html new file mode 100644 index 0000000000..b49411d0d2 --- /dev/null +++ b/docs/develop/ikteam/schedule/supportkit/SupportKitMilestones.html @@ -0,0 +1,168 @@ + + + Support Kit Milestones + + + +

Support Kit Milestones

+ +
    +
  1. + Interface specs completed for all classes, functions, structs + + + + + + + + + + + + + +
    16%
    +

    + + +
  2. +
  3. + Use cases completed for all classes, functions, structs + + + + + + + + + + + + + +
    16%
    +

    + + +
  4. +
  5. + Unit tests completed for all classes, functions, structs + + + + + + + + + + + + + +
    16%
    +

    + + +
  6. +
  7. + Design discussions completed for all classes, functions, structs + + + + + + + + + + + + + +
    16%
    +

    + + +
  8. +
  9. + IO complete + +
  10. + Utilities complete + + + + + + + + + + + + + +
    3%
    +

    + +
  11. + Synchronization complete + + + + + + + + + + + + + +
    60%
    +

    + +
  12. + +
  13. + Alpha +
  14. +
  15. + Beta 1 +
  16. +
  17. + Beta 2 +
  18. +
  19. + Release Candidate 1 +
  20. +
  21. + 1.0! +
  22. +
+ +
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + + diff --git a/docs/develop/ikteam/schedule/supportkit/Synchronization.html b/docs/develop/ikteam/schedule/supportkit/Synchronization.html new file mode 100644 index 0000000000..9346ffa18d --- /dev/null +++ b/docs/develop/ikteam/schedule/supportkit/Synchronization.html @@ -0,0 +1,688 @@ + + + Synchronization Tasks + + +

Synchronization Tasks

+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task SummaryOwner
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BAutoLock + + Jeremy Rand +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BLocker + + Jeremy Rand +
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task Details
BAutoLock Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BAutolock(BLocker *lock); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BAutolock(BLocker &lock); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BAutolock(BLooper *looper); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ ~BAutolock(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsLocked(); +
BLocker Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BLocker(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BLocker(const char *name); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BLocker(bool benaphore_style); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BLocker(const char *name, bool benaphore_style); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BLocker(const char *name, bool benaphore_style, bool); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BLocker(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool Lock(void); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ status_t LockWithTimeout(bigtime_t timeout); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Unlock(void); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ thread_id LockingThread(void) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsLocked(void) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 CountLocks(void) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 CountLockRequests(void) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ sem_id Sem(void) const; +
+ +

+
+

+ + + + + + + + + + +
Legend
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Functional SpecFunctional Spec
Use CasesUse Cases
Unit TestsUnit Tests
Technical SpecTechnical Spec
ImplementationImplementation
CompletedCompleted
+
+
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + diff --git a/docs/develop/ikteam/schedule/supportkit/Utilities.html b/docs/develop/ikteam/schedule/supportkit/Utilities.html new file mode 100644 index 0000000000..66d50b6b44 --- /dev/null +++ b/docs/develop/ikteam/schedule/supportkit/Utilities.html @@ -0,0 +1,4920 @@ + + + Utilities Tasks + + +

Utilities Tasks

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task SummaryOwner
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ Misc + + Steve Vallee +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString Utility + + Steve Vallee +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BList + + Issac Yonemoto +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString + + Steve Vallee +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BBlockCache + + Graham Gilmore +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BStopWatch + + Steve Vallee +
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task Details
Misc Functions
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ convert_from_utf8 +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ convert_to_utf8 +
BString Utility Functions
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool operator<(const char *, const BString &); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool operator<=(const char *, const BString &); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool operator==(const char *, const BString &); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool operator>(const char *, const BString &); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool operator>=(const char *, const BString &); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool operator!=(const char *, const BString &); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int Compare(const BString &, const BString &); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int ICompare(const BString &, const BString &); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int Compare(const BString *, const BString *); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int ICompare(const BString *, const BString *); +
BList Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BList(int32 itemsPerBlock = 20); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BList(const BList&); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BList(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BList& operator=(const BList &from); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool AddItem(void *item); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool AddItem(void *item, int32 atIndex); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool AddList(BList *newItems); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool AddList(BList *newItems, int32 atIndex); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool RemoveItem(void *item); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void* RemoveItem(int32 index); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool RemoveItems(int32 index, int32 count); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool ReplaceItem(int32 index, void *newItem); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void MakeEmpty(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void SortItems(int (*cmp)(const void *, const void *)); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool SwapItems(int32 indexA, int32 indexB); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool MoveItem(int32 fromIndex, int32 toIndex); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void* ItemAt(int32) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void* ItemAtFast(int32) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void* FirstItem() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void* LastItem() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void* Items() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool HasItem(void *item) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 IndexOf(void *item) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 CountItems() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool IsEmpty() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void DoForEach(bool (*func)(void *)); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void DoForEach(bool (*func)(void *, void *), void *); +
BString Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString(const char *); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString(const BString &); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString(const char *, int32 maxLength); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ ~BString(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const char* String() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 Length() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 CountChars() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& operator=(const BString &); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& operator=(const char *); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& operator=(char); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& SetTo(const char *); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& SetTo(const char *, int32 length); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& SetTo(const BString &from); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& Adopt(BString &from); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& SetTo(const BString &, int32 length); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& Adopt(BString &from, int32 length); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& SetTo(char, int32 count); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& CopyInto(BString &into, int32 fromOffset, int32 length) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void CopyInto(char *into, int32 fromOffset, int32 length) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& operator+=(const BString &); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& operator+=(const char *); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& operator+=(char); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& Append(const BString &); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& Append(const char *); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& Append(const BString &, int32 length); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& Append(const char *, int32 length); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& Append(char, int32 count); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& Prepend(const char *); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& Prepend(const BString &); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& Prepend(const char *, int32); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& Prepend(const BString &, int32); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& Prepend(char, int32 count); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& Insert(const char *, int32 pos); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& Insert(const char *, int32 length, int32 pos); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& Insert(const char *, int32 fromOffset, int32 length, int32 pos); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& Insert(const BString &, int32 pos); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& Insert(const BString &, int32 length, int32 pos); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& Insert(const BString &, int32 fromOffset, int32 length, int32 pos); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& Insert(char, int32 count, int32 pos); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& Truncate(int32 newLength, bool lazy = true); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& Remove(int32 from, int32 length); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& RemoveFirst(const BString &); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& RemoveLast(const BString &); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& RemoveAll(const BString &); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& RemoveFirst(const char *); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& RemoveLast(const char *); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& RemoveAll(const char *); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& RemoveSet(const char *setOfCharsToRemove); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& MoveInto(BString &into, int32 from, int32 length); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void MoveInto(char *into, int32 from, int32 length); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool operator<(const BString &) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool operator<=(const BString &) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool operator==(const BString &) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool operator>=(const BString &) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool operator>(const BString &) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool operator!=(const BString &) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool operator<(const char *) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool operator<=(const char *) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool operator==(const char *) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool operator>=(const char *) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool operator>(const char *) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bool operator!=(const char *) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int Compare(const BString &) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int Compare(const char *) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int Compare(const BString &, int32 n) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int Compare(const char *, int32 n) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int ICompare(const BString &) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int ICompare(const char *) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int ICompare(const BString &, int32 n) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int ICompare(const char *, int32 n) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 FindFirst(const BString &) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 FindFirst(const char *) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 FindFirst(const BString &, int32 fromOffset) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 FindFirst(const char *, int32 fromOffset) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 FindFirst(char) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 FindFirst(char, int32 fromOffset) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 FindLast(const BString &) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 FindLast(const char *) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 FindLast(const BString &, int32 beforeOffset) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 FindLast(const char *, int32 beforeOffset) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 FindLast(char) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 FindLast(char, int32 fromOffset) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 IFindFirst(const BString &) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 IFindFirst(const char *) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 IFindFirst(const BString &, int32 fromOffset) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 IFindFirst(const char *, int32 fromOffset) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 IFindLast(const BString &) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 IFindLast(const char *) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 IFindLast(const BString &, int32 beforeOffset) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ int32 IFindLast(const char *, int32 beforeOffset) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& ReplaceFirst(char replaceThis, char withThis); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& ReplaceLast(char replaceThis, char withThis); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& ReplaceAll(char replaceThis, char withThis, int32 fromOffset = 0); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& Replace(char replaceThis, char withThis, int32 maxReplaceCount, int32 fromOffset = 0); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& ReplaceFirst(const char *replaceThis, const char *withThis); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& ReplaceLast(const char *replaceThis, const char *withThis); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& ReplaceAll(const char *replaceThis, const char *withThis, int32 fromOffset = 0); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& Replace(const char *replaceThis, const char *withThis, int32 maxReplaceCount, int32 fromOffset = 0); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& IReplaceFirst(char replaceThis, char withThis); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& IReplaceLast(char replaceThis, char withThis); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& IReplaceAll(char replaceThis, char withThis, int32 fromOffset = 0); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& IReplace(char replaceThis, char withThis, int32 maxReplaceCount, int32 fromOffset = 0); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& IReplaceFirst(const char *replaceThis, const char *withThis); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& IReplaceLast(const char *replaceThis, const char *withThis); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& IReplaceAll(const char *replaceThis, const char *withThis, int32 fromOffset = 0); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& IReplace(const char *replaceThis, const char *withThis, int32 maxReplaceCount, int32 fromOffset = 0); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& ReplaceSet(const char *setOfChars, char with); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& ReplaceSet(const char *setOfChars, const char *with); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ char operator[](int32 index) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ char& operator[](int32 index); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ char ByteAt(int32 index) const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ char* LockBuffer(int32 maxLength); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& UnlockBuffer(int32 length = -1); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& ToLower(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& ToUpper(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& Capitalize(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& CapitalizeEachWord(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& CharacterEscape(const char* original, const char* setOfCharsToEscape, char escapeWith); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& CharacterEscape(const char *setOfCharsToEscape, char escapeWith); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& CharacterDeescape(const char *original, char escapeChar); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& CharacterDeescape(char escapeChar); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& operator<<(const char *); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& operator<<(const BString &); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& operator<<(char); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& operator<<(int); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& operator<<(unsigned int); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& operator<<(uint32); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& operator<<(int32); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& operator<<(uint64); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& operator<<(int64); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BString& operator<<(float); +
BBlockCache Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BBlockCache(size_t cache_size, size_t block_size, uint32 type); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BBlockCache(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void* Get(size_t block_size); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Save(void *pointer, size_t block_size); +
BStopWatch Class
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ BStopWatch(const char *name, bool silent = false); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ virtual ~BStopWatch(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Suspend(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Resume(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bigtime_t Lap(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ bigtime_t ElapsedTime() const; +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ void Reset(); +
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ const char* Name() const; +
+ +

+
+

+ + + + + + + + + + +
Legend
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Functional SpecFunctional Spec
Use CasesUse Cases
Unit TestsUnit Tests
Technical SpecTechnical Spec
ImplementationImplementation
CompletedCompleted
+
+
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + diff --git a/docs/develop/ikteam/schedule/templates/assignments.html b/docs/develop/ikteam/schedule/templates/assignments.html new file mode 100644 index 0000000000..67cadc1865 --- /dev/null +++ b/docs/develop/ikteam/schedule/templates/assignments.html @@ -0,0 +1,83 @@ + + + Interface Kit Team Assignments + + +

+ Interface Kit Team Assignments and Open Tasks +
+

+ +

+ Assignments: +

+ + + +@for_each engineer in $Assignments.engineers + + + +@for_each etask in $engineer.tasks + + + + +@end + + + +@end + +
+ $engineer.name +
+ + $etask.str +
+ + +

+ Open Tasks: +

+ + + +@for_each section in $Assignments.sections + + + +@for_each stask in $section.tasks + + + + +@end + + + +@end + +
+ $section.name +
+ + $stask.str +
+
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + \ No newline at end of file diff --git a/docs/develop/ikteam/schedule/templates/group.html b/docs/develop/ikteam/schedule/templates/group.html new file mode 100644 index 0000000000..6dcb37ce37 --- /dev/null +++ b/docs/develop/ikteam/schedule/templates/group.html @@ -0,0 +1,167 @@ + + + + $GROUP.name Milestones + + + + +

$GROUP.name Milestones

+
+
    +
  1. + Interface specs completed for all classes, functions, structs + +@if $GROUP.ispec_complete + + + + + + + + + + + + + +
    $GROUP.ispec_complete%
    +

    + +@end +
    +
  2. +
  3. + Use cases completed for all classes, functions, structs + +@if $GROUP.cases_complete + + + + + + + + + + + + + +
    $GROUP.cases_complete%
    +

    + +@end +
    +
  4. +
  5. + Unit tests completed for all classes, functions, structs + +@if $GROUP.tests_complete + + + + + + + + + + + + + +
    $GROUP.tests_complete%
    +

    + +@end +
    +
  6. +
  7. + Design discussions completed for all classes, functions, structs + +@if $GROUP.tspec_complete + + + + + + + + + + + + + +
    $GROUP.tspec_complete%
    +

    + +@end +
    +
  8. + +@for_each milestone in $GROUP.milestones +
  9. + $milestone.name$milestone.note complete +@if $milestone.complete + + + + + + + + + + + + + +
    $milestone.complete%
    +

    + +@end +@end +
  10. +
    +
  11. + Alpha +
  12. +
  13. + Beta 1 +
  14. +
  15. + Beta 2 +
  16. +
  17. + Release Candidate 1 +
  18. +
  19. + 1.0! +
  20. +
+ +
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + + diff --git a/docs/develop/ikteam/schedule/templates/index.html b/docs/develop/ikteam/schedule/templates/index.html new file mode 100644 index 0000000000..99ddbb41f0 --- /dev/null +++ b/docs/develop/ikteam/schedule/templates/index.html @@ -0,0 +1,100 @@ + + + Interface Kit Team Schedule + + +

Interface Kit Team Schedule

+

+Here is the schedule for the Interface Kit Team. To help organize our work, +tasks have been broken into 4 general areas: +

    + +@for_each group in $GROUPS +
  • $group.name$group.note
  • +@end +
    +
+

+Organizationally, it's best to consider these as separate projects within the +scope of the IK Team's charter. As such, core contributors should pick a +project and stick with it -- it will make things a lot easier to keep track of, +and losing track of stuff would be a bad thing. =) +

+DarkWyrm is the technical lead for the app_server; he has done an enormous amount +of research and he is currently in the best position to lead the effort. +

+Erik Jakowatz will continue in his capacity as overall project lead, as well as +being directly involved in Integration as technical lead. +

+A word of warning: this schedule is downright huge because of the sheer number of +items to be completed. There is a paper available in which the rationale behind the +schedule is discussed. +

+
+

Current Status

+Here are some fuzzy indicators of what progress the team has made base on the number of +outstanding tasks completed. No warranty is made concerning the accuracy of these +graphs. =) +

+ + + + + + + + + +
Overall
+ + + + + + + + + + +
$GROUPS.complete%
+ + + +@for_each group in $GROUPS + + +

$group.name
+ + + + + + + + + + + + +
$group.complete%
+ +@end +
+ +
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + \ No newline at end of file diff --git a/docs/develop/ikteam/schedule/templates/milestone.html b/docs/develop/ikteam/schedule/templates/milestone.html new file mode 100644 index 0000000000..6e307f7a23 --- /dev/null +++ b/docs/develop/ikteam/schedule/templates/milestone.html @@ -0,0 +1,29 @@ + + + + $GROUP.name Tasks + + + + +

$GROUP.name Tasks

+@for_each milestone in $GROUP.milestones +$milestone.name
+@end +
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + \ No newline at end of file diff --git a/docs/develop/ikteam/schedule/templates/tasks.html b/docs/develop/ikteam/schedule/templates/tasks.html new file mode 100644 index 0000000000..dedc740ca0 --- /dev/null +++ b/docs/develop/ikteam/schedule/templates/tasks.html @@ -0,0 +1,254 @@ + + + + $MILESTONE.name Tasks + + +

$MILESTONE.name Tasks

+
+ + + + + + + + +@for_each s in $MILESTONE + + + + + + + +@end + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task SummaryOwner
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ $s.name + + $s.owner +
+ +
+
+
+
+
+ + + + + + + + + +@for_each s in $MILESTONE + + + + +@for_each t in $s.tasks + + + + + +@end +@end + +
+ + + + + + +
+ + Functional Spec + + + + Use Cases + + + + Unit Tests + + + + Technical Spec + + + + Implementation + +
+
Task Details
$s.name $s.type
+ + + + + + +
Functional SpecUse CasesUnit TestsTechnical SpecImplementation
+
+ $t.name +
+ +

+
+

+ + + + + + + + + + +
Legend
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Functional SpecFunctional Spec
Use CasesUse Cases
Unit TestsUnit Tests
Technical SpecTechnical Spec
ImplementationImplementation
CompletedCompleted
+
+
+
+ + +
+The OpenBeOS project is hosted by:

+ +SourceForge Logo + +

+ +Copyright © 2001-2002 +OpenBeOS Project +

+ + + diff --git a/docs/develop/input/BInputServerDevice b/docs/develop/input/BInputServerDevice new file mode 100644 index 0000000000..9ab5675d17 --- /dev/null +++ b/docs/develop/input/BInputServerDevice @@ -0,0 +1,16 @@ +BInputServerDevice::_ReservedInputServerDevice4(void) +BInputServerDevice::_ReservedInputServerDevice3(void) +BInputServerDevice::_ReservedInputServerDevice2(void) +BInputServerDevice::_ReservedInputServerDevice1(void) +BInputServerDevice::StopMonitoringDevice(char +BInputServerDevice::StartMonitoringDevice(char +BInputServerDevice::EnqueueMessage(BMessage +BInputServerDevice::UnregisterDevices(input_device_ref +BInputServerDevice::RegisterDevices(input_device_ref +BInputServerDevice::Control(char +BInputServerDevice::Stop(char +BInputServerDevice::Start(char +BInputServerDevice::SystemShuttingDown(void) +BInputServerDevice::InitCheck(void) +BInputServerDevice::~BInputServerDevice(void) +BInputServerDevice::BInputServerDevice(void) \ No newline at end of file diff --git a/docs/develop/input/BInputServerFilter b/docs/develop/input/BInputServerFilter new file mode 100644 index 0000000000..7056e82f8b --- /dev/null +++ b/docs/develop/input/BInputServerFilter @@ -0,0 +1,9 @@ +BInputServerFilter::_ReservedInputServerFilter4(void) +BInputServerFilter::_ReservedInputServerFilter3(void) +BInputServerFilter::_ReservedInputServerFilter2(void) +BInputServerFilter::_ReservedInputServerFilter1(void) +BInputServerFilter::GetScreenRegion(BRegion +BInputServerFilter::Filter(BMessage +BInputServerFilter::InitCheck(void) +BInputServerFilter::~BInputServerFilter(void) +BInputServerFilter::BInputServerFilter(void) \ No newline at end of file diff --git a/docs/develop/input/BInputServerMethod b/docs/develop/input/BInputServerMethod new file mode 100644 index 0000000000..f3606768b9 --- /dev/null +++ b/docs/develop/input/BInputServerMethod @@ -0,0 +1,11 @@ +BInputServerMethod::_ReservedInputServerMethod4(void) +BInputServerMethod::_ReservedInputServerMethod3(void) +BInputServerMethod::_ReservedInputServerMethod2(void) +BInputServerMethod::_ReservedInputServerMethod1(void) +BInputServerMethod::SetMenu(BMenu +BInputServerMethod::SetIcon(unsigned +BInputServerMethod::SetName(char +BInputServerMethod::EnqueueMessage(BMessage +BInputServerMethod::MethodActivated(bool) +BInputServerMethod::~BInputServerMethod(void) +BInputServerMethod::BInputServerMethod(char \ No newline at end of file diff --git a/docs/develop/input/Function Specs b/docs/develop/input/Function Specs new file mode 100644 index 0000000000..4cc4fae1b5 --- /dev/null +++ b/docs/develop/input/Function Specs @@ -0,0 +1,32 @@ +**************** BInputServerDevice Section *************** + + BInputServerDevice(); +virtual ~BInputServerDevice(); +virtual status_t InitCheck(); +virtual status_t SystemShuttingDown(); +virtual status_t Start(const char *device, void *cookie); +virtual status_t Stop(const char *device, void *cookie); +virtual status_t Control(const char *device, void *cookie, int32 code, BMessage *message); +status_t RegisterDevices(input_device_ref **devices); +status_t UnregisterDevices(input_device_ref **devices); +status_t EnqueueMessage(BMessage *message); +status_t StartMonitoringDevice(const char *device); +status_t StopMonitoringDevice(const char *device); + +**************** BInputServerFilter Section ***************** + + BInputServerFilter(); +virtual ~BInputServerFilter(); +virtual status_t InitCheck(); +virtual filter_result Filter(BMessage *message, BList *outList); +status_t GetScreenRegion(BRegion *region) const; + +***************** BInputServerMethod Section ***************** + + BInputServerMethod(const char *name, const uchar *icon); +virtual ~BInputServerMethod(); +virtual status_t MethodActivated(bool active); +status_t EnqueueMessage(BMessage *message); +status_t SetName(const char *name); +status_t SetIcon(const uchar *icon); +status_t SetMenu(const BMenu *menu, const BMessenger target); diff --git a/docs/develop/input/Headers b/docs/develop/input/Headers new file mode 100644 index 0000000000..db0057fe8a --- /dev/null +++ b/docs/develop/input/Headers @@ -0,0 +1,51 @@ +Function Specifications + + +Public BInputServerDevice class interface: + + BInputServerDevice(); +virtual ~BInputServerDevice(); + +virtual status_t InitCheck(); +virtual status_t SystemShuttingDown(); + +virtual status_t Start(const char *device, void *cookie); +virtual status_t Stop(const char *device, void *cookie); +virtual status_t Control(const char *device, void *cookie, uint32 code, BMessage *message); + +status_t RegisterDevices(input_device_ref **devices); +status_t UnregisterDevices(input_device_ref **devices); + +status_t EnqueueMessage(BMessage *message); + +status_t StartMonitoringDevice(const char *device); +status_t StopMonitoringDevice(const char *device); +} + + +Public BInputServerFilter class interface: + + BInputServerFilter(); +virtual ~BInputServerFilter(); + +virtual status_t InitCheck(); + +virtual filter_result Filter(BMessage *message, BList *outList); + +status_t GetScreenRegion(BRegion *region) const; + +} + +Public BInputServerMethod class interface: + + BInputServerMethod(const char *name, const uchar *icon); +virtual ~BInputServerMethod(); + +virtual status_t MethodActivated(bool active); + +status_t EnqueueMessage(BMessage *message); + +status_t SetName(const char *name); +status_t SetIcon(const uchar *icon); +status_t SetMenu(const BMenu *menu, const BMessenger target); +} diff --git a/docs/develop/input/InputServer_functions.txt b/docs/develop/input/InputServer_functions.txt new file mode 100644 index 0000000000..199a2c005d --- /dev/null +++ b/docs/develop/input/InputServer_functions.txt @@ -0,0 +1,66 @@ +class InputServer +{ + InputServer(void); + ~InputServer(void); + + ArgvReceived(long, char**); + + InitKeyboardMouseStates(void) + InitFilters(void) + InitMethods(void) + + QuitRequested(void) + ReadyToRun(void) + MessageReceived(BMessage*); + + HandleSetMethod(BMessage*); + HandleGetSetMouseType(BMessage*, BMessage*); + HandleGetSetMouseAcceleration(BMessage*, BMessage*); + HandleGetSetKeyRepeatDelay(BMessage*, BMessage*); + HandleGetKeyInfo(BMessage*, BMessage*); + HandleGetModifiers(BMessage*, BMessage*); + HandleSetModifierKey(BMessage*, BMessage*); + HandleSetKeyboardLocks(BMessage*, BMessage*); + HandleGetSetMouseSpeed(BMessage*, BMessage*); + HandleSetMousePosition(BMessage*, BMessage*); + HandleGetSetMouseMap(BMessage*, BMessage*); + HandleGetKeyboardID(BMessage*, BMessage*); + HandleGetSetClickSpeed(BMessage*, BMessage*); + HandleGetSetKeyRepeatRate(BMessage*, BMessage*); + HandleGetSetKeyMap(BMessage*, BMessage*); + HandleFocusUnfocusIMAwareView(BMessage*, BMessage*); + + EnqueueDeviceMessage(BMessage*); + EnqueueMethodMessage(BMessage*); + UnlockMethodQueue(void); + LockMethodQueue(void); + SetNextMethod(bool); + SetActiveMethod(_BMethodAddOn_*); + MethodReplicant(void); + + EventLoop(void*); + EventLoopRunning(void); + + DispatchEvents(BList*); + CacheEvents(BList*); + GetNextEvents(BList*); + FilterEvents(BList*); + SanitizeEvents(BList*); + MethodizeEvents(BList*, bool); + + StartStopDevices(char const*, input_device_type, bool); // device's name, type, 0 or 1 for start or stop) + ControlDevices(char const*, input_device_type, unsigned long, BMessage*); + + DoMouseAcceleration(long*, long*); + SetMousePos(long*, long*, long, long); + SetMousePos(long*, long*, BPoint); + SetMousePos(long*, long*, float, float); + + SafeMode(void) + +private: + sEventLoopRunning + sSafeMode + fMouseState + +} \ No newline at end of file diff --git a/docs/develop/input/input_server threads b/docs/develop/input/input_server threads new file mode 100644 index 0000000000..0f93d29338 --- /dev/null +++ b/docs/develop/input/input_server threads @@ -0,0 +1,12 @@ +Input_server threads + +input_server(10-Normal Priority) +_input_server_event_loop_(103-Custom Priority) +ScreenSaver Looper(10-Normal Priority) +DevicesLooper(10-Normal Priority) +w>Team Monitor(120-Real Time Priority) +PS/2 Mouse(104-Custom Priority) +AT Keyboard(104-Custom Priority) + +Legend: +w> This signifies that the thread is spawned from a parent process. (most likely from the input_server) \ No newline at end of file diff --git a/docs/develop/input/intro to input_server b/docs/develop/input/intro to input_server new file mode 100644 index 0000000000..c2fbce5a43 --- /dev/null +++ b/docs/develop/input/intro to input_server @@ -0,0 +1,149 @@ +
+
This is G o o g l e's cache of http://bedriven.be-in.org/articles/input_server/II_035-an%20introduction%20to%20the%20input%20server.html.
+G o o g l e's cache is the snapshot that we took of the page as we crawled the web.
+The page may have changed since that time. Click here for the current page without highlighting.


Google is not affiliated with the authors of this page nor responsible for its content.
+
These search terms have been highlighted: hiroshi lockheimer 
+These terms only appear in links pointing to this page: input_server +
+
+ +Be Newsletter, Volume II, Issue 35 + + +
Be Newsletter, Volume II, Issue 35; September 2, 1998

+ + +BE ENGINEERING INSIGHTS:

An Introduction to the Input Server +
By Hiroshi Lockheimer hiroshi@be.com +

One of the many upcoming changes in the BeOS is in the world +of input devices and events. The Input Server, slated to +debut in R4, is a server that deals with all things "input." +Specifically, it serves three functions: manages input +devices such as keyboards and mice; hosts a stream of events +that those devices generate; and dispatches those events +that make it through the stream. + + +

+Managing Input Devices + + +

The Input Server is a pretty dumb piece of software. (Cue to +Alex: roll your eyes and say, "What do you expect Hiroshi, +you wrote it.") On its own, the server doesn't know how a +keyboard or a mouse works; it relies on BInputServerDevice +add-ons to tell it. + + +

BInputServerDevice is a base class from which all input +device add-ons must derive. It provides the basic framework +of virtual hook functions and non-virtual member functions +that the Input Server uses to communicate with an add-on, +and that the add-on can use to talk back to the server. To +give a sneak peak of the API, some of the virtuals include +InitCheck(), Start(), Stop(), and Control(). The common +sequence of the life of an input device is this: + +

    + +
  1. The Input Server loads an add-on and constructs its + BInputServerDevice-derived object. + + +

  2. The Input Server calls InitCheck() on the object. The + object determines whether it is capable of doing its job + -- that is, generating input events. + + +

  3. This task may involve the object sniffing around for + hardware it can drive, or looking for a kernel device + driver in /dev. If the object is happy, it registers with + the Input Server any input device(s) it finds, and + returns B_NO_ERROR. An error return causes the Input + Server to promptly destruct the object and unload the + add-on. + + +

  4. At some point in time, someone will tell the input + devices registered with the Input Server to Start(). The + system automatically starts keyboards and mice at boot + time. Any other type of device (an "undefined" input + device that the system doesn't have any special knowledge + about) can be started by an application using new API in + the Interface Kit. + + +

  5. A registered device, whether it has been started or + not, may be Control()-ed at any time. Think of Control() + as the ioctl() equivalent in input device parlance. + Examples of system-defined control messages include + keymap changes and mouse speed changes. +
+ +

+Generating Input Events + + +

Once a BInputServerDevice-derived object's input device is +up and running, its primary task is to generate input +events. These events are expressed as BMessages. For +example, a keyboard input device will most likely generate +B_KEY_DOWN and B_KEY_UP messages. Similarly, a mouse input +device will probably generate B_MOUSE_UP, B_MOUSE_DOWN, and +B_MOUSE_MOVED events. + + +

There is nothing that prevents an input device from putting +arbitrary data in any of the BMessages it generates. So, for +example, a tablet may generate the aforementioned mouse +events with extra data such as pressure and proximity. Any +information packed into the BMessages is delivered +unmolested by the input server. + + +

When an event is ready to be shipped off, an input device +enqueues it into the Input Server's event stream. Some +BHandler (most likely a BView) down the line eventually +receives the event by way of the usual hook functions such +as KeyDown(), MouseDown(), and MouseMoved(). + + +

+The Input Event Stream + + +

The Input Server's event stream is open for inspection and +alteration by anyone in the system. This is achieved through +another set of add-ons called BInputServerFilter. Like +BInputServerDevice, BInputServerFilter is a base class for input filter add-ons to the Input Server. + + +

An input filter add-on is privy to all the events that pass +through the Input Server's event stream. A filter may +inspect, alter, generate, or completely drop input events. +It's similar in some ways to the Interface Kit's +BMessageFilter, but much more low-level. A +BInputServerFilter sees all events that exist in the system; +BMessageFilters are associated with a specific BLooper and +thus see only the events targeted to its BLooper. Also, +filters in the Input Server can generate additional events +in place of, or in addition to, the original input event +that it was invoked with. + + +

+Conclusion + + +

With the introduction of loadable input device objects, the +Input Server enables the BeOS to be used with a wide variety +of input devices (and more than one of them at once too). +And with the advent of input filters, the Input Server opens +the door to a new class of tricks, hacks, and (gulp) pranks +for the creative developer. It's going to be fun. + + +

+ + + diff --git a/docs/develop/input/is_manager.fil b/docs/develop/input/is_manager.fil new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/develop/input/is_server.fil b/docs/develop/input/is_server.fil new file mode 100644 index 0000000000..22c55b04cd --- /dev/null +++ b/docs/develop/input/is_server.fil @@ -0,0 +1,100 @@ +000124f0 T InputServer::InputServer(void) +0001277c T InputServer::MessageReceived(BMessage *) +00012e64 T InputServer::QuitRequested(void) +0001306c T InputServer::InitKeyboardMouseStates(void) +00013360 T InputServer::InitMethods(void) +00013460 T InputServer::GetNextEvents(BList *) +000135e8 T InputServer::DoMouseAcceleration(long *, long *) +00013794 T InputServer::SanitizeEvents(BList *) +00013ce0 T InputServer::MethodizeEvents(BList *, bool) +00013ecc T InputServer::FilterEvents(BList *) +000140dc T InputServer::CacheEvents(BList *) +000144d0 T InputServer::DispatchEvents(BList *) +00014800 T InputServer::HandleSetKeyboardLocks(BMessage *, BMessage *) +000148e0 T InputServer::HandleSetModifierKey(BMessage *, BMessage *) +00014ad0 T InputServer::HandleGetSetKeyMap(BMessage *, BMessage *) +00014c3c T InputServer::HandleGetSetKeyRepeatDelay(BMessage *, BMessage *) +00014d4c T InputServer::HandleGetSetKeyRepeatRate(BMessage *, BMessage *) +00014e5c T InputServer::HandleGetSetMouseMap(BMessage *, BMessage *) +00014f9c T InputServer::HandleGetSetMouseType(BMessage *, BMessage *) +000150ac T InputServer::HandleGetSetMouseSpeed(BMessage *, BMessage *) +000151bc T InputServer::HandleGetSetMouseAcceleration(BMessage *, BMessage *) +000152cc T InputServer::HandleGetSetClickSpeed(BMessage *, BMessage *) +000153dc T InputServer::HandleSetMousePosition(BMessage *, BMessage *) +00015534 T InputServer::HandleFocusUnfocusIMAwareView(BMessage *, BMessage *) +00015690 T InputServer::HandleSetMethod(BMessage *) +000157f8 T InputServer::EventLoop(void *) +00015b1c T InputServer::UnlockMethodQueue(void) +00015b5c T InputServer::LockMethodQueue(void) +00015ba4 T InputServer::HandleGetModifiers(BMessage *, BMessage *) +00015bec T InputServer::HandleGetKeyInfo(BMessage *, BMessage *) +00015c40 T InputServer::HandleGetKeyboardID(BMessage *, BMessage *) +00015c88 T InputServer::SetActiveMethod(_BMethodAddOn_ *) +00015d8c T InputServer::SetNextMethod(bool) +00015e04 T InputServer::SetMousePos(long *, long *, float, float) +00015ec4 T InputServer::SetMousePos(long *, long *, long, long) +00015f14 T InputServer::SetMousePos(long *, long *, BPoint) +00015fc8 T InputServer::InitFilters(void) +00016008 T InputServer::EventLoopRunning(void) +00016028 T InputServer::SafeMode(void) +00016048 T InputServer::ControlDevices(char const *, input_device_type, unsigned long, BMessage *) +0001612c T InputServer::StartStopDevices(char const *, input_device_type, bool) +000161fc T InputServer::MethodReplicant(void) const +0001620c T InputServer::EnqueueMethodMessage(BMessage *) +000162ec T InputServer::EnqueueDeviceMessage(BMessage *) +0001631c T InputServer::ReadyToRun(void) +00016344 T InputServer::ArgvReceived(long, char **) +0001647c T BInputServerDevice::_ReservedInputServerDevice4(void) +00016484 T BInputServerDevice::_ReservedInputServerDevice3(void) +0001648c T BInputServerDevice::_ReservedInputServerDevice2(void) +00016494 T BInputServerDevice::_ReservedInputServerDevice1(void) +0001649c T BInputServerDevice::StopMonitoringDevice(char const *) +000164cc T BInputServerDevice::StartMonitoringDevice(char const *) +000164fc T BInputServerDevice::EnqueueMessage(BMessage *) +00016528 T BInputServerDevice::UnregisterDevices(input_device_ref **) +00016550 T BInputServerDevice::RegisterDevices(input_device_ref **) +00016578 T BInputServerDevice::Control(char const *, void *, unsigned long, BMessage *) +00016584 T BInputServerDevice::Stop(char const *, void *) +00016590 T BInputServerDevice::Start(char const *, void *) +0001659c T BInputServerDevice::SystemShuttingDown(void) +000165a8 T BInputServerDevice::InitCheck(void) +000165b4 T BInputServerDevice::~BInputServerDevice(void) +000165e4 T BInputServerDevice::BInputServerDevice(void) +00016614 T BInputServerFilter::_ReservedInputServerFilter4(void) +0001661c T BInputServerFilter::_ReservedInputServerFilter3(void) +00016624 T BInputServerFilter::_ReservedInputServerFilter2(void) +0001662c T BInputServerFilter::_ReservedInputServerFilter1(void) +00016634 T BInputServerFilter::GetScreenRegion(BRegion *) const +00016698 T BInputServerFilter::Filter(BMessage *, BList *) +000166a4 T BInputServerFilter::InitCheck(void) +000166b0 T BInputServerFilter::~BInputServerFilter(void) +000166e0 T BInputServerFilter::BInputServerFilter(void) +00016710 T BInputServerMethod::_ReservedInputServerMethod4(void) +00016718 T BInputServerMethod::_ReservedInputServerMethod3(void) +00016720 T BInputServerMethod::_ReservedInputServerMethod2(void) +00016728 T BInputServerMethod::_ReservedInputServerMethod1(void) +00016730 T BInputServerMethod::SetMenu(BMenu const *, BMessenger) +000167ac T BInputServerMethod::SetIcon(unsigned char const *) +000167d4 T BInputServerMethod::SetName(char const *) +000167fc T BInputServerMethod::EnqueueMessage(BMessage *) +00016828 T BInputServerMethod::MethodActivated(bool) +00016834 T BInputServerMethod::~BInputServerMethod(void) +00016864 T BInputServerMethod::BInputServerMethod(char const *, unsigned char const *) +00018834 T MethodReplicant::SendToInputServer(BMessage *) +00019d98 W InputServer type_info function +00019ddc W InputServer::~InputServer(void) +00019e68 W BInputServerDevice type_info function +00019ea0 W BInputServerFilter type_info function +00019ed8 W BInputServerMethod type_info function +0001b000 R kInputServerSignature +0001cd34 D InputServer::sSafeMode +0001cd35 D InputServer::sEventLoopRunning +0001fb60 W InputServer virtual table +0001fce0 W BInputServerDevice virtual table +0001fd40 W BInputServerFilter virtual table +0001fd80 W BInputServerMethod virtual table +00024580 B InputServer::fMouseState +000245c0 B InputServer type_info node +000245ec B BInputServerMethod type_info node +00024620 B BInputServerFilter type_info node +00024728 B BInputServerDevice type_info node diff --git a/docs/develop/input/is_server2.fil b/docs/develop/input/is_server2.fil new file mode 100644 index 0000000000..896ff19cd1 --- /dev/null +++ b/docs/develop/input/is_server2.fil @@ -0,0 +1,100 @@ +InputServer::InputServer(void) +InputServer::MessageReceived(BMessage +InputServer::QuitRequested(void) +InputServer::InitKeyboardMouseStates(void) +InputServer::InitMethods(void) +InputServer::GetNextEvents(BList +InputServer::DoMouseAcceleration(long +InputServer::SanitizeEvents(BList +InputServer::MethodizeEvents(BList +InputServer::FilterEvents(BList +InputServer::CacheEvents(BList +InputServer::DispatchEvents(BList +InputServer::HandleSetKeyboardLocks(BMessage +InputServer::HandleSetModifierKey(BMessage +InputServer::HandleGetSetKeyMap(BMessage +InputServer::HandleGetSetKeyRepeatDelay(BMessage +InputServer::HandleGetSetKeyRepeatRate(BMessage +InputServer::HandleGetSetMouseMap(BMessage +InputServer::HandleGetSetMouseType(BMessage +InputServer::HandleGetSetMouseSpeed(BMessage +InputServer::HandleGetSetMouseAcceleration(BMessage +InputServer::HandleGetSetClickSpeed(BMessage +InputServer::HandleSetMousePosition(BMessage +InputServer::HandleFocusUnfocusIMAwareView(BMessage +InputServer::HandleSetMethod(BMessage +InputServer::EventLoop(void +InputServer::UnlockMethodQueue(void) +InputServer::LockMethodQueue(void) +InputServer::HandleGetModifiers(BMessage +InputServer::HandleGetKeyInfo(BMessage +InputServer::HandleGetKeyboardID(BMessage +InputServer::SetActiveMethod(_BMethodAddOn_ +InputServer::SetNextMethod(bool) +InputServer::SetMousePos(long +InputServer::SetMousePos(long +InputServer::SetMousePos(long +InputServer::InitFilters(void) +InputServer::EventLoopRunning(void) +InputServer::SafeMode(void) +InputServer::ControlDevices(char +InputServer::StartStopDevices(char +InputServer::MethodReplicant(void) +InputServer::EnqueueMethodMessage(BMessage +InputServer::EnqueueDeviceMessage(BMessage +InputServer::ReadyToRun(void) +InputServer::ArgvReceived(long, +BInputServerDevice::_ReservedInputServerDevice4(void) +BInputServerDevice::_ReservedInputServerDevice3(void) +BInputServerDevice::_ReservedInputServerDevice2(void) +BInputServerDevice::_ReservedInputServerDevice1(void) +BInputServerDevice::StopMonitoringDevice(char +BInputServerDevice::StartMonitoringDevice(char +BInputServerDevice::EnqueueMessage(BMessage +BInputServerDevice::UnregisterDevices(input_device_ref +BInputServerDevice::RegisterDevices(input_device_ref +BInputServerDevice::Control(char +BInputServerDevice::Stop(char +BInputServerDevice::Start(char +BInputServerDevice::SystemShuttingDown(void) +BInputServerDevice::InitCheck(void) +BInputServerDevice::~BInputServerDevice(void) +BInputServerDevice::BInputServerDevice(void) +BInputServerFilter::_ReservedInputServerFilter4(void) +BInputServerFilter::_ReservedInputServerFilter3(void) +BInputServerFilter::_ReservedInputServerFilter2(void) +BInputServerFilter::_ReservedInputServerFilter1(void) +BInputServerFilter::GetScreenRegion(BRegion +BInputServerFilter::Filter(BMessage +BInputServerFilter::InitCheck(void) +BInputServerFilter::~BInputServerFilter(void) +BInputServerFilter::BInputServerFilter(void) +BInputServerMethod::_ReservedInputServerMethod4(void) +BInputServerMethod::_ReservedInputServerMethod3(void) +BInputServerMethod::_ReservedInputServerMethod2(void) +BInputServerMethod::_ReservedInputServerMethod1(void) +BInputServerMethod::SetMenu(BMenu +BInputServerMethod::SetIcon(unsigned +BInputServerMethod::SetName(char +BInputServerMethod::EnqueueMessage(BMessage +BInputServerMethod::MethodActivated(bool) +BInputServerMethod::~BInputServerMethod(void) +BInputServerMethod::BInputServerMethod(char +MethodReplicant::SendToInputServer(BMessage +InputServer +InputServer::~InputServer(void) +BInputServerDevice +BInputServerFilter +BInputServerMethod +kInputServerSignature +InputServer::sSafeMode +InputServer::sEventLoopRunning +InputServer +BInputServerDevice +BInputServerFilter +BInputServerMethod +InputServer::fMouseState +InputServer +BInputServerMethod +BInputServerFilter +BInputServerDevice diff --git a/docs/develop/input/miscellaneous b/docs/develop/input/miscellaneous new file mode 100644 index 0000000000..1b5746fa09 --- /dev/null +++ b/docs/develop/input/miscellaneous @@ -0,0 +1,18 @@ +MethodReplicant::SendToInputServer(BMessage +InputServer +InputServer::~InputServer(void) +BInputServerDevice +BInputServerFilter +BInputServerMethod +kInputServerSignature +InputServer::sSafeMode +InputServer::sEventLoopRunning +InputServer +BInputServerDevice +BInputServerFilter +BInputServerMethod +InputServer::fMouseState +InputServer +BInputServerMethod +BInputServerFilter +BInputServerDevice diff --git a/docs/develop/input/objdump-inputserver b/docs/develop/input/objdump-inputserver new file mode 100644 index 0000000000..06ffc764ab --- /dev/null +++ b/docs/develop/input/objdump-inputserver @@ -0,0 +1,104 @@ +00000000 l df *ABS* 00000000 InputServer.cpp +00000000 l df *ABS* 00000000 InputServerDevice.cpp +00000000 l df *ABS* 00000000 InputServerFilter.cpp +00000000 l df *ABS* 00000000 InputServerMethod.cpp +000245c0 g O .bss 0000000c InputServer type_info node +000164cc g F .text 0000002f BInputServerDevice::StartMonitoringDevice(char const *) +000245ec g O .bss 0000000c BInputServerMethod type_info node +0001fce0 w O .data 00000058 BInputServerDevice virtual table +00016584 g F .text 00000009 BInputServerDevice::Stop(char const *, void *) +00016550 g F .text 00000026 BInputServerDevice::RegisterDevices(input_device_ref **) +00012e64 g F .text 00000207 InputServer::QuitRequested(void) +00024580 g O .bss 00000020 InputServer::fMouseState +00016720 g F .text 00000007 BInputServerMethod::_ReservedInputServerMethod2(void) +000151bc g F .text 0000010f InputServer::HandleGetSetMouseAcceleration(BMessage *, BMessage *) +0001620c g F .text 000000df InputServer::EnqueueMethodMessage(BMessage *) +00014f9c g F .text 0000010f InputServer::HandleGetSetMouseType(BMessage *, BMessage *) +00016008 g F .text 0000001d InputServer::EventLoopRunning(void) +00015b1c g F .text 0000003e InputServer::UnlockMethodQueue(void) +0001612c g F .text 000000cf InputServer::StartStopDevices(char const *, input_device_type, bool) +000157f8 g F .text 00000323 InputServer::EventLoop(void *) +00018834 g F .text 00000157 MethodReplicant::SendToInputServer(BMessage *) +0001b000 g O .rodata 00000022 kInputServerSignature +00015690 g F .text 00000165 InputServer::HandleSetMethod(BMessage *) +00016578 g F .text 00000009 BInputServerDevice::Control(char const *, void *, unsigned long, BMessage *) +00024620 g O .bss 00000008 BInputServerFilter type_info node +000166b0 g F .text 0000002f BInputServerFilter::~BInputServerFilter(void) +00014c3c g F .text 0000010f InputServer::HandleGetSetKeyRepeatDelay(BMessage *, BMessage *) +00013ce0 g F .text 000001ea InputServer::MethodizeEvents(BList *, bool) +0001cd35 g O .data 00000001 InputServer::sEventLoopRunning +00015bec g F .text 00000053 InputServer::HandleGetKeyInfo(BMessage *, BMessage *) +00015b5c g F .text 00000048 InputServer::LockMethodQueue(void) +00016834 g F .text 0000002d BInputServerMethod::~BInputServerMethod(void) +00016494 g F .text 00000007 BInputServerDevice::_ReservedInputServerDevice1(void) +0001631c g F .text 00000026 InputServer::ReadyToRun(void) +0001fd40 w O .data 00000040 BInputServerFilter virtual table +00015d8c g F .text 00000077 InputServer::SetNextMethod(bool) +0001306c g F .text 000002f2 InputServer::InitKeyboardMouseStates(void) +00013360 g F .text 000000ff InputServer::InitMethods(void) +00019ddc w F .text 00000045 InputServer::~InputServer(void) +0001662c g F .text 00000007 BInputServerFilter::_ReservedInputServerFilter1(void) +0001649c g F .text 0000002f BInputServerDevice::StopMonitoringDevice(char const *) +0001fb60 w O .data 00000180 InputServer virtual table +00015ba4 g F .text 00000045 InputServer::HandleGetModifiers(BMessage *, BMessage *) +000148e0 g F .text 000001ef InputServer::HandleSetModifierKey(BMessage *, BMessage *) +000165a8 g F .text 00000009 BInputServerDevice::InitCheck(void) +00013794 g F .text 00000549 InputServer::SanitizeEvents(BList *) +00016710 g F .text 00000007 BInputServerMethod::_ReservedInputServerMethod4(void) +000166e0 g F .text 00000023 BInputServerFilter::BInputServerFilter(void) +000167ac g F .text 00000027 BInputServerMethod::SetIcon(unsigned char const *) +00014800 g F .text 000000dd InputServer::HandleSetKeyboardLocks(BMessage *, BMessage *) +00019d98 w F .text 00000041 InputServer type_info function +000165b4 g F .text 0000002f BInputServerDevice::~BInputServerDevice(void) +00016528 g F .text 00000026 BInputServerDevice::UnregisterDevices(input_device_ref **) +000165e4 g F .text 0000002d BInputServerDevice::BInputServerDevice(void) +00014e5c g F .text 0000013f InputServer::HandleGetSetMouseMap(BMessage *, BMessage *) +000135e8 g F .text 000001ab InputServer::DoMouseAcceleration(long *, long *) +00015ec4 g F .text 0000004e InputServer::SetMousePos(long *, long *, long, long) +00015c88 g F .text 00000103 InputServer::SetActiveMethod(_BMethodAddOn_ *) +00019ed8 w F .text 00000041 BInputServerMethod type_info function +0001277c g F .text 000006e5 InputServer::MessageReceived(BMessage *) +000162ec g F .text 0000002e InputServer::EnqueueDeviceMessage(BMessage *) +000167d4 g F .text 00000027 BInputServerMethod::SetName(char const *) +00016624 g F .text 00000007 BInputServerFilter::_ReservedInputServerFilter2(void) +00016028 g F .text 0000001d InputServer::SafeMode(void) +00016590 g F .text 00000009 BInputServerDevice::Start(char const *, void *) +00016484 g F .text 00000007 BInputServerDevice::_ReservedInputServerDevice3(void) +00016614 g F .text 00000007 BInputServerFilter::_ReservedInputServerFilter4(void) +00016728 g F .text 00000007 BInputServerMethod::_ReservedInputServerMethod1(void) +0001648c g F .text 00000007 BInputServerDevice::_ReservedInputServerDevice2(void) +0001cd34 g O .data 00000001 InputServer::sSafeMode +00016698 g F .text 0000000c BInputServerFilter::Filter(BMessage *, BList *) +000144d0 g F .text 0000032e InputServer::DispatchEvents(BList *) +000140dc g F .text 000003f4 InputServer::CacheEvents(BList *) +000124f0 g F .text 0000028b InputServer::InputServer(void) +0001647c g F .text 00000007 BInputServerDevice::_ReservedInputServerDevice4(void) +00016828 g F .text 00000009 BInputServerMethod::MethodActivated(bool) +00016344 g F .text 00000079 InputServer::ArgvReceived(long, char **) +000150ac g F .text 0000010f InputServer::HandleGetSetMouseSpeed(BMessage *, BMessage *) +00013460 g F .text 00000186 InputServer::GetNextEvents(BList *) +000153dc g F .text 00000155 InputServer::HandleSetMousePosition(BMessage *, BMessage *) +0001661c g F .text 00000007 BInputServerFilter::_ReservedInputServerFilter3(void) +00019e68 w F .text 00000035 BInputServerDevice type_info function +00016864 g F .text 00000097 BInputServerMethod::BInputServerMethod(char const *, unsigned char const *) +000164fc g F .text 00000029 BInputServerDevice::EnqueueMessage(BMessage *) +00015fc8 g F .text 0000003f InputServer::InitFilters(void) +000166a4 g F .text 00000009 BInputServerFilter::InitCheck(void) +000167fc g F .text 00000029 BInputServerMethod::EnqueueMessage(BMessage *) +00013ecc g F .text 0000020d InputServer::FilterEvents(BList *) +000161fc g F .text 00000010 InputServer::MethodReplicant(void) const +00015c40 g F .text 00000046 InputServer::HandleGetKeyboardID(BMessage *, BMessage *) +000152cc g F .text 0000010f InputServer::HandleGetSetClickSpeed(BMessage *, BMessage *) +0001659c g F .text 00000009 BInputServerDevice::SystemShuttingDown(void) +0001fd80 w O .data 00000068 BInputServerMethod virtual table +00024728 g O .bss 00000008 BInputServerDevice type_info node +00016730 g F .text 0000007c BInputServerMethod::SetMenu(BMenu const *, BMessenger) +00016048 g F .text 000000e3 InputServer::ControlDevices(char const *, input_device_type, unsigned long, BMessage *) +00015534 g F .text 0000015b InputServer::HandleFocusUnfocusIMAwareView(BMessage *, BMessage *) +00019ea0 w F .text 00000035 BInputServerFilter type_info function +00016718 g F .text 00000007 BInputServerMethod::_ReservedInputServerMethod3(void) +00015f14 g F .text 000000b4 InputServer::SetMousePos(long *, long *, BPoint) +00014d4c g F .text 0000010f InputServer::HandleGetSetKeyRepeatRate(BMessage *, BMessage *) +00014ad0 g F .text 0000016c InputServer::HandleGetSetKeyMap(BMessage *, BMessage *) +00015e04 g F .text 000000bf InputServer::SetMousePos(long *, long *, float, float) +00016634 g F .text 00000061 BInputServerFilter::GetScreenRegion(BRegion *) const diff --git a/docs/develop/kernel/arch_vm_translation_map_x86 b/docs/develop/kernel/arch_vm_translation_map_x86 new file mode 100644 index 0000000000..c95b0c2a5f --- /dev/null +++ b/docs/develop/kernel/arch_vm_translation_map_x86 @@ -0,0 +1,72 @@ +static void init_pdentry(pdentry *e) + Sets e's value to 0. + +static void init_ptentry(ptentry *e) + Sets e's value to 0. + +static void _update_all_pgdirs(int index, pdentry e) + For every entry in the translation map, set the index'th entry to e. + +static int lock_tmap(vm_translation_map *map) + Locks the map; if we are the only ones, sets invalidated page count to 0. + +static int unlock_tmap(vm_translation_map *map) + unlocks the map; if no one else has it, call flush_tmap + +static void destroy_tmap(vm_translation_map *map) + Iterate over the entries in the tmap list, removing map when found. Frees the pages associated with this map. + +static void put_pgtable_in_pgdir(pdentry *e, addr pgtable_phys, int attributes) + Populates the pdentry with pgtable_phys and attributes + +static int map_tmap(vm_translation_map *map, addr va, addr pa, unsigned int attributes) + Allocates, if necessary, a page table entry. Gets the page for the page table entry (new or not), populates the page tabel entry with pa and attributes. Puts back the page table entry. Updates the pages to invalidate list. + +static int unmap_tmap(vm_translation_map *map, addr start, addr end) + Loops over the pagetable, finding the page that is present that holds this address. Gets it, and marks the page as not present. Replaces the page and updates the pages to invalidate list. + +static int query_tmap(vm_translation_map *map, addr va, addr *out_physical, unsigned int *out_flags) + Finds the page table's entry for this virtual address. Returns the physical address and flags. + +static addr get_mapped_size_tmap(vm_translation_map *map) + Returns map_count. + +static int protect_tmap(vm_translation_map *map, addr base, addr top, unsigned int attributes) + Unimplemented. + +static int clear_flags_tmap(vm_translation_map *map, addr va, unsigned int flags) + Finds the PTE and clears the requested flags. + +static void flush_tmap(vm_translation_map *map) + Invalidates the TLBs. If too many are in the list, all of the TLBs are invalidated. If not, a list is invalidated. + +static int map_iospace_chunk(addr va, addr pa) + Creates 1024 page table entries, for io. + +static int get_physical_page_tmap(addr pa, addr *va, int flags) + Looks to see if pa is already mapped. If so, return its virtual address in va. If not, find a place to map it and do so. + +static int put_physical_page_tmap(addr va) + Releases a reference to a "checked out" virtual mapping + +int vm_translation_map_create(vm_translation_map *new_map, bool kernel) + Sets up new_map, allocating memory and setting its initial state. + +int vm_translation_map_module_init(kernel_args *ka) + Clears the bottom 2 gig of memory's page mapping. Allocates space for page maps. Initializes data structures. Puts the page tables in the kernel's pagedir. + +void vm_translation_map_module_init_post_sem(kernel_args *ka) + Initializes this module's semaphores and mutexes. + +int vm_translation_map_module_init2(kernel_args *ka) + Creates anonymous regions for the kernel pagedir, physical page mappings, iospaces' virtual chunk descriptors and iospaces' page tables. Creates a null region for iospace. + +int vm_translation_map_quick_map(kernel_args *ka, addr va, addr pa, unsigned int attributes, addr (get_free_page)(kernel_args *)) + Maps a page, ignoring already set up info. + +static int vm_translation_map_quick_query(addr va, addr *out_physical) + Gets the physical address for a page. + +addr vm_translation_map_get_pgdir(vm_translation_map *map) + Returns the pagedirectory structure. + diff --git a/docs/develop/kernel/arch_vm_x86 b/docs/develop/kernel/arch_vm_x86 new file mode 100644 index 0000000000..8b8a943195 --- /dev/null +++ b/docs/develop/kernel/arch_vm_x86 @@ -0,0 +1,11 @@ +int arch_vm_init (kernel_args *ka) + First round of initialization; does nothing. + +int arch_vm_init2 (kernel_args *ka) + Marks the bios and dma ranges as "in use". + +int arch_vm_init_endvm (kernel_args *ka) + Maps the dma region into kernel space + +void arch_vm_aspace_swap(vm_address_space *aspace) + Calls i386_swap_pgdir \ No newline at end of file diff --git a/docs/develop/kernel/vm b/docs/develop/kernel/vm new file mode 100644 index 0000000000..324e4c0f87 --- /dev/null +++ b/docs/develop/kernel/vm @@ -0,0 +1,210 @@ +Variables + +static vm_address_space *kernel_aspace; +static region_id next_region_id; +static void *region_table; +static sem_id region_hash_sem; +static aspace_id next_aspace_id; +static void *aspace_table; +static sem_id aspace_hash_sem; +static int max_commit; +static spinlock_t max_commit_lock; + +Functions + +static int region_compare(void *_r, const void *key) + Compares _r (a vm_region) to key to see if their id's are the same. If so, return 0, else return -1 + +static unsigned int region_hash(void *_r, const void *key, unsigned int range) + If _r is null, return key (a region_id) mod range, else return _r's id mod range. + +static int aspace_compare(void *_a, const void *key) + Compares _a (an address space) to key to see if their id's are the same. If so, return 0, else return -1 + +static unsigned int aspace_hash(void *_a, const void *key, unsigned int range) + If _a is null, return key (an aspace_id) mod range, else return _a's id mod range. + +vm_address_space *vm_get_aspace_by_id(aspace_id aid) + Does a hash lookup on aid to find a vm_address_space struct. Increments its reference count and returns it. + +vm_region *vm_get_region_by_id(region_id rid) + Does a hash lookup on rid to find a vm_region. Increments its reference count and returns it. + +region_id vm_find_region_by_name(aspace_id aid, const char *name) + Finds this address space's structure. Iterates over the region list, looking for a match for name. vm_put_aspace's the address space. + +static vm_region *_vm_create_region_struct(vm_address_space *aspace, const char *name, int wiring, int lock) + Allocates space for a region and its name. Populates the name. Gets a new region id and assigns it. Sets map to the address space's virtual map. + +static int find_and_insert_region_slot(vm_virtual_map *map, addr start, addr size, addr end, int addr_type, vm_region *region) + Loops over the map's region list until it finds where this region should be inserted. If addr_type is any address, find any spot where it will fit and set the region up to start at the end of the previous one + 1. If we are searching for an exact address, see if that area is free and if so, use it. Increment map's change count. + + +static int map_backing_store(vm_address_space *aspace, vm_store *store, void **vaddr,off_t offset, addr size, int addr_type, int wiring, int lock, int mapping, vm_region **_region, const char *region_name) + Creates a region structure for this address space, name, wiring and lock. If this is a private map, create a new store, cache and cache_ref for private copies of pages. If the store's commited size is too small, ask the store to attempt to commit more. Aquire a reference to the cache_ref. Ensure that no one is deleting this address space; if they are, exit with an error. Insert this region into the address space. Attaches the cache to the region. Inserts the region into the region hash table. Adds a reference to the address space. Releases the cache_ref reference. + +region_id user_vm_create_anonymous_region(char *uname, void **uaddress, int addr_type, addr size, int wiring, int lock) + Does some safety checking, copies the name and address to kernel space, calls vm_create_anonymous_region, then copies the return result to uaddress. + +region_id vm_create_anonymous_region(aspace_id aid, char *name, void **address, int addr_type, addr size, int wiring, int lock) + Gets the address space structure. Creates an anonymous store object, a (temporary) cache and a cache_ref. Acquires a ref to the cache_ref. Calls map_backing_store for this address and size. Releases the cache_ref. If wiring is lazy, do nothing. If wiring is wired, calls soft_fault to simulate a fault and force the mapping to occur. If the wiring is "wired already", i.e. we cheated at boot time to make this happen, then find the pages and call vm_cache_insert_page to insert the pages into the cache. If the wiring is contiguous, allocate the pages and put them into the cache. + + +region_id vm_map_physical_memory(aspace_id aid, char *name, void **address, int addr_type, addr size, int lock, addr phys_addr) + Get the address space structure. Create a device store object, a cache and a cache_ref. Acquire a reference for the cache_ref. map backing store to this space and size. release the reference to the cache_ref. + +region_id vm_create_null_region(aspace_id aid, char *name, void **address, int addr_type, addr size) + Get the address space structure. Create a null store object, a cache and a cache_ref. Acquire a reference for the cache_ref. map backing store to this space and size. release the reference to the cache_ref. + +static region_id _vm_map_file(aspace_id aid, char *name, void **address, int addr_type,addr size, int lock, int mapping, const char *path, off_t offset, bool kernel) + Get the address space structure. Get the vnode from the path. If this cache doesn't already exist: + create a vnode store object, a cache and a cache_ref. Acquire a reference for the cache_ref. set the cache_ptr to this cache_ref, and keep retrying until it works. release the reference to the cache_ref. + Acquire a ref to the cache_ref. map backing store, release the ref and put the address space. + +region_id vm_map_file(aspace_id aid, char *name, void **address, int addr_type, addr size, int lock, int mapping, const char *path, off_t offset) + Convenience function - calls _vm_map_file with a kernel param of true. + +region_id user_vm_map_file(char *uname, void **uaddress, int addr_type, addr size, int lock, int mapping, const char *upath, off_t offset) + Sanity checks the name, address and path. Copies those into kernel space and calls _vm_map_file with a kernel param of false. + +region_id user_vm_clone_region(char *uname, void **uaddress, int addr_type, region_id source_region, int mapping, int lock) + Sanity checks the name and address. Copies those into kernel space and calls vm_clone_region. + +region_id vm_clone_region(aspace_id aid, char *name, void **address, int addr_type, region_id source_region, int mapping, int lock) + Gets the address space and region structures. maps backing store and returns. + +static int __vm_delete_region(vm_address_space *aspace, vm_region *region) + If the region's address space matches aspace, put_region it. + +static int _vm_delete_region(vm_address_space *aspace, region_id rid) + Gets the region, calls __vm_delete_region, then puts the region. + +int vm_delete_region(aspace_id aid, region_id rid) + Gets the address space. Calls _vm_delete_region, puts the address space and returns. + +static void _vm_put_region(vm_region *region, bool aspace_locked) + Check to see if there are still references to this region. If not, remove it from the global list and return. Remove the region from the adress space's region list. Remove the region from the vm_cache. Unmap it from the translation map. + +void vm_put_region(vm_region *region) + Calls _vm_put_region with locked=false. + +int user_vm_get_region_info(region_id id, vm_region_info *uinfo) + Calls vm_get_region_info after sanity checking the vm_region_info pointer. + +int vm_get_region_info(region_id id, vm_region_info *info) + Fills in the vm_region_info structure with id, base, size, lock, wiring and name. + +int vm_get_page_mapping(aspace_id aid, addr vaddr, addr *paddr) + Returns a physical address, given a virtual one. + +static void display_mem(int argc, char **argv) + Displays a value in memory. + +static void dump_cache_ref(int argc, char **argv) + Dumps a cache ref to debugging terminal + +static const char *page_state_to_text(int state) + Converts a state enum to a descriptive string. + +static void dump_cache(int argc, char **argv) + Dumps a particular cache entry. + +static void _dump_region(vm_region *region) + Dumps a particular region + +static void dump_region(int argc, char **argv) + Finds region by id and dumps it. + +static void dump_region_list(int argc, char **argv) + Dumps info about every region. + +static void _dump_aspace(vm_address_space *aspace) + Dumps data about an address space. + +static void dump_aspace(int argc, char **argv) + Finds an address space by ID and dumps it. + +static void dump_aspace_list(int argc, char **argv) + Dumps data about every address space. + +vm_address_space *vm_get_kernel_aspace(void) + Returns a pointer to the kernel address space structure. + +aspace_id vm_get_kernel_aspace_id(void) + Returns the kernel's address space id. + +vm_address_space *vm_get_current_user_aspace(void) + Gets the current user address space, given an id. + +aspace_id vm_get_current_user_aspace_id(void) + Uses the thread structure to get the current address space id. + +void vm_put_aspace(vm_address_space *aspace) + Removes a reference to the adress space. If it is the last one, destory the aspace. + +aspace_id vm_create_aspace(const char *name, addr base, addr size, bool kernel) + Allocate space for the structure and the name. Set default state. Creates a translation map. Initializes the virtual map and adds the structure to the global address space list. + +int vm_delete_aspace(aspace_id aid) + Gets the aspace struct from the id. If someone is already deleting, bail out. Put all of the regions, and put the aspace twice to cause it to be deleted. + +int vm_aspace_walk_start(struct hash_iterator *i) + calls open_hash on the aspace table. + +vm_address_space *vm_aspace_walk_next(struct hash_iterator *i) + Get the next address space in the hash list. + +static int vm_thread_dump_max_commit(void *unused) + Calls the unused function, then loops forever, printing the max_commit changes. Weird. + +int vm_init(kernel_args *ka) + Calls translation_map_module_init, and arch_vm_init. Initializes its globals, maps in the new heap and initializes it. Initializes the page list and the cache list. Creates the region and address space hash maps. Creates the kernel address space. Calls arch_vm_init2 and vm_page_init2. Allocates vm space for the stuff that the boot loader already had (heap, kernel read only, kernel read write, bootdir and the kstacks. Calls arch_vm_init_endvm. Adds commands to the debugger. + +int vm_init_postsem(kernel_args *ka) + Calls vm_translation_map_module_init_post_sem, creates the vm locking semaphores, and calls heap_init_postsem. + +int vm_init_postthread(kernel_args *ka) + Creates a max_commit_thread, calling vm_thread_dump_max_commit. + +int vm_page_fault(addr address, addr fault_address, bool is_write, bool is_user, addr *newip) + Calls vm_soft_fault. If that fails then checks to see if there is a fault handler for this case. If so, ensures that it is called. If there is no such case, kernel_panic (is this a good thing?) + +static int vm_soft_fault(addr address, bool is_write, bool is_user) + Sanity checks the address, determining if it is kernel or user land and getting the appropriate address space. Looks up the region from the aspace's map and the address. On failure, fail. Checks permissions. Finds the regions's cache ref; if there is a fault function for that cache_ref, invoke it and return with the error that the fault function returns. + Otherwise, iterates over the cache chain: + If the page is found in the current cache, set that page as busy and stop iterating. + Otherwise, insert a dummy page in this cache (to keep other threads of the same process from chasing us in fault land) + See if this cache's store has a "has_page" function. If so, call it. If it finds the page (meaning that the page is in this cache's storage), allocate a new physical page, read the data into the page and stop iterating. + If we didn't find a cache, pick one (if we are in write mode, the top, if not, the deepest cache). + If we don't have a page at this point, make a new one and insert it into the cache. Replace the dummy page, if any, with our new page. + If this is a writable page and we are not in the topmost cache, we need another physical page for writes. Find the original page and copy it to the new page. Replace the dummy page, if any, with our new page. + Ensure that the address region is still legit. + Map the new page into the address space. + Replace the dummy page, if any, with our new page. + Set the page to active. Release all locks. + + +static vm_region *vm_virtual_map_lookup(vm_virtual_map *map, addr address) + Walk the region list of this map, looking for a region containing this address and return it. + +int vm_get_physical_page(addr paddr, addr *vaddr, int flags) + Get the physical page for this virtual address. + +int vm_put_physical_page(addr vaddr) + Put the physical page for this virtual address. + +void vm_increase_max_commit(addr delta) + Lock everything, increase max_commit, then unlock everything. + +int user_memcpy(void *to, const void *from, size_t size) + Calls the arch_ version. + +int user_strcpy(char *to, const char *from) + Calls the arch_ version. + +int user_strncpy(char *to, const char *from, size_t size) + Calls the arch_ version. + +int user_memset(void *s, char c, size_t count) + Calls the arch_ version. + diff --git a/docs/develop/kernel/vm_cache b/docs/develop/kernel/vm_cache new file mode 100644 index 0000000000..568a9cf748 --- /dev/null +++ b/docs/develop/kernel/vm_cache @@ -0,0 +1,41 @@ +Variables +static void *page_cache_table + +static spinlock_t page_cache_table_lock + +static int page_compare_func(void *_p, const void *_key) + Compares a vm_page's cache_ref and offset to those of key. Returns 0 on match, -1 otherwise. + +static unsigned int page_hash_func(void *_p, const void *_key, unsigned int range) + If p is not null, use it otherwise use key; computes a hash value for offset and reference. + +int vm_cache_init(kernel_args *ka) + Calls hash_init, sets page_cache_table_lock to unlocked and returns 0. + +vm_cache *vm_cache_create(vm_store *store) + Allocates a vm_cache structure and populates with 0's and NULLs (except for store). + +vm_cache_ref *vm_cache_ref_create(vm_cache *cache) + Allocates a vm_cache_ref, setting it to point to the passed in cache. It initalizes the references lock and returns. + +void vm_cache_acquire_ref(vm_cache_ref *cache_ref, bool acquire_store_ref) + If the cache_ref is null, panic. Otherwise, if we are to aquire a reference and there is an aquire reference function for this cache's store, call that function. Finally, increment this cache references' count. + +void vm_cache_release_ref(vm_cache_ref *cache_ref) + If this cache_ref is the last reference to its cache, we call destroy on the store, remove all of its pages from the page_cache_table and set the state of them to free, increase max_commit by the size of the now freed storage, remove the reference to the original cache, destroy the reference's mutex and its space. + Otherwise, we call the store's release ref and return. + +vm_page *vm_cache_lookup_page(vm_cache_ref *cache_ref, off_t offset) + Lock the page_cache_table_lock and lookup the offset and cache_ref in the page_cache_table, then unlock. + +void vm_cache_insert_page(vm_cache_ref *cache_ref, vm_page *page, off_t offset) + Add this page to the page_cache_table. + +void vm_cache_remove_page(vm_cache_ref *cache_ref, vm_page *page) + Find this page and remove it from the hash list. Clean up the linked lists. + +int vm_cache_insert_region(vm_cache_ref *cache_ref, vm_region *region) + Add this region to the cache_ref's region list. + +int vm_cache_remove_region(vm_cache_ref *cache_ref, vm_region *region) + Remove this region from the cache_ref's region list. \ No newline at end of file diff --git a/docs/develop/kernel/vm_daemon b/docs/develop/kernel/vm_daemon new file mode 100644 index 0000000000..b913e30e0c --- /dev/null +++ b/docs/develop/kernel/vm_daemon @@ -0,0 +1,33 @@ +Variables + +bool trimming_cycle; +Do we need free space? + +static addr free_memory_low_water; + +static addr free_memory_high_water; + +static void scan_pages(vm_address_space *aspace, addr free_target) + Finds a region in this address space to scan. + Locks the region's cache_ref. + For each page, + if the page is present, do nothing with this page + Lookup the page structure. If this page doesn't exist, do nothing with this page. + If the page is written to or is hard wired (unswapable), do nothing with it. + If the page is not accessed and is active and we need space (free_target), unmap it. If this is the last reference to that mapped page, put it on the inactive list. + If the page has been modified, but wasn't on the active list, put it there. + Move to the next region in this address space, wrap around until we hit the first one. + +static int page_daemon() + Walk through every address space: + Adjust the size of the processes' working set (i.e. memory allocation) to be larger or smaller, to tailor to faults. + Set trimming cycle if free pages is below the high water mark. + Clear trimming cycle if free pages is above high water mark. + Set free memory target to be the processes' mapped size minus the working set + Call scan_pages + + +int vm_daemon_init() + Sets high water to pages/4 and low water to pages/8. + Creates the page daemon as a kernel thread. + \ No newline at end of file diff --git a/docs/develop/kernel/vm_page b/docs/develop/kernel/vm_page new file mode 100644 index 0000000000..002564433c --- /dev/null +++ b/docs/develop/kernel/vm_page @@ -0,0 +1,112 @@ +Variables +extern bool trimming_cycle; + Determines if we are trimming - if we are nearly out of space + +static page_queue page_free_queue; + The queue that holds unused (but not cleared) pages + +static page_queue page_clear_queue; + The queue that holds cleared (0'ed) pages + +static page_queue page_modified_queue; + The queue that holds altered pages + +static page_queue page_active_queue; + The queue that holds in use pages that are not altered + +static vm_page *all_pages; + Every page in the system + +static addr physical_page_offset; + The first address of real ram + +static unsigned int num_pages; + Total number of pages in the system + +static spinlock_t page_lock; + A lock to protect the queues. + +static sem_id modified_pages_available; + A semaphore to indicate if there are pages that need to be written to disk + +static void clear_page(addr pa); + Sets all values in this page to 0. + +static vm_page * dequeue_page(page_queue *q) + Standard queue remove first page; has count; no locking + +void dump_page_stats(int argc, char **argv); + Dumps counts of each state (active, inactive, busy, not used, modified, free, cleared, wired) + +void dump_free_page_table(int argc, char **argv) + Not done. + +static void enqueue_page(page_queue *q, vm_page *page) + Standard queue add a page; has count; no locking; SPECIAL - for page_modified_queue, if there is only one page modified (new one), release semaphore + +static bool is_page_in_phys_range(kernel_args *ka, addr paddr) + Determines if a physical address is in the physical memory that exists. + +static void move_page_to_queue(page_queue *from_q, page_queue *to_q, vm_page *page) + Removes the page from the from_q and adds it to the to_q. + +static int pageout_daemon() + aquires the "modified pages available" semaphore. Gets first page from modified list. Sets it to busy, updates all processes mapping this page that it is no longer a modified page, writes it out to disk, then puts it on the active list (i.e. not modified). Doesn't write out "anonymous" blocks unless we are trimming. + +static int page_scrubber(void *); + Every 1/10 second, takes a page from the free queue, memsets it to 0's, then puts it on the clear queue. + +static void remove_page_from_queue(page_queue *q, vm_page *page) + Removes a given page from the given page queue. No locking. + +addr vm_alloc_from_ka_struct(kernel_args *ka, unsigned int size, int lock) + Gets virtual space in the ka using vm_alloc_vspace_from_ka_struct, then uses vm_alloc_ppage_from_kernel_struct to find a physical page to map it to. + +static addr vm_alloc_ppage_from_kernel_struct(kernel_args *ka) + Attempts to extend, by one page, one of the phys_alloc_range blocks in the kernel args. + +static addr vm_alloc_vspace_from_ka_struct(kernel_args *ka, unsigned int size) + Attempts to find an address range that can be extended to hold size bytes. + +vm_page * vm_lookup_page(addr page_num) + Does the math to get vm_page pointer from a page number. + +int vm_mark_page_inuse(addr page) + Calls vm_mark_page_range_inuse with len of 1. + +int vm_mark_page_range_inuse(addr start_page, addr len) + Sets state to PAGE_STATE_UNUSED for all pages in this range. + +vm_page * vm_page_allocate_page(int page_state) + Gets a single page from the clear or free queue (from page_state), fall back to the other. + +vm_page * vm_page_allocate_page_run(int page_state, addr len) + Attempts to find a run of pages "len" long that are either free or clear. If found, pulls them from their queues and calls vm_page_set_state_nolock on them + +vm_page * vm_page_allocate_specific_page(addr page_num, int page_state) + Finds this page, removes it from the clear or free queue, clears it if necessary and returns. Returns NULL for not found or page in use. + +int vm_page_init(kernel_args *ka) + Initializes the free, clear, modified and active queues. Sets up the vm structures. + +int vm_page_init2(kernel_args *ka) + Properly maps the vm structures allocated in vm_page_init. + +int vm_page_init_postthread(kernel_args *ka) + Creates the page scrubber and the pageout daemon. + +addr vm_page_num_pages() + Returns the total number of pages. + +addr vm_page_num_free_pages() + Returns count of pages in free and clear queues. + +int vm_page_set_state(vm_page *page, int page_state) + Locks, then calls vm_page_set_state_nolock, then unlocks. + +static int vm_page_set_state_nolock(vm_page *page, int page_state); + Moves a page from the state that it is in to the state specified, and moves it from the old queue to the new one. + + + + diff --git a/docs/develop/kernel/vm_store_anonumous_noswap b/docs/develop/kernel/vm_store_anonumous_noswap new file mode 100644 index 0000000000..7312c3c3df --- /dev/null +++ b/docs/develop/kernel/vm_store_anonumous_noswap @@ -0,0 +1,21 @@ +static void anonymous_destroy(struct vm_store *store) + Free's the memory associated with store + +static off_t anonymous_commit(struct vm_store *store, off_t size) + Returns 0 + +static int anonymous_has_page(struct vm_store *store, off_t offset) + Returns 0 + +static ssize_t anonymous_read(struct vm_store *store, off_t offset, iovecs *vecs) + Returns unimplemented + +static ssize_t anonymous_write(struct vm_store *store, off_t offset, iovecs *vecs) + Returns 0 +/* +static int anonymous_fault(struct vm_store *backing_store, struct vm_address_space *aspace, off_t offset) +*/ + + +vm_store *vm_store_create_anonymous_noswap() + Allocates space for a vm_store. Populates its ops with the above, sets its cache and data to none. \ No newline at end of file diff --git a/docs/develop/kernel/vm_store_device b/docs/develop/kernel/vm_store_device new file mode 100644 index 0000000000..b9aeb38c78 --- /dev/null +++ b/docs/develop/kernel/vm_store_device @@ -0,0 +1,20 @@ +static void device_destroy(struct vm_store *store) + Frees the space associated with this store + +static off_t device_commit(struct vm_store *store, off_t size) + Sets this store's commited size to size. + +static int device_has_page(struct vm_store *store, off_t offset) + Returns 0 + +static ssize_t device_read(struct vm_store *store, off_t offset, iovecs *vecs) + Returns unimplemented. + +static ssize_t device_write(struct vm_store *store, off_t offset, iovecs *vecs) + Returns 0 + +static int device_fault(struct vm_store *store, struct vm_address_space *aspace, off_t offset) + Should be called when a page is not mapped in. Locks the translation map, Finds the region in the cache that contains this page and maps it in. Unlocks the cache. + +vm_store *vm_store_create_device(addr base_addr) + Allocates memory for the vm_store structure, plus the data_store_device structure. Sets cache to null, and data to the device_store_data. Sets the device_store_data's base address to the base address passed in. \ No newline at end of file diff --git a/docs/develop/kernel/vm_store_null b/docs/develop/kernel/vm_store_null new file mode 100644 index 0000000000..88098fae21 --- /dev/null +++ b/docs/develop/kernel/vm_store_null @@ -0,0 +1,20 @@ +static void null_destroy(struct vm_store *store) + Frees this stores space. + +static off_t null_commit(struct vm_store *store, off_t size) + Sets committed size to size and returns it. + +static int null_has_page(struct vm_store *store, off_t offset) + returns 1. + +static ssize_t null_read(struct vm_store *store, off_t offset, iovecs *vecs) + Returns -1. + +static ssize_t null_write(struct vm_store *store, off_t offset, iovecs *vecs) + Returns -1. + +static int null_fault(struct vm_store *store, struct vm_address_space *aspace, off_t offset) + Returns a Fatal page fault error. + +vm_store *vm_store_create_null(void) + Creates an empty vm_store struct. \ No newline at end of file diff --git a/docs/develop/kernel/vm_store_vnode b/docs/develop/kernel/vm_store_vnode new file mode 100644 index 0000000000..1adb0fddbb --- /dev/null +++ b/docs/develop/kernel/vm_store_vnode @@ -0,0 +1,23 @@ +static void vnode_destroy(struct vm_store *store) + Frees memory associated with this store. + +static off_t vnode_commit(struct vm_store *store, off_t size) + Sets committed size to size and returns it. + +static int vnode_has_page(struct vm_store *store, off_t offset) + Returns 1. + +static ssize_t vnode_read(struct vm_store *store, off_t offset, iovecs *vecs) + Calls vfs_readpage. + +static ssize_t vnode_write(struct vm_store *store, off_t offset, iovecs *vecs) + calls vfs_writepage + +static void vnode_acquire_ref(struct vm_store *store) + Calls vfs_vnode_aquire_ref + +static void vnode_release_ref(struct vm_store *store) + Calls vfs_vnode_release_ref + +vm_store *vm_store_create_vnode(void *vnode) + Creates space for a vm_store and a vnode_store_data. Sets data = vnode_store_data. Sets the vnode_store_data's vnode to vnode. diff --git a/docs/develop/keymap/About.txt b/docs/develop/keymap/About.txt new file mode 100644 index 0000000000..17cd661e75 --- /dev/null +++ b/docs/develop/keymap/About.txt @@ -0,0 +1,38 @@ +OpenBeOS Keymap preferences + +2002-05-16 - The input_server is restarted when a keymap is 'use'd. Hooray! + +2002-05-11 - Ok, I have found the 'move keys around with the right mouse button' feature. Now I see the Revert button make sense. Sorry I doubted you JLG :) + +2002-05-08 - Fixed switching from user- to system maps and vice versa and added revert button. Just like the original, it does abolutely nothing. Makes one wonder why it is there in the first place. + +2002-02-16 - Moved message definitions to messages.h, chopped KeymapApplication::UseKeymap into smaller pieces, created member variable fApplication in KeymapWindow, applied OpenTracker guidelines + +2002-02-15 - Added resource file and 'Use' button, made 'System' and 'User' lists mutually exclusive and implemented keymap file copying + +2002-02-09 - Added resource file and 'Use' button and made 'System' and 'User' lists mutually exclusive - sort of + +2002-02-08 - Initial checkin + + +This version: +Copies keymap files but doesn't do much else - you even have to restart the Input Server (try BeReset for that) for the new keymap to work. It seems bugfree at doing what it does though :) + + +To do (likely in this order): +- somehow inform Input Server to use the newly chosen keymap, or else restart the Input Server +- preselect 'Current' +- make the 'System' and 'User' labels show up (or: why are they invisible in the current version?) +- layout the sources to conform to OBOS standards +- find Be-defined constants for paths and/or files +- check validity of keymap file before copying +- add all the fancy stuff that's in the original Keymap application +- switch to Jam +- get rid of all excess symbols (or: what linker switch makes the linker remove all external symbols?) +- hunt leaks and fix'em + + +If anyone looks at my code and sees any major problems, please email me to tell me, I want to work hard on this app to make sure it's as stable and complete as it can get for the OpenBeOS project. + +Sandor Vroemisse +svroemisse@users.sf.net \ No newline at end of file diff --git a/docs/develop/midi/Milestones b/docs/develop/midi/Milestones new file mode 100644 index 0000000000..8ac26ea36b --- /dev/null +++ b/docs/develop/midi/Milestones @@ -0,0 +1,5 @@ +Milestones + +1) Implement all MIDI1 classes. + +2) Implement all MIDI2 classes. diff --git a/docs/develop/midi/ToDo b/docs/develop/midi/ToDo new file mode 100644 index 0000000000..87d8e440fe --- /dev/null +++ b/docs/develop/midi/ToDo @@ -0,0 +1,19 @@ + +General: + - Fill out headers. + - Add copyright information to files. + +BMidi: + - Put semaphores in the right places if necessary. + +BMidiStore: + - Implement formats 1 and 2 + - Implement frame based timing + - Implement export functionality. + - Cleanup + +BMidiText: + - Nothing? + +midi_server: + - Get started. \ No newline at end of file diff --git a/docs/develop/net/00-Design_general b/docs/develop/net/00-Design_general new file mode 100644 index 0000000000..87719510eb --- /dev/null +++ b/docs/develop/net/00-Design_general @@ -0,0 +1,97 @@ +Just some general thoughts that have occurred to me as I've started +looking at stuff related to designing a network stack... + +These are in no particular order. + +General Jottings +---------------- + +- zero-copy is a laudible aim, but in reality single copy is probably + as good as we're going to get to. Basically this means that we copy data + into the stack at some point. +- we should use a version of the mbuff's that the BSD stack uses with changes + so we use them more efficiently for our stack. +- probably need an rx and tx queue for frames. +- we should reallt be dealing with frames as soon as we can in the stack, + though we don't want to fragment earlier than we need to - what a quandry! +- it should be possible to stack/reorder modules as needed. This would be cool + if we could deal with input from other sources, e.g. data from a USB port + to be fed into a ppp stack, onto an atm/ethernet frame module and upwards. + + +Userland vs Kernel Land +----------------------- + +This has been decided as follows... +- initial stack will be userland +- stack should be modular enough that it could be moved into kernel with + little or no real work. + + +Initial Protocols +----------------- + +- ethernet/802.x encapsulation (rx only for 802.x) +- slip (?) +- ppp (?) +- arp +- ipv4 +- icmp (v4) +- udp +- tcp + +Extra's +------- + +- appletalk ? +- ipv6 +- icmpv6 +- ipv6 discovery (arp for v6) +- atm encapsulation module? +- usb interface (net stack to usb??) + +Stack Map +========= + +So, how does this all fit together??? + +[david: My ascii art is terrible, so hope this works out :)] + + ================= + = User apps = USERLAND + ================= + | | | + | | | + ========= ========= ========= + = UDP = = ICMP* = = TCP = + ========= ========= ========= + \ | / + \ | / + =============== + MBUF = IP (v4/v6) = + =============== + | + ----------------------------- + | | + =============== | ======= + BUFFER = Eth/802.x =----|---= ARP = + =============== | ======= + | | + ----------------------------|----- + | | + =========== | + = NIC IF = | KERNEL + =========== + +* ICMP is used as a placeholder for both ICMPv4 and ICMPv6, which are very + different from each other in scope and usage. + +Basically every module only needs to be able to call the module that deal with the +input/output of the protocol it find encapsulated, i.e. if IP finds a TCP packet +it simply needs to be able to call tcp_input and pass the mbuf along. There is a +requirement that each call to xxx_input gives the length of the header as they're +variable in most protocols. + +This just starts to scratch the surface, but I hope gives more of an idea +of what's been bouncing around in my head. :) + diff --git a/docs/develop/net/10-NetworkDrivers b/docs/develop/net/10-NetworkDrivers new file mode 100644 index 0000000000..44061d239b --- /dev/null +++ b/docs/develop/net/10-NetworkDrivers @@ -0,0 +1,13 @@ +Network Drivers - Milestone #1 + +Having done some work on the Tulip cards, here are some general +comments. + +- we should have both an rx and tx queue and pop/push from the queue + in the system rx/tx_thread. this should provide good performance +- order of calling is + : detect + : init +- the driver is normally in 2 pieces, one for the general calls and + one for the device specific stuff. + diff --git a/docs/develop/net/30-NetCache b/docs/develop/net/30-NetCache new file mode 100644 index 0000000000..9d3d943380 --- /dev/null +++ b/docs/develop/net/30-NetCache @@ -0,0 +1,22 @@ +Net Cache - Milestone #2 +======================== + +Hmm, a general purpose net cache. + +Types of Cache +============== + +What are we likely to need a fast cache for? Look below. + +- ipv4 address to ethernet MAC address (ARP) +- MAC address to IPv4 (RARP) +- list of IPv6 neighbours/routers/prefix's + +There remain problems in that for many of these needs additional +information is required, this information being specific to the +use at the time. + +However, all these uses require an ability to quickly find information +given a key that is a number of variable length, hence the conceptual +idea of using a hash lookup. + diff --git a/docs/develop/net/Milestones b/docs/develop/net/Milestones new file mode 100644 index 0000000000..797311b2f1 --- /dev/null +++ b/docs/develop/net/Milestones @@ -0,0 +1,66 @@ +Milestones +========== + +These were agreed 17th january 2002 in an IRC meeting. + +IRC log http://www.darkest.org/openbeos/netkit/02.01.17.openbeosnetkit.log + +Milestone Description + +1 network drivers + It was recognised that until the team members had + working NIC's there was little point in trying to + develop a network stack. + + STATUS: rtl8139 in repository + tulip driver written covering Netgear FA310TX + Ne2000 driver started + +2 Encapsulation + Ethernet packets come in 2 basic forms, + ethernet encapsulation (rfc 894) + IEEE 802.2/3/4/5 (rfc1042) + We need to be able to handle both. However, we only + MUST be able to send ethernet compatible frames. In pactice + we should try to send the frame in the same format that it + was received. In fact we may want to store the format used by + hosts? + + David says this isn't easy to do with the current newos + stack design. + + STATUS: newos has ethernet support, but with the current + architecture it's difficult to add fully transparent + support for other encapsulations. + +3 ARP module + Once we can get frames from the network, one of the first + things we need to do is start capturing and caching ARP + requests. + NB david thinks this should be aimed at providing more + general purpose caching so it's useful beyond ARP. he + suggests we call this a Net Cache module. + + STATUS: newos has an arp module, though cache needs work + and is limited to ipv4 + +4 IPv4 checksums + routing + Implement IPv4 checksums and routing + + STATUS: newos has a basic version of thisi + +5 IPv4 ICMP + Add ICMP support to out IPv4 module + +6 IPv4 Fragmentation + This will be interesting, adding support for reconstructing + and deconstructing packets into suitable frames for transport. + NB this needs to be abel to deal with different sizes of + frame. + + STATUS: + +7 TCP/UDP + + STATUS: newos has rudimentary UDP support + diff --git a/docs/develop/net/naming b/docs/develop/net/naming new file mode 100644 index 0000000000..94af397c2b --- /dev/null +++ b/docs/develop/net/naming @@ -0,0 +1,20 @@ +Document naming. + +Well, I've been thinking about this and I've decided that maybe +this formatting of the numbers we use will work. Maybe it won't, +but until someone else shouts... + +First digit is the milestone referred to, with 0 being for +general design. + +Second digit: + - layer involved for general design + - incremental for milestones + - 0 for general design comments + +So, 00 = general design principals + 01 = general design for layer 1 + 10 = general design comments for milestone 1 + 11 = first document about milestone 1 + +Does that work for people? diff --git a/docs/develop/print/AddPrinter Message.txt b/docs/develop/print/AddPrinter Message.txt new file mode 100644 index 0000000000..ce4ea557d8 --- /dev/null +++ b/docs/develop/print/AddPrinter Message.txt @@ -0,0 +1,6 @@ +PrintServerApp::MessageReceived(): BMessage: what = selp (0x73656c70, or 1936026736) + entry driver, type='CSTR', c=1, size=17, data[0]: "EPSON C40 Series" + entry transport, type='CSTR', c=1, size=12, data[0]: "Serial Port" + entry transport path, type='CSTR', c=1, size=8, data[0]: "serial1" + entry printer name, type='CSTR', c=1, size=8, data[0]: "my_test" + entry connection, type='CSTR', c=1, size=6, data[0]: "Local" diff --git a/docs/develop/print/Input Driver.txt b/docs/develop/print/Input Driver.txt new file mode 100644 index 0000000000..7df925772b --- /dev/null +++ b/docs/develop/print/Input Driver.txt @@ -0,0 +1,19 @@ +2x PageSetup +1x Print + + +config_page((null),0x80013478) +BMessage: what = pgst (0x70677374, or 1885827956) + entry printer, type='LONG', c=1, size= 4, data[0]: 0x80013218 (-2147405288, à§€2') + + +config_page((null),0x80013478) +BMessage: what = pgst (0x70677374, or 1885827956) + entry current_printer, type='CSTR', c=1, size=12, data[0]: "DemoPrinter" + entry printer, type='LONG', c=1, size= 4, data[0]: 0x80013218 (-2147405288, à§€2') + + +config_job((null),0x80013478) +BMessage: what = ppst (0x70707374, or 1886417780) + entry current_printer, type='CSTR', c=1, size=12, data[0]: "DemoPrinter" + entry printer, type='LONG', c=1, size= 4, data[0]: 0x80013218 (-2147405288, à§€2') diff --git a/docs/develop/print/MessagesFromPageSetup.txt b/docs/develop/print/MessagesFromPageSetup.txt new file mode 100644 index 0000000000..491481d0f9 --- /dev/null +++ b/docs/develop/print/MessagesFromPageSetup.txt @@ -0,0 +1,72 @@ +BMessage: what = okok (0x6f6b6f6b, or 1869311851) + entry printer, type='LONG', c=1, size= 4, data[0]: 0x8003b390 (-2147241072, à³') + entry page_format, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry orientation, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry scale, type='FLOT', c=1, size= 4, data[0]: 100.0000 + entry xres, type='LONG', c=1, size= 4, data[0]: 0x12c (300, '') + entry yres, type='LONG', c=1, size= 4, data[0]: 0x12c (300, '') + entry paper_rect, type='RECT', c=1, size=16, data[0]: BRect(l:0.0, t:0.0, r:612.0, b:792.0) + entry printable_rect, type='RECT', c=1, size=16, data[0]: BRect(l:18.0, t:18.0, r:594.0, b:774.0) + entry current_printer, type='CSTR', c=1, size=27, data[0]: "HPLaserJetPCL3Driver_BeInc" + +BMessage: what = GOOD (0x474f4f44, or 1196379972) + entry printer, type='LONG', c=1, size= 4, data[0]: 0x800131a8 (-2147405400, ী౨') + entry EPST_copies, type='LONG', c=1, size= 4, data[0]: 0x1 (1, '') + entry EPST_dst_idx_page, type='LONG', c=1, size= 4, data[0]: 0x5 (5, '') + entry EPST_src_idx_page, type='LONG', c=1, size= 4, data[0]: 0x7 (7, '') + entry EPST_orientation, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry EPST_page_order, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry EPST_centered, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry EPST_extended, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry EPST_rotate180, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry EPST_page_state, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry EPST_logic_userdef_width, type='FLOT', c=1, size= 4, data[0]: 0.0000 + entry EPST_logic_userdef_height, type='FLOT', c=1, size= 4, data[0]: 0.0000 + entry EPST_page_name, type='CSTR', c=1, size=3, data[0]: "A4" + entry EPST_scale, type='FLOT', c=1, size= 4, data[0]: 100.0000 + entry paper_rect, type='RECT', c=1, size=16, data[0]: BRect(l:0.0, t:0.0, r:595.2, b:841.8) + entry printable_rect, type='RECT', c=1, size=16, data[0]: BRect(l:8.4, t:8.4, r:586.8, b:802.2) + entry EPST_page_rect, type='RECT', c=1, size=16, data[0]: BRect(l:0.0, t:0.0, r:2976.0, b:4209.0) + entry EPST_printer_rect, type='RECT', c=1, size=16, data[0]: BRect(l:42.0, t:42.0, r:2934.0, b:4011.0) + entry EPST_page_settings_dpi, type='FLOT', c=1, size= 4, data[0]: 72.0000 + entry EPST_printer_settings_dpi, type='FLOT', c=1, size= 4, data[0]: 360.0000 + entry EPST_paper_feed, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry EPST_quality, type='LONG', c=1, size= 4, data[0]: 0x1 (1, '') + entry EPST_resolution, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry EPST_paper_type, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry EPST_color, type='LONG', c=1, size= 4, data[0]: 0x6 (6, '') + entry EPST_microweave, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry EPST_unidirectionnal, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry xres, type='LONG', c=1, size= 4, data[0]: 0x168 (360, '') + entry yres, type='LONG', c=1, size= 4, data[0]: 0x168 (360, '') + entry EPST_BEATWARE, type='BOOL', c=1, size= 1, data[0]: 0 + entry first_page, type='LONG', c=1, size= 4, data[0]: 0x1 (1, '') + entry last_page, type='LONG', c=1, size= 4, data[0]: 0x7fffffff (2147483647, '') + entry EPST_preview, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry current_printer, type='CSTR', c=1, size=24, data[0]: "EPSONStylusDriver_BeInc" + +BMessage: what = okok (0x6f6b6f6b, or 1869311851) + entry printer, type='LONG', c=1, size= 4, data[0]: 0x8003b498 (-2147240808, à´˜') + entry bitmap, type='BOOL', c=1, size= 1, data[0]: 0 + entry HighQuality, type='BOOL', c=1, size= 1, data[0]: 0 + entry in_color, type='BOOL', c=1, size= 1, data[0]: 0 + entry orientation, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry page size, type='CSTR', c=1, size=7, data[0]: "Letter" + entry ppd_item, type='MSGG', c=1, size= 0, + entry xres, type='LLNG', c=1, size= 8, data[0]: 0x12c (300, '') + entry yres, type='LLNG', c=1, size= 8, data[0]: 0x12c (300, '') + entry paper_rect, type='RECT', c=1, size=16, data[0]: BRect(l:0.0, t:0.0, r:612.0, b:792.0) + entry units, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry printable_rect, type='RECT', c=1, size=16, data[0]: BRect(l:14.4, t:21.6, r:597.6, b:784.8) + entry first up, type='BOOL', c=1, size= 1, data[0]: 1 + entry current_printer, type='CSTR', c=1, size=23, data[0]: "PostScriptDriver_BeInc" + +BMessage: what = okok (0x6f6b6f6b, or 1869311851) + entry printer, type='LONG', c=1, size= 4, data[0]: 0x80018af0 (-2147382544, 瀊') + entry orientation, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry scale, type='FLOT', c=1, size= 4, data[0]: 100.0000 + entry xres, type='LONG', c=1, size= 4, data[0]: 0x12c (300, '') + entry yres, type='LONG', c=1, size= 4, data[0]: 0x12c (300, '') + entry paper_rect, type='RECT', c=1, size=16, data[0]: BRect(l:0.0, t:0.0, r:612.0, b:792.0) + entry printable_rect, type='RECT', c=1, size=16, data[0]: BRect(l:0.0, t:0.0, r:612.0, b:792.0) + entry current_printer, type='CSTR', c=1, size=20, data[0]: "PreviewDriver_BeInc" diff --git a/docs/develop/print/PrintSession Messages.txt b/docs/develop/print/PrintSession Messages.txt new file mode 100644 index 0000000000..222c10a898 --- /dev/null +++ b/docs/develop/print/PrintSession Messages.txt @@ -0,0 +1,40 @@ +$ print_server + +---------------------------------------------------------------------------------------------------------------------------------------------------- + PAGE SETUP......... +---------------------------------------------------------------------------------------------------------------------------------------------------- + +PrintServerApp::MessageReceived(): BMessage: what = pgst (0x70677374, or 1885827956) +PrintServerApp::MessageReceived(): BMessage: what = BRAW (0x42524157, or 1112686935) + entry active, type='BOOL', c=1, size= 1, data[0]: 1 +PrintServerApp::MessageReceived(): BMessage: what = BRAW (0x42524157, or 1112686935) + entry active, type='BOOL', c=1, size= 1, data[0]: 0 +PrintServerApp::MessageReceived(): BMessage: what = pgcp (0x70676370, or 1885823856) + +---------------------------------------------------------------------------------------------------------------------------------------------------- + PRINT......... +---------------------------------------------------------------------------------------------------------------------------------------------------- + +PrintServerApp::MessageReceived(): BMessage: what = pgcp (0x70676370, or 1885823856) +PrintServerApp::MessageReceived(): BMessage: what = ppst (0x70707374, or 1886417780) + entry orientation, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry scale, type='FLOT', c=1, size= 4, data[0]: 100.0000 + entry xres, type='LONG', c=1, size= 4, data[0]: 0x12c (300, '') + entry yres, type='LONG', c=1, size= 4, data[0]: 0x12c (300, '') + entry paper_rect, type='RECT', c=1, size=16, data[0]: BRect(l:0.0, t:0.0, r:612.0, b:792.0) + entry printable_rect, type='RECT', c=1, size=16, data[0]: BRect(l:0.0, t:0.0, r:612.0, b:792.0) + entry current_printer, type='CSTR', c=1, size=20, data[0]: "PreviewDriver_BeInc" +PrintServerApp::MessageReceived(): BMessage: what = BRAW (0x42524157, or 1112686935) + entry active, type='BOOL', c=1, size= 1, data[0]: 1 +PrintServerApp::MessageReceived(): BMessage: what = BRAW (0x42524157, or 1112686935) + entry active, type='BOOL', c=1, size= 1, data[0]: 0 +PrintServerApp::MessageReceived(): BMessage: what = pgcp (0x70676370, or 1885823856) + +---------------------------------------------------------------------------------------------------------------------------------------------------- + After spooling: +---------------------------------------------------------------------------------------------------------------------------------------------------- + +PrintServerApp::MessageReceived(): BMessage: what = pgcp (0x70676370, or 1885823856) +PrintServerApp::MessageReceived(): BMessage: what = psns (0x70736e73, or 1886613107) + entry JobName, type='CSTR', c=1, size=15, data[0]: "InterestFields" + entry Spool File, type='CSTR', c=1, size=79, data[0]: "/boot/home/config/settings/printers/PreviewDriver_BeInc/InterestFields@8257001" diff --git a/docs/develop/print/Printers Def Window Frame.txt b/docs/develop/print/Printers Def Window Frame.txt new file mode 100644 index 0000000000..70ce626a9a --- /dev/null +++ b/docs/develop/print/Printers Def Window Frame.txt @@ -0,0 +1 @@ +BRect(78.0, 71.0, 561.0, 409.0) \ No newline at end of file diff --git a/docs/develop/print/Printing Architecture.txt b/docs/develop/print/Printing Architecture.txt new file mode 100644 index 0000000000..ddc80fbab4 --- /dev/null +++ b/docs/develop/print/Printing Architecture.txt @@ -0,0 +1,5 @@ +Information from BeOS R5 implementation: + +BPrintJob::ConfigPage() +BPrintJob::ConfigJob() +BPrintJob::TakeJob() diff --git a/docs/develop/print/StyleEdit_PageSetup_JobSetup.txt b/docs/develop/print/StyleEdit_PageSetup_JobSetup.txt new file mode 100644 index 0000000000..b3e7e41dfe --- /dev/null +++ b/docs/develop/print/StyleEdit_PageSetup_JobSetup.txt @@ -0,0 +1,18 @@ +$ print_server +Loaded addon /boot/home/config/add-ons/Print/DemoDriver +Loaded addon /boot/beos/system/add-ons/Print/transport/Serial Port +Loaded addon /boot/beos/system/add-ons/Print/EPSON Stylus Driver +Loaded addon /boot/beos/system/add-ons/Print/transport/Parallel Port +Loaded addon /boot/beos/system/add-ons/Print/HP PCL3 LaserJet Compatible +Loaded addon /boot/beos/system/add-ons/Print/transport/USB Port +Loaded addon /boot/beos/system/add-ons/Print/PostScript +Loaded addon /boot/beos/system/add-ons/Print/transport/Print To File +Loaded addon /boot/beos/system/add-ons/Print/Preview +BMessage: what = pgst (0x70677374, or 1885827956) +BMessage: what = pgcp (0x70676370, or 1885823856) +------------------------------------------------- +BMessage: what = pgcp (0x70676370, or 1885823856) +BMessage: what = ppst (0x70707374, or 1886417780) + entry current_printer, type='CSTR', c=1, size=24, data[0]: "EPSONStylusDriver_BeInc" +BMessage: what = pdef (0x70646566, or 1885627750) +BMessage: what = pgcp (0x70676370, or 1885823856) diff --git a/docs/develop/print/libbe.so.printing.txt b/docs/develop/print/libbe.so.printing.txt new file mode 100644 index 0000000000..2e8e5f96e2 Binary files /dev/null and b/docs/develop/print/libbe.so.printing.txt differ diff --git a/docs/develop/storage/Annotations b/docs/develop/storage/Annotations new file mode 100644 index 0000000000..888424ebe4 --- /dev/null +++ b/docs/develop/storage/Annotations @@ -0,0 +1,444 @@ +# Annotations +# =========== +# +# This file contains a list of miscellaneous annotations. +# An entry has the following tags: +# * OS: the concerned "operating system" (BeOS R5, OBOS POSIX) +# * Module: the concerned class or file +# * Location: a more precise location, e.g. a function +# * Description: a description of the item + +OS: BeOS R5 +Module: BEntry +Location: BEntry(const BDirectory*, const char*), + SetTo(const BDirectory*, const char*) +Description: Crash when passing a NULL BDirectory. + + +OS: BeOS R5 +Module: BEntry +Location: MoveTo() +Description: Crashs when passing a NULL BDirectory. + + +OS: BeOS R5 +Module: BPath +Location: BPath(const BDirectory*, const char*, bool), + SetTo(const BDirectory*, const char*, bool) +Description: Crash when passing a NULL BDirectory. + + +OS: BeOS R5 +Module: BPath +Location: GetParent() +Description: Crashs when called on an uninitialized object or when passing + a NULL BPath. + + +OS: BeOS R5 +Module: BPath +Location: operator==(), operator!=() +Description: Uninitialized paths are not equal. An initialized path equals + a (const char*)NULL, an uninitialized path does not. + + +OS: BeOS R5 +Module: BPath +Location: Flatten() +Description: Crashs when passing a NULL buffer and doesn't check the buffer + size. + + +OS: BeOS R5 +Module: BStatable +Location: destructor +Description: Is not virtual. + + +OS: BeOS R5 +Module: BStatable +Location: GetAccessTime(), SetAccessTime() +Description: Access time unused. + + +OS: BeOS R5 +Module: BStatable +Location: GetPermissions() +Description: Doesn't filter the mode flags, thus not only the permissions are + returned. + + +OS: BeOS R5 +Module: BStatable +Location: Get*() +Description: Crash when passing a NULL pointer. + + +OS: OBOS POSIX +Module: BStatable +Location: SetPermissions/ModificationTime/CreationTime() +Description: Don't work due to set_stat(FileDescriptor, StatMember) + limitations. + + +OS: OBOS POSIX +Module: kernel_interface +Location: set_stat(FileDescriptor, StatMember) +Description: WSTAT_MODE, WSTAT_*TIME can't be implemented due to missing + fchmod()/FD time setters. + + +OS: BeOS R5 +Module: libroot +Location: fchown() +Description: fchown(file, 0xFFFFFFFF, gid) sets the UID to 0xFFFFFFFF, which + is a bug. + + +OS: BeOS R5 +Module: libroot +Location: readdir(), fs_read_attr_dir() +Description: The d_reclen field of a dirent structure does not contain the + length of the whole structure (unlike stated in + BeBook::BEntryList), but only the length of the d_name field. + If the terminating '\0' is counted or not seems to depend on the + file system. + + +OS: OBOS POSIX +Module: kernel_interface +Location: read_link(FileDescriptor, char*, size_t) +Description: Can't be implemented due to the lack of an FD readlink() version. + + +OS: BeOS R5 +Module: BSymLink +Location: MakeLinkedPath(const char*, BPath*) +Description: The dirPath seems to be converted into a BDirectory, which + causes links to be resolved, i.e. a "/tmp" dirPath expands to + "/boot/var/tmp". That does also mean, that the dirPath must + exists! + + +OS: BeOS R5 +Module: BSymLink +Location: MakeLinkedPath() +Description: Crashs when passing a NULL const char* or BDirectory. + + +OS: BeOS R5 +Module: BNode +Location: GetNextAttrName() +Description: Crashs when passing a NULL buffer. + + +OS: BeOS R5 +Module: BNode +Location: Read/WriteAttrString() +Description: Crash when passing a NULL BString. + + +OS: BeOS R5 +Module: BNode +Location: Lock() +Description: Given two BNode objects initialized to the same node, it is + possible to Lock() one of them, although the BeBook says it isn't. + + +OS: BeOS R5 +Module: BDirectory +Location: BDirectory(const node_ref*), SetTo(const node_ref*) +Description: Crash when passing a NULL node_ref. + + +OS: BeOS R5 +Module: BDirectory +Location: GetEntry() +Description: Crashs when passing a NULL BEntry. + + +OS: BeOS R5 +Module: BDirectory +Location: FindEntry() +Description: Crashs when passing a NULL BEntry. + + +OS: BeOS R5 +Module: BDirectory +Location: Contains() +Description: If the BDirectory is uninitialized, the const char* version + returns true for existing entries, whereas the const BEntry* + version returns false. + + +OS: BeOS R5 +Module: BDirectory +Location: Contains(const BEntry*, bool) +Description: Crashs when passing a NULL BEntry. + + +OS: BeOS R5 +Module: BDirectory +Location: Contains(const BEntry*, bool) +Description: Bug: Tests with a directory, contained file/dir/symlink and + the respective node kind (B_FILE_NODE/B_DIRECTORY_NODE/ + B_SYMLINK_NODE) result false. + + +OS: BeOS R5 +Module: BDirectory +Location: GetNextDirents() +Description: Crashs when passing a NULL buffer. + + +OS: OBOS +Module: BQuery +Location: Push*() +Description: Return status_t instead of void. Fail, if Fetch() has already + been called. + + +OS: BeOS R5 +Module: BQuery +Location: PushOp() +Description: Crashs when pushing B_CONTAINS/B_BEGINS/ENDS_WITH on an empty + stack. + + +OS: BeOS R5 +Module: BQuery +Location: PushUInt64() +Description: Doesn't work. Predicates constructed using it are invalid. + + +OS: BeOS R5 +Module: BQuery +Location: Get/SetPredicate() +Description: Crash when passing a NULL BString/char*. + + +OS: BeOS R5 +Module: BQuery +Location: SetVolume() +Description: Crashs when passing a NULL BVolume. + + +OS: BeOS R5 +Module: BQuery +Location: GetNextEntry/Ref() +Description: Crash when passing a NULL BEntry/entry_ref. + + +OS: BeOS R5 +Module: BMimeType +Location: {Get,Set}LongDescription() +Description: Crashes when passed a NULL description + + +OS: BeOS R5 +Module: BMimeType +Location: GetLongDescription() +Description: The contents of the description string are modified even if + the function fails. + + +OS: BeOS R5 +Module: BMimeType +Location: SetShortDescription() +Description: When passed a NULL description, doesn't crash, but does + appear to make the result of following calls to SetShortDescription + unreliable (sometimes they work, sometimes they don't). + + +OS: BeOS R5 +Module: BMimeType +Location: +Description: The maximal MIME string length, BMimeType accepts is + B_MIME_TYPE_LENGTH *not* including terminating null. Note, that + app_info reserves only B_MIME_TYPE_LENGTH chars for the + signature field. + + +OS: BeOS R5 +Module: BMimeType +Location: SetAppHint() +Description: The entry_ref passed to SetAppHint() must be valid but is not + required to refer to a file that actually exists; furthermore, + if it does exist, the MIME type of the file is not required to + match the BMimeType object's type. + + +OS: BeOS R5 +Module: BMimeType +Location: SetIcon() +Description: The BBitmap passed to BMimeType::SetIcon() must be in the B_CMAP8 + color space, or the application will crash. We should remember + to be smarter about this. + + +OS: BeOS R5 +Module: BMimeType +Location: GetIcon() +Description: The BBitmap passed to BMimeType::GetIcon() must be in the B_CMAP8 + color space. If not, the call returns B_OK but doesn't actually + modify the bitmap. We should remember to be smarter about this. + + +OS: BeOS R5 +Module: BMimeType +Location: IsValid(const char*), GetSupertype(), Contains() +Description: Crash when passing NULL. + + +OS: BeOS R5 +Module: BMimeType +Location: {Get,Set}IconForType(char*, BBitmap*, icon_size) +Description: Passing NULL as the first parameter is the same as calling + {Get,Set}Icon() with the second two parameters (i.e. {gets,sets} + the icon for the type itself). + + +OS: BeOS R5 +Module: BMimeType +Location: SetFileExtensions() +Description: Passing a NULL message does not clear the File Extensions field + for the MIME type as indicated by the Be Book; instead, it crashes + the application :-) + + +OS: BeOS R5 +Module: BMimeType +Location: GetFileExtensions() +Description: A B_STRING_TYPE field of name "type" is *added* to the result + containing the MIME type of the BMimeType object. Since the + BMessage passed to SetFileExtensions() appears to be simply + flattened into the appropriate attribute, the "type" field is + appended to any such "type" fields that may already exist in + the original BMessage. + + +OS: BeOS R5 +Module: BMimeType +Location: Install() +Description: From the Be Book: "Currently, Install() may return a random value + if the object is already installed." + + +OS: BeOS R5 +Module: BMimeType +Location: +Description: MIME Type strings are converted to lowercase before being used + as filenames in the MIME database. + + +OS: BeOS R5 +Module: BMimeType +Location: Start/StopWatching() +Description: An invalid messenger (BMessenger::Invalid()) is fine as parameter. + + +OS: BeOS R5 +Module: Mime.h/cpp +Location: get_device_icon() +Description: KDL when passing a NULL buffer! + + +OS: BeOS R5 +Module: BMimeType +Location: CheckSnifferRule() +Description: Crashes when passing a NULL rule. + + +OS: BeOS R5 +Module: BMimeType +Location: GetSnifferRule() +Description: Crashes when passing a NULL BString. + + +OS: BeOS R5 +Module: BMimeType +Location: Check/Get/SetSnifferRule() +Description: The sniffer rules description in the BeBook deviates considerably + from the actual implementation: + - + masks + - + top level ORs: (patterns...) | (patterns...) | ... + - - range overriding: [range1] ([range2]pattern) + - either no or complete ranges: (pattern1 | pattern2) + or ([range1]pattern1 | [range2]pattern2), but not + ([range1]pattern1 | pattern2) + - CheckSnifferRule() doesn't check some of the values, e.g. + ranges (negative values, or begin > end) or 0 <= priority <= 1. + + +OS: BeOS R5 +Module: BMimeType +Location: GuessMimeType(const entry_ref *, BMimeType *) +Description: When passing an uninitialized entry_ref, B_OK and + "application/octet-stream" are returned. + + +OS: BeOS R5 +Module: BMimeType +Location: SetAttrInfo +Description: Crashes when passed a NULL BMessage. + + +OS: BeOS R5 +Module: BMimeType +Location: GetInstalledTypes(BMessage*) +Description: The set of types returned by this function is determined as follows: + + All *entries* (files, dirs, or symlinks) in the root MIME database + directory treated as MIME types, except those that begin with an + underscore; only dirs are treated as supertypes (unless the dir's + META:TYPE attribute is different than its filename, in which case + it's not treated as a supertype). + + For each supertype, all *entries* (files, dirs, or symlinks) in the + corresponding supertype subdirectory are treated as a MIME type, except + those that begin with an underscore. + + The MIME type for supertypes is taken from the name of the supertype + subdirectory. + + The MIME type for non-supertypes is take from the entry's META:TYPE + attribute. If the entry has no META:TYPE attribute, the MIME type is + derived by concatentating the name of the supertype directory to the + name of the entry, separated by a "/" character. Either way, the MIME + string returned is not checked to be valid. + + +OS: BeOS R5 +Module: BMimeType +Location: GetInstalledTypes(char *super, BMessage*) +Description: The set of types returned by this function is determined as follows: + + All *entries* (files, dirs, or symlinks) in the MIME database directory + corresponding to the "super" argument are treated as subtypes, *except* + those whose filenames begin with an underscore. It does not matter if + the supertype directory has a META:TYPE attribute or not. + + The MIME type is taken from the entry's META:TYPE attribute. If the entry + has no such attribute, the MIME type is derived by concatentating the name + of the supertype directory (the directory's META:TYPE attribute is ignored + if present) to the name of the entry, separated by a "/" character. Either + way, the MIME string returned is not checked to be valid. + + +OS: BeOS R5 +Module: BMimeType +Location: GetInstalledSupertypes(BMessage*) +Description: The set of types returned by this function is determined as follows: + + All directories in the root MIME database directory are treated as + supertypes (even directories beginning with an underscore). + + The MIME type is derived from the directory name, which is not + checked to be a valid MIME string. + + +OS: BeOS R5 +Module: BMimeType +Location: GetWildcardApps() +Description: This code: + BMessage msg; + status_t error = BMimeType::GetWildcardApps(&msg); + is the same as: + BMessage msg; + BMimeType mime("application/octet-stream"); + status_t error = mime.InitCheck(); + if (!error) + error = mime.GetSupportingApps(&msg); + diff --git a/docs/develop/storage/Completed b/docs/develop/storage/Completed new file mode 100644 index 0000000000..be116ce2b6 --- /dev/null +++ b/docs/develop/storage/Completed @@ -0,0 +1,5 @@ +# Completed +# ========= +# +# This file contains completed ToDo items. + diff --git a/docs/develop/storage/RegistrarNotes.html b/docs/develop/storage/RegistrarNotes.html new file mode 100644 index 0000000000..94d59997e6 --- /dev/null +++ b/docs/develop/storage/RegistrarNotes.html @@ -0,0 +1,102 @@ + + + Registrar Notes + + + + + +


+Registrar Tasks: +
    +
  • MIME Database chores (note that BMimeType appears to read from the database directly for Get*() calls.)
    +
      +
    • Writes to the database -- SetLongDescription(), SetPreferredApp(), create_app_meta_mime(), etc +
    • Monitoring of the database -- {Start,Stop}Watching()
      +
    • Sniffer duties -- Sniffer code plus {Get,Set,Check}SnifferRule() +
    +
    + +
  • Timing chores +
      +
    • BMessageRunner functionality +
    +
  • System Shutdown chores
    +
      +
    • Shutdown cycle +
    • System shutdown window +
    +
  • Roster chores +
      +
    • Recent documents, folders, and apps +
    • Info about running applications +
    • etc... +
    +
+ + +
+Registrar Internals:
+
+ +The registrar is a non-standard BApplication. It has a shadow app in the app_server +like a normal BApplication, but one of its ports is slightly different: + +
    +
  • Standard ports -- snd, rcv, AppLooperPort +
  • Registrar ports -- snd, rcv, _roster_port_ +
+ +Since BLooper::port_id is private to BLooper (to whom BApplication +is a friend), and since you can't rename a port after it's been created, +it's likely that the only way to rename the AppLooperPort and have the registrar +still be a BApplication is to have BApplication check if it's the +registrar when it's created, and use _roster_port_ as the name for what would +otherwise be its AppLooperPort. +
+
+The rationale behind having a port with a specific name is that the registrar +implements the roster functionality. Thus one can't address it using the app signature +constructor of BMessenger, but rather must send the message directly to +a named port (for example, upon creation, a BApplication object must find and contact +the registrar to notify it of another running application; if the registrar +cannot be found, the application putzes out). + +
+
+ +The Registrar has three threads: +
    +
  • _roster_thread_ +
  • timer_thread +
  • main_mime +
+ + +
+BMimeType Notes: +
    +
  • The Get*() methods directly access the MIME database. +
  • The Set*() methods send a message to another entity which does the job. + The function that does the sending is called _send_to_roster_(), so I + suppose the roster is the one. Since the registrar has a thread named + _roster_thread_, I assume the roster lives in the registrar. +
  • Start/StopWatching() call BRoster::_Start/_StopWatching(). +
  • Adding/removing a MIME type file in ~/config/settings/beos_mime/*/ does + not trigger a notification message. So obviously no node monitoring is + done and changes to the database are supposed to be done using the API. +
+ +
+Links: +
    +
  • Icon World -- The Registrar +
  • The BeOS Bible -- File Typing and The Registrar +
  • BApplication +
  • BMimeType +
  • BMimeType (sniffer docs) +
  • BRoster + + + + \ No newline at end of file diff --git a/docs/develop/storage/ToDo b/docs/develop/storage/ToDo new file mode 100644 index 0000000000..49f7f5a293 --- /dev/null +++ b/docs/develop/storage/ToDo @@ -0,0 +1,237 @@ +# ToDo +# ==== +# +# This file lists items that have to be worked on. +# An entry for an item has the following tags: +# * Module: the concerned class or file +# * Location: a more precise location, e.g. a function +# * Description: a description of the item +# * Priority: the priority of the item, may be +# deferrable: of no/little relevance for OBOS R1 (to be future compatible: +# the next release) +# low: of relevance for the next release, but not needed in the +# near future +# medium: of relevance for the next release, needed in the near future +# high: of relevance for the next release, needed as soon as possible +# urgent: of relevance for the next release, needed yesterday, i.e. +# some people depend on it being finished and can't continue +# with their tasks otherwise +# +# * Requires: a list of prerequisites needed for the item to be worked on, +# omitted, when empty +# * Responsible: a list of people working on the item, omitted, when empty +# + +Module: BEntry +Location: Entry.cpp +Description: Definition of SYMLINK_MAX belongs to some header file. Remove it. +Priority: low + + +Module: BEntry +Location: SetTo(const BDirectory *, const char *, bool) +Description: Reimplement! Concatenating dir and leaf to an absolute path + prevents the user from accessing entries with longer absolute + path. R5 handles this without problems. +Priority: medium +Requires: - OBOS kernel? + + +Module: BEntry +Location: SetTo(const BDirectory *, const char *, bool) +Description: Reimplement! Implemented using StorageKit::entry_ref_to_path(). +Priority: low +Requires: - OBOS kernel + + +Module: EntryTest +Location: InitTest1(), InitTest2() +Description: Enable tests with strlen(dir + leaf) > B_PATH_NAME_LENGTH. +Priority: low +Requires: - reimpl. of SetTo(const BDirectory *, const char *, bool) + + +Module: BPath +Location: Flatten() +Description: Reimplement for performance reasons. Don't call FlattenedSize(). +Priority: low + + +Module: BVolume +Location: operator==() +Description: Implement. +Priority: high + + +Module: StatableTest +Location: GetXYZTest() +Description: Uncomment GetVolume() test, when BVolume::==() is implemented. +Priority: low +Requires: - implementation of BVolume::operator==() + + +Module: kernel_interface +Location: set_stat(const char*, StatMember) +Description: Implement WSTAT_CRTIME. +Priority: medium + + +Module: kernel_interface +Location: remove_attr() +Description: Verify return behavior of fs_remove_attr(). +Priority: medium + + +Module: BeOS R5::libroot +Location: +Description: Propose a project wide common handling of the + B_FILE/PATH_NAME_LENGTH (+ 1?) issue. +Priority: low + + +Module: BSymLink +Location: +Description: Remove the work-around introduced because of the missing FD + version of readlink(). +Priority: medium +Requires: - OBOS kernel + + +Module: BNode +Location: SetTo(const entry_ref *) +Description: Reimplement! Implemented using StorageKit::entry_ref_to_path(). +Priority: low +Requires: - OBOS kernel + + +Module: BNode +Location: SetTo(const BEntry *) +Description: Check if necessary to reimplement! Implemented using + SetTo(const entry_ref*). +Priority: low +Requires: - OBOS kernel + + +Module: BNode +Location: SetTo(const BDirectory*, const char*) +Description: Check if necessary to reimplement! Implemented using + SetTo(const BEntry*). +Priority: low +Requires: - OBOS kernel + + +Module: BNode +Location: Lock(), Unlock() +Description: Implement when kernel support is available. +Priority: medium +Requires: - OBOS kernel + + +Module: NodeTest +Location: SyncTest() +Description: Add more thorough tests. +Priority: low +Requires: - OBOS kernel + + +Module: NodeTest +Location: LockTest() +Description: Implement when kernel support is available. +Priority: medium +Requires: - OBOS kernel + + +Module: BFile +Location: SetTo(const entry_ref *, uint32) +Description: Reimplement! Implemented using StorageKit::entry_ref_to_path(). +Priority: low +Requires: - OBOS kernel + + +Module: BFile +Location: SetTo(const BEntry *, uint32) +Description: Check if necessary to reimplement! Implemented using + SetTo(const entry_ref*, uint32). +Priority: low +Requires: - OBOS kernel + + +Module: BFile +Location: SetTo(const BDirectory*, const char*, uint32) +Description: Check if necessary to reimplement! Implemented using + SetTo(const BEntry*, uint32). +Priority: low +Requires: - OBOS kernel + + +Module: BFile +Location: Read/Write[At]() +Description: Verify behavior of B_OPEN_AT_END. +Priority: medium + + +Module: FileTest +Location: PositionTest() +Description: Uncomment test, when B_OPEN_AT_END behavior is understood. +Priority: medium +Requires: - verification of B_OPEN_AT_END behavior + + +Module: BDirectory +Location: SetTo(const entry_ref *) +Description: Reimplement! Implemented using StorageKit::entry_ref_to_path(). +Priority: low +Requires: - OBOS kernel + + +Module: BDirectory +Location: SetTo(const BEntry *) +Description: Check if necessary to reimplement! Implemented using + SetTo(const entry_ref*). +Priority: low +Requires: - OBOS kernel + + +Module: BDirectory +Location: SetTo(const BDirectory*, const char*) +Description: Check if necessary to reimplement! Implemented using + SetTo(const BEntry*). +Priority: low +Requires: - OBOS kernel + + +Module: BDirectory +Location: GetEntry() +Description: Check if necessary to reimplement! Implemented using + StorageKit::dir_to_self_entry_ref(). +Priority: low +Requires: - OBOS kernel + + +Module: fs_info.h +Location: struct fs_info +Description: Change "char device_name[128]" to "char device_name[B_DEV_NAME_LENGTH]" + whenever appropriate, since B_DEV_NAME_LENGTH is now declared in + StorageDefs.h. +Priority: low +Requires: - filesystem support files in the source hierarchy + + +Module: BQuery +Location: SetTarget() +Description: Used a bad hack to get port and token of the BMessenger. Fix it. +Priority: low +Requires: - respective function(s) to be provided by the IK team + + +Module: BMimeType/MimeTypeTest +Location: update_mime_info(), create_app_meta_mime() +Description: Find out, what is the meaning of the force parameter. It does + obviously not mean, that calling the function twice, the second + time with force, has the same effect as calling it only at the + second time. At least the tests indicate, that the second call, + though with force, does not have any effect at all. +Priority: medium +Requires: + + diff --git a/docs/develop/storage/doxygen_config b/docs/develop/storage/doxygen_config new file mode 100644 index 0000000000..b5ced8aa62 --- /dev/null +++ b/docs/develop/storage/doxygen_config @@ -0,0 +1,691 @@ +# Doxyfile 1.2.1 + +# This file describes the settings to be used by doxygen for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = "OpenBeOS Storage Kit" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Dutch, French, Italian, Czech, Swedish, German, Finnish, Japanese, +# Spanish, Russian, Croatian, Polish, and Portuguese. + +OUTPUT_LANGUAGE = English + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these class will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. It is allowed to use relative paths in the argument list. + +STRIP_FROM_PATH = /cvsroot/open-beos/ + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a class diagram (in Html and LaTeX) for classes with base or +# super classes. Setting the tag to NO turns the diagrams off. + +CLASS_DIAGRAMS = YES + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the CASE_SENSE_NAMES tag is set to NO (the default) then Doxygen +# will only generate file names in lower case letters. If set to +# YES upper case letters are also allowed. This is useful if you have +# classes or files whose names only differ in case and if your file system +# supports case sensitive file names. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the JAVADOC_AUTOBRIEF tag is set to YES (the default) then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the Javadoc-style will +# behave just like the Qt-style comments. + +JAVADOC_AUTOBRIEF = YES + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# reimplements. + +INHERIT_DOCS = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# The ENABLE_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. + +WARN_FORMAT = "$file:$line: $text" + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../source/lib/ + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +FILE_PATTERNS = *.cpp *.h + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. + +EXCLUDE_PATTERNS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. + +INPUT_FILTER = + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimised for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using a WORD or other. +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assigments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. Warning: This feature +# is still experimental and very incomplete. + +GENERATE_XML = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_PREDEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +#--------------------------------------------------------------------------- +# Configuration::addtions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tagfiles. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the ENABLE_PREPROCESSING, INCLUDE_GRAPH, and HAVE_DOT tags are set to +# YES then doxygen will generate a graph for each documented file showing +# the direct and indirect include dependencies of the file with other +# documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, INCLUDED_BY_GRAPH, and HAVE_DOT tags are set to +# YES then doxygen will generate a graph for each documented header file showing +# the documented files that directly or indirectly include this file + +INCLUDED_BY_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found on the path. + +DOT_PATH = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO + +# The CGI_NAME tag should be the name of the CGI script that +# starts the search engine (doxysearch) with the correct parameters. +# A script with this name will be generated by doxygen. + +CGI_NAME = search.cgi + +# The CGI_URL tag should be the absolute URL to the directory where the +# cgi binaries are located. See the documentation of your http daemon for +# details. + +CGI_URL = + +# The DOC_URL tag should be the absolute URL to the directory where the +# documentation is located. If left blank the absolute path to the +# documentation, with file:// prepended to it, will be used. + +DOC_URL = + +# The DOC_ABSPATH tag should be the absolute path to the directory where the +# documentation is located. If left blank the directory on the local machine +# will be used. + +DOC_ABSPATH = + +# The BIN_ABSPATH tag must point to the directory where the doxysearch binary +# is installed. + +BIN_ABSPATH = /usr/local/bin/ + +# The EXT_DOC_PATHS tag can be used to specify one or more paths to +# documentation generated for other projects. This allows doxysearch to search +# the documentation for these projects as well. + +EXT_DOC_PATHS = diff --git a/docs/develop/storage/resources/ResourcesFormat.tex b/docs/develop/storage/resources/ResourcesFormat.tex new file mode 100644 index 0000000000..752db96f05 --- /dev/null +++ b/docs/develop/storage/resources/ResourcesFormat.tex @@ -0,0 +1,614 @@ +\documentclass[12pt, a4paper]{article} + +\usepackage{amssymb,amsmath,latexsym} +\usepackage[english]{babel} +\usepackage{hhline} + +\newcommand{\code}[1]{{\tt #1}} + +\newenvironment{nitemize}{ + \newdimen\oldparindent + \oldparindent=\parindent + \begin{itemize} + \itemindent=-\oldparindent +}{ + \end{itemize} +} + +%\newcommand{\codeblockspace}{\vspace{12pt}} + +% begin/end a code block +\newcommand{\codeblockbegin}{\begin{flushleft}\begin{minipage}{\textwidth}} +\newcommand{\codeblockend}{\end{minipage}\end{flushleft}} + + +\begin{document} + +\sloppy + +\title{The Resources Format} +%\date{} +\author{Ingo Weinhold (bonefish@users.sf.net)} + +\maketitle +\tableofcontents + + +\section{Introduction} +\label{introduction} + +Resources provide a means to store structured but flat data in files. Unlike +attributes resources are part of the file contents and thus do not require a +special file system handling, but rather a special file format. +On the one hand there are formats of files that exclusively contain resources +(resource files), on the other hand these are file formats extended to +additionally contain resources -- namely the ELF and PEF object formats. +In either case the format of the chunk of data that frames the resources +themselves is the same. We call it the resources format. + +Section \ref{file-formats} explains how the resources format is embedded in +different file formats. Section \ref{resources-format} discusses the resources +format itself. In section \ref{implementations} we focus on robustness of +resources reading/writing implementations. +The final section says some words about the status of the information provided +by this document. + + + +\section{File Formats} +\label{file-formats} + +In all file formats described in this section the resources are being located +at the end of the files. They are completely independent of their location. + + +\subsection{x86 Resource Files} + +x86 resource files introduce the least overhead. The resources start directly +after the magic number identifying the file format: +% +\codeblockbegin +\begin{verbatim} + const char kX86ResourceFileMagic[4] = { 'R', 'S', 0, 0 }; + const uint32 kX86ResourcesOffset = 0x00000004; +\end{verbatim} +\codeblockend +% +The resources start at \code{kX86ResourcesOffset}. + + +\subsection{PPC Resource Files} + +PPC resource files begin with a PEF container header, after which the +resources start. +% +\codeblockbegin +\begin{verbatim} +typedef char PefOSType[4]; + +struct PEFContainerHeader { + PefOSType tag1; + PefOSType tag2; + PefOSType architecture; + uint32 formatVersion; + uint32 dateTimeStamp; + uint32 oldDefVersion; + uint32 oldImpVersion; + uint32 currentVersion; + uint16 sectionCount; + uint16 instSectionCount; + uint32 reservedA; +}; +\end{verbatim} +\codeblockend +% +\codeblockbegin +\begin{verbatim} + const char kPEFFileMagic1[4] = { 'J', 'o', 'y', '!' }; + const char kPPCResourceFileMagic[4] = { 'r', 'e', 's', 'f' }; + const uint32 kPPCResourcesOffset = 0x00000028; +\end{verbatim} +\codeblockend + +\begin{nitemize} +\item{\code{tag1}: + Must be \code{kPEFFileMagic1}.} +\item{\code{tag2}: + Must be \code{kPPCResourceFileMagic}.} +\item{All other fields must be set to 0.} +\end{nitemize} + +\noindent +The resources start at \code{kPPCResourcesOffset}. + + +\subsection{ELF Object Files} + +In an ELF file, resources are appended to rather than contained in the +regular data of the file. That is adding resources to an existing ELF file +will not cause any modification to its data (i.e. ELF header, program header +table, section header table or sections), but will enlarge the file by some +alignment padding and, of course, the resources themselves. + +Therefore two values have to be known: The size of the actual ELF file and the +block size to which the resources must be aligned. As ELF files do not contain +a size field, it has to be deduced, where the file ends. This end offset is +supposed to be the maximum of the end offsets of ELF header, program header +table (if any), section header table (if any), sections and segments. + +The block size to which the resources have to be aligned is the maximum of +\code{kELFMinResourceAlignment} and the alignments of the segments in the file. +% +\begin{verbatim} + const uint32 kELFMinResourceAlignment = 32; +\end{verbatim} +% +The data used for the padding between the end of the actual ELF data and the +beginning of the resources may be arbitrary. + + +\subsection{PEF Object Files} + +Similar to ELF files the resources are simply appended to the regular data of +a PEF file, but they are not aligned to any value. That is the resources +start directly after the last PEF section without any padding. +As no field exists, that tells about the size of the PEF container (the +regular data), it has to be deduced by iterating through the PEF section +headers. + + + +\section{The Resources Format} +\label{resources-format} + +This section describes the resources format. After a subsection that outlines +their general layout, it follow subsections discussing the major parts. + +A general remark regarding the byte ordering: Resources have no standard +endianess, that is the resources created by little endian and big endian +machines differ. Usually it should be possible, to deduce the used endianess +from the type of the file. x86 resource files contain little endian, PPC +resource files big endian data. The endianess of an ELF file is encoded in +its header. + +As there is in fact no good reason to have different resource file formats, +even if they differ only in the format of the header (see section +\ref{file-formats}), it may be decided to use the x86 resource file format +also for big endian machines. Therefore the endianess may be deduced by the +first field of the resources header (\code{rh\_resources\_magic}, see +subsection \ref{resources-header}). + + +\subsection{Resources Layout} + +The layout of the resources in a file is shown in figure +\ref{fig:resources-layout}. + +\begin{figure}[h!tb] + \begin{center} + \begin{tabular}{|c|c|c|} + \hline + & \multicolumn{2}{c|}{resources header}\\ + \hhline{|~==|} + admin section & & index section header \\ + \hhline{~~|-|} + & index section & resource index \\ + \hhline{~~|-|} + & & padding \\ + \hhline{:===:} + \multicolumn{3}{|c|}{unknown section}\\ + \hhline{:===:} + \multicolumn{3}{|c|}{data section}\\ + \hhline{|~~~|} + \hhline{:===:} + \multicolumn{3}{|c|}{info section}\\ + \hline + \end{tabular} + \end{center} + \caption{The Resources Layout.} + \label{fig:resources-layout} +\end{figure} + +\noindent +There are four sections: +% +\begin{itemize} +\item{An administrative section which comprises the resources header and the + resource index subsection. The latter locates all other data in the file. +} +\item{An unknown section, whose purpose is (unsurprisingly) unknown, but which + seems to be unused, always containing the same data. +} +\item{A data section holding the actual resource data. +} +\item{An info section, which provides aditional information for each resource, + such as type, id and name. +} +\end{itemize} + + +\subsection{Resources Header} +\label{resources-header} + +The resources header has the following structure: +% +\codeblockbegin +\begin{verbatim} + struct resources_header { + uint32 rh_resources_magic; + uint32 rh_resource_count; + uint32 rh_index_section_offset; + uint32 rh_admin_section_size; + uint32 rh_pad[13]; + }; +\end{verbatim} +\codeblockend +% +\codeblockbegin +\begin{verbatim} + const uint32 kResourcesHeaderMagic = 0x444f1000; + const uint32 kResourceIndexSectionOffset = 0x00000044; + const uint32 kResourceIndexSectionAlignment = 0x00000600; +\end{verbatim} +\codeblockend + +\begin{nitemize} +\item{\code{rh\_resources\_magic}: + Must be \code{kResourcesHeaderMagic}. +} +\item{\code{rh\_resource\_count}: + Specifies the number of resources stored in this file. May be 0. +} +\item{\code{rh\_index\_section\_offset}: + Specifies the offset of the resource index section relative to the beginning + of the resources. An alternative interpretation may be the size of the + resources header. + Must be \code{kResourceIndexSectionOffset}. +} +\item{\code{rh\_admin\_section\_size}: + Specifies the size of the administrative section. + Must be \code{kResourceIndexSectionOffset} plus a multiple of + \code{kResourceIndexSectionAlignment}. +} +\item{\code{rh\_pad}: + Padding. \code{0x00000000} words. +} +\end{nitemize} + + +\subsection{Resource Index Section} +\label{resources-index} + +The resource index section starts with a header, it follows a table of +\code{resource\_index\_entry} structures, that locates the data of each +resource, and the section ends with a special padding. + +\noindent +The resource index header has the following structure: +% +\codeblockbegin +\begin{verbatim} + struct resource_index_section_header { + uint32 rish_index_section_offset; + uint32 rish_index_section_size; + uint32 rish_unused_data1; + uint32 rish_unknown_section_offset; + uint32 rish_unknown_section_size; + uint32 rish_unused_data2[25]; + uint32 rish_info_table_offset; + uint32 rish_info_table_size; + uint32 rish_unused_data3; + }; +\end{verbatim} +\codeblockend + +\begin{verbatim} + const uint32 kUnknownResourceSectionSize = 0x00000168; +\end{verbatim} +% +\begin{nitemize} +\item{\code{rish\_index\_section\_offset}: + Specifies the offset of the resource index section relative to the beginning + of the resources. An alternative interpretation may be the size of the + resources header. + Must be \code{kResourceIndexSectionOffset}. +} +\item{\code{rish\_index\_section\_size}: + Specifies the size of the resource index section. + Must be a multiple of \code{kResourceIndexSectionAlignment}. +} +\item{\code{rish\_unused\_data1}: + Contains special data as described in section \ref{resources-unknown}. +} +\item{\code{rish\_unknown\_section\_offset}: + Specifies the offset of the unknown section relative to the beginning + of the resources. + Must be the same value as given in the resources header for + \code{rh\_admin\_section\_size}. +} +\item{\code{rish\_unknown\_section\_size}: + Specifies the offset of the unknown section relative to the beginning + of the resources. + Must be \code{kUnknownResourceSectionSize}; +} +\item{\code{rish\_unused\_data2}: + Contains special data as described in section \ref{resources-unknown}. +} +\item{\code{rish\_info\_table\_offset}: + Specifies the offset of the resource info table relative to the beginning + of the resources. +} +\item{\code{rish\_info\_table\_size}: + Specifies the size of the resource info table. +} +\item{\code{rish\_unused\_data3}: + Contains special data as described in section \ref{resources-unknown}. +} +\end{nitemize} + +Directly, without padding, it follows a table of \code{resource\_index\_entry} +structures. The number of entries in the table is the number of resources +stored in the file, that is the value specified by the +\code{rh\_resource\_count} member of the resources header. Since the entries +are stored without padding, the size of the table is exactly the product of +the size of \code{resource\_index\_entry} and the number of resources. +If the latter is 0, the table takes no space. +% +\codeblockbegin +\begin{verbatim} + struct resource_index_entry { + uint32 rie_offset; + uint32 rie_size; + uint32 rie_pad; + }; +\end{verbatim} +\codeblockend +% +\begin{nitemize} +\item{\code{rie\_offset}: + Specifies the offset of the resource data relative to the beginning + of the resources. +} +\item{\code{rie\_size}: + Specifies the size of the resource data. +} +\item{\code{rie\_pad}: + Padding. Must be \code{0x00000000}. +} +\end{nitemize} + +Since the size of the resource index section must be a multiple of +\code{kResourceIndexSectionAlignment}, some padding may be needed at the end +of this section. How this padding looks like is described in section +\ref{resources-unknown}. + + +\subsection{Unknown Section} +\label{resources-unknown} + +The meaning of this section is unknown. It does not seem to be used at all. +It always contains the same data given by \code{kUnusedResourceDataPattern}: +% +\codeblockbegin +\begin{verbatim} + const uint32 kUnusedResourceDataPattern[3] = { + 0xffffffff, 0x000003e9, 0x00000000 + }; +\end{verbatim} +\codeblockend +% +In section \ref{resources-index} some members where named \code{unused\_data}. +These fields contain the same kind of data. To understand what the value for a +certain field of this type is, it may help to imagine, that before the +resources are written to a file, the space they will take is filled with the +pattern specified by \code{kUnusedResourceDataPattern}, and that only those +fields are written that are not unused. Thus the original pattern can be seen +through at the unused locations. + +To be precise: Let \verb|uint32 resources[]| be the resources and +\code{index} the index of an unused field in \code{resources}, then it holds: +% +\begin{verbatim} + resources[index] == kUnusedResourceDataPattern[index % 3]; +\end{verbatim} +% + + +\subsection{Resource Info Table} +\label{resources-infotable} + +The resource info table features exactly one entry for each resource. +Such an entry (resource info) specifies the ID and name of a +resource. Subsequent infos for resources of the same type are collected in +a block that starts with a type field. + +The following grammar specifies the layout of the resource info table. +Nonterminals start with an upper case, terminals with a lower case letter. +% +\begin{verbatim} + ResourceInfoTable ::= [ ResourceBlockList ] + ResourceInfoSeparator + ResourceInfoTableEnd + + ResourceBlockList ::= ResourceBlock + [ ResourceInfoSeparator + ResourceBlockList ] + + ResourceBlock ::= type ResourceInfoList + + ResourceInfoList ::= ResourceInfo [ ResourceInfoList ] + + ResourceInfo ::= id index name_size name + + ResourceInfoSeparator ::= 0xffffffff 0xffffffff + + ResourceInfoTableEnd ::= check_sum 0x00000000 +\end{verbatim} +% +The relevant structures follow: +% +\codeblockbegin +\begin{verbatim} + struct resource_info_block { + type_code rib_type; + resource_info rib_info[1]; + }; +\end{verbatim} +\codeblockend +% +\begin{nitemize} +\item{\code{rib\_type}: + Specifies the type of the resources in the block. +} +\item{\code{rib\_info}: + Is the first resource info of the block. More infos may follow. +} +\end{nitemize} +% +\codeblockbegin +\begin{verbatim} + struct resource_info { + int32 ri_id; + int32 ri_index; + uint16 ri_name_size; + char ri_name[1]; + }; +\end{verbatim} +\codeblockend + +\begin{verbatim} + const uint32 kMinResourceInfoSize = 10; +\end{verbatim} +% +\begin{nitemize} +\item{\code{ri\_id}: + Specifies the ID of the resource. +} +\item{\code{ri\_index}: + Specifies the index of the resource this resource info refers to. +} +\item{\code{ri\_name\_size}: + Specifies the size of the resource name. May be 0 -- then the resource does + not have a name and \code{ri\_name} has a size of 0. +} +\item{\code{ri\_name}: + Specifies the name of the resource. The name must be null terminated. + \code{ri\_name\_size} specifies the size of this field (including the + terminating null). If it is 0, the resource does not have a name and + \code{ri\_name} is empty, i.e. has size 0. +} +\item{\code{kMinResourceInfoSize}: + Is the minimal size of a resource info. That is the size it has, if the + resource does not have a name. +} +\end{nitemize} +% +\codeblockbegin +\begin{verbatim} + struct resource_info_separator { + uint32 ris_value1; + uint32 ris_value2; + }; +\end{verbatim} +\codeblockend +% +\begin{nitemize} +\item{\code{ris\_value1}: + Specifies the first word of the separator. + Must be \code{0xffffffff}. +} +\item{\code{ris\_value2}: + Specifies the second word of the separator. + Must be \code{0xffffffff}. +} +\end{nitemize} +% +\codeblockbegin +\begin{verbatim} + struct resource_info_table_end { + uint32 rite_check_sum; + uint32 rite_terminator; + }; +\end{verbatim} +\codeblockend +% +\begin{nitemize} +\item{\code{rite\_check\_sum}: + Contains the check sum for the resource info table. The check sum is + calculated from all bytes of the resource info table not including + \code{rite\_check\_sum} and \code{rite\_terminator}. The data are grouped + into four byte blocks, which are interpreted as big endian unsigned words + and summed up, ignoring carry. If the number of bytes to be considered is + not dividable by four, the remaining bytes are interpreted as the lower + bytes of a big endian unsigned word (the upper byte(s) set to 0). +} +\item{\code{rite\_terminator}: + Terminates the resource info table. + Must be \code{0x00000000}. +} +\end{nitemize} + + + +\section{Implementations} +\label{implementations} + +Code that writes resources should strictly stick to the specification +presented in the preceding sections to achieve maximal compatibility. + +Resources reading implementations may tolerate certain deviations that +for instance happen to occur in several files of the BeOS R5 distribution +and that are handled gracefully by xres and QuickRes. It follows a, possibly +incomplete, list: +% +\begin{itemize} +\item{The third and fourth byte of the x86 resource file magic (the 0 bytes) + may be arbitrary bytes.} +\item{\code{rh\_resource\_count} may be unreliable. The resource index table + should be read until its end, which is either marked by the unused data + pattern (see section \ref{resources-unknown}) or at the latest by the + beginning of the unknown section.} +\item{The resource info table may contain entries for indices that are out + of range, i.e. greater than the number of resources induced by the resource + index table. Those entries should be ignored.} +\item{The resource info table may contain multiple entries for an index. + Any such entry after the first one should be ignored.} +\item{The resource info table may not contain an entry for an index. + The respective resource should be ignored.} +\item{The resource info table may not contain a \code{ResourceInfoTableEnd} + (see section \ref{resources-infotable}) and thus no check sum. The table + should be accepted nevertheless. Note, that a table containing a wrong check + sum is {\em not} to be accepted.} +\end{itemize} + + + +\section{Status of this Document} +\label{status} + +The information contained in this document are obtained by analyzing +resources-containing files created or modified by tools available for BeOS R5, +namely QuickRes and xres. They are incomplete and may even be partially wrong, +where being based on incorrect assumptions. + +\noindent +It follows a list of items with a low degree of reliance: +\begin{itemize} +\item{Resources alignment in ELF files: Several tests with linker object files + have shown, that QuickRes aligns their resources offset to 32 bytes. + For executables on the other hand the alignment was always 4096, which is + the usual memory page size of current x86 architectures and therefore the + preferred program segment alignment. From these two information it has been + deduced, that the alignment is, if present, the maximum of + the segment alignments to be found in the program header table, + but at minimum 32.} +\item{The resources layout: The general layout of the resources is not very + well understood. The layout presented in figure \ref{fig:resources-layout} + resulted from the attempt to assign all the fields a reasonable meaning, but + in fact not even the exact length and meaning of the fields of the resources + header is unclear. The same holds for the resource index section header.} +\item{The unknown section: The contents of the unknown section and of unknown + fields is base on educated guesses.} +\end{itemize} + +\end{document} diff --git a/docs/develop/support/usecases/BAutolockUseCases.html b/docs/develop/support/usecases/BAutolockUseCases.html new file mode 100644 index 0000000000..9195f64f9b --- /dev/null +++ b/docs/develop/support/usecases/BAutolockUseCases.html @@ -0,0 +1,79 @@ + + + +BAutolock Use Cases and Implementation Details + + + + + + +

    BAutolock Use Cases and Implementation Details:

    + +

    This document describes the BAutolock interface and some basics of how it is implemented. +The document has the following sections:

    + +
      +
    1. BAutolock Interface
    2. +
    3. BAutolock Use Cases
    4. +
    5. BAutolock Implementation
    6. +
    + +

    BAutolock Interface:

    + +

    The BAutolock class is a simple class for handling synchronization between threads. The best +source of information for the BAutolock interface can be found +here in the Be Book. +

    + +

    BAutolock Use Cases:

    + +

    The following use cases cover the BAutolock functionality:

    + +
      +
    1. Construction 1: A BAutolock can be created by passing a pointer to a BLocker object. +An attempt will be made to Lock() this BLocker during the construction of the BAutolock object. +

    2. + +
    3. Construction 2: A BAutolock can be created by passing a reference to a BLocker object. +An attempt will be made to Lock() this BLocker during the construction of the BAutolock object. +

    4. + +
    5. Construction 3: A BAutolock can be created by passing a pointer to a BLooper object. +An attempt will be made to Lock() this BLooper during the construction of the BAutolock object. +

    6. + +
    7. Is Locked: When the BAutolock is constructed, a lock is attempted on the BLocker or +BLooper passed in. The result of that lock attempt is returned by calling IsLocked() on the +BAutolock. The result is a boolean. True is returned if the lock was successfully acquired. +False is returned if the lock could not be acquired. See the docs for BLocker and BLooper to +find out why the lock acquisition may fail.

    8. + +
    9. Destruction 1: If the lock acquisition on the BLocker or BLooper was successful at +construction time, when the BAutolock is destructed, the lock will be released by calling Unlock() +on the BLocker or BLooper.

    10. + +
    11. Destruction 2: If the lock acquisition on the BLocker or BLooper failed at +construction time, when the BAutolock is destructed, nothing is done to the BLocker or the BLooper. +An Unlock() is not attempted because the lock at construction time failed.

    12. + +
    + +

    BAutolock Implementation:

    + +

    The entire BAutolock implementation is inline. Because BAutolock is implemented inline, there +is no code for BAutolock in libbe.so. The code is all in Be's Autolock.h header file and compiled +at build time directly into any object being built.

    + +

    This has some interesting implications from a backwards compatibility perspective. Because +there are no references from existing non-Be executables and libraries to libbe.so expecting +to find the BAutolock class, the entire definition of BAutolock can be changed almost without risk +of breaking compatibility. This gives anyone wishing to expand and build on the current BAutolock +class a great deal of flexibility.

    + +

    However, it may be worthwhile when changing BAutolock in the future to try and stay source +compatible. That way, existing source code will continue to compile without having to update +it.

    + + + diff --git a/docs/develop/support/usecases/BLockerUseCases.html b/docs/develop/support/usecases/BLockerUseCases.html new file mode 100644 index 0000000000..18bccbf8e8 --- /dev/null +++ b/docs/develop/support/usecases/BLockerUseCases.html @@ -0,0 +1,130 @@ + + + +BLocker Use Cases and Implementation Details + + + + + + +

    BLocker Use Cases and Implementation Details:

    + +

    This document describes the BLocker interface and some basics of how it is implemented. +The document has the following sections:

    + +
      +
    1. BLocker Interface
    2. +
    3. BLocker Use Cases
    4. +
    5. BLocker Implementation
    6. +
    + +

    BLocker Interface:

    + +

    The BLocker class is a simple class for handling synchronization between threads. The best +source of information for the BLocker interface can be found +here in the Be Book. +

    + +

    BLocker Use Cases:

    + +

    The following use cases cover the BLocker functionality:

    + +
      +
    1. Construction 1: A BLocker can be created by specifying a name for the semaphore used +internally. If a name is specified during construction, then that name is given to the internal +semaphore. If no name is given at construction, the semaphore is given the name "some BLocker". +

    2. + +
    3. Construction 2: A BLocker can use a semaphore or a "benaphore" internally depending +on a flag passed when the BLocker is created. If the flag is false, the BLocker uses a semaphore +to do synchronization. If the flag is true, the BLocker uses a benaphore internally to do +synchronization. If no flag is specified, the BLocker uses a benaphore internally.

    4. + +
    5. Destruction: When a BLocker is destructed, any threads waiting for the lock are +immediately unblocked. The threads are notified by the return code of the locking member function +that the lock was not successfully acquired. Any threads blocked on Lock() will return with +a false value. Any threads blocked on LockWithTimeout() will return with B_BAD_SEM_ID.

    6. + +
    7. Locking 1: When a thread acquires the BLocker using the Lock() or LockWithTimeout() +member functions, no other thread can acquire the lock until this thread releases it.

    8. + +
    9. Locking 2: When a thread holds the BLocker and it calls Lock() or LockWithTimeout(), +the member function returns immediately. The thread must call Unlock() the same number of times +it calls Lock...() before the BLocker is released. At any time, the thread can call CountLocks() +to get the number of times it must call Unlock() to release the BLocker.

    10. + +
    11. Locking 3: When a thread calls Lock(), the thread blocks until it can acquire the +lock. Once the lock has been acquired or an unrecoverable error has occurred, the Lock() member +function completes. If the lock has been acquired, Lock() returns true. If the lock has not +been acquired, Lock() returns false.

    12. + +
    13. Locking 4: When a thread calls LockWithTimeout(), the thread blocks until it can +acquire the lock, the time specified in microseconds expires, or an unrecoverable error occurs. +If the timeout specified is B_INFINTE_TIMEOUT, there is no timeout and the member function will +either acquire the lock or fail due to an unrecoverable error. If the lock is acquired, the +member function returns B_OK. If the timeout is reached, B_TIMED_OUT is returned and the lock is +not acquired. If a serious error occurs, a non B_OK code is returned.

    14. + +
    15. Unlocking: The Unlock() member function takes no arguments and returns no value. +If the thread currently holds the lock, the lock count is reduced by the call to Unlock(). If +the lock count reaches zero, then another thread may acquire the lock. If the thread does not +hold the lock and it calls Unlock(), the call will have no affect at all on the BLocker.

    16. + +
    17. Locking Thread: The LockingThread() member function returns the thread_id of the +thread that is holding the lock. If no thread holds the lock, then B_ERROR is returned.

    18. + +
    19. Is Locked: The IsLocked() member function returns true if the BLocker is currently +held by the calling thread. If the BLocker is not acquired by any thread or it is acquired by a +different thread, IsLocked() returns false.

    20. + +
    21. Count Locks: The CountLocks() member function returns the number of times the lock +has been acquired by the thread which holds the lock. If no thread holds the lock, then 0 is +returned. If the BLocker is held by any thread, including a thread which is not the thread +making the CountLocks() request, the number of times the lock has been acquired by the thread which +holds the lock is returned.

    22. + +
    23. Count Lock Requests: The CountLockRequests() member function returns the number of +threads currently attempting to lock the BLocker. If no thread holds the lock and no thread is +waiting for the lock, then 0 is returned. If one thread holds the lock and no other threads +are waiting for the lock, then 1 is returned. If one thread holds the lock and x threads are +waiting for the lock, then x+1 is returned. The call to CountLockRequests() can be made by any +thread including threads which do not have the lock.

      + +

      NOTE: Reading the Be Book, that would seem like what is returned by this member +function. In actuality, the value returned is just the "benaphore count" for the BLocker. +If the BLocker is semaphore style, then the benaphore count is set to 1 at construction time +to ensure that the semaphore is always tested when a lock is acquired. The return value is +just this count. So, the return value for benaphore style is:

      + +
      +numThreadsWaitingForTheLock + numThreadsHoldingTheLock + numOfTimeoutsOccuredOnTheLock
      +
      + +

      The return value for a semaphore style is:

      + +
      +numThreadsWaitingForTheLock + numThreadsHoldingTheLock + numOfTimeoutsOccuredOnTheLock + 1
      +
      + +

      Again, this is what we are implementing but the above description is what appears in the +BeBook as far as I understand it.

      +
    24. + +
    25. Sem: The Sem() member function returns the sem_id of the semaphore used by the +BLocker. If the BLocker is a benaphore, then the sem_id returned is the semaphore used to +implement the benaphore. If the BLocker is a not a benaphore, then the sem_id returned is the +semaphore which the BLocker represents.

    26. +
    + +

    BLocker Implementation:

    + +

    For more information about how to implement a benaphore, you can reference an implementation +found on Be's website at + +http://www-classic.be.com/aboutbe/benewsletter/Issue26.html.

    + + + + + diff --git a/docs/develop/virtualmemory/README.XML b/docs/develop/virtualmemory/README.XML new file mode 100644 index 0000000000..5112038f9f --- /dev/null +++ b/docs/develop/virtualmemory/README.XML @@ -0,0 +1,147 @@ + + + Virtual Memory + + 0.9 + + + + Matt McMinn + melfinadev@earthlink.net + http://home.earthlink.net/~melfina/ + + + + + + It's just a copy of the virtual memory preferences app that comes with BeOS. + + + + + + + + 1 + + + Matthieu Ferte + mferte@club-internet.fr + + + + + Get the physical memory in a better way. + + + + + + + #include + + int physMem; + + system_info info; + get_system_info(&info); + physMem = (info.max_pages * 4096) / 1048576; + + + + + + + + + 2 + + + Matthieu Ferte + mferte@club-internet.fr + + + + + Get the current memory by reading the file. + + + + + + + #include + + int currSwap; + + const char *swap_file; + swap_file = "/boot/var/swap"; + BEntry swap(swap_file); + off_t swapsize; + swap.GetSize(&swapsize); + currSwap = swapsize / 1048576; + + + + + + + + + 3 + + + Matthieu Ferte + mferte@club-internet.fr + + + + + Equation that calculates the minimum swap size is wrong (not linear). + + + + + + + I got the values on my computer with the original vm app : + Ram 256 Mb -> Swap 341 Mb + Ram 512 Mb -> Swap 640 Mb + Ram 768 Mb -> Swap 886 Mb + Ram 1024 Mb -> Swap 1133 Mb + + With obos app i got : + Ram 256 Mb -> Swap 341 Mb + Ram 512 Mb -> Swap 683 Mb + Ram 768 Mb -> Swap 1024 Mb + Ram 1024 Mb -> Swap 1365 Mb + + + + + + + + + + + + + + 10/31/2001 + Initial release. Visually complete. + + + + + + + + Even tho it wasn't really necessary, I know I've overdocumented this app. + My excuse is that I wanted to learn how to use doxygen, and this was a + good app to run it on. So if you want full documentation, and you have + doxygen installed, available from BeBits, run doxygen .doxygen-conf + in the code directory, and it will create docs for you. + + + + \ No newline at end of file diff --git a/docs/develop/virtualmemory/readme b/docs/develop/virtualmemory/readme new file mode 100644 index 0000000000..7676e211e6 --- /dev/null +++ b/docs/develop/virtualmemory/readme @@ -0,0 +1,19 @@ +Virtual Memory Preferences App +By: Matt McMinn +melfinadev@earthlink.net +http://home.earthlink.net/~melfina/ + +Introduction +It's just a copy of the virtual memory preferences app that comes with BeOS. It works. + +Documentation +Even tho it wasn't really necessary, I know I've overdocumented this app, My excuse is that I wanted to learn how to use doxygen, and this was a good app to run it on. So if you want full documentation, and you have doxygen installed, available from BeBits, run +doxygen .doxygen-conf +in the code directory, and it will create docs for you + +Version +1.0: 1/28/2002 +Hey, it works. You can set your virtual memory size just like in the actual app. + +0.9: 10/31/2001 +Initial release. Visually complete. \ No newline at end of file diff --git a/headers/os/BeBuild.h b/headers/os/BeBuild.h new file mode 100644 index 0000000000..e8efc29924 --- /dev/null +++ b/headers/os/BeBuild.h @@ -0,0 +1,547 @@ +/****************************************************************************** +/ +/ File: BeBuild.h +/ +/ Description: Import/export macros +/ +/ Copyright 1993-98, Be Incorporated +/ +*******************************************************************************/ + +#ifndef _BE_BUILD_H +#define _BE_BUILD_H + +#define B_BEOS_VERSION_4 0x0400 +#define B_BEOS_VERSION_4_5 0x0450 +#define B_BEOS_VERSION_5 0x0500 + +#define B_BEOS_VERSION B_BEOS_VERSION_5 +#define B_BEOS_VERSION_MAUI B_BEOS_VERSION_5 + +#if defined(__powerc) || defined(powerc) + #define _PR2_COMPATIBLE_ 1 + #define _PR3_COMPATIBLE_ 1 + #define _R4_COMPATIBLE_ 1 + #define _R4_5_COMPATIBLE_ 1 +#else + #define _PR2_COMPATIBLE_ 0 + #define _PR3_COMPATIBLE_ 0 + #define _R4_COMPATIBLE_ 1 + #define _R4_5_COMPATIBLE_ 1 +#endif + + +#if __MWERKS__ +#define _UNUSED(x) +#define _PACKED +#endif + +#if __GNUC__ +#define _UNUSED(x) x +#define _PACKED __attribute__((packed)) +#endif + +#if _STATIC_LINKING + +#define _EXPORT +#define _IMPORT +#define _IMPEXP_KERNEL +#define _IMPEXP_GL +#define _IMPEXP_ROOT +#define _IMPEXP_NET +#define _IMPEXP_NETDEV +#define _IMPEXP_ATALK +#define _IMPEXP_BE +#define _IMPEXP_TRACKER +#define _IMPEXP_MAIL +#define _IMPEXP_DEVICE +#define _IMPEXP_MEDIA +#define _IMPEXP_MIDI +#define _IMPEXP_MIDI2 +#define _IMPEXP_GAME +#define _IMPEXP_GSOUND +#define _IMPEXP_TRANSLATION +#define _IMPEXP_TEXTENCODING +#define _IMPEXP_INPUT + +#else + +#if __INTEL__ + +#define _EXPORT __declspec(dllexport) +#define _IMPORT __declspec(dllimport) + +#if _BUILDING_kernel +#define _IMPEXP_KERNEL __declspec(dllexport) +#else +#define _IMPEXP_KERNEL __declspec(dllimport) +#endif + +#if _BUILDING_root +#define _IMPEXP_ROOT __declspec(dllexport) +#else +#define _IMPEXP_ROOT __declspec(dllimport) +#endif + +#if _BUILDING_net +#define _IMPEXP_NET __declspec(dllexport) +#else +#define _IMPEXP_NET __declspec(dllimport) +#endif + +#if _BUILDING_netdev +#define _IMPEXP_NETDEV __declspec(dllexport) +#else +#define _IMPEXP_NETDEV __declspec(dllimport) +#endif + +#if _BUILDING_atalk +#define _IMPEXP_ATALK __declspec(dllexport) +#else +#define _IMPEXP_ATALK __declspec(dllimport) +#endif + +#if _BUILDING_be +#define _IMPEXP_BE __declspec(dllexport) +#else +#define _IMPEXP_BE __declspec(dllimport) +#endif + +#if _BUILDING_gl +#define _IMPEXP_GL __declspec(dllexport) +#else +#define _IMPEXP_GL __declspec(dllimport) +#endif + +#if _BUILDING_tracker +#define _IMPEXP_TRACKER __declspec(dllexport) +#else +#define _IMPEXP_TRACKER __declspec(dllimport) +#endif + +#if _BUILDING_mail +#define _IMPEXP_MAIL __declspec(dllexport) +#else +#define _IMPEXP_MAIL __declspec(dllimport) +#endif + +#if _BUILDING_device +#define _IMPEXP_DEVICE __declspec(dllexport) +#else +#define _IMPEXP_DEVICE __declspec(dllimport) +#endif + +#if _BUILDING_media +#define _IMPEXP_MEDIA __declspec(dllexport) +#else +#define _IMPEXP_MEDIA __declspec(dllimport) +#endif + +#if _BUILDING_midi2 +#define _IMPEXP_MIDI2 __declspec(dllexport) +#else +#define _IMPEXP_MIDI2 __declspec(dllimport) +#endif + +#if _BUILDING_midi +#define _IMPEXP_MIDI __declspec(dllexport) +#else +#define _IMPEXP_MIDI __declspec(dllimport) +#endif + +#if _BUILDING_game +#define _IMPEXP_GAME __declspec(dllexport) +#else +#define _IMPEXP_GAME __declspec(dllimport) +#endif + +#if _BUILDING_gsound +#define _IMPEXP_GSOUND __declspec(dllexport) +#else +#define _IMPEXP_GSOUND __declspec(dllimport) +#endif + +#if _BUILDING_translation +#define _IMPEXP_TRANSLATION __declspec(dllexport) +#else +#define _IMPEXP_TRANSLATION __declspec(dllimport) +#endif + +#if _BUILDING_textencoding +#define _IMPEXP_TEXTENCODING __declspec(dllexport) +#else +#define _IMPEXP_TEXTENCODING __declspec(dllimport) +#endif + +#if _BUILDING_input +#define _IMPEXP_INPUT __declspec(dllexport) +#else +#define _IMPEXP_INPUT __declspec(dllimport) +#endif + +#endif /* __INTEL__ */ + +#if __POWERPC__ + +#define _EXPORT __declspec(dllexport) +#define _IMPORT __declspec(dllimport) + +#define _IMPEXP_KERNEL +#define _IMPEXP_GL +#define _IMPEXP_ROOT +#define _IMPEXP_NET +#define _IMPEXP_NETDEV +#define _IMPEXP_ATALK +#define _IMPEXP_BE +#define _IMPEXP_TRACKER +#define _IMPEXP_MAIL +#define _IMPEXP_DEVICE +#define _IMPEXP_MEDIA +#define _IMPEXP_MIDI +#define _IMPEXP_MIDI2 +#define _IMPEXP_GAME +#define _IMPEXP_GSOUND +#define _IMPEXP_TRANSLATION +#define _IMPEXP_TEXTENCODING +#define _IMPEXP_INPUT + +#endif + +#if __SH__ + +#define _EXPORT +#define _IMPORT + +#define _IMPEXP_KERNEL +#define _IMPEXP_GL +#define _IMPEXP_ROOT +#define _IMPEXP_NET +#define _IMPEXP_NETDEV +#define _IMPEXP_ATALK +#define _IMPEXP_BE +#define _IMPEXP_TRACKER +#define _IMPEXP_MAIL +#define _IMPEXP_DEVICE +#define _IMPEXP_MEDIA +#define _IMPEXP_MIDI +#define _IMPEXP_GAME +#define _IMPEXP_GSOUND +#define _IMPEXP_TRANSLATION +#define _IMPEXP_TEXTENCODING +#define _IMPEXP_INPUT + +#endif + +#endif + + +#ifdef __cplusplus + +/* cpp kit */ + +/* -- */ +class _IMPEXP_ROOT bad_cast; +class _IMPEXP_ROOT bad_typeid; +class _IMPEXP_ROOT type_info; + +/* -- */ +class _IMPEXP_ROOT exception; +class _IMPEXP_ROOT bad_exception; + +/* -- */ +class _IMPEXP_ROOT bad_alloc; + +/* -- */ +class _IMPEXP_ROOT logic_error; +class _IMPEXP_ROOT domain_error; +class _IMPEXP_ROOT invalid_argument; +class _IMPEXP_ROOT length_error; +class _IMPEXP_ROOT out_of_range; +class _IMPEXP_ROOT runtime_error; +class _IMPEXP_ROOT range_error; +class _IMPEXP_ROOT overflow_error; + +/* support kit */ +class _IMPEXP_BE BArchivable; +class _IMPEXP_BE BAutolock; +class _IMPEXP_BE BBlockCache; +class _IMPEXP_BE BBufferIO; +class _IMPEXP_BE BDataIO; +class _IMPEXP_BE BPositionIO; +class _IMPEXP_BE BMallocIO; +class _IMPEXP_BE BMemoryIO; +class _IMPEXP_BE BFlattenable; +class _IMPEXP_BE BList; +class _IMPEXP_BE BLocker; +class _IMPEXP_BE BStopWatch; +class _IMPEXP_BE BString; + +class _IMPEXP_BE PointerList; + +/*storage kit */ +struct _IMPEXP_BE entry_ref; +struct _IMPEXP_BE node_ref; +class _IMPEXP_BE BAppFileInfo; +class _IMPEXP_BE BDirectory; +class _IMPEXP_BE BEntry; +class _IMPEXP_BE BFile; +class _IMPEXP_BE BRefFilter; +class _IMPEXP_BE BMimeType; +class _IMPEXP_BE BNode; +class _IMPEXP_BE BNodeInfo; +class _IMPEXP_BE BPath; +class _IMPEXP_BE BQuery; +class _IMPEXP_BE BResources; +class _IMPEXP_BE BResourceStrings; +class _IMPEXP_BE BStatable; +class _IMPEXP_BE BSymLink; +class _IMPEXP_BE BVolume; +class _IMPEXP_BE BVolumeRoster; + +class _IMPEXP_BE Partition; +class _IMPEXP_BE Session; +class _IMPEXP_BE Device; +class _IMPEXP_BE DeviceList; +class _IMPEXP_BE TNodeWalker; +class _IMPEXP_BE TQueryWalker; +class _IMPEXP_BE TVolWalker; + +/*app kit */ +struct _IMPEXP_BE app_info; +class _IMPEXP_BE BApplication; +class _IMPEXP_BE BClipboard; +class _IMPEXP_BE BHandler; +class _IMPEXP_BE BInvoker; +class _IMPEXP_BE BLooper; +class _IMPEXP_BE BMessage; +class _IMPEXP_BE BMessageFilter; +class _IMPEXP_BE BMessageQueue; +class _IMPEXP_BE BMessageRunner; +class _IMPEXP_BE BMessenger; +class _IMPEXP_BE BPropertyInfo; +class _IMPEXP_BE BRoster; + +class _IMPEXP_BE _BAppServerLink_; +class _IMPEXP_BE _BSession_; + +/*interface kit */ +class _IMPEXP_BE BAlert; +class _IMPEXP_BE BBitmap; +class _IMPEXP_BE BBox; +class _IMPEXP_BE BButton; +class _IMPEXP_BE BChannelControl; +class _IMPEXP_BE BChannelSlider; +class _IMPEXP_BE BCheckBox; +class _IMPEXP_BE BColorControl; +class _IMPEXP_BE BControl; +class _IMPEXP_BE BDeskbar; +class _IMPEXP_BE BDragger; +class _IMPEXP_BE BFont; +class _IMPEXP_BE BInputDevice; +class _IMPEXP_BE BListItem; +class _IMPEXP_BE BListView; +class _IMPEXP_BE BStringItem; +class _IMPEXP_BE BMenu; +class _IMPEXP_BE BMenuBar; +class _IMPEXP_BE BMenuField; +class _IMPEXP_BE BMenuItem; +class _IMPEXP_BE BOptionControl; +class _IMPEXP_BE BOptionPopUp; +class _IMPEXP_BE BOutlineListView; +class _IMPEXP_BE BPicture; +class _IMPEXP_BE BPictureButton; +class _IMPEXP_BE BPoint; +class _IMPEXP_BE BPolygon; +class _IMPEXP_BE BPopUpMenu; +class _IMPEXP_BE BPrintJob; +class _IMPEXP_BE BRadioButton; +class _IMPEXP_BE BRect; +class _IMPEXP_BE BRegion; +class _IMPEXP_BE BScreen; +class _IMPEXP_BE BScrollBar; +class _IMPEXP_BE BScrollView; +class _IMPEXP_BE BSeparatorItem; +class _IMPEXP_BE BShelf; +class _IMPEXP_BE BShape; +class _IMPEXP_BE BShapeIterator; +class _IMPEXP_BE BSlider; +class _IMPEXP_BE BStatusBar; +class _IMPEXP_BE BStringView; +class _IMPEXP_BE BTab; +class _IMPEXP_BE BTabView; +class _IMPEXP_BE BTextControl; +class _IMPEXP_BE BTextView; +class _IMPEXP_BE BView; +class _IMPEXP_BE BWindow; + +class _IMPEXP_BE _BTextInput_; +class _IMPEXP_BE _BMCMenuBar_; +class _IMPEXP_BE _BMCItem_; +class _IMPEXP_BE _BWidthBuffer_; +class _IMPEXP_BE BPrivateScreen; + +/* net kit */ +class _IMPEXP_NET _Allocator; +class _IMPEXP_NET _Transacter; +class _IMPEXP_NET _FastIPC; + +/* netdev kit */ +class _IMPEXP_NETDEV BNetPacket; +class _IMPEXP_NETDEV BStandardPacket; +class _IMPEXP_NETDEV BTimeoutHandler; +class _IMPEXP_NETDEV BPacketHandler; +class _IMPEXP_NETDEV BNetProtocol; +class _IMPEXP_NETDEV BNetDevice; +class _IMPEXP_NETDEV BCallBackHandler; +class _IMPEXP_NETDEV BNetConfig; +class _IMPEXP_NETDEV BIpDevice; + +class _IMPEXP_NETDEV _NetBufList; +class _IMPEXP_NETDEV _BSem; + +/* atalk kit */ +class _IMPEXP_ATALK _PrinterNode; + +/* tracker kit */ +class _IMPEXP_TRACKER BFilePanel; +class _IMPEXP_TRACKER BRecentItemsList; +class _IMPEXP_TRACKER BRecentFilesList; +class _IMPEXP_TRACKER BRecentFoldersList; +class _IMPEXP_TRACKER BRecentAppsList; + +/* mail kit */ +class _IMPEXP_MAIL BMailMessage; + +/* device kit */ +class _IMPEXP_DEVICE BA2D; +class _IMPEXP_DEVICE BD2A; +class _IMPEXP_DEVICE BDigitalPort; +class _IMPEXP_DEVICE BJoystick; +class _IMPEXP_DEVICE BSerialPort; + +/* media kit */ +class _IMPEXP_MEDIA BDACRenderer; +class _IMPEXP_MEDIA BAudioFileStream; +class _IMPEXP_MEDIA BADCStream; +class _IMPEXP_MEDIA BDACStream; +class _IMPEXP_MEDIA BAbstractBufferStream; +class _IMPEXP_MEDIA BBufferStreamManager; +class _IMPEXP_MEDIA BBufferStream; +class _IMPEXP_MEDIA BSoundFile; +class _IMPEXP_MEDIA BSubscriber; + +class _IMPEXP_MEDIA BMediaRoster; +class _IMPEXP_MEDIA BMediaNode; +class _IMPEXP_MEDIA BTimeSource; +class _IMPEXP_MEDIA BBufferProducer; +class _IMPEXP_MEDIA BBufferConsumer; +class _IMPEXP_MEDIA BBuffer; +class _IMPEXP_MEDIA BBufferGroup; +class _IMPEXP_MEDIA BControllable; +class _IMPEXP_MEDIA BFileInterface; +class _IMPEXP_MEDIA BEntityInterface; +class _IMPEXP_MEDIA BMediaAddOn; +class _IMPEXP_MEDIA BMediaTheme; +class _IMPEXP_MEDIA BParameterWeb; +class _IMPEXP_MEDIA BParameterGroup; +class _IMPEXP_MEDIA BParameter; +class _IMPEXP_MEDIA BNullParameter; +class _IMPEXP_MEDIA BDiscreteParameter; +class _IMPEXP_MEDIA BContinuousParameter; +class _IMPEXP_MEDIA BMediaFiles; +class _IMPEXP_MEDIA BSound; +class _IMPEXP_MEDIA BSoundCard; +class _IMPEXP_MEDIA BSoundPlayer; +class _IMPEXP_MEDIA BMediaFormats; +class _IMPEXP_MEDIA BTimedEventQueue; +//class _IMPEXP_MEDIA BEventIterator; +class _IMPEXP_MEDIA BMediaEventLooper; +class _IMPEXP_MEDIA BMediaFile; +class _IMPEXP_MEDIA BMediaTrack; + +class _IMPEXP_MEDIA media_node; +struct _IMPEXP_MEDIA media_input; +struct _IMPEXP_MEDIA media_output; +struct _IMPEXP_MEDIA live_node_info; +struct _IMPEXP_MEDIA buffer_clone_info; +struct _IMPEXP_MEDIA media_source; +struct _IMPEXP_MEDIA media_destination; +struct _IMPEXP_MEDIA media_raw_audio_format; +struct _IMPEXP_MEDIA media_raw_video_format; +struct _IMPEXP_MEDIA media_video_display_info; +struct _IMPEXP_MEDIA flavor_info; +struct _IMPEXP_MEDIA dormant_node_info; +struct _IMPEXP_MEDIA dormant_flavor_info; +struct _IMPEXP_MEDIA media_source; +struct _IMPEXP_MEDIA media_destination; +struct _IMPEXP_MEDIA _media_format_description; +struct _IMPEXP_MEDIA media_timed_event; + +/* midi kit */ +class _IMPEXP_MIDI BMidi; +class _IMPEXP_MIDI BMidiPort; +class _IMPEXP_MIDI BMidiStore; +class _IMPEXP_MIDI BMidiSynth; +class _IMPEXP_MIDI BMidiSynthFile; +class _IMPEXP_MIDI BMidiText; +class _IMPEXP_MIDI BSamples; +class _IMPEXP_MIDI BSynth; + +class _IMPEXP_MIDI2 BMidiEndpoint; +class _IMPEXP_MIDI2 BMidiProducer; +class _IMPEXP_MIDI2 BMidiConsumer; +class _IMPEXP_MIDI2 BMidiLocalProducer; +class _IMPEXP_MIDI2 BMidiLocalConsumer; +class _IMPEXP_MIDI2 BMidiRoster; + +/* game kit */ +class _IMPEXP_GAME BWindowScreen; +class _IMPEXP_GAME BDirectWindow; + +/* gamesound kit */ +class _IMPEXP_GSOUND BGameSound; +class _IMPEXP_GSOUND BSimpleGameSound; +class _IMPEXP_GSOUND BStreamingGameSound; +class _IMPEXP_GSOUND BFileGameSound; +class _IMPEXP_GSOUND BPushGameSound; + +/* translation kit */ +class _IMPEXP_TRANSLATION BTranslatorRoster; +class _IMPEXP_TRANSLATION BTranslationUtils; +class _IMPEXP_TRANSLATION BBitmapStream; +class _IMPEXP_TRANSLATION BTranslator; +struct _IMPEXP_TRANSLATION translation_format; +struct _IMPEXP_TRANSLATION translator_info; + +/* GL */ +class _IMPEXP_GL BGLView; +class _IMPEXP_GL BGLScreen; +#ifdef __cplusplus +class _IMPEXP_GL GLUnurbs; +class _IMPEXP_GL GLUquadric; +class _IMPEXP_GL GLUtesselator; + +typedef class _IMPEXP_GL GLUnurbs GLUnurbsObj; +typedef class _IMPEXP_GL GLUquadric GLUquadricObj; +typedef class _IMPEXP_GL GLUtesselator GLUtesselatorObj; +typedef class _IMPEXP_GL GLUtesselator GLUtriangulatorObj; + +#else +typedef struct _IMPEXP_GL GLUnurbs GLUnurbs; +typedef struct _IMPEXP_GL GLUquadric GLUquadric; +typedef struct _IMPEXP_GL GLUtesselator GLUtesselator; + +typedef struct _IMPEXP_GL GLUnurbs GLUnurbsObj; +typedef struct _IMPEXP_GL GLUquadric GLUquadricObj; +typedef struct _IMPEXP_GL GLUtesselator GLUtesselatorObj; +typedef struct _IMPEXP_GL GLUtesselator GLUtriangulatorObj; +#endif + +/* input_server */ +class _IMPEXP_INPUT BInputServerDevice; +class _IMPEXP_INPUT BInputServerFilter; +class _IMPEXP_INPUT BInputServerMethod; + +#endif /* __cplusplus */ + +#endif diff --git a/headers/os/add-ons/file_system/fsproto.h b/headers/os/add-ons/file_system/fsproto.h new file mode 100644 index 0000000000..465371f1b3 --- /dev/null +++ b/headers/os/add-ons/file_system/fsproto.h @@ -0,0 +1,246 @@ +/* + Copyright 1999-2001, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. +*/ + +#ifndef _FSPROTO_H +#define _FSPROTO_H + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +typedef dev_t nspace_id; +typedef ino_t vnode_id; + +/* + * PUBLIC PART OF THE FILE SYSTEM PROTOCOL + */ + +#define WSTAT_MODE 0x0001 +#define WSTAT_UID 0x0002 +#define WSTAT_GID 0x0004 +#define WSTAT_SIZE 0x0008 +#define WSTAT_ATIME 0x0010 +#define WSTAT_MTIME 0x0020 +#define WSTAT_CRTIME 0x0040 + +#define WFSSTAT_NAME 0x0001 + +#define B_ENTRY_CREATED 1 +#define B_ENTRY_REMOVED 2 +#define B_ENTRY_MOVED 3 +#define B_STAT_CHANGED 4 +#define B_ATTR_CHANGED 5 +#define B_DEVICE_MOUNTED 6 +#define B_DEVICE_UNMOUNTED 7 + +#define B_STOP_WATCHING 0x0000 +#define B_WATCH_NAME 0x0001 +#define B_WATCH_STAT 0x0002 +#define B_WATCH_ATTR 0x0004 +#define B_WATCH_DIRECTORY 0x0008 + +#define SELECT_READ 1 +#define SELECT_WRITE 2 +#define SELECT_EXCEPTION 3 + +#define B_CUR_FS_API_VERSION 2 + +struct attr_info; +struct index_info; + +typedef int op_read_vnode(void *ns, vnode_id vnid, char r, void **node); +typedef int op_write_vnode(void *ns, void *node, char r); +typedef int op_remove_vnode(void *ns, void *node, char r); +typedef int op_secure_vnode(void *ns, void *node); + +typedef int op_walk(void *ns, void *base, const char *file, char **newpath, + vnode_id *vnid); + +typedef int op_access(void *ns, void *node, int mode); + +typedef int op_create(void *ns, void *dir, const char *name, + int omode, int perms, vnode_id *vnid, void **cookie); +typedef int op_mkdir(void *ns, void *dir, const char *name, int perms); +typedef int op_symlink(void *ns, void *dir, const char *name, + const char *path); +typedef int op_link(void *ns, void *dir, const char *name, void *node); + +typedef int op_rename(void *ns, void *olddir, const char *oldname, + void *newdir, const char *newname); +typedef int op_unlink(void *ns, void *dir, const char *name); +typedef int op_rmdir(void *ns, void *dir, const char *name); + +typedef int op_readlink(void *ns, void *node, char *buf, size_t *bufsize); + +typedef int op_opendir(void *ns, void *node, void **cookie); +typedef int op_closedir(void *ns, void *node, void *cookie); +typedef int op_rewinddir(void *ns, void *node, void *cookie); +typedef int op_readdir(void *ns, void *node, void *cookie, long *num, + struct dirent *buf, size_t bufsize); + +typedef int op_open(void *ns, void *node, int omode, void **cookie); +typedef int op_close(void *ns, void *node, void *cookie); +typedef int op_free_cookie(void *ns, void *node, void *cookie); +typedef int op_read(void *ns, void *node, void *cookie, off_t pos, void *buf, + size_t *len); +typedef int op_write(void *ns, void *node, void *cookie, off_t pos, + const void *buf, size_t *len); +typedef int op_readv(void *ns, void *node, void *cookie, off_t pos, const iovec *vec, + size_t count, size_t *len); +typedef int op_writev(void *ns, void *node, void *cookie, off_t pos, const iovec *vec, + size_t count, size_t *len); +typedef int op_ioctl(void *ns, void *node, void *cookie, int cmd, void *buf, + size_t len); +typedef int op_setflags(void *ns, void *node, void *cookie, int flags); + +typedef int op_rstat(void *ns, void *node, struct stat *); +typedef int op_wstat(void *ns, void *node, struct stat *, long mask); +typedef int op_fsync(void *ns, void *node); + +typedef int op_select(void *ns, void *node, void *cookie, uint8 event, + uint32 ref, selectsync *sync); +typedef int op_deselect(void *ns, void *node, void *cookie, uint8 event, + selectsync *sync); + +typedef int op_initialize(const char *devname, void *parms, size_t len); +typedef int op_mount(nspace_id nsid, const char *devname, ulong flags, + void *parms, size_t len, void **data, vnode_id *vnid); +typedef int op_unmount(void *ns); +typedef int op_sync(void *ns); +typedef int op_rfsstat(void *ns, struct fs_info *); +typedef int op_wfsstat(void *ns, struct fs_info *, long mask); + + +typedef int op_open_attrdir(void *ns, void *node, void **cookie); +typedef int op_close_attrdir(void *ns, void *node, void *cookie); +typedef int op_rewind_attrdir(void *ns, void *node, void *cookie); +typedef int op_read_attrdir(void *ns, void *node, void *cookie, long *num, + struct dirent *buf, size_t bufsize); +typedef int op_remove_attr(void *ns, void *node, const char *name); +typedef int op_rename_attr(void *ns, void *node, const char *oldname, + const char *newname); +typedef int op_stat_attr(void *ns, void *node, const char *name, + struct attr_info *buf); + +typedef int op_write_attr(void *ns, void *node, const char *name, int type, + const void *buf, size_t *len, off_t pos); +typedef int op_read_attr(void *ns, void *node, const char *name, int type, + void *buf, size_t *len, off_t pos); + +typedef int op_open_indexdir(void *ns, void **cookie); +typedef int op_close_indexdir(void *ns, void *cookie); +typedef int op_rewind_indexdir(void *ns, void *cookie); +typedef int op_read_indexdir(void *ns, void *cookie, long *num, + struct dirent *buf, size_t bufsize); +typedef int op_create_index(void *ns, const char *name, int type, int flags); +typedef int op_remove_index(void *ns, const char *name); +typedef int op_rename_index(void *ns, const char *oldname, + const char *newname); +typedef int op_stat_index(void *ns, const char *name, struct index_info *buf); + +typedef int op_open_query(void *ns, const char *query, ulong flags, + port_id port, long token, void **cookie); +typedef int op_close_query(void *ns, void *cookie); +typedef int op_read_query(void *ns, void *cookie, long *num, + struct dirent *buf, size_t bufsize); + +typedef struct vnode_ops { + op_read_vnode (*read_vnode); + op_write_vnode (*write_vnode); + op_remove_vnode (*remove_vnode); + op_secure_vnode (*secure_vnode); + op_walk (*walk); + op_access (*access); + op_create (*create); + op_mkdir (*mkdir); + op_symlink (*symlink); + op_link (*link); + op_rename (*rename); + op_unlink (*unlink); + op_rmdir (*rmdir); + op_readlink (*readlink); + op_opendir (*opendir); + op_closedir (*closedir); + op_free_cookie (*free_dircookie); + op_rewinddir (*rewinddir); + op_readdir (*readdir); + op_open (*open); + op_close (*close); + op_free_cookie (*free_cookie); + op_read (*read); + op_write (*write); + op_readv (*readv); + op_writev (*writev); + op_ioctl (*ioctl); + op_setflags (*setflags); + op_rstat (*rstat); + op_wstat (*wstat); + op_fsync (*fsync); + op_initialize (*initialize); + op_mount (*mount); + op_unmount (*unmount); + op_sync (*sync); + op_rfsstat (*rfsstat); + op_wfsstat (*wfsstat); + op_select (*select); + op_deselect (*deselect); + op_open_indexdir (*open_indexdir); + op_close_indexdir (*close_indexdir); + op_free_cookie (*free_indexdircookie); + op_rewind_indexdir (*rewind_indexdir); + op_read_indexdir (*read_indexdir); + op_create_index (*create_index); + op_remove_index (*remove_index); + op_rename_index (*rename_index); + op_stat_index (*stat_index); + op_open_attrdir (*open_attrdir); + op_close_attrdir (*close_attrdir); + op_free_cookie (*free_attrdircookie); + op_rewind_attrdir (*rewind_attrdir); + op_read_attrdir (*read_attrdir); + op_write_attr (*write_attr); + op_read_attr (*read_attr); + op_remove_attr (*remove_attr); + op_rename_attr (*rename_attr); + op_stat_attr (*stat_attr); + op_open_query (*open_query); + op_close_query (*close_query); + op_free_cookie (*free_querycookie); + op_read_query (*read_query); +} vnode_ops; + +extern _IMPEXP_KERNEL int new_path(const char *path, char **copy); +extern _IMPEXP_KERNEL void free_path(char *p); + +extern _IMPEXP_KERNEL int notify_listener(int op, nspace_id nsid, + vnode_id vnida, vnode_id vnidb, + vnode_id vnidc, const char *name); +extern _IMPEXP_KERNEL void notify_select_event(selectsync *sync, uint32 ref); +extern _IMPEXP_KERNEL int send_notification(port_id port, long token, + ulong what, long op, nspace_id nsida, + nspace_id nsidb, vnode_id vnida, + vnode_id vnidb, vnode_id vnidc, + const char *name); +extern _IMPEXP_KERNEL int get_vnode(nspace_id nsid, vnode_id vnid, void **data); +extern _IMPEXP_KERNEL int put_vnode(nspace_id nsid, vnode_id vnid); +extern _IMPEXP_KERNEL int new_vnode(nspace_id nsid, vnode_id vnid, void *data); +extern _IMPEXP_KERNEL int remove_vnode(nspace_id nsid, vnode_id vnid); +extern _IMPEXP_KERNEL int unremove_vnode(nspace_id nsid, vnode_id vnid); +extern _IMPEXP_KERNEL int is_vnode_removed(nspace_id nsid, vnode_id vnid); + + +extern _EXPORT vnode_ops fs_entry; +extern _EXPORT int32 api_version; + +#endif diff --git a/headers/os/add-ons/input_server/InputServerDevice.h b/headers/os/add-ons/input_server/InputServerDevice.h new file mode 100644 index 0000000000..fdf9201de1 --- /dev/null +++ b/headers/os/add-ons/input_server/InputServerDevice.h @@ -0,0 +1,79 @@ +/****************************************************************************** +/ +/ File: InputServerDevice.h +/ +/ Description: Add-on class for input_server devices. +/ +/ Copyright 1998, Be Incorporated, All Rights Reserved. +/ +******************************************************************************/ + +#ifndef _INPUTSERVERDEVICE_H +#define _INPUTSERVERDEVICE_H + +#include +#include +#include + + +struct input_device_ref { + char *name; + input_device_type type; + void *cookie; +}; + + +enum { + // B_KEYBOARD_DEVICE notifications + B_KEY_MAP_CHANGED = 1, + B_KEY_LOCKS_CHANGED, + B_KEY_REPEAT_DELAY_CHANGED, + B_KEY_REPEAT_RATE_CHANGED, + + // B_POINTING_DEVICE notifications + B_MOUSE_TYPE_CHANGED, + B_MOUSE_MAP_CHANGED, + B_MOUSE_SPEED_CHANGED, + B_CLICK_SPEED_CHANGED, + B_MOUSE_ACCELERATION_CHANGED +}; + + +class _BDeviceAddOn_; + + +class BInputServerDevice { +public: + BInputServerDevice(); + virtual ~BInputServerDevice(); + + virtual status_t InitCheck(); + virtual status_t SystemShuttingDown(); + + virtual status_t Start(const char *device, void *cookie); + virtual status_t Stop(const char *device, void *cookie); + virtual status_t Control(const char *device, + void *cookie, + uint32 code, + BMessage *message); + + status_t RegisterDevices(input_device_ref **devices); + status_t UnregisterDevices(input_device_ref **devices); + + status_t EnqueueMessage(BMessage *message); + + status_t StartMonitoringDevice(const char *device); + status_t StopMonitoringDevice(const char *device); + +private: + _BDeviceAddOn_* fOwner; + + virtual void _ReservedInputServerDevice1(); + virtual void _ReservedInputServerDevice2(); + virtual void _ReservedInputServerDevice3(); + virtual void _ReservedInputServerDevice4(); + uint32 _reserved[4]; +}; + + +#endif diff --git a/headers/os/add-ons/input_server/InputServerFilter.h b/headers/os/add-ons/input_server/InputServerFilter.h new file mode 100644 index 0000000000..28e37f4133 --- /dev/null +++ b/headers/os/add-ons/input_server/InputServerFilter.h @@ -0,0 +1,39 @@ +/****************************************************************************** +/ +/ File: InputServerFilter.h +/ +/ Description: Add-on class for input_server filters. +/ +/ Copyright 1998, Be Incorporated, All Rights Reserved. +/ +*******************************************************************************/ + +#ifndef _INPUTSERVERFILTER_H +#define _INPUTSERVERFILTER_H + +#include +#include +#include + + +class BInputServerFilter { +public: + BInputServerFilter(); + virtual ~BInputServerFilter(); + + virtual status_t InitCheck(); + + virtual filter_result Filter(BMessage *message, BList *outList); + + status_t GetScreenRegion(BRegion *region) const; + +private: + virtual void _ReservedInputServerFilter1(); + virtual void _ReservedInputServerFilter2(); + virtual void _ReservedInputServerFilter3(); + virtual void _ReservedInputServerFilter4(); + uint32 _reserved[4]; +}; + + +#endif diff --git a/headers/os/add-ons/input_server/InputServerMethod.h b/headers/os/add-ons/input_server/InputServerMethod.h new file mode 100644 index 0000000000..9678626421 --- /dev/null +++ b/headers/os/add-ons/input_server/InputServerMethod.h @@ -0,0 +1,47 @@ +/****************************************************************************** +/ +/ File: InputServerMethod.h +/ +/ Description: Add-on class for input_server methods. +/ +/ Copyright 1998, Be Incorporated, All Rights Reserved. +/ +/******************************************************************************/ + +#ifndef _INPUTSERVERMETHOD_H +#define _INPUTSERVERMETHOD_H + +#include +#include +#include + + +class _BMethodAddOn_; + + +class BInputServerMethod : public BInputServerFilter { +public: + BInputServerMethod(const char *name, + const uchar *icon); + virtual ~BInputServerMethod(); + + virtual status_t MethodActivated(bool active); + + status_t EnqueueMessage(BMessage *message); + + status_t SetName(const char *name); + status_t SetIcon(const uchar *icon); + status_t SetMenu(const BMenu *menu, const BMessenger target); + +private: + _BMethodAddOn_* fOwner; + + virtual void _ReservedInputServerMethod1(); + virtual void _ReservedInputServerMethod2(); + virtual void _ReservedInputServerMethod3(); + virtual void _ReservedInputServerMethod4(); + uint32 _reserved[4]; +}; + + +#endif diff --git a/headers/os/app/AppDefs.h b/headers/os/app/AppDefs.h new file mode 100644 index 0000000000..a2e04a5534 --- /dev/null +++ b/headers/os/app/AppDefs.h @@ -0,0 +1,167 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: AppDefs.h +// Author: Erik Jaesler (erik@cgsoftware.com) +// Description: Message codes and the global cursors. +//------------------------------------------------------------------------------ + +#ifndef _APP_DEFS_H +#define _APP_DEFS_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + + +// Global Cursors -------------------------------------------------------------- + +// Old-style cursors +extern const unsigned char B_HAND_CURSOR[]; +extern const unsigned char B_I_BEAM_CURSOR[]; + +// New-style cursors +#ifdef __cplusplus +class BCursor; +extern const BCursor *B_CURSOR_SYSTEM_DEFAULT; +extern const BCursor *B_CURSOR_I_BEAM; +#endif + +// System Message Codes -------------------------------------------------------- + +enum { + B_ABOUT_REQUESTED = '_ABR', + B_WINDOW_ACTIVATED = '_ACT', + B_APP_ACTIVATED = '_ACT', // Same as B_WINDOW_ACTIVATED + B_ARGV_RECEIVED = '_ARG', + B_QUIT_REQUESTED = '_QRQ', + B_CLOSE_REQUESTED = '_QRQ', // Obsolete; use B_QUIT_REQUESTED + B_CANCEL = '_CNC', + B_KEY_DOWN = '_KYD', + B_KEY_UP = '_KYU', + B_UNMAPPED_KEY_DOWN = '_UKD', + B_UNMAPPED_KEY_UP = '_UKU', + B_MODIFIERS_CHANGED = '_MCH', + B_MINIMIZE = '_WMN', + B_MOUSE_DOWN = '_MDN', + B_MOUSE_MOVED = '_MMV', + B_MOUSE_ENTER_EXIT = '_MEX', + B_MOUSE_UP = '_MUP', + B_MOUSE_WHEEL_CHANGED = '_MWC', + B_OPEN_IN_WORKSPACE = '_OWS', + B_PRINTER_CHANGED = '_PCH', + B_PULSE = '_PUL', + B_READY_TO_RUN = '_RTR', + B_REFS_RECEIVED = '_RRC', + B_RELEASE_OVERLAY_LOCK = '_ROV', + B_ACQUIRE_OVERLAY_LOCK = '_AOV', + B_SCREEN_CHANGED = '_SCH', + B_VALUE_CHANGED = '_VCH', + B_VIEW_MOVED = '_VMV', + B_VIEW_RESIZED = '_VRS', + B_WINDOW_MOVED = '_WMV', + B_WINDOW_RESIZED = '_WRS', + B_WORKSPACES_CHANGED = '_WCG', + B_WORKSPACE_ACTIVATED = '_WAC', + B_ZOOM = '_WZM', + _APP_MENU_ = '_AMN', + _BROWSER_MENUS_ = '_BRM', + _MENU_EVENT_ = '_MEV', + _PING_ = '_PBL', + _QUIT_ = '_QIT', + _VOLUME_MOUNTED_ = '_NVL', + _VOLUME_UNMOUNTED_ = '_VRM', + _MESSAGE_DROPPED_ = '_MDP', + _DISPOSE_DRAG_ = '_DPD', + _MENUS_DONE_ = '_MND', + _SHOW_DRAG_HANDLES_ = '_SDH', + _EVENTS_PENDING_ = '_EVP', + _UPDATE_ = '_UPD', + _UPDATE_IF_NEEDED_ = '_UPN', + _PRINTER_INFO_ = '_PIN', + _SETUP_PRINTER_ = '_SUP', + _SELECT_PRINTER_ = '_PSL' + // Media Kit reserves all reserved codes starting in '_TR' +}; + + +// Other Commands -------------------------------------------------------------- + +enum { + B_SET_PROPERTY = 'PSET', + B_GET_PROPERTY = 'PGET', + B_CREATE_PROPERTY = 'PCRT', + B_DELETE_PROPERTY = 'PDEL', + B_COUNT_PROPERTIES = 'PCNT', + B_EXECUTE_PROPERTY = 'PEXE', + B_GET_SUPPORTED_SUITES = 'SUIT', + B_UNDO = 'UNDO', + B_CUT = 'CCUT', + B_COPY = 'COPY', + B_PASTE = 'PSTE', + B_SELECT_ALL = 'SALL', + B_SAVE_REQUESTED = 'SAVE', + B_MESSAGE_NOT_UNDERSTOOD = 'MNOT', + B_NO_REPLY = 'NONE', + B_REPLY = 'RPLY', + B_SIMPLE_DATA = 'DATA', + B_MIME_DATA = 'MIME', + B_ARCHIVED_OBJECT = 'ARCV', + B_UPDATE_STATUS_BAR = 'SBUP', + B_RESET_STATUS_BAR = 'SBRS', + B_NODE_MONITOR = 'NDMN', + B_QUERY_UPDATE = 'QUPD', + B_ENDORSABLE = 'ENDO', + B_COPY_TARGET = 'DDCP', + B_MOVE_TARGET = 'DDMV', + B_TRASH_TARGET = 'DDRM', + B_LINK_TARGET = 'DDLN', + B_INPUT_DEVICES_CHANGED = 'IDCH', + B_INPUT_METHOD_EVENT = 'IMEV', + B_WINDOW_MOVE_TO = 'WDMT', + B_WINDOW_MOVE_BY = 'WDMB', + B_SILENT_RELAUNCH = 'AREL', + B_OBSERVER_NOTICE_CHANGE = 'NTCH', + B_CONTROL_INVOKED = 'CIVK', + B_CONTROL_MODIFIED = 'CMOD' + + // Media Kit reserves all reserved codes starting in 'TRI' +}; +//------------------------------------------------------------------------------ + +#endif // _APP_DEFS_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/headers/os/app/Application.h b/headers/os/app/Application.h new file mode 100644 index 0000000000..2eca5270a2 --- /dev/null +++ b/headers/os/app/Application.h @@ -0,0 +1,223 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: Application.h +// Author: Erik Jaesler (erik@cgsoftware.com) +// Description: BApplication class is the center of the application +// universe. The global be_app and be_app_messenger +// variables are defined here as well. +//------------------------------------------------------------------------------ + +#ifndef _APPLICATION_H +#define _APPLICATION_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include +#include // For convenience +#include +#include +#include +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +class BCursor; +class BList; +class BWindow; +class _BSession_; +class BResources; +class BMessageRunner; +struct _server_heap_; +struct _drag_data_; + +// BApplication class ---------------------------------------------------------- +class BApplication : public BLooper { + +public: + BApplication(const char* signature); + BApplication(const char* signature, + status_t* error); + virtual ~BApplication(); + + // Archiving + BApplication(BMessage* data); + static BArchivable* Instantiate(BMessage* data); + virtual status_t Archive(BMessage* data, bool deep = true) const; + + status_t InitCheck() const; + + // App control and System Message handling + virtual thread_id Run(); + virtual void Quit(); + virtual bool QuitRequested(); + virtual void Pulse(); + virtual void ReadyToRun(); + virtual void MessageReceived(BMessage* msg); + virtual void ArgvReceived(int32 argc, char** argv); + virtual void AppActivated(bool active); + virtual void RefsReceived(BMessage* a_message); + virtual void AboutRequested(); + + // Scripting + virtual BHandler* ResolveSpecifier(BMessage* msg, + int32 index, + BMessage* specifier, + int32 form, + const char* property); + + // Cursor control, window/looper list, and app info + void ShowCursor(); + void HideCursor(); + void ObscureCursor(); + bool IsCursorHidden() const; + void SetCursor(const void* cursor); + void SetCursor(const BCursor* cursor, bool sync = true); + int32 CountWindows() const; + BWindow* WindowAt(int32 index) const; + int32 CountLoopers() const; + BLooper* LooperAt(int32 index) const; + bool IsLaunching() const; + status_t GetAppInfo(app_info* info) const; + static BResources* AppResources(); + + virtual void DispatchMessage(BMessage* an_event, + BHandler* handler); + void SetPulseRate(bigtime_t rate); + + // More scripting + virtual status_t GetSupportedSuites(BMessage* data); + + +// Private or reserved --------------------------------------------------------- + virtual status_t Perform(perform_code d, void* arg); + +private: + + typedef BLooper _inherited; + + friend class BWindow; + friend class BView; + friend class BBitmap; + friend class BScrollBar; + friend class BPrivateScreen; + friend class _BAppServerLink_; + friend void _toggle_handles_(bool); + + BApplication(uint32 signature); + BApplication(const BApplication&); + BApplication& operator=(const BApplication&); + + virtual void _ReservedApplication1(); + virtual void _ReservedApplication2(); + virtual void _ReservedApplication3(); + virtual void _ReservedApplication4(); + virtual void _ReservedApplication5(); + virtual void _ReservedApplication6(); + virtual void _ReservedApplication7(); + virtual void _ReservedApplication8(); + + virtual bool ScriptReceived(BMessage* msg, + int32 index, + BMessage* specifier, + int32 form, + const char* property); + void run_task(); + void InitData(const char* signature, status_t* error); + void BeginRectTracking(BRect r, bool trackWhole); + void EndRectTracking(); + void get_scs(); + void setup_server_heaps(); + void* rw_offs_to_ptr(uint32 offset); + void* ro_offs_to_ptr(uint32 offset); + void* global_ro_offs_to_ptr(uint32 offset); + void connect_to_app_server(); + void send_drag( BMessage* msg, + int32 vs_token, + BPoint offset, + BRect drag_rect, + BHandler* reply_to); + void send_drag( BMessage* msg, + int32 vs_token, + BPoint offset, + int32 bitmap_token, + drawing_mode dragMode, + BHandler* reply_to); + void write_drag(_BSession_* session, BMessage* a_message); + bool quit_all_windows(bool force); + bool window_quit_loop(bool, bool); + void do_argv(BMessage* msg); +#ifndef FIX_FOR_4_6 + void SetAppCursor(); +#endif + uint32 InitialWorkspace(); + int32 count_windows(bool incl_menus) const; + BWindow* window_at(uint32 index, bool incl_menus) const; + status_t get_window_list(BList* list, bool incl_menus) const; + static int32 async_quit_entry(void*); + static BResources* _app_resources; + static BLocker _app_resources_lock; + + const char* fAppName; + int32 fServerFrom; + int32 fServerTo; +#ifndef FIX_FOR_4_6 + void* fCursorData; +#else + void* _unused1; +#endif + _server_heap_* fServerHeap; + bigtime_t fPulseRate; + uint32 fInitialWorkspace; + _drag_data_* fDraggedMessage; + BMessageRunner* fPulseRunner; + status_t fInitError; + uint32 _reserved[11]; + + bool fReadyToRunCalled; +}; +//------------------------------------------------------------------------------ + + +// Global Objects -------------------------------------------------------------- + +extern _IMPEXP_BE BApplication* be_app; +extern _IMPEXP_BE BMessenger be_app_messenger; + +//------------------------------------------------------------------------------ + +#endif // _APPLICATION_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/headers/os/app/Clipboard.h b/headers/os/app/Clipboard.h new file mode 100644 index 0000000000..35e343db78 --- /dev/null +++ b/headers/os/app/Clipboard.h @@ -0,0 +1,82 @@ +/****************************************************************************** +/ +/ File: Clipboard.h +/ +/ Description: BClipboard class defines clipboard functionality. +/ The global be_clipboard represents the default clipboard. +/ +/ Copyright 1995-98, Be Incorporated, All Rights Reserved. +/ +*******************************************************************************/ + +#ifndef _CLIPBOARD_H +#define _CLIPBOARD_H + +#include +#include +#include + +class BMessage; + +enum { + B_CLIPBOARD_CHANGED = 'CLCH' +}; + +/*------------------------------------------------------------------*/ +/*----- BClipboard class --------------------------------------------*/ + +class BClipboard { +public: + BClipboard(const char *name, bool transient = false); +virtual ~BClipboard(); + + const char *Name() const; + + uint32 LocalCount() const; + uint32 SystemCount() const; + status_t StartWatching(BMessenger target); + status_t StopWatching(BMessenger target); + + bool Lock(); + void Unlock(); + bool IsLocked() const; + + status_t Clear(); + status_t Commit(); + status_t Revert(); + + BMessenger DataSource() const; + BMessage *Data() const; + +/*----- Private or reserved -----------------------------------------*/ +private: + BClipboard(const BClipboard &); + BClipboard &operator=(const BClipboard &); + +virtual void _ReservedClipboard1(); +virtual void _ReservedClipboard2(); +virtual void _ReservedClipboard3(); + + bool AssertLocked() const; + status_t DownloadFromSystem(bool force = false); + status_t UploadToSystem(); + + uint32 fCount; + BMessage *fData; + BLocker fLock; + BMessenger fClipHandler; + BMessenger fDataSource; + uint32 fSystemCount; + char *fName; + uint32 _reserved[4]; +}; + +/*----------------------------------------------------------------*/ +/*----- Global Clipboard -----------------------------------------*/ + +extern _IMPEXP_BE BClipboard *be_clipboard; + +/*-------------------------------------------------------------*/ +/*-------------------------------------------------------------*/ + +#endif /* _CLIPBOARD_H */ diff --git a/headers/os/app/Cursor.h b/headers/os/app/Cursor.h new file mode 100644 index 0000000000..54ec6a1933 --- /dev/null +++ b/headers/os/app/Cursor.h @@ -0,0 +1,83 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: Cursor.h +// Author: Frans van Nispen (xlr8@tref.nl) +// Description: BCursor describes a view-wide or application-wide cursor. +//------------------------------------------------------------------------------ + +#ifndef _CURSOR_H +#define _CURSOR_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + + +// BCursor class --------------------------------------------------------------- +class BCursor : BArchivable { +public: + BCursor(const void* cursorData); + BCursor(BMessage* data); + virtual ~BCursor(); + + virtual status_t Archive(BMessage* into, bool deep = true) const; + static BArchivable* Instantiate(BMessage* data); + +// Private or reserved --------------------------------------------------------- + virtual status_t Perform(perform_code d, void* arg); + +private: + + virtual void _ReservedCursor1(); + virtual void _ReservedCursor2(); + virtual void _ReservedCursor3(); + virtual void _ReservedCursor4(); + + friend class BApplication; + friend class BView; + + int32 m_serverToken; + int32 m_needToFree; + uint32 _reserved[6]; +}; +//------------------------------------------------------------------------------ + +#endif // _CURSOR_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/headers/os/app/Handler.h b/headers/os/app/Handler.h new file mode 100644 index 0000000000..9a17a7f9d9 --- /dev/null +++ b/headers/os/app/Handler.h @@ -0,0 +1,148 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: Handler.cpp +// Author: Erik Jaesler (erik@cgsoftware.com) +// Description: BHandler defines the message-handling protocol. +// MessageReceived() is its lynchpin. +//------------------------------------------------------------------------------ + +#ifndef _HANDLER_H +#define _HANDLER_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +class BLooper; +class BMessageFilter; +class BMessage; +class BList; +class _ObserverList; + +#define B_OBSERVE_WHAT_CHANGE "be:observe_change_what" +#define B_OBSERVE_ORIGINAL_WHAT "be:observe_orig_what" +const uint32 B_OBSERVER_OBSERVE_ALL = 0xffffffff; + +// BHandler class -------------------------------------------------------------- +class BHandler : public BArchivable { + +public: + BHandler(const char* name = NULL); + virtual ~BHandler(); + + // Archiving + BHandler(BMessage* data); + static BArchivable* Instantiate(BMessage* data); + virtual status_t Archive(BMessage* data, bool deep = true) const; + + // BHandler guts. + virtual void MessageReceived(BMessage* message); + BLooper* Looper() const; + void SetName(const char* name); + const char* Name() const; + virtual void SetNextHandler(BHandler* handler); + BHandler* NextHandler() const; + + // Message filtering + virtual void AddFilter(BMessageFilter* filter); + virtual bool RemoveFilter(BMessageFilter* filter); + virtual void SetFilterList(BList* filters); + BList* FilterList(); + + bool LockLooper(); + status_t LockLooperWithTimeout(bigtime_t timeout); + void UnlockLooper(); + + // Scripting + virtual BHandler* ResolveSpecifier(BMessage* msg, + int32 index, + BMessage* specifier, + int32 form, + const char* property); + virtual status_t GetSupportedSuites(BMessage* data); + + // Observer calls, inter-looper and inter-team + status_t StartWatching(BMessenger, uint32 what); + status_t StartWatchingAll(BMessenger); + status_t StopWatching(BMessenger, uint32 what); + status_t StopWatchingAll(BMessenger); + + // Observer calls for observing targets in the same BLooper + status_t StartWatching(BHandler* , uint32 what); + status_t StartWatchingAll(BHandler* ); + status_t StopWatching(BHandler* , uint32 what); + status_t StopWatchingAll(BHandler* ); + + + // Reserved + virtual status_t Perform(perform_code d, void* arg); + + // Notifier calls + virtual void SendNotices(uint32 what, const BMessage* = 0); + bool IsWatched() const; + +//----- Private or reserved ----------------------------------------- +private: + typedef BArchivable _inherited; + friend inline int32 _get_object_token_(const BHandler* ); + friend class BLooper; + friend class BMessageFilter; + + virtual void _ReservedHandler2(); + virtual void _ReservedHandler3(); + virtual void _ReservedHandler4(); + + void InitData(const char* name); + + BHandler(const BHandler&); + BHandler& operator=(const BHandler&); + void SetLooper(BLooper* loop); + + int32 fToken; + char* fName; + BLooper* fLooper; + BHandler* fNextHandler; + BList* fFilters; + _ObserverList* fObserverList; + uint32 _reserved[3]; +}; +//------------------------------------------------------------------------------ + +#endif // _HANDLER_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/headers/os/app/Invoker.h b/headers/os/app/Invoker.h new file mode 100644 index 0000000000..96b5cd2604 --- /dev/null +++ b/headers/os/app/Invoker.h @@ -0,0 +1,128 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: Invoker.h +// Author: Frans van Nispen (xlr8@tref.nl) +// Description: BInvoker class defines a protocol for objects that +// post messages to a "target". +//------------------------------------------------------------------------------ + +#ifndef _INVOKER_H +#define _INVOKER_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +class BHandler; +class BLooper; +class BMessage; + +// BInvoker class -------------------------------------------------------------- +class BInvoker { +public: + BInvoker(); + BInvoker(BMessage *message, + const BHandler *handler, + const BLooper *looper = NULL); + BInvoker(BMessage *message, BMessenger target); + virtual ~BInvoker(); + + virtual status_t SetMessage(BMessage *message); + BMessage *Message() const; + uint32 Command() const; + + virtual status_t SetTarget(const BHandler *h, const BLooper *loop = NULL); + virtual status_t SetTarget(BMessenger messenger); + bool IsTargetLocal() const; + BHandler *Target(BLooper **looper = NULL) const; + BMessenger Messenger() const; + + virtual status_t SetHandlerForReply(BHandler *handler); + BHandler *HandlerForReply() const; + + virtual status_t Invoke(BMessage *msg = NULL); + + // Invoke with BHandler notification. Use this to perform an + // Invoke() with some other kind of notification change code. + // (A raw invoke should always notify as B_CONTROL_INVOKED.) + // Unlike a raw Invoke(), there is no standard message that is + // sent. If 'msg' is NULL, then nothing will be sent to this + // invoker's target... however, a notification message will + // still be sent to any watchers of the invoker's handler. + // Note that the BInvoker class does not actually implement + // any of this behavior -- it is up to subclasses to override + // Invoke() and call Notify() with the appropriate change code. + status_t InvokeNotify(BMessage *msg, uint32 kind = B_CONTROL_INVOKED); + status_t SetTimeout(bigtime_t timeout); + bigtime_t Timeout() const; + +protected: + // Return the change code for a notification. This is either + // B_CONTROL_INVOKED for raw Invoke() calls, or the kind + // supplied to InvokeNotify(). In addition, 'notify' will be + // set to true if this was an InvokeNotify() call, else false. + uint32 InvokeKind(bool* notify = NULL); + + // Start and end an InvokeNotify context around an Invoke() call. + // These are only needed for writing custom methods that + // emulate the standard InvokeNotify() call. + void BeginInvokeNotify(uint32 kind = B_CONTROL_INVOKED); + void EndInvokeNotify(); + +// Private or reserved --------------------------------------------------------- +private: + // to be able to keep binary compatibility + virtual void _ReservedInvoker1(); + virtual void _ReservedInvoker2(); + virtual void _ReservedInvoker3(); + + BInvoker(const BInvoker&); + BInvoker &operator=(const BInvoker&); + + BMessage *fMessage; + BMessenger fMessenger; + BHandler *fReplyTo; + bigtime_t fTimeout; + uint32 fNotifyKind; + uint32 _reserved[2]; // to be able to keep binary compatibility +}; +//------------------------------------------------------------------------------ + +#endif // _INVOKER_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/headers/os/app/Looper.h b/headers/os/app/Looper.h new file mode 100644 index 0000000000..231d39b4fa --- /dev/null +++ b/headers/os/app/Looper.h @@ -0,0 +1,237 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: Looper.h +// Author(s): Erik Jaesler (erik@cgsoftware.com) +// DarkWyrm (bpmagic@columbus.rr.com) +// Description: BLooper class spawns a thread that runs a message loop. +//------------------------------------------------------------------------------ + +#ifndef _LOOPER_H +#define _LOOPER_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include +#include +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +class BMessage; +class BMessageQueue; +struct _loop_data_; + +// Port (Message Queue) Capacity ----------------------------------------------- +#define B_LOOPER_PORT_DEFAULT_CAPACITY 100 + + +// BLooper class --------------------------------------------------------------- +class BLooper : public BHandler { +public: + BLooper(const char* name = NULL, + int32 priority = B_NORMAL_PRIORITY, + int32 port_capacity = B_LOOPER_PORT_DEFAULT_CAPACITY); +virtual ~BLooper(); + +// Archiving + BLooper(BMessage* data); +static BArchivable* Instantiate(BMessage* data); +virtual status_t Archive(BMessage* data, bool deep = true) const; + +// Message transmission + status_t PostMessage(uint32 command); + status_t PostMessage(BMessage* message); + status_t PostMessage(uint32 command, + BHandler* handler, + BHandler* reply_to = NULL); + status_t PostMessage(BMessage* message, + BHandler* handler, + BHandler* reply_to = NULL); + +virtual void DispatchMessage(BMessage* message, BHandler* handler); +virtual void MessageReceived(BMessage* msg); + BMessage* CurrentMessage() const; + BMessage* DetachCurrentMessage(); + BMessageQueue* MessageQueue() const; + bool IsMessageWaiting() const; + +// Message handlers + void AddHandler(BHandler* handler); + bool RemoveHandler(BHandler* handler); + int32 CountHandlers() const; + BHandler* HandlerAt(int32 index) const; + int32 IndexOf(BHandler* handler) const; + + BHandler* PreferredHandler() const; + void SetPreferredHandler(BHandler* handler); + +// Loop control +virtual thread_id Run(); +virtual void Quit(); +virtual bool QuitRequested(); + bool Lock(); + void Unlock(); + bool IsLocked() const; + status_t LockWithTimeout(bigtime_t timeout); + thread_id Thread() const; + team_id Team() const; +static BLooper* LooperForThread(thread_id tid); + +// Loop debugging + thread_id LockingThread() const; + int32 CountLocks() const; + int32 CountLockRequests() const; + sem_id Sem() const; + +// Scripting +virtual BHandler* ResolveSpecifier(BMessage* msg, + int32 index, + BMessage* specifier, + int32 form, + const char* property); +virtual status_t GetSupportedSuites(BMessage* data); + +// Message filters (also see BHandler). +virtual void AddCommonFilter(BMessageFilter* filter); +virtual bool RemoveCommonFilter(BMessageFilter* filter); +virtual void SetCommonFilterList(BList* filters); + BList* CommonFilterList() const; + +// Private or reserved --------------------------------------------------------- +virtual status_t Perform(perform_code d, void* arg); + +protected: + // called from overridden task_looper + BMessage* MessageFromPort(bigtime_t = B_INFINITE_TIMEOUT); + +private: + typedef BHandler _inherited; + friend class BWindow; + friend class BApplication; + friend class BMessenger; + friend class BView; + friend class BHandler; + friend port_id _get_looper_port_(const BLooper* ); + friend status_t _safe_get_server_token_(const BLooper* , int32* ); + friend team_id _find_cur_team_id_(); + +virtual void _ReservedLooper1(); +virtual void _ReservedLooper2(); +virtual void _ReservedLooper3(); +virtual void _ReservedLooper4(); +virtual void _ReservedLooper5(); +virtual void _ReservedLooper6(); + + BLooper(const BLooper&); + BLooper& operator=(const BLooper&); + + BLooper(int32 priority, port_id port, const char* name); + + status_t _PostMessage(BMessage* msg, + BHandler* handler, + BHandler* reply_to); + +static status_t _Lock(BLooper* loop, + port_id port, + bigtime_t timeout); +static status_t _LockComplete(BLooper* loop, + int32 old, + thread_id this_tid, + sem_id sem, + bigtime_t timeout); + void InitData(); + void InitData(const char* name, int32 prio, int32 capacity); + void AddMessage(BMessage* msg); + void _AddMessagePriv(BMessage* msg); +static status_t _task0_(void* arg); + + void* ReadRawFromPort(int32* code, + bigtime_t tout = B_INFINITE_TIMEOUT); + BMessage* ReadMessageFromPort(bigtime_t tout = B_INFINITE_TIMEOUT); +virtual BMessage* ConvertToMessage(void* raw, int32 code); +virtual void task_looper(); + void do_quit_requested(BMessage* msg); + bool AssertLocked() const; + BHandler* top_level_filter(BMessage* msg, BHandler* t); + BHandler* handler_only_filter(BMessage* msg, BHandler* t); + BHandler* apply_filters( BList* list, + BMessage* msg, + BHandler* target); + void check_lock(); + BHandler* resolve_specifier(BHandler* target, BMessage* msg); + void UnlockFully(); + +static uint32 sLooperID; +static uint32 sLooperListSize; +static uint32 sLooperCount; +static _loop_data_* sLooperList; +static BLocker sLooperListLock; +static team_id sTeamID; + +static void AddLooper(BLooper* l); +static bool IsLooperValid(const BLooper* l); +static void RemoveLooper(BLooper* l); +static void GetLooperList(BList* list); +static BLooper* LooperForName(const char* name); +static BLooper* LooperForPort(port_id port); + + uint32 fLooperID; + BMessageQueue* fQueue; + BMessage* fLastMessage; + port_id fMsgPort; + long fAtomicCount; + sem_id fLockSem; + long fOwnerCount; + thread_id fOwner; + thread_id fTaskID; + uint32 _unused1; + int32 fInitPriority; + BHandler* fPreferred; + BList fHandlers; + BList* fCommonFilters; + bool fTerminating; + bool fRunCalled; + thread_id fCachedPid; + size_t fCachedStack; + void* fMsgBuffer; + size_t fMsgBufferSize; + uint32 _reserved[6]; +}; +//------------------------------------------------------------------------------ + +#endif // _LOOPER_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/headers/os/app/MessageFilter.h b/headers/os/app/MessageFilter.h new file mode 100644 index 0000000000..9fc1965034 --- /dev/null +++ b/headers/os/app/MessageFilter.h @@ -0,0 +1,126 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: MessageFilter.h +// Author: Erik Jaesler (erik@cgsoftware.com) +// Description: BMessageFilter class creates objects that filter +// in-coming BMessages. +//------------------------------------------------------------------------------ + +#ifndef _MESSAGE_FILTER_H +#define _MESSAGE_FILTER_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +class BMessage; + +// filter_hook Return Codes and Protocol --------------------------------------- +enum filter_result { + B_SKIP_MESSAGE, + B_DISPATCH_MESSAGE +}; + +typedef filter_result (*filter_hook) + (BMessage* message, BHandler** target, BMessageFilter* filter); + + +// BMessageFilter invocation criteria ------------------------------------------ +enum message_delivery { + B_ANY_DELIVERY, + B_DROPPED_DELIVERY, + B_PROGRAMMED_DELIVERY +}; + +enum message_source { + B_ANY_SOURCE, + B_REMOTE_SOURCE, + B_LOCAL_SOURCE +}; + +// BMessageFilter Class -------------------------------------------------------- +class BMessageFilter { + +public: + BMessageFilter( uint32 what, + filter_hook func = NULL); + BMessageFilter( message_delivery delivery, + message_source source, + filter_hook func = NULL); + BMessageFilter( message_delivery delivery, + message_source source, + uint32 what, + filter_hook func = NULL); + BMessageFilter(const BMessageFilter& filter); + BMessageFilter(const BMessageFilter* filter); + virtual ~BMessageFilter(); + + BMessageFilter &operator=(const BMessageFilter& from); + + // Hook function; ignored if filter_hook is non-NULL + virtual filter_result Filter(BMessage* message, BHandler** target); + + message_delivery MessageDelivery() const; + message_source MessageSource() const; + uint32 Command() const; + bool FiltersAnyCommand() const; + BLooper *Looper() const; + +// Private or reserved --------------------------------------------------------- +private: + friend class BLooper; + friend class BHandler; + + virtual void _ReservedMessageFilter1(); + virtual void _ReservedMessageFilter2(); + + void SetLooper(BLooper* owner); + filter_hook FilterFunction() const; + bool fFiltersAny; + uint32 what; + message_delivery fDelivery; + message_source fSource; + BLooper *fLooper; + filter_hook fFilterFunction; + uint32 _reserved[3]; +}; +//------------------------------------------------------------------------------ + +#endif // _MESSAGE_FILTER_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/headers/os/app/MessageQueue.h b/headers/os/app/MessageQueue.h new file mode 100644 index 0000000000..457f0d1cc5 --- /dev/null +++ b/headers/os/app/MessageQueue.h @@ -0,0 +1,67 @@ +// +// $Id: MessageQueue.h,v 1.1 2002/07/09 12:24:32 ejakowatz Exp $ +// +// This is the BMessageQueue interface for OpenBeOS. It has been created +// to be source and binary compatible with the BeOS version of +// BMessageQueue. +// + + +#ifndef _OPENBEOS_MESSAGEQUEUE_H +#define _OPENBEOS_MESSAGEQUEUE_H + + +#include "Locker.h" + + +class BMessage; + + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS { +#endif + +class BMessageQueue { +public: + BMessageQueue(); + virtual ~BMessageQueue(); + + void AddMessage(BMessage *message); + void RemoveMessage(BMessage *message); + + int32 CountMessages(void) const; + bool IsEmpty(void) const; + + BMessage *FindMessage(int32 index) const; + BMessage *FindMessage(uint32 what, int32 index=0) const; + + bool Lock(void); + void Unlock(void); + bool IsLocked(void); + + BMessage *NextMessage(void); + +private: + + // Reserved space in the vtable for future changes to BMessageQueue + virtual void _ReservedMessageQueue1(void); + virtual void _ReservedMessageQueue2(void); + virtual void _ReservedMessageQueue3(void); + + BMessageQueue(const BMessageQueue &); + BMessageQueue &operator=(const BMessageQueue &); + + BMessage *fTheQueue; + BMessage *fQueueTail; + int32 fMessageCount; + BLocker fLocker; + + // Reserved space for future changes to BMessageQueue + uint32 fReservedSpace[3]; +}; + +#ifdef USE_OPENBEOS_NAMESPACE +} +#endif + +#endif // _OPENBEOS_MESSAGEQUEUE_H diff --git a/headers/os/app/MessageRunner.h b/headers/os/app/MessageRunner.h new file mode 100644 index 0000000000..aea2329c97 --- /dev/null +++ b/headers/os/app/MessageRunner.h @@ -0,0 +1,62 @@ +/****************************************************************************** +/ +/ File: MessageRunner.h +/ +/ Description: +/ +/ Copyright 1998, Be Incorporated, All Rights Reserved. +/ +*******************************************************************************/ + +#ifndef _MESSAGE_RUNNER_H +#define _MESSAGE_RUNNER_H + +#include +#include + +/*----------------------------------------------------------------------*/ +/*----- BMessageRunner class --------------------------------------------*/ + +class BMessageRunner { +public: + BMessageRunner(BMessenger target, const BMessage *msg, + bigtime_t interval, int32 count = -1); + BMessageRunner(BMessenger target, const BMessage *msg, + bigtime_t interval, int32 count, BMessenger reply_to); +virtual ~BMessageRunner(); + + status_t InitCheck() const; + + status_t SetInterval(bigtime_t interval); + status_t SetCount(int32 count); + status_t GetInfo(bigtime_t *interval, int32 *count) const; + +/*----- Private or reserved -----------------------------------------*/ + +private: + +virtual void _ReservedMessageRunner1(); +virtual void _ReservedMessageRunner2(); +virtual void _ReservedMessageRunner3(); +virtual void _ReservedMessageRunner4(); +virtual void _ReservedMessageRunner5(); +virtual void _ReservedMessageRunner6(); + + BMessageRunner(const BMessageRunner &); + BMessageRunner &operator=(const BMessageRunner &); + + void InitData(BMessenger target, const BMessage *msg, + bigtime_t interval, int32 count, BMessenger reply_to); + status_t SetParams(bool reset_i, bigtime_t interval, + bool reset_c, int32 count); + + int32 fToken; + uint32 _reserved[6]; +}; + +/*-------------------------------------------------------------*/ +/*-------------------------------------------------------------*/ + +#endif /* _MESSAGE_QUEUE_H */ + + diff --git a/headers/os/app/Messenger.h b/headers/os/app/Messenger.h new file mode 100644 index 0000000000..9deaf165c8 --- /dev/null +++ b/headers/os/app/Messenger.h @@ -0,0 +1,116 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: Messenger.h +// Author: Ingo Weinhold (bonefish@users.sf.net) +// Description: BMessenger delivers messages to local or remote targets. +//------------------------------------------------------------------------------ + +#ifndef _MESSENGER_H +#define _MESSENGER_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include +#include +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +class BHandler; +class BLooper; + +// BMessenger class ------------------------------------------------------------ +class BMessenger { +public: + BMessenger(); + BMessenger(const char *signature, team_id team = -1, + status_t *result = NULL); + BMessenger(const BHandler *handler, const BLooper *looper = NULL, + status_t *result = NULL); + BMessenger(const BMessenger &from); + ~BMessenger(); + + // Target + + bool IsTargetLocal() const; + BHandler *Target(BLooper **looper) const; + bool LockTarget() const; + status_t LockTargetWithTimeout(bigtime_t timeout) const; + + // Message sending + + status_t SendMessage(uint32 command, BHandler *replyTo = NULL) const; + status_t SendMessage(BMessage *message, BHandler *replyTo = NULL, + bigtime_t timeout = B_INFINITE_TIMEOUT) const; + status_t SendMessage(BMessage *message, BMessenger replyTo, + bigtime_t timeout = B_INFINITE_TIMEOUT) const; + status_t SendMessage(uint32 command, BMessage *reply) const; + status_t SendMessage(BMessage *message, BMessage *reply, + bigtime_t deliveryTimeout = B_INFINITE_TIMEOUT, + bigtime_t replyTimeout = B_INFINITE_TIMEOUT) const; + + // Operators and misc + + BMessenger &operator=(const BMessenger &from); + bool operator==(const BMessenger &other) const; + + bool IsValid() const; + team_id Team() const; + + //----- Private or reserved ----------------------------------------- +private: + friend class BRoster; + friend class _TRoster_; + friend class BMessage; + friend inline void _set_message_reply_(BMessage *, BMessenger); + friend status_t swap_data(type_code, void *, size_t, swap_action); + friend bool operator<(const BMessenger &a, const BMessenger &b); + friend bool operator!=(const BMessenger &a, const BMessenger &b); + + BMessenger(team_id team, port_id port, int32 token, bool preferred); + + void InitData(const char *signature, team_id team, status_t *result); + +private: + port_id fPort; + int32 fHandlerToken; + team_id fTeam; + int32 extra0; + int32 extra1; + bool fPreferredTarget; + bool extra2; + bool extra3; + bool extra4; +}; + +_IMPEXP_BE bool operator<(const BMessenger &a, const BMessenger &b); +_IMPEXP_BE bool operator!=(const BMessenger &a, const BMessenger &b); + +#endif // _MESSENGER_H diff --git a/headers/os/app/PropertyInfo.h b/headers/os/app/PropertyInfo.h new file mode 100644 index 0000000000..6407783761 --- /dev/null +++ b/headers/os/app/PropertyInfo.h @@ -0,0 +1,134 @@ +/******************************************************************************* +/ +/ File: PropertyInfo.h +/ +/ Description: Utility class for maintain scripting information +/ +/ Copyright 1997-98, Be Incorporated, All Rights Reserved +/ +*******************************************************************************/ + +#ifndef _PROPERTY_INFO_H +#define _PROPERTY_INFO_H + +#include +#include +#include +#include /* For convenience */ + +/*----------------------------------------------------------------*/ +/*----- the property_info structure ------------------------------*/ + + +struct _oproperty_info_; + +struct compound_type { + struct field_pair { + char *name; // name of entry in message + type_code type; // type_code of entry in message + }; + field_pair pairs[5]; +}; + +struct property_info { + char *name; + uint32 commands[10]; + uint32 specifiers[10]; + char *usage; + uint32 extra_data; + uint32 types[10]; + compound_type ctypes[3]; + uint32 _reserved[10]; +}; + +enum value_kind { + B_COMMAND_KIND = 0, + B_TYPE_CODE_KIND = 1 +}; + +struct value_info { + char *name; + uint32 value; + value_kind kind; + char *usage; + uint32 extra_data; + uint32 _reserved[10]; +}; + +#define B_PROPERTY_INFO_TYPE 'SCTD' + +/*----------------------------------------------------------------*/ +/*----- BPropertyInfo class --------------------------------------*/ + +class BPropertyInfo : public BFlattenable { +public: + BPropertyInfo(property_info *p = NULL, + value_info *ci = NULL, + bool free_on_delete = false); +virtual ~BPropertyInfo(); + +virtual int32 FindMatch(BMessage *msg, + int32 index, + BMessage *spec, + int32 form, + const char *prop, + void *data = NULL) const; + +virtual bool IsFixedSize() const; +virtual type_code TypeCode() const; +virtual ssize_t FlattenedSize() const; +virtual status_t Flatten(void *buffer, ssize_t size) const; +virtual bool AllowsTypeCode(type_code code) const; +virtual status_t Unflatten(type_code c, + const void *buf, + ssize_t s); + const property_info *Properties() const; + const value_info *Values() const; + int32 CountProperties() const; + int32 CountValues() const; + + void PrintToStream() const; + +/*----- Private or reserved -----------------------------------------*/ +protected: +static bool FindCommand(uint32, int32, property_info *); +static bool FindSpecifier(uint32, property_info *); + +private: +virtual void _ReservedPropertyInfo1(); +virtual void _ReservedPropertyInfo2(); +virtual void _ReservedPropertyInfo3(); +virtual void _ReservedPropertyInfo4(); + + BPropertyInfo(const BPropertyInfo &); + BPropertyInfo &operator=(const BPropertyInfo &); + void FreeMem(); + void FreeInfoArray(property_info *p, int32); + void FreeInfoArray(value_info *p, int32); + void FreeInfoArray(_oproperty_info_ *p, int32); +static property_info *ConvertToNew(const _oproperty_info_ *p); +static _oproperty_info_ *ConvertFromNew(const property_info *p); + + property_info *fPropInfo; + value_info *fValueInfo; + int32 fPropCount; + bool fInHeap; + bool fOldInHeap; + uint16 fValueCount; + _oproperty_info_ *fOldPropInfo; + uint32 _reserved[2]; /* was 4 */ + + /* Deprecated */ +private: + const property_info *PropertyInfo() const; + BPropertyInfo(property_info *p, + bool free_on_delete); +static bool MatchCommand(uint32, int32, property_info *); +static bool MatchSpecifier(uint32, property_info *); + +}; + +/*-------------------------------------------------------------*/ +/*-------------------------------------------------------------*/ + +#endif /* _PROPERTY_INFO_H */ diff --git a/headers/os/app/Roster.h b/headers/os/app/Roster.h new file mode 100644 index 0000000000..c36bb2a549 --- /dev/null +++ b/headers/os/app/Roster.h @@ -0,0 +1,227 @@ +/****************************************************************************** +/ +/ File: Roster.h +/ +/ Description: BRoster class lets you launch apps and keeps +/ track of apps that are running. +/ Global be_roster represents the default BRoster. +/ app_info structure provides info for a running app. +/ +/ Copyright 1995-98, Be Incorporated, All Rights Reserved. +/ +******************************************************************************/ + +#ifndef _ROSTER_H +#define _ROSTER_H + +#include +#include +#include +#include + +class BList; +class BMessage; +class BNodeInfo; + +extern "C" int _init_roster_(); + +/*-------------------------------------------------------------*/ +/* --------- app_info Struct and Values ------------------------ */ + +struct app_info { + app_info(); + ~app_info(); + + thread_id thread; + team_id team; + port_id port; + uint32 flags; + entry_ref ref; + char signature[B_MIME_TYPE_LENGTH]; +}; + +#define B_LAUNCH_MASK (0x3) + +#define B_SINGLE_LAUNCH (0x0) +#define B_MULTIPLE_LAUNCH (0x1) +#define B_EXCLUSIVE_LAUNCH (0x2) + +#define B_BACKGROUND_APP (0x4) +#define B_ARGV_ONLY (0x8) +#define _B_APP_INFO_RESERVED1_ (0x10000000) + + +enum { + B_REQUEST_LAUNCHED = 0x00000001, + B_REQUEST_QUIT = 0x00000002, + B_REQUEST_ACTIVATED = 0x00000004 +}; + +enum { + B_SOME_APP_LAUNCHED = 'BRAS', + B_SOME_APP_QUIT = 'BRAQ', + B_SOME_APP_ACTIVATED = 'BRAW' +}; + +/*-------------------------------------------------------------*/ +/* --------- BRoster class----------------------------------- */ + +class BRoster { +public: + BRoster(); + ~BRoster(); + +/* Querying for apps */ + bool IsRunning(const char *mime_sig) const; + bool IsRunning(entry_ref *ref) const; + team_id TeamFor(const char *mime_sig) const; + team_id TeamFor(entry_ref *ref) const; + void GetAppList(BList *team_id_list) const; + void GetAppList(const char *sig, BList *team_id_list) const; + status_t GetAppInfo(const char *sig, app_info *info) const; + status_t GetAppInfo(entry_ref *ref, app_info *info) const; + status_t GetRunningAppInfo(team_id team, app_info *info) const; + status_t GetActiveAppInfo(app_info *info) const; + status_t FindApp(const char *mime_type, entry_ref *app) const; + status_t FindApp(entry_ref *ref, entry_ref *app) const; + +/* Launching, activating, and broadcasting to apps */ + status_t Broadcast(BMessage *msg) const; + status_t Broadcast(BMessage *msg, BMessenger reply_to) const; + status_t StartWatching(BMessenger target, + uint32 event_mask = B_REQUEST_LAUNCHED | B_REQUEST_QUIT) const; + status_t StopWatching(BMessenger target) const; + status_t ActivateApp(team_id team) const; + status_t Launch(const char *mime_type, BMessage *initial_msgs = NULL, + team_id *app_team = NULL) const; + status_t Launch(const char *mime_type, BList *message_list, + team_id *app_team = NULL) const; + status_t Launch(const char *mime_type, int argc, char **args, + team_id *app_team = NULL) const; + + status_t Launch(const entry_ref *ref, const BMessage *initial_message = NULL, + team_id *app_team = NULL) const; + status_t Launch(const entry_ref *ref, const BList *message_list, + team_id *app_team = NULL) const; + status_t Launch(const entry_ref *ref, int argc, const char * const *args, + team_id *app_team = NULL) const; + +/* Recent document and app support */ + void GetRecentDocuments(BMessage *refList, int32 maxCount, + const char *ofType = NULL, + const char *openedByAppSig = NULL) const; + void GetRecentDocuments(BMessage *refList, int32 maxCount, + const char *ofTypeList[], int32 ofTypeListCount, + const char *openedByAppSig = NULL) const; + void GetRecentFolders(BMessage *refList, int32 maxCount, + const char *openedByAppSig = NULL) const; + void GetRecentApps(BMessage *refList, int32 maxCount) const; + + void AddToRecentDocuments(const entry_ref *doc, + const char *appSig = NULL) const; + void AddToRecentFolders(const entry_ref *folder, + const char *appSig = NULL) const; + +/*----- Private or reserved ------------------------------*/ +private: + +friend class BApplication; +friend class BWindow; +friend class _BAppCleanup_; +friend int _init_roster_(); +friend status_t _send_to_roster_(BMessage *, BMessage *, bool); +friend bool _is_valid_roster_mess_(bool); +friend status_t BMimeType::StartWatching(BMessenger); +friend status_t BMimeType::StopWatching(BMessenger); +friend status_t BClipboard::StartWatching(BMessenger); +friend status_t BClipboard::StopWatching(BMessenger); + + enum mtarget { + MAIN_MESSENGER, + MIME_MESSENGER, + USE_GIVEN + }; + + status_t _StartWatching(mtarget t, BMessenger *roster_mess, uint32 what, + BMessenger notify, uint32 event_mask) const; + status_t _StopWatching(mtarget t, BMessenger *roster_mess, uint32 what, + BMessenger notify) const; + uint32 AddApplication( const char *mime_sig, + entry_ref *ref, + uint32 flags, + team_id team, + thread_id thread, + port_id port, + bool full_reg) const; + void SetSignature(team_id team, const char *mime_sig) const; + void SetThread(team_id team, thread_id tid) const; + void SetThreadAndTeam(uint32 entry_token, + thread_id tid, + team_id team) const; + void CompleteRegistration(team_id team, + thread_id, + port_id port) const; + bool IsAppPreRegistered( entry_ref *ref, + team_id team, + app_info *info) const; + void RemovePreRegApp(uint32 entry_token) const; + void RemoveApp(team_id team) const; + + status_t xLaunchAppPrivate( const char *mime_sig, + const entry_ref *ref, + BList* msg_list, + int cargs, + char **args, + team_id *app_team) const; + bool UpdateActiveApp(team_id team) const; + void SetAppFlags(team_id team, uint32 flags) const; + void DumpRoster() const; + status_t resolve_app(const char *in_type, + const entry_ref *ref, + entry_ref *app_ref, + char *app_sig, + uint32 *app_flags, + bool *was_document) const; + status_t translate_ref(const entry_ref *ref, + BMimeType *app_meta, + entry_ref *app_ref, + BFile *app_file, + char *app_sig, + bool *was_document) const; + status_t translate_type(const char *mime_type, + BMimeType *meta, + entry_ref *app_ref, + BFile *app_file, + char *app_sig) const; + status_t sniff_file(const entry_ref *file, + BNodeInfo *finfo, + char *mime_type) const; + bool is_wildcard(const char *sig) const; + status_t get_unique_supporting_app(const BMessage *apps, + char *out_sig) const; + status_t get_random_supporting_app(const BMessage *apps, + char *out_sig) const; + char **build_arg_vector(char **args, int *pargs, + const entry_ref *app_ref, + const entry_ref *doc_ref) const; + status_t send_to_running(team_id tema, + const entry_ref *app_ref, + int cargs, char **args, + const BList *msg_list, + const entry_ref *ref) const; + void InitMessengers(); + + BMessenger fMess; + BMessenger fMimeMess; + uint32 _fReserved[3]; +}; + +/*-----------------------------------------------------*/ +/*----- Global be_roster ------------------------------*/ + +extern _IMPEXP_BE const BRoster *be_roster; + +/*-----------------------------------------------------*/ +/*-----------------------------------------------------*/ + +#endif /* _ROSTER_H */ diff --git a/headers/os/game/DirectWindow.h b/headers/os/game/DirectWindow.h new file mode 100644 index 0000000000..46b6df514b --- /dev/null +++ b/headers/os/game/DirectWindow.h @@ -0,0 +1,138 @@ +/*****************************************************************************/ +// DirectWindow.h +// +// A "client window class for direct screen access." +// +// +// Copyright (c) 2001 OpenBeOS Project +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ + +#ifndef GAME_KIT_DIRECT_WINDOW +#define GAME_KIT_DIRECT_WINDOW + +#include +#include + +class BDirectDriver; + +// State of the direct access when called back through DirectConnected. +enum direct_buffer_state +{ + B_DIRECT_MODE_MASK = 15, + + B_DIRECT_START = 0, + B_DIRECT_STOP = 1, + B_DIRECT_MODIFY = 2, + + B_CLIPPING_MODIFIED = 16, + B_BUFFER_RESIZED = 32, + B_BUFFER_MOVED = 64, + B_BUFFER_RESET = 128 +}; + +// State of the direct driver and its hooks functions. +enum direct_driver_state +{ + B_DRIVER_CHANGED = 0x0001, + B_MODE_CHANGED = 0x0002 +}; + +// Frame buffer access descriptor. +typedef struct +{ + direct_buffer_state buffer_state; + direct_driver_state driver_state; + void *bits; + void *pci_bits; + int32 bytes_per_row; + uint32 bits_per_pixel; + color_space pixel_format; + buffer_layout layout; + buffer_orientation orientation; + uint32 _reserved[9]; + uint32 _dd_type_; + uint32 _dd_token_; + uint32 clip_list_count; + clipping_rect window_bounds; + clipping_rect clip_bounds; + clipping_rect clip_list[1]; + +} direct_buffer_info; + + +class BDirectWindow : public BWindow +{ +public: + // Construction and destruction. + BDirectWindow( BRect frame, const char* pTitle, window_type type, + uint32 flags, uint32 workspace = B_CURRENT_WORKSPACE ); + + BDirectWindow( BRect frame, const char* pTitle, window_look look, + window_feel feel, uint32 flags, uint32 workspace = B_CURRENT_WORKSPACE ); + + virtual ~BDirectWindow(); + + // Save and restore. + static BArchivable* Instantiate( BMessage* pData ); + virtual status_t Archive( BMessage *data, bool deep = true ) const; + + + virtual void DirectConnected( direct_buffer_info* pInfo ); + status_t GetClippingRegion( BRegion* pRegion, BPoint* pOrigin = NULL ) const; + status_t SetFullScreen( bool enable ); + bool IsFullScreen() const; + + static bool SupportsWindowMode( screen_id = B_MAIN_SCREEN_ID ); + + // Defined for future extension (fragile base class). Otherwise + // identical to BWindow. + virtual void Quit(); + virtual void DispatchMessage( BMessage* pMessage, BHandler* pHandler ); + virtual void MessageReceived( BMessage* pMessage ); + virtual void FrameMoved( BPoint new_position ); + virtual void WorkspacesChanged( uint32 old_workspace, uint32 new_workspace ); + virtual void WorkspaceActivated( int32 workspace, bool state ); + virtual void FrameResized( float new_width, float new_height ); + virtual void Minimize( bool minimize ); + virtual void Zoom( BPoint rec_position, float rec_width, float rec_height ); + virtual void ScreenChanged( BRect screen_size, color_space depth ); + virtual void MenusBeginning(); + virtual void MenusEnded(); + virtual void WindowActivated( bool state ); + virtual void Show(); + virtual void Hide(); + virtual status_t GetSupportedSuites( BMessage* pData ); + virtual status_t Perform( perform_code performCode, void* pArg ); + virtual BHandler * ResolveSpecifier( BMessage* pMsg, int32 index, + BMessage* pSpecifier, int32 form, const char* pProperty ); + +private: + // No copying allowed. + BDirectWindow(); + BDirectWindow( BDirectWindow& ); + BDirectWindow& operator=( BDirectWindow& ); + +private: + // Fill in all the particulars relating to our implementation, + // once we know what they're going to be, here. +} + +#endif // GAME_KIT_DIRECT_WINDOW \ No newline at end of file diff --git a/headers/os/game/FileGameSound.h b/headers/os/game/FileGameSound.h new file mode 100644 index 0000000000..2ade3e2545 --- /dev/null +++ b/headers/os/game/FileGameSound.h @@ -0,0 +1,80 @@ +/*****************************************************************************/ +// FileGameSound.h +// +// This is "a class that streams data out of a file." +// +// +// Copyright (c) 2001 OpenBeOS Project +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ + +#ifndef GAME_KIT_FILE_GAME_SOUND +#define GAME_KIT_FILE_GAME_SOUND + +#include + +class BMediaFile; +namespace BPrivate +{ + class BTrackReader; +} + +class BFileGameSound : public BStreamingGameSound +{ +public: + BFileGameSound( const entry_ref* pFile, bool looping = true, + BGameSoundDevice* pDevice = NULL ); + BFileGameSound( const char* pFilename, bool looping = true, + BGameSoundDevice* pDevice = NULL ); + + virtual ~BFileGameSound(); + + virtual BGameSound* Clone() const; + + virtual status_t StartPlaying(); + virtual status_t StopPlaying(); + + // Use this if you have stopped and want to start again quickly. + status_t Preload(); + + virtual void FillBuffer( void* pInBuffer, size_t inByteCount ); + + virtual status_t Perform( int32 selector, void* pData ); + + virtual status_t SetPaused( bool isPaused, bigtime_t rampTime ); + + enum + { + B_NOT_PAUSED, + B_PAUSE_IN_PROGRESS, + B_PAUSED + }; + + int32 IsPaused(); + +private: + // Leave these declarations private unless you plan on actually + // implementing and using them. + BFileGameSound(); + BFileGameSound( const BFileGameSound& ); + BFileGameSound& operator=( const BFileGameSound& ); +}; + +#endif // GAME_KIT_FILE_GAME_SOUND diff --git a/headers/os/game/GameKit.h b/headers/os/game/GameKit.h new file mode 100644 index 0000000000..e989526358 --- /dev/null +++ b/headers/os/game/GameKit.h @@ -0,0 +1,35 @@ +/*****************************************************************************/ +// GameKit.h +// +// Includes headers for all classes that comprise the GameKit. +// +// +// Copyright (c) 2001 OpenBeOS Project +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/headers/os/game/GameSound.h b/headers/os/game/GameSound.h new file mode 100644 index 0000000000..e3e7b5af5e --- /dev/null +++ b/headers/os/game/GameSound.h @@ -0,0 +1,98 @@ +/*****************************************************************************/ +// GameSound.h +// +// This is an abstract base class for "all sounds being played using the +// gamesound kit. Use one of the concrete subclasses for actually playing +// sound." +// +// +// Copyright (c) 2001 OpenBeOS Project +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ + +#ifndef GAME_KIT_GAME_SOUND +#define GAME_KIT_GAME_SOUND + +#include +#include + +struct gs_audio_format; +class BGameSoundDevice; + + +class BGameSound +{ +public: + BGameSound( BGameSoundDevice* pDevice = NULL ); + virtual ~BGameSound(); + + virtual BGameSound* Clone() const = 0; + status_t InitCheck() const; + + BGameSoundDevice* Device() const; + gs_id ID() const; + + // Only valid after Init(). + const gs_audio_format& Format() const; + + virtual status_t StartPlaying(); + virtual bool IsPlaying(); + virtual status_t StopPlaying(); + + // Ramp duration is in seconds. + status_t SetGain( float gain, bigtime_t duration = 0 ); + status_t SetPan( float pan, bigtime_t duration = 0 ); + float Gain(); + float Pan(); + + virtual status_t SetAttributes( gs_attribute* pInAttributes, + size_t inAttributeCount ); + virtual status_t GetAttributes( gs_attribute* pOutAttributes, + size_t outAttributeCount ); + + virtual status_t Perform( int32 selector, void * data ); + + void* operator new( size_t size ); + void* operator new( size_t size, const nothrow_t& ) throw(); + void operator delete( void* ptr ); + void operator delete( void* ptr, const nothrow_t& ) throw(); + + // These were implemented in BPrivGameSound, presumably + // for reasons of privacy. If that's the only reason, then + // we can put them here, because you've got the source, my man. + // Otherwise, we'll put 'em where they have to be. + static status_t SetMemoryPoolSize( size_t in_poolSize ); + static status_t LockMemoryPool( bool in_lockInCore ); + static int32 SetMaxSoundCount( int32 in_maxCount ); + +protected: + status_t SetInitError( status_t in_initError ); + status_t Init( gs_id handle ); + + BGameSound( const BGameSound& other ); + BGameSound& operator=( const BGameSound & other ); + +private: + BGameSound(); + + // Our implementation details go here. +}; + +#endif // GAME_KIT_GAME_SOUND \ No newline at end of file diff --git a/headers/os/game/GameSoundDefs.h b/headers/os/game/GameSoundDefs.h new file mode 100644 index 0000000000..610b1f5267 --- /dev/null +++ b/headers/os/game/GameSoundDefs.h @@ -0,0 +1,103 @@ +/*****************************************************************************/ +// GameSoundDefs.h +// +// "Definitions of common types and constants for the gamesound kit." +// +// +// Copyright (c) 2001 OpenBeOS Project +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ + +#ifndef GAME_KIT_GAME_SOUND_DEFS +#define GAME_KIT_GAME_SOUND_DEFS + +#include + +#define B_GS_CUR_API_VERSION B_BEOS_VERSION +#define B_GS_MIN_API_VERSION 0x100 + +typedef int32 gs_id; + +// Invalid sound handle. +#define B_GS_INVALID_SOUND ((gs_id)-1) + +// gs_id for the main mix buffer. +#define B_GS_MAIN_SOUND ((gs_id)-2) + +// FIXME - renumber to real error messages. +enum +{ + B_GS_BAD_HANDLE = -99999, + B_GS_NO_SOUNDS, + B_GS_NO_HARDWARE, + B_GS_ALREADY_COMMITTED, + B_GS_READ_ONLY_VALUE +}; + +struct gs_audio_format +{ + // Same as media_raw_audio_format. + enum format + { + B_GS_U8 = 0x11, // 128 == mid, 1 == bottom, 255 == top. + B_GS_S16 = 0x2, // 0 == mid, -32767 == bottom, +32767 == top. + B_GS_F = 0x24, // 0 == mid, -1.0 == bottom, 1.0 == top. + B_GS_S32 = 0x4 // 0 == mid, 0x80000001 == bottom, 0x7fffffff == top. + }; + + float frame_rate; + uint32 channel_count; // 1 or 2, mostly. + uint32 format; // For compressed formats, go to media_encoded_audio_format. + uint32 byte_order; // 2 for little endian, 1 for big endian. + size_t buffer_size; // Size of each buffer -- NOT GUARANTEED. +}; + + +enum gs_attributes +{ + B_GS_NO_ATTRIBUTE = 0, // When there is no attribute. + B_GS_MAIN_GAIN = 1, // 0 == 0 dB, -6.0 == -6 dB (gs_id ignored). + B_GS_CD_THROUGH_GAIN, // 0 == 0 dB, -12.0 == -12 dB (gs_id ignored). + // But which CD? + B_GS_GAIN = 128, // 0 == 0 dB, -1.0 == -1 dB, +10.0 == +10 dB. + B_GS_PAN, // 0 == middle, -1.0 == left, +1.0 == right. + B_GS_SAMPLING_RATE, // 44100.0 == 44.1 kHz. + B_GS_LOOPING, // 0 == no. + B_GS_FIRST_PRIVATE_ATTRIBUTE = 90000, + B_GS_FIRST_USER_ATTRIBUTE = 100000 +}; + +struct gs_attribute +{ + int32 attribute; // Which attribute. + bigtime_t duration; // How long of time to ramp over for the change. + float value; // Where the value stops changing. + uint32 flags; // Whatever flags are for the attribute. +}; + +struct gs_attribute_info +{ + int32 attribute; + float granularity; + float minimum; + float maximum; +}; + +#endif // GAME_KIT_GAME_SOUND_DEFS diff --git a/headers/os/game/PushGameSound.h b/headers/os/game/PushGameSound.h new file mode 100644 index 0000000000..ec6229f8d0 --- /dev/null +++ b/headers/os/game/PushGameSound.h @@ -0,0 +1,87 @@ +/*****************************************************************************/ +// PushGameSound.h +// +// This is "a class for games that want to push data at the system, +// rather than have a callback get called." +// +// +// Copyright (c) 2001 OpenBeOS Project +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ + +#ifndef GAME_KIT_PUSH_GAME_SOUND +#define GAME_KIT_PUSH_GAME_SOUND + +#include + +class BPushGameSound : public BStreamingGameSound +{ +public: + BPushGameSound( size_t inBufferFrameCount, + const gs_audio_format* pFormat, size_t inBufferCount = 2, + BGameSoundDevice* pDevice = NULL ); + + virtual ~BPushGameSound(); + + enum lock_status + { + lock_failed = -1, // not yet time to do more + lock_ok = 0, // do more + lock_ok_frames_dropped // you may have missed some buffers + }; + + virtual lock_status LockNextPage( void** ppOut_pagePtr, + size_t* pOut_pageSize ); + + virtual status_t UnlockPage( void* pIn_pagePtr ); + + virtual lock_status LockForCyclic( void** ppOut_basePtr, + size_t* pOut_size ); + + virtual status_t UnlockCyclic(); + virtual size_t CurrentPosition(); + + virtual BGameSound* Clone() const; + + virtual status_t Perform( int32 selector, void* pData ); + +protected: + + // Will allocate handle and call Init(). + virtual status_t SetParameters( size_t inBufferFrameCount, + const gs_audio_format* pFormat, size_t inBufferCount ); + + virtual status_t SetStreamHook( + void (*hook)( void* pInCookie, void* pInBuffer, size_t inByteCount, BStreamingGameSound* pMe ), + void* pCookie ); + + // Default is to call stream hook, if any. + virtual void FillBuffer( void* pInBuffer, size_t inByteCount ); + +private: + + // Leave these declarations private unless you plan on actually + // implementing and using them. + BPushGameSound(); + BPushGameSound( const BPushGameSound& ); + BPushGameSound& operator=( const BPushGameSound& ); +}; + +#endif // GAME_KIT_PUSH_GAME_SOUND \ No newline at end of file diff --git a/headers/os/game/SimpleGameSound.h b/headers/os/game/SimpleGameSound.h new file mode 100644 index 0000000000..da051478ac --- /dev/null +++ b/headers/os/game/SimpleGameSound.h @@ -0,0 +1,64 @@ +/*****************************************************************************/ +// SimpleGameSound.h +// +// This is "a class for sound effects that are short, and consist of +// non-changing samples in memory." +// +// +// Copyright (c) 2001 OpenBeOS Project +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ + +#ifndef GAME_KIT_SIMPLE_GAME_SOUND +#define GAME_KIT_SIMPLE_GAME_SOUND + +#include + +class BSimpleGameSound : public BGameSound +{ +public: + BSimpleGameSound( const entry_ref* pInFile, + BGameSoundDevice* pDevice = NULL ); + BSimpleGameSound( const char* pInFile, + BGameSoundDevice* pDevice = NULL ); + BSimpleGameSound( const void* pInData, + size_t inFrameCount, const gs_audio_format* pFormat, + BGameSoundDevice* pDevice = NULL ); + + BSimpleGameSound( const BSimpleGameSound& other ); + + virtual ~BSimpleGameSound(); + + virtual BGameSound* Clone() const; + + virtual status_t Perform( int32 selector, void* pData ); + + status_t SetIsLooping( bool looping ); + bool IsLooping() const; + +private: + + // Leave these declarations private unless you plan on actually + // implementing and using them. + BSimpleGameSound(); + BSimpleGameSound& operator=( const BSimpleGameSound& ); +}; + +#endif \ No newline at end of file diff --git a/headers/os/game/StreamingGameSound.h b/headers/os/game/StreamingGameSound.h new file mode 100644 index 0000000000..c29526c324 --- /dev/null +++ b/headers/os/game/StreamingGameSound.h @@ -0,0 +1,83 @@ +/*****************************************************************************/ +// StreamingGameSound.h +// +// This is "a class for all kinds of streaming (data not known beforehand) +// game sounds." +// +// +// Copyright (c) 2001 OpenBeOS Project +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ + +#ifndef GAME_KIT_STREAMING_GAME_SOUND +#define GAME_KIT_STREAMING_GAME_SOUND + +#include +#include +#include + +class BStreamingGameSound : public BGameSound +{ +public: + BStreamingGameSound( size_t inBufferFrameCount, + const gs_audio_format* pFormat, size_t inBufferCount = 2, + BGameSoundDevice* pDevice = NULL ); + + virtual ~BStreamingGameSound(); + + virtual BGameSound* Clone() const; + + virtual status_t SetStreamHook( + void (*hook)( void* pInCookie, void* pInBuffer, size_t inByteCount, BStreamingGameSound* pMe ), + void* pCookie ); + + // The default is to call stream hook, if any. + virtual void FillBuffer( void * inBuffer, size_t inByteCount ); + + virtual status_t SetAttributes( gs_attribute* inAttributes, + size_t inAttributeCount ); + + virtual status_t Perform( int32 selector, void* pData ); + +protected: + BStreamingGameSound( BGameSoundDevice* pDevice ); + + // Will allocate handle and call Init(). + virtual status_t SetParameters( size_t inBufferFrameCount, + const gs_audio_format* pFormat, size_t inBufferCount ); + + bool Lock(); + void Unlock(); + +private: + + BLocker _m_lock; + + static void stream_callback( void* pCookie, gs_id handle, + void* pBuffer, int32 offset, int32 size, size_t bufSize ); + + // Leave these declarations private unless you plan on actually + // implementing and using them. + BStreamingGameSound(); + BStreamingGameSound( const BStreamingGameSound& ); + BStreamingGameSound& operator=( const BStreamingGameSound& ); +}; + +#endif // GAME_KIT_STREAMING_GAME_SOUND diff --git a/headers/os/game/WindowScreen.h b/headers/os/game/WindowScreen.h new file mode 100644 index 0000000000..cc6821adbc --- /dev/null +++ b/headers/os/game/WindowScreen.h @@ -0,0 +1,174 @@ +/*****************************************************************************/ +// WindowScreen.h +// +// This is a "client window class for direct screen access." +// +// +// Copyright (c) 2001 OpenBeOS Project +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ + +#ifndef GAME_KIT_WINDOW_SCREEN +#define GAME_KIT_WINDOW_SCREEN + +#include +#include +#include +#include +#include +#include +#include + + +// Private struct. +typedef struct +{ + area_id memory_area; + area_id io_area; + char addon_path[64+B_FILE_NAME_LENGTH]; + +} _direct_screen_info_; + +// Private typedef. +typedef int32 (*_add_on_control_)( uint32,void* ); + +// Global function, allowing to move the position of the mouse when +// the GameKit is in control of the screen. +_IMPEXP_GAME void set_mouse_position( int32 x, int32 y ); + +//********************* WARNING - WARNING - WARNING *********************************** +// This is the current version of WindowScreen. The main purpose of this object is to +// establish a direct connexion between application and graphic driver, to increase +// efficiency and abilities. The graphic driver architecture will overcome serious +// changes in the next release, consequently this could only be a preview version of +// the real WindowScreen API. +// +// Question - is what follows below still true? +// Answer - to be determined. +// +// "Nevertheless, compatibility will be insured in future releases FOR MOST OF THE API, +// through the use of a compatibility library (the new game library having a name +// different from "libgame.so"), or a compatibility class (the new WindowScreen class +// using a different name). Part of the API for which compatibility will not be insure +// after the Preview Release are specifically pointed out in the following declarations." +//*************************************************************************************** + +enum +{ + B_ENABLE_VIEW_DRAWING = 0x0001, + B_ENABLE_DEBUGGER = 0x0002 +}; + +class BWindowScreen : public BWindow +{ +public: + BWindowScreen( const char* pTitle, uint32 space, status_t* pError, + bool debug_enable = false ); + BWindowScreen( const char *pTitle, uint32 space, uint32 attributes, + status_t* pError ); + + virtual ~BWindowScreen(); + + virtual void Quit(); + virtual void ScreenConnected( bool active ); + void Disconnect(); + virtual void WindowActivated( bool active ); + virtual void WorkspaceActivated( int32 workspace, bool state ); + virtual void ScreenChanged( BRect screen_size, color_space depth ); + virtual void Hide(); + virtual void Show(); + void SetColorList( rgb_color* pList, int32 first_index = 0, int32 last_index = 255 ); + status_t SetSpace( uint32 space ); + bool CanControlFrameBuffer(); + status_t SetFrameBuffer( int32 width, int32 height ); + status_t MoveDisplayArea( int32 x, int32 y ); + + // IOBase will not be supported in a future compatibility version of + // WindowScreen. Its features should be replaced by other functions + // of the new API. + void *IOBase(); + + rgb_color* ColorList(); + frame_buffer_info* FrameBufferInfo(); + graphics_card_hook CardHookAt( int32 index ); + graphics_card_info* CardInfo(); + +//******************************* Debugger API Notice ******************************** +// Those three calls, and the debug_enable flag in the constructor, have been added to +// help debugging a WindowScreen application without a cross-developement platform or +// the use of serial debug output. +// +// To use them, you need to : +// - enable the debug mode by setting the debug_enable flag of the constructor to "true". +// - register all threads that could be accessing the screen directly at any time. To do +// that, call RegisterThread after spawning the new thread and before resuming +// it (you should never draw from the Window thread itself, neither register it). +// - launch your application from Terminal. The GameKit will first swicth to another +// workspace before opening the WindowScreen. If you launch from workspace 0 [Alt-F1], +// it will choose the workspace 1 [Alt-F2]. For any other workspace, it will choose +// the previous one (for example, for workspace 3 (Alt-F4), it will choose workspace 2 +// [Alt-F3]). +// +// Then : +// - You can use printf(...) anywhere to display informations that will be logged in the +// Terminal window. You can go back to the Terminal Window at any time (using the +// correct Alt-F?? key). Switching workspace will automatically suspend all the thread +// you registered and save the graphic context. Switching back to the WindowScreen +// workspace will restore everything and resume your application. +// - If you need to save and restore more states when your application is suspended and +// resumed, you can overwrite the ForceSwitchForDebug() method. This function is called +// with active == true just after suspending your app, and active == false just before +// resuming it. +// - You can suspend your application by calling the Debugger() method. This will also +// switch to the Terminal workspace. Then you can resume by just switchng back to the +// WindowScreen workspace (using the good Alt-F?? key). It's better not to call Debugger() +// with the WindowScreen locked. +// +// In case of crash : +// - Use the safety short-cut : All the left modifiers (Ctrl, Shift, Option, Command, Alt +// or equivalents) of your keyboard and F12. That should send you back to 640x480, and +// the debugger terminal should be visible (and usable) if any. +// - Then, you can also switch to your Terminal workspace to check the last printf infos. +// - After you got (we hope) more information about your (or our :-) bug, quit the debugger +// window. Then you should be able to change your code and run your application again. +// In any case, check the Error() function immediately after the WindowScreen constructor. +// A bad error code will mean that the GameKit is in a inconsistent state, and then you +// have better to reboot your machine. If you don't want to reboot, you can also try to +// run your application in a different workspace. +// +// It's far from perfect, but we hope it will still help. +// +// The Debug API will not be support after the Preview Release (replaced by the debug +// API in the new WindowScreen class). +//************************************************************************************** + + void RegisterThread( thread_id id ); + virtual void SuspensionHook( bool active ); + void Suspend( char* pLabel ); + + virtual status_t Perform( perform_code d, void* pArg ); + +private: + BWindowScreen(); + BWindowScreen( BWindowScreen& ); + BWindowScreen& operator=( BWindowScreen& ); +}; + +#endif // GAME_KIT_WINDOW_SCREEN \ No newline at end of file diff --git a/headers/os/interface/Alert.h b/headers/os/interface/Alert.h new file mode 100644 index 0000000000..13758a6f07 --- /dev/null +++ b/headers/os/interface/Alert.h @@ -0,0 +1,155 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: Alert.h +// Author: Erik Jaesler (erik@cgsoftware.com) +// Description: BAlert displays a modal alert window. +//------------------------------------------------------------------------------ + +#ifndef _ALERT_H +#define _ALERT_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +class BBitmap; +class BButton; +class BInvoker; +class BTextView; + +// enum for flavors of alert --------------------------------------------------- +enum alert_type { + B_EMPTY_ALERT = 0, + B_INFO_ALERT, + B_IDEA_ALERT, + B_WARNING_ALERT, + B_STOP_ALERT +}; + + +enum button_spacing { + B_EVEN_SPACING = 0, + B_OFFSET_SPACING +}; + +// BAlert class ---------------------------------------------------------------- +class BAlert : public BWindow +{ +public: + + BAlert( const char *title, + const char *text, + const char *button1, + const char *button2 = NULL, + const char *button3 = NULL, + button_width width = B_WIDTH_AS_USUAL, + alert_type type = B_INFO_ALERT); + BAlert( const char *title, + const char *text, + const char *button1, + const char *button2, + const char *button3, + button_width width, + button_spacing spacing, + alert_type type = B_INFO_ALERT); +virtual ~BAlert(); + +// Archiving + BAlert(BMessage *data); +static BArchivable *Instantiate(BMessage *data); +virtual status_t Archive(BMessage *data, bool deep = true) const; + +// BAlert guts + void SetShortcut(int32 button_index, char key); + char Shortcut(int32 button_index) const; + + int32 Go(); + status_t Go(BInvoker *invoker); + +virtual void MessageReceived(BMessage *an_event); +virtual void FrameResized(float new_width, float new_height); + BButton *ButtonAt(int32 index) const; + BTextView *TextView() const; + +virtual BHandler *ResolveSpecifier(BMessage *msg, + int32 index, + BMessage *specifier, + int32 form, + const char *property); +virtual status_t GetSupportedSuites(BMessage *data); + +virtual void DispatchMessage(BMessage *msg, BHandler *handler); +virtual void Quit(); +virtual bool QuitRequested(); + +static BPoint AlertPosition(float width, float height); + +// Private or reserved --------------------------------------------------------- +virtual status_t Perform(perform_code d, void *arg); + +private: +friend class _BAlertFilter_; + +virtual void _ReservedAlert1(); +virtual void _ReservedAlert2(); +virtual void _ReservedAlert3(); + + void InitObject(const char *text, + const char *button1, + const char *button2 = NULL, + const char *button3 = NULL, + button_width width = B_WIDTH_AS_USUAL, + button_spacing spacing = B_EVEN_SPACING, + alert_type type = B_INFO_ALERT); + BBitmap *InitIcon(); + + sem_id fAlertSem; + int32 fAlertVal; + BButton *fButtons[3]; + BTextView *fTextView; + char fKeys[3]; + alert_type fMsgType; + button_width fButtonWidth; + BInvoker *fInvoker; + uint32 _reserved[4]; +}; +//------------------------------------------------------------------------------ + +#endif // _ALERT_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/headers/os/interface/Box.h b/headers/os/interface/Box.h new file mode 100644 index 0000000000..d8575e39e0 --- /dev/null +++ b/headers/os/interface/Box.h @@ -0,0 +1,126 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: Box.h +// Author: Marc Flerackers (mflerackers@androme.be) +// Description: BBox objects group views together and draw a border +// around them. +//------------------------------------------------------------------------------ + +#ifndef _BOX_H +#define _BOX_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + + +// BBox class ------------------------------------------------------------------ +class BBox : public BView { + +public: + BBox(BRect frame, + const char *name = NULL, + uint32 resizingMode = B_FOLLOW_LEFT | B_FOLLOW_TOP, + uint32 flags = B_WILL_DRAW | B_FRAME_EVENTS | + B_NAVIGABLE_JUMP, + border_style border = B_FANCY_BORDER); +virtual ~BBox(); + +/* Archiving */ + BBox(BMessage *archive); +static BArchivable *Instantiate(BMessage *archive); +virtual status_t Archive(BMessage *archive, bool deep = true) const; + +virtual void SetBorder(border_style border); + border_style Border() const; + + void SetLabel(const char *string); + status_t SetLabel(BView *viewLabel); + + const char *Label() const; + BView *LabelView() const; + +virtual void Draw(BRect updateRect); +virtual void AttachedToWindow(); +virtual void DetachedFromWindow(); +virtual void AllAttached(); +virtual void AllDetached(); +virtual void FrameResized(float width, float height); +virtual void MessageReceived(BMessage *message); +virtual void MouseDown(BPoint point); +virtual void MouseUp(BPoint point); +virtual void WindowActivated(bool active); +virtual void MouseMoved(BPoint point, uint32 transit, + const BMessage *message); +virtual void FrameMoved(BPoint newLocation); + +virtual BHandler *ResolveSpecifier(BMessage *message, + int32 index, + BMessage *specifier, + int32 what, + const char *property); + +virtual void ResizeToPreferred(); +virtual void GetPreferredSize(float *width, float *height); +virtual void MakeFocus(bool focused = true); +virtual status_t GetSupportedSuites(BMessage *message); + +virtual status_t Perform(perform_code d, void *arg); + +private: + +virtual void _ReservedBox1(); +virtual void _ReservedBox2(); + + BBox &operator=(const BBox &); + + void InitObject(BMessage *data = NULL); + void DrawPlain(); + void DrawFancy(); + void ClearAnyLabel(); + + char *fLabel; + BRect fBounds; + border_style fStyle; + BView *fLabelView; + uint32 _reserved[1]; +}; +//------------------------------------------------------------------------------ + +#endif // _BOX_H + +/* + * $Log $ + * + * $Id $ + * + */ diff --git a/headers/os/interface/Button.h b/headers/os/interface/Button.h new file mode 100644 index 0000000000..90777ca1ed --- /dev/null +++ b/headers/os/interface/Button.h @@ -0,0 +1,119 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: Button.h +// Author: Marc Flerackers (mflerackers@androme.be) +// Description: BButton displays and controls a button in a window. +//------------------------------------------------------------------------------ + +#ifndef _BUTTON_H +#define _BUTTON_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + + +// BButton class --------------------------------------------------------------- +class BButton : public BControl { + +public: + BButton(BRect frame, + const char *name, + const char *label, + BMessage *message, + uint32 resizingMode = B_FOLLOW_LEFT | B_FOLLOW_TOP, + uint32 flags = B_WILL_DRAW | B_NAVIGABLE); + +virtual ~BButton(); + + BButton(BMessage *archive); + +static BArchivable *Instantiate(BMessage *archive); +virtual status_t Archive (BMessage *archive, bool deep = true) const; + +virtual void Draw(BRect updateRect); +virtual void MouseDown(BPoint point); +virtual void AttachedToWindow(); +virtual void KeyDown(const char *bytes, int32 numBytes); +virtual void MakeDefault(bool flag); +virtual void SetLabel(const char *string); + bool IsDefault() const; + +virtual void MessageReceived(BMessage *message); +virtual void WindowActivated(bool active); +virtual void MouseMoved(BPoint point, uint32 transit, const BMessage *message); +virtual void MouseUp(BPoint point); +virtual void DetachedFromWindow(); +virtual void SetValue(int32 value); +virtual void GetPreferredSize (float *width, float *height); +virtual void ResizeToPreferred(); +virtual status_t Invoke(BMessage *message = NULL); +virtual void FrameMoved(BPoint newLocation); +virtual void FrameResized(float width, float height); + +virtual void MakeFocus(bool focused = true); +virtual void AllAttached(); +virtual void AllDetached(); + +virtual BHandler *ResolveSpecifier(BMessage *message, + int32 index, + BMessage *specifier, + int32 what, + const char *property); +virtual status_t GetSupportedSuites(BMessage *message); +virtual status_t Perform(perform_code d, void *arg); + +private: + +virtual void _ReservedButton1(); +virtual void _ReservedButton2(); +virtual void _ReservedButton3(); + + BButton &operator=(const BButton &); + + BRect DrawDefault(BRect bounds, bool enabled); + status_t Execute (); + + float fCachedWidth; + bool fDrawAsDefault; + uint32 _reserved[3]; +}; +//------------------------------------------------------------------------------ + +#endif // _BUTTON_H + +/* + * $Log $ + * + * $Id $ + * + */ diff --git a/headers/os/interface/CheckBox.h b/headers/os/interface/CheckBox.h new file mode 100644 index 0000000000..f918dc8987 --- /dev/null +++ b/headers/os/interface/CheckBox.h @@ -0,0 +1,111 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: CheckBox.h +// Author: Marc Flerackers (mflerackers@androme.be) +// Description: BCheckBox displays an on/off control. +//------------------------------------------------------------------------------ + +#ifndef _CHECK_BOX_H +#define _CHECK_BOX_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include +#include +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + + +// BCheckBox class ------------------------------------------------------------- +class BCheckBox : public BControl { + +public: + BCheckBox(BRect frame, + const char *name, + const char *label, + BMessage *message, + uint32 resizingMode = B_FOLLOW_LEFT | B_FOLLOW_TOP, + uint32 flags = B_WILL_DRAW | B_NAVIGABLE); +virtual ~BCheckBox(); + +/* Archiving */ + BCheckBox(BMessage *archive); +static BArchivable *Instantiate(BMessage *archive); +virtual status_t Archive(BMessage *archive, bool deep = true) const; + +virtual void Draw(BRect updateRect); +virtual void AttachedToWindow(); +virtual void MouseDown(BPoint point); + +virtual void MessageReceived(BMessage *message); +virtual void WindowActivated(bool active); +virtual void KeyDown(const char *bytes, int32 numBytes); +virtual void MouseUp(BPoint point); +virtual void MouseMoved(BPoint point, uint32 transit, const BMessage *message); +virtual void DetachedFromWindow(); +virtual void SetValue(int32 value); +virtual void GetPreferredSize(float *width, float *height); +virtual void ResizeToPreferred(); +virtual status_t Invoke(BMessage *message = NULL); +virtual void FrameMoved(BPoint newLocation); +virtual void FrameResized(float width, float height); + +virtual BHandler *ResolveSpecifier(BMessage *message, + int32 index, + BMessage *specifier, + int32 what, + const char *property); +virtual status_t GetSupportedSuites(BMessage *message); + +virtual void MakeFocus(bool focused = true); +virtual void AllAttached(); +virtual void AllDetached(); + +virtual status_t Perform(perform_code d, void *arg); + +private: + +virtual void _ReservedCheckBox1(); +virtual void _ReservedCheckBox2(); +virtual void _ReservedCheckBox3(); + + BCheckBox &operator=(const BCheckBox &); + + bool fOutlined; + uint32 _reserved[2]; +}; +//------------------------------------------------------------------------------ + +#endif // _CHECK_BOX_H + +/* + * $Log $ + * + * $Id $ + * + */ diff --git a/headers/os/interface/Control.h b/headers/os/interface/Control.h new file mode 100644 index 0000000000..aadb97003e --- /dev/null +++ b/headers/os/interface/Control.h @@ -0,0 +1,140 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: Control.h +// Author: Marc Flerackers (mflerackers@androme.be) +// Description: BControl is the base class for user-event handling objects. +//------------------------------------------------------------------------------ + +#ifndef _CONTROL_H +#define _CONTROL_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include +#include +#include /* For convenience */ +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- +enum { + B_CONTROL_OFF = 0, + B_CONTROL_ON = 1 +}; + +// Globals --------------------------------------------------------------------- + + +class BWindow; + +// BControl class -------------------------------------------------------------- +class BControl : public BView, public BInvoker { + +public: + BControl(BRect frame, + const char *name, + const char *label, + BMessage *message, + uint32 resizingMode, + uint32 flags); +virtual ~BControl(); + + BControl(BMessage *archive); +static BArchivable *Instantiate(BMessage *archive); +virtual status_t Archive(BMessage *archive, bool deep = true) const; + +virtual void WindowActivated(bool active); +virtual void AttachedToWindow(); +virtual void MessageReceived(BMessage *message); +virtual void MakeFocus(bool focused = true); +virtual void KeyDown(const char *bytes, int32 numBytes); +virtual void MouseDown(BPoint point); +virtual void MouseUp(BPoint point); +virtual void MouseMoved(BPoint point, uint32 transit, const BMessage *message); +virtual void DetachedFromWindow(); + +virtual void SetLabel(const char *string); + const char *Label() const; + +virtual void SetValue(int32 value); + int32 Value() const; + +virtual void SetEnabled(bool enabled); + bool IsEnabled() const; + +virtual void GetPreferredSize(float *width, float *height); +virtual void ResizeToPreferred(); + +virtual status_t Invoke(BMessage *message = NULL); +virtual BHandler *ResolveSpecifier(BMessage *message, + int32 index, + BMessage *specifier, + int32 what, + const char *property); +virtual status_t GetSupportedSuites(BMessage *message); + +virtual void AllAttached(); +virtual void AllDetached(); + +virtual status_t Perform(perform_code d, void *arg); + +protected: + + bool IsFocusChanging() const; + bool IsTracking() const; + void SetTracking(bool state); + + void SetValueNoUpdate(int32 value); + +private: + +virtual void _ReservedControl1(); +virtual void _ReservedControl2(); +virtual void _ReservedControl3(); +virtual void _ReservedControl4(); + + BControl &operator=(const BControl &); + + void InitData(BMessage *data = NULL); + + char *fLabel; + int32 fValue; + bool fEnabled; + bool fFocusChanging; + bool fTracking; + bool fWantsNav; + uint32 _reserved[4]; +}; +//------------------------------------------------------------------------------ + +#endif // _CONTROL_H + +/* + * $Log $ + * + * $Id $ + * + */ diff --git a/headers/os/interface/GraphicsDefs.h b/headers/os/interface/GraphicsDefs.h new file mode 100644 index 0000000000..a09db9171b --- /dev/null +++ b/headers/os/interface/GraphicsDefs.h @@ -0,0 +1,311 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: GraphicsDefs.h +// Author: Frans van Nispen +// Description: BMessageFilter class creates objects that filter +// in-coming BMessages. +//------------------------------------------------------------------------------ + +#ifndef _GRAPHICS_DEFS_H +#define _GRAPHICS_DEFS_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + + +//------------------------------------------------------------------------------ + +typedef struct pattern { + uint8 data[8]; +} pattern; + +extern _IMPEXP_BE const pattern B_SOLID_HIGH; +extern _IMPEXP_BE const pattern B_MIXED_COLORS; +extern _IMPEXP_BE const pattern B_SOLID_LOW; + +//------------------------------------------------------------------------------ + +typedef struct rgb_color { + uint8 red; + uint8 green; + uint8 blue; + uint8 alpha; +} rgb_color; + +//------------------------------------------------------------------------------ + +extern _IMPEXP_BE const rgb_color B_TRANSPARENT_COLOR; +extern _IMPEXP_BE const uint8 B_TRANSPARENT_MAGIC_CMAP8; +extern _IMPEXP_BE const uint16 B_TRANSPARENT_MAGIC_RGBA15; +extern _IMPEXP_BE const uint16 B_TRANSPARENT_MAGIC_RGBA15_BIG; +extern _IMPEXP_BE const uint32 B_TRANSPARENT_MAGIC_RGBA32; +extern _IMPEXP_BE const uint32 B_TRANSPARENT_MAGIC_RGBA32_BIG; + +extern _IMPEXP_BE const uint8 B_TRANSPARENT_8_BIT; +extern _IMPEXP_BE const rgb_color B_TRANSPARENT_32_BIT; + +//------------------------------------------------------------------------------ + +typedef struct color_map { + int32 id; + rgb_color color_list[256]; + uint8 inversion_map[256]; + uint8 index_map[32768]; +} color_map; + +typedef struct overlay_rect_limits { + uint16 horizontal_alignment; + uint16 vertical_alignment; + uint16 width_alignment; + uint16 height_alignment; + uint16 min_width; + uint16 max_width; + uint16 min_height; + uint16 max_height; + uint32 reserved[8]; +} overlay_rect_limits; + +typedef struct overlay_restrictions { + overlay_rect_limits source; + overlay_rect_limits destination; + float min_width_scale; + float max_width_scale; + float min_height_scale; + float max_height_scale; + uint32 reserved[8]; +} overlay_restrictions; + +//------------------------------------------------------------------------------ + +struct screen_id { int32 id; }; + +extern _IMPEXP_BE const struct screen_id B_MAIN_SCREEN_ID; + +//------------------------------------------------------------------------------ + +typedef enum +{ + B_NO_COLOR_SPACE = 0x0000, //* byte in memory order, high bit first + + // linear color space (little endian is the default) + B_RGB32 = 0x0008, //* B[7:0] G[7:0] R[7:0] -[7:0] + B_RGBA32 = 0x2008, // B[7:0] G[7:0] R[7:0] A[7:0] + B_RGB24 = 0x0003, // B[7:0] G[7:0] R[7:0] + B_RGB16 = 0x0005, // G[2:0],B[4:0] R[4:0],G[5:3] + B_RGB15 = 0x0010, // G[2:0],B[4:0] -[0],R[4:0],G[4:3] + B_RGBA15 = 0x2010, // G[2:0],B[4:0] A[0],R[4:0],G[4:3] + B_CMAP8 = 0x0004, // D[7:0] + B_GRAY8 = 0x0002, // Y[7:0] + B_GRAY1 = 0x0001, // Y0[0],Y1[0],Y2[0],Y3[0],Y4[0],Y5[0],Y6[0],Y7[0] + + // big endian version, when the encoding is not endianess independant + B_RGB32_BIG = 0x1008, // -[7:0] R[7:0] G[7:0] B[7:0] + B_RGBA32_BIG = 0x3008, // A[7:0] R[7:0] G[7:0] B[7:0] + B_RGB24_BIG = 0x1003, // R[7:0] G[7:0] B[7:0] + B_RGB16_BIG = 0x1005, // R[4:0],G[5:3] G[2:0],B[4:0] + B_RGB15_BIG = 0x1010, // -[0],R[4:0],G[4:3] G[2:0],B[4:0] + B_RGBA15_BIG = 0x3010, // A[0],R[4:0],G[4:3] G[2:0],B[4:0] + + // little-endian declarations, for completness + B_RGB32_LITTLE = B_RGB32, + B_RGBA32_LITTLE = B_RGBA32, + B_RGB24_LITTLE = B_RGB24, + B_RGB16_LITTLE = B_RGB16, + B_RGB15_LITTLE = B_RGB15, + B_RGBA15_LITTLE = B_RGBA15, + + // non linear color space -- note that these are here for exchange purposes; + // a BBitmap or BView may not necessarily support all these color spaces. + + // Loss/Saturation points are Y 16-235 (absoulte); Cb/Cr 16-240 (center 128) + + B_YCbCr422 = 0x4000, // Y0[7:0] Cb0[7:0] Y1[7:0] Cr0[7:0] Y2[7:0]... + // Cb2[7:0] Y3[7:0] Cr2[7:0] + B_YCbCr411 = 0x4001, // Cb0[7:0] Y0[7:0] Cr0[7:0] Y1[7:0] Cb4[7:0]... + // Y2[7:0] Cr4[7:0] Y3[7:0] Y4[7:0] Y5[7:0]... + // Y6[7:0] Y7[7:0] + B_YCbCr444 = 0x4003, // Y0[7:0] Cb0[7:0] Cr0[7:0] + B_YCbCr420 = 0x4004, // Non-interlaced only, Cb0 Y0 Y1 Cb2 Y2 Y3 + // on even scan lines, Cr0 Y0 Y1 Cr2 Y2 Y3 + // on odd scan lines + + // Extrema points are + // Y 0 - 207 (absolute) + // U -91 - 91 (offset 128) + // V -127 - 127 (offset 128) + // note that YUV byte order is different from YCbCr + // USE YCbCr, not YUV, when that's what you mean! + B_YUV422 = 0x4020, // U0[7:0] Y0[7:0] V0[7:0] Y1[7:0] ... + // U2[7:0] Y2[7:0] V2[7:0] Y3[7:0] + B_YUV411 = 0x4021, // U0[7:0] Y0[7:0] Y1[7:0] V0[7:0] Y2[7:0] Y3[7:0] + // U4[7:0] Y4[7:0] Y5[7:0] V4[7:0] Y6[7:0] Y7[7:0] + B_YUV444 = 0x4023, // U0[7:0] Y0[7:0] V0[7:0] U1[7:0] Y1[7:0] V1[7:0] + B_YUV420 = 0x4024, // Non-interlaced only, U0 Y0 Y1 U2 Y2 Y3 + // on even scan lines, V0 Y0 Y1 V2 Y2 Y3 + // on odd scan lines + B_YUV9 = 0x402C, // planar? 410? + B_YUV12 = 0x402D, // planar? 420? + + B_UVL24 = 0x4030, // U0[7:0] V0[7:0] L0[7:0] ... + B_UVL32 = 0x4031, // U0[7:0] V0[7:0] L0[7:0] X0[7:0]... + B_UVLA32 = 0x6031, // U0[7:0] V0[7:0] L0[7:0] A0[7:0]... + + B_LAB24 = 0x4032, // L0[7:0] a0[7:0] b0[7:0] ... (a is not alpha!) + B_LAB32 = 0x4033, // L0[7:0] a0[7:0] b0[7:0] X0[7:0] ... (b is not alpha!) + B_LABA32 = 0x6033, // L0[7:0] a0[7:0] b0[7:0] A0[7:0] ... (A is alpha) + + // red is at hue = 0 + + B_HSI24 = 0x4040, // H[7:0] S[7:0] I[7:0] + B_HSI32 = 0x4041, // H[7:0] S[7:0] I[7:0] X[7:0] + B_HSIA32 = 0x6041, // H[7:0] S[7:0] I[7:0] A[7:0] + + B_HSV24 = 0x4042, // H[7:0] S[7:0] V[7:0] + B_HSV32 = 0x4043, // H[7:0] S[7:0] V[7:0] X[7:0] + B_HSVA32 = 0x6043, // H[7:0] S[7:0] V[7:0] A[7:0] + + B_HLS24 = 0x4044, // H[7:0] L[7:0] S[7:0] + B_HLS32 = 0x4045, // H[7:0] L[7:0] S[7:0] X[7:0] + B_HLSA32 = 0x6045, // H[7:0] L[7:0] S[7:0] A[7:0] + + B_CMY24 = 0xC001, // C[7:0] M[7:0] Y[7:0] No gray removal done + B_CMY32 = 0xC002, // C[7:0] M[7:0] Y[7:0] X[7:0] No gray removal done + B_CMYA32 = 0xE002, // C[7:0] M[7:0] Y[7:0] A[7:0] No gray removal done + B_CMYK32 = 0xC003, // C[7:0] M[7:0] Y[7:0] K[7:0] + + // compatibility declarations + B_MONOCHROME_1_BIT = B_GRAY1, + B_GRAYSCALE_8_BIT = B_GRAY8, + B_COLOR_8_BIT = B_CMAP8, + B_RGB_32_BIT = B_RGB32, + B_RGB_16_BIT = B_RGB15, + B_BIG_RGB_32_BIT = B_RGB32_BIG, + B_BIG_RGB_16_BIT = B_RGB15_BIG +} color_space; + + +// Find out whether a specific color space is supported by BBitmaps. +// Support_flags will be set to what kinds of support are available. +// If support_flags is set to 0, false will be returned. +enum { + B_VIEWS_SUPPORT_DRAW_BITMAP = 0x1, + B_BITMAPS_SUPPORT_ATTACHED_VIEWS = 0x2 +}; +_IMPEXP_BE bool bitmaps_support_space(color_space space, uint32 * support_flags); + +//------------------------------------------------------------------------------ +// "pixel_chunk" is the native increment from one pixel starting on an integral byte +// to the next. "row_alignment" is the native alignment for pixel scanline starts. +// "pixels_per_chunk" is the number of pixels in a pixel_chunk. For instance, B_GRAY1 +// sets pixel_chunk to 1, row_alignment to 4 and pixels_per_chunk to 8, whereas +// B_RGB24 sets pixel_chunk to 3, row_alignment to 4 and pixels_per_chunk to 1. +//------------------------------------------------------------------------------ +_IMPEXP_BE status_t get_pixel_size_for(color_space space, size_t * pixel_chunk, + size_t * row_alignment, size_t * pixels_per_chunk); + + +enum buffer_orientation { + B_BUFFER_TOP_TO_BOTTOM, + B_BUFFER_BOTTOM_TO_TOP +}; + +enum buffer_layout { + B_BUFFER_NONINTERLEAVED = 1 +}; + +//------------------------------------------------------------------------------ + +enum drawing_mode { + B_OP_COPY, + B_OP_OVER, + B_OP_ERASE, + B_OP_INVERT, + B_OP_ADD, + B_OP_SUBTRACT, + B_OP_BLEND, + B_OP_MIN, + B_OP_MAX, + B_OP_SELECT, + B_OP_ALPHA +}; + +enum source_alpha { + B_PIXEL_ALPHA=0, + B_CONSTANT_ALPHA +}; + +enum alpha_function { + B_ALPHA_OVERLAY=0, + B_ALPHA_COMPOSITE +}; + +enum { + B_8_BIT_640x480 = 0x00000001, + B_8_BIT_800x600 = 0x00000002, + B_8_BIT_1024x768 = 0x00000004, + B_8_BIT_1280x1024 = 0x00000008, + B_8_BIT_1600x1200 = 0x00000010, + B_16_BIT_640x480 = 0x00000020, + B_16_BIT_800x600 = 0x00000040, + B_16_BIT_1024x768 = 0x00000080, + B_16_BIT_1280x1024 = 0x00000100, + B_16_BIT_1600x1200 = 0x00000200, + B_32_BIT_640x480 = 0x00000400, + B_32_BIT_800x600 = 0x00000800, + B_32_BIT_1024x768 = 0x00001000, + B_32_BIT_1280x1024 = 0x00002000, + B_32_BIT_1600x1200 = 0x00004000, + B_8_BIT_1152x900 = 0x00008000, + B_16_BIT_1152x900 = 0x00010000, + B_32_BIT_1152x900 = 0x00020000, + B_15_BIT_640x480 = 0x00040000, + B_15_BIT_800x600 = 0x00080000, + B_15_BIT_1024x768 = 0x00100000, + B_15_BIT_1280x1024 = 0x00200000, + B_15_BIT_1600x1200 = 0x00400000, + B_15_BIT_1152x900 = 0x00800000, + + // do not use B_FAKE_DEVICE--it will go away! + B_FAKE_DEVICE = 0x40000000, + B_8_BIT_640x400 = (int)0x80000000 +}; + +#endif // _GRAPHICSDEFS_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/headers/os/interface/Input.h b/headers/os/interface/Input.h new file mode 100644 index 0000000000..263a94d2f0 --- /dev/null +++ b/headers/os/interface/Input.h @@ -0,0 +1,88 @@ +/****************************************************************************** +/ +/ File: Input.h +/ +/ Description: Functions and class to manage input devices. +/ +/ Copyright 1998, Be Incorporated, All Rights Reserved. +/ +******************************************************************************/ + +#ifndef _INPUT_H +#define _INPUT_H + +#include +#include +#include + + +enum input_method_op { + B_INPUT_METHOD_STARTED = 0, + B_INPUT_METHOD_STOPPED = 1, + B_INPUT_METHOD_CHANGED = 2, + B_INPUT_METHOD_LOCATION_REQUEST = 3 +}; + + +enum input_device_type { + B_POINTING_DEVICE = 0, + B_KEYBOARD_DEVICE = 1, + B_UNDEFINED_DEVICE = 2 +}; + +/* + what == B_INPUT_DEVICES_CHANGED + FindString("name", name_of_device); + FindInt32("opcode", input_device_notification); +*/ + +enum input_device_notification { + B_INPUT_DEVICE_ADDED = 0x0001, + B_INPUT_DEVICE_STARTED = 0x0002, + B_INPUT_DEVICE_STOPPED = 0x0004, + B_INPUT_DEVICE_REMOVED = 0x0008 +}; + + +class BInputDevice; + + +_IMPEXP_BE BInputDevice* find_input_device(const char *name); +_IMPEXP_BE status_t get_input_devices(BList *list); +_IMPEXP_BE status_t watch_input_devices(BMessenger target, bool start); + + +class BInputDevice { +public: + ~BInputDevice(); + + const char* Name() const; + input_device_type Type() const; + bool IsRunning() const; + + status_t Start(); + status_t Stop(); + status_t Control(uint32 code, + BMessage *message); + + static status_t Start(input_device_type type); + static status_t Stop(input_device_type type); + static status_t Control(input_device_type type, + uint32 code, + BMessage *message); + +private: + friend BInputDevice* find_input_device(const char *name); + friend status_t get_input_devices(BList *list); + + BInputDevice(); + void set_name_and_type(const char *name, + input_device_type type); + + char* fName; + input_device_type fType; + uint32 _reserved[4]; +}; + + +#endif diff --git a/headers/os/interface/InterfaceDefs.h b/headers/os/interface/InterfaceDefs.h new file mode 100644 index 0000000000..4c1e6aa5dc --- /dev/null +++ b/headers/os/interface/InterfaceDefs.h @@ -0,0 +1,366 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: InterfaceDefs.h +// Author: Erik Jaesler (erik@cgsoftware.com) +// Description: General Interface Kit definitions and global functions. +//------------------------------------------------------------------------------ + +#ifndef _INTERFACE_DEFS_H +#define _INTERFACE_DEFS_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +class BRect; + +/*----------------------------------------------------------------*/ + +struct key_info { + uint32 modifiers; + uint8 key_states[16]; +}; + +/*----------------------------------------------------------------*/ + +#define B_UTF8_ELLIPSIS "\xE2\x80\xA6" +#define B_UTF8_OPEN_QUOTE "\xE2\x80\x9C" +#define B_UTF8_CLOSE_QUOTE "\xE2\x80\x9D" +#define B_UTF8_COPYRIGHT "\xC2\xA9" +#define B_UTF8_REGISTERED "\xC2\xAE" +#define B_UTF8_TRADEMARK "\xE2\x84\xA2" +#define B_UTF8_SMILING_FACE "\xE2\x98\xBB" +#define B_UTF8_HIROSHI "\xE5\xBC\x98" + +/*----------------------------------------------------------------*/ + +enum { B_BACKSPACE = 0x08, + B_RETURN = 0x0a, + B_ENTER = 0x0a, + B_SPACE = 0x20, + B_TAB = 0x09, + B_ESCAPE = 0x1b, + B_SUBSTITUTE = 0x1a, + + B_LEFT_ARROW = 0x1c, + B_RIGHT_ARROW = 0x1d, + B_UP_ARROW = 0x1e, + B_DOWN_ARROW = 0x1f, + + B_INSERT = 0x05, + B_DELETE = 0x7f, + B_HOME = 0x01, + B_END = 0x04, + B_PAGE_UP = 0x0b, + B_PAGE_DOWN = 0x0c, + + B_FUNCTION_KEY = 0x10 }; + +enum { B_F1_KEY = 0x02, + B_F2_KEY = 0x03, + B_F3_KEY = 0x04, + B_F4_KEY = 0x05, + B_F5_KEY = 0x06, + B_F6_KEY = 0x07, + B_F7_KEY = 0x08, + B_F8_KEY = 0x09, + B_F9_KEY = 0x0a, + B_F10_KEY = 0x0b, + B_F11_KEY = 0x0c, + B_F12_KEY = 0x0d, + B_PRINT_KEY = 0x0e, + B_SCROLL_KEY = 0x0f, + B_PAUSE_KEY = 0x10 }; + +struct key_map { + uint32 version; + uint32 caps_key; + uint32 scroll_key; + uint32 num_key; + uint32 left_shift_key; + uint32 right_shift_key; + uint32 left_command_key; + uint32 right_command_key; + uint32 left_control_key; + uint32 right_control_key; + uint32 left_option_key; + uint32 right_option_key; + uint32 menu_key; + uint32 lock_settings; + int32 control_map[128]; + int32 option_caps_shift_map[128]; + int32 option_caps_map[128]; + int32 option_shift_map[128]; + int32 option_map[128]; + int32 caps_shift_map[128]; + int32 caps_map[128]; + int32 shift_map[128]; + int32 normal_map[128]; + int32 acute_dead_key[32]; + int32 grave_dead_key[32]; + int32 circumflex_dead_key[32]; + int32 dieresis_dead_key[32]; + int32 tilde_dead_key[32]; + uint32 acute_tables; + uint32 grave_tables; + uint32 circumflex_tables; + uint32 dieresis_tables; + uint32 tilde_tables; +}; + +struct mouse_map { + uint32 left; + uint32 right; + uint32 middle; +}; + +/*----------------------------------------------------------------*/ + +enum border_style { + B_PLAIN_BORDER, + B_FANCY_BORDER, + B_NO_BORDER +}; + +/*----------------------------------------------------------------*/ + +enum orientation { + B_HORIZONTAL, + B_VERTICAL +}; + +/*----------------------------------------------------------------*/ + +enum button_width { + B_WIDTH_AS_USUAL, + B_WIDTH_FROM_WIDEST, + B_WIDTH_FROM_LABEL +}; + +/*----------------------------------------------------------------*/ + +enum join_mode { + B_ROUND_JOIN=0, + B_MITER_JOIN, + B_BEVEL_JOIN, + B_BUTT_JOIN, + B_SQUARE_JOIN +}; + +enum cap_mode { + B_ROUND_CAP=B_ROUND_JOIN, + B_BUTT_CAP=B_BUTT_JOIN, + B_SQUARE_CAP=B_SQUARE_JOIN +}; + +const float B_DEFAULT_MITER_LIMIT = 10.0F; + +/*----------------------------------------------------------------*/ + +struct scroll_bar_info { + bool proportional; + bool double_arrows; + int32 knob; + int32 min_knob_size; +}; + +/*----------------------------------------------------------------*/ + +enum alignment { + B_ALIGN_LEFT, + B_ALIGN_RIGHT, + B_ALIGN_CENTER +}; + +enum vertical_alignment { + B_ALIGN_TOP = 0x10L, + B_ALIGN_MIDDLE = 0x20, + B_ALIGN_BOTTOM = 0x30, + B_ALIGN_NO_VERTICAL = -1L +}; + +/*----------------------------------------------------------------*/ + +enum { + B_CONTROL_TABLE = 0x00000001, + B_OPTION_CAPS_SHIFT_TABLE = 0x00000002, + B_OPTION_CAPS_TABLE = 0x00000004, + B_OPTION_SHIFT_TABLE = 0x00000008, + B_OPTION_TABLE = 0x00000010, + B_CAPS_SHIFT_TABLE = 0x00000020, + B_CAPS_TABLE = 0x00000040, + B_SHIFT_TABLE = 0x00000080, + B_NORMAL_TABLE = 0x00000100 +}; + +/*----------------------------------------------------------------*/ + +enum { + B_SHIFT_KEY = 0x00000001, + B_COMMAND_KEY = 0x00000002, + B_CONTROL_KEY = 0x00000004, + B_CAPS_LOCK = 0x00000008, + B_SCROLL_LOCK = 0x00000010, + B_NUM_LOCK = 0x00000020, + B_OPTION_KEY = 0x00000040, + B_MENU_KEY = 0x00000080, + B_LEFT_SHIFT_KEY = 0x00000100, + B_RIGHT_SHIFT_KEY = 0x00000200, + B_LEFT_COMMAND_KEY = 0x00000400, + B_RIGHT_COMMAND_KEY = 0x00000800, + B_LEFT_CONTROL_KEY = 0x00001000, + B_RIGHT_CONTROL_KEY = 0x00002000, + B_LEFT_OPTION_KEY = 0x00004000, + B_RIGHT_OPTION_KEY = 0x00008000 +}; + +/*----------------------------------------------------------------*/ + +enum bitmap_tiling { + B_TILE_BITMAP_X = 0x00000001, + B_TILE_BITMAP_Y = 0x00000002, + B_TILE_BITMAP = 0x00000003 +}; + +enum overlay_options { + B_OVERLAY_FILTER_HORIZONTAL = 0x00010000, + B_OVERLAY_FILTER_VERTICAL = 0x00020000, + B_OVERLAY_MIRROR = 0x00040000, + B_OVERLAY_TRANSFER_CHANNEL = 0x00080000 +}; + +/*----------------------------------------------------------------*/ + +_IMPEXP_BE status_t get_deskbar_frame(BRect *frame); + +_IMPEXP_BE const color_map *system_colors(); + +_IMPEXP_BE status_t set_screen_space(int32 index, uint32 res, + bool stick = true); + +_IMPEXP_BE status_t get_scroll_bar_info(scroll_bar_info *info); +_IMPEXP_BE status_t set_scroll_bar_info(scroll_bar_info *info); + +_IMPEXP_BE status_t get_mouse_type(int32 *type); +_IMPEXP_BE status_t set_mouse_type(int32 type); +_IMPEXP_BE status_t get_mouse_map(mouse_map *map); +_IMPEXP_BE status_t set_mouse_map(mouse_map *map); +_IMPEXP_BE status_t get_click_speed(bigtime_t *speed); +_IMPEXP_BE status_t set_click_speed(bigtime_t speed); +_IMPEXP_BE status_t get_mouse_speed(int32 *speed); +_IMPEXP_BE status_t set_mouse_speed(int32 speed); +_IMPEXP_BE status_t get_mouse_acceleration(int32 *speed); +_IMPEXP_BE status_t set_mouse_acceleration(int32 speed); + +_IMPEXP_BE status_t get_key_repeat_rate(int32 *rate); +_IMPEXP_BE status_t set_key_repeat_rate(int32 rate); +_IMPEXP_BE status_t get_key_repeat_delay(bigtime_t *delay); +_IMPEXP_BE status_t set_key_repeat_delay(bigtime_t delay); + +_IMPEXP_BE uint32 modifiers(); +_IMPEXP_BE status_t get_key_info(key_info *info); +_IMPEXP_BE void get_key_map(key_map **map, char **key_buffer); +_IMPEXP_BE status_t get_keyboard_id(uint16 *id); +_IMPEXP_BE void set_modifier_key(uint32 modifier, uint32 key); +_IMPEXP_BE void set_keyboard_locks(uint32 modifiers); + +_IMPEXP_BE rgb_color keyboard_navigation_color(); + +_IMPEXP_BE int32 count_workspaces(); +_IMPEXP_BE void set_workspace_count(int32 count); +_IMPEXP_BE int32 current_workspace(); +_IMPEXP_BE void activate_workspace(int32 workspace); + +_IMPEXP_BE bigtime_t idle_time(); + +_IMPEXP_BE void run_select_printer_panel(); +_IMPEXP_BE void run_add_printer_panel(); +_IMPEXP_BE void run_be_about(); + +_IMPEXP_BE void set_focus_follows_mouse(bool follow); +_IMPEXP_BE bool focus_follows_mouse(); + +enum mode_mouse { + B_NORMAL_MOUSE = 0, + B_FOCUS_FOLLOWS_MOUSE = 1, + B_WARP_MOUSE = 3, + B_INSTANT_WARP_MOUSE = 7 +}; + +_IMPEXP_BE void set_mouse_mode(mode_mouse mode); +_IMPEXP_BE mode_mouse mouse_mode(); + +enum color_which { + B_PANEL_BACKGROUND_COLOR = 1, + B_MENU_BACKGROUND_COLOR = 2, + B_MENU_SELECTION_BACKGROUND_COLOR = 6, + B_MENU_ITEM_TEXT_COLOR = 7, + B_MENU_SELECTED_ITEM_TEXT_COLOR = 8, + B_WINDOW_TAB_COLOR = 3, + B_KEYBOARD_NAVIGATION_COLOR = 4, + B_DESKTOP_COLOR = 5 +}; + +_IMPEXP_BE rgb_color ui_color(color_which which); +_IMPEXP_BE rgb_color tint_color(rgb_color color, float tint); + +extern "C" status_t _init_interface_kit_(); + /* effects on standard gray level */ +const float B_LIGHTEN_MAX_TINT = 0.0F; /* 216 --> 255.0 (255) */ +const float B_LIGHTEN_2_TINT = 0.385F; /* 216 --> 240.0 (240) */ +const float B_LIGHTEN_1_TINT = 0.590F; /* 216 --> 232.0 (232) */ + +const float B_NO_TINT = 1.0F; /* 216 --> 216.0 (216) */ + +const float B_DARKEN_1_TINT = 1.147F; /* 216 --> 184.2 (184) */ +const float B_DARKEN_2_TINT = 1.295F; /* 216 --> 152.3 (152) */ +const float B_DARKEN_3_TINT = 1.407F; /* 216 --> 128.1 (128) */ +const float B_DARKEN_4_TINT = 1.555F; /* 216 --> 96.1 (96) */ +const float B_DARKEN_MAX_TINT = 2.0F; /* 216 --> 0.0 (0) */ + +const float B_DISABLED_LABEL_TINT = B_DARKEN_3_TINT; +const float B_HIGHLIGHT_BACKGROUND_TINT = B_DARKEN_2_TINT; +const float B_DISABLED_MARK_TINT = B_LIGHTEN_2_TINT; + +/*-------------------------------------------------------------*/ +/*-------------------------------------------------------------*/ + +#endif // _INTERFACE_DEFS_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/headers/os/interface/ListItem.h b/headers/os/interface/ListItem.h new file mode 100644 index 0000000000..0fa1274b47 --- /dev/null +++ b/headers/os/interface/ListItem.h @@ -0,0 +1,103 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// File: ListItem.h +// +// Description: BListView represents a one-dimensional list view. +// +// Copyright 2001, Ulrich Wimboeck +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _LIST_ITEM_H +#define _LIST_ITEM_H + +#include +#include +#include + +class BFont ; +class BMessage ; +class BOutlineListView ; +class BView ; + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS +{ +#endif + +/*----------------------------------------------------------------*/ +/*----- BListItem class ------------------------------------------*/ + +/** + * A BListItem represents a single item in a BListView (or + * BOutlineListView). The BListItem object provides drawing + * instructions that can draw the item (through DrawItem()), and + * keeps track of the item's state. To use a BListItem, you must + * add it to a BListView through BListView::AddItem() + * (BOutlineListView provides additional item-adding functions). + * The BListView object provides the drawing context for the + * BListItem's DrawItem() function. + * + * BListItem is abstract; each subclass must implement DrawItem(). + * BStringItem—the only BListItem subclass provided by + * Be—implements the function to draw the item as a line of text. + */ + +class BListItem : public BArchivable +{ +public: + BListItem(uint32 outlineLevel = 0, bool expanded = true) ; + BListItem(BMessage* data) ; +virtual ~BListItem() ; + +virtual status_t Archive(BMessage* data, bool deep = true) const ; + + float Height() const ; + float Width() const ; + bool IsSelected() const ; + void Select() ; + void Deselect() ; + +virtual void SetEnabled(bool on) ; + bool IsEnabled() const ; + + void SetHeight(float height) ; + void SetWidth(float width) ; +virtual void DrawItem(BView* owner, BRect bounds, bool complete = false) = 0 ; +virtual void Update(BView* owner, const BFont* font) ; + +virtual status_t Perform(perform_code d, void* arg) ; + + bool IsExpanded() const ; + void SetExpanded(bool expanded) ; + uint32 OutlineLevel() const ; + +/*----- Private or reserved -----------------------------------------*/ +private: +friend class BOutlineListView ; + + BListItem(const BListItem&) ; + + BListItem& operator=(const BListItem&) ; + + float fWidth ; + float fHeight ; + uint32 fLevel ; + bool fSelected ; + bool fEnabled ; + + bool fExpanded ; + bool fHasSubItems ; + bool fVisible ; +} ; + +// in the interface kit the BStringItem class is declared within ListItem.h +#ifndef USE_OPENBEOS_NAMESPACE +#include "StringItem.h" +#endif + +#ifdef USE_OPENBEOS_NAMESPACE +} +#endif + +#endif /* _LIST_ITEM_H */ diff --git a/headers/os/interface/ListView.h b/headers/os/interface/ListView.h new file mode 100644 index 0000000000..93ca391ccd --- /dev/null +++ b/headers/os/interface/ListView.h @@ -0,0 +1,213 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// File: ListView.h +// +// Description: BListView represents a one-dimensional list view. +// +// Copyright 2001, Ulrich Wimboeck +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _LIST_VIEW_H +#define _LIST_VIEW_H + +#include +#include +#include +#include +#include + +struct track_data ; + +enum list_view_type { + B_SINGLE_SELECTION_LIST, + B_MULTIPLE_SELECTION_LIST +}; + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS +{ +#endif + +/*----------------------------------------------------------------*/ +/*----- BListView class ------------------------------------------*/ + +/** + * A BListView displays a list of items the user can select and + * invoke. Each item is a kind of BListItem object. The BListView + * manages the layout of the list and the interaction with the user; + * it leaves the display of each item to the BListItem objects. + * A BListItem is not a view and draws only when called upon by + * the BListView. + */ + +class BListView : public BView, public BInvoker +{ + +public: +BListView(BRect frame, const char* name, + list_view_type type = B_SINGLE_SELECTION_LIST, + uint32 resizeMask = B_FOLLOW_LEFT | B_FOLLOW_TOP, + uint32 flags = B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE) ; + +BListView(BMessage* data) ; +virtual ~BListView() ; + +static BArchivable* Instantiate(BMessage* data) ; +virtual status_t Archive(BMessage* data, bool deep = true) const ; +virtual void Draw(BRect updateRect) ; +virtual void MessageReceived(BMessage* msg) ; +virtual void MouseDown(BPoint where) ; +virtual void KeyDown(const char* bytes, int32 numBytes) ; +virtual void MakeFocus(bool state = true) ; +virtual void FrameResized(float newWidth, float newHeight) ; +virtual void TargetedByScrollView(BScrollView* scroller) ; + void ScrollTo(float x, float y) ; +virtual void ScrollTo(BPoint where) ; +virtual bool AddItem(BListItem* item) ; +virtual bool AddItem(BListItem* item, int32 atIndex) ; +virtual bool AddList(BList* newItems) ; +virtual bool AddList(BList* newItems, int32 atIndex) ; +virtual bool RemoveItem(BListItem* item) ; +virtual BListItem* RemoveItem(int32 index) ; +virtual bool RemoveItems(int32 index, int32 count) ; + +virtual void SetSelectionMessage(BMessage* message) ; +virtual void SetInvocationMessage(BMessage* message) ; + + BMessage* SelectionMessage() const ; + uint32 SelectionCommand() const ; + BMessage* InvocationMessage() const ; + uint32 InvocationCommand() const ; + +virtual void SetListType(list_view_type type) ; + list_view_type ListType() const ; + + BListItem* ItemAt(int32 index) const ; + int32 IndexOf(BPoint point) const ; + int32 IndexOf(BListItem *item) const ; + BListItem* FirstItem() const ; + BListItem* LastItem() const ; + bool HasItem(BListItem *item) const ; + int32 CountItems() const ; +virtual void MakeEmpty() ; + bool IsEmpty() const ; + void DoForEach(bool (*func)(BListItem *)) ; + void DoForEach(bool (*func)(BListItem *, void *), void *) ; + const BListItem **Items() const ; + void InvalidateItem(int32 index) ; + void ScrollToSelection() ; + + void Select(int32 index, bool extend = false) ; + void Select(int32 from, int32 to, bool extend = false) ; + bool IsItemSelected(int32 index) const ; + int32 CurrentSelection(int32 index = 0) const ; +virtual status_t Invoke(BMessage* msg = NULL) ; + + void DeselectAll() ; + void DeselectExcept(int32 except_from, int32 except_to) ; + void Deselect(int32 index) ; + +virtual void SelectionChanged() ; + + void SortItems(int (*cmp)(const void *, const void *)) ; + + +/* These functions bottleneck through DoMiscellaneous() */ + bool SwapItems(int32 a, int32 b) ; + bool MoveItem(int32 from, int32 to) ; + bool ReplaceItem(int32 index, BListItem* item) ; + +virtual void AttachedToWindow() ; +virtual void FrameMoved(BPoint new_position) ; + + BRect ItemFrame(int32 index) ; + +virtual BHandler* ResolveSpecifier(BMessage* msg, + int32 index, + BMessage* specifier, + int32 form, + const char* property) ; +virtual status_t GetSupportedSuites(BMessage* data) ; + +virtual status_t Perform(perform_code d, void* arg) ; + +virtual void WindowActivated(bool state) ; +virtual void MouseUp(BPoint pt) ; +virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg) ; +virtual void DetachedFromWindow() ; +virtual bool InitiateDrag(BPoint pt, int32 itemIndex, + bool initialySelected) ; + +virtual void ResizeToPreferred() ; +virtual void GetPreferredSize(float* width, float* height) ; +virtual void AllAttached() ; +virtual void AllDetached() ; + +protected: + + enum MiscCode { B_NO_OP, B_REPLACE_OP, B_MOVE_OP, B_SWAP_OP } ; + union MiscData { + struct Spare { int32 data[5] ; } ; + struct Replace { int32 index ; BListItem* item ; } replace ; + struct Move { int32 from; int32 to; } move ; + struct Swap { int32 a ; int32 b ; } swap ; + } ; + +virtual bool DoMiscellaneous(MiscCode code, MiscData* data) ; + +/*----- Private or reserved -----------------------------------------*/ + +private: + friend class BOutlineListView ; // try to remove friend classes + + BListView& operator=(const BListView&) ; + + void InitObject(list_view_type type) ; + void FixupScrollBar() ; + void InvalidateFrom(int32 index) ; + status_t PostMsg(BMessage* msg) ; + void FontChanged() ; + int32 RangeCheck(int32 index) ; + bool _Select(int32 index, bool extend) ; + bool _Select(int32 from, int32 to, bool extend) ; + bool _Deselect(int32 index) ; + void Deselect(int32 from, int32 to) ; + bool _DeselectAll(int32 except_from, int32 except_to) ; + void PerformDelayedSelect() ; + bool TryInitiateDrag(BPoint where) ; + int32 CalcFirstSelected(int32 after) ; + int32 CalcLastSelected(int32 before) ; +virtual void DrawItem(BListItem* item, BRect itemRect, + bool complete = false) ; + + bool DoSwapItems(int32 a, int32 b) ; + bool DoMoveItem(int32 from, int32 to) ; + bool DoReplaceItem(int32 index, BListItem* item) ; + void RescanSelection(int32 from, int32 to) ; + void DoMouseUp(BPoint where) ; + void DoMouseMoved(BPoint where) ; + + BList fList ; + list_view_type fListType ; + int32 fFirstSelected ; + int32 fLastSelected ; + int32 fAnchorIndex ; + float fWidth ; + BMessage* fSelectMessage ; + BScrollView* fScrollView ; + track_data* fTrack ; +} ; + +inline void BListView::ScrollTo(float x, float y) + /* OK, no private parts */ + { ScrollTo(BPoint(x, y)) ; } + +/*-------------------------------------------------------------*/ +/*-------------------------------------------------------------*/ + +#ifdef USE_OPENBEOS_NAMESPACE +} +#endif + +#endif /* _LIST_VIEW_H */ diff --git a/headers/os/interface/Point.h b/headers/os/interface/Point.h new file mode 100644 index 0000000000..5d7684fdf4 --- /dev/null +++ b/headers/os/interface/Point.h @@ -0,0 +1,114 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: Point.h +// Author: Frans van Nispen +// Description: BPoint represents a single x,y coordinate. +//------------------------------------------------------------------------------ +#ifndef _POINT_H +#define _POINT_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + + +class BRect; + +// BPoint class ---------------------------------------------------------------- +class BPoint { +public: + float x; + float y; + + BPoint(); + BPoint(float X, float Y); + BPoint(const BPoint &p); + + BPoint &operator=(const BPoint &p); + void Set(float X, float Y); + + void ConstrainTo(BRect r); + void PrintToStream() const; + + BPoint operator+(const BPoint &p) const; + BPoint operator-(const BPoint &p) const; + BPoint& operator+=(const BPoint &p); + BPoint& operator-=(const BPoint &p); + + bool operator!=(const BPoint &p) const; + bool operator==(const BPoint &p) const; +}; +//------------------------------------------------------------------------------ + +extern _IMPEXP_BE const BPoint B_ORIGIN; // returns (0,0) + +//------------------------------------------------------------------------------ +inline BPoint::BPoint() +{ + x = y = 0; +} +//------------------------------------------------------------------------------ +inline BPoint::BPoint(float X, float Y) +{ + x = X; + y = Y; +} +//------------------------------------------------------------------------------ +inline BPoint::BPoint(const BPoint& pt) +{ + x = pt.x; + y = pt.y; +} +//------------------------------------------------------------------------------ +inline BPoint &BPoint::operator=(const BPoint& from) +{ + x = from.x; + y = from.y; + return *this; +} +//------------------------------------------------------------------------------ +inline void BPoint::Set(float X, float Y) +{ + x = X; + y = Y; +} +//------------------------------------------------------------------------------ + +#endif // _POINT_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/headers/os/interface/PrintJob.h b/headers/os/interface/PrintJob.h new file mode 100644 index 0000000000..f27a2c9e1e --- /dev/null +++ b/headers/os/interface/PrintJob.h @@ -0,0 +1,123 @@ +/******************************************************************************* +/ +/ File: PrintJob.h +/ +/ Description: BPrintJob runs a printing session. +/ +/ Copyright 1996-98, Be Incorporated, All Rights Reserved +/ +*******************************************************************************/ + +#ifndef _PRINTSESSION_H +#define _PRINTSESSION_H + +#include +#include /* For convenience */ +#include + +class BView; + +/*----------------------------------------------------------------*/ +/*----- BPrintJob related structures -----------------------------*/ + +struct print_file_header { + int32 version; + int32 page_count; + off_t first_page; + int32 _reserved_3_; + int32 _reserved_4_; + int32 _reserved_5_; +}; + +struct _page_header_; + +/*----------------------------------------------------------------*/ +/*----- BPrintJob class ------------------------------------------*/ + +class BPrintJob { +public: + + enum // These values are returned by PrinterType() + { + B_BW_PRINTER = 0, + B_COLOR_PRINTER + }; + + + BPrintJob(const char *job_name); +virtual ~BPrintJob(); + + void BeginJob(); + void CommitJob(); + status_t ConfigJob(); + void CancelJob(); + + status_t ConfigPage(); + void SpoolPage(); + + bool CanContinue(); + +virtual void DrawView(BView *a_view, BRect a_rect, BPoint where); + + BMessage *Settings() /* const */ ; + void SetSettings(BMessage *a_msg); + bool IsSettingsMessageValid(BMessage *a_msg) const; + + BRect PaperRect(); + BRect PrintableRect(); + void GetResolution(int32 *xdpi, int32 *ydpi); + + int32 FirstPage() /* const */ ; + int32 LastPage() /* const */ ; + int32 PrinterType(void * = NULL) const; + + +/*----- Private or reserved -----------------------------------------*/ +private: + +virtual void _ReservedPrintJob1(); +virtual void _ReservedPrintJob2(); +virtual void _ReservedPrintJob3(); +virtual void _ReservedPrintJob4(); + + BPrintJob(const BPrintJob &); + BPrintJob &operator=(const BPrintJob &); + + void RecurseView(BView *v, BPoint origin, BPicture *p, BRect r); + void MangleName(char *filename); + void HandlePageSetup(BMessage *setup); + bool HandlePrintSetup(BMessage *setup); + + void NewPage(); + void EndLastPage(); + + void AddSetupSpec(); + void AddPicture(BPicture *picture, BRect *rect, BPoint where); + + char* GetCurrentPrinterName() const; + void LoadDefaultSettings(); + + char * print_job_name; + int32 page_number; + BFile * spoolFile; + print_file_header current_header; + BRect paper_size; + BRect usable_size; + int pr_error; + char spool_file_name[256]; + BMessage *setup_msg; + BMessage *default_setup_msg; + char stop_the_show; + int32 first_page; + int32 last_page; + short v_xres; + short v_yres; + _page_header_ * m_curPageHeader; + off_t m_curPageHeaderOffset; + uint32 _reserved[2]; +}; + +/*-------------------------------------------------------------*/ +/*-------------------------------------------------------------*/ + +#endif /* _PRINTSESSION_H */ diff --git a/headers/os/interface/RadioButton.h b/headers/os/interface/RadioButton.h new file mode 100644 index 0000000000..973d0c1522 --- /dev/null +++ b/headers/os/interface/RadioButton.h @@ -0,0 +1,115 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: RadioButton.cpp +// Author: Marc Flerackers (mflerackers@androme.be) +// Description: BRadioButton represents a single on/off button. All +// sibling BRadioButton objects comprise a single +// "multiple choice" control. +//------------------------------------------------------------------------------ + +#ifndef _RADIO_BUTTON_H +#define _RADIO_BUTTON_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +// BRadioButton class ---------------------------------------------------------- +class BRadioButton : public BControl { + +public: + BRadioButton(BRect frame, + const char *name, + const char *label, + BMessage *message, + uint32 resizMask = B_FOLLOW_LEFT | B_FOLLOW_TOP, + uint32 flags = B_WILL_DRAW | B_NAVIGABLE); + + BRadioButton(BMessage *archive); +virtual ~BRadioButton(); + +static BArchivable *Instantiate(BMessage *archive); +virtual status_t Archive(BMessage *archive, bool deep = true) const; + +virtual void Draw(BRect updateRect); +virtual void MouseDown(BPoint point); +virtual void AttachedToWindow(); +virtual void KeyDown(const char *bytes, int32 numBytes); +virtual void SetValue(int32 value); +virtual void GetPreferredSize(float *width, float *height); +virtual void ResizeToPreferred(); +virtual status_t Invoke(BMessage *message = NULL); + +virtual void MessageReceived(BMessage *message); +virtual void WindowActivated(bool active); +virtual void MouseUp(BPoint point); +virtual void MouseMoved(BPoint point, uint32 transit, const BMessage *message); +virtual void DetachedFromWindow(); +virtual void FrameMoved(BPoint newLocation); +virtual void FrameResized(float width, float height); + +virtual BHandler *ResolveSpecifier(BMessage *message, + int32 index, + BMessage *specifier, + int32 what, + const char *property); + +virtual void MakeFocus(bool focused = true); +virtual void AllAttached(); +virtual void AllDetached(); +virtual status_t GetSupportedSuites(BMessage *message); + +virtual status_t Perform(perform_code d, void *arg); + +private: +friend status_t _init_interface_kit_(); + +virtual void _ReservedRadioButton1(); +virtual void _ReservedRadioButton2(); + + BRadioButton &operator=(const BRadioButton &); +static BBitmap *sBitmaps[2][3]; + + bool fOutlined; + uint32 _reserved[2]; +}; +//------------------------------------------------------------------------------ + +#endif // _RADIO_BUTTON_H + +/* + * $Log $ + * + * $Id $ + * + */ diff --git a/headers/os/interface/Rect.h b/headers/os/interface/Rect.h new file mode 100644 index 0000000000..a28b215049 --- /dev/null +++ b/headers/os/interface/Rect.h @@ -0,0 +1,223 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: Rect.h +// Author: Frans van Nispen (xlr8@tref.nl) +// Description: BRect represents a rectangular area. +//------------------------------------------------------------------------------ + +#ifndef _RECT_H +#define _RECT_H + +// Standard Includes ----------------------------------------------------------- +#include + +// System Includes ------------------------------------------------------------- +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + + +// BRect class ----------------------------------------------------------------- +class BRect { +public: + float left; + float top; + float right; + float bottom; + + BRect(); + BRect(const BRect &r); + BRect(float l, float t, float r, float b); + BRect(BPoint lt, BPoint rb); + + BRect &operator=(const BRect &r); + void Set(float l, float t, float r, float b); + + void PrintToStream() const; + + BPoint LeftTop() const; + BPoint RightBottom() const; + BPoint LeftBottom() const; + BPoint RightTop() const; + + void SetLeftTop(const BPoint p); + void SetRightBottom(const BPoint p); + void SetLeftBottom(const BPoint p); + void SetRightTop(const BPoint p); + + // transformation + void InsetBy(BPoint p); + void InsetBy(float dx, float dy); + void OffsetBy(BPoint p); + void OffsetBy(float dx, float dy); + void OffsetTo(BPoint p); + void OffsetTo(float x, float y); + + // expression transformations + BRect & InsetBySelf(BPoint); + BRect & InsetBySelf(float dx, float dy); + BRect InsetByCopy(BPoint); + BRect InsetByCopy(float dx, float dy); + BRect & OffsetBySelf(BPoint); + BRect & OffsetBySelf(float dx, float dy); + BRect OffsetByCopy(BPoint); + BRect OffsetByCopy(float dx, float dy); + BRect & OffsetToSelf(BPoint); + BRect & OffsetToSelf(float dx, float dy); + BRect OffsetToCopy(BPoint); + BRect OffsetToCopy(float dx, float dy); + + // comparison + bool operator==(BRect r) const; + bool operator!=(BRect r) const; + + // intersection and union + BRect operator&(BRect r) const; + BRect operator|(BRect r) const; + + bool Intersects(BRect r) const; + bool IsValid() const; + float Width() const; + int32 IntegerWidth() const; + float Height() const; + int32 IntegerHeight() const; + bool Contains(BPoint p) const; + bool Contains(BRect r) const; + +}; +//------------------------------------------------------------------------------ + +// inline definitions ---------------------------------------------------------- + +inline BPoint BRect::LeftTop() const +{ + return(*((const BPoint*)&left)); +} + +inline BPoint BRect::RightBottom() const +{ + return(*((const BPoint*)&right)); +} + +inline BPoint BRect::LeftBottom() const +{ + return(BPoint(left, bottom)); +} + +inline BPoint BRect::RightTop() const +{ + return(BPoint(right, top)); +} + +inline BRect::BRect() +{ + top = left = 0; + bottom = right = -1; +} + +inline BRect::BRect(float l, float t, float r, float b) +{ + left = l; + top = t; + right = r; + bottom = b; +} + +inline BRect::BRect(const BRect &r) +{ + left = r.left; + top = r.top; + right = r.right; + bottom = r.bottom; +} + +inline BRect::BRect(BPoint leftTop, BPoint rightBottom) +{ + left = leftTop.x; + top = leftTop.y; + right = rightBottom.x; + bottom = rightBottom.y; +} + +inline BRect &BRect::operator=(const BRect& from) +{ + left = from.left; + top = from.top; + right = from.right; + bottom = from.bottom; + return *this; +} + +inline void BRect::Set(float l, float t, float r, float b) +{ + left = l; + top = t; + right = r; + bottom = b; +} + +inline bool BRect::IsValid() const +{ + if (left <= right && top <= bottom) + return true; + else + return false; +} + +inline int32 BRect::IntegerWidth() const +{ + return((int32)ceil(right - left)); +} + +inline float BRect::Width() const +{ + return(right - left); +} + +inline int32 BRect::IntegerHeight() const +{ + return((int32)ceil(bottom - top)); +} + +inline float BRect::Height() const +{ + return(bottom - top); +} + +//------------------------------------------------------------------------------ + +#endif // _RECT_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/headers/os/interface/StatusBar.h b/headers/os/interface/StatusBar.h new file mode 100644 index 0000000000..1a0e6de313 --- /dev/null +++ b/headers/os/interface/StatusBar.h @@ -0,0 +1,141 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: StatusBar.h +// Author: Marc Flerackers (mflerackers@androme.be) +// Description: BStatusBar displays a "percentage-of-completion" gauge. +//------------------------------------------------------------------------------ + +#ifndef _STATUS_BAR_H +#define _STATUS_BAR_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + + +// BStatusBar class ------------------------------------------------------------ +class BStatusBar : public BView +{ +public: + BStatusBar(BRect frame, const char *name, const char *label = NULL, + const char *trailingLabel = NULL); + BStatusBar(BMessage *archive); + + virtual ~BStatusBar(); + + static BArchivable *Instantiate(BMessage *archive); + virtual status_t Archive(BMessage *archive, bool deep = true) const; + + virtual void AttachedToWindow(); + virtual void MessageReceived(BMessage *message); + virtual void Draw(BRect updateRect); + + virtual void SetBarColor(rgb_color color); + virtual void SetBarHeight(float height); + virtual void SetText(const char *string); + virtual void SetTrailingText(const char *string); + virtual void SetMaxValue(float max); + + void Update(float delta, const char *text = NULL, const char *trailingText = NULL); + virtual void Reset(const char *label = NULL, const char *trailingLabel = NULL); + + float CurrentValue() const; + float MaxValue() const; + rgb_color BarColor() const; + float BarHeight() const; + const char *Text() const; + const char *TrailingText() const; + const char *Label() const; + const char *TrailingLabel() const; + + virtual void MouseDown(BPoint point); + virtual void MouseUp(BPoint point); + virtual void WindowActivated(bool state); + virtual void MouseMoved(BPoint point, uint32 transit, const BMessage *message); + virtual void DetachedFromWindow(); + virtual void FrameMoved(BPoint new_position); + virtual void FrameResized(float new_width, float new_height); + + virtual BHandler *ResolveSpecifier(BMessage *message, int32 index, BMessage *specifier, + int32 what, const char *property); + + virtual void ResizeToPreferred(); + virtual void GetPreferredSize(float *width, float *height); + virtual void MakeFocus(bool state = true); + virtual void AllAttached(); + virtual void AllDetached(); + virtual status_t GetSupportedSuites(BMessage *data); + + virtual status_t Perform(perform_code d, void *arg); + +private: + virtual void _ReservedStatusBar1(); + virtual void _ReservedStatusBar2(); + virtual void _ReservedStatusBar3(); + virtual void _ReservedStatusBar4(); + + BStatusBar &operator=(const BStatusBar &); + + void InitObject(const char *l, const char *aux_l); + void SetTextData(char **pp, const char *str); + void FillBar(BRect r); + void Resize(); + void _Draw(BRect updateRect, bool bar_only); + + char *fLabel; + char *fTrailingLabel; + char *fText; + char *fTrailingText; + float fMax; + float fCurrent; + float fBarHeight; + float fTrailingWidth; + rgb_color fBarColor; + float fEraseText; + float fEraseTrailingText; + bool fCustomBarHeight; + bool _pad1; + bool _pad2; + bool _pad3; + uint32 _reserved[3]; +}; + +//------------------------------------------------------------------------------ + +#endif // _STATUS_BAR_H + +/* + * $Log $ + * + * $Id $ + * + */ diff --git a/headers/os/interface/StringItem.h b/headers/os/interface/StringItem.h new file mode 100644 index 0000000000..3760e86456 --- /dev/null +++ b/headers/os/interface/StringItem.h @@ -0,0 +1,55 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// File: StringItem.h +// +// Description: +// +// Copyright 2001, Ulrich Wimboeck +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _STRING_ITEM_H +#define _STRING_ITEM_H + +#include + + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS +{ +#endif + +/*----------------------------------------------------------------*/ +/*----- BStringItem class ----------------------------------------*/ + +class BStringItem : public BListItem +{ +public: + BStringItem(const char* text, uint32 outlineLevel = 0, bool expanded = true) ; + BStringItem(BMessage* data) ; +virtual ~MyStringItem() ; + +static BArchivable *Instantiate(BMessage* data); +virtual status_t Archive(BMessage* data, bool deep = true) const ; + +virtual void DrawItem(BView* owner, BRect frame, bool complete = false) ; +virtual void SetText(const char* text) ; + const char* Text() const ; +virtual void Update(BView* owner, const BFont* font) ; + +virtual status_t Perform(perform_code d, void* arg); + +private: + + BStringItem(const BStringItem &) ; + BStringItem& operator=(const BStringItem &) ; + + char* fText; + float fBaselineOffset ; +} ; + +#ifdef USE_OPENBEOS_NAMESPACE +} +#endif + +#endif /* _STRING_ITEM_H */ diff --git a/headers/os/interface/StringView.h b/headers/os/interface/StringView.h new file mode 100644 index 0000000000..444f305e4c --- /dev/null +++ b/headers/os/interface/StringView.h @@ -0,0 +1,107 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: StringView.h +// Author: Frans van Nispen (xlr8@tref.nl) +// Description: BStringView draw a non-editable text string +//------------------------------------------------------------------------------ + +#ifndef _STRING_VIEW_H +#define _STRING_VIEW_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + + +// BStringView class ----------------------------------------------------------- +class BStringView : public BView{ +public: + BStringView(BRect bounds, const char* name, const char* text, + uint32 resizeFlags = B_FOLLOW_LEFT | B_FOLLOW_TOP, + uint32 flags = B_WILL_DRAW); + BStringView(BMessage* data); + virtual ~BStringView(); + static BArchivable *Instantiate(BMessage* data); + virtual status_t Archive(BMessage* data, bool deep = true) const; + + void SetText(const char* text); + const char *Text() const; + void SetAlignment(alignment flag); + alignment Alignment() const; + + virtual void AttachedToWindow(); + virtual void Draw(BRect bounds); + + virtual void MessageReceived(BMessage* msg); + virtual void MouseDown(BPoint pt); + virtual void MouseUp(BPoint pt); + virtual void MouseMoved(BPoint pt, uint32 code, const BMessage* msg); + virtual void DetachedFromWindow(); + virtual void FrameMoved(BPoint new_position); + virtual void FrameResized(float new_width, float new_height); + + virtual BHandler *ResolveSpecifier( BMessage* msg, int32 index, BMessage* specifier, + int32 form, const char* property); + + virtual void ResizeToPreferred(); + virtual void GetPreferredSize(float* width, float* height); + virtual void MakeFocus(bool state = true); + virtual void AllAttached(); + virtual void AllDetached(); + virtual status_t GetSupportedSuites(BMessage* data); + + +// Private or reserved --------------------------------------------------------- + virtual status_t Perform(perform_code d, void* arg); + +private: + virtual void _ReservedStringView1(); + virtual void _ReservedStringView2(); + virtual void _ReservedStringView3(); + + BStringView &operator=(const BStringView&); + + char* fText; + alignment fAlign; + uint32 _reserved[3]; +}; +//------------------------------------------------------------------------------ + +#endif // _STRINGVIEW_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/headers/os/interface/TextControl.h b/headers/os/interface/TextControl.h new file mode 100644 index 0000000000..7dbdf68616 --- /dev/null +++ b/headers/os/interface/TextControl.h @@ -0,0 +1,145 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: TextControl.h +// Author: Frans van Nispen (xlr8@tref.nl) +// Description: BTextControl displays text that can act like a control. +//------------------------------------------------------------------------------ +#ifndef _TEXT_CONTROL_H +#define _TEXT_CONTROL_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include +#include +#include +#include // For convenience + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + + +class _BTextInput_; + +// BTextControl class ----------------------------------------------------------- +class BTextControl : public BControl { +public: + BTextControl(BRect frame, const char* name, + const char* label, + const char* initial_text, BMessage* message, + uint32 rmask = B_FOLLOW_LEFT | B_FOLLOW_TOP, + uint32 flags = B_WILL_DRAW | B_NAVIGABLE); + virtual ~BTextControl(); + BTextControl(BMessage* data); + static BArchivable *Instantiate(BMessage* data); + virtual status_t Archive(BMessage* data, bool deep = true) const; + + virtual void SetText(const char* text); + const char* Text() const; + + virtual void SetValue(int32 value); + virtual status_t Invoke(BMessage* msg = NULL); + + BTextView* TextView() const; + + virtual void SetModificationMessage(BMessage* message); + BMessage* ModificationMessage() const; + + virtual void SetAlignment(alignment label, alignment text); + void GetAlignment(alignment* label, alignment* text) const; + virtual void SetDivider(float dividing_line); + float Divider() const; + + virtual void Draw(BRect updateRect); + virtual void MouseDown(BPoint where); + virtual void AttachedToWindow(); + virtual void MakeFocus(bool focusState = true); + virtual void SetEnabled(bool state); + virtual void FrameMoved(BPoint new_position); + virtual void FrameResized(float new_width, float new_height); + virtual void WindowActivated(bool active); + + virtual void GetPreferredSize(float* width, float* height); + virtual void ResizeToPreferred(); + + virtual void MessageReceived(BMessage* msg); + virtual BHandler *ResolveSpecifier(BMessage* msg, int32 index, + BMessage* specifier, int32 form, + const char* property); + + virtual void MouseUp(BPoint pt); + virtual void MouseMoved(BPoint pt, uint32 code, + const BMessage* msg); + virtual void DetachedFromWindow(); + + virtual void AllAttached(); + virtual void AllDetached(); + virtual status_t GetSupportedSuites(BMessage* data); + virtual void SetFlags(uint32 flags); + +// Private or reserved --------------------------------------------------------- + virtual status_t Perform(perform_code d, void* arg); + +private: + friend class _BTextInput_; + virtual void _ReservedTextControl1(); + virtual void _ReservedTextControl2(); + virtual void _ReservedTextControl3(); + virtual void _ReservedTextControl4(); + + BTextControl& operator=(const BTextControl&); + + // this one is not defined, so I guess I am on my own here + _BTextInput_* fText; + + char* fUnusedCharP; //fLabel; // this is in BControl + BMessage* fModificationMessage; + alignment fLabelAlign; + float fDivider; +// uint16 fPrevWidth; +// uint16 fPrevHeight; + uint32 _reserved[4]; +#if !_PR3_COMPATIBLE_ + uint32 _more_reserved[4]; +#endif + +// bool fClean; + bool fSkipSetFlags; // will use this for SHIFT-TAB + bool fUnusedBool1; + bool fUnusedBool2; +}; +//------------------------------------------------------------------------------ + +#endif // _TEXTCONTROL_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/headers/os/interface/UnicodeBlockObjects.h b/headers/os/interface/UnicodeBlockObjects.h new file mode 100644 index 0000000000..19070e8a12 --- /dev/null +++ b/headers/os/interface/UnicodeBlockObjects.h @@ -0,0 +1,125 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: UnicodeBlockObjects.h +// Author: Erik Jaesler (erik@cgsoftware.com) +// Description: Predefined unicode_block objects +//------------------------------------------------------------------------------ + +#ifndef _UNICODEBLOCKOBJECTS_H +#define _UNICODEBLOCKOBJECTS_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + + +// Unicode block list with their unicode encoding range +const unicode_block B_BASIC_LATIN_BLOCK( /* 0000 - 007F */ 0x0000000000000000LL, 0x0000000000000001LL); +const unicode_block B_LATIN1_SUPPLEMENT_BLOCK( /* 0080 - 00FF */ 0x0000000000000000LL, 0x0000000000000002LL); +const unicode_block B_LATIN_EXTENDED_A_BLOCK( /* 0100 - 017F */ 0x0000000000000000LL, 0x0000000000000004LL); +const unicode_block B_LATIN_EXTENDED_B_BLOCK( /* 0180 - 024F */ 0x0000000000000000LL, 0x0000000000000008LL); +const unicode_block B_IPA_EXTENSIONS_BLOCK( /* 0250 - 02AF */ 0x0000000000000000LL, 0x0000000000000010LL); +const unicode_block B_SPACING_MODIFIER_LETTERS_BLOCK( /* 02B0 - 02FF */ 0x0000000000000000LL, 0x0000000000000020LL); +const unicode_block B_COMBINING_DIACRITICAL_MARKS_BLOCK( /* 0300 - 036F */ 0x0000000000000000LL, 0x0000000000000040LL); +const unicode_block B_BASIC_GREEK_BLOCK( /* 0370 - 03CF */ 0x0000000000000000LL, 0x0000000000000080LL); +const unicode_block B_GREEK_SYMBOLS_AND_COPTIC_BLOCK( /* 03D0 - 03FF */ 0x0000000000000000LL, 0x0000000000000100LL); +const unicode_block B_CYRILLIC_BLOCK( /* 0400 - 04FF */ 0x0000000000000000LL, 0x0000000000000200LL); +const unicode_block B_ARMENIAN_BLOCK( /* 0530 - 058F */ 0x0000000000000000LL, 0x0000000000000400LL); +const unicode_block B_BASIC_HEBREW_BLOCK( /* 0590 - 05CF */ 0x0000000000000000LL, 0x0000000000000800LL); +const unicode_block B_HEBREW_EXTENDED_BLOCK( /* 05D0 - 05FF */ 0x0000000000000000LL, 0x0000000000001000LL); +const unicode_block B_BASIC_ARABIC_BLOCK( /* 0600 - 0670 */ 0x0000000000000000LL, 0x0000000000002000LL); +const unicode_block B_ARABIC_EXTENDED_BLOCK( /* 0671 - 06FF */ 0x0000000000000000LL, 0x0000000000004000LL); +const unicode_block B_DEVANAGARI_BLOCK( /* 0900 - 097F */ 0x0000000000000000LL, 0x0000000000008000LL); +const unicode_block B_BENGALI_BLOCK( /* 0980 - 09FF */ 0x0000000000000000LL, 0x0000000000010000LL); +const unicode_block B_GURMUKHI_BLOCK( /* 0A00 - 0A7F */ 0x0000000000000000LL, 0x0000000000020000LL); +const unicode_block B_GUJARATI_BLOCK( /* 0A80 - 0AFF */ 0x0000000000000000LL, 0x0000000000040000LL); +const unicode_block B_ORIYA_BLOCK( /* 0B00 - 0B7F */ 0x0000000000000000LL, 0x0000000000080000LL); +const unicode_block B_TAMIL_BLOCK( /* 0B80 - 0BFF */ 0x0000000000000000LL, 0x0000000000100000LL); +const unicode_block B_TELUGU_BLOCK( /* 0C00 - 0C7F */ 0x0000000000000000LL, 0x0000000000200000LL); +const unicode_block B_KANNADA_BLOCK( /* 0C80 - 0CFF */ 0x0000000000000000LL, 0x0000000000400000LL); +const unicode_block B_MALAYALAM_BLOCK( /* 0D00 - 0D7F */ 0x0000000000000000LL, 0x0000000000800000LL); +const unicode_block B_THAI_BLOCK( /* 0E00 - 0E7F */ 0x0000000000000000LL, 0x0000000001000000LL); +const unicode_block B_LAO_BLOCK( /* 0E80 - 0EFF */ 0x0000000000000000LL, 0x0000000002000000LL); +const unicode_block B_BASIC_GEORGIAN_BLOCK( /* 10A0 - 10CF */ 0x0000000000000000LL, 0x0000000004000000LL); +const unicode_block B_GEORGIAN_EXTENDED_BLOCK( /* 10D0 - 10FF */ 0x0000000000000000LL, 0x0000000008000000LL); +const unicode_block B_HANGUL_JAMO_BLOCK( /* 1100 - 11FF */ 0x0000000000000000LL, 0x0000000010000000LL); +const unicode_block B_LATIN_EXTENDED_ADDITIONAL_BLOCK( /* 1E00 - 1EFF */ 0x0000000000000000LL, 0x0000000020000000LL); +const unicode_block B_GREEK_EXTENDED_BLOCK( /* 1F00 - 1FFF */ 0x0000000000000000LL, 0x0000000040000000LL); +const unicode_block B_GENERAL_PUNCTUATION_BLOCK( /* 2000 - 206F */ 0x0000000000000000LL, 0x0000000080000000LL); +const unicode_block B_SUPERSCRIPTS_AND_SUBSCRIPTS_BLOCK( /* 2070 - 209F */ 0x0000000000000000LL, 0x0000000100000000LL); +const unicode_block B_CURRENCY_SYMBOLS_BLOCK( /* 20A0 - 20CF */ 0x0000000000000000LL, 0x0000000200000000LL); +const unicode_block B_COMBINING_MARKS_FOR_SYMBOLS_BLOCK( /* 20D0 - 20FF */ 0x0000000000000000LL, 0x0000000400000000LL); +const unicode_block B_LETTERLIKE_SYMBOLS_BLOCK( /* 2100 - 214F */ 0x0000000000000000LL, 0x0000000800000000LL); +const unicode_block B_NUMBER_FORMS_BLOCK( /* 2150 - 218F */ 0x0000000000000000LL, 0x0000001000000000LL); +const unicode_block B_ARROWS_BLOCK( /* 2190 - 21FF */ 0x0000000000000000LL, 0x0000002000000000LL); +const unicode_block B_MATHEMATICAL_OPERATORS_BLOCK( /* 2200 - 22FF */ 0x0000000000000000LL, 0x0000004000000000LL); +const unicode_block B_MISCELLANEOUS_TECHNICAL_BLOCK( /* 2300 - 23FF */ 0x0000000000000000LL, 0x0000008000000000LL); +const unicode_block B_CONTROL_PICTURES_BLOCK( /* 2400 - 243F */ 0x0000000000000000LL, 0x0000010000000000LL); +const unicode_block B_OPTICAL_CHARACTER_RECOGNITION_BLOCK( /* 2440 - 245F */ 0x0000000000000000LL, 0x0000020000000000LL); +const unicode_block B_ENCLOSED_ALPHANUMERICS_BLOCK( /* 2460 - 24FF */ 0x0000000000000000LL, 0x0000040000000000LL); +const unicode_block B_BOX_DRAWING_BLOCK( /* 2500 - 257F */ 0x0000000000000000LL, 0x0000080000000000LL); +const unicode_block B_BLOCK_ELEMENTS_BLOCK( /* 2580 - 259F */ 0x0000000000000000LL, 0x0000100000000000LL); +const unicode_block B_GEOMETRIC_SHAPES_BLOCK( /* 25A0 - 25FF */ 0x0000000000000000LL, 0x0000200000000000LL); +const unicode_block B_MISCELLANEOUS_SYMBOLS_BLOCK( /* 2600 - 26FF */ 0x0000000000000000LL, 0x0000400000000000LL); +const unicode_block B_DINGBATS_BLOCK( /* 2700 - 27BF */ 0x0000000000000000LL, 0x0000800000000000LL); +const unicode_block B_CJK_SYMBOLS_AND_PUNCTUATION_BLOCK( /* 3000 - 303F */ 0x0000000000000000LL, 0x0001000000000000LL); +const unicode_block B_HIRAGANA_BLOCK( /* 3040 - 309F */ 0x0000000000000000LL, 0x0002000000000000LL); +const unicode_block B_KATAKANA_BLOCK( /* 30A0 - 30FF */ 0x0000000000000000LL, 0x0004000000000000LL); +const unicode_block B_BOPOMOFO_BLOCK( /* 3100 - 312F */ 0x0000000000000000LL, 0x0008000000000000LL); +const unicode_block B_HANGUL_COMPATIBILITY_JAMO_BLOCK( /* 3130 - 318F */ 0x0000000000000000LL, 0x0010000000000000LL); +const unicode_block B_CJK_MISCELLANEOUS_BLOCK( /* 3190 - 319F */ 0x0000000000000000LL, 0x0020000000000000LL); +const unicode_block B_ENCLOSED_CJK_LETTERS_AND_MONTHS_BLOCK(/* 3200 - 32FF */ 0x0000000000000000LL, 0x0040000000000000LL); +const unicode_block B_CJK_COMPATIBILITY_BLOCK( /* 3300 - 33FF */ 0x0000000000000000LL, 0x0080000000000000LL); +const unicode_block B_HANGUL_BLOCK( /* AC00 - D7AF */ 0x0000000000000000LL, 0x0100000000000000LL); +const unicode_block B_HIGH_SURROGATES_BLOCK( /* D800 - DBFF */ 0x0000000000000000LL, 0x0200000000000000LL); +const unicode_block B_LOW_SURROGATES_BLOCK( /* DC00 - DFFF */ 0x0000000000000000LL, 0x0400000000000000LL); +const unicode_block B_CJK_UNIFIED_IDEOGRAPHS_BLOCK( /* 4E00 - 9FFF */ 0x0000000000000000LL, 0x0800000000000000LL); +const unicode_block B_PRIVATE_USE_AREA_BLOCK( /* E000 - F8FF */ 0x0000000000000000LL, 0x1000000000000000LL); +const unicode_block B_CJK_COMPATIBILITY_IDEOGRAPHS_BLOCK( /* F900 - FAFF */ 0x0000000000000000LL, 0x2000000000000000LL); +const unicode_block B_ALPHABETIC_PRESENTATION_FORMS_BLOCK( /* FB00 - FB4F */ 0x0000000000000000LL, 0x4000000000000000LL); +const unicode_block B_ARABIC_PRESENTATION_FORMS_A_BLOCK( /* FB50 - FDFF */ 0x0000000000000000LL, 0x8000000000000000LL); +const unicode_block B_COMBINING_HALF_MARKS_BLOCK( /* FE20 - FE2F */ 0x0000000000000001LL, 0x0000000000000000LL); +const unicode_block B_CJK_COMPATIBILITY_FORMS_BLOCK( /* FE30 - FE4F */ 0x0000000000000002LL, 0x0000000000000000LL); +const unicode_block B_SMALL_FORM_VARIANTS_BLOCK( /* FE50 - FE6F */ 0x0000000000000004LL, 0x0000000000000000LL); +const unicode_block B_ARABIC_PRESENTATION_FORMS_B_BLOCK( /* FE70 - FEFE */ 0x0000000000000008LL, 0x0000000000000000LL); +const unicode_block B_HALFWIDTH_AND_FULLWIDTH_FORMS_BLOCK( /* FF00 - FFEF */ 0x0000000000000010LL, 0x0000000000000000LL); +const unicode_block B_SPECIALS_BLOCK( /* FEFF and FFF0 - FFFF */ 0x0000000000000020LL, 0x0000000000000000LL); +const unicode_block B_TIBETAN_BLOCK( /* 0F00 - 0FBF */ 0x0000000000000040LL, 0x0000000000000000LL); + +#endif // _UNICODEBLOCKOBJECTS_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/headers/os/interface/View.h b/headers/os/interface/View.h new file mode 100644 index 0000000000..ebb1b28f55 --- /dev/null +++ b/headers/os/interface/View.h @@ -0,0 +1,667 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: View.h +// Author: Erik Jaesler (erik@cgsoftware.com) +// Description: BView is the base class for all views (clipped regions +// within a window). +//------------------------------------------------------------------------------ + +#ifndef _VIEW_H +#define _VIEW_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include +#include +#include +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + + +// view definitions ------------------------------------------------------------ + +enum { + B_PRIMARY_MOUSE_BUTTON = 0x01, + B_SECONDARY_MOUSE_BUTTON = 0x02, + B_TERTIARY_MOUSE_BUTTON = 0x04 +}; + +enum { + B_ENTERED_VIEW = 0, + B_INSIDE_VIEW, + B_EXITED_VIEW, + B_OUTSIDE_VIEW +}; + +enum { + B_POINTER_EVENTS = 0x00000001, + B_KEYBOARD_EVENTS = 0x00000002 +}; + +enum { + B_LOCK_WINDOW_FOCUS = 0x00000001, + B_SUSPEND_VIEW_FOCUS = 0x00000002, + B_NO_POINTER_HISTORY = 0x00000004 +}; + +enum { + B_TRACK_WHOLE_RECT, + B_TRACK_RECT_CORNER +}; + +enum { + B_FONT_FAMILY_AND_STYLE = 0x00000001, + B_FONT_SIZE = 0x00000002, + B_FONT_SHEAR = 0x00000004, + B_FONT_ROTATION = 0x00000008, + B_FONT_SPACING = 0x00000010, + B_FONT_ENCODING = 0x00000020, + B_FONT_FACE = 0x00000040, + B_FONT_FLAGS = 0x00000080, + B_FONT_ALL = 0x000000FF +}; + +const uint32 B_FULL_UPDATE_ON_RESIZE = 0x80000000UL; /* 31 */ +const uint32 _B_RESERVED1_ = 0x40000000UL; /* 30 */ +const uint32 B_WILL_DRAW = 0x20000000UL; /* 29 */ +const uint32 B_PULSE_NEEDED = 0x10000000UL; /* 28 */ +const uint32 B_NAVIGABLE_JUMP = 0x08000000UL; /* 27 */ +const uint32 B_FRAME_EVENTS = 0x04000000UL; /* 26 */ +const uint32 B_NAVIGABLE = 0x02000000UL; /* 25 */ +const uint32 B_SUBPIXEL_PRECISE = 0x01000000UL; /* 24 */ +const uint32 B_DRAW_ON_CHILDREN = 0x00800000UL; /* 23 */ +const uint32 B_INPUT_METHOD_AWARE = 0x00400000UL; /* 23 */ +const uint32 _B_RESERVED7_ = 0x00200000UL; /* 22 */ + +#define _RESIZE_MASK_ ~(B_FULL_UPDATE_ON_RESIZE|_B_RESERVED1_|B_WILL_DRAW|\ + B_PULSE_NEEDED|B_NAVIGABLE_JUMP|B_FRAME_EVENTS|B_NAVIGABLE|\ + B_SUBPIXEL_PRECISE|B_DRAW_ON_CHILDREN|B_INPUT_METHOD_AWARE|_B_RESERVED7_) + +const uint32 _VIEW_TOP_ = 1UL; +const uint32 _VIEW_LEFT_ = 2UL; +const uint32 _VIEW_BOTTOM_ = 3UL; +const uint32 _VIEW_RIGHT_ = 4UL; +const uint32 _VIEW_CENTER_ = 5UL; + +inline uint32 _rule_(uint32 r1, uint32 r2, uint32 r3, uint32 r4) + { return ((r1 << 12) | (r2 << 8) | (r3 << 4) | r4); } + +#define B_FOLLOW_NONE 0 +#define B_FOLLOW_ALL_SIDES _rule_(_VIEW_TOP_, _VIEW_LEFT_, _VIEW_BOTTOM_,\ + _VIEW_RIGHT_) +#define B_FOLLOW_ALL B_FOLLOW_ALL_SIDES + +#define B_FOLLOW_LEFT _rule_(0, _VIEW_LEFT_, 0, _VIEW_LEFT_) +#define B_FOLLOW_RIGHT _rule_(0, _VIEW_RIGHT_, 0, _VIEW_RIGHT_) +#define B_FOLLOW_LEFT_RIGHT _rule_(0, _VIEW_LEFT_, 0, _VIEW_RIGHT_) +#define B_FOLLOW_H_CENTER _rule_(0, _VIEW_CENTER_, 0, _VIEW_CENTER_) + +#define B_FOLLOW_TOP _rule_(_VIEW_TOP_, 0, _VIEW_TOP_, 0) +#define B_FOLLOW_BOTTOM _rule_(_VIEW_BOTTOM_, 0, _VIEW_BOTTOM_, 0) +#define B_FOLLOW_TOP_BOTTOM _rule_(_VIEW_TOP_, 0, _VIEW_BOTTOM_, 0) +#define B_FOLLOW_V_CENTER _rule_(_VIEW_CENTER_, 0, _VIEW_CENTER_, 0) + +class BBitmap; +class BCursor; +class BMessage; +class BPicture; +class BPolygon; +class BRegion; +class BScrollBar; +class BScrollView; +class BShape; +class BShelf; +class BString; +class BWindow; +struct _view_attr_; +struct _array_data_; +struct _array_hdr_; +struct overlay_restrictions; + +// BView class ----------------------------------------------------------------- +class BView : public BHandler { + +public: + BView(BRect frame, const char* name, + uint32 resizeMask, uint32 flags); + virtual ~BView(); + + BView(BMessage* data); + static BArchivable* Instantiate(BMessage* data); + virtual status_t Archive(BMessage* data, bool deep = true) const; + + virtual void AttachedToWindow(); + virtual void AllAttached(); + virtual void DetachedFromWindow(); + virtual void AllDetached(); + + virtual void MessageReceived(BMessage* msg); + + void AddChild(BView* child, BView* before = NULL); + bool RemoveChild(BView* child); + int32 CountChildren() const; + BView* ChildAt(int32 index) const; + BView* NextSibling() const; + BView* PreviousSibling() const; + bool RemoveSelf(); + + BWindow *Window() const; + + virtual void Draw(BRect updateRect); + virtual void MouseDown(BPoint where); + virtual void MouseUp(BPoint where); + virtual void MouseMoved(BPoint where, + uint32 code, + const BMessage* a_message); + virtual void WindowActivated(bool state); + virtual void KeyDown(const char* bytes, int32 numBytes); + virtual void KeyUp(const char* bytes, int32 numBytes); + virtual void Pulse(); + virtual void FrameMoved(BPoint new_position); + virtual void FrameResized(float new_width, float new_height); + + virtual void TargetedByScrollView(BScrollView* scroll_view); + void BeginRectTracking(BRect startRect, + uint32 style = B_TRACK_WHOLE_RECT); + void EndRectTracking(); + + void GetMouse(BPoint* location, + uint32* buttons, + bool checkMessageQueue = true); + + void DragMessage(BMessage* aMessage, + BRect dragRect, + BHandler* reply_to = NULL); + void DragMessage(BMessage* aMessage, + BBitmap* anImage, + BPoint offset, + BHandler* reply_to = NULL); + void DragMessage(BMessage* aMessage, + BBitmap* anImage, + drawing_mode dragMode, + BPoint offset, + BHandler* reply_to = NULL); + + BView* FindView(const char* name) const; + BView* Parent() const; + BRect Bounds() const; + BRect Frame() const; + void ConvertToScreen(BPoint* pt) const; + BPoint ConvertToScreen(BPoint pt) const; + void ConvertFromScreen(BPoint* pt) const; + BPoint ConvertFromScreen(BPoint pt) const; + void ConvertToScreen(BRect* r) const; + BRect ConvertToScreen(BRect r) const; + void ConvertFromScreen(BRect* r) const; + BRect ConvertFromScreen(BRect r) const; + void ConvertToParent(BPoint* pt) const; + BPoint ConvertToParent(BPoint pt) const; + void ConvertFromParent(BPoint* pt) const; + BPoint ConvertFromParent(BPoint pt) const; + void ConvertToParent(BRect* r) const; + BRect ConvertToParent(BRect r) const; + void ConvertFromParent(BRect* r) const; + BRect ConvertFromParent(BRect r) const; + BPoint LeftTop() const; + + void GetClippingRegion(BRegion* region) const; + virtual void ConstrainClippingRegion(BRegion* region); + void ClipToPicture(BPicture* picture, + BPoint where = B_ORIGIN, + bool sync = true); + void ClipToInversePicture(BPicture* picture, + BPoint where = B_ORIGIN, + bool sync = true); + + virtual void SetDrawingMode(drawing_mode mode); + drawing_mode DrawingMode() const; + + void SetBlendingMode(source_alpha srcAlpha, + alpha_function alphaFunc); + void GetBlendingMode(source_alpha* srcAlpha, + alpha_function* alphaFunc) const; + + virtual void SetPenSize(float size); + float PenSize() const; + + void SetViewCursor(const BCursor* cursor, bool sync=true); + + virtual void SetViewColor(rgb_color c); + void SetViewColor(uchar r, uchar g, uchar b, uchar a = 255); + rgb_color ViewColor() const; + + void SetViewBitmap(const BBitmap* bitmap, + BRect srcRect, BRect dstRect, + uint32 followFlags = B_FOLLOW_TOP|B_FOLLOW_LEFT, + uint32 options = B_TILE_BITMAP); + void SetViewBitmap(const BBitmap* bitmap, + uint32 followFlags = B_FOLLOW_TOP|B_FOLLOW_LEFT, + uint32 options = B_TILE_BITMAP); + void ClearViewBitmap(); + + status_t SetViewOverlay(const BBitmap* overlay, + BRect srcRect, BRect dstRect, + rgb_color* colorKey, + uint32 followFlags = B_FOLLOW_TOP|B_FOLLOW_LEFT, + uint32 options = 0); + status_t SetViewOverlay(const BBitmap* overlay, rgb_color* colorKey, + uint32 followFlags = B_FOLLOW_TOP|B_FOLLOW_LEFT, + uint32 options = 0); + void ClearViewOverlay(); + + virtual void SetHighColor(rgb_color a_color); + void SetHighColor(uchar r, uchar g, uchar b, uchar a = 255); + rgb_color HighColor() const; + + virtual void SetLowColor(rgb_color a_color); + void SetLowColor(uchar r, uchar g, uchar b, uchar a = 255); + rgb_color LowColor() const; + + void SetLineMode(cap_mode lineCap, + join_mode lineJoin, + float miterLimit = B_DEFAULT_MITER_LIMIT); + join_mode LineJoinMode() const; + cap_mode LineCapMode() const; + float LineMiterLimit() const; + + void SetOrigin(BPoint pt); + void SetOrigin(float x, float y); + BPoint Origin() const; + + void PushState(); + void PopState(); + + void MovePenTo(BPoint pt); + void MovePenTo(float x, float y); + void MovePenBy(float x, float y); + BPoint PenLocation() const; + void StrokeLine(BPoint toPt, + pattern p = B_SOLID_HIGH); + void StrokeLine(BPoint pt0, + BPoint pt1, + pattern p = B_SOLID_HIGH); + void BeginLineArray(int32 count); + void AddLine(BPoint pt0, BPoint pt1, rgb_color col); + void EndLineArray(); + + void StrokePolygon(const BPolygon* aPolygon, + bool closed = true, + pattern p = B_SOLID_HIGH); + void StrokePolygon(const BPoint* ptArray, + int32 numPts, + bool closed = true, + pattern p = B_SOLID_HIGH); + void StrokePolygon(const BPoint* ptArray, + int32 numPts, + BRect bounds, + bool closed = true, + pattern p = B_SOLID_HIGH); + void FillPolygon(const BPolygon* aPolygon, + pattern p = B_SOLID_HIGH); + void FillPolygon(const BPoint* ptArray, + int32 numPts, + pattern p = B_SOLID_HIGH); + void FillPolygon(const BPoint* ptArray, + int32 numPts, + BRect bounds, + pattern p = B_SOLID_HIGH); + + void StrokeTriangle(BPoint pt1, + BPoint pt2, + BPoint pt3, + BRect bounds, + pattern p = B_SOLID_HIGH); + void StrokeTriangle(BPoint pt1, + BPoint pt2, + BPoint pt3, + pattern p = B_SOLID_HIGH); + void FillTriangle(BPoint pt1, + BPoint pt2, + BPoint pt3, + pattern p = B_SOLID_HIGH); + void FillTriangle(BPoint pt1, + BPoint pt2, + BPoint pt3, + BRect bounds, + pattern p = B_SOLID_HIGH); + + void StrokeRect(BRect r, pattern p = B_SOLID_HIGH); + void FillRect(BRect r, pattern p = B_SOLID_HIGH); + void FillRegion(BRegion* a_region, pattern p= B_SOLID_HIGH); + void InvertRect(BRect r); + + void StrokeRoundRect(BRect r, + float xRadius, + float yRadius, + pattern p = B_SOLID_HIGH); + void FillRoundRect(BRect r, + float xRadius, + float yRadius, + pattern p = B_SOLID_HIGH); + + void StrokeEllipse(BPoint center, + float xRadius, + float yRadius, + pattern p = B_SOLID_HIGH); + void StrokeEllipse(BRect r, pattern p = B_SOLID_HIGH); + void FillEllipse(BPoint center, + float xRadius, + float yRadius, + pattern p = B_SOLID_HIGH); + void FillEllipse(BRect r, pattern p = B_SOLID_HIGH); + + void StrokeArc(BPoint center, + float xRadius, + float yRadius, + float start_angle, + float arc_angle, + pattern p = B_SOLID_HIGH); + void StrokeArc(BRect r, + float start_angle, + float arc_angle, + pattern p = B_SOLID_HIGH); + void FillArc(BPoint center, + float xRadius, + float yRadius, + float start_angle, + float arc_angle, + pattern p = B_SOLID_HIGH); + void FillArc(BRect r, + float start_angle, + float arc_angle, + pattern p = B_SOLID_HIGH); + + void StrokeBezier(BPoint* controlPoints, + pattern p = B_SOLID_HIGH); + void FillBezier(BPoint* controlPoints, + pattern p = B_SOLID_HIGH); + + void StrokeShape(BShape* shape, + pattern p = B_SOLID_HIGH); + void FillShape(BShape* shape, + pattern p = B_SOLID_HIGH); + + void CopyBits(BRect src, BRect dst); + void DrawBitmapAsync(const BBitmap* aBitmap, + BRect srcRect, + BRect dstRect); + void DrawBitmapAsync(const BBitmap* aBitmap); + void DrawBitmapAsync(const BBitmap* aBitmap, BPoint where); + void DrawBitmapAsync(const BBitmap* aBitmap, BRect dstRect); + void DrawBitmap(const BBitmap* aBitmap, + BRect srcRect, + BRect dstRect); + void DrawBitmap(const BBitmap* aBitmap); + void DrawBitmap(const BBitmap* aBitmap, BPoint where); + void DrawBitmap(const BBitmap* aBitmap, BRect dstRect); + + void DrawChar(char aChar); + void DrawChar(char aChar, BPoint location); + void DrawString(const char* aString, + escapement_delta* delta = NULL); + void DrawString(const char* aString, BPoint location, + escapement_delta* delta = NULL); + void DrawString(const char* aString, int32 length, + escapement_delta* delta = NULL); + void DrawString(const char* aString, + int32 length, + BPoint location, + escapement_delta* delta = 0L); + + virtual void SetFont(const BFont* font, uint32 mask = B_FONT_ALL); + + #if !_PR3_COMPATIBLE_ + void GetFont(BFont* font) const; + #else + void GetFont(BFont* font); + #endif + void TruncateString(BString* in_out, + uint32 mode, + float width) const; + float StringWidth(const char* string) const; + float StringWidth(const char* string, int32 length) const; + void GetStringWidths(char* stringArray[], + int32 lengthArray[], + int32 numStrings, + float widthArray[]) const; + void SetFontSize(float size); + void ForceFontAliasing(bool enable); + void GetFontHeight(font_height* height) const; + + void Invalidate(BRect invalRect); + void Invalidate(const BRegion* invalRegion); + void Invalidate(); + + void SetDiskMode(char* filename, long offset); + + void BeginPicture(BPicture* a_picture); + void AppendToPicture(BPicture* a_picture); + BPicture* EndPicture(); + + void DrawPicture(const BPicture* a_picture); + void DrawPicture(const BPicture* a_picture, BPoint where); + void DrawPicture(const char* filename, long offset, BPoint where); + void DrawPictureAsync(const BPicture* a_picture); + void DrawPictureAsync(const BPicture* a_picture, BPoint where); + void DrawPictureAsync(const char* filename, long offset, + BPoint where); + + status_t SetEventMask(uint32 mask, uint32 options=0); + uint32 EventMask(); + status_t SetMouseEventMask(uint32 mask, uint32 options=0); + + virtual void SetFlags(uint32 flags); + uint32 Flags() const; + virtual void SetResizingMode(uint32 mode); + uint32 ResizingMode() const; + void MoveBy(float dh, float dv); + void MoveTo(BPoint where); + void MoveTo(float x, float y); + void ResizeBy(float dh, float dv); + void ResizeTo(float width, float height); + void ScrollBy(float dh, float dv); + void ScrollTo(float x, float y); + virtual void ScrollTo(BPoint where); + virtual void MakeFocus(bool focusState = true); + bool IsFocus() const; + + virtual void Show(); + virtual void Hide(); + bool IsHidden() const; + bool IsHidden(const BView* looking_from) const; + + void Flush() const; + void Sync() const; + + virtual void GetPreferredSize(float* width, float* height); + virtual void ResizeToPreferred(); + + BScrollBar* ScrollBar(orientation posture) const; + + virtual BHandler* ResolveSpecifier(BMessage* msg, + int32 index, + BMessage* specifier, + int32 form, + const char* property); + virtual status_t GetSupportedSuites(BMessage* data); + + bool IsPrinting() const; + void SetScale(float scale) const; + +// Private or reserved --------------------------------------------------------- + virtual status_t Perform(perform_code d, void* arg); + + virtual void DrawAfterChildren(BRect r); + +private: + + friend class BScrollBar; + friend class BWindow; + friend class BBitmap; + friend class BPrintJob; + friend class BShelf; + friend class BTabView; + + virtual void _ReservedView2(); + virtual void _ReservedView3(); + virtual void _ReservedView4(); + virtual void _ReservedView5(); + virtual void _ReservedView6(); + virtual void _ReservedView7(); + virtual void _ReservedView8(); + +#if !_PR3_COMPATIBLE_ + virtual void _ReservedView9(); + virtual void _ReservedView10(); + virtual void _ReservedView11(); + virtual void _ReservedView12(); + virtual void _ReservedView13(); + virtual void _ReservedView14(); + virtual void _ReservedView15(); + virtual void _ReservedView16(); +#endif + + BView(const BView&); + BView& operator=(const BView&); + + void InitData(BRect f, const char* name, uint32 rs, uint32 fl); + status_t ArchiveChildren(BMessage* data, bool deep) const; + status_t UnarchiveChildren(BMessage* data, BWindow* w = NULL); + status_t SetViewImage(const BBitmap* bitmap,BRect srcRect, BRect dstRect, + uint32 followFlags, uint32 options); + void BeginPicture_pr(BPicture* a_picture, BRect r); + void SetPattern(pattern pat); + void DoBezier(int32 gr, BPoint* controlPoints, pattern p); + void DoShape(int32 gr, BShape* shape, pattern p); + void DoPictureClip(BPicture* picture, BPoint where, bool invert, + bool sync); + bool remove_from_list(BView* a_view); + bool remove_self(); + bool do_owner_check() const; + void set_owner(BWindow* the_owner); + void do_activate(int32 state); + void check_lock() const; + void check_lock_no_pick() const; + void movesize(uint32 code, int32 h, int32 v); + void handle_tick(); + char *test_area(int32 length); + void remove_comm_array(); + _array_hdr_ *new_comm_array(int32 cnt); + BView *RealParent() const; + void SetScroller(BScrollBar* sb); + void UnsetScroller(BScrollBar* sb); + void RealScrollTo(BPoint); + void init_cache(); + void set_cached_state(); + void update_cached_state(); + void set_font_state(const BFont* font, uint32 mask); + void fetch_font(); + uchar font_encoding() const; + BShelf* shelf() const; + void set_shelf(BShelf* ); + + int32 server_token; + uint32 f_type; + float origin_h; + float origin_v; + BWindow* owner; + BView* parent; + BView* next_sibling; + BView* prev_sibling; + BView* first_child; + + int16 fShowLevel; + bool top_level_view; + bool fNoISInteraction; + BPicture* cpicture; + _array_data_* comm; + + BScrollBar* fVerScroller; + BScrollBar* fHorScroller; + bool f_is_printing; + bool attached; + bool _unused_bool1; + bool _unused_bool2; + _view_attr_* fPermanentState; + _view_attr_* fState; + BRect fCachedBounds; + BShelf* fShelf; + void* pr_state; + uint32 fEventMask; + uint32 fEventOptions; + uint32 _reserved[4]; +#if !_PR3_COMPATIBLE_ + uint32 _more_reserved[3]; +#endif +}; +//------------------------------------------------------------------------------ + + +// inline definitions ---------------------------------------------------------- +inline void BView::ScrollTo(float x, float y) +{ + ScrollTo(BPoint(x, y)); +} +//------------------------------------------------------------------------------ +inline void BView::SetViewColor(uchar r, uchar g, uchar b, uchar a) +{ + rgb_color a_color; + a_color.red = r; a_color.green = g; + a_color.blue = b; a_color.alpha = a; + SetViewColor(a_color); +} +//------------------------------------------------------------------------------ +inline void BView::SetHighColor(uchar r, uchar g, uchar b, uchar a) +{ + rgb_color a_color; + a_color.red = r; a_color.green = g; + a_color.blue = b; a_color.alpha = a; + SetHighColor(a_color); +} +//------------------------------------------------------------------------------ +inline void BView::SetLowColor(uchar r, uchar g, uchar b, uchar a) +{ + rgb_color a_color; + a_color.red = r; a_color.green = g; + a_color.blue = b; a_color.alpha = a; + SetLowColor(a_color); +} +//------------------------------------------------------------------------------ + +#endif // _VIEW_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/headers/os/interface/Window.h b/headers/os/interface/Window.h new file mode 100644 index 0000000000..e1c0cc6ef4 --- /dev/null +++ b/headers/os/interface/Window.h @@ -0,0 +1,456 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: Window.h +// Author: Erik Jaesler (erik@cgsoftware.com) +// Description: BWindow is the base class for all windows (graphic areas +// displayed on-screen). +//------------------------------------------------------------------------------ + +#ifndef _WINDOW_H +#define _WINDOW_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include +#include +#include +#include +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + + +// window definitions ---------------------------------------------------------- + +enum window_type { + B_UNTYPED_WINDOW = 0, + B_TITLED_WINDOW = 1, + B_MODAL_WINDOW = 3, + B_DOCUMENT_WINDOW = 11, + B_BORDERED_WINDOW = 20, + B_FLOATING_WINDOW = 21 +}; + +//---------------------------------------------------------------- + +enum window_look { + B_BORDERED_WINDOW_LOOK = 20, + B_NO_BORDER_WINDOW_LOOK = 19, + B_TITLED_WINDOW_LOOK = 1, + B_DOCUMENT_WINDOW_LOOK = 11, + B_MODAL_WINDOW_LOOK = 3, + B_FLOATING_WINDOW_LOOK = 7 +}; + +//---------------------------------------------------------------- + +enum window_feel { + B_NORMAL_WINDOW_FEEL = 0, + B_MODAL_SUBSET_WINDOW_FEEL = 2, + B_MODAL_APP_WINDOW_FEEL = 1, + B_MODAL_ALL_WINDOW_FEEL = 3, + B_FLOATING_SUBSET_WINDOW_FEEL = 5, + B_FLOATING_APP_WINDOW_FEEL = 4, + B_FLOATING_ALL_WINDOW_FEEL = 6 +}; + +//---------------------------------------------------------------- + +enum window_alignment { + B_BYTE_ALIGNMENT = 0, + B_PIXEL_ALIGNMENT = 1 +}; + +//---------------------------------------------------------------- + +enum { + B_NOT_MOVABLE = 0x00000001, + B_NOT_CLOSABLE = 0x00000020, + B_NOT_ZOOMABLE = 0x00000040, + B_NOT_MINIMIZABLE = 0x00004000, + B_NOT_RESIZABLE = 0x00000002, + B_NOT_H_RESIZABLE = 0x00000004, + B_NOT_V_RESIZABLE = 0x00000008, + B_AVOID_FRONT = 0x00000080, + B_AVOID_FOCUS = 0x00002000, + B_WILL_ACCEPT_FIRST_CLICK = 0x00000010, + B_OUTLINE_RESIZE = 0x00001000, + B_NO_WORKSPACE_ACTIVATION = 0x00000100, + B_NOT_ANCHORED_ON_ACTIVATE = 0x00020000, + B_ASYNCHRONOUS_CONTROLS = 0x00080000, + B_QUIT_ON_WINDOW_CLOSE = 0x00100000 +}; + +#define B_CURRENT_WORKSPACE 0 +#define B_ALL_WORKSPACES 0xffffffff + +//---------------------------------------------------------------- + +class _BSession_; +class BButton; +class BMenuBar; +class BMenuItem; +class BMessage; +class BMessageRunner; +class BMessenger; +class BView; + +struct message; +struct _cmd_key_; +struct _view_attr_; + +// BWindow class --------------------------------------------------------------- +class BWindow : public BLooper { + +public: + BWindow(BRect frame, + const char* title, + window_type type, + uint32 flags, + uint32 workspace = B_CURRENT_WORKSPACE); + BWindow(BRect frame, + const char* title, + window_look look, + window_feel feel, + uint32 flags, + uint32 workspace = B_CURRENT_WORKSPACE); +virtual ~BWindow(); + + BWindow(BMessage* data); +static BArchivable *Instantiate(BMessage* data); +virtual status_t Archive(BMessage* data, bool deep = true) const; + +virtual void Quit(); + void Close(); // Synonym of Quit() + + void AddChild(BView* child, BView* before = NULL); + bool RemoveChild(BView* child); + int32 CountChildren() const; + BView *ChildAt(int32 index) const; + +virtual void DispatchMessage(BMessage* message, BHandler* handler); +virtual void MessageReceived(BMessage* message); +virtual void FrameMoved(BPoint new_position); +virtual void WorkspacesChanged(uint32 old_ws, uint32 new_ws); +virtual void WorkspaceActivated(int32 ws, bool state); +virtual void FrameResized(float new_width, float new_height); +virtual void Minimize(bool minimize); +virtual void Zoom( BPoint rec_position, + float rec_width, + float rec_height); + void Zoom(); + void SetZoomLimits(float max_h, float max_v); +virtual void ScreenChanged(BRect screen_size, color_space depth); + void SetPulseRate(bigtime_t rate); + bigtime_t PulseRate() const; + void AddShortcut( uint32 key, + uint32 modifiers, + BMessage* msg); + void AddShortcut( uint32 key, + uint32 modifiers, + BMessage* msg, + BHandler* target); + void RemoveShortcut(uint32 key, uint32 modifiers); + void SetDefaultButton(BButton* button); + BButton *DefaultButton() const; +virtual void MenusBeginning(); +virtual void MenusEnded(); + bool NeedsUpdate() const; + void UpdateIfNeeded(); + BView *FindView(const char* view_name) const; + BView *FindView(BPoint) const; + BView *CurrentFocus() const; + void Activate(bool = true); +virtual void WindowActivated(bool state); + void ConvertToScreen(BPoint* pt) const; + BPoint ConvertToScreen(BPoint pt) const; + void ConvertFromScreen(BPoint* pt) const; + BPoint ConvertFromScreen(BPoint pt) const; + void ConvertToScreen(BRect* rect) const; + BRect ConvertToScreen(BRect rect) const; + void ConvertFromScreen(BRect* rect) const; + BRect ConvertFromScreen(BRect rect) const; + void MoveBy(float dx, float dy); + void MoveTo(BPoint); + void MoveTo(float x, float y); + void ResizeBy(float dx, float dy); + void ResizeTo(float width, float height); +virtual void Show(); +virtual void Hide(); + bool IsHidden() const; + bool IsMinimized() const; + + void Flush() const; + void Sync() const; + + status_t SendBehind(const BWindow* window); + + void DisableUpdates(); + void EnableUpdates(); + + void BeginViewTransaction(); + void EndViewTransaction(); + + BRect Bounds() const; + BRect Frame() const; + const char *Title() const; + void SetTitle(const char* title); + bool IsFront() const; + bool IsActive() const; + void SetKeyMenuBar(BMenuBar* bar); + BMenuBar *KeyMenuBar() const; + void SetSizeLimits( float min_h, + float max_h, + float min_v, + float max_v); + void GetSizeLimits( float* min_h, + float* max_h, + float* min_v, + float* max_v); + uint32 Workspaces() const; + void SetWorkspaces(uint32); + BView *LastMouseMovedView() const; + +virtual BHandler *ResolveSpecifier(BMessage* msg, + int32 index, + BMessage* specifier, + int32 form, + const char* property); +virtual status_t GetSupportedSuites(BMessage* data); + + status_t AddToSubset(BWindow* window); + status_t RemoveFromSubset(BWindow* window); + +virtual status_t Perform(perform_code d, void* arg); + + status_t SetType(window_type type); + window_type Type() const; + + status_t SetLook(window_look look); + window_look Look() const; + + status_t SetFeel(window_feel feel); + window_feel Feel() const; + + status_t SetFlags(uint32); + uint32 Flags() const; + + bool IsModal() const; + bool IsFloating() const; + + status_t SetWindowAlignment(window_alignment mode, + int32 h, + int32 hOffset = 0, + int32 width = 0, + int32 widthOffset = 0, + int32 v = 0, + int32 vOffset = 0, + int32 height = 0, + int32 heightOffset = 0); + status_t GetWindowAlignment(window_alignment* mode = NULL, + int32* h = NULL, + int32* hOffset = NULL, + int32* width = NULL, + int32* widthOffset = NULL, + int32* v = NULL, + int32* vOffset = NULL, + int32* height = NULL, + int32* heightOffset = NULL) const; + +virtual bool QuitRequested(); +virtual thread_id Run(); + +// Private or reserved --------------------------------------------------------- +private: + +typedef BLooper inherited; + +friend class BApplication; +friend class BBitmap; +friend class BScrollBar; +friend class BView; +friend class BMenuItem; +friend class BWindowScreen; +friend class BDirectWindow; +friend class BFilePanel; +friend class _CEventPort_; +friend void _set_menu_sem_(BWindow* w, sem_id sem); +friend status_t _safe_get_server_token_(const BLooper* , int32* ); + +virtual void _ReservedWindow1(); +virtual void _ReservedWindow2(); +virtual void _ReservedWindow3(); +virtual void _ReservedWindow4(); +virtual void _ReservedWindow5(); +virtual void _ReservedWindow6(); +virtual void _ReservedWindow7(); +virtual void _ReservedWindow8(); + + BWindow(); + BWindow(BWindow&); + BWindow &operator=(BWindow&); + + BWindow(BRect frame, color_space depth, + uint32 bitmapFlags, int32 rowBytes); + void InitData(BRect frame, + const char* title, + window_look look, + window_feel feel, + uint32 flags, + uint32 workspace); + status_t ArchiveChildren(BMessage* data, bool deep) const; + status_t UnarchiveChildren(BMessage* data); + void BitmapClose(); +virtual void task_looper(); + void start_drag( BMessage* msg, + int32 token, + BPoint offset, + BRect track_rect, + BHandler* reply_to); + void start_drag( BMessage* msg, + int32 token, + BPoint offset, + int32 bitmap_token, + drawing_mode dragMode, + BHandler* reply_to); + void view_builder(BView* a_view); + void attach_builder(BView* a_view); + void detach_builder(BView* a_view); + int32 get_server_token() const; + BMessage *extract_drop(BMessage* an_event, BHandler* *target); + void movesize(uint32 opcode, float h, float v); + + BMessage* ReadMessageFromPort(bigtime_t tout = B_INFINITE_TIMEOUT); + int32 MessagesWaiting(); + + void handle_activate(BMessage* an_event); + void do_view_frame(BMessage* an_event); + void do_value_change(BMessage* an_event, BHandler* handler); + void do_mouse_down(BMessage* an_event, BView* target); + void do_mouse_moved(BMessage* an_event, BView* target); + void do_key_down(BMessage* an_event, BHandler* handler); + void do_key_up(BMessage* an_event, BHandler* handler); + void do_menu_event(BMessage* an_event); + void do_draw_views(); +virtual BMessage *ConvertToMessage(void* raw, int32 code); + _cmd_key_ *allocShortcut(uint32 key, uint32 modifiers); + _cmd_key_ *FindShortcut(uint32 key, uint32 modifiers); + void AddShortcut(uint32 key, + uint32 modifiers, + BMenuItem* item); + void post_message(BMessage* message); + void SetLocalTitle(const char* new_title); + void enable_pulsing(bool enable); + BHandler *determine_target(BMessage* msg, BHandler* target, bool pref); + void kb_navigate(); + void navigate_to_next(int32 direction, bool group = false); + void set_focus(BView* focus, bool notify_input_server); + bool InUpdate(); + void DequeueAll(); + bool find_token_and_handler(BMessage* msg, + int32* token, + BHandler* *handler); + window_type compose_type(window_look look, + window_feel feel) const; + void decompose_type(window_type type, + window_look* look, + window_feel* feel) const; + + void SetIsFilePanel(bool panel); + bool IsFilePanel() const; + + // 3 deprecated calls + void AddFloater(BWindow* a_floating_window); + void RemoveFloater(BWindow* a_floating_window); + window_type WindowType() const; + + char *fTitle; + int32 server_token; + char fInUpdate; + char f_active; + short fShowLevel; + uint32 fFlags; + + port_id send_port; + port_id receive_port; + + BView *top_view; + BView *fFocus; + BView *fLastMouseMovedView; + _BSession_ *a_session; + BMenuBar *fKeyMenuBar; + BButton *fDefaultButton; + BList accelList; + int32 top_view_token; + bool pulse_enabled; + bool fViewsNeedPulse; + bool fIsFilePanel; + bool fUnused1; + bigtime_t pulse_rate; + bool fWaitingForMenu; + bool fOffscreen; + sem_id fMenuSem; + float fMaxZoomH; + float fMaxZoomV; + float fMinWindH; + float fMinWindV; + float fMaxWindH; + float fMaxWindV; + BRect fFrame; + window_look fLook; + _view_attr_ *fCurDrawViewState; + window_feel fFeel; + int32 fLastViewToken; + _CEventPort_* fEventPort; + BMessageRunner *fPulseRunner; + BRect fCurrentFrame; + + uint32 _reserved[2]; // was 8 +#if !_PR3_COMPATIBLE_ + uint32 _more_reserved[4]; +#endif +}; + +// inline definitions ---------------------------------------------------------- +inline void BWindow::Close() +{ + Quit(); +} +//------------------------------------------------------------------------------ + +#endif // _WINDOW_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/headers/os/kernel/OS.h b/headers/os/kernel/OS.h new file mode 100644 index 0000000000..8c3b5d824a --- /dev/null +++ b/headers/os/kernel/OS.h @@ -0,0 +1,246 @@ +/* OS.h + * + * Quake with fear - it's back!!! + */ + +#ifndef _OS_H +#define _OS_H + +/** + * @mainpage OpenBeOS Header Documentation + * + * @section Introduction + * This is the header documentation as produced with doxygen. Anyone can + * produce this using the doxygen tool and doing this + *
    + *	cd docs
    + *	doxygen doxygen.conf
    + * 
    + * The resulting files will be produced in dox/html. + * + * @section Updating + * I will attempt to keep these up to date, but if they're not, just + * give me a nudge! + */ + +/** + * @file kernel/OS.h + * @brief Definitions, prototypes needed throughout the OS + */ + +/** + * @defgroup OpenBeOS_Headers OpenBeOS System Headers + * @brief Headers that are available for applications + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define B_OS_NAME_LENGTH 32 + +/** + * @defgroup Areas Memory Areas + * @ingroup OpenBeOS_Headers + * @{ + */ + +/* temporary hacks */ +typedef int32 team_id; +typedef int32 area_id; + +/* Areas */ +typedef struct area_info { + area_id area; + char name[B_OS_NAME_LENGTH]; + int foo; + size_t size; + uint32 lock; + uint32 protection; + team_id team; + uint32 ram_size; + uint32 copy_count; + uint32 in_count; + uint32 out_count; + void *address; +} area_info; + +#define get_area_info(id, ainfo) \ + _get_area_info((id), (ainfo),sizeof(*(ainfo))) +#define get_next_area_info(team, cookie, ainfo) \ + _get_next_area_info((team), (cookie), (ainfo), sizeof(*(ainfo))) + +/** @} */ + +/** + * @defgroup Ports Messaging Ports + * @ingroup OpenBeOS_Headers + * @{ + */ + +/* Ports */ +typedef struct port_info { + port_id port; + team_id team; + char name[B_OS_NAME_LENGTH]; + int32 capacity; /* queue depth */ + int32 queue_count; /* # msgs waiting to be read */ + int32 total_count; /* total # msgs read so far */ +} port_info; + +port_id create_port(int32, const char *); +port_id find_port(const char *); +int read_port(port_id, int32 *, void *, size_t); +int read_port_etc(port_id, int32 *, void *, size_t, uint32, bigtime_t); +int write_port(port_id, int32, const void *, size_t); +int write_port_etc(port_id, int32, const void *, size_t, uint32, bigtime_t); +int close_port(port_id port); +int delete_port(port_id port); + +ssize_t port_buffer_size(port_id); +ssize_t port_buffer_size_etc(port_id, uint32, bigtime_t); +ssize_t port_count(port_id); +int set_port_owner(port_id, team_id); + +int _get_port_info(port_id, port_info *, size_t); +int _get_next_port_info(team_id, int32 *, port_info *, size_t); + +#define get_port_info(port, info) \ + _get_port_info((port), (info), sizeof(*(info))) + +#define get_next_port_info(team, cookie, info) \ + _get_next_port_info((team), (cookie), (info), sizeof(*(info))) + +/** @} */ + +/** + * @defgroup Sems Semaphores + * @ingroup OpenBeOS_Headers + * @{ + */ + +#define B_CAN_INTERRUPT 1 +#define B_DO_NOT_RESCHEDULE 2 +#define B_CHECK_PERMISSION 4 +#define B_TIMEOUT 8 +#define B_RELATIVE_TIMEOUT 8 +#define B_ABSOLUTE_TIMEOUT 16 + +typedef struct sem_info { + sem_id sem; + proc_id proc; + char name[B_OS_NAME_LENGTH]; + int32 count; + thread_id latest_holder; +} sem_info; + +sem_id create_sem_etc(int count, const char *name, proc_id owner); +sem_id create_sem(int count, const char *name); +int delete_sem(sem_id id); +int delete_sem_etc(sem_id id, int return_code); +int acquire_sem(sem_id id); +int acquire_sem_etc(sem_id id, int count, int flags, bigtime_t timeout); +int release_sem(sem_id id); +int release_sem_etc(sem_id id, int count, int flags); +int get_sem_count(sem_id id, int32* thread_count); +int _get_sem_info(sem_id id, struct sem_info *info, size_t); +int _get_next_sem_info(proc_id proc, uint32 *cookie, struct sem_info *info, size_t); +int set_sem_owner(sem_id id, proc_id proc); + +#define get_sem_info(sem, info) \ + _get_sem_info((sem), (info), sizeof(*(info))) + +#define get_next_sem_info(team, cookie, info) \ + _get_next_sem_info((team), (cookie), (info), sizeof(*(info))) + +/** @} */ + +/** + * @defgroup Threads Threads + * @ingroup OpenBeOS_Headers + * @{ + */ + +/* Threads */ + +//enum { +// THREAD_STATE_READY = 0, // ready to run +// THREAD_STATE_RUNNING, // running right now somewhere +// THREAD_STATE_WAITING, // blocked on something +// THREAD_STATE_SUSPENDED, // suspended, not in queue +// THREAD_STATE_FREE_ON_RESCHED, // free the thread structure upon reschedule +// THREAD_STATE_BIRTH // thread is being created +//}; + +typedef enum { + B_THREAD_RUNNING=1, + B_THREAD_READY, + B_THREAD_RECEIVING, + B_THREAD_ASLEEP, + B_THREAD_SUSPENDED, + B_THREAD_WAITING +} thread_state; + +#define THREAD_IDLE_PRIORITY 0 + +#define THREAD_NUM_PRIORITY_LEVELS 64 +#define THREAD_MIN_PRIORITY (THREAD_IDLE_PRIORITY + 1) +#define THREAD_MAX_PRIORITY (THREAD_NUM_PRIORITY_LEVELS - THREAD_NUM_RT_PRIORITY_LEVELS - 1) + +#define THREAD_NUM_RT_PRIORITY_LEVELS 16 +#define THREAD_MIN_RT_PRIORITY (THREAD_MAX_PRIORITY + 1) +#define THREAD_MAX_RT_PRIORITY (THREAD_NUM_PRIORITY_LEVELS - 1) + +#define THREAD_LOWEST_PRIORITY THREAD_MIN_PRIORITY +#define THREAD_LOW_PRIORITY 12 +#define THREAD_MEDIUM_PRIORITY 24 +#define THREAD_HIGH_PRIORITY 36 +#define THREAD_HIGHEST_PRIORITY THREAD_MAX_PRIORITY + +#define THREAD_RT_LOW_PRIORITY THREAD_MIN_RT_PRIORITY +#define THREAD_RT_HIGH_PRIORITY THREAD_MAX_RT_PRIORITY + +#define B_LOW_PRIORITY 5 +#define B_NORMAL_PRIORITY 10 +#define B_DISPLAY_PRIORITY 15 +#define B_URGENT_DISPLAY_PRIORITY 20 +#define B_REAL_TIME_DISPLAY_PRIORITY 100 +#define B_URGENT_PRIORITY 110 +#define B_REAL_TIME_PRIORITY 120 + +typedef struct { + thread_id thread; + team_id team; + char name[B_OS_NAME_LENGTH]; + thread_state state; + int32 priority; + sem_id sem; + bigtime_t user_time; + bigtime_t kernel_time; + void *stack_base; + void *stack_end; +} thread_info; + +typedef struct { + bigtime_t user_time; + bigtime_t kernel_time; +} team_usage_info; + +typedef int32 (*thread_func) (void *); + +thread_id spawn_thread (thread_func, const char *, int32, void *); +int kill_thread(thread_id thread); +int resume_thread(thread_id thread); +int suspend_thread(thread_id thread); + +thread_id find_thread(const char *); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* _OS_H */ + diff --git a/headers/os/kernel/dirent.h b/headers/os/kernel/dirent.h new file mode 100644 index 0000000000..33c111ff7d --- /dev/null +++ b/headers/os/kernel/dirent.h @@ -0,0 +1,35 @@ +/** + * @file dirent.h + * @brief File Control functions and definitions + */ + +#ifndef _DIRENT_H +#define _DIRENT_H + +typedef struct dirent { + vnode_id d_ino; + unsigned short d_reclen; + char d_name[1]; +} dirent_t; + +typedef struct { + int fd; + struct dirent *ent; + struct dirent me; +} DIR; + +#ifndef MAXNAMLEN +#ifdef NAME_MAX +#define MAXNAMLEN NAME_MAX +#else +#define MAXNAMLEN 256 +#endif +#endif + +DIR *opendir(const char *dirname); +struct dirent *readdir(DIR *dirp); +int closedir(DIR *dirp); +void rewinddir(DIR *dirp); + +#endif /* _DIRENT_H */ + diff --git a/headers/os/kernel/fcntl.h b/headers/os/kernel/fcntl.h new file mode 100644 index 0000000000..bafd82eba0 --- /dev/null +++ b/headers/os/kernel/fcntl.h @@ -0,0 +1,341 @@ +/*- + * Copyright (c) 1983, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)fcntl.h 8.3 (Berkeley) 1/21/94 + */ + +/** + * @file fcntl.h + * @brief File Control functions and definitions + */ + +#ifndef _FCNTL_H_ +#define _FCNTL_H_ + +/** + * @defgroup Fcntl fcntl.h + * @brief File Control functions and definitions + * @note Definitions in this file also apply to open() and + * internally in the kernel + * @note Relevant kernel functions should be here as well + * @ingroup OpenBeOS_POSIX + * @{ + */ + +#ifndef _KERNEL_ +//#include +#endif + + +/** + * @defgroup File_Status_Flags File Status Flags + * The flags described in this section are used by fcntl(), open() and also + * withing the kernel. + * @note O_ are used by fcntl() and open() + * @note F flags are used by the kernel + * @ingroup fcntl + * @{ + */ +/** open for reading only */ +#define O_RDONLY 0x0000 +/** open for writing only */ +#define O_WRONLY 0x0001 +/** open for reading and writing */ +#define O_RDWR 0x0002 +/** mask for above modes */ +#define O_ACCMODE 0x0003 + +#ifndef _POSIX_SOURCE + /** kernel flag to allow testing of read/write directly + * @note not #ifdef _KERNEL_ to allow TIOCFLUSH to work */ + #define FREAD 0x0001 + /** kernel flag to allow testing of read/write directly + * @note not #ifdef _KERNEL_ to allow TIOCFLUSH to work */ + #define FWRITE 0x0002 +#endif + +/** no delay */ +#define O_NONBLOCK 0x0004 +/** set append mode */ +#define O_APPEND 0x0008 +/** open with shared file lock */ +#define O_SHLOCK 0x0010 +/** open with exclusive file lock */ +#define O_EXLOCK 0x0020 +/** signal pgrp when data ready */ +#define O_ASYNC 0x0040 +/** backwards compatibility */ +#define O_FSYNC O_SYNC +/** if path is a symlink, don't follow */ +#define O_NOFOLLOW 0x0100 +/** synchronous writes */ +#define O_SYNC 0x0080 +/** create if nonexistant */ +#define O_CREAT 0x0200 +/** truncate to zero length */ +#define O_TRUNC 0x0400 +/** error if already exists */ +#define O_EXCL 0x0800 + +#ifdef _KERNEL_ + /* mark during gc() */ + #define FMARK 0x1000 + /* defer for next gc pass */ + #define FDEFER 0x2000 + /* descriptor holds advisory lock */ + #define FHASLOCK 0x4000 +#endif + +/* + * POSIX 1003.1 specifies a higher granularity for syncronous operations + * than are currently supported. We may want to look at what needs to be done + * to support these. At present just map them. + */ +/** @def O_DSYNC synchronous data writes */ +#define O_DSYNC O_SYNC +/** @def O_RSYNC synchronous reads */ +#define O_RSYNC O_SYNC + +/* defined by POSIX 1003.1; BSD default, this bit is not required */ +/** @def O_NOCTTY don't assign controlling terminal */ +#define O_NOCTTY 0x8000 + +#ifdef _KERNEL_ + /* + * convert from open() flags to/from fflags; convert O_RD/WR to FREAD/FWRITE. + * For out-of-range values for the flags, be slightly careful (but lossy). + */ + /** @def FFLAGS(oflags) Convert from O_ flags to F flags for kernel */ + #define FFLAGS(oflags) (((oflags) & ~O_ACCMODE) | (((oflags) + 1) & O_ACCMODE)) + /** @def OFLAGS(fflags) Convert from F flags to O_ flags for open() */ + #define OFLAGS(fflags) (((fflags) & ~O_ACCMODE) | (((fflags) - 1) & O_ACCMODE)) + + /** @def FMASK bits to save after open */ + #define FMASK (FREAD|FWRITE|FAPPEND|FASYNC|FFSYNC|FNONBLOCK) + /** @def FCNTLFLAGS bits settable by fcntl(F_SETFL, ...) */ + #define FCNTLFLAGS (FAPPEND|FASYNC|FFSYNC|FNONBLOCK) +#endif + +/* + * The O_* flags used to have only F* names, which were used in the kernel + * and by fcntl. We retain the F* names for the kernel f_flags field + * and for backward compatibility for fcntl. + */ +#ifndef _POSIX_SOURCE + /** kernel/compat */ + #define FAPPEND O_APPEND + /** kernel/compat */ + #define FASYNC O_ASYNC + /** kernel */ + #define FFSYNC O_SYNC + /** kernel */ + #define FNONBLOCK O_NONBLOCK + /** compat */ + #define FNDELAY O_NONBLOCK + /** compat */ + #define O_NDELAY O_NONBLOCK +#endif + +/** @} */ + +/** + * @defgroup FCNTL_Flags Flags used for fcntl() + * @ingroup FCNTL + * @{ + */ + +/** + * @def F_DUPFD Return a new file descriptor that has + * @li the lowest number available (>= fd used) + * @li same object references as original fd + * @li same offsets as original (file only) + * @li same file status + * @li close-on-exec flag is set so it will remain open across execv() + * + * @ref FD_CLOEXEC + */ +#define F_DUPFD 0 /* duplicate file descriptor */ +/** @def F_GETFD Get the close-on-exec flag for the fd + * @note the argument is ignored + * @ref FD_CLOEXEC */ +#define F_GETFD 1 +/** @def F_SETFD Set the close-on-exec flag for the fd + * @ref FD_CLOEXEC */ +#define F_SETFD 2 +/** @def F_GETFL Get fd status flags */ +#define F_GETFL 3 +/** @def F_SETFL Set the fd status flags */ +#define F_SETFL 4 +/** @def F_GETOWN Get the process ID receiving SIGIO/SIGURG signals */ +#define F_GETOWN 5 +/** @def F_SETOWN Set the process ID receiving SIGIO/SIGURG signals */ +#define F_SETOWN 6 +/** @def F_GETLK Get the first lock that blocks the requested lock requested + * int the flock structure passed in. + * @li If the call succeeds then the structure is returned unaltered except + * the lock type is set to F_UNLCK + * @li If the call fails the details of the blocking lock will be inserted + * into the strcture, overwriting the details submitted. + */ +#define F_GETLK 7 +/** @def F_SETLK Set/Clear a file segment lock based on the flock structure + * passed in. + * @note If a shared/exclusive lock cannot be set, EAGAIN will be returned + */ +#define F_SETLK 8 +/** @def F_SETLKW Same as F_SETLK but will block if a shared/exclusive + * lock is requested and is not available. + */ +#define F_SETLKW 9 + +/* file descriptor flags (F_GETFD, F_SETFD) */ +/** @def FD_CLOEXEC Flag set in status is fd is set to remain open + * across exec + * @ref F_DUPFD + * @ref F_GETFD + * @ref F_SETFD + */ +#define FD_CLOEXEC 1 /* close-on-exec flag */ +/** @} */ + +/** + * @defgroup FCNTL_FileLocks Locking types for fcntl() + * @ingroup FCNTL + * @{ + */ + +/** shared or read lock */ +#define F_RDLCK 1 +/** unlock */ +#define F_UNLCK 2 +/** exclusive or write lock */ +#define F_WRLCK 3 + +#ifdef _KERNEL_ + /** Wait until lock is granted */ + #define F_WAIT 0x010 + /** Use flock(2) semantics for lock */ + #define F_FLOCK 0x020 + /** Use POSIX semantics for lock */ + #define F_POSIX 0x040 +#endif + +/** @} */ + +/** + * Advisory file segment locking data type - + * information passed to system by user + * @note This structure can be used to lock all or part of a file + * @note Not yet implemented in OpenBeOS + */ +struct flock { + /** starting offset for lock */ + off_t l_start; + /** length of lock required (0 means lock to end of file) */ + off_t l_len; + /** process id of process owning lock */ + pid_t l_pid; + /** type of lock + * @link FCNTL_FileLocks */ + short l_type; + /** type of start poition given */ + short l_whence; +}; + + +/** + * @defgroup FCNTL_flock Locking types for flock() + * @ingroup FCNTL + * @{ + */ +/** shared lock */ +#define LOCK_SH 0x01 +/** exclusive lock */ +#define LOCK_EX 0x02 +/** don't block when locking */ +#define LOCK_NB 0x04 +/** unlock */ +#define LOCK_UN 0x08 +/** @} */ + + +#ifndef _KERNEL_MODE + //#include + #include + + /** @fn int open(const char *path, int oflags, ...); + * Used to open or create a file for reading/writing + * @note oflags passed should be OR'd together, e.g. + * @code + * int fd = open("file.txt", O_RDWR | O_APPEND | O_CREAT); + * @endcode + * @note if the flag O_CREAT is supplied and the file given by path doesn't + * exist it will be created. + * + * @ref File_Status_Flags + */ + int open (const char *, int, ...); + + /** @fn int creat(const char *path, mode_t mode) + * Creates a file. + * @note Obsoleted by open() + * @code + * Same as doing open(path, O_CREAT | O_TRUNC | O_WRONLY, mode); + * @endcode + * @ref open() + */ + int creat (const char *, mode_t); + + /** @fn int fcntl(int fd, int cmd, ...) + * Provides control over the properties of a descriptor that is + * already open. The 3rd paramater is technically a void *, but may + * be interpretted as an int by some commands or cast by others. + * @ref FCNTL_Flags should be used as the cmd parameter + */ + int fcntl (int, int, ...); + + /** @fn int flock(int fd, int operation) + * Applies or removes an advisory lock from descriptor fd. + * @ref FCNTL_flock codes should be used as the operation parameter + */ + int flock (int, int); +#endif + +/** @} */ + +#endif /* !_SYS_FCNTL_H_ */ + diff --git a/headers/os/kernel/sys/domain.h b/headers/os/kernel/sys/domain.h new file mode 100644 index 0000000000..6ba774e21c --- /dev/null +++ b/headers/os/kernel/sys/domain.h @@ -0,0 +1,26 @@ +/* domain.h */ + +/* A domain is just a container for like minded protocols! */ + +#ifndef DOMAIN_H +#define DOMAIN_H + +struct domain { + int dom_family; /* AF_INET and so on */ + char *dom_name; + + void (*dom_init)(void); /* initialise */ + + struct protosw *dom_protosw; /* the protocols we have */ + struct domain *dom_next; + + int (*dom_rtattach)(void **, int); + int dom_rtoffset; + int dom_maxrtkey; +}; + +struct domain *domains; +void add_domain(struct domain *dom, int fam); +void remove_domain(int fam); + +#endif /* DOMAIN_H */ diff --git a/headers/os/kernel/sys/filio.h b/headers/os/kernel/sys/filio.h new file mode 100644 index 0000000000..a68c42200b --- /dev/null +++ b/headers/os/kernel/sys/filio.h @@ -0,0 +1,40 @@ +/** + * @file sys/filio.h + * @brief ioctl() definitions for file descriptor operations + */ + +#ifndef _SYS_FILIO_H +#define _SYS_FILIO_H +/** + * @defgroup IOCTL_filio sys/filio.h + * @brief ioctl() definitions for file descriptor operations + * @ingroup OpenBeOS_POSIX + * @ingroup IOCTL + * @{ + */ + +#include + +/** @def FIOCLEX set close on exec + * @ref FD_CLOEXEC */ +#define FIOCLEX _IO('f', 1) +/** @def FIONCLEX remove close on exec flag + * @ref FD_CLOEXEC*/ +#define FIONCLEX _IO('f', 2) +/** @def FIBMAP get logical block + * @note this is not yet implemented on OpenBeOS */ +#define FIBMAP _IOWR('f', 122, void *) +/** @def FIOASYNC set/clear async I/O */ +#define FIOASYNC _IOW('f', 123, int) +/** @def FIOGETOWN get owner */ +#define FIOGETOWN _IOR('f', 123, int) +/** @def FIOSETOWN set owner */ +#define FIOSETOWN _IOW('f', 123, int) +/** @def FIONBIO set/clear non-blocking I/O */ +#define FIONBIO _IOW('f', 126, int) +/** @def FIONREAD get number of bytes available to read */ +#define FIONREAD _IOW('f', 127, int) + +/** @} */ + +#endif /* _SYS_FILIO_H */ diff --git a/headers/os/kernel/sys/ioccom.h b/headers/os/kernel/sys/ioccom.h new file mode 100644 index 0000000000..9af5c74643 --- /dev/null +++ b/headers/os/kernel/sys/ioccom.h @@ -0,0 +1,80 @@ +/** + * @file sys/ioccom.h + * @brief Definitions & maros common to ioctl + */ + +#ifndef _SYS_IOCCOM_H +#define _SYS_IOCCOM_H + +/** + * @defgroup IOCTL_common sys/ioccom.h + * @brief Definitions & maros common to ioctl() + * @ingroup OpenBeOS_POSIX + * @ingroup IOCTL + * Ioctl values passed as the command (2nd) variable have the + * command encoded in the lower word and the size of any parameters + * in the upper word (in or out). + * The high 3 bits are used to encode whether it's in or out. + * Due to this you can't just give an ioctl value, you need to encode + * it using macros described in + * @ref IOCTL_macros + * @{ + */ + +/** @defgroup IOCTL_parm ioctl() parameter definitions + * @ingroup IOCTL_common + * @{ + */ +/** @def IOC_VOID */ +#define IOC_VOID (ulong)0x20000000 +/** @def IOC_OUT ioctl expects data (output) */ +#define IOC_OUT (ulong)0x40000000 +/** @def IOC_IN ioctl passes a value in */ +#define IOC_IN (ulong)0x80000000 +/** @def IOC_INOUT ioctl passes data in and out */ +#define IOC_INOUT (IOC_IN|IOC_OUT) +/** @def IOC_DIRMASK */ +#define IOC_DIRMASK (ulong)0xe0000000 +/** @} */ + +/** + * @defgroup IOCTL_macros IOCTL macros + * These should be used to define the values passed in as cmd to + * ioctl() + * @ingroup IOCTL_common + * @{ + */ +/** @def IOCPARM_MASK mask used to for following macros */ +#define IOCPARM_MASK 0x1fff +/** @def IOCPARM_LEN(x) length of the data passed as param */ +#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK) +/** @def IOCBASECMD(x) the base command encoded in the ioctl value */ +#define IOCBASECMD(x) ((x) & ~(IOCPARM_MASK << 16)) +/** @def IOCGROUP(x) which group of ioctl() commands does this belong to? */ +#define IOCGROUP(x) (((x) >> 8) & 0xff) +/** @def IOCPARM_MAX Maximum size of parameter that can be passed (20 bytes) */ +#define IOCPARM_MAX 20 + +/** + * @defgroup IOCTL_createmacros macro's to create ioctl() values + * @brief these macro's should be used to create new ioctl() values + * @ingroup IOCTL_common + * @{ + */ +/** @def _IOC(inout, group, num , len) create a new ioctl */ +#define _IOC(inout, group, num, len) \ + (inout | ((len & IOCPARM_MASK)<<16) | ((group) << 8) | (num)) +/** @def _IO(g,n) create a new void ioctl for group g, number n */ +#define _IO(g,n) _IOC(IOC_VOID, (g), (n), 0) +/** @def _IOR(g,n,t) create a ioctl() that reads a value of type t*/ +#define _IOR(g,n,t) _IOC(IOC_OUT, (g), (n), sizeof(t)) +/** @def _IOW(g,n,t) ioctl() that writes value of type t, group g, number n */ +#define _IOW(g,n,t) _IOC(IOC_IN , (g), (n), sizeof(t)) +/** @def _IOWR(g,n,t) ioctl() that reads/writes value of type t + * @note this isn't _IORW as this causes name conflicts on some systems */ +#define _IOWR(g,n,t) _IOC(IOC_INOUT, (g), (n), sizeof(t)) +/** @} */ + +/** @} */ + +#endif /* _SYS_IOCCOM_H */ diff --git a/headers/os/kernel/sys/ioctl.h b/headers/os/kernel/sys/ioctl.h new file mode 100644 index 0000000000..8a2bcb6243 --- /dev/null +++ b/headers/os/kernel/sys/ioctl.h @@ -0,0 +1,37 @@ +/** + * @file sys/ioctl.h + * @brief I/O control functions + */ + +#ifndef _SYS_IOCTL_H +#define _SYS_IOCTL_H + +/** + * @defgroup IOCTL sys/ioctl.h + * @brief I/O control functions + * @ingroup OpenBeOS_POSIX + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + + +#include + +#include +#include + +#ifndef _KERNEL_MODE + /** @fn int ioctl(int fd, ulong cmd, ...) + * Manipulates the characteristics of the affected descriptor. May be used + * on all forms of descriptor, including sockets and pipes. cmd should be one + * of the values given in + * @ref IOCTL_cmds + */ + int ioctl(int, ulong, ...); +#endif /* !_KERNEL_MODE */ + +/** @} */ +#endif /* _SYS_IOCTL_H */ diff --git a/headers/os/kernel/sys/protosw.h b/headers/os/kernel/sys/protosw.h new file mode 100644 index 0000000000..2b46b55af2 --- /dev/null +++ b/headers/os/kernel/sys/protosw.h @@ -0,0 +1,147 @@ +/* protosw.h */ + +#ifndef PROTOSW_H +#define PROTOSW_H + +#include "sys/socketvar.h" /* for struct socket */ +#include "net/route.h" + +#define PRCO_SETOPT 0 +#define PRCO_GETOPT 1 + +/* every protocol module init's one of these and passes it into + * the add_protocol() function, defined below */ +/* NB The pr_domain pointer will be filled in during the + * add_protocol() call + */ +struct protosw { + char *name; + char *mod_path; + uint16 pr_type; /* SOCK_xxx */ + struct domain *pr_domain; + uint16 pr_protocol; /* protocol number */ + uint16 pr_flags; /* flags, PR_xxx */ + int layer; /* which layer are we? */ + + /* the functions! */ + void (*pr_init)(void); + void (*pr_input)(struct mbuf*, int); + int (*pr_output)(struct mbuf *, struct mbuf *, + struct route *, + int, void *); + + int (*pr_userreq)(struct socket *, int, + struct mbuf *, + struct mbuf *, + struct mbuf *); + int (*pr_sysctl)(int *, uint, void *, size_t *, void *, size_t); + void (*pr_ctlinput)(int, struct sockaddr *, void *); + int (*pr_ctloutput)(int, struct socket*, int, int, struct mbuf **); + + struct protosw *pr_next; /* pointer to next proto structure */ + struct protosw *dom_next; /* next protosw pointed by the domain */ +}; + + +/* + * Values for pr_flags. + * PR_ADDR requires PR_ATOMIC; + * PR_ADDR and PR_CONNREQUIRED are mutually exclusive. + */ +#define PR_ATOMIC 0x01 /* exchange atomic messages only */ +#define PR_ADDR 0x02 /* addresses given with messages */ +#define PR_CONNREQUIRED 0x04 /* connection required by protocol */ +#define PR_WANTRCVD 0x08 /* want PRU_RCVD calls */ +#define PR_RIGHTS 0x10 /* passes capabilities */ +#define PR_ABRTACPTDIS 0x20 /* abort on accept(2) to disconnected + socket */ + +#define PR_SLOWHZ 2 /* 2 timeouts per second... */ +#define PR_FASTHZ 5 /* 5 timeouts per second */ +/* + * Defines for the userreq function req field are below. + * + * (*usrreq)(up, req, m, nam, opt); + * + * up is a (struct socket *) + * req is one of these requests, + * m is a optional mbuf chain containing a message, + * nam is an optional mbuf chain containing an address, + * opt is a pointer to a socketopt structure or nil. + * + * The protocol is responsible for disposal of the mbuf chain m, + * the caller is responsible for any space held by nam and opt. + * A non-zero return from usrreq gives an + * UNIX error number which should be passed to higher level software. + */ +#define PRU_ATTACH 0 /* attach protocol to up */ +#define PRU_DETACH 1 /* detach protocol from up */ +#define PRU_BIND 2 /* bind socket to address */ +#define PRU_LISTEN 3 /* listen for connection */ +#define PRU_CONNECT 4 /* establish connection to peer */ +#define PRU_ACCEPT 5 /* accept connection from peer */ +#define PRU_DISCONNECT 6 /* disconnect from peer */ +#define PRU_SHUTDOWN 7 /* won't send any more data */ +#define PRU_RCVD 8 /* have taken data; more room now */ +#define PRU_SEND 9 /* send this data */ +#define PRU_ABORT 10 /* abort (fast DISCONNECT, DETATCH) */ +#define PRU_CONTROL 11 /* control operations on protocol */ +#define PRU_SENSE 12 /* return status into m */ +#define PRU_RCVOOB 13 /* retrieve out of band data */ +#define PRU_SENDOOB 14 /* send out of band data */ +#define PRU_SOCKADDR 15 /* fetch socket's address */ +#define PRU_PEERADDR 16 /* fetch peer's address */ +#define PRU_CONNECT2 17 /* connect two sockets */ +/* begin for protocols internal use */ +#define PRU_FASTTIMO 18 /* 200ms timeout */ +#define PRU_SLOWTIMO 19 /* 500ms timeout */ +#define PRU_PROTORCV 20 /* receive from below */ +#define PRU_PROTOSEND 21 /* send to below */ +#define PRU_PEEREID 22 /* get local peer eid */ + +#define PRU_NREQ 22 + +/* + * The arguments to the ctlinput routine are + * (*protosw[].pr_ctlinput)(cmd, sa, arg); + * where cmd is one of the commands below, sa is a pointer to a sockaddr, + * and arg is an optional caddr_t argument used within a protocol family. + */ +#define PRC_IFDOWN 0 /* interface transition */ +#define PRC_ROUTEDEAD 1 /* select new route if possible ??? */ +#define PRC_MTUINC 2 /* increase in mtu to host */ +#define PRC_QUENCH2 3 /* DEC congestion bit says slow down */ +#define PRC_QUENCH 4 /* some one said to slow down */ +#define PRC_MSGSIZE 5 /* message size forced drop */ +#define PRC_HOSTDEAD 6 /* host appears to be down */ +#define PRC_HOSTUNREACH 7 /* deprecated (use PRC_UNREACH_HOST) */ +#define PRC_UNREACH_NET 8 /* no route to network */ +#define PRC_UNREACH_HOST 9 /* no route to host */ +#define PRC_UNREACH_PROTOCOL 10 /* dst says bad protocol */ +#define PRC_UNREACH_PORT 11 /* bad port # */ +/* was PRC_UNREACH_NEEDFRAG 12 (use PRC_MSGSIZE) */ +#define PRC_UNREACH_SRCFAIL 13 /* source route failed */ +#define PRC_REDIRECT_NET 14 /* net routing redirect */ +#define PRC_REDIRECT_HOST 15 /* host routing redirect */ +#define PRC_REDIRECT_TOSNET 16 /* redirect for type of service & net */ +#define PRC_REDIRECT_TOSHOST 17 /* redirect for tos & host */ +#define PRC_TIMXCEED_INTRANS 18 /* packet lifetime expired in transit */ +#define PRC_TIMXCEED_REASS 19 /* lifetime expired on reass q */ +#define PRC_PARAMPROB 20 /* header incorrect */ + +#define PRC_NCMDS 21 + +#define PRC_IS_REDIRECT(cmd) \ + ((cmd) >= PRC_REDIRECT_NET && (cmd) <= PRC_REDIRECT_TOSHOST) + + +/* Network stack defines... */ +#ifdef _NETWORK_STACK +struct protosw *protocols; +void add_protocol(struct protosw *pr, int fam); +void remove_protocol(struct protosw *pr); +#endif +struct protosw *pffindproto(int domain, int protocol, int type); +struct protosw *pffindtype(int domain, int type); + +#endif /* PROTOSW_H */ diff --git a/headers/os/kernel/sys/socket.h b/headers/os/kernel/sys/socket.h new file mode 100644 index 0000000000..1ab46688e5 --- /dev/null +++ b/headers/os/kernel/sys/socket.h @@ -0,0 +1,251 @@ +/* sys/socket.h */ + + +#ifndef _SYS_SOCKET_H +#define _SYS_SOCKET_H + +#include +#include +#include + +/* These are the address/protocol families we'll be using... */ +/* NB these should be added to as required... */ + +/* If we want to have Binary compatability we may need to alter these + * to agree with the Be versions... + */ +#define AF_UNSPEC 0 +#define AF_LOCAL 1 +#define AF_UNIX AF_LOCAL /* for compatability */ +#define AF_INET 2 +#define AF_ROUTE 3 +#define AF_IMPLINK 4 +#define AF_LINK 18 +#define AF_IPX 23 +#define AF_INET6 24 + +#define AF_MAX 24 + +#define PF_UNSPEC AF_UNSPEC +#define PF_INET AF_INET +#define PF_ROUTE AF_ROUTE +#define PF_LINK AF_LINK +#define PF_INET6 AF_INET6 +#define PF_IPX AF_IPX +#define PF_IMPLINK AF_IMPLINK + +/* Types of socket we can create (eventually) */ +#define SOCK_DGRAM 10 +#define SOCK_STREAM 11 +#define SOCK_RAW 12 +#define SOCK_MISC 255 + +/* + * Option flags per-socket. + */ +#define SO_DEBUG 0x0001 /* turn on debugging info recording */ +#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */ +#define SO_REUSEADDR 0x0004 /* allow local address reuse */ +#define SO_KEEPALIVE 0x0008 /* keep connections alive */ +#define SO_DONTROUTE 0x0010 /* just use interface addresses */ +#define SO_BROADCAST 0x0020 /* permit sending of broadcast msgs */ +#define SO_USELOOPBACK 0x0040 /* bypass hardware when possible */ +#define SO_LINGER 0x0080 /* linger on close if data present */ +#define SO_OOBINLINE 0x0100 /* leave received OOB data in line */ +#define SO_REUSEPORT 0x0200 /* allow local address & port reuse */ + +#define SOL_SOCKET 0xffff + +/* + * Additional options, not kept in so_options. + */ +#define SO_SNDBUF 0x1001 /* send buffer size */ +#define SO_RCVBUF 0x1002 /* receive buffer size */ +#define SO_SNDLOWAT 0x1003 /* send low-water mark */ +#define SO_RCVLOWAT 0x1004 /* receive low-water mark */ +#define SO_SNDTIMEO 0x1005 /* send timeout */ +#define SO_RCVTIMEO 0x1006 /* receive timeout */ +#define SO_ERROR 0x1007 /* get error status and clear */ +#define SO_TYPE 0x1008 /* get socket type */ +#define SO_NETPROC 0x1020 /* multiplex; network processing */ + +/* + * These are the valid values for the "how" field used by shutdown(2). + */ +#define SHUT_RD 1 +#define SHUT_WR 2 +#define SHUT_RDWR 3 + +struct linger { + int l_onoff; + int l_linger; +}; + +struct sockaddr { + uint8 sa_len; + uint8 sa_family; + uint8 sa_data[30]; +}; + +/* this can hold ANY sockaddr we care to throw at it! */ +struct sockaddr_storage { + uint8 ss_len; /* total length */ + uint8 ss_family; /* address family */ + uint8 __ss_pad1[6]; /* align to quad */ + uint64 __ss_pad2; /* force alignment for stupid compilers */ + uint8 __ss_pad3[240]; /* pad to a total of 256 bytes */ +}; + +struct sockproto { + uint16 sp_family; + uint16 sp_protocol; +}; + +#define CTL_NET 4 + +#define CTL_NET_NAMES { \ + { 0, 0 }, \ + { "unix", CTLTYPE_NODE }, \ + { "inet", CTLTYPE_NODE }, \ + { "implink", CTLTYPE_NODE }, \ + { "pup", CTLTYPE_NODE }, \ + { "chaos", CTLTYPE_NODE }, \ + { "xerox_ns", CTLTYPE_NODE }, \ + { "iso", CTLTYPE_NODE }, \ + { "emca", CTLTYPE_NODE }, \ + { "datakit", CTLTYPE_NODE }, \ + { "ccitt", CTLTYPE_NODE }, \ + { "ibm_sna", CTLTYPE_NODE }, \ + { "decnet", CTLTYPE_NODE }, \ + { "dec_dli", CTLTYPE_NODE }, \ + { "lat", CTLTYPE_NODE }, \ + { "hylink", CTLTYPE_NODE }, \ + { "appletalk", CTLTYPE_NODE }, \ + { "route", CTLTYPE_NODE }, \ + { "link_layer", CTLTYPE_NODE }, \ + { "xtp", CTLTYPE_NODE }, \ + { "coip", CTLTYPE_NODE }, \ + { "cnt", CTLTYPE_NODE }, \ + { "rtip", CTLTYPE_NODE }, \ + { "ipx", CTLTYPE_NODE }, \ + { "inet6", CTLTYPE_NODE }, \ + { "pip", CTLTYPE_NODE }, \ + { "isdn", CTLTYPE_NODE }, \ + { "natm", CTLTYPE_NODE }, \ + { "encap", CTLTYPE_NODE }, \ + { "sip", CTLTYPE_NODE }, \ + { "key", CTLTYPE_NODE }, \ +} + +/* + * PF_ROUTE - Routing table + * + * Three additional levels are defined: + * Fourth: address family, 0 is wildcard + * Fifth: type of info, defined below + * Sixth: flag(s) to mask with for NET_RT_FLAGS + */ +#define NET_RT_DUMP 1 /* dump; may limit to a.f. */ +#define NET_RT_FLAGS 2 /* by flags, e.g. RESOLVING */ +#define NET_RT_IFLIST 3 /* survey interface list */ +#define NET_RT_MAXID 4 + +#define CTL_NET_RT_NAMES { \ + { 0, 0 }, \ + { "dump", CTLTYPE_STRUCT }, \ + { "flags", CTLTYPE_STRUCT }, \ + { "iflist", CTLTYPE_STRUCT }, \ +} + + /* Max listen queue for a socket */ +#define SOMAXCONN 5 /* defined as 128 in OpenBSD */ + +struct msghdr { + char * msg_name; /* address we're using (optional) */ + uint msg_namelen; /* length of address */ + struct iovec *msg_iov; /* scatter/gather array we'll use */ + uint msg_iovlen; /* # elements in msg_iov */ + char * msg_control; /* extra data */ + uint msg_controllen; /* length of extra data */ + int msg_flags; /* flags */ +}; + +/* Defines used in msghdr structure. */ +#define MSG_OOB 0x1 /* process out-of-band data */ +#define MSG_PEEK 0x2 /* peek at incoming message */ +#define MSG_DONTROUTE 0x4 /* send without using routing tables */ +#define MSG_EOR 0x8 /* data completes record */ +#define MSG_TRUNC 0x10 /* data discarded before delivery */ +#define MSG_CTRUNC 0x20 /* control data lost before delivery */ +#define MSG_WAITALL 0x40 /* wait for full request or error */ +#define MSG_DONTWAIT 0x80 /* this message should be nonblocking */ +#define MSG_BCAST 0x100 /* this message rec'd as broadcast */ +#define MSG_MCAST 0x200 /* this message rec'd as multicast */ + +struct cmsghdr { + uint cmsg_len; + int cmsg_level; + int cmsg_type; + /* there now follows uchar[] cmsg_data */ +}; + +#define SIOCSHIWAT _IOW('s', 0, int) /* set high watermark */ +#define SIOCGHIWAT _IOR('s', 1, int) /* get high watermark */ +#define SIOCSLOWAT _IOW('s', 2, int) /* set low watermark */ +#define SIOCGLOWAT _IOR('s', 3, int) /* get low watermark */ +#define SIOCATMARK _IOR('s', 7, int) /* at oob mark? */ + +#define SIOCADDRT _IOW('r', 10, struct ortentry) /* add route */ +#define SIOCDELRT _IOW('r', 11, struct ortentry) /* delete route */ + +#define SIOCSIFADDR _IOW('i', 12, struct ifreq) /* set ifnet address */ +#define OSIOCGIFADDR _IOWR('i', 13, struct ifreq) /* get ifnet address */ +#define SIOCGIFADDR _IOWR('i', 33, struct ifreq) /* get ifnet address */ +#define SIOCSIFDSTADDR _IOW('i', 14, struct ifreq) /* set p-p address */ +#define OSIOCGIFDSTADDR _IOWR('i', 15, struct ifreq) /* get p-p address */ +#define SIOCGIFDSTADDR _IOWR('i', 34, struct ifreq) /* get p-p address */ +#define SIOCSIFFLAGS _IOW('i', 16, struct ifreq) /* set ifnet flags */ +#define SIOCGIFFLAGS _IOWR('i', 17, struct ifreq) /* get ifnet flags */ +#define OSIOCGIFBRDADDR _IOWR('i', 18, struct ifreq) /* get broadcast addr */ +#define SIOCGIFBRDADDR _IOWR('i', 35, struct ifreq) /* get broadcast addr */ +#define SIOCSIFBRDADDR _IOW('i', 19, struct ifreq) /* set broadcast addr */ +#define OSIOCGIFCONF _IOWR('i', 20, struct ifconf) /* get ifnet list */ +#define SIOCGIFCONF _IOWR('i', 36, struct ifconf) /* get ifnet list */ +#define OSIOCGIFNETMASK _IOWR('i', 21, struct ifreq) /* get net addr mask */ +#define SIOCGIFNETMASK _IOWR('i', 37, struct ifreq) /* get net addr mask */ +#define SIOCSIFNETMASK _IOW('i', 22, struct ifreq) /* set net addr mask */ +#define SIOCGIFMETRIC _IOWR('i', 23, struct ifreq) /* get IF metric */ +#define SIOCSIFMETRIC _IOW('i', 24, struct ifreq) /* set IF metric */ +#define SIOCDIFADDR _IOW('i', 25, struct ifreq) /* delete IF addr */ +#define SIOCAIFADDR _IOW('i', 26, struct ifaliasreq)/* add/chg IF alias */ +#define SIOCGIFDATA _IOWR('i', 27, struct ifreq) /* get if_data */ + +#define SIOCGIFMTU _IOWR('i', 126, struct ifreq) /* get ifnet MTU */ +#define SIOCSIFMTU _IOW('i', 127, struct ifreq) /* set ifnet MTU */ + +#define SIOCADDMULTI _IOW('i', 49, struct ifreq) /* add m'cast addr */ +#define SIOCDELMULTI _IOW('i', 50, struct ifreq) /* del m'cast addr */ + +#ifndef _KERNEL_MODE +/* Function declarations */ +int socket (int, int, int); +int bind(int, const struct sockaddr *, int); +int connect(int, const struct sockaddr *, int); +int listen(int, int); +int accept(int, struct sockaddr *, int *); +int closesocket(int); +int shutdown(int sock, int how); + +ssize_t send(int, const void *, size_t, int); +ssize_t recv(int, void *, size_t, int); +ssize_t sendto(int, const void *, size_t, int, const struct sockaddr *, size_t); +ssize_t recvfrom(int, void *, size_t, int, struct sockaddr *, size_t *); + +int setsockopt(int, int, int, const void *, size_t); +int getsockopt(int, int, int, void *, size_t *); +int getpeername(int, struct sockaddr *, int *); +int getsockname(int, struct sockaddr *, int *); +#endif /* _KERNEL_MODE_ */ + +#endif /* _SYS_SOCKET_H */ + diff --git a/headers/os/kernel/sys/socketvar.h b/headers/os/kernel/sys/socketvar.h new file mode 100644 index 0000000000..f363d15f6a --- /dev/null +++ b/headers/os/kernel/sys/socketvar.h @@ -0,0 +1,236 @@ +/* socketvar.h */ + + +#ifndef SYS_SOCKETVAR_H +#define SYS_SOCKETVAR_H + +#include +#include +#include +#include + +struct sockbuf { + uint32 sb_cc; /* actual chars in buffer */ + uint32 sb_hiwat; /* max actual char count (high water mark) */ + uint32 sb_mbcnt; /* chars of mbufs used */ + uint32 sb_mbmax; /* max chars of mbufs to use */ + int32 sb_lowat; /* low water mark */ + struct mbuf *sb_mb; /* the mbuf chain */ + int16 sb_flags; /* flags, see below */ + int32 sb_timeo; /* timeout for read/write */ + sem_id sb_sleep; /* our sleep sem */ + sem_id sb_pop; /* sem to wait on... */ +}; + +#define SB_MAX (256*1024) /* default for max chars in sockbuf */ +#define SB_LOCK 0x01 /* lock on data queue */ +#define SB_WANT 0x02 /* someone is waiting to lock */ +#define SB_WAIT 0x04 /* someone is waiting for data/space */ +#define SB_SEL 0x08 /* someone is selecting */ +#define SB_ASYNC 0x10 /* ASYNC I/O, need signals */ +#define SB_NOINTR 0x40 /* operations not interruptible */ +#define SB_KNOTE 0x80 /* kernel note attached */ +#define SB_NOTIFY (SB_WAIT|SB_SEL|SB_ASYNC) + +typedef void (*socket_event_callback)(void * socket, uint32 event, void * cookie); + +struct socket { + uint16 so_type; /* type of socket */ + uint16 so_options; /* socket options */ + int16 so_linger; /* dreaded linger value */ + int16 so_state; /* socket state */ + char *so_pcb; /* pointer to the control block */ + sem_id so_lock; /* socket lock */ + sem_id so_timeo; /* our wait channel */ + + struct protosw *so_proto; /* pointer to protocol module */ + + struct socket *so_head; + struct socket *so_q0; + struct socket *so_q; + + int16 so_q0len; + int16 so_qlen; + int16 so_qlimit; + int32 so_error; +// pid_t so_pgid; + uint32 so_oobmark; + + /* our send/recv buffers */ + struct sockbuf so_snd; + struct sockbuf so_rcv; + + // event callback + socket_event_callback event_callback; + void * event_callback_cookie; + int sel_ev; +}; + +/* Select event bit mask */ +#define SEL_READ 0x01 +#define SEL_WRITE 0x02 +#define SEL_EX 0x04 + +/* + * Socket state bits. + */ +#define SS_NOFDREF 0x001 /* no file table ref any more */ +#define SS_ISCONNECTED 0x002 /* socket connected to a peer */ +#define SS_ISCONNECTING 0x004 /* in process of connecting to peer */ +#define SS_ISDISCONNECTING 0x008 /* in process of disconnecting */ +#define SS_CANTSENDMORE 0x010 /* can't send more data to peer */ +#define SS_CANTRCVMORE 0x020 /* can't receive more data from peer */ +#define SS_RCVATMARK 0x040 /* at mark on input */ +#define SS_ISDISCONNECTED 0x800 /* socket disconnected from peer */ + +#define SS_PRIV 0x080 /* privileged for broadcast, raw... */ +#define SS_NBIO 0x100 /* non-blocking ops */ +#define SS_ASYNC 0x200 /* async i/o notify */ +#define SS_ISCONFIRMING 0x400 /* deciding to accept connection req */ +#define SS_CONNECTOUT 0x1000 /* connect, not accept, at this end */ + +/* helpful defines... */ + +/* adjust counters in sb reflecting freeing of m */ +#define sbfree(sb, m) { \ + (sb)->sb_cc -= (m)->m_len; \ + (sb)->sb_mbcnt -= MSIZE; \ + if ((m)->m_flags & M_EXT) \ + (sb)->sb_mbcnt -= (m)->m_ext.ext_size; \ +} + +#define sbspace(sb) \ + ((uint32) min((int)((sb)->sb_hiwat - (sb)->sb_cc), \ + (int)((sb)->sb_mbmax - (sb)->sb_mbcnt))) + +/* do we have to send all at once on a socket? */ +#define sosendallatonce(so) \ + ((so)->so_proto->pr_flags & PR_ATOMIC) + +/* adjust counters in sb reflecting allocation of m */ +#define sballoc(sb, m) { \ + (sb)->sb_cc += (m)->m_len; \ + (sb)->sb_mbcnt += MSIZE; \ + if ((m)->m_flags & M_EXT) \ + (sb)->sb_mbcnt += (m)->m_ext.ext_size; \ +} + +#define soreadable(so) \ + ((so)->so_rcv.sb_cc >= (so)->so_rcv.sb_lowat || \ + ((so)->so_state & SS_CANTRCVMORE) || \ + (so)->so_qlen || (so)->so_error) + +#define sowriteable(so) \ + ((sbspace(&(so)->so_snd) >= (so)->so_snd.sb_lowat) && \ + (((so)->so_state & SS_ISCONNECTED) || \ + (((so)->so_proto->pr_flags & PR_CONNREQUIRED) == 0) || \ + ((so)->so_state & SS_CANTSENDMORE) || (so)->so_error)) + +#define M_WAITOK 0x0000 +#define M_NOWAIT 0x0001 + +/* + * Set lock on sockbuf sb; sleep if lock is already held. + * Unless SB_NOINTR is set on sockbuf, sleep is interruptible. + * Returns error without lock if sleep is interrupted. + */ +#define sblock(sb, wf) ((sb)->sb_flags & SB_LOCK ? \ + (((wf) == M_WAITOK) ? sb_lock(sb) : EWOULDBLOCK) : \ + ((sb)->sb_flags |= SB_LOCK), 0) + +/* release lock on sockbuf sb */ +#define sbunlock(sb) { \ + (sb)->sb_flags &= ~SB_LOCK; \ + if ((sb)->sb_flags & SB_WANT) { \ + (sb)->sb_flags &= ~SB_WANT; \ + wakeup((sb)->sb_sleep); \ + } \ +} + +#define sorwakeup(so) sowakeup((so), &(so)->so_rcv) +/* we don't handle upcall for sockets */ +#define sowwakeup(so) sowakeup((so), &(so)->so_snd) + +#ifdef _KERNEL_MODE + +uint32 sb_max; + +/* Function prototypes */ + +/* These are the ones we export to libnet.so */ + +int initsocket(void **); +int socreate (int, struct socket **, int, int); +int soshutdown(void *, int); +int soclose (void *); + +int sobind (void *, char *, int); +int solisten (void *, int); +int soconnect (void *, char *, int); +int soaccept (void *, void **, void *, int *); + +int writeit (void *, struct iovec *, int); +int readit (void *, struct iovec *, int *); +int sendit (void *, struct msghdr *, int, int *); +int recvit (void *, struct msghdr *, char *, int *); + +//int so_ioctl (void *, int, void *, size_t); +int sosysctl (int *, uint, void *, size_t *, void *, size_t); +int sosetopt (void *, int, int, const void *, size_t); +int sogetopt (void *, int, int, void *, size_t *); + +int sogetpeername(void *, struct sockaddr *, int *); +int sogetsockname(void *, struct sockaddr *, int *); + + +/* these are all private to the stack...although may be shared with + * other network modules. + */ + +int sosend(struct socket *so, struct mbuf *addr, struct uio *uio, + struct mbuf *top, struct mbuf *control, int flags); + +struct socket *sonewconn(struct socket *head, int connstatus); +int set_socket_event_callback(void *, socket_event_callback, void *, int); +int soreserve (struct socket *so, uint32 sndcc, uint32 rcvcc); + +void sbrelease (struct sockbuf *sb); +int sbreserve (struct sockbuf *sb, uint32 cc); +void sbdrop (struct sockbuf *sb, int len); +void sbdroprecord (struct sockbuf *sb); +void sbflush (struct sockbuf *sb); +int sbwait (struct sockbuf *sb); +void sbappend (struct sockbuf *sb, struct mbuf *m); +int sbappendaddr (struct sockbuf *sb, struct sockaddr *asa, + struct mbuf *m0, struct mbuf *control); +int sbappendcontrol (struct sockbuf *sb, struct mbuf *m0, + struct mbuf *control); +void sbappendrecord (struct sockbuf *sb, struct mbuf *m0); +void sbcheck (struct sockbuf *sb); +void sbcompress (struct sockbuf *sb, struct mbuf *m, struct mbuf *n); +int soreceive (struct socket *so, struct mbuf **paddr, struct uio *uio, + struct mbuf **mp0, struct mbuf **controlp, int *flagsp); +void sowakeup(struct socket *so, struct sockbuf *sb); +int sbwait(struct sockbuf *sb); + +int sodisconnect(struct socket *); +void sofree(struct socket *); + +void sohasoutofband(struct socket *so); +void socantsendmore(struct socket *so); +void socantrcvmore(struct socket *so); +void soisconnected (struct socket *so); +void soisconnecting (struct socket *so); +void soisdisconnected (struct socket *so); +void soisdisconnecting (struct socket *so); +void soqinsque (struct socket *head, struct socket *so, int q); +int soqremque (struct socket *so, int q); +int sorflush(struct socket *so); + +int sb_lock(struct sockbuf *sb); +int nsleep(sem_id chan, char *msg, int timeo); +void wakeup(sem_id chan); + +#endif /* _NETWORK_STACK */ + +#endif /* SYS_SOCKETVAR_H */ diff --git a/headers/os/kernel/sys/stat.h b/headers/os/kernel/sys/stat.h new file mode 100644 index 0000000000..1f5e68cccc --- /dev/null +++ b/headers/os/kernel/sys/stat.h @@ -0,0 +1,229 @@ +/*- + * Copyright (c) 1982, 1986, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)stat.h 8.9 (Berkeley) 8/17/94 + */ + +#ifndef _SYS_STAT_H_ +#define _SYS_STAT_H_ + +//#include + +/** + * @file stat.h + * @brief Stat structures and defines + */ + +/** + * @defgroup OpenBeOS_POSIX POSIX Headers + * @brief Headers to provide the POSIX layer + */ + +/** + * @defgroup Stat sys/stat.h + * @brief Structures and prototypes for stat operations + * @ingroup OpenBeOS_POSIX + * @{ + */ + +/* XXX - some types we don't yet have in sys/types.h (because we don't yet + * have a sys/types.h and these aren't in ktypes.h!) + */ + +#ifdef _KERNEL_MODE_ +struct ostat { + mode_t st_mode; /* inode protection mode */ + ino_t st_ino; /* inode's number */ + uint16 st_dev; /* inode's device */ + nlink_t st_nlink; /* number of hard links */ + uid_t st_uid; /* user ID of the file's owner */ + gid_t st_gid; /* group ID of the file's group */ + off_t st_size; /* file size, in bytes */ + time_t st_atime; /* time of last access */ + time_t st_mtime; /* time of last data modification */ + time_t st_ctime; /* time of last file status change */ + int64 st_blocks; /* blocks allocated for file */ + int32 st_blksize; /* optimal blocksize for I/O */ +}; +#endif /* _KERNEL_MODE_ */ + +/* XXX - The stat structure, as defined by POSIX. + * Just implement what we can for the time being. + */ +struct stat { + mode_t st_mode; /* File mode */ + ino_t st_ino; /* vnode_id */ +// dev_t st_dev; /* inode's device */ + nlink_t st_nlink; /* number of hard links */ + uid_t st_uid; /* user ID of the file's owner */ + gid_t st_gid; /* group ID of the file's group */ + off_t st_size; /* file size, in bytes */ + time_t st_atime; /* time of last access */ + time_t st_mtime; /* time of last data modification */ + time_t st_ctime; /* time of last file status change */ + int64 st_blocks; /* blocks allocated for file */ + uint32 st_blksize; /* optimal blocksize for I/O */ +}; + +/** + * @defgroup POSIX_filemodes File mode defines + * @brief Defines of the file modes we allow + * @ingroup Stat + *@{ + */ +/** set user id on execution */ +#define S_ISUID 0004000 +/** set group id on execution */ +#define S_ISGID 0002000 +/** sticky bit */ +#define S_ISTXT 0001000 + +/** + * @def S_IRWXU RWX mask for owner + * @def S_IRUSR R for owner + * @def S_IWUSR W for owner + * @def S_IXUSR X for owner + */ +#define S_IRWXU 0000700 +#define S_IRUSR 0000400 +#define S_IWUSR 0000200 +#define S_IXUSR 0000100 + +/* @def S_IRWXG RWX mask for group + * @def S_IWGRP W for group + * @def S_IRGRP R for group + * @def S_IXGRP X for group + */ +#define S_IRWXG 0000070 +#define S_IRGRP 0000040 +#define S_IWGRP 0000020 +#define S_IXGRP 0000010 + +#define S_IRWXO 0000007 /* RWX mask for other */ +#define S_IROTH 0000004 /* R for other */ +#define S_IWOTH 0000002 /* W for other */ +#define S_IXOTH 0000001 /* X for other */ + +#define S_IFMT 0170000 +#define S_IFSOCK 0140000 +#define S_IFIFO 0010000 +#define S_IFCHR 0020000 +#define S_IFDIR 0040000 +#define S_IFBLK 0060000 +#define S_IFREG 0100000 +#define S_IFLNK 0120000 +#define S_IFWHT 0160000 +#define S_ISVTX 0001000 + +#define S_ISDIR(m) ((m & 0170000) == 0040000) /* directory */ +#define S_ISCHR(m) ((m & 0170000) == 0020000) /* char special */ +#define S_ISBLK(m) ((m & 0170000) == 0060000) /* block special */ +#define S_ISREG(m) ((m & 0170000) == 0100000) /* regular file */ +#define S_ISFIFO(m) ((m & 0170000) == 0010000) /* fifo */ +#define S_ISLNK(m) ((m & 0170000) == 0120000) /* symbolic link */ +#define S_ISSOCK(m) ((m & 0170000) == 0140000)/* socket */ +#define S_ISWHT(m)((m & 0170000) == 0160000)/* whiteout */ + +/** 00777 */ +#define ACCESSPERMS (S_IRWXU | S_IRWXG | S_IRWXO) +/** 07777 */ +#define ALLPERMS (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO) +/** 00666 */ +#define DEFFILEMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) + +/** @} */ +/* + * Definitions of flags stored in file flags word. + * + * Super-user and owner changeable flags. + */ +#define UF_SETTABLE 0x0000ffff /* mask of owner changeable flags */ +#define UF_NODUMP 0x00000001 /* do not dump file */ +#define UF_IMMUTABLE 0x00000002 /* file may not be changed */ +#define UF_APPEND 0x00000004 /* writes to file may only append */ +#define UF_OPAQUE 0x00000008 /* directory is opaque wrt. union */ +/* + * Super-user changeable flags. + */ +#define SF_SETTABLE 0xffff0000 /* mask of superuser changeable flags */ +#define SF_ARCHIVED 0x00010000 /* file is archived */ +#define SF_IMMUTABLE 0x00020000 /* file may not be changed */ +#define SF_APPEND 0x00040000 /* writes to file may only append */ + +#ifdef _KERNEL_MODE +/* + * Shorthand abbreviations of above. + */ +#define OPAQUE (UF_OPAQUE) +#define APPEND (UF_APPEND | SF_APPEND) +#define IMMUTABLE (UF_IMMUTABLE | SF_IMMUTABLE) +#endif /* _KERNEL_MODE */ + +#ifndef _KERNEL_MODE_ + //#include + + /** @fn int chmod(const char *path, mode_t mode) + * Changes the file protection modes to those given by mode + * + * @ref POISX_filemodes + */ + int chmod (const char *, mode_t); + /** @fn int fstat(int fd, struct stat *stat) + * get file information on a file identified by descriptor fd + * + * @ref stat + */ + int fstat (int, struct stat *); + //int mknod (const char *, mode_t, dev_t); + int mkdir (const char *, mode_t); + int mkfifo (const char *, mode_t); + /** @fn int stat(const char *path, struct stat *stat) + * Get file information for file path and store it in the structure + * stat + * + * @ref stat + */ + int stat (const char *, struct stat *); + mode_t umask (mode_t); + int fchmod (int, mode_t); + int lstat (const char *, struct stat *); + +#endif + +/** @} */ + +#endif /* !_SYS_STAT_H_ */ diff --git a/headers/os/kernel/sys/uio.h b/headers/os/kernel/sys/uio.h new file mode 100644 index 0000000000..7a7baafad7 --- /dev/null +++ b/headers/os/kernel/sys/uio.h @@ -0,0 +1,41 @@ +/* uio.h */ + +#ifndef _SYS_UIO_H +#define _SYS_UIO_H + +#include + +typedef struct iovec { + void *iov_base; + size_t iov_len; +} iovec; + + +#ifdef _KERNEL_MODE +enum uio_rw { UIO_READ, UIO_WRITE }; + +/* Segment flag values. */ +enum uio_seg { + UIO_USERSPACE, /* from user data space */ + UIO_SYSSPACE /* from system space */ +}; + +struct uio { + struct iovec *uio_iov; /* pointer to array of iovecs */ + int uio_iovcnt; /* number of iovecs in array */ + off_t uio_offset; /* offset into file this uio corresponds to */ + size_t uio_resid; /* residual i/o count */ + enum uio_seg uio_segflg; /* see above */ + enum uio_rw uio_rw; /* see above */ +// struct proc *uio_procp; /* process if UIO_USERSPACE */ +}; + +int uiomove(char *cp, int n, struct uio *uio); +#endif + +ssize_t readv(int fd, const struct iovec *vector, size_t count); +ssize_t readv_pos(int fd, off_t pos, const struct iovec *vec, size_t count); +ssize_t writev(int fd, const struct iovec *vector, size_t count); +ssize_t writev_pos(int fd, off_t pos, const struct iovec *vec, size_t count); + +#endif /* _SYS_UIO_H */ diff --git a/headers/os/kernel/syscalls.h b/headers/os/kernel/syscalls.h new file mode 100755 index 0000000000..c037e86d1a --- /dev/null +++ b/headers/os/kernel/syscalls.h @@ -0,0 +1,128 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _LIBSYS_SYSCALLS_H +#define _LIBSYS_SYSCALLS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int sys_null(); + +/* fs api */ +int sys_mount(const char *path, const char *device, const char *fs_name, void *args); +int sys_unmount(const char *path); +int sys_sync(); +int sys_open(const char *path, stream_type st, int omode); +int sys_close(int fd); +int sys_fsync(int fd); +ssize_t sys_read(int fd, void *buf, off_t pos, size_t len); +ssize_t sys_write(int fd, const void *buf, off_t pos, size_t len); +int sys_seek(int fd, off_t pos, int seek_type); +int sys_ioctl(int fd, ulong op, void *buf); +int sys_create(const char *path, stream_type stream_type); +int sys_unlink(const char *path); +int sys_rename(const char *oldpath, const char *newpath); +int sys_rstat(const char *path, struct stat *stat); +int sys_wstat(const char *path, struct stat *stat, int stat_mask); +int sys_fstat(int, struct stat *); +char *sys_getcwd(char* buf, size_t size); +int sys_setcwd(const char* path); +int sys_dup(int fd); +int sys_dup2(int ofd, int nfd); + +bigtime_t sys_system_time(); +int sys_snooze(bigtime_t time); +int sys_getrlimit(int resource, struct rlimit * rlp); +int sys_setrlimit(int resource, const struct rlimit * rlp); + +/* sem functions */ +sem_id kern_create_sem(int count, const char *name); +int kern_delete_sem(sem_id id); +int kern_acquire_sem(sem_id id); +int kern_acquire_sem_etc(sem_id id, int count, int flags, bigtime_t timeout); +int kern_release_sem(sem_id id); +int kern_release_sem_etc(sem_id id, int count, int flags); +int sys_sem_get_count(sem_id id, int32* thread_count); +int kern_get_sem_info(sem_id, struct sem_info *, size_t); +int kern_get_next_sem_info(proc_id, uint32 *, struct sem_info *, size_t); +int sys_set_sem_owner(sem_id id, proc_id proc); + + +int sys_proc_get_table(struct proc_info *pi, size_t len); +void sys_exit(int retcode); +proc_id sys_proc_create_proc(const char *path, const char *name, char **args, int argc, int priority); + +thread_id kern_spawn_thread(int (*func)(void*), const char *, int, void *); +thread_id kern_get_current_thread_id(void); +int kern_suspend_thread(thread_id tid); +int kern_resume_thread(thread_id tid); +int kern_kill_thread(thread_id tid); + +int sys_thread_wait_on_thread(thread_id tid, int *retcode); +int sys_proc_kill_proc(proc_id pid); + +proc_id sys_get_current_proc_id(); +int sys_proc_wait_on_proc(proc_id pid, int *retcode); + +region_id sys_vm_create_anonymous_region(const char *name, void **address, int addr_type, + addr size, int wiring, int lock); +region_id sys_vm_clone_region(const char *name, void **address, int addr_type, + region_id source_region, int mapping, int lock); +region_id sys_vm_map_file(const char *name, void **address, int addr_type, + addr size, int lock, int mapping, const char *path, off_t offset); +int sys_vm_delete_region(region_id id); +int sys_vm_get_region_info(region_id id, vm_region_info *info); + +/* kernel port functions */ +port_id sys_port_create(int32 queue_length, const char *name); +int sys_port_close(port_id id); +int sys_port_delete(port_id id); +port_id sys_port_find(const char *port_name); +int sys_port_get_info(port_id id, struct port_info *info); +int sys_port_get_next_port_info(proc_id proc, uint32 *cookie, struct port_info *info); +ssize_t sys_port_buffer_size(port_id port); +ssize_t sys_port_buffer_size_etc(port_id port, uint32 flags, bigtime_t timeout); +int32 sys_port_count(port_id port); +ssize_t sys_port_read(port_id port, int32 *msg_code, void *msg_buffer, size_t buffer_size); +ssize_t sys_port_read_etc(port_id port, int32 *msg_code, void *msg_buffer, size_t buffer_size, uint32 flags, bigtime_t timeout); +int sys_port_set_owner(port_id port, team_id proc); +int sys_port_write(port_id port, int32 msg_code, const void *msg_buffer, size_t buffer_size); +int sys_port_write_etc(port_id port, int32 msg_code, const void *msg_buffer, size_t buffer_size, uint32 flags, bigtime_t timeout); + +/* atomic_* ops (needed for cpus that dont support them directly) */ +int sys_atomic_add(int *val, int incr); +int sys_atomic_and(int *val, int incr); +int sys_atomic_or(int *val, int incr); +int sys_atomic_set(int *val, int set_to); +int sys_test_and_set(int *val, int set_to, int test_val); + +int sys_sysctl(int *, uint, void *, size_t *, void *, size_t); +int sys_socket(int, int, int); + +/* region prototypes */ +area_id sys_find_region_by_name(const char *); + +/* This is a real BSD'ism :) Basically it returns the size of the + * descriptor table for the current process as an integer. + */ +int kern_getdtablesize(void); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/headers/os/kernel/thread_types.h b/headers/os/kernel/thread_types.h new file mode 100644 index 0000000000..09b2bb3d53 --- /dev/null +++ b/headers/os/kernel/thread_types.h @@ -0,0 +1,172 @@ +#ifndef _KERNEL_THREAD_TYPES_H +#define _KERNEL_THREAD_TYPES_H + +/** + * @file kernel/thread_types.h + * @brief Definitions, structures and functions for threads. + */ + +/** + * @defgroup Kernel_Threads Threads + * @ingroup OpenBeOS_Kernel + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include +#include + + +#define THREAD_IDLE_PRIORITY 0 + +#define THREAD_NUM_PRIORITY_LEVELS 64 +#define THREAD_MIN_PRIORITY (THREAD_IDLE_PRIORITY + 1) +#define THREAD_MAX_PRIORITY (THREAD_NUM_PRIORITY_LEVELS - THREAD_NUM_RT_PRIORITY_LEVELS - 1) + +#define THREAD_NUM_RT_PRIORITY_LEVELS 16 +#define THREAD_MIN_RT_PRIORITY (THREAD_MAX_PRIORITY + 1) +#define THREAD_MAX_RT_PRIORITY (THREAD_NUM_PRIORITY_LEVELS - 1) + +#define THREAD_LOWEST_PRIORITY THREAD_MIN_PRIORITY +#define THREAD_LOW_PRIORITY 12 +#define THREAD_MEDIUM_PRIORITY 24 +#define THREAD_HIGH_PRIORITY 36 +#define THREAD_HIGHEST_PRIORITY THREAD_MAX_PRIORITY + +#define THREAD_RT_LOW_PRIORITY THREAD_MIN_RT_PRIORITY +#define THREAD_RT_HIGH_PRIORITY THREAD_MAX_RT_PRIORITY + +extern spinlock_t thread_spinlock; +#define GRAB_THREAD_LOCK() acquire_spinlock(&thread_spinlock) +#define RELEASE_THREAD_LOCK() release_spinlock(&thread_spinlock) + +enum { + THREAD_STATE_READY = 0, // ready to run + THREAD_STATE_RUNNING, // running right now somewhere + THREAD_STATE_WAITING, // blocked on something + THREAD_STATE_SUSPENDED, // suspended, not in queue + THREAD_STATE_FREE_ON_RESCHED, // free the thread structure upon reschedule + THREAD_STATE_BIRTH // thread is being created +}; + +enum { + PROC_STATE_NORMAL, // normal state + PROC_STATE_BIRTH, // being contructed + PROC_STATE_DEATH // being killed +}; + +#define SIG_NONE 0 +#define SIG_SUSPEND 1 +#define SIG_KILL 2 + +/** + * The proc structure. + * @note This is available only within the kernel. + */ +struct proc { + /** Pointer to next proc structure */ + struct proc *next; + /** The proc_id for this process. + * @note This is equivalent to a team_id (???) + */ + proc_id id; + /** name of the process + * @note The maximum length is current SYS_MAX_OS_NAME_LEN chars. + */ + char name[SYS_MAX_OS_NAME_LEN]; + /** How many threads does this process have? */ + int num_threads; + /** Current state of the process. */ + int state; + /** Signals pending for the process? */ + int pending_signals; + /** Pointer to the I/O context for this process. + * @note see fd.h for definition of ioctx + */ + void *ioctx; + /** Path ??? */ + char path[SYS_MAX_PATH_LEN]; + /** Our address space pointer */ + aspace_id _aspace_id; + vm_address_space *aspace; + vm_address_space *kaspace; + struct thread *main_thread; + struct thread *thread_list; + struct arch_proc arch_info; +}; + +struct thread { + struct thread *all_next; + struct thread *proc_next; + struct thread *q_next; + thread_id id; + char name[SYS_MAX_OS_NAME_LEN]; + int priority; + int state; + int next_state; + union cpu_ent *cpu; + int pending_signals; + bool in_kernel; + sem_id sem_blocking; + int sem_count; + int sem_acquire_count; + int sem_deleted_retcode; + int sem_errcode; + int sem_flags; + addr fault_handler; + addr entry; + void *args; + struct proc *proc; + sem_id return_code_sem; + region_id kernel_stack_region_id; + addr kernel_stack_base; + region_id user_stack_region_id; + addr user_stack_base; + + bigtime_t user_time; + bigtime_t kernel_time; + bigtime_t last_time; + + // architecture dependant section + struct arch_thread arch_info; +}; + +struct thread_queue { + struct thread *head; + struct thread *tail; +}; + +/** + * Process information structure + * @note Seem to be a lot of duplicated fields with main + * proc structure??? + */ +struct proc_info { + proc_id id; + char name[SYS_MAX_OS_NAME_LEN]; + int state; + int num_threads; +}; + +#if 1 +/** + * Test routine for threads. + * @note This function will be removed as is intended for test and + * development purposes only. + */ +int thread_test(void); +#endif + +#ifdef __cplusplus +} +#endif +/** @} */ + +#endif /* _KERNEL_THREAD_TYPES_H */ + diff --git a/headers/os/kernel/vfs_types.h b/headers/os/kernel/vfs_types.h new file mode 100644 index 0000000000..04e19589ed --- /dev/null +++ b/headers/os/kernel/vfs_types.h @@ -0,0 +1,35 @@ +#ifndef VFS_TYPES_H +#define VFS_TYPES_H + +#include + +typedef enum { + STREAM_TYPE_ANY = 0, + STREAM_TYPE_FILE, + STREAM_TYPE_DIR, + STREAM_TYPE_DEVICE +} stream_type; + +typedef void * fs_cookie; +typedef void * file_cookie; +typedef void * fs_vnode; + +//typedef struct iovec { +// void *start; +// size_t len; +//} iovec; + +typedef struct iovecs { + size_t num; + size_t total_len; + iovec vec[0]; +} iovecs; + +//struct file_stat { +// vnode_id vnid; +// stream_type type; +// off_t size; +//}; + +#endif + diff --git a/headers/os/kernel/vm_types.h b/headers/os/kernel/vm_types.h new file mode 100755 index 0000000000..7813272621 --- /dev/null +++ b/headers/os/kernel/vm_types.h @@ -0,0 +1,183 @@ +#ifndef _PUBLIC_KERNEL_VM_TYPES_H +#define _PUBLIC_KERNEL_VM_TYPES_H + +#include +#include +#include +#include +#include + +// vm page +typedef struct vm_page { + struct vm_page *queue_prev; + struct vm_page *queue_next; + + struct vm_page *hash_next; + + addr ppn; // physical page number + off_t offset; + + struct vm_cache_ref *cache_ref; + + struct vm_page *cache_prev; + struct vm_page *cache_next; + + unsigned int ref_count; + + unsigned int type : 2; + unsigned int state : 3; +} vm_page; + +enum { + PAGE_TYPE_PHYSICAL = 0, + PAGE_TYPE_DUMMY, + PAGE_TYPE_GUARD +}; + +enum { + PAGE_STATE_ACTIVE = 0, + PAGE_STATE_INACTIVE, + PAGE_STATE_BUSY, + PAGE_STATE_MODIFIED, + PAGE_STATE_FREE, + PAGE_STATE_CLEAR, + PAGE_STATE_WIRED, + PAGE_STATE_UNUSED +}; + +// vm_cache_ref +typedef struct vm_cache_ref { + struct vm_cache *cache; + mutex lock; + + struct vm_region *region_list; + + int ref_count; +} vm_cache_ref; + +// vm_cache +typedef struct vm_cache { + vm_page *page_list; + vm_cache_ref *ref; + struct vm_cache *source; + struct vm_store *store; + off_t virtual_size; + unsigned int temporary : 1; + unsigned int scan_skip : 1; +} vm_cache; + +// info about a region that external entities may want to know +// used in vm_get_region_info() +typedef struct vm_region_info { + region_id id; + addr base; + addr size; + int lock; + int wiring; + char name[SYS_MAX_OS_NAME_LEN]; +} vm_region_info; + +// vm region +typedef struct vm_region { + char *name; + region_id id; + addr base; + addr size; + int lock; + int wiring; + int ref_count; + + struct vm_cache_ref *cache_ref; + off_t cache_offset; + + struct vm_address_space *aspace; + struct vm_region *aspace_next; + struct vm_virtual_map *map; + struct vm_region *cache_next; + struct vm_region *cache_prev; + struct vm_region *hash_next; +} vm_region; + +// virtual map (1 per address space) +typedef struct vm_virtual_map { + vm_region *region_list; + vm_region *region_hint; + int change_count; + sem_id sem; + struct vm_address_space *aspace; + addr base; + addr size; +} vm_virtual_map; + +enum { + VM_ASPACE_STATE_NORMAL = 0, + VM_ASPACE_STATE_DELETION +}; + +// address space +typedef struct vm_address_space { + vm_virtual_map virtual_map; + vm_translation_map translation_map; + char *name; + aspace_id id; + int ref_count; + int fault_count; + int state; + addr scan_va; + addr working_set_size; + addr max_working_set; + addr min_working_set; + bigtime_t last_working_set_adjust; + struct vm_address_space *hash_next; +} vm_address_space; + +// vm_store +typedef struct vm_store { + struct vm_store_ops *ops; + struct vm_cache *cache; + void *data; + off_t committed_size; +} vm_store; + +// vm_store_ops +typedef struct vm_store_ops { + void (*destroy)(struct vm_store *backing_store); + off_t (*commit)(struct vm_store *backing_store, off_t size); + int (*has_page)(struct vm_store *backing_store, off_t offset); + ssize_t (*read)(struct vm_store *backing_store, off_t offset, iovecs *vecs); + ssize_t (*write)(struct vm_store *backing_store, off_t offset, iovecs *vecs); + int (*fault)(struct vm_store *backing_store, struct vm_address_space *aspace, off_t offset); + void (*acquire_ref)(struct vm_store *backing_store); + void (*release_ref)(struct vm_store *backing_store); +} vm_store_ops; + +// args for the create_area funcs +enum { + REGION_ADDR_ANY_ADDRESS = 0, + REGION_ADDR_EXACT_ADDRESS +}; + +enum { + REGION_NO_PRIVATE_MAP = 0, + REGION_PRIVATE_MAP +}; + +enum { + REGION_WIRING_LAZY = 0, + REGION_WIRING_WIRED, + REGION_WIRING_WIRED_ALREADY, + REGION_WIRING_WIRED_CONTIG + }; + +enum { + PHYSICAL_PAGE_NO_WAIT = 0, + PHYSICAL_PAGE_CAN_WAIT, +}; + +#define LOCK_RO 0x0 +#define LOCK_RW 0x1 +#define LOCK_KERNEL 0x2 +#define LOCK_MASK 0x3 + +#endif /* _PUBLIC_KERNEL_VM_TYPES_H */ + diff --git a/headers/os/media/Buffer.h b/headers/os/media/Buffer.h new file mode 100644 index 0000000000..7af0087c52 --- /dev/null +++ b/headers/os/media/Buffer.h @@ -0,0 +1,108 @@ +/******************************************************************************* +/ +/ File: Buffer.h +/ +/ Description: A BBuffer is a container of media data in the Media Kit +/ +/ Copyright 1997-98, Be Incorporated, All Rights Reserved +/ +*******************************************************************************/ + +#if !defined(_BUFFER_H) +#define _BUFFER_H + +#include + + +/*** A BBuffer is not the same thing as the area segment that gets cloned ***/ +/*** For each buffer that gets created, a BBuffer object is created to represent ***/ +/*** it in each participant address space. ***/ + + +struct _shared_buffer_list; + +struct buffer_clone_info { + buffer_clone_info(); + ~buffer_clone_info(); + media_buffer_id buffer; + area_id area; + size_t offset; + size_t size; + int32 flags; +private: + uint32 _reserved_[4]; +}; + + +class BBuffer +{ +public: + + void * Data(); /* returns NULL if buffer not correctly initialized */ + size_t SizeAvailable(); // total size of buffer (how much data can it hold) + size_t SizeUsed(); // how much was written (how much data does it hold) + void SetSizeUsed( + size_t size_used); + uint32 Flags(); + + void Recycle(); + buffer_clone_info CloneInfo() const; + + media_buffer_id ID(); /* 0 if not registered */ + media_type Type(); + media_header * Header(); + media_audio_header * AudioHeader(); + media_video_header * VideoHeader(); + + enum { /* for flags */ + B_F1_BUFFER = 0x1, + B_F2_BUFFER = 0x2, + B_SMALL_BUFFER = 0x80000000 + }; + + size_t Size(); // deprecated; use SizeAvailable() + +private: + + friend struct _buffer_id_cache; + friend struct _shared_buffer_list; + friend class BMediaRoster; + friend class BBufferProducer; + friend class BBufferConsumer; /* for buffer receiving */ + friend class BBufferGroup; + friend class BSmallBuffer; + + explicit BBuffer(const buffer_clone_info & info); + ~BBuffer(); /* BBuffer is NOT a virtual class!!! */ + + BBuffer(); /* not implemented */ + BBuffer(const BBuffer & clone); /* not implemented */ + BBuffer & operator=(const BBuffer & clone); /* not implemented */ + + void SetHeader(const media_header *header); + + media_header fMediaHeader; + _shared_buffer_list * fBufferList; + area_id fArea; + void * fData; + size_t fOffset; + size_t fSize; + media_buffer_id fBufferID; + int32 fFlags; + + uint32 _reserved_buffer_[11]; + +}; + + +class BSmallBuffer : public BBuffer +{ +public: + BSmallBuffer(); + +static size_t SmallBufferSizeLimit(); + +}; + +#endif /* _BUFFER_H */ + diff --git a/headers/os/media/BufferConsumer.h b/headers/os/media/BufferConsumer.h new file mode 100644 index 0000000000..31dc3fa969 --- /dev/null +++ b/headers/os/media/BufferConsumer.h @@ -0,0 +1,203 @@ +/******************************************************************************* +/ +/ File: BufferConsumer.h +/ +/ Description: A BBufferConsumer is anything that wants to receive buffers in the Media Kit +/ +/ Copyright 1997-98, Be Incorporated, All Rights Reserved +/ +*******************************************************************************/ + +#if !defined(_BUFFER_CONSUMER_H) +#define _BUFFER_CONSUMER_H + +#include +#include + +class _buffer_id_cache; + +class BBufferConsumer : + public virtual BMediaNode +{ +protected: + /* this has to be at the top to force a vtable */ +virtual ~BBufferConsumer(); + +public: + + media_type ConsumerType(); + + /* for encoding a region into the format needed for clipping requests */ +static status_t RegionToClipData( + const BRegion * region, + int32 * format, + int32 * ioSize, + void * data); + +protected: +explicit BBufferConsumer( + media_type consumer_type /* = B_MEDIA_UNKNOWN_TYPE */); + +static void NotifyLateProducer( + const media_source & what_source, + bigtime_t how_much, + bigtime_t performance_time); + status_t SetVideoClippingFor( + const media_source & output, + const media_destination & destination, + const int16 * shorts, + int32 short_count, + const media_video_display_info & display, + void * user_data, + int32 * change_tag, + void * _reserved_ = 0); // change_tag value will be passed to RequestCompleted() + status_t SetOutputEnabled( + const media_source & source, + const media_destination & destination, + bool enabled, + void * user_data, + int32 * change_tag, + void * _reserved_ = 0); // change_tag value will be passed to RequestCompleted() + status_t RequestFormatChange( + const media_source & source, + const media_destination & destination, + const media_format & to_format, + void * user_data, + int32 * change_tag, + void * _reserved_ = 0); // change_tag value will be passed to RequestCompleted() + status_t RequestAdditionalBuffer( // new in 4.1 + const media_source & source, + BBuffer * prev_buffer, + void * _reserved = NULL); + status_t RequestAdditionalBuffer( // new in 4.1 + const media_source & source, + bigtime_t start_time, + void * _reserved = NULL); + status_t SetOutputBuffersFor( // new in 4.1 + const media_source & source, + const media_destination & destination, + BBufferGroup * group, + void * user_data, + int32 * change_tag, // passed to RequestCompleted() + bool will_reclaim = false, + void * _reserved_ = 0); + status_t SendLatencyChange( + const media_source & source, + const media_destination & destination, + bigtime_t my_new_latency, + uint32 flags = 0); + +protected: + +virtual status_t HandleMessage( + int32 message, + const void * data, + size_t size); + + /* Someone, probably the producer, is asking you about this format. Give */ + /* your honest opinion, possibly modifying *format. Do not ask upstream */ + /* producer about the format, since he's synchronously waiting for your */ + /* reply. */ +virtual status_t AcceptFormat( + const media_destination & dest, + media_format * format) = 0; +virtual status_t GetNextInput( + int32 * cookie, + media_input * out_input) = 0; +virtual void DisposeInputCookie( + int32 cookie) = 0; +virtual void BufferReceived( + BBuffer * buffer) = 0; +virtual void ProducerDataStatus( + const media_destination & for_whom, + int32 status, + bigtime_t at_performance_time) = 0; +virtual status_t GetLatencyFor( + const media_destination & for_whom, + bigtime_t * out_latency, + media_node_id * out_timesource) = 0; +virtual status_t Connected( + const media_source & producer, /* here's a good place to request buffer group usage */ + const media_destination & where, + const media_format & with_format, + media_input * out_input) = 0; +virtual void Disconnected( + const media_source & producer, + const media_destination & where) = 0; + /* The notification comes from the upstream producer, so he's already cool with */ + /* the format; you should not ask him about it in here. */ +virtual status_t FormatChanged( + const media_source & producer, + const media_destination & consumer, + int32 change_tag, + const media_format & format) = 0; + + /* Given a performance time of some previous buffer, retrieve the remembered tag */ + /* of the closest (previous or exact) performance time. Set *out_flags to 0; the */ + /* idea being that flags can be added later, and the understood flags returned in */ + /* *out_flags. */ +virtual status_t SeekTagRequested( + const media_destination & destination, + bigtime_t in_target_time, + uint32 in_flags, + media_seek_tag * out_seek_tag, + bigtime_t * out_tagged_time, + uint32 * out_flags); + +private: + + friend class BMediaNode; + + BBufferConsumer(); /* private unimplemented */ + BBufferConsumer( + const BBufferConsumer & clone); + BBufferConsumer & operator=( + const BBufferConsumer & clone); + + // these functions are deprecated from the 4.0 API +static status_t SetVideoClippingFor( + const media_source & output, + const int16 * shorts, + int32 short_count, + const media_video_display_info & display, + int32 * change_tag); // change_tag value will be passed to RequestCompleted() +static status_t RequestFormatChange( + const media_source & source, + const media_destination & destination, + media_format * io_to_format, // the "o" part is unused from 4.1 + int32 * change_tag); // change_tag value will be passed to RequestCompleted() +static status_t SetOutputEnabled( + const media_source & source, + bool enabled, + int32 * change_tag); // change_tag value will be passed to RequestCompleted() + + /* Mmmh, stuffing! */ + status_t _Reserved_BufferConsumer_0(void *); /* SeekTagRequested */ +virtual status_t _Reserved_BufferConsumer_1(void *); +virtual status_t _Reserved_BufferConsumer_2(void *); +virtual status_t _Reserved_BufferConsumer_3(void *); +virtual status_t _Reserved_BufferConsumer_4(void *); +virtual status_t _Reserved_BufferConsumer_5(void *); +virtual status_t _Reserved_BufferConsumer_6(void *); +virtual status_t _Reserved_BufferConsumer_7(void *); +virtual status_t _Reserved_BufferConsumer_8(void *); +virtual status_t _Reserved_BufferConsumer_9(void *); +virtual status_t _Reserved_BufferConsumer_10(void *); +virtual status_t _Reserved_BufferConsumer_11(void *); +virtual status_t _Reserved_BufferConsumer_12(void *); +virtual status_t _Reserved_BufferConsumer_13(void *); +virtual status_t _Reserved_BufferConsumer_14(void *); +virtual status_t _Reserved_BufferConsumer_15(void *); + + friend class BMediaRoster; + + media_type fConsumerType; + _buffer_id_cache * fBufferCache; + BBufferGroup *fDeleteBufferGroup; + uint32 _reserved_buffer_consumer_[14]; + +}; + + +#endif /* _BUFFER_CONSUMER_H */ + diff --git a/headers/os/media/BufferGroup.h b/headers/os/media/BufferGroup.h new file mode 100644 index 0000000000..969f1f95bb --- /dev/null +++ b/headers/os/media/BufferGroup.h @@ -0,0 +1,81 @@ +/******************************************************************************* +/ +/ File: BufferGroup.h +/ +/ Description: A BBufferGroup organizes sets of BBuffers so that you can request +/ and reclaim them. +/ +/ Copyright 1997-98, Be Incorporated, All Rights Reserved +/ +*******************************************************************************/ + +#if !defined(_BUFFER_GROUP_H) +#define _BUFFER_GROUP_H + +#include + +struct _shared_buffer_list; + +class BBufferGroup +{ +public: + + BBufferGroup( + size_t size, + int32 count = 3, + uint32 placement = B_ANY_ADDRESS, + uint32 lock = B_FULL_LOCK); +explicit BBufferGroup(); + BBufferGroup( + int32 count, + const media_buffer_id * buffers); + ~BBufferGroup(); /* BBufferGroup is NOT a virtual class!!! */ + + status_t InitCheck(); + + /* use this function to add buffers you created on your own */ + status_t AddBuffer( + const buffer_clone_info & info, + BBuffer ** out_buffer = NULL); + + BBuffer * RequestBuffer( + size_t size, + bigtime_t timeout = B_INFINITE_TIMEOUT); + status_t RequestBuffer( + BBuffer * buffer, + bigtime_t timeout = B_INFINITE_TIMEOUT); + status_t RequestError(); /* return last RequestBuffer error, useful if NULL is returned */ + + status_t CountBuffers( + int32 * out_count); + status_t GetBufferList( + int32 buf_count, + BBuffer ** out_buffers); + + status_t WaitForBuffers(); + status_t ReclaimAllBuffers(); + +private: + /* in BeOS R5 this is a deprecated api, from BeOS R4 times */ + status_t AddBuffersTo(BMessage * message, const char * name, bool needLock=true); + + status_t InitBufferGroup(); /* used internally */ + BBufferGroup(const BBufferGroup &); /* not implemented */ + BBufferGroup& operator=(const BBufferGroup&); /* not implemented */ + + friend struct _shared_buffer_list; + + status_t fInitError; + status_t fRequestError; + int32 fBufferCount; + _shared_buffer_list * fBufferList; + + // this is a BBufferGroup specific semaphore used for reclaiming BBuffers of this group + // is also is a system wide unique identifier of this group + sem_id fReclaimSem; + + uint32 _reserved_buffer_group_[9]; +}; + +#endif /* _BUFFER_GROUP_H */ + diff --git a/headers/os/media/BufferProducer.h b/headers/os/media/BufferProducer.h new file mode 100644 index 0000000000..6016d75f2a --- /dev/null +++ b/headers/os/media/BufferProducer.h @@ -0,0 +1,239 @@ +/******************************************************************************* +/ +/ File: BBufferProducer.h +/ +/ Description: A BBufferProducer is any source of media buffers in the Media Kit +/ +/ Copyright 1997-98, Be Incorporated, All Rights Reserved +/ +*******************************************************************************/ + +#if !defined(_BUFFER_PRODUCER_H) +#define _BUFFER_PRODUCER_H + +#include +#include + + +class BBufferProducer : + public virtual BMediaNode +{ +protected: + /* this has to be at the top to force a vtable */ +virtual ~BBufferProducer(); + +public: + + /* Supported formats for low-level clipping data */ + enum { + B_CLIP_SHORT_RUNS = 1 + }; + + /* Handy conversion functions for dealing with clip information */ +static status_t ClipDataToRegion( + int32 format, + int32 size, + const void * data, + BRegion * region); + + media_type ProducerType(); + +protected: +explicit BBufferProducer( + media_type producer_type /* = B_MEDIA_UNKNOWN_TYPE */); + + enum suggestion_quality { + B_ANY_QUALITY = 0, + B_LOW_QUALITY = 10, + B_MEDIUM_QUALITY = 50, + B_HIGH_QUALITY = 100 + }; + + /* functionality of BBufferProducer */ +virtual status_t FormatSuggestionRequested( + media_type type, + int32 quality, + media_format * format) = 0; +virtual status_t FormatProposal( + const media_source & output, + media_format * format) = 0; + /* If the format isn't good, put a good format into *io_format and return error */ + /* If format has wildcard, specialize to what you can do (and change). */ + /* If you can change the format, return OK. */ + /* The request comes from your destination sychronously, so you cannot ask it */ + /* whether it likes it -- you should assume it will since it asked. */ +virtual status_t FormatChangeRequested( + const media_source & source, + const media_destination & destination, + media_format * io_format, + int32 * _deprecated_) = 0; +virtual status_t GetNextOutput( /* cookie starts as 0 */ + int32 * cookie, + media_output * out_output) = 0; +virtual status_t DisposeOutputCookie( + int32 cookie) = 0; + /* In this function, you should either pass on the group to your upstream guy, */ + /* or delete your current group and hang on to this group. Deleting the previous */ + /* group (unless you passed it on with the reclaim flag set to false) is very */ + /* important, else you will 1) leak memory and 2) block someone who may want */ + /* to reclaim the buffers living in that group. */ +virtual status_t SetBufferGroup( + const media_source & for_source, + BBufferGroup * group) = 0; + /* Format of clipping is (as int16-s): . */ + /* Repeat for each line where the clipping is different from the previous line. */ + /* If is negative, use the data from line - (there are 0 pairs after */ + /* a negative . Yes, we only support 32k*32k frame buffers for clipping. */ + /* Any non-0 field of 'display' means that that field changed, and if you don't support */ + /* that change, you should return an error and ignore the request. Note that the buffer */ + /* offset values do not have wildcards; 0 (or -1, or whatever) are real values and must */ + /* be adhered to. */ +virtual status_t VideoClippingChanged( + const media_source & for_source, + int16 num_shorts, + int16 * clip_data, + const media_video_display_info & display, + int32 * _deprecated_); + /* Iterates over all outputs and maxes the latency found */ +virtual status_t GetLatency( + bigtime_t * out_lantency); +virtual status_t PrepareToConnect( + const media_source & what, + const media_destination & where, + media_format * format, + media_source * out_source, + char * out_name) = 0; +virtual void Connect( + status_t error, + const media_source & source, + const media_destination & destination, + const media_format & format, + char * io_name) = 0; +virtual void Disconnect( + const media_source & what, + const media_destination & where) = 0; +virtual void LateNoticeReceived( + const media_source & what, + bigtime_t how_much, + bigtime_t performance_time) = 0; +virtual void EnableOutput( + const media_source & what, + bool enabled, + int32 * _deprecated_) = 0; +virtual status_t SetPlayRate( + int32 numer, + int32 denom); + +virtual status_t HandleMessage( /* call this from the thread that listens to the port */ + int32 message, + const void * data, + size_t size); + +virtual void AdditionalBufferRequested( // used to be Reserved 0 + const media_source & source, + media_buffer_id prev_buffer, + bigtime_t prev_time, + const media_seek_tag * prev_tag); // may be NULL + +virtual void LatencyChanged( // used to be Reserved 1 + const media_source & source, + const media_destination & destination, + bigtime_t new_latency, + uint32 flags); + + /* Use this function in BBufferProducer to pass on the buffer. */ + status_t SendBuffer( + BBuffer * buffer, + const media_destination & destination); + + status_t SendDataStatus( + int32 status, + const media_destination & destination, + bigtime_t at_time); + + /* Check in advance if a target is prepared to accept a format. You may */ + /* want to call this from Connect(), although that's not required. */ + status_t ProposeFormatChange( + media_format * format, + const media_destination & for_destination); + /* Tell consumer to accept a proposed format change */ + /* YOU MUST NOT CALL BROADCAST_BUFFER WHILE THIS CALL IS OUTSTANDING! */ + status_t ChangeFormat( + const media_source & for_source, + const media_destination & for_destination, + media_format * format); + /* Check how much latency the down-stream graph introduces */ + status_t FindLatencyFor( + const media_destination & for_destination, + bigtime_t * out_latency, + media_node_id * out_timesource); + + /* Find the tag of a previously seen buffer to expedite seeking */ + status_t FindSeekTag( + const media_destination & for_destination, + bigtime_t in_target_time, + media_seek_tag * out_tag, + bigtime_t * out_tagged_time, + uint32 * out_flags = 0, + uint32 in_flags = 0); + + /* Set the initial latency, which is the maximum additional latency */ + /* that will be imposed while starting/syncing to a signal (such as */ + /* starting a TV capture card in the middle of a field). Most nodes */ + /* have this at 0 (the default); only TV input Nodes need it currently */ + /* because they slave to a low-resolution (59.94 Hz) clock that arrives */ + /* from the outside world. Call this from the constructor if you need it. */ + void SetInitialLatency( + bigtime_t inInitialLatency, + uint32 flags = 0); + +private: + + friend class BMediaRoster; + friend class BBufferConsumer; + friend class BMediaNode; + + BBufferProducer(); /* private unimplemented */ + BBufferProducer( + const BBufferProducer & clone); + BBufferProducer & operator=( + const BBufferProducer & clone); + + /* Mmmh, stuffing! */ + status_t _Reserved_BufferProducer_0(void *); /* AdditionalBufferRequested() */ + status_t _Reserved_BufferProducer_1(void *); /* LatencyChanged() */ +virtual status_t _Reserved_BufferProducer_2(void *); +virtual status_t _Reserved_BufferProducer_3(void *); +virtual status_t _Reserved_BufferProducer_4(void *); +virtual status_t _Reserved_BufferProducer_5(void *); +virtual status_t _Reserved_BufferProducer_6(void *); +virtual status_t _Reserved_BufferProducer_7(void *); +virtual status_t _Reserved_BufferProducer_8(void *); +virtual status_t _Reserved_BufferProducer_9(void *); +virtual status_t _Reserved_BufferProducer_10(void *); +virtual status_t _Reserved_BufferProducer_11(void *); +virtual status_t _Reserved_BufferProducer_12(void *); +virtual status_t _Reserved_BufferProducer_13(void *); +virtual status_t _Reserved_BufferProducer_14(void *); +virtual status_t _Reserved_BufferProducer_15(void *); + + + media_type fProducerType; + bigtime_t fInitialLatency; + uint32 fInitialFlags; + +static status_t clip_shorts_to_region( + const int16 * data, + int count, + BRegion * output); +static status_t clip_region_to_shorts( + const BRegion * input, + int16 * data, + int max_count, + int * out_count); + + uint32 _reserved_buffer_producer_[14]; +}; + +#endif /* _BUFFER_PRODUCER_H */ + diff --git a/headers/os/media/Controllable.h b/headers/os/media/Controllable.h new file mode 100644 index 0000000000..b99339f5e9 --- /dev/null +++ b/headers/os/media/Controllable.h @@ -0,0 +1,139 @@ +/******************************************************************************* +/ +/ File: Controllable.h +/ +/ Description: A BControllable is a BMediaNode with "tweakable" parameters/settings. +/ +/ Copyright 1997-98, Be Incorporated, All Rights Reserved +/ +*******************************************************************************/ + +#if !defined(_CONTROLLABLE_H) +#define _CONTROLLABLE_H + +#include +#include + +class BParameterWeb; + + +class BControllable : + public virtual BMediaNode +{ +protected: + /* Need this to force vtable */ +virtual ~BControllable(); + +public: + + /* BControllable might seem somewhat spartan. */ + + /* That is because control change requests and notifications */ + /* typically come in/go out in B_MEDIA_PARAMETERS type buffers */ + /* (and a BControllable thus also needs to be a BBufferConsumer */ + /* and/or a BBufferProducer) */ + /* The format of these buffers is: */ + /* media_node(node), int32(count) */ + /* repeat(count) { int64(when), int32(control_id), int32(value_size), } */ + + BParameterWeb * Web(); + bool LockParameterWeb(); + void UnlockParameterWeb(); + +protected: + + BControllable(); /* call SetParameterWeb() from your constructor */ + status_t SetParameterWeb( + BParameterWeb * web); + +virtual status_t HandleMessage( + int32 message, + const void * data, + size_t size); + + /* Call when the actual control changes, NOT when the value changes. */ + /* A typical case would be a CD with a Selector for Track when a new CD is inserted */ + status_t BroadcastChangedParameter( + int32 id); + + /* Call this function when a value change takes effect, and */ + /* you want people who are interested to stay in sync with you. */ + /* Don't call this too densely, though, or you will flood the system */ + /* with messages. */ + status_t BroadcastNewParameterValue( + bigtime_t when, // performance time + int32 id, // parameter ID + void * newValue, + size_t valueSize); + + /* These are alternate methods of accomplishing the same thing as */ + /* connecting to control information source/destinations would. */ +virtual status_t GetParameterValue( + int32 id, + bigtime_t * last_change, + void * value, + size_t * ioSize) = 0; +virtual void SetParameterValue( + int32 id, + bigtime_t when, + const void * value, + size_t size) = 0; + + /* The default implementation of StartControlPanel launches the add-on */ + /* as an application (if the Node lives in an add-on). Thus, you can write your */ + /* control panel as a "main()" in your add-on, and it'll automagically work! */ + /* Your add-on needs to have multi-launch app flags for this to work right. */ + /* The first argv argument to main() will be a string of the format "node=%d" */ + /* with the node ID in question as "%d". */ +virtual status_t StartControlPanel( + BMessenger * out_messenger); + + /* Call this from your BufferReceived() for control information buffers */ + /* if you implement BBufferConsumer for that format (recommended!) */ + status_t ApplyParameterData( + const void * value, + size_t size); + /* If you want to generate control information for a set of controls, you */ + /* can use this utility function. */ + status_t MakeParameterData( + const int32 * controls, + int32 count, + void * buf, + size_t * ioSize); + +private: + + friend class BMediaNode; + + BControllable( /* private unimplemented */ + const BControllable & clone); + BControllable & operator=( + const BControllable & clone); + + /* Mmmh, stuffing! */ +virtual status_t _Reserved_Controllable_0(void *); +virtual status_t _Reserved_Controllable_1(void *); +virtual status_t _Reserved_Controllable_2(void *); +virtual status_t _Reserved_Controllable_3(void *); +virtual status_t _Reserved_Controllable_4(void *); +virtual status_t _Reserved_Controllable_5(void *); +virtual status_t _Reserved_Controllable_6(void *); +virtual status_t _Reserved_Controllable_7(void *); +virtual status_t _Reserved_Controllable_8(void *); +virtual status_t _Reserved_Controllable_9(void *); +virtual status_t _Reserved_Controllable_10(void *); +virtual status_t _Reserved_Controllable_11(void *); +virtual status_t _Reserved_Controllable_12(void *); +virtual status_t _Reserved_Controllable_13(void *); +virtual status_t _Reserved_Controllable_14(void *); +virtual status_t _Reserved_Controllable_15(void *); + + BParameterWeb * _mWeb; + sem_id _m_webSem; + int32 _m_webBen; + uint32 _reserved_controllable_[14]; +}; + + +#endif /* _CONTROLLABLE_H */ + diff --git a/headers/os/media/FileInterface.h b/headers/os/media/FileInterface.h new file mode 100644 index 0000000000..aacba0099d --- /dev/null +++ b/headers/os/media/FileInterface.h @@ -0,0 +1,91 @@ +/******************************************************************************* +/ +/ File: FileInterface.h +/ +/ Description: A BFileInterface is something which can read and/or write files for the +/ use of other Media Kit participants. +/ +/ Copyright 1997-98, Be Incorporated, All Rights Reserved +/ +*******************************************************************************/ + +#if !defined(_FILE_INTERFACE_H) +#define _FILE_INTERFACE_H + +#include +#include + + +class BFileInterface : + public virtual BMediaNode +{ +protected: + +virtual ~BFileInterface(); /* force vtable */ + +public: + + /* look, no hands! */ + +protected: + + BFileInterface(); +virtual status_t HandleMessage( + int32 message, + const void * data, + size_t size); + +virtual status_t GetNextFileFormat( + int32 * cookie, + media_file_format * out_format) = 0; +virtual void DisposeFileFormatCookie( + int32 cookie) = 0; + +virtual status_t GetDuration( + bigtime_t * out_time) = 0; +virtual status_t SniffRef( + const entry_ref & file, + char * out_mime_type, /* 256 bytes */ + float * out_quality) = 0; +virtual status_t SetRef( + const entry_ref & file, + bool create, + bigtime_t * out_time) = 0; +virtual status_t GetRef( + entry_ref * out_ref, + char * out_mime_type) = 0; + +private: + + friend class BMediaNode; + + BFileInterface( /* private unimplemented */ + const BFileInterface & clone); + BFileInterface & operator=( + const BFileInterface & clone); + + /* Mmmh, stuffing! */ +virtual status_t _Reserved_FileInterface_0(void *); +virtual status_t _Reserved_FileInterface_1(void *); +virtual status_t _Reserved_FileInterface_2(void *); +virtual status_t _Reserved_FileInterface_3(void *); +virtual status_t _Reserved_FileInterface_4(void *); +virtual status_t _Reserved_FileInterface_5(void *); +virtual status_t _Reserved_FileInterface_6(void *); +virtual status_t _Reserved_FileInterface_7(void *); +virtual status_t _Reserved_FileInterface_8(void *); +virtual status_t _Reserved_FileInterface_9(void *); +virtual status_t _Reserved_FileInterface_10(void *); +virtual status_t _Reserved_FileInterface_11(void *); +virtual status_t _Reserved_FileInterface_12(void *); +virtual status_t _Reserved_FileInterface_13(void *); +virtual status_t _Reserved_FileInterface_14(void *); +virtual status_t _Reserved_FileInterface_15(void *); + + uint32 _reserved_file_interface_[16]; + +}; + + +#endif /* _FILE_INTERFACE_H */ + diff --git a/headers/os/media/MediaAddOn.h b/headers/os/media/MediaAddOn.h new file mode 100644 index 0000000000..3847272747 --- /dev/null +++ b/headers/os/media/MediaAddOn.h @@ -0,0 +1,174 @@ +/******************************************************************************* +/ +/ File: MediaAddOn.h +/ +/ Description: A BMediaAddOn is created by Media Kit add-ons to instantiate and +/ handle "latent" Nodes. +/ +/ Copyright 1997-98, Be Incorporated, All Rights Reserved +/ +*******************************************************************************/ + +#if !defined(_MEDIA_ADD_ON_H) +#define _MEDIA_ADD_ON_H + +#include + +#include +#include + + +struct dormant_node_info { + dormant_node_info(); + ~dormant_node_info(); + + media_addon_id addon; + int32 flavor_id; + char name[B_MEDIA_NAME_LENGTH]; +private: + char reserved[128]; +}; + + + +enum +{ // flavor_flags + B_FLAVOR_IS_GLOBAL = 0x100000L, // force in media_addon_server, only one instance + B_FLAVOR_IS_LOCAL = 0x200000L // force in loading app, many instances + // if none is set, could go either way +}; + +struct flavor_info { + char * name; + char * info; + uint64 kinds; /* node_kind */ + uint32 flavor_flags; + int32 internal_id; /* For BMediaAddOn internal use */ + int32 possible_count; /* 0 for "any number" */ + + int32 in_format_count; /* for BufferConsumer kinds */ + uint32 in_format_flags; /* set to 0 */ + const media_format * in_formats; + + int32 out_format_count; /* for BufferProducer kinds */ + uint32 out_format_flags; /* set to 0 */ + const media_format * out_formats; + + uint32 _reserved_[16]; + +private: + flavor_info & operator=(const flavor_info & other); +}; + +struct dormant_flavor_info : public flavor_info, public BFlattenable { + + dormant_flavor_info(); +virtual ~dormant_flavor_info(); + dormant_flavor_info(const dormant_flavor_info &); + dormant_flavor_info& operator=(const dormant_flavor_info &); + dormant_flavor_info& operator=(const flavor_info &); + + dormant_node_info node_info; + + void set_name(const char * in_name); + void set_info(const char * in_info); + void add_in_format(const media_format & in_format); + void add_out_format(const media_format & out_format); + +virtual bool IsFixedSize() const; +virtual type_code TypeCode() const; +virtual ssize_t FlattenedSize() const; +virtual status_t Flatten(void *buffer, ssize_t size) const; +virtual status_t Unflatten(type_code c, const void *buf, ssize_t size); +}; + + + +/* a MediaAddOn is something which can manufacture MediaNodes */ +class BMediaAddOn +{ +public: +explicit BMediaAddOn( + image_id image); +virtual ~BMediaAddOn(); + +virtual status_t InitCheck( + const char ** out_failure_text); +virtual int32 CountFlavors(); +virtual status_t GetFlavorAt( + int32 n, + const flavor_info ** out_info); +virtual BMediaNode * InstantiateNodeFor( + const flavor_info * info, + BMessage * config, + status_t * out_error); +virtual status_t GetConfigurationFor( + BMediaNode * your_node, + BMessage * into_message); +virtual bool WantsAutoStart(); +virtual status_t AutoStart( + int in_count, + BMediaNode ** out_node, + int32 * out_internal_id, + bool * out_has_more); +/* only implement if you have a B_FILE_INTERFACE node */ +virtual status_t SniffRef( + const entry_ref & file, + BMimeType * io_mime_type, + float * out_quality, + int32 * out_internal_id); +virtual status_t SniffType( // This is broken if you deal with producers + const BMimeType & type, // and consumers both. Use SniffTypeKind instead. + float * out_quality, // If you implement SniffTypeKind, this doesn't + int32 * out_internal_id); // get called. +virtual status_t GetFileFormatList( + int32 flavor_id, // for this node flavor (if it matters) + media_file_format * out_writable_formats, // don't write here if NULL + int32 in_write_items, // this many slots in out_writable_formats + int32 * out_write_items, // set this to actual # available, even if bigger than in count + media_file_format * out_readable_formats, // don't write here if NULL + int32 in_read_items, // this many slots in out_readable_formats + int32 * out_read_items, // set this to actual # available, even if bigger than in count + void * _reserved); // ignore until further notice +virtual status_t SniffTypeKind( // Like SniffType, but for the specific kind(s) + const BMimeType & type, + uint64 in_kinds, + float * out_quality, + int32 * out_internal_id, + void * _reserved); + + image_id ImageID(); + media_addon_id AddonID(); + +protected: + + // Calling this will cause everyone to get notified, and also + // cause the server to re-scan your flavor info. It is thread safe. + status_t NotifyFlavorChange(); + +private: + BMediaAddOn(); /* private unimplemented */ + BMediaAddOn(const BMediaAddOn & clone); + BMediaAddOn & operator=(const BMediaAddOn & clone); + + /* Mmmh, stuffing! */ +virtual status_t _Reserved_MediaAddOn_2(void *); +virtual status_t _Reserved_MediaAddOn_3(void *); +virtual status_t _Reserved_MediaAddOn_4(void *); +virtual status_t _Reserved_MediaAddOn_5(void *); +virtual status_t _Reserved_MediaAddOn_6(void *); +virtual status_t _Reserved_MediaAddOn_7(void *); + + image_id _fImage; + media_addon_id _fAddon; + uint32 _reserved_media_add_on_[7]; +}; + + +#if BUILDING_MEDIA_ADDON +extern "C" _EXPORT BMediaAddOn * make_media_addon(image_id you); +#endif + + +#endif /* _MEDIA_ADD_ON_H */ + diff --git a/headers/os/media/MediaDecoder.h b/headers/os/media/MediaDecoder.h new file mode 100644 index 0000000000..12748810f0 --- /dev/null +++ b/headers/os/media/MediaDecoder.h @@ -0,0 +1,90 @@ +#ifndef MEDIADECODER_H +#define MEDIADECODER_H + +#include +#include + +namespace BPrivate { + class Decoder; +} + +class BMediaDecoder { + public: + BMediaDecoder(); + BMediaDecoder(const media_format *in_format, + const void *info = NULL, size_t info_size = 0); + BMediaDecoder(const media_codec_info *mci); + virtual ~BMediaDecoder(); + status_t InitCheck() const; + + status_t SetTo(const media_format *in_format, + const void *info = NULL, size_t info_size = 0); + status_t SetTo(const media_codec_info *mci); + status_t SetInputFormat(const media_format *in_format, + const void *in_info = NULL, size_t in_size = 0); + status_t SetOutputFormat(media_format *output_format); + // Set output format to closest acceptable format, returns the + // format used. + status_t Decode(void *out_buffer, int64 *out_frameCount, + media_header *out_mh, media_decode_info *info); + status_t GetDecoderInfo(media_codec_info *out_info) const; + + protected: + virtual status_t GetNextChunk(const void **chunkData, size_t *chunkLen, + media_header *mh) = 0; + + private: + + // unimplemented + BMediaDecoder(const BMediaDecoder &); + BMediaDecoder & operator=(const BMediaDecoder &); + + static status_t next_chunk(void *classptr, void **chunkData, size_t *chunkLen, media_header *mh); + void ReleaseDecoder(); + + BPrivate::Decoder *fDecoder; + int32 fDecoderID; + status_t fInitStatus; + + + /* fbc data and virtuals */ + + uint32 _reserved_BMediaDecoder_[32]; + + virtual status_t _Reserved_BMediaDecoder_0(int32 arg, ...); + virtual status_t _Reserved_BMediaDecoder_1(int32 arg, ...); + virtual status_t _Reserved_BMediaDecoder_2(int32 arg, ...); + virtual status_t _Reserved_BMediaDecoder_3(int32 arg, ...); + virtual status_t _Reserved_BMediaDecoder_4(int32 arg, ...); + virtual status_t _Reserved_BMediaDecoder_5(int32 arg, ...); + virtual status_t _Reserved_BMediaDecoder_6(int32 arg, ...); + virtual status_t _Reserved_BMediaDecoder_7(int32 arg, ...); + virtual status_t _Reserved_BMediaDecoder_8(int32 arg, ...); + virtual status_t _Reserved_BMediaDecoder_9(int32 arg, ...); + virtual status_t _Reserved_BMediaDecoder_10(int32 arg, ...); + virtual status_t _Reserved_BMediaDecoder_11(int32 arg, ...); + virtual status_t _Reserved_BMediaDecoder_12(int32 arg, ...); + virtual status_t _Reserved_BMediaDecoder_13(int32 arg, ...); + virtual status_t _Reserved_BMediaDecoder_14(int32 arg, ...); + virtual status_t _Reserved_BMediaDecoder_15(int32 arg, ...); +}; + +class BMediaBufferDecoder : public BMediaDecoder { + public: + BMediaBufferDecoder(); + BMediaBufferDecoder(const media_format *in_format, + const void *info = NULL, size_t info_size = 0); + BMediaBufferDecoder(const media_codec_info *mci); + status_t DecodeBuffer(const void *input_buffer, size_t input_size, + void *out_buffer, int64 *out_frameCount, + media_header *out_mh, + media_decode_info *info = NULL); + protected: + virtual status_t GetNextChunk(const void **chunkData, size_t *chunkLen, + media_header *mh); + const void *buffer; + int32 buffer_size; +}; + +#endif + diff --git a/headers/os/media/MediaDefs.h b/headers/os/media/MediaDefs.h new file mode 100644 index 0000000000..3554af3141 --- /dev/null +++ b/headers/os/media/MediaDefs.h @@ -0,0 +1,736 @@ +/******************************************************************************* +/ +/ File: MediaDefs.h +/ +/ Description: Basic data types and defines for the Media Kit. +/ +/ Copyright 1997-1999, Be Incorporated, All Rights Reserved +/ +*******************************************************************************/ + +#if !defined(_MEDIA_DEFS_H) +#define _MEDIA_DEFS_H + +#include +#include +#include +#include + +#if defined(__cplusplus) +#include +#include +#endif + + +#define B_MEDIA_NAME_LENGTH 64 + + +enum { /* maybe migrate these into Errors.h */ + B_MEDIA_SYSTEM_FAILURE = (int)B_MEDIA_ERROR_BASE+0x100, /* 80004100 */ + B_MEDIA_BAD_NODE, + B_MEDIA_NODE_BUSY, + B_MEDIA_BAD_FORMAT, + B_MEDIA_BAD_BUFFER, + B_MEDIA_TOO_MANY_NODES, + B_MEDIA_TOO_MANY_BUFFERS, + B_MEDIA_NODE_ALREADY_EXISTS, + B_MEDIA_BUFFER_ALREADY_EXISTS, + B_MEDIA_CANNOT_SEEK, + B_MEDIA_CANNOT_CHANGE_RUN_MODE, + B_MEDIA_APP_ALREADY_REGISTERED, + B_MEDIA_APP_NOT_REGISTERED, + B_MEDIA_CANNOT_RECLAIM_BUFFERS, + B_MEDIA_BUFFERS_NOT_RECLAIMED, + B_MEDIA_TIME_SOURCE_STOPPED, + B_MEDIA_TIME_SOURCE_BUSY, /* 80004110 */ + B_MEDIA_BAD_SOURCE, + B_MEDIA_BAD_DESTINATION, + B_MEDIA_ALREADY_CONNECTED, + B_MEDIA_NOT_CONNECTED, + B_MEDIA_BAD_CLIP_FORMAT, + B_MEDIA_ADDON_FAILED, + B_MEDIA_ADDON_DISABLED, + B_MEDIA_CHANGE_IN_PROGRESS, + B_MEDIA_STALE_CHANGE_COUNT, + B_MEDIA_ADDON_RESTRICTED, + B_MEDIA_NO_HANDLER, + B_MEDIA_DUPLICATE_FORMAT, + B_MEDIA_REALTIME_DISABLED, + B_MEDIA_REALTIME_UNAVAILABLE +}; + +/* Notification message 'what's */ +enum { + // Note that BMediaNode::node_error also belongs in here! */ + B_MEDIA_WILDCARD = 'TRWC', /* used to match any notification in Start/StopWatching */ + B_MEDIA_NODE_CREATED = 'TRIA', /* "media_node_id" (multiple items) */ + B_MEDIA_NODE_DELETED, /* "media_node_id" (multiple items) */ + B_MEDIA_CONNECTION_MADE, /* "output", "input", "format" */ + B_MEDIA_CONNECTION_BROKEN, /* "source", "destination" */ + B_MEDIA_BUFFER_CREATED, /* "clone_info" -- handled by BMediaRoster */ + B_MEDIA_BUFFER_DELETED, /* "media_buffer_id" -- handled by BMediaRoster */ + B_MEDIA_TRANSPORT_STATE, /* "state", "location", "realtime" */ + B_MEDIA_PARAMETER_CHANGED, /* N "node", "parameter" */ + B_MEDIA_FORMAT_CHANGED, /* N "source", "destination", "format" */ + B_MEDIA_WEB_CHANGED, /* N "node" */ + B_MEDIA_DEFAULT_CHANGED, /* "default", "node" -- handled by BMediaRoster */ + B_MEDIA_NEW_PARAMETER_VALUE, /* N "node", "parameter", "when", "value" */ + B_MEDIA_NODE_STOPPED, /* N "node", "when" */ + B_MEDIA_FLAVORS_CHANGED /* "be:addon_id", "be:new_count", "be:gone_count" */ +}; + +enum media_type { + B_MEDIA_NO_TYPE = -1, + B_MEDIA_UNKNOWN_TYPE = 0, + B_MEDIA_RAW_AUDIO = 1, /* uncompressed raw_audio -- linear relationship bytes <-> samples */ + B_MEDIA_RAW_VIDEO, /* uncompressed raw_video -- linear relationship bytes <-> pixels */ + B_MEDIA_VBL, /* raw data from VBL area, 1600/line */ + B_MEDIA_TIMECODE, /* data format TBD */ + B_MEDIA_MIDI, + B_MEDIA_TEXT, /* typically closed captioning */ + B_MEDIA_HTML, + B_MEDIA_MULTISTREAM, /* AVI, etc */ + B_MEDIA_PARAMETERS, /* BControllable change data */ + B_MEDIA_ENCODED_AUDIO, /* dts, AC3, ... */ + B_MEDIA_ENCODED_VIDEO, /* Indeo, MPEG, ... */ + B_MEDIA_PRIVATE = 90000, /* Don't touch! */ + B_MEDIA_FIRST_USER_TYPE = 100000 /* Use something bigger than this for */ + /* experimentation with your own media forms */ +}; + +enum node_kind { + B_BUFFER_PRODUCER = 0x1, + B_BUFFER_CONSUMER = 0x2, + B_TIME_SOURCE = 0x4, + B_CONTROLLABLE = 0x8, + B_FILE_INTERFACE = 0x10, + B_ENTITY_INTERFACE = 0x20, + /* Set these flags for nodes that are suitable as default entities */ + B_PHYSICAL_INPUT = 0x10000, + B_PHYSICAL_OUTPUT = 0x20000, + B_SYSTEM_MIXER = 0x40000 +}; + +enum video_orientation { /* for orientation, which pixel is first and how do we scan each "line"? */ + B_VIDEO_TOP_LEFT_RIGHT = 1, /* This is the typical progressive scan format */ + B_VIDEO_BOTTOM_LEFT_RIGHT /* This is how BMP and TGA might scan */ +}; + + +enum media_flags /* data */ +{ + B_MEDIA_FLAGS_VERSION = 1, /* uint32, bigger for newer */ + B_MEDIA_FLAGS_PRIVATE = 0x40000000 /* private to Be */ +}; + + +enum media_producer_status { /* for producer status */ + B_DATA_NOT_AVAILABLE = 1, + B_DATA_AVAILABLE = 2, + B_PRODUCER_STOPPED = 3 +}; + +// realtime flags +enum media_realtime_flags { + B_MEDIA_REALTIME_ALLOCATOR = 0x1, + B_MEDIA_REALTIME_AUDIO = 0x2, + B_MEDIA_REALTIME_VIDEO = 0x4, + B_MEDIA_REALTIME_ANYKIND = 0xffff +}; + +enum media_frame_flags { + B_MEDIA_KEY_FRAME = 0x1 +}; + +#define B_MEDIA_ANY_QUALITY 0.0f +#define B_MEDIA_LOW_QUALITY 0.1f +#define B_MEDIA_MEDIUM_QUALITY 0.5f +#define B_MEDIA_HIGH_QUALITY 1.0f + + +#if !defined(_MULTI_AUDIO_H) /* #define in protocol header */ +enum media_multi_channels { + B_CHANNEL_LEFT = 0x1, + B_CHANNEL_RIGHT = 0x2, + B_CHANNEL_CENTER = 0x4, /* 5.1+ or fake surround */ + B_CHANNEL_SUB = 0x8, /* 5.1+ */ + B_CHANNEL_REARLEFT = 0x10, /* quad surround or 5.1+ */ + B_CHANNEL_REARRIGHT = 0x20, /* quad surround or 5.1+ */ + B_CHANNEL_FRONT_LEFT_CENTER = 0x40, + B_CHANNEL_FRONT_RIGHT_CENTER = 0x80, + B_CHANNEL_BACK_CENTER = 0x100, /* 6.1 or fake surround */ + B_CHANNEL_SIDE_LEFT = 0x200, + B_CHANNEL_SIDE_RIGHT = 0x400, + B_CHANNEL_TOP_CENTER = 0x800, + B_CHANNEL_TOP_FRONT_LEFT = 0x1000, + B_CHANNEL_TOP_FRONT_CENTER = 0x2000, + B_CHANNEL_TOP_FRONT_RIGHT = 0x4000, + B_CHANNEL_TOP_BACK_LEFT = 0x8000, + B_CHANNEL_TOP_BACK_CENTER = 0x10000, + B_CHANNEL_TOP_BACK_RIGHT = 0x20000 +}; +enum media_multi_matrix { + B_MATRIX_PROLOGIC_LR = 0x1, + B_MATRIX_AMBISONIC_WXYZ = 0x4 +}; +#endif + + +typedef int32 media_node_id; +typedef int32 media_buffer_id; +typedef int32 media_addon_id; + + +#if defined(__cplusplus) +struct media_destination { + media_destination(port_id, int32); + media_destination(const media_destination & clone); + media_destination & operator=(const media_destination & clone); + media_destination(); + ~media_destination(); + port_id port; /* can be different from media_node.port */ + int32 id; +static media_destination null; +private: + uint32 _reserved_media_destination_[2]; +}; + +struct media_source { + media_source(port_id, int32); + media_source(const media_source & clone); + media_source & operator=(const media_source & clone); + media_source(); + ~media_source(); + port_id port; /* must be the same as media_node.port for owner */ + int32 id; +static media_source null; +private: + uint32 _reserved_media_source_[2]; +}; + +_IMPEXP_MEDIA bool operator==(const media_destination & a, const media_destination & b); +_IMPEXP_MEDIA bool operator!=(const media_destination & a, const media_destination & b); +_IMPEXP_MEDIA bool operator<(const media_destination & a, const media_destination & b); +_IMPEXP_MEDIA bool operator==(const media_source & a, const media_source & b); +_IMPEXP_MEDIA bool operator!=(const media_source & a, const media_source & b); +_IMPEXP_MEDIA bool operator<(const media_source & a, const media_source & b); +_IMPEXP_MEDIA bool operator==(const media_node & a, const media_node & b); +_IMPEXP_MEDIA bool operator!=(const media_node & a, const media_node & b); +_IMPEXP_MEDIA bool operator<(const media_node & a, const media_node & b); + + + +/* Buffers are low-level constructs identified by an ID. */ +/* Buffers consist of the actual data area, plus a 64-byte */ +/* header area that is different for each type. */ +/* Buffers contain typed data. Type is not part of the */ +/* buffer header; it's negotiated out-of-bounds by nodes. */ + +enum { + B_MEDIA_BIG_ENDIAN = 1, + B_MEDIA_LITTLE_ENDIAN = 2, +#if B_HOST_IS_BENDIAN + B_MEDIA_HOST_ENDIAN = B_MEDIA_BIG_ENDIAN +#else + B_MEDIA_HOST_ENDIAN = B_MEDIA_LITTLE_ENDIAN +#endif +}; + +struct media_multi_audio_format; + +struct media_raw_audio_format { + enum { // for "format" + B_AUDIO_FLOAT = 0x24, // 0 == mid, -1.0 == bottom, 1.0 == top (the preferred format for non-game audio) + B_AUDIO_INT = 0x4, // 0 == mid, 0x80000001 == bottom, 0x7fffffff == top (all >16-bit formats, left-adjusted) + B_AUDIO_SHORT = 0x2, // 0 == mid, -32767 == bottom, +32767 == top + B_AUDIO_UCHAR = 0x11, // 128 == mid, 1 == bottom, 255 == top (discouraged but supported format) + B_AUDIO_CHAR = 0x1, // 0 == mid, -127 == bottom, +127 == top (not officially supported format) + B_AUDIO_SIZE_MASK = 0xf + }; // we guarantee that (format&0xf) == sizeof(sample) for raw formats + + float frame_rate; + uint32 channel_count; // 1 or 2, mostly + uint32 format; // for compressed formats, go to media_encoded_audio_format + uint32 byte_order; // 2 for little endian (B_MEDIA_LITTLE_ENDIAN), 1 for big endian (B_MEDIA_BIG_ENDIAN) + size_t buffer_size; // size of each buffer + +static media_multi_audio_format wildcard; +}; + +struct media_audio_header { + // please put actual data at the end + int32 _reserved_[16]; // gotta have something +}; + +struct media_multi_audio_info { + uint32 channel_mask; // bitmask + int16 valid_bits; // if < 32, for B_AUDIO_INT + uint16 matrix_mask; // each of these bits may mean more than one channel + + uint32 _reserved_b[3]; +}; + +#if defined(__cplusplus) +struct media_multi_audio_format : public media_raw_audio_format, public media_multi_audio_info { +static media_multi_audio_format wildcard; +}; +#else +struct media_multi_audio_format { + media_raw_audio_format raw; + media_multi_audio_info multi; +}; +#endif + + +struct media_encoded_audio_format { + enum audio_encoding { + B_ANY + }; + media_raw_audio_format output; + audio_encoding encoding; + + float bit_rate; // BIT rate, not byte rate + size_t frame_size; + + media_multi_audio_info multi_info; + + uint32 _reserved_[3]; + +static media_encoded_audio_format wildcard; +}; + +struct media_encoded_audio_header { + // please put actual data at the end + int32 _reserved_0[14]; // gotta have something + uint32 buffer_flags; // B_MEDIA_KEY_FRAME for key buffers (ADPCM etc) + uchar unused_mask; // mask of unused bits for the last byte of data + uchar _reserved_2[3]; + +}; + +enum media_display_flags { + B_F1_DOMINANT = 0x1, // The first buffer sent (temporally) will be an F1 field + B_F2_DOMINANT = 0x2, // The first buffer sent (temporally) will be an F2 field + B_TOP_SCANLINE_F1 = 0x4, // The topmost scanline of the output buffer belongs to F1 + B_TOP_SCANLINE_F2 = 0x8 // The topmost scanline of the output buffer belongs to F2 +}; +struct media_video_display_info { + color_space format; + uint32 line_width; + uint32 line_count; // total of all interlace fields + uint32 bytes_per_row; // bytes_per_row is in format, not header, because it's part of SetBuffers + uint32 pixel_offset; // (in pixels) ... These are offsets from the start of the buffer ... + uint32 line_offset; // (in lines) ... to the start of the field. Think "buffer == framebuffer" ... + // ... when the window displaying the active field moves on screen. + uint32 flags; + uint32 _reserved_[3]; +static media_video_display_info wildcard; +}; + +struct media_raw_video_format { + float field_rate; + uint32 interlace; // how many fields per frame -- 1 means progressive (non-interlaced) + uint32 first_active; // 0, typically (wildcard, or "don't care") + uint32 last_active; // line_count-1, if first_active is 0. + uint32 orientation; // B_VIDEO_TOP_LEFT_RIGHT is preferred + // PIXEL aspect ratio; not active area aspect ratio... + uint16 pixel_width_aspect; // 1:1 has 1 here, 4:3 has 4 here + uint16 pixel_height_aspect; // 1:1 has 1 here, 4:3 has 3 here + + media_video_display_info display; + +static media_raw_video_format wildcard; +}; + +struct media_video_header { + uint32 _reserved_[12]; // at the top to push used data to the end + float field_gamma; + uint32 field_sequence; // sequence since start of capture -- may roll over if machine is on for a LONG time + uint16 field_number; // 0 .. {interlace-1}; F1 == 0 ("odd"), F2 == 1 ("even") + uint16 pulldown_number; // 0..2 for pulldown duplicated sequence + uint16 first_active_line; // the NTSC/PAL line number (1-based) of the first line in this field + uint16 line_count; // number of active lines in buffer +}; + +struct media_encoded_video_format { + enum video_encoding { + B_ANY + }; + media_raw_video_format output; // set unknowns to wildcard + float avg_bit_rate; + float max_bit_rate; + video_encoding encoding; + size_t frame_size; + int16 forward_history; // maximum forward memory required by algorithm + int16 backward_history; // maximum backward memory required by algorithm + + uint32 _reserved_[3]; // can't grow more than this + +static media_encoded_video_format wildcard; +}; + +struct media_encoded_video_header { + /* please put actual data at the end */ + int32 _reserved_1[9]; // gotta have something... + + uint32 field_flags; // B_MEDIA_KEY_FRAME + + int16 forward_history; // forward memory required by this buffer (0 for key frames) + int16 backward_history; // backward memory required by this buffer (0 for key frames) + uchar unused_mask; // mask of unused bits for the last byte of data + uchar _reserved_2[3]; + float field_gamma; + uint32 field_sequence; // sequence since start of capture + uint16 field_number; // 0 .. {interlace-1}; F1 == 0, F2 == 1 + uint16 pulldown_number; // 0..2 for pulldown duplicated sequence + uint16 first_active_line; // 0 or 1, typically, but could be 10 or 11 for full-NTSC formats + uint16 line_count; // number of actual lines in buffer +}; + +struct media_multistream_format { + enum { + B_ANY = 0, + B_VID = 1, // raw raw_video/raw_audio buffers + B_AVI, + B_MPEG1, + B_MPEG2, + B_QUICKTIME, + B_PRIVATE = 90000, + B_FIRST_USER_TYPE = 100000 // user formats >= 100000 + }; + float avg_bit_rate; // 8 * byte rate, on average + float max_bit_rate; // 8 * byte rate, tops + uint32 avg_chunk_size; // == max_chunk_size for fixed-size chunks + uint32 max_chunk_size; // max buffer size + enum { + B_HEADER_HAS_FLAGS = 0x1, // are flags important? + B_CLEAN_BUFFERS = 0x2, // each buffer represents an integral number of "frames" + B_HOMOGENOUS_BUFFERS = 0x4 // a buffer has only one format in it + }; + uint32 flags; + int32 format; + uint32 _reserved_[2]; + + struct vid_info { + float frame_rate; + uint16 width; + uint16 height; + color_space space; + + float sampling_rate; + uint32 sample_format; + uint16 byte_order; + uint16 channel_count; + }; + struct avi_info { + uint32 us_per_frame; + uint16 width; + uint16 height; + uint16 _reserved_; + uint16 type_count; + media_type types[5]; + }; + + union { + vid_info vid; + avi_info avi; + } u; + +static media_multistream_format wildcard; +}; + +struct media_multistream_header { + uint32 _reserved_[14]; + uchar unused_mask; // mask of unused bits for the last byte of data + uchar _reserved_2[3]; + enum { + B_MASTER_HEADER = 0x1, // for master stream header data in buffer + B_SUBSTREAM_HEADER = 0x2, // for sub-stream header data in buffer + B_COMPLETE_BUFFER = 0x4 // data is an integral number of "frames" + }; + uint32 flags; +}; + +extern const type_code B_CODEC_TYPE_INFO; + +enum media_format_flags { + B_MEDIA_RETAINED_DATA = 0x1, + B_MEDIA_MULTIPLE_BUFFERS = 0x2, + B_MEDIA_CONTIGUOUS_BUFFER = 0x4, + B_MEDIA_LINEAR_UPDATES = 0x8, + B_MEDIA_MAUI_UNDEFINED_FLAGS = ~0xf /* always deny these */ +}; + +/* typically, a field of 0 means "anything" or "wildcard" */ +struct media_format { /* no more than 192 bytes */ + media_type type; + type_code user_data_type; + uchar user_data[48]; + uint32 _reserved_[3]; + uint16 require_flags; // media_format_flags + uint16 deny_flags; // media_format_flags + + private: + + void * meta_data; + int32 meta_data_size; + area_id meta_data_area; + area_id use_area; + team_id team; + void * thisPtr; + + public: + + union { + media_multi_audio_format raw_audio; + media_raw_video_format raw_video; + media_multistream_format multistream; + media_encoded_audio_format encoded_audio; + media_encoded_video_format encoded_video; + char _reserved_[96]; // pad to 96 bytes + } u; + + bool IsVideo() const { return (type==B_MEDIA_ENCODED_VIDEO)||(type==B_MEDIA_RAW_VIDEO); }; + uint32 Width() const { return (type==B_MEDIA_ENCODED_VIDEO)?u.encoded_video.output.display.line_width:u.raw_video.display.line_width; }; + uint32 Height() const { return (type==B_MEDIA_ENCODED_VIDEO)?u.encoded_video.output.display.line_count:u.raw_video.display.line_count; }; + color_space ColorSpace() const { return (type==B_MEDIA_ENCODED_VIDEO)?u.encoded_video.output.display.format:u.raw_video.display.format; }; + uint32 & Width() { return (type==B_MEDIA_ENCODED_VIDEO)?u.encoded_video.output.display.line_width:u.raw_video.display.line_width; }; + uint32 & Height() { return (type==B_MEDIA_ENCODED_VIDEO)?u.encoded_video.output.display.line_count:u.raw_video.display.line_count; }; + color_space & ColorSpace() { return (type==B_MEDIA_ENCODED_VIDEO)?u.encoded_video.output.display.format:u.raw_video.display.format; }; + + bool IsAudio() const { return (type==B_MEDIA_ENCODED_AUDIO)||(type==B_MEDIA_RAW_AUDIO); }; + uint32 AudioFormat() const { return (type==B_MEDIA_ENCODED_AUDIO)?u.encoded_audio.output.format:u.raw_audio.format; }; + uint32 & AudioFormat() { return (type==B_MEDIA_ENCODED_AUDIO)?u.encoded_audio.output.format:u.raw_audio.format; }; + + uint32 Encoding() const { return (type==B_MEDIA_ENCODED_VIDEO)?u.encoded_video.encoding:(type==B_MEDIA_ENCODED_AUDIO)?u.encoded_audio.encoding:(type==B_MEDIA_MULTISTREAM)?u.multistream.format:0UL; } + + bool Matches(const media_format *otherFormat) const; + void SpecializeTo(const media_format *otherFormat); + + status_t SetMetaData(const void *data, size_t size); + const void * MetaData() const; + int32 MetaDataSize() const; + + media_format(); + media_format(const media_format &other); + ~media_format(); + media_format & operator=(const media_format & clone); +}; + +_IMPEXP_MEDIA bool operator==(const media_raw_audio_format & a, const media_raw_audio_format & b); +_IMPEXP_MEDIA bool operator==(const media_multi_audio_info & a, const media_multi_audio_info & b); +_IMPEXP_MEDIA bool operator==(const media_multi_audio_format & a, const media_multi_audio_format & b); +_IMPEXP_MEDIA bool operator==(const media_encoded_audio_format & a, const media_encoded_audio_format & b); +_IMPEXP_MEDIA bool operator==(const media_video_display_info & a, const media_video_display_info & b); +_IMPEXP_MEDIA bool operator==(const media_raw_video_format & a, const media_raw_video_format & b); +_IMPEXP_MEDIA bool operator==(const media_encoded_video_format & a, const media_encoded_video_format & b); +_IMPEXP_MEDIA bool operator==(const media_multistream_format::vid_info & a, const media_multistream_format::vid_info & b); +_IMPEXP_MEDIA bool operator==(const media_multistream_format::avi_info & a, const media_multistream_format::avi_info & b); +_IMPEXP_MEDIA bool operator==(const media_multistream_format & a, const media_multistream_format & b); +_IMPEXP_MEDIA bool operator==(const media_format & a, const media_format & b); + +/* return true if a and b are compatible (accounting for wildcards) */ +_IMPEXP_MEDIA bool format_is_compatible(const media_format & a, const media_format & b); /* a is the format you want to feed to something accepting b */ +_IMPEXP_MEDIA bool string_for_format(const media_format & f, char * buf, size_t size); + +struct media_seek_tag { + char data[16]; +}; + +struct media_header_time_code { + int8 type; // See TimeCode.h; don't use the "DEFAULT" value + int8 _reserved; + int8 hours; + int8 minutes; + int8 seconds; + int8 frames; + int16 subframes; // -1 if not available +}; + +struct media_header { // Broadcast() fills in fields marked with "//+" + media_type type; // what kind of data (for union) + media_buffer_id buffer; //+ what buffer does this header go with? + int32 destination; //+ what 'socket' is this intended for? + media_node_id time_source; // node that encoded start_time + uint32 _deprecated_; // used to be change_tag + uint32 size_used; // size within buffer that is used + bigtime_t start_time; // performance time + area_id owner; //+ buffer owner info area + enum { + B_SEEK_TAG = 'TRST', // user data type of the codec seek + // protocol. size of seek tag is 16 bytes + B_TIME_CODE = 'TRTC' // user data is media_header_time_code + }; + type_code user_data_type; + uchar user_data[64]; // user_data_type indicates what this is + uint32 _reserved_[2]; + + off_t file_pos; // where in a file this data came from + size_t orig_size; // and how big it was. if unused, zero out + + uint32 data_offset; // offset within buffer (already reflected in Data()) + + union { + media_audio_header raw_audio; + media_video_header raw_video; + media_multistream_header multistream; + media_encoded_audio_header encoded_audio; + media_encoded_video_header encoded_video; + char _reserved_[64]; // pad to 64 bytes + } u; +}; + + +struct media_file_format_id { + ino_t node; + dev_t device; + uint32 internal_id; +}; +_IMPEXP_MEDIA bool operator==(const media_file_format_id & a, const media_file_format_id & b); +_IMPEXP_MEDIA bool operator<(const media_file_format_id & a, const media_file_format_id & b); + +typedef enum { + B_ANY_FORMAT_FAMILY = 0, + B_BEOS_FORMAT_FAMILY = 1, + B_QUICKTIME_FORMAT_FAMILY = 2, /* QuickTime is a registered trademark of Apple Computer */ + B_AVI_FORMAT_FAMILY = 3, + B_ASF_FORMAT_FAMILY = 4, + B_MPEG_FORMAT_FAMILY = 5, + B_WAV_FORMAT_FAMILY = 6, + B_AIFF_FORMAT_FAMILY = 7, + B_AVR_FORMAT_FAMILY = 8, + + B_MISC_FORMAT_FAMILY = 99999 +} media_format_family; + +struct media_file_format { + enum { /* flags */ + B_READABLE = 0x1, + B_WRITABLE = 0x2, + B_PERFECTLY_SEEKABLE = 0x4, + B_IMPERFECTLY_SEEKABLE = 0x8, + B_KNOWS_RAW_VIDEO = 0x10, + B_KNOWS_RAW_AUDIO = 0x20, + B_KNOWS_MIDI = 0x40, + B_KNOWS_ENCODED_VIDEO = 0x80, + B_KNOWS_ENCODED_AUDIO = 0x100, + B_KNOWS_OTHER = 0x1000000, /* clipping, text, control, ... */ + B_KNOWS_ANYTHING = 0x2000000 + }; + uint32 capabilities; // can this format support audio, video, etc + media_file_format_id id; // opaque id used to construct a BMediaFile + media_format_family family; // one of the family enums + int32 version; // 100 for 1.0 + + uint32 _reserved_[25]; + + char mime_type[64]; // eg: "video/quicktime", "audio/aiff", etc + char pretty_name[64]; // eg: "QuickTime File Format" + char short_name[32]; // eg: "quicktime", "avi", "mpeg" + char file_extension[8]; // eg: "mov", "avi", "mpg" + char reserved[88]; +}; + + +// +// Use this function iterate through available file format writers +// +status_t get_next_file_format(int32 *cookie, media_file_format *mfi); + + + +/* This struct is guaranteed to be large enough for any message your service */ +/* thread will get for any media_node -- 16k is an upper-bound size limit. */ +/* In your thread, read_port() into this struct, and call HandleMessage() on it. */ +const size_t B_MEDIA_MESSAGE_SIZE = 16384; + +_IMPEXP_MEDIA extern const char * B_MEDIA_SERVER_SIGNATURE; + +class media_node; /* found in MediaNode.h */ +struct media_input; +struct media_output; +struct live_node_info; +struct dormant_node_info; +struct buffer_clone_info; + + +// If you for some reason need to get rid of the media_server (and friends) +// use these functions, rather than sending messages yourself. +// The callback will be called for various stages of the process, with 100 meaning completely done +// The callback should always return TRUE for the time being. +status_t shutdown_media_server(bigtime_t timeout = B_INFINITE_TIMEOUT, bool (*progress)(int stage, const char * message, void * cookie) = NULL, void * cookie = NULL); +status_t launch_media_server(uint32 flags = 0); + +// Given an image_id, prepare that image_id for realtime media +// If the kind of media indicated by "flags" is not enabled for real-time, +// B_MEDIA_REALTIME_DISABLED is returned. +// If there are not enough system resources to enable real-time performance, +// B_MEDIA_REALTIME_UNAVAILABLE is returned. +status_t media_realtime_init_image(image_id image, uint32 flags); + +// Given a thread ID, and an optional indication of what the thread is +// doing in "flags", prepare the thread for real-time media performance. +// Currently, this means locking the thread stack, up to size_used bytes, +// or all of it if 0 is passed. Typically, you will not be using all +// 256 kB of the stack, so you should pass some smaller value you determine +// from profiling the thread; typically in the 32-64kB range. +// Return values are the same as for media_prepare_realtime_image(). +status_t media_realtime_init_thread(thread_id thread, size_t stack_used, uint32 flags); + +// A teeny bit of legacy preserved for BSoundFile from R3. +// These came from the old MediaDefs.h; don't use them +// unless you get them from BSoundFile. + +/* values for byte_ordering */ +enum { B_BIG_ENDIAN, B_LITTLE_ENDIAN }; + +/* values for sample_format */ +enum { + B_UNDEFINED_SAMPLES, + B_LINEAR_SAMPLES, + B_FLOAT_SAMPLES, + B_MULAW_SAMPLES + }; + + +/* for encoders and file writers */ + +struct media_encode_info { + uint32 flags; /* B_MEDIA_KEY_FRAME, set before every use */ + int32 used_data_size; /* data size used by other tracks */ + /* add output size used by this encoder */ + bigtime_t start_time; /* us from start of file */ + bigtime_t time_to_encode; /* 0 - hurry up, B_INFINITE_TIMEOUT - don't care */ + int32 _pad[22]; + void *file_format_data; /* file format specific info */ + size_t file_format_data_size; + void *codec_data; /* codec specific info */ + size_t codec_data_size; + + media_encode_info(); +}; + +struct encode_parameters { + float quality; // 0.0-1.0 , 1.0 is high quality + int32 avg_field_size; // in bytes + int32 max_field_size; // in bytes + int32 _pad[27]; + void *user_data; // codec specific info + size_t user_data_size; +}; + +struct media_decode_info { + bigtime_t time_to_decode; /* 0 - hurry up, B_INFINITE_TIMEOUT - don't care */ + int32 _pad[26]; + void *file_format_data; /* file format specific info */ + size_t file_format_data_size; + void *codec_data; /* codec specific info */ + size_t codec_data_size; + + media_decode_info(); +}; + + +#endif // __cplusplus + +#endif /* MEDIA_DEFS_H */ diff --git a/headers/os/media/MediaEncoder.h b/headers/os/media/MediaEncoder.h new file mode 100644 index 0000000000..e3b974f9f6 --- /dev/null +++ b/headers/os/media/MediaEncoder.h @@ -0,0 +1,91 @@ +#ifndef MEDIAENCODER_H +#define MEDIAENCODER_H + +#include +#include + +namespace BPrivate { + class Encoder; + class _AddonManager; +} + +class BMediaEncoder { + public: + BMediaEncoder(); + BMediaEncoder(const media_format *output_format); + BMediaEncoder(const media_codec_info *mci); + virtual ~BMediaEncoder(); + status_t InitCheck() const; + + status_t SetTo(const media_format *output_format); + status_t SetTo(const media_codec_info *mci); + status_t SetFormat(media_format *input_format, + media_format *output_format, + media_file_format *mfi = NULL); + status_t Encode(const void *buffer, int64 frame_count, + media_encode_info *info); + status_t GetEncodeParameters(encode_parameters *parameters) const; + status_t SetEncodeParameters(encode_parameters *parameters); + protected: + virtual status_t WriteChunk(const void *chunk_data, size_t chunk_len, + media_encode_info *info) = 0; + virtual status_t AddTrackInfo(uint32 code, const char *data, size_t size); + + private: + // unimplemented + BMediaEncoder(const BMediaEncoder &); + BMediaEncoder & operator=(const BMediaEncoder &); + + static status_t write_chunk(void *classptr, const void *chunk_data, + size_t chunk_len, media_encode_info *info); + void Init(); + void ReleaseEncoder(); + + BPrivate::_AddonManager *fEncoderMgr; + BPrivate::Encoder *fEncoder; + int32 fEncoderID; + bool fFormatValid; + bool fEncoderStarted; + status_t fInitStatus; + + /* fbc data and virtuals */ + + uint32 _reserved_BMediaEncoder_[32]; + + virtual status_t _Reserved_BMediaEncoder_0(int32 arg, ...); + virtual status_t _Reserved_BMediaEncoder_1(int32 arg, ...); + virtual status_t _Reserved_BMediaEncoder_2(int32 arg, ...); + virtual status_t _Reserved_BMediaEncoder_3(int32 arg, ...); + virtual status_t _Reserved_BMediaEncoder_4(int32 arg, ...); + virtual status_t _Reserved_BMediaEncoder_5(int32 arg, ...); + virtual status_t _Reserved_BMediaEncoder_6(int32 arg, ...); + virtual status_t _Reserved_BMediaEncoder_7(int32 arg, ...); + virtual status_t _Reserved_BMediaEncoder_8(int32 arg, ...); + virtual status_t _Reserved_BMediaEncoder_9(int32 arg, ...); + virtual status_t _Reserved_BMediaEncoder_10(int32 arg, ...); + virtual status_t _Reserved_BMediaEncoder_11(int32 arg, ...); + virtual status_t _Reserved_BMediaEncoder_12(int32 arg, ...); + virtual status_t _Reserved_BMediaEncoder_13(int32 arg, ...); + virtual status_t _Reserved_BMediaEncoder_14(int32 arg, ...); + virtual status_t _Reserved_BMediaEncoder_15(int32 arg, ...); +}; + +class BMediaBufferEncoder: public BMediaEncoder { + public: + BMediaBufferEncoder(); + BMediaBufferEncoder(const media_format *output_format); + BMediaBufferEncoder(const media_codec_info *mci); + status_t EncodeToBuffer(void *output_buffer, size_t *output_size, + const void *input_buffer, int64 frame_count, + media_encode_info *info); + protected: + virtual status_t WriteChunk(const void *chunk_data, size_t chunk_len, + media_encode_info *info); + + void *fBuffer; + int32 fBufferSize; +}; + + +#endif + diff --git a/headers/os/media/MediaEventLooper.h b/headers/os/media/MediaEventLooper.h new file mode 100644 index 0000000000..db3d7c9d3d --- /dev/null +++ b/headers/os/media/MediaEventLooper.h @@ -0,0 +1,169 @@ +/******************************************************************************* +/ +/ File: MediaEventLooper.h +/ +/ Description: BMediaEventLooper spawns a thread which calls WaitForMessage, +/ pushes BMediaNode messages onto its BTimedEventQueues. +/ informs you when it is time to handle an event. +/ Report your event latency, push other events onto the queue +/ and override HandleEvent to do your work. +/ +/ Copyright 1999, Be Incorporated, All Rights Reserved +/ +*******************************************************************************/ + +#if !defined(_MEDIA_EVENT_LOOPER_H) +#define _MEDIA_EVENT_LOOPER_H + +#include +#include + +class BMediaEventLooper : + public virtual BMediaNode +{ + protected: + enum run_state { + B_IN_DISTRESS = -1, + B_UNREGISTERED, + B_STOPPED, + B_STARTED, + B_QUITTING, + B_TERMINATED, + B_USER_RUN_STATES = 0x4000 + }; + + protected: + /* this has to be on top rather than bottom to force a vtable in mwcc */ + virtual ~BMediaEventLooper(); + explicit BMediaEventLooper(uint32 apiVersion = B_BEOS_VERSION); + + /* from BMediaNode */ + protected: + virtual void NodeRegistered(); + virtual void Start(bigtime_t performance_time); + virtual void Stop(bigtime_t performance_time, bool immediate); + virtual void Seek(bigtime_t media_time, bigtime_t performance_time); + virtual void TimeWarp(bigtime_t at_real_time, bigtime_t to_performance_time); + virtual status_t AddTimer(bigtime_t at_performance_time, int32 cookie); + virtual void SetRunMode(run_mode mode); + + /* BMediaEventLooper Hook functions */ + protected: + /* you must override to handle your events! */ + /* you should not call HandleEvent directly */ + virtual void HandleEvent( const media_timed_event *event, + bigtime_t lateness, + bool realTimeEvent = false) = 0; + + /* override to clean up custom events you have added to your queue */ + virtual void CleanUpEvent(const media_timed_event *event); + + /* called from Offline mode to determine the current time of the node */ + /* update your internal information whenever it changes */ + virtual bigtime_t OfflineTime(); + + /* override only if you know what you are doing! */ + /* otherwise much badness could occur */ + /* the actual control loop function: */ + /* waits for messages, Pops events off the queue and calls DispatchEvent */ + virtual void ControlLoop(); + + thread_id ControlThread(); + + protected: + BTimedEventQueue * EventQueue(); + BTimedEventQueue * RealTimeQueue(); + + int32 Priority() const; + int32 RunState() const; + bigtime_t EventLatency() const; + bigtime_t BufferDuration() const; + bigtime_t SchedulingLatency() const; + + /* use the priority constants from OS.h */ + /* or suggest_thread_priority from scheduler.h */ + /* will clamp priorities to be inbetween 5 and 120 */ + status_t SetPriority(int32 priority); + + /* set the run state */ + void SetRunState(run_state state); + + /* clamps to 0 if latency < 0 */ + void SetEventLatency(bigtime_t latency); + + /* clamps to 0 if duration is < 0 */ + void SetBufferDuration(bigtime_t duration); + + /* set the offline time returned in OfflineTime */ + void SetOfflineTime(bigtime_t offTime); + + /* spawn and resume the thread - must be called from NodeRegistered */ + void Run(); + + /* close down the thread - must be called from your destructor */ + void Quit(); + + /* calls HandleEvent and does BMediaEventLooper event work */ + void DispatchEvent( const media_timed_event *event, + bigtime_t lateness, + bool realTimeEvent = false); + + private: + static int32 _ControlThreadStart(void *arg); + static void _CleanUpEntry(const media_timed_event *event, void *context); + void _DispatchCleanUp(const media_timed_event *event); + + BTimedEventQueue fEventQueue; + BTimedEventQueue fRealTimeQueue; + thread_id fControlThread; + int32 fCurrentPriority; + int32 fSetPriority; + volatile int32 fRunState; + bigtime_t fEventLatency; + bigtime_t fSchedulingLatency; + bigtime_t fBufferDuration; + bigtime_t fOfflineTime; + uint32 fApiVersion; + + private: + /* unimplemented for your protection */ + BMediaEventLooper(const BMediaEventLooper&); + BMediaEventLooper& operator=(const BMediaEventLooper&); + + protected: + virtual status_t DeleteHook(BMediaNode * node); + + /* fragile base class stuffing */ + private: + /* it must be thanksgiving!! lots of stuffing! */ + virtual status_t _Reserved_BMediaEventLooper_0(int32 arg, ...); + virtual status_t _Reserved_BMediaEventLooper_1(int32 arg, ...); + virtual status_t _Reserved_BMediaEventLooper_2(int32 arg, ...); + virtual status_t _Reserved_BMediaEventLooper_3(int32 arg, ...); + virtual status_t _Reserved_BMediaEventLooper_4(int32 arg, ...); + virtual status_t _Reserved_BMediaEventLooper_5(int32 arg, ...); + virtual status_t _Reserved_BMediaEventLooper_6(int32 arg, ...); + virtual status_t _Reserved_BMediaEventLooper_7(int32 arg, ...); + virtual status_t _Reserved_BMediaEventLooper_8(int32 arg, ...); + virtual status_t _Reserved_BMediaEventLooper_9(int32 arg, ...); + virtual status_t _Reserved_BMediaEventLooper_10(int32 arg, ...); + virtual status_t _Reserved_BMediaEventLooper_11(int32 arg, ...); + virtual status_t _Reserved_BMediaEventLooper_12(int32 arg, ...); + virtual status_t _Reserved_BMediaEventLooper_13(int32 arg, ...); + virtual status_t _Reserved_BMediaEventLooper_14(int32 arg, ...); + virtual status_t _Reserved_BMediaEventLooper_15(int32 arg, ...); + virtual status_t _Reserved_BMediaEventLooper_16(int32 arg, ...); + virtual status_t _Reserved_BMediaEventLooper_17(int32 arg, ...); + virtual status_t _Reserved_BMediaEventLooper_18(int32 arg, ...); + virtual status_t _Reserved_BMediaEventLooper_19(int32 arg, ...); + virtual status_t _Reserved_BMediaEventLooper_20(int32 arg, ...); + virtual status_t _Reserved_BMediaEventLooper_21(int32 arg, ...); + virtual status_t _Reserved_BMediaEventLooper_22(int32 arg, ...); + virtual status_t _Reserved_BMediaEventLooper_23(int32 arg, ...); + + /* turkey for weeks! */ + bool _reserved_bool_[4]; + uint32 _reserved_BMediaEventLooper_[12]; +}; + +#endif diff --git a/headers/os/media/MediaFile.h b/headers/os/media/MediaFile.h new file mode 100644 index 0000000000..c7e641f7e2 --- /dev/null +++ b/headers/os/media/MediaFile.h @@ -0,0 +1,207 @@ +#ifndef _MEDIA_FILE_H +#define _MEDIA_FILE_H + +#include +#include +#include +#include +#include +#include + + +namespace BPrivate { + class MediaExtractor; + class _IMPEXP_MEDIA MediaWriter; + class _AddonManager; +} + + +// forward declarations +class BMediaTrack; +class BParameterWeb; +class BView; + + +// flags for the BMediaFile constructor +enum { + B_MEDIA_FILE_REPLACE_MODE = 0x00000001, + B_MEDIA_FILE_NO_READ_AHEAD = 0x00000002, + B_MEDIA_FILE_UNBUFFERED = 0x00000006, + B_MEDIA_FILE_BIG_BUFFERS = 0x00000008 +}; + +// BMediaFile represents a media file (AVI, Quicktime, MPEG, AIFF, WAV, etc) +// +// To read a file you construct a BMediaFile with an entry_ref, get the +// BMediaTracks out of it and use those to read the data. +// +// To write a file you construct a BMediaFile with an entry ref and an id as +// returned by get_next_file_format(). You then CreateTrack() to create +// various audio & video tracks. Once you're done creating tracks, call +// CommitHeader(), then write data to each track and call CloseFile() when +// you're done. +// + +class BMediaFile { + +public: + // these four constructors are used for read-only access + BMediaFile( const entry_ref *ref); + BMediaFile( BDataIO * source); // BFile is a BDataIO + BMediaFile( const entry_ref * ref, + int32 flags); + BMediaFile( BDataIO * source, + int32 flags); // BFile is a BDataIO + + // these two constructors are for read-write access + BMediaFile(const entry_ref *ref, // these two are write-only + const media_file_format * mfi, + int32 flags=0); + BMediaFile(BDataIO *destination, // BFile is a BDataIO + const media_file_format * mfi, + int32 flags=0); + +/* modified by Marcus Overhagen */ +BMediaFile(const media_file_format * mfi, + int32 flags); +/* modified by Marcus Overhagen */ + + + virtual ~BMediaFile(); + + status_t InitCheck() const; + + // Get info about the underlying file format. + status_t GetFileFormatInfo(media_file_format *mfi) const; + + // + // These functions are for read-only access to a media file. + // The data is read using the BMediaTrack object. + // + const char *Copyright(void) const; + int32 CountTracks() const; + + // Can be called multiple times with the same index. You must call + // ReleaseTrack() when you're done with a track. + BMediaTrack *TrackAt(int32 index); + + // Release the resource used by a given BMediaTrack object, to reduce + // the memory usage of your application. The specific 'track' object + // can no longer be used, but you can create another one by calling + // TrackAt() with the same track index. + status_t ReleaseTrack(BMediaTrack *track); + + // A convenience. + status_t ReleaseAllTracks(void); + + + // Create and add a track to the media file + BMediaTrack *CreateTrack(media_format *mf, const media_codec_info *mci); + // Create and add a raw track to the media file (it has no encoder) + BMediaTrack *CreateTrack(media_format *mf); + + // Lets you set the copyright info for the entire file + status_t AddCopyright(const char *data); + + // Call this to add user-defined chunks to a file (if they're supported) + status_t AddChunk(int32 type, const void *data, size_t size); + + // After you have added all the tracks you want, call this + status_t CommitHeader(void); + + // After you have written all the data to the track objects, call this + status_t CloseFile(void); + + // This is for controlling file format parameters + BParameterWeb *Web(); + status_t GetParameterValue(int32 id, void *valu, size_t *size); + status_t SetParameterValue(int32 id, const void *valu, size_t size); + BView *GetParameterView(); + + + // For the future... + virtual status_t Perform(int32 selector, void * data); + +private: + BPrivate::MediaExtractor *fExtractor; + int32 _reserved_BMediaFile_was_fExtractorID; + int32 fTrackNum; + status_t fErr; + + BPrivate::_AddonManager *fEncoderMgr; + BPrivate::_AddonManager *fWriterMgr; + BPrivate::MediaWriter *fWriter; + int32 fWriterID; + media_file_format fMFI; + + bool fFileClosed; + bool _reserved_was_fUnused[3]; + BList *fTrackList; + + void Init(); + void InitReader(BDataIO *source, int32 flags = 0); + void InitWriter(BDataIO *source, const media_file_format * mfi, + int32 flags); + + BMediaFile(); + BMediaFile(const BMediaFile&); + BMediaFile& operator=(const BMediaFile&); + + BFile *fFile; + + + /* fbc data and virtuals */ + + uint32 _reserved_BMediaFile_[32]; + +virtual status_t _Reserved_BMediaFile_0(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_1(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_2(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_3(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_4(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_5(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_6(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_7(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_8(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_9(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_10(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_11(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_12(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_13(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_14(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_15(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_16(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_17(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_18(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_19(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_20(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_21(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_22(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_23(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_24(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_25(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_26(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_27(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_28(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_29(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_30(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_31(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_32(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_33(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_34(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_35(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_36(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_37(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_38(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_39(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_40(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_41(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_42(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_43(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_44(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_45(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_46(int32 arg, ...); +virtual status_t _Reserved_BMediaFile_47(int32 arg, ...); +}; + +#endif diff --git a/headers/os/media/MediaFiles.h b/headers/os/media/MediaFiles.h new file mode 100644 index 0000000000..45d47cff1c --- /dev/null +++ b/headers/os/media/MediaFiles.h @@ -0,0 +1,69 @@ +/* MediaFiles.h */ +/* Copyright 1998 Be Incorporated. All rights reserved. */ + +#if !defined(_MEDIA_FILES_H) +#define _MEDIA_FILES_H + +#include +#include + +struct entry_ref; + +#include + +class BMediaFiles { +public: + + BMediaFiles(); +virtual ~BMediaFiles(); + +virtual status_t RewindTypes(); +virtual status_t GetNextType( + BString * out_type); + +virtual status_t RewindRefs( + const char * type); +virtual status_t GetNextRef( + BString * out_type, + entry_ref * out_ref = NULL); + +virtual status_t GetRefFor( + const char * type, + const char * item, + entry_ref * out_ref); +virtual status_t SetRefFor( + const char * type, + const char * item, + const entry_ref & ref); +virtual status_t RemoveRefFor( // This might better be called "ClearRefFor" + const char * type, // but it's too late now... + const char * item, + const entry_ref & ref); + +static const char B_SOUNDS[]; /* for "types" */ + +virtual status_t RemoveItem( // new in 4.1, removes the whole item. + const char * type, + const char * item); + + +private: + + status_t _Reserved_MediaFiles_0(void *, ...); +virtual status_t _Reserved_MediaFiles_1(void *, ...); +virtual status_t _Reserved_MediaFiles_2(void *, ...); +virtual status_t _Reserved_MediaFiles_3(void *, ...); +virtual status_t _Reserved_MediaFiles_4(void *, ...); +virtual status_t _Reserved_MediaFiles_5(void *, ...); +virtual status_t _Reserved_MediaFiles_6(void *, ...); +virtual status_t _Reserved_MediaFiles_7(void *, ...); + + BList m_types; + int m_type_index; + BString m_cur_type; + BList m_items; + int m_item_index; +}; + +#endif /* _MEDIA_FILES_H */ + diff --git a/headers/os/media/MediaFormats.h b/headers/os/media/MediaFormats.h new file mode 100644 index 0000000000..56f4dc0c57 --- /dev/null +++ b/headers/os/media/MediaFormats.h @@ -0,0 +1,249 @@ +/* MediaFormats.h */ +/* Copyright 1998 Be Incorporated. All rights reserved. */ + +#if !defined(_MEDIA_TYPES_H) +#define _MEDIA_TYPES_H + +#if defined(__cplusplus) +#include + +#include +#include +#include +#endif + + +struct media_codec_info { + char pretty_name[96]; // eg: "SuperSqueeze Encoder by Foo Inc" + char short_name[32]; // eg: "supersqueeze" + + int32 id; // opaque id passed to BMediaFile::CreateTrack + int32 sub_id; + + int32 pad[63]; +}; + +// +// Use this to iterate through the available encoders for a file format. +// +status_t get_next_encoder(int32 *cookie, + const media_file_format *mfi, // this comes from get_next_file_format() + const media_format *input_format, // this is the type of data given to the encoder + media_format *output_format, // this is the type of data encoder will output + media_codec_info *ei); // information about the encoder + +status_t get_next_encoder( + int32 *cookie, + const media_file_format *mfi, // this comes from get_next_file_format() + // pass NULL if you don't care + const media_format *input_format, // this is the type of data given to the + // encoder, wildcards are accepted + const media_format *output_format, // this is the type of data encoder + // you want the encoder to output. + // Wildcards are accepted + media_codec_info *ei, // information about the encoder + media_format *accepted_input_format,// this is the type of data that the + // encoder will accept as input. + // Wildcards in input_format will be + // specialized here. + media_format *accepted_output_format// this is the type of data that the + // encoder will output. + // Wildcards in output_format will be + // specialized here. + ); + + +status_t get_next_encoder(int32 *cookie, media_codec_info *ei); + +enum media_file_accept_format_flags { + B_MEDIA_REJECT_WILDCARDS = 0x1 +}; + +bool does_file_accept_format(const media_file_format *mfi, + media_format *format, uint32 flags = 0); + +typedef struct { + uint8 data[16]; +} GUID; + +typedef struct { + int32 format; +} media_beos_description; + +typedef struct { + uint32 codec; + uint32 vendor; +} media_quicktime_description; + +typedef struct { + uint32 codec; +} media_avi_description; + +typedef struct { + uint32 id; +} media_avr_description; + +typedef struct { + GUID guid; +} media_asf_description; + +enum mpeg_id { + B_MPEG_ANY = 0, + B_MPEG_1_AUDIO_LAYER_1 = 0x101, + B_MPEG_1_AUDIO_LAYER_2 = 0x102, + B_MPEG_1_AUDIO_LAYER_3 = 0x103, // "MP3" + B_MPEG_1_VIDEO = 0x111 +}; +typedef struct { + uint32 id; +} media_mpeg_description; + +typedef struct { + uint32 codec; +} media_wav_description; + +typedef struct { + uint32 codec; +} media_aiff_description; + +typedef struct { + uint32 file_format; + uint32 codec; +} media_misc_description; + +typedef struct _media_format_description { +#if defined(__cplusplus) + _media_format_description(); + ~_media_format_description(); + _media_format_description(const _media_format_description & other); + _media_format_description & operator=(const _media_format_description & other); +#endif + media_format_family family; + uint32 _reserved_[3]; + union { + media_beos_description beos; + media_quicktime_description quicktime; + media_avi_description avi; + media_asf_description asf; + media_mpeg_description mpeg; + media_wav_description wav; + media_aiff_description aiff; + media_misc_description misc; + media_avr_description avr; + uint32 _reserved_[12]; + } u; +} media_format_description; + + +#if defined(__cplusplus) + +namespace BPrivate { + class addon_list; + void dec_load_hook(void *arg, image_id imgid); + void extractor_load_hook(void *arg, image_id imgid); + class Extractor; +} + +class BMediaFormats { +public: + BMediaFormats(); +virtual ~BMediaFormats(); + + status_t InitCheck(); + + // Make sure you memset() your descs to 0 before you start filling + // them in! Else you may register some bogus value. + enum make_format_flags { + B_EXCLUSIVE = 0x1, // Fail if this format has already been registered + B_NO_MERGE = 0x2, // Don't re-number any formats if there are multiple + // clashing previous registrations, but fail instead + B_SET_DEFAULT = 0x4 // Set the first format to be the default for the + // format family (when registering more than one in + // the same family). Only use in Encoder add-ons. + }; + status_t MakeFormatFor( + const media_format_description * descs, + int32 desc_count, + media_format * io_format, + uint32 flags = 0, + void * _reserved = 0); + status_t GetFormatFor( + const media_format_description & desc, + media_format * out_format); + + // convenience functions + static status_t GetBeOSFormatFor( + uint32 fourcc, media_format * out_format, + media_type type = B_MEDIA_UNKNOWN_TYPE); + static status_t GetAVIFormatFor( + uint32 fourcc, media_format * out_format, + media_type type = B_MEDIA_UNKNOWN_TYPE); + static status_t GetQuicktimeFormatFor( + uint32 vendor, uint32 fourcc, media_format * out_format, + media_type type = B_MEDIA_UNKNOWN_TYPE); + + status_t GetCodeFor( + const media_format & format, + media_format_family family, + media_format_description * out_description); + + status_t RewindFormats(); + status_t GetNextFormat( + media_format * out_format, + media_format_description * out_description); + // You need to lock/unlock (only) when using RewindFormats()/GetNextFormat() + bool Lock(); + void Unlock(); + + /* --- begin deprecated API --- */ + status_t MakeFormatFor( + const media_format_description & desc, + const media_format & in_format, + media_format * out_format); +private: + friend class BPrivate::addon_list; + friend void BPrivate::dec_load_hook(void *arg, image_id imgid); + friend void BPrivate::extractor_load_hook(void * arg, image_id imgid); + friend class BMediaDecoder; + friend class BMediaTrack; + friend class BPrivate::Extractor; + + char _reserved_messenger[24]; // sizeof(BMessenger) 24 + char _reserved_list[28]; // sizeof(BList) 28 + char _reserved_locker[32]; // sizeof(BLocker) 36 + int32 m_lock_count; +static int32 s_cleared; +static BMessenger s_server; +static BList s_formats; +static BLocker s_lock; + int32 m_index; + + void clear_formats(); +static void ex_clear_formats_imp(); +static void clear_formats_imp(); + status_t get_formats(); +static status_t get_formats_imp(); +static BMessenger & get_server(); + +static status_t bind_addon( + const char * addon, + const media_format * formats, + int32 count); +static bool is_bound( + const char * addon, + const media_format * formats, + int32 count); +static status_t find_addons( + const media_format * format, + BPrivate::addon_list & addons); +}; + +_IMPEXP_MEDIA bool operator==(const media_format_description & a, const media_format_description & b); +_IMPEXP_MEDIA bool operator<(const media_format_description & a, const media_format_description & b); + +_IMPEXP_MEDIA bool operator==(const GUID & a, const GUID & b); +_IMPEXP_MEDIA bool operator<(const GUID & a, const GUID & b); +#endif + +#endif /* _MEDIA_TYPES_H */ + diff --git a/headers/os/media/MediaNode.h b/headers/os/media/MediaNode.h new file mode 100644 index 0000000000..f0da72d3c6 --- /dev/null +++ b/headers/os/media/MediaNode.h @@ -0,0 +1,340 @@ +/******************************************************************************* +/ +/ File: MediaNode.h +/ +/ Description: BMediaNode is the indirect base class for all Media Kit participants. +/ However, you should use the more specific BBufferConsumer, BBufferProducer +/ and others rather than BMediaNode directly. It's OK to multiply inherit. +/ +/ Copyright 1997-98, Be Incorporated, All Rights Reserved +/ +*******************************************************************************/ + + +#if !defined(_MEDIA_NODE_H) +#define _MEDIA_NODE_H + +#include +#include + +#include + +class BMediaAddOn; + + + +class media_node { + +public: + + media_node(); + ~media_node(); + + media_node_id node; + port_id port; + uint32 kind; + +static media_node null; + +private: + uint32 _reserved_[3]; +}; + + +struct media_input { + media_input(); + ~media_input(); + media_node node; + media_source source; + media_destination destination; + media_format format; + char name[B_MEDIA_NAME_LENGTH]; +private: + uint32 _reserved_media_input_[4]; +}; + +struct media_output { + media_output(); + ~media_output(); + media_node node; + media_source source; + media_destination destination; + media_format format; + char name[B_MEDIA_NAME_LENGTH]; +private: + uint32 _reserved_media_output_[4]; +}; + +struct live_node_info { + live_node_info(); + ~live_node_info(); + media_node node; + BPoint hint_point; + char name[B_MEDIA_NAME_LENGTH]; +private: + char reserved[160]; +}; + + +struct media_request_info +{ + enum what_code + { + B_SET_VIDEO_CLIPPING_FOR = 1, + B_REQUEST_FORMAT_CHANGE, + B_SET_OUTPUT_ENABLED, + B_SET_OUTPUT_BUFFERS_FOR, + + B_FORMAT_CHANGED = 4097 + }; + what_code what; + int32 change_tag; + status_t status; + int32 cookie; + void * user_data; + media_source source; + media_destination destination; + media_format format; + uint32 _reserved_[32]; +}; + +struct media_node_attribute +{ + enum { + B_R40_COMPILED = 1, // has this attribute if compiled using R4.0 headers + B_USER_ATTRIBUTE_NAME = 0x1000000, + B_FIRST_USER_ATTRIBUTE + }; + uint32 what; + uint32 flags; // per attribute + int64 data; // per attribute +}; + + +class BMediaNode +{ +protected: + /* this has to be on top rather than bottom to force a vtable in mwcc */ +virtual ~BMediaNode(); /* should be called through Release() */ +public: + + enum run_mode { + B_OFFLINE = 1, /* data accurate, no realtime constraint */ + B_DECREASE_PRECISION, /* when slipping, try to catch up */ + B_INCREASE_LATENCY, /* when slipping, increase playout delay */ + B_DROP_DATA, /* when slipping, skip data */ + B_RECORDING /* you're on the receiving end of recording; buffers are guaranteed to be late */ + }; + + + BMediaNode * Acquire(); /* return itself */ + BMediaNode * Release(); /* release will decrement refcount, and delete if 0 */ + + const char * Name() const; + media_node_id ID() const; + uint64 Kinds() const; + media_node Node() const; + run_mode RunMode() const; + BTimeSource * TimeSource() const; + + /* this port is what a media node listens to for commands */ +virtual port_id ControlPort() const; + +virtual BMediaAddOn* AddOn( + int32 * internal_id) const = 0; /* Who instantiated you -- or NULL for app class */ + + /* These will be sent to anyone watching the MediaRoster. */ + /* The message field "be:node_id" will contain the node ID. */ + enum node_error { + /* Note that these belong with the notifications in MediaDefs.h! */ + /* They are here to provide compiler type checking in ReportError(). */ + B_NODE_FAILED_START = 'TRI0', + B_NODE_FAILED_STOP, // TRI1 + B_NODE_FAILED_SEEK, // TRI2 + B_NODE_FAILED_SET_RUN_MODE, // TRI3 + B_NODE_FAILED_TIME_WARP, // TRI4 + B_NODE_FAILED_PREROLL, // TRI5 + B_NODE_FAILED_SET_TIME_SOURCE_FOR, // TRI6 + /* display this node with a blinking exclamation mark or something */ + B_NODE_IN_DISTRESS // TRI7 + /* TRIA and up are used in MediaDefs.h */ + }; + +protected: + + /* Send one of the above codes to anybody who's watching. */ + status_t ReportError( + node_error what, + const BMessage * info = NULL); /* String "message" for instance */ + + /* When you've handled a stop request, call this function. If anyone is */ + /* listening for stop information from you, they will be notified. Especially */ + /* important for offline capable Nodes. */ + status_t NodeStopped( + bigtime_t whenPerformance); // performance time + void TimerExpired( + bigtime_t notifyPoint, // performance time + int32 cookie, + status_t error = B_OK); + +explicit BMediaNode( /* constructor sets refcount to 1 */ + const char * name); + + status_t WaitForMessage( + bigtime_t waitUntil, + uint32 flags = 0, + void * _reserved_ = 0); + + /* These don't return errors; instead, they use the global error condition reporter. */ + /* A node is required to have a queue of at least one pending command (plus TimeWarp) */ + /* and is recommended to allow for at least one pending command of each type. */ + /* Allowing an arbitrary number of outstanding commands might be nice, but apps */ + /* cannot depend on that happening. */ +virtual void Start( + bigtime_t performance_time); +virtual void Stop( + bigtime_t performance_time, + bool immediate); +virtual void Seek( + bigtime_t media_time, + bigtime_t performance_time); +virtual void SetRunMode( + run_mode mode); +virtual void TimeWarp( + bigtime_t at_real_time, + bigtime_t to_performance_time); +virtual void Preroll(); +virtual void SetTimeSource( + BTimeSource * time_source); + +public: + +virtual status_t HandleMessage( + int32 message, + const void * data, + size_t size); + void HandleBadMessage( /* call this with messages you and your superclasses don't recognize */ + int32 code, + const void * buffer, + size_t size); + + /* Called from derived system classes; you don't need to */ + void AddNodeKind( + uint64 kind); + + // These were not in 4.0. + // We added them in 4.1 for future use. They just call + // the default global versions for now. + void * operator new( + size_t size); + void * operator new( + size_t size, + const nothrow_t &) throw(); + void operator delete( + void * ptr); +#if !__MWERKS__ + // there's a bug in MWCC under R4.1 and earlier + void operator delete( + void * ptr, + const nothrow_t &) throw(); +#endif + +protected: + + /* Called when requests have completed, or failed. */ +virtual status_t RequestCompleted( /* reserved 0 */ + const media_request_info & info); + +private: + friend class BTimeSource; + friend class _BTimeSourceP; + friend class BMediaRoster; + friend class _BMediaRosterP; + friend class MNodeManager; + friend class BBufferProducer; // for getting _mNodeID + + // Deprecated in 4.1 + int32 IncrementChangeTag(); + int32 ChangeTag(); + int32 MintChangeTag(); + status_t ApplyChangeTag( + int32 previously_reserved); + + /* Mmmh, stuffing! */ +protected: + +virtual status_t DeleteHook(BMediaNode * node); /* reserved 1 */ + +virtual void NodeRegistered(); /* reserved 2 */ + +public: + + /* fill out your attributes in the provided array, returning however many you have. */ +virtual status_t GetNodeAttributes( /* reserved 3 */ + media_node_attribute * outAttributes, + size_t inMaxCount); + +virtual status_t AddTimer( + bigtime_t at_performance_time, + int32 cookie); + +private: + + status_t _Reserved_MediaNode_0(void *); /* DeleteHook() */ + status_t _Reserved_MediaNode_1(void *); /* RequestCompletionHook() */ + status_t _Reserved_MediaNode_2(void *); /* NodeRegistered() */ + status_t _Reserved_MediaNode_3(void *); /* GetNodeAttributes() */ + status_t _Reserved_MediaNode_4(void *); /* AddTimer() */ +virtual status_t _Reserved_MediaNode_5(void *); +virtual status_t _Reserved_MediaNode_6(void *); +virtual status_t _Reserved_MediaNode_7(void *); +virtual status_t _Reserved_MediaNode_8(void *); +virtual status_t _Reserved_MediaNode_9(void *); +virtual status_t _Reserved_MediaNode_10(void *); +virtual status_t _Reserved_MediaNode_11(void *); +virtual status_t _Reserved_MediaNode_12(void *); +virtual status_t _Reserved_MediaNode_13(void *); +virtual status_t _Reserved_MediaNode_14(void *); +virtual status_t _Reserved_MediaNode_15(void *); + + BMediaNode(); /* private unimplemented */ + BMediaNode( + const BMediaNode & clone); + BMediaNode & operator=( + const BMediaNode & clone); + + BMediaNode( /* constructor sets refcount to 1 */ + const char * name, + media_node_id id, + uint32 kinds); + + media_node_id fNodeID; + BTimeSource * fTimeSource; + int32 fRefCount; + char fName[B_MEDIA_NAME_LENGTH]; + run_mode fRunMode; + int32 _mChangeCount; // deprecated + int32 _mChangeCountReserved; // deprecated + uint64 fKinds; + media_node_id fTimeSourceID; + bool _mReservedBool[4]; + +mutable port_id fControlPort; + + uint32 _reserved_media_node_[13]; + + + +protected: + +static int32 NewChangeTag(); // for use by BBufferConsumer, mostly + +private: + // dont' rename this one, it's static and needed for binary compatibility +static int32 _m_changeTag; // not to be confused with _mChangeCount +}; + + + +#endif /* _MEDIA_NODE_H */ + diff --git a/headers/os/media/MediaRoster.h b/headers/os/media/MediaRoster.h new file mode 100644 index 0000000000..d88932538d --- /dev/null +++ b/headers/os/media/MediaRoster.h @@ -0,0 +1,428 @@ +/******************************************************************************* +/ +/ File: MediaRoster.h +/ +/ Description: The BMediaRoster is the main application interface to the Media Kit +/ +/ Copyright 1997-98, Be Incorporated, All Rights Reserved +/ +*******************************************************************************/ + +#if !defined(_MEDIA_ROSTER_H) +#define _MEDIA_ROSTER_H + +#include +#include +#include +#include + +class BMimeType; +struct dormant_flavor_info; +class BMediaAddOn; + +class BMediaRoster : public BLooper +{ +public: + + status_t GetVideoInput( + media_node * out_node); + status_t GetAudioInput( + media_node * out_node); + status_t GetVideoOutput( + media_node * out_node); + status_t GetAudioMixer( + media_node * out_node); + status_t GetAudioOutput( + media_node * out_node); /* Use the mixer rather than the output for most needs! */ + status_t GetAudioOutput( + media_node * out_node, + int32 * out_input_id, + BString * out_input_name); + status_t GetTimeSource( + media_node * out_node); + + status_t SetVideoInput( + const media_node & producer); + status_t SetVideoInput( + const dormant_node_info & producer); + status_t SetAudioInput( + const media_node & producer); + status_t SetAudioInput( + const dormant_node_info & producer); + status_t SetVideoOutput( + const media_node & consumer); + status_t SetVideoOutput( + const dormant_node_info & consumer); + status_t SetAudioOutput( + const media_node & consumer); + status_t SetAudioOutput( + const media_input & input_to_output); + status_t SetAudioOutput( + const dormant_node_info & consumer); + + /* Get a media_node from a node ID -- this is how you reference your own nodes! */ + status_t GetNodeFor( + media_node_id node, + media_node * clone); + status_t GetSystemTimeSource( /* typically, you want to use GetTimeSource() */ + media_node * clone); + status_t ReleaseNode( /* might shut down Node if you're last */ + const media_node & node); + + BTimeSource * MakeTimeSourceFor( /* Release() the object when done */ + const media_node & for_node); + + /* note that the media_source and media_destination found in */ + /* out_output and out_input are the ones actually used; from and to */ + /* are only "hints" that the app should not use once a real connection */ + /* has been established */ + status_t Connect( + const media_source & from, + const media_destination & to, + media_format * io_format, + media_output * out_output, + media_input * out_input); + enum connect_flags { + B_CONNECT_MUTED = 0x1 + }; + status_t Connect( + const media_source & from, + const media_destination & to, + media_format * io_format, + media_output * out_output, + media_input * out_input, + uint32 in_flags, + void * _reserved = 0); + status_t Disconnect( + media_node_id source_node, + const media_source & source, + media_node_id destination_node, + const media_destination & destination); + + status_t StartNode( + const media_node & node, + bigtime_t at_performance_time); + status_t StopNode( + const media_node & node, + bigtime_t at_performance_time, + bool immediate = false); /* immediate -> at_time is insignificant */ + status_t SeekNode( + const media_node & node, + bigtime_t to_media_time, + bigtime_t at_performance_time = 0 /* if running */ ); + + status_t StartTimeSource( + const media_node & node, + bigtime_t at_real_time); + status_t StopTimeSource( + const media_node & node, + bigtime_t at_real_time, + bool immediate = false); + status_t SeekTimeSource( + const media_node & node, + bigtime_t to_performance_time, + bigtime_t at_real_time); + + status_t SyncToNode( + const media_node & node, + bigtime_t at_time, + bigtime_t timeout = B_INFINITE_TIMEOUT); + status_t SetRunModeNode( + const media_node & node, + BMediaNode::run_mode mode); + status_t PrerollNode( /* synchronous */ + const media_node & node); + + status_t RollNode( + const media_node & node, + bigtime_t startPerformance, + bigtime_t stopPerformance, + bigtime_t atMediaTime = -B_INFINITE_TIMEOUT); + + status_t SetProducerRunModeDelay( /* should only be used with B_RECORDING */ + const media_node & node, + bigtime_t delay, + BMediaNode::run_mode mode = BMediaNode::B_RECORDING); + status_t SetProducerRate( /* not necessarily supported by node */ + const media_node & producer, + int32 numer, + int32 denom); + + /* Nodes will have available inputs/outputs as long as they are capable */ + /* of accepting more connections. The node may create an additional */ + /* output or input as the currently available is taken into usage. */ + status_t GetLiveNodeInfo( + const media_node & node, + live_node_info * out_live_info); + status_t GetLiveNodes( + live_node_info * out_live_nodes, + int32 * io_total_count, + const media_format * has_input = NULL, + const media_format * has_output = NULL, + const char * name = NULL, + uint64 node_kinds = 0); /* B_BUFFER_PRODUCER etc */ + + status_t GetFreeInputsFor( + const media_node & node, + media_input * out_free_inputs, + int32 buf_num_inputs, + int32 * out_total_count, + media_type filter_type = B_MEDIA_UNKNOWN_TYPE); + status_t GetConnectedInputsFor( + const media_node & node, + media_input * out_active_inputs, + int32 buf_num_inputs, + int32 * out_total_count); + status_t GetAllInputsFor( + const media_node & node, + media_input * out_inputs, + int32 buf_num_inputs, + int32 * out_total_count); + status_t GetFreeOutputsFor( + const media_node & node, + media_output * out_free_outputs, + int32 buf_num_outputs, + int32 * out_total_count, + media_type filter_type = B_MEDIA_UNKNOWN_TYPE); + status_t GetConnectedOutputsFor( + const media_node & node, + media_output * out_active_outputs, + int32 buf_num_outputs, + int32 * out_total_count); + status_t GetAllOutputsFor( + const media_node & node, + media_output * out_outputs, + int32 buf_num_outputs, + int32 * out_total_count); + + status_t StartWatching( + const BMessenger & where); + status_t StartWatching( + const BMessenger & where, + int32 notificationType); + status_t StartWatching( + const BMessenger & where, + const media_node & node, + int32 notificationType); + status_t StopWatching( + const BMessenger & where); + status_t StopWatching( + const BMessenger & where, + int32 notificationType); + status_t StopWatching( + const BMessenger & where, + const media_node & node, + int32 notificationType); + + status_t RegisterNode( + BMediaNode * node); + status_t UnregisterNode( + BMediaNode * node); + +static BMediaRoster * Roster( // will create if there isn't one + status_t * out_error = NULL); // thread safe for multiple calls to Roster() +static BMediaRoster * CurrentRoster(); // won't create it if there isn't one + // not thread safe if you call Roster() at the same time + status_t SetTimeSourceFor( + media_node_id node, + media_node_id time_source); + + status_t GetParameterWebFor( + const media_node & node, + BParameterWeb ** out_web); + status_t StartControlPanel( + const media_node & node, + BMessenger * out_messenger = NULL); + + status_t GetDormantNodes( + dormant_node_info * out_info, + int32 * io_count, + const media_format * has_input = NULL, + const media_format * has_output = NULL, + const char * name = NULL, + uint64 require_kinds = 0, + uint64 deny_kinds = 0); + status_t InstantiateDormantNode( + const dormant_node_info & in_info, + media_node * out_node, + uint32 flags /* currently B_FLAVOR_IS_GLOBAL or B_FLAVOR_IS_LOCAL */ ); + status_t InstantiateDormantNode( + const dormant_node_info & in_info, + media_node * out_node); + status_t GetDormantNodeFor( + const media_node & node, + dormant_node_info * out_info); + status_t GetDormantFlavorInfoFor( + const dormant_node_info & in_dormant, + dormant_flavor_info * out_flavor); + + status_t GetLatencyFor( + const media_node & producer, + bigtime_t * out_latency); + status_t GetInitialLatencyFor( + const media_node & producer, + bigtime_t * out_latency, + uint32 * out_flags = 0); + status_t GetStartLatencyFor( + const media_node & time_source, + bigtime_t * out_latency); + + status_t GetFileFormatsFor( + const media_node & file_interface, + media_file_format * out_formats, + int32 * io_num_infos); + status_t SetRefFor( + const media_node & file_interface, + const entry_ref & file, + bool create_and_truncate, + bigtime_t * out_length); /* if create is false */ + status_t GetRefFor( + const media_node & node, + entry_ref * out_file, + BMimeType * mime_type = NULL); + status_t SniffRefFor( + const media_node & file_interface, + const entry_ref & file, + BMimeType * mime_type, + float * out_capability); + /* This is the generic "here's a file, now can someone please play it" interface */ + status_t SniffRef( + const entry_ref & file, + uint64 require_node_kinds, /* if you need an EntityInterface or BufferConsumer or something */ + dormant_node_info * out_node, + BMimeType * mime_type = NULL); + status_t GetDormantNodeForType( + const BMimeType & type, + uint64 require_node_kinds, + dormant_node_info * out_node); + status_t GetReadFileFormatsFor( + const dormant_node_info & in_node, + media_file_format * out_read_formats, + int32 in_read_count, + int32 * out_read_count); + status_t GetWriteFileFormatsFor( + const dormant_node_info & in_node, + media_file_format * out_write_formats, + int32 in_write_count, + int32 * out_write_count); + + status_t GetFormatFor( + const media_output & output, + media_format * io_format, + uint32 flags = 0); + status_t GetFormatFor( + const media_input & input, + media_format * io_format, + uint32 flags = 0); + status_t GetFormatFor( + const media_node & node, + media_format * io_format, + float quality = B_MEDIA_ANY_QUALITY); + ssize_t GetNodeAttributesFor( + const media_node & node, + media_node_attribute * outArray, + size_t inMaxCount); + media_node_id NodeIDFor( + port_id source_or_destination_port); + status_t GetInstancesFor( + media_addon_id addon, + int32 flavor, + media_node_id * out_id, + int32 * io_count = 0); // default to 1 + + + status_t SetRealtimeFlags( + uint32 in_enabled); + status_t GetRealtimeFlags( + uint32 * out_enabled); + ssize_t AudioBufferSizeFor( + int32 channel_count, + uint32 sample_format, + float frame_rate, + bus_type bus_kind); + + /* Use MediaFlags to inquire about specific features of the Media Kit. */ + /* Returns < 0 for "not present", positive size for output data size. */ + /* 0 means that the capability is present, but no data about it. */ +static ssize_t MediaFlags( + media_flags cap, + void * buf, + size_t maxSize); + + /* BLooper overrides */ +virtual void MessageReceived( + BMessage * message); + +virtual bool QuitRequested(); + +virtual BHandler * ResolveSpecifier( + BMessage *msg, + int32 index, + BMessage *specifier, + int32 form, + const char *property); +virtual status_t GetSupportedSuites( + BMessage *data); + + ~BMediaRoster(); + +private: + + // deprecated call + status_t SetOutputBuffersFor( + const media_source & output, + BBufferGroup * group, + bool will_reclaim = false); + + /* FBC stuffing (Mmmh, Stuffing!) */ +virtual status_t _Reserved_MediaRoster_0(void *); +virtual status_t _Reserved_MediaRoster_1(void *); +virtual status_t _Reserved_MediaRoster_2(void *); +virtual status_t _Reserved_MediaRoster_3(void *); +virtual status_t _Reserved_MediaRoster_4(void *); +virtual status_t _Reserved_MediaRoster_5(void *); +virtual status_t _Reserved_MediaRoster_6(void *); +virtual status_t _Reserved_MediaRoster_7(void *); + +friend class _DefaultDeleter; +friend class _BMediaRosterP; +friend class _HostApp; +friend class MLatentManager; +friend class BBufferProducer; +friend class media_node; +friend class BBuffer; +friend class BMediaNode; + +static bool _isMediaServer; + + BMediaRoster(); + +static port_id _mReplyPort; +static int32 _mReplyPortRes; +static int32 _mReplyPortUnavailCount; + + uint32 _reserved_media_roster_[67]; + + +static BMediaRoster * _sDefault; + +static status_t ParseCommand( + BMessage & reply); + + status_t GetDefaultInfo( + media_node_id for_default, + BMessage & out_config); + status_t SetRunningDefault( + media_node_id for_default, + const media_node & node); + +static port_id checkout_reply_port( + const char * name = NULL); +static void checkin_reply_port( + port_id port); + +}; + + +#endif /* _MEDIA_ROSTER_H */ + diff --git a/headers/os/media/MediaTheme.h b/headers/os/media/MediaTheme.h new file mode 100644 index 0000000000..6141426b51 --- /dev/null +++ b/headers/os/media/MediaTheme.h @@ -0,0 +1,122 @@ +/******************************************************************************* +/ +/ File: ControlTheme.h +/ +/ Description: A BMediaTheme is something which can live in an add-on and is +/ responsible for creating BViews or BControls from a BParameterWeb and its +/ set of BMControls. This way, different "looks" for Media Kit control panels +/ can be achieved. +/ +/ Copyright 1997-98, Be Incorporated, All Rights Reserved +/ +*******************************************************************************/ + +#if !defined(_CONTROL_THEME_H) +#define _CONTROL_THEME_H + + +#include +#include + +class BParameterWeb; + + +class BMediaTheme +{ +public: +virtual ~BMediaTheme(); + + const char * Name(); + const char * Info(); + int32 ID(); + bool GetRef( + entry_ref * out_ref); + +static BView * ViewFor( + BParameterWeb * web, + const BRect * hintRect = NULL, + BMediaTheme * using_theme = NULL); + + /* This function takes possession of default_theme, even it if returns error */ +static status_t SetPreferredTheme( + BMediaTheme * default_theme = NULL); + +static BMediaTheme * PreferredTheme(); + +virtual BControl * MakeControlFor( + BParameter * control) = 0; + + enum bg_kind { + B_GENERAL_BG = 0, + B_SETTINGS_BG, + B_PRESENTATION_BG, + B_EDIT_BG, + B_CONTROL_BG, + B_HILITE_BG + }; + enum fg_kind { + B_GENERAL_FG = 0, + B_SETTINGS_FG, + B_PRESENTATION_FG, + B_EDIT_FG, + B_CONTROL_FG, + B_HILITE_FG + }; + +virtual BBitmap * BackgroundBitmapFor( + bg_kind bg = B_GENERAL_BG); +virtual rgb_color BackgroundColorFor( + bg_kind bg = B_GENERAL_BG); +virtual rgb_color ForegroundColorFor( + fg_kind fg = B_GENERAL_FG); + +protected: + BMediaTheme( + const char * name, + const char * info, + const entry_ref * add_on = 0, + int32 theme_id = 0); + +virtual BView * MakeViewFor( + BParameterWeb * web, + const BRect * hintRect = NULL) = 0; + +static BControl * MakeFallbackViewFor( + BParameter * control); + +private: + + BMediaTheme(); /* private unimplemented */ + BMediaTheme( + const BMediaTheme & clone); + BMediaTheme & operator=( + const BMediaTheme & clone); + + /* Mmmh, stuffing! */ +virtual status_t _Reserved_ControlTheme_0(void *); +virtual status_t _Reserved_ControlTheme_1(void *); +virtual status_t _Reserved_ControlTheme_2(void *); +virtual status_t _Reserved_ControlTheme_3(void *); +virtual status_t _Reserved_ControlTheme_4(void *); +virtual status_t _Reserved_ControlTheme_5(void *); +virtual status_t _Reserved_ControlTheme_6(void *); +virtual status_t _Reserved_ControlTheme_7(void *); + + char * _mName; + char * _mInfo; + int32 _mID; + bool _mAddOn; + entry_ref _mAddOnRef; + uint32 _reserved_control_theme_[8]; + +static BMediaTheme * _mDefaultTheme; + +}; + +/* Theme add-ons should export the functions: */ +#if defined(_BUILDING_THEME_ADDON) +extern "C" _EXPORT BMediaTheme * make_theme(int32 id, image_id you); +extern "C" _EXPORT status_t get_theme_at(int32 n, const char ** out_name, const char ** out_info, int32 * out_id); +#endif /* _BUILDING_THEME_ADDON */ + +#endif /* _CONTROL_THEME_H */ diff --git a/headers/os/media/MediaTrack.h b/headers/os/media/MediaTrack.h new file mode 100644 index 0000000000..3e810f981b --- /dev/null +++ b/headers/os/media/MediaTrack.h @@ -0,0 +1,293 @@ +#ifndef _MEDIA_TRACK_H +#define _MEDIA_TRACK_H + +#include +#include +#include + +namespace BPrivate { + class MediaExtractor; + class Decoder; + class MediaWriter; + class Encoder; +} + +class BView; +class BParameterWeb; + +enum media_seek_type { + B_MEDIA_SEEK_CLOSEST_FORWARD = 1, + B_MEDIA_SEEK_CLOSEST_BACKWARD = 2, + B_MEDIA_SEEK_DIRECTION_MASK = 3 +}; + +// +// BMediaTrack gives access to a particular media track in a media file +// (as represented by BMediaFile). +// +// You always instantiate a BMediaTrack through BMediaFile::TrackAt() +// or BMediaFile::CreateTrack(). When a BMediaTrack object is +// constructed it finds the necessary decoder or encoder for the type +// of data stored in the track. +// +// Unless you created the BMediaFile() in B_MEDIA_REPLACE_MODE, you +// can only access a track for reading or writing, not both. +// +// If InitCheck() indicates no errors, then the track is ready to be +// used to read and write frames using ReadFrames() and WriteFrames(). +// For video data you should always only read one frame. +// +// You can seek a track with SeekToTime() and SeekToFrame(). +// +// If no codec could be found for the track, it is still possible to +// access the encoded data using ReadChunk(). +// +class BMediaTrack { + +protected: + + // Use BMediaFile::ReleaseTrack() instead -- or it will go away + // on its own when the MediaFile is deleted. + // + virtual ~BMediaTrack(); + +public: + + // for read-only access the BMediaTrack should be instantiated + // through BMediaFile::TrackAt() + + // for write-only access the BMediaTrack should be instantiated + // through BMediaFile::CreateTrack() + + status_t InitCheck() const; + + // Get information about the codec being used. + status_t GetCodecInfo(media_codec_info *mci) const; + + + // EncodedFormat returns information about the track's + // "native" encoded format. + + status_t EncodedFormat(media_format *out_format) const; + + // DecodedFormat is used to negotiate the format that the codec will + // use when decoding the track's data. You pass in the format that + // that you want; the codec will find and return its "best fit" + // format. (inout_format is used as both the input and the returned + // format.) The format is typically of the B_MEDIA_RAW_AUDIO or + // B_MEDIA_RAW_VIDEO flavor. + // The data returned through ReadFrames() will be in the format that's + // returned by this function. + + status_t DecodedFormat(media_format *inout_format); + + // CountFrames and Duration return the total number of frame and the + // total duration (expressed in microseconds) of a track. + + int64 CountFrames() const; + bigtime_t Duration() const; + + // CurrentFrame and CurrentTime return the current position (expressed in + // microseconds) within the track, expressed in frame index and time. + + int64 CurrentFrame() const; + bigtime_t CurrentTime() const; + + // ReadFrames() fills a buffer with the next frames/samples. For a video + // track, it decodes the next frame of video in the passed buffer. For + // an audio track, it fills the buffers with the next N samples, as + // negotiated by DecodedFormat(). However, if it reaches the end of the + // file and was not able to fill the whole buffer, it returns a partial + // buffer. Upon return, out_frameCount contains the actual number of + // frame/samples returned, and the start time for the frame, expressed + // in microseconds, is in the media_header structure. + + status_t ReadFrames(void *out_buffer, int64 *out_frameCount, + media_header *mh = NULL); + + status_t ReadFrames(void *out_buffer, int64 *out_frameCount, + media_header *mh, media_decode_info *info); + + status_t ReplaceFrames(const void *in_buffer, int64 *io_frameCount, + const media_header *mh); + + + // SeekToTime and SeekToFrame are used for seeking to a particular + // position in a track, expressed in either frames or microseconds. + // They return whatever position they were able to seek to. For example, + // a video codec may not be able to seek to arbitrary frames, but only to + // key frames. In this case, it would return the closest key frame before + // the specified seek point. + // + // If you want to explicitly seek to the nearest keyframe _before_ this + // frame or _after_ this frame, pass B_MEDIA_SEEK_CLOSEST_FORWARD or + // B_MEDIA_SEEK_CLOSEST_BACKWARD as the flags field. + // + + status_t SeekToTime(bigtime_t *inout_time, int32 flags=0); + status_t SeekToFrame(int64 *inout_frame, int32 flags=0); + + status_t FindKeyFrameForTime(bigtime_t *inout_time, int32 flags=0) const; + status_t FindKeyFrameForFrame(int64 *inout_frame, int32 flags=0) const; + + // ReadChunk returns, in out_buffer, the next out_size bytes of + // data from the track. The data is not decoded -- it will be + // in its native encoded format (as specified by EncodedFormat()). + // You can not mix calling ReadChunk() and ReadFrames() -- either + // you access the track raw (i.e. with ReadChunk) or you access + // it with ReadFrames. + + status_t ReadChunk(char **out_buffer, int32 *out_size, + media_header *mh = NULL); + + + // + // Write-only Functions + // + status_t AddCopyright(const char *data); + status_t AddTrackInfo(uint32 code, const void *data, size_t size, + uint32 flags = 0); + + // + // Write num_frames of data to the track. This data is passed + // through the encoder that was specified when the MediaTrack + // was constructed. + // Pass B_MEDIA_KEY_FRAME for flags if it is. + // + status_t WriteFrames(const void *data, int32 num_frames, + int32 flags = 0); + status_t WriteFrames(const void *data, int64 num_frames, + media_encode_info *info); + + // + // Write a raw chunk of (presumably already encoded data) to + // the file. + // Pass B_MEDIA_KEY_FRAME for flags if it is. + // + status_t WriteChunk(const void *data, size_t size, + uint32 flags = 0); + status_t WriteChunk(const void *data, size_t size, + media_encode_info *info); + + // Flush all buffered encoded datas to disk. You should call it after + // writing the last frame to be sure all datas are flushed at the right + // offset into the file. + status_t Flush(); + + // These are for controlling the underlying encoder and track parameters + BParameterWeb *Web(); + status_t GetParameterValue(int32 id, void *valu, size_t *size); + status_t SetParameterValue(int32 id, const void *valu, size_t size); + BView *GetParameterView(); + + // This is a simplified control API, only one parameter low=0.0, high=1.0 + // Return B_ERROR if it's not supported by the current encoder. + status_t GetQuality(float *quality); + status_t SetQuality(float quality); + + status_t GetEncodeParameters(encode_parameters *parameters) const; + status_t SetEncodeParameters(encode_parameters *parameters); + + +virtual status_t Perform(int32 selector, void * data); + +private: + // for read-only access to a track + BMediaTrack(BPrivate::MediaExtractor *extractor, int32 stream); + + // for write-only access to a BMediaTrack + BMediaTrack(BPrivate::MediaWriter *writer, + int32 stream_num, + media_format *in_format, + BPrivate::Encoder *encoder, + media_codec_info *mci); + + status_t TrackInfo(media_format *out_format, void **out_info, + int32 *out_infoSize); + + status_t fErr; + BPrivate::Decoder *fDecoder; + int32 fDecoderID; + BPrivate::MediaExtractor *fExtractor; + + int32 fStream; + int64 fCurFrame; + bigtime_t fCurTime; + + media_codec_info fMCI; + + BPrivate::Encoder *fEncoder; + int32 fEncoderID; + BPrivate::MediaWriter *fWriter; + media_format fWriterFormat; + void *fExtractorCookie; + +protected: + int32 EncoderID() { return fEncoderID; }; + +private: + +friend class BMediaFile; +friend class BPrivate::Decoder; + + BMediaTrack(); + BMediaTrack(const BMediaTrack&); + BMediaTrack& operator=(const BMediaTrack&); + +static BPrivate::Decoder * find_decoder(BMediaTrack *track, int32 *id); + + /* fbc data and virtuals */ + + uint32 _reserved_BMediaTrack_[31]; + +virtual status_t _Reserved_BMediaTrack_0(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_1(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_2(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_3(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_4(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_5(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_6(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_7(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_8(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_9(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_10(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_11(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_12(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_13(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_14(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_15(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_16(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_17(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_18(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_19(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_20(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_21(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_22(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_23(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_24(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_25(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_26(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_27(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_28(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_29(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_30(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_31(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_32(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_33(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_34(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_35(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_36(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_37(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_38(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_39(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_40(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_41(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_42(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_43(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_44(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_45(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_46(int32 arg, ...); +virtual status_t _Reserved_BMediaTrack_47(int32 arg, ...); +}; + +#endif diff --git a/headers/os/media/ParameterWeb.h b/headers/os/media/ParameterWeb.h new file mode 100644 index 0000000000..5d2ed617ed --- /dev/null +++ b/headers/os/media/ParameterWeb.h @@ -0,0 +1,523 @@ +/******************************************************************************* +/ +/ File: ParameterWeb.h +/ +/ Description: A BParameterWeb is a description of media controls within a BControllable +/ Media Kit Node. +/ BParameter, BParameterGroup, BContinuousParameter, BDiscreteParameter and +/ BNullParameter are "data classes" used to describe the relation within a +/ BParameterWeb. These are NOT direct visible classes like BControls; just data +/ containers which applications can use to decide what kind of views to create. +/ +/ Copyright 1997-98, Be Incorporated, All Rights Reserved +/ +*******************************************************************************/ + +#if !defined(_CONTROL_WEB_H) +#define _CONTROL_WEB_H + +#include +#include +#include + +#if !defined(_PR3_COMPATIBLE_) +enum { + B_MEDIA_PARAMETER_TYPE = 'BMCT', + B_MEDIA_PARAMETER_WEB_TYPE = 'BMCW', + B_MEDIA_PARAMETER_GROUP_TYPE= 'BMCG' +}; +#endif + + +// It is highly unfortunate that a linker bug forces these symbols out +// from the BParameter class. Hope they don't collide with anything else. + +/* These are control KINDs */ + /* kind used when you don't know or care */ +extern _IMPEXP_MEDIA const char * const B_GENERIC; + /* kinds used for sliders */ +extern _IMPEXP_MEDIA const char * const B_MASTER_GAIN; /* Main Volume */ +extern _IMPEXP_MEDIA const char * const B_GAIN; +extern _IMPEXP_MEDIA const char * const B_BALANCE; +extern _IMPEXP_MEDIA const char * const B_FREQUENCY; /* like a radio tuner */ +extern _IMPEXP_MEDIA const char * const B_LEVEL; /* like for effects */ +extern _IMPEXP_MEDIA const char * const B_SHUTTLE_SPEED; /* Play, SloMo, Scan 1.0 == regular */ +extern _IMPEXP_MEDIA const char * const B_CROSSFADE; /* 0 == first input, +100 == second input */ +extern _IMPEXP_MEDIA const char * const B_EQUALIZATION; /* depth (dB) */ + + /* kinds used for compressors */ +extern _IMPEXP_MEDIA const char * const B_COMPRESSION; /* 0% == no compression, 99% == 100:1 compression */ +extern _IMPEXP_MEDIA const char * const B_QUALITY; /* 0% == full compression, 100% == no compression */ +extern _IMPEXP_MEDIA const char * const B_BITRATE; /* in bits/second */ +extern _IMPEXP_MEDIA const char * const B_GOP_SIZE; /* Group Of Pictures. a k a "Keyframe every N frames" */ + /* kinds used for selectors */ +extern _IMPEXP_MEDIA const char * const B_MUTE; /* 0 == thru, 1 == mute */ +extern _IMPEXP_MEDIA const char * const B_ENABLE; /* 0 == disable, 1 == enable */ +extern _IMPEXP_MEDIA const char * const B_INPUT_MUX; /* "value" 1-N == input selected */ +extern _IMPEXP_MEDIA const char * const B_OUTPUT_MUX; /* "value" 1-N == output selected */ +extern _IMPEXP_MEDIA const char * const B_TUNER_CHANNEL; /* like cable TV */ +extern _IMPEXP_MEDIA const char * const B_TRACK; /* like a CD player; "value" should be 1-N */ +extern _IMPEXP_MEDIA const char * const B_RECSTATE; /* like mutitrack tape deck, 0 == silent, 1 == play, 2 == record */ +extern _IMPEXP_MEDIA const char * const B_SHUTTLE_MODE; /* -1 == backwards, 0 == stop, 1 == play, 2 == pause/cue */ +extern _IMPEXP_MEDIA const char * const B_RESOLUTION; +extern _IMPEXP_MEDIA const char * const B_COLOR_SPACE; /* "value" should be color_space */ +extern _IMPEXP_MEDIA const char * const B_FRAME_RATE; +extern _IMPEXP_MEDIA const char * const B_VIDEO_FORMAT; /* 1 == NTSC-M, 2 == NTSC-J, 3 == PAL-BDGHI, 4 == PAL-M, 5 == PAL-N, 6 == SECAM, 7 == MPEG-1, 8 == MPEG-2 */ + /* kinds used for junctions */ + // the prefix of "WEB" is to avoid collission with an enum in Defs.h +extern _IMPEXP_MEDIA const char * const B_WEB_PHYSICAL_INPUT; /* a jack on the back of the card */ +extern _IMPEXP_MEDIA const char * const B_WEB_PHYSICAL_OUTPUT; +extern _IMPEXP_MEDIA const char * const B_WEB_ADC_CONVERTER; /* from analog to digital signals */ +extern _IMPEXP_MEDIA const char * const B_WEB_DAC_CONVERTER; /* from digital to analog signals */ +extern _IMPEXP_MEDIA const char * const B_WEB_LOGICAL_INPUT; /* an "input" that may not be physical */ +extern _IMPEXP_MEDIA const char * const B_WEB_LOGICAL_OUTPUT; +extern _IMPEXP_MEDIA const char * const B_WEB_LOGICAL_BUS; /* a logical connection point that is neither input nor output; auxilliary bus */ +extern _IMPEXP_MEDIA const char * const B_WEB_BUFFER_INPUT; /* an input that corresponds to a media_input */ +extern _IMPEXP_MEDIA const char * const B_WEB_BUFFER_OUTPUT; + + // a simple transport control is a discrete parameter with five values (states): + // rewinding, stopped, playing, paused, and fast-forwarding +extern _IMPEXP_MEDIA const char * const B_SIMPLE_TRANSPORT; + +class BList; +class BParameterGroup; +class BParameter; +class BNullParameter; +class BContinuousParameter; +class BDiscreteParameter; + + +/* Set these flags on parameters and groups to control how a Theme will */ +/* render the Web. Hidden means, generally, "don't show". Advanced means, */ +/* generally, that you can show it or not depending on your whim. */ +enum media_parameter_flags { + B_HIDDEN_PARAMETER = 0x1, + B_ADVANCED_PARAMETER = 0x2 +}; + + +class BParameterWeb : + public BFlattenable +{ +public: + BParameterWeb(); + ~BParameterWeb(); + + media_node Node(); + + BParameterGroup * MakeGroup( + const char * name); + + int32 CountGroups(); + BParameterGroup * GroupAt( + int32 index); + int32 CountParameters(); + BParameter * ParameterAt( + int32 index); + +virtual bool IsFixedSize() const; +virtual type_code TypeCode() const; +virtual ssize_t FlattenedSize() const; +virtual status_t Flatten(void *buffer, ssize_t size) const; +virtual bool AllowsTypeCode(type_code code) const; +virtual status_t Unflatten(type_code c, const void *buf, ssize_t size); + +private: + + friend class BParameterGroup; + friend class BControllable; + + BParameterWeb( + const BParameterWeb & clone); + BParameterWeb & operator=( + const BParameterWeb & clone); + + /* Mmmh, stuffing! */ +virtual status_t _Reserved_ControlWeb_0(void *); +virtual status_t _Reserved_ControlWeb_1(void *); +virtual status_t _Reserved_ControlWeb_2(void *); +virtual status_t _Reserved_ControlWeb_3(void *); +virtual status_t _Reserved_ControlWeb_4(void *); +virtual status_t _Reserved_ControlWeb_5(void *); +virtual status_t _Reserved_ControlWeb_6(void *); +virtual status_t _Reserved_ControlWeb_7(void *); + + BList * mGroups; + media_node mNode; + uint32 _reserved_control_web_[8]; + + BList * mOldRefs; + BList * mNewRefs; + + void AddRefFix( + void * oldItem, + void * newItem); +}; + + +class BParameterGroup : + public BFlattenable +{ +private: + + BParameterGroup( + BParameterWeb * web, + const char * name); +virtual ~BParameterGroup(); + +public: + + BParameterWeb * Web() const; + const char * Name() const; + + void SetFlags(uint32 flags); + uint32 Flags() const; + + BNullParameter * MakeNullParameter( + int32 id, + media_type m_type, + const char * name, + const char * kind); + BContinuousParameter * MakeContinuousParameter( + int32 id, + media_type m_type, + const char * name, + const char * kind, + const char * unit, + float minimum, + float maximum, + float stepping); + BDiscreteParameter * MakeDiscreteParameter( + int32 id, + media_type m_type, + const char * name, + const char * kind); + BParameterGroup * MakeGroup( + const char * name); + + int32 CountParameters(); + BParameter * ParameterAt( + int32 index); + int32 CountGroups(); + BParameterGroup * GroupAt( + int32 index); + +virtual bool IsFixedSize() const; +virtual type_code TypeCode() const; +virtual ssize_t FlattenedSize() const; +virtual status_t Flatten(void *buffer, ssize_t size) const; +virtual bool AllowsTypeCode(type_code code) const; +virtual status_t Unflatten(type_code c, const void *buf, ssize_t size); + +private: + + BParameterGroup(); /* private unimplemented */ + BParameterGroup( + const BParameterGroup & clone); + BParameterGroup & operator=( + const BParameterGroup & clone); + + /* Mmmh, stuffing! */ +virtual status_t _Reserved_ControlGroup_0(void *); +virtual status_t _Reserved_ControlGroup_1(void *); +virtual status_t _Reserved_ControlGroup_2(void *); +virtual status_t _Reserved_ControlGroup_3(void *); +virtual status_t _Reserved_ControlGroup_4(void *); +virtual status_t _Reserved_ControlGroup_5(void *); +virtual status_t _Reserved_ControlGroup_6(void *); +virtual status_t _Reserved_ControlGroup_7(void *); + + friend class BParameterWeb; + + BParameterWeb * mWeb; + BList * mControls; + BList * mGroups; + char * mName; + uint32 mFlags; + uint32 _reserved_control_group_[7]; + + BParameter * MakeControl( + int32 type); +}; + + +/* After you create a BParameter, hook it up by calling AddInput() and/or AddOutput() */ +/* (which will call the reciprocal in the target) and optionally call SetChannelCount() and SetMediaType() */ +class BParameter : + public BFlattenable +{ +public: + + /* This is a parameter TYPE */ + enum media_parameter_type + { + B_NULL_PARAMETER, + B_DISCRETE_PARAMETER, + B_CONTINUOUS_PARAMETER + }; + + media_parameter_type Type() const; + BParameterWeb * Web() const; + BParameterGroup * Group() const; + const char * Name() const; + const char * Kind() const; + const char * Unit() const; + int32 ID() const; + + void SetFlags(uint32 flags); + uint32 Flags() const; + +virtual type_code ValueType() = 0; + /* These functions are typically used by client apps; they will result in */ + /* your BControllable getting called to read/write values. */ + status_t GetValue( + void * buffer, + size_t * ioSize, + bigtime_t * when); + status_t SetValue( + const void * buffer, + size_t size, + bigtime_t when); + int32 CountChannels(); /* Number of ValueType() values; default is 1 */ + void SetChannelCount( /* One value could still control e g a stereo pair */ + int32 channel_count); + + media_type MediaType(); /* Optional (default is B_MEDIA_NO_TYPE) */ + void SetMediaType(media_type m_type); + + int32 CountInputs(); + BParameter * InputAt( + int32 index); + void AddInput( + BParameter * input); + int32 CountOutputs(); + BParameter * OutputAt( + int32 index); + void AddOutput( + BParameter * output); + +virtual bool IsFixedSize() const; +virtual type_code TypeCode() const; +virtual ssize_t FlattenedSize() const; +virtual status_t Flatten(void *buffer, ssize_t size) const; +virtual bool AllowsTypeCode(type_code code) const; +virtual status_t Unflatten(type_code c, const void *buf, ssize_t size); + +private: + friend class BNullParameter; + friend class BContinuousParameter; + friend class BDiscreteParameter; + friend class BParameterGroup; + friend class BParameterWeb; + + bool SwapOnUnflatten() { return mSwapDetected; } + + /* Mmmh, stuffing! */ +virtual status_t _Reserved_Control_0(void *); +virtual status_t _Reserved_Control_1(void *); +virtual status_t _Reserved_Control_2(void *); +virtual status_t _Reserved_Control_3(void *); +virtual status_t _Reserved_Control_4(void *); +virtual status_t _Reserved_Control_5(void *); +virtual status_t _Reserved_Control_6(void *); +virtual status_t _Reserved_Control_7(void *); + + + BParameter( + int32 id, + media_type m_type, + media_parameter_type type, + BParameterWeb * web, + const char * name, + const char * kind, + const char * unit); + ~BParameter(); + + int32 mID; + media_parameter_type mType; + BParameterWeb * mWeb; + BParameterGroup * mGroup; + char * mName; + char * mKind; + char * mUnit; + BList * mInputs; + BList * mOutputs; + bool mSwapDetected; + media_type mMediaType; + int32 mChannels; + uint32 mFlags; + uint32 _reserved_control_[7]; + +virtual void FixRefs( + BList & old, + BList & updated); +}; + + +class BContinuousParameter : + public BParameter +{ +public: + +virtual type_code ValueType(); + + float MinValue(); + float MaxValue(); + float ValueStep(); + + /* The "response" specifies what value to display to the user. */ + /* Thus, if response is B_POLYNOMIAL with factor 2, an actual */ + /* control value of 10 would be displayed to the user as 100, and */ + /* if response was B_EXPONENTIAL and factor was 2, an actual */ + /* value of 3 would display 8 (two to the third). The ValueStep() */ + /* is given in actual control values, before the transformation for */ + /* display is done. Thus, with min 0, max 4 and value step 1, and an */ + /* exponential response with factor 10, you will get the displayed */ + /* values 1, 10, 100, 1000 and 10000 equally spaced across a slider */ + /* (or whatever UI the app puts to the parameter). */ + /* The "offset" is added to the value after transformation, before display. */ + /* If "resp" is negative, the resulting value/display relation is turned upside down. */ + enum response { + B_UNKNOWN = 0, + B_LINEAR = 1, /* factor is direct multiplier >= 0 */ + B_POLYNOMIAL, /* factor should be power; typically "2" for squared or "-1" for inverse */ + B_EXPONENTIAL, /* factor should be base, typically 2 or 10 */ + B_LOGARITHMIC /* factor should be base, typically 2 or 10 */ + }; + void SetResponse( + int resp, + float factor, + float offset); + void GetResponse( + int * resp, + float * factor, + float * offset); + +virtual ssize_t FlattenedSize() const; +virtual status_t Flatten(void *buffer, ssize_t size) const; +virtual status_t Unflatten(type_code c, const void *buf, ssize_t size); + +private: + + /* Mmmh, stuffing! */ +virtual status_t _Reserved_ContinuousParameter_0(void *); +virtual status_t _Reserved_ContinuousParameter_1(void *); +virtual status_t _Reserved_ContinuousParameter_2(void *); +virtual status_t _Reserved_ContinuousParameter_3(void *); +virtual status_t _Reserved_ContinuousParameter_4(void *); +virtual status_t _Reserved_ContinuousParameter_5(void *); +virtual status_t _Reserved_ContinuousParameter_6(void *); +virtual status_t _Reserved_ContinuousParameter_7(void *); + friend class BParameterGroup; + + BContinuousParameter( + int32 id, + media_type m_type, + BParameterWeb * web, + const char * name, + const char * kind, + const char * unit, + float minimum, + float maximum, + float stepping); + ~BContinuousParameter(); + + float mMinimum; + float mMaximum; + float mStepping; + response mResponse; + float mFactor; + float mOffset; + uint32 _reserved_control_slider_[8]; + +}; + + +class BDiscreteParameter : + public BParameter +{ +public: + +virtual type_code ValueType(); + + int32 CountItems(); + const char * ItemNameAt( + int32 index); + int32 ItemValueAt( + int32 index); + status_t AddItem( + int32 value, + const char * name); + status_t MakeItemsFromInputs(); + status_t MakeItemsFromOutputs(); + void MakeEmpty(); + +virtual ssize_t FlattenedSize() const; +virtual status_t Flatten(void *buffer, ssize_t size) const; +virtual status_t Unflatten(type_code c, const void *buf, ssize_t size); + +private: + /* Mmmh, stuffing! */ +virtual status_t _Reserved_DiscreteParameter_0(void *); +virtual status_t _Reserved_DiscreteParameter_1(void *); +virtual status_t _Reserved_DiscreteParameter_2(void *); +virtual status_t _Reserved_DiscreteParameter_3(void *); +virtual status_t _Reserved_DiscreteParameter_4(void *); +virtual status_t _Reserved_DiscreteParameter_5(void *); +virtual status_t _Reserved_DiscreteParameter_6(void *); +virtual status_t _Reserved_DiscreteParameter_7(void *); + + friend class BParameterGroup; + + BList * mSelections; + BList * mValues; + uint32 _reserved_control_selector_[8]; + + BDiscreteParameter( + int32 id, + media_type m_type, + BParameterWeb * web, + const char * name, + const char * kind); + ~BDiscreteParameter(); +}; + + +class BNullParameter : + public BParameter +{ +public: + +virtual type_code ValueType(); + +virtual ssize_t FlattenedSize() const; +virtual status_t Flatten(void *buffer, ssize_t size) const; +virtual status_t Unflatten(type_code c, const void *buf, ssize_t size); + +private: + /* Mmmh, stuffing! */ +virtual status_t _Reserved_NullParameter_0(void *); +virtual status_t _Reserved_NullParameter_1(void *); +virtual status_t _Reserved_NullParameter_2(void *); +virtual status_t _Reserved_NullParameter_3(void *); +virtual status_t _Reserved_NullParameter_4(void *); +virtual status_t _Reserved_NullParameter_5(void *); +virtual status_t _Reserved_NullParameter_6(void *); +virtual status_t _Reserved_NullParameter_7(void *); + + friend class BParameterGroup; + + uint32 _reserved_control_junction_[8]; + + BNullParameter( + int32 id, + media_type m_type, + BParameterWeb * web, + const char * name, + const char * kind); + ~BNullParameter(); + +}; + + +#endif /* _CONTROL_WEB_H */ diff --git a/headers/os/media/PlaySound.h b/headers/os/media/PlaySound.h new file mode 100644 index 0000000000..7ee6bad966 --- /dev/null +++ b/headers/os/media/PlaySound.h @@ -0,0 +1,34 @@ +/****************************************************************************** + + File: PlaySound.h + + Description: Interface for a simple beep sound. + + Copyright 1995-97, Be Incorporated + +******************************************************************************/ +#ifndef _PLAY_SOUND_H +#define _PLAY_SOUND_H + +#ifndef _BE_BUILD_H +#include +#endif +#include +#include + +typedef sem_id sound_handle; + +_IMPEXP_MEDIA +sound_handle play_sound(const entry_ref *soundRef, + bool mix, + bool queue, + bool background + ); + +_IMPEXP_MEDIA +status_t stop_sound(sound_handle handle); + +_IMPEXP_MEDIA +status_t wait_for_sound(sound_handle handle); + +#endif /* #ifndef _PLAY_SOUND_H*/ diff --git a/headers/os/media/RealtimeAlloc.h b/headers/os/media/RealtimeAlloc.h new file mode 100644 index 0000000000..c39ba79f1e --- /dev/null +++ b/headers/os/media/RealtimeAlloc.h @@ -0,0 +1,51 @@ +/******************************************************************************* +/ +/ File: RealtimeAlloc.h +/ +/ Description: Allocation from separate "pools" of memory. Those pools +/ will be locked in RAM if realtime allocators are turned +/ on in the BMediaRoster, so don't waste this memory unless +/ it's needed. Also, the shared pool is a scarce resource, +/ so it's better if you create your own pool for your own +/ needs and leave the shared pool for BMediaNode instances +/ and the needs of the Media Kit. +/ +/ Copyright 1998-99, Be Incorporated, All Rights Reserved +/ +*******************************************************************************/ + +#if !defined(_REALTIME_ALLOC_H) +#define _REALTIME_ALLOC_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +typedef struct rtm_pool rtm_pool; + +/* If out_pool is NULL, the default pool will be created if it isn't already. */ +/* If the default pool is already created, it will return EALREADY. */ +#if defined(__cplusplus) +_IMPEXP_MEDIA status_t rtm_create_pool(rtm_pool ** out_pool, size_t total_size, const char * name=NULL); +#else +_IMPEXP_MEDIA status_t rtm_create_pool(rtm_pool ** out_pool, size_t total_size, const char * name); +#endif +_IMPEXP_MEDIA status_t rtm_delete_pool(rtm_pool * pool); +/* If NULL is passed for pool, the default pool is used (if created). */ +_IMPEXP_MEDIA void * rtm_alloc(rtm_pool * pool, size_t size); +_IMPEXP_MEDIA status_t rtm_free(void * data); +_IMPEXP_MEDIA status_t rtm_realloc(void ** data, size_t new_size); +_IMPEXP_MEDIA status_t rtm_size_for(void * data); +_IMPEXP_MEDIA status_t rtm_phys_size_for(void * data); + +/* Return the default pool, or NULL if not yet initialized */ +_IMPEXP_MEDIA rtm_pool * rtm_default_pool(); + +#if defined(__cplusplus) +} +#endif + +#endif // _REALTIME_ALLOC_H + diff --git a/headers/os/media/Sound.h b/headers/os/media/Sound.h new file mode 100644 index 0000000000..1a81204b7f --- /dev/null +++ b/headers/os/media/Sound.h @@ -0,0 +1,111 @@ +/* BSound.h */ +/* Copyright 1998 Be Incorporated. All rights reserved. */ + +#if !defined(_SOUND_H) +#define _SOUND_H + +#include + +class BSoundFile; + +namespace BPrivate { + class BTrackReader; +} + +class BSound { +public: + BSound( + void * data, + size_t size, + const media_raw_audio_format & format, + bool free_when_done = false); + BSound( + const entry_ref * sound_file, + bool load_into_memory = false); + + status_t InitCheck(); + BSound * AcquireRef(); + bool ReleaseRef(); + int32 RefCount() const; // unreliable! + +virtual bigtime_t Duration() const; +virtual const media_raw_audio_format & Format() const; +virtual const void * Data() const; /* returns NULL for files */ +virtual off_t Size() const; + +virtual bool GetDataAt( + off_t offset, + void * into_buffer, + size_t buffer_size, + size_t * out_used); + +protected: + + BSound( + const media_raw_audio_format & format); + +virtual status_t Perform( + int32 code, + ...); + +private: + + BSound(const BSound &); // unimplemented + BSound & operator=(const BSound &); // unimplemented + + friend class BSoundPlayer; + friend class _HostApp; + + void Reset(); + +virtual ~BSound(); + + void free_data(); +static status_t load_entry(void * arg); + void loader_thread(); + bool check_stop(); + +public: + +virtual status_t BindTo( + BSoundPlayer * player, + const media_raw_audio_format & format); +virtual status_t UnbindFrom( + BSoundPlayer * player); + +private: + status_t _Reserved_Sound_0(void *); // BindTo + status_t _Reserved_Sound_1(void *); // UnbindFrom +virtual status_t _Reserved_Sound_2(void *); +virtual status_t _Reserved_Sound_3(void *); +virtual status_t _Reserved_Sound_4(void *); +virtual status_t _Reserved_Sound_5(void *); + + void * _m_data; + BMediaFile * _m_file; + int32 _m_ref_count; + status_t _m_error; + size_t _m_size; + media_raw_audio_format _m_format; + bool _m_free_when_done; + bool _m_checkStopped; + bool _m_reserved[2]; + area_id _m_area; + sem_id _m_avail_sem; + sem_id _m_free_sem; + thread_id _m_loader_thread; + size_t _m_read_pos; + sem_id _m_check_token; + int32 _m_prev_sem_count; + + BSoundPlayer * _m_bound_player; + int32 _m_bind_flags; + + BPrivate::BTrackReader * _m_trackReader; + char m_tname[32]; + uint32 _reserved_[1]; + +}; + + +#endif /* _SOUND_H */ diff --git a/headers/os/media/SoundFile.h b/headers/os/media/SoundFile.h new file mode 100644 index 0000000000..6a1fba8b2a --- /dev/null +++ b/headers/os/media/SoundFile.h @@ -0,0 +1,101 @@ +/****************************************************************************** + + File: SoundFile.h + + Description: Interface for a format-insensitive sound file object. + + Copyright 1995-97, Be Incorporated + +******************************************************************************/ + + +#ifndef _SOUND_FILE_H +#define _SOUND_FILE_H + +#ifndef _BE_BUILD_H +#include +#endif +#include +#include +#include + +enum /* sound_format*/ +{ B_UNKNOWN_FILE, + B_AIFF_FILE, + B_WAVE_FILE, + B_UNIX_FILE }; + +class BSoundFile { + +public: + BSoundFile(); + BSoundFile(const entry_ref *ref, + uint32 open_mode); + virtual ~BSoundFile(); + + status_t InitCheck() const; + + status_t SetTo(const entry_ref *ref, uint32 open_mode); + + int32 FileFormat() const; + int32 SamplingRate() const; + int32 CountChannels() const; + int32 SampleSize() const; + int32 ByteOrder() const; + int32 SampleFormat() const; + int32 FrameSize() const; + off_t CountFrames() const; + + bool IsCompressed() const; + int32 CompressionType() const; + char *CompressionName() const; + + virtual int32 SetFileFormat(int32 format); + virtual int32 SetSamplingRate(int32 fps); + virtual int32 SetChannelCount(int32 spf); + virtual int32 SetSampleSize(int32 bps); + virtual int32 SetByteOrder(int32 bord); + virtual int32 SetSampleFormat(int32 fmt); + virtual int32 SetCompressionType(int32 type); + virtual char *SetCompressionName(char *name); + virtual bool SetIsCompressed(bool tf); + virtual off_t SetDataLocation(off_t offset); + virtual off_t SetFrameCount(off_t count); + + size_t ReadFrames(char *buf, size_t count); + size_t WriteFrames(char *buf, size_t count); + virtual off_t SeekToFrame(off_t n); + off_t FrameIndex() const; + off_t FramesRemaining() const; + + BFile *fSoundFile; + +private: + +virtual void _ReservedSoundFile1(); +virtual void _ReservedSoundFile2(); +virtual void _ReservedSoundFile3(); + + int32 fFileFormat; + int32 fSamplingRate; + int32 fChannelCount; + int32 fSampleSize; + int32 fByteOrder; + int32 fSampleFormat; + + off_t fByteOffset; /* offset to first sample */ + + off_t fFrameCount; + off_t fFrameIndex; + + bool fIsCompressed; + int32 fCompressionType; + char *fCompressionName; + status_t fCStatus; + void _init_raw_stats(); + status_t _ref_to_file(const entry_ref *ref); + uint32 _reserved[4]; +}; + + +#endif /* #ifndef _SOUND_FILE_H*/ diff --git a/headers/os/media/SoundPlayer.h b/headers/os/media/SoundPlayer.h new file mode 100644 index 0000000000..64dfee5d8a --- /dev/null +++ b/headers/os/media/SoundPlayer.h @@ -0,0 +1,197 @@ +/* SoundPlayer.h */ +/* Copyright 1998 Be Incorporated. All rights reserved. */ + +#if !defined(_SOUND_PLAYER_H) +#define _SOUND_PLAYER_H + + +#include +#include +#include +#include + + +class BSound; +class sound_error : public exception { + const char * m_str_const; +public: + sound_error(const char * str); + const char * what() const; +}; + +class BSoundPlayer { + friend class _SoundPlayNode; +public: + enum sound_player_notification { + B_STARTED = 1, + B_STOPPED, + B_SOUND_DONE + }; + + BSoundPlayer( + const char * name = NULL, + void (*PlayBuffer)(void *, void * buffer, size_t size, const media_raw_audio_format & format) = NULL, + void (*Notifier)(void *, sound_player_notification what, ...) = NULL, + void * cookie = NULL); + BSoundPlayer( + const media_raw_audio_format * format, + const char * name = NULL, + void (*PlayBuffer)(void *, void * buffer, size_t size, const media_raw_audio_format & format) = NULL, + void (*Notifier)(void *, sound_player_notification what, ...) = NULL, + void * cookie = NULL); + BSoundPlayer( + const media_node & toNode, + const media_multi_audio_format * format = NULL, + const char * name = NULL, + const media_input * input = NULL, + void (*PlayBuffer)(void *, void * buffer, size_t size, const media_raw_audio_format & format) = NULL, + void (*Notifier)(void *, sound_player_notification what, ...) = NULL, + void * cookie = NULL); +virtual ~BSoundPlayer(); + + status_t InitCheck(); // new in R4.1 + media_raw_audio_format Format() const; // new in R4.1 + + status_t Start(); + void Stop( + bool block = true, + bool flush = true); + + typedef void (*BufferPlayerFunc)(void *, void *, size_t, const media_raw_audio_format &); + BufferPlayerFunc BufferPlayer() const; + void SetBufferPlayer( + void (*PlayBuffer)(void *, void * buffer, size_t size, const media_raw_audio_format & format)); + typedef void (*EventNotifierFunc)(void *, sound_player_notification what, ...); + EventNotifierFunc EventNotifier() const; + void SetNotifier( + void (*Notifier)(void *, sound_player_notification what, ...)); + void * Cookie() const; + void SetCookie( + void * cookie); + void SetCallbacks( // atomic change + void (*PlayBuffer)(void *, void * buffer, size_t size, const media_raw_audio_format & format) = NULL, + void (*Notifier)(void *, sound_player_notification what, ...) = NULL, + void * cookie = NULL); + + typedef int32 play_id; + + bigtime_t CurrentTime(); + bigtime_t PerformanceTime(); + status_t Preroll(); + play_id StartPlaying( + BSound * sound, + bigtime_t at_time = 0); + play_id StartPlaying( + BSound * sound, + bigtime_t at_time, + float with_volume); + status_t SetSoundVolume( + play_id sound, // update only non-NULL values + float new_volume); + bool IsPlaying( + play_id id); + status_t StopPlaying( + play_id id); + status_t WaitForSound( + play_id id); + + float Volume(); /* 0 - 1.0 */ + void SetVolume( /* 0 - 1.0 */ + float new_volume); + float VolumeDB( /* -xx - +xx (see GetVolumeInfo()) */ + bool forcePoll = false); /* if false, cached value will be used if new enough */ + void SetVolumeDB( + float volume_dB); + status_t GetVolumeInfo( + media_node * out_node, + int32 * out_parameter, + float * out_min_dB, + float * out_max_dB); + bigtime_t Latency(); + +virtual bool HasData(); + void SetHasData( // this does more than just set a flag + bool has_data); + +protected: + + void SetInitError( // new in R4.1 + status_t in_error); + +private: + +virtual status_t _Reserved_SoundPlayer_0(void *, ...); +virtual status_t _Reserved_SoundPlayer_1(void *, ...); +virtual status_t _Reserved_SoundPlayer_2(void *, ...); +virtual status_t _Reserved_SoundPlayer_3(void *, ...); +virtual status_t _Reserved_SoundPlayer_4(void *, ...); +virtual status_t _Reserved_SoundPlayer_5(void *, ...); +virtual status_t _Reserved_SoundPlayer_6(void *, ...); +virtual status_t _Reserved_SoundPlayer_7(void *, ...); + + _SoundPlayNode * _m_node; + struct _playing_sound { + _playing_sound * next; + off_t cur_offset; + BSound * sound; + play_id id; + int32 delta; + int32 rate; + float volume; + }; + _playing_sound * _m_sounds; + struct _waiting_sound { + _waiting_sound * next; + bigtime_t start_time; + BSound * sound; + play_id id; + int32 rate; + float volume; + }; + _waiting_sound * _m_waiting; + void (*_PlayBuffer)(void * cookie, void * buffer, size_t size, const media_raw_audio_format & format); + void (*_Notifier)(void * cookie, sound_player_notification what, ...); + BLocker _m_lock; + float _m_volume; + media_input m_input; + media_output m_output; + float * _m_mix_buffer; + size_t _m_mix_buffer_size; + void * _m_cookie; + void * _m_buf; + size_t _m_bufsize; + int32 _m_has_data; + + status_t _m_init_err; // new in R4.1 + bigtime_t _m_perfTime; + BContinuousParameter * _m_volumeSlider; + bigtime_t _m_gotVolume; + uint32 _m_reserved[10]; + + void NotifySoundDone( + play_id sound, + bool got_to_play); + + void get_volume_slider(); + void Init( + const media_node * node, + const media_multi_audio_format * format, + const char * name, + const media_input * input, + void (*PlayBuffer)(void *, void * buffer, size_t size, const media_raw_audio_format & format), + void (*Notifier)(void *, sound_player_notification what, ...), + void * cookie); + // for B_STARTED and B_STOPPED, the argument is BSoundPlayer* (this) + // for B_SOUND_DONE, the arguments are play_id and true/false for whether it got to play data at all +virtual void Notify( + sound_player_notification what, + ...); + // get data into the buffer to play -- this version will use the queued BSound system +virtual void PlayBuffer( + void * buffer, + size_t size, + const media_raw_audio_format & format); +}; + + +#endif /* _SOUND_PLAYER_H */ diff --git a/headers/os/media/TimeCode.h b/headers/os/media/TimeCode.h new file mode 100644 index 0000000000..16eae0be74 --- /dev/null +++ b/headers/os/media/TimeCode.h @@ -0,0 +1,119 @@ +/***************************************************************** + + File: TimeCode.h + + Description: Time code handling functions and class + + Copyright 1998-, Be Incorporated. All Rights Reserved. + +*****************************************************************/ + +#if !defined(_TIME_CODE_H) +#define _TIME_CODE_H + +#include + + +/* Time code is always in the form HH:MM:SS:FF, it's the definition of FF that varies */ +enum timecode_type { + B_TIMECODE_DEFAULT, + B_TIMECODE_100, + B_TIMECODE_75, /* CD */ + B_TIMECODE_30, /* MIDI */ + B_TIMECODE_30_DROP_2, /* NTSC */ + B_TIMECODE_30_DROP_4, /* Brazil */ + B_TIMECODE_25, /* PAL */ + B_TIMECODE_24, /* Film */ + B_TIMECODE_18 /* Super8 */ +}; +struct timecode_info { + timecode_type type; + int drop_frames; + int every_nth; + int except_nth; + int fps_div; + char name[32]; /* for popup menu etc */ + char format[32]; /* for sprintf(fmt, h, m, s, f) */ + char _reserved_[64]; +}; +_IMPEXP_MEDIA status_t us_to_timecode(bigtime_t micros, int * hours, int * minutes, int * seconds, int * frames, const timecode_info * code = NULL); +_IMPEXP_MEDIA status_t timecode_to_us(int hours, int minutes, int seconds, int frames, bigtime_t * micros, const timecode_info * code = NULL); +_IMPEXP_MEDIA status_t frames_to_timecode(int32 l_frames, int * hours, int * minutes, int * seconds, int * frames, const timecode_info * code = NULL); +_IMPEXP_MEDIA status_t timecode_to_frames(int hours, int minutes, int seconds, int frames, int32 * l_frames, const timecode_info * code = NULL); +_IMPEXP_MEDIA status_t get_timecode_description(timecode_type type, timecode_info * out_timecode); +_IMPEXP_MEDIA status_t count_timecodes(); +/* we may want a set_default_timecode, too -- but that's bad from a thread standpoint */ + + +class BTimeCode { +public: + BTimeCode(); + BTimeCode( + bigtime_t us, + timecode_type type = B_TIMECODE_DEFAULT); + BTimeCode( + const BTimeCode & clone); + BTimeCode( + int hours, + int minutes, + int seconds, + int frames, + timecode_type type = B_TIMECODE_DEFAULT); + ~BTimeCode(); + + void SetData( + int hours, + int minutes, + int seconds, + int frames); + status_t SetType( + timecode_type type); + void SetMicroseconds( + bigtime_t us); + void SetLinearFrames( + int32 linear_frames); + + BTimeCode & operator=( + const BTimeCode & clone); + bool operator==( + const BTimeCode & other) const; + bool operator<( + const BTimeCode & other) const; + + BTimeCode & operator+=( + const BTimeCode & other); + BTimeCode & operator-=( + const BTimeCode & other); + + BTimeCode operator+( + const BTimeCode & other) const; + BTimeCode operator-( + const BTimeCode & other) const; + + int Hours() const; + int Minutes() const; + int Seconds() const; + int Frames() const; + timecode_type Type() const; + void GetData( + int * out_hours, + int * out_minutes, + int * out_seconds, + int * out_frames, + timecode_type * out_type = NULL) const; + + bigtime_t Microseconds() const; + int32 LinearFrames() const; + void GetString( + char * str) const; /* at least 24 bytes */ + +private: + int m_hours; + int m_minutes; + int m_seconds; + int m_frames; + timecode_info m_info; +}; + + +#endif /* _TIME_CODE_H */ diff --git a/headers/os/media/TimeSource.h b/headers/os/media/TimeSource.h new file mode 100644 index 0000000000..44e24dc512 --- /dev/null +++ b/headers/os/media/TimeSource.h @@ -0,0 +1,141 @@ +/******************************************************************************* +/ +/ File: TimeSource.h +/ +/ Description: A BTimeSource is something to which others can slave timing information +/ using the Media Kit. +/ +/ Copyright 1997-98, Be Incorporated, All Rights Reserved +/ +*******************************************************************************/ + +#if !defined(_TIME_SOURCE_H) +#define _TIME_SOURCE_H + +#include +#include + + +class _BSlaveNodeStorageP; +struct _time_transmit_buf; + + +class BTimeSource : + public virtual BMediaNode +{ +protected: + /* this has to be at the top to force a vtable */ +virtual ~BTimeSource(); + +public: + +virtual status_t SnoozeUntil( /* returns error if stopped */ + bigtime_t performance_time, + bigtime_t with_latency = 0, + bool retry_signals = false); + + bigtime_t Now(); /* convenience, less accurate */ + bigtime_t PerformanceTimeFor( /* all three go through GetTime() */ + bigtime_t real_time); + bigtime_t RealTimeFor( + bigtime_t performance_time, + bigtime_t with_latency); + bool IsRunning(); + + status_t GetTime( /* return B_OK if reading is usable */ + bigtime_t * performance_time, + bigtime_t * real_time, + float * drift); + +static bigtime_t RealTime(); /* this produces real time, nothing else is guaranteed to */ + + status_t GetStartLatency( + bigtime_t * out_latency); + +protected: + + BTimeSource(); + +virtual status_t HandleMessage( + int32 message, + const void * data, + size_t size); + + void PublishTime( /* call this at convenient times to update approximation */ + bigtime_t performance_time, + bigtime_t real_time, + float drift); + + void BroadcastTimeWarp( + bigtime_t at_real_time, + bigtime_t new_performance_time); /* when running */ + void SendRunMode( + run_mode mode); + +virtual void SetRunMode( + run_mode mode); /* or, instead, SendRunMode() */ + + enum time_source_op { + B_TIMESOURCE_START = 1, + B_TIMESOURCE_STOP, + B_TIMESOURCE_STOP_IMMEDIATELY, + B_TIMESOURCE_SEEK + }; + struct time_source_op_info { + time_source_op op; + int32 _reserved1; + bigtime_t real_time; + bigtime_t performance_time; + int32 _reserved2[6]; + }; +virtual status_t TimeSourceOp( + const time_source_op_info & op, + void * _reserved) = 0; + +private: + + friend class _BMediaRosterP; + friend class _BTimeSourceP; + friend class _SysTimeSource; + friend class BMediaNode; + friend class BMediaRoster; + friend class _ServerApp; + + BTimeSource( /* private unimplemented */ + const BTimeSource & clone); + BTimeSource & operator=( + const BTimeSource & clone); + + /* Mmmh, stuffing! */ + status_t _Reserved_TimeSource_0(void *); // TimeSourceOp() +virtual status_t _Reserved_TimeSource_1(void *); +virtual status_t _Reserved_TimeSource_2(void *); +virtual status_t _Reserved_TimeSource_3(void *); +virtual status_t _Reserved_TimeSource_4(void *); +virtual status_t _Reserved_TimeSource_5(void *); + + bool fStopped; + + area_id _mArea; +volatile _time_transmit_buf * _mBuf; + _BSlaveNodeStorageP * _mSlaveNodes; + + area_id _mOrigArea; + uint32 _reserved_time_source_[11]; + +explicit BTimeSource( + media_node_id id); + void FinishCreate(); /* called by roster and/or server */ + +virtual status_t RemoveMe(BMediaNode * node); +virtual status_t AddMe(BMediaNode * node); + + void DirectStart(bigtime_t at); + void DirectStop(bigtime_t at, bool immediate); + void DirectSeek(bigtime_t to, bigtime_t at); + void DirectSetRunMode(run_mode mode); +}; + + +#endif /* _TIME_SOURCE_H */ + diff --git a/headers/os/media/TimedEventQueue.h b/headers/os/media/TimedEventQueue.h new file mode 100644 index 0000000000..582cb7e019 --- /dev/null +++ b/headers/os/media/TimedEventQueue.h @@ -0,0 +1,186 @@ +/******************************************************************************* +/ +/ File: TimedEventQueue.h +/ +/ Description: A priority queue for holding media_timed_events. +/ Sorts by increasing time, so events near the front +/ of the queue are to occur earlier. +/ +/ Copyright 1999, Be Incorporated, All Rights Reserved +/ +*******************************************************************************/ + +#ifndef _TIMED_EVENT_QUEUE_H +#define _TIMED_EVENT_QUEUE_H + +#include + +struct _event_queue_imp; + + +struct media_timed_event { + media_timed_event(); + media_timed_event(bigtime_t inTime, int32 inType); + media_timed_event(bigtime_t inTime, int32 inType, + void *inPointer, uint32 inCleanup); + media_timed_event( + bigtime_t inTime, int32 inType, + void *inPointer, uint32 inCleanup, + int32 inData, int64 inBigdata, + char *inUserData, size_t dataSize = 0); + + media_timed_event(const media_timed_event & clone); + void operator=(const media_timed_event & clone); + + ~media_timed_event(); + + bigtime_t event_time; + int32 type; + void * pointer; + uint32 cleanup; + int32 data; + int64 bigdata; + char user_data[64]; + uint32 _reserved_media_timed_event_[8]; +}; + +_IMPEXP_MEDIA bool operator==(const media_timed_event & a, const media_timed_event & b); +_IMPEXP_MEDIA bool operator!=(const media_timed_event & a, const media_timed_event & b); +_IMPEXP_MEDIA bool operator<(const media_timed_event & a, const media_timed_event & b); +_IMPEXP_MEDIA bool operator>(const media_timed_event & a, const media_timed_event &b); + + +class BTimedEventQueue { + public: + + enum event_type { + B_NO_EVENT = -1, // never push this type! it will fail + B_ANY_EVENT = 0, // never push this type! it will fail + B_START, + B_STOP, + B_SEEK, + B_WARP, + B_TIMER, + B_HANDLE_BUFFER, + B_DATA_STATUS, + B_HARDWARE, + B_PARAMETER, + /* user defined events above this value */ + B_USER_EVENT = 0x4000 + }; + + enum cleanup_flag { + B_NO_CLEANUP = 0, + B_RECYCLE_BUFFER, // recycle buffers handled by BTimedEventQueue + B_EXPIRE_TIMER, // call TimerExpired() on the event->data + B_USER_CLEANUP = 0x4000 // others go to the cleanup func + }; + + enum time_direction { + B_ALWAYS = -1, + B_BEFORE_TIME = 0, + B_AT_TIME, + B_AFTER_TIME + }; + + + void * operator new(size_t s); + void operator delete(void * p, size_t s); + + BTimedEventQueue(); + virtual ~BTimedEventQueue(); + + status_t AddEvent(const media_timed_event &event); + status_t RemoveEvent(const media_timed_event *event); + status_t RemoveFirstEvent(media_timed_event * outEvent = NULL); + + bool HasEvents() const; + int32 EventCount() const; + + /* Accessors */ + const media_timed_event * FirstEvent() const; + bigtime_t FirstEventTime() const; + const media_timed_event * LastEvent() const; + bigtime_t LastEventTime() const; + + const media_timed_event * FindFirstMatch( + bigtime_t eventTime, + time_direction direction, + bool inclusive = true, + int32 eventType = B_ANY_EVENT); + + + /* queue manipulation */ + /* call DoForEach to perform a function on each event in the */ + /* queue. Return an appropriate status defining an action to take */ + /* for that event. DoForEach is an atomic operation ensuring the */ + /* consistency of the queue during the call. */ + enum queue_action { + B_DONE = -1, + B_NO_ACTION = 0, + B_REMOVE_EVENT, + B_RESORT_QUEUE + }; + typedef queue_action (*for_each_hook)(media_timed_event *event, void *context); + + status_t DoForEach( + for_each_hook hook, + void *context, + bigtime_t eventTime = 0, + time_direction direction = B_ALWAYS, + bool inclusive = true, + int32 eventType = B_ANY_EVENT); + + + /* flushing events */ + /* the cleanup hook is called when events are flushed from the queue */ + /* and the cleanup is not B_NO_CLEANUP or B_RECYCLE_BUFFER */ + typedef void (*cleanup_hook)(const media_timed_event *event, void * context); + void SetCleanupHook(cleanup_hook hook, void *context); + status_t FlushEvents( + bigtime_t eventTime, + time_direction direction, + bool inclusive = true, + int32 eventType = B_ANY_EVENT); + + + private: + BTimedEventQueue( //unimplemented + const BTimedEventQueue & other); + BTimedEventQueue &operator =( //unimplemented + const BTimedEventQueue & other); + + + /* hide actual queue implementation */ + _event_queue_imp * fImp; + + /* Mmmh, stuffing! */ + virtual status_t _Reserved_BTimedEventQueue_0(void *, ...); + virtual status_t _Reserved_BTimedEventQueue_1(void *, ...); + virtual status_t _Reserved_BTimedEventQueue_2(void *, ...); + virtual status_t _Reserved_BTimedEventQueue_3(void *, ...); + virtual status_t _Reserved_BTimedEventQueue_4(void *, ...); + virtual status_t _Reserved_BTimedEventQueue_5(void *, ...); + virtual status_t _Reserved_BTimedEventQueue_6(void *, ...); + virtual status_t _Reserved_BTimedEventQueue_7(void *, ...); + virtual status_t _Reserved_BTimedEventQueue_8(void *, ...); + virtual status_t _Reserved_BTimedEventQueue_9(void *, ...); + virtual status_t _Reserved_BTimedEventQueue_10(void *, ...); + virtual status_t _Reserved_BTimedEventQueue_11(void *, ...); + virtual status_t _Reserved_BTimedEventQueue_12(void *, ...); + virtual status_t _Reserved_BTimedEventQueue_13(void *, ...); + virtual status_t _Reserved_BTimedEventQueue_14(void *, ...); + virtual status_t _Reserved_BTimedEventQueue_15(void *, ...); + virtual status_t _Reserved_BTimedEventQueue_16(void *, ...); + virtual status_t _Reserved_BTimedEventQueue_17(void *, ...); + virtual status_t _Reserved_BTimedEventQueue_18(void *, ...); + virtual status_t _Reserved_BTimedEventQueue_19(void *, ...); + virtual status_t _Reserved_BTimedEventQueue_20(void *, ...); + virtual status_t _Reserved_BTimedEventQueue_21(void *, ...); + virtual status_t _Reserved_BTimedEventQueue_22(void *, ...); + virtual status_t _Reserved_BTimedEventQueue_23(void *, ...); + + uint32 _reserved_timed_event_queue_[6]; +}; + +#endif diff --git a/headers/os/midi/Midi.h b/headers/os/midi/Midi.h new file mode 100644 index 0000000000..17783bc3e6 --- /dev/null +++ b/headers/os/midi/Midi.h @@ -0,0 +1,89 @@ +//----------------------------------------------------------------------------- +#ifndef _MIDI_H_ +#define _MIDI_H_ + +#include +#include + +class BMidiEvent; +class BList; + +class BMidi { +public: + BMidi(); + virtual ~BMidi(); + + virtual void NoteOff(uchar channel, uchar note, + uchar velocity, uint32 time = B_NOW); + virtual void NoteOn(uchar channel, uchar note, + uchar velocity, uint32 time = B_NOW); + virtual void KeyPressure(uchar channel, uchar note, + uchar pressure, uint32 time = B_NOW); + virtual void ControlChange(uchar channel, uchar control_number, + uchar control_value, uint32 time = B_NOW); + virtual void ProgramChange(uchar channel, uchar program_number, + uint32 time = B_NOW); + virtual void ChannelPressure(uchar channel, uchar pressure, + uint32 time = B_NOW); + virtual void PitchBend(uchar channel, uchar lsb, + uchar msb, uint32 time = B_NOW); + virtual void SystemExclusive(void * data, size_t data_length, + uint32 time = B_NOW); + virtual void SystemCommon(uchar status_byte, uchar data1, + uchar data2, uint32 time = B_NOW); + virtual void SystemRealTime(uchar status_byte, uint32 time = B_NOW); + virtual void TempoChange(int32 beats_per_minute, uint32 time = B_NOW); + virtual void AllNotesOff(bool just_channel = true, uint32 time = B_NOW); + + virtual status_t Start(); + virtual void Stop(); + + bool IsRunning() const; + void Connect(BMidi * to_object); + void Disconnect(BMidi * from_object); + bool IsConnected(BMidi * to_object) const; + BList * Connections() const; + void SnoozeUntil(uint32 time) const; + +protected: + void SprayNoteOff(uchar channel, uchar note, + uchar velocity, uint32 time) const; + void SprayNoteOn(uchar channel, uchar note, + uchar velocity, uint32 time) const; + void SprayKeyPressure(uchar channel, uchar note, + uchar pressure, uint32 time) const; + void SprayControlChange(uchar channel, uchar control_number, + uchar control_value, uint32 time) const; + void SprayProgramChange(uchar channel, uchar program_number, + uint32 time) const; + void SprayChannelPressure(uchar channel, uchar pressure, + uint32 time) const; + void SprayPitchBend(uchar channel, uchar lsb, + uchar msb, uint32 time) const; + void SpraySystemExclusive(void * data, size_t data_length, + uint32 time) const; + void SpraySystemCommon(uchar status_byte, uchar data1, + uchar data2, uint32 time) const; + void SpraySystemRealTime(uchar status_byte, uint32 time) const; + void SprayTempoChange(int32 beats_per_minute, uint32 time) const; + + bool KeepRunning(); + +private: + virtual void Run(); + void _Inflow(); + void _SprayEvent(BMidiEvent *) const; + static int32 _RunThread(void * data); + static int32 _InflowThread(void * data); + +private: + BList * _con_list; + thread_id _run_thread_id; + thread_id _inflow_thread_id; + port_id _inflow_port; + bool _is_running; + bool _is_inflowing; + bool _keep_running; +}; + +#endif //_MIDI_H_ diff --git a/headers/os/midi/MidiDefs.h b/headers/os/midi/MidiDefs.h new file mode 100644 index 0000000000..360b6b42bd --- /dev/null +++ b/headers/os/midi/MidiDefs.h @@ -0,0 +1,248 @@ +//----------------------------------------------------------------------------- +#ifndef _MIDI_DEFS_H_ +#define _MIDI_DEFS_H_ + +#include +#include + +#define B_NOW ((uint32)(system_time()/1000)) + +#define B_SYNTH_DIRECTORY B_BEOS_ETC_DIRECTORY +#define B_BIG_SYNTH_FILE "synth/big_synth.sy" +#define B_LITTLE_SYNTH_FILE "synth/little_synth.sy" + +typedef enum synth_mode { + B_NO_SYNTH, + B_BIG_SYNTH, + B_LITTLE_SYNTH, + B_DEFAULT_SYNTH, + B_SAMPLES_ONLY, +} synth_mode; + +enum { + B_BAD_INSTRUMENT = B_MIDI_ERROR_BASE + 0x100, + B_BAD_MIDI_DATA, + B_ALREADY_PAUSED, + B_ALREADY_RESUMED, + B_NO_SONG_PLAYING, + B_TOO_MANY_SONGS_PLAYING, +}; + +#ifndef uchar +typedef unsigned char uchar; +#endif + +#ifndef _MIDI_CONSTANTS_ +#define _MIDI_CONSTANTS_ + +const uchar B_NOTE_OFF = 0x80; +const uchar B_NOTE_ON = 0x90; +const uchar B_KEY_PRESSURE = 0xa0; +const uchar B_CONTROL_CHANGE = 0xb0; +const uchar B_PROGRAM_CHANGE = 0xc0; +const uchar B_CHANNEL_PRESSURE = 0xd0; +const uchar B_PITCH_BEND = 0xe0; + +const uchar B_SYS_EX_START = 0xf0; +const uchar B_MIDI_TIME_CODE = 0xf1; +const uchar B_SONG_POSITION = 0xf2; +const uchar B_SONG_SELECT = 0xf3; +const uchar B_CABLE_MESSAGE = 0xf5; +const uchar B_TUNE_REQUEST = 0xf6; +const uchar B_SYS_EX_END = 0xf7; +const uchar B_TIMING_CLOCK = 0xf8; +const uchar B_START = 0xfa; +const uchar B_CONTINUE = 0xfb; +const uchar B_STOP = 0xfc; +const uchar B_ACTIVE_SENSING = 0xfe; +const uchar B_SYSTEM_RESET = 0xff; + +const uchar B_MODULATION = 0x01; +const uchar B_BREATH_CONTROLLER = 0x02; +const uchar B_FOOT_CONTROLLER = 0x04; +const uchar B_PORTAMENTO_TIME = 0x05; +const uchar B_DATA_ENTRY = 0x06; +const uchar B_MAIN_VOLUME = 0x07; +const uchar B_MIDI_BALANCE = 0x08; +const uchar B_PAN = 0x0a; +const uchar B_EXPRESSION_CTRL = 0x0b; +const uchar B_GENERAL_CTRL_1 = 0x10; +const uchar B_GENERAL_CTRL_2 = 0x11; +const uchar B_GENERAL_CTRL_3 = 0x12; +const uchar B_GENERAL_CTRL_4 = 0x13; +const uchar B_SUSTAIN_PEDAL = 0x40; +const uchar B_PORTAMENTO = 0x41; +const uchar B_SOSTENUTO = 0x42; +const uchar B_SOFT_PEDAL = 0x43; +const uchar B_HOLD_2 = 0x45; +const uchar B_GENERAL_CTRL_5 = 0x50; +const uchar B_GENERAL_CTRL_6 = 0x51; +const uchar B_GENERAL_CTRL_7 = 0x52; +const uchar B_GENERAL_CTRL_8 = 0x53; +const uchar B_EFFECTS_DEPTH = 0x5b; +const uchar B_TREMOLO_DEPTH = 0x5c; +const uchar B_CHORUS_DEPTH = 0x5d; +const uchar B_CELESTE_DEPTH = 0x5e; +const uchar B_PHASER_DEPTH = 0x5f; +const uchar B_DATA_INCREMENT = 0x60; +const uchar B_DATA_DECREMENT = 0x61; +const uchar B_RESET_ALL_CONTROLLERS = 0x79; +const uchar B_LOCAL_CONTROL = 0x7a; +const uchar B_ALL_NOTES_OFF = 0x7b; +const uchar B_OMNI_MODE_OFF = 0x7c; +const uchar B_OMNI_MODE_ON = 0x7d; +const uchar B_MONO_MODE_ON = 0x7e; +const uchar B_POLY_MODE_ON = 0x7f; + +const uchar B_TEMPO_CHANGE = 0x51; + +#endif + +typedef enum midi_axe { + B_ACOUSTIC_GRAND=0, + B_BRIGHT_GRAND, + B_ELECTRIC_GRAND, + B_HONKY_TONK, + B_ELECTRIC_PIANO_1, + B_ELECTRIC_PIANO_2, + B_HARPSICHORD, + B_CLAVICHORD, + B_CELESTA, + B_GLOCKENSPIEL, + B_MUSIC_BOX, + B_VIBRAPHONE, + B_MARIMBA, + B_XYLOPHONE, + B_TUBULAR_BELLS, + B_DULCIMER, + B_DRAWBAR_ORGAN, + B_PERCUSSIVE_ORGAN, + B_ROCK_ORGAN, + B_CHURCH_ORGAN, + B_REED_ORGAN, + B_ACCORDION, + B_HARMONICA, + B_TANGO_ACCORDION, + B_ACOUSTIC_GUITAR_NYLON, + B_ACOUSTIC_GUITAR_STEEL, + B_ELECTRIC_GUITAR_JAZZ, + B_ELECTRIC_GUITAR_CLEAN, + B_ELECTRIC_GUITAR_MUTED, + B_OVERDRIVEN_GUITAR, + B_DISTORTION_GUITAR, + B_GUITAR_HARMONICS, + B_ACOUSTIC_BASS, + B_ELECTRIC_BASS_FINGER, + B_ELECTRIC_BASS_PICK, + B_FRETLESS_BASS, + B_SLAP_BASS_1, + B_SLAP_BASS_2, + B_SYNTH_BASS_1, + B_SYNTH_BASS_2, + B_VIOLIN, + B_VIOLA, + B_CELLO, + B_CONTRABASS, + B_TREMOLO_STRINGS, + B_PIZZICATO_STRINGS, + B_ORCHESTRAL_STRINGS, + B_TIMPANI, + B_STRING_ENSEMBLE_1, + B_STRING_ENSEMBLE_2, + B_SYNTH_STRINGS_1, + B_SYNTH_STRINGS_2, + B_VOICE_AAH, + B_VOICE_OOH, + B_SYNTH_VOICE, + B_ORCHESTRA_HIT, + B_TRUMPET, + B_TROMBONE, + B_TUBA, + B_MUTED_TRUMPET, + B_FRENCH_HORN, + B_BRASS_SECTION, + B_SYNTH_BRASS_1, + B_SYNTH_BRASS_2, + B_SOPRANO_SAX, + B_ALTO_SAX, + B_TENOR_SAX, + B_BARITONE_SAX, + B_OBOE, + B_ENGLISH_HORN, + B_BASSOON, + B_CLARINET, + B_PICCOLO, + B_FLUTE, + B_RECORDER, + B_PAN_FLUTE, + B_BLOWN_BOTTLE, + B_SHAKUHACHI, + B_WHISTLE, + B_OCARINA, + B_LEAD_1, + B_SQUARE_WAVE = B_LEAD_1, + B_LEAD_2, + B_SAWTOOTH_WAVE = B_LEAD_2, + B_LEAD_3, + B_CALLIOPE = B_LEAD_3, + B_LEAD_4, + B_CHIFF = B_LEAD_4, + B_LEAD_5, + B_CHARANG = B_LEAD_5, + B_LEAD_6, + B_VOICE = B_LEAD_6, + B_LEAD_7, + B_FIFTHS = B_LEAD_7, + B_LEAD_8, + B_BASS_LEAD = B_LEAD_8, + B_PAD_1, + B_NEW_AGE = B_PAD_1, + B_PAD_2, + B_WARM = B_PAD_2, + B_PAD_3, + B_POLYSYNTH = B_PAD_3, + B_PAD_4, + B_CHOIR = B_PAD_4, + B_PAD_5, + B_BOWED = B_PAD_5, + B_PAD_6, + B_METALLIC = B_PAD_6, + B_PAD_7, + B_HALO = B_PAD_7, + B_PAD_8, + B_SWEEP = B_PAD_8, + B_FX_1, + B_FX_2, + B_FX_3, + B_FX_4, + B_FX_5, + B_FX_6, + B_FX_7, + B_FX_8, + B_SITAR, + B_BANJO, + B_SHAMISEN, + B_KOTO, + B_KALIMBA, + B_BAGPIPE, + B_FIDDLE, + B_SHANAI, + B_TINKLE_BELL, + B_AGOGO, + B_STEEL_DRUMS, + B_WOODBLOCK, + B_TAIKO_DRUMS, + B_MELODIC_TOM, + B_SYNTH_DRUM, + B_REVERSE_CYMBAL, + B_FRET_NOISE, + B_BREATH_NOISE, + B_SEASHORE, + B_BIRD_TWEET, + B_TELEPHONE, + B_HELICOPTER, + B_APPLAUSE, + B_GUNSHOT +} midi_axe; + +#endif //_MIDI_DEFS_H_ diff --git a/headers/os/midi/MidiStore.h b/headers/os/midi/MidiStore.h new file mode 100644 index 0000000000..9c16a068e1 --- /dev/null +++ b/headers/os/midi/MidiStore.h @@ -0,0 +1,76 @@ +//----------------------------------------------------------------------------- +#ifndef _MIDI_STORE_H_ +#define _MIDI_STORE_H_ + +#include +#include + +struct entry_ref; +class BMidiEvent; +class BFile; + +class BMidiStore : public BMidi { +public: +BMidiStore(); +virtual ~BMidiStore(); + + virtual void NoteOff(uchar channel, uchar note, + uchar velocity, uint32 time = B_NOW); + virtual void NoteOn(uchar channel, uchar note, + uchar velocity, uint32 time = B_NOW); + virtual void KeyPressure(uchar channel, uchar note, + uchar pressure, uint32 time = B_NOW); + virtual void ControlChange(uchar channel, uchar control_number, + uchar control_value, uint32 time = B_NOW); + virtual void ProgramChange(uchar channel, uchar program_number, + uint32 time = B_NOW); + virtual void ChannelPressure(uchar channel, uchar pressure, + uint32 time = B_NOW); + virtual void PitchBend(uchar channel, uchar lsb, + uchar msb, uint32 time = B_NOW); + virtual void SystemExclusive(void * data, size_t data_length, + uint32 time = B_NOW); + virtual void SystemCommon(uchar status_byte, uchar data1, + uchar data2, uint32 time = B_NOW); + virtual void SystemRealTime(uchar status_byte, uint32 time = B_NOW); + virtual void TempoChange(int32 beats_per_minute, uint32 time = B_NOW); + virtual void AllNotesOff(bool just_channel = true, uint32 time = B_NOW); + + status_t Import(const entry_ref * ref); + status_t Export(const entry_ref * ref, int32 format); + + void SortEvents(bool force = false); + uint32 CountEvents() const; + uint32 CurrentEvent() const; + void SetCurrentEvent(uint32 event_number); + uint32 DeltaOfEvent(uint32 event_number) const; + uint32 EventAtDelta(uint32 time) const; + uint32 BeginTime() const; + void SetTempo(int32 beats_per_minute); + int32 Tempo() const; + +private: + virtual void Run(); + void _RunThread(); + uint8* _DecodeTrack(uint8 *); + void _DecodeFormat0Tracks(uint8 *, uint16, uint32); + void _DecodeFormat1Tracks(uint8 *, uint16, uint32); + void _DecodeFormat2Tracks(uint8 *, uint16, uint32); + void _EncodeFormat0Tracks(uint8 *); + void _EncodeFormat1Tracks(uint8 *); + void _EncodeFormat2Tracks(uint8 *); + void _ReadEvent(uint8, uint8 **, uint8 *, BMidiEvent *); + void _WriteEvent(BMidiEvent *); + uint32 _ReadVarLength(uint8 **, uint8 *); + void _WriteVarLength(uint32); + static int _CompareEvents(const void *, const void *); + +private: + BList * _evt_list; + uint32 _tempo; + uint32 _cur_evt; + uint32 _start_time; + uint32 _ticks_per_beat; +}; + +#endif _MIDI_STORE_H_ diff --git a/headers/os/midi/MidiText.h b/headers/os/midi/MidiText.h new file mode 100644 index 0000000000..18588f89a2 --- /dev/null +++ b/headers/os/midi/MidiText.h @@ -0,0 +1,43 @@ +//----------------------------------------------------------------------------- +#ifndef _MIDI_TEXT_H_ +#define _MIDI_TEXT_H_ + +#include + +class BMidiText : public BMidi { +public: + BMidiText(); + virtual ~BMidiText(); + + virtual void NoteOff(uchar channel, uchar note, + uchar velocity, uint32 time = B_NOW); + virtual void NoteOn(uchar channel, uchar note, + uchar velocity, uint32 time = B_NOW); + virtual void KeyPressure(uchar channel, uchar note, + uchar pressure, uint32 time = B_NOW); + virtual void ControlChange(uchar channel, uchar control_number, + uchar control_value, uint32 time = B_NOW); + virtual void ProgramChange(uchar channel, uchar program_number, + uint32 time = B_NOW); + virtual void ChannelPressure(uchar channel, uchar pressure, + uint32 time = B_NOW); + virtual void PitchBend(uchar channel, uchar lsb, + uchar msb, uint32 time = B_NOW); + virtual void SystemExclusive(void * data, size_t data_length, + uint32 time = B_NOW); + virtual void SystemCommon(uchar status_byte, uchar data1, + uchar data2, uint32 time = B_NOW); + virtual void SystemRealTime(uchar status_byte, uint32 time = B_NOW); + virtual void TempoChange(int32 beats_per_minute, uint32 time = B_NOW); + virtual void AllNotesOff(bool just_channel = true, uint32 time = B_NOW); + + void ResetTimer(bool start = false); + +private: + int32 _start_time; + +private: + void _PrintTime(); +}; + +#endif _MIDI_TEXT_H_ diff --git a/headers/os/storage/Directory.h b/headers/os/storage/Directory.h new file mode 100644 index 0000000000..5e71e40336 --- /dev/null +++ b/headers/os/storage/Directory.h @@ -0,0 +1,109 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file Directory.h + BDirectory interface declaration. +*/ + +#ifndef __sk_directory_h__ +#define __sk_directory_h__ + +#include +#include +#include +#include + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS { +#endif + +class BSymLink; + +/*! + \class BDirectory + \brief A directory in the filesystem + + Provides an interface for manipulating directories and their contents. + + \author Ingo Weinhold + \author Tyler Dauwalder + + \version 0.0.0 +*/ +class BDirectory : public BNode, public BEntryList { +public: + BDirectory(); + BDirectory(const BDirectory &dir); + BDirectory(const entry_ref *ref); + BDirectory(const node_ref *nref); + BDirectory(const BEntry *entry); + BDirectory(const char *path); + BDirectory(const BDirectory *dir, const char *path); + + virtual ~BDirectory(); + + status_t SetTo(const entry_ref *ref); + status_t SetTo(const node_ref *nref); + status_t SetTo(const BEntry *entry); + status_t SetTo(const char *path); + status_t SetTo(const BDirectory *dir, const char *path); + + status_t GetEntry(BEntry *entry) const; + + bool IsRootDirectory() const; + + status_t FindEntry(const char *path, BEntry *entry, + bool traverse = false) const; + + bool Contains(const char *path, int32 nodeFlags = B_ANY_NODE) const; + bool Contains(const BEntry *entry, int32 nodeFlags = B_ANY_NODE) const; + + status_t GetStatFor(const char *path, struct stat *st) const; + + virtual status_t GetNextEntry(BEntry *entry, bool traverse = false); + virtual status_t GetNextRef(entry_ref *ref); + virtual int32 GetNextDirents(dirent *buf, size_t bufSize, + int32 count = INT_MAX); + virtual status_t Rewind(); + virtual int32 CountEntries(); + + status_t CreateDirectory(const char *path, BDirectory *dir); + status_t CreateFile(const char *path, BFile *file, + bool failIfExists = false); + status_t CreateSymLink(const char *path, const char *linkToPath, + BSymLink *link); + + BDirectory &operator=(const BDirectory &dir); + +private: + virtual void _ReservedDirectory1(); + virtual void _ReservedDirectory2(); + virtual void _ReservedDirectory3(); + virtual void _ReservedDirectory4(); + virtual void _ReservedDirectory5(); + virtual void _ReservedDirectory6(); + +private: + virtual void close_fd(); + StorageKit::FileDescriptor get_fd() const; + +private: + uint32 _reservedData[7]; + StorageKit::FileDescriptor fDirFd; + + friend class BEntry; +}; + + +// C functions + +status_t create_directory(const char *path, mode_t mode); + + +#ifdef USE_OPENBEOS_NAMESPACE +}; // namespace OpenBeOS +#endif + +#endif // __sk_directory_h__ diff --git a/headers/os/storage/Entry.h b/headers/os/storage/Entry.h new file mode 100644 index 0000000000..ac25dbf2c6 --- /dev/null +++ b/headers/os/storage/Entry.h @@ -0,0 +1,120 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file Entry.h + BEntry and entry_ref interface declarations. +*/ +#ifndef __sk_entry_h__ +#define __sk_entry_h__ + +#include +#include +#include + +#include +#include + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS { +#endif + +class BDirectory; +class BPath; + +struct entry_ref { + entry_ref(); + entry_ref(dev_t dev, ino_t dir, const char *name); + entry_ref(const entry_ref &ref); + ~entry_ref(); + + status_t set_name(const char *name); + + bool operator==(const entry_ref &ref) const; + bool operator!=(const entry_ref &ref) const; + entry_ref &operator=(const entry_ref &ref); + + dev_t device; + ino_t directory; + char *name; +}; + +class BEntry : public BStatable { +public: + BEntry(); + BEntry(const BDirectory *dir, const char *path, bool traverse = false); + BEntry(const entry_ref *ref, bool traverse = false); + BEntry(const char *path, bool traverse = false); + BEntry(const BEntry &entry); + virtual ~BEntry(); + + status_t InitCheck() const; + bool Exists() const; + + virtual status_t GetStat(struct stat *st) const; + + status_t SetTo(const BDirectory *dir, const char *path, + bool traverse = false); + status_t SetTo(const entry_ref *ref, bool traverse = false); + status_t SetTo(const char *path, bool traverse = false); + void Unset(); + + status_t GetRef(entry_ref *ref) const; + status_t GetPath(BPath *path) const; + status_t GetParent(BEntry *entry) const; + status_t GetParent(BDirectory *dir) const; + status_t GetName(char *buffer) const; + + status_t Rename(const char *path, bool clobber = false); + status_t MoveTo(BDirectory *dir, const char *path = NULL, + bool clobber = false); + status_t Remove(); + + bool operator==(const BEntry &item) const; + bool operator!=(const BEntry &item) const; + + BEntry &operator=(const BEntry &item); + +private: + virtual void _PennyEntry1(); + virtual void _PennyEntry2(); + virtual void _PennyEntry3(); + virtual void _PennyEntry4(); + virtual void _PennyEntry5(); + virtual void _PennyEntry6(); + + /*! Currently unused. */ + uint32 _pennyData[4]; + + /*! BEntry implementation of BStatable::set_stat() */ + virtual status_t set_stat(struct stat &st, uint32 what); + + status_t set(StorageKit::FileDescriptor dir, const char *path, + bool traverse); + + /*! File descriptor for the entry's parent directory. */ + StorageKit::FileDescriptor fDirFd; + + /*! Leaf name of the entry. */ + char *fName; + + /*! The object's initialization status. */ + status_t fCStatus; + + status_t set_name(const char *name); + + void Dump(const char *name = NULL); +}; + +// C functions + +status_t get_ref_for_path(const char *path, entry_ref *ref); +bool operator<(const entry_ref &a, const entry_ref &b); + + +#ifdef USE_OPENBEOS_NAMESPACE +}; // namespace OpenBeOS +#endif + +#endif // __sk_entry_h__ diff --git a/headers/os/storage/EntryList.h b/headers/os/storage/EntryList.h new file mode 100644 index 0000000000..19afca2c9e --- /dev/null +++ b/headers/os/storage/EntryList.h @@ -0,0 +1,60 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file EntryList.h + BEntryList interface declaration. +*/ + +#ifndef __sk_entry_list_h__ +#define __sk_entry_list_h__ + +#include +#include + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS { +#endif + +// Forward declarations +class BEntry; +struct entry_ref; + +//! Interface for iterating through a list of filesystem entries +/*! Defines a general interface for iterating through a list of entries (i.e. + files in a folder + + @author Tyler Dauwalder + @author Be Inc. + @version 0.0.0 +*/ +class BEntryList { +public: + BEntryList(); + virtual ~BEntryList(); + + virtual status_t GetNextEntry(BEntry *entry, bool traverse = false) = 0; + virtual status_t GetNextRef(entry_ref *ref) = 0; + virtual int32 GetNextDirents(struct dirent *buf, size_t length, + int32 count = INT_MAX) = 0; + virtual status_t Rewind() = 0; + virtual int32 CountEntries() = 0; + +private: + virtual void _ReservedEntryList1(); + virtual void _ReservedEntryList2(); + virtual void _ReservedEntryList3(); + virtual void _ReservedEntryList4(); + virtual void _ReservedEntryList5(); + virtual void _ReservedEntryList6(); + virtual void _ReservedEntryList7(); + virtual void _ReservedEntryList8(); + +}; + +#ifdef USE_OPENBEOS_NAMESPACE +}; // namespace OpenBeOS +#endif + +#endif // __sk_entry_list_h__ diff --git a/headers/os/storage/File.h b/headers/os/storage/File.h new file mode 100644 index 0000000000..c01dd63306 --- /dev/null +++ b/headers/os/storage/File.h @@ -0,0 +1,85 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file File.h + BFile interface declaration. +*/ +#ifndef __sk_file_h__ +#define __sk_file_h__ + +#include +#include +#include + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS { +#endif + +/*! + \class BFile + \brief BFile is a wrapper class for common operations on files providing + access to the file's content data and its attributes. + + A BFile represents a file in some file system. It implements the + BPositionIO interface and thus the methods to read from and write to the + file, and is derived of BNode to provide access to the file's attributes. + + \author Ingo Weinhold + + \version 0.0.0 +*/ +class BFile : public BNode, public BPositionIO { +public: + BFile(); + BFile(const BFile &file); + BFile(const entry_ref *ref, uint32 openMode); + BFile(const BEntry *entry, uint32 openMode); + BFile(const char *path, uint32 openMode); + BFile(BDirectory *dir, const char *path, uint32 openMode); + virtual ~BFile(); + + status_t SetTo(const entry_ref *ref, uint32 openMode); + status_t SetTo(const BEntry *entry, uint32 openMode); + status_t SetTo(const char *path, uint32 openMode); + status_t SetTo(const BDirectory *dir, const char *path, uint32 openMode); + + bool IsReadable() const; + bool IsWritable() const; + + virtual ssize_t Read(void *buffer, size_t size); + virtual ssize_t ReadAt(off_t location, void *buffer, size_t size); + virtual ssize_t Write(const void *buffer, size_t size); + virtual ssize_t WriteAt(off_t location, const void *buffer, size_t size); + + virtual off_t Seek(off_t offset, uint32 seekMode); + virtual off_t Position() const; + + virtual status_t SetSize(off_t size); + + BFile &operator=(const BFile &file); + +private: + virtual void _ReservedFile1(); + virtual void _ReservedFile2(); + virtual void _ReservedFile3(); + virtual void _ReservedFile4(); + virtual void _ReservedFile5(); + virtual void _ReservedFile6(); + + uint32 _reservedData[8]; + +private: + StorageKit::FileDescriptor get_fd() const; + +private: + //! The file's open mode. + uint32 fMode; +}; + +#ifdef USE_OPENBEOS_NAMESPACE +}; // namespace OpenBeOS +#endif + +#endif // __sk_file_h__ diff --git a/headers/os/storage/FindDirectory.h b/headers/os/storage/FindDirectory.h new file mode 100644 index 0000000000..41fc2d5089 --- /dev/null +++ b/headers/os/storage/FindDirectory.h @@ -0,0 +1,135 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file FindDirectory.h + Declarations of find_directory() functions and associated types. +*/ + +#ifndef __sk_find_directory_h__ +#define __sk_find_directory_h__ + +#include + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS { +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + /* --- + Per volume directories. When asking for these + directories, a volume must be specified, or the call will assume + the boot volume. + --- */ + + B_DESKTOP_DIRECTORY = 0, + B_TRASH_DIRECTORY, + + /* --- + BeOS directories. These are mostly accessed read-only. + --- */ + + B_BEOS_DIRECTORY = 1000, + B_BEOS_SYSTEM_DIRECTORY, + B_BEOS_ADDONS_DIRECTORY, + B_BEOS_BOOT_DIRECTORY, + B_BEOS_FONTS_DIRECTORY, + B_BEOS_LIB_DIRECTORY, + B_BEOS_SERVERS_DIRECTORY, + B_BEOS_APPS_DIRECTORY, + B_BEOS_BIN_DIRECTORY, + B_BEOS_ETC_DIRECTORY, + B_BEOS_DOCUMENTATION_DIRECTORY, + B_BEOS_PREFERENCES_DIRECTORY, + B_BEOS_TRANSLATORS_DIRECTORY, + B_BEOS_MEDIA_NODES_DIRECTORY, + B_BEOS_SOUNDS_DIRECTORY, + + /* --- + Common directories, shared among all users. + --- */ + + B_COMMON_DIRECTORY = 2000, + B_COMMON_SYSTEM_DIRECTORY, + B_COMMON_ADDONS_DIRECTORY, + B_COMMON_BOOT_DIRECTORY, + B_COMMON_FONTS_DIRECTORY, + B_COMMON_LIB_DIRECTORY, + B_COMMON_SERVERS_DIRECTORY, + B_COMMON_BIN_DIRECTORY, + B_COMMON_ETC_DIRECTORY, + B_COMMON_DOCUMENTATION_DIRECTORY, + B_COMMON_SETTINGS_DIRECTORY, + B_COMMON_DEVELOP_DIRECTORY, + B_COMMON_LOG_DIRECTORY, + B_COMMON_SPOOL_DIRECTORY, + B_COMMON_TEMP_DIRECTORY, + B_COMMON_VAR_DIRECTORY, + B_COMMON_TRANSLATORS_DIRECTORY, + B_COMMON_MEDIA_NODES_DIRECTORY, + B_COMMON_SOUNDS_DIRECTORY, + + + /* --- + User directories. These are interpreted in the context + of the user making the find_directory call. + --- */ + + B_USER_DIRECTORY = 3000, + B_USER_CONFIG_DIRECTORY, + B_USER_ADDONS_DIRECTORY, + B_USER_BOOT_DIRECTORY, + B_USER_FONTS_DIRECTORY, + B_USER_LIB_DIRECTORY, + B_USER_SETTINGS_DIRECTORY, + B_USER_DESKBAR_DIRECTORY, + B_USER_PRINTERS_DIRECTORY, + B_USER_TRANSLATORS_DIRECTORY, + B_USER_MEDIA_NODES_DIRECTORY, + B_USER_SOUNDS_DIRECTORY, + + /* --- + Global directories. + --- */ + + B_APPS_DIRECTORY = 4000, + B_PREFERENCES_DIRECTORY, + B_UTILITIES_DIRECTORY + +} directory_which; + +/* --- + The C interface +--- */ + +status_t find_directory(directory_which which, dev_t volume, bool createIt, + char *pathString, int32 length); + +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus + +class BVolume; +class BPath; + +/* --- + C++ interface +--- */ + +status_t find_directory(directory_which which, BPath *path, + bool createIt = false, BVolume *volume = NULL); + +#endif + +#ifdef USE_OPENBEOS_NAMESPACE +}; // namespace OpenBeOS +#endif + +#endif // __sk_find_directory_h__ diff --git a/headers/os/storage/Mime.h b/headers/os/storage/Mime.h new file mode 100644 index 0000000000..bfb1c79ad9 --- /dev/null +++ b/headers/os/storage/Mime.h @@ -0,0 +1,45 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file Mime.h + Mime type C functions interface declarations. +*/ +#ifndef _sk_mime_h_ +#define _sk_mime_h_ + +#include +#include + +// C functions + +#ifdef __cplusplus +extern "C" { +#endif + +int update_mime_info(const char *path, int recursive, int synchronous, + int force); + +status_t create_app_meta_mime(const char *path, int recursive, int synchronous, + int force); + +status_t get_device_icon(const char *dev, void *icon, int32 size); + +static const uint32 B_MIME_STRING_TYPE = 'MIMS'; + +enum icon_size { + B_LARGE_ICON = 32, + B_MINI_ICON = 16 +}; + +#ifdef __cplusplus +} +#endif + +// include the C++ API +#ifdef __cplusplus +#include +#endif + +#endif // _sk_mime_h_ diff --git a/headers/os/storage/MimeType.h b/headers/os/storage/MimeType.h new file mode 100644 index 0000000000..bb26090d49 --- /dev/null +++ b/headers/os/storage/MimeType.h @@ -0,0 +1,192 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file MimeType.h + BMimeType interface declarations. +*/ +#ifndef _sk_mime_type_h_ +#define _sk_mime_type_h_ + +#include +#include + +#include +#include +#include +#include + +class BBitmap; +class BResources; +class BAppFileInfo; +class BMessenger; + +enum app_verb { + B_OPEN +}; + +extern const char *B_APP_MIME_TYPE; // platform dependent +extern const char *B_PEF_APP_MIME_TYPE; // "application/x-be-executable" +extern const char *B_PE_APP_MIME_TYPE; // "application/x-vnd.be-peexecutable" +extern const char *B_ELF_APP_MIME_TYPE; // "application/x-vnd.be-elfexecutable" +extern const char *B_RESOURCE_MIME_TYPE;// "application/x-be-resource" +extern const char *B_FILE_MIME_TYPE; // "application/octet-stream" + +/* ------------------------------------------------------------- */ + +enum { + B_META_MIME_CHANGED = 'MMCH' +}; + +enum { + B_ICON_CHANGED = 0x00000001, + B_PREFERRED_APP_CHANGED = 0x00000002, + B_ATTR_INFO_CHANGED = 0x00000004, + B_FILE_EXTENSIONS_CHANGED = 0x00000008, + B_SHORT_DESCRIPTION_CHANGED = 0x00000010, + B_LONG_DESCRIPTION_CHANGED = 0x00000020, + B_ICON_FOR_TYPE_CHANGED = 0x00000040, + B_APP_HINT_CHANGED = 0x00000080, + B_MIME_TYPE_CREATED = 0x00000100, + B_MIME_TYPE_DELETED = 0x00000200, + B_SNIFFER_RULE_CHANGED = 0x00000400, + + B_EVERYTHING_CHANGED = (int)0xFFFFFFFF +}; + +/* ------------------------------------------------------------- */ + +//! File typing functionality. +/*! The BMimeType class provides access to the file typing system, which + provides the following functionality: + - Basic MIME string manipulation + - Access to file type information in the MIME database + - Ways to receive notifications when parts of the MIME database are updated + - Methods to determine/help determine the types of untyped files + + \author Tyler Dauwalder + \author Ingo Weinhold + \version 0.0.0 +*/ +class BMimeType { +public: + BMimeType(); + BMimeType(const char *mimeType); + virtual ~BMimeType(); + + status_t SetTo(const char *mimeType); + void Unset(); + status_t InitCheck() const; + + /* these functions simply perform string manipulations*/ + const char *Type() const; + bool IsValid() const; + bool IsSupertypeOnly() const; + bool IsInstalled() const; + status_t GetSupertype(BMimeType *superType) const; + + bool operator==(const BMimeType &type) const; + bool operator==(const char *type) const; + + bool Contains(const BMimeType *type) const; + + /* These functions are for managing data in the meta mime file*/ + status_t Install(); + status_t Delete(); + status_t GetIcon(BBitmap *icon, icon_size size) const; + status_t GetPreferredApp(char *signature, app_verb verb = B_OPEN) const; + status_t GetAttrInfo(BMessage *info) const; + status_t GetFileExtensions(BMessage *extensions) const; + status_t GetShortDescription(char *description) const; + status_t GetLongDescription(char *description) const; + status_t GetSupportingApps(BMessage *signatures) const; + + status_t SetIcon(const BBitmap *icon, icon_size size); + status_t SetPreferredApp(const char *signature, app_verb verb = B_OPEN); + status_t SetAttrInfo(const BMessage *info); + status_t SetFileExtensions(const BMessage *extensions); + status_t SetShortDescription(const char *description); + status_t SetLongDescription(const char *description); + + static status_t GetInstalledSupertypes(BMessage *super_types); + static status_t GetInstalledTypes(BMessage *types); + static status_t GetInstalledTypes(const char *super_type, + BMessage *subtypes); + static status_t GetWildcardApps(BMessage *wild_ones); + static bool IsValid(const char *mimeType); + + status_t GetAppHint(entry_ref *ref) const; + status_t SetAppHint(const entry_ref *ref); + + /* for application signatures only.*/ + status_t GetIconForType(const char *type, BBitmap *icon, + icon_size which) const; + status_t SetIconForType(const char *type, const BBitmap *icon, + icon_size which); + + /* sniffer rule manipulation */ + status_t GetSnifferRule(BString *result) const; + status_t SetSnifferRule(const char *); + static status_t CheckSnifferRule(const char *rule, BString *parseError); + + /* calls to ask the sniffer to identify the MIME type of a file or data in + memory */ + static status_t GuessMimeType(const entry_ref *file, BMimeType *result); + static status_t GuessMimeType(const void *buffer, int32 length, + BMimeType *result); + static status_t GuessMimeType(const char *filename, BMimeType *result); + + static status_t StartWatching(BMessenger target); + static status_t StopWatching(BMessenger target); + + /* Deprecated Use SetTo instead. */ + status_t SetType(const char *mimeType); + +private: + BMimeType(const char *mimeType, const char *mimePath); + // if mimePath is NULL, defaults to "/boot/home/config/settings/beos_mime/" + + friend class MimeTypeTest; + +// Uncomment, when needed... + +// friend class BAppFileInfo; +// friend class BRoster; +// friend class TRosterApp; +// friend class TMimeWorker; + +// friend status_t _update_mime_info_(const char *, int32); +// friend status_t _real_update_app_(BAppFileInfo *, const char *, bool); + +// static void _set_local_dispatch_target_(BMessenger *, void (*)(BMessage *)); +// void _touch_(); + + virtual void _ReservedMimeType1(); + virtual void _ReservedMimeType2(); + virtual void _ReservedMimeType3(); + + BMimeType &operator=(const BMimeType &); + BMimeType(const BMimeType &); + +/* + void InitData(const char *type); + status_t OpenFile(bool create_file = false, dev_t dev = -1) const; + status_t CloseFile() const; + status_t GetSupportedTypes(BMessage *types); + status_t SetSupportedTypes(const BMessage *types); + void MimeChanged(int32 w, const char *type = NULL, + bool large = true) const; +*/ + + char *fType; + BFile *fMeta; + char *fMimePath; // Was: "void *_unused;" + entry_ref fRef; + int fWhere; + status_t fCStatus; + uint32 _reserved[3]; +}; + + +#endif // _sk_mime_type_h_ diff --git a/headers/os/storage/Node.h b/headers/os/storage/Node.h new file mode 100644 index 0000000000..505721c5ce --- /dev/null +++ b/headers/os/storage/Node.h @@ -0,0 +1,137 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file Node.h + BNode and node_ref interface declarations. +*/ + +#ifndef __sk_node_h__ +#define __sk_node_h__ + +#include +#include + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS { +#endif + +//--------------------------------------------------------------- +// node_ref +//--------------------------------------------------------------- + +//! Reference structure to a particular vnode on a particular device +/*! node_ref - A node reference. + + @author Tyler Dauwalder + @author Be Inc. + @version 0.0.0 +*/ +struct node_ref { + node_ref(); + node_ref(const node_ref &ref); + + bool operator==(const node_ref &ref) const; + bool operator!=(const node_ref &ref) const; + node_ref& operator=(const node_ref &ref); + + dev_t device; + ino_t node; +}; + + +//--------------------------------------------------------------- +// BNode +//--------------------------------------------------------------- + +//! A BNode represents a chunk of data in the filesystem. +/*! The BNode class provides an interface for manipulating the data and attributes + belonging to filesystem entries. The BNode is unaware of the name that refers + to it in the filesystem (i.e. its entry); a BNode is solely concerned with + the entry's data and attributes. + + + @author Tyler Dauwalder + @version 0.0.0 + +*/ +class BNode : public BStatable { +public: + + BNode(); + BNode(const entry_ref *ref); + BNode(const BEntry *entry); + BNode(const char *path); + BNode(const BDirectory *dir, const char *path); + BNode(const BNode &node); + virtual ~BNode(); + + status_t InitCheck() const; + + virtual status_t GetStat(struct stat *st) const; + + status_t SetTo(const entry_ref *ref); + status_t SetTo(const BEntry *entry); + status_t SetTo(const char *path); + status_t SetTo(const BDirectory *dir, const char *path); + void Unset(); + + status_t Lock(); + status_t Unlock(); + + status_t Sync(); + + ssize_t WriteAttr(const char *name, type_code type, off_t offset, + const void *buffer, size_t len); + ssize_t ReadAttr(const char *name, type_code type, off_t offset, + void *buffer, size_t len) const; + status_t RemoveAttr(const char *name); + status_t RenameAttr(const char *oldname, const char *newname); + status_t GetAttrInfo(const char *name, struct attr_info *info) const; + status_t GetNextAttrName(char *buffer); + status_t RewindAttrs(); + status_t WriteAttrString(const char *name, const BString *data); + status_t ReadAttrString(const char *name, BString *result) const; + + BNode& operator=(const BNode &node); + bool operator==(const BNode &node) const; + bool operator!=(const BNode &node) const; + + int Dup(); // This should be "const" but R5's is not... Ugggh. + +private: + friend class BFile; + friend class BDirectory; + friend class BSymLink; + + virtual void _ReservedNode1(); + virtual void _ReservedNode2(); + virtual void _ReservedNode3(); + virtual void _ReservedNode4(); + virtual void _ReservedNode5(); + virtual void _ReservedNode6(); + + uint32 rudeData[4]; + +private: + status_t set_fd(StorageKit::FileDescriptor fd); + virtual void close_fd(); + void set_status(status_t newStatus); + + virtual status_t set_stat(struct stat &st, uint32 what); + + StorageKit::FileDescriptor fFd; + StorageKit::FileDescriptor fAttrFd; + status_t fCStatus; + + status_t InitAttrDir(); +}; + + + +#ifdef USE_OPENBEOS_NAMESPACE +}; // namespace OpenBeOS +#endif + +#endif // __sk_node_h__ \ No newline at end of file diff --git a/headers/os/storage/NodeInfo.h b/headers/os/storage/NodeInfo.h new file mode 100644 index 0000000000..8e0df5afee --- /dev/null +++ b/headers/os/storage/NodeInfo.h @@ -0,0 +1,117 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file NodeInfo.h + BNodeInfo interface declaration. +*/ + +#ifndef __sk_node_info_h__ +#define __sk_node_info_h__ + +#ifndef _BE_BUILD_H +#include +#endif +#include +#include +#include +#include +#include + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS { +#endif // USE_OPENBEOS_NAMESPACE + +class BBitmap; +class BResources; + + +//! BNodeInfo provides file type information +/*! BNodeInfo provides a nice wrapper to all sorts of usefull meta data. + * Like it's mime type, the files icon and the application which will load + * the file. + * + * @see MIT + * @author Michael Lloyd Lee + * @author Be Inc + * @version 0 + */ +class BNodeInfo { +public: + + //! Uninitialized Constuctor + /*! After created a BNodeInfo with this, you should call \sa SetTo() + * @see SetTo(BNode *node) + */ + BNodeInfo(); + + //! The Constuctor + /*! @see SetTo(BNode *node) + * @param node The node to gather information on. Can be any favour */ + BNodeInfo(BNode *node); + virtual ~BNodeInfo(); + + //! Sets the node for which you want data on + /*! @param node The node to play with + * @return
    • B_OKAll is fine (still check InitCheck)
    • + *
    • B_BAD_VALUEThe node was bad
      • + */ + status_t SetTo(BNode *node); + + //! Has it been created OK? + /*! @returns
        • B_OK
        • + *
        • B_NO_INIT
        + */ + status_t InitCheck() const; + + //! Gets the nodes MIME type + virtual status_t GetType(char *type) const; + //! Sets the nodes MIME type + virtual status_t SetType(const char *type); + //! Gets the nodes icon + virtual status_t GetIcon(BBitmap *icon, icon_size k = B_LARGE_ICON) const; + //! Sets the nodes icon + virtual status_t SetIcon(const BBitmap *icon, icon_size k = B_LARGE_ICON); + + //! Gets the application which will open the node when a user double-clicks + status_t GetPreferredApp(char *signature, + app_verb verb = B_OPEN) const; + //! Sets the application which will open the node. + status_t SetPreferredApp(const char *signature, + app_verb verb = B_OPEN); + //! Gets a entry_ref which may point to an application which will load when + //! the user double clicks + status_t GetAppHint(entry_ref *ref) const; + //! Sets the entry_reg which should point to the app you wish to load when + //! node (icon in tracker) is double clicked + status_t SetAppHint(const entry_ref *ref); + + //! Gets the icon which tracker displays + status_t GetTrackerIcon(BBitmap *icon, + icon_size k = B_LARGE_ICON) const; + //! Sets the icon which tracker will desplay + static status_t GetTrackerIcon(const entry_ref *ref, + BBitmap *icon, + icon_size k = B_LARGE_ICON); +private: + friend class BAppFileInfo; + + virtual void _ReservedNodeInfo1(); //< FBC + virtual void _ReservedNodeInfo2(); //< FBC + virtual void _ReservedNodeInfo3(); //< FBC + + BNodeInfo &operator=(const BNodeInfo &); + BNodeInfo(const BNodeInfo &); + + BNode *fNode; //< The Node in question + uint32 _reserved[2]; //< FBC + status_t fCStatus; //< The status to return from InitCheck +}; + +#ifdef USE_OPENBEOS_NAMESPACE +} +#endif // USE_OPENBEOS_NAMESPACE + +#endif // __sk_node_info_h__ + diff --git a/headers/os/storage/Path.h b/headers/os/storage/Path.h new file mode 100644 index 0000000000..562aca0631 --- /dev/null +++ b/headers/os/storage/Path.h @@ -0,0 +1,100 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file Path.h + BPath interface declaration. +*/ + +#ifndef __sk_path_h__ +#define __sk_path_h__ + +#include +#include + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS { +#endif + +// Forward declarations +class BDirectory; +class BEntry; +struct entry_ref; + +/*! + \class BPath + \brief An absolute pathname wrapper class + + Provides a convenient means of managing pathnames. + + \author Ingo Weinhold + \author Tyler Dauwalder + + \version 0.0.0 +*/ +class BPath : public BFlattenable { +public: + + BPath(); + BPath(const BPath &path); + BPath(const entry_ref *ref); + BPath(const BEntry *entry); + BPath(const char *dir, const char *leaf = NULL, bool normalize = false); + BPath(const BDirectory *dir, const char *leaf, bool normalize = false); + + virtual ~BPath(); + + status_t InitCheck() const; + + status_t SetTo(const entry_ref *ref); + status_t SetTo(const BEntry *entry); + status_t SetTo(const char *path, const char *leaf = NULL, + bool normalize = false); + status_t SetTo(const BDirectory *dir, const char *path, + bool normalize = false); + void Unset(); + + status_t Append(const char *path, bool normalize = false); + + const char *Path() const; + const char *Leaf() const; + status_t GetParent(BPath *path) const; + + bool operator==(const BPath &item) const; + bool operator==(const char *path) const; + bool operator!=(const BPath &item) const; + bool operator!=(const char *path) const; + BPath& operator=(const BPath &item); + BPath& operator=(const char *path); + + // BFlattenable protocol + virtual bool IsFixedSize() const; + virtual type_code TypeCode() const; + virtual ssize_t FlattenedSize() const; + virtual status_t Flatten(void *buffer, ssize_t size) const; + virtual bool AllowsTypeCode(type_code code) const; + virtual status_t Unflatten(type_code c, const void *buf, ssize_t size); + +private: + virtual void _WarPath1(); + virtual void _WarPath2(); + virtual void _WarPath3(); + + uint32 _warData[4]; + + char *fName; + status_t fCStatus; + + class EBadInput { }; + + status_t set_path(const char *path); + + static bool MustNormalize(const char *path); +}; + +#ifdef USE_OPENBEOS_NAMESPACE +}; // namespace OpenBeOS +#endif + +#endif // __sk_path_h__ diff --git a/headers/os/storage/Query.h b/headers/os/storage/Query.h new file mode 100644 index 0000000000..d1d96b9287 --- /dev/null +++ b/headers/os/storage/Query.h @@ -0,0 +1,123 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file Query.h + BQuery interface declaration. +*/ + +#ifndef _sk_query_h_ +#define _sk_query_h_ + +#include +#include +#include +#include + +#include + +class BVolume; +struct entry_ref; + +namespace StorageKit { + class QueryNode; + class QueryStack; + class QueryTree; +}; + +typedef enum { + B_INVALID_OP = 0, + B_EQ, + B_GT, + B_GE, + B_LT, + B_LE, + B_NE, + B_CONTAINS, + B_BEGINS_WITH, + B_ENDS_WITH, + B_AND = 0x101, + B_OR, + B_NOT, + _B_RESERVED_OP_ = 0x100000 +} query_op; + +/*! + \class BQuery + \brief Represents a live or non-live file system query + + Provides an interface for creating file system queries. Implements + the BEntryList for iterating through the found entries. + + \author Ingo Weinhold + + \version 0.0.0 +*/ +class BQuery : public BEntryList { +public: + BQuery(); + virtual ~BQuery(); + + status_t Clear(); + + status_t PushAttr(const char *attrName); + status_t PushOp(query_op op); + + status_t PushUInt32(uint32 value); + status_t PushInt32(int32 value); + status_t PushUInt64(uint64 value); + status_t PushInt64(int64 value); + status_t PushFloat(float value); + status_t PushDouble(double value); + status_t PushString(const char *value, bool caseInsensitive = false); + status_t PushDate(const char *date); + + status_t SetVolume(const BVolume *volume); + status_t SetPredicate(const char *expression); + status_t SetTarget(BMessenger messenger); + + bool IsLive() const; + + status_t GetPredicate(char *buffer, size_t length); + status_t GetPredicate(BString *predicate); + size_t PredicateLength(); + + dev_t TargetDevice() const; + + status_t Fetch(); + + // BEntryList interface + virtual status_t GetNextEntry(BEntry *entry, bool traverse = false); + virtual status_t GetNextRef(entry_ref *ref); + virtual int32 GetNextDirents(struct dirent *buf, size_t length, + int32 count = INT_MAX); + virtual status_t Rewind(); + virtual int32 CountEntries(); + +private: + bool _HasFetched() const; + status_t _PushNode(StorageKit::QueryNode *node, bool deleteOnError); + status_t _SetPredicate(const char *expression); + status_t _EvaluateStack(); + + // FBC + virtual void _ReservedQuery1(); + virtual void _ReservedQuery2(); + virtual void _ReservedQuery3(); + virtual void _ReservedQuery4(); + virtual void _ReservedQuery5(); + virtual void _ReservedQuery6(); + +private: + int32 _reservedData[4]; // FBC + StorageKit::QueryStack *fStack; + char *fPredicate; + dev_t fDevice; + bool fLive; + port_id fPort; + long fToken; + StorageKit::FileDescriptor fQueryFd; +}; + +#endif // _sk_query_h_ diff --git a/headers/os/storage/ResourceStrings.h b/headers/os/storage/ResourceStrings.h new file mode 100644 index 0000000000..27a7702b0a --- /dev/null +++ b/headers/os/storage/ResourceStrings.h @@ -0,0 +1,90 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file ResourceStrings.h + BResourceStrings interface declaration. +*/ + +#ifndef _sk_resource_strings_h_ +#define _sk_resource_strings_h_ + +#include +#include + +class BResources; +class BString; + +/*! + \class BResourceStrings + \brief Simple class to access the string resources in a file. + + A BResourceStrings object reads the string type resources from a given + resource file and provides fast read only access to them. + + \author Ingo Weinhold + + \version 0.0.0 +*/ +class BResourceStrings { +public: + BResourceStrings(); + BResourceStrings(const entry_ref &ref); + virtual ~BResourceStrings(); + + status_t InitCheck(); + virtual BString *NewString(int32 id); + virtual const char *FindString(int32 id); + + virtual status_t SetStringFile(const entry_ref *ref); + status_t GetStringFile(entry_ref *outRef); + +public: + enum { + RESOURCE_TYPE = 'CSTR' + }; + +protected: + struct _string_id_hash { + _string_id_hash(); + ~_string_id_hash(); + void assign_string(const char *str, bool makeCopy); + _string_id_hash *next; + int32 id; + char *data; + bool data_alloced; + bool _reserved1[3]; + uint32 _reserved2; + }; + +protected: + BLocker _string_lock; + status_t _init_error; + +private: + entry_ref fFileRef; + BResources *fResources; + _string_id_hash **fHashTable; + int32 fHashTableSize; + int32 fStringCount; + uint32 _reserved[16]; // FBC + +private: + void _Cleanup(); + void _MakeEmpty(); + status_t _Rehash(int32 newSize); + _string_id_hash *_AddString(char *str, int32 id, bool wasMalloced); + + virtual _string_id_hash *_FindString(int32 id); + + // FBC + virtual void _ReservedResourceStrings0(); + virtual void _ReservedResourceStrings1(); + virtual void _ReservedResourceStrings2(); + virtual void _ReservedResourceStrings3(); + virtual void _ReservedResourceStrings4(); + virtual void _ReservedResourceStrings5(); +}; + +#endif // _sk_resource_strings_h_ diff --git a/headers/os/storage/Resources.h b/headers/os/storage/Resources.h new file mode 100644 index 0000000000..4162af69ac --- /dev/null +++ b/headers/os/storage/Resources.h @@ -0,0 +1,114 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file Resources.h + BResources interface declaration. +*/ + +#ifndef _sk_resources_h_ +#define _sk_resources_h_ + +#include + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS { +#endif + +namespace StorageKit { + class ResourcesContainer; + class ResourceFile; +}; + +/*! + \class BResources + \brief Represent the resources in a file + + Provides an interface for accessing and manipulating resources. + + \author Ingo Weinhold + + \version 0.0.0 +*/ +class BResources { +public: + BResources(); + BResources(const BFile *file, bool clobber = false); + virtual ~BResources(); + + status_t SetTo(const BFile *file, bool clobber = false); + void Unset(); + status_t InitCheck() const; + + const BFile &File() const; + + const void *LoadResource(type_code type, int32 id, size_t *outSize); + const void *LoadResource(type_code type, const char *name, + size_t *outSize); + + status_t PreloadResourceType(type_code type = 0); + + status_t Sync(); + status_t MergeFrom(BFile *fromFile); + status_t WriteTo(BFile *file); + + status_t AddResource(type_code type, int32 id, const void *data, + size_t length, const char *name = NULL); + + bool HasResource(type_code type, int32 id); + bool HasResource(type_code type, const char *name); + + bool GetResourceInfo(int32 byIndex, type_code *typeFound, int32 *idFound, + const char **nameFound, size_t *lengthFound); + bool GetResourceInfo(type_code byType, int32 andIndex, int32 *idFound, + const char **nameFound, size_t *lengthFound); + bool GetResourceInfo(type_code byType, int32 andID, + const char **nameFound, size_t *lengthFound); + bool GetResourceInfo(type_code byType, const char *andName, int32 *idFound, + size_t *lengthFound); + bool GetResourceInfo(const void *byPointer, type_code *typeFound, + int32 *idFound, size_t *lengthFound, + const char **nameFound); + + status_t RemoveResource(const void *resource); + status_t RemoveResource(type_code type, int32 id); + + + // deprecated + + status_t WriteResource(type_code type, int32 id, const void *data, + off_t offset, size_t length); + + status_t ReadResource(type_code type, int32 id, void *data, off_t offset, + size_t length); + + void *FindResource(type_code type, int32 id, size_t *lengthFound); + void *FindResource(type_code type, const char *name, size_t *lengthFound); + +private: + // FBC + virtual void _ReservedResources1(); + virtual void _ReservedResources2(); + virtual void _ReservedResources3(); + virtual void _ReservedResources4(); + virtual void _ReservedResources5(); + virtual void _ReservedResources6(); + virtual void _ReservedResources7(); + virtual void _ReservedResources8(); + +private: + BFile fFile; + StorageKit::ResourcesContainer *fContainer; + StorageKit::ResourceFile *fResourceFile; + bool fReadOnly; + bool _pad[3]; + uint32 _reserved[3]; // FBC +}; + + +#ifdef USE_OPENBEOS_NAMESPACE +}; // namespace OpenBeOS +#endif + +#endif // _sk_resources_h_ diff --git a/headers/os/storage/Statable.h b/headers/os/storage/Statable.h new file mode 100644 index 0000000000..36c9da6528 --- /dev/null +++ b/headers/os/storage/Statable.h @@ -0,0 +1,83 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file Statable.h + BStatable interface declaration. +*/ + +#ifndef __sk_statable_h__ +#define __sk_statable_h__ + +#include +#include +#include + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS { +#endif // USE_OPENBEOS_NAMESPACE + + struct node_ref; + class BVolume; + + + //! BStatable - A nice C++ wrapper to \sa stat() + /*! A purly abstract class which provieds an expenive, but convenet + * C++ wrapper to the posix \sa stat() command. + * + * @see MIT + * @author Michael Lloyd Lee + * @author Be Inc + * @version 0 + */ +class BStatable { +public: + virtual status_t GetStat(struct stat *st) const = 0; + + bool IsFile() const; + bool IsDirectory() const; + bool IsSymLink() const; + + status_t GetNodeRef(node_ref *ref) const; + + status_t GetOwner(uid_t *owner) const; + status_t SetOwner(uid_t owner); + + status_t GetGroup(gid_t *group) const; + status_t SetGroup(gid_t group); + + status_t GetPermissions(mode_t *perms) const; + status_t SetPermissions(mode_t perms); + + status_t GetSize(off_t *size) const; + + status_t GetModificationTime(time_t *mtime) const; + status_t SetModificationTime(time_t mtime); + + status_t GetCreationTime(time_t *ctime) const; + status_t SetCreationTime(time_t ctime); + + status_t GetAccessTime(time_t *atime) const; + status_t SetAccessTime(time_t atime); + + status_t GetVolume(BVolume *vol) const; + + private: + + friend class BEntry; + friend class BNode; + + virtual void _OhSoStatable1(); //< FBC + virtual void _OhSoStatable2(); //< FBC + virtual void _OhSoStatable3(); //< FBC + uint32 _ohSoData[4]; //< FBC + + virtual status_t set_stat(struct stat &st, uint32 what) = 0; +}; + +#ifdef USE_OPENBEOS_NAMESPACE +} +#endif // USE_OPENBEOS_NAMESPACE + +#endif // __sk_statable_h__ diff --git a/headers/os/storage/StorageDefs.h b/headers/os/storage/StorageDefs.h new file mode 100644 index 0000000000..08e5fc2a5f --- /dev/null +++ b/headers/os/storage/StorageDefs.h @@ -0,0 +1,56 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file StorageDefs.h + Miscellaneous Storage Kit definitions and includes. +*/ + +#ifndef __sk_def_storage_h__ +#define __sk_def_storage_h__ + +#include +#include +#include + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS { +#endif // USE_OPENBEOS_NAMESPACE + +// Limits +#define B_DEV_NAME_LENGTH 128 +#define B_FILE_NAME_LENGTH NAME_MAX +#define B_PATH_NAME_LENGTH MAXPATHLEN +#define B_ATTR_NAME_LENGTH (B_FILE_NAME_LENGTH-1) +#define B_MIME_TYPE_LENGTH (B_ATTR_NAME_LENGTH - 15) +#define B_MAX_SYMLINKS SYMLINK_MAX + + +// Open Modes +#define B_READ_ONLY O_RDONLY // read only +#define B_WRITE_ONLY O_WRONLY // write only +#define B_READ_WRITE O_RDWR // read and write + +#define B_FAIL_IF_EXISTS O_EXCL // exclusive create +#define B_CREATE_FILE O_CREAT // create the file +#define B_ERASE_FILE O_TRUNC // erase the file's data +#define B_OPEN_AT_END O_APPEND // point to the end of the data + + +// Node Flavors +enum node_flavor { + B_FILE_NODE = 0x01, + B_SYMLINK_NODE = 0x02, + B_DIRECTORY_NODE = 0x04, + B_ANY_NODE = 0x07 +}; + + + +#ifdef USE_OPENBEOS_NAMESPACE +}; // namespace OpenBeOS +#endif // USE_OPENBEOS_NAMESPACE + + +#endif __sk_def_storage_h__ \ No newline at end of file diff --git a/headers/os/storage/SymLink.h b/headers/os/storage/SymLink.h new file mode 100644 index 0000000000..ae7103b072 --- /dev/null +++ b/headers/os/storage/SymLink.h @@ -0,0 +1,87 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// File Name: SymLink.h +//--------------------------------------------------------------------- +/*! + \file SymLink.h + BSymLink interface declaration. +*/ + +#ifndef __sk_sym_link_h__ +#define __sk_sym_link_h__ + +#include +#include +#include "kernel_interface.h" + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS { +#endif + +/*! + \class BSymLink + \brief A symbolic link in the filesystem + + Provides an interface for manipulating symbolic links. + + \author Ingo Weinhold + + \version 0.0.0 +*/ +class BSymLink : public BNode { +public: + BSymLink(); + BSymLink(const BSymLink &link); + BSymLink(const entry_ref *ref); + BSymLink(const BEntry *entry); + BSymLink(const char *path); + BSymLink(const BDirectory *dir, const char *path); + virtual ~BSymLink(); + + // WORKAROUND + // SetTo() methods: Part of a work around until someone has an idea how to + // get StorageKit::read_link(FileDescriptor,...) to work. + status_t SetTo(const entry_ref *ref); + status_t SetTo(const BEntry *entry); + status_t SetTo(const char *path); + status_t SetTo(const BDirectory *dir, const char *path); + void Unset(); + + ssize_t ReadLink(char *buf, size_t size); + + ssize_t MakeLinkedPath(const char *dirPath, BPath *path); + ssize_t MakeLinkedPath(const BDirectory *dir, BPath *path); + + bool IsAbsolute(); + + // WORKAROUND + // operator=(): Part of a work around until someone has an idea how to + // get StorageKit::read_link(FileDescriptor,...) to work. + BSymLink &operator=(const BSymLink &link); + +private: + virtual void _ReservedSymLink1(); + virtual void _ReservedSymLink2(); + virtual void _ReservedSymLink3(); + virtual void _ReservedSymLink4(); + virtual void _ReservedSymLink5(); + virtual void _ReservedSymLink6(); + + // WORKAROUND + // fSecretEntry: Part of a work around until someone has an idea how to + // get StorageKit::read_link(FileDescriptor,...) to work. +// uint32 _reservedData[4]; + uint32 _reservedData[3]; + BEntry *fSecretEntry; + +private: + StorageKit::FileDescriptor get_fd() const; +}; + +#ifdef USE_OPENBEOS_NAMESPACE +}; // namespace OpenBeOS +#endif + +#endif // __sk_sym_link_h__ diff --git a/headers/os/storage/Volume.h b/headers/os/storage/Volume.h new file mode 100644 index 0000000000..56f125fe5c --- /dev/null +++ b/headers/os/storage/Volume.h @@ -0,0 +1,109 @@ +// ---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// File Name: Directory.cpp +// +// Description: BVolume class +// ---------------------------------------------------------------------- + +#ifndef __sk_volume_h__ +#define __sk_volume_h__ + +#ifndef _BE_BUILD_H +#include +#endif +#include + +#ifndef _FS_INFO_H +#include +//#include "fs_info.h" +#endif +#ifndef _STORAGE_DEFS_H +#include +//#include "StorageDefs.h" +#endif +#ifndef _MIME_H +#include +#endif +#ifndef _SUPPORT_DEFS_H +#include +#endif + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS { +#endif + + +class BDirectory; +class BBitmap; + +class BVolume { + public: + BVolume(void); + BVolume(dev_t dev); + BVolume(const BVolume& vol); + + virtual ~BVolume(void); + + status_t InitCheck(void) const; + + status_t SetTo(dev_t dev); + void Unset(void); + + dev_t Device(void) const; + + status_t GetRootDirectory(BDirectory* dir) const; + + off_t Capacity(void) const; + off_t FreeBytes(void) const; + + status_t GetName(char* name) const; + status_t SetName(const char* name); + + status_t GetIcon( + BBitmap* icon, + icon_size which) const; + + bool IsRemovable(void) const; + bool IsReadOnly(void) const; + bool IsPersistent(void) const; + bool IsShared(void) const; + bool KnowsMime(void) const; + bool KnowsAttr(void) const; + bool KnowsQuery(void) const; + + bool operator==(const BVolume& vol) const; + bool operator!=(const BVolume& vol) const; + BVolume& operator=(const BVolume& vol); + + private: + + friend class BVolumeRoster; + + virtual void _TurnUpTheVolume1(); + virtual void _TurnUpTheVolume2(); + + #if !_PR3_COMPATIBLE_ + virtual void _TurnUpTheVolume3(); + virtual void _TurnUpTheVolume4(); + virtual void _TurnUpTheVolume5(); + virtual void _TurnUpTheVolume6(); + virtual void _TurnUpTheVolume7(); + virtual void _TurnUpTheVolume8(); + #endif + + dev_t fDev; + status_t fCStatus; + + #if !_PR3_COMPATIBLE_ + int32 _reserved[8]; + #endif +}; + + +#ifdef USE_OPENBEOS_NAMESPACE +} +#endif + +#endif diff --git a/headers/os/support/Archivable.h b/headers/os/support/Archivable.h new file mode 100644 index 0000000000..a741f62b53 --- /dev/null +++ b/headers/os/support/Archivable.h @@ -0,0 +1,97 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: Archivable.h +// Author: Erik Jaesler (erik@cgsoftware.com) +// Description: BArchivable mix-in class defines the archiving +// protocol. Also some global archiving functions. +//------------------------------------------------------------------------------ + +#ifndef _ARCHIVABLE_H +#define _ARCHIVABLE_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +class BMessage; + +// BArchivable class ----------------------------------------------------------- +class BArchivable { +public: + BArchivable(); + virtual ~BArchivable(); + + BArchivable(BMessage* from); + virtual status_t Archive(BMessage* into, bool deep = true) const; + static BArchivable *Instantiate(BMessage* from); + +// Private or reserved --------------------------------------------------------- + virtual status_t Perform(perform_code d, void* arg); + +private: + + virtual void _ReservedArchivable1(); + virtual void _ReservedArchivable2(); + virtual void _ReservedArchivable3(); + + uint32 _reserved[2]; +}; + + +// Global Functions ------------------------------------------------------------ + +typedef BArchivable* (*instantiation_func) (BMessage *); + +_IMPEXP_BE BArchivable* instantiate_object(BMessage *from, image_id *id); +_IMPEXP_BE BArchivable* instantiate_object(BMessage *from); +_IMPEXP_BE bool validate_instantiation(BMessage* from, + const char* class_name); + +_IMPEXP_BE instantiation_func find_instantiation_func(const char* class_name, + const char* sig); +_IMPEXP_BE instantiation_func find_instantiation_func(const char* class_name); +_IMPEXP_BE instantiation_func find_instantiation_func(BMessage* archive_data); + + +//------------------------------------------------------------------------------ + + +#endif // _ARCHIVABLE_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/headers/os/support/Autolock.h b/headers/os/support/Autolock.h new file mode 100644 index 0000000000..27dd098dfa --- /dev/null +++ b/headers/os/support/Autolock.h @@ -0,0 +1,79 @@ +// +// $Id: Autolock.h,v 1.1 2002/07/09 12:24:33 ejakowatz Exp $ +// +// This is the BAutolock interface for OpenBeOS. It has been created to +// be source and binary compatible with the BeOS version of BAutolock. +// To that end, all members are inline just as with the BeOS version. +// + + +#ifndef _OPENBEOS_AUTOLOCK_H +#define _OPENBEOS_AUTOLOCK_H + + +#include "Locker.h" +#include + + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS { +#endif + +class BAutolock { +public: + inline BAutolock(BLooper *looper); + inline BAutolock(BLocker *locker); + inline BAutolock(BLocker &locker); + + inline ~BAutolock(); + + inline bool IsLocked(void); + +private: + BLocker *fTheLocker; + BLooper *fTheLooper; + bool fIsLocked; +}; + + +inline BAutolock::BAutolock(BLooper *looper) : + fTheLocker(NULL), fTheLooper(looper), fIsLocked(looper->Lock()) +{ +} + + +inline BAutolock::BAutolock(BLocker *locker) : + fTheLocker(locker), fTheLooper(NULL), fIsLocked(locker->Lock()) +{ +} + + +inline BAutolock::BAutolock(BLocker &locker) : + fTheLocker(&locker), fTheLooper(NULL), fIsLocked(locker.Lock()) +{ +} + + +inline BAutolock::~BAutolock() +{ + if (fIsLocked) { + if (fTheLooper != NULL) { + fTheLooper->Unlock(); + } else { + fTheLocker->Unlock(); + } + } +} + + +inline bool BAutolock::IsLocked() +{ + return fIsLocked; +} + + +#ifdef USE_OPENBEOS_NAMESPACE +} +#endif + +#endif // _OPENBEOS_LOCKER_H diff --git a/headers/os/support/ByteOrder.h b/headers/os/support/ByteOrder.h new file mode 100644 index 0000000000..62f5a01de3 --- /dev/null +++ b/headers/os/support/ByteOrder.h @@ -0,0 +1,142 @@ +// Modified BeOS header. Just here to be able to compile and test BResources. +// To be replaced by the OpenBeOS version to be provided by the IK Team. + +#ifndef _sk_byte_order_h_ +#define _sk_byte_order_h_ + +#include +#include +#include +#include /* For convenience */ + +#ifdef __cplusplus +extern "C" { +#endif + +/*----------------------------------------------------------------------*/ +/*------- Swap-direction constants, and swapping functions -------------*/ + +typedef enum { + B_SWAP_HOST_TO_LENDIAN, + B_SWAP_HOST_TO_BENDIAN, + B_SWAP_LENDIAN_TO_HOST, + B_SWAP_BENDIAN_TO_HOST, + B_SWAP_ALWAYS +} swap_action; + +extern status_t swap_data(type_code type, void *data, size_t length, + swap_action action); + +extern bool is_type_swapped(type_code type); + + +/*-----------------------------------------------------------------------*/ +/*----- Private implementations -----------------------------------------*/ +extern double __swap_double(double arg); +extern float __swap_float(float arg); +extern uint64 __swap_int64(uint64 uarg); +extern uint32 __swap_int32(uint32 uarg); +extern uint16 __swap_int16(uint16 uarg); +/*-------------------------------------------------------------*/ + + +/*-------------------------------------------------------------*/ +/*--------- Host is Little --------------------------------------*/ + +#if BYTE_ORDER == __LITTLE_ENDIAN +#define B_HOST_IS_LENDIAN 1 +#define B_HOST_IS_BENDIAN 0 + +/*--------- Host Native -> Little --------------------*/ + +#define B_HOST_TO_LENDIAN_DOUBLE(arg) (double)(arg) +#define B_HOST_TO_LENDIAN_FLOAT(arg) (float)(arg) +#define B_HOST_TO_LENDIAN_INT64(arg) (uint64)(arg) +#define B_HOST_TO_LENDIAN_INT32(arg) (uint32)(arg) +#define B_HOST_TO_LENDIAN_INT16(arg) (uint16)(arg) + +/*--------- Host Native -> Big ------------------------*/ +#define B_HOST_TO_BENDIAN_DOUBLE(arg) __swap_double(arg) +#define B_HOST_TO_BENDIAN_FLOAT(arg) __swap_float(arg) +#define B_HOST_TO_BENDIAN_INT64(arg) __swap_int64(arg) +#define B_HOST_TO_BENDIAN_INT32(arg) __swap_int32(arg) +#define B_HOST_TO_BENDIAN_INT16(arg) __swap_int16(arg) + +/*--------- Little -> Host Native ---------------------*/ +#define B_LENDIAN_TO_HOST_DOUBLE(arg) (double)(arg) +#define B_LENDIAN_TO_HOST_FLOAT(arg) (float)(arg) +#define B_LENDIAN_TO_HOST_INT64(arg) (uint64)(arg) +#define B_LENDIAN_TO_HOST_INT32(arg) (uint32)(arg) +#define B_LENDIAN_TO_HOST_INT16(arg) (uint16)(arg) + +/*--------- Big -> Host Native ------------------------*/ +#define B_BENDIAN_TO_HOST_DOUBLE(arg) __swap_double(arg) +#define B_BENDIAN_TO_HOST_FLOAT(arg) __swap_float(arg) +#define B_BENDIAN_TO_HOST_INT64(arg) __swap_int64(arg) +#define B_BENDIAN_TO_HOST_INT32(arg) __swap_int32(arg) +#define B_BENDIAN_TO_HOST_INT16(arg) __swap_int16(arg) + +#else /* __LITTLE_ENDIAN */ + + +/*-------------------------------------------------------------*/ +/*--------- Host is Big --------------------------------------*/ + +#define B_HOST_IS_LENDIAN 0 +#define B_HOST_IS_BENDIAN 1 + +/*--------- Host Native -> Little -------------------*/ +#define B_HOST_TO_LENDIAN_DOUBLE(arg) __swap_double(arg) +#define B_HOST_TO_LENDIAN_FLOAT(arg) __swap_float(arg) +#define B_HOST_TO_LENDIAN_INT64(arg) __swap_int64(arg) +#define B_HOST_TO_LENDIAN_INT32(arg) __swap_int32(arg) +#define B_HOST_TO_LENDIAN_INT16(arg) __swap_int16(arg) + +/*--------- Host Native -> Big ------------------------*/ +#define B_HOST_TO_BENDIAN_DOUBLE(arg) (double)(arg) +#define B_HOST_TO_BENDIAN_FLOAT(arg) (float)(arg) +#define B_HOST_TO_BENDIAN_INT64(arg) (uint64)(arg) +#define B_HOST_TO_BENDIAN_INT32(arg) (uint32)(arg) +#define B_HOST_TO_BENDIAN_INT16(arg) (uint16)(arg) + +/*--------- Little -> Host Native ----------------------*/ +#define B_LENDIAN_TO_HOST_DOUBLE(arg) __swap_double(arg) +#define B_LENDIAN_TO_HOST_FLOAT(arg) __swap_float(arg) +#define B_LENDIAN_TO_HOST_INT64(arg) __swap_int64(arg) +#define B_LENDIAN_TO_HOST_INT32(arg) __swap_int32(arg) +#define B_LENDIAN_TO_HOST_INT16(arg) __swap_int16(arg) + +/*--------- Big -> Host Native -------------------------*/ +#define B_BENDIAN_TO_HOST_DOUBLE(arg) (double)(arg) +#define B_BENDIAN_TO_HOST_FLOAT(arg) (float)(arg) +#define B_BENDIAN_TO_HOST_INT64(arg) (uint64)(arg) +#define B_BENDIAN_TO_HOST_INT32(arg) (uint32)(arg) +#define B_BENDIAN_TO_HOST_INT16(arg) (uint16)(arg) + +#endif /* __LITTLE_ENDIAN */ + + +/*-------------------------------------------------------------*/ +/*--------- Just-do-it macros ---------------------------------*/ +#define B_SWAP_DOUBLE(arg) __swap_double(arg) +#define B_SWAP_FLOAT(arg) __swap_float(arg) +#define B_SWAP_INT64(arg) __swap_int64(arg) +#define B_SWAP_INT32(arg) __swap_int32(arg) +#define B_SWAP_INT16(arg) __swap_int16(arg) + + +/*-------------------------------------------------------------*/ +/*---------Berkeley macros -----------------------------------*/ +#define htonl(x) B_HOST_TO_BENDIAN_INT32(x) +#define ntohl(x) B_BENDIAN_TO_HOST_INT32(x) +#define htons(x) B_HOST_TO_BENDIAN_INT16(x) +#define ntohs(x) B_BENDIAN_TO_HOST_INT16(x) + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +/*-------------------------------------------------------------*/ +/*-------------------------------------------------------------*/ + +#endif // _sk_byte_order_h_ diff --git a/headers/os/support/ClassInfo.h b/headers/os/support/ClassInfo.h new file mode 100644 index 0000000000..8f377d2956 --- /dev/null +++ b/headers/os/support/ClassInfo.h @@ -0,0 +1,38 @@ +/****************************************************************************** +/ +/ File: ClassInfo.h +/ +/ Description: C++ class identification and casting macros +/ +/ Copyright 1993-98, Be Incorporated +/ +******************************************************************************/ + +#ifndef _CLASS_INFO_H +#define _CLASS_INFO_H + +#include + +// deprecated, use standard RTTI calls instead + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS { +#endif + +/*-------------------------------------------------------------*/ +/*--------- Class Info Macros ---------------------------------*/ + +#define class_name(ptr) ((typeid(*(ptr))).name()) +#define cast_as(ptr, class) (dynamic_cast(ptr)) +#define is_kind_of(ptr, class) (cast_as(ptr, class) != 0) +#define is_instance_of(ptr, class) (typeid(*(ptr)) == typeid(class)) + +/*-------------------------------------------------------------*/ +/*-------------------------------------------------------------*/ + +#ifdef USE_OPENBEOS_NAMESPACE +} // namespace OpenBeOS +using namespace OpenBeOS; +#endif + +#endif /* _CLASS_INFO_H */ diff --git a/headers/os/support/DataIO.h b/headers/os/support/DataIO.h new file mode 100644 index 0000000000..896fd3c1bd --- /dev/null +++ b/headers/os/support/DataIO.h @@ -0,0 +1,74 @@ +// Modified BeOS header. Just here to be able to compile and test BFile. +// To be replaced by the OpenBeOS version to be provided by the IK Team. + +#ifndef __sk_data_io_h__ +#define __sk_data_io_h__ + +#include + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS { +#endif + +/*-----------------------------------------------------------------*/ +/*------- BDataIO Class -------------------------------------------*/ + +class BDataIO { +public: + BDataIO(); +virtual ~BDataIO(); + +virtual ssize_t Read(void *buffer, size_t size) = 0; +virtual ssize_t Write(const void *buffer, size_t size) =0; + +/*----- Private or reserved ---------------*/ +private: + +virtual void _ReservedDataIO1(); +virtual void _ReservedDataIO2(); +virtual void _ReservedDataIO3(); +virtual void _ReservedDataIO4(); + + BDataIO(const BDataIO &); + BDataIO &operator=(const BDataIO &); + + int32 _reserved[2]; +}; + +/*---------------------------------------------------------------------*/ +/*------- BPositionIO Class -------------------------------------------*/ + +class BPositionIO : public BDataIO { +public: + BPositionIO(); +virtual ~BPositionIO(); + +virtual ssize_t Read(void *buffer, size_t size); +virtual ssize_t Write(const void *buffer, size_t size); + +virtual ssize_t ReadAt(off_t pos, void *buffer, size_t size) = 0; +virtual ssize_t WriteAt(off_t pos, const void *buffer, size_t size) = 0; + +virtual off_t Seek(off_t position, uint32 seek_mode) = 0; +virtual off_t Position() const = 0; + +virtual status_t SetSize(off_t size); + +/*----- Private or reserved ---------------*/ +private: +virtual void _ReservedPositionIO1(); +virtual void _ReservedPositionIO2(); +virtual void _ReservedPositionIO3(); +virtual void _ReservedPositionIO4(); + + int32 _reserved[2]; +}; + +/*-------------------------------------------------------------*/ +/*-------------------------------------------------------------*/ + +#ifdef USE_OPENBEOS_NAMESPACE +} +#endif + +#endif // __sk_data_io_h__ diff --git a/headers/os/support/Errors.h b/headers/os/support/Errors.h new file mode 100644 index 0000000000..7091343bfa --- /dev/null +++ b/headers/os/support/Errors.h @@ -0,0 +1,258 @@ +#ifndef _ERRORS_H +#define _ERRORS_H + +#include + +/*-------------------------------------------------------------*/ +/*----- Error baselines ---------------------------------------*/ + +#define B_GENERAL_ERROR_BASE LONG_MIN +#define B_OS_ERROR_BASE B_GENERAL_ERROR_BASE + 0x1000 +#define B_APP_ERROR_BASE B_GENERAL_ERROR_BASE + 0x2000 +#define B_INTERFACE_ERROR_BASE B_GENERAL_ERROR_BASE + 0x3000 +#define B_MEDIA_ERROR_BASE B_GENERAL_ERROR_BASE + 0x4000 +#define B_TRANSLATION_ERROR_BASE B_GENERAL_ERROR_BASE + 0x4800 +#define B_MIDI_ERROR_BASE B_GENERAL_ERROR_BASE + 0x5000 +#define B_STORAGE_ERROR_BASE B_GENERAL_ERROR_BASE + 0x6000 +#define B_POSIX_ERROR_BASE B_GENERAL_ERROR_BASE + 0x7000 +#define B_MAIL_ERROR_BASE B_GENERAL_ERROR_BASE + 0x8000 +#define B_PRINT_ERROR_BASE B_GENERAL_ERROR_BASE + 0x9000 +#define B_DEVICE_ERROR_BASE B_GENERAL_ERROR_BASE + 0xa000 + +/*--- Developer-defined errors start at (B_ERRORS_END+1)----*/ + +#define B_ERRORS_END (B_GENERAL_ERROR_BASE + 0xffff) + + +/*-------------------------------------------------------------*/ +/*----- General Errors ----------------------------------------*/ +enum { + B_NO_MEMORY = B_GENERAL_ERROR_BASE, + B_IO_ERROR, + B_PERMISSION_DENIED, + B_BAD_INDEX, + B_BAD_TYPE, + B_BAD_VALUE, + B_MISMATCHED_VALUES, + B_NAME_NOT_FOUND, + B_NAME_IN_USE, + B_TIMED_OUT, + B_INTERRUPTED, + B_WOULD_BLOCK, + B_CANCELED, + B_NO_INIT, + B_BUSY, + B_NOT_ALLOWED, + B_BAD_DATA, + + B_ERROR = -1, + B_OK = 0, + B_NO_ERROR = 0 +}; + +/*-------------------------------------------------------------*/ +/*----- Kernel Kit Errors -------------------------------------*/ +enum { + B_BAD_SEM_ID = B_OS_ERROR_BASE, + B_NO_MORE_SEMS, + + B_BAD_THREAD_ID = B_OS_ERROR_BASE + 0x100, + B_NO_MORE_THREADS, + B_BAD_THREAD_STATE, + B_BAD_TEAM_ID, + B_NO_MORE_TEAMS, + + B_BAD_PORT_ID = B_OS_ERROR_BASE + 0x200, + B_NO_MORE_PORTS, + + B_BAD_IMAGE_ID = B_OS_ERROR_BASE + 0x300, + B_BAD_ADDRESS, + B_NOT_AN_EXECUTABLE, + B_MISSING_LIBRARY, + B_MISSING_SYMBOL, + + B_DEBUGGER_ALREADY_INSTALLED = B_OS_ERROR_BASE + 0x400 +}; + + +/*-------------------------------------------------------------*/ +/*----- Application Kit Errors --------------------------------*/ +enum +{ + B_BAD_REPLY = B_APP_ERROR_BASE, + B_DUPLICATE_REPLY, + B_MESSAGE_TO_SELF, + B_BAD_HANDLER, + B_ALREADY_RUNNING, + B_LAUNCH_FAILED, + B_AMBIGUOUS_APP_LAUNCH, + B_UNKNOWN_MIME_TYPE, + B_BAD_SCRIPT_SYNTAX, + B_LAUNCH_FAILED_NO_RESOLVE_LINK, + B_LAUNCH_FAILED_EXECUTABLE, + B_LAUNCH_FAILED_APP_NOT_FOUND, + B_LAUNCH_FAILED_APP_IN_TRASH, + B_LAUNCH_FAILED_NO_PREFERRED_APP, + B_LAUNCH_FAILED_FILES_APP_NOT_FOUND, + B_BAD_MIME_SNIFFER_RULE +}; + + +/*-------------------------------------------------------------*/ +/*----- Storage Kit/File System Errors ------------------------*/ +enum { + B_FILE_ERROR =B_STORAGE_ERROR_BASE, + B_FILE_NOT_FOUND, /* discouraged; use B_ENTRY_NOT_FOUND in new code*/ + B_FILE_EXISTS, + B_ENTRY_NOT_FOUND, + B_NAME_TOO_LONG, + B_NOT_A_DIRECTORY, + B_DIRECTORY_NOT_EMPTY, + B_DEVICE_FULL, + B_READ_ONLY_DEVICE, + B_IS_A_DIRECTORY, + B_NO_MORE_FDS, + B_CROSS_DEVICE_LINK, + B_LINK_LIMIT, + B_BUSTED_PIPE, + B_UNSUPPORTED, + B_PARTITION_TOO_SMALL +}; + + +/*-------------------------------------------------------------*/ +/*----- POSIX Errors ------------------------------------------*/ +#define E2BIG (B_POSIX_ERROR_BASE + 1) +#define ECHILD (B_POSIX_ERROR_BASE + 2) +#define EDEADLK (B_POSIX_ERROR_BASE + 3) +#define EFBIG (B_POSIX_ERROR_BASE + 4) +#define EMLINK (B_POSIX_ERROR_BASE + 5) +#define ENFILE (B_POSIX_ERROR_BASE + 6) +#define ENODEV (B_POSIX_ERROR_BASE + 7) +#define ENOLCK (B_POSIX_ERROR_BASE + 8) +#define ENOSYS (B_POSIX_ERROR_BASE + 9) +#define ENOTTY (B_POSIX_ERROR_BASE + 10) +#define ENXIO (B_POSIX_ERROR_BASE + 11) +#define ESPIPE (B_POSIX_ERROR_BASE + 12) +#define ESRCH (B_POSIX_ERROR_BASE + 13) +#define EFPOS (B_POSIX_ERROR_BASE + 14) +#define ESIGPARM (B_POSIX_ERROR_BASE + 15) +#define EDOM (B_POSIX_ERROR_BASE + 16) +#define ERANGE (B_POSIX_ERROR_BASE + 17) +#define EPROTOTYPE (B_POSIX_ERROR_BASE + 18) +#define EPROTONOSUPPORT (B_POSIX_ERROR_BASE + 19) +#define EPFNOSUPPORT (B_POSIX_ERROR_BASE + 20) +#define EAFNOSUPPORT (B_POSIX_ERROR_BASE + 21) +#define EADDRINUSE (B_POSIX_ERROR_BASE + 22) +#define EADDRNOTAVAIL (B_POSIX_ERROR_BASE + 23) +#define ENETDOWN (B_POSIX_ERROR_BASE + 24) +#define ENETUNREACH (B_POSIX_ERROR_BASE + 25) +#define ENETRESET (B_POSIX_ERROR_BASE + 26) +#define ECONNABORTED (B_POSIX_ERROR_BASE + 27) +#define ECONNRESET (B_POSIX_ERROR_BASE + 28) +#define EISCONN (B_POSIX_ERROR_BASE + 29) +#define ENOTCONN (B_POSIX_ERROR_BASE + 30) +#define ESHUTDOWN (B_POSIX_ERROR_BASE + 31) +#define ECONNREFUSED (B_POSIX_ERROR_BASE + 32) +#define EHOSTUNREACH (B_POSIX_ERROR_BASE + 33) +#define ENOPROTOOPT (B_POSIX_ERROR_BASE + 34) +#define ENOBUFS (B_POSIX_ERROR_BASE + 35) +#define EINPROGRESS (B_POSIX_ERROR_BASE + 36) +#define EALREADY (B_POSIX_ERROR_BASE + 37) +#define EILSEQ (B_POSIX_ERROR_BASE + 38) +#define ENOMSG (B_POSIX_ERROR_BASE + 39) +#define ESTALE (B_POSIX_ERROR_BASE + 40) +#define EOVERFLOW (B_POSIX_ERROR_BASE + 41) +#define EMSGSIZE (B_POSIX_ERROR_BASE + 42) +#define EOPNOTSUPP (B_POSIX_ERROR_BASE + 43) +#define ENOTSOCK (B_POSIX_ERROR_BASE + 44) + +#define ENOMEM B_NO_MEMORY +#define EACCES B_PERMISSION_DENIED +#define EINTR B_INTERRUPTED +#define EIO B_IO_ERROR +#define EBUSY B_BUSY +#define EFAULT B_BAD_ADDRESS +#define ETIMEDOUT B_TIMED_OUT +#define EAGAIN B_WOULD_BLOCK /* SysV compatibility */ +#define EWOULDBLOCK B_WOULD_BLOCK /* BSD compatibility */ +#define EBADF B_FILE_ERROR +#define EEXIST B_FILE_EXISTS +#define EINVAL B_BAD_VALUE +#define ENAMETOOLONG B_NAME_TOO_LONG +#define ENOENT B_ENTRY_NOT_FOUND +#define EPERM B_NOT_ALLOWED +#define ENOTDIR B_NOT_A_DIRECTORY +#define EISDIR B_IS_A_DIRECTORY +#define ENOTEMPTY B_DIRECTORY_NOT_EMPTY +#define ENOSPC B_DEVICE_FULL +#define EROFS B_READ_ONLY_DEVICE +#define EMFILE B_NO_MORE_FDS +#define EXDEV B_CROSS_DEVICE_LINK +#define ELOOP B_LINK_LIMIT +#define ENOEXEC B_NOT_AN_EXECUTABLE +#define EPIPE B_BUSTED_PIPE + +/*-------------------------------------------------------------*/ +/*----- Media Kit Errors --------------------------------------*/ +enum { + B_STREAM_NOT_FOUND = B_MEDIA_ERROR_BASE, + B_SERVER_NOT_FOUND, + B_RESOURCE_NOT_FOUND, + B_RESOURCE_UNAVAILABLE, + B_BAD_SUBSCRIBER, + B_SUBSCRIBER_NOT_ENTERED, + B_BUFFER_NOT_AVAILABLE, + B_LAST_BUFFER_ERROR +}; + +/*-------------------------------------------------------------*/ +/*----- Mail Kit Errors ---------------------------------------*/ +enum +{ + B_MAIL_NO_DAEMON = B_MAIL_ERROR_BASE, + B_MAIL_UNKNOWN_USER, + B_MAIL_WRONG_PASSWORD, + B_MAIL_UNKNOWN_HOST, + B_MAIL_ACCESS_ERROR, + B_MAIL_UNKNOWN_FIELD, + B_MAIL_NO_RECIPIENT, + B_MAIL_INVALID_MAIL +}; + +/*-------------------------------------------------------------*/ +/*----- Printing Errors --------------------------------------*/ +enum +{ + B_NO_PRINT_SERVER = B_PRINT_ERROR_BASE +}; + +/*-------------------------------------------------------------*/ +/*----- Device Kit Errors -------------------------------------*/ +enum +{ + B_DEV_INVALID_IOCTL = B_DEVICE_ERROR_BASE, + B_DEV_NO_MEMORY, + B_DEV_BAD_DRIVE_NUM, + B_DEV_NO_MEDIA, + B_DEV_UNREADABLE, + B_DEV_FORMAT_ERROR, + B_DEV_TIMEOUT, + B_DEV_RECALIBRATE_ERROR, + B_DEV_SEEK_ERROR, + B_DEV_ID_ERROR, + B_DEV_READ_ERROR, + B_DEV_WRITE_ERROR, + B_DEV_NOT_READY, + B_DEV_MEDIA_CHANGED, + B_DEV_MEDIA_CHANGE_REQUESTED, + B_DEV_RESOURCE_CONFLICT, + B_DEV_CONFIGURATION_ERROR, + B_DEV_DISABLED_BY_USER, + B_DEV_DOOR_OPEN +}; + +/*-------------------------------------------------------------*/ +/*-------------------------------------------------------------*/ + +#endif /* _ERRORS_H */ diff --git a/headers/os/support/Flattenable.h b/headers/os/support/Flattenable.h new file mode 100644 index 0000000000..3f5be54746 --- /dev/null +++ b/headers/os/support/Flattenable.h @@ -0,0 +1,36 @@ +// Modified BeOS header. Just here to be able to compile and test BPath. +// To be replaced by the OpenBeOS version to be provided by the IK Team. + +#ifndef __sk_flattenable_h__ +#define __sk_flattenable_h__ + +#include + +/*-------------------------------------------------------------*/ +/*----- BFlattenable class ------------------------------------*/ + +class BFlattenable { +public: + +virtual bool IsFixedSize() const = 0; +virtual type_code TypeCode() const = 0; +virtual ssize_t FlattenedSize() const = 0; +virtual status_t Flatten(void *buffer, ssize_t size) const = 0; +virtual bool AllowsTypeCode(type_code code) const; +virtual status_t Unflatten(type_code c, const void *buf, ssize_t size) = 0; + +virtual ~BFlattenable(); // was a reserved virtual in R4.0 + +/*----- Private or reserved ---------------*/ + +private: + void _ReservedFlattenable1(); +virtual void _ReservedFlattenable2(); +virtual void _ReservedFlattenable3(); +}; + +/*-------------------------------------------------------------*/ +/*-------------------------------------------------------------*/ + +#endif // __sk_flattenable_h__ + diff --git a/headers/os/support/List.h b/headers/os/support/List.h new file mode 100644 index 0000000000..e9b3339e0d --- /dev/null +++ b/headers/os/support/List.h @@ -0,0 +1,53 @@ +// List.h +// Just here to be able to compile and test BResources. +// To be replaced by the OpenBeOS version to be provided by the IK Team. + +#ifndef _sk_list_h_ +#define _sk_list_h_ + +#include + +class BList { +public: + BList(int32 count = 20); + BList(const BList& anotherList); + virtual ~BList(); + + bool AddItem(void *item, int32 index); + bool AddItem(void *item); + bool AddList(BList *list, int32 index); + bool AddList(BList *list); + int32 CountItems() const; + void DoForEach(bool (*func)(void *)); + void DoForEach(bool (*func)(void *, void *), void *arg2); + void *FirstItem() const; + bool HasItem(void *item) const; + int32 IndexOf(void *item) const; + bool IsEmpty() const; + void *ItemAt(int32 index) const; + void *Items() const; + void *LastItem() const; + void MakeEmpty(); + bool RemoveItem(void *item); + void *RemoveItem(int32 index); + bool RemoveItems(int32 index, int32 count); + void SortItems(int (*compareFunc)(const void *, const void *)); + + BList& operator =(const BList &); + +private: + virtual void _ReservedList1(); + virtual void _ReservedList2(); + + // return type differs from BeOS version + bool Resize(int32 count); + +private: + void** fObjectList; + size_t fPhysicalSize; + int32 fItemCount; + int32 fBlockSize; + uint32 _reserved[2]; +}; + +#endif // _sk_list_h_ diff --git a/headers/os/support/Locker.h b/headers/os/support/Locker.h new file mode 100644 index 0000000000..ef0260f225 --- /dev/null +++ b/headers/os/support/Locker.h @@ -0,0 +1,62 @@ +// +// $Id: Locker.h,v 1.1 2002/07/09 12:24:33 ejakowatz Exp $ +// +// This is the BLocker interface for OpenBeOS. It has been created to +// be source and binary compatible with the BeOS version of BLocker. +// + + +#ifndef _OPENBEOS_LOCKER_H +#define _OPENBEOS_LOCKER_H + + +#include +#include + + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS { +#endif + +class BLocker { +public: + BLocker(); + BLocker(const char *name); + BLocker(bool benaphore_style); + BLocker(const char *name, bool benaphore_style); + + // The following constructor is not documented in the BeBook + // and is only listed here to ensure binary compatibility. + // DO NOT USE THIS CONSTRUCTOR! + BLocker(const char *name, bool benaphore_style, bool); + + virtual ~BLocker(); + + bool Lock(void); + status_t LockWithTimeout(bigtime_t timeout); + void Unlock(void); + + thread_id LockingThread(void) const; + bool IsLocked(void) const; + int32 CountLocks(void) const; + int32 CountLockRequests(void) const; + sem_id Sem(void) const; + +private: + void InitLocker(const char *name, bool benaphore_style); + bool AcquireLock(bigtime_t timeout, status_t *error); + + int32 fBenaphoreCount; + sem_id fSemaphoreID; + thread_id fLockOwner; + int32 fRecursiveCount; + + // Reserved space for future changes to BLocker + int32 fReservedSpace[4]; +}; + +#ifdef USE_OPENBEOS_NAMESPACE +} +#endif + +#endif // _OPENBEOS_LOCKER_H diff --git a/headers/os/support/MallocIO.h b/headers/os/support/MallocIO.h new file mode 100644 index 0000000000..7d27b36ab2 --- /dev/null +++ b/headers/os/support/MallocIO.h @@ -0,0 +1,45 @@ +// MallocIO.h +// Just here to be able to compile and test BResources. +// To be replaced by the OpenBeOS version to be provided by the IK Team. + +#ifndef _sk_malloc_io_h +#define _sk_malloc_io_h + +#include + +class BMallocIO : public BPositionIO { +public: + BMallocIO(); + virtual ~BMallocIO(); + + virtual ssize_t ReadAt(off_t pos, void *buffer, size_t size); + virtual ssize_t WriteAt(off_t pos, const void *buffer, size_t size); + + virtual off_t Seek(off_t pos, uint32 seekMode); + virtual off_t Position() const; + virtual status_t SetSize(off_t size); + + void SetBlockSize(size_t blockSize); + + const void *Buffer() const; + size_t BufferLength() const; + +private: + status_t _Resize(off_t size); + + virtual void _ReservedMallocIO1(); + virtual void _ReservedMallocIO2(); + + BMallocIO(const BMallocIO &); + BMallocIO &operator=(const BMallocIO &); + +private: + size_t fBlockSize; + size_t fMallocSize; + size_t fLength; + char *fData; + off_t fPosition; + int32 _reserved[1]; +}; + +#endif // _sk_malloc_io_h diff --git a/headers/os/support/StopWatch.h b/headers/os/support/StopWatch.h new file mode 100644 index 0000000000..1a58c4c18f --- /dev/null +++ b/headers/os/support/StopWatch.h @@ -0,0 +1,41 @@ +#ifndef _BLUE_STOP_WATCH_H +#define _BLUE_STOP_WATCH_H + +#include +#include "support/SupportDefs.h" + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS { +#endif + +class BStopWatch { + public: + BStopWatch(const char *name, bool silent = false); + virtual ~BStopWatch(); + + void Suspend(); + void Resume(); + bigtime_t Lap(); + bigtime_t ElapsedTime() const; + void Reset(); + const char *Name() const; + + private: + virtual void _ReservedStopWatch1(); + virtual void _ReservedStopWatch2(); + + bigtime_t fStart; + bigtime_t fSuspendTime; + bigtime_t fLaps[10]; + int32 fLap; + const char *fName; + uint32 _reserved[2]; // these are for fName to be initiased + bool fSilent; +}; + +#ifdef USE_OPENBEOS_NAMESPACE +} // namespace OpenBeOS +using namespace OpenBeOS; +#endif + +#endif /* _STOP_WATCH_H */ diff --git a/headers/os/support/String.h b/headers/os/support/String.h new file mode 100644 index 0000000000..5a55b02dfb --- /dev/null +++ b/headers/os/support/String.h @@ -0,0 +1,9 @@ +/****************************************************************************** +/ +/ File: String.h +/ +/ Description: Header for the BString class +/ +/ Author: Steve Vallee +/ +******************************************************************************/ diff --git a/headers/os/support/SupportDefs.h b/headers/os/support/SupportDefs.h new file mode 100644 index 0000000000..b42669a884 --- /dev/null +++ b/headers/os/support/SupportDefs.h @@ -0,0 +1,167 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: SupportDefs.h +// Author: Erik Jaesler (erik@cgsoftware.com) +// Description: Common type definitions. +//------------------------------------------------------------------------------ + +#ifndef _SUPPORT_DEFS_H +#define _SUPPORT_DEFS_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +#ifndef _SYS_TYPES_H +typedef unsigned long ulong; +typedef unsigned int uint; +typedef unsigned short ushort; +#endif // _SYS_TYPES_H + + +// Shorthand type formats ------------------------------------------------------ + +typedef signed char int8; +typedef unsigned char uint8; +typedef volatile signed char vint8; +typedef volatile unsigned char vuint8; + +typedef short int16; +typedef unsigned short uint16; +typedef volatile short vint16; +typedef volatile unsigned short vuint16; + +typedef long int32; +typedef unsigned long uint32; +typedef volatile long vint32; +typedef volatile unsigned long vuint32; + +typedef long long int64; +typedef unsigned long long uint64; +typedef volatile long long vint64; +typedef volatile unsigned long long vuint64; + +typedef volatile long vlong; +typedef volatile int vint; +typedef volatile short vshort; +typedef volatile char vchar; + +typedef volatile unsigned long vulong; +typedef volatile unsigned int vuint; +typedef volatile unsigned short vushort; +typedef volatile unsigned char vuchar; + +typedef unsigned char uchar; +typedef unsigned short unichar; + + +// Descriptive formats --------------------------------------------------------- +typedef int32 status_t; +typedef int64 bigtime_t; +typedef uint32 type_code; +typedef uint32 perform_code; + + +// Empty string ("") ----------------------------------------------------------- +#ifdef __cplusplus +extern _IMPEXP_BE const char *B_EMPTY_STRING; +#endif + + +// min and max comparisons ----------------------------------------------------- +// min() and max() won't work in C++ +#define min_c(a,b) ((a)>(b)?(b):(a)) +#define max_c(a,b) ((a)>(b)?(a):(b)) + +#ifndef __cplusplus +#ifndef min +#define min(a,b) ((a)>(b)?(b):(a)) +#endif +#ifndef max +#define max(a,b) ((a)>(b)?(a):(b)) +#endif +#endif + + +// Grandfathering -------------------------------------------------------------- + +#ifndef __cplusplus +typedef unsigned char bool; +#define false 0 +#define true 1 +#endif + +#ifndef NULL +#define NULL (0) +#endif + + +//------------------------------------------------------------------------------ +#ifdef __cplusplus +extern "C" { +#endif + +//----- Atomic functions; old value is returned -------------------------------- +extern _IMPEXP_ROOT int32 atomic_add(vint32 *value, int32 addvalue); +extern _IMPEXP_ROOT int32 atomic_and(vint32 *value, int32 andvalue); +extern _IMPEXP_ROOT int32 atomic_or(vint32 *value, int32 orvalue); + +// Other stuff ----------------------------------------------------------------- +extern _IMPEXP_ROOT void * get_stack_frame(void); + +#ifdef __cplusplus +} +#endif + +//-------- Obsolete or discouraged API ----------------------------------------- + +// use 'true' and 'false' +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif + + +//------------------------------------------------------------------------------ + +#endif // _SUPPORT_DEFS_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/headers/os/support/TypeConstants.h b/headers/os/support/TypeConstants.h new file mode 100644 index 0000000000..5fe87ee2e0 --- /dev/null +++ b/headers/os/support/TypeConstants.h @@ -0,0 +1,125 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: TypeConstants.h +// Author: Erik Jaesler (erik@cgsoftware.com) +// Description: Constants that represent distinct data types, as used +// by BMessage et. al. +//------------------------------------------------------------------------------ + +#ifndef _TYPE_CONSTANTS_H +#define _TYPE_CONSTANTS_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + + +// Data Types ------------------------------------------------------------------ + +enum { + B_ANY_TYPE = 'ANYT', + B_BOOL_TYPE = 'BOOL', + B_CHAR_TYPE = 'CHAR', + B_COLOR_8_BIT_TYPE = 'CLRB', + B_DOUBLE_TYPE = 'DBLE', + B_FLOAT_TYPE = 'FLOT', + B_GRAYSCALE_8_BIT_TYPE = 'GRYB', + B_INT64_TYPE = 'LLNG', + B_INT32_TYPE = 'LONG', + B_INT16_TYPE = 'SHRT', + B_INT8_TYPE = 'BYTE', + B_MESSAGE_TYPE = 'MSGG', + B_MESSENGER_TYPE = 'MSNG', + B_MIME_TYPE = 'MIME', + B_MONOCHROME_1_BIT_TYPE = 'MNOB', + B_OBJECT_TYPE = 'OPTR', + B_OFF_T_TYPE = 'OFFT', + B_PATTERN_TYPE = 'PATN', + B_POINTER_TYPE = 'PNTR', + B_POINT_TYPE = 'BPNT', + B_RAW_TYPE = 'RAWT', + B_RECT_TYPE = 'RECT', + B_REF_TYPE = 'RREF', + B_RGB_32_BIT_TYPE = 'RGBB', + B_RGB_COLOR_TYPE = 'RGBC', + B_SIZE_T_TYPE = 'SIZT', + B_SSIZE_T_TYPE = 'SSZT', + B_STRING_TYPE = 'CSTR', + B_TIME_TYPE = 'TIME', + B_UINT64_TYPE = 'ULLG', + B_UINT32_TYPE = 'ULNG', + B_UINT16_TYPE = 'USHT', + B_UINT8_TYPE = 'UBYT', + B_MEDIA_PARAMETER_TYPE = 'BMCT', + B_MEDIA_PARAMETER_WEB_TYPE = 'BMCW', + B_MEDIA_PARAMETER_GROUP_TYPE= 'BMCG', + + // deprecated, do not use + B_ASCII_TYPE = 'TEXT' // use B_STRING_TYPE instead +}; + +//----- System-wide MIME types for handling URL's ------------------------------ + + // To register your application as a handler for a specific URL type, + // mark it as a handler of the corresponding MIME type from the list + // below. When the user clicks on a link in NetPositive that your + // application is a handler for, you will get a B_ARGV_RECEIVED message + // with the full URL as the second argument. +extern _IMPEXP_BE const char *B_URL_HTTP; // application/x-vnd.Be.URL.http +extern _IMPEXP_BE const char *B_URL_HTTPS; // application/x-vnd.Be.URL.https +extern _IMPEXP_BE const char *B_URL_FTP; // application/x-vnd.Be.URL.ftp +extern _IMPEXP_BE const char *B_URL_GOPHER; // application/x-vnd.Be.URL.gopher +extern _IMPEXP_BE const char *B_URL_MAILTO; // application/x-vnd.Be.URL.mailto +extern _IMPEXP_BE const char *B_URL_NEWS; // application/x-vnd.Be.URL.news +extern _IMPEXP_BE const char *B_URL_NNTP; // application/x-vnd.Be.URL.nntp +extern _IMPEXP_BE const char *B_URL_TELNET; // application/x-vnd.Be.URL.telnet +extern _IMPEXP_BE const char *B_URL_RLOGIN; // application/x-vnd.Be.URL.rlogin +extern _IMPEXP_BE const char *B_URL_TN3270; // application/x-vnd.Be.URL.tn3270 +extern _IMPEXP_BE const char *B_URL_WAIS; // application/x-vnd.Be.URL.wais +extern _IMPEXP_BE const char *B_URL_FILE; // application/x-vnd.Be.URL.file + +//----- Obsolete; do not use --------------------------------------------------- + +enum { + _DEPRECATED_TYPE_1_ = 'PATH' +}; + +//------------------------------------------------------------------------------ + +#endif // _TYPE_CONSTANTS_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/headers/os/support/byteorder.h b/headers/os/support/byteorder.h new file mode 100644 index 0000000000..f8fab12b30 --- /dev/null +++ b/headers/os/support/byteorder.h @@ -0,0 +1 @@ +#include diff --git a/headers/os/translation/BitmapStream.h b/headers/os/translation/BitmapStream.h new file mode 100644 index 0000000000..c50f87475a --- /dev/null +++ b/headers/os/translation/BitmapStream.h @@ -0,0 +1,117 @@ +/*****************************************************************************/ +// File: BitmapStream.h +// Class: BBitmapStream +// Reimplimented by: Travis Smith, Michael Wilber, Translation Kit Team +// Reimplimentation: 2002-04 +// +// Description: BPositionIO based object to read/write bitmap format to/from +// a BBitmap object. +// +// The BTranslationUtils class uses this object and makes it +// easy for users to load bitmaps. +// +// Copyright (c) 2002 OpenBeOS Project +// +// Original Version: Copyright 1998, Be Incorporated, All Rights Reserved. +// Copyright 1995-1997, Jon Watte +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ + +#if !defined(_BITMAP_STREAM_H) +#define _BITMAP_STREAM_H + +#include +#include +#include +#include +#include + +class BBitmap; + +class BBitmapStream : public BPositionIO { +public: + BBitmapStream(BBitmap *bitmap = NULL); + // Initializes the stream to use map as the bitmap for stream + // operations. If map is null, a BBitmap is created when properly + // formatted data is written to the stream. + + ~BBitmapStream(); + // Destroys the BBitmap held by this object if it has not been + // detached and frees fpBigEndianHeader + + // Overrides from BPositionIO + ssize_t ReadAt(off_t pos, void *buffer, size_t size); + // reads data from the bitmap into buffer + ssize_t WriteAt(off_t pos, const void *data, size_t size); + // writes the data from data into this bitmap + // (if the data is properly formatted) + off_t Seek(off_t position, uint32 whence); + // sets the stream position member + off_t Position() const; + // returns the current stream position + off_t Size() const; + // returns the size of the data + status_t SetSize(off_t size); + // sets the amount of memory to be used by this object + + status_t DetachBitmap(BBitmap **outMap); + // "Detaches" the bitmap used by this stream and returns it + // to the user through outMap. This allows the user to + // use the bitmap even after the BBitmapStream that it + // came from has been deleted. + +protected: + TranslatorBitmap fHeader; + // stores the bitmap header information in the + // host format, used to determine the format of + // the bitmap data and to see if the data is valid + BBitmap *fBitmap; + // the actual bitmap used by this object + size_t fPosition; + // current data position + size_t fSize; + // size of the data stored + bool fDetached; + // true if the bitmap has been detached, false if not + + static status_t ConvertBEndianToHost(TranslatorBitmap *); + // Converts a TranslatorBitmap struct from the Big Endian + // format to the host format. This is needed because + // the headers are always stored in the Big Endian format + // when read in from or written out to files. + status_t SetBigEndianHeader(); + // Sets fpBigEndianHeader to be the Big Endian version + // of the data in fHeader. I need a Big Endian copy + // of fHeader for the ReadAt() function. + +private: + TranslatorBitmap *fpBigEndianHeader; + // same data as in fHeader, but in Big Endian format + // (Intel machines are Little Endian) + + // For maintaining binary compatibility with past and future + // versions of this object + long fUnused[5]; + virtual void _ReservedBitmapStream1(); + virtual void _ReservedBitmapStream2(); +}; + +#endif /* _BITMAP_STREAM_H */ + diff --git a/headers/os/translation/R4xTranslator.h b/headers/os/translation/R4xTranslator.h new file mode 100644 index 0000000000..2ed8e1e3ae --- /dev/null +++ b/headers/os/translation/R4xTranslator.h @@ -0,0 +1,98 @@ +/*****************************************************************************/ +// File: R4xTranslator.h +// Class: BR4xTranslator +// Author: Michael Wilber, Translation Kit Team +// Originally Created: 2002-06-11 +// +// Description: This header file contains the BTranslator based object for +// BeOS R4.0 and R4.5 type translators, aka, the translators +// that don't use the make_nth_translator() mechanism. +// +// This class is used by the OpenBeOS BTranslatorRoster +// so that R4x translators, post R4.5 translators and private +// BTranslator objects could be accessed in the same way. +// +// +// Copyright (c) 2002 OpenBeOS Project +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ + +#ifndef _R4X_TRANSLATOR_H +#define _R4X_TRANSLATOR_H + +#include +#include +#include + +class BR4xTranslator : public BTranslator { +public: + BR4xTranslator(const translator_data *kpData); + // assigns the translator to the object + + virtual const char *TranslatorName() const; + // returns the short translator name + + virtual const char *TranslatorInfo() const; + // returns the verbose translator name/description + + virtual int32 TranslatorVersion() const; + // returns the translator's version + + virtual const translation_format *InputFormats(int32 *out_count) const; + // returns the list of supported input formats + + virtual const translation_format *OutputFormats(int32 *out_count) const; + // returns the list of supported output formats + + virtual status_t Identify(BPositionIO *inSource, + const translation_format *inFormat, BMessage *ioExtension, + translator_info *outInfo, uint32 outType); + // identifies wether or not the translator can handle + // translating the data in inSource + + virtual status_t Translate(BPositionIO *inSource, + const translator_info *inInfo, BMessage *ioExtension, uint32 outType, + BPositionIO * outDestination); + // translates the data from inSource to outDestination + // in the format outType + + virtual status_t MakeConfigurationView(BMessage *ioExtension, + BView **outView, BRect *outExtent); + // creates a view object that allows the user to change + // the translator's options + // (not required to be in all translators) + + virtual status_t GetConfigurationMessage(BMessage *ioExtension); + // returns the current settings of the translator + // (not required to be in all translators) + +protected: + virtual ~BR4xTranslator(); + // This object is deleted by calling Release(), + // it can not be deleted directly. See BTranslator in the Be Book + +private: + translator_data *fpData; + // This contains all of the member variables used by this class. + // It also contains pointers to functions that the member functions + // use to do all of the actual work for this class. +}; + +#endif // _R4X_TRANSLATOR_H diff --git a/headers/os/translation/TranslationDefs.h b/headers/os/translation/TranslationDefs.h new file mode 100644 index 0000000000..758f686e96 --- /dev/null +++ b/headers/os/translation/TranslationDefs.h @@ -0,0 +1,86 @@ +/******************************************************************************** +/ +/ File: TranslationDefs.h +/ +/ Description: Miscellaneous basic definitions for the Translation Kit +/ +/ Copyright 1998, Be Incorporated, All Rights Reserved. +/ Copyright 1995-1997, Jon Watte +/ +/ 2002 - translation_data struct added by Michael Wilber, OBOS TransKit Team +********************************************************************************/ + +#if !defined(_TRANSLATION_DEFS_H) +#define _TRANSLATION_DEFS_H + +#include +#include +#include + + +typedef unsigned long translator_id; + + +/* when you export this struct, end with an empty */ +/* record that has 0 for "type" */ + + +/* These are defines, because they reflect the state at which the app was compiled */ +#define B_TRANSLATION_CURRENT_VERSION B_BEOS_VERSION +#define B_TRANSLATION_MIN_VERSION 161 + +extern const char * B_TRANSLATOR_MIME_TYPE; + +struct translation_format { + uint32 type; /* B_ASCII_TYPE, ...*/ + uint32 group; /* B_TRANSLATOR_BITMAP, B_TRANSLATOR_TEXT, ...*/ + float quality; /* format quality 0.0-1.0*/ + float capability; /* translator capability 0.0-1.0*/ + char MIME[251]; /* MIME string*/ + char name[251]; /* only descriptive */ +}; + + +/* This struct is different from the format struct for a reason: */ +/* to separate the notion of formats from the notion of translations */ + +struct translator_info { /* Info about a specific translation*/ + uint32 type; /* B_ASCII_TYPE, ...*/ + translator_id translator; /* Filled in by BTranslationRoster*/ + uint32 group; /* B_TRANSLATOR_BITMAP, B_TRANSLATOR_TEXT, ...*/ + float quality; /* Quality of format in group 0.0-1.0*/ + float capability; /* How much of the format do we do? 0.0-1.0*/ + char name[251]; + char MIME[251]; +}; + +// BEGIN: Added by Michael Wilber +struct translator_data { + const char * translatorName; + const char * translatorInfo; + int32 translatorVersion; + const translation_format * inputFormats; + const translation_format * outputFormats; + + status_t (*Identify)( + BPositionIO * inSource, + const translation_format * inFormat, + BMessage * ioExtension, + translator_info * outInfo, + uint32 outType); + status_t (*Translate)( + BPositionIO * inSource, + const translator_info * inInfo, + BMessage * ioExtension, + uint32 outType, + BPositionIO * outDestination); + status_t (*MakeConfig)( + BMessage * ioExtension, + BView * * outView, + BRect * outExtent); + status_t (*GetConfigMessage)( + BMessage * ioExtension); +}; +// END: Added by Michael Wilber + +#endif /* _TRANSLATION_DEFS_H */ diff --git a/headers/os/translation/TranslationErrors.h b/headers/os/translation/TranslationErrors.h new file mode 100644 index 0000000000..e4965123e5 --- /dev/null +++ b/headers/os/translation/TranslationErrors.h @@ -0,0 +1,27 @@ +/******************************************************************************** +/ +/ File: TranslationErrors.h +/ +/ Description: Error codes for the Translation Kit +/ +/ Copyright 1998, Be Incorporated, All Rights Reserved. +/ Copyright 1995-1997, Jon Watte +/ +********************************************************************************/ + +#if !defined(_TRANSLATION_ERRORS_H) +#define _TRANSLATION_ERRORS_H + +#include + + +enum B_TRANSLATION_ERROR { + B_TRANSLATION_BASE_ERROR = B_TRANSLATION_ERROR_BASE, + B_NO_TRANSLATOR = B_TRANSLATION_BASE_ERROR, /* no translator exists for data */ + B_ILLEGAL_DATA, /* data is not what it said it was */ +/* aliases */ + B_NOT_INITIALIZED = B_NO_INIT +}; + + +#endif /* _TRANSLATION_ERRORS_H */ diff --git a/headers/os/translation/TranslationKit.h b/headers/os/translation/TranslationKit.h new file mode 100644 index 0000000000..c334eae58f --- /dev/null +++ b/headers/os/translation/TranslationKit.h @@ -0,0 +1,18 @@ +/*************************************************************** +/ +/ File: TranslationKit.h +/ +/ Copyright 1998, Be Incorporated. +/ +***************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +/* we do not include TranslatorAddOn.h because it's only used when building an add-on */ + diff --git a/headers/os/translation/TranslationUtils.h b/headers/os/translation/TranslationUtils.h new file mode 100644 index 0000000000..99102ffa25 --- /dev/null +++ b/headers/os/translation/TranslationUtils.h @@ -0,0 +1,137 @@ +/*****************************************************************************/ +// File: TranslationUtils.h +// Class: BTranslationUtils +// Reimplimented by: Michael Wilber, Translation Kit Team +// Reimplimentation: 2002-04 +// +// Description: Utility functions for the Translation Kit +// +// +// Copyright (c) 2002 OpenBeOS Project +// +// Original Version: Copyright 1998, Be Incorporated, All Rights Reserved. +// Copyright 1995-1997, Jon Watte +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ + +#if !defined(_TRANSLATION_UTILS_H) +#define _TRANSLATION_UTILS_H + +#include +#include + +class BBitmap; +class BTranslatorRoster; +class BPositionIO; +class BMenu; + +// This class is a little different from many other classes. +// You don't create an instance of it; you just call its various +// static member functions for utility-like operations. +class BTranslationUtils { + BTranslationUtils(); + ~BTranslationUtils(); + BTranslationUtils(const BTranslationUtils &); + BTranslationUtils & operator=(const BTranslationUtils &); + +public: + +// BITMAP getters - allocate the BBitmap; you call delete on it! + +static BBitmap *GetBitmap(const char *kName, BTranslatorRoster *roster = NULL); + // Get bitmap - first try as file name, then as B_TRANSLATOR_BITMAP + // resource type from app file -- can be of any kind for which a + // translator is installed (TGA, etc) + +static BBitmap *GetBitmap(uint32 type, int32 id, + BTranslatorRoster *roster = NULL); + // Get bitmap - from app resource by id + +static BBitmap *GetBitmap(uint32 type, const char *kName, + BTranslatorRoster *roster = NULL); + // Get Bitmap - from app resource by name + +static BBitmap *GetBitmapFile(const char *kName, + BTranslatorRoster *roster = NULL); + // Get bitmap - from file only + +static BBitmap *GetBitmap(const entry_ref *kRef, + BTranslatorRoster *roster = NULL); + // Get bitmap - from open file (or BMemoryIO) + +static BBitmap *GetBitmap(BPositionIO *stream, + BTranslatorRoster *roster = NULL); + // Get bitmap - from open file or IO type object + +static status_t GetStyledText(BPositionIO *fromStream, BTextView *intoView, + BTranslatorRoster *roster = NULL); + // For styled text, we can translate from a stream + // directly into a BTextView + +static status_t PutStyledText(BTextView *fromView, BPositionIO *intoStream, + BTranslatorRoster *roster = NULL); + // Saving is slightly different -- given the BTextView, a + // B_STYLED_TEXT_FORMAT stream is written to intoStream. You can then call + // Translate() yourself to translate that stream into something else if + // you want, if it is a temp file or a BMallocIO. It's also OK to write + // the B_STYLED_TEXT_FORMAT to a file, although the StyledEdit format + // (TEXT file + style attributes) is preferred. This convenience function + // is only marginally part of the Translation Kit, but what the hey :-) + +static status_t WriteStyledEditFile(BTextView *fromView, BFile *intoFile); + // Writes the styled text data from fromView to intoFile + +static BMessage *GetDefaultSettings(translator_id forTranslator, + BTranslatorRoster *roster = NULL); + // Get default settings for the translator with the id forTranslator + +static BMessage *GetDefaultSettings(const char *kTranslatorName, + int32 translatorVersion); + // Get default settings for the translator with the name kTranslatorName + +// Envious of that "Save As" menu in ShowImage? Well, you can have your own! +// AddTranslationItems will add menu items for all translations from the +// basic format you specify (B_TRANSLATOR_BITMAP, B_TRANSLATOR_TEXT etc). +// The translator ID and format constant chosen will be added to the message +// that is sent to you when the menu item is selected. + enum { + B_TRANSLATION_MENU = 'BTMN' + }; +static status_t AddTranslationItems(BMenu *intoMenu, uint32 fromType, + const BMessage *kModel = NULL, // default B_TRANSLATION_MENU + const char *kTranslatorIdName = NULL, // default "be:translator" + const char *kTranslatorTypeName = NULL, // default "be:type" + BTranslatorRoster *roster = NULL); + +// BEGIN: Added by Michael Wilber +private: + +static BBitmap * TranslateToBitmap(BPositionIO *pio, + BTranslatorRoster *roster = NULL); + // Translates the image data from pio to the type type using the + // supplied BTranslatorRoster. If BTranslatorRoster is not supplied + // the default BTranslatorRoster is used. + +// END: Added by Michael Wilber + +}; + +#endif /* _TRANSLATION_UTILS_H */ + diff --git a/headers/os/translation/Translator.h b/headers/os/translation/Translator.h new file mode 100644 index 0000000000..0dffa72e5c --- /dev/null +++ b/headers/os/translation/Translator.h @@ -0,0 +1,137 @@ +/*****************************************************************************/ +// File: Translator.h +// Class: BTranslator +// Reimplimented by: Michael Wilber, Translation Kit Team +// Reimplimentation: 2002-06-15 +// +// Description: This file contains the BTranslator class, the base class for +// all translators that don't use the BeOS R4/R4.5 add-on method. +// +// +// Copyright (c) 2002 OpenBeOS Project +// +// Original Version: Copyright 1998, Be Incorporated, All Rights Reserved. +// Copyright 1995-1997, Jon Watte +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ +#ifndef _TRANSLATOR_H +#define _TRANSLATOR_H + +#include +#include + +class BTranslator : public BArchivable { +public: + BTranslator(); + // Sets refcount to 1 (the object is initially Acquired()'d once) + + BTranslator *Acquire(); + // return actual object and increment the refcount + + BTranslator *Release(); + // Decrements the refcount and returns pointer to the object. + // When the refcount is zero, NULL is returned and the object is + // deleted + + int32 ReferenceCount(); + // returns the refcount, THIS IS NOT THREAD SAFE, ITS ONLY FOR "FUN" + + virtual const char *TranslatorName() const = 0; + // returns the short name of the translator + + virtual const char *TranslatorInfo() const = 0; + // returns a verbose name/description for the translator + + virtual int32 TranslatorVersion() const = 0; + // returns the version of the translator + + virtual const translation_format *InputFormats(int32 *out_count) + const = 0; + // returns the input formats and the count of input formats + // that this translator supports + + virtual const translation_format *OutputFormats(int32 *out_count) + const = 0; + // returns the output formats and the count of output formats + // that this translator supports + + virtual status_t Identify(BPositionIO *inSource, + const translation_format *inFormat, BMessage *ioExtension, + translator_info *outInfo, uint32 outType) = 0; + // determines whether or not this translator can convert the + // data in inSource to the type outType + + virtual status_t Translate(BPositionIO *inSource, + const translator_info *inInfo, BMessage *ioExtension, + uint32 outType, BPositionIO *outDestination) = 0; + // this function is the whole point of the Translation Kit, + // it translates the data in inSource to outDestination + // using the format outType + + virtual status_t MakeConfigurationView(BMessage *ioExtension, + BView **outView, BRect *outExtent); + // this function creates a view that allows the user to + // configure the translator, this function is not + // required for all translators + + virtual status_t GetConfigurationMessage(BMessage *ioExtension); + // puts information about the current configuration of the + // translator into ioExtension so that it can be used with + // Identify or Translate or whatever, this function is + // not required for all translators + +protected: + virtual ~BTranslator(); + // this is protected because the object is deleted by the + // Release() function instead of being deleted directly by + // the user + +private: + int32 fRefCount; + // number of times this object has been referenced + // by the Acquire() function + + sem_id fSem; + // used to lock object for Acquire() and Release() + + // For binary compatibility with past and future + // version of this class + uint32 fUnused[8]; + virtual status_t _Reserved_Translator_0(int32, void *); + virtual status_t _Reserved_Translator_1(int32, void *); + virtual status_t _Reserved_Translator_2(int32, void *); + virtual status_t _Reserved_Translator_3(int32, void *); + virtual status_t _Reserved_Translator_4(int32, void *); + virtual status_t _Reserved_Translator_5(int32, void *); + virtual status_t _Reserved_Translator_6(int32, void *); + virtual status_t _Reserved_Translator_7(int32, void *); +}; + +// The post-4.5 API suggests implementing this function in your translator +// add-on rather than the separate functions and variables of the previous +// API. You will be called for values of n starting at 0 and increasing; +// return 0 when you can't make another kind of translator (i.e. for n=1 +// if you only implement one subclass of BTranslator). Ignore flags for now. +extern "C" _EXPORT BTranslator *make_nth_translator(int32 n, image_id you, + uint32 flags, ...); + + + +#endif /* _TRANSLATOR_H */ diff --git a/headers/os/translation/TranslatorAddOn.h b/headers/os/translation/TranslatorAddOn.h new file mode 100644 index 0000000000..551df235bc --- /dev/null +++ b/headers/os/translation/TranslatorAddOn.h @@ -0,0 +1,92 @@ +/******************************************************************************** +/ +/ File: TranslatorAddOn.h +/ +/ Description: This header file defines the interface that should be +/ implemented and exported by a Tanslation Kit add-on. +/ You will only need to include this header when building +/ an actual add-on, not when just using the kit. +/ +/ Copyright 1998, Be Incorporated, All Rights Reserved. +/ Copyright 1995-1997, Jon Watte +/ +********************************************************************************/ + +#ifndef _TRANSLATOR_ADD_ON_H +#define _TRANSLATOR_ADD_ON_H + +#include + + +class BView; +class BRect; +class BPositionIO; + + +/* This is the 4.0 and 4.5 compatible API. For later versions, use the */ +/* BTranslator-based API (make_nth_translator) */ + +/* These variables and functions should be exported by a translator add-on */ + +extern "C" { + +_EXPORT extern char translatorName[]; /* required, C string, ex "Jon's Sound" */ +_EXPORT extern char translatorInfo[]; /* required, descriptive C string, ex "Jon's Sound Translator (shareware $5: user@mail.net) v1.00" */ +_EXPORT extern int32 translatorVersion; /* required, integer, ex 100 */ + +_EXPORT extern translation_format inputFormats[]; /* optional (else Identify is always called) */ +_EXPORT extern translation_format outputFormats[]; /* optional (else Translate is called anyway) */ + /* Translators that don't export outputFormats */ + /* will not be considered by files looking for */ + /* specific output formats. */ + + /* Return B_NO_TRANSLATOR if not handling this data. */ + /* Even if inputFormats exists, may be called for data without hints */ + /* Ff outType is not 0, must be able to export in wanted format */ + +_EXPORT extern status_t Identify( /* required */ + BPositionIO * inSource, + const translation_format * inFormat, /* can beNULL */ + BMessage * ioExtension, /* can be NULL */ + translator_info * outInfo, + uint32 outType); + + /* Return B_NO_TRANSLATOR if not handling the output format */ + /* If outputFormats exists, will only be called for those formats */ + +_EXPORT extern status_t Translate( /* required */ + BPositionIO * inSource, + const translator_info * inInfo, + BMessage * ioExtension, /* can be NULL */ + uint32 outType, + BPositionIO * outDestination); + + /* The view will get resized to what the parent thinks is */ + /* reasonable. However, it will still receive MouseDowns etc. */ + /* Your view should change settings in the translator immediately, */ + /* taking care not to change parameters for a translation that is */ + /* currently running. Typically, you'll have a global struct for */ + /* settings that is atomically copied into the translator function */ + /* as a local when translation starts. */ + /* Store your settings wherever you feel like it. */ + +_EXPORT extern status_t MakeConfig( /* optional */ + BMessage * ioExtension, /* can be NULL */ + BView * * outView, + BRect * outExtent); + + /* Copy your current settings to a BMessage that may be passed */ + /* to BTranslators::Translate at some later time when the user wants to */ + /* use whatever settings you're using right now. */ + +_EXPORT extern status_t GetConfigMessage( /* optional */ + BMessage * ioExtension); + + +} + + + +#endif /* _TRANSLATOR_ADD_ON_H */ + + diff --git a/headers/os/translation/TranslatorFormats.h b/headers/os/translation/TranslatorFormats.h new file mode 100644 index 0000000000..93b6e4d187 --- /dev/null +++ b/headers/os/translation/TranslatorFormats.h @@ -0,0 +1,179 @@ +/******************************************************************************** +/ +/ File: TranslatorFormats.h +/ +/ Description: Defines for common "lowest common denominator" formats +/ used in the Translation Kit. +/ +/ Copyright 1998, Be Incorporated, All Rights Reserved. +/ Copyright 1995-1997, Jon Watte +/ +********************************************************************************/ + + +#ifndef _TRANSLATOR_FORMATS_H +#define _TRANSLATOR_FORMATS_H + + +#include +#include + +/* extensions used in the extension BMessage. Use of these */ +/* is described in the documentation. */ + +_IMPEXP_TRANSLATION extern char B_TRANSLATOR_EXT_HEADER_ONLY[]; +_IMPEXP_TRANSLATION extern char B_TRANSLATOR_EXT_DATA_ONLY[]; +_IMPEXP_TRANSLATION extern char B_TRANSLATOR_EXT_COMMENT[]; +_IMPEXP_TRANSLATION extern char B_TRANSLATOR_EXT_TIME[]; +_IMPEXP_TRANSLATION extern char B_TRANSLATOR_EXT_FRAME[]; +_IMPEXP_TRANSLATION extern char B_TRANSLATOR_EXT_BITMAP_RECT[]; +_IMPEXP_TRANSLATION extern char B_TRANSLATOR_EXT_BITMAP_COLOR_SPACE[]; +_IMPEXP_TRANSLATION extern char B_TRANSLATOR_EXT_BITMAP_PALETTE[]; +_IMPEXP_TRANSLATION extern char B_TRANSLATOR_EXT_SOUND_CHANNEL[]; +_IMPEXP_TRANSLATION extern char B_TRANSLATOR_EXT_SOUND_MONO[]; +_IMPEXP_TRANSLATION extern char B_TRANSLATOR_EXT_SOUND_MARKER[]; +_IMPEXP_TRANSLATION extern char B_TRANSLATOR_EXT_SOUND_LOOP[]; + +#if defined(_DATATYPES_COMPATIBLE_) +#define kCommentExtension "/comment" +#define kTimeExtension "/time" +#define kFrameExtension "/frame" +#define kBitsRectExtension "bits/Rect" +#define kBitsSpaceExtension "bits/space" +#define kHeaderExtension "/headerOnly" +#define kDataExtension "/dataOnly" +#define kNoisChannelExtension "nois/channel" +#define kNoisMonoExtension "nois/mono" +#define kNoisMarkerExtension "nois/marker" +#define kNoisLoopExtension "nois/loop" +#endif + + +/* For each data group, there is a "standard" format that */ +/* all translators should support. */ +/* These type codes are lower-case because they are already */ +/* established standards in the Be developer community. */ +enum TranslatorGroups { + B_TRANSLATOR_BITMAP = 'bits', /* TranslatorBitmap */ + B_TRANSLATOR_PICTURE = 'pict', /* BPicture data */ + B_TRANSLATOR_TEXT = 'TEXT', /* B_ASCII_TYPE */ + B_TRANSLATOR_SOUND = 'nois', /* TranslatorSound */ + B_TRANSLATOR_MIDI = 'midi', /* standard MIDI */ + B_TRANSLATOR_MEDIA = 'mhi!', /* a stream of stuff */ + B_TRANSLATOR_NONE = 'none', + B_TRANSLATOR_ANY_TYPE = 0 +}; +#if defined(_DATATYPES_COMPATIBLE_) +#define kAnyType 0 +#endif + + +/* some pre-defined data format type codes */ + +enum { +/* bitmap formats (B_TRANSLATOR_BITMAP) */ + B_GIF_FORMAT = 'GIF ', + B_JPEG_FORMAT = 'JPEG', + B_PNG_FORMAT = 'PNG ', + B_PPM_FORMAT = 'PPM ', + B_TGA_FORMAT = 'TGA ', + B_BMP_FORMAT = 'BMP ', + B_TIFF_FORMAT = 'TIFF', + +/* line drawing formats (B_TRANSLATOR_PICTURE) */ + B_DXF_FORMAT = 'DXF ', + B_EPS_FORMAT = 'EPS ', + B_PICT_FORMAT = 'PICT', /* MacOS PICT file */ + +/* sound file formats (B_TRANSLATOR_SOUND) */ + B_WAV_FORMAT = 'WAV ', + B_AIFF_FORMAT = 'AIFF', + B_CD_FORMAT = 'CD ', /* 44 kHz, stereo, 16 bit, linear, big-endian */ + B_AU_FORMAT = 'AU ', /* Sun ulaw */ + +/* text file formats (B_TRANSLATOR_TEXT) */ + B_STYLED_TEXT_FORMAT = 'STXT' +}; + + + +/* This is the standard bitmap format */ +/* Note that data is always in big-endian format in the stream! */ +struct TranslatorBitmap { + uint32 magic; /* B_TRANSLATOR_BITMAP */ + BRect bounds; + uint32 rowBytes; + color_space colors; + uint32 dataSize; +}; /* data follows, padded to rowBytes */ + +/* This is the standard sound format */ +/* Note that data is always in big-endian format in the stream! */ +struct TranslatorSound { + uint32 magic; /* B_TRANSLATOR_SOUND */ + uint32 channels; /* Left should always be first */ + float sampleFreq; /* 16 bit linear is assumed */ + uint32 numFrames; +}; /* data follows */ + +/* This is the standard styled text format */ +/* Note that it is of group type text! */ +/* Skip any records types you don't know about. */ +/* Always big-endian. */ +struct TranslatorStyledTextRecordHeader { + uint32 magic; + uint32 header_size; + uint32 data_size; +}; /* any number of records */ +struct TranslatorStyledTextStreamHeader { +#if defined(__cplusplus) + enum { + STREAM_HEADER_MAGIC = 'STXT' + }; +#endif + TranslatorStyledTextRecordHeader header; + int32 version; /* 100 */ +}; /* no data for this header */ +struct TranslatorStyledTextTextHeader { +#if defined(__cplusplus) + enum { + TEXT_HEADER_MAGIC = 'TEXT' + }; +#endif + TranslatorStyledTextRecordHeader header; + int32 charset; /* Always write B_UTF8 for now! */ +}; /* text data follows */ +struct TranslatorStyledTextStyleHeader { +#if defined(__cplusplus) + enum { + STYLE_HEADER_MAGIC = 'STYL' + }; +#endif + TranslatorStyledTextRecordHeader header; + uint32 apply_offset; + uint32 apply_length; +}; /* flattened R3 BTextView style records for preceding text */ +#if 0 +/* format of the STYL record data (always big-endian) FYI: */ +struct { + uchar magic[4]; /* 41 6c 69 21 */ + uchar version[4]; /* 00 00 00 00 */ + int32 count; + struct { + int32 offset; + char family[64]; + char style[64]; + float size; + float shear; /* typically 90.0 */ + uint16 face; /* typically 0 */ + uint8 red; + uint8 green; + uint8 blue; + uint8 alpha; /* 255 == opaque */ + uint16 _reserved_; /* 0 */ + } styles[]; +}; +#endif + +#endif /* _TRANSLATOR_FORMATS_H */ + diff --git a/headers/os/translation/TranslatorRoster.h b/headers/os/translation/TranslatorRoster.h new file mode 100644 index 0000000000..b14348ea5c --- /dev/null +++ b/headers/os/translation/TranslatorRoster.h @@ -0,0 +1,238 @@ +/*****************************************************************************/ +// File: TranslatorRoster.h +// Class: BTranslatorRoster +// Reimplimented by: Michael Wilber, Translation Kit Team +// Reimplimentation: 2002-06-11 +// +// Description: This class is the guts of the translation kit, it makes the +// whole thing happen. It bridges the applications using this +// object with the translators that the apps need to access. +// +// +// Copyright (c) 2002 OpenBeOS Project +// +// Original Version: Copyright 1998, Be Incorporated, All Rights Reserved. +// Copyright 1995-1997, Jon Watte +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ + +#ifndef _TRANSLATOR_ROSTER_H +#define _TRANSLATOR_ROSTER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct translation_format; + +class BBitmap; +class BView; +class BPositionIO; +class BQuery; +class BMessage; + +const char kgDefaultTranslatorPath[] = "/boot/home/config/add-ons/Translators:/boot/home/config/add-ons/Datatypes:/system/add-ons/Translators"; + +// used by BTranslatorRoster to store the list of translators +struct translator_node { + BTranslator *translator; + char *path; + image_id image; + translator_id id; + translator_node *next; +}; + +class BTranslatorRoster : public BArchivable { + // private, unimplemented functions + // (I'm not sure if there is a need for them anyway) + BTranslatorRoster(const BTranslatorRoster &); + BTranslatorRoster & operator=(const BTranslatorRoster &); + +public: + BTranslatorRoster(); + // initializes the object with no translators + + BTranslatorRoster(BMessage *model); + // initializes the object and loads all translators from the + // "be:translator_path" string array in model + + ~BTranslatorRoster(); + // frees memory used by this object + + virtual status_t Archive(BMessage *into, bool deep = true) const; + // store the BTranslatorRoster in into so it can later be + // used with Instantiate or the BMessage constructor + + static BArchivable *Instantiate(BMessage *from); + // creates a BTranslatorRoster object from the from archive + + static const char *Version(int32 *outCurVersion, int32 *outMinVersion, + int32 inAppVersion = B_TRANSLATION_CURRENT_VERSION); + // returns the version of BTranslator roster as a string + // and through the int32 pointers; inAppVersion appears + // to be ignored + + static BTranslatorRoster *Default(); + // returns the "default" set of translators, they are translators + // that are loaded from the default paths + // /boot/home/config/add-ons/Translators, + // /boot/home/config/add-ons/Datatypes, + // /system/add-ons/Translators or the paths in the + // TRANSLATORS environment variable, if it exists + + status_t AddTranslators(const char *load_path = NULL); + // this adds a translator, all of the translators in a folder or + // the default translators if the path is NULL + + status_t AddTranslator(BTranslator * translator); + // adds a translator that you've created yourself to the + // BTranslatorRoster; this is useful if you have translators + // that you don't want to make public or don't want loaded as + // an add-on + + virtual status_t Identify(BPositionIO *inSource, BMessage *ioExtension, + translator_info *outInfo, uint32 inHintType = 0, + const char *inHintMIME = NULL, uint32 inWantType = 0); + // identifies the translator that can handle the data in inSource + + virtual status_t GetTranslators(BPositionIO *inSource, + BMessage *ioExtension, translator_info **outInfo, int32 *outNumInfo, + uint32 inHintType = 0, const char *inHintMIME = NULL, + uint32 inWantType = 0); + // finds all translators for the given type + + virtual status_t GetAllTranslators(translator_id **outList, + int32 *outCount); + // returns all translators that this object contains + + virtual status_t GetTranslatorInfo(translator_id forTranslator, + const char **outName, const char **outInfo, int32 *outVersion); + // gets user visible info about a specific translator + + virtual status_t GetInputFormats(translator_id forTranslator, + const translation_format **outFormats, int32 *outNumFormats); + // finds all input formats for a translator; + // note that translators don't always publish the formats + // that they support + + virtual status_t GetOutputFormats(translator_id forTranslator, + const translation_format **outFormats, int32 *outNumFormats); + // finds all output formats for a translator; + // note that translators don't always publish the formats + // that they support + + virtual status_t Translate(BPositionIO *inSource, + const translator_info *inInfo, BMessage *ioExtension, + BPositionIO *outDestination, uint32 inWantOutType, + uint32 inHintType = 0, const char *inHintMIME = NULL); + // the whole point of this entire kit boils down to this function; + // this translates the data in inSource into outDestination + // using the format inWantOutType + + virtual status_t Translate(translator_id inTranslator, + BPositionIO *inSource, BMessage *ioExtension, + BPositionIO *outDestination, uint32 inWantOutType); + // the whole point of this entire kit boils down to this function; + // this translates the data in inSource into outDestination + // using the format inWantOutType and the translator inTranslator + + virtual status_t MakeConfigurationView(translator_id forTranslator, + BMessage *ioExtension, BView **outView, BRect *outExtent); + // create the view for forTranslator that allows the user + // to configure it; + // NOTE: translators are not required to support this function + + virtual status_t GetConfigurationMessage(translator_id forTranslator, + BMessage *ioExtension); + // this is used to save the settings for a translator so that + // they can be written to disk or used in an Indentify or + // Translate call + + status_t GetRefFor(translator_id translator, entry_ref *out_ref); + // I'm guessing that this returns the entry_ref for the + // translator add-on file for the translator_id translator + +private: + void Initialize(); + // class initialization code used by all constructors + + translator_node *FindTranslatorNode(translator_id id); + // used to find the translator_node for the translator_id id + // returns NULL if the id is not valid + + status_t LoadTranslator(const char *path); + // loads the translator add-on specified by path + + void LoadDir(const char *path, int32 &loadErr, int32 &nLoaded); + // loads all of the translator add-ons from path and + // returns error status in loadErr and the number of + // translators loaded in nLoaded + + bool CheckFormats(const translation_format *inputFormats, + int32 inputFormatsCount, uint32 hintType, const char *hintMIME, + const translation_format **outFormat); + // determines how the Identify function is called + + // adds the translator to the list of translators + // that this object maintains + status_t AddTranslatorToList(BTranslator *translator); + status_t AddTranslatorToList(BTranslator *translator, + const char *path, image_id image, bool acquire); + + static BTranslatorRoster *fspDefaultTranslators; + // object that contains the default translators + translator_node *fpTranslators; + // list of translators maintained by this object + sem_id fSem; + // semaphore used to lock this object + + // used to maintain binary combatibility with + // past and future versions of this object + int32 fUnused[5]; + virtual void ReservedTranslatorRoster1(); + virtual void ReservedTranslatorRoster2(); + virtual void ReservedTranslatorRoster3(); + virtual void ReservedTranslatorRoster4(); + virtual void ReservedTranslatorRoster5(); + virtual void ReservedTranslatorRoster6(); +}; + +#endif /* _TRANSLATOR_ROSTER_H */ + diff --git a/headers/posix/arpa/inet.h b/headers/posix/arpa/inet.h new file mode 100644 index 0000000000..9e10b1dde9 --- /dev/null +++ b/headers/posix/arpa/inet.h @@ -0,0 +1,26 @@ +/* arpa/inet.h */ + +/* public definitions of inet functions... */ + +#ifndef _INET_H_ +#define _INET_H_ + +#include +#include + +in_addr_t inet_addr (const char *); +int inet_aton (const char *, struct in_addr *); +in_addr_t inet_lnaof (struct in_addr); +struct in_addr inet_makeaddr (in_addr_t , in_addr_t); +char * inet_neta (in_addr_t, char *, size_t); +in_addr_t inet_netof (struct in_addr); +in_addr_t inet_network (const char *); +char *inet_net_ntop (int, const void *, int, char *, size_t); +int inet_net_pton (int, const char *, void *, size_t); +char *inet_ntoa (struct in_addr); +int inet_pton (int, const char *, void *); +const char *inet_ntop (int, const void *, char *, size_t); +u_int inet_nsap_addr (const char *, u_char *, int); +char *inet_nsap_ntoa (int, const u_char *, char *); + +#endif /* _INET_H */ diff --git a/headers/posix/arpa/nameser.h b/headers/posix/arpa/nameser.h new file mode 100644 index 0000000000..4e747a764b --- /dev/null +++ b/headers/posix/arpa/nameser.h @@ -0,0 +1,395 @@ +/* $OpenBSD: nameser.h,v 1.6 2001/07/31 22:02:18 jakob Exp $ */ + +/* + * ++Copyright++ 1983, 1989, 1993 + * - + * Copyright (c) 1983, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + * --Copyright-- + */ + +/* + * @(#)nameser.h 8.1 (Berkeley) 6/2/93 + * $From: nameser.h,v 8.11 1996/10/08 04:51:02 vixie Exp $ + */ + +#ifndef _NAMESER_H_ +#define _NAMESER_H_ + +#include +#include + +#ifdef _AUX_SOURCE +# include +#endif + +/* + * revision information. this is the release date in YYYYMMDD format. + * it can change every day so the right thing to do with it is use it + * in preprocessor commands such as "#if (__BIND > 19931104)". do not + * compare for equality; rather, use it to determine whether your resolver + * is new enough to contain a certain feature. + */ + +#define __BIND 19960801 /* interface version stamp */ + +/* + * Define constants based on rfc883 + */ +#define PACKETSZ 512 /* maximum packet size */ +#define MAXDNAME 1025 /* maximum presentation domain name */ +#define MAXCDNAME 255 /* maximum compressed domain name */ +#define MAXLABEL 63 /* maximum length of domain label */ +#define HFIXEDSZ 12 /* #/bytes of fixed data in header */ +#define QFIXEDSZ 4 /* #/bytes of fixed data in query */ +#define RRFIXEDSZ 10 /* #/bytes of fixed data in r record */ +#define INT32SZ 4 /* for systems without 32-bit ints */ +#define INT16SZ 2 /* for systems without 16-bit ints */ +#define INADDRSZ 4 /* IPv4 T_A */ +#define IN6ADDRSZ 16 /* IPv6 T_AAAA */ + +/* + * Internet nameserver port number + */ +#define NAMESERVER_PORT 53 + +/* + * Currently defined opcodes + */ +#define QUERY 0x0 /* standard query */ +#define IQUERY 0x1 /* inverse query */ +#define STATUS 0x2 /* nameserver status query */ +/*#define xxx 0x3*/ /* 0x3 reserved */ +#define NS_NOTIFY_OP 0x4 /* notify secondary of SOA change */ +/* + * Currently defined response codes + */ +#define NOERROR 0 /* no error */ +#define FORMERR 1 /* format error */ +#define SERVFAIL 2 /* server failure */ +#define NXDOMAIN 3 /* non existent domain */ +#define NOTIMP 4 /* not implemented */ +#define REFUSED 5 /* query refused */ + +/* + * Type values for resources and queries + */ +#define T_A 1 /* host address */ +#define T_NS 2 /* authoritative server */ +#define T_MD 3 /* mail destination */ +#define T_MF 4 /* mail forwarder */ +#define T_CNAME 5 /* canonical name */ +#define T_SOA 6 /* start of authority zone */ +#define T_MB 7 /* mailbox domain name */ +#define T_MG 8 /* mail group member */ +#define T_MR 9 /* mail rename name */ +#define T_NULL 10 /* null resource record */ +#define T_WKS 11 /* well known service */ +#define T_PTR 12 /* domain name pointer */ +#define T_HINFO 13 /* host information */ +#define T_MINFO 14 /* mailbox information */ +#define T_MX 15 /* mail routing information */ +#define T_TXT 16 /* text strings */ +#define T_RP 17 /* responsible person */ +#define T_AFSDB 18 /* AFS cell database */ +#define T_X25 19 /* X_25 calling address */ +#define T_ISDN 20 /* ISDN calling address */ +#define T_RT 21 /* router */ +#define T_NSAP 22 /* NSAP address */ +#define T_NSAP_PTR 23 /* reverse NSAP lookup (deprecated) */ +#define T_SIG 24 /* security signature */ +#define T_KEY 25 /* security key */ +#define T_PX 26 /* X.400 mail mapping */ +#define T_GPOS 27 /* geographical position (withdrawn) */ +#define T_AAAA 28 /* IP6 Address */ +#define T_LOC 29 /* Location Information */ +#define T_NXT 30 /* Next Valid Name in Zone */ +#define T_EID 31 /* Endpoint identifier */ +#define T_NIMLOC 32 /* Nimrod locator */ +#define T_SRV 33 /* Server selection */ +#define T_ATMA 34 /* ATM Address */ +#define T_NAPTR 35 /* Naming Authority PoinTeR */ +#define T_OPT 41 /* OPT pseudo-RR, RFC2671 */ + /* non standard */ +#define T_UINFO 100 /* user (finger) information */ +#define T_UID 101 /* user ID */ +#define T_GID 102 /* group ID */ +#define T_UNSPEC 103 /* Unspecified format (binary data) */ + /* Query type values which do not appear in resource records */ +#define T_IXFR 251 /* incremental zone transfer */ +#define T_AXFR 252 /* transfer zone of authority */ +#define T_MAILB 253 /* transfer mailbox records */ +#define T_MAILA 254 /* transfer mail agent records */ +#define T_ANY 255 /* wildcard match */ + +/* + * Values for class field + */ + +#define C_IN 1 /* the arpa internet */ +#define C_CHAOS 3 /* for chaos net (MIT) */ +#define C_HS 4 /* for Hesiod name server (MIT) (XXX) */ + /* Query class values which do not appear in resource records */ +#define C_ANY 255 /* wildcard match */ + +/* + * Flags field of the KEY RR rdata + */ +#define KEYFLAG_TYPEMASK 0xC000 /* Mask for "type" bits */ +#define KEYFLAG_TYPE_AUTH_CONF 0x0000 /* Key usable for both */ +#define KEYFLAG_TYPE_CONF_ONLY 0x8000 /* Key usable for confidentiality */ +#define KEYFLAG_TYPE_AUTH_ONLY 0x4000 /* Key usable for authentication */ +#define KEYFLAG_TYPE_NO_KEY 0xC000 /* No key usable for either; no key */ +/* The type bits can also be interpreted independently, as single bits: */ +#define KEYFLAG_NO_AUTH 0x8000 /* Key not usable for authentication */ +#define KEYFLAG_NO_CONF 0x4000 /* Key not usable for confidentiality */ + +#define KEYFLAG_EXPERIMENTAL 0x2000 /* Security is *mandatory* if bit=0 */ +#define KEYFLAG_RESERVED3 0x1000 /* reserved - must be zero */ +#define KEYFLAG_RESERVED4 0x0800 /* reserved - must be zero */ +#define KEYFLAG_USERACCOUNT 0x0400 /* key is assoc. with a user acct */ +#define KEYFLAG_ENTITY 0x0200 /* key is assoc. with entity eg host */ +#define KEYFLAG_ZONEKEY 0x0100 /* key is zone key for the zone named */ +#define KEYFLAG_IPSEC 0x0080 /* key is for IPSEC use (host or user)*/ +#define KEYFLAG_EMAIL 0x0040 /* key is for email (MIME security) */ +#define KEYFLAG_RESERVED10 0x0020 /* reserved - must be zero */ +#define KEYFLAG_RESERVED11 0x0010 /* reserved - must be zero */ +#define KEYFLAG_SIGNATORYMASK 0x000F /* key can sign DNS RR's of same name */ + +#define KEYFLAG_RESERVED_BITMASK ( KEYFLAG_RESERVED3 | \ + KEYFLAG_RESERVED4 | \ + KEYFLAG_RESERVED10| KEYFLAG_RESERVED11) + +/* The Algorithm field of the KEY and SIG RR's is an integer, {1..254} */ +#define ALGORITHM_MD5RSA 1 /* MD5 with RSA */ +#define ALGORITHM_EXPIRE_ONLY 253 /* No alg, no security */ +#define ALGORITHM_PRIVATE_OID 254 /* Key begins with OID indicating alg */ + +/* Signatures */ + /* Size of a mod or exp in bits */ +#define MIN_MD5RSA_KEY_PART_BITS 512 +#define MAX_MD5RSA_KEY_PART_BITS 2552 + /* Total of binary mod and exp, bytes */ +#define MAX_MD5RSA_KEY_BYTES ((MAX_MD5RSA_KEY_PART_BITS+7/8)*2+3) + /* Max length of text sig block */ +#define MAX_KEY_BASE64 (((MAX_MD5RSA_KEY_BYTES+2)/3)*4) + +/* + * EDNS0 Z-field extended flags + */ +#define DNS_MESSAGEEXTFLAG_DO 0x8000U + +/* + * Status return codes for T_UNSPEC conversion routines + */ +#define CONV_SUCCESS 0 +#define CONV_OVERFLOW (-1) +#define CONV_BADFMT (-2) +#define CONV_BADCKSUM (-3) +#define CONV_BADBUFLEN (-4) + +#ifndef BYTE_ORDER +#if (BSD >= 199103) +# include +#else +#ifdef linux +# include +#else +#define LITTLE_ENDIAN 1234 /* least-significant byte first (vax, pc) */ +#define BIG_ENDIAN 4321 /* most-significant byte first (IBM, net) */ +#define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long (pdp)*/ + +#if defined(vax) || defined(ns32000) || defined(sun386) || defined(i386) || \ + defined(MIPSEL) || defined(_MIPSEL) || defined(BIT_ZERO_ON_RIGHT) || \ + defined(__alpha__) || defined(__alpha) +#define BYTE_ORDER LITTLE_ENDIAN +#endif + +#if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \ + defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \ + defined(MIPSEB) || defined(_MIPSEB) || defined(_IBMR2) || defined(DGUX) ||\ + defined(apollo) || defined(__convex__) || defined(_CRAY) || \ + defined(__hppa) || defined(__hp9000) || \ + defined(__hp9000s300) || defined(__hp9000s700) || \ + defined (BIT_ZERO_ON_LEFT) || defined(m68k) +#define BYTE_ORDER BIG_ENDIAN +#endif +#endif /* linux */ +#endif /* BSD */ +#endif /* BYTE_ORDER */ + +#if !defined(BYTE_ORDER) || \ + (BYTE_ORDER != BIG_ENDIAN && BYTE_ORDER != LITTLE_ENDIAN && \ + BYTE_ORDER != PDP_ENDIAN) + /* you must determine what the correct bit order is for + * your compiler - the next line is an intentional error + * which will force your compiles to bomb until you fix + * the above macros. + */ + error "Undefined or invalid BYTE_ORDER"; +#endif + +/* + * Structure for query header. The order of the fields is machine- and + * compiler-dependent, depending on the byte/bit order and the layout + * of bit fields. We use bit fields only in int variables, as this + * is all ANSI requires. This requires a somewhat confusing rearrangement. + */ + +typedef struct { + unsigned id :16; /* query identification number */ +#if BYTE_ORDER == BIG_ENDIAN + /* fields in third byte */ + unsigned qr: 1; /* response flag */ + unsigned opcode: 4; /* purpose of message */ + unsigned aa: 1; /* authoritive answer */ + unsigned tc: 1; /* truncated message */ + unsigned rd: 1; /* recursion desired */ + /* fields in fourth byte */ + unsigned ra: 1; /* recursion available */ + unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */ + unsigned ad: 1; /* authentic data from named */ + unsigned cd: 1; /* checking disabled by resolver */ + unsigned rcode :4; /* response code */ +#endif +#if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN + /* fields in third byte */ + unsigned rd :1; /* recursion desired */ + unsigned tc :1; /* truncated message */ + unsigned aa :1; /* authoritive answer */ + unsigned opcode :4; /* purpose of message */ + unsigned qr :1; /* response flag */ + /* fields in fourth byte */ + unsigned rcode :4; /* response code */ + unsigned cd: 1; /* checking disabled by resolver */ + unsigned ad: 1; /* authentic data from named */ + unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */ + unsigned ra :1; /* recursion available */ +#endif + /* remaining bytes */ + unsigned qdcount :16; /* number of question entries */ + unsigned ancount :16; /* number of answer entries */ + unsigned nscount :16; /* number of authority entries */ + unsigned arcount :16; /* number of resource entries */ +} HEADER; + +/* + * Defines for handling compressed domain names + */ +#define INDIR_MASK 0xc0 + +extern uint16 _getshort (const u_char *); +extern uint32 _getlong (const u_char *); + +/* + * Inline versions of get/put short/long. Pointer is advanced. + * + * These macros demonstrate the property of C whereby it can be + * portable or it can be elegant but rarely both. + */ +#define GETSHORT(s, cp) { \ + register u_char *t_cp = (u_char *)(cp); \ + (s) = ((uint16)t_cp[0] << 8) \ + | ((uint16)t_cp[1]) \ + ; \ + (cp) += INT16SZ; \ +} + +#define GETLONG(l, cp) { \ + register u_char *t_cp = (u_char *)(cp); \ + (l) = ((uint32)t_cp[0] << 24) \ + | ((uint32)t_cp[1] << 16) \ + | ((uint32)t_cp[2] << 8) \ + | ((uint32)t_cp[3]) \ + ; \ + (cp) += INT32SZ; \ +} + +#define PUTSHORT(s, cp) { \ + register uint16 t_s = (uint16)(s); \ + register u_char *t_cp = (u_char *)(cp); \ + *t_cp++ = t_s >> 8; \ + *t_cp = t_s; \ + (cp) += INT16SZ; \ +} + +#define PUTLONG(l, cp) { \ + register uint32 t_l = (uint32)(l); \ + register u_char *t_cp = (u_char *)(cp); \ + *t_cp++ = t_l >> 24; \ + *t_cp++ = t_l >> 16; \ + *t_cp++ = t_l >> 8; \ + *t_cp = t_l; \ + (cp) += INT32SZ; \ +} + +#endif /* !_NAMESER_H_ */ diff --git a/headers/posix/core_funcs.h b/headers/posix/core_funcs.h new file mode 100644 index 0000000000..0ad72846f0 --- /dev/null +++ b/headers/posix/core_funcs.h @@ -0,0 +1,115 @@ +/* core_funcs.h + * convenience macros to for calling core functions in the kernel + */ + +#ifndef OBOS_CORE_FUNCS_H +#define OBOS_CORE_FUNCS_H + +#include "core_module.h" + +# define add_protosw core->add_protosw +# define add_domain core->add_domain +# define remove_domain core->remove_domain +# define add_protocol core->add_protocol +# define remove_protocol core->remove_protocol +# define start_rx_thread core->start_rx_thread +# define start_tx_thread core->start_tx_thread + +# define net_add_timer core->net_add_timer +# define net_remove_timer core->net_remove_timer + +# define start_ifq core->start_ifq +# define stop_ifq core->stop_ifq + +# define pool_init core->pool_init +# define pool_get core->pool_get +# define pool_put core->pool_put + +# define m_get core->m_get +# define m_gethdr core->m_gethdr +# define m_free core->m_free +# define m_freem core->m_freem +# define m_cat core->m_cat +# define m_adj core->m_adj +# define m_prepend core->m_prepend +# define m_pullup core->m_pullup +# define m_copydata core->m_copydata +# define m_copyback core->m_copyback +# define m_copym core->m_copym +# define m_reserve core->m_reserve +# define m_devget core->m_devget + +# define if_attach core->if_attach +# define if_detach core->if_detach + +# define in_pcballoc core->in_pcballoc +# define in_pcbconnect core->in_pcbconnect +# define in_pcbdisconnect core->in_pcbdisconnect +# define in_pcbbind core->in_pcbbind +# define in_pcblookup core->in_pcblookup +# define in_pcbdetach core->in_pcbdetach +# define in_pcbrtentry core->in_pcbrtentry +# define in_canforward core->in_canforward +# define in_localaddr core->in_localaddr +# define in_losing core->in_losing +# define in_broadcast core->in_broadcast +# define in_control core->in_control +# define in_setsockaddr core->in_setsockaddr +# define in_setpeeraddr core->in_setpeeraddr +# define in_pcbnotify core->in_pcbnotify +# define inetctlerrmap core->inetctlerrmap + +# define ifa_ifwithdstaddr core->ifa_ifwithdstaddr +# define ifa_ifwithaddr core->ifa_ifwithaddr +# define ifa_ifwithnet core->ifa_ifwithnet +# define ifa_ifwithroute core->ifa_ifwithroute +# define ifaof_ifpforaddr core->ifaof_ifpforaddr +# define ifafree core->ifafree + +# define sbappend core->sbappend +# define sbappendaddr core->sbappendaddr +# define sbdrop core->sbdrop +# define sbflush core->sbflush +# define sbreserve core->sbreserve + +# define soreserve core->soreserve +# define sowakeup core->sowakeup +# define sonewconn core->sonewconn +# define soisconnected core->soisconnected +# define soisconnecting core->soisconnecting +# define soisdisconnected core->soisdisconnected +# define soisdisconnecting core->soisdisconnecting +# define sohasoutofband core->sohasoutofband +# define socantsendmore core->socantsendmore +# define socantrcvmore core->socantrcvmore + +# define rtfree core->rtfree +# define rtalloc core->rtalloc +# define rtalloc1 core->rtalloc1 +# define rtrequest core->rtrequest + +# define rt_setgate core->rt_setgate +# define get_rt_tables core->get_rt_tables + +# define rn_addmask core->rn_addmask +# define rn_head_search core->rn_head_search + +# define get_interfaces core->get_interfaces +# define get_primary_addr core->get_primary_addr + +# define initsocket core->initsocket +# define socreate core->socreate +# define soclose core->soclose + +# define sobind core->sobind +# define soconnect core->soconnect +# define solisten core->solisten +# define soaccept core->soaccept + +# define soo_ioctl core->soo_ioctl +# define net_sysctl core->net_sysctl + +# define readit core->readit +# define writeit core->writeit + +#endif /* OBOS_CORE_FUNCS_H */ diff --git a/headers/posix/core_module.h b/headers/posix/core_module.h new file mode 100644 index 0000000000..5f2dd7f873 --- /dev/null +++ b/headers/posix/core_module.h @@ -0,0 +1,158 @@ +/* core_module.h + * definitions needed by the core networking module + */ + +#ifndef OBOS_CORE_MODULE_H +#define OBOS_CORE_MODULE_H + +#include "sys/mbuf.h" +#include "sys/protosw.h" +#include "sys/socketvar.h" +#include "netinet/in_pcb.h" +#include "net/if.h" +#include "net_timer.h" +#include "net_module.h" + +struct core_module_info { + module_info module; + + int (*start)(void); + int (*stop)(void); + void (*add_domain)(struct domain *, int); + void (*remove_domain)(int); + void (*add_protocol)(struct protosw *, int); + void (*remove_protocol)(struct protosw *pr); + void (*add_protosw)(struct protosw *prt[], int layer); + void (*start_rx_thread)(struct ifnet *dev); + void (*start_tx_thread)(struct ifnet *dev); + + /* timer functions */ + net_timer_id (*net_add_timer)(net_timer_hook ,void *, + bigtime_t); + status_t (*net_remove_timer)(net_timer_id); + + /* ifq functions */ + struct ifq *(*start_ifq)(void); + void (*stop_ifq)(struct ifq *); + + /* pool functions */ + status_t (*pool_init)(pool_ctl **p, size_t sz); + char *(*pool_get)(pool_ctl *p); + void (*pool_put)(pool_ctl *p, void *ptr); + void (*pool_destroy)(pool_ctl *p); + + /* socket functions - called "internally" */ + struct socket *(*sonewconn)(struct socket *, int); + int (*soreserve)(struct socket *, uint32, uint32); + int (*sbreserve)(struct sockbuf *, uint32); + void (*sbappend)(struct sockbuf *, struct mbuf *); + int (*sbappendaddr)(struct sockbuf *, struct sockaddr *, + struct mbuf *, struct mbuf *); + void (*sbdrop)(struct sockbuf *, int); + void (*sbflush)(struct sockbuf *sb); + void (*sowakeup)(struct socket *, struct sockbuf *); + void (*soisconnected)(struct socket *); + void (*soisconnecting)(struct socket*); + void (*soisdisconnected)(struct socket *); + void (*soisdisconnecting)(struct socket *); + void (*sohasoutofband)(struct socket *so); + void (*socantrcvmore)(struct socket*); + void (*socantsendmore)(struct socket *); + + /* pcb options */ + int (*in_pcballoc)(struct socket *, struct inpcb *); + void (*in_pcbdetach)(struct inpcb *); + int (*in_pcbbind)(struct inpcb *, struct mbuf *); + int (*in_pcbconnect)(struct inpcb *, struct mbuf *); + int (*in_pcbdisconnect)(struct inpcb *); + struct inpcb * (*in_pcblookup)(struct inpcb *, + struct in_addr, uint16, struct in_addr, uint16, int); + int (*in_control)(struct socket *, int, caddr_t, + struct ifnet *); + void (*in_losing)(struct inpcb *); + int (*in_canforward)(struct in_addr); + int (*in_localaddr)(struct in_addr); + struct rtentry *(*in_pcbrtentry)(struct inpcb *); + void (*in_setsockaddr)(struct inpcb *, struct mbuf *); + void (*in_setpeeraddr)(struct inpcb *, struct mbuf *); + void (*in_pcbnotify)(struct inpcb *, struct sockaddr *, + uint16, struct in_addr, uint16, + int, void (*)(struct inpcb *, int)); + int (*inetctlerrmap)(int); + + /* mbuf routines... */ + struct mbuf * (*m_gethdr)(int); + struct mbuf * (*m_get)(int); + void (*m_cat)(struct mbuf *, struct mbuf *); + void (*m_adj)(struct mbuf*, int); + struct mbuf * (*m_prepend)(struct mbuf*, int); + struct mbuf *(*m_pullup)(struct mbuf *, int); + void (*m_copyback)(struct mbuf *, int, int, caddr_t); + void (*m_copydata)(struct mbuf *, int, int, caddr_t); + struct mbuf *(*m_copym)(struct mbuf *, int, int); + struct mbuf * (*m_free)(struct mbuf *); + void (*m_freem)(struct mbuf *); + void (*m_reserve)(struct mbuf *, int); + struct mbuf *(*m_devget)(char *, int, int, struct ifnet *, + void (*copy)(const void *, void *, size_t)); + + /* module control routines... */ + void (*add_device)(struct ifnet *); + struct ifnet *(*get_interfaces)(void); + int (*in_broadcast)(struct in_addr, struct ifnet *); + + /* routing */ + void (*rtalloc)(struct route *ro); + struct rtentry *(*rtalloc1)(struct sockaddr *, int); + void (*rtfree)(struct rtentry *); + int (*rtrequest)(int, struct sockaddr *, + struct sockaddr *, struct sockaddr *, int, + struct rtentry **); + struct radix_node *(*rn_addmask)(void *, int, int); + struct radix_node *(*rn_head_search)(void *argv_v); + struct radix_node_head **(*get_rt_tables)(void); + int (*rt_setgate)(struct rtentry *, struct sockaddr *, + struct sockaddr *); + + /* ifnet functions */ + struct ifaddr *(*ifa_ifwithdstaddr)(struct sockaddr *addr); + struct ifaddr *(*ifa_ifwithnet)(struct sockaddr *addr); + void (*if_attach)(struct ifnet *); + void (*if_detach)(struct ifnet *); + struct ifaddr *(*ifa_ifwithaddr)(struct sockaddr *); + struct ifaddr *(*ifa_ifwithroute)(int, struct sockaddr *, + struct sockaddr *); + struct ifaddr *(*ifaof_ifpforaddr)(struct sockaddr *, struct ifnet *); + void (*ifafree)(struct ifaddr *); + + struct in_ifaddr *(*get_primary_addr)(void); + + /* socket functions - used by socket driver */ + int (*initsocket)(void **); + int (*socreate)(int, void *, int, int); + int (*soclose)(void *); + int (*sobind)(void *, caddr_t, int); + int (*solisten)(void *, int); + int (*soconnect)(void *, caddr_t, int); + int (*recvit)(void *, struct msghdr *, caddr_t, int *); + int (*sendit)(void *, struct msghdr *, int, int *); + int (*soo_ioctl)(void *, int, caddr_t); + int (*net_sysctl)(int *, uint, void *, size_t *, void *, size_t); + int (*writeit)(void *, struct iovec *, int); + int (*readit)(void*, struct iovec *, int *); + int (*sosetopt)(void *, int, int, const void *, size_t); + int (*sogetopt)(void *, int, int, void *, size_t *); + int (*set_socket_event_callback)(void *, socket_event_callback, void *, int); + int (*sogetpeername)(void *, struct sockaddr *, int *); + int (*sogetsockname)(void *, struct sockaddr *, int *); + int (*soaccept)(void *, void **, void *, int *); +}; + +#ifdef _KERNEL_ +#define CORE_MODULE_PATH "network/core" +#else +#define CORE_MODULE_PATH "modules/core" +#endif + +#endif /* OBOS_CORE_MODULE_H */ + diff --git a/headers/posix/lock.h b/headers/posix/lock.h new file mode 100644 index 0000000000..05ad4e9330 --- /dev/null +++ b/headers/posix/lock.h @@ -0,0 +1,128 @@ +#ifndef LOCK_H +#define LOCK_H +/* lock.h - benaphore locking, "faster semaphores", read/write locks +** sorry for all those macros; I wish C would support C++-style +** inline functions. +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include + +// for read/write locks +#define MAX_READERS 100000 + + +struct benaphore { + sem_id sem; + int32 count; +}; + +typedef struct benaphore benaphore; + +// it may make sense to add a status field to the rw_lock to +// be able to check if the semaphore could be locked + +struct rw_lock { + sem_id sem; + int32 count; + benaphore writeLock; +}; + +typedef struct rw_lock rw_lock; + +#ifndef _KERNEL_ +#define INIT_BENAPHORE(lock,name) \ + { \ + (lock).count = 1; \ + (lock).sem = create_sem(0, name); \ + } + +#else + +#define INIT_BENAPHORE(lock,name) \ + { \ + (lock).count = 1; \ + (lock).sem = create_sem(0, name); \ + set_sem_owner((lock).sem, B_SYSTEM_TEAM); \ + } +#endif + + +#define CHECK_BENAPHORE(lock) \ + ((lock).sem) + +#define UNINIT_BENAPHORE(lock) \ + delete_sem((lock).sem); + +#define ACQUIRE_BENAPHORE(lock) \ + (atomic_add(&((lock).count), -1) <= 0 ? \ + acquire_sem_etc((lock).sem, 1, B_CAN_INTERRUPT, 0) \ + : B_OK) + +#define RELEASE_BENAPHORE(lock) \ + { \ + if (atomic_add(&((lock).count), 1) < 0) \ + release_sem((lock).sem); \ + } + +/* read/write lock */ +#ifndef _KERNEL_ +#define INIT_RW_LOCK(lock,name) \ + { \ + (lock).sem = create_sem(0, name); \ + (lock).count = MAX_READERS; \ + INIT_BENAPHORE((lock).writeLock, "r/w write lock"); \ + } + +#else + +#define INIT_RW_LOCK(lock,name) \ + { \ + (lock).sem = create_sem(0, name); \ + set_sem_owner((lock).sem, B_SYSTEM_TEAM); \ + (lock).count = MAX_READERS; \ + INIT_BENAPHORE((lock).writeLock, "r/w write lock"); \ + } + +#endif +#define CHECK_RW_LOCK(lock) \ + ((lock).sem) + +#define UNINIT_RW_LOCK(lock) \ + delete_sem((lock).sem); \ + UNINIT_BENAPHORE((lock).writeLock) + +#define ACQUIRE_READ_LOCK(lock) \ + { \ + if (atomic_add(&(lock).count, -1) <= 0) \ + acquire_sem((lock).sem); \ + } + +#define RELEASE_READ_LOCK(lock) \ + { \ + if (atomic_add(&(lock).count, 1) < 0) \ + release_sem((lock).sem); \ + } + +#define ACQUIRE_WRITE_LOCK(lock) \ + { \ + int32 readers; \ + ACQUIRE_BENAPHORE((lock).writeLock); \ + readers = atomic_add(&(lock).count, -MAX_READERS); \ + if (readers < MAX_READERS) \ + acquire_sem_etc((lock).sem,readers <= 0 ? 1 : MAX_READERS - readers,0,0); \ + RELEASE_BENAPHORE((lock).writeLock); \ + } + +#define RELEASE_WRITE_LOCK(lock) \ + { \ + int32 readers = atomic_add(&(lock).count,MAX_READERS); \ + if (readers < 0) \ + release_sem_etc((lock).sem,readers <= -MAX_READERS ? 1 : -readers,B_CAN_INTERRUPT); \ + } + +#endif /* LOCK_H */ diff --git a/headers/posix/net/if.h b/headers/posix/net/if.h new file mode 100644 index 0000000000..4e033b1193 --- /dev/null +++ b/headers/posix/net/if.h @@ -0,0 +1,275 @@ +/* if.h + * Interface definitions for beos + */ + +#ifndef OBOS_IF_H +#define OBOS_IF_H + +#include +#include +#include "sys/socketvar.h" +#include "net/if_types.h" +#include "netinet/in.h" +#include "net/route.h" + +enum { + IF_GETADDR = B_DEVICE_OP_CODES_END, + IF_INIT, + IF_NONBLOCK, + IF_ADDMULTI, + IF_REMMULTI, + IF_SETPROMISC, + IF_GETFRAMESIZE +}; + +/* Media types are now listed in net/if_types.h */ + +/* Interface flags */ +enum { + IFF_UP = 0x0001, + IFF_DOWN = 0x0002, + IFF_PROMISC = 0x0004, + IFF_RUNNING = 0x0008, + IFF_MULTICAST = 0x0010, + IFF_BROADCAST = 0x0020, + IFF_POINTOPOINT = 0x0040, + IFF_NOARP = 0x0080, + IFF_LOOPBACK = 0x0100, + IFF_DEBUG = 0x0200, + IFF_LINK0 = 0x0400, + IFF_LINK1 = 0x0800, + IFF_LINK2 = 0x1000, + IFF_SIMPLEX = 0x2000 +}; + +struct ifq { + struct mbuf *head; + struct mbuf *tail; + int maxlen; + int len; + sem_id lock; + sem_id pop; +}; + +#define IFQ_FULL(ifq) (ifq->len >= ifq->maxlen) + +#define IFQ_ENQUEUE(ifq, m) { \ + acquire_sem((ifq)->lock); \ + (m)->m_nextpkt = 0; \ + if ((ifq)->tail == 0) \ + (ifq)->head = m; \ + else \ + (ifq)->tail->m_nextpkt = m; \ + (ifq)->tail = m; \ + (ifq)->len++; \ + release_sem((ifq)->lock); \ + release_sem((ifq)->pop); \ +} + +#define IFQ_DEQUEUE(ifq, m) { \ + acquire_sem((ifq)->lock); \ + (m) = (ifq)->head; \ + if (m) { \ + if (((ifq)->head = (m)->m_nextpkt) == 0) \ + (ifq)->tail = 0; \ + (m)->m_nextpkt = 0; \ + (ifq)->len--; \ + } \ + release_sem((ifq)->lock); \ +} + +struct ifaddr { + struct ifaddr *ifa_next; /* the next address for the interface */ + struct ifnet *ifa_ifp; /* pointer to the interface structure */ + + struct sockaddr *ifa_addr; /* the address - cast to be a suitable type, so we + * use this structure to store any type of address that + * we have a struct sockaddr_? for. e.g. + * link level address via sockaddr_dl and + * ipv4 via sockeddr_in + * same for next 2 pointers as well + */ + struct sockaddr *ifa_dstaddr; /* if we're on a point-to-point link this + * is the other end */ + struct sockaddr *ifa_netmask; /* The netmask we're using */ + + /* check or clean routes... */ + void (*ifa_rtrequest)(int, struct rtentry *, struct sockaddr *); + uint8 ifa_flags; /* flags (mainly routing */ + uint16 ifa_refcnt; /* how many references are there to + * this structure? */ + int ifa_metric; /* the metirc for this interface/address */ +}; +#define ifa_broadaddr ifa_dstaddr + +struct if_data { + uint8 ifi_type; /* type of media */ + uint8 ifi_addrlen; /* length of media address length */ + uint8 ifi_hdrlen; /* size of media header */ + uint32 ifi_mtu; /* mtu */ + uint32 ifi_metric; /* routing metric */ + uint32 ifi_baudrate; /* baudrate of line */ + /* statistics!! */ + int32 ifi_ipackets; /* packets received on interface */ + int32 ifi_ierrors; /* input errors on interface */ + int32 ifi_opackets; /* packets sent on interface */ + int32 ifi_oerrors; /* output errors on interface */ + int32 ifi_collisions; /* collisions on csma interfaces */ + int32 ifi_ibytes; /* total number of octets received */ + int32 ifi_obytes; /* total number of octets sent */ + int32 ifi_imcasts; /* packets received via multicast */ + int32 ifi_omcasts; /* packets sent via multicast */ + int32 ifi_iqdrops; /* dropped on input, this interface */ + int32 ifi_noproto; /* destined for unsupported protocol */ +}; + +struct ifnet { + struct ifnet *if_next; /* next device */ + struct ifaddr *if_addrlist; /* linked list of addresses */ + int devid; /* our device id if we have one... */ + int id; /* id within the stack's device list */ + char *name; /* name of driver e.g. tulip */ + int if_unit; /* number of unit e.g 0 */ + char *if_name; /* full name, e.g. tulip0 */ + struct if_data ifd; /* if_data structure, shortcuts below */ + int if_flags; /* if flags */ + int if_index; /* our index in ifnet_addrs and interfaces */ + + struct ifq *rxq; + thread_id rx_thread; + struct ifq *txq; + thread_id tx_thread; + struct ifq *devq; + + int (*start) (struct ifnet *); + int (*stop) (struct ifnet *); + void (*input) (struct mbuf*); + int (*output)(struct ifnet *, struct mbuf*, + struct sockaddr*, struct rtentry *); + int (*ioctl) (struct ifnet *, int, caddr_t); +}; +#define if_mtu ifd.ifi_mtu +#define if_type ifd.ifi_type +#define if_addrlen ifd.ifi_addrlen +#define if_hdrlen ifd.ifi_hdrlen +#define if_metric ifd.ifi_metric +#define if_baudrate ifd.ifi_baurdate +#define if_ipackets ifd.ifi_ipackets +#define if_ierrors ifd.ifi_ierrors +#define if_opackets ifd.ifi_opackets +#define if_oerrors ifd.ifi_oerrors +#define if_collisions ifd.ifi_collisions +#define if_ibytes ifd.ifi_ibytes +#define if_obytes ifd.ifi_obytes +#define if_imcasts ifd.ifi_imcasts +#define if_omcasts ifd.ifi_omcasts +#define if_iqdrops ifd.ifi_iqdrops +#define if_noproto ifd.ifi_noproto + +#define IFNAMSIZ 16 + +/* This structure is used for passing interface requests via ioctl */ +struct ifreq { + char ifr_name[IFNAMSIZ]; /* name of interface */ + union { + struct sockaddr ifru_addr; + struct sockaddr ifru_dstaddr; + struct sockaddr ifru_broadaddr; + uint16 ifru_flags; + int ifru_metric; + caddr_t ifru_data; + } ifr_ifru; +}; +#define ifr_addr ifr_ifru.ifru_addr +#define ifr_dstaddr ifr_ifru.ifru_dstaddr +#define ifr_broadaddr ifr_ifru.ifru_broadaddr +#define ifr_flags ifr_ifru.ifru_flags +#define ifr_metric ifr_ifru.ifru_metric +#define ifr_mtu ifr_ifru.ifru_metric /* sneaky overload :) */ +#define ifr_data ifr_ifru.ifru_data + +struct ifconf { + int ifc_len; /* length of associated buffer */ + union { + caddr_t ifcu_buf; + struct ifreq *ifcu_req; + } ifc_ifcu; +}; +#define ifc_buf ifc_ifcu.ifcu_buf +#define ifc_req ifc_ifcu.ifcu_req + + +#define IFAFREE(ifa) \ +do { \ + if ((ifa)->ifa_refcnt <= 0) \ + ifafree(ifa); \ + else \ + (ifa)->ifa_refcnt--; \ +} while (0) + +/* used to pass in additional information, such as aliases */ +struct ifaliasreq { + char ifa_name[IFNAMSIZ]; + struct sockaddr ifra_addr; + struct sockaddr ifra_broadaddr; +#define ifra_dstaddr ifra_broadaddr + struct sockaddr ifra_mask; +}; + +#define IFA_ROUTE RTF_UP + +/* + * Message format for use in obtaining information about interfaces + * from sysctl and the routing socket. + */ +struct if_msghdr { + u_short ifm_msglen; /* to skip over non-understood messages */ + u_char ifm_version; /* future binary compatability */ + u_char ifm_type; /* message type */ + int ifm_addrs; /* like rtm_addrs */ + int ifm_flags; /* value of if_flags */ + u_short ifm_index; /* index for associated ifp */ + struct if_data ifm_data;/* statistics and other data about if */ +}; + +/* + * Message format for use in obtaining information about interface addresses + * from sysctl and the routing socket. + */ +struct ifa_msghdr { + u_short ifam_msglen; /* to skip over non-understood messages */ + u_char ifam_version; /* future binary compatability */ + u_char ifam_type; /* message type */ + int ifam_addrs; /* like rtm_addrs */ + int ifam_flags; /* value of ifa_flags */ + u_short ifam_index; /* index for associated ifp */ + int ifam_metric; /* value of ifa_metric */ +}; + +#ifdef _NETWORK_STACK + +/* function declaration */ +struct ifq *start_ifq(void); +void stop_ifq(struct ifq *); +struct ifnet *get_interfaces(void); +struct ifnet *ifunit(char *name); +struct ifaddr *ifa_ifwithaddr(struct sockaddr *); +struct ifaddr *ifa_ifwithaf(int); +struct ifaddr *ifa_ifwithdstaddr(struct sockaddr *); +struct ifaddr *ifa_ifwithnet(struct sockaddr *); +struct ifaddr *ifa_ifwithroute(int, struct sockaddr *, + struct sockaddr *); +struct ifaddr *ifaof_ifpforaddr(struct sockaddr *, struct ifnet *); +void ifafree(struct ifaddr *); + +void if_attach(struct ifnet *ifp); +void if_detach(struct ifnet *ifp); + +int ifioctl(struct socket *so, int cmd, caddr_t data); +int ifconf(int cmd, caddr_t data); +void if_init(void); + +#endif + +#endif /* OBOS_IF_H */ + diff --git a/headers/posix/net/if_arp.h b/headers/posix/net/if_arp.h new file mode 100644 index 0000000000..579d35fd1f --- /dev/null +++ b/headers/posix/net/if_arp.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)if_arp.h 8.1 (Berkeley) 6/10/93 + */ + +#ifndef NET_IF_ARP_H +#define NET_IF_ARP_H +/* + * Address Resolution Protocol. + * + * See RFC 826 for protocol description. ARP packets are variable + * in size; the arphdr structure defines the fixed-length portion. + * Protocol type values are the same as those for 10 Mb/s Ethernet. + * It is followed by the variable-sized fields ar_sha, arp_spa, + * arp_tha and arp_tpa in that order, according to the lengths + * specified. Field names used correspond to RFC 826. + */ +struct arphdr { + uint16 ar_hrd; /* format of hardware address */ + uint16 ar_pro; /* format of protocol address */ + uint8 ar_hln; /* length of hardware address */ + uint8 ar_pln; /* length of protocol address */ + uint16 ar_op; /* one of: */ +/* + * The remaining fields are variable in size, + * according to the sizes above. + */ +#ifdef COMMENT_ONLY + uint8 ar_sha[]; /* sender hardware address */ + uint8 ar_spa[]; /* sender protocol address */ + uint8 ar_tha[]; /* target hardware address */ + uint8 ar_tpa[]; /* target protocol address */ +#endif +}; + +#define ARPHRD_ETHER 1 /* ethernet hardware format */ +#define ARPHRD_IEEE802 6 /* IEEE 802 hardware format */ +#define ARPHRD_FRELAY 15 /* frame relay hardware format */ + +#define ARPOP_REQUEST 1 /* request to resolve address */ +#define ARPOP_REPLY 2 /* response to previous request */ +#define ARPOP_REVREQUEST 3 /* request protocol address given hardware */ +#define ARPOP_REVREPLY 4 /* response giving protocol address */ +#define ARPOP_INVREQUEST 8 /* request to identify peer */ +#define ARPOP_INVREPLY 9 /* response identifying peer */ + +/* + * ARP ioctl request + */ +struct arpreq { + struct sockaddr arp_pa; /* protocol address */ + struct sockaddr arp_ha; /* hardware address */ + int arp_flags; /* flags */ +}; +/* arp_flags and at_flags field values */ +#define ATF_INUSE 0x01 /* entry in use */ +#define ATF_COM 0x02 /* completed entry (enaddr valid) */ +#define ATF_PERM 0x04 /* permanent entry */ +#define ATF_PUBL 0x08 /* publish entry (respond for other host) */ +#define ATF_USETRAILERS 0x10 /* has requested trailers */ + +#endif /* NET_IF_ARP_H */ diff --git a/headers/posix/net/if_dl.h b/headers/posix/net/if_dl.h new file mode 100644 index 0000000000..23b56b20f0 --- /dev/null +++ b/headers/posix/net/if_dl.h @@ -0,0 +1,30 @@ +/* if.h + * Interface definitions for beos + */ + +#ifndef OBOS_IF_DL_H +#define OBOS_IF_DL_H + +#include "net/if.h" + +/* link level sockaddr structure */ +struct sockaddr_dl { + uint8 sdl_len; /* Total length of sockaddr */ + uint8 sdl_family; /* AF_LINK */ + uint16 sdl_index; /* if != 0, system given index for interface */ + uint8 sdl_type; /* interface type */ + uint8 sdl_nlen; /* interface name length, no trailing 0 reqd. */ + uint8 sdl_alen; /* link level address length */ + uint8 sdl_slen; /* link layer selector length */ + char sdl_data[12]; /* minimum work area, can be larger; + contains both if name and ll address */ +}; + +/* Macro to get a pointer to the link level address */ +#define LLADDR(s) ((caddr_t)((s)->sdl_data + (s)->sdl_nlen)) + +void link_addr (const char *, struct sockaddr_dl *); +char *link_ntoa (const struct sockaddr_dl *); + +#endif /* OBOS_IF_DL_H */ + diff --git a/headers/posix/net/if_ppp.h b/headers/posix/net/if_ppp.h new file mode 100644 index 0000000000..a06ca8bbca --- /dev/null +++ b/headers/posix/net/if_ppp.h @@ -0,0 +1,129 @@ +/* $OpenBSD: if_ppp.h,v 1.6 2001/06/09 06:16:38 angelos Exp $ */ +/* $NetBSD: if_ppp.h,v 1.11 1996/03/15 02:28:05 paulus Exp $ */ + +/* + * if_ppp.h - Point-to-Point Protocol definitions. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef _NET_IF_PPP_H_ +#define _NET_IF_PPP_H_ + +/* + * Bit definitions for flags. + */ +#define SC_COMP_PROT 0x00000001 /* protocol compression (output) */ +#define SC_COMP_AC 0x00000002 /* header compression (output) */ +#define SC_COMP_TCP 0x00000004 /* TCP (VJ) compression (output) */ +#define SC_NO_TCP_CCID 0x00000008 /* disable VJ connection-id comp. */ +#define SC_REJ_COMP_AC 0x00000010 /* reject adrs/ctrl comp. on input */ +#define SC_REJ_COMP_TCP 0x00000020 /* reject TCP (VJ) comp. on input */ +#define SC_CCP_OPEN 0x00000040 /* Look at CCP packets */ +#define SC_CCP_UP 0x00000080 /* May send/recv compressed packets */ +#define SC_DEBUG 0x00010000 /* enable debug messages */ +#define SC_LOG_INPKT 0x00020000 /* log contents of good pkts recvd */ +#define SC_LOG_OUTPKT 0x00040000 /* log contents of pkts sent */ +#define SC_LOG_RAWIN 0x00080000 /* log all chars received */ +#define SC_LOG_FLUSH 0x00100000 /* log all chars flushed */ +#define SC_RCV_B7_0 0x01000000 /* have rcvd char with bit 7 = 0 */ +#define SC_RCV_B7_1 0x02000000 /* have rcvd char with bit 7 = 1 */ +#define SC_RCV_EVNP 0x04000000 /* have rcvd char with even parity */ +#define SC_RCV_ODDP 0x08000000 /* have rcvd char with odd parity */ +#define SC_MASK 0x0fff00ff /* bits that user can change */ + +/* + * State bits in sc_flags, not changeable by user. + */ +#define SC_TIMEOUT 0x00000400 /* timeout is currently pending */ +#define SC_VJ_RESET 0x00000800 /* need to reset VJ decomp */ +#define SC_COMP_RUN 0x00001000 /* compressor has been inited */ +#define SC_DECOMP_RUN 0x00002000 /* decompressor has been inited */ +#define SC_DC_ERROR 0x00004000 /* non-fatal decomp error detected */ +#define SC_DC_FERROR 0x00008000 /* fatal decomp error detected */ +#define SC_TBUSY 0x10000000 /* xmitter doesn't need a packet yet */ +#define SC_PKTLOST 0x20000000 /* have lost or dropped a packet */ +#define SC_FLUSH 0x40000000 /* flush input until next PPP_FLAG */ +#define SC_ESCAPED 0x80000000 /* saw a PPP_ESCAPE */ + +/* + * Ioctl definitions. + */ + +struct npioctl { + int protocol; /* PPP procotol, e.g. PPP_IP */ + int on; +}; + +/* Structure describing a CCP configuration option, for PPPIOCSCOMPRESS */ +struct ppp_option_data { + u_char *ptr; + u_int length; + int transmit; +}; + +struct ifpppstatsreq { + char ifr_name[IFNAMSIZ]; + struct ppp_stats stats; +}; + +struct ifpppcstatsreq { + char ifr_name[IFNAMSIZ]; + struct ppp_comp_stats stats; +}; + +/* + * Ioctl definitions. + */ + +#define PPPIOCGFLAGS _IOR('t', 90, int) /* get configuration flags */ +#define PPPIOCSFLAGS _IOW('t', 89, int) /* set configuration flags */ +#define PPPIOCGASYNCMAP _IOR('t', 88, int) /* get async map */ +#define PPPIOCSASYNCMAP _IOW('t', 87, int) /* set async map */ +#define PPPIOCGUNIT _IOR('t', 86, int) /* get ppp unit number */ +#define PPPIOCGRASYNCMAP _IOR('t', 85, int) /* get receive async map */ +#define PPPIOCSRASYNCMAP _IOW('t', 84, int) /* set receive async map */ +#define PPPIOCGMRU _IOR('t', 83, int) /* get max receive unit */ +#define PPPIOCSMRU _IOW('t', 82, int) /* set max receive unit */ +#define PPPIOCSMAXCID _IOW('t', 81, int) /* set VJ max slot ID */ +#define PPPIOCGXASYNCMAP _IOR('t', 80, ext_accm) /* get extended ACCM */ +#define PPPIOCSXASYNCMAP _IOW('t', 79, ext_accm) /* set extended ACCM */ +#define PPPIOCXFERUNIT _IO('t', 78) /* transfer PPP unit */ +#define PPPIOCSCOMPRESS _IOW('t', 77, struct ppp_option_data) +#define PPPIOCGNPMODE _IOWR('t', 76, struct npioctl) /* get NP mode */ +#define PPPIOCSNPMODE _IOW('t', 75, struct npioctl) /* set NP mode */ +#define PPPIOCGIDLE _IOR('t', 74, struct ppp_idle) /* get idle time */ +#define PPPIOCSPASS _IOW('t', 71, struct bpf_program) /* set pass filter */ +#define PPPIOCSACTIVE _IOW('t', 70, struct bpf_program) /* set active filt */ + +/* PPPIOC[GS]MTU are alternatives to SIOC[GS]IFMTU, used under Ultrix */ +#define PPPIOCGMTU _IOR('t', 73, int) /* get interface MTU */ +#define PPPIOCSMTU _IOW('t', 72, int) /* set interface MTU */ + +/* + * These two are interface ioctls so that pppstats can do them on + * a socket without having to open the serial device. + */ +#define SIOCGPPPSTATS _IOWR('i', 123, struct ifpppstatsreq) +#define SIOCGPPPCSTATS _IOWR('i', 122, struct ifpppcstatsreq) + +#ifdef _KERNEL_ +int pppoutput (struct ifnet *, struct mbuf *, struct sockaddr *, + struct rtentry *); +void pppinput (struct mbuf *); +#endif + +#endif /* _NET_IF_PPP_H_ */ diff --git a/headers/posix/net/if_types.h b/headers/posix/net/if_types.h new file mode 100644 index 0000000000..88f61f9594 --- /dev/null +++ b/headers/posix/net/if_types.h @@ -0,0 +1,23 @@ +/* if_types.h + * + * + */ + +#ifndef NET_IF_TYPES_H +#define NET_IF_TYPES_H + +/* We just list the ones here we actually use... */ + +#define IFT_ETHER 0x06 +#define IFT_PPP 0x17 +#define IFT_LOOP 0x18 +#define IFT_SLIP 0x1c +#define IFT_RS232 0x21 +#define IFT_PARA 0x22 /* Parallel port! ?? */ +#define IFT_ATM 0x25 +#define IFT_MODEM 0x31 /* Just a simple generic modem */ +#define IFT_FASTETHER 0x32 /* 100BaseT ethernet */ +#define IFT_ISDN 0x3f /* ISDN / X.25 */ + +#endif /* NET_IF_TYPES_H */ + diff --git a/headers/posix/net/ppp_ctrl.h b/headers/posix/net/ppp_ctrl.h new file mode 100644 index 0000000000..870c688c0b --- /dev/null +++ b/headers/posix/net/ppp_ctrl.h @@ -0,0 +1,24 @@ +/* + * ppp_ctrl.h + * + * Definitions required to control PPP from userland + */ + +#ifndef _NET_PPP_CTRL_H_ +#define _NET_PPP_CTRL_H_ + +#define PPPCTRL_THREADNAME "PPP_Control_Thread" +#define PPPCTRL_MAXSIZE 100 /* biggest lump of data we accept */ + +enum { + PPPCTRL_OK = 0, /* Operation completed OK */ + PPPCTRL_FAIL, /* Operation failed */ + PPPCTRL_CREATE, /* create a new PPP device */ + PPPCTRL_DELETE, /* delete a PPP device */ + PPPCTRL_UP, /* start a ppp connection */ + PPPCTRL_OPEN, /* Open a device */ + PPPCTRL_DOWN, /* stop a ppp connection */ + +}; + +#endif /* _NET_PPP_CTRL_H_ */ diff --git a/headers/posix/net/ppp_defs.h b/headers/posix/net/ppp_defs.h new file mode 100644 index 0000000000..0d9fc4a204 --- /dev/null +++ b/headers/posix/net/ppp_defs.h @@ -0,0 +1,158 @@ +/* + * ppp_defs.h - PPP definitions. + * + * Copyright (c) 1994 The Australian National University. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, provided that the above copyright + * notice appears in all copies. This software is provided without any + * warranty, express or implied. The Australian National University + * makes no representations about the suitability of this software for + * any purpose. + * + * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY + * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO + * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, + * OR MODIFICATIONS. + */ + +#ifndef _PPP_DEFS_H_ +#define _PPP_DEFS_H_ + +/* + * The basic PPP frame. + */ + +/* pppoe header = 6 bytes + * hdlc frame header is 3 bytes + * PPP protocol is 2 bytes, + * so PPP_HDRLEN set to 8 to try and get us enough storage + * for any of these. If we have to allocate a new mbuf then so be it. + */ +#define PPP_HDRLEN 8 /* octets for standard ppp header */ +#define PPP_PROTHDRLEN 2 +#define PPP_PROTOFF PPP_HDRLEN - PPP_PROTHDRLEN + +#define PPP_FCSLEN 2 /* octets for FCS */ +#define PPP_MRU 1500 /* default MRU = max length of info field */ + +#define PPP_PROTOCOL(p) ((((u_char *)(p))[0] << 8) + ((u_char *)(p))[1]) + +/* + * Significant octet values. + */ +#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */ +#define PPP_UI 0x03 /* Unnumbered Information */ +#define PPP_FLAG 0x7e /* Flag Sequence */ +#define PPP_ESCAPE 0x7d /* Asynchronous Control Escape */ +#define PPP_TRANS 0x20 /* Asynchronous transparency modifier */ + +/* + * Protocol field values. + */ +#define PPP_IP 0x21 /* Internet Protocol */ +#define PPP_XNS 0x25 /* Xerox NS */ +#define PPP_AT 0x29 /* AppleTalk Protocol */ +#define PPP_IPX 0x2b /* Internetwork Packet Exchange */ +#define PPP_VJC_COMP 0x2d /* VJ compressed TCP */ +#define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */ +#define PPP_IPV6 0x57 /* Internet Protocol Version 6 */ +#define PPP_COMP 0xfd /* compressed packet */ +#define PPP_IPCP 0x8021 /* IP Control Protocol */ +#define PPP_ATCP 0x8029 /* AppleTalk Control Protocol */ +#define PPP_IPXCP 0x802b /* IPX Control Protocol */ +#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */ +#define PPP_CCP 0x80fd /* Compression Control Protocol */ +#define PPP_LCP 0xc021 /* Link Control Protocol */ +#define PPP_PAP 0xc023 /* Password Authentication Protocol */ +#define PPP_LQR 0xc025 /* Link Quality Report protocol */ +#define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */ +#define PPP_CBCP 0xc029 /* Callback Control Protocol */ + +/* + * Values for FCS calculations. + */ +#define PPP_INITFCS 0xffff /* Initial FCS value */ +#define PPP_GOODFCS 0xf0b8 /* Good final FCS value */ + +/* + * Extended asyncmap - allows any character to be escaped. + */ +typedef uint32 ext_accm[8]; + +/* + * What to do with network protocol (NP) packets. + */ +enum NPmode { + NPMODE_PASS, /* pass the packet through */ + NPMODE_DROP, /* silently drop the packet */ + NPMODE_ERROR, /* return an error */ + NPMODE_QUEUE /* save it up for later. */ +}; + +/* + * Statistics. + */ +struct pppstat { + uint ppp_ibytes; /* bytes received */ + uint ppp_ipackets; /* packets received */ + uint ppp_ierrors; /* receive errors */ + uint ppp_obytes; /* bytes sent */ + uint ppp_opackets; /* packets sent */ + uint ppp_oerrors; /* transmit errors */ +}; + +struct vjstat { + uint vjs_packets; /* outbound packets */ + uint vjs_compressed; /* outbound compressed packets */ + uint vjs_searches; /* searches for connection state */ + uint vjs_misses; /* times couldn't find conn. state */ + uint vjs_uncompressedin; /* inbound uncompressed packets */ + uint vjs_compressedin; /* inbound compressed packets */ + uint vjs_errorin; /* inbound unknown type packets */ + uint vjs_tossed; /* inbound packets tossed because of error */ +}; + +struct ppp_stats { + struct pppstat p; /* basic PPP statistics */ + struct vjstat vj; /* VJ header compression statistics */ +}; + +struct compstat { + uint unc_bytes; /* total uncompressed bytes */ + uint unc_packets; /* total uncompressed packets */ + uint comp_bytes; /* compressed bytes */ + uint comp_packets; /* compressed packets */ + uint inc_bytes; /* incompressible bytes */ + uint inc_packets; /* incompressible packets */ + uint ratio; /* recent compression ratio << 8 */ +}; + +struct ppp_comp_stats { + struct compstat c; /* packet compression statistics */ + struct compstat d; /* packet decompression statistics */ +}; + +/* + * The following structure records the time in seconds since + * the last NP packet was sent or received. + */ +struct ppp_idle { + time_t xmit_idle; /* time since last NP packet sent */ + time_t recv_idle; /* time since last NP packet received */ +}; + +#ifdef _NETWORK_STACK +uint16 pppfcs16(uint16 fcs, u_char *cp, int len); +#endif + +#endif /* _PPP_DEFS_H_ */ diff --git a/headers/posix/net/ppp_stats.h b/headers/posix/net/ppp_stats.h new file mode 100644 index 0000000000..b5357c3429 --- /dev/null +++ b/headers/posix/net/ppp_stats.h @@ -0,0 +1,47 @@ +#ifndef _PPP_STATS_H_ +#define _PPP_STATS_H_ + +/* + * Statistics. + */ +struct pppstat { + uint ppp_ibytes; /* bytes received */ + uint ppp_ipackets; /* packets received */ + uint ppp_ierrors; /* receive errors */ + uint ppp_obytes; /* bytes sent */ + uint ppp_opackets; /* packets sent */ + uint ppp_oerrors; /* transmit errors */ +}; + +struct vjstat { + uint vjs_packets; /* outbound packets */ + uint vjs_compressed; /* outbound compressed packets */ + uint vjs_searches; /* searches for connection state */ + uint vjs_misses; /* times couldn't find conn. state */ + uint vjs_uncompressedin; /* inbound uncompressed packets */ + uint vjs_compressedin; /* inbound compressed packets */ + uint vjs_errorin; /* inbound unknown type packets */ + uint vjs_tossed; /* inbound packets tossed because of error */ +}; + +struct ppp_stats { + struct pppstat p; /* basic PPP statistics */ + struct vjstat vj; /* VJ header compression statistics */ +}; + +struct compstat { + uint unc_bytes; /* total uncompressed bytes */ + uint unc_packets; /* total uncompressed packets */ + uint comp_bytes; /* compressed bytes */ + uint comp_packets; /* compressed packets */ + uint inc_bytes; /* incompressible bytes */ + uint inc_packets; /* incompressible packets */ + uint ratio; /* recent compression ratio << 8 */ +}; + +struct ppp_comp_stats { + struct compstat c; /* packet compression statistics */ + struct compstat d; /* packet decompression statistics */ +}; + +#endif /* _PPP_STATS_H_ */ diff --git a/headers/posix/net/radix.h b/headers/posix/net/radix.h new file mode 100644 index 0000000000..3fbe46bbee --- /dev/null +++ b/headers/posix/net/radix.h @@ -0,0 +1,165 @@ +/* + * Copyright (c) 1988, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)radix.h 8.2 (Berkeley) 10/31/94 + * $FreeBSD: src/sys/net/radix.h,v 1.16.2.1 2000/05/03 19:17:11 wollman Exp $ + */ + +#ifndef _RADIX_H_ +#define _RADIX_H_ + +#include + +/* + * Radix search tree node layout. + */ + +struct radix_node { + struct radix_mask *rn_mklist; /* list of masks contained in subtree */ + struct radix_node *rn_parent; /* parent */ + short rn_bit; /* bit offset; -1-index(netmask) */ + char rn_bmask; /* node: mask for bit test*/ + u_char rn_flags; /* enumerated next */ +#define RNF_NORMAL 1 /* leaf contains normal route */ +#define RNF_ROOT 2 /* leaf is root leaf for tree */ +#define RNF_ACTIVE 4 /* This node is alive (for rtfree) */ + union { + struct { /* leaf only data: */ + caddr_t rn_Key; /* object of search */ + caddr_t rn_Mask; /* netmask, if present */ + struct radix_node *rn_Dupedkey; + } rn_leaf; + struct { /* node only data: */ + int rn_Off; /* where to start compare */ + struct radix_node *rn_L;/* progeny */ + struct radix_node *rn_R;/* progeny */ + } rn_node; + } rn_u; +#ifdef RN_DEBUG + int rn_info; + struct radix_node *rn_twin; + struct radix_node *rn_ybro; +#endif +}; + +#define rn_dupedkey rn_u.rn_leaf.rn_Dupedkey +#define rn_key rn_u.rn_leaf.rn_Key +#define rn_mask rn_u.rn_leaf.rn_Mask +#define rn_offset rn_u.rn_node.rn_Off +#define rn_left rn_u.rn_node.rn_L +#define rn_right rn_u.rn_node.rn_R + +/* + * Annotations to tree concerning potential routes applying to subtrees. + */ + +struct radix_mask { + short rm_bit; /* bit offset; -1-index(netmask) */ + char rm_unused; /* cf. rn_bmask */ + u_char rm_flags; /* cf. rn_flags */ + struct radix_mask *rm_mklist; /* more masks to try */ + union { + caddr_t rmu_mask; /* the mask */ + struct radix_node *rmu_leaf; /* for normal routes */ + } rm_rmu; + int rm_refs; /* # of references to this struct */ +}; + +#define rm_mask rm_rmu.rmu_mask +#define rm_leaf rm_rmu.rmu_leaf /* extra field would make 32 bytes */ + +#define MKGet(m) {\ + if (rn_mkfreelist) {\ + m = rn_mkfreelist; \ + rn_mkfreelist = (m)->rm_mklist; \ + } else \ + R_Malloc(m, struct radix_mask *, sizeof (*(m))); }\ + +#define MKFree(m) { (m)->rm_mklist = rn_mkfreelist; rn_mkfreelist = (m);} + +typedef int walktree_f_t (struct radix_node *, void *); + +struct radix_node_head { + struct radix_node *rnh_treetop; + int rnh_addrsize; /* permit, but not require fixed keys */ + int rnh_pktsize; /* permit, but not require fixed keys */ + struct radix_node *(*rnh_addaddr) /* add based on sockaddr */ + (void *v, void *mask, + struct radix_node_head *head, struct radix_node nodes[]); + struct radix_node *(*rnh_addpkt) /* add based on packet hdr */ + (void *v, void *mask, + struct radix_node_head *head, struct radix_node nodes[]); + struct radix_node *(*rnh_deladdr) /* remove based on sockaddr */ + (void *v, void *mask, struct radix_node_head *head); + struct radix_node *(*rnh_delpkt) /* remove based on packet hdr */ + (void *v, void *mask, struct radix_node_head *head); + struct radix_node *(*rnh_matchaddr) /* locate based on sockaddr */ + (void *v, struct radix_node_head *head); + struct radix_node *(*rnh_lookup) /* locate based on sockaddr */ + (void *v, void *mask, struct radix_node_head *head); + struct radix_node *(*rnh_matchpkt) /* locate based on packet hdr */ + (void *v, struct radix_node_head *head); + int (*rnh_walktree) /* traverse tree */ + (struct radix_node_head *head, walktree_f_t *f, void *w); + int (*rnh_walktree_from) /* traverse tree below a */ + (struct radix_node_head *head, void *a, void *m, + walktree_f_t *f, void *w); + void (*rnh_close) /* do something when the last ref drops */ + (struct radix_node *rn, struct radix_node_head *head); + struct radix_node rnh_nodes[3]; /* empty tree for common case */ +}; + +#define Bcmp(a, b, n) memcmp(((char *)(a)), ((char *)(b)), (n)) +#define Bcopy(a, b, n) memcpy(((char *)(b)), ((char *)(a)), (unsigned)(n)) +#define Bzero(p, n) memset((char *)(p),0, (int)(n)); +#define R_Malloc(p, t, n) do { \ + (p = (t) malloc((unsigned int)(n))); \ + memset(p, 0, sizeof(*p)); \ + } while (0) +#define Free(p) free((char *)p); + +void rn_init (void); +int rn_inithead (void **, int); +int rn_refines (void *, void *); +struct radix_node + *rn_addmask (void *, int, int), + *rn_addroute (void *, void *, struct radix_node_head *, + struct radix_node [2]), + *rn_delete (void *, void *, struct radix_node_head *), + *rn_lookup (void *v_arg, void *m_arg, + struct radix_node_head *head), + *rn_match (void *, struct radix_node_head *); + +/* extra fucntion so we don't have to export the mask_rnhead */ +struct radix_node *rn_head_search(void *argv_v); + +#endif /* _RADIX_H_ */ diff --git a/headers/posix/net/raw_cb.h b/headers/posix/net/raw_cb.h new file mode 100644 index 0000000000..8af2d33caa --- /dev/null +++ b/headers/posix/net/raw_cb.h @@ -0,0 +1,17 @@ +/* raw_cb.h */ + +#ifndef NET_RAW_CB_H +#define NET_RAW_CB_H + +struct rawcb { + struct rawcb *rcb_next; + struct rawcb *rcb_prev; + struct socket *rcb_socket; + struct sockaddr *rcb_faddr; + struct sockaddr *rcb_laddr; + struct sockproto rcb_proto; +}; + +#define sotorawcb(so) ((struct rawcb*)(so)->so_pcb) + +#endif /* NET_RAW_CB_H */ diff --git a/headers/posix/net/route.h b/headers/posix/net/route.h new file mode 100644 index 0000000000..07b6c2b770 --- /dev/null +++ b/headers/posix/net/route.h @@ -0,0 +1,208 @@ +/* route.h */ + +#ifndef NET_ROUTE_H +#define NET_ROUTE_H + +#include "net/radix.h" +#include "sys/socket.h" /* for AF_MAX */ +/* + * A route consists of a destination address and a reference + * to a routing entry. These are often held by protocols + * in their control blocks, e.g. inpcb. + */ +struct route { + struct rtentry *ro_rt; + struct sockaddr ro_dst; +}; + +/* + * These numbers are used by reliable protocols for determining + * retransmission behavior and are included in the routing structure. + */ +struct rt_metrics { + uint32 rmx_locks; /* Kernel must leave these values alone */ + uint32 rmx_mtu; /* MTU for this path */ + uint32 rmx_hopcount; /* max hops expected */ + uint32 rmx_expire; /* lifetime for route, e.g. redirect */ + u_long rmx_recvpipe; /* inbound delay-bandwith product */ + u_long rmx_sendpipe; /* outbound delay-bandwith product */ + u_long rmx_ssthresh; /* outbound gateway buffer limit */ + u_long rmx_rtt; /* estimated round trip time */ + u_long rmx_rttvar; /* estimated rtt variance */ + u_long rmx_pksent; /* packets sent using this route */ +}; + +/* + * rmx_rtt and rmx_rttvar are stored as microseconds; + * RTTTOPRHZ(rtt) converts to a value suitable for use + * by a protocol slowtimo counter. + */ +#define RTM_RTTUNIT 1000000 /* units for rtt, rttvar, as units per sec */ +#define RTTTOPRHZ(r) ((r) / (RTM_RTTUNIT / PR_SLOWHZ)) + +struct rtentry { + struct radix_node rt_nodes[2]; /* tree glue, and other values */ + struct sockaddr *rt_gateway; /* value */ + uint rt_flags; /* up/down?, host/net */ + int rt_refcnt; /* # held references */ + uint32 rt_use; /* raw # packets forwarded */ + struct ifnet *rt_ifp; /* the answer: interface to use */ + struct ifaddr *rt_ifa; /* the answer: interface to use */ + struct sockaddr *rt_genmask; /* for generation of cloned routes */ + caddr_t rt_llinfo; /* pointer to link level info cache */ + struct rt_metrics rt_rmx; /* metrics used by rx'ing protocols */ + struct rtentry *rt_gwroute; /* implied entry for gatewayed routes */ + struct rtentry *rt_parent; /* If cloned, parent of this route. */ + /* XXX - add this! */ + // rt_timer; * queue of timeouts for misc funcs * +}; +#define rt_use rt_rmx.rmx_pksent +#define rt_key(r) ((struct sockaddr *)((r)->rt_nodes->rn_key)) +#define rt_mask(r) ((struct sockaddr *)((r)->rt_nodes->rn_mask)) + +#define RTF_UP 0x1 /* route usable */ +#define RTF_GATEWAY 0x2 /* destination is a gateway */ +#define RTF_HOST 0x4 /* host entry (net otherwise) */ +#define RTF_REJECT 0x8 /* host or net unreachable */ +#define RTF_DYNAMIC 0x10 /* created dynamically (by redirect) */ +#define RTF_MODIFIED 0x20 /* modified dynamically (by redirect) */ +#define RTF_DONE 0x40 /* message confirmed */ +#define RTF_MASK 0x80 /* subnet mask present */ +#define RTF_CLONING 0x100 /* generate new routes on use */ +#define RTF_XRESOLVE 0x200 /* external daemon resolves name */ +#define RTF_LLINFO 0x400 /* generated by ARP or ESIS */ +#define RTF_STATIC 0x800 /* manually added */ +#define RTF_BLACKHOLE 0x1000 /* just discard pkts (during updates) */ +#define RTF_PROTO3 0x2000 /* protocol specific routing flag */ +#define RTF_PROTO2 0x4000 /* protocol specific routing flag */ +#define RTF_PROTO1 0x8000 /* protocol specific routing flag */ + +#define RTM_VERSION 3 /* Up the ante and ignore older versions */ + +#define RTM_ADD 0x1 /* Add Route */ +#define RTM_DELETE 0x2 /* Delete Route */ +#define RTM_CHANGE 0x3 /* Change Metrics or flags */ +#define RTM_GET 0x4 /* Report Metrics */ +#define RTM_LOSING 0x5 /* Kernel Suspects Partitioning */ +#define RTM_REDIRECT 0x6 /* Told to use different route */ +#define RTM_MISS 0x7 /* Lookup failed on this address */ +#define RTM_LOCK 0x8 /* fix specified metrics */ +#define RTM_OLDADD 0x9 /* caused by SIOCADDRT */ +#define RTM_OLDDEL 0xa /* caused by SIOCDELRT */ +#define RTM_RESOLVE 0xb /* req to resolve dst to LL addr */ +#define RTM_NEWADDR 0xc /* address being added to iface */ +#define RTM_DELADDR 0xd /* address being removed from iface */ +#define RTM_IFINFO 0xe /* iface going up/down etc. */ + +#define RTV_MTU 0x1 /* init or lock _mtu */ +#define RTV_HOPCOUNT 0x2 /* init or lock _hopcount */ +#define RTV_EXPIRE 0x4 /* init or lock _hopcount */ +#define RTV_RPIPE 0x8 /* init or lock _recvpipe */ +#define RTV_SPIPE 0x10 /* init or lock _sendpipe */ +#define RTV_SSTHRESH 0x20 /* init or lock _ssthresh */ +#define RTV_RTT 0x40 /* init or lock _rtt */ +#define RTV_RTTVAR 0x80 /* init or lock _rttvar */ + +/* + * Bitmask values for rtm_addr. + */ +#define RTA_DST 0x1 /* destination sockaddr present */ +#define RTA_GATEWAY 0x2 /* gateway sockaddr present */ +#define RTA_NETMASK 0x4 /* netmask sockaddr present */ +#define RTA_GENMASK 0x8 /* cloning mask sockaddr present */ +#define RTA_IFP 0x10 /* interface name sockaddr present */ +#define RTA_IFA 0x20 /* interface addr sockaddr present */ +#define RTA_AUTHOR 0x40 /* sockaddr for author of redirect */ +#define RTA_BRD 0x80 /* for NEWADDR, broadcast or p-p dest addr */ + +/* + * Index offsets for sockaddr array for alternate internal encoding. + */ +#define RTAX_DST 0 /* destination sockaddr present */ +#define RTAX_GATEWAY 1 /* gateway sockaddr present */ +#define RTAX_NETMASK 2 /* netmask sockaddr present */ +#define RTAX_GENMASK 3 /* cloning mask sockaddr present */ +#define RTAX_IFP 4 /* interface name sockaddr present */ +#define RTAX_IFA 5 /* interface addr sockaddr present */ +#define RTAX_AUTHOR 6 /* sockaddr for author of redirect */ +#define RTAX_BRD 7 /* for NEWADDR, broadcast or p-p dest addr */ +#define RTAX_MAX 8 /* size of array to allocate */ + +struct rt_msghdr { + uint16 rtm_msglen; + uint8 rtm_version; + uint8 rtm_type; + + uint16 rtm_index; + int rtm_flags; + int rtm_addrs; + int rtm_seq; + int rtm_errno; + int rtm_use; + uint32 rtm_inits; + struct rt_metrics rtm_rmx; +}; + +struct rt_addrinfo { + int rti_addrs; + struct sockaddr *rti_info[RTAX_MAX]; + int rti_flags; + struct ifaddr *rti_ifa; + struct ifnet *rti_ifp; + struct rt_msghdr *rti_rtm; +}; + +struct route_cb { + int32 ip_count; /* how many AF_INET structures we have */ + int32 any_count; /* total of all above... */ +}; + +struct walkarg { + int w_op; + int w_arg; + int w_given; + int w_needed; + int w_tmemsize; + caddr_t w_where; + caddr_t w_tmem; +}; + +/* + * Routing statistics. + */ +struct rtstat { + int32 rts_badredirect; /* bogus redirect calls */ + int32 rts_dynamic; /* routes created by redirects */ + int32 rts_newgateway; /* routes modified by redirects */ + int32 rts_unreach; /* lookups which failed */ + int32 rts_wildcard; /* lookups satisfied by a wildcard */ +}; + +#define RTFREE(rt) do { \ + if ((rt)->rt_refcnt <= 1) \ + rtfree(rt); \ + else \ + (rt)->rt_refcnt--; \ +} while (0) + +struct rtstat rtstat; +struct radix_node_head *rt_tables[AF_MAX+1]; + +void route_init(void); + +int rtinit (struct ifaddr *, int, int); +void rtalloc (struct route *); +struct rtentry *rtalloc1 (struct sockaddr *, int); +void rtfree (struct rtentry *); +int rtrequest (int, struct sockaddr *, + struct sockaddr *, struct sockaddr *, int, + struct rtentry **); +void rt_maskedcopy(struct sockaddr *src, + struct sockaddr *dst, + struct sockaddr *netmask); +int rt_setgate (struct rtentry *, struct sockaddr *, + struct sockaddr *); + +struct radix_node_head ** get_rt_tables(void); + +#endif /* NET_ROUTE_H */ diff --git a/headers/posix/net_malloc.h b/headers/posix/net_malloc.h new file mode 100644 index 0000000000..4b041f79a4 --- /dev/null +++ b/headers/posix/net_malloc.h @@ -0,0 +1,37 @@ +/* net_malloc.h + * + * Are we useing the system amlloc or our own... + */ + +#ifndef NET_MALLOC_H +#define NET_MALLOC_H + +#include +#include "net_misc.h" + +#if USE_DEBUG_MALLOC + + + +/* We check the boundary of the malloc'd area at one end of the + * area allocated. If we are outside the area it'll stop, but we can + * check only one end of the boundary. So the following essentially + * allows us to choose which end. + */ +//#define OVERRUN +#ifdef OVERRUN +#define CHECK_OVERRUN 1 +#else +#define CHECK_UNDERRUN 1 +#endif + +/* use the area malloc code from marcus Overhagen */ +void *dbg_malloc(char *file, int line, size_t size); +void dbg_free (char *file, int line, void *ptr); + +#define malloc(s) dbg_malloc(__FILE__, __LINE__, s) +#define free(s) do { dbg_free(__FILE__, __LINE__, s); s = NULL; } while (0) +#endif /* USE_DEBUG_MALLOC */ + +#endif /* NET_MALLOC_H */ + diff --git a/headers/posix/net_misc.h b/headers/posix/net_misc.h new file mode 100644 index 0000000000..ad714fcd87 --- /dev/null +++ b/headers/posix/net_misc.h @@ -0,0 +1,102 @@ +/* net_misc.h + * Miscellaneous networking stuff that doesn't yet have a home. + */ + +#ifdef _NETWORK_STACK + +#include +#include +#include + +#include "sys/mbuf.h" + +#ifndef OBOS_NET_MISC_H +#define OBOS_NET_MISC_H + +#ifdef _KERNEL_ +#include +#define printf dprintf +#endif + +/* Not really sure if this is safe... */ +#define EHOSTDOWN (B_POSIX_ERROR_BASE + 45) + +/* These are GCC only, so we'll need PPC version eventually... */ +struct quehead { + struct quehead *qh_link; + struct quehead *qh_rlink; +}; + +static __inline void insque(void *a, void *b) +{ + struct quehead *element = (struct quehead *)a, + *head = (struct quehead *)b; + + element->qh_link = head->qh_link; + element->qh_rlink = head; + head->qh_link = element; + element->qh_link->qh_rlink = element; +} + +static __inline void remque(void *a) +{ + struct quehead *element = (struct quehead *)a; + + element->qh_link->qh_rlink = element->qh_rlink; + element->qh_rlink->qh_link = element->qh_link; + element->qh_rlink = 0; +} + +/* DEBUG Options! + * + * Having a single option is sort of lame so I'm going to start adding more here... + * + */ +#define SHOW_DEBUG 0 /* general debugging stuff (verbose!) */ +#define SHOW_ROUTE 0 /* show routing information */ +#define ARP_DEBUG 0 /* show ARP debug info */ +#define USE_DEBUG_MALLOC 0 /* use the debug malloc code*/ + +typedef struct ifnet ifnet; + +/* ARP lookup return codes... */ +enum { + ARP_LOOKUP_OK = 1, + ARP_LOOKUP_QUEUED = 2, + ARP_LOOKUP_FAILED = 3 +}; + +typedef uint32 ipv4_addr; + +/* These should be in KernelExport.h */ +#define B_SELECT_READ 1 +#define B_SELECT_WRITE 2 +#define B_SELECT_EXCEPTION 3 + +/* XXX - add some macro's for inserting various types of address + */ + +void net_server_add_device(ifnet *ifn); +uint16 in_cksum(struct mbuf *m, int len, int off); +void local_init(void); + +/* sockets and in_pcb init */ +int sockets_init(void); +void sockets_shutdown(void); +int inpcb_init(void); + +void start_tx_thread(ifnet *dev); +void start_rx_thread(ifnet *dev); + +/* Useful debugging functions */ +void dump_ipv4_addr(char *msg, void *ad); +void print_ipv4_addr(void *ad); +void dump_ether_addr(char *msg, void *ma); +void print_ether_addr(void *ea); +void dump_buffer(char *buffer, int len); +void dump_sockaddr(void *ptr); + +#endif /* OBOS_NET_MISC_H */ + +#endif /* _NETWORK_STACK */ + diff --git a/headers/posix/net_module.h b/headers/posix/net_module.h new file mode 100644 index 0000000000..cba4a18fd1 --- /dev/null +++ b/headers/posix/net_module.h @@ -0,0 +1,56 @@ +/* net_module.h + * fundtions and staructures for all modules using the + * net_server + */ + +#ifndef OBOS_NET_MODULE_H +#define OBOS_NET_MODULE_H + +#include +#include + +#include "sys/mbuf.h" +#include "net_misc.h" +#include "sys/socketvar.h" +#include "net/if.h" +#include "net/route.h" + +#ifdef _KERNEL_ +#include +#else +typedef struct module_info { + const char *name; + uint32 flags; + status_t (*std_ops)(int32, ...); +} module_info; + +#define B_MODULE_INIT 1 +#define B_MODULE_UNINIT 2 +#define B_KEEP_LOADED 0x00000001 +#endif + +struct kernel_net_module_info { + module_info info; + int (*start)(void *); + int (*stop)(void); +}; + +struct net_module { + struct net_module *next; + char *name; + struct kernel_net_module_info *ptr; +#ifndef _KERNEL_ + image_id iid; +#endif + int status; +}; + +enum { + NET_LAYER1 = 1, /* link layer */ + NET_LAYER2, /* network layer */ + NET_LAYER3, /* transport layer */ + NET_LAYER4 /* socket layer */ +}; + +#endif /* OBOS_NET_MODULE_H */ + diff --git a/headers/posix/net_timer.h b/headers/posix/net_timer.h new file mode 100644 index 0000000000..c700d76d56 --- /dev/null +++ b/headers/posix/net_timer.h @@ -0,0 +1,26 @@ +#ifndef NET_TIMER_H +#define NET_TIMER_H +/* net_timer.h - a small and more or less inaccurate timer for net modules. +** The registered hooks will be called in the thread of the timer. +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include + + +typedef void (*net_timer_hook)(void *); +typedef int32 net_timer_id; + + +extern status_t net_init_timer(void); +extern void net_shutdown_timer(void); + +extern net_timer_id net_add_timer(net_timer_hook hook, void *data, bigtime_t interval); +extern status_t net_remove_timer(net_timer_id); + + +#endif /* NET_TIMER_H */ diff --git a/headers/posix/netdb.h b/headers/posix/netdb.h new file mode 100644 index 0000000000..32a6682127 --- /dev/null +++ b/headers/posix/netdb.h @@ -0,0 +1,177 @@ +/* netdb.h */ + +#ifndef NETDB_H +#define NETDB_H + +#include + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 64 +#endif + +#define HOST_NOT_FOUND 1 +#define TRY_AGAIN 2 +#define NO_RECOVERY 3 +#define NO_DATA 4 + +#ifndef h_errno +extern int h_errno; +extern int *_h_errnop(void); +#define h_errno (*_h_errnop()) +#endif /* h_errno */ + +struct hostent { + char *h_name; + char **h_aliases; + int h_addrtype; + int h_length; + char **h_addr_list; +}; +#define h_addr h_addr_list[0] + +struct servent { + char *s_name; + char **s_aliases; + int s_port; + char *s_proto; +}; + +/* + * Assumption here is that a network number + * fits in an in_addr_t -- probably a poor one. + */ +struct netent { + char *n_name; /* official name of net */ + char **n_aliases; /* alias list */ + int n_addrtype; /* net address type */ + in_addr_t n_net; /* network # */ +}; + +struct protoent { + char *p_name; /* official protocol name */ + char **p_aliases; /* alias list */ + int p_proto; /* protocol # */ +}; + +struct addrinfo { + int ai_flags; /* input flags */ + int ai_family; /* protocol family for socket */ + int ai_socktype; /* socket type */ + int ai_protocol; /* protocol for socket */ + socklen_t ai_addrlen; /* length of socket-address */ + struct sockaddr *ai_addr; /* socket-address for socket */ + char *ai_canonname; /* canonical name for service location (iff req) */ + struct addrinfo *ai_next; /* pointer to next in list */ +}; + + +struct hostent *gethostbyname(const char *hostname); +struct hostent *gethostbyaddr(const char *hostname, int len, int type); +struct servent *getservbyname(const char *name, const char *proto); +void herror(const char *); +unsigned long inet_addr(const char *a_addr); +char *inet_ntoa(struct in_addr addr); + +int gethostname(char *hostname, size_t hostlen); + +/* BE specific, because of lack of UNIX passwd functions */ +int getusername(char *username, size_t userlen); +int getpassword(char *password, size_t passlen); + + +/* These are new! */ +struct netent *getnetbyaddr (in_addr_t, int); +struct netent *getnetbyname (const char *); +struct netent *getnetent (void); +struct protoent *getprotoent (void); +struct protoent *getprotobyname (const char *); +struct protoent *getprotobynumber (int); +struct hostent *gethostbyname2 (const char *, int); +struct servent *getservbyport (int, const char *); + +int getaddrinfo (const char *, const char *, + const struct addrinfo *, + struct addrinfo **); +void freeaddrinfo (struct addrinfo *); +int getnameinfo (const struct sockaddr *, socklen_t, + char *, size_t, char *, size_t, + int); + +void sethostent (int); +void setnetent (int); +void setprotoent (int); +void setservent (int); + +void endhostent (void); +void endnetent (void); +void endprotoent (void); +void endservent (void); + +#define _PATH_HEQUIV "/etc/hosts.equiv" +#define _PATH_HOSTS "/etc/hosts" +#define _PATH_NETWORKS "/etc/networks" +#define _PATH_PROTOCOLS "/etc/protocols" +#define _PATH_SERVICES "/etc/services" + +/* + * Error return codes from gethostbyname() and gethostbyaddr() + * (left in extern int h_errno). + */ + +#define NETDB_INTERNAL -1 /* see errno */ +#define NETDB_SUCCESS 0 /* no problem */ +#define HOST_NOT_FOUND 1 /* Authoritative Answer Host not found */ +#define TRY_AGAIN 2 /* Non-Authoritive Host not found, or SERVERFAIL */ +#define NO_RECOVERY 3 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */ +#define NO_DATA 4 /* Valid name, no data record of requested type */ +#define NO_ADDRESS NO_DATA /* no address, look for MX record */ + +/* Values for getaddrinfo() and getnameinfo() */ +#define AI_PASSIVE 1 /* socket address is intended for bind() */ +#define AI_CANONNAME 2 /* request for canonical name */ +#define AI_NUMERICHOST 4 /* don't ever try nameservice */ +#define AI_EXT 8 /* enable non-portable extensions */ +/* valid flags for addrinfo */ +#define AI_MASK (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST) + +#define NI_NUMERICHOST 1 /* return the host address, not the name */ +#define NI_NUMERICSERV 2 /* return the service address, not the name */ +#define NI_NOFQDN 4 /* return a short name if in the local domain */ +#define NI_NAMEREQD 8 /* fail if either host or service name is unknown */ +#define NI_DGRAM 16 /* look up datagram service instead of stream */ +#define NI_WITHSCOPEID 32 /* KAME hack: attach scopeid to host portion */ + +#define NI_MAXHOST MAXHOSTNAMELEN /* max host name returned by getnameinfo */ +#define NI_MAXSERV 32 /* max serv. name length returned by getnameinfo */ + +/* + * Scope delimit character (KAME hack) + */ +#define SCOPE_DELIMITER '%' + +#define EAI_BADFLAGS -1 /* invalid value for ai_flags */ +#define EAI_NONAME -2 /* name or service is not known */ +#define EAI_AGAIN -3 /* temporary failure in name resolution */ +#define EAI_FAIL -4 /* non-recoverable failure in name resolution */ +#define EAI_NODATA -5 /* no address associated with name */ +#define EAI_FAMILY -6 /* ai_family not supported */ +#define EAI_SOCKTYPE -7 /* ai_socktype not supported */ +#define EAI_SERVICE -8 /* service not supported for ai_socktype */ +#define EAI_ADDRFAMILY -9 /* address family for name not supported */ +#define EAI_MEMORY -10 /* memory allocation failure */ +#define EAI_SYSTEM -11 /* system error (code indicated in errno) */ +#define EAI_BADHINTS -12 /* invalid value for hints */ +#define EAI_PROTOCOL -13 /* resolved protocol is unknown */ + + +/* + * Flags for getrrsetbyname() + */ +#define RRSET_VALIDATED 1 + +/* + * Return codes for getrrsetbyname() + */ +#define ERRSET_SUCCESS 0 + +#endif /* NETDB_H */ diff --git a/headers/posix/netinet/icmp_var.h b/headers/posix/netinet/icmp_var.h new file mode 100644 index 0000000000..a147803eb2 --- /dev/null +++ b/headers/posix/netinet/icmp_var.h @@ -0,0 +1,61 @@ +/* Parts of this file are covered under the following copyright */ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)icmp_var.h 8.1 (Berkeley) 6/10/93 + */ + +#ifndef NETINET_ICMP_VAR_H +#define NETINET_ICMP_VAR_H + +#include + +#include "netinet/ip_icmp.h" + +struct icmpstat { + int32 icps_oldicmp; + int32 icps_oldshort; + int32 icps_badcode; + int32 icps_badlen; + int32 icps_checksum; + int32 icps_tooshort; + int32 icps_error; + int32 icps_reflect; + int32 icps_outhist[ICMP_MAXTYPE + 1]; + int32 icps_inhist[ICMP_MAXTYPE + 1]; +}; + +#ifdef _NETWORK_STACK +struct icmpstat icmpstat; +#endif + +#endif /* NETINET_ICMP_VAR_H */ diff --git a/headers/posix/netinet/if_ether.h b/headers/posix/netinet/if_ether.h new file mode 100644 index 0000000000..2ac714f8f3 --- /dev/null +++ b/headers/posix/netinet/if_ether.h @@ -0,0 +1,200 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)if_ether.h 8.1 (Berkeley) 6/10/93 + */ + +#ifndef NETINET_IF_ETHER_H +#define NETINET_IF_ETHER_H + +#include + +#include "net/if_arp.h" + +/* + * Ethernet address - 6 octets + * this is only used by the ethers(3) functions. + */ +struct ether_addr { + uint8 ether_addr_octet[6]; +}; + +/* + * Some Ethernet constants. + */ +#define ETHER_ADDR_LEN 6 /* Ethernet address length */ +#define ETHER_TYPE_LEN 2 /* Ethernet type field length */ +#define ETHER_CRC_LEN 4 /* Ethernet CRC lenght */ +#define ETHER_HDR_LEN ((ETHER_ADDR_LEN * 2) + ETHER_TYPE_LEN) +#define ETHER_MIN_LEN 64 /* Minimum frame length, CRC included */ +#define ETHER_MAX_LEN 1518 /* Maximum frame length, CRC included */ + +struct ether_header { + uint8 ether_dhost[ETHER_ADDR_LEN]; + uint8 ether_shost[ETHER_ADDR_LEN]; + uint16 ether_type; +}; + +#define ETHERTYPE_PUP 0x0200 /* PUP protocol */ +#define ETHERTYPE_IP 0x0800 /* IP protocol */ +#define ETHERTYPE_ARP 0x0806 /* address resolution protocol */ +#define ETHERTYPE_REVARP 0x8035 /* reverse addr resolution protocol */ +#define ETHERTYPE_8021Q 0x8100 /* IEEE 802.1Q VLAN tagging */ +#define ETHERTYPE_IPV6 0x86DD /* IPv6 protocol */ +#define ETHERTYPE_PPPOEDISC 0x8863 /* PPP Over Ethernet Discovery Stage */ +#define ETHERTYPE_PPPOE 0x8864 /* PPP Over Ethernet Session Stage */ +#define ETHERTYPE_LOOPBACK 0x9000 /* used to test interfaces */ + +#define ETHER_IS_MULTICAST(addr) (*(addr) & 0x01) /* is address mcast/bcast? */ + +#define ETHERMTU (ETHER_MAX_LEN - ETHER_HDR_LEN - ETHER_CRC_LEN) +#define ETHERMIN (ETHER_MIN_LEN - ETHER_HDR_LEN - ETHER_CRC_LEN) + + +#ifdef _NETWORK_STACK + +/* + * Macro to map an IP multicast address to an Ethernet multicast address. + * The high-order 25 bits of the Ethernet address are statically assigned, + * and the low-order 23 bits are taken from the low end of the IP address. + */ +#define ETHER_MAP_IP_MULTICAST(ipaddr, enaddr) \ + /* struct in_addr *ipaddr; */ \ + /* u_int8_t enaddr[ETHER_ADDR_LEN]; */ \ +{ \ + (enaddr)[0] = 0x01; \ + (enaddr)[1] = 0x00; \ + (enaddr)[2] = 0x5e; \ + (enaddr)[3] = ((uint8 *)ipaddr)[1] & 0x7f; \ + (enaddr)[4] = ((uint8 *)ipaddr)[2]; \ + (enaddr)[5] = ((uint8 *)ipaddr)[3]; \ +} + +/* + * Macro to map an IPv6 multicast address to an Ethernet multicast address. + * The high-order 16 bits of the Ethernet address are statically assigned, + * and the low-order 32 bits are taken from the low end of the IPv6 address. + */ +#define ETHER_MAP_IPV6_MULTICAST(ip6addr, enaddr) \ + /* struct in6_addr *ip6addr; */ \ + /* u_int8_t enaddr[ETHER_ADDR_LEN]; */ \ +{ \ + (enaddr)[0] = 0x33; \ + (enaddr)[1] = 0x33; \ + (enaddr)[2] = ((u_int8_t *)ip6addr)[12]; \ + (enaddr)[3] = ((u_int8_t *)ip6addr)[13]; \ + (enaddr)[4] = ((u_int8_t *)ip6addr)[14]; \ + (enaddr)[5] = ((u_int8_t *)ip6addr)[15]; \ +} +#endif + +/* + * Structure shared between the ethernet driver modules and + * the address resolution code. For example, each ec_softc or il_softc + * begins with this structure. + */ +struct arpcom { + struct ifnet ac_if; /* network-visible interface */ + uint8 ac_enaddr[ETHER_ADDR_LEN]; /* ethernet hardware address */ + struct in_addr ac_ipaddr; + char ac__pad[2]; /* pad for some machines */ +// struct ether_multi *ac_multiaddrs; /* list of ether multicast addrs */ + int ac_multicnt; /* length of ac_multiaddrs list */ +}; + +struct ether_device { + struct arpcom sc_ac; + struct ether_device *next; /* next ether_device */ +}; +#define sc_if sc_ac.ac_if +#define sc_addr sc_ac.ac_enaddr + +struct ether_arp { + struct arphdr ea_hdr; + u_char arp_sha[6]; + u_char arp_spa[4]; + u_char arp_tha[6]; + u_char arp_tpa[4]; +}; +#define arp_hrd ea_hdr.ar_hrd +#define arp_pro ea_hdr.ar_pro +#define arp_hln ea_hdr.ar_hln +#define arp_pln ea_hdr.ar_pln +#define arp_op ea_hdr.ar_op + +struct llinfo_arp { + struct llinfo_arp *la_next; + struct llinfo_arp *la_prev; + struct rtentry *la_rt; + struct mbuf *la_hold; + int32 la_asked; +}; + +#define la_timer la_rt->rt_rmx.rmx_expire + +struct sockaddr_inarp { + uint8 sin_len; + uint8 sin_family; + uint16 sin_port; + struct in_addr sin_addr; + struct in_addr sin_srcaddr; + uint16 sin_tos; + uint16 sin_other; +}; +#define SIN_PROXY 1 + +/* + * IP and ethernet specific routing flags + */ +#define RTF_USETRAILERS RTF_PROTO1 /* use trailers */ +#define RTF_ANNOUNCE RTF_PROTO2 /* announce new arp entry */ +#define RTF_PERMANENT_ARP RTF_PROTO3 /* only manual overwrite of entry */ + +#ifdef _NETWORK_STACK + +int arpresolve(struct arpcom *ac, struct rtentry *rt, struct mbuf *m, + struct sockaddr *dst, uint8 *desten); +void arpwhohas(struct arpcom *ac, struct in_addr *ia); + + +#else + +char *ether_ntoa (struct ether_addr *); +struct ether_addr *ether_aton (char *); +int ether_ntohost (char *, struct ether_addr *); +int ether_hostton (char *, struct ether_addr *); +int ether_line(char *line, struct ether_addr *e, char *hostname); + +#endif + +#endif /* NETINET_IF_ETHER_H */ + diff --git a/headers/posix/netinet/in.h b/headers/posix/netinet/in.h new file mode 100644 index 0000000000..5a6fc0ec01 --- /dev/null +++ b/headers/posix/netinet/in.h @@ -0,0 +1,148 @@ +/* in.h */ +#ifndef _NETINET_IN_H_ +#define _NETINET_IN_H_ + +#include /* for htonl */ + +#ifdef _NETWORK_STACK +#include "net_misc.h" +#endif +#include "net/if.h" + +/* XXX - This really doesn't belong in here... */ +/* XXX - move these to sys/param.h */ +typedef uint32 in_addr_t; +typedef uint16 in_port_t; + +/* Protocol definitions - add to as required... */ + +enum { + IPPROTO_IP = 0, /* 0, IPv4 */ + IPPROTO_ICMP = 1, /* 1, ICMP (v4) */ + IPPROTO_IGMP = 2, /* 2, IGMP (group management) */ + IPPROTO_TCP = 6, /* 6, tcp */ + IPPROTO_UDP = 17, /* 17, UDP */ + IPPROTO_IPV6 = 41, /* 41, IPv6 in IPv6 */ + IPPROTO_ROUTING = 43, /* 43, Routing */ + IPPROTO_ICMPV6 = 58, /* 58, IPv6 ICMP */ + IPPROTO_ETHERIP = 97, /* 97, Ethernet in IPv4 */ + IPPROTO_RAW = 255 /* 255 */ +}; + +#define IPPROTO_MAX 256 + +/* Port numbers... + * < IPPORT_RESERVED are privileged and should be + * accessible only by root + * > IPPORT_USERRESERVED are reserved for servers, though + * not requiring privileged status + */ + +#define IPPORT_RESERVED 1024 +#define IPPORT_USERRESERVED 49151 + +/* This is an IPv4 address structure. Why is it a structure? + * Historical reasons. + */ +struct in_addr { + in_addr_t s_addr; +}; + +/* + * IP Version 4 socket address. + */ +struct sockaddr_in { + uint8 sin_len; + uint8 sin_family; + uint16 sin_port; + struct in_addr sin_addr; + int8 sin_zero[8]; +}; +/* the address is therefore at sin_addr.s_addr */ + +/* + * Options for use with [gs]etsockopt at the IP level. + * First word of comment is data type; bool is stored in int. + */ +#define IP_OPTIONS 1 /* buf/ip_opts; set/get IP options */ +#define IP_HDRINCL 2 /* int; header is included with data */ +#define IP_TOS 3 /* int; IP type of service and preced. */ +#define IP_TTL 4 /* int; IP time to live */ +#define IP_RECVOPTS 5 /* bool; receive all IP opts w/dgram */ +#define IP_RECVRETOPTS 6 /* bool; receive IP opts for response */ +#define IP_RECVDSTADDR 7 /* bool; receive IP dst addr w/dgram */ +#define IP_RETOPTS 8 /* ip_opts; set/get IP options */ +#define IP_MULTICAST_IF 9 /* in_addr; set/get IP multicast i/f */ +#define IP_MULTICAST_TTL 10 /* u_char; set/get IP multicast ttl */ +#define IP_MULTICAST_LOOP 11 /* u_char; set/get IP multicast loopback */ +#define IP_ADD_MEMBERSHIP 12 /* ip_mreq; add an IP group membership */ +#define IP_DROP_MEMBERSHIP 13 /* ip_mreq; drop an IP group membership */ + +#ifdef _NETWORK_STACK +#define __IPADDR(x) ((uint32) htonl((uint32)(x))) +#else +#define __IPADDR(x) ((uint32)(x)) +#endif + +#define INADDR_ANY __IPADDR(0x00000000) +#define INADDR_LOOPBACK __IPADDR(0x7f000001) +#define INADDR_BROADCAST __IPADDR(0xffffffff) /* must be masked */ + +#define INADDR_UNSPEC_GROUP __IPADDR(0xe0000000) /* 224.0.0.0 */ +#define INADDR_ALLHOSTS_GROUP __IPADDR(0xe0000001) /* 224.0.0.1 */ +#define INADDR_ALLROUTERS_GROUP __IPADDR(0xe0000002) /* 224.0.0.2 */ +#define INADDR_MAX_LOCAL_GROUP __IPADDR(0xe00000ff) /* 224.0.0.255 */ + +#define IN_LOOPBACKNET 127 /* official! */ + +#ifndef _NETWORK_STACK +#define INADDR_NONE __IPADDR(0xffffffff) +#endif + +#define IN_CLASSA(i) (((uint32)(i) & __IPADDR(0x80000000)) == \ + __IPADDR(0x00000000)) +#define IN_CLASSA_NET __IPADDR(0xff000000) +#define IN_CLASSA_NSHIFT 24 +#define IN_CLASSA_HOST __IPADDR(0x00ffffff) +#define IN_CLASSA_MAX 128 + +#define IN_CLASSB(i) (((uint32)(i) & __IPADDR(0xc0000000)) == \ + __IPADDR(0x80000000)) +#define IN_CLASSB_NET __IPADDR(0xffff0000) +#define IN_CLASSB_NSHIFT 16 +#define IN_CLASSB_HOST __IPADDR(0x0000ffff) +#define IN_CLASSB_MAX 65536 + +#define IN_CLASSC(i) (((uint32)(i) & __IPADDR(0xe0000000)) == \ + __IPADDR(0xc0000000)) +#define IN_CLASSC_NET __IPADDR(0xffffff00) +#define IN_CLASSC_NSHIFT 8 +#define IN_CLASSC_HOST __IPADDR(0x000000ff) + +#define IN_CLASSD(i) (((uint32)(i) & __IPADDR(0xf0000000)) == \ + __IPADDR(0xe0000000)) +/* These ones aren't really net and host fields, but routing needn't know. */ +#define IN_CLASSD_NET __IPADDR(0xf0000000) +#define IN_CLASSD_NSHIFT 28 +#define IN_CLASSD_HOST __IPADDR(0x0fffffff) + +#define IN_MULTICAST(i) IN_CLASSD(i) + +#define IN_EXPERIMENTAL(i) (((uint32)(i) & 0xf0000000) == 0xf0000000) +#define IN_BADCLASS(i) (((uint32)(i) & 0xf0000000) == 0xf0000000) + +#define IP_MAX_MEMBERSHIPS 20 + +/* some helpful macro's :) */ +#define in_hosteq(s,t) ((s).s_addr == (t).s_addr) +#define in_nullhost(x) ((x).s_addr == INADDR_ANY) +#define satosin(sa) ((struct sockaddr_in *)(sa)) +#define sintosa(sin) ((struct sockaddr *)(sin)) + +/* Prototypes... */ +int in_broadcast (struct in_addr, struct ifnet *); +int in_canforward (struct in_addr); +int in_localaddr (struct in_addr); +void in_socktrim (struct sockaddr_in*); + +#endif /* NETINET_IN_H */ diff --git a/headers/posix/netinet/in_pcb.h b/headers/posix/netinet/in_pcb.h new file mode 100644 index 0000000000..42a936fa55 --- /dev/null +++ b/headers/posix/netinet/in_pcb.h @@ -0,0 +1,71 @@ +/* in_pcb.h + * internet protcol control blocks + */ + +#include "sys/socketvar.h" +#include "sys/socket.h" +#include "net_misc.h" +#include "pools.h" +#include "netinet/ip.h" +#include "netinet/in.h" +#include "net/route.h" + +#ifndef IN_PCB_H +#define IN_PCB_H + +enum { + INP_HDRINCL = 0x01, + INP_RECVOPTS = 0x02, + INP_RECVRETOPTS = 0x04, + INP_RECVDSTADDR = 0x08 /* receive IP destination as control inf. */ +}; +#define INP_CONTROLOPT (INP_RECVOPTS | INP_RECVRETOPTS | INP_RECVDSTADDR) + +/* Constants for in_pcblookup */ +enum { + INPLOOKUP_WILDCARD = 1, + INPLOOKUP_SETLOCAL = 2, + INPLOOKUP_IPV6 = 4 +}; + +struct inpcb { + struct inpcb *inp_next; + struct inpcb *inp_prev; + struct inpcb *inp_head; + + struct in_addr faddr; /* foreign address */ + uint16 fport; /* foreign port # */ + struct in_addr laddr; /* local address */ + uint16 lport; /* local port # */ + + struct socket *inp_socket; + caddr_t inp_ppcb; /* pointer to a per protocol pcb*/ + struct ip inp_ip; /* header prototype */ + int inp_flags; /* flags */ + struct mbuf *inp_options; /* IP options */ + /* more will be required */ + struct route inp_route; /* the route to host */ +}; + +int in_pcballoc (struct socket *, struct inpcb *); +int in_pcbbind (struct inpcb *, struct mbuf *); +int in_pcbconnect (struct inpcb *, struct mbuf *); +void in_pcbdetach (struct inpcb *); +int in_pcbdisconnect (struct inpcb *); +void in_losing (struct inpcb *); +void in_setpeeraddr (struct inpcb *, struct mbuf *); +void in_setsockaddr (struct inpcb *, struct mbuf *); + +struct inpcb *in_pcblookup(struct inpcb *head, struct in_addr faddr, + uint16 fport_a, struct in_addr laddr, + uint16 lport_a, int flags); +struct rtentry *in_pcbrtentry (struct inpcb *); +void in_pcbnotify (struct inpcb *, struct sockaddr *, + uint16, struct in_addr, uint16, + int, void (*)(struct inpcb *, int)); + +/* helpful macro's */ +#define sotoinpcb(so) ((struct inpcb *)(so)->so_pcb) + +#endif /* IN_PCB_H */ + diff --git a/headers/posix/netinet/in_systm.h b/headers/posix/netinet/in_systm.h new file mode 100644 index 0000000000..8a80663d4f --- /dev/null +++ b/headers/posix/netinet/in_systm.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 1982, 1986, 1993 + *The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + *This product includes software developed by the University of + *California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *@(#)in_systm.h 8.1 (Berkeley) 6/10/93 + */ + +#ifndef NETINET_IN_SYSTM_H +#define NETINET_IN_SYSTM_H + +/* + * Miscellaneous internetwork + * definitions for kernel. + */ + +/* + * Network types. + * + * Internally the system keeps counters in the headers with the bytes + * swapped so that VAX instructions will work on them. It reverses + * the bytes before transmission at each protocol level. The n_ types + * represent the types with the bytes in ``high-ender'' order. + */ +typedef uint16 n_short; /* short as received from the net */ +typedef uint32 n_long; /* long as received from the net */ + +typedef uint32 n_time; /* ms since 00:00 GMT, byte rev */ + +#ifdef _NETWORK_STACK +#define iptime() (htonl((uint32)real_time_clock_usecs())) +#endif /* _NETWORK_STACK */ + +#endif /* NETINET_IN_SYSTM_H */ + + diff --git a/headers/posix/netinet/in_var.h b/headers/posix/netinet/in_var.h new file mode 100644 index 0000000000..5d06fb5027 --- /dev/null +++ b/headers/posix/netinet/in_var.h @@ -0,0 +1,64 @@ +/* in_var.h */ +#ifndef NETINET_IN_VAR_H +#define NETINET_IN_VAR_H + +#include "netinet/in.h" +#include "net/if.h" + +struct in_ifaddr { + struct ifaddr ia_ifa; + struct in_ifaddr *ia_next; + + uint32 ia_net; + uint32 ia_netmask; + uint32 ia_subnet; + uint32 ia_subnetmask; + struct in_addr ia_netbroadcast; + struct sockaddr_in ia_addr; + struct sockaddr_in ia_dstaddr; /* broadcast address */ + struct sockaddr_in ia_sockmask; + /*XXX - milticast address list */ +}; +#define ia_ifp ia_ifa.ifa_ifp +#define ia_flags ia_ifa.ifa_flags +#define ia_broadaddr ia_dstaddr + +#define ifatoia(ifa) ((struct in_ifaddr *)(ifa)) +#define sintosa(sin) ((struct sockaddr *)(sin)) + +/* used to pass in additional information, such as aliases */ +struct in_aliasreq { + char ifa_name[IFNAMSIZ]; + struct sockaddr_in ifra_addr; + struct sockaddr_in ifra_broadaddr; +#define ifra_dstaddr ifra_broadaddr + struct sockaddr_in ifra_mask; +}; + + +struct in_multi { + struct in_addr inm_addr; + struct ifnet *inm_ifp; + struct in_ifaddr *inm_ia; + uint inm_refcount; + uint inm_timer; + struct in_multi *next; + struct in_multi **prev; + uint inm_state; +}; + +/* + * Given a pointer to an in_ifaddr (ifaddr), + * return a pointer to the addr as a sockaddr_in. + */ +#define IA_SIN(ia) (&(((struct in_ifaddr *)(ia))->ia_addr)) + +struct in_ifaddr *in_ifaddr; + +int in_control(struct socket *so, int cmd, caddr_t data, struct ifnet *ifp); +int in_ifinit(struct ifnet *dev, struct in_ifaddr *ia, struct sockaddr_in *sin, + int scrub); +int inetctlerr(int cmd); +struct in_ifaddr *get_primary_addr(void); + +#endif /* NETINET_IN_VAR_H */ diff --git a/headers/posix/netinet/ip.h b/headers/posix/netinet/ip.h new file mode 100644 index 0000000000..3f364850f6 --- /dev/null +++ b/headers/posix/netinet/ip.h @@ -0,0 +1,129 @@ +/* netinet/ip.h + * definitions for ipv4 protocol + */ + +#ifndef NETINET_IP_H +#define NETINET_IP_H + +#include + +#include "sys/mbuf.h" +#include "net_misc.h" +#include "netinet/in_systm.h" +#include "netinet/in.h" + +/* Based on RFC 791 */ + +#define IPVERSION 4 + +struct ip { +#if B_HOST_IS_BENDIAN + uint8 ip_v:4; + uint8 ip_hl:4; +#else + uint8 ip_hl:4; + uint8 ip_v:4; +#endif + uint8 ip_tos; + uint16 ip_len; + uint16 ip_id; + int16 ip_off; + uint8 ip_ttl; + uint8 ip_p; + uint16 ip_sum; + struct in_addr ip_src; + struct in_addr ip_dst; +} _PACKED; + +#define IP_MAXPACKET 65535/* Maximum packet size */ + +/* IP Type of Service */ +#define IPTOS_RELIABILITY 0x04 +#define IPTOS_THROUGHPUT 0x08 +#define IPTOS_LOWDELAY 0x10 + +/* + * Definitions for options. + */ +#define IPOPT_COPIED(o)((o)&0x80) +#define IPOPT_CLASS(o)((o)&0x60) +#define IPOPT_NUMBER(o)((o)&0x1f) + +#define IPOPT_CONTROL 0x00 +#define IPOPT_RESERVED1 0x20 +#define IPOPT_DEBMEAS 0x40 +#define IPOPT_RESERVED2 0x60 + +#define IPOPT_EOL 0/* end of option list */ +#define IPOPT_NOP 1/* no operation */ + +#define IPOPT_RR 7/* record packet route */ +#define IPOPT_TS 68/* timestamp */ +#define IPOPT_SECURITY 130/* provide s,c,h,tcc */ +#define IPOPT_LSRR 131/* loose source route */ +#define IPOPT_SATID 136/* satnet id */ +#define IPOPT_SSRR 137/* strict source route */ + +/* + * Offsets to fields in options other than EOL and NOP. + */ +#define IPOPT_OPTVAL 0/* option ID */ +#define IPOPT_OLEN 1/* option length */ +#define IPOPT_OFFSET 2/* offset within option */ +#define IPOPT_MINOFF 4/* min value of above */ + +struct ip_timestamp { + uint8 ipt_code;/* IPOPT_TS */ + uint8 ipt_len;/* size of structure (variable) */ + uint8 ipt_ptr;/* index of current entry */ +#if B_HOST_IS_BENDIAN + uint8 ipt_oflw:4, + ipt_flg:4; +#else + uint8 ipt_flg:4, + ipt_oflw:4; +#endif + union ipt_timestamp { + n_time ipt_time[1]; + struct ipt_ta { + struct in_addr ipt_addr; + n_time ipt_time; + } ipt_ta; + } ipt_timestamp; +}; + +/* flag bits for ipt_flg */ +#define IPOPT_TS_TSONLY 0/* timestamps only */ +#define IPOPT_TS_TSANDADDR 1/* timestamps and addresses */ +#define IPOPT_TS_PRESPEC 3/* specified modules only */ + +/* bits for security (not byte swapped) */ +#define IPOPT_SECUR_UNCLASS 0x0000 +#define IPOPT_SECUR_CONFID 0xf135 +#define IPOPT_SECUR_EFTO 0x789a +#define IPOPT_SECUR_MMMM 0xbc4d +#define IPOPT_SECUR_RESTR 0xaf13 +#define IPOPT_SECUR_SECRET 0xd788 +#define IPOPT_SECUR_TOPSECRET 0x6bc5 + +#define MAXTTL 255/* maximum time to live (seconds) */ +#define IPDEFTTL 64/* default ttl, from RFC 1340 */ +#define IPFRAGTTL 60/* time to live for frags, slowhz */ +#define IPTTLDEC 1/* subtracted when forwarding */ + +#define IP_MSS 576/* default maximum segment size */ + +struct ippseudo { + struct in_addr ippseudo_src; /* source internet address */ + struct in_addr ippseudo_dst; /* destination internet address */ + uint8 ippseudo_pad;/* pad, must be zero */ + uint8 ippseudo_p;/* protocol */ + uint16 ippseudo_len;/* protocol length */ +}; + +/* Fragment flags */ +#define IP_DF 0x4000 /* don't fragment */ +#define IP_MF 0x2000 /* more fragments */ +#define IP_OFFMASK 0x1fff + +#endif /* NETINET_IP_H */ diff --git a/headers/posix/netinet/ip_icmp.h b/headers/posix/netinet/ip_icmp.h new file mode 100644 index 0000000000..2959004ad7 --- /dev/null +++ b/headers/posix/netinet/ip_icmp.h @@ -0,0 +1,172 @@ +/* Parts of this file are covered under the following copyright */ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ip_icmp.h 8.1 (Berkeley) 6/10/93 + */ + +#ifndef NETINET_IP_ICMP_H +#define NETINET_IP_ICMP_H + +#include + +#include "net_misc.h" +#include "netinet/in.h" + +struct icmp { + uint8 icmp_type; + uint8 icmp_code; + uint16 icmp_cksum; + union { + uint8 ih_pptr; + struct in_addr ih_gwaddr; + struct ih_idseq { + n_short icd_id; + n_short icd_seq; + } ih_idseq; + int32 ih_void; + + /* ICMP_UNREACH_NEEDFRAG (RFC 1191) */ + struct ih_pmtu { + n_short ipm_void; + n_short ipm_nextmtu; + } ih_pmtu; + } icmp_hun; + union { + struct id_ts { + n_time its_otime; + n_time its_rtime; + n_time its_ttime; + } id_ts; + struct id_ip { + struct ip idi_ip; + } id_ip; + uint32 id_mask; + char id_data[1]; + } icmp_dun; +}; + +#define icmp_pptr icmp_hun.ih_pptr +#define icmp_gwaddr icmp_hun.ih_gwaddr +#define icmp_id icmp_hun.ih_idseq.icd_id +#define icmp_seq icmp_hun.ih_idseq.icd_seq +#define icmp_void icmp_hun.ih_void +#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void +#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu + +#define icmp_otime icmp_dun.id_ts.its_otime +#define icmp_rtime icmp_dun.id_ts.its_rtime +#define icmp_ttime icmp_dun.id_ts.its_ttime +#define icmp_ip icmp_dun.id_ip.idi_ip +#define icmp_mask icmp_dun.id_mask +#define icmp_data icmp_dun.id_data + +#define ICMP_MINLEN 8 /* absolute minimum length */ +#define ICMP_ADVLENMIN (8 + sizeof(struct ip) + 8) +#define ICMP_ADVLEN(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8) + +/* Definition of type and code field values. + *http://www.iana.org/assignments/icmp-parameters + */ +#define ICMP_ECHOREPLY 0/* echo reply */ +#define ICMP_UNREACH 3/* dest unreachable, codes: */ +#define ICMP_SOURCEQUENCH 4/* packet lost, slow down */ +#define ICMP_REDIRECT 5/* shorter route, codes: */ +#define ICMP_ALTHOSTADDR 6/* alternate host address */ +#define ICMP_ECHO 8/* echo service */ +#define ICMP_ROUTERADVERT 9/* router advertisement */ +#define ICMP_ROUTERSOLICIT 10/* router solicitation */ +#define ICMP_TIMXCEED 11/* time exceeded, code: */ +#define ICMP_PARAMPROB 12/* ip header bad */ +#define ICMP_TSTAMP 13/* timestamp request */ +#define ICMP_TSTAMPREPLY 14/* timestamp reply */ +#define ICMP_IREQ 15/* information request */ +#define ICMP_IREQREPLY 16/* information reply */ +#define ICMP_MASKREQ 17/* address mask request */ +#define ICMP_MASKREPLY 18/* address mask reply */ +#define ICMP_TRACEROUTE 30/* traceroute */ +#define ICMP_DATACONVERR 31/* data conversion error */ +#define ICMP_MOBILE_REDIRECT 32/* mobile host redirect */ +#define ICMP_IPV6_WHEREAREYOU 33/* IPv6 where-are-you */ +#define ICMP_IPV6_IAMHERE 34/* IPv6 i-am-here */ +#define ICMP_MOBILE_REGREQUEST 35/* mobile registration req */ +#define ICMP_MOBILE_REGREPLY 36/* mobile registration reply */ +#define ICMP_SKIP 39/* SKIP */ +#define ICMP_PHOTURIS 40/* Photuris */ + +#define ICMP_MAXTYPE 40 + +#define ICMP_UNREACH_NET 0/* bad net */ +#define ICMP_UNREACH_HOST 1/* bad host */ +#define ICMP_UNREACH_PROTOCOL 2/* bad protocol */ +#define ICMP_UNREACH_PORT 3/* bad port */ +#define ICMP_UNREACH_NEEDFRAG 4/* IP_DF caused drop */ +#define ICMP_UNREACH_SRCFAIL 5/* src route failed */ +#define ICMP_UNREACH_NET_UNKNOWN 6/* unknown net */ +#define ICMP_UNREACH_HOST_UNKNOWN 7/* unknown host */ +#define ICMP_UNREACH_ISOLATED 8/* src host isolated */ +#define ICMP_UNREACH_NET_PROHIB 9/* for crypto devs */ +#define ICMP_UNREACH_HOST_PROHIB 10/* ditto */ +#define ICMP_UNREACH_TOSNET 11/* bad tos for net */ +#define ICMP_UNREACH_TOSHOST 12/* bad tos for host */ +#define ICMP_UNREACH_FILTER_PROHIB 13/* prohibited access */ +#define ICMP_UNREACH_HOST_PRECEDENCE 14/* precedence violat'n*/ +#define ICMP_UNREACH_PRECEDENCE_CUTOFF 15/* precedence cutoff */ + +#define ICMP_REDIRECT_NET 0/* for network */ +#define ICMP_REDIRECT_HOST 1/* for host */ +#define ICMP_REDIRECT_TOSNET 2/* for tos and net */ +#define ICMP_REDIRECT_TOSHOST 3/* for tos and host */ + +#define ICMP_ROUTERADVERT_NORMAL 0/* normal advertisement */ +#define ICMP_ROUTERADVERT_NOROUTE_COMMON16/* selective routing */ + +#define ICMP_TIMXCEED_INTRANS 0/* ttl==0 in transit */ +#define ICMP_TIMXCEED_REASS 1/* ttl==0 in reass */ + +#define ICMP_PARAMPROB_ERRATPTR 0/* req. opt. absent */ +#define ICMP_PARAMPROB_OPTABSENT 1/* req. opt. absent */ +#define ICMP_PARAMPROB_LENGTH 2/* bad length */ + +#define ICMP_PHOTURIS_UNKNOWN_INDEX 1/* unknown sec index */ +#define ICMP_PHOTURIS_AUTH_FAILED 2/* auth failed */ +#define ICMP_PHOTURIS_DECRYPT_FAILED 3/* decrypt failed */ + + +#define ICMP_INFOTYPE(type) \ + ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \ + (type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \ + (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \ + (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \ + (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY) + +#endif /* NETINET_IP_ICMP_H */ diff --git a/headers/posix/netinet/ip_var.h b/headers/posix/netinet/ip_var.h new file mode 100644 index 0000000000..f41b976580 --- /dev/null +++ b/headers/posix/netinet/ip_var.h @@ -0,0 +1,155 @@ +/* Parts of this file are covered under the following copyright */ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ip_var.h 8.1 (Berkeley) 6/10/93 + */ + +#ifndef NETINET_IP_VAR_H +#define NETINET_IP_VAR_H + +#include "sys/socket.h" + +/* + * Overlay for ip header used by other protocols (tcp, udp). + */ +struct ipovly { + caddr_t ih_next; + caddr_t ih_prev; + uint8 ih_x1; /* (unused) */ + uint8 ih_pr; /* protocol */ + uint16 ih_len; /* protocol length */ + struct in_addr ih_src; /* source internet address */ + struct in_addr ih_dst; /* destination internet address */ +}; + +/* + * Structure stored in mbuf in inpcb.ip_options + * and passed to ip_output when ip options are in use. + * The actual length of the options (including ipopt_dst) + * is in m_len. + */ +#define MAX_IPOPTLEN 40 + +struct ipoption { + struct in_addr ipopt_dst; /* first-hop dst if source routed */ + int8 ipopt_list[MAX_IPOPTLEN]; /* options proper */ +}; + +/* + * Structure attached to inpcb.ip_moptions and + * passed to ip_output when IP multicast options are in use. + */ +struct ip_moptions { + struct ifnet *imo_multicast_ifp; /* ifp for outgoing multicasts */ + uint8 imo_multicast_ttl; /* TTL for outgoing multicasts */ + uint8 imo_multicast_loop; /* 1 => here sends if a member */ + uint16 imo_num_memberships; /* no. memberships this socket */ + struct in_multi *imo_membership[IP_MAX_MEMBERSHIPS]; +}; + +struct ipasfrag { +#if B_HOST_IS_BENDIAN + uint8 ip_v:4; + uint8 ip_hl:4; +#else + uint8 ip_hl:4; + uint8 ip_v:4; +#endif + uint8 ipf_mff; + int16 ip_len; + uint16 ip_id; + int16 ip_off; + uint8 ip_ttl; + uint8 ip_p; + struct ipasfrag *ipf_next; + struct ipasfrag *ipf_prev; +}; + +struct ipq { + struct ipq *next, *prev; + uint8 ipq_ttl; + uint8 ipq_p; + uint16 ipq_id; + struct ipasfrag *ipq_next, *ipq_prev; + struct in_addr ipq_src, ipq_dst; +}; + +struct ipstat { + int32 ips_total; /* total packets received */ + int32 ips_badsum; /* checksum bad */ + int32 ips_tooshort; /* packet too short */ + int32 ips_toosmall; /* not enough data */ + int32 ips_badhlen; /* ip header length < data size */ + int32 ips_badlen; /* ip length < ip header length */ + int32 ips_fragments; /* fragments received */ + int32 ips_fragdropped; /* frags dropped (dups, out of space) */ + int32 ips_fragtimeout; /* fragments timed out */ + int32 ips_forward; /* packets forwarded */ + int32 ips_cantforward; /* packets rcvd for unreachable dest */ + int32 ips_redirectsent; /* packets forwarded on same net */ + int32 ips_noproto; /* unknown or unsupported protocol */ + int32 ips_delivered; /* datagrams delivered to upper level*/ + int32 ips_localout; /* total ip packets generated here */ + int32 ips_odropped; /* lost packets due to nobufs, etc. */ + int32 ips_reassembled; /* total packets reassembled ok */ + int32 ips_fragmented; /* datagrams sucessfully fragmented */ + int32 ips_ofragments; /* output fragments created */ + int32 ips_cantfrag; /* don't fragment flag was set, etc. */ + int32 ips_badoptions; /* error in option processing */ + int32 ips_noroute; /* packets discarded due to no route */ + int32 ips_badvers; /* ip version != 4 */ + int32 ips_rawout; /* total raw ip packets generated */ + int32 ips_badfrags; /* malformed fragments (bad length) */ + int32 ips_rcvmemdrop; /* frags dropped for lack of memory */ + int32 ips_toolong; /* ip length > max ip packet size */ + int32 ips_nogif; /* no match gif found */ + int32 ips_badaddr; /* invalid address on header */ + int32 ips_inhwcsum; /* hardware checksummed on input */ + int32 ips_outhwcsum; /* hardware checksummed on output */ +}; + +#ifdef _NETWORK_STACK + +#define IP_FORWARDING 0x1 /* most of ip header exists */ +#define IP_RAWOUTPUT 0x2 /* raw ip header exists */ +#define IP_ROUTETOIF SO_DONTROUTE /* bypass routing tables */ +#define IP_ALLOWBROADCAST SO_BROADCAST /* can send broadcast packets */ +#define IP_MTUDISC 0x0400 /* pmtu discovery, set DF */ + +struct ipstat ipstat; + +void ip_stripoptions (struct mbuf *, struct mbuf *); + +#endif /* _NETWORK_STACK */ + +#endif /* NETINET_IP_VAR_H */ diff --git a/headers/posix/netinet/tcp.h b/headers/posix/netinet/tcp.h new file mode 100644 index 0000000000..a34cf05037 --- /dev/null +++ b/headers/posix/netinet/tcp.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 1982, 1986, 1993 + *The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef NETINET_TCP_H +#define NETINET_TCP_H + +typedef uint32 tcp_seq; + +struct tcphdr { + uint16 th_sport; /* src port */ + uint16 th_dport; /* dest. port */ + tcp_seq th_seq; /* seq number */ + tcp_seq th_ack; /* ack number */ + +#if B_HOST_IS_BENDIAN + uint8 th_off:4, + th_x2:4; +#else + uint8 th_x2:4, /* unused */ + th_off:4; /* data offset */ +#endif + uint8 th_flags; /* ACK, FIN, PUSH, RST, SYN, URG */ + uint16 th_win; /* advertised window */ + uint16 th_sum; /* checksum */ + uint16 th_urp; /* urgent offset */ +} _PACKED; + +#define TH_FIN 0x01 +#define TH_SYN 0x02 +#define TH_RST 0x04 +#define TH_PUSH 0x08 +#define TH_ACK 0x10 +#define TH_URG 0x20 + +#define TCPOPT_EOL 0 +#define TCPOPT_NOP 1 +#define TCPOPT_MAXSEG 2 +#define TCPOPT_WINDOW 3 +#define TCPOPT_SACK_PERMITTED 4 /* Experimental */ +#define TCPOPT_SACK 5 /* Experimental */ +#define TCPOPT_TIMESTAMP 8 +#define TCPOPT_SIGNATURE 19 + +#define MAX_TCPOPTLEN 40 /* Absolute maximum TCP options len */ + +#define TCPOLEN_MAXSEG 4 +#define TCPOLEN_WINDOW 3 +#define TCPOLEN_SACK 8 /* 2*sizeof(tcp_seq) */ +#define TCPOLEN_SACK_PERMITTED 2 +#define TCPOLEN_TIMESTAMP 10 +#define TCPOLEN_TSTAMP_APPA (TCPOLEN_TIMESTAMP+2) /* appendix A */ +#define TCPOLEN_SIGNATURE 18 + +#define TCPOPT_TSTAMP_HDR \ + (TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_TIMESTAMP<<8|TCPOLEN_TIMESTAMP) + +#define TCP_MSS 512 +#define TCP_MAXWIN 65535 +#define TCP_MAX_WINSHIFT 14 + + +#endif /* NETINET_TCP_H */ diff --git a/headers/posix/netinet/tcp_debug.h b/headers/posix/netinet/tcp_debug.h new file mode 100644 index 0000000000..33ca7c6d51 --- /dev/null +++ b/headers/posix/netinet/tcp_debug.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tcp_debug.h 8.1 (Berkeley) 6/10/93 + */ + +#ifndef NETINET_TCP_DEBUG_H_ +#define NETINET_TCP_DEBUG_H_ + +struct tcp_debug { + n_time td_time; + short td_act; + short td_ostate; + caddr_t td_tcb; + struct tcpiphdr td_ti; + short td_req; + struct tcpcb td_cb; +}; + +#define TA_INPUT 0 +#define TA_OUTPUT 1 +#define TA_USER 2 +#define TA_RESPOND 3 +#define TA_DROP 4 + +#ifdef TANAMES +char *tanames[] = + { "input", "output", "user", "respond", "drop" }; +#endif /* TANAMES */ + +#define TCP_NDEBUG 100 +struct tcp_debug tcp_debug[TCP_NDEBUG]; +int tcp_debx; +#endif /* _NETINET_TCP_DEBUG_H_ */ diff --git a/headers/posix/netinet/tcp_fsm.h b/headers/posix/netinet/tcp_fsm.h new file mode 100644 index 0000000000..a8150f8034 --- /dev/null +++ b/headers/posix/netinet/tcp_fsm.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tcp_fsm.h 8.1 (Berkeley) 6/10/93 + */ + +#ifndef _NETINET_TCP_FSM_H_ +#define _NETINET_TCP_FSM_H_ + +/* + * TCP FSM state definitions. + * Per RFC793, September, 1981. + */ + +#define TCP_NSTATES 11 + +#define TCPS_CLOSED 0 /* closed */ +#define TCPS_LISTEN 1 /* listening for connection */ +#define TCPS_SYN_SENT 2 /* active, have sent syn */ +#define TCPS_SYN_RECEIVED 3 /* have sent and received syn */ +/* states < TCPS_ESTABLISHED are those where connections not established */ +#define TCPS_ESTABLISHED 4 /* established */ +#define TCPS_CLOSE_WAIT 5 /* rcvd fin, waiting for close */ +/* states > TCPS_CLOSE_WAIT are those where user has closed */ +#define TCPS_FIN_WAIT_1 6 /* have closed, sent fin */ +#define TCPS_CLOSING 7 /* closed xchd FIN; await ACK */ +#define TCPS_LAST_ACK 8 /* had fin and close; await FIN ACK */ +/* states > TCPS_CLOSE_WAIT && < TCPS_FIN_WAIT_2 await ACK of FIN */ +#define TCPS_FIN_WAIT_2 9 /* have closed, fin is acked */ +#define TCPS_TIME_WAIT 10 /* in 2*msl quiet wait after close */ + +#define TCPS_HAVERCVDSYN(s) ((s) >= TCPS_SYN_RECEIVED) +#define TCPS_HAVEESTABLISHED(s) ((s) >= TCPS_ESTABLISHED) +#define TCPS_HAVERCVDFIN(s) ((s) >= TCPS_TIME_WAIT) + +#ifdef TCPOUTFLAGS +/* + * Flags used when sending segments in tcp_output. + * Basic flags (TH_RST,TH_ACK,TH_SYN,TH_FIN) are totally + * determined by state, with the proviso that TH_FIN is sent only + * if all data queued for output is included in the segment. + */ +u_char tcp_outflags[TCP_NSTATES] = { + TH_RST|TH_ACK, 0, TH_SYN, TH_SYN|TH_ACK, + TH_ACK, TH_ACK, + TH_FIN|TH_ACK, TH_ACK, TH_FIN|TH_ACK, TH_ACK, TH_ACK, +}; +#endif /* TCPOUTFLAGS */ + +#ifdef TCPSTATES +char *tcpstates[] = { + "CLOSED", "LISTEN", "SYN_SENT", "SYN_RCVD", + "ESTABLISHED", "CLOSE_WAIT", "FIN_WAIT_1", "CLOSING", + "LAST_ACK", "FIN_WAIT_2", "TIME_WAIT", +}; +#endif /* TCPSTATES */ +#endif /* _NETINET_TCP_FSM_H_ */ diff --git a/headers/posix/netinet/tcp_seq.h b/headers/posix/netinet/tcp_seq.h new file mode 100644 index 0000000000..e062c3c4bd --- /dev/null +++ b/headers/posix/netinet/tcp_seq.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tcp_seq.h 8.1 (Berkeley) 6/10/93 + */ + +#ifndef _NETINET_TCP_SEQ_H_ +#define _NETINET_TCP_SEQ_H_ + +/* + * TCP sequence numbers are 32 bit integers operated + * on with modular arithmetic. These macros can be + * used to compare such integers. + */ +#define SEQ_LT(a,b) ((int)((a)-(b)) < 0) +#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) +#define SEQ_GT(a,b) ((int)((a)-(b)) > 0) +#define SEQ_GEQ(a,b) ((int)((a)-(b)) >= 0) + +/* + * Macros to initialize tcp sequence numbers for + * send and receive from initial send and receive + * sequence numbers. + */ +#define tcp_rcvseqinit(tp) \ + (tp)->rcv_adv = (tp)->rcv_nxt = (tp)->irs + 1 + +#define tcp_sendseqinit(tp) \ + (tp)->snd_una = (tp)->snd_nxt = (tp)->snd_max = (tp)->snd_up = \ + (tp)->iss + +#define TCP_ISSINCR (125*1024) /* increment for tcp_iss each second */ + +#ifdef _NETWORK_STACK +tcp_seq tcp_iss; /* tcp initial send seq # */ +#endif /* _NETWORK_STACK */ + +#endif /* _NETINET_TCP_SEQ_H_ */ diff --git a/headers/posix/netinet/tcp_timer.h b/headers/posix/netinet/tcp_timer.h new file mode 100644 index 0000000000..769a527afd --- /dev/null +++ b/headers/posix/netinet/tcp_timer.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 1982, 1986, 1993 + *The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef NETINET_TCP_TIMERS_H +#define NETINET_TCP_TIMERS_H + +/* + * Definitions of the TCP timers. These timers are counted + * down PR_SLOWHZ times a second. + */ +#define TCPT_NTIMERS 4 + +#define TCPT_REXMT 0 /* retransmission timer */ +#define TCPT_PERSIST 1 /* presist timer */ +#define TCPT_KEEP 2 /* keeplaive timer or conn est timer */ +#define TCPT_2MSL 3 /* 2MSL timer or FIN_WAIT_2 timer */ + +/* + * The TCPT_REXMT timer is used to force retransmissions. + * The TCP has the TCPT_REXMT timer set whenever segments + * have been sent for which ACKs are expected but not yet + * received. If an ACK is received which advances tp->snd_una, + * then the retransmit timer is cleared (if there are no more + * outstanding segments) or reset to the base value (if there + * are more ACKs expected). Whenever the retransmit timer goes off, + * we retransmit one unacknowledged segment, and do a backoff + * on the retransmit timer. + * + * The TCPT_PERSIST timer is used to keep window size information + * flowing even if the window goes shut. If all previous transmissions + * have been acknowledged (so that there are no retransmissions in progress), + * and the window is too small to bother sending anything, then we start + * the TCPT_PERSIST timer. When it expires, if the window is nonzero, + * we go to transmit state. Otherwise, at intervals send a single byte + * into the peer's window to force him to update our window information. + * We do this at most as often as TCPT_PERSMIN time intervals, + * but no more frequently than the current estimate of round-trip + * packet time. The TCPT_PERSIST timer is cleared whenever we receive + * a window update from the peer. + * + * The TCPT_KEEP timer is used to keep connections alive. If an + * connection is idle (no segments received) for TCPTV_KEEP_INIT amount of time, + * but not yet established, then we drop the connection. Once the connection + * is established, if the connection is idle for TCPTV_KEEP_IDLE time + * (and keepalives have been enabled on the socket), we begin to probe + * the connection. We force the peer to send us a segment by sending: + * + * This segment is (deliberately) outside the window, and should elicit + * an ack segment in response from the peer. If, despite the TCPT_KEEP + * initiated segments we cannot elicit a response from a peer in TCPT_MAXIDLE + * amount of time probing, then we drop the connection. + */ + +/* + * Time constants. + */ +#define TCPTV_MSL ( 30*PR_SLOWHZ ) /* max seg lifetime (hah!) */ +#define TCPTV_SRTTBASE 0 /* base roundtrip time; + * if 0, no idea yet */ +#define TCPTV_SRTTDFLT ( 3*PR_SLOWHZ ) /* assumed RTT if no info */ + +#define TCPTV_PERSMIN ( 5*PR_SLOWHZ ) /* retransmit persistance */ +#define TCPTV_PERSMAX ( 60*PR_SLOWHZ ) /* maximum persist interval */ + +#define TCPTV_KEEP_INIT ( 75*PR_SLOWHZ ) /* initial connect keep alive */ +#define TCPTV_KEEP_IDLE (120*60*PR_SLOWHZ) /* dflt time before probing */ +#define TCPTV_KEEPINTVL ( 75*PR_SLOWHZ ) /* default probe interval */ +#define TCPTV_KEEPCNT 8 /* max probes before drop */ + +#define TCPTV_MIN ( 1*PR_SLOWHZ ) /* minimum allowable value */ +#define TCPTV_REXMTMAX ( 64*PR_SLOWHZ ) /* max allowable REXMT value */ + +#define TCP_LINGERTIME 120 /* at most 2 minutes... */ +#define TCP_MAXRXTSHIFT 12 /* maximum retransmits */ + +#ifdef TCPTIMERS +char *tcptimers[] = + { "REXMT", "PERSIST", "KEEP", "2MSL" }; +#endif /* TCPTIMERS */ + +/* + * Force a time value to be in a certain range. + */ +#define TCPT_RANGESET(tv, value, tvmin, tvmax) { \ + (tv) = (value); \ + if ((tv) < (tvmin)) \ + (tv) = (tvmin); \ + else if ((tv) > (tvmax)) \ + (tv) = (tvmax); \ +} + +#ifdef _NETWORK_STACK +extern int tcptv_keep_init; +extern int tcp_keepidle; /* time before keepalive probes begin */ +extern int tcp_keepintvl; /* time between keepalive probes */ +extern int tcp_maxidle; /* time to drop after starting probes */ +extern int tcp_ttl; /* time to live for TCP segs */ +extern int tcp_backoff[]; + + +#endif /* _NETWORK_STACK */ + +#endif /* NETINET_TCP_TIMERS_H */ diff --git a/headers/posix/netinet/tcp_var.h b/headers/posix/netinet/tcp_var.h new file mode 100644 index 0000000000..96f369d15d --- /dev/null +++ b/headers/posix/netinet/tcp_var.h @@ -0,0 +1,280 @@ +/* + * Copyright (c) 1982, 1986, 1993 + *The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef NETINET_TCP_VAR_H +#define NETINET_TCP_VAR_H + +/* + * Tcp control block, one per tcp connection + */ +struct tcpcb { + struct tcpiphdr *seg_next; + struct tcpiphdr *seg_prev; + int16 t_state; /* state of this connection */ + int16 t_timer[TCPT_NTIMERS]; /* tcp timers */ + int16 t_rxtshift; /* log(2) of rexmt exp. backoff */ + int16 t_rxtcur; /* current retransmit value */ + int16 t_dupacks; /* consecutive dup acks recd */ + uint16 t_maxseg; /* maximum segment size */ + int8 t_force; /* 1 if forcing out a byte */ + uint16 t_flags; + + struct tcpiphdr *t_template; /* skeletal packet for transmit */ + struct inpcb *t_inpcb; /* back pointer to internet pcb */ +/* + * The following fields are used as in the protocol specification. + * See RFC783, Dec. 1981, page 21. + */ +/* send sequence variables */ + tcp_seq snd_una; /* send unacknowledged */ + tcp_seq snd_nxt; /* send next */ + tcp_seq snd_up; /* send urgent pointer */ + tcp_seq snd_wl1; /* window update seg seq number */ + tcp_seq snd_wl2; /* window update seg ack number */ + tcp_seq iss; /* initial send sequence number */ + unsigned long snd_wnd; /* send window */ + +/* receive sequence variables */ + unsigned long rcv_wnd; /* receive window */ + tcp_seq rcv_nxt; /* receive next */ + tcp_seq rcv_up; /* receive urgent pointer */ + tcp_seq irs; /* initial receive sequence number */ + +/* + * Additional variables for this implementation. + */ +/* receive variables */ + tcp_seq rcv_adv; /* advertised window */ +/* retransmit variables */ + tcp_seq snd_max; /* highest sequence number sent; + * used to recognize retransmits + */ +/* congestion control (for slow start, source quench, retransmit after loss) */ + unsigned long snd_cwnd; /* congestion-controlled window */ + unsigned long snd_ssthresh; /* snd_cwnd size threshhold for + * for slow start exponential to + * linear switch + */ + uint16 t_maxopd; /* mss plus options */ + uint16 t_peermss; /* peer's maximum segment size */ + +/* + * transmit timing stuff. See below for scale of srtt and rttvar. + * "Variance" is actually smoothed difference. + */ + int16 t_idle; /* inactivity time */ + int16 t_rtt; /* round trip time */ + tcp_seq t_rtseq; /* sequence number being timed */ + uint16 t_srtt; /* smoothed round-trip time */ + uint16 t_rttvar; /* variance in round-trip time */ + uint16 t_rttmin; /* minimum rtt allowed */ + uint32 max_sndwnd; /* largest window peer has offered */ + +/* out-of-band data */ + int8 t_oobflags; /* have some */ + int8 t_iobc; /* input character */ + int16 t_softerror; /* possible error, not yet reported... */ +/* RFC 1323 variables */ + uint8 snd_scale; /* window scaling for send window */ + uint8 rcv_scale; /* window scaling for recv window */ + uint8 request_r_scale; /* pending window scaling */ + uint8 requested_s_scale; + uint32 ts_recent; /* timestamp echo data */ + uint32 ts_recent_age; /* when last updated */ + tcp_seq last_ack_sent; +}; + +#define intotcpcb(ip) ((struct tcpcb*)(ip)->inp_ppcb) +#define sototcpcb(so) (intotcpcb(sotoinpcb(so))) + +#define TF_ACKNOW 0x0001 /* send ACK immeadiately */ +#define TF_DELACK 0x0002 /* send ACK, but try to delay it */ +#define TF_NODELAY 0x0004 /* don't delay packets to coalesce */ +#define TF_NOOPT 0x0008 /* don't use tcp options */ +#define TF_SENTFIN 0x0010 /* have sent FIN */ +#define TF_REQ_SCALE 0x0020 /* have/will request window scaling */ +#define TF_RCVD_SCALE 0x0040 /* other side has requested scaling */ +#define TF_REQ_TSTMP 0x0080 /* have/will request timestamps */ +#define TF_RCVD_TSTMP 0x0100 /* a timestamp was received in SYN */ +#define TF_SACK_PERMIT 0x0200 /* other side said I could SACK */ +#define TF_SIGNATURE 0x0400 /* require TCP MD5 signature */ + +#define TCPOOB_HAVEDATA 0x01 /* we have TCP OOB data */ +#define TCPOOB_HADDATA 0x02 /* we've had some TCP OOB data */ + +/* + * The smoothed round-trip time and estimated variance + * are stored as fixed point numbers scaled by the values below. + * For convenience, these scales are also used in smoothing the average + * (smoothed = (1/scale)sample + ((scale-1)/scale)smoothed). + * With these scales, srtt has 3 bits to the right of the binary point, + * and thus an "ALPHA" of 0.875. rttvar has 2 bits to the right of the + * binary point, and is smoothed with an ALPHA of 0.75. + */ +#define TCP_RTT_SCALE 8 /* multiplier for srtt; 3 bits frac. */ +#define TCP_RTT_SHIFT 3 /* shift for srtt; 3 bits frac. */ +#define TCP_RTTVAR_SCALE 4 /* multiplier for rttvar; 2 bits */ +#define TCP_RTTVAR_SHIFT 2 /* multiplier for rttvar; 2 bits */ + +#define TCP_REXMTVAL(tp) \ + ((((tp)->t_srtt >> TCP_RTT_SHIFT) + (tp)->t_rttvar) >> 2) +/* + * TCP statistics. + * Many of these should be kept per connection, + * but that's inconvenient at the moment. + */ +struct tcpstat { + uint32 tcps_connattempt; /* connections initiated */ + uint32 tcps_accepts; /* connections accepted */ + uint32 tcps_connects; /* connections established */ + uint32 tcps_drops; /* connections dropped */ + uint32 tcps_conndrops; /* embryonic connections dropped */ + uint32 tcps_closed; /* conn. closed (includes drops) */ + uint32 tcps_segstimed; /* segs where we tried to get rtt */ + uint32 tcps_rttupdated; /* times we succeeded */ + uint32 tcps_delack; /* delayed acks sent */ + uint32 tcps_timeoutdrop; /* conn. dropped in rxmt timeout */ + uint32 tcps_rexmttimeo; /* retransmit timeouts */ + uint32 tcps_persisttimeo; /* persist timeouts */ + uint32 tcps_persistdrop; /* connections dropped in persist */ + uint32 tcps_keeptimeo; /* keepalive timeouts */ + uint32 tcps_keepprobe; /* keepalive probes sent */ + uint32 tcps_keepdrops; /* connections dropped in keepalive */ + + uint32 tcps_sndtotal; /* total packets sent */ + uint32 tcps_sndpack; /* data packets sent */ + uint64 tcps_sndbyte; /* data bytes sent */ + uint32 tcps_sndrexmitpack; /* data packets retransmitted */ + uint64 tcps_sndrexmitbyte; /* data bytes retransmitted */ + uint64 tcps_sndrexmitfast; /* Fast retransmits */ + uint32 tcps_sndacks; /* ack-only packets sent */ + uint32 tcps_sndprobe; /* window probes sent */ + uint32 tcps_sndurg; /* packets sent with URG only */ + uint32 tcps_sndwinup; /* window update-only packets sent */ + uint32 tcps_sndctrl; /* control (SYN|FIN|RST) packets sent */ + + uint32 tcps_rcvtotal; /* total packets received */ + uint32 tcps_rcvpack; /* packets received in sequence */ + uint64 tcps_rcvbyte; /* bytes received in sequence */ + uint32 tcps_rcvbadsum; /* packets received with ccksum errs */ + uint32 tcps_rcvbadoff; /* packets received with bad offset */ + uint32 tcps_rcvmemdrop; /* packets dropped for lack of memory */ + uint32 tcps_rcvnosec; /* packets dropped for lack of ipsec */ + uint32 tcps_rcvshort; /* packets received too short */ + uint32 tcps_rcvduppack; /* duplicate-only packets received */ + uint64 tcps_rcvdupbyte; /* duplicate-only bytes received */ + uint32 tcps_rcvpartduppack; /* packets with some duplicate data */ + uint64 tcps_rcvpartdupbyte; /* dup. bytes in part-dup. packets */ + uint32 tcps_rcvoopack; /* out-of-order packets received */ + uint64 tcps_rcvoobyte; /* out-of-order bytes received */ + uint32 tcps_rcvpackafterwin; /* packets with data after window */ + uint64 tcps_rcvbyteafterwin; /* bytes rcvd after window */ + uint32 tcps_rcvafterclose; /* packets rcvd after "close" */ + uint32 tcps_rcvwinprobe; /* rcvd window probe packets */ + uint32 tcps_rcvdupack; /* rcvd duplicate acks */ + uint32 tcps_rcvacktoomuch; /* rcvd acks for unsent data */ + uint32 tcps_rcvackpack; /* rcvd ack packets */ + uint64 tcps_rcvackbyte; /* bytes acked by rcvd acks */ + uint32 tcps_rcvwinupd; /* rcvd window update packets */ + uint32 tcps_pawsdrop; /* segments dropped due to PAWS */ + uint32 tcps_predack; /* times hdr predict ok for acks */ + uint32 tcps_preddat; /* times hdr predict ok for data pkts */ + + uint32 tcps_pcbhashmiss; /* input packets missing pcb hash */ + uint32 tcps_noport; /* no socket on port */ + uint32 tcps_badsyn; /* SYN packet with src==dst rcv'ed */ + + uint32 tcps_rcvbadsig; /* rcvd bad/missing TCP signatures */ + uint64 tcps_rcvgoodsig; /* rcvd good TCP signatures */ + uint32 tcps_inhwcsum; /* input hardware-checksummed packets */ + uint32 tcps_outhwcsum; /* output hardware-checksummed packets */ +}; + +/* + * Names for TCP sysctl objects. + */ + +#define TCPCTL_RFC1323 1 /* enable/disable RFC1323 timestamps/scaling */ +#define TCPCTL_KEEPINITTIME 2 /* TCPT_KEEP value */ +#define TCPCTL_KEEPIDLE 3 /* allow tcp_keepidle to be changed */ +#define TCPCTL_KEEPINTVL 4 /* allow tcp_keepintvl to be changed */ +#define TCPCTL_SLOWHZ 5 /* return kernel idea of PR_SLOWHZ */ +#define TCPCTL_BADDYNAMIC 6 /* return bad dynamic port bitmap */ +#define TCPCTL_RECVSPACE 7 /* receive buffer space */ +#define TCPCTL_SENDSPACE 8 /* send buffer space */ +#define TCPCTL_IDENT 9 /* get connection owner */ +#define TCPCTL_SACK 10 /* selective acknowledgement, rfc 2018 */ +#define TCPCTL_MSSDFLT 11 /* Default maximum segment size */ +#define TCPCTL_RSTPPSLIMIT 12 /* RST pps limit */ +#define TCPCTL_MAXID 13 + +#ifdef _NETWORK_STACK +struct inpcb tcb; +struct tcpstat tcpstat; +int tcp_mssdflt; +int tcp_do_rfc1323; +unsigned long tcp_now; + +void tcp_input(struct mbuf *, int); +int tcp_output(struct tcpcb*); +int tcp_mss(struct tcpcb *, uint); +void tcp_mss_update(struct tcpcb *); +void tcp_quench(struct inpcb *, int); +int tcp_userreq(struct socket *, int, struct mbuf *, struct mbuf *, + struct mbuf *); +struct tcpcb * tcp_timers(struct tcpcb *, int); +struct tcpcb *tcp_close(struct tcpcb *); +void tcp_setpersist(struct tcpcb *); +struct tcpcb *tcp_drop(struct tcpcb *, int); +void tcp_respond(struct tcpcb *, struct tcpiphdr *, struct mbuf *, + tcp_seq, tcp_seq, int); +void tcp_xmit_timer(struct tcpcb *, int16); +void tcp_dooptions(struct tcpcb *, u_char *, int, struct tcpiphdr *, + int *, uint32 *, uint32 *); +struct tcpiphdr *tcp_template(struct tcpcb *); +void tcp_pulloutofband(struct socket *, struct tcpiphdr *, struct mbuf *); + +void tcp_canceltimers(struct tcpcb *); +void tcp_trace(int16, int16, struct tcpcb *, void *, int, int); + +void tcp_slowtimer(void *data); +void tcp_fasttimer(void *data); + + + +#endif + +#endif /* NETINET_TCP_VAR_H */ diff --git a/headers/posix/netinet/tcpip.h b/headers/posix/netinet/tcpip.h new file mode 100644 index 0000000000..231ffdd853 --- /dev/null +++ b/headers/posix/netinet/tcpip.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 1982, 1986, 1993 + *The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef NETINET_TCPIP_H +#define NETINET_TCPIP_H + +/* The TCP + IPv4 header (NB no options) */ +struct tcpiphdr { + struct ipovly ti_i; + struct tcphdr ti_t; +}; + +#define ti_next ti_i.ih_next +#define ti_prev ti_i.ih_prev +#define ti_x1 ti_i.ih_x1 +#define ti_pr ti_i.ih_pr +#define ti_len ti_i.ih_len +#define ti_src ti_i.ih_src +#define ti_dst ti_i.ih_dst +#define ti_sport ti_t.th_sport +#define ti_dport ti_t.th_dport +#define ti_seq ti_t.th_seq +#define ti_ack ti_t.th_ack +#define ti_x2 ti_t.th_x2 +#define ti_off ti_t.th_off +#define ti_flags ti_t.th_flags +#define ti_win ti_t.th_win +#define ti_sum ti_t.th_sum +#define ti_urp ti_t.th_urp + +#define REASS_MBUF(ti) (*(struct mbuf **)&((ti)->ti_t)) + +#endif /* NETINET_TCPIP_H */ diff --git a/headers/posix/netinet/udp.h b/headers/posix/netinet/udp.h new file mode 100644 index 0000000000..39fb0168c5 --- /dev/null +++ b/headers/posix/netinet/udp.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 1982, 1986, 1993 + *The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *@(#)udp.h8.1 (Berkeley) 6/10/93 + */ + +#ifndef NETINET_UDP_H +#define NETINET_UDP_H + +struct udphdr { + uint16 uh_sport; + uint16 uh_dport; + uint16 uh_ulen; + uint16 uh_sum; +}; + +#endif /* NETINET_UDP_H */ diff --git a/headers/posix/netinet/udp_var.h b/headers/posix/netinet/udp_var.h new file mode 100644 index 0000000000..a058bd04fc --- /dev/null +++ b/headers/posix/netinet/udp_var.h @@ -0,0 +1,51 @@ +/* udp_var.h */ + +#ifndef UDP_VAR_H +#define UDP_VAR_H + +#include "netinet/ip_var.h" + +struct udpiphdr { + struct ipovly ui_i; + struct udphdr ui_u; +}; +#define ui_next ui_i.ih_next +#define ui_prev ui_i.ih_prev +#define ui_x1 ui_i.ih_x1 /* NB _x1 (one) */ +#define ui_pr ui_i.ih_pr +#define ui_len ui_i.ih_len +#define ui_src ui_i.ih_src +#define ui_dst ui_i.ih_dst +#define ui_sport ui_u.uh_sport +#define ui_dport ui_u.uh_dport +#define ui_ulen ui_u.uh_ulen +#define ui_sum ui_u.uh_sum + +struct udpstat { + /* input statistics: */ + uint32 udps_ipackets; /* total input packets */ + uint32 udps_hdrops; /* packet shorter than header */ + uint32 udps_badsum; /* checksum error */ + uint32 udps_nosum; /* no checksum */ + uint32 udps_badlen; /* data length larger than packet */ + uint32 udps_noport; /* no socket on port */ + uint32 udps_noportbcast; /* of above, arrived as broadcast */ + uint32 udps_nosec; /* dropped for lack of ipsec */ + uint32 udps_fullsock; /* not delivered, input socket full */ + uint32 udps_pcbhashmiss; /* input packets missing pcb hash */ + uint32 udps_inhwcsum; /* input hardware-csummed packets */ + /* output statistics: */ + uint32 udps_opackets; /* total output packets */ + uint32 udps_outhwcsum; /* output hardware-csummed packets */ +}; + +/* + * Names for UDP sysctl objects + */ +#define UDPCTL_CHECKSUM 1 /* checksum UDP packets */ +#define UDPCTL_BADDYNAMIC 2 /* return bad dynamic port bitmap */ +#define UDPCTL_RECVSPACE 3 /* receive buffer space */ +#define UDPCTL_SENDSPACE 4 /* send buffer space */ +#define UDPCTL_MAXID 5 + +#endif diff --git a/headers/posix/nhash.h b/headers/posix/nhash.h new file mode 100644 index 0000000000..2e0fa4bbb7 --- /dev/null +++ b/headers/posix/nhash.h @@ -0,0 +1,40 @@ +/* nhash.h + */ + +#ifndef OBOS_NHASH_H +#define OBOS_NHASH_H + +#include "pools.h" + +typedef struct net_hash_entry net_hash_entry; +typedef struct net_hash net_hash; +typedef struct net_hash_index net_hash_index; + +struct net_hash_entry { + net_hash_entry *next; + int hash; + const void *key; + ssize_t klen; + const void *val; +}; + +struct net_hash_index { + net_hash *nh; + net_hash_entry *this; + net_hash_entry *next; + int index; +}; + +struct net_hash { + net_hash_entry **array; + net_hash_index iterator; + int count; + int max; + struct pool_ctl *pool; +}; + +net_hash *nhash_make(void); +void *nhash_get(net_hash *, const void *key, ssize_t klen); +void nhash_set(net_hash *, const void *, ssize_t , const void *); + +#endif /* OBOS_NHASH_H */ diff --git a/headers/posix/poll.h b/headers/posix/poll.h new file mode 100644 index 0000000000..c5b927aeea --- /dev/null +++ b/headers/posix/poll.h @@ -0,0 +1,24 @@ +/* poll.h + * + * poll is an alternative way to deal with system notification + * of events on sockets + */ + +#ifndef __POLL_H +#define __POLL_H + +#define POLLIN 0x0001 +#define POLLPRI 0x0002 /* not used */ +#define POLLOUT 0x0004 +#define POLLERR 0x0008 + +struct pollfd { + int fd; + int events; /* events to look for */ + int revents; /* events that occured */ +}; + +extern int poll(struct pollfd * p, int nb, int timeout); + +#endif /* __POLL_H */ + diff --git a/headers/posix/pools.h b/headers/posix/pools.h new file mode 100644 index 0000000000..61d3b1d182 --- /dev/null +++ b/headers/posix/pools.h @@ -0,0 +1,55 @@ +/* pools.h + * simple fixed size block allocator + */ + +#ifndef OBOS_POOLS_H +#define OBOS_POOLS_H + + +#include + +#include "lock.h" + + +typedef struct pool_ctl pool_ctl; + +struct pool_mem { + struct pool_mem *next; + area_id aid; + char *base_addr; + size_t mem_size; + char *ptr; + size_t avail; + benaphore lock; +}; + +struct free_blk { + char *next; +}; + +#define POOL_USES_BENAPHORES 0 +#define POOL_DEBUG_NAME_SZ 32 + +struct pool_ctl { + struct pool_mem *list; + char *freelist; + size_t alloc_size; + size_t block_size; +#if POOL_USES_BENAPHORES + benaphore lock; +#else + rw_lock lock; +#endif + int debug; + char name[POOL_DEBUG_NAME_SZ]; +}; + +status_t pool_init(pool_ctl **p, size_t sz); +char *pool_get(pool_ctl *p); +void pool_put(pool_ctl *p, void *ptr); +void pool_destroy(pool_ctl *p); +void pool_debug(struct pool_ctl *p, char *name); + +void pool_debug_walk(pool_ctl *p); + +#endif /* OBOS_POOLS_H */ diff --git a/headers/posix/protocols.h b/headers/posix/protocols.h new file mode 100644 index 0000000000..a2fff62fc7 --- /dev/null +++ b/headers/posix/protocols.h @@ -0,0 +1,48 @@ +/* protocols.h + * The various protocols we're likely to come across as + * they're identified in the type fields of packets... + */ + +#include "netinet/in.h" + +#ifndef OBOS_PROTOCOLS_H +#define OBOS_PROTOCOLS_H + +/* define some protocol numbers unique to ethernet */ +enum { + ETHER_IPV4 = 0x0800, + ETHER_ARP = 0x0806, + ETHER_RARP = 0x8035, + ETHER_ATALK = 0x809b, /* Appletalk */ + ETHER_SNMP = 0x814c, /* SNMP */ + ETHER_IPV6 = 0x86dd, /* IPv6 */ + ETHER_PPPOE_DISC = 0x8863, /* PPPoE Discovery */ + ETHER_PPPOE_SESS = 0x8864 /* PPPoE Session */ +}; + +/* these are used when assigning slots in the protocol table, so they + * should tie in with IP numbers wherever possible, with other + * protocols fitting in. + * These are used in the module definitions. + */ +enum { + NS_IPV4 = IPPROTO_IP, + NS_ICMP = IPPROTO_ICMP, + NS_IGMP = IPPROTO_IGMP, + NS_TCP = IPPROTO_TCP, + NS_UDP = IPPROTO_UDP, + NS_ETHER=200, + NS_IPV6, + NS_ATALK, + NS_ARP, + NS_RARP, + NS_PPPOE, + NS_SERIAL, + NS_LOOP, + NS_SOCKET, + NS_ROUTE +}; + + +#endif /* OBOS_PROTOCOLS_H */ + diff --git a/headers/posix/resolv.h b/headers/posix/resolv.h new file mode 100644 index 0000000000..19f92221c5 --- /dev/null +++ b/headers/posix/resolv.h @@ -0,0 +1,349 @@ +/* $OpenBSD: resolv.h,v 1.7 2001/07/31 22:02:18 jakob Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * ++Copyright++ 1983, 1987, 1989, 1993 + * - + * Copyright (c) 1983, 1987, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * --Copyright-- + */ + +/* + * @(#)resolv.h 8.1 (Berkeley) 6/2/93 + * $From: resolv.h,v 8.17 1996/11/26 10:11:20 vixie Exp $ + */ + +#ifndef _RESOLV_H_ +#define _RESOLV_H_ + +#include +#include +#include +#include "sys/socket.h" +#include + +/* + * Revision information. This is the release date in YYYYMMDD format. + * It can change every day so the right thing to do with it is use it + * in preprocessor commands such as "#if (__RES > 19931104)". Do not + * compare for equality; rather, use it to determine whether your resolver + * is new enough to contain a certain feature. + */ + +#define __RES 19960801 + +/* + * Resolver configuration file. + * Normally not present, but may contain the address of the + * initial name server(s) to query and the domain search list. + */ + +#ifndef _PATH_RESCONF +#define _PATH_RESCONF "/etc/resolv.conf" +#endif + +/* + * Global defines and variables for resolver stub. + */ +#define MAXNS 3 /* max # name servers we'll track */ +#define MAXDFLSRCH 3 /* # default domain levels to try */ +#define MAXDNSRCH 6 /* max # domains in search path */ +#define LOCALDOMAINPARTS 2 /* min levels in name that is "local" */ +#define MAXDNSLUS 4 /* max # of host lookup types */ + +#define RES_TIMEOUT 5 /* min. seconds between retries */ +#define MAXRESOLVSORT 10 /* number of net to sort on */ +#define RES_MAXNDOTS 15 /* should reflect bit field size */ + +struct __res_state { + int retrans; /* retransmition time interval */ + int retry; /* number of times to retransmit */ + u_long options; /* option flags - see below. */ + int nscount; /* number of name servers */ + struct sockaddr_in + nsaddr_list[MAXNS]; /* address of name server */ +#define nsaddr nsaddr_list[0] /* for backward compatibility */ + u_short id; /* current message id */ + char *dnsrch[MAXDNSRCH+1]; /* components of domain to search */ + char defdname[256]; /* default domain (deprecated) */ + u_long pfcode; /* RES_PRF_ flags - see below. */ + unsigned ndots:4; /* threshold for initial abs. query */ + unsigned nsort:4; /* number of elements in sort_list[] */ + char unused[3]; + struct { + struct in_addr addr; + uint32 mask; + } sort_list[MAXRESOLVSORT]; + char lookups[MAXDNSLUS]; + char pad[68]; /* on an i386 this means 512b total */ +}; + +#ifdef INET6 +/* + * replacement of __res_state, separated to keep binary compatibility. + */ +struct __res_state_ext { + struct sockaddr_storage nsaddr_list[MAXNS]; + struct { + int af; /* address family for addr, mask */ + union { + struct in_addr ina; + struct in6_addr in6a; + } addr, mask; + } sort_list[MAXRESOLVSORT]; +}; +#endif + + +/* + * Resolver options (keep these in synch with res_debug.c, please) + */ +#define RES_INIT 0x00000001 /* address initialized */ +#define RES_DEBUG 0x00000002 /* print debug messages */ +#define RES_AAONLY 0x00000004 /* authoritative answers only (!IMPL)*/ +#define RES_USEVC 0x00000008 /* use virtual circuit */ +#define RES_PRIMARY 0x00000010 /* query primary server only (!IMPL) */ +#define RES_IGNTC 0x00000020 /* ignore trucation errors */ +#define RES_RECURSE 0x00000040 /* recursion desired */ +#define RES_DEFNAMES 0x00000080 /* use default domain name */ +#define RES_STAYOPEN 0x00000100 /* Keep TCP socket open */ +#define RES_DNSRCH 0x00000200 /* search up local domain tree */ +#define RES_INSECURE1 0x00000400 /* type 1 security disabled */ +#define RES_INSECURE2 0x00000800 /* type 2 security disabled */ +#define RES_NOALIASES 0x00001000 /* shuts off HOSTALIASES feature */ +#define RES_USE_INET6 0x00002000 /* use/map IPv6 in gethostbyname() */ +/* KAME extensions: use higher bit to avoid conflict with ISC use */ +#define RES_USE_EDNS0 0x40000000 /* use EDNS0 */ +/* DNSSEC extensions: use higher bit to avoid conflict with ISC use */ +#define RES_USE_DNSSEC 0x20000000 /* use DNSSEC using OK bit in OPT */ + +#define RES_DEFAULT (RES_RECURSE | RES_DEFNAMES | RES_DNSRCH) + +/* + * Resolver "pfcode" values. Used by dig. + */ +#define RES_PRF_STATS 0x00000001 +/* 0x00000002 */ +#define RES_PRF_CLASS 0x00000004 +#define RES_PRF_CMD 0x00000008 +#define RES_PRF_QUES 0x00000010 +#define RES_PRF_ANS 0x00000020 +#define RES_PRF_AUTH 0x00000040 +#define RES_PRF_ADD 0x00000080 +#define RES_PRF_HEAD1 0x00000100 +#define RES_PRF_HEAD2 0x00000200 +#define RES_PRF_TTLID 0x00000400 +#define RES_PRF_HEADX 0x00000800 +#define RES_PRF_QUERY 0x00001000 +#define RES_PRF_REPLY 0x00002000 +#define RES_PRF_INIT 0x00004000 +/* 0x00008000 */ + +/* hooks are still experimental as of 4.9.2 */ +typedef enum { res_goahead, res_nextns, res_modified, res_done, res_error } + res_sendhookact; + +typedef res_sendhookact (*res_send_qhook)(struct sockaddr_in * const *ns, + const uchar **query, + int *querylen, + uchar *ans, + int anssiz, + int *resplen); + +typedef res_sendhookact (*res_send_rhook)(const struct sockaddr_in *ns, + const uchar *query, + int querylen, + uchar *ans, + int anssiz, + int *resplen); + +struct res_sym { + int number; /* Identifying number, like T_MX */ + char * name; /* Its symbolic name, like "MX" */ + char * humanname; /* Its fun name, like "mail exchanger" */ +}; + +extern struct __res_state _res; +#ifdef INET6 +extern struct __res_state_ext _res_ext; +#endif +extern const struct res_sym __p_class_syms[]; +extern const struct res_sym __p_type_syms[]; + +/* Private routines shared between libc/net, named, nslookup and others. */ +#define res_hnok __res_hnok +#define res_ownok __res_ownok +#define res_mailok __res_mailok +#define res_dnok __res_dnok +#define sym_ston __sym_ston +#define sym_ntos __sym_ntos +#define sym_ntop __sym_ntop +#define b64_ntop __b64_ntop +#define b64_pton __b64_pton +#define loc_ntoa __loc_ntoa +#define loc_aton __loc_aton +#define dn_skipname __dn_skipname +#define fp_resstat __fp_resstat +#define fp_query __fp_query +#define fp_nquery __fp_nquery +#define hostalias __hostalias +#define putlong __putlong +#define putshort __putshort +#define p_class __p_class +#define p_time __p_time +#define p_type __p_type +#define p_query __p_query +#define p_cdnname __p_cdnname +#define p_cdname __p_cdname +#define p_fqnname __p_fqnname +#define p_fqname __p_fqname +#define p_rr __p_rr +#define p_option __p_option +#define p_secstodate __p_secstodate +#define dn_count_labels __dn_count_labels +#define dn_comp __dn_comp +#define res_randomid __res_randomid +#define res_send __res_send +#define res_isourserver __res_isourserver +#define res_nameinquery __res_nameinquery +#define res_queriesmatch __res_queriesmatch +#define res_close __res_close +#define res_opt __res_opt + +#ifdef BIND_RES_POSIX3 +#define dn_expand __dn_expand +#define res_init __res_init +#define res_query __res_query +#define res_search __res_search +#define res_querydomain __res_querydomain +#define res_mkquery __res_mkquery +#endif + +int res_hnok (const char *); +int res_ownok (const char *); +int res_mailok (const char *); +int res_dnok (const char *); +int sym_ston (const struct res_sym *, char *, int *); +const char * sym_ntos (const struct res_sym *, int, int *); +const char * sym_ntop (const struct res_sym *, int, int *); +int b64_ntop (uchar const *, size_t, char *, size_t); +int b64_pton (char const *, uchar *, size_t); +int loc_aton (const char *, uchar *); +const char * loc_ntoa (const uchar *, char *); +int dn_skipname (const uchar *, const uchar *); +void fp_resstat (struct __res_state *, FILE *); +void fp_query (const uchar *, FILE *); +void fp_nquery (const uchar *, int, FILE *); +const char * hostalias (const char *); +void putlong (uint32, uchar *); +void putshort (uint16, uchar *); +const char * p_class (int); +const char * p_time (uint32); +const char * p_type (int); +void p_query (const uchar *); +const uchar * p_cdnname (const uchar *, const uchar *, int, FILE *); +const uchar * p_cdname (const uchar *, const uchar *, FILE *); +const uchar * p_fqnname (const uchar *cp, const uchar *msg, + int, char *, int); +const uchar * p_fqname (const uchar *, const uchar *, FILE *); +const uchar * p_rr (const uchar *, const uchar *, FILE *); +const char * p_option (u_long option); +char * p_secstodate (u_long); +int dn_count_labels (char *); +int dn_comp (const char *, uchar *, int, + uchar **, uchar **); +int dn_expand (const uchar *, const uchar *, const uchar *, + char *, int); +int res_init (void); +uint res_randomid (void); +int res_query (const char *, int, int, uchar *, int); +int res_search (const char *, int, int, uchar *, int); +int res_querydomain (const char *, const char *, int, int, + uchar *, int); +int res_mkquery (int, const char *, int, int, const uchar *, int, + const uchar *, uchar *, int); +int res_send (const uchar *, int, uchar *, int); +int res_isourserver (const struct sockaddr_in *); +int res_nameinquery (const char *, int, int, + const uchar *, const uchar *); +int res_queriesmatch (const uchar *, const uchar *, + const uchar *, const uchar *); +void res_close (void); + +#endif /* !_RESOLV_H_ */ diff --git a/headers/posix/sys/domain.h b/headers/posix/sys/domain.h new file mode 100644 index 0000000000..6ba774e21c --- /dev/null +++ b/headers/posix/sys/domain.h @@ -0,0 +1,26 @@ +/* domain.h */ + +/* A domain is just a container for like minded protocols! */ + +#ifndef DOMAIN_H +#define DOMAIN_H + +struct domain { + int dom_family; /* AF_INET and so on */ + char *dom_name; + + void (*dom_init)(void); /* initialise */ + + struct protosw *dom_protosw; /* the protocols we have */ + struct domain *dom_next; + + int (*dom_rtattach)(void **, int); + int dom_rtoffset; + int dom_maxrtkey; +}; + +struct domain *domains; +void add_domain(struct domain *dom, int fam); +void remove_domain(int fam); + +#endif /* DOMAIN_H */ diff --git a/headers/posix/sys/mbuf.h b/headers/posix/sys/mbuf.h new file mode 100644 index 0000000000..6a3e15b612 --- /dev/null +++ b/headers/posix/sys/mbuf.h @@ -0,0 +1,318 @@ +/* mbuf.h + * network buffer definitions + * + * Based on BSD's mbuf principal. + */ + +#include "pools.h" + +#ifndef OBOS_MBUF_H +#define OBOS_MBUF_H + +/* MBuf's are all of a single size, MSIZE bytes. If we have more data + * than can be fitted we can add a single "MBuf cluster" which is of + * fixed size MCLBYTES. + * If the data to be written is larger than MCLMINBYTES bytes we won't use + * the storage provided within the MBuf, but rather all data will go + * directly into an added cluster. + */ + +#define MSIZE 256 /* total size of structure */ +#define MCLSHIFT 11 +#define MCLBYTES (1 << MCLSHIFT) + +#define MCLMAXBYTES 2048 /* they can't be bigger than 2k */ +#define MLEN (MSIZE - sizeof(struct m_hdr)) /* data length w/o a pkt_hdr */ +#define MHLEN (MLEN - sizeof(struct pkt_hdr)) /* data length w/pkt_hdr */ +#define CLLEN (MCLBYTES - sizeof(struct cl_hdr)) + +#define MINCLSIZE (MHLEN + 1) + +/* mbuf header structure + * This appears at teh start of every MBuf + */ +struct m_hdr { + struct mbuf *m_next; /* next mbuf in a chain */ + struct mbuf *m_nxtpkt; /* next chain in a packet/queue */ + char * m_data; /* pointer to data */ + uint32 m_len; /* length data in this mbuf NB NOT total length */ + uint16 m_type; /* what sort of data do we have ? */ + uint16 m_flags; /* flags as defined below */ + uint16 m_cksum; /* flags about the checksum on the packet */ +}; + +/* pkt_hdr + * This is ONLY found in the first MBuf in a chain and is valid + * ONLY if we have the M_PKTHDR flag is set + */ +/* XXX - we also need to record things like the interface and also maintain + * a list of the packets associated with this message here. + */ +struct pkt_hdr { + struct ifnet *rcvif; /* interface we came it on */ + int len; /* total length */ + int csum; /* hardware cksum info... */ +}; + +/* m_ext + * External storage, i.e. a cluster + */ +struct m_ext { + char *ext_buf; /* start of the buffer */ +// void *(ext_free)(); /* free routine (if not standard) */ + uint ext_size; /* how big is the buffer */ +}; + +/* struct mbuf + * The actual buffer structure. + * This is defined as unions as the size is slightly variable + * depending on the options set. + */ + +struct mbuf { + struct m_hdr m_hdr; + union { + struct { + struct pkt_hdr MH_pkthdr; + union { + struct m_ext MH_ext; + char MH_databuf[MHLEN]; + } MH_dat; + } MH; + char m_databuf[MLEN]; + } um_dat; +}; + +/* these are simply shortcuts... */ +#define m_next m_hdr.m_next +#define m_len m_hdr.m_len +#define m_data m_hdr.m_data +#define m_type m_hdr.m_type +#define m_flags m_hdr.m_flags +#define m_cksum m_hdr.m_cksum +#define m_nextpkt m_hdr.m_nxtpkt +#define m_ext um_dat.MH.MH_dat.MH_ext +#define m_pktdat um_dat.MH.MH_dat.MH_databuf +#define m_pkthdr um_dat.MH.MH_pkthdr +#define m_dat um_dat.m_databuf + +/* define a little macro that gives us the data pointer for an mbuf */ +#define mtod(m, t) ((t)((m)->m_data)) +#define dtom(x) ((struct mbuf *)((int)(x) & ~(MSIZE-1))) + +/* mbuf flags */ +enum { + M_EXT = 0x0001, /* has extenal storage attached */ + M_PKTHDR = 0x0002, /* contains the packet header */ + M_EOR = 0x0004, /* end of record (not used for tcp/udp) */ + M_CLUSTER = 0x0008, /* external storage is a cluster */ +/* + M_PROTO = 0x0010, * protocol specific * +*/ + M_BCAST = 0x0100, /* rx/tx as a link-level broadcast */ + M_MCAST = 0x0200, /* rx/tx as a link-level multicast */ + M_CONF = 0x0400, /* packet was encrypted?? */ + M_AUTH = 0x0800, /* packet was authenticated */ + M_COMP = 0x1000, /* packet was compressed */ + M_ANYCAST6 = 0x4000 /* it was an IPv6 anycast packet */ +}; +/* the M_COPYFLAGS lists the flags that can be copied when we copy + * an mbuf with the M_PKTHDR flag set */ +#define M_COPYFLAGS (M_PKTHDR | M_EOR | M_BCAST | M_MCAST) + +/* checksum flags */ +enum { + M_IPV4_CSUM_OUT = 0x0001, /* ipv4 checksum required */ + M_TCPV4_CSUM_OUT = 0x0002, /* TCP v4 checksum required */ + M_UDPV4_CSUM_OUT = 0x0004, + + M_IPV4_CSUM_IN_OK = 0x0008, + M_IPV4_CSUM_IN_OUT = 0x0010, + + M_TCP_CSUM_IN_OK = 0x0020, + M_TCP_CSUM_IN_BAD = 0x0040, + + M_UDP_CSUM_IN_OK = 0x0080, + M_UDP_CSUM_IN_BAD = 0x0100 +}; + +/* MBuf types */ +enum { + MT_FREE = 0, /* should be on free list */ + MT_DATA = 1, /* dynamic data allocation */ + MT_HEADER = 2, /* packet header */ + MT_SONAME = 3, + MT_SOOPTS = 4, + MT_FTABLE = 5, /* fragment reassembly header */ + MT_CONTROL = 6, /* extra-data protocol message */ + MT_OOBDATA = 7 /* out-of-band data */ +}; + +/* length to m_copy to copy all */ +#define M_COPYALL 1000000000 + +/* now some macro's to make life easier... */ + +/* need to add the macro's here :) */ + +#define MRESETDATA(m) do { \ + if ((m)->m_flags & M_EXT) \ + (m)->m_data = (m)->m_ext.ext_buf; \ + else if ((m)->m_flags & M_PKTHDR) \ + (m)->m_data = (m)->m_pktdat; \ + else \ + (m)->m_data = (m)->dat; \ + } while (0) + +/* fill in an mbuf */ +#define MGET(n, type) \ + n = (struct mbuf*) pool_get(mbpool); \ + if (n) { \ + (n)->m_type = (type); \ + (n)->m_next = NULL; \ + (n)->m_nextpkt = NULL; \ + (n)->m_data = (n)->m_dat; \ + (n)->m_flags = 0; \ + (n)->m_cksum = 0; \ + } + +#define MGETHDR(n, type) \ + n = (struct mbuf*) pool_get(mbpool); \ + if (n) { \ + (n)->m_type = (type); \ + (n)->m_next = NULL; \ + (n)->m_nextpkt = NULL; \ + (n)->m_data = (n)->m_pktdat; \ + (n)->m_flags = M_PKTHDR; \ + (n)->m_cksum = 0; \ + } + +#define _MEXTREMOVE(m) do { \ + if ((m)->m_flags & M_CLUSTER) { \ + pool_put(clpool, (m)->m_ext.ext_buf); \ + } \ + (m)->m_flags &= ~(M_CLUSTER|M_EXT); \ + (m)->m_ext.ext_size = 0; \ + } while (0) + +#define MFREE(m, n) \ + if ((m)->m_flags & M_EXT) { \ + _MEXTREMOVE(m); \ + } \ + (n) = (m)->m_next; \ + pool_put(mbpool, m); + +/* set the data pointer to place an object of size len at the end + * of the mbuf, aligned to long word (16 bits) + */ +#define M_ALIGN(m, len) \ + { (m)->m_data += (MLEN - (len)) &~ (sizeof(int16) -1);} + +#define MH_ALIGN(m, len) \ + { (m)->m_data += (MHLEN - (len)) &~ (sizeof(int16) -1);} + +#define M_MOVE_HDR(to, from) { \ + (to)->m_pkthdr = (from)->m_pkthdr; \ + (from)->m_flags &= ~M_PKTHDR; \ + } + +#define M_MOVE_PKTHDR(to, from) { \ + (to)->m_flags = (from)->m_flags & M_COPYFLAGS; \ + M_MOVE_HDR((to), (from)); \ + (to)->m_data = (to)->m_pktdat; \ + } + +#define MCLGET(m) do { \ + (m)->m_ext.ext_buf = pool_get(clpool); \ + if ((m)->m_ext.ext_buf != NULL) { \ + (m)->m_data = (m)->m_ext.ext_buf; \ + (m)->m_flags |= M_EXT|M_CLUSTER; \ + (m)->m_ext.ext_size = MCLBYTES; \ + } \ + } while (0) + +#define M_LEADINGSPACE(m) \ + ((m)->m_flags & M_EXT ? (m)->m_data - (m)->m_ext.ext_buf : \ + (m)->m_flags & M_PKTHDR ? (m)->m_data - (m)->m_pktdat : \ + (m)->m_data - (m)->m_dat) + +#define M_PREPEND(m, plen) { \ + if (M_LEADINGSPACE(m) >= (plen)) { \ + (m)->m_data -= (plen); \ + (m)->m_len += (plen); \ + } else \ + (m) = m_prepend((m), (plen)); \ + if ((m) && (m)->m_flags & M_PKTHDR) \ + (m)->m_pkthdr.len += (plen); \ +} + +/* + * Duplicate just m_pkthdr from from to to. + */ +#define M_DUP_HDR(to, from) { \ + (to)->m_pkthdr = (from)->m_pkthdr; \ +} + +/* + * Duplicate mbuf pkthdr from from to to. + * from must have M_PKTHDR set, and to must be empty. + */ +#define M_DUP_PKTHDR(to, from) { \ + (to)->m_flags = (from)->m_flags & M_COPYFLAGS; \ + M_DUP_HDR((to), (from)); \ + (to)->m_data = (to)->m_pktdat; \ +} + +#define M_TRAILINGSPACE(m) \ + ((m)->m_flags & M_EXT ? (m)->m_ext.ext_buf + (m)->m_ext.ext_size - \ + ((m)->m_data + (m)->m_len) : \ + &(m)->m_dat[MLEN] - ((m)->m_data + (m)->m_len)) + +#define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT) + +#define M_DATASTART(m) \ + (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \ + (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat) + +#define M_DATASIZE(m) \ + (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \ + (m)->m_flags & M_PKTHDR ? MHLEN: MLEN) + +/* Functions! */ +void mbinit(void); +struct mbuf *m_get(int type); + +struct mbuf *m_gethdr(int type); +struct mbuf *m_getclr(int type); + +struct mbuf *m_prepend(struct mbuf *m, int len); +struct mbuf *m_devget(char *buf, int totlen, int off0, + struct ifnet *ifp, + void (*copy)(const void *, void *, size_t)); +struct mbuf *m_pullup(struct mbuf *, int len); +void m_copyback(struct mbuf *m0, int off, int len, caddr_t cp); + +struct mbuf *m_free(struct mbuf *mfree); +void m_freem(struct mbuf *m); + +void m_reserve(struct mbuf *mp, int len); +void m_cat(struct mbuf *m, struct mbuf *n); +void m_adj(struct mbuf *mp, int req_len); +void m_copydata(struct mbuf *m, int off, int len, caddr_t cp); +struct mbuf *m_copym(struct mbuf *m, int off0, int len); + +/* debug functions */ +void dump_freelist(void); + +/* Stats structure */ +/* XXX - add me! */ + + +struct pool_ctl *mbpool; +struct pool_ctl *clpool; + +int max_hdr; /* largest link+protocol header */ +int max_linkhdr; /* largest link level header */ +int max_protohdr; /* largest protocol header */ + +#endif /* OBOS_MBUF_H */ diff --git a/headers/posix/sys/net_uio.h b/headers/posix/sys/net_uio.h new file mode 100644 index 0000000000..c5730f4deb --- /dev/null +++ b/headers/posix/sys/net_uio.h @@ -0,0 +1,26 @@ +/* uio.h */ + +#ifndef NET_SYS_UIO_H +#define NET_SYS_UIO_H + +enum uio_rw { UIO_READ, UIO_WRITE }; + +/* Segment flag values. */ +enum uio_seg { + UIO_USERSPACE, /* from user data space */ + UIO_SYSSPACE /* from system space */ +}; + +struct uio { + struct iovec *uio_iov; /* pointer to array of iovecs */ + int uio_iovcnt; /* number of iovecs in array */ + off_t uio_offset; /* offset into file this uio corresponds to */ + size_t uio_resid; /* residual i/o count */ + enum uio_seg uio_segflg; /* see above */ + enum uio_rw uio_rw; /* see above */ +// struct proc *uio_procp; /* process if UIO_USERSPACE */ +}; + +int uiomove(caddr_t cp, int n, struct uio *uio); + +#endif /* NET_SYS_UIO_H */ diff --git a/headers/posix/sys/protosw.h b/headers/posix/sys/protosw.h new file mode 100644 index 0000000000..2b46b55af2 --- /dev/null +++ b/headers/posix/sys/protosw.h @@ -0,0 +1,147 @@ +/* protosw.h */ + +#ifndef PROTOSW_H +#define PROTOSW_H + +#include "sys/socketvar.h" /* for struct socket */ +#include "net/route.h" + +#define PRCO_SETOPT 0 +#define PRCO_GETOPT 1 + +/* every protocol module init's one of these and passes it into + * the add_protocol() function, defined below */ +/* NB The pr_domain pointer will be filled in during the + * add_protocol() call + */ +struct protosw { + char *name; + char *mod_path; + uint16 pr_type; /* SOCK_xxx */ + struct domain *pr_domain; + uint16 pr_protocol; /* protocol number */ + uint16 pr_flags; /* flags, PR_xxx */ + int layer; /* which layer are we? */ + + /* the functions! */ + void (*pr_init)(void); + void (*pr_input)(struct mbuf*, int); + int (*pr_output)(struct mbuf *, struct mbuf *, + struct route *, + int, void *); + + int (*pr_userreq)(struct socket *, int, + struct mbuf *, + struct mbuf *, + struct mbuf *); + int (*pr_sysctl)(int *, uint, void *, size_t *, void *, size_t); + void (*pr_ctlinput)(int, struct sockaddr *, void *); + int (*pr_ctloutput)(int, struct socket*, int, int, struct mbuf **); + + struct protosw *pr_next; /* pointer to next proto structure */ + struct protosw *dom_next; /* next protosw pointed by the domain */ +}; + + +/* + * Values for pr_flags. + * PR_ADDR requires PR_ATOMIC; + * PR_ADDR and PR_CONNREQUIRED are mutually exclusive. + */ +#define PR_ATOMIC 0x01 /* exchange atomic messages only */ +#define PR_ADDR 0x02 /* addresses given with messages */ +#define PR_CONNREQUIRED 0x04 /* connection required by protocol */ +#define PR_WANTRCVD 0x08 /* want PRU_RCVD calls */ +#define PR_RIGHTS 0x10 /* passes capabilities */ +#define PR_ABRTACPTDIS 0x20 /* abort on accept(2) to disconnected + socket */ + +#define PR_SLOWHZ 2 /* 2 timeouts per second... */ +#define PR_FASTHZ 5 /* 5 timeouts per second */ +/* + * Defines for the userreq function req field are below. + * + * (*usrreq)(up, req, m, nam, opt); + * + * up is a (struct socket *) + * req is one of these requests, + * m is a optional mbuf chain containing a message, + * nam is an optional mbuf chain containing an address, + * opt is a pointer to a socketopt structure or nil. + * + * The protocol is responsible for disposal of the mbuf chain m, + * the caller is responsible for any space held by nam and opt. + * A non-zero return from usrreq gives an + * UNIX error number which should be passed to higher level software. + */ +#define PRU_ATTACH 0 /* attach protocol to up */ +#define PRU_DETACH 1 /* detach protocol from up */ +#define PRU_BIND 2 /* bind socket to address */ +#define PRU_LISTEN 3 /* listen for connection */ +#define PRU_CONNECT 4 /* establish connection to peer */ +#define PRU_ACCEPT 5 /* accept connection from peer */ +#define PRU_DISCONNECT 6 /* disconnect from peer */ +#define PRU_SHUTDOWN 7 /* won't send any more data */ +#define PRU_RCVD 8 /* have taken data; more room now */ +#define PRU_SEND 9 /* send this data */ +#define PRU_ABORT 10 /* abort (fast DISCONNECT, DETATCH) */ +#define PRU_CONTROL 11 /* control operations on protocol */ +#define PRU_SENSE 12 /* return status into m */ +#define PRU_RCVOOB 13 /* retrieve out of band data */ +#define PRU_SENDOOB 14 /* send out of band data */ +#define PRU_SOCKADDR 15 /* fetch socket's address */ +#define PRU_PEERADDR 16 /* fetch peer's address */ +#define PRU_CONNECT2 17 /* connect two sockets */ +/* begin for protocols internal use */ +#define PRU_FASTTIMO 18 /* 200ms timeout */ +#define PRU_SLOWTIMO 19 /* 500ms timeout */ +#define PRU_PROTORCV 20 /* receive from below */ +#define PRU_PROTOSEND 21 /* send to below */ +#define PRU_PEEREID 22 /* get local peer eid */ + +#define PRU_NREQ 22 + +/* + * The arguments to the ctlinput routine are + * (*protosw[].pr_ctlinput)(cmd, sa, arg); + * where cmd is one of the commands below, sa is a pointer to a sockaddr, + * and arg is an optional caddr_t argument used within a protocol family. + */ +#define PRC_IFDOWN 0 /* interface transition */ +#define PRC_ROUTEDEAD 1 /* select new route if possible ??? */ +#define PRC_MTUINC 2 /* increase in mtu to host */ +#define PRC_QUENCH2 3 /* DEC congestion bit says slow down */ +#define PRC_QUENCH 4 /* some one said to slow down */ +#define PRC_MSGSIZE 5 /* message size forced drop */ +#define PRC_HOSTDEAD 6 /* host appears to be down */ +#define PRC_HOSTUNREACH 7 /* deprecated (use PRC_UNREACH_HOST) */ +#define PRC_UNREACH_NET 8 /* no route to network */ +#define PRC_UNREACH_HOST 9 /* no route to host */ +#define PRC_UNREACH_PROTOCOL 10 /* dst says bad protocol */ +#define PRC_UNREACH_PORT 11 /* bad port # */ +/* was PRC_UNREACH_NEEDFRAG 12 (use PRC_MSGSIZE) */ +#define PRC_UNREACH_SRCFAIL 13 /* source route failed */ +#define PRC_REDIRECT_NET 14 /* net routing redirect */ +#define PRC_REDIRECT_HOST 15 /* host routing redirect */ +#define PRC_REDIRECT_TOSNET 16 /* redirect for type of service & net */ +#define PRC_REDIRECT_TOSHOST 17 /* redirect for tos & host */ +#define PRC_TIMXCEED_INTRANS 18 /* packet lifetime expired in transit */ +#define PRC_TIMXCEED_REASS 19 /* lifetime expired on reass q */ +#define PRC_PARAMPROB 20 /* header incorrect */ + +#define PRC_NCMDS 21 + +#define PRC_IS_REDIRECT(cmd) \ + ((cmd) >= PRC_REDIRECT_NET && (cmd) <= PRC_REDIRECT_TOSHOST) + + +/* Network stack defines... */ +#ifdef _NETWORK_STACK +struct protosw *protocols; +void add_protocol(struct protosw *pr, int fam); +void remove_protocol(struct protosw *pr); +#endif +struct protosw *pffindproto(int domain, int protocol, int type); +struct protosw *pffindtype(int domain, int type); + +#endif /* PROTOSW_H */ diff --git a/headers/posix/sys/select.h b/headers/posix/sys/select.h new file mode 100644 index 0000000000..e55afb01c1 --- /dev/null +++ b/headers/posix/sys/select.h @@ -0,0 +1,50 @@ +/* select.h */ + +#ifndef _SYS_SELECT_H +#define _SYS_SELECT_H + +#include /* for struct timeval */ +/* + * You can define your own FDSETSIZE if you want more bits + */ + +#ifndef FD_SETSIZE +#define FD_SETSIZE 1024 +#endif /* FD_SETSIZE */ + +/* compatability with BSD */ +#define NBBY 8 /* number of bits in a byte */ + +typedef unsigned long fd_mask; + +#ifndef howmany +#define howmany(x, y) (((x) + ((y) - 1)) / (y)) +#endif + +/* + * Compatibily only: use FD_SETSIZE instead + */ +#ifndef FDSETSIZE +#define FDSETSIZE FD_SETSIZE +#endif /* FDSETSIZE */ + +#define NFDBITS 32 + +typedef struct fd_set { + unsigned mask[FDSETSIZE / NFDBITS]; +} fd_set; + +#define _FDMSKNO(fd) ((fd) / NFDBITS) +#define _FDBITNO(fd) ((fd) % NFDBITS) + +#define FD_ZERO(setp) memset((setp)->mask, 0, sizeof((setp)->mask)) +#define FD_SET(fd, setp) ((setp)->mask[_FDMSKNO(fd)] |= (1 << (_FDBITNO(fd)))) +#define FD_CLR(fd, setp) ((setp)->mask[_FDMSKNO(fd)] &= ~(1 << (_FDBITNO(fd)))) +#define FD_ISSET(fd, setp) ((setp)->mask[_FDMSKNO(fd)] & (1 << (_FDBITNO(fd)))) + +int select(int nbits, struct fd_set *rbits, + struct fd_set *wbits, + struct fd_set *ebits, + struct timeval *timeout); + +#endif /* _SYS_SELECT_H */ diff --git a/headers/posix/sys/socket.h b/headers/posix/sys/socket.h new file mode 100644 index 0000000000..eda7d3bdd7 --- /dev/null +++ b/headers/posix/sys/socket.h @@ -0,0 +1,216 @@ +/* sys/socket.h */ + +#ifndef OBOS_SYS_SOCKET_H +#define OBOS_SYS_SOCKET_H + +#include + +/* shoudl bt in types.h */ +typedef uint32 socklen_t; + +/* These are the address/protocol families we'll be using... */ +/* NB these should be added to as required... */ + +/* If we want to have Binary compatability we may need to alter these + * to agree with the Be versions... + */ +#define AF_UNSPEC 0 +#define AF_LOCAL 1 +#define AF_UNIX AF_LOCAL /* for compatability */ +#define AF_INET 2 +#define AF_ROUTE 3 +#define AF_IMPLINK 4 +#define AF_LINK 18 +#define AF_IPX 23 +#define AF_INET6 24 + +#define AF_MAX 24 + +#define PF_UNSPEC AF_UNSPEC +#define PF_INET AF_INET +#define PF_ROUTE AF_ROUTE +#define PF_LINK AF_LINK +#define PF_INET6 AF_INET6 +#define PF_IPX AF_IPX +#define PF_IMPLINK AF_IMPLINK + +/* Types of socket we can create (eventually) */ +#define SOCK_DGRAM 10 +#define SOCK_STREAM 11 +#define SOCK_RAW 12 +#define SOCK_MISC 255 + +/* + * Option flags per-socket. + */ +#define SO_DEBUG 0x0001 /* turn on debugging info recording */ +#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */ +#define SO_REUSEADDR 0x0004 /* allow local address reuse */ +#define SO_KEEPALIVE 0x0008 /* keep connections alive */ +#define SO_DONTROUTE 0x0010 /* just use interface addresses */ +#define SO_BROADCAST 0x0020 /* permit sending of broadcast msgs */ +#define SO_USELOOPBACK 0x0040 /* bypass hardware when possible */ +#define SO_LINGER 0x0080 /* linger on close if data present */ +#define SO_OOBINLINE 0x0100 /* leave received OOB data in line */ +#define SO_REUSEPORT 0x0200 /* allow local address & port reuse */ + +#define SOL_SOCKET 0xffff + +/* + * Additional options, not kept in so_options. + */ +#define SO_SNDBUF 0x1001 /* send buffer size */ +#define SO_RCVBUF 0x1002 /* receive buffer size */ +#define SO_SNDLOWAT 0x1003 /* send low-water mark */ +#define SO_RCVLOWAT 0x1004 /* receive low-water mark */ +#define SO_SNDTIMEO 0x1005 /* send timeout */ +#define SO_RCVTIMEO 0x1006 /* receive timeout */ +#define SO_ERROR 0x1007 /* get error status and clear */ +#define SO_TYPE 0x1008 /* get socket type */ +#define SO_NETPROC 0x1020 /* multiplex; network processing */ + +/* + * These are the valid values for the "how" field used by shutdown(2). + */ +#define SHUT_RD 1 +#define SHUT_WR 2 +#define SHUT_RDWR 3 + +struct linger { + int l_onoff; + int l_linger; +}; + +struct sockaddr { + uint8 sa_len; + uint8 sa_family; + uint8 sa_data[30]; +}; + +/* this can hold ANY sockaddr we care to throw at it! */ +struct sockaddr_storage { + uint8 ss_len; /* total length */ + uint8 ss_family; /* address family */ + uint8 __ss_pad1[6]; /* align to quad */ + uint64 __ss_pad2; /* force alignment for stupid compilers */ + uint8 __ss_pad3[240]; /* pad to a total of 256 bytes */ +}; + +struct sockproto { + uint16 sp_family; + uint16 sp_protocol; +}; + +#define CTL_NET 4 + +#define CTL_NET_NAMES { \ + { 0, 0 }, \ + { "unix", CTLTYPE_NODE }, \ + { "inet", CTLTYPE_NODE }, \ + { "implink", CTLTYPE_NODE }, \ + { "pup", CTLTYPE_NODE }, \ + { "chaos", CTLTYPE_NODE }, \ + { "xerox_ns", CTLTYPE_NODE }, \ + { "iso", CTLTYPE_NODE }, \ + { "emca", CTLTYPE_NODE }, \ + { "datakit", CTLTYPE_NODE }, \ + { "ccitt", CTLTYPE_NODE }, \ + { "ibm_sna", CTLTYPE_NODE }, \ + { "decnet", CTLTYPE_NODE }, \ + { "dec_dli", CTLTYPE_NODE }, \ + { "lat", CTLTYPE_NODE }, \ + { "hylink", CTLTYPE_NODE }, \ + { "appletalk", CTLTYPE_NODE }, \ + { "route", CTLTYPE_NODE }, \ + { "link_layer", CTLTYPE_NODE }, \ + { "xtp", CTLTYPE_NODE }, \ + { "coip", CTLTYPE_NODE }, \ + { "cnt", CTLTYPE_NODE }, \ + { "rtip", CTLTYPE_NODE }, \ + { "ipx", CTLTYPE_NODE }, \ + { "inet6", CTLTYPE_NODE }, \ + { "pip", CTLTYPE_NODE }, \ + { "isdn", CTLTYPE_NODE }, \ + { "natm", CTLTYPE_NODE }, \ + { "encap", CTLTYPE_NODE }, \ + { "sip", CTLTYPE_NODE }, \ + { "key", CTLTYPE_NODE }, \ +} + +/* + * PF_ROUTE - Routing table + * + * Three additional levels are defined: + * Fourth: address family, 0 is wildcard + * Fifth: type of info, defined below + * Sixth: flag(s) to mask with for NET_RT_FLAGS + */ +#define NET_RT_DUMP 1 /* dump; may limit to a.f. */ +#define NET_RT_FLAGS 2 /* by flags, e.g. RESOLVING */ +#define NET_RT_IFLIST 3 /* survey interface list */ +#define NET_RT_MAXID 4 + +#define CTL_NET_RT_NAMES { \ + { 0, 0 }, \ + { "dump", CTLTYPE_STRUCT }, \ + { "flags", CTLTYPE_STRUCT }, \ + { "iflist", CTLTYPE_STRUCT }, \ +} + + /* Max listen queue for a socket */ +#define SOMAXCONN 5 /* defined as 128 in OpenBSD */ + +struct msghdr { + caddr_t msg_name; /* address we're using (optional) */ + uint msg_namelen; /* length of address */ + struct iovec *msg_iov; /* scatter/gather array we'll use */ + uint msg_iovlen; /* # elements in msg_iov */ + caddr_t msg_control; /* extra data */ + uint msg_controllen; /* length of extra data */ + int msg_flags; /* flags */ +}; + +/* Defines used in msghdr structure. */ +#define MSG_OOB 0x1 /* process out-of-band data */ +#define MSG_PEEK 0x2 /* peek at incoming message */ +#define MSG_DONTROUTE 0x4 /* send without using routing tables */ +#define MSG_EOR 0x8 /* data completes record */ +#define MSG_TRUNC 0x10 /* data discarded before delivery */ +#define MSG_CTRUNC 0x20 /* control data lost before delivery */ +#define MSG_WAITALL 0x40 /* wait for full request or error */ +#define MSG_DONTWAIT 0x80 /* this message should be nonblocking */ +#define MSG_BCAST 0x100 /* this message rec'd as broadcast */ +#define MSG_MCAST 0x200 /* this message rec'd as multicast */ + +struct cmsghdr { + uint cmsg_len; + int cmsg_level; + int cmsg_type; + /* there now follows uchar[] cmsg_data */ +}; + + +/* Function declarations */ +int socket (int, int, int); +int bind(int, const struct sockaddr *, int); +int connect(int, const struct sockaddr *, int); +int listen(int, int); +int accept(int, struct sockaddr *, int *); +int closesocket(int); +int shutdown(int sock, int how); + +ssize_t send(int, const void *, size_t, int); +ssize_t recv(int, void *, size_t, int); +ssize_t sendto(int, const void *, size_t, int, const struct sockaddr *, size_t); +ssize_t recvfrom(int, void *, size_t, int, struct sockaddr *, size_t *); + +int setsockopt(int, int, int, const void *, size_t); +int getsockopt(int, int, int, void *, size_t *); +int getpeername(int, struct sockaddr *, int *); +int getsockname(int, struct sockaddr *, int *); + +/* is it really part of sockets BSD API?*/ +int sysctl (int *, uint, void *, size_t *, void *, size_t); + +#endif /* OBOS_SYS_SOCKET_H */ + diff --git a/headers/posix/sys/socketvar.h b/headers/posix/sys/socketvar.h new file mode 100644 index 0000000000..664dbca4c8 --- /dev/null +++ b/headers/posix/sys/socketvar.h @@ -0,0 +1,236 @@ +/* socketvar.h */ + + +#ifndef SYS_SOCKETVAR_H +#define SYS_SOCKETVAR_H + +#include +#include "sys/mbuf.h" +#include "sys/net_uio.h" +#include "sys/socket.h" + +struct sockbuf { + uint32 sb_cc; /* actual chars in buffer */ + uint32 sb_hiwat; /* max actual char count (high water mark) */ + uint32 sb_mbcnt; /* chars of mbufs used */ + uint32 sb_mbmax; /* max chars of mbufs to use */ + int32 sb_lowat; /* low water mark */ + struct mbuf *sb_mb; /* the mbuf chain */ + int16 sb_flags; /* flags, see below */ + int32 sb_timeo; /* timeout for read/write */ + sem_id sb_sleep; /* our sleep sem */ + sem_id sb_pop; /* sem to wait on... */ +}; + +#define SB_MAX (256*1024) /* default for max chars in sockbuf */ +#define SB_LOCK 0x01 /* lock on data queue */ +#define SB_WANT 0x02 /* someone is waiting to lock */ +#define SB_WAIT 0x04 /* someone is waiting for data/space */ +#define SB_SEL 0x08 /* someone is selecting */ +#define SB_ASYNC 0x10 /* ASYNC I/O, need signals */ +#define SB_NOINTR 0x40 /* operations not interruptible */ +#define SB_KNOTE 0x80 /* kernel note attached */ +#define SB_NOTIFY (SB_WAIT|SB_SEL|SB_ASYNC) + +typedef void (*socket_event_callback)(void * socket, uint32 event, void * cookie); + +struct socket { + uint16 so_type; /* type of socket */ + uint16 so_options; /* socket options */ + int16 so_linger; /* dreaded linger value */ + int16 so_state; /* socket state */ + caddr_t so_pcb; /* pointer to the control block */ + sem_id so_lock; /* socket lock */ + sem_id so_timeo; /* our wait channel */ + + struct protosw *so_proto; /* pointer to protocol module */ + + struct socket *so_head; + struct socket *so_q0; + struct socket *so_q; + + int16 so_q0len; + int16 so_qlen; + int16 so_qlimit; + int32 so_error; +// pid_t so_pgid; + uint32 so_oobmark; + + /* our send/recv buffers */ + struct sockbuf so_snd; + struct sockbuf so_rcv; + + // event callback + socket_event_callback event_callback; + void * event_callback_cookie; + int sel_ev; +}; + +/* Select event bit mask */ +#define SEL_READ 0x01 +#define SEL_WRITE 0x02 +#define SEL_EX 0x04 + +/* + * Socket state bits. + */ +#define SS_NOFDREF 0x001 /* no file table ref any more */ +#define SS_ISCONNECTED 0x002 /* socket connected to a peer */ +#define SS_ISCONNECTING 0x004 /* in process of connecting to peer */ +#define SS_ISDISCONNECTING 0x008 /* in process of disconnecting */ +#define SS_CANTSENDMORE 0x010 /* can't send more data to peer */ +#define SS_CANTRCVMORE 0x020 /* can't receive more data from peer */ +#define SS_RCVATMARK 0x040 /* at mark on input */ +#define SS_ISDISCONNECTED 0x800 /* socket disconnected from peer */ + +#define SS_PRIV 0x080 /* privileged for broadcast, raw... */ +#define SS_NBIO 0x100 /* non-blocking ops */ +#define SS_ASYNC 0x200 /* async i/o notify */ +#define SS_ISCONFIRMING 0x400 /* deciding to accept connection req */ +#define SS_CONNECTOUT 0x1000 /* connect, not accept, at this end */ + +/* helpful defines... */ + +/* adjust counters in sb reflecting freeing of m */ +#define sbfree(sb, m) { \ + (sb)->sb_cc -= (m)->m_len; \ + (sb)->sb_mbcnt -= MSIZE; \ + if ((m)->m_flags & M_EXT) \ + (sb)->sb_mbcnt -= (m)->m_ext.ext_size; \ +} + +#define sbspace(sb) \ + ((uint32) min((int)((sb)->sb_hiwat - (sb)->sb_cc), \ + (int)((sb)->sb_mbmax - (sb)->sb_mbcnt))) + +/* do we have to send all at once on a socket? */ +#define sosendallatonce(so) \ + ((so)->so_proto->pr_flags & PR_ATOMIC) + +/* adjust counters in sb reflecting allocation of m */ +#define sballoc(sb, m) { \ + (sb)->sb_cc += (m)->m_len; \ + (sb)->sb_mbcnt += MSIZE; \ + if ((m)->m_flags & M_EXT) \ + (sb)->sb_mbcnt += (m)->m_ext.ext_size; \ +} + +#define soreadable(so) \ + ((so)->so_rcv.sb_cc >= (so)->so_rcv.sb_lowat || \ + ((so)->so_state & SS_CANTRCVMORE) || \ + (so)->so_qlen || (so)->so_error) + +#define sowriteable(so) \ + ((sbspace(&(so)->so_snd) >= (so)->so_snd.sb_lowat) && \ + (((so)->so_state & SS_ISCONNECTED) || \ + (((so)->so_proto->pr_flags & PR_CONNREQUIRED) == 0) || \ + ((so)->so_state & SS_CANTSENDMORE) || (so)->so_error)) + +#define M_WAITOK 0x0000 +#define M_NOWAIT 0x0001 + +/* + * Set lock on sockbuf sb; sleep if lock is already held. + * Unless SB_NOINTR is set on sockbuf, sleep is interruptible. + * Returns error without lock if sleep is interrupted. + */ +#define sblock(sb, wf) ((sb)->sb_flags & SB_LOCK ? \ + (((wf) == M_WAITOK) ? sb_lock(sb) : EWOULDBLOCK) : \ + ((sb)->sb_flags |= SB_LOCK), 0) + +/* release lock on sockbuf sb */ +#define sbunlock(sb) { \ + (sb)->sb_flags &= ~SB_LOCK; \ + if ((sb)->sb_flags & SB_WANT) { \ + (sb)->sb_flags &= ~SB_WANT; \ + wakeup((sb)->sb_sleep); \ + } \ +} + +#define sorwakeup(so) sowakeup((so), &(so)->so_rcv) +/* we don't handle upcall for sockets */ +#define sowwakeup(so) sowakeup((so), &(so)->so_snd) + +#ifdef _NETWORK_STACK + +uint32 sb_max; + +/* Function prototypes */ + +/* These are the ones we export to libnet.so */ + +int initsocket(void **); +int socreate (int, void *, int, int); +int soshutdown(void *, int); +int soclose (void *); + +int sobind (void *, caddr_t, int); +int solisten (void *, int); +int soconnect (void *, caddr_t, int); +int soaccept (void *, void **, void *, int *); + +int writeit (void *, struct iovec *, int); +int readit (void *, struct iovec *, int *); +int sendit (void *, struct msghdr *, int, int *); +int recvit (void *, struct msghdr *, caddr_t, int *); + +int soo_ioctl (void *, int, caddr_t); +int sosysctl (int *, uint, void *, size_t *, void *, size_t); +int sosetopt (void *, int, int, const void *, size_t); +int sogetopt (void *, int, int, void *, size_t *); + +int sogetpeername(void *, struct sockaddr *, int *); +int sogetsockname(void *, struct sockaddr *, int *); + + +/* these are all private to the stack...although may be shared with + * other network modules. + */ + +int sosend(struct socket *so, struct mbuf *addr, struct uio *uio, + struct mbuf *top, struct mbuf *control, int flags); + +struct socket *sonewconn(struct socket *head, int connstatus); +int set_socket_event_callback(void *, socket_event_callback, void *, int); +int soreserve (struct socket *so, uint32 sndcc, uint32 rcvcc); + +void sbrelease (struct sockbuf *sb); +int sbreserve (struct sockbuf *sb, uint32 cc); +void sbdrop (struct sockbuf *sb, int len); +void sbdroprecord (struct sockbuf *sb); +void sbflush (struct sockbuf *sb); +int sbwait (struct sockbuf *sb); +void sbappend (struct sockbuf *sb, struct mbuf *m); +int sbappendaddr (struct sockbuf *sb, struct sockaddr *asa, + struct mbuf *m0, struct mbuf *control); +int sbappendcontrol (struct sockbuf *sb, struct mbuf *m0, + struct mbuf *control); +void sbappendrecord (struct sockbuf *sb, struct mbuf *m0); +void sbcheck (struct sockbuf *sb); +void sbcompress (struct sockbuf *sb, struct mbuf *m, struct mbuf *n); +int soreceive (struct socket *so, struct mbuf **paddr, struct uio *uio, + struct mbuf **mp0, struct mbuf **controlp, int *flagsp); +void sowakeup(struct socket *so, struct sockbuf *sb); +int sbwait(struct sockbuf *sb); + +int sodisconnect(struct socket *); +void sofree(struct socket *); + +void sohasoutofband(struct socket *so); +void socantsendmore(struct socket *so); +void socantrcvmore(struct socket *so); +void soisconnected (struct socket *so); +void soisconnecting (struct socket *so); +void soisdisconnected (struct socket *so); +void soisdisconnecting (struct socket *so); +void soqinsque (struct socket *head, struct socket *so, int q); +int soqremque (struct socket *so, int q); +int sorflush(struct socket *so); + +int sb_lock(struct sockbuf *sb); +int nsleep(sem_id chan, char *msg, int timeo); +void wakeup(sem_id chan); + +#endif /* _NETWORK_STACK */ + +#endif /* SYS_SOCKETVAR_H */ diff --git a/headers/posix/sys/sockio.h b/headers/posix/sys/sockio.h new file mode 100644 index 0000000000..a9b6f55327 --- /dev/null +++ b/headers/posix/sys/sockio.h @@ -0,0 +1,65 @@ +/* net_ioctl.h */ + +#ifndef SYS_NET_IOCTL_H +#define SYS_NET_IOCTL_H + +#define IOCPARM_MASK 0x1fff /* parameter length, at most 13 bits */ + +#define IOC_OUT (unsigned long)0x40000000 + /* copy parameters in */ +#define IOC_IN (unsigned long)0x80000000 + /* copy paramters in and out */ +#define IOC_INOUT (IOC_IN|IOC_OUT) + /* mask for IN/OUT/VOID */ + +#define _IOC(inout,group,num,len) \ + (inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num)) + +#define IOCGROUP(x) (((x) >> 8) & 0xff) + +#define _IOR(g,n,t) _IOC(IOC_OUT, (g), (n), sizeof(t)) +#define _IOW(g,n,t) _IOC(IOC_IN, (g), (n), sizeof(t)) +#define _IOWR(g,n,t) _IOC(IOC_INOUT, (g), (n), sizeof(t)) + +#define FIONBIO _IOW('f', 126, int) /* set/clear non-blocking i/o */ +#define FIONREAD _IOR('f', 127, int) /* get # bytes to read */ + +#define SIOCSHIWAT _IOW('s', 0, int) /* set high watermark */ +#define SIOCGHIWAT _IOR('s', 1, int) /* get high watermark */ +#define SIOCSLOWAT _IOW('s', 2, int) /* set low watermark */ +#define SIOCGLOWAT _IOR('s', 3, int) /* get low watermark */ +#define SIOCATMARK _IOR('s', 7, int) /* at oob mark? */ + +#define SIOCADDRT _IOW('r', 10, struct ortentry) /* add route */ +#define SIOCDELRT _IOW('r', 11, struct ortentry) /* delete route */ + +#define SIOCSIFADDR _IOW('i', 12, struct ifreq) /* set ifnet address */ +#define OSIOCGIFADDR _IOWR('i', 13, struct ifreq) /* get ifnet address */ +#define SIOCGIFADDR _IOWR('i', 33, struct ifreq) /* get ifnet address */ +#define SIOCSIFDSTADDR _IOW('i', 14, struct ifreq) /* set p-p address */ +#define OSIOCGIFDSTADDR _IOWR('i', 15, struct ifreq) /* get p-p address */ +#define SIOCGIFDSTADDR _IOWR('i', 34, struct ifreq) /* get p-p address */ +#define SIOCSIFFLAGS _IOW('i', 16, struct ifreq) /* set ifnet flags */ +#define SIOCGIFFLAGS _IOWR('i', 17, struct ifreq) /* get ifnet flags */ +#define OSIOCGIFBRDADDR _IOWR('i', 18, struct ifreq) /* get broadcast addr */ +#define SIOCGIFBRDADDR _IOWR('i', 35, struct ifreq) /* get broadcast addr */ +#define SIOCSIFBRDADDR _IOW('i', 19, struct ifreq) /* set broadcast addr */ +#define OSIOCGIFCONF _IOWR('i', 20, struct ifconf) /* get ifnet list */ +#define SIOCGIFCONF _IOWR('i', 36, struct ifconf) /* get ifnet list */ +#define OSIOCGIFNETMASK _IOWR('i', 21, struct ifreq) /* get net addr mask */ +#define SIOCGIFNETMASK _IOWR('i', 37, struct ifreq) /* get net addr mask */ +#define SIOCSIFNETMASK _IOW('i', 22, struct ifreq) /* set net addr mask */ +#define SIOCGIFMETRIC _IOWR('i', 23, struct ifreq) /* get IF metric */ +#define SIOCSIFMETRIC _IOW('i', 24, struct ifreq) /* set IF metric */ +#define SIOCDIFADDR _IOW('i', 25, struct ifreq) /* delete IF addr */ +#define SIOCAIFADDR _IOW('i', 26, struct ifaliasreq)/* add/chg IF alias */ +#define SIOCGIFDATA _IOWR('i', 27, struct ifreq) /* get if_data */ + +#define SIOCGIFMTU _IOWR('i', 126, struct ifreq) /* get ifnet MTU */ +#define SIOCSIFMTU _IOW('i', 127, struct ifreq) /* set ifnet MTU */ + +#define SIOCADDMULTI _IOW('i', 49, struct ifreq) /* add m'cast addr */ +#define SIOCDELMULTI _IOW('i', 50, struct ifreq) /* del m'cast addr */ + +#endif /* SYS_NET_IOCTL_H */ + diff --git a/headers/posix/userland_ipc.h b/headers/posix/userland_ipc.h new file mode 100644 index 0000000000..397aa0f98a --- /dev/null +++ b/headers/posix/userland_ipc.h @@ -0,0 +1,53 @@ +#ifndef USERLAND_IPC_H +#define USERLAND_IPC_H +/* userland_ipc - Communication between the network driver +** and the userland stack. +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include +#include "net_stack_driver.h" + + +#define NET_STACK_PORTNAME "net_server connection" + +enum { + NET_STACK_OPEN = NET_STACK_IOCTL_MAX, + NET_STACK_CLOSE, + NET_STACK_NEW_CONNECTION, +}; + +#define MAX_NET_AREAS 5 + +typedef struct { + area_id id; + uint8 *offset; +} net_area_info; + +typedef struct { + int32 op; +// int32 buffer; + uint8 *data; + int32 length; + int32 result; + net_area_info area[MAX_NET_AREAS]; +} net_command; + +#define CONNECTION_QUEUE_LENGTH 128 +#define CONNECTION_COMMAND_SIZE 2048 + +typedef struct { + port_id port; + area_id area; + + sem_id commandSemaphore; // command queue + uint32 numCommands,bufferSize; +} net_connection; + +extern status_t init_userland_ipc(void); +extern void shutdown_userland_ipc(void); + +#endif /* USERLAND_IPC_H */ diff --git a/headers/private/app/PortLink.h b/headers/private/app/PortLink.h new file mode 100644 index 0000000000..9f5432daab --- /dev/null +++ b/headers/private/app/PortLink.h @@ -0,0 +1,43 @@ +#ifndef _PORTLINK_H_ +#define _PORTLINK_H_ + +#include +#include +#include +#include + +#ifndef _PORTLINK_BUFFERSIZE +#define _PORTLINK_MAX_ATTACHMENTS 50 +#endif + +class PortLinkData; + +class PortLink +{ +public: + PortLink(port_id port); + ~PortLink(void); + void SetOpCode(int32 code); + void SetPort(port_id port); + port_id GetPort(void); + void Flush(bigtime_t timeout=B_INFINITE_TIMEOUT); + int8* FlushWithReply(int32 *code, status_t *status, ssize_t *buffersize, + bigtime_t timeout=B_INFINITE_TIMEOUT); + void Attach(void *data, size_t size); + void Attach(int32 data); + void Attach(int16 data); + void Attach(int8 data); + void Attach(float data); + void Attach(bool data); + void Attach(BRect data); + void Attach(BPoint data); + void MakeEmpty(void); +protected: + void FlattenData(int8 **buffer,int32 *size); + port_id target, replyport; + int32 opcode, bufferlength; + int num_attachments; + PortLinkData *attachments[_PORTLINK_MAX_ATTACHMENTS]; +}; + +#endif \ No newline at end of file diff --git a/headers/private/app/TokenSpace.h b/headers/private/app/TokenSpace.h new file mode 100644 index 0000000000..fef6e334d7 --- /dev/null +++ b/headers/private/app/TokenSpace.h @@ -0,0 +1,89 @@ +//------------------------------------------------------------------------------ +// TokenSpace.h +// +//------------------------------------------------------------------------------ + +#ifndef TOKENSPACE_H +#define TOKENSPACE_H + +// Standard Includes ----------------------------------------------------------- +#include +#include + +// System Includes ------------------------------------------------------------- +#include +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- +#define B_NULL_TOKEN -1 +#define B_ANY_TOKEN 0 +#define B_HANDLER_TOKEN 1 + +// Globals --------------------------------------------------------------------- + +namespace BPrivate { + +typedef void (*new_token_callback)(int16, void*); +typedef void (*remove_token_callback)(int16, void*); +typedef bool (*get_token_callback)(int16, void*); + +class BTokenSpace +{ + public: + BTokenSpace(); + ~BTokenSpace(); + + int32 NewToken(int16 type, void* object, + new_token_callback callback= NULL); + bool RemoveToken(int32 token, remove_token_callback callback = NULL); + bool CheckToken(int32, int16) const; + status_t GetToken(int32, int16, void**, + get_token_callback callback = NULL) const; + +// Possible expansion +// void Dump(BDataIO&, bool) const; +// int32 NewToken(void*, BDirectMessageTarget*, void (*)(short, void*)); +// bool SetTokenTarget(uint32, BDirectMessageTarget*); +// BDirectMessageTarget* TokenTarget(uint32 token, int16 type); + + private: + struct TTokenInfo + { + int16 type; + void* object; + }; + + typedef std::map TTokenMap; + + TTokenMap fTokenMap; + std::stack fTokenBin; + int32 fTokenCount; + BLocker fLocker; +}; + +// Possible expansion +//_delete_tokens_(); +//_init_tokens_(); +//get_handler_token(short, void*); +//get_token_list(long, long*); +//new_handler_token(short, void*); +//remove_handler_token(short, void*); + +extern _IMPEXP_BE BTokenSpace gDefaultTokens; + +} // namespace BPrivate + +#endif //TOKENSPACE_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/headers/private/input/kb_mouse_driver.h b/headers/private/input/kb_mouse_driver.h new file mode 100644 index 0000000000..da7c61b071 --- /dev/null +++ b/headers/private/input/kb_mouse_driver.h @@ -0,0 +1,172 @@ +// +// kb_mouse_driver.h +// + + +#ifndef _KB_MOUSE_DRIVER_H +#define _KB_MOUSE_DRIVER_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + + +// Be key numbers for various cool keys + +#define KEY_Scroll 0x0f +#define KEY_Pause 0x10 +#define KEY_Num 0x22 +#define KEY_CapsLock 0x3b +#define KEY_ShiftL 0x4b +#define KEY_ShiftR 0x56 +#define KEY_ControlL 0x5c +#define KEY_CmdL 0x5d +#define KEY_AltL 0x5d +#define KEY_CmdR 0x5f +#define KEY_AltR 0x5f +#define KEY_ControlR 0x60 +#define KEY_OptL 0x66 +#define KEY_WinL 0x66 +#define KEY_OptR 0x67 +#define KEY_WinR 0x67 +#define KEY_Menu 0x68 +#define KEY_NumEqual 0x6a +#define KEY_Power 0x6b +#define KEY_SysRq 0x7e +#define KEY_Break 0x7f + +#define KB_DEFAULT_CONTROL_ALT_DEL_TIMEOUT 4000000 + + +// ioctl codes + +enum { + KB_READ = B_DEVICE_OP_CODES_END, + KB_GET_KEYBOARD_ID, + KB_SET_LEDS, + KB_SET_KEY_REPEATING, + KB_SET_KEY_NONREPEATING, + KB_SET_KEY_REPEAT_RATE, + KB_GET_KEY_REPEAT_RATE, + KB_SET_KEY_REPEAT_DELAY, + KB_GET_KEY_REPEAT_DELAY, + KB_SET_CONTROL_ALT_DEL_TIMEOUT, + KB_RESERVED_1, // was KB_ACKNOWLEDGE_CONTROL_ALT_DEL, + KB_CANCEL_CONTROL_ALT_DEL, + KB_DELAY_CONTROL_ALT_DEL, + + MS_READ = B_DEVICE_OP_CODES_END + 100, + MS_NUM_EVENTS, + MS_GETA, + MS_SETA, + MS_GETTYPE, + MS_SETTYPE, + MS_GETMAP, + MS_SETMAP, + MS_GETCLICK, + MS_SETCLICK, + MS_NUM_SERIAL_MICE, + + IIC_WRITE = B_DEVICE_OP_CODES_END + 200, + RESTART_SYSTEM, + SHUTDOWN_SYSTEM +}; + + +// keyboard settings info, as kept in settings file + + +typedef struct { + bigtime_t key_repeat_delay; + int32 key_repeat_rate; +} kb_settings; + +#define kb_settings_file "Keyboard_settings" + + +// structure passed to KB_READ + +typedef struct { // USB, ADB keyboards + bigtime_t timestamp; + uint32 be_keycode; + bool is_keydown; +} raw_key_info; + +typedef struct { // AT keyboards + bigtime_t timestamp; + uint8 scancode; // high bit set for extended scancodes + bool is_keydown; +} at_kbd_io; + + +// structure passed to KB_SET_LEDS + +typedef struct { + bool num_lock; + bool caps_lock; + bool scroll_lock; +} led_info; + + + +// mouse settings info + +typedef enum { + MOUSE_1_BUTTON = 1, + MOUSE_2_BUTTON, + MOUSE_3_BUTTON +} mouse_type; + +typedef struct { + int32 left; + int32 right; + int32 middle; +} map_mouse; + +typedef struct { + bool enabled; // Acceleration on / off + int32 accel_factor; // accel factor: 256 = step by 1, 128 = step by 1/2 + int32 speed; // speed accelerator (1=1X, 2 = 2x)... +} mouse_accel; + +typedef struct { + mouse_type type; + map_mouse map; + mouse_accel accel; + bigtime_t click_speed; +} mouse_settings; + +#define mouse_settings_file "Mouse_settings" + +typedef struct { + int serial_cookie; + int buttons; + int xdelta; + int ydelta; + int32 clicks; + int32 modifiers; + bigtime_t time; + int wheel_delta; +} mouse_pos; + + +// On the Mac, the I-squared C bus is controlled by the Cuda microcontroller, +// which also runs ADB. Since we have not yet partitioned the driver into +// a separate Cuda driver and a kb/mouse driver, the iic is controlled with +// control calls to the kb_mouse driver. Yuck. + +typedef struct { + char device; + char reg; + char value; +} iic_write; + +#ifdef __cplusplus +} +#endid + +#endif \ No newline at end of file diff --git a/headers/private/interface/TextInput.h b/headers/private/interface/TextInput.h new file mode 100644 index 0000000000..f838aea59b --- /dev/null +++ b/headers/private/interface/TextInput.h @@ -0,0 +1,81 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: TextInput.h +// Author: Frans van Nispen (xlr8@tref.nl) +// Description: The BTextView derivative owned by an instance of +// BTextControl. +//------------------------------------------------------------------------------ + +#ifndef _TEXT_CONTROLI_H +#define _TEXT_CONTROLI_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +class BTextControl; + +// _BTextInput_ class ---------------------------------------------------------- +class _BTextInput_ : public BTextView { +public: + _BTextInput_(BTextControl* parent, BRect frame, + const char* name, BRect rect, + uint32 mask = B_FOLLOW_LEFT | B_FOLLOW_TOP, + uint32 flags = B_WILL_DRAW | B_NAVIGABLE); + ~_BTextInput_(); + + virtual void AttachedToWindow(); + virtual void MakeFocus(bool state = true); + virtual void SetViewColor(rgb_color); + rgb_color ViewColor(); + virtual bool CanEndLine(int32); + virtual void KeyDown(const char* bytes, int32 numBytes); + virtual void Draw(BRect); + virtual void SetEnabled(bool state); + virtual void MouseDown(BPoint where); + +private: + rgb_color fViewColor; + bool fEnabled; + bool fChanged; + BTextControl* fParent; +}; +//------------------------------------------------------------------------------ + +#endif // _TEXT_CONTROLI_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/headers/private/interface/pr_server.h b/headers/private/interface/pr_server.h new file mode 100644 index 0000000000..2748d3ecb2 --- /dev/null +++ b/headers/private/interface/pr_server.h @@ -0,0 +1,74 @@ +/*****************************************************************************/ +// print_server Background Application. +// +// Version: 1.0.0d1 +// +// The print_server manages the communication between applications and the +// printer and transport drivers. +// +// +// This application and all source files used in its construction, except +// where noted, are licensed under the MIT License, and have been written +// and are: +// +// Copyright (c) 2001 OpenBeOS Project +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ + +#ifndef _PR_SERVER_H_ +#define _PR_SERVER_H_ + +// signature mime types +#define PSRV_SIGNATURE_TYPE "application/x-vnd.Be-PSRV" +#define PRNT_SIGNATURE_TYPE "application/x-vnd.Be-PRNT" + +// messages understood by print_server +#define PSRV_GET_ACTIVE_PRINTER 'pgcp' +#define PSRV_MAKE_PRINTER_ACTIVE_QUIETLY 'pmaq' +#define PSRV_MAKE_PRINTER_ACTIVE 'pmac' +#define PSRV_MAKE_PRINTER 'selp' +#define PSRV_SHOW_PAGE_SETUP 'pgst' +#define PSRV_SHOW_PRINT_SETUP 'ppst' +#define PSRV_PRINT_SPOOLED_JOB 'psns' + +// mime file types +#define PSRV_PRINTER_FILETYPE "application/x-vnd.Be.printer" +#define PSRV_SPOOL_FILETYPE "application/x-vnd.Be.printer-spool" + +// spool Attributes +#define PSRV_SPOOL_ATTR_MIMETYPE "_spool/MimeType" +#define PSRV_SPOOL_ATTR_PAGECOUNT "_spool/Page Count" +#define PSRV_SPOOL_ATTR_DESCRIPTION "_spool/Description" +#define PSRV_SPOOL_ATTR_PRINTER "_spool/Printer" +#define PSRV_SPOOL_ATTR_STATUS "_spool/Status" +#define PSRV_SPOOL_ATTR_ERRCODE "_spool/_errorcode" + +// printer attributes +#define PSRV_PRINTER_ATTR_DRV_NAME "Driver Name" +#define PSRV_PRINTER_ATTR_PRT_NAME "Printer Name" +#define PSRV_PRINTER_ATTR_COMMENTS "Comments" +#define PSRV_PRINTER_ATTR_STATE "state" +#define PSRV_PRINTER_ATTR_TRANSPORT "transport" +#define PSRV_PRINTER_ATTR_TRANSPORT_ADDR "transport_address" +#define PSRV_PRINTER_ATTR_CNX "connection" +#define PSRV_PRINTER_ATTR_PNP "_PNP" +#define PSRV_PRINTER_ATTR_MDL "_MDL" + +#endif diff --git a/headers/private/kernel/Errors.h b/headers/private/kernel/Errors.h new file mode 100644 index 0000000000..8f9c12167b --- /dev/null +++ b/headers/private/kernel/Errors.h @@ -0,0 +1,261 @@ +/* Errors.h + * + * Error codes used by OpenBeOS. + * + * NB Where the codes can be directly mapped to a POSIX + * error value they have been. + * + * XXX - should be installed as support/Errors.h to keep + * compatibility with beos source code + */ + +/* The codes shown here are the ones that Be defined. If new + * error codes are needed they should be added AT THE END of the + * enums to make sure we don't damage our compatibility. + */ + +#ifndef _ERRORS_H +#define _ERRORS_H + +#include + +/* XXX - paranoid...should be in limits.h */ +#ifndef LONG_MIN +#define LONG_MIN (-2147483647L-1) +#endif + +/* These are the start points for the various categories of + * error. + * These are identical to the Be codes so we have compatibility + * with them. + */ +#define B_GENERAL_ERROR_BASE LONG_MIN +#define B_OS_ERROR_BASE B_GENERAL_ERROR_BASE + 0x1000 +#define B_APP_ERROR_BASE B_GENERAL_ERROR_BASE + 0x2000 +#define B_INTERFACE_ERROR_BASE B_GENERAL_ERROR_BASE + 0x3000 +#define B_MEDIA_ERROR_BASE B_GENERAL_ERROR_BASE + 0x4000 +#define B_TRANSLATION_ERROR_BASE B_GENERAL_ERROR_BASE + 0x4800 +#define B_MIDI_ERROR_BASE B_GENERAL_ERROR_BASE + 0x5000 +#define B_STORAGE_ERROR_BASE B_GENERAL_ERROR_BASE + 0x6000 +#define B_POSIX_ERROR_BASE B_GENERAL_ERROR_BASE + 0x7000 +#define B_MAIL_ERROR_BASE B_GENERAL_ERROR_BASE + 0x8000 +#define B_PRINT_ERROR_BASE B_GENERAL_ERROR_BASE + 0x9000 +#define B_DEVICE_ERROR_BASE B_GENERAL_ERROR_BASE + 0xa000 + +/* This can be used to add user-defined errors, use the + * value B_ERRORS_END +1 as the first value. + */ +#define B_ERRORS_END (B_GENERAL_ERROR_BASE + 0xffff) + +#define B_NO_ERROR 0 +#define B_OK 0 +#define B_ERROR -1 + +enum { + B_NO_MEMORY = B_GENERAL_ERROR_BASE, /* ENOMEM */ + B_IO_ERROR, /* EIO */ + B_PERMISSION_DENIED, /* EACCES */ + B_BAD_INDEX, + B_BAD_TYPE, + B_BAD_VALUE, /* EINVAL */ + B_MISMATCHED_VALUES, + B_NAME_NOT_FOUND, + B_NAME_IN_USE, + B_TIMED_OUT, /* ETIMEDOUT */ + B_INTERRUPTED, /* EINTR */ + B_WOULD_BLOCK, /* EWOULDBLOCK == EAGAIN */ + B_CANCELED, + B_NO_INIT, + B_BUSY, /* EBUSY */ + B_NOT_ALLOWED, /* EPERM */ +}; + +/* Kernel Kit Errors */ +enum { + B_BAD_SEM_ID = B_OS_ERROR_BASE, + B_NO_MORE_SEMS, + + B_BAD_THREAD_ID = B_OS_ERROR_BASE + 0x100, + B_NO_MORE_THREADS, + B_BAD_THREAD_STATE, + B_BAD_TEAM_ID, + B_NO_MORE_TEAMS, + + B_BAD_PORT_ID = B_OS_ERROR_BASE + 0x200, + B_NO_MORE_PORTS, + + B_BAD_IMAGE_ID = B_OS_ERROR_BASE + 0x300, + B_BAD_ADDRESS, + B_NOT_AN_EXECUTABLE, + B_MISSING_LIBRARY, + B_MISSING_SYMBOL, + + B_DEBUGGER_ALREADY_INSTALLED = B_OS_ERROR_BASE + 0x400 +}; + +/* Application Kit Errors */ +enum +{ + B_BAD_REPLY = B_APP_ERROR_BASE, + B_DUPLICATE_REPLY, + B_MESSAGE_TO_SELF, + B_BAD_HANDLER, + B_ALREADY_RUNNING, + B_LAUNCH_FAILED, + B_AMBIGUOUS_APP_LAUNCH, + B_UNKNOWN_MIME_TYPE, + B_BAD_SCRIPT_SYNTAX, + B_LAUNCH_FAILED_NO_RESOLVE_LINK, + B_LAUNCH_FAILED_EXECUTABLE, + B_LAUNCH_FAILED_APP_NOT_FOUND, + B_LAUNCH_FAILED_APP_IN_TRASH, + B_LAUNCH_FAILED_NO_PREFERRED_APP, + B_LAUNCH_FAILED_FILES_APP_NOT_FOUND, + B_BAD_MIME_SNIFFER_RULE +}; + + +/* Storage Kit & File System Errors */ +enum { + B_FILE_ERROR = B_STORAGE_ERROR_BASE, /* EBADF */ + B_FILE_NOT_FOUND, /* discouraged; use B_ENTRY_NOT_FOUND in new code*/ + B_FILE_EXISTS, /* EEXIST */ + B_ENTRY_NOT_FOUND, /* ENOENT */ + B_NAME_TOO_LONG, /* ENAMETOOLONG */ + B_NOT_A_DIRECTORY, /* ENOTDIR */ + B_DIRECTORY_NOT_EMPTY, /* ENOTEMPTY */ + B_DEVICE_FULL, /* ENOSPC */ + B_READ_ONLY_DEVICE, /* EROFS */ + B_IS_A_DIRECTORY, + B_NO_MORE_FDS, + B_CROSS_DEVICE_LINK, + B_LINK_LIMIT, + B_BUSTED_PIPE, + B_UNSUPPORTED, + B_PARTITION_TOO_SMALL +}; + +/* Media Kit Errors */ +enum { + B_STREAM_NOT_FOUND = B_MEDIA_ERROR_BASE, + B_SERVER_NOT_FOUND, + B_RESOURCE_NOT_FOUND, + B_RESOURCE_UNAVAILABLE, + B_BAD_SUBSCRIBER, + B_SUBSCRIBER_NOT_ENTERED, + B_BUFFER_NOT_AVAILABLE, + B_LAST_BUFFER_ERROR +}; + +/* Mail Kit Errors */ +enum +{ + B_MAIL_NO_DAEMON = B_MAIL_ERROR_BASE, + B_MAIL_UNKNOWN_USER, + B_MAIL_WRONG_PASSWORD, + B_MAIL_UNKNOWN_HOST, + B_MAIL_ACCESS_ERROR, + B_MAIL_UNKNOWN_FIELD, + B_MAIL_NO_RECIPIENT, + B_MAIL_INVALID_MAIL +}; + +/* Printing Errors */ +enum +{ + B_NO_PRINT_SERVER = B_PRINT_ERROR_BASE +}; + +/* Device Kit Errors */ +enum +{ + B_DEV_INVALID_IOCTL = B_DEVICE_ERROR_BASE, + B_DEV_NO_MEMORY, + B_DEV_BAD_DRIVE_NUM, + B_DEV_NO_MEDIA, + B_DEV_UNREADABLE, + B_DEV_FORMAT_ERROR, + B_DEV_TIMEOUT, + B_DEV_RECALIBRATE_ERROR, + B_DEV_SEEK_ERROR, + B_DEV_ID_ERROR, + B_DEV_READ_ERROR, + B_DEV_WRITE_ERROR, + B_DEV_NOT_READY, + B_DEV_MEDIA_CHANGED, + B_DEV_MEDIA_CHANGE_REQUESTED, + B_DEV_RESOURCE_CONFLICT, + B_DEV_CONFIGURATION_ERROR, + B_DEV_DISABLED_BY_USER, + B_DEV_DOOR_OPEN +}; + +/* These are the old newos errors - we should be trying to remove these + * in favour of the error codes above!!! + */ + +/* General errors */ +#define ERR_GENERAL -1 +#define ERR_NO_MEMORY ENOMEM +#define ERR_IO_ERROR EIO +#define ERR_INVALID_ARGS EINVAL +#define ERR_TIMED_OUT ETIMEDOUT +#define ERR_NOT_ALLOWED EPERM +#define ERR_PERMISSION_DENIED EACCES +#define ERR_INVALID_BINARY ERR_GENERAL-7 +#define ERR_INVALID_HANDLE ERR_GENERAL-8 +#define ERR_NO_MORE_HANDLES ERR_GENERAL-9 +#define ERR_UNIMPLEMENTED ENOSYS +#define ERR_TOO_BIG EDOM +#define ERR_NOT_FOUND ERR_GENERAL-12 +#define ERR_NOT_IMPLEMENTED_YET ERR_GENERAL-13 + +/* Semaphore errors */ +#define ERR_SEM_GENERAL -1024 +#define ERR_SEM_DELETED ERR_SEM_GENERAL-1 +#define ERR_SEM_TIMED_OUT ERR_SEM_GENERAL-2 +#define ERR_SEM_OUT_OF_SLOTS ERR_SEM_GENERAL-3 +#define ERR_SEM_NOT_ACTIVE ERR_SEM_GENERAL-4 +#define ERR_SEM_INTERRUPTED ERR_SEM_GENERAL-5 +#define ERR_SEM_NOT_INTERRUPTABLE ERR_SEM_GENERAL-6 +#define ERR_SEM_NOT_FOUND ERR_SEM_GENERAL-7 + + +/* Tasker errors */ +#define ERR_TASK_GENERAL -2048 +#define ERR_TASK_PROC_DELETED ERR_TASK_GENERAL-1 + +/* VFS errors */ +#define ERR_VFS_GENERAL -3072 +#define ERR_VFS_INVALID_FS ERR_VFS_GENERAL-1 +#define ERR_VFS_NOT_MOUNTPOINT ERR_VFS_GENERAL-2 +#define ERR_VFS_PATH_NOT_FOUND ERR_VFS_GENERAL-3 +#define ERR_VFS_INSUFFICIENT_BUF ENOBUFS +#define ERR_VFS_READONLY_FS EROFS +#define ERR_VFS_ALREADY_EXISTS EEXIST +#define ERR_VFS_FS_BUSY ERR_VFS_GENERAL-7 +#define ERR_VFS_FD_TABLE_FULL ERR_VFS_GENERAL-8 +#define ERR_VFS_CROSS_FS_RENAME ERR_VFS_GENERAL-9 +#define ERR_VFS_DIR_NOT_EMPTY ERR_VFS_GENERAL-10 +#define ERR_VFS_NOT_DIR ENOTDIR +#define ERR_VFS_WRONG_STREAM_TYPE ERR_VFS_GENERAL-12 +#define ERR_VFS_ALREADY_MOUNTPOINT ERR_VFS_GENERAL-13 + +/* VM errors */ +#define ERR_VM_GENERAL -4096 +#define ERR_VM_INVALID_ASPACE ERR_VM_GENERAL-1 +#define ERR_VM_INVALID_REGION ERR_VM_GENERAL-2 +#define ERR_VM_BAD_ADDRESS ERR_VM_GENERAL-3 +#define ERR_VM_PF_FATAL ERR_VM_GENERAL-4 +#define ERR_VM_PF_BAD_ADDRESS ERR_VM_GENERAL-5 +#define ERR_VM_PF_BAD_PERM ERR_VM_GENERAL-6 +#define ERR_VM_PAGE_NOT_PRESENT ERR_VM_GENERAL-7 +#define ERR_VM_NO_REGION_SLOT ERR_VM_GENERAL-8 +#define ERR_VM_WOULD_OVERCOMMIT ERR_VM_GENERAL-9 +#define ERR_VM_BAD_USER_MEMORY ERR_VM_GENERAL-10 + +/* Elf errors */ +#define ERR_ELF_GENERAL -5120 +#define ERR_ELF_RESOLVING_SYMBOL ERR_ELF_GENERAL -1 + +#endif /* _ERRORS_H */ diff --git a/headers/private/kernel/arch/alpha/cpu.h b/headers/private/kernel/arch/alpha/cpu.h new file mode 100644 index 0000000000..ccaaf312b1 --- /dev/null +++ b/headers/private/kernel/arch/alpha/cpu.h @@ -0,0 +1,11 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _ALPHA_CPU_H +#define _ALPHA_CPU_H + +#define PAGE_SIZE 8192 + +#endif + diff --git a/headers/private/kernel/arch/alpha/kernel.h b/headers/private/kernel/arch/alpha/kernel.h new file mode 100644 index 0000000000..f71b7ba8d6 --- /dev/null +++ b/headers/private/kernel/arch/alpha/kernel.h @@ -0,0 +1,15 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _ALPHA_KERNEL_H +#define _ALPHA_KERNEL_H + +// memory layout +#define KERNEL_BASE 0x80000000 +#define KERNEL_SIZE 0x80000000 + +#define USER_BASE 0x00000000 +#define USER_SIZE 0x80000000 + +#endif diff --git a/headers/private/kernel/arch/alpha/ktypes.h b/headers/private/kernel/arch/alpha/ktypes.h new file mode 100644 index 0000000000..96ae4368c2 --- /dev/null +++ b/headers/private/kernel/arch/alpha/ktypes.h @@ -0,0 +1,11 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _ALPHA_KTYPES_H +#define _ALPHA_KTYPES_H + +typedef unsigned long addr; + +#endif + diff --git a/headers/private/kernel/arch/alpha/stage2.h b/headers/private/kernel/arch/alpha/stage2.h new file mode 100644 index 0000000000..bfaf9dd262 --- /dev/null +++ b/headers/private/kernel/arch/alpha/stage2.h @@ -0,0 +1,41 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _STAGE2_H +#define _STAGE2_H + +#include + +// must match SMP_MAX_CPUS in arch_smp.h +#define MAX_BOOT_CPUS 1 + +#define MAX_PHYS_MEM_ADDR_RANGE 4 +#define MAX_VIRT_ALLOC_ADDR_RANGE 4 +#define MAX_PHYS_ALLOC_ADDR_RANGE 4 + +typedef struct { + unsigned int start; + unsigned int size; +} addr_range; + +// kernel args +typedef struct { + unsigned int cons_line; + char *str; + addr_range bootdir_addr; + addr_range kernel_seg0_addr; + addr_range kernel_seg1_addr; + unsigned int num_phys_mem_ranges; + addr_range phys_mem_range[MAX_PHYS_MEM_ADDR_RANGE]; + unsigned int num_phys_alloc_ranges; + addr_range phys_alloc_range[MAX_PHYS_ALLOC_ADDR_RANGE]; + unsigned int num_virt_alloc_ranges; + addr_range virt_alloc_range[MAX_VIRT_ALLOC_ADDR_RANGE]; + unsigned int num_cpus; + addr_range cpu_kstack[MAX_BOOT_CPUS]; + // architecture specific +} kernel_args; + +#endif + diff --git a/headers/private/kernel/arch/alpha/thread_struct.h b/headers/private/kernel/arch/alpha/thread_struct.h new file mode 100644 index 0000000000..088c752ab0 --- /dev/null +++ b/headers/private/kernel/arch/alpha/thread_struct.h @@ -0,0 +1,18 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _ALPHA_THREAD_STRUCT_H +#define _ALPHA_THREAD_STRUCT_H + +// architecture specific thread info +struct arch_thread { + unsigned int *sp; +}; + +struct arch_proc { + int foo; +}; + +#endif + diff --git a/headers/private/kernel/arch/alpha/va-alpha.h b/headers/private/kernel/arch/alpha/va-alpha.h new file mode 100644 index 0000000000..1ca91a89ad --- /dev/null +++ b/headers/private/kernel/arch/alpha/va-alpha.h @@ -0,0 +1,129 @@ +/* GNU C varargs and stdargs support for the DEC Alpha. */ + +/* Note: We must use the name __builtin_savregs. GCC attaches special + significance to that name. In particular, regardless of where in a + function __builtin_saveregs is called, GCC moves the call up to the + very start of the function. */ + +/* Define __gnuc_va_list. */ + +#ifndef __GNUC_VA_LIST +#define __GNUC_VA_LIST + +/* In VMS, __gnuc_va_list is simply char *; on OSF, it's a structure. */ + +#ifdef __VMS__ +typedef char *__gnuc_va_list; +#else + +typedef struct { + char *__base; /* Pointer to first integer register. */ + int __offset; /* Byte offset of args so far. */ +} __gnuc_va_list; +#endif + +#endif /* __GNUC_VA_LIST */ + +/* If this is for internal libc use, don't define anything but + __gnuc_va_list. */ + +#if !defined(__GNUC_VA_LIST_1) && (defined (_STDARG_H) || defined (_VARARGS_H)) +#define __GNUC_VA_LIST_1 + +#define _VA_LIST +#define _VA_LIST_ + +typedef __gnuc_va_list va_list; + +#if !defined(_STDARG_H) + +/* varargs support */ +#define va_alist __builtin_va_alist +#define va_dcl int __builtin_va_alist;... +#ifdef __VMS__ +#define va_start(pvar) ((pvar) = __builtin_saveregs ()) +#else +#define va_start(pvar) ((pvar) = * (__gnuc_va_list *) __builtin_saveregs ()) +#endif + +#else /* STDARG.H */ + +/* ANSI alternative. */ + +/* Call __builtin_next_arg even though we aren't using its value, so that + we can verify that firstarg is correct. */ + +#ifdef __VMS__ +#define va_start(pvar, firstarg) \ + (__builtin_next_arg (firstarg), \ + (pvar) = __builtin_saveregs ()) +#else +#define va_start(pvar, firstarg) \ + (__builtin_next_arg (firstarg), \ + (pvar) = *(__gnuc_va_list *) __builtin_saveregs ()) +#endif + +#endif /* _STDARG_H */ + +#define va_end(__va) ((void) 0) + +/* Values returned by __builtin_classify_type. */ + +enum { + __no_type_class = -1, + __void_type_class, + __integer_type_class, + __char_type_class, + __enumeral_type_class, + __boolean_type_class, + __pointer_type_class, + __reference_type_class, + __offset_type_class, + __real_type_class, + __complex_type_class, + __function_type_class, + __method_type_class, + __record_type_class, + __union_type_class, + __array_type_class, + __string_type_class, + __set_type_class, + __file_type_class, + __lang_type_class +}; + +/* Note that parameters are always aligned at least to a word boundary + (when passed) regardless of what GCC's __alignof__ operator says. */ + +/* Avoid errors if compiling GCC v2 with GCC v1. */ +#if __GNUC__ == 1 +#define __extension__ +#endif + +/* Get the size of a type in bytes, rounded up to an integral number + of words. */ + +#define __va_tsize(__type) \ + (((sizeof (__type) + __extension__ sizeof (long long) - 1) \ + / __extension__ sizeof (long long)) * __extension__ sizeof (long long)) + +#ifdef __VMS__ +#define va_arg(__va, __type) \ +(*(((__va) += __va_tsize (__type)), \ + (__type *)(void *)((__va) - __va_tsize (__type)))) + +#else + +#define va_arg(__va, __type) \ +(*(((__va).__offset += __va_tsize (__type)), \ + (__type *)(void *)((__va).__base + (__va).__offset \ + - (((__builtin_classify_type (* (__type *) 0) \ + == __real_type_class) && (__va).__offset <= (6 * 8)) \ + ? (6 * 8) + 8 : __va_tsize (__type))))) +#endif + +/* Copy __gnuc_va_list into another variable of this type. */ +#define __va_copy(dest, src) (dest) = (src) + +#endif /* __GNUC_VA_LIST_1 */ + diff --git a/headers/private/kernel/arch/cpu.h b/headers/private/kernel/arch/cpu.h new file mode 100644 index 0000000000..a1eceef7a6 --- /dev/null +++ b/headers/private/kernel/arch/cpu.h @@ -0,0 +1,47 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _KERNEL_ARCH_CPU_H +#define _KERNEL_ARCH_CPU_H + +#include +#include +#include + +#define PAGE_ALIGN(x) (((x) + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1)) + +#ifdef __cplusplus +extern "C" { +#endif + +/* +int atomic_add(volatile int *val, int incr); +int atomic_and(volatile int *val, int incr); +int atomic_or(volatile int *val, int incr); +int atomic_set(volatile int *val, int set_to); +int test_and_set(int *val, int set_to, int test_val); +*/ + +bigtime_t system_time(void); +int arch_cpu_preboot_init(kernel_args *ka); +int arch_cpu_init(kernel_args *ka); +int arch_cpu_init2(kernel_args *ka); +void reboot(void); +#ifdef __cplusplus +} +#endif + +void arch_cpu_invalidate_TLB_range(addr start, addr end); +void arch_cpu_invalidate_TLB_list(addr pages[], int num_pages); +void arch_cpu_global_TLB_invalidate(void); + +int arch_cpu_user_memcpy(void *to, const void *from, size_t size, addr *fault_handler); +int arch_cpu_user_strcpy(char *to, const char *from, addr *fault_handler); +int arch_cpu_user_strncpy(char *to, const char *from, size_t size, addr *fault_handler); +int arch_cpu_user_memset(void *s, char c, size_t count, addr *fault_handler); + +#include + +#endif /* _KERNEL_ARCH_CPU_H */ + diff --git a/headers/private/kernel/arch/dbg_console.h b/headers/private/kernel/arch/dbg_console.h new file mode 100644 index 0000000000..fa0480df49 --- /dev/null +++ b/headers/private/kernel/arch/dbg_console.h @@ -0,0 +1,16 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _NEWOS_KERNEL_ARCH_DBG_CONSOLE +#define _NEWOS_KERNEL_ARCH_DBG_CONSOLE + +#include + +char arch_dbg_con_read(void); +char arch_dbg_con_putch(char c); +void arch_dbg_con_puts(const char *s); +int arch_dbg_con_init(kernel_args *ka); + +#endif + diff --git a/headers/private/kernel/arch/debug.h b/headers/private/kernel/arch/debug.h new file mode 100644 index 0000000000..b3abd64286 --- /dev/null +++ b/headers/private/kernel/arch/debug.h @@ -0,0 +1,9 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _NEWOS_KERNEL_ARCH_DEBUG +#define _NEWOS_KERNEL_ARCH_DEBUG + +#endif + diff --git a/headers/private/kernel/arch/faults.h b/headers/private/kernel/arch/faults.h new file mode 100644 index 0000000000..3356a0b53b --- /dev/null +++ b/headers/private/kernel/arch/faults.h @@ -0,0 +1,14 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _NEWOS_KERNEL_ARCH_FAULTS +#define _NEWOS_KERNEL_ARCH_FAULTS + +#include + +int faults_init(kernel_args *ka); +int arch_faults_init(kernel_args *ka); + +#endif + diff --git a/headers/private/kernel/arch/int.h b/headers/private/kernel/arch/int.h new file mode 100644 index 0000000000..21ab56d9ae --- /dev/null +++ b/headers/private/kernel/arch/int.h @@ -0,0 +1,22 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _NEWOS_KERNEL_ARCH_INT_H +#define _NEWOS_KERNEL_ARCH_INT_H + +#include +#include + +int arch_int_init(kernel_args *ka); +int arch_int_init2(kernel_args *ka); + +void arch_int_enable_interrupts(void); +int arch_int_disable_interrupts(void); +void arch_int_restore_interrupts(int oldstate); +void arch_int_enable_io_interrupt(int irq); +void arch_int_disable_io_interrupt(int irq); +bool arch_int_is_interrupts_enabled(void); + +#endif + diff --git a/headers/private/kernel/arch/ppc/cpu.h b/headers/private/kernel/arch/ppc/cpu.h new file mode 100644 index 0000000000..7724f24f8b --- /dev/null +++ b/headers/private/kernel/arch/ppc/cpu.h @@ -0,0 +1,11 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _PPC_CPU_H +#define _PPC_CPU_H + +#define PAGE_SIZE 4096 + +#endif + diff --git a/headers/private/kernel/arch/ppc/kernel.h b/headers/private/kernel/arch/ppc/kernel.h new file mode 100644 index 0000000000..61942bf0f6 --- /dev/null +++ b/headers/private/kernel/arch/ppc/kernel.h @@ -0,0 +1,28 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _PPC_KERNEL_H +#define _PPC_KERNEL_H + +// memory layout +#define KERNEL_BASE 0x80000000 +#define KERNEL_SIZE 0x80000000 +#define KERNEL_TOP (KERNEL_BASE + (KERNEL_SIZE - 1)) + +/* +** User space layout is a little special: +** The user space does not completely cover the space not covered by the kernel. +** This is accomplished by starting user space at 1Mb and running to 64kb short of kernel space. +** The lower 1Mb reserved spot makes it easy to find null pointer references and guarantees a +** region wont be placed there. The 64kb region assures a user space thread cannot pass +** a buffer into the kernel as part of a syscall that would cross into kernel space. +*/ +#define USER_BASE 0x100000 +#define USER_SIZE (0x80000000 - (0x10000 + 0x100000)) +#define USER_TOP (USER_BASE + USER_SIZE) + +#define USER_STACK_REGION 0x70000000 +#define USER_STACK_REGION_SIZE (USER_BASE + (USER_SIZE - USER_STACK_REGION)) + +#endif diff --git a/headers/private/kernel/arch/ppc/ktypes.h b/headers/private/kernel/arch/ppc/ktypes.h new file mode 100644 index 0000000000..a97bad8fec --- /dev/null +++ b/headers/private/kernel/arch/ppc/ktypes.h @@ -0,0 +1,11 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _PPC_KTYPES_H +#define _PPC_KTYPES_H + +typedef unsigned long addr; + +#endif + diff --git a/headers/private/kernel/arch/ppc/stage2.h b/headers/private/kernel/arch/ppc/stage2.h new file mode 100644 index 0000000000..c8827d6114 --- /dev/null +++ b/headers/private/kernel/arch/ppc/stage2.h @@ -0,0 +1,19 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _PPC_STAGE2_H +#define _PPC_STAGE2_H + +#include + +// kernel args +typedef struct { + // architecture specific + addr_range page_table; // maps where the page table is located, in physical memory + addr_range framebuffer; // maps where the framebuffer is located, in physical memory + int screen_x, screen_y, screen_depth; +} arch_kernel_args; + +#endif + diff --git a/headers/private/kernel/arch/ppc/stage2_priv.h b/headers/private/kernel/arch/ppc/stage2_priv.h new file mode 100644 index 0000000000..605ad5a733 --- /dev/null +++ b/headers/private/kernel/arch/ppc/stage2_priv.h @@ -0,0 +1,43 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _STAGE2_PRIV_H +#define _STAGE2_PRIV_H + +#define LOAD_ADDR 0x100000 +#define BOOTDIR_ADDR 0x101000 + +int s2_text_init(); +void s2_change_framebuffer_addr(unsigned int address); +void putchar(char c); +void puts(char *str); +int printf(const char *fmt, ...); + +int of_init(void *of_entry); +int of_open(const char *node_name); +int of_finddevice(const char *dev); +int of_instance_to_package(int in_handle); +int of_getprop(int handle, const char *prop, void *buf, int buf_len); +int of_setprop(int handle, const char *prop, const void *buf, int buf_len); +int of_read(int handle, void *buf, int buf_len); +int of_write(int handle, void *buf, int buf_len); +int of_seek(int handle, long long pos); + +int s2_mmu_init(); +void mmu_map_page(unsigned int vsid, unsigned long pa, unsigned long va);; +void syncicache(void *address, int len); + +void s2_faults_init(kernel_args *ka); + +void getibats(int bats[8]); +void setibats(int bats[8]); +void getdbats(int bats[8]); +void setdbats(int bats[8]); +unsigned int *getsdr1(); +void setsdr1(unsigned int sdr); +unsigned int getsr(int sr); +unsigned int getmsr(); +void setmsr(unsigned int msr); + +#endif diff --git a/headers/private/kernel/arch/ppc/thread_struct.h b/headers/private/kernel/arch/ppc/thread_struct.h new file mode 100644 index 0000000000..acb398fe1e --- /dev/null +++ b/headers/private/kernel/arch/ppc/thread_struct.h @@ -0,0 +1,18 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _PPC_THREAD_STRUCT_H +#define _PPC_THREAD_STRUCT_H + +// architecture specific thread info +struct arch_thread { + // stack pointer +}; + +struct arch_proc { + // nothing here +}; + +#endif + diff --git a/headers/private/kernel/arch/ppc/types.h b/headers/private/kernel/arch/ppc/types.h new file mode 100644 index 0000000000..5ee0d1661b --- /dev/null +++ b/headers/private/kernel/arch/ppc/types.h @@ -0,0 +1,18 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _PPC_TYPES_H +#define _PPC_TYPES_H + +typedef unsigned long long uint64; +typedef long long int64; +typedef unsigned int uint32; +typedef int int32; +typedef unsigned short uint16; +typedef short int16; +typedef unsigned char uint8; +typedef char int8; + +#endif + diff --git a/headers/private/kernel/arch/sh4/cpu.h b/headers/private/kernel/arch/sh4/cpu.h new file mode 100644 index 0000000000..b42e34653f --- /dev/null +++ b/headers/private/kernel/arch/sh4/cpu.h @@ -0,0 +1,25 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _NEWOS_KERNEL_ARCH_SH4_CPU_H +#define _NEWOS_KERNEL_ARCH_SH4_CPU_H + +#include +#include + +unsigned int get_fpscr(); +unsigned int get_sr(); +void sh4_context_switch(unsigned int **old_sp, unsigned int *new_sp); +void sh4_function_caller(); +void sh4_set_kstack(addr kstack); +void sh4_enter_uspace(addr entry, void *args, addr ustack_top); +void sh4_set_user_pgdir(addr pgdir); +void sh4_invl_page(addr va); +void sh4_switch_stack_and_call(addr stack, void (*func)(void *), void *arg); +#define PAGE_SIZE 4096 + +#define _BIG_ENDIAN 0 +#define _LITTLE_ENDIAN 1 +#endif + diff --git a/headers/private/kernel/arch/sh4/defs.h b/headers/private/kernel/arch/sh4/defs.h new file mode 100755 index 0000000000..b1e6456aa7 --- /dev/null +++ b/headers/private/kernel/arch/sh4/defs.h @@ -0,0 +1,36 @@ +/* $Id: defs.h,v 1.1 2002/07/09 12:24:34 ejakowatz Exp $ +** +** Copyright 2001 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _DEFS_H +#define _DEFS_H + +typedef unsigned char u1; +typedef unsigned short u2; +typedef unsigned int u4; + +#endif diff --git a/headers/private/kernel/arch/sh4/kernel.h b/headers/private/kernel/arch/sh4/kernel.h new file mode 100644 index 0000000000..a6d95b83df --- /dev/null +++ b/headers/private/kernel/arch/sh4/kernel.h @@ -0,0 +1,30 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _NEWOS_KERNEL_ARCH_SH4_KERNEL_H +#define _NEWOS_KERNEL_ARCH_SH4_KERNEL_H + +#include + +// memory layout +#define KERNEL_BASE P3_AREA +#define KERNEL_SIZE P3_AREA_LEN +#define KERNEL_TOP (KERNEL_BASE + (KERNEL_SIZE - 1)) + +/* +** User space layout is a little special: +** The user space does not completely cover the space not covered by the kernel. +** This is accomplished by starting user space at 1Mb and running to 64kb short of kernel space. +** The lower 1Mb reserved spot makes it easy to find null pointer references and guarantees a +** region wont be placed there. The 64kb region assures a user space thread cannot pass +** a buffer into the kernel as part of a syscall that would cross into kernel space. +*/ +#define USER_BASE (U0_AREA + 0x100000) +#define USER_SIZE (U0_AREA_LEN - (0x10000 + 0x100000)) +#define USER_TOP (USER_BASE + USER_SIZE) + +#define USER_STACK_REGION (USER_BASE + USER_SIZE - USER_STACK_REGION_SIZE) +#define USER_STACK_REGION_SIZE 0x10000000 + +#endif diff --git a/headers/private/kernel/arch/sh4/ktypes.h b/headers/private/kernel/arch/sh4/ktypes.h new file mode 100644 index 0000000000..84099ae34b --- /dev/null +++ b/headers/private/kernel/arch/sh4/ktypes.h @@ -0,0 +1,11 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _NEWOS_KERNEL_ARCH_SH4_KTYPES_H +#define _NEWOS_KERNEL_ARCH_SH4_KTYPES_H + +typedef unsigned long addr; + +#endif + diff --git a/headers/private/kernel/arch/sh4/mmu.h b/headers/private/kernel/arch/sh4/mmu.h new file mode 100644 index 0000000000..2dadff7994 --- /dev/null +++ b/headers/private/kernel/arch/sh4/mmu.h @@ -0,0 +1,14 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _MMU_H +#define _MMU_H + +#include + +void mmu_init(kernel_args *ka, unsigned int *next_paddr); +void mmu_map_page(unsigned int vaddr, unsigned int paddr); + +#endif + diff --git a/headers/private/kernel/arch/sh4/rtl8139_priv.h b/headers/private/kernel/arch/sh4/rtl8139_priv.h new file mode 100755 index 0000000000..ce42583381 --- /dev/null +++ b/headers/private/kernel/arch/sh4/rtl8139_priv.h @@ -0,0 +1,13 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _RTL8139_PRIV_H +#define _RTL8139_PRIV_H + +int rtl8139_detect(); +int rtl8139_init(); +void rtl8139_xmit(const char *ptr, int len); +int rtl8139_rx(char *buf, int buf_len); + +#endif diff --git a/headers/private/kernel/arch/sh4/rtl8139c.h b/headers/private/kernel/arch/sh4/rtl8139c.h new file mode 100755 index 0000000000..57735699a5 --- /dev/null +++ b/headers/private/kernel/arch/sh4/rtl8139c.h @@ -0,0 +1,84 @@ +/* +** +** Naive RealTek 8139C driver for the DC Broadband Adapter. Some +** assistance on names of things from the NetBSD-DC sources. +** +** (c)2001 Dan Potter +** License: X11 +** +*/ + +#ifndef _RTL_8139C_H +#define _RTL_8139C_H + +/* RTL8139C register definitions */ +#define RT_IDR0 0x00 /* Mac address */ +#define RT_MAR0 0x08 /* Multicast filter */ +#define RT_TXSTATUS0 0x10 /* Transmit status (4 32bit regs) */ +#define RT_TXADDR0 0x20 /* Tx descriptors (also 4 32bit) */ +#define RT_RXBUF 0x30 /* Receive buffer start address */ +#define RT_RXEARLYCNT 0x34 /* Early Rx byte count */ +#define RT_RXEARLYSTATUS 0x36 /* Early Rx status */ +#define RT_CHIPCMD 0x37 /* Command register */ +#define RT_RXBUFTAIL 0x38 /* Current address of packet read (queue tail) */ +#define RT_RXBUFHEAD 0x3A /* Current buffer address (queue head) */ +#define RT_INTRMASK 0x3C /* Interrupt mask */ +#define RT_INTRSTATUS 0x3E /* Interrupt status */ +#define RT_TXCONFIG 0x40 /* Tx config */ +#define RT_RXCONFIG 0x44 /* Rx config */ +#define RT_TIMER 0x48 /* A general purpose counter */ +#define RT_RXMISSED 0x4C /* 24 bits valid, write clears */ +#define RT_CFG9346 0x50 /* 93C46 command register */ +#define RT_CONFIG0 0x51 /* Configuration reg 0 */ +#define RT_CONFIG1 0x52 /* Configuration reg 1 */ +#define RT_TIMERINT 0x54 /* Timer interrupt register (32 bits) */ +#define RT_MEDIASTATUS 0x58 /* Media status register */ +#define RT_CONFIG3 0x59 /* Config register 3 */ +#define RT_CONFIG4 0x5A /* Config register 4 */ +#define RT_MULTIINTR 0x5C /* Multiple interrupt select */ +#define RT_MII_TSAD 0x60 /* Transmit status of all descriptors (16 bits) */ +#define RT_MII_BMCR 0x62 /* Basic Mode Control Register (16 bits) */ +#define RT_MII_BMSR 0x64 /* Basic Mode Status Register (16 bits) */ +#define RT_AS_ADVERT 0x66 /* Auto-negotiation advertisement reg (16 bits) */ +#define RT_AS_LPAR 0x68 /* Auto-negotiation link partner reg (16 bits) */ +#define RT_AS_EXPANSION 0x6A /* Auto-negotiation expansion reg (16 bits) */ + +/* RTL8193C command bits; or these together and write teh resulting value + into CHIPCMD to execute it. */ +#define RT_CMD_RESET 0x10 +#define RT_CMD_RX_ENABLE 0x08 +#define RT_CMD_TX_ENABLE 0x04 +#define RT_CMD_RX_BUF_EMPTY 0x01 + +/* RTL8139C interrupt status bits */ +#define RT_INT_PCIERR 0x8000 /* PCI Bus error */ +#define RT_INT_TIMEOUT 0x4000 /* Set when TCTR reaches TimerInt value */ +#define RT_INT_RXFIFO_OVERFLOW 0x0040 /* Rx FIFO overflow */ +#define RT_INT_RXFIFO_UNDERRUN 0x0020 /* Packet underrun / link change */ +#define RT_INT_RXBUF_OVERFLOW 0x0010 /* Rx BUFFER overflow */ +#define RT_INT_TX_ERR 0x0008 +#define RT_INT_TX_OK 0x0004 +#define RT_INT_RX_ERR 0x0002 +#define RT_INT_RX_OK 0x0001 + +/* RTL8139C transmit status bits */ +#define RT_TX_CARRIER_LOST 0x80000000 /* Carrier sense lost */ +#define RT_TX_ABORTED 0x40000000 /* Transmission aborted */ +#define RT_TX_OUT_OF_WINDOW 0x20000000 /* Out of window collision */ +#define RT_TX_STATUS_OK 0x00008000 /* Status ok: a good packet was transmitted */ +#define RT_TX_UNDERRUN 0x00004000 /* Transmit FIFO underrun */ +#define RT_TX_HOST_OWNS 0x00002000 /* Set to 1 when DMA operation is completed */ +#define RT_TX_SIZE_MASK 0x00001fff /* Descriptor size mask */ + +/* RTL8139C receive status bits */ +#define RT_RX_MULTICAST 0x00008000 /* Multicast packet */ +#define RT_RX_PAM 0x00004000 /* Physical address matched */ +#define RT_RX_BROADCAST 0x00002000 /* Broadcast address matched */ +#define RT_RX_BAD_SYMBOL 0x00000020 /* Invalid symbol in 100TX packet */ +#define RT_RX_RUNT 0x00000010 /* Packet size is <64 bytes */ +#define RT_RX_TOO_LONG 0x00000008 /* Packet size is >4K bytes */ +#define RT_RX_CRC_ERR 0x00000004 /* CRC error */ +#define RT_RX_FRAME_ALIGN 0x00000002 /* Frame alignment error */ +#define RT_RX_STATUS_OK 0x00000001 /* Status ok: a good packet was received */ + +#endif diff --git a/headers/private/kernel/arch/sh4/serial.h b/headers/private/kernel/arch/sh4/serial.h new file mode 100644 index 0000000000..c724c31483 --- /dev/null +++ b/headers/private/kernel/arch/sh4/serial.h @@ -0,0 +1,14 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _SERIAL_H +#define _SERIAL_H + +int dprintf(const char *fmt, ...); +int serial_init(); +char serial_putch(const char c); +void serial_puts(const char *str); + +#endif + diff --git a/headers/private/kernel/arch/sh4/sh4.h b/headers/private/kernel/arch/sh4/sh4.h new file mode 100644 index 0000000000..b3c32443c2 --- /dev/null +++ b/headers/private/kernel/arch/sh4/sh4.h @@ -0,0 +1,152 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _SH4_H +#define _SH4_H + +#define P4_AREA 0xe0000000 +#define P4_AREA_LEN 0x20000000 +#define P3_AREA 0xc0000000 +#define P3_AREA_LEN (P4_AREA - P3_AREA) +#define P2_AREA 0xa0000000 +#define P2_AREA_LEN (P3_AREA - P2_AREA) +#define P1_AREA 0x80000000 +#define P1_AREA_LEN (P2_AREA - P1_AREA) +#define P0_AREA 0 +#define P0_AREA_LEN (P1_AREA - P0_AREA) +#define U0_AREA P0_AREA +#define U0_AREA_LEN P0_AREA_LEN + +#define PHYS_MEM_START 0x0c000000 +#define PHYS_MEM_LEN 0x01000000 +#define PHYS_MEM_END (PHYS_MEM_START + PHYS_MEM_LEN) +#define P1_PHYS_MEM_START (P1_AREA + PHYS_MEM_START) +#define P1_PHYS_MEM_LEN PHYS_MEM_LEN +#define P1_PHYS_MEM_END (P1_PHYS_MEM_START + P1_PHYS_MEM_LEN) + +#define PHYS_ADDR_TO_P1(x) (((unsigned int)(x)) + P1_AREA) +#define PHYS_ADDR_TO_P2(x) (((unsigned int)(x)) + P2_AREA) +#define P1_TO_PHYS_ADDR(x) (((unsigned int)(x)) - P1_AREA) + +#define PHYS_ADDR_SIZE (0x1fffffff+1) + +//#define PAGE_SIZE 4096 +#define PAGE_SIZE_1K 0 +#define PAGE_SIZE_4K 1 +#define PAGE_SIZE_64K 2 +#define PAGE_SIZE_1M 3 + +#define PTEH 0xff000000 +#define PTEL 0xff000004 +#define PTEA 0xff000034 +#define TTB 0xff000008 +#define TEA 0xff00000c +#define MMUCR 0xff000010 + +#define UTLB 0xf6000000 +#define UTLB1 0xf7000000 +#define UTLB2 0xf3800000 +#define UTLB_ADDR_SHIFT 0x8 +#define UTLB_COUNT 64 + +struct utlb_addr_array { + unsigned int asid: 8; + unsigned int valid: 1; + unsigned int dirty: 1; + unsigned int vpn: 22; +}; + +struct utlb_data_array_1 { + unsigned int wt: 1; + unsigned int sh: 1; + unsigned int dirty: 1; + unsigned int cacheability: 1; + unsigned int psize0: 1; + unsigned int prot_key: 2; + unsigned int psize1: 1; + unsigned int valid: 1; + unsigned int unused: 1; + unsigned int ppn: 19; + unsigned int unused2: 3; +}; + +struct utlb_data_array_2 { + unsigned int sa: 2; + unsigned int tc: 1; + unsigned int unused: 29; +}; + +struct utlb_data { + struct utlb_addr_array a; + struct utlb_data_array_1 da1; + struct utlb_data_array_2 da2; +}; + +#define ITLB 0xf2000000 +#define ITLB1 0xf3000000 +#define ITLB2 0xf3800000 +#define ITLB_ADDR_SHIFT 0x8 +#define ITLB_COUNT 4 + +struct itlb_addr_array { + unsigned int asid: 8; + unsigned int valid: 1; + unsigned int unused: 1; + unsigned int vpn: 22; +}; + +struct itlb_data_array_1 { + unsigned int unused1: 1; + unsigned int sh: 1; + unsigned int unused2: 1; + unsigned int cacheability: 1; + unsigned int psize0: 1; + unsigned int unused3: 1; + unsigned int prot_key: 1; + unsigned int psize1: 1; + unsigned int valid: 1; + unsigned int unused4: 1; + unsigned int ppn: 19; + unsigned int unused5: 3; +}; + +struct itlb_data_array_2 { + unsigned int sa: 2; + unsigned int tc: 1; + unsigned int unused: 29; +}; + +struct itlb_data { + struct itlb_addr_array a; + struct itlb_data_array_1 da1; + struct itlb_data_array_2 da2; +}; + +// timer stuff +#define TOCR 0xffd80000 +#define TSTR 0xffd80004 +#define TCOR0 0xffd80008 +#define TCNT0 0xffd8000c +#define TCR0 0xffd80010 +#define TCOR1 0xffd80014 +#define TCNT1 0xffd80018 +#define TCR1 0xffd8001c +#define TCOR2 0xffd80020 +#define TCNT2 0xffd80024 +#define TCR2 0xffd80028 +#define TCPR2 0xffd8002c + +// interrupt controller stuff +#define ICR 0xffd00000 +#define IPRA 0xffd00004 +#define IPRB 0xffd00008 +#define IPRC 0xffd0000c + +// cache stuff +#define CCR 0xff00001c +#define QACR0 0xff000038 +#define QACR1 0xff00003c + +#endif + diff --git a/headers/private/kernel/arch/sh4/stage2.h b/headers/private/kernel/arch/sh4/stage2.h new file mode 100644 index 0000000000..20659a8ced --- /dev/null +++ b/headers/private/kernel/arch/sh4/stage2.h @@ -0,0 +1,19 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _SH4_STAGE2_H +#define _SH4_STAGE2_H + +#include + +#include + +// kernel args +typedef struct { + // architecture specific + vcpu_struct *vcpu; +} arch_kernel_args; + +#endif + diff --git a/headers/private/kernel/arch/sh4/thread_struct.h b/headers/private/kernel/arch/sh4/thread_struct.h new file mode 100644 index 0000000000..e36c52cde3 --- /dev/null +++ b/headers/private/kernel/arch/sh4/thread_struct.h @@ -0,0 +1,17 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _NEWOS_KERNEL_ARCH_SH4_THREAD_STRUCT_H +#define _NEWOS_KERNEL_ARCH_SH4_THREAD_STRUCT_H + +// architecture specific thread info +struct arch_thread { + unsigned int *sp; +}; + +struct arch_proc { +}; + +#endif + diff --git a/headers/private/kernel/arch/sh4/types.h b/headers/private/kernel/arch/sh4/types.h new file mode 100644 index 0000000000..95ef7aeffe --- /dev/null +++ b/headers/private/kernel/arch/sh4/types.h @@ -0,0 +1,19 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _SH4_TYPES_H +#define _SH4_TYPES_H + +// XXX is this accurate? +typedef unsigned long long uint64; +typedef long long int64; +typedef unsigned int uint32; +typedef int int32; +typedef unsigned short uint16; +typedef short int16; +typedef unsigned char uint8; +typedef char int8; + +#endif + diff --git a/headers/private/kernel/arch/sh4/va-sh.h b/headers/private/kernel/arch/sh4/va-sh.h new file mode 100644 index 0000000000..729269045d --- /dev/null +++ b/headers/private/kernel/arch/sh4/va-sh.h @@ -0,0 +1,230 @@ +/* The ! __SH3E_VARG case is similar to the default gvarargs.h . */ + +#if (defined (__SH3E__) || defined (__SH4_SINGLE__) || defined (__SH4__) || defined (__SH4_SINGLE_ONLY__)) && ! defined (__HITACHI__) +#define __SH3E_VARG +#endif + +/* Define __gnuc_va_list. */ + +#ifndef __GNUC_VA_LIST +#define __GNUC_VA_LIST + +#ifdef __SH3E_VARG + +typedef long __va_greg; +typedef float __va_freg; + +typedef struct { + __va_greg * __va_next_o; /* next available register */ + __va_greg * __va_next_o_limit; /* past last available register */ + __va_freg * __va_next_fp; /* next available fp register */ + __va_freg * __va_next_fp_limit; /* last available fp register */ + __va_greg * __va_next_stack; /* next extended word on stack */ +} __gnuc_va_list; + +#else /* ! SH3E */ + +typedef void *__gnuc_va_list; + +#endif /* ! SH3E */ + +#endif /* __GNUC_VA_LIST */ + +/* If this is for internal libc use, don't define anything but + __gnuc_va_list. */ +#if defined (_STDARG_H) || defined (_VARARGS_H) + +#ifdef _STDARG_H + +#ifdef __SH3E_VARG + +#define va_start(AP, LASTARG) \ +__extension__ \ + ({ \ + (AP).__va_next_fp = (__va_freg *) __builtin_saveregs (); \ + (AP).__va_next_fp_limit = ((AP).__va_next_fp + \ + (__builtin_args_info (1) < 8 ? 8 - __builtin_args_info (1) : 0)); \ + (AP).__va_next_o = (__va_greg *) (AP).__va_next_fp_limit; \ + (AP).__va_next_o_limit = ((AP).__va_next_o + \ + (__builtin_args_info (0) < 4 ? 4 - __builtin_args_info (0) : 0)); \ + (AP).__va_next_stack = (__va_greg *) __builtin_next_arg (LASTARG); \ + }) + +#else /* ! SH3E */ + +#define va_start(AP, LASTARG) \ + ((AP) = ((__gnuc_va_list) __builtin_next_arg (LASTARG))) + +#endif /* ! SH3E */ + +#else /* _VARARGS_H */ + +#define va_alist __builtin_va_alist +#define va_dcl int __builtin_va_alist;... + +#ifdef __SH3E_VARG + +#define va_start(AP) \ +__extension__ \ + ({ \ + (AP).__va_next_fp = (__va_freg *) __builtin_saveregs (); \ + (AP).__va_next_fp_limit = ((AP).__va_next_fp + \ + (__builtin_args_info (1) < 8 ? 8 - __builtin_args_info (1) : 0)); \ + (AP).__va_next_o = (__va_greg *) (AP).__va_next_fp_limit; \ + (AP).__va_next_o_limit = ((AP).__va_next_o + \ + (__builtin_args_info (0) < 4 ? 4 - __builtin_args_info (0) : 0)); \ + (AP).__va_next_stack \ + = ((__va_greg *) __builtin_next_arg (__builtin_va_alist) \ + - (__builtin_args_info (0) >= 4 || __builtin_args_info (1) >= 8 \ + ? 1 : 0)); \ + }) + +#else /* ! SH3E */ + +#define va_start(AP) ((AP) = (char *) &__builtin_va_alist) + +#endif /* ! SH3E */ + +#endif /* _STDARG */ + +#ifndef va_end +void va_end (__gnuc_va_list); /* Defined in libgcc.a */ + +/* Values returned by __builtin_classify_type. */ + +enum __va_type_classes { + __no_type_class = -1, + __void_type_class, + __integer_type_class, + __char_type_class, + __enumeral_type_class, + __boolean_type_class, + __pointer_type_class, + __reference_type_class, + __offset_type_class, + __real_type_class, + __complex_type_class, + __function_type_class, + __method_type_class, + __record_type_class, + __union_type_class, + __array_type_class, + __string_type_class, + __set_type_class, + __file_type_class, + __lang_type_class +}; + +#endif +#define va_end(pvar) ((void)0) + +#ifdef __LITTLE_ENDIAN__ +#define __LITTLE_ENDIAN_P 1 +#else +#define __LITTLE_ENDIAN_P 0 +#endif + +#define __SCALAR_TYPE(TYPE) \ + ((TYPE) == __integer_type_class \ + || (TYPE) == __char_type_class \ + || (TYPE) == __enumeral_type_class) + +/* RECORD_TYPE args passed using the C calling convention are + passed by invisible reference. ??? RECORD_TYPE args passed + in the stack are made to be word-aligned; for an aggregate that is + not word-aligned, we advance the pointer to the first non-reg slot. */ + + /* When this is a smaller-than-int integer, using + auto-increment in the promoted (SImode) is fastest; + however, there is no way to express that is C. Therefore, + we use an asm. + We want the MEM_IN_STRUCT_P bit set in the emitted RTL, therefore we + use unions even when it would otherwise be unnecessary. */ + +/* gcc has an extension that allows to use a casted lvalue as an lvalue, + But it doesn't work in C++ with -pedantic - even in the presence of + __extension__ . We work around this problem by using a reference type. */ +#ifdef __cplusplus +#define __VA_REF & +#else +#define __VA_REF +#endif + +#define __va_arg_sh1(AP, TYPE) __extension__ \ +({(sizeof (TYPE) == 1 \ + ? ({union {TYPE t; char c;} __t; \ + __asm("" \ + : "=r" (__t.c) \ + : "0" ((((union { int i, j; } *__VA_REF) (AP))++)->i)); \ + __t.t;}) \ + : sizeof (TYPE) == 2 \ + ? ({union {TYPE t; short s;} __t; \ + __asm("" \ + : "=r" (__t.s) \ + : "0" ((((union { int i, j; } *__VA_REF) (AP))++)->i)); \ + __t.t;}) \ + : sizeof (TYPE) >= 4 || __LITTLE_ENDIAN_P \ + ? (((union { TYPE t; int i;} *__VA_REF) (AP))++)->t \ + : ((union {TYPE t;TYPE u;}*) ((char *)++(int *__VA_REF)(AP) - sizeof (TYPE)))->t);}) + +#ifdef __SH3E_VARG + +#define __PASS_AS_FLOAT(TYPE_CLASS,SIZE) \ + (TYPE_CLASS == __real_type_class && SIZE == 4) + +#define __TARGET_SH4_P 0 + +#if defined(__SH4__) || defined(__SH4_SINGLE__) +#undef __PASS_AS_FLOAT +#define __PASS_AS_FLOAT(TYPE_CLASS,SIZE) \ + ((TYPE_CLASS == __real_type_class && SIZE <= 8) \ + || (TYPE_CLASS == __complex_type_class && SIZE <= 16)) +#undef __TARGET_SH4_P +#define __TARGET_SH4_P 1 +#endif + +#define va_arg(pvar,TYPE) \ +__extension__ \ +({int __type = __builtin_classify_type (* (TYPE *) 0); \ + void * __result_p; \ + if (__PASS_AS_FLOAT (__type, sizeof(TYPE))) \ + { \ + if ((pvar).__va_next_fp < (pvar).__va_next_fp_limit) \ + { \ + if (((__type == __real_type_class && sizeof (TYPE) > 4)\ + || sizeof (TYPE) > 8) \ + && (((int) (pvar).__va_next_fp ^ (int) (pvar).__va_next_fp_limit)\ + & 4)) \ + (pvar).__va_next_fp++; \ + __result_p = &(pvar).__va_next_fp; \ + } \ + else \ + __result_p = &(pvar).__va_next_stack; \ + } \ + else \ + { \ + if ((pvar).__va_next_o + ((sizeof (TYPE) + 3) / 4) \ + <= (pvar).__va_next_o_limit) \ + __result_p = &(pvar).__va_next_o; \ + else \ + { \ + if (sizeof (TYPE) > 4) \ + if (! __TARGET_SH4_P) \ + (pvar).__va_next_o = (pvar).__va_next_o_limit; \ + \ + __result_p = &(pvar).__va_next_stack; \ + } \ + } \ + __va_arg_sh1(*(void **)__result_p, TYPE);}) + +#else /* ! SH3E */ + +#define va_arg(AP, TYPE) __va_arg_sh1((AP), TYPE) + +#endif /* SH3E */ + +/* Copy __gnuc_va_list into another variable of this type. */ +#define __va_copy(dest, src) ((dest) = (src)) + +#endif /* defined (_STDARG_H) || defined (_VARARGS_H) */ + diff --git a/headers/private/kernel/arch/sh4/vcpu.h b/headers/private/kernel/arch/sh4/vcpu.h new file mode 100644 index 0000000000..92dd611297 --- /dev/null +++ b/headers/private/kernel/arch/sh4/vcpu.h @@ -0,0 +1,103 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _VCPU_H +#define _VCPU_H + +#include + +// layout of the iframe is defined in boot/sh4/vcpu.S +struct iframe { + unsigned int page_fault_addr; + unsigned int excode; + unsigned int spc; + unsigned int ssr; + unsigned int sgr; + unsigned int pr; + unsigned int macl; + unsigned int mach; + unsigned int gbr; + unsigned int fpscr; + unsigned int fpul; + + float fr15_1; + float fr14_1; + float fr13_1; + float fr12_1; + float fr11_1; + float fr10_1; + float fr9_1; + float fr8_1; + float fr7_1; + float fr6_1; + float fr5_1; + float fr4_1; + float fr3_1; + float fr2_1; + float fr1_1; + float fr0_1; + + float fr15_0; + float fr14_0; + float fr13_0; + float fr12_0; + float fr11_0; + float fr10_0; + float fr9_0; + float fr8_0; + float fr7_0; + float fr6_0; + float fr5_0; + float fr4_0; + float fr3_0; + float fr2_0; + float fr1_0; + float fr0_0; + + unsigned int r7; + unsigned int r6; + unsigned int r5; + unsigned int r4; + unsigned int r3; + unsigned int r2; + unsigned int r1; + unsigned int r0; + unsigned int r14; + unsigned int r13; + unsigned int r12; + unsigned int r11; + unsigned int r10; + unsigned int r9; + unsigned int r8; +}; + +// page table structures +struct pdent { + unsigned int v:1; + unsigned int unused0:11; + unsigned int ppn:17; + unsigned int unused1:3; +}; + +struct ptent { + unsigned int v:1; + unsigned int d:1; + unsigned int sh:1; + unsigned int sz:2; + unsigned int c:1; + unsigned int tlb_ent:6; + unsigned int ppn:17; + unsigned int pr:2; + unsigned int wt:1; +}; + +// soft faults +#define EXCEPTION_PAGE_FAULT_READ 0xfe +#define EXCEPTION_PAGE_FAULT_WRITE 0xff + +// can only be used in stage2 +int vcpu_init(kernel_args *ka); + +#endif + diff --git a/headers/private/kernel/arch/sh4/vcpu_struct.h b/headers/private/kernel/arch/sh4/vcpu_struct.h new file mode 100644 index 0000000000..e0f425e9cd --- /dev/null +++ b/headers/private/kernel/arch/sh4/vcpu_struct.h @@ -0,0 +1,22 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _VCPU_STRUCT_H +#define _VCPU_STRUCT_H + +struct vector { + int (*func)(void *iframe); +}; + +typedef struct { + unsigned int *kernel_pgdir; + unsigned int *user_pgdir; + unsigned int kernel_asid; + unsigned int user_asid; + unsigned int *kstack; + struct vector vt[256]; +} vcpu_struct; + +#endif + diff --git a/headers/private/kernel/arch/smp.h b/headers/private/kernel/arch/smp.h new file mode 100644 index 0000000000..995a1f9f42 --- /dev/null +++ b/headers/private/kernel/arch/smp.h @@ -0,0 +1,19 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _NEWOS_KERNEL_ARCH_SMP_H +#define _NEWOS_KERNEL_ARCH_SMP_H + +#include +#include + +// must match MAX_BOOT_CPUS in stage2.h +#define SMP_MAX_CPUS MAX_BOOT_CPUS + +int arch_smp_init(kernel_args *ka); +void arch_smp_send_ici(int target_cpu); +void arch_smp_send_broadcast_ici(void); + +#endif + diff --git a/headers/private/kernel/arch/sparc/DEFS.h b/headers/private/kernel/arch/sparc/DEFS.h new file mode 100644 index 0000000000..f0b72ae3a8 --- /dev/null +++ b/headers/private/kernel/arch/sparc/DEFS.h @@ -0,0 +1,44 @@ +/* $OpenBSD: DEFS.h,v 1.2 1997/11/07 15:57:30 niklas Exp $ */ +/* $NetBSD: DEFS.h,v 1.2 1994/10/26 06:39:51 cgd Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)DEFS.h 8.1 (Berkeley) 6/4/93 + */ + +#include + diff --git a/headers/private/kernel/arch/sparc/cpu.h b/headers/private/kernel/arch/sparc/cpu.h new file mode 100644 index 0000000000..e1ef9e31d1 --- /dev/null +++ b/headers/private/kernel/arch/sparc/cpu.h @@ -0,0 +1,11 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _SPARC64_CPU_H +#define _SPARC64_CPU_H + +#define PAGE_SIZE 8192 + +#endif + diff --git a/headers/private/kernel/arch/sparc/kernel.h b/headers/private/kernel/arch/sparc/kernel.h new file mode 100644 index 0000000000..13d6aa530e --- /dev/null +++ b/headers/private/kernel/arch/sparc/kernel.h @@ -0,0 +1,15 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _SPARC64_KERNEL_H +#define _SPARC64_KERNEL_H + +// memory layout +#define KERNEL_BASE 0x80000000 +#define KERNEL_SIZE 0x80000000 + +#define USER_BASE 0x00000000 +#define USER_SIZE 0x80000000 + +#endif diff --git a/headers/private/kernel/arch/sparc/ktypes.h b/headers/private/kernel/arch/sparc/ktypes.h new file mode 100644 index 0000000000..c2736a57ff --- /dev/null +++ b/headers/private/kernel/arch/sparc/ktypes.h @@ -0,0 +1,11 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _SPARC64_KTYPES_H +#define _SPARC64_KTYPES_H + +typedef unsigned long addr; + +#endif + diff --git a/headers/private/kernel/arch/sparc/promdev.h b/headers/private/kernel/arch/sparc/promdev.h new file mode 100644 index 0000000000..afb0f6a359 --- /dev/null +++ b/headers/private/kernel/arch/sparc/promdev.h @@ -0,0 +1,86 @@ +/* $OpenBSD: promdev.h,v 1.1 1997/09/17 10:46:19 downsj Exp $ */ +/* $NetBSD: promdev.h,v 1.3 1995/09/18 21:31:50 pk Exp $ */ + +/* + * Copyright (c) 1993 Paul Kranenburg + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Paul Kranenburg. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +struct promdata { + int fd; /* Openboot descriptor */ + struct saioreq *si; /* Oldmon IO request */ + int devtype; /* Kind of device we're booting from */ +#define DT_BLOCK 1 +#define DT_NET 2 +#define DT_BYTE 3 + /* Hooks for netif.c */ + int (*xmit) __P((struct promdata *, void *, size_t)); + int (*recv) __P((struct promdata *, void *, size_t)); +}; + +#define LOADADDR ((caddr_t)0x4000) +#define DDB_MAGIC0 ( ('D'<<24) | ('D'<<16) | ('B'<<8) | ('0') ) +#define DDB_MAGIC1 ( ('D'<<24) | ('D'<<16) | ('B'<<8) | ('1') ) +#define DDB_MAGIC DDB_MAGIC0 + +extern struct promvec *promvec; +extern char *prom_bootdevice; +extern char *prom_bootfile; +extern int prom_boothow; +extern int hz; +extern int cputyp, nbpg, pgofset, pgshift; +extern int debug; + +extern void prom_init __P((void)); + +/* Note: dvma_*() routines are for "oldmon" machines only */ +extern char *dvma_mapin __P((char *, size_t)); +extern char *dvma_mapout __P((char *, size_t)); +extern char *dvma_alloc __P((int)); + +/* + * duplicates from pmap.c for mapping device on "oldmon" machines. + */ +#include + +#define getcontext() lduba(AC_CONTEXT, ASI_CONTROL) +#define setcontext(c) stba(AC_CONTEXT, ASI_CONTROL, c) +#define getsegmap(va) (cputyp == CPU_SUN4C \ + ? lduba(va, ASI_SEGMAP) \ + : lduha(va, ASI_SEGMAP)) +#define setsegmap(va, pmeg) (cputyp == CPU_SUN4C \ + ? stba(va, ASI_SEGMAP, pmeg) \ + : stha(va, ASI_SEGMAP, pmeg)) +#define getregmap(va) ((unsigned)lduha(va+2, ASI_REGMAP) >> 8) +#define setregmap(va, smeg) stha(va+2, ASI_REGMAP, (smeg << 8)) + +#define getpte(va) lda(va, ASI_PTE) +#define setpte(va, pte) sta(va, ASI_PTE, pte) + diff --git a/headers/private/kernel/arch/sparc/saerrno.h b/headers/private/kernel/arch/sparc/saerrno.h new file mode 100644 index 0000000000..8630c50aff --- /dev/null +++ b/headers/private/kernel/arch/sparc/saerrno.h @@ -0,0 +1,59 @@ +/* $OpenBSD: saerrno.h,v 1.4 1996/10/29 08:00:58 mickey Exp $ */ +/* $NetBSD: saerrno.h,v 1.6 1995/09/18 21:19:45 pk Exp $ */ + +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)saerrno.h 8.1 (Berkeley) 6/11/93 + */ + +#include + +extern int errno; + +/* special stand error codes */ +#define EADAPT (ELAST+1) /* bad adaptor */ +#define ECTLR (ELAST+2) /* bad controller */ +#define EUNIT (ELAST+3) /* bad drive */ +#define EPART (ELAST+4) /* bad partition */ +#define ERDLAB (ELAST+5) /* can't read disk label */ +#define EUNLAB (ELAST+6) /* unlabeled disk */ +#define EOFFSET (ELAST+7) /* relative seek not supported */ +#define ECMD (ELAST+8) /* undefined driver command */ +#define EBSE (ELAST+9) /* bad sector error */ +#define EWCK (ELAST+10) /* write check error */ +#define EECC (ELAST+11) /* uncorrectable ecc error */ +#define EHER (ELAST+12) /* hard error */ +#define ESALAST (ELAST+12) /* */ + +char *strerror __P((int err)); + diff --git a/headers/private/kernel/arch/sparc/saioctl.h b/headers/private/kernel/arch/sparc/saioctl.h new file mode 100644 index 0000000000..47c2f1bb0d --- /dev/null +++ b/headers/private/kernel/arch/sparc/saioctl.h @@ -0,0 +1,54 @@ +/* $OpenBSD: saioctl.h,v 1.2 1996/09/23 14:19:04 mickey Exp $ */ +/* $NetBSD: saioctl.h,v 1.2 1994/10/26 05:45:04 cgd Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)saioctl.h 8.1 (Berkeley) 6/11/93 + */ + +/* ioctl's -- for disks just now */ +#define SAIOHDR (('d'<<8)|1) /* next i/o includes header */ +#define SAIOCHECK (('d'<<8)|2) /* next i/o checks data */ +#define SAIOHCHECK (('d'<<8)|3) /* next i/o checks header & data */ +#define SAIONOBAD (('d'<<8)|4) /* inhibit bad sector forwarding */ +#define SAIODOBAD (('d'<<8)|5) /* enable bad sector forwarding */ +#define SAIOECCLIM (('d'<<8)|6) /* set limit to ecc correction, bits */ +#define SAIOECCUNL (('d'<<8)|7) /* use standard ecc procedures */ +#define SAIORETRIES (('d'<<8)|8) /* set retry count for unit */ +#define SAIODEVDATA (('d'<<8)|9) /* get pointer to pack label */ +#define SAIOSSI (('d'<<8)|10) /* set skip sector inhibit */ +#define SAIONOSSI (('d'<<8)|11) /* inhibit skip sector handling */ +#define SAIOSSDEV (('d'<<8)|12) /* is device skip sector type? */ +#define SAIODEBUG (('d'<<8)|13) /* enable/disable debugging */ +#define SAIOGBADINFO (('d'<<8)|14) /* get bad-sector table */ + diff --git a/headers/private/kernel/arch/sparc/sparc.h b/headers/private/kernel/arch/sparc/sparc.h new file mode 100755 index 0000000000..0a9a4cd79c --- /dev/null +++ b/headers/private/kernel/arch/sparc/sparc.h @@ -0,0 +1,12 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _SPARC_H +#define _SPARC_H + +#define PAGE_SIZE 4096 +#define PAGE_ALIGN(x) (((x) + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1)) + +#endif + diff --git a/headers/private/kernel/arch/sparc/sparcbootblock.h b/headers/private/kernel/arch/sparc/sparcbootblock.h new file mode 100644 index 0000000000..7b39ae6ddc --- /dev/null +++ b/headers/private/kernel/arch/sparc/sparcbootblock.h @@ -0,0 +1,13 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +unsigned char sparcbootblock[] = { +1,3,1,7,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,60,0,56,0,0,0,0,0,0,0,0,0,0,3,0, +14,4,130,16,98,120,129,192,64,0,1,0,0,0,0,0,0,4,5,0,0,0,0,56,0,0,0,0,0, +10,5,0,0,0,0,56,0,16,0,0,0,17,7,0,0,0,0,56,0,16,0,0,0,24,9,0,0,0,0,56,0, +16,0,0,0,29,31,0,0,0,0,56,0,0,0,0,0,46,115,116,97,114,116,0,95,101,116, +101,120,116,0,95,101,100,97,116,97,0,95,101,110,100,0,115,112,97,114,99, +98,111,111,116,98,108,111,99,107,46,111,0 +}; + diff --git a/headers/private/kernel/arch/sparc/stage2.h b/headers/private/kernel/arch/sparc/stage2.h new file mode 100644 index 0000000000..2e5226421d --- /dev/null +++ b/headers/private/kernel/arch/sparc/stage2.h @@ -0,0 +1,31 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _STAGE2_H +#define _STAGE2_H + +#include + +// kernel args +struct kernel_args { + unsigned int cons_line; + unsigned int mem_size; + char *str; + const boot_entry *bootdir; + unsigned int bootdir_size; + unsigned int kernel_seg0_base; + unsigned int kernel_seg0_size; + unsigned int kernel_seg1_base; + unsigned int kernel_seg1_size; + unsigned int phys_alloc_range_low; + unsigned int phys_alloc_range_high; + unsigned int virt_alloc_range_low; + unsigned int virt_alloc_range_high; + unsigned int stack_start; + unsigned int stack_end; + // architecture specific +}; + +#endif + diff --git a/headers/private/kernel/arch/sparc/stand.h b/headers/private/kernel/arch/sparc/stand.h new file mode 100644 index 0000000000..34cb2de057 --- /dev/null +++ b/headers/private/kernel/arch/sparc/stand.h @@ -0,0 +1,215 @@ +/* $OpenBSD: stand.h,v 1.35 1998/07/29 00:38:36 mickey Exp $ */ +/* $NetBSD: stand.h,v 1.18 1996/11/30 04:35:51 gwr Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)stand.h 8.1 (Berkeley) 6/11/93 + */ + +#include +#include +#include +#ifdef __STDC__ +#include +#else +#include +#endif +#include "saioctl.h" +#include "saerrno.h" + +#ifndef NULL +#define NULL 0 +#endif + +struct open_file; + +/* + * Useful macros + */ +#define NENTS(x) sizeof(x)/sizeof(x[0]) +/* don't define if libkern included */ +#ifndef LIBKERN_INLINE +#define max(a,b) (((a)>(b))? (a) : (b)) +#define min(a,b) (((a)>(b))? (b) : (a)) +#endif + +/* + * This structure is used to define file system operations in a file system + * independent way. + */ +struct fs_ops { + int (*open) __P((char *path, struct open_file *f)); + int (*close) __P((struct open_file *f)); + int (*read) __P((struct open_file *f, void *buf, + size_t size, size_t *resid)); + int (*write) __P((struct open_file *f, void *buf, + size_t size, size_t *resid)); + off_t (*seek) __P((struct open_file *f, off_t offset, int where)); + int (*stat) __P((struct open_file *f, struct stat *sb)); + int (*readdir) __P((struct open_file *f, char *)); +}; + +extern struct fs_ops file_system[]; +extern int nfsys; + +/* where values for lseek(2) */ +#define SEEK_SET 0 /* set file offset to offset */ +#define SEEK_CUR 1 /* set file offset to current plus offset */ +#define SEEK_END 2 /* set file offset to EOF plus offset */ + +/* Device switch */ +struct devsw { + char *dv_name; + int (*dv_strategy) __P((void *devdata, int rw, + daddr_t blk, size_t size, + void *buf, size_t *rsize)); + int (*dv_open) __P((struct open_file *f, ...)); + int (*dv_close) __P((struct open_file *f)); + int (*dv_ioctl) __P((struct open_file *f, u_long cmd, void *data)); +}; + +extern struct devsw devsw[]; /* device array */ +extern int ndevs; /* number of elements in devsw[] */ + +extern struct consdev constab[]; +extern struct consdev *cn_tab; + +struct open_file { + int f_flags; /* see F_* below */ + struct devsw *f_dev; /* pointer to device operations */ + void *f_devdata; /* device specific data */ + struct fs_ops *f_ops; /* pointer to file system operations */ + void *f_fsdata; /* file system specific data */ + off_t f_offset; /* current file offset (F_RAW) */ +}; + +#define SOPEN_MAX 4 +extern struct open_file files[]; + +/* f_flags values */ +#define F_READ 0x0001 /* file opened for reading */ +#define F_WRITE 0x0002 /* file opened for writing */ +#define F_RAW 0x0004 /* raw device open - no file system */ +#define F_NODEV 0x0008 /* network open - no device */ + +#define isupper(c) ((c) >= 'A' && (c) <= 'Z') +#define islower(c) ((c) >= 'a' && (c) <= 'z') +#define isalpha(c) (isupper(c)||islower(c)) +#define tolower(c) (isupper(c)?((c) - 'A' + 'a'):(c)) +#define toupper(c) (islower(c)?((c) - 'a' + 'A'):(c)) +#define isspace(c) ((c) == ' ' || (c) == '\t') +#define isdigit(c) ((c) >= '0' && (c) <= '9') + +#define btochs(b,c,h,s,nh,ns) \ + c = (b) / ((nh) * (ns)); \ + h = ((b) % ((nh) * (ns))) / (ns); \ + s = ((b) % ((nh) * (ns))) % (ns); + +void *alloc __P((u_int)); +void *alloca __P((size_t)); +void free __P((void *, u_int)); +struct disklabel; +char *getdisklabel __P((const char *, struct disklabel *)); +u_int dkcksum __P((struct disklabel *)); + +void printf __P((const char *, ...)); +void sprintf __P((char *, const char *, ...)); +void vprintf __P((const char *, _BSD_VA_LIST_)); +void twiddle __P((void)); +void gets __P((char *)); +__dead void panic __P((const char *, ...)) __attribute__((noreturn)); +__dead void _rtt __P((void)) __attribute__((noreturn)); +#define bzero(s,n) ((void)memset((s),0,(n))) +#define bcmp(s1,s2,n) (memcmp((s2),(s1),(n))) +#define bcopy(s1,s2,n) ((void)memcpy((s2),(s1),(n))) +void *memcpy __P((void *, const void *, size_t)); +int memcmp __P((const void *, const void*, size_t)); +char *strncpy __P((char *, const char *, size_t)); +char *strcpy __P((char *, const char *)); +int strncmp __P((const char *, const char *, size_t)); +size_t strlen __P((const char *)); +long strtol __P((const char *, char **, int)); +char *strchr __P((const char *, int)); +void *memset __P((void *, int, size_t)); +void exec __P((char *, void *, int)); +void exit __P((void)); +int open __P((const char *, int)); +int close __P((int)); +void closeall __P((void)); +ssize_t read __P((int, void *, size_t)); +ssize_t write __P((int, void *, size_t)); +int stat __P((const char *path, struct stat *sb)); +int fstat __P((int fd, struct stat *sb)); +int opendir __P((char *)); +int readdir __P((int, char *)); +void closedir __P((int)); +int nodev __P((void)); +int noioctl __P((struct open_file *, u_long, void *)); +void nullsys __P((void)); + +int null_open __P((char *path, struct open_file *f)); +int null_close __P((struct open_file *f)); +ssize_t null_read __P((struct open_file *f, void *buf, + size_t size, size_t *resid)); +ssize_t null_write __P((struct open_file *f, void *buf, + size_t size, size_t *resid)); +off_t null_seek __P((struct open_file *f, off_t offset, int where)); +int null_stat __P((struct open_file *f, struct stat *sb)); +int null_readdir __P((struct open_file *f, char *name)); +char *ttyname __P((int)); /* match userland decl, but ignore !0 */ +dev_t ttydev __P((char *)); +void cninit __P((void)); +int cnset __P((dev_t)); +void cnputc __P((int)); +int cngetc __P((void)); +int cnischar __P((void)); +int cnspeed __P((dev_t, int)); +u_int sleep __P((u_int)); +void usleep __P((u_int)); +char *ctime __P((const time_t *)); + +void putchar __P((int)); +int getchar __P((void)); + +#ifdef __INTERNAL_LIBSA_CREAD +int oopen __P((const char *, int)); +int oclose __P((int)); +ssize_t oread __P((int, void *, size_t)); +off_t olseek __P((int, off_t, int)); +#endif + +/* Machine dependent functions */ +int devopen __P((struct open_file *, const char *, char **)); +void machdep_start __P((char *, int, char *, char *, char *)); +time_t getsecs __P((void)); + diff --git a/headers/private/kernel/arch/sparc/thread_struct.h b/headers/private/kernel/arch/sparc/thread_struct.h new file mode 100644 index 0000000000..34f68ec6bc --- /dev/null +++ b/headers/private/kernel/arch/sparc/thread_struct.h @@ -0,0 +1,18 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _SPARC64_THREAD_STRUCT_H +#define _SPARC64_THREAD_STRUCT_H + +// architecture specific thread info +struct arch_thread { + addr sp; +}; + +struct arch_proc { + int foo; +}; + +#endif + diff --git a/headers/private/kernel/arch/sparc/types.h b/headers/private/kernel/arch/sparc/types.h new file mode 100644 index 0000000000..0277bdd368 --- /dev/null +++ b/headers/private/kernel/arch/sparc/types.h @@ -0,0 +1,18 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _ALPHA_TYPES_H +#define _ALPHA_TYPES_H + +typedef unsigned long uint64; +typedef long int64; +typedef unsigned int uint32; +typedef int int32; +typedef unsigned short uint16; +typedef short int16; +typedef unsigned char uint8; +typedef char int8; + +#endif + diff --git a/headers/private/kernel/arch/sparc/va-sparc.h b/headers/private/kernel/arch/sparc/va-sparc.h new file mode 100644 index 0000000000..56f915a5ed --- /dev/null +++ b/headers/private/kernel/arch/sparc/va-sparc.h @@ -0,0 +1,166 @@ +/* This is just like the default gvarargs.h + except for differences described below. */ + +/* Define __gnuc_va_list. */ + +#ifndef __GNUC_VA_LIST +#define __GNUC_VA_LIST +#if ! defined (__svr4__) && ! defined (__linux__) && ! defined (__arch64__) +/* This has to be a char * to be compatible with Sun. + i.e., we have to pass a `va_list' to vsprintf. */ +typedef char * __gnuc_va_list; +#else +/* This has to be a void * to be compatible with Sun svr4. + i.e., we have to pass a `va_list' to vsprintf. */ +typedef void * __gnuc_va_list; +#endif +#endif /* not __GNUC_VA_LIST */ + +/* If this is for internal libc use, don't define anything but + __gnuc_va_list. */ +#if defined (_STDARG_H) || defined (_VARARGS_H) + +#ifdef _STDARG_H + +/* Call __builtin_next_arg even though we aren't using its value, so that + we can verify that LASTARG is correct. */ +#if defined (__GCC_NEW_VARARGS__) || defined (__arch64__) +#define va_start(AP, LASTARG) \ + (__builtin_next_arg (LASTARG), AP = (char *) __builtin_saveregs ()) +#else +#define va_start(AP, LASTARG) \ + (__builtin_saveregs (), AP = ((char *) __builtin_next_arg (LASTARG))) +#endif + +#else + +#define va_alist __builtin_va_alist +#define va_dcl int __builtin_va_alist;... + +#if defined (__GCC_NEW_VARARGS__) || defined (__arch64__) +#define va_start(AP) ((AP) = (char *) __builtin_saveregs ()) +#else +#define va_start(AP) \ + (__builtin_saveregs (), (AP) = ((char *) &__builtin_va_alist)) +#endif + +#endif + +#ifndef va_end +void va_end (__gnuc_va_list); /* Defined in libgcc.a */ + +/* Values returned by __builtin_classify_type. */ + +enum __va_type_classes { + __no_type_class = -1, + __void_type_class, + __integer_type_class, + __char_type_class, + __enumeral_type_class, + __boolean_type_class, + __pointer_type_class, + __reference_type_class, + __offset_type_class, + __real_type_class, + __complex_type_class, + __function_type_class, + __method_type_class, + __record_type_class, + __union_type_class, + __array_type_class, + __string_type_class, + __set_type_class, + __file_type_class, + __lang_type_class +}; + +#endif +#define va_end(pvar) ((void)0) + +/* Avoid errors if compiling GCC v2 with GCC v1. */ +#if __GNUC__ == 1 +#define __extension__ +#endif + +/* RECORD_TYPE args passed using the C calling convention are + passed by invisible reference. ??? RECORD_TYPE args passed + in the stack are made to be word-aligned; for an aggregate that is + not word-aligned, we advance the pointer to the first non-reg slot. */ + +#ifdef __arch64__ + +typedef unsigned int __ptrint __attribute__ ((__mode__ (__DI__))); + +/* ??? TODO: little endian support */ + +#define va_arg(pvar, TYPE) \ +__extension__ \ +(*({int __type = __builtin_classify_type (* (TYPE *) 0); \ + char * __result; \ + if (__type == __real_type_class) /* float? */ \ + { \ + if (__alignof__ (TYPE) == 16) \ + (pvar) = (void *) (((__ptrint) (pvar) + 15) & -16); \ + __result = (pvar); \ + (pvar) = (char *) (pvar) + sizeof (TYPE); \ + } \ + else if (__type < __record_type_class) /* integer? */ \ + { \ + (pvar) = (char *) (pvar) + 8; \ + __result = (char *) (pvar) - sizeof (TYPE); \ + } \ + else /* aggregate object */ \ + { \ + if (sizeof (TYPE) <= 8) \ + { \ + __result = (pvar); \ + (pvar) = (char *) (pvar) + 8; \ + } \ + else if (sizeof (TYPE) <= 16) \ + { \ + if (__alignof__ (TYPE) == 16) \ + (pvar) = (void *) (((__ptrint) (pvar) + 15) & -16); \ + __result = (pvar); \ + (pvar) = (char *) (pvar) + 16; \ + } \ + else \ + { \ + __result = * (void **) (pvar); \ + (pvar) = (char *) (pvar) + 8; \ + } \ + } \ + (TYPE *) __result;})) + +#else /* not __arch64__ */ + +#define __va_rounded_size(TYPE) \ + (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int)) + +/* We don't declare the union member `d' to have type TYPE + because that would lose in C++ if TYPE has a constructor. */ +/* We cast to void * and then to TYPE * because this avoids + a warning about increasing the alignment requirement. + The casts to char * avoid warnings about invalid pointer arithmetic. */ +#define va_arg(pvar,TYPE) \ +__extension__ \ +(*({((__builtin_classify_type (*(TYPE*) 0) >= __record_type_class \ + || (__builtin_classify_type (*(TYPE*) 0) == __real_type_class \ + && sizeof (TYPE) == 16)) \ + ? ((pvar) = (char *)(pvar) + __va_rounded_size (TYPE *), \ + *(TYPE **) (void *) ((char *)(pvar) - __va_rounded_size (TYPE *))) \ + : __va_rounded_size (TYPE) == 8 \ + ? ({ union {char __d[sizeof (TYPE)]; int __i[2];} __u; \ + __u.__i[0] = ((int *) (void *) (pvar))[0]; \ + __u.__i[1] = ((int *) (void *) (pvar))[1]; \ + (pvar) = (char *)(pvar) + 8; \ + (TYPE *) (void *) __u.__d; }) \ + : ((pvar) = (char *)(pvar) + __va_rounded_size (TYPE), \ + ((TYPE *) (void *) ((char *)(pvar) - __va_rounded_size (TYPE)))));})) + +#endif /* not __arch64__ */ + +/* Copy __gnuc_va_list into another variable of this type. */ +#define __va_copy(dest, src) (dest) = (src) + +#endif /* defined (_STDARG_H) || defined (_VARARGS_H) */ + diff --git a/headers/private/kernel/arch/thread.h b/headers/private/kernel/arch/thread.h new file mode 100644 index 0000000000..2aae21133c --- /dev/null +++ b/headers/private/kernel/arch/thread.h @@ -0,0 +1,25 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _NEWOS_KERNEL_ARCH_THREAD_H +#define _NEWOS_KERNEL_ARCH_THREAD_H + +#include + +int arch_proc_init_proc_struct(struct proc *p, bool kernel); +int arch_thread_init_thread_struct(struct thread *t); +void arch_thread_context_switch(struct thread *t_from, struct thread *t_to); +int arch_thread_initialize_kthread_stack(struct thread *t, int (*start_func)(void), void (*entry_func)(void), void (*exit_func)(void)); +void arch_thread_dump_info(void *info); +void arch_thread_enter_uspace(addr entry, void *args, addr ustack_top); +void arch_thread_switch_kstack_and_call(struct thread *t, addr new_kstack, void (*func)(void *), void *arg); + +struct thread *arch_thread_get_current_thread(void); +void arch_thread_set_current_thread(struct thread *t); + +// for any inline overrides +#include + +#endif + diff --git a/headers/private/kernel/arch/thread_struct.h b/headers/private/kernel/arch/thread_struct.h new file mode 100644 index 0000000000..bd50bd7c19 --- /dev/null +++ b/headers/private/kernel/arch/thread_struct.h @@ -0,0 +1,31 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _NEWOS_KERNEL_ARCH_THREAD_STRUCT_H +#define _NEWOS_KERNEL_ARCH_THREAD_STRUCT_H + +#ifdef ARCH_x86 +#include +#endif +#ifdef ARCH_sh4 +#include +#endif +#ifdef ARCH_alpha +#include +#endif +#ifdef ARCH_sparc64 +#include +#endif +#ifdef ARCH_mips +#include +#endif +#ifdef ARCH_ppc +#include +#endif +#ifdef ARCH_m68k +#include +#endif + +#endif + diff --git a/headers/private/kernel/arch/timer.h b/headers/private/kernel/arch/timer.h new file mode 100644 index 0000000000..11a4b293ef --- /dev/null +++ b/headers/private/kernel/arch/timer.h @@ -0,0 +1,15 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _NEWOS_KERNEL_ARCH_TIMER_H +#define _NEWOS_KERNEL_ARCH_TIMER_H + +#include + +void arch_timer_set_hardware_timer(bigtime_t timeout); +void arch_timer_clear_hardware_timer(void); +int arch_init_timer(kernel_args *ka); + +#endif + diff --git a/headers/private/kernel/arch/vm.h b/headers/private/kernel/arch/vm.h new file mode 100644 index 0000000000..ac640dc506 --- /dev/null +++ b/headers/private/kernel/arch/vm.h @@ -0,0 +1,17 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _NEWOS_KERNEL_ARCH_VM_H +#define _NEWOS_KERNEL_ARCH_VM_H + +#include +#include + +int arch_vm_init(kernel_args *ka); +int arch_vm_init2(kernel_args *ka); +int arch_vm_init_endvm(kernel_args *ka); +void arch_vm_aspace_swap(vm_address_space *aspace); + +#endif + diff --git a/headers/private/kernel/arch/vm_translation_map.h b/headers/private/kernel/arch/vm_translation_map.h new file mode 100644 index 0000000000..191895e22c --- /dev/null +++ b/headers/private/kernel/arch/vm_translation_map.h @@ -0,0 +1,48 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _NEWOS_KERNEL_ARCH_VM_TRANSLATION_MAP_H +#define _NEWOS_KERNEL_ARCH_VM_TRANSLATION_MAP_H + +#include +#include +#include + +typedef struct vm_translation_map_struct { + struct vm_translation_map_struct *next; + struct vm_translation_map_ops_struct *ops; + recursive_lock lock; + int map_count; + struct vm_translation_map_arch_info_struct *arch_data; +} vm_translation_map; + +// table of operations the vm may want to do to this mapping +typedef struct vm_translation_map_ops_struct { + void (*destroy)(vm_translation_map *); + int (*lock)(vm_translation_map*); + int (*unlock)(vm_translation_map*); + int (*map)(vm_translation_map *map, addr va, addr pa, unsigned int attributes); + int (*unmap)(vm_translation_map *map, addr start, addr end); + int (*query)(vm_translation_map *map, addr va, addr *out_physical, unsigned int *out_flags); + addr (*get_mapped_size)(vm_translation_map*); + int (*protect)(vm_translation_map *map, addr base, addr top, unsigned int attributes); + int (*clear_flags)(vm_translation_map *map, addr va, unsigned int flags); + void (*flush)(vm_translation_map *map); + int (*get_physical_page)(addr physical_address, addr *out_virtual_address, int flags); + int (*put_physical_page)(addr virtual_address); +} vm_translation_map_ops; + +int vm_translation_map_create(vm_translation_map *new_map, bool kernel); +int vm_translation_map_module_init(kernel_args *ka); +int vm_translation_map_module_init2(kernel_args *ka); +void vm_translation_map_module_init_post_sem(kernel_args *ka); +// quick function to map a page in regardless of map context. Used in VM initialization, +// before most vm data structures exist +int vm_translation_map_quick_map(kernel_args *ka, addr va, addr pa, unsigned int attributes, addr (*get_free_page)(kernel_args *)); + +// quick function to return the physical pgdir of a mapping, needed for a context switch +addr vm_translation_map_get_pgdir(vm_translation_map *map); + +#endif + diff --git a/headers/private/kernel/arch/x86/arch_cpu.h b/headers/private/kernel/arch/x86/arch_cpu.h new file mode 100644 index 0000000000..37bc66a854 --- /dev/null +++ b/headers/private/kernel/arch/x86/arch_cpu.h @@ -0,0 +1,151 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _KERNEL_ARCH_x86_CPU_H +#define _KERNEL_ARCH_x86_CPU_H + +/* ??? why include this as we're normally included from that file! */ +#include + +#define KERNEL_CODE_SEG 0x8 +#define KERNEL_DATA_SEG 0x10 +#define USER_CODE_SEG 0x1b +#define USER_DATA_SEG 0x23 +#define TSS 0x28 +#define PAGE_SIZE 4096 + +#define _BIG_ENDIAN 0 +#define _LITTLE_ENDIAN 1 + +typedef struct desc_struct { + unsigned int a,b; +} desc_table; + +struct tss { + uint16 prev_task; + uint16 unused0; + uint32 sp0; + uint32 ss0; + uint32 sp1; + uint32 ss1; + uint32 sp2; + uint32 ss2; + uint32 sp3; + uint32 ss3; + uint32 cr3; + uint32 eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi; + uint32 es, cs, ss, ds, fs, gs; + uint32 ldt_seg_selector; + uint16 unused1; + uint16 io_map_base; +}; + +struct tss_descriptor { + uint16 limit_00_15; + uint16 base_00_15; + uint32 base_23_16 : 8; + uint32 type : 4; + uint32 zero : 1; + uint32 dpl : 2; + uint32 present : 1; + uint32 limit_19_16 : 4; + uint32 avail : 1; + uint32 zero1 : 1; + uint32 zero2 : 1; + uint32 granularity : 1; + uint32 base_31_24 : 8; +}; + +typedef struct ptentry { + unsigned int present:1; + unsigned int rw:1; + unsigned int user:1; + unsigned int write_through:1; + unsigned int cache_disabled:1; + unsigned int accessed:1; + unsigned int dirty:1; + unsigned int reserved:1; + unsigned int global:1; + unsigned int avail:3; + unsigned int addr:20; +} ptentry; + +typedef struct pdentry { + unsigned int present:1; + unsigned int rw:1; + unsigned int user:1; + unsigned int write_through:1; + unsigned int cache_disabled:1; + unsigned int accessed:1; + unsigned int reserved:1; + unsigned int page_size:1; + unsigned int global:1; + unsigned int avail:3; + unsigned int addr:20; +} pdentry; + +#define nop() __asm__ ("nop"::) + +void setup_system_time(unsigned int cv_factor); +void i386_context_switch(unsigned int **old_esp, unsigned int *new_esp, addr new_pgdir); +void i386_enter_uspace(addr entry, void *args, addr ustack_top); +void i386_set_kstack(addr kstack); +void i386_switch_stack_and_call(addr stack, void (*func)(void *), void *arg); +void i386_swap_pgdir(addr new_pgdir); +void i386_fsave_swap(void *old_fpu_state, void *new_fpu_state); +void i386_fxsave_swap(void *old_fpu_state, void *new_fpu_state); + +#define read_dr3(value) \ + __asm__("movl %%dr3,%0" : "=r" (value)) + +#define write_dr3(value) \ + __asm__("movl %0,%%dr3" :: "r" (value)) + +#define invalidate_TLB(va) \ + __asm__("invlpg (%0)" : : "r" (va)) + +#define out8(value,port) \ +__asm__ ("outb %%al,%%dx"::"a" (value),"d" (port)) + +#define out16(value,port) \ +__asm__ ("outw %%ax,%%dx"::"a" (value),"d" (port)) + +#define out32(value,port) \ +__asm__ ("outl %%eax,%%dx"::"a" (value),"d" (port)) + +#define in8(port) ({ \ +unsigned char _v; \ +__asm__ volatile ("inb %%dx,%%al":"=a" (_v):"d" (port)); \ +_v; \ +}) + +#define in16(port) ({ \ +unsigned short _v; \ +__asm__ volatile ("inw %%dx,%%ax":"=a" (_v):"d" (port)); \ +_v; \ +}) + +#define in32(port) ({ \ +unsigned int _v; \ +__asm__ volatile ("inl %%dx,%%eax":"=a" (_v):"d" (port)); \ +_v; \ +}) + +#define out8_p(value,port) \ +__asm__ ("outb %%al,%%dx\n" \ + "\tjmp 1f\n" \ + "1:\tjmp 1f\n" \ + "1:"::"a" (value),"d" (port)) + +#define in8_p(port) ({ \ +unsigned char _v; \ +__asm__ volatile ("inb %%dx,%%al\n" \ + "\tjmp 1f\n" \ + "1:\tjmp 1f\n" \ + "1:":"=a" (_v):"d" (port)); \ +_v; \ +}) + +#endif + diff --git a/headers/private/kernel/arch/x86/arch_kernel.h b/headers/private/kernel/arch/x86/arch_kernel.h new file mode 100644 index 0000000000..106728c219 --- /dev/null +++ b/headers/private/kernel/arch/x86/arch_kernel.h @@ -0,0 +1,30 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _KERNEL_ARCH_x86_KERNEL_H +#define _KERNEL_ARCH_x86_KERNEL_H + +#include + +// memory layout +#define KERNEL_BASE 0x80000000 +#define KERNEL_SIZE 0x80000000 +#define KERNEL_TOP (KERNEL_BASE + (KERNEL_SIZE - 1)) + +/* +** User space layout is a little special: +** The user space does not completely cover the space not covered by the kernel. +** This is accomplished by starting user space at 1Mb and running to 64kb short of kernel space. +** The lower 1Mb reserved spot makes it easy to find null pointer references and guarantees a +** region wont be placed there. The 64kb region assures a user space thread cannot pass +** a buffer into the kernel as part of a syscall that would cross into kernel space. +*/ +#define USER_BASE 0x100000 +#define USER_SIZE (0x80000000 - (0x10000 + 0x100000)) +#define USER_TOP (USER_BASE + USER_SIZE) + +#define USER_STACK_REGION 0x70000000 +#define USER_STACK_REGION_SIZE (USER_BASE + (USER_SIZE - USER_STACK_REGION)) + +#endif /* _KERNEL_ARCH_x86_KERNEL_H */ diff --git a/headers/private/kernel/arch/x86/arch_stage2.h b/headers/private/kernel/arch/x86/arch_stage2.h new file mode 100644 index 0000000000..a4318fb148 --- /dev/null +++ b/headers/private/kernel/arch/x86/arch_stage2.h @@ -0,0 +1,38 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _NEWOS_KERNEL_BOOT_ARCH_I386_STAGE2_H +#define _NEWOS_KERNEL_BOOT_ARCH_I386_STAGE2_H + +#include + + +#define MAX_BOOT_PTABLES 4 + +// kernel args +typedef struct { + // architecture specific + unsigned int system_time_cv_factor; + unsigned int phys_pgdir; + unsigned int vir_pgdir; + unsigned int num_pgtables; + unsigned int pgtables[MAX_BOOT_PTABLES]; + unsigned int phys_idt; + unsigned int vir_idt; + unsigned int phys_gdt; + unsigned int vir_gdt; + unsigned int page_hole; + // smp stuff + unsigned int apic_time_cv_factor; // apic ticks per second + unsigned int apic_phys; + unsigned int *apic; + unsigned int ioapic_phys; + unsigned int *ioapic; + unsigned int cpu_apic_id[MAX_BOOT_CPUS]; + unsigned int cpu_os_id[MAX_BOOT_CPUS]; + unsigned int cpu_apic_version[MAX_BOOT_CPUS]; +} arch_kernel_args; + +#endif + diff --git a/headers/private/kernel/arch/x86/arch_thread.h b/headers/private/kernel/arch/x86/arch_thread.h new file mode 100644 index 0000000000..3911ae4ab0 --- /dev/null +++ b/headers/private/kernel/arch/x86/arch_thread.h @@ -0,0 +1,29 @@ +/* +** Copyright 2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _KERNEL_ARCH_x86_THREAD_H +#define _KERNEL_ARCH_x86_THREAD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +extern inline struct thread *arch_thread_get_current_thread(void) { + struct thread *t; + read_dr3(t); + return t; +} + +extern inline void arch_thread_set_current_thread(struct thread *t) { + write_dr3(t); +} + +#ifdef __cplusplus +} +#endif + +#endif /* _KERNEL_ARCH_x86_THREAD_H */ + diff --git a/headers/private/kernel/arch/x86/console_dev.h b/headers/private/kernel/arch/x86/console_dev.h new file mode 100755 index 0000000000..7ff9c3e9dc --- /dev/null +++ b/headers/private/kernel/arch/x86/console_dev.h @@ -0,0 +1,16 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _CONSOLE_DEV_H +#define _CONSOLE_DEV_H + +#include + +int console_dev_init(kernel_args *ka); + +enum { + CONSOLE_OP_WRITEXY = 2376 +}; + +#endif diff --git a/headers/private/kernel/arch/x86/faults.h b/headers/private/kernel/arch/x86/faults.h new file mode 100755 index 0000000000..7998a04f20 --- /dev/null +++ b/headers/private/kernel/arch/x86/faults.h @@ -0,0 +1,12 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _NEWOS_KERNEL_ARCH_I386_FAULTS +#define _NEWOS_KERNEL_ARCH_I386_FAULTS + +int i386_general_protection_fault(int errorcode); +int i386_double_fault(int errorcode); + +#endif + diff --git a/headers/private/kernel/arch/x86/ide_bus.h b/headers/private/kernel/arch/x86/ide_bus.h new file mode 100755 index 0000000000..f17c2aab90 --- /dev/null +++ b/headers/private/kernel/arch/x86/ide_bus.h @@ -0,0 +1,9 @@ +#ifndef _IDE_BUS_H +#define _IDE_BUS_H + +#include + +int ide_bus_init(kernel_args *ka); + +#endif + diff --git a/headers/private/kernel/arch/x86/ide_private.h b/headers/private/kernel/arch/x86/ide_private.h new file mode 100755 index 0000000000..ca915e4660 --- /dev/null +++ b/headers/private/kernel/arch/x86/ide_private.h @@ -0,0 +1,100 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Modified Sep 2001 by Rob Judd +** Distributed under the terms of the NewOS License. +*/ + +#ifndef __IDE_PRIVATE_H__ +#define __IDE_PRIVATE_H__ + +#include +#include "partition.h" + +typedef struct +{ + unsigned short config; /* obsolete stuff */ + unsigned short cyls; /* logical cylinders */ + unsigned short _reserved_2; + unsigned short heads; /* logical heads */ + unsigned short _vendor_4; /* bytes per track unformatted */ + unsigned short _vendor_5; /* sectors per track unformatted */ + unsigned short sectors; /* logical sectors */ + unsigned short _vendor_7; + unsigned short _vendor_8; + unsigned short _vendor_9; + char serial[20]; //40 /* serial number */ + unsigned short _vendor_20; + unsigned short _vendor_21; + unsigned short vend_bytes_long; /* number of ECC bytes on long cmd */ + char firmware[8]; /* firmware revision */ + char model[40]; //94 /* model name */ + unsigned short mult_support; /* vendor stuff and multiple cmds */ + unsigned short _reserved_48; /* bit 0: double word i/o possible */ + unsigned short capabilities; /* bit 9: LBA; bit 8: DMA support */ + unsigned short _reserved_50; + unsigned short pio; /* bit 15-8: timing mode for PIO */ + unsigned short dma; /* bit 15-8: timing mode for DMA */ + unsigned short _reserved_53; + unsigned short curr_cyls; /* current logical cylinders */ + unsigned short curr_heads; /* current logical heads */ + unsigned short curr_sectors; /* current logical sectors */ + unsigned long capacity; //118 /* apparent capacity in sectors */ + unsigned short _pad[511-59]; /* don't need this stuff for now */ +} ide_hw_id_t; + +#define IDE_MAGIC_COOKIE 0xABCDEF10 +#define IDE_MAGIC_COOKIE2 0x12345678 + +#define NO_DEVICE -1 +#define UNKNOWN_DEVICE 0 +#define ATA_DEVICE 1 +#define ATAPI_DEVICE 2 + +#define IDE_NAME 40 + +typedef struct s_ide_device +{ + uint32 magic; + ide_hw_id_t hardware_device; + uint32 magic2; + int iobase; + int bus; + int device; + int device_type; + uint32 sector_count; + int bytes_per_sector; + int lba_supported; + int start_block; + int end_block; + tPartition partitions[8]; // 4 Primary + 4 Extended +} ide_device; + +#define MAX_IDE_BUSES 2 +#define MAX_DEVICES 4 + +extern ide_device devices[MAX_DEVICES]; + +#define DISK_GET_GEOMETRY 1 +#define DISK_USE_DMA 2 +#define DISK_USE_BUS_MASTERING 3 +#define DISK_USE_PIO 4 +#define DISK_GET_ACCOUSTIC_LEVEL 5 +#define DISK_SET_ACCOUSTIC_LEVEL 6 + + +typedef struct s_drive_geometry +{ + uint32 blocks; + uint32 heads; + uint32 cylinders; + uint32 sectors; + int removable; + uint32 bytes_per_sector; + int read_only; + char model[40]; + char serial[20]; + char firmware[8]; +} drive_geometry; + +#endif + diff --git a/headers/private/kernel/arch/x86/ide_raw.h b/headers/private/kernel/arch/x86/ide_raw.h new file mode 100755 index 0000000000..1f52218e57 --- /dev/null +++ b/headers/private/kernel/arch/x86/ide_raw.h @@ -0,0 +1,31 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Modified Sep 2001 by Rob Judd +** Distributed under the terms of the NewOS License. +*/ + +#ifndef __IDE_RAW_H__ +#define __IDE_RAW_H__ + +#include "ide_private.h" + +#define NO_ERR 0 +#define ERR_TIMEOUT 1 +#define ERR_HARDWARE_ERROR 2 +#define ERR_DRQ_NOT_SET 3 +#define ERR_DISK_BUSY 4 +#define ERR_DEVICE_FAULT 5 +#define ERR_BUFFER_NOT_EMPTY 6 + +int ide_read_block(ide_device *device, char *buffer, uint32 block, uint8 numSectors); +int ide_write_block(ide_device *device, const char *buffer, uint32 block, uint8 numSectors); +int ide_base (int bus); +void ide_string_conv (char *str, int len); +int ide_reset (int bus, int device); +bool ide_identify_device (int bus, int device); +void ide_raw_init(int base1, int base2); +bool ide_get_partitions(ide_device *device); +int ide_get_accoustic(ide_device *device, int8* level_ptr); +int ide_set_accoustic(ide_device *device, int8 level); + +#endif diff --git a/headers/private/kernel/arch/x86/interrupts.h b/headers/private/kernel/arch/x86/interrupts.h new file mode 100755 index 0000000000..c2901ed898 --- /dev/null +++ b/headers/private/kernel/arch/x86/interrupts.h @@ -0,0 +1,19 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _NEWOS_KERNEL_ARCH_I386_INTERRUPTS_H +#define _NEWOS_KERNEL_ARCH_I386_INTERRUPTS_H + +void trap0();void trap1();void trap2();void trap3();void trap4();void trap5(); +void trap6();void trap7();void trap8();void trap9();void trap10();void trap11(); +void trap12();void trap13();void trap14();void trap16();void trap17();void trap18(); +void trap32();void trap33();void trap34();void trap35();void trap36();void trap37(); +void trap38();void trap39();void trap40();void trap41();void trap42();void trap43(); +void trap44();void trap45();void trap46();void trap47(); + +void trap99(); + +void trap251();void trap252();void trap253();void trap254();void trap255(); +#endif + diff --git a/headers/private/kernel/arch/x86/keyboard.h b/headers/private/kernel/arch/x86/keyboard.h new file mode 100755 index 0000000000..0943d903ef --- /dev/null +++ b/headers/private/kernel/arch/x86/keyboard.h @@ -0,0 +1,9 @@ +#ifndef _KEYBOARD_H +#define _KEYBOARD_H + +#include + +int keyboard_dev_init(kernel_args *ka); + +#endif + diff --git a/headers/private/kernel/arch/x86/partition.h b/headers/private/kernel/arch/x86/partition.h new file mode 100755 index 0000000000..1042e99a26 --- /dev/null +++ b/headers/private/kernel/arch/x86/partition.h @@ -0,0 +1,84 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#ifndef __PARTITION_H +#define __PARTITION_H + +#define PARTITION_MAGIC1 0x55 +#define PARTITION_MAGIC2 0xaa +#define PART_MAGIC_OFFSET 0x01fe +#define PARTITION_OFFSET 0x01be +#define NUM_PARTITIONS 4 + +#define PTCHSToLBA(c, h, s, scnt, hcnt) ((s) & 0x3f) + \ + (scnt) * ( (h) + (hcnt) * ((c) | (((s) & 0xc0) << 2))) +#define PTLBAToCHS(lba, c, h, s, scnt, hcnt) ( \ + (s) = (lba) % (scnt) + 1, \ + (lba) /= (scnt), \ + (h) = (lba) % (hcnt), \ + (lba) /= (heads), \ + (c) = (lba) & 0xff, \ + (s) |= ((lba) >> 2) & 0xc0) + +/* taken from linux fdisk src */ +typedef enum PartitionTypes +{ + PTEmpty = 0, + PTDOS3xPrimary, /* 1 */ + PTXENIXRoot, /* 2 */ + PTXENIXUsr, /* 3 */ + PTOLDDOS16Bit, /* 4 */ + PTDosExtended, /* 5 */ + PTDos5xPrimary, /* 6 */ + PTOS2HPFS, /* 7 */ + PTAIX, /* 8 */ + PTAIXBootable, /* 9 */ + PTOS2BootMgr, /* 10 */ + PTWin95FAT32, + PTWin95FAT32LBA, + PTWin95FAT16LBA, + PTWin95ExtendedLBA, + PTVenix286 = 0x40, + PTNovell = 0x51, + PTMicroport = 0x52, + PTGnuHurd = 0x63, + PTNetware286 = 0x64, + PTNetware386 = 0x65, + PTPCIX = 0x75, + PTOldMinix = 0x80, + PTMinix = 0x81, + PTLinuxSwap = 0x82, + PTLinuxExt2 = 0x83, + PTAmoeba = 0x93, + PTAmoebaBBT = 0x94, + PTBSD = 0xa5, + PTBSDIFS = 0xb7, + PTBSDISwap = 0xb8, + PTSyrinx = 0xc7, + PTCPM = 0xdb, + PTDOSAccess = 0xe1, + PTDOSRO = 0xe3, + PTDOSSecondary = 0xf2, + PTBBT = 0xff +} partitionTypes; + +#define PartitionIsExtended(P) ((P)->PartitionType == PTDosExtended) + +typedef struct sPartition +{ + unsigned char boot_flags; + unsigned char starting_head; + unsigned char starting_sector; + unsigned char starting_cylinder; + unsigned char partition_type; + unsigned char ending_head; + unsigned char ending_sector; + unsigned char ending_cylinder; + unsigned int starting_block; + unsigned int sector_count; + +} tPartition; + +#endif diff --git a/headers/private/kernel/arch/x86/ps2mouse.h b/headers/private/kernel/arch/x86/ps2mouse.h new file mode 100755 index 0000000000..4a03e00861 --- /dev/null +++ b/headers/private/kernel/arch/x86/ps2mouse.h @@ -0,0 +1,106 @@ +/* + * ps2mouse.c: + * PS/2 mouse device driver for NewOS and OpenBeOS. + * Author: Elad Lahav (elad@eldarshany.com) + * Created: 21.12.2001 + * Modified: 11.1.2002 + */ + +/* + * A PS/2 mouse is connected to the IBM 8042 controller, and gets its + * name from the IBM PS/2 personal computer, which was the first to + * use this device. All resources are shared between the keyboard, and + * the mouse, referred to as the "Auxiliary Device". + * I/O: + * ~~~ + * The controller has 3 I/O registers: + * 1. Status (input), mapped to port 64h + * 2. Control (output), mapped to port 64h + * 3. Data (input/output), mapped to port 60h + * Data: + * ~~~~ + * Since a mouse is an input only device, data can only be read, and + * not written. A packet read from the mouse data port is composed of + * three bytes: + * byte 0: status byte, where + * - bit 0: Y overflow (1 = true) + * - bit 1: X overflow (1 = true) + * - bit 2: MSB of Y offset + * - bit 3: MSB of X offset + * - bit 4: Syncronization bit (always 1) + * - bit 5: Middle button (1 = down) + * - bit 6: Right button (1 = down) + * - bit 7: Left button (1 = down) + * byte 1: X position change, since last probed (-127 to +127) + * byte 2: Y position change, since last probed (-127 to +127) + * Interrupts: + * ~~~~~~~~~~ + * The PS/2 mouse device is connected to interrupt 12, which means that + * it uses the second interrupt controller (handles INT8 to INT15). In + * order for this interrupt to be enabled, both the 5th interrupt of + * the second controller AND the 3rd interrupt of the first controller + * (cascade mode) should be unmasked. + * The controller uses 3 consecutive interrupts to inform the computer + * that it has new data. On the first the data register holds the status + * byte, on the second the X offset, and on the 3rd the Y offset. + */ + +#ifndef _KERNEL_ARCH_x86_PS2MOUSE_H +#define _KERNEL_ARCH_x86_PS2MOUSE_H + +#include +#include +#include +#include +#include +#include +#include +#include + +///////////////////////////////////////////////////////////////////////// +// definitions + +// I/O addresses +#define PS2_PORT_DATA 0x60 +#define PS2_PORT_CTRL 0x64 + +// control words +#define PS2_CTRL_WRITE_CMD 0x60 +#define PS2_CTRL_WRITE_AUX 0xD4 + +// data words +#define PS2_CMD_DEV_INIT 0x43 +#define PS2_CMD_ENABLE_MOUSE 0xF4 +#define PS2_CMD_DISABLE_MOUSE 0xF5 +#define PS2_CMD_RESET_MOUSE 0xFF + +#define PS2_RES_ACK 0xFA +#define PS2_RES_RESEND 0xFE + +// interrupts +#define INT_BASE 0x20 +#define INT_PS2_MOUSE 0x0C +#define INT_CASCADE 0x02 + +#define PACKET_SIZE 3 + +/* + * mouse_data: + * Holds the data read from the PS/2 auxiliary device. + */ +typedef struct { + char status; + char delta_x; + char delta_y; +} mouse_data; // mouse_data + +#ifdef _PS2MOUSE_ +static mouse_data md_int; +static mouse_data md_read; +static sem_id mouse_sem; +static bool in_read; +#endif + +int mouse_dev_init(kernel_args *ka); + +#endif /* _KERNEL_ARCH_x86_PS2MOUSE_H */ diff --git a/headers/private/kernel/arch/x86/rtl8139_dev.h b/headers/private/kernel/arch/x86/rtl8139_dev.h new file mode 100755 index 0000000000..a44534f5a1 --- /dev/null +++ b/headers/private/kernel/arch/x86/rtl8139_dev.h @@ -0,0 +1,96 @@ +/* +** +** Naive RealTek 8139C driver for the DC Broadband Adapter. Some +** assistance on names of things from the NetBSD-DC sources. +** +** (c)2001 Dan Potter +** License: X11 +** +*/ + +#ifndef _RTL_8139C_H +#define _RTL_8139C_H + +/* RTL8139C register definitions */ +#define RT_IDR0 0x00 /* Mac address */ +#define RT_MAR0 0x08 /* Multicast filter */ +#define RT_TXSTATUS0 0x10 /* Transmit status (4 32bit regs) */ +#define RT_TXSTATUS1 0x14 /* Transmit status (4 32bit regs) */ +#define RT_TXSTATUS2 0x18 /* Transmit status (4 32bit regs) */ +#define RT_TXSTATUS3 0x1c /* Transmit status (4 32bit regs) */ +#define RT_TXADDR0 0x20 /* Tx descriptors (also 4 32bit) */ +#define RT_TXADDR1 0x24 /* Tx descriptors (also 4 32bit) */ +#define RT_TXADDR2 0x28 /* Tx descriptors (also 4 32bit) */ +#define RT_TXADDR3 0x2c /* Tx descriptors (also 4 32bit) */ +#define RT_RXBUF 0x30 /* Receive buffer start address */ +#define RT_RXEARLYCNT 0x34 /* Early Rx byte count */ +#define RT_RXEARLYSTATUS 0x36 /* Early Rx status */ +#define RT_CHIPCMD 0x37 /* Command register */ +#define RT_RXBUFTAIL 0x38 /* Current address of packet read (queue tail) */ +#define RT_RXBUFHEAD 0x3A /* Current buffer address (queue head) */ +#define RT_INTRMASK 0x3C /* Interrupt mask */ +#define RT_INTRSTATUS 0x3E /* Interrupt status */ +#define RT_TXCONFIG 0x40 /* Tx config */ +#define RT_RXCONFIG 0x44 /* Rx config */ +#define RT_TIMER 0x48 /* A general purpose counter */ +#define RT_RXMISSED 0x4C /* 24 bits valid, write clears */ +#define RT_CFG9346 0x50 /* 93C46 command register */ +#define RT_CONFIG0 0x51 /* Configuration reg 0 */ +#define RT_CONFIG1 0x52 /* Configuration reg 1 */ +#define RT_TIMERINT 0x54 /* Timer interrupt register (32 bits) */ +#define RT_MEDIASTATUS 0x58 /* Media status register */ +#define RT_CONFIG3 0x59 /* Config register 3 */ +#define RT_CONFIG4 0x5A /* Config register 4 */ +#define RT_MULTIINTR 0x5C /* Multiple interrupt select */ +#define RT_MII_TSAD 0x60 /* Transmit status of all descriptors (16 bits) */ +#define RT_MII_BMCR 0x62 /* Basic Mode Control Register (16 bits) */ +#define RT_MII_BMSR 0x64 /* Basic Mode Status Register (16 bits) */ +#define RT_AS_ADVERT 0x66 /* Auto-negotiation advertisement reg (16 bits) */ +#define RT_AS_LPAR 0x68 /* Auto-negotiation link partner reg (16 bits) */ +#define RT_AS_EXPANSION 0x6A /* Auto-negotiation expansion reg (16 bits) */ + +/* RTL8193C command bits; or these together and write teh resulting value + into CHIPCMD to execute it. */ +#define RT_CMD_RESET 0x10 +#define RT_CMD_RX_ENABLE 0x08 +#define RT_CMD_TX_ENABLE 0x04 +#define RT_CMD_RX_BUF_EMPTY 0x01 + +/* RTL8139C interrupt status bits */ +#define RT_INT_PCIERR 0x8000 /* PCI Bus error */ +#define RT_INT_TIMEOUT 0x4000 /* Set when TCTR reaches TimerInt value */ +#define RT_INT_RXFIFO_OVERFLOW 0x0040 /* Rx FIFO overflow */ +#define RT_INT_RXFIFO_UNDERRUN 0x0020 /* Packet underrun / link change */ +#define RT_INT_RXBUF_OVERFLOW 0x0010 /* Rx BUFFER overflow */ +#define RT_INT_TX_ERR 0x0008 +#define RT_INT_TX_OK 0x0004 +#define RT_INT_RX_ERR 0x0002 +#define RT_INT_RX_OK 0x0001 + +/* RTL8139C transmit status bits */ +#define RT_TX_CARRIER_LOST 0x80000000 /* Carrier sense lost */ +#define RT_TX_ABORTED 0x40000000 /* Transmission aborted */ +#define RT_TX_OUT_OF_WINDOW 0x20000000 /* Out of window collision */ +#define RT_TX_STATUS_OK 0x00008000 /* Status ok: a good packet was transmitted */ +#define RT_TX_UNDERRUN 0x00004000 /* Transmit FIFO underrun */ +#define RT_TX_HOST_OWNS 0x00002000 /* Set to 1 when DMA operation is completed */ +#define RT_TX_SIZE_MASK 0x00001fff /* Descriptor size mask */ + +/* RTL8139C receive status bits */ +#define RT_RX_MULTICAST 0x00008000 /* Multicast packet */ +#define RT_RX_PAM 0x00004000 /* Physical address matched */ +#define RT_RX_BROADCAST 0x00002000 /* Broadcast address matched */ +#define RT_RX_BAD_SYMBOL 0x00000020 /* Invalid symbol in 100TX packet */ +#define RT_RX_RUNT 0x00000010 /* Packet size is <64 bytes */ +#define RT_RX_TOO_LONG 0x00000008 /* Packet size is >4K bytes */ +#define RT_RX_CRC_ERR 0x00000004 /* CRC error */ +#define RT_RX_FRAME_ALIGN 0x00000002 /* Frame alignment error */ +#define RT_RX_STATUS_OK 0x00000001 /* Status ok: a good packet was received */ + +/* Realtek PCI vendor ID */ +#define RT_VENDORID 0x10EC + +/* Realtek Device ID */ +#define RT_DEVICEID_8139 0x8139 + +#endif diff --git a/headers/private/kernel/arch/x86/rtl8139_priv.h b/headers/private/kernel/arch/x86/rtl8139_priv.h new file mode 100755 index 0000000000..82d790a268 --- /dev/null +++ b/headers/private/kernel/arch/x86/rtl8139_priv.h @@ -0,0 +1,37 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _RTL8139_PRIV_H +#define _RTL8139_PRIV_H + +#include +#include +#include + +typedef struct rtl8139 { + int irq; + addr phys_base; + addr phys_size; + addr virt_base; + uint16 io_port; + region_id region; + uint8 mac_addr[6]; + int txbn; + int last_txbn; + region_id rxbuf_region; + addr rxbuf; + sem_id rx_sem; + region_id txbuf_region; + addr txbuf; + sem_id tx_sem; + mutex lock; + spinlock_t reg_spinlock; +} rtl8139; + +int rtl8139_detect(rtl8139 **rtl); +int rtl8139_init(rtl8139 *rtl); +void rtl8139_xmit(rtl8139 *rtl, const char *ptr, ssize_t len); +ssize_t rtl8139_rx(rtl8139 *rtl, char *buf, ssize_t buf_len); + +#endif diff --git a/headers/private/kernel/arch/x86/smp_priv.h b/headers/private/kernel/arch/x86/smp_priv.h new file mode 100755 index 0000000000..8a5708f4ca --- /dev/null +++ b/headers/private/kernel/arch/x86/smp_priv.h @@ -0,0 +1,161 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _NEWOS_KERNEL_ARCH_I386_SMP_PRIV_H +#define _NEWOS_KERNEL_ARCH_I386_SMP_PRIV_H + +int i386_smp_interrupt(int vector); +void arch_smp_ack_interrupt(void); +int arch_smp_set_apic_timer(bigtime_t relative_timeout); +int arch_smp_clear_apic_timer(void); +int smp_intercpu_int_handler(void); + +#define MP_FLT_SIGNATURE '_PM_' +#define MP_CTH_SIGNATURE 'PCMP' + +#define APIC_DM_INIT (5 << 8) +#define APIC_DM_STARTUP (6 << 8) +#define APIC_LEVEL_TRIG (1 << 14) +#define APIC_ASSERT (1 << 13) + +#define APIC_ENABLE 0x100 +#define APIC_FOCUS (~(1 << 9)) +#define APIC_SIV (0xff) + +#define APIC_ID ((unsigned int *) ((unsigned int) apic + 0x020)) +#define APIC_VERSION ((unsigned int *) ((unsigned int) apic + 0x030)) +#define APIC_TPRI ((unsigned int *) ((unsigned int) apic + 0x080)) +#define APIC_EOI ((unsigned int *) ((unsigned int) apic + 0x0b0)) +#define APIC_SIVR ((unsigned int *) ((unsigned int) apic + 0x0f0)) +#define APIC_ESR ((unsigned int *) ((unsigned int) apic + 0x280)) +#define APIC_ICR1 ((unsigned int *) ((unsigned int) apic + 0x300)) +#define APIC_ICR2 ((unsigned int *) ((unsigned int) apic + 0x310)) +#define APIC_LVTT ((unsigned int *) ((unsigned int) apic + 0x320)) +#define APIC_LINT0 ((unsigned int *) ((unsigned int) apic + 0x350)) +#define APIC_LVT3 ((unsigned int *) ((unsigned int) apic + 0x370)) +#define APIC_ICRT ((unsigned int *) ((unsigned int) apic + 0x380)) +#define APIC_CCRT ((unsigned int *) ((unsigned int) apic + 0x390)) +#define APIC_TDCR ((unsigned int *) ((unsigned int) apic + 0x3e0)) + +#define APIC_ICR1_WRITE_MASK 0xfff3f000 +#define APIC_ICR1_DELMODE_FIXED 0 +#define APIC_ICR1_DELMODE_LOWESTPRI (1 << 8) +#define APIC_ICR1_DESTMODE_LOG (1 << 11) +#define APIC_ICR1_DESTMODE_PHYS 0 + +#define APIC_ICR1_READ_MASK 0xfff32000 +#define APIC_ICR1_DELSTATUS (1 << 12) + +#define APIC_ICR1_DEST_FIELD (0) +#define APIC_ICR1_DEST_SELF (1 << 18) +#define APIC_ICR1_DEST_ALL (2 << 18) +#define APIC_ICR1_DEST_ALL_BUT_SELF (3 << 18) + + + +#define APIC_ICR2_MASK 0x00ffffff + +#define APIC_TDCR_2 0x00 +#define APIC_TDCR_4 0x01 +#define APIC_TDCR_8 0x02 +#define APIC_TDCR_16 0x03 +#define APIC_TDCR_32 0x08 +#define APIC_TDCR_64 0x09 +#define APIC_TDCR_128 0x0a +#define APIC_TDCR_1 0x0b + +#define APIC_LVTT_MASK 0x000310ff +#define APIC_LVTT_VECTOR 0x000000ff +#define APIC_LVTT_DS 0x00001000 +#define APIC_LVTT_M 0x00010000 +#define APIC_LVTT_TM 0x00020000 + +#define APIC_LVT_DM 0x00000700 +#define APIC_LVT_IIPP 0x00002000 +#define APIC_LVT_TM 0x00008000 +#define APIC_LVT_M 0x00010000 +#define APIC_LVT_OS 0x00020000 + +#define APIC_TPR_PRIO 0x000000ff +#define APIC_TPR_INT 0x000000f0 +#define APIC_TPR_SUB 0x0000000f + +#define APIC_SVR_SWEN 0x00000100 +#define APIC_SVR_FOCUS 0x00000200 + +#define APIC_DEST_STARTUP 0x00600 + +#define LOPRIO_LEVEL 0x00000010 + +#define IOAPIC_ID 0x0 +#define IOAPIC_VERSION 0x1 +#define IOAPIC_ARB 0x2 +#define IOAPIC_REDIR_TABLE 0x10 + +#define IPI_CACHE_FLUSH 0x40 +#define IPI_INV_TLB 0x41 +#define IPI_INV_PTE 0x42 +#define IPI_INV_RESCHED 0x43 +#define IPI_STOP 0x44 + +#define MP_EXT_PE 0 +#define MP_EXT_BUS 1 +#define MP_EXT_IO_APIC 2 +#define MP_EXT_IO_INT 3 +#define MP_EXT_LOCAL_INT 4 + +#define MP_EXT_PE_LEN 20 +#define MP_EXT_BUS_LEN 8 +#define MP_EXT_IO_APIC_LEN 8 +#define MP_EXT_IO_INT_LEN 8 +#define MP_EXT_LOCAL_INT_LEN 8 + +struct mp_config_table { + unsigned int signature; /* "PCMP" */ + unsigned short table_len; /* length of this structure */ + unsigned char mp_rev; /* spec supported, 1 for 1.1 or 4 for 1.4 */ + unsigned char checksum; /* checksum, all bytes add up to zero */ + char oem[8]; /* oem identification, not null-terminated */ + char product[12]; /* product name, not null-terminated */ + void *oem_table_ptr; /* addr of oem-defined table, zero if none */ + unsigned short oem_len; /* length of oem table */ + unsigned short num_entries; /* number of entries in base table */ + unsigned int apic; /* address of apic */ + unsigned short ext_len; /* length of extended section */ + unsigned char ext_checksum; /* checksum of extended table entries */ +}; + +struct mp_flt_struct { + unsigned int signature; /* "_MP_" */ + struct mp_config_table *mpc; /* address of mp configuration table */ + unsigned char mpc_len; /* length of this structure in 16-byte units */ + unsigned char mp_rev; /* spec supported, 1 for 1.1 or 4 for 1.4 */ + unsigned char checksum; /* checksum, all bytes add up to zero */ + unsigned char mp_feature_1; /* mp system configuration type if no mpc */ + unsigned char mp_feature_2; /* imcrp */ + unsigned char mp_feature_3, mp_feature_4, mp_feature_5; /* reserved */ +}; + +struct mp_ext_pe +{ + unsigned char type; + unsigned char apic_id; + unsigned char apic_version; + unsigned char cpu_flags; + unsigned int signature; /* stepping, model, family, each four bits */ + unsigned int feature_flags; + unsigned int res1, res2; +}; + +struct mp_ext_ioapic +{ + unsigned char type; + unsigned char ioapic_id; + unsigned char ioapic_version; + unsigned char ioapic_flags; + unsigned int *addr; +}; + +#endif + diff --git a/headers/private/kernel/arch/x86/stage2_priv.h b/headers/private/kernel/arch/x86/stage2_priv.h new file mode 100755 index 0000000000..817e445193 --- /dev/null +++ b/headers/private/kernel/arch/x86/stage2_priv.h @@ -0,0 +1,200 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _STAGE2_PRIV_H +#define _STAGE2_PRIV_H + +#include + +extern void _start(unsigned int mem, int in_vesa, unsigned int vesa_ptr); +extern void clearscreen(void); +extern void kputs(const char *str); +extern int dprintf(const char *fmt, ...); +extern void sleep(long long time); +extern long long system_time(void); +extern void execute_n_instructions(int count); +void system_time_setup(long a); +long long rdtsc(); +unsigned int get_eflags(void); +void set_eflags(unsigned int val); +void cpuid(unsigned int selector, unsigned int *data); + +//void put_uint_dec(unsigned int a); +//void put_uint_hex(unsigned int a); +//void nmessage(const char *str1, unsigned int a, const char *str2); +//void nmessage2(const char *str1, unsigned int a, const char *str2, unsigned int b, const char *str3); + +#define ROUNDUP(a, b) (((a) + ((b) - 1)) & (~((b) - 1))) +#define ROUNDOWN(a, b) (((a) / (b)) * (b)) + +#define PAGE_SIZE 0x1000 +#define KERNEL_BASE 0x80000000 +#define KERNEL_ENTRY 0x80000080 +#define STACK_SIZE 2 +#define DEFAULT_PAGE_FLAGS (1 | 2) // present/rw +#define SCREEN_WIDTH 80 +#define SCREEN_HEIGHT 24 +#define ADDR_MASK 0xfffff000 + +#define NULL ((void *)0) + +#define _PACKED __attribute__((packed)) + +#define IDT_LIMIT 0x800 +#define GDT_LIMIT 0x800 + +struct gdt_idt_descr { + unsigned short a; + unsigned int *b; +} _PACKED; + +// SMP stuff +extern int smp_boot(kernel_args *ka, unsigned int kernel_entry); +extern void smp_trampoline(void); +extern void smp_trampoline_end(void); + +#define MP_FLT_SIGNATURE '_PM_' +#define MP_CTH_SIGNATURE 'PCMP' + +#define APIC_DM_INIT (5 << 8) +#define APIC_DM_STARTUP (6 << 8) +#define APIC_LEVEL_TRIG (1 << 14) +#define APIC_ASSERT (1 << 13) + +#define APIC_ENABLE 0x100 +#define APIC_FOCUS (~(1 << 9)) +#define APIC_SIV (0xff) + +#define APIC_ID ((unsigned int *) ((unsigned int) ka->arch_args.apic + 0x020)) +#define APIC_VERSION ((unsigned int *) ((unsigned int) ka->arch_args.apic + 0x030)) +#define APIC_TPRI ((unsigned int *) ((unsigned int) ka->arch_args.apic + 0x080)) +#define APIC_EOI ((unsigned int *) ((unsigned int) ka->arch_args.apic + 0x0b0)) +#define APIC_LDR ((unsigned int *) ((unsigned int) ka->arch_args.apic + 0x0d0)) +#define APIC_SIVR ((unsigned int *) ((unsigned int) ka->arch_args.apic + 0x0f0)) +#define APIC_ESR ((unsigned int *) ((unsigned int) ka->arch_args.apic + 0x280)) +#define APIC_ICR1 ((unsigned int *) ((unsigned int) ka->arch_args.apic + 0x300)) +#define APIC_ICR2 ((unsigned int *) ((unsigned int) ka->arch_args.apic + 0x310)) +#define APIC_LVTT ((unsigned int *) ((unsigned int) ka->arch_args.apic + 0x320)) +#define APIC_LINT0 ((unsigned int *) ((unsigned int) ka->arch_args.apic + 0x350)) +#define APIC_LINT1 ((unsigned int *) ((unsigned int) ka->arch_args.apic + 0x360)) +#define APIC_LVT3 ((unsigned int *) ((unsigned int) ka->arch_args.apic + 0x370)) +#define APIC_ICRT ((unsigned int *) ((unsigned int) ka->arch_args.apic + 0x380)) +#define APIC_CCRT ((unsigned int *) ((unsigned int) ka->arch_args.apic + 0x390)) +#define APIC_TDCR ((unsigned int *) ((unsigned int) ka->arch_args.apic + 0x3e0)) + +#define APIC_TDCR_2 0x00 +#define APIC_TDCR_4 0x01 +#define APIC_TDCR_8 0x02 +#define APIC_TDCR_16 0x03 +#define APIC_TDCR_32 0x08 +#define APIC_TDCR_64 0x09 +#define APIC_TDCR_128 0x0a +#define APIC_TDCR_1 0x0b + +#define APIC_LVTT_MASK 0x000310ff +#define APIC_LVTT_VECTOR 0x000000ff +#define APIC_LVTT_DS 0x00001000 +#define APIC_LVTT_M 0x00010000 +#define APIC_LVTT_TM 0x00020000 + +#define APIC_LVT_DM_ExtINT 0x00000700 +#define APIC_LVT_DM_NMI 0x00000400 +#define APIC_LVT_IIPP 0x00002000 +#define APIC_LVT_TM 0x00008000 +#define APIC_LVT_M 0x00010000 +#define APIC_LVT_OS 0x00020000 +#define APIC_TPR_PRIO 0x000000ff +#define APIC_TPR_INT 0x000000f0 +#define APIC_TPR_SUB 0x0000000f + +#define APIC_SVR_SWEN 0x00000100 +#define APIC_SVR_FOCUS 0x00000200 + +#define APIC_DEST_STARTUP 0x00600 + +#define LOPRIO_LEVEL 0x00000010 + +#define APIC_DEST_FIELD (0) +#define APIC_DEST_SELF (1 << 18) +#define APIC_DEST_ALL (2 << 18) +#define APIC_DEST_ALL_BUT_SELF (3 << 18) + +#define IOAPIC_ID 0x0 +#define IOAPIC_VERSION 0x1 +#define IOAPIC_ARB 0x2 +#define IOAPIC_REDIR_TABLE 0x10 + +#define IPI_CACHE_FLUSH 0x40 +#define IPI_INV_TLB 0x41 +#define IPI_INV_PTE 0x42 +#define IPI_INV_RESCHED 0x43 +#define IPI_STOP 0x44 + +#define MP_EXT_PE 0 +#define MP_EXT_BUS 1 +#define MP_EXT_IO_APIC 2 +#define MP_EXT_IO_INT 3 +#define MP_EXT_LOCAL_INT 4 + +#define MP_EXT_PE_LEN 20 +#define MP_EXT_BUS_LEN 8 +#define MP_EXT_IO_APIC_LEN 8 +#define MP_EXT_IO_INT_LEN 8 +#define MP_EXT_LOCAL_INT_LEN 8 + +struct mp_config_table { + unsigned int signature; /* "PCMP" */ + unsigned short table_len; /* length of this structure */ + unsigned char mp_rev; /* spec supported, 1 for 1.1 or 4 for 1.4 */ + unsigned char checksum; /* checksum, all bytes add up to zero */ + char oem[8]; /* oem identification, not null-terminated */ + char product[12]; /* product name, not null-terminated */ + void *oem_table_ptr; /* addr of oem-defined table, zero if none */ + unsigned short oem_len; /* length of oem table */ + unsigned short num_entries; /* number of entries in base table */ + unsigned int apic; /* address of apic */ + unsigned short ext_len; /* length of extended section */ + unsigned char ext_checksum; /* checksum of extended table entries */ +}; + +struct mp_flt_struct { + unsigned int signature; /* "_MP_" */ + struct mp_config_table *mpc; /* address of mp configuration table */ + unsigned char mpc_len; /* length of this structure in 16-byte units */ + unsigned char mp_rev; /* spec supported, 1 for 1.1 or 4 for 1.4 */ + unsigned char checksum; /* checksum, all bytes add up to zero */ + unsigned char mp_feature_1; /* mp system configuration type if no mpc */ + unsigned char mp_feature_2; /* imcrp */ + unsigned char mp_feature_3, mp_feature_4, mp_feature_5; /* reserved */ +}; + +struct mp_ext_pe +{ + unsigned char type; + unsigned char apic_id; + unsigned char apic_version; + unsigned char cpu_flags; + unsigned int signature; /* stepping, model, family, each four bits */ + unsigned int feature_flags; + unsigned int res1, res2; +}; + +struct mp_ext_ioapic +{ + unsigned char type; + unsigned char ioapic_id; + unsigned char ioapic_version; + unsigned char ioapic_flags; + unsigned int *addr; +}; + +struct mp_ext_bus +{ + unsigned char type; + unsigned char bus_id; + char name[6]; +}; + +#endif + diff --git a/headers/private/kernel/arch/x86/thread_struct.h b/headers/private/kernel/arch/x86/thread_struct.h new file mode 100755 index 0000000000..508be3d54b --- /dev/null +++ b/headers/private/kernel/arch/x86/thread_struct.h @@ -0,0 +1,20 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _NEWOS_KERNEL_ARCH_I386_THREAD_STRUCT_H +#define _NEWOS_KERNEL_ARCH_I386_THREAD_STRUCT_H + +// architecture specific thread info +struct arch_thread { + unsigned int *esp; + // 512 byte floating point save point + uint8 fpu_state[512]; +}; + +struct arch_proc { + // nothing here +}; + +#endif + diff --git a/headers/private/kernel/arch/x86/timer.h b/headers/private/kernel/arch/x86/timer.h new file mode 100755 index 0000000000..2869657641 --- /dev/null +++ b/headers/private/kernel/arch/x86/timer.h @@ -0,0 +1,11 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _NEWOS_KERNEL_ARCH_I386_TIMER +#define _NEWOS_KERNEL_ARCH_I386_TIMER + +int apic_timer_interrupt(void); + +#endif + diff --git a/headers/private/kernel/arch/x86/types.h b/headers/private/kernel/arch/x86/types.h new file mode 100755 index 0000000000..f7df3fc1ce --- /dev/null +++ b/headers/private/kernel/arch/x86/types.h @@ -0,0 +1,31 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _ARCH_x86_TYPES_H +#define _ARCH_x86_TYPES_H + +#ifndef WIN32 + typedef unsigned long long uint64; + typedef long long int64; +#else /* WIN32 */ + typedef unsigned __int64 uint64; + typedef __int64 int64; +#endif + +typedef unsigned int uint32; +typedef int int32; +typedef unsigned short uint16; +typedef short int16; +typedef unsigned char uint8; +typedef char int8; +typedef unsigned long addr; + +#define _OBOS_TIME_T_ int /* basic time_t type */ + +/* define this as not all platforms have it set, but we'll make sure as + * some conditional checks need it + */ +#define __INTEL__ 1 + +#endif /* _ARCH_x86_TYPES_H */ diff --git a/headers/private/kernel/arch/x86/vesa.h b/headers/private/kernel/arch/x86/vesa.h new file mode 100755 index 0000000000..516e4c841d --- /dev/null +++ b/headers/private/kernel/arch/x86/vesa.h @@ -0,0 +1,66 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _STAGE2_VESA_H +#define _STAGE2_VESA_H + +#include + +struct VBEInfoBlock { + char signature[4]; // should be 'VESA' + uint16 version; + uint32 oem_ptr; + uint32 capabilities; + uint32 video_ptr; + uint16 total_memory; + // VESA 2.x stuff + uint16 oem_software_rev; + uint32 oem_vendor_name_ptr; + uint32 oem_product_name_ptr; + uint32 oem_product_rev_ptr; + uint8 reserved[222]; + uint8 oem_data[256]; +} _PACKED; + +struct VBEModeInfoBlock { + uint16 attributes; + uint8 wina_attributes; + uint8 winb_attributes; + uint16 win_granulatiry; + uint16 win_size; + uint16 wina_segment; + uint16 winb_segment; + uint32 win_function_ptr; + uint16 bytes_per_scanline; + + uint16 x_resolution; + uint16 y_resolution; + uint8 x_charsize; + uint8 y_charsize; + uint8 num_planes; + uint8 bits_per_pixel; + uint8 num_banks; + uint8 memory_model; + uint8 bank_size; + uint8 num_image_pages; + uint8 _reserved; + + uint8 red_mask_size; + uint8 red_field_position; + uint8 green_mask_size; + uint8 green_field_position; + uint8 blue_mask_size; + uint8 blue_field_position; + uint8 reserved_mask_size; + uint8 reserved_field_position; + uint8 direct_color_mode_info; + + uint32 phys_base_ptr; + uint32 offscreen_mem_offset; + uint16 offscreen_mem_size; + uint8 _reserved2[206]; +} _PACKED; + +#endif + diff --git a/headers/private/kernel/arch/x86/vm.h b/headers/private/kernel/arch/x86/vm.h new file mode 100755 index 0000000000..a5c79539de --- /dev/null +++ b/headers/private/kernel/arch/x86/vm.h @@ -0,0 +1,10 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _NEWOS_KERNEL_ARCH_I386_VM_H +#define _NEWOS_KERNEL_ARCH_I386_VM_H + + +#endif + diff --git a/headers/private/kernel/assert.h b/headers/private/kernel/assert.h new file mode 100755 index 0000000000..14647622d0 --- /dev/null +++ b/headers/private/kernel/assert.h @@ -0,0 +1,32 @@ +/* +** Copyright 2002, Travis Geiselbrecht. All rights reserved. +** Copyright 2002, Manuel J. Petit. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#ifndef __newos__nulibc_assert__hh__ +#define __newos__nulibc_assert__hh__ + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +void _assert(char const *, int, char const *); + + +#ifdef NDEBUG +# define assert(x) +#else +# define assert(x) ( (x) ? (void)0 : _assert(__FILE__, __LINE__, #x) ) +#endif + + +#ifdef __cplusplus +} /* "C" */ +#endif + + +#endif diff --git a/headers/private/kernel/atomic.h b/headers/private/kernel/atomic.h new file mode 100755 index 0000000000..98dd845b9f --- /dev/null +++ b/headers/private/kernel/atomic.h @@ -0,0 +1,87 @@ +#ifndef _KERNEL_ATOMIC_H +#define _KERNEL_ATOMIC_H + +/** + * @file kernel/atomic.h + * @brief Prototypes for kernel and user versions of atomic + * functions. + */ + +/** + * @defgroup Kernel_Atomic Atomic Operations + * @ingroup OpenBeOS_Kernel + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* XXX - atomic_set is defined as using a volatile as this stops a + * compiler warning, but is there any reason why they shouldn't all + * be so defined? They were in arch/cpu.h... + */ +/** + * Perform an atomic addition. + * @param val Pointer to an integer + * @param incr The increment to add (may be -ve) + * @note Returns value of val before addition + */ +int atomic_add(int *val, int incr); +/** + * Atomic and operation + * @param val Pointer to an integer + * @param incr The increment to add (may be -ve) + * @note Returns value of val before addition + */ +int atomic_and(int *val, int incr); +/** + * Atomic or operation + * @param val Pointer to an integer + * @param incr The increment to add (may be -ve) + * @note Returns value of val before addition + */ +int atomic_or(int *val, int incr); +int atomic_set(volatile int *val, int set_to); +/* Compare the value of val with test_val. If they + * are equal then set the value of 'val' to + * 'set_to' + */ +int test_and_set(int *val, int set_to, int test_val); + +/** + * Atomic add (user version) + * @param val Pointer to an integer + * @param incr The increment to add (may be -ve) + * @note Returns value of val before addition + */ +int user_atomic_add(int *val, int incr); +/** + * Atomic and (user version) + * @param val Pointer to an integer + * @param incr The increment to add (may be -ve) + * @note Returns value of val before addition + */ +int user_atomic_and(int *val, int incr); +/** + * Atomic or (user version) + * @param val Pointer to an integer + * @param incr The increment to add (may be -ve) + * @note Returns value of val before addition + */ +int user_atomic_or(int *val, int incr); +int user_atomic_set(int *val, int set_to); +/* Compare the value of val with test_val. If they + * are equal then set the value of 'val' to + * 'set_to' + * @note This is the user version and should not be used within + * the kernel. + */ +int user_test_and_set(int *val, int set_to, int test_val); + +#ifdef __cplusplus +} +#endif +/** @} */ + +#endif /* _KERNEL_ATOMIC_H */ diff --git a/headers/private/kernel/beos.h b/headers/private/kernel/beos.h new file mode 100755 index 0000000000..8ad4e6b24a --- /dev/null +++ b/headers/private/kernel/beos.h @@ -0,0 +1,8 @@ +#ifndef _KERNEL_DEV_BEOS +#define _KERNEL_DEV_BEOS + +int beos_layer_init(void); +int beos_load_beos_driver(const char *name); + +#endif + diff --git a/headers/private/kernel/beos_p.h b/headers/private/kernel/beos_p.h new file mode 100755 index 0000000000..4f9eead62c --- /dev/null +++ b/headers/private/kernel/beos_p.h @@ -0,0 +1,192 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _BEOS_PRIV_H +#define _BEOS_PRIV_H + +#include +#include +#include + +typedef int status_t; +typedef unsigned short ushort; + +/* +** NOTE: +** Contains stuff taken from beos headers. +** Please dont sue me. I'll clean it up when I get the chance. +*/ + +/* beos driver interface */ +struct selectsync; +typedef struct selectsync selectsync; + +typedef status_t (*device_open_hook) (const char *name, uint32 flags, void **cookie); +typedef status_t (*device_close_hook) (void *cookie); +typedef status_t (*device_free_hook) (void *cookie); +typedef status_t (*device_control_hook) (void *cookie, uint32 op, void *data, size_t len); +typedef status_t (*device_read_hook) (void *cookie, off_t position, void *data, size_t *numBytes); +typedef status_t (*device_write_hook) (void *cookie, off_t position, const void *data, size_t *numBytes); +typedef status_t (*device_select_hook) (void *cookie, uint8 event, uint32 ref, selectsync *sync); +typedef status_t (*device_deselect_hook) (void *cookie, uint8 event, selectsync *sync); +typedef status_t (*device_readv_hook) (void *cookie, off_t position, const iovec *vec, size_t count, size_t *numBytes); +typedef status_t (*device_writev_hook) (void *cookie, off_t position, const iovec *vec, size_t count, size_t *numBytes); + +#define B_CUR_DRIVER_API_VERSION 2 + +typedef struct { + device_open_hook open; + device_close_hook close; + device_free_hook free; + device_control_hook control; + device_read_hook read; + device_write_hook write; + device_select_hook select; + device_deselect_hook deselect; + device_readv_hook readv; + device_writev_hook writev; +} beos_device_hooks; + +/* sem stuff */ +#define B_CAN_INTERRUPT 1 +#define B_DO_NOT_RESCHEDULE 2 +#define B_CHECK_PERMISSION 4 +#define B_TIMEOUT 8 +#define B_RELATIVE_TIMEOUT 8 +#define B_ABSOLUTE_TIMEOUT 16 + +/* module stuff */ +struct module_info { + const char *name; + uint32 flags; + int (*std_ops)(int32, ...); +}; +typedef struct module_info module_info; + +struct bus_manager_info { + module_info minfo; + status_t (*rescan)(void); +}; +typedef struct bus_manager_info bus_manager_info; + +/* isa module */ +typedef struct { + ulong address; /* memory address (little endian!) 4 bytes */ + ushort transfer_count; /* # transfers minus one (little endian!) 2 bytes*/ + uchar reserved; /* filler, 1byte*/ + uchar flag; /* end of link flag, 1byte */ +} isa_dma_entry; + +struct isa_module_info { + bus_manager_info binfo; + + uint8 (*read_io_8) (int mapped_io_addr); + void (*write_io_8) (int mapped_io_addr, uint8 value); + uint16 (*read_io_16) (int mapped_io_addr); + void (*write_io_16) (int mapped_io_addr, uint16 value); + uint32 (*read_io_32) (int mapped_io_addr); + void (*write_io_32) (int mapped_io_addr, uint32 value); + + void * (*ram_address) (const void *physical_address_in_system_memory); + + long (*make_isa_dma_table) ( + const void *buffer, /* buffer to make a table for */ + long buffer_size, /* buffer size */ + ulong num_bits, /* dma transfer size that will be used */ + isa_dma_entry *table, /* -> caller-supplied scatter/gather table */ + long num_entries /* max # entries in table */ + ); + long (*start_isa_dma) ( + long channel, /* dma channel to use */ + void *buf, /* buffer to transfer */ + long transfer_count, /* # transfers */ + uchar mode, /* mode flags */ + uchar e_mode /* extended mode flags */ + ); + long (*start_scattered_isa_dma) ( + long channel, /* channel # to use */ + const isa_dma_entry *table, /* physical address of scatter/gather table */ + uchar mode, /* mode flags */ + uchar emode /* extended mode flags */ + ); + long (*lock_isa_dma_channel) (long channel); + long (*unlock_isa_dma_channel) (long channel); +}; +typedef struct isa_module_info isa_module_info; +#define B_ISA_MODULE_NAME "bus_managers/isa/v1" + +/* beos error codes */ + +#define LONG_MIN (-2147483647L-1) + +#define B_GENERAL_ERROR_BASE LONG_MIN +#define B_OS_ERROR_BASE B_GENERAL_ERROR_BASE + 0x1000 + +enum { + B_NO_MEMORY = B_GENERAL_ERROR_BASE, + B_IO_ERROR, + B_PERMISSION_DENIED, + B_BAD_INDEX, + B_BAD_TYPE, + B_BAD_VALUE, + B_MISMATCHED_VALUES, + B_NAME_NOT_FOUND, + B_NAME_IN_USE, + B_TIMED_OUT, + B_INTERRUPTED, + B_WOULD_BLOCK, + B_CANCELED, + B_NO_INIT, + B_BUSY, + B_NOT_ALLOWED, + B_BAD_DATA, + + B_ERROR = -1, + B_OK = 0, + B_NO_ERROR = 0 +}; +enum { + B_BAD_SEM_ID = B_OS_ERROR_BASE, + B_NO_MORE_SEMS, + + B_BAD_THREAD_ID = B_OS_ERROR_BASE + 0x100, + B_NO_MORE_THREADS, + B_BAD_THREAD_STATE, + B_BAD_TEAM_ID, + B_NO_MORE_TEAMS, + + B_BAD_PORT_ID = B_OS_ERROR_BASE + 0x200, + B_NO_MORE_PORTS, + + B_BAD_IMAGE_ID = B_OS_ERROR_BASE + 0x300, + B_BAD_ADDRESS, + B_NOT_AN_EXECUTABLE, + B_MISSING_LIBRARY, + B_MISSING_SYMBOL, + + B_DEBUGGER_ALREADY_INSTALLED = B_OS_ERROR_BASE + 0x400 +}; + + +/* + * BeOS functions protypes, same functions as BeOS but with + * '_beos_' prepended to the names, the kernel loader + * handles the magick of matching the names + */ +int _beos_atomic_add(volatile int *val, int incr); +int _beos_atomic_and(volatile int *val, int incr); +int _beos_atomic_or(volatile int *val, int incr); +int _beos_acquire_sem(sem_id id); +int _beos_acquire_sem_etc(sem_id id, uint32 count, uint32 flags, bigtime_t timeout); +sem_id _beos_create_sem(uint32 count, const char *name); +int _beos_delete_sem(sem_id id); +int _beos_get_sem_count(sem_id id, int32 *count); +int _beos_release_sem(sem_id id); +int _beos_release_sem_etc(sem_id id, int32 count, uint32 flags); +int _beos_strcmp(const char *cs, const char *ct); +void _beos_spin(bigtime_t microseconds); +int _beos_get_module(const char *path, module_info **vec); +int _beos_put_module(const char *path); + +#endif diff --git a/headers/private/kernel/bootdir.h b/headers/private/kernel/bootdir.h new file mode 100755 index 0000000000..cbe1842509 --- /dev/null +++ b/headers/private/kernel/bootdir.h @@ -0,0 +1,66 @@ +/* $Id: bootdir.h,v 1.1 2002/07/09 12:24:34 ejakowatz Exp $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _NEWOS_BOOT_H_ +#define _NEWOS_BOOT_H_ + +#define BOOTDIR_NAMELEN 32 +#define BOOTDIR_MAX_ENTRIES 64 +#define BOOTDIR_DIRECTORY "SBBB/Directory" + +typedef struct { + char be_name[BOOTDIR_NAMELEN]; /* name of loaded object, zero terminated */ + int be_offset; /* offset of object relative to the start of boot_dir */ + int be_type; /* object type designator */ + int be_size; /* size of loaded object (pages) */ + int be_vsize; /* size loaded object should occupy when mapped in */ + int be_extra0; + int be_extra1; + int be_extra2; + int be_extra3; +} boot_entry; + +typedef struct { + boot_entry bd_entry[BOOTDIR_MAX_ENTRIES]; +} boot_dir; + +/* void _start(uint32 mem, char *params, boot_dir *bd); */ + +#define BE_TYPE_NONE 0 /* empty entry */ +#define BE_TYPE_DIRECTORY 1 /* directory (entry 0) */ +#define BE_TYPE_BOOTSTRAP 2 /* bootstrap code object (entry 1) */ +#define BE_TYPE_CODE 3 /* executable code object */ +#define BE_TYPE_DATA 4 /* raw data object */ +#define BE_TYPE_ELF32 5 /* 32bit ELF object */ + +/* for BE_TYPE_CODE */ +#define be_code_vaddr be_extra0 /* virtual address (rel offset 0) */ +#define be_code_ventr be_extra1 /* virtual entry point (rel offset 0) */ + +#endif + diff --git a/headers/private/kernel/bootfs.h b/headers/private/kernel/bootfs.h new file mode 100755 index 0000000000..a957d2067f --- /dev/null +++ b/headers/private/kernel/bootfs.h @@ -0,0 +1,10 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _NEWOS_KERNEL_FS_BOOTFS_H +#define _NEWOS_KERNEL_FS_BOOTFS_H + +int bootstrap_bootfs(void); + +#endif diff --git a/headers/private/kernel/bus.h b/headers/private/kernel/bus.h new file mode 100755 index 0000000000..ef707607e0 --- /dev/null +++ b/headers/private/kernel/bus.h @@ -0,0 +1,41 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _BUS_H +#define _BUS_H + +#include +#include + +int bus_init(kernel_args *ka); +int bus_man_init(kernel_args *ka); + +int bus_register_bus(const char *path); + +typedef struct { + module_info minfo; + status_t (*rescan)(void); +} bus_manager_info; + +typedef struct id_list { + uint32 num_ids; + uint32 id[0]; +} id_list; + +#define MAX_DEV_IO_RANGES 8 + +typedef struct device { + uint32 vendor_id; + uint32 device_id; + + uint32 irq; + addr base[MAX_DEV_IO_RANGES]; + addr size[MAX_DEV_IO_RANGES]; + + char dev_path[256]; +} device; + +int bus_find_device(int n, id_list *vendor_ids, id_list *device_ids, device *dev); + +#endif diff --git a/headers/private/kernel/cbuf.h b/headers/private/kernel/cbuf.h new file mode 100755 index 0000000000..64d4a8c682 --- /dev/null +++ b/headers/private/kernel/cbuf.h @@ -0,0 +1,51 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _KERNEL_CBUF_H +#define _KERNEL_CBUF_H + +#include + +#define CBUF_LEN 2048 + +#define CBUF_FLAG_CHAIN_HEAD 1 +#define CBUF_FLAG_CHAIN_TAIL 2 + +typedef struct cbuf { + struct cbuf *next; + size_t len; + size_t total_len; + void *data; + int flags; + char dat[CBUF_LEN - sizeof(struct cbuf *) - 2*sizeof(int) - sizeof(void *) - sizeof(int)]; +} cbuf; + +int cbuf_init(void); +cbuf *cbuf_get_chain(size_t len); +cbuf *cbuf_get_chain_noblock(size_t len); +void cbuf_free_chain_noblock(cbuf *buf); +void cbuf_free_chain(cbuf *buf); + +size_t cbuf_get_len(cbuf *buf); +void *cbuf_get_ptr(cbuf *buf, size_t offset); +int cbuf_is_contig_region(cbuf *buf, size_t start, size_t end); + +int cbuf_memcpy_to_chain(cbuf *chain, size_t offset, const void *_src, size_t len); +int cbuf_memcpy_from_chain(void *dest, cbuf *chain, size_t offset, size_t len); + +int cbuf_user_memcpy_to_chain(cbuf *chain, size_t offset, const void *_src, size_t len); +int cbuf_user_memcpy_from_chain(void *dest, cbuf *chain, size_t offset, size_t len); + +uint16 cbuf_ones_cksum16(cbuf *chain, size_t offset, size_t len); + +cbuf *cbuf_merge_chains(cbuf *chain1, cbuf *chain2); +cbuf *cbuf_duplicate_chain(cbuf *chain, size_t offset, size_t len); + +int cbuf_truncate_head(cbuf *chain, size_t trunc_bytes); +int cbuf_truncate_tail(cbuf *chain, size_t trunc_bytes); + +void cbuf_test(void); + +#endif + diff --git a/headers/private/kernel/cdefs.h b/headers/private/kernel/cdefs.h new file mode 100755 index 0000000000..0ffc9b244a --- /dev/null +++ b/headers/private/kernel/cdefs.h @@ -0,0 +1,18 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _CDEFS_H +#define _CDEFS_H + +#ifdef __GNUC__ +# define __PRINTFLIKE(__fmt,__varargs) __attribute__((__format__ (__printf__, __fmt, __varargs))) +# define __SCANFLIKE(__fmt,__varargs) __attribute__((__format__ (__scanf__, __fmt, __varargs))) +# define __PURE __attribute__((__const__)) +#else +# define __PRINTFLIKE(__fmt,__varargs) +# define __SCANFLIKE(__fmt,__varargs) +# define __PURE +#endif + +#endif diff --git a/headers/private/kernel/console.h b/headers/private/kernel/console.h new file mode 100755 index 0000000000..b87c98f12d --- /dev/null +++ b/headers/private/kernel/console.h @@ -0,0 +1,15 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _KERNEL_CONSOLE_H +#define _KERNEL_CONSOLE_H + +#include +#include + +int con_init(kernel_args *ka); +int kprintf(const char *fmt, ...) __PRINTFLIKE(1,2); +int kprintf_xy(int x, int y, const char *fmt, ...) __PRINTFLIKE(3,4); + +#endif diff --git a/headers/private/kernel/cpu.h b/headers/private/kernel/cpu.h new file mode 100644 index 0000000000..419ea10202 --- /dev/null +++ b/headers/private/kernel/cpu.h @@ -0,0 +1,79 @@ +#ifndef _KERNEL_CPU_H +#define _KERNEL_CPU_H + +/** + * @file kernel/cpu.h + * @brief CPU Local per-CPU data structure + */ + +#include +#include +#include + +/** + * @defgroup CPU CPU Structures (not architecture specific) + * @ingroup OpenBeOS_Kernel + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * CPU local data structure + */ +/** + * One structure per cpu. + * The structure contains data that is local to the CPU, + * helping reduce the amount of cache thrashing. + */ +typedef union cpu_ent { + /** The information structure, followed by alignment bytes to make it ?? bytes */ + struct { + /** Number of this CPU, starting from 0 */ + int cpu_num; + /** If set this will force a reschedule when the quantum timer expires */ + int preempted; + /** Quantum timer */ + struct timer_event quantum_timer; + } info; + /** Alignment bytes */ + uint32 align[16]; +} cpu_ent; + +/** + * Defined in core/cpu.c + */ +extern cpu_ent cpu[MAX_BOOT_CPUS]; + +/** + * Perform pre-boot initialisation + * @param ka The kernel_args structure + */ +int cpu_preboot_init(kernel_args *ka); +/** + * Initialise a CPU + * @param ka The kernel_args structure + */ +int cpu_init(kernel_args *ka); + +/** + * Get a pointer to the CPU's local data structure + */ +/** + * This is declared as an inline function in this header + */ +cpu_ent *get_cpu_struct(void); + +/** + * Inline declaration of get_cpu_struct(void) + */ +extern inline cpu_ent *get_cpu_struct(void) { return &cpu[smp_get_current_cpu()]; } + +#ifdef __cplusplus +} +#endif +/** @} */ + +#endif /* _KERNEL_CPU_H */ diff --git a/headers/private/kernel/ctlreg.h b/headers/private/kernel/ctlreg.h new file mode 100755 index 0000000000..b66a6b55f6 --- /dev/null +++ b/headers/private/kernel/ctlreg.h @@ -0,0 +1,383 @@ +/* $OpenBSD: ctlreg.h,v 1.6 2000/02/18 16:12:26 art Exp $ */ +/* $NetBSD: ctlreg.h,v 1.15 1997/07/20 18:55:03 pk Exp $ */ + +/* + * Copyright (c) 1996 + * The President and Fellows of Harvard College. All rights reserved. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Harvard University. + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ctlreg.h 8.1 (Berkeley) 6/11/93 + */ + +/* + * Sun4m support by Aaron Brown, Harvard University. + * Changes Copyright (c) 1995 The President and Fellows of Harvard College. + * All rights reserved. + */ + +/* + * Sun 4, 4c, and 4m control registers. (includes address space definitions + * and some registers in control space). + */ + +/* + * The Alternate address spaces. + */ + +/* 0x00 unused */ +/* 0x01 unused */ +#define ASI_CONTROL 0x02 /* cache enable, context reg, etc */ +#define ASI_SEGMAP 0x03 /* [4/4c] segment maps */ +#define ASI_SRMMUFP 0x03 /* [4m] ref mmu flush/probe */ +#define ASI_PTE 0x04 /* [4/4c] PTE space (pmegs) */ +#define ASI_SRMMU 0x04 /* [4m] ref mmu registers */ +#define ASI_REGMAP 0x06 /* [4/3-level MMU ] region maps */ +#define ASI_HWFLUSHSEG 0x05 /* [4/4c] hardware assisted version of FLUSHSEG */ +#define ASI_HWFLUSHPG 0x06 /* [4/4c] hardware assisted version of FLUSHPG */ +#define ASI_SRMMUDIAG 0x06 /* [4m] */ +#define ASI_HWFLUSHCTX 0x07 /* [4/4c] hardware assisted version of FLUSHCTX */ + +#define ASI_USERI 0x08 /* I-space (user) */ +#define ASI_KERNELI 0x09 /* I-space (kernel) */ +#define ASI_USERD 0x0a /* D-space (user) */ +#define ASI_KERNELD 0x0b /* D-space (kernel) */ + +#define ASI_FLUSHREG 0x7 /* [4/4c] flush cache by region */ +#define ASI_FLUSHSEG 0x0c /* [4/4c] flush cache by segment */ +#define ASI_FLUSHPG 0x0d /* [4/4c] flush cache by page */ +#define ASI_FLUSHCTX 0x0e /* [4/4c] flush cache by context */ + +#define ASI_DCACHE 0x0f /* [4] flush data cache */ + +#define ASI_ICACHETAG 0x0c /* [4m] instruction cache tag */ +#define ASI_ICACHEDATA 0x0d /* [4m] instruction cache data */ +#define ASI_DCACHETAG 0x0e /* [4m] data cache tag */ +#define ASI_DCACHEDATA 0x0f /* [4m] data cache data */ +#define ASI_IDCACHELFP 0x10 /* [4m] flush i&d cache line (page) */ +#define ASI_IDCACHELFS 0x11 /* [4m] flush i&d cache line (seg) */ +#define ASI_IDCACHELFR 0x12 /* [4m] flush i&d cache line (reg) */ +#define ASI_IDCACHELFC 0x13 /* [4m] flush i&d cache line (ctxt) */ +#define ASI_IDCACHELFU 0x14 /* [4m] flush i&d cache line (user) */ +#define ASI_BYPASS 0x20 /* [4m] sun ref mmu bypass, + ie. direct phys access */ +#define ASI_HICACHECLR 0x31 /* [4m] hypersparc only: I-cache flash clear */ +#define ASI_ICACHECLR 0x36 /* [4m] ms1 only: I-cache flash clear */ +#define ASI_DCACHECLR 0x37 /* [4m] ms1 only: D-cache flash clear */ +#define ASI_DCACHEDIAG 0x39 /* [4m] data cache diagnostic register access */ + +/* + * [4/4c] Registers in the control space (ASI_CONTROL). + */ +#define AC_IDPROM 0x00000000 /* [4] ID PROM */ +#define AC_CONTEXT 0x30000000 /* [4/4c] context register (byte) */ +#define AC_SYSENABLE 0x40000000 /* [4/4c] system enable register (byte) */ +#define AC_DVMA_ENABLE 0x50000000 /* [4] enable user dvma */ +#define AC_BUS_ERR 0x60000000 /* [4] bus error register */ +#define AC_SYNC_ERR 0x60000000 /* [4c] sync (memory) error reg */ +#define AC_SYNC_VA 0x60000004 /* [4c] sync error virtual addr */ +#define AC_ASYNC_ERR 0x60000008 /* [4c] async error reg */ +#define AC_ASYNC_VA 0x6000000c /* [4c] async error virtual addr */ +#define AC_DIAG_REG 0x70000000 /* [4] diagnostic reg */ +#define AC_CACHETAGS 0x80000000 /* [4/4c?] cache tag base address */ +#define AC_CACHEDATA 0x90000000 /* [4] cached data [sun4/400?] */ +#define AC_DVMA_MAP 0xd0000000 /* [4] user dvma map entries */ +#define AC_VMEINTVEC 0xe0000000 /* [4] vme interrupt vector */ +#define AC_SERIAL 0xf0000000 /* [4/4c] special serial port sneakiness */ + /* AC_SERIAL is not used in the kernel (it is for the PROM) */ + +/* XXX: does not belong here */ +#define ME_REG_IERR 0x80 /* memory err ctrl reg error intr pending bit */ + +/* + * [4/4c] + * Bits in sync error register. Reading the register clears these; + * otherwise they accumulate. The error(s) occurred at the virtual + * address stored in the sync error address register, and may have + * been due to, e.g., what would usually be called a page fault. + * Worse, the bits accumulate during instruction prefetch, so + * various bits can be on that should be off. + */ +#define SER_WRITE 0x8000 /* error occurred during write */ +#define SER_INVAL 0x80 /* PTE had PG_V off */ +#define SER_PROT 0x40 /* operation violated PTE prot */ +#define SER_TIMEOUT 0x20 /* bus timeout (non-existent mem) */ +#define SER_SBUSERR 0x10 /* S-Bus bus error */ +#define SER_MEMERR 0x08 /* memory ecc/parity error */ +#define SER_SZERR 0x02 /* [4/vme?] size error, whatever that is */ +#define SER_WATCHDOG 0x01 /* watchdog reset (never see this) */ + +#define SER_BITS \ +"\20\20WRITE\10INVAL\7PROT\6TIMEOUT\5SBUSERR\4MEMERR\2SZERR\1WATCHDOG" + +/* + * [4/4c] + * Bits in async error register (errors from DVMA or Sun-4 cache + * writeback). The corresponding bit is also set in the sync error reg. + * + * A writeback invalid error means there is a bug in the PTE manager. + * + * The word is that the async error register does not work right. + */ +#define AER_WBINVAL 0x80 /* writeback found PTE without PG_V */ +#define AER_TIMEOUT 0x20 /* bus timeout */ +#define AER_DVMAERR 0x10 /* bus error during DVMA */ + +#define AER_BITS "\20\10WBINVAL\6TIMEOUT\5DVMAERR" + +/* + * [4/4c] Bits in system enable register. + */ +#define SYSEN_DVMA 0x20 /* Enable dvma */ +#define SYSEN_CACHE 0x10 /* Enable cache */ +#define SYSEN_IOCACHE 0x40 /* Enable IO cache */ +#define SYSEN_VIDEO 0x08 /* Enable on-board video */ +#define SYSEN_RESET 0x04 /* Reset the hardware */ +#define SYSEN_RESETVME 0x02 /* Reset the VME bus */ + + +/* + * [4m] Bits in ASI_CONTROL? space, sun4m only. + */ +#define MXCC_ENABLE_ADDR 0x1c00a00 /* Enable register for MXCC */ +#define MXCC_ENABLE_BIT 0x4 /* Enable bit for MXCC */ + +/* + * Bits in ASI_SRMMUFP space. + * Bits 8-11 determine the type of flush/probe. + * Address bits 12-31 hold the page frame. + */ +#define ASI_SRMMUFP_L3 (0<<8) /* probe L3 | flush L3 PTE */ +#define ASI_SRMMUFP_L2 (1<<8) /* probe L2 | flush L2/L3 PTE/PTD's */ +#define ASI_SRMMUFP_L1 (2<<8) /* probe L1 | flush L1/L2/L3 PTE/PTD's*/ +#define ASI_SRMMUFP_L0 (3<<8) /* probe L0 | flush L0/L1/L2/L3 PTE/PTD's */ +#define ASI_SRMMUFP_LN (4<<8) /* probe all | flush all levels */ + +/* + * [4m] Registers and bits in the SPARC Reference MMU (ASI_SRMMU). + */ +#define SRMMU_PCR 0x00000000 /* Processor control register */ +#define SRMMU_CXTPTR 0x00000100 /* Context table pointer register */ +#define SRMMU_CXR 0x00000200 /* Context register */ +#define SRMMU_SFSR 0x00000300 /* Synchronous fault status reg */ +#define SRMMU_SFAR 0x00000400 /* Synchronous fault address reg */ +#define SRMMU_AFSR 0x00000500 /* Asynchronous fault status reg (HS)*/ +#define SRMMU_AFAR 0x00000600 /* Asynchronous fault address reg (HS)*/ +#define SRMMU_PCFG 0x00000600 /* Processor configuration reg (TURBO)*/ +#define SRMMU_TLBCTRL 0x00001000 /* TLB replacement control reg */ + + +/* + * [4m] Bits in SRMMU control register. One set per module. + */ +#define VIKING_PCR_ME 0x00000001 /* MMU Enable */ +#define VIKING_PCR_NF 0x00000002 /* Fault inhibit bit */ +#define VIKING_PCR_PSO 0x00000080 /* Partial Store Ordering enable */ +#define VIKING_PCR_DCE 0x00000100 /* Data cache enable bit */ +#define VIKING_PCR_ICE 0x00000200 /* SuperSPARC instr. cache enable */ +#define VIKING_PCR_SB 0x00000400 /* Store buffer enable bit */ +#define VIKING_PCR_MB 0x00000800 /* MBus mode: 0=MXCC, 1=no MXCC */ +#define VIKING_PCR_PE 0x00001000 /* Enable memory parity checking */ +#define VIKING_PCR_BM 0x00002000 /* 1 iff booting */ +#define VIKING_PCR_SE 0x00004000 /* Coherent bus snoop enable */ +#define VIKING_PCR_AC 0x00008000 /* 1=cache non-MMU accesses */ +#define VIKING_PCR_TC 0x00010000 /* 1=cache table walks */ + +#define HYPERSPARC_PCR_ME 0x00000001 /* MMU Enable */ +#define HYPERSPARC_PCR_NF 0x00000002 /* Fault inhibit bit */ +#define HYPERSPARC_PCR_CE 0x00000100 /* Cache enable bit */ +#define HYPERSPARC_PCR_CM 0x00000400 /* Cache mode: 1=write-back */ +#define HYPERSPARC_PCR_MR 0x00000800 /* Memory reflection: 1 = on */ +#define HYPERSPARC_PCR_CS 0x00001000 /* cache size: 1=256k, 0=128k */ +#define HYPERSPARC_PCR_C 0x00002000 /* enable cache when MMU off */ +#define HYPERSPARC_PCR_BM 0x00004000 /* 1 iff booting */ +#define HYPERSPARC_PCR_MID 0x00078000 /* MBus module ID MID<3:0> */ +#define HYPERSPARC_PCR_WBE 0x00080000 /* Write buffer enable */ +#define HYPERSPARC_PCR_SE 0x00100000 /* Coherent bus snoop enable */ +#define HYPERSPARC_PCR_CWR 0x00200000 /* Cache wrap enable */ + +#define CYPRESS_PCR_ME 0x00000001 /* MMU Enable */ +#define CYPRESS_PCR_NF 0x00000002 /* Fault inhibit bit */ +#define CYPRESS_PCR_CE 0x00000100 /* Cache enable bit */ +#define CYPRESS_PCR_CL 0x00000200 /* Cache Lock (604 only) */ +#define CYPRESS_PCR_CM 0x00000400 /* Cache mode: 1=write-back */ +#define CYPRESS_PCR_MR 0x00000800 /* Memory reflection: 1=on (605 only) */ +#define CYPRESS_PCR_C 0x00002000 /* enable cache when MMU off */ +#define CYPRESS_PCR_BM 0x00004000 /* 1 iff booting */ +#define CYPRESS_PCR_MID 0x00078000 /* MBus module ID MID<3:0> (605 only) */ +#define CYPRESS_PCR_MV 0x00080000 /* Multichip Valid */ +#define CYPRESS_PCR_MCM 0x00300000 /* Multichip Mask */ +#define CYPRESS_PCR_MCA 0x00c00000 /* Multichip Address */ + +#define MS1_PCR_ME 0x00000001 /* MMU Enable */ +#define MS1_PCR_NF 0x00000002 /* Fault inhibit bit */ +#define MS1_PCR_DCE 0x00000100 /* Data cache enable */ +#define MS1_PCR_ICE 0x00000200 /* Instruction cache enable */ +#define MS1_PCR_RC 0x00000c00 /* DRAM Refresh control */ +#define MS1_PCR_PE 0x00001000 /* Enable memory parity checking */ +#define MS1_PCR_BM 0x00004000 /* 1 iff booting */ +#define MS1_PCR_AC 0x00008000 /* 1=cache if ME==0 (and [ID]CE on) */ +#define MS1_PCR_ID 0x00010000 /* 1=disable ITBR */ +#define MS1_PCR_PC 0x00020000 /* Parity control: 0=even,1=odd */ +#define MS1_PCR_MV 0x00100000 /* Memory data View (diag) */ +#define MS1_PCR_DV 0x00200000 /* Data View (diag) */ +#define MS1_PCR_AV 0x00400000 /* Address View (diag) */ +#define MS1_PCR_STW 0x00800000 /* Software Tablewalk enable */ + +#define SWIFT_PCR_ME 0x00000001 /* MMU Enable */ +#define SWIFT_PCR_NF 0x00000002 /* Fault inhibit bit */ +#define SWIFT_PCR_DCE 0x00000100 /* Data cache enable */ +#define SWIFT_PCR_ICE 0x00000200 /* Instruction cache enable */ +#define SWIFT_PCR_RC 0x00003c00 /* DRAM Refresh control */ +#define SWIFT_PCR_BM 0x00004000 /* 1 iff booting */ +#define SWIFT_PCR_AC 0x00008000 /* 1=cache if ME=0 (and [ID]CE on) */ +#define SWIFT_PCR_PA 0x00010000 /* TCX/SX control */ +#define SWIFT_PCR_PC 0x00020000 /* Parity control: 0=even,1=odd */ +#define SWIFT_PCR_PE 0x00040000 /* Enable memory parity checking */ +#define SWIFT_PCR_PMC 0x00180000 /* Page mode control */ +#define SWIFT_PCR_BF 0x00200000 /* Branch Folding */ +#define SWIFT_PCR_WP 0x00400000 /* Watch point enable */ +#define SWIFT_PCR_STW 0x00800000 /* Software Tablewalk enable */ + +#define TURBOSPARC_PCR_ME 0x00000001 /* MMU Enable */ +#define TURBOSPARC_PCR_NF 0x00000002 /* Fault inhibit bit */ +#define TURBOSPARC_PCR_ICS 0x00000004 /* I-cache snoop enable */ +#define TURBOSPARC_PCR_PSO 0x00000008 /* Partial Store order (ro!) */ +#define TURBOSPARC_PCR_DCE 0x00000100 /* Data cache enable */ +#define TURBOSPARC_PCR_ICE 0x00000200 /* Instruction cache enable */ +#define TURBOSPARC_PCR_RC 0x00003c00 /* DRAM Refresh control */ +#define TURBOSPARC_PCR_BM 0x00004000 /* 1 iff booting */ +#define TURBOSPARC_PCR_PC 0x00020000 /* Parity ctrl: 0=even,1=odd */ +#define TURBOSPARC_PCR_PE 0x00040000 /* Enable parity checking */ +#define TURBOSPARC_PCR_PMC 0x00180000 /* Page mode control */ + +/* The Turbosparc's Processor Configuration Register */ +#define TURBOSPARC_PCFG_SCC 0x00000007 /* e-cache config */ +#define TURBOSPARC_PCFG_SE 0x00000008 /* e-cache enable */ +#define TURBOSPARC_PCFG_US2 0x00000010 /* microsparc II compat */ +#define TURBOSPARC_PCFG_WT 0x00000020 /* write-through enable */ +#define TURBOSPARC_PCFG_SBC 0x000000c0 /* SBus Clock */ +#define TURBOSPARC_PCFG_WS 0x03800000 /* DRAM wait states */ +#define TURBOSPARC_PCFG_RAH 0x0c000000 /* DRAM Row Address Hold */ +#define TURBOSPARC_PCFG_AXC 0x30000000 /* AFX Clock */ +#define TURBOSPARC_PCFG_SNP 0x40000000 /* DVMA Snoop enable */ +#define TURBOSPARC_PCFG_IOCLK 0x80000000 /* I/O clock ratio */ + + +/* Implementation and Version fields are common to all modules */ +#define SRMMU_PCR_VER 0x0f000000 /* Version of MMU implementation */ +#define SRMMU_PCR_IMPL 0xf0000000 /* Implementation number of MMU */ + + +/* [4m] Bits in the Synchronous Fault Status Register */ +#define SFSR_EM 0x00020000 /* Error mode watchdog reset occurred */ +#define SFSR_CS 0x00010000 /* Control Space error */ +#define SFSR_PERR 0x00006000 /* Parity error code */ +#define SFSR_SB 0x00008000 /* SS: Store Buffer Error */ +#define SFSR_P 0x00004000 /* SS: Parity error */ +#define SFSR_UC 0x00001000 /* Uncorrectable error */ +#define SFSR_TO 0x00000800 /* S-Bus timeout */ +#define SFSR_BE 0x00000400 /* S-Bus bus error */ +#define SFSR_LVL 0x00000300 /* Pagetable level causing the fault */ +#define SFSR_AT 0x000000e0 /* Access type */ +#define SFSR_FT 0x0000001c /* Fault type */ +#define SFSR_FAV 0x00000002 /* Fault Address is valid */ +#define SFSR_OW 0x00000001 /* Overwritten with new fault */ + +#define SFSR_BITS \ +"\20\21CSERR\17PARITY\16SYSERR\15UNCORR\14TIMEOUT\13BUSERR\2FAV\1OW" + +/* [4m] Synchronous Fault Types */ +#define SFSR_FT_NONE (0 << 2) /* no fault */ +#define SFSR_FT_INVADDR (1 << 2) /* invalid address fault */ +#define SFSR_FT_PROTERR (2 << 2) /* protection fault */ +#define SFSR_FT_PRIVERR (3 << 2) /* privelege violation */ +#define SFSR_FT_TRANSERR (4 << 2) /* translation fault */ +#define SFSR_FT_BUSERR (5 << 2) /* access bus error */ +#define SFSR_FT_INTERR (6 << 2) /* internal error */ +#define SFSR_FT_RESERVED (7 << 2) /* reserved */ + +/* [4m] Synchronous Fault Access Types */ +#define SFSR_AT_LDUDATA (0 << 5) /* Load user data */ +#define SFSR_AT_LDSDATA (1 << 5) /* Load supervisor data */ +#define SFSR_AT_LDUTEXT (2 << 5) /* Load user text */ +#define SFSR_AT_LDSTEXT (3 << 5) /* Load supervisor text */ +#define SFSR_AT_STUDATA (4 << 5) /* Store user data */ +#define SFSR_AT_STSDATA (5 << 5) /* Store supervisor data */ +#define SFSR_AT_STUTEXT (6 << 5) /* Store user text */ +#define SFSR_AT_STSTEXT (7 << 5) /* Store supervisor text */ +#define SFSR_AT_SUPERVISOR (1 << 5) /* Set iff supervisor */ +#define SFSR_AT_TEXT (2 << 5) /* Set iff text */ +#define SFSR_AT_STORE (4 << 5) /* Set iff store */ + +/* [4m] Synchronous Fault PT Levels */ +#define SFSR_LVL_0 (0 << 8) /* Context table entry */ +#define SFSR_LVL_1 (1 << 8) /* Region table entry */ +#define SFSR_LVL_2 (2 << 8) /* Segment table entry */ +#define SFSR_LVL_3 (3 << 8) /* Page table entry */ + +/* [4m] Asynchronous Fault Status Register bits */ +#define AFSR_AFO 0x00000001 /* Async. fault occurred */ +#define AFSR_AFA 0x000000f0 /* Bits <35:32> of faulting phys addr */ +#define AFSR_AFA_RSHIFT 4 /* Shift to get AFA to bit 0 */ +#define AFSR_AFA_LSHIFT 28 /* Shift to get AFA to bit 32 */ +#define AFSR_BE 0x00000400 /* Bus error */ +#define AFSR_TO 0x00000800 /* Bus timeout */ +#define AFSR_UC 0x00001000 /* Uncorrectable error */ +#define AFSR_SE 0x00002000 /* System error */ + +#define AFSR_BITS "\20\16SYSERR\15UNCORR\14TIMEOUT\13BUSERR\1AFO" + +/* [4m] TLB Replacement Control Register bits */ +#define TLBC_DISABLE 0x00000020 /* Disable replacement counter */ +#define TLBC_RCNTMASK 0x0000001f /* Replacement counter (0-31) */ + +/* + * The Ross Hypersparc has an Instruction Cache Control Register (ICCR) + * It contains an enable bit for the on-chip instruction cache and a bit + * that controls whether a FLUSH instruction causes an Unimplemented + * Flush Trap or just flushes the appropriate instruction cache line. + * The ICCR register is implemented as Ancillary State register number 31. + */ +#define HYPERSPARC_ICCR_ICE 1 /* Instruction cache enable */ +#define HYPERSPARC_ICCR_FTD 2 /* Unimpl. flush trap disable */ +#define HYPERSPARC_ASRNUM_ICCR 31 /* ICCR == ASR#31 */ + diff --git a/headers/private/kernel/ctype.h b/headers/private/kernel/ctype.h new file mode 100755 index 0000000000..8728e2d317 --- /dev/null +++ b/headers/private/kernel/ctype.h @@ -0,0 +1,35 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _CTYPE_H +#define _CTYPE_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +int isalnum(int c); +int isalpha(int c); +int iscntrl(int c); +int isdigit(int c); +int isgraph(int c); +int islower(int c); +int isprint(int c); +int ispunct(int c); +int isspace(int c); +int isupper(int c); +int isxdigit(int c); +int isascii(int c); +int toascii(int c); + +unsigned char tolower(unsigned char c); +unsigned char toupper(unsigned char c); + +#ifdef __cplusplus +} /* "C" */ +#endif + +#endif + diff --git a/headers/private/kernel/dbg_console.h b/headers/private/kernel/dbg_console.h new file mode 100755 index 0000000000..d1e8a9aba4 --- /dev/null +++ b/headers/private/kernel/dbg_console.h @@ -0,0 +1,16 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _NEWOS_KERNEL_ARCH_DBG_CONSOLE +#define _NEWOS_KERNEL_ARCH_DBG_CONSOLE + +#include + +char arch_dbg_con_read(void); +char arch_dbg_con_putch(char c); +void arch_dbg_con_puts(const char *s); +int arch_dbg_con_init(kernel_args *ka); + +#endif + diff --git a/headers/private/kernel/debug.h b/headers/private/kernel/debug.h new file mode 100755 index 0000000000..e4f23f41f5 --- /dev/null +++ b/headers/private/kernel/debug.h @@ -0,0 +1,27 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _KERNEL_DEBUG_H +#define _KERNEL_DEBUG_H + +#include +#include +#include + +extern int dbg_register_file[2][14]; /* XXXmpetit -- must be made generic */ + +int dbg_init(kernel_args *ka); +int dbg_init2(kernel_args *ka); +char dbg_putch(char c); +void dbg_puts(const char *s); +bool dbg_set_serial_debug(bool new_val); +bool dbg_get_serial_debug(void); +int dprintf(const char *fmt, ...) __PRINTFLIKE(1,2); +int panic(const char *fmt, ...) __PRINTFLIKE(1,2); +void kernel_debugger(void); +int dbg_add_command(void (*func)(int, char **), const char *cmd, const char *desc); + +extern void dbg_save_registers(int *); /* arch provided */ + +#endif diff --git a/headers/private/kernel/defines.h b/headers/private/kernel/defines.h new file mode 100755 index 0000000000..e7323a4b44 --- /dev/null +++ b/headers/private/kernel/defines.h @@ -0,0 +1,17 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _SYS_DEFINES_H +#define _SYS_DEFINES_H + +/* the following two are for filesystem paths and names */ +#define SYS_MAX_NAME_LEN 128 +#define SYS_MAX_PATH_LEN 512 + +/* the following is for OS object names: semaphores, threads, regions, etc.. */ +#define SYS_MAX_OS_NAME_LEN 32 + +#define SYS_THREAD_ARG_LENGTH_MAX 255 + +#endif diff --git a/headers/private/kernel/dev.h b/headers/private/kernel/dev.h new file mode 100755 index 0000000000..1b8c72ca04 --- /dev/null +++ b/headers/private/kernel/dev.h @@ -0,0 +1,15 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _KERNEL_DEV_H +#define _KERNEL_DEV_H + +#include +#include + +int dev_init(kernel_args *ka); +image_id dev_load_dev_module(const char *name, const char *directory); + +#endif + diff --git a/headers/private/kernel/devfs.h b/headers/private/kernel/devfs.h new file mode 100755 index 0000000000..c871d63341 --- /dev/null +++ b/headers/private/kernel/devfs.h @@ -0,0 +1,16 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _DEVFS_H +#define _DEVFS_H + +#include +#include + +int bootstrap_devfs(void); + +/* api drivers will use to publish devices */ +int devfs_publish_device(const char *path, void *ident, device_hooks *calls); + +#endif /* _DEVFS_H */ diff --git a/headers/private/kernel/devs.h b/headers/private/kernel/devs.h new file mode 100755 index 0000000000..a80c31f22a --- /dev/null +++ b/headers/private/kernel/devs.h @@ -0,0 +1,12 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _NEWOS_KERNEL_ARCH_DEVS_H +#define _NEWOS_KERNEL_ARCH_DEVS_H + +#include + +int devs_init(kernel_args *ka); + +#endif diff --git a/headers/private/kernel/dlfcn.h b/headers/private/kernel/dlfcn.h new file mode 100755 index 0000000000..12be811d58 --- /dev/null +++ b/headers/private/kernel/dlfcn.h @@ -0,0 +1,30 @@ +/* +** Copyright 2002, Manuel J. Petit. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#ifndef __newos__dl_functions__hh__ +#define __newos__dl_functions__hh__ + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +#define RTLD_LAZY 0 +#define RTLD_NOW 1 +#define RLTD_LOCAL 0 +#define RLTD_GLOBAL 2 + +void *dlopen(char const *, unsigned); +int dlclose(void *); +void *dlsym(void *, char const *); + + +#ifdef _cplusplus +} /* "C" */ +#endif + +#endif diff --git a/headers/private/kernel/drivers.h b/headers/private/kernel/drivers.h new file mode 100755 index 0000000000..601299098e --- /dev/null +++ b/headers/private/kernel/drivers.h @@ -0,0 +1,89 @@ +/* +** Copyright 2002, Thomas Kurschel. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#ifndef _DRIVERS_H +#define _DRIVERS_H + +#include +#include + +/* --- + these hooks are how the kernel accesses the device +--- */ + +struct selectsync; +typedef struct selectsync selectsync; + +typedef status_t (*device_open_hook) (const char *name, uint32 flags, void **cookie); +typedef status_t (*device_close_hook) (void *cookie); +typedef status_t (*device_free_hook) (void *cookie); +typedef status_t (*device_control_hook) (void *cookie, uint32 op, void *data, + size_t len); +typedef ssize_t (*device_read_hook) (void *cookie, off_t position, void *data, + size_t *numBytes); +typedef ssize_t (*device_write_hook) (void *cookie, off_t position, + const void *data, size_t *numBytes); +typedef status_t (*device_select_hook) (void *cookie, uint8 event, uint32 ref, + selectsync *sync); +typedef status_t (*device_deselect_hook) (void *cookie, uint8 event, + selectsync *sync); +/* XXX - no iovec support yet +typedef status_t (*device_readv_hook) (void *cookie, off_t position, const iovec *vec, + size_t count, size_t *numBytes); +typedef status_t (*device_writev_hook) (void *cookie, off_t position, const iovec *vec, + size_t count, size_t *numBytes); +*/ + +/* --- + the device_hooks structure is a descriptor for the device, giving its + entry points. +--- */ + +typedef struct { + device_open_hook open; /* called to open the device */ + device_close_hook close; /* called to close the device */ + device_free_hook free; /* called to free the cookie */ + device_control_hook control; /* called to control the device */ + device_read_hook read; /* reads from the device */ + device_write_hook write; /* writes to the device */ + device_select_hook select; /* start select */ + device_deselect_hook deselect; /* stop select */ +/* XXX - no iovec support yet */ +// device_readv_hook readv; /* scatter-gather read from the device */ +// device_writev_hook writev; /* scatter-gather write to the device */ +} device_hooks; + +status_t init_hardware(void); +const char **publish_devices(void); +device_hooks *find_device(const char *name); +status_t init_driver(void); +void uninit_driver(void); + +extern int32 api_version; + +enum { + // called on partition device to get info + IOCTL_DEVFS_GET_PARTITION_INFO = 1000, + // called on raw device to declare one partition + IOCTL_DEVFS_SET_PARTITION, +}; + +typedef struct devfs_partition_info { + // offset and size relative to raw device in bytes + off_t offset; + off_t size; + + // logical block size in bytes + uint32 logical_block_size; + + // session/partition id + uint32 session; + uint32 partition; + + // path of raw device (GET_PARTITION_INFO only) + char raw_device[SYS_MAX_PATH_LEN]; +} devfs_partition_info; + +#endif /* _DRIVERS_H */ diff --git a/headers/private/kernel/elf.h b/headers/private/kernel/elf.h new file mode 100755 index 0000000000..2b42002268 --- /dev/null +++ b/headers/private/kernel/elf.h @@ -0,0 +1,17 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _KERNEL_ELF_H +#define _KERNEL_ELF_H + +#include + +int elf_load_uspace(const char *path, struct proc *p, int flags, addr *entry); +image_id elf_load_kspace(const char *path, const char *sym_prepend); +int elf_unload_kspace( const char *path); +addr elf_lookup_symbol(image_id id, const char *symbol); +int elf_init(kernel_args *ka); + +#endif + diff --git a/headers/private/kernel/elf32.h b/headers/private/kernel/elf32.h new file mode 100755 index 0000000000..9f55aadb5a --- /dev/null +++ b/headers/private/kernel/elf32.h @@ -0,0 +1,217 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _ELF32_H +#define _ELF32_H + +#include + +typedef uint32 Elf32_Addr; +typedef uint16 Elf32_Half; +typedef uint32 Elf32_Off; +typedef int32 Elf32_Sword; +typedef uint32 Elf32_Word; + +#define ELF_MAGIC "\x7f""ELF" +#define EI_MAG0 0 +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_PAD 7 +#define EI_NIDENT 16 + +#define ELFCLASS32 1 +#define ELFCLASS64 2 +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +struct Elf32_Ehdr { + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +} ; + +struct Elf32_Shdr { + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +} ; + +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7fffffff +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0xffffffff + +#define SHF_WRITE 1 + +struct Elf32_Phdr { + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +} ; + +#define PF_X 0x1 +#define PF_W 0x2 +#define PF_R 0x4 +#define PF_MASKPROC 0xf0000000 + + +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff + +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xff00 +#define SHN_LOPROC 0xff00 +#define SHN_HIPROC 0xff1f +#define SHN_ABS 0xfff1 +#define SHN_COMMON 0xfff2 +#define SHN_HIRESERVE 0xffff + +struct Elf32_Sym { + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Half st_shndx; +}; + +#define ELF32_ST_BIND(i) ((i) >> 4) +#define ELF32_ST_TYPE(i) ((i) & 0xf) +#define ELF32_ST_INFO(b, t) (((b) << 4) + ((t) & 0xf)) + +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_LOPROC 13 +#define STT_HIPROC 15 + +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 +#define STB_LOPROC 13 +#define STB_HIPROC 15 + +#define STN_UNDEF 0 + +struct Elf32_Rel { + Elf32_Addr r_offset; + Elf32_Word r_info; +}; + +struct Elf32_Rela { + Elf32_Addr r_offset; + Elf32_Word r_info; + Elf32_Sword r_addend; +}; + +#define ELF32_R_SYM(i) ((i) >> 8) +#define ELF32_R_TYPE(i) ((unsigned char)(i)) +#define ELF32_R_INFO(s, t) (((s) << 8) + (unsigned char)(t)) + +/* + * i386 relocation types + */ +#define R_386_NONE 0 +#define R_386_32 1 +#define R_386_PC32 2 +#define R_386_GOT32 3 +#define R_386_PLT32 4 +#define R_386_COPY 5 +#define R_386_GLOB_DAT 6 +#define R_386_JMP_SLOT 7 +#define R_386_RELATIVE 8 +#define R_386_GOTOFF 9 +#define R_386_GOTPC 10 + +/* + * sh4 relocation types + */ +#define R_SH_NONE 0 +#define R_SH_DIR32 1 +#define R_SH_RELATIVE 0xa5 + +struct Elf32_Dyn { + Elf32_Sword d_tag; + union { + Elf32_Word d_val; + Elf32_Addr d_ptr; + } d_un; +}; + +#define DT_NULL 0 +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_RELASZ 8 +#define DT_RELAENT 9 +#define DT_STRSZ 10 +#define DT_SYMENT 11 +#define DT_INIT 12 +#define DT_FINI 13 +#define DT_SONAME 14 +#define DT_RPATH 15 +#define DT_SYMBOLIC 16 +#define DT_REL 17 +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_DEBUG 21 +#define DT_TEXTREL 22 +#define DT_JMPREL 23 +#define DT_LOPROC 0x70000000 +#define DT_HIPROC 0x7fffffff + +#endif diff --git a/headers/private/kernel/errno.h b/headers/private/kernel/errno.h new file mode 100755 index 0000000000..351557a8a5 --- /dev/null +++ b/headers/private/kernel/errno.h @@ -0,0 +1,149 @@ +/* + * errno.h + * + * POSIX style error codes. + * Be values used where required to keep compatibility. + */ + +#ifndef _POSIX_ERRNO_H +#define _POSIX_ERRNO_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* XXX - this really belongs in limits.h, but as we don't have one + * yet it's here so we can build. + * XXX - move me! + */ +/* Minimum's */ +#ifndef LONG_MIN +#define LONG_MIN (-2147483647L-1) +#endif + +/* XXX - Fix this once TLS works */ +extern int errno; + +/* We're defining values based on the values that Be used, hence + * the starting point at + 0x7000 + */ +#define POSIX_ERROR_START LONG_MIN + 0x7000 + +/* The basic error codes that don't have a B_ equivalent + * + * NB when adding codes make sure that the Be Errors.h didn't + * define a value or it needs to go in the bottom section and + * have an identical value assigned. + * NB new values just go on the bottom. + */ +enum { + E2BIG = POSIX_ERROR_START + 1, + ECHILD, + EDEADLK, + EFBIG, + EMLINK, + ENFILE, + ENODEV, + ENOLCK, + ENOSYS, + ENOTTY, /* +10 */ + ENXIO, + ESPIPE, + ESRCH, + EFPOS, + ESIGPARM, + EDOM, + ERANGE, + EPROTOTYPE, + EPROTONOSUPPORT, + EPFNOSUPPORT, /* +20 */ + EAFNOSUPPORT, + EADDRINUSE, + EADDRNOTAVAIL, + ENETDOWN, + ENETUNREACH, + ENETRESET, + ECONNABORTED, + ECONNRESET, + EISCONN, + ENOTCONN, /* +30 */ + ESHUTDOWN, + ECONNREFUSED, + EHOSTUNREACH, + ENOPROTOOPT, + ENOBUFS, + EINPROGRESS, + EALREADY, + EILSEQ, + ENOMSG, + ESTALE, /* +40 */ + EOVERFLOW, + EMSGSIZE, + EOPNOTSUPP, + ENOTSOCK, + + /* These are additional to the Be ones */ + EBADMSG, + ECANCELLED, + EDESTADDRREQ, + EDQUOT, + EHOSTDOWN, + EIDRM, /* +50 */ + EISDIR, + EMULTIHOP, + ENODATA, + ENOLINK, + ENOSR, + ENOSTR, + EPROTO, + EPROTOOPT, + ETIME, + EFTYPE +}; + +/* + * Errors with Be equivalents + */ + +/* TODO: add comments showing what the equivalent Be errors are... */ + +/* NB - These have strange values to be the same as the Be values... */ + +/* General errors */ +enum { + ENOMEM = LONG_MIN, + EIO, + EACCES, + EINVAL = LONG_MIN + 5, + ETIMEDOUT = LONG_MIN + 9, + EINTR, + EWOULDBLOCK, + EAGAIN = EWOULDBLOCK, + EBUSY = LONG_MIN + 14, + EPERM +}; + +/* Storage kit/File system errors */ +enum { + EBADF = LONG_MIN + 0x6000, + EEXIST = EBADF + 2, + ENOENT, + ENAMETOOLONG, + ENOTDIR, + ENOTEMPTY, + ENOSPC, + EROFS, + EMFILE, + EXDEV, + ELOOP, + EPIPE +}; + +#define ENOEXEC LONG_MIN + 0x1302 + +#ifdef __cplusplus +} /* "C" */ +#endif + +#endif /* _POSIX_ERRNO_H */ diff --git a/headers/private/kernel/faults_priv.h b/headers/private/kernel/faults_priv.h new file mode 100755 index 0000000000..97c6f47caf --- /dev/null +++ b/headers/private/kernel/faults_priv.h @@ -0,0 +1,23 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _KERNEL_FAULTS_PRIV_H +#define _KERNEL_FAULTS_PRIV_H + +int general_protection_fault(int errorcode); + +enum fpu_faults { + FPU_FAULT_CODE_UNKNOWN = 0, + FPU_FAULT_CODE_DIVBYZERO, + FPU_FAULT_CODE_INVALID_OP, + FPU_FAULT_CODE_OVERFLOW, + FPU_FAULT_CODE_UNDERFLOW, + FPU_FAULT_CODE_INEXACT +}; +int fpu_fault(int fpu_fault); + +int fpu_disable_fault(void); + +#endif + diff --git a/headers/private/kernel/fb_console.h b/headers/private/kernel/fb_console.h new file mode 100755 index 0000000000..a13cf6ee5a --- /dev/null +++ b/headers/private/kernel/fb_console.h @@ -0,0 +1,12 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _FB_CONSOLE_DEV_H +#define _FB_CONSOLE_DEV_H + +#include + +int fb_console_dev_init(kernel_args *ka); + +#endif diff --git a/headers/private/kernel/fd.h b/headers/private/kernel/fd.h new file mode 100644 index 0000000000..db847d8fc2 --- /dev/null +++ b/headers/private/kernel/fd.h @@ -0,0 +1,87 @@ +/* file.h + * + * File Descriptors + */ + +#ifndef _FILE_H +#define _FILE_H + +#include +#include +#include +#include +#include + + +struct file_descriptor; +struct vnode; + +/** The I/O context of a process/team, holds the fd array */ +struct io_context { + struct vnode *cwd; + mutex io_mutex; + int table_size; + int num_used_fds; + struct file_descriptor **fds; +}; + +struct fd_ops { + char *fs_name; + ssize_t (*fd_read) (struct file_descriptor *, void *buffer, off_t pos, size_t *length); + ssize_t (*fd_write)(struct file_descriptor *, const void *buffer, off_t pos, size_t *length); + int (*fd_ioctl)(struct file_descriptor *, ulong op, void *buffer, size_t length); +// int (*fd_poll)(struct file_descriptor *, int); + status_t (*fd_read_dir)(struct file_descriptor *,struct dirent *buffer,size_t bufferSize,uint32 *_count); + status_t (*fd_rewind_dir)(struct file_descriptor *); + int (*fd_stat)(struct file_descriptor *, struct stat *); + int (*fd_close)(struct file_descriptor *, int, struct io_context *); + void (*fd_free)(struct file_descriptor *); +}; + +struct file_descriptor { + int32 type; /* descriptor type */ + int32 ref_count; + struct fd_ops *ops; + struct vnode *vnode; + void *cookie; +}; + +//#define DTYPE_VNODE 1 +//#define DTYPE_SOCKET 2 + +/* Types of file descriptors we can create */ + +enum fd_types { + FDTYPE_VNODE = 1, // ToDo: to be removed shortly + FDTYPE_FILE = 1, + FDTYPE_ATTR, + FDTYPE_DIR, + FDTYPE_ATTRDIR, + FDTYPE_INDEX, + FDTYPE_QUERY, + FDTYPE_SOCKET +}; + + +/* Prototypes */ + +struct file_descriptor *alloc_fd(void); +int new_fd(struct io_context *, struct file_descriptor *); +struct file_descriptor *get_fd(struct io_context *, int); +void remove_fd(struct io_context *, int); +void put_fd(struct file_descriptor *); +void free_fd(struct file_descriptor *); +static struct io_context *get_current_io_context(bool kernel); + + +/* Inlines */ + +static __inline struct io_context *get_current_io_context(bool kernel) +{ + if (kernel) + return proc_get_kernel_proc()->ioctx; + + return thread_get_current_thread()->proc->ioctx; +} + +#endif /* _FILE_H */ diff --git a/headers/private/kernel/float.h b/headers/private/kernel/float.h new file mode 100755 index 0000000000..99272bf3ca --- /dev/null +++ b/headers/private/kernel/float.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)float.h 7.1 (Berkeley) 5/8/90 + * $FreeBSD: src/sys/i386/include/float.h,v 1.8 1999/08/28 00:44:11 peter Exp $ + */ + +#ifndef _MACHINE_FLOAT_H_ +#define _MACHINE_FLOAT_H_ 1 + +#define FLT_RADIX 2 /* b */ +#define FLT_ROUNDS 1 /* FP addition rounds to nearest */ + +#define FLT_MANT_DIG 24 /* p */ +#define FLT_EPSILON 1.19209290E-07F /* b**(1-p) */ +#define FLT_DIG 6 /* floor((p-1)*log10(b))+(b == 10) */ +#define FLT_MIN_EXP (-125) /* emin */ +#define FLT_MIN 1.17549435E-38F /* b**(emin-1) */ +#define FLT_MIN_10_EXP (-37) /* ceil(log10(b**(emin-1))) */ +#define FLT_MAX_EXP 128 /* emax */ +#define FLT_MAX 3.40282347E+38F /* (1-b**(-p))*b**emax */ +#define FLT_MAX_10_EXP 38 /* floor(log10((1-b**(-p))*b**emax)) */ + +#define DBL_MANT_DIG 53 +#define DBL_EPSILON 2.2204460492503131E-16 +#define DBL_DIG 15 +#define DBL_MIN_EXP (-1021) +#define DBL_MIN 2.2250738585072014E-308 +#define DBL_MIN_10_EXP (-307) +#define DBL_MAX_EXP 1024 +#define DBL_MAX 1.7976931348623157E+308 +#define DBL_MAX_10_EXP 308 + +#define LDBL_MANT_DIG DBL_MANT_DIG +#define LDBL_EPSILON DBL_EPSILON +#define LDBL_DIG DBL_DIG +#define LDBL_MIN_EXP DBL_MIN_EXP +#define LDBL_MIN DBL_MIN +#define LDBL_MIN_10_EXP DBL_MIN_10_EXP +#define LDBL_MAX_EXP DBL_MAX_EXP +#define LDBL_MAX DBL_MAX +#define LDBL_MAX_10_EXP DBL_MAX_10_EXP +#endif /* _MACHINE_FLOAT_H_ */ diff --git a/headers/private/kernel/font.h b/headers/private/kernel/font.h new file mode 100755 index 0000000000..d1a01a2c78 --- /dev/null +++ b/headers/private/kernel/font.h @@ -0,0 +1,161 @@ +/* $Id: font.h,v 1.1 2002/07/09 12:24:34 ejakowatz Exp $ +** +** Copyright 2001 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define CHAR_WIDTH 6 +#define CHAR_HEIGHT 12 + +static unsigned char FONT[] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, /* '!' */ +0x00, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* '"' */ +0x00, 0x00, 0x14, 0x14, 0x3e, 0x14, 0x3e, 0x14, 0x14, 0x00, 0x00, 0x00, /* '#' */ +0x00, 0x00, 0x08, 0x3c, 0x0a, 0x1c, 0x28, 0x1e, 0x08, 0x00, 0x00, 0x00, /* '$' */ +0x00, 0x00, 0x06, 0x26, 0x10, 0x08, 0x04, 0x32, 0x30, 0x00, 0x00, 0x00, /* '%' */ +0x00, 0x00, 0x1c, 0x02, 0x02, 0x04, 0x2a, 0x12, 0x2c, 0x00, 0x00, 0x00, /* '&' */ +0x00, 0x18, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ''' */ +0x20, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, 0x10, 0x20, 0x00, /* '(' */ +0x02, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x02, 0x00, /* ')' */ +0x00, 0x00, 0x00, 0x08, 0x2a, 0x1c, 0x2a, 0x08, 0x00, 0x00, 0x00, 0x00, /* '*' */ +0x00, 0x00, 0x00, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* '+' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x08, 0x04, 0x00, /* ',' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* '-' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, /* '.' */ +0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x04, 0x02, 0x02, 0x00, 0x00, /* '/' */ +0x00, 0x1c, 0x22, 0x32, 0x2a, 0x26, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* '0' */ +0x00, 0x08, 0x0c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, /* '1' */ +0x00, 0x1c, 0x22, 0x20, 0x10, 0x08, 0x04, 0x02, 0x3e, 0x00, 0x00, 0x00, /* '2' */ +0x00, 0x1c, 0x22, 0x20, 0x18, 0x20, 0x20, 0x22, 0x1c, 0x00, 0x00, 0x00, /* '3' */ +0x00, 0x10, 0x18, 0x18, 0x14, 0x14, 0x3e, 0x10, 0x38, 0x00, 0x00, 0x00, /* '4' */ +0x00, 0x3e, 0x02, 0x02, 0x1e, 0x20, 0x20, 0x22, 0x1c, 0x00, 0x00, 0x00, /* '5' */ +0x00, 0x18, 0x04, 0x02, 0x1e, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* '6' */ +0x00, 0x3e, 0x22, 0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x00, 0x00, 0x00, /* '7' */ +0x00, 0x1c, 0x22, 0x22, 0x1c, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* '8' */ +0x00, 0x1c, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x10, 0x0c, 0x00, 0x00, 0x00, /* '9' */ +0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, /* ':' */ +0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x08, 0x04, 0x00, /* ';' */ +0x00, 0x00, 0x00, 0x30, 0x0c, 0x03, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00, /* '<' */ +0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, /* '=' */ +0x00, 0x00, 0x00, 0x03, 0x0c, 0x30, 0x0c, 0x03, 0x00, 0x00, 0x00, 0x00, /* '>' */ +0x00, 0x1c, 0x22, 0x20, 0x10, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, /* '?' */ +0x00, 0x00, 0x1c, 0x22, 0x3a, 0x3a, 0x1a, 0x02, 0x1c, 0x00, 0x00, 0x00, /* '@' */ +0x00, 0x00, 0x08, 0x14, 0x22, 0x22, 0x3e, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'A' */ +0x00, 0x00, 0x1e, 0x22, 0x22, 0x1e, 0x22, 0x22, 0x1e, 0x00, 0x00, 0x00, /* 'B' */ +0x00, 0x00, 0x1c, 0x22, 0x02, 0x02, 0x02, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'C' */ +0x00, 0x00, 0x0e, 0x12, 0x22, 0x22, 0x22, 0x12, 0x0e, 0x00, 0x00, 0x00, /* 'D' */ +0x00, 0x00, 0x3e, 0x02, 0x02, 0x1e, 0x02, 0x02, 0x3e, 0x00, 0x00, 0x00, /* 'E' */ +0x00, 0x00, 0x3e, 0x02, 0x02, 0x1e, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, /* 'F' */ +0x00, 0x00, 0x1c, 0x22, 0x02, 0x32, 0x22, 0x22, 0x3c, 0x00, 0x00, 0x00, /* 'G' */ +0x00, 0x00, 0x22, 0x22, 0x22, 0x3e, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'H' */ +0x00, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, /* 'I' */ +0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'J' */ +0x00, 0x00, 0x22, 0x12, 0x0a, 0x06, 0x0a, 0x12, 0x22, 0x00, 0x00, 0x00, /* 'K' */ +0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x3e, 0x00, 0x00, 0x00, /* 'L' */ +0x00, 0x00, 0x22, 0x36, 0x2a, 0x2a, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'M' */ +0x00, 0x00, 0x22, 0x26, 0x26, 0x2a, 0x32, 0x32, 0x22, 0x00, 0x00, 0x00, /* 'N' */ +0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'O' */ +0x00, 0x00, 0x1e, 0x22, 0x22, 0x1e, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, /* 'P' */ +0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1c, 0x30, 0x00, 0x00, /* 'Q' */ +0x00, 0x00, 0x1e, 0x22, 0x22, 0x1e, 0x0a, 0x12, 0x22, 0x00, 0x00, 0x00, /* 'R' */ +0x00, 0x00, 0x1c, 0x22, 0x02, 0x1c, 0x20, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'S' */ +0x00, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, /* 'T' */ +0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'U' */ +0x00, 0x00, 0x22, 0x22, 0x22, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00, 0x00, /* 'V' */ +0x00, 0x00, 0x22, 0x22, 0x22, 0x2a, 0x2a, 0x36, 0x22, 0x00, 0x00, 0x00, /* 'W' */ +0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'X' */ +0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, /* 'Y' */ +0x00, 0x00, 0x3e, 0x20, 0x10, 0x08, 0x04, 0x02, 0x3e, 0x00, 0x00, 0x00, /* 'Z' */ +0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, /* '[' */ +0x02, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x00, 0x00, /* '\' */ +0x0e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0e, 0x00, /* ']' */ +0x00, 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* '^' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, /* '_' */ +0x00, 0x0c, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* '`' */ +0x00, 0x00, 0x00, 0x00, 0x3c, 0x22, 0x22, 0x32, 0x2c, 0x00, 0x00, 0x00, /* 'a' */ +0x00, 0x02, 0x02, 0x02, 0x1e, 0x22, 0x22, 0x22, 0x1e, 0x00, 0x00, 0x00, /* 'b' */ +0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x02, 0x02, 0x3c, 0x00, 0x00, 0x00, /* 'c' */ +0x00, 0x20, 0x20, 0x20, 0x3c, 0x22, 0x22, 0x22, 0x3c, 0x00, 0x00, 0x00, /* 'd' */ +0x00, 0x00, 0x00, 0x00, 0x1c, 0x22, 0x3e, 0x02, 0x1c, 0x00, 0x00, 0x00, /* 'e' */ +0x00, 0x38, 0x04, 0x04, 0x1e, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, /* 'f' */ +0x00, 0x00, 0x00, 0x00, 0x3c, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x20, 0x1c, /* 'g' */ +0x00, 0x02, 0x02, 0x02, 0x1e, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'h' */ +0x00, 0x08, 0x08, 0x00, 0x0c, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, /* 'i' */ +0x00, 0x10, 0x10, 0x00, 0x1c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0e, /* 'j' */ +0x00, 0x02, 0x02, 0x02, 0x12, 0x0a, 0x06, 0x0a, 0x12, 0x00, 0x00, 0x00, /* 'k' */ +0x00, 0x0c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, /* 'l' */ +0x00, 0x00, 0x00, 0x00, 0x16, 0x2a, 0x2a, 0x2a, 0x22, 0x00, 0x00, 0x00, /* 'm' */ +0x00, 0x00, 0x00, 0x00, 0x1a, 0x26, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'n' */ +0x00, 0x00, 0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'o' */ +0x00, 0x00, 0x00, 0x00, 0x1e, 0x22, 0x22, 0x22, 0x1e, 0x02, 0x02, 0x02, /* 'p' */ +0x00, 0x00, 0x00, 0x00, 0x3c, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x20, 0x20, /* 'q' */ +0x00, 0x00, 0x00, 0x00, 0x1a, 0x06, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, /* 'r' */ +0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x1c, 0x20, 0x1e, 0x00, 0x00, 0x00, /* 's' */ +0x00, 0x08, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x08, 0x30, 0x00, 0x00, 0x00, /* 't' */ +0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x32, 0x2c, 0x00, 0x00, 0x00, /* 'u' */ +0x00, 0x00, 0x00, 0x00, 0x36, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00, 0x00, /* 'v' */ +0x00, 0x00, 0x00, 0x00, 0x22, 0x2a, 0x2a, 0x2a, 0x14, 0x00, 0x00, 0x00, /* 'w' */ +0x00, 0x00, 0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, /* 'x' */ +0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x20, 0x1c, /* 'y' */ +0x00, 0x00, 0x00, 0x00, 0x3e, 0x10, 0x08, 0x04, 0x3e, 0x00, 0x00, 0x00, /* 'z' */ +0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x10, 0x10, 0x10, 0x10, 0x20, 0x00, /* '{' */ +0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, /* '|' */ +0x02, 0x04, 0x04, 0x04, 0x04, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x00, /* '}' */ +0x00, 0x04, 0x2a, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* '~' */ +0x00, 0x00, 0x00, 0x08, 0x08, 0x14, 0x14, 0x22, 0x3e, 0x00, 0x00, 0x00, /* '' */ +}; diff --git a/headers/private/kernel/gdb.h b/headers/private/kernel/gdb.h new file mode 100755 index 0000000000..a066ffc4c5 --- /dev/null +++ b/headers/private/kernel/gdb.h @@ -0,0 +1,10 @@ +/* +** Copyright 2002, Manuel J. Petit. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _KERNEL_GDB_H +#define _KERNEL_GDB_H + +extern void cmd_gdb(int, char **); + +#endif diff --git a/headers/private/kernel/int.h b/headers/private/kernel/int.h new file mode 100755 index 0000000000..3a740c0b8d --- /dev/null +++ b/headers/private/kernel/int.h @@ -0,0 +1,28 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _KERNEL_INT_H +#define _KERNEL_INT_H + +#include +#include + +int int_init(kernel_args *ka); +int int_init2(kernel_args *ka); +int int_io_interrupt_handler(int vector); +int int_set_io_interrupt_handler(int vector, int (*func)(void*), void* data); +int int_remove_io_interrupt_handler(int vector, int (*func)(void*), void* data); + +#define int_enable_interrupts arch_int_enable_interrupts +#define int_disable_interrupts arch_int_disable_interrupts +#define int_restore_interrupts arch_int_restore_interrupts +#define int_is_interrupts_enabled arch_int_is_interrupts_enabled + +enum { + INT_NO_RESCHEDULE, + INT_RESCHEDULE +}; + +#endif + diff --git a/headers/private/kernel/isa.h b/headers/private/kernel/isa.h new file mode 100755 index 0000000000..e09ef97406 --- /dev/null +++ b/headers/private/kernel/isa.h @@ -0,0 +1,58 @@ +/* +** Copyright 2002, Thomas Kurschel. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +// this is not to be taken seriously - it's just a simple module + +#ifndef __ISA_H__ +#define __ISA_H__ + +#include +#include + +#define ISA_MODULE_NAME "bus_managers/isa/v1" + +typedef struct { + ulong address; /* memory address (little endian!) 4 bytes */ + ushort transfer_count; /* # transfers minus one (little endian!) 2 bytes*/ + uchar reserved; /* filler, 1byte*/ + uchar flag; /* end of link flag, 1byte */ +} isa_dma_entry; + +typedef struct { + bus_manager_info binfo; + uint8 (*read_io_8) (int mapped_io_addr); + void (*write_io_8) (int mapped_io_addr, uint8 value); + uint16 (*read_io_16) (int mapped_io_addr); + void (*write_io_16) (int mapped_io_addr, uint16 value); + uint32 (*read_io_32) (int mapped_io_addr); + void (*write_io_32) (int mapped_io_addr, uint32 value); + void *(*ram_address) (const void *physical_address_in_system_memory); + + long (*make_isa_dma_table) ( + const void *buffer, /* buffer to make a table for */ + long buffer_size, /* buffer size */ + ulong num_bits, /* dma transfer size that will be used */ + isa_dma_entry *table, /* -> caller-supplied scatter/gather table */ + long num_entries /* max # entries in table */ + ); + long (*start_isa_dma) ( + long channel, /* dma channel to use */ + void *buf, /* buffer to transfer */ + long transfer_count, /* # transfers */ + uchar mode, /* mode flags */ + uchar e_mode /* extended mode flags */ + ); + long (*start_scattered_isa_dma) ( + long channel, /* channel # to use */ + const isa_dma_entry *table, /* physical address of scatter/gather table */ + uchar mode, /* mode flags */ + uchar emode /* extended mode flags */ + ); + long (*lock_isa_dma_channel) (long channel); + long (*unlock_isa_dma_channel) (long channel); + +} isa_bus_manager; + +#endif diff --git a/headers/private/kernel/isovol.h b/headers/private/kernel/isovol.h new file mode 100755 index 0000000000..341fc745e8 --- /dev/null +++ b/headers/private/kernel/isovol.h @@ -0,0 +1,106 @@ +#ifndef ISOVOLDESC_H +#define ISOVOLDESC_H + +// Volume Descriptor types +#define ISO_VD_PRIMARY 0x01 +#define ISO_VD_SUPPLEMENTARY 0x02 +#define ISO_VD_END 0xFF + +// Volume Descriptor ID +#define ISO_VD_ID "CD001" + +// Volume Descriptor offset in image +#define ISO_VD_START 0x8000 + +// Index for LE/BE data +#define ISO_LSB_INDEX 0 +#define ISO_MSB_INDEX 1 + +#if 0 +#define PACKED _PACKED +#else +#define PACKED +#endif + +typedef struct iso_vol_date { + char year[4]; // year (*not* ASCIIZ) + char month[2]; // month (1-12) (*not* ASCIIZ) + char day[2]; // day of the month (1-31) (*not* ASCIIZ) + char hour[2]; // hour (00-23) (*not* ASCIIZ) + char minute[2]; // minute (00-59) (*not* ASCIIZ) + char second[2]; // second (00-59) (*not* ASCIIZ) + char hundrSecond[2]; // hundr. of a sec (00-99) (*not* ASCIIZ) + signed char gmtOffset; // offset from GMT, in 15-minute intervals +} PACKED iso_vol_date; + +typedef struct iso_dir_entry { + unsigned char recordLength; // Total length of this record + unsigned char extAttrSecCount; // Number of sectors in extended attr record + unsigned long dataStartSector[2]; // Sector # of 1st data sector for file/dir + unsigned long dataLength[2]; // Length of data for file/directory + unsigned char year; // Years since 1900 + unsigned char month; // Month (1=jan, etc) + unsigned char day; // Day of the month (1-31) + unsigned char hour; // Hour (0-23) + unsigned char minute; // Minute (0-59) + unsigned char second; // Second (0-59) + signed char gmtOffset; // GMT offset in 15 minutes intervals + unsigned char flags; // Flags + unsigned char unitSize; // Unit size for interleaved file (0) + unsigned char gapSize; // Gap size for interleaved file (0) + unsigned short volSeqNumber[2]; // Volume sequence number + unsigned char nameLength; // Length of name + char name[32]; // Name + padding (nameLength [+1]) +} PACKED iso_dir_entry; + +typedef struct iso_path_entry { + unsigned char nameLength; // Length of directory name + unsigned char extAttrSecCount; // Number of sectors in extended attr record + unsigned long dataStartSector; // Sector # of 1st data sector for directory + unsigned short parentDirRec; // Record # of parent directory + unsigned char name[32]; // Name of this entry (nameLength bytes) +} PACKED iso_path_entry; + +typedef struct iso_volume_descriptor { + unsigned char type; // ISO_VD_PRIMARY / ISO_VD_SUPPLEMENTARY + char id[5]; // ISO_VD_ID + unsigned char undef1; // 1 + unsigned char undef2; // 0 + unsigned char systemID[32]; // System Identifier (*not* ASCIIZ) + unsigned char volumeID[32]; // Volume Identifier (*not* ASCIIZ) + unsigned char undef3[8]; // all 0 + unsigned long numSectors[2]; // Total Number Of Sectors (little+big endian) + unsigned char undef4[32]; // all 0 + unsigned short volSetSize[2]; // Volume Set Size (little+big endian) + unsigned short volSeqNumber[2]; // Volume Sequence Number (little+big endian) + unsigned short sectorSize[2]; // Sector Size (little+big endian) + unsigned long pathTblSize[2]; // Path Table Size (bytes) (little+big endian) + unsigned long lePathTbl1Sector; // First sector of LE Path Table + unsigned long lePathTbl2Sector; // First sector of 2nd LE Path Table + unsigned long bePathTbl1Sector; // First sector of BE Path Table + unsigned long bePathTbl2Sector; // First sector of 2nd BE Path Table + + /* Root Directory Entry */ + unsigned char rootDirEntry[34]; // To use, cast to iso_dir_entry + + char volumeSetID[128]; // Volume Set Identifier (*not* ASCIIZ) + char publisherID[128]; // Publisher Identifier (*not* ASCIIZ) + char dataPreparerID[128];// Data Preparer Identifier (*not* ASCIIZ) + char applicationID[128]; // Application Identifier (*not* ASCIIZ) + + char copyrightFile[37]; // Copyright File Identifier(*not* ASCIIZ) + char abstractFile[37]; // Abstract File Identifier (*not* ASCIIZ) + char bibliogrFile[37]; // Bibliographical File Id. (*not* ASCIIZ) + + iso_vol_date dateCreation; // Date and Time of volume creation + iso_vol_date dateModification; // Date and Time of volume modification + iso_vol_date dateExpires; // Date and Time that volume expires + iso_vol_date dateEffective; // Date and Time that volume comes effective + + unsigned char undef5; // 1 + unsigned char undef6; // 0 + unsigned char forAppUse[512]; // usually zeroes + unsigned char undef7[653]; // all 0 +} PACKED iso_volume_descriptor; + +#endif diff --git a/headers/private/kernel/kernel.h b/headers/private/kernel/kernel.h new file mode 100644 index 0000000000..961dcd71ef --- /dev/null +++ b/headers/private/kernel/kernel.h @@ -0,0 +1,59 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _KERNEL_KERNEL_H +#define _KERNEL_KERNEL_H + +/** + * @file kernel/kernel.h + * @brief Kernel Definitions + */ + +/** + * @defgroup OpenBeOS_Kernel OpenBeOS Kernel + * @brief The OpenBeOS Kernel + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* david - same fiddle as stage2.h. Renamed the arch specific + * kernel.h file into arch_kernel.h and then just include + * it here as the arch specific directories are included on the + * include paths for the build. + */ + +#include + +/** + * Size of the kernel stack + */ +#define KSTACK_SIZE (PAGE_SIZE*2) +/** + * Size of the stack given to processes + */ +#define STACK_SIZE (PAGE_SIZE*16) + + +#define ROUNDUP(a, b) (((a) + ((b)-1)) & ~((b)-1)) +#define ROUNDOWN(a, b) (((a) / (b)) * (b)) + +#define min(a, b) ((a) < (b) ? (a) : (b)) +#define max(a, b) ((a) > (b) ? (a) : (b)) + +/** Is bit 'b' set in 'a' */ +#define CHECK_BIT(a, b) ((a) & (1 << (b))) +/** Set bit 'b' in 'a' */ +#define SET_BIT(a, b) ((a) | (1 << (b))) +/** Unset bit 'b' in 'a' */ +#define CLEAR_BIT(a, b) ((a) & (~(1 << (b)))) + +#ifdef __cplusplus +} +#endif +/** @} */ + +#endif /* _KERNEL_KERNEL_H */ diff --git a/headers/private/kernel/khash.h b/headers/private/kernel/khash.h new file mode 100755 index 0000000000..6374cef0ca --- /dev/null +++ b/headers/private/kernel/khash.h @@ -0,0 +1,40 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _KERNEL_KHASH_H +#define _KERNEL_KHASH_H + +struct hash_iterator { + void *ptr; + int bucket; +}; + +void *hash_init(unsigned int table_size, int next_ptr_offset, + int compare_func(void *a, const void *key), + unsigned int hash_func(void *a, const void *key, unsigned int range)); +int hash_uninit(void *_hash_table); +int hash_insert(void *_hash_table, void *_elem); +int hash_remove(void *_hash_table, void *_elem); +void *hash_find(void *_hash_table, void *e); +void *hash_lookup(void *_hash_table, const void *key); +struct hash_iterator *hash_open(void *_hash_table, struct hash_iterator *i); +void hash_close(void *_hash_table, struct hash_iterator *i, bool free_iterator); +void *hash_next(void *_hash_table, struct hash_iterator *i); +void hash_rewind(void *_hash_table, struct hash_iterator *i); + +/* function ptrs must look like this: + // hash function should calculate hash on either e or key, + // depending on which one is not NULL +unsigned int hash_func(void *e, const void *key, unsigned int range); + // compare function should compare the element with + // the key, returning 0 if equal, other if not + // NOTE: compare func can be null, in which case the hash + // code will compare the key pointer with the target +int compare_func(void *e, const void *key); +*/ + +unsigned int hash_hash_str( const char *str ); + +#endif + diff --git a/headers/private/kernel/ksocket.h b/headers/private/kernel/ksocket.h new file mode 100644 index 0000000000..da4be195fb --- /dev/null +++ b/headers/private/kernel/ksocket.h @@ -0,0 +1,30 @@ +/* socket.h + * Very simply file. This will grow! + */ + +/** + * @file ksocket.h + * @brief Kernel socket definitions + * These never need to be seen outside of the kernel and no user + * application should ever include this file. + */ + +#ifndef _KERNEL_KSOCKET_H +#define _KERNEL_KSOCKET_H + +/** + * @defgroup KSOCKET Kernel Socket Definitions + * @brief Kernel socket prototypes and definitions + * @ingroup OpenBeOS_Kernel + * @{ + */ + +#ifdef _KERNEL_MODE +int socket(int, int, int, bool); + + + +#endif +/** @} */ + +#endif /* _KERNEL_KSOCKET_H */ diff --git a/headers/private/kernel/ksyscalls.h b/headers/private/kernel/ksyscalls.h new file mode 100755 index 0000000000..7f684ba1f8 --- /dev/null +++ b/headers/private/kernel/ksyscalls.h @@ -0,0 +1,90 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#ifndef _KERNEL_SYSCALLS_H +#define _KERNEL_SYSCALLS_H + +enum { + SYSCALL_NULL = 0, + SYSCALL_MOUNT, + SYSCALL_UNMOUNT, + SYSCALL_SYNC, + SYSCALL_OPEN, + SYSCALL_CLOSE, + SYSCALL_FSYNC, + SYSCALL_READ, + SYSCALL_WRITE, + SYSCALL_SEEK, + SYSCALL_IOCTL, /* 10 */ + SYSCALL_CREATE, + SYSCALL_UNLINK, + SYSCALL_RENAME, + SYSCALL_RSTAT, + SYSCALL_WSTAT, + SYSCALL_SYSTEM_TIME, + SYSCALL_SNOOZE, + SYSCALL_SEM_CREATE, + SYSCALL_SEM_DELETE, + SYSCALL_SEM_ACQUIRE, /* 20 */ + SYSCALL_SEM_ACQUIRE_ETC, + SYSCALL_SEM_RELEASE, + SYSCALL_SEM_RELEASE_ETC, + SYSCALL_GET_CURRENT_THREAD_ID, + SYSCALL_EXIT_THREAD, + SYSCALL_PROC_CREATE_PROC, + SYSCALL_THREAD_WAIT_ON_THREAD, + SYSCALL_PROC_WAIT_ON_PROC, + SYSCALL_VM_CREATE_ANONYMOUS_REGION, + SYSCALL_VM_CLONE_REGION, /* 30 */ + SYSCALL_VM_MAP_FILE, + SYSCALL_VM_DELETE_REGION, + SYSCALL_VM_GET_REGION_INFO, + SYSCALL_VM_FIND_REGION_BY_NAME, + SYSCALL_SPAWN_THREAD, + SYSCALL_KILL_THREAD, + SYSCALL_SUSPEND_THREAD, + SYSCALL_RESUME_THREAD, + SYSCALL_PROC_KILL_PROC, + SYSCALL_GET_CURRENT_PROC_ID, + SYSCALL_GETCWD, /* 40 */ + SYSCALL_SETCWD, + SYSCALL_PORT_CREATE, + SYSCALL_PORT_CLOSE, + SYSCALL_PORT_DELETE, + SYSCALL_PORT_FIND, + SYSCALL_PORT_GET_INFO, + SYSCALL_PORT_GET_NEXT_PORT_INFO, + SYSCALL_PORT_BUFFER_SIZE, + SYSCALL_PORT_BUFFER_SIZE_ETC, + SYSCALL_PORT_COUNT, /* 50 */ + SYSCALL_PORT_READ, + SYSCALL_PORT_READ_ETC, + SYSCALL_PORT_SET_OWNER, + SYSCALL_PORT_WRITE, + SYSCALL_PORT_WRITE_ETC, + SYSCALL_SEM_GET_COUNT, + SYSCALL_SEM_GET_SEM_INFO, + SYSCALL_SEM_GET_NEXT_SEM_INFO, + SYSCALL_SEM_SET_SEM_OWNER, + SYSCALL_FDDUP, /* 60 */ + SYSCALL_FDDUP2, + SYSCALL_GET_PROC_TABLE, + SYSCALL_GETRLIMIT, + SYSCALL_SETRLIMIT, + SYSCALL_ATOMIC_ADD, + SYSCALL_ATOMIC_AND, + SYSCALL_ATOMIC_OR, + SYSCALL_ATOMIC_SET, + SYSCALL_TEST_AND_SET,/* 70 */ + SYSCALL_SYSCTL, + SYSCALL_SOCKET, + SYSCALL_GETDTABLESIZE, + SYSCALL_FSTAT +}; + +int syscall_dispatcher(unsigned long call_num, void *arg_buffer, uint64 *call_ret); + +#endif + diff --git a/headers/private/kernel/ktypes.h b/headers/private/kernel/ktypes.h new file mode 100755 index 0000000000..4ac8bd221f --- /dev/null +++ b/headers/private/kernel/ktypes.h @@ -0,0 +1,91 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _KERNEL_KTYPES_H +#define _KERNEL_KTYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef uint16 mode_t; +typedef int pid_t; +typedef int thread_id; +typedef int region_id; +typedef int aspace_id; +typedef int proc_id; +typedef int sem_id; +typedef int port_id; +typedef int image_id; +typedef uint64 ino_t; +typedef uint64 vnode_id; +typedef uint32 fs_id; +typedef uint16 nlink_t; +typedef uint32 uid_t; +typedef uint32 gid_t; + +/* compat with beos (was int32 on beos) */ +typedef int status_t; + + +#ifdef _OBOS_TIME_T_ +typedef _OBOS_TIME_T_ time_t; +#undef _OBOS_TIME_T_ +#endif /* _OBOS_TIME_T_ */ + +typedef int64 bigtime_t; + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef __cplusplus + +#define false 0 +#define true 1 + +typedef int bool; + +#endif + +/* + * XXX serious hack that doesn't really solve the problem. + * As of right now, some versions of the toolchain expect size_t to + * be unsigned long (newer ones than 2.95.2 and beos), and the older + * ones need it to be unsigned int. It's an actual failure when + * operator new is declared. This will have to be resolved in the future. + */ + +#ifdef __BEOS__ +typedef unsigned long size_t; +typedef signed long ssize_t; +#else +typedef unsigned int size_t; +typedef signed int ssize_t; +#endif +typedef int64 off_t; + +typedef unsigned char u_char; +typedef unsigned short u_short; +typedef unsigned int u_int; +typedef unsigned long u_long; + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned int uint; +typedef unsigned long ulong; + +// Handled in arch_ktypes.h + +//typedef unsigned long addr; + +typedef uint32 socklen_t; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/headers/private/kernel/lock.h b/headers/private/kernel/lock.h new file mode 100755 index 0000000000..01335f6414 --- /dev/null +++ b/headers/private/kernel/lock.h @@ -0,0 +1,123 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _KERNEL_LOCK_H +#define _KERNEL_LOCK_H + +#include + +typedef struct recursive_lock { + thread_id holder; + int recursion; + sem_id sem; +} recursive_lock; + +int recursive_lock_create(recursive_lock *lock); +void recursive_lock_destroy(recursive_lock *lock); +bool recursive_lock_lock(recursive_lock *lock); +bool recursive_lock_unlock(recursive_lock *lock); +int recursive_lock_get_recursion(recursive_lock *lock); + +typedef struct mutex { + int count; + sem_id sem; +} mutex; + +int mutex_init(mutex *m, const char *name); +void mutex_destroy(mutex *m); +void mutex_lock(mutex *m); +void mutex_unlock(mutex *m); + +// for read/write locks +#define MAX_READERS 100000 + +struct benaphore { + sem_id sem; + int32 count; +}; + +typedef struct benaphore benaphore; + +// it may make sense to add a status field to the rw_lock to +// be able to check if the semaphore could be locked + +struct rw_lock { + sem_id sem; + int32 count; + benaphore writeLock; +}; + +typedef struct rw_lock rw_lock; + +#define INIT_BENAPHORE(lock,name) \ + { \ + (lock).count = 1; \ + (lock).sem = create_sem(0, name); \ + } + +#define CHECK_BENAPHORE(lock) \ + ((lock).sem) + +#define UNINIT_BENAPHORE(lock) \ + delete_sem((lock).sem); + +#define ACQUIRE_BENAPHORE(lock) \ + (atomic_add(&((lock).count), -1) <= 0 ? \ + acquire_sem_etc((lock).sem, 1, B_CAN_INTERRUPT, 0) \ + : 0) + +#define RELEASE_BENAPHORE(lock) \ + { \ + if (atomic_add(&((lock).count), 1) < 0) \ + release_sem_etc((lock).sem, 1, B_CAN_INTERRUPT); \ + } + +/* read/write lock */ +#define INIT_RW_LOCK(lock,name) \ + { \ + (lock).sem = create_sem(0, name); \ + (lock).count = MAX_READERS; \ + INIT_BENAPHORE((lock).writeLock, "r/w write lock"); \ + } + +#define CHECK_RW_LOCK(lock) \ + ((lock).sem) + +#define UNINIT_RW_LOCK(lock) \ + delete_sem((lock).sem); \ + UNINIT_BENAPHORE((lock).writeLock) + +#define ACQUIRE_READ_LOCK(lock) \ + { \ + if (atomic_add(&(lock).count, -1) <= 0) \ + acquire_sem_etc((lock).sem, 1, B_CAN_INTERRUPT, 0); \ + } + +#define RELEASE_READ_LOCK(lock) \ + { \ + if (atomic_add(&(lock).count, 1) < 0) \ + release_sem_etc((lock).sem, 1, B_CAN_INTERRUPT); \ + } + +#define ACQUIRE_WRITE_LOCK(lock) \ + { \ + int32 readers; \ + ACQUIRE_BENAPHORE((lock).writeLock); \ + readers = atomic_add(&(lock).count, -MAX_READERS); \ + if (readers < MAX_READERS) \ + acquire_sem_etc((lock).sem,readers <= 0 ? 1 : MAX_READERS - readers, \ + B_CAN_INTERRUPT,0); \ + RELEASE_BENAPHORE((lock).writeLock); \ + } + +#define RELEASE_WRITE_LOCK(lock) \ + { \ + int32 readers = atomic_add(&(lock).count,MAX_READERS); \ + if (readers < 0) \ + release_sem_etc((lock).sem,readers <= -MAX_READERS ? 1 : -readers,B_CAN_INTERRUPT); \ + } + + +#endif + diff --git a/headers/private/kernel/math.h b/headers/private/kernel/math.h new file mode 100755 index 0000000000..480258e8aa --- /dev/null +++ b/headers/private/kernel/math.h @@ -0,0 +1,285 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * from: @(#)fdlibm.h 5.1 93/09/24 + * $FreeBSD: src/lib/msun/src/math.h,v 1.8 1999/08/28 00:06:42 peter Exp $ + */ + +#ifndef _MATH_H_ +#define _MATH_H_ + +/* + * ANSI/POSIX + */ +extern char __infinity[]; +#define HUGE_VAL (*(double *) __infinity) + +/* + * XOPEN/SVID + */ +#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE) +#define M_E 2.7182818284590452354 /* e */ +#define M_LOG2E 1.4426950408889634074 /* log 2e */ +#define M_LOG10E 0.43429448190325182765 /* log 10e */ +#define M_LN2 0.69314718055994530942 /* log e2 */ +#define M_LN10 2.30258509299404568402 /* log e10 */ +#define M_PI 3.14159265358979323846 /* pi */ +#define M_PI_2 1.57079632679489661923 /* pi/2 */ +#define M_PI_4 0.78539816339744830962 /* pi/4 */ +#define M_1_PI 0.31830988618379067154 /* 1/pi */ +#define M_2_PI 0.63661977236758134308 /* 2/pi */ +#define M_2_SQRTPI 1.12837916709551257390 /* 2/sqrt(pi) */ +#define M_SQRT2 1.41421356237309504880 /* sqrt(2) */ +#define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */ + +#define MAXFLOAT ((float)3.40282346638528860e+38) +extern int signgam; + +#if !defined(_XOPEN_SOURCE) +enum fdversion {fdlibm_ieee = -1, fdlibm_svid, fdlibm_xopen, fdlibm_posix}; + +#define _LIB_VERSION_TYPE enum fdversion +#define _LIB_VERSION _fdlib_version + +/* if global variable _LIB_VERSION is not desirable, one may + * change the following to be a constant by: + * #define _LIB_VERSION_TYPE const enum version + * In that case, after one initializes the value _LIB_VERSION (see + * s_lib_version.c) during compile time, it cannot be modified + * in the middle of a program + */ +extern _LIB_VERSION_TYPE _LIB_VERSION; + +#define _IEEE_ fdlibm_ieee +#define _SVID_ fdlibm_svid +#define _XOPEN_ fdlibm_xopen +#define _POSIX_ fdlibm_posix + +#ifndef __cplusplus +struct exception { + int type; + char *name; + double arg1; + double arg2; + double retval; +}; +#endif + +#define HUGE MAXFLOAT + +/* + * set X_TLOSS = pi*2**52, which is possibly defined in + * (one may replace the following line by "#include ") + */ + +#define X_TLOSS 1.41484755040568800000e+16 + +#define DOMAIN 1 +#define SING 2 +#define OVERFLOW 3 +#define UNDERFLOW 4 +#define TLOSS 5 +#define PLOSS 6 + +#endif /* !_XOPEN_SOURCE */ +#endif /* !_ANSI_SOURCE && !_POSIX_SOURCE */ + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* + * ANSI/POSIX + */ +extern double acos(double); +extern double asin(double); +extern double atan(double); +extern double atan2(double, double); +extern double cos(double); +extern double sin(double); +extern double tan(double); + +extern double cosh(double); +extern double sinh(double); +extern double tanh(double); + +extern double exp(double); +extern double frexp(double, int *); +extern double ldexp(double, int); +extern double log(double); +extern double log10(double); +extern double modf(double, double *); + +extern double pow(double, double); +extern double sqrt(double); + +extern double ceil(double); +extern double fabs(double); +extern double floor(double); +extern double fmod(double, double); + +#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE) +extern double erf(double); +extern double erfc(double); +extern double gamma(double); +extern double hypot(double, double); +extern int isinf(double); +extern int isnan(double); +extern int finite(double); +extern double j0(double); +extern double j1(double); +extern double jn(int, double); +extern double lgamma(double); +extern double y0(double); +extern double y1(double); +extern double yn(int, double); + +#if !defined(_XOPEN_SOURCE) +extern double acosh(double); +extern double asinh(double); +extern double atanh(double); +extern double cbrt(double); +extern double logb(double); +extern double nextafter(double, double); +extern double remainder(double, double); +extern double scalb(double, double); + +#ifndef __cplusplus +extern int matherr(struct exception *); +#endif + +/* + * IEEE Test Vector + */ +extern double significand(double); + +/* + * Functions callable from C, intended to support IEEE arithmetic. + */ +extern double copysign(double, double); +extern int ilogb(double); +extern double rint(double); +extern double scalbn(double, int); + +/* + * BSD math library entry points + */ +struct complex { double x, y; }; +extern double cabs(struct complex); +extern double drem(double, double); +extern double expm1(double); +extern double log1p(double); +extern double z_abs(struct complex const *); /* complete non standard */ + +/* + * Reentrant version of gamma & lgamma; passes signgam back by reference + * as the second argument; user must allocate space for signgam. + */ +#ifdef _REENTRANT +extern double gamma_r(double, int *); +extern double lgamma_r(double, int *); +#endif /* _REENTRANT */ + + +/* float versions of ANSI/POSIX functions */ +extern float acosf(float); +extern float asinf(float); +extern float atanf(float); +extern float atan2f(float, float); +extern float cosf(float); +extern float sinf(float); +extern float tanf(float); + +extern float coshf(float); +extern float sinhf(float); +extern float tanhf(float); + +extern float expf(float); +extern float frexpf(float, int *); +extern float ldexpf(float, int); +extern float logf(float); +extern float log10f(float); +extern float modff(float, float *); + +extern float powf(float, float); +extern float sqrtf(float); + +extern float ceilf(float); +extern float fabsf(float); +extern float floorf(float); +extern float fmodf(float, float); + +extern float erff(float); +extern float erfcf(float); +extern float gammaf(float); +extern float hypotf(float, float); +extern int isnanf(float); +extern int finitef(float); +extern float j0f(float); +extern float j1f(float); +extern float jnf(int, float); +extern float lgammaf(float); +extern float y0f(float); +extern float y1f(float); +extern float ynf(int, float); + +extern float acoshf(float); +extern float asinhf(float); +extern float atanhf(float); +extern float cbrtf(float); +extern float logbf(float); +extern float nextafterf(float, float); +extern float remainderf(float, float); +extern float scalbf(float, float); + +/* + * float version of IEEE Test Vector + */ +extern float significandf(float); + +/* + * Float versions of functions callable from C, intended to support + * IEEE arithmetic. + */ +extern float copysignf(float, float); +extern int ilogbf(float); +extern float rintf(float); +extern float scalbnf(float, int); + +/* + * float versions of BSD math library entry points + */ +extern float cabsf (); +extern float dremf(float, float); +extern float expm1f(float); +extern float log1pf(float); + +/* + * Float versions of reentrant version of gamma & lgamma; passes + * signgam back by reference as the second argument; user must + * allocate space for signgam. + */ +#ifdef _REENTRANT +extern float gammaf_r(float, int *); +extern float lgammaf_r(float, int *); +#endif /* _REENTRANT */ + +#endif /* !_XOPEN_SOURCE */ +#endif /* !_ANSI_SOURCE && !_POSIX_SOURCE */ + +#ifdef __cplusplus +} /* "C" */ +#endif + +#endif /* _MATH_H_ */ diff --git a/headers/private/kernel/mathimpl.h b/headers/private/kernel/mathimpl.h new file mode 100755 index 0000000000..eee54a6931 --- /dev/null +++ b/headers/private/kernel/mathimpl.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)mathimpl.h 8.1 (Berkeley) 6/4/93 + */ + +#include +#include + +#if defined(vax)||defined(tahoe) + +/* Deal with different ways to concatenate in cpp */ +# ifdef __STDC__ +# define cat3(a,b,c) a ## b ## c +# else +# define cat3(a,b,c) a/**/b/**/c +# endif + +/* Deal with vax/tahoe byte order issues */ +# ifdef vax +# define cat3t(a,b,c) cat3(a,b,c) +# else +# define cat3t(a,b,c) cat3(a,c,b) +# endif + +# define vccast(name) (*(const double *)(cat3(name,,x))) + + /* + * Define a constant to high precision on a Vax or Tahoe. + * + * Args are the name to define, the decimal floating point value, + * four 16-bit chunks of the float value in hex + * (because the vax and tahoe differ in float format!), the power + * of 2 of the hex-float exponent, and the hex-float mantissa. + * Most of these arguments are not used at compile time; they are + * used in a post-check to make sure the constants were compiled + * correctly. + * + * People who want to use the constant will have to do their own + * #define foo vccast(foo) + * since CPP cannot do this for them from inside another macro (sigh). + * We define "vccast" if this needs doing. + */ +# define vc(name, value, x1,x2,x3,x4, bexp, xval) \ + static long const cat3(name,,x)[] = {cat3t(0x,x1,x2), cat3t(0x,x3,x4)}; + +# define ic(name, value, bexp, xval) ; + +#else /* vax or tahoe */ + + /* Hooray, we have an IEEE machine */ +# undef vccast +# define vc(name, value, x1,x2,x3,x4, bexp, xval) ; + +# define ic(name, value, bexp, xval) \ + static double const name = value; + +#endif /* defined(vax)||defined(tahoe) */ + + +/* + * Functions internal to the math package, yet not static. + */ +extern double __exp__E(double, double); +extern double __log__L(double); + +struct Double {double a, b;}; +double __exp__D(double, double); +struct Double __log__D(double); diff --git a/headers/private/kernel/mbuf.h b/headers/private/kernel/mbuf.h new file mode 100644 index 0000000000..dc69b92d44 --- /dev/null +++ b/headers/private/kernel/mbuf.h @@ -0,0 +1,319 @@ +/* mbuf.h + * network buffer definitions + * + * Based on BSD's mbuf principal. + */ + + +#ifndef OBOS_MBUF_H +#define OBOS_MBUF_H + +#include + +/* MBuf's are all of a single size, MSIZE bytes. If we have more data + * than can be fitted we can add a single "MBuf cluster" which is of + * fixed size MCLBYTES. + * If the data to be written is larger than MCLMINBYTES bytes we won't use + * the storage provided within the MBuf, but rather all data will go + * directly into an added cluster. + */ + +#define MSIZE 256 /* total size of structure */ +#define MCLSHIFT 11 +#define MCLBYTES (1 << MCLSHIFT) + +#define MCLMAXBYTES 2048 /* they can't be bigger than 2k */ +#define MLEN (MSIZE - sizeof(struct m_hdr)) /* data length w/o a pkt_hdr */ +#define MHLEN (MLEN - sizeof(struct pkt_hdr)) /* data length w/pkt_hdr */ +#define CLLEN (MCLBYTES - sizeof(struct cl_hdr)) + +#define MINCLSIZE (MHLEN + 1) + +/* mbuf header structure + * This appears at teh start of every MBuf + */ +struct m_hdr { + struct mbuf *m_next; /* next mbuf in a chain */ + struct mbuf *m_nxtpkt; /* next chain in a packet/queue */ + char * m_data; /* pointer to data */ + uint32 m_len; /* length data in this mbuf NB NOT total length */ + uint16 m_type; /* what sort of data do we have ? */ + uint16 m_flags; /* flags as defined below */ + uint16 m_cksum; /* flags about the checksum on the packet */ +}; + +/* pkt_hdr + * This is ONLY found in the first MBuf in a chain and is valid + * ONLY if we have the M_PKTHDR flag is set + */ +/* XXX - we also need to record things like the interface and also maintain + * a list of the packets associated with this message here. + */ +struct pkt_hdr { + struct ifnet *rcvif; /* interface we came it on */ + int len; /* total length */ + int csum; /* hardware cksum info... */ +}; + +/* m_ext + * External storage, i.e. a cluster + */ +struct m_ext { + char *ext_buf; /* start of the buffer */ +// void *(ext_free)(); /* free routine (if not standard) */ + uint ext_size; /* how big is the buffer */ +}; + +/* struct mbuf + * The actual buffer structure. + * This is defined as unions as the size is slightly variable + * depending on the options set. + */ + +struct mbuf { + struct m_hdr m_hdr; + union { + struct { + struct pkt_hdr MH_pkthdr; + union { + struct m_ext MH_ext; + char MH_databuf[MHLEN]; + } MH_dat; + } MH; + char m_databuf[MLEN]; + } um_dat; +}; + +/* these are simply shortcuts... */ +#define m_next m_hdr.m_next +#define m_len m_hdr.m_len +#define m_data m_hdr.m_data +#define m_type m_hdr.m_type +#define m_flags m_hdr.m_flags +#define m_cksum m_hdr.m_cksum +#define m_nextpkt m_hdr.m_nxtpkt +#define m_ext um_dat.MH.MH_dat.MH_ext +#define m_pktdat um_dat.MH.MH_dat.MH_databuf +#define m_pkthdr um_dat.MH.MH_pkthdr +#define m_dat um_dat.m_databuf + +/* define a little macro that gives us the data pointer for an mbuf */ +#define mtod(m, t) ((t)((m)->m_data)) +#define dtom(x) ((struct mbuf *)((int)(x) & ~(MSIZE-1))) + +/* mbuf flags */ +enum { + M_EXT = 0x0001, /* has extenal storage attached */ + M_PKTHDR = 0x0002, /* contains the packet header */ + M_EOR = 0x0004, /* end of record (not used for tcp/udp) */ + M_CLUSTER = 0x0008, /* external storage is a cluster */ +/* + M_PROTO = 0x0010, * protocol specific * +*/ + M_BCAST = 0x0100, /* rx/tx as a link-level broadcast */ + M_MCAST = 0x0200, /* rx/tx as a link-level multicast */ + M_CONF = 0x0400, /* packet was encrypted?? */ + M_AUTH = 0x0800, /* packet was authenticated */ + M_COMP = 0x1000, /* packet was compressed */ + M_ANYCAST6 = 0x4000 /* it was an IPv6 anycast packet */ +}; +/* the M_COPYFLAGS lists the flags that can be copied when we copy + * an mbuf with the M_PKTHDR flag set */ +#define M_COPYFLAGS (M_PKTHDR | M_EOR | M_BCAST | M_MCAST) + +/* checksum flags */ +enum { + M_IPV4_CSUM_OUT = 0x0001, /* ipv4 checksum required */ + M_TCPV4_CSUM_OUT = 0x0002, /* TCP v4 checksum required */ + M_UDPV4_CSUM_OUT = 0x0004, + + M_IPV4_CSUM_IN_OK = 0x0008, + M_IPV4_CSUM_IN_OUT = 0x0010, + + M_TCP_CSUM_IN_OK = 0x0020, + M_TCP_CSUM_IN_BAD = 0x0040, + + M_UDP_CSUM_IN_OK = 0x0080, + M_UDP_CSUM_IN_BAD = 0x0100 +}; + +/* MBuf types */ +enum { + MT_FREE = 0, /* should be on free list */ + MT_DATA = 1, /* dynamic data allocation */ + MT_HEADER = 2, /* packet header */ + MT_SONAME = 3, + MT_SOOPTS = 4, + MT_FTABLE = 5, /* fragment reassembly header */ + MT_CONTROL = 6, /* extra-data protocol message */ + MT_OOBDATA = 7 /* out-of-band data */ +}; + +/* length to m_copy to copy all */ +#define M_COPYALL 1000000000 + +/* now some macro's to make life easier... */ + +/* need to add the macro's here :) */ + +#define MRESETDATA(m) do { \ + if ((m)->m_flags & M_EXT) \ + (m)->m_data = (m)->m_ext.ext_buf; \ + else if ((m)->m_flags & M_PKTHDR) \ + (m)->m_data = (m)->m_pktdat; \ + else \ + (m)->m_data = (m)->dat; \ + } while (0) + +/* fill in an mbuf */ +#define MGET(n, type) \ + n = (struct mbuf*) pool_get(mbpool); \ + if (n) { \ + (n)->m_type = (type); \ + (n)->m_next = NULL; \ + (n)->m_nextpkt = NULL; \ + (n)->m_data = (n)->m_dat; \ + (n)->m_flags = 0; \ + (n)->m_cksum = 0; \ + } + +#define MGETHDR(n, type) \ + n = (struct mbuf*) pool_get(mbpool); \ + if (n) { \ + (n)->m_type = (type); \ + (n)->m_next = NULL; \ + (n)->m_nextpkt = NULL; \ + (n)->m_data = (n)->m_pktdat; \ + (n)->m_flags = M_PKTHDR; \ + (n)->m_cksum = 0; \ + } + +#define _MEXTREMOVE(m) do { \ + if ((m)->m_flags & M_CLUSTER) { \ + pool_put(clpool, (m)->m_ext.ext_buf); \ + } \ + (m)->m_flags &= ~(M_CLUSTER|M_EXT); \ + (m)->m_ext.ext_size = 0; \ + } while (0) + +#define MFREE(m, n) \ + if ((m)->m_flags & M_EXT) { \ + _MEXTREMOVE(m); \ + } \ + (n) = (m)->m_next; \ + pool_put(mbpool, m); + +/* set the data pointer to place an object of size len at the end + * of the mbuf, aligned to long word (16 bits) + */ +#define M_ALIGN(m, len) \ + { (m)->m_data += (MLEN - (len)) &~ (sizeof(int16) -1);} + +#define MH_ALIGN(m, len) \ + { (m)->m_data += (MHLEN - (len)) &~ (sizeof(int16) -1);} + +#define M_MOVE_HDR(to, from) { \ + (to)->m_pkthdr = (from)->m_pkthdr; \ + (from)->m_flags &= ~M_PKTHDR; \ + } + +#define M_MOVE_PKTHDR(to, from) { \ + (to)->m_flags = (from)->m_flags & M_COPYFLAGS; \ + M_MOVE_HDR((to), (from)); \ + (to)->m_data = (to)->m_pktdat; \ + } + +#define MCLGET(m) do { \ + (m)->m_ext.ext_buf = pool_get(clpool); \ + if ((m)->m_ext.ext_buf != NULL) { \ + (m)->m_data = (m)->m_ext.ext_buf; \ + (m)->m_flags |= M_EXT|M_CLUSTER; \ + (m)->m_ext.ext_size = MCLBYTES; \ + } \ + } while (0) + +#define M_LEADINGSPACE(m) \ + ((m)->m_flags & M_EXT ? (m)->m_data - (m)->m_ext.ext_buf : \ + (m)->m_flags & M_PKTHDR ? (m)->m_data - (m)->m_pktdat : \ + (m)->m_data - (m)->m_dat) + +#define M_PREPEND(m, plen) { \ + if (M_LEADINGSPACE(m) >= (plen)) { \ + (m)->m_data -= (plen); \ + (m)->m_len += (plen); \ + } else \ + (m) = m_prepend((m), (plen)); \ + if ((m) && (m)->m_flags & M_PKTHDR) \ + (m)->m_pkthdr.len += (plen); \ +} + +/* + * Duplicate just m_pkthdr from from to to. + */ +#define M_DUP_HDR(to, from) { \ + (to)->m_pkthdr = (from)->m_pkthdr; \ +} + +/* + * Duplicate mbuf pkthdr from from to to. + * from must have M_PKTHDR set, and to must be empty. + */ +#define M_DUP_PKTHDR(to, from) { \ + (to)->m_flags = (from)->m_flags & M_COPYFLAGS; \ + M_DUP_HDR((to), (from)); \ + (to)->m_data = (to)->m_pktdat; \ +} + +#define M_TRAILINGSPACE(m) \ + ((m)->m_flags & M_EXT ? (m)->m_ext.ext_buf + (m)->m_ext.ext_size - \ + ((m)->m_data + (m)->m_len) : \ + &(m)->m_dat[MLEN] - ((m)->m_data + (m)->m_len)) + +#define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT) + +#define M_DATASTART(m) \ + (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \ + (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat) + +#define M_DATASIZE(m) \ + (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \ + (m)->m_flags & M_PKTHDR ? MHLEN: MLEN) + +/* Functions! */ +void mbinit(void); +struct mbuf *m_get(int type); + +struct mbuf *m_gethdr(int type); +struct mbuf *m_getclr(int type); + +struct mbuf *m_prepend(struct mbuf *m, int len); +struct mbuf *m_devget(char *buf, int totlen, int off0, + struct ifnet *ifp, + void (*copy)(const void *, void *, size_t)); +struct mbuf *m_pullup(struct mbuf *, int len); +void m_copyback(struct mbuf *m0, int off, int len, char * cp); + +struct mbuf *m_free(struct mbuf *mfree); +void m_freem(struct mbuf *m); + +void m_reserve(struct mbuf *mp, int len); +void m_cat(struct mbuf *m, struct mbuf *n); +void m_adj(struct mbuf *mp, int req_len); +void m_copydata(struct mbuf *m, int off, int len, char * cp); +struct mbuf *m_copym(struct mbuf *m, int off0, int len); + +/* debug functions */ +void dump_freelist(void); + +/* Stats structure */ +/* XXX - add me! */ + + +struct pool_ctl *mbpool; +struct pool_ctl *clpool; + +int max_hdr; /* largest link+protocol header */ +int max_linkhdr; /* largest link level header */ +int max_protohdr; /* largest protocol header */ + +#endif /* OBOS_MBUF_H */ diff --git a/headers/private/kernel/memheap.h b/headers/private/kernel/memheap.h new file mode 100755 index 0000000000..4e77e7871b --- /dev/null +++ b/headers/private/kernel/memheap.h @@ -0,0 +1,17 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _KERNEL_MEMHEAP_H +#define _KERNEL_MEMHEAP_H + +#include +#include + +int heap_init(addr new_heap_base, unsigned int new_heap_size); +int heap_init_postsem(kernel_args *ka); +void *kmalloc(unsigned int size); +void kfree(void *address); +char *kstrdup(const char*text); + +#endif /* _KERNEL_MEMHEAP_H */ diff --git a/headers/private/kernel/module.h b/headers/private/kernel/module.h new file mode 100755 index 0000000000..3a70601e06 --- /dev/null +++ b/headers/private/kernel/module.h @@ -0,0 +1,40 @@ +/* +** Copyright 2001-2002, Thomas Kurschel. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#ifndef _KERNEL_MODULE_H +#define _KERNEL_MODULE_H + +#include +#include + +typedef struct module_info module_info; + +struct module_info { + const char *name; + uint32 flags; + int32 (*std_ops)(int32, ...); +}; + +// boot init +// XXX this is very private, so move it away +extern int module_init( kernel_args *ka, module_info **sys_module_headers ); + +/* Be Module Compatability... */ + +#define B_MODULE_INIT 1 +#define B_MODULE_UNINIT 2 +#define B_KEEP_LOADED 0x00000001 + +int get_module(const char *path, module_info **vec); +int put_module(const char *path); + +int get_next_loaded_module_name(uint32 *cookie, char *buf, size_t *bufsize); +void *open_module_list(const char *prefix); +int read_next_module_name(void *cookie, char *buf, size_t *bufsize); +int close_module_list(void *cookie); + +extern module_info *modules[]; + +#endif /* _|KRENEL_MODULE_H */ diff --git a/headers/private/kernel/nhash.h b/headers/private/kernel/nhash.h new file mode 100644 index 0000000000..61b98d86b4 --- /dev/null +++ b/headers/private/kernel/nhash.h @@ -0,0 +1,40 @@ +/* nhash.h + */ + +#ifndef OBOS_NHASH_H +#define OBOS_NHASH_H + +#include + +typedef struct net_hash_entry net_hash_entry; +typedef struct net_hash net_hash; +typedef struct net_hash_index net_hash_index; + +struct net_hash_entry { + net_hash_entry *next; + int hash; + const void *key; + ssize_t klen; + const void *val; +}; + +struct net_hash_index { + net_hash *nh; + net_hash_entry *this; + net_hash_entry *next; + int index; +}; + +struct net_hash { + net_hash_entry **array; + net_hash_index iterator; + int count; + int max; + struct pool_ctl *pool; +}; + +net_hash *nhash_make(void); +void *nhash_get(net_hash *, const void *key, ssize_t klen); +void nhash_set(net_hash *, const void *, ssize_t , const void *); + +#endif /* OBOS_NHASH_H */ diff --git a/headers/private/kernel/null.h b/headers/private/kernel/null.h new file mode 100755 index 0000000000..e7abbcbfab --- /dev/null +++ b/headers/private/kernel/null.h @@ -0,0 +1,12 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _NULL_DEV_H +#define _NULL_DEV_H + +#include + +int null_dev_init(kernel_args *ka); + +#endif diff --git a/headers/private/kernel/pci_bus.h b/headers/private/kernel/pci_bus.h new file mode 100755 index 0000000000..f5fa4a62a0 --- /dev/null +++ b/headers/private/kernel/pci_bus.h @@ -0,0 +1,43 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _PCI_BUS_H +#define _PCI_BUS_H + +#include + +struct pci_cfg { + uint16 vendor_id; + uint16 device_id; + + uint16 command; + uint16 status; + + uint8 revision_id; + uint8 interface; + uint8 sub_class; + uint8 base_class; + + uint8 cache_line_size; + uint8 latency_timer; + uint8 header_type; + uint8 bist; + + uint8 bus; + uint8 unit; + uint8 func; + uint8 irq; + + uint32 base[6]; + uint32 size[6]; +}; + +typedef enum { + PCI_GET_CFG = 10099, + PCI_DUMP_CFG +} pci_ioctl_cmd; + +int pci_bus_init(kernel_args *ka); + +#endif diff --git a/headers/private/kernel/pci_p.h b/headers/private/kernel/pci_p.h new file mode 100755 index 0000000000..3d80c9dce9 --- /dev/null +++ b/headers/private/kernel/pci_p.h @@ -0,0 +1,21 @@ +#ifndef _PCI_P_H +#define _PCI_P_H + +#define CONFIG_ADDRESS 0xcf8 +#define CONFIG_DATA 0xcfc + +struct pci_config_address { + unsigned reg : 8, + function : 3, + unit : 5, + bus : 8, + reserved : 7, + enable : 1; +}; + +void dump_pci_config(struct pci_cfg *cfg); +int pci_probe(uint8 bus, uint8 unit, uint8 function, struct pci_cfg *cfg); + +#endif + + diff --git a/headers/private/kernel/pools.h b/headers/private/kernel/pools.h new file mode 100644 index 0000000000..aa2f5d97bc --- /dev/null +++ b/headers/private/kernel/pools.h @@ -0,0 +1,53 @@ +/* pools.h + * simple fixed size block allocator + */ + +#ifndef _KERNEL_POOLS_H +#define _KERNEL_POOLS_H + + +#include +#include + +typedef struct pool_ctl pool_ctl; + +struct pool_mem { + struct pool_mem *next; + region_id aid; + char *base_addr; + size_t mem_size; + char *ptr; + size_t avail; + benaphore lock; +}; + +struct free_blk { + char *next; +}; + +#define POOL_USES_BENAPHORES 0 +#define POOL_DEBUG_NAME_SZ 32 + +struct pool_ctl { + struct pool_mem *list; + char *freelist; + size_t alloc_size; + size_t block_size; +#if POOL_USES_BENAPHORES + benaphore lock; +#else + rw_lock lock; +#endif + int debug : 1; + char name[POOL_DEBUG_NAME_SZ]; +}; + +int32 pool_init(pool_ctl **p, size_t sz); +char *pool_get(pool_ctl *p); +void pool_put(pool_ctl *p, void *ptr); +void pool_destroy(pool_ctl *p); +void pool_debug(struct pool_ctl *p, char *name); + +void pool_debug_walk(pool_ctl *p); + +#endif /* _KERNEL_POOLS_H */ diff --git a/headers/private/kernel/port.h b/headers/private/kernel/port.h new file mode 100755 index 0000000000..b4fc4d4835 --- /dev/null +++ b/headers/private/kernel/port.h @@ -0,0 +1,48 @@ +/* ports.h + * + * Definitions here are for kernel use only. For the actual + * definitions of port functions, please look at OS.h + */ + +#ifndef _KERNEL_PORT_H +#define _KERNEL_PORT_H + +#include + +#define PORT_FLAG_USE_USER_MEMCPY 0x80000000 + +int port_init(kernel_args *ka); +int delete_owned_ports(proc_id owner); + +// temp: test +void port_test(void); +int port_test_thread_func(void* arg); + +// user-level API +port_id user_create_port(int32 queue_length, const char *name); +int user_close_port(port_id id); +int user_delete_port(port_id id); +port_id user_find_port(const char *port_name); +int user_get_port_info(port_id id, struct port_info *info); +int user_get_next_port_info(proc_id proc, + uint32 *cookie, + struct port_info *info); +ssize_t user_port_buffer_size_etc(port_id port, + uint32 flags, + bigtime_t timeout); +int32 user_port_count(port_id port); +ssize_t user_read_port_etc(port_id port, + int32 *msg_code, + void *msg_buffer, + size_t buffer_size, + uint32 flags, + bigtime_t timeout); +int user_set_port_owner(port_id port, proc_id proc); +int user_write_port_etc(port_id port, + int32 msg_code, + void *msg_buffer, + size_t buffer_size, + uint32 flags, + bigtime_t timeout); + +#endif diff --git a/headers/private/kernel/queue.h b/headers/private/kernel/queue.h new file mode 100755 index 0000000000..c946de37a2 --- /dev/null +++ b/headers/private/kernel/queue.h @@ -0,0 +1,37 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _KERNEL_QUEUE_H +#define _KERNEL_QUEUE_H + +#include + +typedef struct queue { + void *head; + void *tail; + int count; +} queue; + +int queue_init(queue *q); +int queue_remove_item(queue *q, void *e); +int queue_enqueue(queue *q, void *e); +void *queue_dequeue(queue *q); +void *queue_peek(queue *q); + +typedef struct fixed_queue { + void **table; + int head; + int tail; + int count; + int size; +} fixed_queue; + +int fixed_queue_init(fixed_queue *q, int size); +void fixed_queue_destroy(fixed_queue *q); +int fixed_queue_enqueue(fixed_queue *q, void *e); +void *fixed_queue_dequeue(fixed_queue *q); +void *fixed_queue_peek(fixed_queue *q); + +#endif + diff --git a/headers/private/kernel/resource.h b/headers/private/kernel/resource.h new file mode 100755 index 0000000000..f5a7acea6e --- /dev/null +++ b/headers/private/kernel/resource.h @@ -0,0 +1,38 @@ +/* +** Copyright 2002, Jeff Hamilton. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#ifndef __newos__nulibc_sys_resource__hh__ +#define __newos__nulibc_sys_resource__hh__ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned long rlim_t; + +struct rlimit { + rlim_t rlim_cur; // Current soft limit + rlim_t rlim_max; // System hard limit +}; + +#define RLIMIT_CORE 0 +#define RLIMIT_CPU 1 +#define RLIMIT_DATA 2 +#define RLIMIT_FSIZE 3 +#define RLIMIT_NOFILE 4 +#define RLIMIT_STACK 5 +#define RLIMIT_AS 6 +#define RLIMIT_VMEM 7 + +#define RLIM_INFINITY (0xffffffffUL) + +int getrlimit(int resource, struct rlimit * rlp); +int setrlimit(int resource, const struct rlimit * rlp); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/headers/private/kernel/rootfs.h b/headers/private/kernel/rootfs.h new file mode 100755 index 0000000000..41bccdfde2 --- /dev/null +++ b/headers/private/kernel/rootfs.h @@ -0,0 +1,10 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _NEWOS_KERNEL_FS_ROOTFS_H +#define _NEWOS_KERNEL_FS_ROOTFS_H + +int bootstrap_rootfs(void); + +#endif diff --git a/headers/private/kernel/sem.h b/headers/private/kernel/sem.h new file mode 100755 index 0000000000..eedb99a793 --- /dev/null +++ b/headers/private/kernel/sem.h @@ -0,0 +1,36 @@ +/* sem.h + * + * Definitions here are for kernel use ONLY! + * + * For the actual definitions of the calls for sems please look in + * OS.h + */ + +#ifndef _SEM_H +#define _SEM_H + +#include +#include + +/* #ifdef _KERNEL_ */ + +sem_id user_create_sem(int count, const char *name); +int user_delete_sem(sem_id id); +int user_delete_sem_etc(sem_id id, int return_code); +int user_acquire_sem(sem_id id); +int user_acquire_sem_etc(sem_id id, int count, int flags, bigtime_t timeout); +int user_release_sem(sem_id id); +int user_release_sem_etc(sem_id id, int count, int flags); +int user_get_sem_count(sem_id id, int32* thread_count); +int user_get_sem_info(sem_id, struct sem_info *, size_t); +int user_get_next_sem_info(proc_id, uint32 *, struct sem_info *, size_t); +int user_set_sem_owner(sem_id id, proc_id proc); + + +int sem_init(kernel_args *ka); +int sem_delete_owned_sems(proc_id owner); +int sem_interrupt_thread(struct thread *t); +/* #endif */ + +#endif /* _KERNEL_SEM_H */ + diff --git a/headers/private/kernel/smp.h b/headers/private/kernel/smp.h new file mode 100755 index 0000000000..ab4ac1f73a --- /dev/null +++ b/headers/private/kernel/smp.h @@ -0,0 +1,44 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _KERNEL_SMP_H +#define _KERNEL_SMP_H + +#include + +// intercpu messages +enum { + SMP_MSG_INVL_PAGE_RANGE = 0, + SMP_MSG_INVL_PAGE_LIST, + SMP_MSG_GLOBAL_INVL_PAGE, + SMP_MSG_RESCHEDULE, + SMP_MSG_CPU_HALT, + SMP_MSG_1, +}; + +enum { + SMP_MSG_FLAG_ASYNC = 0, + SMP_MSG_FLAG_SYNC, +}; + +int smp_init(kernel_args *ka); +int smp_trap_non_boot_cpus(kernel_args *ka, int cpu); +void smp_wake_up_all_non_boot_cpus(void); +void smp_wait_for_ap_cpus(kernel_args *ka); +void smp_send_ici(int target_cpu, int message, unsigned long data, unsigned long data2, unsigned long data3, void *data_ptr, int flags); +void smp_send_broadcast_ici(int message, unsigned long data, unsigned long data2, unsigned long data3, void *data_ptr, int flags); +int smp_enable_ici(void); +int smp_disable_ici(void); + +int smp_get_num_cpus(void); +void smp_set_num_cpus(int num_cpus); +int smp_get_current_cpu(void); + +// spinlock functions +typedef volatile int spinlock_t; +void acquire_spinlock(spinlock_t *lock); +void release_spinlock(spinlock_t *lock); + +#endif + diff --git a/headers/private/kernel/stage2.h b/headers/private/kernel/stage2.h new file mode 100755 index 0000000000..4d41f33d3d --- /dev/null +++ b/headers/private/kernel/stage2.h @@ -0,0 +1,52 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#ifndef _KERNEL_STAGE2_H +#define _KERNEL_STAGE2_H + +// this file declares stuff like addr_range, MAX_*, etc. +#include + +/* david - I renmaed arch/.../stage2.h to arch_stage2.h and so + * as we have the arch specific include directory on the include + * path we can just include it here. It's neater and avoids a + * name collision that could cause us problems at some point in + * the future. + */ +#include + + +// kernel args +typedef struct ka { + unsigned int cons_line; + char *str; + addr_range bootdir_addr; + addr_range kernel_seg0_addr; + addr_range kernel_seg1_addr; + addr_range kernel_dynamic_section_addr; + unsigned int num_phys_mem_ranges; + + addr_range phys_mem_range[MAX_PHYS_MEM_ADDR_RANGE]; + unsigned int num_phys_alloc_ranges; + addr_range phys_alloc_range[MAX_PHYS_ALLOC_ADDR_RANGE]; + unsigned int num_virt_alloc_ranges; + addr_range virt_alloc_range[MAX_VIRT_ALLOC_ADDR_RANGE]; + unsigned int num_cpus; + addr_range cpu_kstack[MAX_BOOT_CPUS]; + + arch_kernel_args arch_args; + + struct framebuffer { + int enabled; + int x_size; + int y_size; + int bit_depth; + int already_mapped; + addr_range mapping; + } fb; + +} kernel_args; + +#endif /* _KERNEL_STAGE2_H */ diff --git a/headers/private/kernel/stage2_struct.h b/headers/private/kernel/stage2_struct.h new file mode 100755 index 0000000000..9f87b39169 --- /dev/null +++ b/headers/private/kernel/stage2_struct.h @@ -0,0 +1,20 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _NEWOS_BOOT_STAGE2_STRUCT_H +#define _NEWOS_BOOT_STAGE2_STRUCT_H + +// must match SMP_MAX_CPUS in arch_smp.h +#define MAX_BOOT_CPUS 4 +#define MAX_PHYS_MEM_ADDR_RANGE 4 +#define MAX_VIRT_ALLOC_ADDR_RANGE 4 +#define MAX_PHYS_ALLOC_ADDR_RANGE 4 + +typedef struct ar { + unsigned long start; + unsigned long size; +} addr_range; + +#endif + diff --git a/headers/private/kernel/stdarg.h b/headers/private/kernel/stdarg.h new file mode 100755 index 0000000000..9317402ec4 --- /dev/null +++ b/headers/private/kernel/stdarg.h @@ -0,0 +1,206 @@ +/* stdarg.h for GNU. + Note that the type used in va_arg is supposed to match the + actual type **after default promotions**. + Thus, va_arg (..., short) is not valid. */ + +#ifndef _STDARG_H +#ifndef _ANSI_STDARG_H_ +#ifndef __need___va_list +#define _STDARG_H +#define _ANSI_STDARG_H_ +#endif /* not __need___va_list */ +#undef __need___va_list + +#ifdef __clipper__ +#include "arch/va-clipper.h" +#else +#ifdef __m88k__ +#include "arch/va-m88k.h" +#else +#ifdef __i860__ +#include "arch/va-i860.h" +#else +#ifdef __hppa__ +#include "arch/va-pa.h" +#else +#ifdef __mips__ +#include "arch/va-mips.h" +#else +#ifdef __sparc__ +#include "arch/va-sparc.h" +#else +#ifdef __i960__ +#include "arch/va-i960.h" +#else +#ifdef __alpha__ +#include "arch/va-alpha.h" +#else +#if defined (__H8300__) || defined (__H8300H__) || defined (__H8300S__) +#include "arch/va-h8300.h" +#else +#if defined (__PPC__) && (defined (_CALL_SYSV) || defined (_WIN32)) +#include "arch/va-ppc.h" +#else +#ifdef __arc__ +#include "arch/va-arc.h" +#else +#ifdef __M32R__ +#include "arch/va-m32r.h" +#else +#ifdef __sh__ +#include "arch/va-sh.h" +#else +#ifdef __mn10300__ +#include "arch/va-mn10300.h" +#else +#ifdef __mn10200__ +#include "arch/va-mn10200.h" +#else +#ifdef __v850__ +#include "arch/va-v850.h" +#else + +/* Define __gnuc_va_list. */ + +#ifndef __GNUC_VA_LIST +#define __GNUC_VA_LIST +#if defined(__svr4__) || defined(_AIX) || defined(_M_UNIX) || defined(__NetBSD__) +typedef char *__gnuc_va_list; +#else +typedef void *__gnuc_va_list; +#endif +#endif + +/* Define the standard macros for the user, + if this invocation was from the user program. */ +#ifdef _STDARG_H + +/* Amount of space required in an argument list for an arg of type TYPE. + TYPE may alternatively be an expression whose type is used. */ + +#if defined(sysV68) +#define __va_rounded_size(TYPE) \ + (((sizeof (TYPE) + sizeof (short) - 1) / sizeof (short)) * sizeof (short)) +#else +#define __va_rounded_size(TYPE) \ + (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int)) +#endif + +#define va_start(AP, LASTARG) \ + (AP = ((__gnuc_va_list) __builtin_next_arg (LASTARG))) + +#undef va_end +void va_end (__gnuc_va_list); /* Defined in libgcc.a */ +#define va_end(AP) ((void)0) + +/* We cast to void * and then to TYPE * because this avoids + a warning about increasing the alignment requirement. */ + +#if defined (__arm__) || defined (__i386__) || defined (__i860__) || defined (__ns32000__) || defined (__vax__) +/* This is for little-endian machines; small args are padded upward. */ +#define va_arg(AP, TYPE) \ + (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)), \ + *((TYPE *) (void *) ((char *) (AP) - __va_rounded_size (TYPE)))) +#else /* big-endian */ +/* This is for big-endian machines; small args are padded downward. */ +#define va_arg(AP, TYPE) \ + (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)), \ + *((TYPE *) (void *) ((char *) (AP) \ + - ((sizeof (TYPE) < __va_rounded_size (char) \ + ? sizeof (TYPE) : __va_rounded_size (TYPE)))))) +#endif /* big-endian */ + +/* Copy __gnuc_va_list into another variable of this type. */ +#define __va_copy(dest, src) (dest) = (src) + +#endif /* _STDARG_H */ + +#endif /* not v850 */ +#endif /* not mn10200 */ +#endif /* not mn10300 */ +#endif /* not sh */ +#endif /* not m32r */ +#endif /* not arc */ +#endif /* not powerpc with V.4 calling sequence */ +#endif /* not h8300 */ +#endif /* not alpha */ +#endif /* not i960 */ +#endif /* not sparc */ +#endif /* not mips */ +#endif /* not hppa */ +#endif /* not i860 */ +#endif /* not m88k */ +#endif /* not clipper */ + +#ifdef _STDARG_H +/* Define va_list, if desired, from __gnuc_va_list. */ +/* We deliberately do not define va_list when called from + stdio.h, because ANSI C says that stdio.h is not supposed to define + va_list. stdio.h needs to have access to that data type, + but must not use that name. It should use the name __gnuc_va_list, + which is safe because it is reserved for the implementation. */ + +#ifdef _HIDDEN_VA_LIST /* On OSF1, this means varargs.h is "half-loaded". */ +#undef _VA_LIST +#endif + +#ifdef _BSD_VA_LIST +#undef _BSD_VA_LIST +#endif + +#if defined(__svr4__) || (defined(_SCO_DS) && !defined(__VA_LIST)) +/* SVR4.2 uses _VA_LIST for an internal alias for va_list, + so we must avoid testing it and setting it here. + SVR4 uses _VA_LIST as a flag in stdarg.h, but we should + have no conflict with that. */ +#ifndef _VA_LIST_ +#define _VA_LIST_ +#ifdef __i860__ +#ifndef _VA_LIST +#define _VA_LIST va_list +#endif +#endif /* __i860__ */ +typedef __gnuc_va_list va_list; +#ifdef _SCO_DS +#define __VA_LIST +#endif +#endif /* _VA_LIST_ */ +#else /* not __svr4__ || _SCO_DS */ + +/* The macro _VA_LIST_ is the same thing used by this file in Ultrix. + But on BSD NET2 we must not test or define or undef it. + (Note that the comments in NET 2's ansi.h + are incorrect for _VA_LIST_--see stdio.h!) */ +#if !defined (_VA_LIST_) || defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__) || defined (__FreeBSD__) || defined(WINNT) +/* The macro _VA_LIST_DEFINED is used in Windows NT 3.5 */ +#ifndef _VA_LIST_DEFINED +/* The macro _VA_LIST is used in SCO Unix 3.2. */ +#ifndef _VA_LIST +/* The macro _VA_LIST_T_H is used in the Bull dpx2 */ +#ifndef _VA_LIST_T_H +typedef __gnuc_va_list va_list; +#endif /* not _VA_LIST_T_H */ +#endif /* not _VA_LIST */ +#endif /* not _VA_LIST_DEFINED */ +#if !(defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__) || defined (__FreeBSD__)) +#define _VA_LIST_ +#endif +#ifndef _VA_LIST +#define _VA_LIST +#endif +#ifndef _VA_LIST_DEFINED +#define _VA_LIST_DEFINED +#endif +#ifndef _VA_LIST_T_H +#define _VA_LIST_T_H +#endif + +#endif /* not _VA_LIST_, except on certain systems */ + +#endif /* not __svr4__ */ + +#endif /* _STDARG_H */ + +#endif /* not _ANSI_STDARG_H_ */ +#endif /* not _STDARG_H */ + diff --git a/headers/private/kernel/stdio.h b/headers/private/kernel/stdio.h new file mode 100755 index 0000000000..15f23427a3 --- /dev/null +++ b/headers/private/kernel/stdio.h @@ -0,0 +1,195 @@ +/* stdio.h + */ + +#ifndef _STDIO_H +#define _STDIO_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef off_t fpos_t; /* stdio file position type */ + +/* stdio buffers */ +struct __sbuf { + unsigned char *_base; + int _size; +}; + +/* + * stdio state variables. + * + * The following always hold: + * + *if (_flags&(__SLBF|__SWR)) == (__SLBF|__SWR), + * _lbfsize is -_bf._size, else _lbfsize is 0 + *if _flags&__SRD, _w is 0 + *if _flags&__SWR, _r is 0 + * + * This ensures that the getc and putc macros (or inline functions) never + * try to write or read from a file that is in `read' or `write' mode. + * (Moreover, they can, and do, automatically switch from read mode to + * write mode, and back, on "r+" and "w+" files.) + * + * _lbfsize is used only to make the inline line-buffered output stream + * code as compact as possible. + * + * _ub, _up, and _ur are used when ungetc() pushes back more characters + * than fit in the current _bf, or when ungetc() pushes back a character + * that does not match the previous one in _bf. When this happens, + * _ub._base becomes non-nil (i.e., a stream has ungetc() data iff + * _ub._base!=NULL) and _up and _ur save the current values of _p and _r. + */ +typedef struct __FILE { + unsigned char *_p;/* current position in (some) buffer */ + int _r; /* read space left for getc() */ + int _w; /* write space left for putc() */ + short _flags; /* flags, below; this FILE is free if 0 */ + short _file; /* fileno, if Unix descriptor, else -1 */ + struct __sbuf _bf; /* the buffer (at least 1 byte, if !NULL) */ + int _lbfsize;/* 0 or -_bf._size, for inline putc */ + + /* operations */ + void *_cookie;/* cookie passed to io functions */ + int (*_close) (void *); + int (*_read) (void *, char *, int); + fpos_t (*_seek) (void *, fpos_t, int); + int (*_write) (void *, const char *, int); + + /* separate buffer for long sequences of ungetc() */ + struct __sbuf _ub; /* ungetc buffer */ + unsigned char *_up; /* saved _p when _p is doing ungetc data */ + int _ur;/* saved _r when _r is counting ungetc data */ + + /* tricks to meet minimum requirements even when malloc() fails */ + unsigned char _ubuf[3]; /* guarantee an ungetc() buffer */ + unsigned char _nbuf[1]; /* guarantee a getc() buffer */ + + /* separate buffer for fgetln() when line crosses buffer boundary */ + struct __sbuf _lb; /* buffer for fgetln() */ + + /* Unix stdio files get aligned to block boundaries on fseek() */ + int _blksize;/* stat.st_blksize (may be != _bf._size) */ + fpos_t _offset;/* current lseek offset */ +} FILE; + +#define __SLBF 0x0001 /* line buffered */ +#define __SNBF 0x0002 /* unbuffered */ +#define __SRD 0x0004 /* OK to read */ +#define __SWR 0x0008 /* OK to write */ + /* RD and WR are never simultaneously asserted */ +#define __SRW 0x0010 /* open for reading & writing */ +#define __SEOF 0x0020 /* found EOF */ +#define __SERR 0x0040 /* found error */ +#define __SMBF 0x0080 /* _buf is from malloc */ +#define __SAPP 0x0100 /* fdopen()ed in append mode */ +#define __SSTR 0x0200 /* this is an sprintf/snprintf string */ +#define __SOPT 0x0400 /* do fseek() optimisation */ +#define __SNPT 0x0800 /* do not do fseek() optimisation */ +#define __SOFF 0x1000 /* set iff _offset is in fact correct */ +#define __SMOD 0x2000 /* true => fgetln modified _p text */ +#define __SALC 0x4000 /* allocate string space dynamically */ + +/* + * FOPEN_MAX is a minimum maximum, and should be the number of descriptors + * that the kernel can provide without allocation of a resource that can + * fail without the process sleeping. Do not use this for anything + */ +#define FOPEN_MAX 20 /* must be <= OPEN_MAX */ +#define BUFSIZ 1024 + +extern FILE __sF[]; + +#define stdin (&__sF[0]) +#define stdout (&__sF[1]) +#define stderr (&__sF[2]) + +//extern FILE *stdout; +//extern FILE *stderr; + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#define EOF -1 + +int printf(char const *format, ...) __PRINTFLIKE(1,2); +int fprintf(FILE *stream, char const *format, ...) __PRINTFLIKE(2,3); +int sprintf(char *str, char const *format, ...) __PRINTFLIKE(2,3); +int snprintf(char *str, size_t size, char const *format, ...) __PRINTFLIKE(3,4); +int asprintf(char **ret, char const *format, ...) __PRINTFLIKE(2,3); +int vprintf(char const *format, va_list ap); +int vfprintf(FILE *stream, char const *format, va_list ap); +int vsprintf(char *str, char const *format, va_list ap); +int vsnprintf(char *str, size_t size, char const *format, va_list ap); +int vasprintf(char **ret, char const *format, va_list ap); + +void clearerr(FILE *); +int fclose(FILE *); +int feof(FILE *); +int fflush(FILE *); +int fgetc(FILE *); +char *fgetln(FILE *, size_t *); +int fgetpos(FILE *, fpos_t); +char *fgets(char *, int, FILE *); +void flockfile(FILE *); +FILE *fopen(char const *, char const *); +int fputc(int, FILE *); +int fputs(const char *, FILE*); +size_t fread(void *, size_t, size_t, FILE *); +int fscanf(FILE *stream, char const *format, ...); +int fseek(FILE *, long, int); +int fseeko(FILE *, off_t, int); +size_t fwrite(const void *, size_t, size_t, FILE *); +void funlockfile(FILE *); +int getc(FILE *); +char *gets(char *); +int getw(FILE *); +int getchar(void); +int putc(int, FILE *); +int putchar(int); +int puts(const char *); +int putw(int, FILE *); +void rewind(FILE *); +int scanf(char const *format, ...); +int sscanf(char const *str, char const *format, ...); +int ungetc(int, FILE *); +int vscanf(char const *format, va_list ap); +int vsscanf(char const *str, char const *format, va_list ap); +int vfscanf(FILE *stream, char const *format, va_list ap); + + +int __srget(FILE *); +int __svfscanf(FILE *, char const *, va_list ap); +int __swbuf(int c, FILE* fp); + +#define __sgetc(p) (--(p)->_r < 0 ? __srget(p) : (int)(*(p)->_p++)) +static __inline int __sputc(int _c, FILE *_p) { + if (--_p->_w >= 0 || (_p->_w >= _p->_lbfsize && (char)_c != '\n')) + return (*_p->_p++ = _c); + else + return (__swbuf(_c, _p)); +} + +#define __sfeof(x) (((x)->_flags & __SEOF) != 0) +#define __sferror(x) (((x)->_flags & __SERR) != 0) + +#define feof(x) __sfeof(x) +#define ferror(x) __sferror(x) + +#ifdef __cplusplus +} +#endif + +#endif /* _STDIO_H */ diff --git a/headers/private/kernel/stdlib.h b/headers/private/kernel/stdlib.h new file mode 100755 index 0000000000..ce694c0758 --- /dev/null +++ b/headers/private/kernel/stdlib.h @@ -0,0 +1,76 @@ +/* +** Copyright 2002, Travis Geiselbrecht. All rights reserved. +** Copyright 2002, Manuel J. Petit. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#ifndef __newos__nulibc_stdlib__hh__ +#define __newos__nulibc_stdlib__hh__ + + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int atoi(char const *); +unsigned int atoui(const char *num); +long atol(const char *num); +unsigned long atoul(const char *num); + +void * malloc(size_t); +void free(void *); +void * realloc(void *, size_t); +void * reallocf(void *, size_t); +void * calloc(size_t, size_t); +void * memalign(size_t, size_t); +void * valloc(size_t); + +char *getenv(char const *); +int setenv(char const *, char const *, int); +int putenv(char const *); +void unsetenv(char const *); + +void *bsearch(void const *, void const *, size_t, size_t, int (*) (void const *, void const *)); +int heapsort(void *, size_t , size_t , int (*)(void const *, void const *)); +int mergesort(void *, size_t, size_t, int (*)(void const *, void const *)); +void qsort(void *, size_t, size_t, int (*)(void const *, void const *)); +int radixsort(u_char const **, int, u_char const *, u_int); +int sradixsort(u_char const **, int, u_char const *, u_int); + +int mblen(const char *, size_t); +int mbtowc(int *, const char *, size_t); +int wctomb(char *, int); +size_t mbstowcs(int *, const char*, size_t); +size_t wcstombs(char *, const int*, size_t); + +int64 strtoq(const char *, char **, int); +uint64 strtouq(const char *, char **, int); + +#define RAND_MAX 0x7fffffff +int rand(void); +int rand_r(unsigned int *ctx); +void srand(unsigned); +long random(void); +void srandom(unsigned long); + +void exit(int); +void _exit(int); + +#define MB_CUR_MAX 1 + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#ifdef __cplusplus +void * operator new (size_t); +void * operator new[] (size_t); +void operator delete (void *); +void operator delete[] (void *); +#endif + + +#endif diff --git a/headers/private/kernel/string.h b/headers/private/kernel/string.h new file mode 100755 index 0000000000..6b8afbe048 --- /dev/null +++ b/headers/private/kernel/string.h @@ -0,0 +1,56 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Copyright 2002, Manuel J. Petit. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#ifndef __newos__nulibc_string__hh__ +#define __newos__nulibc_string__hh__ + + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +void *memchr (void const *, int, size_t); +int memcmp (void const *, const void *, size_t); +void *memcpy (void *, void const *, size_t); +void *memmove(void *, void const *, size_t); +void *memset (void *, int, size_t); + +char *strcat(char *, char const *); +char *strchr(char const *, int); +int strcmp(char const *, char const *); +char *strcpy(char *, char const *); +char const *strerror(int); +size_t strlen(char const *); +char *strncat(char *, char const *, size_t); +int strncmp(char const *, char const *, size_t); +char *strncpy(char *, char const *, size_t); +char *strpbrk(char const *, char const *); +char *strrchr(char const *, int); +size_t strspn(char const *, char const *); +char *strstr(char const *, char const *); +char *strtok(char *, char const *); + + +/* non standard */ +void *bcopy(void const *, void *, size_t); +void bzero(void *, size_t); +size_t strlcat(char *, char const *, size_t); +size_t strlcpy(char *, char const *, size_t); +int strncasecmp(char const *, char const *, size_t); +int strnicmp(char const *, char const *, size_t); +size_t strnlen(char const *s, size_t count); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif diff --git a/headers/private/kernel/sysctl.h b/headers/private/kernel/sysctl.h new file mode 100644 index 0000000000..773de0c322 --- /dev/null +++ b/headers/private/kernel/sysctl.h @@ -0,0 +1,121 @@ +/* sysctl.h + * should really be installed as sys/sysctl.h + */ + +#ifndef _SYS_SYSCTL_H +#define _SYS_SYSCTL_H + +/* This file contains definitions for the sysctl call. + * The call uses a heirachy of names for objects that can be + * examined or modified. The name is expressed as a sequence + * of integers and works in a similar manner to a filename, ie each + * component is dependant upon it's place in the heirachy. + * + * NB this file defines only the top level and kernel level (_KERN) + * identifiers with others being defined in files specific to + * the subsystem concerned. + */ + +#define CTL_MAXNAME 12 /* This is the largest no. of components we support */ + +/* Each subsystem defines a list of variables for that subsystem. + * The name can either be: + * - a node that has further levels defined below it, or + * - a leaf in a particular type. + * Each level of sysctl has a set of name/type pairs used when manipulating + * that level. + */ + +struct ctlname { + char *ctl_name; /* the subsystem name */ + int ctl_type; /* type of name */ +}; + +#define CTLTYPE_NODE 1 /* it's a node */ +#define CTLTYPE_INT 2 /* integer */ +#define CTLTYPE_STRING 3 /* string */ +#define CTLTYPE_QUAD 4 /* 64-bit number */ +#define CTLTYPE_STRUCT 5 /* it's a structure */ + +/* The top level identifiers we support */ +#define CTL_UNSPEC 0 /* unused */ +#define CTL_KERN 1 /* Kernel level */ +#define CTL_VM 2 /* VM */ +#define CTL_FS 3 /* Filesystem */ +#define CTL_NET 4 /* networking (socket.h) */ +#define CTL_HW 5 /* hardware */ + +#define CTL_NAMES { \ + { 0, 0 }, \ + { "kern", CTLTYPE_NODE }, \ + { "vm" , CTLTYPE_NODE }, \ + { "fs" , CTLTYPE_NODE }, \ + { "net" , CTLTYPE_NODE }, \ + { "hardware", CTL_TYPE_NODE }, \ +} + +/* Identifiers for use in the CTL_KERN subsystem */ +#define KERN_OSTYPE 1 /* string: system type string */ +#define KERN_OSRELEASE 2 /* string: system release */ +#define KERN_OSVERSION 3 /* int: system revision */ +#define KERN_HOSTNAME 4 /* string: hostname of system */ +#define KERN_DOMAINNAME 5 /* string: (YP) domain name */ +#define KERN_VERSION 6 /* string: system version string */ + +#define CTL_KERN_NAMES { \ + { 0, 0 }, \ + { "ostype" , CTLTYPE_STRING }, \ + { "osrelease" , CTLTYPE_STRING }, \ + { "osversion" , CTLTYPE_STRING }, \ + { "hostname" , CTLTYPE_STRING }, \ + { "domainname" , CTLTYPE_STRING }, \ + { "version" , CTLTYPE_STRING }, \ +} + +/* + * CTL_HW identifiers + */ +#define HW_MACHINE 1 /* string: machine class */ +#define HW_MODEL 2 /* string: specific machine model */ +#define HW_NCPU 3 /* int: number of cpus */ +#define HW_BYTEORDER 4 /* int: machine byte order */ +#define HW_PHYSMEM 5 /* int: total memory */ +#define HW_USERMEM 6 /* int: non-kernel memory */ +#define HW_PAGESIZE 7 /* int: software page size */ +#define HW_DISKNAMES 8 /* strings: disk drive names */ +#define HW_DISKSTATS 9 /* struct: diskstats[] */ +#define HW_DISKCOUNT 10 /* int: number of disks */ +#define HW_MAXID 11 /* number of valid hw ids */ + +#define CTL_HW_NAMES { \ + { 0, 0 }, \ + { "machine", CTLTYPE_STRING }, \ + { "model", CTLTYPE_STRING }, \ + { "ncpu", CTLTYPE_INT }, \ + { "byteorder", CTLTYPE_INT }, \ + { "physmem", CTLTYPE_INT }, \ + { "usermem", CTLTYPE_INT }, \ + { "pagesize", CTLTYPE_INT }, \ + { "disknames", CTLTYPE_STRING }, \ + { "diskstats", CTLTYPE_STRUCT }, \ + { "diskcount", CTLTYPE_INT }, \ +} + + +#ifdef _KERNEL_MODE + typedef int (sysctlfn)(int *, uint, void *, size_t *, void *, size_t); + + int kern_sysctl(int *, uint, void *, size_t *, void *, size_t); + int hw_sysctl(int *, uint, void *, size_t *, void *, size_t); + int sysctl_int (void *, size_t *, void *, size_t, int *); + int sysctl_rdint (void *, size_t *, void *, int); + int sysctl_tstring(void *, size_t *, void *, size_t, char *, int); + int sysctl__string(void *, size_t *, void *, size_t, char *, int, int); + int sysctl_rdstring(void *, size_t *, void *, char *); + int user_sysctl(int *, uint, void *, size_t *, void *, size_t); +#endif + +int sysctl(int *, uint, void *, size_t *, void *, size_t); + +#endif /* _SYS_SYSCTL_H */ + diff --git a/headers/private/kernel/thread.h b/headers/private/kernel/thread.h new file mode 100755 index 0000000000..80676f4964 --- /dev/null +++ b/headers/private/kernel/thread.h @@ -0,0 +1,81 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _THREAD_H +#define _THREAD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +void thread_enqueue(struct thread *t, struct thread_queue *q); +struct thread *thread_lookat_queue(struct thread_queue *q); +struct thread *thread_dequeue(struct thread_queue *q); +struct thread *thread_dequeue_id(struct thread_queue *q, thread_id thr_id); +struct thread *thread_lookat_run_q(int priority); +void thread_enqueue_run_q(struct thread *t); +struct thread *thread_dequeue_run_q(int priority); +void thread_atkernel_entry(void); // called when the thread enters the kernel on behalf of the thread +void thread_atkernel_exit(void); + +int thread_suspend_thread(thread_id id); +int thread_resume_thread(thread_id id); +int thread_set_priority(thread_id id, int priority); +void thread_resched(void); +void thread_start_threading(void); +void thread_snooze(bigtime_t time); +int thread_init(kernel_args *ka); +int thread_init_percpu(int cpu_num); +void thread_exit(int retcode); +int thread_kill_thread(thread_id id); +int thread_kill_thread_nowait(thread_id id); + +#define thread_get_current_thread arch_thread_get_current_thread + +struct thread *thread_get_thread_struct(thread_id id); +thread_id thread_get_current_thread_id(void); + +extern inline thread_id thread_get_current_thread_id(void) { + struct thread *t = thread_get_current_thread(); return t ? t->id : 0; +} +int thread_wait_on_thread(thread_id id, int *retcode); + +thread_id thread_create_user_thread(char *name, proc_id pid, addr entry, void *args); +thread_id thread_create_kernel_thread(const char *name, int (*func)(void *args), void *args); + +struct proc *proc_get_kernel_proc(void); +proc_id proc_create_proc(const char *path, const char *name, char **args, int argc, int priority); +int proc_kill_proc(proc_id); +int proc_wait_on_proc(proc_id id, int *retcode); +proc_id proc_get_kernel_proc_id(void); +proc_id proc_get_current_proc_id(void); +char **user_proc_get_arguments(void); +int user_proc_get_arg_count(void); + +// used in syscalls.c +int user_thread_wait_on_thread(thread_id id, int *uretcode); +proc_id user_proc_create_proc(const char *path, const char *name, char **args, int argc, int priority); +int user_proc_wait_on_proc(proc_id id, int *uretcode); + +thread_id user_thread_create_user_thread(addr, proc_id, const char*, + int, void *); + +int user_thread_snooze(bigtime_t time); +int user_proc_get_table(struct proc_info *pi, size_t len); +int user_getrlimit(int resource, struct rlimit * rlp); +int user_setrlimit(int resource, const struct rlimit * rlp); + +#if 1 +// XXX remove later +int thread_test(void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _THREAD_H */ diff --git a/headers/private/kernel/timer.h b/headers/private/kernel/timer.h new file mode 100755 index 0000000000..891037038c --- /dev/null +++ b/headers/private/kernel/timer.h @@ -0,0 +1,43 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _KERNEL_TIMER_H +#define _KERNEL_TIMER_H + +#include + +typedef int (*timer_callback)(void *); + + +typedef enum { + TIMER_MODE_ONESHOT = 0, + TIMER_MODE_PERIODIC +} timer_mode; + +struct timer_event { + struct timer_event *next; + timer_mode mode; + bigtime_t sched_time; + bigtime_t periodic_time; + timer_callback func; + void *data; +}; + +void timer_setup_timer(timer_callback func, void *data, struct timer_event *event); +int timer_set_event(bigtime_t relative_time, timer_mode mode, struct timer_event *event); +int timer_cancel_event(struct timer_event *event); +void spin(bigtime_t microseconds); + +/* kernel functions */ +int timer_init(kernel_args *); +int timer_interrupt(void); + +/* + * these two are only to be used by the scheduler + */ +int local_timer_cancel_event(struct timer_event *event); +int _local_timer_cancel_event(int curr_cpu, struct timer_event *event); + +#endif + diff --git a/headers/private/kernel/trig.h b/headers/private/kernel/trig.h new file mode 100755 index 0000000000..e31fb4c25b --- /dev/null +++ b/headers/private/kernel/trig.h @@ -0,0 +1,215 @@ +/* + * Copyright (c) 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)trig.h 8.1 (Berkeley) 6/4/93 + */ + +#include "mathimpl.h" + +vc(thresh, 2.6117239648121182150E-1 ,b863,3f85,6ea0,6b02, -1, .85B8636B026EA0) +vc(PIo4, 7.8539816339744830676E-1 ,0fda,4049,68c2,a221, 0, .C90FDAA22168C2) +vc(PIo2, 1.5707963267948966135E0 ,0fda,40c9,68c2,a221, 1, .C90FDAA22168C2) +vc(PI3o4, 2.3561944901923449203E0 ,cbe3,4116,0e92,f999, 2, .96CBE3F9990E92) +vc(PI, 3.1415926535897932270E0 ,0fda,4149,68c2,a221, 2, .C90FDAA22168C2) +vc(PI2, 6.2831853071795864540E0 ,0fda,41c9,68c2,a221, 3, .C90FDAA22168C2) + +ic(thresh, 2.6117239648121182150E-1 , -2, 1.0B70C6D604DD4) +ic(PIo4, 7.8539816339744827900E-1 , -1, 1.921FB54442D18) +ic(PIo2, 1.5707963267948965580E0 , 0, 1.921FB54442D18) +ic(PI3o4, 2.3561944901923448370E0 , 1, 1.2D97C7F3321D2) +ic(PI, 3.1415926535897931160E0 , 1, 1.921FB54442D18) +ic(PI2, 6.2831853071795862320E0 , 2, 1.921FB54442D18) + +#ifdef vccast +#define thresh vccast(thresh) +#define PIo4 vccast(PIo4) +#define PIo2 vccast(PIo2) +#define PI3o4 vccast(PI3o4) +#define PI vccast(PI) +#define PI2 vccast(PI2) +#endif + +#ifdef national +static long fmaxx[] = { 0xffffffff, 0x7fefffff}; +#define fmax (*(double*)fmaxx) +#endif /* national */ + +static const double + zero = 0, + one = 1, + negone = -1, + half = 1.0/2.0, + small = 1E-10, /* 1+small**2 == 1; better values for small: + * small = 1.5E-9 for VAX D + * = 1.2E-8 for IEEE Double + * = 2.8E-10 for IEEE Extended + */ + big = 1E20; /* big := 1/(small**2) */ + +/* sin__S(x*x) ... re-implemented as a macro + * DOUBLE PRECISION (VAX D format 56 bits, IEEE DOUBLE 53 BITS) + * STATIC KERNEL FUNCTION OF SIN(X), COS(X), AND TAN(X) + * CODED IN C BY K.C. NG, 1/21/85; + * REVISED BY K.C. NG on 8/13/85. + * + * sin(x*k) - x + * RETURN --------------- on [-PI/4,PI/4] , where k=pi/PI, PI is the rounded + * x + * value of pi in machine precision: + * + * Decimal: + * pi = 3.141592653589793 23846264338327 ..... + * 53 bits PI = 3.141592653589793 115997963 ..... , + * 56 bits PI = 3.141592653589793 227020265 ..... , + * + * Hexadecimal: + * pi = 3.243F6A8885A308D313198A2E.... + * 53 bits PI = 3.243F6A8885A30 = 2 * 1.921FB54442D18 + * 56 bits PI = 3.243F6A8885A308 = 4 * .C90FDAA22168C2 + * + * Method: + * 1. Let z=x*x. Create a polynomial approximation to + * (sin(k*x)-x)/x = z*(S0 + S1*z^1 + ... + S5*z^5). + * Then + * sin__S(x*x) = z*(S0 + S1*z^1 + ... + S5*z^5) + * + * The coefficient S's are obtained by a special Remez algorithm. + * + * Accuracy: + * In the absence of rounding error, the approximation has absolute error + * less than 2**(-61.11) for VAX D FORMAT, 2**(-57.45) for IEEE DOUBLE. + * + * Constants: + * The hexadecimal values are the intended ones for the following constants. + * The decimal values may be used, provided that the compiler will convert + * from decimal to binary accurately enough to produce the hexadecimal values + * shown. + * + */ + +vc(S0, -1.6666666666666646660E-1 ,aaaa,bf2a,aa71,aaaa, -2, -.AAAAAAAAAAAA71) +vc(S1, 8.3333333333297230413E-3 ,8888,3d08,477f,8888, -6, .8888888888477F) +vc(S2, -1.9841269838362403710E-4 ,0d00,ba50,1057,cf8a, -12, -.D00D00CF8A1057) +vc(S3, 2.7557318019967078930E-6 ,ef1c,3738,bedc,a326, -18, .B8EF1CA326BEDC) +vc(S4, -2.5051841873876551398E-8 ,3195,b3d7,e1d3,374c, -25, -.D73195374CE1D3) +vc(S5, 1.6028995389845827653E-10 ,3d9c,3030,cccc,6d26, -32, .B03D9C6D26CCCC) +vc(S6, -6.2723499671769283121E-13 ,8d0b,ac30,ea82,7561, -40, -.B08D0B7561EA82) + +ic(S0, -1.6666666666666463126E-1 , -3, -1.555555555550C) +ic(S1, 8.3333333332992771264E-3 , -7, 1.111111110C461) +ic(S2, -1.9841269816180999116E-4 , -13, -1.A01A019746345) +ic(S3, 2.7557309793219876880E-6 , -19, 1.71DE3209CDCD9) +ic(S4, -2.5050225177523807003E-8 , -26, -1.AE5C0E319A4EF) +ic(S5, 1.5868926979889205164E-10 , -33, 1.5CF61DF672B13) + +#ifdef vccast +#define S0 vccast(S0) +#define S1 vccast(S1) +#define S2 vccast(S2) +#define S3 vccast(S3) +#define S4 vccast(S4) +#define S5 vccast(S5) +#define S6 vccast(S6) +#endif + +#if defined(vax)||defined(tahoe) +# define sin__S(z) (z*(S0+z*(S1+z*(S2+z*(S3+z*(S4+z*(S5+z*S6))))))) +#else /* defined(vax)||defined(tahoe) */ +# define sin__S(z) (z*(S0+z*(S1+z*(S2+z*(S3+z*(S4+z*S5)))))) +#endif /* defined(vax)||defined(tahoe) */ + +/* cos__C(x*x) ... re-implemented as a macro + * DOUBLE PRECISION (VAX D FORMAT 56 BITS, IEEE DOUBLE 53 BITS) + * STATIC KERNEL FUNCTION OF SIN(X), COS(X), AND TAN(X) + * CODED IN C BY K.C. NG, 1/21/85; + * REVISED BY K.C. NG on 8/13/85. + * + * x*x + * RETURN cos(k*x) - 1 + ----- on [-PI/4,PI/4], where k = pi/PI, + * 2 + * PI is the rounded value of pi in machine precision : + * + * Decimal: + * pi = 3.141592653589793 23846264338327 ..... + * 53 bits PI = 3.141592653589793 115997963 ..... , + * 56 bits PI = 3.141592653589793 227020265 ..... , + * + * Hexadecimal: + * pi = 3.243F6A8885A308D313198A2E.... + * 53 bits PI = 3.243F6A8885A30 = 2 * 1.921FB54442D18 + * 56 bits PI = 3.243F6A8885A308 = 4 * .C90FDAA22168C2 + * + * + * Method: + * 1. Let z=x*x. Create a polynomial approximation to + * cos(k*x)-1+z/2 = z*z*(C0 + C1*z^1 + ... + C5*z^5) + * then + * cos__C(z) = z*z*(C0 + C1*z^1 + ... + C5*z^5) + * + * The coefficient C's are obtained by a special Remez algorithm. + * + * Accuracy: + * In the absence of rounding error, the approximation has absolute error + * less than 2**(-64) for VAX D FORMAT, 2**(-58.3) for IEEE DOUBLE. + * + * + * Constants: + * The hexadecimal values are the intended ones for the following constants. + * The decimal values may be used, provided that the compiler will convert + * from decimal to binary accurately enough to produce the hexadecimal values + * shown. + */ + +vc(C0, 4.1666666666666504759E-2 ,aaaa,3e2a,a9f0,aaaa, -4, .AAAAAAAAAAA9F0) +vc(C1, -1.3888888888865302059E-3 ,0b60,bbb6,0cca,b60a, -9, -.B60B60B60A0CCA) +vc(C2, 2.4801587285601038265E-5 ,0d00,38d0,098f,cdcd, -15, .D00D00CDCD098F) +vc(C3, -2.7557313470902390219E-7 ,f27b,b593,e805,b593, -21, -.93F27BB593E805) +vc(C4, 2.0875623401082232009E-9 ,74c8,320f,3ff0,fa1e, -28, .8F74C8FA1E3FF0) +vc(C5, -1.1355178117642986178E-11 ,c32d,ae47,5a63,0a5c, -36, -.C7C32D0A5C5A63) + +ic(C0, 4.1666666666666504759E-2 , -5, 1.555555555553E) +ic(C1, -1.3888888888865301516E-3 , -10, -1.6C16C16C14199) +ic(C2, 2.4801587269650015769E-5 , -16, 1.A01A01971CAEB) +ic(C3, -2.7557304623183959811E-7 , -22, -1.27E4F1314AD1A) +ic(C4, 2.0873958177697780076E-9 , -29, 1.1EE3B60DDDC8C) +ic(C5, -1.1250289076471311557E-11 , -37, -1.8BD5986B2A52E) + +#ifdef vccast +#define C0 vccast(C0) +#define C1 vccast(C1) +#define C2 vccast(C2) +#define C3 vccast(C3) +#define C4 vccast(C4) +#define C5 vccast(C5) +#endif + +#define cos__C(z) (z*z*(C0+z*(C1+z*(C2+z*(C3+z*(C4+z*C5)))))) diff --git a/headers/private/kernel/unistd.h b/headers/private/kernel/unistd.h new file mode 100755 index 0000000000..62ec8e7217 --- /dev/null +++ b/headers/private/kernel/unistd.h @@ -0,0 +1,64 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Copyright 2002, Manuel J. Petit. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +/** + * @file unistd.h + * @brief Miscellaneous macro's and functions + */ + +#ifndef _UNISTD_H +#define _UNISTD_H + +/** + * @defgroup Unistd unistd.h + * @brief Miscellaneous macro's and functions + * @ingroup OpenBeOS_POSIX + * @{ + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int close(int); +int dup(int); +int dup2(int, int); + +ssize_t read(int, void *, size_t); +ssize_t write(int, const void *, size_t); + +int getopt(int, char * const *, const char *); +extern char *optarg; /* getopt(3) external variables */ +extern int opterr; +extern int optind; +extern int optopt; +extern int optreset; + +off_t lseek(int, off_t, int); +ssize_t read(int, void *, size_t); +ssize_t pread(int, void *, size_t, off_t); +ssize_t write(int, void const*, size_t); +ssize_t pwrite(int, void const*, size_t, off_t); + + +unsigned sleep(unsigned); +int usleep(unsigned); + +int getdtablesize(void); + +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 + +/** @} */ +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif diff --git a/headers/private/kernel/user_runtime.h b/headers/private/kernel/user_runtime.h new file mode 100755 index 0000000000..9f2139e87f --- /dev/null +++ b/headers/private/kernel/user_runtime.h @@ -0,0 +1,44 @@ +/* +** Copyright 2002, Manuel J. Petit. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef __newos__kernel__user_runtime__hh__ +#define __newos__kernel__user_runtime__hh__ + + +#include + + +struct rld_export_t +{ + int (*dl_open )(char const *path, unsigned flags); + int (*dl_close)(int lib, unsigned flags); + void *(*dl_sym )(int lib, char const *sym, unsigned flags); + + int (*load_addon)(char const *path, unsigned flags); + int (*unload_addon)(int add_on, unsigned flags); + void *(*addon_symbol)(int lib, char const *sym, unsigned flags); +}; + +struct uspace_prog_args_t +{ + char prog_name[SYS_MAX_OS_NAME_LEN]; + char prog_path[SYS_MAX_PATH_LEN]; + int argc; + int envc; + char **argv; + char **envp; + + /* + * hooks into rld for POSIX and BeOS library/module loading + */ + struct rld_export_t *rld_export; +}; + +typedef void (libinit_f)(unsigned, struct uspace_prog_args_t const *); + +void INIT_BEFORE_CTORS(unsigned, struct uspace_prog_args_t const *); +void INIT_AFTER_CTORS(unsigned, struct uspace_prog_args_t const *); + + +#endif diff --git a/headers/private/kernel/vfs.h b/headers/private/kernel/vfs.h new file mode 100755 index 0000000000..5a00a97345 --- /dev/null +++ b/headers/private/kernel/vfs.h @@ -0,0 +1,172 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#ifndef _KERNEL_VFS_H +#define _KERNEL_VFS_H + +#include +#include +#include +#include + +#define DEFAULT_FD_TABLE_SIZE 128 +#define MAX_FD_TABLE_SIZE 2048 + +#include + +/* macro to allocate a iovec array on the stack */ +#define IOVECS(name, size) \ + uint8 _##name[sizeof(iovecs) + (size)*sizeof(iovec)]; \ + iovecs *name = (iovecs *)_##name + +#ifdef __cplusplus +extern "C" { +#endif + + +#if 0 +struct fs_calls { + int (*fs_mount)(void **fs_cookie, void *flags, void *covered_vnode, fs_id id, void **priv_vnode_root); + int (*fs_unmount)(void *fs_cookie); + int (*fs_register_mountpoint)(void *fs_cookie, void *vnode, void *redir_vnode); + int (*fs_unregister_mountpoint)(void *fs_cookie, void *vnode); + int (*fs_dispose_vnode)(void *fs_cookie, void *vnode); + int (*fs_open)(void *fs_cookie, void *base_vnode, const char *path, const char *stream, stream_type stream_type, void **vnode, void **cookie, struct redir_struct *redir); + int (*fs_seek)(void *fs_cookie, void *vnode, void *cookie, off_t pos, int seek_type); + int (*fs_read)(void *fs_cookie, void *vnode, void *cookie, void *buf, off_t pos, size_t *len); + int (*fs_write)(void *fs_cookie, void *vnode, void *cookie, const void *buf, off_t pos, size_t *len); + int (*fs_ioctl)(void *fs_cookie, void *vnode, void *cookie, ulong op, void *buf, size_t len); + int (*fs_close)(void *fs_cookie, void *vnode, void *cookie); + int (*fs_create)(void *fs_cookie, void *base_vnode, const char *path, const char *stream, stream_type stream_type, struct redir_struct *redir); + int (*fs_stat)(void *fs_cookie, void *base_vnode, const char *path, const char *stream, stream_type stream_type, struct vnode_stat *stat, struct redir_struct *redir); +}; +#endif + +struct fs_calls { + int (*fs_mount)(fs_cookie *fs, fs_id id, const char *device, void *args, vnode_id *root_vnid); + int (*fs_unmount)(fs_cookie fs); + int (*fs_sync)(fs_cookie fs); + + int (*fs_lookup)(fs_cookie fs, fs_vnode dir, const char *name, vnode_id *id); + + int (*fs_getvnode)(fs_cookie fs, vnode_id id, fs_vnode *v, bool r); + int (*fs_putvnode)(fs_cookie fs, fs_vnode v, bool r); + int (*fs_removevnode)(fs_cookie fs, fs_vnode v, bool r); + + int (*fs_open)(fs_cookie fs, fs_vnode v, file_cookie *cookie, stream_type st, int oflags); + int (*fs_close)(fs_cookie fs, fs_vnode v, file_cookie cookie); + int (*fs_freecookie)(fs_cookie fs, fs_vnode v, file_cookie cookie); + int (*fs_fsync)(fs_cookie fs, fs_vnode v); + + ssize_t (*fs_read)(fs_cookie fs, fs_vnode v, file_cookie cookie, void *buf, off_t pos, size_t *len); + ssize_t (*fs_write)(fs_cookie fs, fs_vnode v, file_cookie cookie, const void *buf, off_t pos, size_t *len); + int (*fs_seek)(fs_cookie fs, fs_vnode v, file_cookie cookie, off_t pos, int st); + + int (*fs_read_dir)(fs_cookie fs, fs_vnode v, file_cookie cookie, struct dirent *buffer, size_t bufferSize, uint32 *_num); + int (*fs_rewind_dir)(fs_cookie fs, fs_vnode v, file_cookie cookie); + int (*fs_ioctl)(fs_cookie fs, fs_vnode v, file_cookie cookie, ulong op, void *buf, size_t len); + + int (*fs_canpage)(fs_cookie fs, fs_vnode v); + ssize_t (*fs_readpage)(fs_cookie fs, fs_vnode v, iovecs *vecs, off_t pos); + ssize_t (*fs_writepage)(fs_cookie fs, fs_vnode v, iovecs *vecs, off_t pos); + + int (*fs_create)(fs_cookie fs, fs_vnode dir, const char *name, stream_type st, void *create_args, vnode_id *new_vnid); + int (*fs_unlink)(fs_cookie fs, fs_vnode dir, const char *name); + int (*fs_rename)(fs_cookie fs, fs_vnode olddir, const char *oldname, fs_vnode newdir, const char *newname); + + int (*fs_rstat)(fs_cookie fs, fs_vnode v, struct stat *stat); + int (*fs_wstat)(fs_cookie fs, fs_vnode v, struct stat *stat, int stat_mask); +}; + +int vfs_init(kernel_args *ka); +int vfs_bootstrap_all_filesystems(void); +int vfs_register_filesystem(const char *name, struct fs_calls *calls); +void *vfs_new_io_context(void *parent_ioctx); +int vfs_free_io_context(void *ioctx); +int vfs_test(void); + +struct rlimit; +int vfs_getrlimit(int resource, struct rlimit * rlp); +int vfs_setrlimit(int resource, const struct rlimit * rlp); + +image_id vfs_load_fs_module(const char *path); + +/* calls needed by fs internals */ +int vfs_get_vnode(fs_id fsid, vnode_id vnid, fs_vnode *v); +int vfs_put_vnode(fs_id fsid, vnode_id vnid); +int vfs_remove_vnode(fs_id fsid, vnode_id vnid); + +/* calls needed by the VM for paging */ +int vfs_get_vnode_from_fd(int fd, bool kernel, void **vnode); +int vfs_get_vnode_from_path(const char *path, bool kernel, void **vnode); +int vfs_put_vnode_ptr(void *vnode); +void vfs_vnode_acquire_ref(void *vnode); +void vfs_vnode_release_ref(void *vnode); +ssize_t vfs_canpage(void *vnode); +ssize_t vfs_readpage(void *vnode, iovecs *vecs, off_t pos); +ssize_t vfs_writepage(void *vnode, iovecs *vecs, off_t pos); +void *vfs_get_cache_ptr(void *vnode); +int vfs_set_cache_ptr(void *vnode, void *cache); + +/* calls kernel code should make for file I/O */ +int sys_mount(const char *path, const char *device, const char *fs_name, void *args); +int sys_unmount(const char *path); +int sys_sync(void); +int sys_open(const char *path, stream_type st, int omode); +int sys_fsync(int fd); +int sys_seek(int fd, off_t pos, int seek_type); +int sys_create(const char *path, stream_type stream_type); +int sys_unlink(const char *path); +int sys_rename(const char *oldpath, const char *newpath); +int sys_wstat(const char *path, struct stat *stat, int stat_mask); +char *sys_getcwd(char *buf, size_t size); +int sys_setcwd(const char* path); +int sys_dup(int fd); +int sys_dup2(int ofd, int nfd); + +/* calls the syscall dispatcher should use for user file I/O */ +int user_mount(const char *path, const char *device, const char *fs_name, void *args); +int user_unmount(const char *path); +int user_sync(void); +int user_open(const char *path, stream_type st, int omode); +int user_fsync(int fd); +int user_seek(int fd, off_t pos, int seek_type); +int user_create(const char *path, stream_type stream_type); +int user_unlink(const char *path); +int user_rename(const char *oldpath, const char *newpath); +int user_rstat(const char *path, struct stat *stat); +int user_wstat(const char *path, struct stat *stat, int stat_mask); +int user_getcwd(char *buf, size_t size); +int user_setcwd(const char* path); +int user_dup(int fd); +int user_dup2(int ofd, int nfd); + +/* fd kernel prototypes (implementation located in fd.c) */ +extern ssize_t sys_read(int fd, void *buf, off_t pos, size_t len); +extern ssize_t sys_write(int fd, const void *buf, off_t pos, size_t len); +extern int sys_ioctl(int fd, ulong cmd, void *data, size_t length); +extern ssize_t sys_read_dir(int fd, struct dirent *buffer, size_t bufferSize); +extern status_t sys_rewind_dir(int fd); +extern int sys_rstat(const char *path, struct stat *stat); +extern int sys_close(int fd); + + +/* fd user prototypes (implementation located in fd.c) */ +extern ssize_t user_read(int fd, void *buf, off_t pos, size_t len); +extern ssize_t user_write(int fd, const void *buf, off_t pos, size_t len); +extern int user_ioctl(int fd, ulong cmd, void *data, size_t length); +extern ssize_t user_read_dir(int fd, struct dirent *buffer, size_t bufferSize); +extern status_t user_rewind_dir(int fd); +extern int user_fstat(int, struct stat *); +extern int user_close(int fd); + +/* vfs entry points... */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/headers/private/kernel/vm.h b/headers/private/kernel/vm.h new file mode 100755 index 0000000000..bca0d38591 --- /dev/null +++ b/headers/private/kernel/vm.h @@ -0,0 +1,70 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _KERNEL_VM_H +#define _KERNEL_VM_H + +#include +#include +#include +#include +#include +#include + +//void vm_dump_areas(vm_address_space *aspace); +int vm_init(kernel_args *ka); +int vm_init_postsem(kernel_args *ka); +int vm_init_postthread(kernel_args *ka); + +aspace_id vm_create_aspace(const char *name, addr base, addr size, bool kernel); +int vm_delete_aspace(aspace_id); +vm_address_space *vm_get_kernel_aspace(void); +aspace_id vm_get_kernel_aspace_id(void); +vm_address_space *vm_get_current_user_aspace(void); +aspace_id vm_get_current_user_aspace_id(void); +vm_address_space *vm_get_aspace_by_id(aspace_id aid); +void vm_put_aspace(vm_address_space *aspace); +vm_region *vm_get_region_by_id(region_id rid); +void vm_put_region(vm_region *region); +#define vm_aspace_swap(aspace) arch_vm_aspace_swap(aspace) + +region_id vm_create_anonymous_region(aspace_id aid, char *name, void **address, int addr_type, + addr size, int wiring, int lock); +region_id vm_map_physical_memory(aspace_id aid, char *name, void **address, int addr_type, + addr size, int lock, addr phys_addr); +region_id vm_map_file(aspace_id aid, char *name, void **address, int addr_type, + addr size, int lock, int mapping, const char *path, off_t offset); +region_id vm_create_null_region(aspace_id aid, char *name, void **address, int addr_type, addr size); +region_id vm_clone_region(aspace_id aid, char *name, void **address, int addr_type, + region_id source_region, int mapping, int lock); +int vm_delete_region(aspace_id aid, region_id id); +region_id vm_find_region_by_name(aspace_id aid, const char *name); +int vm_get_region_info(region_id id, vm_region_info *info); + +int vm_get_page_mapping(aspace_id aid, addr vaddr, addr *paddr); +int vm_get_physical_page(addr paddr, addr *vaddr, int flags); +int vm_put_physical_page(addr vaddr); + +int user_memcpy(void *to, const void *from, size_t size); +int user_strcpy(char *to, const char *from); +int user_strncpy(char *to, const char *from, size_t size); +int user_memset(void *s, char c, size_t count); + +region_id user_vm_create_anonymous_region(char *uname, void **uaddress, int addr_type, + addr size, int wiring, int lock); +region_id user_vm_clone_region(char *uname, void **uaddress, int addr_type, + region_id source_region, int mapping, int lock); +region_id user_vm_map_file(char *uname, void **uaddress, int addr_type, + addr size, int lock, int mapping, const char *upath, off_t offset); +int user_vm_get_region_info(region_id id, vm_region_info *uinfo); + +region_id find_region_by_name(const char *); +region_id find_region_by_address (addr); +int vm_resize_region (aspace_id, region_id, size_t); + +// XXX remove later +void vm_test(void); + +#endif + diff --git a/headers/private/kernel/vm_cache.h b/headers/private/kernel/vm_cache.h new file mode 100755 index 0000000000..a487a7dd15 --- /dev/null +++ b/headers/private/kernel/vm_cache.h @@ -0,0 +1,24 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _KERNEL_VM_CACHE_H +#define _KERNEL_VM_CACHE_H + +#include +#include +#include + +int vm_cache_init(kernel_args *ka); +vm_cache *vm_cache_create(vm_store *store); +vm_cache_ref *vm_cache_ref_create(vm_cache *cache); +void vm_cache_acquire_ref(vm_cache_ref *cache_ref, bool acquire_store_ref); +void vm_cache_release_ref(vm_cache_ref *cache_ref); +vm_page *vm_cache_lookup_page(vm_cache_ref *cache_ref, off_t page); +void vm_cache_insert_page(vm_cache_ref *cache_ref, vm_page *page, off_t offset); +void vm_cache_remove_page(vm_cache_ref *cache_ref, vm_page *page); +int vm_cache_insert_region(vm_cache_ref *cache_ref, vm_region *region); +int vm_cache_remove_region(vm_cache_ref *cache_ref, vm_region *region); + +#endif + diff --git a/headers/private/kernel/vm_page.h b/headers/private/kernel/vm_page.h new file mode 100755 index 0000000000..37abdeee29 --- /dev/null +++ b/headers/private/kernel/vm_page.h @@ -0,0 +1,26 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _KERNEL_VM_PAGE_H +#define _KERNEL_VM_PAGE_H + +#include +#include +#include + +int vm_page_init(kernel_args *ka); +int vm_page_init2(kernel_args *ka); +int vm_page_init_postthread(kernel_args *ka); + +int vm_mark_page_inuse(addr page); +int vm_mark_page_range_inuse(addr start_page, addr len); +int vm_page_set_state(vm_page *page, int state); + +vm_page *vm_page_allocate_page(int state); +vm_page *vm_page_allocate_page_run(int state, addr len); +vm_page *vm_page_allocate_specific_page(addr page_num, int state); +vm_page *vm_lookup_page(addr page_num); + +#endif + diff --git a/headers/private/kernel/vm_priv.h b/headers/private/kernel/vm_priv.h new file mode 100755 index 0000000000..a8718611e0 --- /dev/null +++ b/headers/private/kernel/vm_priv.h @@ -0,0 +1,51 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _KERNEL_VM_PRIV_H +#define _KERNEL_VM_PRIV_H + +#include +#include + +/* should make these scale with the system */ +#define DEFAULT_KERNEL_WORKING_SET 1024 +#define DEFAULT_WORKING_SET 256 +#define DEFAULT_MAX_WORKING_SET 65536 +#define DEFAULT_MIN_WORKING_SET 64 + +#define WORKING_SET_INCREMENT 32 +#define WORKING_SET_DECREMENT 32 + +#define PAGE_DAEMON_INTERVAL 500000 +#define PAGE_SCAN_QUANTUM 500 +#define WORKING_SET_ADJUST_INTERVAL 5000000 +#define MAX_FAULTS_PER_SECOND 100 +#define MIN_FAULTS_PER_SECOND 10 + +#define WRITE_COUNT 1024 +#define READ_COUNT 1 + +// page attributes +#define PAGE_MODIFIED 0x04 +#define PAGE_ACCESSED 0x08 +#define PAGE_PRESENT 0x10 + +// Should only be used by vm internals +int vm_page_fault(addr address, addr fault_address, bool is_write, bool is_user, addr *newip); +void vm_increase_max_commit(addr delta); +int vm_daemon_init(void); + +// used by the page daemon to walk the list of address spaces +int vm_aspace_walk_start(struct hash_iterator *i); +vm_address_space *vm_aspace_walk_next(struct hash_iterator *i); + +// get some data about the number of pages in the system +addr vm_page_num_pages(void); +addr vm_page_num_free_pages(void); + +// allocates memory from the ka structure +addr vm_alloc_from_ka_struct(kernel_args *ka, unsigned int size, int lock); + +#endif + diff --git a/headers/private/kernel/vm_store_anonymous_noswap.h b/headers/private/kernel/vm_store_anonymous_noswap.h new file mode 100755 index 0000000000..4634f0fc3c --- /dev/null +++ b/headers/private/kernel/vm_store_anonymous_noswap.h @@ -0,0 +1,14 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _KERNEL_VM_STORE_ANONYMOUS_H +#define _KERNEL_VM_STORE_ANONYMOUS_H + +#include +#include + +vm_store *vm_store_create_anonymous_noswap(void); + +#endif + diff --git a/headers/private/kernel/vm_store_device.h b/headers/private/kernel/vm_store_device.h new file mode 100755 index 0000000000..31fd91235d --- /dev/null +++ b/headers/private/kernel/vm_store_device.h @@ -0,0 +1,14 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _KERNEL_VM_STORE_DEVICE_H +#define _KERNEL_VM_STORE_DEVICE_H + +#include +#include + +vm_store *vm_store_create_device(addr base_addr); + +#endif + diff --git a/headers/private/kernel/vm_store_null.h b/headers/private/kernel/vm_store_null.h new file mode 100755 index 0000000000..6e7f0a8a60 --- /dev/null +++ b/headers/private/kernel/vm_store_null.h @@ -0,0 +1,14 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _KERNEL_VM_STORE_NULL_H +#define _KERNEL_VM_STORE_NULL_H + +#include +#include + +vm_store *vm_store_create_null(void); + +#endif + diff --git a/headers/private/kernel/vm_store_vnode.h b/headers/private/kernel/vm_store_vnode.h new file mode 100755 index 0000000000..5d624110c5 --- /dev/null +++ b/headers/private/kernel/vm_store_vnode.h @@ -0,0 +1,14 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _KERNEL_VM_STORE_VNODE_H +#define _KERNEL_VM_STORE_VNODE_H + +#include +#include + +vm_store *vm_store_create_vnode(void *vnode); + +#endif + diff --git a/headers/private/kernel/vm_translation_map.h b/headers/private/kernel/vm_translation_map.h new file mode 100755 index 0000000000..191895e22c --- /dev/null +++ b/headers/private/kernel/vm_translation_map.h @@ -0,0 +1,48 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _NEWOS_KERNEL_ARCH_VM_TRANSLATION_MAP_H +#define _NEWOS_KERNEL_ARCH_VM_TRANSLATION_MAP_H + +#include +#include +#include + +typedef struct vm_translation_map_struct { + struct vm_translation_map_struct *next; + struct vm_translation_map_ops_struct *ops; + recursive_lock lock; + int map_count; + struct vm_translation_map_arch_info_struct *arch_data; +} vm_translation_map; + +// table of operations the vm may want to do to this mapping +typedef struct vm_translation_map_ops_struct { + void (*destroy)(vm_translation_map *); + int (*lock)(vm_translation_map*); + int (*unlock)(vm_translation_map*); + int (*map)(vm_translation_map *map, addr va, addr pa, unsigned int attributes); + int (*unmap)(vm_translation_map *map, addr start, addr end); + int (*query)(vm_translation_map *map, addr va, addr *out_physical, unsigned int *out_flags); + addr (*get_mapped_size)(vm_translation_map*); + int (*protect)(vm_translation_map *map, addr base, addr top, unsigned int attributes); + int (*clear_flags)(vm_translation_map *map, addr va, unsigned int flags); + void (*flush)(vm_translation_map *map); + int (*get_physical_page)(addr physical_address, addr *out_virtual_address, int flags); + int (*put_physical_page)(addr virtual_address); +} vm_translation_map_ops; + +int vm_translation_map_create(vm_translation_map *new_map, bool kernel); +int vm_translation_map_module_init(kernel_args *ka); +int vm_translation_map_module_init2(kernel_args *ka); +void vm_translation_map_module_init_post_sem(kernel_args *ka); +// quick function to map a page in regardless of map context. Used in VM initialization, +// before most vm data structures exist +int vm_translation_map_quick_map(kernel_args *ka, addr va, addr pa, unsigned int attributes, addr (*get_free_page)(kernel_args *)); + +// quick function to return the physical pgdir of a mapping, needed for a context switch +addr vm_translation_map_get_pgdir(vm_translation_map *map); + +#endif + diff --git a/headers/private/kernel/zero.h b/headers/private/kernel/zero.h new file mode 100755 index 0000000000..41dc576e33 --- /dev/null +++ b/headers/private/kernel/zero.h @@ -0,0 +1,12 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _ZERO_DEV_H +#define _ZERO_DEV_H + +#include + +int zero_dev_init(kernel_args *ka); + +#endif diff --git a/headers/private/kernel/zfs.h b/headers/private/kernel/zfs.h new file mode 100755 index 0000000000..cd070ef054 --- /dev/null +++ b/headers/private/kernel/zfs.h @@ -0,0 +1,51 @@ +/* +** Copyright 2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _ZFS_H +#define _ZFS_H + +#include +#include "zfs_fs.h" + +/* mount structure */ +typedef struct zfs_fs { + fs_id id; + int fd; + void *dev_vnode; + zfs_superblock sb; +} zfs_fs; + +/* fs calls */ +int zfs_mount(fs_cookie *fs, fs_id id, const char *device, void *args, vnode_id *root_vnid); +int zfs_unmount(fs_cookie fs); +int zfs_sync(fs_cookie fs); + +int zfs_lookup(fs_cookie fs, fs_vnode dir, const char *name, vnode_id *id); + +int zfs_getvnode(fs_cookie fs, vnode_id id, fs_vnode *v, bool r); +int zfs_putvnode(fs_cookie fs, fs_vnode v, bool r); +int zfs_removevnode(fs_cookie fs, fs_vnode v, bool r); + +int zfs_open(fs_cookie fs, fs_vnode v, file_cookie *cookie, stream_type st, int oflags); +int zfs_close(fs_cookie fs, fs_vnode v, file_cookie cookie); +int zfs_freecookie(fs_cookie fs, fs_vnode v, file_cookie cookie); +int zfs_fsync(fs_cookie fs, fs_vnode v); + +ssize_t zfs_read(fs_cookie fs, fs_vnode v, file_cookie cookie, void *buf, off_t pos, size_t *len); +ssize_t zfs_write(fs_cookie fs, fs_vnode v, file_cookie cookie, const void *buf, off_t pos, size_t *len); +int zfs_seek(fs_cookie fs, fs_vnode v, file_cookie cookie, off_t pos, seek_type st); +int zfs_ioctl(fs_cookie fs, fs_vnode v, file_cookie cookie, int op, void *buf, size_t len); + +int zfs_canpage(fs_cookie fs, fs_vnode v); +ssize_t zfs_readpage(fs_cookie fs, fs_vnode v, iovecs *vecs, off_t pos); +ssize_t zfs_writepage(fs_cookie fs, fs_vnode v, iovecs *vecs, off_t pos); + +int zfs_create(fs_cookie fs, fs_vnode dir, const char *name, stream_type st, void *create_args, vnode_id *new_vnid); +int zfs_unlink(fs_cookie fs, fs_vnode dir, const char *name); +int zfs_rename(fs_cookie fs, fs_vnode olddir, const char *oldname, fs_vnode newdir, const char *newname); + +int zfs_rstat(fs_cookie fs, fs_vnode v, struct file_stat *stat); +int zfs_wstat(fs_cookie fs, fs_vnode v, struct file_stat *stat, int stat_mask); + +#endif diff --git a/headers/private/kernel/zfs_fs.h b/headers/private/kernel/zfs_fs.h new file mode 100755 index 0000000000..2e50ca0862 --- /dev/null +++ b/headers/private/kernel/zfs_fs.h @@ -0,0 +1,117 @@ +/* +** Copyright 2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _ZFS_FS_H +#define _ZFS_FS_H + +#include + +typedef int64 inode_num; +typedef int64 block_num; + +#define ZFS_SB_MAGIC1 0x23afb490 +#define ZFS_SB_MAGIC2 0x343287f4 + +#define ZFS_SB_OFFSET 1024 +#define ZFS_BLOCKSIZE 4096 + +#define ZFS_INODE_TABLE_INODE 0 +#define ZFS_BOOT_INODE 1 +#define ZFS_BITMAP_INODE 2 +#define ZFS_ROOT_DIR_INODE 3 + +#define ZFS_RESERVED_INODES 32 + +#define ZFS_HOST_ENDIAN 0x12345678 +#define ZFS_SWAPPED_ENDIAN 0x78563412 + +#define ZFS_CURRENT_VERSION 1 + +typedef struct zfs_superblock { + int32 magic1; + int32 version; + int32 endian; + int32 blocksize; + + int64 num_blocks; + int64 used_blocks; + + block_num boot_code_start; + block_num inode_table_start; + + char name[32]; + + int32 magic2; +} zfs_superblock; + +#define ZFS_INODE_SIZE ZFS_BLOCKSIZE + +#define ZFS_INODE_MAGIC 0x444f4e49 // 'INOD' + +#define ZFS_INODE_FLAG_INUSE 0x1 +#define ZFS_INODE_FLAG_PRIMARY 0x2 + +typedef struct zfs_inode_container { + int32 magic; + int16 flags; + int16 num_attributes; + inode_num num; +/* 0x10 */ + inode_num next_spillover_inode; + inode_num primary_inode; +/* 0x20 */ +} zfs_inode_container; + +typedef struct zfs_attribute_header { + uint32 type; + uint32 len; + uint8 non_resident; + uint8 name_len; + uint16 value_offset; + uint32 filler; +/* 0x10 */ +} zfs_attribute_header; + +typedef struct zfs_attribute_resident { + uint32 len; + uint16 offset; + uint16 filler; +/* 0x08 */ +} zfs_attribute_resident; + +typedef struct zfs_attribute_nonresident { + block_num starting_fileblock; + block_num ending_fileblock; +/* 0x10 */ + uint16 runlist_offset; + uint16 num_runs; + uint32 filler; + uint64 len; +/* 0x20 */ +} zfs_attribute_nonresident; + +typedef struct zfs_run { + block_num start; + int64 len; +} zfs_run; + +#define ZFS_ATTR_STD_INFO 0x10 +#define ZFS_ATTR_DIR 0x20 +#define ZFS_ATTR_DATA 0x30 +#define ZFS_ATTR_BITMAP 0x40 + +typedef struct zfs_attr_std_info { + uint64 create_time; + uint64 last_mod_time; + uint64 last_access_time; +} zfs_attr_std_info; + +typedef struct zfs_dir_ent { + inode_num inum; + uint16 len; + uint16 name_len; + char name[0]; +} zfs_dir_ent; + +#endif diff --git a/headers/private/media/ChannelMixer.h b/headers/private/media/ChannelMixer.h new file mode 100644 index 0000000000..0a9c59d992 --- /dev/null +++ b/headers/private/media/ChannelMixer.h @@ -0,0 +1,32 @@ +#ifndef _CHANNEL_MIXER_ +#define _CHANNEL_MIXER_ + +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: ChannelMixer.h + * DESCR: Converts mono into stereo + * stereo into mono (this one isn't very good) + * (multiple channel support should be added in the future) + ***********************************************************************/ + +namespace MediaKitPrivate { + +class ChannelMixer +{ +public: + static status_t + mix(void *dest, int dest_chan_count, + const void *source, int source_chan_count, + int framecount, uint32 format); + + static status_t + mix_2_to_1(void *dest, const void *source, int framecount, uint32 format); + + static status_t + mix_1_to_2(void *dest, const void *source, int framecount, uint32 format); + +}; + +} //namespace MediaKitPrivate + +#endif diff --git a/headers/private/media/Decoder.h b/headers/private/media/Decoder.h new file mode 100644 index 0000000000..0bcbc125e5 --- /dev/null +++ b/headers/private/media/Decoder.h @@ -0,0 +1,42 @@ + +// this header is similar to functions found in libmedia.so +// and the media_kit decoder add-ons +// we will use it as basic information, but are not trying to +// create a binary compatible interface +// this API will totally change, as we are creating our own API + +#include +#include + +namespace media_kit_private { + +class Decoder +{ +public: + virtual ~Decoder(void); /* this needs to be virtual */ + Decoder(void); + + /* not sure if all three need to be virtual */ + virtual status_t SetTrack(BMediaTrack *track); + /* what does this one do? strange parameters */ + virtual status_t Reset(long, long long, long long *, long long, long long *); + virtual status_t GetNextChunk(void const **chunkData, size_t *chunkSize, + media_header *mh, media_decode_info *mdi); + + virtual status_t Decode(void *out_buffer, int64 *out_frameCount, + media_header *out_mh, media_decode_info *info) = 0; + virtual status_t Format(media_format *) = 0; + virtual status_t Sniff(media_format const *, void const *in_buffer, unsigned long in_buffersize) = 0; + virtual status_t GetCodecInfo(media_codec_info *out_mci) const = 0; + +private: + virtual status_t Perform(long, void *); + //virtual function and data stuffing will be done later +}; + +}; // namespace media_kit_private + + +extern "C" status_t register_decoder(); +extern "C" BPrivate::Decoder * instantiate_decoder(); + diff --git a/headers/private/media/Encoder.h b/headers/private/media/Encoder.h new file mode 100644 index 0000000000..d4468ab29d --- /dev/null +++ b/headers/private/media/Encoder.h @@ -0,0 +1,44 @@ + +// this header is similar to functions found in libmedia.so +// and the media_kit encoder add-ons +// we will use it as basic information, but are not trying to +// create a binary compatible interface +// this API will totally change, as we are creating our own API + +namespace media_kit_private { + +class Encoder +{ +public: + virtual ~Encoder(void); /* this needs to be virtual */ + Encoder(void); + + /* not sure if all these need to be virtual */ + virtual status_t Flush(void); + virtual status_t StartEncoder(void); + virtual status_t SetEncodeParameters(encode_parameters *); + virtual status_t GetEncodeParameters(encode_parameters *) const; + virtual status_t GetParameterView(void); + virtual status_t SetParameterValue(long, void const *, unsigned long); + virtual status_t GetParameterValue(long, void *, unsigned long *); + virtual status_t WriteChunk(void const *, unsigned long, media_encode_info *); + virtual status_t AddTrackInfo(unsigned long, char const *, unsigned long); + virtual status_t AddCopyright(char const *); + virtual status_t Web(void); + virtual status_t AttachedToTrack(void); + virtual status_t SetTrack(BMediaTrack *); + + virtual status_t GetCodecInfo(media_codec_info *) const = 0; + virtual status_t Encode(void const *, long long, media_encode_info *) = 0; + virtual status_t SetFormat(media_file_format *, media_format *, media_format *) = 0; + +private: + virtual status_t Perform(long, void *); + //virtual function and data stuffing will be done later +}; + +}; // namespace media_kit_private + +extern "C" status_t register_encoder(); +extern "C" BPrivate::Encoder *instantiate_nth_encoder(); +extern "C" BPrivate::Encoder *instantiate_encoder(); diff --git a/headers/private/media/Extractor.h b/headers/private/media/Extractor.h new file mode 100644 index 0000000000..651686b0a8 --- /dev/null +++ b/headers/private/media/Extractor.h @@ -0,0 +1,45 @@ + +// this header is similar to functions found in libmedia.so +// and the media_kit extractor add-ons +// we will use it as basic information, but are not trying to +// create a binary compatible interface +// this API will totally change, as we are creating our own API + +namespace media_kit_private { + +class Extractor +{ +public: + Extractor(void); + virtual ~Extractor(void); + + virtual status_t Copyright(void); + virtual status_t Extractor(void); + virtual status_t Perform(long, void *); + virtual status_t SniffFormat(media_format const *, long *, long *); + virtual status_t Source(void) const; + + virtual status_t find_stream_extractor(long *, media_format *, BPrivate::Extractor *, long, long *, long *); + + virtual status_t Sniff(long *, long *) = 0; + virtual status_t GetDuration(long, long long *) = 0; + virtual status_t SplitNext(long, void *, long long *, char *, long *, char **, long *, media_header *) = 0; + virtual status_t Seek(long, void *, long, long, long long *, long long *, long long *, char *, long *, bool *) = 0; + virtual status_t FreeCookie(long, void *) = 0; + virtual status_t AllocateCookie(long, void **) = 0; + virtual status_t CountFrames(long, long long *) = 0; + virtual status_t TrackInfo(long, media_format *, void **, long *) = 0; + virtual status_t GetFileFormatInfo(media_file_format *) = 0; + +private: + virtual status_t Perform(long, void *); + //virtual function and data stuffing will be done later +}; + +}; // namespace media_kit_private + +extern "C" { + status_t instantiate_extractor(); +} + + diff --git a/headers/private/media/PortPool.h b/headers/private/media/PortPool.h new file mode 100644 index 0000000000..3f174ff45b --- /dev/null +++ b/headers/private/media/PortPool.h @@ -0,0 +1,37 @@ +/*********************************************************************** + * Copyright (c) 2002 Marcus Overhagen. All Rights Reserved. + * This file may be used under the terms of the OpenBeOS License. + * + * A pool of kernel ports + ***********************************************************************/ +#ifndef _POOL_PORT_H_ +#define _POOL_PORT_H_ + +class PortPool +{ +public: + PortPool(); + ~PortPool(); + + port_id GetPort(); + void PutPort(port_id port); + +private: + void Lock(); + void Unlock(); + + struct PortInfo + { + port_id port; + bool used; + }; + PortInfo * pool; + int count; + int maxcount; + int32 locker_atom; + sem_id locker_sem; +}; + +extern PortPool *_PortPool; + +#endif diff --git a/headers/private/media/SampleConverter.h b/headers/private/media/SampleConverter.h new file mode 100644 index 0000000000..f5f50bca33 --- /dev/null +++ b/headers/private/media/SampleConverter.h @@ -0,0 +1,53 @@ +#ifndef _SAMPLE_CONVERTER_ +#define _SAMPLE_CONVERTER_ + +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: SampleConverter.h + * DESCR: Converts between different sample formats: + * media_raw_audio_format::B_AUDIO_FLOAT + * media_raw_audio_format::B_AUDIO_INT + * media_raw_audio_format::B_AUDIO_SHORT + * media_raw_audio_format::B_AUDIO_CHAR + * media_raw_audio_format::B_AUDIO_UCHAR + ***********************************************************************/ + +namespace MediaKitPrivate { + +class SampleConverter +{ +public: + static status_t + convert(void *dest, uint32 dest_format, + const void *source, uint32 source_format, + int samplecount); + + static void convert(uint8 *dest, const float *source, int samplecount); + static void convert(uint8 *dest, const int32 *source, int samplecount); + static void convert(uint8 *dest, const int16 *source, int samplecount); + static void convert(uint8 *dest, const int8 *source, int samplecount); + + static void convert(int8 *dest, const float *source, int samplecount); + static void convert(int8 *dest, const int32 *source, int samplecount); + static void convert(int8 *dest, const int16 *source, int samplecount); + static void convert(int8 *dest, const uint8 *source, int samplecount); + + static void convert(int16 *dest, const float *source, int samplecount); + static void convert(int16 *dest, const int32 *source, int samplecount); + static void convert(int16 *dest, const int8 *source, int samplecount); + static void convert(int16 *dest, const uint8 *source, int samplecount); + + static void convert(int32 *dest, const float *source, int samplecount); + static void convert(int32 *dest, const int16 *source, int samplecount); + static void convert(int32 *dest, const int8 *source, int samplecount); + static void convert(int32 *dest, const uint8 *source, int samplecount); + + static void convert(float *dest, const int32 *source, int samplecount); + static void convert(float *dest, const int16 *source, int samplecount); + static void convert(float *dest, const int8 *source, int samplecount); + static void convert(float *dest, const uint8 *source, int samplecount); +}; + +} //namespace MediaKitPrivate + +#endif diff --git a/headers/private/media/SamplingrateConverter.h b/headers/private/media/SamplingrateConverter.h new file mode 100644 index 0000000000..7877df15c5 --- /dev/null +++ b/headers/private/media/SamplingrateConverter.h @@ -0,0 +1,29 @@ +#ifndef _SAMPLINGRATE_CONVERTER_ +#define _SAMPLINGRATE_CONVERTER_ + +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: SamplingrateConverter.cpp + * DESCR: Converts between different sampling rates + * This is really bad code, as there are much better algorithms + * than the simple duplicating or dropping of samples. + * Also, the implementation isn't very nice. + * Feel free to send me better versions to marcus@overhagen.de + ***********************************************************************/ + +namespace MediaKitPrivate { + +class SamplingrateConverter +{ +public: + static status_t + convert(void *dest, int destframecount, + const void *src, int srcframecount, + uint32 format, + int channel_count); +}; + +} //namespace MediaKitPrivate + +#endif + diff --git a/headers/private/media/SharedBufferList.h b/headers/private/media/SharedBufferList.h new file mode 100644 index 0000000000..dd9b3f2b85 --- /dev/null +++ b/headers/private/media/SharedBufferList.h @@ -0,0 +1,51 @@ +/*********************************************************************** + * Copyright (c) 2002 Marcus Overhagen. All Rights Reserved. + * This file may be used under the terms of the OpenBeOS License. + * + * Used for BBufferGroup and BBuffer management across teams + ***********************************************************************/ +#ifndef _SHARED_BUFFER_LIST_H_ +#define _SHARED_BUFFER_LIST_H_ + +// created in the media server, cloned into +// each BBufferGroup (visible in all address spaces / teams) +struct _shared_buffer_list +{ + struct _shared_buffer_info + { + media_buffer_id id; + BBuffer * buffer; + bool reclaimed; + // the reclaim_sem belonging to the BBufferGroup of this BBuffer + // also used as a unique identifier of the group + sem_id reclaim_sem; + }; + enum { MAX_BUFFER = 666 }; // this fixed limit is probably very evil + + sem_id locker_sem; + int32 locker_atom; + + // always only the first "buffercount" entries in the "info" array are used + int32 buffercount; + _shared_buffer_info info[MAX_BUFFER]; + + status_t AddBuffer(sem_id group_reclaim_sem, BBuffer *buffer); + status_t RequestBuffer(sem_id group_reclaim_sem, int32 buffers_in_group, size_t size, media_buffer_id wantID, BBuffer **buffer, bigtime_t timeout); + status_t GetBufferList(sem_id group_reclaim_sem, int32 buf_count, BBuffer **out_buffers); + status_t RecycleBuffer(BBuffer *buffer); + + + status_t Init(); + + static _shared_buffer_list *Clone(area_id id = -1); + void Terminate(sem_id group_reclaim_sem); + void Unmap(); + + status_t Lock(); + status_t Unlock(); + + // used by RequestBuffer, call this one with the list locked! + void RequestBufferInOtherGroups(sem_id group_reclaim_sem, media_buffer_id id); +}; + +#endif diff --git a/headers/private/media/TList.h b/headers/private/media/TList.h new file mode 100644 index 0000000000..7069759730 --- /dev/null +++ b/headers/private/media/TList.h @@ -0,0 +1,40 @@ + +template class List +{ +public: + List() : count(0) {} + + void Insert(const value &v) + { + value temp; + if (count == MAXENT) debugger("template List out of memory"); + list[count] = v; + count++; + } + + // you can't Remove() while iterating through the list using GetAt() + bool GetAt(int32 index, value *v) + { + if (index < 0 || index >= count) + return false; + *v = list[index]; + return true; + } + + // you can't Remove() while iterating through the map using GetAt() + bool Remove(int32 index) + { + if (index < 0 || index >= count) + return false; + count--; + if (count > 0) + list[index] = list[count]; + return true; + } + +private: + enum { MAXENT = 64 }; + value list[MAXENT]; + int count; +}; + diff --git a/headers/private/media/TMap.h b/headers/private/media/TMap.h new file mode 100644 index 0000000000..7b8798a644 --- /dev/null +++ b/headers/private/media/TMap.h @@ -0,0 +1,60 @@ + +template class Map +{ +public: + Map() : count(0) {} + + void Insert(const key &k, const value &v) + { + value temp; + if (count == MAXENT) debugger("template Map out of memory"); + if (Get(k, &temp)) debugger("template Map inserting duplicate key"); + list[count].k = k; + list[count].v = v; + count++; + } + + bool Get(const key &k, value *v) + { + for (int i = 0; i < count; i++) + if (list[i].k == k) { + *v = list[i].v; + return true; + } + return false; + } + + // you can't Remove() while iterating through the map using GetAt() + bool GetAt(int32 index, value *v) + { + if (index < 0 || index >= count) + return false; + *v = list[index].v; + return true; + } + + // you can't Remove() while iterating through the map using GetAt() + bool Remove(const key &k) + { + for (int i = 0; i < count; i++) + if (list[i].k == k) { + count--; + if (count > 0) { + list[i].v = list[count].v; + list[i].k = list[count].k; + } + return true; + } + return false; + } + +private: + enum { MAXENT = 64 }; + struct ent { + key k; + value v; + }; + ent list[MAXENT]; + int count; +}; + diff --git a/headers/private/media/VolumeControl.h b/headers/private/media/VolumeControl.h new file mode 100644 index 0000000000..ba6debf0ef --- /dev/null +++ b/headers/private/media/VolumeControl.h @@ -0,0 +1,17 @@ +#ifndef _VOLUME_CONTROL_ +#define _VOLUME_CONTROL_ + +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: VolumeControl.h + * DESCR: transitional private volume control functions + ***********************************************************************/ + +namespace MediaKitPrivate { + +status_t GetMasterVolume(float *left, float *right); +status_t SetMasterVolume(float left, float right); + +} //namespace MediaKitPrivate + +#endif diff --git a/headers/private/media/Writer.h b/headers/private/media/Writer.h new file mode 100644 index 0000000000..1ed3363bb3 --- /dev/null +++ b/headers/private/media/Writer.h @@ -0,0 +1,38 @@ + +// this header is similar to functions found in libmedia.so +// and the media_kit writer add-ons +// we will use it as basic information, but are not trying to +// create a binary compatible interface +// this API will totally change, as we are creating our own API + + +namespace media_kit_private { + +class Writer +{ +public: + Writer(void) + virtual ~Writer(void); + virtual status_t SetWriteBufferSize(unsigned long); + + virtual status_t SetSource(BDataIO *) = 0; + virtual status_t AddTrack(BMediaTrack *) = 0; + virtual status_t CommitHeader(void) = 0; + virtual status_t WriteData(long, media_type, void const *, unsigned long, media_encode_info *) = 0; + virtual status_t CloseFile(void) = 0; + virtual status_t AddTrackInfo(long, unsigned long, char const *, unsigned long) = 0; + virtual status_t AddCopyright(char const *) = 0; + virtual status_t AddChunk(long, char const *, unsigned long) = 0; + +private: + virtual status_t Perform(long, void *); + //virtual function and data stuffing will be done later +}; + +}; // namespace media_kit_private + +extern "C" { + status_t accepts_format(); + status_t get_mediawriter_info(); + status_t instantiate_mediawriter(); +}; diff --git a/headers/private/media/debug.h b/headers/private/media/debug.h new file mode 100644 index 0000000000..123aaab019 --- /dev/null +++ b/headers/private/media/debug.h @@ -0,0 +1,40 @@ + +#include + +#ifndef NDEBUG + + #ifndef DEBUG + #define DEBUG 2 + #endif + + #if DEBUG >= 1 + #define UNIMPLEMENTED() printf("libmedia.so: UNIMPLEMENTED %s\n",__PRETTY_FUNCTION__) + #else + #define UNIMPLEMENTED() ((void)0) + #endif + + #if DEBUG >= 2 + #define BROKEN() printf("libmedia.so: BROKEN %s\n",__PRETTY_FUNCTION__) + #else + #define BROKEN() ((void)0) + #endif + + #if DEBUG >= 3 + #define CALLED() printf("libmedia.so: CALLED %s\n",__PRETTY_FUNCTION__) + #else + #define CALLED() ((void)0) + #endif + + #undef TRACE + #define TRACE \ + printf + +#else + + #define UNIMPLEMENTED() ((void)0) + #define BROKEN() ((void)0) + #define CALLED() ((void)0) + #define TRACE \ + if (1) {} else printf + +#endif diff --git a/headers/private/shared/ObjectList.h b/headers/private/shared/ObjectList.h new file mode 100644 index 0000000000..cc639c574b --- /dev/null +++ b/headers/private/shared/ObjectList.h @@ -0,0 +1,800 @@ +/* +Open Tracker License + +Terms and Conditions + +Copyright (c) 1991-2000, Be Incorporated. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice applies to all licensees +and shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Be Incorporated shall not be +used in advertising or otherwise to promote the sale, use or other dealings in +this Software without prior written authorization from Be Incorporated. + +Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks +of Be Incorporated in the United States and other countries. Other brand product +names are registered trademarks or trademarks of their respective holders. +All rights reserved. +*/ + +/**************************************************************************** +** WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING ** +** ** +** DANGER, WILL ROBINSON! ** +** ** +** The interfaces contained here are part of BeOS's ** +** ** +** >> PRIVATE NOT FOR PUBLIC USE << ** +** ** +** implementation. ** +** ** +** These interfaces WILL CHANGE in future releases. ** +** If you use them, your app WILL BREAK at some future time. ** +** ** +** (And yes, this does mean that binaries built from OpenTracker will not ** +** be compatible with some future releases of the OS. When that happens, ** +** we will provide an updated version of this file to keep compatibility.) ** +** ** +** WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING ** +****************************************************************************/ + +// +// ObjectList is a wrapper around BList that adds type safety, +// optional object ownership, search, insert operations, etc. +// + +#ifndef __OBJECT_LIST__ +#define __OBJECT_LIST__ + +#ifndef _BE_H +#include +#endif + +#include + +template class BObjectList; + +template +struct UnaryPredicate { + + virtual int operator()(const T *) const + // virtual could be avoided here if FindBinaryInsertionIndex, + // etc. were member template functions + { return 0; } + +private: + static int _unary_predicate_glue(const void *item, void *context); + +friend class BObjectList; +}; + +template +int +UnaryPredicate::_unary_predicate_glue(const void *item, void *context) +{ + return ((UnaryPredicate *)context)->operator()((const T *)item); +} + + +class _PointerList_ : public BList { +public: + _PointerList_(const _PointerList_ &list); + _PointerList_(int32 itemsPerBlock = 20, bool owning = false); + ~_PointerList_(); + + typedef void *(* GenericEachFunction)(void *, void *); + typedef int (* GenericCompareFunction)(const void *, const void *); + typedef int (* GenericCompareFunctionWithState)(const void *, const void *, + void *); + typedef int (* UnaryPredicateGlue)(const void *, void *); + + void *EachElement(GenericEachFunction, void *); + void SortItems(GenericCompareFunction); + void SortItems(GenericCompareFunctionWithState, void *state); + void HSortItems(GenericCompareFunction); + void HSortItems(GenericCompareFunctionWithState, void *state); + + void *BinarySearch(const void *, GenericCompareFunction) const; + void *BinarySearch(const void *, GenericCompareFunctionWithState, void *state) const; + + int32 BinarySearchIndex(const void *, GenericCompareFunction) const; + int32 BinarySearchIndex(const void *, GenericCompareFunctionWithState, void *state) const; + int32 BinarySearchIndexByPredicate(const void *, UnaryPredicateGlue) const; + + bool Owning() const; + bool ReplaceItem(int32, void *); + +protected: + bool owning; + +}; + +template +class BObjectList : private _PointerList_ { +public: + + // iteration and sorting + typedef T *(* EachFunction)(T *, void *); + typedef const T *(* ConstEachFunction)(const T *, void *); + typedef int (* CompareFunction)(const T *, const T *); + typedef int (* CompareFunctionWithState)(const T *, const T *, void *state); + + BObjectList(int32 itemsPerBlock = 20, bool owning = false); + BObjectList(const BObjectList &list); + // clones list; if list is owning, makes copies of all + // the items + + virtual ~BObjectList(); + + BObjectList &operator=(const BObjectList &list); + // clones list; if list is owning, makes copies of all + // the items + + // adding and removing + // ToDo: + // change Add calls to return const item + bool AddItem(T *); + bool AddItem(T *, int32); + bool AddList(BObjectList *); + bool AddList(BObjectList *, int32); + + bool RemoveItem(T *, bool deleteIfOwning = true); + // if owning, deletes the removed item + T *RemoveItemAt(int32); + // returns the removed item + + void MakeEmpty(); + + // item access + T *ItemAt(int32) const; + + bool ReplaceItem(int32 index, T *); + // if list is owning, deletes the item at first + T *SwapWithItem(int32 index, T *newItem); + // same as ReplaceItem, except does not delete old item at , + // returns it instead + + T *FirstItem() const; + T *LastItem() const; + + // misc. getters + int32 IndexOf(const T *) const; + bool HasItem(const T *) const; + bool IsEmpty() const; + int32 CountItems() const; + + T *EachElement(EachFunction, void *); + const T *EachElement(ConstEachFunction, void *) const; + + void SortItems(CompareFunction); + void SortItems(CompareFunctionWithState, void *state); + void HSortItems(CompareFunction); + void HSortItems(CompareFunctionWithState, void *state); + + // linear search, returns first item that matches predicate + const T *FindIf(const UnaryPredicate &) const; + T *FindIf(const UnaryPredicate &); + + // list must be sorted with CompareFunction for these to work + const T *BinarySearch(const T &, CompareFunction) const; + const T *BinarySearch(const T &, CompareFunctionWithState, void *state) const; + + // Binary insertion - list must be sorted with CompareFunction for + // these to work + + // simple insert + void BinaryInsert(T *, CompareFunction); + void BinaryInsert(T *, CompareFunctionWithState, void *state); + void BinaryInsert(T *, const UnaryPredicate &); + + // unique insert, returns false if item already in list + bool BinaryInsertUnique(T *, CompareFunction); + bool BinaryInsertUnique(T *, CompareFunctionWithState, void *state); + bool BinaryInsertUnique(T *, const UnaryPredicate &); + + // insert a copy of the item, returns new inserted item + T *BinaryInsertCopy(const T ©This, CompareFunction); + T *BinaryInsertCopy(const T ©This, CompareFunctionWithState, void *state); + + // insert a copy of the item if not in list already + // returns new inserted item or existing item in case of a conflict + T *BinaryInsertCopyUnique(const T ©This, CompareFunction); + T *BinaryInsertCopyUnique(const T ©This, CompareFunctionWithState, void *state); + + + int32 FindBinaryInsertionIndex(const UnaryPredicate &, bool *alreadyInList = 0) const; + // returns either the index into which a new item should be inserted + // or index of an existing item that matches the predicate + + // deprecated API, will go away + BList *AsBList() + { return this; } + const BList *AsBList() const + { return this; } +private: + void SetItem(int32, T *); +}; + +template +Result +WhileEachListItem(BObjectList *list, Result (Item::*func)(Param1), Param1 p1) +{ + Result result = 0; + int32 count = list->CountItems(); + + for (int32 index = 0; index < count; index++) + if ((result = (list->ItemAt(index)->*func)(p1)) != 0) + break; + + return result; +} + +template +Result +WhileEachListItem(BObjectList *list, Result (*func)(Item *, Param1), Param1 p1) +{ + Result result = 0; + int32 count = list->CountItems(); + + for (int32 index = 0; index < count; index++) + if ((result = (*func)(list->ItemAt(index), p1)) != 0) + break; + + return result; +} + +template +Result +WhileEachListItem(BObjectList *list, Result (Item::*func)(Param1, Param2), + Param1 p1, Param2 p2) +{ + Result result = 0; + int32 count = list->CountItems(); + + for (int32 index = 0; index < count; index++) + if ((result = (list->ItemAt(index)->*func)(p1, p2)) != 0) + break; + + return result; +} + +template +Result +WhileEachListItem(BObjectList *list, Result (*func)(Item *, Param1, Param2), + Param1 p1, Param2 p2) +{ + Result result = 0; + int32 count = list->CountItems(); + + for (int32 index = 0; index < count; index++) + if ((result = (*func)(list->ItemAt(index), p1, p2)) != 0) + break; + + return result; +} + +template +Result +WhileEachListItem(BObjectList *list, Result (*func)(Item *, Param1, Param2, + Param3, Param4), Param1 p1, Param2 p2, Param3 p3, Param4 p4) +{ + Result result = 0; + int32 count = list->CountItems(); + + for (int32 index = 0; index < count; index++) + if ((result = (*func)(list->ItemAt(index), p1, p2, p3, p4)) != 0) + break; + + return result; +} + +template +void +EachListItemIgnoreResult(BObjectList *list, Result (Item::*func)()) +{ + int32 count = list->CountItems(); + for (int32 index = 0; index < count; index++) + (list->ItemAt(index)->*func)(); +} + +template +void +EachListItem(BObjectList *list, void (*func)(Item *, Param1), Param1 p1) +{ + int32 count = list->CountItems(); + for (int32 index = 0; index < count; index++) + (func)(list->ItemAt(index), p1); +} + +template +void +EachListItem(BObjectList *list, void (Item::*func)(Param1, Param2), + Param1 p1, Param2 p2) +{ + int32 count = list->CountItems(); + for (int32 index = 0; index < count; index++) + (list->ItemAt(index)->*func)(p1, p2); +} + +template +void +EachListItem(BObjectList *list, void (*func)(Item *,Param1, Param2), + Param1 p1, Param2 p2) +{ + int32 count = list->CountItems(); + for (int32 index = 0; index < count; index++) + (func)(list->ItemAt(index), p1, p2); +} + +template +void +EachListItem(BObjectList *list, void (*func)(Item *,Param1, Param2, + Param3), Param1 p1, Param2 p2, Param3 p3) +{ + int32 count = list->CountItems(); + for (int32 index = 0; index < count; index++) + (func)(list->ItemAt(index), p1, p2, p3); +} + + +template +void +EachListItem(BObjectList *list, void (*func)(Item *,Param1, Param2, + Param3, Param4), Param1 p1, Param2 p2, Param3 p3, Param4 p4) +{ + int32 count = list->CountItems(); + for (int32 index = 0; index < count; index++) + (func)(list->ItemAt(index), p1, p2, p3, p4); +} + +// inline code + +inline bool +_PointerList_::Owning() const +{ + return owning; +} + +template +BObjectList::BObjectList(int32 itemsPerBlock, bool owning) + : _PointerList_(itemsPerBlock, owning) +{ +} + +template +BObjectList::BObjectList(const BObjectList &list) + : _PointerList_(list) +{ + owning = list.owning; + if (owning) { + // make our own copies in an owning list + int32 count = list.CountItems(); + for (int32 index = 0; index < count; index++) { + T *item = list.ItemAt(index); + if (item) + item = new T(*item); + SetItem(index, item); + } + } +} + +template +BObjectList::~BObjectList() +{ + if (Owning()) + // have to nuke elements first + MakeEmpty(); + +} + +template +BObjectList & +BObjectList::operator=(const BObjectList &list) +{ + owning = list.owning; + BObjectList &result = (BObjectList &)_PointerList_::operator=(list); + if (owning) { + // make our own copies in an owning list + int32 count = list.CountItems(); + for (int32 index = 0; index < count; index++) { + T *item = list.ItemAt(index); + if (item) + item = new T(*item); + SetItem(index, item); + } + } + return result; +} + +template +bool +BObjectList::AddItem(T *item) +{ + // need to cast to void * to make T work for const pointers + return _PointerList_::AddItem((void *)item); +} + +template +bool +BObjectList::AddItem(T *item, int32 atIndex) +{ + return _PointerList_::AddItem((void *)item, atIndex); +} + +template +bool +BObjectList::AddList(BObjectList *newItems) +{ + return _PointerList_::AddList(newItems); +} + +template +bool +BObjectList::AddList(BObjectList *newItems, int32 atIndex) +{ + return _PointerList_::AddList(newItems, atIndex); +} + + +template +bool +BObjectList::RemoveItem(T *item, bool deleteIfOwning) +{ + bool result = _PointerList_::RemoveItem((void *)item); + + if (result && Owning() && deleteIfOwning) + delete item; + + return result; +} + +template +T * +BObjectList::RemoveItemAt(int32 index) +{ + return (T *)_PointerList_::RemoveItem(index); +} + +template +inline T * +BObjectList::ItemAt(int32 index) const +{ + return (T *)_PointerList_::ItemAt(index); +} + +template +bool +BObjectList::ReplaceItem(int32 index, T *item) +{ + if (owning) + delete ItemAt(index); + return _PointerList_::ReplaceItem(index, (void *)item); +} + +template +T * +BObjectList::SwapWithItem(int32 index, T *newItem) +{ + T *result = ItemAt(index); + _PointerList_::ReplaceItem(index, (void *)newItem); + return result; +} + +template +void +BObjectList::SetItem(int32 index, T *newItem) +{ + _PointerList_::ReplaceItem(index, (void *)newItem); +} + +template +int32 +BObjectList::IndexOf(const T *item) const +{ + return _PointerList_::IndexOf((void *)item); +} + +template +T * +BObjectList::FirstItem() const +{ + return (T *)_PointerList_::FirstItem(); +} + +template +T * +BObjectList::LastItem() const +{ + return (T *)_PointerList_::LastItem(); +} + +template +bool +BObjectList::HasItem(const T *item) const +{ + return _PointerList_::HasItem((void *)item); +} + +template +bool +BObjectList::IsEmpty() const +{ + return _PointerList_::IsEmpty(); +} + +template +int32 +BObjectList::CountItems() const +{ + return _PointerList_::CountItems(); +} + +template +void +BObjectList::MakeEmpty() +{ + if (owning) { + int32 count = CountItems(); + for (int32 index = 0; index < count; index++) + delete ItemAt(index); + } + _PointerList_::MakeEmpty(); +} + +template +T * +BObjectList::EachElement(EachFunction func, void *params) +{ + return (T *)_PointerList_::EachElement((GenericEachFunction)func, params); +} + + +template +const T * +BObjectList::EachElement(ConstEachFunction func, void *params) const +{ + return (const T *) + const_cast *>(this)->_PointerList_::EachElement( + (GenericEachFunction)func, params); +} + +template +const T * +BObjectList::FindIf(const UnaryPredicate &predicate) const +{ + int32 count = CountItems(); + for (int32 index = 0; index < count; index++) + if (predicate.operator()(ItemAt(index)) == 0) + return ItemAt(index); + return 0; +} + +template +T * +BObjectList::FindIf(const UnaryPredicate &predicate) +{ + int32 count = CountItems(); + for (int32 index = 0; index < count; index++) + if (predicate.operator()(ItemAt(index)) == 0) + return ItemAt(index); + return 0; +} + + +template +void +BObjectList::SortItems(CompareFunction function) +{ + _PointerList_::SortItems((GenericCompareFunction)function); +} + +template +void +BObjectList::SortItems(CompareFunctionWithState function, void *state) +{ + _PointerList_::SortItems((GenericCompareFunctionWithState)function, state); +} + +template +void +BObjectList::HSortItems(CompareFunction function) +{ + _PointerList_::HSortItems((GenericCompareFunction)function); +} + +template +void +BObjectList::HSortItems(CompareFunctionWithState function, void *state) +{ + _PointerList_::HSortItems((GenericCompareFunctionWithState)function, state); +} + +template +const T * +BObjectList::BinarySearch(const T &key, CompareFunction func) const +{ + return (const T *)_PointerList_::BinarySearch(&key, + (GenericCompareFunction)func); +} + +template +const T * +BObjectList::BinarySearch(const T &key, CompareFunctionWithState func, void *state) const +{ + return (const T *)_PointerList_::BinarySearch(&key, + (GenericCompareFunctionWithState)func, state); +} + +template +void +BObjectList::BinaryInsert(T *item, CompareFunction func) +{ + int32 index = _PointerList_::BinarySearchIndex(item, + (GenericCompareFunction)func); + if (index >= 0) + // already in list, add after existing + AddItem(item, index + 1); + else + AddItem(item, -index - 1); +} + +template +void +BObjectList::BinaryInsert(T *item, CompareFunctionWithState func, void *state) +{ + int32 index = _PointerList_::BinarySearchIndex(item, + (GenericCompareFunctionWithState)func, state); + if (index >= 0) + // already in list, add after existing + AddItem(item, index + 1); + else + AddItem(item, -index - 1); +} + +template +bool +BObjectList::BinaryInsertUnique(T *, CompareFunction func) +{ + int32 index = _PointerList_::BinarySearchIndex(item, + (GenericCompareFunction)func); + if (index >= 0) + return false; + + AddItem(item, -index - 1); + return true; +} + +template +bool +BObjectList::BinaryInsertUnique(T *, CompareFunctionWithState func, void *state) +{ + int32 index = _PointerList_::BinarySearchIndex(item, + (GenericCompareFunctionWithState)func, state); + if (index >= 0) + return false; + + AddItem(item, -index - 1); + return true; +} + + +template +T * +BObjectList::BinaryInsertCopy(const T ©This, CompareFunction func) +{ + int32 index = _PointerList_::BinarySearchIndex(©This, + (GenericCompareFunction)func); + + if (index >= 0) + index++; + else + index = -index - 1; + + T *newItem = new T(copyThis); + AddItem(newItem, index); + return newItem; +} + +template +T * +BObjectList::BinaryInsertCopy(const T ©This, CompareFunctionWithState func, void *state) +{ + int32 index = _PointerList_::BinarySearchIndex(©This, + (GenericCompareFunctionWithState)func, state); + + if (index >= 0) + index++; + else + index = -index - 1; + + T *newItem = new T(copyThis); + AddItem(newItem, index); + return newItem; +} + +template +T * +BObjectList::BinaryInsertCopyUnique(const T ©This, CompareFunction func) +{ + int32 index = _PointerList_::BinarySearchIndex(©This, + (GenericCompareFunction)func); + if (index >= 0) + return ItemAt(index); + + index = -index - 1; + T *newItem = new T(copyThis); + AddItem(newItem, index); + return newItem; +} + +template +T * +BObjectList::BinaryInsertCopyUnique(const T ©This, CompareFunctionWithState func, + void *state) +{ + int32 index = _PointerList_::BinarySearchIndex(©This, + (GenericCompareFunctionWithState)func, state); + if (index >= 0) + return ItemAt(index); + + index = -index - 1; + T *newItem = new T(copyThis); + AddItem(newItem, index); + return newItem; +} + +template +int32 +BObjectList::FindBinaryInsertionIndex(const UnaryPredicate &pred, bool *alreadyInList) + const +{ + int32 index = _PointerList_::BinarySearchIndexByPredicate(&pred, + (UnaryPredicateGlue)&UnaryPredicate::_unary_predicate_glue); + + if (alreadyInList) + *alreadyInList = index >= 0; + + if (index < 0) + index = -index - 1; + + return index; +} + +template +void +BObjectList::BinaryInsert(T *item, const UnaryPredicate &pred) +{ + int32 index = FindBinaryInsertionIndex(pred); + AddItem(item, index); +} + +template +bool +BObjectList::BinaryInsertUnique(T *item, const UnaryPredicate &pred) +{ + bool alreadyInList; + int32 index = FindBinaryInsertionIndex(pred, &alreadyInList); + if (alreadyInList) + return false; + + AddItem(item, index); + return true; +} + + +#endif diff --git a/headers/private/storage/Elf.h b/headers/private/storage/Elf.h new file mode 100644 index 0000000000..9373f0945d --- /dev/null +++ b/headers/private/storage/Elf.h @@ -0,0 +1,105 @@ +// Elf.h + +#ifndef _sk_elf_h_ +#define _sk_elf_h_ + +// types +typedef uint32 Elf32_Addr; +typedef uint16 Elf32_Half; +typedef uint32 Elf32_Off; +typedef int32 Elf32_Sword; +typedef uint32 Elf32_Word; + +// e_ident indices +#define EI_MAG0 0 +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_PAD 7 +#define EI_NIDENT 16 + +// object file header +typedef struct { + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +} Elf32_Ehdr; + +// e_ident EI_CLASS and EI_DATA values +#define ELFCLASSNONE 0 +#define ELFCLASS32 1 +#define ELFCLASS64 2 +#define ELFDATANONE 0 +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +// program header +typedef struct { + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +} Elf32_Phdr; + +// p_type +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDIR 6 +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff + +// section header +typedef struct { + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +} Elf32_Shdr; + +// sh_type values +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7fffffff +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0xffffffff + +#endif // _sk_elf_h_ diff --git a/headers/private/storage/Exception.h b/headers/private/storage/Exception.h new file mode 100644 index 0000000000..d59c298621 --- /dev/null +++ b/headers/private/storage/Exception.h @@ -0,0 +1,111 @@ +// Exception + +#ifndef _sk_exception_ +#define _sk_exception_ + +#include +#include + +#include + +namespace StorageKit { + +class Exception { +public: + // constructor + Exception() + : fError(B_OK), + fDescription() + { + } + + // constructor + Exception(BString description) + : fError(B_OK), + fDescription(description) + { + } + + // constructor + Exception(const char* format,...) + : fError(B_OK), + fDescription() + { + va_list args; + va_start(args, format); + SetTo(B_OK, format, args); + va_end(args); + } + + // constructor + Exception(status_t error) + : fError(error), + fDescription() + { + } + + // constructor + Exception(status_t error, BString description) + : fError(error), + fDescription(description) + { + } + + // constructor + Exception(status_t error, const char* format,...) + : fError(error), + fDescription() + { + va_list args; + va_start(args, format); + SetTo(error, format, args); + va_end(args); + } + + // copy constructor + Exception(const Exception& exception) + : fError(exception.fError), + fDescription(exception.fDescription) + { + } + + // destructor + ~Exception() + { + } + + // SetTo + void SetTo(status_t error, BString description) + { + fError = error; + fDescription.SetTo(description); + } + + // SetTo + void SetTo(status_t error, const char* format, va_list arg) + { + char buffer[2048]; + vsprintf(buffer, format, arg); + SetTo(error, BString(buffer)); + } + + // GetError + status_t Error() const + { + return fError; + } + + // GetDescription + const char* Description() const + { + return fDescription.String(); + } + +private: + status_t fError; + BString fDescription; +}; + +}; // namespace StorageKit + +#endif // _sk_exception_ diff --git a/headers/private/storage/LibBeAdapter.h b/headers/private/storage/LibBeAdapter.h new file mode 100644 index 0000000000..c027d67184 --- /dev/null +++ b/headers/private/storage/LibBeAdapter.h @@ -0,0 +1,19 @@ +// LibBeAdapter.h + +#ifndef _sk_lib_be_adapter_h_ +#define _sk_lib_be_adapter_h_ + +#include + +struct entry_ref; + +extern status_t entry_ref_to_path_adapter(dev_t device, ino_t directory, + const char *name, + char *buffer, size_t size); + +extern status_t swap_data_adapter(type_code type, void *data, size_t length, + swap_action action); + +extern bool is_type_swapped_adapter(type_code type); + +#endif // _sk_lib_be_adapter_h_ diff --git a/headers/private/storage/OffsetFile.h b/headers/private/storage/OffsetFile.h new file mode 100644 index 0000000000..e71cc65bd9 --- /dev/null +++ b/headers/private/storage/OffsetFile.h @@ -0,0 +1,63 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file OffsetFile.h + OffsetFile interface declaration. +*/ + +#ifndef _sk_offset_file_h_ +#define _sk_offset_file_h_ + +#include +#include + +namespace StorageKit { + +/*! + \class OffsetFile + \brief Provides access to a file skipping a certain amount of bytes at + the beginning. + + This class implements the BPositionIO interface to provide access to the + data of a file past a certain offset. This is very handy e.g. for dealing + with resources, as they always reside at the end of a file, but may start + at arbitrary offsets. + + \author Ingo Weinhold + + \version 0.0.0 +*/ +class OffsetFile : public BPositionIO { +public: + OffsetFile(); + OffsetFile(BFile *file, off_t offset); + virtual ~OffsetFile(); + + status_t SetTo(BFile *file, off_t offset); + void Unset(); + status_t InitCheck() const; + + BFile *File() const; + + ssize_t ReadAt(off_t pos, void *buffer, size_t size); + ssize_t WriteAt(off_t pos, const void *buffer, + size_t size); + off_t Seek(off_t position, uint32 seekMode); + off_t Position() const; + + status_t SetSize(off_t size); + status_t GetSize(off_t *size); + + off_t Offset() const; + +private: + BFile* fFile; + off_t fOffset; + off_t fCurrentPosition; +}; + +}; // namespace StorageKit + +#endif // _sk_offset_file_h_ diff --git a/headers/private/storage/Pef.h b/headers/private/storage/Pef.h new file mode 100644 index 0000000000..a54e5da2ce --- /dev/null +++ b/headers/private/storage/Pef.h @@ -0,0 +1,46 @@ +// Pef.h + +#ifndef _sk_pef_h_ +#define _sk_pef_h_ + +#include + +typedef char PefOSType[4]; + +// container header +struct PEFContainerHeader { + PefOSType tag1; + PefOSType tag2; + PefOSType architecture; + uint32 formatVersion; + uint32 dateTimeStamp; + uint32 oldDefVersion; + uint32 oldImpVersion; + uint32 currentVersion; + uint16 sectionCount; + uint16 instSectionCount; + uint32 reservedA; +}; + +const char kPEFFileMagic1[4] = { 'J', 'o', 'y', '!' }; +const char kPEFFileMagic2[4] = { 'p', 'e', 'f', 'f' }; +const char kPEFArchitecturePPC[4] = { 'p', 'w', 'p', 'c' }; +const char kPEFContainerHeaderSize = 40; + +// section header +struct PEFSectionHeader { + int32 nameOffset; + uint32 defaultAddress; + uint32 totalSize; + uint32 unpackedSize; + uint32 packedSize; + uint32 containerOffset; + uint8 sectionKind; + uint8 shareKind; + uint8 alignment; + uint8 reservedA; +}; + +const uint32 kPEFSectionHeaderSize = 28; + +#endif // _sk_pef_h_ diff --git a/headers/private/storage/QueryPredicate.h b/headers/private/storage/QueryPredicate.h new file mode 100644 index 0000000000..12bf02b0df --- /dev/null +++ b/headers/private/storage/QueryPredicate.h @@ -0,0 +1,206 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file QueryPredicate.h + BQuery predicate helper classes interface declaration. +*/ +#ifndef _sk_query_predicate_h_ +#define _sk_query_predicate_h_ + +#include + +#include +#include +#include + +namespace StorageKit { + +// QueryNode +class QueryNode { +public: + QueryNode(); + virtual ~QueryNode(); + + virtual uint32 Arity() const = 0; + virtual status_t SetChildAt(QueryNode *child, int32 index) = 0; + virtual QueryNode *ChildAt(int32 index) = 0; + + virtual status_t GetString(BString &predicate) = 0; +}; + +// LeafNode +class LeafNode : public QueryNode { +public: + LeafNode(); + virtual ~LeafNode(); + + virtual uint32 Arity() const; + virtual status_t SetChildAt(QueryNode *child, int32 index); + virtual QueryNode *ChildAt(int32 index); +}; + +// UnaryNode +class UnaryNode : public QueryNode { +public: + UnaryNode(); + virtual ~UnaryNode(); + + virtual uint32 Arity() const; + virtual status_t SetChildAt(QueryNode *child, int32 index); + virtual QueryNode *ChildAt(int32 index); + +protected: + QueryNode *fChild; +}; + +// BinaryNode +class BinaryNode : public QueryNode { +public: + BinaryNode(); + virtual ~BinaryNode(); + + virtual uint32 Arity() const; + virtual status_t SetChildAt(QueryNode *child, int32 index); + virtual QueryNode *ChildAt(int32 index); + +protected: + QueryNode *fChild1; + QueryNode *fChild2; +}; + +// AttributeNode +class AttributeNode : public LeafNode { +public: + AttributeNode(const char *attribute); + + virtual status_t GetString(BString &predicate); + +private: + BString fAttribute; +}; + +// StringNode +class StringNode : public LeafNode { +public: + StringNode(const char *value, bool caseInsensitive = false); + + virtual status_t GetString(BString &predicate); + + inline const char *Value() const { return fValue.String(); } + +private: + BString fValue; +}; + +// DateNode +class DateNode : public LeafNode { +public: + DateNode(const char *value); + + virtual status_t GetString(BString &predicate); + +private: + BString fValue; +}; + +// ValueNode +template +class ValueNode : public LeafNode { +public: + ValueNode(const ValueType &value); + + virtual status_t GetString(BString &predicate); + +private: + ValueType fValue; +}; + +// constructor +template +ValueNode::ValueNode(const ValueType &value) + : LeafNode(), + fValue(value) +{ +} + +// GetString +template +status_t +ValueNode::GetString(BString &predicate) +{ + predicate.SetTo(""); + predicate << fValue; + return B_OK; +} + +// specializations for float and double +template<> status_t ValueNode::GetString(BString &predicate); +template<> status_t ValueNode::GetString(BString &predicate); + + +// short hands +typedef ValueNode Int32ValueNode; +typedef ValueNode UInt32ValueNode; +typedef ValueNode Int64ValueNode; +typedef ValueNode UInt64ValueNode; +typedef ValueNode FloatValueNode; +typedef ValueNode DoubleValueNode; + + +// SpecialOpNode +class SpecialOpNode : public LeafNode { +public: + SpecialOpNode(query_op op); + + virtual status_t GetString(BString &predicate); + +private: + query_op fOp; +}; + +// UnaryOpNode +class UnaryOpNode : public UnaryNode { +public: + UnaryOpNode(query_op op); + + virtual status_t GetString(BString &predicate); + +private: + query_op fOp; +}; + +// BinaryOpNode +class BinaryOpNode : public BinaryNode { +public: + BinaryOpNode(query_op op); + + virtual status_t GetString(BString &predicate); + +private: + query_op fOp; +}; + + +// QueryStack +class QueryStack { +public: + QueryStack(); + virtual ~QueryStack(); + + status_t PushNode(QueryNode *node); + QueryNode *PopNode(); + + status_t ConvertToTree(QueryNode *&rootNode); + +private: + status_t _GetSubTree(QueryNode *&rootNode); + +private: + BList fNodes; +}; + +}; // namespace StorageKit + +#endif // _sk_query_predicate_h_ diff --git a/headers/private/storage/ResourceFile.h b/headers/private/storage/ResourceFile.h new file mode 100644 index 0000000000..9e7cfc4a7a --- /dev/null +++ b/headers/private/storage/ResourceFile.h @@ -0,0 +1,128 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file ResourceFile.h + ResourceFile interface declaration. +*/ + +#ifndef _sk_resource_file_h_ +#define _sk_resource_file_h_ + +#include + +#include "OffsetFile.h" + +struct resource_info; +struct PEFContainerHeader; + +namespace StorageKit { + +class Exception; +struct MemArea; +class ResourceItem; +struct resource_parse_info; +class ResourcesContainer; + +/*! + \class ResourceFile + \brief Represents a file capable of containing resources. + + This class provides access to the resources of a file. + Basically a ResourceFile object can be set to a file, load infos for the + resources without loading their data (InitContainer()), read the data of + one (ReadResource()) or all resources (ReadResources()) and write all + resources to the file (WriteResources()). + + Note, that the object does only provide the I/O functionality, it does + not store any information about the resources -- this is done via a + ResourcesContainer. We gain flexibility using this approach, since e.g. + a certain resource may be represented by more than one ResourceItem and + we can have as many ResourcesContainers for the resources as we like. + In particular it is nice, that at any time we can write an arbitrary set + of resources to the file. + + \author Ingo Weinhold + + \version 0.0.0 +*/ +class ResourceFile { +public: + ResourceFile(); + virtual ~ResourceFile(); + + status_t SetTo(BFile *file, bool clobber = false); + void Unset(); + status_t InitCheck() const; + + status_t InitContainer(ResourcesContainer &container); + status_t ReadResource(ResourceItem &resource, bool force = false); + status_t ReadResources(ResourcesContainer &container, bool force = false); + status_t WriteResources(ResourcesContainer &container); + +private: + void _InitFile(BFile &file, bool clobber); + void _InitELFFile(BFile &file); + void _InitPEFFile(BFile &file, const PEFContainerHeader &pefHeader); + void _ReadHeader(resource_parse_info &parseInfo); + void _ReadIndex(resource_parse_info &parseInfo); + bool _ReadIndexEntry(resource_parse_info &parseInfo, int32 index, + uint32 tableOffset, bool peekAhead); + void _ReadInfoTable(resource_parse_info &parseInfo); + bool _ReadInfoTableEnd(const void *data, int32 dataSize); + const void *_ReadResourceInfo(resource_parse_info &parseInfo, + const MemArea &area, + const resource_info *info, type_code type, + bool *readIndices); + + status_t _WriteResources(ResourcesContainer &container); + status_t _MakeEmptyResourceFile(); + + inline int16 _GetInt16(int16 value); + inline uint16 _GetUInt16(uint16 value); + inline int32 _GetInt32(int32 value); + inline uint32 _GetUInt32(uint32 value); + +private: + OffsetFile fFile; + uint32 fFileType; + bool fHostEndianess; + bool fEmptyResources; +}; + +// _GetInt16 +inline +int16 +ResourceFile::_GetInt16(int16 value) +{ + return (fHostEndianess ? value : B_SWAP_INT16(value)); +} + +// _GetUInt16 +inline +uint16 +ResourceFile::_GetUInt16(uint16 value) +{ + return (fHostEndianess ? value : B_SWAP_INT16(value)); +} + +// _GetInt32 +inline +int32 +ResourceFile::_GetInt32(int32 value) +{ + return (fHostEndianess ? value : B_SWAP_INT32(value)); +} + +// _GetUInt32 +inline +uint32 +ResourceFile::_GetUInt32(uint32 value) +{ + return (fHostEndianess ? value : B_SWAP_INT32(value)); +} + +}; // namespace StorageKit + +#endif // _sk_resource_file_h_ diff --git a/headers/private/storage/ResourceItem.h b/headers/private/storage/ResourceItem.h new file mode 100644 index 0000000000..ca9b37bf60 --- /dev/null +++ b/headers/private/storage/ResourceItem.h @@ -0,0 +1,87 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file ResourcesItem.h + ResourceItem interface declaration. +*/ + +#ifndef _sk_resource_item_h_ +#define _sk_resource_item_h_ + +#include +#include + +namespace StorageKit { + +/*! + \class ResourceItem + \brief Represents a resource loaded into memory. + + This class represents a resource completely or partially loaded into + memory. The minimal information stored in the object should be its + type, ID and name and the size of its data. If the data are not loaded + then additionally the offset (into a resource file) should be valid. + As soon as the data are loaded as well, the offset is more or less + meaningless. + + Creating a new resource can be done by calling SetIdentity() after the + default construction. The object then represents a resource with the + specified type, ID and name and with empty data. Data can arbitrarily + be read and written using the methods the super class BMallocIO provides. + + The memory for the resource data is owned by the ResourceItem object and + freed on destruction. + + \author Ingo Weinhold + + \version 0.0.0 +*/ +class ResourceItem : public BMallocIO { +public: + ResourceItem(); + virtual ~ResourceItem(); + + virtual ssize_t WriteAt(off_t pos, const void *buffer, size_t size); + virtual status_t SetSize(off_t size); + + void SetLocation(int32 offset, size_t initialSize); + void SetIdentity(type_code type, int32 id, const char *name); + + void SetOffset(int32 offset); + int32 Offset() const; + + size_t InitialSize() const; + size_t DataSize() const; + + void SetType(type_code type); + type_code Type() const; + + void SetID(int32 id); + int32 ID() const; + + void SetName(const char *name); + const char *Name() const; + + void *Data() const; + + void SetLoaded(bool loaded); + bool IsLoaded() const; + + void SetModified(bool modified); + bool IsModified() const; + +private: + int32 fOffset; + size_t fInitialSize; + type_code fType; + int32 fID; + BString fName; + bool fIsLoaded; + bool fIsModified; +}; + +}; // namespace StorageKit + +#endif // _sk_resource_item_h_ diff --git a/headers/private/storage/ResourcesContainer.h b/headers/private/storage/ResourcesContainer.h new file mode 100644 index 0000000000..2a0c025390 --- /dev/null +++ b/headers/private/storage/ResourcesContainer.h @@ -0,0 +1,75 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file ResourcesContainer.h + ResourcesContainer interface declaration. +*/ + +#ifndef _sk_resources_container_h_ +#define _sk_resources_container_h_ + +#include + +namespace StorageKit { + +class ResourceItem; + +/*! + \class ResourcesContainer + \brief Represents a collection of resources. + + This class can be used to manage a collection of resources represented + by ResourceItem's. Usually it does never contain two resources with the + same type \em and ID, since AddResource() replaces an old item with the + new one, unless explicitly told not to do so. This should only be done + by ResourceFile, when type and ID of the items are not yet known. + Asside from the basic vector features like Add/RemoveResource()/ + ResourceAt() and MakeEmpty() a bunch of IndexOf() methods are provided + and AssimilateResources() which incorporates all resources of another + container into this one (replacing old resources, if necessary), emptying + the other one. + + The ResourceItem's in a container are deleted on destruction, unless + removed before via RemoveResource(). MakeEmpty() deletes the items as + well. + + \author Ingo Weinhold + + \version 0.0.0 +*/ +class ResourcesContainer { +public: + ResourcesContainer(); + virtual ~ResourcesContainer(); + + bool AddResource(ResourceItem *item, int32 index = -1, + bool replace = true); + + ResourceItem *RemoveResource(int32 index); + bool RemoveResource(ResourceItem *item); + + void MakeEmpty(); + + void AssimilateResources(ResourcesContainer &container); + + int32 IndexOf(ResourceItem *item) const; + int32 IndexOf(const void *data) const; + int32 IndexOf(type_code type, int32 id) const; + int32 IndexOf(type_code type, const char *name) const; + int32 IndexOfType(type_code type, int32 index) const; + ResourceItem *ResourceAt(int32 index) const; + int32 CountResources() const; + + void SetModified(bool modified); + bool IsModified() const; + +private: + BList fResources; + bool fIsModified; +}; + +}; // namespace StorageKit + +#endif // _sk_resources_container_h_ diff --git a/headers/private/storage/ResourcesDefs.h b/headers/private/storage/ResourcesDefs.h new file mode 100644 index 0000000000..3f90c774dc --- /dev/null +++ b/headers/private/storage/ResourcesDefs.h @@ -0,0 +1,105 @@ +// ResourcesDefs.h + +#ifndef _sk_resources_defs_h_ +#define _sk_resources_defs_h_ + +#include + +// x86 resource file constants +const char kX86ResourceFileMagic[4] = { 'R', 'S', 0, 0 }; +const uint32 kX86ResourcesOffset = 0x00000004; + +// PPC resource file constants +const char kPPCResourceFileMagic[4] = { 'r', 'e', 's', 'f' }; +const uint32 kPPCResourcesOffset = 0x00000028; + +// ELF file related constants +const uint32 kELFMinResourceAlignment = 32; + +// the unused data pattern +const uint32 kUnusedResourceDataPattern[3] = { + 0xffffffff, 0x000003e9, 0x00000000 +}; + + +// the resources header +struct resources_header { + uint32 rh_resources_magic; + uint32 rh_resource_count; + uint32 rh_index_section_offset; + uint32 rh_admin_section_size; + uint32 rh_pad[13]; +}; + +const uint32 kResourcesHeaderMagic = 0x444f1000; +const uint32 kResourceIndexSectionOffset = 0x00000044; +const uint32 kResourceIndexSectionAlignment = 0x00000600; +const uint32 kResourcesHeaderSize = 68; + + +// the header of the index section +struct resource_index_section_header { + uint32 rish_index_section_offset; + uint32 rish_index_section_size; + uint32 rish_unused_data1; + uint32 rish_unknown_section_offset; + uint32 rish_unknown_section_size; + uint32 rish_unused_data2[25]; + uint32 rish_info_table_offset; + uint32 rish_info_table_size; + uint32 rish_unused_data3; +}; + +const uint32 kUnknownResourceSectionSize = 0x00000168; +const uint32 kResourceIndexSectionHeaderSize = 132; + + +// an entry of the index table +struct resource_index_entry { + uint32 rie_offset; + uint32 rie_size; + uint32 rie_pad; +}; + +const uint32 kResourceIndexEntrySize = 12; + + +// a resource info +struct resource_info { + int32 ri_id; + int32 ri_index; + uint16 ri_name_size; + char ri_name[1]; +}; + +const uint32 kMinResourceInfoSize = 10; + + +// a resource info block +struct resource_info_block { + type_code rib_type; + resource_info rib_info[1]; +}; + +const uint32 kMinResourceInfoBlockSize = 4 + kMinResourceInfoSize; + + +// the structure separating resource info blocks +struct resource_info_separator { + uint32 ris_value1; + uint32 ris_value2; +}; + +const uint32 kResourceInfoSeparatorSize = 8; + + +// the end of the info table +struct resource_info_table_end { + uint32 rite_check_sum; + uint32 rite_terminator; +}; + +const uint32 kResourceInfoTableEndSize = 8; + + +#endif // _sk_resources_defs_h_ diff --git a/headers/private/storage/StorageDefs.Private.h b/headers/private/storage/StorageDefs.Private.h new file mode 100644 index 0000000000..6d0798cd37 --- /dev/null +++ b/headers/private/storage/StorageDefs.Private.h @@ -0,0 +1,17 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file StorageDefs.Private.h + Private Storage Kit declarations needed in public headers. +*/ + +#ifndef __sk_def_storage_private_h__ +#define __sk_def_storage_private_h__ + +namespace StorageKit { + typedef int FileDescriptor; +}; + +#endif // __sk_def_storage_private_h__ \ No newline at end of file diff --git a/headers/private/storage/kernel_interface.h b/headers/private/storage/kernel_interface.h new file mode 100644 index 0000000000..662c5a56b6 --- /dev/null +++ b/headers/private/storage/kernel_interface.h @@ -0,0 +1,326 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file kernel_interface.h + This is the private interface used by the Storage Kit + to communicate with the kernel +*/ + +#ifndef _sk_kernel_interface_h_ +#define _sk_kernel_interface_h_ + +#include +#include + +// For typedefs +#include // For dirent +#include // For struct stat +#include // For flock + +// Forward Declarations +typedef struct attr_info; +typedef struct entry_ref; + +//! Private Storage Kit Namespace +/*! Encompasses the functions used internally by the Storage Kit to + interface with the kernel, as well as various internal support functions, + data types, and type aliases. */ +namespace StorageKit { + +// Type aliases +typedef dirent DirEntry; +typedef flock FileLock; +typedef struct stat Stat; +typedef uint32 StatMember; +typedef attr_info AttrInfo; +typedef int OpenFlags; // open() flags +typedef mode_t CreationFlags; // open() mode +typedef int SeekMode; // lseek() mode + +// For convenience: +struct LongDirEntry : DirEntry { char _buffer[B_FILE_NAME_LENGTH]; }; + +// Constants -- POSIX versions +const FileDescriptor NullFd = -1; + + +//------------------------------------------------------------------------------ +// File Functions +//------------------------------------------------------------------------------ +/*! \brief Opens the filesystem entry specified by path. + + Returns a + new file descriptor if successful, -1 otherwise. This version + fails if the given file does not exist, or if you specify + O_CREAT as one of the flags (use the four argument version + of StorageKit::open() if you wish to create the file when + it doesn't already exist). */ +status_t open(const char *path, OpenFlags flags, FileDescriptor &result); + +/*! \brief Same as the other version of open() except the file is created with the + permissions given by creationFlags if it doesn't exist. */ +status_t open(const char *path, OpenFlags flags, CreationFlags creationFlags, + FileDescriptor &result); + +/*! \brief Closes a previously open()ed file. */ +status_t close( FileDescriptor file ); + +//! Reads data from a file into a buffer. +ssize_t read(FileDescriptor fd, void *buf, size_t len); + +//! Reads data from a certain position in a file into a buffer. +ssize_t read(FileDescriptor fd, void *buf, off_t pos, size_t len); + +//! Writes data from a buffer into a file. +ssize_t write(FileDescriptor fd, const void *buf, size_t len); + +//! Writes data from a buffer to a certain position in a file. +ssize_t write(FileDescriptor fd, const void *buf, off_t pos, size_t len); + +//! Moves a file's read/write pointer. +off_t seek(FileDescriptor fd, off_t pos, SeekMode mode); + +//! Returns the position of a file's read/write pointer. +off_t get_position(FileDescriptor fd); + +/*! \brief Returns a new file descriptor that refers to the same file as + that specified, or -1 if unsuccessful. Remember to call close + on the file descriptor when through with it. */ +FileDescriptor dup(FileDescriptor file); + +/*! \brief Similar to the first version, aside from that an error code is + returned and the resulting file descriptor is passed back via a reference + parameter. */ +status_t dup(FileDescriptor file, FileDescriptor& result); + +/*! \brief Flushes any buffers associated with the given file to disk + and then returns. */ +status_t sync(FileDescriptor file); + +//! Locks the given file so it may not be accessed by anyone else. +status_t lock(FileDescriptor file, OpenFlags mode, FileLock *lock); + +//! Unlocks a file previously locked with lock(). +status_t unlock(FileDescriptor file, FileLock *lock); + +//! Returns statistical information for the given file. +status_t get_stat(const char *path, Stat *s); +status_t get_stat(FileDescriptor file, Stat *s); +status_t get_stat(entry_ref &ref, Stat *s); + +//! Modifies a given portion of the file's statistical information. +status_t set_stat(FileDescriptor file, Stat &s, StatMember what); + +//! Same as the other version of set_stat(), except the file is specified by name. +status_t set_stat(const char *filename, Stat &s, StatMember what); + +//------------------------------------------------------------------------------ +// Attribute Functions +//------------------------------------------------------------------------------ +/*! \brief Reads the data from the specified attribute into the given buffer of size + count. Returns the number of bytes actually read. */ +ssize_t read_attr(FileDescriptor file, const char *attribute, uint32 type, + off_t pos, void *buf, size_t count ); + +//! Write count bytes from the given data buffer into the specified attribute. +ssize_t write_attr(FileDescriptor file, const char *attribute, uint32 type, + off_t pos, const void *buf, size_t count); + +//! Renames the specified attribute. +status_t rename_attr(FileDescriptor file, const char *oldName, + const char *newName); + +//! Removes the specified attribute and any data associated with it. +status_t remove_attr(FileDescriptor file, const char *attr); + +//! Returns statistical information about the given attribute. */ +status_t stat_attr(FileDescriptor file, const char *name, AttrInfo *ai); + + + +//------------------------------------------------------------------------------ +// Attribute Directory Functions +//------------------------------------------------------------------------------ +/*! Opens the attribute directory of a given file. */ +status_t open_attr_dir(FileDescriptor file, FileDescriptor &result); + +/*! Rewinds the given attribute directory. */ +status_t rewind_attr_dir(FileDescriptor dir); + +/*! Returns the next item in the given attribute directory, or + B_ENTRY_NOT_FOUND if at the end of the list. */ +status_t read_attr_dir(FileDescriptor dir, DirEntry &buffer); + +/*! Closes an attribute directory previously opened with open_attr_dir(). */ +status_t close_attr_dir(FileDescriptor dir); + + +//------------------------------------------------------------------------------ +// Directory Functions +//------------------------------------------------------------------------------ +/*! \brief Opens the given directory. Sets result to a properly "unitialized" directory + if the function fails. */ +status_t open_dir(const char *path, FileDescriptor &result); + +//! Creates a new directory. +status_t create_dir(const char *path, + mode_t mode = S_IRWXU | S_IRWXG | S_IRWXU); + +//! Creates a new directory and opens it. +status_t create_dir(const char *path, FileDescriptor &result, + mode_t mode = S_IRWXU | S_IRWXG | S_IRWXU); + +//! Returns the next entries in the given directory. +int32 read_dir(FileDescriptor dir, DirEntry *buffer, size_t length, + int32 count = INT_MAX); + +/*! Rewindes the directory to the first entry in the list. */ +status_t rewind_dir(FileDescriptor dir); + +/*! Iterates through the given directory searching for an entry whose name + matches that given by name. On success, places the DirEntry in result + and returns B_OK. On failures, returns an error code and sets result to + StorageKit::NullDir. + + Note: This call modifies the internal position marker of dir. */ +status_t find_dir(FileDescriptor dir, const char *name, DirEntry *result, + size_t length); + +/*! Calls the other version of StorageKit::find_dir() and stores the results + in the given entry_ref. */ +status_t find_dir(FileDescriptor dir, const char *name, entry_ref *result); + +/*! Creates a duplicated of the given directory and places it in result if successful, + returning B_OK. Returns an error code and sets result to -1 if + unsuccessful. */ +status_t dup_dir(FileDescriptor dir, FileDescriptor &result); + +/*! Closes the given directory. */ +status_t close_dir(FileDescriptor dir); + +//------------------------------------------------------------------------------ +// SymLink functions +//------------------------------------------------------------------------------ +//! Creates a new symbolic link. +status_t create_link(const char *path, const char *linkToPath); + +//! Creates a new symbolic link and opens it. +status_t create_link(const char *path, const char *linkToPath, + FileDescriptor &result); + +/*! If path refers to a symlink, the pathname of the target to which path + is linked is copied into result and NULL terminated, if the buffer is + long enough, the path is being truncated at size chars if necessary + (a buffer of size B_PATH_NAME_LENGTH+1 is a good idea), and the number of + chars in the target pathname is returned. If size is less than 1 or result + is NULL, B_BAD_VALUE will be returned and result will remain unmodified. + For any other error, result is set to an empty string and an error code + is returned. */ +ssize_t read_link(const char *path, char *result, size_t size); + +/*! Similar to the first version. Instead of a path name, a file descriptor + of the symbolic link is supplied. +*/ +ssize_t read_link(FileDescriptor fd, char *result, size_t size); + + +//------------------------------------------------------------------------------ +// Query Functions +//------------------------------------------------------------------------------ +/*! \brief Opens a query. Sets result to a properly "unitialized" query + if the function fails. */ +status_t open_query(dev_t device, const char *query, uint32 flags, + FileDescriptor &result); + +/*! \brief Opens a live query. Sets result to a properly "unitialized" query + if the function fails. */ +status_t open_live_query(dev_t device, const char *query, uint32 flags, + port_id port, int32 token, FileDescriptor &result); + +//! Returns the next entries in the given query. +int32 read_query(FileDescriptor query, DirEntry *buffer, size_t length, + int32 count = INT_MAX); + +/*! Closes the given query. */ +status_t close_query(FileDescriptor dir); + + +//------------------------------------------------------------------------------ +// Miscellaneous Functions +//------------------------------------------------------------------------------ +/*! Converts the given entry_ref into an absolute pathname, returning + the result in the string of length size pointed to by result (a size + of B_PATH_NAME_LENGTH+1 is a good idea). + + Returns B_OK if successful. + + If ref or result is NULL, B_BAD_VALUE is returned. Otherwise, + an error code is returned. The state of result after an error is undefined. +*/ +status_t entry_ref_to_path(const struct entry_ref *ref, char *result, + size_t size); + +/*! See the other definition of entry_ref_to_path() */ +status_t entry_ref_to_path(dev_t device, ino_t directory, const char *name, + char *result, size_t size); + +/*! Converts the given directory into an entry_ref. Note that the entry_ref is + actually a reference to the file "." in the given directory. + + Returns B_OK if successful. + + If dir is < 0 or result is NULL, B_BAD_VALUE is returned. + Otherwise, an appropriate error code is returned. + */ +status_t dir_to_self_entry_ref(FileDescriptor dir, entry_ref *result); + + +/*! Converts the given directory into an absolute pathname, returning the + result in the string of length size pointed to by result (a size of + B_PATH_NAME_LENGTH+1 is a good idea). + + Returns B_OK if successful. + + If dir is < 0 or result is NULL, B_BAD_VALUE + is returned. Otherwise, an error code is returned. The state of result after + an error is undefined. +*/ +status_t dir_to_path( FileDescriptor dir, char *result, size_t size ); + +/*! \brief Returns the canonical representation of a given path referring to an + potentially abstract entry in an existing directory. */ +status_t get_canonical_path(const char *path, char *result, size_t size); + +/*! \brief Returns the canonical representation of a given path referring to an + potentially abstract entry in an existing directory. */ +status_t get_canonical_path(const char *path, char *&result); + +/*! \brief Returns the canonical representation of a given path referring to an + existing directory. */ +status_t get_canonical_dir_path(const char *path, char *result, size_t size); + +/*! \brief Returns the canonical representation of a given path referring to an + existing directory. */ +status_t get_canonical_dir_path(const char *path, char *&result); + +/*! \brief Returns the path of this application. + The supplied buffer must be at least B_PATH_NAME_LENGTH + 1 bytes long. + The result will be null terminated. +*/ +status_t get_app_path(char *buffer); + +/*! Returns true if the given entry_ref represents the root directory, false otherwise. */ +bool entry_ref_is_root_dir(entry_ref &ref); + +/*! Renames oldPath to newPath, replacing newPath if it exists. */ +status_t rename(const char *oldPath, const char *newPath); + +/*! Removes path from the filesystem. */ +status_t remove(const char *path); + + +} // namespace StorageKit + +#endif diff --git a/headers/private/storage/storage_support.h b/headers/private/storage/storage_support.h new file mode 100644 index 0000000000..af659304cb --- /dev/null +++ b/headers/private/storage/storage_support.h @@ -0,0 +1,42 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file storage_support.h + Interface declarations for miscellaneous internal + Storage Kit support functions. +*/ + +#ifndef _sk_storage_support_h_ +#define _sk_storage_support_h_ + + +namespace StorageKit { + +//! Returns whether the supplied path is absolute. +bool is_absolute_path(const char *path); + +//! splits a path name into directory path and leaf name +status_t split_path(const char *fullPath, char *&path, char *&leaf); + +//! splits a path name into directory path and leaf name +status_t split_path(const char *fullPath, char **path, char **leaf); + +//! Parses the first component of a path name. +status_t parse_first_path_component(const char *path, int32& length, + int32& nextComponent); + +//! Parses the first component of a path name. +status_t parse_first_path_component(const char *path, char *&component, + int32& nextComponent); + +//! Checks whether an entry name is a valid entry name. +status_t check_entry_name(const char *entry); + +//! Checks whether a path name is a valid path name. +status_t check_path_name(const char *path); + +} // namespace StorageKit + +#endif // _sk_storage_support_h_ diff --git a/headers/tools/cppunit/CppUnitShell.h b/headers/tools/cppunit/CppUnitShell.h new file mode 100644 index 0000000000..1b8ad89185 --- /dev/null +++ b/headers/tools/cppunit/CppUnitShell.h @@ -0,0 +1,126 @@ +//---------------------------------------------------------------------- +// CppUnitShell.h - Copyright 2002 Tyler Dauwalder +// This software is release under the GNU Lesser GPL +// See the accompanying CppUnitShell.LICENSE file, or wander +// over to: http://www.gnu.org/copyleft/lesser.html +//---------------------------------------------------------------------- +#ifndef __cppunitshell_h__ +#define __cppunitshell_h__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Defines SuiteFunction to be a pointer to a function that +// takes no arguments and returns a pointer to a CppUnit::Test +typedef CppUnit::Test* (*SuiteFunction)(void); + +// This is just absurd to have to type... +typedef CppUnit::SynchronizedObject::SynchronizationObject SyncObject; + +// This class provides a fully functional command-line testing interface +// built on top of the CppUnit testing library. You add named test suites +// via AddSuite(), and then call Run(), which does all the dirty work. The +// user can get a list of each test installed via AddSuite(), and optionally +// can opt to run only a specified set of them. +class CppUnitShell { +public: + CppUnitShell(const std::string &description = "", SyncObject *syncObject = 0); + + // This function is used to add test suites to the list of available + // tests. A SuiteFunction is just a function that takes no parameters + // and returns a pointer to a CppUnit::Test object. Return NULL at + // your own risk :-). The name given is the name that will be presented + // when the program is run with "--list" as an argument. Usually the + // given suite would be a test suite for an entire class, but that's + // not a requirement. + void AddSuite(const std::string &name, const SuiteFunction suite); + + // This is the function you call after you've added all your test + // suites with calls to AddSuite(). It runs the test, or displays + // help, or lists installed tests, or whatever, depending on the + // command-line arguments passed in. + int Run(int argc, char *argv[]); + + // Verbosity Level enumeration and accessor function + enum VerbosityLevel { v0, v1, v2, v3 }; + VerbosityLevel Verbosity() const; + + // Returns true if verbosity is high enough that individual tests are + // allowed to make noise. + bool BeVerbose() const { return Verbosity() >= v2; }; + + +protected: + + VerbosityLevel fVerbosityLevel; + std::set fTestsToRun; + std::map fTests; + CppUnit::TestResult fTestResults; + CppUnit::TestResultCollector fResultsCollector; + std::string fDescription; + + // Prints a brief description of the program and a guess as to + // which Storage Kit library the app was linked with based on + // the filename of the app + virtual void PrintDescription(int argc, char *argv[]); + + // Prints out command line argument instructions + void PrintHelp(); + + // Handles command line arguments; returns true if everything goes + // okay, false if not (or if the program just needs to terminate without + // running any tests). Modifies settings in "settings" as necessary. + bool ProcessArguments(int argc, char *argv[]); + + // Makes any necessary pre-test preparations + void InitOutput(); + + // Prints out the test results in the proper format per + // the specified verbosity level. + void PrintResults(); + + //! Handles printing of test progress info + /*! Receives notification of the beginning and end of each test, + as well as all failures and errors for each test. Prints out + said test information in a standard format to standard output. + */ + class TestListener : public ::CppUnit::TestListener { + protected: + bool ok; + + public: + + virtual void startTest( CppUnit::Test *test ) { + ok = true; + cout << test->getName() << endl; + } + + virtual void addError( CppUnit::Test *test, CppUnit::Exception *e ) { + ok = false; + cout << " - ERROR -- " << e->what() << endl; + } + + virtual void addFailure( CppUnit::Test *test, CppUnit::Exception *e ) { + ok = false; + cout << " - FAILURE -- " << e->what() << endl; + } + + virtual void endTest( CppUnit::Test *test ) { + if (ok) + cout << " + PASSED" << endl; + cout << endl; + } + + }; + + +}; // class CppUnitShell + +#endif // __cppunitshell_h__ diff --git a/headers/tools/cppunit/LockerSyncObject.h b/headers/tools/cppunit/LockerSyncObject.h new file mode 100644 index 0000000000..523b3105de --- /dev/null +++ b/headers/tools/cppunit/LockerSyncObject.h @@ -0,0 +1,28 @@ +#ifndef _beos_synchronization_object_h_ +#define _beos_synchronization_object_h_ + +#include +#include + +/*! \brief BLocker based implementation of CppUnit::SynchronizedObject::SynchronizationObject +*/ +class LockerSyncObject : public CppUnit::SynchronizedObject::SynchronizationObject { +public: +/* LockerSyncObject() : fLock(new BLocker()) {} + virtual ~LockerSyncObject() { cout << 1 << endl; delete fLock; cout << 2 << endl; } + + virtual void lock() { fLock->Lock(); } + virtual void unlock() { fLock->Unlock(); } +protected: + BLocker *fLock; +*/ + LockerSyncObject() {} + virtual ~LockerSyncObject() {} + + virtual void lock() { fLock.Lock(); } + virtual void unlock() { fLock.Unlock(); } +protected: + BLocker fLock; +}; + +#endif // _beos_synchronization_object_h_ diff --git a/headers/tools/cppunit/TestCase.h b/headers/tools/cppunit/TestCase.h new file mode 100644 index 0000000000..558dc0f9d3 --- /dev/null +++ b/headers/tools/cppunit/TestCase.h @@ -0,0 +1,18 @@ +#ifndef _beos_test_case_h_ +#define _beos_test_case_h_ + +#include +#include + +class TestCase : public CppUnit::TestCase { +public: + TestCase(); + TestCase(std::string Name); + void SaveCWD(); + void RestoreCWD(const char *alternate = NULL); +protected: + bool fValidCWD; + char fCurrentWorkingDir[B_PATH_NAME_LENGTH+1]; +}; + +#endif // _beos_test_case_h_ \ No newline at end of file diff --git a/headers/tools/cppunit/TestResult.h b/headers/tools/cppunit/TestResult.h new file mode 100644 index 0000000000..499bb4d06c --- /dev/null +++ b/headers/tools/cppunit/TestResult.h @@ -0,0 +1,18 @@ +#ifndef _beos_test_result_h_ +#define _beos_test_result_h_ + +#include + +/*! \brief CppUnit::TestResult class with BeOS synchronization implementation. + +*/ +//template +class TestResult : public CppUnit::TestResult { +public: + TestResult(); +protected: +}; + +#endif // _beos_test_result_h_ + + diff --git a/headers/tools/cppunit/TestShell.h b/headers/tools/cppunit/TestShell.h new file mode 100644 index 0000000000..c6dd3994f3 --- /dev/null +++ b/headers/tools/cppunit/TestShell.h @@ -0,0 +1,17 @@ +#ifndef _beos_test_shell_h_ +#define _beos_test_shell_h_ + +#include + +class TestShell : public CppUnitShell { +public: + TestShell(const std::string &description = "", SyncObject *syncObject = 0); + ~TestShell(); + int Run(int argc, char *argv[]); +// virtual void PrintDescription(int argc, char *argv[]); + const char* TestDir() const; +private: + BPath *fTestDir; +}; + +#endif // _beos_test_shell_h_ \ No newline at end of file diff --git a/headers/tools/cppunit/TestSuite.h b/headers/tools/cppunit/TestSuite.h new file mode 100644 index 0000000000..bf92a28a51 --- /dev/null +++ b/headers/tools/cppunit/TestSuite.h @@ -0,0 +1,18 @@ +#ifndef _beos_test_suite_h_ +#define _beos_test_suite_h_ + +#include + +class TestSuite : public CppUnit::TestSuite { + //! Calls setUp(), runs the test suite, calls tearDown(). + virtual void run (CppUnit::TestResult *result); + + //! This function called *once* before the entire suite of tests is run + virtual void setUp() {} + + //! This function called *once* after the entire suite of tests is run + virtual void tearDown() {} + +}; + +#endif // _beos_test_suite_h_ \ No newline at end of file diff --git a/headers/tools/cppunit/cppunit/Asserter.h b/headers/tools/cppunit/cppunit/Asserter.h new file mode 100644 index 0000000000..808b909c05 --- /dev/null +++ b/headers/tools/cppunit/cppunit/Asserter.h @@ -0,0 +1,91 @@ +#ifndef CPPUNIT_ASSERTER_H +#define CPPUNIT_ASSERTER_H + +#include +#include +#include + +namespace CppUnit +{ + +/*! \brief A set of functions to help writing assertion macros. + * \ingroup CreatingNewAssertions + * + * Here is an example of assertion, a simplified version of the + * actual assertion implemented in examples/cppunittest/XmlUniformiser.h: + * \code + * #include + * #include + * + * void + * checkXmlEqual( std::string expectedXml, + * std::string actualXml, + * CppUnit::SourceLine sourceLine ) + * { + * std::string expected = XmlUniformiser( expectedXml ).stripped(); + * std::string actual = XmlUniformiser( actualXml ).stripped(); + * + * if ( expected == actual ) + * return; + * + * ::CppUnit::Asserter::failNotEqual( expected, + * actual, + * sourceLine ); + * } + * + * /// Asserts that two XML strings are equivalent. + * #define CPPUNITTEST_ASSERT_XML_EQUAL( expected, actual ) \ + * checkXmlEqual( expected, actual, \ + * CPPUNIT_SOURCELINE() ) + * \endcode + */ +namespace Asserter +{ + + /*! Throws a Exception with the specified message and location. + */ + void CPPUNIT_API fail( std::string message, + SourceLine sourceLine = SourceLine() ); + + /*! Throws a Exception with the specified message and location. + * \param shouldFail if \c true then the exception is thrown. Otherwise + * nothing happen. + * \param message Message explaining the assertion failiure. + * \param sourceLine Location of the assertion. + */ + void CPPUNIT_API failIf( bool shouldFail, + std::string message, + SourceLine sourceLine = SourceLine() ); + + /*! Throws a NotEqualException with the specified message and location. + * \param expected Text describing the expected value. + * \param actual Text describing the actual value. + * \param additionalMessage Additional message. Usually used to report + * where the "difference" is located. + * \param sourceLine Location of the assertion. + */ + void CPPUNIT_API failNotEqual( std::string expected, + std::string actual, + SourceLine sourceLine = SourceLine(), + std::string additionalMessage ="" ); + + /*! Throws a NotEqualException with the specified message and location. + * \param shouldFail if \c true then the exception is thrown. Otherwise + * nothing happen. + * \param expected Text describing the expected value. + * \param actual Text describing the actual value. + * \param additionalMessage Additional message. Usually used to report + * where the "difference" is located. + * \param sourceLine Location of the assertion. + */ + void CPPUNIT_API failNotEqualIf( bool shouldFail, + std::string expected, + std::string actual, + SourceLine sourceLine = SourceLine(), + std::string additionalMessage ="" ); + +} // namespace Asserter +} // namespace CppUnit + + +#endif // CPPUNIT_ASSERTER_H diff --git a/headers/tools/cppunit/cppunit/CompilerOutputter.h b/headers/tools/cppunit/cppunit/CompilerOutputter.h new file mode 100644 index 0000000000..0075972bc0 --- /dev/null +++ b/headers/tools/cppunit/cppunit/CompilerOutputter.h @@ -0,0 +1,109 @@ +#ifndef CPPUNIT_COMPILERTESTRESULTOUTPUTTER_H +#define CPPUNIT_COMPILERTESTRESULTOUTPUTTER_H + +#include +#include +#include +#include + +namespace CppUnit +{ + +class Exception; +class SourceLine; +class Test; +class TestFailure; +class TestResultCollector; + +/*! + * \brief Outputs a TestResultCollector in a compiler compatible format. + * \ingroup WritingTestResult + * + * Printing the test results in a compiler compatible format (assertion + * location has the same format as compiler error), allow you to use your + * IDE to jump to the assertion failure. + * + * For example, when running the test in a post-build with VC++, if an assertion + * fails, you can jump to the assertion by pressing F4 (jump to next error). + * + * You should use defaultOutputter() to create an instance. + * + * Heres is an example of usage (from examples/cppunittest/CppUnitTestMain.cpp): + * \code + * int main( int argc, char* argv[] ) { + * // if command line contains "-selftest" then this is the post build check + * // => the output must be in the compiler error format. + * bool selfTest = (argc > 1) && + * (std::string("-selftest") == argv[1]); + * + * CppUnit::TextUi::TestRunner runner; + * runner.addTest( CppUnitTest::suite() ); // Add the top suite to the test runner + * + * if ( selfTest ) + * { // Change the default outputter to a compiler error format outputter + * // The test runner owns the new outputter. + * runner.setOutputter( CppUnit::CompilerOutputter::defaultOutputter( + * &runner.result(), + * std::cerr ) ); + * } + * + * // Run the test and don't wait a key if post build check. + * bool wasSucessful = runner.run( "", !selfTest ); + * + * // Return error code 1 if the one of test failed. + * return wasSucessful ? 0 : 1; + * } + * \endcode + */ +class CPPUNIT_API CompilerOutputter : public Outputter +{ +public: + /*! Constructs a CompilerOutputter object. + */ + CompilerOutputter( TestResultCollector *result, + std::ostream &stream ); + + /// Destructor. + virtual ~CompilerOutputter(); + + /*! Creates an instance of an outputter that matches your current compiler. + */ + static CompilerOutputter *defaultOutputter( TestResultCollector *result, + std::ostream &stream ); + + void write(); + + virtual void printSucess(); + virtual void printFailureReport(); + virtual void printFailuresList(); + virtual void printStatistics(); + virtual void printFailureDetail( TestFailure *failure ); + virtual void printFailureLocation( SourceLine sourceLine ); + virtual void printFailureType( TestFailure *failure ); + virtual void printFailedTestName( TestFailure *failure ); + virtual void printFailureMessage( TestFailure *failure ); + virtual void printNotEqualMessage( Exception *thrownException ); + virtual void printDefaultMessage( Exception *thrownException ); + virtual std::string wrap( std::string message ); + +private: + /// Prevents the use of the copy constructor. + CompilerOutputter( const CompilerOutputter © ); + + /// Prevents the use of the copy operator. + void operator =( const CompilerOutputter © ); + + typedef std::vector Lines; + static Lines splitMessageIntoLines( std::string message ); + +private: + TestResultCollector *m_result; + std::ostream &m_stream; +}; + + +} // namespace CppUnit + + + +#endif // CPPUNIT_COMPILERTESTRESULTOUTPUTTER_H diff --git a/headers/tools/cppunit/cppunit/Exception.h b/headers/tools/cppunit/cppunit/Exception.h new file mode 100644 index 0000000000..505d16edf8 --- /dev/null +++ b/headers/tools/cppunit/cppunit/Exception.h @@ -0,0 +1,81 @@ +#ifndef CPPUNIT_EXCEPTION_H +#define CPPUNIT_EXCEPTION_H + +#include +#include +#include +#include + +namespace CppUnit { + +/*! \brief Exceptions thrown by failed assertions. + * \ingroup BrowsingCollectedTestResult + * + * Exception is an exception that serves + * descriptive strings through its what() method + */ +class CPPUNIT_API Exception : public std::exception +{ +public: + + class Type + { + public: + Type( std::string type ) : m_type ( type ) {} + + bool operator ==( const Type &other ) const + { + return m_type == other.m_type; + } + private: + const std::string m_type; + }; + + + Exception( std::string message = "", + SourceLine sourceLine = SourceLine() ); + +#ifdef CPPUNIT_ENABLE_SOURCELINE_DEPRECATED + Exception( std::string message, + long lineNumber, + std::string fileName ); +#endif + + Exception (const Exception& other); + + virtual ~Exception () throw(); + + Exception& operator= (const Exception& other); + + const char *what() const throw (); + + SourceLine sourceLine() const; + +#ifdef CPPUNIT_ENABLE_SOURCELINE_DEPRECATED + long lineNumber() const; + std::string fileName() const; + + static const std::string UNKNOWNFILENAME; + static const long UNKNOWNLINENUMBER; +#endif + + virtual Exception *clone() const; + + virtual bool isInstanceOf( const Type &type ) const; + + static Type type(); + +private: + // VC++ does not recognize call to parent class when prefixed + // with a namespace. This is a workaround. + typedef std::exception SuperClass; + + std::string m_message; + SourceLine m_sourceLine; +}; + + +} // namespace CppUnit + +#endif // CPPUNIT_EXCEPTION_H + diff --git a/headers/tools/cppunit/cppunit/NotEqualException.h b/headers/tools/cppunit/cppunit/NotEqualException.h new file mode 100644 index 0000000000..52cc7d2d97 --- /dev/null +++ b/headers/tools/cppunit/cppunit/NotEqualException.h @@ -0,0 +1,65 @@ +#ifndef NOTEQUALEXCEPTION_H +#define NOTEQUALEXCEPTION_H + +#include + + +namespace CppUnit { + +/*! \brief Exception thrown by failed equality assertions. + * \ingroup BrowsingCollectedTestResult + */ +class CPPUNIT_API NotEqualException : public Exception +{ +public: + /*! Constructs the exception. + * \param expected Text that represents the expected value. + * \param actual Text that represents the actual value. + * \param sourceLine Location of the assertion. + * \param additionalMessage Additionnal information provided to further qualify + * the inequality. + */ + NotEqualException( std::string expected, + std::string actual, + SourceLine sourceLine = SourceLine(), + std::string additionalMessage = "" ); + +#ifdef CPPUNIT_ENABLE_SOURCELINE_DEPRECATED + NotEqualException( std::string expected, + std::string actual, + long lineNumber, + std::string fileName ); +#endif + + NotEqualException( const NotEqualException &other ); + + + virtual ~NotEqualException() throw(); + + std::string expectedValue() const; + + std::string actualValue() const; + + std::string additionalMessage() const; + + /*! Copy operator. + * @param other Object to copy. + * @return Reference on this object. + */ + NotEqualException &operator =( const NotEqualException &other ); + + Exception *clone() const; + + bool isInstanceOf( const Type &type ) const; + + static Type type(); + +private: + std::string m_expected; + std::string m_actual; + std::string m_additionalMessage; +}; + +} // namespace CppUnit + +#endif // NOTEQUALEXCEPTION_H diff --git a/headers/tools/cppunit/cppunit/Outputter.h b/headers/tools/cppunit/cppunit/Outputter.h new file mode 100644 index 0000000000..1f28652813 --- /dev/null +++ b/headers/tools/cppunit/cppunit/Outputter.h @@ -0,0 +1,31 @@ +#ifndef CPPUNIT_OUTPUTTER_H +#define CPPUNIT_OUTPUTTER_H + +#include + + +namespace CppUnit +{ + +/*! \brief Abstract outputter to print test result summary. + * \ingroup WritingTestResult + */ +class CPPUNIT_API Outputter +{ +public: + /// Destructor. + virtual ~Outputter() {} + + virtual void write() =0; +}; + + + +// Inlines methods for Outputter: +// ------------------------------ + + +} // namespace CppUnit + + +#endif // CPPUNIT_OUTPUTTER_H diff --git a/headers/tools/cppunit/cppunit/Portability.h b/headers/tools/cppunit/cppunit/Portability.h new file mode 100644 index 0000000000..902de567f4 --- /dev/null +++ b/headers/tools/cppunit/cppunit/Portability.h @@ -0,0 +1,85 @@ +#ifndef CPPUNIT_PORTABILITY_H +#define CPPUNIT_PORTABILITY_H + +/* include platform specific config */ +#if defined(__BORLANDC__) +# include +#elif defined (_MSC_VER) +# include +#else +# include +#endif + + +/* Options that the library user may switch on or off. + * If the user has not done so, we chose default values. + */ + + +/* Define to 1 if you wish to have the old-style macros + assert(), assertEqual(), assertDoublesEqual(), and assertLongsEqual() */ +#ifndef CPPUNIT_ENABLE_NAKED_ASSERT +#define CPPUNIT_ENABLE_NAKED_ASSERT 0 +#endif + +/* Define to 1 if you wish to have the old-style CU_TEST family + of macros. */ +#ifndef CPPUNIT_ENABLE_CU_TEST_MACROS +#define CPPUNIT_ENABLE_CU_TEST_MACROS 0 +#endif + +/* Define to 1 if the preprocessor expands (#foo) to "foo" (quotes incl.) + I don't think there is any C preprocess that does NOT support this! */ +#ifndef CPPUNIT_HAVE_CPP_SOURCE_ANNOTATION +#define CPPUNIT_HAVE_CPP_SOURCE_ANNOTATION 1 +#endif + +// CPPUNIT_API is defined in if required (building or using as dll) +#ifndef CPPUNIT_API +#define CPPUNIT_API +#undef CPPUNIT_NEED_DLL_DECL +#define CPPUNIT_NEED_DLL_DECL 0 +#endif + + +/* perform portability hacks */ + + +/* Define CPPUNIT_SSTREAM as a stream with a "std::string str()" + * method. + */ +#if CPPUNIT_HAVE_SSTREAM +# include + namespace CppUnit { + class OStringStream : public std::ostringstream + { + }; + } +#else +#if CPPUNIT_HAVE_CLASS_STRSTREAM +# include +# if CPPUNIT_HAVE_STRSTREAM +# include +# else +# include +# endif + + namespace CppUnit { + class OStringStream : public std::ostrstream + { + public: + std::string str() + { + (*this) << '\0'; + std::string msg(std::ostrstream::str()); + std::ostrstream::freeze(false); + return msg; + } + }; + } +#else +# error Cannot define CppUnit::OStringStream. +#endif +#endif + +#endif // CPPUNIT_PORTABILITY_H diff --git a/headers/tools/cppunit/cppunit/SourceLine.h b/headers/tools/cppunit/cppunit/SourceLine.h new file mode 100644 index 0000000000..5d2a3c1ce2 --- /dev/null +++ b/headers/tools/cppunit/cppunit/SourceLine.h @@ -0,0 +1,60 @@ +#ifndef CPPUNIT_SOURCELINE_H +#define CPPUNIT_SOURCELINE_H + +#include +#include + +/*! \brief Constructs a SourceLine object initialized with the location where the macro is expanded. + * \ingroup CreatingNewAssertions + * \relates CppUnit::SourceLine + * Used to write your own assertion macros. + * \see Asserter for example of usage. + */ +#define CPPUNIT_SOURCELINE() ::CppUnit::SourceLine( __FILE__, __LINE__ ) + + +namespace CppUnit +{ + +/*! \brief Represents a source line location. + * \ingroup CreatingNewAssertions + * \ingroup BrowsingCollectedTestResult + * + * Used to capture the failure location in assertion. + * + * Use the CPPUNIT_SOURCELINE() macro to construct that object. Typically used when + * writing an assertion macro in association with Asserter. + * + * \see Asserter. + */ +class CPPUNIT_API SourceLine +{ +public: + SourceLine(); + + SourceLine( const std::string &fileName, + int lineNumber ); + + /// Destructor. + virtual ~SourceLine(); + + bool isValid() const; + + int lineNumber() const; + + std::string fileName() const; + + bool operator ==( const SourceLine &other ) const; + bool operator !=( const SourceLine &other ) const; + +private: + std::string m_fileName; + int m_lineNumber; +}; + + +} // namespace CppUnit + + + +#endif // CPPUNIT_SOURCELINE_H diff --git a/headers/tools/cppunit/cppunit/SynchronizedObject.h b/headers/tools/cppunit/cppunit/SynchronizedObject.h new file mode 100644 index 0000000000..7ee8447e40 --- /dev/null +++ b/headers/tools/cppunit/cppunit/SynchronizedObject.h @@ -0,0 +1,82 @@ +#ifndef CPPUNIT_SYNCHRONIZEDOBJECT_H +#define CPPUNIT_SYNCHRONIZEDOBJECT_H + +#include + + +namespace CppUnit +{ + +/*! \brief Base class for synchronized object. + * + * Synchronized object are object which members are used concurrently by mutiple + * threads. + * + * This class define the class SynchronizationObject which must be subclassed + * to implement an actual lock. + * + * Each instance of this class holds a pointer on a lock object. + * + * See src/msvc6/MfcSynchronizedObject.h for an example. + */ +class CPPUNIT_API SynchronizedObject +{ +public: + /*! \brief Abstract synchronization object (mutex) + */ + class SynchronizationObject + { + public: + SynchronizationObject() {} + virtual ~SynchronizationObject() {} + + virtual void lock() {} + virtual void unlock() {} + }; + + /*! Constructs a SynchronizedObject object. + */ + SynchronizedObject( SynchronizationObject *syncObject =0 ); + + /// Destructor. + virtual ~SynchronizedObject(); + +protected: + /*! \brief Locks a synchronization object in the current scope. + */ + class ExclusiveZone + { + SynchronizationObject *m_syncObject; + + public: + ExclusiveZone( SynchronizationObject *syncObject ) + : m_syncObject( syncObject ) + { + m_syncObject->lock(); + } + + ~ExclusiveZone() + { + m_syncObject->unlock (); + } + }; + + virtual void setSynchronizationObject( SynchronizationObject *syncObject ); + +protected: + SynchronizationObject *m_syncObject; + +private: + /// Prevents the use of the copy constructor. + SynchronizedObject( const SynchronizedObject © ); + + /// Prevents the use of the copy operator. + void operator =( const SynchronizedObject © ); +}; + + + +} // namespace CppUnit + + +#endif // CPPUNIT_SYNCHRONIZEDOBJECT_H diff --git a/headers/tools/cppunit/cppunit/Test.h b/headers/tools/cppunit/cppunit/Test.h new file mode 100644 index 0000000000..2ee2a483e3 --- /dev/null +++ b/headers/tools/cppunit/cppunit/Test.h @@ -0,0 +1,63 @@ +#ifndef CPPUNIT_TEST_H +#define CPPUNIT_TEST_H + +#include +#include + +namespace CppUnit { + +class TestResult; + +/*! \brief Base class for all test objects. + * \ingroup BrowsingCollectedTestResult + * + * All test objects should be a subclass of Test. Some test objects, + * TestCase for example, represent one individual test. Other test + * objects, such as TestSuite, are comprised of several tests. + * + * When a Test is run, the result is collected by a TestResult object. + * + * \see TestCase + * \see TestSuite + */ +class CPPUNIT_API Test +{ +public: + virtual ~Test () {}; + + /*! \brief Run the test, collecting results. + */ + virtual void run (TestResult *result) = 0; + + /*! \brief Return the number of test cases invoked by run(). + * + * The base unit of testing is the class TestCase. This + * method returns the number of TestCase objects invoked by + * the run() method. + */ + virtual int countTestCases () const = 0; + + /*! \brief Returns the test name. + * + * Each test has a name. This name may be used to find the + * test in a suite or registry of tests. + */ + virtual std::string getName () const = 0; + + /*! \brief Description of the test, for diagnostic output. + * + * The test description will typically include the test name, + * but may have additional description. For example, a test + * suite named complex_add may be described as + * suite complex_add. + */ + virtual std::string toString () const = 0; + + +}; + + +} // namespace CppUnit + +#endif // CPPUNIT_TEST_H + diff --git a/headers/tools/cppunit/cppunit/TestAssert.h b/headers/tools/cppunit/cppunit/TestAssert.h new file mode 100644 index 0000000000..2f47f59b4d --- /dev/null +++ b/headers/tools/cppunit/cppunit/TestAssert.h @@ -0,0 +1,229 @@ +#ifndef CPPUNIT_TESTASSERT_H +#define CPPUNIT_TESTASSERT_H + +#include +#include +#include + + +namespace CppUnit { + + /*! \brief Traits used by CPPUNIT_ASSERT_EQUAL(). + * + * Here is an example of specialization of that traits: + * + * \code + * template<> + * struct assertion_traits // specialization for the std::string type + * { + * static bool equal( const std::string& x, const std::string& y ) + * { + * return x == y; + * } + * + * static std::string toString( const std::string& x ) + * { + * std::string text = '"' + x + '"'; // adds quote around the string to see whitespace + * OStringStream ost; + * ost << text; + * return ost.str(); + * } + * }; + * \endcode + */ + template + struct assertion_traits + { + static bool equal( const T& x, const T& y ) + { + return x == y; + } + + static std::string toString( const T& x ) + { + OStringStream ost; + ost << x; + return ost.str(); + } + }; + + + namespace TestAssert + { +#ifdef CPPUNIT_ENABLE_SOURCELINE_DEPRECATED + void CPPUNIT_API assertImplementation( bool condition, + std::string conditionExpression = "", + long lineNumber, + std::string fileName ); + + void CPPUNIT_API assertNotEqualImplementation( std::string expected, + std::string actual, + long lineNumber, + std::string fileName ); + + + template + void assertEquals( const T& expected, + const T& actual, + long lineNumber, + std::string fileName ) + { + if ( !assertion_traits::equal(expected,actual) ) // lazy toString conversion... + { + assertNotEqualImplementation( assertion_traits::toString(expected), + assertion_traits::toString(actual), + lineNumber, + fileName ); + } + } + + void CPPUNIT_API assertEquals( double expected, + double actual, + double delta, + long lineNumber, + std::string fileName ); + +#else // using SourceLine + + template + void assertEquals( const T& expected, + const T& actual, + SourceLine sourceLine, + const std::string &message ="" ) + { + if ( !assertion_traits::equal(expected,actual) ) // lazy toString conversion... + { + Asserter::failNotEqual( assertion_traits::toString(expected), + assertion_traits::toString(actual), + sourceLine, + message ); + } + } + + void CPPUNIT_API assertDoubleEquals( double expected, + double actual, + double delta, + SourceLine sourceLine ); + +#endif + } + + +/* A set of macros which allow us to get the line number + * and file name at the point of an error. + * Just goes to show that preprocessors do have some + * redeeming qualities. + */ +#if CPPUNIT_HAVE_CPP_SOURCE_ANNOTATION +/** Assertions that a condition is \c true. + * \ingroup Assertions + */ +#define CPPUNIT_ASSERT(condition) \ + ( ::CppUnit::Asserter::failIf( !(condition), \ + (#condition), \ + CPPUNIT_SOURCELINE() ) ) +#else +#define CPPUNIT_ASSERT(condition) \ + ( ::CppUnit::Asserter::failIf( !(condition), \ + "", \ + CPPUNIT_SOURCELINE() ) ) +#endif + +/** Assertion with a user specified message. + * \ingroup Assertions + * \param message Message reported in diagnostic if \a condition evaluates + * to \c false. + * \param condition If this condition evaluates to \c false then the + * test failed. + */ +#define CPPUNIT_ASSERT_MESSAGE(message,condition) \ + ( ::CppUnit::Asserter::failIf( !(condition), \ + (message), \ + CPPUNIT_SOURCELINE() ) ) + +/** Fails with the specified message. + * \ingroup Assertions + * \param message Message reported in diagnostic. + */ +#define CPPUNIT_FAIL( message ) \ + ( ::CppUnit::Asserter::fail( message, \ + CPPUNIT_SOURCELINE() ) ) + +#ifdef CPPUNIT_ENABLE_SOURCELINE_DEPRECATED +/// Generalized macro for primitive value comparisons +#define CPPUNIT_ASSERT_EQUAL(expected,actual) \ + ( ::CppUnit::TestAssert::assertEquals( (expected), \ + (actual), \ + __LINE__, __FILE__ ) ) +#else +/** Asserts that two values are equals. + * \ingroup Assertions + * + * Equality and string representation can be defined with + * an appropriate CppUnit::assertion_traits class. + * + * A diagnostic is printed if actual and expected values disagree. + * + * Requirement for \a expected and \a actual parameters: + * - They are exactly of the same type + * - They are serializable into a std::strstream using operator <<. + * - They can be compared using operator ==. + * + * The last two requirements (serialization and comparison) can be + * removed by specializing the CppUnit::assertion_traits. + */ +#define CPPUNIT_ASSERT_EQUAL(expected,actual) \ + ( ::CppUnit::TestAssert::assertEquals( (expected), \ + (actual), \ + CPPUNIT_SOURCELINE() ) ) + +/** Asserts that two values are equals, provides additional messafe on failure. + * \ingroup Assertions + * + * Equality and string representation can be defined with + * an appropriate assertion_traits class. + * + * A diagnostic is printed if actual and expected values disagree. + * The message is printed in addition to the expected and actual value + * to provide additional information. + * + * Requirement for \a expected and \a actual parameters: + * - They are exactly of the same type + * - They are serializable into a std::strstream using operator <<. + * - They can be compared using operator ==. + * + * The last two requirements (serialization and comparison) can be + * removed by specializing the CppUnit::assertion_traits. + */ +#define CPPUNIT_ASSERT_EQUAL_MESSAGE(message,expected,actual) \ + ( ::CppUnit::TestAssert::assertEquals( (expected), \ + (actual), \ + CPPUNIT_SOURCELINE(), \ + (message) ) ) +#endif + +/*! \brief Macro for primitive value comparisons + * \ingroup Assertions + */ +#define CPPUNIT_ASSERT_DOUBLES_EQUAL(expected,actual,delta) \ + ( ::CppUnit::TestAssert::assertDoubleEquals( (expected), \ + (actual), \ + (delta), \ + CPPUNIT_SOURCELINE() ) ) + +// Backwards compatibility + +#if CPPUNIT_ENABLE_NAKED_ASSERT + +#undef assert +#define assert(c) CPPUNIT_ASSERT(c) +#define assertEqual(e,a) CPPUNIT_ASSERT_EQUAL(e,a) +#define assertDoublesEqual(e,a,d) CPPUNIT_ASSERT_DOUBLES_EQUAL(e,a,d) +#define assertLongsEqual(e,a) CPPUNIT_ASSERT_EQUAL(e,a) + +#endif + + +} // namespace CppUnit + +#endif // CPPUNIT_TESTASSERT_H diff --git a/headers/tools/cppunit/cppunit/TestCaller.h b/headers/tools/cppunit/cppunit/TestCaller.h new file mode 100644 index 0000000000..785301901b --- /dev/null +++ b/headers/tools/cppunit/cppunit/TestCaller.h @@ -0,0 +1,204 @@ +#ifndef CPPUNIT_TESTCALLER_H // -*- C++ -*- +#define CPPUNIT_TESTCALLER_H + +#include +#include + + +#if CPPUNIT_USE_TYPEINFO_NAME +# include +#endif + + +namespace CppUnit { + +/*! \brief Marker class indicating that no exception is expected by TestCaller. + * This class is an implementation detail. You should never use this class directly. + */ +class CPPUNIT_API NoExceptionExpected +{ +private: + //! Prevent class instantiation. + NoExceptionExpected(); +}; + + +/*! \brief (Implementation) Traits used by TestCaller to expect an exception. + * + * This class is an implementation detail. You should never use this class directly. + */ +template +struct ExpectedExceptionTraits +{ + static void expectedException() + { +#if CPPUNIT_USE_TYPEINFO_NAME + std::string message( "Expected exception of type " ); + message += TypeInfoHelper::getClassName( typeid( ExceptionType ) ); + message += ", but got none"; +#else + std::string message( "Expected exception but got none" ); +#endif + throw Exception( message ); + } +}; + + +/*! \brief (Implementation) Traits specialization used by TestCaller to + * expect no exception. + * + * This class is an implementation detail. You should never use this class directly. + */ +template<> +struct ExpectedExceptionTraits +{ + static void expectedException() + { + } +}; + + + +//*** FIXME: rework this when class Fixture is implemented. ***// + + +/*! \brief Generate a test case from a fixture method. + * \ingroup WritingTestFixture + * + * A test caller provides access to a test case method + * on a test fixture class. Test callers are useful when + * you want to run an individual test or add it to a + * suite. + * Test Callers invoke only one Test (i.e. test method) on one + * Fixture of a TestFixture. + * + * Here is an example: + * \code + * class MathTest : public CppUnit::TestFixture { + * ... + * public: + * void setUp(); + * void tearDown(); + * + * void testAdd(); + * void testSubtract(); + * }; + * + * CppUnit::Test *MathTest::suite() { + * CppUnit::TestSuite *suite = new CppUnit::TestSuite; + * + * suite->addTest( new CppUnit::TestCaller( "testAdd", testAdd ) ); + * return suite; + * } + * \endcode + * + * You can use a TestCaller to bind any test method on a TestFixture + * class, as long as it accepts void and returns void. + * + * \see TestCase + */ + +template +class TestCaller : public TestCase +{ + typedef void (Fixture::*TestMethod)(); + +public: + /*! + * Constructor for TestCaller. This constructor builds a new Fixture + * instance owned by the TestCaller. + * \param name name of this TestCaller + * \param test the method this TestCaller calls in runTest() + */ + TestCaller( std::string name, TestMethod test ) : + TestCase( name ), + m_ownFixture( true ), + m_fixture( new Fixture() ), + m_test( test ) + { + } + + /*! + * Constructor for TestCaller. + * This constructor does not create a new Fixture instance but accepts + * an existing one as parameter. The TestCaller will not own the + * Fixture object. + * \param name name of this TestCaller + * \param test the method this TestCaller calls in runTest() + * \param fixture the Fixture to invoke the test method on. + */ + TestCaller(std::string name, TestMethod test, Fixture& fixture) : + TestCase( name ), + m_ownFixture( false ), + m_fixture( &fixture ), + m_test( test ) + { + } + + /*! + * Constructor for TestCaller. + * This constructor does not create a new Fixture instance but accepts + * an existing one as parameter. The TestCaller will own the + * Fixture object and delete it in its destructor. + * \param name name of this TestCaller + * \param test the method this TestCaller calls in runTest() + * \param fixture the Fixture to invoke the test method on. + */ + TestCaller(std::string name, TestMethod test, Fixture* fixture) : + TestCase( name ), + m_ownFixture( true ), + m_fixture( fixture ), + m_test( test ) + { + } + + ~TestCaller() + { + if (m_ownFixture) + delete m_fixture; + } + +protected: + void runTest() + { + try { + (m_fixture->*m_test)(); + } + catch ( ExpectedException & ) { + return; + } + + ExpectedExceptionTraits::expectedException(); + } + + void setUp() + { + m_fixture->setUp (); + } + + void tearDown() + { + m_fixture->tearDown (); + } + + std::string toString() const + { + return "TestCaller " + getName(); + } + +private: + TestCaller( const TestCaller &other ); + TestCaller &operator =( const TestCaller &other ); + +private: + bool m_ownFixture; + Fixture *m_fixture; + TestMethod m_test; +}; + + + +} // namespace CppUnit + +#endif // CPPUNIT_TESTCALLER_H diff --git a/headers/tools/cppunit/cppunit/TestCase.h b/headers/tools/cppunit/cppunit/TestCase.h new file mode 100644 index 0000000000..f9cb1d911a --- /dev/null +++ b/headers/tools/cppunit/cppunit/TestCase.h @@ -0,0 +1,61 @@ +#ifndef CPPUNIT_TESTCASE_H +#define CPPUNIT_TESTCASE_H + +#include +#include +#include +#include +#include + + +namespace CppUnit { + +class TestResult; + + +/*! \brief A single test object. + * + * This class is used to implement a simple test case: define a subclass + * that overrides the runTest method. + * + * You don't usually need to use that class, but TestFixture and TestCaller instead. + * + * You are expected to subclass TestCase is you need to write a class similiar + * to TestCaller. + */ +class CPPUNIT_API TestCase : public Test, + public TestFixture +{ +public: + + TestCase( std::string Name ); + //! \internal + TestCase(); + ~TestCase(); + + virtual void run(TestResult *result); + virtual int countTestCases() const; + std::string getName() const; + std::string toString() const; + + //! FIXME: what is this for? + virtual TestResult *run(); + +protected: + //! FIXME: this should probably be pure virtual. + virtual void runTest(); + + //! Create TestResult for the run(void) method. + TestResult *defaultResult(); + +private: + TestCase( const TestCase &other ); + TestCase &operator=( const TestCase &other ); + +private: + const std::string m_name; +}; + +} // namespace CppUnit + +#endif // CPPUNIT_TESTCASE_H diff --git a/headers/tools/cppunit/cppunit/TestFailure.h b/headers/tools/cppunit/cppunit/TestFailure.h new file mode 100644 index 0000000000..a610072a68 --- /dev/null +++ b/headers/tools/cppunit/cppunit/TestFailure.h @@ -0,0 +1,59 @@ +#ifndef CPPUNIT_TESTFAILURE_H // -*- C++ -*- +#define CPPUNIT_TESTFAILURE_H + +#include +#include + +namespace CppUnit { + +class Exception; +class SourceLine; +class Test; + + +/*! \brief Record of a failed Test execution. + * \ingroup BrowsingCollectedTestResult + * + * A TestFailure collects a failed test together with + * the caught exception. + * + * TestFailure assumes lifetime control for any exception + * passed to it. + */ +class CPPUNIT_API TestFailure +{ +public: + TestFailure( Test *failedTest, + Exception *thrownException, + bool isError ); + + virtual ~TestFailure (); + + virtual Test *failedTest() const; + + virtual Exception *thrownException() const; + + virtual SourceLine sourceLine() const; + + virtual bool isError() const; + + virtual std::string failedTestName() const; + + virtual std::string toString() const; + + virtual TestFailure *clone() const; + +protected: + Test *m_failedTest; + Exception *m_thrownException; + bool m_isError; + +private: + TestFailure( const TestFailure &other ); + TestFailure &operator =( const TestFailure& other ); +}; + + +} // namespace CppUnit + +#endif // CPPUNIT_TESTFAILURE_H diff --git a/headers/tools/cppunit/cppunit/TestFixture.h b/headers/tools/cppunit/cppunit/TestFixture.h new file mode 100644 index 0000000000..eb2264b54b --- /dev/null +++ b/headers/tools/cppunit/cppunit/TestFixture.h @@ -0,0 +1,98 @@ +#ifndef CPPUNIT_TESTFIXTURE_H // -*- C++ -*- +#define CPPUNIT_TESTFIXTURE_H + +#include + +namespace CppUnit { + + +/*! \brief Wraps a test case with setUp and tearDown methods. + * \ingroup WritingTestFixture + * + * A TestFixture is used to provide a common environment for a set + * of test cases. + * + * To define a test fixture, do the following: + * - implement a subclass of TestCase + * - the fixture is defined by instance variables + * - initialize the fixture state by overriding setUp + * (i.e. construct the instance variables of the fixture) + * - clean-up after a test by overriding tearDown. + * + * Each test runs in its own fixture so there + * can be no side effects among test runs. + * Here is an example: + * + * \code + * class MathTest : public CppUnit::TestFixture { + * protected: + * int m_value1, m_value2; + * + * public: + * MathTest() {} + * + * void setUp () { + * m_value1 = 2; + * m_value2 = 3; + * } + * } + * \endcode + * + * For each test implement a method which interacts + * with the fixture. Verify the expected results with assertions specified + * by calling CPPUNIT_ASSERT on the expression you want to test: + * + * \code + * public: + * void testAdd () { + * int result = m_value1 + m_value2; + * CPPUNIT_ASSERT( result == 5 ); + * } + * \endcode + * + * Once the methods are defined you can run them. To do this, use + * a TestCaller. + * + * \code + * CppUnit::Test *test = new CppUnit::TestCaller( "testAdd", + * &MathTest::testAdd ); + * test->run(); + * \endcode + * + * + * The tests to be run can be collected into a TestSuite. + * + * \code + * public: + * static CppUnit::TestSuite *MathTest::suite () { + * CppUnit::TestSuite *suiteOfTests = new CppUnit::TestSuite; + * suiteOfTests->addTest(new CppUnit::TestCaller( + * "testAdd", &MathTest::testAdd)); + * suiteOfTests->addTest(new CppUnit::TestCaller( + * "testDivideByZero", &MathTest::testDivideByZero)); + * return suiteOfTests; + * } + * \endcode + * + * A set of macros have been created for convenience. They are located in HelperMacros.h. + * + * \see TestResult, TestSuite, TestCaller, + * \see CPPUNIT_TEST_SUB_SUITE, CPPUNIT_TEST, CPPUNIT_TEST_SUITE_END, + * \see CPPUNIT_TEST_SUITE_REGISTRATION, CPPUNIT_TEST_EXCEPTION, CPPUNIT_TEST_FAIL. + */ +class CPPUNIT_API TestFixture +{ +public: + virtual ~TestFixture() {}; + + //! \brief Set up context before running a test. + virtual void setUp() {}; + + //! Clean up after the test run. + virtual void tearDown() {}; +}; + + +} + +#endif diff --git a/headers/tools/cppunit/cppunit/TestListener.h b/headers/tools/cppunit/cppunit/TestListener.h new file mode 100644 index 0000000000..595bcb72ba --- /dev/null +++ b/headers/tools/cppunit/cppunit/TestListener.h @@ -0,0 +1,54 @@ +#ifndef CPPUNIT_TESTLISTENER_H // -*- C++ -*- +#define CPPUNIT_TESTLISTENER_H + +#include + + +namespace CppUnit { + +class Exception; +class Test; +class TestFailure; + + +/*! \brief Listener for test progress and result. + * \ingroup TrackingTestExecution + * + * Implementing the Observer pattern a TestListener may be registered + * to a TestResult to obtain information on the testing progress. Use + * specialized sub classes of TestListener for text output + * (TextTestProgressListener). Do not use the Listener for the test + * result output, use a subclass of Outputter instead. + * + * The test framework distinguishes between failures and errors. + * A failure is anticipated and checked for with assertions. Errors are + * unanticipated problems signified by exceptions that are not generated + * by the framework. + * + * \see TestResult + */ +class CPPUNIT_API TestListener +{ +public: + virtual ~TestListener() {} + + /// Called when just before a TestCase is run. + virtual void startTest( Test *test ) {} + + /*! Called when a failure occurs while running a test. + * \see TestFailure. + * \warning \a failure is a temporary object that is destroyed after the + * method call. Use TestFailure::clone() to create a duplicate. + */ + virtual void addFailure( const TestFailure &failure ) {} + + /// Called just after a TestCase was run (even if a failure occured). + virtual void endTest( Test *test ) {} +}; + + +} // namespace CppUnit + +#endif // CPPUNIT_TESTLISTENER_H + + diff --git a/headers/tools/cppunit/cppunit/TestResult.h b/headers/tools/cppunit/cppunit/TestResult.h new file mode 100644 index 0000000000..b573cf3b38 --- /dev/null +++ b/headers/tools/cppunit/cppunit/TestResult.h @@ -0,0 +1,87 @@ +#ifndef CPPUNIT_TESTRESULT_H +#define CPPUNIT_TESTRESULT_H + +#include + +#if CPPUNIT_NEED_DLL_DECL +#pragma warning( push ) +#pragma warning( disable: 4251 ) // X needs to have dll-interface to be used by clients of class Z +#endif + +#include +#include + +namespace CppUnit { + +class Exception; +class Test; +class TestFailure; +class TestListener; + +#if CPPUNIT_NEED_DLL_DECL + template class CPPUNIT_API std::deque; +#endif + +/*! \brief Manages TestListener. + * \ingroup TrackingTestExecution + * + * A single instance of this class is used when running the test. It is usually + * created by the test runner (TestRunner). + * + * This class shouldn't have to be inherited from. Use a TestListener + * or one of its subclasses to be informed of the ongoing tests. + * Use a Outputter to receive a test summary once it has finished + * + * TestResult supplies a template method 'setSynchronizationObject()' + * so that subclasses can provide mutual exclusion in the face of multiple + * threads. This can be useful when tests execute in one thread and + * they fill a subclass of TestResult which effects change in another + * thread. To have mutual exclusion, override setSynchronizationObject() + * and make sure that you create an instance of ExclusiveZone at the + * beginning of each method. + * + * \see Test, TestListener, TestResultCollector, Outputter. + */ +class CPPUNIT_API TestResult : protected SynchronizedObject +{ +public: + TestResult( SynchronizationObject *syncObject = 0 ); + virtual ~TestResult(); + + virtual void addListener( TestListener *listener ); + virtual void removeListener( TestListener *listener ); + + virtual void reset(); + virtual void stop(); + + virtual bool shouldStop() const; + + virtual void startTest( Test *test ); + virtual void addError( Test *test, Exception *e ); + virtual void addFailure( Test *test, Exception *e ); + virtual void endTest( Test *test ); + +protected: + void addFailure( const TestFailure &failure ); + +protected: + typedef std::deque TestListeners; + TestListeners m_listeners; + bool m_stop; + +private: + TestResult( const TestResult &other ); + TestResult &operator =( const TestResult &other ); +}; + + +} // namespace CppUnit + + +#if CPPUNIT_NEED_DLL_DECL +#pragma warning( pop ) +#endif + +#endif // CPPUNIT_TESTRESULT_H + + diff --git a/headers/tools/cppunit/cppunit/TestResultCollector.h b/headers/tools/cppunit/cppunit/TestResultCollector.h new file mode 100644 index 0000000000..a9cbcfe8da --- /dev/null +++ b/headers/tools/cppunit/cppunit/TestResultCollector.h @@ -0,0 +1,88 @@ +#ifndef CPPUNIT_TESTRESULTCOLLECTOR_H +#define CPPUNIT_TESTRESULTCOLLECTOR_H + +#include + +#if CPPUNIT_NEED_DLL_DECL +#pragma warning( push ) +#pragma warning( disable: 4251 ) // X needs to have dll-interface to be used by clients of class Z +#endif + +#include +#include + + +namespace CppUnit +{ + + +#if CPPUNIT_NEED_DLL_DECL + template class CPPUNIT_API std::deque; + template class CPPUNIT_API std::deque; +#endif + + +/*! \brief Collects test result. + * \ingroup WritingTestResult + * \ingroup BrowsingCollectedTestResult + * + * A TestResultCollector is a TestListener which collects the results of executing + * a test case. It is an instance of the Collecting Parameter pattern. + * + * The test framework distinguishes between failures and errors. + * A failure is anticipated and checked for with assertions. Errors are + * unanticipated problems signified by exceptions that are not generated + * by the framework. + * \see TestListener, TestFailure. + */ +class CPPUNIT_API TestResultCollector : public TestSucessListener +{ +public: + typedef std::deque TestFailures; + typedef std::deque Tests; + + + /*! Constructs a TestResultCollector object. + */ + TestResultCollector( SynchronizationObject *syncObject = 0 ); + + /// Destructor. + virtual ~TestResultCollector(); + + void startTest( Test *test ); + void addFailure( const TestFailure &failure ); + + virtual void reset(); + + virtual int runTests() const; + virtual int testErrors() const; + virtual int testFailures() const; + virtual int testFailuresTotal() const; + + virtual const TestFailures& failures() const; + virtual const Tests &tests() const; + +protected: + Tests m_tests; + TestFailures m_failures; + int m_testErrors; + +private: + /// Prevents the use of the copy constructor. + TestResultCollector( const TestResultCollector © ); + + /// Prevents the use of the copy operator. + void operator =( const TestResultCollector © ); +}; + + + +} // namespace CppUnit + + +#if CPPUNIT_NEED_DLL_DECL +#pragma warning( pop ) +#endif + + +#endif // CPPUNIT_TESTRESULTCOLLECTOR_H diff --git a/headers/tools/cppunit/cppunit/TestSucessListener.h b/headers/tools/cppunit/cppunit/TestSucessListener.h new file mode 100644 index 0000000000..51dc24833f --- /dev/null +++ b/headers/tools/cppunit/cppunit/TestSucessListener.h @@ -0,0 +1,40 @@ +#ifndef CPPUNIT_TESTSUCESSLISTENER_H +#define CPPUNIT_TESTSUCESSLISTENER_H + +#include +#include + + +namespace CppUnit +{ + +/*! \brief TestListener that checks if any test case failed. + * \ingroup TrackingTestExecution + */ +class CPPUNIT_API TestSucessListener : public TestListener, + public SynchronizedObject +{ +public: + /*! Constructs a TestSucessListener object. + */ + TestSucessListener( SynchronizationObject *syncObject = 0 ); + + /// Destructor. + virtual ~TestSucessListener(); + + virtual void reset(); + + void addFailure( const TestFailure &failure ); + + /// Returns whether the entire test was successful or not. + virtual bool wasSuccessful() const; + +private: + bool m_sucess; +}; + + +} // namespace CppUnit + + +#endif // CPPUNIT_TESTSUCESSLISTENER_H diff --git a/headers/tools/cppunit/cppunit/TestSuite.h b/headers/tools/cppunit/cppunit/TestSuite.h new file mode 100644 index 0000000000..3cd77cb853 --- /dev/null +++ b/headers/tools/cppunit/cppunit/TestSuite.h @@ -0,0 +1,77 @@ +#ifndef CPPUNIT_TESTSUITE_H // -*- C++ -*- +#define CPPUNIT_TESTSUITE_H + +#include + +#if CPPUNIT_NEED_DLL_DECL +#pragma warning( push ) +#pragma warning( disable: 4251 ) // X needs to have dll-interface to be used by clients of class Z +#endif + +#include +#include +#include + +namespace CppUnit { + +class TestResult; + +#if CPPUNIT_NEED_DLL_DECL + template class CPPUNIT_API std::vector; +#endif + + +/*! \brief A Composite of Tests. + * \ingroup CreatingTestSuite + * + * It runs a collection of test cases. Here is an example. + * \code + * CppUnit::TestSuite *suite= new CppUnit::TestSuite(); + * suite->addTest(new CppUnit::TestCaller ( + * "testAdd", testAdd)); + * suite->addTest(new CppUnit::TestCaller ( + * "testDivideByZero", testDivideByZero)); + * \endcode + * Note that TestSuites assume lifetime + * control for any tests added to them. + * + * TestSuites do not register themselves in the TestRegistry. + * \see Test + * \see TestCaller + */ + + +class CPPUNIT_API TestSuite : public Test +{ +public: + TestSuite( std::string name = "" ); + ~TestSuite(); + + void run( TestResult *result ); + int countTestCases() const; + std::string getName() const; + std::string toString() const; + + void addTest( Test *test ); + const std::vector &getTests() const; + + virtual void deleteContents(); + +private: + TestSuite( const TestSuite &other ); + TestSuite &operator =( const TestSuite &other ); + +private: + std::vector m_tests; + const std::string m_name; +}; + + +} // namespace CppUnit + + +#if CPPUNIT_NEED_DLL_DECL +#pragma warning( pop ) +#endif + +#endif // CPPUNIT_TESTSUITE_H diff --git a/headers/tools/cppunit/cppunit/TextOutputter.h b/headers/tools/cppunit/cppunit/TextOutputter.h new file mode 100644 index 0000000000..db09575a50 --- /dev/null +++ b/headers/tools/cppunit/cppunit/TextOutputter.h @@ -0,0 +1,60 @@ +#ifndef CPPUNIT_TEXTOUTPUTTER_H +#define CPPUNIT_TEXTOUTPUTTER_H + +#include +#include +#include + +namespace CppUnit +{ + +class Exception; +class SourceLine; +class TestResultCollector; +class TestFailure; + + +/*! \brief Prints a TestResultCollector to a text stream. + * \ingroup WritingTestResult + */ +class CPPUNIT_API TextOutputter : public Outputter +{ +public: + TextOutputter( TestResultCollector *result, + std::ostream &stream ); + + /// Destructor. + virtual ~TextOutputter(); + + void write(); + virtual void printFailures(); + virtual void printHeader(); + + virtual void printFailure( TestFailure *failure, + int failureNumber ); + virtual void printFailureListMark( int failureNumber ); + virtual void printFailureTestName( TestFailure *failure ); + virtual void printFailureType( TestFailure *failure ); + virtual void printFailureLocation( SourceLine sourceLine ); + virtual void printFailureDetail( Exception *thrownException ); + virtual void printFailureWarning(); + virtual void printStatistics(); + +protected: + TestResultCollector *m_result; + std::ostream &m_stream; + +private: + /// Prevents the use of the copy constructor. + TextOutputter( const TextOutputter © ); + + /// Prevents the use of the copy operator. + void operator =( const TextOutputter © ); +}; + + + +} // namespace CppUnit + + +#endif // CPPUNIT_TEXTOUTPUTTER_H diff --git a/headers/tools/cppunit/cppunit/TextTestProgressListener.h b/headers/tools/cppunit/cppunit/TextTestProgressListener.h new file mode 100644 index 0000000000..dbd22cbb49 --- /dev/null +++ b/headers/tools/cppunit/cppunit/TextTestProgressListener.h @@ -0,0 +1,43 @@ +#ifndef CPPUNIT_TEXTTESTPROGRESSLISTENER_H +#define CPPUNIT_TEXTTESTPROGRESSLISTENER_H + +#include + + +namespace CppUnit +{ + +/*! + * \brief TestListener that show the status of each TestCase test result. + * \ingroup TrackingTestExecution + */ +class CPPUNIT_API TextTestProgressListener : public TestListener +{ +public: + /*! Constructs a TextTestProgressListener object. + */ + TextTestProgressListener(); + + /// Destructor. + virtual ~TextTestProgressListener(); + + void startTest( Test *test ); + void addFailure( const TestFailure &failure ); + + void done(); + +private: + /// Prevents the use of the copy constructor. + TextTestProgressListener( const TextTestProgressListener © ); + + /// Prevents the use of the copy operator. + void operator =( const TextTestProgressListener © ); + +private: +}; + + +} // namespace CppUnit + + +#endif // CPPUNIT_TEXTTESTPROGRESSLISTENER_H diff --git a/headers/tools/cppunit/cppunit/TextTestResult.h b/headers/tools/cppunit/cppunit/TextTestResult.h new file mode 100644 index 0000000000..0e3937633f --- /dev/null +++ b/headers/tools/cppunit/cppunit/TextTestResult.h @@ -0,0 +1,56 @@ +#ifndef CPPUNIT_TEXTTESTRESULT_H +#define CPPUNIT_TEXTTESTRESULT_H + +#include +#include +#include + +namespace CppUnit { + +class SourceLine; +class Exception; +class Test; + +/*! \brief Holds printable test result (DEPRECATED). + * \ingroup TrackingTestExecution + * + * deprecated Use class TextTestProgressListener and TextOutputter instead. + */ +class CPPUNIT_API TextTestResult : public TestResult, + public TestResultCollector +{ +public: + TextTestResult(); + + virtual void addFailure( const TestFailure &failure ); + virtual void startTest( Test *test ); + virtual void print( std::ostream &stream ); + virtual void printFailures( std::ostream &stream ); + virtual void printHeader( std::ostream &stream ); + + virtual void printFailure( TestFailure *failure, + int failureNumber, + std::ostream &stream ); + virtual void printFailureListMark( int failureNumber, + std::ostream &stream ); + virtual void printFailureTestName( TestFailure *failure, + std::ostream &stream ); + virtual void printFailureType( TestFailure *failure, + std::ostream &stream ); + virtual void printFailureLocation( SourceLine sourceLine, + std::ostream &stream ); + virtual void printFailureDetail( Exception *thrownException, + std::ostream &stream ); + virtual void printFailureWarning( std::ostream &stream ); + virtual void printStatistics( std::ostream &stream ); +}; + +/** insertion operator for easy output */ +std::ostream &operator <<( std::ostream &stream, + TextTestResult &result ); + +} // namespace CppUnit + +#endif // CPPUNIT_TEXTTESTRESULT_H + + diff --git a/headers/tools/cppunit/cppunit/TextTestRunner.h b/headers/tools/cppunit/cppunit/TextTestRunner.h new file mode 100644 index 0000000000..82f2710046 --- /dev/null +++ b/headers/tools/cppunit/cppunit/TextTestRunner.h @@ -0,0 +1,17 @@ +#ifndef CPPUNIT_TEXTTESTRUNNER_H +#define CPPUNIT_TEXTTESTRUNNER_H + +#include + +namespace CppUnit { + +/*! + * \brief A text mode test runner. + * \ingroup ExecutingTest + * \deprecated Use CppUnit::TextUi::TestRunner instead. + */ +typedef CppUnit::TextUi::TestRunner TextTestRunner; + +} // namespace CppUnit + +#endif // CPPUNIT_TEXTTESTRUNNER_H diff --git a/headers/tools/cppunit/cppunit/XmlOutputter.h b/headers/tools/cppunit/cppunit/XmlOutputter.h new file mode 100644 index 0000000000..80fbcee551 --- /dev/null +++ b/headers/tools/cppunit/cppunit/XmlOutputter.h @@ -0,0 +1,136 @@ +#ifndef CPPUNIT_XMLTESTRESULTOUTPUTTER_H +#define CPPUNIT_XMLTESTRESULTOUTPUTTER_H + +#include + +#if CPPUNIT_NEED_DLL_DECL +#pragma warning( push ) +#pragma warning( disable: 4251 ) // X needs to have dll-interface to be used by clients of class Z +#endif + +#include +#include +#include +#include +#include +#include + + +namespace CppUnit +{ + +class Test; +class TestFailure; +class TestResultCollector; + + +/*! \brief Outputs a TestResultCollector in XML format. + * \ingroup WritingTestResult + */ +class CPPUNIT_API XmlOutputter : public Outputter +{ +public: + /*! Constructs a XmlOutputter object. + * \param result Result of the test run. + * \param stream Stream used to output the XML output. + * \param encoding Encoding used in the XML file (default is Latin-1). + */ + XmlOutputter( TestResultCollector *result, + std::ostream &stream, + std::string encoding = "ISO-8859-1" ); + + /// Destructor. + virtual ~XmlOutputter(); + + /*! Writes the specified result as an XML document to the stream. + * + * Refer to examples/cppunittest/XmlOutputterTest.cpp for example + * of use and XML document structure. + */ + virtual void write(); + + /*! \brief An XML Element. + * \warning This class will probably be replaced with an abstract + * builder in future version. + */ + class CPPUNIT_API Node + { + public: + Node( std::string elementName, + std::string content ="" ); + Node( std::string elementName, + int numericContent ); + virtual ~Node(); + + void addAttribute( std::string attributeName, + std::string value ); + void addAttribute( std::string attributeName, + int numericValue ); + void addNode( Node *node ); + + std::string toString() const; + + private: + typedef std::pair Attribute; + + std::string attributesAsString() const; + std::string escape( std::string value ) const; + static std::string asString( int value ); + + private: + std::string m_name; + std::string m_content; + typedef std::deque Attributes; + Attributes m_attributes; + typedef std::deque Nodes; + Nodes m_nodes; + }; + + + virtual void writeProlog(); + virtual void writeTestsResult(); + + typedef std::map FailedTests; + virtual Node *makeRootNode(); + virtual void addFailedTests( FailedTests &failedTests, + Node *rootNode ); + virtual void addSucessfulTests( FailedTests &failedTests, + Node *rootNode ); + virtual void addStatistics( Node *rootNode ); + virtual void addFailedTest( Test *test, + TestFailure *failure, + int testNumber, + Node *testsNode ); + virtual void addFailureLocation( TestFailure *failure, + Node *testNode ); + virtual void addSucessfulTest( Test *test, + int testNumber, + Node *testsNode ); +protected: + virtual void fillFailedTestsMap( FailedTests &failedTests ); + +protected: + TestResultCollector *m_result; + std::ostream &m_stream; + std::string m_encoding; + +private: + /// Prevents the use of the copy constructor. + XmlOutputter( const XmlOutputter © ); + + /// Prevents the use of the copy operator. + void operator =( const XmlOutputter © ); + +private: +}; + + + +} // namespace CppUnit + + +#if CPPUNIT_NEED_DLL_DECL +#pragma warning( pop ) +#endif + +#endif // CPPUNIT_XMLTESTRESULTOUTPUTTER_H diff --git a/headers/tools/cppunit/cppunit/config-auto.h b/headers/tools/cppunit/cppunit/config-auto.h new file mode 100644 index 0000000000..1f83a5a2fc --- /dev/null +++ b/headers/tools/cppunit/cppunit/config-auto.h @@ -0,0 +1,60 @@ +#ifndef _INCLUDE_CPPUNIT_CONFIG_AUTO_H +#define _INCLUDE_CPPUNIT_CONFIG_AUTO_H 1 + +/* include/cppunit/config-auto.h. Generated automatically at end of configure. */ +/* config/config.h. Generated automatically by configure. */ +/* config/config.h.in. Generated automatically from configure.in by autoheader. */ + +/* define if library uses std::string::compare(string,pos,n) */ +#ifndef CPPUNIT_FUNC_STRING_COMPARE_STRING_FIRST +#define CPPUNIT_FUNC_STRING_COMPARE_STRING_FIRST 1 +#endif + +/* define if the library defines strstream */ +#ifndef CPPUNIT_HAVE_CLASS_STRSTREAM +#define CPPUNIT_HAVE_CLASS_STRSTREAM 1 +#endif + +/* Define if you have the header file. */ +#ifndef CPPUNIT_HAVE_CMATH +#define CPPUNIT_HAVE_CMATH 1 +#endif + +/* Define if you have the header file. */ +/* #undef CPPUNIT_HAVE_DLFCN_H */ + +/* define to 1 if the compiler implements namespaces */ +#ifndef CPPUNIT_HAVE_NAMESPACES +#define CPPUNIT_HAVE_NAMESPACES 1 +#endif + +/* define if the compiler supports Run-Time Type Identification */ +#ifndef CPPUNIT_HAVE_RTTI +#define CPPUNIT_HAVE_RTTI 1 +#endif + +/* define if the compiler has stringstream */ +/* #undef CPPUNIT_HAVE_SSTREAM */ + +/* Define if you have the header file. */ +#ifndef CPPUNIT_HAVE_STRSTREAM +#define CPPUNIT_HAVE_STRSTREAM 1 +#endif + +/* Name of package */ +#ifndef CPPUNIT_PACKAGE +#define CPPUNIT_PACKAGE "cppunit" +#endif + +/* Define to 1 to use type_info::name() for class names */ +#ifndef CPPUNIT_USE_TYPEINFO_NAME +#define CPPUNIT_USE_TYPEINFO_NAME CPPUNIT_HAVE_RTTI +#endif + +/* Version number of package */ +#ifndef CPPUNIT_VERSION +#define CPPUNIT_VERSION "1.8.0" +#endif + +/* _INCLUDE_CPPUNIT_CONFIG_AUTO_H */ +#endif diff --git a/headers/tools/cppunit/cppunit/extensions/AutoRegisterSuite.h b/headers/tools/cppunit/cppunit/extensions/AutoRegisterSuite.h new file mode 100644 index 0000000000..8af34895a4 --- /dev/null +++ b/headers/tools/cppunit/cppunit/extensions/AutoRegisterSuite.h @@ -0,0 +1,51 @@ +#ifndef CPPUNIT_EXTENSIONS_AUTOREGISTERSUITE_H +#define CPPUNIT_EXTENSIONS_AUTOREGISTERSUITE_H + +#include +#include +#include + +namespace CppUnit { + + /** Automatically register the test suite of the specified type. + * + * You should not use this class directly. Instead, use the following macros: + * - CPPUNIT_TEST_SUITE_REGISTRATION() + * - CPPUNIT_TEST_SUITE_NAMED_REGISTRATION() + * + * This object will register the test returned by TestCaseType::suite() + * when constructed to the test registry. + * + * This object is intented to be used as a static variable. + * + * + * \param TestCaseType Type of the test case which suite is registered. + * \see CPPUNIT_TEST_SUITE_REGISTRATION, CPPUNIT_TEST_SUITE_NAMED_REGISTRATION + * \see CppUnit::TestFactoryRegistry. + */ + template + class AutoRegisterSuite + { + public: + /** Auto-register the suite factory in the global registry. + */ + AutoRegisterSuite() + { + TestFactory *factory = new TestSuiteFactory(); + TestFactoryRegistry::getRegistry().registerFactory( factory ); + } + + /** Auto-register the suite factory in the specified registry. + * \param name Name of the registry. + */ + AutoRegisterSuite( const std::string &name ) + { + TestFactory *factory = new TestSuiteFactory(); + TestFactoryRegistry::getRegistry( name ).registerFactory( factory ); + } + }; + +} // namespace CppUnit + + +#endif // CPPUNIT_EXTENSIONS_AUTOREGISTERSUITE_H diff --git a/headers/tools/cppunit/cppunit/extensions/HelperMacros.h b/headers/tools/cppunit/cppunit/extensions/HelperMacros.h new file mode 100644 index 0000000000..142cd1d7f8 --- /dev/null +++ b/headers/tools/cppunit/cppunit/extensions/HelperMacros.h @@ -0,0 +1,345 @@ +// ////////////////////////////////////////////////////////////////////////// +// Header file HelperMacros.h +// (c)Copyright 2000, Baptiste Lepilleur. +// Created: 2001/04/15 +// ////////////////////////////////////////////////////////////////////////// +#ifndef CPPUNIT_EXTENSIONS_HELPERMACROS_H +#define CPPUNIT_EXTENSIONS_HELPERMACROS_H + +#include +#include +#include +#include + +namespace CppUnit +{ + class TestFixture; + + /*! \brief Abstract TestFixture factory. + */ + class TestFixtureFactory + { + public: + //! Creates a new TestFixture instance. + virtual CppUnit::TestFixture *makeFixture() =0; + }; +} // namespace CppUnit + + +// The macro __CPPUNIT_SUITE_CTOR_ARGS expand to an expression used to construct +// the TestSuiteBuilder with macro CPPUNIT_TEST_SUITE. +// +// The name of the suite is obtained using RTTI if CPPUNIT_USE_TYPEINFO_NAME +// is defined, otherwise it is extracted from the macro parameter +// +// This macro is for cppunit internal and should not be use otherwise. +#if CPPUNIT_USE_TYPEINFO_NAME +# define __CPPUNIT_SUITE_CTOR_ARGS( ATestFixtureType ) +#else +# define __CPPUNIT_SUITE_CTOR_ARGS( ATestFixtureType ) (std::string(#ATestFixtureType)) +#endif + + +/*! \addtogroup WritingTestFixture Writing test fixture + */ +/** @{ + */ + + +/** \file + * Macros intended to ease the definition of test suites. + * + * The macros + * CPPUNIT_TEST_SUITE(), CPPUNIT_TEST(), and CPPUNIT_TEST_SUITE_END() + * are designed to facilitate easy creation of a test suite. + * For example, + * + * \code + * #include + * class MyTest : public CppUnit::TestFixture { + * CPPUNIT_TEST_SUITE( MyTest ); + * CPPUNIT_TEST( testEquality ); + * CPPUNIT_TEST( testSetName ); + * CPPUNIT_TEST_SUITE_END(); + * public: + * void testEquality(); + * void testSetName(); + * }; + * \endcode + * + * The effect of these macros is to define two methods in the + * class MyTest. The first method is an auxiliary function + * named registerTests that you will not need to call directly. + * The second function + * \code static CppUnit::TestSuite *suite()\endcode + * returns a pointer to the suite of tests defined by the CPPUNIT_TEST() + * macros. + * + * Rather than invoking suite() directly, + * the macro CPPUNIT_TEST_SUITE_REGISTRATION() is + * used to create a static variable that automatically + * registers its test suite in a global registry. + * The registry yields a Test instance containing all the + * registered suites. + * \code + * CPPUNIT_TEST_SUITE_REGISTRATION( MyTest ); + * CppUnit::Test* tp = + * CppUnit::TestFactoryRegistry::getRegistry().makeTest(); + * \endcode + * + * The test suite macros can even be used with templated test classes. + * For example: + * + * \code + * template + * class StringTest : public CppUnit::TestFixture { + * CPPUNIT_TEST_SUITE( StringTest ); + * CPPUNIT_TEST( testAppend ); + * CPPUNIT_TEST_SUITE_END(); + * public: + * ... + * }; + * \endcode + * + * You need to add in an implementation file: + * + * \code + * CPPUNIT_TEST_SUITE_REGISTRATION( StringTest ); + * CPPUNIT_TEST_SUITE_REGISTRATION( StringTest ); + * \endcode + */ + + +/*! \brief Begin test suite + * + * This macro starts the declaration of a new test suite. + * Use CPPUNIT_TEST_SUB_SUITE() instead, if you wish to include the + * test suite of the parent class. + * + * \param ATestFixtureType Type of the test case class. This type \b MUST + * be derived from TestFixture. + * \see CPPUNIT_TEST_SUB_SUITE, CPPUNIT_TEST, CPPUNIT_TEST_SUITE_END, + * \see CPPUNIT_TEST_SUITE_REGISTRATION, CPPUNIT_TEST_EXCEPTION, CPPUNIT_TEST_FAIL. + */ +#define CPPUNIT_TEST_SUITE( ATestFixtureType ) \ + private: \ + typedef ATestFixtureType __ThisTestFixtureType; \ + class ThisTestFixtureFactory : public CppUnit::TestFixtureFactory \ + { \ + virtual CppUnit::TestFixture *makeFixture() \ + { \ + return new ATestFixtureType(); \ + } \ + }; \ + public: \ + static void \ + registerTests( CppUnit::TestSuite *suite, \ + CppUnit::TestFixtureFactory *factory ) \ + { \ + CppUnit::TestSuiteBuilder<__ThisTestFixtureType> builder( suite ); + + +/*! \brief Begin test suite (includes parent suite) + * + * This macro may only be used in a class whose parent class + * defines a test suite using CPPUNIT_TEST_SUITE() or CPPUNIT_TEST_SUB_SUITE(). + * + * This macro begins the declaration of a test suite, in the same + * manner as CPPUNIT_TEST_SUITE(). In addition, the test suite of the + * parent is automatically inserted in the test suite being + * defined. + * + * Here is an example: + * + * \code + * #include + * class MySubTest : public MyTest { + * CPPUNIT_TEST_SUB_SUITE( MySubTest, MyTest ); + * CPPUNIT_TEST( testAdd ); + * CPPUNIT_TEST( testSub ); + * CPPUNIT_TEST_SUITE_END(); + * public: + * void testAdd(); + * void testSub(); + * }; + * \endcode + * + * \param ATestFixtureType Type of the test case class. This type \b MUST + * be derived from TestFixture. + * \param ASuperClass Type of the parent class. + * \see CPPUNIT_TEST_SUITE. + */ +#define CPPUNIT_TEST_SUB_SUITE( ATestFixtureType, ASuperClass ) \ + private: \ + typedef ASuperClass __ThisSuperClassType; \ + CPPUNIT_TEST_SUITE( ATestFixtureType ); \ + __ThisSuperClassType::registerTests( suite, factory ) + + +/*! \brief Add a method to the suite. + * \param testMethod Name of the method of the test case to add to the + * suite. The signature of the method must be of + * type: void testMethod(); + * \see CPPUNIT_TEST_SUITE. + */ +#define CPPUNIT_TEST( testMethod ) \ + builder.addTestCaller( #testMethod, \ + &__ThisTestFixtureType::testMethod , \ + (__ThisTestFixtureType*)factory->makeFixture() ) + + +/*! \brief Add a test which fail if the specified exception is not caught. + * + * Example: + * \code + * #include + * #include + * class MyTest : public CppUnit::TestFixture { + * CPPUNIT_TEST_SUITE( MyTest ); + * CPPUNIT_TEST_EXCEPTION( testVectorAtThrow, std::invalid_argument ); + * CPPUNIT_TEST_SUITE_END(); + * public: + * void testVectorAtThrow() + * { + * std::vector v; + * v.at( 1 ); // must throw exception std::invalid_argument + * } + * }; + * \endcode + * + * \param testMethod Name of the method of the test case to add to the suite. + * \param ExceptionType Type of the exception that must be thrown by the test + * method. + */ +#define CPPUNIT_TEST_EXCEPTION( testMethod, ExceptionType ) \ + builder.addTestCallerForException( #testMethod, \ + &__ThisTestFixtureType::testMethod , \ + (__ThisTestFixtureType*)factory->makeFixture(), \ + (ExceptionType *)NULL ); + +/*! \brief Adds a test case which is excepted to fail. + * + * The added test case expect an assertion to fail. You usually used that type + * of test case when testing custom assertion macros. + * + * \code + * CPPUNIT_TEST_FAIL( testAssertFalseFail ); + * + * void testAssertFalseFail() + * { + * CPPUNIT_ASSERT( false ); + * } + * \endcode + * \see CreatingNewAssertions. + */ +#define CPPUNIT_TEST_FAIL( testMethod ) \ + CPPUNIT_TEST_EXCEPTION( testMethod, CppUnit::Exception ) + +/*! \brief End declaration of the test suite. + * + * After this macro, member access is set to "private". + * + * \see CPPUNIT_TEST_SUITE. + * \see CPPUNIT_TEST_SUITE_REGISTRATION. + */ +#define CPPUNIT_TEST_SUITE_END() \ + builder.takeSuite(); \ + } \ + static CppUnit::TestSuite *suite() \ + { \ + CppUnit::TestSuiteBuilder<__ThisTestFixtureType> \ + builder __CPPUNIT_SUITE_CTOR_ARGS( ATestFixtureType ); \ + ThisTestFixtureFactory factory; \ + __ThisTestFixtureType::registerTests( builder.suite(), &factory ); \ + return builder.takeSuite(); \ + } \ + private: /* dummy typedef so that the macro can still end with ';'*/ \ + typedef ThisTestFixtureFactory __ThisTestFixtureFactory + +/** @} + */ + +#define __CPPUNIT_CONCATENATE_DIRECT( s1, s2 ) s1##s2 +#define __CPPUNIT_CONCATENATE( s1, s2 ) __CPPUNIT_CONCATENATE_DIRECT( s1, s2 ) + +/** Decorates the specified string with the line number to obtain a unique name; + * @param str String to decorate. + */ +#define __CPPUNIT_MAKE_UNIQUE_NAME( str ) __CPPUNIT_CONCATENATE( str, __LINE__ ) + + +/** Adds the specified fixture suite to the unnamed registry. + * \ingroup CreatingTestSuite + * + * This macro declares a static variable whose construction + * causes a test suite factory to be inserted in a global registry + * of such factories. The registry is available by calling + * the static function CppUnit::TestFactoryRegistry::getRegistry(). + * + * \param ATestFixtureType Type of the test case class. + * \warning This macro should be used only once per line of code (the line + * number is used to name a hidden static variable). + * \see CPPUNIT_TEST_SUITE_NAMED_REGISTRATION + * \see CPPUNIT_TEST_SUITE, CppUnit::AutoRegisterSuite, + * CppUnit::TestFactoryRegistry. + */ +#define CPPUNIT_TEST_SUITE_REGISTRATION( ATestFixtureType ) \ + static CppUnit::AutoRegisterSuite< ATestFixtureType > \ + __CPPUNIT_MAKE_UNIQUE_NAME(__autoRegisterSuite ) + + +/** Adds the specified fixture suite to the specified registry suite. + * \ingroup CreatingTestSuite + * + * This macro declares a static variable whose construction + * causes a test suite factory to be inserted in the global registry + * suite of the specified name. The registry is available by calling + * the static function CppUnit::TestFactoryRegistry::getRegistry(). + * + * For the suite name, use a string returned by a static function rather + * than a hardcoded string. That way, you can know what are the name of + * named registry and you don't risk mistyping the registry name. + * + * \code + * // MySuites.h + * namespace MySuites { + * std::string math() { + * return "Math"; + * } + * } + * + * // ComplexNumberTest.cpp + * #include "MySuites.h" + * + * CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( ComplexNumberTest, MySuites::math() ); + * \endcode + * + * \param ATestFixtureType Type of the test case class. + * \param suiteName Name of the global registry suite the test suite is + * registered into. + * \warning This macro should be used only once per line of code (the line + * number is used to name a hidden static variable). + * \see CPPUNIT_TEST_SUITE_REGISTRATION + * \see CPPUNIT_TEST_SUITE, CppUnit::AutoRegisterSuite, + * CppUnit::TestFactoryRegistry.. + */ +#define CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( ATestFixtureType, suiteName ) \ + static CppUnit::AutoRegisterSuite< ATestFixtureType > \ + __CPPUNIT_MAKE_UNIQUE_NAME(__autoRegisterSuite )(suiteName) + + +// Backwards compatibility +// (Not tested!) + +#if CPPUNIT_ENABLE_CU_TEST_MACROS + +#define CU_TEST_SUITE(tc) CPPUNIT_TEST_SUITE(tc) +#define CU_TEST_SUB_SUITE(tc,sc) CPPUNIT_TEST_SUB_SUITE(tc,sc) +#define CU_TEST(tm) CPPUNIT_TEST(tm) +#define CU_TEST_SUITE_END() CPPUNIT_TEST_SUITE_END() +#define CU_TEST_SUITE_REGISTRATION(tc) CPPUNIT_TEST_SUITE_REGISTRATION(tc) + +#endif + + +#endif // CPPUNIT_EXTENSIONS_HELPERMACROS_H diff --git a/headers/tools/cppunit/cppunit/extensions/Orthodox.h b/headers/tools/cppunit/cppunit/extensions/Orthodox.h new file mode 100644 index 0000000000..69eb5c63ac --- /dev/null +++ b/headers/tools/cppunit/cppunit/extensions/Orthodox.h @@ -0,0 +1,94 @@ +#ifndef CPPUNIT_EXTENSIONS_ORTHODOX_H +#define CPPUNIT_EXTENSIONS_ORTHODOX_H + +#include + +namespace CppUnit { + +/* + * Orthodox performs a simple set of tests on an arbitary + * class to make sure that it supports at least the + * following operations: + * + * default construction - constructor + * equality/inequality - operator== && operator!= + * assignment - operator= + * negation - operator! + * safe passage - copy construction + * + * If operations for each of these are not declared + * the template will not instantiate. If it does + * instantiate, tests are performed to make sure + * that the operations have correct semantics. + * + * Adding an orthodox test to a suite is very + * easy: + * + * public: Test *suite () { + * TestSuite *suiteOfTests = new TestSuite; + * suiteOfTests->addTest (new ComplexNumberTest ("testAdd"); + * suiteOfTests->addTest (new TestCaller > ()); + * return suiteOfTests; + * } + * + * Templated test cases be very useful when you are want to + * make sure that a group of classes have the same form. + * + * see TestSuite + */ + + +template class Orthodox : public TestCase +{ +public: + Orthodox () : TestCase ("Orthodox") {} + +protected: + ClassUnderTest call (ClassUnderTest object); + void runTest (); + + +}; + + +// Run an orthodoxy test +template void Orthodox::runTest () +{ + // make sure we have a default constructor + ClassUnderTest a, b, c; + + // make sure we have an equality operator + CPPUNIT_ASSERT (a == b); + + // check the inverse + b.operator= (a.operator! ()); + CPPUNIT_ASSERT (a != b); + + // double inversion + b = !!a; + CPPUNIT_ASSERT (a == b); + + // invert again + b = !a; + + // check calls + c = a; + CPPUNIT_ASSERT (c == call (a)); + + c = b; + CPPUNIT_ASSERT (c == call (b)); + +} + + +// Exercise a call +template +ClassUnderTest Orthodox::call (ClassUnderTest object) +{ + return object; +} + +} // namespace CppUnit + +#endif + diff --git a/headers/tools/cppunit/cppunit/extensions/RepeatedTest.h b/headers/tools/cppunit/cppunit/extensions/RepeatedTest.h new file mode 100644 index 0000000000..067fd20da6 --- /dev/null +++ b/headers/tools/cppunit/cppunit/extensions/RepeatedTest.h @@ -0,0 +1,40 @@ +#ifndef CPPUNIT_EXTENSIONS_REPEATEDTEST_H +#define CPPUNIT_EXTENSIONS_REPEATEDTEST_H + +#include +#include + +namespace CppUnit { + +class Test; +class TestResult; + + +/*! \brief Decorator that runs a test repeatedly. + * + * Does not assume ownership of the test it decorates + */ +class CPPUNIT_API RepeatedTest : public TestDecorator +{ +public: + RepeatedTest( Test *test, + int timesRepeat ) : + TestDecorator( test ), + m_timesRepeat(timesRepeat) {} + + void run( TestResult *result ); + int countTestCases() const; + std::string toString() const; + +private: + RepeatedTest( const RepeatedTest & ); + void operator=( const RepeatedTest & ); + + const int m_timesRepeat; +}; + + + +} // namespace CppUnit + +#endif // CPPUNIT_EXTENSIONS_REPEATEDTEST_H diff --git a/headers/tools/cppunit/cppunit/extensions/TestDecorator.h b/headers/tools/cppunit/cppunit/extensions/TestDecorator.h new file mode 100644 index 0000000000..c3dc34329f --- /dev/null +++ b/headers/tools/cppunit/cppunit/extensions/TestDecorator.h @@ -0,0 +1,66 @@ +#ifndef CPPUNIT_EXTENSIONS_TESTDECORATOR_H +#define CPPUNIT_EXTENSIONS_TESTDECORATOR_H + +#include +#include + +namespace CppUnit { + +class TestResult; + + +/*! \brief Decorator for Tests. + * + * TestDecorator provides an alternate means to extend functionality + * of a test class without subclassing the test. Instead, one can + * subclass the decorater and use it to wrap the test class. + * + * Does not assume ownership of the test it decorates + */ +class CPPUNIT_API TestDecorator : public Test +{ +public: + TestDecorator (Test *test); + ~TestDecorator (); + + void run (TestResult *result); + int countTestCases () const; + std::string getName () const; + std::string toString () const; + +protected: + Test *m_test; + +private: + TestDecorator( const TestDecorator &); + void operator =( const TestDecorator & ); +}; + + +inline TestDecorator::TestDecorator (Test *test) +{ m_test = test; } + + +inline TestDecorator::~TestDecorator () +{} + + +inline int TestDecorator::countTestCases () const +{ return m_test->countTestCases (); } + + +inline void TestDecorator::run (TestResult *result) +{ m_test->run (result); } + + +inline std::string TestDecorator::toString () const +{ return m_test->toString (); } + + +inline std::string TestDecorator::getName () const +{ return m_test->getName(); } + +} // namespace CppUnit + +#endif + diff --git a/headers/tools/cppunit/cppunit/extensions/TestFactory.h b/headers/tools/cppunit/cppunit/extensions/TestFactory.h new file mode 100644 index 0000000000..3a964b6fcc --- /dev/null +++ b/headers/tools/cppunit/cppunit/extensions/TestFactory.h @@ -0,0 +1,25 @@ +#ifndef CPPUNIT_EXTENSIONS_TESTFACTORY_H +#define CPPUNIT_EXTENSIONS_TESTFACTORY_H + +#include + +namespace CppUnit { + +class Test; + +/*! \brief Abstract Test factory. + */ +class CPPUNIT_API TestFactory +{ +public: + virtual ~TestFactory() {} + + /*! Makes a new test. + * \return A new Test. + */ + virtual Test* makeTest() = 0; +}; + +} // namespace CppUnit + +#endif // CPPUNIT_EXTENSIONS_TESTFACTORY_H diff --git a/headers/tools/cppunit/cppunit/extensions/TestFactoryRegistry.h b/headers/tools/cppunit/cppunit/extensions/TestFactoryRegistry.h new file mode 100644 index 0000000000..6553fe5742 --- /dev/null +++ b/headers/tools/cppunit/cppunit/extensions/TestFactoryRegistry.h @@ -0,0 +1,148 @@ +#ifndef CPPUNIT_EXTENSIONS_TESTFACTORYREGISTRY_H +#define CPPUNIT_EXTENSIONS_TESTFACTORYREGISTRY_H + +#include + +#if CPPUNIT_NEED_DLL_DECL +#pragma warning( push ) +#pragma warning( disable: 4251 ) // X needs to have dll-interface to be used by clients of class Z +#endif + +#include +#include +#include + +namespace CppUnit { + +class TestSuite; + +#if CPPUNIT_NEED_DLL_DECL + template class CPPUNIT_API std::map; +#endif + + +/*! \brief Registry for TestFactory. + * \ingroup CreatingTestSuite + * + * Notes that the registry assumes lifetime control for any registered test. + * + * To register tests, use the macros: + * - CPPUNIT_TEST_SUITE_REGISTRATION(): to add tests in the unnamed registry. + * - CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(): to add tests in a named registry. + * + * Example 1: retreiving a suite that contains all the test registered with + * CPPUNIT_TEST_SUITE_REGISTRATION(). + * \code + * CppUnit::TestFactoryRegistry ®istry = CppUnit::TestFactoryRegistry::getRegistry(); + * CppUnit::TestSuite *suite = registry.makeTest(); + * \endcode + * + * Example 2: retreiving a suite that contains all the test registered with + * \link CPPUNIT_TEST_SUITE_NAMED_REGISTRATION() CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( ..., "Math" )\endlink. + * \code + * CppUnit::TestFactoryRegistry &mathRegistry = CppUnit::TestFactoryRegistry::getRegistry( "Math" ); + * CppUnit::TestSuite *mathSuite = mathRegistry.makeTest(); + * \endcode + * + * Example 3: creating a test suite hierarchy composed of unnamed registration and + * named registration: + * - All Tests + * - tests registered with CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( ..., "Graph" ) + * - tests registered with CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( ..., "Math" ) + * - tests registered with CPPUNIT_TEST_SUITE_REGISTRATION + * + * \code + * CppUnit::TestSuite *rootSuite = new CppUnit::TestSuite( "All tests" ); + * rootSuite->addTest( CppUnit::TestFactoryRegistry::getRegistry( "Graph" ).makeTest() ); + * rootSuite->addTest( CppUnit::TestFactoryRegistry::getRegistry( "Math" ).makeTest() ); + * CppUnit::TestFactoryRegistry::getRegistry().addTestToSuite( rootSuite ); + * \endcode + * + * The same result can be obtained with: + * \code + * CppUnit::TestFactoryRegistry ®istry = CppUnit::TestFactoryRegistry::getRegistry(); + * registry.registerFactory( CppUnit::TestFactoryRegistry::getRegistry( "Graph" ) ); + * registry.registerFactory( CppUnit::TestFactoryRegistry::getRegistry( "Math" ) ); + * CppUnit::TestSuite *suite = registry.makeTest(); + * \endcode + * + * Since a TestFactoryRegistry is a TestFactory, the named registries can be + * registered in the unnamed registry, creating the hierarchy links. + * + * \see TestSuiteFactory, AutoRegisterSuite + * \see CPPUNIT_TEST_SUITE_REGISTRATION, CPPUNIT_TEST_SUITE_NAMED_REGISTRATION + */ +class CPPUNIT_API TestFactoryRegistry : public TestFactory +{ +public: + /** Constructs the registry with the specified name. + * \param name Name of the registry. It is the name of TestSuite returned by + * makeTest(). + */ + TestFactoryRegistry( std::string name = "All Tests" ); + + /// Destructor. + virtual ~TestFactoryRegistry(); + + /** Returns a new TestSuite that contains the registered test. + * \return A new TestSuite which contains all the test added using + * registerFactory(TestFactory *). + */ + virtual Test *makeTest(); + + /** Returns unnamed the registry. + * TestSuite registered using CPPUNIT_TEST_SUITE_REGISTRATION() are registered + * in this registry. + * \return Registry which name is "All Tests". + */ + static TestFactoryRegistry &getRegistry(); + + /** Returns a named registry. + * TestSuite registered using CPPUNIT_TEST_SUITE_NAMED_REGISTRATION() are registered + * in the registry of the same name. + * \param name Name of the registry to return. + * \return Registry. If the registry does not exist, it is created with the + * specified name. + */ + static TestFactoryRegistry &getRegistry( const std::string &name ); + + /** Adds the registered tests to the specified suite. + * \param suite Suite the tests are added to. + */ + void addTestToSuite( TestSuite *suite ); + + /** Adds the specified TestFactory with a specific name (DEPRECATED). + * \param name Name associated to the factory. + * \param factory Factory to register. + * \deprecated Use registerFactory( TestFactory *) instead. + */ + void registerFactory( const std::string &name, + TestFactory *factory ); + + /** Adds the specified TestFactory to the registry. + * + * \param factory Factory to register. + */ + void registerFactory( TestFactory *factory ); + +private: + TestFactoryRegistry( const TestFactoryRegistry © ); + void operator =( const TestFactoryRegistry © ); + +private: + typedef std::map Factories; + Factories m_factories; + + std::string m_name; +}; + + +} // namespace CppUnit + + +#if CPPUNIT_NEED_DLL_DECL +#pragma warning( pop ) +#endif + + +#endif // CPPUNIT_EXTENSIONS_TESTFACTORYREGISTRY_H diff --git a/headers/tools/cppunit/cppunit/extensions/TestSetUp.h b/headers/tools/cppunit/cppunit/extensions/TestSetUp.h new file mode 100644 index 0000000000..0fe26638c9 --- /dev/null +++ b/headers/tools/cppunit/cppunit/extensions/TestSetUp.h @@ -0,0 +1,32 @@ +#ifndef CPPUNIT_EXTENSIONS_TESTSETUP_H +#define CPPUNIT_EXTENSIONS_TESTSETUP_H + +#include + +namespace CppUnit { + +class Test; +class TestResult; + + +class CPPUNIT_API TestSetUp : public TestDecorator +{ +public: + TestSetUp( Test *test ); + + void run( TestResult *result ); + +protected: + virtual void setUp(); + virtual void tearDown(); + +private: + TestSetUp( const TestSetUp & ); + void operator =( const TestSetUp & ); +}; + + +} // namespace CppUnit + +#endif // CPPUNIT_EXTENSIONS_TESTSETUP_H + diff --git a/headers/tools/cppunit/cppunit/extensions/TestSuiteBuilder.h b/headers/tools/cppunit/cppunit/extensions/TestSuiteBuilder.h new file mode 100644 index 0000000000..1f3e028747 --- /dev/null +++ b/headers/tools/cppunit/cppunit/extensions/TestSuiteBuilder.h @@ -0,0 +1,105 @@ +#ifndef CPPUNIT_EXTENSIONS_TESTSUITEBUILDER_H +#define CPPUNIT_EXTENSIONS_TESTSUITEBUILDER_H + +#include +#include +#include +#include + +#if CPPUNIT_USE_TYPEINFO_NAME +# include +#endif + +namespace CppUnit { + + /*! \brief Helper to add tests to a TestSuite. + * \ingroup WritingTestFixture + * + * All tests added to the TestSuite are prefixed by TestSuite name. The resulting + * TestCase name has the following pattern: + * + * MyTestSuiteName.myTestName + */ + template + class TestSuiteBuilder + { + public: + typedef void (Fixture::*TestMethod)(); + +#if CPPUNIT_USE_TYPEINFO_NAME + TestSuiteBuilder() : + m_suite( new TestSuite( + TypeInfoHelper::getClassName( typeid(Fixture) ) ) ) + { + } +#endif + + TestSuiteBuilder( TestSuite *suite ) : m_suite( suite ) + { + } + + TestSuiteBuilder(std::string name) : m_suite( new TestSuite(name) ) + { + } + + TestSuite *suite() const + { + return m_suite.get(); + } + + TestSuite *takeSuite() + { + return m_suite.release(); + } + + void addTest( Test *test ) + { + m_suite->addTest( test ); + } + + void addTestCaller( std::string methodName, + TestMethod testMethod ) + { + Test *test = + new TestCaller( makeTestName( methodName ), + testMethod ); + addTest( test ); + } + + void addTestCaller( std::string methodName, + TestMethod testMethod, + Fixture *fixture ) + { + Test *test = + new TestCaller( makeTestName( methodName ), + testMethod, + fixture); + addTest( test ); + } + + template + void addTestCallerForException( std::string methodName, + TestMethod testMethod, + Fixture *fixture, + ExceptionType *dummyPointer ) + { + Test *test = new TestCaller( + makeTestName( methodName ), + testMethod, + fixture); + addTest( test ); + } + + + std::string makeTestName( const std::string &methodName ) + { + return m_suite->getName() + "." + methodName; + } + + private: + std::auto_ptr m_suite; + }; + +} // namespace CppUnit + +#endif // CPPUNIT_EXTENSIONS_TESTSUITEBUILDER_H diff --git a/headers/tools/cppunit/cppunit/extensions/TestSuiteFactory.h b/headers/tools/cppunit/cppunit/extensions/TestSuiteFactory.h new file mode 100644 index 0000000000..567812d53d --- /dev/null +++ b/headers/tools/cppunit/cppunit/extensions/TestSuiteFactory.h @@ -0,0 +1,25 @@ +#ifndef CPPUNIT_EXTENSIONS_TESTSUITEFACTORY_H +#define CPPUNIT_EXTENSIONS_TESTSUITEFACTORY_H + +#include + +namespace CppUnit { + + class Test; + + /*! \brief TestFactory for TestFixture that implements a static suite() method. + * \see AutoRegisterSuite. + */ + template + class TestSuiteFactory : public TestFactory + { + public: + virtual Test *makeTest() + { + return TestCaseType::suite(); + } + }; + +} // namespace CppUnit + +#endif // CPPUNIT_EXTENSIONS_TESTSUITEFACTORY_H diff --git a/headers/tools/cppunit/cppunit/extensions/TypeInfoHelper.h b/headers/tools/cppunit/cppunit/extensions/TypeInfoHelper.h new file mode 100644 index 0000000000..5199a705ed --- /dev/null +++ b/headers/tools/cppunit/cppunit/extensions/TypeInfoHelper.h @@ -0,0 +1,31 @@ +#ifndef CPPUNIT_TYPEINFOHELPER_H +#define CPPUNIT_TYPEINFOHELPER_H + +#include + +#if CPPUNIT_USE_TYPEINFO_NAME + +#include + + +namespace CppUnit { + + /** Helper to use type_info. + */ + class CPPUNIT_API TypeInfoHelper + { + public: + /** Get the class name of the specified type_info. + * \param info Info which the class name is extracted from. + * \return The string returned by type_info::name() without + * the "class" prefix. If the name is not prefixed + * by "class", it is returned as this. + */ + static std::string getClassName( const std::type_info &info ); + }; + +} // namespace CppUnit + +#endif + +#endif // CPPUNIT_TYPEINFOHELPER_H diff --git a/headers/tools/cppunit/cppunit/ui/text/TestRunner.h b/headers/tools/cppunit/cppunit/ui/text/TestRunner.h new file mode 100644 index 0000000000..6bfa6c9d17 --- /dev/null +++ b/headers/tools/cppunit/cppunit/ui/text/TestRunner.h @@ -0,0 +1,103 @@ +#ifndef CPPUNITUI_TEXT_TESTRUNNER_H +#define CPPUNITUI_TEXT_TESTRUNNER_H + +#include +#include +#include + +namespace CppUnit { + +class Outputter; +class Test; +class TestSuite; +class TextOutputter; +class TestResult; +class TestResultCollector; + +namespace TextUi +{ + +/*! + * \brief A text mode test runner. + * \ingroup WritingTestResult + * \ingroup ExecutingTest + * + * The test runner manage the life cycle of the added tests. + * + * The test runner can run only one of the added tests or all the tests. + * + * TestRunner prints out a trace as the tests are executed followed by a + * summary at the end. The trace and summary print are optional. + * + * Here is an example of use: + * + * \code + * CppUnit::TextUi::TestRunner runner; + * runner.addTest( ExampleTestCase::suite() ); + * runner.run( "", true ); // Run all tests and wait + * \endcode + * + * The trace is printed using a TextTestProgressListener. The summary is printed + * using a TextOutputter. + * + * You can specify an alternate Outputter at construction + * or later with setOutputter(). + * + * After construction, you can register additional TestListener to eventManager(), + * for a custom progress trace, for example. + * + * \code + * CppUnit::TextUi::TestRunner runner; + * runner.addTest( ExampleTestCase::suite() ); + * runner.setOutputter( CppUnit::CompilerOutputter::defaultOutputter( + * &runner.result(), + * std::cerr ) ); + * MyCustomProgressTestListener progress; + * runner.eventManager().addListener( &progress ); + * runner.run( "", true ); // Run all tests and wait + * \endcode + * + * \see CompilerOutputter, XmlOutputter, TextOutputter. + */ +class CPPUNIT_API TestRunner +{ +public: + TestRunner( Outputter *outputter =NULL ); + + virtual ~TestRunner(); + + bool run( std::string testName ="", + bool doWait = false, + bool doPrintResult = true, + bool doPrintProgress = true ); + + void addTest( Test *test ); + + void setOutputter( Outputter *outputter ); + + TestResultCollector &result() const; + + TestResult &eventManager() const; + +protected: + virtual bool runTest( Test *test, + bool doPrintProgress ); + virtual bool runTestByName( std::string testName, + bool printProgress ); + virtual void wait( bool doWait ); + virtual void printResult( bool doPrintResult ); + + virtual Test *findTestByName( std::string name ) const; + + TestSuite *m_suite; + TestResultCollector *m_result; + TestResult *m_eventManager; + Outputter *m_outputter; +}; + + +} // namespace TextUi + +} // namespace CppUnit + +#endif // CPPUNITUI_TEXT_TESTRUNNER_H diff --git a/src/add-ons/input_server/filters/screensaver/SSInputFilter.cpp b/src/add-ons/input_server/filters/screensaver/SSInputFilter.cpp new file mode 100644 index 0000000000..0ecec20b23 --- /dev/null +++ b/src/add-ons/input_server/filters/screensaver/SSInputFilter.cpp @@ -0,0 +1,82 @@ +#include "SSInputFilter.h" +#include "Messenger.h" +#include "OS.h" + +extern "C" _EXPORT BInputServerFilter* instantiate_input_filter(); + +SSISFilter::SSISFilter() +{ + first=real_time_clock(); + enabled=false; + ssApp=NULL; +} + +BInputServerFilter* instantiate_input_filter() +{ + return (new SSISFilter()); +} + +void SSISFilter::UpdateRectangles(void) +{ + BRegion region; + BRect frame; + GetScreenRegion(®ion); + frame=region.Frame(); + + topLeft.Set(frame.left,frame.top,frame.left+CORNER_SIZE,frame.top+CORNER_SIZE); + topRight.Set(frame.right-CORNER_SIZE,frame.top,frame.right,frame.top+CORNER_SIZE); + bottomLeft.Set(frame.left,frame.bottom-CORNER_SIZE,frame.left+CORNER_SIZE,frame.bottom); + bottomRight.Set(frame.right-CORNER_SIZE,frame.bottom-CORNER_SIZE,frame.right,frame.bottom); +} + +void SSISFilter::Cornered(cornerPos pos) +{ + static cornerPos oldPos; + if (oldPos!=pos) + enabled=(B_OK == ssApp->SendMessage((int32)(pos))); + oldPos=pos; +} + +filter_result SSISFilter::Filter(BMessage *msg,BList *outList) +{ + status_t err; + if (msg->what==B_SCREEN_CHANGED) + UpdateRectangles(); + else if (enabled && msg->what==B_MOUSE_MOVED) + { + BPoint pos; + msg->FindPoint("where",&pos); + if (topLeft.Contains(pos)) + Cornered(TOPL); + else if (topRight.Contains(pos)) + Cornered(TOPR); + else if (bottomLeft.Contains(pos)) + Cornered(BOTL); + else if (bottomRight.Contains(pos)) + Cornered(BOTR); + else + Cornered(MIDDLE); + } + if (real_time_clock()>first+4) // Only check every 5 seconds or so + { + if (!enabled) + { + delete ssApp; + ssApp=new BMessenger("application/x-vnd.OBOS-ScreenSaverApp",-1,&err); + if (err==B_OK) + { + enabled=true; + UpdateRectangles(); + } + } + + if (enabled) + enabled=(B_OK == ssApp->SendMessage('INPT')); + first=real_time_clock(); + } +} + +SSISFilter::~SSISFilter() +{ + ; +} diff --git a/src/add-ons/input_server/filters/screensaver/SSInputFilter.h b/src/add-ons/input_server/filters/screensaver/SSInputFilter.h new file mode 100644 index 0000000000..d2c545e346 --- /dev/null +++ b/src/add-ons/input_server/filters/screensaver/SSInputFilter.h @@ -0,0 +1,23 @@ +#include "InputServerFilter.h" +#include "Rect.h" +#include "Region.h" + +const int CORNER_SIZE=10; + +class SSISFilter: public BInputServerFilter +{ +public: + SSISFilter(); + virtual ~SSISFilter(); + virtual filter_result Filter(BMessage *msg, BList *outList); +private: + uint32 first; + bool enabled; + BMessenger *ssApp; + BRect topLeft,topRight,bottomLeft,bottomRight; + //enum cornerPos {MIDDLE=(int32)'ENDC',TOPL=(int32)'TOPL',TOPR=(int32)'TOPR',BOTL=(int32)'BOTL',BOTR=(int32)'BOTR'}; + enum cornerPos {MIDDLE='ENDC',TOPL='TOPL',TOPR='TOPR',BOTL='BOTL',BOTR='BOTR'}; + void UpdateRectangles(void); + void Cornered(cornerPos pos); +}; + diff --git a/src/add-ons/kernel/file_systems/befs/BPlusTree.cpp b/src/add-ons/kernel/file_systems/befs/BPlusTree.cpp new file mode 100644 index 0000000000..ed651db33e --- /dev/null +++ b/src/add-ons/kernel/file_systems/befs/BPlusTree.cpp @@ -0,0 +1,2053 @@ +/* BPlusTree - BFS B+Tree implementation +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** Roughly based on 'btlib' written by Marcus J. Ranum +** +** Copyright (c) 2001-2002 pinc Software. All Rights Reserved. +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include "Debug.h" +#include "cpp.h" +#include "BPlusTree.h" +#include "Inode.h" +#include "Utility.h" +#include "Stack.h" + +#include + +#include +#include +#include + + +// Node Caching for the BPlusTree class +// +// With write support, there is the need for a function that allocates new +// nodes by either returning empty nodes, or by growing the file's data stream +// +// !! The CachedNode class assumes that you have properly locked the stream +// !! before asking for nodes. +// +// Note: This code will fail if the block size is smaller than the node size! +// Since BFS supports block sizes of 1024 bytes or greater, and the node size +// is hard-coded to 1024 bytes, that's not an issue now. + +void +CachedNode::Unset() +{ + if (fTree == NULL || fTree->fStream == NULL) + return; + + if (fBlock != NULL) { + release_block(fTree->fStream->GetVolume()->Device(),fBlockNumber); + + fBlock = NULL; + fNode = NULL; + } +} + + +bplustree_node * +CachedNode::SetTo(off_t offset,bool check) +{ + if (fTree == NULL || fTree->fStream == NULL) { + REPORT_ERROR(B_BAD_VALUE); + return NULL; + } + + Unset(); + + // You can only ask for nodes at valid positions - you can't + // even access the b+tree header with this method (use SetToHeader() + // instead) + if (offset > fTree->fHeader->maximum_size - fTree->fNodeSize + || offset <= 0 + || (offset % fTree->fNodeSize) != 0) + return NULL; + + if (InternalSetTo(offset) != NULL && check) { + // sanity checks (links, all_key_count) + bplustree_header *header = fTree->fHeader; + if (!header->IsValidLink(fNode->left_link) + || !header->IsValidLink(fNode->right_link) + || !header->IsValidLink(fNode->overflow_link) + || (int8 *)fNode->Values() + fNode->all_key_count * sizeof(off_t) > + (int8 *)fNode + fTree->fNodeSize) { + FATAL(("invalid node read from offset %Ld, inode at %Ld\n", + offset,fTree->fStream->ID())); + return NULL; + } + } + return fNode; +} + + +bplustree_header * +CachedNode::SetToHeader() +{ + if (fTree == NULL || fTree->fStream == NULL) { + REPORT_ERROR(B_BAD_VALUE); + return NULL; + } + + Unset(); + + InternalSetTo(0LL); + return (bplustree_header *)fNode; +} + + +bplustree_node * +CachedNode::InternalSetTo(off_t offset) +{ + fNode = NULL; + + off_t fileOffset; + block_run run; + if (offset < fTree->fStream->Size() + && fTree->fStream->FindBlockRun(offset,run,fileOffset) == B_OK) { + Volume *volume = fTree->fStream->GetVolume(); + + int32 blockOffset = (offset - fileOffset) / volume->BlockSize(); + fBlockNumber = volume->ToBlock(run) + blockOffset; + + fBlock = (uint8 *)get_block(volume->Device(),fBlockNumber,volume->BlockSize()); + if (fBlock) { + // the node is somewhere in that block... (confusing offset calculation) + fNode = (bplustree_node *)(fBlock + offset - + (fileOffset + blockOffset * volume->BlockSize())); + } else + REPORT_ERROR(B_IO_ERROR); + } + return fNode; +} + + +status_t +CachedNode::Free(Transaction *transaction,off_t offset) +{ + if (transaction == NULL || fTree == NULL || fTree->fStream == NULL + || offset == BPLUSTREE_NULL) + RETURN_ERROR(B_BAD_VALUE); + + // ToDo: scan the free nodes list and remove all nodes at the end + // of the tree - perhaps that shouldn't be done everytime that + // function is called, perhaps it should be done when the directory + // inode is closed or based on some calculation or whatever... + + // if the node is the last one in the tree, we shrink + // the tree and file size by one node + off_t lastOffset = fTree->fHeader->maximum_size - fTree->fNodeSize; + if (offset == lastOffset) { + fTree->fHeader->maximum_size = lastOffset; + + status_t status = fTree->fStream->SetFileSize(transaction,lastOffset); + if (status < B_OK) + return status; + + return fTree->fCachedHeader.WriteBack(transaction); + } + + // add the node to the free nodes list + fNode->left_link = fTree->fHeader->free_node_pointer; + fNode->overflow_link = BPLUSTREE_FREE; + + if (WriteBack(transaction) == B_OK) { + fTree->fHeader->free_node_pointer = offset; + return fTree->fCachedHeader.WriteBack(transaction); + } + return B_ERROR; +} + + +status_t +CachedNode::Allocate(Transaction *transaction, bplustree_node **_node, off_t *_offset) +{ + if (transaction == NULL || fTree == NULL || fTree->fHeader == NULL + || fTree->fStream == NULL) { + RETURN_ERROR(B_BAD_VALUE); + } + + status_t status; + + // if there are any free nodes, recycle them + if (SetTo(fTree->fHeader->free_node_pointer,false) != NULL) { + *_offset = fTree->fHeader->free_node_pointer; + + // set new free node pointer + fTree->fHeader->free_node_pointer = fNode->left_link; + if ((status = fTree->fCachedHeader.WriteBack(transaction)) == B_OK) { + fNode->Initialize(); + *_node = fNode; + return B_OK; + } + return status; + } + // allocate space for a new node + Inode *stream = fTree->fStream; + if ((status = stream->Append(transaction,fTree->fNodeSize)) < B_OK) + return status; + + // the maximum_size has to be changed before the call to SetTo() - or + // else it will fail because the requested node is out of bounds + off_t offset = fTree->fHeader->maximum_size; + fTree->fHeader->maximum_size += fTree->fNodeSize; + + if (SetTo(offset,false) != NULL) { + *_offset = offset; + + if (fTree->fCachedHeader.WriteBack(transaction) >= B_OK) { + fNode->Initialize(); + *_node = fNode; + return B_OK; + } + } + RETURN_ERROR(B_ERROR); +} + + +status_t +CachedNode::WriteBack(Transaction *transaction) +{ + if (transaction == NULL || fTree == NULL || fTree->fStream == NULL || fNode == NULL) + RETURN_ERROR(B_BAD_VALUE); + + return transaction->WriteBlocks(fBlockNumber,fBlock); +} + + +// #pragma mark - + + +BPlusTree::BPlusTree(Transaction *transaction,Inode *stream,int32 nodeSize) + : + fStream(NULL), + fHeader(NULL), + fCachedHeader(this) +{ + SetTo(transaction,stream); +} + + +BPlusTree::BPlusTree(Inode *stream) + : + fStream(NULL), + fHeader(NULL), + fCachedHeader(this) +{ + SetTo(stream); +} + + +BPlusTree::BPlusTree() + : + fStream(NULL), + fHeader(NULL), + fCachedHeader(this), + fNodeSize(BPLUSTREE_NODE_SIZE), + fAllowDuplicates(true), + fStatus(B_NO_INIT) +{ +} + + +BPlusTree::~BPlusTree() +{ + // if there are any TreeIterators left, we need to stop them + // (can happen when the tree's inode gets deleted while + // traversing the tree - a TreeIterator doesn't lock the inode) + if (fIteratorLock.Lock() < B_OK) + return; + + TreeIterator *iterator = NULL; + while ((iterator = fIterators.Next(iterator)) != NULL) + iterator->Stop(); + + fIteratorLock.Unlock(); +} + + +status_t +BPlusTree::SetTo(Transaction *transaction,Inode *stream,int32 nodeSize) +{ + // initializes in-memory B+Tree + + fCachedHeader.Unset(); + fStream = stream; + + fHeader = fCachedHeader.SetToHeader(); + if (fHeader == NULL) { + // allocate space for new header + node! + fStatus = stream->SetFileSize(transaction,nodeSize * 2); + if (fStatus < B_OK) + RETURN_ERROR(fStatus); + + fHeader = fCachedHeader.SetToHeader(); + if (fHeader == NULL) + RETURN_ERROR(fStatus = B_ERROR); + } + + fAllowDuplicates = ((stream->Mode() & S_INDEX_DIR) == S_INDEX_DIR + && stream->BlockRun() != stream->Parent()) + || (stream->Mode() & S_ALLOW_DUPS) != 0; + + fNodeSize = nodeSize; + + // initialize b+tree header + fHeader->magic = BPLUSTREE_MAGIC; + fHeader->node_size = fNodeSize; + fHeader->max_number_of_levels = 1; + fHeader->data_type = ModeToKeyType(stream->Mode()); + fHeader->root_node_pointer = nodeSize; + fHeader->free_node_pointer = BPLUSTREE_NULL; + fHeader->maximum_size = nodeSize * 2; + + if (fCachedHeader.WriteBack(transaction) < B_OK) + RETURN_ERROR(fStatus = B_ERROR); + + // initialize b+tree root node + CachedNode cached(this,fHeader->root_node_pointer,false); + if (cached.Node() == NULL) + RETURN_ERROR(B_ERROR); + + cached.Node()->Initialize(); + return fStatus = cached.WriteBack(transaction); +} + + +status_t +BPlusTree::SetTo(Inode *stream) +{ + if (stream == NULL || stream->Node() == NULL) + RETURN_ERROR(fStatus = B_BAD_VALUE); + + // get on-disk B+Tree header + + fCachedHeader.Unset(); + fStream = stream; + + fHeader = fCachedHeader.SetToHeader(); + if (fHeader == NULL) + RETURN_ERROR(fStatus = B_NO_INIT); + + // is header valid? + + if (fHeader->magic != BPLUSTREE_MAGIC + || fHeader->maximum_size != stream->Size() + || (fHeader->root_node_pointer % fHeader->node_size) != 0 + || !fHeader->IsValidLink(fHeader->root_node_pointer) + || !fHeader->IsValidLink(fHeader->free_node_pointer)) + RETURN_ERROR(fStatus = B_BAD_DATA); + + fNodeSize = fHeader->node_size; + + { + uint32 toMode[] = {S_STR_INDEX, S_INT_INDEX, S_UINT_INDEX, S_LONG_LONG_INDEX, + S_ULONG_LONG_INDEX, S_FLOAT_INDEX, S_DOUBLE_INDEX}; + uint32 mode = stream->Mode() & (S_STR_INDEX | S_INT_INDEX | S_UINT_INDEX | S_LONG_LONG_INDEX + | S_ULONG_LONG_INDEX | S_FLOAT_INDEX | S_DOUBLE_INDEX); + + if (fHeader->data_type > BPLUSTREE_DOUBLE_TYPE + || (stream->Mode() & S_INDEX_DIR) && toMode[fHeader->data_type] != mode + || !stream->IsDirectory()) { + D( dump_bplustree_header(fHeader); + dump_inode(stream->Node()); + ); + RETURN_ERROR(fStatus = B_BAD_TYPE); + } + + // although it's in stat.h, the S_ALLOW_DUPS flag is obviously unused + // in the original BFS code - we will honour it nevertheless + fAllowDuplicates = ((stream->Mode() & S_INDEX_DIR) == S_INDEX_DIR + && stream->BlockRun() != stream->Parent()) + || (stream->Mode() & S_ALLOW_DUPS) != 0; + } + + CachedNode cached(this,fHeader->root_node_pointer); + RETURN_ERROR(fStatus = cached.Node() ? B_OK : B_BAD_DATA); +} + + +status_t +BPlusTree::InitCheck() +{ + return fStatus; +} + + +int32 +BPlusTree::TypeCodeToKeyType(type_code code) +{ + switch (code) { + case B_STRING_TYPE: + return BPLUSTREE_STRING_TYPE; + case B_INT32_TYPE: + return BPLUSTREE_INT32_TYPE; + case B_UINT32_TYPE: + return BPLUSTREE_UINT32_TYPE; + case B_INT64_TYPE: + return BPLUSTREE_INT64_TYPE; + case B_UINT64_TYPE: + return BPLUSTREE_UINT64_TYPE; + case B_FLOAT_TYPE: + return BPLUSTREE_FLOAT_TYPE; + case B_DOUBLE_TYPE: + return BPLUSTREE_DOUBLE_TYPE; + } + return -1; +} + + +int32 +BPlusTree::ModeToKeyType(mode_t mode) +{ + switch (mode & (S_STR_INDEX | S_INT_INDEX | S_UINT_INDEX | S_LONG_LONG_INDEX + | S_ULONG_LONG_INDEX | S_FLOAT_INDEX | S_DOUBLE_INDEX)) { + case S_INT_INDEX: + return BPLUSTREE_INT32_TYPE; + case S_UINT_INDEX: + return BPLUSTREE_UINT32_TYPE; + case S_LONG_LONG_INDEX: + return BPLUSTREE_INT64_TYPE; + case S_ULONG_LONG_INDEX: + return BPLUSTREE_UINT64_TYPE; + case S_FLOAT_INDEX: + return BPLUSTREE_FLOAT_TYPE; + case S_DOUBLE_INDEX: + return BPLUSTREE_DOUBLE_TYPE; + case S_STR_INDEX: + default: + // default is for standard directories + return BPLUSTREE_STRING_TYPE; + } +} + + +// #pragma mark - + + +void +BPlusTree::UpdateIterators(off_t offset,off_t nextOffset,uint16 keyIndex,uint16 splitAt,int8 change) +{ + // Although every iterator which is affected by this update currently + // waits on a semaphore, other iterators could be added/removed at + // any time, so we need to protect this loop + if (fIteratorLock.Lock() < B_OK) + return; + + TreeIterator *iterator = NULL; + while ((iterator = fIterators.Next(iterator)) != NULL) + iterator->Update(offset,nextOffset,keyIndex,splitAt,change); + + fIteratorLock.Unlock(); +} + + +void +BPlusTree::AddIterator(TreeIterator *iterator) +{ + if (fIteratorLock.Lock() < B_OK) + return; + + fIterators.Add(iterator); + + fIteratorLock.Unlock(); +} + + +void +BPlusTree::RemoveIterator(TreeIterator *iterator) +{ + if (fIteratorLock.Lock() < B_OK) + return; + + fIterators.Remove(iterator); + + fIteratorLock.Unlock(); +} + + +int32 +BPlusTree::CompareKeys(const void *key1, int keyLength1, const void *key2, int keyLength2) +{ + type_code type = 0; + switch (fHeader->data_type) + { + case BPLUSTREE_STRING_TYPE: + type = B_STRING_TYPE; + break; + case BPLUSTREE_INT32_TYPE: + type = B_INT32_TYPE; + break; + case BPLUSTREE_UINT32_TYPE: + type = B_UINT32_TYPE; + break; + case BPLUSTREE_INT64_TYPE: + type = B_INT64_TYPE; + break; + case BPLUSTREE_UINT64_TYPE: + type = B_UINT64_TYPE; + break; + case BPLUSTREE_FLOAT_TYPE: + type = B_FLOAT_TYPE; + break; + case BPLUSTREE_DOUBLE_TYPE: + type = B_DOUBLE_TYPE; + break; + } + return compareKeys(type,key1,keyLength1,key2,keyLength2); +} + + +status_t +BPlusTree::FindKey(bplustree_node *node,const uint8 *key,uint16 keyLength,uint16 *index,off_t *next) +{ + if (node->all_key_count == 0) + { + if (index) + *index = 0; + if (next) + *next = node->overflow_link; + return B_ENTRY_NOT_FOUND; + } + + off_t *values = node->Values(); + int16 saveIndex; + + // binary search in the key array + for (int16 first = 0,last = node->all_key_count - 1;first <= last;) + { + uint16 i = (first + last) >> 1; + + uint16 searchLength; + uint8 *searchKey = node->KeyAt(i,&searchLength); + if (searchKey + searchLength + sizeof(off_t) + sizeof(uint16) > (uint8 *)node + fNodeSize + || searchLength > BPLUSTREE_MAX_KEY_LENGTH) { + fStream->GetVolume()->Panic(); + RETURN_ERROR(B_BAD_DATA); + } + + int32 cmp = CompareKeys(key,keyLength,searchKey,searchLength); + if (cmp < 0) + { + last = i - 1; + saveIndex = i; + } + else if (cmp > 0) + { + saveIndex = first = i + 1; + } + else + { + if (index) + *index = i; + if (next) + *next = values[i]; + return B_OK; + } + } + + if (index) + *index = saveIndex; + if (next) + { + if (saveIndex == node->all_key_count) + *next = node->overflow_link; + else + *next = values[saveIndex]; + } + return B_ENTRY_NOT_FOUND; +} + + +/** Prepares the stack to contain all nodes that were passed while + * following the key, from the root node to the leaf node that could + * or should contain that key. + */ + +status_t +BPlusTree::SeekDown(Stack &stack,const uint8 *key,uint16 keyLength) +{ + // set the root node to begin with + node_and_key nodeAndKey; + nodeAndKey.nodeOffset = fHeader->root_node_pointer; + + CachedNode cached(this); + bplustree_node *node; + while ((node = cached.SetTo(nodeAndKey.nodeOffset)) != NULL) { + // if we are already on leaf level, we're done + if (node->overflow_link == BPLUSTREE_NULL) { + // node that the keyIndex is not properly set here (but it's not + // needed in the calling functions anyway)! + nodeAndKey.keyIndex = 0; + stack.Push(nodeAndKey); + return B_OK; + } + + off_t nextOffset; + status_t status = FindKey(node,key,keyLength,&nodeAndKey.keyIndex,&nextOffset); + + if (status == B_ENTRY_NOT_FOUND && nextOffset == nodeAndKey.nodeOffset) + RETURN_ERROR(B_ERROR); + + // put the node offset & the correct keyIndex on the stack + stack.Push(nodeAndKey); + + nodeAndKey.nodeOffset = nextOffset; + } + RETURN_ERROR(B_ERROR); +} + + +status_t +BPlusTree::FindFreeDuplicateFragment(bplustree_node *node,CachedNode *cached,off_t *_offset,bplustree_node **_fragment,uint32 *_index) +{ + off_t *values = node->Values(); + for (int32 i = 0;i < node->all_key_count;i++) { + // does the value link to a duplicate fragment? + if (bplustree_node::LinkType(values[i]) != BPLUSTREE_DUPLICATE_FRAGMENT) + continue; + + bplustree_node *fragment = cached->SetTo(bplustree_node::FragmentOffset(values[i]),false); + if (fragment == NULL) { + FATAL(("Could not get duplicate fragment at %Ld\n",values[i])); + continue; + } + + // see if there is some space left for us + int32 num = (fNodeSize >> 3) / (NUM_FRAGMENT_VALUES + 1); + for (int32 j = 0;j < num;j++) { + duplicate_array *array = fragment->FragmentAt(j); + + if (array->count == 0) { + *_offset = bplustree_node::FragmentOffset(values[i]); + *_fragment = fragment; + *_index = j; + return B_OK; + } + } + } + return B_ENTRY_NOT_FOUND; +} + + +status_t +BPlusTree::InsertDuplicate(Transaction *transaction,CachedNode *cached,bplustree_node *node,uint16 index,off_t value) +{ + CachedNode cachedDuplicate(this); + off_t *values = node->Values(); + off_t oldValue = values[index]; + status_t status; + off_t offset; + + if (bplustree_node::IsDuplicate(oldValue)) { + // + // If it's a duplicate fragment, try to insert it into that, or if it + // doesn't fit anymore, create a new duplicate node + // + if (bplustree_node::LinkType(oldValue) == BPLUSTREE_DUPLICATE_FRAGMENT) { + bplustree_node *duplicate = cachedDuplicate.SetTo(bplustree_node::FragmentOffset(oldValue),false); + if (duplicate == NULL) + return B_IO_ERROR; + + duplicate_array *array = duplicate->FragmentAt(bplustree_node::FragmentIndex(oldValue)); + if (array->count > NUM_FRAGMENT_VALUES + || array->count < 1) { + FATAL(("insertDuplicate: Invalid array[%ld] size in fragment %Ld == %Ld!\n",bplustree_node::FragmentIndex(oldValue),bplustree_node::FragmentOffset(oldValue),array->count)); + return B_BAD_DATA; + } + + if (array->count < NUM_FRAGMENT_VALUES) { + array->Insert(value); + } else { + // test if the fragment will be empty if we remove this key's values + if (duplicate->FragmentsUsed(fNodeSize) < 2) { + // the node will be empty without our values, so let us + // reuse it as a duplicate node + offset = bplustree_node::FragmentOffset(oldValue); + + memmove(duplicate->DuplicateArray(),array,(NUM_FRAGMENT_VALUES + 1) * sizeof(off_t)); + duplicate->left_link = duplicate->right_link = BPLUSTREE_NULL; + + array = duplicate->DuplicateArray(); + array->Insert(value); + } else { + // create a new duplicate node + CachedNode cachedNewDuplicate(this); + bplustree_node *newDuplicate; + status = cachedNewDuplicate.Allocate(transaction,&newDuplicate,&offset); + if (status < B_OK) + return status; + + // copy the array from the fragment node to the duplicate node + // and free the old entry (by zero'ing all values) + newDuplicate->overflow_link = array->count; + memcpy(&newDuplicate->all_key_count,&array->values[0],array->count * sizeof(off_t)); + memset(array,0,(NUM_FRAGMENT_VALUES + 1) * sizeof(off_t)); + + array = newDuplicate->DuplicateArray(); + array->Insert(value); + + // if this fails, the old fragments node will contain wrong + // data... (but since it couldn't be written, it shouldn't + // be fatal) + if ((status = cachedNewDuplicate.WriteBack(transaction)) < B_OK) + return status; + } + + // update the main pointer to link to a duplicate node + values[index] = bplustree_node::MakeLink(BPLUSTREE_DUPLICATE_NODE,offset); + if ((status = cached->WriteBack(transaction)) < B_OK) + return status; + } + + return cachedDuplicate.WriteBack(transaction); + } + + // + // Put the value into a dedicated duplicate node + // + + // search for free space in the duplicate nodes of that key + duplicate_array *array; + bplustree_node *duplicate; + off_t duplicateOffset; + do { + duplicateOffset = bplustree_node::FragmentOffset(oldValue); + duplicate = cachedDuplicate.SetTo(duplicateOffset,false); + if (duplicate == NULL) + return B_IO_ERROR; + + array = duplicate->DuplicateArray(); + if (array->count > NUM_DUPLICATE_VALUES + || array->count < 0) { + FATAL(("removeDuplicate: Invalid array size in duplicate %Ld == %Ld!\n",duplicateOffset,array->count)); + return B_BAD_DATA; + } + } while (array->count >= NUM_DUPLICATE_VALUES && (oldValue = duplicate->right_link) != BPLUSTREE_NULL); + + if (array->count < NUM_DUPLICATE_VALUES) { + array->Insert(value); + } else { + // no space left - add a new duplicate node + + CachedNode cachedNewDuplicate(this); + bplustree_node *newDuplicate; + status = cachedNewDuplicate.Allocate(transaction,&newDuplicate,&offset); + if (status < B_OK) + return status; + + // link the two nodes together + duplicate->right_link = offset; + newDuplicate->left_link = duplicateOffset; + + array = newDuplicate->DuplicateArray(); + array->count = 0; + array->Insert(value); + + status = cachedNewDuplicate.WriteBack(transaction); + if (status < B_OK) + return status; + } + return cachedDuplicate.WriteBack(transaction); + } + + // + // Search for a free duplicate fragment or create a new one + // to insert the duplicate value into + // + + uint32 fragmentIndex = 0; + bplustree_node *fragment; + if (FindFreeDuplicateFragment(node,&cachedDuplicate,&offset,&fragment,&fragmentIndex) < B_OK) { + // allocate a new duplicate fragment node + if ((status = cachedDuplicate.Allocate(transaction,&fragment,&offset)) < B_OK) + return status; + + memset(fragment,0,fNodeSize); + } + duplicate_array *array = fragment->FragmentAt(fragmentIndex); + array->Insert(oldValue); + array->Insert(value); + + if ((status = cachedDuplicate.WriteBack(transaction)) < B_OK) + return status; + + values[index] = bplustree_node::MakeLink(BPLUSTREE_DUPLICATE_FRAGMENT,offset,fragmentIndex); + + return cached->WriteBack(transaction); +} + + +void +BPlusTree::InsertKey(bplustree_node *node,uint16 index,uint8 *key,uint16 keyLength,off_t value) +{ + // should never happen, but who knows? + if (index > node->all_key_count) + return; + + off_t *values = node->Values(); + uint16 *keyLengths = node->KeyLengths(); + uint8 *keys = node->Keys(); + + node->all_key_count++; + node->all_key_length += keyLength; + + off_t *newValues = node->Values(); + uint16 *newKeyLengths = node->KeyLengths(); + + // move values and copy new value into them + memmove(newValues + index + 1,values + index,sizeof(off_t) * (node->all_key_count - 1 - index)); + memmove(newValues,values,sizeof(off_t) * index); + + newValues[index] = value; + + // move and update key length index + for (uint16 i = node->all_key_count;i-- > index + 1;) + newKeyLengths[i] = keyLengths[i - 1] + keyLength; + memmove(newKeyLengths,keyLengths,sizeof(uint16) * index); + + int32 keyStart; + newKeyLengths[index] = keyLength + (keyStart = index > 0 ? newKeyLengths[index - 1] : 0); + + // move keys and copy new key into them + int32 size = node->all_key_length - newKeyLengths[index]; + if (size > 0) + memmove(keys + newKeyLengths[index],keys + newKeyLengths[index] - keyLength,size); + + memcpy(keys + keyStart,key,keyLength); +} + + +status_t +BPlusTree::SplitNode(bplustree_node *node,off_t nodeOffset,bplustree_node *other,off_t otherOffset,uint16 *_keyIndex,uint8 *key,uint16 *_keyLength,off_t *_value) +{ + if (*_keyIndex > node->all_key_count + 1) + return B_BAD_VALUE; + + uint16 *inKeyLengths = node->KeyLengths(); + off_t *inKeyValues = node->Values(); + uint8 *inKeys = node->Keys(); + uint8 *outKeys = other->Keys(); + int32 keyIndex = *_keyIndex; // can become less than zero! + + // how many keys will fit in one (half) page? + // that loop will find the answer to this question and + // change the key lengths indices for their new home + + // "bytes" is the number of bytes written for the new key, + // "bytesBefore" are the bytes before that key + // "bytesAfter" are the bytes after the new key, if any + int32 bytes = 0,bytesBefore = 0,bytesAfter = 0; + + size_t size = fNodeSize >> 1; + int32 out,in; + for (in = out = 0;in < node->all_key_count + 1;) { + if (!bytes) + bytesBefore = in > 0 ? inKeyLengths[in - 1] : 0; + + if (in == keyIndex && !bytes) { + bytes = *_keyLength; + } else { + if (keyIndex < out) + bytesAfter = inKeyLengths[in] - bytesBefore; + + in++; + } + out++; + + if (round_up(sizeof(bplustree_node) + bytesBefore + bytesAfter + bytes) + + out * (sizeof(uint16) + sizeof(off_t)) >= size) { + // we have found the number of keys in the new node! + break; + } + } + + // if the new key was not inserted, set the length of the keys + // that can be copied directly + if (keyIndex >= out && in > 0) + bytesBefore = inKeyLengths[in - 1]; + + if (bytesBefore < 0 || bytesAfter < 0) + return B_BAD_DATA; + + other->left_link = node->left_link; + other->right_link = nodeOffset; + other->all_key_length = bytes + bytesBefore + bytesAfter; + other->all_key_count = out; + + uint16 *outKeyLengths = other->KeyLengths(); + off_t *outKeyValues = other->Values(); + int32 keys = out > keyIndex ? keyIndex : out; + + if (bytesBefore) { + // copy the keys + memcpy(outKeys,inKeys,bytesBefore); + memcpy(outKeyLengths,inKeyLengths,keys * sizeof(uint16)); + memcpy(outKeyValues,inKeyValues,keys * sizeof(off_t)); + } + if (bytes) { + // copy the newly inserted key + memcpy(outKeys + bytesBefore,key,bytes); + outKeyLengths[keyIndex] = bytes + bytesBefore; + outKeyValues[keyIndex] = *_value; + + if (bytesAfter) { + // copy the keys after the new key + memcpy(outKeys + bytesBefore + bytes,inKeys + bytesBefore,bytesAfter); + keys = out - keyIndex - 1; + for (int32 i = 0;i < keys;i++) + outKeyLengths[keyIndex + i + 1] = inKeyLengths[keyIndex + i] + bytes; + memcpy(outKeyValues + keyIndex + 1,inKeyValues + keyIndex,keys * sizeof(off_t)); + } + } + + // if the new key was already inserted, we shouldn't use it again + if (in != out) + keyIndex--; + + int32 total = bytesBefore + bytesAfter; + + // these variables are for the key that will be returned + // to the parent node + uint8 *newKey = NULL; + uint16 newLength; + bool newAllocated = false; + + // If we have split an index node, we have to drop the first key + // of the next node (which can also be the new key to insert). + // The dropped key is also the one which has to be inserted in + // the parent node, so we will set the "newKey" already here. + if (node->overflow_link != BPLUSTREE_NULL) { + if (in == keyIndex) { + newKey = key; + newLength = *_keyLength; + + other->overflow_link = *_value; + keyIndex--; + } else { + // If a key is dropped (is not the new key), we have to copy + // it, because it would be lost if not. + uint8 *droppedKey = node->KeyAt(in,&newLength); + if (droppedKey + newLength + sizeof(off_t) + sizeof(uint16) > (uint8 *)node + fNodeSize + || newLength > BPLUSTREE_MAX_KEY_LENGTH) { + fStream->GetVolume()->Panic(); + RETURN_ERROR(B_BAD_DATA); + } + newKey = (uint8 *)malloc(newLength); + if (newKey == NULL) + return B_NO_MEMORY; + memcpy(newKey,droppedKey,newLength); + + other->overflow_link = inKeyValues[in]; + total = inKeyLengths[in++]; + } + } + + // and now the same game for the other page and the rest of the keys + // (but with memmove() instead of memcpy(), because they may overlap) + + bytesBefore = bytesAfter = bytes = 0; + out = 0; + int32 skip = in; + while (in < node->all_key_count + 1) { + if (in == keyIndex && !bytes) { + // it's enough to set bytesBefore once here, because we do + // not need to know the exact length of all keys in this + // loop + bytesBefore = in > skip ? inKeyLengths[in - 1] : 0; + bytes = *_keyLength; + } else { + if (in < node->all_key_count) { + inKeyLengths[in] -= total; + if (bytes) { + inKeyLengths[in] += bytes; + bytesAfter = inKeyLengths[in] - bytesBefore - bytes; + } + } + in++; + } + + out++; + + // break out when all keys are done + if (in > node->all_key_count && keyIndex < in) + break; + } + + // adjust the byte counts (since we were a bit lazy in the loop) + if (keyIndex >= in && keyIndex - skip < out) + bytesAfter = inKeyLengths[in] - bytesBefore - total; + else if (keyIndex < skip) + bytesBefore = node->all_key_length - total; + + if (bytesBefore < 0 || bytesAfter < 0) + return B_BAD_DATA; + + node->left_link = otherOffset; + // right link, and overflow link can stay the same + node->all_key_length = bytes + bytesBefore + bytesAfter; + node->all_key_count = out - 1; + + // array positions have changed + outKeyLengths = node->KeyLengths(); + outKeyValues = node->Values(); + + // move the keys in the old node: the order is important here, + // because we don't want to overwrite any contents + + keys = keyIndex <= skip ? out : keyIndex - skip; + keyIndex -= skip; + + if (bytesBefore) + memmove(inKeys,inKeys + total,bytesBefore); + if (bytesAfter) + memmove(inKeys + bytesBefore + bytes,inKeys + total + bytesBefore,bytesAfter); + + if (bytesBefore) + memmove(outKeyLengths,inKeyLengths + skip,keys * sizeof(uint16)); + in = out - keyIndex - 1; + if (bytesAfter) + memmove(outKeyLengths + keyIndex + 1,inKeyLengths + skip + keyIndex,in * sizeof(uint16)); + + if (bytesBefore) + memmove(outKeyValues,inKeyValues + skip,keys * sizeof(off_t)); + if (bytesAfter) + memmove(outKeyValues + keyIndex + 1,inKeyValues + skip + keyIndex,in * sizeof(off_t)); + + if (bytes) { + // finally, copy the newly inserted key (don't overwrite anything) + memcpy(inKeys + bytesBefore,key,bytes); + outKeyLengths[keyIndex] = bytes + bytesBefore; + outKeyValues[keyIndex] = *_value; + } + + // Prepare the key that will be inserted in the parent node which + // is either the dropped key or the last of the other node. + // If it's the dropped key, "newKey" was already set earlier. + + if (newKey == NULL) + newKey = other->KeyAt(other->all_key_count - 1,&newLength); + + memcpy(key,newKey,newLength); + *_keyLength = newLength; + *_value = otherOffset; + + if (newAllocated) + free(newKey); + + return B_OK; +} + + +status_t +BPlusTree::Insert(Transaction *transaction,const uint8 *key,uint16 keyLength,off_t value) +{ + if (keyLength < BPLUSTREE_MIN_KEY_LENGTH || keyLength > BPLUSTREE_MAX_KEY_LENGTH) + RETURN_ERROR(B_BAD_VALUE); + + // lock access to stream + WriteLocked locked(fStream->Lock()); + + Stack stack; + if (SeekDown(stack,key,keyLength) != B_OK) + RETURN_ERROR(B_ERROR); + + uint8 keyBuffer[BPLUSTREE_MAX_KEY_LENGTH + 1]; + + memcpy(keyBuffer,key,keyLength); + keyBuffer[keyLength] = 0; + + node_and_key nodeAndKey; + bplustree_node *node; + + CachedNode cached(this); + while (stack.Pop(&nodeAndKey) && (node = cached.SetTo(nodeAndKey.nodeOffset)) != NULL) { + if (node->IsLeaf()) { + // first round, check for duplicate entries + status_t status = FindKey(node,key,keyLength,&nodeAndKey.keyIndex); + + // is this a duplicate entry? + if (status == B_OK) { + if (fAllowDuplicates) + return InsertDuplicate(transaction,&cached,node,nodeAndKey.keyIndex,value); + else + RETURN_ERROR(B_NAME_IN_USE); + } + } + + // is the node big enough to hold the pair? + if (int32(round_up(sizeof(bplustree_node) + node->all_key_length + keyLength) + + (node->all_key_count + 1) * (sizeof(uint16) + sizeof(off_t))) < fNodeSize) + { + InsertKey(node,nodeAndKey.keyIndex,keyBuffer,keyLength,value); + UpdateIterators(nodeAndKey.nodeOffset,BPLUSTREE_NULL,nodeAndKey.keyIndex,0,1); + + return cached.WriteBack(transaction); + } else { + CachedNode cachedNewRoot(this); + CachedNode cachedOther(this); + + // do we need to allocate a new root node? if so, then do + // it now + off_t newRoot = BPLUSTREE_NULL; + if (nodeAndKey.nodeOffset == fHeader->root_node_pointer) { + bplustree_node *root; + status_t status = cachedNewRoot.Allocate(transaction,&root,&newRoot); + if (status < B_OK) { + // The tree is most likely corrupted! + // But it's still sane at leaf level - we could set + // a flag in the header that forces the tree to be + // rebuild next time... + // But since we will have journaling, that's not a big + // problem anyway. + RETURN_ERROR(status); + } + } + + // reserve space for the other node + bplustree_node *other; + off_t otherOffset; + status_t status = cachedOther.Allocate(transaction,&other,&otherOffset); + if (status < B_OK) { + cachedNewRoot.Free(transaction,newRoot); + RETURN_ERROR(status); + } + + if (SplitNode(node,nodeAndKey.nodeOffset,other,otherOffset,&nodeAndKey.keyIndex,keyBuffer,&keyLength,&value) < B_OK) { + // free root node & other node here + cachedNewRoot.Free(transaction,newRoot); + cachedOther.Free(transaction,otherOffset); + + RETURN_ERROR(B_ERROR); + } + + // write the updated nodes back + + if (cached.WriteBack(transaction) < B_OK + || cachedOther.WriteBack(transaction) < B_OK) + RETURN_ERROR(B_ERROR); + + UpdateIterators(nodeAndKey.nodeOffset,otherOffset,nodeAndKey.keyIndex,node->all_key_count,1); + + // update the right link of the node in the left of the new node + if ((other = cachedOther.SetTo(other->left_link)) != NULL) { + other->right_link = otherOffset; + if (cachedOther.WriteBack(transaction) < B_OK) + RETURN_ERROR(B_ERROR); + } + + // create a new root if necessary + if (newRoot != BPLUSTREE_NULL) { + bplustree_node *root = cachedNewRoot.Node(); + + InsertKey(root,0,keyBuffer,keyLength,node->left_link); + root->overflow_link = nodeAndKey.nodeOffset; + + if (cachedNewRoot.WriteBack(transaction) < B_OK) + RETURN_ERROR(B_ERROR); + + // finally, update header to point to the new root + fHeader->root_node_pointer = newRoot; + fHeader->max_number_of_levels++; + + return fCachedHeader.WriteBack(transaction); + } + } + } + RETURN_ERROR(B_ERROR); +} + + +status_t +BPlusTree::RemoveDuplicate(Transaction *transaction,bplustree_node *node,CachedNode *cached,uint16 index,off_t value) +{ + CachedNode cachedDuplicate(this); + off_t *values = node->Values(); + off_t oldValue = values[index]; + status_t status; + + off_t duplicateOffset = bplustree_node::FragmentOffset(oldValue); + bplustree_node *duplicate = cachedDuplicate.SetTo(duplicateOffset,false); + if (duplicate == NULL) + return B_IO_ERROR; + + // if it's a duplicate fragment, remove the entry from there + if (bplustree_node::LinkType(oldValue) == BPLUSTREE_DUPLICATE_FRAGMENT) { + duplicate_array *array = duplicate->FragmentAt(bplustree_node::FragmentIndex(oldValue)); + + if (array->count > NUM_FRAGMENT_VALUES + || array->count < 1) { + FATAL(("removeDuplicate: Invalid array[%ld] size in fragment %Ld == %Ld!\n",bplustree_node::FragmentIndex(oldValue),duplicateOffset,array->count)); + return B_BAD_DATA; + } + if (!array->Remove(value)) + FATAL(("Oh no, value %Ld not found in fragments of node %Ld...\n",value,duplicateOffset)); + + // remove the array from the fragment node if it is empty + if (array->count == 1) { + // set the link to the remaining value + values[index] = array->values[0]; + + // Remove the whole fragment node, if this was the only array, + // otherwise free the array and write the changes back + if (duplicate->FragmentsUsed(fNodeSize) == 1) + status = cachedDuplicate.Free(transaction,duplicateOffset); + else { + array->count = 0; + status = cachedDuplicate.WriteBack(transaction); + } + if (status < B_OK) + return status; + + return cached->WriteBack(transaction); + } + return cachedDuplicate.WriteBack(transaction); + } + + // + // Remove value from a duplicate node! + // + + duplicate_array *array; + + if (duplicate->left_link != BPLUSTREE_NULL) { + FATAL(("invalid duplicate node: first left link points to %Ld!\n",duplicate->left_link)); + return B_BAD_DATA; + } + + // Search the duplicate nodes until the entry could be found (and removed) + while (duplicate != NULL) { + array = duplicate->DuplicateArray(); + if (array->count > NUM_DUPLICATE_VALUES + || array->count < 0) { + FATAL(("removeDuplicate: Invalid array size in duplicate %Ld == %Ld!\n",duplicateOffset,array->count)); + return B_BAD_DATA; + } + + if (array->Remove(value)) + break; + + if ((duplicateOffset = duplicate->right_link) == BPLUSTREE_NULL) + RETURN_ERROR(B_ENTRY_NOT_FOUND); + + duplicate = cachedDuplicate.SetTo(duplicateOffset,false); + } + if (duplicate == NULL) + RETURN_ERROR(B_IO_ERROR); + + while (true) { + off_t left = duplicate->left_link; + off_t right = duplicate->right_link; + bool isLast = left == BPLUSTREE_NULL && right == BPLUSTREE_NULL; + + if (isLast && array->count == 1 || array->count == 0) { + // Free empty duplicate page, link their siblings together, and + // update the duplicate link if needed (which should not be, if + // we are the only one working on that tree...) + + if (duplicateOffset == bplustree_node::FragmentOffset(oldValue) + || array->count == 1) { + if (array->count == 1 && isLast) + values[index] = array->values[0]; + else if (isLast) { + FATAL(("removed last value from duplicate!\n")); + } else + values[index] = bplustree_node::MakeLink(BPLUSTREE_DUPLICATE_NODE,right); + + if ((status = cached->WriteBack(transaction)) < B_OK) + return status; + } + + if ((status = cachedDuplicate.Free(transaction,duplicateOffset)) < B_OK) + return status; + + if (left != BPLUSTREE_NULL + && (duplicate = cachedDuplicate.SetTo(left,false)) != NULL) { + duplicate->right_link = right; + + // If the next node is the last node, we need to free that node + // and convert the duplicate entry back into a normal entry + if (right == BPLUSTREE_NULL && duplicate->left_link == BPLUSTREE_NULL + && duplicate->DuplicateArray()->count <= NUM_FRAGMENT_VALUES) { + duplicateOffset = left; + continue; + } + + status = cachedDuplicate.WriteBack(transaction); + if (status < B_OK) + return status; + } + if (right != BPLUSTREE_NULL + && (duplicate = cachedDuplicate.SetTo(right,false)) != NULL) { + duplicate->left_link = left; + + // Again, we may need to turn the duplicate entry back into a normal entry + array = duplicate->DuplicateArray(); + if (left == BPLUSTREE_NULL && duplicate->right_link == BPLUSTREE_NULL + && duplicate->DuplicateArray()->count <= NUM_FRAGMENT_VALUES) { + duplicateOffset = right; + continue; + } + + return cachedDuplicate.WriteBack(transaction); + } + return status; + } else if (isLast && array->count <= NUM_FRAGMENT_VALUES) { + // If the number of entries fits in a duplicate fragment, then + // either find a free fragment node, or convert this node to a + // fragment node. + CachedNode cachedOther(this); + + bplustree_node *fragment = NULL; + uint32 fragmentIndex = 0; + off_t offset; + if (FindFreeDuplicateFragment(node,&cachedOther,&offset,&fragment,&fragmentIndex) < B_OK) { + // convert node + memmove(duplicate,array,(NUM_FRAGMENT_VALUES + 1) * sizeof(off_t)); + memset((off_t *)duplicate + NUM_FRAGMENT_VALUES + 1,0,fNodeSize - (NUM_FRAGMENT_VALUES + 1) * sizeof(off_t)); + } else { + // move to other node + duplicate_array *target = fragment->FragmentAt(fragmentIndex); + memcpy(target,array,(NUM_FRAGMENT_VALUES + 1) * sizeof(off_t)); + + cachedDuplicate.Free(transaction,duplicateOffset); + duplicateOffset = offset; + } + values[index] = bplustree_node::MakeLink(BPLUSTREE_DUPLICATE_FRAGMENT,duplicateOffset,fragmentIndex); + + if ((status = cached->WriteBack(transaction)) < B_OK) + return status; + + if (fragment != NULL) + return cachedOther.WriteBack(transaction); + } + return cachedDuplicate.WriteBack(transaction); + } +} + + +/** Removes the key with the given index from the specified node. + * Since it has to get the key from the node anyway (to obtain it's + * pointer), it's not needed to pass the key & its length, although + * the calling method (BPlusTree::Remove()) have this data. + */ + +void +BPlusTree::RemoveKey(bplustree_node *node,uint16 index) +{ + // should never happen, but who knows? + if (index > node->all_key_count && node->all_key_count > 0) { + FATAL(("Asked me to remove key outer limits: %u\n",index)); + return; + } + + off_t *values = node->Values(); + + // if we would have to drop the overflow link, drop + // the last key instead and update the overflow link + // to the value of that one + if (!node->IsLeaf() && index == node->all_key_count) + node->overflow_link = values[--index]; + + uint16 length; + uint8 *key = node->KeyAt(index,&length); + if (key + length + sizeof(off_t) + sizeof(uint16) > (uint8 *)node + fNodeSize + || length > BPLUSTREE_MAX_KEY_LENGTH) { + FATAL(("Key length to long: %s, %u (inode at %ld,%u [%s])\n",key,length,fStream->BlockRun().allocation_group,fStream->BlockRun().start,fStream->Name())); + fStream->GetVolume()->Panic(); + return; + } + + uint16 *keyLengths = node->KeyLengths(); + uint8 *keys = node->Keys(); + + node->all_key_count--; + node->all_key_length -= length; + + off_t *newValues = node->Values(); + uint16 *newKeyLengths = node->KeyLengths(); + + // move key data + memmove(key,key + length,node->all_key_length - (key - keys)); + + // move and update key lengths + if (index > 0 && newKeyLengths != keyLengths) + memmove(newKeyLengths,keyLengths,index * sizeof(uint16)); + for (uint16 i = index;i < node->all_key_count;i++) + newKeyLengths[i] = keyLengths[i + 1] - length; + + // move values + if (index > 0) + memmove(newValues,values,index * sizeof(off_t)); + if (node->all_key_count > index) + memmove(newValues + index,values + index + 1,(node->all_key_count - index) * sizeof(off_t)); +} + + +/** Removes the specified key from the tree. The "value" parameter is only used + * for trees which allow duplicates, so you may safely ignore it. + * It's not an optional parameter, so at least you have to think about it. + */ + +status_t +BPlusTree::Remove(Transaction *transaction,const uint8 *key,uint16 keyLength,off_t value) +{ + if (keyLength < BPLUSTREE_MIN_KEY_LENGTH || keyLength > BPLUSTREE_MAX_KEY_LENGTH) + RETURN_ERROR(B_BAD_VALUE); + + // lock access to stream + WriteLocked locked(fStream->Lock()); + + Stack stack; + if (SeekDown(stack,key,keyLength) != B_OK) + RETURN_ERROR(B_ERROR); + + node_and_key nodeAndKey; + bplustree_node *node; + + CachedNode cached(this); + while (stack.Pop(&nodeAndKey) && (node = cached.SetTo(nodeAndKey.nodeOffset)) != NULL) + { + if (node->IsLeaf()) // first round, check for duplicate entries + { + status_t status = FindKey(node,key,keyLength,&nodeAndKey.keyIndex); + if (status < B_OK) + RETURN_ERROR(status); + + // If we will remove the last key, the iterator will be set + // to the next node after the current - if there aren't any + // more nodes, we need a way to prevent the TreeIterators to + // touch the old node again, we use BPLUSTREE_FREE for this + off_t next = node->right_link == BPLUSTREE_NULL ? BPLUSTREE_FREE : node->right_link; + UpdateIterators(nodeAndKey.nodeOffset,node->all_key_count == 1 ? + next : BPLUSTREE_NULL,nodeAndKey.keyIndex,0,-1); + + // is this a duplicate entry? + if (bplustree_node::IsDuplicate(node->Values()[nodeAndKey.keyIndex])) { + if (fAllowDuplicates) + return RemoveDuplicate(transaction,node,&cached,nodeAndKey.keyIndex,value); + else + RETURN_ERROR(B_NAME_IN_USE); + } + } + + // if it's an empty root node, we have to convert it + // to a leaf node by dropping the overflow link, or, + // if it's a leaf node, just empty it + if (nodeAndKey.nodeOffset == fHeader->root_node_pointer + && node->all_key_count == 0 + || node->all_key_count == 1 && node->IsLeaf()) { + node->overflow_link = BPLUSTREE_NULL; + node->all_key_count = 0; + node->all_key_length = 0; + + if (cached.WriteBack(transaction) < B_OK) + return B_IO_ERROR; + + fHeader->max_number_of_levels = 1; + return fCachedHeader.WriteBack(transaction); + } + + // if there is only one key left, we don't have to remove + // it, we can just dump the node (index nodes still have + // the overflow link, so we have to drop the last key) + if (node->all_key_count > 1 + || !node->IsLeaf() && node->all_key_count == 1) { + RemoveKey(node,nodeAndKey.keyIndex); + return cached.WriteBack(transaction); + } + + // when we are here, we can just free the node, but + // we have to update the right/left link of the + // siblings first + CachedNode otherCached(this); + bplustree_node *other = otherCached.SetTo(node->left_link); + if (other != NULL) { + other->right_link = node->right_link; + if (otherCached.WriteBack(transaction) < B_OK) + return B_IO_ERROR; + } + + if ((other = otherCached.SetTo(node->right_link)) != NULL) { + other->left_link = node->left_link; + if (otherCached.WriteBack(transaction) < B_OK) + return B_IO_ERROR; + } + + cached.Free(transaction,nodeAndKey.nodeOffset); + } + RETURN_ERROR(B_ERROR); +} + + +/** Replaces the value for the key in the tree. + * Returns B_OK if the key could be found and its value replaced, + * B_ENTRY_NOT_FOUND if the key couldn't be found, and other errors + * to indicate that something went terribly wrong. + * Note that this doesn't work with duplicates - it will just + * return B_BAD_TYPE if you call this function on a tree where + * duplicates are allowed. + */ + +status_t +BPlusTree::Replace(Transaction *transaction,const uint8 *key,uint16 keyLength,off_t value) +{ + if (keyLength < BPLUSTREE_MIN_KEY_LENGTH || keyLength > BPLUSTREE_MAX_KEY_LENGTH + || key == NULL) + RETURN_ERROR(B_BAD_VALUE); + + if (fAllowDuplicates) + RETURN_ERROR(B_BAD_TYPE); + + // lock access to stream (a read lock is okay for this purpose) + ReadLocked locked(fStream->Lock()); + + off_t nodeOffset = fHeader->root_node_pointer; + CachedNode cached(this); + bplustree_node *node; + + while ((node = cached.SetTo(nodeOffset)) != NULL) { + uint16 keyIndex = 0; + off_t nextOffset; + status_t status = FindKey(node,key,keyLength,&keyIndex,&nextOffset); + + if (node->overflow_link == BPLUSTREE_NULL) { + if (status == B_OK) { + node->Values()[keyIndex] = value; + return cached.WriteBack(transaction); + } + + return status; + } else if (nextOffset == nodeOffset) + RETURN_ERROR(B_ERROR); + + nodeOffset = nextOffset; + } + RETURN_ERROR(B_ERROR); +} + + +/** Searches the key in the tree, and stores the offset found in + * _value, if successful. + * It's very similar to BPlusTree::SeekDown(), but doesn't fill + * a stack while it descends the tree. + * Returns B_OK when the key could be found, B_ENTRY_NOT_FOUND + * if not. It can also return other errors to indicate that + * something went wrong. + * Note that this doesn't work with duplicates - it will just + * return B_BAD_TYPE if you call this function on a tree where + * duplicates are allowed. + */ + +status_t +BPlusTree::Find(const uint8 *key,uint16 keyLength,off_t *_value) +{ + if (keyLength < BPLUSTREE_MIN_KEY_LENGTH || keyLength > BPLUSTREE_MAX_KEY_LENGTH + || key == NULL) + RETURN_ERROR(B_BAD_VALUE); + + if (fAllowDuplicates) + RETURN_ERROR(B_BAD_TYPE); + + // lock access to stream + ReadLocked locked(fStream->Lock()); + + off_t nodeOffset = fHeader->root_node_pointer; + CachedNode cached(this); + bplustree_node *node; + + while ((node = cached.SetTo(nodeOffset)) != NULL) { + uint16 keyIndex = 0; + off_t nextOffset; + status_t status = FindKey(node,key,keyLength,&keyIndex,&nextOffset); + + if (node->overflow_link == BPLUSTREE_NULL) { + if (status == B_OK && _value != NULL) + *_value = node->Values()[keyIndex]; + + return status; + } else if (nextOffset == nodeOffset) + RETURN_ERROR(B_ERROR); + + nodeOffset = nextOffset; + } + RETURN_ERROR(B_ERROR); +} + + +// #pragma mark - + + +TreeIterator::TreeIterator(BPlusTree *tree) + : + fTree(tree), + fCurrentNodeOffset(BPLUSTREE_NULL), + fNext(NULL) +{ + tree->AddIterator(this); +} + + +TreeIterator::~TreeIterator() +{ + if (fTree) + fTree->RemoveIterator(this); +} + + +status_t +TreeIterator::Goto(int8 to) +{ + if (fTree == NULL || fTree->fHeader == NULL) + RETURN_ERROR(B_BAD_VALUE); + + // lock access to stream + ReadLocked locked(fTree->fStream->Lock()); + + off_t nodeOffset = fTree->fHeader->root_node_pointer; + CachedNode cached(fTree); + bplustree_node *node; + + while ((node = cached.SetTo(nodeOffset)) != NULL) { + // is the node a leaf node? + if (node->overflow_link == BPLUSTREE_NULL) { + fCurrentNodeOffset = nodeOffset; + fCurrentKey = to == BPLUSTREE_BEGIN ? -1 : node->all_key_count; + fDuplicateNode = BPLUSTREE_NULL; + + return B_OK; + } + + // get the next node offset depending on the direction (and if there + // are any keys in that node at all) + off_t nextOffset; + if (to == BPLUSTREE_END || node->all_key_count == 0) + nextOffset = node->overflow_link; + else { + if (node->all_key_length > fTree->fNodeSize + || (uint32)node->Values() > (uint32)node + fTree->fNodeSize - 8 * node->all_key_count) + RETURN_ERROR(B_ERROR); + + nextOffset = node->Values()[0]; + } + if (nextOffset == nodeOffset) + break; + + nodeOffset = nextOffset; + } + FATAL(("%s fails\n",__PRETTY_FUNCTION__)); + RETURN_ERROR(B_ERROR); +} + + +/** Iterates through the tree in the specified direction. + * When it iterates through duplicates, the "key" is only updated for the + * first entry - if you need to know when this happens, use the "duplicate" + * parameter which is 0 for no duplicate, 1 for the first, and 2 for all + * the other duplicates. + * That's not too nice, but saves the 256 bytes that would be needed to + * store the last key - if this will ever become an issue, it will be + * easy to change. + * The other advantage of this is, that the queries can skip all duplicates + * at once when they are not relevant to them. + */ + +status_t +TreeIterator::Traverse(int8 direction,void *key,uint16 *keyLength,uint16 maxLength,off_t *value,uint16 *duplicate) +{ + if (fTree == NULL) + return B_INTERRUPTED; + if (fCurrentNodeOffset == BPLUSTREE_NULL + && Goto(direction == BPLUSTREE_FORWARD ? BPLUSTREE_BEGIN : BPLUSTREE_END) < B_OK) + RETURN_ERROR(B_ERROR); + + // if the tree was emptied since the last call + if (fCurrentNodeOffset == BPLUSTREE_FREE) + return B_ENTRY_NOT_FOUND; + + // lock access to stream + ReadLocked locked(fTree->fStream->Lock()); + + CachedNode cached(fTree); + bplustree_node *node; + + if (fDuplicateNode != BPLUSTREE_NULL) + { + // regardless of traverse direction the duplicates are always presented in + // the same order; since they are all considered as equal, this shouldn't + // cause any problems + + if (!fIsFragment || fDuplicate < fNumDuplicates) + node = cached.SetTo(bplustree_node::FragmentOffset(fDuplicateNode),false); + else + node = NULL; + + if (node != NULL) + { + if (!fIsFragment && fDuplicate >= fNumDuplicates) + { + // if the node is out of duplicates, we go directly to the next one + fDuplicateNode = node->right_link; + if (fDuplicateNode != BPLUSTREE_NULL + && (node = cached.SetTo(fDuplicateNode,false)) != NULL) + { + fNumDuplicates = node->CountDuplicates(fDuplicateNode,false); + fDuplicate = 0; + } + } + if (fDuplicate < fNumDuplicates) + { + *value = node->DuplicateAt(fDuplicateNode,fIsFragment,fDuplicate++); + if (duplicate) + *duplicate = 2; + return B_OK; + } + } + fDuplicateNode = BPLUSTREE_NULL; + } + + off_t savedNodeOffset = fCurrentNodeOffset; + if ((node = cached.SetTo(fCurrentNodeOffset)) == NULL) + RETURN_ERROR(B_ERROR); + + if (duplicate) + *duplicate = 0; + + fCurrentKey += direction; + + // is the current key in the current node? + while ((direction == BPLUSTREE_FORWARD && fCurrentKey >= node->all_key_count) + || (direction == BPLUSTREE_BACKWARD && fCurrentKey < 0)) + { + fCurrentNodeOffset = direction == BPLUSTREE_FORWARD ? node->right_link : node->left_link; + + // are there any more nodes? + if (fCurrentNodeOffset != BPLUSTREE_NULL) + { + node = cached.SetTo(fCurrentNodeOffset); + if (!node) + RETURN_ERROR(B_ERROR); + + // reset current key + fCurrentKey = direction == BPLUSTREE_FORWARD ? 0 : node->all_key_count; + } + else + { + // there are no nodes left, so turn back to the last key + fCurrentNodeOffset = savedNodeOffset; + fCurrentKey = direction == BPLUSTREE_FORWARD ? node->all_key_count : -1; + + return B_ENTRY_NOT_FOUND; + } + } + + if (node->all_key_count == 0) + RETURN_ERROR(B_ERROR); // B_ENTRY_NOT_FOUND ? + + uint16 length; + uint8 *keyStart = node->KeyAt(fCurrentKey,&length); + if (keyStart + length + sizeof(off_t) + sizeof(uint16) > (uint8 *)node + fTree->fNodeSize + || length > BPLUSTREE_MAX_KEY_LENGTH) { + fTree->fStream->GetVolume()->Panic(); + RETURN_ERROR(B_BAD_DATA); + } + + length = min_c(length,maxLength); + memcpy(key,keyStart,length); + + if (fTree->fHeader->data_type == BPLUSTREE_STRING_TYPE) // terminate string type + { + if (length == maxLength) + length--; + ((char *)key)[length] = '\0'; + } + *keyLength = length; + + off_t offset = node->Values()[fCurrentKey]; + + // duplicate fragments? + uint8 type = bplustree_node::LinkType(offset); + if (type == BPLUSTREE_DUPLICATE_FRAGMENT || type == BPLUSTREE_DUPLICATE_NODE) + { + fDuplicateNode = offset; + + node = cached.SetTo(bplustree_node::FragmentOffset(fDuplicateNode),false); + if (node == NULL) + RETURN_ERROR(B_ERROR); + + fIsFragment = type == BPLUSTREE_DUPLICATE_FRAGMENT; + + fNumDuplicates = node->CountDuplicates(offset,fIsFragment); + if (fNumDuplicates) + { + offset = node->DuplicateAt(offset,fIsFragment,0); + fDuplicate = 1; + if (duplicate) + *duplicate = 1; + } + else + { + // shouldn't happen, but we're dealing here with potentially corrupt disks... + fDuplicateNode = BPLUSTREE_NULL; + offset = 0; + } + } + *value = offset; + + return B_OK; +} + + +/** This is more or less a copy of BPlusTree::Find() - but it just + * sets the current position in the iterator, regardless of if the + * key could be found or not. + */ + +status_t +TreeIterator::Find(const uint8 *key, uint16 keyLength) +{ + if (fTree == NULL) + return B_INTERRUPTED; + if (keyLength < BPLUSTREE_MIN_KEY_LENGTH || keyLength > BPLUSTREE_MAX_KEY_LENGTH + || key == NULL) + RETURN_ERROR(B_BAD_VALUE); + + // lock access to stream + ReadLocked locked(fTree->fStream->Lock()); + + off_t nodeOffset = fTree->fHeader->root_node_pointer; + + CachedNode cached(fTree); + bplustree_node *node; + while ((node = cached.SetTo(nodeOffset)) != NULL) { + uint16 keyIndex = 0; + off_t nextOffset; + status_t status = fTree->FindKey(node,key,keyLength,&keyIndex,&nextOffset); + + if (node->overflow_link == BPLUSTREE_NULL) { + fCurrentNodeOffset = nodeOffset; + fCurrentKey = keyIndex - 1; + fDuplicateNode = BPLUSTREE_NULL; + + return status; + } else if (nextOffset == nodeOffset) + RETURN_ERROR(B_ERROR); + + nodeOffset = nextOffset; + } + RETURN_ERROR(B_ERROR); +} + + +void +TreeIterator::SkipDuplicates() +{ + fDuplicateNode = BPLUSTREE_NULL; +} + + +void +TreeIterator::Update(off_t offset,off_t nextOffset,uint16 keyIndex,uint16 splitAt,int8 change) +{ + if (offset != fCurrentNodeOffset) + return; + + if (nextOffset != BPLUSTREE_NULL) { + fCurrentNodeOffset = nextOffset; + if (splitAt <= fCurrentKey) { + fCurrentKey -= splitAt; + keyIndex -= splitAt; + } + } + + // Adjust fCurrentKey to point to the same key as before. + // Note, that if a key is inserted at the current position + // it won't be included in this tree transition. + if (keyIndex <= fCurrentKey) + fCurrentKey += change; + + // ToDo: duplicate handling! +} + + +void +TreeIterator::Stop() +{ + fTree = NULL; +} + + +#ifdef DEBUG +void +TreeIterator::Dump() +{ + __out("TreeIterator at %p:\n",this); + __out("\tfTree = %p\n",fTree); + __out("\tfCurrentNodeOffset = %Ld\n",fCurrentNodeOffset); + __out("\tfCurrentKey = %ld\n",fCurrentKey); + __out("\tfDuplicateNode = %Ld (%Ld, 0x%Lx)\n",bplustree_node::FragmentOffset(fDuplicateNode),fDuplicateNode,fDuplicateNode); + __out("\tfDuplicate = %u\n",fDuplicate); + __out("\tfNumDuplicates = %u\n",fNumDuplicates); + __out("\tfIsFragment = %s\n",fIsFragment ? "true" : "false"); +} +#endif + + +// #pragma mark - + + +void +bplustree_node::Initialize() +{ + left_link = right_link = overflow_link = BPLUSTREE_NULL; + all_key_count = 0; + all_key_length = 0; +} + + +uint8 * +bplustree_node::KeyAt(int32 index,uint16 *keyLength) const +{ + if (index < 0 || index > all_key_count) + return NULL; + + uint8 *keyStart = Keys(); + uint16 *keyLengths = KeyLengths(); + + *keyLength = keyLengths[index] - (index != 0 ? keyLengths[index - 1] : 0); + if (index > 0) + keyStart += keyLengths[index - 1]; + + return keyStart; +} + + +uint8 +bplustree_node::CountDuplicates(off_t offset,bool isFragment) const +{ + // the duplicate fragment handling is currently hard-coded to a node size + // of 1024 bytes - with future versions of BFS, this may be a problem + + if (isFragment) { + uint32 fragment = (NUM_FRAGMENT_VALUES + 1) * ((uint64)offset & 0x3ff); + + return ((off_t *)this)[fragment]; + } + return overflow_link; +} + + +off_t +bplustree_node::DuplicateAt(off_t offset,bool isFragment,int8 index) const +{ + uint32 start; + if (isFragment) + start = 8 * ((uint64)offset & 0x3ff); + else + start = 2; + + return ((off_t *)this)[start + 1 + index]; +} + + +/** Although the name suggests it, this function doesn't return the real + * used fragment count; at least, it can only count to two: it returns + * 0, if there is no fragment used, 1 if there is only one fragment + * used, and 2 if there are at least 2 fragments used. + */ + +int32 +bplustree_node::FragmentsUsed(uint32 nodeSize) +{ + uint32 used = 0; + for (int32 i = 0;i < nodeSize / ((NUM_FRAGMENT_VALUES + 1) * sizeof(off_t));i++) { + duplicate_array *array = FragmentAt(i); + if (array->count > 0 && ++used > 1) + return used; + } + return used; +} + + +// #pragma mark - + + +int32 +compareKeys(type_code type,const void *key1, int keyLength1, const void *key2, int keyLength2) +{ + // if one of the keys is NULL, bail out gracefully + if (key1 == NULL || key2 == NULL) + return -1; + + switch (type) + { + case B_STRING_TYPE: + { + int len = min_c(keyLength1,keyLength2); + int result = strncmp((const char *)key1,(const char *)key2,len); + + if (result == 0 + && !(((const char *)key1)[len] == '\0' && ((const char *)key2)[len] == '\0')) + result = keyLength1 - keyLength2; + + return result; + } + + case B_INT32_TYPE: + return *(int32 *)key1 - *(int32 *)key2; + + case B_UINT32_TYPE: + { + if (*(uint32 *)key1 == *(uint32 *)key2) + return 0; + else if (*(uint32 *)key1 > *(uint32 *)key2) + return 1; + + return -1; + } + + case B_INT64_TYPE: + { + if (*(int64 *)key1 == *(int64 *)key2) + return 0; + else if (*(int64 *)key1 > *(int64 *)key2) + return 1; + + return -1; + } + + case B_UINT64_TYPE: + { + if (*(uint64 *)key1 == *(uint64 *)key2) + return 0; + else if (*(uint64 *)key1 > *(uint64 *)key2) + return 1; + + return -1; + } + + case B_FLOAT_TYPE: + { + float result = *(float *)key1 - *(float *)key2; + if (result == 0.0f) + return 0; + + return (result < 0.0f) ? -1 : 1; + } + + case B_DOUBLE_TYPE: + { + double result = *(double *)key1 - *(double *)key2; + if (result == 0.0) + return 0; + + return (result < 0.0) ? -1 : 1; + } + } + return 0; +} + + diff --git a/src/add-ons/kernel/file_systems/befs/BPlusTree.h b/src/add-ons/kernel/file_systems/befs/BPlusTree.h new file mode 100644 index 0000000000..402db41f84 --- /dev/null +++ b/src/add-ons/kernel/file_systems/befs/BPlusTree.h @@ -0,0 +1,436 @@ +#ifndef B_PLUS_TREE_H +#define B_PLUS_TREE_H +/* BPlusTree - BFS B+Tree implementation +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** Roughly based on 'btlib' written by Marcus J. Ranum +** +** Copyright (c) 2001-2002 pinc Software. All Rights Reserved. +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include "bfs.h" +#include "Journal.h" +#include "Chain.h" + + +//****************** on-disk structures ******************** + +#define BPLUSTREE_NULL -1LL +#define BPLUSTREE_FREE -2LL + +struct bplustree_header { + uint32 magic; + uint32 node_size; + uint32 max_number_of_levels; + uint32 data_type; + off_t root_node_pointer; + off_t free_node_pointer; + off_t maximum_size; + + inline bool IsValidLink(off_t link); +}; + +#define BPLUSTREE_MAGIC 0x69f6c2e8 +#define BPLUSTREE_NODE_SIZE 1024 +#define BPLUSTREE_MAX_KEY_LENGTH 256 +#define BPLUSTREE_MIN_KEY_LENGTH 1 + +enum bplustree_types { + BPLUSTREE_STRING_TYPE = 0, + BPLUSTREE_INT32_TYPE = 1, + BPLUSTREE_UINT32_TYPE = 2, + BPLUSTREE_INT64_TYPE = 3, + BPLUSTREE_UINT64_TYPE = 4, + BPLUSTREE_FLOAT_TYPE = 5, + BPLUSTREE_DOUBLE_TYPE = 6 +}; + +struct sorted_array; +typedef sorted_array duplicate_array; + +struct bplustree_node { + off_t left_link; + off_t right_link; + off_t overflow_link; + uint16 all_key_count; + uint16 all_key_length; + + inline uint16 *KeyLengths() const; + inline off_t *Values() const; + inline uint8 *Keys() const; + inline int32 Used() const; + uint8 *KeyAt(int32 index,uint16 *keyLength) const; + + inline bool IsLeaf() const; + + void Initialize(); + uint8 CountDuplicates(off_t offset,bool isFragment) const; + off_t DuplicateAt(off_t offset,bool isFragment,int8 index) const; + int32 FragmentsUsed(uint32 nodeSize); + inline duplicate_array *FragmentAt(int8 index); + inline duplicate_array *DuplicateArray(); + + static inline uint8 LinkType(off_t link); + static inline off_t MakeLink(uint8 type, off_t link, uint32 fragmentIndex = 0); + static inline bool IsDuplicate(off_t link); + static inline off_t FragmentOffset(off_t link); + static inline uint32 FragmentIndex(off_t link); +}; + +//#define BPLUSTREE_NODE 0 +#define BPLUSTREE_DUPLICATE_NODE 2 +#define BPLUSTREE_DUPLICATE_FRAGMENT 3 + +#define NUM_FRAGMENT_VALUES 7 +#define NUM_DUPLICATE_VALUES 125 + +//************************************** + +enum bplustree_traversing { + BPLUSTREE_FORWARD = 1, + BPLUSTREE_BACKWARD = -1, + + BPLUSTREE_BEGIN = 0, + BPLUSTREE_END = 1 +}; + + +//****************** in-memory structures ******************** + +template class Stack; +class BPlusTree; +class TreeIterator; +class CachedNode; +class Inode; + +// needed for searching (utilizing a stack) +struct node_and_key { + off_t nodeOffset; + uint16 keyIndex; +}; + + +//***** Cache handling ***** + +class CachedNode { + public: + CachedNode(BPlusTree *tree) + : + fTree(tree), + fNode(NULL), + fBlock(NULL) + { + } + + CachedNode(BPlusTree *tree,off_t offset,bool check = true) + : + fTree(tree), + fNode(NULL), + fBlock(NULL) + { + SetTo(offset,check); + } + + ~CachedNode() + { + Unset(); + } + + bplustree_node *SetTo(off_t offset,bool check = true); + bplustree_header *SetToHeader(); + void Unset(); + + status_t Free(Transaction *transaction, off_t offset); + status_t Allocate(Transaction *transaction,bplustree_node **node,off_t *offset); + status_t WriteBack(Transaction *transaction); + + bplustree_node *Node() const { return fNode; } + + protected: + bplustree_node *InternalSetTo(off_t offset); + + BPlusTree *fTree; + bplustree_node *fNode; + uint8 *fBlock; + off_t fBlockNumber; +}; + + +//******** B+tree class ********* + +class BPlusTree { + public: + BPlusTree(Transaction *transaction,Inode *stream,int32 nodeSize = BPLUSTREE_NODE_SIZE); + BPlusTree(Inode *stream); + BPlusTree(); + ~BPlusTree(); + + status_t SetTo(Transaction *transaction,Inode *stream,int32 nodeSize = BPLUSTREE_NODE_SIZE); + status_t SetTo(Inode *stream); + status_t SetStream(Inode *stream); + + status_t InitCheck(); + status_t Validate(); + + status_t Remove(Transaction *transaction,const uint8 *key, uint16 keyLength, off_t value); + status_t Insert(Transaction *transaction,const uint8 *key, uint16 keyLength, off_t value); + + status_t Insert(Transaction *transaction,const char *key, off_t value); + status_t Insert(Transaction *transaction,int32 key, off_t value); + status_t Insert(Transaction *transaction,uint32 key, off_t value); + status_t Insert(Transaction *transaction,int64 key, off_t value); + status_t Insert(Transaction *transaction,uint64 key, off_t value); + status_t Insert(Transaction *transaction,float key, off_t value); + status_t Insert(Transaction *transaction,double key, off_t value); + + status_t Replace(Transaction *transaction, const uint8 *key, uint16 keyLength, off_t value); + status_t Find(const uint8 *key, uint16 keyLength, off_t *value); + + static int32 TypeCodeToKeyType(type_code code); + static int32 ModeToKeyType(mode_t mode); + + private: + int32 CompareKeys(const void *key1, int keylength1, const void *key2, int keylength2); + status_t FindKey(bplustree_node *node, const uint8 *key, uint16 keyLength, uint16 *index = NULL, off_t *next = NULL); + status_t SeekDown(Stack &stack, const uint8 *key, uint16 keyLength); + + status_t FindFreeDuplicateFragment(bplustree_node *node, CachedNode *cached, off_t *_offset, bplustree_node **_fragment,uint32 *_index); + status_t InsertDuplicate(Transaction *transaction,CachedNode *cached,bplustree_node *node,uint16 index,off_t value); + void InsertKey(bplustree_node *node, uint16 index, uint8 *key, uint16 keyLength, off_t value); + status_t SplitNode(bplustree_node *node, off_t nodeOffset, bplustree_node *other, off_t otherOffset, uint16 *_keyIndex, uint8 *key, uint16 *_keyLength, off_t *_value); + + status_t RemoveDuplicate(Transaction *transaction,bplustree_node *node,CachedNode *cached,uint16 keyIndex, off_t value); + void RemoveKey(bplustree_node *node, uint16 index); + + void UpdateIterators(off_t offset,off_t nextOffset,uint16 keyIndex,uint16 splitAt,int8 change); + void AddIterator(TreeIterator *iterator); + void RemoveIterator(TreeIterator *iterator); + + private: + friend TreeIterator; + friend CachedNode; + + Inode *fStream; + bplustree_header *fHeader; + CachedNode fCachedHeader; + int32 fNodeSize; + bool fAllowDuplicates; + status_t fStatus; + SimpleLock fIteratorLock; + Chain fIterators; +}; + + +//***** helper classes/functions ***** + +extern int32 compareKeys(type_code type,const void *key1, int keyLength1, const void *key2, int keyLength2); + +class TreeIterator { + public: + TreeIterator(BPlusTree *tree); + ~TreeIterator(); + + status_t Goto(int8 to); + status_t Traverse(int8 direction, void *key, uint16 *keyLength, uint16 maxLength, off_t *value,uint16 *duplicate = NULL); + status_t Find(const uint8 *key, uint16 keyLength); + + status_t Rewind(); + status_t GetNextEntry(void *key,uint16 *keyLength,uint16 maxLength,off_t *value,uint16 *duplicate = NULL); + status_t GetPreviousEntry(void *key,uint16 *keyLength,uint16 maxLength,off_t *value,uint16 *duplicate = NULL); + void SkipDuplicates(); + +#ifdef DEBUG + void Dump(); +#endif + + private: + BPlusTree *fTree; + + off_t fCurrentNodeOffset; // traverse position + int32 fCurrentKey; + off_t fDuplicateNode; + uint16 fDuplicate, fNumDuplicates; + bool fIsFragment; + + private: + friend Chain; + friend BPlusTree; + + void Update(off_t offset,off_t nextOffset,uint16 keyIndex,uint16 splitAt,int8 change); + void Stop(); + TreeIterator *fNext; +}; + +// BPlusTree's inline functions (most of them may not be needed) + +inline status_t +BPlusTree::Insert(Transaction *transaction,const char *key,off_t value) +{ + if (fHeader->data_type != BPLUSTREE_STRING_TYPE) + return B_BAD_TYPE; + return Insert(transaction,(uint8 *)key, strlen(key), value); +} + +inline status_t +BPlusTree::Insert(Transaction *transaction,int32 key, off_t value) +{ + if (fHeader->data_type != BPLUSTREE_INT32_TYPE) + return B_BAD_TYPE; + return Insert(transaction,(uint8 *)&key, sizeof(key), value); +} + +inline status_t +BPlusTree::Insert(Transaction *transaction,uint32 key, off_t value) +{ + if (fHeader->data_type != BPLUSTREE_UINT32_TYPE) + return B_BAD_TYPE; + return Insert(transaction,(uint8 *)&key, sizeof(key), value); +} + +inline status_t +BPlusTree::Insert(Transaction *transaction,int64 key, off_t value) +{ + if (fHeader->data_type != BPLUSTREE_INT64_TYPE) + return B_BAD_TYPE; + return Insert(transaction,(uint8 *)&key, sizeof(key), value); +} + +inline status_t +BPlusTree::Insert(Transaction *transaction,uint64 key, off_t value) +{ + if (fHeader->data_type != BPLUSTREE_UINT64_TYPE) + return B_BAD_TYPE; + return Insert(transaction,(uint8 *)&key, sizeof(key), value); +} + +inline status_t +BPlusTree::Insert(Transaction *transaction,float key, off_t value) +{ + if (fHeader->data_type != BPLUSTREE_FLOAT_TYPE) + return B_BAD_TYPE; + return Insert(transaction,(uint8 *)&key, sizeof(key), value); +} + +inline status_t +BPlusTree::Insert(Transaction *transaction,double key, off_t value) +{ + if (fHeader->data_type != BPLUSTREE_DOUBLE_TYPE) + return B_BAD_TYPE; + return Insert(transaction,(uint8 *)&key, sizeof(key), value); +} + + +/************************ TreeIterator inline functions ************************/ +// #pragma mark - + +inline status_t +TreeIterator::Rewind() +{ + return Goto(BPLUSTREE_BEGIN); +} + +inline status_t +TreeIterator::GetNextEntry(void *key,uint16 *keyLength,uint16 maxLength,off_t *value,uint16 *duplicate) +{ + return Traverse(BPLUSTREE_FORWARD,key,keyLength,maxLength,value,duplicate); +} + +inline status_t +TreeIterator::GetPreviousEntry(void *key,uint16 *keyLength,uint16 maxLength,off_t *value,uint16 *duplicate) +{ + return Traverse(BPLUSTREE_BACKWARD,key,keyLength,maxLength,value,duplicate); +} + +/************************ bplustree_header inline functions ************************/ +// #pragma mark - + + +inline bool +bplustree_header::IsValidLink(off_t link) +{ + return link == BPLUSTREE_NULL || (link > 0 && link <= maximum_size - node_size); +} + + +/************************ bplustree_node inline functions ************************/ +// #pragma mark - + + +inline uint16 * +bplustree_node::KeyLengths() const +{ + return (uint16 *)(((char *)this) + round_up(sizeof(bplustree_node) + all_key_length)); +} + +inline off_t * +bplustree_node::Values() const +{ + return (off_t *)((char *)KeyLengths() + all_key_count * sizeof(uint16)); +} + +inline uint8 * +bplustree_node::Keys() const +{ + return (uint8 *)this + sizeof(bplustree_node); +} + +inline int32 +bplustree_node::Used() const +{ + return round_up(sizeof(bplustree_node) + all_key_length) + all_key_count * (sizeof(uint16) + sizeof(off_t)); +} + +inline bool +bplustree_node::IsLeaf() const +{ + return overflow_link == BPLUSTREE_NULL; +} + + +inline duplicate_array * +bplustree_node::FragmentAt(int8 index) +{ + return (duplicate_array *)((off_t *)this + index * (NUM_FRAGMENT_VALUES + 1)); +} + + +inline duplicate_array * +bplustree_node::DuplicateArray() +{ + return (duplicate_array *)&this->overflow_link; +} + + +inline uint8 +bplustree_node::LinkType(off_t link) +{ + return *(uint64 *)&link >> 62; +} + +inline off_t +bplustree_node::MakeLink(uint8 type,off_t link,uint32 fragmentIndex) +{ + return ((off_t)type << 62) | (link & 0x3ffffffffffffc00LL) | (fragmentIndex & 0x3ff); +} + +inline bool +bplustree_node::IsDuplicate(off_t link) +{ + return (LinkType(link) & (BPLUSTREE_DUPLICATE_NODE | BPLUSTREE_DUPLICATE_FRAGMENT)) > 0; +} + +inline off_t +bplustree_node::FragmentOffset(off_t link) +{ + return link & 0x3ffffffffffffc00LL; +} + +inline uint32 +bplustree_node::FragmentIndex(off_t link) +{ + return (uint32)(link & 0x3ff); +} + +#endif /* B_PLUS_TREE_H */ diff --git a/src/add-ons/kernel/file_systems/befs/BlockAllocator.cpp b/src/add-ons/kernel/file_systems/befs/BlockAllocator.cpp new file mode 100644 index 0000000000..027f2fb1d5 --- /dev/null +++ b/src/add-ons/kernel/file_systems/befs/BlockAllocator.cpp @@ -0,0 +1,599 @@ +/* BlockAllocator - block bitmap handling and allocation policies +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include "cpp.h" +#include "Debug.h" +#include "BlockAllocator.h" +#include "Volume.h" +#include "Inode.h" + +#ifdef USER +# define spawn_kernel_thread spawn_thread +#endif + +// Things the BlockAllocator should do: + +// - find a range of blocks of a certain size nearby a specific position +// - allocating a unsharp range of blocks for pre-allocation +// - free blocks +// - know how to deal with each allocation, special handling for directories, +// files, symlinks, etc. (type sensitive allocation policies) + +// What makes the code complicated is the fact that we are not just reading +// in the whole bitmap and operate on that in memory - e.g. a 13 GB partition +// with a block size of 2048 bytes already has a 800kB bitmap, and the size +// of partitions will grow even more - so that's not an option. +// Instead we are reading in every block when it's used - since an allocation +// group can span several blocks in the block bitmap, the AllocationBlock +// class is there to make handling those easier. + +// The current implementation is very basic and will be heavily optimized +// in the future. +// Furthermore, the allocation policies used here (when they will be in place) +// should have some real world tests. + + +class AllocationBlock : public CachedBlock { + public: + AllocationBlock(Volume *volume); + + void Allocate(uint16 start,uint16 numBlocks = 0xffff); + void Free(uint16 start,uint16 numBlocks = 0xffff); + inline bool IsUsed(uint16 block); + + status_t SetTo(AllocationGroup &group,uint16 block); + + int32 NumBlockBits() const { return fNumBits; } + + private: + int32 fNumBits; +}; + + +class AllocationGroup { + public: + AllocationGroup(); + + void AddFreeRange(int32 start,int32 blocks); + bool IsFull() const { return fFreeBits == 0; } + + int32 fNumBits; + int32 fStart; + int32 fFirstFree,fLargest,fLargestFirst; + int32 fFreeBits; +}; + + +AllocationBlock::AllocationBlock(Volume *volume) + : CachedBlock(volume) +{ +} + + +status_t +AllocationBlock::SetTo(AllocationGroup &group, uint16 block) +{ + // 8 blocks per byte + fNumBits = fVolume->BlockSize() << 3; + // the last group may have less bits in the last block + if ((group.fNumBits % fNumBits) != 0) + fNumBits = group.fNumBits % fNumBits; + + return CachedBlock::SetTo(group.fStart + block) != NULL ? B_OK : B_ERROR; +} + + +bool +AllocationBlock::IsUsed(uint16 block) +{ + if (block > fNumBits) + return true; + return ((uint32 *)fBlock)[block >> 5] & (1UL << (block % 32)); +} + + +void +AllocationBlock::Allocate(uint16 start,uint16 numBlocks) +{ + start = start % fNumBits; + if (numBlocks == 0xffff) { + // allocate all blocks after "start" + numBlocks = fNumBits - start; + } else if (start + numBlocks > fNumBits) { + FATAL(("should allocate more blocks than there are in a block!\n")); + numBlocks = fNumBits - start; + } + + int32 block = start >> 5; + + while (numBlocks > 0) { + uint32 mask = 0; + for (int32 i = start % 32;i < 32 && numBlocks;i++,numBlocks--) + mask |= 1UL << (i % 32); + + ((uint32 *)fBlock)[block++] |= mask; + start = 0; + } +} + + +void +AllocationBlock::Free(uint16 start,uint16 numBlocks) +{ + start = start % fNumBits; + if (numBlocks == 0xffff) { + // free all blocks after "start" + numBlocks = fNumBits - start; + } else if (start + numBlocks > fNumBits) { + FATAL(("should free more blocks than there are in a block!\n")); + numBlocks = fNumBits - start; + } + + int32 block = start >> 5; + + while (numBlocks > 0) { + uint32 mask = 0; + for (int32 i = start % 32;i < 32 && numBlocks;i++,numBlocks--) + mask |= 1UL << (i % 32); + + ((uint32 *)fBlock)[block++] &= ~mask; + start = 0; + } +} + + +// #pragma mark - + + +AllocationGroup::AllocationGroup() + : + fFirstFree(-1), + fLargest(-1), + fLargestFirst(-1), + fFreeBits(0) +{ +} + + +void +AllocationGroup::AddFreeRange(int32 start, int32 blocks) +{ + D(if (blocks > 512) + PRINT(("range of %ld blocks starting at %ld\n",blocks,start))); + + if (fFirstFree == -1) + fFirstFree = start; + + if (fLargest < blocks) { + fLargest = blocks; + fLargestFirst = start; + } + + fFreeBits += blocks; +} + + +// #pragma mark - + + +BlockAllocator::BlockAllocator(Volume *volume) + : + fVolume(volume), + fGroups(NULL) +{ +} + + +BlockAllocator::~BlockAllocator() +{ + delete[] fGroups; +} + + +status_t +BlockAllocator::Initialize() +{ + if (fLock.InitCheck() < B_OK) + return B_ERROR; + + fNumGroups = fVolume->AllocationGroups(); + fBlocksPerGroup = fVolume->SuperBlock().blocks_per_ag; + fGroups = new AllocationGroup[fNumGroups]; + if (fGroups == NULL) + return B_NO_MEMORY; + + thread_id id = spawn_kernel_thread((thread_func)BlockAllocator::initialize,"bfs block allocator",B_LOW_PRIORITY,(void *)this); + if (id < B_OK) + return initialize(this); + + return resume_thread(id); +} + + +status_t +BlockAllocator::initialize(BlockAllocator *allocator) +{ + Locker lock(allocator->fLock); + + Volume *volume = allocator->fVolume; + uint32 blocks = allocator->fBlocksPerGroup; + uint32 numBits = 8 * blocks * volume->BlockSize(); + off_t freeBlocks = 0; + + uint32 *buffer = (uint32 *)malloc(numBits >> 3); + if (buffer == NULL) + RETURN_ERROR(B_NO_MEMORY); + + AllocationGroup *groups = allocator->fGroups; + off_t offset = 1; + int32 num = allocator->fNumGroups; + + for (int32 i = 0;i < num;i++) { + if (cached_read(volume->Device(),offset,buffer,blocks,volume->BlockSize()) < B_OK) + break; + + // the last allocation group may contain less blocks than the others + groups[i].fNumBits = i == num - 1 ? allocator->fVolume->NumBlocks() - i * numBits : numBits; + groups[i].fStart = offset; + + // finds all free ranges in this allocation group + int32 start,range = 0; + int32 size = groups[i].fNumBits,num = 0; + + for (int32 k = 0;k < (size >> 2);k++) { + for (int32 j = 0;j < 32 && num < size;j++,num++) { + if (buffer[k] & (1UL << j)) { + if (range > 0) { + groups[i].AddFreeRange(start,range); + range = 0; + } + } else if (range++ == 0) + start = num; + } + } + if (range) + groups[i].AddFreeRange(start,range); + + freeBlocks += groups[i].fFreeBits; + + offset += blocks; + } + free(buffer); + + off_t usedBlocks = volume->NumBlocks() - freeBlocks; + if (volume->UsedBlocks() != usedBlocks) { + // If the disk in a dirty state at mount time, it's + // normal that the values don't match + INFORM(("volume reports %Ld used blocks, correct is %Ld\n",volume->UsedBlocks(),usedBlocks)); + volume->SuperBlock().used_blocks = usedBlocks; + } + + return B_OK; +} + + +status_t +BlockAllocator::AllocateBlocks(Transaction *transaction,int32 group,uint16 start,uint16 maximum,uint16 minimum, block_run &run) +{ + AllocationBlock cached(fVolume); + Locker lock(fLock); + + // the first scan through all allocation groups will look for the + // wanted maximum of blocks, the second scan will just look to + // satisfy the minimal requirement + uint16 numBlocks = maximum; + + for (int32 i = 0;i < fNumGroups * 2;i++,group++,start = 0) { + group = group % fNumGroups; + + if (start >= fGroups[group].fNumBits || fGroups[group].IsFull()) + continue; + + if (i >= fNumGroups) { + // if the minimum is the same as the maximum, it's not necessary to + // search for in the allocation groups a second time + if (maximum == minimum) + return B_DEVICE_FULL; + + numBlocks = minimum; + } + + // The wanted maximum is smaller than the largest free block in the group + // or already smaller than the minimum + // ToDo: disabled because it's currently not maintained after the first allocation + //if (numBlocks > fGroups[group].fLargest) + // continue; + + if (start < fGroups[group].fFirstFree) + start = fGroups[group].fFirstFree; + + // there may be more than one block per allocation group - and + // we iterate through it to find a place for the allocation. + // (one allocation can't exceed one allocation group) + + uint32 block = start / (fVolume->BlockSize() << 3); + int32 range = 0, rangeStart = 0,rangeBlock = 0; + + for (;block < fBlocksPerGroup;block++) { + if (cached.SetTo(fGroups[group],block) < B_OK) + RETURN_ERROR(B_ERROR); + + // find a block large enough to hold the allocation + for (int32 bit = start % cached.NumBlockBits();bit < cached.NumBlockBits();bit++) { + if (!cached.IsUsed(bit)) { + if (range == 0) { + // start new range + rangeStart = block * cached.NumBlockBits() + bit; + rangeBlock = block; + } + + // have we found a range large enough to hold numBlocks? + if (++range >= maximum) + break; + } else if (i >= fNumGroups && range >= minimum) { + // we have found a block larger than the required minimum (second pass) + break; + } else { + // end of a range + range = 0; + } + } + + // if we found a suitable block, mark the blocks as in use, and write + // the updated block bitmap back to disk + if (range >= numBlocks) { + // adjust allocation size + if (numBlocks < maximum) + numBlocks = range; + + // Update the allocation group info + // Note, the fFirstFree block doesn't have to be really free + if (rangeStart == fGroups[group].fFirstFree) + fGroups[group].fFirstFree = rangeStart + numBlocks; + fGroups[group].fFreeBits -= numBlocks; + + if (block != rangeBlock) { + // allocate the part that's in the current block + cached.Allocate(0,(rangeStart + numBlocks) % cached.NumBlockBits()); + if (cached.WriteBack(transaction) < B_OK) + RETURN_ERROR(B_ERROR); + + // set the blocks in the previous block + if (cached.SetTo(fGroups[group],block - 1) < B_OK) + cached.Allocate(rangeStart); + else + RETURN_ERROR(B_ERROR); + } else { + // just allocate the bits in the current block + cached.Allocate(rangeStart,numBlocks); + } + run.allocation_group = group; + run.start = rangeStart; + run.length = numBlocks; + + fVolume->SuperBlock().used_blocks += numBlocks; + // We are not writing back the disk's super block - it's + // either done by the journaling code, or when the disk + // is unmounted. + // If the value is not correct at mount time, it will be + // fixed anyway. + + return cached.WriteBack(transaction); + } + + // start from the beginning of the next block + start = 0; + } + } + return B_DEVICE_FULL; +} + + +status_t +BlockAllocator::AllocateForInode(Transaction *transaction,const block_run *parent, mode_t type, block_run &run) +{ + // apply some allocation policies here (AllocateBlocks() will break them + // if necessary) - we will start with those described in Dominic Giampaolo's + // "Practical File System Design", and see how good they work + + // files are going in the same allocation group as its parent, sub-directories + // will be inserted 8 allocation groups after the one of the parent + uint16 group = parent->allocation_group; + if ((type & (S_DIRECTORY | S_INDEX_DIR | S_ATTR_DIR)) == S_DIRECTORY) + group += 8; + + return AllocateBlocks(transaction,group,0,1,1,run); +} + + +status_t +BlockAllocator::Allocate(Transaction *transaction,const Inode *inode, off_t numBlocks, block_run &run, uint16 minimum) +{ + if (numBlocks <= 0) + return B_ERROR; + + // one block_run can't hold more data than it is in one allocation group + if (numBlocks > fGroups[0].fNumBits) + numBlocks = fGroups[0].fNumBits; + + // apply some allocation policies here (AllocateBlocks() will break them + // if necessary) + uint16 group = inode->BlockRun().allocation_group; + uint16 start = 0; + + // are there already allocated blocks? (then just allocate near the last) + if (inode->Size() > 0) { + data_stream *data = &inode->Node()->data; + // we currently don't care for when the data stream is + // already grown into the indirect ranges + if (data->max_double_indirect_range == 0 + && data->max_indirect_range == 0) { + int32 last = 0; + for (;last < NUM_DIRECT_BLOCKS - 1;last++) + if (data->direct[last + 1].IsZero()) + break; + + group = data->direct[last].allocation_group; + start = data->direct[last].start + data->direct[last].length; + } + } else if (inode->IsDirectory()) { + // directory data will go in the same allocation group as the inode is in + // but after the inode data + start = inode->BlockRun().start; + } else { + // file data will start in the next allocation group + group = inode->BlockRun().allocation_group + 1; + } + + return AllocateBlocks(transaction,group,start,numBlocks,minimum,run); +} + + +status_t +BlockAllocator::Free(Transaction *transaction,block_run &run) +{ + Locker lock(fLock); + + int32 group = run.allocation_group; + uint16 start = run.start; + uint16 length = run.length; + + // doesn't use Volume::IsValidBlockRun() here because it can check better + // against the group size (the last group may have a different length) + if (group < 0 || group >= fNumGroups + || start > fGroups[group].fNumBits + || start + length > fGroups[group].fNumBits + || length == 0) { + FATAL(("someone tried to free an invalid block_run (%ld, %u, %u)\n",group,start,length)); + return B_BAD_VALUE; + } + // check if someone tries to free reserved areas at the beginning of the drive + if (group == 0 && start < fVolume->Log().start + fVolume->Log().length) { + FATAL(("someone tried to free a reserved block_run (%ld, %u, %u)\n",group,start,length)); + return B_BAD_VALUE; + } +#ifdef DEBUG + if (CheckBlockRun(run) < B_OK) + return B_BAD_DATA; +#endif + + AllocationBlock cached(fVolume); + + uint32 block = run.start / (fVolume->BlockSize() << 3); + + if (fGroups[group].fFirstFree > start) + fGroups[group].fFirstFree = start; + fGroups[group].fFreeBits += length; + + for (;block < fBlocksPerGroup;block++) { + if (cached.SetTo(fGroups[group],block) < B_OK) + RETURN_ERROR(B_IO_ERROR); + + uint16 freeLength = length; + if (start + length > cached.NumBlockBits()) + freeLength = cached.NumBlockBits() - start; + + cached.Free(start,freeLength); + + if (cached.WriteBack(transaction) < B_OK) + return B_IO_ERROR; + + length -= freeLength; + if (length <= 0) + break; + + start = 0; + } + + fVolume->SuperBlock().used_blocks -= run.length; + return B_OK; +} + +#ifdef DEBUG +#include "BPlusTree.h" + +status_t +BlockAllocator::CheckBlockRun(block_run run) +{ + uint32 block = run.start / (fVolume->BlockSize() << 3); + uint32 start = run.start; + uint32 pos = 0; + + AllocationBlock cached(fVolume); + + for (;block < fBlocksPerGroup;block++) { + if (cached.SetTo(fGroups[run.allocation_group],block) < B_OK) + RETURN_ERROR(B_IO_ERROR); + + start = start % cached.NumBlockBits(); + while (pos < run.length && start + pos < cached.NumBlockBits()) { + if (!cached.IsUsed(start + pos)) { + PRINT(("block_run(%ld,%u,%u) is only partially allocated!\n",run.allocation_group,run.start,run.length)); + fVolume->Panic(); + return B_BAD_DATA; + } + pos++; + } + start = 0; + } + return B_OK; +} + + +status_t +BlockAllocator::CheckInode(Inode *inode) +{ + status_t status = CheckBlockRun(inode->BlockRun()); + if (status < B_OK) + return status; + + // only checks the direct range for now... + + data_stream *data = &inode->Node()->data; + for (int32 i = 0;i < NUM_DIRECT_BLOCKS;i++) { + if (data->direct[i].IsZero()) + break; + + status = CheckBlockRun(data->direct[i]); + if (status < B_OK) + return status; + } + return B_OK; +} + + +status_t +BlockAllocator::Check(Inode *inode) +{ + if (!inode || !inode->IsDirectory()) + return B_BAD_VALUE; + + BPlusTree *tree; + status_t status = inode->GetTree(&tree); + if (status < B_OK) + return status; + + TreeIterator iterator(tree); + char key[BPLUSTREE_MAX_KEY_LENGTH]; + uint16 length; + off_t offset; + while (iterator.GetNextEntry(key,&length,BPLUSTREE_MAX_KEY_LENGTH,&offset) == B_OK) { + Vnode vnode(fVolume,offset); + Inode *entry; + if (vnode.Get(&entry) < B_OK) { + FATAL(("could not get inode in tree at: %Ld\n",offset)); + continue; + } + block_run run = entry->BlockRun(); + PRINT(("check allocations of inode \"%s\" (%ld,%u,%u)\n",key,run.allocation_group,run.start,run.length)); + status = CheckInode(entry); + if (status < B_OK) + return status; + } + return B_OK; +} +#endif /* DEBUG */ diff --git a/src/add-ons/kernel/file_systems/befs/BlockAllocator.h b/src/add-ons/kernel/file_systems/befs/BlockAllocator.h new file mode 100644 index 0000000000..8f2ea0ba26 --- /dev/null +++ b/src/add-ons/kernel/file_systems/befs/BlockAllocator.h @@ -0,0 +1,49 @@ +#ifndef BLOCK_ALLOCATOR_H +#define BLOCK_ALLOCATOR_H +/* BlockAllocator - block bitmap handling and allocation policies +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include + + +class AllocationGroup; +class Transaction; +class Volume; +class Inode; +struct disk_super_block; +struct block_run; + + +class BlockAllocator { + public: + BlockAllocator(Volume *volume); + ~BlockAllocator(); + + status_t Initialize(); + + status_t AllocateForInode(Transaction *transaction,const block_run *parent,mode_t type,block_run &run); + status_t Allocate(Transaction *transaction,const Inode *inode,off_t numBlocks,block_run &run,uint16 minimum = 1); + status_t Free(Transaction *transaction,block_run &run); + + status_t AllocateBlocks(Transaction *transaction,int32 group, uint16 start, uint16 numBlocks, uint16 minimum, block_run &run); + +#ifdef DEBUG + status_t CheckBlockRun(block_run run); + status_t CheckInode(Inode *inode); + status_t Check(Inode *inode); +#endif + + private: + static status_t initialize(BlockAllocator *); + + Volume *fVolume; + Benaphore fLock; + AllocationGroup *fGroups; + int32 fNumGroups,fBlocksPerGroup; +}; + +#endif /* BLOCK_ALLOCATOR_H */ diff --git a/src/add-ons/kernel/file_systems/befs/Chain.h b/src/add-ons/kernel/file_systems/befs/Chain.h new file mode 100644 index 0000000000..7d7e3e87ef --- /dev/null +++ b/src/add-ons/kernel/file_systems/befs/Chain.h @@ -0,0 +1,55 @@ +#ifndef CHAIN_H +#define CHAIN_H +/* Chain - a chain implementation; it's used for the callback management +** throughout the code (currently TreeIterator, and AttributeIterator). +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ + + +/** The Link class you want to use with the Chain class needs to have + * a "fNext" member which is accessable from within the Chain class. + */ + +template class Chain { + public: + Chain() + : + fFirst(NULL) + { + } + + void Add(Link *link) + { + link->fNext = fFirst; + fFirst = link; + } + + void Remove(Link *link) + { + // search list for the correct callback to remove + Link *last = NULL,*entry; + for (entry = fFirst;link != entry;entry = entry->fNext) + last = entry; + if (link == entry) { + if (last) + last->fNext = link->fNext; + else + fFirst = link->fNext; + } + } + + Link *Next(Link *last) + { + if (last == NULL) + return fFirst; + + return last->fNext; + } + + private: + Link *fFirst; +}; + +#endif /* CHAIN_H */ diff --git a/src/add-ons/kernel/file_systems/befs/Debug.cpp b/src/add-ons/kernel/file_systems/befs/Debug.cpp new file mode 100644 index 0000000000..89bed31f9a --- /dev/null +++ b/src/add-ons/kernel/file_systems/befs/Debug.cpp @@ -0,0 +1,241 @@ +/* Debug - debug stuff +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** Some code is based on work previously done by Marcus Overhagen +** +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include "Debug.h" +#include "BPlusTree.h" + +#include + +#include + +#define Print __out + + +char * +get_tupel(uint32 id) +{ + static unsigned char tupel[5]; + + tupel[0] = 0xff & (id >> 24); + tupel[1] = 0xff & (id >> 16); + tupel[2] = 0xff & (id >> 8); + tupel[3] = 0xff & (id); + tupel[4] = 0; + for (int16 i = 0;i < 4;i++) + if (tupel[i] < ' ' || tupel[i] > 128) + tupel[i] = '.'; + + return (char *)tupel; +} + + +void +dump_block_run(const char *prefix,block_run &run) +{ + Print("%s(%ld, %d, %d)\n",prefix,run.allocation_group,run.start,run.length); +} + + +void +dump_super_block(disk_super_block *superBlock) +{ + Print("disk_super_block:\n"); + Print(" name = %s\n",superBlock->name); + Print(" magic1 = %#08lx (%s) %s\n",superBlock->magic1, get_tupel(superBlock->magic1), (superBlock->magic1 == SUPER_BLOCK_MAGIC1 ? "valid" : "INVALID")); + Print(" fs_byte_order = %#08lx (%s)\n",superBlock->fs_byte_order, get_tupel(superBlock->fs_byte_order)); + Print(" block_size = %lu\n",superBlock->block_size); + Print(" block_shift = %lu\n",superBlock->block_shift); + Print(" num_blocks = %Lu\n",superBlock->num_blocks); + Print(" used_blocks = %Lu\n",superBlock->used_blocks); + Print(" inode_size = %lu\n",superBlock->inode_size); + Print(" magic2 = %#08lx (%s) %s\n",superBlock->magic2, get_tupel(superBlock->magic2), (superBlock->magic2 == (int)SUPER_BLOCK_MAGIC2 ? "valid" : "INVALID")); + Print(" blocks_per_ag = %lu\n",superBlock->blocks_per_ag); + Print(" ag_shift = %lu (%ld bytes)\n",superBlock->ag_shift, 1LL << superBlock->ag_shift); + Print(" num_ags = %lu\n",superBlock->num_ags); + Print(" flags = %#08lx (%s)\n",superBlock->flags, get_tupel(superBlock->flags)); + dump_block_run(" log_blocks = ",superBlock->log_blocks); + Print(" log_start = %Lu\n",superBlock->log_start); + Print(" log_end = %Lu\n",superBlock->log_end); + Print(" magic3 = %#08lx (%s) %s\n",superBlock->magic3, get_tupel(superBlock->magic3), (superBlock->magic3 == SUPER_BLOCK_MAGIC3 ? "valid" : "INVALID")); + dump_block_run(" root_dir = ",superBlock->root_dir); + dump_block_run(" indices = ",superBlock->indices); +} + + +void +dump_data_stream(data_stream *stream) +{ + Print("data_stream:\n"); + for (int i = 0; i < NUM_DIRECT_BLOCKS; i++) { + if (!stream->direct[i].IsZero()) { + Print(" direct[%02d] = ",i); + dump_block_run("",stream->direct[i]); + } + } + Print(" max_direct_range = %Lu\n",stream->max_direct_range); + + if (!stream->indirect.IsZero()) + dump_block_run(" indirect = ",stream->indirect); + + Print(" max_indirect_range = %Lu\n",stream->max_indirect_range); + + if (!stream->double_indirect.IsZero()) + dump_block_run(" double_indirect = ",stream->double_indirect); + + Print(" max_double_indirect_range = %Lu\n",stream->max_double_indirect_range); + Print(" size = %Lu\n",stream->size); +} + + +void +dump_inode(bfs_inode *inode) +{ + Print("inode:\n"); + Print(" magic1 = %08lx (%s) %s\n",inode->magic1, + get_tupel(inode->magic1), (inode->magic1 == INODE_MAGIC1 ? "valid" : "INVALID")); + dump_block_run( " inode_num = ",inode->inode_num); + Print(" uid = %lu\n",inode->uid); + Print(" gid = %lu\n",inode->gid); + Print(" mode = %08lx\n",inode->mode); + Print(" flags = %08lx\n",inode->flags); + Print(" create_time = %Ld (%Ld)\n",inode->create_time,inode->create_time >> INODE_TIME_SHIFT); + Print(" last_modified_time = %Ld (%Ld)\n",inode->last_modified_time,inode->last_modified_time >> INODE_TIME_SHIFT); + dump_block_run( " parent = ",inode->parent); + dump_block_run( " attributes = ",inode->attributes); + Print(" type = %lu\n",inode->type); + Print(" inode_size = %lu\n",inode->inode_size); + Print(" etc = %#08lx\n",inode->etc); + Print(" short_symlink = %s\n", + S_ISLNK(inode->mode) && (inode->flags & INODE_LONG_SYMLINK) == 0? inode->short_symlink : "-"); + dump_data_stream(&(inode->data)); + Print(" --\n pad[0] = %08lx\n",inode->pad[0]); + Print(" pad[1] = %08lx\n",inode->pad[1]); + Print(" pad[2] = %08lx\n",inode->pad[2]); + Print(" pad[3] = %08lx\n",inode->pad[3]); +} + + +void +dump_bplustree_header(bplustree_header *header) +{ + Print("bplustree_header:\n"); + Print(" magic = %#08lx (%s) %s\n",header->magic, + get_tupel(header->magic), (header->magic == BPLUSTREE_MAGIC ? "valid" : "INVALID")); + Print(" node_size = %lu\n",header->node_size); + Print(" max_number_of_levels = %lu\n",header->max_number_of_levels); + Print(" data_type = %lu\n",header->data_type); + Print(" root_node_pointer = %Ld\n",header->root_node_pointer); + Print(" free_node_pointer = %Ld\n",header->free_node_pointer); + Print(" maximum_size = %Lu\n",header->maximum_size); +} + + +#define DUMPED_BLOCK_SIZE 16 + +void +dump_block(const char *buffer,int size) +{ + for(int i = 0;i < size;) { + int start = i; + + for(;i < start+DUMPED_BLOCK_SIZE;i++) { + if (!(i % 4)) + Print(" "); + + if (i >= size) + Print(" "); + else + Print("%02x",*(unsigned char *)(buffer+i)); + } + Print(" "); + + for(i = start;i < start + DUMPED_BLOCK_SIZE;i++) { + if (i < size) { + char c = *(buffer+i); + + if (c < 30) + Print("."); + else + Print("%c",c); + } + else + break; + } + Print("\n"); + } +} + + +void +dump_bplustree_node(bplustree_node *node,bplustree_header *header,Volume *volume) +{ + Print("bplustree_node:\n"); + Print(" left_link = %Ld\n",node->left_link); + Print(" right_link = %Ld\n",node->right_link); + Print(" overflow_link = %Ld\n",node->overflow_link); + Print(" all_key_count = %u\n",node->all_key_count); + Print(" all_key_length = %u\n",node->all_key_length); + + if (header == NULL) + return; + + if (node->all_key_count > node->all_key_length + || uint32(node->all_key_count * 10) > (uint32)header->node_size + || node->all_key_count == 0) { + Print("\n"); + dump_block((char *)node,header->node_size/*,sizeof(off_t)*/); + return; + } + + Print("\n"); + for (int32 i = 0;i < node->all_key_count;i++) { + uint16 length; + char buffer[256],*key = (char *)node->KeyAt(i,&length); + if (length > 255 || length == 0) { + Print(" %2ld. Invalid length (%u)!!\n",i,length); + dump_block((char *)node,header->node_size/*,sizeof(off_t)*/); + break; + } + memcpy(buffer,key,length); + buffer[length] = '\0'; + + off_t *value = node->Values() + i; + if ((uint32)value < (uint32)node || (uint32)value > (uint32)node + header->node_size) + Print(" %2ld. Invalid Offset!!\n",i); + else { + Print(" %2ld. ",i); + if (header->data_type == BPLUSTREE_STRING_TYPE) + Print("\"%s\"",buffer); + else if (header->data_type == BPLUSTREE_INT32_TYPE) + Print("int32 = %ld (0x%lx)",*(int32 *)&buffer,*(int32 *)&buffer); + else if (header->data_type == BPLUSTREE_UINT32_TYPE) + Print("uint32 = %lu (0x%lx)",*(uint32 *)&buffer,*(uint32 *)&buffer); + else if (header->data_type == BPLUSTREE_INT64_TYPE) + Print("int64 = %Ld (0x%Lx)",*(int64 *)&buffer,*(int64 *)&buffer); + else + Print("???"); + + off_t offset = *value & 0x3fffffffffffffffLL; + Print(" (%d bytes) -> %Ld",length,offset); + if (volume != NULL) + { + block_run run = volume->ToBlockRun(offset); + Print(" (%ld, %d)",run.allocation_group,run.start); + } + if (bplustree_node::LinkType(*value) == BPLUSTREE_DUPLICATE_FRAGMENT) + Print(" (duplicate fragment %Ld)\n",*value & 0x3ff); + else if (bplustree_node::LinkType(*value) == BPLUSTREE_DUPLICATE_NODE) + Print(" (duplicate node)\n"); + else + Print("\n"); + } + } +} + + diff --git a/src/add-ons/kernel/file_systems/befs/Debug.h b/src/add-ons/kernel/file_systems/befs/Debug.h new file mode 100644 index 0000000000..dfde5cdc92 --- /dev/null +++ b/src/add-ons/kernel/file_systems/befs/Debug.h @@ -0,0 +1,74 @@ +#ifndef DEBUG_H +#define DEBUG_H +/* Debug - debug stuff +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include +#ifdef USER +# include +# define __out printf +#else +# include +# define __out dprintf +#endif + +// Short overview over the debug output macros: +// PRINT() +// is for general messages that very unlikely should appear in a release build +// FATAL() +// this is for fatal messages, when something has really gone wrong +// INFORM() +// general information, as disk size, etc. +// REPORT_ERROR(status_t) +// prints out error information +// RETURN_ERROR(status_t) +// calls REPORT_ERROR() and return the value +// D() +// the statements in D() are only included if DEBUG is defined + +#ifdef DEBUG + #define PRINT(x) { __out("bfs: "); __out x; } + #define REPORT_ERROR(status) __out("bfs: %s:%ld: %s\n",__FUNCTION__,__LINE__,strerror(status)); + #define RETURN_ERROR(err) { status_t _status = err; if (_status < B_OK) REPORT_ERROR(_status); return _status;} + #define FATAL(x) { __out("bfs: "); __out x; } + #define INFORM(x) { __out("bfs: "); __out x; } +// #define FUNCTION() __out("bfs: %s()\n",__FUNCTION__); + #define FUNCTION_START(x) { __out("bfs: %s() ",__FUNCTION__); __out x; } + #define FUNCTION() ; +// #define FUNCTION_START(x) ; + #define D(x) {x;}; +#else + #define PRINT(x) ; + #define REPORT_ERROR(status) ; + #define RETURN_ERROR(status) return status; + #define FATAL(x) { __out("bfs: "); __out x; } + #define INFORM(x) { __out("bfs: "); __out x; } + #define FUNCTION() ; + #define FUNCTION_START(x) ; + #define D(x) ; +#endif + +#ifdef DEBUG + struct block_run; + struct bplustree_header; + struct bplustree_node; + struct data_stream; + struct bfs_inode; + struct disk_super_block; + class Volume; + + // some structure dump functions + extern void dump_block_run(const char *prefix, block_run &run); + extern void dump_super_block(disk_super_block *superBlock); + extern void dump_data_stream(data_stream *stream); + extern void dump_inode(bfs_inode *inode); + extern void dump_bplustree_header(bplustree_header *header); + extern void dump_bplustree_node(bplustree_node *node,bplustree_header *header = NULL,Volume *volume = NULL); + extern void dump_block(const char *buffer, int size); +#endif + +#endif /* DEBUG_H */ diff --git a/src/add-ons/kernel/file_systems/befs/Index.cpp b/src/add-ons/kernel/file_systems/befs/Index.cpp new file mode 100644 index 0000000000..48a0d07727 --- /dev/null +++ b/src/add-ons/kernel/file_systems/befs/Index.cpp @@ -0,0 +1,335 @@ +/* Index - index access functions +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include "Debug.h" +#include "cpp.h" +#include "Index.h" +#include "Volume.h" +#include "Inode.h" +#include "BPlusTree.h" + +#include + + +Index::Index(Volume *volume) + : + fVolume(volume), + fNode(NULL) +{ +} + + +Index::~Index() +{ + if (fNode == NULL) + return; + + put_vnode(fVolume->ID(),fNode->ID()); +} + + +void +Index::Unset() +{ + if (fNode == NULL) + return; + + put_vnode(fVolume->ID(),fNode->ID()); + fNode = NULL; +} + + +status_t +Index::SetTo(const char *name) +{ + // remove the old node, if the index is set for the second time + Unset(); + + Inode *indices = fVolume->IndicesNode(); + if (indices == NULL) + return B_ENTRY_NOT_FOUND; + + BPlusTree *tree; + if (indices->GetTree(&tree) != B_OK) + return B_BAD_VALUE; + + vnode_id id; + status_t status = tree->Find((uint8 *)name,(uint16)strlen(name),&id); + if (status != B_OK) + return status; + + if (get_vnode(fVolume->ID(),id,(void **)&fNode) != B_OK) + return B_ENTRY_NOT_FOUND; + + if (fNode == NULL) { + FATAL(("fatal error at Index::InitCheck(), get_vnode() returned NULL pointer\n")); + put_vnode(fVolume->ID(),id); + return B_ERROR; + } + fName = name; + // only stores the pointer, so it assumes that it will stay constant + // in further comparisons (currently only used in Index::Update()) + + return B_OK; +} + + +uint32 +Index::Type() +{ + if (fNode == NULL) + return 0; + + switch (fNode->Mode() & (S_STR_INDEX | S_INT_INDEX | S_UINT_INDEX | S_LONG_LONG_INDEX | + S_ULONG_LONG_INDEX | S_FLOAT_INDEX | S_DOUBLE_INDEX)) { + case S_INT_INDEX: + return B_INT32_TYPE; + case S_UINT_INDEX: + return B_UINT32_TYPE; + case S_LONG_LONG_INDEX: + return B_INT64_TYPE; + case S_ULONG_LONG_INDEX: + return B_UINT64_TYPE; + case S_FLOAT_INDEX: + return B_FLOAT_TYPE; + case S_DOUBLE_INDEX: + return B_DOUBLE_TYPE; + case S_STR_INDEX: + return B_STRING_TYPE; + } + FATAL(("index has unknown type!\n")); + return 0; +} + + +size_t +Index::KeySize() +{ + if (fNode == NULL) + return 0; + + int32 mode = fNode->Mode() & (S_STR_INDEX | S_INT_INDEX | S_UINT_INDEX | S_LONG_LONG_INDEX | + S_ULONG_LONG_INDEX | S_FLOAT_INDEX | S_DOUBLE_INDEX); + + if (mode == S_STR_INDEX) + // string indices don't have a fixed key size + return 0; + + switch (mode) { + case S_INT_INDEX: + case S_UINT_INDEX: + return sizeof(int32); + case S_LONG_LONG_INDEX: + case S_ULONG_LONG_INDEX: + return sizeof(int64); + case S_FLOAT_INDEX: + return sizeof(float); + case S_DOUBLE_INDEX: + return sizeof(double); + } + FATAL(("index has unknown type!\n")); + return 0; +} + + +status_t +Index::Create(Transaction *transaction,const char *name,uint32 type) +{ + Unset(); + + int32 mode = 0; + switch (type) { + case B_INT32_TYPE: + mode = S_INT_INDEX; + break; + case B_UINT32_TYPE: + mode = S_UINT_INDEX; + break; + case B_INT64_TYPE: + mode = S_LONG_LONG_INDEX; + break; + case B_UINT64_TYPE: + mode = S_ULONG_LONG_INDEX; + break; + case B_FLOAT_TYPE: + mode = S_FLOAT_INDEX; + break; + case B_DOUBLE_TYPE: + mode = S_DOUBLE_INDEX; + break; + case B_STRING_TYPE: + mode = S_STR_INDEX; + break; + default: + return B_BAD_TYPE; + } + + status_t status; + + // do we need to create the index directory first? + if (fVolume->IndicesNode() == NULL) { + if ((status = fVolume->CreateIndicesRoot(transaction)) < B_OK) + RETURN_ERROR(status); + } + + vnode_id id; + status = Inode::Create(transaction,fVolume->IndicesNode(),name,S_INDEX_DIR | S_DIRECTORY | mode,0,type,&id); + if (status == B_OK) { + // since Inode::Create() lets the created inode open if "id" is specified, + // we don't need to call Vnode::Keep() here + Vnode vnode(fVolume,id); + return vnode.Get(&fNode); + } + return status; +} + + +/** Updates the specified index, the oldKey will be removed from, the newKey + * inserted into the tree. + * If the method returns B_BAD_INDEX, it means the index couldn't be found - + * the most common reason will be that the index doesn't exist. + * You may not want to let the whole transaction fail because of that. + */ + +status_t +Index::Update(Transaction *transaction,const char *name,int32 type,const uint8 *oldKey,uint16 oldLength,const uint8 *newKey,uint16 newLength,Inode *inode) +{ + if (name == NULL + || oldKey == NULL && newKey == NULL + || oldKey != NULL && oldLength == 0 + || newKey != NULL && newLength == 0) + return B_BAD_VALUE; + + // if the two keys are identical, don't do anything + if (type != 0 && !compareKeys(type,oldKey,oldLength,newKey,newLength)) + return B_OK; + + // update all live queries about the change, if they have an index or not + fVolume->UpdateLiveQueries(inode,name,type,oldKey,oldLength,newKey,newLength); + + status_t status; + if (name != fName && (status = SetTo(name)) < B_OK) + return B_BAD_INDEX; + + // now that we have the type, check again for equality + if (type == 0 && !compareKeys(Type(),oldKey,oldLength,newKey,newLength)) + return B_OK; + + BPlusTree *tree; + if ((status = Node()->GetTree(&tree)) < B_OK) + return status; + + // remove the old key from the tree + + if (oldKey != NULL) { + status = tree->Remove(transaction,(const uint8 *)oldKey,oldLength,inode->ID()); + if (status == B_ENTRY_NOT_FOUND) { + // That's not nice, but should be no reason to let the whole thing fail + FATAL(("Could not find value in index \"%s\"!\n",name)); + } else if (status < B_OK) + return status; + } + + // add the new key to the key + + if (newKey != NULL) + status = tree->Insert(transaction,(const uint8 *)newKey,newLength,inode->ID()); + + return status; +} + + +status_t +Index::InsertName(Transaction *transaction,const char *name,Inode *inode) +{ + return UpdateName(transaction,NULL,name,inode); +} + + +status_t +Index::RemoveName(Transaction *transaction,const char *name,Inode *inode) +{ + return UpdateName(transaction,name,NULL,inode); +} + + +status_t +Index::UpdateName(Transaction *transaction,const char *oldName, const char *newName,Inode *inode) +{ + uint16 oldLength = oldName ? strlen(oldName) : 0; + uint16 newLength = newName ? strlen(newName) : 0; + return Update(transaction,"name",B_STRING_TYPE,(uint8 *)oldName,oldLength,(uint8 *)newName,newLength,inode); +} + + +status_t +Index::InsertSize(Transaction *transaction, Inode *inode) +{ + off_t size = inode->Size(); + return Update(transaction,"size",B_INT64_TYPE,NULL,0,(uint8 *)&size,sizeof(int64),inode); +} + + +status_t +Index::RemoveSize(Transaction *transaction, Inode *inode) +{ + // Inode::OldSize() is the size that's in the index + off_t size = inode->OldSize(); + return Update(transaction,"size",B_INT64_TYPE,(uint8 *)&size,sizeof(int64),NULL,0,inode); +} + + +status_t +Index::UpdateSize(Transaction *transaction,Inode *inode) +{ + off_t oldSize = inode->OldSize(); + off_t newSize = inode->Size(); + status_t status = Update(transaction,"size",B_INT64_TYPE,(uint8 *)&oldSize,sizeof(int64), + (uint8 *)&newSize,sizeof(int64),inode); + + if (status == B_OK) + inode->UpdateOldSize(); + + return status; +} + + +status_t +Index::InsertLastModified(Transaction *transaction, Inode *inode) +{ + off_t modified = inode->Node()->last_modified_time; + return Update(transaction,"last_modified",B_INT64_TYPE,NULL,0,(uint8 *)&modified,sizeof(int64),inode); +} + + +status_t +Index::RemoveLastModified(Transaction *transaction, Inode *inode) +{ + // Inode::OldLastModified() is the value which is in the index + off_t modified = inode->OldLastModified(); + return Update(transaction,"last_modified",B_INT64_TYPE,(uint8 *)&modified,sizeof(int64),NULL,0,inode); +} + + +status_t +Index::UpdateLastModified(Transaction *transaction, Inode *inode, off_t modified) +{ + off_t oldModified = inode->OldLastModified(); + if (modified == -1) + modified = (bigtime_t)time(NULL) << INODE_TIME_SHIFT; + modified |= fVolume->GetUniqueID() & INODE_TIME_MASK; + + status_t status = Update(transaction,"last_modified",B_INT64_TYPE,(uint8 *)&oldModified,sizeof(int64), + (uint8 *)&modified,sizeof(int64),inode); + + inode->Node()->last_modified_time = modified; + if (status == B_OK) + inode->UpdateOldLastModified(); + + return status; +} + diff --git a/src/add-ons/kernel/file_systems/befs/Index.h b/src/add-ons/kernel/file_systems/befs/Index.h new file mode 100644 index 0000000000..5e65953614 --- /dev/null +++ b/src/add-ons/kernel/file_systems/befs/Index.h @@ -0,0 +1,51 @@ +#ifndef INDEX_H +#define INDEX_H +/* Index - index access functions +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include + +class Transaction; +class Volume; +class Inode; + + +class Index { + public: + Index(Volume *volume); + ~Index(); + + status_t SetTo(const char *name); + void Unset(); + + Inode *Node() const { return fNode; }; + uint32 Type(); + size_t KeySize(); + + status_t Create(Transaction *transaction, const char *name, uint32 type); + + status_t Update(Transaction *transaction, const char *name, int32 type, const uint8 *oldKey, uint16 oldLength, const uint8 *newKey, uint16 newLength, Inode *inode); + + status_t InsertName(Transaction *transaction,const char *name,Inode *inode); + status_t RemoveName(Transaction *transaction,const char *name,Inode *inode); + status_t UpdateName(Transaction *transaction,const char *oldName,const char *newName,Inode *inode); + + status_t InsertSize(Transaction *transaction, Inode *inode); + status_t RemoveSize(Transaction *transaction, Inode *inode); + status_t UpdateSize(Transaction *transaction, Inode *inode); + + status_t InsertLastModified(Transaction *transaction, Inode *inode); + status_t RemoveLastModified(Transaction *transaction, Inode *inode); + status_t UpdateLastModified(Transaction *transaction, Inode *inode,off_t modified = -1); + + private: + Volume *fVolume; + Inode *fNode; + const char *fName; +}; + +#endif /* INDEX_H */ diff --git a/src/add-ons/kernel/file_systems/befs/Inode.cpp b/src/add-ons/kernel/file_systems/befs/Inode.cpp new file mode 100644 index 0000000000..dc6212f639 --- /dev/null +++ b/src/add-ons/kernel/file_systems/befs/Inode.cpp @@ -0,0 +1,2107 @@ +/* Inode - inode access functions +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include "Debug.h" +#include "cpp.h" +#include "Inode.h" +#include "BPlusTree.h" +#include "Index.h" + +#include + + +class InodeAllocator { + public: + InodeAllocator(Transaction *transaction); + ~InodeAllocator(); + + status_t New(block_run *parentRun,mode_t mode,block_run &run,Inode **inode); + void Keep(); + + private: + Transaction *fTransaction; + block_run fRun; + Inode *fInode; +}; + + +InodeAllocator::InodeAllocator(Transaction *transaction) + : + fTransaction(transaction), + fInode(NULL) +{ +} + + +InodeAllocator::~InodeAllocator() +{ + delete fInode; + + if (fTransaction) + fTransaction->GetVolume()->Free(fTransaction,fRun); +} + + +status_t +InodeAllocator::New(block_run *parentRun, mode_t mode, block_run &run, Inode **inode) +{ + Volume *volume = fTransaction->GetVolume(); + + status_t status = volume->AllocateForInode(fTransaction,parentRun,mode,fRun); + if (status < B_OK) { + // don't free the space in the destructor, because + // the allocation failed + fTransaction = NULL; + RETURN_ERROR(status); + } + + run = fRun; + fInode = new Inode(volume,volume->ToVnode(run),true); + if (fInode == NULL) + RETURN_ERROR(B_NO_MEMORY); + + *inode = fInode; + return B_OK; +} + + +void InodeAllocator::Keep() +{ + fTransaction = NULL; + fInode = NULL; +} + + +// #pragma mark - + + +Inode::Inode(Volume *volume,vnode_id id,bool empty,uint8 reenter) + : CachedBlock(volume,volume->VnodeToBlock(id),empty), + fTree(NULL), + fLock("bfs inode") +{ + Node()->flags &= INODE_PERMANENT_FLAGS; + + // these two will help to maintain the indices + fOldSize = Size(); + fOldLastModified = Node()->last_modified_time; +} + + +Inode::~Inode() +{ + delete fTree; +} + + +status_t +Inode::InitCheck() +{ + if (!Node()) + RETURN_ERROR(B_IO_ERROR); + + // test inode magic and flags + if (Node()->magic1 != INODE_MAGIC1 + || !(Node()->flags & INODE_IN_USE) + || Node()->inode_num.length != 1 + // matches inode size? + || Node()->inode_size != fVolume->InodeSize() + // parent resides on disk? + || Node()->parent.allocation_group > fVolume->AllocationGroups() + || Node()->parent.allocation_group < 0 + || Node()->parent.start > (1L << fVolume->AllocationGroupShift()) + || Node()->parent.length != 1 + // attributes, too? + || Node()->attributes.allocation_group > fVolume->AllocationGroups() + || Node()->attributes.allocation_group < 0 + || Node()->attributes.start > (1L << fVolume->AllocationGroupShift())) { + FATAL(("inode at block %Ld corrupt!\n",fBlockNumber)); + RETURN_ERROR(B_BAD_DATA); + } + + // ToDo: Add some tests to check the integrity of the other stuff here, + // especially for the data_stream! + + // it's more important to know that the inode is corrupt + // so we check for the lock not until here + return fLock.InitCheck(); +} + + +status_t +Inode::CheckPermissions(int accessMode) const +{ + uid_t user = geteuid(); + gid_t group = getegid(); + + // you never have write access to a read-only volume + if (accessMode & W_OK && fVolume->IsReadOnly()) + return B_READ_ONLY_DEVICE; + + // root users always have full access (but they can't execute anything) + if (user == 0 && !((accessMode & X_OK) && (Mode() & S_IXUSR) == 0)) + return B_OK; + + // shift mode bits, to check directly against accessMode + mode_t mode = Mode(); + if (user == Node()->uid) + mode >>= 6; + else if (group == Node()->gid) + mode >>= 3; + + if (accessMode & ~(mode & S_IRWXO)) + return B_NOT_ALLOWED; + + return B_OK; +} + + +// #pragma mark - + + +void +Inode::AddIterator(AttributeIterator *iterator) +{ + if (fSmallDataLock.Lock() < B_OK) + return; + + fIterators.Add(iterator); + + fSmallDataLock.Unlock(); +} + + +void +Inode::RemoveIterator(AttributeIterator *iterator) +{ + if (fSmallDataLock.Lock() < B_OK) + return; + + fIterators.Remove(iterator); + + fSmallDataLock.Unlock(); +} + + +/** Tries to free up "bytes" space in the small_data section by moving + * attributes to real files. Used for system attributes like the name. + * You need to hold the fSmallDataLock when you call this method + */ + +status_t +Inode::MakeSpaceForSmallData(Transaction *transaction,const char *name,int32 bytes) +{ + while (bytes > 0) { + small_data *item = Node()->small_data_start,*max = NULL; + int32 index = 0,maxIndex = 0; + for (;!item->IsLast(Node());item = item->Next(),index++) { + // should not remove those + if (*item->Name() == FILE_NAME_NAME || !strcmp(name,item->Name())) + continue; + + if (max == NULL || max->Size() < item->Size()) { + maxIndex = index; + max = item; + } + + // remove the first one large enough to free the needed amount of bytes + if (bytes < item->Size()) + break; + } + + if (item->IsLast(Node()) || item->Size() < bytes) + return B_ERROR; + + bytes -= max->Size(); + + // Move the attribute to a real attribute file + // Luckily, this doesn't cause any index updates + + Inode *attribute; + status_t status = CreateAttribute(transaction,item->Name(),item->type,&attribute); + if (status < B_OK) + RETURN_ERROR(status); + + size_t length = item->data_size; + status = attribute->WriteAt(transaction,0,item->Data(),&length); + + ReleaseAttribute(attribute); + + if (status < B_OK) { + Vnode vnode(fVolume,Attributes()); + Inode *attributes; + if (vnode.Get(&attributes) < B_OK + || attributes->Remove(transaction,name) < B_OK) { + FATAL(("Could not remove newly created attribute!\n")); + } + + RETURN_ERROR(status); + } + + RemoveSmallData(max,maxIndex); + } + return B_OK; +} + + +/** Private function which removes the given attribute from the small_data + * section. + * You need to hold the fSmallDataLock when you call this method + */ + +status_t +Inode::RemoveSmallData(small_data *item,int32 index) +{ + small_data *next = item->Next(); + if (!next->IsLast(Node())) { + // find the last attribute + small_data *last = next; + while (!last->IsLast(Node())) + last = last->Next(); + + int32 size = (uint8 *)last - (uint8 *)next; + if (size < 0 || size > (uint8 *)Node() + fVolume->BlockSize() - (uint8 *)next) + return B_BAD_DATA; + + memmove(item,next,size); + + // Move the "last" one to its new location and + // correctly terminate the small_data section + last = (small_data *)((uint8 *)last - ((uint8 *)next - (uint8 *)item)); + memset(last,0,(uint8 *)Node() + fVolume->BlockSize() - (uint8 *)last); + } else + memset(item,0,item->Size()); + + // update all current iterators + AttributeIterator *iterator = NULL; + while ((iterator = fIterators.Next(iterator)) != NULL) + iterator->Update(index,-1); + + return B_OK; +} + + +/** Removes the given attribute from the small_data section. + * Note that you need to write back the inode yourself after having called + * that method. + */ + +status_t +Inode::RemoveSmallData(Transaction *transaction,const char *name) +{ + if (name == NULL) + return B_BAD_VALUE; + + SimpleLocker locker(fSmallDataLock); + + // search for the small_data item + + small_data *item = Node()->small_data_start; + int32 index = 0; + while (!item->IsLast(Node()) && strcmp(item->Name(),name)) { + item = item->Next(); + index++; + } + + if (item->IsLast(Node())) + return B_ENTRY_NOT_FOUND; + + return RemoveSmallData(item,index); +} + + +/** Try to place the given attribute in the small_data section - if the + * new attribute is too big to fit in that section, it returns B_DEVICE_FULL. + * In that case, the attribute should be written to a real attribute file; + * if the attribute was already part of the small_data section, but the new + * one wouldn't fit, the old one is automatically removed from the small_data + * section. + * Note that you need to write back the inode yourself after having called that + * method - it's a bad API decision that it needs a transaction but enforces you + * to write back the inode all by yourself, but it's just more efficient in most + * cases... + */ + +status_t +Inode::AddSmallData(Transaction *transaction,const char *name,uint32 type,const uint8 *data,size_t length,bool force) +{ + if (name == NULL || data == NULL || type == 0) + return B_BAD_VALUE; + + // reject any requests that can't fit into the small_data section + uint32 nameLength = strlen(name); + uint32 spaceNeeded = sizeof(small_data) + nameLength + 3 + length + 1; + if (spaceNeeded > fVolume->InodeSize() - sizeof(bfs_inode)) + return B_DEVICE_FULL; + + SimpleLocker locker(fSmallDataLock); + + small_data *item = Node()->small_data_start; + int32 index = 0; + while (!item->IsLast(Node()) && strcmp(item->Name(),name)) { + item = item->Next(); + index++; + } + + // is the attribute already in the small_data section? + // then just replace the data part of that one + if (!item->IsLast(Node())) { + // find last attribute + small_data *last = item; + while (!last->IsLast(Node())) + last = last->Next(); + + // try to change the attributes value + if (item->data_size > length + || force + || ((uint8 *)last + length - item->data_size) <= ((uint8 *)Node() + fVolume->InodeSize())) { + // make room for the new attribute if needed (and we are forced to do so) + if (force + && ((uint8 *)last + length - item->data_size) > ((uint8 *)Node() + fVolume->InodeSize())) { + // We also take the free space at the end of the small_data section + // into account, and request only what's really needed + uint32 needed = length - item->data_size - + (uint32)((uint8 *)Node() + fVolume->InodeSize() - (uint8 *)last); + + if (MakeSpaceForSmallData(transaction,name,needed) < B_OK) + return B_ERROR; + + // reset our pointers + item = Node()->small_data_start; + index = 0; + while (!item->IsLast(Node()) && strcmp(item->Name(),name)) { + item = item->Next(); + index++; + } + + last = item; + while (!last->IsLast(Node())) + last = last->Next(); + } + + // move the attributes after the current one + small_data *next = item->Next(); + if (!next->IsLast(Node())) + memmove((uint8 *)item + spaceNeeded,next,(uint8 *)last - (uint8 *)next); + + // Move the "last" one to its new location and + // correctly terminate the small_data section + last = (small_data *)((uint8 *)last - ((uint8 *)next - ((uint8 *)item + spaceNeeded))); + if ((uint8 *)last < (uint8 *)Node() + fVolume->BlockSize()) + memset(last,0,(uint8 *)Node() + fVolume->BlockSize() - (uint8 *)last); + + item->type = type; + item->data_size = length; + memcpy(item->Data(),data,length); + item->Data()[length] = '\0'; + + return B_OK; + } + + // Could not replace the old attribute, so remove it to let + // let the calling function create an attribute file for it + if (RemoveSmallData(item,index) < B_OK) + return B_ERROR; + + return B_DEVICE_FULL; + } + + // try to add the new attribute! + + if ((uint8 *)item + spaceNeeded > (uint8 *)Node() + fVolume->InodeSize()) { + // there is not enough space for it! + if (!force) + return B_DEVICE_FULL; + + // make room for the new attribute + if (MakeSpaceForSmallData(transaction,name,spaceNeeded) < B_OK) + return B_ERROR; + + // get new last item! + item = Node()->small_data_start; + index = 0; + while (!item->IsLast(Node())) { + item = item->Next(); + index++; + } + } + + memset(item,0,spaceNeeded); + item->type = type; + item->name_size = nameLength; + item->data_size = length; + strcpy(item->Name(),name); + memcpy(item->Data(),data,length); + + // correctly terminate the small_data section + item = item->Next(); + if (!item->IsLast(Node())) + memset(item,0,(uint8 *)Node() + fVolume->InodeSize() - (uint8 *)item); + + // update all current iterators + AttributeIterator *iterator = NULL; + while ((iterator = fIterators.Next(iterator)) != NULL) + iterator->Update(index,1); + + return B_OK; +} + + +/** Iterates through the small_data section of an inode. + * To start at the beginning of this section, you let smallData + * point to NULL, like: + * small_data *data = NULL; + * while (inode->GetNextSmallData(&data) { ... } + * + * This function is reentrant and doesn't allocate any memory; + * you can safely stop calling it at any point (you don't need + * to iterate through the whole list). + * You need to hold the fSmallDataLock when you call this method + */ + +status_t +Inode::GetNextSmallData(small_data **smallData) const +{ + if (!Node()) + RETURN_ERROR(B_ERROR); + + small_data *data = *smallData; + + // begin from the start? + if (data == NULL) + data = Node()->small_data_start; + else + data = data->Next(); + + // is already last item? + if (data->IsLast(Node())) + return B_ENTRY_NOT_FOUND; + + *smallData = data; + + return B_OK; +} + + +/** Finds the attribute "name" in the small data section, and + * returns a pointer to it (or NULL if it doesn't exist). + * You need to hold the fSmallDataLock when you call this method + */ + +small_data * +Inode::FindSmallData(const char *name) const +{ + small_data *smallData = NULL; + while (GetNextSmallData(&smallData) == B_OK) { + if (!strcmp(smallData->Name(),name)) + return smallData; + } + return NULL; +} + + +const char * +Inode::Name() const +{ + SimpleLocker locker(fSmallDataLock); + + small_data *smallData = NULL; + while (GetNextSmallData(&smallData) == B_OK) { + if (*smallData->Name() == FILE_NAME_NAME && smallData->name_size == FILE_NAME_NAME_LENGTH) + return (const char *)smallData->Data(); + } + return NULL; +} + + +/** Changes or set the name of a file: in the inode small_data section only, it + * doesn't change it in the parent directory's b+tree. + * Note that you need to write back the inode yourself after having called + * that method. It suffers from the same API decision as AddSmallData() does + * (and for the same reason). + */ + +status_t +Inode::SetName(Transaction *transaction,const char *name) +{ + if (name == NULL || *name == '\0') + return B_BAD_VALUE; + + const char nameTag[2] = {FILE_NAME_NAME, 0}; + + return AddSmallData(transaction,nameTag,FILE_NAME_TYPE,(uint8 *)name,strlen(name),true); +} + + +/** Reads data from the specified attribute. + * This is a high-level attribute function that understands attributes + * in the small_data section as well as real attribute files. + */ + +status_t +Inode::ReadAttribute(const char *name,int32 type,off_t pos,uint8 *buffer,size_t *_length) +{ + if (pos < 0) + pos = 0; + + // search in the small_data section (which has to be locked first) + { + SimpleLocker locker(fSmallDataLock); + + small_data *smallData = FindSmallData(name); + if (smallData != NULL) { + size_t length = *_length; + if (pos >= smallData->data_size) { + *_length = 0; + return B_OK; + } + if (length + pos > smallData->data_size) + length = smallData->data_size - pos; + + memcpy(buffer,smallData->Data() + pos,length); + *_length = length; + return B_OK; + } + } + + // search in the attribute directory + Inode *attribute; + status_t status = GetAttribute(name,&attribute); + if (status == B_OK) { + if (attribute->Lock().Lock() == B_OK) { + status = attribute->ReadAt(pos,(uint8 *)buffer,_length); + attribute->Lock().Unlock(); + } else + status = B_ERROR; + + ReleaseAttribute(attribute); + } + + RETURN_ERROR(status); +} + + +/** Writes data to the specified attribute. + * This is a high-level attribute function that understands attributes + * in the small_data section as well as real attribute files. + */ + +status_t +Inode::WriteAttribute(Transaction *transaction,const char *name,int32 type,off_t pos,const uint8 *buffer,size_t *_length) +{ + // needed to maintain the index + uint8 oldBuffer[BPLUSTREE_MAX_KEY_LENGTH],*oldData = NULL; + size_t oldLength = 0; + + Index index(fVolume); + bool hasIndex = index.SetTo(name) == B_OK; + + Inode *attribute = NULL; + status_t status; + if (GetAttribute(name,&attribute) < B_OK) { + // save the old attribute data + if (hasIndex) { + fSmallDataLock.Lock(); + + small_data *smallData = FindSmallData(name); + if (smallData != NULL) { + oldLength = smallData->data_size; + if (oldLength > BPLUSTREE_MAX_KEY_LENGTH) + oldLength = BPLUSTREE_MAX_KEY_LENGTH; + memcpy(oldData = oldBuffer,smallData->Data(),oldLength); + } + fSmallDataLock.Unlock(); + } + + // if the attribute doesn't exist yet (as a file), try to put it in the + // small_data section first - if that fails (due to insufficent space), + // create a real attribute file + status = AddSmallData(transaction,name,type,buffer,*_length); + if (status == B_DEVICE_FULL) { + status = CreateAttribute(transaction,name,type,&attribute); + if (status < B_OK) + RETURN_ERROR(status); + } else if (status == B_OK) + status = WriteBack(transaction); + } + + if (attribute != NULL) { + if (attribute->Lock().LockWrite() == B_OK) { + // save the old attribute data (if this fails, oldLength will reflect it) + if (hasIndex) { + oldLength = BPLUSTREE_MAX_KEY_LENGTH; + if (attribute->ReadAt(0,oldBuffer,&oldLength) == B_OK) + oldData = oldBuffer; + } + status = attribute->WriteAt(transaction,pos,buffer,_length); + + attribute->Lock().UnlockWrite(); + } else + status = B_ERROR; + + ReleaseAttribute(attribute); + } + + if (status == B_OK) { + // ToDo: find a better way for that "pos" thing... + // Update index + if (hasIndex && pos == 0) { + // index only the first BPLUSTREE_MAX_KEY_LENGTH bytes + uint16 length = *_length; + if (length > BPLUSTREE_MAX_KEY_LENGTH) + length = BPLUSTREE_MAX_KEY_LENGTH; + + index.Update(transaction,name,0,oldData,oldLength,buffer,length,this); + } + } + return status; +} + + +/** Removes the specified attribute from the inode. + * This is a high-level attribute function that understands attributes + * in the small_data section as well as real attribute files. + */ + +status_t +Inode::RemoveAttribute(Transaction *transaction,const char *name) +{ + Index index(fVolume); + bool hasIndex = index.SetTo(name) == B_OK; + + // update index for attributes in the small_data section + if (hasIndex) { + fSmallDataLock.Lock(); + + small_data *smallData = FindSmallData(name); + if (smallData != NULL) { + uint32 length = smallData->data_size; + if (length > BPLUSTREE_MAX_KEY_LENGTH) + length = BPLUSTREE_MAX_KEY_LENGTH; + index.Update(transaction,name,0,smallData->Data(),length,NULL,0,this); + } + fSmallDataLock.Unlock(); + } + + status_t status = RemoveSmallData(transaction,name); + if (status == B_OK) { + status = WriteBack(transaction); + } else if (status == B_ENTRY_NOT_FOUND && !Attributes().IsZero()) { + // remove the attribute file if it exists + Vnode vnode(fVolume,Attributes()); + Inode *attributes; + if ((status = vnode.Get(&attributes)) < B_OK) + return status; + + // update index + Inode *attribute; + if (hasIndex && GetAttribute(name,&attribute) == B_OK) { + uint8 data[BPLUSTREE_MAX_KEY_LENGTH]; + size_t length = BPLUSTREE_MAX_KEY_LENGTH; + if (attribute->ReadAt(0,data,&length) == B_OK) + index.Update(transaction,name,0,data,length,NULL,0,this); + + ReleaseAttribute(attribute); + } + + if ((status = attributes->Remove(transaction,name)) < B_OK) + return status; + + if (attributes->IsEmpty()) { + // remove attribute directory (don't fail if that can't be done) + if (remove_vnode(fVolume->ID(),attributes->ID()) == B_OK) { + // update the inode, so that no one will ever doubt it's deleted :-) + attributes->Node()->flags |= INODE_DELETED; + if (attributes->WriteBack(transaction) == B_OK) { + Attributes().SetTo(0,0,0); + WriteBack(transaction); + } else + unremove_vnode(fVolume->ID(),attributes->ID()); + } + } + } + return status; +} + + +status_t +Inode::GetAttribute(const char *name,Inode **attribute) +{ + // does this inode even have attributes? + if (Attributes().IsZero()) + return B_ENTRY_NOT_FOUND; + + Vnode vnode(fVolume,Attributes()); + Inode *attributes; + if (vnode.Get(&attributes) < B_OK) { + FATAL(("get_vnode() failed in Inode::GetAttribute(name = \"%s\")\n",name)); + return B_ERROR; + } + + BPlusTree *tree; + status_t status = attributes->GetTree(&tree); + if (status == B_OK) { + vnode_id id; + if ((status = tree->Find((uint8 *)name,(uint16)strlen(name),&id)) == B_OK) + return get_vnode(fVolume->ID(),id,(void **)attribute); + } + return status; +} + + +void +Inode::ReleaseAttribute(Inode *attribute) +{ + if (attribute == NULL) + return; + + put_vnode(fVolume->ID(),attribute->ID()); +} + + +status_t +Inode::CreateAttribute(Transaction *transaction,const char *name,uint32 type,Inode **attribute) +{ + // do we need to create the attribute directory first? + if (Attributes().IsZero()) { + status_t status = Inode::Create(transaction,this,NULL,S_ATTR_DIR | 0666,0,0,NULL); + if (status < B_OK) + RETURN_ERROR(status); + } + Vnode vnode(fVolume,Attributes()); + Inode *attributes; + if (vnode.Get(&attributes) < B_OK) + return B_ERROR; + + // Inode::Create() locks the inode if we provide the "id" parameter + vnode_id id; + return Inode::Create(transaction,attributes,name,S_ATTR | 0666,0,type,&id,attribute); +} + + +// #pragma mark - + + +/** Gives the caller direct access to the b+tree for a given directory. + * The tree is created on demand, but lasts until the inode is + * deleted. + */ + +status_t +Inode::GetTree(BPlusTree **tree) +{ + if (fTree) { + *tree = fTree; + return B_OK; + } + + if (IsDirectory()) { + fTree = new BPlusTree(this); + if (!fTree) + RETURN_ERROR(B_NO_MEMORY); + + *tree = fTree; + status_t status = fTree->InitCheck(); + if (status < B_OK) { + delete fTree; + fTree = NULL; + } + RETURN_ERROR(status); + } + RETURN_ERROR(B_BAD_VALUE); +} + + +bool +Inode::IsEmpty() +{ + BPlusTree *tree; + status_t status = GetTree(&tree); + if (status < B_OK) + return status; + + TreeIterator iterator(tree); + + // index and attribute directories are really empty when they are + // empty - directories for standard files always contain ".", and + // "..", so we need to ignore those two + + uint32 count = 0; + char name[BPLUSTREE_MAX_KEY_LENGTH]; + uint16 length; + vnode_id id; + while (iterator.GetNextEntry(name,&length,B_FILE_NAME_LENGTH,&id) == B_OK) { + if (Mode() & (S_ATTR_DIR | S_INDEX_DIR)) + return false; + + if (++count > 2 || strcmp(".",name) && strcmp("..",name)) + return false; + } + return true; +} + + +/** Finds the block_run where "pos" is located in the data_stream of + * the inode. + * If successful, "offset" will then be set to the file offset + * of the block_run returned; so "pos - offset" is for the block_run + * what "pos" is for the whole stream. + */ + +status_t +Inode::FindBlockRun(off_t pos,block_run &run,off_t &offset) +{ + data_stream *data = &Node()->data; + + // Inode::ReadAt() does already does this + //if (pos > data->size) + // return B_ENTRY_NOT_FOUND; + + // find matching block run + + if (data->max_direct_range > 0 && pos >= data->max_direct_range) { + if (data->max_double_indirect_range > 0 && pos >= data->max_indirect_range) { + // access to double indirect blocks + + CachedBlock cached(fVolume); + + off_t start = pos - data->max_indirect_range; + int32 indirectSize = (16 << fVolume->BlockShift()) * (fVolume->BlockSize() / sizeof(block_run)); + int32 directSize = 4 << fVolume->BlockShift(); + int32 index = start / indirectSize; + int32 runsPerBlock = fVolume->BlockSize() / sizeof(block_run); + + block_run *indirect = (block_run *)cached.SetTo( + fVolume->ToBlock(data->double_indirect) + index / runsPerBlock); + if (indirect == NULL) + RETURN_ERROR(B_ERROR); + + //printf("\tstart = %Ld, indirectSize = %ld, directSize = %ld, index = %ld\n",start,indirectSize,directSize,index); + //printf("\tlook for indirect block at %ld,%d\n",indirect[index].allocation_group,indirect[index].start); + + int32 current = (start % indirectSize) / directSize; + + indirect = (block_run *)cached.SetTo( + fVolume->ToBlock(indirect[index % runsPerBlock]) + current / runsPerBlock); + if (indirect == NULL) + RETURN_ERROR(B_ERROR); + + run = indirect[current % runsPerBlock]; + offset = data->max_indirect_range + (index * indirectSize) + (current * directSize); + //printf("\tfCurrent = %ld, fRunFileOffset = %Ld, fRunBlockEnd = %Ld, fRun = %ld,%d\n",fCurrent,fRunFileOffset,fRunBlockEnd,fRun.allocation_group,fRun.start); + } else { + // access to indirect blocks + + int32 runsPerBlock = fVolume->BlockSize() / sizeof(block_run); + off_t runBlockEnd = data->max_direct_range; + + CachedBlock cached(fVolume); + off_t block = fVolume->ToBlock(data->indirect); + + for (int32 i = 0;i < data->indirect.length;i++) { + block_run *indirect = (block_run *)cached.SetTo(block + i); + if (indirect == NULL) + RETURN_ERROR(B_IO_ERROR); + + int32 current = -1; + while (++current < runsPerBlock) { + if (indirect[current].IsZero()) + break; + + runBlockEnd += indirect[current].length << fVolume->BlockShift(); + if (runBlockEnd > pos) { + run = indirect[current]; + offset = runBlockEnd - (run.length << fVolume->BlockShift()); + //printf("reading from indirect block: %ld,%d\n",fRun.allocation_group,fRun.start); + //printf("### indirect-run[%ld] = (%ld,%d,%d), offset = %Ld\n",fCurrent,fRun.allocation_group,fRun.start,fRun.length,fRunFileOffset); + return fVolume->IsValidBlockRun(run); + } + } + } + RETURN_ERROR(B_ERROR); + } + } else { + // access from direct blocks + + off_t runBlockEnd = 0LL; + int32 current = -1; + + while (++current < NUM_DIRECT_BLOCKS) { + if (data->direct[current].IsZero()) + break; + + runBlockEnd += data->direct[current].length << fVolume->BlockShift(); + if (runBlockEnd > pos) { + run = data->direct[current]; + offset = runBlockEnd - (run.length << fVolume->BlockShift()); + //printf("### run[%ld] = (%ld,%d,%d), offset = %Ld\n",fCurrent,fRun.allocation_group,fRun.start,fRun.length,fRunFileOffset); + return fVolume->IsValidBlockRun(run); + } + } + //PRINT(("FindBlockRun() failed in direct range: size = %Ld, pos = %Ld\n",data->size,pos)); + return B_ENTRY_NOT_FOUND; + } + return fVolume->IsValidBlockRun(run); +} + + +status_t +Inode::ReadAt(off_t pos, uint8 *buffer, size_t *_length) +{ + // set/check boundaries for pos/length + + if (pos < 0) + pos = 0; + else if (pos >= Node()->data.size) { + *_length = 0; + return B_NO_ERROR; + } + + size_t length = *_length; + + if (pos + length > Node()->data.size) + length = Node()->data.size - pos; + + block_run run; + off_t offset; + if (FindBlockRun(pos,run,offset) < B_OK) { + *_length = 0; + RETURN_ERROR(B_BAD_VALUE); + } + + uint32 bytesRead = 0; + uint32 blockSize = fVolume->BlockSize(); + uint32 blockShift = fVolume->BlockShift(); + uint8 *block; + + // the first block_run we read could not be aligned to the block_size boundary + // (read partial block at the beginning) + + // pos % block_size == (pos - offset) % block_size, offset % block_size == 0 + if (pos % blockSize != 0) { + run.start += (pos - offset) / blockSize; + run.length -= (pos - offset) / blockSize; + + CachedBlock cached(fVolume,run); + if ((block = cached.Block()) == NULL) { + *_length = 0; + RETURN_ERROR(B_BAD_VALUE); + } + + bytesRead = blockSize - (pos % blockSize); + if (length < bytesRead) + bytesRead = length; + + memcpy(buffer,block + (pos % blockSize),bytesRead); + pos += bytesRead; + + length -= bytesRead; + if (length == 0) { + *_length = bytesRead; + return B_OK; + } + + if (FindBlockRun(pos,run,offset) < B_OK) { + *_length = bytesRead; + RETURN_ERROR(B_BAD_VALUE); + } + } + + // the first block_run is already filled in at this point + // read the following complete blocks using cached_read(), + // the last partial block is read using the CachedBlock class + + bool partial = false; + + while (length > 0) { + // offset is the offset to the current pos in the block_run + run.start += (pos - offset) >> blockShift; + run.length -= (pos - offset) >> blockShift; + + if ((run.length << blockShift) > length) { + if (length < blockSize) { + CachedBlock cached(fVolume,run); + if ((block = cached.Block()) == NULL) { + *_length = bytesRead; + RETURN_ERROR(B_BAD_VALUE); + } + memcpy(buffer + bytesRead,block,length); + bytesRead += length; + break; + } + run.length = length >> blockShift; + partial = true; + } + + if (cached_read(fVolume->Device(),fVolume->ToBlock(run),buffer + bytesRead, + run.length,blockSize) != B_OK) { + *_length = bytesRead; + RETURN_ERROR(B_BAD_VALUE); + } + + int32 bytes = run.length << blockShift; + length -= bytes; + bytesRead += bytes; + if (length == 0) + break; + + pos += bytes; + + if (partial) { + // if the last block was read only partially, point block_run + // to the remaining part + run.start += run.length; + run.length = 1; + offset = pos; + } else if (FindBlockRun(pos,run,offset) < B_OK) { + *_length = bytesRead; + RETURN_ERROR(B_BAD_VALUE); + } + } + + *_length = bytesRead; + return B_NO_ERROR; +} + + +status_t +Inode::WriteAt(Transaction *transaction,off_t pos,const uint8 *buffer,size_t *_length) +{ + size_t length = *_length; + + // set/check boundaries for pos/length + if (pos < 0) + pos = 0; + else if (pos + length > Node()->data.size) { + off_t oldSize = Size(); + + // the transaction doesn't have to be started already + if ((Flags() & INODE_NO_TRANSACTION) == 0) + transaction->Start(fVolume,BlockNumber()); + + // let's grow the data stream to the size needed + status_t status = SetFileSize(transaction,pos + length); + if (status < B_OK) { + *_length = 0; + RETURN_ERROR(status); + } + // If the position of the write was beyond the file size, we + // have to fill the gap between that position and the old file + // size with zeros. + FillGapWithZeros(oldSize,pos); + } + + block_run run; + off_t offset; + if (FindBlockRun(pos,run,offset) < B_OK) { + *_length = 0; + RETURN_ERROR(B_BAD_VALUE); + } + + bool logStream = (Flags() & INODE_LOGGED) == INODE_LOGGED; + if (logStream) + transaction->Start(fVolume,BlockNumber()); + + uint32 bytesWritten = 0; + uint32 blockSize = fVolume->BlockSize(); + uint32 blockShift = fVolume->BlockShift(); + uint8 *block; + + // the first block_run we write could not be aligned to the block_size boundary + // (write partial block at the beginning) + + // pos % block_size == (pos - offset) % block_size, offset % block_size == 0 + if (pos % blockSize != 0) { + run.start += (pos - offset) / blockSize; + run.length -= (pos - offset) / blockSize; + + CachedBlock cached(fVolume,run); + if ((block = cached.Block()) == NULL) { + *_length = 0; + RETURN_ERROR(B_BAD_VALUE); + } + + bytesWritten = blockSize - (pos % blockSize); + if (length < bytesWritten) + bytesWritten = length; + + memcpy(block + (pos % blockSize),buffer,bytesWritten); + + // either log the stream or write it directly to disk + if (logStream) + cached.WriteBack(transaction); + else + fVolume->WriteBlocks(cached.BlockNumber(),block,1); + + pos += bytesWritten; + + length -= bytesWritten; + if (length == 0) { + *_length = bytesWritten; + return B_OK; + } + + if (FindBlockRun(pos,run,offset) < B_OK) { + *_length = bytesWritten; + RETURN_ERROR(B_BAD_VALUE); + } + } + + // the first block_run is already filled in at this point + // write the following complete blocks using Volume::WriteBlocks(), + // the last partial block is written using the CachedBlock class + + bool partial = false; + + while (length > 0) { + // offset is the offset to the current pos in the block_run + run.start += (pos - offset) >> blockShift; + run.length -= (pos - offset) >> blockShift; + + if ((run.length << blockShift) > length) { + if (length < blockSize) { + CachedBlock cached(fVolume,run); + if ((block = cached.Block()) == NULL) { + *_length = bytesWritten; + RETURN_ERROR(B_BAD_VALUE); + } + memcpy(block,buffer + bytesWritten,length); + + if (logStream) + cached.WriteBack(transaction); + else + fVolume->WriteBlocks(cached.BlockNumber(),block,1); + + bytesWritten += length; + break; + } + run.length = length >> blockShift; + partial = true; + } + + status_t status; + if (logStream) { + status = transaction->WriteBlocks(fVolume->ToBlock(run), + buffer + bytesWritten,run.length); + } else { + status = fVolume->WriteBlocks(fVolume->ToBlock(run), + buffer + bytesWritten,run.length); + } + if (status != B_OK) { + *_length = bytesWritten; + RETURN_ERROR(B_BAD_VALUE); + } + + int32 bytes = run.length << blockShift; + length -= bytes; + bytesWritten += bytes; + if (length == 0) + break; + + pos += bytes; + + if (partial) { + // if the last block was written only partially, point block_run + // to the remaining part + run.start += run.length; + run.length = 1; + offset = pos; + } else if (FindBlockRun(pos,run,offset) < B_OK) { + *_length = bytesWritten; + RETURN_ERROR(B_BAD_VALUE); + } + } + + *_length = bytesWritten; + + return B_NO_ERROR; +} + + +/** Fills the gap between the old file size and the new file size + * with zeros. + * It's more or less a copy of Inode::WriteAt() but it can handle + * length differences of more than just 4 GB, and it never uses + * the log, even if the INODE_LOGGED flag is set. + */ + +status_t +Inode::FillGapWithZeros(off_t pos,off_t newSize) +{ + //if (pos >= newSize) + return B_OK; + + block_run run; + off_t offset; + if (FindBlockRun(pos,run,offset) < B_OK) + RETURN_ERROR(B_BAD_VALUE); + + off_t length = newSize - pos; + uint32 bytesWritten = 0; + uint32 blockSize = fVolume->BlockSize(); + uint32 blockShift = fVolume->BlockShift(); + uint8 *block; + + // the first block_run we write could not be aligned to the block_size boundary + // (write partial block at the beginning) + + // pos % block_size == (pos - offset) % block_size, offset % block_size == 0 + if (pos % blockSize != 0) { + run.start += (pos - offset) / blockSize; + run.length -= (pos - offset) / blockSize; + + CachedBlock cached(fVolume,run); + if ((block = cached.Block()) == NULL) + RETURN_ERROR(B_BAD_VALUE); + + bytesWritten = blockSize - (pos % blockSize); + if (length < bytesWritten) + bytesWritten = length; + + memset(block + (pos % blockSize),0,bytesWritten); + fVolume->WriteBlocks(cached.BlockNumber(),block,1); + + pos += bytesWritten; + + length -= bytesWritten; + if (length == 0) + return B_OK; + + if (FindBlockRun(pos,run,offset) < B_OK) + RETURN_ERROR(B_BAD_VALUE); + } + + while (length > 0) { + // offset is the offset to the current pos in the block_run + run.start += (pos - offset) >> blockShift; + run.length -= (pos - offset) >> blockShift; + + CachedBlock cached(fVolume); + off_t blockNumber = fVolume->ToBlock(run); + for (int32 i = 0;i < run.length;i++) { + if ((block = cached.SetTo(blockNumber + i,true)) == NULL) + RETURN_ERROR(B_IO_ERROR); + + if (fVolume->WriteBlocks(cached.BlockNumber(),block,1) < B_OK) + RETURN_ERROR(B_IO_ERROR); + } + + int32 bytes = run.length << blockShift; + length -= bytes; + bytesWritten += bytes; + + // since we don't respect a last partial block, length can be lower + if (length <= 0) + break; + + pos += bytes; + + if (FindBlockRun(pos,run,offset) < B_OK) + RETURN_ERROR(B_BAD_VALUE); + } + return B_OK; +} + + +status_t +Inode::GrowStream(Transaction *transaction, off_t size) +{ + data_stream *data = &Node()->data; + + // is the data stream already large enough to hold the new size? + // (can be the case with preallocated blocks) + if (size < data->max_direct_range + || size < data->max_indirect_range + || size < data->max_double_indirect_range) { + data->size = size; + return B_OK; + } + + // how many bytes are still needed? (unused ranges are always zero) + off_t bytes; + if (data->size < data->max_double_indirect_range) + bytes = size - data->max_double_indirect_range; + else if (data->size < data->max_indirect_range) + bytes = size - data->max_indirect_range; + else if (data->size < data->max_direct_range) + bytes = size - data->max_direct_range; + else + bytes = size - data->size; + + // do we have enough free blocks on the disk? + off_t blocks = (bytes + fVolume->BlockSize() - 1) / fVolume->BlockSize(); + if (blocks > fVolume->FreeBlocks()) + return B_DEVICE_FULL; + + // should we preallocate some blocks (currently, always 64k)? + off_t blocksNeeded = blocks; + if (blocks < 65536 / fVolume->BlockSize() && fVolume->FreeBlocks() > 128) + blocks = 65536 / fVolume->BlockSize(); + + while (blocksNeeded > 0) { + // the requested blocks do not need to be returned with a + // single allocation, so we need to iterate until we have + // enough blocks allocated + block_run run; + status_t status = fVolume->Allocate(transaction,this,blocks,run); + if (status < B_OK) + return status; + + // okay, we have the needed blocks, so just distribute them to the + // different ranges of the stream (direct, indirect & double indirect) + + blocksNeeded -= run.length; + // don't preallocate if the first allocation was already too small + blocks = blocksNeeded; + + if (data->size <= data->max_direct_range) { + // let's try to put them into the direct block range + int32 free = 0; + for (;free < NUM_DIRECT_BLOCKS;free++) + if (data->direct[free].IsZero()) + break; + + if (free < NUM_DIRECT_BLOCKS) { + // can we merge the last allocated run with the new one? + int32 last = free - 1; + if (free > 0 + && data->direct[last].allocation_group == run.allocation_group + && data->direct[last].start + data->direct[last].length == run.start) { + data->direct[last].length += run.length; + } else { + data->direct[free] = run; + } + data->max_direct_range += run.length * fVolume->BlockSize(); + data->size = blocksNeeded > 0 ? data->max_direct_range : size; + continue; + } + } + + if (data->size <= data->max_indirect_range || !data->max_indirect_range) { + CachedBlock cached(fVolume); + block_run *runs = NULL; + int32 free = 0; + off_t block; + + // if there is no indirect block yet, create one + if (data->indirect.IsZero()) { + status = fVolume->Allocate(transaction,this,4,data->indirect,4); + if (status < B_OK) + return status; + + // make sure those blocks are empty + block = fVolume->ToBlock(data->indirect); + for (int32 i = 1;i < data->indirect.length;i++) { + block_run *runs = (block_run *)cached.SetTo(block + i,true); + if (runs == NULL) + return B_IO_ERROR; + + cached.WriteBack(transaction); + } + data->max_indirect_range = data->max_direct_range; + // insert the block_run in the first block + runs = (block_run *)cached.SetTo(block,true); + } else { + uint32 numberOfRuns = fVolume->BlockSize() / sizeof(block_run); + block = fVolume->ToBlock(data->indirect); + + // search first empty entry + int32 i = 0; + for (;i < data->indirect.length;i++) { + if ((runs = (block_run *)cached.SetTo(block + i)) == NULL) + return B_IO_ERROR; + + for (free = 0;free < numberOfRuns;free++) + if (runs[free].IsZero()) + break; + + if (free < numberOfRuns) + break; + } + if (i == data->indirect.length) + runs = NULL; + } + + if (runs != NULL) { + // try to insert the run to the last one - note that this doesn't + // take block borders into account, so it could be further optimized + int32 last = free - 1; + if (free > 0 + && runs[last].allocation_group == run.allocation_group + && runs[last].start + runs[last].length == run.start) { + runs[last].length += run.length; + } else { + runs[free] = run; + } + data->max_indirect_range += run.length * fVolume->BlockSize(); + data->size = blocksNeeded > 0 ? data->max_indirect_range : size; + + cached.WriteBack(transaction); + continue; + } + } + + // when we are here, we need to grow into the double indirect + // range - but that's not yet implemented, so bail out! + + if (data->size <= data->max_double_indirect_range || !data->max_double_indirect_range) { + FATAL(("growing in the double indirect range is not yet implemented!\n")); + // ToDo: implement growing into the double indirect range, please! + } + + RETURN_ERROR(EFBIG); + } + // update the size of the data stream + data->size = size; + + return B_OK; +} + + +status_t +Inode::FreeStaticStreamArray(Transaction *transaction,int32 level,block_run run,off_t size,off_t offset,off_t &max) +{ + int32 indirectSize; + if (level == 0) + indirectSize = (16 << fVolume->BlockShift()) * (fVolume->BlockSize() / sizeof(block_run)); + else if (level == 1) + indirectSize = 4 << fVolume->BlockShift(); + + off_t start; + if (size > offset) + start = size - offset; + else + start = 0; + + int32 index = start / indirectSize; + int32 runsPerBlock = fVolume->BlockSize() / sizeof(block_run); + + CachedBlock cached(fVolume); + off_t blockNumber = fVolume->ToBlock(run); + + // set the file offset to the current block run + offset += (off_t)index * indirectSize; + + for (int32 i = index / runsPerBlock;i < run.length;i++) { + block_run *array = (block_run *)cached.SetTo(blockNumber + i); + if (array == NULL) + RETURN_ERROR(B_ERROR); + + for (index = index % runsPerBlock;index < runsPerBlock;index++) { + if (array[index].IsZero()) { + // we also want to break out of the outer loop + i = run.length; + break; + } + + status_t status = B_OK; + if (level == 0) + status = FreeStaticStreamArray(transaction,1,array[index],size,offset,max); + else if (offset >= size) + status = fVolume->Free(transaction,array[index]); + else + max = offset + indirectSize; + + if (status < B_OK) + RETURN_ERROR(status); + + if (offset >= size) + array[index].SetTo(0,0,0); + + offset += indirectSize; + } + index = 0; + + cached.WriteBack(transaction); + } + return B_OK; +} + + +/** Frees all block_runs in the array which come after the specified size. + * It also trims the last block_run that contain the size. + * "offset" and "max" are maintained until the last block_run that doesn't + * have to be freed - after this, the values won't be correct anymore, but + * will still assure correct function for all subsequent calls. + */ + +status_t +Inode::FreeStreamArray(Transaction *transaction,block_run *array,uint32 arrayLength,off_t size,off_t &offset,off_t &max) +{ + off_t newOffset = offset; + uint32 i = 0; + for (;i < arrayLength;i++,offset = newOffset) { + if (array[i].IsZero()) + break; + + newOffset += (off_t)array[i].length << fVolume->BlockShift(); + if (newOffset <= size) + continue; + + block_run run = array[i]; + + // determine the block_run to be freed + if (newOffset > size && offset < size) { + // free partial block_run (and update the original block_run) + run.start = array[i].start + ((size - offset) >> fVolume->BlockShift()) + 1; + array[i].length = run.start - array[i].start; + run.length -= array[i].length; + + if (run.length == 0) + continue; + + // update maximum range + max = offset + ((off_t)array[i].length << fVolume->BlockShift()); + } else { + // free the whole block_run + array[i].SetTo(0,0,0); + + if (max > offset) + max = offset; + } + + if (fVolume->Free(transaction,run) < B_OK) + return B_IO_ERROR; + } + return B_OK; +} + + +status_t +Inode::ShrinkStream(Transaction *transaction, off_t size) +{ + data_stream *data = &Node()->data; + + if (data->max_double_indirect_range > size) { + FreeStaticStreamArray(transaction,0,data->double_indirect,size,data->max_indirect_range,data->max_double_indirect_range); + + if (size <= data->max_indirect_range) { + fVolume->Free(transaction,data->double_indirect); + data->double_indirect.SetTo(0,0,0); + data->max_double_indirect_range = 0; + } + } + if (data->max_indirect_range > size) { + CachedBlock cached(fVolume); + off_t block = fVolume->ToBlock(data->indirect); + off_t offset = data->max_direct_range; + + for (int32 i = 0;i < data->indirect.length;i++) { + block_run *array = (block_run *)cached.SetTo(block + i); + if (array == NULL) + break; + + if (FreeStreamArray(transaction,array,fVolume->BlockSize() / sizeof(block_run),size,offset,data->max_indirect_range) == B_OK) + cached.WriteBack(transaction); + } + if (data->max_direct_range == data->max_indirect_range) { + fVolume->Free(transaction,data->indirect); + data->indirect.SetTo(0,0,0); + data->max_indirect_range = 0; + } + } + if (data->max_direct_range > size) { + off_t offset = 0; + FreeStreamArray(transaction,data->direct,NUM_DIRECT_BLOCKS,size,offset,data->max_direct_range); + } + + data->size = size; + return B_OK; +} + + +status_t +Inode::SetFileSize(Transaction *transaction, off_t size) +{ + if (size < 0) + return B_BAD_VALUE; + + off_t oldSize = Node()->data.size; + + if (size == oldSize) + return B_OK; + + // should the data stream grow or shrink? + status_t status; + if (size > oldSize) { + status = GrowStream(transaction,size); + if (status < B_OK) { + // if the growing of the stream fails, the whole operation + // fails, so we should shrink the stream to its former size + ShrinkStream(transaction,oldSize); + } + } + else + status = ShrinkStream(transaction,size); + + if (status < B_OK) + return status; + + return WriteBack(transaction); +} + + +status_t +Inode::Append(Transaction *transaction,off_t bytes) +{ + return SetFileSize(transaction,Size() + bytes); +} + + +status_t +Inode::Trim(Transaction *transaction) +{ + return ShrinkStream(transaction,Size()); +} + + +status_t +Inode::Sync() +{ + // We may also want to flush the attribute's data stream to + // disk here... (do we?) + + data_stream *data = &Node()->data; + status_t status; + + // flush direct range + + for (int32 i = 0;i < NUM_DIRECT_BLOCKS;i++) { + if (data->direct[i].IsZero()) + return B_OK; + + status = flush_blocks(fVolume->Device(),fVolume->ToBlock(data->direct[i]),data->direct[i].length); + if (status != B_OK) + return status; + } + + // flush indirect range + + if (data->max_indirect_range == 0) + return B_OK; + + CachedBlock cached(fVolume); + off_t block = fVolume->ToBlock(data->indirect); + int32 count = fVolume->BlockSize() / sizeof(block_run); + + for (int32 j = 0;j < data->indirect.length;j++) { + block_run *runs = (block_run *)cached.SetTo(block + j); + if (runs == NULL) + break; + + for (int32 i = 0;i < count;i++) { + if (runs[i].IsZero()) + return B_OK; + + status = flush_blocks(fVolume->Device(),fVolume->ToBlock(runs[i]),runs[i].length); + if (status != B_OK) + return status; + } + } + + // flush double indirect range + + if (data->max_double_indirect_range == 0) + return B_OK; + + off_t indirectBlock = fVolume->ToBlock(data->double_indirect); + + for (int32 l = 0;l < data->double_indirect.length;l++) { + block_run *indirectRuns = (block_run *)cached.SetTo(indirectBlock + l); + if (indirectRuns == NULL) + return B_FILE_ERROR; + + CachedBlock directCached(fVolume); + + for (int32 k = 0;k < count;k++) { + if (indirectRuns[k].IsZero()) + return B_OK; + + block = fVolume->ToBlock(indirectRuns[k]); + for (int32 j = 0;j < indirectRuns[k].length;j++) { + block_run *runs = (block_run *)directCached.SetTo(block + j); + if (runs == NULL) + return B_FILE_ERROR; + + for (int32 i = 0;i < count;i++) { + if (runs[i].IsZero()) + return B_OK; + + // ToDo: combine single block_runs to bigger ones when + // they are adjacent + status = flush_blocks(fVolume->Device(),fVolume->ToBlock(runs[i]),runs[i].length); + if (status != B_OK) + return status; + } + } + } + } + return B_OK; +} + + +status_t +Inode::Remove(Transaction *transaction,const char *name,off_t *_id,bool isDirectory) +{ + BPlusTree *tree; + if (GetTree(&tree) != B_OK) + RETURN_ERROR(B_BAD_VALUE); + + // does the file even exists? + off_t id; + if (tree->Find((uint8 *)name,(uint16)strlen(name),&id) < B_OK) + return B_ENTRY_NOT_FOUND; + + if (_id) + *_id = id; + + Vnode vnode(fVolume,id); + Inode *inode; + status_t status = vnode.Get(&inode); + if (status < B_OK) { + REPORT_ERROR(status); + return B_ENTRY_NOT_FOUND; + } + + // It's a bit stupid, but indices are regarded as directories + // in BFS - so a test for a directory always succeeds, but you + // should really be able to do whatever you want with your indices + // without having to remove all files first :) + if (!inode->IsIndex()) { + // if it's not of the correct type, don't delete it! + if (inode->IsDirectory() != isDirectory) + return isDirectory ? B_NOT_A_DIRECTORY : B_IS_A_DIRECTORY; + + // only delete empty directories + if (isDirectory && !inode->IsEmpty()) + return B_DIRECTORY_NOT_EMPTY; + } + + // remove_vnode() allows the inode to be accessed until the last put_vnode() + if (remove_vnode(fVolume->ID(),id) != B_OK) + return B_ERROR; + + if (tree->Remove(transaction,(uint8 *)name,(uint16)strlen(name),id) < B_OK) { + unremove_vnode(fVolume->ID(),id); + RETURN_ERROR(B_ERROR); + } + + // update the inode, so that no one will ever doubt it's deleted :-) + inode->Node()->flags |= INODE_DELETED; + + // In balance to the Inode::Create() method, the main indices + // are updated here (name, size, & last_modified) + + Index index(fVolume); + if ((inode->Mode() & (S_ATTR_DIR | S_ATTR | S_INDEX_DIR)) == 0) { + index.RemoveName(transaction,name,inode); + // If removing from the index fails, it is not regarded as a + // fatal error and will not be reported back! + // Deleted inodes won't be visible in queries anyway. + } + + if ((inode->Mode() & (S_FILE | S_SYMLINK)) != 0) { + index.RemoveSize(transaction,inode); + index.RemoveLastModified(transaction,inode); + } + + if (inode->WriteBack(transaction) < B_OK) + return B_ERROR; + + return B_OK; +} + + +/** Creates the inode with the specified parent directory, and automatically + * adds the created inode to that parent directory. If an attribute directory + * is created, it will also automatically added to the parent inode as such. + * However, the indices root node, and the regular root node won't be added + * to the super block. + * It will also create the initial B+tree for the inode if it's a directory + * of any kind. + * If the "id" variable is given to store the inode's ID, the inode stays + * locked - you have to call put_vnode() if you don't use it anymore. + */ + +status_t +Inode::Create(Transaction *transaction,Inode *parent, const char *name, int32 mode, int omode, uint32 type, off_t *_id, Inode **_inode) +{ + block_run parentRun = parent ? parent->BlockRun() : block_run::Run(0,0,0); + Volume *volume = transaction->GetVolume(); + BPlusTree *tree = NULL; + + if (parent && (mode & S_ATTR_DIR) == 0 && parent->IsDirectory()) { + // check if the file already exists in the directory + if (parent->GetTree(&tree) != B_OK) + RETURN_ERROR(B_BAD_VALUE); + + // does the file already exist? + off_t offset; + if (tree->Find((uint8 *)name,(uint16)strlen(name),&offset) == B_OK) { + // return if the file should be a directory or opened in exclusive mode + if (mode & S_DIRECTORY || omode & O_EXCL) + return B_FILE_EXISTS; + + Vnode vnode(volume,offset); + Inode *inode; + status_t status = vnode.Get(&inode); + if (status < B_OK) { + REPORT_ERROR(status); + return B_ENTRY_NOT_FOUND; + } + + // if it's a directory, bail out! + if (inode->IsDirectory()) + return B_IS_A_DIRECTORY; + + // if omode & O_TRUNC, truncate the existing file + if (omode & O_TRUNC) { + WriteLocked locked(inode->Lock()); + + status_t status = inode->SetFileSize(transaction,0); + if (status < B_OK) + return status; + } + + // only keep the vnode in memory if the vnode_id pointer is provided + if (_id) { + *_id = offset; + vnode.Keep(); + } + if (_inode) + *_inode = inode; + + return B_OK; + } + } else if (parent && (mode & S_ATTR_DIR) == 0) + return B_BAD_VALUE; + + // allocate space for the new inode + InodeAllocator allocator(transaction); + block_run run; + Inode *inode; + status_t status = allocator.New(&parentRun,mode,run,&inode); + if (status < B_OK) + return status; + + // initialize the on-disk bfs_inode structure + + bfs_inode *node = inode->Node(); + + node->magic1 = INODE_MAGIC1; + node->inode_num = run; + node->parent = parentRun; + + node->uid = geteuid(); + node->gid = parent ? parent->Node()->gid : getegid(); + // the group ID is inherited from the parent, if available + node->mode = mode; + node->flags = INODE_IN_USE; + node->type = type; + + node->create_time = (bigtime_t)time(NULL) << INODE_TIME_SHIFT; + node->last_modified_time = node->create_time | (volume->GetUniqueID() & INODE_TIME_MASK); + // we use Volume::GetUniqueID() to avoid having too many duplicates in the + // last_modified index + + node->inode_size = volume->InodeSize(); + + // only add the name to regular files, directories, or symlinks + // don't add it to attributes, or indices + if (tree && (mode & (S_INDEX_DIR | S_ATTR_DIR | S_ATTR)) == 0 + && inode->SetName(transaction,name) < B_OK) + return B_ERROR; + + // initialize b+tree if it's a directory (and add "." & ".." if it's + // a standard directory for files - not for attributes or indices) + if (mode & (S_DIRECTORY | S_ATTR_DIR | S_INDEX_DIR)) { + BPlusTree *tree = inode->fTree = new BPlusTree(transaction,inode); + if (tree == NULL || tree->InitCheck() < B_OK) + return B_ERROR; + + if ((mode & (S_INDEX_DIR | S_ATTR_DIR)) == 0) { + if (tree->Insert(transaction,".",inode->BlockNumber()) < B_OK + || tree->Insert(transaction,"..",volume->ToBlock(inode->Parent())) < B_OK) + return B_ERROR; + } + } + + // update the main indices (name, size & last_modified) + Index index(volume); + if ((mode & (S_ATTR_DIR | S_ATTR | S_INDEX_DIR)) == 0) { + status = index.InsertName(transaction,name,inode); + if (status < B_OK && status != B_BAD_INDEX) + return status; + } + + inode->UpdateOldLastModified(); + + // The "size" & "last_modified" indices don't contain directories + if ((mode & (S_FILE | S_SYMLINK)) != 0) { + // if adding to these indices fails, the inode creation will not be harmed + index.InsertSize(transaction,inode); + index.InsertLastModified(transaction,inode); + } + + if ((status = inode->WriteBack(transaction)) < B_OK) + return status; + + if (new_vnode(volume->ID(),inode->ID(),inode) != B_OK) + return B_ERROR; + + // add a link to the inode from the parent, depending on its type + if (tree && tree->Insert(transaction,name,volume->ToBlock(run)) < B_OK) { + put_vnode(volume->ID(),inode->ID()); + RETURN_ERROR(B_ERROR); + } else if (parent && mode & S_ATTR_DIR) { + parent->Attributes() = run; + parent->WriteBack(transaction); + } + + allocator.Keep(); + + if (_id != NULL) + *_id = inode->ID(); + else + put_vnode(volume->ID(),inode->ID()); + + if (_inode != NULL) + *_inode = inode; + + return B_OK; +} + + +// #pragma mark - + + +AttributeIterator::AttributeIterator(Inode *inode) + : + fCurrentSmallData(0), + fInode(inode), + fAttributes(NULL), + fIterator(NULL), + fBuffer(NULL) +{ + inode->AddIterator(this); +} + + +AttributeIterator::~AttributeIterator() +{ + if (fAttributes) + put_vnode(fAttributes->GetVolume()->ID(),fAttributes->ID()); + + delete fIterator; + fInode->RemoveIterator(this); +} + + +status_t +AttributeIterator::Rewind() +{ + fCurrentSmallData = 0; + + if (fIterator != NULL) + fIterator->Rewind(); + + return B_OK; +} + + +status_t +AttributeIterator::GetNext(char *name, size_t *_length, uint32 *_type, vnode_id *_id) +{ + // read attributes out of the small data section + + if (fCurrentSmallData >= 0) { + small_data *item = fInode->Node()->small_data_start; + + fInode->SmallDataLock().Lock(); + + int32 i = 0; + for (;;item = item->Next()) { + if (item->IsLast(fInode->Node())) + break; + + if (item->name_size == FILE_NAME_NAME_LENGTH + && *item->Name() == FILE_NAME_NAME) + continue; + + if (i++ == fCurrentSmallData) + break; + } + + if (!item->IsLast(fInode->Node())) { + strncpy(name,item->Name(),B_FILE_NAME_LENGTH); + *_type = item->type; + *_length = item->name_size; + *_id = (vnode_id)fCurrentSmallData; + + fCurrentSmallData = i; + } + else { + // stop traversing the small_data section + fCurrentSmallData = -1; + } + + fInode->SmallDataLock().Unlock(); + + if (fCurrentSmallData != -1) + return B_OK; + } + + // read attributes out of the attribute directory + + if (fInode->Attributes().IsZero()) + return B_ENTRY_NOT_FOUND; + + Volume *volume = fInode->GetVolume(); + + // if you haven't yet access to the attributes directory, get it + if (fAttributes == NULL) { + if (get_vnode(volume->ID(),volume->ToVnode(fInode->Attributes()),(void **)&fAttributes) != 0 + || fAttributes == NULL) { + FATAL(("get_vnode() failed in AttributeIterator::GetNext(vnode_id = %Ld,name = \"%s\")\n",fInode->ID(),name)); + return B_ENTRY_NOT_FOUND; + } + + BPlusTree *tree; + if (fAttributes->GetTree(&tree) < B_OK + || (fIterator = new TreeIterator(tree)) == NULL) { + FATAL(("could not get tree in AttributeIterator::GetNext(vnode_id = %Ld,name = \"%s\")\n",fInode->ID(),name)); + return B_ENTRY_NOT_FOUND; + } + } + + block_run run; + uint16 length; + vnode_id id; + status_t status = fIterator->GetNextEntry(name,&length,B_FILE_NAME_LENGTH,&id); + if (status < B_OK) + return status; + + Vnode vnode(volume,id); + Inode *attribute; + if ((status = vnode.Get(&attribute)) == B_OK) { + *_type = attribute->Node()->type; + *_length = attribute->Node()->data.size; + *_id = id; + } + + return status; +} + + +void +AttributeIterator::Update(uint16 index, int8 change) +{ + // fCurrentSmallData points already to the next item + if (index < fCurrentSmallData) + fCurrentSmallData += change; +} + diff --git a/src/add-ons/kernel/file_systems/befs/Inode.h b/src/add-ons/kernel/file_systems/befs/Inode.h new file mode 100644 index 0000000000..5148270997 --- /dev/null +++ b/src/add-ons/kernel/file_systems/befs/Inode.h @@ -0,0 +1,309 @@ +#ifndef INODE_H +#define INODE_H +/* Inode - inode access functions +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include +#ifdef USER +# include "myfs.h" +# include +#endif + +#ifndef _IMPEXP_KERNEL +# define _IMPEXP_KERNEL +#endif + +extern "C" { + #include + #include +} + +#include + +#include "Volume.h" +#include "Journal.h" +#include "Lock.h" +#include "Chain.h" +#include "Debug.h" + + +class BPlusTree; +class TreeIterator; +class AttributeIterator; + + +enum inode_type { + S_DIRECTORY = S_IFDIR, + S_FILE = S_IFREG, + S_SYMLINK = S_IFLNK +}; + + +// The CachedBlock class is completely implemented as inlines. +// It should be used when cache single blocks to make sure they +// will be properly released after use (and it's also very +// convenient to use them). + +class CachedBlock { + public: + CachedBlock(Volume *volume) + : + fVolume(volume), + fBlock(NULL) + { + } + + CachedBlock(Volume *volume,off_t block,bool empty = false) + : + fVolume(volume), + fBlock(NULL) + { + SetTo(block,empty); + } + + CachedBlock(Volume *volume,block_run run,bool empty = false) + : + fVolume(volume), + fBlock(NULL) + { + SetTo(volume->ToBlock(run),empty); + } + + ~CachedBlock() + { + Unset(); + } + + void Unset() + { + if (fBlock != NULL) + release_block(fVolume->Device(),fBlockNumber); + } + + uint8 *SetTo(off_t block,bool empty = false) + { + Unset(); + fBlockNumber = block; + return fBlock = empty ? (uint8 *)get_empty_block(fVolume->Device(),block,fVolume->BlockSize()) + : (uint8 *)get_block(fVolume->Device(),block,fVolume->BlockSize()); + } + + uint8 *SetTo(block_run run,bool empty = false) + { + return SetTo(fVolume->ToBlock(run),empty); + } + + status_t WriteBack(Transaction *transaction) + { + if (transaction == NULL || fBlock == NULL) + RETURN_ERROR(B_BAD_VALUE); + + return transaction->WriteBlocks(fBlockNumber,fBlock); + } + + uint8 *Block() const { return fBlock; } + off_t BlockNumber() const { return fBlockNumber; } + + protected: + Volume *fVolume; + off_t fBlockNumber; + uint8 *fBlock; +}; + + +class Inode : public CachedBlock { + public: + Inode(Volume *volume,vnode_id id,bool empty = false,uint8 reenter = 0); + ~Inode(); + + bfs_inode *Node() const { return (bfs_inode *)fBlock; } + vnode_id ID() const { return fVolume->ToVnode(fBlockNumber); } + + ReadWriteLock &Lock() { return fLock; } + SimpleLock &SmallDataLock() { return fSmallDataLock; } + + mode_t Mode() const { return Node()->mode; } + int32 Flags() const { return Node()->flags; } + bool IsDirectory() const { return Mode() & (S_DIRECTORY | S_INDEX_DIR | S_ATTR_DIR); } + // note, that this test will also be true for S_IFBLK (not that it's used in the fs :) + bool IsIndex() const { return (Mode() & (S_INDEX_DIR | 0777)) == S_INDEX_DIR; } + // that's a stupid check, but AFAIK the only possible method... + + bool IsSymLink() const { return S_ISLNK(Mode()); } + bool HasUserAccessableStream() const { return S_ISREG(Mode()); } + // currently only files can be accessed with bfs_read()/bfs_write() + + off_t Size() const { return Node()->data.size; } + + block_run &BlockRun() const { return Node()->inode_num; } + block_run &Parent() const { return Node()->parent; } + block_run &Attributes() const { return Node()->attributes; } + Volume *GetVolume() const { return fVolume; } + + status_t InitCheck(); + + status_t CheckPermissions(int accessMode) const; + + // small_data access methods + status_t MakeSpaceForSmallData(Transaction *transaction,const char *name, int32 length); + status_t RemoveSmallData(Transaction *transaction,const char *name); + status_t AddSmallData(Transaction *transaction,const char *name,uint32 type,const uint8 *data,size_t length,bool force = false); + status_t GetNextSmallData(small_data **smallData) const; + small_data *FindSmallData(const char *name) const; + const char *Name() const; + status_t SetName(Transaction *transaction,const char *name); + + // high-level attribute methods + status_t ReadAttribute(const char *name, int32 type, off_t pos, uint8 *buffer, size_t *_length); + status_t WriteAttribute(Transaction *transaction, const char *name, int32 type, off_t pos, const uint8 *buffer, size_t *_length); + status_t RemoveAttribute(Transaction *transaction, const char *name); + + // attribute methods + status_t GetAttribute(const char *name,Inode **attribute); + void ReleaseAttribute(Inode *attribute); + status_t CreateAttribute(Transaction *transaction,const char *name,uint32 type,Inode **attribute); + + // for directories only: + status_t GetTree(BPlusTree **); + bool IsEmpty(); + + // manipulating the data stream + status_t FindBlockRun(off_t pos,block_run &run,off_t &offset); + + status_t ReadAt(off_t pos,uint8 *buffer,size_t *length); + status_t WriteAt(Transaction *transaction,off_t pos,const uint8 *buffer,size_t *length); + status_t FillGapWithZeros(off_t oldSize,off_t newSize); + + status_t SetFileSize(Transaction *transaction,off_t size); + status_t Append(Transaction *transaction,off_t bytes); + status_t Trim(Transaction *transaction); + + status_t Sync(); + + // create/remove inodes + status_t Remove(Transaction *transaction,const char *name,off_t *_id = NULL,bool isDirectory = false); + static status_t Create(Transaction *transaction,Inode *parent,const char *name,int32 mode,int omode,uint32 type,off_t *_id = NULL,Inode **_inode = NULL); + + // index maintaining helper + void UpdateOldSize() { fOldSize = Size(); } + void UpdateOldLastModified() { fOldLastModified = Node()->last_modified_time; } + off_t OldSize() { return fOldSize; } + off_t OldLastModified() { return fOldLastModified; } + + private: + friend AttributeIterator; + + status_t RemoveSmallData(small_data *item,int32 index); + + void AddIterator(AttributeIterator *iterator); + void RemoveIterator(AttributeIterator *iterator); + + status_t FreeStaticStreamArray(Transaction *transaction,int32 level,block_run run,off_t size,off_t offset,off_t &max); + status_t FreeStreamArray(Transaction *transaction, block_run *array, uint32 arrayLength, off_t size, off_t &offset, off_t &max); + status_t GrowStream(Transaction *transaction,off_t size); + status_t ShrinkStream(Transaction *transaction,off_t size); + + BPlusTree *fTree; + Inode *fAttributes; + ReadWriteLock fLock; + off_t fOldSize; // we need those values to ensure we will remove + off_t fOldLastModified; // the correct keys from the indices + + mutable SimpleLock fSmallDataLock; + Chain fIterators; +}; + + +// The Vnode class provides a convenience layer upon get_vnode(), so that +// you don't have to call put_vnode() anymore, which may make code more +// readable in some cases + +class Vnode { + public: + Vnode(Volume *volume,vnode_id id) + : + fVolume(volume), + fID(id) + { + } + + Vnode(Volume *volume,block_run run) + : + fVolume(volume), + fID(volume->ToVnode(run)) + { + } + + ~Vnode() + { + Put(); + } + + status_t Get(Inode **inode) + { + // should we check inode against NULL here? it should not be necessary + return get_vnode(fVolume->ID(),fID,(void **)inode); + } + + void Put() + { + if (fVolume) + put_vnode(fVolume->ID(),fID); + fVolume = NULL; + } + + void Keep() + { + fVolume = NULL; + } + + private: + Volume *fVolume; + vnode_id fID; +}; + + +class AttributeIterator { + public: + AttributeIterator(Inode *inode); + ~AttributeIterator(); + + status_t Rewind(); + status_t GetNext(char *name,size_t *length,uint32 *type,vnode_id *id); + + private: + int32 fCurrentSmallData; + Inode *fInode, *fAttributes; + TreeIterator *fIterator; + void *fBuffer; + + private: + friend Chain; + friend Inode; + + void Update(uint16 index,int8 change); + AttributeIterator *fNext; +}; + + +/** Converts the "omode", the open flags given to bfs_open(), into + * access modes, e.g. since O_RDONLY requires read access to the + * file, it will be converted to R_OK. + */ + +inline int oModeToAccess(int omode) +{ + omode &= O_RWMASK; + if (omode == O_RDONLY) + return R_OK; + else if (omode == O_WRONLY) + return W_OK; + + return R_OK | W_OK; +} + +#endif /* INODE_H */ diff --git a/src/add-ons/kernel/file_systems/befs/Journal.cpp b/src/add-ons/kernel/file_systems/befs/Journal.cpp new file mode 100644 index 0000000000..a60b7c8b88 --- /dev/null +++ b/src/add-ons/kernel/file_systems/befs/Journal.cpp @@ -0,0 +1,433 @@ +/* Journal - transaction and logging +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include "Journal.h" +#include "Inode.h" +#include "Debug.h" +#include "cpp.h" + + +Journal::Journal(Volume *volume) + : + fVolume(volume), + fLock("bfs journal"), + fOwner(NULL), + fOwningThread(-1), + fArray(volume->BlockSize()), + fLogSize(volume->Log().length), + fMaxTransactionSize(fLogSize / 4 - 5), + fUsed(0), + fTransactionsInEntry(0) +{ + if (fMaxTransactionSize > fLogSize / 2) + fMaxTransactionSize = fLogSize / 2 - 5; +} + + +Journal::~Journal() +{ + FlushLogAndBlocks(); +} + + +status_t +Journal::InitCheck() +{ + if (fVolume->LogStart() != fVolume->LogEnd()) { + if (fVolume->SuperBlock().flags != SUPER_BLOCK_DISK_DIRTY) + FATAL(("log_start and log_end differ, but disk is marked clean - trying to replay log...\n")); + + return ReplayLog(); + } + + return B_OK; +} + + +status_t +Journal::CheckLogEntry(int32 count,off_t *array) +{ + // ToDo: check log entry integrity (block numbers and entry size) + PRINT(("Log entry has %ld entries (%Ld)\n",count)); + return B_OK; +} + + +status_t +Journal::ReplayLogEntry(int32 *_start) +{ + PRINT(("ReplayLogEntry(start = %u)\n",*_start)); + + off_t logOffset = fVolume->ToBlock(fVolume->Log()); + off_t arrayBlock = (*_start % fLogSize) + fVolume->ToBlock(fVolume->Log()); + int32 blockSize = fVolume->BlockSize(); + int32 count = 1,valuesInBlock = blockSize / sizeof(off_t); + int32 numArrayBlocks; + off_t blockNumber; + bool first = true; + + CachedBlock cached(fVolume); + while (count > 0) { + off_t *array = (off_t *)cached.SetTo(arrayBlock); + if (array == NULL) + return B_IO_ERROR; + + int32 index = 0; + if (first) { + count = array[0]; + if (count < 1 || count >= fLogSize) + return B_BAD_DATA; + + first = false; + + numArrayBlocks = ((count + 1) * sizeof(off_t) + blockSize - 1) / blockSize; + blockNumber = (*_start + numArrayBlocks) % fLogSize; + // first real block in this log entry + *_start += count; + index++; + // the first entry in the first block is the number + // of blocks in that log entry + } + (*_start)++; + + if (CheckLogEntry(count,array + 1) < B_OK) + return B_BAD_DATA; + + CachedBlock cachedCopy(fVolume); + for (;index < valuesInBlock && count-- > 0;index++) { + PRINT(("replay block %Ld in log at %Ld!\n",array[index],blockNumber)); + + uint8 *copy = cachedCopy.SetTo(logOffset + blockNumber); + if (copy == NULL) + RETURN_ERROR(B_IO_ERROR); + + ssize_t written = write_pos(fVolume->Device(),array[index] << fVolume->BlockShift(),copy,blockSize); + if (written != blockSize) + RETURN_ERROR(B_IO_ERROR); + + blockNumber = (blockNumber + 1) % fLogSize; + } + arrayBlock++; + if (arrayBlock > fVolume->ToBlock(fVolume->Log()) + fLogSize) + arrayBlock = fVolume->ToBlock(fVolume->Log()); + } + return B_OK; +} + + +/** Replays all log entries - this will put the disk into a + * consistent and clean state, if it was not correctly unmounted + * before. + * This method is called by Journal::InitCheck() if the log start + * and end pointer don't match. + */ + +status_t +Journal::ReplayLog() +{ + INFORM(("Replay log, disk was not correctly unmounted...\n")); + + int32 start = fVolume->LogStart(); + int32 lastStart = -1; + while (true) { + + // stop if the log is completely flushed + if (start == fVolume->LogEnd()) + break; + + if (start == lastStart) { + // strange, flushing the log hasn't changed the log_start pointer + return B_ERROR; + } + lastStart = start; + + status_t status = ReplayLogEntry(&start); + if (status < B_OK) { + FATAL(("replaying log entry from %u failed: %s\n",start,strerror(status))); + return B_ERROR; + } + start = start % fLogSize; + } + + PRINT(("replaying worked fine!\n")); + fVolume->SuperBlock().log_start = fVolume->LogEnd(); + fVolume->LogStart() = fVolume->LogEnd(); + fVolume->SuperBlock().flags = SUPER_BLOCK_DISK_CLEAN; + + return fVolume->WriteSuperBlock(); +} + + +/** This is a callback function that is called by the cache, whenever + * a block is flushed to disk that was updated as part of a transaction. + * This is necessary to keep track of completed transactions, to be + * able to update the log start pointer. + */ + +void +Journal::blockNotify(off_t blockNumber,size_t numBlocks,void *arg) +{ + log_entry *logEntry = (log_entry *)arg; + + logEntry->cached_blocks -= numBlocks; + if (logEntry->cached_blocks > 0) { + // nothing to do yet... + return; + } + + Journal *journal = logEntry->journal; + disk_super_block &superBlock = journal->fVolume->SuperBlock(); + bool update = false; + + // Set log_start pointer if possible... + + if (logEntry == journal->fEntries.head) { + if (logEntry->Next() != NULL) { + int32 length = logEntry->next->start - logEntry->start; + superBlock.log_start = (superBlock.log_start + length) % journal->fLogSize; + } else + superBlock.log_start = journal->fVolume->LogEnd(); + + update = true; + } + journal->fUsed -= logEntry->length; + + journal->fEntriesLock.Lock(); + logEntry->Remove(); + journal->fEntriesLock.Unlock(); + + free(logEntry); + + // update the super block, and change the disk's state, if necessary + + if (update) { + journal->fVolume->LogStart() = superBlock.log_start; + + if (superBlock.log_start == superBlock.log_end) + superBlock.flags = SUPER_BLOCK_DISK_CLEAN; + + journal->fVolume->WriteSuperBlock(); + } +} + + +status_t +Journal::WriteLogEntry() +{ + fTransactionsInEntry = 0; + fHasChangedBlocks = false; + + sorted_array *array = fArray.Array(); + if (array == NULL || array->count == 0) + return B_OK; + + // Make sure there is enough space in the log. + // If that fails for whatever reason, panic! + force_cache_flush(fVolume->Device(),false); + int32 tries = fLogSize / 2 + 1; + while (TransactionSize() > FreeLogBlocks() && tries-- > 0) + force_cache_flush(fVolume->Device(),true); + + if (tries <= 0) { + fVolume->Panic(); + return B_BAD_DATA; + } + + int32 blockShift = fVolume->BlockShift(); + off_t logOffset = fVolume->ToBlock(fVolume->Log()) << blockShift; + off_t logStart = fVolume->LogEnd(); + off_t logPosition = logStart % fLogSize; + + // Write disk block array + + uint8 *arrayBlock = (uint8 *)array; + + for (int32 size = fArray.BlocksUsed();size-- > 0;) { + write_pos(fVolume->Device(),logOffset + (logPosition << blockShift),arrayBlock,fVolume->BlockSize()); + + logPosition = (logPosition + 1) % fLogSize; + arrayBlock += fVolume->BlockSize(); + } + + // Write logged blocks into the log + + CachedBlock cached(fVolume); + for (int32 i = 0;i < array->count;i++) { + uint8 *block = cached.SetTo(array->values[i]); + if (block == NULL) + return B_IO_ERROR; + + write_pos(fVolume->Device(),logOffset + (logPosition << blockShift),block,fVolume->BlockSize()); + logPosition = (logPosition + 1) % fLogSize; + } + + log_entry *logEntry = (log_entry *)malloc(sizeof(log_entry)); + if (logEntry != NULL) { + logEntry->start = logStart; + logEntry->length = TransactionSize(); + logEntry->cached_blocks = array->count; + logEntry->journal = this; + + fEntriesLock.Lock(); + fEntries.Add(logEntry); + fEntriesLock.Unlock(); + + fCurrent = logEntry; + fUsed += logEntry->length; + + set_blocks_info(fVolume->Device(),&array->values[0],array->count,blockNotify,logEntry); + } + + // If the log goes to the next round (the log is written as a + // circular buffer), all blocks will be flushed out which is + // possible because we don't have any locked blocks at this + // point. + if (logPosition < logStart) + fVolume->FlushDevice(); + + // We need to flush the drives own cache here to ensure + // disk consistency. + // If that call fails, we can't do anything about it anyway + ioctl(fVolume->Device(),B_FLUSH_DRIVE_CACHE); + + fArray.MakeEmpty(); + + // Update the log end pointer in the super block + fVolume->SuperBlock().flags = SUPER_BLOCK_DISK_DIRTY; + fVolume->SuperBlock().log_end = logPosition; + fVolume->LogEnd() = logPosition; + + fVolume->WriteSuperBlock(); +} + + +status_t +Journal::FlushLogAndBlocks() +{ + status_t status = Lock((Transaction *)this); + if (status != B_OK) + return status; + + // write the current log entry to disk + + if (TransactionSize() != 0) { + status = WriteLogEntry(); + if (status < B_OK) + FATAL(("writing current log entry failed: %s\n",status)); + } + status = fVolume->FlushDevice(); + + Unlock((Transaction *)this,true); + return status; +} + + +status_t +Journal::Lock(Transaction *owner) +{ + if (owner == fOwner) + return B_OK; + + status_t status = fLock.Lock(); + if (status == B_OK) { + fOwner = owner; + fOwningThread = find_thread(NULL); + } + + // if the last transaction is older than 2 secs, start a new one + if (fTransactionsInEntry != 0 && system_time() - fTimestamp > 2000000L) + WriteLogEntry(); + + return B_OK; +} + + +void +Journal::Unlock(Transaction *owner,bool success) +{ + if (owner != fOwner) + return; + + TransactionDone(success); + + fTimestamp = system_time(); + fOwner = NULL; + fOwningThread = -1; + fLock.Unlock(); +} + + +status_t +Journal::TransactionDone(bool success) +{ + if (!success && fTransactionsInEntry == 0) { + // we can safely abort the transaction + // ToDo: abort the transaction + PRINT(("should abort transaction...\n")); + } + + // Up to a maximum size, we will just batch several + // transactions together to improve speed + if (TransactionSize() < fMaxTransactionSize) { + fTransactionsInEntry++; + fHasChangedBlocks = false; + + return B_OK; + } + + return WriteLogEntry(); +} + + +status_t +Journal::LogBlocks(off_t blockNumber,const uint8 *buffer,size_t numBlocks) +{ + // ToDo: that's for now - we should change the log file size here + if (TransactionSize() + numBlocks + 1 > fLogSize) + return B_DEVICE_FULL; + + fHasChangedBlocks = true; + int32 blockSize = fVolume->BlockSize(); + + for (;numBlocks-- > 0;blockNumber++,buffer += blockSize) { + if (fArray.Find(blockNumber) >= 0) + continue; + + // Insert the block into the transaction's array, and write the changes + // back into the locked cache buffer + fArray.Insert(blockNumber); + status_t status = cached_write_locked(fVolume->Device(),blockNumber,buffer,1,blockSize); + if (status < B_OK) + return status; + } + + // If necessary, flush the log, so that we have enough space for this transaction + if (TransactionSize() > FreeLogBlocks()) + force_cache_flush(fVolume->Device(),true); + + return B_OK; +} + + +// #pragma mark - + + +status_t +Transaction::Start(Volume *volume,off_t refBlock) +{ + // has it already been started? + if (fJournal != NULL) + return B_OK; + + fJournal = volume->GetJournal(refBlock); + if (fJournal != NULL && fJournal->Lock(this) == B_OK) + return B_OK; + + fJournal = NULL; + return B_ERROR; +} + diff --git a/src/add-ons/kernel/file_systems/befs/Journal.h b/src/add-ons/kernel/file_systems/befs/Journal.h new file mode 100644 index 0000000000..f9195d780e --- /dev/null +++ b/src/add-ons/kernel/file_systems/befs/Journal.h @@ -0,0 +1,152 @@ +#ifndef JOURNAL_H +#define JOURNAL_H +/* Journal - transaction and logging +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include + +#ifdef USER +# include "myfs.h" +# include +#endif + +#ifndef _IMPEXP_KERNEL +# define _IMPEXP_KERNEL +#endif + +extern "C" { + #include + #include +} + +#include "Volume.h" +#include "Chain.h" +#include "Utility.h" + + +struct log_entry : node { + uint16 start; + uint16 length; + uint32 cached_blocks; + Journal *journal; +}; + + +class Journal { + public: + Journal(Volume *); + ~Journal(); + + status_t InitCheck(); + + status_t Lock(Transaction *owner); + void Unlock(Transaction *owner,bool success); + + status_t CheckLogEntry(int32 count, off_t *array); + status_t ReplayLogEntry(int32 *start); + status_t ReplayLog(); + + status_t WriteLogEntry(); + status_t LogBlocks(off_t blockNumber,const uint8 *buffer, size_t numBlocks); + + thread_id CurrentThread() const { return fOwningThread; } + Transaction *CurrentTransaction() const { return fOwner; } + uint32 TransactionSize() const { return fArray.CountItems() + fArray.BlocksUsed(); } + + status_t FlushLogAndBlocks(); + Volume *GetVolume() const { return fVolume; } + + inline int32 FreeLogBlocks() const; + + private: + friend log_entry; + + static void blockNotify(off_t blockNumber, size_t numBlocks, void *arg); + status_t TransactionDone(bool success); + + Volume *fVolume; + Benaphore fLock; + Transaction *fOwner; + thread_id fOwningThread; + BlockArray fArray; + uint32 fLogSize,fMaxTransactionSize,fUsed; + int32 fTransactionsInEntry; + SimpleLock fEntriesLock; + list fEntries; + log_entry *fCurrent; + bool fHasChangedBlocks; + bigtime_t fTimestamp; +}; + + +inline int32 +Journal::FreeLogBlocks() const +{ + return fVolume->LogStart() <= fVolume->LogEnd() ? + fLogSize - fVolume->LogEnd() + fVolume->LogStart() + : fVolume->LogStart() - fVolume->LogEnd(); +} + + +// For now, that's only a dumb class that does more or less nothing +// else than writing the blocks directly to the real location. +// It doesn't yet use logging. + +class Transaction { + public: + Transaction(Volume *volume,off_t refBlock) + : + fJournal(NULL) + { + Start(volume,refBlock); + } + + Transaction(Volume *volume,block_run refRun) + : + fJournal(NULL) + { + Start(volume,volume->ToBlock(refRun)); + } + + Transaction() + : + fJournal(NULL) + { + } + + ~Transaction() + { + if (fJournal) + fJournal->Unlock(this,false); + } + + status_t Start(Volume *volume,off_t refBlock); + + void Done() + { + if (fJournal != NULL) + fJournal->Unlock(this,true); + fJournal = NULL; + } + + status_t WriteBlocks(off_t blockNumber,const uint8 *buffer,size_t numBlocks = 1) + { + if (fJournal == NULL) + return B_NO_INIT; + + return fJournal->LogBlocks(blockNumber,buffer,numBlocks); + //status_t status = cached_write/*_locked*/(fVolume->Device(),blockNumber,buffer,numBlocks,fVolume->BlockSize()); + //return status; + } + + Volume *GetVolume() { return fJournal != NULL ? fJournal->GetVolume() : NULL; } + + protected: + Journal *fJournal; +}; + +#endif /* JOURNAL_H */ diff --git a/src/add-ons/kernel/file_systems/befs/Lock.h b/src/add-ons/kernel/file_systems/befs/Lock.h new file mode 100644 index 0000000000..8ffd9dc133 --- /dev/null +++ b/src/add-ons/kernel/file_systems/befs/Lock.h @@ -0,0 +1,337 @@ +#ifndef LOCK_H +#define LOCK_H +/* Lock - benaphores, read/write lock implementation +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** Roughly based on a Be sample code written by Nathan Schrenk. +** +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include + + +class Benaphore { + public: + Benaphore(const char *name = "bfs benaphore") + : + fSemaphore(create_sem(0, name)), + fCount(1) + { + } + + ~Benaphore() + { + delete_sem(fSemaphore); + } + + status_t InitCheck() + { + if (fSemaphore < B_OK) + return fSemaphore; + + return B_OK; + } + + status_t Lock() + { + if (atomic_add(&fCount, -1) <= 0) + return acquire_sem(fSemaphore); + + return B_OK; + } + + void Unlock() + { + if (atomic_add(&fCount, 1) < 0) + release_sem(fSemaphore); + } + + private: + sem_id fSemaphore; + vint32 fCount; +}; + +// a convenience class to lock the benaphore + +class Locker { + public: + Locker(Benaphore &lock) + : fLock(lock) + { + fStatus = lock.Lock(); + } + + ~Locker() + { + if (fStatus == B_OK) + fLock.Unlock(); + } + + private: + Benaphore &fLock; + status_t fStatus; +}; + + +//**** Many Reader/Single Writer Lock + +// This is a "fast" implementation of a single writer/many reader +// locking scheme. It's fast because it uses the benaphore idea +// to do lazy semaphore locking - in most cases it will only have +// to do some simple integer arithmetic. +// The second semaphore (fWriteLock) is needed to prevent the situation +// that a second writer can acquire the lock when there are still readers +// holding it. + +#define MAX_READERS 100000 + +// Note: this code will break if you actually have 100000 readers +// at once. With the current thread/... limits in BeOS you can't +// touch that value, but it might be possible in the future. +// Also, you can only have about 20000 concurrent writers until +// the semaphore count exceeds the int32 bounds + +// Timeouts: +// It may be a good idea to have timeouts for the WriteLocked class, +// in case something went wrong - we'll see if this is necessary, +// but it would be a somewhat poor work-around for a deadlock... +// But the only real problem with timeouts could be for things like +// "chkbfs" - because such a tool may need to lock for some more time + + +// define if you want to have fast locks as the foundation for the +// ReadWriteLock class - the benefit is that acquire_sem() doesn't +// have to be called when there is no one waiting. +// The disadvantage is the use of 2 real semaphores which is quite +// expensive regarding that BeOS only allows for a total of 64k +// semaphores. + +//#define FAST_LOCK +#ifdef FAST_LOCK +class ReadWriteLock { + public: + ReadWriteLock(const char *name = "bfs r/w lock") + : + fSemaphore(create_sem(0, name)), + fCount(MAX_READERS), + fWriteLock() + { + } + + ~ReadWriteLock() + { + delete_sem(fSemaphore); + } + + status_t InitCheck() + { + if (fSemaphore < B_OK) + return fSemaphore; + + return B_OK; + } + + status_t Lock() + { + if (atomic_add(&fCount, -1) <= 0) + return acquire_sem(fSemaphore); + + return B_OK; + } + + void Unlock() + { + if (atomic_add(&fCount, 1) < 0) + release_sem(fSemaphore); + } + + status_t LockWrite() + { + if (fWriteLock.Lock() < B_OK) + return B_ERROR; + + int32 readers = atomic_add(&fCount, -MAX_READERS); + status_t status = B_OK; + + if (readers < MAX_READERS) { + // Acquire sem for all readers currently not using a semaphore. + // But if we are not the only write lock in the queue, just get + // the one for us + status = acquire_sem_etc(fSemaphore,readers <= 0 ? 1 : MAX_READERS - readers,0,0); + } + fWriteLock.Unlock(); + + return status; + } + + void UnlockWrite() + { + int32 readers = atomic_add(&fCount,MAX_READERS); + if (readers < 0) { + // release sem for all readers only when we were the only writer + release_sem_etc(fSemaphore,readers <= -MAX_READERS ? 1 : -readers,0); + } + } + + private: + friend class ReadLocked; + friend class WriteLocked; + + sem_id fSemaphore; + vint32 fCount; + Benaphore fWriteLock; +}; +#else // FAST_LOCK +class ReadWriteLock { + public: + ReadWriteLock(const char *name = "bfs r/w lock") + : + fSemaphore(create_sem(MAX_READERS, name)) + { + } + + ~ReadWriteLock() + { + delete_sem(fSemaphore); + } + + status_t InitCheck() + { + if (fSemaphore < B_OK) + return fSemaphore; + + return B_OK; + } + + status_t Lock() + { + return acquire_sem(fSemaphore); + } + + void Unlock() + { + release_sem(fSemaphore); + } + + status_t LockWrite() + { + return acquire_sem_etc(fSemaphore,MAX_READERS,0,0); + } + + void UnlockWrite() + { + release_sem_etc(fSemaphore,MAX_READERS,0); + } + + private: + friend class ReadLocked; + friend class WriteLocked; + + sem_id fSemaphore; +}; +#endif // FAST_LOCK + + +class ReadLocked { + public: + ReadLocked(ReadWriteLock &lock) + : + fLock(lock) + { + fStatus = lock.Lock(); + } + + ~ReadLocked() + { + if (fStatus == B_OK) + fLock.Unlock(); + } + + private: + ReadWriteLock &fLock; + status_t fStatus; +}; + + +class WriteLocked { + public: + WriteLocked(ReadWriteLock &lock) + : + fLock(lock) + { + fStatus = lock.LockWrite(); + } + + ~WriteLocked() + { + if (fStatus == B_OK) + fLock.UnlockWrite(); + } + + status_t IsLocked() + { + return fStatus; + } + + private: + ReadWriteLock &fLock; + status_t fStatus; +}; + + +// A simple locking structure that doesn't use a semaphore - it's useful +// if you have to protect critical parts with a short runtime. + +class SimpleLock { + public: + SimpleLock() + : + fLock(0), + fUnlock(0) + { + } + + status_t Lock(bigtime_t time = 500) + { + int32 turn = atomic_add(&fLock,1); + while (turn != fUnlock) + snooze(time); + + // ToDo: the lock cannot fail currently! We may want + // to change this + return B_OK; + } + + void Unlock() + { + atomic_add(&fUnlock,1); + } + + private: + vint32 fLock; + vint32 fUnlock; +}; + +// A convenience class to lock the SimpleLock, note the +// different timing compared to the direct call + +class SimpleLocker { + public: + SimpleLocker(SimpleLock &lock,bigtime_t time = 1000) + : fLock(lock) + { + lock.Lock(time); + } + + ~SimpleLocker() + { + fLock.Unlock(); + } + + private: + SimpleLock &fLock; +}; + +#endif /* LOCK_H */ diff --git a/src/add-ons/kernel/file_systems/befs/Query.cpp b/src/add-ons/kernel/file_systems/befs/Query.cpp new file mode 100644 index 0000000000..ce37e6122a --- /dev/null +++ b/src/add-ons/kernel/file_systems/befs/Query.cpp @@ -0,0 +1,1505 @@ +/* Query - query parsing and evaluation +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** The pattern matching is roughly based on code originally written +** by J. Kercheval, and on code written by Kenneth Almquist, though +** it shares no code. +** +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include "Query.h" +#include "cpp.h" +#include "bfs.h" +#include "Debug.h" +#include "Stack.h" +#include "Volume.h" +#include "Inode.h" +#include "BPlusTree.h" +#include "Index.h" + +#include +#include +#include + +#include +#include +#include + + +// The parser has a very static design, but it will do what is required. +// +// ParseOr(), ParseAnd(), ParseEquation() are guarantying the operator +// precedence, that is =,!=,>,<,>=,<= .. && .. ||. +// Apparently, the "!" (not) can only be used with brackets. +// +// If you think that there are too few NULL pointer checks in some places +// of the code, just read the beginning of the query constructor. +// The API is not fully available, just the Query and the Expression class +// are. + + +enum ops { + OP_NONE, + + OP_AND, + OP_OR, + + OP_EQUATION, + + OP_EQUAL, + OP_UNEQUAL, + OP_GREATER_THAN, + OP_LESS_THAN, + OP_GREATER_THAN_OR_EQUAL, + OP_LESS_THAN_OR_EQUAL, +}; + +enum match { + NO_MATCH = 0, + MATCH_OK = 1, + + MATCH_BAD_PATTERN = -2, + MATCH_INVALID_CHARACTER +}; + +// return values from isValidPattern() +enum { + PATTERN_INVALID_ESCAPE = -3, + PATTERN_INVALID_RANGE, + PATTERN_INVALID_SET +}; + +union value { + int64 Int64; + uint64 Uint64; + int32 Int32; + uint32 Uint32; + float Float; + double Double; + char String[INODE_FILE_NAME_LENGTH]; +}; + +class Term { + public: + Term(int8 op) : fOp(op), fParent(NULL) {} + + int8 Op() const { return fOp; } + + void SetParent(Term *parent) { fParent = parent; } + Term *Parent() const { return fParent; } + + virtual status_t Match(Inode *inode,const char *attribute = NULL,int32 type = 0, + const uint8 *key = NULL,size_t size = 0) = 0; + virtual void Complement() = 0; + + virtual void CalculateScore(Index &index) = 0; + virtual int32 Score() const = 0; + + virtual status_t InitCheck() = 0; + +#ifdef DEBUG + virtual void PrintToStream() = 0; +#endif + + protected: + int8 fOp; + Term *fParent; +}; + +// Although an Equation object is quite independent from the volume on which +// the query is run, there are some dependencies that are produced while +// querying: +// The type/size of the value, the score, and if it has an index or not. +// So you could run more than one query on the same volume, but it might return +// wrong values when it runs concurrently on another volume. +// That's not an issue right now, because we run single-threaded and don't use +// queries more than once. + +class Equation : public Term { + public: + Equation(char **expr); + ~Equation(); + + virtual status_t InitCheck(); + + status_t ParseQuotedString(char **_start,char **_end); + char *CopyString(char *start, char *end); + + virtual status_t Match(Inode *inode,const char *attribute = NULL,int32 type = 0,const uint8 *key = NULL,size_t size = 0); + virtual void Complement(); + + status_t PrepareQuery(Volume *volume, Index &index, TreeIterator **iterator); + status_t GetNextMatching(Volume *volume,TreeIterator *iterator,struct dirent *dirent,size_t bufferSize); + + virtual void CalculateScore(Index &index); + virtual int32 Score() const { return fScore; } + +#ifdef DEBUG + virtual void PrintToStream(); +#endif + + private: + status_t ConvertValue(type_code type); + bool CompareTo(const uint8 *value, uint16 size); + uint8 *Value() const { return (uint8 *)&fValue; } + status_t MatchEmptyString(); + + char *fAttribute; + char *fString; + union value fValue; + type_code fType; + size_t fSize; + bool fIsPattern; + bool fIsSpecialTime; + + int32 fScore; + bool fHasIndex; +}; + +class Operator : public Term { + public: + Operator(Term *,int8,Term *); + ~Operator(); + + Term *Left() const { return fLeft; } + Term *Right() const { return fRight; } + + virtual status_t Match(Inode *inode,const char *attribute = NULL,int32 type = 0,const uint8 *key = NULL,size_t size = 0); + virtual void Complement(); + + virtual void CalculateScore(Index &index); + virtual int32 Score() const; + + virtual status_t InitCheck(); + + //Term *Copy() const; +#ifdef DEBUG + virtual void PrintToStream(); +#endif + + protected: + Term *fLeft,*fRight; +}; + + +//--------------------------------- + + +void +skipWhitespace(char **expr, int32 skip = 0) +{ + char *string = (*expr) + skip; + while (*string == ' ' || *string == '\t') string++; + *expr = string; +} + + +void +skipWhitespaceReverse(char **expr,char *stop) +{ + char *string = *expr; + while (string > stop && (*string == ' ' || *string == '\t')) string--; + *expr = string; +} + + +// #pragma mark - + + +uint32 +utf8ToUnicode(char **string) +{ + uint8 *bytes = (uint8 *)*string; + int32 length; + uint8 mask = 0x1f; + + switch (bytes[0] & 0xf0) { + case 0xc0: + case 0xd0: length = 2; break; + case 0xe0: length = 3; break; + case 0xf0: + mask = 0x0f; + length = 4; + break; + default: + // valid 1-byte character + // and invalid characters + (*string)++; + return bytes[0]; + } + uint32 c = bytes[0] & mask; + int32 i = 1; + for (;i < length && (bytes[i] & 0x80) > 0;i++) + c = (c << 6) | (bytes[i] & 0x3f); + + if (i < length) { + // invalid character + (*string)++; + return (uint32)bytes[0]; + } + *string += length; + return c; +} + + +int32 +getFirstPatternSymbol(char *string) +{ + char c; + + for (int32 index = 0;(c = *string++);index++) { + if (c == '*' || c == '?' || c == '[') + return index; + } + return -1; +} + + +bool +isPattern(char *string) +{ + return getFirstPatternSymbol(string) >= 0 ? true : false; +} + + +status_t +isValidPattern(char *pattern) +{ + while (*pattern) { + switch (*pattern++) { + case '\\': + // the escape character must not be at the end of the pattern + if (!*pattern++) + return PATTERN_INVALID_ESCAPE; + break; + + case '[': + if (pattern[0] == ']' || !pattern[0]) + return PATTERN_INVALID_SET; + + while (*pattern != ']') { + if (*pattern == '\\' && !*++pattern) + return PATTERN_INVALID_ESCAPE; + + if (!*pattern) + return PATTERN_INVALID_SET; + + if (pattern[0] == '-' && pattern[1] == '-') + return PATTERN_INVALID_RANGE; + + pattern++; + } + break; + } + } + return B_OK; +} + + +/** Matches the string against the given wildcard pattern. + * Returns either MATCH_OK, or NO_MATCH when everything went fine, + * or values < 0 (see enum at the top of Query.cpp) if an error + * occurs + */ + +status_t +matchString(char *pattern,char *string) +{ + while (*pattern) { + // end of string == valid end of pattern? + if (!string[0]) { + while (pattern[0] == '*') + pattern++; + return !pattern[0] ? MATCH_OK : NO_MATCH; + } + + switch (*pattern++) { + case '?': + { + // match exactly one UTF-8 character; we are + // not interested in the result + utf8ToUnicode(&string); + break; + } + + case '*': + { + // compact pattern + while (true) { + if (pattern[0] == '?') { + if (!*++string) + return NO_MATCH; + } else if (pattern[0] != '*') + break; + + pattern++; + } + + // if the pattern is done, we have matched the string + if (!pattern[0]) + return MATCH_OK; + + while(true) { + // we have removed all occurences of '*' and '?' + if (pattern[0] == string[0] + || pattern[0] == '[' + || pattern[0] == '\\') { + status_t status = matchString(pattern,string); + if (status < B_OK || status == MATCH_OK) + return status; + } + + // we could be nice here and just jump to the next + // UTF-8 character - but we wouldn't gain that much + // and it'd be slower (since we're checking for + // equality before entering the recursion) + if (!*++string) + return NO_MATCH; + } + break; + } + + case '[': + { + bool invert = false; + if (pattern[0] == '^' || pattern[0] == '!') { + invert = true; + pattern++; + } + + if (!pattern[0] || pattern[0] == ']') + return MATCH_BAD_PATTERN; + + uint32 c = utf8ToUnicode(&string); + bool matched = false; + + while (pattern[0] != ']') { + if (!pattern[0]) + return MATCH_BAD_PATTERN; + + if (pattern[0] == '\\') + pattern++; + + uint32 first = utf8ToUnicode(&pattern); + + // Does this character match, or is this a range? + if (first == c) { + matched = true; + break; + } else if (pattern[0] == '-' && pattern[1] != ']' && pattern[1]) { + pattern++; + + if (pattern[0] == '\\') { + pattern++; + if (!pattern[0]) + return MATCH_BAD_PATTERN; + } + uint32 last = utf8ToUnicode(&pattern); + + if (c >= first && c <= last) { + matched = true; + break; + } + } + } + + if (invert) + matched = !matched; + + if (matched) { + while (pattern[0] != ']') { + if (!pattern[0]) + return MATCH_BAD_PATTERN; + pattern++; + } + pattern++; + break; + } + return NO_MATCH; + } + + case '\\': + if (!pattern[0]) + return MATCH_BAD_PATTERN; + // supposed to fall through + default: + if (pattern[-1] != string[0]) + return NO_MATCH; + string++; + break; + } + } + + if (string[0]) + return NO_MATCH; + + return MATCH_OK; +} + + +// #pragma mark - + + +Equation::Equation(char **expr) + : Term(OP_EQUATION), + fAttribute(NULL), + fString(NULL), + fType(0), + fIsPattern(false) +{ + char *string = *expr; + char *start = string; + char *end = NULL; + + // Since the equation is the integral part of any query, we're just parsing + // the whole thing here. + // The whitespace at the start is already removed in Expression::ParseEquation() + + if (*start == '"' || *start == '\'') { + // string is quoted (start has to be on the beginning of a string) + if (ParseQuotedString(&start,&end) < B_OK) + return; + + // set string to a valid start of the equation symbol + string = end + 2; + skipWhitespace(&string); + if (*string != '=' && *string != '<' && *string != '>' && *string != '!') { + *expr = string; + return; + } + } else { + // search the (in)equation for the actual equation symbol (and for other operators + // in case the equation is malformed) + while (*string && *string != '=' && *string != '<' && *string != '>' && *string != '!' + && *string != '&' && *string != '|') + string++; + + // get the attribute string (and trim whitespace), in case + // the string was not quoted + end = string - 1; + skipWhitespaceReverse(&end,start); + } + + // attribute string is empty (which is not allowed) + if (start > end) + return; + + // at this point, "start" points to the beginning of the string, "end" points + // to the last character of the string, and "string" points to the first + // character of the equation symbol + + // test for the right symbol (as this doesn't need any memory) + switch (*string) { + case '=': + fOp = OP_EQUAL; + break; + case '>': + fOp = *(string + 1) == '=' ? OP_GREATER_THAN_OR_EQUAL : OP_GREATER_THAN; + break; + case '<': + fOp = *(string + 1) == '=' ? OP_LESS_THAN_OR_EQUAL : OP_LESS_THAN; + break; + case '!': + if (*(string + 1) != '=') + return; + fOp = OP_UNEQUAL; + break; + + // any invalid characters will be rejected + default: + *expr = string; + return; + } + // lets change "start" to point to the first character after the symbol + if (*(string + 1) == '=') + string++; + string++; + skipWhitespace(&string); + + // allocate & copy the attribute string + + fAttribute = CopyString(start,end); + if (fAttribute == NULL) + return; + + start = string; + if (*start == '"' || *start == '\'') { + // string is quoted (start has to be on the beginning of a string) + if (ParseQuotedString(&start,&end) < B_OK) + return; + + string = end + 2; + skipWhitespace(&string); + } else { + while (*string && *string != '&' && *string != '|' && *string != ')') + string++; + + end = string - 1; + skipWhitespaceReverse(&end,start); + } + + // at this point, "start" will point to the first character of the value, + // "end" will point to its last character, and "start" to the first non- + // whitespace character after the value string + + fString = CopyString(start,end); + if (fString == NULL) + return; + + // patterns are only allowed for these operations (and strings) + if (fOp == OP_EQUAL || fOp == OP_UNEQUAL) { + fIsPattern = isPattern(fString); + if (fIsPattern && isValidPattern(fString) < B_OK) { + // we only want to have valid patterns; setting fString + // to NULL will cause InitCheck() to fail + free(fString); + fString = NULL; + } + } + + // The special time flag is set if the time values are shifted + // 64-bit values to reduce the number of duplicates. + // We have to be able to compare them against unshifted values + // later. The only index which needs this is the last_modified + // index, but we may want to open that feature for other indices, + // too one day. + fIsSpecialTime = !strcmp(fAttribute,"last_modified"); + + *expr = string; +} + + +Equation::~Equation() +{ + if (fAttribute != NULL) + free(fAttribute); + if (fString != NULL) + free(fString); +} + + +status_t +Equation::InitCheck() +{ + if (fAttribute == NULL + || fString == NULL + || fOp == OP_NONE) + return B_BAD_VALUE; + + return B_OK; +} + + +status_t +Equation::ParseQuotedString(char **_start, char **_end) +{ + char *start = *_start; + char quote = *start++; + char *end = start; + + for (;*end && *end != quote;end++) { + if (*end == '\\') + end++; + } + if (*end == '\0') + return B_BAD_VALUE; + + *_start = start; + *_end = end - 1; + + return B_OK; +} + + +char * +Equation::CopyString(char *start,char *end) +{ + // end points to the last character of the string - and the length + // also has to include the null-termination + int32 length = end + 2 - start; + // just to make sure; since that's the max. attribute name length and + // the max. string in an index, it make sense to have it that way + if (length > INODE_FILE_NAME_LENGTH || length <= 0) + return NULL; + + char *copy = (char *)malloc(length); + if (copy == NULL) + return NULL; + + memcpy(copy,start,length - 1); + copy[length - 1] = '\0'; + + return copy; +} + + +status_t +Equation::ConvertValue(type_code type) +{ + // Has the type already been converted? + if (type == fType) + return B_OK; + + fType = type; + char *string = fString; + + switch (type) { + // B_MIME_STRING_TYPE is defined in Mime.h which I didn't want to include just for that + case 'MIMS': + type = B_STRING_TYPE; + // supposed to fall through + case B_STRING_TYPE: + strncpy(fValue.String,string,INODE_FILE_NAME_LENGTH); + fValue.String[INODE_FILE_NAME_LENGTH - 1] = '\0'; + fSize = strlen(fValue.String); + break; + case B_INT32_TYPE: + fValue.Int32 = strtol(string,&string,0); + fSize = sizeof(int32); + break; + case B_UINT32_TYPE: + fValue.Int32 = strtoul(string,&string,0); + fSize = sizeof(uint32); + break; + case B_INT64_TYPE: + fValue.Int64 = strtoll(string,&string,0); + fSize = sizeof(int64); + break; + case B_UINT64_TYPE: + fValue.Uint64 = strtoull(string,&string,0); + fSize = sizeof(uint64); + break; + case B_FLOAT_TYPE: + fValue.Float = strtod(string,&string); + fSize = sizeof(float); + break; + case B_DOUBLE_TYPE: + fValue.Double = strtod(string,&string); + fSize = sizeof(double); + break; + default: + FATAL(("query value conversion to 0x%lx requested!\n",type)); + // should we fail here or just do a safety int32 conversion? + return B_ERROR; + } + + // patterns are only allowed for string types + if (fType != B_STRING_TYPE && fIsPattern) + fIsPattern = false; + + return B_OK; +} + + +/** Returns true when the key matches the equation. You have to + * call ConvertValue() before this one. + */ + +bool +Equation::CompareTo(const uint8 *value,uint16 size) +{ + int32 compare; + + // fIsPattern is only true if it's a string type, and fOp OP_EQUAL, or OP_UNEQUAL + if (fIsPattern) { + // we have already validated the pattern, so we don't check for failing + // here - if something is broken, and matchString() returns an error, + // we just don't match + compare = matchString(fValue.String,(char *)value) == MATCH_OK ? 0 : 1; + } else if (fIsSpecialTime) { + // the index is a shifted int64 index, but we have to match + // against an unshifted value (i.e. the last_modified index) + int64 timeValue = *(int64 *)value >> INODE_TIME_SHIFT; + compare = compareKeys(fType,&timeValue,sizeof(int64),&fValue.Int64,sizeof(int64)); + } else + compare = compareKeys(fType,value,size,Value(),fSize); + + switch (fOp) { + case OP_EQUAL: + return compare == 0; + case OP_UNEQUAL: + return compare != 0; + case OP_LESS_THAN: + return compare < 0; + case OP_LESS_THAN_OR_EQUAL: + return compare <= 0; + case OP_GREATER_THAN: + return compare > 0; + case OP_GREATER_THAN_OR_EQUAL: + return compare >= 0; + } + FATAL(("Unknown/Unsupported operation: %d\n",fOp)); + return false; +} + + +void +Equation::Complement() +{ + D(if (fOp <= OP_EQUATION || fOp > OP_LESS_THAN_OR_EQUAL) { + FATAL(("op out of range!")); + return; + }); + + int8 complementOp[] = {OP_UNEQUAL, OP_EQUAL, OP_LESS_THAN_OR_EQUAL, + OP_GREATER_THAN_OR_EQUAL, OP_LESS_THAN, OP_GREATER_THAN}; + fOp = complementOp[fOp - OP_EQUAL]; +} + + +status_t +Equation::MatchEmptyString() +{ + // there is no matching attribute, we will just bail out if we + // already know that our value is not of a string type. + // If not, it will be converted to a string - and then be compared with "". + // That's why we have to call ConvertValue() here - but it will be + // a cheap call for the next time + // Should we do this only for OP_UNEQUAL? + if (fType != 0 && fType != B_STRING_TYPE) + return NO_MATCH; + + status_t status = ConvertValue(B_STRING_TYPE); + if (status == B_OK) + status = CompareTo((const uint8 *)"",fSize) ? MATCH_OK : NO_MATCH; + + return status; +} + + +/** Matches the inode's attribute value with the equation. + * Returns MATCH_OK if it matches, NO_MATCH if not, < 0 if something went wrong + */ + +status_t +Equation::Match(Inode *inode,const char *attributeName,int32 type,const uint8 *key,size_t size) +{ + // get a pointer to the attribute in question + union value value; + uint8 *buffer; + + // first, check if we are matching for a live query and use that value + if (attributeName != NULL && !strcmp(fAttribute,attributeName)) { + if (key == NULL) { + if (type == B_STRING_TYPE) + return MatchEmptyString(); + + return NO_MATCH; + } + buffer = const_cast(key); + } else if (!strcmp(fAttribute,"name")) { + // if not, check for "fake" attributes, "name", "size", "last_modified", + buffer = (uint8 *)inode->Name(); + if (buffer == NULL) + return B_ERROR; + + type = B_STRING_TYPE; + size = strlen((const char *)buffer); + } else if (!strcmp(fAttribute,"size")) { + buffer = (uint8 *)&inode->Node()->data.size; + type = B_INT64_TYPE; + } else if (!strcmp(fAttribute,"last_modified")) { + buffer = (uint8 *)&inode->Node()->last_modified_time; + type = B_INT64_TYPE; + } else { + // then for attributes in the small_data section, and finally for the + // real attributes + Inode *attribute; + + inode->SmallDataLock().Lock(); + small_data *smallData = inode->FindSmallData(fAttribute); + if (smallData != NULL) { + buffer = smallData->Data(); + type = smallData->type; + size = smallData->data_size; + inode->SmallDataLock().Unlock(); + } else { + // needed to unlock the small_data section as fast as possible + inode->SmallDataLock().Unlock(); + + if (inode->GetAttribute(fAttribute,&attribute) == B_OK) { + buffer = (uint8 *)&value; + type = attribute->Node()->type; + size = attribute->Size(); + + if (size > INODE_FILE_NAME_LENGTH) + size = INODE_FILE_NAME_LENGTH; + + if (attribute->ReadAt(0,buffer,&size) < B_OK) { + inode->ReleaseAttribute(attribute); + return B_IO_ERROR; + } + inode->ReleaseAttribute(attribute); + } else + return MatchEmptyString(); + } + } + // prepare own value for use, if it is possible to convert it + status_t status = ConvertValue(type); + if (status == B_OK) + status = CompareTo(buffer,size) ? MATCH_OK : NO_MATCH; + + RETURN_ERROR(status); +} + + +void +Equation::CalculateScore(Index &index) +{ + // As always, these values could be tuned and refined. + // And the code could also need some real world testing :-) + + // do we have to operate on a "foreign" index? + if (fOp == OP_UNEQUAL || index.SetTo(fAttribute) < B_OK) { + fScore = 0; + return; + } + + // if we have a pattern, how much does it help our search? + if (fIsPattern) + fScore = getFirstPatternSymbol(fString) << 3; + else { + // Score by operator + if (fOp == OP_EQUAL) + // higher than pattern="255 chars+*" + fScore = 2048; + else + // the pattern search is regarded cheaper when you have at + // least one character to set your index to + fScore = 5; + } + + // take index size into account (1024 is the current node size + // in our B+trees) + // 2048 * 2048 == 4194304 is the maximum score (for an empty + // tree, since the header + 1 node are already 2048 bytes) + fScore = fScore * ((2048 * 1024LL) / index.Node()->Size()); +} + + +status_t +Equation::PrepareQuery(Volume */*volume*/, Index &index, TreeIterator **iterator) +{ + type_code type; + status_t status = index.SetTo(fAttribute); + + // special case for OP_UNEQUAL - it will always operate through the whole index + // but we need the call to the original index to get the correct type + if (status < B_OK || fOp == OP_UNEQUAL) { + // Try to get an index that holds all files (name) + // Also sets the default type for all attributes without index + // to string. + type = status < B_OK ? B_STRING_TYPE : index.Type(); + + if (index.SetTo("name") < B_OK) + return B_ENTRY_NOT_FOUND; + + fHasIndex = false; + } else { + fHasIndex = true; + type = index.Type(); + } + + if (ConvertValue(type) < B_OK) + return B_BAD_VALUE; + + BPlusTree *tree; + if (index.Node()->GetTree(&tree) < B_OK) + return B_ERROR; + + *iterator = new TreeIterator(tree); + if (*iterator == NULL) + return B_NO_MEMORY; + + if ((fOp == OP_EQUAL || fOp == OP_GREATER_THAN || fOp == OP_GREATER_THAN_OR_EQUAL + || fIsPattern) + && fHasIndex) { + // set iterator to the exact position + + int32 keySize = index.KeySize(); + + // at this point, fIsPattern is only true if it's a string type, and fOp + // is either OP_EQUAL or OP_UNEQUAL + if (fIsPattern) { + // let's see if we can use the beginning of the key for positioning + // the iterator and adjust the key size; if not, just leave the + // iterator at the start and return success + keySize = getFirstPatternSymbol(fString); + if (keySize <= 0) + return B_OK; + } + + if (keySize == 0) { + if (fType == B_STRING_TYPE) + keySize = strlen(fValue.String); + else + RETURN_ERROR(B_ENTRY_NOT_FOUND); + } + + if (fIsSpecialTime) { + // we have to find the first matching shifted value + off_t value = fValue.Int64 << INODE_TIME_SHIFT; + status = (*iterator)->Find((uint8 *)&value,keySize); + if (status == B_ENTRY_NOT_FOUND) + return B_OK; + } else { + status = (*iterator)->Find(Value(),keySize); + if (fOp == OP_EQUAL && !fIsPattern) + return status; + else if (status == B_ENTRY_NOT_FOUND && (fIsPattern || fOp == OP_GREATER_THAN || fOp == OP_GREATER_THAN_OR_EQUAL)) + return B_OK; + } + + RETURN_ERROR(status); + } + + return B_OK; +} + + +status_t +Equation::GetNextMatching(Volume *volume, TreeIterator *iterator, + struct dirent *dirent, size_t bufferSize) +{ + while (true) { + union value indexValue; + uint16 keyLength; + uint16 duplicate; + off_t offset; + + status_t status = iterator->GetNextEntry(&indexValue,&keyLength,(uint16)sizeof(indexValue),&offset,&duplicate); + if (status < B_OK) + return status; + + // only compare against the index entry when this is the correct + // index for the equation + if (fHasIndex && duplicate < 2 && !CompareTo((uint8 *)&indexValue,keyLength)) { + // They aren't equal? let the operation decide what to do + // Since we always start at the beginning of the index (or the correct + // position), only some needs to be stopped if the entry doesn't fit. + if (fOp == OP_LESS_THAN + || fOp == OP_LESS_THAN_OR_EQUAL + || (fOp == OP_EQUAL && !fIsPattern)) + return B_ENTRY_NOT_FOUND; + + if (duplicate > 0) + iterator->SkipDuplicates(); + continue; + } + + Inode *inode; + if ((status = get_vnode(volume->ID(),offset,(void **)&inode)) != B_OK) { + REPORT_ERROR(status); + FATAL(("could not get inode %Ld in index \"%s\"!\n",offset,fAttribute)); + // try with next + continue; + } + + // check user permissions here - but which one?! + // we could filter out all those where we don't have + // read access... (we should check for every parent + // directory if the X_OK is allowed) + // Although it's quite expensive to open all parents, + // it's likely that the application that runs the + // query will do something similar (and we don't have + // to do it for root, either). + + // go up in the tree until a &&-operator is found, and check if the + // inode matches with the rest of the expression - we don't have to + // check ||-operators for that + Term *term = this; + status = MATCH_OK; + + if (!fHasIndex) + status = Match(inode); + + while (term != NULL && status == MATCH_OK) { + Operator *parent = (Operator *)term->Parent(); + if (parent == NULL) + break; + + if (parent->Op() == OP_AND) { + // choose the other child of the parent + Term *other = parent->Right(); + if (other == term) + other = parent->Left(); + + if (other == NULL) { + FATAL(("&&-operator has only one child... (parent = %p)\n",parent)); + break; + } + status = other->Match(inode); + if (status < 0) { + REPORT_ERROR(status); + status = NO_MATCH; + } + } + term = (Term *)parent; + } + + if (status == MATCH_OK) { + dirent->d_dev = volume->ID(); + dirent->d_ino = offset; + dirent->d_pdev = volume->ID(); + dirent->d_pino = volume->ToVnode(inode->Parent()); + strcpy(dirent->d_name,inode->Name()); + dirent->d_reclen = strlen(dirent->d_name); + } + + put_vnode(volume->ID(), inode->ID()); + + if (status == MATCH_OK) + return B_OK; + } + RETURN_ERROR(B_ERROR); +} + + +// #pragma mark - + + +Operator::Operator(Term *left, int8 op, Term *right) + : Term(op), + fLeft(left), + fRight(right) +{ + if (left) + left->SetParent(this); + if (right) + right->SetParent(this); +} + + +Operator::~Operator() +{ + delete fLeft; + delete fRight; +} + + +status_t +Operator::Match(Inode *inode,const char *attribute,int32 type,const uint8 *key,size_t size) +{ + if (fOp == OP_AND) { + status_t status = fLeft->Match(inode,attribute,type,key,size); + if (status != MATCH_OK) + return status; + + return fRight->Match(inode,attribute,type,key,size); + } else { + // choose the term with the better score for OP_OR + if (fRight->Score() > fLeft->Score()) { + status_t status = fRight->Match(inode,attribute,type,key,size); + if (status != NO_MATCH) + return status; + } + return fLeft->Match(inode,attribute,type,key,size); + } +} + + +void +Operator::Complement() +{ + if (fOp == OP_AND) + fOp = OP_OR; + else + fOp = OP_AND; + + fLeft->Complement(); + fRight->Complement(); +} + + +void +Operator::CalculateScore(Index &index) +{ + fLeft->CalculateScore(index); + fRight->CalculateScore(index); +} + + +int32 +Operator::Score() const +{ + if (fOp == OP_AND) { + // return the one with the better score + if (fRight->Score() > fLeft->Score()) + return fRight->Score(); + + return fLeft->Score(); + } + + // for OP_OR, be honest, and return the one with the worse score + if (fRight->Score() < fLeft->Score()) + return fRight->Score(); + + return fLeft->Score(); +} + + +status_t +Operator::InitCheck() +{ + if (fOp != OP_AND && fOp != OP_OR + || fLeft == NULL || fLeft->InitCheck() < B_OK + || fRight == NULL || fRight->InitCheck() < B_OK) + return B_ERROR; + + return B_OK; +} + + +#if 0 +Term * +Operator::Copy() const +{ + if (fEquation != NULL) { + Equation *equation = new Equation(*fEquation); + if (equation == NULL) + return NULL; + + Term *term = new Term(equation); + if (term == NULL) + delete equation; + + return term; + } + + Term *left = NULL, *right = NULL; + + if (fLeft != NULL && (left = fLeft->Copy()) == NULL) + return NULL; + if (fRight != NULL && (right = fRight->Copy()) == NULL) { + delete left; + return NULL; + } + + Term *term = new Term(left,fOp,right); + if (term == NULL) { + delete left; + delete right; + return NULL; + } + return term; +} +#endif + + +// #pragma mark - + +#ifdef DEBUG +void +Operator::PrintToStream() +{ + D(__out("( ")); + if (fLeft != NULL) + fLeft->PrintToStream(); + + char *op; + switch (fOp) { + case OP_OR: op = "OR"; break; + case OP_AND: op = "AND"; break; + default: op = "?"; break; + } + D(__out(" %s ",op)); + + if (fRight != NULL) + fRight->PrintToStream(); + + D(__out(" )")); +} + + +void +Equation::PrintToStream() +{ + char *symbol = "???"; + switch (fOp) { + case OP_EQUAL: symbol = "=="; break; + case OP_UNEQUAL: symbol = "!="; break; + case OP_GREATER_THAN: symbol = ">"; break; + case OP_GREATER_THAN_OR_EQUAL: symbol = ">="; break; + case OP_LESS_THAN: symbol = "<"; break; + case OP_LESS_THAN_OR_EQUAL: symbol = "<="; break; + } + D(__out("[\"%s\" %s \"%s\"]",fAttribute,symbol,fString)); +} + +#endif /* DEBUG */ + +// #pragma mark - + + +Expression::Expression(char *expr) +{ + if (expr == NULL) + return; + + fTerm = ParseOr(&expr); + if (fTerm != NULL && fTerm->InitCheck() < B_OK) { + FATAL(("Corrupt tree in expression!\n")); + delete fTerm; + fTerm = NULL; + } + D(if (fTerm != NULL) { + fTerm->PrintToStream(); + D(__out("\n")); + if (*expr != '\0') + PRINT(("Unexpected end of string: \"%s\"!\n",expr)); + }); + fPosition = expr; +} + + +Expression::~Expression() +{ + delete fTerm; +} + + +Term * +Expression::ParseEquation(char **expr) +{ + skipWhitespace(expr); + + bool not = false; + if (**expr == '!') { + skipWhitespace(expr, 1); + if (**expr != '(') + return NULL; + + not = true; + } + + if (**expr == ')') { + // shouldn't be handled here + return NULL; + } else if (**expr == '(') { + skipWhitespace(expr, 1); + + Term *term = ParseOr(expr); + + skipWhitespace(expr); + + if (**expr != ')') { + delete term; + return NULL; + } + + // If the term is negated, we just complement the tree, to get + // rid of the not, a.k.a. DeMorgan's Law. + if (not) + term->Complement(); + + skipWhitespace(expr, 1); + + return term; + } + + Equation *equation = new Equation(expr); + if (equation == NULL || equation->InitCheck() < B_OK) { + delete equation; + return NULL; + } + return equation; +} + + +Term * +Expression::ParseAnd(char **expr) +{ + Term *left = ParseEquation(expr); + if (left == NULL) + return NULL; + + while (IsOperator(expr,'&')) { + Term *right = ParseAnd(expr); + Term *newParent = NULL; + + if (right == NULL || (newParent = new Operator(left,OP_AND,right)) == NULL) { + delete left; + delete right; + + return NULL; + } + left = newParent; + } + + return left; +} + + +Term * +Expression::ParseOr(char **expr) +{ + Term *left = ParseAnd(expr); + if (left == NULL) + return NULL; + + while (IsOperator(expr,'|')) { + Term *right = ParseAnd(expr); + Term *newParent = NULL; + + if (right == NULL || (newParent = new Operator(left,OP_OR,right)) == NULL) { + delete left; + delete right; + + return NULL; + } + left = newParent; + } + + return left; +} + + +bool +Expression::IsOperator(char **expr, char op) +{ + char *string = *expr; + + if (*string == op && *(string + 1) == op) { + *expr += 2; + return true; + } + return false; +} + + +status_t +Expression::InitCheck() +{ + if (fTerm == NULL) + return B_BAD_VALUE; + + return B_OK; +} + + +// #pragma mark - + + +Query::Query(Volume *volume,Expression *expression) + : + fVolume(volume), + fExpression(expression), + fCurrent(NULL), + fIterator(NULL), + fIndex(volume), + fPort(-1) +{ + // if the expression has a valid root pointer, the whole tree has + // already passed the sanity check, so that we don't have to check + // every pointer + if (volume == NULL || expression == NULL || expression->Root() == NULL) + return; + + // create index on the stack and delete it afterwards + fExpression->Root()->CalculateScore(fIndex); + fIndex.Unset(); + + Stack stack; + stack.Push(fExpression->Root()); + + Term *term; + while (stack.Pop(&term)) { + if (term->Op() < OP_EQUATION) { + Operator *op = (Operator *)term; + + if (op->Op() == OP_OR) { + stack.Push(op->Left()); + stack.Push(op->Right()); + } else { + // For OP_AND, we can use the scoring system to decide which path to add + if (op->Right()->Score() > op->Left()->Score()) + stack.Push(op->Right()); + else + stack.Push(op->Left()); + } + } else if (term->Op() == OP_EQUATION || fStack.Push((Equation *)term) < B_OK) + FATAL(("Unknown term on stack or stack error")); + } + + volume->AddQuery(this); +} + + +Query::~Query() +{ + fVolume->RemoveQuery(this); +} + + +status_t +Query::GetNextEntry(struct dirent *dirent, size_t size) +{ + // If we don't have an equation to use yet/anymore, get a new one + // from the stack + while (true) { + if (fIterator == NULL) { + if (!fStack.Pop(&fCurrent) + || fCurrent == NULL + || fCurrent->PrepareQuery(fVolume,fIndex,&fIterator) < B_OK) + return B_ENTRY_NOT_FOUND; + } + if (fCurrent == NULL) + RETURN_ERROR(B_ERROR); + + status_t status = fCurrent->GetNextMatching(fVolume,fIterator,dirent,size); + if (status < B_OK) { + delete fIterator; + fIterator = NULL; + fCurrent = NULL; + } else { + // only return if we have another entry + return B_OK; + } + } +} + + +void +Query::SetLiveMode(port_id port,int32 token) +{ + fPort = port; + fToken = token; +} + + +void +Query::LiveUpdate(Inode *inode,const char *attribute,int32 type,const uint8 *oldKey,size_t oldLength,const uint8 *newKey,size_t newLength) +{ + if (fPort < 0 || fExpression == NULL || attribute == NULL) + return; + + // ToDo: check if the attribute is part of the query at all... + + status_t oldStatus = fExpression->Root()->Match(inode,attribute,type,oldKey,oldLength); + status_t newStatus = fExpression->Root()->Match(inode,attribute,type,newKey,newLength); + int32 op; + if (oldStatus == MATCH_OK && newStatus == MATCH_OK) { + // only send out a notification if the name was changed + if (oldKey == NULL || strcmp(attribute,"name")) + return; + + send_notification(fPort,fToken,B_QUERY_UPDATE,B_ENTRY_REMOVED,fVolume->ID(),0,fVolume->ToVnode(inode->Parent()),0,inode->ID(),(const char *)oldKey); + op = B_ENTRY_CREATED; + } else if (oldStatus != MATCH_OK && newStatus != MATCH_OK) { + // nothing has changed + return; + } else if (oldStatus == MATCH_OK && newStatus != MATCH_OK) + op = B_ENTRY_REMOVED; + else + op = B_ENTRY_CREATED; + + // if "value" is NULL, send_notification() crashes... + const char *value = (const char *)newKey; + if (type != B_STRING_TYPE || value == NULL) + value = ""; + + send_notification(fPort,fToken,B_QUERY_UPDATE,op,fVolume->ID(),0,fVolume->ToVnode(inode->Parent()),0,inode->ID(),value); +} + diff --git a/src/add-ons/kernel/file_systems/befs/Query.h b/src/add-ons/kernel/file_systems/befs/Query.h new file mode 100644 index 0000000000..50f3779063 --- /dev/null +++ b/src/add-ons/kernel/file_systems/befs/Query.h @@ -0,0 +1,72 @@ +#ifndef QUERY_H +#define QUERY_H +/* Query - query parsing and evaluation +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include + +#include "Index.h" +#include "Stack.h" +#include "Chain.h" + +class Volume; +class Term; +class Equation; +class TreeIterator; +class Query; + + +class Expression { + public: + Expression(char *expr); + ~Expression(); + + status_t InitCheck(); + const char *Position() const { return fPosition; } + Term *Root() const { return fTerm; } + + protected: + Term *ParseOr(char **expr); + Term *ParseAnd(char **expr); + Term *ParseEquation(char **expr); + + bool IsOperator(char **expr,char op); + + private: + char *fPosition; + Term *fTerm; +}; + +class Query { + public: + Query(Volume *volume,Expression *expression); + ~Query(); + + status_t GetNextEntry(struct dirent *,size_t size); + + void SetLiveMode(port_id port,int32 token); + void LiveUpdate(Inode *inode,const char *attribute,int32 type,const uint8 *oldKey,size_t oldLength,const uint8 *newKey,size_t newLength); + + Expression *GetExpression() const { return fExpression; } + + private: + Volume *fVolume; + Expression *fExpression; + Equation *fCurrent; + TreeIterator *fIterator; + Index fIndex; + Stack fStack; + + port_id fPort; + int32 fToken; + + private: + friend Chain; + Query *fNext; +}; + +#endif /* QUERY_H */ diff --git a/src/add-ons/kernel/file_systems/befs/Stack.h b/src/add-ons/kernel/file_systems/befs/Stack.h new file mode 100644 index 0000000000..9793eb2491 --- /dev/null +++ b/src/add-ons/kernel/file_systems/befs/Stack.h @@ -0,0 +1,58 @@ +#ifndef STACK_H +#define STACK_H +/* Stack - a template stack class +** +** Copyright 2001 pinc Software. All Rights Reserved. +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include + + +template class Stack { + public: + Stack() + : + fArray(NULL), + fUsed(0), + fMax(0) + { + } + + ~Stack() + { + if (fArray) + free(fArray); + } + + status_t Push(T value) + { + if (fUsed >= fMax) { + fMax += 16; + T *newArray = (T *)realloc(fArray,fMax * sizeof(T)); + if (newArray == NULL) + return B_NO_MEMORY; + + fArray = newArray; + } + fArray[fUsed++] = value; + return B_OK; + } + + bool Pop(T *value) + { + if (fUsed == 0) + return false; + + *value = fArray[--fUsed]; + return true; + } + + private: + T *fArray; + int32 fUsed; + int32 fMax; +}; + +#endif /* STACK_H */ diff --git a/src/add-ons/kernel/file_systems/befs/ToDo b/src/add-ons/kernel/file_systems/befs/ToDo new file mode 100644 index 0000000000..9badbc44cc --- /dev/null +++ b/src/add-ons/kernel/file_systems/befs/ToDo @@ -0,0 +1,74 @@ +BFS - ToDo, June 5th, 2002 +----- + +BlockAllocator + + - the BlockAllocator is only slightly optimized and probably slow + - the first free and the largest range are currently not correctly maintained (only efficiency suffers - it does work correctly) + - the allocation policies will have to stand against some real world tests + - the access to the block bitmap is currently managed using a global lock + + +DataStream + + - growing/shrinking the stream size is not implemented for the double indirect range + - only files are trimmed back (in bfs_close()), but every inode has a preallocated stream... + - merging of block_runs doesn't work between range/block boundaries + + +Queries + + - There shouldn't be any cases where you can speed up a query with reordering the query expression - test it + - Check permissions of the parent directories + - Add protection against crashing applications which had a query open - at least the original BeOS kernel does not free the cookie (which throws some memory away *and* prevents unmounting the disk) + + +Journal + + - Check if there are any standard and often-happening cases for a transaction to fail, and if so, start the transaction only when necessary + - if the system crashes between bfs_unlink() and bfs_remove_vnode(), the inode can be removed from the tree, but its memory is still allocated - this can happen if the inode is still in use by someone (and that's what the "chkbfs" utility is for, mainly). + - add delayed index updating (+ delete actions to solve the issue above) + - multiple log files, parallel transactions? + - variable sized log file + - as long as we have a fixed-sized log file, it should be possible to reserve space for a transaction to be able to decide if batching it is possible + + +BPlusTree + + - BPlusTree::Remove() could trigger CachedNode::Free() to go through the free nodes list and free all pages at the end of the data stream + - updating the TreeIterators doesn't work yet for duplicates (which may be a problem if a duplicate node will go away after a remove) + - BPlusTree::RemoveDuplicate() could spread the contents of duplicate node with only a few entries to save some space (right now, only empty nodes are freed) + + +Inode + + - sometimes the inode's last modified time seems to be wrong, and is therefore not found in the b+tree (assuming that the b+tree is working correctly, what I do) + - Inode::FillGapWithZeros() currently disabled; apart from being slow, it really shouldn't be executed while a transaction is running, because that stops all other threads from doing anything (which can be a long time for a 100 MB file) + + +Indices + + + +Attributes + + - bfs_write_attr() doesn't check if the attribute data may fit into the small_data region if there already is that attribute as an attribute file + + +Volume + + +kernel_interface + + - missing functions, maybe they are not all needed (but most of them are): bfs_rename_attr(), bfs_rename_index(), bfs_initialize(), bfs_setflags(), bfs_link() + - bfs_rename() currently doesn't respect any permissions + + +general stuff + + - There are also some comments with a leading "ToDo:" directly in the code which may not be mentioned here. + + +----- +Axel Dörfler +axeld@pinc-software.de diff --git a/src/add-ons/kernel/file_systems/befs/Utility.cpp b/src/add-ons/kernel/file_systems/befs/Utility.cpp new file mode 100644 index 0000000000..4e1d1b91e2 --- /dev/null +++ b/src/add-ons/kernel/file_systems/befs/Utility.cpp @@ -0,0 +1,138 @@ +/* Utility - some helper classes +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include "Utility.h" +#include "Debug.h" +#include "cpp.h" + +#include +#include + + +bool +sorted_array::FindInternal(off_t value, int32 &index) const +{ + int32 min = 0, max = count-1; + off_t cmp; + while (min <= max) { + index = (min + max) / 2; + + cmp = values[index] - value; + if (cmp < 0) + min = index + 1; + else if (cmp > 0) + max = index - 1; + else + return true; + } + return false; +} + + +void +sorted_array::Insert(off_t value) +{ + // if there are more than 8 values in this array, use a + // binary search, if not, just iterate linearly to find + // the insertion point + int32 i; + if (count > 8 ) { + if (!FindInternal(value,i) + && values[i] <= value) + i++; + } else { + for (i = 0;i < count; i++) + if (values[i] > value) + break; + } + + memmove(&values[i+1],&values[i],(count - i) * sizeof(off_t)); + values[i] = value; + count++; +} + + +bool +sorted_array::Remove(off_t value) +{ + int32 index = Find(value); + if (index == -1) + return false; + + memmove(&values[index],&values[index + 1],(count - index) * sizeof(off_t)); + count--; + + return true; +} + + +// #pragma mark - + + +BlockArray::BlockArray(int32 blockSize) + : + fArray(NULL), + fSize(0), + fBlockSize(blockSize) +{ +} + + +BlockArray::~BlockArray() +{ + if (fArray) + free(fArray); +} + + +int32 +BlockArray::Find(off_t value) +{ + if (fArray == NULL) + return -1; + + return fArray->Find(value); +} + + +status_t +BlockArray::Insert(off_t value) +{ + if (fArray == NULL || fArray->count + 1 > fMaxBlocks) { + sorted_array *array = (sorted_array *)realloc(fArray,fSize + fBlockSize); + if (array == NULL) + return B_NO_MEMORY; + + if (fArray == NULL) + array->count = 0; + + fArray = array; + fSize += fBlockSize; + fMaxBlocks = fSize / sizeof(off_t) - 1; + } + + fArray->Insert(value); + return B_OK; +} + + +status_t +BlockArray::Remove(off_t value) +{ + if (fArray == NULL) + return B_ENTRY_NOT_FOUND; + + return fArray->Remove(value) ? B_OK : B_ENTRY_NOT_FOUND; +} + + +void +BlockArray::MakeEmpty() +{ + fArray->count = 0; +} + diff --git a/src/add-ons/kernel/file_systems/befs/Utility.h b/src/add-ons/kernel/file_systems/befs/Utility.h new file mode 100644 index 0000000000..f095545a16 --- /dev/null +++ b/src/add-ons/kernel/file_systems/befs/Utility.h @@ -0,0 +1,110 @@ +#ifndef UTILITY_H +#define UTILITY_H +/* Utility - some helper classes +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include + + +// Simple array, used for the duplicate handling in the B+Tree, +// and for the log entries. + +struct sorted_array { + public: + off_t count; + off_t values[0]; + + inline int32 Find(off_t value) const; + void Insert(off_t value); + bool Remove(off_t value); + + private: + bool FindInternal(off_t value,int32 &index) const; +}; + + +inline int32 +sorted_array::Find(off_t value) const +{ + int32 i; + return FindInternal(value,i) ? i : -1; +} + + +// The BlockArray reserves a multiple of "blockSize" and +// maintain array size for new entries. +// This is used for the in-memory log entries before they +// are written to disk. + +class BlockArray { + public: + BlockArray(int32 blockSize); + ~BlockArray(); + + int32 Find(off_t value); + status_t Insert(off_t value); + status_t Remove(off_t value); + + void MakeEmpty(); + + int32 CountItems() const { return fArray != NULL ? fArray->count : 0; } + int32 BlocksUsed() const { return fArray != NULL ? ((fArray->count + 1) * sizeof(off_t) + fBlockSize - 1) / fBlockSize : 0; } + sorted_array *Array() const { return fArray; } + int32 Size() const { return fSize; } + + private: + sorted_array *fArray; + int32 fBlockSize; + int32 fSize; + int32 fMaxBlocks; +}; + + +// Doubly linked list + +template struct node { + Node *next,*prev; + + void + Remove() + { + prev->next = next; + next->prev = prev; + } + + Node * + Next() + { + if (next && next->next != NULL) + return next; + + return NULL; + } +}; + +template struct list { + Node *head,*tail,*last; + + list() + { + head = (Node *)&tail; + tail = NULL; + last = (Node *)&head; + } + + void + Add(Node *entry) + { + entry->next = (Node *)&tail; + entry->prev = last; + last->next = entry; + last = entry; + } +}; + + +#endif /* UTILITY_H */ diff --git a/src/add-ons/kernel/file_systems/befs/Volume.cpp b/src/add-ons/kernel/file_systems/befs/Volume.cpp new file mode 100644 index 0000000000..f7a3a1aa2f --- /dev/null +++ b/src/add-ons/kernel/file_systems/befs/Volume.cpp @@ -0,0 +1,304 @@ +/* Volume - BFS super block, mounting, etc. +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include "Debug.h" +#include "cpp.h" +#include "Volume.h" +#include "Journal.h" +#include "Inode.h" +#include "Query.h" + +#include + +#include +#include +#include +#include +#include + + +Volume::Volume(nspace_id id) + : + fID(id), + fBlockAllocator(this), + fLock("bfs volume"), + fDirtyCachedBlocks(0), + fUniqueID(0), + fFlags(0) +{ +} + + +Volume::~Volume() +{ +} + + +bool +Volume::IsValidSuperBlock() +{ + if (fSuperBlock.magic1 != (int32)SUPER_BLOCK_MAGIC1 + || fSuperBlock.magic2 != (int32)SUPER_BLOCK_MAGIC2 + || fSuperBlock.magic3 != (int32)SUPER_BLOCK_MAGIC3 + || (int32)fSuperBlock.block_size != fSuperBlock.inode_size + || fSuperBlock.fs_byte_order != SUPER_BLOCK_FS_LENDIAN + || (1UL << fSuperBlock.block_shift) != fSuperBlock.block_size + || fSuperBlock.num_ags < 1 + || fSuperBlock.ag_shift < 1 + || fSuperBlock.blocks_per_ag < 1 + || fSuperBlock.num_blocks < 10 + || fSuperBlock.num_ags != divide_roundup(fSuperBlock.num_blocks,1L << fSuperBlock.ag_shift)) + return false; + + return true; +} + + +void +Volume::Panic() +{ + FATAL(("we have to panic... switch to read-only mode!\n")); + fFlags |= VOLUME_READ_ONLY; +#ifdef USER + debugger("BFS panics!"); +#endif +} + + +status_t +Volume::Mount(const char *deviceName,uint32 flags) +{ + if (flags & B_MOUNT_READ_ONLY) + fFlags |= VOLUME_READ_ONLY; + + fDevice = open(deviceName,flags & B_MOUNT_READ_ONLY ? O_RDONLY : O_RDWR); + + // if we couldn't open the device, try read-only (don't rely on a specific error code) + if (fDevice < B_OK && (flags & B_MOUNT_READ_ONLY) == 0) { + fDevice = open(deviceName,O_RDONLY); + fFlags |= VOLUME_READ_ONLY; + } + + if (fDevice < B_OK) + RETURN_ERROR(fDevice); + + // check if it's a regular file, and if so, disable the cache for the + // underlaying file system + struct stat stat; + if (fstat(fDevice,&stat) < 0) + RETURN_ERROR(B_ERROR); + +//#ifndef USER + if (stat.st_mode & S_FILE && ioctl(fDevice,IOCTL_FILE_UNCACHED_IO,NULL) < 0) { + // mount read-only if the cache couldn't be disabled +# ifdef DEBUG + FATAL(("couldn't disable cache for image file - system may dead-lock!\n")); +# else + FATAL(("couldn't disable cache for image file!\n")); + Panic(); +# endif + } +//#endif + + // read the super block + char buffer[1024]; + if (read_pos(fDevice,0,buffer,sizeof(buffer)) != sizeof(buffer)) + return B_IO_ERROR; + + status_t status = B_OK; + + // Note: that does work only for x86, for PowerPC, the super block + // is located at offset 0! + memcpy(&fSuperBlock,buffer + 512,sizeof(disk_super_block)); + + if (IsValidSuperBlock()) { + // set the current log pointers, so that journaling will work correctly + fLogStart = fSuperBlock.log_start; + fLogEnd = fSuperBlock.log_end; + + if (init_cache_for_device(fDevice, NumBlocks()) == B_OK) { + fJournal = new Journal(this); + // replaying the log is the first thing we will do on this disk + if (fJournal && fJournal->InitCheck() == B_OK + && fBlockAllocator.Initialize() == B_OK) { + fRootNode = new Inode(this,ToVnode(Root())); + + if (fRootNode && fRootNode->InitCheck() == B_OK) { + if (new_vnode(fID,ToVnode(Root()),(void *)fRootNode) == B_OK) { + // try to get indices root dir + + // question: why doesn't get_vnode() work here?? + // answer: we have not yet backpropagated the pointer to the + // volume in bfs_mount(), so bfs_read_vnode() can't get it. + // But it's not needed to do that anyway. + + fIndicesNode = new Inode(this,ToVnode(Indices())); + if (fIndicesNode == NULL + || fIndicesNode->InitCheck() < B_OK + || !fIndicesNode->IsDirectory()) { + INFORM(("bfs: volume doesn't have indices!\n")); + + if (fIndicesNode) { + // if this is the case, the index root node is gone bad, and + // BFS switch to read-only mode + fFlags |= VOLUME_READ_ONLY; + fIndicesNode = NULL; + } + } + + // all went fine + return B_OK; + } else + status = B_NO_MEMORY; + } else + status = B_BAD_VALUE; + + FATAL(("could not create root node: new_vnode() failed!\n")); + } else { + // ToDo: improve error reporting for a bad journal + status = B_NO_MEMORY; + FATAL(("could not initialize journal/block bitmap allocator!\n")); + } + + remove_cached_device_blocks(fDevice,NO_WRITES); + } else { + FATAL(("could not initialize cache!\n")); + status = B_IO_ERROR; + } + FATAL(("invalid super block!\n")); + } + else + status = B_BAD_VALUE; + + close(fDevice); + + return status; +} + + +status_t +Volume::Unmount() +{ + // This will also flush the log & all blocks to disk + delete fJournal; + fJournal = NULL; + + delete fIndicesNode; + + remove_cached_device_blocks(fDevice,ALLOW_WRITES); + close(fDevice); + + return B_OK; +} + + +status_t +Volume::Sync() +{ + return fJournal->FlushLogAndBlocks(); +} + + +status_t +Volume::IsValidBlockRun(block_run run) +{ + if (run.allocation_group < 0 || run.allocation_group > AllocationGroups() + || run.start > (1LL << AllocationGroupShift()) + || run.length == 0 + || (uint32)run.length + run.start > (1LL << AllocationGroupShift())) { + Panic(); + FATAL(("*** invalid run(%ld,%d,%d)\n",run.allocation_group,run.start,run.length)); + return B_BAD_DATA; + } + return B_OK; +} + + +block_run +Volume::ToBlockRun(off_t block) const +{ + block_run run; + run.allocation_group = block >> fSuperBlock.ag_shift; + run.start = block & ~((1LL << fSuperBlock.ag_shift) - 1); + run.length = 1; + return run; +} + + +status_t +Volume::CreateIndicesRoot(Transaction *transaction) +{ + off_t id; + status_t status = Inode::Create(transaction,NULL,NULL, + S_INDEX_DIR | S_STR_INDEX | S_DIRECTORY | 0700,0,0,&id); + if (status < B_OK) + RETURN_ERROR(status); + + fSuperBlock.indices = ToBlockRun(id); + WriteSuperBlock(); + + // The Vnode destructor will unlock the inode, but it has already been + // locked by the Inode::Create() call. + Vnode vnode(this,id); + return vnode.Get(&fIndicesNode); +} + + +status_t +Volume::AllocateForInode(Transaction *transaction, const Inode *parent, mode_t type, block_run &run) +{ + return fBlockAllocator.AllocateForInode(transaction,&parent->BlockRun(),type,run); +} + + +status_t +Volume::WriteSuperBlock() +{ + if (write_pos(fDevice,512,&fSuperBlock,sizeof(disk_super_block)) != sizeof(disk_super_block)) + return B_IO_ERROR; + + return B_OK; +} + + +void +Volume::UpdateLiveQueries(Inode *inode,const char *attribute,int32 type,const uint8 *oldKey,size_t oldLength,const uint8 *newKey,size_t newLength) +{ + if (fQueryLock.Lock() < B_OK) + return; + + Query *query = NULL; + while ((query = fQueries.Next(query)) != NULL) + query->LiveUpdate(inode,attribute,type,oldKey,oldLength,newKey,newLength); + + fQueryLock.Unlock(); +} + + +void +Volume::AddQuery(Query *query) +{ + if (fQueryLock.Lock() < B_OK) + return; + + fQueries.Add(query); + + fQueryLock.Unlock(); +} + + +void +Volume::RemoveQuery(Query *query) +{ + if (fQueryLock.Lock() < B_OK) + return; + + fQueries.Remove(query); + + fQueryLock.Unlock(); +} + diff --git a/src/add-ons/kernel/file_systems/befs/Volume.h b/src/add-ons/kernel/file_systems/befs/Volume.h new file mode 100644 index 0000000000..1c6a143e10 --- /dev/null +++ b/src/add-ons/kernel/file_systems/befs/Volume.h @@ -0,0 +1,176 @@ +#ifndef VOLUME_H +#define VOLUME_H +/* Volume - BFS super block, mounting, etc. +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include + +extern "C" { + #ifndef _IMPEXP_KERNEL + # define _IMPEXP_KERNEL + #endif + #include "fsproto.h" + #include "lock.h" + #include "cache.h" +} + +#include "bfs.h" +#include "BlockAllocator.h" +#include "Chain.h" + +class Journal; +class Inode; +class Query; + +enum volume_flags { + VOLUME_READ_ONLY = 0x0001 +}; + + +class Volume { + public: + Volume(nspace_id id); + ~Volume(); + + status_t Mount(const char *device,uint32 flags); + status_t Unmount(); + + bool IsValidSuperBlock(); + bool IsReadOnly() const { return fFlags & VOLUME_READ_ONLY; } + void Panic(); + Benaphore &Lock() { return fLock; } + + block_run Root() const { return fSuperBlock.root_dir; } + Inode *RootNode() const { return fRootNode; } + block_run Indices() const { return fSuperBlock.indices; } + Inode *IndicesNode() const { return fIndicesNode; } + block_run Log() const { return fSuperBlock.log_blocks; } + vint32 &LogStart() { return fLogStart; } + vint32 &LogEnd() { return fLogEnd; } + int Device() const { return fDevice; } + + nspace_id ID() const { return fID; } + const char *Name() const { return fSuperBlock.name; } + + off_t NumBlocks() const { return fSuperBlock.num_blocks; } + off_t UsedBlocks() const { return fSuperBlock.used_blocks; } + off_t FreeBlocks() const { return fSuperBlock.num_blocks - fSuperBlock.used_blocks; } + + uint32 BlockSize() const { return fSuperBlock.block_size; } + uint32 BlockShift() const { return fSuperBlock.block_shift; } + uint32 InodeSize() const { return fSuperBlock.inode_size; } + uint32 AllocationGroups() const { return fSuperBlock.num_ags; } + uint32 AllocationGroupShift() const { return fSuperBlock.ag_shift; } + disk_super_block &SuperBlock() { return fSuperBlock; } + + off_t ToOffset(block_run run) const { return ToBlock(run) << fSuperBlock.block_shift; } + off_t ToBlock(block_run run) const { return ((((off_t)run.allocation_group) << fSuperBlock.ag_shift) | (off_t)run.start); } + block_run ToBlockRun(off_t block) const; + status_t IsValidBlockRun(block_run run); + + off_t ToVnode(block_run run) const { return ToBlock(run); } + off_t ToVnode(off_t block) const { return block; } + off_t VnodeToBlock(vnode_id id) const { return (off_t)id; } + + status_t CreateIndicesRoot(Transaction *transaction); + + status_t AllocateForInode(Transaction *transaction,const Inode *parent,mode_t type,block_run &run); + status_t AllocateForInode(Transaction *transaction,const block_run *parent,mode_t type,block_run &run); + status_t Allocate(Transaction *transaction,const Inode *inode,off_t numBlocks,block_run &run,uint16 minimum = 1); + status_t Free(Transaction *transaction,block_run &run); + +#ifdef DEBUG + BlockAllocator &Allocator() { return fBlockAllocator; } +#endif + + status_t Sync(); + Journal *GetJournal(off_t /*refBlock*/) const { return fJournal; } + + status_t WriteSuperBlock(); + status_t WriteBlocks(off_t blockNumber,const uint8 *block,uint32 numBlocks); + void WriteCachedBlocksIfNecessary(); + status_t FlushDevice(); + + void UpdateLiveQueries(Inode *inode,const char *attribute,int32 type,const uint8 *oldKey,size_t oldLength,const uint8 *newKey,size_t newLength); + void AddQuery(Query *query); + void RemoveQuery(Query *query); + + uint32 GetUniqueID() { return atomic_add(&fUniqueID,1); } + + + protected: + nspace_id fID; + int fDevice; + disk_super_block fSuperBlock; + BlockAllocator fBlockAllocator; + Benaphore fLock; + Journal *fJournal; + vint32 fLogStart,fLogEnd; + + Inode *fRootNode; + Inode *fIndicesNode; + + vint32 fDirtyCachedBlocks; + + SimpleLock fQueryLock; + Chain fQueries; + + int32 fUniqueID; + uint32 fFlags; +}; + +// inline functions + +inline status_t +Volume::AllocateForInode(Transaction *transaction, const block_run *parent, mode_t type, block_run &run) +{ + return fBlockAllocator.AllocateForInode(transaction,parent,type,run); +} + + +inline status_t +Volume::Allocate(Transaction *transaction, const Inode *inode, off_t numBlocks, block_run &run, uint16 minimum) +{ + return fBlockAllocator.Allocate(transaction,inode,numBlocks,run,minimum); +} + + +inline status_t +Volume::Free(Transaction *transaction, block_run &run) +{ + return fBlockAllocator.Free(transaction,run); +} + + +inline status_t +Volume::WriteBlocks(off_t blockNumber, const uint8 *block, uint32 numBlocks) +{ + atomic_add(&fDirtyCachedBlocks,numBlocks); + return cached_write(fDevice,blockNumber,block,numBlocks,fSuperBlock.block_size); +} + + +inline void +Volume::WriteCachedBlocksIfNecessary() +{ + // the specific values are only valid for the current BeOS cache + if (fDirtyCachedBlocks > 128) { + force_cache_flush(fDevice,false); + atomic_add(&fDirtyCachedBlocks,-64); + } +} + + +inline status_t +Volume::FlushDevice() +{ + fDirtyCachedBlocks = 0; + return flush_device(fDevice,0); +} + + +#endif /* VOLUME_H */ diff --git a/src/add-ons/kernel/file_systems/befs/bfs.h b/src/add-ons/kernel/file_systems/befs/bfs.h new file mode 100644 index 0000000000..ba6488e513 --- /dev/null +++ b/src/add-ons/kernel/file_systems/befs/bfs.h @@ -0,0 +1,298 @@ +#ifndef BFS_H +#define BFS_H +/* bfs - BFS definitions and helper functions +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** Parts of this code is based on work previously done by Marcus Overhagen +** +** Copyright 2001 pinc Software. All Rights Reserved. +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include + +#ifndef B_BAD_DATA +# define B_BAD_DATA B_ERROR +#endif + + +struct block_run +{ + int32 allocation_group; + uint16 start; + uint16 length; + + inline bool operator==(const block_run &run) const; + inline bool operator!=(const block_run &run) const; + inline bool IsZero(); + inline void SetTo(int32 group,uint16 start,uint16 length = 1); + + inline static block_run Run(int32 group,uint16 start,uint16 length = 1); +}; + +typedef block_run inode_addr; + +//************************************** + + +#define BFS_DISK_NAME_LENGTH 32 + +struct disk_super_block +{ + char name[BFS_DISK_NAME_LENGTH]; + int32 magic1; + int32 fs_byte_order; + uint32 block_size; + uint32 block_shift; + off_t num_blocks; + off_t used_blocks; + int32 inode_size; + int32 magic2; + int32 blocks_per_ag; + int32 ag_shift; + int32 num_ags; + int32 flags; + block_run log_blocks; + off_t log_start; + off_t log_end; + int32 magic3; + inode_addr root_dir; + inode_addr indices; + int32 pad[8]; +}; + +#define SUPER_BLOCK_FS_LENDIAN 'BIGE' /* BIGE */ + +#define SUPER_BLOCK_MAGIC1 'BFS1' /* BFS1 */ +#define SUPER_BLOCK_MAGIC2 0xdd121031 +#define SUPER_BLOCK_MAGIC3 0x15b6830e + +#define SUPER_BLOCK_DISK_CLEAN 'CLEN' /* CLEN */ +#define SUPER_BLOCK_DISK_DIRTY 'DIRT' /* DIRT */ + +//************************************** + +#define NUM_DIRECT_BLOCKS 12 + +struct data_stream +{ + block_run direct[NUM_DIRECT_BLOCKS]; + off_t max_direct_range; + block_run indirect; + off_t max_indirect_range; + block_run double_indirect; + off_t max_double_indirect_range; + off_t size; +}; + +//************************************** + +struct bfs_inode; + +struct small_data +{ + uint32 type; + uint16 name_size; + uint16 data_size; + char name[0]; // name_size long, followed by data + + inline char *Name(); + inline uint8 *Data(); + inline uint32 Size(); + inline small_data *Next(); + inline bool IsLast(bfs_inode *inode); +}; + +// the file name is part of the small_data structure +#define FILE_NAME_TYPE 'CSTR' +#define FILE_NAME_NAME 0x13 +#define FILE_NAME_NAME_LENGTH 1 + +//************************************** + +#define SHORT_SYMLINK_NAME_LENGTH 144 // length incl. terminating '\0' + +struct bfs_inode +{ + int32 magic1; + inode_addr inode_num; + int32 uid; + int32 gid; + int32 mode; // see sys/stat.h + int32 flags; + bigtime_t create_time; + bigtime_t last_modified_time; + inode_addr parent; + inode_addr attributes; + uint32 type; // attribute type + + int32 inode_size; + uint32 etc; // for in-memory structures (unused in OpenBeOS' fs) + + union { + data_stream data; + char short_symlink[SHORT_SYMLINK_NAME_LENGTH]; + }; + int32 pad[4]; + small_data small_data_start[0]; +}; + +#define INODE_MAGIC1 0x3bbe0ad9 +#define INODE_TIME_SHIFT 16 +#define INODE_TIME_MASK 0xffff +#define INODE_FILE_NAME_LENGTH 256 + +enum inode_flags +{ + INODE_IN_USE = 0x00000001, // always set + INODE_ATTR_INODE = 0x00000004, + INODE_LOGGED = 0x00000008, // log changes to the data stream + INODE_DELETED = 0x00000010, + INODE_EMPTY = 0x00000020, + INODE_LONG_SYMLINK = 0x00000040, // symlink in data stream + + INODE_PERMANENT_FLAGS = 0x0000ffff, + + INODE_NO_CACHE = 0x00010000, + INODE_WAS_WRITTEN = 0x00020000, + INODE_NO_TRANSACTION = 0x00040000, +}; + +//************************************** + +struct file_cookie { + bigtime_t last_notification; + off_t last_size; + int open_mode; +}; + +// notify every second if the file size has changed +#define INODE_NOTIFICATION_INTERVAL 1000000LL + +//************************************** + + +inline int32 +divide_roundup(int32 num,int32 divisor) +{ + return (num + divisor - 1) / divisor; +} + +inline int64 +divide_roundup(int64 num,int32 divisor) +{ + return (num + divisor - 1) / divisor; +} + +inline int +get_shift(uint64 i) +{ + int c; + c = 0; + while (i > 1) { + i >>= 1; + c++; + } + return c; +} + +inline int32 +round_up(uint32 data) +{ + // rounds up to the next off_t boundary + return (data + sizeof(off_t) - 1) & ~(sizeof(off_t) - 1); +} + + +/************************ block_run inline functions ************************/ +// #pragma mark - + + +inline bool +block_run::operator==(const block_run &run) const +{ + return allocation_group == run.allocation_group + && start == run.start + && length == run.length; +} + + +inline bool +block_run::operator!=(const block_run &run) const +{ + return allocation_group != run.allocation_group + || start != run.start + || length != run.length; +} + + +inline bool +block_run::IsZero() +{ + return allocation_group == 0 && start == 0 && length == 0; +} + + +inline void +block_run::SetTo(int32 _group,uint16 _start,uint16 _length) +{ + allocation_group = _group; + start = _start; + length = _length; +} + + +inline block_run +block_run::Run(int32 group, uint16 start, uint16 length) +{ + block_run run; + run.allocation_group = group; + run.start = start; + run.length = length; + return run; +} + + +/************************ small_data inline functions ************************/ +// #pragma mark - + + +inline char * +small_data::Name() +{ + return name; +} + + +inline uint8 * +small_data::Data() +{ + return (uint8 *)name + name_size + 3; +} + + +inline uint32 +small_data::Size() +{ + return sizeof(small_data) + name_size + 3 + data_size + 1; +} + + +inline small_data * +small_data::Next() +{ + return (small_data *)((uint8 *)this + Size()); +} + + +inline bool +small_data::IsLast(bfs_inode *inode) +{ + // we need to check the location first, because if name_size is already beyond + // the block, we would touch invalid memory (although that can't cause wrong + // results) + return (uint32)this > (uint32)inode + inode->inode_size - sizeof(small_data) || name_size == 0; +} + +#endif /* BFS_H */ diff --git a/src/add-ons/kernel/file_systems/befs/cache.h b/src/add-ons/kernel/file_systems/befs/cache.h new file mode 100644 index 0000000000..a0e913840e --- /dev/null +++ b/src/add-ons/kernel/file_systems/befs/cache.h @@ -0,0 +1,108 @@ +/* + Copyright 1999-2001, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. +*/ + +#ifndef _CACHE_H_ +#define _CACHE_H_ + +#include + +typedef struct hash_ent { + int dev; + off_t bnum; + off_t hash_val; + void *data; + struct hash_ent *next; +} hash_ent; + + +typedef struct hash_table { + hash_ent **table; + int max; + int mask; /* == max - 1 */ + int num_elements; +} hash_table; + + +#define HT_DEFAULT_MAX 128 + + +typedef struct cache_ent { + int dev; + off_t block_num; + int bsize; + volatile int flags; + + void *data; + void *clone; /* copy of data by set_block_info() */ + int lock; + + void (*func)(off_t bnum, size_t num_blocks, void *arg); + off_t logged_bnum; + void *arg; + + struct cache_ent *next, /* points toward mru end of list */ + *prev; /* points toward lru end of list */ + +} cache_ent; + +#define CE_NORMAL 0x0000 /* a nice clean pristine page */ +#define CE_DIRTY 0x0002 /* needs to be written to disk */ +#define CE_BUSY 0x0004 /* this block has i/o happening, don't touch it */ + + +typedef struct cache_ent_list { + cache_ent *lru; /* tail of the list */ + cache_ent *mru; /* head of the list */ +} cache_ent_list; + + +typedef struct block_cache { + struct lock lock; + int flags; + int cur_blocks; + int max_blocks; + hash_table ht; + + cache_ent_list normal, /* list of "normal" blocks (clean & dirty) */ + locked; /* list of clean and locked blocks */ +} block_cache; + +#if 0 /* XXXdbg -- need to deal with write through caches */ +#define DC_WRITE_THROUGH 0x0001 /* cache is write-through (for floppies) */ +#endif + +#define ALLOW_WRITES 1 +#define NO_WRITES 0 + +extern _IMPEXP_KERNEL int init_block_cache(int max_blocks, int flags); +extern _IMPEXP_KERNEL void shutdown_block_cache(void); + +extern _IMPEXP_KERNEL void force_cache_flush(int dev, int prefer_log_blocks); +extern _IMPEXP_KERNEL int flush_blocks(int dev, off_t bnum, int nblocks); +extern _IMPEXP_KERNEL int flush_device(int dev, int warn_locked); + +extern _IMPEXP_KERNEL int init_cache_for_device(int fd, off_t max_blocks); +extern _IMPEXP_KERNEL int remove_cached_device_blocks(int dev, int allow_write); + +extern _IMPEXP_KERNEL void *get_block(int dev, off_t bnum, int bsize); +extern _IMPEXP_KERNEL void *get_empty_block(int dev, off_t bnum, int bsize); +extern _IMPEXP_KERNEL int release_block(int dev, off_t bnum); +extern _IMPEXP_KERNEL int mark_blocks_dirty(int dev, off_t bnum, int nblocks); + + +extern _IMPEXP_KERNEL int cached_read(int dev, off_t bnum, void *data, off_t num_blocks, int bsize); +extern _IMPEXP_KERNEL int cached_write(int dev, off_t bnum, const void *data, + off_t num_blocks, int bsize); +extern _IMPEXP_KERNEL int cached_write_locked(int dev, off_t bnum, const void *data, + off_t num_blocks, int bsize); +extern _IMPEXP_KERNEL int set_blocks_info(int dev, off_t *blocks, int nblocks, + void (*func)(off_t bnum, size_t nblocks, void *arg), + void *arg); + + +extern _IMPEXP_KERNEL size_t read_phys_blocks (int fd, off_t bnum, void *data, uint num_blocks, int bsize); +extern _IMPEXP_KERNEL size_t write_phys_blocks(int fd, off_t bnum, void *data, uint num_blocks, int bsize); + +#endif /* _CACHE_H_ */ diff --git a/src/add-ons/kernel/file_systems/befs/cpp.cpp b/src/add-ons/kernel/file_systems/befs/cpp.cpp new file mode 100644 index 0000000000..47d5ca110b --- /dev/null +++ b/src/add-ons/kernel/file_systems/befs/cpp.cpp @@ -0,0 +1,17 @@ +/* cpp - C++ in the kernel +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include "cpp.h" + + +nothrow_t _dontthrow; + +extern "C" void __pure_virtual() +{ + //printf("pure virtual function call"); +} + diff --git a/src/add-ons/kernel/file_systems/befs/cpp.h b/src/add-ons/kernel/file_systems/befs/cpp.h new file mode 100644 index 0000000000..c9fd65fdf3 --- /dev/null +++ b/src/add-ons/kernel/file_systems/befs/cpp.h @@ -0,0 +1,52 @@ +#ifndef CPP_H +#define CPP_H +/* cpp - C++ in the kernel +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include +#include + + +// Oh no! C++ in the kernel! Are you nuts? +// +// - no exceptions +// - (almost) no virtuals (well, the Query code now uses them) +// - it's basically only the C++ syntax, and type checking +// - since one tend to encapsulate everything in classes, it has a slightly +// higher memory overhead +// - nicer code +// - easier to maintain + + +inline void *operator new(size_t size, const nothrow_t&) throw() +{ + return malloc(size); +} + +inline void *operator new[](size_t size, const nothrow_t&) throw() +{ + return malloc(size); +} + +inline void operator delete(void *ptr) +{ + free(ptr); +} + +inline void operator delete[](void *ptr) +{ + free(ptr); +} + +// now we're using virtuals +extern "C" void __pure_virtual(); + +extern nothrow_t _dontthrow; +#define new new (_dontthrow) + + +#endif /* CPP_H */ diff --git a/src/add-ons/kernel/file_systems/befs/fsproto.h b/src/add-ons/kernel/file_systems/befs/fsproto.h new file mode 100644 index 0000000000..1fc15ddc7c --- /dev/null +++ b/src/add-ons/kernel/file_systems/befs/fsproto.h @@ -0,0 +1,249 @@ +/* + Copyright 1999-2001, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. +*/ + +#ifndef _FSPROTO_H +#define _FSPROTO_H + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +typedef dev_t nspace_id; +typedef ino_t vnode_id; + +/* + * PUBLIC PART OF THE FILE SYSTEM PROTOCOL + */ + +#define WSTAT_MODE 0x0001 +#define WSTAT_UID 0x0002 +#define WSTAT_GID 0x0004 +#define WSTAT_SIZE 0x0008 +#define WSTAT_ATIME 0x0010 +#define WSTAT_MTIME 0x0020 +#define WSTAT_CRTIME 0x0040 + +#define WFSSTAT_NAME 0x0001 + +#define B_ENTRY_CREATED 1 +#define B_ENTRY_REMOVED 2 +#define B_ENTRY_MOVED 3 +#define B_STAT_CHANGED 4 +#define B_ATTR_CHANGED 5 +#define B_DEVICE_MOUNTED 6 +#define B_DEVICE_UNMOUNTED 7 + +#define B_STOP_WATCHING 0x0000 +#define B_WATCH_NAME 0x0001 +#define B_WATCH_STAT 0x0002 +#define B_WATCH_ATTR 0x0004 +#define B_WATCH_DIRECTORY 0x0008 + +#define SELECT_READ 1 +#define SELECT_WRITE 2 +#define SELECT_EXCEPTION 3 + +// missing ioctl() call added +#define IOCTL_FILE_UNCACHED_IO 10000 + +#define B_CUR_FS_API_VERSION 2 + +struct attr_info; +struct index_info; + +typedef int op_read_vnode(void *ns, vnode_id vnid, char r, void **node); +typedef int op_write_vnode(void *ns, void *node, char r); +typedef int op_remove_vnode(void *ns, void *node, char r); +typedef int op_secure_vnode(void *ns, void *node); + +typedef int op_walk(void *ns, void *base, const char *file, char **newpath, + vnode_id *vnid); + +typedef int op_access(void *ns, void *node, int mode); + +typedef int op_create(void *ns, void *dir, const char *name, + int omode, int perms, vnode_id *vnid, void **cookie); +typedef int op_mkdir(void *ns, void *dir, const char *name, int perms); +typedef int op_symlink(void *ns, void *dir, const char *name, + const char *path); +typedef int op_link(void *ns, void *dir, const char *name, void *node); + +typedef int op_rename(void *ns, void *olddir, const char *oldname, + void *newdir, const char *newname); +typedef int op_unlink(void *ns, void *dir, const char *name); +typedef int op_rmdir(void *ns, void *dir, const char *name); + +typedef int op_readlink(void *ns, void *node, char *buf, size_t *bufsize); + +typedef int op_opendir(void *ns, void *node, void **cookie); +typedef int op_closedir(void *ns, void *node, void *cookie); +typedef int op_rewinddir(void *ns, void *node, void *cookie); +typedef int op_readdir(void *ns, void *node, void *cookie, long *num, + struct dirent *buf, size_t bufsize); + +typedef int op_open(void *ns, void *node, int omode, void **cookie); +typedef int op_close(void *ns, void *node, void *cookie); +typedef int op_free_cookie(void *ns, void *node, void *cookie); +typedef int op_read(void *ns, void *node, void *cookie, off_t pos, void *buf, + size_t *len); +typedef int op_write(void *ns, void *node, void *cookie, off_t pos, + const void *buf, size_t *len); +typedef int op_readv(void *ns, void *node, void *cookie, off_t pos, const iovec *vec, + size_t count, size_t *len); +typedef int op_writev(void *ns, void *node, void *cookie, off_t pos, const iovec *vec, + size_t count, size_t *len); +typedef int op_ioctl(void *ns, void *node, void *cookie, int cmd, void *buf, + size_t len); +typedef int op_setflags(void *ns, void *node, void *cookie, int flags); + +typedef int op_rstat(void *ns, void *node, struct stat *); +typedef int op_wstat(void *ns, void *node, struct stat *, long mask); +typedef int op_fsync(void *ns, void *node); + +typedef int op_select(void *ns, void *node, void *cookie, uint8 event, + uint32 ref, selectsync *sync); +typedef int op_deselect(void *ns, void *node, void *cookie, uint8 event, + selectsync *sync); + +typedef int op_initialize(const char *devname, void *parms, size_t len); +typedef int op_mount(nspace_id nsid, const char *devname, ulong flags, + void *parms, size_t len, void **data, vnode_id *vnid); +typedef int op_unmount(void *ns); +typedef int op_sync(void *ns); +typedef int op_rfsstat(void *ns, struct fs_info *); +typedef int op_wfsstat(void *ns, struct fs_info *, long mask); + + +typedef int op_open_attrdir(void *ns, void *node, void **cookie); +typedef int op_close_attrdir(void *ns, void *node, void *cookie); +typedef int op_rewind_attrdir(void *ns, void *node, void *cookie); +typedef int op_read_attrdir(void *ns, void *node, void *cookie, long *num, + struct dirent *buf, size_t bufsize); +typedef int op_remove_attr(void *ns, void *node, const char *name); +typedef int op_rename_attr(void *ns, void *node, const char *oldname, + const char *newname); +typedef int op_stat_attr(void *ns, void *node, const char *name, + struct attr_info *buf); + +typedef int op_write_attr(void *ns, void *node, const char *name, int type, + const void *buf, size_t *len, off_t pos); +typedef int op_read_attr(void *ns, void *node, const char *name, int type, + void *buf, size_t *len, off_t pos); + +typedef int op_open_indexdir(void *ns, void **cookie); +typedef int op_close_indexdir(void *ns, void *cookie); +typedef int op_rewind_indexdir(void *ns, void *cookie); +typedef int op_read_indexdir(void *ns, void *cookie, long *num, + struct dirent *buf, size_t bufsize); +typedef int op_create_index(void *ns, const char *name, int type, int flags); +typedef int op_remove_index(void *ns, const char *name); +typedef int op_rename_index(void *ns, const char *oldname, + const char *newname); +typedef int op_stat_index(void *ns, const char *name, struct index_info *buf); + +typedef int op_open_query(void *ns, const char *query, ulong flags, + port_id port, long token, void **cookie); +typedef int op_close_query(void *ns, void *cookie); +typedef int op_read_query(void *ns, void *cookie, long *num, + struct dirent *buf, size_t bufsize); + +typedef struct vnode_ops { + op_read_vnode (*read_vnode); + op_write_vnode (*write_vnode); + op_remove_vnode (*remove_vnode); + op_secure_vnode (*secure_vnode); + op_walk (*walk); + op_access (*access); + op_create (*create); + op_mkdir (*mkdir); + op_symlink (*symlink); + op_link (*link); + op_rename (*rename); + op_unlink (*unlink); + op_rmdir (*rmdir); + op_readlink (*readlink); + op_opendir (*opendir); + op_closedir (*closedir); + op_free_cookie (*free_dircookie); + op_rewinddir (*rewinddir); + op_readdir (*readdir); + op_open (*open); + op_close (*close); + op_free_cookie (*free_cookie); + op_read (*read); + op_write (*write); + op_readv (*readv); + op_writev (*writev); + op_ioctl (*ioctl); + op_setflags (*setflags); + op_rstat (*rstat); + op_wstat (*wstat); + op_fsync (*fsync); + op_initialize (*initialize); + op_mount (*mount); + op_unmount (*unmount); + op_sync (*sync); + op_rfsstat (*rfsstat); + op_wfsstat (*wfsstat); + op_select (*select); + op_deselect (*deselect); + op_open_indexdir (*open_indexdir); + op_close_indexdir (*close_indexdir); + op_free_cookie (*free_indexdircookie); + op_rewind_indexdir (*rewind_indexdir); + op_read_indexdir (*read_indexdir); + op_create_index (*create_index); + op_remove_index (*remove_index); + op_rename_index (*rename_index); + op_stat_index (*stat_index); + op_open_attrdir (*open_attrdir); + op_close_attrdir (*close_attrdir); + op_free_cookie (*free_attrdircookie); + op_rewind_attrdir (*rewind_attrdir); + op_read_attrdir (*read_attrdir); + op_write_attr (*write_attr); + op_read_attr (*read_attr); + op_remove_attr (*remove_attr); + op_rename_attr (*rename_attr); + op_stat_attr (*stat_attr); + op_open_query (*open_query); + op_close_query (*close_query); + op_free_cookie (*free_querycookie); + op_read_query (*read_query); +} vnode_ops; + +extern _IMPEXP_KERNEL int new_path(const char *path, char **copy); +extern _IMPEXP_KERNEL void free_path(char *p); + +extern _IMPEXP_KERNEL int notify_listener(int op, nspace_id nsid, + vnode_id vnida, vnode_id vnidb, + vnode_id vnidc, const char *name); +extern _IMPEXP_KERNEL void notify_select_event(selectsync *sync, uint32 ref); +extern _IMPEXP_KERNEL int send_notification(port_id port, long token, + ulong what, long op, nspace_id nsida, + nspace_id nsidb, vnode_id vnida, + vnode_id vnidb, vnode_id vnidc, + const char *name); +extern _IMPEXP_KERNEL int get_vnode(nspace_id nsid, vnode_id vnid, void **data); +extern _IMPEXP_KERNEL int put_vnode(nspace_id nsid, vnode_id vnid); +extern _IMPEXP_KERNEL int new_vnode(nspace_id nsid, vnode_id vnid, void *data); +extern _IMPEXP_KERNEL int remove_vnode(nspace_id nsid, vnode_id vnid); +extern _IMPEXP_KERNEL int unremove_vnode(nspace_id nsid, vnode_id vnid); +extern _IMPEXP_KERNEL int is_vnode_removed(nspace_id nsid, vnode_id vnid); + + +extern _EXPORT vnode_ops fs_entry; +extern _EXPORT int32 api_version; + +#endif diff --git a/src/add-ons/kernel/file_systems/befs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/befs/kernel_interface.cpp new file mode 100644 index 0000000000..5dcaab7628 --- /dev/null +++ b/src/add-ons/kernel/file_systems/befs/kernel_interface.cpp @@ -0,0 +1,1880 @@ +/* kernel_interface - file system interface to BeOS' vnode layer +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include "Debug.h" +#include "cpp.h" +#include "Volume.h" +#include "Inode.h" +#include "Index.h" +#include "BPlusTree.h" +#include "Query.h" + +#include +#include + +// BeOS vnode layer stuff +#include +#ifndef _IMPEXP_KERNEL +# define _IMPEXP_KERNEL +#endif + +extern "C" { + #include + #include + #include +} +#include +#include + + +#ifdef USER +# define dprintf printf +#endif + + +extern "C" { + static int bfs_mount(nspace_id nsid, const char *device, ulong flags, + void *parms, size_t len, void **data, vnode_id *vnid); + static int bfs_unmount(void *_ns); + static int bfs_read_fs_stat(void *_ns, struct fs_info *); + static int bfs_write_fs_stat(void *ns, struct fs_info *, long mode); + static int bfs_initialize(const char *devname, void *parms, size_t len); + + static int bfs_sync(void *ns); + + static int bfs_read_vnode(void *_ns, vnode_id vnid, char r, void **node); + static int bfs_release_vnode(void *_ns, void *_node, char r); + static int bfs_remove_vnode(void *ns, void *node, char r); + + static int bfs_walk(void *_ns, void *_base, const char *file, + char **newpath, vnode_id *vnid); + + static int bfs_ioctl(void *ns, void *node, void *cookie, int cmd, void *buf,size_t len); + static int bfs_setflags(void *ns, void *node, void *cookie, int flags); + + static int bfs_select(void *ns, void *node, void *cookie, uint8 event, + uint32 ref, selectsync *sync); + static int bfs_deselect(void *ns, void *node, void *cookie, uint8 event, + selectsync *sync); + static int bfs_fsync(void *ns,void *node); + + static int bfs_create(void *ns, void *dir, const char *name, + int perms, int omode, vnode_id *vnid, void **cookie); + static int bfs_symlink(void *ns, void *dir, const char *name, + const char *path); + static int bfs_link(void *ns, void *dir, const char *name, void *node); + static int bfs_unlink(void *ns, void *dir, const char *name); + static int bfs_rename(void *ns, void *oldDir, const char *oldName, void *newDir, const char *newName); + + static int bfs_read_stat(void *_ns, void *_node, struct stat *st); + static int bfs_write_stat(void *ns, void *node, struct stat *st, long mask); + + static int bfs_open(void *_ns, void *_node, int omode, void **cookie); + static int bfs_read(void *_ns, void *_node, void *cookie, off_t pos, + void *buf, size_t *len); + static int bfs_write(void *ns, void *node, void *cookie, off_t pos, + const void *buf, size_t *len); + static int bfs_free_cookie(void *ns, void *node, void *cookie); + static int bfs_close(void *ns, void *node, void *cookie); + + static int bfs_access(void *_ns, void *_node, int mode); + static int bfs_read_link(void *_ns, void *_node, char *buffer, size_t *bufferSize); + + // directory functions + static int bfs_mkdir(void *ns, void *dir, const char *name, int perms); + static int bfs_rmdir(void *ns, void *dir, const char *name); + static int bfs_open_dir(void *_ns, void *_node, void **cookie); + static int bfs_read_dir(void *_ns, void *_node, void *cookie, + long *num, struct dirent *dirent, size_t bufferSize); + static int bfs_rewind_dir(void *_ns, void *_node, void *cookie); + static int bfs_close_dir(void *_ns, void *_node, void *cookie); + static int bfs_free_dir_cookie(void *_ns, void *_node, void *cookie); + + // attribute support + static int bfs_open_attrdir(void *ns, void *node, void **cookie); + static int bfs_close_attrdir(void *ns, void *node, void *cookie); + static int bfs_free_attrdir_cookie(void *ns, void *node, void *cookie); + static int bfs_rewind_attrdir(void *ns, void *node, void *cookie); + static int bfs_read_attrdir(void *ns, void *node, void *cookie, long *num, + struct dirent *buf, size_t bufferSize); + static int bfs_remove_attr(void *ns, void *node, const char *name); + static int bfs_rename_attr(void *ns, void *node, const char *oldname, + const char *newname); + static int bfs_stat_attr(void *ns, void *node, const char *name, + struct attr_info *buf); + static int bfs_write_attr(void *ns, void *node, const char *name, int type, + const void *buf, size_t *len, off_t pos); + static int bfs_read_attr(void *ns, void *node, const char *name, int type, + void *buf, size_t *len, off_t pos); + + // index support + static int bfs_open_indexdir(void *ns, void **cookie); + static int bfs_close_indexdir(void *ns, void *cookie); + static int bfs_free_indexdir_cookie(void *ns, void *node, void *cookie); + static int bfs_rewind_indexdir(void *ns, void *cookie); + static int bfs_read_indexdir(void *ns, void *cookie, long *num,struct dirent *dirent, + size_t bufferSize); + static int bfs_create_index(void *ns, const char *name, int type, int flags); + static int bfs_remove_index(void *ns, const char *name); + static int bfs_rename_index(void *ns, const char *oldname, const char *newname); + static int bfs_stat_index(void *ns, const char *name, struct index_info *indexInfo); + + // query support + static int bfs_open_query(void *ns, const char *query, ulong flags, + port_id port, long token, void **cookie); + static int bfs_close_query(void *ns, void *cookie); + static int bfs_free_query_cookie(void *ns, void *node, void *cookie); + static int bfs_read_query(void *ns, void *cookie, long *num, + struct dirent *buf, size_t bufsize); +} // extern "C" + + +/* vnode_ops struct. Fill this in to tell the kernel how to call + functions in your driver. +*/ + +vnode_ops fs_entry = { + &bfs_read_vnode, // read_vnode + &bfs_release_vnode, // write_vnode + &bfs_remove_vnode, // remove_vnode + NULL, // secure_vnode (not needed) + &bfs_walk, // walk + &bfs_access, // access + &bfs_create, // create + &bfs_mkdir, // mkdir + &bfs_symlink, // symlink + &bfs_link, // link + &bfs_rename, // rename + &bfs_unlink, // unlink + &bfs_rmdir, // rmdir + &bfs_read_link, // readlink + &bfs_open_dir, // opendir + &bfs_close_dir, // closedir + &bfs_free_dir_cookie, // free_dircookie + &bfs_rewind_dir, // rewinddir + &bfs_read_dir, // readdir + &bfs_open, // open file + &bfs_close, // close file + &bfs_free_cookie, // free cookie + &bfs_read, // read file + &bfs_write, // write file + NULL, // readv + NULL, // writev + &bfs_ioctl, // ioctl + &bfs_setflags, // setflags file + &bfs_read_stat, // read stat + &bfs_write_stat, // write stat + &bfs_fsync, // fsync + &bfs_initialize, // initialize + &bfs_mount, // mount + &bfs_unmount, // unmount + &bfs_sync, // sync + &bfs_read_fs_stat, // read fs stat + &bfs_write_fs_stat, // write fs stat + &bfs_select, // select + &bfs_deselect, // deselect + + &bfs_open_indexdir, // open index dir + &bfs_close_indexdir, // close index dir + &bfs_free_indexdir_cookie, // free index dir cookie + &bfs_rewind_indexdir, // rewind index dir + &bfs_read_indexdir, // read index dir + &bfs_create_index, // create index + &bfs_remove_index, // remove index + &bfs_rename_index, // rename index + &bfs_stat_index, // stat index + + &bfs_open_attrdir, // open attr dir + &bfs_close_attrdir, // close attr dir + &bfs_free_attrdir_cookie, // free attr dir cookie + &bfs_rewind_attrdir, // rewind attr dir + &bfs_read_attrdir, // read attr dir + &bfs_write_attr, // write attr + &bfs_read_attr, // read attr + &bfs_remove_attr, // remove attr + &bfs_rename_attr, // rename attr + &bfs_stat_attr, // stat attr + + &bfs_open_query, // open query + &bfs_close_query, // close query + &bfs_free_query_cookie, // free query cookie + &bfs_read_query // read query +}; + +#define BFS_IO_SIZE 65536 +int32 api_version = B_CUR_FS_API_VERSION; + + +static int +bfs_mount(nspace_id nsid, const char *device, ulong flags, void *parms, + size_t len, void **data, vnode_id *rootID) +{ + FUNCTION(); + +#ifndef USER + // If you can't build the file system because of this line, you can either + // add the prototype: + // extern int load_driver_symbols(const char *driver_name); + // to your KernelExport.h include (since it's missing there in some releases + // of BeOS R5), or just comment out the line, it won't do any harm and is + // used only for debugging purposes. + load_driver_symbols("obfs"); +#endif + + Volume *volume = new Volume(nsid); + if (volume == NULL) + return B_NO_MEMORY; + + status_t status; + if ((status = volume->Mount(device,flags)) == B_OK) { + *data = volume; + *rootID = volume->ToVnode(volume->Root()); + INFORM(("mounted \"%s\" (root node at %Ld, device = %s)\n",volume->Name(),*rootID,device)); + } + else + delete volume; + + RETURN_ERROR(status); +} + + +static int +bfs_unmount(void *ns) +{ + FUNCTION(); + Volume* volume = (Volume *)ns; + + status_t status = volume->Unmount(); + delete volume; + + RETURN_ERROR(status); +} + + +/** Fill in bfs_info struct for device. + */ + +static int +bfs_read_fs_stat(void *_ns, struct fs_info *info) +{ + FUNCTION(); + if (_ns == NULL || info == NULL) + return B_BAD_VALUE; + + Volume *volume = (Volume *)_ns; + + // File system flags. + info->flags = B_FS_IS_PERSISTENT | B_FS_HAS_ATTR | B_FS_HAS_MIME | B_FS_HAS_QUERY | + (volume->IsReadOnly() ? B_FS_IS_READONLY : 0); + + info->io_size = BFS_IO_SIZE; + // whatever is appropriate here? Just use the same value as BFS (and iso9660) for now + + info->block_size = volume->BlockSize(); + info->total_blocks = volume->NumBlocks(); + info->free_blocks = volume->FreeBlocks(); + + // Volume name + strncpy(info->volume_name, volume->Name(), sizeof(info->volume_name) - 1); + info->volume_name[sizeof(info->volume_name) - 1] = '\0'; + + // File system name (ToDo: has to change to "bfs" later) + strcpy(info->fsh_name,"obfs"); + + return B_NO_ERROR; +} + + +static int +bfs_write_fs_stat(void *_ns, struct fs_info *info, long mask) +{ + FUNCTION_START(("mask = %ld\n",mask)); + Volume *volume = (Volume *)_ns; + disk_super_block &superBlock = volume->SuperBlock(); + + Locker locker(volume->Lock()); + + status_t status = B_BAD_VALUE; + + if (mask & WFSSTAT_NAME) { + strncpy(superBlock.name,info->volume_name,sizeof(superBlock.name) - 1); + superBlock.name[sizeof(superBlock.name) - 1] = '\0'; + + status = volume->WriteSuperBlock(); + } + return status; +} + + +int +bfs_initialize(const char *deviceName, void *parms, size_t len) +{ + FUNCTION_START(("deviceName = %s, parameter len = %ld\n",deviceName,len)); + + // ToDo: implement bfs_initialize()! + + return B_ERROR; +} + + +int +bfs_sync(void *_ns) +{ + FUNCTION(); + if (_ns == NULL) + return B_BAD_VALUE; + + Volume *volume = (Volume *)_ns; + + return volume->Sync(); +} + + +// #pragma mark - + + +/** Using vnode id, read in vnode information into fs-specific struct, + * and return it in node. the reenter flag tells you if this function + * is being called via some other fs routine, so that things like + * double-locking can be avoided. + */ + +static int +bfs_read_vnode(void *_ns, vnode_id id, char reenter, void **node) +{ + FUNCTION_START(("vnode_id = %Ld\n",id)); + Volume *volume = (Volume *)_ns; + + if (id < 0 || id > volume->NumBlocks()) { + FATAL(("inode at %Ld requested!\n",id)); + return B_ERROR; + } + + Inode *inode = new Inode(volume,id,false,reenter); + if (inode == NULL) + return B_NO_MEMORY; + + if (inode->InitCheck() == B_OK) { + *node = (void *)inode; + return B_OK; + } + + delete inode; + RETURN_ERROR(B_ERROR); +} + + +static int +bfs_release_vnode(void *ns, void *_node, char reenter) +{ + //FUNCTION_START(("node = %p\n",_node)); + Inode *inode = (Inode *)_node; + + delete inode; + + return B_NO_ERROR; +} + + +int +bfs_remove_vnode(void *_ns, void *_node, char reenter) +{ + FUNCTION(); + + if (_ns == NULL || _node == NULL) + return B_BAD_VALUE; + + Volume *volume = (Volume *)_ns; + Inode *inode = (Inode *)_node; + + // If the inode isn't in use anymore, we were called before + // bfs_unlink() returns - in this case, we can just use the + // transaction which has already deleted the inode. + Transaction localTransaction,*transaction = &localTransaction; + Journal *journal = volume->GetJournal(volume->ToBlock(inode->Parent())); + + if (journal != NULL && journal->CurrentThread() == find_thread(NULL)) + transaction = journal->CurrentTransaction(); + else + localTransaction.Start(volume,inode->BlockNumber()); + + // Perhaps there should be an implementation of Inode::ShrinkStream() that + // just frees the data_stream, but doesn't change the inode (since it is + // freed anyway) - that would make an undelete command possible + status_t status = inode->SetFileSize(transaction,0); + if (status < B_OK) + return status; + + // Free all attributes, and remove their indices + { + // We have to limit the scope of AttributeIterator, so that its + // destructor is not called after the inode is deleted + AttributeIterator iterator(inode); + + char name[B_FILE_NAME_LENGTH]; + uint32 type; + size_t length; + vnode_id id; + while ((status = iterator.GetNext(name,&length,&type,&id)) == B_OK) + inode->RemoveAttribute(transaction,name); + } + + if ((status = volume->Free(transaction,inode->BlockRun())) == B_OK) { + if (transaction == &localTransaction) + localTransaction.Done(); + + delete inode; + } + + return B_OK; +} + + +// #pragma mark - + + +/** the walk function just "walks" through a directory looking for the + * specified file. It calls get_vnode() on its vnode-id to init it + * for the kernel. + */ + +static int +bfs_walk(void *_ns, void *_directory, const char *file, char **_resolvedPath, vnode_id *vnid) +{ + FUNCTION_START(("file = %s\n",file)); + + if (_ns == NULL || _directory == NULL || file == NULL) + return B_BAD_VALUE; + + Volume *volume = (Volume *)_ns; + Inode *directory = (Inode *)_directory; + + // check access permissions + status_t status = directory->CheckPermissions(X_OK); + if (status < B_OK) + RETURN_ERROR(status); + + BPlusTree *tree; + if (directory->GetTree(&tree) != B_OK) + RETURN_ERROR(B_BAD_VALUE); + + if ((status = tree->Find((uint8 *)file,(uint16)strlen(file),vnid)) < B_OK) + RETURN_ERROR(status); + + Inode *inode; + if ((status = get_vnode(volume->ID(),*vnid,(void **)&inode)) != B_OK) { + REPORT_ERROR(status); + return B_ENTRY_NOT_FOUND; + } + + // Is inode a symlink? Then resolve it, if we should + + if (inode->IsSymLink() && _resolvedPath != NULL) { + status_t status = B_OK; + char *newPath = NULL; + + // Symbolic links can store their target in the data stream (for links + // that take more than 144 bytes of storage [the size of the data_stream + // structure]), or directly instead of the data_stream class + // So we have to deal with both cases here. + + // Note: we would naturally call bfs_read_link() here, but the API of the + // vnode layer would require us to always reserve a large chunk of memory + // for the path, so we're not going to do that + + if (inode->Flags() & INODE_LONG_SYMLINK) { + size_t readBytes = inode->Node()->data.size; + char *data = (char *)malloc(readBytes); + if (data != NULL) { + status = inode->ReadAt(0, (uint8 *)data, &readBytes); + if (status == B_OK && readBytes == inode->Node()->data.size) + status = new_path(data, &newPath); + + free(data); + } else + status = B_NO_MEMORY; + } else + status = new_path((char *)&inode->Node()->short_symlink, &newPath); + + put_vnode(volume->ID(), inode->ID()); + if (status == B_OK) + *_resolvedPath = newPath; + + RETURN_ERROR(status); + } + + return B_OK; +} + + +int +bfs_ioctl(void *_ns, void *_node, void *_cookie, int cmd, void *buffer, size_t bufferLength) +{ + FUNCTION_START(("node = %p, cmd = %d, buf = %p, len = %ld\n",_node,cmd,buffer,bufferLength)); + + if (_ns == NULL) + return B_BAD_VALUE; + + Volume *volume = (Volume *)_ns; + Inode *inode = (Inode *)_node; + + switch (cmd) { + case IOCTL_FILE_UNCACHED_IO: + if (inode != NULL) + PRINT(("trying to make access to inode %lx uncached. Not yet implemented!\n",inode->ID())); + return B_ERROR; +#ifdef DEBUG + case 56742: + { + // allocate all free blocks and zero them out (a test for the BlockAllocator)! + BlockAllocator &allocator = volume->Allocator(); + Transaction transaction(volume,0); + CachedBlock cached(volume); + block_run run; + while (allocator.AllocateBlocks(&transaction,8,0,64,1,run) == B_OK) { + PRINT(("write block_run(%ld, %d, %d)\n",run.allocation_group,run.start,run.length)); + for (int32 i = 0;i < run.length;i++) { + uint8 *block = cached.SetTo(run); + if (block != NULL) { + memset(block,0,volume->BlockSize()); + cached.WriteBack(&transaction); + } + } + } + return B_OK; + } + case 56743: + dump_super_block(&volume->SuperBlock()); + return B_OK; + case 56744: + if (inode != NULL) + dump_inode(inode->Node()); + return B_OK; + case 56745: + if (inode != NULL) + dump_block((const char *)inode->Node(),volume->BlockSize()); + return B_OK; +#endif + } + return B_BAD_VALUE; +} + + +int +bfs_setflags(void *ns, void *node, void *cookie, int flags) +{ + FUNCTION_START(("node = %p, flags = %d",node,flags)); + + // ToDo: implement bfs_setflags()! + INFORM(("setflags not yet implemented...\n")); + + return B_OK; +} + + +int +bfs_select(void *ns, void *node, void *cookie, uint8 event, uint32 ref, selectsync *sync) +{ + FUNCTION_START(("event = %d, ref = %lu, sync = %p\n",event,ref,sync)); + notify_select_event(sync, ref); + + return B_OK; +} + + +int +bfs_deselect(void *ns, void *node, void *cookie, uint8 event, selectsync *sync) +{ + FUNCTION(); + return B_OK; +} + + +int +bfs_fsync(void *_ns, void *_node) +{ + FUNCTION(); + if (_node == NULL) + return B_BAD_VALUE; + + Inode *inode = (Inode *)_node; + return inode->Sync(); +} + + +/** Fills in the stat struct for a node + */ + +static int +bfs_read_stat(void *_ns, void *_node, struct stat *st) +{ + FUNCTION(); + + Volume *volume = (Volume *)_ns; + Inode *inode = (Inode *)_node; + bfs_inode *node = inode->Node(); + + st->st_dev = volume->ID(); + st->st_ino = inode->ID(); + st->st_nlink = 1; + st->st_blksize = BFS_IO_SIZE; + + st->st_uid = node->uid; + st->st_gid = node->gid; + st->st_mode = node->mode; + st->st_size = node->data.size; + + st->st_atime = time(NULL); + st->st_mtime = st->st_ctime = (time_t)(node->last_modified_time >> INODE_TIME_SHIFT); + st->st_crtime = (time_t)(node->create_time >> INODE_TIME_SHIFT); + + return B_NO_ERROR; +} + + +int +bfs_write_stat(void *_ns, void *_node, struct stat *stat, long mask) +{ + FUNCTION(); + + if (_ns == NULL || _node == NULL || stat == NULL) + RETURN_ERROR(B_BAD_VALUE); + + Volume *volume = (Volume *)_ns; + Inode *inode = (Inode *)_node; + + // that may be incorrect here - I don't think we need write access to + // change most of the stat... + // we should definitely check a bit more if the new stats are correct and valid... + + status_t status = inode->CheckPermissions(W_OK); + if (status < B_OK) + RETURN_ERROR(status); + + WriteLocked locked(inode->Lock()); + if (locked.IsLocked() < B_OK) + RETURN_ERROR(B_ERROR); + + Transaction transaction(volume,inode->BlockNumber()); + + bfs_inode *node = inode->Node(); + + if (mask & WSTAT_MODE) { + PRINT(("original mode = %ld, stat->st_mode = %ld\n",node->mode,stat->st_mode)); + node->mode = node->mode & ~S_IUMSK | stat->st_mode & S_IUMSK; + } + + if (mask & WSTAT_UID) + node->uid = stat->st_uid; + if (mask & WSTAT_GID) + node->gid = stat->st_gid; + + if (mask & WSTAT_SIZE) { + if (inode->IsDirectory()) + return B_IS_A_DIRECTORY; + + if (inode->Size() != stat->st_size) { + status = inode->SetFileSize(&transaction,stat->st_size); + + // fill the new blocks (if any) with zeros + inode->FillGapWithZeros(inode->OldSize(),inode->Size()); + + Index index(volume); + index.UpdateSize(&transaction,inode); + + if ((mask & WSTAT_MTIME) == 0) + index.UpdateLastModified(&transaction,inode); + } + } + + if (mask & WSTAT_MTIME) { + // Index::UpdateLastModified() will set the new time in the inode + Index index(volume); + index.UpdateLastModified(&transaction,inode,(bigtime_t)stat->st_mtime << INODE_TIME_SHIFT); + } + if (mask & WSTAT_CRTIME) { + node->create_time = (bigtime_t)stat->st_crtime << INODE_TIME_SHIFT; + } + + if ((status = inode->WriteBack(&transaction)) == B_OK) + transaction.Done(); + + notify_listener(B_STAT_CHANGED,volume->ID(),0,0,inode->ID(),NULL); + + return status; +} + + +int +bfs_create(void *_ns, void *_directory, const char *name, int omode, int mode, vnode_id *vnid, void **_cookie) +{ + FUNCTION_START(("name = \"%s\", perms = %ld, omode = %ld\n",name,mode,omode)); + + if (_ns == NULL || _directory == NULL || _cookie == NULL + || name == NULL || *name == '\0') + RETURN_ERROR(B_BAD_VALUE); + + Volume *volume = (Volume *)_ns; + Inode *directory = (Inode *)_directory; + + if (!directory->IsDirectory()) + RETURN_ERROR(B_BAD_TYPE); + + status_t status = directory->CheckPermissions(W_OK); + if (status < B_OK) + RETURN_ERROR(status); + + file_cookie *cookie = (file_cookie *)malloc(sizeof(file_cookie)); + if (cookie == NULL) + RETURN_ERROR(B_NO_MEMORY); + + // initialize the cookie + cookie->open_mode = omode; + cookie->last_size = 0; + cookie->last_notification = system_time(); + + Transaction transaction(volume,directory->BlockNumber()); + + status = Inode::Create(&transaction,directory,name,S_FILE | (mode & S_IUMSK),omode,0,vnid); + if (status == B_OK) { + transaction.Done(); + + notify_listener(B_ENTRY_CREATED,volume->ID(),directory->ID(),0,*vnid,name); + } + if (status < B_OK) + free(cookie); + else + *_cookie = cookie; + + return status; +} + + +int +bfs_symlink(void *_ns, void *_directory, const char *name, const char *path) +{ + FUNCTION(); + + if (_ns == NULL || _directory == NULL || path == NULL + || name == NULL || *name == '\0') + RETURN_ERROR(B_BAD_VALUE); + + Volume *volume = (Volume *)_ns; + Inode *directory = (Inode *)_directory; + + if (!directory->IsDirectory()) + RETURN_ERROR(B_BAD_TYPE); + + status_t status = directory->CheckPermissions(W_OK); + if (status < B_OK) + RETURN_ERROR(status); + + Transaction transaction(volume,directory->BlockNumber()); + + Inode *link; + off_t id; + status = Inode::Create(&transaction,directory,name,S_SYMLINK | 0777,0,0,&id,&link); + if (status < B_OK) + RETURN_ERROR(status); + + size_t length = strlen(path); + if (length < SHORT_SYMLINK_NAME_LENGTH) { + strcpy(link->Node()->short_symlink,path); + status = link->WriteBack(&transaction); + } else { + link->Node()->flags |= INODE_LONG_SYMLINK | INODE_LOGGED; + // The following call will have to write the inode back, so + // we don't have to do that here... + status = link->WriteAt(&transaction,0,(const uint8 *)path,&length); + } + + // Inode::Create() left the inode locked + put_vnode(volume->ID(),id); + + if (status == B_OK) { + transaction.Done(); + + notify_listener(B_ENTRY_CREATED,volume->ID(),directory->ID(),0,id,name); + } + + return status; +} + + +int +bfs_link(void *ns, void *dir, const char *name, void *node) +{ + FUNCTION_START(("name = \"%s\"\n",name)); + + // ToDo: implement bfs_link()?!? + + return B_ERROR; +} + + +int +bfs_unlink(void *_ns, void *_directory, const char *name) +{ + FUNCTION_START(("name = \"%s\"\n",name)); + + if (_ns == NULL || _directory == NULL || name == NULL || *name == '\0') + return B_BAD_VALUE; + if (!strcmp(name,"..") || !strcmp(name,".")) + return B_NOT_ALLOWED; + + Volume *volume = (Volume *)_ns; + Inode *directory = (Inode *)_directory; + + status_t status = directory->CheckPermissions(W_OK); + if (status < B_OK) + return status; + + Transaction transaction(volume,directory->BlockNumber()); + + off_t id; + if ((status = directory->Remove(&transaction,name,&id)) == B_OK) { + transaction.Done(); + + notify_listener(B_ENTRY_REMOVED,volume->ID(),directory->ID(),0,id,NULL); + } + return status; +} + + +int +bfs_rename(void *_ns, void *_oldDir, const char *oldName, void *_newDir, const char *newName) +{ + FUNCTION_START(("oldDir = %p, oldName = \"%s\", newDir = %p, newName = \"%s\"\n",_oldDir,oldName,_newDir,newName)); + + // there may be some more tests needed?! + if (_ns == NULL || _oldDir == NULL || _newDir == NULL + || oldName == NULL || *oldName == '\0' + || newName == NULL || *newName == '\0' + || !strcmp(oldName,".") || !strcmp(oldName,"..") + || !strcmp(newName,".") || !strcmp(newName,"..")) + RETURN_ERROR(B_BAD_VALUE); + + Volume *volume = (Volume *)_ns; + Inode *oldDirectory = (Inode *)_oldDir; + Inode *newDirectory = (Inode *)_newDir; + + // get the directory's tree, and a pointer to the inode which should be changed + BPlusTree *tree; + status_t status = oldDirectory->GetTree(&tree); + if (status < B_OK) + RETURN_ERROR(status); + + off_t id; + status = tree->Find((const uint8 *)oldName,strlen(oldName),&id); + if (status < B_OK) + RETURN_ERROR(status); + + Vnode vnode(volume,id); + Inode *inode; + if (vnode.Get(&inode) < B_OK) + return B_IO_ERROR; + + // Don't move a directory into one of its children - we soar up + // from the newDirectory to either the root node or the old + // directory, whichever comes first. + // If we meet our inode on that way, we have to bail out. + + if (oldDirectory != newDirectory) { + vnode_id parent = volume->ToVnode(newDirectory->Parent()); + vnode_id root = volume->RootNode()->ID(); + while (true) + { + if (parent == id) + return B_BAD_VALUE; + else if (parent == root || parent == oldDirectory->ID()) + break; + + Vnode vnode(volume,parent); + Inode *parentNode; + if (vnode.Get(&parentNode) < B_OK) + return B_ERROR; + + parent = volume->ToVnode(parentNode->Parent()); + } + } + + // Everything okay? Then lets get to work... + + Transaction transaction(volume,oldDirectory->BlockNumber()); + + // First, try to make sure there is nothing that will stop us in + // the target directory - since this is the only non-critical + // failure, we will test this case first + BPlusTree *newTree = tree; + if (newDirectory != oldDirectory) { + status = newDirectory->GetTree(&newTree); + if (status < B_OK) + RETURN_ERROR(status); + } + + status = newTree->Insert(&transaction,(const uint8 *)newName,strlen(newName),id); + if (status == B_NAME_IN_USE) { + // If there is already a file with that name, we have to remove + // it, as long it's not a directory with files in it + off_t clobber; + if (newTree->Find((const uint8 *)newName,strlen(newName),&clobber) < B_OK) + return B_NAME_IN_USE; + if (clobber == id) + return B_BAD_VALUE; + + Vnode vnode(volume,clobber); + Inode *other; + if (vnode.Get(&other) < B_OK) + return B_NAME_IN_USE; + + status = newDirectory->Remove(&transaction,newName,NULL,other->IsDirectory()); + if (status < B_OK) + return status; + + notify_listener(B_ENTRY_REMOVED,volume->ID(),newDirectory->ID(),0,clobber,NULL); + + status = newTree->Insert(&transaction,(const uint8 *)newName,strlen(newName),id); + } + if (status < B_OK) + return status; + + // If anything fails now, we have to remove the inode from the + // new directory in any case to restore the previous state + status_t bailStatus = B_OK; + + // update the name only when they differ + bool nameUpdated = false; + if (strcmp(oldName,newName)) { + status = inode->SetName(&transaction,newName); + if (status == B_OK) { + Index index(volume); + index.UpdateName(&transaction,oldName,newName,inode); + nameUpdated = true; + } + } + + if (status == B_OK) { + status = tree->Remove(&transaction,(const uint8 *)oldName,strlen(oldName),id); + if (status == B_OK) { + inode->Node()->parent = newDirectory->BlockRun(); + + // if it's a directory, update the parent directory pointer + // in its tree if necessary + BPlusTree *movedTree = NULL; + if (oldDirectory != newDirectory + && inode->IsDirectory() + && (status = inode->GetTree(&movedTree)) == B_OK) + status = movedTree->Replace(&transaction,(const uint8 *)"..",2,newDirectory->ID()); + + if (status == B_OK) { + status = inode->WriteBack(&transaction); + if (status == B_OK) { + transaction.Done(); + + notify_listener(B_ENTRY_MOVED,volume->ID(),oldDirectory->ID(),newDirectory->ID(),id,newName); + return B_OK; + } + } + // Those better don't fail, or we switch to a read-only + // device for safety reasons (Volume::Panic() does this + // for us) + // Anyway, if we overwrote a file in the target directory + // this is lost now (only in-memory, not on-disk)... + bailStatus = tree->Insert(&transaction,(const uint8 *)oldName,strlen(oldName),id); + if (movedTree != NULL) + movedTree->Replace(&transaction,(const uint8 *)"..",2,oldDirectory->ID()); + } + } + if (bailStatus == B_OK && nameUpdated) + bailStatus = inode->SetName(&transaction,oldName); + + if (bailStatus == B_OK) + bailStatus = newTree->Remove(&transaction,(const uint8 *)newName,strlen(newName),id); + + if (bailStatus < B_OK) + volume->Panic(); + + return status; +} + + +/** Opens the file with the specified mode. + */ + +static int +bfs_open(void *_ns, void *_node, int omode, void **_cookie) +{ + FUNCTION(); + if (_ns == NULL || _node == NULL || _cookie == NULL) + RETURN_ERROR(B_BAD_VALUE); + + Volume *volume = (Volume *)_ns; + Inode *inode = (Inode *)_node; + + // opening a directory read-only is allowed, although you can't read + // any data from it. + if (inode->IsDirectory() && omode & O_RWMASK) { + omode = omode & ~O_RWMASK; + // ToDo: for compatibility reasons, we don't return an error here... + // e.g. "copyattr" tries to do that + //return B_IS_A_DIRECTORY; + } + + status_t status = inode->CheckPermissions(oModeToAccess(omode)); + if (status < B_OK) + RETURN_ERROR(status); + + // we could actually use the cookie to keep track of: + // - the last block_run + // - the location in the data_stream (indirect, double indirect, + // position in block_run array) + // + // This could greatly speed up continuous reads of big files, especially + // in the indirect block section. + + file_cookie *cookie = (file_cookie *)malloc(sizeof(file_cookie)); + if (cookie == NULL) + RETURN_ERROR(B_NO_MEMORY); + + // initialize the cookie + cookie->open_mode = omode; + // needed by e.g. bfs_write() for O_APPEND + cookie->last_size = inode->Size(); + cookie->last_notification = system_time(); + + // Should we truncate the file? + if (omode & O_TRUNC) { + Transaction transaction(volume,inode->BlockNumber()); + WriteLocked locked(inode->Lock()); + + status_t status = inode->SetFileSize(&transaction,0); + if (status < B_OK) { + // bfs_free_cookie() is only called if this function is successful + free(cookie); + return status; + } + + transaction.Done(); + } + + *_cookie = cookie; + return B_OK; +} + + +/** Read a file specified by node, using information in cookie + * and at offset specified by pos. read len bytes into buffer buf. + */ + +static int +bfs_read(void *_ns, void *_node, void *_cookie, off_t pos, void *buffer, size_t *_length) +{ + //FUNCTION(); + Inode *inode = (Inode *)_node; + + if (!inode->HasUserAccessableStream()) { + *_length = 0; + RETURN_ERROR(B_BAD_VALUE); + } + + ReadLocked locked(inode->Lock()); + return inode->ReadAt(pos,(uint8 *)buffer,_length); +} + + +int +bfs_write(void *_ns, void *_node, void *_cookie, off_t pos, const void *buffer, size_t *_length) +{ + //FUNCTION(); + // uncomment to be more robust against a buggy vnode layer ;-) + //if (_ns == NULL || _node == NULL || _cookie == NULL) + // return B_BAD_VALUE; + + Volume *volume = (Volume *)_ns; + Inode *inode = (Inode *)_node; + + if (!inode->HasUserAccessableStream()) { + *_length = 0; + RETURN_ERROR(B_BAD_VALUE); + } + + file_cookie *cookie = (file_cookie *)_cookie; + + if (cookie->open_mode & O_APPEND) + pos = inode->Size(); + + WriteLocked locked(inode->Lock()); + if (locked.IsLocked() < B_OK) + RETURN_ERROR(B_ERROR); + + Transaction transaction; + // We are not starting the transaction here, since + // it might not be needed at all + + status_t status = inode->WriteAt(&transaction,pos,(const uint8 *)buffer,_length); + + if (status == B_OK) + transaction.Done(); + + // periodically notify if the file size has changed + if (cookie->last_size != inode->Size() + && system_time() > cookie->last_notification + INODE_NOTIFICATION_INTERVAL) { + notify_listener(B_STAT_CHANGED,volume->ID(),0,0,inode->ID(),NULL); + cookie->last_size = inode->Size(); + cookie->last_notification = system_time(); + } + + // This will flush the dirty blocks to disk from time to time. + // It's done here and not in Inode::WriteAt() so that it won't + // add to the duration of a transaction - it might even be a + // good idea to offload those calls to another thread + volume->WriteCachedBlocksIfNecessary(); + + return status; +} + + +/** Do whatever is necessary to close a file, EXCEPT for freeing + * the cookie! + */ + +static int +bfs_close(void *_ns, void *_node, void *_cookie) +{ + FUNCTION(); + if (_ns == NULL || _node == NULL || _cookie == NULL) + return B_BAD_VALUE; + + file_cookie *cookie = (file_cookie *)_cookie; + + if (cookie->open_mode & O_RWMASK) { + // trim the preallocated blocks and update the size, + // and last_modified indices if needed + Volume *volume = (Volume *)_ns; + Inode *inode = (Inode *)_node; + + Transaction transaction(volume,inode->BlockNumber()); + + status_t status = inode->Trim(&transaction); + if (status < B_OK) + FATAL(("Could not trim preallocated blocks!")); + + Index index(volume); + index.UpdateSize(&transaction,inode); + index.UpdateLastModified(&transaction,inode); + + if (status == B_OK) + transaction.Done(); + + notify_listener(B_STAT_CHANGED,volume->ID(),0,0,inode->ID(),NULL); + } + + return B_OK; +} + + +static int +bfs_free_cookie(void * /*ns*/, void * /*node*/, void *cookie) +{ + FUNCTION(); + + if (cookie != NULL) + free(cookie); + + return B_OK; +} + + +/** Checks access permissions, return B_NOT_ALLOWED if the action + * is not allowed. + */ + +static int +bfs_access(void *_ns, void *_node, int accessMode) +{ + FUNCTION(); + + if (_ns == NULL || _node == NULL) + return B_BAD_VALUE; + + Inode *inode = (Inode *)_node; + status_t status = inode->CheckPermissions(accessMode); + if (status < B_OK) + RETURN_ERROR(status); + + return B_OK; +} + + +static int +bfs_read_link(void *_ns, void *_node, char *buffer, size_t *bufferSize) +{ + FUNCTION(); + + Inode *inode = (Inode *)_node; + + if (!inode->IsSymLink()) + RETURN_ERROR(B_BAD_VALUE); + + if (inode->Flags() & INODE_LONG_SYMLINK) { + status_t status = inode->ReadAt(0, (uint8 *)buffer, bufferSize); + if (status < B_OK) + RETURN_ERROR(status); + + *bufferSize = inode->Size(); + return B_OK; + } + + size_t numBytes = strlen((char *)&inode->Node()->short_symlink); + uint32 bytes = numBytes; + if (bytes > *bufferSize) + bytes = *bufferSize; + + memcpy(buffer, inode->Node()->short_symlink, bytes); + *bufferSize = numBytes; + + return B_OK; +} + + +// #pragma mark - +// Directory functions + + +int +bfs_mkdir(void *_ns, void *_directory, const char *name, int mode) +{ + FUNCTION_START(("name = \"%s\", perms = %ld\n",name,mode)); + + if (_ns == NULL || _directory == NULL + || name == NULL || *name == '\0') + RETURN_ERROR(B_BAD_VALUE); + + Volume *volume = (Volume *)_ns; + Inode *directory = (Inode *)_directory; + + if (!directory->IsDirectory()) + RETURN_ERROR(B_BAD_TYPE); + + status_t status = directory->CheckPermissions(W_OK); + if (status < B_OK) + RETURN_ERROR(status); + + Transaction transaction(volume,directory->BlockNumber()); + + // Inode::Create() locks the inode if we pass the "id" parameter, but we + // need it anyway + off_t id; + status = Inode::Create(&transaction,directory,name,S_DIRECTORY | (mode & S_IUMSK),0,0,&id); + if (status == B_OK) { + put_vnode(volume->ID(),id); + transaction.Done(); + + notify_listener(B_ENTRY_CREATED,volume->ID(),directory->ID(),0,id,name); + } + + return status; +} + + +int +bfs_rmdir(void *_ns, void *_directory, const char *name) +{ + FUNCTION_START(("name = \"%s\"\n",name)); + + if (_ns == NULL || _directory == NULL || name == NULL || *name == '\0') + return B_BAD_VALUE; + + Volume *volume = (Volume *)_ns; + Inode *directory = (Inode *)_directory; + + Transaction transaction(volume,directory->BlockNumber()); + + off_t id; + status_t status = directory->Remove(&transaction,name,&id,true); + if (status == B_OK) { + transaction.Done(); + + notify_listener(B_ENTRY_REMOVED,volume->ID(),directory->ID(),0,id,NULL); + } + + return status; +} + + +/** creates fs-specific "cookie" struct that keeps track of where + * you are at in reading through directory entries in bfs_readdir. + */ + +static int +bfs_open_dir(void *_ns, void *_node, void **_cookie) +{ + FUNCTION(); + + if (_ns == NULL || _node == NULL || _cookie == NULL) + RETURN_ERROR(B_BAD_VALUE); + + Inode *inode = (Inode *)_node; + + if (!inode->IsDirectory()) + RETURN_ERROR(B_BAD_VALUE); + + BPlusTree *tree; + if (inode->GetTree(&tree) != B_OK) + RETURN_ERROR(B_BAD_VALUE); + + TreeIterator *iterator = new TreeIterator(tree); + if (iterator == NULL) + RETURN_ERROR(B_NO_MEMORY); + + *_cookie = iterator; + return B_OK; +} + + +static int +bfs_read_dir(void *_ns, void *_node, void *_cookie, long *num, + struct dirent *dirent, size_t bufferSize) +{ + FUNCTION(); + + TreeIterator *iterator = (TreeIterator *)_cookie; + if (iterator == NULL) + RETURN_ERROR(B_BAD_VALUE); + + uint16 length; + vnode_id id; + status_t status = iterator->GetNextEntry(dirent->d_name,&length,bufferSize,&id); + if (status == B_ENTRY_NOT_FOUND) { + *num = 0; + return B_OK; + } else if (status != B_OK) + RETURN_ERROR(status); + + Volume *volume = (Volume *)_ns; + + dirent->d_dev = volume->ID(); + dirent->d_ino = id; + dirent->d_reclen = length; + + *num = 1; + return B_OK; +} + + +/** Sets the TreeIterator back to the beginning of the directory + */ + +static int +bfs_rewind_dir(void * /*ns*/, void * /*node*/, void *_cookie) +{ + FUNCTION(); + TreeIterator *iterator = (TreeIterator *)_cookie; + + if (iterator == NULL) + RETURN_ERROR(B_BAD_VALUE); + + return iterator->Rewind(); +} + + +static int +bfs_close_dir(void * /*ns*/, void * /*node*/, void * /*_cookie*/) +{ + FUNCTION(); + // Do whatever you need to to close a directory, but DON'T free the cookie! + return B_OK; +} + + +static int +bfs_free_dir_cookie(void *ns, void *node, void *_cookie) +{ + TreeIterator *iterator = (TreeIterator *)_cookie; + + if (iterator == NULL) + RETURN_ERROR(B_BAD_VALUE); + + delete iterator; + return B_OK; +} + + +// #pragma mark - +// Attribute functions + + +int +bfs_open_attrdir(void *_ns, void *_node, void **cookie) +{ + FUNCTION(); + + Inode *inode = (Inode *)_node; + if (inode == NULL || inode->Node() == NULL) + RETURN_ERROR(B_ERROR); + + AttributeIterator *iterator = new AttributeIterator(inode); + if (iterator == NULL) + RETURN_ERROR(B_NO_MEMORY); + + *cookie = iterator; + return B_OK; +} + + +int +bfs_close_attrdir(void *ns, void *node, void *cookie) +{ + FUNCTION(); + return B_OK; +} + + +int +bfs_free_attrdir_cookie(void *ns, void *node, void *_cookie) +{ + FUNCTION(); + AttributeIterator *iterator = (AttributeIterator *)_cookie; + + if (iterator == NULL) + RETURN_ERROR(B_BAD_VALUE); + + delete iterator; + return B_OK; +} + + +int +bfs_rewind_attrdir(void *_ns, void *_node, void *_cookie) +{ + FUNCTION(); + + AttributeIterator *iterator = (AttributeIterator *)_cookie; + if (iterator == NULL) + RETURN_ERROR(B_BAD_VALUE); + + RETURN_ERROR(iterator->Rewind()); +} + + +int +bfs_read_attrdir(void *_ns, void *node, void *_cookie, long *num, struct dirent *dirent, size_t bufsize) +{ + FUNCTION(); + AttributeIterator *iterator = (AttributeIterator *)_cookie; + + if (iterator == NULL) + RETURN_ERROR(B_BAD_VALUE); + + uint32 type; + size_t length; + status_t status = iterator->GetNext(dirent->d_name,&length,&type,&dirent->d_ino); + if (status == B_ENTRY_NOT_FOUND) { + *num = 0; + return B_OK; + } else if (status != B_OK) + RETURN_ERROR(status); + + Volume *volume = (Volume *)_ns; + + dirent->d_dev = volume->ID(); + dirent->d_reclen = length; + + *num = 1; + return B_OK; +} + + +int +bfs_remove_attr(void *_ns, void *_node, const char *name) +{ + FUNCTION_START(("name = \"%s\"\n",name)); + + if (_ns == NULL || _node == NULL || name == NULL) + return B_BAD_VALUE; + + Volume *volume = (Volume *)_ns; + Inode *inode = (Inode *)_node; + + status_t status = inode->CheckPermissions(W_OK); + if (status < B_OK) + return status; + + Transaction transaction(volume,inode->BlockNumber()); + + status = inode->RemoveAttribute(&transaction,name); + if (status == B_OK) { + transaction.Done(); + + notify_listener(B_ATTR_CHANGED,volume->ID(),0,0,inode->ID(),name); + } + + RETURN_ERROR(status); +} + + +int +bfs_rename_attr(void *ns, void *node, const char *oldname,const char *newname) +{ + FUNCTION_START(("name = \"%s\",to = \"%s\"\n",oldname,newname)); + + // ToDo: implement bfs_rename_attr()! + // Does anybody need this? :-) + + RETURN_ERROR(B_ENTRY_NOT_FOUND); +} + + +int +bfs_stat_attr(void *ns, void *_node, const char *name,struct attr_info *attrInfo) +{ + FUNCTION_START(("name = \"%s\"\n",name)); + + Inode *inode = (Inode *)_node; + if (inode == NULL || inode->Node() == NULL) + RETURN_ERROR(B_ERROR); + + small_data *smallData = NULL; + if (inode->SmallDataLock().Lock() == B_OK) + { + if ((smallData = inode->FindSmallData((const char *)name)) != NULL) { + attrInfo->type = smallData->type; + attrInfo->size = smallData->data_size; + } + inode->SmallDataLock().Unlock(); + } + if (smallData != NULL) + return B_OK; + + // search in the attribute directory + Inode *attribute; + status_t status = inode->GetAttribute(name,&attribute); + if (status == B_OK) { + attrInfo->type = attribute->Node()->type; + attrInfo->size = attribute->Node()->data.size; + + inode->ReleaseAttribute(attribute); + return B_OK; + } + + RETURN_ERROR(status); +} + + +int +bfs_write_attr(void *_ns, void *_node, const char *name, int type,const void *buffer, size_t *_length, off_t pos) +{ + FUNCTION_START(("name = \"%s\"\n",name)); + + if (_ns == NULL || _node == NULL || name == NULL || *name == '\0') + RETURN_ERROR(B_BAD_VALUE); + + // Writing the name attribute using this function is not allowed, + // also using the reserved indices name, last_modified, and size + // shouldn't be allowed. + if (name[0] == FILE_NAME_NAME && name[1] == '\0' + || !strcmp(name,"name") + || !strcmp(name,"last_modified") + || !strcmp(name,"size")) + RETURN_ERROR(B_NOT_ALLOWED); + + Volume *volume = (Volume *)_ns; + Inode *inode = (Inode *)_node; + + status_t status = inode->CheckPermissions(W_OK); + if (status < B_OK) + return status; + + Transaction transaction(volume,inode->BlockNumber()); + + status = inode->WriteAttribute(&transaction,name,type,pos,(const uint8 *)buffer,_length); + if (status == B_OK) { + transaction.Done(); + + notify_listener(B_ATTR_CHANGED,volume->ID(),0,0,inode->ID(),name); + } + + return status; +} + + +int +bfs_read_attr(void *_ns, void *_node, const char *name, int type,void *buffer, size_t *_length, off_t pos) +{ + FUNCTION(); + Inode *inode = (Inode *)_node; + + if (inode == NULL || name == NULL || *name == '\0' || buffer == NULL) + RETURN_ERROR(B_BAD_VALUE); + + status_t status = inode->CheckPermissions(R_OK); + if (status < B_OK) + return status; + + return inode->ReadAttribute(name,type,pos,(uint8 *)buffer,_length); +} + + +// #pragma mark - +// Index functions + + +int +bfs_open_indexdir(void *_ns, void **_cookie) +{ + FUNCTION(); + + if (_ns == NULL || _cookie == NULL) + RETURN_ERROR(B_BAD_VALUE); + + Volume *volume = (Volume *)_ns; + + if (volume->IndicesNode() == NULL) + RETURN_ERROR(B_ENTRY_NOT_FOUND); + + // Since the indices root node is just a directory, and we are storing + // a pointer to it in our Volume object, we can just use the directory + // traversal functions. + // In fact we're storing it in the Volume object for that reason. + + RETURN_ERROR(bfs_open_dir(_ns,volume->IndicesNode(),_cookie)); +} + + +int +bfs_close_indexdir(void *_ns, void *_cookie) +{ + FUNCTION(); + if (_ns == NULL || _cookie == NULL) + RETURN_ERROR(B_BAD_VALUE); + + Volume *volume = (Volume *)_ns; + RETURN_ERROR(bfs_close_dir(_ns,volume->IndicesNode(),_cookie)); +} + + +int +bfs_free_indexdir_cookie(void *_ns, void *_node, void *_cookie) +{ + FUNCTION(); + if (_ns == NULL || _cookie == NULL) + RETURN_ERROR(B_BAD_VALUE); + + Volume *volume = (Volume *)_ns; + RETURN_ERROR(bfs_free_dir_cookie(_ns,volume->IndicesNode(),_cookie)); +} + + +int +bfs_rewind_indexdir(void *_ns, void *_cookie) +{ + FUNCTION(); + if (_ns == NULL || _cookie == NULL) + RETURN_ERROR(B_BAD_VALUE); + + Volume *volume = (Volume *)_ns; + RETURN_ERROR(bfs_rewind_dir(_ns,volume->IndicesNode(),_cookie)); +} + + +int +bfs_read_indexdir(void *_ns, void *_cookie, long *num, struct dirent *dirent, size_t bufferSize) +{ + FUNCTION(); + if (_ns == NULL || _cookie == NULL) + RETURN_ERROR(B_BAD_VALUE); + + Volume *volume = (Volume *)_ns; + RETURN_ERROR(bfs_read_dir(_ns,volume->IndicesNode(),_cookie,num,dirent,bufferSize)); +} + + +int +bfs_create_index(void *_ns, const char *name, int type, int flags) +{ + FUNCTION_START(("name = \"%s\", type = %ld, flags = %ld\n",name,type,flags)); + if (_ns == NULL || name == NULL || *name == '\0') + return B_BAD_VALUE; + + Volume *volume = (Volume *)_ns; + + if (volume->IsReadOnly()) + return B_READ_ONLY_DEVICE; + + // only root users are allowed to create indices + if (geteuid() != 0) + return B_NOT_ALLOWED; + + Transaction transaction(volume,volume->Indices()); + + Index index(volume); + status_t status = index.Create(&transaction,name,type); + + if (status == B_OK) + transaction.Done(); + + RETURN_ERROR(status); +} + + +int +bfs_remove_index(void *_ns, const char *name) +{ + FUNCTION(); + if (_ns == NULL || name == NULL || *name == '\0') + return B_BAD_VALUE; + + Volume *volume = (Volume *)_ns; + + if (volume->IsReadOnly()) + return B_READ_ONLY_DEVICE; + + // only root users are allowed to remove indices + if (geteuid() != 0) + return B_NOT_ALLOWED; + + Inode *indices; + if ((indices = volume->IndicesNode()) == NULL) + return B_ENTRY_NOT_FOUND; + + Transaction transaction(volume,volume->Indices()); + + status_t status = indices->Remove(&transaction,name); + if (status == B_OK) + transaction.Done(); + + RETURN_ERROR(status); +} + + +int +bfs_rename_index(void *ns, const char *oldname, const char *newname) +{ + FUNCTION_START(("from = %s, to = %s\n",oldname,newname)); + + // ToDo: implement bfs_rename_index()?! + // Well, renaming an index doesn't make that much sense, as you + // would also need to remove every file in it (or the index + // would contain wrong data) + // But in that case, you can better remove the old one, and + // create a new one... + // There is also no way to call this function from a userland + // application. + + RETURN_ERROR(B_ENTRY_NOT_FOUND); +} + + +int +bfs_stat_index(void *_ns, const char *name, struct index_info *indexInfo) +{ + FUNCTION_START(("name = %s\n",name)); + if (_ns == NULL || name == NULL || indexInfo == NULL) + RETURN_ERROR(B_BAD_VALUE); + + Volume *volume = (Volume *)_ns; + Index index(volume); + status_t status = index.SetTo(name); + if (status < B_OK) + RETURN_ERROR(status); + + bfs_inode *node = index.Node()->Node(); + + indexInfo->type = index.Type(); + indexInfo->size = node->data.size; + indexInfo->modification_time = (time_t)(node->last_modified_time >> INODE_TIME_SHIFT); + indexInfo->creation_time = (time_t)(node->create_time >> INODE_TIME_SHIFT); + indexInfo->uid = node->uid; + indexInfo->gid = node->gid; + + return B_OK; +} + + +// #pragma mark - +// Query functions + + +int +bfs_open_query(void *_ns,const char *queryString,ulong flags,port_id port,long token,void **cookie) +{ + FUNCTION(); + if (_ns == NULL || queryString == NULL || cookie == NULL) + RETURN_ERROR(B_BAD_VALUE); + + PRINT(("query = \"%s\", flags = %lu, port_id = %ld, token = %ld\n",queryString,flags,port,token)); + + Volume *volume = (Volume *)_ns; + + Expression *expression = new Expression((char *)queryString); + if (expression == NULL) + RETURN_ERROR(B_NO_MEMORY); + + if (expression->InitCheck() < B_OK) { + FATAL(("Could not parse query, stopped at: \"%s\"\n",expression->Position())); + delete expression; + RETURN_ERROR(B_BAD_VALUE); + } + + Query *query = new Query(volume,expression); + if (query == NULL) { + delete expression; + RETURN_ERROR(B_NO_MEMORY); + } + + if (flags & B_LIVE_QUERY) + query->SetLiveMode(port,token); + + *cookie = (void *)query; + + return B_OK; +} + + +int +bfs_close_query(void *ns, void *cookie) +{ + FUNCTION(); + return B_OK; +} + + +int +bfs_free_query_cookie(void *ns, void *node, void *cookie) +{ + FUNCTION(); + if (cookie == NULL) + RETURN_ERROR(B_BAD_VALUE); + + Query *query = (Query *)cookie; + Expression *expression = query->GetExpression(); + delete query; + delete expression; + + return B_OK; +} + + +int +bfs_read_query(void */*ns*/,void *cookie,long *num,struct dirent *dirent,size_t bufferSize) +{ + FUNCTION(); + Query *query = (Query *)cookie; + if (query == NULL) + RETURN_ERROR(B_BAD_VALUE); + + status_t status = query->GetNextEntry(dirent,bufferSize); + if (status == B_OK) + *num = 1; + else if (status == B_ENTRY_NOT_FOUND) + *num = 0; + else + return status; + + return B_OK; +} + diff --git a/src/add-ons/kernel/file_systems/befs/lock.h b/src/add-ons/kernel/file_systems/befs/lock.h new file mode 100644 index 0000000000..b05adaa21b --- /dev/null +++ b/src/add-ons/kernel/file_systems/befs/lock.h @@ -0,0 +1,47 @@ +/* + Copyright 1999-2001, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. +*/ + +#ifndef _LOCK_H +#define _LOCK_H + +#include + +#include + +#ifdef __cplusplus + extern "C" { +#else + typedef struct lock lock; + typedef struct mlock mlock; +#endif + + +struct lock { + sem_id s; + long c; +}; + +struct mlock { + sem_id s; +}; + +extern _IMPEXP_KERNEL int new_lock(lock *l, const char *name); +extern _IMPEXP_KERNEL int free_lock(lock *l); + +#define LOCK(l) if (atomic_add(&l.c, -1) <= 0) acquire_sem(l.s); +#define UNLOCK(l) if (atomic_add(&l.c, 1) < 0) release_sem(l.s); + +extern _IMPEXP_KERNEL int new_mlock(mlock *l, long c, const char *name); +extern _IMPEXP_KERNEL int free_mlock(mlock *l); + +#define LOCKM(l,cnt) acquire_sem_etc(l.s, cnt, 0, 0) +#define UNLOCKM(l,cnt) release_sem_etc(l.s, cnt, 0) + + +#ifdef __cplusplus + } // extern "C" +#endif + +#endif diff --git a/src/add-ons/print/drivers/canon_lips/libprint/AboutBox.cpp b/src/add-ons/print/drivers/canon_lips/libprint/AboutBox.cpp new file mode 100644 index 0000000000..d94d716c74 --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/AboutBox.cpp @@ -0,0 +1,107 @@ +/* + * AboutBox.cpp + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#include +#include + +#include +#include +#include + +#include "AboutBox.h" + +#if (!__MWERKS__ || defined(MSIPL_USING_NAMESPACE)) +using namespace std; +#else +#define std +#endif + +class AboutBoxView : public BView { +public: + AboutBoxView(BRect frame, const char *driver_name, const char *version, const char *copyright); + virtual void Draw(BRect); + virtual void AttachedToWindow(); + +private: + string __driver_name; + string __version; + string __copyright; +}; + +AboutBoxView::AboutBoxView(BRect rect, const char *driver_name, const char *version, const char *copyright) + : BView(rect, "", B_FOLLOW_ALL, B_WILL_DRAW) +{ + __driver_name = driver_name; + __version = version; + __copyright = copyright; + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + SetDrawingMode(B_OP_SELECT); +} + +void AboutBoxView::Draw(BRect) +{ + SetHighColor(0, 0, 0); + DrawString(__driver_name.c_str(), BPoint(10.0f, 16.0f)); + DrawString(" Driver for "); + SetHighColor(0, 0, 0xff); + DrawString("B"); + SetHighColor(0xff, 0, 0); + DrawString("e"); + SetHighColor(0, 0, 0); + DrawString("OS Version "); + DrawString(__version.c_str()); + DrawString(__copyright.c_str(), BPoint(10.0f, 30.0f)); +} + +#define M_OK 1 + +void AboutBoxView::AttachedToWindow() +{ + BRect rect; + rect.Set(110, 50, 175, 55); + BButton *button = new BButton(rect, "", "OK", new BMessage(M_OK)); + AddChild(button); + button->MakeDefault(true); +} + +class AboutBoxWindow : public BWindow { +public: + AboutBoxWindow(BRect frame, const char *driver_name, const char *version, const char *copyright); + virtual void MessageReceived(BMessage *msg); + virtual bool QuitRequested(); +}; + +AboutBoxWindow::AboutBoxWindow(BRect frame, const char *driver_name, const char *version, const char *copyright) + : BWindow(frame, "", B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE ) +{ + char title[256]; + sprintf(title, "About %s Driver", driver_name); + SetTitle(title); + AddChild(new AboutBoxView(Bounds(), driver_name, version, copyright)); +} + +void AboutBoxWindow::MessageReceived(BMessage *msg) +{ + switch (msg->what) { + case M_OK: + be_app->PostMessage(B_QUIT_REQUESTED); + break; + } +} + +bool AboutBoxWindow::QuitRequested() +{ + be_app->PostMessage(B_QUIT_REQUESTED); + return true; +} + +AboutBox::AboutBox(const char *signature, const char *driver_name, const char *version, const char *copyright) + : BApplication(signature) +{ + BRect rect; + rect.Set(100, 80, 400, 170); + AboutBoxWindow *window = new AboutBoxWindow(rect, driver_name, version, copyright); + window->Show(); +} diff --git a/src/add-ons/print/drivers/canon_lips/libprint/AboutBox.h b/src/add-ons/print/drivers/canon_lips/libprint/AboutBox.h new file mode 100644 index 0000000000..be7d88189b --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/AboutBox.h @@ -0,0 +1,16 @@ +/* + * AboutBox.h + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#ifndef __ABOUTBOX_H +#define __ABOUTBOX_H + +#include + +class AboutBox : public BApplication { +public: + AboutBox(const char *signature, const char *driver_name, const char *version, const char *copyright); +}; + +#endif /* __ABOUTBOX_H */ diff --git a/src/add-ons/print/drivers/canon_lips/libprint/DbgMsg.cpp b/src/add-ons/print/drivers/canon_lips/libprint/DbgMsg.cpp new file mode 100644 index 0000000000..39825fb4d5 --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/DbgMsg.cpp @@ -0,0 +1,237 @@ +/* + * DbgMsg.cpp + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#include +#include + +#include +#include +#include +#include + +#include "DbgMsg.h" + +#ifdef DBG + +#if (!__MWERKS__ || defined(MSIPL_USING_NAMESPACE)) +using namespace std; +#else +#define std +#endif + +void write_debug_stream(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + FILE *f = fopen("/boot/home/libprint.log", "aw+"); + vfprintf(f, format, ap); + fclose(f); + va_end(ap); +} + + +void DUMP_BFILE(BFile *in, const char *path) +{ + off_t size; + if (B_NO_ERROR == in->GetSize(&size)) { + uchar *buffer = new uchar[size]; + in->Read(buffer, size); + BFile out(path, B_WRITE_ONLY | B_CREATE_FILE); + out.Write(buffer, size); + in->Seek(0, SEEK_SET); + delete [] buffer; + } +} + + +void DUMP_BMESSAGE(BMessage *msg) +{ + uint32 i; + int32 j; + char *name = ""; + uint32 type = 0; + int32 count = 0; + + DBGMSG(("\t************ START - DUMP BMessage ***********\n")); + DBGMSG(("\taddress: 0x%x\n", (int)msg)); + if (!msg) + return; + +// DBGMSG(("\tmsg->what: 0x%x\n", msg->what)); + DBGMSG(("\tmsg->what: %c%c%c%c\n", + *((char *)&msg->what + 3), + *((char *)&msg->what + 2), + *((char *)&msg->what + 1), + *((char *)&msg->what + 0))); + + for (i= 0; msg->GetInfo(B_ANY_TYPE, i, &name, &type, &count) == B_OK; i++) { + switch (type) { + case B_BOOL_TYPE: + for (j = 0; j < count; j++) { + bool aBool; + aBool = msg->FindBool(name, j); + DBGMSG(("\t%s, B_BOOL_TYPE[%d]: %s\n", + name, j, aBool ? "true" : "false")); + } + break; + + case B_INT8_TYPE: + for (j = 0; j < count; j++) { + int8 anInt8; + msg->FindInt8(name, j, &anInt8); + DBGMSG(("\t%s, B_INT8_TYPE[%d]: %d\n", name, j, (int)anInt8)); + } + break; + + case B_INT16_TYPE: + for (j = 0; j < count; j++) { + int16 anInt16; + msg->FindInt16(name, j, &anInt16); + DBGMSG(("\t%s, B_INT16_TYPE[%d]: %d\n", name, j, (int)anInt16)); + } + break; + + case B_INT32_TYPE: + for (j = 0; j < count; j++) { + int32 anInt32; + msg->FindInt32(name, j, &anInt32); + DBGMSG(("\t%s, B_INT32_TYPE[%d]: %d\n", name, j, (int)anInt32)); + } + break; + + case B_INT64_TYPE: + for (j = 0; j < count; j++) { + int64 anInt64; + msg->FindInt64(name, j, &anInt64); + DBGMSG(("\t%s, B_INT64_TYPE[%d]: %d\n", name, j, (int)anInt64)); + } + break; + + case B_FLOAT_TYPE: + for (j = 0; j < count; j++) { + float aFloat; + msg->FindFloat(name, j, &aFloat); + DBGMSG(("\t%s, B_FLOAT_TYPE[%d]: %f\n", name, j, aFloat)); + } + break; + + case B_DOUBLE_TYPE: + for (j = 0; j < count; j++) { + double aDouble; + msg->FindDouble(name, j, &aDouble); + DBGMSG(("\t%s, B_DOUBLE_TYPE[%d]: %f\n", name, j, (float)aDouble)); + } + break; + + case B_STRING_TYPE: + for (j = 0; j < count; j++) { + const char *string; + msg->FindString(name, j, &string); + DBGMSG(("\t%s, B_STRING_TYPE[%d]: %s\n", name, j, string)); + } + break; + + case B_POINT_TYPE: + for (j = 0; j < count; j++) { + BPoint aPoint; + msg->FindPoint(name, j, &aPoint); + DBGMSG(("\t%s, B_POINT_TYPE[%d]: %f, %f\n", + name, j, aPoint.x, aPoint.y)); + } + break; + + case B_RECT_TYPE: + for (j = 0; j < count; j++) { + BRect aRect; + msg->FindRect(name, j, &aRect); + DBGMSG(("\t%s, B_RECT_TYPE[%d]: %f, %f, %f, %f\n", + name, j, aRect.left, aRect.top, aRect.right, aRect.bottom)); + } + break; + + case B_REF_TYPE: + case B_MESSAGE_TYPE: + case B_MESSENGER_TYPE: + case B_POINTER_TYPE: + DBGMSG(("\t%s, 0x%x, count: %d\n", + name ? name : "(null)", type, count)); + break; + default: + DBGMSG(("\t%s, 0x%x, count: %d\n", + name ? name : "(null)", type, count)); + break; + } + + name = ""; + type = 0; + count = 0; + } + DBGMSG(("\t************ END - DUMP BMessage ***********\n")); +} + +#define PD_DRIVER_NAME "Driver Name" +#define PD_PRINTER_NAME "Printer Name" +#define PD_COMMENTS "Comments" + +void DUMP_BDIRECTORY(BDirectory *dir) +{ + DUMP_BNODE(dir); +} + +void DUMP_BNODE(BNode *dir) +{ + char buffer1[256]; + char buffer2[256]; + attr_info info; + int32 i; + float f; + BRect rc; + bool b; + + DBGMSG(("\t************ STRAT - DUMP BNode ***********\n")); + + dir->RewindAttrs(); + while (dir->GetNextAttrName(buffer1) == B_NO_ERROR) { + dir->GetAttrInfo(buffer1, &info); + switch (info.type) { + case B_ASCII_TYPE: + dir->ReadAttr(buffer1, info.type, 0, buffer2, sizeof(buffer2)); + DBGMSG(("\t%s, B_ASCII_TYPE: %s\n", buffer1, buffer2)); + break; + case B_STRING_TYPE: + dir->ReadAttr(buffer1, info.type, 0, buffer2, sizeof(buffer2)); + DBGMSG(("\t%s, B_STRING_TYPE: %s\n", buffer1, buffer2)); + break; + case B_INT32_TYPE: + dir->ReadAttr(buffer1, info.type, 0, &i, sizeof(i)); + DBGMSG(("\t%s, B_INT32_TYPE: %d\n", buffer1, i)); + break; + case B_FLOAT_TYPE: + dir->ReadAttr(buffer1, info.type, 0, &f, sizeof(f)); + DBGMSG(("\t%s, B_FLOAT_TYPE: %f\n", buffer1, f)); + break; + case B_RECT_TYPE: + dir->ReadAttr(buffer1, info.type, 0, &rc, sizeof(rc)); + DBGMSG(("\t%s, B_RECT_TYPE: %f, %f, %f, %f\n", buffer1, rc.left, rc.top, rc.right, rc.bottom)); + break; + case B_BOOL_TYPE: + dir->ReadAttr(buffer1, info.type, 0, &b, sizeof(b)); + DBGMSG(("\t%s, B_BOOL_TYPE: %d\n", buffer1, (int)b)); + break; + default: + DBGMSG(("\t%s, %c%c%c%c\n", + buffer1, + *((char *)&info.type + 3), + *((char *)&info.type + 2), + *((char *)&info.type + 1), + *((char *)&info.type + 0))); + break; + } + } + + DBGMSG(("\t************ END - DUMP BNode ***********\n")); +} + +#endif /* DBG */ diff --git a/src/add-ons/print/drivers/canon_lips/libprint/DbgMsg.h b/src/add-ons/print/drivers/canon_lips/libprint/DbgMsg.h new file mode 100644 index 0000000000..fca1ebdc36 --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/DbgMsg.h @@ -0,0 +1,26 @@ +/* + * DbgMsg.h + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#ifndef __DBGMSG_H +#define __DBGMSG_H + +//#define DBG + +#ifdef DBG + void write_debug_stream(const char *, ...); + void DUMP_BFILE(BFile *file, const char *name); + void DUMP_BMESSAGE(BMessage *msg); + void DUMP_BDIRECTORY(BDirectory *dir); + void DUMP_BNODE(BNode *node); + #define DBGMSG(args) write_debug_stream args +#else + #define DUMP_BFILE(file, name) (void)0 + #define DUMP_BMESSAGE(msg) (void)0 + #define DUMP_BDIRECTORY(dir) (void)0 + #define DUMP_BNODE(node) (void)0 + #define DBGMSG(args) (void)0 +#endif + +#endif /* __DBGMSG_H */ diff --git a/src/add-ons/print/drivers/canon_lips/libprint/Exports.h b/src/add-ons/print/drivers/canon_lips/libprint/Exports.h new file mode 100644 index 0000000000..072fb4a70a --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/Exports.h @@ -0,0 +1,22 @@ +/* + * Exports.h + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#ifndef __EXPORTS_H +#define __EXPORTS_H + +#include + +class BNode; +class BMessage; +class BFile; + +extern "C" { + _EXPORT char *add_printer(char *printer_name); + _EXPORT BMessage *config_page(BNode *node, BMessage *msg); + _EXPORT BMessage *config_job(BNode *node, BMessage *msg); + _EXPORT BMessage *take_job(BFile *spool_file, BNode *node, BMessage *msg); +} + +#endif // __EXPORTS_H diff --git a/src/add-ons/print/drivers/canon_lips/libprint/GraphicsDriver.cpp b/src/add-ons/print/drivers/canon_lips/libprint/GraphicsDriver.cpp new file mode 100644 index 0000000000..00be43b732 --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/GraphicsDriver.cpp @@ -0,0 +1,578 @@ +/* + * GraphicsDriver.cpp + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "GraphicsDriver.h" +#include "PrintProcess.h" +#include "JobData.h" +#include "PrinterData.h" +#include "PrinterCap.h" +#include "Preview.h" +#include "Transport.h" +#include "ValidRect.h" +#include "DbgMsg.h" + +#if (!__MWERKS__ || defined(MSIPL_USING_NAMESPACE)) +using namespace std; +#else +#define std +#endif + +GraphicsDriver::GraphicsDriver(BMessage *msg, PrinterData *printer_data, const PrinterCap *printer_cap) + : __msg(msg), __printer_data(printer_data), __printer_cap(printer_cap) +{ + __view = NULL; + __bitmap = NULL; + __transport = NULL; + __org_job_data = NULL; + __real_job_data = NULL; +} + +GraphicsDriver::~GraphicsDriver() +{ +} + +void GraphicsDriver::setupData(BFile *spool_file, long page_count) +{ + BMessage *msg = new BMessage(); + msg->Unflatten(spool_file); + __org_job_data = new JobData(msg, __printer_cap); + DUMP_BMESSAGE(msg); + delete msg; + + __real_job_data = new JobData(*__org_job_data); + BRect rc; + + switch (__org_job_data->getNup()) { + case 2: + case 8: + case 32: + case 128: + rc.left = __org_job_data->getPrintableRect().top; + rc.top = __org_job_data->getPrintableRect().left; + rc.right = __org_job_data->getPrintableRect().bottom; + rc.bottom = __org_job_data->getPrintableRect().right; + __real_job_data->setPrintableRect(rc); + if (JobData::PORTRAIT == __org_job_data->getOrientation()) + __real_job_data->setOrientation(JobData::LANDSCAPE); + else + __real_job_data->setOrientation(JobData::PORTRAIT); + break; + } + + if (__org_job_data->getCollate() && page_count > 1) { + __real_job_data->setCopies(1); + __internal_copies = __org_job_data->getCopies(); + } else { + __internal_copies = 1; + } +} + +void GraphicsDriver::cleanupData() +{ + delete __real_job_data; + delete __org_job_data; + __real_job_data = NULL; + __org_job_data = NULL; +} + +#define MAX_MEMORY_SIZE (4 *1024 *1024) + +void GraphicsDriver::setupBitmap() +{ + __pixel_depth = color_space2pixel_depth(__org_job_data->getSurfaceType()); + + __page_width = (__real_job_data->getPrintableRect().IntegerWidth() * __org_job_data->getXres() + 71) / 72; + __page_height = (__real_job_data->getPrintableRect().IntegerHeight() * __org_job_data->getYres() + 71) / 72; + + int widthByte = (__page_width * __pixel_depth + 7) / 8; + int size = widthByte * __page_height; + + if (size < MAX_MEMORY_SIZE) { + __band_count = 0; + __band_width = __page_width; + __band_height = __page_height; + } else { + __band_count = (size + MAX_MEMORY_SIZE - 1) / MAX_MEMORY_SIZE; + if ((JobData::LANDSCAPE == __real_job_data->getOrientation()) && (__flags & GDF_ROTATE_BAND_BITMAP)) { + __band_width = (__page_width + __band_count - 1) / __band_count; + __band_height = __page_height; + } else { + __band_width = __page_width; + __band_height = (__page_height + __band_count - 1) / __band_count; + } + } + + DBGMSG(("****************\n")); + DBGMSG(("page_width = %d\n", __page_width)); + DBGMSG(("page_height = %d\n", __page_height)); + DBGMSG(("band_count = %d\n", __band_count)); + DBGMSG(("band_height = %d\n", __band_height)); + DBGMSG(("****************\n")); + + BRect rect; + rect.Set(0, 0, __band_width - 1, __band_height - 1); + __bitmap = new BBitmap(rect, __org_job_data->getSurfaceType(), true); + __view = new BView(rect, "", B_FOLLOW_ALL, B_WILL_DRAW); + __bitmap->AddChild(__view); +} + +void GraphicsDriver::cleanupBitmap() +{ + delete __bitmap; + __bitmap = NULL; + __view = NULL; +} + +BPoint get_scale(JobData *org_job_data) +{ + float width; + float height; + BPoint scale; + + scale.x = scale.y = 1.0f; + + switch (org_job_data->getNup()) { + case 1: + scale.x = scale.y = 1.0f; + break; + case 2: /* 1x2 or 2x1 */ + width = org_job_data->getPrintableRect().Width(); + height = org_job_data->getPrintableRect().Height(); + if (width < height) { // portrait + scale.x = height / 2.0f / width; + scale.y = width / height; + } else { // landscape + scale.x = height / width; + scale.y = width / 2.0f / height; + } + break; + case 8: /* 2x4 or 4x2 */ + width = org_job_data->getPrintableRect().Width(); + height = org_job_data->getPrintableRect().Height(); + if (width < height) { + scale.x = height / 4.0f / width; + scale.y = width / height / 2.0f; + } else { + scale.x = height / width / 2.0f; + scale.y = width / 4.0f / height; + } + break; + case 32: /* 4x8 or 8x4 */ + width = org_job_data->getPrintableRect().Width(); + height = org_job_data->getPrintableRect().Height(); + if (width < height) { + scale.x = height / 8.0f / width; + scale.y = width / height / 4.0f; + } else { + scale.x = height / width / 4.0f; + scale.y = width / 8.0f / height; + } + break; + case 4: /* 2x2 */ + scale.x = scale.y = 1.0f / 2.0f; + break; + case 9: /* 3x3 */ + scale.x = scale.y = 1.0f / 3.0f; + break; + case 16: /* 4x4 */ + scale.x = scale.y = 1.0f / 4.0f; + break; + case 25: /* 5x5 */ + scale.x = scale.y = 1.0f / 5.0f; + break; + case 36: /* 6x6 */ + scale.x = scale.y = 1.0f / 6.0f; + break; + case 49: /* 7x7 */ + scale.x = scale.y = 1.0f / 7.0f; + break; + case 64: /* 8x8 */ + scale.x = scale.y = 1.0f / 8.0f; + break; + case 81: /* 9x9 */ + scale.x = scale.y = 1.0f / 9.0f; + break; + case 100: /* 10x10 */ + scale.x = scale.y = 1.0f / 10.0f; + break; + case 121: /* 11x11 */ + scale.x = scale.y = 1.0f / 11.0f; + break; + } + + DBGMSG(("real scale = %f, %f\n", scale.x, scale.y)); + return scale; +} + +BPoint get_offset( + int index, + const BPoint *scale, + JobData *org_job_data) +{ + BPoint offset; + offset.x = 0; + offset.y = 0; + + float width = org_job_data->getPrintableRect().Width(); + float height = org_job_data->getPrintableRect().Height(); + + switch (org_job_data->getNup()) { + case 1: + break; + case 2: + if (index == 1) { + if (JobData::PORTRAIT == org_job_data->getOrientation()) { + offset.x = width; + } else { + offset.y = height; + } + } + break; + case 8: + if (JobData::PORTRAIT == org_job_data->getOrientation()) { + offset.x = width * (index / 2); + offset.y = height * (index % 2); + } else { + offset.x = width * (index % 2); + offset.y = height * (index / 2); + } + break; + case 32: + if (JobData::PORTRAIT == org_job_data->getOrientation()) { + offset.x = width * (index / 4); + offset.y = height * (index % 4); + } else { + offset.x = width * (index % 4); + offset.y = height * (index / 4); + } + break; + case 4: + offset.x = width * (index / 2); + offset.y = height * (index % 2); + break; + case 9: + offset.x = width * (index / 3); + offset.y = height * (index % 3); + break; + case 16: + offset.x = width * (index / 4); + offset.y = height * (index % 4); + break; + case 25: + offset.x = width * (index / 5); + offset.y = height * (index % 5); + break; + case 36: + offset.x = width * (index / 6); + offset.y = height * (index % 6); + break; + case 49: + offset.x = width * (index / 7); + offset.y = height * (index % 7); + break; + case 64: + offset.x = width * (index / 8); + offset.y = height * (index % 8); + break; + case 81: + offset.x = width * (index / 9); + offset.y = height * (index % 9); + break; + case 100: + offset.x = width * (index / 10); + offset.y = height * (index % 10); + break; + case 121: + offset.x = width * (index / 11); + offset.y = height * (index % 11); + break; + } + + float real_scale = min(scale->x, scale->y); + if (real_scale != scale->x) + offset.x *= scale->x / real_scale; + else + offset.y *= scale->y / real_scale; + + return offset; +} + +bool GraphicsDriver::printPage(PageDataList *pages) +{ +#ifndef USE_PREVIEW_FOR_DEBUG + BPoint offset; + offset.x = 0.0f; + offset.y = 0.0f; + + if (pages == NULL) { + return nextBand(NULL, &offset); + } + + do { + __view->SetScale(1.0); + __view->SetHighColor(255, 255, 255); + __view->ConstrainClippingRegion(NULL); + __view->FillRect(__view->Bounds()); + + BPoint scale = get_scale(__org_job_data); + float real_scale = min(scale.x, scale.y) * __org_job_data->getXres() / 72.0f; + __view->SetScale(real_scale); + float x = offset.x / real_scale; + float y = offset.y / real_scale; + int page_index = 0; + + for (PageDataList::iterator it = pages->begin(); it != pages->end(); it++) { + BPoint left_top(get_offset(page_index++, &scale, __org_job_data)); + left_top.x -= x; + left_top.y -= y; + BRect clip(__org_job_data->getPrintableRect()); + clip.OffsetTo(left_top); + BRegion *region = new BRegion(); + region->Set(clip); + __view->ConstrainClippingRegion(region); + delete region; + if ((*it)->startEnum()) { + bool more; + do { + PictureData *picture_data; + more = (*it)->enumObject(&picture_data); + BPoint real_offset = left_top + picture_data->point; + __view->DrawPicture(picture_data->picture, real_offset); + __view->Sync(); + delete picture_data; + } while (more); + } + } + if (!nextBand(__bitmap, &offset)) { + return false; + } + } while (offset.x >= 0.0f && offset.y >= 0.0f); + + return true; +#else // !USE_PREVIEW_FOR_DEBUG + __view->SetScale(1.0); + __view->SetHighColor(255, 255, 255); + __view->ConstrainClippingRegion(NULL); + __view->FillRect(__view->Bounds()); + + BPoint scale = get_scale(__org_job_data); + __view->SetScale(min(scale.x, scale.y)); + + int page_index = 0; + PageDataList::iterator it; + + for (it = pages->begin() ; it != pages->end() ; it++) { + BPoint left_top(get_offset(page_index, &scale, __org_job_data)); + BRect clip(__org_job_data->getPrintableRect()); + clip.OffsetTo(left_top); + BRegion *region = new BRegion(); + region->Set(clip); + __view->ConstrainClippingRegion(region); + delete region; + if ((*it)->startEnum()) { + bool more; + do { + PictureData *picture_data; + more = (*it)->enumObject(&picture_data); + BPoint real_offset = left_top + picture_data->point; + __view->DrawPicture(picture_data->picture, real_offset); + __view->Sync(); + delete picture_data; + } while (more); + } + page_index++; + } + + BRect rc(__real_job_data->getPrintableRect()); + rc.OffsetTo(30.0, 30.0); + PreviewWindow *preview = new PreviewWindow(rc, "Preview", __bitmap); + preview->Go(); +#endif // USE_PREVIEW_FOR_DEBUG +} + +bool GraphicsDriver::printDocument(SpoolData *spool_data) +{ + bool more; + bool success; + PageData *page_data; + int page_index; + int nup; + + more = false; + success = true; + page_index = 0; + + if (spool_data->startEnum()) { + do { + DBGMSG(("page index = %d\n", page_index)); + if (!(success = startPage(page_index))) + break; + nup = __org_job_data->getNup(); + PageDataList pages; + do { + more = spool_data->enumObject(&page_data); + pages.push_back(page_data); + } while (more && --nup); + __view->Window()->Lock(); + success = printPage(&pages); + __view->Window()->Unlock(); + if (!success) + break; + if (!(success = endPage(page_index))) + break; + page_index++; + } while (more); + } + +#ifndef USE_PREVIEW_FOR_DEBUG + if (success + && __printer_cap->isSupport(PrinterCap::PRINTSTYLE) + && (__org_job_data->getPrintStyle() != JobData::SIMPLEX) + && (((page_index + __org_job_data->getNup() - 1) / __org_job_data->getNup()) % 2)) + { + success = startPage(page_index); + if (success) { + success = printPage(NULL); + if (success) { + success = endPage(page_index); + } + } + } +#endif + + return success; +} + +bool GraphicsDriver::printJob(BFile *spool_file) +{ + bool success = true; + print_file_header pfh; + + spool_file->Seek(0, SEEK_SET); + spool_file->Read(&pfh, sizeof(pfh)); + + DBGMSG(("print_file_header::version = 0x%x\n", pfh.version)); + DBGMSG(("print_file_header::page_count = %d\n", pfh.page_count)); + DBGMSG(("print_file_header::first_page = 0x%x\n", (int)pfh.first_page)); + + if (pfh.page_count <= 0) { + return true; + } + + __transport = new Transport(__printer_data); + + if (__transport->check_abort()) { + success = false; + } else { + setupData(spool_file, pfh.page_count); + setupBitmap(); + SpoolData spool_data(spool_file, pfh.page_count, __org_job_data->getNup(), __org_job_data->getReverse()); + success = startDoc(); + if (success) { + while (__internal_copies--) { + success = printDocument(&spool_data); + if (success == false) { + break; + } + } + endDoc(success); + } + cleanupBitmap(); + cleanupData(); + } + + if (success == false) { + BAlert *alert; + if (__transport->check_abort()) { + alert = new BAlert("", __transport->last_error().c_str(), "OK"); + } else { + alert = new BAlert("", "Printer not responding.", "OK"); + } + alert->Go(); + } + + delete __transport; + __transport = NULL; + + return success; +} + +BMessage *GraphicsDriver::takeJob(BFile* spool_file, uint32 flags) +{ + __flags = flags; + BMessage *msg; + if (printJob(spool_file)) { + msg = new BMessage('okok'); + } else { + msg = new BMessage('baad'); + } + return msg; +} + +bool GraphicsDriver::startDoc() +{ + return true; +} + +bool GraphicsDriver::startPage(int) +{ + return true; +} + +bool GraphicsDriver::nextBand(BBitmap *, BPoint *) +{ + return true; +} + +bool GraphicsDriver::endPage(int) +{ + return true; +} + +bool GraphicsDriver::endDoc(bool) +{ + return true; +} + +void GraphicsDriver::writeSpoolData(const void *buffer, size_t size) throw(TransportException) +{ + if (__transport) { + __transport->write(buffer, size); + } +} + +void GraphicsDriver::writeSpoolString(const char *format, ...) throw(TransportException) +{ + if (__transport) { + char buffer[256]; + va_list ap; + va_start(ap, format); + vsprintf(buffer, format, ap); + __transport->write(buffer, strlen(buffer)); + va_end(ap); + } +} + +void GraphicsDriver::writeSpoolChar(char c) throw(TransportException) +{ + if (__transport) { + __transport->write(&c, 1); + } +} diff --git a/src/add-ons/print/drivers/canon_lips/libprint/GraphicsDriver.h b/src/add-ons/print/drivers/canon_lips/libprint/GraphicsDriver.h new file mode 100644 index 0000000000..73684c1684 --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/GraphicsDriver.h @@ -0,0 +1,114 @@ +/* + * GraphicsDriver.h + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#ifndef __GRAPHICSDRIVER_H +#define __GRAPHICSDRIVER_H + +#include "JobData.h" +#include "PrintProcess.h" +#include "Transport.h" + +class BView; +class BBitmap; +class BMessage; +class PrinterData; +class PrinterCap; + +#define GDF_ROTATE_BAND_BITMAP 0x01 + +class GraphicsDriver { +public: + GraphicsDriver(BMessage *, PrinterData *, const PrinterCap *); + virtual ~GraphicsDriver(); + BMessage *takeJob(BFile *spool, uint32 flags = 0); + +protected: + virtual bool startDoc(); + virtual bool startPage(int page_number); + virtual bool nextBand(BBitmap *bitmap, BPoint *offset); + virtual bool endPage(int page_number); + virtual bool endDoc(bool success); + + void writeSpoolData(const void *buffer, size_t size) throw(TransportException); + void writeSpoolString(const char *buffer, ...) throw(TransportException); + void writeSpoolChar(char c) throw(TransportException); + + const JobData *getJobData() const; + const PrinterData *getPrinterData() const; + const PrinterCap *getPrinterCap() const; + + int getPageWidth() const; + int getPageHeight() const; + int getBandWidth() const; + int getBandHeight() const; + int getPixelDepth() const; + + GraphicsDriver(const GraphicsDriver &); + GraphicsDriver &operator = (const GraphicsDriver &); + +private: + void setupData(BFile *file, long page_count); + void setupBitmap(); + void cleanupData(); + void cleanupBitmap(); + bool printPage(PageDataList *pages); + bool printDocument(SpoolData *spool_data); + bool printJob(BFile *file); + + uint32 __flags; + BMessage *__msg; + BView *__view; + BBitmap *__bitmap; + Transport *__transport; + JobData *__org_job_data; + JobData *__real_job_data; + PrinterData *__printer_data; + const PrinterCap *__printer_cap; + + int __page_width; + int __page_height; + int __band_width; + int __band_height; + int __pixel_depth; + int __band_count; + int __internal_copies; +}; + +inline const JobData *GraphicsDriver::getJobData() const +{ + return __real_job_data; +} + +inline const PrinterData *GraphicsDriver::getPrinterData() const +{ + return __printer_data; +} + +inline const PrinterCap *GraphicsDriver::getPrinterCap() const +{ + return __printer_cap; +} + +inline int GraphicsDriver::getPageWidth() const +{ + return __page_width; +} + +inline int GraphicsDriver::getPageHeight() const +{ + return __page_height; +} + +inline int GraphicsDriver::getBandWidth() const +{ + return __band_width; +} + +inline int GraphicsDriver::getBandHeight() const +{ + return __band_height; +} + +#endif /* __GRAPHICSDRIVER_H */ diff --git a/src/add-ons/print/drivers/canon_lips/libprint/Halftone.cpp b/src/add-ons/print/drivers/canon_lips/libprint/Halftone.cpp new file mode 100644 index 0000000000..3555caf6f7 --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/Halftone.cpp @@ -0,0 +1,308 @@ +/* + * HalftoneEngine.cpp + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#include +#include +#include +#include "Halftone.h" +#include "ValidRect.h" +#include "DbgMsg.h" + +#if (!__MWERKS__ || defined(MSIPL_USING_NAMESPACE)) +using namespace std; +#else +#define std +#endif + +#include "Pattern.h" + +uint gray(rgb_color c) +{ + if (c.red == c.green && c.red == c.blue) { + return 255 - c.red; + } else { + return 255 - (c.red * 3 + c.green * 6 + c.blue) / 10; + } +} + +Halftone::Halftone(color_space cs, double gamma, DITHERTYPE dither_type) +{ + __pixel_depth = color_space2pixel_depth(cs); + __palette = system_colors()->color_list; + __gray = gray; + + createGammaTable(gamma); + memset(__cache_table, 0, sizeof(__cache_table)); + + switch (dither_type) { + case TYPE2: + __pattern = pattern16x16_type2; + break; + case TYPE3: + __pattern = pattern16x16_type3; + break; + default: + __pattern = pattern16x16_type1; + break; + } + + switch (cs) { + case B_GRAY1: + __dither = &Halftone::ditherGRAY1; + break; + case B_GRAY8: + __dither = &Halftone::ditherGRAY8; + break; + case B_RGB32: + case B_RGB32_BIG: + __dither = &Halftone::ditherRGB32; + break; +// case B_CMAP8: + default: + __dither = &Halftone::ditherCMAP8; + break; + } +} + +Halftone::~Halftone() +{ +} + +void Halftone::createGammaTable(double gamma) +{ +// gamma = 1.0f / gamma; + uint *g = __gamma_table; + for (int i = 0; i < 256; i++) { + *g++ = (uint)(pow((double)i / 255.0, gamma) * 256.0); + } +} + +void Halftone::initElements(int x, int y, uchar *elements) +{ + x &= 0x0F; + y &= 0x0F; + + const uchar *left = &__pattern[y * 16]; + const uchar *pos = left + x; + const uchar *right = left + 0x0F; + + for (int i = 0; i < 16; i++) { + *elements++ = *pos; + if (pos >= right) { + pos = left; + } else { + pos++; + } + } +} + +int Halftone::dither( + uchar *dst, + const uchar *src, + int x, + int y, + int width) +{ + return (this->*__dither)(dst, src, x, y, width); +} + +int Halftone::ditherGRAY1( + uchar *dst, + const uchar *src, + int, + int, + int width) +{ + int widthByte = (width + 7) / 8; + memcpy(dst, src, widthByte); + return widthByte; +} + +int Halftone::ditherGRAY8( + uchar *dst, + const uchar *src, + int x, + int y, + int width) +{ + uchar elements[16]; + initElements(x, y, elements); + + int widthByte = (width + 7) / 8; + int remainder = width % 8; + if (!remainder) + remainder = 8; + + uchar cur; + uint density; + int i, j; + uchar *e = elements; + uchar *last_e = elements + 16; + + if (width >= 8) { + for (i = 0; i < widthByte - 1; i++) { + cur = 0; + if (e == last_e) { + e = elements; + } + for (j = 0; j < 8; j++) { + density = __gamma_table[*src++]; + if (density > *e++) { + cur |= (0x80 >> j); + } + } + *dst++ = cur; + } + } + if (remainder > 0) { + cur = 0; + if (e == last_e) { + e = elements; + } + for (j = 0; j < remainder; j++) { + density = __gamma_table[*src++]; + if (density > *e++) { + cur |= (0x80 >> j); + } + } + *dst++ = cur; + } + + return widthByte; +} + +int Halftone::ditherCMAP8( + uchar *dst, + const uchar *src, + int x, + int y, + int width) +{ + uchar elements[16]; + initElements(x, y, elements); + + int widthByte = (width + 7) / 8; + int remainder = width % 8; + if (!remainder) + remainder = 8; + + rgb_color c; + uchar cur; + int i, j; + + uchar *e = elements; + uchar *last_e = elements + 16; + CACHE_FOR_CMAP8 *cache; + + if (width >= 8) { + for (i = 0; i < widthByte - 1; i++) { + cur = 0; + if (e == last_e) { + e = elements; + } + for (j = 0; j < 8; j++) { + cache = &__cache_table[*src]; + if (!cache->hit) { + cache->hit = true; + c = __palette[*src]; + cache->density = __gamma_table[__gray(c)]; + } + src++; + if (cache->density > *e++) { + cur |= (0x80 >> j); + } + } + *dst++ = cur; + } + } + if (remainder > 0) { + cur = 0; + if (e == last_e) { + e = elements; + } + for (j = 0; j < remainder; j++) { + cache = &__cache_table[*src]; + if (!cache->hit) { + cache->hit = true; + c = __palette[*src]; + cache->density = __gamma_table[__gray(c)]; + } + src++; + if (cache->density > *e++) { + cur |= (0x80 >> j); + } + } + *dst++ = cur; + } + + return widthByte; +} + +int Halftone::ditherRGB32( + uchar *dst, + const uchar *a_src, + int x, + int y, + int width) +{ + uchar elements[16]; + initElements(x, y, elements); + + const rgb_color *src = (const rgb_color *)a_src; + + int widthByte = (width + 7) / 8; + int remainder = width % 8; + if (remainder == 0) + remainder = 8; + + rgb_color c; + uchar cur; + uint density; + int i, j; + uchar *e = elements; + uchar *last_e = elements + 16; + + c = *src; + density = __gamma_table[__gray(c)]; + + if (width >= 8) { + for (i = 0; i < widthByte - 1; i++) { + cur = 0; + if (e == last_e) { + e = elements; + } + for (j = 0; j < 8; j++) { + if (c.red != src->red || c.green != src->green || c.blue != src->blue) { + c = *src; + density = __gamma_table[__gray(c)]; + } + src++; + if (density > *e++) { + cur |= (0x80 >> j); + } + } + *dst++ = cur; + } + } + if (remainder > 0) { + cur = 0; + if (e == last_e) { + e = elements; + } + for (j = 0; j < remainder; j++) { + if (c.red != src->red || c.green != src->green || c.blue != src->blue) { + c = *src; + density = __gamma_table[__gray(c)]; + } + src++; + if (density > *e++) { + cur |= (0x80 >> j); + } + } + *dst++ = cur; + } + + return widthByte; +} diff --git a/src/add-ons/print/drivers/canon_lips/libprint/Halftone.h b/src/add-ons/print/drivers/canon_lips/libprint/Halftone.h new file mode 100644 index 0000000000..f5837cb4eb --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/Halftone.h @@ -0,0 +1,87 @@ +/* + * HalftoneEngine.h + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#ifndef __HALFTONE_H +#define __HALFTONE_H + +#include + +struct CACHE_FOR_CMAP8 { + uint density; + bool hit; +}; + +class Halftone; +typedef int (Halftone::*PFN_dither)(uchar *dst, const uchar *src, int x, int y, int width); +typedef uint (*PFN_gray)(rgb_color c); + +class Halftone { +public: + enum DITHERTYPE { + TYPE1, + TYPE2, + TYPE3 + }; + Halftone(color_space cs, double gamma = 1.4, DITHERTYPE dither_type = TYPE3); + ~Halftone(); + int dither(uchar *dst, const uchar *src, int x, int y, int width); + int getPixelDepth() const; + const rgb_color *getPalette() const; + const uchar *getPattern() const; + void setPattern(const uchar *pattern); + PFN_gray getGrayFunction() const; + void setGrayFunction(PFN_gray gray); + +protected: + void createGammaTable(double gamma); + void initElements(int x, int y, uchar *elements); + int ditherGRAY1(uchar *dst, const uchar *src, int x, int y, int width); + int ditherGRAY8(uchar *dst, const uchar *src, int x, int y, int width); + int ditherCMAP8(uchar *dst, const uchar *src, int x, int y, int width); + int ditherRGB32(uchar *dst, const uchar *src, int x, int y, int width); + + Halftone(const Halftone &); + Halftone &operator = (const Halftone &); + +private: + PFN_dither __dither; + PFN_gray __gray; + int __pixel_depth; + const rgb_color *__palette; + const uchar *__pattern; + uint __gamma_table[256]; + CACHE_FOR_CMAP8 __cache_table[256]; +}; + +inline int Halftone::getPixelDepth() const +{ + return __pixel_depth; +} + +inline const rgb_color *Halftone::getPalette() const +{ + return __palette; +} + +inline const uchar * Halftone::getPattern() const +{ + return __pattern; +} + +inline void Halftone::setPattern(const uchar *pattern) +{ + __pattern = pattern; +} + +inline PFN_gray Halftone::getGrayFunction() const +{ + return __gray; +} +inline void Halftone::setGrayFunction(PFN_gray gray) +{ + __gray = gray; +} + +#endif /* __HALFTONE_H */ diff --git a/src/add-ons/print/drivers/canon_lips/libprint/JobData.cpp b/src/add-ons/print/drivers/canon_lips/libprint/JobData.cpp new file mode 100644 index 0000000000..9ee23cd035 --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/JobData.cpp @@ -0,0 +1,309 @@ +/* + * JobData.cpp + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#include +#include +#include "JobData.h" +#include "PrinterCap.h" +#include "DbgMsg.h" + +const char *JD_XRES = "xres"; +const char *JD_YRES = "yres"; +const char *JD_COPIES = "copies"; +const char *JD_ORIENTATION = "orientation"; +const char *JD_SCALING = "scaling"; +const char *JD_PAPER_RECT = "paper_rect"; +const char *JD_FIRST_PAGE = "first_page"; +const char *JD_LAST_PAGE = "last_page"; +const char *JD_PRINTABLE_RECT = "printable_rect"; + +const char *JD_PAPER = "JJJJ_paper"; +const char *JD_NUP = "JJJJ_nup"; +const char *JD_SURFACE_TYPE = "JJJJ_surface_type"; +const char *JD_GAMMA = "JJJJ_gamma"; +const char *JD_PAPER_SOURCE = "JJJJ_paper_source"; +const char *JD_COLLATE = "JJJJ_collate"; +const char *JD_REVERSE = "JJJJ_reverse"; +const char *JD_PRINT_STYLE = "JJJJ_print_style"; +const char *JD_BINDING_LOCATION = "JJJJ_binding_location"; +const char *JD_PAGE_ORDER = "JJJJ_page_order"; + +JobData::JobData(BMessage *msg, const PrinterCap *cap) +{ + load(msg, cap); +} + +JobData::~JobData() +{ +} + +JobData::JobData(const JobData &job_data) +{ + __paper = job_data.__paper; + __xres = job_data.__xres; + __yres = job_data.__yres; + __orientation = job_data.__orientation; + __scaling = job_data.__scaling; + __paper_rect = job_data.__paper_rect; + __printable_rect = job_data.__printable_rect; + __nup = job_data.__nup; + __first_page = job_data.__first_page; + __last_page = job_data.__last_page; + __surface_type = job_data.__surface_type; + __gamma = job_data.__gamma; + __paper_source = job_data.__paper_source; + __copies = job_data.__copies; + __collate = job_data.__collate; + __reverse = job_data.__reverse; + __print_style = job_data.__print_style; + __binding_location = job_data.__binding_location; + __page_order = job_data.__page_order; + __msg = job_data.__msg; +} + +JobData &JobData::operator = (const JobData &job_data) +{ + __paper = job_data.__paper; + __xres = job_data.__xres; + __yres = job_data.__yres; + __orientation = job_data.__orientation; + __scaling = job_data.__scaling; + __paper_rect = job_data.__paper_rect; + __printable_rect = job_data.__printable_rect; + __nup = job_data.__nup; + __first_page = job_data.__first_page; + __last_page = job_data.__last_page; + __surface_type = job_data.__surface_type; + __gamma = job_data.__gamma; + __paper_source = job_data.__paper_source; + __copies = job_data.__copies; + __collate = job_data.__collate; + __reverse = job_data.__reverse; + __print_style = job_data.__print_style; + __binding_location = job_data.__binding_location; + __page_order = job_data.__page_order; + __msg = job_data.__msg; + return *this; +} + +void JobData::load(BMessage *msg, const PrinterCap *cap) +{ + __msg = msg; + + if (msg->HasInt32(JD_PAPER)) + __paper = (PAPER)msg->FindInt32(JD_PAPER); + else if (cap->isSupport(PrinterCap::PAPER)) + __paper = ((const PaperCap *)cap->getDefaultCap(PrinterCap::PAPER))->paper; + else + __paper = A4; + + if (msg->HasInt64(JD_XRES)) { + int64 xres64; + msg->FindInt64(JD_XRES, &xres64); + __xres = xres64; + } else if (cap->isSupport(PrinterCap::RESOLUTION)) { + __xres = ((const ResolutionCap *)cap->getDefaultCap(PrinterCap::RESOLUTION))->xres; + } else { + __xres = 300; + } + + if (msg->HasInt64(JD_YRES)) { + int64 yres64; + msg->FindInt64(JD_YRES, &yres64); + __yres = yres64; + } else if (cap->isSupport(PrinterCap::RESOLUTION)) { + __yres = ((const ResolutionCap *)cap->getDefaultCap(PrinterCap::RESOLUTION))->yres; + } else { + __yres = 300; + } + + if (msg->HasInt32(JD_ORIENTATION)) + __orientation = (ORIENTATION)msg->FindInt32(JD_ORIENTATION); + else if (cap->isSupport(PrinterCap::ORIENTATION)) + __orientation = ((const OrientationCap *)cap->getDefaultCap(PrinterCap::ORIENTATION))->orientation; + else + __orientation = PORTRAIT; + + if (msg->HasFloat(JD_SCALING)) + __scaling = msg->FindFloat(JD_SCALING); + else + __scaling = 100.0f; + + if (msg->HasRect(JD_PAPER_RECT)) { + __paper_rect = msg->FindRect(JD_PAPER_RECT); + } + + if (msg->HasRect(JD_PRINTABLE_RECT)) { + __printable_rect = msg->FindRect(JD_PRINTABLE_RECT); + } + + if (msg->HasInt32(JD_FIRST_PAGE)) + __first_page = msg->FindInt32(JD_FIRST_PAGE); + else + __first_page = 1; + + if (msg->HasInt32(JD_LAST_PAGE)) + __last_page = msg->FindInt32(JD_LAST_PAGE); + else + __last_page = -1; + + if (msg->HasInt32(JD_NUP)) + __nup = msg->FindInt32(JD_NUP); + else + __nup = 1; + + if (msg->HasInt32(JD_SURFACE_TYPE)) + __surface_type = (color_space)msg->FindInt32(JD_SURFACE_TYPE); + else + __surface_type = B_CMAP8; + + if (msg->HasFloat(JD_GAMMA)) + __gamma = __msg->FindFloat(JD_GAMMA); + else + __gamma = 1.4f; + + if (msg->HasInt32(JD_PAPER_SOURCE)) + __paper_source = (PAPERSOURCE)__msg->FindInt32(JD_PAPER_SOURCE); + else if (cap->isSupport(PrinterCap::PAPERSOURCE)) + __paper_source = ((const PaperSourceCap *)cap->getDefaultCap(PrinterCap::PAPERSOURCE))->paper_source; + else + __paper_source = AUTO; + + if (msg->HasInt32(JD_COPIES)) + __copies = msg->FindInt32(JD_COPIES); + else + __copies = 1; + + if (msg->HasBool(JD_COLLATE)) + __collate = msg->FindBool(JD_COLLATE); + else + __collate = false; + + if (msg->HasBool(JD_REVERSE)) + __reverse = msg->FindBool(JD_REVERSE); + else + __reverse = false; + + if (msg->HasInt32(JD_PRINT_STYLE)) + __print_style = (PRINTSTYLE)msg->FindInt32(JD_PRINT_STYLE); + else if (cap->isSupport(PrinterCap::PRINTSTYLE)) + __print_style = ((const PrintStyleCap *)cap->getDefaultCap(PrinterCap::PRINTSTYLE))->print_style; + else + __print_style = SIMPLEX; + + if (msg->HasInt32(JD_BINDING_LOCATION)) + __binding_location = (BINDINGLOCATION)msg->FindInt32(JD_BINDING_LOCATION); + else if (cap->isSupport(PrinterCap::BINDINGLOCATION)) + __binding_location = ((const BindingLocationCap *)cap->getDefaultCap(PrinterCap::BINDINGLOCATION))->binding_location; + else + __binding_location = LONG_EDGE_LEFT; + + if (msg->HasInt32(JD_PAGE_ORDER)) + __page_order = (PAGEORDER)msg->FindInt32(JD_PAGE_ORDER); + else + __page_order = ACROSS_FROM_LEFT; +} + +void JobData::save(BMessage *msg) +{ + if (msg == NULL) { + msg = __msg; + } + + if (msg->HasInt32(JD_PAPER)) + msg->ReplaceInt32(JD_PAPER, __paper); + else + msg->AddInt32(JD_PAPER, __paper); + + if (msg->HasInt64(JD_XRES)) + msg->ReplaceInt64(JD_XRES, __xres); + else + msg->AddInt64(JD_XRES, __xres); + + if (msg->HasInt64(JD_YRES)) + msg->ReplaceInt64(JD_YRES, __yres); + else + msg->AddInt64(JD_YRES, __yres); + + if (msg->HasInt32(JD_ORIENTATION)) + msg->ReplaceInt32(JD_ORIENTATION, __orientation); + else + msg->AddInt32(JD_ORIENTATION, __orientation); + + if (msg->HasFloat(JD_SCALING)) + msg->ReplaceFloat(JD_SCALING, __scaling); + else + msg->AddFloat(JD_SCALING, __scaling); + + if (msg->HasRect(JD_PAPER_RECT)) + msg->ReplaceRect(JD_PAPER_RECT, __paper_rect); + else + msg->AddRect(JD_PAPER_RECT, __paper_rect); + + if (msg->HasRect(JD_PRINTABLE_RECT)) + msg->ReplaceRect(JD_PRINTABLE_RECT, __printable_rect); + else + msg->AddRect(JD_PRINTABLE_RECT, __printable_rect); + + if (msg->HasInt32(JD_NUP)) + msg->ReplaceInt32(JD_NUP, __nup); + else + msg->AddInt32(JD_NUP, __nup); + + if (msg->HasInt32(JD_FIRST_PAGE)) + msg->ReplaceInt32(JD_FIRST_PAGE, __first_page); + else + msg->AddInt32(JD_FIRST_PAGE, __first_page); + + if (msg->HasInt32(JD_LAST_PAGE)) + msg->ReplaceInt32(JD_LAST_PAGE, __last_page); + else + msg->AddInt32(JD_LAST_PAGE, __last_page); + + if (msg->HasInt32(JD_SURFACE_TYPE)) + msg->ReplaceInt32(JD_SURFACE_TYPE, __surface_type); + else + msg->AddInt32(JD_SURFACE_TYPE, __surface_type); + + if (msg->HasFloat(JD_GAMMA)) + msg->ReplaceFloat(JD_GAMMA, __gamma); + else + msg->AddFloat(JD_GAMMA, __gamma); + + if (msg->HasInt32(JD_PAPER_SOURCE)) + msg->ReplaceInt32(JD_PAPER_SOURCE, __paper_source); + else + msg->AddInt32(JD_PAPER_SOURCE, __paper_source); + + if (msg->HasInt32(JD_COPIES)) + msg->ReplaceInt32(JD_COPIES, __copies); + else + msg->AddInt32(JD_COPIES, __copies); + + if (msg->HasBool(JD_COLLATE)) + msg->ReplaceBool(JD_COLLATE, __collate); + else + msg->AddBool(JD_COLLATE, __collate); + + if (msg->HasBool(JD_REVERSE)) + msg->ReplaceBool(JD_REVERSE, __reverse); + else + msg->AddBool(JD_REVERSE, __reverse); + + if (msg->HasInt32(JD_PRINT_STYLE)) + msg->ReplaceInt32(JD_PRINT_STYLE, __print_style); + else + msg->AddInt32(JD_PRINT_STYLE, __print_style); + + if (msg->HasInt32(JD_BINDING_LOCATION)) + msg->ReplaceInt32(JD_BINDING_LOCATION, __binding_location); + else + msg->AddInt32(JD_BINDING_LOCATION, __binding_location); + + if (msg->HasInt32(JD_PAGE_ORDER)) + msg->ReplaceInt32(JD_PAGE_ORDER, __page_order); + else + msg->AddInt32(JD_PAGE_ORDER, __page_order); +} diff --git a/src/add-ons/print/drivers/canon_lips/libprint/JobData.h b/src/add-ons/print/drivers/canon_lips/libprint/JobData.h new file mode 100644 index 0000000000..e2d317bfd9 --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/JobData.h @@ -0,0 +1,305 @@ +/* + * JobData.h + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#ifndef __JOBDATA_H +#define __JOBDATA_H + +#include +#include +#include + +class BMessage; +class PrinterCap; + +class JobData { +public: + enum ORIENTATION { + PORTRAIT, + LANDSCAPE + }; + + enum PAPER { + LETTER = 1, // 1 Letter 8 1/2 x 11 in + LETTERSMALL, // 2 Letter Small 8 1/2 x 11 in + TABLOID, // 3 Tabloid 11 x 17 in + LEDGER, // 4 Ledger 17 x 11 in + LEGAL, // 5 Legal 8 1/2 x 14 in + STATEMENT, // 6 Statement 5 1/2 x 8 1/2 in + EXECUTIVE, // 7 Executive 7 1/4 x 10 1/2 in + A3, // 8 A3 297 x 420 mm + A4, // 9 A4 210 x 297 mm + A4SMALL, // 10 A4 Small 210 x 297 mm + A5, // 11 A5 148 x 210 mm + B4, // 12 B4 (JIS) 250 x 354 + B5, // 13 B5 (JIS) 182 x 257 mm + FOLIO, // 14 Folio 8 1/2 x 13 in + QUARTO, // 15 Quarto 215 x 275 mm + P_10X14, // 16 10x14 in + P_11X17, // 17 11x17 in + NOTE, // 18 Note 8 1/2 x 11 in + ENV_9, // 19 Envelope #9 3 7/8 x 8 7/8 + ENV_10, // 20 Envelope #10 4 1/8 x 9 1/2 + ENV_11, // 21 Envelope #11 4 1/2 x 10 3/8 + ENV_12, // 22 Envelope #12 4 \276 x 11 + ENV_14, // 23 Envelope #14 5 x 11 1/2 + CSHEET, // 24 C size sheet + DSHEET, // 25 D size sheet + ESHEET, // 26 E size sheet + ENV_DL, // 27 Envelope DL 110 x 220mm + ENV_C5, // 28 Envelope C5 162 x 229 mm + ENV_C3, // 29 Envelope C3 324 x 458 mm + ENV_C4, // 30 Envelope C4 229 x 324 mm + ENV_C6, // 31 Envelope C6 114 x 162 mm + ENV_C65, // 32 Envelope C65 114 x 229 mm + ENV_B4, // 33 Envelope B4 250 x 353 mm + ENV_B5, // 34 Envelope B5 176 x 250 mm + ENV_B6, // 35 Envelope B6 176 x 125 mm + ENV_ITALY, // 36 Envelope 110 x 230 mm + ENV_MONARCH, // 37 Envelope Monarch 3.875 x 7.5 in + ENV_PERSONAL, // 38 6 3/4 Envelope 3 5/8 x 6 1/2 in + FANFOLD_US, // 39 US Std Fanfold 14 7/8 x 11 in + FANFOLD_STD_GERMAN, // 40 German Std Fanfold 8 1/2 x 12 in + FANFOLD_LGL_GERMAN, // 41 German Legal Fanfold 8 1/2 x 13 in + ISO_B4, // 42 B4 (ISO) 250 x 353 mm + JAPANESE_POSTCARD, // 43 Japanese Postcard 100 x 148 mm + P_9X11, // 44 9 x 11 in + P_10X11, // 45 10 x 11 in + P_15X11, // 46 15 x 11 in + ENV_INVITE, // 47 Envelope Invite 220 x 220 mm + RESERVED_48, // 48 RESERVED--DO NOT USE + RESERVED_49, // 49 RESERVED--DO NOT USE + LETTER_EXTRA, // 50 Letter Extra 9 \275 x 12 in + LEGAL_EXTRA, // 51 Legal Extra 9 \275 x 15 in + TABLOID_EXTRA, // 52 Tabloid Extra 11.69 x 18 in + A4_EXTRA, // 53 A4 Extra 9.27 x 12.69 in + LETTER_TRANSVERSE, // 54 Letter Transverse 8 \275 x 11 in + A4_TRANSVERSE, // 55 A4 Transverse 210 x 297 mm + LETTER_EXTRA_TRANSVERSE,// 56 Letter Extra Transverse 9\275 x 12 in + A_PLUS, // 57 SuperA/SuperA/A4 227 x 356 mm + B_PLUS, // 58 SuperB/SuperB/A3 305 x 487 mm + LETTER_PLUS, // 59 Letter Plus 8.5 x 12.69 in + A4_PLUS, // 60 A4 Plus 210 x 330 mm + A5_TRANSVERSE, // 61 A5 Transverse 148 x 210 mm + B5_TRANSVERSE, // 62 B5 (JIS) Transverse 182 x 257 mm + A3_EXTRA, // 63 A3 Extra 322 x 445 mm + A5_EXTRA, // 64 A5 Extra 174 x 235 mm + B5_EXTRA, // 65 B5 (ISO) Extra 201 x 276 mm + A2, // 66 A2 420 x 594 mm + A3_TRANSVERSE, // 67 A3 Transverse 297 x 420 mm + A3_EXTRA_TRANSVERSE, // 68 A3 Extra Transverse 322 x 445 mm + DBL_JAPANESE_POSTCARD, // 69 Japanese Double Postcard 200 x 148 mm + A6, // 70 A6 105 x 148 mm + JENV_KAKU2, // 71 Japanese Envelope Kaku #2 + JENV_KAKU3, // 72 Japanese Envelope Kaku #3 + JENV_CHOU3, // 73 Japanese Envelope Chou #3 + JENV_CHOU4, // 74 Japanese Envelope Chou #4 + LETTER_ROTATED, // 75 Letter Rotated 11 x 8 1/2 11 in + A3_ROTATED, // 76 A3 Rotated 420 x 297 mm + A4_ROTATED, // 77 A4 Rotated 297 x 210 mm + A5_ROTATED, // 78 A5 Rotated 210 x 148 mm + B4_JIS_ROTATED, // 79 B4 (JIS) Rotated 364 x 257 mm + B5_JIS_ROTATED, // 80 B5 (JIS) Rotated 257 x 182 mm + JAPANESE_POSTCARD_ROTATED, // 81 Japanese Postcard Rotated 148 x 100 mm + DBL_JAPANESE_POSTCARD_ROTATED, // 82 Double Japanese Postcard Rotated 148 x 200 mm + A6_ROTATED, // 83 A6 Rotated 148 x 105 mm + JENV_KAKU2_ROTATED, // 84 Japanese Envelope Kaku #2 Rotated + JENV_KAKU3_ROTATED, // 85 Japanese Envelope Kaku #3 Rotated + JENV_CHOU3_ROTATED, // 86 Japanese Envelope Chou #3 Rotated + JENV_CHOU4_ROTATED, // 87 Japanese Envelope Chou #4 Rotated + B6_JIS, // 88 B6 (JIS) 128 x 182 mm + B6_JIS_ROTATED, // 89 B6 (JIS) Rotated 182 x 128 mm + P_12X11, // 90 12 x 11 in + JENV_YOU4, // 91 Japanese Envelope You #4 + JENV_YOU4_ROTATED, // 92 Japanese Envelope You #4 Rotated + P16K, // 93 PRC 16K 146 x 215 mm + P32K, // 94 PRC 32K 97 x 151 mm + P32KBIG, // 95 PRC 32K(Big) 97 x 151 mm + PENV_1, // 96 PRC Envelope #1 102 x 165 mm + PENV_2, // 97 PRC Envelope #2 102 x 176 mm + PENV_3, // 98 PRC Envelope #3 125 x 176 mm + PENV_4, // 99 PRC Envelope #4 110 x 208 mm + PENV_5, // 100 PRC Envelope #5 110 x 220 mm + PENV_6, // 101 PRC Envelope #6 120 x 230 mm + PENV_7, // 102 PRC Envelope #7 160 x 230 mm + PENV_8, // 103 PRC Envelope #8 120 x 309 mm + PENV_9, // 104 PRC Envelope #9 229 x 324 mm + PENV_10, // 105 PRC Envelope #10 324 x 458 mm + P16K_ROTATED, // 106 PRC 16K Rotated + P32K_ROTATED, // 107 PRC 32K Rotated + P32KBIG_ROTATED, // 108 PRC 32K(Big) Rotated + PENV_1_ROTATED, // 109 PRC Envelope #1 Rotated 165 x 102 mm + PENV_2_ROTATED, // 110 PRC Envelope #2 Rotated 176 x 102 mm + PENV_3_ROTATED, // 111 PRC Envelope #3 Rotated 176 x 125 mm + PENV_4_ROTATED, // 112 PRC Envelope #4 Rotated 208 x 110 mm + PENV_5_ROTATED, // 113 PRC Envelope #5 Rotated 220 x 110 mm + PENV_6_ROTATED, // 114 PRC Envelope #6 Rotated 230 x 120 mm + PENV_7_ROTATED, // 115 PRC Envelope #7 Rotated 230 x 160 mm + PENV_8_ROTATED, // 116 PRC Envelope #8 Rotated 309 x 120 mm + PENV_9_ROTATED, // 117 PRC Envelope #9 Rotated 324 x 229 mm + PENV_10_ROTATED, // 118 PRC Envelope #10 Rotated 458 x 324 mm + USER_DEFINED = 256 + }; + + enum PAPERSOURCE { + AUTO, // 7 o + MANUAL, // 4 o + UPPER, // 1 o + MIDDLE, // 3 o + LOWER, // 2 o +// ONLYONE, // 1 x +// ENVELOPE, // 5 o +// ENVMANUAL, // 6 x +// TRACTOR, // 8 x +// SMALLFMT, // 9 x +// LARGEFMT, // 10 x +// LARGECAPACITY, // 11 x +// CASSETTE, // 14 x +// FORMSOURCE, // 15 x + CASSETTE1 = 21, + CASSETTE2, + CASSETTE3, + CASSETTE4, + CASSETTE5, + CASSETTE6, + CASSETTE7, + CASSETTE8, + CASSETTE9, + USER = 256 // device specific bins start here + }; + + enum PRINTSTYLE { + SIMPLEX, + DUPLEX, + BOOKLET + }; + + enum BINDINGLOCATION { + LONG_EDGE_LEFT, + LONG_EDGE_RIGHT, + SHORT_EDGE_TOP, + SHORT_EDGE_BOTTOM, + LONG_EDGE = LONG_EDGE_LEFT, + SHORT_EDGE = SHORT_EDGE_TOP + }; + + enum PAGEORDER { + ACROSS_FROM_LEFT, + DOWN_FROM_LEFT, + ACROSS_FROM_RIGHT, + DOWN_FROM_RIGHT, + LEFT_TO_RIGHT = ACROSS_FROM_LEFT, + RIGHT_TO_LEFT = ACROSS_FROM_RIGHT + }; + +/* + enum QUALITY { + DRAFT = -1, + LOW = -2, + MEDIUM = -3, + HIGH = -4 + }; + + enum COLOR { + MONOCHROME = 1, + COLOR + }; +*/ + +private: + PAPER __paper; + int32 __xres; + int32 __yres; + ORIENTATION __orientation; + float __scaling; + BRect __paper_rect; + BRect __printable_rect; + int32 __nup; + int32 __first_page; + int32 __last_page; + color_space __surface_type; + float __gamma; + PAPERSOURCE __paper_source; + int32 __copies; + bool __collate; + bool __reverse; + PRINTSTYLE __print_style; + BINDINGLOCATION __binding_location; + PAGEORDER __page_order; + BMessage *__msg; + +public: + JobData(BMessage *msg, const PrinterCap *cap); + ~JobData(); + + JobData(const JobData &job_data); + JobData &operator = (const JobData &job_data); + + void load(BMessage *msg, const PrinterCap *cap); + void save(BMessage *msg = NULL); + + PAPER getPaper() const { return __paper; } + void setPaper(PAPER paper) { __paper = paper; } + + int32 getXres() const { return __xres; } + void setXres(int32 xres) { __xres = xres; } + + int32 getYres() const { return __yres; } + void setYres(int32 yres) { __yres = yres; }; + + ORIENTATION getOrientation() const { return __orientation; } + void setOrientation(ORIENTATION orientation) { __orientation = orientation; } + + float getScaling() const { return __scaling; } + void setScaling(float scaling) { __scaling = scaling; } + + const BRect &getPaperRect() const { return __paper_rect; } + void setPaperRect(const BRect &paper_rect) { __paper_rect = paper_rect; } + + const BRect &getPrintableRect() const { return __printable_rect; } + void setPrintableRect(const BRect &printable_rect) { __printable_rect = printable_rect; } + + int32 getNup() const { return __nup; } + void setNup(int32 nup) { __nup = nup; } + + bool getReverse() const { return __reverse; } + void setReverse(bool reverse) { __reverse = reverse; } + + int32 getFirstPage() const { return __first_page; } + void setFirstPage(int32 first_page) { __first_page = first_page; } + + int32 getLastPage() const { return __last_page; } + void setLastPage(int32 last_page) { __last_page = last_page; } + + color_space getSurfaceType() const { return __surface_type; } + void setSurfaceType(color_space surface_type) { __surface_type = surface_type; } + + float getGamma() const { return __gamma; } + void setGamma(float gamma) { __gamma = gamma; } + + PAPERSOURCE getPaperSource() const { return __paper_source; } + void setPaperSource(PAPERSOURCE paper_source) { __paper_source = paper_source; }; + + int32 getCopies() const { return __copies; } + void setCopies(int32 copies) { __copies = copies; } + + bool getCollate() const { return __collate; } + void setCollate(bool collate) { __collate = collate; } + + PRINTSTYLE getPrintStyle() const { return __print_style; } + void setPrintStyle(PRINTSTYLE print_style) { __print_style = print_style; } + + BINDINGLOCATION getBindingLocation() const { return __binding_location; } + void setBindingLocation(BINDINGLOCATION binding_location) { __binding_location = binding_location; } + + PAGEORDER getPageOrder() const { return __page_order; } + void setPageOrder(PAGEORDER page_order) { __page_order = page_order; } +/* +protected: + JobData(const JobData &job_data); + JobData &operator = (const JobData &job_data); +*/ +}; + +#endif /* __JOBDATA_H */ diff --git a/src/add-ons/print/drivers/canon_lips/libprint/JobSetupDlg.cpp b/src/add-ons/print/drivers/canon_lips/libprint/JobSetupDlg.cpp new file mode 100644 index 0000000000..e2bb0270ab --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/JobSetupDlg.cpp @@ -0,0 +1,660 @@ +/* + * JobSetupDlg.cpp + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#include +#include +#include +#include "_sstream" +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "JobSetupDlg.h" +#include "JobData.h" +#include "PrinterData.h" +#include "PrinterCap.h" +#include "DbgMsg.h" + +#if (!__MWERKS__ || defined(MSIPL_USING_NAMESPACE)) +using namespace std; +#else +#define std +#endif + +//#define PRINT_COPIES 100 + +#define PRINT_WIDTH 355 +#define PRINT_HEIGHT 210 + +#define QUALITY_H 10 +#define QUALITY_V 10 +#define QUALITY_WIDTH 180 +#define QUALITY_HEIGHT 70 + + #define BPP_H 10 + #define BPP_V 15 + #define BPP_WIDTH 140 + #define BPP_HEIGHT 16 + + #define GAMMA_H BPP_H + #define GAMMA_V BPP_V + BPP_HEIGHT + 10 + #define GAMMA_WIDTH 120 + #define GAMMA_HEIGHT BPP_HEIGHT + +#define PAGERABGE_H QUALITY_H +#define PAGERABGE_V QUALITY_V + QUALITY_HEIGHT + 5 +#define PAGERABGE_WIDTH QUALITY_WIDTH +#define PAGERABGE_HEIGHT 70 + + #define ALL_H 10 + #define ALL_V 20 + #define ALL_WIDTH 36 + #define ALL_HEIGHT 16 + + #define SELECTION_H ALL_H + #define SELECTION_V ALL_V + ALL_HEIGHT + 4 + #define SELECTION_WIDTH 16 + #define SELECTION_HEIGHT 16 + + #define FROM_H (SELECTION_H + SELECTION_WIDTH + 1) + #define FROM_V ALL_V + 19 + #define FROM_WIDTH 73 + #define FROM_HEIGHT 16 + + #define TO_H (FROM_H + FROM_WIDTH + 7) + #define TO_V FROM_V + #define TO_WIDTH 59 + #define TO_HEIGHT FROM_HEIGHT + +#define PAPERFEED_H QUALITY_H + QUALITY_WIDTH + 10 +#define PAPERFEED_V QUALITY_V + 5 +#define PAPERFEED_WIDTH 160 +#define PAPERFEED_HEIGHT 16 + +#define NUP_H PAPERFEED_H +#define NUP_V PAPERFEED_V + PAPERFEED_HEIGHT + 7 +#define NUP_WIDTH PAPERFEED_WIDTH +#define NUP_HEIGHT 16 +#define MENU_HEIGHT 16 + +#define COPIES_H PAPERFEED_H +#define COPIES_V NUP_V + NUP_HEIGHT + 10 +#define COPIES_WIDTH 140 +#define COPIES_HEIGHT 16 + +#define DUPLEX_H PAPERFEED_H +#define DUPLEX_V COPIES_V + COPIES_HEIGHT + 7 +#define DUPLEX_WIDTH PAPERFEED_WIDTH +#define DUPLEX_HEIGHT 16 + +#define COLLATE_H PAPERFEED_H +#define COLLATE_V DUPLEX_V + DUPLEX_HEIGHT + 5 +#define COLLATE_WIDTH PAPERFEED_WIDTH +#define COLLATE_HEIGHT 16 + +#define REVERSE_H PAPERFEED_H +#define REVERSE_V COLLATE_V + COLLATE_HEIGHT + 5 +#define REVERSE_WIDTH PAPERFEED_WIDTH +#define REVERSE_HEIGHT 16 + +#define PRINT_BUTTON_WIDTH 70 +#define PRINT_BUTTON_HEIGHT 20 + +#define PRINT_LINE_V (PRINT_HEIGHT - PRINT_BUTTON_HEIGHT - 23) + +#define PRINT_OK_BUTTON_H (PRINT_WIDTH - PRINT_BUTTON_WIDTH - 10) +#define PRINT_OK_BUTTON_V (PRINT_HEIGHT - PRINT_BUTTON_HEIGHT - 11) + +#define PRINT_CANCEL_BUTTON_H (PRINT_OK_BUTTON_H - PRINT_BUTTON_WIDTH - 12) +#define PRINT_CANCEL_BUTTON_V PRINT_OK_BUTTON_V + +const BRect quality_rect( + QUALITY_H, + QUALITY_V, + QUALITY_H + QUALITY_WIDTH, + QUALITY_V + QUALITY_HEIGHT); + +const BRect bpp_rect( + BPP_H, + BPP_V, + BPP_H + BPP_WIDTH, + BPP_V + BPP_HEIGHT); + +const BRect gamma_rect( + GAMMA_H, + GAMMA_V, + GAMMA_H + GAMMA_WIDTH, + GAMMA_V + GAMMA_HEIGHT); + +const BRect pagerange_rect( + PAGERABGE_H, + PAGERABGE_V, + PAGERABGE_H + PAGERABGE_WIDTH, + PAGERABGE_V + PAGERABGE_HEIGHT); + +const BRect all_button_rect( + ALL_H, + ALL_V, + ALL_H + ALL_WIDTH, + ALL_V + ALL_HEIGHT); + +const BRect selection_rect( + SELECTION_H, + SELECTION_V, + SELECTION_H + SELECTION_WIDTH, + SELECTION_V + SELECTION_HEIGHT); + +const BRect from_rect( + FROM_H, + FROM_V, + FROM_H + FROM_WIDTH, + FROM_V + FROM_HEIGHT); + +const BRect to_rect( + TO_H, + TO_V, + TO_H + TO_WIDTH, + TO_V + TO_HEIGHT); + +const BRect paperfeed_rect( + PAPERFEED_H, + PAPERFEED_V, + PAPERFEED_H + PAPERFEED_WIDTH, + PAPERFEED_V + PAPERFEED_HEIGHT); + +const BRect nup_rect( + NUP_H, + NUP_V, + NUP_H + NUP_WIDTH, + NUP_V + NUP_HEIGHT); + +const BRect copies_rect( + COPIES_H, + COPIES_V, + COPIES_H + COPIES_WIDTH, + COPIES_V + COPIES_HEIGHT); + +const BRect duplex_rect( + DUPLEX_H, + DUPLEX_V, + DUPLEX_H + DUPLEX_WIDTH, + DUPLEX_V + DUPLEX_HEIGHT); + +const BRect collate_rect( + COLLATE_H, + COLLATE_V, + COLLATE_H + COLLATE_WIDTH, + COLLATE_V + COLLATE_HEIGHT); + +const BRect reverse_rect( + REVERSE_H, + REVERSE_V, + REVERSE_H + REVERSE_WIDTH, + REVERSE_V + REVERSE_HEIGHT); + +const BRect ok_rect( + PRINT_OK_BUTTON_H, + PRINT_OK_BUTTON_V, + PRINT_OK_BUTTON_H + PRINT_BUTTON_WIDTH, + PRINT_OK_BUTTON_V + PRINT_BUTTON_HEIGHT); + +const BRect cancel_rect( + PRINT_CANCEL_BUTTON_H, + PRINT_CANCEL_BUTTON_V, + PRINT_CANCEL_BUTTON_H + PRINT_BUTTON_WIDTH, + PRINT_CANCEL_BUTTON_V + PRINT_BUTTON_HEIGHT); + +struct SurfaceCap : public BaseCap { + color_space surface_type; + SurfaceCap(const string &s, bool d, color_space cs) : BaseCap(s, d), surface_type(cs) {} +}; + +struct NupCap : public BaseCap { + int nup; + NupCap(const string &s, bool d, int n) : BaseCap(s, d), nup(n) {} +}; + +const SurfaceCap rgb32("RGB32", false, B_RGB32); +const SurfaceCap cmap8("CMAP8", true, B_CMAP8); +const SurfaceCap gray8("GRAY8", false, B_GRAY8); +const SurfaceCap gray1("GRAY1", false, B_GRAY1); + +const NupCap nup1("Normal", true, 1); +const NupCap nup2("2-up", false, 2); +const NupCap nup4("4-up", false, 4); +const NupCap nup8("8-up", false, 8); +const NupCap nup9("9-up", false, 9); +const NupCap nup16("16-up", false, 16); +const NupCap nup25("25-up", false, 25); +const NupCap nup32("32-up", false, 32); +const NupCap nup36("36-up", false, 36); + +const SurfaceCap *surfaces[] = { + &rgb32, + &cmap8, + &gray8, + &gray1 +}; + +const NupCap *nups[] = { + &nup1, + &nup2, + &nup4, + &nup8, + &nup9, + &nup16, + &nup25, + &nup32, + &nup36 +}; + +enum { + M_RANGE_ALL = 1, + M_RANGE_SELECTION, + M_CANCEL, + M_OK +}; + +JobSetupView::JobSetupView(BRect frame, JobData *job_data, PrinterData *printer_data, const PrinterCap *printer_cap) + : BView(frame, "", B_FOLLOW_ALL, B_WILL_DRAW), __job_data(job_data), __printer_data(printer_data), __printer_cap(printer_cap) +{ + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); +} + +void JobSetupView::AttachedToWindow() +{ + BBox *box; + BMenuItem *item = NULL; + BMenuField *menufield; + BButton *button; + float width; + bool marked; + int count; + + /* quality */ + + box = new BBox(quality_rect); + AddChild(box); + box->SetLabel("Quality"); + + marked = false; + __surface_type = new BPopUpMenu(""); + __surface_type->SetRadioMode(true); + count = sizeof(surfaces) / sizeof(surfaces[0]); + const SurfaceCap **surface_cap = surfaces; + uint32 support_flags; + while (count--) { + if (bitmaps_support_space((*surface_cap)->surface_type, &support_flags)) { + item = new BMenuItem((*surface_cap)->label.c_str(), NULL); + __surface_type->AddItem(item); + if ((*surface_cap)->surface_type == __job_data->getSurfaceType()) { + item->SetMarked(true); + marked = true; + } + } + surface_cap++; + } + menufield = new BMenuField(bpp_rect, "", "Surface Type", __surface_type); + box->AddChild(menufield); + width = StringWidth("Surface Type") + 10; + menufield->SetDivider(width); + + __gamma = new BTextControl(gamma_rect, "", "Gamma", "", NULL); + box->AddChild(__gamma); + __gamma->SetDivider(width); + ostringstream oss3; + oss3 << __job_data->getGamma(); + __gamma->SetText(oss3.str().c_str()); + + /* page range */ + + box = new BBox(pagerange_rect); + AddChild(box); + box->SetLabel("Page Range"); + + __all = new BRadioButton(all_button_rect, "", "All", new BMessage(M_RANGE_ALL)); + box->AddChild(__all); + + BRadioButton *from = new BRadioButton(selection_rect, "", "", new BMessage(M_RANGE_SELECTION)); + box->AddChild(from); + + from_page = new BTextControl(from_rect, "", "From", "", NULL); + box->AddChild(from_page); + from_page->SetAlignment(B_ALIGN_LEFT, B_ALIGN_RIGHT); + from_page->SetDivider(StringWidth("From") + 7); + + to_page = new BTextControl(to_rect, "", "To", "", NULL); + box->AddChild(to_page); + to_page->SetAlignment(B_ALIGN_LEFT, B_ALIGN_RIGHT); + to_page->SetDivider(StringWidth("To") + 7); + + int first_page = __job_data->getFirstPage(); + int last_page = __job_data->getLastPage(); + + if (first_page <= 1 && last_page <= 0) { + __all->SetValue(B_CONTROL_ON); + from_page->SetEnabled(false); + to_page->SetEnabled(false); + } else { + from->SetValue(B_CONTROL_ON); + if (first_page < 1) + first_page = 1; + if (first_page > last_page) + last_page = -1; + + ostringstream oss1; + oss1 << first_page; + from_page->SetText(oss1.str().c_str()); + + ostringstream oss2; + oss2 << last_page; + to_page->SetText(oss2.str().c_str()); + } + + __all->SetTarget(this); + from->SetTarget(this); + + /* paper source */ + + marked = false; + __paper_feed = new BPopUpMenu(""); + __paper_feed->SetRadioMode(true); + count = __printer_cap->countCap(PrinterCap::PAPERSOURCE); + const PaperSourceCap **paper_source_cap = (const PaperSourceCap **)__printer_cap->enumCap(PrinterCap::PAPERSOURCE); + while (count--) { + item = new BMenuItem((*paper_source_cap)->label.c_str(), NULL); + __paper_feed->AddItem(item); + if ((*paper_source_cap)->paper_source == __job_data->getPaperSource()) { + item->SetMarked(true); + marked = true; + } + paper_source_cap++; + } + if (!marked) + item->SetMarked(true); + menufield = new BMenuField(paperfeed_rect, "", "Paper Source", __paper_feed); + AddChild(menufield); + width = StringWidth("Number of Copies") + 7; + menufield->SetDivider(width); + + /* Page Per Sheet */ + + marked = false; + __nup = new BPopUpMenu(""); + __nup->SetRadioMode(true); + count = sizeof(nups) / sizeof(nups[0]); + const NupCap **nup_cap = nups; + while (count--) { + item = new BMenuItem((*nup_cap)->label.c_str(), NULL); + __nup->AddItem(item); + if ((*nup_cap)->nup == __job_data->getNup()) { + item->SetMarked(true); + marked = true; + } + nup_cap++; + } + if (!marked) + item->SetMarked(true); + menufield = new BMenuField(nup_rect, "", "Page Per Sheet", __nup); + menufield->SetDivider(width); + AddChild(menufield); + + /* duplex */ + + if (__printer_cap->isSupport(PrinterCap::PRINTSTYLE)) { + __duplex = new BCheckBox(duplex_rect, "Duplex", "Duplex", NULL); + AddChild(__duplex); + if (__job_data->getPrintStyle() != JobData::SIMPLEX) { + __duplex->SetValue(B_CONTROL_ON); + } + } + + /* copies */ + + copies = new BTextControl(copies_rect, "", "Number of Copies", "", NULL); + AddChild(copies); + copies->SetDivider(width); + + ostringstream oss4; + oss4 << __job_data->getCopies(); + copies->SetText(oss4.str().c_str()); + + /* collate */ + + __collate = new BCheckBox(collate_rect, "Collate", "Collate", NULL); + AddChild(__collate); + if (__job_data->getCollate()) { + __collate->SetValue(B_CONTROL_ON); + } + + /* reverse */ + + __reverse = new BCheckBox(reverse_rect, "Reverse", "Reverse", NULL); + AddChild(__reverse); + if (__job_data->getReverse()) { + __reverse->SetValue(B_CONTROL_ON); + } + + /* cancel */ + + button = new BButton(cancel_rect, "", "Cancel", new BMessage(M_CANCEL)); + AddChild(button); + + /* ok */ + + button = new BButton(ok_rect, "", "OK", new BMessage(M_OK)); + AddChild(button); + button->MakeDefault(true); +} + +void JobSetupView::MessageReceived(BMessage *msg) +{ + switch (msg->what) { + case M_RANGE_ALL: + Window()->Lock(); + from_page->SetEnabled(false); + to_page->SetEnabled(false); + Window()->Unlock(); + break; + + case M_RANGE_SELECTION: + Window()->Lock(); + from_page->SetEnabled(true); + to_page->SetEnabled(true); + Window()->Unlock(); + break; + } +} + +bool JobSetupView::UpdateJobData() +{ + int count; + + count = sizeof(surfaces) / sizeof(surfaces[0]); + const SurfaceCap **surface_cap = surfaces; + const char *surface_label = __surface_type->FindMarked()->Label(); + while (count--) { + if (!strcmp((*surface_cap)->label.c_str(), surface_label)) { + __job_data->setSurfaceType((*surface_cap)->surface_type); + break; + } + surface_cap++; + } + + __job_data->setGamma(atof(__gamma->Text())); + + int first_page; + int last_page; + + if (B_CONTROL_ON == __all->Value()) { + first_page = 1; + last_page = -1; + } else { + first_page = atoi(from_page->Text()); + last_page = atoi(to_page->Text()); + } + + __job_data->setFirstPage(first_page); + __job_data->setLastPage(last_page); + + count = __printer_cap->countCap(PrinterCap::PAPERSOURCE); + const PaperSourceCap **paper_source_cap = (const PaperSourceCap **)__printer_cap->enumCap(PrinterCap::PAPERSOURCE); + const char *paper_source_label = __paper_feed->FindMarked()->Label(); + while (count--) { + if (!strcmp((*paper_source_cap)->label.c_str(), paper_source_label)) { + __job_data->setPaperSource((*paper_source_cap)->paper_source); + break; + } + paper_source_cap++; + } + + count = sizeof(nups) / sizeof(nups[0]); + const NupCap **nup_cap = nups; + const char *nup_label = __nup->FindMarked()->Label(); + while (count--) { + if (!strcmp((*nup_cap)->label.c_str(), nup_label)) { + __job_data->setNup((*nup_cap)->nup); + break; + } + nup_cap++; + } + + if (__printer_cap->isSupport(PrinterCap::PRINTSTYLE)) { + __job_data->setPrintStyle((B_CONTROL_ON == __duplex->Value()) ? JobData::DUPLEX : JobData::SIMPLEX); + } + + __job_data->setCopies(atoi(copies->Text())); + + __job_data->setCollate((B_CONTROL_ON == __collate->Value()) ? true : false); + __job_data->setReverse((B_CONTROL_ON == __reverse->Value()) ? true : false); + + __job_data->save(); + return true; +} + +//==================================================================== + +filter_result PrintKeyFilter(BMessage *msg, BHandler **target, BMessageFilter *filter) +{ + + BWindow *window = (BWindow *)filter->Looper(); + JobSetupView *view = (JobSetupView *)window->ChildAt(0); + + if ((*target != view->copies->ChildAt(0)) && + (*target != view->from_page->ChildAt(0)) && + (*target != view->to_page->ChildAt(0))) + { + return B_DISPATCH_MESSAGE; + } + + ulong mods = msg->FindInt32("modifiers"); + if (mods & B_COMMAND_KEY) + return B_DISPATCH_MESSAGE; + + const uchar *bytes = NULL; + if (msg->FindString("bytes", (const char **)&bytes) != B_NO_ERROR) + return B_DISPATCH_MESSAGE; + + long key = bytes[0]; + if (key < '0') { + if ((key != B_TAB) && (key != B_BACKSPACE) && (key != B_ENTER) && + (key != B_LEFT_ARROW) && (key != B_RIGHT_ARROW) && + (key != B_UP_ARROW) && (key != B_DOWN_ARROW)) + return B_SKIP_MESSAGE; + } + if (key > '9') + return B_SKIP_MESSAGE; + return B_DISPATCH_MESSAGE; +} + +//==================================================================== + +JobSetupDlg::JobSetupDlg(JobData *job_data, PrinterData *printer_data, const PrinterCap *printer_cap) + : BWindow(BRect(100, 100, 100 + PRINT_WIDTH, 100 + PRINT_HEIGHT), + "PrintJob Setup", B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL, + B_NOT_RESIZABLE | B_NOT_MINIMIZABLE | B_NOT_ZOOMABLE) +{ + __result = 0; +/* + ostringstream oss; + oss << printer_data->get_printer_name() << " Print"; + SetTitle(oss.str().c_str()); +*/ + Lock(); + JobSetupView *view = new JobSetupView(Bounds(), job_data, printer_data, printer_cap); + AddChild(view); + __filter = new BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE, B_KEY_DOWN, &PrintKeyFilter); + AddCommonFilter(__filter); + Unlock(); + + __semaphore = create_sem(0, "JobSetupSem"); +} + +JobSetupDlg::~JobSetupDlg() +{ + Lock(); + RemoveCommonFilter(__filter); + Unlock(); + delete __filter; +} + +bool JobSetupDlg::QuitRequested() +{ + __result = B_ERROR; + release_sem(__semaphore); + return true; +} + +void JobSetupDlg::MessageReceived(BMessage *msg) +{ + switch (msg->what) { + case M_OK: + Lock(); + ((JobSetupView *)ChildAt(0))->UpdateJobData(); + Unlock(); + __result = B_NO_ERROR; + release_sem(__semaphore); + break; + + case M_CANCEL: + __result = B_ERROR; + release_sem(__semaphore); + break; + + default: + BWindow::MessageReceived(msg); + break; + } +} + +int JobSetupDlg::Go() +{ + Show(); + acquire_sem(__semaphore); + delete_sem(__semaphore); + int value = __result; + Lock(); + Quit(); + return value; +} diff --git a/src/add-ons/print/drivers/canon_lips/libprint/JobSetupDlg.h b/src/add-ons/print/drivers/canon_lips/libprint/JobSetupDlg.h new file mode 100644 index 0000000000..4e19a9915e --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/JobSetupDlg.h @@ -0,0 +1,60 @@ +/* + * JobSetupDlg.cpp + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#ifndef __JOBSETUPDLG_H +#define __JOBSETUPDLG_H + +#include +#include + +class BTextControl; +class BRadioButton; +class BCheckBox; +class BPopUpMenu; +class JobData; +class PrinterData; +class PrinterCap; + +class JobSetupView : public BView { +public: + JobSetupView(BRect frame, JobData *job_data, PrinterData *printer_data, const PrinterCap *printer_cap); + virtual void AttachedToWindow(); + virtual void MessageReceived(BMessage *msg); + bool UpdateJobData(); + +public: + BTextControl *copies; + BTextControl *from_page; + BTextControl *to_page; + +private: + JobData *__job_data; + PrinterData *__printer_data; + const PrinterCap *__printer_cap; + BTextControl *__gamma; + BRadioButton *__all; + BCheckBox *__collate; + BCheckBox *__reverse; + BPopUpMenu *__surface_type; + BPopUpMenu *__paper_feed; + BCheckBox *__duplex; + BPopUpMenu *__nup; +}; + +class JobSetupDlg : public BWindow { +public: + JobSetupDlg(JobData *job_data, PrinterData *printer_data, const PrinterCap *printer_cap); + ~JobSetupDlg(); + virtual bool QuitRequested(); + virtual void MessageReceived(BMessage *message); + int Go(); + +private: + int __result; + long __semaphore; + BMessageFilter *__filter; +}; + +#endif /* __JOBSETUPDLG_H */ diff --git a/src/add-ons/print/drivers/canon_lips/libprint/PageSetupDlg.cpp b/src/add-ons/print/drivers/canon_lips/libprint/PageSetupDlg.cpp new file mode 100644 index 0000000000..8d24502566 --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/PageSetupDlg.cpp @@ -0,0 +1,334 @@ +/* + * PageSetupDlg.cpp + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "PageSetupDlg.h" +#include "JobData.h" +#include "PrinterData.h" +#include "PrinterCap.h" +#include "DbgMsg.h" + +#if (!__MWERKS__ || defined(MSIPL_USING_NAMESPACE)) +using namespace std; +#else +#define std +#endif + +#define PAGESETUP_WIDTH 270 +#define PAGESETUP_HEIGHT 125 + +#define MENU_HEIGHT 16 +#define BUTTON_WIDTH 70 +#define BUTTON_HEIGHT 20 + +#define ORIENT_H 10 +#define ORIENT_V 10 +#define ORIENT_WIDTH 100 +#define ORIENT_HEIGHT 60 +#define PORT_TEXT "Portrait" +#define RAND_TEXT "Landscape" + +#define PAPER_H ORIENT_H + ORIENT_WIDTH + 15 +#define PAPER_V 20 +#define PAPER_WIDTH 200 +#define PAPER_HEIGHT MENU_HEIGHT +#define PAPER_TEXT "Paper Size" + +#define RES_H PAPER_H +#define RES_V PAPER_V + 24 +#define RES_WIDTH 150 +#define RES_HEIGHT MENU_HEIGHT +#define RES_TEXT "Resolution" + +#define OK_H (PAGESETUP_WIDTH - BUTTON_WIDTH - 11) +#define OK_V (PAGESETUP_HEIGHT - BUTTON_HEIGHT - 11) +#define OK_TEXT "OK" + +#define CANCEL_H (OK_H - BUTTON_WIDTH - 12) +#define CANCEL_V OK_V +#define CANCEL_TEXT "Cancel" + +#define PRINT_LINE_V (PAGESETUP_HEIGHT - BUTTON_HEIGHT - 23) + +const BRect ORIENTAION_RECT( + ORIENT_H, + ORIENT_V, + ORIENT_H + ORIENT_WIDTH, + ORIENT_V + ORIENT_HEIGHT); + +const BRect PORT_RECT(10, 15, 80, 14); +const BRect LAND_RECT(10, 35, 80, 14); + +const BRect PAPER_RECT( + PAPER_H, + PAPER_V, + PAPER_H + PAPER_WIDTH, + PAPER_V + PAPER_HEIGHT); + +const BRect RESOLUTION_RECT( + RES_H, + RES_V, + RES_H + RES_WIDTH, + RES_V + RES_HEIGHT); + +const BRect OK_RECT( + OK_H, + OK_V, + OK_H + BUTTON_WIDTH, + OK_V + BUTTON_HEIGHT); + +const BRect CANCEL_RECT( + CANCEL_H, + CANCEL_V, + CANCEL_H + BUTTON_WIDTH, + CANCEL_V + BUTTON_HEIGHT); + +enum MSGS { + M_CANCEL = 1, + M_OK +}; + +PageSetupView::PageSetupView(BRect frame, JobData *job_data, PrinterData *printer_data, const PrinterCap *printer_cap) + : BView(frame, "", B_FOLLOW_ALL, B_WILL_DRAW), __job_data(job_data), __printer_data(printer_data), __printer_cap(printer_cap) +{ + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); +} + +PageSetupView::~PageSetupView() +{ +} + +void PageSetupView::AttachedToWindow() +{ + BMenuItem *item = NULL; + BMenuField *menufield; + BButton *button; + bool marked; + int count; + + /* orientaion */ + + BBox *box = new BBox(ORIENTAION_RECT); + AddChild(box); + box->SetLabel("Orientation"); + + __portrait = new BRadioButton(PORT_RECT, "", PORT_TEXT, NULL); + box->AddChild(__portrait); + + BRadioButton *landscape = new BRadioButton(LAND_RECT, "", RAND_TEXT, NULL); + box->AddChild(landscape); + + if (JobData::PORTRAIT == __job_data->getOrientation()) + __portrait->SetValue(B_CONTROL_ON); + else + landscape->SetValue(B_CONTROL_ON); + + /* paper selection */ + + marked = false; + __paper = new BPopUpMenu(""); + __paper->SetRadioMode(true); + count = __printer_cap->countCap(PrinterCap::PAPER); + PaperCap **paper_cap = (PaperCap **)__printer_cap->enumCap(PrinterCap::PAPER); + while (count--) { + item = new BMenuItem((*paper_cap)->label.c_str(), NULL); + __paper->AddItem(item); + item->SetTarget(this); + if ((*paper_cap)->paper == __job_data->getPaper()) { + item->SetMarked(true); + marked = true; + } + paper_cap++; + } + if (!marked) + item->SetMarked(true); + menufield = new BMenuField(PAPER_RECT, "", PAPER_TEXT, __paper); + AddChild(menufield); + float width = StringWidth(PAPER_TEXT) + 7; + menufield->SetDivider(width); + + /* resolution */ + + marked = false; + __resolution = new BPopUpMenu(""); + __resolution->SetRadioMode(true); + count = __printer_cap->countCap(PrinterCap::RESOLUTION); + ResolutionCap **resolution_cap = (ResolutionCap **)__printer_cap->enumCap(PrinterCap::RESOLUTION); + while (count--) { + item = new BMenuItem((*resolution_cap)->label.c_str(), NULL); + __resolution->AddItem(item); + item->SetTarget(this); + if (((*resolution_cap)->xres == __job_data->getXres()) && ((*resolution_cap)->yres == __job_data->getYres())) { + item->SetMarked(true); + marked = true; + } + resolution_cap++; + } + if (!marked) + item->SetMarked(true); + menufield = new BMenuField(RESOLUTION_RECT, "", RES_TEXT, __resolution); + AddChild(menufield); + menufield->SetDivider(width); + + /* cancel */ + + button = new BButton(CANCEL_RECT, "", CANCEL_TEXT, new BMessage(M_CANCEL)); + AddChild(button); + + /* ok */ + + button = new BButton(OK_RECT, "", OK_TEXT, new BMessage(M_OK)); + AddChild(button); + button->MakeDefault(true); +} + +inline void swap(float *e1, float *e2) +{ + float e = *e1; + *e1 = *e2; + *e2 = e; +} + +bool PageSetupView::UpdateJobData() +{ + if (B_CONTROL_ON == __portrait->Value()) { + __job_data->setOrientation(JobData::PORTRAIT); + } else { + __job_data->setOrientation(JobData::LANDSCAPE); + } + + BRect paper_rect; + BRect printable_rect; + + int count; + + count = __printer_cap->countCap(PrinterCap::PAPER); + PaperCap **paper_cap = (PaperCap **)__printer_cap->enumCap(PrinterCap::PAPER); + const char *paper_label = __paper->FindMarked()->Label(); + while (count--) { + if (!strcmp((*paper_cap)->label.c_str(), paper_label)) { + __job_data->setPaper((*paper_cap)->paper); + paper_rect = (*paper_cap)->paper_rect; + printable_rect = (*paper_cap)->printable_rect; + break; + } + paper_cap++; + } + + count = __printer_cap->countCap(PrinterCap::RESOLUTION); + ResolutionCap **resolution_cap = (ResolutionCap **)__printer_cap->enumCap(PrinterCap::RESOLUTION); + const char *resolution_label = __resolution->FindMarked()->Label(); + while (count--) { + if (!strcmp((*resolution_cap)->label.c_str(), resolution_label)) { + __job_data->setXres((*resolution_cap)->xres); + __job_data->setYres((*resolution_cap)->yres); + break; + } + resolution_cap++; + } + + if (JobData::LANDSCAPE == __job_data->getOrientation()) { + swap(&paper_rect.left, &paper_rect.top); + swap(&paper_rect.right, &paper_rect.bottom); + swap(&printable_rect.left, &printable_rect.top); + swap(&printable_rect.right, &printable_rect.bottom); + } + + __job_data->setScaling(100.0); + __job_data->setPaperRect(paper_rect); + __job_data->setPrintableRect(printable_rect); + + __job_data->save(); + return true; +} + +//==================================================================== + +PageSetupDlg::PageSetupDlg(JobData *job_data, PrinterData *printer_data, const PrinterCap *printer_cap) + : BWindow(BRect(100, 100, 100 + PAGESETUP_WIDTH, 100 + PAGESETUP_HEIGHT), + "Page Setup", B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL, + B_NOT_RESIZABLE | B_NOT_MINIMIZABLE | B_NOT_ZOOMABLE) +{ + __result = 0; +/* + ostringstream oss; + oss << printer_data->get_printer_name() << " Setup"; + SetTitle(title.str().c_str()); +*/ + + Lock(); + PageSetupView *view = new PageSetupView(Bounds(), job_data, printer_data, printer_cap); + AddChild(view); + Unlock(); + + __semaphore = create_sem(0, "PageSetupSem"); +} + +PageSetupDlg::~PageSetupDlg() +{ +} + +bool PageSetupDlg::QuitRequested() +{ + __result = B_ERROR; + release_sem(__semaphore); + return true; +} + +void PageSetupDlg::MessageReceived(BMessage *msg) +{ + switch (msg->what) { + case M_OK: + Lock(); + ((PageSetupView *)ChildAt(0))->UpdateJobData(); + Unlock(); + __result = B_NO_ERROR; + release_sem(__semaphore); + break; + + case M_CANCEL: + __result = B_ERROR; + release_sem(__semaphore); + break; + + default: + BWindow::MessageReceived(msg); + break; + } +} + +int PageSetupDlg::Go() +{ + Show(); + acquire_sem(__semaphore); + delete_sem(__semaphore); + int value = __result; + Lock(); + Quit(); + return value; +} diff --git a/src/add-ons/print/drivers/canon_lips/libprint/PageSetupDlg.h b/src/add-ons/print/drivers/canon_lips/libprint/PageSetupDlg.h new file mode 100644 index 0000000000..be37398b3a --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/PageSetupDlg.h @@ -0,0 +1,48 @@ +/* + * PageSetupDlg.h + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#ifndef __PAGESETUPDLG_H +#define __PAGESETUPDLG_H + +#include +#include + +class BRadioButton; +class BPopUpMenu; +class JobData; +class PrinterData; +class PrinterCap; + +class PageSetupView : public BView { +public: + PageSetupView(BRect frame, JobData *job_data, PrinterData *printer_data, const PrinterCap *printer_cap); + ~PageSetupView(); + virtual void AttachedToWindow(); + bool UpdateJobData(); + +private: + JobData *__job_data; + PrinterData *__printer_data; + const PrinterCap *__printer_cap; + BRadioButton *__portrait; + BPopUpMenu *__paper; + BPopUpMenu *__resolution; +}; + +class PageSetupDlg : public BWindow { +public: + PageSetupDlg(JobData *job_data, PrinterData *printer_data, const PrinterCap *printer_cap); + ~PageSetupDlg(); + virtual bool QuitRequested(); + virtual void MessageReceived(BMessage *message); + int Go(); + +private: + int __result; + long __semaphore; + BMessageFilter *__filter; +}; + +#endif /* __PAGESETUPDLG_H */ diff --git a/src/add-ons/print/drivers/canon_lips/libprint/Pattern.h b/src/add-ons/print/drivers/canon_lips/libprint/Pattern.h new file mode 100644 index 0000000000..0d718bb678 --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/Pattern.h @@ -0,0 +1,57 @@ +const unsigned char pattern16x16_type1[] = { + 0,128, 32,160, 8,136, 40,168, 2,130, 34,162, 10,138, 42,170, + 192, 64,224, 96,200, 72,232,104,194, 66,226, 98,202, 74,234,106, + 48,176, 16,144, 56,184, 24,152, 50,178, 18,146, 58,186, 26,154, + 240,112,208, 80,248,120,216, 88,242,114,210, 82,250,122,218, 90, + 12,140, 44,172, 4,132, 36,164, 14,142, 46,174, 6,134, 38,166, + 204, 76,236,108,196, 68,228,100,206, 78,238,110,198, 70,230,102, + 60,188, 28,156, 52,180, 20,148, 62,190, 30,158, 54,182, 22,150, + 252,124,220, 92,244,116,212, 84,254,126,222, 94,246,118,214, 86, + 3,131, 35,163, 11,139, 43,171, 1,129, 33,161, 9,137, 41,169, + 195, 67,227, 99,203, 75,235,107,193, 65,225, 97,201, 73,233,105, + 51,179, 19,147, 59,187, 27,155, 49,177, 17,145, 57,185, 25,153, + 243,115,211, 83,251,123,219, 91,241,113,209, 81,249,121,217, 89, + 15,143, 47,175, 7,135, 39,167, 13,141, 45,173, 5,133, 37,165, + 207, 79,239,111,199, 71,231,103,205, 77,237,109,197, 69,229,101, + 63,191, 31,159, 55,183, 23,151, 61,189, 29,157, 53,181, 21,149, + 255,127,223, 95,247,119,215, 87,253,125,221, 93,245,117,213, 85 +}; + +const unsigned char pattern16x16_type2[] = { + 153,137,121,105,152,136,120,104,151,135,119,103,150,134,118,102, + 169, 25, 9, 89,168, 24, 8, 88,167, 23, 7, 87,166, 22, 6, 86, + 185, 41, 57, 73,184, 40, 56, 72,183, 39, 55, 71,182, 38, 54, 70, + 201,217,233,249,200,216,232,248,199,215,231,247,198,214,230,246, + 154,138,122,106,145,129,113, 97,144,128,112, 96,149,133,117,101, + 170, 26, 10, 90,161, 17, 1, 81,160, 16, 0, 80,165, 21, 5, 85, + 186, 42, 58, 74,177, 33, 49, 65,176, 32, 48, 64,181, 37, 53, 69, + 202,218,234,250,193,209,225,241,192,208,224,240,197,213,229,245, + 155,139,123,107,146,130,114, 98,147,131,115, 99,148,132,116,100, + 171, 27, 11, 91,162, 18, 2, 82,163, 19, 3, 83,164, 20, 4, 84, + 187, 43, 59, 75,178, 34, 50, 66,179, 35, 51, 67,180, 36, 52, 68, + 203,219,235,251,194,210,226,242,195,211,227,243,196,212,228,244, + 156,140,124,108,157,141,125,109,158,142,126,110,159,143,127,111, + 172, 28, 12, 92,173, 29, 13, 93,174, 30, 14, 94,175, 31, 15, 95, + 188, 44, 60, 76,189, 45, 61, 77,190, 46, 62, 78,191, 47, 63, 79, + 204,220,236,252,205,221,237,253,206,222,238,254,207,223,239,255 +}; + +const unsigned char pattern16x16_type3[] = { + 0, 32,224,192, 2, 34,226,194, 14, 46,238,206, 12, 44,236,204, + 128,160, 80,112,130,162, 82,114,142,174, 94,126,140,172, 92,124, + 240,208, 16, 48,242,210, 18, 50,254,222, 30, 62,252,220, 28, 60, + 64, 96,144,176, 66, 98,146,178, 78,110,158,190, 76,108,156,188, + 8, 40,232,200, 10, 42,234,202, 5, 37,229,197, 7, 39,231,199, + 136,168, 88,120,138,170, 90,122,133,165, 85,117,135,167, 87,119, + 248,216, 24, 56,250,218, 26, 58,245,213, 21, 53,247,215, 23, 55, + 72,104,152,184, 74,106,154,186, 69,101,149,181, 71,103,151,183, + 15, 47,239,207, 13, 45,237,205, 1, 33,225,193, 3, 35,227,195, + 143,175, 95,127,141,173, 93,125,129,161, 81,113,131,163, 83,115, + 255,223, 31, 63,253,221, 29, 61,241,209, 17, 49,243,211, 19, 51, + 79,111,159,191, 77,109,157,189, 65, 97,145,177, 67, 99,147,179, + 4, 36,228,196, 6, 38,230,198, 9, 41,233,201, 11, 43,235,203, + 132,164, 84,116,134,166, 86,118,137,169, 89,121,139,171, 91,123, + 244,212, 20, 52,246,214, 22, 54,249,217, 25, 57,251,219, 27, 59, + 68,100,148,180, 70,102,150,182, 73,105,153,185, 75,107,155,187 +}; + diff --git a/src/add-ons/print/drivers/canon_lips/libprint/Preview.cpp b/src/add-ons/print/drivers/canon_lips/libprint/Preview.cpp new file mode 100644 index 0000000000..b1b086115f --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/Preview.cpp @@ -0,0 +1,53 @@ +/* + * Preview.cpp + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#include +#include "Preview.h" + +#ifdef USE_PREVIEW_FOR_DEBUG + +class PreviewView : public BView { +public: + PreviewView(BRect, BBitmap *); + void Draw(BRect); +private: + BBitmap *__bitmap; +}; + +PreviewView::PreviewView(BRect frame, BBitmap *bitmap) + : BView(frame, "preview", B_FOLLOW_ALL, B_WILL_DRAW) +{ + __bitmap = bitmap; +} + +void PreviewView::Draw(BRect) +{ + DrawBitmap(__bitmap); +} + +PreviewWindow::PreviewWindow(BRect frame, const char *title, BBitmap *bitmap) + : BWindow(frame, title, B_TITLED_WINDOW, 0) +{ + AddChild(new PreviewView(Bounds(), bitmap)); + __semaphore = create_sem(0, "PreviewSem"); +} + +bool PreviewWindow::QuitRequested() +{ + release_sem(__semaphore); + return true; +} + +int PreviewWindow::Go() +{ + Show(); + acquire_sem(__semaphore); + delete_sem(__semaphore); + Lock(); + Quit(); + return 0; +} + +#endif /* USE_PREVIEW_FOR_DEBUG */ diff --git a/src/add-ons/print/drivers/canon_lips/libprint/Preview.h b/src/add-ons/print/drivers/canon_lips/libprint/Preview.h new file mode 100644 index 0000000000..9bf00aa4e9 --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/Preview.h @@ -0,0 +1,29 @@ +/* + * Preview.h + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +//#define USE_PREVIEW_FOR_DEBUG + +#ifdef USE_PREVIEW_FOR_DEBUG +#ifndef __PREVIEW_H +#define __PREVIEW_H + +#include + +class PreviewWindow : public BWindow { +public: + PreviewWindow(BRect, const char *, BBitmap *); + virtual bool QuitRequested(); + int Go(); + +protected: + PreviewWindow(const PreviewWindow &); + PreviewWindow &operator = (const PreviewWindow &); + +private: + long __semaphore; +}; + +#endif /* __PREVIEW_H */ +#endif /* USE_PREVIEW_FOR_DEBUG */ diff --git a/src/add-ons/print/drivers/canon_lips/libprint/PrintProcess.cpp b/src/add-ons/print/drivers/canon_lips/libprint/PrintProcess.cpp new file mode 100644 index 0000000000..e98f0fcc1b --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/PrintProcess.cpp @@ -0,0 +1,163 @@ +/* + * PrintProcess.cpp + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#include +#include +#include + +#include "PrintProcess.h" +#include "DbgMsg.h" + +PictureData::PictureData(BFile *file) +{ + off_t offset; + uchar dummy[40]; + + DBGMSG(("construct PictureData\n")); + DBGMSG(("1: current seek position = 0x%x\n", (int)file->Position())); + + file->Read(&offset, sizeof(offset)); + file->Read(dummy, sizeof(dummy)); + file->Read(&point, sizeof(BPoint)); + file->Read(&rect, sizeof(BRect)); + + picture = new BPicture(); + + DBGMSG(("next picture position = 0x%x\n", (int)offset)); + DBGMSG(("picture_data::point = %f, %f\n", point.x, point.y)); + DBGMSG(("picture_data::rect = %f, %f, %f, %f\n", + rect.left, rect.top, rect.right, rect.bottom)); + DBGMSG(("2: current seek position = 0x%x\n", (int)file->Position())); + + picture->Unflatten(file); + + DBGMSG(("3: current seek position = 0x%x\n", (int)file->Position())); +} + +PictureData::~PictureData() +{ + delete picture; +} + +/*--------------------------------------------------*/ + +PageData::PageData() +{ + __hollow = true; +} + +PageData::PageData(BFile *file, bool reverse) +{ + __file = file; + __reverse = reverse; + __picture_count = 0; + __rest = 0; + __offset = 0; + __hollow = false; + + if (reverse) { + file->Read(&__picture_count, sizeof(long)); + DBGMSG(("picture_count = %d\n", (int)__picture_count)); + __offset = __file->Position(); + off_t o = __offset; + for (long i = 0; i < __picture_count; i++) { + __file->Read(&o, sizeof(o)); + __file->Seek(o, SEEK_SET); + } + } +} + +bool PageData::startEnum() +{ + if (__hollow) + return false; + + if (__offset == 0) { + __file->Read(&__picture_count, sizeof(long)); + DBGMSG(("picture_count = %d\n", (int)__picture_count)); + __offset = __file->Position(); + } else { + __file->Seek(__offset, SEEK_SET); + } + + __rest = __picture_count; + return __picture_count > 0; +} + +bool PageData::enumObject(PictureData **picture_data) +{ + if (__hollow || __picture_count <= 0) { + *picture_data = NULL; + } else { + *picture_data = new PictureData(__file); + if (--__rest > 0) { + return true; + } + } + return false; +} + +/*--------------------------------------------------*/ + +SpoolData::SpoolData( + BFile *file, + int page_count, + int nup, + bool reverse) +{ + DBGMSG(("nup = %d\n", nup)); + DBGMSG(("page_count = %d\n", page_count)); + DBGMSG(("reverse = %s\n", reverse ? "true" : "false")); + + if (reverse) { + if (nup > 1) { + for (int page_index = 0; page_index < page_count; page_index++) { + if (page_index % nup == 0) { + __pages.push_front(new PageData(file, reverse)); + __it = __pages.begin(); + __it++; + } else { + __pages.insert(__it, new PageData(file, reverse)); + } + } + page_count = nup - page_count % nup; + if (page_count < nup) { + while (page_count--) { + __pages.insert(__it, new PageData); + } + } + } else { + while (page_count--) { + __pages.push_front(new PageData(file, reverse)); + } + } + } else { + while (page_count--) { + __pages.push_back(new PageData(file, reverse)); + } + } +} + +SpoolData::~SpoolData() +{ + for (__it = __pages.begin(); __it != __pages.end(); __it++) { + delete (*__it); + } +} + +bool SpoolData::startEnum() +{ + __it = __pages.begin(); + return true; +} + +bool SpoolData::enumObject(PageData **page_data) +{ + *page_data = *__it++; + if (__it == __pages.end()) { + return false; + } + return true; +} diff --git a/src/add-ons/print/drivers/canon_lips/libprint/PrintProcess.h b/src/add-ons/print/drivers/canon_lips/libprint/PrintProcess.h new file mode 100644 index 0000000000..62c6f97227 --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/PrintProcess.h @@ -0,0 +1,64 @@ +/* + * PrintProcess.h + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#ifndef __PRINTPROCESS_H +#define __PRINTPROCESS_H + +#include +#include +#include + +#include +#include + +#if (!__MWERKS__ || defined(MSIPL_USING_NAMESPACE)) +using namespace std; +#else +#define std +#endif + +class BFile; +class BPicture; + +class PictureData { +public: + PictureData(BFile *file); + ~PictureData(); + BPoint point; + BRect rect; + BPicture *picture; +}; + +class PageData { +public: + PageData(); + PageData(BFile *file, bool reverse); + bool startEnum(); + bool enumObject(PictureData **); + +private: + BFile *__file; + bool __reverse; + int __picture_count; + int __rest; + off_t __offset; + bool __hollow; +}; + +typedef list PageDataList; + +class SpoolData { +public: + SpoolData(BFile *file, int page_count, int nup, bool reverse); + ~SpoolData(); + bool startEnum(); + bool enumObject(PageData **); + +private: + PageDataList __pages; + PageDataList::iterator __it; +}; + +#endif /* __PRINTPROCESS_H */ diff --git a/src/add-ons/print/drivers/canon_lips/libprint/PrinterCap.cpp b/src/add-ons/print/drivers/canon_lips/libprint/PrinterCap.cpp new file mode 100644 index 0000000000..886d072078 --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/PrinterCap.cpp @@ -0,0 +1,45 @@ +/* + * PrinterCap.cpp + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#include "PrinterCap.h" + +PrinterCap::PrinterCap(const PrinterData *printer_data) + : __printer_data(printer_data), __printer_id(UNKNOWN_PRINTER) +{ +} + +PrinterCap::~PrinterCap() +{ +} + +/* +PrinterCap::PrinterCap(const PrinterCap &printer_cap) +{ + __printer_data = printer_cap.__printer_data; + __printer_id = printer_cap.__printer_id; +} + +PrinterCap::PrinterCap &operator = (const PrinterCap &printer_cap) +{ + __printer_data = printer_cap.__printer_data; + __printer_id = printer_cap.__printer_id; + return *this; +} +*/ + +const BaseCap *PrinterCap::getDefaultCap(CAPID id) const +{ + int count = countCap(id); + if (count > 0) { + const BaseCap **base_cap = enumCap(id); + while (count--) { + if ((*base_cap)->is_default) { + return *base_cap; + } + base_cap++; + } + } + return NULL; +} diff --git a/src/add-ons/print/drivers/canon_lips/libprint/PrinterCap.h b/src/add-ons/print/drivers/canon_lips/libprint/PrinterCap.h new file mode 100644 index 0000000000..9be75bd937 --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/PrinterCap.h @@ -0,0 +1,117 @@ +/* + * PrinterCap.h + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#ifndef __PRINTERCAP_H +#define __PRINTERCAP_H + +#include +#include +#include "JobData.h" + +#if (!__MWERKS__ || defined(MSIPL_USING_NAMESPACE)) +using namespace std; +#else +#define std +#endif + +#define UNKNOWN_PRINTER 0 + +struct BaseCap { + string label; + bool is_default; + BaseCap(const string &n, bool d) : label(n), is_default(d) {} +}; + +struct PaperCap : public BaseCap { + JobData::PAPER paper; + BRect paper_rect; + BRect printable_rect; + PaperCap(const string &n, bool d, JobData::PAPER p, const BRect &r1, const BRect &r2) + : BaseCap(n, d), paper(p), paper_rect(r1), printable_rect(r2) {} +}; + +struct PaperSourceCap : public BaseCap { + JobData::PAPERSOURCE paper_source; + PaperSourceCap(const string &n, bool d, JobData::PAPERSOURCE f) + : BaseCap(n, d), paper_source(f) {} +}; + +struct ResolutionCap : public BaseCap { + int xres; + int yres; + ResolutionCap(const string &n, bool d, int x, int y) + : BaseCap(n, d), xres(x), yres(y) {} +}; + +struct OrientationCap : public BaseCap { + JobData::ORIENTATION orientation; + OrientationCap(const string &n, bool d, JobData::ORIENTATION o) + : BaseCap(n, d), orientation(o) {} +}; + +struct PrintStyleCap : public BaseCap { + JobData::PRINTSTYLE print_style; + PrintStyleCap(const string &n, bool d, JobData::PRINTSTYLE x) + : BaseCap(n, d), print_style(x) {} +}; + +struct BindingLocationCap : public BaseCap { + JobData::BINDINGLOCATION binding_location; + BindingLocationCap(const string &n, bool d, JobData::BINDINGLOCATION b) + : BaseCap(n, d), binding_location(b) {} +}; + +class PrinterData; + +class PrinterCap { +public: + PrinterCap(const PrinterData *printer_data); + virtual ~PrinterCap(); +/* + PrinterCap(const PrinterCap &printer_cap); + PrinterCap &operator = (const PrinterCap &printer_cap); +*/ + enum CAPID { + PAPER, + PAPERSOURCE, + RESOLUTION, + ORIENTATION, + PRINTSTYLE, + BINDINGLOCATION + }; + + virtual int countCap(CAPID) const = 0; + virtual bool isSupport(CAPID) const = 0; + virtual const BaseCap **enumCap(CAPID) const = 0; + const BaseCap *getDefaultCap(CAPID) const; + int getPrinterId() const; + +protected: + PrinterCap(const PrinterCap &); + PrinterCap &operator = (const PrinterCap &); + const PrinterData *getPrinterData() const; + void setPrinterId(int id); + +private: + const PrinterData *__printer_data; + int __printer_id; +}; + +inline const PrinterData *PrinterCap::getPrinterData() const +{ + return __printer_data; +} + +inline int PrinterCap::getPrinterId() const +{ + return __printer_id; +} + +inline void PrinterCap::setPrinterId(int id) +{ + __printer_id = id; +} + +#endif /* __PRINTERCAP_H */ diff --git a/src/add-ons/print/drivers/canon_lips/libprint/PrinterData.cpp b/src/add-ons/print/drivers/canon_lips/libprint/PrinterData.cpp new file mode 100644 index 0000000000..3ba1cd49df --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/PrinterData.cpp @@ -0,0 +1,97 @@ +/* + * PrinterData.cpp + * Copyright 1999-2000 Y.Takagi All Rights Reserved. + */ + +#include +#include +#include +#include + +#include "PrinterData.h" + +const char *PD_DRIVER_NAME = "Driver Name"; +const char *PD_PRINTER_NAME = "Printer Name"; +const char *PD_COMMENTS = "Comments"; +const char *PD_TRANSPORT = "transport"; + +PrinterData::PrinterData(BNode *node) +{ + if (node) { + load(node); + } +} + +PrinterData::~PrinterData() +{ +} + +/* +PrinterData::PrinterData(const PrinterData &printer_data) +{ + __driver_name = printer_data.__driver_name; + __printer_name = printer_data.__printer_name; + __comments = printer_data.__comments; + __transport = printer_data.__transport; + __node = printer_data.__node; +} + +PrinterData &PrinterData::operator = (const PrinterData &printer_data) +{ + __driver_name = printer_data.__driver_name; + __printer_name = printer_data.__printer_name; + __comments = printer_data.__comments; + __transport = printer_data.__transport; + __node = printer_data.__node; + return *this; +} +*/ + +void PrinterData::load(BNode *node) +{ + char buffer[512]; + + __node = node; + + __node->ReadAttr(PD_DRIVER_NAME, B_STRING_TYPE, 0, buffer, sizeof(buffer)); + __driver_name = buffer; + __node->ReadAttr(PD_PRINTER_NAME, B_STRING_TYPE, 0, buffer, sizeof(buffer)); + __printer_name = buffer; + __node->ReadAttr(PD_COMMENTS, B_STRING_TYPE, 0, buffer, sizeof(buffer)); + __comments = buffer; + __node->ReadAttr(PD_TRANSPORT, B_STRING_TYPE, 0, buffer, sizeof(buffer)); + __transport = buffer; +} + +/* +void PrinterData::save(BNode *node) +{ + BDirectory dir; + if (node == NULL) { + BPath path; + ::find_directory(B_USER_PRINTERS_DIRECTORY, &path, false); + path.Append(__printer_name.c_str()); + BDirectory base_dir; + base_dir.CreateDirectory(path.Path(), &dir); + node = &dir; + } + node->WriteAttr(PD_DRIVER_NAME, B_STRING_TYPE, 0, driver_name_.c_str(), driver_name_.length() + 1); + node->WriteAttr(PD_PRINTER_NAME, B_STRING_TYPE, 0, printer_name_.c_str(), printer_name_.length() + 1); + node->WriteAttr(PD_COMMENTS, B_STRING_TYPE, 0, comments_.c_str(), comments_.length() + 1); +} +*/ + +bool PrinterData::getPath(char *buf) const +{ + if (__node) { + node_ref nref; + __node->GetNodeRef(&nref); + BDirectory dir; + dir.SetTo(&nref); + BPath path(&dir, NULL); + strcpy(buf, path.Path()); + return true; + } + *buf = '\0'; + return false; +} diff --git a/src/add-ons/print/drivers/canon_lips/libprint/PrinterData.h b/src/add-ons/print/drivers/canon_lips/libprint/PrinterData.h new file mode 100644 index 0000000000..b2ed002dab --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/PrinterData.h @@ -0,0 +1,84 @@ +/* + * PrinterData.h + * Copyright 1999-2000 Y.Takagi All Rights Reserved. + */ + +#ifndef __PRINTERDATA_H +#define __PRINTERDATA_H + +#include +#include + +#if (!__MWERKS__ || defined(MSIPL_USING_NAMESPACE)) +using namespace std; +#else +#define std +#endif + +class BNode; + +class PrinterData { +public: + PrinterData(BNode *node = NULL); + ~PrinterData(); +/* + PrinterData(const PrinterData &printer_data); + PrinterData &operator = (const PrinterData &printer_data); +*/ + void load(BNode *node); +// void save(BNode *node = NULL); + + const string &getDriverName() const; + const string &getPrinterName() const; + const string &getComments() const; + const string &getTransport() const; + +// void setDriverName(const char *s) { __driver_name = driver_name; } + void setPrinterName(const char *printer_name); + void setComments(const char *comments); + + bool getPath(char *path) const; + +protected: + PrinterData(const PrinterData &printer_data); + PrinterData &operator = (const PrinterData &printer_data); + +private: + string __driver_name; + string __printer_name; + string __comments; + string __transport; + BNode *__node; +}; + +inline const string &PrinterData::getDriverName() const +{ + return __driver_name; +} + +inline const string &PrinterData::getPrinterName() const +{ + return __printer_name; +} + +inline const string &PrinterData::getComments() const +{ + return __comments; +} + +inline const string &PrinterData::getTransport() const +{ + return __transport; +} + +inline void PrinterData::setPrinterName(const char *printer_name) +{ + __printer_name = printer_name; +} + +inline void PrinterData::setComments(const char *comments) +{ + __comments = comments; +} + +#endif // __PRINTERDATA_H diff --git a/src/add-ons/print/drivers/canon_lips/libprint/Transport.cpp b/src/add-ons/print/drivers/canon_lips/libprint/Transport.cpp new file mode 100644 index 0000000000..a5129460fc --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/Transport.cpp @@ -0,0 +1,111 @@ +/* + * Transport.cpp + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#include +#include +#include +#include +#include +#include + +#include "Transport.h" +#include "PrinterData.h" +#include "DbgMsg.h" + +#if (!__MWERKS__ || defined(MSIPL_USING_NAMESPACE)) +using namespace std; +#else +#define std +#endif + +Transport::Transport(const PrinterData *printer_data) + : __image(-1), __init_transport(0), __exit_transport(0), __data_stream(0), __abort(false) +{ + BPath path; + + if (B_OK == find_directory(B_USER_ADDONS_DIRECTORY, &path)) { + path.Append("Print/transport"); + path.Append(printer_data->getTransport().c_str()); + DBGMSG(("load_add_on: %s\n", path.Path())); + __image = load_add_on(path.Path()); + } + if (__image < 0) { + if (B_OK == find_directory(B_BEOS_ADDONS_DIRECTORY, &path)) { + path.Append("Print/transport"); + path.Append(printer_data->getTransport().c_str()); + DBGMSG(("load_add_on: %s\n", path.Path())); + __image = load_add_on(path.Path()); + } + } + + if (__image < 0) { + set_last_error("cannot load a transport add-on"); + return; + } + + DBGMSG(("image id = %d\n", (int)__image)); + + get_image_symbol(__image, "init_transport", B_SYMBOL_TYPE_TEXT, (void **)&__init_transport); + get_image_symbol(__image, "exit_transport", B_SYMBOL_TYPE_TEXT, (void **)&__exit_transport); + + if (__init_transport == NULL) { + set_last_error("get_image_symbol failed."); + DBGMSG(("init_transport is NULL\n")); + } + + if (__exit_transport == NULL) { + set_last_error("get_image_symbol failed."); + DBGMSG(("exit_transport is NULL\n")); + } + + if (__init_transport) { + char spool_path[256]; + printer_data->getPath(spool_path); + BMessage *msg = new BMessage('TRIN'); + msg->AddString("printer_file", spool_path); + __data_stream = (*__init_transport)(msg); + delete msg; + if (__data_stream == 0) { + set_last_error("init_transport failed."); + } + } +} + +Transport::~Transport() +{ + if (__exit_transport) { + (*__exit_transport)(); + } + if (__image >= 0) { + unload_add_on(__image); + } +} + +bool Transport::check_abort() const +{ + return __data_stream == 0; +} + +const string &Transport::last_error() const +{ + return __last_error_string; +} + +void Transport::set_last_error(const char *e) +{ + __last_error_string = e; + __abort = true; +} + +void Transport::write(const void *buffer, size_t size) throw(TransportException) +{ + if (__data_stream) { + if (size == (size_t)__data_stream->Write(buffer, size)) { + return; + } + set_last_error("BDataIO::Write failed."); + } + throw TransportException(last_error()); +} diff --git a/src/add-ons/print/drivers/canon_lips/libprint/Transport.h b/src/add-ons/print/drivers/canon_lips/libprint/Transport.h new file mode 100644 index 0000000000..8e0b5369c6 --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/Transport.h @@ -0,0 +1,56 @@ +/* + * Transport.h + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#ifndef __TRANSPORT_H +#define __TRANSPORT_H + +#include +#include + +class BDataIO; +class PrinterData; + +#if (!__MWERKS__ || defined(MSIPL_USING_NAMESPACE)) +using namespace std; +#else +#define std +#endif + +extern "C" { + typedef BDataIO *(*PFN_init_transport)(BMessage *); + typedef void (*PFN_exit_transport)(void); +} + +class TransportException { +private: + string __str; +public: + TransportException(const string &what_arg) : __str(what_arg) {} + const char *what() const { return __str.c_str(); } +}; + +class Transport { +public: + Transport(const PrinterData *printer_data); + ~Transport(); + void write(const void *buffer, size_t size) throw(TransportException); + bool check_abort() const; + const string &last_error() const; + +protected: + void set_last_error(const char *e); + Transport(const Transport &); + Transport &operator = (const Transport &); + +private: + image_id __image; + PFN_init_transport __init_transport; + PFN_exit_transport __exit_transport; + BDataIO *__data_stream; + bool __abort; + string __last_error_string; +}; + +#endif // __TRANSPORT_H diff --git a/src/add-ons/print/drivers/canon_lips/libprint/UIDriver.cpp b/src/add-ons/print/drivers/canon_lips/libprint/UIDriver.cpp new file mode 100644 index 0000000000..f17680141f --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/UIDriver.cpp @@ -0,0 +1,66 @@ +/* + * UIDriver.cpp + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#include + +#include "UIDriver.h" +#include "JobData.h" +#include "PrinterData.h" +#include "JobSetupDlg.h" +#include "PageSetupDlg.h" +#include "DbgMsg.h" + +UIDriver::UIDriver(BMessage *msg, PrinterData *printer_data, const PrinterCap *printer_cap) + : __msg(msg), __printer_data(printer_data), __printer_cap(printer_cap) +{ +} + +UIDriver::~UIDriver() +{ +} + +BMessage *UIDriver::configPage() +{ + BMessage *clone_msg = new BMessage(*__msg); + JobData *job_data = new JobData(clone_msg, __printer_cap); + + if (doPageSetup(job_data,__printer_data, __printer_cap) < 0) { + delete clone_msg; + clone_msg = NULL; + } else { + clone_msg->what = 'okok'; + } + + delete job_data; + return clone_msg; +} + +BMessage *UIDriver::configJob() +{ + BMessage *clone_msg = new BMessage(*__msg); + JobData *job_data = new JobData(clone_msg, __printer_cap); + + if (doJobSetup(job_data, __printer_data, __printer_cap) < 0) { + delete clone_msg; + clone_msg = NULL; + } else { + clone_msg->what = 'okok'; + } + + delete job_data; + return clone_msg; +} + +long UIDriver::doPageSetup(JobData *job_data, PrinterData *printer_data, const PrinterCap *printer_cap) +{ + PageSetupDlg *dlg = new PageSetupDlg(job_data, printer_data, printer_cap); + return dlg->Go(); +} + +long UIDriver::doJobSetup(JobData *job_data, PrinterData *printer_data, const PrinterCap *printer_cap) +{ + JobSetupDlg *dlg = new JobSetupDlg(job_data, printer_data, printer_cap); + return dlg->Go(); +} diff --git a/src/add-ons/print/drivers/canon_lips/libprint/UIDriver.h b/src/add-ons/print/drivers/canon_lips/libprint/UIDriver.h new file mode 100644 index 0000000000..ca2cf098ec --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/UIDriver.h @@ -0,0 +1,34 @@ +/* + * UIDriver.h + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#ifndef __UIDRIVER_H +#define __UIDRIVER_H + +class BMessage; +class PrinterData; +class PrinterCap; +class JobData; + +class UIDriver { +public: + UIDriver(BMessage *msg, PrinterData *printer_data, const PrinterCap *printer_cap); + virtual ~UIDriver(); + BMessage *configPage(); + BMessage *configJob(); + +protected: + virtual long doPageSetup(JobData *job_data, PrinterData *printer_data, const PrinterCap *printer_cap); + virtual long doJobSetup(JobData *job_data, PrinterData *printer_data, const PrinterCap *printer_cap); + + UIDriver(const UIDriver &); + UIDriver &operator = (const UIDriver &); + +private: + BMessage *__msg; + PrinterData *__printer_data; + const PrinterCap *__printer_cap; +}; + +#endif /* __UIDRIVER_H */ diff --git a/src/add-ons/print/drivers/canon_lips/libprint/ValidRect.cpp b/src/add-ons/print/drivers/canon_lips/libprint/ValidRect.cpp new file mode 100644 index 0000000000..e2ba0eb022 --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/ValidRect.cpp @@ -0,0 +1,253 @@ +/* + * ValidRect.cpp + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#include +#include "ValidRect.h" + +bool get_valid_line_RGB32( + const uchar *bits, + const rgb_color *, + int width, + int *left, + int *right) +{ + int i = 0; + rgb_color c; + const rgb_color *ptr = (const rgb_color *)bits; + + while (i < *left) { + c = *ptr++; + if (c.red != 0xff || c.green != 0xff || c.blue != 0xff) { + *left = i; + break; + } + i++; + } + + if (i == width) { + return false; + } + + i = width - 1; + ptr = (const rgb_color *)bits + width - 1; + + while (i > *right) { + c = *ptr--; + if (c.red != 0xff || c.green != 0xff || c.blue != 0xff) { + *right = i; + break; + } + i--; + } + return true; +} + +bool get_valid_line_CMAP8( + const uchar *bits, + const rgb_color *palette, + int width, + int *left, + int *right) +{ + int i = 0; + rgb_color c; + const uchar *ptr = bits; + + while (i < *left) { + c = palette[*ptr++]; + if (c.red != 0xff || c.green != 0xff || c.blue != 0xff) { + *left = i; + break; + } + i++; + } + + if (i == width) { + return false; + } + + i = width - 1; + ptr = bits + width - 1; + + while (i > *right) { + c = palette[*ptr--]; + if (c.red != 0xff || c.green != 0xff || c.blue != 0xff) { + *right = i; + break; + } + i--; + } + return true; +} + +bool get_valid_line_GRAY8( + const uchar *bits, + const rgb_color *, + int width, + int *left, + int *right) +{ + int i = 0; + const uchar *ptr = bits; + + while (i < *left) { + if (*ptr++) { + *left = i; + break; + } + i++; + } + + if (i == width) { + return false; + } + + i = width - 1; + ptr = bits + width - 1; + + while (i > *right) { + if (*ptr--) { + *right = i; + break; + } + i--; + } + return true; +} + +bool get_valid_line_GRAY1( + const uchar *bits, + const rgb_color *, + int width, + int *left, + int *right) +{ + int i = 0; + const uchar *ptr = bits; + + while (i < *left) { + if (*ptr++) { + *left = i; + break; + } + i += 8; + } + + if (i == width) { + return false; + } + + i = width - 1; + ptr = bits + ((width - 1) + 7) / 8; + + while (i > *right) { + if (*ptr--) { + *right = i; + break; + } + i -= 8; + } + return true; +} + +typedef bool (*PFN_GET_VALID_LINE)(const uchar *, const rgb_color *, int, int *, int *); + +bool get_valid_rect(BBitmap *a_bitmap, const rgb_color *palette, RECT *rc) +{ + int width = rc->right - rc->left + 1; + int height = rc->bottom - rc->top + 1; + int delta = a_bitmap->BytesPerRow(); + + int left = width; + int right = 0; + int top = 0; + int bottom = 0; + + PFN_GET_VALID_LINE get_valid_line; + + switch (a_bitmap->ColorSpace()) { + case B_RGB32: + case B_RGB32_BIG: + get_valid_line = get_valid_line_RGB32; + break; + case B_CMAP8: + get_valid_line = get_valid_line_CMAP8; + break; + case B_GRAY8: + get_valid_line = get_valid_line_GRAY8; + break; + case B_GRAY1: + get_valid_line = get_valid_line_GRAY1; + break; + default: + get_valid_line = get_valid_line_GRAY1; + break; + }; + + int i = 0; + uchar *ptr = (uchar *)a_bitmap->Bits(); + + while (i < height) { + if (get_valid_line(ptr, palette, width, &left, &right)) { + top = i; + break; + } + ptr += delta; + i++; + } + + if (i == height) { + return false; + } + + int j = height - 1; + ptr = (uchar *)a_bitmap->Bits() + (height - 1) * delta; + bool found_boundary = false; + + while (j >= i) { + if (get_valid_line(ptr, palette, width, &left, &right)) { + if (!found_boundary) { + bottom = j; + found_boundary = true; + } + } + ptr -= delta; + j--; + } + + rc->left = left; + rc->top = top; + rc->right = right; + rc->bottom = bottom; + + return true; +} + +int color_space2pixel_depth(color_space cs) +{ + int pixel_depth; + + switch (cs) { + case B_GRAY1: /* Y0[0],Y1[0],Y2[0],Y3[0],Y4[0],Y5[0],Y6[0],Y7[0] */ + pixel_depth = 1; + break; + case B_GRAY8: /* Y[7:0] */ + case B_CMAP8: /* D[7:0] */ + pixel_depth = 8; + break; + case B_RGB15: /* G[2:0],B[4:0] -[0],R[4:0],G[4:3] */ + case B_RGB15_BIG: /* -[0],R[4:0],G[4:3] G[2:0],B[4:0] */ + pixel_depth = 16; + break; + case B_RGB32: /* B[7:0] G[7:0] R[7:0] -[7:0] */ + case B_RGB32_BIG: /* -[7:0] R[7:0] G[7:0] B[7:0] */ + pixel_depth = 32; + break; + default: + pixel_depth = 0; + break; + } + return pixel_depth; +} diff --git a/src/add-ons/print/drivers/canon_lips/libprint/ValidRect.h b/src/add-ons/print/drivers/canon_lips/libprint/ValidRect.h new file mode 100644 index 0000000000..b737a68633 --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/ValidRect.h @@ -0,0 +1,24 @@ +/* + * ValidRect.h + * Copyright 1999-2000 Y.Takagi All Rights Reserved. + */ + +#ifndef __VALIDRECT_H +#define __VALIDRECT_H + +#include + +class BBitmap; + +struct RECT { + int left; + int top; + int right; + int bottom; +}; + +bool get_valid_rect(BBitmap *bitmap, const rgb_color *palette, RECT *rc); + +int color_space2pixel_depth(color_space cs); + +#endif // __VALIDRECT_H diff --git a/src/add-ons/print/drivers/canon_lips/libprint/tools/make_pattern.cpp b/src/add-ons/print/drivers/canon_lips/libprint/tools/make_pattern.cpp new file mode 100644 index 0000000000..e4e7e3e681 --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/tools/make_pattern.cpp @@ -0,0 +1,90 @@ +/* + * make_pattern.cpp + * Copyright 2000 Y.Takagi All Rights Reserved. + */ + +#include +#include + +using namespace std; + +#define MAX_HORTZ 4 +#define MAX_VERT 4 +#define MAX_ELEMENT (MAX_HORTZ * MAX_VERT) + +#include "original_dither_pattern.h" + +void create_index_table(const unsigned char *p1, unsigned char *p2) +{ + for (int i = 0 ; i < MAX_ELEMENT ; i++) { + p2[*p1] = i; + p1++; + } +} + +inline int index2horz(int index) +{ + return index % MAX_HORTZ; +} + +inline int index2vert(int index) +{ + return index / MAX_HORTZ; +} + +void create_pattern16x16(const unsigned char *pattern4x4, unsigned char *pattern16x16) +{ + unsigned char value2index[MAX_ELEMENT]; + create_index_table(pattern4x4, value2index); + + for (int i = 0 ; i < MAX_ELEMENT ; i++) { + int index = value2index[i]; + int h = index2horz(index); + int v = index2vert(index); + for (int j = 0 ; j < MAX_ELEMENT ; j++) { + int index2 = value2index[j]; + int h2 = index2horz(index2) * 4 + h; + int v2 = index2vert(index2) * 4 + v; + pattern16x16[h2 + v2 * MAX_ELEMENT] = j + i * MAX_ELEMENT; + } + } +} + +void print_pattern(ostream &os, const char *name, const unsigned char *pattern) +{ + os << "const unsigned char " << name << "[] = {" << '\n' << '\t'; + for (int i = 0 ; i < 256 ; i++) { + os << setw(3) << (int)pattern[i]; + if (i == MAX_ELEMENT * MAX_ELEMENT - 1) { + os << '\n'; + } else { + os << ','; + if (i % MAX_ELEMENT == MAX_ELEMENT - 1) { + os << '\n' << '\t'; + } + } + } + os << "};" << '\n'; +} + +int main() +{ + unsigned char pattern16x16_type1[MAX_ELEMENT * MAX_ELEMENT]; + create_pattern16x16(pattern4x4_type1, pattern16x16_type1); + print_pattern(cout, "pattern16x16_type1", pattern16x16_type1); + + cout << endl; + + unsigned char pattern16x16_type2[MAX_ELEMENT * MAX_ELEMENT]; + create_pattern16x16(pattern4x4_type2, pattern16x16_type2); + print_pattern(cout, "pattern16x16_type2", pattern16x16_type2); + + cout << endl; + + unsigned char pattern16x16_type3[MAX_ELEMENT * MAX_ELEMENT]; + create_pattern16x16(pattern4x4_type3, pattern16x16_type3); + print_pattern(cout, "pattern16x16_type3", pattern16x16_type3); + + cout << endl; + return 0; +} diff --git a/src/add-ons/print/drivers/canon_lips/libprint/tools/original_dither_pattern.h b/src/add-ons/print/drivers/canon_lips/libprint/tools/original_dither_pattern.h new file mode 100644 index 0000000000..b203a55204 --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/libprint/tools/original_dither_pattern.h @@ -0,0 +1,24 @@ +/* + * These patterns are defined referring to Japanese Monthly C Magazine (May 2000 Vol.12 No.5). + */ + +const unsigned char pattern4x4_type1[MAX_ELEMENT] = { + 0, 8, 2, 10, + 12, 4, 14, 6, + 3, 11, 1, 9, + 15, 7, 13, 5 +}; + +const unsigned char pattern4x4_type2[MAX_ELEMENT] = { + 9, 8, 7, 6, + 10, 1, 0, 5, + 11, 2, 3, 4, + 12, 13, 14, 15 +}; + +const unsigned char pattern4x4_type3[MAX_ELEMENT] = { + 0, 2, 14, 12, + 8, 10, 5, 7, + 15, 13, 1, 3, + 4, 6, 9, 11 +}; diff --git a/src/add-ons/print/drivers/canon_lips/lips3/Compress3.cpp b/src/add-ons/print/drivers/canon_lips/lips3/Compress3.cpp new file mode 100644 index 0000000000..50cbfce004 --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/lips3/Compress3.cpp @@ -0,0 +1,97 @@ +/* + * Compress3.cpp + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +//#define DBG_CON_STREAM + +#ifdef DBG_CON_STREAM +#include +using namespace std; +#endif + +#include "Compress3.h" + +#define PACK_TYPE 2 + +int compress3(unsigned char *pOut, unsigned char *pIn, int n) +{ + int count; + int count_byte; + unsigned char *pBase; + unsigned char *pLast; + unsigned char keep; + + count = 0; + count_byte = 0; + + keep = ~(*pIn); + pLast = pIn + n; + + for (pBase = pIn; (pBase < pLast) && (count_byte < n) ; pBase++) { + if (*pBase == keep) { + if (count < 0xff + PACK_TYPE) { + count++; + } else { + *pOut++ = keep; + *pOut++ = count - PACK_TYPE; + count = 1; + keep = *pOut++ = *pBase; + count_byte += 3; + } + } else { + if (count > 1) { + *pOut++ = keep; + *pOut++ = count - PACK_TYPE; + count_byte += 2; + } + count = 1; + keep = *pOut++ = *pBase; + count_byte++; + } + } + + if (count > 1) { + if ((count_byte + 2) < n) { + *pOut++ = keep; + *pOut++ = count - PACK_TYPE; + count_byte += 2; + } else { + count_byte = n; + } + } + + return count_byte; +} + +#ifdef DBG_CON_STREAM +int main(int argc, char **argv) +{ + if (argc < 2) { + return -1; + } + + ifstream ifs(*++argv, ios::binary | ios::nocreate); + if (!ifs) { + return -1; + } + + ifs.seekg(0, ios::end); + long size = ifs.tellg(); + ifs.seekg(0, ios::beg); + + unsigned char *pIn = new unsigned char[size]; + unsigned char *pOut = new unsigned char[size * 3]; + + ifs.read(pIn, size); + + int cnt = PackBits(pOut, pIn, size); + + ofstream ofs("test.bin", ios::binary); + ofs.write(pOut, cnt); + + delete [] pIn; + delete [] pOut; + +} +#endif diff --git a/src/add-ons/print/drivers/canon_lips/lips3/Compress3.h b/src/add-ons/print/drivers/canon_lips/lips3/Compress3.h new file mode 100644 index 0000000000..64a9b79352 --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/lips3/Compress3.h @@ -0,0 +1,11 @@ +/* + * Compress3.h + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#ifndef __COMPRESS3_H +#define __COMPRESS3_H + +int compress3(unsigned char *out, unsigned char *in, int bytes); + +#endif /* __COMPRESS3_H */ diff --git a/src/add-ons/print/drivers/canon_lips/lips3/Lips3.cpp b/src/add-ons/print/drivers/canon_lips/lips3/Lips3.cpp new file mode 100644 index 0000000000..4fdcbe2217 --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/lips3/Lips3.cpp @@ -0,0 +1,424 @@ +/* + * Lips3.cpp + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#include +#include +#include +#include +#include "Lips3.h" +#include "UIDriver.h" +#include "Compress3.h" +#include "JobData.h" +#include "PrinterData.h" +#include "Lips3Cap.h" +#include "Halftone.h" +#include "ValidRect.h" +#include "DbgMsg.h" + +#if (!__MWERKS__ || defined(MSIPL_USING_NAMESPACE)) +using namespace std; +#else +#define std +#endif + +LIPS3Driver::LIPS3Driver(BMessage *msg, PrinterData *printer_data, const PrinterCap *printer_cap) + : GraphicsDriver(msg, printer_data, printer_cap) +{ + __halftone = NULL; +} + +bool LIPS3Driver::startDoc() +{ + try { + beginTextMode(); + jobStart(); + softReset(); + sizeUnitMode(); + selectSizeUnit(); + selectPageFormat(); + paperFeedMode(); + disableAutoFF(); + setNumberOfCopies(); + __halftone = new Halftone(getJobData()->getSurfaceType(), getJobData()->getGamma()); + return true; + } + catch (TransportException &err) { + return false; + } +} + +bool LIPS3Driver::startPage(int) +{ + try { + __current_x = 0; + __current_y = 0; + memorizedPosition(); + return true; + } + catch (TransportException &err) { + return false; + } +} + +bool LIPS3Driver::endPage(int) +{ + try { + formFeed(); + return true; + } + catch (TransportException &err) { + return false; + } +} + +bool LIPS3Driver::endDoc(bool) +{ + try { + if (__halftone) { + delete __halftone; + } + jobEnd(); + return true; + } + catch (TransportException &err) { + return false; + } +} + +bool LIPS3Driver::nextBand(BBitmap *bitmap, BPoint *offset) +{ + DBGMSG(("> nextBand\n")); + + try { + BRect bounds = bitmap->Bounds(); + + RECT rc; + rc.left = (int)bounds.left; + rc.top = (int)bounds.top; + rc.right = (int)bounds.right; + rc.bottom = (int)bounds.bottom; + + int height = rc.bottom - rc.top + 1; + + int x = (int)offset->x; + int y = (int)offset->y; + + int page_height = getPageHeight(); + + if (y + height > page_height) { + height = page_height - y; + } + + rc.bottom = height - 1; + + DBGMSG(("height = %d\n", height)); + DBGMSG(("x = %d\n", x)); + DBGMSG(("y = %d\n", y)); + + if (get_valid_rect(bitmap, __halftone->getPalette(), &rc)) { + + DBGMSG(("validate rect = %d, %d, %d, %d\n", + rc.left, rc.top, rc.right, rc.bottom)); + + x = rc.left; + y += rc.top; + + int width = rc.right - rc.left + 1; + int widthByte = (width + 7) / 8; /* byte boundary */ + int height = rc.bottom - rc.top + 1; + int in_size = widthByte * height; + int out_size = (in_size * 6 + 4) / 5; + int delta = bitmap->BytesPerRow(); + + DBGMSG(("width = %d\n", width)); + DBGMSG(("widthByte = %d\n", widthByte)); + DBGMSG(("height = %d\n", height)); + DBGMSG(("in_size = %d\n", in_size)); + DBGMSG(("out_size = %d\n", out_size)); + DBGMSG(("delta = %d\n", delta)); + DBGMSG(("renderobj->get_pixel_depth() = %d\n", __halftone->getPixelDepth())); + + uchar *ptr = (uchar *)bitmap->Bits() + + rc.top * delta + + (rc.left * __halftone->getPixelDepth()) / 8; + + int compression_method; + int compressed_size; + const uchar *buffer; + + uchar *in_buffer = new uchar[in_size]; + uchar *out_buffer = new uchar[out_size]; + + auto_ptr _in_buffer (in_buffer); + auto_ptr _out_buffer(out_buffer); + + uchar *ptr2 = (uchar *)in_buffer; + + DBGMSG(("move\n")); + + move(x, y); + + for (int i = rc.top; i <= rc.bottom; i++) { + __halftone->dither(ptr2, ptr, x, y, width); + ptr += delta; + ptr2 += widthByte; + y++; + } + + compressed_size = compress3(out_buffer, in_buffer, in_size); + + if (compressed_size < in_size) { + compression_method = 9; /* compress3 */ + buffer = out_buffer; + } else if (compressed_size > out_size) { + BAlert *alert = new BAlert("memory overrun!!!", "warning", "OK"); + alert->Go(); + return false; + } else { + compression_method = 0; + buffer = in_buffer; + compressed_size = in_size; + } + + DBGMSG(("compressed_size = %d\n", compressed_size)); + DBGMSG(("widthByte = %d\n", widthByte)); + DBGMSG(("height = %d\n", height)); + DBGMSG(("compression_method = %d\n", compression_method)); + + rasterGraphics( + compressed_size, // size, + widthByte, // widthByte + height, // height, + compression_method, + buffer); + + } else { + DBGMSG(("band bitmap is clean.\n")); + } + + if (y >= page_height) { + offset->x = -1.0; + offset->y = -1.0; + } else { + offset->y += height; + } + + DBGMSG(("< nextBand\n")); + return true; + } + catch (TransportException &err) { + BAlert *alert = new BAlert("", err.what(), "OK"); + alert->Go(); + return false; + } +} + +void LIPS3Driver::beginTextMode() +{ + writeSpoolString("\033%%@"); +} + +void LIPS3Driver::jobStart() +{ + writeSpoolString("\033P31;300;1J\033\\"); +} + +void LIPS3Driver::softReset() +{ + writeSpoolString("\033<"); +} + +void LIPS3Driver::sizeUnitMode() +{ + writeSpoolString("\033[11h"); +} + +void LIPS3Driver::selectSizeUnit() +{ + writeSpoolString("\033[7 I"); +} + +void LIPS3Driver::selectPageFormat() +{ + int i; + int width = 0; + int height = 0; + + switch (getJobData()->getPaper()) { + case JobData::A3: + i = 12; + break; + + case JobData::A4: + i = 14; + break; + + case JobData::A5: + i = 16; + break; + + case JobData::JAPANESE_POSTCARD: + i = 18; + break; + + case JobData::B4: + i = 24; + break; + + case JobData::B5: + i = 26; + break; + + case JobData::LETTER: + i = 30; + break; + + case JobData::LEGAL: + i = 32; + break; + +// case JobData::EXECUTIVE: +// i = 40; +// break; +// +// case JobData::JENV_YOU4: +// i = 50; +// break; +// +// case JobData::USER: +// i = 90; +// break; +// + default: + i = 80; + width = getJobData()->getPaperRect().IntegerWidth(); + height = getJobData()->getPaperRect().IntegerHeight(); + break; + } + + if (JobData::LANDSCAPE == getJobData()->getOrientation()) + i++; + + if (i < 80) { + writeSpoolString("\033[%d;;p", i); + } else { + writeSpoolString("\033[%d;%d;%dp", i, height, width); + } +} + +void LIPS3Driver::paperFeedMode() +{ + // 0 auto + // -------------- + // 1 MP tray + // 2 lower + // 3 lupper + // -------------- + // 10 MP tray + // 11 casette 1 + // 12 casette 2 + // 13 casette 3 + // 14 casette 4 + // 15 casette 5 + // 16 casette 6 + // 17 casette 7 + + int i; + + switch (getJobData()->getPaperSource()) { + case JobData::MANUAL: + i = 1; + break; + case JobData::LOWER: + i = 2; + break; + case JobData::UPPER: + i = 3; + break; + case JobData::AUTO: + default: + i = 0; + break; + } + + writeSpoolString("\033[%dq", i); +} + +void LIPS3Driver::disableAutoFF() +{ + writeSpoolString("\033[?2h"); +} + +void LIPS3Driver::setNumberOfCopies() +{ + writeSpoolString("\033[%ldv", getJobData()->getCopies()); +} + +void LIPS3Driver::memorizedPosition() +{ + writeSpoolString("\033[0;1;0x"); +} + +void LIPS3Driver::moveAbsoluteHorizontal(int x) +{ + writeSpoolString("\033[%d`", x); +} + +void LIPS3Driver::carriageReturn() +{ + writeSpoolChar('\x0d'); +} + +void LIPS3Driver::moveDown(int dy) +{ + writeSpoolString("\033[%de", dy); +} + +void LIPS3Driver::rasterGraphics( + int compression_size, + int widthbyte, + int height, + int compression_method, + const uchar *buffer) +{ +// 0 RAW +// 9 compress-3 + writeSpoolString( + "\033[%d;%d;%d;%d;%d.r", + compression_size, + widthbyte, + getJobData()->getXres(), + compression_method, + height); + + writeSpoolData(buffer, compression_size); +} + +void LIPS3Driver::formFeed() +{ + writeSpoolChar('\014'); +} + +void LIPS3Driver::jobEnd() +{ + writeSpoolString("\033P0J\033\\"); +} + +void LIPS3Driver::move(int x, int y) +{ + if (__current_x != x) { + if (x) { + moveAbsoluteHorizontal(x); + } else { + carriageReturn(); + } + __current_x = x; + } + if (__current_y != y) { + int dy = y - __current_y; + moveDown(dy); + __current_y = y; + } +} diff --git a/src/add-ons/print/drivers/canon_lips/lips3/Lips3.h b/src/add-ons/print/drivers/canon_lips/lips3/Lips3.h new file mode 100644 index 0000000000..db369a540e --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/lips3/Lips3.h @@ -0,0 +1,53 @@ +/* + * Lips3.h + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#ifndef __LIPS3_H +#define __LIPS3_H + +#include "GraphicsDriver.h" + +class Halftone; + +class LIPS3Driver : public GraphicsDriver { +public: + LIPS3Driver(BMessage *msg, PrinterData *printer_data, const PrinterCap *printer_cap); + +protected: + virtual bool startDoc(); + virtual bool startPage(int page); + virtual bool nextBand(BBitmap *bitmap, BPoint *offset); + virtual bool endPage(int page); + virtual bool endDoc(bool success); + +private: + void move(int x, int y); + void beginTextMode(); + void jobStart(); + void softReset(); + void sizeUnitMode(); + void selectSizeUnit(); + void paperFeedMode(); + void selectPageFormat(); + void disableAutoFF(); + void setNumberOfCopies(); + void memorizedPosition(); + void moveAbsoluteHorizontal(int x); + void carriageReturn(); + void moveDown(int dy); + void rasterGraphics( + int size, + int widthbyte, + int height, + int compression_method, + const uchar *buffer); + void formFeed(); + void jobEnd(); + + int __current_x; + int __current_y; + Halftone *__halftone; +}; + +#endif /* __LIPS3_H */ diff --git a/src/add-ons/print/drivers/canon_lips/lips3/Lips3.rsrc b/src/add-ons/print/drivers/canon_lips/lips3/Lips3.rsrc new file mode 100644 index 0000000000..13831f49d4 Binary files /dev/null and b/src/add-ons/print/drivers/canon_lips/lips3/Lips3.rsrc differ diff --git a/src/add-ons/print/drivers/canon_lips/lips3/Lips3Cap.cpp b/src/add-ons/print/drivers/canon_lips/lips3/Lips3Cap.cpp new file mode 100644 index 0000000000..96d7e6ce9b --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/lips3/Lips3Cap.cpp @@ -0,0 +1,138 @@ +/* + * Lips3Cap.cpp + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#include "PrinterData.h" +#include "Lips3Cap.h" + +#define TO72DPI(a) (a * 72.0f / 600.0f) + +const PaperCap a3( + "A3", + false, + JobData::A3, + BRect(0.0f, 0.0f, TO72DPI(7014.0f), TO72DPI(9920.0f)), + BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(6894.0f), TO72DPI(9800.0f))); + +const PaperCap a4( + "A4", + true, + JobData::A4, + BRect(0.0f, 0.0f, TO72DPI(4960.0f), TO72DPI(7014.0f)), + BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(4840.0f), TO72DPI(6894.0f))); + +const PaperCap a5( + "A5", + false, + JobData::A5, + BRect(0.0f, 0.0f, TO72DPI(3506.0f), TO72DPI(4960.0f)), + BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(3386.0f), TO72DPI(4840.0f))); + +const PaperCap japanese_postcard( + "Japanese Postcard", + false, + JobData::JAPANESE_POSTCARD, + BRect(0.0f, 0.0f, TO72DPI(2362.0f), TO72DPI(3506.0f)), + BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(2242.0f), TO72DPI(3386.0f))); + +const PaperCap b4( + "B4", + false, + JobData::B4, + BRect(0.0f, 0.0f, TO72DPI(6070.0f), TO72DPI(8598.0f)), + BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(5950.0f), TO72DPI(8478.0f))); + +const PaperCap b5( + "B5", + false, + JobData::B5, + BRect(0.0f, 0.0f, TO72DPI(4298.0f), TO72DPI(6070.0f)), + BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(4178.0f), TO72DPI(5950.0f))); + +const PaperCap letter( + "Letter", + false, + JobData::LETTER, + BRect(0.0f, 0.0f, TO72DPI(5100.0f), TO72DPI(6600.0f)), + BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(4980.0f), TO72DPI(6480.0f))); + +const PaperCap legal( + "Legal", + false, + JobData::LEGAL, + BRect(0.0f, 0.0f, TO72DPI(5100.0f), TO72DPI(8400.0f)), + BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(4980.0f), TO72DPI(8280.0f))); + +const PaperSourceCap autobin("Auto", true, JobData::AUTO); +const PaperSourceCap manual("Manual", false, JobData::MANUAL); +const PaperSourceCap upper("Upper", false, JobData::UPPER); +const PaperSourceCap lower("Lower", false, JobData::LOWER); + +const ResolutionCap dpi300("300dpi", true, 300, 300); + +const PaperCap *papers[] = { + &a4, + &a3, + &a5, + &b4, + &b5, + &letter, + &legal +}; + +const PaperSourceCap *papersources[] = { + &autobin, + &manual, + &upper, + &lower +}; + +const ResolutionCap *resolutions[] = { + &dpi300 +}; + +Lips3Cap::Lips3Cap(const PrinterData *printer_data) + : PrinterCap(printer_data) +{ +} + +int Lips3Cap::countCap(CAPID capid) const +{ + switch (capid) { + case PAPER: + return sizeof(papers) / sizeof(papers[0]); + case PAPERSOURCE: + return sizeof(papersources) / sizeof(papersources[0]); + case RESOLUTION: + return sizeof(resolutions) / sizeof(resolutions[0]); + default: + return 0; + } +} + +const BaseCap **Lips3Cap::enumCap(CAPID capid) const +{ + switch (capid) { + case PAPER: + return (const BaseCap **)papers; + case PAPERSOURCE: + return (const BaseCap **)papersources; + case RESOLUTION: + return (const BaseCap **)resolutions; + default: + return NULL; + } +} + +bool Lips3Cap::isSupport(CAPID capid) const +{ + switch (capid) { + case PAPER: + case PAPERSOURCE: + case RESOLUTION: + return true; + default: + return false; + } +} diff --git a/src/add-ons/print/drivers/canon_lips/lips3/Lips3Cap.h b/src/add-ons/print/drivers/canon_lips/lips3/Lips3Cap.h new file mode 100644 index 0000000000..d895d6c349 --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/lips3/Lips3Cap.h @@ -0,0 +1,19 @@ +/* + * Lips3Cap.h + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#ifndef __LIPS3CAP_H +#define __LIPS3CAP_H + +#include "PrinterCap.h" + +class Lips3Cap : public PrinterCap { +public: + Lips3Cap(const PrinterData *printer_data); + virtual int countCap(CAPID) const; + virtual bool isSupport(CAPID) const; + virtual const BaseCap **enumCap(CAPID) const; +}; + +#endif /* __LIPS3CAP_H */ diff --git a/src/add-ons/print/drivers/canon_lips/lips3/Lips3Entry.cpp b/src/add-ons/print/drivers/canon_lips/lips3/Lips3Entry.cpp new file mode 100644 index 0000000000..3f311ed544 --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/lips3/Lips3Entry.cpp @@ -0,0 +1,79 @@ +/* + * Lips3Entry.cpp + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#include +#include +#include + +#include "Exports.h" +#include "Lips3.h" +#include "PrinterData.h" +#include "Lips3Cap.h" +#include "UIDriver.h" +#include "AboutBox.h" +#include "DbgMsg.h" + +char *add_printer(char *printer_name) +{ + DBGMSG((">LIPS3: add_printer\n")); + DBGMSG(("\tprinter_name: %s\n", printer_name)); + DBGMSG(("LIPS3: config_page\n")); + DUMP_BMESSAGE(msg); + DUMP_BNODE(node); + + PrinterData printer_data(node); + Lips3Cap printer_cap(&printer_data); + UIDriver drv(msg, &printer_data, &printer_cap); + BMessage *result = drv.configPage(); + + DUMP_BMESSAGE(result); + DBGMSG(("LIPS3: config_job\n")); + DUMP_BMESSAGE(msg); + DUMP_BNODE(node); + + PrinterData printer_data(node); + Lips3Cap printer_cap(&printer_data); + UIDriver drv(msg, &printer_data, &printer_cap); + BMessage *result = drv.configJob(); + + DUMP_BMESSAGE(result); + DBGMSG(("LIPS3: take_job\n")); + DUMP_BMESSAGE(msg); + DUMP_BNODE(node); + + PrinterData printer_data(node); + Lips3Cap printer_cap(&printer_data); + LIPS3Driver drv(msg, &printer_data, &printer_cap); + BMessage *result = drv.takeJob(spool); + +// DUMP_BMESSAGE(result); + DBGMSG((" +#include +#include +#include +#include "Lips4.h" +#include "PackBits.h" +#include "JobData.h" +#include "PrinterData.h" +#include "Lips4Cap.h" +#include "Halftone.h" +#include "ValidRect.h" +#include "DbgMsg.h" + +#if (!__MWERKS__ || defined(MSIPL_USING_NAMESPACE)) +using namespace std; +#else +#define std +#endif + +LIPS4Driver::LIPS4Driver(BMessage *msg, PrinterData *printer_data, const PrinterCap *printer_cap) + : GraphicsDriver(msg, printer_data, printer_cap) +{ + __halftone = NULL; +} + +bool LIPS4Driver::startDoc() +{ + try { + beginTextMode(); + jobStart(); + colorModeDeclaration(); + softReset(); + sizeUnitMode(); + selectSizeUnit(); + paperFeedMode(); + selectPageFormat(); + disableAutoFF(); + setNumberOfCopies(); + sidePrintingControl(); + setBindingMargin(); + __halftone = new Halftone(getJobData()->getSurfaceType(), getJobData()->getGamma()); + return true; + } + catch (TransportException &err) { + return false; + } +} + +bool LIPS4Driver::startPage(int) +{ + try { + __current_x = 0; + __current_y = 0; + memorizedPosition(); + return true; + } + catch (TransportException &err) { + return false; + } +} + +bool LIPS4Driver::endPage(int) +{ + try { + formFeed(); + return true; + } + catch (TransportException &err) { + return false; + } +} + +bool LIPS4Driver::endDoc(bool) +{ + try { + if (__halftone) { + delete __halftone; + } + jobEnd(); + return true; + } + catch (TransportException &err) { + return false; + } +} + +bool LIPS4Driver::nextBand(BBitmap *bitmap, BPoint *offset) +{ + DBGMSG(("> nextBand\n")); + + try { + + if (bitmap == NULL) { + uchar dummy[1]; + dummy[0] = '\0'; + rasterGraphics(1, 1, 1, 0, dummy); + DBGMSG(("< next_band\n")); + return true; + } + + BRect bounds = bitmap->Bounds(); + + RECT rc; + rc.left = (int)bounds.left; + rc.top = (int)bounds.top; + rc.right = (int)bounds.right; + rc.bottom = (int)bounds.bottom; + + int height = rc.bottom - rc.top + 1; + + int x = (int)offset->x; + int y = (int)offset->y; + + int page_height = getPageHeight(); + + if (y + height > page_height) { + height = page_height - y; + } + + rc.bottom = height - 1; + + DBGMSG(("height = %d\n", height)); + DBGMSG(("x = %d\n", x)); + DBGMSG(("y = %d\n", y)); + + if (get_valid_rect(bitmap, __halftone->getPalette(), &rc)) { + + DBGMSG(("validate rect = %d, %d, %d, %d\n", + rc.left, rc.top, rc.right, rc.bottom)); + + x = rc.left; + y += rc.top; + + int width = rc.right - rc.left + 1; + int widthByte = (width + 7) / 8; + int height = rc.bottom - rc.top + 1; + int in_size = widthByte * height; + int out_size = (in_size * 6 + 4) / 5; + int delta = bitmap->BytesPerRow(); + + DBGMSG(("width = %d\n", width)); + DBGMSG(("widthByte = %d\n", widthByte)); + DBGMSG(("height = %d\n", height)); + DBGMSG(("in_size = %d\n", in_size)); + DBGMSG(("out_size = %d\n", out_size)); + DBGMSG(("delta = %d\n", delta)); + DBGMSG(("__halftone_engine->get_pixel_depth() = %d\n", __halftone->getPixelDepth())); + + uchar *ptr = (uchar *)bitmap->Bits() + + rc.top * delta + + (rc.left * __halftone->getPixelDepth()) / 8; + + int compression_method; + int compressed_size; + const uchar *buffer; + + uchar *in_buffer = new uchar[in_size]; + uchar *out_buffer = new uchar[out_size]; + + auto_ptr _in_buffer (in_buffer); + auto_ptr _out_buffer(out_buffer); + + uchar *ptr2 = (uchar *)in_buffer; + + DBGMSG(("move\n")); + + move(x, y); + + for (int i = rc.top; i <= rc.bottom; i++) { + __halftone->dither(ptr2, ptr, x, y, width); + ptr += delta; + ptr2 += widthByte; + y++; + } + + DBGMSG(("PackBits\n")); + + compressed_size = pack_bits(out_buffer, in_buffer, in_size); + + if (compressed_size < in_size) { + compression_method = 11; + buffer = out_buffer; + } else if (compressed_size > out_size) { + BAlert *alert = new BAlert("memory overrun!!!", "warning", "OK"); + alert->Go(); + return false; + } else { + compression_method = 0; + buffer = in_buffer; + compressed_size = in_size; + } + + DBGMSG(("compressed_size = %d\n", compressed_size)); + DBGMSG(("widthByte = %d\n", widthByte)); + DBGMSG(("height = %d\n", height)); + DBGMSG(("compression_method = %d\n", compression_method)); + + rasterGraphics( + compressed_size, // size, + widthByte, // widthByte + height, // height, + compression_method, + buffer); + + } else { + DBGMSG(("band bitmap is clean.\n")); + } + + if (y >= page_height) { + offset->x = -1.0; + offset->y = -1.0; + } else { + offset->y += height; + } + + DBGMSG(("< nextBand\n")); + return true; + } + catch (TransportException &err) { + BAlert *alert = new BAlert("", err.what(), "OK"); + alert->Go(); + return false; + } +} + +void LIPS4Driver::beginTextMode() +{ + writeSpoolString("\033%%@"); +} + +void LIPS4Driver::jobStart() +{ + writeSpoolString("\033P41;%d;1J\033\\", getJobData()->getXres()); +} + +void LIPS4Driver::colorModeDeclaration() +{ +// if (color) +// writeSpoolString("\033[1\"p"); +// else + writeSpoolString("\033[0\"p"); +} + +void LIPS4Driver::softReset() +{ + writeSpoolString("\033<"); +} + +void LIPS4Driver::sizeUnitMode() +{ + writeSpoolString("\033[11h"); +} + +void LIPS4Driver::selectSizeUnit() +{ + writeSpoolString("\033[?7;%d I", getJobData()->getXres()); +} + +void LIPS4Driver::paperFeedMode() +{ + // 0 auto + // -------------- + // 1 MP tray + // 2 lower + // 3 lupper + // -------------- + // 10 MP tray + // 11 casette 1 + // 12 casette 2 + // 13 casette 3 + // 14 casette 4 + // 15 casette 5 + // 16 casette 6 + // 17 casette 7 + + int i; + + switch (getJobData()->getPaperSource()) { + case JobData::MANUAL: + i = 10; + break; + case JobData::UPPER: + i = 11; + break; + case JobData::MIDDLE: + i = 12; + break; + case JobData::LOWER: + i = 13; + break; + case JobData::AUTO: + default: + i = 0; + break; + } + + writeSpoolString("\033[%dq", i); +} + +void LIPS4Driver::selectPageFormat() +{ + int i; + + switch (getJobData()->getPaper()) { + case JobData::A3: + i = 12; + break; + + case JobData::A4: + i = 14; + break; + + case JobData::A5: + i = 16; + break; + + case JobData::JAPANESE_POSTCARD: + i = 18; + break; + + case JobData::B4: + i = 24; + break; + + case JobData::B5: + i = 26; + break; + + case JobData::LETTER: + i = 30; + break; + + case JobData::LEGAL: + i = 32; + break; + + case JobData::EXECUTIVE: + i = 40; + break; + + case JobData::JENV_YOU4: + i = 50; + break; + + case JobData::USER: + i = 90; + break; + + default: + i = 0; + break; + } + + if (JobData::LANDSCAPE == getJobData()->getOrientation()) + i++; + + writeSpoolString("\033[%d;;p", i); +} + +void LIPS4Driver::disableAutoFF() +{ + writeSpoolString("\033[?2h"); +} + +void LIPS4Driver::setNumberOfCopies() +{ + writeSpoolString("\033[%ldv", getJobData()->getCopies()); +} + +void LIPS4Driver::sidePrintingControl() +{ + if (getJobData()->getPrintStyle() == JobData::SIMPLEX) + writeSpoolString("\033[0#x"); + else + writeSpoolString("\033[2;0#x"); +} + +void LIPS4Driver::setBindingMargin() +{ + if (getJobData()->getPrintStyle() == JobData::DUPLEX) { + int i; +// switch (job_data()->binding_location()) { +// case LONG_EDGE_LEFT: + i = 0; +// break; +// case LONG_EDGE_RIGHT: +// i = 1; +// break; +// case SHORT_EDGE_TOP: +// i = 2; +// break; +// case SHORT_EDGE_BOTTOM: +// i = 3; +// break; +// } + writeSpoolString("\033[%d;0#w", i); + } +} + +void LIPS4Driver::memorizedPosition() +{ + writeSpoolString("\033[0;1;0x"); +} + +void LIPS4Driver::moveAbsoluteHorizontal(int x) +{ + writeSpoolString("\033[%ld`", x); +} + +void LIPS4Driver::carriageReturn() +{ + writeSpoolChar('\x0d'); +} + +void LIPS4Driver::moveDown(int dy) +{ + writeSpoolString("\033[%lde", dy); +} + +void LIPS4Driver::rasterGraphics( + int compression_size, + int widthbyte, + int height, + int compression_method, + const uchar *buffer) +{ +// 0 RAW +// 10 RLE +// 11 packbits + + writeSpoolString( + "\033[%ld;%ld;%d;%ld;%ld.r", + compression_size, + widthbyte, + getJobData()->getXres(), + compression_method, + height); + + writeSpoolData(buffer, compression_size); +} + +void LIPS4Driver::formFeed() +{ + writeSpoolChar('\014'); +} + +void LIPS4Driver::jobEnd() +{ + writeSpoolString("\033P0J\033\\"); +} + +void LIPS4Driver::move(int x, int y) +{ + if (__current_x != x) { + if (x) { + moveAbsoluteHorizontal(x); + } else { + carriageReturn(); + } + __current_x = x; + } + if (__current_y != y) { + int dy = y - __current_y; + moveDown(dy); + __current_y = y; + } +} diff --git a/src/add-ons/print/drivers/canon_lips/lips4/Lips4.h b/src/add-ons/print/drivers/canon_lips/lips4/Lips4.h new file mode 100644 index 0000000000..89faa44723 --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/lips4/Lips4.h @@ -0,0 +1,56 @@ +/* + * Lips4.h + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#ifndef __LIPS4_H +#define __LIPS4_H + +#include "GraphicsDriver.h" + +class Halftone; + +class LIPS4Driver : public GraphicsDriver { +public: + LIPS4Driver(BMessage *msg, PrinterData *printer_data, const PrinterCap *cap); + +protected: + virtual bool startDoc(); + virtual bool startPage(int page); + virtual bool nextBand(BBitmap *bitmap, BPoint *offset); + virtual bool endPage(int page); + virtual bool endDoc(bool success); + +private: + void move(int x, int y); + void beginTextMode(); + void jobStart(); + void colorModeDeclaration(); + void softReset(); + void sizeUnitMode(); + void selectSizeUnit(); + void paperFeedMode(); + void selectPageFormat(); + void disableAutoFF(); + void setNumberOfCopies(); + void sidePrintingControl(); + void setBindingMargin(); + void memorizedPosition(); + void moveAbsoluteHorizontal(int x); + void carriageReturn(); + void moveDown(int dy); + void rasterGraphics( + int size, + int widthbyte, + int height, + int compression_method, + const uchar *buffer); + void formFeed(); + void jobEnd(); + + int __current_x; + int __current_y; + Halftone *__halftone; +}; + +#endif /* __LIPS4_H */ diff --git a/src/add-ons/print/drivers/canon_lips/lips4/Lips4.rsrc b/src/add-ons/print/drivers/canon_lips/lips4/Lips4.rsrc new file mode 100644 index 0000000000..b7ae7f40a3 Binary files /dev/null and b/src/add-ons/print/drivers/canon_lips/lips4/Lips4.rsrc differ diff --git a/src/add-ons/print/drivers/canon_lips/lips4/Lips4Cap.cpp b/src/add-ons/print/drivers/canon_lips/lips4/Lips4Cap.cpp new file mode 100644 index 0000000000..0c5fc5c7f9 --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/lips4/Lips4Cap.cpp @@ -0,0 +1,203 @@ +/* + * Lips4Cap.cpp + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#include "Lips4Cap.h" + +#define TO72DPI(a) (a * 72.0f / 600.0f) + +const PaperCap a3( + "A3", + false, + JobData::A3, + BRect(0.0f, 0.0f, TO72DPI(7014.0f), TO72DPI(9920.0f)), + BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(6894.0f), TO72DPI(9800.0f))); + +const PaperCap a4( + "A4", + true, + JobData::A4, + BRect(0.0f, 0.0f, TO72DPI(4960.0f), TO72DPI(7014.0f)), + BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(4840.0f), TO72DPI(6894.0f))); + +const PaperCap a5( + "A5", + false, + JobData::A5, + BRect(0.0f, 0.0f, TO72DPI(3506.0f), TO72DPI(4960.0f)), + BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(3386.0f), TO72DPI(4840.0f))); + +const PaperCap japanese_postcard( + "Japanese Postcard", + false, + JobData::JAPANESE_POSTCARD, + BRect(0.0f, 0.0f, TO72DPI(2362.0f), TO72DPI(3506.0f)), + BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(2242.0f), TO72DPI(3386.0f))); + +const PaperCap b4( + "B4", + false, + JobData::B4, + BRect(0.0f, 0.0f, TO72DPI(6070.0f), TO72DPI(8598.0f)), + BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(5950.0f), TO72DPI(8478.0f))); + +const PaperCap b5( + "B5", + false, + JobData::B5, + BRect(0.0f, 0.0f, TO72DPI(4298.0f), TO72DPI(6070.0f)), + BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(4178.0f), TO72DPI(5950.0f))); + +const PaperCap letter( + "Letter", + false, + JobData::LETTER, + BRect(0.0f, 0.0f, TO72DPI(5100.0f), TO72DPI(6600.0f)), + BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(4980.0f), TO72DPI(6480.0f))); + +const PaperCap legal( + "Legal", + false, + JobData::LEGAL, + BRect(0.0f, 0.0f, TO72DPI(5100.0f), TO72DPI(8400.0f)), + BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(4980.0f), TO72DPI(8280.0f))); + +const PaperCap tabloid( + "Tabloid", + false, + JobData::TABLOID, + BRect(0.0f, 0.0f, TO72DPI(6600.0), TO72DPI(10200.0)), + BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(6480.0), TO72DPI(10080.0))); + +const PaperCap executive( + "Executive", + false, + JobData::EXECUTIVE, + BRect(0.0f, 0.0f, TO72DPI(4350.0f), TO72DPI(6300.0f)), + BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(4230.0f), TO72DPI(6180.0f))); + +const PaperCap japanese_envelope_you4( + "Japanese Envelope You#4", + false, + JobData::JENV_YOU4, + BRect(0.0f, 0.0f, TO72DPI(2480.0f), TO72DPI(5550.0f)), + BRect(TO72DPI(236.0f), TO72DPI(236.0f), TO72DPI(2244.0f), TO72DPI(5314.0f))); +/* +const PaperCap japanese_envelope_kaku2( + "Japanese Envelope Kaku#2", + false, + JobData::JENV_KAKU2, + BRect(0.0f, 0.0f, TO72DPI(5568.0f), TO72DPI(7842.0f)), + BRect(TO72DPI(236.0f), TO72DPI(236.0f), TO72DPI(5432.0f), TO72DPI(7606.0f))); +*/ +const PaperSourceCap autobin("Auto", true, JobData::AUTO); +const PaperSourceCap manual("Manual", false, JobData::MANUAL); +const PaperSourceCap upper("Upper", false, JobData::UPPER); +const PaperSourceCap middle("Middle", false, JobData::MIDDLE); +const PaperSourceCap lower("Lower", false, JobData::LOWER); + +const ResolutionCap dpi1200("1200dpi", false, 1200, 1200); +const ResolutionCap dpi600("600dpi", true, 600, 600); +const ResolutionCap dpi300("300dpi", false, 300, 300); + +const PrintStyleCap simplex("Simplex", true, JobData::SIMPLEX); +const PrintStyleCap duplex("Duplex", false, JobData::DUPLEX); +const PrintStyleCap booklet("Booklet", false, JobData::BOOKLET); + +const BindingLocationCap longedge1("Long Edge (left)", true, JobData::LONG_EDGE_LEFT); +const BindingLocationCap longedge2("Long Edge (right)", false, JobData::LONG_EDGE_RIGHT); +const BindingLocationCap shortedge1("Short Edge (top)", false, JobData::SHORT_EDGE_TOP); +const BindingLocationCap shortedge2("Short Edge (bottom)", false, JobData::SHORT_EDGE_BOTTOM); + +const PaperCap *papers[] = { + &a4, + &a3, + &a5, + &b4, + &b5, + &letter, + &legal, + &tabloid, + &executive, + &japanese_postcard, + &japanese_envelope_you4 +}; + +const PaperSourceCap *papersources[] = { + &autobin, + &manual, + &upper, + &middle, + &lower +}; + +const ResolutionCap *resolutions[] = { + &dpi1200, + &dpi600, + &dpi300 +}; + +const PrintStyleCap *printstyles[] = { + &simplex, + &duplex, + &booklet +}; + +const BindingLocationCap *bindinglocations[] = { + &longedge1, + &longedge2, + &shortedge1, + &shortedge2 +}; + + +int Lips4Cap::countCap(CAPID capid) const +{ + switch (capid) { + case PAPER: + return sizeof(papers) / sizeof(papers[0]); + case PAPERSOURCE: + return sizeof(papersources) / sizeof(papersources[0]); + case RESOLUTION: + return sizeof(resolutions) / sizeof(resolutions[0]); + case PRINTSTYLE: + return sizeof(printstyles) / sizeof(printstyles[0]); + case BINDINGLOCATION: + return sizeof(bindinglocations) / sizeof(bindinglocations[0]); + default: + return 0; + } +} + +const BaseCap **Lips4Cap::enumCap(CAPID capid) const +{ + switch (capid) { + case PAPER: + return (const BaseCap **)papers; + case PAPERSOURCE: + return (const BaseCap **)papersources; + case RESOLUTION: + return (const BaseCap **)resolutions; + case PRINTSTYLE: + return (const BaseCap **)printstyles; + case BINDINGLOCATION: + return (const BaseCap **)bindinglocations; + default: + return NULL; + } +} + +bool Lips4Cap::isSupport(CAPID capid) const +{ + switch (capid) { + case PAPER: + case PAPERSOURCE: + case RESOLUTION: + case PRINTSTYLE: + case BINDINGLOCATION: + return true; + default: + return false; + } +} diff --git a/src/add-ons/print/drivers/canon_lips/lips4/Lips4Cap.h b/src/add-ons/print/drivers/canon_lips/lips4/Lips4Cap.h new file mode 100644 index 0000000000..6e6b070f2a --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/lips4/Lips4Cap.h @@ -0,0 +1,19 @@ +/* + * Lips4Cap.h + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#ifndef __LIPS4CAP_H +#define __LIPS4CAP_H + +#include "PrinterCap.h" + +class Lips4Cap : public PrinterCap { +public: + Lips4Cap(const PrinterData *printer_data) : PrinterCap(printer_data) {} + virtual int countCap(CAPID) const; + virtual bool isSupport(CAPID) const; + virtual const BaseCap **enumCap(CAPID) const; +}; + +#endif /* __LIPS4CAP_H */ diff --git a/src/add-ons/print/drivers/canon_lips/lips4/Lips4Entry.cpp b/src/add-ons/print/drivers/canon_lips/lips4/Lips4Entry.cpp new file mode 100644 index 0000000000..fef14c2d41 --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/lips4/Lips4Entry.cpp @@ -0,0 +1,79 @@ +/* + * Lips4Entry.cpp + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#include +#include +#include + +#include "Exports.h" +#include "Lips4.h" +#include "PrinterData.h" +#include "Lips4Cap.h" +#include "UIDriver.h" +#include "AboutBox.h" +#include "DbgMsg.h" + +char *add_printer(char *printer_name) +{ + DBGMSG((">LIPS4: add_printer\n")); + DBGMSG(("\tprinter_name: %s\n", printer_name)); + DBGMSG(("LIPS4: config_page\n")); + DUMP_BMESSAGE(msg); + DUMP_BNODE(node); + + PrinterData printer_data(node); + Lips4Cap printer_cap(&printer_data); + UIDriver drv(msg, &printer_data, &printer_cap); + BMessage *result = drv.configPage(); + + DUMP_BMESSAGE(result); + DBGMSG(("LIPS4: config_job\n")); + DUMP_BMESSAGE(msg); + DUMP_BNODE(node); + + PrinterData printer_data(node); + Lips4Cap printer_cap(&printer_data); + UIDriver drv(msg, &printer_data, &printer_cap); + BMessage *result = drv.configJob(); + + DUMP_BMESSAGE(result); + DBGMSG(("LIPS4: take_job\n")); + DUMP_BMESSAGE(msg); + DUMP_BNODE(node); + + PrinterData printer_data(node); + Lips4Cap printer_cap(&printer_data); + LIPS4Driver drv(msg, &printer_data, &printer_cap); + BMessage *result = drv.takeJob(spool); + +// DUMP_BMESSAGE(result); + DBGMSG((" +#endif + +#include +#include "PackBits.h" + +#if (!__MWERKS__ || defined(MSIPL_USING_NAMESPACE)) +using namespace std; +#else +#define std +#endif + +#define MAXINBYTES 127 +#define CONTROL1(i) -i +#define CONTROL2(i) i + +enum STATUS { + INITIAL, + UNDECIDED, + UNMATCHED, + MATCHED +}; + +int pack_bits(unsigned char *pOut, unsigned char *pIn, int n) +{ + int i; + unsigned char *control; + unsigned char *runbuf; + unsigned char thisbyte; + unsigned char runbyte; + STATUS status; + + i = 0; + status = INITIAL; + control = runbuf = pOut; + runbyte = *pIn++; + + while (--n) { + thisbyte = *pIn++; + switch (status) { + case INITIAL: + control = runbuf++; + *runbuf++ = runbyte; + if (thisbyte == runbyte) { + status = UNDECIDED; + } else { + runbyte = thisbyte; + status = UNMATCHED; + } + i = 1; + break; + + case UNDECIDED: + if (i == MAXINBYTES) { + *control = CONTROL2(i); + *runbuf++ = runbyte; + runbyte = thisbyte; + status = INITIAL; + } else if (thisbyte == runbyte) { + if (i > 1) { + *control = CONTROL2(i - 2); + control = runbuf - 1; + } + i = 2; + status = MATCHED; + } else { + *runbuf++ = runbyte; + runbyte = thisbyte; + status = UNMATCHED; + i++; + } + break; + + case UNMATCHED: + if (i == MAXINBYTES) { + *control = CONTROL2(i); + status = INITIAL; + } else { + if (thisbyte == runbyte) { + status = UNDECIDED; + } + i++; + } + *runbuf++ = runbyte; + runbyte = thisbyte; + break; + + case MATCHED: + if ((thisbyte != runbyte) || (i == MAXINBYTES)) { + runbuf = control; + *runbuf++ = CONTROL1(i); + *runbuf++ = runbyte; + runbyte = thisbyte; + status = INITIAL; + } else { + i++; + } + break; + } + } + + switch (status) { + case INITIAL: + *runbuf++ = CONTROL2(1); + break; + case UNDECIDED: + case UNMATCHED: + *control = CONTROL2(i); + break; + case MATCHED: + runbuf = control; + *runbuf++ = CONTROL1(i); + break; + } + *runbuf++ = runbyte; + + return runbuf - pOut; +} + +#ifdef DBG_CON_STREAM +int main(int argc, char **argv) +{ + if (argc < 2) { + return -1; + } + + ifstream ifs(*++argv, ios::binary | ios::nocreate); + if (!ifs) { + return -1; + } + + ifs.seekg(0, ios::end); + long size = ifs.tellg(); + ifs.seekg(0, ios::beg); + + unsigned char *pIn = new unsigned char[size]; + unsigned char *pOut = new unsigned char[size * 3]; + + ifs.read(pIn, size); + + int cnt = PackBits(pOut, pIn, size); + + ofstream ofs("test.bin", ios::binary); + ofs.write(pOut, cnt); + + delete [] pIn; + delete [] pOut; + +} +#endif diff --git a/src/add-ons/print/drivers/canon_lips/lips4/PackBits.h b/src/add-ons/print/drivers/canon_lips/lips4/PackBits.h new file mode 100644 index 0000000000..faf4ec5083 --- /dev/null +++ b/src/add-ons/print/drivers/canon_lips/lips4/PackBits.h @@ -0,0 +1,11 @@ +/* + * PackBits.h + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ + +#ifndef __PACKBITS_H +#define __PACKBITS_H + +int pack_bits(unsigned char *out, unsigned char *in, int bytes); + +#endif /* __PACKBITS_H */ diff --git a/src/add-ons/print/drivers/pdf/CHANGES b/src/add-ons/print/drivers/pdf/CHANGES new file mode 100644 index 0000000000..c68c122cf1 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/CHANGES @@ -0,0 +1,39 @@ +CHANGES + +From version 1.5b1 to 1.5b2 (7/5/2002): + +- fixed bug in install script +- better position detection of bookmarks on a page +- updated to PDFlib 4.0.3 (both x86 and PPC!) + + +From version 1.0b1 to 1.5b1 (5/30/2002): + +- Added interactive pdf features (Web links, cross references, bookmarks) +- Added advanced settings for configuration of interactive features +- Added bookmarks definition "Sample" file +- Added xref definition sample files "English" and "Deutsch" +- Added Bookmarks.zip sample document (StyledEdit and gP) +- Added sample document that shows the interactive features of PDF Writer (gP document and generated PDF file) + +- Added doc info window for configuration of PDF document information +- Fixed Document information is now UCS2 encoded + +- Added font embedding configuration window (Fonts->Embedding) +- Added CJK search order configuration window (Fonts->CJK) +- Added Korean font support + +- Added pattern support +- Implemented clipping to "stroked" graphic primitives +- Fixed font color is always high color and not the current pattern +- Fixed ClipChar() creates a rectangle if the glyph can not be retrieved from BFont +- Update to PDFlib 4.0.2 (Intel only) + +- Fixed: silently exit from OpenTransport() in Print To File cancelation case + +- Report information in status window + +- Install script copies bookmark and xref definition files to PDF Writer settings directory +- Install script restarts print_server before termination +- Fixed window title of page setup window + diff --git a/src/add-ons/print/drivers/pdf/Install b/src/add-ons/print/drivers/pdf/Install new file mode 100755 index 0000000000..a8b6877d6b --- /dev/null +++ b/src/add-ons/print/drivers/pdf/Install @@ -0,0 +1,20 @@ +#!/bin/sh + +launchdir=$(dirname $0) +copyattr -d "$launchdir/PDF Writer" "$HOME/config/add-ons/Print/PDF Writer" +copyattr -d "$launchdir/libpdf.so" "$HOME/config/lib/libpdf.so" + +mkdir /boot/home/config/settings/PDF\ Writer +cd $launchdir +cp encoding/* $HOME/config/settings/PDF\ Writer/ + +mkdir /boot/home/config/settings/PDF\ Writer/bookmarks +cp bookmarks/* /boot/home/config/settings/PDF\ Writer/bookmarks + +mkdir /boot/home/config/settings/PDF\ Writer/xrefs +cp xrefs/* /boot/home/config/settings/PDF\ Writer/xrefs + +# restart print_server +/boot/beos/system/servers/print_server + +alert --info "PDF Writer driver is installed" diff --git a/src/add-ons/print/drivers/pdf/README b/src/add-ons/print/drivers/pdf/README new file mode 100644 index 0000000000..887ad66e7d --- /dev/null +++ b/src/add-ons/print/drivers/pdf/README @@ -0,0 +1,88 @@ +PDF Writer 1.5b2 +7/5/2002 + +is now part of the print_kit of the OBOS (OpenBeOS) project. +http://open-beos.sourceforge.net + +Developers + Name Email address Native language + Phillipe Houdoin French + Michael Pfeiffer German + Celerick Stephens English +Former developer: + Simon Gauvin French/English + +Installation + +1. Expand the zip file somewhere +2. Open the newly created folder +3. Run the Install script to install the driver + +These steps are needed only if you don't have already set up a PDF Writer spooler: + +4. Open the Printers preference panel +5. Click Add button +6. Choose local printer (Network printing is untested, feedback welcome!) +7. Type a name for your new PDF Writer spooler +8. Select PDF Writer as kind +9. Select port to output PDF (Print to file to generate PDF files) +10. Click Add button +11. Click Ok button +12. Enjoy! + + +Changes + +Read the "CHANGES" file for the most recent changes. + + +Known Bugs/Limitations + +- Limited alpha transparency support only (bitmap/pattern only) +- Not all drawing modes supported +- No security settings support. +- Clipping to inverse BPicture not supported + +Note +- BePDF does not take the alpha channel of transparent bitmaps or patterns into account; + Acrobat Reader shows them properly! + + +Contact + +Either one of the developers or post to the print_kit mailing list +open-beos-printing@freelists.org (preferred) +Before any post, you'll need to subscribe it: +http://www.freelists.org/cgi-bin/list?list_id=open-beos-printing + + +Build Instructions for BeOS on x86 platform + +Building for x86 +- copy libpdf.so into /boot/home/config/lib +- make "PDF Writer x86" with "PDF Writer_x86.proj" +- execute _CopyAndRestart shell script + +Building for PPC +- copy libpdf.so into /boot/develop/tools/develop_ppc/lib/ppc +- make "PDF Writer ppc" with "PDF Writer_ppc.proj" +- rename into "PDF Writer" +- After making the binary copy it to /boot/home/config/add-ons/Print + and restart the print_server by executing + /boot/beos/system/servers/print_server + +Install PDF Writer with the Printers preferences application. + + +Links + +Latest PDF Writer release +http://www.bebits.com/app/2494 + +CVS +https://sourceforge.net/cvs/?group_id=33869 + +CVS Browser +http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/open-beos/print_kit/source/add-ons/drivers/PDF/ + + \ No newline at end of file diff --git a/src/add-ons/print/drivers/pdf/TODO b/src/add-ons/print/drivers/pdf/TODO new file mode 100644 index 0000000000..52b1fb9e87 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/TODO @@ -0,0 +1,14 @@ +TODO + +(in abitrary order) +- pdf generation + - alpha channel support + - support for more drawing modes (XOR, AND, OR, alpha, blend) + - text attributes + - check: char spacing + - security settings (printing, copying, changing, ...) -> not with PDFlib :( + - password protection (ditto) + - thumbnails? note recent Acrobat Reader doesn't require them; BePDF does not support them. + - optimize CID tables; the mapping from Unicode to CID is not required, it is sufficient + to know whether a code point is in a certain CID table or not! -> use bitfield instead + diff --git a/src/add-ons/print/drivers/pdf/bookmarks/Sample b/src/add-ons/print/drivers/pdf/bookmarks/Sample new file mode 100644 index 0000000000..cbfc768790 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/bookmarks/Sample @@ -0,0 +1,13 @@ +# This is the PDF Writer bookmarks definition file! +# The next line is mandatory. +Bookmarks 1.0 + +# PDF Writer searches for this file in directory: +# /boot/home/config/settings/PDF Writer/bookmarks + +# level "font family" "font style" font size +# level has to be between 1 and 10 (both inclusive) +# font family and style and size of the font +1 "Swis721 BT" "Roman" 27.0 +2 "Swis721 BT" "Roman" 20.0 +3 "Swis721 BT" "Roman" 18.0 \ No newline at end of file diff --git a/src/add-ons/print/drivers/pdf/doc/Create_Report_Mail.sh b/src/add-ons/print/drivers/pdf/doc/Create_Report_Mail.sh new file mode 100755 index 0000000000..907f0f9d1c --- /dev/null +++ b/src/add-ons/print/drivers/pdf/doc/Create_Report_Mail.sh @@ -0,0 +1,43 @@ +#!/bin/sh +/boot/apps/BeMail mailto:philippe.houdoin@free.fr -subject "pdf_writer v.1.0b1 report" -body "Thanks for taking the time to report how pdf_writer v1.0b1 worked for you! + +Please edit the following text to reflect your experience when trying pdf_writer: + +1 - How did pdf_writed worked? +It crashed/it produced grabage inside the window/it produced gargage all over the screen/it first worked, but stopped working when I did.../other... + +2 - more information: + + + +-------------------------------------------------------------------------- +Please do not edit the information below, unless you don't want to disclose some information it contains: + +-- Version app_server: +`/bin/version /system/servers/app_server` + +-- Version print_server: +`/bin/version /system/servers/print_server` + +-- Version libbe.so: +`/bin/version /system/lib/libbe.so` + +-- System print_server add-ons: +`/bin/ls -lt /boot/beos/system/add-ons/Print/*` + +-- Custom print_server add-ons: +`/bin/ls -lt /boot/home/config/add-ons/Print/*` + +-- System libraries: +`/bin/ls -lt /boot/beos/system/lib/` + +-- Custom libraries: +`/bin/ls -lt /boot/home/config/lib/` + +-- PDF Encoding files: +`/bin/ls -lt /boot/home/config/settings/PDF\ Writer/` + +-- Latest pdf_writer.log: +`/bin/cat /tmp/pdf_writer.log` +" + diff --git a/src/add-ons/print/drivers/pdf/doc/IF.pdf b/src/add-ons/print/drivers/pdf/doc/IF.pdf new file mode 100644 index 0000000000..cb993a5185 Binary files /dev/null and b/src/add-ons/print/drivers/pdf/doc/IF.pdf differ diff --git a/src/add-ons/print/drivers/pdf/doc/Interactive Features.gbe b/src/add-ons/print/drivers/pdf/doc/Interactive Features.gbe new file mode 100644 index 0000000000..d6d36d788b Binary files /dev/null and b/src/add-ons/print/drivers/pdf/doc/Interactive Features.gbe differ diff --git a/src/add-ons/print/drivers/pdf/doc/User Guide.html b/src/add-ons/print/drivers/pdf/doc/User Guide.html new file mode 100644 index 0000000000..8cb328ea3c --- /dev/null +++ b/src/add-ons/print/drivers/pdf/doc/User Guide.html @@ -0,0 +1,33 @@ + + + +User Guide + + + +TODO! + +

        Installation

        +
          +
        1. Open Printers preference panel:
          + +  + +
        2. Click Add button to add a new printer spool:
          + + + +
        3. Choose Local Printer and click Ok button. The Add Local Printer window show up:
          + + + +
        4. Click Add button to validate printer spool settings. +The Printer Model Canon Bubble Jet window show up:
          + + + +
        + + + + \ No newline at end of file diff --git a/src/add-ons/print/drivers/pdf/doc/credits.zip b/src/add-ons/print/drivers/pdf/doc/credits.zip new file mode 100644 index 0000000000..150e4bd8f5 Binary files /dev/null and b/src/add-ons/print/drivers/pdf/doc/credits.zip differ diff --git a/src/add-ons/print/drivers/pdf/doc/images/add_local_printer.jpeg b/src/add-ons/print/drivers/pdf/doc/images/add_local_printer.jpeg new file mode 100644 index 0000000000..3e60dfac6c Binary files /dev/null and b/src/add-ons/print/drivers/pdf/doc/images/add_local_printer.jpeg differ diff --git a/src/add-ons/print/drivers/pdf/doc/images/add_printer.jpeg b/src/add-ons/print/drivers/pdf/doc/images/add_printer.jpeg new file mode 100644 index 0000000000..0c3052c68b Binary files /dev/null and b/src/add-ons/print/drivers/pdf/doc/images/add_printer.jpeg differ diff --git a/src/add-ons/print/drivers/pdf/doc/images/make_default_printer.jpeg b/src/add-ons/print/drivers/pdf/doc/images/make_default_printer.jpeg new file mode 100644 index 0000000000..393620fe7e Binary files /dev/null and b/src/add-ons/print/drivers/pdf/doc/images/make_default_printer.jpeg differ diff --git a/src/add-ons/print/drivers/pdf/doc/images/preferences_printers.jpeg b/src/add-ons/print/drivers/pdf/doc/images/preferences_printers.jpeg new file mode 100644 index 0000000000..113795a99f Binary files /dev/null and b/src/add-ons/print/drivers/pdf/doc/images/preferences_printers.jpeg differ diff --git a/src/add-ons/print/drivers/pdf/doc/images/printers.jpeg b/src/add-ons/print/drivers/pdf/doc/images/printers.jpeg new file mode 100644 index 0000000000..65d9445f31 Binary files /dev/null and b/src/add-ons/print/drivers/pdf/doc/images/printers.jpeg differ diff --git a/src/add-ons/print/drivers/pdf/doc/pdf_icon.tga b/src/add-ons/print/drivers/pdf/doc/pdf_icon.tga new file mode 100644 index 0000000000..f45732d54e Binary files /dev/null and b/src/add-ons/print/drivers/pdf/doc/pdf_icon.tga differ diff --git a/src/add-ons/print/drivers/pdf/encoding/t1enc0.enc b/src/add-ons/print/drivers/pdf/encoding/t1enc0.enc new file mode 100644 index 0000000000..bfffa802e8 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/encoding/t1enc0.enc @@ -0,0 +1,260 @@ +% Encoding definition for PDFlib +% t1enc0 +% WARNING: MACHINE GENERATED DON'T CHANGE! +% Format: glyph name index (decimal) % index (hex) +space 0 % 0x00 +exclam 1 % 0x01 +quotedbl 2 % 0x02 +numbersign 3 % 0x03 +dollar 4 % 0x04 +percent 5 % 0x05 +ampersand 6 % 0x06 +quotesingle 7 % 0x07 +parenleft 8 % 0x08 +parenright 9 % 0x09 +asterisk 10 % 0x0a +plus 11 % 0x0b +comma 12 % 0x0c +hyphen 13 % 0x0d +period 14 % 0x0e +slash 15 % 0x0f +zero 16 % 0x10 +one 17 % 0x11 +two 18 % 0x12 +three 19 % 0x13 +four 20 % 0x14 +five 21 % 0x15 +six 22 % 0x16 +seven 23 % 0x17 +eight 24 % 0x18 +nine 25 % 0x19 +colon 26 % 0x1a +semicolon 27 % 0x1b +less 28 % 0x1c +equal 29 % 0x1d +greater 30 % 0x1e +question 31 % 0x1f +at 32 % 0x20 +A 33 % 0x21 +B 34 % 0x22 +C 35 % 0x23 +D 36 % 0x24 +E 37 % 0x25 +F 38 % 0x26 +G 39 % 0x27 +H 40 % 0x28 +I 41 % 0x29 +J 42 % 0x2a +K 43 % 0x2b +L 44 % 0x2c +M 45 % 0x2d +N 46 % 0x2e +O 47 % 0x2f +P 48 % 0x30 +Q 49 % 0x31 +R 50 % 0x32 +S 51 % 0x33 +T 52 % 0x34 +U 53 % 0x35 +V 54 % 0x36 +W 55 % 0x37 +X 56 % 0x38 +Y 57 % 0x39 +Z 58 % 0x3a +bracketleft 59 % 0x3b +backslash 60 % 0x3c +bracketright 61 % 0x3d +asciicircum 62 % 0x3e +underscore 63 % 0x3f +grave 64 % 0x40 +a 65 % 0x41 +b 66 % 0x42 +c 67 % 0x43 +d 68 % 0x44 +e 69 % 0x45 +f 70 % 0x46 +g 71 % 0x47 +h 72 % 0x48 +i 73 % 0x49 +j 74 % 0x4a +k 75 % 0x4b +l 76 % 0x4c +m 77 % 0x4d +n 78 % 0x4e +o 79 % 0x4f +p 80 % 0x50 +q 81 % 0x51 +r 82 % 0x52 +s 83 % 0x53 +t 84 % 0x54 +u 85 % 0x55 +v 86 % 0x56 +w 87 % 0x57 +x 88 % 0x58 +y 89 % 0x59 +z 90 % 0x5a +braceleft 91 % 0x5b +bar 92 % 0x5c +braceright 93 % 0x5d +asciitilde 94 % 0x5e +space 95 % 0x5f +exclamdown 96 % 0x60 +cent 97 % 0x61 +sterling 98 % 0x62 +currency 99 % 0x63 +yen 100 % 0x64 +brokenbar 101 % 0x65 +section 102 % 0x66 +dieresis 103 % 0x67 +copyright 104 % 0x68 +ordfeminine 105 % 0x69 +guillemotleft 106 % 0x6a +logicalnot 107 % 0x6b +hyphen 108 % 0x6c +registered 109 % 0x6d +macron 110 % 0x6e +degree 111 % 0x6f +plusminus 112 % 0x70 +twosuperior 113 % 0x71 +threesuperior 114 % 0x72 +acute 115 % 0x73 +mu 116 % 0x74 +paragraph 117 % 0x75 +periodcentered 118 % 0x76 +cedilla 119 % 0x77 +onesuperior 120 % 0x78 +ordmasculine 121 % 0x79 +guillemotright 122 % 0x7a +onequarter 123 % 0x7b +onehalf 124 % 0x7c +threequarters 125 % 0x7d +questiondown 126 % 0x7e +Agrave 127 % 0x7f +Aacute 128 % 0x80 +Acircumflex 129 % 0x81 +Atilde 130 % 0x82 +Adieresis 131 % 0x83 +Aring 132 % 0x84 +AE 133 % 0x85 +Ccedilla 134 % 0x86 +Egrave 135 % 0x87 +Eacute 136 % 0x88 +Ecircumflex 137 % 0x89 +Edieresis 138 % 0x8a +Igrave 139 % 0x8b +Iacute 140 % 0x8c +Icircumflex 141 % 0x8d +Idieresis 142 % 0x8e +Eth 143 % 0x8f +Ntilde 144 % 0x90 +Ograve 145 % 0x91 +Oacute 146 % 0x92 +Ocircumflex 147 % 0x93 +Otilde 148 % 0x94 +Odieresis 149 % 0x95 +multiply 150 % 0x96 +Oslash 151 % 0x97 +Ugrave 152 % 0x98 +Uacute 153 % 0x99 +Ucircumflex 154 % 0x9a +Udieresis 155 % 0x9b +Yacute 156 % 0x9c +Thorn 157 % 0x9d +germandbls 158 % 0x9e +agrave 159 % 0x9f +aacute 160 % 0xa0 +acircumflex 161 % 0xa1 +atilde 162 % 0xa2 +adieresis 163 % 0xa3 +aring 164 % 0xa4 +ae 165 % 0xa5 +ccedilla 166 % 0xa6 +egrave 167 % 0xa7 +eacute 168 % 0xa8 +ecircumflex 169 % 0xa9 +edieresis 170 % 0xaa +igrave 171 % 0xab +iacute 172 % 0xac +icircumflex 173 % 0xad +idieresis 174 % 0xae +eth 175 % 0xaf +ntilde 176 % 0xb0 +ograve 177 % 0xb1 +oacute 178 % 0xb2 +ocircumflex 179 % 0xb3 +otilde 180 % 0xb4 +odieresis 181 % 0xb5 +divide 182 % 0xb6 +oslash 183 % 0xb7 +ugrave 184 % 0xb8 +uacute 185 % 0xb9 +ucircumflex 186 % 0xba +udieresis 187 % 0xbb +yacute 188 % 0xbc +thorn 189 % 0xbd +ydieresis 190 % 0xbe +Amacron 191 % 0xbf +amacron 192 % 0xc0 +Abreve 193 % 0xc1 +abreve 194 % 0xc2 +Aogonek 195 % 0xc3 +aogonek 196 % 0xc4 +Cacute 197 % 0xc5 +cacute 198 % 0xc6 +Ccircumflex 199 % 0xc7 +ccircumflex 200 % 0xc8 +Cdotaccent 201 % 0xc9 +cdotaccent 202 % 0xca +Ccaron 203 % 0xcb +ccaron 204 % 0xcc +Dcaron 205 % 0xcd +dcaron 206 % 0xce +Dcroat 207 % 0xcf +dcroat 208 % 0xd0 +Emacron 209 % 0xd1 +emacron 210 % 0xd2 +Ebreve 211 % 0xd3 +ebreve 212 % 0xd4 +Edotaccent 213 % 0xd5 +edotaccent 214 % 0xd6 +Eogonek 215 % 0xd7 +eogonek 216 % 0xd8 +Ecaron 217 % 0xd9 +ecaron 218 % 0xda +Gcircumflex 219 % 0xdb +gcircumflex 220 % 0xdc +Gbreve 221 % 0xdd +gbreve 222 % 0xde +Gdotaccent 223 % 0xdf +gdotaccent 224 % 0xe0 +Gcommaaccent 225 % 0xe1 +gcommaaccent 226 % 0xe2 +Hcircumflex 227 % 0xe3 +hcircumflex 228 % 0xe4 +Hbar 229 % 0xe5 +hbar 230 % 0xe6 +Itilde 231 % 0xe7 +itilde 232 % 0xe8 +Imacron 233 % 0xe9 +imacron 234 % 0xea +Ibreve 235 % 0xeb +ibreve 236 % 0xec +Iogonek 237 % 0xed +iogonek 238 % 0xee +Idotaccent 239 % 0xef +dotlessi 240 % 0xf0 +IJ 241 % 0xf1 +ij 242 % 0xf2 +Jcircumflex 243 % 0xf3 +jcircumflex 244 % 0xf4 +Kcommaaccent 245 % 0xf5 +kcommaaccent 246 % 0xf6 +kgreenlandic 247 % 0xf7 +Lacute 248 % 0xf8 +lacute 249 % 0xf9 +Lcommaaccent 250 % 0xfa +lcommaaccent 251 % 0xfb +Lcaron 252 % 0xfc +lcaron 253 % 0xfd +Ldot 254 % 0xfe +ldot 255 % 0xff diff --git a/src/add-ons/print/drivers/pdf/encoding/t1enc1.enc b/src/add-ons/print/drivers/pdf/encoding/t1enc1.enc new file mode 100644 index 0000000000..e5a80f2e24 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/encoding/t1enc1.enc @@ -0,0 +1,260 @@ +% Encoding definition for PDFlib +% t1enc1 +% WARNING: MACHINE GENERATED DON'T CHANGE! +% Format: glyph name index (decimal) % index (hex) +Lslash 0 % 0x00 +lslash 1 % 0x01 +Nacute 2 % 0x02 +nacute 3 % 0x03 +Ncommaaccent 4 % 0x04 +ncommaaccent 5 % 0x05 +Ncaron 6 % 0x06 +ncaron 7 % 0x07 +napostrophe 8 % 0x08 +Eng 9 % 0x09 +eng 10 % 0x0a +Omacron 11 % 0x0b +omacron 12 % 0x0c +Obreve 13 % 0x0d +obreve 14 % 0x0e +Ohungarumlaut 15 % 0x0f +ohungarumlaut 16 % 0x10 +OE 17 % 0x11 +oe 18 % 0x12 +Racute 19 % 0x13 +racute 20 % 0x14 +Rcommaaccent 21 % 0x15 +rcommaaccent 22 % 0x16 +Rcaron 23 % 0x17 +rcaron 24 % 0x18 +Sacute 25 % 0x19 +sacute 26 % 0x1a +Scircumflex 27 % 0x1b +scircumflex 28 % 0x1c +Scedilla 29 % 0x1d +scedilla 30 % 0x1e +Scaron 31 % 0x1f +scaron 32 % 0x20 +Tcommaaccent 33 % 0x21 +tcommaaccent 34 % 0x22 +Tcaron 35 % 0x23 +tcaron 36 % 0x24 +Tbar 37 % 0x25 +tbar 38 % 0x26 +Utilde 39 % 0x27 +utilde 40 % 0x28 +Umacron 41 % 0x29 +umacron 42 % 0x2a +Ubreve 43 % 0x2b +ubreve 44 % 0x2c +Uring 45 % 0x2d +uring 46 % 0x2e +Uhungarumlaut 47 % 0x2f +uhungarumlaut 48 % 0x30 +Uogonek 49 % 0x31 +uogonek 50 % 0x32 +Wcircumflex 51 % 0x33 +wcircumflex 52 % 0x34 +Ycircumflex 53 % 0x35 +ycircumflex 54 % 0x36 +Ydieresis 55 % 0x37 +Zacute 56 % 0x38 +zacute 57 % 0x39 +Zdotaccent 58 % 0x3a +zdotaccent 59 % 0x3b +Zcaron 60 % 0x3c +zcaron 61 % 0x3d +longs 62 % 0x3e +florin 63 % 0x3f +Ohorn 64 % 0x40 +ohorn 65 % 0x41 +Uhorn 66 % 0x42 +uhorn 67 % 0x43 +Gcaron 68 % 0x44 +gcaron 69 % 0x45 +Aringacute 70 % 0x46 +aringacute 71 % 0x47 +AEacute 72 % 0x48 +aeacute 73 % 0x49 +Oslashacute 74 % 0x4a +oslashacute 75 % 0x4b +Scommaaccent 76 % 0x4c +scommaaccent 77 % 0x4d +Tcommaaccent 78 % 0x4e +tcommaaccent 79 % 0x4f +afii57929 80 % 0x50 +afii64937 81 % 0x51 +circumflex 82 % 0x52 +caron 83 % 0x53 +macron 84 % 0x54 +breve 85 % 0x55 +dotaccent 86 % 0x56 +ring 87 % 0x57 +ogonek 88 % 0x58 +tilde 89 % 0x59 +hungarumlaut 90 % 0x5a +gravecomb 91 % 0x5b +acutecomb 92 % 0x5c +tildecomb 93 % 0x5d +hookabovecomb 94 % 0x5e +dotbelowcomb 95 % 0x5f +tonos 96 % 0x60 +dieresistonos 97 % 0x61 +Alphatonos 98 % 0x62 +anoteleia 99 % 0x63 +Epsilontonos 100 % 0x64 +Etatonos 101 % 0x65 +Iotatonos 102 % 0x66 +Omicrontonos 103 % 0x67 +Upsilontonos 104 % 0x68 +Omegatonos 105 % 0x69 +iotadieresistonos 106 % 0x6a +Alpha 107 % 0x6b +Beta 108 % 0x6c +Gamma 109 % 0x6d +Delta 110 % 0x6e +Epsilon 111 % 0x6f +Zeta 112 % 0x70 +Eta 113 % 0x71 +Theta 114 % 0x72 +Iota 115 % 0x73 +Kappa 116 % 0x74 +Lambda 117 % 0x75 +Mu 118 % 0x76 +Nu 119 % 0x77 +Xi 120 % 0x78 +Omicron 121 % 0x79 +Pi 122 % 0x7a +Rho 123 % 0x7b +Sigma 124 % 0x7c +Tau 125 % 0x7d +Upsilon 126 % 0x7e +Phi 127 % 0x7f +Chi 128 % 0x80 +Psi 129 % 0x81 +Omega 130 % 0x82 +Iotadieresis 131 % 0x83 +Upsilondieresis 132 % 0x84 +alphatonos 133 % 0x85 +epsilontonos 134 % 0x86 +etatonos 135 % 0x87 +iotatonos 136 % 0x88 +upsilondieresistonos 137 % 0x89 +alpha 138 % 0x8a +beta 139 % 0x8b +gamma 140 % 0x8c +delta 141 % 0x8d +epsilon 142 % 0x8e +zeta 143 % 0x8f +eta 144 % 0x90 +theta 145 % 0x91 +iota 146 % 0x92 +kappa 147 % 0x93 +lambda 148 % 0x94 +mu 149 % 0x95 +nu 150 % 0x96 +xi 151 % 0x97 +omicron 152 % 0x98 +pi 153 % 0x99 +rho 154 % 0x9a +sigma1 155 % 0x9b +sigma 156 % 0x9c +tau 157 % 0x9d +upsilon 158 % 0x9e +phi 159 % 0x9f +chi 160 % 0xa0 +psi 161 % 0xa1 +omega 162 % 0xa2 +iotadieresis 163 % 0xa3 +upsilondieresis 164 % 0xa4 +omicrontonos 165 % 0xa5 +upsilontonos 166 % 0xa6 +omegatonos 167 % 0xa7 +theta1 168 % 0xa8 +Upsilon1 169 % 0xa9 +phi1 170 % 0xaa +omega1 171 % 0xab +afii10023 172 % 0xac +afii10051 173 % 0xad +afii10052 174 % 0xae +afii10053 175 % 0xaf +afii10054 176 % 0xb0 +afii10055 177 % 0xb1 +afii10056 178 % 0xb2 +afii10057 179 % 0xb3 +afii10058 180 % 0xb4 +afii10059 181 % 0xb5 +afii10060 182 % 0xb6 +afii10061 183 % 0xb7 +afii10062 184 % 0xb8 +afii10145 185 % 0xb9 +afii10017 186 % 0xba +afii10018 187 % 0xbb +afii10019 188 % 0xbc +afii10020 189 % 0xbd +afii10021 190 % 0xbe +afii10022 191 % 0xbf +afii10024 192 % 0xc0 +afii10025 193 % 0xc1 +afii10026 194 % 0xc2 +afii10027 195 % 0xc3 +afii10028 196 % 0xc4 +afii10029 197 % 0xc5 +afii10030 198 % 0xc6 +afii10031 199 % 0xc7 +afii10032 200 % 0xc8 +afii10033 201 % 0xc9 +afii10034 202 % 0xca +afii10035 203 % 0xcb +afii10036 204 % 0xcc +afii10037 205 % 0xcd +afii10038 206 % 0xce +afii10039 207 % 0xcf +afii10040 208 % 0xd0 +afii10041 209 % 0xd1 +afii10042 210 % 0xd2 +afii10043 211 % 0xd3 +afii10044 212 % 0xd4 +afii10045 213 % 0xd5 +afii10046 214 % 0xd6 +afii10047 215 % 0xd7 +afii10048 216 % 0xd8 +afii10049 217 % 0xd9 +afii10065 218 % 0xda +afii10066 219 % 0xdb +afii10067 220 % 0xdc +afii10068 221 % 0xdd +afii10069 222 % 0xde +afii10070 223 % 0xdf +afii10072 224 % 0xe0 +afii10073 225 % 0xe1 +afii10074 226 % 0xe2 +afii10075 227 % 0xe3 +afii10076 228 % 0xe4 +afii10077 229 % 0xe5 +afii10078 230 % 0xe6 +afii10079 231 % 0xe7 +afii10080 232 % 0xe8 +afii10081 233 % 0xe9 +afii10082 234 % 0xea +afii10083 235 % 0xeb +afii10084 236 % 0xec +afii10085 237 % 0xed +afii10086 238 % 0xee +afii10087 239 % 0xef +afii10088 240 % 0xf0 +afii10089 241 % 0xf1 +afii10090 242 % 0xf2 +afii10091 243 % 0xf3 +afii10092 244 % 0xf4 +afii10093 245 % 0xf5 +afii10094 246 % 0xf6 +afii10095 247 % 0xf7 +afii10096 248 % 0xf8 +afii10097 249 % 0xf9 +afii10071 250 % 0xfa +afii10099 251 % 0xfb +afii10100 252 % 0xfc +afii10101 253 % 0xfd +afii10102 254 % 0xfe +afii10103 255 % 0xff diff --git a/src/add-ons/print/drivers/pdf/encoding/t1enc2.enc b/src/add-ons/print/drivers/pdf/encoding/t1enc2.enc new file mode 100644 index 0000000000..67d04c4a64 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/encoding/t1enc2.enc @@ -0,0 +1,260 @@ +% Encoding definition for PDFlib +% t1enc2 +% WARNING: MACHINE GENERATED DON'T CHANGE! +% Format: glyph name index (decimal) % index (hex) +afii10104 0 % 0x00 +afii10105 1 % 0x01 +afii10106 2 % 0x02 +afii10107 3 % 0x03 +afii10108 4 % 0x04 +afii10109 5 % 0x05 +afii10110 6 % 0x06 +afii10193 7 % 0x07 +afii10146 8 % 0x08 +afii10194 9 % 0x09 +afii10147 10 % 0x0a +afii10195 11 % 0x0b +afii10148 12 % 0x0c +afii10196 13 % 0x0d +afii10050 14 % 0x0e +afii10098 15 % 0x0f +afii10846 16 % 0x10 +afii57799 17 % 0x11 +afii57801 18 % 0x12 +afii57800 19 % 0x13 +afii57802 20 % 0x14 +afii57793 21 % 0x15 +afii57794 22 % 0x16 +afii57795 23 % 0x17 +afii57798 24 % 0x18 +afii57797 25 % 0x19 +afii57806 26 % 0x1a +afii57796 27 % 0x1b +afii57807 28 % 0x1c +afii57839 29 % 0x1d +afii57645 30 % 0x1e +afii57841 31 % 0x1f +afii57842 32 % 0x20 +afii57804 33 % 0x21 +afii57803 34 % 0x22 +afii57658 35 % 0x23 +afii57664 36 % 0x24 +afii57665 37 % 0x25 +afii57666 38 % 0x26 +afii57667 39 % 0x27 +afii57668 40 % 0x28 +afii57669 41 % 0x29 +afii57670 42 % 0x2a +afii57671 43 % 0x2b +afii57672 44 % 0x2c +afii57673 45 % 0x2d +afii57674 46 % 0x2e +afii57675 47 % 0x2f +afii57676 48 % 0x30 +afii57677 49 % 0x31 +afii57678 50 % 0x32 +afii57679 51 % 0x33 +afii57680 52 % 0x34 +afii57681 53 % 0x35 +afii57682 54 % 0x36 +afii57683 55 % 0x37 +afii57684 56 % 0x38 +afii57685 57 % 0x39 +afii57686 58 % 0x3a +afii57687 59 % 0x3b +afii57688 60 % 0x3c +afii57689 61 % 0x3d +afii57690 62 % 0x3e +afii57716 63 % 0x3f +afii57717 64 % 0x40 +afii57718 65 % 0x41 +afii57388 66 % 0x42 +afii57403 67 % 0x43 +afii57407 68 % 0x44 +afii57409 69 % 0x45 +afii57410 70 % 0x46 +afii57411 71 % 0x47 +afii57412 72 % 0x48 +afii57413 73 % 0x49 +afii57414 74 % 0x4a +afii57415 75 % 0x4b +afii57416 76 % 0x4c +afii57417 77 % 0x4d +afii57418 78 % 0x4e +afii57419 79 % 0x4f +afii57420 80 % 0x50 +afii57421 81 % 0x51 +afii57422 82 % 0x52 +afii57423 83 % 0x53 +afii57424 84 % 0x54 +afii57425 85 % 0x55 +afii57426 86 % 0x56 +afii57427 87 % 0x57 +afii57428 88 % 0x58 +afii57429 89 % 0x59 +afii57430 90 % 0x5a +afii57431 91 % 0x5b +afii57432 92 % 0x5c +afii57433 93 % 0x5d +afii57434 94 % 0x5e +afii57440 95 % 0x5f +afii57441 96 % 0x60 +afii57442 97 % 0x61 +afii57443 98 % 0x62 +afii57444 99 % 0x63 +afii57445 100 % 0x64 +afii57446 101 % 0x65 +afii57470 102 % 0x66 +afii57448 103 % 0x67 +afii57449 104 % 0x68 +afii57450 105 % 0x69 +afii57451 106 % 0x6a +afii57452 107 % 0x6b +afii57453 108 % 0x6c +afii57454 109 % 0x6d +afii57455 110 % 0x6e +afii57456 111 % 0x6f +afii57457 112 % 0x70 +afii57458 113 % 0x71 +afii57392 114 % 0x72 +afii57393 115 % 0x73 +afii57394 116 % 0x74 +afii57395 117 % 0x75 +afii57396 118 % 0x76 +afii57397 119 % 0x77 +afii57398 120 % 0x78 +afii57399 121 % 0x79 +afii57400 122 % 0x7a +afii57401 123 % 0x7b +afii57381 124 % 0x7c +afii63167 125 % 0x7d +afii57511 126 % 0x7e +afii57506 127 % 0x7f +afii57507 128 % 0x80 +afii57512 129 % 0x81 +afii57513 130 % 0x82 +afii57508 131 % 0x83 +afii57505 132 % 0x84 +afii57509 133 % 0x85 +afii57514 134 % 0x86 +afii57519 135 % 0x87 +afii57534 136 % 0x88 +Wgrave 137 % 0x89 +wgrave 138 % 0x8a +Wacute 139 % 0x8b +wacute 140 % 0x8c +Wdieresis 141 % 0x8d +wdieresis 142 % 0x8e +Ygrave 143 % 0x8f +ygrave 144 % 0x90 +afii61664 145 % 0x91 +afii301 146 % 0x92 +afii299 147 % 0x93 +afii300 148 % 0x94 +figuredash 149 % 0x95 +endash 150 % 0x96 +emdash 151 % 0x97 +afii00208 152 % 0x98 +underscoredbl 153 % 0x99 +quoteleft 154 % 0x9a +quoteright 155 % 0x9b +quotesinglbase 156 % 0x9c +quotereversed 157 % 0x9d +quotedblleft 158 % 0x9e +quotedblright 159 % 0x9f +quotedblbase 160 % 0xa0 +dagger 161 % 0xa1 +daggerdbl 162 % 0xa2 +bullet 163 % 0xa3 +onedotenleader 164 % 0xa4 +twodotenleader 165 % 0xa5 +ellipsis 166 % 0xa6 +afii61573 167 % 0xa7 +afii61574 168 % 0xa8 +afii61575 169 % 0xa9 +perthousand 170 % 0xaa +minute 171 % 0xab +second 172 % 0xac +guilsinglleft 173 % 0xad +guilsinglright 174 % 0xae +exclamdbl 175 % 0xaf +fraction 176 % 0xb0 +zerosuperior 177 % 0xb1 +foursuperior 178 % 0xb2 +fivesuperior 179 % 0xb3 +sixsuperior 180 % 0xb4 +sevensuperior 181 % 0xb5 +eightsuperior 182 % 0xb6 +ninesuperior 183 % 0xb7 +parenleftsuperior 184 % 0xb8 +parenrightsuperior 185 % 0xb9 +nsuperior 186 % 0xba +zeroinferior 187 % 0xbb +oneinferior 188 % 0xbc +twoinferior 189 % 0xbd +threeinferior 190 % 0xbe +fourinferior 191 % 0xbf +fiveinferior 192 % 0xc0 +sixinferior 193 % 0xc1 +seveninferior 194 % 0xc2 +eightinferior 195 % 0xc3 +nineinferior 196 % 0xc4 +parenleftinferior 197 % 0xc5 +parenrightinferior 198 % 0xc6 +colonmonetary 199 % 0xc7 +franc 200 % 0xc8 +lira 201 % 0xc9 +peseta 202 % 0xca +afii57636 203 % 0xcb +dong 204 % 0xcc +Euro 205 % 0xcd +afii61248 206 % 0xce +Ifraktur 207 % 0xcf +afii61289 208 % 0xd0 +afii61352 209 % 0xd1 +weierstrass 210 % 0xd2 +Rfraktur 211 % 0xd3 +prescription 212 % 0xd4 +trademark 213 % 0xd5 +Omega 214 % 0xd6 +estimated 215 % 0xd7 +aleph 216 % 0xd8 +onethird 217 % 0xd9 +twothirds 218 % 0xda +oneeighth 219 % 0xdb +threeeighths 220 % 0xdc +fiveeighths 221 % 0xdd +seveneighths 222 % 0xde +arrowleft 223 % 0xdf +arrowup 224 % 0xe0 +arrowright 225 % 0xe1 +arrowdown 226 % 0xe2 +arrowboth 227 % 0xe3 +arrowupdn 228 % 0xe4 +arrowupdnbse 229 % 0xe5 +carriagereturn 230 % 0xe6 +arrowdblleft 231 % 0xe7 +arrowdblup 232 % 0xe8 +arrowdblright 233 % 0xe9 +arrowdbldown 234 % 0xea +arrowdblboth 235 % 0xeb +universal 236 % 0xec +partialdiff 237 % 0xed +existential 238 % 0xee +emptyset 239 % 0xef +Delta 240 % 0xf0 +gradient 241 % 0xf1 +element 242 % 0xf2 +notelement 243 % 0xf3 +suchthat 244 % 0xf4 +product 245 % 0xf5 +summation 246 % 0xf6 +minus 247 % 0xf7 +fraction 248 % 0xf8 +asteriskmath 249 % 0xf9 +periodcentered 250 % 0xfa +radical 251 % 0xfb +proportional 252 % 0xfc +infinity 253 % 0xfd +orthogonal 254 % 0xfe +angle 255 % 0xff diff --git a/src/add-ons/print/drivers/pdf/encoding/t1enc3.enc b/src/add-ons/print/drivers/pdf/encoding/t1enc3.enc new file mode 100644 index 0000000000..4eea00e567 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/encoding/t1enc3.enc @@ -0,0 +1,260 @@ +% Encoding definition for PDFlib +% t1enc3 +% WARNING: MACHINE GENERATED DON'T CHANGE! +% Format: glyph name index (decimal) % index (hex) +logicaland 0 % 0x00 +logicalor 1 % 0x01 +intersection 2 % 0x02 +union 3 % 0x03 +integral 4 % 0x04 +therefore 5 % 0x05 +similar 6 % 0x06 +congruent 7 % 0x07 +approxequal 8 % 0x08 +notequal 9 % 0x09 +equivalence 10 % 0x0a +lessequal 11 % 0x0b +greaterequal 12 % 0x0c +propersubset 13 % 0x0d +propersuperset 14 % 0x0e +notsubset 15 % 0x0f +reflexsubset 16 % 0x10 +reflexsuperset 17 % 0x11 +circleplus 18 % 0x12 +circlemultiply 19 % 0x13 +perpendicular 20 % 0x14 +dotmath 21 % 0x15 +house 22 % 0x16 +revlogicalnot 23 % 0x17 +integraltp 24 % 0x18 +integralbt 25 % 0x19 +angleleft 26 % 0x1a +angleright 27 % 0x1b +SF100000 28 % 0x1c +SF110000 29 % 0x1d +SF010000 30 % 0x1e +SF030000 31 % 0x1f +SF020000 32 % 0x20 +SF040000 33 % 0x21 +SF080000 34 % 0x22 +SF090000 35 % 0x23 +SF060000 36 % 0x24 +SF070000 37 % 0x25 +SF050000 38 % 0x26 +SF430000 39 % 0x27 +SF240000 40 % 0x28 +SF510000 41 % 0x29 +SF520000 42 % 0x2a +SF390000 43 % 0x2b +SF220000 44 % 0x2c +SF210000 45 % 0x2d +SF250000 46 % 0x2e +SF500000 47 % 0x2f +SF490000 48 % 0x30 +SF380000 49 % 0x31 +SF280000 50 % 0x32 +SF270000 51 % 0x33 +SF260000 52 % 0x34 +SF360000 53 % 0x35 +SF370000 54 % 0x36 +SF420000 55 % 0x37 +SF190000 56 % 0x38 +SF200000 57 % 0x39 +SF230000 58 % 0x3a +SF470000 59 % 0x3b +SF480000 60 % 0x3c +SF410000 61 % 0x3d +SF450000 62 % 0x3e +SF460000 63 % 0x3f +SF400000 64 % 0x40 +SF540000 65 % 0x41 +SF530000 66 % 0x42 +SF440000 67 % 0x43 +upblock 68 % 0x44 +dnblock 69 % 0x45 +block 70 % 0x46 +lfblock 71 % 0x47 +rtblock 72 % 0x48 +ltshade 73 % 0x49 +shade 74 % 0x4a +dkshade 75 % 0x4b +filledbox 76 % 0x4c +H22073 77 % 0x4d +H18543 78 % 0x4e +H18551 79 % 0x4f +filledrect 80 % 0x50 +triagup 81 % 0x51 +triagrt 82 % 0x52 +triagdn 83 % 0x53 +triaglf 84 % 0x54 +lozenge 85 % 0x55 +circle 86 % 0x56 +H18533 87 % 0x57 +invbullet 88 % 0x58 +invcircle 89 % 0x59 +openbullet 90 % 0x5a +smileface 91 % 0x5b +invsmileface 92 % 0x5c +sun 93 % 0x5d +female 94 % 0x5e +male 95 % 0x5f +spade 96 % 0x60 +club 97 % 0x61 +heart 98 % 0x62 +diamond 99 % 0x63 +musicalnote 100 % 0x64 +musicalnotedbl 101 % 0x65 +dotlessj 102 % 0x66 +LL 103 % 0x67 +ll 104 % 0x68 +Scedilla 105 % 0x69 +scedilla 106 % 0x6a +commaaccent 107 % 0x6b +afii10063 108 % 0x6c +afii10064 109 % 0x6d +afii10192 110 % 0x6e +afii10831 111 % 0x6f +afii10832 112 % 0x70 +Acute 113 % 0x71 +Caron 114 % 0x72 +Dieresis 115 % 0x73 +DieresisAcute 116 % 0x74 +DieresisGrave 117 % 0x75 +Grave 118 % 0x76 +Hungarumlaut 119 % 0x77 +Macron 120 % 0x78 +cyrBreve 121 % 0x79 +cyrFlex 122 % 0x7a +dblGrave 123 % 0x7b +cyrbreve 124 % 0x7c +cyrflex 125 % 0x7d +dblgrave 126 % 0x7e +dieresisacute 127 % 0x7f +dieresisgrave 128 % 0x80 +copyrightserif 129 % 0x81 +registerserif 130 % 0x82 +trademarkserif 131 % 0x83 +onefitted 132 % 0x84 +rupiah 133 % 0x85 +threequartersemdash 134 % 0x86 +centinferior 135 % 0x87 +centsuperior 136 % 0x88 +commainferior 137 % 0x89 +commasuperior 138 % 0x8a +dollarinferior 139 % 0x8b +dollarsuperior 140 % 0x8c +hypheninferior 141 % 0x8d +hyphensuperior 142 % 0x8e +periodinferior 143 % 0x8f +periodsuperior 144 % 0x90 +asuperior 145 % 0x91 +bsuperior 146 % 0x92 +dsuperior 147 % 0x93 +esuperior 148 % 0x94 +isuperior 149 % 0x95 +lsuperior 150 % 0x96 +msuperior 151 % 0x97 +osuperior 152 % 0x98 +rsuperior 153 % 0x99 +ssuperior 154 % 0x9a +tsuperior 155 % 0x9b +Brevesmall 156 % 0x9c +Caronsmall 157 % 0x9d +Circumflexsmall 158 % 0x9e +Dotaccentsmall 159 % 0x9f +Hungarumlautsmall 160 % 0xa0 +Lslashsmall 161 % 0xa1 +OEsmall 162 % 0xa2 +Ogoneksmall 163 % 0xa3 +Ringsmall 164 % 0xa4 +Scaronsmall 165 % 0xa5 +Tildesmall 166 % 0xa6 +Zcaronsmall 167 % 0xa7 +exclamsmall 168 % 0xa8 +dollaroldstyle 169 % 0xa9 +ampersandsmall 170 % 0xaa +zerooldstyle 171 % 0xab +oneoldstyle 172 % 0xac +twooldstyle 173 % 0xad +threeoldstyle 174 % 0xae +fouroldstyle 175 % 0xaf +fiveoldstyle 176 % 0xb0 +sixoldstyle 177 % 0xb1 +sevenoldstyle 178 % 0xb2 +eightoldstyle 179 % 0xb3 +nineoldstyle 180 % 0xb4 +questionsmall 181 % 0xb5 +Gravesmall 182 % 0xb6 +Asmall 183 % 0xb7 +Bsmall 184 % 0xb8 +Csmall 185 % 0xb9 +Dsmall 186 % 0xba +Esmall 187 % 0xbb +Fsmall 188 % 0xbc +Gsmall 189 % 0xbd +Hsmall 190 % 0xbe +Ismall 191 % 0xbf +Jsmall 192 % 0xc0 +Ksmall 193 % 0xc1 +Lsmall 194 % 0xc2 +Msmall 195 % 0xc3 +Nsmall 196 % 0xc4 +Osmall 197 % 0xc5 +Psmall 198 % 0xc6 +Qsmall 199 % 0xc7 +Rsmall 200 % 0xc8 +Ssmall 201 % 0xc9 +Tsmall 202 % 0xca +Usmall 203 % 0xcb +Vsmall 204 % 0xcc +Wsmall 205 % 0xcd +Xsmall 206 % 0xce +Ysmall 207 % 0xcf +Zsmall 208 % 0xd0 +exclamdownsmall 209 % 0xd1 +centoldstyle 210 % 0xd2 +Dieresissmall 211 % 0xd3 +Macronsmall 212 % 0xd4 +Acutesmall 213 % 0xd5 +Cedillasmall 214 % 0xd6 +questiondownsmall 215 % 0xd7 +Agravesmall 216 % 0xd8 +Aacutesmall 217 % 0xd9 +Acircumflexsmall 218 % 0xda +Atildesmall 219 % 0xdb +Adieresissmall 220 % 0xdc +Aringsmall 221 % 0xdd +AEsmall 222 % 0xde +Ccedillasmall 223 % 0xdf +Egravesmall 224 % 0xe0 +Eacutesmall 225 % 0xe1 +Ecircumflexsmall 226 % 0xe2 +Edieresissmall 227 % 0xe3 +Igravesmall 228 % 0xe4 +Iacutesmall 229 % 0xe5 +Icircumflexsmall 230 % 0xe6 +Idieresissmall 231 % 0xe7 +Ethsmall 232 % 0xe8 +Ntildesmall 233 % 0xe9 +Ogravesmall 234 % 0xea +Oacutesmall 235 % 0xeb +Ocircumflexsmall 236 % 0xec +Otildesmall 237 % 0xed +Odieresissmall 238 % 0xee +Oslashsmall 239 % 0xef +Ugravesmall 240 % 0xf0 +Uacutesmall 241 % 0xf1 +Ucircumflexsmall 242 % 0xf2 +Udieresissmall 243 % 0xf3 +Yacutesmall 244 % 0xf4 +Thornsmall 245 % 0xf5 +Ydieresissmall 246 % 0xf6 +radicalex 247 % 0xf7 +arrowvertex 248 % 0xf8 +arrowhorizex 249 % 0xf9 +registersans 250 % 0xfa +copyrightsans 251 % 0xfb +trademarksans 252 % 0xfc +parenlefttp 253 % 0xfd +parenleftex 254 % 0xfe +parenleftbt 255 % 0xff diff --git a/src/add-ons/print/drivers/pdf/encoding/t1enc4.enc b/src/add-ons/print/drivers/pdf/encoding/t1enc4.enc new file mode 100644 index 0000000000..67d221c877 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/encoding/t1enc4.enc @@ -0,0 +1,31 @@ +% Encoding definition for PDFlib +% t1enc4 +% WARNING: MACHINE GENERATED DON'T CHANGE! +% Format: glyph name index (decimal) % index (hex) +bracketlefttp 0 % 0x00 +bracketleftex 1 % 0x01 +bracketleftbt 2 % 0x02 +bracelefttp 3 % 0x03 +braceleftmid 4 % 0x04 +braceleftbt 5 % 0x05 +braceex 6 % 0x06 +integralex 7 % 0x07 +parenrighttp 8 % 0x08 +parenrightex 9 % 0x09 +parenrightbt 10 % 0x0a +bracketrighttp 11 % 0x0b +bracketrightex 12 % 0x0c +bracketrightbt 13 % 0x0d +bracerighttp 14 % 0x0e +bracerightmid 15 % 0x0f +bracerightbt 16 % 0x10 +ff 17 % 0x11 +fi 18 % 0x12 +fl 19 % 0x13 +ffi 20 % 0x14 +ffl 21 % 0x15 +afii57705 22 % 0x16 +afii57694 23 % 0x17 +afii57695 24 % 0x18 +afii57723 25 % 0x19 +afii57700 26 % 0x1a diff --git a/src/add-ons/print/drivers/pdf/encoding/ttenc0.cpg b/src/add-ons/print/drivers/pdf/encoding/ttenc0.cpg new file mode 100644 index 0000000000..22acaba1db --- /dev/null +++ b/src/add-ons/print/drivers/pdf/encoding/ttenc0.cpg @@ -0,0 +1,260 @@ +% Encoding definition for PDFlib +% ttenc0 +% WARNING: MACHINE GENERATED DON'T CHANGE! +% Format: unicode (hex) index (decimal) % index (hex) +0x20 0 % 0x00 +0x21 1 % 0x01 +0x22 2 % 0x02 +0x23 3 % 0x03 +0x24 4 % 0x04 +0x25 5 % 0x05 +0x26 6 % 0x06 +0x27 7 % 0x07 +0x28 8 % 0x08 +0x29 9 % 0x09 +0x2a 10 % 0x0a +0x2b 11 % 0x0b +0x2c 12 % 0x0c +0x2d 13 % 0x0d +0x2e 14 % 0x0e +0x2f 15 % 0x0f +0x30 16 % 0x10 +0x31 17 % 0x11 +0x32 18 % 0x12 +0x33 19 % 0x13 +0x34 20 % 0x14 +0x35 21 % 0x15 +0x36 22 % 0x16 +0x37 23 % 0x17 +0x38 24 % 0x18 +0x39 25 % 0x19 +0x3a 26 % 0x1a +0x3b 27 % 0x1b +0x3c 28 % 0x1c +0x3d 29 % 0x1d +0x3e 30 % 0x1e +0x3f 31 % 0x1f +0x40 32 % 0x20 +0x41 33 % 0x21 +0x42 34 % 0x22 +0x43 35 % 0x23 +0x44 36 % 0x24 +0x45 37 % 0x25 +0x46 38 % 0x26 +0x47 39 % 0x27 +0x48 40 % 0x28 +0x49 41 % 0x29 +0x4a 42 % 0x2a +0x4b 43 % 0x2b +0x4c 44 % 0x2c +0x4d 45 % 0x2d +0x4e 46 % 0x2e +0x4f 47 % 0x2f +0x50 48 % 0x30 +0x51 49 % 0x31 +0x52 50 % 0x32 +0x53 51 % 0x33 +0x54 52 % 0x34 +0x55 53 % 0x35 +0x56 54 % 0x36 +0x57 55 % 0x37 +0x58 56 % 0x38 +0x59 57 % 0x39 +0x5a 58 % 0x3a +0x5b 59 % 0x3b +0x5c 60 % 0x3c +0x5d 61 % 0x3d +0x5e 62 % 0x3e +0x5f 63 % 0x3f +0x60 64 % 0x40 +0x61 65 % 0x41 +0x62 66 % 0x42 +0x63 67 % 0x43 +0x64 68 % 0x44 +0x65 69 % 0x45 +0x66 70 % 0x46 +0x67 71 % 0x47 +0x68 72 % 0x48 +0x69 73 % 0x49 +0x6a 74 % 0x4a +0x6b 75 % 0x4b +0x6c 76 % 0x4c +0x6d 77 % 0x4d +0x6e 78 % 0x4e +0x6f 79 % 0x4f +0x70 80 % 0x50 +0x71 81 % 0x51 +0x72 82 % 0x52 +0x73 83 % 0x53 +0x74 84 % 0x54 +0x75 85 % 0x55 +0x76 86 % 0x56 +0x77 87 % 0x57 +0x78 88 % 0x58 +0x79 89 % 0x59 +0x7a 90 % 0x5a +0x7b 91 % 0x5b +0x7c 92 % 0x5c +0x7d 93 % 0x5d +0x7e 94 % 0x5e +0xa0 95 % 0x5f +0xa1 96 % 0x60 +0xa2 97 % 0x61 +0xa3 98 % 0x62 +0xa4 99 % 0x63 +0xa5 100 % 0x64 +0xa6 101 % 0x65 +0xa7 102 % 0x66 +0xa8 103 % 0x67 +0xa9 104 % 0x68 +0xaa 105 % 0x69 +0xab 106 % 0x6a +0xac 107 % 0x6b +0xad 108 % 0x6c +0xae 109 % 0x6d +0xaf 110 % 0x6e +0xb0 111 % 0x6f +0xb1 112 % 0x70 +0xb2 113 % 0x71 +0xb3 114 % 0x72 +0xb4 115 % 0x73 +0xb5 116 % 0x74 +0xb6 117 % 0x75 +0xb7 118 % 0x76 +0xb8 119 % 0x77 +0xb9 120 % 0x78 +0xba 121 % 0x79 +0xbb 122 % 0x7a +0xbc 123 % 0x7b +0xbd 124 % 0x7c +0xbe 125 % 0x7d +0xbf 126 % 0x7e +0xc0 127 % 0x7f +0xc1 128 % 0x80 +0xc2 129 % 0x81 +0xc3 130 % 0x82 +0xc4 131 % 0x83 +0xc5 132 % 0x84 +0xc6 133 % 0x85 +0xc7 134 % 0x86 +0xc8 135 % 0x87 +0xc9 136 % 0x88 +0xca 137 % 0x89 +0xcb 138 % 0x8a +0xcc 139 % 0x8b +0xcd 140 % 0x8c +0xce 141 % 0x8d +0xcf 142 % 0x8e +0xd0 143 % 0x8f +0xd1 144 % 0x90 +0xd2 145 % 0x91 +0xd3 146 % 0x92 +0xd4 147 % 0x93 +0xd5 148 % 0x94 +0xd6 149 % 0x95 +0xd7 150 % 0x96 +0xd8 151 % 0x97 +0xd9 152 % 0x98 +0xda 153 % 0x99 +0xdb 154 % 0x9a +0xdc 155 % 0x9b +0xdd 156 % 0x9c +0xde 157 % 0x9d +0xdf 158 % 0x9e +0xe0 159 % 0x9f +0xe1 160 % 0xa0 +0xe2 161 % 0xa1 +0xe3 162 % 0xa2 +0xe4 163 % 0xa3 +0xe5 164 % 0xa4 +0xe6 165 % 0xa5 +0xe7 166 % 0xa6 +0xe8 167 % 0xa7 +0xe9 168 % 0xa8 +0xea 169 % 0xa9 +0xeb 170 % 0xaa +0xec 171 % 0xab +0xed 172 % 0xac +0xee 173 % 0xad +0xef 174 % 0xae +0xf0 175 % 0xaf +0xf1 176 % 0xb0 +0xf2 177 % 0xb1 +0xf3 178 % 0xb2 +0xf4 179 % 0xb3 +0xf5 180 % 0xb4 +0xf6 181 % 0xb5 +0xf7 182 % 0xb6 +0xf8 183 % 0xb7 +0xf9 184 % 0xb8 +0xfa 185 % 0xb9 +0xfb 186 % 0xba +0xfc 187 % 0xbb +0xfd 188 % 0xbc +0xfe 189 % 0xbd +0xff 190 % 0xbe +0x100 191 % 0xbf +0x101 192 % 0xc0 +0x102 193 % 0xc1 +0x103 194 % 0xc2 +0x104 195 % 0xc3 +0x105 196 % 0xc4 +0x106 197 % 0xc5 +0x107 198 % 0xc6 +0x108 199 % 0xc7 +0x109 200 % 0xc8 +0x10a 201 % 0xc9 +0x10b 202 % 0xca +0x10c 203 % 0xcb +0x10d 204 % 0xcc +0x10e 205 % 0xcd +0x10f 206 % 0xce +0x110 207 % 0xcf +0x111 208 % 0xd0 +0x112 209 % 0xd1 +0x113 210 % 0xd2 +0x114 211 % 0xd3 +0x115 212 % 0xd4 +0x116 213 % 0xd5 +0x117 214 % 0xd6 +0x118 215 % 0xd7 +0x119 216 % 0xd8 +0x11a 217 % 0xd9 +0x11b 218 % 0xda +0x11c 219 % 0xdb +0x11d 220 % 0xdc +0x11e 221 % 0xdd +0x11f 222 % 0xde +0x120 223 % 0xdf +0x121 224 % 0xe0 +0x122 225 % 0xe1 +0x123 226 % 0xe2 +0x124 227 % 0xe3 +0x125 228 % 0xe4 +0x126 229 % 0xe5 +0x127 230 % 0xe6 +0x128 231 % 0xe7 +0x129 232 % 0xe8 +0x12a 233 % 0xe9 +0x12b 234 % 0xea +0x12c 235 % 0xeb +0x12d 236 % 0xec +0x12e 237 % 0xed +0x12f 238 % 0xee +0x130 239 % 0xef +0x131 240 % 0xf0 +0x132 241 % 0xf1 +0x133 242 % 0xf2 +0x134 243 % 0xf3 +0x135 244 % 0xf4 +0x136 245 % 0xf5 +0x137 246 % 0xf6 +0x138 247 % 0xf7 +0x139 248 % 0xf8 +0x13a 249 % 0xf9 +0x13b 250 % 0xfa +0x13c 251 % 0xfb +0x13d 252 % 0xfc +0x13e 253 % 0xfd +0x13f 254 % 0xfe +0x140 255 % 0xff diff --git a/src/add-ons/print/drivers/pdf/encoding/ttenc1.cpg b/src/add-ons/print/drivers/pdf/encoding/ttenc1.cpg new file mode 100644 index 0000000000..80271ef295 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/encoding/ttenc1.cpg @@ -0,0 +1,260 @@ +% Encoding definition for PDFlib +% ttenc1 +% WARNING: MACHINE GENERATED DON'T CHANGE! +% Format: unicode (hex) index (decimal) % index (hex) +0x141 0 % 0x00 +0x142 1 % 0x01 +0x143 2 % 0x02 +0x144 3 % 0x03 +0x145 4 % 0x04 +0x146 5 % 0x05 +0x147 6 % 0x06 +0x148 7 % 0x07 +0x149 8 % 0x08 +0x14a 9 % 0x09 +0x14b 10 % 0x0a +0x14c 11 % 0x0b +0x14d 12 % 0x0c +0x14e 13 % 0x0d +0x14f 14 % 0x0e +0x150 15 % 0x0f +0x151 16 % 0x10 +0x152 17 % 0x11 +0x153 18 % 0x12 +0x154 19 % 0x13 +0x155 20 % 0x14 +0x156 21 % 0x15 +0x157 22 % 0x16 +0x158 23 % 0x17 +0x159 24 % 0x18 +0x15a 25 % 0x19 +0x15b 26 % 0x1a +0x15c 27 % 0x1b +0x15d 28 % 0x1c +0x15e 29 % 0x1d +0x15f 30 % 0x1e +0x160 31 % 0x1f +0x161 32 % 0x20 +0x162 33 % 0x21 +0x163 34 % 0x22 +0x164 35 % 0x23 +0x165 36 % 0x24 +0x166 37 % 0x25 +0x167 38 % 0x26 +0x168 39 % 0x27 +0x169 40 % 0x28 +0x16a 41 % 0x29 +0x16b 42 % 0x2a +0x16c 43 % 0x2b +0x16d 44 % 0x2c +0x16e 45 % 0x2d +0x16f 46 % 0x2e +0x170 47 % 0x2f +0x171 48 % 0x30 +0x172 49 % 0x31 +0x173 50 % 0x32 +0x174 51 % 0x33 +0x175 52 % 0x34 +0x176 53 % 0x35 +0x177 54 % 0x36 +0x178 55 % 0x37 +0x179 56 % 0x38 +0x17a 57 % 0x39 +0x17b 58 % 0x3a +0x17c 59 % 0x3b +0x17d 60 % 0x3c +0x17e 61 % 0x3d +0x17f 62 % 0x3e +0x192 63 % 0x3f +0x1a0 64 % 0x40 +0x1a1 65 % 0x41 +0x1af 66 % 0x42 +0x1b0 67 % 0x43 +0x1e6 68 % 0x44 +0x1e7 69 % 0x45 +0x1fa 70 % 0x46 +0x1fb 71 % 0x47 +0x1fc 72 % 0x48 +0x1fd 73 % 0x49 +0x1fe 74 % 0x4a +0x1ff 75 % 0x4b +0x218 76 % 0x4c +0x219 77 % 0x4d +0x21a 78 % 0x4e +0x21b 79 % 0x4f +0x2bc 80 % 0x50 +0x2bd 81 % 0x51 +0x2c6 82 % 0x52 +0x2c7 83 % 0x53 +0x2c9 84 % 0x54 +0x2d8 85 % 0x55 +0x2d9 86 % 0x56 +0x2da 87 % 0x57 +0x2db 88 % 0x58 +0x2dc 89 % 0x59 +0x2dd 90 % 0x5a +0x300 91 % 0x5b +0x301 92 % 0x5c +0x303 93 % 0x5d +0x309 94 % 0x5e +0x323 95 % 0x5f +0x384 96 % 0x60 +0x385 97 % 0x61 +0x386 98 % 0x62 +0x387 99 % 0x63 +0x388 100 % 0x64 +0x389 101 % 0x65 +0x38a 102 % 0x66 +0x38c 103 % 0x67 +0x38e 104 % 0x68 +0x38f 105 % 0x69 +0x390 106 % 0x6a +0x391 107 % 0x6b +0x392 108 % 0x6c +0x393 109 % 0x6d +0x394 110 % 0x6e +0x395 111 % 0x6f +0x396 112 % 0x70 +0x397 113 % 0x71 +0x398 114 % 0x72 +0x399 115 % 0x73 +0x39a 116 % 0x74 +0x39b 117 % 0x75 +0x39c 118 % 0x76 +0x39d 119 % 0x77 +0x39e 120 % 0x78 +0x39f 121 % 0x79 +0x3a0 122 % 0x7a +0x3a1 123 % 0x7b +0x3a3 124 % 0x7c +0x3a4 125 % 0x7d +0x3a5 126 % 0x7e +0x3a6 127 % 0x7f +0x3a7 128 % 0x80 +0x3a8 129 % 0x81 +0x3a9 130 % 0x82 +0x3aa 131 % 0x83 +0x3ab 132 % 0x84 +0x3ac 133 % 0x85 +0x3ad 134 % 0x86 +0x3ae 135 % 0x87 +0x3af 136 % 0x88 +0x3b0 137 % 0x89 +0x3b1 138 % 0x8a +0x3b2 139 % 0x8b +0x3b3 140 % 0x8c +0x3b4 141 % 0x8d +0x3b5 142 % 0x8e +0x3b6 143 % 0x8f +0x3b7 144 % 0x90 +0x3b8 145 % 0x91 +0x3b9 146 % 0x92 +0x3ba 147 % 0x93 +0x3bb 148 % 0x94 +0x3bc 149 % 0x95 +0x3bd 150 % 0x96 +0x3be 151 % 0x97 +0x3bf 152 % 0x98 +0x3c0 153 % 0x99 +0x3c1 154 % 0x9a +0x3c2 155 % 0x9b +0x3c3 156 % 0x9c +0x3c4 157 % 0x9d +0x3c5 158 % 0x9e +0x3c6 159 % 0x9f +0x3c7 160 % 0xa0 +0x3c8 161 % 0xa1 +0x3c9 162 % 0xa2 +0x3ca 163 % 0xa3 +0x3cb 164 % 0xa4 +0x3cc 165 % 0xa5 +0x3cd 166 % 0xa6 +0x3ce 167 % 0xa7 +0x3d1 168 % 0xa8 +0x3d2 169 % 0xa9 +0x3d5 170 % 0xaa +0x3d6 171 % 0xab +0x401 172 % 0xac +0x402 173 % 0xad +0x403 174 % 0xae +0x404 175 % 0xaf +0x405 176 % 0xb0 +0x406 177 % 0xb1 +0x407 178 % 0xb2 +0x408 179 % 0xb3 +0x409 180 % 0xb4 +0x40a 181 % 0xb5 +0x40b 182 % 0xb6 +0x40c 183 % 0xb7 +0x40e 184 % 0xb8 +0x40f 185 % 0xb9 +0x410 186 % 0xba +0x411 187 % 0xbb +0x412 188 % 0xbc +0x413 189 % 0xbd +0x414 190 % 0xbe +0x415 191 % 0xbf +0x416 192 % 0xc0 +0x417 193 % 0xc1 +0x418 194 % 0xc2 +0x419 195 % 0xc3 +0x41a 196 % 0xc4 +0x41b 197 % 0xc5 +0x41c 198 % 0xc6 +0x41d 199 % 0xc7 +0x41e 200 % 0xc8 +0x41f 201 % 0xc9 +0x420 202 % 0xca +0x421 203 % 0xcb +0x422 204 % 0xcc +0x423 205 % 0xcd +0x424 206 % 0xce +0x425 207 % 0xcf +0x426 208 % 0xd0 +0x427 209 % 0xd1 +0x428 210 % 0xd2 +0x429 211 % 0xd3 +0x42a 212 % 0xd4 +0x42b 213 % 0xd5 +0x42c 214 % 0xd6 +0x42d 215 % 0xd7 +0x42e 216 % 0xd8 +0x42f 217 % 0xd9 +0x430 218 % 0xda +0x431 219 % 0xdb +0x432 220 % 0xdc +0x433 221 % 0xdd +0x434 222 % 0xde +0x435 223 % 0xdf +0x436 224 % 0xe0 +0x437 225 % 0xe1 +0x438 226 % 0xe2 +0x439 227 % 0xe3 +0x43a 228 % 0xe4 +0x43b 229 % 0xe5 +0x43c 230 % 0xe6 +0x43d 231 % 0xe7 +0x43e 232 % 0xe8 +0x43f 233 % 0xe9 +0x440 234 % 0xea +0x441 235 % 0xeb +0x442 236 % 0xec +0x443 237 % 0xed +0x444 238 % 0xee +0x445 239 % 0xef +0x446 240 % 0xf0 +0x447 241 % 0xf1 +0x448 242 % 0xf2 +0x449 243 % 0xf3 +0x44a 244 % 0xf4 +0x44b 245 % 0xf5 +0x44c 246 % 0xf6 +0x44d 247 % 0xf7 +0x44e 248 % 0xf8 +0x44f 249 % 0xf9 +0x451 250 % 0xfa +0x452 251 % 0xfb +0x453 252 % 0xfc +0x454 253 % 0xfd +0x455 254 % 0xfe +0x456 255 % 0xff diff --git a/src/add-ons/print/drivers/pdf/encoding/ttenc2.cpg b/src/add-ons/print/drivers/pdf/encoding/ttenc2.cpg new file mode 100644 index 0000000000..ff4a6fb2f0 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/encoding/ttenc2.cpg @@ -0,0 +1,260 @@ +% Encoding definition for PDFlib +% ttenc2 +% WARNING: MACHINE GENERATED DON'T CHANGE! +% Format: unicode (hex) index (decimal) % index (hex) +0x457 0 % 0x00 +0x458 1 % 0x01 +0x459 2 % 0x02 +0x45a 3 % 0x03 +0x45b 4 % 0x04 +0x45c 5 % 0x05 +0x45e 6 % 0x06 +0x45f 7 % 0x07 +0x462 8 % 0x08 +0x463 9 % 0x09 +0x472 10 % 0x0a +0x473 11 % 0x0b +0x474 12 % 0x0c +0x475 13 % 0x0d +0x490 14 % 0x0e +0x491 15 % 0x0f +0x4d9 16 % 0x10 +0x5b0 17 % 0x11 +0x5b1 18 % 0x12 +0x5b2 19 % 0x13 +0x5b3 20 % 0x14 +0x5b4 21 % 0x15 +0x5b5 22 % 0x16 +0x5b6 23 % 0x17 +0x5b7 24 % 0x18 +0x5b8 25 % 0x19 +0x5b9 26 % 0x1a +0x5bb 27 % 0x1b +0x5bc 28 % 0x1c +0x5bd 29 % 0x1d +0x5be 30 % 0x1e +0x5bf 31 % 0x1f +0x5c0 32 % 0x20 +0x5c1 33 % 0x21 +0x5c2 34 % 0x22 +0x5c3 35 % 0x23 +0x5d0 36 % 0x24 +0x5d1 37 % 0x25 +0x5d2 38 % 0x26 +0x5d3 39 % 0x27 +0x5d4 40 % 0x28 +0x5d5 41 % 0x29 +0x5d6 42 % 0x2a +0x5d7 43 % 0x2b +0x5d8 44 % 0x2c +0x5d9 45 % 0x2d +0x5da 46 % 0x2e +0x5db 47 % 0x2f +0x5dc 48 % 0x30 +0x5dd 49 % 0x31 +0x5de 50 % 0x32 +0x5df 51 % 0x33 +0x5e0 52 % 0x34 +0x5e1 53 % 0x35 +0x5e2 54 % 0x36 +0x5e3 55 % 0x37 +0x5e4 56 % 0x38 +0x5e5 57 % 0x39 +0x5e6 58 % 0x3a +0x5e7 59 % 0x3b +0x5e8 60 % 0x3c +0x5e9 61 % 0x3d +0x5ea 62 % 0x3e +0x5f0 63 % 0x3f +0x5f1 64 % 0x40 +0x5f2 65 % 0x41 +0x60c 66 % 0x42 +0x61b 67 % 0x43 +0x61f 68 % 0x44 +0x621 69 % 0x45 +0x622 70 % 0x46 +0x623 71 % 0x47 +0x624 72 % 0x48 +0x625 73 % 0x49 +0x626 74 % 0x4a +0x627 75 % 0x4b +0x628 76 % 0x4c +0x629 77 % 0x4d +0x62a 78 % 0x4e +0x62b 79 % 0x4f +0x62c 80 % 0x50 +0x62d 81 % 0x51 +0x62e 82 % 0x52 +0x62f 83 % 0x53 +0x630 84 % 0x54 +0x631 85 % 0x55 +0x632 86 % 0x56 +0x633 87 % 0x57 +0x634 88 % 0x58 +0x635 89 % 0x59 +0x636 90 % 0x5a +0x637 91 % 0x5b +0x638 92 % 0x5c +0x639 93 % 0x5d +0x63a 94 % 0x5e +0x640 95 % 0x5f +0x641 96 % 0x60 +0x642 97 % 0x61 +0x643 98 % 0x62 +0x644 99 % 0x63 +0x645 100 % 0x64 +0x646 101 % 0x65 +0x647 102 % 0x66 +0x648 103 % 0x67 +0x649 104 % 0x68 +0x64a 105 % 0x69 +0x64b 106 % 0x6a +0x64c 107 % 0x6b +0x64d 108 % 0x6c +0x64e 109 % 0x6d +0x64f 110 % 0x6e +0x650 111 % 0x6f +0x651 112 % 0x70 +0x652 113 % 0x71 +0x660 114 % 0x72 +0x661 115 % 0x73 +0x662 116 % 0x74 +0x663 117 % 0x75 +0x664 118 % 0x76 +0x665 119 % 0x77 +0x666 120 % 0x78 +0x667 121 % 0x79 +0x668 122 % 0x7a +0x669 123 % 0x7b +0x66a 124 % 0x7c +0x66d 125 % 0x7d +0x679 126 % 0x7e +0x67e 127 % 0x7f +0x686 128 % 0x80 +0x688 129 % 0x81 +0x691 130 % 0x82 +0x698 131 % 0x83 +0x6a4 132 % 0x84 +0x6af 133 % 0x85 +0x6ba 134 % 0x86 +0x6d2 135 % 0x87 +0x6d5 136 % 0x88 +0x1e80 137 % 0x89 +0x1e81 138 % 0x8a +0x1e82 139 % 0x8b +0x1e83 140 % 0x8c +0x1e84 141 % 0x8d +0x1e85 142 % 0x8e +0x1ef2 143 % 0x8f +0x1ef3 144 % 0x90 +0x200c 145 % 0x91 +0x200d 146 % 0x92 +0x200e 147 % 0x93 +0x200f 148 % 0x94 +0x2012 149 % 0x95 +0x2013 150 % 0x96 +0x2014 151 % 0x97 +0x2015 152 % 0x98 +0x2017 153 % 0x99 +0x2018 154 % 0x9a +0x2019 155 % 0x9b +0x201a 156 % 0x9c +0x201b 157 % 0x9d +0x201c 158 % 0x9e +0x201d 159 % 0x9f +0x201e 160 % 0xa0 +0x2020 161 % 0xa1 +0x2021 162 % 0xa2 +0x2022 163 % 0xa3 +0x2024 164 % 0xa4 +0x2025 165 % 0xa5 +0x2026 166 % 0xa6 +0x202c 167 % 0xa7 +0x202d 168 % 0xa8 +0x202e 169 % 0xa9 +0x2030 170 % 0xaa +0x2032 171 % 0xab +0x2033 172 % 0xac +0x2039 173 % 0xad +0x203a 174 % 0xae +0x203c 175 % 0xaf +0x2044 176 % 0xb0 +0x2070 177 % 0xb1 +0x2074 178 % 0xb2 +0x2075 179 % 0xb3 +0x2076 180 % 0xb4 +0x2077 181 % 0xb5 +0x2078 182 % 0xb6 +0x2079 183 % 0xb7 +0x207d 184 % 0xb8 +0x207e 185 % 0xb9 +0x207f 186 % 0xba +0x2080 187 % 0xbb +0x2081 188 % 0xbc +0x2082 189 % 0xbd +0x2083 190 % 0xbe +0x2084 191 % 0xbf +0x2085 192 % 0xc0 +0x2086 193 % 0xc1 +0x2087 194 % 0xc2 +0x2088 195 % 0xc3 +0x2089 196 % 0xc4 +0x208d 197 % 0xc5 +0x208e 198 % 0xc6 +0x20a1 199 % 0xc7 +0x20a3 200 % 0xc8 +0x20a4 201 % 0xc9 +0x20a7 202 % 0xca +0x20aa 203 % 0xcb +0x20ab 204 % 0xcc +0x20ac 205 % 0xcd +0x2105 206 % 0xce +0x2111 207 % 0xcf +0x2113 208 % 0xd0 +0x2116 209 % 0xd1 +0x2118 210 % 0xd2 +0x211c 211 % 0xd3 +0x211e 212 % 0xd4 +0x2122 213 % 0xd5 +0x2126 214 % 0xd6 +0x212e 215 % 0xd7 +0x2135 216 % 0xd8 +0x2153 217 % 0xd9 +0x2154 218 % 0xda +0x215b 219 % 0xdb +0x215c 220 % 0xdc +0x215d 221 % 0xdd +0x215e 222 % 0xde +0x2190 223 % 0xdf +0x2191 224 % 0xe0 +0x2192 225 % 0xe1 +0x2193 226 % 0xe2 +0x2194 227 % 0xe3 +0x2195 228 % 0xe4 +0x21a8 229 % 0xe5 +0x21b5 230 % 0xe6 +0x21d0 231 % 0xe7 +0x21d1 232 % 0xe8 +0x21d2 233 % 0xe9 +0x21d3 234 % 0xea +0x21d4 235 % 0xeb +0x2200 236 % 0xec +0x2202 237 % 0xed +0x2203 238 % 0xee +0x2205 239 % 0xef +0x2206 240 % 0xf0 +0x2207 241 % 0xf1 +0x2208 242 % 0xf2 +0x2209 243 % 0xf3 +0x220b 244 % 0xf4 +0x220f 245 % 0xf5 +0x2211 246 % 0xf6 +0x2212 247 % 0xf7 +0x2215 248 % 0xf8 +0x2217 249 % 0xf9 +0x2219 250 % 0xfa +0x221a 251 % 0xfb +0x221d 252 % 0xfc +0x221e 253 % 0xfd +0x221f 254 % 0xfe +0x2220 255 % 0xff diff --git a/src/add-ons/print/drivers/pdf/encoding/ttenc3.cpg b/src/add-ons/print/drivers/pdf/encoding/ttenc3.cpg new file mode 100644 index 0000000000..7508da1ae9 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/encoding/ttenc3.cpg @@ -0,0 +1,260 @@ +% Encoding definition for PDFlib +% ttenc3 +% WARNING: MACHINE GENERATED DON'T CHANGE! +% Format: unicode (hex) index (decimal) % index (hex) +0x2227 0 % 0x00 +0x2228 1 % 0x01 +0x2229 2 % 0x02 +0x222a 3 % 0x03 +0x222b 4 % 0x04 +0x2234 5 % 0x05 +0x223c 6 % 0x06 +0x2245 7 % 0x07 +0x2248 8 % 0x08 +0x2260 9 % 0x09 +0x2261 10 % 0x0a +0x2264 11 % 0x0b +0x2265 12 % 0x0c +0x2282 13 % 0x0d +0x2283 14 % 0x0e +0x2284 15 % 0x0f +0x2286 16 % 0x10 +0x2287 17 % 0x11 +0x2295 18 % 0x12 +0x2297 19 % 0x13 +0x22a5 20 % 0x14 +0x22c5 21 % 0x15 +0x2302 22 % 0x16 +0x2310 23 % 0x17 +0x2320 24 % 0x18 +0x2321 25 % 0x19 +0x2329 26 % 0x1a +0x232a 27 % 0x1b +0x2500 28 % 0x1c +0x2502 29 % 0x1d +0x250c 30 % 0x1e +0x2510 31 % 0x1f +0x2514 32 % 0x20 +0x2518 33 % 0x21 +0x251c 34 % 0x22 +0x2524 35 % 0x23 +0x252c 36 % 0x24 +0x2534 37 % 0x25 +0x253c 38 % 0x26 +0x2550 39 % 0x27 +0x2551 40 % 0x28 +0x2552 41 % 0x29 +0x2553 42 % 0x2a +0x2554 43 % 0x2b +0x2555 44 % 0x2c +0x2556 45 % 0x2d +0x2557 46 % 0x2e +0x2558 47 % 0x2f +0x2559 48 % 0x30 +0x255a 49 % 0x31 +0x255b 50 % 0x32 +0x255c 51 % 0x33 +0x255d 52 % 0x34 +0x255e 53 % 0x35 +0x255f 54 % 0x36 +0x2560 55 % 0x37 +0x2561 56 % 0x38 +0x2562 57 % 0x39 +0x2563 58 % 0x3a +0x2564 59 % 0x3b +0x2565 60 % 0x3c +0x2566 61 % 0x3d +0x2567 62 % 0x3e +0x2568 63 % 0x3f +0x2569 64 % 0x40 +0x256a 65 % 0x41 +0x256b 66 % 0x42 +0x256c 67 % 0x43 +0x2580 68 % 0x44 +0x2584 69 % 0x45 +0x2588 70 % 0x46 +0x258c 71 % 0x47 +0x2590 72 % 0x48 +0x2591 73 % 0x49 +0x2592 74 % 0x4a +0x2593 75 % 0x4b +0x25a0 76 % 0x4c +0x25a1 77 % 0x4d +0x25aa 78 % 0x4e +0x25ab 79 % 0x4f +0x25ac 80 % 0x50 +0x25b2 81 % 0x51 +0x25ba 82 % 0x52 +0x25bc 83 % 0x53 +0x25c4 84 % 0x54 +0x25ca 85 % 0x55 +0x25cb 86 % 0x56 +0x25cf 87 % 0x57 +0x25d8 88 % 0x58 +0x25d9 89 % 0x59 +0x25e6 90 % 0x5a +0x263a 91 % 0x5b +0x263b 92 % 0x5c +0x263c 93 % 0x5d +0x2640 94 % 0x5e +0x2642 95 % 0x5f +0x2660 96 % 0x60 +0x2663 97 % 0x61 +0x2665 98 % 0x62 +0x2666 99 % 0x63 +0x266a 100 % 0x64 +0x266b 101 % 0x65 +0xf6be 102 % 0x66 +0xf6bf 103 % 0x67 +0xf6c0 104 % 0x68 +0xf6c1 105 % 0x69 +0xf6c2 106 % 0x6a +0xf6c3 107 % 0x6b +0xf6c4 108 % 0x6c +0xf6c5 109 % 0x6d +0xf6c6 110 % 0x6e +0xf6c7 111 % 0x6f +0xf6c8 112 % 0x70 +0xf6c9 113 % 0x71 +0xf6ca 114 % 0x72 +0xf6cb 115 % 0x73 +0xf6cc 116 % 0x74 +0xf6cd 117 % 0x75 +0xf6ce 118 % 0x76 +0xf6cf 119 % 0x77 +0xf6d0 120 % 0x78 +0xf6d1 121 % 0x79 +0xf6d2 122 % 0x7a +0xf6d3 123 % 0x7b +0xf6d4 124 % 0x7c +0xf6d5 125 % 0x7d +0xf6d6 126 % 0x7e +0xf6d7 127 % 0x7f +0xf6d8 128 % 0x80 +0xf6d9 129 % 0x81 +0xf6da 130 % 0x82 +0xf6db 131 % 0x83 +0xf6dc 132 % 0x84 +0xf6dd 133 % 0x85 +0xf6de 134 % 0x86 +0xf6df 135 % 0x87 +0xf6e0 136 % 0x88 +0xf6e1 137 % 0x89 +0xf6e2 138 % 0x8a +0xf6e3 139 % 0x8b +0xf6e4 140 % 0x8c +0xf6e5 141 % 0x8d +0xf6e6 142 % 0x8e +0xf6e7 143 % 0x8f +0xf6e8 144 % 0x90 +0xf6e9 145 % 0x91 +0xf6ea 146 % 0x92 +0xf6eb 147 % 0x93 +0xf6ec 148 % 0x94 +0xf6ed 149 % 0x95 +0xf6ee 150 % 0x96 +0xf6ef 151 % 0x97 +0xf6f0 152 % 0x98 +0xf6f1 153 % 0x99 +0xf6f2 154 % 0x9a +0xf6f3 155 % 0x9b +0xf6f4 156 % 0x9c +0xf6f5 157 % 0x9d +0xf6f6 158 % 0x9e +0xf6f7 159 % 0x9f +0xf6f8 160 % 0xa0 +0xf6f9 161 % 0xa1 +0xf6fa 162 % 0xa2 +0xf6fb 163 % 0xa3 +0xf6fc 164 % 0xa4 +0xf6fd 165 % 0xa5 +0xf6fe 166 % 0xa6 +0xf6ff 167 % 0xa7 +0xf721 168 % 0xa8 +0xf724 169 % 0xa9 +0xf726 170 % 0xaa +0xf730 171 % 0xab +0xf731 172 % 0xac +0xf732 173 % 0xad +0xf733 174 % 0xae +0xf734 175 % 0xaf +0xf735 176 % 0xb0 +0xf736 177 % 0xb1 +0xf737 178 % 0xb2 +0xf738 179 % 0xb3 +0xf739 180 % 0xb4 +0xf73f 181 % 0xb5 +0xf760 182 % 0xb6 +0xf761 183 % 0xb7 +0xf762 184 % 0xb8 +0xf763 185 % 0xb9 +0xf764 186 % 0xba +0xf765 187 % 0xbb +0xf766 188 % 0xbc +0xf767 189 % 0xbd +0xf768 190 % 0xbe +0xf769 191 % 0xbf +0xf76a 192 % 0xc0 +0xf76b 193 % 0xc1 +0xf76c 194 % 0xc2 +0xf76d 195 % 0xc3 +0xf76e 196 % 0xc4 +0xf76f 197 % 0xc5 +0xf770 198 % 0xc6 +0xf771 199 % 0xc7 +0xf772 200 % 0xc8 +0xf773 201 % 0xc9 +0xf774 202 % 0xca +0xf775 203 % 0xcb +0xf776 204 % 0xcc +0xf777 205 % 0xcd +0xf778 206 % 0xce +0xf779 207 % 0xcf +0xf77a 208 % 0xd0 +0xf7a1 209 % 0xd1 +0xf7a2 210 % 0xd2 +0xf7a8 211 % 0xd3 +0xf7af 212 % 0xd4 +0xf7b4 213 % 0xd5 +0xf7b8 214 % 0xd6 +0xf7bf 215 % 0xd7 +0xf7e0 216 % 0xd8 +0xf7e1 217 % 0xd9 +0xf7e2 218 % 0xda +0xf7e3 219 % 0xdb +0xf7e4 220 % 0xdc +0xf7e5 221 % 0xdd +0xf7e6 222 % 0xde +0xf7e7 223 % 0xdf +0xf7e8 224 % 0xe0 +0xf7e9 225 % 0xe1 +0xf7ea 226 % 0xe2 +0xf7eb 227 % 0xe3 +0xf7ec 228 % 0xe4 +0xf7ed 229 % 0xe5 +0xf7ee 230 % 0xe6 +0xf7ef 231 % 0xe7 +0xf7f0 232 % 0xe8 +0xf7f1 233 % 0xe9 +0xf7f2 234 % 0xea +0xf7f3 235 % 0xeb +0xf7f4 236 % 0xec +0xf7f5 237 % 0xed +0xf7f6 238 % 0xee +0xf7f8 239 % 0xef +0xf7f9 240 % 0xf0 +0xf7fa 241 % 0xf1 +0xf7fb 242 % 0xf2 +0xf7fc 243 % 0xf3 +0xf7fd 244 % 0xf4 +0xf7fe 245 % 0xf5 +0xf7ff 246 % 0xf6 +0xf8e5 247 % 0xf7 +0xf8e6 248 % 0xf8 +0xf8e7 249 % 0xf9 +0xf8e8 250 % 0xfa +0xf8e9 251 % 0xfb +0xf8ea 252 % 0xfc +0xf8eb 253 % 0xfd +0xf8ec 254 % 0xfe +0xf8ed 255 % 0xff diff --git a/src/add-ons/print/drivers/pdf/encoding/ttenc4.cpg b/src/add-ons/print/drivers/pdf/encoding/ttenc4.cpg new file mode 100644 index 0000000000..c96d20774a --- /dev/null +++ b/src/add-ons/print/drivers/pdf/encoding/ttenc4.cpg @@ -0,0 +1,31 @@ +% Encoding definition for PDFlib +% ttenc4 +% WARNING: MACHINE GENERATED DON'T CHANGE! +% Format: unicode (hex) index (decimal) % index (hex) +0xf8ee 0 % 0x00 +0xf8ef 1 % 0x01 +0xf8f0 2 % 0x02 +0xf8f1 3 % 0x03 +0xf8f2 4 % 0x04 +0xf8f3 5 % 0x05 +0xf8f4 6 % 0x06 +0xf8f5 7 % 0x07 +0xf8f6 8 % 0x08 +0xf8f7 9 % 0x09 +0xf8f8 10 % 0x0a +0xf8f9 11 % 0x0b +0xf8fa 12 % 0x0c +0xf8fb 13 % 0x0d +0xf8fc 14 % 0x0e +0xf8fd 15 % 0x0f +0xf8fe 16 % 0x10 +0xfb00 17 % 0x11 +0xfb01 18 % 0x12 +0xfb02 19 % 0x13 +0xfb03 20 % 0x14 +0xfb04 21 % 0x15 +0xfb1f 22 % 0x16 +0xfb2a 23 % 0x17 +0xfb2b 24 % 0x18 +0xfb35 25 % 0x19 +0xfb4b 26 % 0x1a diff --git a/src/add-ons/print/drivers/pdf/source/AdvancedSettingsWindow.cpp b/src/add-ons/print/drivers/pdf/source/AdvancedSettingsWindow.cpp new file mode 100644 index 0000000000..1e2a73d736 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/AdvancedSettingsWindow.cpp @@ -0,0 +1,275 @@ +/* + +AdvancedSettingsWindow.cpp + +Copyright (c) 2002 OpenBeOS. + +Author: + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#include +#include +#include +#include "AdvancedSettingsWindow.h" + +static BMessage* BorderWidthMessage(uint32 what, float width) +{ + BMessage* m = new BMessage(what); + m->AddFloat("width", width); + return m; +} + +// -------------------------------------------------- +AdvancedSettingsWindow::AdvancedSettingsWindow(BMessage *settings) + : HWindow(BRect(0,0,400,220), "Advanced Settings", B_TITLED_WINDOW_LOOK, + B_MODAL_APP_WINDOW_FEEL, B_NOT_RESIZABLE | B_NOT_MINIMIZABLE | + B_NOT_ZOOMABLE) +{ + // ---- Ok, build a default page setup user interface + BRect r; + BBox *panel; + BButton *button; + BCheckBox *cb; + BMenuField *mf; + float x, y, w, h; + fSettings = settings; + + // add a *dialog* background + r = Bounds(); + panel = new BBox(r, "top_panel", B_FOLLOW_ALL, + B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP, + B_PLAIN_BORDER); + + x = 5; y = 5; w = r.Width(); h = r.Height(); + + // web links + cb = new BCheckBox(BRect(x, y, x+w-10, y+14), "create_links", "Create links for URLs", new BMessage(CREATE_LINKS_MSG)); + panel->AddChild(cb); + if (settings->FindBool("create_web_links", &fCreateLinks) != B_OK) fCreateLinks = false; + cb->SetValue(fCreateLinks ? B_CONTROL_ON : B_CONTROL_OFF); + y += cb->Bounds().Height() + 5; + + BMenuItem* item; + if (settings->FindFloat("link_border_width", &fLinkBorderWidth)) fLinkBorderWidth = 1; + BPopUpMenu* m = new BPopUpMenu("link_border_width"); + m->SetRadioMode(true); + m->AddItem(item = new BMenuItem("no border", BorderWidthMessage(LINK_BORDER_MSG, 0.0))); + if (fLinkBorderWidth == 0) item->SetMarked(true); + m->AddItem(item = new BMenuItem("normal", BorderWidthMessage(LINK_BORDER_MSG, 1.0))); + if (fLinkBorderWidth == 1) item->SetMarked(true); + m->AddItem(item = new BMenuItem("bold", BorderWidthMessage(LINK_BORDER_MSG, 2.0))); + if (fLinkBorderWidth == 2) item->SetMarked(true); + + mf = new BMenuField(BRect(x, y, x+w-10, y+14), "link_border_width_menu", "Link Border Width:", m); + mf->ResizeToPreferred(); + panel->AddChild(mf); + y += mf->Bounds().Height() + 15; + + // bookmarks + if (settings->FindBool("create_bookmarks", &fCreateBookmarks) != B_OK) fCreateBookmarks = false; + cb = new BCheckBox(BRect(x, y, x+w-10, y+14), "create_bookmarks", "Create bookmarks", new BMessage(CREATE_BOOKMARKS_MSG)); + cb->SetValue(fCreateBookmarks ? B_CONTROL_ON : B_CONTROL_OFF); + panel->AddChild(cb); + y += cb->Bounds().Height() + 5; + + m = new BPopUpMenu("definition"); + m->SetRadioMode(true); + mf = new BMenuField(BRect(x, y, x+w-10, y+14), "definition_menu", "Bookmark Definition File:", m); + panel->AddChild(mf); + y += mf->Bounds().Height() + 15; + + if (settings->FindString("bookmark_definition_file", &fBookmarkDefinition) != B_OK) fBookmarkDefinition = ""; + + BDirectory Folder; + BEntry entry; + + // XXX: B_USER_SETTINGS_DIRECTORY + Folder.SetTo ("/boot/home/config/settings/PDF Writer/bookmarks/"); + if (Folder.InitCheck() == B_OK) { + while (Folder.GetNextEntry(&entry) != B_ENTRY_NOT_FOUND) { + char name[B_FILE_NAME_LENGTH]; + if (entry.GetName(name) == B_NO_ERROR) + m->AddItem (item = new BMenuItem(name, new BMessage(DEFINITION_MSG))); + if (strcmp(name, fBookmarkDefinition.String()) == 0) item->SetMarked(true); + } + } + + // cross references + if (settings->FindBool("create_xrefs", &fCreateXRefs) != B_OK) fCreateXRefs = false; + + cb = new BCheckBox(BRect(x, y, x+w-10, y+14), "create_xrefs", "Create cross references", new BMessage(CREATE_XREFS_MSG)); + cb->SetValue(fCreateXRefs ? B_CONTROL_ON : B_CONTROL_OFF); + panel->AddChild(cb); + y += cb->Bounds().Height() + 5; + + m = new BPopUpMenu("cross references"); + m->SetRadioMode(true); + mf = new BMenuField(BRect(x, y, x+w-10, y+14), "xrefs_menu", "Cross References File:", m); + panel->AddChild(mf); + + if (settings->FindString("xrefs_file", &fXRefs) != B_OK) fXRefs = ""; + + // XXX: B_USER_SETTINGS_DIRECTORY + Folder.SetTo ("/boot/home/config/settings/PDF Writer/xrefs/"); + if (Folder.InitCheck() == B_OK) { + while (Folder.GetNextEntry(&entry) != B_ENTRY_NOT_FOUND) { + char name[B_FILE_NAME_LENGTH]; + if (entry.GetName(name) == B_NO_ERROR) + m->AddItem (item = new BMenuItem(name, new BMessage(XREFS_MSG))); + if (strcmp(name, fXRefs.String()) == 0) item->SetMarked(true); + } + } + + // add a "OK" button, and make it default + button = new BButton(r, NULL, "OK", new BMessage(OK_MSG), + B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + button->ResizeToPreferred(); + button->GetPreferredSize(&w, &h); + x = r.right - w - 8; + y = r.bottom - h - 8; + button->MoveTo(x, y); + panel->AddChild(button); + + // add a "Cancel button + button = new BButton(r, NULL, "Cancel", new BMessage(CANCEL_MSG), + B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + button->GetPreferredSize(&w, &h); + button->ResizeToPreferred(); + button->MoveTo(x - w - 8, y); + panel->AddChild(button); + + // add a separator line... + BBox * line = new BBox(BRect(r.left, y - 9, r.right, y - 8), NULL, + B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM ); + panel->AddChild(line); + + // Finally, add our panel to window + AddChild(panel); + + MoveTo(320, 320); +} + +void +AdvancedSettingsWindow::UpdateSettings() +{ + if (fSettings->HasBool("create_web_links")) { + fSettings->ReplaceBool("create_web_links", fCreateLinks); + } else { + fSettings->AddBool("create_web_links", fCreateLinks); + } + + if (fSettings->HasFloat("link_border_width")) { + fSettings->ReplaceFloat("link_border_width", fLinkBorderWidth); + } else { + fSettings->AddFloat("link_border_width", fLinkBorderWidth); + } + + if (fSettings->HasBool("create_bookmarks")) { + fSettings->ReplaceBool("create_bookmarks", fCreateBookmarks); + } else { + fSettings->AddBool("create_bookmarks", fCreateBookmarks); + } + + if (fSettings->HasString("bookmark_definition_file")) { + fSettings->ReplaceString("bookmark_definition_file", fBookmarkDefinition.String()); + } else { + fSettings->AddString("bookmark_definition_file", fBookmarkDefinition.String()); + } + + if (fSettings->HasBool("create_xrefs")) { + fSettings->ReplaceBool("create_xrefs", fCreateXRefs); + } else { + fSettings->AddBool("create_xrefs", fCreateXRefs); + } + + if (fSettings->HasString("xrefs_file")) { + fSettings->ReplaceString("xrefs_file", fXRefs.String()); + } else { + fSettings->AddString("xrefs_file", fXRefs.String()); + } +} + + +// -------------------------------------------------- +void +AdvancedSettingsWindow::MessageReceived(BMessage *msg) +{ + float w; + void *source; + + if (msg->FindPointer("source", &source) != B_OK) source = NULL; + + switch (msg->what){ + case OK_MSG: UpdateSettings(); Quit(); + break; + + case CANCEL_MSG: Quit(); + break; + + case CREATE_LINKS_MSG: + if (source) { + BCheckBox* cb = (BCheckBox*)source; + fCreateLinks = cb->Value() == B_CONTROL_ON; + } + break; + + case LINK_BORDER_MSG: + if (msg->FindFloat("width", &w) == B_OK) { + fLinkBorderWidth = w; + } + break; + + case CREATE_BOOKMARKS_MSG: + if (source) { + BCheckBox* cb = (BCheckBox*)source; + fCreateBookmarks = cb->Value() == B_CONTROL_ON; + } + break; + + case DEFINITION_MSG: + if (source) { + BMenuItem* item = (BMenuItem*)source; + fBookmarkDefinition = item->Label(); + } + break; + + case CREATE_XREFS_MSG: + if (source) { + BCheckBox* cb = (BCheckBox*)source; + fCreateXRefs = cb->Value() == B_CONTROL_ON; + } + break; + + case XREFS_MSG: + if (source) { + BMenuItem* item = (BMenuItem*)source; + fXRefs = item->Label(); + } + break; + + default: + inherited::MessageReceived(msg); + break; + } +} + diff --git a/src/add-ons/print/drivers/pdf/source/AdvancedSettingsWindow.h b/src/add-ons/print/drivers/pdf/source/AdvancedSettingsWindow.h new file mode 100644 index 0000000000..7bef94e350 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/AdvancedSettingsWindow.h @@ -0,0 +1,82 @@ +/* + +PDF Writer printer driver. + +Copyright (c) 2002 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef ADVANCED_SETTINGS_WINDOW_H +#define ADVANCED_SETTINGS_WINDOW_H + +#include +#include +#include +#include +#include +#include +#include +#include "Utils.h" + +class AdvancedSettingsWindow : public HWindow +{ +public: + // Constructors, destructors, operators... + + AdvancedSettingsWindow(BMessage *doc_info); + + typedef HWindow inherited; + + // public constantes + enum { + OK_MSG = 'ok__', + CANCEL_MSG = 'cncl', + CREATE_LINKS_MSG = 'clnk', + LINK_BORDER_MSG = 'lnkb', + CREATE_BOOKMARKS_MSG = 'cbmk', + DEFINITION_MSG = 'defi', + CREATE_XREFS_MSG = 'cxrf', + XREFS_MSG = 'xref', + }; + + // Virtual function overrides +public: + virtual void MessageReceived(BMessage *msg); + +private: + BMessage* fSettings; + + bool fCreateLinks; + float fLinkBorderWidth; + bool fCreateBookmarks; + BString fBookmarkDefinition; + bool fCreateXRefs; + BString fXRefs; + + void UpdateSettings(); +}; + +#endif diff --git a/src/add-ons/print/drivers/pdf/source/Bezier.cpp b/src/add-ons/print/drivers/pdf/source/Bezier.cpp new file mode 100644 index 0000000000..44224af2ef --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/Bezier.cpp @@ -0,0 +1,85 @@ +/* + +PDF Writer printer driver. + +Copyright (c) 2002 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#include +#include "Bezier.h" + +/* + Bezier curve of degree n with control points P[0] ... P[n]: + P(t) = sum i from 0 to n of B(i, n, t) * P[i] + Bernsteinpolynomial: + B(i, n, t) = n! / (i! * (n-i)!) * t^i * (1-t)^(n-i) +*/ + +Bezier::Bezier(BPoint *points, int noOfPoints) +{ + int i; + fPoints = new BPoint[noOfPoints]; + fBernsteinWeights = new double[noOfPoints]; + fNoOfPoints = noOfPoints; + const int n = noOfPoints - 1; + for (i = 0; i < noOfPoints; i++) { + fPoints[i] = points[i]; + fBernsteinWeights[i] = Fact(n) / (Fact(i) * Fact(n-i)); + } +} + + +Bezier::~Bezier() +{ + delete []fPoints; + delete []fBernsteinWeights; +} + + +double +Bezier::Fact(int n) +{ + double f = 1; + for (; n > 0; n --) f *= n; + return f; +} + + +BPoint +Bezier::PointAt(float t) +{ + const int n = fNoOfPoints - 1; + double x, y; + x = y = 0.0; + for (int i = 0; i < fNoOfPoints; i ++) { + double w = fBernsteinWeights[i] * pow(t, i) * pow(1 - t, n - i); + x += w * fPoints[i].x; + y += w * fPoints[i].y; + } + return BPoint(x, y); +} + diff --git a/src/add-ons/print/drivers/pdf/source/Bezier.h b/src/add-ons/print/drivers/pdf/source/Bezier.h new file mode 100644 index 0000000000..6e13093812 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/Bezier.h @@ -0,0 +1,49 @@ +/* + +Bezier curve + +Copyright (c) 2002 OpenBeOS. + +Author: + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef BEZIER_H +#define BEZIER_H + +#include + +class Bezier +{ + BPoint *fPoints; + int fNoOfPoints; + double *fBernsteinWeights; + + double Fact(int n); + +public: + Bezier(BPoint *points, int n); + ~Bezier(); + BPoint PointAt(float t); +}; + +#endif diff --git a/src/add-ons/print/drivers/pdf/source/Bookmark.cpp b/src/add-ons/print/drivers/pdf/source/Bookmark.cpp new file mode 100644 index 0000000000..95464ad9c7 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/Bookmark.cpp @@ -0,0 +1,190 @@ +#include +#include "PDFWriter.h" +#include "Bookmark.h" +#include "Scanner.h" +#include "Report.h" + + +Bookmark::Definition::Definition(int level, BFont* font) + : fLevel(level) + , fFont(*font) +{ +} + + +bool Bookmark::Definition::Matches(font_family* family, font_style* style, float size) const +{ + font_family family0; + font_style style0; + + if (fFont.Size() != size) return false; + + fFont.GetFamilyAndStyle(&family0, &style0); + + return strcmp(family0, *family) == 0 && + strcmp(style0, *style) == 0; +} + + +Bookmark::Bookmark(PDFWriter* writer) + : fWriter(writer) +{ + for (int i = 0; i < kMaxBookmarkLevels; i ++) { + fLevels[i] = 0; + } +} + + +bool Bookmark::Find(BFont* font, int& level) const +{ + font_family family; + font_style style; + float size; + + font->GetFamilyAndStyle(&family, &style); + size = font->Size(); + + for (int i = 0; i < fDefinitions.CountItems(); i++) { + Definition* d = fDefinitions.ItemAt(i); + if (d->Matches(&family, &style, size)) { + level = d->fLevel; + return true; + } + } + return false; +} + + +void Bookmark::AddDefinition(int level, BFont* font) +{ + ASSERT(1 <= level && level <= kMaxBookmarkLevels); + if (!Find(font, level)) { + fDefinitions.AddItem(new Definition(level, font)); + } +} + + +void Bookmark::AddBookmark(BPoint start, const char* text, BFont* font) +{ + int level; + if (Find(font, level)) { + fOutlines.AddItem(new Outline(start, text, level)); + } +} + + +int Bookmark::AscendingByStart(const Outline** a, const Outline** b) { + return (int)((*b)->Start().y - (*a)->Start().y); +} + + +void Bookmark::CreateBookmarks() { + fOutlines.SortItems(AscendingByStart); + + for (int i = 0; i < fOutlines.CountItems(); i++) { + BString ucs2; + + Outline* o = fOutlines.ItemAt(i); + REPORT(kInfo, fWriter->fPage, "Bookmark '%s' at level %d", o->Text(), o->Level()); + + fWriter->ToPDFUnicode(o->Text(), ucs2); + + int bookmark = PDF_add_bookmark(fWriter->fPdf, ucs2.String(), fLevels[o->Level()-1], 1); + + if (bookmark < 0) bookmark = 0; + + for (int i = o->Level(); i < kMaxBookmarkLevels; i ++) { + fLevels[i] = bookmark; + } + } + + fOutlines.MakeEmpty(); +} + +// Reads bookmark definitions from file + +/* +File Format: Definition. +Line comment starts with '#'. + +Definition = Version { Font }. +Version = "Bookmarks" "1.0". +Font = Level Family Style Size. +Level = int. +Family = String. +Style = String. +Size = float. +String = '"' string '"'. +*/ + +bool Bookmark::Exists(const char* f, const char* s) const { + font_family family; + font_style style; + uint32 flags; + int32 nFamilies; + int32 nStyles; + + nFamilies = count_font_families(); + + for (int32 i = 0; i < nFamilies; i ++) { + if (get_font_family(i, &family, &flags) == B_OK && strcmp(f, family) == 0) { + nStyles = count_font_styles(family); + for (int32 j = 0; j < nStyles; j++) { + if (get_font_style(family, j, &style, &flags) == B_OK && strcmp(s, style) == 0) { + return true; + } + } + } + } + return false; +} + + +bool Bookmark::Read(const char* name) { + Scanner scnr(name); + if (scnr.InitCheck() == B_OK) { + BString s; float f; bool ok; + ok = scnr.ReadName(&s) && scnr.ReadFloat(&f); + if (!ok || strcmp(s.String(), "Bookmarks") != 0 || f != 1.0) { + REPORT(kError, 0, "Bookmarks (line %d, column %d): '%s' not a bookmarks file or wrong version!", scnr.Line(), scnr.Column(), name); + return false; + } + + while (!scnr.IsEOF()) { + float level, size; + BString family, style; + if (!(scnr.ReadFloat(&level) && level >= 1.0 && level <= 10.0)) { + REPORT(kError, 0, "Bookmarks (line %d, column %d): Invalid level", scnr.Line(), scnr.Column()); + return false; + } + if (!scnr.ReadString(&family)) { + REPORT(kError, 0, "Bookmarks (line %d, column %d): Invalid font family", scnr.Line(), scnr.Column()); + return false; + } + if (!scnr.ReadString(&style)) { + REPORT(kError, 0, "Bookmarks (line %d, column %d): Invalid font style", scnr.Line(), scnr.Column()); + return false; + } + if (!scnr.ReadFloat(&size)) { + REPORT(kError, 0, "Bookmarks (line %d, column %d): Invalid font size", scnr.Line(), scnr.Column()); + return false; + } + + if (Exists(family.String(), style.String())) { + BFont font; + font.SetFamilyAndStyle(family.String(), style.String()); + font.SetSize(size); + + AddDefinition((int)level, &font); + } else { + REPORT(kWarning, 0, "Bookmarks (line %d, column %d): Font %s-%s not available!", scnr.Line(), scnr.Column(), family.String(), style.String()); + } + + scnr.SkipSpaces(); + } + return true; + } else { + REPORT(kError, 0, "Bookmarks: Could not open bookmarks file '%d'", name); + } + return false; +} diff --git a/src/add-ons/print/drivers/pdf/source/Bookmark.h b/src/add-ons/print/drivers/pdf/source/Bookmark.h new file mode 100644 index 0000000000..88cc822869 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/Bookmark.h @@ -0,0 +1,55 @@ +#ifndef _BOOKMARK_H +#define _BOOKMARK_H + +#include +#include +#include + +class PDFWriter; + +const int kMaxBookmarkLevels = 10; + +class Bookmark { + class Definition { + public: + int fLevel; + BFont fFont; + Definition(int level, BFont* font); + bool Matches(font_family* family, font_style* style, float size) const; + }; + + class Outline { + public: + BPoint fStart; + BString fText; + int fLevel; + + Outline(BPoint start, const char* text, int level) : fStart(start), fText(text), fLevel(level) { } + int Level() const { return fLevel; } + const char* Text() const { return fText.String(); } + BPoint Start() const { return fStart; } + }; + + PDFWriter* fWriter; + TList fDefinitions; + TList fOutlines; // of the current page + + int fLevels[kMaxBookmarkLevels+1]; + + bool Exists(const char* family, const char* style) const; + bool Find(BFont* font, int &level) const; + + static int AscendingByStart(const Outline** a, const Outline** b); + +public: + + Bookmark(PDFWriter* writer); + + // level starts with 1 + void AddDefinition(int level, BFont* font); + void AddBookmark(BPoint start, const char* text, BFont* font); + bool Read(const char* name); // adds definitions from file + void CreateBookmarks(); +}; + +#endif diff --git a/src/add-ons/print/drivers/pdf/source/Defs4PPC.pch++ b/src/add-ons/print/drivers/pdf/source/Defs4PPC.pch++ new file mode 100644 index 0000000000..176a24bf5b --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/Defs4PPC.pch++ @@ -0,0 +1,7 @@ +#include +#include +#include +#include + +#define PATTERN_SUPPORT 1 +#define LOGGING 0 \ No newline at end of file diff --git a/src/add-ons/print/drivers/pdf/source/DocInfoWindow.cpp b/src/add-ons/print/drivers/pdf/source/DocInfoWindow.cpp new file mode 100644 index 0000000000..658e97676c --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/DocInfoWindow.cpp @@ -0,0 +1,521 @@ +/* + +DocInfoWindow.cpp + +Copyright (c) 2002 OpenBeOS. + +Author: + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#include +#include +#include "DocInfoWindow.h" +#include + + +// -------------------------------------------------- +class TextView : public BTextView +{ +public: + typedef BTextView inherited; + + TextView(BRect frame, + const char *name, + BRect textRect, + uint32 rmask = B_FOLLOW_LEFT | B_FOLLOW_TOP, + uint32 flags = B_WILL_DRAW | B_NAVIGABLE); + + TextView(BRect frame, + const char *name, + BRect textRect, + const BFont *font, const rgb_color *color, + uint32 rmask = B_FOLLOW_LEFT | B_FOLLOW_TOP, + uint32 flags = B_WILL_DRAW | B_NAVIGABLE); + + void KeyDown(const char *bytes, int32 numBytes); + void MakeFocus(bool focus = true); + void Draw(BRect r); +}; + + +// -------------------------------------------------- +class TextControl : public BView +{ + BStringView *fLabel; + TextView *fText; +public: + TextControl(BRect frame, + const char *name, + const char *label, + const char *initial_text, + BMessage *message, + uint32 rmask = B_FOLLOW_LEFT | B_FOLLOW_TOP, + uint32 flags = B_WILL_DRAW | B_NAVIGABLE); + const char *Label() { return fLabel->Text(); } + const char *Text() { return fText->Text(); } + void MakeFocus(bool focus = true) { fText->MakeFocus(focus); } + void ConvertToParent(BView* parent, BView* child, BRect &rect); + void FocusSetTo(BView* child); +}; + + +// -------------------------------------------------- +class Table : public BView +{ +public: + typedef BView inherited; + + Table(BRect frame, const char *name, uint32 rmode, uint32 flags); + void ScrollTo(BPoint p); +}; + + +// -------------------------------------------------- +TextView::TextView(BRect frame, + const char *name, + BRect textRect, + uint32 rmask, + uint32 flags) + : BTextView(frame, name, textRect, rmask, flags) +{ +} + + +// -------------------------------------------------- +TextView::TextView(BRect frame, + const char *name, + BRect textRect, + const BFont *font, const rgb_color *color, + uint32 rmask, + uint32 flags) + : BTextView(frame, name, textRect, font, color, rmask, flags) +{ +} + + +// -------------------------------------------------- +void +TextView::KeyDown(const char *bytes, int32 numBytes) +{ + if (numBytes == 1 && *bytes == B_TAB) { + BView::KeyDown(bytes, numBytes); + return; + } + inherited::KeyDown(bytes, numBytes); +} + + +// -------------------------------------------------- +void +TextView::Draw(BRect update) +{ + inherited::Draw(update); + if (IsFocus()) { + // stroke focus rectangle + SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR)); + StrokeRect(Bounds()); + } +} + + +// -------------------------------------------------- +void +TextView::MakeFocus(bool focus) +{ + Invalidate(); + inherited::MakeFocus(focus); + // notify TextControl + BView* parent = Parent(); // BBox + if (focus && parent) { + parent = parent->Parent(); // TextControl + TextControl* control = dynamic_cast(parent); + if (control) control->FocusSetTo(this); + } +} + + +// -------------------------------------------------- +TextControl::TextControl(BRect frame, + const char *name, + const char *label, + const char *initial_text, + BMessage *message, + uint32 rmask, + uint32 flags) + : BView(frame, name, rmask, flags) +{ + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + BRect r(0, 0, frame.Width() / 2 -1, frame.Height()); + fLabel = new BStringView(r, "", label); + BRect f(r); + f.OffsetTo(frame.Width() / 2 + 1, 0); + // box around TextView + BBox *box = new BBox(f, "", B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW); + f.OffsetTo(0, 0); + f.InsetBy(1,1); + r.InsetBy(2,2); + fText = new TextView(f, "", r, rmask, flags | B_NAVIGABLE); + fText->SetWordWrap(false); + fText->DisallowChar('\n'); + fText->Insert(initial_text); + AddChild(fLabel); + AddChild(box); + box->AddChild(fText); +} + + +// -------------------------------------------------- +void +TextControl::ConvertToParent(BView* parent, BView* child, BRect &rect) +{ + do { + child->ConvertToParent(&rect); + child = child->Parent(); + } while (child != NULL && child != parent); +} + + +// -------------------------------------------------- +void +TextControl::FocusSetTo(BView *child) +{ + BRect r; + BView* parent = Parent(); // Table + if (parent) { + ConvertToParent(parent, child, r); + parent->ScrollTo(0, r.top); + } +} + + +// -------------------------------------------------- +Table::Table(BRect frame, const char *name, uint32 rmode, uint32 flags) + : BView(frame, name, rmode, flags) +{ +} + + +// -------------------------------------------------- +void +Table::ScrollTo(BPoint p) +{ + float h = Frame().Height()+1; + if (Parent()) { + BScrollView* scrollView = dynamic_cast(Parent()); + if (scrollView) { + BScrollBar *sb = scrollView->ScrollBar(B_VERTICAL); + float min, max; + sb->GetRange(&min, &max); + if (p.y < (h/2)) p.y = 0; + else if (p.y > max) p.y = max; + } + } + inherited::ScrollTo(p); +} + + +// -------------------------------------------------- +DocInfoWindow::DocInfoWindow(BMessage *doc_info) + : HWindow(BRect(0,0,400,220), "Document Information", B_TITLED_WINDOW_LOOK, + B_MODAL_APP_WINDOW_FEEL, B_NOT_RESIZABLE | B_NOT_MINIMIZABLE | + B_NOT_ZOOMABLE) +{ + // ---- Ok, build a default page setup user interface + BRect r; + BBox *panel; + BButton *button; + float x, y, w, h; + BString setting_value; + + fDocInfo = doc_info; + + // add a *dialog* background + r = Bounds(); + panel = new BBox(r, "top_panel", B_FOLLOW_ALL, + B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP, + B_PLAIN_BORDER); + + // add list of keys + fKeyList = new BMenu("Delete Key"); + BMenuField *menu = new BMenuField(BRect(0, 0, 90, 10), "delete", "", fKeyList); + menu->SetDivider(0); + panel->AddChild(menu); + + // add table for text controls (document info key and value) + fTable = new Table(BRect(r.left+5, r.top+5, r.right-5-B_V_SCROLL_BAR_WIDTH, r.bottom-5-B_H_SCROLL_BAR_HEIGHT-30-20), "table", B_FOLLOW_ALL, B_WILL_DRAW); + fTable->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + + // add table to ScrollView + fTableScrollView = new BScrollView("scroll_table", fTable, B_FOLLOW_LEFT | B_FOLLOW_TOP, 0, false, true); + panel->AddChild(fTableScrollView); + + // position list of keys + menu->MoveTo(5, fTableScrollView->Frame().bottom+2); + + BMenu* defaultKeys = new BMenu("Default Keys"); + defaultKeys->AddItem(new BMenuItem("Author", new BMessage(DEFAULT_KEY_MSG))); + defaultKeys->AddItem(new BMenuItem("Subject", new BMessage(DEFAULT_KEY_MSG))); + defaultKeys->AddItem(new BMenuItem("Keywords", new BMessage(DEFAULT_KEY_MSG))); + defaultKeys->AddItem(new BMenuItem("Creator", new BMessage(DEFAULT_KEY_MSG))); + // PDFlib sets these itselves: + // defaultKeys->AddItem(new BMenuItem("Producer", new BMessage(DEFAULT_KEY_MSG))); + // defaultKeys->AddItem(new BMenuItem("CreationDate", new BMessage(DEFAULT_KEY_MSG))); + // Not meaningful to set the modification date at creation time! + // defaultKeys->AddItem(new BMenuItem("ModDate", new BMessage(DEFAULT_KEY_MSG))); + BMenuField *keys = new BMenuField(BRect(0, 0, 90, 10), "add", "", defaultKeys); + keys->SetDivider(0); + panel->AddChild(keys); + keys->MoveTo(menu->Frame().right + 5, menu->Frame().top); + + // add add key text control + BTextControl *add = new BTextControl(BRect(0, 0, 180, 20), "add", "Add Key:", "", new BMessage(ADD_KEY_MSG)); + add->SetDivider(60); + panel->AddChild(add); + add->MoveTo(keys->Frame().right + 5, keys->Frame().top); + + // fill table + BuildTable(fDocInfo); + + // add a "OK" button, and make it default + button = new BButton(r, NULL, "OK", new BMessage(OK_MSG), + B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + button->ResizeToPreferred(); + button->GetPreferredSize(&w, &h); + x = r.right - w - 8; + y = r.bottom - h - 8; + button->MoveTo(x, y); + panel->AddChild(button); + + // add a "Cancel button + button = new BButton(r, NULL, "Cancel", new BMessage(CANCEL_MSG), + B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + button->GetPreferredSize(&w, &h); + button->ResizeToPreferred(); + button->MoveTo(x - w - 8, y); + panel->AddChild(button); + + // add a separator line... + BBox * line = new BBox(BRect(r.left, y - 9, r.right, y - 8), NULL, + B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM ); + panel->AddChild(line); + + // Finally, add our panel to window + AddChild(panel); + + MoveTo(320, 320); + + if (fTable->ChildAt(0)) fTable->ChildAt(0)->MakeFocus(); +} + + +// -------------------------------------------------- +bool +DocInfoWindow::QuitRequested() +{ + return true; +} + + +// -------------------------------------------------- +void +DocInfoWindow::Quit() +{ + EmptyKeyList(); + inherited::Quit(); +} + + +// -------------------------------------------------- +void +DocInfoWindow::MessageReceived(BMessage *msg) +{ + switch (msg->what){ + case OK_MSG: ReadFieldsFromTable(fDocInfo); Quit(); + break; + + case CANCEL_MSG: Quit(); + break; + + case DEFAULT_KEY_MSG: + case ADD_KEY_MSG: AddKey(msg, msg->what == ADD_KEY_MSG); + break; + + case REMOVE_KEY_MSG: RemoveKey(msg); + break; + + default: + inherited::MessageReceived(msg); + break; + } +} + +// -------------------------------------------------- +void +DocInfoWindow::BuildTable(BMessage *docInfo) +{ + BRect r; + float y; + float w; + float rowHeight; +#ifndef B_BEOS_VERSION_DANO + char *name; +#else + const char *name; +#endif + uint32 type; + int32 count; + + EmptyKeyList(); + while (fTable->ChildAt(0)) { + BView *child = fTable->ChildAt(0); + fTable->RemoveChild(child); + delete child; + } + + fTable->ScrollTo(0, 0); + + r = fTable->Bounds(); + y = 5; + w = r.Width() - 10; + + for (int32 i = 0; docInfo->GetInfo(B_STRING_TYPE, i, &name, &type, &count) != B_BAD_INDEX; i++) { + if (type == B_STRING_TYPE) { + BString value; + if (docInfo->FindString(name, &value) == B_OK) { + BString s; + TextControl* v = new TextControl(BRect(0, 0, w, 20), name, name, value.String(), new BMessage(), B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW); + float w; + fTable->AddChild(v); + v->GetPreferredSize(&w, &rowHeight); + v->MoveTo(5, y); + y += rowHeight + 2; + + fKeyList->AddItem(new BMenuItem(name, new BMessage(REMOVE_KEY_MSG))); + } + } + } + + BScrollBar *sb = fTableScrollView->ScrollBar(B_VERTICAL); + if (sb) { + float th = fTable->Bounds().Height()+1; + float h = y - th; + if (h > 0) { + sb->SetProportion(th / (float)y); + sb->SetRange(0, h); + sb->SetSteps(rowHeight + 2 + 2, th); + } else { + sb->SetRange(0, 0); + } + } +} + + +// -------------------------------------------------- +void +DocInfoWindow::ReadFieldsFromTable(BMessage *toDocInfo) +{ + BView* child; + BMessage m; + for (int32 i = 0; (child = fTable->ChildAt(i)) != NULL; i++) { + TextControl* t = dynamic_cast(child); + if (t) { + m.AddString(t->Label(), t->Text()); + } + } + *toDocInfo = m; +} + + +// -------------------------------------------------- +bool +DocInfoWindow::IsValidKey(const char* key) +{ + if (*key == 0) return false; + while (*key) { + if (isspace(*key) || iscntrl(*key)) break; + key ++; + } + return *key == 0; +} + + +// -------------------------------------------------- +void +DocInfoWindow::AddKey(BMessage *msg, bool textControl) +{ + void *p; + BTextControl *text; + BMenuItem *item; + BString key; + BMessage docInfo; + if (msg->FindPointer("source", &p) != B_OK || p == NULL) return; + if (textControl) { + text = reinterpret_cast(p); + key = text->Text(); + } else { + item = reinterpret_cast(p); + key = item->Label(); + } + + // key is valid and is not in list already + if (IsValidKey(key.String())) { + BMessage docInfo; + ReadFieldsFromTable(&docInfo); + if (!docInfo.HasString(key.String())) { + docInfo.AddString(key.String(), ""); + BuildTable(&docInfo); + } + } +} + + +// -------------------------------------------------- +void +DocInfoWindow::RemoveKey(BMessage *msg) +{ + void *p; + BMenuItem *item; + BString key; + BMessage docInfo; + if (msg->FindPointer("source", &p) != B_OK) return; + item = reinterpret_cast(p); + if (!item) return; + key = item->Label(); + + ReadFieldsFromTable(&docInfo); + if (docInfo.HasString(key.String())) { + docInfo.RemoveName(key.String()); + BuildTable(&docInfo); + } +} + +// -------------------------------------------------- +void +DocInfoWindow::EmptyKeyList() +{ + while (fKeyList->ItemAt(0)) { + BMenuItem *i = fKeyList->ItemAt(0); + fKeyList->RemoveItem(i); + delete i; + } +} diff --git a/src/add-ons/print/drivers/pdf/source/DocInfoWindow.h b/src/add-ons/print/drivers/pdf/source/DocInfoWindow.h new file mode 100644 index 0000000000..ee9af50fce --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/DocInfoWindow.h @@ -0,0 +1,82 @@ +/* + +PDF Writer printer driver. + +Copyright (c) 2002 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef DOCINFOWINDOW_H +#define DOCINFOWINDOW_H + +#include +#include +#include +#include +#include +#include +#include +#include "Utils.h" + +class DocInfoWindow : public HWindow +{ +public: + // Constructors, destructors, operators... + + DocInfoWindow(BMessage *doc_info); + + typedef HWindow inherited; + + // public constantes + enum { + OK_MSG = 'ok__', + CANCEL_MSG = 'cncl', + ADD_KEY_MSG = 'add_', + REMOVE_KEY_MSG = 'rmov', + DEFAULT_KEY_MSG = 'dflt', + }; + + // Virtual function overrides +public: + virtual void MessageReceived(BMessage *msg); + virtual bool QuitRequested(); + virtual void Quit(); + +private: + BMessage *fDocInfo; + BView *fTable; + BScrollView *fTableScrollView; + BMenu *fKeyList; + + void BuildTable(BMessage *fromDocInfo); + void ReadFieldsFromTable(BMessage *toDocInfo); + void EmptyKeyList(); + bool IsValidKey(const char *key); + void AddKey(BMessage* msg, bool textControl); + void RemoveKey(BMessage* msg); +}; + +#endif diff --git a/src/add-ons/print/drivers/pdf/source/DrawShape.cpp b/src/add-ons/print/drivers/pdf/source/DrawShape.cpp new file mode 100644 index 0000000000..103a40a531 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/DrawShape.cpp @@ -0,0 +1,200 @@ +/* + +DrawShape + +Copyright (c) 2002 OpenBeOS. + +Author: + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#include "DrawShape.h" +#include "Bezier.h" +#include "PDFLinePathBuilder.h" +#include "Log.h" +#include "Report.h" + +#ifdef CODEWARRIOR + #pragma mark [BShape drawing support routines] +#endif + +// -------------------------------------------------- +DrawShape::DrawShape(PDFWriter *writer, bool stroke) + : fWriter(writer) + , fStroke(stroke) + , fDrawn(false) + , fCurrentPoint(0, 0) +{ +} + + +// -------------------------------------------------- +DrawShape::~DrawShape() +{ + Draw(); +} + + +// -------------------------------------------------- +// approximate length of bezier curve +float +DrawShape::BezierLength(BPoint *curve, int n) { + float len = 0.0; + if (n <= 0) return len; + BPoint start = curve[0]; + for (int i = 1; i < n; i++) { + BPoint end = curve[i]; + BPoint diff = start - end; + len += sqrt(diff.x * diff.x + diff.y * diff.y); + start = end; + } + return scale(len); +} + + +// -------------------------------------------------- +int +DrawShape::BezierPoints(BPoint *curve, int n) { + float len = BezierLength(curve, n); + if (len <= kMinBezierPoints) return kMinBezierPoints; + if (len > kMaxBezierPoints) return kMaxBezierPoints; + return (int)len; +} + + +// -------------------------------------------------- +void +DrawShape::CreateBezierPath(BPoint *curve) { + Bezier bezier(curve, 4); + const int n = BezierPoints(curve, 4)-1; + REPORT(kDebug, 0, "BezierPoints %d", n); + for (int i = 0; i <= n; i ++) { + fSubPath.AddPoint(bezier.PointAt(i / (float) n)); + } +} + + +// -------------------------------------------------- +void +DrawShape::EndSubPath() +{ + PDFLinePathBuilder builder(&fSubPath, fWriter); + builder.CreateLinePath(); +} + + +// -------------------------------------------------- +status_t +DrawShape::IterateBezierTo(int32 bezierCount, BPoint *control) +{ + REPORT(kDebug, 0, "BezierTo"); + for (int32 i = 0; i < bezierCount; i++, control += 3) { + REPORT(kDebug, 0," (%f %f) (%f %f) (%f %f)", tx(control[0].x), ty(control[0].y), tx(control[1].x), ty(control[1].y), tx(control[2].x), ty(control[2].y)); + if (TransformPath()) { + BPoint p[4] = { fCurrentPoint, control[0], control[1], control[2] }; + CreateBezierPath(p); + } else { + PDF_curveto(Pdf(), + tx(control[0].x), ty(control[0].y), + tx(control[1].x), ty(control[1].y), + tx(control[2].x), ty(control[2].y)); + } + fCurrentPoint = control[2]; + } + return B_OK; +} + + +// -------------------------------------------------- +status_t +DrawShape::IterateClose(void) +{ + REPORT(kDebug, 0, "IterateClose %s", IsDrawing() ? (fStroke ? "stroke" : "fill") : "clip"); + if (fDrawn) REPORT(kDebug, 0, ">>> IterateClose called multiple times!"); + if (TransformPath()) + fSubPath.Close(); + else + PDF_closepath(Pdf()); + Draw(); + return B_OK; +} + + +// -------------------------------------------------- +void +DrawShape::Draw() +{ + if (!fDrawn) { + fDrawn = true; + if (IsDrawing()) { + if (fStroke) + PDF_stroke(Pdf()); + else { + PDF_fill(Pdf()); + } + } else if (TransformPath()) { + EndSubPath(); + } else { + PDF_closepath(Pdf()); + } + } +} + + +// -------------------------------------------------- +status_t +DrawShape::IterateLineTo(int32 lineCount, BPoint *linePoints) +{ + REPORT(kDebug, 0, "IterateLineTo %d", (int)lineCount); + BPoint *p = linePoints; + for (int32 i = 0; i < lineCount; i++) { + REPORT(kDebug, 0, "(%f, %f) ", p->x, p->y); + + if (TransformPath()) { + fSubPath.AddPoint(*p); + } else { + PDF_lineto(Pdf(), tx(p->x), ty(p->y)); + } + fCurrentPoint = *p; + p++; + } + return B_OK; +} + + +// -------------------------------------------------- +status_t +DrawShape::IterateMoveTo(BPoint *point) +{ + REPORT(kDebug, 0, "IterateMoveTo "); + if (!TransformPath()) { + PDF_moveto(Pdf(), tx(point->x), ty(point->y)); + } else { + EndSubPath(); + fSubPath.MakeEmpty(); + fSubPath.AddPoint(*point); + } + REPORT(kDebug, 0, "(%f, %f)", point->x, point->y); + fCurrentPoint = *point; + return B_OK; +} + diff --git a/src/add-ons/print/drivers/pdf/source/DrawShape.h b/src/add-ons/print/drivers/pdf/source/DrawShape.h new file mode 100644 index 0000000000..87cf28ce8f --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/DrawShape.h @@ -0,0 +1,79 @@ +/* + +DrawShape + +Copyright (c) 2002 OpenBeOS. + +Author: + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef DRAW_SHAPE_H +#define DRAW_SHAPE_H + +#include "PDFWriter.h" + +class DrawShape : public BShapeIterator +{ + PDFWriter *fWriter; + bool fStroke; + bool fDrawn; + BPoint fCurrentPoint; + SubPath fSubPath; + + inline FILE *Log() { return fWriter->fLog; } + inline PDF *Pdf() { return fWriter->fPdf; } + inline float tx(float x) { return fWriter->tx(x); } + inline float ty(float y) { return fWriter->ty(y); } + inline float scale(float f) { return fWriter->scale(f); } + + inline bool IsDrawing() const { return fWriter->IsDrawing(); } + inline bool IsClipping() const { return fWriter->IsClipping(); } + + inline bool IsStroking() const { return fStroke; } + inline bool IsFilling() const { return !fStroke; } + + inline float PenSize() const { return fWriter->PenSize(); } + inline bool TransformPath() const { return IsStroking() && IsClipping(); } + + enum { + kMinBezierPoints = 2, // must be greater or equal to 2 + kMaxBezierPoints = 30 + }; + + float BezierLength(BPoint *p, int n); + int BezierPoints(BPoint *p, int n); + void CreateBezierPath(BPoint *p); + void EndSubPath(); + +public: + DrawShape(PDFWriter *writer, bool stroke); + ~DrawShape(); + status_t IterateBezierTo(int32 bezierCount, BPoint *bezierPoints); + status_t IterateClose(void); + status_t IterateLineTo(int32 lineCount, BPoint *linePoints); + status_t IterateMoveTo(BPoint *point); + + void Draw(); +}; + +#endif diff --git a/src/add-ons/print/drivers/pdf/source/Driver.cpp b/src/add-ons/print/drivers/pdf/source/Driver.cpp new file mode 100644 index 0000000000..d809d613d9 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/Driver.cpp @@ -0,0 +1,228 @@ +/* + +PDF Writer printer driver. + +Copyright (c) 2001 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + + +#include +#include + +#include + +#include "Driver.h" +#include "PDFWriter.h" +#include "PrinterSettings.h" + +static PrinterDriver *instanciate_driver(BNode *spoolDir); + +/* ======== For testing only ================== */ + +//#include "MessagePrinter.h" + +//static MessagePrinter* make_Printer(); + +/** + * Static initilizer function + * + * @param none + * @return MessagePrinter* instance + */ +//static MessagePrinter* make_Printer() { +// return new MessagePrinter(); +//} + +// ======== For testing only ================== + +BMessage* +take_job(BFile *spoolFile, BNode *spoolDir, BMessage *msg) +{ + PrinterDriver *driver; + + driver = instanciate_driver(spoolDir); + if (driver->PrintJob(spoolFile, spoolDir, msg) == B_OK) { + msg = new BMessage('okok'); + } else { + msg = new BMessage('baad'); + } + delete driver; + + return msg; +} + + +// -------------------------------------------------- +BMessage* +config_page(BNode *spoolDir, BMessage *msg) +{ + BMessage *pagesetupMsg; + PrinterDriver *driver; + const char *printerName; + char buffer[B_ATTR_NAME_LENGTH+1]; + + pagesetupMsg = new BMessage(*msg); + + // Validate the message so that it is good for PDF Writer GUI + PrinterSettings *ps = new PrinterSettings(*spoolDir); + if (ps->Validate(pagesetupMsg) != B_OK) { + // check for previously saved settings + if (ps->ReadSettings(pagesetupMsg) != B_OK) { + // if there were none, then create a default set... + ps->GetDefaults(pagesetupMsg); + // ...and save them + ps->WriteSettings(pagesetupMsg); + } + } + delete ps; + +/* ======== For testing only ================== + + MessagePrinter *mp = make_Printer(); + if (mp->Print(pagesetupMsg) == B_OK) { + (new BAlert("", "config_page:MessagePrinter", "OK"))->Go(); + } else { + (new BAlert("", "config_page:MessagePrinter", "ERROR"))->Go(); + } + + ======== For testing only ================== */ + + // retrieve the printer (spool) name. + printerName = NULL; + if (spoolDir->ReadAttr("Printer Name", B_STRING_TYPE, 1, buffer, B_ATTR_NAME_LENGTH+1) > 0) { + printerName = buffer; + } + + driver = instanciate_driver(spoolDir); + if (driver->PageSetup(pagesetupMsg, printerName) == B_OK) { + pagesetupMsg->what = 'okok'; + } else { + delete pagesetupMsg; + pagesetupMsg = NULL; + } + + delete driver; + + return pagesetupMsg; +} + + +// -------------------------------------------------- +BMessage* +config_job(BNode *spoolDir, BMessage *msg) +{ + BMessage *jobsetupMsg; + PrinterDriver *driver; + const char *printerName; + char buffer[B_ATTR_NAME_LENGTH+1]; + + jobsetupMsg = new BMessage(*msg); + + // Validate the message so that it is good for PDF Writer GUI + PrinterSettings *ps = new PrinterSettings(*spoolDir); + if (ps->Validate(jobsetupMsg) != B_OK) { + // check for previously saved settings + if (ps->ReadSettings(jobsetupMsg) != B_OK) { + // if there were none, then create a default set... + ps->GetDefaults(jobsetupMsg); + // ...and save them + ps->WriteSettings(jobsetupMsg); + } + } + delete ps; + +/* ======== For testing only ================== + + MessagePrinter *mp = make_Printer(); + if (mp->Print(jobsetupMsg) == B_OK) { + (new BAlert("", "config_job:MessagePrinter", "OK"))->Go(); + } else { + (new BAlert("", "config_job:MessagePrinter", "ERROR"))->Go(); + } + + ======== For testing only ================== */ + + // retrieve the printer (spool) name. + printerName = NULL; + if (spoolDir->ReadAttr("Printer Name", B_STRING_TYPE, 1, buffer, B_ATTR_NAME_LENGTH+1) > 0) { + printerName = buffer; + } + driver = instanciate_driver(spoolDir); + if (driver->JobSetup(jobsetupMsg, printerName) == B_OK) { + jobsetupMsg->what = 'okok'; + } else { + delete jobsetupMsg; + jobsetupMsg = NULL; + } + + delete driver; + + return jobsetupMsg; +} + + +// -------------------------------------------------- +char* +add_printer(char *printerName) +{ + return printerName; +} + + +// -------------------------------------------------- +static PrinterDriver* +instanciate_driver(BNode *spoolDir) +{ + return new PDFWriter(); +} + +/** + * default_settings + * + * @param BNode* printer spool directory + * @return BMessage* the settings + */ +BMessage* +default_settings(BNode* printer) +{ +// (new BAlert("", "default_settings()", "Driver.cpp"))->Go(); + + PrinterSettings *ps = new PrinterSettings(*printer); + BMessage *msg = new BMessage(); + + // first read the settings from the spool dir + if (ps->ReadSettings(msg) != B_OK) { + // if there were none, then create a default set... + ps->GetDefaults(msg); + // ...and save them + ps->WriteSettings(msg); + } + delete ps; + + return msg; +} + diff --git a/src/add-ons/print/drivers/pdf/source/Driver.h b/src/add-ons/print/drivers/pdf/source/Driver.h new file mode 100644 index 0000000000..aa903e0677 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/Driver.h @@ -0,0 +1,43 @@ +/* + +PDF Writer printer driver. + +Copyright (c) 2002 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#include + +extern "C" +{ +__declspec(dllexport) BMessage * take_job(BFile * spool_file, BNode * spool_dir, BMessage * msg); +__declspec(dllexport) BMessage * config_page(BNode * spool_dir, BMessage * msg); +__declspec(dllexport) BMessage * config_job(BNode * spool_dir, BMessage * msg); +__declspec(dllexport) char * add_printer(char * printer_name); +__declspec(dllexport) BMessage * default_settings(BNode * printer); +} + + diff --git a/src/add-ons/print/drivers/pdf/source/Fonts.cpp b/src/add-ons/print/drivers/pdf/source/Fonts.cpp new file mode 100644 index 0000000000..b0265f8018 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/Fonts.cpp @@ -0,0 +1,534 @@ +/* + +Copyright (c) 2001, 2002 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#include +#include +#include +#include "Fonts.h" + + +// FontFile + +// --------------------------------------- +// Implementation of BArchivable interface +// --------------------------------------- + + +// -------------------------------------------------- +FontFile::FontFile(BMessage *archive) +{ + int8 type; + archive->FindString("name", &fName); + archive->FindString("path", &fPath); + archive->FindInt64 ("size", &fSize); + if (B_OK == archive->FindInt8 ("type", &type)) + fType = (font_type)type; + else + fType = unknown_type; + archive->FindBool ("embed", &fEmbed); + archive->FindString("subst", &fSubst); +} + +// -------------------------------------------------- +BArchivable *FontFile::Instantiate(BMessage *archive) +{ + if (!validate_instantiation(archive, "FontFile")) { + return NULL; + } + return new FontFile(archive); +} + + +// -------------------------------------------------- +status_t FontFile::Archive(BMessage *archive, bool deep) const +{ + archive->AddString("class", "FontFile"); + archive->AddString("name", fName); + archive->AddString("path", fPath); + archive->AddInt64 ("size", fSize); + archive->AddInt8 ("type", (int8)fType); + archive->AddBool ("embed", fEmbed); + archive->AddString("subst", fSubst); + return B_OK; +} + + +// Fonts + +#define fmin(x, y) ( (x < y) ? x : y); + +#define TRUETYPE_VERSION 0x00010000 +#define OPENTYPE_CFF_VERSION 'OTTO' + +#define TRUETTYPE_TABLE_NAME_TAG 'name' + +static uint16 ttf_get_uint16(FILE * ttf); +static uint32 ttf_get_uint32(FILE *ttf); +static status_t ttf_get_fontname(const char * path, char * fontname, size_t fn_size); +static status_t psf_get_fontname(const char * path, char * fontname, size_t fn_size); + + +// -------------------------------------------------- +Fonts::Fonts() +{ + SetDefaultCJKOrder(); +} + + +void +Fonts::SetDefaultCJKOrder() +{ + SetCJKOrder(0, japanese_encoding, true); + SetCJKOrder(1, chinese_gb1_encoding, true); + SetCJKOrder(2, chinese_cns1_encoding, true); + SetCJKOrder(3, korean_encoding, true); +} + +// -------------------------------------------------- +bool +Fonts::SetCJKOrder(int i, font_encoding enc, bool active) +{ + if (0 <= i && i < no_of_cjk_encodings) { + fCJKOrder[i].encoding = enc; + fCJKOrder[i].active = active; + return true; + } + return false; +} + + +// -------------------------------------------------- +bool +Fonts::GetCJKOrder(int i, font_encoding& enc, bool& active) const +{ + if (0 <= i && i < no_of_cjk_encodings) { + enc = fCJKOrder[i].encoding; + active = fCJKOrder[i].active; + return true; + } + return false; +} + + +// --------------------------------------- +// Implementation of BArchivable interface +// --------------------------------------- + + +// -------------------------------------------------- +Fonts::Fonts(BMessage *archive) +{ + BMessage m; + for (int i = 0; archive->FindMessage("fontfile", i, &m) == B_OK; i++) { + BArchivable* base = instantiate_object(&m); + if (base) { + FontFile* f = dynamic_cast(base); + if (f) fFontFiles.AddItem(f); + else delete f; + } + } + if (archive->FindMessage("cjk_order", &m) == B_OK) { + for (int i = 0; i < no_of_cjk_encodings; i++) { + bool active; int32 encoding; + if (m.FindInt32("encoding", i, &encoding) == B_OK && + m.FindBool("active", i, &active) == B_OK && + first_cjk_encoding <= encoding && + encoding < first_cjk_encoding + no_of_cjk_encodings) { + SetCJKOrder(i, (font_encoding)encoding, active); + } else { + SetDefaultCJKOrder(); return; + } + } + return; + } + SetDefaultCJKOrder(); +} + + +// -------------------------------------------------- +BArchivable *Fonts::Instantiate(BMessage *archive) +{ + if (!validate_instantiation(archive, "Fonts")) { + return NULL; + } + return new Fonts(archive); +} + + +// -------------------------------------------------- +status_t Fonts::Archive(BMessage *archive, bool deep) const +{ + archive->AddString("class", "Fonts"); + const int n = Length(); + for (int i = 0; i < n; i++) { + FontFile* f = At(i); + BMessage m; + if (f->Archive(&m) == B_OK) { + archive->AddMessage("fontfile", &m); + } + } + BMessage m; + font_encoding enc; + bool active; + for (int i = 0; GetCJKOrder(i, enc, active); i++) { + m.AddInt32("encoding", enc); + m.AddBool("active", active); + } + archive->AddMessage("cjk_order", &m); + return B_OK; +} + + +// -------------------------------------------------- +status_t +Fonts::CollectFonts() +{ + BPath path; + directory_which * which_dir; + directory_which lookup_dirs[] = { + B_BEOS_FONTS_DIRECTORY, + // B_COMMON_FONTS_DIRECTORY, // seem to be the same directory than B_USER_FONTS_DIRECTORY!!! + B_USER_FONTS_DIRECTORY, + (directory_which) -1 + }; + + which_dir = lookup_dirs; + while (*which_dir >= 0) { + if ( find_directory(*which_dir, &path) == B_OK ) + LookupFontFiles(path); + + which_dir++; + }; + + return B_OK; +} + + +// -------------------------------------------------- +status_t +Fonts::LookupFontFiles(BPath path) +{ + BDirectory dir(path.Path()); + BEntry entry; + + if (dir.InitCheck() != B_OK) + return B_ERROR; + + dir.Rewind(); + while (dir.GetNextEntry(&entry) >= 0) { + BPath name; + char fn[512]; + font_type ft = unknown_type; // to keep the compiler silent. + off_t size; + status_t status; + + entry.GetPath(&name); + if (entry.IsDirectory()) + // recursivly lookup in sub-directories... + LookupFontFiles(name); + + if (! entry.IsFile()) + continue; + + fn[0] = 0; + ft = unknown_type; + + // is it a truetype file? + status = ttf_get_fontname(name.Path(), fn, sizeof(fn)); + if (status == B_OK ) { + ft = true_type_type; + } else { + // okay, maybe it's a postscript type file? + status = psf_get_fontname(name.Path(), fn, sizeof(fn)); + if (status == B_OK) { + ft = type1_type; + } + } + + if (ft == unknown_type) + // not a font file... + continue; + + if (entry.GetSize(&size) != B_OK) + size = 1024*1024*1024; + + fFontFiles.AddItem(new FontFile(fn, name.Path(), size, ft, size < 100*1024)); + } // while dir.GetNextEntry()... + + return B_OK; +} + +// -------------------------------------------------- +void +Fonts::SetTo(BMessage *archive) +{ + BArchivable *a = Instantiate(archive); + Fonts *f = a ? dynamic_cast(a) : NULL; + if (f) { + const int n = Length(); + const int m = f->Length(); + for (int i = 0; i < m; i ++) { + FontFile *font = f->At(i); + for (int j = 0; j < n; j ++) { + if (strcmp(font->Path(), At(j)->Path()) == 0) { + At(j)->SetEmbed(font->Embed()); + At(j)->SetSubst(font->Subst()); + break; + } + } + } + + font_encoding enc; + bool active; + for (int i = 0; f->GetCJKOrder(i, enc, active); i++) { + SetCJKOrder(i, enc, active); + } + delete f; + } +} + + +// -------------------------------------------------- +static uint16 ttf_get_uint16(FILE * ttf) +{ + uint16 v; + + if (fread(&v, 1, 2, ttf) != 2) + return 0; + + return B_BENDIAN_TO_HOST_INT16(v); +} + + +// -------------------------------------------------- +static uint32 ttf_get_uint32(FILE *ttf) +{ + uint32 buf; + + if (fread(&buf, 1, 4, ttf) != 4) + return 0; + + return B_BENDIAN_TO_HOST_INT32(buf); +} + + +// -------------------------------------------------- +static status_t ttf_get_fontname(const char * path, char * fontname, size_t fn_size) +{ + FILE * ttf; + status_t status; + uint16 nb_tables, nb_records; + uint16 i; + uint32 tag; + uint32 checksum, table_offset, length; + uint32 strings_offset; + char family_name[256]; + char face_name[256]; + int names_found; + + status = B_ERROR; + + ttf = fopen(path, "rb"); + if (! ttf) + return status; + + tag = ttf_get_uint32(ttf); /* version */ + switch(tag) { + case TRUETYPE_VERSION: + case OPENTYPE_CFF_VERSION: + break; + + default: + goto exit; + } + + /* set up table directory */ + nb_tables = ttf_get_uint16(ttf); + + fseek(ttf, 12, SEEK_SET); + + table_offset = 0; // quiet the compiler... + + for (i = 0; i < nb_tables; ++i) { + tag = ttf_get_uint32(ttf); + checksum = ttf_get_uint32(ttf); + table_offset = ttf_get_uint32(ttf); + length = ttf_get_uint32(ttf); + + if (tag == TRUETTYPE_TABLE_NAME_TAG) + break; + } + + if (tag != TRUETTYPE_TABLE_NAME_TAG) + // Mandatory name table not found! + goto exit; + + // move to name table start + fseek(ttf, table_offset, SEEK_SET); + + ttf_get_uint16(ttf); // name table format (must be 0!) + nb_records = ttf_get_uint16(ttf); + strings_offset = table_offset + ttf_get_uint16(ttf); // string storage offset is from table offset + + // offs = ttf->dir[idx].offset + tp->offsetStrings; + + // printf(" pid eid lid nid len offset value\n"); + // 65536 65536 65536 65536 65536 65536 ...... + + family_name[0] = 0; + face_name[0] = 0; + names_found = 0; + + for (i = 0; i < nb_records; ++i) { + uint16 platform_id, encoding_id, language_id, name_id; + uint16 string_len, string_offset; + + platform_id = ttf_get_uint16(ttf); + encoding_id = ttf_get_uint16(ttf); + language_id = ttf_get_uint16(ttf); + name_id = ttf_get_uint16(ttf); + string_len = ttf_get_uint16(ttf); + string_offset = ttf_get_uint16(ttf); + + if ( name_id != 1 && name_id != 2 ) + continue; + + // printf("%5d %5d %5d %5d %5d %5d ", + // platform_id, encoding_id, language_id, name_id, string_len, string_offset); + + if (string_len != 0) { + long pos; + char * buffer; + + pos = ftell(ttf); + fseek(ttf, strings_offset + string_offset, SEEK_SET); + + buffer = (char *) malloc(string_len + 16); + + fread(buffer, 1, string_len, ttf); + buffer[string_len] = '\0'; + + fseek(ttf, pos, SEEK_SET); + + if ( (platform_id == 3 && encoding_id == 1) || // Windows Unicode + (platform_id == 0) ) { // Unicode + // dirty unicode -> ascii conversion + int k; + + for (k=0; k < string_len/2; k++) + buffer[k] = buffer[2*k + 1]; + buffer[k] = '\0'; + } + + // printf("%s\n", buffer); + + if (name_id == 1) + strncpy(family_name, buffer, sizeof(family_name)); + else if (name_id == 2) + strncpy(face_name, buffer, sizeof(face_name)); + + names_found += name_id; + + free(buffer); + } + // else + // printf("\n"); + + if (names_found == 3) + break; + } + + if (names_found == 3) { +#ifndef __POWERPC__ + snprintf(fontname, fn_size, "%s-%s", family_name, face_name); +#else + sprintf(fontname, "%s-%s", family_name, face_name); +#endif + status = B_OK; + } + +exit: + fclose(ttf); + return status; +} + + +// -------------------------------------------------- +static status_t psf_get_fontname(const char * path, char * fontname, size_t fn_size) +{ + FILE * psf; + status_t status; + int i; + char line[1024]; + char * token; + char * name; + + // *.afm search for "FontName " line + // *.pfa search for "/FontName / def" line + + status = B_ERROR; + + psf = fopen(path, "r"); + if (! psf) + return status; + + name = NULL; + + i = 0; + while ( fgets(line, sizeof(line), psf) != NULL ) { + i++; + if ( i > 64 ) + // only check the first 64 lines of files... + break; + + token = strtok(line, " \r\n"); + if (! token) + continue; + + if (strcmp(token, "FontName") == 0) + name = strtok(NULL, " \r\n"); + else if (strcmp(token, "/FontName") == 0) { + name = strtok(NULL, " \r\n"); + if (name) + name++; // skip the '/' + } + + if (name) + break; + } + + if (name) { + strncpy(fontname, name, fn_size); + status = B_OK; + } + + fclose(psf); + return status; +} + diff --git a/src/add-ons/print/drivers/pdf/source/Fonts.h b/src/add-ons/print/drivers/pdf/source/Fonts.h new file mode 100644 index 0000000000..c264fe70b0 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/Fonts.h @@ -0,0 +1,136 @@ +/* + +PDF Writer printer driver. + +Copyright (c) 2001 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef FONTS_H +#define FONTS_H + +#include +#include +#include +#include "Utils.h" + +enum font_encoding +{ + macroman_encoding, + // TrueType + tt_encoding0, + tt_encoding1, + tt_encoding2, + tt_encoding3, + tt_encoding4, + // Type 1 + t1_encoding0, + t1_encoding1, + t1_encoding2, + t1_encoding3, + t1_encoding4, + // CJK + japanese_encoding, + chinese_cns1_encoding, + chinese_gb1_encoding, + korean_encoding, + first_cjk_encoding = japanese_encoding, + no_of_cjk_encodings = korean_encoding - first_cjk_encoding + 1, + invalid_encoding, +}; + + +enum font_type +{ + true_type_type, + type1_type, + unknown_type +}; + + +class FontFile : public BArchivable +{ +private: + BString fName; + BString fPath; + int64 fSize; + font_type fType; + bool fEmbed; + BString fSubst; + +public: + FontFile() { } + FontFile(const char *n, const char *p, int64 s, font_type t, bool embed) : fName(n), fPath(p), fSize(s), fType(t), fEmbed(embed) { } + FontFile(BMessage *archive); + ~FontFile() {}; + + static BArchivable* Instantiate(BMessage *archive); + status_t Archive(BMessage *archive, bool deep = true) const; + + // accessors + const char* Name() const { return fName.String(); } + const char* Path() const { return fPath.String(); } + int64 Size() const { return fSize; } + font_type Type() const { return fType; } + bool Embed() const { return fEmbed; } + const char* Subst() const { return fSubst.String(); } + + // setters + void SetEmbed(bool embed) { fEmbed = embed; } + void SetSubst(const char* subst) { fSubst = subst; } +}; + + +class Fonts : public BArchivable { +private: + TList fFontFiles; + + struct { + font_encoding encoding; + bool active; + } fCJKOrder[no_of_cjk_encodings]; + + status_t LookupFontFiles(BPath path); + +public: + Fonts(); + Fonts(BMessage *archive); + + static BArchivable* Instantiate(BMessage *archive); + status_t Archive(BMessage *archive, bool deep = true) const; + + status_t CollectFonts(); + void SetTo(BMessage *archive); + + FontFile* At(int i) const { return fFontFiles.ItemAt(i); } + int32 Length() const { return fFontFiles.CountItems(); } + + void SetDefaultCJKOrder(); + bool SetCJKOrder(int i, font_encoding enc, bool active); + bool GetCJKOrder(int i, font_encoding& enc, bool& active) const; +}; + +#endif // FONTS_H diff --git a/src/add-ons/print/drivers/pdf/source/FontsWindow.cpp b/src/add-ons/print/drivers/pdf/source/FontsWindow.cpp new file mode 100644 index 0000000000..c01ec5dd26 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/FontsWindow.cpp @@ -0,0 +1,550 @@ +/* + +PDF Writer printer driver. + +Copyright (c) 2002 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#include +#include +#include "FontsWindow.h" +#include "Fonts.h" + + +class DragListView : public BListView +{ +public: + DragListView(BRect frame, const char *name, + list_view_type type = B_SINGLE_SELECTION_LIST, + uint32 resizingMode = B_FOLLOW_LEFT | B_FOLLOW_TOP, + uint32 flags = B_WILL_DRAW | B_NAVIGABLE | B_FRAME_EVENTS); + bool InitiateDrag(BPoint point, int32 index, bool wasSelected); +}; + +DragListView::DragListView(BRect frame, const char *name, + list_view_type type, + uint32 resizingMode, uint32 flags) + : BListView(frame, name, type, resizingMode, flags) +{ +} + +bool DragListView::InitiateDrag(BPoint point, int32 index, bool wasSelected) +{ + BMessage m; + DragMessage(&m, ItemFrame(index), this); + return true; +} + + +class CJKFontItem : public BStringItem +{ + font_encoding fEncoding; + bool fActive; + +public: + CJKFontItem(const char* label, font_encoding encoding, bool active = true); + void SetActive(bool active) { fActive = active; } + void DrawItem(BView* owner, BRect rect, bool drawEverything); + + bool Active() const { return fActive; } + font_encoding Encoding() const { return fEncoding; } +}; + +CJKFontItem::CJKFontItem(const char* label, font_encoding encoding, bool active) + : BStringItem(label) + , fEncoding(encoding) + , fActive(active) +{ +} + +void +CJKFontItem::DrawItem(BView* owner, BRect rect, bool drawEverything) +{ + BStringItem::DrawItem(owner, rect, drawEverything); + if (!fActive) { + owner->SetHighColor(0, 0, 0, 0); + float y = (rect.top + rect.bottom) / 2; + owner->StrokeLine(BPoint(rect.left, y), BPoint(rect.right, y)); + } +} + +static const char* FontName(font_encoding enc) { + switch(enc) { + case japanese_encoding: return "Japanese"; + case chinese_cns1_encoding: return "Traditional Chinese"; + case chinese_gb1_encoding: return "Simplified Chinese"; + case korean_encoding: return "Korean"; + default: return "invalid font encoding!"; + } +} + +/** + * Constuctor + * + * @param + * @return + */ +FontsWindow::FontsWindow(Fonts *fonts) + : HWindow(BRect(0,0,400,220), "Fonts", B_TITLED_WINDOW_LOOK, + B_MODAL_APP_WINDOW_FEEL, B_NOT_RESIZABLE | B_NOT_MINIMIZABLE | + B_NOT_ZOOMABLE) +{ + // ---- Ok, build a default page setup user interface + BRect r, r1; + BView *panel; + BButton *button; + float x, y, w, h; + BString setting_value; + BTabView *tabView; + BTab *tab; + + fFonts = fonts; + + r = Bounds(); + tabView = new BTabView(r, "tab_view"); + + // --- Embedding tab --- + tab = new BTab(); + + // add a *dialog* background + + r.bottom -= tabView->TabHeight(); + panel = new BView(r, "embedding_panel", B_FOLLOW_ALL, + B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP); + panel-> SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + + r1 = r; r1.OffsetTo(0, 0); + // add font list +#if USE_CLV + fList = new BColumnListView(BRect(r.left+5, r.top+5, r.right-5-B_V_SCROLL_BAR_WIDTH, r.bottom-5-B_H_SCROLL_BAR_HEIGHT-30), + "fonts_list", B_FOLLOW_ALL, B_WILL_DRAW | B_NAVIGABLE_JUMP); + panel->AddChild(fList); +#else + fList = new BListView(BRect(r1.left+5, r1.top+5, r1.right-5-B_V_SCROLL_BAR_WIDTH, r1.bottom-5-B_H_SCROLL_BAR_HEIGHT-30), + "fonts_list", B_MULTIPLE_SELECTION_LIST); + panel->AddChild(new BScrollView("scroll_list", fList, + B_FOLLOW_LEFT | B_FOLLOW_TOP, 0, false, true)); + fList->SetSelectionMessage(new BMessage(SELECTION_MSG)); +#endif + FillFontList(); + + // add a "Embed" button, and make it default + button = new BButton(r1, NULL, "Embed", new BMessage(EMBED_MSG), + B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + button->ResizeToPreferred(); + button->GetPreferredSize(&w, &h); + x = r1.right - w - 8; + y = r1.bottom - h - 8; + button->MoveTo(x, y); + button->SetEnabled(false); + panel->AddChild(button); + button->MakeDefault(true); + fEmbedButton = button; + + // add a "Substitute" button + button = new BButton(r, NULL, "Substitute", new BMessage(SUBST_MSG), + B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + button->GetPreferredSize(&w, &h); + button->ResizeToPreferred(); + button->MoveTo(x - w - 8, y); + button->SetEnabled(false); + panel->AddChild(button); + fSubstButton = button; + + // add a separator line... + BBox * line = new BBox(BRect(r1.left, y - 9, r1.right, y - 8), NULL, + B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM ); + panel->AddChild(line); + + tabView->AddTab(panel, tab); + tab->SetLabel("Embedding"); + + // --- CJK tab --- + tab = new BTab(); + + // add a *dialog* background + panel = new BView(r, "cjk_panel", B_FOLLOW_ALL, + B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP); + panel-> SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + + BListView* list = + new DragListView(BRect(r1.left+5, r1.top+5, r1.right-5-B_V_SCROLL_BAR_WIDTH, r1.bottom-5-B_H_SCROLL_BAR_HEIGHT-30), + "cjk", B_MULTIPLE_SELECTION_LIST); + panel->AddChild(new BScrollView("cjk_scroll_list", list, + B_FOLLOW_LEFT | B_FOLLOW_TOP, 0, false, true)); + + font_encoding enc; bool active; + for (int i = 0; fFonts->GetCJKOrder(i, enc, active); i++) { + list->AddItem(new CJKFontItem(FontName(enc), enc, active)); + } + list->SetSelectionMessage(new BMessage(CJK_SELECTION_MSG)); + fCJKList = list; + + // add a "Embed" button + button = new BButton(r, NULL, "Enable", new BMessage(ENABLE_MSG), + B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + button->ResizeToPreferred(); + button->GetPreferredSize(&w, &h); + x = r1.right - w - 8; + y = r1.bottom - h - 8; + button->MoveTo(x, y); + button->SetEnabled(false); + panel->AddChild(button); + fEnableButton = button; + + // add a "Disable" button + button = new BButton(r, NULL, "Disable", new BMessage(DISABLE_MSG), + B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + button->GetPreferredSize(&w, &h); + button->ResizeToPreferred(); + x -= w + 8; + button->MoveTo(x, y); + button->SetEnabled(false); + panel->AddChild(button); + fDisableButton = button; + + // add a "Down" button + button = new BButton(r, NULL, "Down", new BMessage(DOWN_MSG), + B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + button->GetPreferredSize(&w, &h); + button->ResizeToPreferred(); + x -= w + 8; + button->MoveTo(x, y); + button->SetEnabled(false); + panel->AddChild(button); + fDownButton = button; + + // add a "Up" button + button = new BButton(r, NULL, "Up", new BMessage(UP_MSG), + B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + button->GetPreferredSize(&w, &h); + button->ResizeToPreferred(); + x -= w + 8; + button->MoveTo(x, y); + button->SetEnabled(false); + panel->AddChild(button); + fUpButton = button; + + // add a separator line... + line = new BBox(BRect(r1.left, y - 9, r1.right, y - 8), NULL, + B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM ); + panel->AddChild(line); + + + tabView->AddTab(panel, tab); + tab->SetLabel("CJK"); + + // add the tabView to the window + AddChild(tabView); + + MoveTo(320, 320); +} + + +// -------------------------------------------------- +FontsWindow::~FontsWindow() +{ +} + + +// -------------------------------------------------- +bool +FontsWindow::QuitRequested() +{ + return true; +} + + +// -------------------------------------------------- +void +FontsWindow::Quit() +{ + inherited::Quit(); +} + + +class ListIterator +{ + virtual bool DoItem(BListItem* item) = 0; +public: + static bool DoIt(BListItem* item, void* data); +}; + + +bool +ListIterator::DoIt(BListItem* item, void* data) +{ + if (item->IsSelected()) { + ListIterator* e = (ListIterator*)data; + return e->DoItem(item); + } + return false; +} + +class CountItems : public ListIterator +{ + BListView* fList; + Fonts* fFonts; + int fNumEmbed; + int fNumSubst; + + bool DoItem(BListItem* item); + +public: + CountItems(BListView* list, Fonts* fonts); + int GetNumEmbed() { return fNumEmbed; } + int GetNumSubst() { return fNumSubst; } +}; + +CountItems::CountItems(BListView* list, Fonts* fonts) + : fList(list) + , fFonts(fonts) + , fNumEmbed(0) + , fNumSubst(0) +{ } + +bool CountItems::DoItem(BListItem* item) +{ + int32 i = fList->IndexOf(item); + if (0 <= i && i < fFonts->Length()) { + if (fFonts->At(i)->Embed()) { + fNumEmbed ++; + } else { + fNumSubst ++; + } + } + return false; +} + +class EmbedFont : public ListIterator +{ + FontsWindow* fWindow; + BListView* fList; + Fonts* fFonts; + bool fEmbed; + + bool DoItem(BListItem* item); +public: + EmbedFont(FontsWindow* window, BListView* list, Fonts* fonts, bool embed); +}; + +EmbedFont::EmbedFont(FontsWindow* window, BListView* list, Fonts* fonts, bool embed) + : fWindow(window) + , fList(list) + , fFonts(fonts) + , fEmbed(embed) +{ +} + +bool +EmbedFont::DoItem(BListItem* item) +{ + int32 i = fList->IndexOf(item); + if (0 <= i && i < fFonts->Length()) { + fFonts->At(i)->SetEmbed(fEmbed); + fWindow->SetItemText((BStringItem*)item, fFonts->At(i)); + } + return false; +} + +// move selected item in list one position up or down +void +FontsWindow::MoveItemInList(BListView* list, bool up) +{ + int32 from = list->CurrentSelection(0); + if (from >= 0) { + int32 to; + if (up) { + if (from == 0) return; // at top of list + to = from - 1; + } else { + if (from == list->CountItems() -1) return; // at bottom of list + to = from + 1; + } + list->SwapItems(from, to); + + font_encoding enc; + bool active; + fFonts->GetCJKOrder(from, enc, active); + + font_encoding enc1; + bool active1; + fFonts->GetCJKOrder(to, enc1, active1); + fFonts->SetCJKOrder(to, enc, active); + fFonts->SetCJKOrder(from, enc1, active1); + } +} + + +void +FontsWindow::EnableItemInList(BListView* list, bool enable) +{ + int32 i = list->CurrentSelection(0); + if (i >= 0) { + BListItem* item0 = list->ItemAt(i); + CJKFontItem* item = dynamic_cast(item0); + if (item) { + item->SetActive(enable); + list->Invalidate(); + font_encoding enc; + bool active; + fFonts->GetCJKOrder(i, enc, active); + fFonts->SetCJKOrder(i, enc, enable); + } + } +} + +// -------------------------------------------------- +void +FontsWindow::MessageReceived(BMessage *msg) +{ + switch (msg->what){ + case OK_MSG: Quit(); + break; + + case CANCEL_MSG: Quit(); + break; + + case EMBED_MSG: + { + #if USE_CLV + #else + EmbedFont e(this, fList, fFonts, true); + fList->DoForEach(EmbedFont::DoIt, (void*)&e); + } + PostMessage(SELECTION_MSG); + fList->Invalidate(); + #endif + break; + + case SUBST_MSG: + { + #if USE_CLV + #else + EmbedFont e(this, fList, fFonts, false); + fList->DoForEach(EmbedFont::DoIt, (void*)&e); + } + PostMessage(SELECTION_MSG); + fList->Invalidate(); + #endif + break; + + case SELECTION_MSG: + { + CountItems count(fList, fFonts); + fList->DoForEach(CountItems::DoIt, (void*)&count); + fEmbedButton->SetEnabled(count.GetNumSubst() > 0); + fSubstButton->SetEnabled(count.GetNumEmbed() > 0); + } + break; + + case UP_MSG: + case DOWN_MSG: + MoveItemInList(fCJKList, msg->what == UP_MSG); + PostMessage(CJK_SELECTION_MSG); + break; + + case ENABLE_MSG: + case DISABLE_MSG: + EnableItemInList(fCJKList, msg->what == ENABLE_MSG); + PostMessage(CJK_SELECTION_MSG); + break; + + case CJK_SELECTION_MSG: + { + int32 i = fCJKList->CurrentSelection(0); + if (i >= 0) { + BListItem* item0 = fCJKList->ItemAt(i); + CJKFontItem* item = dynamic_cast(item0); + if (item) { + fUpButton->SetEnabled(i != 0); + fDownButton->SetEnabled(i != fCJKList->CountItems()-1); + fEnableButton->SetEnabled(!item->Active()); + fDisableButton->SetEnabled(item->Active()); + } + } + } + break; + + default: + inherited::MessageReceived(msg); + break; + } +} + +void +FontsWindow::SetItemText(BStringItem* i, FontFile* f) +{ + const int64 KB = 1024; + const int64 MB = KB * KB; + char buffer[40]; + BString s; + s << f->Name() << ": "; + if (f->Type() == true_type_type) s << "TrueType"; + else s << "Type 1"; + s << " ("; + if (f->Size() >= MB) { + sprintf(buffer, "%d MB", (int)(f->Size()/MB)); + } else if (f->Size() >= KB) { + sprintf(buffer, "%d KB", (int)(f->Size()/KB)); + } else { + sprintf(buffer, "%d B", (int)(f->Size())); + } + s << buffer; + s << ") "; + s << (f->Embed() ? "embed" : "substitute"); + i->SetText(s.String()); +} + +void +FontsWindow::FillFontList() +{ + const int n = fFonts->Length(); + for (int i = 0; i < n; i++) { +#if USE_CLV +#else + BStringItem* s; + FontFile* f = fFonts->At(i); + fList->AddItem(s = new BStringItem("")); + SetItemText(s, f); +#endif + } +} + +void +FontsWindow::EmptyFontList() +{ +#if USE_CLV +#else + const int n = fList->CountItems(); + for (int i = 0; i < n; i++) { + BListItem* item = fList->ItemAt(i); + delete item; + } + fList->MakeEmpty(); +#endif +} \ No newline at end of file diff --git a/src/add-ons/print/drivers/pdf/source/FontsWindow.h b/src/add-ons/print/drivers/pdf/source/FontsWindow.h new file mode 100644 index 0000000000..d4898611e4 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/FontsWindow.h @@ -0,0 +1,106 @@ +/* + +PDF Writer printer driver. + +Copyright (c) 2002 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef FONTSWINDOW_H +#define FONTSWINDOW_H + +#include +#include +#include +#include +#include +#include +#include +#include "Utils.h" +#include "Fonts.h" + +#define USE_CLV 0 +#if USE_CLV +#include "ColumnListView.h" +#endif + +class FontsWindow : public HWindow +{ +public: + // Constructors, destructors, operators... + + FontsWindow(Fonts* fonts); + ~FontsWindow(); + + typedef HWindow inherited; + + // public constantes + enum { + OK_MSG = 'ok__', + CANCEL_MSG = 'cncl', + EMBED_MSG = 'mbed', + SUBST_MSG = 'subs', + SELECTION_MSG = 'sele', + CJK_SELECTION_MSG = 'cjks', + UP_MSG = 'up__', + DOWN_MSG = 'down', + ENABLE_MSG = 'enbl', + DISABLE_MSG = 'dsbl', + }; + + // Virtual function overrides +public: + virtual void MessageReceived(BMessage *msg); + virtual bool QuitRequested(); + void Quit(); + +private: + Fonts* fFonts; +#if USE_CLV + BColumnListView fList; +#else + BListView* fList; +#endif + BButton* fEmbedButton; + BButton* fSubstButton; + + BListView* fCJKList; + BButton* fUpButton; + BButton* fDownButton; + BButton* fEnableButton; + BButton* fDisableButton; + + + void FillFontList(); + void EmptyFontList(); + void SetItemText(BStringItem* i, FontFile* f); + void MoveItemInList(BListView* list, bool up); + void EnableItemInList(BListView* list, bool enable); + + friend class EmbedFont; +}; + +#endif diff --git a/src/add-ons/print/drivers/pdf/source/JobSetupWindow.cpp b/src/add-ons/print/drivers/pdf/source/JobSetupWindow.cpp new file mode 100644 index 0000000000..34141c742e --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/JobSetupWindow.cpp @@ -0,0 +1,318 @@ +/* + +PDF Writer printer driver. + +Copyright (c) 2001 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#include +#include +#include + +#include "PrinterDriver.h" +#include "JobSetupWindow.h" +#include "DocInfoWindow.h" + +// -------------------------------------------------- +JobSetupWindow::JobSetupWindow(BMessage *msg, const char * printerName) + : HWindow(BRect(0, 0, 320, 160), "Job Setup", B_TITLED_WINDOW_LOOK, + B_MODAL_APP_WINDOW_FEEL, B_NOT_RESIZABLE | B_NOT_MINIMIZABLE | + B_NOT_ZOOMABLE) +{ + fSetupMsg = msg; + fExitSem = create_sem(0, "JobSetup"); + fResult = B_ERROR; + + if (printerName) { + BString title; + title << printerName << " Job Setup"; + SetTitle(title.String()); + } + + // ---- Ok, build a default job setup user interface + BRect r; + BBox *panel; + BBox *line; + BButton *ok; + BButton *cancel; + BStringView *sv; + float x, y, w, h; + float indent; + int32 copies; + int32 firstPage; + int32 lastPage; + bool allPages; + char buffer[80]; + + // PrinterDriver ensures that property exists + msg->FindInt32("copies", &copies); + msg->FindInt32("first_page", &firstPage); + msg->FindInt32("last_page", &lastPage); + if (B_OK != msg->FindMessage("doc_info", &fDocInfo)) { + fDocInfo.AddString("Author", ""); + fDocInfo.AddString("Subject", ""); + fDocInfo.AddString("Keywords", ""); + } + + allPages = firstPage == 1 && lastPage == MAX_INT32; + + r = Bounds(); + + // add a *dialog* background + panel = new BBox(r, "top_panel", B_FOLLOW_ALL, + B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP, + B_PLAIN_BORDER); + + const int kMargin = 6; + + //const char *kCopiesLabel = "Copies:"; + const char *kCopiesLabelExtraSpace = "Copies:##"; + const char *kPagesRangeLabel = "Pages:"; + const char *kAllPagesLabel = "All"; + const char *kPagesRangeSelectionLabel = ""; + const char *kFromLabel = "From:"; + const char *kFromLabelExtraSpace = "From:##"; + const char *kToLabel = "To:"; + const char *kToLabelExtraSpace = "To:##"; + + r = panel->Bounds(); + + x = r.left + kMargin; + y = r.top + kMargin; + + + // add a "copies" input field + +/* Simon: temporarily removed this code + sprintf(buffer, "%d", (int)copies); + fCopies = new BTextControl(BRect(x, y, x+100, y+20), "copies", kCopiesLabel, + buffer, new BMessage(NB_COPIES_MSG)); + fCopies->SetAlignment(B_ALIGN_LEFT, B_ALIGN_RIGHT); + fCopies->ResizeToPreferred(); + fCopies->GetPreferredSize(&w, &h); + panel->AddChild(fCopies); + + y += h + kMargin; // "new line" +*/ + // add a "pages" label + sv = new BStringView(BRect(x, y, x+100, y+20), "pages_range", kPagesRangeLabel); + panel->AddChild(sv); + sv->ResizeToPreferred(); + sv->GetPreferredSize(&w, &h); + + // align "copies" textcontrol field on the "allPages" radiobutton bellow... + indent = be_plain_font->StringWidth(kCopiesLabelExtraSpace); + w += kMargin; + if ( w > indent ) + indent = w; + // fCopies->SetDivider(indent); + + x += indent; + + // add a "all" radiobutton + fAll = new BRadioButton(BRect(x, y, x+100, y+20), "all_pages", kAllPagesLabel, + new BMessage(ALL_PAGES_MGS)); + fAll->ResizeToPreferred(); + fAll->GetPreferredSize(&w, &h); + fAll->SetValue(allPages); + panel->AddChild(fAll); + + y += h + kMargin; // "new line" + + // add a range selection raddiobutton + fRange = new BRadioButton(BRect(x, y, x+100, y+20), "pages_range_selection", kPagesRangeSelectionLabel, + new BMessage(RANGE_SELECTION_MSG)); + fRange->ResizeToPreferred(); + fRange->GetPreferredSize(&w, &h); + fRange->SetValue(!allPages); + panel->AddChild(fRange); + + x += w + kMargin; + + // add a "from" field + if (allPages) { + buffer[0] = 0; + } else { + sprintf(buffer, "%d", (int)firstPage); + } + fFrom = new BTextControl(BRect(x, y, x+100, y+20), "from_field", kFromLabel, buffer, + new BMessage(RANGE_FROM_MSG)); + fFrom->SetAlignment(B_ALIGN_LEFT, B_ALIGN_RIGHT); + fFrom->SetDivider(be_plain_font->StringWidth(kFromLabelExtraSpace)); + fFrom->ResizeToPreferred(); + fFrom->GetPreferredSize(&w, &h); + panel->AddChild(fFrom); + + x += w + kMargin; + + // add a "to" field + if (allPages) { + buffer[0] = 0; + } else { + sprintf(buffer, "%d", (int)lastPage); + } + fTo = new BTextControl(BRect(x, y, x+100, y+20), "to_field", kToLabel, buffer, + new BMessage(RANGE_TO_MSG)); + fTo->SetAlignment(B_ALIGN_LEFT, B_ALIGN_RIGHT); + fTo->SetDivider(be_plain_font->StringWidth(kToLabelExtraSpace)); + fTo->ResizeToPreferred(); + fTo->GetPreferredSize(&w, &h); + panel->AddChild(fTo); + + y += h + kMargin + kMargin; // "new line" + x = r.left + kMargin; + + // add a separator line... + line = new BBox(BRect(r.left, y - 1, r.right, y), NULL, + B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP ); + panel->AddChild(line); + + y += 2 + kMargin + kMargin; // "new line" + + // add a "OK" button, and make it default + ok = new BButton(BRect(x, y, x+100, y+20), NULL, "OK", new BMessage(OK_MSG), B_FOLLOW_RIGHT | B_FOLLOW_TOP); + ok->MakeDefault(true); + ok->ResizeToPreferred(); + ok->GetPreferredSize(&w, &h); + x = r.right - w - kMargin; + ok->MoveTo(x, ok->Frame().top); // put the ok bottom at bottom right corner + panel->AddChild(ok); + + // add a "Cancel" button + cancel = new BButton(BRect(x, y, x + 100, y + 20), NULL, "Cancel", new BMessage(CANCEL_MSG), B_FOLLOW_RIGHT | B_FOLLOW_TOP); + cancel->ResizeToPreferred(); + cancel->GetPreferredSize(&w, &h); + cancel->MoveTo(x - w - kMargin, y); // put cancel button left next the ok button + panel->AddChild(cancel); + + // add a "DocInfo" button + BButton *button = new BButton(r, NULL, "Doc Info", new BMessage(DOC_INFO_MSG), + B_FOLLOW_RIGHT | B_FOLLOW_TOP); + button->GetPreferredSize(&w, &h); + button->ResizeToPreferred(); + button->MoveTo(8, y); + panel->AddChild(button); + + // Finally, add our panel to window + AddChild(panel); + + // Auto resize window + ResizeTo(ok->Frame().right + kMargin, ok->Frame().bottom + kMargin); +} + + +// -------------------------------------------------- +void +JobSetupWindow::UpdateJobMessage() +{ +// int32 copies = atoi(fCopies->Text()); +// if (copies <= 0) + int32 copies = 1; + + int32 from; + int32 to; + if (fAll->Value() == B_CONTROL_ON) { + from = 1; to = MAX_INT32; + } else { + from = atoi(fFrom->Text()); + to = atoi(fTo->Text()); + if (from <= 0) from = 1; + if (to < from) to = from; + } + + fSetupMsg->ReplaceInt32("copies", copies); + fSetupMsg->ReplaceInt32("first_page", from); + fSetupMsg->ReplaceInt32("last_page", to); + if (fSetupMsg->HasMessage("doc_info")) { + fSetupMsg->ReplaceMessage("doc_info", &fDocInfo); + } else { + fSetupMsg->AddMessage("doc_info", &fDocInfo); + } +} + + +// -------------------------------------------------- +JobSetupWindow::~JobSetupWindow() +{ + delete_sem(fExitSem); +} + + +// -------------------------------------------------- +bool +JobSetupWindow::QuitRequested() +{ + release_sem(fExitSem); + return true; +} + + +// -------------------------------------------------- +void +JobSetupWindow::MessageReceived(BMessage *msg) +{ + switch (msg->what) { + case OK_MSG: + UpdateJobMessage(); + fResult = B_OK; + release_sem(fExitSem); + break; + + case CANCEL_MSG: + release_sem(fExitSem); + break; + + case RANGE_FROM_MSG: + case RANGE_TO_MSG: + fRange->SetValue(B_CONTROL_ON); + break; + + case DOC_INFO_MSG: + (new DocInfoWindow(&fDocInfo))->Show(); + break; + + default: + inherited::MessageReceived(msg); + break; + } +} + + +// -------------------------------------------------- +status_t +JobSetupWindow::Go() +{ + MoveTo(300,300); + Show(); + acquire_sem(fExitSem); + Lock(); + Quit(); + + return fResult; +} + + diff --git a/src/add-ons/print/drivers/pdf/source/JobSetupWindow.h b/src/add-ons/print/drivers/pdf/source/JobSetupWindow.h new file mode 100644 index 0000000000..b6ea893e82 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/JobSetupWindow.h @@ -0,0 +1,83 @@ +/* + +PDF Writer printer driver. + +Copyright (c) 2001 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef JOBSETUPWINDOW_H +#define JOBSETUPWINDOW_H + +#include +#include "Utils.h" + +class JobSetupWindow : public HWindow +{ +public: + // Constructors, destructors, operators... + + JobSetupWindow(BMessage *msg, const char *printer_name = NULL); + ~JobSetupWindow(); + + typedef HWindow inherited; + + // public constantes + enum { + NB_COPIES_MSG = 'copy', + ALL_PAGES_MGS = 'all_', + RANGE_SELECTION_MSG = 'rnge', + RANGE_FROM_MSG = 'from', + RANGE_TO_MSG = 'to__', + OK_MSG = 'ok__', + CANCEL_MSG = 'cncl', + DOC_INFO_MSG = 'doci' + }; + + // Virtual function overrides +public: + virtual void MessageReceived(BMessage *msg); + virtual bool QuitRequested(); + status_t Go(); + + // From here, it's none of your business! ;-) +private: + long fExitSem; + status_t fResult; + BMessage *fSetupMsg; + BMessage fDocInfo; + BTextControl *fCopies; + BRadioButton *fAll; + BRadioButton *fRange; + BTextControl *fFrom; + BTextControl *fTo; + + void UpdateJobMessage(); +}; + +#endif + + \ No newline at end of file diff --git a/src/add-ons/print/drivers/pdf/source/LinePathBuilder.cpp b/src/add-ons/print/drivers/pdf/source/LinePathBuilder.cpp new file mode 100644 index 0000000000..0f402e7a08 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/LinePathBuilder.cpp @@ -0,0 +1,338 @@ +/* + +LinePathBuilder + +Copyright (c) 2002 OpenBeOS. + +Author: + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#include "LinePathBuilder.h" + +static const float kNearZero = 0.000000000001; +static const float kMinPenSize = 0.0001; + +LinePathBuilder::LinePathBuilder(SubPath *subPath, float penSize, cap_mode capMode, join_mode joinMode, float miterLimit) + : fSubPath(subPath) + , fPenSize(penSize) + , fCapMode(capMode) + , fJoinMode(joinMode) + , fMiterLimit(miterLimit) + , fFirst(true) +{ +} + + +// vector of length w/2 in direction of line [a, b] +bool +LinePathBuilder::Vector(BPoint a, BPoint b, float w, BPoint &v) +{ + v = b - a; + float l = 2.0 * sqrt(v.x * v.x + v.y * v.y); + if (fabs(l) <= kNearZero) return false; + w /= l; + v.x *= w; + v.y *= w; + return true; +} + + +// calculate line [pa, pb] parallel to line [a, b] in distance of w/2 +bool +LinePathBuilder::Parallel(BPoint a, BPoint b, float w, BPoint &pa, BPoint &pb) +{ + BPoint d; + if (!Vector(a, b, w, d)) return false; + BPoint r(-d.y, d.x); + + pa = a - r; + pb = b - r; + return true; +} + + +// calculate intercept point e of lines [a, b] and [c, d] +bool +LinePathBuilder::Cut(BPoint a, BPoint b, BPoint c, BPoint d, BPoint &e) +{ + BPoint r = b - a; + BPoint s = d - c; + BPoint v = c - a; + float div = r.x * s.y - r.y * s.x; + if (fabs(div) <= kNearZero) return false; + float u = (r.y * v.x - r.x * v.y) / div; + e.x = c.x + s.x * u; + e.y = c.y + s.y * u; + return true; +} + + +void +LinePathBuilder::RoundCap(BPoint a, BPoint b, BPoint ra, BPoint rb, bool start) +{ + BPoint bezier[3]; + BPoint v; + if (start) { // first quarter circle + Vector(b, a, PenSize(), v); + BPoint v055(0.55*v.x, 0.55*v.y); + BPoint vr055(-v.y, v.x); + bezier[0] = a + v + vr055; + bezier[1] = ra + v055; + bezier[2] = ra; + AddPoint(a+v); + BezierTo(bezier); + } else { // second quarter circle + Vector(a, b, PenSize(), v); + BPoint v055(0.55*v.x, 0.55*v.y); + BPoint vr055(v.y, -v.x); + bezier[0] = rb + v055; + bezier[1] = b + v + vr055; + bezier[2] = b + v; + AddPoint(rb); + BezierTo(bezier); + } +} + + +void +LinePathBuilder::Corner(BPoint a, BPoint b, bool start) +{ + BPoint ra, rb, r; + if (Parallel(a, b, PenSize(), ra, rb)) { + BPoint v; + switch (LineCapMode()) { + case B_ROUND_CAP: + RoundCap(a, b, ra, rb, start); + return; + case B_BUTT_CAP: // nothing to do + break; + case B_SQUARE_CAP: + Vector(a, b, PenSize(), v); + ra -= v; + rb += v; + break; + } + if (start) r = ra; else r = rb; + AddPoint(r); + } +} + + +bool +LinePathBuilder::Inside(BPoint a, BPoint b, BPoint r) +{ + BPoint v; + Vector(a, b, 2.0, v); + + if (kNearZero <= fabs(v.x)) return (r.x - b.x) / v.x <= 0.0; + else if (kNearZero <= fabs(v.y)) return (r.y - b.y) / v.y <= 0.0; + else return false; // should not reach here (length of v > 0.0!) +} + + +bool +LinePathBuilder::InMiterLimit(BPoint a, BPoint b) +{ + BPoint d = a - b; + return 2.0*sqrt(d.x*d.x + d.y*d.y)/PenSize() <= LineMiterLimit(); +} + + +void +LinePathBuilder::RoundJoin(BPoint p[4]) +{ + BPoint v[2]; + Vector(p[0], p[1], PenSize() * 0.63, v[0]); + Vector(p[3], p[2], PenSize() * 0.63, v[1]); + AddPoint(p[1]); + BPoint bezier[3] = {p[1]+v[0], p[2]+v[1], p[2] }; + BezierTo(bezier); +} + + +void +LinePathBuilder::Connect(BPoint a, BPoint b, BPoint c) +{ + BPoint p[4], r, v; + if (Parallel(a, b, PenSize(), p[0], p[1]) && + Parallel(b, c, PenSize(), p[2], p[3]) && + Cut(p[0], p[1], p[2], p[3], r)) { + + + + if (LineJoinMode() != B_BUTT_JOIN && + LineJoinMode() != B_SQUARE_JOIN && + Inside(p[0], p[1], r)) { + if (!Inside(p[1], p[0], r) || !Inside(p[2], p[3], r)) { + AddPoint(p[1]); AddPoint(p[2]); + } else { + AddPoint(r); + } + return; + } + + switch (LineJoinMode()) { + case B_ROUND_JOIN: + RoundJoin(p); + break; + case B_MITER_JOIN: + if (InMiterLimit(b, r)) { + AddPoint(r); + break; + } + // fall through + case B_BEVEL_JOIN: + AddPoint(p[1]); AddPoint(p[2]); + break; + case B_BUTT_JOIN: // ??? + AddPoint(p[1]); AddPoint(b); AddPoint(p[2]); + break; + case B_SQUARE_JOIN: // ??? + Vector(a, b, PenSize(), v); + AddPoint(p[1] + v); AddPoint(b + v); + Vector(b, c, PenSize(), v); + AddPoint(b - v); AddPoint(p[2] - v); + break; + } + } +} + + +bool +LinePathBuilder::IdenticalPoints(int i, int j) +{ + BPoint d = fSubPath->PointAt(i) - fSubPath->PointAt(j); + return d.x * d.x + d.y * d.y < kNearZero; +} + + +// remove identical points +void +LinePathBuilder::OptimizeSubPath() +{ + int i, j = 0; + const int n = fSubPath->CountPoints(); + for (i = 1; i < n; i++) { + if (!IdenticalPoints(i, j)) { + fSubPath->AtPut(++j, fSubPath->PointAt(i)); + } + } + fSubPath->Truncate(i-j-1); + + // check also first point == last point if path is closed + if (fSubPath->IsClosed() && fSubPath->CountPoints() >= 2) { + const int n = fSubPath->CountPoints()-1; + if (IdenticalPoints(0, n)) fSubPath->Truncate(1); + } +} + + +BPoint +LinePathBuilder::PointAt(int i) +{ + const int n = fSubPath->CountPoints(); + return fSubPath->PointAt((i+n) % n); +} + + +void +LinePathBuilder::AddPoint(BPoint p) +{ + if (fFirst) { + fFirst = false; + MoveTo(p); + } else { + LineTo(p); + } +} + + +void +LinePathBuilder::CreateLinePath() +{ + OptimizeSubPath(); + if (fPenSize < kMinPenSize) fPenSize = kMinPenSize; + + const bool start = true; + const bool end = false; + const int n = fSubPath->CountPoints(); + + if (n < 2) return; + + bool is_closed = fSubPath->IsClosed() && n != 2; + + if (fSubPath->IsClosed() && n == 2) { + switch (LineJoinMode()) { + case B_ROUND_JOIN: + fCapMode = B_ROUND_CAP; + break; + case B_MITER_JOIN: // fall through + case B_BEVEL_JOIN: // fall through + case B_BUTT_JOIN: + fCapMode = B_BUTT_CAP; + break; + case B_SQUARE_JOIN: + fCapMode = B_SQUARE_CAP; + break; + } + } + + // ahead + if (is_closed) { + Connect(PointAt(n-1), PointAt(0), PointAt(1)); + } else { + Corner(PointAt(0), PointAt(1), start); + } + + for (int i = 1; i < n-1; i++) { + Connect(PointAt(i-1), PointAt(i), PointAt(i+1)); + } + + if (is_closed) { + Connect(PointAt(n-2), PointAt(n-1), PointAt(n)); + Connect(PointAt(n-1), PointAt(n), PointAt(n+1)); + } else { + Corner(PointAt(n-2), PointAt(n-1), end); + } + + // and back + if (is_closed) { + ClosePath(); fFirst = true; + Connect(PointAt(n+1), PointAt(n), PointAt(n-1)); + Connect(PointAt(n), PointAt(n-1), PointAt(n-2)); + } else { + Corner(PointAt(n-1), PointAt(n-2), start); + } + + for (int i = n-2; i >= 1; i--) { + Connect(PointAt(i+1), PointAt(i), PointAt(i-1)); + } + + if (is_closed) { + Connect(PointAt(1), PointAt(0), PointAt(n-1)); + } else { + Corner(PointAt(1), PointAt(0), end); + } + ClosePath(); +} + diff --git a/src/add-ons/print/drivers/pdf/source/LinePathBuilder.h b/src/add-ons/print/drivers/pdf/source/LinePathBuilder.h new file mode 100644 index 0000000000..06b559c280 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/LinePathBuilder.h @@ -0,0 +1,81 @@ +/* + +LinePathBuilder + +Copyright (c) 2002 OpenBeOS. + +Author: + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef LINE_PATH_BUILDER_H +#define LINE_PATH_BUILDER_H + +#include "SubPath.h" +#include + +class LinePathBuilder +{ + SubPath *fSubPath; + float fPenSize; + cap_mode fCapMode; + join_mode fJoinMode; + float fMiterLimit; + bool fFirst; + + float PenSize() const { return fPenSize; } + cap_mode LineCapMode() const { return fCapMode; } + join_mode LineJoinMode() const { return fJoinMode; } + float LineMiterLimit() const { return fMiterLimit; } + + bool Vector(BPoint a, BPoint b, float w, BPoint &v); + bool Parallel(BPoint a, BPoint b, float w, BPoint &pa, BPoint &pb); + bool Cut(BPoint a, BPoint b, BPoint c, BPoint d, BPoint &e); + bool Inside(BPoint a, BPoint b, BPoint r); + bool InMiterLimit(BPoint a, BPoint b); + + void RoundCap(BPoint a, BPoint b, BPoint ra, BPoint rb, bool start); + void RoundJoin(BPoint p[4]); + void AddPoint(BPoint p); + void Corner(BPoint a, BPoint b, bool start); + void Connect(BPoint a, BPoint b, BPoint c); + + bool IdenticalPoints(int i, int j); + void OptimizeSubPath(); + + BPoint PointAt(int i); + + +protected: + virtual void MoveTo(BPoint p) = 0; + virtual void LineTo(BPoint p) = 0; + virtual void BezierTo(BPoint p[3]) = 0; + virtual void ClosePath(void) = 0; + +public: + LinePathBuilder(SubPath *subPath, float penSize, cap_mode capMode, join_mode joinMode, float miterLimit); + virtual ~LinePathBuilder() { } + + virtual void CreateLinePath(); +}; + +#endif diff --git a/src/add-ons/print/drivers/pdf/source/Link.cpp b/src/add-ons/print/drivers/pdf/source/Link.cpp new file mode 100644 index 0000000000..ca4c11d748 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/Link.cpp @@ -0,0 +1,452 @@ +/* + +Detection and adding of web links. + +Copyright (c) 2002 OpenBeOS. + +Author: + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#define DEBUG 1 +#include +#include +#include "Link.h" +#include "XReferences.h" +#include "Bookmark.h" +#include "PDFWriter.h" +#include "Log.h" +#include "Report.h" + +Link::Link(PDFWriter* writer, BString* utf8, BFont* font) + : fWriter(writer) + , fUtf8(utf8) + , fFont(font) + , fPos(0) + , fContainsLink(false) +{ +} + + +// create link from fStartPos to fEndPos and fStart to end +void +Link::CreateLink(BPoint end) +{ + if (fFont->Rotation() != 0.0) { + REPORT(kWarning, fWriter->fPage, "Warning: Can not create link for rotated font!"); + return; + } + + // calculate rectangle for url + font_height height; + fFont->GetHeight(&height); + + float llx, lly, urx, ury; + + llx = fWriter->tx(fStart.x); + urx = fWriter->tx(end.x); + lly = fWriter->ty(fStart.y + height.descent); + ury = fWriter->ty(end.y - height.ascent); + + CreateLink(llx, lly, urx, ury); +} + + +void +Link::NextChar(int cps, float x, float y, float w) +{ + if (fContainsLink) { + if (fPos == fStartPos) { + fStart.Set(x, y); + } + if (fPos == fEndPos) { + CreateLink(BPoint(x + w, y)); + DetectLink(fPos + cps); + } + fPos += cps; + } +} + +// TODO: check this list and add more prefixes +char* WebLink::fURLPrefix[] = { + "http://", + "https://", + "ftp://", + "telnet://", + "mailto:", + "news://", + "nntp://", + "gopher://", + "wais://", + "prospero://", + "mid:", + "cid:", + "afs://", + NULL +}; + + +// Superset of xpalphas rule in BNF for specific URL schemes +// See: http://www.w3.org/Addressing/URL/5_BNF.html +bool +WebLink::IsValidCodePoint(const char* cp, int cps) { + if (cps == 1) { + char c = *cp; + switch (c) { + // safe + case '$': case '-': case '_': case '@': + case '.': case '&': case '+': + // extra + case '!': case '*': case '"': case '\'': + case '(': case ')': case ',': + // hex (prefix only) + case '%': + // reserved (subset) + case '/': case '?': case '=': + // national (subset) + case '~': + return true; + default: + return isalpha(c) || isdigit(c); + } + } + return false; +} + + +bool +WebLink::DetectUrlWithPrefix(int start) +{ + int pos = INT_MAX; + char* prefix = NULL; + const char* utf8 = fUtf8->String(); + + // search prefix with smallest position + for (int i = 0; fURLPrefix[i]; i ++) { + int p = fUtf8->FindFirst(fURLPrefix[i], start); + if (p >= start && p < pos) { + pos = p; + prefix = fURLPrefix[i]; + } + } + + if (pos != INT_MAX) { + fStartPos = pos; + fEndPos = pos + strlen(prefix); + + // search end of url + int prev; + int cps; + const char* cp; + + prev = fEndPos; + pos = fEndPos; + cp = &utf8[pos]; + cps = fWriter->CodePointSize(cp); + while (IsValidCodePoint(cp, cps)) { + prev = pos; + pos += cps; + cp = &utf8[pos]; + cps = fWriter->CodePointSize(cp); + } + + // skip from end over '.' and '@' + while (fStartPos < prev && (utf8[prev] == '.' || utf8[prev] == '@')) { + // search to begin of code point + do { + prev --; + } while (!fWriter->BeginsChar(utf8[prev])); + } + + if (prev != fEndPos) { // url not empty + fEndPos = prev; + return true; + } + } + + return false; +} + + +bool +WebLink::IsValidStart(const char* cp) +{ + return *cp != '.' && *cp != '@' && IsValidCodePoint(cp, 1); +} + +bool +WebLink::IsValidChar(const char* cp) +{ + return IsValidCodePoint(cp, 1); +} + +// TODO: add better url detection (ie. "e.g." is detected as "http://e.g") +// A complete implementation should identify these kind of urls correctly: +// domain/~user +// domain/page.html?value=key +bool +WebLink::DetectUrlWithoutPrefix(int start) +{ + const char* utf8 = fUtf8->String(); + + while (utf8[start]) { + // search to start + while (utf8[start] && !IsValidStart(&utf8[start])) { + start += fWriter->CodePointSize(&utf8[start]); + } + + // search end and count dots and @s + int numDots = 0, numAts = 0; + int end = start; + int prev = end; + while (utf8[end] && IsValidChar(&utf8[end])) { + if (utf8[end] == '.') numDots ++; + else if (utf8[end] == '@') numAts ++; + prev = end; end += fWriter->CodePointSize(&utf8[end]); + } + + // skip from end over '.' and '@' + while (start < prev && (utf8[prev] == '.' || utf8[prev] == '@')) { + if (utf8[prev] == '.') numDots --; + else if (utf8[prev] == '@') numAts --; + // search to begin of code point + do { + prev --; + } while (!fWriter->BeginsChar(utf8[prev])); + } + + fStartPos = start; fEndPos = prev; + int32 length = fEndPos - fStartPos; + + if (numAts == 1) { + fKind = kMailtoKind; + return true; + } else if (numDots >= 2 && length > 2*numDots+1 && numAts == 0) { + if (strncmp(&utf8[start], "ftp", 3) == 0) fKind = kFtpKind; + else fKind = kHttpKind; + return true; + } + + // next iteration + start = end; + } + return false; +} + +void +WebLink::DetectLink(int start) +{ + fContainsLink = true; + fKind = kUnknownKind; + if (DetectUrlWithPrefix(start)) return; + if (DetectUrlWithoutPrefix(start)) return; + fContainsLink = false; +} + + +// create link from fStartPos to fEndPos and fStart to end +void +WebLink::CreateLink(float llx, float lly, float urx, float ury) +{ + BString url; + + // prepend protocol if required + switch (fKind) { + case kMailtoKind: url = "mailto:"; break; + case kHttpKind: url = "http://"; break; + case kFtpKind: url = "ftp://"; break; + case kUnknownKind: break; + default: + LOG((fWriter->fLog, "Error: Link kind missing!!!")); + } + + // append url + int endPos = fEndPos + fWriter->CodePointSize(&fUtf8->String()[fEndPos]); + + for (int i = fStartPos; i < endPos; i ++) { + url.Append(fUtf8->ByteAt(i), 1); + } + + REPORT(kInfo, fWriter->fPage, "Web link '%s'", url.String()); + // XXX: url should be in 7-bit ascii encoded! + PDF_add_weblink(fWriter->fPdf, llx, lly, urx, ury, url.String()); +} + + +WebLink::WebLink(PDFWriter* writer, BString* utf8, BFont* font) + : Link(writer, utf8, font) +{ +} + + +// TextSegment + +TextSegment::TextSegment(const char* text, BPoint start, float escpSpace, float escpNoSpace, BRect* bounds, BFont* font, PDFSystem* system) + : fText(text) + , fStart(start) + , fEscpSpace(escpSpace) + , fEscpNoSpace(escpNoSpace) + , fBounds(*bounds) + , fFont(*font) + , fSystem(*system) + , fSpaces(0) +{ +} + + +void TextSegment::PrependSpaces(int32 n) { + ASSERT(fSpaces == 0); + fSpaces = n; + BString spaces; + spaces.Append(' ', n); + fText.Prepend(spaces.String()); +} + + +// TextLine + +TextLine::TextLine(PDFWriter* writer) + : fWriter(writer) +{ +} + + +void TextLine::Add(TextSegment* segment) { + // simply skip rotated text + if (segment->Font()->Rotation() != 0.0) { + delete segment; return; + } + + if (!Follows(segment)) { + Flush(); + } + + fSegments.AddItem(segment); +} + + +bool TextLine::Follows(TextSegment* segment) const { + const int32 n = fSegments.CountItems(); + if (n == 0) return true; + TextSegment* s = fSegments.ItemAt(n-1); + // ATM segments must have same PDFSystem! + PDFSystem* os = s->System(); + PDFSystem* ns = segment->System(); + if (os->Origin() != ns->Origin() || os->Scale() != ns->Scale() || os->Height() != ns->Height()) return false; + + // follows the new segment the latest one? + BPoint start = segment->Start(); + BRect b = s->Bounds(); + float w = segment->Font()->StringWidth(" ", 1); + if (b.top <= start.y && start.y <= b.bottom && (b.right-w/2.0) <= start.x) { + // insert spaces + if (w > 0.0) { + int n = (int)((start.x - b.right) / w); + if (n > 200) n = 200; // santiy check + if (n > 0) { + segment->PrependSpaces(n); + } + } + return true; + } + return false; +} + + +void TextLine::Flush() { + const int32 n = fSegments.CountItems(); + if (n == 0) return; + + // build the text in the line + BString line; + for (int32 i = 0; i < n; i ++) { + line << fSegments.ItemAt(i)->Text(); + } + + const char* c = line.String(); +// fprintf(fWriter->fLog, "==== TextLine\n\t\t'%s'\n", c); + + if (!fWriter->MakesPDF()) { + if (fWriter->fCreateXRefs) fWriter->RecordDests(c); + } else { + // XXX + TextSegment* s = fSegments.ItemAt(0); + BFont* f = s->Font(); + + // simple link handling for now + WebLink webLink(fWriter, &line, f); + if (fWriter->fCreateWebLinks) webLink.Init(); + + // local links + LocalLink localLink(fWriter->fXRefs, fWriter->fXRefDests, fWriter, &line, f, fWriter->fPage); + if (fWriter->fCreateXRefs) localLink.Init(); + + // simple bookmark adding (XXX: s->Start() + if (fWriter->fCreateBookmarks) { + BPoint start(s->System()->tx(s->Start().x), s->System()->ty(s->Start().y)); + fWriter->fBookmark->AddBookmark(start, c, f); + } + + + for (int32 i = 0; i < n; i ++) { + + TextSegment* seg = fSegments.ItemAt(i); + BPoint pos = seg->Start(); + BFont* font = seg->Font(); + const char* sc = seg->Text(); + float escpSpace = seg->EscpSpace(); + float escpNoSpace = seg->EscpNoSpace(); + int32 spaces = seg->Spaces(); + + while (*sc != 0) { + ASSERT(*sc == *c); + + int s = fWriter->CodePointSize((char*)c); + + float w = font->StringWidth(c, s); + + if (fWriter->fCreateWebLinks) webLink.NextChar(s, pos.x, pos.y, w); + if (fWriter->fCreateXRefs) localLink.NextChar(s, pos.x, pos.y, w); + + if (spaces == 0) { + // position of next character + if (*(unsigned char*)c <= 0x20) { // should test if c is a white-space! + w += escpSpace; + } else { + w += escpNoSpace; + } + + pos.x += w; + } else { + // skip over the prepended spaces + spaces --; + } + + // next character + c += s; sc += s; + } + } + } + + fSegments.MakeEmpty(); +} + diff --git a/src/add-ons/print/drivers/pdf/source/Link.h b/src/add-ons/print/drivers/pdf/source/Link.h new file mode 100644 index 0000000000..8444095c68 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/Link.h @@ -0,0 +1,128 @@ +/* + +Detection and adding of web links. + +Copyright (c) 2002 OpenBeOS. + +Author: + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef _LINK_H +#define _LINK_H + +#include +#include +#include +#include "Utils.h" + +class PDFWriter; + +class Link { +protected: + PDFWriter* fWriter; + BString* fUtf8; + BFont* fFont; + int fPos; // into fUtf8 + + bool fContainsLink; + int fStartPos, fEndPos; + BPoint fStart; + + virtual void DetectLink(int start) = 0; + virtual void CreateLink(float llx, float lly, float urx, float ury) = 0; + + void CreateLink(BPoint end); + +public: + Link(PDFWriter* writer, BString* utf8, BFont* font); + void Init() { DetectLink(0); } + void NextChar(int cps, float x, float y, float w); +}; + +class WebLink : public Link { + enum kind { + kMailtoKind, + kHttpKind, + kFtpKind, + kUnknownKind + }; + + enum kind fKind; + + static char* fURLPrefix[]; + + bool IsValidStart(const char* cp); + bool IsValidChar(const char* cp); + bool DetectUrlWithoutPrefix(int start); + + bool IsValidCodePoint(const char* cp, int cps); + bool DetectUrlWithPrefix(int start); + + void CreateLink(float llx, float lly, float urx, float ury); + void DetectLink(int start); + +public: + WebLink(PDFWriter* writer, BString* utf8, BFont* font); +}; + +class TextSegment { + BString fText; + BPoint fStart; + float fEscpSpace; // escapement space + float fEscpNoSpace; // escapement no space + BRect fBounds; + BFont fFont; + PDFSystem fSystem; + int32 fSpaces; + +public: + TextSegment(const char* text, BPoint start, float escpSpace, float escpNoSpace, BRect* bounds, BFont* font, PDFSystem* system); + + void PrependSpaces(int32 n); + + const char* Text() const { return fText.String(); } + BPoint Start() const { return fStart; } + float EscpSpace() const { return fEscpSpace; } + float EscpNoSpace() const { return fEscpNoSpace; } + BRect Bounds() const { return fBounds; } + BFont* Font() { return &fFont; } + PDFSystem* System() { return &fSystem; } + int32 Spaces() const { return fSpaces; } +}; + + +class TextLine { + TList fSegments; + PDFWriter* fWriter; + + bool Follows(TextSegment* segment) const; + +public: + TextLine(PDFWriter* writer); + + void Add(TextSegment* segment); + void Flush(); +}; + + +#endif diff --git a/src/add-ons/print/drivers/pdf/source/Log.h b/src/add-ons/print/drivers/pdf/source/Log.h new file mode 100644 index 0000000000..d6e8f518ba --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/Log.h @@ -0,0 +1,12 @@ + +#ifndef LOG_H +#define LOG_H + +#if LOGGING + #define LOG(l) fprintf l +#else + #define LOG(l) ___do_nothing() + inline void ___do_nothing() { } +#endif + +#endif diff --git a/src/add-ons/print/drivers/pdf/source/MarginView.cpp b/src/add-ons/print/drivers/pdf/source/MarginView.cpp new file mode 100644 index 0000000000..74f910f27c --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/MarginView.cpp @@ -0,0 +1,694 @@ +/* + +MarginView.cpp + +Copyright (c) 2002 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + Todo: + + 2 Make Strings constants or UI resources + +*/ + +#ifndef MARGIN_VIEW_H +#include "MarginView.h" +#endif + +#include +#include + +#include +#include + +/*----------------- MarginView Private Constants --------------------*/ + +const int Y_OFFSET = 20; +const int X_OFFSET = 10; +const int STRING_SIZE = 50; +const int _WIDTH = 50; +const int NUM_COUNT = 10; + +const static float _pointUnits = 1; // 1 point = 1 point +const static float _inchUnits = 72; // 1" = 72 points +const static float _cmUnits = 28.346; // 72/2.54 1cm = 28.346 points + +const static float _minFieldWidth = 100; // pixels +const static float _minUnitHeight = 30; // pixels +const static float _drawInset = 10; // pixels + +const static float unitFormat[] = { _inchUnits, _cmUnits, _pointUnits }; +const static char *unitNames[] = { "Inch", "cm", "Points", NULL }; +const static uint32 unitMsg[] = { MarginView::UNIT_INCH, + MarginView::UNIT_CM, + MarginView::UNIT_POINT }; + +const pattern dots = {{ 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 }}; + +const rgb_color black = { 0,0,0,0 }; +const rgb_color red = { 255,0,0,0 }; +const rgb_color white = { 255,255,255,0 }; +const rgb_color gray = { 220,220,220,0 }; + +/*----------------- MarginView Public Methods --------------------*/ + +/** + * Constructor + * + * @param frame, BRect that is the size of the view passed to the superclase + * @param pageWidth, float that is the points value of the page width + * @param pageHeight, float that is the points value of the page height + * @param margins, BRect values of margins + * @param units, unit32 enum for units used in view + * @return void + */ +MarginView::MarginView(BRect frame, + int32 pageWidth, + int32 pageHeight, + BRect margins, + uint32 units) + + :BBox(frame, NULL, B_FOLLOW_ALL) +{ + fUnits = units; + fUnitValue = unitFormat[units]; + + SetLabel("Margins"); + + fMaxPageHeight = frame.Height() - _minUnitHeight - Y_OFFSET; + fMaxPageWidth = frame.Width() - _minFieldWidth - X_OFFSET; + + fMargins = margins; + + fPageWidth = pageWidth; + fPageHeight = pageHeight; +} + +/** + * Destructor + * + * @param none + * @return void + */ +MarginView::~MarginView() { +} + +/*----------------- MarginView Public BeOS Hook Methods --------------------*/ + +/** + * Draw + * + * @param BRect, the draw bounds + * @return void + */ +void MarginView::Draw(BRect rect) +{ + BBox::Draw(rect); + + float y_offset = (float)Y_OFFSET; + float x_offset = (float)X_OFFSET; + BRect r; + + // Calculate offsets depending on orientation + if (fPageWidth < fPageHeight) { // Portrait + x_offset = (fMaxPageWidth/2 + X_OFFSET) - fViewWidth/2; + } else { // landscape + y_offset = (fMaxPageHeight/2 + Y_OFFSET) - fViewHeight/2; + } + + // draw the page + SetHighColor(white); + r = BRect(0, 0, fViewWidth, fViewHeight); + r.OffsetBy(x_offset, y_offset); + FillRect(r); + SetHighColor(black); + StrokeRect(r); + + // draw margin + SetHighColor(red); + SetLowColor(white); + r.top += fMargins.top; + r.right -= fMargins.right; + r.bottom -= fMargins.bottom; + r.left += fMargins.left; + StrokeRect(r, dots); + + // draw the page size label + SetHighColor(black); + SetLowColor(gray); + char str[STRING_SIZE]; + sprintf(str, "%2.1f x %2.1f", fPageWidth/fUnitValue, fPageHeight/fUnitValue); + SetFontSize(10); + DrawString((const char *)str, BPoint(x_offset, fMaxPageHeight + 40)); +} + + +/** + * BeOS Hook Function, change the size of the margin display + * + * @param width of the page + * @param height the page + * @return void + */ +void MarginView::FrameResized(float width, float height) +{ + fMaxPageHeight = height - _minUnitHeight - X_OFFSET; + fMaxPageWidth = width - _minFieldWidth - Y_OFFSET; + + CalculateViewSize(MARGIN_CHANGED); + Invalidate(); +} + +/** + * AttachToWindow + * + * @param none + * @return void + */ +void MarginView::AttachedToWindow() +{ + if (Parent()) { + SetViewColor(Parent()->ViewColor()); + } + ConstructGUI(); +} + +/*----------------- MarginView Public Methods --------------------*/ + +/** + * GetUnits + * + * @param none + * @return uint32 enum, units in inches, cm, points + */ +uint32 MarginView::GetUnits(void) { + return fUnits; +} + +/** + * UpdateView, recalculate and redraw the view + * + * @param msg is a message to the calculate size to tell which field caused + * the update to occur, or it is a general update. + * @return void + */ +void MarginView::UpdateView(uint32 msg) +{ + Window()->Lock(); + CalculateViewSize(msg); + Invalidate(); + Window()->Unlock(); +} + +/** + * SetPageSize + * + * @param pageWidth, float that is the unit value of the page width + * @param pageHeight, float that is the unit value of the page height + * @return void + */ +void MarginView::SetPageSize(float pageWidth, float pageHeight) +{ + fPageWidth = pageWidth; + fPageHeight = pageHeight; +} + +/** + * GetPageSize + * + * @param none + * @return BPoint, contains actual point values of page in x, y of point + */ +BPoint MarginView::GetPageSize(void) { + return BPoint(fPageWidth, fPageHeight); +} + +/** + * GetMargin + * + * @param none + * @return rect, return margin values always in points + */ +BRect MarginView::GetMargin(void) +{ + BRect margin; + + // convert the field text to values + float ftop = atof(fTop->Text()); + float fright = atof(fRight->Text()); + float fleft = atof(fLeft->Text()); + float fbottom = atof(fBottom->Text()); + + // convert to units to points + switch (fUnits) + { + case UNIT_INCH: + // convert to points + ftop *= _inchUnits; + fright *= _inchUnits; + fleft *= _inchUnits; + fbottom *= _inchUnits; + break; + case UNIT_CM: + // convert to points + ftop *= _cmUnits; + fright *= _cmUnits; + fleft *= _cmUnits; + fbottom *= _cmUnits; + break; + } + + margin.Set(fleft, ftop, fright, fbottom); + + return margin; +} + +/** + * MesssageReceived() + * + * Receive messages for the view + * + * @param BMessage* , the message being received + * @return void + */ +void MarginView::MessageReceived(BMessage *msg) +{ + switch (msg->what) + { + case CHANGE_PAGE_SIZE: { + float w; + float h; + msg->FindFloat("width", &w); + msg->FindFloat("height", &h); + SetPageSize(w, h); + UpdateView(MARGIN_CHANGED); + } + break; + + case FLIP_PAGE: { + BPoint p; + p = GetPageSize(); + SetPageSize(p.y, p.x); + UpdateView(MARGIN_CHANGED); + } + break; + + case MARGIN_CHANGED: + UpdateView(MARGIN_CHANGED); + break; + + case TOP_MARGIN_CHANGED: + UpdateView(TOP_MARGIN_CHANGED); + break; + + case LEFT_MARGIN_CHANGED: + UpdateView(LEFT_MARGIN_CHANGED); + break; + + case RIGHT_MARGIN_CHANGED: + UpdateView(RIGHT_MARGIN_CHANGED); + break; + + case BOTTOM_MARGIN_CHANGED: + UpdateView(BOTTOM_MARGIN_CHANGED); + break; + + case UNIT_INCH: + case UNIT_CM: + case UNIT_POINT: + SetUnits(msg->what); + break; + + default: + BView::MessageReceived(msg); + break; + } +} +/*----------------- MarginView Private Methods --------------------*/ + +/** + * ConstructGUI() + * + * Creates the GUI for the View. MUST be called AFTER the View is attached to + * the Window, or will crash and/or create strange behaviour + * + * @param none + * @return void + */ +void MarginView::ConstructGUI() +{ + BMessage *msg; + BString str; + BMenuItem *item; + BMenuField *mf; + BPopUpMenu *menu; + +// Create text fields + msg = new BMessage(MARGIN_CHANGED); + BRect r(Frame().Width() - be_plain_font->StringWidth("Top#") - _WIDTH, + Y_OFFSET, Frame().Width() - X_OFFSET, _WIDTH); + + // top + msg = new BMessage(TOP_MARGIN_CHANGED); + str << fMargins.top/fUnitValue; + fTop = new BTextControl( r, "top", "Top", str.String(), msg, + B_FOLLOW_RIGHT); + fTop->SetDivider(be_plain_font->StringWidth("Top#")); + fTop->SetTarget(this); + AllowOnlyNumbers(fTop, NUM_COUNT); + AddChild(fTop); + + //left + r.OffsetBy(0, Y_OFFSET); + r.left = Frame().Width() - be_plain_font->StringWidth("Left#") - _WIDTH; + str = ""; + str << fMargins.left/fUnitValue; + msg = new BMessage(LEFT_MARGIN_CHANGED); + fLeft = new BTextControl( r, "left", "Left", str.String(), msg, + B_FOLLOW_RIGHT); + fLeft->SetDivider(be_plain_font->StringWidth("Left#")); + fLeft->SetTarget(this); + AllowOnlyNumbers(fLeft, NUM_COUNT); + AddChild(fLeft); + + //bottom + r.OffsetBy(0, Y_OFFSET); + r.left = Frame().Width() - be_plain_font->StringWidth("Bottom#") - _WIDTH; + str = ""; + str << fMargins.bottom/fUnitValue; + msg = new BMessage(BOTTOM_MARGIN_CHANGED); + fBottom = new BTextControl( r, "bottom", "Bottom", str.String(), msg, + B_FOLLOW_RIGHT); + fBottom->SetDivider(be_plain_font->StringWidth("Bottom#")); + fBottom->SetTarget(this); + + AllowOnlyNumbers(fBottom, NUM_COUNT); + AddChild(fBottom); + + //right + r.OffsetBy(0, Y_OFFSET); + r.left = Frame().Width() - be_plain_font->StringWidth("Right#") - _WIDTH; + str = ""; + str << fMargins.right/fUnitValue; + msg = new BMessage(RIGHT_MARGIN_CHANGED); + fRight = new BTextControl( r, "right", "Right", str.String(), msg, + B_FOLLOW_RIGHT); + fRight->SetDivider(be_plain_font->StringWidth("Right#")); + fRight->SetTarget(this); + AllowOnlyNumbers(fRight, NUM_COUNT); + AddChild(fRight); + +// Create Units popup + r.OffsetBy(-X_OFFSET,Y_OFFSET); + r.right += Y_OFFSET; + + menu = new BPopUpMenu("units"); + mf = new BMenuField(r, "units", "Units", menu, + B_FOLLOW_BOTTOM|B_FOLLOW_RIGHT|B_WILL_DRAW); + mf->ResizeToPreferred(); + mf->SetDivider(be_plain_font->StringWidth("Units#")); + + // Construct menu items + for (int i=0; unitNames[i] != NULL; i++ ) + { + msg = new BMessage(unitMsg[i]); + menu->AddItem(item = new BMenuItem(unitNames[i], msg)); + item->SetTarget(this); + if (fUnits == unitMsg[i]) { + item->SetMarked(true); + } + } + AddChild(mf); + + // calculate the sizes for drawing page view + CalculateViewSize(MARGIN_CHANGED); +} + + +/** + * AllowOnlyNumbers() + * + * @param BTextControl, the control we want to only allow numbers + * @param maxNum, the maximun number of characters allowed + * @return void + */ +void MarginView::AllowOnlyNumbers(BTextControl *textControl, int maxNum) +{ + BTextView *tv = textControl->TextView(); + + for (long i = 0; i < 256; i++) { + tv->DisallowChar(i); + } + for (long i = '0'; i <= '9'; i++) { + tv->AllowChar(i); + } + tv->AllowChar(B_BACKSPACE); + tv->AllowChar('.'); + tv->SetMaxBytes(maxNum); +} + +/** + * SetMargin + * + * @param brect, margin values in rect + * @return void + */ +void MarginView::SetMargin(BRect margin) { + fMargins = margin; +} + +/** + * SetUnits, called by the MarginMgr when the units popup is selected + * + * @param uint32, the enum that identifies the units requested to change to. + * @return void + */ +void MarginView::SetUnits(uint32 unit) +{ + // do nothing if the current units are the same as requested + if (unit == fUnits) { + return; + } + + // set the units Format + fUnitValue = unitFormat[unit]; + + // convert the field text to values + float ftop = atof(fTop->Text()); + float fright = atof(fRight->Text()); + float fleft = atof(fLeft->Text()); + float fbottom = atof(fBottom->Text()); + + // convert to target units + switch (fUnits) + { + case UNIT_INCH: + // convert to points + ftop *= _inchUnits; + fright *= _inchUnits; + fleft *= _inchUnits; + fbottom *= _inchUnits; + // check for target unit is cm + if (unit == UNIT_CM) { + ftop /= _cmUnits; + fright /= _cmUnits; + fleft /= _cmUnits; + fbottom /= _cmUnits; + } + break; + case UNIT_CM: + // convert to points + ftop *= _cmUnits; + fright *= _cmUnits; + fleft *= _cmUnits; + fbottom *= _cmUnits; + // check for target unit is inches + if (unit == UNIT_INCH) { + ftop /= _inchUnits; + fright /= _inchUnits; + fleft /= _inchUnits; + fbottom /= _inchUnits; + } + break; + case UNIT_POINT: + // check for target unit is cm + if (unit == UNIT_CM) { + ftop /= _cmUnits; + fright /= _cmUnits; + fleft /= _cmUnits; + fbottom /= _cmUnits; + } + // check for target unit is inches + if (unit == UNIT_INCH) { + ftop /= _inchUnits; + fright /= _inchUnits; + fleft /= _inchUnits; + fbottom /= _inchUnits; + } + break; + } + fUnits = unit; + + // lock Window since these changes are from another thread + Window()->Lock(); + + // set the fields to new units + BString str; + str << ftop; + fTop->SetText(str.String()); + + str = ""; + str << fleft; + fLeft->SetText(str.String()); + + str = ""; + str << fright; + fRight->SetText(str.String()); + + str = ""; + str << fbottom; + fBottom->SetText(str.String()); + + // update UI + CalculateViewSize(MARGIN_CHANGED); + Invalidate(); + + Window()->Unlock(); +} + +/** + * CalculateViewSize + * + * calculate the size of the view that is used + * to show the page inside the margin box. This is dependent + * on the size of the box and the room we have to show it and + * the units that we are using and the orientation of the page. + * + * @param msg, the message for which field changed to check value bounds + * @return void + */ +void MarginView::CalculateViewSize(uint32 msg) +{ + // determine page orientation + if (fPageHeight < fPageWidth) { // LANDSCAPE + fViewWidth = fMaxPageWidth; + fViewHeight = fPageHeight * (fViewWidth/fPageWidth); + float hdiff = fViewHeight - fMaxPageHeight; + if (hdiff > 0) { + fViewHeight -= hdiff; + fViewWidth -= hdiff; + } + } else { // PORTRAIT + fViewHeight = fMaxPageHeight; + fViewWidth = fPageWidth * (fViewHeight/fPageHeight); + float wdiff = fViewWidth - fMaxPageWidth; + if (wdiff > 0) { + fViewHeight -= wdiff; + fViewWidth -= wdiff; + } + } + + // calculate margins based on view size + + // find the length of 1 pixel in points + // ex: 80px/800pt = 0.1px/pt + float pixelLength = fViewHeight/fPageHeight; + + // convert the margins to points + // The text field will have a number that us in the current unit + // ex 0.2" * 72pt = 14.4pts + float ftop = atof(fTop->Text()) * fUnitValue; + float fright = atof(fRight->Text()) * fUnitValue; + float fbottom = atof(fBottom->Text()) * fUnitValue; + float fleft = atof(fLeft->Text()) * fUnitValue; + + // Check that the margins don't overlap each other... + float ph = fPageHeight; + float pw = fPageWidth; + BString str; + + // Bounds calculation rules: + if (msg == TOP_MARGIN_CHANGED) + { + // top must be <= bottom + if (ftop > (ph - fbottom)) { + ftop = ph - fbottom; + str = ""; + str << ftop / fUnitValue; + Window()->Lock(); + fTop->SetText(str.String()); + Window()->Unlock(); + } + + } + + if (msg == BOTTOM_MARGIN_CHANGED) + { + // bottom must be <= pageHeight + if (fbottom > (ph - ftop)) { + fbottom = ph - ftop; + str = ""; + str << fbottom / fUnitValue; + Window()->Lock(); + fBottom->SetText(str.String()); + Window()->Unlock(); + } + } + + if (msg == LEFT_MARGIN_CHANGED) + { + // left must be <= right + if (fleft > (pw - fright)) { + fleft = pw - fright; + str = ""; + str << fleft / fUnitValue; + Window()->Lock(); + fLeft->SetText(str.String()); + Window()->Unlock(); + } + } + + if (msg == RIGHT_MARGIN_CHANGED) + { + // right must be <= fPageWidth + if (fright > (pw - fleft)) { + fright = pw - fleft; + str = ""; + str << fright / fUnitValue; + Window()->Lock(); + fRight->SetText(str.String()); + Window()->Unlock(); + } + } + + // convert the unit value to pixels + // ex: 14.4pt * 0.1px/pt = 1.44px + fMargins.top = ftop * pixelLength; + fMargins.right = fright * pixelLength; + fMargins.bottom = fbottom * pixelLength; + fMargins.left = fleft * pixelLength; +} + + diff --git a/src/add-ons/print/drivers/pdf/source/MarginView.h b/src/add-ons/print/drivers/pdf/source/MarginView.h new file mode 100644 index 0000000000..ca342e697f --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/MarginView.h @@ -0,0 +1,226 @@ +/* + +MarginView.h + +Copyright (c) 2002 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + Documentation: + + The MarginView is designed to be a self contained component that manages + the display of a BBox control that shows a graphic of a page and its' + margings. The component also includes text fields that are used to mofify + the margin values and a popup to change the units used for the margins. + + There are two interfaces for the MarginView component: + + 1) Set methods: + - page size + - orientation + + Get methods to retrieve: + - margins + - page size + + The method interface is available for the parent Component to call on + the MarginView in response to the Window receiveing messages from + other BControls that it contains, such as a Page Size popup. The + Get methods are used to extract the page size and margins so that + the printer driver may put these values into a BMessage for printing. + + 2) 'Optional' Message interface: + - Set Page Size + - Flip Orientation + + The message interface is available for GUI Controls, BPopupMenu to send + messages to the MarginView if the parent Window is not used to handle + the messages. + + General Use of MarginView component: + + 1) Simply construct a new MarginView object with the margins + you want as defaults and add this view to the parent view + of the dialog. + + MarginView *mv; + mv = new MarginView(viewSizeRect, pageWidth, pageHeight); + parentView->AddChild(mv); + + * you can also set the margins in the constructor, and the units: + + mv = new MarginView(viewSizeRect, pageWidth, pageHeight + marginRect, UNIT_POINTS); + + ! but remeber to have the marginRect values match the UNITS :-) + + 2) Set Page Size with methods: + + mv-SetPageSize( pageWidth, pageHeight ); + mv->UpdateView(); + + 3) Set Page Size with BMessage: + + BMessage* msg = new BMessage(CHANGE_PAGE_SIZE); + msg->AddFloat("width", pageWidth); + msg->AddFloat("height", pageHeight); + mv->PostMessage(msg); + + 4) Flip Page with methods: + + mv-SetPageSize( pageHeight, pageWidth ); + mv->UpdateView(); + + 5) Flip Page with BMessage: + + BMessage* msg = new BMessage(FLIP_PAGE); + mv->Looper()->PostMessage(msg); + + Note: the MarginView DOES NOT keep track of the orientation. This + should be done by the code for the Page setup dialog. + + 6) Get Page Size + + BPoint pageSize = mv->GetPageSize(); + + 7) Get Margins + + BRect margins = mv->GetMargins(); + + 8) Get Units + + uint32 units = mv->GetUnits(); + + where units is one of: + UNIT_INCH, 72 points/in + UNIT_CM, 28.346 points/cm + UNIT_POINT, 1 point/point +*/ + +#ifndef MARGIN_VIEW_H +#define MARGIN_VIEW_H + +#include +#include + +class MarginManager; + +// Messages that the MarginManager accepts +const uint32 TOP_MARGIN_CHANGED = 'tchg'; +const uint32 RIGHT_MARGIN_CHANGED = 'rchg'; +const uint32 LEFT_MARGIN_CHANGED = 'lchg'; +const uint32 BOTTOM_MARGIN_CHANGED = 'bchg'; +const uint32 MARGIN_CHANGED = 'mchg'; +const uint32 CHANGE_PAGE_SIZE = 'chps'; +const uint32 FLIP_PAGE = 'flip'; + +/** + * Class MarginView + */ +class MarginView : public BBox +{ +friend MarginManager; + +public: + // used to index unitFormat array + typedef enum { + UNIT_INCH = 0, + UNIT_CM, + UNIT_POINT + }; + +private: + + // GUI components + BTextControl *fTop, *fBottom, *fLeft, *fRight; + + // rect that holds the margins for the page as a set of point offsets + BRect fMargins; + + // the maximum size of the page view calculated from the view size + float fMaxPageWidth; + float fMaxPageHeight; + + // the actual size of the page in points + float fPageHeight; + float fPageWidth; + + // the units used to calculate the page size + uint32 fUnits; + float fUnitValue; + + // the size of the drawing area we have to draw the view in pixels + float fViewHeight; + float fViewWidth; + + // Calculate the view size for the margins + void CalculateViewSize(uint32 msg); + + // performed internally using the supplied popup + void SetUnits(uint32 unit); + + // performed internally using text fields + void SetMargin(BRect margin); + + // utility method + void AllowOnlyNumbers(BTextControl *textControl, int maxNum); + +public: + MarginView(BRect rect, + int32 pageWidth = 0, + int32 pageHeight = 0, + BRect margins = BRect(1, 1, 1, 1), // default to 1 inch + uint32 units = UNIT_INCH); + + ~MarginView(); + + /// all the GUI construction code + void ConstructGUI(); + + // page size + void SetPageSize(float pageWidth, float pageHeight); + // point.x = width, point.y = height + BPoint GetPageSize(void); + + // margin + BRect GetMargin(void); + + // orientation + // None, this state should be saved elsewhere in the page setup code + // and not here. See the FLIP_PAGE message to perform this function. + + // units + uint32 GetUnits(void); + + // will cause a recalc and redraw + void UpdateView(uint32 msg); + + // BeOS Hook methods + virtual void AttachedToWindow(void); + void Draw(BRect rect); + void FrameResized(float width, float height); + void MessageReceived(BMessage *msg); +}; + +#endif //MARGIN_VIEW_H diff --git a/src/add-ons/print/drivers/pdf/source/MessagePrinter.cpp b/src/add-ons/print/drivers/pdf/source/MessagePrinter.cpp new file mode 100644 index 0000000000..2e9e69ae65 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/MessagePrinter.cpp @@ -0,0 +1,173 @@ +/* + +MessagePrinter.cpp + +Copyright (c) 2001 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#include +#include + +#include "MessagePrinter.h" + +/** + * Print() + * + * @param BMessage* + * @return status_t, any result from the operation + */ +status_t MessagePrinter::Print(BMessage* msg) +{ + status_t status; + BFile file; + BPath settingsPath; + // char settingsPath[B_PATH_NAME_LENGTH]; + char *name; + uint32 type; + int32 count; + + // open a file to print message on the desktop + status = find_directory(B_DESKTOP_DIRECTORY, &settingsPath); + if (status != B_OK) { + (new BAlert("","find directory error", "Doh!"))->Go(); + return status; + } + + settingsPath.Append(msgFileName); + status = file.SetTo(settingsPath.Path(), B_WRITE_ONLY | B_CREATE_FILE); + if (status != B_OK) { + (new BAlert("","file write error", "Doh!"))->Go(); + return status; + } + + // print the contents of the message to file + for ( int32 i = 0; + msg->GetInfo(B_ANY_TYPE, i, &name, &type, &count) == B_OK; + i++ ) + { + BString out; + // count + out << i; + if (file.Write(out.String(), out.Length()) < 0) { + (new BAlert("","count write error", "Doh!"))->Go(); + return B_ERROR; + } + // name + out = " "; + out << name; + if (file.Write(out.String(), out.Length()) < 0) { + (new BAlert("","name write error", "Doh!"))->Go(); + return B_ERROR; + } + + // type + switch (type) { + case B_INT32_TYPE: + { + int32 v; + out = " B_INT32_TYPE "; + msg->FindInt32(name, 0, &v); + out << v << '\n'; + } + break; + case B_UINT32_TYPE: + { + int32 v; + out = " B_UINT32_TYPE "; + msg->FindInt32(name, 0, &v); + out << v << '\n'; + } + break; + case B_INT64_TYPE: + { + int64 v; + out = " B_INT64_TYPE "; + msg->FindInt64(name, 0, &v); + out << v << '\n'; + } + break; + case B_FLOAT_TYPE: + { + float f; + out = " B_FLOAT_TYPE "; + msg->FindFloat(name, 0, &f); + out << f << '\n'; + } + break; + case B_BOOL_TYPE: + { + bool b; + out = " B_BOOL_TYPE "; + msg->FindBool(name, 0, &b); + out << (int)b << '\n'; + } + break; + case B_MESSAGE_TYPE: + { + BMessage *m = new BMessage(); + MessagePrinter *mp = new MessagePrinter(name); + msg->FindMessage(name, m); + mp->Print(m); + out = " B_MESSAGE_TYPE \n"; + delete m; + delete mp; + } + break; + case B_RECT_TYPE: + { + BRect r; + out = " B_RECT_TYPE "; + msg->FindRect(name, 0, &r); + out << "{ " + << r.left <<" " + << r.top <<" " + << r.right <<" " + << r.bottom <<" " + << " }" + << '\n'; + } + break; + case B_STRING_TYPE: + { + BString s; + out = " B_STRING_TYPE "; + msg->FindString(name, 0, &s); + out << s.String() << '\n'; + } + break; + default: + out = " UNKNOWN TYPE \n"; + break; + } + if (file.Write(out.String(), out.Length()) < 0) { + (new BAlert("","value write error", "Doh!"))->Go(); + return B_ERROR; + } + } + return status; +} + diff --git a/src/add-ons/print/drivers/pdf/source/MessagePrinter.h b/src/add-ons/print/drivers/pdf/source/MessagePrinter.h new file mode 100644 index 0000000000..130b5d1905 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/MessagePrinter.h @@ -0,0 +1,59 @@ +/* + +MessagePrinter.h + +Copyright (c) 2001 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef MSG_PRINTER_H +#define MSG_PRINTER_H + +#include +#include +#include + +const char FILE_NAME[] = "MessageFile"; + +/** + * Class + */ +class MessagePrinter +{ +private: + BNode node; + status_t _err; + char msgFileName[B_FILE_NAME_LENGTH]; + +public: + MessagePrinter() { strcpy(msgFileName, FILE_NAME); } + MessagePrinter(const char *fileName) { strcpy(msgFileName, fileName); } + ~MessagePrinter() { } + + status_t Print(BMessage *msg); +}; + +#endif diff --git a/src/add-ons/print/drivers/pdf/source/Notes.txt b/src/add-ons/print/drivers/pdf/source/Notes.txt new file mode 100644 index 0000000000..dcce250abc --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/Notes.txt @@ -0,0 +1,59 @@ +Notes: + +1) Called after printer is created: + char* add_printer(char* printer_name); + +2) Called by print_server if app uses page setup settings before calling + ConfigPage(). + + BMessage* default_settings(BNode* printer); + + BNode is the spool dir where attributes exist + BMessage contains the attribute default settings + +3) Called by BPrintJob::ConfigPage() + + BMessage* config_page(BNode* printer, BMessage* settings); + + BMessage* settings is the current settings + returns the settings specified in the dialog + +4) Called by print_server to start printing + + BMessage* take_job(BFile* spool, BNode* printer, BMessage* msg); + +- there is always a config_page() before a config_job() +- if settings passed to config_job is empty the print_server will call + config_page() + +Path for settings: + 1) default_settings() should write the attributes to the BNode and return + them in the BMessage + 2) config_page() could be called with an empty settings BMessage, which + should then call default_settings()? + +- default_settings does not exist + +===================================================== +Simon 02/01/2002: +===================================================== +1) Added default_settings() to Driver.cpp to use PrinterSettings class that controls settings + +- accorting to the scheme above I have found no code that calls page setup before calling ConfigPage(), so the default_settings() function never gets called resulting in a badly formated message (has the wrong set of data fields we need) being sent to PageSetupWindow constructor. Therefore, on the council of Philippe, I have added a Validate() method to the PrinterSettings class that validates the structure of the message and adds constructs the message to be correct for PageSetupWindow. This means that PageSetupWindow will always get a good message, and I have taken out the code in the PageSetupWindow constructor to check for the presence of the data fields it needs. However, the result of the initial problem, that default_settings() is not called, resulted in my adding these Validate calls to both config_page() and config_job() functions, which really they should not be there... + +- what is really needed is a test app with a bunch of test harnesses to check all combination of app based printing scenarios, and also test for bad coding errors that an app may perform, rather than using StyleEdit and Gobe to test the driver. + +NOTE: depending on the app that causes config_page() to be called, the message will have different configurations of data fields. StyledEdit passes only a single field, while Gobe passes a bunch. The issue is that config_page() cannot simply call default_settings() in the case where the message does not have the data fields we want, since we will wipe them out with the new default one. So rather than calling default_settings() from config_page(), I just add the data fields we need with a call to PrinterSettings::ReadSettings(), or PrinterSettings::GetDefaults() if there are no previously saved settings. + +2) Code now does the following: + +a) Reads BNode to check if there is a previous BFS attibute called printer_settings that has the latest default settings + +b) If no attib printer_settings, then reads pdf_default_settings file in /home/config/settings for initial defaults. If pdf_default_settings not there, it uses hard coded values, writes the pdf_default_settings file and saves BMessage to spool BNode as a BFS attribute called printer_settings + +c) If pdf_default_settings are there it uses these values, then saves BMessage to spool BNode as a BFS attribute called printer_settings + +d) PageSetupWindow::UpdateSetupMessage() will call the PrinterSettings class to write the new settings created in the dialog to the spooler BNode attribute printer_settings + +3) Added a debug MessagePrinter class that prints the contents of a BMessage to a text file on the desktop with the name of the message as the name of the file. If there are BMessages in the BMessage it will print these too, but in seperate files. You can see the use of this class in the code commented out in Driver.cpp, which should be removed at some later time, and perhaps put in a printer testing app. + diff --git a/src/add-ons/print/drivers/pdf/source/PDFLinePathBuilder.cpp b/src/add-ons/print/drivers/pdf/source/PDFLinePathBuilder.cpp new file mode 100644 index 0000000000..de797d6b4b --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/PDFLinePathBuilder.cpp @@ -0,0 +1,65 @@ +/* + +PDFLinePathBuilder + +Copyright (c) 2002 OpenBeOS. + +Author: + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#include "PDFLinePathBuilder.h" + +PDFLinePathBuilder::PDFLinePathBuilder(SubPath *subPath, PDFWriter *writer) + : LinePathBuilder(subPath, writer->PenSize(), writer->LineCapMode(), writer->LineJoinMode(), writer->LineMiterLimit()) + , fWriter(writer) +{ +} + +void +PDFLinePathBuilder::MoveTo(BPoint p) +{ + PDF_moveto(Pdf(), tx(p.x), ty(p.y)); +} + +void +PDFLinePathBuilder::LineTo(BPoint p) +{ + PDF_lineto(Pdf(), tx(p.x), ty(p.y)); +} + +void +PDFLinePathBuilder::BezierTo(BPoint p[3]) +{ + PDF_curveto(Pdf(), + tx(p[0].x), ty(p[0].y), + tx(p[1].x), ty(p[1].y), + tx(p[2].x), ty(p[2].y)); +} + +void +PDFLinePathBuilder::ClosePath(void) +{ + PDF_closepath(Pdf()); +} + + diff --git a/src/add-ons/print/drivers/pdf/source/PDFLinePathBuilder.h b/src/add-ons/print/drivers/pdf/source/PDFLinePathBuilder.h new file mode 100644 index 0000000000..2be1e67bea --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/PDFLinePathBuilder.h @@ -0,0 +1,58 @@ +/* + +PDFLinePathBuilder + +Copyright (c) 2002 OpenBeOS. + +Author: + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef PDFLINE_PATH_BUILDER_H +#define PDFLINE_PATH_BUILDER_H + +#include "LinePathBuilder.h" +#include "PDFWriter.h" + +class PDFLinePathBuilder : public LinePathBuilder +{ + PDFWriter *fWriter; + + PDF *Pdf() const { return fWriter->fPdf; } + float tx(float x) const { return fWriter->tx(x); } + float ty(float y) const { return fWriter->ty(y); } + +protected: + void MoveTo(BPoint p); + void LineTo(BPoint p); + void BezierTo(BPoint p[3]); + void ClosePath(void); + +public: + cap_mode LineCapMode() const { return fWriter->fState->capMode; } + join_mode LineJoinMode() const { return fWriter->fState->joinMode; } + float LineMiterLimit() const { return fWriter->fState->miterLimit; } + + PDFLinePathBuilder(SubPath *subPath, PDFWriter *writer); +}; + +#endif diff --git a/src/add-ons/print/drivers/pdf/source/PDFText.cpp b/src/add-ons/print/drivers/pdf/source/PDFText.cpp new file mode 100644 index 0000000000..600d37e771 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/PDFText.cpp @@ -0,0 +1,561 @@ +/* + +PDF Writer printer driver. + +Copyright (c) 2001, 2002 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#include +#include +#include + +#include +#include +#include +#include + +#include "PDFWriter.h" +#include "Link.h" +#include "Bookmark.h" +#include "DrawShape.h" +#include "XReferences.h" +#include "Log.h" +#include "Report.h" +#include "pdflib.h" + +typedef struct +{ + uint16 from; + uint16 to; + int16 length; + uint16 *unicodes; +} unicode_to_encoding; + +typedef struct +{ + uint16 unicode; + uint16 cid; +} unicode_to_cid; + +typedef struct +{ + uint16 length; + unicode_to_cid *table; +} cid_table; + +#ifdef UNICODE5_FROM + #error check code! +#endif + +#define ELEMS(v, e) sizeof(v) / sizeof(e) + +// Adobe Glyph List +#include "enc_range.h" +#include "unicode0.h" +#include "unicode1.h" +#include "unicode2.h" +#include "unicode3.h" +#include "unicode4.h" + +static unicode_to_encoding encodings[] = +{ + {UNICODE0_FROM, UNICODE0_TO, ELEMS(unicode0, uint16), unicode0}, + {UNICODE1_FROM, UNICODE1_TO, ELEMS(unicode1, uint16), unicode1}, + {UNICODE2_FROM, UNICODE2_TO, ELEMS(unicode2, uint16), unicode2}, + {UNICODE3_FROM, UNICODE3_TO, ELEMS(unicode3, uint16), unicode3}, + {UNICODE4_FROM, UNICODE4_TO, ELEMS(unicode4, uint16), unicode4} +}; + +// unicode to cid +#include "japanese.h" +#include "gb1.h" +#include "cns1.h" +#include "korean.h" + + +static cid_table cid_tables[] = +{ + {ELEMS(japanese, unicode_to_cid), japanese}, + {ELEMS(CNS1, unicode_to_cid), CNS1}, + {ELEMS(GB1, unicode_to_cid), GB1}, + {ELEMS(korean, unicode_to_cid), korean} +}; + + +// -------------------------------------------------- +static bool +find_encoding(uint16 unicode, uint8 &encoding, uint16 &index) +{ + for (unsigned int i = 0; i < ELEMS(encodings, unicode_to_encoding); i++) { + if (encodings[i].from <= unicode && unicode <= encodings[i].to) { + int16 bottom = 0; + int16 top = encodings[i].length-1; + uint16* codes = encodings[i].unicodes; + while (top >= bottom) { + int16 m = (top + bottom) / 2; + if (unicode < codes[m]) { + top = m-1; + } else if (unicode > codes[m]) { + bottom = m+1; + } else { + index = m; + encoding = i; + return true; + } + } + return false; + } + } + return false; +} + + +// -------------------------------------------------- +static bool +find_in_cid_tables(uint16 unicode, font_encoding &encoding, uint16 &index, font_encoding* order) +{ + for (unsigned int i = 0; i < ELEMS(cid_tables, cid_table); i++) { + encoding = order[i]; + if (encoding == invalid_encoding) break; + int index = encoding - first_cjk_encoding; + int32 bottom = 0; + int32 top = cid_tables[index].length-1; + unicode_to_cid *table = cid_tables[index].table; + while (top >= bottom) { + int32 m = (top + bottom) / 2; + if (unicode < table[m].unicode) { + top = m-1; + } else if (unicode > table[m].unicode) { + bottom = m+1; + } else { + index = table[m].cid; + return true; + } + } + } + return false; +} + + +// -------------------------------------------------- +void +PDFWriter::GetFontName(BFont *font, char *fontname, bool &embed, font_encoding encoding) +{ + font_family family; + font_style style; + + font->GetFamilyAndStyle(&family, &style); + + strcat(strcat(strcpy(fontname, family), "-"), style); + + switch (encoding) { + case japanese_encoding: + strcpy(fontname, "HeiseiMin-W3"); return; + case chinese_cns1_encoding: + strcpy(fontname, "MHei-Medium"); return; + case chinese_gb1_encoding: + strcpy(fontname, "STSong-Light"); return; + case korean_encoding: + strcpy(fontname, "HYGoThic-Medium"); return; + return; + default:; + } +} + + +static const char* encoding_names[] = +{ + "macroman", + // TrueType + "ttenc0", + "ttenc1", + "ttenc2", + "ttenc3", + "ttenc4", + // Type 1 + "t1enc0", + "t1enc1", + "t1enc2", + "t1enc3", + "t1enc4", + // CJK + "UniJIS-UCS2-H", + "UniCNS-UCS2-H", + "UniGB-UCS2-H", + "UniKS-UCS2-H" +}; + + +// -------------------------------------------------- +int +PDFWriter::FindFont(char* fontName, bool embed, font_encoding encoding) +{ + static Font* cache = NULL; + if (cache && cache->encoding == encoding && strcmp(cache->name.String(), fontName) == 0) + return cache->font; + + REPORT(kDebug, fPage, "FindFont %s", fontName); + Font *f = NULL; + const int n = fFontCache.CountItems(); + for (int i = 0; i < n; i++) { + f = fFontCache.ItemAt(i); + if (f->encoding == encoding && strcmp(f->name.String(), fontName) == 0) { + cache = f; + return f->font; + } + } + + if (embed) embed = EmbedFont(fontName); + + REPORT(kDebug, fPage, "Create new font"); + int font = PDF_findfont(fPdf, fontName, encoding_names[encoding], embed); + if (font != -1) { + REPORT(kDebug, fPage, "font created"); + cache = new Font(fontName, font, encoding); + fFontCache.AddItem(cache); + } + return font; +} + + +// -------------------------------------------------- +void +PDFWriter::ToUtf8(uint32 encoding, const char *string, BString &utf8) +{ + int32 len = strlen(string); + int32 srcLen = len, destLen = 255; + int32 state = 0; + char buffer[256]; + int32 srcStart = 0; + + do { + convert_to_utf8(encoding, &string[srcStart], &srcLen, buffer, &destLen, &state); + srcStart += srcLen; + len -= srcLen; + srcLen = len; + + utf8.Append(buffer, destLen); + destLen = 255; + } while (len > 0); +}; + + +// -------------------------------------------------- +void +PDFWriter::ToUnicode(const char *string, BString &unicode) +{ + int32 len = strlen(string); + int32 srcLen = len, destLen = 255; + int32 state = 0; + char buffer[256]; + int32 srcStart = 0; + int i = 0; + + unicode = ""; + if (len == 0) return; + + do { + convert_from_utf8(B_UNICODE_CONVERSION, &string[srcStart], &srcLen, buffer, &destLen, &state); + srcStart += srcLen; + len -= srcLen; + srcLen = len; + + char *b = unicode.LockBuffer(i + destLen); + memcpy(&b[i], buffer, destLen); + unicode.UnlockBuffer(i + destLen); + i += destLen; + destLen = 255; + } while (len > 0); +} + + +// -------------------------------------------------- +void +PDFWriter::ToPDFUnicode(const char *string, BString &unicode) +{ + // PDFlib requires BOM at begin and two 0 at end of string + char marker[3] = { 0xfe, 0xff, 0}; // byte order marker + BString s; + ToUnicode(string, s); + unicode << marker; + int32 len = s.Length()+2; + char* buf = unicode.LockBuffer(len + 2); // reserve space for two additional '\0' + memcpy(&buf[2], s.String(), s.Length()); + buf[len] = buf[len+1] = 0; + unicode.UnlockBuffer(len + 2); +} + + +// -------------------------------------------------- +uint16 +PDFWriter::CodePointSize(const char* s) +{ + uint16 i = 1; + for (s++; !BeginsChar(*s); s++) i++; + return i; +} + + +void PDFWriter::RecordDests(const char* s) { + ::RecordDests record(fXRefDests, fPage); + fXRefs->Matches(s, &record, true); +} + + + +// -------------------------------------------------- +void +PDFWriter::DrawChar(uint16 unicode, const char* utf8, int16 size) +{ + // try to convert from utf8 to MacRoman encoding schema... + int32 srcLen = size; + int32 destLen = 1; + char dest[2] = "\0"; + int32 state = 0; + bool embed = true; + font_encoding encoding = macroman_encoding; + + if (convert_from_utf8(B_MAC_ROMAN_CONVERSION, utf8, &srcLen, dest, &destLen, &state, 0) != B_OK || dest[0] == 0 ) { + // could not convert to MacRoman + uint8 enc; + uint16 index; + font_encoding fenc; + + // is code point in the Adobe Glyph List? + if (find_encoding(unicode, enc, index)) { + // LOG((fLog, "encoding for %x -> %d %d\n", unicode, (int)enc, (int)index)); + // use one of the user defined encodings + if (fState->beFont.FileFormat() == B_TRUETYPE_WINDOWS) { + encoding = font_encoding(enc + tt_encoding0); + } else { + encoding = font_encoding(enc + t1_encoding0); + } + *dest = index; + } else if (find_in_cid_tables(unicode, fenc, index, fFontSearchOrder)) { + // LOG((fLog, "cid table %d index = %d\n", (int)enc, (int)index)); + dest[0] = unicode / 256; + dest[1] = unicode % 256; + destLen = 2; + encoding = fenc; + embed = false; + } else { + // LOG((fLog, "encoding for %x not found!\n", unicode)); + *dest = 0; // paint a box (is 0 a box in MacRoman) or + return; // simply skip character + } + } + // else LOG((fLog, "macroman srcLen=%d destLen=%d dest= %d %d!\n", srcLen, destLen, (int)dest[0], (int)dest[1])); + + char fontName[B_FONT_FAMILY_LENGTH+B_FONT_STYLE_LENGTH+1]; + int font; + + GetFontName(&fState->beFont, fontName, embed, encoding); + font = FindFont(fontName, embed, encoding); + if (font < 0) { + REPORT(kWarning, fPage, "**** PDF_findfont(%s) failed, back to default font", fontName); + font = PDF_findfont(fPdf, "Helvetica", "macroman", 0); + } + + fState->font = font; + + uint16 face = fState->beFont.Face(); + PDF_set_parameter(fPdf, "underline", (face & B_UNDERSCORE_FACE) != 0 ? "true" : "false"); + PDF_set_parameter(fPdf, "strikeout", (face & B_STRIKEOUT_FACE) != 0 ? "true" : "false"); + PDF_set_value(fPdf, "textrendering", (face & B_OUTLINED_FACE) != 0 ? 1 : 0); + + PDF_setfont(fPdf, fState->font, scale(fState->beFont.Size())); + + const float x = tx(fState->penX); + const float y = ty(fState->penY); + const float rotation = fState->beFont.Rotation(); + const bool rotate = rotation != 0.0; + + if (rotate) { + PDF_save(fPdf); + PDF_translate(fPdf, x, y); + PDF_rotate(fPdf, rotation); + PDF_set_text_pos(fPdf, 0, 0); + } else + PDF_set_text_pos(fPdf, x, y); + + PDF_show2(fPdf, dest, destLen); + + if (rotate) { + PDF_restore(fPdf); + } +} + + +// -------------------------------------------------- +void +PDFWriter::ClipChar(BFont* font, const char* unicode, const char* utf8, int16 size, float width) +{ + BShape glyph; + bool hasGlyph[1]; + font->GetHasGlyphs(utf8, 1, hasGlyph); + if (hasGlyph[0]) { + BShape *glyphs[1]; + glyphs[0] = &glyph; + font->GetGlyphShapes(utf8, 1, glyphs); + } else { + REPORT(kWarning, fPage, "glyph for %*.*s not found!", size, size, utf8); + // create a rectangle instead + font_height height; + fState->beFont.GetHeight(&height); + BRect r(0, 0, width, height.ascent); + float w = r.Width() < r.Height() ? r.Width()*0.1 : r.Height()*0.1; + BRect o = r; o.InsetBy(w, w); + w *= 2.0; + BRect i = r; i.InsetBy(w, w); + + o.OffsetBy(0, -height.ascent); + i.OffsetBy(0, -height.ascent); + + glyph.MoveTo(BPoint(o.left, o.top)); + glyph.LineTo(BPoint(o.right, o.top)); + glyph.LineTo(BPoint(o.right, o.bottom)); + glyph.LineTo(BPoint(o.left, o.bottom)); + glyph.Close(); + + glyph.MoveTo(BPoint(i.left, i.top)); + glyph.LineTo(BPoint(i.left, i.bottom)); + glyph.LineTo(BPoint(i.right, i.bottom)); + glyph.LineTo(BPoint(i.right, i.top)); + glyph.Close(); + } + + BPoint p(fState->penX, fState->penY); + PushInternalState(); SetOrigin(p); + { + DrawShape iterator(this, false); + iterator.Iterate(&glyph); + } + PopInternalState(); +} + +// -------------------------------------------------- +void +PDFWriter::DrawString(char *string, float escapement_nospace, float escapement_space) +{ + REPORT(kDebug, fPage, "DrawString string=\"%s\", escapement_nospace=%f, escapement_space=%f, at %f, %f", \ + string, escapement_nospace, escapement_space, fState->penX, fState->penY); + + if (IsDrawing()) { + // text color is always the high color and not the pattern! + SetColor(fState->foregroundColor); + } + // convert string to UTF8 + BString utf8; + if (fState->beFont.Encoding() == B_UNICODE_UTF8) { + utf8 = string; + } else { + ToUtf8(fState->beFont.Encoding()-1, string, utf8); + } + + // convert string in UTF8 to unicode UCS2 + BString unicode; + ToUnicode(utf8.String(), unicode); + // need font object to calculate width of utf8 code point + BFont font = fState->beFont; + font.SetEncoding(B_UNICODE_UTF8); + // constants to calculate position of next character + const double rotation = DEGREE2RAD(fState->beFont.Rotation()); + const bool rotate = rotation != 0.0; + const double cos1 = rotate ? cos(rotation) : 1; + const double sin1 = rotate ? -sin(rotation) : 0; + + BPoint start(fState->penX, fState->penY); + + // If !MakesPDF() all the effort below just for the bounding box! + // draw each character + const char *c = utf8.String(); + const unsigned char *u = (unsigned char*)unicode.String(); + for (int i = 0; i < unicode.Length(); i += 2) { + int s = CodePointSize((char*)c); + + float w = font.StringWidth(c, s); + + if (MakesPDF()) { + if (IsClipping()) { + ClipChar(&font, (char*)u, c, s, w); + } else { + DrawChar(u[0]*256+u[1], c, s); + } + } + + // position of next character + if (*(unsigned char*)c <= 0x20) { // should test if c is a white-space! + w += escapement_space; + } else { + w += escapement_nospace; + } + + fState->penX += w * cos1; + fState->penY += w * sin1; + + // next character + c += s; u += 2; + } + + // text line processing (for non rotated text only!) + BPoint end(fState->penX, fState->penY); + BRect bounds; + font_height height; + + font.GetHeight(&height); + + bounds.left = start.x; + bounds.right = end.x; + bounds.top = start.y - height.ascent; + bounds.bottom = end.y + height.descent; + + TextSegment* segment = new TextSegment( + utf8.String(), start, + escapement_space, escapement_nospace, + &bounds, &font, pdfSystem()); + + fTextLine.Add(segment); +} + + +// -------------------------------------------------- +bool +PDFWriter::EmbedFont(const char* name) +{ + static FontFile* cache = NULL; + if (cache && strcmp(cache->Name(), name) == 0) return cache->Embed(); + + const int n = fFonts->Length(); + for (int i = 0; i < n; i++) { + FontFile* f = fFonts->At(i); + if (strcmp(f->Name(), name) == 0) { + cache = f; + return f->Embed(); // Size() < fEmbedMaxFontSize; + } + } + return false; +} diff --git a/src/add-ons/print/drivers/pdf/source/PDFWriter.cpp b/src/add-ons/print/drivers/pdf/source/PDFWriter.cpp new file mode 100644 index 0000000000..80e3e8dc85 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/PDFWriter.cpp @@ -0,0 +1,2182 @@ +/* + + PDFWriter.cpp + +Copyright (c) 2001, 2002 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Based on: + - gdevbjc.c from Aladdin GhostScript + - LMDriver.cpp from Ryan Lockhart Lexmark 5/7xxxx BeOS driver + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#include +#include // for memset() +#include +#include + +#include +#include +#include +#include + +#include "PDFWriter.h" +#include "Bezier.h" +#include "LinePathBuilder.h" +#include "DrawShape.h" +#include "Log.h" +#include "pdflib.h" +#include "Bookmark.h" +#include "XReferences.h" +#include "Report.h" + +// Constructor & destructor +// ------------------------ + +PDFWriter::PDFWriter() + : PrinterDriver() + , fTextLine(this) +{ + fFontSearchOrder[0] = japanese_encoding; + fFontSearchOrder[1] = chinese_cns1_encoding; + fFontSearchOrder[2] = chinese_gb1_encoding; + fFontSearchOrder[3] = korean_encoding; + + fPage = 0; + fEmbedMaxFontSize = 250 * 1024; + fScreen = new BScreen(); + fFonts = NULL; + fBookmark = new Bookmark(this); + fXRefs = new XRefDefs(); + fXRefDests = NULL; +} + + +// -------------------------------------------------- +PDFWriter::~PDFWriter() +{ + if (Transport()) + CloseTransport(); + + delete fScreen; + delete fFonts; + delete fBookmark; + delete fXRefs; + delete fXRefDests; +} + + +#ifdef CODEWARRIOR + #pragma mark [Public methods] +#endif + +// Public methods +// -------------- + +// -------------------------------------------------- +status_t +PDFWriter::PrintPage(int32 pageNumber, int32 pageCount) +{ + status_t status; + BRect r; + uint32 pictureCount; + BRect paperRect; + BRect printRect; + BRect *picRects; + BPoint *picPoints; + BRegion *picRegion; + BPicture **pictures; + uint32 i; + int32 orientation; + + status = B_OK; + + fPage = pageNumber; + + if (pageNumber == 1) { + if (MakesPattern()) + REPORT(kDebug, fPage, ">>>>> Collecting patterns..."); + else if (MakesPDF()) + REPORT(kDebug, fPage, ">>>>> Generating PDF..."); + } + + paperRect = JobMsg()->FindRect("paper_rect"); + printRect = JobMsg()->FindRect("printable_rect"); + if (B_OK != JobMsg()->FindInt32("orientation", &orientation)) orientation = 0; + if (orientation == 1) + printRect.Set(printRect.top, printRect.left, + printRect.bottom, printRect.right); + + JobFile()->Read(&pictureCount, sizeof(uint32)); + + pictures = (BPicture **) malloc(pictureCount * sizeof(BPicture *)); + picRects = (BRect *) malloc(pictureCount * sizeof(BRect)); + picPoints = (BPoint *) malloc(pictureCount * sizeof(BPoint)); + picRegion = new BRegion(); + + for (i = 0; i < pictureCount; i++) { + JobFile()->Seek(40 + sizeof(off_t), SEEK_CUR); + JobFile()->Read(&picPoints[i], sizeof(BPoint)); + JobFile()->Read(&picRects[i], sizeof(BRect)); + pictures[i] = new BPicture(); + pictures[i]->Unflatten(JobFile()); + picRegion->Include(picRects[i]); + } + + r = picRegion->Frame(); + delete picRegion; + + BeginPage(paperRect, printRect); + for (i = 0; i < pictureCount; i++) { + Iterate(pictures[i]); + delete pictures[i]; + } + EndPage(); + + free(pictures); + free(picRects); + free(picPoints); + + return status; +} + + +// -------------------------------------------------- +status_t +PDFWriter::BeginJob() +{ + fLog = fopen("/tmp/pdf_writer.log", "w"); + + PDF_boot(); + + fPdf = PDF_new2(_ErrorHandler, NULL, NULL, NULL, this); // set *this* as pdf cookie + if ( fPdf == NULL ) + return B_ERROR; + + // load font embedding settings + fFonts = new Fonts(); + fFonts->CollectFonts(); + BMessage fonts; + if (B_OK == JobMsg()->FindMessage("fonts", &fonts)) { + fFonts->SetTo(&fonts); + } + + // set font search order + int j = 0; + font_encoding enc; + bool active; + + for (int i = 0; j < no_of_cjk_encodings && fFonts->GetCJKOrder(i, enc, active); i ++) { + if (active) fFontSearchOrder[j++] = enc; + } + for (; j < no_of_cjk_encodings; j ++) { + fFontSearchOrder[j] = invalid_encoding; + } + + return InitWriter(); +} + + +// -------------------------------------------------- +status_t +PDFWriter::EndJob() +{ +#ifdef DEBUG + Report* r = Report::Instance(); + int32 n = r->CountItems(); + fprintf(fLog, "Report:\n"); + fprintf(fLog, "=======\n"); + if (n == 0) { + fprintf(fLog, "\n"); + } + for (int32 i = 0; i < n; i++) { + ReportRecord* rr = r->ItemAt(i); + switch (rr->Kind()) { + case kInfo: fprintf(fLog, "Info"); break; + case kWarning: fprintf(fLog, "Warning"); break; + case kError: fprintf(fLog, "Error"); break; + case kDebug: fprintf(fLog, "Debug"); break; + } + fprintf(fLog, " %s", rr->Label()); + if (rr->Page() > 0) fprintf(fLog, " (Page %d)", (int)rr->Page()); + fprintf(fLog, ": %s\n", rr->Desc()); + } +#endif + + PDF_close(fPdf); + REPORT(kDebug, 0, ">>>> PDF_close"); + + PDF_delete(fPdf); + PDF_shutdown(); + + fclose(fLog); + return B_OK; +} + + +// -------------------------------------------------- +void +PDFWriter::SetAttribute(const char* name, const char* value) { + BFile* file = dynamic_cast(Transport()); + if (file) { + + } +} + + +// -------------------------------------------------- +status_t +PDFWriter::InitWriter() +{ + char buffer[512]; + BString s; + + const char * compatibility; + if (JobMsg()->FindString("pdf_compatibility", &compatibility) == B_OK) { + PDF_set_parameter(fPdf, "compatibility", compatibility); + } + + REPORT(kDebug, 0, ">>>> PDF_open_mem"); + PDF_open_mem(fPdf, _WriteData); // use callback to stream PDF document data to printer transport + + PDF_set_parameter(fPdf, "flush", "heavy"); + + // set document info + BMessage doc; + bool setTitle = true; + bool setCreator = true; + if (JobMsg()->FindMessage("doc_info", &doc) == B_OK) { +#ifndef B_BEOS_VERSION_DANO + char *name; +#else + const char *name; +#endif + uint32 type; + int32 count; + for (int32 i = 0; doc.GetInfo(B_STRING_TYPE, i, &name, &type, &count) != B_BAD_INDEX; i++) { + if (type == B_STRING_TYPE) { + BString value; + if (doc.FindString(name, &value) == B_OK && value != "") { + SetAttribute(name, value.String()); + BString s; + ToPDFUnicode(value.String(), s); + PDF_set_info(fPdf, name, s.String()); + } + } + } + BString s; + if (doc.FindString("Title", &s) == B_OK && s != "") setTitle = false; + if (doc.FindString("Creator", &s) == B_OK && s != "") setCreator = false; + } + + // find job title + if (setTitle && JobFile()->ReadAttr("_spool/Description", B_STRING_TYPE, 0, buffer, sizeof(buffer))) { + SetAttribute("Title", buffer); + ToPDFUnicode(buffer, s); PDF_set_info(fPdf, "Title", s.String()); + } + + // find job creator + if (setCreator && JobFile()->ReadAttr("_spool/MimeType", B_STRING_TYPE, 0, buffer, sizeof(buffer))) { + SetAttribute("Creator", buffer); + ToPDFUnicode(buffer, s); PDF_set_info(fPdf, "Creator", s.String()); + } + + int32 compression; + if (JobMsg()->FindInt32("pdf_compression", &compression) == B_OK) { + PDF_set_value(fPdf, "compress", compression); + } + + // PDF_set_parameter(fPdf, "warning", "false"); + + PDF_set_parameter(fPdf, "fontwarning", "false"); + // PDF_set_parameter(fPdf, "native-unicode", "true"); + + REPORT(kDebug, 0, "Start of fonts declaration:"); + + PDF_set_parameter(fPdf, "Encoding", "t1enc0==/boot/home/config/settings/PDF Writer/t1enc0.enc"); + PDF_set_parameter(fPdf, "Encoding", "t1enc1==/boot/home/config/settings/PDF Writer/t1enc1.enc"); + PDF_set_parameter(fPdf, "Encoding", "t1enc2==/boot/home/config/settings/PDF Writer/t1enc2.enc"); + PDF_set_parameter(fPdf, "Encoding", "t1enc3==/boot/home/config/settings/PDF Writer/t1enc3.enc"); + PDF_set_parameter(fPdf, "Encoding", "t1enc4==/boot/home/config/settings/PDF Writer/t1enc4.enc"); + + PDF_set_parameter(fPdf, "Encoding", "ttenc0==/boot/home/config/settings/PDF Writer/ttenc0.cpg"); + PDF_set_parameter(fPdf, "Encoding", "ttenc1==/boot/home/config/settings/PDF Writer/ttenc1.cpg"); + PDF_set_parameter(fPdf, "Encoding", "ttenc2==/boot/home/config/settings/PDF Writer/ttenc2.cpg"); + PDF_set_parameter(fPdf, "Encoding", "ttenc3==/boot/home/config/settings/PDF Writer/ttenc3.cpg"); + PDF_set_parameter(fPdf, "Encoding", "ttenc4==/boot/home/config/settings/PDF Writer/ttenc4.cpg"); + + DeclareFonts(); + + REPORT(kDebug, fPage, "End of fonts declaration."); + + // Links + float width; + if (JobMsg()->FindFloat("link_border_width", &width) != B_OK) { + width = 1; + } + PDF_set_border_style(fPdf, "solid", width); + + if (JobMsg()->FindBool("create_web_links", &fCreateWebLinks) != B_OK) { + fCreateWebLinks = false; + } + + // Bookmarks + if (JobMsg()->FindBool("create_bookmarks", &fCreateBookmarks) != B_OK) { + fCreateBookmarks = false; + } + + if (fCreateBookmarks) { + BString name; + if (JobMsg()->FindString("bookmark_definition_file", &name) == B_OK && LoadBookmarkDefinitions(name.String())) { + } else { + fCreateBookmarks = false; + } + } + + // Cross References + if (JobMsg()->FindBool("create_xrefs", &fCreateXRefs) != B_OK) { + fCreateXRefs = false; + } + + if (fCreateXRefs) { + BString name; + if (JobMsg()->FindString("xrefs_file", &name) == B_OK && LoadXRefsDefinitions(name.String())) { + } else { + REPORT(kError, 0, "Could not read xrefs file!"); + fCreateXRefs = false; + } + } + + fState = NULL; + fStateDepth = 0; + + return B_OK; +} + + +// -------------------------------------------------- +status_t +PDFWriter::DeclareFonts() +{ + char buffer[1024]; + char *parameter_name; + + for (int i = 0; i < fFonts->Length(); i++) { + FontFile* f = fFonts->At(i); +// LOG((fLog, "path= %s\n", f->Path())); + if (f->Type() == true_type_type) { + parameter_name = "FontOutline"; + } else { // f->Type() == type1_type + if (strstr(f->Path(), ".afm")) + parameter_name = "FontAFM"; + else if (strstr(f->Path(), ".pfm")) + parameter_name = "FontPFM"; + else // should not reach here! + continue; + } +#ifndef __POWERPC__ + snprintf(buffer, sizeof(buffer), "%s==%s", f->Name(), f->Path()); +#else + sprintf(buffer, "%s==%s", f->Name(), f->Path()); +#endif +// LOG((fLog, "%s: %s\n", parameter_name, buffer)); + + PDF_set_parameter(fPdf, parameter_name, buffer); + } + return B_OK; +} + +bool +PDFWriter::LoadBookmarkDefinitions(const char* name) +{ + // TODO: use B_USER_SETTINGS_DIRECTORY instead of hard coded constant + BString path("/boot/home/config/settings/PDF Writer/bookmarks/"); + path.Append(name); + + return fBookmark->Read(path.String()); +} + + +bool +PDFWriter::LoadXRefsDefinitions(const char* name) +{ + // TODO: use B_USER_SETTINGS_DIRECTORY instead of hard coded constant + BString path("/boot/home/config/settings/PDF Writer/xrefs/"); + path.Append(name); + + if (fXRefs->Read(path.String())) { + fXRefDests = new XRefDests(fXRefs->Count()); + return true; + } + return false; +} + + +// -------------------------------------------------- +status_t +PDFWriter::BeginPage(BRect paperRect, BRect printRect) +{ + float width = paperRect.Width() < 10 ? a4_width : paperRect.Width(); + float height = paperRect.Height() < 10 ? a4_height : paperRect.Height(); + + fMode = kDrawingMode; + + ASSERT(fState == NULL); + fState = new State(height, printRect.left, printRect.top); + + if (MakesPDF()) + PDF_begin_page(fPdf, width, height); + + REPORT(kDebug, fPage, ">>>> PDF_begin_page [%f, %f]", width, height); + + if (MakesPDF()) + PDF_initgraphics(fPdf); + + fState->penX = 0; + fState->penY = 0; + + // XXX should we clip to the printRect here? + + PushState(); // so that fState->prev != NULL + + return B_OK; +} + + +// -------------------------------------------------- +status_t +PDFWriter::EndPage() +{ + fTextLine.Flush(); + if (fCreateBookmarks) fBookmark->CreateBookmarks(); + + while (fState->prev != NULL) PopState(); + + if (MakesPDF()) + PDF_end_page(fPdf); + REPORT(kDebug, fPage, ">>>> PDF_end_page"); + + delete fState; fState = NULL; + + return B_OK; +} + + +#ifdef CODEWARRIOR + #pragma mark [PDFlib callbacks] +#endif + +// -------------------------------------------------- +size_t +PDFWriter::WriteData(void *data, size_t size) +{ + REPORT(kDebug, fPage, ">>>> WriteData %p, %ld", data, size); + + return Transport()->Write(data, size); +} + + +// -------------------------------------------------- +void +PDFWriter::ErrorHandler(int type, const char *msg) +{ + REPORT(kError, fPage, "PDFlib %d: %s", type, msg); +} + +#ifdef CODEWARRIOR + #pragma mark [Generic drawing support routines] +#endif + + +// -------------------------------------------------- +void +PDFWriter::PushInternalState() +{ + REPORT(kDebug, fPage, "PushInternalState"); + fState = new State(fState); fStateDepth ++; +} + + +// -------------------------------------------------- +bool +PDFWriter::PopInternalState() +{ + REPORT(kDebug, fPage, "PopInternalState"); + if (fStateDepth != 0) { + State* s = fState; fStateDepth --; + fState = fState->prev; + delete s; +// LOG((fLog, "height = %f x0 = %f y0 = %f", pdfSystem->Height(), pdfSystem->Origin().x, pdfSystem.Origin().y)); + return true; + } else { + REPORT(kDebug, fPage, "State stack underflow!"); + return false; + } +} + + +// -------------------------------------------------- +void +PDFWriter::SetColor(rgb_color color) +{ + if (!MakesPDF()) return; + if (fState->currentColor.red != color.red || + fState->currentColor.blue != color.blue || + fState->currentColor.green != color.green || + fState->currentColor.alpha != color.alpha) { + fState->currentColor = color; + float red = color.red / 255.0; + float green = color.green / 255.0; + float blue = color.blue / 255.0; + PDF_setcolor(fPdf, "both", "rgb", red, green, blue, 0.0); + } +} + + +// -------------------------------------------------- +int +PDFWriter::FindPattern() +{ + // TODO: use hashtable instead of BList for fPatterns + const int n = fPatterns.CountItems(); + for (int i = 0; i < n; i ++) { + Pattern* p = fPatterns.ItemAt(i); + if (p->Matches(fState->pattern, fState->backgroundColor, fState->foregroundColor)) return p->patternId; + } + return -1; +} + + +// -------------------------------------------------- +void +PDFWriter::CreatePattern() +{ + REPORT(kDebug, fPage, "CreatePattern"); + BBitmap bm(BRect(0, 0, 7, 7), B_RGBA32); + + uint8* data = (uint8*)fState->pattern.data; + rgb_color h = fState->foregroundColor; + rgb_color l = fState->backgroundColor; + if (h.alpha < 128) { + h.red = h.green = h.blue = 255; + } + if (l.alpha < 128) { + l.red = l.green = l.blue = 255; + } + + uint8* row = (uint8*)bm.Bits(); + for (int8 y = 0; y <= 7; y ++, data ++) { + uint8 d = *data; + uint8* b = row; row += bm.BytesPerRow(); + for (int8 x = 0; x <= 7; x ++, d >>= 1, b += 4) { + if (d & 1 == 1) { + b[2] = h.red; //fState->foregroundColor.red; + b[1] = h.green; //fState->foregroundColor.green; + b[0] = h.blue; //fState->foregroundColor.blue; + b[3] = h.alpha; //fState->foregroundColor.alpha; + } else { + b[2] = l.red; //fState->backgroundColor.red; + b[1] = l.green; //fState->backgroundColor.green; + b[0] = l.blue; //fState->backgroundColor.blue; + b[3] = l.alpha; //fState->backgroundColor.alpha; + } + } + } + + int mask, image; + + if (!GetImages(bm.Bounds(), 8, 8, bm.BytesPerRow(), bm.ColorSpace(), 0, bm.Bits(), &mask, &image)) { + return; + } + + int pattern = PDF_begin_pattern(fPdf, 8, 8, 8, 8, 1); + if (pattern == -1) { + REPORT(kError, fPage, "CreatePattern could not create pattern"); + PDF_close_image(fPdf, image); + if (mask != -1) PDF_close_image(fPdf, mask); + return; + } + PDF_setcolor(fPdf, "both", "rgb", 0, 0, 1, 0); + PDF_place_image(fPdf, image, 0, 0, 1); + PDF_end_pattern(fPdf); + PDF_close_image(fPdf, image); + if (mask != -1) PDF_close_image(fPdf, mask); + + Pattern* p = new Pattern(fState->pattern, fState->backgroundColor, fState->foregroundColor, pattern); + fPatterns.AddItem(p); +} + + +// -------------------------------------------------- +void +PDFWriter::SetPattern() +{ +#if PATTERN_SUPPORT + REPORT(kDebug, fPage, "SetPattern (bitmap version)"); + if (MakesPattern()) { + if (FindPattern() == -1) CreatePattern(); + } else { + int pattern = FindPattern(); + if (pattern != -1) { + PDF_setcolor(fPdf, "both", "pattern", pattern, 0, 0, 0); + } else { + // TODO: fall back to another method + REPORT(kError, fPage, "pattern missing!"); + } + } +#else + REPORT(kDebug, fPage, "SetPattern (color version)"); + if (IsSame(fState->pattern, B_MIXED_COLORS)) { + rgb_color mixed; // approximate mixed colors + mixed.red = (fState->foregroundColor.red + fState->backgroundColor.red) / 2; + mixed.green = (fState->foregroundColor.green + fState->backgroundColor.green) / 2; + mixed.blue = (fState->foregroundColor.blue + fState->backgroundColor.blue) / 2; + mixed.alpha = (fState->foregroundColor.alpha + fState->backgroundColor.alpha) / 2; + SetColor(mixed); + } else { + SetColor(fState->foregroundColor); + } +#endif +} + + +// -------------------------------------------------- +void +PDFWriter::StrokeOrClip() +{ + if (IsDrawing()) { + PDF_stroke(fPdf); + } else { + REPORT(kError, fPage, "Clipping not implemented for this primitive!!!"); + PDF_closepath(fPdf); + } +} + + +// -------------------------------------------------- +void +PDFWriter::FillOrClip() +{ + if (IsDrawing()) { + PDF_fill(fPdf); + } else { + PDF_closepath(fPdf); + } +} + + +// -------------------------------------------------- +void +PDFWriter::Paint(bool stroke) +{ + if (stroke) { + StrokeOrClip(); + } else { + FillOrClip(); + } +} + + +// -------------------------------------------------- +bool +PDFWriter::IsSame(const pattern &p1, const pattern &p2) +{ + char *a = (char*)p1.data; + char *b = (char*)p2.data; + return strncmp(a, b, 8) == 0; +} + + +// -------------------------------------------------- +bool +PDFWriter::IsSame(const rgb_color &c1, const rgb_color &c2) +{ + char *a = (char*)&c1; + char *b = (char*)&c1; + return strncmp(a, b, sizeof(rgb_color)) == 0; +} + + +// -------------------------------------------------- +void +PDFWriter::SetColor() +{ + if (IsSame(fState->pattern, B_SOLID_HIGH)) { + SetColor(fState->foregroundColor); + } else if (IsSame(fState->pattern, B_SOLID_LOW)) { + SetColor(fState->backgroundColor); + } else { + SetPattern(); + } +} + + +#ifdef CODEWARRIOR + #pragma mark [Image drawing support routines] +#endif + + +// -------------------------------------------------- +int32 +PDFWriter::BytesPerPixel(int32 pixelFormat) +{ + switch (pixelFormat) { + case B_RGB32: // fall through + case B_RGB32_BIG: // fall through + case B_RGBA32: // fall through + case B_RGBA32_BIG: return 4; + + case B_RGB24_BIG: // fall through + case B_RGB24: return 3; + + case B_RGB16: // fall through + case B_RGB16_BIG: // fall through + case B_RGB15: // fall through + case B_RGB15_BIG: // fall through + case B_RGBA15: // fall through + case B_RGBA15_BIG: return 2; + + case B_GRAY8: // fall through + case B_CMAP8: return 1; + case B_GRAY1: return 0; + default: return -1; + } +} + + +// -------------------------------------------------- +bool +PDFWriter::NeedsAlphaCheck(int32 pixelFormat) +{ + switch (pixelFormat) { + case B_RGB32: // fall through + case B_RGB32_BIG: // fall through + case B_RGBA32: // fall through + case B_RGBA32_BIG: // fall through +// case B_RGB24: // fall through +// case B_RGB24_BIG: // fall through +// case B_RGB16: // fall through +// case B_RGB16_BIG: // fall through + case B_RGB15: // fall through + case B_RGB15_BIG: // fall through + case B_RGBA15: // fall through + case B_RGBA15_BIG: // fall through + case B_CMAP8: return true; + default: return false; + } +} + + +// -------------------------------------------------- +bool +PDFWriter::IsTransparentRGB32(uint8* in) +{ + return *((uint32*)in) == B_TRANSPARENT_MAGIC_RGBA32; +} + + +// -------------------------------------------------- +bool +PDFWriter::IsTransparentRGB32_BIG(uint8* in) +{ + return *(uint32*)in == B_TRANSPARENT_MAGIC_RGBA32_BIG; +} + + +// -------------------------------------------------- +bool +PDFWriter::IsTransparentRGBA32(uint8* in) +{ + return in[3] < 128 || IsTransparentRGB32(in); +} + + +// -------------------------------------------------- +bool +PDFWriter::IsTransparentRGBA32_BIG(uint8* in) +{ + return in[0] < 127 || IsTransparentRGB32_BIG(in); +} + +/* +// -------------------------------------------------- +bool +PDFWriter::IsTransparentRGB24(uint8* in) +{ + return false; +} + + +// -------------------------------------------------- +bool +PDFWriter::IsTransparentRGB24_BIG(uint8* in) +{ +} + + +// -------------------------------------------------- +bool +PDFWriter::IsTransparentRGB16(uint8* in) +{ + return false; +} + + +// -------------------------------------------------- +bool +PDFWriter::IsTransparentRGB16_BIG(uint8* in) +{ +} +*/ + + +// -------------------------------------------------- +bool +PDFWriter::IsTransparentRGB15(uint8* in) +{ + return *((uint16*)in) == B_TRANSPARENT_MAGIC_RGBA15; +} + + +// -------------------------------------------------- +bool +PDFWriter::IsTransparentRGB15_BIG(uint8* in) +{ + // 01234567 01234567 + // 00123434 01201234 + // -RRRRRGG GGGBBBBB + return *(uint16*)in == B_TRANSPARENT_MAGIC_RGBA15_BIG; +} + + +// -------------------------------------------------- +bool +PDFWriter::IsTransparentRGBA15(uint8* in) +{ + // 01234567 01234567 + // 01201234 00123434 + // GGGBBBBB ARRRRRGG + return in[1] & 1 == 0 || IsTransparentRGB15(in); +} + + +// -------------------------------------------------- +bool +PDFWriter::IsTransparentRGBA15_BIG(uint8* in) +{ + // 01234567 01234567 + // 00123434 01201234 + // ARRRRRGG GGGBBBBB + return in[0] & 1 == 0 || IsTransparentRGB15_BIG(in); +} + + +// -------------------------------------------------- +bool +PDFWriter::IsTransparentCMAP8(uint8* in) +{ + return *in == B_TRANSPARENT_MAGIC_CMAP8; +} + + +/* +// -------------------------------------------------- +bool +PDFWriter::IsTransparentGRAY8(uint8* in) +{ +} + + +// -------------------------------------------------- +bool +PDFWriter::IsTransparentGRAY1(uint8* in, int8 bit) +{ +} +*/ + + +// -------------------------------------------------- +void * +PDFWriter::CreateMask(BRect src, int32 bytesPerRow, int32 pixelFormat, int32 flags, void *data) +{ + uint8 *in; + uint8 *inRow; + int32 x, y; + + uint8 *mask; + uint8 *maskRow; + uint8 *out; + int32 maskWidth; + uint8 shift; + bool alpha; + int32 bpp = 4; + + bpp = BytesPerPixel(pixelFormat); + if (bpp < 0) + return NULL; + + int32 width = src.IntegerWidth() + 1; + int32 height = src.IntegerHeight() + 1; + + if (!NeedsAlphaCheck(pixelFormat)) + return NULL; + + // Image Mask + inRow = (uint8 *) data; + inRow += bytesPerRow * (int) src.top + bpp * (int) src.left; + + maskWidth = (width+7)/8; + maskRow = mask = new uint8[maskWidth * height]; + memset(mask, 0, maskWidth*height); + alpha = false; + + for (y = height; y > 0; y--) { + in = inRow; + out = maskRow; + shift = 7; + + bool a = false; + + for (x = width; x > 0; x-- ) { + // For each pixel + switch (pixelFormat) { + case B_RGB32: a = IsTransparentRGB32(in); break; + case B_RGB32_BIG: a = IsTransparentRGB32_BIG(in); break; + case B_RGBA32: a = IsTransparentRGBA32(in); break; + case B_RGBA32_BIG: a = IsTransparentRGBA32_BIG(in); break; + //case B_RGB24: a = IsTransparentRGB24(in); break; + //case B_RGB24_BIG: a = IsTransparentRGB24_BIG(in); break; + //case B_RGB16: a = IsTransparentRGB16(in); break; + //case B_RGB16_BIG: a = IsTransparentRGB16_BIG(in); break; + case B_RGB15: a = IsTransparentRGB15(in); break; + case B_RGB15_BIG: a = IsTransparentRGB15_BIG(in); break; + case B_RGBA15: a = IsTransparentRGBA15(in); break; + case B_RGBA15_BIG: a = IsTransparentRGBA15_BIG(in); break; + case B_CMAP8: a = IsTransparentCMAP8(in); break; + //case B_GRAY8: a = IsTransparentGRAY8(in); break; + //case B_GRAY1: a = false; break; + default: a = false; // should not reach here + REPORT(kDebug, fPage, "CreateMask: non transparentable pixelFormat"); + } + + if (a) { + out[0] |= (1 << shift); + alpha = true; + } + // next pixel + if (shift == 0) out ++; + shift = (shift + 7) & 0x07; + in += bpp; + } + + // next row + inRow += bytesPerRow; + maskRow += maskWidth; + } + + if (!alpha) { + delete []mask; + mask = NULL; + } + return mask; +} + + +// -------------------------------------------------- +void +PDFWriter::ConvertFromRGB32(uint8* in, uint8 *out) +{ + *((rgb_color*)out) = *((rgb_color*)in); +} + + +// -------------------------------------------------- +void +PDFWriter::ConvertFromRGBA32(uint8* in, uint8 *out) +{ + *((rgb_color*)out) = *((rgb_color*)in); +} + + +// -------------------------------------------------- +void +PDFWriter::ConvertFromRGB24(uint8* in, uint8 *out) +{ + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = 255; +} + + +// -------------------------------------------------- +void +PDFWriter::ConvertFromRGB16(uint8* in, uint8 *out) +{ + // 01234567 01234567 + // 01201234 01234345 + // GGGBBBBB RRRRRGGG + out[0] = in[0] & 0xf8; // blue + out[1] = ((in[0] & 7) << 2) | (in[1] & 0xe0); // green + out[2] = in[1] << 3; // red + out[3] = 255; +} + + +// -------------------------------------------------- +void +PDFWriter::ConvertFromRGB15(uint8* in, uint8 *out) +{ + // 01234567 01234567 + // 01201234 00123434 + // GGGBBBBB -RRRRRGG + out[0] = in[0] & 0xf8; // blue + out[1] = ((in[0] & 7) << 3) | (in[1] & 0xc0); // green + out[2] = (in[1] & ~1) << 2; // red + out[3] = 255; +} + + +// -------------------------------------------------- +void +PDFWriter::ConvertFromRGBA15(uint8* in, uint8 *out) +{ + // 01234567 01234567 + // 01201234 00123434 + // GGGBBBBB ARRRRRGG + out[0] = in[0] & 0xf8; // blue + out[1] = ((in[0] & 7) << 3) | (in[1] & 0xc0); // green + out[2] = (in[1] & ~1) << 2; // red + out[3] = in[1] << 7; +} + + +// -------------------------------------------------- +void +PDFWriter::ConvertFromCMAP8(uint8* in, uint8 *out) +{ + rgb_color c = fScreen->ColorForIndex(in[0]); + out[0] = c.blue; + out[1] = c.green; + out[2] = c.red; + out[3] = c.alpha; +} + + +// -------------------------------------------------- +void +PDFWriter::ConvertFromGRAY8(uint8* in, uint8 *out) +{ + out[0] = in[0]; + out[1] = in[0]; + out[2] = in[0]; + out[3] = 255; +} + + +// -------------------------------------------------- +void +PDFWriter::ConvertFromGRAY1(uint8* in, uint8 *out, int8 bit) +{ + uint8 gray = (in[0] & (1 << bit)) ? 255 : 0; + out[0] = gray; + out[1] = gray; + out[2] = gray; + out[3] = 255; +} + + +// -------------------------------------------------- +void +PDFWriter::ConvertFromRGB32_BIG(uint8* in, uint8 *out) +{ + out[0] = in[3]; + out[1] = in[2]; + out[2] = in[1]; + out[3] = 255; +} + + +// -------------------------------------------------- +void +PDFWriter::ConvertFromRGBA32_BIG(uint8* in, uint8 *out) +{ + out[0] = in[3]; + out[1] = in[2]; + out[2] = in[1]; + out[3] = in[0]; +} + + +// -------------------------------------------------- +void +PDFWriter::ConvertFromRGB24_BIG(uint8* in, uint8 *out) +{ + out[0] = in[2]; + out[1] = in[1]; + out[2] = in[0]; + out[3] = 255; +} + + +// -------------------------------------------------- +void +PDFWriter::ConvertFromRGB16_BIG(uint8* in, uint8 *out) +{ + // 01234567 01234567 + // 01234345 01201234 + // RRRRRGGG GGGBBBBB + out[0] = in[2] & 0xf8; // blue + out[1] = ((in[1] & 7) << 2) | (in[0] & 0xe0); // green + out[2] = in[0] << 3; // red + out[3] = 255; +} + + +// -------------------------------------------------- +void +PDFWriter::ConvertFromRGB15_BIG(uint8* in, uint8 *out) +{ + // 01234567 01234567 + // 00123434 01201234 + // -RRRRRGG GGGBBBBB + out[0] = in[1] & 0xf8; // blue + out[1] = ((in[1] & 7) << 3) | (in[0] & 0xc0); // green + out[2] = (in[0] & ~1) << 2; // red + out[3] = 255; +} + + +// -------------------------------------------------- +void +PDFWriter::ConvertFromRGBA15_BIG(uint8* in, uint8 *out) +{ + // 01234567 01234567 + // 00123434 01201234 + // ARRRRRGG GGGBBBBB + out[0] = in[1] & 0xf8; // blue + out[1] = ((in[1] & 7) << 3) | (in[0] & 0xc0); // green + out[2] = (in[0] & ~1) << 2; // red + out[3] = in[0] << 7; +} + + +// -------------------------------------------------- +// Convert and clip bits to colorspace B_RGBA32 +BBitmap * +PDFWriter::ConvertBitmap(BRect src, int32 bytesPerRow, int32 pixelFormat, int32 flags, void *data) +{ + uint8 *in; + uint8 *inLeft; + uint8 *out; + uint8 *outLeft; + int32 x, y; + int8 bit; + int32 bpp = 4; + + bpp = BytesPerPixel(pixelFormat); + if (bpp < 0) + return NULL; + + int32 width = src.IntegerWidth(); + int32 height = src.IntegerHeight(); + BBitmap * bm = new BBitmap(BRect(0, 0, width, height), B_RGB32); + if (!bm->IsValid()) { + delete bm; + REPORT(kError, fPage, "BBitmap constructor failed"); + return NULL; + } + + inLeft = (uint8 *)data; + inLeft += bytesPerRow * (int)src.top + bpp * (int)src.left; + outLeft = (uint8*)bm->Bits(); + + for (y = height; y >= 0; y--) { + in = inLeft; + out = outLeft; + + for (x = 0; x <= width; x++) { + // For each pixel + switch (pixelFormat) { + case B_RGB32: ConvertFromRGB32(in, out); break; + case B_RGBA32: ConvertFromRGBA32(in, out); break; + case B_RGB24: ConvertFromRGB24(in, out); break; + case B_RGB16: ConvertFromRGB16(in, out); break; + case B_RGB15: ConvertFromRGB15(in, out); break; + case B_RGBA15: ConvertFromRGBA15(in, out); break; + case B_CMAP8: ConvertFromCMAP8(in, out); break; + case B_GRAY8: ConvertFromGRAY8(in, out); break; + case B_GRAY1: + bit = x & 7; + ConvertFromGRAY1(in, out, bit); + if (bit == 7) in ++; + break; + case B_RGB32_BIG: ConvertFromRGB32_BIG(in, out); break; + case B_RGBA32_BIG: ConvertFromRGBA32_BIG(in, out); break; + case B_RGB24_BIG: ConvertFromRGB24_BIG(in, out); break; + case B_RGB16_BIG: ConvertFromRGB16_BIG(in, out); break; + case B_RGB15_BIG: ConvertFromRGB15_BIG(in, out); break; + case B_RGBA15_BIG: ConvertFromRGBA15_BIG(in, out); break; + default:; // should not reach here + } + in += bpp; // next pixel + out += 4; + } + + // next row + inLeft += bytesPerRow; + outLeft += bm->BytesPerRow(); + } + + return bm; +} + + +// -------------------------------------------------- +bool +PDFWriter::StoreTranslatorBitmap(BBitmap *bitmap, const char *filename, uint32 type) +{ + BTranslatorRoster *roster = BTranslatorRoster::Default(); + if (!roster) { + REPORT(kDebug, fPage, "TranslatorRoster is NULL!"); + return false; + } + BBitmapStream stream(bitmap); // init with contents of bitmap +/* + translator_info info, *i = NULL; + if (quality != -1.0 && roster->Identify(&stream, NULL, &info) == B_OK) { + #ifdef DEBUG + LOG((fLog, ">>> translator_info:\n")); + LOG((fLog, " type = %4.4s\n", (char*)&info.type)); + LOG((fLog, " id = %d\n", info.translator)); + LOG((fLog, " group = %4.4s\n", (char*)&info.group)); + LOG((fLog, " quality = %f\n", info.quality)); + LOG((fLog, " capability = %f\n", info.type)); + LOG((fLog, " name = %s\n", info.name)); + LOG((fLog, " MIME = %s\n", info.MIME)); + #endif + + int32 numInfo; + translator_info *tInfo = NULL; + if (roster->GetTranslators(&stream, NULL, &tInfo, &numInfo, + info.type, NULL, type) == B_OK) { + +// #ifdef DEBUG + for (int j = 0; j < numInfo; j++) { + LOG((fLog, ">>> translator_info [%d]:\n", j)); + LOG((fLog, " type = %4.4s\n", (char*)&tInfo[j].type)); + LOG((fLog, " id = %d\n", tInfo[j].translator)); + LOG((fLog, " group = %4.4s\n", (char*)&tInfo[j].group)); + LOG((fLog, " quality = %f\n", tInfo[j].quality)); + LOG((fLog, " capability = %f\n", tInfo[j].type)); + LOG((fLog, " name = %s\n", tInfo[j].name)); + LOG((fLog, " MIME = %s\n", tInfo[j].MIME)); + } +// #endif + + BMessage m; + status_t s = roster->GetConfigurationMessage(tInfo[0].translator, &m); + if (s == B_OK) { + fMessagePrinter.Print(&m); + } else { + LOG((fLog, "ERROR: could not get configuration message %d\n", s)); + } + + info = tInfo[0]; + info.quality = quality; + delete []tInfo; + + i = &info; + } + } +*/ + BFile file(filename, B_CREATE_FILE | B_WRITE_ONLY | B_ERASE_FILE); + bool res = roster->Translate(&stream, NULL /*i*/, NULL, &file, type) == B_OK; + BBitmap *bm = NULL; stream.DetachBitmap(&bm); // otherwise bitmap destructor crashes here! + ASSERT(bm == bitmap); + return res; +} + +// -------------------------------------------------- +bool +PDFWriter::GetImages(BRect src, int32 width, int32 height, int32 bytesPerRow, int32 pixelFormat, + int32 flags, void *data, int* maskId, int* image) +{ + void *mask = NULL; + *maskId = -1; + + mask = CreateMask(src, bytesPerRow, pixelFormat, flags, data); + + if (mask) { + int32 width = src.IntegerWidth() + 1; + int32 height = src.IntegerHeight() + 1; + int32 w = (width+7)/8; + int32 h = height; + *maskId = PDF_open_image(fPdf, "raw", "memory", (const char *) mask, w*h, width, height, 1, 1, "mask"); + delete []mask; + } + + BBitmap * bm = ConvertBitmap(src, bytesPerRow, pixelFormat, flags, data); + if (!bm) { + REPORT(kError, fPage, "ConvertBitmap failed!"); + if (*maskId != -1) PDF_close_image(fPdf, *maskId); + return false; + } + + char *pdfLibFormat = "png"; + char *bitmapFileName = "/tmp/pdfwriter.png"; + const uint32 beosFormat = B_PNG_FORMAT; + + if (!StoreTranslatorBitmap(bm, bitmapFileName, beosFormat)) { + delete bm; + REPORT(kError, fPage, "StoreTranslatorBitmap failed"); + if (*maskId != -1) PDF_close_image(fPdf, *maskId); + return false; + } + delete bm; + + *image = PDF_open_image_file(fPdf, pdfLibFormat, bitmapFileName, + *maskId == -1 ? "" : "masked", *maskId == -1 ? 0 : *maskId); + + return *image >= 0; +} + + +#ifdef CODEWARRIOR + #pragma mark -- BPicture playback handlers +#endif + + +// -------------------------------------------------- +void PDFWriter::Op(int number) +{ + REPORT(kError, fPage, "Unhandled operand %d", number); +} + + +// -------------------------------------------------- +void +PDFWriter::MovePenBy(BPoint delta) +{ + REPORT(kDebug, fPage, "MovePenBy delta=[%f, %f]", \ + delta.x, delta.y); + fState->penX += delta.x; + fState->penY += delta.y; +} + + +// -------------------------------------------------- +void +PDFWriter::StrokeLine(BPoint start, BPoint end) +{ + REPORT(kDebug, fPage, "StrokeLine start=[%f, %f], end=[%f, %f]", \ + start.x, start.y, end.x, end.y); + + SetColor(); + if (!MakesPDF()) return; + if (IsClipping()) { + BShape shape; + shape.MoveTo(start); + shape.LineTo(end); + StrokeShape(&shape); + } else { + PDF_moveto(fPdf, tx(start.x), ty(start.y)); + PDF_lineto(fPdf, tx(end.x), ty(end.y)); + StrokeOrClip(); + } +} + + +// -------------------------------------------------- +void +PDFWriter::StrokeRect(BRect rect) +{ + REPORT(kDebug, fPage, "StrokeRect rect=[%f, %f, %f, %f]", \ + rect.left, rect.top, rect.right, rect.bottom); + + SetColor(); + if (!MakesPDF()) return; + if (IsClipping()) { + BShape shape; + shape.MoveTo(BPoint(rect.left, rect.top)); + shape.LineTo(BPoint(rect.right, rect.top)); + shape.LineTo(BPoint(rect.right, rect.bottom)); + shape.LineTo(BPoint(rect.left, rect.bottom)); + shape.Close(); + StrokeShape(&shape); + } else { + PDF_rect(fPdf, tx(rect.left), ty(rect.bottom), scale(rect.Width()), scale(rect.Height())); + StrokeOrClip(); + } +} + + +// -------------------------------------------------- +void +PDFWriter::FillRect(BRect rect) +{ + REPORT(kDebug, fPage, "FillRect rect=[%f, %f, %f, %f]", \ + rect.left, rect.top, rect.right, rect.bottom); + + SetColor(); + if (!MakesPDF()) return; + PDF_rect(fPdf, tx(rect.left), ty(rect.bottom), scale(rect.Width()), scale(rect.Height())); + FillOrClip(); +} + + +// -------------------------------------------------- +// The quarter ellipses in the corners of the rectangle are +// approximated with bezier curves. +// The constant 0.555... is taken from gobeProductive. +void +PDFWriter::PaintRoundRect(BRect rect, BPoint radii, bool stroke) { + SetColor(); + if (!MakesPDF()) return; + + BPoint center; + + float sx = radii.x; + float sy = radii.y; + + float ax = sx; + float bx = 0.5555555555555 * sx; + float ay = sy; + float by = 0.5555555555555 * sy; + + center.x = rect.left + sx; + center.y = rect.top - sy; + + BShape shape; + shape.MoveTo(BPoint(center.x - ax, center.y)); + BPoint a[3] = { + BPoint(center.x - ax, center.y + by), + BPoint(center.x - bx, center.y + ay), + BPoint(center.x , center.y + ay)}; + shape.BezierTo(a); + + center.x = rect.right - sx; + shape.LineTo(BPoint(center.x, center.y + ay)); + + BPoint b[3] = { + BPoint(center.x + bx, center.y + ay), + BPoint(center.x + ax, center.y + by), + BPoint(center.x + ax, center.y)}; + shape.BezierTo(b); + + center.y = rect.bottom + sy; + shape.LineTo(BPoint(center.x + sx, center.y)); + + BPoint c[3] = { + BPoint(center.x + ax, center.y - by), + BPoint(center.x + bx, center.y - ay), + BPoint(center.x , center.y - ay)}; + shape.BezierTo(c); + + center.x = rect.left + sx; + shape.LineTo(BPoint(center.x, center.y - ay)); + + BPoint d[3] = { + BPoint(center.x - bx, center.y - ay), + BPoint(center.x - ax, center.y - by), + BPoint(center.x - ax, center.y)}; + shape.BezierTo(d); + + shape.Close(); + + PaintShape(&shape, stroke); +} + + +// -------------------------------------------------- +void +PDFWriter::StrokeRoundRect(BRect rect, BPoint radii) +{ + REPORT(kDebug, fPage, "StrokeRoundRect center=[%f, %f, %f, %f], radii=[%f, %f]", \ + rect.left, rect.top, rect.right, rect.bottom, radii.x, radii.y); + PaintRoundRect(rect, radii, kStroke); +} + + +// -------------------------------------------------- +void +PDFWriter::FillRoundRect(BRect rect, BPoint radii) +{ + REPORT(kDebug, fPage, "FillRoundRect rect=[%f, %f, %f, %f], radii=[%f, %f]", \ + rect.left, rect.top, rect.right, rect.bottom, radii.x, radii.y); + PaintRoundRect(rect, radii, kFill); +} + + +// -------------------------------------------------- +void +PDFWriter::StrokeBezier(BPoint *control) +{ + REPORT(kDebug, fPage, "StrokeBezier"); + SetColor(); + if (!MakesPDF()) return; + + BShape shape; + shape.MoveTo(control[0]); + shape.BezierTo(&control[1]); + StrokeShape(&shape); +} + + +// -------------------------------------------------- +void +PDFWriter::FillBezier(BPoint *control) +{ + REPORT(kDebug, fPage, "FillBezier"); + SetColor(); + if (!MakesPDF()) return; + PDF_moveto(fPdf, tx(control[0].x), ty(control[0].y)); + PDF_curveto(fPdf, tx(control[1].x), ty(control[1].y), + tx(control[2].x), ty(control[2].y), + tx(control[3].x), ty(control[3].y)); + PDF_closepath(fPdf); + FillOrClip(); +} + + +// -------------------------------------------------- +// Note the pen size is also scaled! +// We should approximate it with bezier curves too! +void +PDFWriter::PaintArc(BPoint center, BPoint radii, float startTheta, float arcTheta, int stroke) { + float sx = scale(radii.x); + float sy = scale(radii.y); + float smax = sx > sy ? sx : sy; + + SetColor(); + if (!MakesPDF()) return; + if (IsClipping()); // TODO clip to line path + + PDF_save(fPdf); + PDF_scale(fPdf, sx, sy); + PDF_setlinewidth(fPdf, fState->penSize / smax); + PDF_arc(fPdf, tx(center.x) / sx, ty(center.y) / sy, 1, startTheta, startTheta + arcTheta); + Paint(stroke); + PDF_restore(fPdf); +} + + +// -------------------------------------------------- +void +PDFWriter::StrokeArc(BPoint center, BPoint radii, float startTheta, float arcTheta) +{ + REPORT(kDebug, fPage, "StrokeArc center=[%f, %f], radii=[%f, %f], startTheta=%f, arcTheta=%f", \ + center.x, center.y, radii.x, radii.y, startTheta, arcTheta); + PaintArc(center, radii, startTheta, arcTheta, true); +} + + +// -------------------------------------------------- +void +PDFWriter::FillArc(BPoint center, BPoint radii, float startTheta, float arcTheta) +{ + REPORT(kDebug, fPage, "FillArc center=[%f, %f], radii=[%f, %f], startTheta=%f, arcTheta=%f", \ + center.x, center.y, radii.x, radii.y, startTheta, arcTheta); + PaintArc(center, radii, startTheta, arcTheta, false); +} + + +// -------------------------------------------------- +void +PDFWriter::PaintEllipse(BPoint center, BPoint radii, bool stroke) +{ + float sx = radii.x; + float sy = radii.y; + + float ax = sx; + float bx = 0.5555555555555 * sx; + float ay = sy; + float by = 0.5555555555555 * sy; + + SetColor(); + if (!MakesPDF()) return; + + BShape shape; + + shape.MoveTo(BPoint(center.x - ax, center.y)); + + BPoint a[3] = { + BPoint(center.x - ax, center.y - by), + BPoint(center.x - bx, center.y - ay), + BPoint(center.x , center.y - ay) }; + shape.BezierTo(a); + + BPoint b[3] = { + BPoint(center.x + bx, center.y - ay), + BPoint(center.x + ax, center.y - by), + BPoint(center.x + ax, center.y)}; + shape.BezierTo(b); + + BPoint c[3] = { + BPoint(center.x + ax, center.y + by), + BPoint(center.x + bx, center.y + ay), + BPoint(center.x , center.y + ay)}; + shape.BezierTo(c); + + BPoint d[3] = { + BPoint(center.x - bx, center.y + ay), + BPoint(center.x - ax, center.y + by), + BPoint(center.x - ax, center.y)}; + shape.BezierTo(d); + + shape.Close(); + + PaintShape(&shape, stroke); +} + +// -------------------------------------------------- +void +PDFWriter::StrokeEllipse(BPoint center, BPoint radii) +{ + REPORT(kDebug, fPage, "StrokeEllipse center=[%f, %f], radii=[%f, %f]", \ + center.x, center.y, radii.x, radii.y); + PaintEllipse(center, radii, true); +} + + +// -------------------------------------------------- +void +PDFWriter::FillEllipse(BPoint center, BPoint radii) +{ + REPORT(kDebug, fPage, "FillEllipse center=[%f, %f], radii=[%f, %f]", \ + center.x, center.y, radii.x, radii.y); + PaintEllipse(center, radii, false); +} + + +// -------------------------------------------------- +void +PDFWriter::StrokePolygon(int32 numPoints, BPoint *points, bool isClosed) +{ + int32 i; + float x0, y0; + REPORT(kDebug, fPage, "StrokePolygon numPoints=%ld, isClosed=%d\npoints=", \ + numPoints, isClosed); + + if (numPoints <= 1) return; + + x0 = y0 = 0.0; + + SetColor(); + if (!MakesPDF()) return; + + if (IsClipping()) { + BShape shape; + shape.MoveTo(*points); + for (i = 1, points ++; i < numPoints; i++, points++) { + shape.LineTo(*points); + } + if (isClosed) + shape.Close(); + StrokeShape(&shape); + } else { + for ( i = 0; i < numPoints; i++, points++ ) { + REPORT(kDebug, fPage, " [%f, %f]", points->x, points->y); + if (i != 0) { + PDF_lineto(fPdf, tx(points->x), ty(points->y)); + } else { + x0 = tx(points->x); + y0 = ty(points->y); + PDF_moveto(fPdf, x0, y0); + } + } + if (isClosed) + PDF_lineto(fPdf, x0, y0); + StrokeOrClip(); + } +} + + +// -------------------------------------------------- +void +PDFWriter::FillPolygon(int32 numPoints, BPoint *points, bool isClosed) +{ + int32 i; + + REPORT(kDebug, fPage, "FillPolygon numPoints=%ld, isClosed=%dpoints=", \ + numPoints, isClosed); + + SetColor(); + if (!MakesPDF()) return; + + for ( i = 0; i < numPoints; i++, points++ ) { + REPORT(kDebug, fPage, " [%f, %f]", points->x, points->y); + if (i != 0) { + PDF_lineto(fPdf, tx(points->x), ty(points->y)); + } else { + PDF_moveto(fPdf, tx(points->x), ty(points->y)); + } + } + PDF_closepath(fPdf); + FillOrClip(); +} + + +// -------------------------------------------------- +void PDFWriter::PaintShape(BShape *shape, bool stroke) +{ + if (stroke) StrokeShape(shape); else FillShape(shape); +} + + +// -------------------------------------------------- +void PDFWriter::StrokeShape(BShape *shape) +{ + REPORT(kDebug, fPage, "StrokeShape"); + SetColor(); + if (!MakesPDF()) return; + DrawShape iterator(this, true); + iterator.Iterate(shape); +} + + +// -------------------------------------------------- +void PDFWriter::FillShape(BShape *shape) +{ + REPORT(kDebug, fPage, "FillShape"); + SetColor(); + if (!MakesPDF()) return; + DrawShape iterator(this, false); + iterator.Iterate(shape); +} + + +// -------------------------------------------------- +void +PDFWriter::ClipToPicture(BPicture *picture, BPoint point, bool clip_to_inverse_picture) +{ + REPORT(kDebug, fPage, "ClipToPicture at (%f, %f) clip_to_inverse_picture = %s", point.x, point.y, clip_to_inverse_picture ? "true" : "false"); + if (!MakesPDF()) return; + if (clip_to_inverse_picture) { + REPORT(kError, fPage, "Clipping to inverse picture not implemented!"); + return; + } + if (fMode == kDrawingMode) { + const bool set_origin = point.x != 0 || point.y != 0; + if (set_origin) { + PushInternalState(); SetOrigin(point); PushInternalState(); + } + + fMode = kClippingMode; + // create subpath(s) for clipping + Iterate(picture); + fMode = kDrawingMode; + // and clip to it/them + PDF_clip(fPdf); + + if (set_origin) { + PopInternalState(); PopInternalState(); + } + + REPORT(kDebug, fPage, "Returning from ClipToPicture"); + } else { + REPORT(kError, fPage, "Nested call of ClipToPicture not implemented yet!"); + } +} + +// -------------------------------------------------- +void +PDFWriter::DrawPixels(BRect src, BRect dest, int32 width, int32 height, int32 bytesPerRow, int32 pixelFormat, + int32 flags, void *data) +{ + REPORT(kDebug, fPage, "DrawPixels src=[%f, %f, %f, %f], dest=[%f, %f, %f, %f], " \ + "width=%ld, height=%ld, bytesPerRow=%ld, pixelFormat=%ld, " \ + "flags=%ld, data=%p", \ + src.left, src.top, src.right, src.bottom, \ + dest.left, dest.top, dest.right, dest.bottom, \ + width, height, bytesPerRow, pixelFormat, flags, data); + + if (!MakesPDF()) return; + + if (IsClipping()) { + REPORT(kError, fPage, "DrawPixels for clipping not implemented yet!"); + return; + } + + int maskId, image; + + if (!GetImages(src, width, height, bytesPerRow, pixelFormat, flags, data, &maskId, &image)) { + return; + } + + const float scaleX = (dest.Width()+1) / (src.Width()+1); + const float scaleY = (dest.Height()+1) / (src.Height()+1); + + const bool needs_scaling = scaleX != 1.0 || scaleY != 1.0; + + if (needs_scaling) { + PDF_save(fPdf); + PDF_scale(fPdf, scaleX, scaleY); + } + + float x = tx(dest.left) / scaleX; + float y = ty(dest.bottom) / scaleY; + + if ( image >= 0 ) { + PDF_place_image(fPdf, image, x, y, scale(1.0)); + PDF_close_image(fPdf, image); + } else + REPORT(kError, fPage, "PDF_open_image_file failed!"); + + if (maskId != -1) PDF_close_image(fPdf, maskId); + if (needs_scaling) PDF_restore(fPdf); +} + + + +// -------------------------------------------------- +void +PDFWriter::SetClippingRects(BRect *rects, uint32 numRects) +{ + uint32 i; + + REPORT(kDebug, fPage, "SetClippingRects numRects=%ld\nrects=", \ + numRects); + + if (!MakesPDF()) return; + + for ( i = 0; i < numRects; i++, rects++ ) { + REPORT(kDebug, fPage, " [%f, %f, %f, %f]", \ + rects->left, rects->top, rects->right, rects->bottom); + PDF_moveto(fPdf, tx(rects->left), ty(rects->top)); + PDF_lineto(fPdf, tx(rects->right), ty(rects->top)); + PDF_lineto(fPdf, tx(rects->right), ty(rects->bottom)); + PDF_lineto(fPdf, tx(rects->left), ty(rects->bottom)); + PDF_closepath(fPdf); + } + if (numRects > 0) PDF_clip(fPdf); +} + + +// -------------------------------------------------- +void +PDFWriter::PushState() +{ + REPORT(kDebug, fPage, "PushState"); + PushInternalState(); +// LOG((fLog, "height = %f x0 = %f y0 = %f", fState->height, fState->x0, fState->y0)); + if (!MakesPDF()) return; + PDF_save(fPdf); +} + + +// -------------------------------------------------- +void +PDFWriter::PopState() +{ + REPORT(kDebug, fPage, "PopState"); + if (PopInternalState()) { + if (!MakesPDF()) return; + PDF_restore(fPdf); + } +} + + +// -------------------------------------------------- +void +PDFWriter::EnterStateChange() +{ + REPORT(kDebug, fPage, "EnterStateChange"); + // nothing to do +} + + +// -------------------------------------------------- +void +PDFWriter::ExitStateChange() +{ + REPORT(kDebug, fPage, "ExitStateChange"); + // nothing to do +} + + +// -------------------------------------------------- +void +PDFWriter::EnterFontState() +{ + REPORT(kDebug, fPage, "EnterFontState"); + // nothing to do +} + + +// -------------------------------------------------- +void +PDFWriter::ExitFontState() +{ + REPORT(kDebug, fPage, "ExitFontState"); + // nothing to do +} + + +// -------------------------------------------------- +void +PDFWriter::SetOrigin(BPoint pt) +{ + REPORT(kDebug, fPage, "SetOrigin pt=[%f, %f]", \ + pt.x, pt.y); + + // XXX scale pt with current scaling factor or with + // scaling factor of previous state? (fState->prev->scale) + BPoint o = fState->prev->pdfSystem.Origin(); + pdfSystem()->SetOrigin( + o.x + pdfSystem()->scale(pt.x), + o.y + pdfSystem()->scale(pt.y) + ); +} + + +// -------------------------------------------------- +void +PDFWriter::SetPenLocation(BPoint pt) +{ + REPORT(kDebug, fPage, "SetPenLocation pt=[%f, %f]", \ + pt.x, pt.y); + + fState->penX = pt.x; + fState->penY = pt.y; +} + + + +// -------------------------------------------------- +void +PDFWriter::SetDrawingMode(drawing_mode mode) +{ + REPORT(kDebug, fPage, "SetDrawingMode mode=%d", mode); + fState->drawingMode = mode; +} + + + +// -------------------------------------------------- +void +PDFWriter::SetLineMode(cap_mode capMode, join_mode joinMode, float miterLimit) +{ + REPORT(kDebug, fPage, "SetLineMode"); + fState->capMode = capMode; + fState->joinMode = joinMode; + fState->miterLimit = miterLimit; + if (!MakesPDF()) return; + int m = 0; + switch (capMode) { + case B_BUTT_CAP: m = 0; break; + case B_ROUND_CAP: m = 1; break; + case B_SQUARE_CAP: m = 2; break; + } + PDF_setlinecap(fPdf, m); + + m = 0; + switch (joinMode) { + case B_MITER_JOIN: m = 0; break; + case B_ROUND_JOIN: m = 1; break; + case B_BUTT_JOIN: // fall through XXX: check this; no equivalent in PDF? + case B_SQUARE_JOIN: // fall through XXX: check this too + case B_BEVEL_JOIN: m = 2; break; + } + PDF_setlinejoin(fPdf, m); + + PDF_setmiterlimit(fPdf, miterLimit); + +} + + +// -------------------------------------------------- +void +PDFWriter::SetPenSize(float size) +{ + REPORT(kDebug, fPage, "SetPenSize size=%f", size); + if (size <= 0.00001) size = 1; + // XXX scaling required? + fState->penSize = scale(size); + if (!MakesPDF()) return; + PDF_setlinewidth(fPdf, size); +} + + +// -------------------------------------------------- +void +PDFWriter::SetForeColor(rgb_color color) +{ + float red, green, blue; + + red = color.red / 255.0; + green = color.green / 255.0; + blue = color.blue / 255.0; + + REPORT(kDebug, fPage, "SetForColor color=[%d, %d, %d, %d] -> [%f, %f, %f]", \ + color.red, color.green, color.blue, color.alpha, \ + red, green, blue); + + fState->foregroundColor = color; +} + + +// -------------------------------------------------- +void +PDFWriter::SetBackColor(rgb_color color) +{ + float red, green, blue; + + red = color.red / 255.0; + green = color.green / 255.0; + blue = color.blue / 255.0; + + REPORT(kDebug, fPage, "SetBackColor color=[%d, %d, %d, %d] -> [%f, %f, %f]", \ + color.red, color.green, color.blue, color.alpha, \ + red, green, blue); + + fState->backgroundColor = color; +} + + +// -------------------------------------------------- +void +PDFWriter::SetStipplePattern(pattern pat) +{ + REPORT(kDebug, fPage, "SetStipplePattern"); + fState->pattern = pat; +} + + +// -------------------------------------------------- +void +PDFWriter::SetScale(float scale) +{ + REPORT(kDebug, fPage, "SetScale scale=%f", scale); + pdfSystem()->SetScale(scale * fState->prev->pdfSystem.Scale()); +} + + +// -------------------------------------------------- +void +PDFWriter::SetFontFamily(char *family) +{ + REPORT(kDebug, fPage, "SetFontFamily family=\"%s\"", family); + + fState->beFont.SetFamilyAndStyle(family, NULL); +} + + +// -------------------------------------------------- +void +PDFWriter::SetFontStyle(char *style) +{ + REPORT(kDebug, fPage, "SetFontStyle style=\"%s\"", style); + + fState->beFont.SetFamilyAndStyle(NULL, style); +} + + +// -------------------------------------------------- +void +PDFWriter::SetFontSpacing(int32 spacing) +{ + REPORT(kDebug, fPage, "SetFontSpacing spacing=%ld", spacing); + // XXX scaling required? + // if it is, do it when the font is used... + fState->beFont.SetSpacing(spacing); +} + + +// -------------------------------------------------- +void +PDFWriter::SetFontSize(float size) +{ + REPORT(kDebug, fPage, "SetFontSize size=%f", size); + + fState->beFont.SetSize(size); +} + + +// -------------------------------------------------- +void +PDFWriter::SetFontRotate(float rotation) +{ + REPORT(kDebug, fPage, "SetFontRotate rotation=%f", rotation); + fState->beFont.SetRotation(RAD2DEGREE(rotation)); +} + + +// -------------------------------------------------- +void +PDFWriter::SetFontEncoding(int32 encoding) +{ + REPORT(kDebug, fPage, "SetFontEncoding encoding=%ld", encoding); + fState->beFont.SetEncoding(encoding); +} + + +// -------------------------------------------------- +void +PDFWriter::SetFontFlags(int32 flags) +{ + REPORT(kDebug, fPage, "SetFontFlags flags=%ld (0x%lx)", flags, flags); + fState->beFont.SetFlags(flags); +} + + +// -------------------------------------------------- +void +PDFWriter::SetFontShear(float shear) +{ + REPORT(kDebug, fPage, "SetFontShear shear=%f", shear); + fState->beFont.SetShear(shear); +} + + +// -------------------------------------------------- +void +PDFWriter::SetFontFace(int32 flags) +{ + REPORT(kDebug, fPage, "SetFontFace flags=%ld (0x%lx)", flags, flags); +// fState->beFont.SetFace(flags); +} + +#ifdef CODEWARRIOR + #pragma mark [Redirectors to instance callbacks/handlers] +#endif + + +// -------------------------------------------------- +size_t +_WriteData(PDF *pdf, void *data, size_t size) +{ + return ((PDFWriter *) PDF_get_opaque(pdf))->WriteData(data, size); +} + + +// -------------------------------------------------- +void +_ErrorHandler(PDF *pdf, int type, const char *msg) +{ + return ((PDFWriter *) PDF_get_opaque(pdf))->ErrorHandler(type, msg); +} + diff --git a/src/add-ons/print/drivers/pdf/source/PDFWriter.h b/src/add-ons/print/drivers/pdf/source/PDFWriter.h new file mode 100644 index 0000000000..e93e8074e0 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/PDFWriter.h @@ -0,0 +1,356 @@ +/* + +PDF Writer printer driver. + +Copyright (c) 2001 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef PDFWRITER_H +#define PDFWRITER_H + +#include +#include +#include +#include + +#include "math.h" + +#include "PrinterDriver.h" +#include "PictureIterator.h" +#include "Fonts.h" +#include "SubPath.h" +#include "Utils.h" +#include "Link.h" + +#include "pdflib.h" + +#define RAD2DEGREE(r) (180.0 * r / PI) +#define DEGREE2RAD(d) (PI * d / 180.0) + +class DrawShape; +class WebLink; +class Bookmark; +class XRefDefs; +class XRefDests; + +class PDFWriter : public PrinterDriver, public PictureIterator +{ + + friend class DrawShape; + friend class PDFLinePathBuilder; + friend class WebLink; + friend class Link; + friend class Bookmark; + friend class LocalLink; + friend class TextLine; + + public: + // constructors / destructor + PDFWriter(); + ~PDFWriter(); + + // public methods + status_t BeginJob(); + status_t PrintPage(int32 pageNumber, int32 pageCount); + status_t EndJob(); + status_t InitWriter(); + status_t BeginPage(BRect paperRect, BRect printRect); + status_t EndPage(); + + void SetAttribute(const char* name, const char* value); + bool LoadBookmarkDefinitions(const char* name); + bool LoadXRefsDefinitions(const char* name); + void RecordDests(const char* s); + + // PDFLib callbacks + size_t WriteData(void *data, size_t size); + void ErrorHandler(int type, const char *msg); + + // Image support + int32 BytesPerPixel(int32 pixelFormat); + + bool NeedsAlphaCheck(int32 pixelFormat); + + inline bool IsTransparentRGB32(uint8* in); + inline bool IsTransparentRGBA32(uint8* in); + inline bool IsTransparentRGB32_BIG(uint8* in); + inline bool IsTransparentRGBA32_BIG(uint8* in); + //inline bool IsTransparentRGB24(uint8* in); + //inline bool IsTransparentRGB24_BIG(uint8* in); + //inline bool IsTransparentRGB16(uint8* in); + //inline bool IsTransparentRGB16_BIG(uint8* in); + inline bool IsTransparentRGB15(uint8* in); + inline bool IsTransparentRGB15_BIG(uint8* in); + inline bool IsTransparentRGBA15(uint8* in); + inline bool IsTransparentRGBA15_BIG(uint8* in); + inline bool IsTransparentCMAP8(uint8* in); + //inline bool IsTransparentGRAY8(uint8* in); + //inline bool IsTransparentGRAY1(uint8* in); + + inline void ConvertFromRGB32(uint8* in, uint8* out); + inline void ConvertFromRGB32_BIG(uint8* in, uint8* out); + inline void ConvertFromRGBA32(uint8* in, uint8* out); + inline void ConvertFromRGBA32_BIG(uint8* in, uint8* out); + inline void ConvertFromRGB24(uint8* in, uint8* out); + inline void ConvertFromRGB24_BIG(uint8* in, uint8* out); + inline void ConvertFromRGB16(uint8* in, uint8* out); + inline void ConvertFromRGB16_BIG(uint8* in, uint8* out); + inline void ConvertFromRGB15(uint8* in, uint8* out); + inline void ConvertFromRGBA15_BIG(uint8* in, uint8* out); + inline void ConvertFromRGB15_BIG(uint8* in, uint8* out); + inline void ConvertFromRGBA15(uint8* in, uint8* out); + inline void ConvertFromCMAP8(uint8* in, uint8* out); + inline void ConvertFromGRAY8(uint8* in, uint8* out); + inline void ConvertFromGRAY1(uint8* in, uint8* out, int8 bit); + + void *CreateMask(BRect src, int32 bytesPerRow, int32 pixelFormat, int32 flags, void *data); + BBitmap *ConvertBitmap(BRect src, int32 bytesPerRow, int32 pixelFormat, int32 flags, void *data); + bool GetImages(BRect src, int32 width, int32 height, int32 bytesPerRow, int32 pixelFormat, int32 flags, void *data, int* mask, int* image); + + // String handling + bool BeginsChar(char byte) { return BEGINS_CHAR(byte); } + void ToUtf8(uint32 encoding, const char *string, BString &utf8); + void ToUnicode(const char *string, BString &unicode); + void ToPDFUnicode(const char *string, BString &unicode); + uint16 CodePointSize(const char *s); + void DrawChar(uint16 unicode, const char *utf8, int16 size); + void ClipChar(BFont* font, const char* unicode, const char *utf8, int16 size, float width); + bool EmbedFont(const char* n); + status_t DeclareFonts(); + + // BPicture playback handlers + void Op(int number); + void MovePenBy(BPoint delta); + void StrokeLine(BPoint start, BPoint end); + void StrokeRect(BRect rect); + void FillRect(BRect rect); + void StrokeRoundRect(BRect rect, BPoint radii); + void FillRoundRect(BRect rect, BPoint radii); + void StrokeBezier(BPoint *control); + void FillBezier(BPoint *control); + void StrokeArc(BPoint center, BPoint radii, float startTheta, float arcTheta); + void FillArc(BPoint center, BPoint radii, float startTheta, float arcTheta); + void StrokeEllipse(BPoint center, BPoint radii); + void FillEllipse(BPoint center, BPoint radii); + void StrokePolygon(int32 numPoints, BPoint *points, bool isClosed); + void FillPolygon(int32 numPoints, BPoint *points, bool isClosed); + void StrokeShape(BShape *shape); + void FillShape(BShape *shape); + void DrawString(char *string, float deltax, float deltay); + void DrawPixels(BRect src, BRect dest, int32 width, int32 height, int32 bytesPerRow, int32 pixelFormat, int32 flags, void *data); + void SetClippingRects(BRect *rects, uint32 numRects); + void ClipToPicture(BPicture *picture, BPoint point, bool clip_to_inverse_picture); + void PushState(); + void PopState(); + void EnterStateChange(); + void ExitStateChange(); + void EnterFontState(); + void ExitFontState(); + void SetOrigin(BPoint pt); + void SetPenLocation(BPoint pt); + void SetDrawingMode(drawing_mode mode); + void SetLineMode(cap_mode capMode, join_mode joinMode, float miterLimit); + void SetPenSize(float size); + void SetForeColor(rgb_color color); + void SetBackColor(rgb_color color); + void SetStipplePattern(pattern p); + void SetScale(float scale); + void SetFontFamily(char *family); + void SetFontStyle(char *style); + void SetFontSpacing(int32 spacing); + void SetFontSize(float size); + void SetFontRotate(float rotation); + void SetFontEncoding(int32 encoding); + void SetFontFlags(int32 flags); + void SetFontShear(float shear); + void SetFontFace(int32 flags); + + static inline bool IsSame(const pattern &p1, const pattern &p2); + static inline bool IsSame(const rgb_color &c1, const rgb_color &c2); + + private: + + class State + { + public: + State *prev; + BFont beFont; + int font; + PDFSystem pdfSystem; + float penX; + float penY; + drawing_mode drawingMode; + rgb_color foregroundColor; + rgb_color backgroundColor; + rgb_color currentColor; + cap_mode capMode; + join_mode joinMode; + float miterLimit; + float penSize; + pattern pattern; + int32 fontSpacing; + + // initialize with defalt values + State(float h = a4_height, float x = 0, float y = 0) + { + static rgb_color white = {255, 255, 255, 255}; + static rgb_color black = {0, 0, 0, 255}; + prev = NULL; + font = 0; + pdfSystem.SetHeight(h); + pdfSystem.SetOrigin(x, y); + penX = 0; + penY = 0; + drawingMode = B_OP_COPY; + foregroundColor = white; + backgroundColor = black; + currentColor = black; + capMode = B_BUTT_CAP; + joinMode = B_MITER_JOIN; + miterLimit = B_DEFAULT_MITER_LIMIT; + penSize = 1; + pattern = B_SOLID_HIGH; + fontSpacing = B_STRING_SPACING; + } + + State(State *prev) + { + *this = *prev; + this->prev = prev; + } + }; + + class Font + { + public: + Font(char *n, int f, font_encoding e) : name(n), font(f), encoding(e) { } + BString name; + int font; + font_encoding encoding; + }; + + class Pattern + { + public: + pattern pat; + rgb_color lowColor, highColor; + int patternId; + + Pattern(const pattern &p, rgb_color low, rgb_color high, int id) + : pat(p) + , lowColor(low) + , highColor(high) + , patternId(id) + {}; + + inline bool Matches(const pattern &p, rgb_color low, rgb_color high) const { + return IsSame(pat, p) && IsSame(lowColor, low) && IsSame(highColor, high); + }; + }; + + FILE *fLog; + PDF *fPdf; + int32 fPage; + State *fState; + int32 fStateDepth; + TList fFontCache; + TList fPatterns; + int64 fEmbedMaxFontSize; + BScreen *fScreen; + Fonts *fFonts; + bool fCreateWebLinks; + bool fCreateBookmarks; + Bookmark *fBookmark; + bool fCreateXRefs; + XRefDefs *fXRefs; + XRefDests *fXRefDests; + font_encoding fFontSearchOrder[no_of_cjk_encodings]; + TextLine fTextLine; + + enum + { + kDrawingMode, + kClippingMode + } fMode; + + inline float tx(float x) { return fState->pdfSystem.tx(x); } + inline float ty(float y) { return fState->pdfSystem.ty(y); } + inline float scale(float f) { return fState->pdfSystem.scale(f); } + + PDFSystem* pdfSystem() const { return &fState->pdfSystem; } + + enum + { + kStroke = true, + kFill = false + }; + +#if PATTERN_SUPPORT + inline bool MakesPattern() { return Pass() == 0; } + inline bool MakesPDF() { return Pass() == 1; } +#else + inline bool MakesPattern() { return false; } + inline bool MakesPDF() { return true; } +#endif + inline bool IsDrawing() const { return fMode == kDrawingMode; } + inline bool IsClipping() const { return fMode == kClippingMode; } + + inline float PenSize() const { return fState->penSize; } + inline cap_mode LineCapMode() const { return fState->capMode; } + inline join_mode LineJoinMode() const { return fState->joinMode; } + inline float LineMiterLimit() const { return fState->miterLimit; } + + bool StoreTranslatorBitmap(BBitmap *bitmap, const char *filename, uint32 type); + + void GetFontName(BFont *font, char *fontname, bool &embed, font_encoding encoding); + int FindFont(char *fontname, bool embed, font_encoding encoding); + + void PushInternalState(); + bool PopInternalState(); + + void SetColor(rgb_color toSet); + void SetColor(); + void CreatePattern(); + int FindPattern(); + void SetPattern(); + + void StrokeOrClip(); + void FillOrClip(); + void Paint(bool stroke); + void PaintShape(BShape *shape, bool stroke); + void PaintRoundRect(BRect rect, BPoint radii, bool stroke); + void PaintArc(BPoint center, BPoint radii, float startTheta, float arcTheta, int stroke); + void PaintEllipse(BPoint center, BPoint radii, bool stroke); +}; + + + +// PDFLib C callbacks class instance redirectors +size_t _WriteData(PDF *p, void *data, size_t size); +void _ErrorHandler(PDF *p, int type, const char *msg); + +#endif // #if PDFWRITER_H diff --git a/src/add-ons/print/drivers/pdf/source/PDFWriter.rsrc b/src/add-ons/print/drivers/pdf/source/PDFWriter.rsrc new file mode 100644 index 0000000000..a0ae8d9cf0 Binary files /dev/null and b/src/add-ons/print/drivers/pdf/source/PDFWriter.rsrc differ diff --git a/src/add-ons/print/drivers/pdf/source/PageSetupWindow.cpp b/src/add-ons/print/drivers/pdf/source/PageSetupWindow.cpp new file mode 100644 index 0000000000..7ae5b8a5fc --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/PageSetupWindow.cpp @@ -0,0 +1,580 @@ +/* + +PDF Writer printer driver. + +Version: 12.19.2000 + +Copyright (c) 2001 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#include +#include +#include "pdflib.h" // for pageFormat constants +#include "PrinterDriver.h" +#include "PageSetupWindow.h" + +#include "MarginView.h" +#include "PrinterSettings.h" +#include "FontsWindow.h" +#include "AdvancedSettingsWindow.h" + +// static global variables +static struct +{ + char *label; + float width; + float height; +} pageFormat[] = +{ + {"Letter", letter_width, letter_height }, + {"Legal", legal_width, legal_height }, + {"Ledger", ledger_width, ledger_height }, + {"p11x17", p11x17_width, p11x17_height }, + {"A0", a0_width, a0_height }, + {"A1", a1_width, a1_height }, + {"A2", a2_width, a2_height }, + {"A3", a3_width, a3_height }, + {"A4", a4_width, a4_height }, + {"A5", a5_width, a5_height }, + {"A6", a6_width, a6_height }, + {"B5", b5_width, b5_height }, + {NULL, 0.0, 0.0 } +}; + + +static struct +{ + char *label; + int32 orientation; +} orientation[] = +{ + {"Portrait", PrinterDriver::PORTRAIT_ORIENTATION}, + {"Landscape", PrinterDriver::LANDSCAPE_ORIENTATION}, + {NULL, 0} +}; + +static const char *pdf_compatibility[] = {"1.2", "1.3", "1.4", NULL}; + +/** + * Constuctor + * + * @param + * @return + */ +PageSetupWindow::PageSetupWindow(BMessage *msg, const char *printerName) + : HWindow(BRect(0,0,400,220), "Page Setup", B_TITLED_WINDOW_LOOK, + B_MODAL_APP_WINDOW_FEEL, B_NOT_RESIZABLE | B_NOT_MINIMIZABLE | + B_NOT_ZOOMABLE) +{ + fSetupMsg = msg; + fExitSem = create_sem(0, "PageSetup"); + fResult = B_ERROR; + fAdvancedSettings = *msg; + + if ( printerName ) { + BString title; + + title << printerName << " Page Setup"; + SetTitle( title.String() ); + + // save the printer name + fPrinterDirName = printerName; + } + + // ---- Ok, build a default page setup user interface + BRect r; + BBox *panel; + BButton *button; + float x, y, w, h; + int i; + BMenuItem *item; + float width, height; + int32 orient; + BRect page; + BRect margin(0,0,0,0); + int32 units; + int32 compression; + BString setting_value; + + // load orientation + fSetupMsg->FindInt32("orientation", &orient); +// (new BAlert("", "orientation not in msg", "Shit"))->Go(); + + // load page rect + fSetupMsg->FindRect("paper_rect", &r); + width = r.Width(); + height = r.Height(); + page = r; + + // Load compression + fSetupMsg->FindInt32("pdf_compression", &compression); + + // Load units + fSetupMsg->FindInt32("units", &units); + + // Load printable rect + fSetupMsg->FindRect("printable_rect", &margin); + + // Load pdf compatability + fSetupMsg->FindString("pdf_compatibility", &setting_value); + + // Load font settings + fFonts = new Fonts(); + fFonts->CollectFonts(); + BMessage fonts; + if (fSetupMsg->FindMessage("fonts", &fonts) == B_OK) { + fFonts->SetTo(&fonts); + } + + // add a *dialog* background + r = Bounds(); + panel = new BBox(r, "top_panel", B_FOLLOW_ALL, + B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP, + B_PLAIN_BORDER); + + ////////////// Create the margin view ////////////////////// + + // re-calculate the margin from the printable rect in points + margin.top -= page.top; + margin.left -= page.left; + margin.right = page.right - margin.right; + margin.bottom = page.bottom - margin.bottom; + + fMarginView = new MarginView(BRect(20,20,200,160), width, height, + margin, units); + panel->AddChild(fMarginView); + + // add page format menu + // Simon Changed to OFFSET popups + x = r.left + kMargin * 2 + kOffset; y = r.top + kMargin * 2; + + BPopUpMenu* m = new BPopUpMenu("page_size"); + m->SetRadioMode(true); + + // Simon changed width 200->140 + BMenuField *mf = new BMenuField(BRect(x, y, x + 140, y + 20), "page_size", + "Page Size:", m); + fPageSizeMenu = mf; + mf->ResizeToPreferred(); + mf->GetPreferredSize(&w, &h); + + // Simon added: SetDivider + mf->SetDivider(be_plain_font->StringWidth("Page Size#")); + + panel->AddChild(mf); + + item = NULL; + for (i = 0; pageFormat[i].label != NULL; i++) + { + BMessage* msg = new BMessage('pgsz'); + msg->AddFloat("width", pageFormat[i].width); + msg->AddFloat("height", pageFormat[i].height); + BMenuItem* mi = new BMenuItem(pageFormat[i].label, msg); + m->AddItem(mi); + + if (width == pageFormat[i].width && height == pageFormat[i].height) { + item = mi; + } + if (height == pageFormat[i].width && width == pageFormat[i].height) { + item = mi; + } + } + mf->Menu()->SetLabelFromMarked(true); + if (!item) { + item = m->ItemAt(0); + } + item->SetMarked(true); + mf->MenuItem()->SetLabel(item->Label()); + + // add orientation menu + y += h + kMargin; + + m = new BPopUpMenu("orientation"); + m->SetRadioMode(true); + + // Simon changed 200->140 + mf = new BMenuField(BRect(x, y, x + 140, y + 20), "orientation", "Orientation:", m); + + // Simon added: SetDivider + mf->SetDivider(be_plain_font->StringWidth("Orientation#")); + + fOrientationMenu = mf; + mf->ResizeToPreferred(); + panel->AddChild(mf); + r.top += h; + item = NULL; + for (int i = 0; orientation[i].label != NULL; i++) + { + BMessage* msg = new BMessage('ornt'); + msg->AddInt32("orientation", orientation[i].orientation); + BMenuItem* mi = new BMenuItem(orientation[i].label, msg); + m->AddItem(mi); + + if (orient == orientation[i].orientation) { + item = mi; + } + } + mf->Menu()->SetLabelFromMarked(true); +// SHOULD BE REMOVED + if (!item) { + item = m->ItemAt(0); + } +/////////////////// + item->SetMarked(true); + mf->MenuItem()->SetLabel(item->Label()); + + // add PDF comptibility menu + y += h + kMargin; + + m = new BPopUpMenu("pdf_compatibility"); + m->SetRadioMode(true); + mf = new BMenuField(BRect(x, y, x + 200, y + 20), "pdf_compatibility", "PDF Compatibility:", m); + fPDFCompatibilityMenu = mf; + mf->ResizeToPreferred(); + panel->AddChild(mf); + r.top += h; + + item = NULL; + for (int i = 0; pdf_compatibility[i] != NULL; i++) + { + BMenuItem* mi = new BMenuItem(pdf_compatibility[i], NULL); + m->AddItem(mi); + +//(new BAlert("", setting_value.String(), pdf_compatibility[i]))->Go(); + if (setting_value == pdf_compatibility[i]) { + item = mi; + } + } + + mf->Menu()->SetLabelFromMarked(true); + +/// SHOULD BE REMOVED + if (!item) { + item = m->ItemAt(0); + } +//////////////////// + + item->SetMarked(true); + mf->MenuItem()->SetLabel(item->Label()); + + // add PDF compression slider + y += h + kMargin; + + BSlider * slider = new BSlider(BRect(x, y, panel->Bounds().right - kMargin, y + 20), "pdf_compression", + "Compression:", + NULL, 0, 9); + fPDFCompressionSlider = slider; + + panel->AddChild(slider); + + slider->SetLimitLabels("None", "Best"); + slider->SetHashMarks(B_HASH_MARKS_BOTTOM); + slider->ResizeToPreferred(); + slider->GetPreferredSize(&w, &h); + + slider->SetValue(compression); + + // add a "OK" button, and make it default + button = new BButton(r, NULL, "OK", new BMessage(OK_MSG), + B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + button->ResizeToPreferred(); + button->GetPreferredSize(&w, &h); + x = r.right - w - 8; + y = r.bottom - h - 8; + button->MoveTo(x, y); + panel->AddChild(button); + button->MakeDefault(true); + + // add a "Cancel button + button = new BButton(r, NULL, "Cancel", new BMessage(CANCEL_MSG), + B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + button->GetPreferredSize(&w, &h); + button->ResizeToPreferred(); + button->MoveTo(x - w - 8, y); + panel->AddChild(button); + + // add a "Fonts" button + button = new BButton(r, NULL, "Fonts", new BMessage(FONTS_MSG), + B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + button->GetPreferredSize(&w, &h); + button->ResizeToPreferred(); + button->MoveTo(r.left + 8, y); + panel->AddChild(button); + + // add a "Fonts" button + BButton* font = button; + button = new BButton(r, NULL, "Advanced", new BMessage(ADVANCED_MSG), + B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + button->GetPreferredSize(&w, &h); + button->ResizeToPreferred(); + button->MoveTo(font->Frame().right + 8, y); + panel->AddChild(button); + + // add a separator line... + BBox * line = new BBox(BRect(r.left, y - 9, r.right, y - 8), NULL, + B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM ); + panel->AddChild(line); + + // Finally, add our panel to window + AddChild(panel); +} + + +// -------------------------------------------------- +PageSetupWindow::~PageSetupWindow() +{ + delete_sem(fExitSem); + delete fFonts; +} + + +// -------------------------------------------------- +bool +PageSetupWindow::QuitRequested() +{ + release_sem(fExitSem); + return true; +} + + +// -------------------------------------------------- +void +PageSetupWindow::UpdateSetupMessage() +{ + BMenuItem *item; + int32 orientation = 0; + + item = fOrientationMenu->Menu()->FindMarked(); + if (item) { + BMessage *msg = item->Message(); + msg->FindInt32("orientation", &orientation); + fSetupMsg->ReplaceInt32("orientation", orientation); + } + + item = fPDFCompatibilityMenu->Menu()->FindMarked(); + if (item) { + if (fSetupMsg->HasString("pdf_compatibility")) + fSetupMsg->ReplaceString("pdf_compatibility", item->Label()); + else + fSetupMsg->AddString("pdf_compatibility", item->Label()); + } + + if (fSetupMsg->HasInt32("pdf_compression")) { + fSetupMsg->ReplaceInt32("pdf_compression", fPDFCompressionSlider->Value()); + } else { + fSetupMsg->AddInt32("pdf_compression", fPDFCompressionSlider->Value()); + } + + item = fPageSizeMenu->Menu()->FindMarked(); + if (item) { + float w, h; + BMessage *msg = item->Message(); + msg->FindFloat("width", &w); + msg->FindFloat("height", &h); + BRect r; + if (orientation == 0) + r.Set(0, 0, w, h); + else + r.Set(0, 0, h, w); + fSetupMsg->ReplaceRect("paper_rect", r); + + // Save the printable_rect + BRect margin = fMarginView->GetMargin(); + if (orientation == 0) { + margin.right = w - margin.right; + margin.bottom = h - margin.bottom; + } else { + margin.right = h - margin.right; + margin.bottom = w - margin.bottom; + } + fSetupMsg->ReplaceRect("printable_rect", margin); + + // save the units used + int32 units = fMarginView->GetUnits(); + if (fSetupMsg->HasInt32("units")) { + fSetupMsg->ReplaceInt32("units", units); + } else { + fSetupMsg->AddInt32("units", units); + } + } + + BMessage fonts; + if (B_OK == fFonts->Archive(&fonts)) { + if (fSetupMsg->HasMessage("fonts")) { + fSetupMsg->ReplaceMessage("fonts", &fonts); + } else { + fSetupMsg->AddMessage("fonts", &fonts); + } + } + + // advanced settings + bool b; + float f; + BString s; + + if (fAdvancedSettings.FindBool("create_web_links", &b) == B_OK) { + if (fSetupMsg->HasBool("create_web_links")) { + fSetupMsg->ReplaceBool("create_web_links", b); + } else { + fSetupMsg->AddBool("create_web_links", b); + } + } + + if (fAdvancedSettings.FindFloat("link_border_width", &f) == B_OK) { + if (fSetupMsg->HasFloat("link_border_width")) { + fSetupMsg->ReplaceFloat("link_border_width", f); + } else { + fSetupMsg->AddFloat("link_border_width", f); + } + } + + if (fAdvancedSettings.FindBool("create_bookmarks", &b) == B_OK) { + if (fSetupMsg->HasBool("create_bookmarks")) { + fSetupMsg->ReplaceBool("create_bookmarks", b); + } else { + fSetupMsg->AddBool("create_bookmarks", b); + } + } + + if (fAdvancedSettings.FindString("bookmark_definition_file", &s) == B_OK) { + if (fSetupMsg->HasString("bookmark_definition_file")) { + fSetupMsg->ReplaceString("bookmark_definition_file", s.String()); + } else { + fSetupMsg->AddString("bookmark_definition_file", s.String()); + } + } + + if (fAdvancedSettings.FindBool("create_xrefs", &b) == B_OK) { + if (fSetupMsg->HasBool("create_xrefs")) { + fSetupMsg->ReplaceBool("create_xrefs", b); + } else { + fSetupMsg->AddBool("create_xrefs", b); + } + } + + if (fAdvancedSettings.FindString("xrefs_file", &s) == B_OK) { + if (fSetupMsg->HasString("xrefs_file")) { + fSetupMsg->ReplaceString("xrefs_file", s.String()); + } else { + fSetupMsg->AddString("xrefs_file", s.String()); + } + } + + // save the settings to be new defaults + PrinterSettings *ps = new PrinterSettings(fPrinterDirName.String()); + if (ps->InitCheck() == B_OK) { + ps->WriteSettings(fSetupMsg); + } + delete ps; +} + + +// -------------------------------------------------- +void +PageSetupWindow::MessageReceived(BMessage *msg) +{ + switch (msg->what){ + case OK_MSG: + UpdateSetupMessage(); + fResult = B_OK; + release_sem(fExitSem); + break; + + case CANCEL_MSG: + fResult = B_ERROR; + release_sem(fExitSem); + break; + + // Simon added + case 'pgsz': + { + float w, h; + msg->FindFloat("width", &w); + msg->FindFloat("height", &h); + BMenuItem *item = fOrientationMenu->Menu()->FindMarked(); + if (item) { + int32 orientation = 0; + BMessage *m = item->Message(); + m->FindInt32("orientation", &orientation); + if (orientation == PrinterDriver::PORTRAIT_ORIENTATION) { + fMarginView->SetPageSize(w, h); + } else { + fMarginView->SetPageSize(h, w); + } + fMarginView->UpdateView(MARGIN_CHANGED); + } + } + break; + + // Simon added + case 'ornt': + { + BPoint p = fMarginView->GetPageSize(); + int32 orientation; + msg->FindInt32("orientation", &orientation); + if (orientation == PrinterDriver::LANDSCAPE_ORIENTATION + && p.y > p.x) { + fMarginView->SetPageSize(p.y, p.x); + fMarginView->UpdateView(MARGIN_CHANGED); + } + if (orientation == PrinterDriver::PORTRAIT_ORIENTATION + && p.x > p.y) { + fMarginView->SetPageSize(p.y, p.x); + fMarginView->UpdateView(MARGIN_CHANGED); + } + } + break; + + case FONTS_MSG: + (new FontsWindow(fFonts))->Show(); + break; + + case ADVANCED_MSG: + (new AdvancedSettingsWindow(&fAdvancedSettings))->Show(); + break; + + default: + inherited::MessageReceived(msg); + break; + } +} + + +// -------------------------------------------------- +status_t +PageSetupWindow::Go() +{ + MoveTo(300,300); + Show(); + acquire_sem(fExitSem); + Lock(); + Quit(); + + return fResult; +} + + diff --git a/src/add-ons/print/drivers/pdf/source/PageSetupWindow.h b/src/add-ons/print/drivers/pdf/source/PageSetupWindow.h new file mode 100644 index 0000000000..9038444560 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/PageSetupWindow.h @@ -0,0 +1,95 @@ +/* + +PDF Writer printer driver. + +Copyright (c) 2001 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef PAGESETUPWINDOW_H +#define PAGESETUPWINDOW_H + +#include +#include +#include +#include +#include +#include +#include +#include "Utils.h" +#include "Fonts.h" + +class MarginView; + +class PageSetupWindow : public HWindow +{ +public: + // Constructors, destructors, operators... + + PageSetupWindow(BMessage *msg, const char *printerName = NULL); + ~PageSetupWindow(); + + typedef HWindow inherited; + + // public constantes + enum { + OK_MSG = 'ok__', + CANCEL_MSG = 'cncl', + FONTS_MSG = 'font', + ADVANCED_MSG = 'advc' + }; + + // Virtual function overrides +public: + virtual void MessageReceived(BMessage *msg); + virtual bool QuitRequested(); + status_t Go(); + + // From here, it's none of your business! ;-) +private: + long fExitSem; + status_t fResult; + BMessage * fSetupMsg; + BMenuField * fPageSizeMenu; + BMenuField * fOrientationMenu; + BMenuField * fPDFCompatibilityMenu; + BSlider * fPDFCompressionSlider; + Fonts * fFonts; + BMessage fAdvancedSettings; + + void UpdateSetupMessage(); + + MarginView * fMarginView; + + // used for saving settings + BString fPrinterDirName; + + //private class constants + static const int kMargin = 10; + static const int kOffset = 200; +}; + +#endif diff --git a/src/add-ons/print/drivers/pdf/source/PictureIterator.cpp b/src/add-ons/print/drivers/pdf/source/PictureIterator.cpp new file mode 100644 index 0000000000..f23c47a591 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/PictureIterator.cpp @@ -0,0 +1,151 @@ +/* + +PDF Writer printer driver. + +Copyright (c) 2001, 2002 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#include "PictureIterator.h" + +// BPicture playback handlers class instance redirectors +static void _MovePenBy(void *p, BPoint delta) { return ((PictureIterator *) p)->MovePenBy(delta); } +static void _StrokeLine(void *p, BPoint start, BPoint end) { return ((PictureIterator *) p)->StrokeLine(start, end); } +static void _StrokeRect(void *p, BRect rect) { return ((PictureIterator *) p)->StrokeRect(rect); } +static void _FillRect(void *p, BRect rect) { return ((PictureIterator *) p)->FillRect(rect); } +static void _StrokeRoundRect(void *p, BRect rect, BPoint radii) { return ((PictureIterator *) p)->StrokeRoundRect(rect, radii); } +static void _FillRoundRect(void *p, BRect rect, BPoint radii) { return ((PictureIterator *) p)->FillRoundRect(rect, radii); } +static void _StrokeBezier(void *p, BPoint *control) { return ((PictureIterator *) p)->StrokeBezier(control); } +static void _FillBezier(void *p, BPoint *control) { return ((PictureIterator *) p)->FillBezier(control); } +static void _StrokeArc(void *p, BPoint center, BPoint radii, float startTheta, float arcTheta) { return ((PictureIterator *) p)->StrokeArc(center, radii, startTheta, arcTheta); } +static void _FillArc(void *p, BPoint center, BPoint radii, float startTheta, float arcTheta) { return ((PictureIterator *) p)->FillArc(center, radii, startTheta, arcTheta); } +static void _StrokeEllipse(void *p, BPoint center, BPoint radii) { return ((PictureIterator *) p)->StrokeEllipse(center, radii); } +static void _FillEllipse(void *p, BPoint center, BPoint radii) { return ((PictureIterator *) p)->FillEllipse(center, radii); } +static void _StrokePolygon(void *p, int32 numPoints, BPoint *points, bool isClosed) { return ((PictureIterator *) p)->StrokePolygon(numPoints, points, isClosed); } +static void _FillPolygon(void *p, int32 numPoints, BPoint *points, bool isClosed) { return ((PictureIterator *) p)->FillPolygon(numPoints, points, isClosed); } +static void _StrokeShape(void * p, BShape *shape) { return ((PictureIterator *) p)->StrokeShape(shape); } +static void _FillShape(void * p, BShape *shape) { return ((PictureIterator *) p)->FillShape(shape); } +static void _DrawString(void *p, char *string, float deltax, float deltay) { return ((PictureIterator *) p)->DrawString(string, deltax, deltay); } +static void _DrawPixels(void *p, BRect src, BRect dest, int32 width, int32 height, int32 bytesPerRow, int32 pixelFormat, int32 flags, void *data) + { return ((PictureIterator *) p)->DrawPixels(src, dest, width, height, bytesPerRow, pixelFormat, flags, data); } +static void _SetClippingRects(void *p, BRect *rects, uint32 numRects) { return ((PictureIterator *) p)->SetClippingRects(rects, numRects); } +static void _ClipToPicture(void * p, BPicture *picture, BPoint point, bool clip_to_inverse_picture) { return ((PictureIterator *) p)->ClipToPicture(picture, point, clip_to_inverse_picture); } +static void _PushState(void *p) { return ((PictureIterator *) p)->PushState(); } +static void _PopState(void *p) { return ((PictureIterator *) p)->PopState(); } +static void _EnterStateChange(void *p) { return ((PictureIterator *) p)->EnterStateChange(); } +static void _ExitStateChange(void *p) { return ((PictureIterator *) p)->ExitStateChange(); } +static void _EnterFontState(void *p) { return ((PictureIterator *) p)->EnterFontState(); } +static void _ExitFontState(void *p) { return ((PictureIterator *) p)->ExitFontState(); } +static void _SetOrigin(void *p, BPoint pt) { return ((PictureIterator *) p)->SetOrigin(pt); } +static void _SetPenLocation(void *p, BPoint pt) { return ((PictureIterator *) p)->SetPenLocation(pt); } +static void _SetDrawingMode(void *p, drawing_mode mode) { return ((PictureIterator *) p)->SetDrawingMode(mode); } +static void _SetLineMode(void *p, cap_mode capMode, join_mode joinMode, float miterLimit) { return ((PictureIterator *) p)->SetLineMode(capMode, joinMode, miterLimit); } +static void _SetPenSize(void *p, float size) { return ((PictureIterator *) p)->SetPenSize(size); } +static void _SetForeColor(void *p, rgb_color color) { return ((PictureIterator *) p)->SetForeColor(color); } +static void _SetBackColor(void *p, rgb_color color) { return ((PictureIterator *) p)->SetBackColor(color); } +static void _SetStipplePattern(void *p, pattern pat) { return ((PictureIterator *) p)->SetStipplePattern(pat); } +static void _SetScale(void *p, float scale) { return ((PictureIterator *) p)->SetScale(scale); } +static void _SetFontFamily(void *p, char *family) { return ((PictureIterator *) p)->SetFontFamily(family); } +static void _SetFontStyle(void *p, char *style) { return ((PictureIterator *) p)->SetFontStyle(style); } +static void _SetFontSpacing(void *p, int32 spacing) { return ((PictureIterator *) p)->SetFontSpacing(spacing); } +static void _SetFontSize(void *p, float size) { return ((PictureIterator *) p)->SetFontSize(size); } +static void _SetFontRotate(void *p, float rotation) { return ((PictureIterator *) p)->SetFontRotate(rotation); } +static void _SetFontEncoding(void *p, int32 encoding) { return ((PictureIterator *) p)->SetFontEncoding(encoding); } +static void _SetFontFlags(void *p, int32 flags) { return ((PictureIterator *) p)->SetFontFlags(flags); } +static void _SetFontShear(void *p, float shear) { return ((PictureIterator *) p)->SetFontShear(shear); } +static void _SetFontFace(void * p, int32 flags) { return ((PictureIterator *) p)->SetFontFace(flags); } + +// undefined or undocumented operation handlers... +static void _op0(void * p) { return ((PictureIterator *) p)->Op(0); } +static void _op19(void * p) { return ((PictureIterator *) p)->Op(19); } +static void _op45(void * p) { return ((PictureIterator *) p)->Op(45); } +static void _op47(void * p) { return ((PictureIterator *) p)->Op(47); } +static void _op48(void * p) { return ((PictureIterator *) p)->Op(48); } +static void _op49(void * p) { return ((PictureIterator *) p)->Op(49); } + +// Private Variables +// ----------------- + +static void * +playbackHandlers[] = { + _op0, // 0 no operation + _MovePenBy, // 1 MovePenBy(void *user, BPoint delta) + _StrokeLine, // 2 StrokeLine(void *user, BPoint start, BPoint end) + _StrokeRect, // 3 StrokeRect(void *user, BRect rect) + _FillRect, // 4 FillRect(void *user, BRect rect) + _StrokeRoundRect, // 5 StrokeRoundRect(void *user, BRect rect, BPoint radii) + _FillRoundRect, // 6 FillRoundRect(void *user, BRect rect, BPoint radii) + _StrokeBezier, // 7 StrokeBezier(void *user, BPoint *control) + _FillBezier, // 8 FillBezier(void *user, BPoint *control) + _StrokeArc, // 9 StrokeArc(void *user, BPoint center, BPoint radii, float startTheta, float arcTheta) + _FillArc, // 10 FillArc(void *user, BPoint center, BPoint radii, float startTheta, float arcTheta) + _StrokeEllipse, // 11 StrokeEllipse(void *user, BPoint center, BPoint radii) + _FillEllipse, // 12 FillEllipse(void *user, BPoint center, BPoint radii) + _StrokePolygon, // 13 StrokePolygon(void *user, int32 numPoints, BPoint *points, bool isClosed) + _FillPolygon, // 14 FillPolygon(void *user, int32 numPoints, BPoint *points, bool isClosed) + _StrokeShape, // 15 StrokeShape(void *user, BShape *shape) + _FillShape, // 16 FillShape(void *user, BShape *shape) + _DrawString, // 17 DrawString(void *user, char *string, float deltax, float deltay) + _DrawPixels, // 18 DrawPixels(void *user, BRect src, BRect dest, int32 width, int32 height, int32 bytesPerRow, int32 pixelFormat, int32 flags, void *data) + _op19, // 19 *reserved* + _SetClippingRects, // 20 SetClippingRects(void *user, BRect *rects, uint32 numRects) + _ClipToPicture, // 21 ClipToPicture(void *user, BPicture *picture, BPoint pt, bool clip_to_inverse_picture) + _PushState, // 22 PushState(void *user) + _PopState, // 23 PopState(void *user) + _EnterStateChange, // 24 EnterStateChange(void *user) + _ExitStateChange, // 25 ExitStateChange(void *user) + _EnterFontState, // 26 EnterFontState(void *user) + _ExitFontState, // 27 ExitFontState(void *user) + _SetOrigin, // 28 SetOrigin(void *user, BPoint pt) + _SetPenLocation, // 29 SetPenLocation(void *user, BPoint pt) + _SetDrawingMode, // 30 SetDrawingMode(void *user, drawing_mode mode) + _SetLineMode, // 31 SetLineMode(void *user, cap_mode capMode, join_mode joinMode, float miterLimit) + _SetPenSize, // 32 SetPenSize(void *user, float size) + _SetForeColor, // 33 SetForeColor(void *user, rgb_color color) + _SetBackColor, // 34 SetBackColor(void *user, rgb_color color) + _SetStipplePattern, // 35 SetStipplePattern(void *user, pattern p) + _SetScale, // 36 SetScale(void *user, float scale) + _SetFontFamily, // 37 SetFontFamily(void *user, char *family) + _SetFontStyle, // 38 SetFontStyle(void *user, char *style) + _SetFontSpacing, // 39 SetFontSpacing(void *user, int32 spacing) + _SetFontSize, // 40 SetFontSize(void *user, float size) + _SetFontRotate, // 41 SetFontRotate(void *user, float rotation) + _SetFontEncoding, // 42 SetFontEncoding(void *user, int32 encoding) + _SetFontFlags, // 43 SetFontFlags(void *user, int32 flags) + _SetFontShear, // 44 SetFontShear(void *user, float shear) + _op45, // 45 *reserved* + _SetFontFace, // 46 SetFontFace(void *user, int32 flags) + _op47, + _op48, + _op49, + + NULL + }; + +void +PictureIterator::Iterate(BPicture* picture) { + picture->Play(playbackHandlers, 50, this); +} diff --git a/src/add-ons/print/drivers/pdf/source/PictureIterator.h b/src/add-ons/print/drivers/pdf/source/PictureIterator.h new file mode 100644 index 0000000000..dfdfbc57b7 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/PictureIterator.h @@ -0,0 +1,93 @@ +/* + +PDF Writer printer driver. + +Copyright (c) 2001, 2002 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef _PICTURE_ITERATOR_H +#define _PICTURE_TIERATOR_H + +#include +#include + +class PictureIterator +{ +public: + virtual ~PictureIterator() { } + + // BPicture playback handlers + virtual void Op(int number) { } + virtual void MovePenBy(BPoint delta) { } + virtual void StrokeLine(BPoint start, BPoint end) { } + virtual void StrokeRect(BRect rect) { } + virtual void FillRect(BRect rect) { } + virtual void StrokeRoundRect(BRect rect, BPoint radii) { } + virtual void FillRoundRect(BRect rect, BPoint radii) { } + virtual void StrokeBezier(BPoint *control) { } + virtual void FillBezier(BPoint *control) { } + virtual void StrokeArc(BPoint center, BPoint radii, float startTheta, float arcTheta) { } + virtual void FillArc(BPoint center, BPoint radii, float startTheta, float arcTheta) { } + virtual void StrokeEllipse(BPoint center, BPoint radii) { } + virtual void FillEllipse(BPoint center, BPoint radii) { } + virtual void StrokePolygon(int32 numPoints, BPoint *points, bool isClosed) { } + virtual void FillPolygon(int32 numPoints, BPoint *points, bool isClosed) { } + virtual void StrokeShape(BShape *shape) { } + virtual void FillShape(BShape *shape) { } + virtual void DrawString(char *string, float escapement_nospace, float escapement_space) { } + virtual void DrawPixels(BRect src, BRect dest, int32 width, int32 height, int32 bytesPerRow, int32 pixelFormat, int32 flags, void *data) { } + virtual void SetClippingRects(BRect *rects, uint32 numRects) { } + virtual void ClipToPicture(BPicture *picture, BPoint point, bool clip_to_inverse_picture) { } + virtual void PushState() { } + virtual void PopState() { } + virtual void EnterStateChange() { } + virtual void ExitStateChange() { } + virtual void EnterFontState() { } + virtual void ExitFontState() { } + virtual void SetOrigin(BPoint pt) { } + virtual void SetPenLocation(BPoint pt) { } + virtual void SetDrawingMode(drawing_mode mode) { } + virtual void SetLineMode(cap_mode capMode, join_mode joinMode, float miterLimit) { } + virtual void SetPenSize(float size) { } + virtual void SetForeColor(rgb_color color) { } + virtual void SetBackColor(rgb_color color) { } + virtual void SetStipplePattern(pattern p) { } + virtual void SetScale(float scale) { } + virtual void SetFontFamily(char *family) { } + virtual void SetFontStyle(char *style) { } + virtual void SetFontSpacing(int32 spacing) { } + virtual void SetFontSize(float size) { } + virtual void SetFontRotate(float rotation) { } + virtual void SetFontEncoding(int32 encoding) { } + virtual void SetFontFlags(int32 flags) { } + virtual void SetFontShear(float shear) { } + virtual void SetFontFace(int32 flags) { } + + virtual void Iterate(BPicture* picture); +}; + +#endif _PICTURE_ITERATOR_H diff --git a/src/add-ons/print/drivers/pdf/source/PrinterDriver.cpp b/src/add-ons/print/drivers/pdf/source/PrinterDriver.cpp new file mode 100644 index 0000000000..89dac44284 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/PrinterDriver.cpp @@ -0,0 +1,429 @@ +/* + +PDF Writer printer driver. + +Copyright (c) 2001 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + + +#include +#include // for memset() + +#include + +#include "PrinterDriver.h" + +#include "PrinterSetupWindow.h" +#include "PageSetupWindow.h" +#include "JobSetupWindow.h" +#include "StatusWindow.h" +#include "PrinterSettings.h" +#include "Report.h" + +// Private prototypes +// ------------------ + +#ifdef CODEWARRIOR + #pragma mark [Constructor & destructor] +#endif + +// Constructor & destructor +// ------------------------ + +// -------------------------------------------------- +PrinterDriver::PrinterDriver() + : fJobFile(NULL), + fPrinterNode(NULL), + fJobMsg(NULL), + + fTransport(NULL), + fTransportAddOn(-1), + fTransportInitProc(NULL), + fTransportExitProc(NULL) +{ +} + + +// -------------------------------------------------- +PrinterDriver::~PrinterDriver() +{ +} + +#ifdef CODEWARRIOR + #pragma mark [Public methods] +#endif + +#ifdef B_BEOS_VERSION_DANO +struct print_file_header { + int32 version; + int32 page_count; + off_t first_page; + int32 _reserved_3_; + int32 _reserved_4_; + int32 _reserved_5_; +}; +#endif + +//void PrinterDriver::SimonStopPrinting() { +// printingProgress = false; +//} + +// Public methods +// -------------- + +status_t +PrinterDriver::PrintJob + ( + BFile *jobFile, // spool file + BNode *printerNode, // printer node, used by OpenTransport() to find & load transport add-on + BMessage *jobMsg // job message + ) +{ + print_file_header pfh; + status_t status; + BMessage *msg; + int32 page; + uint32 copy; + uint32 copies; +#if PATTERN_SUPPORT + const int32 passes = 2; +#else + const int32 passes = 1; +#endif + + fJobFile = jobFile; + fPrinterNode = printerNode; + fJobMsg = jobMsg; + + if (!fJobFile || !fPrinterNode) + return B_ERROR; + + // open transport + if (OpenTransport() != B_OK) { + return B_ERROR; + } + + // read print file header + fJobFile->Seek(0, SEEK_SET); + fJobFile->Read(&pfh, sizeof(pfh)); + + // read job message + fJobMsg = msg = new BMessage(); + msg->Unflatten(fJobFile); + + if (msg->HasInt32("copies")) { + copies = msg->FindInt32("copies"); + } else { + copies = 1; + } + + // force creation of Report object + Report::Instance(); + + // show status window + fStatusWindow = new StatusWindow(passes, pfh.page_count, this); + + status = BeginJob(); + + fPrinting = true; + for (fPass = 0; fPass < passes && status == B_OK && fPrinting; fPass++) { + for (copy = 0; copy < copies && status == B_OK && fPrinting; copy++) + { + for (page = 1; page <= pfh.page_count && status == B_OK && fPrinting; page++) { + fStatusWindow->PostMessage(new BMessage('page')); + status = PrintPage(page, pfh.page_count); + } + + // re-read job message for next page + fJobFile->Seek(sizeof(pfh), SEEK_SET); + msg->Unflatten(fJobFile); + } + } + + status_t s = EndJob(); + if (status == B_OK) status = s; + + CloseTransport(); + + delete fJobMsg; + + // close status window + if (Report::Instance()->CountItems() != 0) { + fStatusWindow->WaitForClose(); + } + if (fStatusWindow->Lock()) { + fStatusWindow->Quit(); + } + + // delete Report object + Report::Instance()->Free(); + + return status; +} + +/** + * This will stop the printing loop + * + * @param none + * @return void + */ +void +PrinterDriver::StopPrinting() +{ + fPrinting = false; +} + + +// -------------------------------------------------- +status_t +PrinterDriver::BeginJob() +{ + return B_OK; +} + + +// -------------------------------------------------- +status_t +PrinterDriver::PrintPage(int32 pageNumber, int32 pageCount) +{ + char text[128]; + + sprintf(text, "Faking print of page %ld/%ld...", pageNumber, pageCount); + BAlert *alert = new BAlert("PrinterDriver::PrintPage()", text, "Hmm?"); + alert->Go(); + return B_OK; +} + + +// -------------------------------------------------- +status_t +PrinterDriver::EndJob() +{ + return B_OK; +} + + +// -------------------------------------------------- +status_t +PrinterDriver::PrinterSetup(char *printerName) + // name of printer, to attach printer settings +{ + PrinterSetupWindow *psw; + + psw = new PrinterSetupWindow(printerName); + return psw->Go(); +} + + +// -------------------------------------------------- +status_t +PrinterDriver::PageSetup(BMessage *setupMsg, const char *printerName) +{ + /* + BRect paperRect; + BRect printRect; + + // const float kScale = 8.3333f; + const float kScreen = 72.0f; + const float kLetterWidth = 8.5; + const float kLetterHeight = 11; + + // set default value if property not set + if (!setupMsg->HasInt64("xres")) + setupMsg->AddInt64("xres", 360); + + if (!setupMsg->HasInt64("yres")) + setupMsg->AddInt64("yres", 360); + + if (!setupMsg->HasInt32("orientation")) + setupMsg->AddInt32("orientation", PORTRAIT_ORIENTATION); + + paperRect = BRect(0, 0, kLetterWidth * kScreen, kLetterHeight * kScreen); + printRect = BRect(0, 0, kLetterWidth * kScreen, kLetterHeight * kScreen); + + if (!setupMsg->HasRect("paper_rect")) + setupMsg->AddRect("paper_rect", paperRect); + + if (!setupMsg->HasRect("printable_rect")) + setupMsg->AddRect("printable_rect", printRect); + + */ + + // check to see if the messag is built correctly... + if (setupMsg->HasFloat("scaling") != B_OK) { + PrinterSettings *ps = new PrinterSettings(printerName); + + if (ps->InitCheck() == B_OK) { + // first read the settings from the spool dir + if (ps->ReadSettings(setupMsg) != B_OK) { + // if there were none, then create a default set... + ps->GetDefaults(setupMsg); + // ...and save them + ps->WriteSettings(setupMsg); + } + } else { +// Temp +//(new BAlert("", "Problem Loading Settings", "PrinterDriver"))->Go(); + } + } + + PageSetupWindow *psw; + + psw = new PageSetupWindow(setupMsg, printerName); + return psw->Go(); +} + + +// -------------------------------------------------- +status_t +PrinterDriver::JobSetup(BMessage *jobMsg, const char *printerName) +{ + // set default value if property not set + if (!jobMsg->HasInt32("copies")) + jobMsg->AddInt32("copies", 1); + + if (!jobMsg->HasInt32("first_page")) + jobMsg->AddInt32("first_page", 1); + + if (!jobMsg->HasInt32("last_page")) + jobMsg->AddInt32("last_page", MAX_INT32); + + JobSetupWindow * jsw; + + jsw = new JobSetupWindow(jobMsg, printerName); + return jsw->Go(); +} + + +// -------------------------------------------------- +status_t +PrinterDriver::OpenTransport() +{ + char buffer[512]; + BPath *path; + + + if (!fPrinterNode) + return B_ERROR; + + // first, find & load transport add-on + path = new BPath(); + + // find name of this printer transport add-on + fPrinterNode->ReadAttr("transport", B_STRING_TYPE, 0, buffer, sizeof(buffer)); + + // try first on user add-ons directory + find_directory(B_USER_ADDONS_DIRECTORY, path); + path->Append("Print/transport"); + path->Append(buffer); + fTransportAddOn = load_add_on(path->Path()); + + if (fTransportAddOn < 0) { + // add-on not in user add-ons directory. try system one + find_directory(B_BEOS_ADDONS_DIRECTORY, path); + path->Append("Print/transport"); + path->Append(buffer); + fTransportAddOn = load_add_on(path->Path()); + } + + if (fTransportAddOn < 0) { + BAlert * alert = new BAlert("Uh oh!", "Couldn't find transport add-on.", "OK"); + alert->Go(); + return B_ERROR; + } + + // get init & exit proc + get_image_symbol(fTransportAddOn, "init_transport", B_SYMBOL_TYPE_TEXT, (void **) &fTransportInitProc); + get_image_symbol(fTransportAddOn, "exit_transport", B_SYMBOL_TYPE_TEXT, (void **) &fTransportExitProc); + + if (!fTransportInitProc || !fTransportExitProc) { + BAlert * alert = new BAlert("Uh oh!", "Couldn't resolve transport symbols.", "OK"); + alert->Go(); + return B_ERROR; + } + + delete path; + + // now, init transport add-on + node_ref ref; + BDirectory dir; + + fPrinterNode->GetNodeRef(&ref); + dir.SetTo(&ref); + + path = new BPath(&dir, NULL); + strcpy(buffer, path->Path()); + + // create BMessage for init_transport() + BMessage *msg = new BMessage('TRIN'); + msg->AddString("printer_file", buffer); + + fTransport = (*fTransportInitProc)(msg); + + delete msg; + delete path; + + // The BeOS "Print To File" transport returns a non-NULL BDataIO * + // even after user filepanel cancellation! + BFile* file = dynamic_cast(fTransport); + if (file && file->InitCheck() != B_OK) + // Quietly return + return B_ERROR; + + if (fTransport == 0) { + BAlert *alert = new BAlert("Uh oh!", "Couldn't open transport.", "OK"); + alert->Go(); + return B_ERROR; + } + + return B_OK; +} + + +// -------------------------------------------------- +status_t +PrinterDriver::CloseTransport() +{ + if (!fTransportAddOn) + return B_ERROR; + + if (fTransportExitProc) + (*fTransportExitProc)(); + + unload_add_on(fTransportAddOn); + fTransportAddOn = 0; + fTransport = NULL; + + return B_OK; +} + +#ifdef CODEWARRIOR + #pragma mark [Privates routines] +#endif + +// Private routines +// ---------------- diff --git a/src/add-ons/print/drivers/pdf/source/PrinterDriver.h b/src/add-ons/print/drivers/pdf/source/PrinterDriver.h new file mode 100644 index 0000000000..b0efe90539 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/PrinterDriver.h @@ -0,0 +1,114 @@ +/* + +PDF Writer printer driver. + +Copyright (c) 2001 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef PRINTERDRIVER_H +#define PRINTERDRIVER_H + +#include +#include + +#ifndef ROUND_UP + #define ROUND_UP(x, y) (((x) + (y) - 1) & ~((y) - 1)) +#endif + +#define MAX_INT32 ((int32)0x7fffffffL) + +// transport add-on calls definition +extern "C" { + typedef BDataIO *(*init_transport_proc)(BMessage *); + typedef void (*exit_transport_proc)(void); +}; + + +class StatusWindow; + + +/** + * Class PrinterDriver + */ +class PrinterDriver +{ +public: + // constructors / destructor + PrinterDriver(); + virtual ~PrinterDriver(); + + void StopPrinting(); + + virtual status_t PrintJob(BFile *jobFile, BNode *printerNode, BMessage *jobMsg); + virtual status_t BeginJob(); + virtual status_t PrintPage(int32 pageNumber, int32 pageCount); + virtual status_t EndJob(); + + // configuration default methods + virtual status_t PrinterSetup(char *printerName); + virtual status_t PageSetup(BMessage *msg, const char *printerName = NULL); + virtual status_t JobSetup(BMessage *msg, const char *printerName = NULL); + + // transport-related methods + status_t OpenTransport(); + status_t CloseTransport(); + + // accessors + inline BFile *JobFile() { return fJobFile; } + inline BNode *PrinterNode() { return fPrinterNode; } + inline BMessage *JobMsg() { return fJobMsg; } + inline BDataIO *Transport() { return fTransport; } + inline StatusWindow *Status() { return fStatusWindow; } + inline int32 Pass() const { return fPass; } + + // publics status code + typedef enum { + PORTRAIT_ORIENTATION, + LANDSCAPE_ORIENTATION + } Orientation; + + +private: + BFile *fJobFile; + BNode *fPrinterNode; + BMessage *fJobMsg; + StatusWindow *fStatusWindow; + + volatile Orientation fOrientation; + + bool fPrinting; + int32 fPass; + + // transport-related + BDataIO *fTransport; + image_id fTransportAddOn; + init_transport_proc fTransportInitProc; + exit_transport_proc fTransportExitProc; +}; + +#endif // #ifndef PRINTERDRIVER_H + diff --git a/src/add-ons/print/drivers/pdf/source/PrinterPrefs.cpp b/src/add-ons/print/drivers/pdf/source/PrinterPrefs.cpp new file mode 100644 index 0000000000..191d13e96c --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/PrinterPrefs.cpp @@ -0,0 +1,102 @@ +/* + +PrinterPrefs.cpp + +Copyright (c) 2002 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef PRINTER_PREFS_H +#include "PrinterPrefs.h" +#endif + +/** + * Constructor + * + * @param none + * @return none + */ +PrinterPrefs::PrinterPrefs() +{ +} + +/** + * Destructor + * + * @param none + * @return none + */ +PrinterPrefs::~PrinterPrefs() +{ +} + +/** + * Init the settings message from settings file + * + * @param BMessage*, the settings + * @return status_t, any result from the operation + */ +status_t +PrinterPrefs::LoadSettings(BMessage *settings) +{ + status_t status; + BFile file; + + status = find_directory(B_COMMON_SETTINGS_DIRECTORY, &fSettingsPath); + if (status != B_OK) { + // Could not find settings folder. + return status; + } + + fSettingsPath.Append(SETTINGS_FILE_NAME); + status = file.SetTo(fSettingsPath.Path(), B_READ_ONLY); + if (status == B_OK) { + status = settings->Unflatten(&file); + } + + return status; +} + +/** + * Save the settings + * + * @param BMessage*, the settings + * @return status_t + */ +status_t +PrinterPrefs::SaveSettings(BMessage* settings) +{ + status_t status; + BFile file; + + status = file.SetTo(fSettingsPath.Path(), B_WRITE_ONLY | B_CREATE_FILE); + if (status == B_OK) { + return settings->Flatten(&file); + } + return status; +} + + diff --git a/src/add-ons/print/drivers/pdf/source/PrinterPrefs.h b/src/add-ons/print/drivers/pdf/source/PrinterPrefs.h new file mode 100644 index 0000000000..6ea72e6115 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/PrinterPrefs.h @@ -0,0 +1,56 @@ +/* + +PrinterPrefs.h + +Copyright (c) 2002 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef PRINTER_PREFS_H +#define PRINTER_PREFS_H + +#include +#include + +const char SETTINGS_FILE_NAME[] = "pdf_printer_settings"; + +/** + * Class + */ +class PrinterPrefs +{ +private: + BPath fSettingsPath; + +public: + PrinterPrefs(); + ~PrinterPrefs(); + + status_t LoadSettings(BMessage* settings); + status_t SaveSettings(BMessage* settings); +}; + +#endif diff --git a/src/add-ons/print/drivers/pdf/source/PrinterSettings.cpp b/src/add-ons/print/drivers/pdf/source/PrinterSettings.cpp new file mode 100644 index 0000000000..1edb943c31 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/PrinterSettings.cpp @@ -0,0 +1,261 @@ +/* + +Printer Settings helper class + +Copyright (c) 2001 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef PRINTER_SETTINGS_H +#include "PrinterSettings.h" +#endif + +#include + +#include "PrinterPrefs.h" + +/** + * Constructor + * + * @param BNode& the spooler folder + * @return void + */ +PrinterSettings::PrinterSettings(BNode &printer) +{ + fNode = printer; + fErr = fNode.InitCheck(); +} + +/** + * Constructor + * + * @param const char*, the printer name + * @return void + */ +PrinterSettings::PrinterSettings(const char *printer) +{ + BPath path; + + find_directory(B_USER_SETTINGS_DIRECTORY, &path); + path.Append(PRINTER_SETTINGS_PATH); + path.Append(printer); + fErr = fNode.SetTo(path.Path()); +} + +/** + * InitCheck, check status of initialization + * + * @param none + * @return status_t the status + */ +status_t +PrinterSettings::InitCheck() +{ + return fErr; +} + +/** + * Destructor + * + * @param none + * @return void + */ +PrinterSettings::~PrinterSettings() { } + +/** + * ReadSettings() return the settings for the printer from flattened BMessage + * attached as an attribute to the spool folder node. + * + * @param BMessage* the settings in a message object + * @return status_t the status of the read operation + */ +status_t +PrinterSettings::ReadSettings(BMessage *msg) +{ + attr_info info; + char *data = NULL; + status_t err = B_ERROR; + + msg->MakeEmpty(); + msg->what = 0; + + if (fNode.GetAttrInfo(ATTR_NAME, &info) == B_OK) { + data = (char *)malloc(info.size); + if (data != NULL) { + err = fNode.ReadAttr(ATTR_NAME, B_MESSAGE_TYPE, 0, data, info.size); + if (err >= 0) { + err = B_OK; + msg->Unflatten(data); + } + } + } else { // no attributes found, then we create them + GetDefaults(msg); + WriteSettings(msg); + err = B_OK; + } + return err; +} + +/** + * WriteSettings() save the settings in a flattened BMessage and attach this + * to the node as an attribute + * + * @param BMessage* the settings to save in a BMessage object + * @return status_t the status of the write operation + */ +status_t +PrinterSettings::WriteSettings(BMessage* msg) +{ + size_t length; + char *data = NULL; + status_t err = B_ERROR; + + length = msg->FlattenedSize(); + data = (char *) malloc(length); + if (data != NULL) { + msg->Flatten(data, length); + err = fNode.WriteAttr(ATTR_NAME, B_MESSAGE_TYPE, 0, data, length); + if (err > 0) { + err = B_OK; + } + } + return err; +} + +/** + * GetDefaults() return the default settings for the printer using: + * 1) text file pdf_printer_settings in /home/config/settings + * 2) if file not found return hard coded in this method... Yuck! + * + * @param BMessage* the settings in a message object + * @return status_t the status of the read operation + */ +status_t +PrinterSettings::GetDefaults(BMessage *msg) +{ + // check to see if there is a pdf_printer_settings file + PrinterPrefs *prefs = new PrinterPrefs(); + BMessage *settings = new BMessage(); + settings->what = 'okok'; + if (prefs->LoadSettings(settings) == B_OK) { + // yes, copy the settings into message + *msg = *settings; + } else { + // set default value if property not set + msg->AddInt64("xres", XRES); + msg->AddInt64("yres", YRES); + msg->AddInt32("orientation", ORIENTATION); + msg->AddRect("paper_rect", PAPER_RECT); + msg->AddRect("printable_rect", PRINT_RECT); + msg->AddFloat("scaling", RES); + msg->AddString("pdf_compatibility", PDF_COMPATIBILITY); + msg->AddInt32("pdf_compression", PDF_COMPRESSION); + msg->AddInt32("units", UNITS); + msg->AddBool("create_web_links", CREATE_WEB_LINKS); + msg->AddFloat("link_border_width", LINK_BORDER_WIDTH); + msg->AddBool("create_bookmarks", CREATE_BOOKMARKS); + msg->AddString("bookmark_definition_file", BOOKMARK_DEFINITION_FILE); + msg->AddBool("create_xrefs", CREATE_XREFS); + msg->AddString("xrefs_file", XREFS_FILE); + + // create pdf_printer_settings file + prefs->SaveSettings(msg); + } + + delete prefs; + delete settings; + + return B_OK; +} + +/** + * Validate(), check that the message is built correctly for the PDF driver + Safe: does not modify the message + * + * @param BMessage*, the message to validate + * @return status_t, B_OK if the message is correctly structured + * B_ERROR if the message is corrupt + */ +status_t +PrinterSettings::Validate(const BMessage *msg) +{ + int64 i64; + int32 i32; + float f; + BRect r; + BString s; + bool b; + + // Test for data field existance + if (msg->FindInt64("xres", 0, &i64) != B_OK) { + return B_ERROR; + } + if (msg->FindInt64("yres", 0, &i64) != B_OK) { + return B_ERROR; + } + if (msg->FindInt32("orientation", &i32) != B_OK) { + return B_ERROR; + } + if (msg->FindRect("paper_rect", &r) != B_OK) { + return B_ERROR; + } + if (msg->FindRect("printable_rect", &r) != B_OK) { + return B_ERROR; + } + if (msg->FindFloat("scaling", &f) != B_OK) { + return B_ERROR; + } + if (msg->FindString("pdf_compatibility", &s) != B_OK) { + return B_ERROR; + } + if (msg->FindInt32("pdf_compression", &i32) != B_OK) { + return B_ERROR; + } + if (msg->FindInt32("units", &i32) != B_OK) { + return B_ERROR; + } + if (msg->FindBool("create_web_links", &b) != B_OK) { + return B_ERROR; + } + if (msg->FindFloat("link_border_width", &f) != B_OK) { + return B_ERROR; + } + if (msg->FindBool("create_bookmarks", &b) != B_OK) { + return B_ERROR; + } + if (msg->FindString("bookmark_definition_file", &s) != B_OK) { + return B_ERROR; + } + if (msg->FindBool("create_xrefs", &b) != B_OK) { + return B_ERROR; + } + if (msg->FindString("xrefs_file", &s) != B_OK) { + return B_ERROR; + } + // message ok + return B_OK; +} + diff --git a/src/add-ons/print/drivers/pdf/source/PrinterSettings.h b/src/add-ons/print/drivers/pdf/source/PrinterSettings.h new file mode 100644 index 0000000000..4f06d4df55 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/PrinterSettings.h @@ -0,0 +1,83 @@ +/* + +PrinterSettings.h + +Copyright (c) 2001 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef PRINTER_SETTINGS_H +#define PRINTER_SETTINGS_H + +#include + +#include "PrinterDriver.h" + +// Constants +const char ATTR_NAME[] = "printer_settings"; +const char PDF_COMPATIBILITY[] = "1.3"; +const char PRINTER_SETTINGS_PATH[] = "printers/"; +const int64 XRES = 360; +const int64 YRES = 360; +const int32 ORIENTATION = PrinterDriver::PORTRAIT_ORIENTATION; +const float RES = 72.0f; +const int32 PDF_COMPRESSION = 3; +const int32 UNITS = 1; +const float LETTER_W = 8.5f * RES; +const float LETTER_H = 11.0f * RES; +const BRect PAPER_RECT(0, 0, LETTER_W, LETTER_H); +const BRect PRINT_RECT(0, 0, LETTER_W, LETTER_H); +const bool CREATE_WEB_LINKS = false; +const float LINK_BORDER_WIDTH = 1.0; +const bool CREATE_BOOKMARKS = false; +const char BOOKMARK_DEFINITION_FILE[] = ""; +const bool CREATE_XREFS = false; +const char XREFS_FILE[] = ""; + +/** + * Class + */ +class PrinterSettings +{ +private: + BNode fNode; + status_t fErr; + +public: + PrinterSettings() { } + PrinterSettings(const char *printer); + PrinterSettings(BNode &printer); + ~PrinterSettings(); + + status_t InitCheck(); + status_t WriteSettings(BMessage *msg); + status_t ReadSettings(BMessage *msg); + status_t GetDefaults(BMessage *msg); + status_t Validate(const BMessage *msg); +}; + +#endif + diff --git a/src/add-ons/print/drivers/pdf/source/PrinterSetupWindow.cpp b/src/add-ons/print/drivers/pdf/source/PrinterSetupWindow.cpp new file mode 100644 index 0000000000..4cc322c063 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/PrinterSetupWindow.cpp @@ -0,0 +1,244 @@ +/* + +PDF Writer printer driver. + +Copyright (c) 2001 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#include +#include +#include + +#include "PrinterSetupWindow.h" + +// -------------------------------------------------- +PrinterSetupWindow::PrinterSetupWindow(char *printerName) + : HWindow(BRect(0,0,300,300), printerName, B_TITLED_WINDOW_LOOK, + B_MODAL_APP_WINDOW_FEEL, B_NOT_ZOOMABLE) +{ + fExitSem = create_sem(0, "PrinterSetup"); + fResult = B_ERROR; + fPrinterName = printerName; + + if (printerName) { + BString title; + title << printerName << " Printer Setup"; + SetTitle(title.String()); + } else + SetTitle("Printer Setup"); + + // ---- Ok, build a default job setup user interface + BRect r; + BButton *button; + float x, y, w, h; + font_height fh; + + r = Bounds(); + + // add a *dialog* background + BBox *panel = new BBox(r, "top_panel", B_FOLLOW_ALL, + B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP, + B_PLAIN_BORDER); + + + const int kInterSpace = 8; + const int kHorzMargin = 10; + const int kVertMargin = 10; + + x = kHorzMargin; + y = kVertMargin; + + // add a label before the list + const char *kModelLabel = "Printer model"; + + be_plain_font->GetHeight(&fh); + + w = Bounds().Width(); + w -= 2 * kHorzMargin; + h = 150; + + BBox * model_group = new BBox(BRect(x, y, x+w, y+h), "model_group", B_FOLLOW_ALL_SIDES); + model_group->SetLabel(kModelLabel); + + BRect rlv = model_group->Bounds(); + + rlv.InsetBy(kHorzMargin, kVertMargin); + rlv.top += fh.ascent + fh.descent + fh.leading; + rlv.right -= B_V_SCROLL_BAR_WIDTH; + fModelList = new BListView(rlv, "model_list", + B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES ); + + BScrollView * sv = new BScrollView( "model_list_scrollview", fModelList, + B_FOLLOW_ALL_SIDES, B_WILL_DRAW | B_FRAME_EVENTS, false, true ); + model_group->AddChild(sv); + + panel->AddChild(model_group); + + y += (h + kInterSpace); + + x = r.right - kHorzMargin; + + // add a "OK" button, and make it default + fOkButton = new BButton(BRect(x, y, x + 400, y), NULL, "OK", new BMessage(OK_MSG), B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + fOkButton->ResizeToPreferred(); + fOkButton->GetPreferredSize(&w, &h); + x -= w; + fOkButton->MoveTo(x, y); + fOkButton->MakeDefault(true); + fOkButton->SetEnabled(false); + + panel->AddChild(fOkButton); + + x -= kInterSpace; + + // add a "Cancel" button + button = new BButton(BRect(x, y, x + 400, y), NULL, "Cancel", new BMessage(CANCEL_MSG), B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + button->ResizeToPreferred(); + button->GetPreferredSize(&w, &h); + x -= w; + button->MoveTo(x, y); + panel->AddChild(button); + + y += (h + kInterSpace); + + panel->ResizeTo(Bounds().Width(), y); + ResizeTo(Bounds().Width(), y); + + float minWidth, maxWidth, minHeight, maxHeight; + + GetSizeLimits(&minWidth, &maxWidth, &minHeight, &maxHeight); + SetSizeLimits(panel->Frame().Width(), panel->Frame().Width(), + panel->Frame().Height(), maxHeight); + + // Finally, add our panel to window + AddChild(panel); + + BDirectory Folder; + BEntry entry; + + Folder.SetTo ("/boot/beos/etc/bubblejet"); + if (Folder.InitCheck() != B_OK) + return; + + while (Folder.GetNextEntry(&entry) != B_ENTRY_NOT_FOUND) { + char name[B_FILE_NAME_LENGTH]; + if (entry.GetName(name) == B_NO_ERROR) + fModelList->AddItem (new BStringItem(name)); + } + + fModelList->SetSelectionMessage(new BMessage(MODEL_MSG)); + fModelList->SetInvocationMessage(new BMessage(OK_MSG)); +} + + +// -------------------------------------------------- +PrinterSetupWindow::~PrinterSetupWindow() +{ + delete_sem(fExitSem); +} + + +// -------------------------------------------------- +bool +PrinterSetupWindow::QuitRequested() +{ + release_sem(fExitSem); + return true; +} + + +// -------------------------------------------------- +void +PrinterSetupWindow::MessageReceived(BMessage *msg) +{ + switch (msg->what) { + case OK_MSG: + { + // Test model selection (if any), save it in printerName node and return + BNode spoolDir; + BPath * path; + + if (fModelList->CurrentSelection() < 0) + break; + + BStringItem * item = dynamic_cast + (fModelList->ItemAt(fModelList->CurrentSelection())); + + if (!item) + break; + + path = new BPath(); + + find_directory(B_USER_SETTINGS_DIRECTORY, path); + path->Append("printers"); + path->Append(fPrinterName); + + spoolDir.SetTo(path->Path()); + delete path; + + if (spoolDir.InitCheck() != B_OK) { + BAlert * alert = new BAlert("Uh oh!", + "Couldn't find printer spool directory.", "OK"); + alert->Go(); + } else { + spoolDir.WriteAttr("printer_model", B_STRING_TYPE, 0, item->Text(), + strlen(item->Text())); + fResult = B_OK; + } + + release_sem(fExitSem); + break; + } + + case CANCEL_MSG: + fResult = B_ERROR; + release_sem(fExitSem); + break; + + case MODEL_MSG: + fOkButton->SetEnabled((fModelList->CurrentSelection() >= 0)); + break; + + default: + inherited::MessageReceived(msg); + break; + }; +} + + +// -------------------------------------------------- +status_t +PrinterSetupWindow::Go() +{ + MoveTo(300, 300); + Show(); + acquire_sem(fExitSem); + Lock(); + Quit(); + + return fResult; +} diff --git a/src/add-ons/print/drivers/pdf/source/PrinterSetupWindow.h b/src/add-ons/print/drivers/pdf/source/PrinterSetupWindow.h new file mode 100644 index 0000000000..f03b34b08e --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/PrinterSetupWindow.h @@ -0,0 +1,72 @@ +/* + +PDF Writer printer driver. + +Copyright (c) 2001 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef PRINTERSETUPWINDOW_H +#define PRINTERSETUPWINDOW_H + +#include +#include "Utils.h" + +class PrinterSetupWindow : public HWindow +{ +public: + // Constructors, destructors, operators... + + PrinterSetupWindow(char *printerName); + ~PrinterSetupWindow(); + + typedef HWindow inherited; + + // public constantes + enum { + OK_MSG = 'ok__', + CANCEL_MSG = 'cncl', + MODEL_MSG = 'modl' + }; + + // Virtual function overrides +public: + virtual void MessageReceived(BMessage *msg); + virtual bool QuitRequested(); + status_t Go(); + + // From here, it's none of your business! ;-) +private: + BButton *fOkButton; + BListView *fModelList; + char *fPrinterName; + long fExitSem; + status_t fResult; +}; + +#endif + + \ No newline at end of file diff --git a/src/add-ons/print/drivers/pdf/source/RegExp.cpp b/src/add-ons/print/drivers/pdf/source/RegExp.cpp new file mode 100644 index 0000000000..f03fcc8c38 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/RegExp.cpp @@ -0,0 +1,1340 @@ +/* +Open Tracker License + +Terms and Conditions + +Copyright (c) 1991-2000, Be Incorporated. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice applies to all licensees +and shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Be Incorporated shall not be +used in advertising or otherwise to promote the sale, use or other dealings in +this Software without prior written authorization from Be Incorporated. + +Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks +of Be Incorporated in the United States and other countries. Other brand product +names are registered trademarks or trademarks of their respective holders. +All rights reserved. +*/ + +// This code is based on regexp.c, v.1.3 by Henry Spencer: + +// @(#)regexp.c 1.3 of 18 April 87 +// +// Copyright (c) 1986 by University of Toronto. +// Written by Henry Spencer. Not derived from licensed software. +// +// Permission is granted to anyone to use this software for any +// purpose on any computer system, and to redistribute it freely, +// subject to the following restrictions: +// +// 1. The author is not responsible for the consequences of use of +// this software, no matter how awful, even if they arise +// from defects in it. +// +// 2. The origin of this software must not be misrepresented, either +// by explicit claim or by omission. +// +// 3. Altered versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// Beware that some of this code is subtly aware of the way operator +// precedence is structured in regular expressions. Serious changes in +// regular-expression syntax might require a total rethink. +// + +// ALTERED VERSION: Adapted to ANSI C and C++ for the OpenTracker +// project (www.opentracker.org), Jul 11, 2000. + +#include +#include +#include + +#include + +#include "RegExp.h" + +// The first byte of the regexp internal "program" is actually this magic +// number; the start node begins in the second byte. + +const uint8 kRegExpMagic = 0234; + +// The "internal use only" fields in RegExp.h are present to pass info from +// compile to execute that permits the execute phase to run lots faster on +// simple cases. They are: +// +// regstart char that must begin a match; '\0' if none obvious +// reganch is the match anchored (at beginning-of-line only)? +// regmust string (pointer into program) that match must include, or NULL +// regmlen length of regmust string +// +// Regstart and reganch permit very fast decisions on suitable starting points +// for a match, cutting down the work a lot. Regmust permits fast rejection +// of lines that cannot possibly match. The regmust tests are costly enough +// that Compile() supplies a regmust only if the r.e. contains something +// potentially expensive (at present, the only such thing detected is * or + +// at the start of the r.e., which can involve a lot of backup). Regmlen is +// supplied because the test in RunMatcher() needs it and Compile() is computing +// it anyway. +// +// +// +// Structure for regexp "program". This is essentially a linear encoding +// of a nondeterministic finite-state machine (aka syntax charts or +// "railroad normal form" in parsing technology). Each node is an opcode +// plus a "next" pointer, possibly plus an operand. "Next" pointers of +// all nodes except kRegExpBranch implement concatenation; a "next" pointer with +// a kRegExpBranch on both ends of it is connecting two alternatives. (Here we +// have one of the subtle syntax dependencies: an individual kRegExpBranch (as +// opposed to a collection of them) is never concatenated with anything +// because of operator precedence.) The operand of some types of node is +// a literal string; for others, it is a node leading into a sub-FSM. In +// particular, the operand of a kRegExpBranch node is the first node of the branch. +// (NB this is *not* a tree structure: the tail of the branch connects +// to the thing following the set of kRegExpBranches.) The opcodes are: +// + +// definition number opnd? meaning +enum { + kRegExpEnd = 0, // no End of program. + kRegExpBol = 1, // no Match "" at beginning of line. + kRegExpEol = 2, // no Match "" at end of line. + kRegExpAny = 3, // no Match any one character. + kRegExpAnyOf = 4, // str Match any character in this string. + kRegExpAnyBut = 5, // str Match any character not in this string. + kRegExpBranch = 6, // node Match this alternative, or the next... + kRegExpBack = 7, // no Match "", "next" ptr points backward. + kRegExpExactly = 8, // str Match this string. + kRegExpNothing = 9, // no Match empty string. + kRegExpStar = 10, // node Match this (simple) thing 0 or more times. + kRegExpPlus = 11, // node Match this (simple) thing 1 or more times. + kRegExpOpen = 20, // no Mark this point in input as start of #n. + // kRegExpOpen + 1 is number 1, etc. + kRegExpClose = 30 // no Analogous to kRegExpOpen. +}; + +// +// Opcode notes: +// +// kRegExpBranch The set of branches constituting a single choice are hooked +// together with their "next" pointers, since precedence prevents +// anything being concatenated to any individual branch. The +// "next" pointer of the last kRegExpBranch in a choice points to the +// thing following the whole choice. This is also where the +// final "next" pointer of each individual branch points; each +// branch starts with the operand node of a kRegExpBranch node. +// +// kRegExpBack Normal "next" pointers all implicitly point forward; kRegExpBack +// exists to make loop structures possible. +// +// kRegExpStar,kRegExpPlus '?', and complex '*' and '+', are implemented as circular +// kRegExpBranch structures using kRegExpBack. Simple cases (one character +// per match) are implemented with kRegExpStar and kRegExpPlus for speed +// and to minimize recursive plunges. +// +// kRegExpOpen,kRegExpClose ...are numbered at compile time. +// +// +// +// A node is one char of opcode followed by two chars of "next" pointer. +// "Next" pointers are stored as two 8-bit pieces, high order first. The +// value is a positive offset from the opcode of the node containing it. +// An operand, if any, simply follows the node. (Note that much of the +// code generation knows about this implicit relationship.) +// +// Using two bytes for the "next" pointer is vast overkill for most things, +// but allows patterns to get big without disasters. +// + +const char *kMeta = "^$.[()|?+*\\"; +const int32 kMaxSize = 32767L; // Probably could be 65535L. + +// Flags to be passed up and down: +enum { + kHasWidth = 01, // Known never to match null string. + kSimple = 02, // Simple enough to be kRegExpStar/kRegExpPlus operand. + kSPStart = 04, // Starts with * or +. + kWorst = 0 // Worst case. +}; + +const char *kRegExpErrorStringArray[] = { + "Unmatched parenthesis.", + "Expression too long.", + "Too many parenthesis.", + "Junk on end.", + "*+? operand may be empty.", + "Nested *?+.", + "Invalid bracket range.", + "Unmatched brackets.", + "Internal error.", + "?+* follows nothing.", + "Trailing \\.", + "Corrupted expression.", + "Memory corruption.", + "Corrupted pointers.", + "Corrupted opcode." +}; + +#ifdef DEBUG +int32 regnarrate = 0; +#endif + +RegExp::RegExp() + : fError(B_OK), + fRegExp(NULL) +{ +} + +RegExp::RegExp(const char *pattern) + : fError(B_OK), + fRegExp(NULL) +{ + fRegExp = Compile(pattern); +} + +RegExp::RegExp(const BString &pattern) + : fError(B_OK), + fRegExp(NULL) +{ + fRegExp = Compile(pattern.String()); +} + +RegExp::~RegExp() +{ + free(fRegExp); +} + + + +status_t +RegExp::InitCheck() const +{ + return fError; +} + +status_t +RegExp::SetTo(const char *pattern) +{ + fError = B_OK; + free(fRegExp); + fRegExp = Compile(pattern); + return fError; +} + +status_t +RegExp::SetTo(const BString &pattern) +{ + fError = B_OK; + free(fRegExp); + fRegExp = Compile(pattern.String()); + return fError; +} + +bool +RegExp::Matches(const char *string) const +{ + if (!fRegExp || !string) + return false; + + return RunMatcher(fRegExp, string) == 1; +} + +bool +RegExp::Matches(const BString &string) const +{ + if (!fRegExp) + return false; + + return RunMatcher(fRegExp, string.String()) == 1; +} + + +// +// - Compile - compile a regular expression into internal code +// +// We can't allocate space until we know how big the compiled form will be, +// but we can't compile it (and thus know how big it is) until we've got a +// place to put the code. So we cheat: we compile it twice, once with code +// generation turned off and size counting turned on, and once "for real". +// This also means that we don't allocate space until we are sure that the +// thing really will compile successfully, and we never have to move the +// code and thus invalidate pointers into it. (Note that it has to be in +// one piece because free() must be able to free it all.) +// +// Beware that the optimization-preparation code in here knows about some +// of the structure of the compiled regexp. + +regexp * +RegExp::Compile(const char *exp) +{ + regexp *r; + const char *scan; + const char *longest; + int32 len; + int32 flags; + + if (exp == NULL) { + SetError(B_BAD_VALUE); + return NULL; + } + + // First pass: determine size, legality. + fInputScanPointer = exp; + fParenthesisCount = 1; + fCodeSize = 0L; + fCodeEmitPointer = &fDummy; + Char(kRegExpMagic); + if (Reg(0, &flags) == NULL) + return NULL; + + // Small enough for pointer-storage convention? + if (fCodeSize >= kMaxSize) { + SetError(REGEXP_TOO_BIG); + return NULL; + } + + // Allocate space. + r = (regexp *)malloc(sizeof(regexp) + fCodeSize); + + if (!r) { + SetError(B_NO_MEMORY); + return NULL; + } + + // Second pass: emit code. + fInputScanPointer = exp; + fParenthesisCount = 1; + fCodeEmitPointer = r->program; + Char(kRegExpMagic); + if (Reg(0, &flags) == NULL) { + free(r); + return NULL; + } + + // Dig out information for optimizations. + r->regstart = '\0'; // Worst-case defaults. + r->reganch = 0; + r->regmust = NULL; + r->regmlen = 0; + scan = r->program + 1; // First kRegExpBranch. + if (*Next((char *)scan) == kRegExpEnd) { // Only one top-level choice. + scan = Operand(scan); + + // Starting-point info. + if (*scan == kRegExpExactly) + r->regstart = *Operand(scan); + else if (*scan == kRegExpBol) + r->reganch++; + + // + // If there's something expensive in the r.e., find the + // longest literal string that must appear and make it the + // regmust. Resolve ties in favor of later strings, since + // the regstart check works with the beginning of the r.e. + // and avoiding duplication strengthens checking. Not a + // strong reason, but sufficient in the absence of others. + // + if (flags&kSPStart) { + longest = NULL; + len = 0; + for (; scan != NULL; scan = Next((char *)scan)) + if (*scan == kRegExpExactly && (int32)strlen(Operand(scan)) >= len) { + longest = Operand(scan); + len = (int32)strlen(Operand(scan)); + } + r->regmust = longest; + r->regmlen = len; + } + } + + return r; +} + +regexp * +RegExp::Expression() const +{ + return fRegExp; +} + +const char * +RegExp::ErrorString() const +{ + if (fError >= REGEXP_UNMATCHED_PARENTHESIS + && fError <= REGEXP_CORRUPTED_OPCODE) + return kRegExpErrorStringArray[fError - B_ERRORS_END]; + + return strerror(fError); +} + + +void +RegExp::SetError(status_t error) const +{ + fError = error; +} + + +// +// - Reg - regular expression, i.e. main body or parenthesized thing +// +// Caller must absorb opening parenthesis. +// +// Combining parenthesis handling with the base level of regular expression +// is a trifle forced, but the need to tie the tails of the branches to what +// follows makes it hard to avoid. +// +char * +RegExp::Reg(int32 paren, int32 *flagp) +{ + char *ret; + char *br; + char *ender; + int32 parno = 0; + int32 flags; + + *flagp = kHasWidth; // Tentatively. + + // Make an kRegExpOpen node, if parenthesized. + if (paren) { + if (fParenthesisCount >= kSubExpressionMax) { + SetError(REGEXP_TOO_MANY_PARENTHESIS); + return NULL; + } + parno = fParenthesisCount; + fParenthesisCount++; + ret = Node((char)(kRegExpOpen + parno)); + } else + ret = NULL; + + // Pick up the branches, linking them together. + br = Branch(&flags); + if (br == NULL) + return NULL; + if (ret != NULL) + Tail(ret, br); // kRegExpOpen -> first + else + ret = br; + if (!(flags & kHasWidth)) + *flagp &= ~kHasWidth; + *flagp |= flags&kSPStart; + while (*fInputScanPointer == '|') { + fInputScanPointer++; + br = Branch(&flags); + if (br == NULL) + return NULL; + Tail(ret, br); // kRegExpBranch -> kRegExpBranch. + if (!(flags & kHasWidth)) + *flagp &= ~kHasWidth; + *flagp |= flags&kSPStart; + } + + // Make a closing node, and hook it on the end. + ender = Node(paren ? (char)(kRegExpClose + parno) : (char)kRegExpEnd); + Tail(ret, ender); + + // Hook the tails of the branches to the closing node. + for (br = ret; br != NULL; br = Next(br)) + OpTail(br, ender); + + // Check for proper termination. + if (paren && *fInputScanPointer++ != ')') { + SetError(REGEXP_UNMATCHED_PARENTHESIS); + return NULL; + } else if (!paren && *fInputScanPointer != '\0') { + if (*fInputScanPointer == ')') { + SetError(REGEXP_UNMATCHED_PARENTHESIS); + return NULL; + } else { + SetError(REGEXP_JUNK_ON_END); + return NULL; // "Can't happen". + } + // NOTREACHED + } + + return ret; +} + +// +// - Branch - one alternative of an | operator +// +// Implements the concatenation operator. +// +char * +RegExp::Branch(int32 *flagp) +{ + char *ret; + char *chain; + char *latest; + int32 flags; + + *flagp = kWorst; // Tentatively. + + ret = Node(kRegExpBranch); + chain = NULL; + while (*fInputScanPointer != '\0' + && *fInputScanPointer != '|' + && *fInputScanPointer != ')') { + latest = Piece(&flags); + if (latest == NULL) + return NULL; + *flagp |= flags & kHasWidth; + if (chain == NULL) // First piece. + *flagp |= flags & kSPStart; + else + Tail(chain, latest); + chain = latest; + } + if (chain == NULL) // Loop ran zero times. + Node(kRegExpNothing); + + return ret; +} + +// +// - Piece - something followed by possible [*+?] +// +// Note that the branching code sequences used for ? and the general cases +// of * and + are somewhat optimized: they use the same kRegExpNothing node as +// both the endmarker for their branch list and the body of the last branch. +// It might seem that this node could be dispensed with entirely, but the +// endmarker role is not redundant. +// +char * +RegExp::Piece(int32 *flagp) +{ + char *ret; + char op; + char *next; + int32 flags; + + ret = Atom(&flags); + if (ret == NULL) + return NULL; + + op = *fInputScanPointer; + if (!IsMult(op)) { + *flagp = flags; + return ret; + } + + if (!(flags & kHasWidth) && op != '?') { + SetError(REGEXP_STAR_PLUS_OPERAND_EMPTY); + return NULL; + } + *flagp = op != '+' ? kWorst | kSPStart : kWorst | kHasWidth; + + if (op == '*' && (flags & kSimple)) + Insert(kRegExpStar, ret); + else if (op == '*') { + // Emit x* as (x&|), where & means "self". + Insert(kRegExpBranch, ret); // Either x + OpTail(ret, Node(kRegExpBack)); // and loop + OpTail(ret, ret); // back + Tail(ret, Node(kRegExpBranch)); // or + Tail(ret, Node(kRegExpNothing)); // null. + } else if (op == '+' && (flags & kSimple)) + Insert(kRegExpPlus, ret); + else if (op == '+') { + // Emit x+ as x(&|), where & means "self". + next = Node(kRegExpBranch); // Either + Tail(ret, next); + Tail(Node(kRegExpBack), ret); // loop back + Tail(next, Node(kRegExpBranch)); // or + Tail(ret, Node(kRegExpNothing)); // null. + } else if (op == '?') { + // Emit x? as (x|) + Insert(kRegExpBranch, ret); // Either x + Tail(ret, Node(kRegExpBranch)); // or + next = Node(kRegExpNothing); // null. + Tail(ret, next); + OpTail(ret, next); + } + fInputScanPointer++; + if (IsMult(*fInputScanPointer)) { + SetError(REGEXP_NESTED_STAR_QUESTION_PLUS); + return NULL; + } + return ret; +} + +// +// - Atom - the lowest level +// +// Optimization: gobbles an entire sequence of ordinary characters so that +// it can turn them into a single node, which is smaller to store and +// faster to run. Backslashed characters are exceptions, each becoming a +// separate node; the code is simpler that way and it's not worth fixing. +// +char * +RegExp::Atom(int32 *flagp) +{ + char *ret; + int32 flags; + + *flagp = kWorst; // Tentatively. + + switch (*fInputScanPointer++) { + case '^': + ret = Node(kRegExpBol); + break; + case '$': + ret = Node(kRegExpEol); + break; + case '.': + ret = Node(kRegExpAny); + *flagp |= kHasWidth|kSimple; + break; + case '[': + { + int32 cclass; + int32 classend; + + if (*fInputScanPointer == '^') { // Complement of range. + ret = Node(kRegExpAnyBut); + fInputScanPointer++; + } else + ret = Node(kRegExpAnyOf); + if (*fInputScanPointer == ']' || *fInputScanPointer == '-') + Char(*fInputScanPointer++); + while (*fInputScanPointer != '\0' && *fInputScanPointer != ']') { + if (*fInputScanPointer == '-') { + fInputScanPointer++; + if (*fInputScanPointer == ']' || *fInputScanPointer == '\0') + Char('-'); + else { + cclass = UCharAt(fInputScanPointer - 2) + 1; + classend = UCharAt(fInputScanPointer); + if (cclass > classend + 1) { + SetError(REGEXP_INVALID_BRACKET_RANGE); + return NULL; + } + for (; cclass <= classend; cclass++) + Char((char)cclass); + fInputScanPointer++; + } + } else + Char(*fInputScanPointer++); + } + Char('\0'); + if (*fInputScanPointer != ']') { + SetError(REGEXP_UNMATCHED_BRACKET); + return NULL; + } + fInputScanPointer++; + *flagp |= kHasWidth | kSimple; + } + break; + case '(': + ret = Reg(1, &flags); + if (ret == NULL) + return NULL; + *flagp |= flags & (kHasWidth | kSPStart); + break; + case '\0': + case '|': + case ')': + SetError(REGEXP_INTERNAL_ERROR); + return NULL; // Supposed to be caught earlier. + case '?': + case '+': + case '*': + SetError(REGEXP_QUESTION_PLUS_STAR_FOLLOWS_NOTHING); + return NULL; + case '\\': + if (*fInputScanPointer == '\0') { + SetError(REGEXP_TRAILING_BACKSLASH); + return NULL; + } + ret = Node(kRegExpExactly); + Char(*fInputScanPointer++); + Char('\0'); + *flagp |= kHasWidth|kSimple; + break; + default: + { + int32 len; + char ender; + + fInputScanPointer--; + len = (int32)strcspn(fInputScanPointer, kMeta); + if (len <= 0) { + SetError(REGEXP_INTERNAL_ERROR); + return NULL; + } + ender = *(fInputScanPointer + len); + if (len > 1 && IsMult(ender)) + len--; // Back off clear of ?+* operand. + *flagp |= kHasWidth; + if (len == 1) + *flagp |= kSimple; + ret = Node(kRegExpExactly); + while (len > 0) { + Char(*fInputScanPointer++); + len--; + } + Char('\0'); + } + break; + } + + return ret; +} + +// +// - Node - emit a node +// +char * // Location. +RegExp::Node(char op) +{ + char *ret; + char *ptr; + + ret = fCodeEmitPointer; + if (ret == &fDummy) { + fCodeSize += 3; + return ret; + } + + ptr = ret; + *ptr++ = op; + *ptr++ = '\0'; // Null "next" pointer. + *ptr++ = '\0'; + fCodeEmitPointer = ptr; + + return ret; +} + +// +// - Char - emit (if appropriate) a byte of code +// +void +RegExp::Char(char b) +{ + if (fCodeEmitPointer != &fDummy) + *fCodeEmitPointer++ = b; + else + fCodeSize++; +} + +// +// - Insert - insert an operator in front of already-emitted operand +// +// Means relocating the operand. +// +void +RegExp::Insert(char op, char *opnd) +{ + char *src; + char *dst; + char *place; + + if (fCodeEmitPointer == &fDummy) { + fCodeSize += 3; + return; + } + + src = fCodeEmitPointer; + fCodeEmitPointer += 3; + dst = fCodeEmitPointer; + while (src > opnd) + *--dst = *--src; + + place = opnd; // Op node, where operand used to be. + *place++ = op; + *place++ = '\0'; + *place++ = '\0'; +} + +// +// - Tail - set the next-pointer at the end of a node chain +// +void +RegExp::Tail(char *p, char *val) +{ + char *scan; + char *temp; + int32 offset; + + if (p == &fDummy) + return; + + // Find last node. + scan = p; + for (;;) { + temp = Next(scan); + if (temp == NULL) + break; + scan = temp; + } + + if (scan[0] == kRegExpBack) + offset = scan - val; + else + offset = val - scan; + + scan[1] = (char)((offset >> 8) & 0377); + scan[2] = (char)(offset & 0377); +} + +// +// - OpTail - Tail on operand of first argument; nop if operandless +// +void +RegExp::OpTail(char *p, char *val) +{ + // "Operandless" and "op != kRegExpBranch" are synonymous in practice. + if (p == NULL || p == &fDummy || *p != kRegExpBranch) + return; + Tail(Operand(p), val); +} + +// +// RunMatcher and friends +// + +// +// - RunMatcher - match a regexp against a string +// +int32 +RegExp::RunMatcher(regexp *prog, const char *string) const +{ + const char *s; + + // Be paranoid... + if (prog == NULL || string == NULL) { + SetError(B_BAD_VALUE); + return 0; + } + + // Check validity of program. + if (UCharAt(prog->program) != kRegExpMagic) { + SetError(REGEXP_CORRUPTED_PROGRAM); + return 0; + } + + // If there is a "must appear" string, look for it. + if (prog->regmust != NULL) { + s = string; + while ((s = strchr(s, prog->regmust[0])) != NULL) { + if (strncmp(s, prog->regmust, (size_t)prog->regmlen) == 0) + break; // Found it. + s++; + } + if (s == NULL) // Not present. + return 0; + } + + // Mark beginning of line for ^ . + fRegBol = string; + + // Simplest case: anchored match need be tried only once. + if (prog->reganch) + return Try(prog, (char*)string); + + // Messy cases: unanchored match. + s = string; + if (prog->regstart != '\0') + // We know what char it must start with. + while ((s = strchr(s, prog->regstart)) != NULL) { + if (Try(prog, (char*)s)) + return 1; + s++; + } + else + // We don't -- general case. + do { + if (Try(prog, (char*)s)) + return 1; + } while (*s++ != '\0'); + + // Failure. + return 0; +} + +// +// - Try - try match at specific point +// +int32 // 0 failure, 1 success +RegExp::Try(regexp *prog, const char *string) const +{ + int32 i; + const char **sp; + const char **ep; + + fStringInputPointer = string; + fStartPArrayPointer = prog->startp; + fEndPArrayPointer = prog->endp; + + sp = prog->startp; + ep = prog->endp; + for (i = kSubExpressionMax; i > 0; i--) { + *sp++ = NULL; + *ep++ = NULL; + } + if (Match(prog->program + 1)) { + prog->startp[0] = string; + prog->endp[0] = fStringInputPointer; + return 1; + } else + return 0; +} + +// +// - Match - main matching routine +// +// Conceptually the strategy is simple: check to see whether the current +// node matches, call self recursively to see whether the rest matches, +// and then act accordingly. In practice we make some effort to avoid +// recursion, in particular by going through "ordinary" nodes (that don't +// need to know whether the rest of the match failed) by a loop instead of +// by recursion. +/// +int32 // 0 failure, 1 success +RegExp::Match(const char *prog) const +{ + const char *scan; // Current node. + const char *next; // Next node. + + scan = prog; +#ifdef DEBUG + if (scan != NULL && regnarrate) + fprintf(stderr, "%s(\n", Prop(scan)); +#endif + while (scan != NULL) { +#ifdef DEBUG + if (regnarrate) + fprintf(stderr, "%s...\n", Prop(scan)); +#endif + next = Next(scan); + + switch (*scan) { + case kRegExpBol: + if (fStringInputPointer != fRegBol) + return 0; + break; + case kRegExpEol: + if (*fStringInputPointer != '\0') + return 0; + break; + case kRegExpAny: + if (*fStringInputPointer == '\0') + return 0; + fStringInputPointer++; + break; + case kRegExpExactly: + { + const char *opnd = Operand(scan); + // Inline the first character, for speed. + if (*opnd != *fStringInputPointer) + return 0; + + uint32 len = strlen(opnd); + if (len > 1 && strncmp(opnd, fStringInputPointer, len) != 0) + return 0; + + fStringInputPointer += len; + } + break; + case kRegExpAnyOf: + if (*fStringInputPointer == '\0' + || strchr(Operand(scan), *fStringInputPointer) == NULL) + return 0; + fStringInputPointer++; + break; + case kRegExpAnyBut: + if (*fStringInputPointer == '\0' + || strchr(Operand(scan), *fStringInputPointer) != NULL) + return 0; + fStringInputPointer++; + break; + case kRegExpNothing: + break; + case kRegExpBack: + break; + case kRegExpOpen + 1: + case kRegExpOpen + 2: + case kRegExpOpen + 3: + case kRegExpOpen + 4: + case kRegExpOpen + 5: + case kRegExpOpen + 6: + case kRegExpOpen + 7: + case kRegExpOpen + 8: + case kRegExpOpen + 9: + { + int32 no; + const char *save; + + no = *scan - kRegExpOpen; + save = fStringInputPointer; + + if (Match(next)) { + // + // Don't set startp if some later + // invocation of the same parentheses + // already has. + // + if (fStartPArrayPointer[no] == NULL) + fStartPArrayPointer[no] = save; + return 1; + } else + return 0; + } + break; + case kRegExpClose + 1: + case kRegExpClose + 2: + case kRegExpClose + 3: + case kRegExpClose + 4: + case kRegExpClose + 5: + case kRegExpClose + 6: + case kRegExpClose + 7: + case kRegExpClose + 8: + case kRegExpClose + 9: + { + int32 no; + const char *save; + + no = *scan - kRegExpClose; + save = fStringInputPointer; + + if (Match(next)) { + // + // Don't set endp if some later + // invocation of the same parentheses + // already has. + // + if (fEndPArrayPointer[no] == NULL) + fEndPArrayPointer[no] = save; + return 1; + } else + return 0; + } + break; + case kRegExpBranch: + { + const char *save; + + if (*next != kRegExpBranch) // No choice. + next = Operand(scan); // Avoid recursion. + else { + do { + save = fStringInputPointer; + if (Match(Operand(scan))) + return 1; + fStringInputPointer = save; + scan = Next(scan); + } while (scan != NULL && *scan == kRegExpBranch); + return 0; + // NOTREACHED/ + } + } + break; + case kRegExpStar: + case kRegExpPlus: + { + char nextch; + int32 no; + const char *save; + int32 min; + + // + //Lookahead to avoid useless match attempts + // when we know what character comes next. + // + nextch = '\0'; + if (*next == kRegExpExactly) + nextch = *Operand(next); + min = (*scan == kRegExpStar) ? 0 : 1; + save = fStringInputPointer; + no = Repeat(Operand(scan)); + while (no >= min) { + // If it could work, try it. + if (nextch == '\0' || *fStringInputPointer == nextch) + if (Match(next)) + return 1; + // Couldn't or didn't -- back up. + no--; + fStringInputPointer = save + no; + } + return 0; + } + break; + case kRegExpEnd: + return 1; // Success! + + default: + SetError(REGEXP_MEMORY_CORRUPTION); + return 0; + } + + scan = next; + } + + // + // We get here only if there's trouble -- normally "case kRegExpEnd" is + // the terminating point. + // + SetError(REGEXP_CORRUPTED_POINTERS); + return 0; +} + +// +// - Repeat - repeatedly match something simple, report how many +// +int32 +RegExp::Repeat(const char *p) const +{ + int32 count = 0; + const char *scan; + const char *opnd; + + scan = fStringInputPointer; + opnd = Operand(p); + switch (*p) { + case kRegExpAny: + count = (int32)strlen(scan); + scan += count; + break; + + case kRegExpExactly: + while (*opnd == *scan) { + count++; + scan++; + } + break; + + case kRegExpAnyOf: + while (*scan != '\0' && strchr(opnd, *scan) != NULL) { + count++; + scan++; + } + break; + + case kRegExpAnyBut: + while (*scan != '\0' && strchr(opnd, *scan) == NULL) { + count++; + scan++; + } + break; + + default: // Oh dear. Called inappropriately. + SetError(REGEXP_INTERNAL_ERROR); + count = 0; // Best compromise. + break; + } + fStringInputPointer = scan; + + return count; +} + +// +// - Next - dig the "next" pointer out of a node +// +char * +RegExp::Next(char *p) +{ + int32 offset; + + if (p == &fDummy) + return NULL; + + offset = ((*(p + 1) & 0377) << 8) + (*(p + 2) & 0377); + if (offset == 0) + return NULL; + + if (*p == kRegExpBack) + return p - offset; + else + return p + offset; +} + +const char * +RegExp::Next(const char *p) const +{ + int32 offset; + + if (p == &fDummy) + return NULL; + + offset = ((*(p + 1) & 0377) << 8) + (*(p + 2) & 0377); + if (offset == 0) + return NULL; + + if (*p == kRegExpBack) + return p - offset; + else + return p + offset; +} + +inline int32 +RegExp::UCharAt(const char *p) const +{ + return (int32)*(unsigned char *)p; +} + +inline char * +RegExp::Operand(char* p) const +{ + return p + 3; +} + +inline const char * +RegExp::Operand(const char* p) const +{ + return p + 3; +} + +inline bool +RegExp::IsMult(char c) const +{ + return c == '*' || c == '+' || c == '?'; +} + + +#ifdef DEBUG + +// +// - Dump - dump a regexp onto stdout in vaguely comprehensible form +// +void +RegExp::Dump() +{ + const char *s; + char op = kRegExpExactly; // Arbitrary non-kRegExpEnd op. + const char *next; + + s = fRegExp->program + 1; + while (op != kRegExpEnd) { // While that wasn't kRegExpEnd last time... + op = *s; + printf("%2ld%s", s - fRegExp->program, Prop(s)); // Where, what. + next = Next(s); + if (next == NULL) // Next ptr. + printf("(0)"); + else + printf("(%ld)", (s - fRegExp->program) + (next - s)); + s += 3; + if (op == kRegExpAnyOf || op == kRegExpAnyBut || op == kRegExpExactly) { + // Literal string, where present. + while (*s != '\0') { + putchar(*s); + s++; + } + s++; + } + putchar('\n'); + } + + // Header fields of interest. + if (fRegExp->regstart != '\0') + printf("start `%c' ", fRegExp->regstart); + if (fRegExp->reganch) + printf("anchored "); + if (fRegExp->regmust != NULL) + printf("must have \"%s\"", fRegExp->regmust); + printf("\n"); +} + +// +// - Prop - printable representation of opcode +// +char * +RegExp::Prop(const char *op) const +{ + char *p = NULL; + static char buf[50]; + + (void) strcpy(buf, ":"); + + switch (*op) { + case kRegExpBol: + p = "kRegExpBol"; + break; + case kRegExpEol: + p = "kRegExpEol"; + break; + case kRegExpAny: + p = "kRegExpAny"; + break; + case kRegExpAnyOf: + p = "kRegExpAnyOf"; + break; + case kRegExpAnyBut: + p = "kRegExpAnyBut"; + break; + case kRegExpBranch: + p = "kRegExpBranch"; + break; + case kRegExpExactly: + p = "kRegExpExactly"; + break; + case kRegExpNothing: + p = "kRegExpNothing"; + break; + case kRegExpBack: + p = "kRegExpBack"; + break; + case kRegExpEnd: + p = "kRegExpEnd"; + break; + case kRegExpOpen + 1: + case kRegExpOpen + 2: + case kRegExpOpen + 3: + case kRegExpOpen + 4: + case kRegExpOpen + 5: + case kRegExpOpen + 6: + case kRegExpOpen + 7: + case kRegExpOpen + 8: + case kRegExpOpen + 9: + sprintf(buf + strlen(buf), "kRegExpOpen%d", *op - kRegExpOpen); + p = NULL; + break; + case kRegExpClose + 1: + case kRegExpClose + 2: + case kRegExpClose + 3: + case kRegExpClose + 4: + case kRegExpClose + 5: + case kRegExpClose + 6: + case kRegExpClose + 7: + case kRegExpClose + 8: + case kRegExpClose + 9: + sprintf(buf + strlen(buf), "kRegExpClose%d", *op - kRegExpClose); + p = NULL; + break; + case kRegExpStar: + p = "kRegExpStar"; + break; + case kRegExpPlus: + p = "kRegExpPlus"; + break; + default: + RegExpError("corrupted opcode"); + break; + } + + if (p != NULL) + strcat(buf, p); + + return buf; +} + +void +RegExp::RegExpError(const char *) const +{ + // does nothing now, perhaps it should printf? +} + +#endif diff --git a/src/add-ons/print/drivers/pdf/source/RegExp.h b/src/add-ons/print/drivers/pdf/source/RegExp.h new file mode 100644 index 0000000000..f8f55a4f56 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/RegExp.h @@ -0,0 +1,179 @@ +/* +Open Tracker License + +Terms and Conditions + +Copyright (c) 1991-2000, Be Incorporated. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice applies to all licensees +and shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Be Incorporated shall not be +used in advertising or otherwise to promote the sale, use or other dealings in +this Software without prior written authorization from Be Incorporated. + +Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks +of Be Incorporated in the United States and other countries. Other brand product +names are registered trademarks or trademarks of their respective holders. +All rights reserved. +*/ + + +// This code is based on regexp.c, v.1.3 by Henry Spencer: + +// @(#)regexp.c 1.3 of 18 April 87 +// +// Copyright (c) 1986 by University of Toronto. +// Written by Henry Spencer. Not derived from licensed software. +// +// Permission is granted to anyone to use this software for any +// purpose on any computer system, and to redistribute it freely, +// subject to the following restrictions: +// +// 1. The author is not responsible for the consequences of use of +// this software, no matter how awful, even if they arise +// from defects in it. +// +// 2. The origin of this software must not be misrepresented, either +// by explicit claim or by omission. +// +// 3. Altered versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// Beware that some of this code is subtly aware of the way operator +// precedence is structured in regular expressions. Serious changes in +// regular-expression syntax might require a total rethink. +// + +// ALTERED VERSION: Adapted to ANSI C and C++ for the OpenTracker +// project (www.opentracker.org), Jul 11, 2000. + +#ifndef _REG_EXP_H +#define _REG_EXP_H + +#include + +enum { + REGEXP_UNMATCHED_PARENTHESIS = B_ERRORS_END, + REGEXP_TOO_BIG, + REGEXP_TOO_MANY_PARENTHESIS, + REGEXP_JUNK_ON_END, + REGEXP_STAR_PLUS_OPERAND_EMPTY, + REGEXP_NESTED_STAR_QUESTION_PLUS, + REGEXP_INVALID_BRACKET_RANGE, + REGEXP_UNMATCHED_BRACKET, + REGEXP_INTERNAL_ERROR, + REGEXP_QUESTION_PLUS_STAR_FOLLOWS_NOTHING, + REGEXP_TRAILING_BACKSLASH, + REGEXP_CORRUPTED_PROGRAM, + REGEXP_MEMORY_CORRUPTION, + REGEXP_CORRUPTED_POINTERS, + REGEXP_CORRUPTED_OPCODE +}; + +const int32 kSubExpressionMax = 10; + +struct regexp { + const char *startp[kSubExpressionMax]; + const char *endp[kSubExpressionMax]; + char regstart; /* Internal use only. See RegExp.cpp for details. */ + char reganch; /* Internal use only. */ + const char *regmust;/* Internal use only. */ + int regmlen; /* Internal use only. */ + char program[1]; /* Unwarranted chumminess with compiler. */ +}; + +class RegExp { + +public: + RegExp(); + RegExp(const char *); + RegExp(const BString &); + ~RegExp(); + + status_t InitCheck() const; + + status_t SetTo(const char*); + status_t SetTo(const BString &); + + bool Matches(const char *string) const; + bool Matches(const BString &) const; + + int32 RunMatcher(regexp *, const char *) const; + regexp *Compile(const char *); + regexp *Expression() const; + const char *ErrorString() const; + +#ifdef DEBUG + void Dump(); +#endif + +private: + + void SetError(status_t error) const; + + // Working functions for Compile(): + char *Reg(int32, int32 *); + char *Branch(int32 *); + char *Piece(int32 *); + char *Atom(int32 *); + char *Node(char); + char *Next(char *); + const char *Next(const char *) const; + void Char(char); + void Insert(char, char *); + void Tail(char *, char *); + void OpTail(char *, char *); + + // Working functions for RunMatcher(): + int32 Try(regexp *, const char *) const; + int32 Match(const char *) const; + int32 Repeat(const char *) const; + + // Utility functions: +#ifdef DEBUG + char *Prop(const char *) const; + void RegExpError(const char *) const; +#endif + inline int32 UCharAt(const char *p) const; + inline char *Operand(char* p) const; + inline const char *Operand(const char* p) const; + inline bool IsMult(char c) const; + +// --------- Variables ------------- + + mutable status_t fError; + regexp *fRegExp; + + // Work variables for Compile(). + + const char *fInputScanPointer; + int32 fParenthesisCount; + char fDummy; + char *fCodeEmitPointer; // &fDummy = don't. + long fCodeSize; + + // Work variables for RunMatcher(). + + mutable const char *fStringInputPointer; + mutable const char *fRegBol; // Beginning of input, for ^ check. + mutable const char **fStartPArrayPointer; + mutable const char **fEndPArrayPointer; +}; + + +#endif diff --git a/src/add-ons/print/drivers/pdf/source/Report.cpp b/src/add-ons/print/drivers/pdf/source/Report.cpp new file mode 100644 index 0000000000..4a490e58ef --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/Report.cpp @@ -0,0 +1,95 @@ +/* + +Report. + +Copyright (c) 2002 OpenBeOS. + +Author: + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#include "Report.h" +#include +#include + +Report* Report::fInstance = NULL; + + +Report::Report() { + for (int i = 0; i < kNumKinds; i++) { + fNum[i] = 0; + } +} + + +Report::~Report() { +} + + +Report* Report::Instance() { + if (fInstance == NULL) { + fInstance = new Report(); + } + return fInstance; +} + + +void Report::Free() { + delete fInstance; fInstance = NULL; +} + +void Report::Add(kind kind, int32 page, const char* fmt, ...) { + #if !LOGGING + if (kind == kDebug) return; + #endif + + if (kind >= 0 && kind < kNumKinds) { + BAutolock lock(fLock); + fNum[kind] ++; + + va_list list; + char *b = new char[1 << 16]; + va_start(list, fmt); + vsprintf(b, fmt, list); + AddItem(new ReportRecord(kind, page, "", b)); + delete b; + va_end(list); + } +} + +int Report::Count(kind kind) { + if (kind >= 0 && kind < kNumKinds) { + BAutolock lock(fLock); + return (int)fNum[kind]; + } + return 0; +} + +ReportRecord* Report::ItemAt(int32 i) { + BAutolock lock(fLock); + return inherited::ItemAt(i); +} + +int32 Report::CountItems() { + BAutolock lock(fLock); + return inherited::CountItems(); +} diff --git a/src/add-ons/print/drivers/pdf/source/Report.h b/src/add-ons/print/drivers/pdf/source/Report.h new file mode 100644 index 0000000000..eabd6fe29e --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/Report.h @@ -0,0 +1,94 @@ +/* + +Report. + +Copyright (c) 2002 OpenBeOS. + +Author: + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef _REPORT_H +#define _REPORT_H + +#include +#include +#include +#include "Utils.h" + + +enum kind { + kInfo, + kWarning, + kError, + kDebug, +}; + +const int32 kNumKinds = kDebug + 1; + + +class ReportRecord { +public: +private: + kind fKind; + int32 fPage; + BString fLabel; + BString fDesc; + +public: + ReportRecord(kind kind, int32 page, const char* label, const char* desc) + : fKind(kind), fPage(page), fLabel(label), fDesc(desc) + { } + + kind Kind() const { return fKind; } + int32 Page() const { return fPage; } + const char* Label() const { return fLabel.String(); } + const char* Desc() const { return fDesc.String(); } +}; + + +class Report : public TList{ + static Report* fInstance; + int32 fNum[kNumKinds]; + BLocker fLock; + + Report(); + ~Report(); + + typedef TList inherited; + +public: + static Report* Instance(); + void Free(); + + // Only these methods are "synchronized": + // Note that they are *NOT* virtual in the base class! + void Add(kind kind, int32 page, const char* fmt, ...); + int Count(kind kind); + ReportRecord* ItemAt(int32 i); + int32 CountItems(); +}; + + +#define REPORT Report::Instance()->Add + +#endif diff --git a/src/add-ons/print/drivers/pdf/source/Scanner.cpp b/src/add-ons/print/drivers/pdf/source/Scanner.cpp new file mode 100644 index 0000000000..231cb92d37 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/Scanner.cpp @@ -0,0 +1,146 @@ +/* + +Scanner. + +Copyright (c) 2002 OpenBeOS. + +Author: + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#include "Scanner.h" +#include + +Scanner::Scanner(const char* name) { + fFile = fopen(name, "r"); + fCur.line = 1; fCur.column = 0; // line and column start at 1 + fPrev.line = 1; fPrev.column = 0; +} + +Scanner::~Scanner() { + if (fFile) fclose(fFile); +} + +status_t Scanner::InitCheck() const { + return fFile != NULL ? B_OK : B_ERROR; +} + +bool Scanner::IsEOF() const { + return feof(fFile); +} + +int Scanner::GetCh() { + int ch = fgetc(fFile); + fPrev = fCur; + if (ch == '\n') { + fCur.column = 0; + fCur.line ++; + } else { + fCur.column ++; + } + return ch; +} + + +void Scanner::UngetCh(int ch) { + ungetc(ch, fFile); + fCur = fPrev; +} + +void Scanner::SkipSpaces() +{ + int c = GetCh(); + for(;;) { + while (!IsEOF() && isspace(c)) c = GetCh(); + if (!IsEOF() && c == '#') { // line comment; skip to end of line + while (!IsEOF() && c != '\n') c = GetCh(); + } else { + UngetCh(c); return; + } + } +} + +bool Scanner::ReadName(BString *s) +{ + SkipSpaces(); + *s = ""; + + int c = GetCh(); + if (isalpha(c)) { + do { + s->Append((char)c, 1); + c = GetCh(); + } while (!IsEOF() && isalpha(c)); + UngetCh(c); + return true; + } + return false; +} + +bool Scanner::ReadString(BString *s) +{ + SkipSpaces(); + *s = ""; + + int c = GetCh(); + if (c == '"') { + c = GetCh(); + while (!IsEOF() && c != '"') { + s->Append((char)c, 1); + c = GetCh(); + } + if (c == '"') return true; + } + return false; +} + +bool Scanner::ReadFloat(float *value) +{ + SkipSpaces(); + BString s = ""; + *value = 0.0; + + int c = GetCh(); + if (isdigit(c) || c == '.') { + do { + s.Append((char)c, 1); + c = GetCh(); + } while(isdigit(c) || c == '.'); + if (EOF != sscanf(s.String(), "%f", value)) { + UngetCh(c); + return true; + } + } + return false; +} + +bool Scanner::NextChar(char ch) { + SkipSpaces(); + int c = GetCh(); + if (c == ch) { + return true; + } else { + UngetCh(c); + return false; + } +} + diff --git a/src/add-ons/print/drivers/pdf/source/Scanner.h b/src/add-ons/print/drivers/pdf/source/Scanner.h new file mode 100644 index 0000000000..0a31a6886a --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/Scanner.h @@ -0,0 +1,65 @@ +/* + +Cross References. + +Copyright (c) 2002 OpenBeOS. + +Author: + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef _SCANNER_H +#define _SCANNER_H + +#include +#include + +class Scanner { + class Position { + public: + int32 line; + int32 column; + }; + + FILE* fFile; + Position fCur; + Position fPrev; + + int GetCh(); + void UngetCh(int ch); + +public: + Scanner(const char* name); + status_t InitCheck() const; + ~Scanner(); + + void SkipSpaces(); + bool ReadName(BString* s); + bool ReadString(BString* s); + bool ReadFloat(float* f); + bool NextChar(char c); + bool IsEOF() const; + int32 Line() const { return fCur.line; } + int32 Column() const { return fCur.column; } +}; + +#endif diff --git a/src/add-ons/print/drivers/pdf/source/StatusWindow.cpp b/src/add-ons/print/drivers/pdf/source/StatusWindow.cpp new file mode 100644 index 0000000000..7dc9f07eb7 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/StatusWindow.cpp @@ -0,0 +1,214 @@ +/* + +PDF Writer printer driver. + +Copyright (c) 2001 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#include "StatusWindow.h" +#include "Report.h" +#include +#include + + +// -------------------------------------------------- +StatusWindow::StatusWindow(int32 passes, int32 pages, PrinterDriver *pd) + : HWindow(BRect(100, 100, 700, 600/*400, 185*/), "PDF Writer", + B_TITLED_WINDOW, + B_NOT_RESIZABLE|B_NOT_ZOOMABLE|B_NOT_CLOSABLE|B_FRAME_EVENTS, + B_CURRENT_WORKSPACE, 'cncl') +{ + fPass = 0; + fPages = pages; + fPrinterDriver = pd; + fPageCount = 0; +// fPopyCount = 0; + fReportIndex = 0; + fCloseSem = -1; + BRect r(0, 0, Frame().Width(), Frame().Height()); + + // view for the background color + BView *fPanel = new BBox(r, "top_panel", B_FOLLOW_ALL, + B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP, + B_PLAIN_BORDER); + AddChild(fPanel); +/* + if (fCopies > 1) { + pages *= fCopies; + } + + r.Set(10, 0, Frame().Width(), 50); + copyLabel = new BStringView(r, "copy_text", "Copy"); + panel->AddChild(copyLabel); + + r.Set(10, 55, Frame().Width()-20, 65); + copyStatus = new BStatusBar(r, "copyStatus"); + copyStatus->SetMaxValue(copies); + copyStatus->SetBarHeight(12); + panel->AddChild(copyStatus); +*/ + r.Set(10, 12, Frame().Width()-5, 22); + fPageLabel = new BStringView(r, "page_text", "Page", B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); + fPanel->AddChild(fPageLabel); + + r.Set(10, 15, 300-10, 10); + fPageStatus = new BStatusBar(r, "pageStatus"); + fPageStatus->SetMaxValue(pages * passes); + fPageStatus->SetBarHeight(12); + fPanel->AddChild(fPageStatus); + + // Cancel button + // add a separator line... +// BBox *line = new BBox(BRect(r.left, 50, r.right, 51), NULL, +// B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP ); +// panel->AddChild(line); + + // add a "Cancel" button + int32 x = 110; + int32 y = 55; + fCancel = new BButton(BRect(x, y, x + 100, y + 20), NULL, "Cancel", + new BMessage('cncl'), B_FOLLOW_NONE, B_WILL_DRAW | B_FRAME_EVENTS); + fCancel->ResizeToPreferred(); + fPanel->AddChild(fCancel); + + BRect b(0, 90, Bounds().right-B_V_SCROLL_BAR_WIDTH, Bounds().bottom); + BRect t(b); + t.OffsetTo(0, 0); + fReport = new BTextView(b, "", t, B_FOLLOW_TOP_BOTTOM | B_FOLLOW_LEFT_RIGHT); + fReport->SetStylable(true); + fReport->MakeEditable(false); + fPanel->AddChild(new BScrollView("", fReport, B_FOLLOW_ALL, 0, false, true)); +// fPanel->AddChild(fReport); + + ResizeTo(300, 85); + + Show(); +} + +// -------------------------------------------------- +void +StatusWindow::MessageReceived(BMessage *msg) +{ + switch (msg->what) { +/* + case 'copy': + copy = ""; + copy << "Copy: " << ++copyCount; + copyLabel->SetText(copy.String()); + copyStatus->Update(1); + break; +*/ + case 'cncl': + if (fCloseSem == -1) { + fPrinterDriver->StopPrinting(); + fCancel->SetEnabled(false); + } else { + fCancel->SetEnabled(false); + release_sem(fCloseSem); + } + break; + case 'page': + fPage = ""; +#if PATTERN_SUPPORT + if (fPass == 0) + fPage << "Collecting Patterns Page: " << ++fPageCount; + else +#endif + fPage << "Generating Page: " << ++fPageCount; + if (fPageCount == fPages) { + fPass ++; + fPageCount = 0; + } + fPageLabel->SetText(fPage.String()); + fPageStatus->Update(1); + UpdateReport(); + break; + default: + inherited::MessageReceived(msg); + } +} + + +void StatusWindow::UpdateReport() { + Report* r = Report::Instance(); + const int32 n = r->CountItems(); + const bool update = fReportIndex < n; + if (update && fReportIndex == 0) { + SetFlags(Flags() & ~(B_NOT_RESIZABLE)); + ResizeTo(600, 500); + } + while (fReportIndex < n) { + ReportRecord* rr = r->ItemAt(fReportIndex ++); + const char* label = NULL; + rgb_color color = {0, 0, 0, 255}; + switch (rr->Kind()) { + case kInfo: label = "Info"; color.green = 255; break; + case kWarning: label = "Warning"; color.red = 255; color.green=255; break; + case kError: label = "Error"; color.red = 255; break; + case kDebug: label = "Debug"; color.blue = 255; break; + } + + int32 cur = fReport->TextLength()-1; + fReport->Insert(fReport->TextLength(), label, strlen(label)); + int32 end = fReport->TextLength(); + fReport->SetFontAndColor(cur, end, NULL, 0, &color); + + char page[80]; + if (rr->Page() > 0) { + sprintf(page, " (Page %d)", (int)rr->Page()); + int32 len = strlen(page); + fReport->Insert(fReport->TextLength(), page, len); + } + + fReport->Insert(fReport->TextLength(), ": ", 2); + + fReport->Insert(fReport->TextLength(), rr->Desc(), strlen(rr->Desc())); + fReport->Insert(fReport->TextLength(), "\n", 1); + } + + if (update) { + fReport->ScrollToOffset(fReport->TextLength()); + fReport->Invalidate(); + } +} + +void StatusWindow::WaitForClose() { + fCloseSem = create_sem(0, "close_sem"); + + Lock(); + Report* r = Report::Instance(); + char b[80]; + sprintf(b, "%d Infos, %d Warnings, %d Errors", r->Count(kInfo), r->Count(kWarning), r->Count(kError)); + fPageLabel->SetText(b); + fCancel->SetLabel("Close"); + fCancel->SetEnabled(true); + UpdateReport(); + Unlock(); + + acquire_sem(fCloseSem); + delete_sem(fCloseSem); +} diff --git a/src/add-ons/print/drivers/pdf/source/StatusWindow.h b/src/add-ons/print/drivers/pdf/source/StatusWindow.h new file mode 100644 index 0000000000..2c5ca8bd3d --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/StatusWindow.h @@ -0,0 +1,69 @@ +/* + +PDF Writer printer driver. + +Copyright (c) 2001 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef STATUS_WINDOW_H +#define STATUS_WINDOW_H +#include +#include + +//class PrinterDriver; +#include "PrinterDriver.h" +#include "Utils.h" + +class StatusWindow : public HWindow +{ +private: + int32 fPass; + int32 fPages; +// BString fCopy; + BString fPage; + int32 fPageCount; +// int fCopyCount; +// BStringView *fCopyLabel; + BStringView *fPageLabel; + BStatusBar *fPageStatus; +// BStatusBar *fCopyStatus; + BButton *fCancel; + PrinterDriver *fPrinterDriver; + int32 fReportIndex; + BTextView* fReport; + sem_id fCloseSem; + + void UpdateReport(); +public: + typedef HWindow inherited; + + StatusWindow(int32 passes, int32 pages, PrinterDriver *pd); + + void MessageReceived(BMessage *msg); + void WaitForClose(); +}; +#endif diff --git a/src/add-ons/print/drivers/pdf/source/SubPath.cpp b/src/add-ons/print/drivers/pdf/source/SubPath.cpp new file mode 100644 index 0000000000..c1ac585b42 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/SubPath.cpp @@ -0,0 +1,127 @@ +/* + +SubPath + +Copyright (c) 2002 OpenBeOS. + +Author: + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#include + +#include "SubPath.h" + + +SubPath::SubPath(int size) +{ + fSize = size <= 0 ? kInitialSize : size; + fLength = 0; + fPoints = new BPoint[fSize]; + fClosed = false; +} + + +SubPath::~SubPath() +{ + delete []fPoints; +} + + +void +SubPath::MakeEmpty() +{ + fLength = 0; + fClosed = false; +} + + +void +SubPath::Truncate(int numOfPoints) +{ + fLength -= numOfPoints; + if (fLength < 0) fLength = 0; +} + + +void +SubPath::CheckSize(int size) +{ + if (fSize < size) { + fSize = size + kIncrement; + BPoint* points = new BPoint[fSize]; + for (int i = 0; i < fLength; i++) points[i] = fPoints[i]; + delete []fPoints; + fPoints = points; + } +} + + +void +SubPath::AddPoint(BPoint p) +{ + CheckSize(fLength + 1); + fPoints[fLength] = p; fLength ++; +} + + +void +SubPath::Close() +{ + fClosed = true; +} + + +void +SubPath::Open() +{ + fClosed = false; +} + + +BPoint +SubPath::PointAt(int i) +{ + if (InBounds(i)) { + return fPoints[i]; + } + return fPoints[0]; +} + +void +SubPath::AtPut(int i, BPoint p) +{ + if (InBounds(i)) { + fPoints[i] = p; + } +} + +void +SubPath::Print() +{ + fprintf(stderr, "SubPath length = %d, size = %d ", (int)fLength, (int)fSize); + for (int i = 0; i < fLength; i++) { + if (i != 0) fprintf(stderr, ", "); + fprintf(stderr, "(%f, %f)", PointAt(i).x, PointAt(i).y); + } + fprintf(stderr, "\n"); +} diff --git a/src/add-ons/print/drivers/pdf/source/SubPath.h b/src/add-ons/print/drivers/pdf/source/SubPath.h new file mode 100644 index 0000000000..4d0f09738a --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/SubPath.h @@ -0,0 +1,66 @@ +/* + +SubPath + +Copyright (c) 2002 OpenBeOS. + +Author: + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef SUBPATH_H +#define SUBPATH_H + +#include + +class SubPath { +private: + enum { + kInitialSize = 5, + kIncrement = 10 + }; + int32 fSize; // allocated points + int32 fLength; // number of valid points + BPoint *fPoints; + bool fClosed; // subpath connects last point with first point + + void CheckSize(int size); + bool InBounds(int i) { return 0 <= i && i < fLength; } + +public: + SubPath(int size = 10); + ~SubPath(); + void MakeEmpty(); + void Truncate(int numOfPoints); + + void AddPoint(BPoint p); + void Close(); + void Open(); + + int32 CountPoints() const { return fLength; } + BPoint PointAt(int i); + void AtPut(int i, BPoint p); + bool IsClosed() const { return fClosed; } + void Print(); // for debugging +}; + +#endif diff --git a/src/add-ons/print/drivers/pdf/source/Utils.cpp b/src/add-ons/print/drivers/pdf/source/Utils.cpp new file mode 100644 index 0000000000..734314365f --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/Utils.cpp @@ -0,0 +1,138 @@ +/* + +PDF Writer printer driver. + +Copyright (c) 2001, 2002 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#include "Utils.h" +#include +#include +#include +#include + +// -------------------------------------------------- +EscapeMessageFilter::EscapeMessageFilter(BWindow *window, int32 what) + : BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE, '_KYD') + , fWindow(window), + fWhat(what) +{ +} + + +// -------------------------------------------------- +filter_result +EscapeMessageFilter::Filter(BMessage *msg, BHandler **target) +{ + int32 key; + // notify window with message fWhat if Escape key is hit + if (B_OK == msg->FindInt32("key", &key) && key == 1) { + fWindow->PostMessage(fWhat); + return B_SKIP_MESSAGE; + } + return B_DISPATCH_MESSAGE; +} + + +// -------------------------------------------------- +HWindow::HWindow(BRect frame, const char *title, window_type type, uint32 flags, uint32 workspace, uint32 escape_msg) + : BWindow(frame, title, type, flags, workspace) +{ + Init(escape_msg); +} + + +// -------------------------------------------------- +HWindow::HWindow(BRect frame, const char *title, window_look look, window_feel feel, uint32 flags, uint32 workspace, uint32 escape_msg) + : BWindow(frame, title, look, feel, flags, workspace) +{ + Init(escape_msg); +} + + +// -------------------------------------------------- +void +HWindow::Init(uint32 escape_msg) +{ + AddShortcut('i', 0, new BMessage(B_ABOUT_REQUESTED)); + AddCommonFilter(new EscapeMessageFilter(this, escape_msg)); +} + + +// -------------------------------------------------- +void +HWindow::MessageReceived(BMessage* msg) +{ + if (msg->what == B_ABOUT_REQUESTED) { + AboutRequested(); + } else { + inherited::MessageReceived(msg); + } +} + +// -------------------------------------------------- +static const char* +kAbout = +"PDF Writer for BeOS\n" +"© 2001, 2002 OpenBeOS\n" +"\n" +"\tPhilippe Houdoin - Project Leader\n" +"\tSimon Gauvin - GUI Design\n" +"\tMichael Pfeiffer - PDF Generation, Configuration, Interactive Features\n" +"\tCelerick Stephens - Documentation\n" +; + +void +HWindow::AboutRequested() +{ + BAlert *about = new BAlert("About PDF Writer", kAbout, "Cool"); + BTextView *v = about->TextView(); + if (v) { + rgb_color red = {255, 0, 51, 255}; + rgb_color blue = {0, 102, 255, 255}; + + v->SetStylable(true); + char *text = (char*)v->Text(); + char *s = text; + // set all Be in blue and red + while ((s = strstr(s, "Be")) != NULL) { + int32 i = s - text; + v->SetFontAndColor(i, i+1, NULL, 0, &blue); + v->SetFontAndColor(i+1, i+2, NULL, 0, &red); + s += 2; + } + // first text line + s = strchr(text, '\n'); + BFont font; + v->GetFontAndColor(0, &font); + font.SetSize(12); // font.SetFace(B_OUTLINED_FACE); + v->SetFontAndColor(0, s-text+1, &font, B_FONT_SIZE); + }; + about->Go(); +} + + diff --git a/src/add-ons/print/drivers/pdf/source/Utils.h b/src/add-ons/print/drivers/pdf/source/Utils.h new file mode 100644 index 0000000000..777f1d10e2 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/Utils.h @@ -0,0 +1,160 @@ +/* + +PDF Writer printer driver. + +Copyright (c) 2001, 2002 OpenBeOS. + +Authors: + Philippe Houdoin + Simon Gauvin + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef _UTILS_H +#define _UTILS_H + +#include +#include +#include + + +class EscapeMessageFilter : public BMessageFilter +{ +private: + BWindow *fWindow; + int32 fWhat; + +public: + EscapeMessageFilter(BWindow *window, int32 what); + filter_result Filter(BMessage *msg, BHandler **target); +}; + + +class HWindow : public BWindow +{ +protected: + void Init(uint32 escape_msg); + +public: + typedef BWindow inherited; + + HWindow(BRect frame, const char *title, window_type type, uint32 flags, uint32 workspace = B_CURRENT_WORKSPACE, uint32 escape_msg = B_QUIT_REQUESTED); + HWindow(BRect frame, const char *title, window_look look, window_feel feel, uint32 flags, uint32 workspace = B_CURRENT_WORKSPACE, uint32 escape_msg = B_QUIT_REQUESTED); + + virtual void MessageReceived(BMessage* m); + virtual void AboutRequested(); +}; + +#define BEGINS_CHAR(byte) ((byte & 0xc0) != 0x80) + + +template +class TList { +private: + BList fList; + typedef int (*sort_func)(const void*, const void*); + +public: + virtual ~TList(); + void MakeEmpty(); + int32 CountItems() const; + T* ItemAt(int32 index) const; + void AddItem(T* p); + T* Items(); + void SortItems(int (*comp)(const T**, const T**)); +}; + +// TList +template +TList::~TList() { + MakeEmpty(); +} + + +template +void TList::MakeEmpty() { + const int32 n = CountItems(); + for (int i = 0; i < n; i++) { + delete ItemAt(i); + } + fList.MakeEmpty(); +} + + +template +int32 TList::CountItems() const { + return fList.CountItems(); +} + + +template +T* TList::ItemAt(int32 index) const { + return (T*)fList.ItemAt(index); +} + + +template +void TList::AddItem(T* p) { + fList.AddItem(p); +} + + +template +T* TList::Items() { + return (T*)fList.Items(); +} + + +template +void TList::SortItems(int (*comp)(const T**, const T**)) { + sort_func sort = (sort_func)comp; + fList.SortItems(sort); +} + +// PDF coordinate system +class PDFSystem { +private: + float fHeight; + float fX; + float fY; + float fScale; + +public: + PDFSystem() + : fHeight(0), fX(0), fY(0), fScale(1) { } + PDFSystem(float h, float x, float y, float s) + : fHeight(h), fX(x), fY(y), fScale(s) { } + + void SetHeight(float h) { fHeight = h; } + void SetOrigin(float x, float y) { fX = x; fY = y; } + void SetScale(float scale) { fScale = scale; } + float Height() const { return fHeight; } + BPoint Origin() const { return BPoint(fX, fY); } + float Scale() const { return fScale; } + + inline float tx(float x) { return fX + fScale*x; } + inline float ty(float y) { return fHeight - (fY + fScale * y); } + inline float scale(float f) { return fScale * f; } +}; + + +#endif diff --git a/src/add-ons/print/drivers/pdf/source/XReferences.cpp b/src/add-ons/print/drivers/pdf/source/XReferences.cpp new file mode 100644 index 0000000000..a799f65617 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/XReferences.cpp @@ -0,0 +1,436 @@ +/* + +Cross References. + +Copyright (c) 2002 OpenBeOS. + +Author: + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#include +#include +#include "Scanner.h" +#include "PDFWriter.h" +#include "XReferences.h" +#include "Report.h" + + +// Pattern + +Pattern::Pattern(const char* pattern) { + fPattern.SetTo(pattern); +} + + +Pattern::~Pattern() { +} + + +status_t Pattern::InitCheck() { + return fPattern.InitCheck(); +} + + +bool Pattern::Matches(const char* string, MatchResult* result) const { + regexp* re = fPattern.Expression(); + result->SetRegExp(re); + result->SetString(string); + if (fPattern.RunMatcher(re, string)) { + int32 i; + for (i = 0; i < kSubExpressionMax && re->startp[i]; i++); + result->SetResults(i); + return true; + } else { + result->SetResults(0); + return false; + } +} + + +// MatchResult + +MatchResult::MatchResult() { + fRegExp = NULL; + fString = NULL; + fResults = 0; +} + + +bool MatchResult::HasResult(int32 index) const { + return fRegExp && fString && index >= 0 && index < fResults; +} + + +const char* MatchResult::Start(int index) const { + if (HasResult(index)) { + return fRegExp->startp[index]; + } + return NULL; +} + +int32 MatchResult::StartPos(int index) const { + if (HasResult(index)) { + return fRegExp->startp[index] - fString; + } + return -1; +} + + +int32 MatchResult::EndPos(int index) const { + if (HasResult(index)) { + return fRegExp->endp[index] - fString; + } + return -1; +} + + +void MatchResult::GetString(int index, BString *result) { + *result = ""; + if (HasResult(index)) { + const char* s = fRegExp->startp[index]; + const char* e = fRegExp->endp[index]; + while (s != e) { *result << *s; s++; } + } +} + + +// XRefDef + +Pattern* XRefDef::Matches(PatternList* list, const char* s, const char** start, int32* len) { + MatchResult m; + const int32 n = list->CountItems(); + Pattern* pat = NULL; + for (int32 i = 0; i < n; i++) { + Pattern* p = list->ItemAt(i); + + if (p->Matches(s, &m) && m.CountResults() >= 1) { + if (m.Start(0) <= s) { + if (m.Start(0) == s && m.Length(0) <= *len) continue; + pat = p; + *start = m.Start(0); + *len = m.Length(0); + } + } + } + return pat; +} + + +Pattern* XRefDef::Matches(const char* s, const char** start, int32* len) { + *start = s + strlen(s); *len = 0; + Pattern* pat1 = Matches(&fLinks, s, start, len); + Pattern* pat2 = Matches(&fDests, s, start, len); + return pat2 ? pat2 : pat1; +} + + +// XRefDefs + +void XRefDefs::Add(XRefDef* def) { + def->SetId(fDefs.CountItems()); + fDefs.AddItem(def); +} + + +void XRefDefs::Matches(const char* s, XMatchResult* r, bool all) { + const int32 n = fDefs.CountItems(); + const char* end = s + strlen(s); + MatchResult match; + + do { + // match that starts at lowest position + const char* start1 = end; + XRefDef* def1 = NULL; + Pattern* pat1 = NULL; + int32 len1 = 0; + + for (int32 i = 0; i < n; i ++) { + const char* start; int32 len; + XRefDef* def = fDefs.ItemAt(i); + Pattern* pat = def->Matches(s, &start, &len); + if (pat && start <= start1) { + if (start == start1 && len <= len1) continue; + start1 = start; len1 = len; pat1 = pat; def1 = def; + } + } + + if (def1) { + bool found = pat1->Matches(start1, &match); + bool cont; + ASSERT(found); (void)found; + if (pat1->IsLink()) { + cont = r->Link(def1, &match); + } else { + cont = r->Dest(def1, &match); + } + if (!cont) break; + + // update for next iteration + s = start1 + len1; + } else { + if (all) { + do { + s ++; + } while (!BEGINS_CHAR(*s)); + } else { + break; + } + } + } while (*s); +} + + +class AutoDelete { + XRefDef* fDefs; +public: + AutoDelete(XRefDef* defs) : fDefs(defs) { } + ~AutoDelete() { delete fDefs; } + void Release() { fDefs = NULL; } +}; + +/* +FileFormat: Definition. +Line comment starts with: '#' + +Definition = Version {XRefDef}. +Version = "CrossReferences" "1.0". +XRefDef = Pattern {"," Pattern} "-" ">" Pattern {, Pattern} ".". +Pattern = '"' string '"'. + +Example: +CrossReferences 1.0 +"see [tT]able ([0-9]+)", "see [tT]bl. ([0-9]+)" -> "[tT]able ([0-9]+)". +"see [fF]igure ([0-9]+)" -> "[fF]igure ([0-9]+)". +"page ([0-9]+)" -> "- ([0-9]+) -" +*/ + +bool XRefDefs::Read(const char* name) { + Scanner scnr(name); + + if (scnr.InitCheck() == B_OK) { + + BString s; float f; + bool ok = scnr.ReadName(&s) && scnr.ReadFloat(&f); + if (!ok || strcmp(s.String(), "CrossReferences") != 0 || f != 1.0) { + REPORT(kError, 0, "XRefs (line %d, column %d): '%s' not a cross references file or wrong version!", scnr.Line(), scnr.Column(), name); + return false; + } + + while (!scnr.IsEOF()) { + XRefDef* def = new XRefDef(); + AutoDelete autoDelete(def); + BString pattern; + + // Links: Pattern {"," Pattern}. + do { + if (!scnr.ReadString(&pattern)) { + REPORT(kError, 0, "XRefs (line %d, column %d): Could not parse 'link' pattern", scnr.Line(), scnr.Column()); + return false; + } + LinkPattern* link = new LinkPattern(pattern.String()); + if (link->InitCheck() == B_OK) { + def->AddLink(link); + } else { + delete link; + REPORT(kError, 0, "XRefs (line %d, column %d): Invalid RegExp '%s'", pattern.String(), scnr.Line(), scnr.Column()); + return false; + } + } while (scnr.NextChar(',')); + + // "->" + if (scnr.NextChar('-') && scnr.NextChar('>')) { + + // Dests: Pattern {"," Pattern}. + do { + if (!scnr.ReadString(&pattern)) { + REPORT(kError, 0, "XRefs (line %d, column %d): Could not parse 'destination' pattern", scnr.Line(), scnr.Column()); + return false; + } + DestPattern* dest = new DestPattern(pattern.String()); + if (dest->InitCheck() == B_OK) { + def->AddDest(dest); + } else { + delete dest; + REPORT(kError, 0, "XRefs (line %d, column %d): Invalid RegExp '%s'", scnr.Line(), scnr.Column(), pattern.String()); + return false; + } + } while (scnr.NextChar(',')); + + // "." + if (!scnr.NextChar('.')) { + REPORT(kError, 0, "XRefs (line %d, column %d): '.' expected at end of definition", scnr.Line(), scnr.Column()); + return false; + } + } else { + REPORT(kError, 0, "XRefs (line %d, column %d): '->' expected", scnr.Line(), scnr.Column()); + return false; + } + + this->Add(def); + autoDelete.Release(); + + scnr.SkipSpaces(); + } + return true; + } else { + REPORT(kError, 0, "XRefs: Could not open cross references file '%d'", name); + } + return false; +} + + +// Destination + +Destination::Destination(const char* label, int32 page) + : fLabel(label) + , fPage(page) +{ +} + + +// DestList + +void DestList::Sort() { + // TODO: sort by label +} + + +Destination* DestList::Find(const char* label) { + const int n = CountItems(); + // TODO: binary sort + for (int32 i = 0; i < n; i++) { + Destination* d = ItemAt(i); + if (strcmp(d->Label(), label) == 0) return d; + } + return NULL; +} + + +// XRefDefs + +XRefDests::XRefDests(int32 n) { + fDests.MakeEmpty(); + for (int32 i = 0; i < n; i ++) { + fDests.AddItem(new DestList()); + } +} + + +bool XRefDests::Add(XRefDef* def, const char* label, int32 page) { + DestList* list = GetList(def); + ASSERT(list != NULL); + if (!list->Find(label)) { + list->AddItem(new Destination(label, page)); + return true; + } + return false; +} + + +bool XRefDests::Find(XRefDef* def, const char* label, int32* page) const { + DestList* list = GetList(def); + ASSERT(list != NULL); + Destination* dest = list->Find(label); + if (dest) { + *page = dest->Page(); + return true; + } + return false; +} + + +// RecordDests + +RecordDests::RecordDests(XRefDests* dests, int32 page) + : fDests(dests) + , fPage(page) +{ +} + + +bool RecordDests::Link(XRefDef* def, MatchResult* result) { + return true; +} + + +bool RecordDests::Dest(XRefDef* def, MatchResult* result) { + if (result->CountResults() >= 2) { + BString s; + result->GetString(1, &s); + fDests->Add(def, s.String(), fPage); + } + return true; +} + + +// LocalLink + +LocalLink::LocalLink(XRefDefs* defs, XRefDests* dests, PDFWriter* writer, BString* utf8, BFont* font, int32 page) + : ::Link(writer, utf8, font) + , fDefs(defs) + , fDests(dests) + , fLinkPage(page) +{ +} + + +bool LocalLink::Link(XRefDef* def, MatchResult* result) { + if (result->CountResults() >= 2) { + BString label; + result->GetString(1, &label); + if (fDests->Find(def, label.String(), &fDestPage)) { + result->Start(1); + fContainsLink = true; + fStartPos = result->Start(1) - fUtf8->String(); + const char* p = result->Start(1) + result->Length(1); + do { + p --; + } while (!BEGINS_CHAR(*p)); + fEndPos = p - fUtf8->String(); + return false; + } else { + REPORT(kWarning, fLinkPage, "Destination for link '%s' not found!", label.String()); + } + } + return true; +} + + +bool LocalLink::Dest(XRefDef* def, MatchResult* result) { + return true; +} + + +void LocalLink::DetectLink(int start) { + fContainsLink = false; + fDefs->Matches(fUtf8->String() + start, this, true); +} + + +void LocalLink::CreateLink(float llx, float lly, float urx, float ury) { + if (fDestPage != fLinkPage) { + BString s(&fUtf8->String()[fStartPos], fEndPos-fStartPos+1); + REPORT(kInfo, fLinkPage, "Link '%s' to page %d", s.String(), fDestPage); + PDF_add_locallink(fWriter->fPdf, llx, lly, urx, ury, fDestPage, "retain"); + } +} diff --git a/src/add-ons/print/drivers/pdf/source/XReferences.h b/src/add-ons/print/drivers/pdf/source/XReferences.h new file mode 100644 index 0000000000..7d72b72a9a --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/XReferences.h @@ -0,0 +1,234 @@ +/* + +Cross References. + +Copyright (c) 2002 OpenBeOS. + +Author: + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef _X_REF_H +#define _X_REF_H + +#include +#include "Link.h" +#include "RegExp.h" +#include "Utils.h" + +class MatchResult; +class Pattern; + + +// PatternList + +typedef TList PatternList; + + +// Pattern + +class Pattern { +protected: + RegExp fPattern; + + Pattern() { }; + +public: + Pattern(const char* pattern); + virtual ~Pattern(); + status_t InitCheck(); + bool Matches(const char* string, MatchResult* result) const; + + virtual bool IsLink() const { return false; } + virtual bool IsDest() const { return false; } + void Print() const; +}; + + +// two subclasses for destinction between link and anchor + +class LinkPattern : public Pattern { +public: + LinkPattern(const char* pattern) : Pattern(pattern) { } + + bool IsLink() const { return true; } +}; + + +class DestPattern : public Pattern { +public: + DestPattern(const char* pattern) : Pattern(pattern) { } + + bool IsDest() const { return true; } +}; + + +// MatchResult; wrapper for struct regexp + +// NB: Pattern object must not die while MatchResult is alive +// Pattern::Matches() invalidates a previous MatchResult! + +class MatchResult { +private: + regexp* fRegExp; + const char* fString; + int32 fResults; + + bool HasResult(int32 index) const; +public: + MatchResult(); + void SetRegExp(regexp* regexp) { fRegExp = regexp; } + void SetString(const char* string) { fString = string; } + void SetResults(int32 results) { fResults = results; } + + int32 CountResults() const { return fResults; } + const char* Start(int index) const; + int32 StartPos(int index) const; // inclusive + int32 EndPos(int index) const; // exclusive + int32 Length(int index) const { return EndPos(index) - StartPos(index); } + void GetString(int index, BString *result); +}; + + +// XRefDef + +class XRefDef { +private: + PatternList fLinks; + PatternList fDests; + int fId; + + Pattern* Matches(PatternList* list, const char* s, const char** start, int32 *len); + +public: + XRefDef() { fId = -1; } + + void SetId(int32 id) { fId = id; } + int32 Id() const { return fId; } + + void AddLink(LinkPattern* p) { fLinks.AddItem(p); } + void AddDest(DestPattern* p) { fDests.AddItem(p); } + int32 CountLinks() const { return fLinks.CountItems(); } + int32 CountDests() const { return fDests.CountItems(); } + Pattern* LinkAt(int32 index) const { return fLinks.ItemAt(index); } + Pattern* DestAt(int32 index) const { return fDests.ItemAt(index); } + + Pattern* Matches(const char* s, const char** start, int32 *len); +}; + + +// XMatchResult; called from XRefDefs::Matches with matches + +class XMatchResult { +public: + virtual ~XMatchResult() { }; + virtual bool Link(XRefDef* def, MatchResult* result) = 0; + virtual bool Dest(XRefDef* def, MatchResult* result) = 0; +}; + + +// XRefDefs + +class XRefDefs { +private: + TList fDefs; +public: + + void Add(XRefDef* def); + int32 Count() { return fDefs.CountItems(); } + // if "all" is false, only start of string is matched + void Matches(const char* s, XMatchResult* result, bool all); + + bool Read(const char* name); +}; + + +// Destination + +class Destination { +private: + BString fLabel; + int32 fPage; + +public: + Destination(const char* label, int32 page); + const char* Label() const { return fLabel.String(); } + int32 Page() const { return fPage; } +}; + + +// DestList + +class DestList : public TList { +public: + void Sort(); + Destination* Find(const char* label); +}; + + +// XRefDests; container for the destinations + +class XRefDests { + TList fDests; + + DestList* GetList(XRefDef* def) const { return fDests.ItemAt(def->Id()); } + +public: + XRefDests(int32 n); + bool Add(XRefDef* def, const char* label, int32 page); + bool Find(XRefDef* def, const char* label, int32* page) const; +}; + + +// RecordDests; detect destinations and store them in XRefDests object + +class RecordDests : public XMatchResult { + XRefDests* fDests; + int32 fPage; + +public: + RecordDests(XRefDests* dests, int32 page); + bool Link(XRefDef* def, MatchResult* result); + bool Dest(XRefDef* def, MatchResult* result); +}; + + +// LocalLink; detect links and create local links in PDF to destination + +class LocalLink : public Link, XMatchResult { +protected: + XRefDefs* fDefs; + XRefDests* fDests; + + int32 fLinkPage, fDestPage; + + void DetectLink(int start); + void CreateLink(float llx, float lly, float urx, float ury); + +public: + LocalLink(XRefDefs* defs, XRefDests* dests, PDFWriter* writer, BString* utf8, BFont* font, int32 page); + bool Link(XRefDef* def, MatchResult* result); + bool Dest(XRefDef* def, MatchResult* result); +}; + + +#endif diff --git a/src/add-ons/print/drivers/pdf/source/_CopyAndRestart b/src/add-ons/print/drivers/pdf/source/_CopyAndRestart new file mode 100755 index 0000000000..bd820b008b --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/_CopyAndRestart @@ -0,0 +1,11 @@ +#! /bin/sh +cd $(dirname "$0") + +# remove cpu postfix +mv PDF\ Writer\ x86 PDF\ Writer + +# copy driver to Print add-ons directory +cp PDF\ Writer /boot/home/config/add-ons/Print + +# restart print_server +/boot/beos/system/servers/print_server \ No newline at end of file diff --git a/src/add-ons/print/drivers/pdf/source/cns1.h b/src/add-ons/print/drivers/pdf/source/cns1.h new file mode 100644 index 0000000000..4fb589b4eb --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/cns1.h @@ -0,0 +1,11120 @@ +// WARNING: MACHINE GENERATED, DON'T CHANGE! +static unicode_to_cid CNS1[] = { + {0x20, 1}, + {0x21, 2}, + {0x22, 3}, + {0x23, 4}, + {0x24, 5}, + {0x25, 6}, + {0x26, 7}, + {0x27, 8}, + {0x28, 9}, + {0x29, 10}, + {0x2a, 11}, + {0x2b, 12}, + {0x2c, 13}, + {0x2d, 14}, + {0x2e, 15}, + {0x2f, 16}, + {0x30, 17}, + {0x31, 18}, + {0x32, 19}, + {0x33, 20}, + {0x34, 21}, + {0x35, 22}, + {0x36, 23}, + {0x37, 24}, + {0x38, 25}, + {0x39, 26}, + {0x3a, 27}, + {0x3b, 28}, + {0x3c, 29}, + {0x3d, 30}, + {0x3e, 31}, + {0x3f, 32}, + {0x40, 33}, + {0x41, 34}, + {0x42, 35}, + {0x43, 36}, + {0x44, 37}, + {0x45, 38}, + {0x46, 39}, + {0x47, 40}, + {0x48, 41}, + {0x49, 42}, + {0x4a, 43}, + {0x4b, 44}, + {0x4c, 45}, + {0x4d, 46}, + {0x4e, 47}, + {0x4f, 48}, + {0x50, 49}, + {0x51, 50}, + {0x52, 51}, + {0x53, 52}, + {0x54, 53}, + {0x55, 54}, + {0x56, 55}, + {0x57, 56}, + {0x58, 57}, + {0x59, 58}, + {0x5a, 59}, + {0x5b, 60}, + {0x5c, 61}, + {0x5d, 62}, + {0x5e, 63}, + {0x5f, 64}, + {0x60, 65}, + {0x61, 66}, + {0x62, 67}, + {0x63, 68}, + {0x64, 69}, + {0x65, 70}, + {0x66, 71}, + {0x67, 72}, + {0x68, 73}, + {0x69, 74}, + {0x6a, 75}, + {0x6b, 76}, + {0x6c, 77}, + {0x6d, 78}, + {0x6e, 79}, + {0x6f, 80}, + {0x70, 81}, + {0x71, 82}, + {0x72, 83}, + {0x73, 84}, + {0x74, 85}, + {0x75, 86}, + {0x76, 87}, + {0x77, 88}, + {0x78, 89}, + {0x79, 90}, + {0x7a, 91}, + {0x7b, 92}, + {0x7c, 93}, + {0x7d, 94}, + {0x7e, 95}, + {0xa2, 262}, + {0xa3, 263}, + {0xa5, 260}, + {0xa7, 178}, + {0xb0, 280}, + {0xb1, 212}, + {0xb7, 115}, + {0xd7, 210}, + {0xf7, 211}, + {0x2c7, 504}, + {0x2ca, 503}, + {0x2cb, 505}, + {0x2d9, 502}, + {0x391, 417}, + {0x392, 418}, + {0x393, 419}, + {0x394, 420}, + {0x395, 421}, + {0x396, 422}, + {0x397, 423}, + {0x398, 424}, + {0x399, 425}, + {0x39a, 426}, + {0x39b, 427}, + {0x39c, 428}, + {0x39d, 429}, + {0x39e, 430}, + {0x39f, 431}, + {0x3a0, 432}, + {0x3a1, 433}, + {0x3a3, 434}, + {0x3a4, 435}, + {0x3a5, 436}, + {0x3a6, 437}, + {0x3a7, 438}, + {0x3a8, 439}, + {0x3a9, 440}, + {0x3b1, 441}, + {0x3b2, 442}, + {0x3b3, 443}, + {0x3b4, 444}, + {0x3b5, 445}, + {0x3b6, 446}, + {0x3b7, 447}, + {0x3b8, 448}, + {0x3b9, 449}, + {0x3ba, 450}, + {0x3bb, 451}, + {0x3bc, 452}, + {0x3bd, 453}, + {0x3be, 454}, + {0x3bf, 455}, + {0x3c0, 456}, + {0x3c1, 457}, + {0x3c3, 458}, + {0x3c4, 459}, + {0x3c5, 460}, + {0x3c6, 461}, + {0x3c7, 462}, + {0x3c8, 463}, + {0x3c9, 464}, + {0x411, 0}, + {0x412, 1}, + {0x413, 2}, + {0x414, 3}, + {0x415, 4}, + {0x417, 0}, + {0x418, 1}, + {0x419, 2}, + {0x41a, 3}, + {0x41b, 4}, + {0x41c, 5}, + {0x41d, 6}, + {0x41e, 7}, + {0x41f, 8}, + {0x420, 9}, + {0x421, 10}, + {0x422, 11}, + {0x423, 12}, + {0x424, 13}, + {0x425, 14}, + {0x426, 15}, + {0x427, 16}, + {0x428, 17}, + {0x429, 18}, + {0x42a, 19}, + {0x42b, 20}, + {0x42c, 21}, + {0x42d, 22}, + {0x42e, 23}, + {0x42f, 24}, + {0x430, 25}, + {0x431, 26}, + {0x432, 27}, + {0x433, 28}, + {0x434, 29}, + {0x435, 30}, + {0x437, 0}, + {0x438, 1}, + {0x439, 2}, + {0x43a, 3}, + {0x43b, 4}, + {0x43c, 5}, + {0x43d, 6}, + {0x43e, 7}, + {0x43f, 8}, + {0x440, 9}, + {0x441, 10}, + {0x442, 11}, + {0x443, 12}, + {0x444, 13}, + {0x445, 14}, + {0x446, 15}, + {0x447, 16}, + {0x448, 17}, + {0x449, 18}, + {0x44a, 19}, + {0x44b, 20}, + {0x44c, 21}, + {0x44d, 22}, + {0x44e, 23}, + {0x44f, 24}, + {0x2013, 121}, + {0x2014, 123}, + {0x2018, 166}, + {0x2019, 167}, + {0x201c, 168}, + {0x201d, 169}, + {0x2022, 104}, + {0x2025, 111}, + {0x2026, 110}, + {0x2032, 173}, + {0x2035, 172}, + {0x203b, 177}, + {0x203e, 195}, + {0x2103, 266}, + {0x2105, 194}, + {0x2109, 267}, + {0x2160, 343}, + {0x2161, 344}, + {0x2162, 345}, + {0x2163, 346}, + {0x2164, 347}, + {0x2165, 348}, + {0x2166, 349}, + {0x2167, 350}, + {0x2168, 351}, + {0x2169, 352}, + {0x2170, 526}, + {0x2171, 527}, + {0x2172, 528}, + {0x2173, 529}, + {0x2174, 530}, + {0x2175, 531}, + {0x2176, 532}, + {0x2177, 533}, + {0x2178, 534}, + {0x2179, 535}, + {0x2190, 248}, + {0x2191, 245}, + {0x2192, 247}, + {0x2193, 246}, + {0x2196, 249}, + {0x2197, 250}, + {0x2198, 252}, + {0x2199, 251}, + {0x21b9, 0}, + {0x221a, 213}, + {0x221e, 220}, + {0x221f, 233}, + {0x2220, 232}, + {0x2223, 254}, + {0x2225, 253}, + {0x2229, 229}, + {0x222a, 230}, + {0x222b, 237}, + {0x222e, 238}, + {0x2234, 240}, + {0x2235, 239}, + {0x223c, 228}, + {0x2252, 221}, + {0x2260, 219}, + {0x2261, 222}, + {0x2266, 217}, + {0x2267, 218}, + {0x22a5, 231}, + {0x22bf, 234}, + {0x2400, 562}, + {0x2401, 563}, + {0x2402, 564}, + {0x2403, 565}, + {0x2404, 566}, + {0x2405, 567}, + {0x2406, 568}, + {0x2407, 569}, + {0x2408, 570}, + {0x2409, 571}, + {0x240a, 572}, + {0x240b, 573}, + {0x240c, 574}, + {0x240d, 575}, + {0x240e, 576}, + {0x240f, 577}, + {0x2410, 578}, + {0x2411, 579}, + {0x2412, 580}, + {0x2413, 581}, + {0x2414, 582}, + {0x2415, 583}, + {0x2416, 584}, + {0x2417, 585}, + {0x2418, 586}, + {0x2419, 587}, + {0x241a, 588}, + {0x241b, 589}, + {0x241c, 590}, + {0x241d, 591}, + {0x241e, 592}, + {0x241f, 593}, + {0x2421, 594}, + {0x2460, 506}, + {0x2461, 507}, + {0x2462, 508}, + {0x2463, 509}, + {0x2464, 510}, + {0x2465, 511}, + {0x2466, 512}, + {0x2467, 513}, + {0x2468, 514}, + {0x2469, 515}, + {0x2474, 516}, + {0x2475, 517}, + {0x2476, 518}, + {0x2477, 519}, + {0x2478, 520}, + {0x2479, 521}, + {0x247a, 522}, + {0x247b, 523}, + {0x247c, 524}, + {0x247d, 525}, + {0x2500, 311}, + {0x2502, 312}, + {0x250c, 314}, + {0x2510, 315}, + {0x2514, 316}, + {0x2518, 317}, + {0x251c, 309}, + {0x2524, 308}, + {0x252c, 307}, + {0x2534, 306}, + {0x253c, 305}, + {0x2550, 322}, + {0x255e, 323}, + {0x2561, 325}, + {0x256a, 324}, + {0x256d, 318}, + {0x256e, 319}, + {0x256f, 321}, + {0x2570, 320}, + {0x2571, 330}, + {0x2572, 331}, + {0x2573, 332}, + {0x2581, 290}, + {0x2582, 291}, + {0x2583, 292}, + {0x2584, 293}, + {0x2585, 294}, + {0x2586, 295}, + {0x2587, 296}, + {0x2588, 297}, + {0x2589, 304}, + {0x258a, 303}, + {0x258b, 302}, + {0x258c, 301}, + {0x258d, 300}, + {0x258e, 299}, + {0x258f, 298}, + {0x2594, 310}, + {0x2595, 313}, + {0x25a0, 190}, + {0x25a1, 189}, + {0x25b2, 183}, + {0x25b3, 182}, + {0x25bc, 192}, + {0x25bd, 191}, + {0x25c6, 188}, + {0x25c7, 187}, + {0x25cb, 180}, + {0x25ce, 184}, + {0x25cf, 181}, + {0x25e2, 326}, + {0x25e3, 327}, + {0x25e4, 329}, + {0x25e5, 328}, + {0x2605, 186}, + {0x2606, 185}, + {0x2609, 244}, + {0x2640, 241}, + {0x2641, 243}, + {0x2642, 242}, + {0x2e87, 0}, + {0x2e88, 1}, + {0x2e8d, 0}, + {0x2e9d, 732}, + {0x2ec6, 1289}, + {0x2ecd, 0}, + {0x2ed7, 0}, + {0x2ee3, 2550}, + {0x2f33, 551}, + {0x3000, 99}, + {0x3001, 101}, + {0x3002, 102}, + {0x3003, 179}, + {0x3006, 0}, + {0x3007, 1}, + {0x3008, 148}, + {0x3009, 149}, + {0x300a, 144}, + {0x300b, 145}, + {0x300c, 152}, + {0x300d, 153}, + {0x300e, 156}, + {0x300f, 157}, + {0x3010, 140}, + {0x3011, 141}, + {0x3012, 261}, + {0x3014, 136}, + {0x3015, 137}, + {0x301d, 170}, + {0x301e, 171}, + {0x3021, 353}, + {0x3022, 354}, + {0x3023, 355}, + {0x3024, 356}, + {0x3025, 357}, + {0x3026, 358}, + {0x3027, 359}, + {0x3028, 360}, + {0x3029, 361}, + {0x3042, 0}, + {0x3043, 1}, + {0x3044, 2}, + {0x3045, 3}, + {0x3046, 4}, + {0x3047, 5}, + {0x3048, 6}, + {0x3049, 7}, + {0x304a, 8}, + {0x304b, 9}, + {0x304c, 10}, + {0x304d, 11}, + {0x304e, 12}, + {0x304f, 13}, + {0x3050, 14}, + {0x3051, 15}, + {0x3052, 16}, + {0x3053, 17}, + {0x3054, 18}, + {0x3055, 19}, + {0x3056, 20}, + {0x3057, 21}, + {0x3058, 22}, + {0x3059, 23}, + {0x305a, 24}, + {0x305b, 25}, + {0x305c, 26}, + {0x305d, 27}, + {0x305e, 28}, + {0x305f, 29}, + {0x3060, 30}, + {0x3061, 31}, + {0x3062, 32}, + {0x3063, 33}, + {0x3064, 34}, + {0x3065, 35}, + {0x3066, 36}, + {0x3067, 37}, + {0x3068, 38}, + {0x3069, 39}, + {0x306a, 40}, + {0x306b, 41}, + {0x306c, 42}, + {0x306d, 43}, + {0x306e, 44}, + {0x306f, 45}, + {0x3070, 46}, + {0x3071, 47}, + {0x3072, 48}, + {0x3073, 49}, + {0x3074, 50}, + {0x3075, 51}, + {0x3076, 52}, + {0x3077, 53}, + {0x3078, 54}, + {0x3079, 55}, + {0x307a, 56}, + {0x307b, 57}, + {0x307c, 58}, + {0x307d, 59}, + {0x307e, 60}, + {0x307f, 61}, + {0x3080, 62}, + {0x3081, 63}, + {0x3082, 64}, + {0x3083, 65}, + {0x3084, 66}, + {0x3085, 67}, + {0x3086, 68}, + {0x3087, 69}, + {0x3088, 70}, + {0x3089, 71}, + {0x308a, 72}, + {0x308b, 73}, + {0x308c, 74}, + {0x308d, 75}, + {0x308e, 76}, + {0x308f, 77}, + {0x3090, 78}, + {0x3091, 79}, + {0x3092, 80}, + {0x3093, 81}, + {0x309c, 0}, + {0x309e, 0}, + {0x30a2, 0}, + {0x30a3, 1}, + {0x30a4, 2}, + {0x30a5, 3}, + {0x30a6, 4}, + {0x30a7, 5}, + {0x30a8, 6}, + {0x30a9, 7}, + {0x30aa, 8}, + {0x30ab, 9}, + {0x30ac, 10}, + {0x30ad, 11}, + {0x30ae, 12}, + {0x30af, 13}, + {0x30b0, 14}, + {0x30b1, 15}, + {0x30b2, 16}, + {0x30b3, 17}, + {0x30b4, 18}, + {0x30b5, 19}, + {0x30b6, 20}, + {0x30b7, 21}, + {0x30b8, 22}, + {0x30b9, 23}, + {0x30ba, 24}, + {0x30bb, 25}, + {0x30bc, 26}, + {0x30bd, 27}, + {0x30be, 28}, + {0x30bf, 29}, + {0x30c0, 30}, + {0x30c1, 31}, + {0x30c2, 32}, + {0x30c3, 33}, + {0x30c4, 34}, + {0x30c5, 35}, + {0x30c6, 36}, + {0x30c7, 37}, + {0x30c8, 38}, + {0x30c9, 39}, + {0x30ca, 40}, + {0x30cb, 41}, + {0x30cc, 42}, + {0x30cd, 43}, + {0x30ce, 44}, + {0x30cf, 45}, + {0x30d0, 46}, + {0x30d1, 47}, + {0x30d2, 48}, + {0x30d3, 49}, + {0x30d4, 50}, + {0x30d5, 51}, + {0x30d6, 52}, + {0x30d7, 53}, + {0x30d8, 54}, + {0x30d9, 55}, + {0x30da, 56}, + {0x30db, 57}, + {0x30dc, 58}, + {0x30dd, 59}, + {0x30de, 60}, + {0x30df, 61}, + {0x30e0, 62}, + {0x30e1, 63}, + {0x30e2, 64}, + {0x30e3, 65}, + {0x30e4, 66}, + {0x30e5, 67}, + {0x30e6, 68}, + {0x30e7, 69}, + {0x30e8, 70}, + {0x30e9, 71}, + {0x30ea, 72}, + {0x30eb, 73}, + {0x30ec, 74}, + {0x30ed, 75}, + {0x30ee, 76}, + {0x30ef, 77}, + {0x30f0, 78}, + {0x30f1, 79}, + {0x30f2, 80}, + {0x30f3, 81}, + {0x30f4, 82}, + {0x30f5, 83}, + {0x30f6, 84}, + {0x30fe, 0}, + {0x3105, 465}, + {0x3106, 466}, + {0x3107, 467}, + {0x3108, 468}, + {0x3109, 469}, + {0x310a, 470}, + {0x310b, 471}, + {0x310c, 472}, + {0x310d, 473}, + {0x310e, 474}, + {0x310f, 475}, + {0x3110, 476}, + {0x3111, 477}, + {0x3112, 478}, + {0x3113, 479}, + {0x3114, 480}, + {0x3115, 481}, + {0x3116, 482}, + {0x3117, 483}, + {0x3118, 484}, + {0x3119, 485}, + {0x311a, 486}, + {0x311b, 487}, + {0x311c, 488}, + {0x311d, 489}, + {0x311e, 490}, + {0x311f, 491}, + {0x3120, 492}, + {0x3121, 493}, + {0x3122, 494}, + {0x3123, 495}, + {0x3124, 496}, + {0x3125, 497}, + {0x3126, 498}, + {0x3127, 499}, + {0x3128, 500}, + {0x3129, 501}, + {0x32a3, 193}, + {0x338e, 277}, + {0x338f, 278}, + {0x339c, 272}, + {0x339d, 273}, + {0x339e, 274}, + {0x33a1, 276}, + {0x33c4, 279}, + {0x33ce, 275}, + {0x33d1, 236}, + {0x33d2, 235}, + {0x33d5, 271}, + {0x4e00, 595}, + {0x4e01, 597}, + {0x4e03, 598}, + {0x4e07, 6001}, + {0x4e08, 617}, + {0x4e09, 615}, + {0x4e0a, 618}, + {0x4e0b, 616}, + {0x4e0c, 6002}, + {0x4e0d, 660}, + {0x4e0e, 6010}, + {0x4e0f, 6008}, + {0x4e10, 659}, + {0x4e11, 658}, + {0x4e14, 754}, + {0x4e15, 753}, + {0x4e16, 752}, + {0x4e18, 755}, + {0x4e19, 751}, + {0x4e1e, 878}, + {0x4e1f, 879}, + {0x4e26, 1320}, + {0x4e28, 536}, + {0x4e2b, 619}, + {0x4e2d, 661}, + {0x4e2e, 6011}, + {0x4e30, 662}, + {0x4e31, 6030}, + {0x4e32, 1045}, + {0x4e33, 6388}, + {0x4e36, 537}, + {0x4e38, 620}, + {0x4e39, 663}, + {0x4e3b, 756}, + {0x4e3c, 6031}, + {0x4e3f, 538}, + {0x4e42, 5996}, + {0x4e43, 599}, + {0x4e45, 622}, + {0x4e47, 6003}, + {0x4e48, 623}, + {0x4e4b, 664}, + {0x4e4d, 757}, + {0x4e4e, 759}, + {0x4e4f, 758}, + {0x4e52, 880}, + {0x4e53, 881}, + {0x4e56, 1321}, + {0x4e58, 2097}, + {0x4e59, 596}, + {0x4e5c, 5997}, + {0x4e5d, 600}, + {0x4e5e, 625}, + {0x4e5f, 624}, + {0x4e69, 882}, + {0x4e73, 1322}, + {0x4e7e, 2555}, + {0x4e7f, 7733}, + {0x4e82, 3518}, + {0x4e83, 9057}, + {0x4e84, 9058}, + {0x4e85, 539}, + {0x4e86, 601}, + {0x4e88, 666}, + {0x4e8b, 1323}, + {0x4e8c, 602}, + {0x4e8d, 6004}, + {0x4e8e, 626}, + {0x4e91, 667}, + {0x4e92, 669}, + {0x4e93, 6012}, + {0x4e94, 670}, + {0x4e95, 668}, + {0x4e99, 883}, + {0x4e9b, 1324}, + {0x4e9e, 1325}, + {0x4e9f, 1699}, + {0x4ea0, 540}, + {0x4ea1, 627}, + {0x4ea2, 671}, + {0x4ea4, 884}, + {0x4ea5, 886}, + {0x4ea6, 885}, + {0x4ea8, 1046}, + {0x4eab, 1326}, + {0x4eac, 1327}, + {0x4ead, 1700}, + {0x4eae, 1701}, + {0x4eb3, 2098}, + {0x4eb6, 9059}, + {0x4eba, 603}, + {0x4ec0, 673}, + {0x4ec1, 672}, + {0x4ec2, 6013}, + {0x4ec3, 674}, + {0x4ec4, 680}, + {0x4ec6, 675}, + {0x4ec7, 676}, + {0x4ec8, 6015}, + {0x4ec9, 6014}, + {0x4eca, 678}, + {0x4ecb, 679}, + {0x4ecd, 677}, + {0x4ed4, 762}, + {0x4ed5, 763}, + {0x4ed6, 764}, + {0x4ed7, 765}, + {0x4ed8, 761}, + {0x4ed9, 768}, + {0x4eda, 6037}, + {0x4edc, 6033}, + {0x4edd, 6036}, + {0x4ede, 769}, + {0x4edf, 785}, + {0x4ee1, 6035}, + {0x4ee3, 766}, + {0x4ee4, 767}, + {0x4ee5, 760}, + {0x4ee8, 6032}, + {0x4ee9, 6034}, + {0x4ef0, 899}, + {0x4ef1, 6074}, + {0x4ef2, 896}, + {0x4ef3, 900}, + {0x4ef4, 6084}, + {0x4ef5, 6072}, + {0x4ef6, 897}, + {0x4ef7, 6076}, + {0x4efb, 898}, + {0x4efd, 901}, + {0x4eff, 887}, + {0x4f00, 6075}, + {0x4f01, 902}, + {0x4f02, 6079}, + {0x4f04, 6083}, + {0x4f05, 6080}, + {0x4f08, 6077}, + {0x4f09, 888}, + {0x4f0a, 890}, + {0x4f0b, 903}, + {0x4f0d, 892}, + {0x4f0e, 6069}, + {0x4f0f, 895}, + {0x4f10, 893}, + {0x4f11, 894}, + {0x4f12, 6085}, + {0x4f13, 6082}, + {0x4f14, 6073}, + {0x4f15, 891}, + {0x4f18, 6070}, + {0x4f19, 889}, + {0x4f1d, 6078}, + {0x4f22, 6081}, + {0x4f2c, 6071}, + {0x4f2d, 6191}, + {0x4f2f, 1068}, + {0x4f30, 1055}, + {0x4f33, 6192}, + {0x4f34, 1052}, + {0x4f36, 1070}, + {0x4f38, 1060}, + {0x4f3a, 1059}, + {0x4f3b, 6180}, + {0x4f3c, 1063}, + {0x4f3d, 1058}, + {0x4f3e, 6185}, + {0x4f3f, 6193}, + {0x4f41, 6189}, + {0x4f43, 1061}, + {0x4f46, 1064}, + {0x4f47, 1049}, + {0x4f48, 1073}, + {0x4f49, 6182}, + {0x4f4c, 6400}, + {0x4f4d, 1047}, + {0x4f4e, 1069}, + {0x4f4f, 1048}, + {0x4f50, 1056}, + {0x4f51, 1057}, + {0x4f52, 6187}, + {0x4f53, 6183}, + {0x4f54, 1062}, + {0x4f55, 1054}, + {0x4f56, 6179}, + {0x4f57, 1050}, + {0x4f58, 6190}, + {0x4f59, 1071}, + {0x4f5a, 1074}, + {0x4f5b, 1053}, + {0x4f5c, 1066}, + {0x4f5d, 1072}, + {0x4f5e, 1051}, + {0x4f5f, 6188}, + {0x4f60, 1067}, + {0x4f61, 6194}, + {0x4f62, 6181}, + {0x4f63, 1065}, + {0x4f64, 6184}, + {0x4f67, 6186}, + {0x4f69, 1341}, + {0x4f6a, 6402}, + {0x4f6b, 6414}, + {0x4f6c, 1333}, + {0x4f6e, 6415}, + {0x4f6f, 1328}, + {0x4f70, 1338}, + {0x4f73, 1331}, + {0x4f74, 6396}, + {0x4f75, 1339}, + {0x4f76, 6395}, + {0x4f77, 6399}, + {0x4f78, 6406}, + {0x4f79, 6404}, + {0x4f7a, 1347}, + {0x4f7b, 1342}, + {0x4f7c, 6390}, + {0x4f7d, 6392}, + {0x4f7e, 1344}, + {0x4f7f, 1332}, + {0x4f80, 6393}, + {0x4f81, 6405}, + {0x4f82, 6412}, + {0x4f83, 1337}, + {0x4f84, 6398}, + {0x4f85, 6391}, + {0x4f86, 1336}, + {0x4f87, 6394}, + {0x4f88, 1340}, + {0x4f89, 6397}, + {0x4f8b, 1335}, + {0x4f8d, 1330}, + {0x4f8f, 1345}, + {0x4f90, 6407}, + {0x4f91, 1346}, + {0x4f92, 6411}, + {0x4f94, 6409}, + {0x4f95, 6413}, + {0x4f96, 1343}, + {0x4f97, 6401}, + {0x4f98, 6389}, + {0x4f9a, 6403}, + {0x4f9b, 1334}, + {0x4f9c, 6408}, + {0x4f9d, 1329}, + {0x4f9e, 6410}, + {0x4fae, 1716}, + {0x4faf, 1704}, + {0x4fb2, 6749}, + {0x4fb3, 6757}, + {0x4fb5, 1703}, + {0x4fb6, 1711}, + {0x4fb7, 1723}, + {0x4fb9, 6763}, + {0x4fba, 6761}, + {0x4fbb, 6756}, + {0x4fbf, 1705}, + {0x4fc0, 6762}, + {0x4fc1, 6752}, + {0x4fc2, 1719}, + {0x4fc3, 1710}, + {0x4fc4, 1718}, + {0x4fc5, 6747}, + {0x4fc7, 6759}, + {0x4fc9, 6750}, + {0x4fca, 1714}, + {0x4fcb, 6751}, + {0x4fcd, 6746}, + {0x4fce, 1721}, + {0x4fcf, 1708}, + {0x4fd0, 1717}, + {0x4fd1, 1707}, + {0x4fd3, 6748}, + {0x4fd4, 6753}, + {0x4fd6, 6760}, + {0x4fd7, 1715}, + {0x4fd8, 1712}, + {0x4fd9, 6755}, + {0x4fda, 1720}, + {0x4fdb, 6758}, + {0x4fdc, 6754}, + {0x4fdd, 1709}, + {0x4fde, 1722}, + {0x4fdf, 1713}, + {0x4fe0, 1706}, + {0x4fe1, 1702}, + {0x4fec, 6764}, + {0x4fee, 2124}, + {0x4fef, 2102}, + {0x4ff1, 2118}, + {0x4ff3, 2123}, + {0x4ff4, 7204}, + {0x4ff5, 7203}, + {0x4ff6, 7208}, + {0x4ff7, 7209}, + {0x4ff8, 2105}, + {0x4ffa, 2114}, + {0x4ffe, 2127}, + {0x5000, 2115}, + {0x5005, 7197}, + {0x5006, 2108}, + {0x5007, 7198}, + {0x5009, 2129}, + {0x500b, 2120}, + {0x500c, 2099}, + {0x500d, 2100}, + {0x500e, 7217}, + {0x500f, 2572}, + {0x5011, 2113}, + {0x5012, 2112}, + {0x5013, 7199}, + {0x5014, 2116}, + {0x5015, 7749}, + {0x5016, 2107}, + {0x5017, 7210}, + {0x5018, 2122}, + {0x5019, 2121}, + {0x501a, 2111}, + {0x501b, 7202}, + {0x501c, 7211}, + {0x501e, 7196}, + {0x501f, 2110}, + {0x5020, 7212}, + {0x5021, 2119}, + {0x5022, 7200}, + {0x5023, 2101}, + {0x5025, 2104}, + {0x5026, 2103}, + {0x5027, 7213}, + {0x5028, 2117}, + {0x5029, 2106}, + {0x502a, 2126}, + {0x502b, 2128}, + {0x502c, 7207}, + {0x502d, 2125}, + {0x502f, 7215}, + {0x5030, 7201}, + {0x5031, 7216}, + {0x5033, 7205}, + {0x5035, 7214}, + {0x5037, 7206}, + {0x503c, 2109}, + {0x5040, 7757}, + {0x5041, 7745}, + {0x5043, 2560}, + {0x5045, 7750}, + {0x5046, 7756}, + {0x5047, 2559}, + {0x5048, 7743}, + {0x5049, 2563}, + {0x504a, 7747}, + {0x504b, 7740}, + {0x504c, 2561}, + {0x504d, 7744}, + {0x504e, 2566}, + {0x504f, 2571}, + {0x5051, 7761}, + {0x5053, 7739}, + {0x5055, 2567}, + {0x5057, 7760}, + {0x505a, 2562}, + {0x505b, 7746}, + {0x505c, 2558}, + {0x505d, 7741}, + {0x505e, 7737}, + {0x505f, 7751}, + {0x5060, 7738}, + {0x5061, 7736}, + {0x5062, 7748}, + {0x5063, 7754}, + {0x5064, 7755}, + {0x5065, 2564}, + {0x5068, 8376}, + {0x5069, 7752}, + {0x506a, 7735}, + {0x506b, 7753}, + {0x506d, 2574}, + {0x506e, 7758}, + {0x506f, 2573}, + {0x5070, 7734}, + {0x5072, 7742}, + {0x5073, 7759}, + {0x5074, 2569}, + {0x5075, 2568}, + {0x5076, 2565}, + {0x5077, 2570}, + {0x507a, 2556}, + {0x507d, 2557}, + {0x5080, 3052}, + {0x5082, 8379}, + {0x5083, 8372}, + {0x5085, 3049}, + {0x5087, 8380}, + {0x508b, 8370}, + {0x508c, 8373}, + {0x508d, 3048}, + {0x508e, 8374}, + {0x5091, 3051}, + {0x5092, 8378}, + {0x5094, 8368}, + {0x5095, 8367}, + {0x5096, 3053}, + {0x5098, 3054}, + {0x5099, 3050}, + {0x509a, 3055}, + {0x509b, 8366}, + {0x509c, 8377}, + {0x509d, 8375}, + {0x509e, 8369}, + {0x50a2, 3047}, + {0x50a3, 8371}, + {0x50ac, 3525}, + {0x50ad, 3519}, + {0x50ae, 9063}, + {0x50af, 3528}, + {0x50b0, 9069}, + {0x50b1, 9072}, + {0x50b2, 3521}, + {0x50b3, 3522}, + {0x50b4, 9066}, + {0x50b5, 3520}, + {0x50b6, 9075}, + {0x50b7, 3526}, + {0x50b8, 9076}, + {0x50ba, 9071}, + {0x50bb, 3527}, + {0x50bd, 9060}, + {0x50be, 3524}, + {0x50bf, 9061}, + {0x50c1, 9070}, + {0x50c2, 9068}, + {0x50c4, 9064}, + {0x50c5, 3523}, + {0x50c6, 9062}, + {0x50c7, 3529}, + {0x50c8, 9067}, + {0x50c9, 9074}, + {0x50ca, 9065}, + {0x50cb, 9073}, + {0x50ce, 3976}, + {0x50cf, 3973}, + {0x50d1, 3974}, + {0x50d3, 9756}, + {0x50d4, 9748}, + {0x50d5, 3972}, + {0x50d6, 3969}, + {0x50d7, 9749}, + {0x50da, 3971}, + {0x50db, 9752}, + {0x50dd, 9754}, + {0x50e0, 9761}, + {0x50e3, 9760}, + {0x50e4, 9755}, + {0x50e5, 3968}, + {0x50e6, 9747}, + {0x50e7, 3966}, + {0x50e8, 9750}, + {0x50e9, 3977}, + {0x50ea, 9753}, + {0x50ec, 9757}, + {0x50ed, 3970}, + {0x50ee, 3967}, + {0x50ef, 9759}, + {0x50f0, 9758}, + {0x50f1, 3975}, + {0x50f3, 9751}, + {0x50f5, 4357}, + {0x50f9, 4358}, + {0x50fb, 4356}, + {0x5100, 4355}, + {0x5102, 4359}, + {0x5104, 4354}, + {0x5105, 4362}, + {0x5107, 0}, + {0x5108, 4360}, + {0x5109, 4361}, + {0x510c, 0}, + {0x5110, 4749}, + {0x5112, 4746}, + {0x5114, 4748}, + {0x5115, 4750}, + {0x5118, 4747}, + {0x511f, 5045}, + {0x5121, 5046}, + {0x512a, 5044}, + {0x512e, 0}, + {0x5132, 5047}, + {0x5133, 5493}, + {0x5135, 0}, + {0x5137, 5736}, + {0x5138, 5737}, + {0x513b, 5820}, + {0x513c, 5819}, + {0x513f, 604}, + {0x5140, 628}, + {0x5141, 682}, + {0x5143, 681}, + {0x5144, 771}, + {0x5145, 770}, + {0x5146, 906}, + {0x5147, 905}, + {0x5148, 907}, + {0x5149, 904}, + {0x514b, 1076}, + {0x514c, 1075}, + {0x514d, 1077}, + {0x5152, 1349}, + {0x5154, 1348}, + {0x5155, 1350}, + {0x5157, 1724}, + {0x5159, 281}, + {0x515a, 7218}, + {0x515b, 282}, + {0x515c, 2575}, + {0x515d, 284}, + {0x515e, 283}, + {0x515f, 8381}, + {0x5161, 285}, + {0x5162, 3978}, + {0x5163, 286}, + {0x5165, 605}, + {0x5167, 683}, + {0x5168, 908}, + {0x5169, 1351}, + {0x516b, 606}, + {0x516c, 686}, + {0x516d, 684}, + {0x516e, 685}, + {0x5171, 909}, + {0x5175, 1078}, + {0x5176, 1353}, + {0x5177, 1352}, + {0x5178, 1354}, + {0x517c, 2130}, + {0x5180, 4751}, + {0x5182, 541}, + {0x5187, 6009}, + {0x5189, 772}, + {0x518a, 773}, + {0x518d, 910}, + {0x518f, 6195}, + {0x5191, 1726}, + {0x5192, 1725}, + {0x5193, 7220}, + {0x5194, 7219}, + {0x5195, 2576}, + {0x5196, 542}, + {0x5197, 687}, + {0x5198, 6016}, + {0x519e, 6416}, + {0x51a0, 1727}, + {0x51a2, 2133}, + {0x51a4, 2131}, + {0x51a5, 2132}, + {0x51aa, 4752}, + {0x51ab, 543}, + {0x51ac, 774}, + {0x51b0, 911}, + {0x51b1, 6086}, + {0x51b6, 1079}, + {0x51b7, 1080}, + {0x51b9, 6196}, + {0x51bc, 6417}, + {0x51bd, 1355}, + {0x51be, 6418}, + {0x51c4, 7222}, + {0x51c5, 7223}, + {0x51c6, 2136}, + {0x51c8, 7224}, + {0x51ca, 7221}, + {0x51cb, 2137}, + {0x51cc, 2135}, + {0x51cd, 2134}, + {0x51ce, 7225}, + {0x51d0, 7762}, + {0x51d4, 8382}, + {0x51d7, 9077}, + {0x51d8, 9762}, + {0x51dc, 4363}, + {0x51dd, 4753}, + {0x51e0, 607}, + {0x51e1, 621}, + {0x51f0, 2577}, + {0x51f1, 3057}, + {0x51f3, 3979}, + {0x51f5, 5998}, + {0x51f6, 688}, + {0x51f8, 777}, + {0x51f9, 775}, + {0x51fa, 776}, + {0x51fd, 1356}, + {0x5200, 608}, + {0x5201, 609}, + {0x5203, 629}, + {0x5206, 689}, + {0x5207, 690}, + {0x5208, 691}, + {0x5209, 6039}, + {0x520a, 778}, + {0x520c, 6038}, + {0x520e, 915}, + {0x5210, 6088}, + {0x5211, 913}, + {0x5212, 914}, + {0x5213, 6087}, + {0x5216, 916}, + {0x5217, 912}, + {0x521c, 6197}, + {0x521d, 1675}, + {0x521e, 6198}, + {0x5221, 6199}, + {0x5224, 1082}, + {0x5225, 1081}, + {0x5228, 1085}, + {0x5229, 1083}, + {0x522a, 1084}, + {0x522e, 1362}, + {0x5230, 1361}, + {0x5231, 6423}, + {0x5232, 6420}, + {0x5233, 6421}, + {0x5235, 6419}, + {0x5236, 1363}, + {0x5237, 1359}, + {0x5238, 1358}, + {0x523a, 1360}, + {0x523b, 1357}, + {0x5241, 1364}, + {0x5243, 1729}, + {0x5244, 6765}, + {0x5246, 6422}, + {0x5247, 1734}, + {0x5249, 6766}, + {0x524a, 1730}, + {0x524b, 1733}, + {0x524c, 1732}, + {0x524d, 1731}, + {0x524e, 1728}, + {0x5252, 7228}, + {0x5254, 2140}, + {0x5255, 7231}, + {0x5256, 2138}, + {0x525a, 7227}, + {0x525b, 2141}, + {0x525c, 2139}, + {0x525d, 2142}, + {0x525e, 7229}, + {0x525f, 7230}, + {0x5261, 7226}, + {0x5262, 7232}, + {0x5269, 3061}, + {0x526a, 2578}, + {0x526b, 7763}, + {0x526c, 7765}, + {0x526d, 7764}, + {0x526e, 7766}, + {0x526f, 2579}, + {0x5272, 3058}, + {0x5274, 3059}, + {0x5275, 3060}, + {0x5277, 3531}, + {0x5278, 9079}, + {0x527a, 9078}, + {0x527b, 9080}, + {0x527c, 9081}, + {0x527d, 3532}, + {0x527f, 3530}, + {0x5280, 9763}, + {0x5281, 9764}, + {0x5282, 3981}, + {0x5283, 3980}, + {0x5287, 4364}, + {0x5288, 4365}, + {0x5289, 4366}, + {0x528a, 4368}, + {0x528c, 0}, + {0x528d, 4367}, + {0x5291, 4754}, + {0x5293, 4755}, + {0x529b, 610}, + {0x529f, 780}, + {0x52a0, 779}, + {0x52a3, 917}, + {0x52a6, 6089}, + {0x52a9, 1087}, + {0x52aa, 1088}, + {0x52ab, 1086}, + {0x52ac, 1089}, + {0x52ad, 6200}, + {0x52ae, 6201}, + {0x52bb, 1366}, + {0x52bc, 6424}, + {0x52be, 1365}, + {0x52c0, 6767}, + {0x52c1, 1738}, + {0x52c2, 6768}, + {0x52c3, 1737}, + {0x52c7, 1735}, + {0x52c9, 1736}, + {0x52cd, 7233}, + {0x52d2, 2580}, + {0x52d3, 7768}, + {0x52d5, 2583}, + {0x52d6, 7767}, + {0x52d7, 2767}, + {0x52d8, 2582}, + {0x52d9, 2581}, + {0x52db, 3064}, + {0x52dd, 3063}, + {0x52de, 3062}, + {0x52df, 3533}, + {0x52e2, 3536}, + {0x52e3, 3537}, + {0x52e4, 3535}, + {0x52e6, 3534}, + {0x52e9, 9765}, + {0x52eb, 9766}, + {0x52f0, 4369}, + {0x52f3, 4756}, + {0x52f5, 5048}, + {0x52f8, 5641}, + {0x52f9, 544}, + {0x52fa, 630}, + {0x52fb, 692}, + {0x52fc, 6017}, + {0x52fe, 693}, + {0x52ff, 694}, + {0x5305, 781}, + {0x5306, 782}, + {0x5308, 918}, + {0x5309, 6202}, + {0x530a, 6425}, + {0x530b, 6426}, + {0x530d, 1739}, + {0x530e, 7234}, + {0x530f, 2585}, + {0x5310, 2584}, + {0x5311, 8384}, + {0x5312, 8383}, + {0x5315, 611}, + {0x5316, 695}, + {0x5317, 783}, + {0x5319, 2586}, + {0x531a, 5999}, + {0x531c, 6040}, + {0x531d, 784}, + {0x531f, 6091}, + {0x5320, 920}, + {0x5321, 919}, + {0x5322, 6090}, + {0x5323, 1090}, + {0x532a, 2143}, + {0x532d, 7769}, + {0x532f, 3538}, + {0x5330, 9767}, + {0x5331, 3982}, + {0x5338, 545}, + {0x5339, 696}, + {0x533c, 6427}, + {0x533d, 6769}, + {0x533e, 2589}, + {0x533f, 2587}, + {0x5340, 2588}, + {0x5341, 612}, + {0x5343, 631}, + {0x5344, 363}, + {0x5345, 699}, + {0x5347, 698}, + {0x5348, 697}, + {0x5349, 787}, + {0x534a, 786}, + {0x534c, 6041}, + {0x534d, 6092}, + {0x5351, 1370}, + {0x5352, 1367}, + {0x5353, 1369}, + {0x5354, 1368}, + {0x5357, 1740}, + {0x535a, 3065}, + {0x535c, 613}, + {0x535e, 700}, + {0x5360, 789}, + {0x5361, 788}, + {0x5363, 6203}, + {0x5366, 1371}, + {0x5369, 546}, + {0x536c, 6018}, + {0x536e, 791}, + {0x536f, 790}, + {0x5370, 921}, + {0x5371, 922}, + {0x5372, 6204}, + {0x5373, 1091}, + {0x5375, 1092}, + {0x5377, 1372}, + {0x5378, 1373}, + {0x5379, 1374}, + {0x537b, 1741}, + {0x537c, 6770}, + {0x537f, 2144}, + {0x5382, 6000}, + {0x5384, 701}, + {0x538a, 6093}, + {0x538e, 6205}, + {0x538f, 6206}, + {0x5392, 6428}, + {0x5394, 6429}, + {0x5396, 6772}, + {0x5397, 6771}, + {0x5398, 6774}, + {0x5399, 6773}, + {0x539a, 1742}, + {0x539c, 7770}, + {0x539d, 2146}, + {0x539e, 7235}, + {0x539f, 2145}, + {0x53a4, 8385}, + {0x53a5, 3066}, + {0x53a7, 8386}, + {0x53ac, 9768}, + {0x53ad, 3983}, + {0x53b2, 4370}, + {0x53b6, 547}, + {0x53b9, 6019}, + {0x53bb, 792}, + {0x53c3, 2590}, + {0x53c8, 614}, + {0x53c9, 632}, + {0x53ca, 703}, + {0x53cb, 702}, + {0x53cd, 704}, + {0x53d4, 1376}, + {0x53d6, 1375}, + {0x53d7, 1377}, + {0x53db, 1743}, + {0x53df, 2147}, + {0x53e2, 5321}, + {0x53e3, 633}, + {0x53e4, 794}, + {0x53e5, 809}, + {0x53e6, 804}, + {0x53e8, 799}, + {0x53e9, 798}, + {0x53ea, 805}, + {0x53eb, 803}, + {0x53ec, 796}, + {0x53ed, 810}, + {0x53ee, 797}, + {0x53ef, 793}, + {0x53f0, 808}, + {0x53f1, 807}, + {0x53f2, 806}, + {0x53f3, 795}, + {0x53f5, 802}, + {0x53f8, 801}, + {0x53fb, 811}, + {0x53fc, 800}, + {0x5401, 928}, + {0x5403, 934}, + {0x5404, 930}, + {0x5406, 936}, + {0x5407, 6094}, + {0x5408, 933}, + {0x5409, 923}, + {0x540a, 926}, + {0x540b, 929}, + {0x540c, 925}, + {0x540d, 932}, + {0x540e, 935}, + {0x540f, 924}, + {0x5410, 927}, + {0x5411, 931}, + {0x5412, 937}, + {0x5418, 6215}, + {0x5419, 6212}, + {0x541b, 1105}, + {0x541c, 6213}, + {0x541d, 1093}, + {0x541e, 1095}, + {0x541f, 1119}, + {0x5420, 1114}, + {0x5424, 6220}, + {0x5425, 6214}, + {0x5426, 1097}, + {0x5427, 1099}, + {0x5428, 6219}, + {0x5429, 1106}, + {0x542a, 6209}, + {0x542b, 1118}, + {0x542c, 1120}, + {0x542d, 1094}, + {0x542e, 1111}, + {0x5430, 6207}, + {0x5431, 1117}, + {0x5433, 1102}, + {0x5435, 1112}, + {0x5436, 1113}, + {0x5437, 6208}, + {0x5438, 1110}, + {0x5439, 1108}, + {0x543b, 1109}, + {0x543c, 1115}, + {0x543d, 6216}, + {0x543e, 1096}, + {0x5440, 1116}, + {0x5441, 6218}, + {0x5442, 1104}, + {0x5443, 1101}, + {0x5445, 6211}, + {0x5446, 1100}, + {0x5447, 6221}, + {0x5448, 1103}, + {0x544a, 1107}, + {0x544e, 1098}, + {0x544f, 6217}, + {0x5454, 6210}, + {0x5460, 6446}, + {0x5461, 6445}, + {0x5462, 1395}, + {0x5463, 6448}, + {0x5464, 6450}, + {0x5465, 6439}, + {0x5466, 6442}, + {0x5467, 6449}, + {0x5468, 1396}, + {0x546b, 6436}, + {0x546c, 6440}, + {0x546f, 6444}, + {0x5470, 6789}, + {0x5471, 1391}, + {0x5472, 6793}, + {0x5473, 1378}, + {0x5474, 6441}, + {0x5475, 1379}, + {0x5476, 1392}, + {0x5477, 1385}, + {0x5478, 1381}, + {0x547a, 6437}, + {0x547b, 1384}, + {0x547c, 1389}, + {0x547d, 1398}, + {0x547e, 6438}, + {0x547f, 6431}, + {0x5480, 1383}, + {0x5481, 6432}, + {0x5482, 6434}, + {0x5484, 1386}, + {0x5486, 1388}, + {0x5487, 6430}, + {0x5488, 6435}, + {0x548b, 1397}, + {0x548c, 1393}, + {0x548d, 6443}, + {0x548e, 1399}, + {0x5490, 1390}, + {0x5491, 6433}, + {0x5492, 1387}, + {0x5495, 1382}, + {0x5496, 1380}, + {0x5498, 6447}, + {0x549a, 1394}, + {0x54a0, 6788}, + {0x54a1, 6776}, + {0x54a2, 6791}, + {0x54a5, 6778}, + {0x54a6, 1750}, + {0x54a7, 1764}, + {0x54a8, 1746}, + {0x54a9, 1763}, + {0x54aa, 1755}, + {0x54ab, 1760}, + {0x54ac, 1744}, + {0x54ad, 6777}, + {0x54ae, 6783}, + {0x54af, 1759}, + {0x54b0, 6795}, + {0x54b1, 1761}, + {0x54b3, 1751}, + {0x54b6, 6785}, + {0x54b7, 6782}, + {0x54b8, 1749}, + {0x54ba, 6775}, + {0x54bb, 1762}, + {0x54bc, 6790}, + {0x54bd, 1754}, + {0x54be, 6792}, + {0x54bf, 1765}, + {0x54c0, 1745}, + {0x54c1, 1756}, + {0x54c2, 1753}, + {0x54c3, 6780}, + {0x54c4, 1757}, + {0x54c5, 6786}, + {0x54c6, 6787}, + {0x54c7, 1752}, + {0x54c8, 1758}, + {0x54c9, 1748}, + {0x54ce, 1747}, + {0x54cf, 6779}, + {0x54d6, 6784}, + {0x54de, 6794}, + {0x54e0, 7255}, + {0x54e1, 2160}, + {0x54e2, 7237}, + {0x54e4, 7242}, + {0x54e5, 2153}, + {0x54e6, 2164}, + {0x54e7, 7240}, + {0x54e8, 2148}, + {0x54e9, 2158}, + {0x54ea, 2163}, + {0x54eb, 7247}, + {0x54ed, 2159}, + {0x54ee, 2162}, + {0x54f1, 7250}, + {0x54f2, 2154}, + {0x54f3, 7241}, + {0x54f7, 7253}, + {0x54f8, 7254}, + {0x54fa, 2156}, + {0x54fb, 7252}, + {0x54fc, 2152}, + {0x54fd, 2167}, + {0x54ff, 7244}, + {0x5501, 2150}, + {0x5503, 7257}, + {0x5504, 7245}, + {0x5505, 7249}, + {0x5506, 2155}, + {0x5507, 2166}, + {0x5508, 7246}, + {0x5509, 2161}, + {0x550a, 7251}, + {0x550b, 7258}, + {0x550c, 7785}, + {0x550e, 7256}, + {0x550f, 2168}, + {0x5510, 2149}, + {0x5511, 7248}, + {0x5512, 7239}, + {0x5514, 2157}, + {0x5517, 7238}, + {0x551a, 7243}, + {0x5526, 7236}, + {0x5527, 2165}, + {0x552a, 7777}, + {0x552c, 2609}, + {0x552d, 7791}, + {0x552e, 2607}, + {0x552f, 2604}, + {0x5530, 7782}, + {0x5531, 2600}, + {0x5532, 7786}, + {0x5533, 2611}, + {0x5534, 7776}, + {0x5535, 7781}, + {0x5536, 7780}, + {0x5537, 2151}, + {0x5538, 2606}, + {0x5539, 7789}, + {0x553b, 7792}, + {0x553c, 7773}, + {0x553e, 3084}, + {0x5540, 7793}, + {0x5541, 2612}, + {0x5543, 2598}, + {0x5544, 2595}, + {0x5545, 7784}, + {0x5546, 2592}, + {0x5548, 7790}, + {0x554a, 2599}, + {0x554b, 7794}, + {0x554d, 7774}, + {0x554e, 7788}, + {0x554f, 2602}, + {0x5550, 7775}, + {0x5551, 7778}, + {0x5552, 7783}, + {0x5555, 2603}, + {0x5556, 2601}, + {0x5557, 2613}, + {0x555c, 2608}, + {0x555e, 2596}, + {0x555f, 2748}, + {0x5561, 2597}, + {0x5562, 7779}, + {0x5563, 2610}, + {0x5564, 2605}, + {0x5565, 7787}, + {0x5566, 2594}, + {0x556a, 2593}, + {0x5575, 7771}, + {0x5576, 7772}, + {0x5577, 8391}, + {0x557b, 3067}, + {0x557c, 3070}, + {0x557d, 8402}, + {0x557e, 3090}, + {0x557f, 8405}, + {0x5580, 3068}, + {0x5581, 8398}, + {0x5582, 3074}, + {0x5583, 3080}, + {0x5584, 3355}, + {0x5587, 3078}, + {0x5588, 8395}, + {0x5589, 3091}, + {0x558a, 3071}, + {0x558b, 3079}, + {0x558c, 8403}, + {0x558d, 9095}, + {0x558e, 8408}, + {0x558f, 8396}, + {0x5591, 8387}, + {0x5592, 8400}, + {0x5593, 8394}, + {0x5594, 3077}, + {0x5595, 8406}, + {0x5598, 3073}, + {0x5599, 3093}, + {0x559a, 3086}, + {0x559c, 3075}, + {0x559d, 3072}, + {0x559f, 3083}, + {0x55a1, 8407}, + {0x55a2, 8393}, + {0x55a3, 8399}, + {0x55a4, 8401}, + {0x55a5, 8389}, + {0x55a6, 8404}, + {0x55a7, 3069}, + {0x55a8, 8388}, + {0x55aa, 3076}, + {0x55ab, 3092}, + {0x55ac, 3088}, + {0x55ad, 8390}, + {0x55ae, 3082}, + {0x55b1, 3089}, + {0x55b2, 3085}, + {0x55b3, 3081}, + {0x55b5, 8397}, + {0x55bb, 3087}, + {0x55bf, 9093}, + {0x55c0, 9089}, + {0x55c2, 9104}, + {0x55c3, 9082}, + {0x55c4, 9091}, + {0x55c5, 3552}, + {0x55c6, 3553}, + {0x55c7, 3545}, + {0x55c8, 9100}, + {0x55c9, 3555}, + {0x55ca, 9087}, + {0x55cb, 9086}, + {0x55cc, 9084}, + {0x55cd, 9102}, + {0x55ce, 3543}, + {0x55cf, 9096}, + {0x55d0, 9085}, + {0x55d1, 3546}, + {0x55d2, 9094}, + {0x55d3, 3541}, + {0x55d4, 9090}, + {0x55d5, 9097}, + {0x55d6, 9099}, + {0x55d9, 9103}, + {0x55da, 3550}, + {0x55db, 9083}, + {0x55dc, 3544}, + {0x55dd, 9088}, + {0x55df, 3539}, + {0x55e1, 3551}, + {0x55e2, 9098}, + {0x55e3, 3547}, + {0x55e4, 3548}, + {0x55e5, 3554}, + {0x55e6, 3542}, + {0x55e7, 287}, + {0x55e8, 3540}, + {0x55e9, 9092}, + {0x55ef, 3549}, + {0x55f2, 9101}, + {0x55f6, 3999}, + {0x55f7, 3994}, + {0x55f9, 9783}, + {0x55fa, 9779}, + {0x55fc, 9773}, + {0x55fd, 3988}, + {0x55fe, 3984}, + {0x55ff, 9782}, + {0x5600, 3985}, + {0x5601, 9776}, + {0x5602, 9778}, + {0x5604, 9781}, + {0x5606, 3990}, + {0x5608, 3997}, + {0x5609, 3991}, + {0x560c, 9771}, + {0x560d, 3992}, + {0x560e, 3993}, + {0x560f, 9774}, + {0x5610, 3998}, + {0x5612, 9772}, + {0x5613, 9777}, + {0x5614, 3989}, + {0x5615, 9770}, + {0x5616, 3995}, + {0x5617, 3987}, + {0x561b, 3986}, + {0x561c, 9775}, + {0x561d, 9780}, + {0x561f, 3996}, + {0x5627, 9769}, + {0x5629, 4377}, + {0x562e, 4371}, + {0x562f, 4383}, + {0x5630, 4384}, + {0x5632, 4374}, + {0x5634, 4376}, + {0x5636, 4382}, + {0x5639, 4373}, + {0x563b, 4372}, + {0x563f, 4375}, + {0x5645, 8392}, + {0x564e, 4379}, + {0x5653, 4378}, + {0x5657, 4380}, + {0x5659, 4757}, + {0x5662, 4769}, + {0x5664, 4761}, + {0x5665, 4765}, + {0x5668, 4764}, + {0x5669, 4760}, + {0x566a, 4763}, + {0x566b, 4758}, + {0x566c, 4768}, + {0x566f, 4767}, + {0x5671, 4766}, + {0x5674, 4381}, + {0x5676, 4770}, + {0x5678, 4762}, + {0x5679, 4759}, + {0x5680, 5050}, + {0x5685, 5052}, + {0x5687, 5053}, + {0x568d, 0}, + {0x568e, 5049}, + {0x568f, 5054}, + {0x5690, 5051}, + {0x5695, 5322}, + {0x56a5, 5494}, + {0x56a7, 0}, + {0x56a8, 5495}, + {0x56ae, 5323}, + {0x56b4, 5644}, + {0x56b6, 5643}, + {0x56b7, 5642}, + {0x56bc, 5645}, + {0x56be, 0}, + {0x56c0, 5739}, + {0x56c1, 5738}, + {0x56c2, 5740}, + {0x56c8, 5821}, + {0x56c9, 5823}, + {0x56ca, 5822}, + {0x56cc, 5878}, + {0x56d1, 5919}, + {0x56d7, 6005}, + {0x56da, 813}, + {0x56db, 812}, + {0x56dd, 940}, + {0x56de, 939}, + {0x56df, 6096}, + {0x56e0, 938}, + {0x56e1, 6095}, + {0x56e4, 1123}, + {0x56e5, 6224}, + {0x56e7, 6223}, + {0x56ea, 1121}, + {0x56eb, 1124}, + {0x56ee, 6222}, + {0x56f0, 1122}, + {0x56f7, 6451}, + {0x56f9, 6452}, + {0x56fa, 1400}, + {0x56ff, 1766}, + {0x5701, 7259}, + {0x5702, 7260}, + {0x5703, 2169}, + {0x5704, 2170}, + {0x5707, 7796}, + {0x5708, 2614}, + {0x5709, 2616}, + {0x570a, 7795}, + {0x570b, 2615}, + {0x570c, 8409}, + {0x570d, 3094}, + {0x5712, 3556}, + {0x5713, 3557}, + {0x5714, 9105}, + {0x5716, 4001}, + {0x5718, 4000}, + {0x571f, 634}, + {0x5720, 6020}, + {0x5722, 6042}, + {0x5723, 6043}, + {0x5728, 943}, + {0x5729, 947}, + {0x572a, 6098}, + {0x572c, 945}, + {0x572d, 944}, + {0x572e, 6097}, + {0x572f, 946}, + {0x5730, 942}, + {0x5733, 941}, + {0x5734, 6099}, + {0x573b, 1134}, + {0x573e, 1131}, + {0x5740, 1127}, + {0x5741, 6225}, + {0x5745, 6226}, + {0x5747, 1129}, + {0x5749, 6228}, + {0x574a, 1125}, + {0x574b, 6229}, + {0x574c, 6227}, + {0x574d, 1128}, + {0x574e, 1130}, + {0x574f, 1133}, + {0x5750, 1132}, + {0x5751, 1126}, + {0x5752, 6230}, + {0x5761, 1405}, + {0x5762, 6465}, + {0x5764, 1407}, + {0x5766, 1406}, + {0x5768, 6466}, + {0x5769, 1404}, + {0x576a, 1403}, + {0x576b, 6456}, + {0x576d, 6455}, + {0x576f, 6453}, + {0x5770, 6458}, + {0x5771, 6457}, + {0x5772, 6454}, + {0x5773, 6463}, + {0x5774, 6464}, + {0x5775, 6461}, + {0x5776, 6459}, + {0x5777, 1402}, + {0x577b, 6462}, + {0x577c, 1408}, + {0x577d, 6467}, + {0x5780, 6460}, + {0x5782, 1767}, + {0x5783, 1401}, + {0x578b, 1768}, + {0x578c, 6800}, + {0x578f, 6806}, + {0x5793, 1774}, + {0x5794, 6804}, + {0x5795, 6810}, + {0x5797, 6801}, + {0x5798, 6805}, + {0x5799, 6807}, + {0x579a, 6809}, + {0x579b, 6803}, + {0x579d, 6802}, + {0x579e, 6797}, + {0x579f, 6798}, + {0x57a0, 1769}, + {0x57a2, 1771}, + {0x57a3, 1770}, + {0x57a4, 6799}, + {0x57a5, 6808}, + {0x57ae, 1773}, + {0x57b5, 6796}, + {0x57b6, 7270}, + {0x57b8, 7269}, + {0x57b9, 7274}, + {0x57ba, 7265}, + {0x57bc, 7268}, + {0x57bd, 7267}, + {0x57bf, 7271}, + {0x57c1, 7275}, + {0x57c2, 2171}, + {0x57c3, 2174}, + {0x57c6, 7266}, + {0x57c7, 7272}, + {0x57cb, 2173}, + {0x57cc, 7261}, + {0x57ce, 1772}, + {0x57cf, 7810}, + {0x57d0, 7273}, + {0x57d2, 7264}, + {0x57d4, 2172}, + {0x57d5, 7263}, + {0x57dc, 7801}, + {0x57df, 2617}, + {0x57e0, 2621}, + {0x57e1, 7817}, + {0x57e2, 7799}, + {0x57e3, 7813}, + {0x57e4, 2622}, + {0x57e5, 7815}, + {0x57e7, 7821}, + {0x57e9, 7825}, + {0x57ec, 7816}, + {0x57ed, 7804}, + {0x57ee, 7812}, + {0x57f0, 7826}, + {0x57f1, 7824}, + {0x57f2, 7814}, + {0x57f3, 7809}, + {0x57f4, 7802}, + {0x57f5, 8417}, + {0x57f6, 7800}, + {0x57f7, 2626}, + {0x57f8, 7807}, + {0x57f9, 2627}, + {0x57fa, 2623}, + {0x57fb, 7797}, + {0x57fc, 7819}, + {0x57fd, 7805}, + {0x5800, 7803}, + {0x5801, 7822}, + {0x5802, 2624}, + {0x5804, 7828}, + {0x5805, 2618}, + {0x5806, 2620}, + {0x5807, 7811}, + {0x5808, 7806}, + {0x5809, 2175}, + {0x580a, 2619}, + {0x580b, 7808}, + {0x580c, 7823}, + {0x580d, 7827}, + {0x580e, 7818}, + {0x5810, 7820}, + {0x5814, 7798}, + {0x5819, 8412}, + {0x581b, 8421}, + {0x581c, 8420}, + {0x581d, 3102}, + {0x581e, 8413}, + {0x5820, 3103}, + {0x5821, 3101}, + {0x5823, 8415}, + {0x5824, 3098}, + {0x5825, 8419}, + {0x5827, 8414}, + {0x5828, 8416}, + {0x5829, 8410}, + {0x582a, 3096}, + {0x582c, 8429}, + {0x582d, 8428}, + {0x582e, 8425}, + {0x582f, 3095}, + {0x5830, 3099}, + {0x5831, 3100}, + {0x5832, 7262}, + {0x5833, 8422}, + {0x5834, 3097}, + {0x5835, 2625}, + {0x5836, 8424}, + {0x5837, 8411}, + {0x5838, 8427}, + {0x5839, 8426}, + {0x583b, 8430}, + {0x583d, 9119}, + {0x583f, 8423}, + {0x5848, 8418}, + {0x5849, 9111}, + {0x584a, 3567}, + {0x584b, 3570}, + {0x584c, 3565}, + {0x584d, 9110}, + {0x584e, 9114}, + {0x584f, 9109}, + {0x5851, 3559}, + {0x5852, 3569}, + {0x5853, 9106}, + {0x5854, 3563}, + {0x5855, 9113}, + {0x5857, 3561}, + {0x5858, 3560}, + {0x5859, 9116}, + {0x585a, 3562}, + {0x585b, 9118}, + {0x585d, 9115}, + {0x585e, 3558}, + {0x5862, 3568}, + {0x5863, 9120}, + {0x5864, 9108}, + {0x5865, 9117}, + {0x5868, 9107}, + {0x586b, 3564}, + {0x586d, 3566}, + {0x586f, 9112}, + {0x5871, 9121}, + {0x5874, 9791}, + {0x5875, 4002}, + {0x5876, 9797}, + {0x5879, 4007}, + {0x587a, 9793}, + {0x587b, 9800}, + {0x587c, 9785}, + {0x587d, 4009}, + {0x587e, 4003}, + {0x587f, 9790}, + {0x5880, 4385}, + {0x5881, 9789}, + {0x5882, 9798}, + {0x5883, 4004}, + {0x5885, 4008}, + {0x5886, 9788}, + {0x5887, 9794}, + {0x5888, 9799}, + {0x5889, 9784}, + {0x588a, 4006}, + {0x588b, 9792}, + {0x588e, 9796}, + {0x588f, 9802}, + {0x5890, 9786}, + {0x5891, 9795}, + {0x5893, 4005}, + {0x5894, 9801}, + {0x5898, 9787}, + {0x589c, 4389}, + {0x589e, 4387}, + {0x589f, 4386}, + {0x58a6, 4392}, + {0x58a8, 4744}, + {0x58a9, 4391}, + {0x58ae, 4390}, + {0x58b3, 4388}, + {0x58be, 4772}, + {0x58c1, 4771}, + {0x58c5, 4774}, + {0x58c7, 4773}, + {0x58ce, 5058}, + {0x58d1, 5057}, + {0x58d3, 5056}, + {0x58d5, 5055}, + {0x58d8, 5325}, + {0x58d9, 5324}, + {0x58de, 5496}, + {0x58df, 5497}, + {0x58e2, 5498}, + {0x58e4, 5646}, + {0x58e9, 5920}, + {0x58eb, 635}, + {0x58ec, 705}, + {0x58ef, 1135}, + {0x58f4, 6811}, + {0x58f9, 3104}, + {0x58fa, 3105}, + {0x58fc, 9122}, + {0x58fd, 4010}, + {0x58fe, 9803}, + {0x5902, 548}, + {0x5903, 6021}, + {0x5906, 6231}, + {0x590a, 548}, + {0x590c, 6468}, + {0x590d, 6812}, + {0x590e, 7276}, + {0x590f, 2176}, + {0x5914, 5741}, + {0x5915, 636}, + {0x5916, 814}, + {0x5917, 6044}, + {0x5919, 948}, + {0x591a, 949}, + {0x591c, 1409}, + {0x5920, 2628}, + {0x5922, 4012}, + {0x5924, 4013}, + {0x5925, 4011}, + {0x5927, 637}, + {0x5929, 706}, + {0x592a, 708}, + {0x592b, 707}, + {0x592c, 6022}, + {0x592d, 709}, + {0x592e, 815}, + {0x592f, 6045}, + {0x5931, 816}, + {0x5937, 950}, + {0x5938, 951}, + {0x593c, 6100}, + {0x593e, 1136}, + {0x5940, 6232}, + {0x5944, 1413}, + {0x5945, 6469}, + {0x5947, 1411}, + {0x5948, 1412}, + {0x5949, 1410}, + {0x594a, 7277}, + {0x594e, 1778}, + {0x594f, 1777}, + {0x5950, 1779}, + {0x5951, 1776}, + {0x5953, 6813}, + {0x5954, 1414}, + {0x5955, 1775}, + {0x5957, 2177}, + {0x5958, 2178}, + {0x595a, 2179}, + {0x595c, 7829}, + {0x5960, 3106}, + {0x5961, 8431}, + {0x5962, 2629}, + {0x5967, 3571}, + {0x5969, 4015}, + {0x596a, 4014}, + {0x596b, 9804}, + {0x596d, 4393}, + {0x596e, 4775}, + {0x5973, 638}, + {0x5974, 817}, + {0x5976, 818}, + {0x5977, 6106}, + {0x5978, 953}, + {0x5979, 956}, + {0x597b, 6104}, + {0x597c, 6102}, + {0x597d, 955}, + {0x597e, 6105}, + {0x597f, 6107}, + {0x5980, 6101}, + {0x5981, 958}, + {0x5982, 957}, + {0x5983, 954}, + {0x5984, 952}, + {0x5985, 6103}, + {0x598a, 1147}, + {0x598d, 1144}, + {0x598e, 6237}, + {0x598f, 6240}, + {0x5990, 6239}, + {0x5992, 1138}, + {0x5993, 1146}, + {0x5996, 1143}, + {0x5997, 6236}, + {0x5998, 6234}, + {0x5999, 1142}, + {0x599d, 1137}, + {0x599e, 1140}, + {0x59a0, 6235}, + {0x59a1, 6242}, + {0x59a2, 6238}, + {0x59a3, 1141}, + {0x59a4, 1145}, + {0x59a5, 1148}, + {0x59a6, 6233}, + {0x59a7, 6241}, + {0x59a8, 1139}, + {0x59ae, 1419}, + {0x59af, 1427}, + {0x59b1, 6481}, + {0x59b2, 6474}, + {0x59b3, 1428}, + {0x59b4, 6485}, + {0x59b5, 6470}, + {0x59b6, 6477}, + {0x59b9, 1418}, + {0x59ba, 6471}, + {0x59bb, 1416}, + {0x59bc, 6478}, + {0x59bd, 6482}, + {0x59be, 1415}, + {0x59c0, 6483}, + {0x59c1, 6476}, + {0x59c3, 6479}, + {0x59c5, 1430}, + {0x59c6, 1421}, + {0x59c7, 6486}, + {0x59c8, 6484}, + {0x59ca, 1426}, + {0x59cb, 1424}, + {0x59cc, 6475}, + {0x59cd, 1423}, + {0x59ce, 6473}, + {0x59cf, 6472}, + {0x59d0, 1422}, + {0x59d1, 1420}, + {0x59d2, 1429}, + {0x59d3, 1425}, + {0x59d4, 1417}, + {0x59d6, 6480}, + {0x59d8, 1781}, + {0x59da, 1788}, + {0x59db, 6827}, + {0x59dc, 1780}, + {0x59dd, 6819}, + {0x59de, 6815}, + {0x59e0, 6831}, + {0x59e1, 6814}, + {0x59e3, 1783}, + {0x59e4, 6824}, + {0x59e5, 1786}, + {0x59e6, 1789}, + {0x59e8, 1784}, + {0x59e9, 6828}, + {0x59ea, 1787}, + {0x59ec, 2186}, + {0x59ed, 6834}, + {0x59ee, 6816}, + {0x59f1, 6818}, + {0x59f2, 6825}, + {0x59f3, 6829}, + {0x59f4, 6833}, + {0x59f5, 6830}, + {0x59f6, 6823}, + {0x59f7, 6826}, + {0x59fa, 6820}, + {0x59fb, 1791}, + {0x59fc, 6822}, + {0x59fd, 6821}, + {0x59fe, 6832}, + {0x59ff, 1782}, + {0x5a00, 6817}, + {0x5a01, 1790}, + {0x5a03, 1785}, + {0x5a09, 2192}, + {0x5a0a, 7285}, + {0x5a0c, 2191}, + {0x5a0f, 7283}, + {0x5a11, 2180}, + {0x5a13, 2185}, + {0x5a15, 7282}, + {0x5a16, 7279}, + {0x5a17, 7284}, + {0x5a18, 2181}, + {0x5a19, 7278}, + {0x5a1b, 2184}, + {0x5a1c, 2182}, + {0x5a1e, 7286}, + {0x5a1f, 2183}, + {0x5a20, 2187}, + {0x5a23, 2188}, + {0x5a25, 2190}, + {0x5a29, 2189}, + {0x5a2d, 7280}, + {0x5a2e, 7281}, + {0x5a33, 7287}, + {0x5a35, 7836}, + {0x5a36, 2630}, + {0x5a37, 8445}, + {0x5a38, 7835}, + {0x5a39, 7854}, + {0x5a3c, 2636}, + {0x5a3e, 7852}, + {0x5a40, 2635}, + {0x5a41, 2631}, + {0x5a42, 7861}, + {0x5a43, 7845}, + {0x5a44, 7848}, + {0x5a46, 2639}, + {0x5a47, 7858}, + {0x5a48, 7850}, + {0x5a49, 2632}, + {0x5a4a, 2640}, + {0x5a4c, 7855}, + {0x5a4d, 7853}, + {0x5a50, 7838}, + {0x5a51, 7859}, + {0x5a52, 7847}, + {0x5a53, 7842}, + {0x5a55, 7832}, + {0x5a56, 7860}, + {0x5a57, 7844}, + {0x5a58, 7831}, + {0x5a5a, 2638}, + {0x5a5b, 7849}, + {0x5a5c, 7862}, + {0x5a5d, 7846}, + {0x5a5e, 7834}, + {0x5a5f, 7839}, + {0x5a60, 7830}, + {0x5a62, 2637}, + {0x5a64, 7843}, + {0x5a65, 7840}, + {0x5a66, 2633}, + {0x5a67, 7833}, + {0x5a69, 7857}, + {0x5a6a, 2634}, + {0x5a6c, 7841}, + {0x5a6d, 7837}, + {0x5a70, 7856}, + {0x5a77, 3107}, + {0x5a78, 8438}, + {0x5a7a, 8435}, + {0x5a7b, 8452}, + {0x5a7c, 8440}, + {0x5a7d, 8453}, + {0x5a7f, 3109}, + {0x5a83, 8449}, + {0x5a84, 8446}, + {0x5a8a, 8447}, + {0x5a8b, 8450}, + {0x5a8c, 8454}, + {0x5a8e, 7851}, + {0x5a8f, 8456}, + {0x5a90, 9142}, + {0x5a92, 3110}, + {0x5a93, 8457}, + {0x5a94, 8433}, + {0x5a95, 8443}, + {0x5a97, 8448}, + {0x5a9a, 3108}, + {0x5a9b, 3111}, + {0x5a9c, 8455}, + {0x5a9d, 8458}, + {0x5a9e, 8437}, + {0x5a9f, 8434}, + {0x5aa2, 8436}, + {0x5aa5, 8441}, + {0x5aa6, 8439}, + {0x5aa7, 3112}, + {0x5aa9, 8451}, + {0x5aac, 8442}, + {0x5aae, 8444}, + {0x5aaf, 8432}, + {0x5ab0, 9130}, + {0x5ab1, 9128}, + {0x5ab2, 3580}, + {0x5ab3, 3578}, + {0x5ab4, 9138}, + {0x5ab5, 9129}, + {0x5ab6, 9139}, + {0x5ab7, 9135}, + {0x5ab8, 9127}, + {0x5ab9, 9141}, + {0x5aba, 9126}, + {0x5abb, 9133}, + {0x5abc, 3577}, + {0x5abd, 3576}, + {0x5abe, 3575}, + {0x5abf, 9131}, + {0x5ac0, 9136}, + {0x5ac1, 3572}, + {0x5ac2, 3579}, + {0x5ac4, 9124}, + {0x5ac6, 9134}, + {0x5ac7, 9123}, + {0x5ac8, 9132}, + {0x5ac9, 3573}, + {0x5aca, 9137}, + {0x5acb, 9125}, + {0x5acc, 3574}, + {0x5acd, 9140}, + {0x5ad5, 9808}, + {0x5ad6, 4020}, + {0x5ad7, 4019}, + {0x5ad8, 4021}, + {0x5ad9, 9820}, + {0x5ada, 9810}, + {0x5adb, 9816}, + {0x5adc, 9805}, + {0x5add, 9819}, + {0x5ade, 9818}, + {0x5adf, 9822}, + {0x5ae0, 9815}, + {0x5ae1, 4016}, + {0x5ae2, 9814}, + {0x5ae3, 4022}, + {0x5ae5, 9807}, + {0x5ae6, 4017}, + {0x5ae8, 9821}, + {0x5ae9, 4018}, + {0x5aea, 9809}, + {0x5aeb, 9812}, + {0x5aec, 9817}, + {0x5aed, 9811}, + {0x5aee, 9806}, + {0x5af3, 9813}, + {0x5af5, 4397}, + {0x5afb, 4395}, + {0x5b08, 4399}, + {0x5b09, 4394}, + {0x5b0b, 4396}, + {0x5b0c, 4398}, + {0x5b1d, 4776}, + {0x5b24, 5061}, + {0x5b2a, 5060}, + {0x5b30, 5059}, + {0x5b34, 4777}, + {0x5b38, 5326}, + {0x5b3e, 0}, + {0x5b3f, 1}, + {0x5b40, 5647}, + {0x5b43, 5648}, + {0x5b4c, 0}, + {0x5b50, 639}, + {0x5b51, 640}, + {0x5b53, 641}, + {0x5b54, 710}, + {0x5b55, 819}, + {0x5b56, 6108}, + {0x5b57, 959}, + {0x5b58, 960}, + {0x5b5a, 1151}, + {0x5b5b, 1152}, + {0x5b5c, 1150}, + {0x5b5d, 1149}, + {0x5b5f, 1431}, + {0x5b62, 6487}, + {0x5b63, 1433}, + {0x5b64, 1432}, + {0x5b65, 6488}, + {0x5b69, 1792}, + {0x5b6b, 2193}, + {0x5b6c, 7288}, + {0x5b6e, 7864}, + {0x5b70, 2641}, + {0x5b71, 3114}, + {0x5b72, 7863}, + {0x5b73, 3113}, + {0x5b75, 4023}, + {0x5b77, 9823}, + {0x5b78, 4778}, + {0x5b7a, 5062}, + {0x5b7d, 5649}, + {0x5b7f, 5824}, + {0x5b80, 549}, + {0x5b81, 6046}, + {0x5b83, 820}, + {0x5b84, 6047}, + {0x5b85, 963}, + {0x5b87, 961}, + {0x5b88, 962}, + {0x5b89, 964}, + {0x5b8b, 1154}, + {0x5b8c, 1153}, + {0x5b8e, 6243}, + {0x5b8f, 1155}, + {0x5b92, 6244}, + {0x5b93, 6489}, + {0x5b95, 6490}, + {0x5b97, 1434}, + {0x5b98, 1436}, + {0x5b99, 1438}, + {0x5b9a, 1435}, + {0x5b9b, 1439}, + {0x5b9c, 1437}, + {0x5b9f, 0}, + {0x5ba2, 1796}, + {0x5ba3, 1793}, + {0x5ba4, 1795}, + {0x5ba5, 1797}, + {0x5ba6, 1794}, + {0x5ba7, 7289}, + {0x5ba8, 6835}, + {0x5bac, 7291}, + {0x5bad, 7290}, + {0x5bae, 2199}, + {0x5bb0, 2195}, + {0x5bb3, 2196}, + {0x5bb4, 2198}, + {0x5bb5, 2200}, + {0x5bb6, 2197}, + {0x5bb8, 2202}, + {0x5bb9, 2201}, + {0x5bbf, 2646}, + {0x5bc0, 7866}, + {0x5bc1, 7865}, + {0x5bc2, 2645}, + {0x5bc4, 2644}, + {0x5bc5, 2643}, + {0x5bc6, 2647}, + {0x5bc7, 2642}, + {0x5bca, 8464}, + {0x5bcb, 8461}, + {0x5bcc, 3116}, + {0x5bcd, 8460}, + {0x5bce, 8465}, + {0x5bd0, 3118}, + {0x5bd1, 8463}, + {0x5bd2, 3115}, + {0x5bd3, 3117}, + {0x5bd4, 8462}, + {0x5bd6, 9143}, + {0x5bd8, 9144}, + {0x5bd9, 9145}, + {0x5bde, 4024}, + {0x5bdf, 4032}, + {0x5be0, 9824}, + {0x5be1, 4026}, + {0x5be2, 4030}, + {0x5be3, 9825}, + {0x5be4, 4031}, + {0x5be5, 4027}, + {0x5be6, 4028}, + {0x5be7, 4025}, + {0x5be8, 4029}, + {0x5be9, 4402}, + {0x5bea, 8459}, + {0x5beb, 4403}, + {0x5bec, 4401}, + {0x5bee, 4400}, + {0x5bf0, 4779}, + {0x5bf2, 0}, + {0x5bf5, 5499}, + {0x5bf6, 5650}, + {0x5bf8, 642}, + {0x5bfa, 965}, + {0x5c01, 1798}, + {0x5c03, 7292}, + {0x5c04, 2203}, + {0x5c07, 2650}, + {0x5c08, 2649}, + {0x5c09, 2648}, + {0x5c0a, 3119}, + {0x5c0b, 3120}, + {0x5c0c, 8466}, + {0x5c0d, 4033}, + {0x5c0e, 4780}, + {0x5c0f, 643}, + {0x5c10, 6023}, + {0x5c11, 711}, + {0x5c12, 6048}, + {0x5c15, 6109}, + {0x5c16, 966}, + {0x5c1a, 1440}, + {0x5c1f, 9146}, + {0x5c22, 644}, + {0x5c24, 712}, + {0x5c25, 6110}, + {0x5c28, 6245}, + {0x5c2a, 6246}, + {0x5c2c, 1156}, + {0x5c30, 8467}, + {0x5c31, 3121}, + {0x5c33, 9147}, + {0x5c37, 5063}, + {0x5c38, 645}, + {0x5c39, 665}, + {0x5c3a, 713}, + {0x5c3b, 6049}, + {0x5c3c, 821}, + {0x5c3e, 1160}, + {0x5c3f, 1159}, + {0x5c40, 1157}, + {0x5c41, 1158}, + {0x5c44, 6491}, + {0x5c45, 1442}, + {0x5c46, 1443}, + {0x5c47, 6492}, + {0x5c48, 1441}, + {0x5c4b, 1802}, + {0x5c4c, 6836}, + {0x5c4d, 1801}, + {0x5c4e, 1799}, + {0x5c4f, 1800}, + {0x5c50, 2206}, + {0x5c51, 2204}, + {0x5c54, 7294}, + {0x5c55, 2205}, + {0x5c56, 7293}, + {0x5c58, 2194}, + {0x5c59, 7867}, + {0x5c5c, 2652}, + {0x5c5d, 2653}, + {0x5c60, 2651}, + {0x5c62, 4034}, + {0x5c63, 9826}, + {0x5c64, 4404}, + {0x5c65, 4405}, + {0x5c68, 5064}, + {0x5c6a, 0}, + {0x5c6c, 5742}, + {0x5c6e, 6006}, + {0x5c6f, 714}, + {0x5c71, 646}, + {0x5c73, 6051}, + {0x5c74, 6050}, + {0x5c79, 967}, + {0x5c7a, 6112}, + {0x5c7b, 6113}, + {0x5c7c, 6111}, + {0x5c7e, 6114}, + {0x5c86, 6254}, + {0x5c88, 6249}, + {0x5c89, 6251}, + {0x5c8a, 6253}, + {0x5c8b, 6250}, + {0x5c8c, 1164}, + {0x5c8d, 6247}, + {0x5c8f, 6248}, + {0x5c90, 1161}, + {0x5c91, 1162}, + {0x5c92, 6252}, + {0x5c93, 6255}, + {0x5c94, 1163}, + {0x5c95, 6256}, + {0x5c9d, 6506}, + {0x5c9f, 6500}, + {0x5ca0, 6495}, + {0x5ca1, 1445}, + {0x5ca2, 6503}, + {0x5ca3, 6501}, + {0x5ca4, 6494}, + {0x5ca5, 6507}, + {0x5ca6, 6510}, + {0x5ca7, 6505}, + {0x5ca8, 6498}, + {0x5ca9, 1447}, + {0x5caa, 6504}, + {0x5cab, 1448}, + {0x5cac, 6499}, + {0x5cad, 6502}, + {0x5cae, 6493}, + {0x5caf, 6497}, + {0x5cb0, 6509}, + {0x5cb1, 1449}, + {0x5cb3, 1450}, + {0x5cb5, 6496}, + {0x5cb6, 6508}, + {0x5cb7, 1444}, + {0x5cb8, 1446}, + {0x5cc6, 6853}, + {0x5cc7, 6846}, + {0x5cc8, 6852}, + {0x5cc9, 6845}, + {0x5cca, 6847}, + {0x5ccb, 6841}, + {0x5ccc, 6839}, + {0x5cce, 6854}, + {0x5ccf, 6851}, + {0x5cd0, 6837}, + {0x5cd2, 1804}, + {0x5cd3, 6849}, + {0x5cd4, 6850}, + {0x5cd6, 6848}, + {0x5cd7, 6840}, + {0x5cd8, 6838}, + {0x5cd9, 1803}, + {0x5cda, 6844}, + {0x5cdb, 6842}, + {0x5cde, 6843}, + {0x5cdf, 6855}, + {0x5ce8, 2211}, + {0x5cea, 2210}, + {0x5cec, 7295}, + {0x5ced, 2207}, + {0x5cee, 7297}, + {0x5cf0, 2212}, + {0x5cf1, 7298}, + {0x5cf4, 2215}, + {0x5cf6, 2213}, + {0x5cf7, 7299}, + {0x5cf8, 6856}, + {0x5cf9, 7301}, + {0x5cfb, 2209}, + {0x5cfd, 2208}, + {0x5cff, 7296}, + {0x5d00, 7300}, + {0x5d01, 2214}, + {0x5d06, 2655}, + {0x5d07, 2654}, + {0x5d0b, 7869}, + {0x5d0c, 7873}, + {0x5d0d, 7875}, + {0x5d0e, 2656}, + {0x5d0f, 7878}, + {0x5d11, 2660}, + {0x5d12, 7880}, + {0x5d14, 2662}, + {0x5d16, 2658}, + {0x5d17, 2666}, + {0x5d19, 2663}, + {0x5d1a, 7871}, + {0x5d1b, 2657}, + {0x5d1d, 7870}, + {0x5d1e, 7868}, + {0x5d1f, 7882}, + {0x5d20, 7872}, + {0x5d22, 2659}, + {0x5d23, 7881}, + {0x5d24, 2664}, + {0x5d25, 7877}, + {0x5d26, 7876}, + {0x5d27, 2665}, + {0x5d28, 7874}, + {0x5d29, 2661}, + {0x5d2e, 7883}, + {0x5d30, 7879}, + {0x5d31, 8482}, + {0x5d32, 8489}, + {0x5d33, 8478}, + {0x5d34, 3124}, + {0x5d35, 8474}, + {0x5d36, 8490}, + {0x5d37, 8468}, + {0x5d38, 8487}, + {0x5d39, 8485}, + {0x5d3a, 8479}, + {0x5d3c, 8488}, + {0x5d3d, 8481}, + {0x5d3f, 8473}, + {0x5d40, 8491}, + {0x5d41, 8471}, + {0x5d42, 8484}, + {0x5d43, 8469}, + {0x5d45, 8492}, + {0x5d47, 3125}, + {0x5d49, 8486}, + {0x5d4a, 9150}, + {0x5d4b, 8472}, + {0x5d4c, 3122}, + {0x5d4e, 8476}, + {0x5d50, 3123}, + {0x5d51, 8475}, + {0x5d52, 8480}, + {0x5d55, 8477}, + {0x5d59, 8483}, + {0x5d5e, 9154}, + {0x5d62, 9157}, + {0x5d63, 9149}, + {0x5d65, 9151}, + {0x5d67, 9156}, + {0x5d68, 9155}, + {0x5d69, 3581}, + {0x5d6b, 8470}, + {0x5d6c, 9153}, + {0x5d6f, 3582}, + {0x5d71, 9148}, + {0x5d72, 9152}, + {0x5d77, 9833}, + {0x5d79, 9840}, + {0x5d7a, 9831}, + {0x5d7c, 9838}, + {0x5d7d, 9829}, + {0x5d7e, 9837}, + {0x5d7f, 9841}, + {0x5d80, 9828}, + {0x5d81, 9832}, + {0x5d82, 9827}, + {0x5d84, 4035}, + {0x5d86, 9830}, + {0x5d87, 4036}, + {0x5d88, 9836}, + {0x5d89, 9835}, + {0x5d8a, 9834}, + {0x5d8d, 9839}, + {0x5d94, 4407}, + {0x5d9d, 4406}, + {0x5db8, 5068}, + {0x5dba, 5066}, + {0x5dbc, 5065}, + {0x5dbd, 5067}, + {0x5dc7, 0}, + {0x5dc9, 5651}, + {0x5dcd, 5743}, + {0x5dd2, 5826}, + {0x5dd4, 5825}, + {0x5dd6, 5879}, + {0x5ddb, 550}, + {0x5ddd, 647}, + {0x5dde, 968}, + {0x5ddf, 6115}, + {0x5de0, 6257}, + {0x5de1, 1306}, + {0x5de2, 2667}, + {0x5de5, 648}, + {0x5de6, 824}, + {0x5de7, 823}, + {0x5de8, 822}, + {0x5deb, 1165}, + {0x5dee, 2216}, + {0x5df0, 9158}, + {0x5df1, 649}, + {0x5df2, 650}, + {0x5df3, 651}, + {0x5df4, 715}, + {0x5df7, 1805}, + {0x5df9, 6857}, + {0x5dfd, 3126}, + {0x5dfe, 652}, + {0x5dff, 6024}, + {0x5e02, 825}, + {0x5e03, 826}, + {0x5e04, 6052}, + {0x5e06, 969}, + {0x5e0a, 6258}, + {0x5e0c, 1166}, + {0x5e0e, 6259}, + {0x5e11, 1456}, + {0x5e14, 6512}, + {0x5e15, 1454}, + {0x5e16, 1453}, + {0x5e17, 6511}, + {0x5e18, 1451}, + {0x5e19, 6513}, + {0x5e1a, 1452}, + {0x5e1b, 1455}, + {0x5e1d, 1806}, + {0x5e1f, 1808}, + {0x5e20, 6861}, + {0x5e21, 6858}, + {0x5e22, 6859}, + {0x5e23, 6860}, + {0x5e24, 6862}, + {0x5e25, 1807}, + {0x5e28, 7303}, + {0x5e29, 7302}, + {0x5e2b, 2218}, + {0x5e2d, 2217}, + {0x5e33, 2670}, + {0x5e34, 7885}, + {0x5e36, 2669}, + {0x5e37, 2671}, + {0x5e38, 2668}, + {0x5e3d, 3128}, + {0x5e3e, 7884}, + {0x5e40, 3129}, + {0x5e41, 8494}, + {0x5e43, 3130}, + {0x5e44, 8493}, + {0x5e45, 3127}, + {0x5e4a, 9161}, + {0x5e4b, 9163}, + {0x5e4c, 3583}, + {0x5e4d, 9162}, + {0x5e4e, 9160}, + {0x5e4f, 9159}, + {0x5e53, 9844}, + {0x5e54, 4041}, + {0x5e55, 4039}, + {0x5e57, 4040}, + {0x5e58, 9842}, + {0x5e59, 9843}, + {0x5e5b, 4037}, + {0x5e5f, 4409}, + {0x5e61, 4410}, + {0x5e62, 4408}, + {0x5e63, 4038}, + {0x5e68, 0}, + {0x5e6b, 5069}, + {0x5e6e, 0}, + {0x5e72, 653}, + {0x5e73, 827}, + {0x5e74, 971}, + {0x5e75, 6116}, + {0x5e76, 970}, + {0x5e78, 1457}, + {0x5e79, 3584}, + {0x5e7a, 551}, + {0x5e7b, 716}, + {0x5e7c, 828}, + {0x5e7d, 1809}, + {0x5e7e, 3131}, + {0x5e7f, 552}, + {0x5e80, 6053}, + {0x5e82, 6054}, + {0x5e84, 6117}, + {0x5e87, 1168}, + {0x5e88, 6263}, + {0x5e89, 6261}, + {0x5e8a, 1169}, + {0x5e8b, 6260}, + {0x5e8c, 6262}, + {0x5e8d, 6264}, + {0x5e8f, 1167}, + {0x5e95, 1461}, + {0x5e96, 1462}, + {0x5e97, 1459}, + {0x5e9a, 1458}, + {0x5e9b, 6866}, + {0x5e9c, 1460}, + {0x5ea0, 1810}, + {0x5ea2, 6865}, + {0x5ea3, 6867}, + {0x5ea4, 6864}, + {0x5ea5, 6868}, + {0x5ea6, 1811}, + {0x5ea7, 2221}, + {0x5ea8, 7304}, + {0x5eaa, 7306}, + {0x5eab, 2219}, + {0x5eac, 7307}, + {0x5ead, 2220}, + {0x5eae, 7305}, + {0x5eb0, 6863}, + {0x5eb1, 7886}, + {0x5eb2, 7889}, + {0x5eb3, 7890}, + {0x5eb4, 7887}, + {0x5eb5, 2675}, + {0x5eb6, 2674}, + {0x5eb7, 2672}, + {0x5eb8, 2673}, + {0x5eb9, 7888}, + {0x5ebe, 2676}, + {0x5ec1, 3133}, + {0x5ec2, 3134}, + {0x5ec4, 3135}, + {0x5ec5, 9164}, + {0x5ec6, 9166}, + {0x5ec7, 9168}, + {0x5ec8, 3586}, + {0x5ec9, 3585}, + {0x5eca, 3132}, + {0x5ecb, 9167}, + {0x5ecc, 9165}, + {0x5ece, 9848}, + {0x5ed1, 9846}, + {0x5ed2, 9852}, + {0x5ed3, 4042}, + {0x5ed4, 9853}, + {0x5ed5, 9850}, + {0x5ed6, 4043}, + {0x5ed7, 9847}, + {0x5ed8, 9845}, + {0x5ed9, 9851}, + {0x5eda, 4412}, + {0x5edc, 9849}, + {0x5edd, 4414}, + {0x5edf, 4413}, + {0x5ee0, 4416}, + {0x5ee2, 4411}, + {0x5ee3, 4415}, + {0x5eec, 5501}, + {0x5eef, 0}, + {0x5ef3, 5954}, + {0x5ef4, 553}, + {0x5ef6, 1463}, + {0x5ef7, 1170}, + {0x5efa, 1812}, + {0x5efe, 654}, + {0x5eff, 717}, + {0x5f01, 829}, + {0x5f02, 6118}, + {0x5f04, 1171}, + {0x5f05, 6265}, + {0x5f07, 6869}, + {0x5f08, 1813}, + {0x5f0a, 4044}, + {0x5f0b, 655}, + {0x5f0f, 972}, + {0x5f12, 3587}, + {0x5f13, 656}, + {0x5f14, 718}, + {0x5f15, 719}, + {0x5f17, 831}, + {0x5f18, 830}, + {0x5f1a, 6119}, + {0x5f1b, 973}, + {0x5f1d, 6266}, + {0x5f1f, 1172}, + {0x5f22, 6515}, + {0x5f23, 6516}, + {0x5f24, 6517}, + {0x5f26, 1464}, + {0x5f27, 1465}, + {0x5f28, 6514}, + {0x5f29, 1466}, + {0x5f2d, 1814}, + {0x5f2e, 6870}, + {0x5f30, 7309}, + {0x5f31, 2222}, + {0x5f33, 7308}, + {0x5f35, 2677}, + {0x5f36, 7891}, + {0x5f37, 2678}, + {0x5f38, 7892}, + {0x5f3c, 3136}, + {0x5f40, 9169}, + {0x5f43, 9855}, + {0x5f44, 9854}, + {0x5f46, 4045}, + {0x5f48, 4417}, + {0x5f4a, 4781}, + {0x5f4c, 5070}, + {0x5f4e, 5827}, + {0x5f50, 554}, + {0x5f54, 6518}, + {0x5f56, 6871}, + {0x5f57, 2679}, + {0x5f58, 8495}, + {0x5f59, 3588}, + {0x5f5d, 5327}, + {0x5f61, 555}, + {0x5f62, 1174}, + {0x5f64, 1173}, + {0x5f65, 1815}, + {0x5f67, 7310}, + {0x5f69, 2681}, + {0x5f6a, 2953}, + {0x5f6b, 2682}, + {0x5f6c, 2680}, + {0x5f6d, 3137}, + {0x5f6f, 9856}, + {0x5f70, 4046}, + {0x5f71, 4418}, + {0x5f73, 6007}, + {0x5f74, 6120}, + {0x5f76, 6268}, + {0x5f77, 1175}, + {0x5f78, 6267}, + {0x5f79, 1176}, + {0x5f7c, 1470}, + {0x5f7d, 6521}, + {0x5f7e, 6520}, + {0x5f7f, 1469}, + {0x5f80, 1467}, + {0x5f81, 1468}, + {0x5f82, 6519}, + {0x5f85, 1817}, + {0x5f86, 6872}, + {0x5f87, 1820}, + {0x5f88, 1816}, + {0x5f89, 1822}, + {0x5f8a, 1818}, + {0x5f8b, 1819}, + {0x5f8c, 1821}, + {0x5f90, 2225}, + {0x5f91, 2224}, + {0x5f92, 2223}, + {0x5f96, 7894}, + {0x5f97, 2683}, + {0x5f98, 2686}, + {0x5f99, 2684}, + {0x5f9b, 7893}, + {0x5f9c, 2689}, + {0x5f9e, 2685}, + {0x5f9f, 7895}, + {0x5fa0, 2688}, + {0x5fa1, 2687}, + {0x5fa5, 8497}, + {0x5fa6, 8496}, + {0x5fa8, 3140}, + {0x5fa9, 3138}, + {0x5faa, 3139}, + {0x5fab, 8498}, + {0x5fac, 3589}, + {0x5fad, 9171}, + {0x5fae, 3590}, + {0x5faf, 9170}, + {0x5fb5, 4420}, + {0x5fb6, 9857}, + {0x5fb7, 4419}, + {0x5fb9, 4047}, + {0x5fbd, 5071}, + {0x5fc1, 0}, + {0x5fc3, 720}, + {0x5fc5, 832}, + {0x5fc9, 6055}, + {0x5fcc, 1178}, + {0x5fcd, 1180}, + {0x5fcf, 6123}, + {0x5fd0, 6271}, + {0x5fd1, 6270}, + {0x5fd2, 6269}, + {0x5fd4, 6122}, + {0x5fd5, 6121}, + {0x5fd6, 975}, + {0x5fd7, 1179}, + {0x5fd8, 1177}, + {0x5fd9, 974}, + {0x5fdd, 1471}, + {0x5fde, 6522}, + {0x5fe0, 1472}, + {0x5fe1, 6276}, + {0x5fe3, 6278}, + {0x5fe4, 6277}, + {0x5fe5, 6523}, + {0x5fe8, 6273}, + {0x5fea, 1184}, + {0x5feb, 1182}, + {0x5fed, 6272}, + {0x5fee, 6274}, + {0x5fef, 6280}, + {0x5ff1, 1181}, + {0x5ff3, 6275}, + {0x5ff4, 6284}, + {0x5ff5, 1474}, + {0x5ff7, 6281}, + {0x5ff8, 1183}, + {0x5ffa, 6279}, + {0x5ffb, 6282}, + {0x5ffd, 1473}, + {0x5fff, 1475}, + {0x6000, 6283}, + {0x6009, 6543}, + {0x600a, 6530}, + {0x600b, 6528}, + {0x600c, 6542}, + {0x600d, 6537}, + {0x600e, 1827}, + {0x600f, 1476}, + {0x6010, 6538}, + {0x6011, 6541}, + {0x6012, 1823}, + {0x6013, 6540}, + {0x6014, 1477}, + {0x6015, 1482}, + {0x6016, 1480}, + {0x6017, 6531}, + {0x6019, 6526}, + {0x601a, 6533}, + {0x601b, 1487}, + {0x601c, 6544}, + {0x601d, 1824}, + {0x601e, 6534}, + {0x6020, 1825}, + {0x6021, 1483}, + {0x6022, 6536}, + {0x6024, 6887}, + {0x6025, 1826}, + {0x6026, 6525}, + {0x6027, 1484}, + {0x6028, 1828}, + {0x6029, 1485}, + {0x602a, 1481}, + {0x602b, 1486}, + {0x602c, 6535}, + {0x602d, 6524}, + {0x602e, 6539}, + {0x602f, 1478}, + {0x6032, 6527}, + {0x6033, 6532}, + {0x6034, 6529}, + {0x6035, 1479}, + {0x6037, 6873}, + {0x6039, 6874}, + {0x6040, 6884}, + {0x6041, 7314}, + {0x6042, 6885}, + {0x6043, 1834}, + {0x6044, 6888}, + {0x6045, 6878}, + {0x6046, 1833}, + {0x6047, 6880}, + {0x6049, 6881}, + {0x604c, 6883}, + {0x604d, 1829}, + {0x6050, 2229}, + {0x6053, 6879}, + {0x6054, 6875}, + {0x6055, 2230}, + {0x6058, 6889}, + {0x6059, 2226}, + {0x605a, 7312}, + {0x605b, 6882}, + {0x605d, 7311}, + {0x605e, 6877}, + {0x605f, 6886}, + {0x6062, 1832}, + {0x6063, 2227}, + {0x6064, 1838}, + {0x6065, 2228}, + {0x6066, 6890}, + {0x6067, 7313}, + {0x6068, 1831}, + {0x6069, 2232}, + {0x606a, 1837}, + {0x606b, 1836}, + {0x606c, 1835}, + {0x606d, 2231}, + {0x606e, 6891}, + {0x606f, 2233}, + {0x6070, 1830}, + {0x6072, 6876}, + {0x607f, 2690}, + {0x6080, 7317}, + {0x6081, 7319}, + {0x6083, 7321}, + {0x6084, 2234}, + {0x6085, 2240}, + {0x6086, 7898}, + {0x6087, 7325}, + {0x6088, 7316}, + {0x6089, 2692}, + {0x608a, 7896}, + {0x608c, 2239}, + {0x608d, 2237}, + {0x608e, 7327}, + {0x6090, 7897}, + {0x6092, 7318}, + {0x6094, 2238}, + {0x6095, 7322}, + {0x6096, 2241}, + {0x6097, 7324}, + {0x609a, 2236}, + {0x609b, 7323}, + {0x609c, 7326}, + {0x609d, 7320}, + {0x609f, 2235}, + {0x60a0, 2693}, + {0x60a2, 7315}, + {0x60a3, 2691}, + {0x60a8, 2694}, + {0x60b0, 7900}, + {0x60b1, 7909}, + {0x60b2, 3143}, + {0x60b4, 2696}, + {0x60b5, 2701}, + {0x60b6, 3144}, + {0x60b7, 7911}, + {0x60b8, 2708}, + {0x60b9, 8500}, + {0x60ba, 7901}, + {0x60bb, 2700}, + {0x60bc, 2703}, + {0x60bd, 2698}, + {0x60be, 7899}, + {0x60bf, 7913}, + {0x60c0, 7916}, + {0x60c1, 8515}, + {0x60c3, 7914}, + {0x60c4, 8504}, + {0x60c5, 2699}, + {0x60c6, 2706}, + {0x60c7, 2710}, + {0x60c8, 7908}, + {0x60c9, 8499}, + {0x60ca, 7912}, + {0x60cb, 2695}, + {0x60cc, 8501}, + {0x60cd, 7915}, + {0x60ce, 8503}, + {0x60cf, 7904}, + {0x60d1, 3141}, + {0x60d3, 7902}, + {0x60d4, 7903}, + {0x60d5, 2705}, + {0x60d8, 2704}, + {0x60d9, 7906}, + {0x60da, 2709}, + {0x60db, 7910}, + {0x60dc, 2702}, + {0x60dd, 7907}, + {0x60df, 2707}, + {0x60e0, 3145}, + {0x60e1, 3142}, + {0x60e2, 8502}, + {0x60e4, 7905}, + {0x60e6, 2697}, + {0x60f0, 3150}, + {0x60f1, 3154}, + {0x60f2, 8506}, + {0x60f3, 3595}, + {0x60f4, 3152}, + {0x60f5, 8510}, + {0x60f6, 3156}, + {0x60f7, 9172}, + {0x60f8, 8512}, + {0x60f9, 3597}, + {0x60fa, 3148}, + {0x60fb, 3151}, + {0x60fc, 8513}, + {0x60fe, 8514}, + {0x60ff, 8520}, + {0x6100, 3158}, + {0x6101, 3598}, + {0x6103, 8516}, + {0x6104, 8521}, + {0x6105, 8509}, + {0x6106, 3608}, + {0x6108, 3599}, + {0x6109, 3157}, + {0x610a, 8507}, + {0x610b, 8522}, + {0x610d, 3607}, + {0x610e, 3155}, + {0x610f, 3592}, + {0x6110, 8519}, + {0x6112, 3159}, + {0x6113, 8511}, + {0x6114, 8505}, + {0x6115, 3149}, + {0x6116, 8508}, + {0x6118, 8517}, + {0x611a, 3591}, + {0x611b, 3596}, + {0x611c, 3146}, + {0x611d, 8518}, + {0x611f, 3594}, + {0x6123, 3147}, + {0x6127, 3606}, + {0x6128, 9859}, + {0x6129, 9183}, + {0x612b, 9175}, + {0x612c, 9858}, + {0x612e, 9179}, + {0x612f, 9181}, + {0x6132, 9178}, + {0x6134, 3605}, + {0x6136, 9177}, + {0x6137, 3609}, + {0x613b, 9874}, + {0x613e, 3604}, + {0x613f, 4049}, + {0x6140, 9184}, + {0x6141, 9860}, + {0x6144, 3602}, + {0x6145, 9176}, + {0x6146, 9180}, + {0x6147, 4048}, + {0x6148, 3593}, + {0x6149, 9173}, + {0x614a, 9174}, + {0x614b, 4050}, + {0x614c, 3601}, + {0x614d, 3603}, + {0x614e, 3600}, + {0x614f, 9182}, + {0x6152, 9864}, + {0x6153, 9865}, + {0x6154, 9870}, + {0x6155, 4425}, + {0x6156, 9877}, + {0x6158, 4056}, + {0x615a, 4055}, + {0x615b, 9872}, + {0x615d, 4424}, + {0x615e, 9861}, + {0x615f, 4054}, + {0x6161, 9876}, + {0x6162, 4052}, + {0x6163, 4053}, + {0x6165, 9873}, + {0x6167, 4422}, + {0x6168, 3153}, + {0x616a, 9875}, + {0x616b, 4429}, + {0x616c, 9867}, + {0x616e, 4423}, + {0x6170, 4428}, + {0x6171, 9862}, + {0x6172, 9866}, + {0x6173, 9863}, + {0x6174, 9869}, + {0x6175, 4057}, + {0x6176, 4421}, + {0x6177, 4051}, + {0x617a, 9871}, + {0x617c, 4427}, + {0x617e, 4430}, + {0x6180, 9868}, + {0x6182, 4426}, + {0x618a, 4785}, + {0x618e, 4434}, + {0x6190, 4432}, + {0x6191, 4783}, + {0x6194, 4438}, + {0x619a, 4436}, + {0x61a4, 4437}, + {0x61a7, 4431}, + {0x61a9, 4784}, + {0x61ab, 4433}, + {0x61ac, 4435}, + {0x61ae, 4439}, + {0x61b2, 4782}, + {0x61b6, 4787}, + {0x61be, 4788}, + {0x61c2, 5073}, + {0x61c7, 5074}, + {0x61c8, 4790}, + {0x61c9, 5072}, + {0x61ca, 4789}, + {0x61cb, 5076}, + {0x61cd, 4786}, + {0x61e3, 5328}, + {0x61e6, 5075}, + {0x61ee, 0}, + {0x61f2, 5502}, + {0x61f5, 5505}, + {0x61f6, 5504}, + {0x61f7, 5503}, + {0x61f8, 5652}, + {0x61fa, 5653}, + {0x61fc, 5744}, + {0x61fe, 5745}, + {0x61ff, 5828}, + {0x6200, 5880}, + {0x6204, 0}, + {0x6208, 721}, + {0x6209, 6056}, + {0x620a, 833}, + {0x620c, 977}, + {0x620d, 978}, + {0x620e, 976}, + {0x6210, 979}, + {0x6211, 1186}, + {0x6212, 1185}, + {0x6214, 6545}, + {0x6215, 1489}, + {0x6216, 1488}, + {0x6219, 7328}, + {0x621a, 2711}, + {0x621b, 2712}, + {0x621f, 3160}, + {0x6220, 9185}, + {0x6221, 3610}, + {0x6222, 3611}, + {0x6223, 9187}, + {0x6224, 9189}, + {0x6225, 9188}, + {0x6227, 9879}, + {0x6229, 9878}, + {0x622a, 4058}, + {0x622b, 9880}, + {0x622e, 4440}, + {0x6230, 4791}, + {0x6232, 5077}, + {0x6233, 5329}, + {0x6234, 5078}, + {0x6236, 722}, + {0x623a, 6285}, + {0x623d, 6546}, + {0x623e, 1491}, + {0x623f, 1490}, + {0x6240, 1492}, + {0x6241, 1839}, + {0x6242, 6892}, + {0x6243, 6893}, + {0x6246, 7329}, + {0x6247, 2242}, + {0x6248, 2713}, + {0x6249, 3161}, + {0x624a, 8523}, + {0x624b, 723}, + {0x624d, 657}, + {0x624e, 724}, + {0x6250, 6057}, + {0x6251, 837}, + {0x6252, 836}, + {0x6253, 834}, + {0x6254, 835}, + {0x6258, 982}, + {0x6259, 6130}, + {0x625a, 6132}, + {0x625b, 981}, + {0x625c, 6124}, + {0x625e, 6125}, + {0x6260, 6131}, + {0x6261, 6127}, + {0x6262, 6129}, + {0x6263, 980}, + {0x6264, 6126}, + {0x6265, 6133}, + {0x6266, 6128}, + {0x626d, 1193}, + {0x626e, 1202}, + {0x626f, 1200}, + {0x6270, 6295}, + {0x6271, 6292}, + {0x6272, 6300}, + {0x6273, 1198}, + {0x6274, 6301}, + {0x6276, 1191}, + {0x6277, 6298}, + {0x6279, 1197}, + {0x627a, 6294}, + {0x627b, 6293}, + {0x627c, 1195}, + {0x627d, 6299}, + {0x627e, 1196}, + {0x627f, 1493}, + {0x6280, 1190}, + {0x6281, 6296}, + {0x6283, 6286}, + {0x6284, 1187}, + {0x6286, 1206}, + {0x6287, 6291}, + {0x6288, 6297}, + {0x6289, 1192}, + {0x628a, 1194}, + {0x628c, 6287}, + {0x628e, 6288}, + {0x628f, 6289}, + {0x6291, 1205}, + {0x6292, 1199}, + {0x6293, 1204}, + {0x6294, 6290}, + {0x6295, 1203}, + {0x6296, 1189}, + {0x6297, 1188}, + {0x6298, 1201}, + {0x62a8, 1507}, + {0x62a9, 6558}, + {0x62aa, 6551}, + {0x62ab, 1502}, + {0x62ac, 1521}, + {0x62ad, 6547}, + {0x62ae, 6554}, + {0x62af, 6556}, + {0x62b0, 6559}, + {0x62b1, 1516}, + {0x62b3, 6555}, + {0x62b4, 6548}, + {0x62b5, 1514}, + {0x62b6, 6552}, + {0x62b8, 6560}, + {0x62b9, 1499}, + {0x62bb, 6557}, + {0x62bc, 1509}, + {0x62bd, 1508}, + {0x62be, 6550}, + {0x62bf, 1497}, + {0x62c2, 1498}, + {0x62c4, 1496}, + {0x62c6, 1520}, + {0x62c7, 1512}, + {0x62c8, 1506}, + {0x62c9, 1494}, + {0x62ca, 6553}, + {0x62cb, 1505}, + {0x62cc, 1495}, + {0x62cd, 1513}, + {0x62ce, 1522}, + {0x62cf, 6894}, + {0x62d0, 1510}, + {0x62d1, 6549}, + {0x62d2, 1500}, + {0x62d3, 1503}, + {0x62d4, 1504}, + {0x62d6, 1518}, + {0x62d7, 1519}, + {0x62d8, 1517}, + {0x62d9, 1511}, + {0x62da, 1515}, + {0x62db, 1501}, + {0x62dc, 1840}, + {0x62eb, 6900}, + {0x62ec, 1852}, + {0x62ed, 1844}, + {0x62ee, 1846}, + {0x62ef, 1851}, + {0x62f0, 6912}, + {0x62f1, 1849}, + {0x62f2, 7330}, + {0x62f3, 2243}, + {0x62f4, 1854}, + {0x62f5, 6897}, + {0x62f6, 6905}, + {0x62f7, 1850}, + {0x62f8, 6904}, + {0x62f9, 6901}, + {0x62fa, 6909}, + {0x62fb, 6911}, + {0x62fc, 1843}, + {0x62fd, 1847}, + {0x62fe, 1853}, + {0x62ff, 2245}, + {0x6300, 6906}, + {0x6301, 1845}, + {0x6302, 1856}, + {0x6303, 6899}, + {0x6307, 1848}, + {0x6308, 2244}, + {0x6309, 1842}, + {0x630b, 6896}, + {0x630c, 6903}, + {0x630d, 6895}, + {0x630e, 6898}, + {0x630f, 6902}, + {0x6310, 7331}, + {0x6311, 1855}, + {0x6313, 6907}, + {0x6314, 6908}, + {0x6315, 6910}, + {0x6316, 1841}, + {0x6328, 2259}, + {0x6329, 7343}, + {0x632a, 2257}, + {0x632b, 2258}, + {0x632c, 7333}, + {0x632d, 7349}, + {0x632f, 2248}, + {0x6332, 7917}, + {0x6333, 7351}, + {0x6334, 7345}, + {0x6336, 7336}, + {0x6338, 7354}, + {0x6339, 7339}, + {0x633a, 2254}, + {0x633b, 7940}, + {0x633c, 7342}, + {0x633d, 2256}, + {0x633e, 2247}, + {0x6340, 7356}, + {0x6341, 7344}, + {0x6342, 2250}, + {0x6343, 7337}, + {0x6344, 7334}, + {0x6345, 7335}, + {0x6346, 2251}, + {0x6347, 7350}, + {0x6348, 7357}, + {0x6349, 2253}, + {0x634a, 7341}, + {0x634b, 7340}, + {0x634c, 2261}, + {0x634d, 2260}, + {0x634e, 2246}, + {0x634f, 2252}, + {0x6350, 2255}, + {0x6351, 7353}, + {0x6354, 7347}, + {0x6355, 2249}, + {0x6356, 7332}, + {0x6357, 7355}, + {0x6358, 7346}, + {0x6359, 7348}, + {0x635a, 7352}, + {0x6365, 7918}, + {0x6367, 2721}, + {0x6368, 2741}, + {0x6369, 2740}, + {0x636b, 2729}, + {0x636d, 7936}, + {0x636e, 7932}, + {0x636f, 7929}, + {0x6370, 7947}, + {0x6371, 2724}, + {0x6372, 2716}, + {0x6375, 7934}, + {0x6376, 3177}, + {0x6377, 2720}, + {0x6378, 7942}, + {0x637a, 2742}, + {0x637b, 2739}, + {0x637c, 7938}, + {0x637d, 7921}, + {0x6380, 2738}, + {0x6381, 7944}, + {0x6382, 7920}, + {0x6383, 2727}, + {0x6384, 2731}, + {0x6385, 7943}, + {0x6387, 7930}, + {0x6388, 2732}, + {0x6389, 2726}, + {0x638a, 7919}, + {0x638c, 3163}, + {0x638d, 7946}, + {0x638e, 7928}, + {0x638f, 2737}, + {0x6390, 7931}, + {0x6391, 7945}, + {0x6392, 2736}, + {0x6394, 8524}, + {0x6396, 2717}, + {0x6397, 7926}, + {0x6398, 2722}, + {0x6399, 2733}, + {0x639b, 2728}, + {0x639c, 7935}, + {0x639d, 7925}, + {0x639e, 7923}, + {0x639f, 7941}, + {0x63a0, 2714}, + {0x63a1, 2734}, + {0x63a2, 2718}, + {0x63a3, 3162}, + {0x63a4, 7939}, + {0x63a5, 2719}, + {0x63a7, 2715}, + {0x63a8, 2730}, + {0x63a9, 2725}, + {0x63aa, 2723}, + {0x63ab, 7927}, + {0x63ac, 2735}, + {0x63ad, 7924}, + {0x63ae, 7937}, + {0x63af, 7933}, + {0x63b0, 8526}, + {0x63b1, 8525}, + {0x63bd, 7922}, + {0x63be, 8542}, + {0x63c0, 3165}, + {0x63c2, 8548}, + {0x63c3, 8531}, + {0x63c4, 8545}, + {0x63c5, 9190}, + {0x63c6, 3168}, + {0x63c7, 8549}, + {0x63c8, 8552}, + {0x63c9, 3167}, + {0x63ca, 8534}, + {0x63cb, 8551}, + {0x63cc, 8550}, + {0x63cd, 3169}, + {0x63ce, 8527}, + {0x63cf, 3164}, + {0x63d0, 3172}, + {0x63d2, 3170}, + {0x63d3, 8547}, + {0x63d5, 8537}, + {0x63d6, 3174}, + {0x63d7, 8554}, + {0x63d8, 8546}, + {0x63d9, 8555}, + {0x63da, 3182}, + {0x63db, 3180}, + {0x63dc, 8544}, + {0x63dd, 8543}, + {0x63df, 8541}, + {0x63e0, 8535}, + {0x63e1, 3173}, + {0x63e3, 3171}, + {0x63e4, 7338}, + {0x63e5, 8528}, + {0x63e7, 9220}, + {0x63e8, 8529}, + {0x63e9, 3166}, + {0x63ea, 3179}, + {0x63eb, 9192}, + {0x63ed, 3175}, + {0x63ee, 3176}, + {0x63ef, 8530}, + {0x63f0, 8553}, + {0x63f1, 9191}, + {0x63f2, 8538}, + {0x63f3, 8533}, + {0x63f4, 3178}, + {0x63f5, 8539}, + {0x63f6, 8536}, + {0x63f9, 3183}, + {0x6406, 3626}, + {0x6409, 9195}, + {0x640a, 9214}, + {0x640b, 9219}, + {0x640c, 9207}, + {0x640d, 3622}, + {0x640e, 9224}, + {0x640f, 3619}, + {0x6410, 9193}, + {0x6412, 9194}, + {0x6413, 3612}, + {0x6414, 3621}, + {0x6415, 9201}, + {0x6416, 3624}, + {0x6417, 3625}, + {0x6418, 9202}, + {0x641a, 9215}, + {0x641b, 9221}, + {0x641c, 3620}, + {0x641e, 3614}, + {0x641f, 9200}, + {0x6420, 9196}, + {0x6421, 9223}, + {0x6422, 9205}, + {0x6423, 9206}, + {0x6424, 9197}, + {0x6425, 9217}, + {0x6426, 9208}, + {0x6427, 9218}, + {0x6428, 9210}, + {0x642a, 3615}, + {0x642b, 9881}, + {0x642c, 3618}, + {0x642d, 3616}, + {0x642e, 9222}, + {0x642f, 9213}, + {0x6430, 9209}, + {0x6433, 9198}, + {0x6434, 4068}, + {0x6435, 9212}, + {0x6436, 3623}, + {0x6437, 9204}, + {0x6439, 9203}, + {0x643d, 3617}, + {0x643e, 3613}, + {0x643f, 9902}, + {0x6440, 9216}, + {0x6441, 9211}, + {0x6443, 9199}, + {0x644b, 9897}, + {0x644d, 9882}, + {0x644e, 9893}, + {0x6450, 9900}, + {0x6451, 4066}, + {0x6452, 3181}, + {0x6453, 9898}, + {0x6454, 4061}, + {0x6458, 4060}, + {0x6459, 9905}, + {0x645b, 9883}, + {0x645c, 9896}, + {0x645d, 9884}, + {0x645e, 9895}, + {0x645f, 4064}, + {0x6460, 9899}, + {0x6461, 8540}, + {0x6465, 9906}, + {0x6466, 9891}, + {0x6467, 4067}, + {0x6469, 4441}, + {0x646b, 9904}, + {0x646c, 9903}, + {0x646d, 4069}, + {0x646f, 4442}, + {0x6472, 9887}, + {0x6473, 9888}, + {0x6474, 9885}, + {0x6475, 9890}, + {0x6476, 9886}, + {0x6477, 9907}, + {0x6478, 4063}, + {0x6479, 4443}, + {0x647a, 4065}, + {0x647b, 4070}, + {0x647d, 9889}, + {0x647f, 9901}, + {0x6482, 9894}, + {0x6487, 4059}, + {0x6488, 4446}, + {0x6490, 4447}, + {0x6492, 4453}, + {0x6493, 4450}, + {0x6495, 4451}, + {0x6499, 4459}, + {0x649a, 4457}, + {0x649d, 8532}, + {0x649e, 4444}, + {0x64a2, 4460}, + {0x64a4, 4062}, + {0x64a5, 4449}, + {0x64a6, 9892}, + {0x64a9, 4452}, + {0x64ab, 4456}, + {0x64ac, 4458}, + {0x64ad, 4455}, + {0x64ae, 4454}, + {0x64b0, 4448}, + {0x64b2, 4445}, + {0x64b3, 4461}, + {0x64bb, 4795}, + {0x64bc, 4796}, + {0x64be, 4805}, + {0x64bf, 4802}, + {0x64c1, 4793}, + {0x64c2, 4800}, + {0x64c4, 4798}, + {0x64c5, 4792}, + {0x64c7, 4799}, + {0x64ca, 5080}, + {0x64cb, 4794}, + {0x64cd, 4801}, + {0x64ce, 5079}, + {0x64d2, 4803}, + {0x64d4, 4804}, + {0x64d8, 5081}, + {0x64da, 4797}, + {0x64e0, 5082}, + {0x64e2, 5087}, + {0x64e6, 5084}, + {0x64ec, 5085}, + {0x64ed, 5088}, + {0x64f0, 5083}, + {0x64f1, 5086}, + {0x64f2, 5331}, + {0x64f4, 5330}, + {0x64f7, 5336}, + {0x64fa, 5334}, + {0x64fb, 5335}, + {0x64fe, 5332}, + {0x6500, 5506}, + {0x6506, 5333}, + {0x650f, 5507}, + {0x6514, 5655}, + {0x6518, 5654}, + {0x6519, 5656}, + {0x651c, 5747}, + {0x651d, 5746}, + {0x6523, 5881}, + {0x6524, 5829}, + {0x652a, 5883}, + {0x652b, 5882}, + {0x652c, 5921}, + {0x652f, 725}, + {0x6532, 8556}, + {0x6534, 556}, + {0x6536, 983}, + {0x6537, 6134}, + {0x6538, 1209}, + {0x6539, 1207}, + {0x653b, 1208}, + {0x653d, 6561}, + {0x653e, 1523}, + {0x653f, 1857}, + {0x6541, 6913}, + {0x6543, 6914}, + {0x6545, 1858}, + {0x6546, 7359}, + {0x6548, 2262}, + {0x6549, 2263}, + {0x654a, 7358}, + {0x654f, 2749}, + {0x6551, 2745}, + {0x6553, 7948}, + {0x6554, 2752}, + {0x6555, 2751}, + {0x6556, 2744}, + {0x6557, 2747}, + {0x6558, 2750}, + {0x6559, 2746}, + {0x655c, 8560}, + {0x655d, 2743}, + {0x655e, 3184}, + {0x6562, 3186}, + {0x6563, 3187}, + {0x6564, 8559}, + {0x6565, 8562}, + {0x6566, 3185}, + {0x6567, 8557}, + {0x6568, 8561}, + {0x656a, 8558}, + {0x656c, 3627}, + {0x656f, 9225}, + {0x6572, 4071}, + {0x6573, 9908}, + {0x6574, 4806}, + {0x6575, 4462}, + {0x6577, 4463}, + {0x6578, 4464}, + {0x6582, 5089}, + {0x6583, 5090}, + {0x6587, 726}, + {0x658c, 8563}, + {0x6590, 3189}, + {0x6591, 3188}, + {0x6592, 9226}, + {0x6595, 5748}, + {0x6597, 727}, + {0x6599, 2264}, + {0x659b, 2754}, + {0x659c, 2753}, + {0x659d, 8564}, + {0x659e, 8565}, + {0x659f, 3628}, + {0x65a0, 9909}, + {0x65a1, 4072}, + {0x65a4, 728}, + {0x65a5, 838}, + {0x65a7, 1524}, + {0x65a8, 6562}, + {0x65aa, 6915}, + {0x65ab, 1859}, + {0x65ac, 2755}, + {0x65ae, 8566}, + {0x65af, 3190}, + {0x65b0, 3629}, + {0x65b3, 0}, + {0x65b7, 5337}, + {0x65b9, 729}, + {0x65bb, 6563}, + {0x65bc, 1525}, + {0x65bd, 1860}, + {0x65bf, 6916}, + {0x65c1, 2265}, + {0x65c2, 7363}, + {0x65c3, 7361}, + {0x65c4, 7362}, + {0x65c5, 2266}, + {0x65c6, 7360}, + {0x65cb, 2757}, + {0x65cc, 2758}, + {0x65cd, 7949}, + {0x65ce, 2759}, + {0x65cf, 2756}, + {0x65d0, 8567}, + {0x65d2, 8568}, + {0x65d3, 9227}, + {0x65d6, 4074}, + {0x65d7, 4073}, + {0x65e0, 557}, + {0x65e1, 6025}, + {0x65e2, 1861}, + {0x65e5, 730}, + {0x65e6, 839}, + {0x65e8, 985}, + {0x65e9, 984}, + {0x65ec, 986}, + {0x65ed, 987}, + {0x65ee, 6136}, + {0x65ef, 6135}, + {0x65f0, 6302}, + {0x65f1, 1210}, + {0x65f2, 6305}, + {0x65f3, 6304}, + {0x65f4, 6303}, + {0x65f5, 6306}, + {0x65fa, 1526}, + {0x65fb, 6569}, + {0x65fc, 6565}, + {0x65fd, 6574}, + {0x6600, 1533}, + {0x6602, 1531}, + {0x6603, 6570}, + {0x6604, 6566}, + {0x6605, 6573}, + {0x6606, 1530}, + {0x6607, 1537}, + {0x6608, 6568}, + {0x6609, 6564}, + {0x660a, 1536}, + {0x660b, 6571}, + {0x660c, 1529}, + {0x660d, 6572}, + {0x660e, 1532}, + {0x660f, 1534}, + {0x6610, 6576}, + {0x6611, 6575}, + {0x6612, 6567}, + {0x6613, 1528}, + {0x6614, 1527}, + {0x6615, 1535}, + {0x661c, 6921}, + {0x661d, 6927}, + {0x661f, 1867}, + {0x6620, 1864}, + {0x6621, 6918}, + {0x6622, 6923}, + {0x6624, 1870}, + {0x6625, 1862}, + {0x6626, 6922}, + {0x6627, 1865}, + {0x6628, 1868}, + {0x662b, 6925}, + {0x662d, 1863}, + {0x662e, 6930}, + {0x662f, 1866}, + {0x6631, 1869}, + {0x6632, 6919}, + {0x6633, 6924}, + {0x6634, 6928}, + {0x6635, 6920}, + {0x6636, 6917}, + {0x6639, 6929}, + {0x663a, 6926}, + {0x6641, 2274}, + {0x6642, 2267}, + {0x6643, 2270}, + {0x6645, 2273}, + {0x6647, 7366}, + {0x6649, 2268}, + {0x664a, 7364}, + {0x664c, 2272}, + {0x664f, 2269}, + {0x6651, 7367}, + {0x6652, 2271}, + {0x6659, 7953}, + {0x665a, 2761}, + {0x665b, 7952}, + {0x665c, 7954}, + {0x665d, 2760}, + {0x665e, 2765}, + {0x665f, 7365}, + {0x6661, 7951}, + {0x6662, 7955}, + {0x6664, 2762}, + {0x6665, 7950}, + {0x6666, 2764}, + {0x6668, 2763}, + {0x666a, 8575}, + {0x666c, 8570}, + {0x666e, 3191}, + {0x666f, 3195}, + {0x6670, 3192}, + {0x6671, 8573}, + {0x6672, 8576}, + {0x6674, 3193}, + {0x6676, 3194}, + {0x6677, 3199}, + {0x6678, 9236}, + {0x6679, 8574}, + {0x667a, 3197}, + {0x667b, 8571}, + {0x667c, 8569}, + {0x667e, 3198}, + {0x6680, 8572}, + {0x6684, 3635}, + {0x6686, 9228}, + {0x6687, 3632}, + {0x6688, 3633}, + {0x6689, 3631}, + {0x668a, 9233}, + {0x668b, 9232}, + {0x668c, 9229}, + {0x668d, 3637}, + {0x6690, 9231}, + {0x6691, 3196}, + {0x6694, 9235}, + {0x6695, 9230}, + {0x6696, 3634}, + {0x6697, 3630}, + {0x6698, 3636}, + {0x6699, 9234}, + {0x669d, 4077}, + {0x669f, 9912}, + {0x66a0, 9911}, + {0x66a1, 9910}, + {0x66a2, 4075}, + {0x66a8, 4076}, + {0x66ab, 4466}, + {0x66ae, 4465}, + {0x66b1, 4468}, + {0x66b4, 4467}, + {0x66b8, 4812}, + {0x66b9, 4809}, + {0x66c4, 4810}, + {0x66c6, 4807}, + {0x66c7, 4811}, + {0x66c9, 4808}, + {0x66cb, 0}, + {0x66d6, 5092}, + {0x66d9, 5091}, + {0x66db, 0}, + {0x66dc, 5338}, + {0x66dd, 5509}, + {0x66e0, 5508}, + {0x66e4, 0}, + {0x66e6, 5657}, + {0x66e9, 5749}, + {0x66ec, 5884}, + {0x66ee, 0}, + {0x66f0, 731}, + {0x66f2, 988}, + {0x66f3, 989}, + {0x66f4, 1211}, + {0x66f6, 6577}, + {0x66f7, 1871}, + {0x66f8, 2275}, + {0x66f9, 2766}, + {0x66fc, 2591}, + {0x66fe, 3200}, + {0x66ff, 3201}, + {0x6700, 3056}, + {0x6701, 8577}, + {0x6703, 3638}, + {0x6704, 9914}, + {0x6705, 9913}, + {0x6708, 732}, + {0x6709, 990}, + {0x670a, 6578}, + {0x670b, 1539}, + {0x670d, 1538}, + {0x670f, 6931}, + {0x6710, 6932}, + {0x6712, 7368}, + {0x6713, 7369}, + {0x6714, 2276}, + {0x6715, 2277}, + {0x6717, 2278}, + {0x6718, 7956}, + {0x671b, 2768}, + {0x671d, 3203}, + {0x671f, 3202}, + {0x6720, 9237}, + {0x6721, 9506}, + {0x6722, 9915}, + {0x6726, 5339}, + {0x6727, 5658}, + {0x6728, 733}, + {0x672a, 842}, + {0x672b, 843}, + {0x672c, 841}, + {0x672d, 844}, + {0x672e, 840}, + {0x6731, 993}, + {0x6733, 6144}, + {0x6734, 992}, + {0x6735, 994}, + {0x6738, 6139}, + {0x6739, 6138}, + {0x673a, 6141}, + {0x673b, 6140}, + {0x673c, 6143}, + {0x673d, 991}, + {0x673e, 6137}, + {0x673f, 6142}, + {0x6745, 6307}, + {0x6746, 1221}, + {0x6747, 6308}, + {0x6748, 6312}, + {0x6749, 1220}, + {0x674b, 6316}, + {0x674c, 6311}, + {0x674d, 6314}, + {0x674e, 1213}, + {0x674f, 1214}, + {0x6750, 1215}, + {0x6751, 1216}, + {0x6753, 1223}, + {0x6755, 6310}, + {0x6756, 1218}, + {0x6757, 1224}, + {0x6759, 6309}, + {0x675a, 6315}, + {0x675c, 1217}, + {0x675d, 6313}, + {0x675e, 1219}, + {0x675f, 1212}, + {0x6760, 1222}, + {0x676a, 1560}, + {0x676c, 6580}, + {0x676d, 1540}, + {0x676f, 1550}, + {0x6770, 1551}, + {0x6771, 1543}, + {0x6772, 1561}, + {0x6773, 1545}, + {0x6774, 6588}, + {0x6775, 1556}, + {0x6776, 6583}, + {0x6777, 1546}, + {0x6778, 6598}, + {0x6779, 6599}, + {0x677a, 6591}, + {0x677b, 6584}, + {0x677c, 1559}, + {0x677d, 6596}, + {0x677e, 1554}, + {0x677f, 1552}, + {0x6781, 6597}, + {0x6783, 6595}, + {0x6784, 6587}, + {0x6785, 6579}, + {0x6786, 6586}, + {0x6787, 1547}, + {0x6789, 1553}, + {0x678b, 1541}, + {0x678c, 6590}, + {0x678d, 6589}, + {0x678e, 6581}, + {0x6790, 1555}, + {0x6791, 6593}, + {0x6792, 6582}, + {0x6793, 1558}, + {0x6794, 6600}, + {0x6795, 1542}, + {0x6797, 1549}, + {0x6798, 6585}, + {0x6799, 6594}, + {0x679a, 1557}, + {0x679c, 1544}, + {0x679d, 1548}, + {0x679f, 6592}, + {0x67ae, 6964}, + {0x67af, 1879}, + {0x67b0, 1892}, + {0x67b2, 6959}, + {0x67b3, 6949}, + {0x67b4, 1885}, + {0x67b5, 6947}, + {0x67b6, 1878}, + {0x67b7, 6942}, + {0x67b8, 1888}, + {0x67b9, 6955}, + {0x67ba, 6936}, + {0x67bb, 6938}, + {0x67c0, 6941}, + {0x67c1, 6933}, + {0x67c2, 6954}, + {0x67c3, 6970}, + {0x67c4, 1883}, + {0x67c5, 6943}, + {0x67c6, 6961}, + {0x67c8, 6935}, + {0x67c9, 6968}, + {0x67ca, 6969}, + {0x67cb, 6972}, + {0x67cc, 6963}, + {0x67cd, 6948}, + {0x67ce, 6956}, + {0x67cf, 1889}, + {0x67d0, 1876}, + {0x67d1, 1884}, + {0x67d2, 1896}, + {0x67d3, 1873}, + {0x67d4, 1875}, + {0x67d8, 6940}, + {0x67d9, 1893}, + {0x67da, 1886}, + {0x67db, 6966}, + {0x67dc, 6937}, + {0x67dd, 1895}, + {0x67de, 1890}, + {0x67df, 6946}, + {0x67e2, 1894}, + {0x67e3, 6953}, + {0x67e4, 6945}, + {0x67e5, 1887}, + {0x67e6, 6965}, + {0x67e7, 6957}, + {0x67e9, 1881}, + {0x67ea, 6971}, + {0x67eb, 6944}, + {0x67ec, 1877}, + {0x67ed, 6962}, + {0x67ee, 6952}, + {0x67ef, 1882}, + {0x67f0, 6958}, + {0x67f1, 1874}, + {0x67f2, 6934}, + {0x67f3, 1891}, + {0x67f4, 2293}, + {0x67f5, 1880}, + {0x67f6, 6951}, + {0x67f7, 6950}, + {0x67f8, 6939}, + {0x67fa, 6967}, + {0x67fc, 6960}, + {0x67ff, 1872}, + {0x6812, 7389}, + {0x6813, 2300}, + {0x6814, 7390}, + {0x6816, 7378}, + {0x6817, 2289}, + {0x6818, 2301}, + {0x681a, 7371}, + {0x681c, 7380}, + {0x681d, 7388}, + {0x681f, 7370}, + {0x6820, 7397}, + {0x6821, 2279}, + {0x6825, 7396}, + {0x6826, 7391}, + {0x6828, 7392}, + {0x6829, 2287}, + {0x682a, 2298}, + {0x682b, 7382}, + {0x682d, 7383}, + {0x682e, 7393}, + {0x682f, 7384}, + {0x6831, 7379}, + {0x6832, 7373}, + {0x6833, 7374}, + {0x6834, 7387}, + {0x6835, 7381}, + {0x6838, 2280}, + {0x6839, 2284}, + {0x683a, 7395}, + {0x683b, 7375}, + {0x683c, 2296}, + {0x683d, 2292}, + {0x6840, 2295}, + {0x6841, 2302}, + {0x6842, 2285}, + {0x6843, 2297}, + {0x6844, 7386}, + {0x6845, 2299}, + {0x6846, 2282}, + {0x6848, 2281}, + {0x6849, 7372}, + {0x684b, 7376}, + {0x684c, 2290}, + {0x684d, 7394}, + {0x684e, 7385}, + {0x684f, 7377}, + {0x6850, 2294}, + {0x6851, 2291}, + {0x6853, 2283}, + {0x6854, 2286}, + {0x686b, 7977}, + {0x686d, 7961}, + {0x686e, 7962}, + {0x686f, 7966}, + {0x6871, 7981}, + {0x6872, 7978}, + {0x6874, 7971}, + {0x6875, 7970}, + {0x6876, 2775}, + {0x6877, 7974}, + {0x6878, 7989}, + {0x6879, 7957}, + {0x687b, 7990}, + {0x687c, 7976}, + {0x687d, 7994}, + {0x687e, 7982}, + {0x687f, 2774}, + {0x6880, 7980}, + {0x6881, 2769}, + {0x6882, 2790}, + {0x6883, 2780}, + {0x6885, 2784}, + {0x6886, 2783}, + {0x6887, 7958}, + {0x6889, 7987}, + {0x688a, 7993}, + {0x688b, 7985}, + {0x688c, 7992}, + {0x688f, 7973}, + {0x6890, 7959}, + {0x6891, 7991}, + {0x6892, 7975}, + {0x6893, 2772}, + {0x6894, 2785}, + {0x6896, 7984}, + {0x6897, 2778}, + {0x689b, 7983}, + {0x689c, 7960}, + {0x689d, 2786}, + {0x689f, 2788}, + {0x68a0, 7986}, + {0x68a1, 2789}, + {0x68a2, 2771}, + {0x68a3, 7967}, + {0x68a4, 7988}, + {0x68a7, 2777}, + {0x68a8, 2787}, + {0x68a9, 7969}, + {0x68aa, 7979}, + {0x68ab, 7964}, + {0x68ac, 7968}, + {0x68ad, 2782}, + {0x68ae, 7963}, + {0x68af, 2770}, + {0x68b0, 2779}, + {0x68b1, 2776}, + {0x68b2, 7972}, + {0x68b3, 2288}, + {0x68b4, 8600}, + {0x68b5, 2773}, + {0x68c4, 2781}, + {0x68c6, 8603}, + {0x68c7, 8625}, + {0x68c8, 8614}, + {0x68c9, 3223}, + {0x68cb, 3218}, + {0x68cc, 8597}, + {0x68cd, 3219}, + {0x68ce, 8613}, + {0x68d0, 8606}, + {0x68d1, 8619}, + {0x68d2, 3215}, + {0x68d3, 8579}, + {0x68d4, 8621}, + {0x68d5, 3205}, + {0x68d6, 8587}, + {0x68d7, 3208}, + {0x68d8, 3207}, + {0x68da, 3224}, + {0x68dc, 8581}, + {0x68dd, 8615}, + {0x68de, 8616}, + {0x68df, 3210}, + {0x68e0, 3206}, + {0x68e1, 8595}, + {0x68e3, 3217}, + {0x68e4, 8590}, + {0x68e6, 8617}, + {0x68e7, 3213}, + {0x68e8, 8609}, + {0x68e9, 8622}, + {0x68ea, 8584}, + {0x68eb, 8589}, + {0x68ec, 8583}, + {0x68ee, 3212}, + {0x68ef, 8602}, + {0x68f0, 9259}, + {0x68f1, 8585}, + {0x68f2, 3216}, + {0x68f3, 8594}, + {0x68f4, 8618}, + {0x68f5, 3211}, + {0x68f6, 8591}, + {0x68f7, 8588}, + {0x68f8, 8605}, + {0x68f9, 3214}, + {0x68fa, 3204}, + {0x68fb, 3226}, + {0x68fc, 8608}, + {0x68fd, 8607}, + {0x6904, 8580}, + {0x6905, 3209}, + {0x6906, 8620}, + {0x6907, 8596}, + {0x6908, 8598}, + {0x690a, 8611}, + {0x690b, 8610}, + {0x690c, 8578}, + {0x690d, 3220}, + {0x690e, 3222}, + {0x690f, 8586}, + {0x6910, 8593}, + {0x6911, 8601}, + {0x6912, 3221}, + {0x6913, 8592}, + {0x6914, 8604}, + {0x6915, 8623}, + {0x6917, 8612}, + {0x6925, 8624}, + {0x692a, 8582}, + {0x692f, 9279}, + {0x6930, 3646}, + {0x6932, 9277}, + {0x6933, 9256}, + {0x6934, 9261}, + {0x6935, 9254}, + {0x6937, 9273}, + {0x6938, 9240}, + {0x6939, 9247}, + {0x693b, 9271}, + {0x693c, 9281}, + {0x693d, 9257}, + {0x693f, 9244}, + {0x6940, 9263}, + {0x6941, 9268}, + {0x6942, 9248}, + {0x6944, 9265}, + {0x6945, 9245}, + {0x6948, 9252}, + {0x6949, 9253}, + {0x694a, 3648}, + {0x694b, 9272}, + {0x694c, 9270}, + {0x694e, 9241}, + {0x694f, 9275}, + {0x6951, 9276}, + {0x6952, 9278}, + {0x6953, 3652}, + {0x6954, 3644}, + {0x6956, 7965}, + {0x6957, 9249}, + {0x6958, 9267}, + {0x6959, 9250}, + {0x695a, 3641}, + {0x695b, 3657}, + {0x695c, 9274}, + {0x695d, 3655}, + {0x695e, 3651}, + {0x695f, 9239}, + {0x6960, 3643}, + {0x6962, 9242}, + {0x6963, 3656}, + {0x6965, 9258}, + {0x6966, 9238}, + {0x6968, 3649}, + {0x6969, 9262}, + {0x696a, 9246}, + {0x696b, 3650}, + {0x696c, 9255}, + {0x696d, 3640}, + {0x696e, 3225}, + {0x696f, 9264}, + {0x6970, 8599}, + {0x6971, 9243}, + {0x6974, 9269}, + {0x6975, 3645}, + {0x6976, 9266}, + {0x6977, 3642}, + {0x6978, 9260}, + {0x6979, 3653}, + {0x697a, 9251}, + {0x697b, 9280}, + {0x6982, 3647}, + {0x6983, 9391}, + {0x6986, 3654}, + {0x698d, 9929}, + {0x698e, 9927}, + {0x6990, 9949}, + {0x6991, 9925}, + {0x6993, 9943}, + {0x6994, 3639}, + {0x6995, 4080}, + {0x6996, 9921}, + {0x6997, 9948}, + {0x6999, 9926}, + {0x699a, 9940}, + {0x699b, 4085}, + {0x699c, 4078}, + {0x699e, 9946}, + {0x69a0, 9919}, + {0x69a1, 9945}, + {0x69a3, 4096}, + {0x69a4, 9936}, + {0x69a5, 9952}, + {0x69a6, 4094}, + {0x69a7, 9928}, + {0x69a8, 4079}, + {0x69a9, 9930}, + {0x69aa, 9944}, + {0x69ab, 4088}, + {0x69ac, 9923}, + {0x69ad, 4092}, + {0x69ae, 4082}, + {0x69af, 9932}, + {0x69b0, 9922}, + {0x69b1, 9916}, + {0x69b3, 9942}, + {0x69b4, 4089}, + {0x69b5, 9951}, + {0x69b6, 9917}, + {0x69b7, 4086}, + {0x69b9, 9938}, + {0x69bb, 4087}, + {0x69bc, 9924}, + {0x69bd, 9935}, + {0x69be, 9931}, + {0x69bf, 9933}, + {0x69c1, 4081}, + {0x69c2, 9950}, + {0x69c3, 4095}, + {0x69c4, 9934}, + {0x69c6, 9953}, + {0x69c9, 9918}, + {0x69ca, 9939}, + {0x69cb, 4084}, + {0x69cc, 4093}, + {0x69cd, 4091}, + {0x69ce, 9920}, + {0x69cf, 9941}, + {0x69d0, 4090}, + {0x69d3, 4083}, + {0x69d4, 9937}, + {0x69d9, 9947}, + {0x69e8, 4471}, + {0x69ed, 4482}, + {0x69f3, 4479}, + {0x69fd, 4475}, + {0x6a01, 4472}, + {0x6a02, 4480}, + {0x6a05, 4481}, + {0x6a0a, 4478}, + {0x6a11, 4483}, + {0x6a13, 4477}, + {0x6a19, 4474}, + {0x6a1e, 4473}, + {0x6a1f, 4470}, + {0x6a21, 4476}, + {0x6a23, 4469}, + {0x6a35, 4825}, + {0x6a38, 4814}, + {0x6a39, 4819}, + {0x6a3a, 4815}, + {0x6a3d, 4813}, + {0x6a44, 4820}, + {0x6a47, 4824}, + {0x6a48, 4827}, + {0x6a4b, 4823}, + {0x6a4e, 0}, + {0x6a58, 4818}, + {0x6a59, 4816}, + {0x6a5f, 4826}, + {0x6a61, 4822}, + {0x6a62, 4821}, + {0x6a6b, 4817}, + {0x6a7e, 5100}, + {0x6a80, 5093}, + {0x6a84, 5095}, + {0x6a90, 5102}, + {0x6a94, 5094}, + {0x6a97, 5101}, + {0x6a9c, 5097}, + {0x6aa0, 5103}, + {0x6aa2, 5096}, + {0x6aa3, 5099}, + {0x6aac, 5341}, + {0x6aae, 5346}, + {0x6aaf, 5347}, + {0x6ab3, 5340}, + {0x6ab7, 0}, + {0x6ab8, 5344}, + {0x6abb, 5343}, + {0x6ac2, 5345}, + {0x6ac3, 5342}, + {0x6ad3, 5513}, + {0x6ada, 5512}, + {0x6adb, 5098}, + {0x6add, 5511}, + {0x6ae5, 5510}, + {0x6aec, 5659}, + {0x6aef, 0}, + {0x6afa, 5752}, + {0x6afb, 5750}, + {0x6b04, 5751}, + {0x6b09, 0}, + {0x6b0a, 5830}, + {0x6b10, 5885}, + {0x6b12, 0}, + {0x6b16, 5955}, + {0x6b19, 0}, + {0x6b20, 734}, + {0x6b21, 995}, + {0x6b23, 1562}, + {0x6b25, 6601}, + {0x6b28, 6973}, + {0x6b2c, 7398}, + {0x6b2d, 7400}, + {0x6b2f, 7399}, + {0x6b31, 7401}, + {0x6b32, 2791}, + {0x6b33, 7996}, + {0x6b34, 7402}, + {0x6b36, 7995}, + {0x6b37, 7997}, + {0x6b38, 7998}, + {0x6b39, 8626}, + {0x6b3a, 3228}, + {0x6b3b, 8627}, + {0x6b3c, 8629}, + {0x6b3d, 3229}, + {0x6b3e, 3227}, + {0x6b3f, 8628}, + {0x6b41, 9287}, + {0x6b42, 9285}, + {0x6b43, 9284}, + {0x6b45, 9283}, + {0x6b46, 9282}, + {0x6b47, 3658}, + {0x6b48, 9286}, + {0x6b49, 4097}, + {0x6b4a, 9954}, + {0x6b4b, 9956}, + {0x6b4c, 4098}, + {0x6b4d, 9955}, + {0x6b4e, 4485}, + {0x6b50, 4484}, + {0x6b59, 4828}, + {0x6b5c, 5104}, + {0x6b5f, 5348}, + {0x6b61, 5831}, + {0x6b62, 735}, + {0x6b63, 845}, + {0x6b64, 996}, + {0x6b65, 1225}, + {0x6b66, 1563}, + {0x6b67, 1564}, + {0x6b6a, 1897}, + {0x6b6d, 7403}, + {0x6b72, 3659}, + {0x6b77, 4829}, + {0x6b78, 5349}, + {0x6b79, 736}, + {0x6b7b, 997}, + {0x6b7e, 6603}, + {0x6b7f, 1565}, + {0x6b80, 6602}, + {0x6b82, 6974}, + {0x6b83, 1898}, + {0x6b84, 6975}, + {0x6b86, 1899}, + {0x6b88, 7405}, + {0x6b89, 2304}, + {0x6b8a, 2303}, + {0x6b8c, 8003}, + {0x6b8d, 8001}, + {0x6b8e, 8002}, + {0x6b8f, 8000}, + {0x6b91, 7999}, + {0x6b94, 8630}, + {0x6b95, 8633}, + {0x6b96, 3231}, + {0x6b97, 8631}, + {0x6b98, 3230}, + {0x6b99, 8632}, + {0x6b9b, 9288}, + {0x6b9e, 9957}, + {0x6b9f, 9958}, + {0x6ba0, 9959}, + {0x6ba4, 4486}, + {0x6bab, 0}, + {0x6bae, 5105}, + {0x6baf, 5350}, + {0x6bb2, 5753}, + {0x6bb3, 6026}, + {0x6bb5, 1900}, + {0x6bb6, 6976}, + {0x6bb7, 2305}, + {0x6bba, 2792}, + {0x6bbc, 3232}, + {0x6bbd, 8634}, + {0x6bbf, 3661}, + {0x6bc0, 3660}, + {0x6bc3, 9960}, + {0x6bc4, 9961}, + {0x6bc5, 4487}, + {0x6bc6, 4488}, + {0x6bcb, 737}, + {0x6bcc, 6027}, + {0x6bcd, 846}, + {0x6bcf, 1226}, + {0x6bd0, 6317}, + {0x6bd2, 1901}, + {0x6bd3, 3662}, + {0x6bd4, 738}, + {0x6bd6, 6977}, + {0x6bd7, 1902}, + {0x6bd8, 6978}, + {0x6bda, 5106}, + {0x6bdb, 739}, + {0x6bde, 6604}, + {0x6be0, 6979}, + {0x6be2, 7410}, + {0x6be3, 7409}, + {0x6be4, 7407}, + {0x6be6, 7406}, + {0x6be7, 7411}, + {0x6be8, 7408}, + {0x6beb, 2793}, + {0x6bec, 2794}, + {0x6bef, 3233}, + {0x6bf0, 8635}, + {0x6bf2, 8636}, + {0x6bf3, 8637}, + {0x6bf7, 9292}, + {0x6bf8, 9293}, + {0x6bf9, 9291}, + {0x6bfb, 9289}, + {0x6bfc, 9290}, + {0x6bfd, 3663}, + {0x6bfe, 9962}, + {0x6c05, 4830}, + {0x6c08, 5107}, + {0x6c0f, 740}, + {0x6c10, 848}, + {0x6c11, 847}, + {0x6c13, 1566}, + {0x6c14, 6028}, + {0x6c15, 6058}, + {0x6c16, 998}, + {0x6c18, 6145}, + {0x6c19, 6318}, + {0x6c1a, 6319}, + {0x6c1b, 1567}, + {0x6c1d, 6605}, + {0x6c1f, 1903}, + {0x6c20, 6980}, + {0x6c21, 6981}, + {0x6c23, 2306}, + {0x6c24, 2310}, + {0x6c25, 7412}, + {0x6c26, 2309}, + {0x6c27, 2307}, + {0x6c28, 2308}, + {0x6c2a, 8004}, + {0x6c2b, 2795}, + {0x6c2c, 3236}, + {0x6c2e, 3234}, + {0x6c2f, 3235}, + {0x6c30, 8638}, + {0x6c33, 4099}, + {0x6c34, 741}, + {0x6c36, 6059}, + {0x6c38, 849}, + {0x6c3b, 6062}, + {0x6c3e, 852}, + {0x6c3f, 6061}, + {0x6c40, 851}, + {0x6c41, 850}, + {0x6c42, 1227}, + {0x6c43, 6060}, + {0x6c46, 6146}, + {0x6c4a, 6150}, + {0x6c4b, 6152}, + {0x6c4c, 6153}, + {0x6c4d, 1008}, + {0x6c4e, 1009}, + {0x6c4f, 6149}, + {0x6c50, 1004}, + {0x6c52, 6147}, + {0x6c54, 6151}, + {0x6c55, 1005}, + {0x6c57, 1000}, + {0x6c59, 1001}, + {0x6c5b, 1007}, + {0x6c5c, 6148}, + {0x6c5d, 999}, + {0x6c5e, 1228}, + {0x6c5f, 1002}, + {0x6c60, 1003}, + {0x6c61, 1006}, + {0x6c65, 6336}, + {0x6c66, 6334}, + {0x6c67, 6321}, + {0x6c68, 1240}, + {0x6c69, 6328}, + {0x6c6a, 1235}, + {0x6c6b, 6322}, + {0x6c6d, 6330}, + {0x6c6f, 6327}, + {0x6c70, 1238}, + {0x6c71, 6326}, + {0x6c72, 1245}, + {0x6c73, 6335}, + {0x6c74, 1247}, + {0x6c76, 1249}, + {0x6c78, 6320}, + {0x6c7a, 1236}, + {0x6c7b, 6337}, + {0x6c7d, 1243}, + {0x6c7e, 1246}, + {0x6c80, 6628}, + {0x6c81, 1230}, + {0x6c82, 1253}, + {0x6c83, 1244}, + {0x6c84, 6323}, + {0x6c85, 1233}, + {0x6c86, 1248}, + {0x6c87, 6331}, + {0x6c88, 1231}, + {0x6c89, 1232}, + {0x6c8a, 6626}, + {0x6c8b, 6324}, + {0x6c8c, 1239}, + {0x6c8d, 1250}, + {0x6c8e, 6338}, + {0x6c8f, 6325}, + {0x6c90, 1237}, + {0x6c92, 1242}, + {0x6c93, 6606}, + {0x6c94, 1251}, + {0x6c95, 6332}, + {0x6c96, 1241}, + {0x6c98, 1252}, + {0x6c99, 1229}, + {0x6c9a, 6329}, + {0x6c9b, 1234}, + {0x6c9c, 6333}, + {0x6c9d, 6627}, + {0x6cab, 1579}, + {0x6cac, 1595}, + {0x6cad, 6613}, + {0x6cae, 1586}, + {0x6cb0, 6634}, + {0x6cb1, 1571}, + {0x6cb3, 1574}, + {0x6cb4, 6625}, + {0x6cb6, 6611}, + {0x6cb7, 6615}, + {0x6cb8, 1582}, + {0x6cb9, 1584}, + {0x6cba, 6618}, + {0x6cbb, 1591}, + {0x6cbc, 1577}, + {0x6cbd, 1575}, + {0x6cbe, 1576}, + {0x6cbf, 1590}, + {0x6cc0, 6630}, + {0x6cc1, 1585}, + {0x6cc2, 6617}, + {0x6cc3, 6619}, + {0x6cc4, 1583}, + {0x6cc5, 1588}, + {0x6cc6, 6620}, + {0x6cc7, 6633}, + {0x6cc9, 1904}, + {0x6cca, 1594}, + {0x6ccc, 1572}, + {0x6ccd, 6632}, + {0x6ccf, 6636}, + {0x6cd0, 6616}, + {0x6cd1, 6638}, + {0x6cd2, 6623}, + {0x6cd3, 1581}, + {0x6cd4, 6612}, + {0x6cd5, 1580}, + {0x6cd6, 1598}, + {0x6cd7, 1587}, + {0x6cd9, 6610}, + {0x6cda, 6990}, + {0x6cdb, 1593}, + {0x6cdc, 1597}, + {0x6cdd, 6624}, + {0x6cde, 6629}, + {0x6ce0, 1599}, + {0x6ce1, 1592}, + {0x6ce2, 1578}, + {0x6ce3, 1568}, + {0x6ce5, 1573}, + {0x6ce7, 6614}, + {0x6ce8, 1569}, + {0x6ce9, 6637}, + {0x6ceb, 6608}, + {0x6cec, 6607}, + {0x6ced, 6621}, + {0x6cee, 6609}, + {0x6cef, 1596}, + {0x6cf0, 2311}, + {0x6cf1, 1589}, + {0x6cf2, 6622}, + {0x6cf3, 1570}, + {0x6cf5, 1919}, + {0x6cf9, 6635}, + {0x6d00, 6997}, + {0x6d01, 7000}, + {0x6d03, 7003}, + {0x6d04, 6992}, + {0x6d07, 7006}, + {0x6d08, 7009}, + {0x6d09, 7011}, + {0x6d0a, 6989}, + {0x6d0b, 1905}, + {0x6d0c, 1910}, + {0x6d0d, 7417}, + {0x6d0e, 1926}, + {0x6d0f, 7004}, + {0x6d10, 7012}, + {0x6d11, 6996}, + {0x6d12, 6988}, + {0x6d16, 7444}, + {0x6d17, 1913}, + {0x6d18, 7001}, + {0x6d19, 6993}, + {0x6d1a, 6995}, + {0x6d1b, 1918}, + {0x6d1d, 6998}, + {0x6d1e, 1912}, + {0x6d1f, 6985}, + {0x6d20, 7007}, + {0x6d22, 7010}, + {0x6d25, 1909}, + {0x6d27, 1921}, + {0x6d28, 6982}, + {0x6d29, 1923}, + {0x6d2a, 1907}, + {0x6d2b, 1927}, + {0x6d2c, 7008}, + {0x6d2d, 6984}, + {0x6d2e, 1924}, + {0x6d2f, 7438}, + {0x6d30, 6631}, + {0x6d31, 1911}, + {0x6d32, 1906}, + {0x6d33, 6991}, + {0x6d34, 6983}, + {0x6d35, 1925}, + {0x6d36, 1917}, + {0x6d37, 7002}, + {0x6d38, 1922}, + {0x6d39, 1920}, + {0x6d3a, 6994}, + {0x6d3b, 1914}, + {0x6d3c, 6986}, + {0x6d3d, 1915}, + {0x6d3e, 1916}, + {0x6d3f, 6987}, + {0x6d40, 7005}, + {0x6d41, 1908}, + {0x6d42, 6999}, + {0x6d58, 7420}, + {0x6d59, 2319}, + {0x6d5a, 2324}, + {0x6d5e, 7429}, + {0x6d5f, 7435}, + {0x6d60, 7431}, + {0x6d61, 7418}, + {0x6d62, 7421}, + {0x6d63, 7414}, + {0x6d64, 7415}, + {0x6d65, 2331}, + {0x6d66, 2316}, + {0x6d67, 7430}, + {0x6d68, 7439}, + {0x6d69, 2326}, + {0x6d6a, 2312}, + {0x6d6c, 2321}, + {0x6d6d, 7422}, + {0x6d6e, 2323}, + {0x6d6f, 7423}, + {0x6d70, 7433}, + {0x6d74, 2325}, + {0x6d75, 7448}, + {0x6d76, 7416}, + {0x6d77, 2318}, + {0x6d78, 2317}, + {0x6d79, 2329}, + {0x6d7a, 7413}, + {0x6d7b, 7446}, + {0x6d7c, 7434}, + {0x6d7d, 7447}, + {0x6d7e, 7441}, + {0x6d7f, 7427}, + {0x6d80, 7442}, + {0x6d82, 7436}, + {0x6d83, 7445}, + {0x6d84, 7443}, + {0x6d85, 2330}, + {0x6d86, 7428}, + {0x6d87, 2315}, + {0x6d88, 2314}, + {0x6d89, 2322}, + {0x6d8a, 2328}, + {0x6d8b, 7440}, + {0x6d8c, 2327}, + {0x6d8d, 7425}, + {0x6d8e, 2796}, + {0x6d90, 7449}, + {0x6d91, 7424}, + {0x6d92, 7419}, + {0x6d93, 2320}, + {0x6d94, 2332}, + {0x6d95, 2313}, + {0x6d97, 7432}, + {0x6d98, 7437}, + {0x6daa, 2830}, + {0x6dab, 8006}, + {0x6dac, 8010}, + {0x6dae, 2811}, + {0x6daf, 2809}, + {0x6db2, 2800}, + {0x6db3, 8008}, + {0x6db4, 8007}, + {0x6db5, 2820}, + {0x6db7, 8013}, + {0x6db8, 2814}, + {0x6dba, 8031}, + {0x6dbb, 8043}, + {0x6dbc, 2797}, + {0x6dbd, 8028}, + {0x6dbe, 8021}, + {0x6dbf, 2832}, + {0x6dc0, 8005}, + {0x6dc2, 8033}, + {0x6dc4, 2829}, + {0x6dc5, 2817}, + {0x6dc6, 2828}, + {0x6dc7, 2807}, + {0x6dc8, 8017}, + {0x6dc9, 8035}, + {0x6dca, 8027}, + {0x6dcb, 2808}, + {0x6dcc, 2802}, + {0x6dcd, 8041}, + {0x6dcf, 8034}, + {0x6dd0, 8036}, + {0x6dd1, 2810}, + {0x6dd2, 2818}, + {0x6dd3, 8038}, + {0x6dd4, 8015}, + {0x6dd5, 8032}, + {0x6dd6, 8020}, + {0x6dd7, 8040}, + {0x6dd8, 2823}, + {0x6dd9, 2799}, + {0x6dda, 2821}, + {0x6ddb, 8025}, + {0x6ddc, 8023}, + {0x6ddd, 8024}, + {0x6dde, 2812}, + {0x6ddf, 8019}, + {0x6de0, 8018}, + {0x6de1, 2801}, + {0x6de2, 8012}, + {0x6de3, 8042}, + {0x6de4, 2803}, + {0x6de5, 8022}, + {0x6de6, 2833}, + {0x6de8, 2827}, + {0x6de9, 8011}, + {0x6dea, 2824}, + {0x6deb, 2822}, + {0x6dec, 2831}, + {0x6ded, 8029}, + {0x6dee, 2826}, + {0x6def, 7426}, + {0x6df0, 8030}, + {0x6df1, 2825}, + {0x6df2, 8037}, + {0x6df3, 2798}, + {0x6df4, 8026}, + {0x6df5, 2816}, + {0x6df6, 8014}, + {0x6df7, 2815}, + {0x6df9, 2813}, + {0x6dfa, 2805}, + {0x6dfb, 2804}, + {0x6dfc, 8639}, + {0x6dfd, 8039}, + {0x6e00, 8016}, + {0x6e03, 8660}, + {0x6e05, 2806}, + {0x6e19, 3265}, + {0x6e1a, 2819}, + {0x6e1b, 3247}, + {0x6e1c, 8654}, + {0x6e1d, 3261}, + {0x6e1f, 8642}, + {0x6e20, 3244}, + {0x6e21, 3240}, + {0x6e22, 8672}, + {0x6e23, 3246}, + {0x6e24, 3250}, + {0x6e25, 3245}, + {0x6e26, 3254}, + {0x6e27, 8676}, + {0x6e28, 8667}, + {0x6e2b, 8649}, + {0x6e2c, 3259}, + {0x6e2d, 3253}, + {0x6e2e, 8661}, + {0x6e2f, 3237}, + {0x6e30, 8673}, + {0x6e31, 8666}, + {0x6e32, 3241}, + {0x6e33, 8655}, + {0x6e34, 3256}, + {0x6e35, 8684}, + {0x6e36, 8685}, + {0x6e38, 3238}, + {0x6e39, 8671}, + {0x6e3a, 3258}, + {0x6e3b, 8659}, + {0x6e3c, 8645}, + {0x6e3d, 8646}, + {0x6e3e, 3262}, + {0x6e3f, 8650}, + {0x6e40, 8657}, + {0x6e41, 8651}, + {0x6e43, 3260}, + {0x6e44, 3268}, + {0x6e45, 8647}, + {0x6e46, 8640}, + {0x6e47, 8641}, + {0x6e49, 8643}, + {0x6e4a, 3243}, + {0x6e4b, 8656}, + {0x6e4d, 3257}, + {0x6e4e, 3266}, + {0x6e51, 8658}, + {0x6e52, 8682}, + {0x6e53, 8674}, + {0x6e54, 3239}, + {0x6e55, 8680}, + {0x6e56, 3251}, + {0x6e58, 3249}, + {0x6e5a, 8686}, + {0x6e5b, 3248}, + {0x6e5c, 8664}, + {0x6e5d, 8652}, + {0x6e5e, 8662}, + {0x6e5f, 3271}, + {0x6e60, 8668}, + {0x6e61, 8665}, + {0x6e62, 8648}, + {0x6e63, 3267}, + {0x6e64, 8678}, + {0x6e65, 8675}, + {0x6e66, 8683}, + {0x6e67, 3242}, + {0x6e68, 8663}, + {0x6e69, 3270}, + {0x6e6b, 8670}, + {0x6e6e, 3252}, + {0x6e6f, 3255}, + {0x6e71, 8669}, + {0x6e72, 3269}, + {0x6e73, 8653}, + {0x6e74, 8009}, + {0x6e77, 8679}, + {0x6e78, 8677}, + {0x6e79, 8681}, + {0x6e88, 8644}, + {0x6e89, 3264}, + {0x6e8d, 9324}, + {0x6e8e, 9323}, + {0x6e8f, 9297}, + {0x6e90, 3669}, + {0x6e92, 9322}, + {0x6e93, 9300}, + {0x6e94, 9301}, + {0x6e96, 3679}, + {0x6e97, 9331}, + {0x6e98, 3674}, + {0x6e99, 9321}, + {0x6e9b, 9294}, + {0x6e9c, 3680}, + {0x6e9d, 3670}, + {0x6e9e, 9309}, + {0x6e9f, 9299}, + {0x6ea0, 9302}, + {0x6ea1, 9326}, + {0x6ea2, 3664}, + {0x6ea3, 9333}, + {0x6ea4, 9325}, + {0x6ea5, 3673}, + {0x6ea6, 9314}, + {0x6ea7, 3684}, + {0x6eaa, 3683}, + {0x6eab, 3677}, + {0x6eae, 9332}, + {0x6eaf, 3665}, + {0x6eb0, 9312}, + {0x6eb1, 9303}, + {0x6eb2, 9316}, + {0x6eb3, 9328}, + {0x6eb4, 3685}, + {0x6eb6, 3667}, + {0x6eb7, 9311}, + {0x6eb9, 9304}, + {0x6eba, 3676}, + {0x6ebc, 3675}, + {0x6ebd, 9307}, + {0x6ebe, 9317}, + {0x6ebf, 9327}, + {0x6ec0, 9298}, + {0x6ec1, 9308}, + {0x6ec2, 3668}, + {0x6ec3, 9318}, + {0x6ec4, 3681}, + {0x6ec5, 3672}, + {0x6ec6, 9305}, + {0x6ec7, 3671}, + {0x6ec8, 9296}, + {0x6ec9, 9310}, + {0x6eca, 9330}, + {0x6ecb, 3263}, + {0x6ecc, 4127}, + {0x6ecd, 9313}, + {0x6ece, 9963}, + {0x6ecf, 9315}, + {0x6ed0, 9329}, + {0x6ed1, 3678}, + {0x6ed2, 9306}, + {0x6ed3, 3666}, + {0x6ed4, 3682}, + {0x6ed5, 4506}, + {0x6ed6, 9295}, + {0x6ed8, 9320}, + {0x6edc, 9319}, + {0x6ee9, 0}, + {0x6eeb, 9991}, + {0x6eec, 4124}, + {0x6eed, 9980}, + {0x6eee, 9985}, + {0x6eef, 4113}, + {0x6ef1, 9965}, + {0x6ef2, 4126}, + {0x6ef4, 4104}, + {0x6ef5, 9964}, + {0x6ef6, 9997}, + {0x6ef7, 4128}, + {0x6ef8, 9968}, + {0x6ef9, 9984}, + {0x6efb, 9970}, + {0x6efd, 9996}, + {0x6efe, 4102}, + {0x6eff, 4112}, + {0x6f01, 4125}, + {0x6f02, 4110}, + {0x6f03, 9966}, + {0x6f05, 9995}, + {0x6f06, 4114}, + {0x6f07, 9992}, + {0x6f09, 9972}, + {0x6f0a, 9981}, + {0x6f0e, 9993}, + {0x6f0f, 4109}, + {0x6f12, 9979}, + {0x6f13, 4103}, + {0x6f14, 4101}, + {0x6f15, 4119}, + {0x6f18, 9977}, + {0x6f19, 9974}, + {0x6f1a, 9975}, + {0x6f1c, 9999}, + {0x6f20, 4107}, + {0x6f22, 4111}, + {0x6f23, 4118}, + {0x6f25, 9967}, + {0x6f27, 9976}, + {0x6f29, 4105}, + {0x6f2a, 4123}, + {0x6f2b, 4120}, + {0x6f2c, 4108}, + {0x6f2d, 9986}, + {0x6f2e, 9971}, + {0x6f2f, 4121}, + {0x6f30, 9988}, + {0x6f31, 4115}, + {0x6f32, 4117}, + {0x6f33, 4100}, + {0x6f35, 9990}, + {0x6f36, 9982}, + {0x6f37, 9969}, + {0x6f38, 4116}, + {0x6f39, 9998}, + {0x6f3b, 9978}, + {0x6f3c, 9989}, + {0x6f3e, 4106}, + {0x6f3f, 4489}, + {0x6f40, 9987}, + {0x6f43, 9994}, + {0x6f4e, 9973}, + {0x6f51, 4492}, + {0x6f54, 4494}, + {0x6f58, 4505}, + {0x6f5b, 4497}, + {0x6f5f, 4509}, + {0x6f60, 4508}, + {0x6f64, 4503}, + {0x6f66, 4493}, + {0x6f6d, 4496}, + {0x6f6e, 4499}, + {0x6f6f, 4507}, + {0x6f70, 4502}, + {0x6f73, 9983}, + {0x6f78, 4498}, + {0x6f7a, 4501}, + {0x6f7c, 4490}, + {0x6f80, 5116}, + {0x6f84, 4491}, + {0x6f86, 4495}, + {0x6f88, 4122}, + {0x6f8e, 4500}, + {0x6f97, 4504}, + {0x6fa0, 4843}, + {0x6fa1, 4833}, + {0x6fa4, 4835}, + {0x6fa6, 4842}, + {0x6fa7, 4837}, + {0x6fb1, 4832}, + {0x6fb3, 4838}, + {0x6fb4, 4844}, + {0x6fb6, 4841}, + {0x6fb9, 4840}, + {0x6fc0, 4839}, + {0x6fc1, 4836}, + {0x6fc2, 4831}, + {0x6fc3, 4834}, + {0x6fd5, 5120}, + {0x6fd8, 5108}, + {0x6fdb, 5112}, + {0x6fdf, 5110}, + {0x6fe0, 5111}, + {0x6fe1, 5118}, + {0x6fe4, 5113}, + {0x6fe9, 5119}, + {0x6feb, 5114}, + {0x6fec, 5117}, + {0x6fee, 5121}, + {0x6fef, 5115}, + {0x6ff0, 5122}, + {0x6ff1, 5109}, + {0x6ffa, 5355}, + {0x6ffe, 5353}, + {0x7006, 5354}, + {0x7009, 5351}, + {0x700b, 5352}, + {0x700d, 0}, + {0x700f, 5357}, + {0x7011, 5356}, + {0x7015, 5519}, + {0x7018, 5520}, + {0x701a, 5517}, + {0x701b, 5514}, + {0x701d, 5518}, + {0x701f, 5515}, + {0x7022, 0}, + {0x7023, 1}, + {0x7028, 5516}, + {0x7030, 5661}, + {0x7032, 5662}, + {0x703e, 5660}, + {0x7044, 0}, + {0x7046, 0}, + {0x7049, 0}, + {0x704c, 5754}, + {0x7051, 5832}, + {0x7056, 0}, + {0x7057, 1}, + {0x7058, 5833}, + {0x705e, 5922}, + {0x7063, 5956}, + {0x7064, 5970}, + {0x706a, 0}, + {0x706b, 742}, + {0x7070, 1010}, + {0x7071, 6154}, + {0x7074, 6339}, + {0x7076, 1254}, + {0x7078, 1257}, + {0x707a, 6340}, + {0x707c, 1255}, + {0x707d, 1256}, + {0x7082, 6647}, + {0x7083, 6649}, + {0x7084, 6644}, + {0x7085, 6641}, + {0x7086, 6643}, + {0x708a, 1603}, + {0x708e, 1601}, + {0x7091, 6645}, + {0x7092, 1602}, + {0x7093, 6642}, + {0x7094, 6639}, + {0x7095, 1600}, + {0x7096, 6646}, + {0x7098, 6640}, + {0x7099, 1604}, + {0x709a, 6648}, + {0x709f, 7014}, + {0x70a1, 7018}, + {0x70a4, 1936}, + {0x70a9, 7021}, + {0x70ab, 1928}, + {0x70ac, 1931}, + {0x70ad, 1933}, + {0x70ae, 1935}, + {0x70af, 1932}, + {0x70b0, 7017}, + {0x70b1, 7016}, + {0x70b3, 1930}, + {0x70b4, 7019}, + {0x70b5, 7020}, + {0x70b7, 7013}, + {0x70b8, 1934}, + {0x70ba, 1929}, + {0x70be, 7015}, + {0x70c5, 7463}, + {0x70c6, 7464}, + {0x70c7, 7465}, + {0x70c8, 2337}, + {0x70ca, 2333}, + {0x70cb, 7454}, + {0x70cd, 7462}, + {0x70ce, 7467}, + {0x70cf, 2338}, + {0x70d1, 7452}, + {0x70d2, 7458}, + {0x70d3, 7451}, + {0x70d4, 7461}, + {0x70d6, 0}, + {0x70d7, 7457}, + {0x70d8, 2334}, + {0x70d9, 2336}, + {0x70da, 7466}, + {0x70dc, 7450}, + {0x70dd, 7453}, + {0x70de, 7459}, + {0x70e0, 7460}, + {0x70e1, 7468}, + {0x70e2, 7456}, + {0x70e4, 2335}, + {0x70ef, 2838}, + {0x70f0, 8050}, + {0x70f3, 8052}, + {0x70f4, 8048}, + {0x70f6, 8060}, + {0x70f7, 8046}, + {0x70f8, 8059}, + {0x70f9, 2834}, + {0x70fa, 8044}, + {0x70fb, 8690}, + {0x70fc, 8054}, + {0x70fd, 2837}, + {0x70ff, 8055}, + {0x7100, 8058}, + {0x7102, 8062}, + {0x7104, 8051}, + {0x7106, 8056}, + {0x7109, 2835}, + {0x710a, 2836}, + {0x710b, 8061}, + {0x710c, 8049}, + {0x710d, 8045}, + {0x710e, 8063}, + {0x7110, 8053}, + {0x7113, 8057}, + {0x7117, 8047}, + {0x7119, 3272}, + {0x711a, 3273}, + {0x711b, 8700}, + {0x711c, 3279}, + {0x711e, 8688}, + {0x711f, 8697}, + {0x7120, 8687}, + {0x7121, 3276}, + {0x7122, 8695}, + {0x7123, 8693}, + {0x7125, 8694}, + {0x7126, 3274}, + {0x7128, 8698}, + {0x712e, 8691}, + {0x712f, 8689}, + {0x7130, 3275}, + {0x7131, 8692}, + {0x7132, 8696}, + {0x7136, 3277}, + {0x713a, 8699}, + {0x7141, 9339}, + {0x7142, 9346}, + {0x7143, 9348}, + {0x7144, 9354}, + {0x7146, 3698}, + {0x7147, 9334}, + {0x7149, 3690}, + {0x714b, 9349}, + {0x714c, 3695}, + {0x714d, 9355}, + {0x714e, 3686}, + {0x7150, 9352}, + {0x7152, 9336}, + {0x7153, 9353}, + {0x7154, 9335}, + {0x7156, 3700}, + {0x7158, 9347}, + {0x7159, 3687}, + {0x715a, 9356}, + {0x715c, 3692}, + {0x715d, 9340}, + {0x715e, 3697}, + {0x715f, 9351}, + {0x7160, 9338}, + {0x7161, 9345}, + {0x7162, 9341}, + {0x7163, 9337}, + {0x7164, 3689}, + {0x7165, 3696}, + {0x7166, 3694}, + {0x7167, 3691}, + {0x7168, 3699}, + {0x7169, 3688}, + {0x716a, 9344}, + {0x716c, 3693}, + {0x716e, 3278}, + {0x7170, 9350}, + {0x7172, 9342}, + {0x7178, 9343}, + {0x717d, 4131}, + {0x7184, 4133}, + {0x718a, 4132}, + {0x7192, 4134}, + {0x7194, 4129}, + {0x7199, 4130}, + {0x719f, 4510}, + {0x71a8, 4513}, + {0x71ac, 4511}, + {0x71b1, 4512}, + {0x71b9, 4851}, + {0x71be, 4845}, + {0x71c1, 0}, + {0x71c3, 4855}, + {0x71c4, 4856}, + {0x71c8, 4849}, + {0x71c9, 4846}, + {0x71ce, 4852}, + {0x71d0, 4847}, + {0x71d2, 4848}, + {0x71d5, 4850}, + {0x71d9, 4853}, + {0x71db, 0}, + {0x71dc, 4854}, + {0x71df, 5124}, + {0x71e0, 5131}, + {0x71e5, 5127}, + {0x71e6, 5126}, + {0x71e7, 5123}, + {0x71ec, 5129}, + {0x71ed, 5128}, + {0x71ee, 5125}, + {0x71f4, 5130}, + {0x71f8, 5361}, + {0x71fb, 5358}, + {0x71fc, 5359}, + {0x71fe, 5360}, + {0x7206, 5521}, + {0x720d, 5522}, + {0x7210, 5663}, + {0x7214, 0}, + {0x721b, 5755}, + {0x721f, 0}, + {0x7228, 5990}, + {0x722a, 743}, + {0x722c, 1605}, + {0x722d, 1606}, + {0x7230, 1937}, + {0x7235, 5132}, + {0x7236, 744}, + {0x7238, 1607}, + {0x7239, 2339}, + {0x723a, 3701}, + {0x723b, 745}, + {0x723d, 2839}, + {0x723e, 4135}, + {0x723f, 6029}, + {0x7241, 7022}, + {0x7242, 7469}, + {0x7246, 5133}, + {0x7247, 746}, + {0x7248, 1608}, + {0x7249, 7023}, + {0x724a, 7024}, + {0x724b, 8701}, + {0x724c, 3280}, + {0x724f, 9357}, + {0x7252, 3702}, + {0x7256, 4514}, + {0x7258, 5523}, + {0x7259, 747}, + {0x725a, 8702}, + {0x725b, 748}, + {0x725d, 1012}, + {0x725e, 6155}, + {0x725f, 1011}, + {0x7260, 1260}, + {0x7261, 1259}, + {0x7262, 1258}, + {0x7263, 6341}, + {0x7267, 1609}, + {0x7269, 1610}, + {0x726a, 6650}, + {0x726c, 7025}, + {0x726e, 7028}, + {0x726f, 1939}, + {0x7270, 7026}, + {0x7272, 1938}, + {0x7273, 7027}, + {0x7274, 1940}, + {0x7276, 7472}, + {0x7277, 7471}, + {0x7278, 7470}, + {0x7279, 2340}, + {0x727b, 8065}, + {0x727c, 8066}, + {0x727d, 2840}, + {0x727e, 8064}, + {0x727f, 8067}, + {0x7280, 3282}, + {0x7281, 2841}, + {0x7284, 3281}, + {0x7285, 8706}, + {0x7286, 8705}, + {0x7288, 8703}, + {0x7289, 8704}, + {0x728b, 8707}, + {0x728c, 9359}, + {0x728d, 9358}, + {0x728e, 9362}, + {0x7290, 9361}, + {0x7291, 9360}, + {0x7292, 4136}, + {0x7296, 4137}, + {0x729b, 4515}, + {0x729e, 0}, + {0x72a2, 5524}, + {0x72a6, 0}, + {0x72a7, 5756}, + {0x72ac, 749}, + {0x72ae, 6063}, + {0x72af, 853}, + {0x72b0, 6064}, + {0x72b4, 6156}, + {0x72b5, 6157}, + {0x72ba, 6347}, + {0x72bd, 6343}, + {0x72bf, 6342}, + {0x72c0, 1611}, + {0x72c1, 6346}, + {0x72c2, 1262}, + {0x72c3, 6344}, + {0x72c4, 1261}, + {0x72c5, 6348}, + {0x72c6, 6345}, + {0x72c9, 6654}, + {0x72ca, 7029}, + {0x72cb, 6652}, + {0x72cc, 6659}, + {0x72ce, 1612}, + {0x72d0, 1615}, + {0x72d1, 6660}, + {0x72d2, 6656}, + {0x72d4, 6657}, + {0x72d6, 6651}, + {0x72d7, 1614}, + {0x72d8, 6653}, + {0x72d9, 1613}, + {0x72da, 6658}, + {0x72dc, 6655}, + {0x72df, 7033}, + {0x72e0, 1942}, + {0x72e1, 1943}, + {0x72e3, 7036}, + {0x72e4, 7030}, + {0x72e6, 7035}, + {0x72e8, 7031}, + {0x72e9, 1941}, + {0x72ea, 7034}, + {0x72eb, 7032}, + {0x72f3, 7478}, + {0x72f4, 7475}, + {0x72f6, 7477}, + {0x72f7, 2345}, + {0x72f8, 2344}, + {0x72f9, 2342}, + {0x72fa, 7474}, + {0x72fb, 7479}, + {0x72fc, 2341}, + {0x72fd, 2343}, + {0x72fe, 7476}, + {0x72ff, 8075}, + {0x7300, 7473}, + {0x7301, 7480}, + {0x7307, 8070}, + {0x7308, 8074}, + {0x730a, 8073}, + {0x730b, 8709}, + {0x730c, 8720}, + {0x730f, 8076}, + {0x7311, 8071}, + {0x7312, 8708}, + {0x7313, 2845}, + {0x7316, 2844}, + {0x7317, 8069}, + {0x7318, 8072}, + {0x7319, 2846}, + {0x731b, 2843}, + {0x731c, 2842}, + {0x731d, 8068}, + {0x731e, 8077}, + {0x7322, 8711}, + {0x7323, 8718}, + {0x7325, 3284}, + {0x7326, 8717}, + {0x7327, 8714}, + {0x7329, 3286}, + {0x732d, 8716}, + {0x7330, 8710}, + {0x7331, 8712}, + {0x7332, 8715}, + {0x7333, 8713}, + {0x7334, 3285}, + {0x7335, 8719}, + {0x7336, 3283}, + {0x7337, 3703}, + {0x733a, 9366}, + {0x733b, 9365}, + {0x733c, 9363}, + {0x733e, 3706}, + {0x733f, 3705}, + {0x7340, 9367}, + {0x7342, 9364}, + {0x7344, 4138}, + {0x7345, 3704}, + {0x7349, 9369}, + {0x734a, 9368}, + {0x734e, 4516}, + {0x7350, 4139}, + {0x7357, 4517}, + {0x735f, 0}, + {0x7360, 1}, + {0x7367, 0}, + {0x7368, 4857}, + {0x736f, 0}, + {0x7370, 5134}, + {0x7372, 5135}, + {0x7375, 5363}, + {0x7377, 5362}, + {0x7378, 5525}, + {0x737a, 5526}, + {0x737b, 5664}, + {0x7380, 5834}, + {0x7384, 854}, + {0x7385, 7037}, + {0x7386, 2346}, + {0x7387, 2847}, + {0x7388, 8078}, + {0x7389, 855}, + {0x738a, 6065}, + {0x738b, 750}, + {0x738e, 6158}, + {0x7392, 6353}, + {0x7393, 6351}, + {0x7394, 6352}, + {0x7395, 6349}, + {0x7396, 1263}, + {0x7397, 6350}, + {0x739d, 6668}, + {0x739f, 1618}, + {0x73a0, 6666}, + {0x73a1, 6662}, + {0x73a2, 6665}, + {0x73a4, 6661}, + {0x73a5, 1620}, + {0x73a6, 6664}, + {0x73a8, 1617}, + {0x73a9, 1616}, + {0x73ab, 1619}, + {0x73ac, 6667}, + {0x73ad, 6663}, + {0x73b2, 1947}, + {0x73b3, 1950}, + {0x73b4, 7045}, + {0x73b5, 7044}, + {0x73b6, 7043}, + {0x73b7, 1944}, + {0x73b8, 7052}, + {0x73b9, 7042}, + {0x73bb, 1946}, + {0x73bc, 7485}, + {0x73be, 7049}, + {0x73bf, 7047}, + {0x73c0, 1949}, + {0x73c2, 7039}, + {0x73c3, 7050}, + {0x73c5, 7041}, + {0x73c6, 7051}, + {0x73c7, 7048}, + {0x73c8, 7040}, + {0x73ca, 1945}, + {0x73cb, 7053}, + {0x73cc, 7038}, + {0x73cd, 1948}, + {0x73d2, 7490}, + {0x73d3, 7481}, + {0x73d4, 7492}, + {0x73d6, 7484}, + {0x73d7, 7495}, + {0x73d8, 7496}, + {0x73d9, 7482}, + {0x73da, 7494}, + {0x73db, 7491}, + {0x73dc, 7489}, + {0x73dd, 7493}, + {0x73de, 2352}, + {0x73e0, 2350}, + {0x73e3, 7487}, + {0x73e5, 7483}, + {0x73e7, 7486}, + {0x73e8, 7497}, + {0x73e9, 7488}, + {0x73ea, 2351}, + {0x73eb, 7046}, + {0x73ed, 2347}, + {0x73ee, 2349}, + {0x73f4, 8092}, + {0x73f5, 8081}, + {0x73f6, 8079}, + {0x73f8, 8080}, + {0x73fa, 8087}, + {0x73fc, 8088}, + {0x73fd, 8084}, + {0x73fe, 2852}, + {0x73ff, 8089}, + {0x7400, 8086}, + {0x7401, 8083}, + {0x7403, 2850}, + {0x7404, 8082}, + {0x7405, 2848}, + {0x7406, 2851}, + {0x7407, 8085}, + {0x7408, 8093}, + {0x7409, 2348}, + {0x740a, 2849}, + {0x740b, 8091}, + {0x740c, 8090}, + {0x740d, 2853}, + {0x7416, 8725}, + {0x741a, 8726}, + {0x741b, 3296}, + {0x741d, 8732}, + {0x741f, 0}, + {0x7420, 8734}, + {0x7421, 8727}, + {0x7422, 3290}, + {0x7423, 8731}, + {0x7424, 8730}, + {0x7425, 3291}, + {0x7426, 3297}, + {0x7428, 3298}, + {0x7429, 8733}, + {0x742a, 3288}, + {0x742b, 8724}, + {0x742c, 8722}, + {0x742d, 8728}, + {0x742e, 8721}, + {0x742f, 3295}, + {0x7430, 8723}, + {0x7431, 8729}, + {0x7432, 8735}, + {0x7433, 3289}, + {0x7434, 3294}, + {0x7435, 3292}, + {0x7436, 3293}, + {0x743a, 3287}, + {0x743f, 3713}, + {0x7440, 9376}, + {0x7441, 3712}, + {0x7442, 9380}, + {0x7444, 9370}, + {0x7446, 9381}, + {0x744a, 9371}, + {0x744b, 9372}, + {0x744d, 9382}, + {0x744e, 9379}, + {0x744f, 9377}, + {0x7450, 9378}, + {0x7451, 9374}, + {0x7452, 9373}, + {0x7454, 9383}, + {0x7455, 3709}, + {0x7457, 9375}, + {0x7459, 3714}, + {0x745a, 3708}, + {0x745b, 3715}, + {0x745c, 3716}, + {0x745e, 3711}, + {0x745f, 3710}, + {0x7463, 4141}, + {0x7464, 4140}, + {0x7469, 4518}, + {0x746a, 4142}, + {0x746d, 4144}, + {0x746f, 3707}, + {0x7470, 4143}, + {0x747e, 4521}, + {0x7480, 4522}, + {0x7483, 4520}, + {0x748a, 0}, + {0x748b, 4519}, + {0x7498, 4860}, + {0x749c, 4858}, + {0x749e, 4862}, + {0x749f, 4861}, + {0x74a3, 4859}, + {0x74a6, 5138}, + {0x74a7, 5364}, + {0x74a8, 5139}, + {0x74a9, 5136}, + {0x74b0, 5137}, + {0x74bd, 5527}, + {0x74bf, 5365}, + {0x74ca, 5528}, + {0x74cf, 5665}, + {0x74d4, 5758}, + {0x74d6, 5757}, + {0x74da, 5886}, + {0x74dc, 856}, + {0x74dd, 6669}, + {0x74de, 7498}, + {0x74df, 7499}, + {0x74e0, 2854}, + {0x74e1, 9384}, + {0x74e2, 4863}, + {0x74e3, 5529}, + {0x74e4, 5835}, + {0x74e6, 857}, + {0x74e8, 6670}, + {0x74e9, 288}, + {0x74ec, 7054}, + {0x74ee, 7055}, + {0x74f4, 7500}, + {0x74f5, 7501}, + {0x74f6, 2855}, + {0x74f7, 2856}, + {0x74fb, 8736}, + {0x74fd, 9387}, + {0x74fe, 9386}, + {0x74ff, 9385}, + {0x7503, 0}, + {0x7504, 4145}, + {0x750c, 4864}, + {0x750d, 4865}, + {0x7511, 0}, + {0x7512, 1}, + {0x7515, 5366}, + {0x7518, 858}, + {0x751a, 1951}, + {0x751c, 2857}, + {0x751d, 9388}, + {0x751f, 859}, + {0x7521, 7502}, + {0x7522, 2858}, + {0x7525, 3299}, + {0x7526, 3300}, + {0x7528, 860}, + {0x7529, 861}, + {0x752a, 6159}, + {0x752b, 1265}, + {0x752c, 1264}, + {0x752d, 1952}, + {0x752e, 7056}, + {0x752f, 8737}, + {0x7530, 862}, + {0x7531, 863}, + {0x7532, 864}, + {0x7533, 865}, + {0x7537, 1266}, + {0x7538, 1267}, + {0x7539, 6355}, + {0x753a, 6354}, + {0x753d, 1621}, + {0x753e, 6673}, + {0x753f, 6671}, + {0x7540, 6672}, + {0x7547, 7057}, + {0x7548, 7058}, + {0x754b, 1956}, + {0x754c, 1954}, + {0x754e, 1955}, + {0x754f, 1953}, + {0x7554, 2353}, + {0x7559, 2357}, + {0x755a, 2356}, + {0x755b, 7503}, + {0x755c, 2355}, + {0x755d, 2354}, + {0x755f, 7504}, + {0x7562, 2861}, + {0x7563, 8095}, + {0x7564, 8094}, + {0x7565, 2859}, + {0x7566, 2860}, + {0x756a, 3302}, + {0x756b, 3301}, + {0x756c, 8739}, + {0x756f, 8738}, + {0x7570, 2862}, + {0x7576, 3717}, + {0x7577, 9390}, + {0x7578, 3718}, + {0x7579, 9389}, + {0x757f, 4523}, + {0x7586, 5531}, + {0x7587, 5530}, + {0x758a, 5836}, + {0x758b, 866}, + {0x758c, 6674}, + {0x758f, 2863}, + {0x7591, 4146}, + {0x7592, 558}, + {0x7594, 6356}, + {0x7595, 6357}, + {0x7598, 6675}, + {0x7599, 1623}, + {0x759a, 1624}, + {0x759d, 1622}, + {0x75a2, 1960}, + {0x75a3, 1961}, + {0x75a4, 1958}, + {0x75a5, 1959}, + {0x75a7, 7059}, + {0x75aa, 7060}, + {0x75ab, 1957}, + {0x75b0, 7505}, + {0x75b2, 2361}, + {0x75b3, 2362}, + {0x75b5, 2866}, + {0x75b6, 7511}, + {0x75b8, 2367}, + {0x75b9, 2365}, + {0x75ba, 7512}, + {0x75bb, 7507}, + {0x75bc, 2364}, + {0x75bd, 2363}, + {0x75be, 2358}, + {0x75bf, 7510}, + {0x75c0, 7509}, + {0x75c1, 7506}, + {0x75c2, 2366}, + {0x75c4, 7508}, + {0x75c5, 2359}, + {0x75c7, 2360}, + {0x75ca, 2867}, + {0x75cb, 8099}, + {0x75cc, 8100}, + {0x75cd, 2868}, + {0x75ce, 8096}, + {0x75cf, 8098}, + {0x75d0, 8102}, + {0x75d1, 8101}, + {0x75d2, 8097}, + {0x75d4, 2864}, + {0x75d5, 2865}, + {0x75d7, 8747}, + {0x75d8, 3307}, + {0x75d9, 3306}, + {0x75da, 8741}, + {0x75db, 3304}, + {0x75dd, 8744}, + {0x75de, 3308}, + {0x75df, 8745}, + {0x75e0, 3309}, + {0x75e1, 8742}, + {0x75e2, 3303}, + {0x75e3, 3305}, + {0x75e4, 8746}, + {0x75e6, 8743}, + {0x75e7, 8740}, + {0x75ed, 9403}, + {0x75ef, 9392}, + {0x75f0, 3720}, + {0x75f1, 3723}, + {0x75f2, 3722}, + {0x75f3, 3727}, + {0x75f4, 3726}, + {0x75f5, 9404}, + {0x75f6, 9402}, + {0x75f7, 9395}, + {0x75f8, 9399}, + {0x75f9, 9398}, + {0x75fa, 3724}, + {0x75fb, 9401}, + {0x75fc, 9397}, + {0x75fd, 9405}, + {0x75fe, 9396}, + {0x75ff, 3725}, + {0x7600, 3719}, + {0x7601, 3721}, + {0x7603, 9394}, + {0x7609, 4150}, + {0x760b, 4149}, + {0x760d, 4148}, + {0x760f, 9393}, + {0x7610, 9400}, + {0x7613, 4151}, + {0x761f, 4526}, + {0x7620, 4524}, + {0x7621, 4529}, + {0x7622, 4530}, + {0x7624, 4527}, + {0x7626, 4528}, + {0x7627, 4147}, + {0x7629, 4525}, + {0x7634, 4866}, + {0x7638, 4867}, + {0x763a, 4868}, + {0x7642, 5141}, + {0x7646, 5140}, + {0x7649, 0}, + {0x764c, 5142}, + {0x7652, 5369}, + {0x7656, 5367}, + {0x7658, 5368}, + {0x765f, 5532}, + {0x7661, 5533}, + {0x7662, 5666}, + {0x7665, 5667}, + {0x7669, 5759}, + {0x766c, 5838}, + {0x766e, 5837}, + {0x7671, 5923}, + {0x7672, 5924}, + {0x7676, 559}, + {0x7678, 1962}, + {0x7679, 7061}, + {0x767b, 3310}, + {0x767c, 3311}, + {0x767d, 867}, + {0x767e, 1013}, + {0x767f, 6160}, + {0x7681, 6358}, + {0x7682, 1268}, + {0x7684, 1625}, + {0x7686, 1963}, + {0x7687, 1964}, + {0x7688, 1965}, + {0x7689, 8104}, + {0x768a, 7513}, + {0x768b, 2368}, + {0x768e, 2869}, + {0x768f, 8103}, + {0x7692, 8749}, + {0x7693, 3313}, + {0x7695, 8748}, + {0x7696, 3312}, + {0x7699, 9406}, + {0x769a, 4531}, + {0x769d, 0}, + {0x769e, 1}, + {0x76ae, 868}, + {0x76af, 6676}, + {0x76b0, 2369}, + {0x76b4, 3314}, + {0x76b5, 9407}, + {0x76ba, 4532}, + {0x76bf, 869}, + {0x76c2, 1626}, + {0x76c3, 1968}, + {0x76c4, 7062}, + {0x76c5, 1969}, + {0x76c6, 1967}, + {0x76c8, 1966}, + {0x76c9, 7514}, + {0x76ca, 2370}, + {0x76cd, 2371}, + {0x76ce, 2372}, + {0x76d2, 2871}, + {0x76d3, 8105}, + {0x76d4, 2870}, + {0x76da, 8750}, + {0x76db, 2872}, + {0x76dc, 3315}, + {0x76dd, 9408}, + {0x76de, 3728}, + {0x76df, 3729}, + {0x76e1, 4152}, + {0x76e3, 4153}, + {0x76e4, 4533}, + {0x76e5, 4870}, + {0x76e7, 4869}, + {0x76ea, 5143}, + {0x76ee, 870}, + {0x76ef, 1269}, + {0x76f0, 6679}, + {0x76f1, 6678}, + {0x76f2, 1627}, + {0x76f3, 6677}, + {0x76f4, 1628}, + {0x76f5, 6680}, + {0x76f7, 7068}, + {0x76f8, 1972}, + {0x76f9, 1971}, + {0x76fa, 7070}, + {0x76fb, 7069}, + {0x76fc, 1976}, + {0x76fe, 1975}, + {0x7701, 1970}, + {0x7703, 7064}, + {0x7704, 7065}, + {0x7705, 7066}, + {0x7707, 1977}, + {0x7708, 7063}, + {0x7709, 1973}, + {0x770a, 7067}, + {0x770b, 1974}, + {0x770f, 0}, + {0x7710, 7517}, + {0x7711, 7521}, + {0x7712, 7519}, + {0x7713, 7518}, + {0x7715, 7522}, + {0x7719, 7523}, + {0x771a, 7524}, + {0x771b, 7516}, + {0x771d, 7515}, + {0x771f, 2374}, + {0x7720, 2375}, + {0x7722, 7525}, + {0x7723, 7520}, + {0x7725, 8114}, + {0x7727, 7526}, + {0x7728, 2376}, + {0x7729, 2373}, + {0x772d, 8108}, + {0x772f, 8107}, + {0x7731, 8109}, + {0x7732, 8110}, + {0x7733, 8112}, + {0x7734, 8111}, + {0x7735, 8116}, + {0x7736, 2876}, + {0x7737, 2873}, + {0x7738, 2877}, + {0x7739, 8106}, + {0x773a, 2878}, + {0x773b, 8115}, + {0x773c, 2875}, + {0x773d, 8113}, + {0x773e, 2874}, + {0x7744, 8753}, + {0x7745, 8755}, + {0x7746, 8751}, + {0x7747, 8752}, + {0x774a, 8756}, + {0x774b, 8758}, + {0x774c, 8759}, + {0x774d, 8754}, + {0x774e, 8757}, + {0x774f, 3316}, + {0x7752, 9412}, + {0x7754, 9417}, + {0x7755, 9409}, + {0x7756, 9413}, + {0x7759, 9418}, + {0x775a, 9414}, + {0x775b, 3730}, + {0x775c, 3738}, + {0x775e, 3733}, + {0x775f, 9410}, + {0x7760, 9411}, + {0x7761, 4157}, + {0x7762, 3741}, + {0x7763, 3734}, + {0x7765, 3739}, + {0x7766, 3732}, + {0x7767, 9416}, + {0x7768, 3740}, + {0x7769, 9415}, + {0x776a, 3736}, + {0x776b, 3731}, + {0x776c, 3737}, + {0x776d, 9419}, + {0x7779, 3735}, + {0x777d, 4155}, + {0x777f, 4156}, + {0x7784, 4154}, + {0x7787, 4535}, + {0x778b, 4538}, + {0x778c, 4536}, + {0x778e, 4534}, + {0x7791, 4537}, + {0x779e, 4872}, + {0x779f, 4873}, + {0x77a0, 4871}, + {0x77a3, 0}, + {0x77a5, 4874}, + {0x77a7, 5148}, + {0x77aa, 5145}, + {0x77ac, 5147}, + {0x77ad, 5149}, + {0x77b0, 5146}, + {0x77b3, 5144}, + {0x77bb, 5372}, + {0x77bc, 5373}, + {0x77bd, 5370}, + {0x77bf, 5371}, + {0x77c7, 5534}, + {0x77ca, 0}, + {0x77cf, 0}, + {0x77d3, 5760}, + {0x77d7, 5925}, + {0x77d9, 0}, + {0x77da, 5971}, + {0x77db, 871}, + {0x77dc, 1978}, + {0x77de, 8760}, + {0x77e0, 9420}, + {0x77e2, 872}, + {0x77e3, 1270}, + {0x77e5, 1629}, + {0x77e7, 7071}, + {0x77e8, 7072}, + {0x77e9, 2377}, + {0x77ec, 8761}, + {0x77ed, 3317}, + {0x77ee, 3742}, + {0x77ef, 5150}, + {0x77f3, 873}, + {0x77f7, 6686}, + {0x77f8, 6681}, + {0x77f9, 6683}, + {0x77fa, 6685}, + {0x77fb, 6684}, + {0x77fc, 6682}, + {0x77fd, 1630}, + {0x7802, 1979}, + {0x7803, 7081}, + {0x7805, 7076}, + {0x7806, 7073}, + {0x7809, 7080}, + {0x780c, 1981}, + {0x780d, 1982}, + {0x780e, 7079}, + {0x780f, 7078}, + {0x7810, 7077}, + {0x7811, 7074}, + {0x7812, 7075}, + {0x7813, 7082}, + {0x7814, 1980}, + {0x781d, 2381}, + {0x781f, 2387}, + {0x7820, 2386}, + {0x7821, 7535}, + {0x7822, 7529}, + {0x7823, 7527}, + {0x7825, 2384}, + {0x7826, 8123}, + {0x7827, 2379}, + {0x7828, 7532}, + {0x7829, 7536}, + {0x782a, 7538}, + {0x782b, 7534}, + {0x782c, 7528}, + {0x782d, 2385}, + {0x782e, 7533}, + {0x782f, 7531}, + {0x7830, 2378}, + {0x7831, 7539}, + {0x7832, 2388}, + {0x7833, 7537}, + {0x7834, 2382}, + {0x7835, 7530}, + {0x7837, 2383}, + {0x7838, 2380}, + {0x7843, 2880}, + {0x7845, 8124}, + {0x7848, 8117}, + {0x7849, 8119}, + {0x784a, 8121}, + {0x784c, 8122}, + {0x784d, 8120}, + {0x784e, 2881}, + {0x7850, 8125}, + {0x7852, 8118}, + {0x785c, 8765}, + {0x785d, 3318}, + {0x785e, 8773}, + {0x7860, 8762}, + {0x7862, 8774}, + {0x7864, 8763}, + {0x7865, 8764}, + {0x7868, 8772}, + {0x7869, 8771}, + {0x786a, 8768}, + {0x786b, 2879}, + {0x786c, 3319}, + {0x786d, 8766}, + {0x786e, 8769}, + {0x786f, 3320}, + {0x7870, 8770}, + {0x7871, 8767}, + {0x7879, 9431}, + {0x787b, 9435}, + {0x787c, 3749}, + {0x787f, 3752}, + {0x7880, 9433}, + {0x7883, 9430}, + {0x7884, 9425}, + {0x7885, 9427}, + {0x7886, 9428}, + {0x7887, 9421}, + {0x7889, 3748}, + {0x788c, 3747}, + {0x788e, 3743}, + {0x788f, 9424}, + {0x7891, 3750}, + {0x7893, 3751}, + {0x7894, 9423}, + {0x7895, 9426}, + {0x7896, 9434}, + {0x7897, 3745}, + {0x7898, 3746}, + {0x7899, 9432}, + {0x789a, 9422}, + {0x789f, 4159}, + {0x78a1, 9429}, + {0x78a3, 4163}, + {0x78a7, 4160}, + {0x78a9, 4162}, + {0x78b0, 3744}, + {0x78b3, 4161}, + {0x78ba, 4541}, + {0x78bc, 4545}, + {0x78be, 4543}, + {0x78c1, 4158}, + {0x78c4, 0}, + {0x78c5, 4540}, + {0x78ca, 4542}, + {0x78cb, 4539}, + {0x78d0, 4546}, + {0x78d5, 4544}, + {0x78da, 4876}, + {0x78e0, 0}, + {0x78e2, 0}, + {0x78e7, 4878}, + {0x78e8, 4875}, + {0x78ec, 4877}, + {0x78ef, 5154}, + {0x78f4, 5153}, + {0x78f7, 5151}, + {0x78fa, 5152}, + {0x78fc, 0}, + {0x7901, 5155}, + {0x790e, 5374}, + {0x7914, 0}, + {0x7919, 5535}, + {0x7926, 5668}, + {0x7928, 0}, + {0x792a, 5669}, + {0x792b, 5671}, + {0x792c, 5670}, + {0x793a, 874}, + {0x793d, 6359}, + {0x793e, 1631}, + {0x793f, 6688}, + {0x7940, 1632}, + {0x7941, 1633}, + {0x7942, 6687}, + {0x7944, 7087}, + {0x7945, 7086}, + {0x7946, 1983}, + {0x7947, 1986}, + {0x7948, 1985}, + {0x7949, 1984}, + {0x794a, 7083}, + {0x794b, 7085}, + {0x794c, 7084}, + {0x794f, 7542}, + {0x7950, 2390}, + {0x7951, 7546}, + {0x7952, 7545}, + {0x7953, 7544}, + {0x7954, 7540}, + {0x7955, 2389}, + {0x7956, 2393}, + {0x7957, 2396}, + {0x795a, 2397}, + {0x795b, 7541}, + {0x795c, 7543}, + {0x795d, 2395}, + {0x795e, 2394}, + {0x795f, 2392}, + {0x7960, 2391}, + {0x7961, 8132}, + {0x7963, 8130}, + {0x7964, 8126}, + {0x7965, 2882}, + {0x7967, 8127}, + {0x7968, 2883}, + {0x7969, 8128}, + {0x796a, 8129}, + {0x796b, 8131}, + {0x796d, 2884}, + {0x7970, 8778}, + {0x7972, 8777}, + {0x7973, 8776}, + {0x7974, 8775}, + {0x7979, 9439}, + {0x797a, 3753}, + {0x797c, 9436}, + {0x797d, 9438}, + {0x797f, 3754}, + {0x7981, 3755}, + {0x7982, 9437}, + {0x798b, 0}, + {0x798d, 4166}, + {0x798e, 4164}, + {0x798f, 4165}, + {0x79a6, 4879}, + {0x79a7, 5156}, + {0x79aa, 5157}, + {0x79ae, 5375}, + {0x79b1, 5536}, + {0x79b3, 5839}, + {0x79b8, 6066}, + {0x79b9, 1987}, + {0x79ba, 1988}, + {0x79bb, 8133}, + {0x79bd, 3757}, + {0x79be, 875}, + {0x79bf, 1273}, + {0x79c0, 1272}, + {0x79c1, 1271}, + {0x79c5, 6689}, + {0x79c8, 1635}, + {0x79c9, 1634}, + {0x79cb, 1991}, + {0x79cd, 7089}, + {0x79ce, 7092}, + {0x79cf, 7090}, + {0x79d1, 1989}, + {0x79d2, 1990}, + {0x79d5, 7088}, + {0x79d6, 7091}, + {0x79d8, 2404}, + {0x79dc, 7553}, + {0x79dd, 7555}, + {0x79de, 7554}, + {0x79df, 2401}, + {0x79e0, 7549}, + {0x79e3, 2399}, + {0x79e4, 2398}, + {0x79e6, 2402}, + {0x79e7, 2400}, + {0x79e9, 2403}, + {0x79ea, 7552}, + {0x79eb, 7547}, + {0x79ec, 7548}, + {0x79ed, 7551}, + {0x79ee, 7550}, + {0x79f6, 8136}, + {0x79f7, 8137}, + {0x79f8, 8135}, + {0x79fa, 8134}, + {0x79fb, 2885}, + {0x7a00, 3325}, + {0x7a02, 8779}, + {0x7a03, 8781}, + {0x7a04, 8783}, + {0x7a05, 3324}, + {0x7a08, 3322}, + {0x7a0a, 8780}, + {0x7a0b, 3323}, + {0x7a0c, 8782}, + {0x7a0d, 3321}, + {0x7a10, 9449}, + {0x7a11, 9440}, + {0x7a12, 9443}, + {0x7a13, 9447}, + {0x7a14, 3761}, + {0x7a15, 9445}, + {0x7a17, 9444}, + {0x7a18, 9441}, + {0x7a19, 9442}, + {0x7a1a, 3759}, + {0x7a1b, 9448}, + {0x7a1c, 3758}, + {0x7a1e, 3763}, + {0x7a1f, 3762}, + {0x7a20, 3760}, + {0x7a22, 9446}, + {0x7a2e, 4167}, + {0x7a31, 4168}, + {0x7a37, 4551}, + {0x7a3b, 4552}, + {0x7a3c, 4548}, + {0x7a3d, 4550}, + {0x7a3f, 4547}, + {0x7a40, 4549}, + {0x7a46, 4882}, + {0x7a4b, 4884}, + {0x7a4c, 4883}, + {0x7a4d, 4880}, + {0x7a4e, 4881}, + {0x7a57, 5158}, + {0x7a60, 5378}, + {0x7a61, 5376}, + {0x7a62, 5377}, + {0x7a68, 0}, + {0x7a69, 5538}, + {0x7a6b, 5537}, + {0x7a6d, 0}, + {0x7a71, 0}, + {0x7a74, 876}, + {0x7a75, 6161}, + {0x7a76, 1274}, + {0x7a78, 6690}, + {0x7a79, 1637}, + {0x7a7a, 1636}, + {0x7a7b, 6691}, + {0x7a7e, 7094}, + {0x7a7f, 1992}, + {0x7a80, 7093}, + {0x7a81, 1993}, + {0x7a84, 2405}, + {0x7a85, 7558}, + {0x7a86, 7556}, + {0x7a87, 7562}, + {0x7a88, 2406}, + {0x7a89, 7557}, + {0x7a8a, 7561}, + {0x7a8b, 7559}, + {0x7a8c, 7560}, + {0x7a8f, 8138}, + {0x7a90, 8140}, + {0x7a92, 2886}, + {0x7a94, 8139}, + {0x7a95, 2887}, + {0x7a96, 3328}, + {0x7a97, 3327}, + {0x7a98, 3326}, + {0x7a99, 8784}, + {0x7a9e, 9452}, + {0x7a9f, 3764}, + {0x7aa0, 3765}, + {0x7aa2, 9451}, + {0x7aa3, 9450}, + {0x7aa9, 4170}, + {0x7aaa, 4169}, + {0x7aac, 0}, + {0x7aae, 4554}, + {0x7aaf, 4553}, + {0x7aba, 4885}, + {0x7abf, 5159}, + {0x7ac1, 0}, + {0x7ac3, 0}, + {0x7ac4, 5379}, + {0x7ac5, 5380}, + {0x7ac7, 5672}, + {0x7aca, 5887}, + {0x7acb, 877}, + {0x7ad1, 7095}, + {0x7ad8, 7563}, + {0x7ad9, 2407}, + {0x7adf, 3038}, + {0x7ae0, 3037}, + {0x7ae3, 3330}, + {0x7ae4, 8786}, + {0x7ae5, 3329}, + {0x7ae6, 8785}, + {0x7aeb, 9453}, + {0x7aed, 4171}, + {0x7aef, 4172}, + {0x7af6, 5673}, + {0x7af9, 1014}, + {0x7afa, 1638}, + {0x7afb, 6692}, + {0x7afd, 1995}, + {0x7aff, 1994}, + {0x7b00, 7096}, + {0x7b01, 7097}, + {0x7b04, 7565}, + {0x7b05, 7567}, + {0x7b06, 2408}, + {0x7b08, 7569}, + {0x7b09, 7572}, + {0x7b0a, 7570}, + {0x7b0e, 7571}, + {0x7b0f, 7568}, + {0x7b10, 7564}, + {0x7b11, 2409}, + {0x7b12, 7573}, + {0x7b13, 7566}, + {0x7b18, 8149}, + {0x7b19, 2893}, + {0x7b1a, 8158}, + {0x7b1b, 2890}, + {0x7b1d, 8151}, + {0x7b1e, 2894}, + {0x7b20, 2888}, + {0x7b22, 8146}, + {0x7b23, 8159}, + {0x7b24, 8147}, + {0x7b25, 8144}, + {0x7b26, 2892}, + {0x7b28, 2889}, + {0x7b2a, 8150}, + {0x7b2b, 8153}, + {0x7b2c, 2891}, + {0x7b2d, 8154}, + {0x7b2e, 2895}, + {0x7b2f, 8155}, + {0x7b30, 8145}, + {0x7b31, 8152}, + {0x7b32, 8156}, + {0x7b33, 8148}, + {0x7b34, 8143}, + {0x7b35, 8141}, + {0x7b38, 8157}, + {0x7b3b, 8142}, + {0x7b40, 8793}, + {0x7b44, 8789}, + {0x7b45, 8795}, + {0x7b46, 3333}, + {0x7b47, 8788}, + {0x7b48, 8790}, + {0x7b49, 3331}, + {0x7b4a, 8787}, + {0x7b4b, 3338}, + {0x7b4c, 8791}, + {0x7b4d, 3337}, + {0x7b4e, 8792}, + {0x7b4f, 3339}, + {0x7b50, 3334}, + {0x7b51, 3340}, + {0x7b52, 3335}, + {0x7b54, 3336}, + {0x7b56, 3332}, + {0x7b58, 8794}, + {0x7b60, 3768}, + {0x7b61, 9464}, + {0x7b63, 9467}, + {0x7b64, 9455}, + {0x7b65, 9460}, + {0x7b66, 9454}, + {0x7b67, 3770}, + {0x7b69, 9458}, + {0x7b6d, 9456}, + {0x7b6e, 3769}, + {0x7b70, 9463}, + {0x7b71, 9462}, + {0x7b72, 9459}, + {0x7b73, 9461}, + {0x7b74, 9457}, + {0x7b75, 4176}, + {0x7b76, 9466}, + {0x7b77, 3766}, + {0x7b78, 9465}, + {0x7b84, 4183}, + {0x7b87, 4182}, + {0x7b8b, 4175}, + {0x7b8f, 4180}, + {0x7b94, 4179}, + {0x7b95, 4174}, + {0x7b97, 4177}, + {0x7b9d, 4178}, + {0x7ba0, 4562}, + {0x7ba1, 4173}, + {0x7bad, 4555}, + {0x7bb1, 4556}, + {0x7bb4, 4558}, + {0x7bb8, 4181}, + {0x7bc0, 3767}, + {0x7bc1, 4561}, + {0x7bc4, 4557}, + {0x7bc6, 4559}, + {0x7bc7, 4560}, + {0x7bc9, 4888}, + {0x7bcc, 4563}, + {0x7bd9, 4886}, + {0x7bdb, 4890}, + {0x7be0, 5165}, + {0x7be1, 4891}, + {0x7be4, 4889}, + {0x7be6, 4893}, + {0x7be9, 4892}, + {0x7bf1, 0}, + {0x7bf7, 5163}, + {0x7bfe, 5162}, + {0x7c07, 5160}, + {0x7c0c, 5164}, + {0x7c0d, 5161}, + {0x7c11, 4887}, + {0x7c1e, 5384}, + {0x7c21, 5386}, + {0x7c23, 5385}, + {0x7c27, 5382}, + {0x7c2a, 5383}, + {0x7c2b, 5381}, + {0x7c37, 5543}, + {0x7c38, 5541}, + {0x7c3d, 5542}, + {0x7c3e, 5539}, + {0x7c3f, 5540}, + {0x7c40, 5544}, + {0x7c43, 5675}, + {0x7c4c, 5674}, + {0x7c4d, 5676}, + {0x7c50, 5761}, + {0x7c5f, 5841}, + {0x7c60, 5840}, + {0x7c63, 5889}, + {0x7c64, 5888}, + {0x7c65, 5890}, + {0x7c6c, 5957}, + {0x7c6e, 5958}, + {0x7c72, 5995}, + {0x7c73, 1015}, + {0x7c75, 6693}, + {0x7c78, 7099}, + {0x7c79, 7100}, + {0x7c7a, 7098}, + {0x7c7d, 1996}, + {0x7c7f, 7101}, + {0x7c80, 7102}, + {0x7c81, 7103}, + {0x7c84, 7574}, + {0x7c85, 7580}, + {0x7c88, 7578}, + {0x7c89, 2410}, + {0x7c8a, 7576}, + {0x7c8c, 7577}, + {0x7c8d, 7579}, + {0x7c91, 7575}, + {0x7c92, 2896}, + {0x7c94, 8160}, + {0x7c95, 2898}, + {0x7c96, 8162}, + {0x7c97, 2897}, + {0x7c98, 8161}, + {0x7c9e, 8797}, + {0x7c9f, 3341}, + {0x7ca1, 8799}, + {0x7ca2, 8796}, + {0x7ca3, 8163}, + {0x7ca5, 3342}, + {0x7ca8, 8798}, + {0x7caf, 9470}, + {0x7cb1, 3771}, + {0x7cb2, 9468}, + {0x7cb3, 3772}, + {0x7cb4, 9469}, + {0x7cb5, 3773}, + {0x7cb9, 4184}, + {0x7cbd, 4185}, + {0x7cbe, 4186}, + {0x7cca, 4564}, + {0x7cce, 289}, + {0x7cd1, 0}, + {0x7cd5, 4894}, + {0x7cd6, 4895}, + {0x7cd9, 5171}, + {0x7cdc, 5167}, + {0x7cdd, 5172}, + {0x7cde, 5168}, + {0x7cdf, 5170}, + {0x7ce0, 5166}, + {0x7ce2, 5169}, + {0x7ce7, 5387}, + {0x7cef, 5677}, + {0x7cf0, 5678}, + {0x7cf8, 1016}, + {0x7cfb, 1275}, + {0x7cfd, 6694}, + {0x7cfe, 1639}, + {0x7d00, 1999}, + {0x7d01, 7106}, + {0x7d02, 1997}, + {0x7d03, 7104}, + {0x7d04, 2002}, + {0x7d05, 1998}, + {0x7d06, 2003}, + {0x7d07, 2001}, + {0x7d08, 7105}, + {0x7d09, 2000}, + {0x7d0a, 2414}, + {0x7d0b, 2413}, + {0x7d0c, 7591}, + {0x7d0d, 2422}, + {0x7d0e, 7584}, + {0x7d0f, 7590}, + {0x7d10, 2418}, + {0x7d11, 7583}, + {0x7d12, 7589}, + {0x7d13, 7587}, + {0x7d14, 2417}, + {0x7d15, 2419}, + {0x7d16, 7586}, + {0x7d17, 2412}, + {0x7d18, 7585}, + {0x7d19, 2423}, + {0x7d1a, 2420}, + {0x7d1b, 2424}, + {0x7d1c, 2421}, + {0x7d1d, 7582}, + {0x7d1e, 7581}, + {0x7d1f, 7588}, + {0x7d20, 2415}, + {0x7d21, 2411}, + {0x7d22, 2416}, + {0x7d28, 8178}, + {0x7d29, 8171}, + {0x7d2b, 3347}, + {0x7d2c, 8170}, + {0x7d2e, 2902}, + {0x7d2f, 2909}, + {0x7d30, 2906}, + {0x7d31, 2912}, + {0x7d32, 2911}, + {0x7d33, 2907}, + {0x7d35, 8164}, + {0x7d36, 8167}, + {0x7d38, 8166}, + {0x7d39, 2903}, + {0x7d3a, 8168}, + {0x7d3b, 8177}, + {0x7d3c, 2904}, + {0x7d3d, 8165}, + {0x7d3e, 8174}, + {0x7d3f, 8175}, + {0x7d40, 2905}, + {0x7d41, 8172}, + {0x7d42, 2910}, + {0x7d43, 2900}, + {0x7d44, 2908}, + {0x7d45, 8169}, + {0x7d46, 2899}, + {0x7d47, 8173}, + {0x7d4a, 8176}, + {0x7d4e, 8816}, + {0x7d4f, 8807}, + {0x7d50, 3344}, + {0x7d51, 8814}, + {0x7d52, 8811}, + {0x7d53, 8803}, + {0x7d54, 8812}, + {0x7d55, 3346}, + {0x7d56, 8804}, + {0x7d58, 8800}, + {0x7d5b, 3779}, + {0x7d5c, 8809}, + {0x7d5e, 3343}, + {0x7d5f, 8815}, + {0x7d61, 3350}, + {0x7d62, 3352}, + {0x7d63, 8802}, + {0x7d66, 3351}, + {0x7d67, 8805}, + {0x7d68, 3345}, + {0x7d69, 8813}, + {0x7d6a, 8806}, + {0x7d6b, 8810}, + {0x7d6d, 8808}, + {0x7d6e, 3348}, + {0x7d6f, 8801}, + {0x7d70, 3353}, + {0x7d71, 2901}, + {0x7d72, 3349}, + {0x7d73, 3354}, + {0x7d79, 3775}, + {0x7d7a, 9477}, + {0x7d7b, 9479}, + {0x7d7c, 9481}, + {0x7d7d, 9485}, + {0x7d7f, 9475}, + {0x7d80, 9473}, + {0x7d81, 3777}, + {0x7d83, 9480}, + {0x7d84, 9484}, + {0x7d85, 9476}, + {0x7d86, 9472}, + {0x7d88, 9471}, + {0x7d8c, 9482}, + {0x7d8d, 9474}, + {0x7d8e, 9478}, + {0x7d8f, 3778}, + {0x7d91, 3776}, + {0x7d92, 9486}, + {0x7d93, 3774}, + {0x7d94, 9483}, + {0x7d9c, 4189}, + {0x7d9e, 4577}, + {0x7da0, 4192}, + {0x7da2, 4198}, + {0x7dac, 4205}, + {0x7dad, 4202}, + {0x7db0, 4188}, + {0x7db1, 4196}, + {0x7db2, 4195}, + {0x7db4, 4194}, + {0x7db5, 4200}, + {0x7db8, 4201}, + {0x7dba, 4197}, + {0x7dbb, 4187}, + {0x7dbd, 4190}, + {0x7dbe, 4191}, + {0x7dbf, 4199}, + {0x7dc7, 4204}, + {0x7dca, 4193}, + {0x7dcc, 0}, + {0x7dd2, 4203}, + {0x7dd8, 4569}, + {0x7dd9, 4578}, + {0x7dda, 4574}, + {0x7ddd, 4571}, + {0x7dde, 4575}, + {0x7de0, 4565}, + {0x7de3, 4573}, + {0x7de8, 4572}, + {0x7de9, 4576}, + {0x7dec, 4570}, + {0x7def, 4567}, + {0x7df2, 4579}, + {0x7df4, 4566}, + {0x7df9, 4580}, + {0x7dfb, 4568}, + {0x7e08, 4898}, + {0x7e09, 4903}, + {0x7e0a, 4896}, + {0x7e10, 4904}, + {0x7e11, 4897}, + {0x7e1b, 4899}, + {0x7e1d, 4902}, + {0x7e1e, 4901}, + {0x7e20, 0}, + {0x7e23, 4900}, + {0x7e2b, 5179}, + {0x7e2e, 5173}, + {0x7e2f, 5189}, + {0x7e31, 5181}, + {0x7e32, 5177}, + {0x7e34, 5184}, + {0x7e35, 5187}, + {0x7e37, 5176}, + {0x7e39, 5185}, + {0x7e3d, 5180}, + {0x7e3e, 5174}, + {0x7e3f, 5188}, + {0x7e41, 5183}, + {0x7e43, 5178}, + {0x7e45, 5182}, + {0x7e46, 5175}, + {0x7e48, 5186}, + {0x7e52, 5393}, + {0x7e54, 5388}, + {0x7e55, 5389}, + {0x7e59, 5394}, + {0x7e5a, 5391}, + {0x7e5e, 5390}, + {0x7e61, 5392}, + {0x7e69, 5548}, + {0x7e6a, 5549}, + {0x7e6b, 5545}, + {0x7e6d, 5546}, + {0x7e73, 5550}, + {0x7e79, 5547}, + {0x7e7c, 5681}, + {0x7e7d, 5680}, + {0x7e82, 5682}, + {0x7e88, 0}, + {0x7e8c, 5763}, + {0x7e8f, 5762}, + {0x7e93, 5891}, + {0x7e94, 5893}, + {0x7e96, 5892}, + {0x7e9c, 5977}, + {0x7f36, 1017}, + {0x7f38, 2004}, + {0x7f39, 7455}, + {0x7f3a, 2425}, + {0x7f3d, 2913}, + {0x7f3e, 8817}, + {0x7f3f, 8818}, + {0x7f41, 0}, + {0x7f44, 5190}, + {0x7f48, 5395}, + {0x7f4c, 5683}, + {0x7f50, 5926}, + {0x7f51, 6162}, + {0x7f54, 1640}, + {0x7f55, 1276}, + {0x7f58, 7107}, + {0x7f5b, 7597}, + {0x7f5c, 7592}, + {0x7f5d, 7596}, + {0x7f5e, 7594}, + {0x7f5f, 2426}, + {0x7f60, 7595}, + {0x7f61, 7593}, + {0x7f63, 8179}, + {0x7f65, 8819}, + {0x7f66, 8820}, + {0x7f67, 9489}, + {0x7f68, 9490}, + {0x7f69, 3781}, + {0x7f6a, 3782}, + {0x7f6b, 9488}, + {0x7f6c, 9491}, + {0x7f6d, 9487}, + {0x7f6e, 3780}, + {0x7f70, 4206}, + {0x7f72, 3783}, + {0x7f75, 4581}, + {0x7f77, 4582}, + {0x7f79, 4905}, + {0x7f7c, 0}, + {0x7f85, 5551}, + {0x7f88, 5927}, + {0x7f8a, 1018}, + {0x7f8b, 1642}, + {0x7f8c, 1641}, + {0x7f8d, 7109}, + {0x7f8e, 2005}, + {0x7f91, 7108}, + {0x7f92, 7599}, + {0x7f94, 2427}, + {0x7f95, 8180}, + {0x7f96, 7598}, + {0x7f9a, 2915}, + {0x7f9b, 8183}, + {0x7f9c, 8181}, + {0x7f9d, 8182}, + {0x7f9e, 2914}, + {0x7fa0, 8822}, + {0x7fa1, 8823}, + {0x7fa2, 8821}, + {0x7fa4, 3786}, + {0x7fa5, 9493}, + {0x7fa6, 9492}, + {0x7fa7, 9494}, + {0x7fa8, 3785}, + {0x7fa9, 3784}, + {0x7faf, 4583}, + {0x7fb2, 4906}, + {0x7fb6, 5552}, + {0x7fb8, 5554}, + {0x7fb9, 5553}, + {0x7fbc, 5764}, + {0x7fbd, 1019}, + {0x7fbe, 7110}, + {0x7fbf, 2006}, + {0x7fc0, 7602}, + {0x7fc1, 2429}, + {0x7fc2, 7601}, + {0x7fc3, 7600}, + {0x7fc5, 2428}, + {0x7fc7, 8189}, + {0x7fc9, 8191}, + {0x7fca, 8184}, + {0x7fcb, 8185}, + {0x7fcc, 2916}, + {0x7fcd, 8186}, + {0x7fce, 2917}, + {0x7fcf, 8190}, + {0x7fd0, 8187}, + {0x7fd1, 8188}, + {0x7fd2, 2918}, + {0x7fd4, 3356}, + {0x7fd5, 3357}, + {0x7fd7, 8824}, + {0x7fdb, 9495}, + {0x7fdc, 9496}, + {0x7fdf, 4209}, + {0x7fe0, 4207}, + {0x7fe1, 4208}, + {0x7fe3, 0}, + {0x7fe9, 4584}, + {0x7fee, 4909}, + {0x7ff0, 4907}, + {0x7ff1, 4908}, + {0x7ff3, 5191}, + {0x7ff8, 0}, + {0x7ff9, 5396}, + {0x7ffb, 5397}, + {0x7ffc, 5192}, + {0x7ffe, 0}, + {0x8000, 5684}, + {0x8001, 1020}, + {0x8003, 1021}, + {0x8004, 2431}, + {0x8005, 1643}, + {0x8006, 2430}, + {0x8007, 7111}, + {0x800b, 3358}, + {0x800c, 1022}, + {0x800d, 2008}, + {0x800e, 7112}, + {0x800f, 7113}, + {0x8010, 2007}, + {0x8011, 2009}, + {0x8012, 1023}, + {0x8014, 7114}, + {0x8015, 2433}, + {0x8016, 7603}, + {0x8017, 2435}, + {0x8018, 2432}, + {0x8019, 2434}, + {0x801b, 8194}, + {0x801c, 2919}, + {0x801e, 8193}, + {0x801f, 8192}, + {0x8021, 9497}, + {0x8026, 4585}, + {0x8028, 4910}, + {0x8033, 1024}, + {0x8034, 6360}, + {0x8035, 6695}, + {0x8036, 2010}, + {0x8037, 7115}, + {0x8039, 7605}, + {0x803c, 0}, + {0x803d, 2436}, + {0x803e, 7604}, + {0x803f, 2437}, + {0x8043, 8196}, + {0x8046, 2921}, + {0x8047, 8195}, + {0x8048, 8197}, + {0x804a, 2920}, + {0x804f, 8826}, + {0x8050, 8827}, + {0x8051, 8825}, + {0x8052, 3359}, + {0x8056, 3787}, + {0x8058, 3788}, + {0x805a, 4211}, + {0x805e, 4210}, + {0x806f, 5196}, + {0x8070, 5195}, + {0x8071, 5193}, + {0x8072, 5194}, + {0x8073, 5197}, + {0x8076, 5399}, + {0x8077, 5398}, + {0x807d, 5843}, + {0x807e, 5842}, + {0x807f, 1025}, + {0x8082, 7404}, + {0x8084, 3790}, + {0x8085, 3360}, + {0x8086, 3789}, + {0x8087, 4212}, + {0x8089, 1026}, + {0x808a, 6067}, + {0x808b, 1027}, + {0x808c, 1028}, + {0x808f, 6696}, + {0x8090, 6363}, + {0x8092, 6364}, + {0x8093, 1278}, + {0x8095, 6361}, + {0x8096, 1277}, + {0x8098, 1280}, + {0x8099, 6362}, + {0x809a, 1282}, + {0x809b, 1281}, + {0x809c, 6365}, + {0x809d, 1279}, + {0x80a1, 1648}, + {0x80a2, 1646}, + {0x80a3, 6698}, + {0x80a5, 1645}, + {0x80a9, 1650}, + {0x80aa, 1652}, + {0x80ab, 1649}, + {0x80ad, 6701}, + {0x80ae, 6697}, + {0x80af, 1653}, + {0x80b1, 1647}, + {0x80b2, 1283}, + {0x80b4, 1651}, + {0x80b5, 6700}, + {0x80b8, 6699}, + {0x80ba, 1644}, + {0x80c2, 7121}, + {0x80c3, 2014}, + {0x80c4, 2015}, + {0x80c5, 7123}, + {0x80c7, 7117}, + {0x80c8, 7120}, + {0x80c9, 7129}, + {0x80ca, 7127}, + {0x80cc, 2016}, + {0x80cd, 7133}, + {0x80ce, 2019}, + {0x80cf, 7130}, + {0x80d0, 7122}, + {0x80d1, 7119}, + {0x80d4, 8829}, + {0x80d5, 7128}, + {0x80d6, 2011}, + {0x80d7, 7131}, + {0x80d8, 7116}, + {0x80d9, 7125}, + {0x80da, 2013}, + {0x80db, 2018}, + {0x80dc, 7126}, + {0x80dd, 2022}, + {0x80de, 2020}, + {0x80e0, 7118}, + {0x80e1, 2017}, + {0x80e3, 7124}, + {0x80e4, 2021}, + {0x80e5, 2012}, + {0x80e6, 7132}, + {0x80ed, 2442}, + {0x80ef, 2451}, + {0x80f0, 2440}, + {0x80f1, 2438}, + {0x80f2, 7607}, + {0x80f3, 2446}, + {0x80f4, 2443}, + {0x80f5, 7609}, + {0x80f8, 2445}, + {0x80f9, 7608}, + {0x80fa, 7606}, + {0x80fb, 7611}, + {0x80fc, 2450}, + {0x80fd, 2448}, + {0x80fe, 8828}, + {0x8100, 7612}, + {0x8101, 7610}, + {0x8102, 2439}, + {0x8105, 2441}, + {0x8106, 2444}, + {0x8108, 2447}, + {0x810a, 2449}, + {0x8115, 8207}, + {0x8116, 2923}, + {0x8118, 8198}, + {0x8119, 8200}, + {0x811b, 8201}, + {0x811d, 8209}, + {0x811e, 8205}, + {0x811f, 8203}, + {0x8121, 8206}, + {0x8122, 8210}, + {0x8123, 2924}, + {0x8124, 2928}, + {0x8125, 8199}, + {0x8127, 8208}, + {0x8129, 2926}, + {0x812b, 2925}, + {0x812c, 8204}, + {0x812d, 8202}, + {0x812f, 2922}, + {0x8130, 2927}, + {0x8139, 3366}, + {0x813a, 8837}, + {0x813d, 8835}, + {0x813e, 3368}, + {0x8143, 8830}, + {0x8144, 9511}, + {0x8146, 3367}, + {0x8147, 8834}, + {0x814a, 8831}, + {0x814b, 3363}, + {0x814c, 3369}, + {0x814d, 8836}, + {0x814e, 3365}, + {0x814f, 8833}, + {0x8150, 4213}, + {0x8151, 3364}, + {0x8152, 8832}, + {0x8153, 3370}, + {0x8154, 3362}, + {0x8155, 3361}, + {0x815a, 0}, + {0x815b, 9503}, + {0x815c, 9501}, + {0x815e, 9507}, + {0x8160, 9499}, + {0x8161, 9512}, + {0x8162, 9504}, + {0x8164, 9498}, + {0x8165, 3794}, + {0x8166, 3800}, + {0x8167, 9509}, + {0x8169, 9502}, + {0x816b, 3797}, + {0x816e, 3795}, + {0x816f, 9510}, + {0x8170, 3792}, + {0x8171, 3791}, + {0x8172, 9505}, + {0x8173, 3796}, + {0x8174, 3371}, + {0x8176, 9508}, + {0x8177, 9500}, + {0x8178, 3793}, + {0x8179, 3798}, + {0x817a, 3799}, + {0x817f, 4218}, + {0x8180, 4214}, + {0x8182, 4219}, + {0x8188, 4216}, + {0x818a, 4217}, + {0x818f, 4215}, + {0x8198, 4591}, + {0x819a, 4590}, + {0x819b, 4586}, + {0x819c, 4587}, + {0x819d, 4588}, + {0x81a0, 4589}, + {0x81a8, 4913}, + {0x81a9, 4912}, + {0x81b3, 4911}, + {0x81ba, 5200}, + {0x81bd, 5204}, + {0x81be, 5206}, + {0x81bf, 5203}, + {0x81c0, 5202}, + {0x81c2, 5201}, + {0x81c3, 5199}, + {0x81c6, 5198}, + {0x81c9, 5205}, + {0x81cd, 5400}, + {0x81cf, 5401}, + {0x81d2, 0}, + {0x81d8, 5555}, + {0x81da, 5685}, + {0x81df, 5844}, + {0x81e1, 0}, + {0x81e2, 5894}, + {0x81e3, 1029}, + {0x81e5, 1654}, + {0x81e6, 8838}, + {0x81e7, 4220}, + {0x81e8, 5207}, + {0x81ea, 1030}, + {0x81ec, 2453}, + {0x81ed, 2452}, + {0x81ee, 8839}, + {0x81f3, 1031}, + {0x81f4, 2023}, + {0x81f7, 8840}, + {0x81f8, 8841}, + {0x81f9, 8842}, + {0x81fa, 4221}, + {0x81fb, 4914}, + {0x81fc, 1032}, + {0x81fe, 1655}, + {0x81ff, 7134}, + {0x8200, 2454}, + {0x8201, 7613}, + {0x8202, 2929}, + {0x8204, 8843}, + {0x8205, 3801}, + {0x8207, 4222}, + {0x8208, 4915}, + {0x8209, 5208}, + {0x820a, 5402}, + {0x820c, 1033}, + {0x820d, 1656}, + {0x8210, 2455}, + {0x8211, 8211}, + {0x8212, 3372}, + {0x8214, 4223}, + {0x821b, 1034}, + {0x821c, 3373}, + {0x821d, 9513}, + {0x821e, 4224}, + {0x821f, 1035}, + {0x8220, 6702}, + {0x8221, 7135}, + {0x8222, 2024}, + {0x8225, 7615}, + {0x8228, 2458}, + {0x822a, 2456}, + {0x822b, 2457}, + {0x822c, 2459}, + {0x822f, 7614}, + {0x8232, 8216}, + {0x8233, 8213}, + {0x8234, 8215}, + {0x8235, 2930}, + {0x8236, 2932}, + {0x8237, 2931}, + {0x8238, 8212}, + {0x8239, 2933}, + {0x823a, 8214}, + {0x823c, 8844}, + {0x823d, 8845}, + {0x823f, 8846}, + {0x8240, 9516}, + {0x8242, 9517}, + {0x8244, 9515}, + {0x8245, 9518}, + {0x8247, 3802}, + {0x8249, 9514}, + {0x824b, 4225}, + {0x8256, 0}, + {0x8257, 1}, + {0x8258, 4916}, + {0x8259, 4917}, + {0x8266, 5686}, + {0x8269, 0}, + {0x826e, 1036}, + {0x826f, 1284}, + {0x8271, 5209}, + {0x8272, 1037}, + {0x8274, 8217}, + {0x8275, 8847}, + {0x8277, 5934}, + {0x8278, 6163}, + {0x827c, 6164}, + {0x827d, 6166}, + {0x827e, 1038}, + {0x827f, 6167}, + {0x8280, 6165}, + {0x8283, 6373}, + {0x8284, 6374}, + {0x8285, 6368}, + {0x828a, 6372}, + {0x828b, 1286}, + {0x828d, 1287}, + {0x828e, 6369}, + {0x828f, 6367}, + {0x8290, 6366}, + {0x8291, 6370}, + {0x8292, 1285}, + {0x8293, 6371}, + {0x8294, 7136}, + {0x8298, 6707}, + {0x8299, 1659}, + {0x829a, 6706}, + {0x829b, 6708}, + {0x829d, 1658}, + {0x829e, 6713}, + {0x829f, 1662}, + {0x82a0, 6703}, + {0x82a1, 6717}, + {0x82a2, 6723}, + {0x82a3, 1669}, + {0x82a4, 6720}, + {0x82a5, 1666}, + {0x82a7, 6710}, + {0x82a8, 6716}, + {0x82a9, 6718}, + {0x82ab, 6705}, + {0x82ac, 1665}, + {0x82ad, 1660}, + {0x82ae, 6711}, + {0x82af, 1667}, + {0x82b0, 1670}, + {0x82b1, 1664}, + {0x82b3, 1657}, + {0x82b4, 6715}, + {0x82b5, 6709}, + {0x82b6, 6722}, + {0x82b7, 1672}, + {0x82b8, 1668}, + {0x82b9, 1663}, + {0x82ba, 6714}, + {0x82bb, 2460}, + {0x82bc, 6712}, + {0x82bd, 1661}, + {0x82be, 1671}, + {0x82c0, 6704}, + {0x82c2, 6719}, + {0x82c3, 6721}, + {0x82d1, 2041}, + {0x82d2, 2035}, + {0x82d3, 2043}, + {0x82d4, 2040}, + {0x82d5, 7143}, + {0x82d6, 7146}, + {0x82d7, 2036}, + {0x82d9, 7137}, + {0x82db, 2029}, + {0x82dc, 2039}, + {0x82de, 2042}, + {0x82df, 2044}, + {0x82e0, 7158}, + {0x82e1, 7149}, + {0x82e3, 2028}, + {0x82e4, 7157}, + {0x82e5, 2032}, + {0x82e6, 2030}, + {0x82e7, 2025}, + {0x82e8, 7141}, + {0x82ea, 7156}, + {0x82eb, 7145}, + {0x82ec, 7148}, + {0x82ed, 7161}, + {0x82ef, 2045}, + {0x82f0, 7155}, + {0x82f1, 2037}, + {0x82f2, 7150}, + {0x82f3, 7160}, + {0x82f4, 7147}, + {0x82f5, 7151}, + {0x82f6, 7154}, + {0x82f9, 7139}, + {0x82fa, 7159}, + {0x82fb, 7153}, + {0x82fe, 7138}, + {0x8300, 7142}, + {0x8301, 2038}, + {0x8302, 2033}, + {0x8303, 2026}, + {0x8304, 2031}, + {0x8305, 2027}, + {0x8306, 2046}, + {0x8307, 7140}, + {0x8308, 7632}, + {0x8309, 2034}, + {0x830c, 7152}, + {0x830d, 6781}, + {0x8316, 7635}, + {0x8317, 2474}, + {0x8319, 7619}, + {0x831b, 7630}, + {0x831c, 7626}, + {0x831e, 7645}, + {0x8320, 7637}, + {0x8322, 7627}, + {0x8324, 7636}, + {0x8325, 7621}, + {0x8326, 7625}, + {0x8327, 7648}, + {0x8328, 2477}, + {0x8329, 7640}, + {0x832a, 7631}, + {0x832b, 2461}, + {0x832c, 7646}, + {0x832d, 7617}, + {0x832f, 7639}, + {0x8331, 2476}, + {0x8332, 2471}, + {0x8333, 7616}, + {0x8334, 2469}, + {0x8335, 2468}, + {0x8336, 2473}, + {0x8337, 7638}, + {0x8338, 2465}, + {0x8339, 2472}, + {0x833a, 7144}, + {0x833b, 8848}, + {0x833c, 7633}, + {0x833f, 7623}, + {0x8340, 2475}, + {0x8341, 7624}, + {0x8342, 7628}, + {0x8343, 2478}, + {0x8344, 7618}, + {0x8345, 7642}, + {0x8347, 7641}, + {0x8348, 7649}, + {0x8349, 2467}, + {0x834a, 2464}, + {0x834b, 7647}, + {0x834c, 7643}, + {0x834d, 7634}, + {0x834e, 7629}, + {0x834f, 2470}, + {0x8350, 2466}, + {0x8351, 7620}, + {0x8352, 2462}, + {0x8353, 7644}, + {0x8354, 2463}, + {0x8356, 7622}, + {0x8373, 8223}, + {0x8374, 8225}, + {0x8375, 8230}, + {0x8376, 8250}, + {0x8377, 2947}, + {0x8378, 2937}, + {0x837a, 8222}, + {0x837b, 2948}, + {0x837c, 2949}, + {0x837d, 8233}, + {0x837e, 8240}, + {0x837f, 8246}, + {0x8381, 8227}, + {0x8383, 8234}, + {0x8386, 2950}, + {0x8387, 8248}, + {0x8388, 8243}, + {0x8389, 2945}, + {0x838a, 2943}, + {0x838b, 8239}, + {0x838c, 8235}, + {0x838d, 8221}, + {0x838e, 2934}, + {0x838f, 8226}, + {0x8390, 8218}, + {0x8392, 2942}, + {0x8393, 2944}, + {0x8394, 8231}, + {0x8395, 8228}, + {0x8396, 2939}, + {0x8397, 8244}, + {0x8398, 2936}, + {0x8399, 8229}, + {0x839a, 8889}, + {0x839b, 8237}, + {0x839d, 8236}, + {0x839e, 2935}, + {0x83a0, 2946}, + {0x83a2, 2938}, + {0x83a3, 8219}, + {0x83a4, 8224}, + {0x83a5, 8241}, + {0x83a6, 8247}, + {0x83a7, 2951}, + {0x83a8, 8220}, + {0x83a9, 8232}, + {0x83aa, 8238}, + {0x83ab, 2941}, + {0x83ae, 8249}, + {0x83af, 8242}, + {0x83b0, 8245}, + {0x83bd, 2940}, + {0x83bf, 8864}, + {0x83c0, 8852}, + {0x83c1, 3381}, + {0x83c2, 8881}, + {0x83c3, 8890}, + {0x83c4, 8893}, + {0x83c5, 3379}, + {0x83c6, 8860}, + {0x83c7, 8885}, + {0x83c8, 8861}, + {0x83c9, 8875}, + {0x83ca, 3392}, + {0x83cb, 8871}, + {0x83cc, 3389}, + {0x83ce, 8872}, + {0x83cf, 8849}, + {0x83d1, 8886}, + {0x83d4, 3398}, + {0x83d5, 8883}, + {0x83d6, 8873}, + {0x83d7, 8895}, + {0x83d8, 8868}, + {0x83d9, 9550}, + {0x83db, 8898}, + {0x83dc, 3396}, + {0x83dd, 8866}, + {0x83de, 8878}, + {0x83df, 3399}, + {0x83e0, 3378}, + {0x83e1, 8870}, + {0x83e2, 8896}, + {0x83e3, 8863}, + {0x83e4, 8856}, + {0x83e5, 8867}, + {0x83e7, 8855}, + {0x83e8, 8853}, + {0x83e9, 3374}, + {0x83ea, 8887}, + {0x83eb, 8862}, + {0x83ec, 8891}, + {0x83ee, 8892}, + {0x83ef, 3382}, + {0x83f0, 3387}, + {0x83f1, 3383}, + {0x83f2, 3391}, + {0x83f3, 8882}, + {0x83f4, 3384}, + {0x83f5, 8874}, + {0x83f6, 8858}, + {0x83f8, 3376}, + {0x83f9, 8850}, + {0x83fa, 8884}, + {0x83fb, 8894}, + {0x83fc, 8857}, + {0x83fd, 3390}, + {0x83fe, 8899}, + {0x83ff, 8869}, + {0x8401, 8865}, + {0x8403, 3375}, + {0x8404, 3395}, + {0x8406, 8880}, + {0x8407, 3397}, + {0x8409, 8876}, + {0x840a, 3386}, + {0x840b, 3380}, + {0x840c, 3388}, + {0x840d, 3377}, + {0x840e, 3394}, + {0x840f, 8877}, + {0x8410, 8859}, + {0x8411, 8879}, + {0x8412, 8854}, + {0x8413, 8888}, + {0x841b, 8897}, + {0x8423, 8851}, + {0x8429, 9549}, + {0x842b, 9571}, + {0x842c, 3756}, + {0x842d, 9554}, + {0x842f, 9552}, + {0x8430, 9531}, + {0x8431, 3806}, + {0x8432, 9547}, + {0x8433, 9567}, + {0x8434, 9543}, + {0x8435, 3814}, + {0x8436, 9566}, + {0x8437, 9541}, + {0x8438, 3393}, + {0x8439, 9557}, + {0x843a, 9542}, + {0x843b, 9564}, + {0x843c, 3813}, + {0x843d, 3805}, + {0x843f, 9520}, + {0x8440, 9528}, + {0x8442, 9553}, + {0x8443, 9545}, + {0x8444, 9570}, + {0x8445, 9548}, + {0x8446, 3819}, + {0x8447, 9565}, + {0x8449, 3810}, + {0x844b, 9551}, + {0x844c, 9559}, + {0x844d, 9532}, + {0x844e, 9558}, + {0x8450, 9575}, + {0x8451, 9527}, + {0x8452, 9560}, + {0x8454, 9573}, + {0x8456, 9521}, + {0x8457, 3385}, + {0x8459, 9535}, + {0x845a, 9534}, + {0x845b, 3812}, + {0x845d, 9538}, + {0x845e, 9540}, + {0x845f, 9555}, + {0x8460, 9572}, + {0x8461, 3815}, + {0x8463, 3816}, + {0x8465, 9526}, + {0x8466, 3808}, + {0x8467, 9530}, + {0x8468, 9568}, + {0x8469, 3817}, + {0x846b, 3809}, + {0x846c, 3811}, + {0x846d, 3818}, + {0x846e, 9574}, + {0x846f, 9561}, + {0x8470, 9556}, + {0x8473, 9537}, + {0x8474, 9536}, + {0x8475, 3807}, + {0x8476, 9522}, + {0x8477, 3804}, + {0x8478, 9546}, + {0x8479, 9523}, + {0x847a, 9544}, + {0x847d, 9533}, + {0x847e, 9569}, + {0x8482, 3803}, + {0x8486, 9529}, + {0x848d, 9525}, + {0x848e, 9563}, + {0x848f, 9524}, + {0x8490, 4238}, + {0x8499, 4230}, + {0x849c, 4233}, + {0x849e, 4231}, + {0x84b2, 4232}, + {0x84b8, 4235}, + {0x84bc, 4239}, + {0x84bf, 4227}, + {0x84c0, 4236}, + {0x84c4, 4229}, + {0x84c5, 9562}, + {0x84c6, 4228}, + {0x84c9, 4226}, + {0x84ca, 4241}, + {0x84cb, 4234}, + {0x84d1, 4240}, + {0x84d3, 4237}, + {0x84e8, 0}, + {0x84ec, 4603}, + {0x84ee, 4595}, + {0x84f1, 9519}, + {0x84ff, 4605}, + {0x8506, 4606}, + {0x8507, 9539}, + {0x8511, 4599}, + {0x8513, 4598}, + {0x8514, 4602}, + {0x8517, 4592}, + {0x851a, 4594}, + {0x8521, 4601}, + {0x8523, 4600}, + {0x8525, 4604}, + {0x852c, 4596}, + {0x852d, 4597}, + {0x853d, 4593}, + {0x8543, 4923}, + {0x8548, 4920}, + {0x8549, 4924}, + {0x854a, 4918}, + {0x8559, 4919}, + {0x855e, 4927}, + {0x8568, 4921}, + {0x8569, 4922}, + {0x856a, 4926}, + {0x856d, 4925}, + {0x8570, 0}, + {0x857e, 5212}, + {0x8584, 5211}, + {0x8587, 5218}, + {0x858a, 5220}, + {0x8591, 5214}, + {0x8594, 5215}, + {0x859b, 5217}, + {0x859c, 5213}, + {0x85a6, 5221}, + {0x85a8, 5219}, + {0x85a9, 5404}, + {0x85aa, 5210}, + {0x85af, 5216}, + {0x85b0, 5408}, + {0x85b9, 5410}, + {0x85ba, 5409}, + {0x85c9, 5407}, + {0x85cd, 5405}, + {0x85cf, 5403}, + {0x85d0, 5406}, + {0x85d5, 5559}, + {0x85dd, 5557}, + {0x85e4, 5560}, + {0x85e5, 5561}, + {0x85e9, 5556}, + {0x85ea, 5558}, + {0x85f7, 5562}, + {0x85f9, 5688}, + {0x85fa, 5690}, + {0x85fb, 5687}, + {0x8606, 5691}, + {0x8607, 5693}, + {0x860a, 5694}, + {0x860b, 5692}, + {0x8611, 5689}, + {0x8617, 5765}, + {0x861a, 5767}, + {0x862d, 5766}, + {0x8635, 0}, + {0x8638, 5895}, + {0x863f, 5896}, + {0x8647, 0}, + {0x8648, 1}, + {0x864d, 6168}, + {0x864e, 1673}, + {0x8650, 2047}, + {0x8652, 7651}, + {0x8653, 7650}, + {0x8654, 2479}, + {0x8655, 2952}, + {0x8656, 8252}, + {0x8659, 8251}, + {0x865b, 3400}, + {0x865c, 3821}, + {0x865e, 3820}, + {0x865f, 3822}, + {0x8667, 5222}, + {0x866b, 1039}, + {0x866d, 6726}, + {0x866e, 6727}, + {0x866f, 6725}, + {0x8670, 6724}, + {0x8671, 1674}, + {0x8673, 7165}, + {0x8674, 7163}, + {0x8677, 7162}, + {0x8679, 2048}, + {0x867a, 2050}, + {0x867b, 2049}, + {0x867c, 7164}, + {0x8685, 7663}, + {0x8686, 7660}, + {0x8687, 7658}, + {0x868a, 2480}, + {0x868b, 7661}, + {0x868c, 2485}, + {0x868d, 7655}, + {0x868e, 7670}, + {0x8690, 7672}, + {0x8691, 7656}, + {0x8693, 2482}, + {0x8694, 7673}, + {0x8695, 7668}, + {0x8696, 7654}, + {0x8697, 7659}, + {0x8698, 7669}, + {0x8699, 7665}, + {0x869a, 7662}, + {0x869c, 2487}, + {0x869d, 7671}, + {0x869e, 7657}, + {0x86a1, 7666}, + {0x86a2, 7652}, + {0x86a3, 2486}, + {0x86a4, 2483}, + {0x86a5, 7664}, + {0x86a7, 7667}, + {0x86a8, 7653}, + {0x86a9, 2484}, + {0x86aa, 2481}, + {0x86af, 2962}, + {0x86b0, 8259}, + {0x86b1, 2961}, + {0x86b3, 8262}, + {0x86b4, 8265}, + {0x86b5, 2958}, + {0x86b6, 2956}, + {0x86b7, 8254}, + {0x86b8, 8263}, + {0x86b9, 8261}, + {0x86ba, 8258}, + {0x86bb, 8266}, + {0x86bc, 8267}, + {0x86bd, 8269}, + {0x86be, 8270}, + {0x86bf, 8253}, + {0x86c0, 2955}, + {0x86c1, 8256}, + {0x86c2, 8255}, + {0x86c3, 8268}, + {0x86c4, 2957}, + {0x86c5, 8257}, + {0x86c6, 2959}, + {0x86c7, 2954}, + {0x86c8, 8260}, + {0x86c9, 2963}, + {0x86cb, 2960}, + {0x86cc, 8264}, + {0x86d0, 3407}, + {0x86d1, 8914}, + {0x86d3, 8903}, + {0x86d4, 3404}, + {0x86d6, 9581}, + {0x86d7, 8912}, + {0x86d8, 8900}, + {0x86d9, 3402}, + {0x86da, 8905}, + {0x86db, 3405}, + {0x86dc, 8909}, + {0x86dd, 8907}, + {0x86de, 3408}, + {0x86df, 3401}, + {0x86e2, 8901}, + {0x86e3, 8904}, + {0x86e4, 3406}, + {0x86e6, 8902}, + {0x86e8, 8913}, + {0x86e9, 8911}, + {0x86ea, 8906}, + {0x86eb, 8908}, + {0x86ec, 8910}, + {0x86ed, 3403}, + {0x86f5, 9582}, + {0x86f6, 9588}, + {0x86f7, 9578}, + {0x86f8, 9584}, + {0x86f9, 3823}, + {0x86fa, 9580}, + {0x86fb, 3829}, + {0x86fe, 3828}, + {0x8700, 3827}, + {0x8701, 9587}, + {0x8702, 3830}, + {0x8703, 3831}, + {0x8704, 9577}, + {0x8705, 9590}, + {0x8706, 3832}, + {0x8707, 3826}, + {0x8708, 3825}, + {0x8709, 9586}, + {0x870a, 3833}, + {0x870b, 9576}, + {0x870c, 9579}, + {0x870d, 9589}, + {0x870e, 9585}, + {0x8713, 3824}, + {0x8718, 4248}, + {0x871c, 4243}, + {0x8722, 4245}, + {0x8725, 4246}, + {0x8727, 0}, + {0x8729, 4251}, + {0x8734, 4247}, + {0x8737, 4250}, + {0x873b, 4244}, + {0x873f, 4242}, + {0x874c, 4616}, + {0x874d, 9583}, + {0x8753, 4617}, + {0x8755, 4249}, + {0x8757, 4615}, + {0x8759, 4614}, + {0x8760, 4610}, + {0x8764, 0}, + {0x8766, 4611}, + {0x8768, 4613}, + {0x8774, 4608}, + {0x8776, 4609}, + {0x8778, 4612}, + {0x8782, 4607}, + {0x8783, 4928}, + {0x878d, 4932}, + {0x8791, 0}, + {0x879e, 4930}, + {0x879f, 4929}, + {0x87a2, 4931}, + {0x87ab, 5228}, + {0x87b3, 5225}, + {0x87ba, 5230}, + {0x87bb, 5229}, + {0x87c0, 5223}, + {0x87c6, 5227}, + {0x87c8, 5231}, + {0x87cb, 5232}, + {0x87d1, 5224}, + {0x87d2, 5226}, + {0x87e0, 5414}, + {0x87ec, 5412}, + {0x87ef, 5411}, + {0x87f2, 5413}, + {0x87f7, 0}, + {0x87f9, 5566}, + {0x87fb, 5563}, + {0x87fe, 5567}, + {0x8805, 5564}, + {0x880d, 5565}, + {0x8811, 0}, + {0x8814, 5695}, + {0x8815, 5696}, + {0x881f, 5771}, + {0x8821, 5770}, + {0x8822, 5769}, + {0x8823, 5768}, + {0x8831, 5897}, + {0x8836, 5928}, + {0x8839, 5929}, + {0x883b, 5959}, + {0x8840, 1040}, + {0x8841, 7166}, + {0x8843, 7674}, + {0x8844, 7675}, + {0x8846, 0}, + {0x8848, 8915}, + {0x884c, 1041}, + {0x884d, 2051}, + {0x884e, 7167}, + {0x8852, 8271}, + {0x8853, 2964}, + {0x8855, 8917}, + {0x8856, 8916}, + {0x8857, 3409}, + {0x8859, 3834}, + {0x885b, 4618}, + {0x885d, 4619}, + {0x8861, 4933}, + {0x8862, 5930}, + {0x8863, 1042}, + {0x8867, 7168}, + {0x8868, 1676}, + {0x8869, 7170}, + {0x886a, 7169}, + {0x886b, 2052}, + {0x886d, 7676}, + {0x886f, 7683}, + {0x8870, 2488}, + {0x8871, 7681}, + {0x8872, 7679}, + {0x8874, 7686}, + {0x8875, 7677}, + {0x8876, 7678}, + {0x8877, 2489}, + {0x8879, 2493}, + {0x887c, 7687}, + {0x887d, 2492}, + {0x887e, 7685}, + {0x887f, 7682}, + {0x8880, 7680}, + {0x8881, 2490}, + {0x8882, 2491}, + {0x8883, 7684}, + {0x8888, 2966}, + {0x8889, 8272}, + {0x888b, 2971}, + {0x888c, 8288}, + {0x888d, 2970}, + {0x888e, 8290}, + {0x8891, 8278}, + {0x8892, 2968}, + {0x8893, 8289}, + {0x8895, 8273}, + {0x8896, 2969}, + {0x8897, 8285}, + {0x8898, 8281}, + {0x8899, 8283}, + {0x889a, 8277}, + {0x889b, 8284}, + {0x889e, 2965}, + {0x889f, 8280}, + {0x88a1, 8279}, + {0x88a2, 8275}, + {0x88a4, 8286}, + {0x88a7, 8282}, + {0x88a8, 8274}, + {0x88aa, 8276}, + {0x88ab, 2967}, + {0x88ac, 8287}, + {0x88b1, 3412}, + {0x88b2, 8928}, + {0x88b5, 0}, + {0x88b6, 8924}, + {0x88b7, 8926}, + {0x88b8, 8921}, + {0x88b9, 8920}, + {0x88ba, 8918}, + {0x88bc, 8925}, + {0x88bd, 8927}, + {0x88be, 8923}, + {0x88c0, 8922}, + {0x88c1, 3410}, + {0x88c2, 3411}, + {0x88c9, 8930}, + {0x88ca, 3842}, + {0x88cb, 9592}, + {0x88cc, 9598}, + {0x88cd, 9593}, + {0x88ce, 9594}, + {0x88d0, 9599}, + {0x88d2, 3844}, + {0x88d4, 3836}, + {0x88d5, 3843}, + {0x88d6, 9591}, + {0x88d7, 8919}, + {0x88d8, 3839}, + {0x88d9, 3837}, + {0x88da, 9597}, + {0x88db, 9596}, + {0x88dc, 3838}, + {0x88dd, 3840}, + {0x88de, 9595}, + {0x88df, 3835}, + {0x88e1, 3841}, + {0x88e8, 4258}, + {0x88ef, 4260}, + {0x88f2, 0}, + {0x88f3, 4252}, + {0x88f4, 4254}, + {0x88f8, 4256}, + {0x88f9, 4255}, + {0x88fd, 4257}, + {0x8901, 8929}, + {0x8902, 4253}, + {0x8907, 4621}, + {0x890a, 4625}, + {0x8910, 4620}, + {0x8912, 4622}, + {0x8913, 4623}, + {0x8915, 4624}, + {0x8918, 0}, + {0x8919, 1}, + {0x891a, 4259}, + {0x8921, 4938}, + {0x8925, 4936}, + {0x892a, 4934}, + {0x892b, 4937}, + {0x892e, 0}, + {0x8932, 4935}, + {0x8936, 5234}, + {0x8938, 5236}, + {0x893b, 5233}, + {0x893d, 5237}, + {0x8944, 5235}, + {0x8951, 0}, + {0x8956, 5570}, + {0x895b, 0}, + {0x895e, 5571}, + {0x895f, 5569}, + {0x8960, 5568}, + {0x8964, 5697}, + {0x896a, 5772}, + {0x896c, 5773}, + {0x896f, 5846}, + {0x8972, 5845}, + {0x897a, 0}, + {0x897e, 6169}, + {0x897f, 1043}, + {0x8981, 2053}, + {0x8982, 8291}, + {0x8983, 3413}, + {0x8985, 9600}, + {0x8986, 5415}, + {0x898b, 1288}, + {0x898f, 2973}, + {0x8993, 2972}, + {0x8995, 8931}, + {0x8996, 3414}, + {0x8997, 8933}, + {0x8998, 8932}, + {0x899b, 9601}, + {0x899c, 3845}, + {0x89a6, 4940}, + {0x89aa, 4939}, + {0x89ac, 5238}, + {0x89b2, 5416}, + {0x89ba, 5698}, + {0x89bd, 5774}, + {0x89c0, 5960}, + {0x89d2, 1289}, + {0x89d3, 7171}, + {0x89d4, 2054}, + {0x89d5, 8294}, + {0x89d6, 8292}, + {0x89d9, 8293}, + {0x89da, 8935}, + {0x89db, 8936}, + {0x89dc, 9608}, + {0x89dd, 8934}, + {0x89df, 9602}, + {0x89e0, 9606}, + {0x89e1, 9605}, + {0x89e2, 9607}, + {0x89e3, 3846}, + {0x89e4, 9604}, + {0x89e5, 9603}, + {0x89e6, 9609}, + {0x89f3, 0}, + {0x89f4, 5417}, + {0x89f8, 5699}, + {0x89fc, 5847}, + {0x8a00, 1290}, + {0x8a02, 2056}, + {0x8a03, 2057}, + {0x8a04, 7172}, + {0x8a07, 7173}, + {0x8a08, 2055}, + {0x8a0a, 2499}, + {0x8a0c, 2497}, + {0x8a0e, 2496}, + {0x8a0f, 2503}, + {0x8a10, 2495}, + {0x8a11, 2504}, + {0x8a12, 7688}, + {0x8a13, 2501}, + {0x8a15, 2498}, + {0x8a16, 2502}, + {0x8a17, 2500}, + {0x8a18, 2494}, + {0x8a1b, 2981}, + {0x8a1d, 2975}, + {0x8a1e, 8298}, + {0x8a1f, 2980}, + {0x8a22, 2982}, + {0x8a23, 2976}, + {0x8a25, 2977}, + {0x8a27, 8296}, + {0x8a2a, 2974}, + {0x8a2c, 8297}, + {0x8a2d, 2979}, + {0x8a30, 8295}, + {0x8a31, 2978}, + {0x8a34, 3425}, + {0x8a36, 3427}, + {0x8a39, 8939}, + {0x8a3a, 3426}, + {0x8a3b, 3415}, + {0x8a3c, 3419}, + {0x8a3e, 3865}, + {0x8a3f, 9614}, + {0x8a40, 8941}, + {0x8a41, 3420}, + {0x8a44, 8944}, + {0x8a45, 8945}, + {0x8a46, 3424}, + {0x8a48, 8947}, + {0x8a4a, 8949}, + {0x8a4c, 8950}, + {0x8a4d, 8938}, + {0x8a4e, 8937}, + {0x8a4f, 8951}, + {0x8a50, 3423}, + {0x8a51, 8948}, + {0x8a52, 8946}, + {0x8a54, 3421}, + {0x8a55, 3417}, + {0x8a56, 3428}, + {0x8a57, 8942}, + {0x8a58, 8943}, + {0x8a59, 8940}, + {0x8a5b, 3422}, + {0x8a5e, 3418}, + {0x8a60, 3416}, + {0x8a61, 9613}, + {0x8a62, 3860}, + {0x8a63, 3855}, + {0x8a66, 3850}, + {0x8a68, 3866}, + {0x8a69, 3851}, + {0x8a6b, 3847}, + {0x8a6c, 3862}, + {0x8a6d, 3859}, + {0x8a6e, 3861}, + {0x8a70, 3852}, + {0x8a71, 3857}, + {0x8a72, 3848}, + {0x8a73, 3849}, + {0x8a74, 9621}, + {0x8a75, 9618}, + {0x8a76, 9610}, + {0x8a77, 9615}, + {0x8a79, 3863}, + {0x8a7a, 9622}, + {0x8a7b, 3864}, + {0x8a7c, 3854}, + {0x8a7f, 9612}, + {0x8a81, 9620}, + {0x8a82, 9616}, + {0x8a83, 9619}, + {0x8a84, 9617}, + {0x8a85, 3858}, + {0x8a86, 9611}, + {0x8a87, 3853}, + {0x8a8c, 4262}, + {0x8a8d, 4265}, + {0x8a91, 4273}, + {0x8a93, 4267}, + {0x8a95, 4630}, + {0x8a98, 4272}, + {0x8a9a, 4274}, + {0x8a9e, 4263}, + {0x8aa0, 3856}, + {0x8aa1, 4266}, + {0x8aa3, 4264}, + {0x8aa4, 4268}, + {0x8aa5, 4270}, + {0x8aa6, 4261}, + {0x8aa7, 4275}, + {0x8aa8, 4271}, + {0x8aaa, 4269}, + {0x8ab0, 4637}, + {0x8ab2, 4633}, + {0x8ab6, 4640}, + {0x8ab9, 4641}, + {0x8abc, 4626}, + {0x8abf, 4636}, + {0x8ac2, 4635}, + {0x8ac4, 4629}, + {0x8ac7, 4628}, + {0x8ac9, 4634}, + {0x8acb, 4631}, + {0x8acd, 4639}, + {0x8ad2, 4627}, + {0x8ad5, 0}, + {0x8ad6, 4638}, + {0x8adb, 4642}, + {0x8adc, 4946}, + {0x8ae6, 4941}, + {0x8ae7, 4947}, + {0x8aeb, 4943}, + {0x8aed, 4953}, + {0x8aee, 4948}, + {0x8af1, 4944}, + {0x8af3, 4954}, + {0x8af5, 0}, + {0x8af6, 4955}, + {0x8af7, 4952}, + {0x8af8, 4632}, + {0x8afa, 4942}, + {0x8afc, 4956}, + {0x8afe, 4949}, + {0x8b00, 4945}, + {0x8b01, 4950}, + {0x8b02, 4951}, + {0x8b04, 5246}, + {0x8b0a, 5243}, + {0x8b0e, 5239}, + {0x8b10, 5247}, + {0x8b17, 5240}, + {0x8b19, 5241}, + {0x8b1b, 5242}, + {0x8b1d, 5245}, + {0x8b20, 5244}, + {0x8b28, 5418}, + {0x8b2b, 5421}, + {0x8b2c, 5420}, + {0x8b39, 5419}, + {0x8b41, 5572}, + {0x8b46, 5579}, + {0x8b49, 5575}, + {0x8b4d, 0}, + {0x8b4e, 5577}, + {0x8b4f, 5578}, + {0x8b58, 5574}, + {0x8b59, 5580}, + {0x8b5a, 5576}, + {0x8b5c, 5573}, + {0x8b5f, 5704}, + {0x8b66, 5702}, + {0x8b6b, 5705}, + {0x8b6c, 5701}, + {0x8b6f, 5703}, + {0x8b70, 5700}, + {0x8b74, 5775}, + {0x8b77, 5776}, + {0x8b7b, 0}, + {0x8b7d, 5777}, + {0x8b80, 5848}, + {0x8b8a, 5898}, + {0x8b92, 5932}, + {0x8b93, 5931}, + {0x8b95, 0}, + {0x8b96, 5933}, + {0x8b99, 0}, + {0x8b9a, 5972}, + {0x8b9c, 5978}, + {0x8c37, 1291}, + {0x8c39, 8299}, + {0x8c3b, 8300}, + {0x8c3c, 9623}, + {0x8c3f, 5249}, + {0x8c41, 5248}, + {0x8c46, 1292}, + {0x8c47, 7689}, + {0x8c48, 2505}, + {0x8c49, 2983}, + {0x8c4a, 9625}, + {0x8c4b, 9624}, + {0x8c4c, 4643}, + {0x8c4e, 4644}, + {0x8c50, 5422}, + {0x8c54, 5987}, + {0x8c55, 1293}, + {0x8c56, 6728}, + {0x8c57, 7690}, + {0x8c5a, 2984}, + {0x8c5c, 8301}, + {0x8c5d, 8302}, + {0x8c5f, 8952}, + {0x8c61, 3429}, + {0x8c62, 3867}, + {0x8c64, 9627}, + {0x8c65, 9626}, + {0x8c66, 9628}, + {0x8c69, 0}, + {0x8c6a, 4276}, + {0x8c6b, 4957}, + {0x8c6c, 4645}, + {0x8c6d, 4958}, + {0x8c73, 5250}, + {0x8c78, 6375}, + {0x8c79, 2507}, + {0x8c7a, 2506}, + {0x8c7b, 7691}, + {0x8c7d, 8303}, + {0x8c80, 8954}, + {0x8c81, 8953}, + {0x8c82, 3430}, + {0x8c84, 9630}, + {0x8c85, 9631}, + {0x8c86, 9629}, + {0x8c89, 3869}, + {0x8c8a, 3868}, + {0x8c8c, 4278}, + {0x8c8d, 4277}, + {0x8c92, 0}, + {0x8c93, 4959}, + {0x8c9d, 1294}, + {0x8c9e, 2058}, + {0x8ca0, 2059}, + {0x8ca1, 2508}, + {0x8ca2, 2509}, + {0x8ca3, 7693}, + {0x8ca4, 7692}, + {0x8ca5, 8304}, + {0x8ca7, 2990}, + {0x8ca8, 2988}, + {0x8ca9, 2985}, + {0x8caa, 2989}, + {0x8cab, 2987}, + {0x8cac, 2986}, + {0x8caf, 3431}, + {0x8cb0, 8957}, + {0x8cb2, 3874}, + {0x8cb3, 3433}, + {0x8cb4, 3438}, + {0x8cb5, 8959}, + {0x8cb6, 3440}, + {0x8cb7, 3439}, + {0x8cb8, 3442}, + {0x8cb9, 8958}, + {0x8cba, 8955}, + {0x8cbb, 3436}, + {0x8cbc, 3432}, + {0x8cbd, 3434}, + {0x8cbe, 8956}, + {0x8cbf, 3441}, + {0x8cc0, 3437}, + {0x8cc1, 3435}, + {0x8cc2, 3876}, + {0x8cc3, 3875}, + {0x8cc4, 3873}, + {0x8cc5, 3877}, + {0x8cc7, 3871}, + {0x8cc8, 3872}, + {0x8cca, 3870}, + {0x8ccc, 9632}, + {0x8cd1, 4280}, + {0x8cd2, 4281}, + {0x8cd3, 4279}, + {0x8cdc, 4654}, + {0x8cde, 4647}, + {0x8ce0, 4646}, + {0x8ce1, 4656}, + {0x8ce2, 4652}, + {0x8ce3, 4653}, + {0x8ce4, 4649}, + {0x8ce6, 4648}, + {0x8cea, 4655}, + {0x8cec, 4650}, + {0x8ced, 4651}, + {0x8cf4, 4960}, + {0x8cf8, 5254}, + {0x8cfa, 5251}, + {0x8cfb, 5255}, + {0x8cfc, 5253}, + {0x8cfd, 5252}, + {0x8d05, 5423}, + {0x8d07, 0}, + {0x8d08, 5581}, + {0x8d0a, 5582}, + {0x8d0d, 5707}, + {0x8d0f, 5706}, + {0x8d13, 5778}, + {0x8d16, 5849}, + {0x8d17, 5850}, + {0x8d1b, 5935}, + {0x8d64, 1295}, + {0x8d66, 2992}, + {0x8d67, 2991}, + {0x8d68, 9633}, + {0x8d69, 9634}, + {0x8d6b, 4282}, + {0x8d6d, 4657}, + {0x8d70, 1296}, + {0x8d72, 7174}, + {0x8d73, 2061}, + {0x8d74, 2060}, + {0x8d76, 7694}, + {0x8d77, 2510}, + {0x8d78, 7695}, + {0x8d79, 8307}, + {0x8d7b, 8306}, + {0x8d7d, 8305}, + {0x8d80, 8961}, + {0x8d81, 3445}, + {0x8d84, 8960}, + {0x8d85, 3444}, + {0x8d89, 8962}, + {0x8d8a, 3443}, + {0x8d8c, 9636}, + {0x8d8d, 9639}, + {0x8d8e, 9637}, + {0x8d8f, 9638}, + {0x8d90, 9642}, + {0x8d91, 9635}, + {0x8d92, 9643}, + {0x8d93, 9640}, + {0x8d94, 9641}, + {0x8d95, 4284}, + {0x8d99, 4283}, + {0x8d9f, 4658}, + {0x8da3, 4659}, + {0x8da8, 5256}, + {0x8db3, 1297}, + {0x8db4, 2062}, + {0x8db5, 7696}, + {0x8db6, 7698}, + {0x8db7, 7697}, + {0x8db9, 8310}, + {0x8dba, 2994}, + {0x8dbc, 8308}, + {0x8dbe, 2993}, + {0x8dbf, 8311}, + {0x8dc1, 8312}, + {0x8dc2, 8309}, + {0x8dc5, 8974}, + {0x8dc6, 3453}, + {0x8dc7, 8966}, + {0x8dc8, 8972}, + {0x8dcb, 3448}, + {0x8dcc, 3451}, + {0x8dcd, 8965}, + {0x8dce, 3446}, + {0x8dcf, 8969}, + {0x8dd0, 9649}, + {0x8dd1, 3450}, + {0x8dd3, 8964}, + {0x8dd5, 8970}, + {0x8dd6, 8967}, + {0x8dd7, 8973}, + {0x8dd8, 8963}, + {0x8dd9, 8971}, + {0x8dda, 3449}, + {0x8ddb, 3452}, + {0x8ddc, 8968}, + {0x8ddd, 3447}, + {0x8ddf, 3879}, + {0x8de0, 9645}, + {0x8de1, 3878}, + {0x8de2, 9652}, + {0x8de3, 9651}, + {0x8de4, 3885}, + {0x8de6, 3886}, + {0x8de7, 9653}, + {0x8de8, 3880}, + {0x8de9, 9650}, + {0x8dea, 3884}, + {0x8deb, 9655}, + {0x8dec, 9646}, + {0x8dee, 9648}, + {0x8def, 3881}, + {0x8df0, 9644}, + {0x8df1, 9647}, + {0x8df2, 9654}, + {0x8df3, 3882}, + {0x8df4, 9656}, + {0x8dfa, 3883}, + {0x8dfc, 4285}, + {0x8e0f, 4664}, + {0x8e10, 4661}, + {0x8e1d, 4662}, + {0x8e1e, 4668}, + {0x8e1f, 4666}, + {0x8e21, 4667}, + {0x8e22, 4663}, + {0x8e27, 0}, + {0x8e29, 4665}, + {0x8e2b, 4660}, + {0x8e31, 4962}, + {0x8e34, 4963}, + {0x8e35, 4966}, + {0x8e39, 4965}, + {0x8e3d, 0}, + {0x8e42, 4964}, + {0x8e44, 4961}, + {0x8e48, 5259}, + {0x8e49, 5257}, + {0x8e4a, 5260}, + {0x8e4b, 5258}, + {0x8e55, 5429}, + {0x8e59, 5424}, + {0x8e5f, 5428}, + {0x8e63, 5425}, + {0x8e64, 5427}, + {0x8e66, 5426}, + {0x8e6c, 5587}, + {0x8e72, 5584}, + {0x8e74, 5589}, + {0x8e76, 5586}, + {0x8e7a, 5588}, + {0x8e7c, 5583}, + {0x8e81, 5709}, + {0x8e82, 5711}, + {0x8e85, 5710}, + {0x8e87, 5585}, + {0x8e89, 5708}, + {0x8e8a, 5779}, + {0x8e8b, 5781}, + {0x8e8d, 5780}, + {0x8e91, 5851}, + {0x8e93, 5852}, + {0x8e97, 0}, + {0x8e9f, 0}, + {0x8ea0, 1}, + {0x8ea1, 5961}, + {0x8eaa, 5979}, + {0x8eab, 1298}, + {0x8eac, 2511}, + {0x8eb2, 3887}, + {0x8eba, 4669}, + {0x8ec0, 5430}, + {0x8eca, 1299}, + {0x8ecb, 1677}, + {0x8ecc, 2064}, + {0x8ecd, 2063}, + {0x8ecf, 2514}, + {0x8ed1, 7699}, + {0x8ed2, 2512}, + {0x8ed3, 7700}, + {0x8ed4, 2513}, + {0x8ed7, 8317}, + {0x8ed8, 8313}, + {0x8edb, 2995}, + {0x8edc, 8316}, + {0x8edd, 8315}, + {0x8ede, 8314}, + {0x8edf, 2996}, + {0x8ee0, 8318}, + {0x8ee1, 8319}, + {0x8ee5, 8981}, + {0x8ee6, 8979}, + {0x8ee7, 8983}, + {0x8ee8, 8984}, + {0x8ee9, 8990}, + {0x8eeb, 8986}, + {0x8eec, 8988}, + {0x8eee, 8980}, + {0x8eef, 8975}, + {0x8ef1, 8987}, + {0x8ef4, 8989}, + {0x8ef5, 8982}, + {0x8ef6, 8985}, + {0x8ef7, 8976}, + {0x8ef8, 3455}, + {0x8ef9, 8978}, + {0x8efa, 8977}, + {0x8efb, 3454}, + {0x8efc, 3456}, + {0x8efe, 3890}, + {0x8eff, 9658}, + {0x8f00, 9660}, + {0x8f01, 9659}, + {0x8f02, 9664}, + {0x8f03, 3888}, + {0x8f05, 9661}, + {0x8f06, 9657}, + {0x8f07, 9662}, + {0x8f08, 9663}, + {0x8f09, 3889}, + {0x8f0a, 3891}, + {0x8f0b, 9665}, + {0x8f11, 0}, + {0x8f12, 4287}, + {0x8f13, 4289}, + {0x8f14, 4286}, + {0x8f15, 4288}, + {0x8f17, 0}, + {0x8f1b, 4671}, + {0x8f1c, 4676}, + {0x8f1d, 4670}, + {0x8f1e, 4677}, + {0x8f1f, 4672}, + {0x8f25, 4678}, + {0x8f26, 4674}, + {0x8f29, 4673}, + {0x8f2a, 4675}, + {0x8f2f, 4968}, + {0x8f33, 4970}, + {0x8f38, 4969}, + {0x8f3b, 4967}, + {0x8f3e, 5262}, + {0x8f3f, 5265}, + {0x8f42, 5263}, + {0x8f44, 5261}, + {0x8f45, 5264}, + {0x8f47, 0}, + {0x8f48, 1}, + {0x8f49, 5431}, + {0x8f4d, 5432}, + {0x8f4e, 5591}, + {0x8f50, 0}, + {0x8f54, 5590}, + {0x8f57, 0}, + {0x8f5f, 5782}, + {0x8f61, 5853}, + {0x8f67, 0}, + {0x8f9b, 1300}, + {0x8f9c, 3457}, + {0x8f9f, 3892}, + {0x8fa3, 4290}, + {0x8fa6, 4972}, + {0x8fa8, 4971}, + {0x8fad, 5592}, + {0x8fae, 5679}, + {0x8faf, 5783}, + {0x8fb0, 1301}, + {0x8fb1, 2515}, + {0x8fb2, 3893}, + {0x8fb5, 560}, + {0x8fbc, 0}, + {0x8fbf, 6377}, + {0x8fc2, 1302}, + {0x8fc4, 1305}, + {0x8fc5, 1304}, + {0x8fc6, 1303}, + {0x8fc9, 6376}, + {0x8fcb, 6730}, + {0x8fcd, 6732}, + {0x8fce, 1678}, + {0x8fd1, 1680}, + {0x8fd2, 6729}, + {0x8fd3, 6731}, + {0x8fd4, 1679}, + {0x8fd5, 6734}, + {0x8fd6, 6733}, + {0x8fd7, 6735}, + {0x8fe0, 7178}, + {0x8fe1, 7176}, + {0x8fe2, 2067}, + {0x8fe3, 7175}, + {0x8fe4, 2072}, + {0x8fe5, 2069}, + {0x8fe6, 2066}, + {0x8fe8, 2073}, + {0x8fea, 2068}, + {0x8feb, 2071}, + {0x8fed, 2070}, + {0x8fee, 7177}, + {0x8ff0, 2065}, + {0x8ff4, 2521}, + {0x8ff5, 7702}, + {0x8ff6, 7708}, + {0x8ff7, 2518}, + {0x8ff8, 2525}, + {0x8ffa, 2520}, + {0x8ffb, 7705}, + {0x8ffc, 7707}, + {0x8ffd, 2523}, + {0x8ffe, 7701}, + {0x8fff, 7704}, + {0x9000, 2519}, + {0x9001, 2516}, + {0x9002, 7703}, + {0x9003, 2522}, + {0x9004, 7706}, + {0x9005, 2524}, + {0x9006, 2517}, + {0x900b, 8321}, + {0x900c, 8324}, + {0x900d, 2998}, + {0x900f, 3008}, + {0x9010, 3004}, + {0x9011, 8322}, + {0x9014, 3012}, + {0x9015, 3005}, + {0x9016, 3010}, + {0x9017, 3000}, + {0x9019, 2997}, + {0x901a, 2999}, + {0x901b, 3011}, + {0x901c, 8323}, + {0x901d, 3003}, + {0x901e, 3006}, + {0x901f, 3002}, + {0x9020, 3007}, + {0x9021, 8325}, + {0x9022, 3009}, + {0x9023, 3001}, + {0x9024, 8320}, + {0x902d, 8991}, + {0x902e, 3458}, + {0x902f, 8993}, + {0x9031, 3460}, + {0x9032, 3462}, + {0x9034, 8992}, + {0x9035, 3459}, + {0x9036, 3463}, + {0x9038, 3461}, + {0x903c, 3899}, + {0x903d, 9670}, + {0x903e, 3907}, + {0x903f, 9667}, + {0x9041, 3908}, + {0x9042, 3897}, + {0x9044, 9668}, + {0x9047, 3902}, + {0x9049, 9669}, + {0x904a, 3895}, + {0x904b, 3894}, + {0x904d, 3905}, + {0x904e, 3904}, + {0x904f, 3903}, + {0x9050, 3901}, + {0x9051, 3906}, + {0x9052, 9666}, + {0x9053, 3896}, + {0x9054, 3898}, + {0x9055, 3900}, + {0x9058, 4292}, + {0x9059, 4295}, + {0x905b, 4299}, + {0x905c, 4293}, + {0x905d, 4298}, + {0x905e, 4296}, + {0x9060, 4291}, + {0x9062, 4297}, + {0x9063, 4294}, + {0x9068, 4681}, + {0x9069, 4679}, + {0x906d, 4682}, + {0x906e, 4680}, + {0x9072, 4976}, + {0x9074, 4974}, + {0x9075, 4973}, + {0x9077, 4683}, + {0x9078, 4975}, + {0x907a, 4978}, + {0x907c, 4977}, + {0x907d, 5267}, + {0x907f, 5266}, + {0x9080, 5271}, + {0x9081, 5269}, + {0x9082, 5270}, + {0x9083, 5434}, + {0x9084, 5268}, + {0x9087, 5433}, + {0x9088, 5435}, + {0x908a, 5593}, + {0x908b, 5594}, + {0x908f, 5900}, + {0x9090, 5899}, + {0x9091, 1307}, + {0x9094, 6174}, + {0x9095, 2526}, + {0x9097, 6171}, + {0x9098, 6172}, + {0x9099, 6170}, + {0x909b, 6173}, + {0x909e, 6381}, + {0x909f, 6378}, + {0x90a0, 6383}, + {0x90a1, 6379}, + {0x90a2, 1308}, + {0x90a3, 1311}, + {0x90a5, 6380}, + {0x90a6, 1310}, + {0x90a7, 6382}, + {0x90aa, 1309}, + {0x90af, 6738}, + {0x90b0, 6740}, + {0x90b1, 1683}, + {0x90b2, 6736}, + {0x90b3, 6739}, + {0x90b4, 6737}, + {0x90b5, 1681}, + {0x90b6, 1684}, + {0x90b8, 1682}, + {0x90bd, 7180}, + {0x90be, 7184}, + {0x90bf, 7181}, + {0x90c1, 2076}, + {0x90c3, 2077}, + {0x90c5, 7183}, + {0x90c7, 7185}, + {0x90c8, 7187}, + {0x90ca, 2074}, + {0x90cb, 7186}, + {0x90ce, 2075}, + {0x90d4, 8332}, + {0x90d5, 7182}, + {0x90d6, 7709}, + {0x90d7, 7718}, + {0x90d8, 7716}, + {0x90d9, 7711}, + {0x90da, 7712}, + {0x90db, 7717}, + {0x90dc, 7719}, + {0x90dd, 2528}, + {0x90df, 7714}, + {0x90e0, 7710}, + {0x90e1, 2527}, + {0x90e2, 2529}, + {0x90e3, 7713}, + {0x90e4, 7720}, + {0x90e5, 7715}, + {0x90e8, 3013}, + {0x90e9, 8335}, + {0x90ea, 8327}, + {0x90eb, 8333}, + {0x90ec, 8334}, + {0x90ed, 3014}, + {0x90ef, 8326}, + {0x90f0, 8328}, + {0x90f1, 7179}, + {0x90f2, 8330}, + {0x90f3, 8331}, + {0x90f4, 8329}, + {0x90f5, 3465}, + {0x90f9, 9000}, + {0x90fb, 9001}, + {0x90fc, 8998}, + {0x90fd, 3015}, + {0x90fe, 3467}, + {0x90ff, 8997}, + {0x9100, 9003}, + {0x9101, 9002}, + {0x9102, 3464}, + {0x9103, 9006}, + {0x9104, 8996}, + {0x9105, 9005}, + {0x9106, 8994}, + {0x9107, 9004}, + {0x9108, 8999}, + {0x9109, 3466}, + {0x910b, 9677}, + {0x910d, 9672}, + {0x910e, 9678}, + {0x910f, 9673}, + {0x9110, 9671}, + {0x9111, 9674}, + {0x9112, 3909}, + {0x9114, 9676}, + {0x9116, 9675}, + {0x9117, 3910}, + {0x9118, 4301}, + {0x9119, 4300}, + {0x911e, 4302}, + {0x9127, 4686}, + {0x912a, 0}, + {0x912c, 8995}, + {0x912d, 4685}, + {0x9130, 4684}, + {0x9131, 4687}, + {0x9134, 4979}, + {0x9136, 0}, + {0x9139, 5272}, + {0x913b, 0}, + {0x9145, 0}, + {0x9148, 5854}, + {0x9149, 1312}, + {0x914a, 2079}, + {0x914b, 2078}, + {0x914c, 2532}, + {0x914d, 2531}, + {0x914e, 7722}, + {0x914f, 7723}, + {0x9150, 7721}, + {0x9152, 2530}, + {0x9153, 8339}, + {0x9155, 8340}, + {0x9156, 8336}, + {0x9157, 3016}, + {0x9158, 8337}, + {0x915a, 8338}, + {0x915f, 9009}, + {0x9160, 9011}, + {0x9161, 9007}, + {0x9162, 9010}, + {0x9163, 3468}, + {0x9164, 9008}, + {0x9165, 3469}, + {0x9168, 9186}, + {0x9169, 3913}, + {0x916a, 3912}, + {0x916c, 3911}, + {0x916e, 9679}, + {0x916f, 9680}, + {0x9174, 4306}, + {0x9175, 4303}, + {0x9177, 4305}, + {0x9178, 4304}, + {0x9182, 0}, + {0x9183, 4691}, + {0x9186, 0}, + {0x9187, 4688}, + {0x9189, 4689}, + {0x918b, 4690}, + {0x9191, 0}, + {0x9192, 4980}, + {0x919c, 5275}, + {0x919e, 5274}, + {0x91a3, 5273}, + {0x91ab, 5436}, + {0x91ac, 5437}, + {0x91ae, 5596}, + {0x91b1, 5595}, + {0x91b3, 0}, + {0x91b4, 5712}, + {0x91ba, 5784}, + {0x91c0, 5936}, + {0x91c1, 5962}, + {0x91c5, 5980}, + {0x91c6, 1313}, + {0x91c7, 1685}, + {0x91c9, 3914}, + {0x91cb, 5713}, + {0x91cc, 1314}, + {0x91cd, 2080}, + {0x91ce, 3017}, + {0x91cf, 3470}, + {0x91d0, 5438}, + {0x91d1, 1686}, + {0x91d3, 7189}, + {0x91d4, 7188}, + {0x91d5, 7724}, + {0x91d7, 2535}, + {0x91d8, 2533}, + {0x91d9, 2537}, + {0x91da, 7726}, + {0x91dc, 2536}, + {0x91dd, 2534}, + {0x91e2, 7725}, + {0x91e3, 3020}, + {0x91e4, 8346}, + {0x91e6, 3019}, + {0x91e7, 3021}, + {0x91e8, 8351}, + {0x91e9, 3023}, + {0x91ea, 8348}, + {0x91eb, 8349}, + {0x91ec, 8341}, + {0x91ed, 3022}, + {0x91ee, 8352}, + {0x91f1, 8343}, + {0x91f3, 8344}, + {0x91f4, 8342}, + {0x91f5, 3018}, + {0x91f7, 8350}, + {0x91f8, 8345}, + {0x91f9, 8347}, + {0x91fd, 9023}, + {0x91ff, 9022}, + {0x9200, 9020}, + {0x9201, 9012}, + {0x9202, 9027}, + {0x9203, 9015}, + {0x9204, 9025}, + {0x9205, 9032}, + {0x9206, 9024}, + {0x9207, 3478}, + {0x9209, 3474}, + {0x920a, 9013}, + {0x920c, 9019}, + {0x920d, 3476}, + {0x920f, 9018}, + {0x9210, 3477}, + {0x9211, 3479}, + {0x9212, 9021}, + {0x9214, 3471}, + {0x9215, 3472}, + {0x9216, 9033}, + {0x9217, 9031}, + {0x9219, 9030}, + {0x921a, 9016}, + {0x921c, 9028}, + {0x921e, 3475}, + {0x9223, 3473}, + {0x9224, 9029}, + {0x9225, 9014}, + {0x9226, 9017}, + {0x9227, 9026}, + {0x922e, 9690}, + {0x9230, 9683}, + {0x9231, 9702}, + {0x9232, 9711}, + {0x9233, 9686}, + {0x9234, 3925}, + {0x9236, 9699}, + {0x9237, 3915}, + {0x9238, 3917}, + {0x9239, 3929}, + {0x923a, 9684}, + {0x923d, 3918}, + {0x923e, 3920}, + {0x923f, 3930}, + {0x9240, 3919}, + {0x9245, 3928}, + {0x9246, 9692}, + {0x9248, 9681}, + {0x9249, 3926}, + {0x924a, 9691}, + {0x924b, 3922}, + {0x924c, 9709}, + {0x924d, 3927}, + {0x924e, 9707}, + {0x924f, 9695}, + {0x9250, 9705}, + {0x9251, 3924}, + {0x9252, 9682}, + {0x9253, 9708}, + {0x9254, 9703}, + {0x9256, 9710}, + {0x9257, 3916}, + {0x925a, 3931}, + {0x925b, 3921}, + {0x925e, 9688}, + {0x9260, 9696}, + {0x9261, 9700}, + {0x9263, 9704}, + {0x9264, 3923}, + {0x9265, 9687}, + {0x9266, 9685}, + {0x9267, 9697}, + {0x926c, 9694}, + {0x926d, 9693}, + {0x926f, 9698}, + {0x9270, 9701}, + {0x9272, 9706}, + {0x9278, 4307}, + {0x927b, 4313}, + {0x927c, 4317}, + {0x9280, 4309}, + {0x9283, 9689}, + {0x9285, 4310}, + {0x9291, 4318}, + {0x9293, 4314}, + {0x9296, 4312}, + {0x9298, 4311}, + {0x929c, 4315}, + {0x92a8, 4316}, + {0x92ac, 4308}, + {0x92b2, 4703}, + {0x92b3, 4698}, + {0x92b7, 4694}, + {0x92bb, 4693}, + {0x92bc, 4699}, + {0x92c1, 4697}, + {0x92c4, 0}, + {0x92c5, 4692}, + {0x92c7, 4701}, + {0x92d2, 4700}, + {0x92e4, 4696}, + {0x92ea, 4695}, + {0x92f0, 4702}, + {0x92f4, 0}, + {0x92f8, 4983}, + {0x92fc, 4987}, + {0x9304, 4989}, + {0x9310, 4991}, + {0x9315, 4994}, + {0x9318, 5283}, + {0x9319, 4996}, + {0x931a, 4990}, + {0x9320, 4981}, + {0x9321, 4993}, + {0x9322, 4986}, + {0x9326, 4992}, + {0x9328, 5278}, + {0x932b, 4988}, + {0x932e, 4995}, + {0x932f, 4985}, + {0x9333, 4984}, + {0x9336, 4982}, + {0x934a, 5280}, + {0x934b, 5282}, + {0x934d, 5276}, + {0x9351, 0}, + {0x9354, 5289}, + {0x935a, 5288}, + {0x935b, 5286}, + {0x9365, 5281}, + {0x936c, 5285}, + {0x9370, 5287}, + {0x9375, 5279}, + {0x937e, 5284}, + {0x9382, 5277}, + {0x938a, 5440}, + {0x9394, 5439}, + {0x9396, 5441}, + {0x9397, 5449}, + {0x9398, 5447}, + {0x939a, 5448}, + {0x93a2, 5442}, + {0x93ac, 5445}, + {0x93ae, 5444}, + {0x93b0, 5446}, + {0x93b3, 5443}, + {0x93c3, 5600}, + {0x93c8, 5601}, + {0x93cd, 5606}, + {0x93d1, 5598}, + {0x93d6, 5604}, + {0x93d7, 5609}, + {0x93d8, 5607}, + {0x93dc, 5602}, + {0x93dd, 5603}, + {0x93df, 5599}, + {0x93e1, 5597}, + {0x93e2, 5605}, + {0x93e4, 5608}, + {0x93e8, 5610}, + {0x93fd, 5716}, + {0x9403, 5715}, + {0x9418, 5714}, + {0x942b, 5791}, + {0x942e, 5785}, + {0x9432, 5790}, + {0x9433, 5786}, + {0x9435, 5787}, + {0x9438, 5789}, + {0x943a, 5788}, + {0x9444, 5855}, + {0x9449, 0}, + {0x944b, 0}, + {0x9451, 5856}, + {0x9452, 5857}, + {0x9460, 5902}, + {0x9463, 5901}, + {0x9464, 5903}, + {0x9469, 0}, + {0x946a, 5937}, + {0x9470, 5964}, + {0x9472, 5963}, + {0x9477, 5973}, + {0x947c, 5983}, + {0x947d, 5981}, + {0x947e, 5982}, + {0x947f, 5988}, + {0x9481, 0}, + {0x9577, 1687}, + {0x957a, 8353}, + {0x957b, 9034}, + {0x9580, 1688}, + {0x9582, 2081}, + {0x9583, 2538}, + {0x9586, 8354}, + {0x9588, 8355}, + {0x9589, 3024}, + {0x958b, 3482}, + {0x958c, 9036}, + {0x958d, 9035}, + {0x958e, 3486}, + {0x958f, 3481}, + {0x9590, 9037}, + {0x9591, 3483}, + {0x9592, 3485}, + {0x9593, 3484}, + {0x9594, 3480}, + {0x9598, 3932}, + {0x959b, 9715}, + {0x959c, 9713}, + {0x959e, 9714}, + {0x959f, 9712}, + {0x95a1, 4319}, + {0x95a3, 4322}, + {0x95a4, 4324}, + {0x95a5, 4323}, + {0x95a8, 4320}, + {0x95a9, 4321}, + {0x95ad, 4704}, + {0x95b1, 4705}, + {0x95ba, 0}, + {0x95bb, 4997}, + {0x95c6, 5294}, + {0x95c8, 5293}, + {0x95ca, 5290}, + {0x95cb, 5291}, + {0x95cc, 5292}, + {0x95d0, 5452}, + {0x95d3, 0}, + {0x95d4, 5450}, + {0x95d5, 5453}, + {0x95d6, 5451}, + {0x95db, 0}, + {0x95dc, 5611}, + {0x95e1, 5717}, + {0x95e2, 5792}, + {0x961c, 1689}, + {0x961e, 6068}, + {0x9620, 6177}, + {0x9621, 1044}, + {0x9622, 6175}, + {0x9623, 6178}, + {0x9624, 6176}, + {0x9628, 6385}, + {0x962a, 1318}, + {0x962c, 1319}, + {0x962d, 6387}, + {0x962e, 1316}, + {0x962f, 6386}, + {0x9630, 6384}, + {0x9631, 1317}, + {0x9632, 1315}, + {0x9639, 6741}, + {0x963a, 6744}, + {0x963b, 1692}, + {0x963c, 6743}, + {0x963d, 6742}, + {0x963f, 1691}, + {0x9640, 1690}, + {0x9642, 1694}, + {0x9643, 6745}, + {0x9644, 1693}, + {0x964a, 7194}, + {0x964b, 2083}, + {0x964c, 2084}, + {0x964d, 2085}, + {0x964e, 7195}, + {0x964f, 7191}, + {0x9650, 2082}, + {0x9651, 7192}, + {0x9653, 7193}, + {0x9654, 7190}, + {0x9658, 2545}, + {0x965b, 2542}, + {0x965c, 7727}, + {0x965d, 2543}, + {0x965e, 2546}, + {0x965f, 7728}, + {0x9661, 2541}, + {0x9662, 2539}, + {0x9663, 2540}, + {0x9664, 2544}, + {0x966a, 3025}, + {0x966b, 8358}, + {0x966c, 3033}, + {0x966d, 8357}, + {0x966f, 8360}, + {0x9670, 3029}, + {0x9671, 8359}, + {0x9672, 3494}, + {0x9673, 3027}, + {0x9674, 3030}, + {0x9675, 3026}, + {0x9676, 3031}, + {0x9677, 3032}, + {0x9678, 3028}, + {0x967c, 8356}, + {0x967d, 3490}, + {0x967e, 9039}, + {0x9680, 9043}, + {0x9683, 9042}, + {0x9684, 3495}, + {0x9685, 3491}, + {0x9686, 3492}, + {0x9687, 9038}, + {0x9688, 9040}, + {0x9689, 9041}, + {0x968a, 3487}, + {0x968b, 3489}, + {0x968d, 3493}, + {0x968e, 3488}, + {0x9691, 9718}, + {0x9692, 9716}, + {0x9693, 9717}, + {0x9694, 3934}, + {0x9695, 3935}, + {0x9697, 9719}, + {0x9698, 3933}, + {0x9699, 4325}, + {0x969b, 4327}, + {0x969c, 4326}, + {0x96a7, 4998}, + {0x96a8, 4999}, + {0x96aa, 5000}, + {0x96b1, 5295}, + {0x96b4, 5612}, + {0x96b6, 561}, + {0x96b8, 5296}, + {0x96b9, 1695}, + {0x96bb, 2547}, + {0x96bc, 7729}, + {0x96bf, 8361}, + {0x96c0, 3034}, + {0x96c1, 3496}, + {0x96c2, 9044}, + {0x96c3, 9046}, + {0x96c4, 3498}, + {0x96c5, 3497}, + {0x96c6, 3499}, + {0x96c7, 3500}, + {0x96c8, 9045}, + {0x96c9, 3938}, + {0x96ca, 3939}, + {0x96cb, 3937}, + {0x96cc, 4328}, + {0x96cd, 3936}, + {0x96ce, 9720}, + {0x96d2, 4329}, + {0x96d5, 5001}, + {0x96d6, 5297}, + {0x96d9, 5456}, + {0x96db, 5457}, + {0x96dc, 5455}, + {0x96de, 5458}, + {0x96e2, 5454}, + {0x96e3, 5613}, + {0x96e8, 1696}, + {0x96e9, 3036}, + {0x96ea, 3035}, + {0x96ef, 3501}, + {0x96f0, 9048}, + {0x96f1, 9047}, + {0x96f2, 3502}, + {0x96f5, 9724}, + {0x96f6, 3943}, + {0x96f7, 3940}, + {0x96f8, 9723}, + {0x96f9, 3942}, + {0x96fa, 9721}, + {0x96fb, 3941}, + {0x96fd, 9722}, + {0x9700, 4330}, + {0x9704, 4706}, + {0x9706, 4707}, + {0x9707, 4708}, + {0x9709, 4709}, + {0x970d, 5005}, + {0x970e, 5002}, + {0x970f, 5007}, + {0x9711, 5003}, + {0x9713, 5006}, + {0x9716, 5004}, + {0x971c, 5298}, + {0x971e, 5299}, + {0x9724, 5459}, + {0x9727, 5615}, + {0x972a, 5614}, + {0x972c, 0}, + {0x972f, 0}, + {0x9730, 5718}, + {0x9732, 5795}, + {0x9738, 5793}, + {0x9739, 5794}, + {0x973d, 5858}, + {0x973e, 5859}, + {0x9742, 5938}, + {0x9744, 5940}, + {0x9748, 5939}, + {0x9752, 1697}, + {0x9756, 3944}, + {0x975b, 5008}, + {0x975c, 5009}, + {0x975e, 1698}, + {0x9760, 4710}, + {0x9761, 5616}, + {0x9762, 2086}, + {0x9766, 5010}, + {0x9768, 5904}, + {0x9769, 2087}, + {0x976a, 8362}, + {0x976c, 9049}, + {0x976e, 9051}, + {0x9770, 9050}, + {0x9772, 9728}, + {0x9773, 9725}, + {0x9774, 3945}, + {0x9776, 3946}, + {0x9777, 9726}, + {0x9778, 9727}, + {0x977c, 4331}, + {0x9785, 4332}, + {0x978b, 4712}, + {0x978d, 4711}, + {0x978f, 4713}, + {0x9798, 5011}, + {0x97a0, 5300}, + {0x97a3, 5460}, + {0x97a6, 5461}, + {0x97ad, 5462}, + {0x97c1, 5861}, + {0x97c3, 5860}, + {0x97c5, 0}, + {0x97c6, 5941}, + {0x97c9, 5974}, + {0x97cb, 2088}, + {0x97cc, 3503}, + {0x97d3, 5301}, + {0x97dc, 5617}, + {0x97de, 0}, + {0x97df, 1}, + {0x97ed, 2089}, + {0x97f3, 2090}, + {0x97f6, 4333}, + {0x97f9, 5463}, + {0x97fb, 5618}, + {0x97fe, 0}, + {0x97ff, 5796}, + {0x9801, 2091}, + {0x9802, 3039}, + {0x9803, 3040}, + {0x9804, 8363}, + {0x9805, 3504}, + {0x9806, 3505}, + {0x9807, 9052}, + {0x9808, 3506}, + {0x980a, 3950}, + {0x980c, 3952}, + {0x980d, 9730}, + {0x980e, 9731}, + {0x980f, 9729}, + {0x9810, 3947}, + {0x9811, 3948}, + {0x9812, 3951}, + {0x9813, 3949}, + {0x9817, 4334}, + {0x9818, 4335}, + {0x981c, 4716}, + {0x9821, 4714}, + {0x9824, 5018}, + {0x982b, 4715}, + {0x982d, 5016}, + {0x9830, 5012}, + {0x9837, 5015}, + {0x9838, 5013}, + {0x9839, 5017}, + {0x983b, 5014}, + {0x9846, 5302}, + {0x984c, 5466}, + {0x984d, 5464}, + {0x984e, 5467}, + {0x984f, 5465}, + {0x9851, 0}, + {0x9852, 1}, + {0x9853, 5468}, + {0x9858, 5620}, + {0x985b, 5621}, + {0x985e, 5619}, + {0x9863, 0}, + {0x9865, 5798}, + {0x9867, 5797}, + {0x986b, 5862}, + {0x986f, 5905}, + {0x9870, 5942}, + {0x9871, 5965}, + {0x9874, 0}, + {0x98a8, 2092}, + {0x98a9, 9053}, + {0x98ac, 9732}, + {0x98ae, 0}, + {0x98af, 4336}, + {0x98b1, 4337}, + {0x98b3, 4717}, + {0x98b6, 5303}, + {0x98ba, 5469}, + {0x98bc, 5622}, + {0x98c2, 0}, + {0x98c4, 5719}, + {0x98db, 2093}, + {0x98df, 2094}, + {0x98e2, 2548}, + {0x98e3, 7730}, + {0x98e5, 8364}, + {0x98e7, 3507}, + {0x98e9, 3510}, + {0x98ea, 3508}, + {0x98eb, 9054}, + {0x98ed, 3512}, + {0x98ef, 3509}, + {0x98f2, 3511}, + {0x98f4, 3954}, + {0x98f6, 9733}, + {0x98f9, 9734}, + {0x98fc, 3953}, + {0x98fd, 3955}, + {0x98fe, 3956}, + {0x9903, 4338}, + {0x9905, 4339}, + {0x9909, 4341}, + {0x990a, 4718}, + {0x990c, 4340}, + {0x9910, 5019}, + {0x9912, 4720}, + {0x9913, 4719}, + {0x9917, 0}, + {0x9918, 4721}, + {0x991a, 5024}, + {0x991b, 5022}, + {0x991e, 5021}, + {0x9921, 5023}, + {0x9928, 5020}, + {0x992c, 0}, + {0x992e, 5473}, + {0x9935, 5304}, + {0x993d, 5472}, + {0x993e, 5470}, + {0x993f, 5471}, + {0x9945, 5623}, + {0x9949, 5624}, + {0x9951, 5721}, + {0x9952, 5720}, + {0x9955, 5863}, + {0x9957, 5799}, + {0x995c, 5906}, + {0x995e, 5966}, + {0x9996, 2095}, + {0x9997, 8365}, + {0x9999, 2096}, + {0x99a5, 5474}, + {0x99a7, 0}, + {0x99a8, 5722}, + {0x99ac, 2549}, + {0x99ad, 3514}, + {0x99ae, 3513}, + {0x99af, 9735}, + {0x99b0, 9737}, + {0x99b1, 3958}, + {0x99b2, 9736}, + {0x99b3, 3957}, + {0x99b4, 3959}, + {0x99b5, 9738}, + {0x99c1, 4342}, + {0x99d0, 4723}, + {0x99d1, 4726}, + {0x99d2, 4728}, + {0x99d4, 0}, + {0x99d5, 4727}, + {0x99d9, 4729}, + {0x99db, 4725}, + {0x99dd, 4722}, + {0x99df, 4724}, + {0x99e2, 5026}, + {0x99ed, 5025}, + {0x99f1, 5027}, + {0x99fe, 0}, + {0x99ff, 5306}, + {0x9a01, 5305}, + {0x9a0e, 5475}, + {0x9a16, 5625}, + {0x9a19, 5626}, + {0x9a2b, 5723}, + {0x9a30, 5724}, + {0x9a35, 5726}, + {0x9a37, 5725}, + {0x9a3e, 5803}, + {0x9a40, 5802}, + {0x9a43, 5801}, + {0x9a45, 5800}, + {0x9a4d, 5865}, + {0x9a54, 0}, + {0x9a55, 5864}, + {0x9a57, 5909}, + {0x9a5a, 5907}, + {0x9a5b, 5908}, + {0x9a5f, 5943}, + {0x9a62, 5975}, + {0x9a65, 5976}, + {0x9a67, 0}, + {0x9a6a, 5991}, + {0x9aa8, 2550}, + {0x9aab, 9740}, + {0x9aad, 9739}, + {0x9aaf, 4343}, + {0x9ab0, 4344}, + {0x9ab7, 4730}, + {0x9ab8, 5028}, + {0x9abc, 5029}, + {0x9ac1, 5476}, + {0x9acf, 5804}, + {0x9ad1, 5912}, + {0x9ad2, 5866}, + {0x9ad3, 5910}, + {0x9ad4, 5911}, + {0x9ad6, 5967}, + {0x9ad8, 2551}, + {0x9adf, 7731}, + {0x9ae1, 3960}, + {0x9ae6, 4345}, + {0x9aed, 5031}, + {0x9aee, 4731}, + {0x9aef, 4732}, + {0x9afb, 5030}, + {0x9b03, 5477}, + {0x9b05, 0}, + {0x9b06, 5478}, + {0x9b0d, 5627}, + {0x9b18, 0}, + {0x9b1a, 5867}, + {0x9b1f, 0}, + {0x9b20, 1}, + {0x9b22, 5944}, + {0x9b23, 5968}, + {0x9b25, 2552}, + {0x9b27, 4733}, + {0x9b28, 5032}, + {0x9b2f, 7732}, + {0x9b31, 5992}, + {0x9b32, 2553}, + {0x9b3c, 2554}, + {0x9b3f, 0}, + {0x9b41, 4346}, + {0x9b42, 4347}, + {0x9b44, 4735}, + {0x9b45, 4734}, + {0x9b4d, 5481}, + {0x9b4e, 5480}, + {0x9b4f, 5479}, + {0x9b51, 5806}, + {0x9b54, 5805}, + {0x9b58, 5945}, + {0x9b5a, 3041}, + {0x9b5b, 9741}, + {0x9b61, 0}, + {0x9b6f, 4737}, + {0x9b77, 4736}, + {0x9b91, 5033}, + {0x9baa, 5309}, + {0x9bab, 5308}, + {0x9bad, 5310}, + {0x9bae, 5307}, + {0x9bc0, 5486}, + {0x9bc8, 5485}, + {0x9bc9, 5483}, + {0x9bca, 5482}, + {0x9bd6, 5630}, + {0x9bdb, 5631}, + {0x9be7, 5629}, + {0x9be8, 5628}, + {0x9beb, 0}, + {0x9bfd, 5484}, + {0x9c0d, 5728}, + {0x9c13, 5727}, + {0x9c25, 5808}, + {0x9c29, 0}, + {0x9c2d, 5807}, + {0x9c31, 5869}, + {0x9c3b, 5871}, + {0x9c3e, 5870}, + {0x9c49, 5868}, + {0x9c54, 5913}, + {0x9c56, 5915}, + {0x9c57, 5914}, + {0x9c5f, 5946}, + {0x9c77, 5984}, + {0x9c78, 5985}, + {0x9ce5, 3042}, + {0x9ce6, 9055}, + {0x9ce7, 9744}, + {0x9ce9, 3961}, + {0x9cea, 9742}, + {0x9ced, 9743}, + {0x9cf2, 0}, + {0x9cf3, 4350}, + {0x9cf4, 4348}, + {0x9cf6, 4349}, + {0x9d03, 4740}, + {0x9d06, 4738}, + {0x9d09, 4739}, + {0x9d12, 5038}, + {0x9d15, 5034}, + {0x9d1b, 5039}, + {0x9d23, 5035}, + {0x9d26, 5036}, + {0x9d28, 5037}, + {0x9d2f, 0}, + {0x9d3b, 5311}, + {0x9d3f, 5312}, + {0x9d43, 0}, + {0x9d51, 5487}, + {0x9d5d, 5488}, + {0x9d60, 5489}, + {0x9d61, 5633}, + {0x9d6a, 5635}, + {0x9d6c, 5636}, + {0x9d72, 5634}, + {0x9d75, 0}, + {0x9d89, 5632}, + {0x9d8c, 0}, + {0x9da7, 0}, + {0x9daf, 5809}, + {0x9db4, 5810}, + {0x9db8, 5812}, + {0x9dba, 0}, + {0x9dc2, 5811}, + {0x9dd3, 5872}, + {0x9dd7, 5873}, + {0x9de5, 5916}, + {0x9df9, 5947}, + {0x9dfa, 5948}, + {0x9e01, 0}, + {0x9e1a, 5989}, + {0x9e1b, 5993}, + {0x9e1e, 5994}, + {0x9e75, 3043}, + {0x9e79, 5729}, + {0x9e7c, 5949}, + {0x9e7d, 5950}, + {0x9e7f, 3044}, + {0x9e80, 9745}, + {0x9e82, 3962}, + {0x9e87, 0}, + {0x9e8b, 5313}, + {0x9e92, 5637}, + {0x9e93, 5639}, + {0x9e97, 5638}, + {0x9e9d, 5813}, + {0x9e9f, 5917}, + {0x9ea5, 3045}, + {0x9ea9, 4741}, + {0x9eb4, 5640}, + {0x9eb5, 5730}, + {0x9ebb, 3046}, + {0x9ebc, 4351}, + {0x9ebe, 4742}, + {0x9ec3, 3515}, + {0x9ecc, 5969}, + {0x9ecd, 3516}, + {0x9ece, 4743}, + {0x9ecf, 5314}, + {0x9ed1, 3517}, + {0x9ed4, 5041}, + {0x9ed6, 0}, + {0x9ed8, 5040}, + {0x9edb, 5318}, + {0x9edc, 5316}, + {0x9edd, 5317}, + {0x9ede, 5315}, + {0x9ee0, 5490}, + {0x9ee8, 5731}, + {0x9eef, 5814}, + {0x9ef3, 0}, + {0x9ef4, 5918}, + {0x9ef7, 5986}, + {0x9ef9, 9056}, + {0x9efd, 9746}, + {0x9f07, 5951}, + {0x9f0e, 3963}, + {0x9f10, 0}, + {0x9f13, 3964}, + {0x9f15, 5491}, + {0x9f19, 5815}, + {0x9f20, 3965}, + {0x9f2c, 5492}, + {0x9f2f, 5732}, + {0x9f34, 5874}, + {0x9f3b, 4352}, + {0x9f3e, 5319}, + {0x9f41, 0}, + {0x9f4a, 4353}, + {0x9f4b, 5320}, + {0x9f52, 4745}, + {0x9f57, 0}, + {0x9f58, 1}, + {0x9f5c, 5816}, + {0x9f5f, 5733}, + {0x9f61, 5735}, + {0x9f63, 5734}, + {0x9f66, 5817}, + {0x9f67, 5818}, + {0x9f6a, 5876}, + {0x9f6c, 5875}, + {0x9f6f, 0}, + {0x9f72, 5953}, + {0x9f75, 0}, + {0x9f76, 1}, + {0x9f77, 5952}, + {0x9f8d, 5042}, + {0x9f90, 5500}, + {0x9f94, 5877}, + {0x9f9c, 5043}, + {0xe003, 0}, + {0xe00a, 0}, + {0xe013, 0}, + {0xe014, 1}, + {0xe015, 2}, + {0xe016, 3}, + {0xe01b, 0}, + {0xe01c, 1}, + {0xe01d, 2}, + {0xe01e, 3}, + {0xe023, 0}, + {0xe02e, 0}, + {0xe033, 0}, + {0xe034, 1}, + {0xe035, 2}, + {0xe036, 3}, + {0xe037, 4}, + {0xe038, 5}, + {0xe03c, 0}, + {0xe060, 0}, + {0xe061, 1}, + {0xe075, 0}, + {0xe08a, 0}, + {0xe094, 0}, + {0xe09a, 0}, + {0xe09d, 0}, + {0xe09e, 1}, + {0xe0a7, 0}, + {0xe0c8, 0}, + {0xe0d5, 0}, + {0xe0e3, 0}, + {0xe0e4, 1}, + {0xe0e5, 2}, + {0xe0e8, 0}, + {0xe0e9, 1}, + {0xe0ec, 0}, + {0xe0f9, 0}, + {0xe10a, 0}, + {0xe10b, 1}, + {0xe115, 0}, + {0xe11d, 0}, + {0xe127, 0}, + {0xe128, 1}, + {0xe131, 0}, + {0xe142, 0}, + {0xe148, 0}, + {0xe155, 0}, + {0xe156, 1}, + {0xe157, 2}, + {0xe15a, 0}, + {0xe169, 0}, + {0xe16a, 1}, + {0xe172, 0}, + {0xe179, 0}, + {0xe17c, 0}, + {0xe180, 0}, + {0xe190, 0}, + {0xe1a0, 0}, + {0xe1b1, 0}, + {0xe1b4, 0}, + {0xe1bd, 0}, + {0xe1be, 1}, + {0xe1bf, 2}, + {0xe1c5, 0}, + {0xe1cd, 0}, + {0xe1d5, 0}, + {0xe1f0, 0}, + {0xe20b, 0}, + {0xe20c, 1}, + {0xe213, 0}, + {0xe214, 1}, + {0xe215, 2}, + {0xe216, 3}, + {0xe21c, 0}, + {0xe220, 0}, + {0xe221, 1}, + {0xe227, 0}, + {0xe228, 1}, + {0xe23e, 0}, + {0xe24b, 0}, + {0xe24c, 1}, + {0xe24d, 2}, + {0xe24e, 3}, + {0xe24f, 4}, + {0xe252, 0}, + {0xe253, 1}, + {0xe254, 2}, + {0xe26e, 0}, + {0xe26f, 1}, + {0xe289, 0}, + {0xe291, 0}, + {0xe295, 0}, + {0xe296, 1}, + {0xe29a, 0}, + {0xe29b, 1}, + {0xe2b3, 0}, + {0xe2b4, 1}, + {0xe2b5, 2}, + {0xe2b8, 0}, + {0xe2bf, 0}, + {0xe2d9, 0}, + {0xe2e1, 0}, + {0xe2e2, 1}, + {0xe2ec, 0}, + {0xe2ed, 1}, + {0xe2f1, 0}, + {0xe31c, 0}, + {0xe331, 0}, + {0xe336, 0}, + {0xe35c, 0}, + {0xe365, 0}, + {0xe375, 0}, + {0xe382, 0}, + {0xe389, 0}, + {0xe38a, 1}, + {0xe39b, 0}, + {0xe3a0, 0}, + {0xe3a7, 0}, + {0xe3a8, 1}, + {0xe3a9, 2}, + {0xe3b2, 0}, + {0xe3b5, 0}, + {0xe3ba, 0}, + {0xe3bb, 1}, + {0xe3bc, 2}, + {0xe3bd, 3}, + {0xe3d9, 0}, + {0xe3da, 1}, + {0xe3ee, 0}, + {0xe3f3, 0}, + {0xe3f4, 1}, + {0xe40a, 0}, + {0xe40b, 1}, + {0xe41e, 0}, + {0xe42d, 0}, + {0xe43b, 0}, + {0xe43c, 1}, + {0xe441, 0}, + {0xe44d, 0}, + {0xe44e, 1}, + {0xe451, 0}, + {0xe45a, 0}, + {0xe45e, 0}, + {0xe462, 0}, + {0xe463, 1}, + {0xe468, 0}, + {0xe469, 1}, + {0xe46f, 0}, + {0xe472, 0}, + {0xe47f, 0}, + {0xe487, 0}, + {0xe488, 1}, + {0xe489, 2}, + {0xe48a, 3}, + {0xe48e, 0}, + {0xe492, 0}, + {0xe496, 0}, + {0xe497, 1}, + {0xe4a3, 0}, + {0xe4a4, 1}, + {0xe4b4, 0}, + {0xe4b5, 1}, + {0xe4b6, 2}, + {0xe4b7, 3}, + {0xe4b8, 4}, + {0xe4b9, 5}, + {0xe4ba, 6}, + {0xe4ce, 0}, + {0xe4dd, 0}, + {0xe4e7, 0}, + {0xe4e8, 1}, + {0xe4ef, 0}, + {0xe4f9, 0}, + {0xe502, 0}, + {0xe51d, 0}, + {0xe51e, 1}, + {0xe51f, 2}, + {0xe520, 3}, + {0xe521, 4}, + {0xe52a, 0}, + {0xe52b, 1}, + {0xe52c, 2}, + {0xe52f, 0}, + {0xe555, 0}, + {0xe558, 0}, + {0xe559, 1}, + {0xe55c, 0}, + {0xe55f, 0}, + {0xe567, 0}, + {0xe56e, 0}, + {0xe573, 0}, + {0xe576, 0}, + {0xe577, 1}, + {0xe57a, 0}, + {0xe57d, 0}, + {0xe57e, 1}, + {0xe583, 0}, + {0xe584, 1}, + {0xe585, 2}, + {0xe586, 3}, + {0xe58c, 0}, + {0xe58d, 1}, + {0xe58e, 2}, + {0xe58f, 3}, + {0xe590, 4}, + {0xe593, 0}, + {0xe594, 1}, + {0xe59e, 0}, + {0xe59f, 1}, + {0xe5a0, 2}, + {0xe5a1, 3}, + {0xe5a7, 0}, + {0xe5a8, 1}, + {0xe5b8, 0}, + {0xe5bb, 0}, + {0xe5bf, 0}, + {0xe5c0, 1}, + {0xe5c9, 0}, + {0xe5d8, 0}, + {0xe5d9, 1}, + {0xe5dc, 0}, + {0xe5e2, 0}, + {0xe5e3, 1}, + {0xe5e6, 0}, + {0xe5ef, 0}, + {0xe5f0, 1}, + {0xe5f1, 2}, + {0xe5fc, 0}, + {0xe610, 0}, + {0xe611, 1}, + {0xe612, 2}, + {0xe61a, 0}, + {0xe61b, 1}, + {0xe61c, 2}, + {0xe624, 0}, + {0xe633, 0}, + {0xe634, 1}, + {0xe638, 0}, + {0xe640, 0}, + {0xe641, 1}, + {0xe642, 2}, + {0xe646, 0}, + {0xe64f, 0}, + {0xe653, 0}, + {0xe654, 1}, + {0xe655, 2}, + {0xe658, 0}, + {0xe659, 1}, + {0xe65e, 0}, + {0xe65f, 1}, + {0xe660, 2}, + {0xe663, 0}, + {0xe666, 0}, + {0xe667, 1}, + {0xe668, 2}, + {0xe66f, 0}, + {0xe677, 0}, + {0xe678, 1}, + {0xe679, 2}, + {0xe67c, 0}, + {0xe67d, 1}, + {0xe680, 0}, + {0xe684, 0}, + {0xe685, 1}, + {0xe686, 2}, + {0xe687, 3}, + {0xe688, 4}, + {0xe68b, 0}, + {0xe68c, 1}, + {0xe68f, 0}, + {0xe690, 1}, + {0xe697, 0}, + {0xe69a, 0}, + {0xe69f, 0}, + {0xe6a2, 0}, + {0xe6ad, 0}, + {0xe6ba, 0}, + {0xe6be, 0}, + {0xe6c1, 0}, + {0xe6d2, 0}, + {0xe6d8, 0}, + {0xe6db, 0}, + {0xe6de, 0}, + {0xe6df, 1}, + {0xe6e0, 2}, + {0xe6e1, 3}, + {0xe6e5, 0}, + {0xe6e6, 1}, + {0xe6f3, 0}, + {0xe6fb, 0}, + {0xe6fc, 1}, + {0xe702, 0}, + {0xe707, 0}, + {0xe70a, 0}, + {0xe711, 0}, + {0xe718, 0}, + {0xe71b, 0}, + {0xe725, 0}, + {0xe734, 0}, + {0xe735, 1}, + {0xe736, 2}, + {0xe737, 3}, + {0xe73d, 0}, + {0xe741, 0}, + {0xe742, 1}, + {0xe74e, 0}, + {0xe74f, 1}, + {0xe752, 0}, + {0xe75c, 0}, + {0xe75d, 1}, + {0xe762, 0}, + {0xe765, 0}, + {0xe768, 0}, + {0xe76d, 0}, + {0xe76e, 1}, + {0xe778, 0}, + {0xe77d, 0}, + {0xe797, 0}, + {0xe7a5, 0}, + {0xe7a6, 1}, + {0xe7a7, 2}, + {0xe7a8, 3}, + {0xe7a9, 4}, + {0xe7dd, 0}, + {0xe7e8, 0}, + {0xe7e9, 1}, + {0xe7ee, 0}, + {0xe7ef, 1}, + {0xe7f2, 0}, + {0xe7f3, 1}, + {0xe7fc, 0}, + {0xe801, 0}, + {0xe802, 1}, + {0xe80f, 0}, + {0xe817, 0}, + {0xe818, 1}, + {0xe828, 0}, + {0xe838, 0}, + {0xe83b, 0}, + {0xe842, 0}, + {0xe84e, 0}, + {0xe856, 0}, + {0xe857, 1}, + {0xe858, 2}, + {0xe85c, 0}, + {0xe85d, 1}, + {0xe861, 0}, + {0xe862, 1}, + {0xe866, 0}, + {0xe867, 1}, + {0xe86a, 0}, + {0xe87e, 0}, + {0xe87f, 1}, + {0xe892, 0}, + {0xe895, 0}, + {0xe8a1, 0}, + {0xe8a4, 0}, + {0xe8a5, 1}, + {0xe8a6, 2}, + {0xe8a7, 3}, + {0xe8aa, 0}, + {0xe8ad, 0}, + {0xe8ae, 1}, + {0xe8af, 2}, + {0xe8b0, 3}, + {0xe8b6, 0}, + {0xe8be, 0}, + {0xe8bf, 1}, + {0xe8c0, 2}, + {0xe8c1, 3}, + {0xe8c2, 4}, + {0xe8c3, 5}, + {0xe8ce, 0}, + {0xe8d1, 0}, + {0xe8d6, 0}, + {0xe8d9, 0}, + {0xe8da, 1}, + {0xe8e0, 0}, + {0xe8e1, 1}, + {0xe8e6, 0}, + {0xe8e9, 0}, + {0xe8ea, 1}, + {0xe8f2, 0}, + {0xe908, 0}, + {0xe918, 0}, + {0xe91f, 0}, + {0xe920, 1}, + {0xe921, 2}, + {0xe922, 3}, + {0xe926, 0}, + {0xe927, 1}, + {0xe928, 2}, + {0xe929, 3}, + {0xe92a, 4}, + {0xe92b, 5}, + {0xe92c, 6}, + {0xe92f, 0}, + {0xe934, 0}, + {0xe935, 1}, + {0xe936, 2}, + {0xe93d, 0}, + {0xe93e, 1}, + {0xe945, 0}, + {0xe953, 0}, + {0xe954, 1}, + {0xe955, 2}, + {0xe958, 0}, + {0xe95d, 0}, + {0xe95e, 1}, + {0xe961, 0}, + {0xe96f, 0}, + {0xe978, 0}, + {0xe97b, 0}, + {0xe982, 0}, + {0xeac0, 0}, + {0xeac1, 1}, + {0xeaca, 0}, + {0xeacb, 1}, + {0xeacc, 2}, + {0xead0, 0}, + {0xead1, 1}, + {0xead4, 0}, + {0xead7, 0}, + {0xead8, 1}, + {0xead9, 2}, + {0xeada, 3}, + {0xeadf, 0}, + {0xeae0, 1}, + {0xeae1, 2}, + {0xeae2, 3}, + {0xeae3, 4}, + {0xeae8, 0}, + {0xeae9, 1}, + {0xeaea, 2}, + {0xeaeb, 3}, + {0xeaec, 4}, + {0xeaf1, 0}, + {0xeaf2, 1}, + {0xeaf6, 0}, + {0xeafb, 0}, + {0xeaff, 0}, + {0xeb03, 0}, + {0xeb04, 1}, + {0xeb05, 2}, + {0xeb09, 0}, + {0xeb0a, 1}, + {0xeb0b, 2}, + {0xeb0c, 3}, + {0xeb0d, 4}, + {0xeb0e, 5}, + {0xeb0f, 6}, + {0xeb12, 0}, + {0xeb19, 0}, + {0xeb1a, 1}, + {0xeb1b, 2}, + {0xeb1c, 3}, + {0xeb1d, 4}, + {0xeb20, 0}, + {0xeb21, 1}, + {0xeb2d, 0}, + {0xeb2e, 1}, + {0xeb2f, 2}, + {0xeb30, 3}, + {0xeb31, 4}, + {0xeb32, 5}, + {0xeb33, 6}, + {0xeb34, 7}, + {0xeb35, 8}, + {0xeb36, 9}, + {0xeb37, 10}, + {0xeb38, 11}, + {0xeb39, 12}, + {0xeb3f, 0}, + {0xeb44, 0}, + {0xeb4c, 0}, + {0xeb4e, 0}, + {0xeb50, 0}, + {0xeb56, 0}, + {0xeb59, 0}, + {0xeb5b, 0}, + {0xeb63, 0}, + {0xeb69, 0}, + {0xeb70, 0}, + {0xeb71, 1}, + {0xeb7f, 0}, + {0xeb81, 0}, + {0xeb84, 0}, + {0xeb8d, 0}, + {0xeb8e, 1}, + {0xeb99, 0}, + {0xeb9a, 1}, + {0xeba6, 0}, + {0xebb3, 0}, + {0xebc6, 0}, + {0xebcd, 0}, + {0xebd8, 0}, + {0xebdb, 0}, + {0xebe9, 0}, + {0xebec, 0}, + {0xebfa, 0}, + {0xebfb, 1}, + {0xebfe, 0}, + {0xec06, 0}, + {0xec09, 0}, + {0xec0f, 0}, + {0xec10, 1}, + {0xec18, 0}, + {0xec1a, 0}, + {0xec1b, 1}, + {0xec1c, 2}, + {0xec2d, 0}, + {0xec2e, 1}, + {0xec3c, 0}, + {0xec40, 0}, + {0xec41, 1}, + {0xec46, 0}, + {0xec47, 1}, + {0xec48, 2}, + {0xec49, 3}, + {0xec4c, 0}, + {0xec57, 0}, + {0xec58, 1}, + {0xec5d, 0}, + {0xec60, 0}, + {0xec63, 0}, + {0xec6a, 0}, + {0xec6b, 1}, + {0xec6c, 2}, + {0xec6d, 3}, + {0xec6e, 4}, + {0xec6f, 5}, + {0xec70, 6}, + {0xec71, 7}, + {0xec72, 8}, + {0xec73, 9}, + {0xec76, 0}, + {0xec94, 0}, + {0xec9b, 0}, + {0xeca4, 0}, + {0xeca8, 0}, + {0xecba, 0}, + {0xecbb, 1}, + {0xecdc, 0}, + {0xece0, 0}, + {0xece1, 1}, + {0xed0d, 0}, + {0xed0e, 1}, + {0xed0f, 2}, + {0xed10, 3}, + {0xed11, 4}, + {0xed16, 0}, + {0xed17, 1}, + {0xed25, 0}, + {0xed27, 0}, + {0xed42, 0}, + {0xed4b, 0}, + {0xed4e, 0}, + {0xed54, 0}, + {0xed58, 0}, + {0xed85, 0}, + {0xed8a, 0}, + {0xeea2, 0}, + {0xeea3, 1}, + {0xeea4, 2}, + {0xeea5, 3}, + {0xeea6, 4}, + {0xeea9, 0}, + {0xeeaa, 1}, + {0xeead, 0}, + {0xeeae, 1}, + {0xeeaf, 2}, + {0xeeb0, 3}, + {0xeeb1, 4}, + {0xf304, 0}, + {0xf305, 1}, + {0xf306, 2}, + {0xf307, 3}, + {0xf308, 4}, + {0xf309, 5}, + {0xf30a, 6}, + {0xf30b, 7}, + {0xf30c, 8}, + {0xf30d, 9}, + {0xf30e, 10}, + {0xf30f, 11}, + {0xf310, 12}, + {0xf311, 13}, + {0xf312, 14}, + {0xf313, 15}, + {0xf314, 16}, + {0xf315, 17}, + {0xf316, 18}, + {0xf317, 19}, + {0xf318, 20}, + {0xf34b, 0}, + {0xf3a1, 0}, + {0xf3fa, 0}, + {0xf409, 0}, + {0xf40a, 1}, + {0xf40b, 2}, + {0xf441, 0}, + {0xf442, 1}, + {0xf449, 0}, + {0xf451, 0}, + {0xf452, 1}, + {0xf455, 0}, + {0xf456, 1}, + {0xf45d, 0}, + {0xf45e, 1}, + {0xf45f, 2}, + {0xf462, 0}, + {0xf463, 1}, + {0xf466, 0}, + {0xf46d, 0}, + {0xf47d, 0}, + {0xf47e, 1}, + {0xf481, 0}, + {0xf485, 0}, + {0xf48e, 0}, + {0xf48f, 1}, + {0xf490, 2}, + {0xf498, 0}, + {0xf4a5, 0}, + {0xf4a6, 1}, + {0xf4aa, 0}, + {0xf4b0, 0}, + {0xf4b4, 0}, + {0xf4bb, 0}, + {0xf4bc, 1}, + {0xf4bd, 2}, + {0xf4be, 3}, + {0xf4bf, 4}, + {0xf4c0, 5}, + {0xf4c4, 0}, + {0xf4c5, 1}, + {0xf4c8, 0}, + {0xf4c9, 1}, + {0xf4ca, 2}, + {0xf4cd, 0}, + {0xf4ce, 1}, + {0xf4cf, 2}, + {0xf4d2, 0}, + {0xf4d3, 1}, + {0xf4d4, 2}, + {0xf4d5, 3}, + {0xf4da, 0}, + {0xf4dc, 0}, + {0xf4de, 0}, + {0xf4e8, 0}, + {0xf4e9, 1}, + {0xf4ff, 0}, + {0xf501, 0}, + {0xf508, 0}, + {0xf509, 1}, + {0xf50a, 2}, + {0xf50b, 3}, + {0xf50c, 4}, + {0xf50d, 5}, + {0xf50e, 6}, + {0xf50f, 7}, + {0xf510, 8}, + {0xf511, 9}, + {0xf514, 0}, + {0xf515, 1}, + {0xf516, 2}, + {0xf519, 0}, + {0xf51a, 1}, + {0xf51b, 2}, + {0xf51c, 3}, + {0xf51d, 4}, + {0xf520, 0}, + {0xf521, 1}, + {0xf522, 2}, + {0xf523, 3}, + {0xf524, 4}, + {0xf525, 5}, + {0xf526, 6}, + {0xf534, 0}, + {0xf53b, 0}, + {0xf55a, 0}, + {0xf7e6, 0}, + {0xf7eb, 0}, + {0xf7ee, 0}, + {0xfa0c, 628}, + {0xfa0d, 9089}, + {0xfe30, 109}, + {0xfe31, 122}, + {0xfe35, 130}, + {0xfe36, 131}, + {0xfe37, 134}, + {0xfe38, 135}, + {0xfe39, 138}, + {0xfe3a, 139}, + {0xfe3b, 142}, + {0xfe3c, 143}, + {0xfe3d, 146}, + {0xfe3e, 147}, + {0xfe3f, 150}, + {0xfe40, 151}, + {0xfe41, 154}, + {0xfe42, 155}, + {0xfe43, 158}, + {0xfe44, 159}, + {0xfe49, 199}, + {0xfe4a, 200}, + {0xfe4b, 203}, + {0xfe4c, 204}, + {0xfe4d, 201}, + {0xfe4e, 202}, + {0xfe50, 112}, + {0xfe52, 114}, + {0xfe54, 116}, + {0xfe55, 117}, + {0xfe56, 118}, + {0xfe57, 119}, + {0xfe59, 160}, + {0xfe5a, 161}, + {0xfe5b, 162}, + {0xfe5c, 163}, + {0xfe5d, 164}, + {0xfe5e, 165}, + {0xfe5f, 205}, + {0xfe60, 206}, + {0xfe61, 207}, + {0xfe62, 223}, + {0xfe63, 224}, + {0xfe64, 225}, + {0xfe65, 226}, + {0xfe66, 227}, + {0xfe69, 268}, + {0xfe6a, 269}, + {0xfe6b, 270}, + {0xff01, 108}, + {0xff03, 174}, + {0xff04, 259}, + {0xff05, 264}, + {0xff06, 175}, + {0xff08, 128}, + {0xff09, 129}, + {0xff0a, 176}, + {0xff0b, 208}, + {0xff0c, 100}, + {0xff0d, 209}, + {0xff0e, 103}, + {0xff0f, 257}, + {0xff10, 333}, + {0xff11, 334}, + {0xff12, 335}, + {0xff13, 336}, + {0xff14, 337}, + {0xff15, 338}, + {0xff16, 339}, + {0xff17, 340}, + {0xff18, 341}, + {0xff19, 342}, + {0xff1a, 106}, + {0xff1b, 105}, + {0xff1c, 214}, + {0xff1d, 216}, + {0xff1e, 215}, + {0xff1f, 107}, + {0xff20, 265}, + {0xff21, 365}, + {0xff22, 366}, + {0xff23, 367}, + {0xff24, 368}, + {0xff25, 369}, + {0xff26, 370}, + {0xff27, 371}, + {0xff28, 372}, + {0xff29, 373}, + {0xff2a, 374}, + {0xff2b, 375}, + {0xff2c, 376}, + {0xff2d, 377}, + {0xff2e, 378}, + {0xff2f, 379}, + {0xff30, 380}, + {0xff31, 381}, + {0xff32, 382}, + {0xff33, 383}, + {0xff34, 384}, + {0xff35, 385}, + {0xff36, 386}, + {0xff37, 387}, + {0xff38, 388}, + {0xff39, 389}, + {0xff3a, 390}, + {0xff3c, 258}, + {0xff3f, 197}, + {0xff41, 391}, + {0xff42, 392}, + {0xff43, 393}, + {0xff44, 394}, + {0xff45, 395}, + {0xff46, 396}, + {0xff47, 397}, + {0xff48, 398}, + {0xff49, 399}, + {0xff4a, 400}, + {0xff4b, 401}, + {0xff4c, 402}, + {0xff4d, 403}, + {0xff4e, 404}, + {0xff4f, 405}, + {0xff50, 406}, + {0xff51, 407}, + {0xff52, 408}, + {0xff53, 409}, + {0xff54, 410}, + {0xff55, 411}, + {0xff56, 412}, + {0xff57, 413}, + {0xff58, 414}, + {0xff59, 415}, + {0xff5a, 416}, + {0xff5b, 132}, + {0xff5c, 120}, + {0xff5d, 133}, + {0xff64, 113}}; + diff --git a/src/add-ons/print/drivers/pdf/source/enc_range.h b/src/add-ons/print/drivers/pdf/source/enc_range.h new file mode 100644 index 0000000000..71684bc5c4 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/enc_range.h @@ -0,0 +1,11 @@ +// WARNING: MACHINE GENERATED DON'T CHANGE! +#define UNICODE0_FROM 32 +#define UNICODE0_TO 320 +#define UNICODE1_FROM 321 +#define UNICODE1_TO 1110 +#define UNICODE2_FROM 1111 +#define UNICODE2_TO 8736 +#define UNICODE3_FROM 8743 +#define UNICODE3_TO 63725 +#define UNICODE4_FROM 63726 +#define UNICODE4_TO 64331 diff --git a/src/add-ons/print/drivers/pdf/source/gb1.h b/src/add-ons/print/drivers/pdf/source/gb1.h new file mode 100644 index 0000000000..b44d96e531 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/gb1.h @@ -0,0 +1,23963 @@ +// WARNING: MACHINE GENERATED, DON'T CHANGE! +static unicode_to_cid GB1[] = { + {0x20, 1}, + {0x21, 2}, + {0x22, 3}, + {0x23, 4}, + {0x24, 5}, + {0x25, 6}, + {0x26, 7}, + {0x27, 8}, + {0x28, 9}, + {0x29, 10}, + {0x2a, 11}, + {0x2b, 12}, + {0x2c, 13}, + {0x2d, 14}, + {0x2e, 15}, + {0x2f, 16}, + {0x30, 17}, + {0x31, 18}, + {0x32, 19}, + {0x33, 20}, + {0x34, 21}, + {0x35, 22}, + {0x36, 23}, + {0x37, 24}, + {0x38, 25}, + {0x39, 26}, + {0x3a, 27}, + {0x3b, 28}, + {0x3c, 29}, + {0x3d, 30}, + {0x3e, 31}, + {0x3f, 32}, + {0x40, 33}, + {0x41, 34}, + {0x42, 35}, + {0x43, 36}, + {0x44, 37}, + {0x45, 38}, + {0x46, 39}, + {0x47, 40}, + {0x48, 41}, + {0x49, 42}, + {0x4a, 43}, + {0x4b, 44}, + {0x4c, 45}, + {0x4d, 46}, + {0x4e, 47}, + {0x4f, 48}, + {0x50, 49}, + {0x51, 50}, + {0x52, 51}, + {0x53, 52}, + {0x54, 53}, + {0x55, 54}, + {0x56, 55}, + {0x57, 56}, + {0x58, 57}, + {0x59, 58}, + {0x5a, 59}, + {0x5b, 60}, + {0x5c, 61}, + {0x5d, 62}, + {0x5e, 63}, + {0x5f, 64}, + {0x60, 65}, + {0x61, 66}, + {0x62, 67}, + {0x63, 68}, + {0x64, 69}, + {0x65, 70}, + {0x66, 71}, + {0x67, 72}, + {0x68, 73}, + {0x69, 74}, + {0x6a, 75}, + {0x6b, 76}, + {0x6c, 77}, + {0x6d, 78}, + {0x6e, 79}, + {0x6f, 80}, + {0x70, 81}, + {0x71, 82}, + {0x72, 83}, + {0x73, 84}, + {0x74, 85}, + {0x75, 86}, + {0x76, 87}, + {0x77, 88}, + {0x78, 89}, + {0x79, 90}, + {0x7a, 91}, + {0x7b, 92}, + {0x7c, 93}, + {0x7d, 94}, + {0x7e, 95}, + {0xa4, 167}, + {0xa7, 171}, + {0xa8, 102}, + {0xb0, 162}, + {0xb1, 127}, + {0xd7, 128}, + {0xe0, 671}, + {0xe1, 669}, + {0xe8, 675}, + {0xe9, 673}, + {0xea, 693}, + {0xec, 679}, + {0xed, 677}, + {0xf2, 683}, + {0xf3, 681}, + {0xf7, 129}, + {0xf9, 687}, + {0xfa, 685}, + {0xfc, 692}, + {0x101, 668}, + {0x113, 672}, + {0x11b, 674}, + {0x12b, 676}, + {0x14d, 680}, + {0x16b, 684}, + {0x1ce, 670}, + {0x1d0, 678}, + {0x1d2, 682}, + {0x1d4, 686}, + {0x1d6, 688}, + {0x1d8, 689}, + {0x1da, 690}, + {0x1dc, 691}, + {0x1f9, 698}, + {0x2c7, 101}, + {0x2c9, 100}, + {0x2ca, 9907}, + {0x2cb, 9908}, + {0x2d9, 9909}, + {0x391, 525}, + {0x392, 526}, + {0x393, 527}, + {0x394, 528}, + {0x395, 529}, + {0x396, 530}, + {0x397, 531}, + {0x398, 532}, + {0x399, 533}, + {0x39a, 534}, + {0x39b, 535}, + {0x39c, 536}, + {0x39d, 537}, + {0x39e, 538}, + {0x39f, 539}, + {0x3a0, 540}, + {0x3a1, 541}, + {0x3a3, 542}, + {0x3a4, 543}, + {0x3a5, 544}, + {0x3a6, 545}, + {0x3a7, 546}, + {0x3a8, 547}, + {0x3a9, 548}, + {0x3b1, 549}, + {0x3b2, 550}, + {0x3b3, 551}, + {0x3b4, 552}, + {0x3b5, 553}, + {0x3b6, 554}, + {0x3b7, 555}, + {0x3b8, 556}, + {0x3b9, 557}, + {0x3ba, 558}, + {0x3bb, 559}, + {0x3bc, 560}, + {0x3bd, 561}, + {0x3be, 562}, + {0x3bf, 563}, + {0x3c0, 564}, + {0x3c1, 565}, + {0x3c3, 566}, + {0x3c4, 567}, + {0x3c5, 568}, + {0x3c6, 569}, + {0x3c7, 570}, + {0x3c8, 571}, + {0x3c9, 572}, + {0x401, 608}, + {0x410, 602}, + {0x411, 603}, + {0x412, 604}, + {0x413, 605}, + {0x414, 606}, + {0x415, 607}, + {0x416, 609}, + {0x417, 610}, + {0x418, 611}, + {0x419, 612}, + {0x41a, 613}, + {0x41b, 614}, + {0x41c, 615}, + {0x41d, 616}, + {0x41e, 617}, + {0x41f, 618}, + {0x420, 619}, + {0x421, 620}, + {0x422, 621}, + {0x423, 622}, + {0x424, 623}, + {0x425, 624}, + {0x426, 625}, + {0x427, 626}, + {0x428, 627}, + {0x429, 628}, + {0x42a, 629}, + {0x42b, 630}, + {0x42c, 631}, + {0x42d, 632}, + {0x42e, 633}, + {0x42f, 634}, + {0x430, 635}, + {0x431, 636}, + {0x432, 637}, + {0x433, 638}, + {0x434, 639}, + {0x435, 640}, + {0x436, 642}, + {0x437, 643}, + {0x438, 644}, + {0x439, 645}, + {0x43a, 646}, + {0x43b, 647}, + {0x43c, 648}, + {0x43d, 649}, + {0x43e, 650}, + {0x43f, 651}, + {0x440, 652}, + {0x441, 653}, + {0x442, 654}, + {0x443, 655}, + {0x444, 656}, + {0x445, 657}, + {0x446, 658}, + {0x447, 659}, + {0x448, 660}, + {0x449, 661}, + {0x44a, 662}, + {0x44b, 663}, + {0x44c, 664}, + {0x44d, 665}, + {0x44e, 666}, + {0x44f, 667}, + {0x451, 641}, + {0x1e3f, 695}, + {0x2013, 9910}, + {0x2014, 105}, + {0x2015, 9911}, + {0x2016, 107}, + {0x2018, 109}, + {0x2019, 110}, + {0x201c, 111}, + {0x201d, 112}, + {0x2025, 9912}, + {0x2026, 108}, + {0x2030, 170}, + {0x2032, 163}, + {0x2033, 164}, + {0x2035, 9913}, + {0x203b, 184}, + {0x2103, 165}, + {0x2105, 9914}, + {0x2109, 9915}, + {0x2116, 172}, + {0x2160, 250}, + {0x2161, 251}, + {0x2162, 252}, + {0x2163, 253}, + {0x2164, 254}, + {0x2165, 255}, + {0x2166, 256}, + {0x2167, 257}, + {0x2168, 258}, + {0x2169, 259}, + {0x216a, 260}, + {0x216b, 261}, + {0x2170, 9897}, + {0x2171, 9898}, + {0x2172, 9899}, + {0x2173, 9900}, + {0x2174, 9901}, + {0x2175, 9902}, + {0x2176, 9903}, + {0x2177, 9904}, + {0x2178, 9905}, + {0x2179, 9906}, + {0x2190, 186}, + {0x2191, 187}, + {0x2192, 185}, + {0x2193, 188}, + {0x2196, 9916}, + {0x2197, 9917}, + {0x2198, 9918}, + {0x2199, 9919}, + {0x2208, 137}, + {0x220f, 134}, + {0x2211, 133}, + {0x2215, 9920}, + {0x221a, 139}, + {0x221d, 151}, + {0x221e, 157}, + {0x221f, 9921}, + {0x2220, 142}, + {0x2223, 9922}, + {0x2225, 141}, + {0x2227, 131}, + {0x2228, 132}, + {0x2229, 136}, + {0x222a, 135}, + {0x222b, 145}, + {0x222e, 146}, + {0x2234, 159}, + {0x2235, 158}, + {0x2236, 130}, + {0x2237, 138}, + {0x223d, 150}, + {0x2248, 149}, + {0x224c, 148}, + {0x2252, 9923}, + {0x2260, 152}, + {0x2261, 147}, + {0x2264, 155}, + {0x2265, 156}, + {0x2266, 9924}, + {0x2267, 9925}, + {0x226e, 153}, + {0x226f, 154}, + {0x2295, 9988}, + {0x2299, 144}, + {0x22a5, 140}, + {0x22bf, 9926}, + {0x22ef, 108}, + {0x2312, 143}, + {0x2460, 230}, + {0x2461, 231}, + {0x2462, 232}, + {0x2463, 233}, + {0x2464, 234}, + {0x2465, 235}, + {0x2466, 236}, + {0x2467, 237}, + {0x2468, 238}, + {0x2469, 239}, + {0x2474, 210}, + {0x2475, 211}, + {0x2476, 212}, + {0x2477, 213}, + {0x2478, 214}, + {0x2479, 215}, + {0x247a, 216}, + {0x247b, 217}, + {0x247c, 218}, + {0x247d, 219}, + {0x247e, 220}, + {0x247f, 221}, + {0x2480, 222}, + {0x2481, 223}, + {0x2482, 224}, + {0x2483, 225}, + {0x2484, 226}, + {0x2485, 227}, + {0x2486, 228}, + {0x2487, 229}, + {0x2488, 190}, + {0x2489, 191}, + {0x248a, 192}, + {0x248b, 193}, + {0x248c, 194}, + {0x248d, 195}, + {0x248e, 196}, + {0x248f, 197}, + {0x2490, 198}, + {0x2491, 199}, + {0x2492, 200}, + {0x2493, 201}, + {0x2494, 202}, + {0x2495, 203}, + {0x2496, 204}, + {0x2497, 205}, + {0x2498, 206}, + {0x2499, 207}, + {0x249a, 208}, + {0x249b, 209}, + {0x2500, 738}, + {0x2501, 739}, + {0x2502, 740}, + {0x2503, 741}, + {0x2504, 742}, + {0x2505, 743}, + {0x2506, 744}, + {0x2507, 745}, + {0x2508, 746}, + {0x2509, 747}, + {0x250a, 748}, + {0x250b, 749}, + {0x250c, 750}, + {0x250d, 751}, + {0x250e, 752}, + {0x250f, 753}, + {0x2510, 754}, + {0x2511, 755}, + {0x2512, 756}, + {0x2513, 757}, + {0x2514, 758}, + {0x2515, 759}, + {0x2516, 760}, + {0x2517, 761}, + {0x2518, 762}, + {0x2519, 763}, + {0x251a, 764}, + {0x251b, 765}, + {0x251c, 766}, + {0x251d, 767}, + {0x251e, 768}, + {0x251f, 769}, + {0x2520, 770}, + {0x2521, 771}, + {0x2522, 772}, + {0x2523, 773}, + {0x2524, 774}, + {0x2525, 775}, + {0x2526, 776}, + {0x2527, 777}, + {0x2528, 778}, + {0x2529, 779}, + {0x252a, 780}, + {0x252b, 781}, + {0x252c, 782}, + {0x252d, 783}, + {0x252e, 784}, + {0x252f, 785}, + {0x2530, 786}, + {0x2531, 787}, + {0x2532, 788}, + {0x2533, 789}, + {0x2534, 790}, + {0x2535, 791}, + {0x2536, 792}, + {0x2537, 793}, + {0x2538, 794}, + {0x2539, 795}, + {0x253a, 796}, + {0x253b, 797}, + {0x253c, 798}, + {0x253d, 799}, + {0x253e, 800}, + {0x253f, 801}, + {0x2540, 802}, + {0x2541, 803}, + {0x2542, 804}, + {0x2543, 805}, + {0x2544, 806}, + {0x2545, 807}, + {0x2546, 808}, + {0x2547, 809}, + {0x2548, 810}, + {0x2549, 811}, + {0x254a, 812}, + {0x254b, 813}, + {0x2550, 9927}, + {0x2551, 9928}, + {0x2552, 9929}, + {0x2553, 9930}, + {0x2554, 9931}, + {0x2555, 9932}, + {0x2556, 9933}, + {0x2557, 9934}, + {0x2558, 9935}, + {0x2559, 9936}, + {0x255a, 9937}, + {0x255b, 9938}, + {0x255c, 9939}, + {0x255d, 9940}, + {0x255e, 9941}, + {0x255f, 9942}, + {0x2560, 9943}, + {0x2561, 9944}, + {0x2562, 9945}, + {0x2563, 9946}, + {0x2564, 9947}, + {0x2565, 9948}, + {0x2566, 9949}, + {0x2567, 9950}, + {0x2568, 9951}, + {0x2569, 9952}, + {0x256a, 9953}, + {0x256b, 9954}, + {0x256c, 9955}, + {0x256d, 9956}, + {0x256e, 9957}, + {0x256f, 9958}, + {0x2570, 9959}, + {0x2571, 9960}, + {0x2572, 9961}, + {0x2573, 9962}, + {0x2581, 9963}, + {0x2582, 9964}, + {0x2583, 9965}, + {0x2584, 9966}, + {0x2585, 9967}, + {0x2586, 9968}, + {0x2587, 9969}, + {0x2588, 9970}, + {0x2589, 9971}, + {0x258a, 9972}, + {0x258b, 9973}, + {0x258c, 9974}, + {0x258d, 9975}, + {0x258e, 9976}, + {0x258f, 9977}, + {0x2593, 9978}, + {0x2594, 9979}, + {0x2595, 9980}, + {0x25a0, 181}, + {0x25a1, 180}, + {0x25b2, 183}, + {0x25b3, 182}, + {0x25bc, 9981}, + {0x25bd, 9982}, + {0x25c6, 179}, + {0x25c7, 178}, + {0x25cb, 175}, + {0x25ce, 177}, + {0x25cf, 176}, + {0x25e2, 9983}, + {0x25e3, 9984}, + {0x25e4, 9985}, + {0x25e5, 9986}, + {0x2605, 174}, + {0x2606, 173}, + {0x2609, 9987}, + {0x2640, 161}, + {0x2642, 160}, + {0x2e83, 0}, + {0x2e86, 0}, + {0x2e87, 1}, + {0x2e8a, 0}, + {0x2e8e, 0}, + {0x2e8f, 1}, + {0x2e90, 2}, + {0x2e91, 3}, + {0x2e92, 4}, + {0x2e93, 5}, + {0x2e94, 6}, + {0x2e95, 7}, + {0x2e96, 8}, + {0x2e99, 0}, + {0x2e9c, 0}, + {0x2e9d, 1}, + {0x2e9e, 2}, + {0x2e9f, 3}, + {0x2ea0, 4}, + {0x2ea1, 5}, + {0x2ea2, 6}, + {0x2ea3, 7}, + {0x2ea4, 8}, + {0x2ea5, 9}, + {0x2ea6, 10}, + {0x2ea9, 0}, + {0x2eac, 0}, + {0x2ead, 1}, + {0x2eb0, 0}, + {0x2eb1, 1}, + {0x2eb2, 2}, + {0x2eb5, 0}, + {0x2eb7, 0}, + {0x2eb9, 0}, + {0x2eba, 1}, + {0x2ebd, 0}, + {0x2ebe, 1}, + {0x2ebf, 2}, + {0x2ec0, 3}, + {0x2ec1, 4}, + {0x2ec2, 5}, + {0x2ec3, 6}, + {0x2ec4, 7}, + {0x2ec5, 8}, + {0x2ec6, 9}, + {0x2ec7, 10}, + {0x2ec8, 11}, + {0x2ec9, 12}, + {0x2ecc, 0}, + {0x2ecd, 1}, + {0x2ece, 2}, + {0x2ecf, 3}, + {0x2ed0, 4}, + {0x2ed1, 5}, + {0x2ed2, 6}, + {0x2ed3, 7}, + {0x2ed4, 8}, + {0x2ed5, 9}, + {0x2ed6, 10}, + {0x2ed7, 11}, + {0x2ed8, 12}, + {0x2ed9, 13}, + {0x2eda, 14}, + {0x2edb, 15}, + {0x2edc, 16}, + {0x2edd, 17}, + {0x2ede, 18}, + {0x2edf, 19}, + {0x2ee0, 20}, + {0x2ee1, 21}, + {0x2ee2, 22}, + {0x2ee3, 23}, + {0x2ee4, 24}, + {0x2ee5, 25}, + {0x2ee6, 26}, + {0x2ee7, 27}, + {0x2ee8, 28}, + {0x2ee9, 29}, + {0x2eea, 30}, + {0x2eeb, 31}, + {0x2eec, 32}, + {0x2eed, 33}, + {0x2eee, 34}, + {0x2eef, 35}, + {0x2ef0, 36}, + {0x2ef1, 37}, + {0x2ef2, 38}, + {0x2ef3, 39}, + {0x2f00, 4162}, + {0x2f01, 4707}, + {0x2f02, 4722}, + {0x2f03, 4709}, + {0x2f04, 4185}, + {0x2f06, 1597}, + {0x2f07, 4867}, + {0x2f08, 3238}, + {0x2f09, 1592}, + {0x2f0a, 3270}, + {0x2f0b, 982}, + {0x2f0c, 4765}, + {0x2f0d, 4884}, + {0x2f0e, 4879}, + {0x2f0f, 2091}, + {0x2f10, 5017}, + {0x2f11, 1431}, + {0x2f12, 2543}, + {0x2f13, 4860}, + {0x2f14, 4710}, + {0x2f15, 4740}, + {0x2f17, 3397}, + {0x2f18, 1150}, + {0x2f19, 4946}, + {0x2f1a, 1228}, + {0x2f1b, 5020}, + {0x2f1c, 4283}, + {0x2f1d, 2407}, + {0x2f1e, 5523}, + {0x2f1f, 3698}, + {0x2f20, 3414}, + {0x2f21, 5660}, + {0x2f23, 3859}, + {0x2f24, 1398}, + {0x2f25, 2927}, + {0x2f26, 4656}, + {0x2f27, 5934}, + {0x2f28, 1386}, + {0x2f29, 3948}, + {0x2f2a, 5302}, + {0x2f2b, 3395}, + {0x2f2c, 6004}, + {0x2f2d, 3318}, + {0x2f2e, 6165}, + {0x2f2f, 1789}, + {0x2f30, 2093}, + {0x2f31, 2238}, + {0x2f32, 1732}, + {0x2f33, 6163}, + {0x2f34, 1852}, + {0x2f35, 5016}, + {0x2f36, 5293}, + {0x2f37, 5366}, + {0x2f38, 1798}, + {0x2f39, 5986}, + {0x2f3a, 5614}, + {0x2f3b, 5600}, + {0x2f3c, 3983}, + {0x2f3d, 1765}, + {0x2f3f, 3437}, + {0x2f40, 4518}, + {0x2f41, 6409}, + {0x2f42, 3795}, + {0x2f43, 1526}, + {0x2f44, 2240}, + {0x2f45, 1626}, + {0x2f46, 3821}, + {0x2f47, 3248}, + {0x2f48, 4350}, + {0x2f49, 4357}, + {0x2f4a, 2849}, + {0x2f4b, 3124}, + {0x2f4c, 4536}, + {0x2f4d, 1400}, + {0x2f4e, 6589}, + {0x2f4f, 3826}, + {0x2f50, 1073}, + {0x2f51, 2736}, + {0x2f52, 3430}, + {0x2f53, 3095}, + {0x2f54, 3491}, + {0x2f55, 2053}, + {0x2f56, 4611}, + {0x2f57, 1715}, + {0x2f58, 4713}, + {0x2f59, 5789}, + {0x2f5a, 3019}, + {0x2f5b, 4073}, + {0x2f5c, 2916}, + {0x2f5d, 3209}, + {0x2f5e, 4041}, + {0x2f5f, 4310}, + {0x2f60, 1832}, + {0x2f61, 3728}, + {0x2f62, 1733}, + {0x2f63, 3379}, + {0x2f64, 4264}, + {0x2f65, 3650}, + {0x2f66, 7110}, + {0x2f67, 7008}, + {0x2f69, 994}, + {0x2f6a, 3011}, + {0x2f6b, 2808}, + {0x2f6c, 2850}, + {0x2f6d, 2737}, + {0x2f6e, 3407}, + {0x2f6f, 3398}, + {0x2f70, 3413}, + {0x2f72, 1923}, + {0x2f73, 4049}, + {0x2f74, 2539}, + {0x2f75, 4592}, + {0x2f76, 2780}, + {0x2f77, 7399}, + {0x2f78, 7262}, + {0x2f79, 3753}, + {0x2f7a, 4123}, + {0x2f7b, 4309}, + {0x2f7c, 2490}, + {0x2f7d, 1591}, + {0x2f7e, 7115}, + {0x2f7f, 1593}, + {0x2f80, 6686}, + {0x2f81, 3261}, + {0x2f82, 1249}, + {0x2f83, 4657}, + {0x2f84, 4544}, + {0x2f85, 2297}, + {0x2f86, 3353}, + {0x2f87, 5656}, + {0x2f88, 4570}, + {0x2f89, 7388}, + {0x2f8a, 3300}, + {0x2f8c, 7152}, + {0x2f8d, 1291}, + {0x2f8e, 4051}, + {0x2f8f, 3995}, + {0x2f90, 4169}, + {0x2f92, 8086}, + {0x2f93, 2200}, + {0x2f94, 4093}, + {0x2f95, 1825}, + {0x2f96, 1528}, + {0x2f97, 7445}, + {0x2f98, 7504}, + {0x2f99, 7739}, + {0x2f9a, 1285}, + {0x2f9b, 4668}, + {0x2f9c, 4672}, + {0x2f9d, 3366}, + {0x2f9e, 7803}, + {0x2f9f, 3980}, + {0x2fa0, 1250}, + {0x2fa2, 4191}, + {0x2fa3, 4276}, + {0x2fa5, 2522}, + {0x2fa6, 2241}, + {0x2fa7, 7797}, + {0x2fa8, 8317}, + {0x2fa9, 1714}, + {0x2faa, 2542}, + {0x2fab, 7545}, + {0x2fac, 4303}, + {0x2fae, 1636}, + {0x2faf, 2795}, + {0x2fb0, 1770}, + {0x2fb1, 8589}, + {0x2fb2, 2289}, + {0x2fb3, 4219}, + {0x2fb4, 8713}, + {0x2fb5, 7936}, + {0x2fb6, 7924}, + {0x2fb7, 3402}, + {0x2fb8, 3438}, + {0x2fb9, 3920}, + {0x2fba, 8301}, + {0x2fbb, 1824}, + {0x2fbc, 1754}, + {0x2fbd, 7660}, + {0x2fbe, 7888}, + {0x2fbf, 5019}, + {0x2fc0, 4704}, + {0x2fc1, 1862}, + {0x2fc2, 8761}, + {0x2fc3, 8348}, + {0x2fc4, 9864}, + {0x2fc5, 2656}, + {0x2fc6, 8305}, + {0x2fc7, 2704}, + {0x2fc9, 3465}, + {0x2fca, 1937}, + {0x2fcb, 6741}, + {0x2fcc, 9752}, + {0x2fcd, 1509}, + {0x2fce, 1821}, + {0x2fcf, 3466}, + {0x2fd0, 1072}, + {0x2fd1, 8390}, + {0x2fd2, 7814}, + {0x2fd3, 8247}, + {0x2fd4, 7988}, + {0x2fd5, 4851}, + {0x2ff1, 0}, + {0x2ff2, 1}, + {0x2ff3, 2}, + {0x2ff4, 3}, + {0x2ff5, 4}, + {0x2ff6, 5}, + {0x2ff7, 6}, + {0x2ff8, 7}, + {0x2ff9, 8}, + {0x2ffa, 9}, + {0x2ffb, 10}, + {0x3000, 96}, + {0x3001, 97}, + {0x3002, 98}, + {0x3003, 103}, + {0x3005, 104}, + {0x3007, 7703}, + {0x3008, 115}, + {0x3009, 116}, + {0x300a, 117}, + {0x300b, 118}, + {0x300c, 119}, + {0x300d, 120}, + {0x300e, 121}, + {0x300f, 122}, + {0x3010, 125}, + {0x3011, 126}, + {0x3012, 9989}, + {0x3013, 189}, + {0x3014, 113}, + {0x3015, 114}, + {0x3016, 123}, + {0x3017, 124}, + {0x301d, 9990}, + {0x301e, 9991}, + {0x3021, 9992}, + {0x3022, 9993}, + {0x3023, 9994}, + {0x3024, 9995}, + {0x3025, 9996}, + {0x3026, 9997}, + {0x3027, 9998}, + {0x3028, 9999}, + {0x3029, 10000}, + {0x3034, 0}, + {0x3035, 1}, + {0x3039, 0}, + {0x303a, 1}, + {0x3041, 356}, + {0x3042, 357}, + {0x3043, 358}, + {0x3044, 359}, + {0x3045, 360}, + {0x3046, 361}, + {0x3047, 362}, + {0x3048, 363}, + {0x3049, 364}, + {0x304a, 365}, + {0x304b, 366}, + {0x304c, 367}, + {0x304d, 368}, + {0x304e, 369}, + {0x304f, 370}, + {0x3050, 371}, + {0x3051, 372}, + {0x3052, 373}, + {0x3053, 374}, + {0x3054, 375}, + {0x3055, 376}, + {0x3056, 377}, + {0x3057, 378}, + {0x3058, 379}, + {0x3059, 380}, + {0x305a, 381}, + {0x305b, 382}, + {0x305c, 383}, + {0x305d, 384}, + {0x305e, 385}, + {0x305f, 386}, + {0x3060, 387}, + {0x3061, 388}, + {0x3062, 389}, + {0x3063, 390}, + {0x3064, 391}, + {0x3065, 392}, + {0x3066, 393}, + {0x3067, 394}, + {0x3068, 395}, + {0x3069, 396}, + {0x306a, 397}, + {0x306b, 398}, + {0x306c, 399}, + {0x306d, 400}, + {0x306e, 401}, + {0x306f, 402}, + {0x3070, 403}, + {0x3071, 404}, + {0x3072, 405}, + {0x3073, 406}, + {0x3074, 407}, + {0x3075, 408}, + {0x3076, 409}, + {0x3077, 410}, + {0x3078, 411}, + {0x3079, 412}, + {0x307a, 413}, + {0x307b, 414}, + {0x307c, 415}, + {0x307d, 416}, + {0x307e, 417}, + {0x307f, 418}, + {0x3080, 419}, + {0x3081, 420}, + {0x3082, 421}, + {0x3083, 422}, + {0x3084, 423}, + {0x3085, 424}, + {0x3086, 425}, + {0x3087, 426}, + {0x3088, 427}, + {0x3089, 428}, + {0x308a, 429}, + {0x308b, 430}, + {0x308c, 431}, + {0x308d, 432}, + {0x308e, 433}, + {0x308f, 434}, + {0x3090, 435}, + {0x3091, 436}, + {0x3092, 437}, + {0x3093, 438}, + {0x309c, 0}, + {0x309e, 0}, + {0x30a1, 439}, + {0x30a2, 440}, + {0x30a3, 441}, + {0x30a4, 442}, + {0x30a5, 443}, + {0x30a6, 444}, + {0x30a7, 445}, + {0x30a8, 446}, + {0x30a9, 447}, + {0x30aa, 448}, + {0x30ab, 449}, + {0x30ac, 450}, + {0x30ad, 451}, + {0x30ae, 452}, + {0x30af, 453}, + {0x30b0, 454}, + {0x30b1, 455}, + {0x30b2, 456}, + {0x30b3, 457}, + {0x30b4, 458}, + {0x30b5, 459}, + {0x30b6, 460}, + {0x30b7, 461}, + {0x30b8, 462}, + {0x30b9, 463}, + {0x30ba, 464}, + {0x30bb, 465}, + {0x30bc, 466}, + {0x30bd, 467}, + {0x30be, 468}, + {0x30bf, 469}, + {0x30c0, 470}, + {0x30c1, 471}, + {0x30c2, 472}, + {0x30c3, 473}, + {0x30c4, 474}, + {0x30c5, 475}, + {0x30c6, 476}, + {0x30c7, 477}, + {0x30c8, 478}, + {0x30c9, 479}, + {0x30ca, 480}, + {0x30cb, 481}, + {0x30cc, 482}, + {0x30cd, 483}, + {0x30ce, 484}, + {0x30cf, 485}, + {0x30d0, 486}, + {0x30d1, 487}, + {0x30d2, 488}, + {0x30d3, 489}, + {0x30d4, 490}, + {0x30d5, 491}, + {0x30d6, 492}, + {0x30d7, 493}, + {0x30d8, 494}, + {0x30d9, 495}, + {0x30da, 496}, + {0x30db, 497}, + {0x30dc, 498}, + {0x30dd, 499}, + {0x30de, 500}, + {0x30df, 501}, + {0x30e0, 502}, + {0x30e1, 503}, + {0x30e2, 504}, + {0x30e3, 505}, + {0x30e4, 506}, + {0x30e5, 507}, + {0x30e6, 508}, + {0x30e7, 509}, + {0x30e8, 510}, + {0x30e9, 511}, + {0x30ea, 512}, + {0x30eb, 513}, + {0x30ec, 514}, + {0x30ed, 515}, + {0x30ee, 516}, + {0x30ef, 517}, + {0x30f0, 518}, + {0x30f1, 519}, + {0x30f2, 520}, + {0x30f3, 521}, + {0x30f4, 522}, + {0x30f5, 523}, + {0x30f6, 524}, + {0x30f8, 0}, + {0x30f9, 1}, + {0x30fa, 2}, + {0x30fb, 99}, + {0x30fe, 0}, + {0x3105, 700}, + {0x3106, 701}, + {0x3107, 702}, + {0x3108, 703}, + {0x3109, 704}, + {0x310a, 705}, + {0x310b, 706}, + {0x310c, 707}, + {0x310d, 708}, + {0x310e, 709}, + {0x310f, 710}, + {0x3110, 711}, + {0x3111, 712}, + {0x3112, 713}, + {0x3113, 714}, + {0x3114, 715}, + {0x3115, 716}, + {0x3116, 717}, + {0x3117, 718}, + {0x3118, 719}, + {0x3119, 720}, + {0x311a, 721}, + {0x311b, 722}, + {0x311c, 723}, + {0x311d, 724}, + {0x311e, 725}, + {0x311f, 726}, + {0x3120, 727}, + {0x3121, 728}, + {0x3122, 729}, + {0x3123, 730}, + {0x3124, 731}, + {0x3125, 732}, + {0x3126, 733}, + {0x3127, 734}, + {0x3128, 735}, + {0x3129, 736}, + {0x312b, 0}, + {0x312c, 1}, + {0x31a1, 0}, + {0x31a2, 1}, + {0x31a3, 2}, + {0x31a4, 3}, + {0x31a5, 4}, + {0x31a6, 5}, + {0x31a7, 6}, + {0x31a8, 7}, + {0x31a9, 8}, + {0x31aa, 9}, + {0x31ab, 10}, + {0x31ac, 11}, + {0x31ad, 12}, + {0x31ae, 13}, + {0x31af, 14}, + {0x31b0, 15}, + {0x31b1, 16}, + {0x31b2, 17}, + {0x31b3, 18}, + {0x31b4, 19}, + {0x31b5, 20}, + {0x31b6, 21}, + {0x31b7, 22}, + {0x3220, 240}, + {0x3221, 241}, + {0x3222, 242}, + {0x3223, 243}, + {0x3224, 244}, + {0x3225, 245}, + {0x3226, 246}, + {0x3227, 247}, + {0x3228, 248}, + {0x3229, 249}, + {0x338f, 0}, + {0x339d, 0}, + {0x339e, 1}, + {0x33d2, 0}, + {0x3401, 0}, + {0x3402, 1}, + {0x3403, 2}, + {0x3404, 3}, + {0x3405, 4}, + {0x3406, 5}, + {0x3407, 6}, + {0x3408, 7}, + {0x3409, 8}, + {0x340a, 9}, + {0x340b, 10}, + {0x340c, 11}, + {0x340d, 12}, + {0x340e, 13}, + {0x340f, 14}, + {0x3410, 15}, + {0x3411, 16}, + {0x3412, 17}, + {0x3413, 18}, + {0x3414, 19}, + {0x3415, 20}, + {0x3416, 21}, + {0x3417, 22}, + {0x3418, 23}, + {0x3419, 24}, + {0x341a, 25}, + {0x341b, 26}, + {0x341c, 27}, + {0x341d, 28}, + {0x341e, 29}, + {0x341f, 30}, + {0x3420, 31}, + {0x3421, 32}, + {0x3422, 33}, + {0x3423, 34}, + {0x3424, 35}, + {0x3425, 36}, + {0x3426, 37}, + {0x3427, 38}, + {0x3428, 39}, + {0x3429, 40}, + {0x342a, 41}, + {0x342b, 42}, + {0x342c, 43}, + {0x342d, 44}, + {0x342e, 45}, + {0x342f, 46}, + {0x3430, 47}, + {0x3431, 48}, + {0x3432, 49}, + {0x3433, 50}, + {0x3434, 51}, + {0x3435, 52}, + {0x3436, 53}, + {0x3437, 54}, + {0x3438, 55}, + {0x3439, 56}, + {0x343a, 57}, + {0x343b, 58}, + {0x343c, 59}, + {0x343d, 60}, + {0x343e, 61}, + {0x343f, 62}, + {0x3440, 63}, + {0x3441, 64}, + {0x3442, 65}, + {0x3443, 66}, + {0x3444, 67}, + {0x3445, 68}, + {0x3446, 69}, + {0x3449, 0}, + {0x344a, 1}, + {0x344b, 2}, + {0x344c, 3}, + {0x344d, 4}, + {0x344e, 5}, + {0x344f, 6}, + {0x3450, 7}, + {0x3451, 8}, + {0x3452, 9}, + {0x3453, 10}, + {0x3454, 11}, + {0x3455, 12}, + {0x3456, 13}, + {0x3457, 14}, + {0x3458, 15}, + {0x3459, 16}, + {0x345a, 17}, + {0x345b, 18}, + {0x345c, 19}, + {0x345d, 20}, + {0x345e, 21}, + {0x345f, 22}, + {0x3460, 23}, + {0x3461, 24}, + {0x3462, 25}, + {0x3463, 26}, + {0x3464, 27}, + {0x3465, 28}, + {0x3466, 29}, + {0x3467, 30}, + {0x3468, 31}, + {0x3469, 32}, + {0x346a, 33}, + {0x346b, 34}, + {0x346c, 35}, + {0x346d, 36}, + {0x346e, 37}, + {0x346f, 38}, + {0x3470, 39}, + {0x3471, 40}, + {0x3472, 41}, + {0x3475, 0}, + {0x3476, 1}, + {0x3477, 2}, + {0x3478, 3}, + {0x3479, 4}, + {0x347a, 5}, + {0x347b, 6}, + {0x347c, 7}, + {0x347d, 8}, + {0x347e, 9}, + {0x347f, 10}, + {0x3480, 11}, + {0x3481, 12}, + {0x3482, 13}, + {0x3483, 14}, + {0x3484, 15}, + {0x3485, 16}, + {0x3486, 17}, + {0x3487, 18}, + {0x3488, 19}, + {0x3489, 20}, + {0x348a, 21}, + {0x348b, 22}, + {0x348c, 23}, + {0x348d, 24}, + {0x348e, 25}, + {0x348f, 26}, + {0x3490, 27}, + {0x3491, 28}, + {0x3492, 29}, + {0x3493, 30}, + {0x3494, 31}, + {0x3495, 32}, + {0x3496, 33}, + {0x3497, 34}, + {0x3498, 35}, + {0x3499, 36}, + {0x349a, 37}, + {0x349b, 38}, + {0x349c, 39}, + {0x349d, 40}, + {0x349e, 41}, + {0x349f, 42}, + {0x34a0, 43}, + {0x34a1, 44}, + {0x34a2, 45}, + {0x34a3, 46}, + {0x34a4, 47}, + {0x34a5, 48}, + {0x34a6, 49}, + {0x34a7, 50}, + {0x34a8, 51}, + {0x34a9, 52}, + {0x34aa, 53}, + {0x34ab, 54}, + {0x34ac, 55}, + {0x34ad, 56}, + {0x34ae, 57}, + {0x34af, 58}, + {0x34b0, 59}, + {0x34b1, 60}, + {0x34b2, 61}, + {0x34b3, 62}, + {0x34b4, 63}, + {0x34b5, 64}, + {0x34b6, 65}, + {0x34b7, 66}, + {0x34b8, 67}, + {0x34b9, 68}, + {0x34ba, 69}, + {0x34bb, 70}, + {0x34bc, 71}, + {0x34bd, 72}, + {0x34be, 73}, + {0x34bf, 74}, + {0x34c0, 75}, + {0x34c1, 76}, + {0x34c2, 77}, + {0x34c3, 78}, + {0x34c4, 79}, + {0x34c5, 80}, + {0x34c6, 81}, + {0x34c7, 82}, + {0x34c8, 83}, + {0x34c9, 84}, + {0x34ca, 85}, + {0x34cb, 86}, + {0x34cc, 87}, + {0x34cd, 88}, + {0x34ce, 89}, + {0x34cf, 90}, + {0x34d0, 91}, + {0x34d1, 92}, + {0x34d2, 93}, + {0x34d3, 94}, + {0x34d4, 95}, + {0x34d5, 96}, + {0x34d6, 97}, + {0x34d7, 98}, + {0x34d8, 99}, + {0x34d9, 100}, + {0x34da, 101}, + {0x34db, 102}, + {0x34dc, 103}, + {0x34dd, 104}, + {0x34de, 105}, + {0x34df, 106}, + {0x34e0, 107}, + {0x34e1, 108}, + {0x34e2, 109}, + {0x34e3, 110}, + {0x34e4, 111}, + {0x34e5, 112}, + {0x34e6, 113}, + {0x34e7, 114}, + {0x34e8, 115}, + {0x34e9, 116}, + {0x34ea, 117}, + {0x34eb, 118}, + {0x34ec, 119}, + {0x34ed, 120}, + {0x34ee, 121}, + {0x34ef, 122}, + {0x34f0, 123}, + {0x34f1, 124}, + {0x34f2, 125}, + {0x34f3, 126}, + {0x34f4, 127}, + {0x34f5, 128}, + {0x34f6, 129}, + {0x34f7, 130}, + {0x34f8, 131}, + {0x34f9, 132}, + {0x34fa, 133}, + {0x34fb, 134}, + {0x34fc, 135}, + {0x34fd, 136}, + {0x34fe, 137}, + {0x34ff, 138}, + {0x3501, 0}, + {0x3502, 1}, + {0x3503, 2}, + {0x3504, 3}, + {0x3505, 4}, + {0x3506, 5}, + {0x3507, 6}, + {0x3508, 7}, + {0x3509, 8}, + {0x350a, 9}, + {0x350b, 10}, + {0x350c, 11}, + {0x350d, 12}, + {0x350e, 13}, + {0x350f, 14}, + {0x3510, 15}, + {0x3511, 16}, + {0x3512, 17}, + {0x3513, 18}, + {0x3514, 19}, + {0x3515, 20}, + {0x3516, 21}, + {0x3517, 22}, + {0x3518, 23}, + {0x3519, 24}, + {0x351a, 25}, + {0x351b, 26}, + {0x351c, 27}, + {0x351d, 28}, + {0x351e, 29}, + {0x351f, 30}, + {0x3520, 31}, + {0x3521, 32}, + {0x3522, 33}, + {0x3523, 34}, + {0x3524, 35}, + {0x3525, 36}, + {0x3526, 37}, + {0x3527, 38}, + {0x3528, 39}, + {0x3529, 40}, + {0x352a, 41}, + {0x352b, 42}, + {0x352c, 43}, + {0x352d, 44}, + {0x352e, 45}, + {0x352f, 46}, + {0x3530, 47}, + {0x3531, 48}, + {0x3532, 49}, + {0x3533, 50}, + {0x3534, 51}, + {0x3535, 52}, + {0x3536, 53}, + {0x3537, 54}, + {0x3538, 55}, + {0x3539, 56}, + {0x353a, 57}, + {0x353b, 58}, + {0x353c, 59}, + {0x353d, 60}, + {0x353e, 61}, + {0x353f, 62}, + {0x3540, 63}, + {0x3541, 64}, + {0x3542, 65}, + {0x3543, 66}, + {0x3544, 67}, + {0x3545, 68}, + {0x3546, 69}, + {0x3547, 70}, + {0x3548, 71}, + {0x3549, 72}, + {0x354a, 73}, + {0x354b, 74}, + {0x354c, 75}, + {0x354d, 76}, + {0x354e, 77}, + {0x354f, 78}, + {0x3550, 79}, + {0x3551, 80}, + {0x3552, 81}, + {0x3553, 82}, + {0x3554, 83}, + {0x3555, 84}, + {0x3556, 85}, + {0x3557, 86}, + {0x3558, 87}, + {0x3559, 88}, + {0x355a, 89}, + {0x355b, 90}, + {0x355c, 91}, + {0x355d, 92}, + {0x355e, 93}, + {0x355f, 94}, + {0x3560, 95}, + {0x3561, 96}, + {0x3562, 97}, + {0x3563, 98}, + {0x3564, 99}, + {0x3565, 100}, + {0x3566, 101}, + {0x3567, 102}, + {0x3568, 103}, + {0x3569, 104}, + {0x356a, 105}, + {0x356b, 106}, + {0x356c, 107}, + {0x356d, 108}, + {0x356e, 109}, + {0x356f, 110}, + {0x3570, 111}, + {0x3571, 112}, + {0x3572, 113}, + {0x3573, 114}, + {0x3574, 115}, + {0x3575, 116}, + {0x3576, 117}, + {0x3577, 118}, + {0x3578, 119}, + {0x3579, 120}, + {0x357a, 121}, + {0x357b, 122}, + {0x357c, 123}, + {0x357d, 124}, + {0x357e, 125}, + {0x357f, 126}, + {0x3580, 127}, + {0x3581, 128}, + {0x3582, 129}, + {0x3583, 130}, + {0x3584, 131}, + {0x3585, 132}, + {0x3586, 133}, + {0x3587, 134}, + {0x3588, 135}, + {0x3589, 136}, + {0x358a, 137}, + {0x358b, 138}, + {0x358c, 139}, + {0x358d, 140}, + {0x358e, 141}, + {0x358f, 142}, + {0x3590, 143}, + {0x3591, 144}, + {0x3592, 145}, + {0x3593, 146}, + {0x3594, 147}, + {0x3595, 148}, + {0x3596, 149}, + {0x3597, 150}, + {0x3598, 151}, + {0x3599, 152}, + {0x359a, 153}, + {0x359b, 154}, + {0x359c, 155}, + {0x359d, 156}, + {0x35a0, 0}, + {0x35a1, 1}, + {0x35a2, 2}, + {0x35a3, 3}, + {0x35a4, 4}, + {0x35a5, 5}, + {0x35a6, 6}, + {0x35a7, 7}, + {0x35a8, 8}, + {0x35a9, 9}, + {0x35aa, 10}, + {0x35ab, 11}, + {0x35ac, 12}, + {0x35ad, 13}, + {0x35ae, 14}, + {0x35af, 15}, + {0x35b0, 16}, + {0x35b1, 17}, + {0x35b2, 18}, + {0x35b3, 19}, + {0x35b4, 20}, + {0x35b5, 21}, + {0x35b6, 22}, + {0x35b7, 23}, + {0x35b8, 24}, + {0x35b9, 25}, + {0x35ba, 26}, + {0x35bb, 27}, + {0x35bc, 28}, + {0x35bd, 29}, + {0x35be, 30}, + {0x35bf, 31}, + {0x35c0, 32}, + {0x35c1, 33}, + {0x35c2, 34}, + {0x35c3, 35}, + {0x35c4, 36}, + {0x35c5, 37}, + {0x35c6, 38}, + {0x35c7, 39}, + {0x35c8, 40}, + {0x35c9, 41}, + {0x35ca, 42}, + {0x35cb, 43}, + {0x35cc, 44}, + {0x35cd, 45}, + {0x35ce, 46}, + {0x35cf, 47}, + {0x35d0, 48}, + {0x35d1, 49}, + {0x35d2, 50}, + {0x35d3, 51}, + {0x35d4, 52}, + {0x35d5, 53}, + {0x35d6, 54}, + {0x35d7, 55}, + {0x35d8, 56}, + {0x35d9, 57}, + {0x35da, 58}, + {0x35db, 59}, + {0x35dc, 60}, + {0x35dd, 61}, + {0x35de, 62}, + {0x35df, 63}, + {0x35e0, 64}, + {0x35e1, 65}, + {0x35e2, 66}, + {0x35e3, 67}, + {0x35e4, 68}, + {0x35e5, 69}, + {0x35e6, 70}, + {0x35e7, 71}, + {0x35e8, 72}, + {0x35e9, 73}, + {0x35ea, 74}, + {0x35eb, 75}, + {0x35ec, 76}, + {0x35ed, 77}, + {0x35ee, 78}, + {0x35ef, 79}, + {0x35f0, 80}, + {0x35f1, 81}, + {0x35f2, 82}, + {0x35f3, 83}, + {0x35f4, 84}, + {0x35f5, 85}, + {0x35f6, 86}, + {0x35f7, 87}, + {0x35f8, 88}, + {0x35f9, 89}, + {0x35fa, 90}, + {0x35fb, 91}, + {0x35fc, 92}, + {0x35fd, 93}, + {0x35fe, 94}, + {0x35ff, 95}, + {0x3601, 0}, + {0x3602, 1}, + {0x3603, 2}, + {0x3604, 3}, + {0x3605, 4}, + {0x3606, 5}, + {0x3607, 6}, + {0x3608, 7}, + {0x3609, 8}, + {0x360a, 9}, + {0x360b, 10}, + {0x360c, 11}, + {0x360d, 12}, + {0x3610, 0}, + {0x3611, 1}, + {0x3612, 2}, + {0x3613, 3}, + {0x3614, 4}, + {0x3615, 5}, + {0x3616, 6}, + {0x3617, 7}, + {0x3618, 8}, + {0x3619, 9}, + {0x361c, 0}, + {0x361d, 1}, + {0x361e, 2}, + {0x361f, 3}, + {0x3620, 4}, + {0x3621, 5}, + {0x3622, 6}, + {0x3623, 7}, + {0x3624, 8}, + {0x3625, 9}, + {0x3626, 10}, + {0x3627, 11}, + {0x3628, 12}, + {0x3629, 13}, + {0x362a, 14}, + {0x362b, 15}, + {0x362c, 16}, + {0x362d, 17}, + {0x362e, 18}, + {0x362f, 19}, + {0x3630, 20}, + {0x3631, 21}, + {0x3632, 22}, + {0x3633, 23}, + {0x3634, 24}, + {0x3635, 25}, + {0x3636, 26}, + {0x3637, 27}, + {0x3638, 28}, + {0x3639, 29}, + {0x363a, 30}, + {0x363b, 31}, + {0x363c, 32}, + {0x363d, 33}, + {0x363e, 34}, + {0x363f, 35}, + {0x3640, 36}, + {0x3641, 37}, + {0x3642, 38}, + {0x3643, 39}, + {0x3644, 40}, + {0x3645, 41}, + {0x3646, 42}, + {0x3647, 43}, + {0x3648, 44}, + {0x3649, 45}, + {0x364a, 46}, + {0x364b, 47}, + {0x364c, 48}, + {0x364d, 49}, + {0x364e, 50}, + {0x364f, 51}, + {0x3650, 52}, + {0x3651, 53}, + {0x3652, 54}, + {0x3653, 55}, + {0x3654, 56}, + {0x3655, 57}, + {0x3656, 58}, + {0x3657, 59}, + {0x3658, 60}, + {0x3659, 61}, + {0x365a, 62}, + {0x365b, 63}, + {0x365c, 64}, + {0x365d, 65}, + {0x365e, 66}, + {0x365f, 67}, + {0x3660, 68}, + {0x3661, 69}, + {0x3662, 70}, + {0x3663, 71}, + {0x3664, 72}, + {0x3665, 73}, + {0x3666, 74}, + {0x3667, 75}, + {0x3668, 76}, + {0x3669, 77}, + {0x366a, 78}, + {0x366b, 79}, + {0x366c, 80}, + {0x366d, 81}, + {0x366e, 82}, + {0x366f, 83}, + {0x3670, 84}, + {0x3671, 85}, + {0x3672, 86}, + {0x3673, 87}, + {0x3674, 88}, + {0x3675, 89}, + {0x3676, 90}, + {0x3677, 91}, + {0x3678, 92}, + {0x3679, 93}, + {0x367a, 94}, + {0x367b, 95}, + {0x367c, 96}, + {0x367d, 97}, + {0x367e, 98}, + {0x367f, 99}, + {0x3680, 100}, + {0x3681, 101}, + {0x3682, 102}, + {0x3683, 103}, + {0x3684, 104}, + {0x3685, 105}, + {0x3686, 106}, + {0x3687, 107}, + {0x3688, 108}, + {0x3689, 109}, + {0x368a, 110}, + {0x368b, 111}, + {0x368c, 112}, + {0x368d, 113}, + {0x368e, 114}, + {0x368f, 115}, + {0x3690, 116}, + {0x3691, 117}, + {0x3692, 118}, + {0x3693, 119}, + {0x3694, 120}, + {0x3695, 121}, + {0x3696, 122}, + {0x3697, 123}, + {0x3698, 124}, + {0x3699, 125}, + {0x369a, 126}, + {0x369b, 127}, + {0x369c, 128}, + {0x369d, 129}, + {0x369e, 130}, + {0x369f, 131}, + {0x36a0, 132}, + {0x36a1, 133}, + {0x36a2, 134}, + {0x36a3, 135}, + {0x36a4, 136}, + {0x36a5, 137}, + {0x36a6, 138}, + {0x36a7, 139}, + {0x36a8, 140}, + {0x36a9, 141}, + {0x36aa, 142}, + {0x36ab, 143}, + {0x36ac, 144}, + {0x36ad, 145}, + {0x36ae, 146}, + {0x36af, 147}, + {0x36b0, 148}, + {0x36b1, 149}, + {0x36b2, 150}, + {0x36b3, 151}, + {0x36b4, 152}, + {0x36b5, 153}, + {0x36b6, 154}, + {0x36b7, 155}, + {0x36b8, 156}, + {0x36b9, 157}, + {0x36ba, 158}, + {0x36bb, 159}, + {0x36bc, 160}, + {0x36bd, 161}, + {0x36be, 162}, + {0x36bf, 163}, + {0x36c0, 164}, + {0x36c1, 165}, + {0x36c2, 166}, + {0x36c3, 167}, + {0x36c4, 168}, + {0x36c5, 169}, + {0x36c6, 170}, + {0x36c7, 171}, + {0x36c8, 172}, + {0x36c9, 173}, + {0x36ca, 174}, + {0x36cb, 175}, + {0x36cc, 176}, + {0x36cd, 177}, + {0x36ce, 178}, + {0x36cf, 179}, + {0x36d0, 180}, + {0x36d1, 181}, + {0x36d2, 182}, + {0x36d3, 183}, + {0x36d4, 184}, + {0x36d5, 185}, + {0x36d6, 186}, + {0x36d7, 187}, + {0x36d8, 188}, + {0x36d9, 189}, + {0x36da, 190}, + {0x36db, 191}, + {0x36dc, 192}, + {0x36dd, 193}, + {0x36de, 194}, + {0x36df, 195}, + {0x36e0, 196}, + {0x36e1, 197}, + {0x36e2, 198}, + {0x36e3, 199}, + {0x36e4, 200}, + {0x36e5, 201}, + {0x36e6, 202}, + {0x36e7, 203}, + {0x36e8, 204}, + {0x36e9, 205}, + {0x36ea, 206}, + {0x36eb, 207}, + {0x36ec, 208}, + {0x36ed, 209}, + {0x36ee, 210}, + {0x36ef, 211}, + {0x36f0, 212}, + {0x36f1, 213}, + {0x36f2, 214}, + {0x36f3, 215}, + {0x36f4, 216}, + {0x36f5, 217}, + {0x36f6, 218}, + {0x36f7, 219}, + {0x36f8, 220}, + {0x36f9, 221}, + {0x36fa, 222}, + {0x36fb, 223}, + {0x36fc, 224}, + {0x36fd, 225}, + {0x36fe, 226}, + {0x36ff, 227}, + {0x3701, 0}, + {0x3702, 1}, + {0x3703, 2}, + {0x3704, 3}, + {0x3705, 4}, + {0x3706, 5}, + {0x3707, 6}, + {0x3708, 7}, + {0x3709, 8}, + {0x370a, 9}, + {0x370b, 10}, + {0x370c, 11}, + {0x370d, 12}, + {0x370e, 13}, + {0x370f, 14}, + {0x3710, 15}, + {0x3711, 16}, + {0x3712, 17}, + {0x3713, 18}, + {0x3714, 19}, + {0x3715, 20}, + {0x3716, 21}, + {0x3717, 22}, + {0x3718, 23}, + {0x3719, 24}, + {0x371a, 25}, + {0x371b, 26}, + {0x371c, 27}, + {0x371d, 28}, + {0x371e, 29}, + {0x371f, 30}, + {0x3720, 31}, + {0x3721, 32}, + {0x3722, 33}, + {0x3723, 34}, + {0x3724, 35}, + {0x3725, 36}, + {0x3726, 37}, + {0x3727, 38}, + {0x3728, 39}, + {0x3729, 40}, + {0x372a, 41}, + {0x372b, 42}, + {0x372c, 43}, + {0x372d, 44}, + {0x372e, 45}, + {0x372f, 46}, + {0x3730, 47}, + {0x3731, 48}, + {0x3732, 49}, + {0x3733, 50}, + {0x3734, 51}, + {0x3735, 52}, + {0x3736, 53}, + {0x3737, 54}, + {0x3738, 55}, + {0x3739, 56}, + {0x373a, 57}, + {0x373b, 58}, + {0x373c, 59}, + {0x373d, 60}, + {0x373e, 61}, + {0x373f, 62}, + {0x3740, 63}, + {0x3741, 64}, + {0x3742, 65}, + {0x3743, 66}, + {0x3744, 67}, + {0x3745, 68}, + {0x3746, 69}, + {0x3747, 70}, + {0x3748, 71}, + {0x3749, 72}, + {0x374a, 73}, + {0x374b, 74}, + {0x374c, 75}, + {0x374d, 76}, + {0x374e, 77}, + {0x374f, 78}, + {0x3750, 79}, + {0x3751, 80}, + {0x3752, 81}, + {0x3753, 82}, + {0x3754, 83}, + {0x3755, 84}, + {0x3756, 85}, + {0x3757, 86}, + {0x3758, 87}, + {0x3759, 88}, + {0x375a, 89}, + {0x375b, 90}, + {0x375c, 91}, + {0x375d, 92}, + {0x375e, 93}, + {0x375f, 94}, + {0x3760, 95}, + {0x3761, 96}, + {0x3762, 97}, + {0x3763, 98}, + {0x3764, 99}, + {0x3765, 100}, + {0x3766, 101}, + {0x3767, 102}, + {0x3768, 103}, + {0x3769, 104}, + {0x376a, 105}, + {0x376b, 106}, + {0x376c, 107}, + {0x376d, 108}, + {0x376e, 109}, + {0x376f, 110}, + {0x3770, 111}, + {0x3771, 112}, + {0x3772, 113}, + {0x3773, 114}, + {0x3774, 115}, + {0x3775, 116}, + {0x3776, 117}, + {0x3777, 118}, + {0x3778, 119}, + {0x3779, 120}, + {0x377a, 121}, + {0x377b, 122}, + {0x377c, 123}, + {0x377d, 124}, + {0x377e, 125}, + {0x377f, 126}, + {0x3780, 127}, + {0x3781, 128}, + {0x3782, 129}, + {0x3783, 130}, + {0x3784, 131}, + {0x3785, 132}, + {0x3786, 133}, + {0x3787, 134}, + {0x3788, 135}, + {0x3789, 136}, + {0x378a, 137}, + {0x378b, 138}, + {0x378c, 139}, + {0x378d, 140}, + {0x378e, 141}, + {0x378f, 142}, + {0x3790, 143}, + {0x3791, 144}, + {0x3792, 145}, + {0x3793, 146}, + {0x3794, 147}, + {0x3795, 148}, + {0x3796, 149}, + {0x3797, 150}, + {0x3798, 151}, + {0x3799, 152}, + {0x379a, 153}, + {0x379b, 154}, + {0x379c, 155}, + {0x379d, 156}, + {0x379e, 157}, + {0x379f, 158}, + {0x37a0, 159}, + {0x37a1, 160}, + {0x37a2, 161}, + {0x37a3, 162}, + {0x37a4, 163}, + {0x37a5, 164}, + {0x37a6, 165}, + {0x37a7, 166}, + {0x37a8, 167}, + {0x37a9, 168}, + {0x37aa, 169}, + {0x37ab, 170}, + {0x37ac, 171}, + {0x37ad, 172}, + {0x37ae, 173}, + {0x37af, 174}, + {0x37b0, 175}, + {0x37b1, 176}, + {0x37b2, 177}, + {0x37b3, 178}, + {0x37b4, 179}, + {0x37b5, 180}, + {0x37b6, 181}, + {0x37b7, 182}, + {0x37b8, 183}, + {0x37b9, 184}, + {0x37ba, 185}, + {0x37bb, 186}, + {0x37bc, 187}, + {0x37bd, 188}, + {0x37be, 189}, + {0x37bf, 190}, + {0x37c0, 191}, + {0x37c1, 192}, + {0x37c2, 193}, + {0x37c3, 194}, + {0x37c4, 195}, + {0x37c5, 196}, + {0x37c6, 197}, + {0x37c7, 198}, + {0x37c8, 199}, + {0x37c9, 200}, + {0x37ca, 201}, + {0x37cb, 202}, + {0x37cc, 203}, + {0x37cd, 204}, + {0x37ce, 205}, + {0x37cf, 206}, + {0x37d0, 207}, + {0x37d1, 208}, + {0x37d2, 209}, + {0x37d3, 210}, + {0x37d4, 211}, + {0x37d5, 212}, + {0x37d6, 213}, + {0x37d7, 214}, + {0x37d8, 215}, + {0x37d9, 216}, + {0x37da, 217}, + {0x37db, 218}, + {0x37dc, 219}, + {0x37dd, 220}, + {0x37de, 221}, + {0x37df, 222}, + {0x37e0, 223}, + {0x37e1, 224}, + {0x37e2, 225}, + {0x37e3, 226}, + {0x37e4, 227}, + {0x37e5, 228}, + {0x37e6, 229}, + {0x37e7, 230}, + {0x37e8, 231}, + {0x37e9, 232}, + {0x37ea, 233}, + {0x37eb, 234}, + {0x37ec, 235}, + {0x37ed, 236}, + {0x37ee, 237}, + {0x37ef, 238}, + {0x37f0, 239}, + {0x37f1, 240}, + {0x37f2, 241}, + {0x37f3, 242}, + {0x37f4, 243}, + {0x37f5, 244}, + {0x37f6, 245}, + {0x37f7, 246}, + {0x37f8, 247}, + {0x37f9, 248}, + {0x37fa, 249}, + {0x37fb, 250}, + {0x37fc, 251}, + {0x37fd, 252}, + {0x37fe, 253}, + {0x37ff, 254}, + {0x3801, 0}, + {0x3802, 1}, + {0x3803, 2}, + {0x3804, 3}, + {0x3805, 4}, + {0x3806, 5}, + {0x3807, 6}, + {0x3808, 7}, + {0x3809, 8}, + {0x380a, 9}, + {0x380b, 10}, + {0x380c, 11}, + {0x380d, 12}, + {0x380e, 13}, + {0x380f, 14}, + {0x3810, 15}, + {0x3811, 16}, + {0x3812, 17}, + {0x3813, 18}, + {0x3814, 19}, + {0x3815, 20}, + {0x3816, 21}, + {0x3817, 22}, + {0x3818, 23}, + {0x3819, 24}, + {0x381a, 25}, + {0x381b, 26}, + {0x381c, 27}, + {0x381d, 28}, + {0x381e, 29}, + {0x381f, 30}, + {0x3820, 31}, + {0x3821, 32}, + {0x3822, 33}, + {0x3823, 34}, + {0x3824, 35}, + {0x3825, 36}, + {0x3826, 37}, + {0x3827, 38}, + {0x3828, 39}, + {0x3829, 40}, + {0x382a, 41}, + {0x382b, 42}, + {0x382c, 43}, + {0x382d, 44}, + {0x382e, 45}, + {0x382f, 46}, + {0x3830, 47}, + {0x3831, 48}, + {0x3832, 49}, + {0x3833, 50}, + {0x3834, 51}, + {0x3835, 52}, + {0x3836, 53}, + {0x3837, 54}, + {0x3838, 55}, + {0x3839, 56}, + {0x383a, 57}, + {0x383b, 58}, + {0x383c, 59}, + {0x383d, 60}, + {0x383e, 61}, + {0x383f, 62}, + {0x3840, 63}, + {0x3841, 64}, + {0x3842, 65}, + {0x3843, 66}, + {0x3844, 67}, + {0x3845, 68}, + {0x3846, 69}, + {0x3847, 70}, + {0x3848, 71}, + {0x3849, 72}, + {0x384a, 73}, + {0x384b, 74}, + {0x384c, 75}, + {0x384d, 76}, + {0x384e, 77}, + {0x384f, 78}, + {0x3850, 79}, + {0x3851, 80}, + {0x3852, 81}, + {0x3853, 82}, + {0x3854, 83}, + {0x3855, 84}, + {0x3856, 85}, + {0x3857, 86}, + {0x3858, 87}, + {0x3859, 88}, + {0x385a, 89}, + {0x385b, 90}, + {0x385c, 91}, + {0x385d, 92}, + {0x385e, 93}, + {0x385f, 94}, + {0x3860, 95}, + {0x3861, 96}, + {0x3862, 97}, + {0x3863, 98}, + {0x3864, 99}, + {0x3865, 100}, + {0x3866, 101}, + {0x3867, 102}, + {0x3868, 103}, + {0x3869, 104}, + {0x386a, 105}, + {0x386b, 106}, + {0x386c, 107}, + {0x386d, 108}, + {0x386e, 109}, + {0x386f, 110}, + {0x3870, 111}, + {0x3871, 112}, + {0x3872, 113}, + {0x3873, 114}, + {0x3874, 115}, + {0x3875, 116}, + {0x3876, 117}, + {0x3877, 118}, + {0x3878, 119}, + {0x3879, 120}, + {0x387a, 121}, + {0x387b, 122}, + {0x387c, 123}, + {0x387d, 124}, + {0x387e, 125}, + {0x387f, 126}, + {0x3880, 127}, + {0x3881, 128}, + {0x3882, 129}, + {0x3883, 130}, + {0x3884, 131}, + {0x3885, 132}, + {0x3886, 133}, + {0x3887, 134}, + {0x3888, 135}, + {0x3889, 136}, + {0x388a, 137}, + {0x388b, 138}, + {0x388c, 139}, + {0x388d, 140}, + {0x388e, 141}, + {0x388f, 142}, + {0x3890, 143}, + {0x3891, 144}, + {0x3892, 145}, + {0x3893, 146}, + {0x3894, 147}, + {0x3895, 148}, + {0x3896, 149}, + {0x3897, 150}, + {0x3898, 151}, + {0x3899, 152}, + {0x389a, 153}, + {0x389b, 154}, + {0x389c, 155}, + {0x389d, 156}, + {0x389e, 157}, + {0x389f, 158}, + {0x38a0, 159}, + {0x38a1, 160}, + {0x38a2, 161}, + {0x38a3, 162}, + {0x38a4, 163}, + {0x38a5, 164}, + {0x38a6, 165}, + {0x38a7, 166}, + {0x38a8, 167}, + {0x38a9, 168}, + {0x38aa, 169}, + {0x38ab, 170}, + {0x38ac, 171}, + {0x38ad, 172}, + {0x38ae, 173}, + {0x38af, 174}, + {0x38b0, 175}, + {0x38b1, 176}, + {0x38b2, 177}, + {0x38b3, 178}, + {0x38b4, 179}, + {0x38b5, 180}, + {0x38b6, 181}, + {0x38b7, 182}, + {0x38b8, 183}, + {0x38b9, 184}, + {0x38ba, 185}, + {0x38bb, 186}, + {0x38bc, 187}, + {0x38bd, 188}, + {0x38be, 189}, + {0x38bf, 190}, + {0x38c0, 191}, + {0x38c1, 192}, + {0x38c2, 193}, + {0x38c3, 194}, + {0x38c4, 195}, + {0x38c5, 196}, + {0x38c6, 197}, + {0x38c7, 198}, + {0x38c8, 199}, + {0x38c9, 200}, + {0x38ca, 201}, + {0x38cb, 202}, + {0x38cc, 203}, + {0x38cd, 204}, + {0x38ce, 205}, + {0x38cf, 206}, + {0x38d0, 207}, + {0x38d1, 208}, + {0x38d2, 209}, + {0x38d3, 210}, + {0x38d4, 211}, + {0x38d5, 212}, + {0x38d6, 213}, + {0x38d7, 214}, + {0x38d8, 215}, + {0x38d9, 216}, + {0x38da, 217}, + {0x38db, 218}, + {0x38dc, 219}, + {0x38dd, 220}, + {0x38de, 221}, + {0x38df, 222}, + {0x38e0, 223}, + {0x38e1, 224}, + {0x38e2, 225}, + {0x38e3, 226}, + {0x38e4, 227}, + {0x38e5, 228}, + {0x38e6, 229}, + {0x38e7, 230}, + {0x38e8, 231}, + {0x38e9, 232}, + {0x38ea, 233}, + {0x38eb, 234}, + {0x38ec, 235}, + {0x38ed, 236}, + {0x38ee, 237}, + {0x38ef, 238}, + {0x38f0, 239}, + {0x38f1, 240}, + {0x38f2, 241}, + {0x38f3, 242}, + {0x38f4, 243}, + {0x38f5, 244}, + {0x38f6, 245}, + {0x38f7, 246}, + {0x38f8, 247}, + {0x38f9, 248}, + {0x38fa, 249}, + {0x38fb, 250}, + {0x38fc, 251}, + {0x38fd, 252}, + {0x38fe, 253}, + {0x38ff, 254}, + {0x3901, 0}, + {0x3902, 1}, + {0x3903, 2}, + {0x3904, 3}, + {0x3905, 4}, + {0x3906, 5}, + {0x3907, 6}, + {0x3908, 7}, + {0x3909, 8}, + {0x390a, 9}, + {0x390b, 10}, + {0x390c, 11}, + {0x390d, 12}, + {0x390e, 13}, + {0x390f, 14}, + {0x3910, 15}, + {0x3911, 16}, + {0x3912, 17}, + {0x3913, 18}, + {0x3914, 19}, + {0x3915, 20}, + {0x3916, 21}, + {0x3917, 22}, + {0x391a, 0}, + {0x391b, 1}, + {0x391c, 2}, + {0x391d, 3}, + {0x391e, 4}, + {0x391f, 5}, + {0x3920, 6}, + {0x3921, 7}, + {0x3922, 8}, + {0x3923, 9}, + {0x3924, 10}, + {0x3925, 11}, + {0x3926, 12}, + {0x3927, 13}, + {0x3928, 14}, + {0x3929, 15}, + {0x392a, 16}, + {0x392b, 17}, + {0x392c, 18}, + {0x392d, 19}, + {0x392e, 20}, + {0x392f, 21}, + {0x3930, 22}, + {0x3931, 23}, + {0x3932, 24}, + {0x3933, 25}, + {0x3934, 26}, + {0x3935, 27}, + {0x3936, 28}, + {0x3937, 29}, + {0x3938, 30}, + {0x3939, 31}, + {0x393a, 32}, + {0x393b, 33}, + {0x393c, 34}, + {0x393d, 35}, + {0x393e, 36}, + {0x393f, 37}, + {0x3940, 38}, + {0x3941, 39}, + {0x3942, 40}, + {0x3943, 41}, + {0x3944, 42}, + {0x3945, 43}, + {0x3946, 44}, + {0x3947, 45}, + {0x3948, 46}, + {0x3949, 47}, + {0x394a, 48}, + {0x394b, 49}, + {0x394c, 50}, + {0x394d, 51}, + {0x394e, 52}, + {0x394f, 53}, + {0x3950, 54}, + {0x3951, 55}, + {0x3952, 56}, + {0x3953, 57}, + {0x3954, 58}, + {0x3955, 59}, + {0x3956, 60}, + {0x3957, 61}, + {0x3958, 62}, + {0x3959, 63}, + {0x395a, 64}, + {0x395b, 65}, + {0x395c, 66}, + {0x395d, 67}, + {0x395e, 68}, + {0x395f, 69}, + {0x3960, 70}, + {0x3961, 71}, + {0x3962, 72}, + {0x3963, 73}, + {0x3964, 74}, + {0x3965, 75}, + {0x3966, 76}, + {0x3967, 77}, + {0x3968, 78}, + {0x3969, 79}, + {0x396a, 80}, + {0x396b, 81}, + {0x396c, 82}, + {0x396d, 83}, + {0x3970, 0}, + {0x3971, 1}, + {0x3972, 2}, + {0x3973, 3}, + {0x3974, 4}, + {0x3975, 5}, + {0x3976, 6}, + {0x3977, 7}, + {0x3978, 8}, + {0x3979, 9}, + {0x397a, 10}, + {0x397b, 11}, + {0x397c, 12}, + {0x397d, 13}, + {0x397e, 14}, + {0x397f, 15}, + {0x3980, 16}, + {0x3981, 17}, + {0x3982, 18}, + {0x3983, 19}, + {0x3984, 20}, + {0x3985, 21}, + {0x3986, 22}, + {0x3987, 23}, + {0x3988, 24}, + {0x3989, 25}, + {0x398a, 26}, + {0x398b, 27}, + {0x398c, 28}, + {0x398d, 29}, + {0x398e, 30}, + {0x398f, 31}, + {0x3990, 32}, + {0x3991, 33}, + {0x3992, 34}, + {0x3993, 35}, + {0x3994, 36}, + {0x3995, 37}, + {0x3996, 38}, + {0x3997, 39}, + {0x3998, 40}, + {0x3999, 41}, + {0x399a, 42}, + {0x399b, 43}, + {0x399c, 44}, + {0x399d, 45}, + {0x399e, 46}, + {0x399f, 47}, + {0x39a0, 48}, + {0x39a1, 49}, + {0x39a2, 50}, + {0x39a3, 51}, + {0x39a4, 52}, + {0x39a5, 53}, + {0x39a6, 54}, + {0x39a7, 55}, + {0x39a8, 56}, + {0x39a9, 57}, + {0x39aa, 58}, + {0x39ab, 59}, + {0x39ac, 60}, + {0x39ad, 61}, + {0x39ae, 62}, + {0x39af, 63}, + {0x39b0, 64}, + {0x39b1, 65}, + {0x39b2, 66}, + {0x39b3, 67}, + {0x39b4, 68}, + {0x39b5, 69}, + {0x39b6, 70}, + {0x39b7, 71}, + {0x39b8, 72}, + {0x39b9, 73}, + {0x39ba, 74}, + {0x39bb, 75}, + {0x39bc, 76}, + {0x39bd, 77}, + {0x39be, 78}, + {0x39bf, 79}, + {0x39c0, 80}, + {0x39c1, 81}, + {0x39c2, 82}, + {0x39c3, 83}, + {0x39c4, 84}, + {0x39c5, 85}, + {0x39c6, 86}, + {0x39c7, 87}, + {0x39c8, 88}, + {0x39c9, 89}, + {0x39ca, 90}, + {0x39cb, 91}, + {0x39cc, 92}, + {0x39cd, 93}, + {0x39ce, 94}, + {0x39d2, 0}, + {0x39d3, 1}, + {0x39d4, 2}, + {0x39d5, 3}, + {0x39d6, 4}, + {0x39d7, 5}, + {0x39d8, 6}, + {0x39d9, 7}, + {0x39da, 8}, + {0x39db, 9}, + {0x39dc, 10}, + {0x39dd, 11}, + {0x39de, 12}, + {0x39e1, 0}, + {0x39e2, 1}, + {0x39e3, 2}, + {0x39e4, 3}, + {0x39e5, 4}, + {0x39e6, 5}, + {0x39e7, 6}, + {0x39e8, 7}, + {0x39e9, 8}, + {0x39ea, 9}, + {0x39eb, 10}, + {0x39ec, 11}, + {0x39ed, 12}, + {0x39ee, 13}, + {0x39ef, 14}, + {0x39f0, 15}, + {0x39f1, 16}, + {0x39f2, 17}, + {0x39f3, 18}, + {0x39f4, 19}, + {0x39f5, 20}, + {0x39f6, 21}, + {0x39f7, 22}, + {0x39f8, 23}, + {0x39f9, 24}, + {0x39fa, 25}, + {0x39fb, 26}, + {0x39fc, 27}, + {0x39fd, 28}, + {0x39fe, 29}, + {0x39ff, 30}, + {0x3a01, 0}, + {0x3a02, 1}, + {0x3a03, 2}, + {0x3a04, 3}, + {0x3a05, 4}, + {0x3a06, 5}, + {0x3a07, 6}, + {0x3a08, 7}, + {0x3a09, 8}, + {0x3a0a, 9}, + {0x3a0b, 10}, + {0x3a0c, 11}, + {0x3a0d, 12}, + {0x3a0e, 13}, + {0x3a0f, 14}, + {0x3a10, 15}, + {0x3a11, 16}, + {0x3a12, 17}, + {0x3a13, 18}, + {0x3a14, 19}, + {0x3a15, 20}, + {0x3a16, 21}, + {0x3a17, 22}, + {0x3a18, 23}, + {0x3a19, 24}, + {0x3a1a, 25}, + {0x3a1b, 26}, + {0x3a1c, 27}, + {0x3a1d, 28}, + {0x3a1e, 29}, + {0x3a1f, 30}, + {0x3a20, 31}, + {0x3a21, 32}, + {0x3a22, 33}, + {0x3a23, 34}, + {0x3a24, 35}, + {0x3a25, 36}, + {0x3a26, 37}, + {0x3a27, 38}, + {0x3a28, 39}, + {0x3a29, 40}, + {0x3a2a, 41}, + {0x3a2b, 42}, + {0x3a2c, 43}, + {0x3a2d, 44}, + {0x3a2e, 45}, + {0x3a2f, 46}, + {0x3a30, 47}, + {0x3a31, 48}, + {0x3a32, 49}, + {0x3a33, 50}, + {0x3a34, 51}, + {0x3a35, 52}, + {0x3a36, 53}, + {0x3a37, 54}, + {0x3a38, 55}, + {0x3a39, 56}, + {0x3a3a, 57}, + {0x3a3b, 58}, + {0x3a3c, 59}, + {0x3a3d, 60}, + {0x3a3e, 61}, + {0x3a3f, 62}, + {0x3a40, 63}, + {0x3a41, 64}, + {0x3a42, 65}, + {0x3a43, 66}, + {0x3a44, 67}, + {0x3a45, 68}, + {0x3a46, 69}, + {0x3a47, 70}, + {0x3a48, 71}, + {0x3a49, 72}, + {0x3a4a, 73}, + {0x3a4b, 74}, + {0x3a4c, 75}, + {0x3a4d, 76}, + {0x3a4e, 77}, + {0x3a4f, 78}, + {0x3a50, 79}, + {0x3a51, 80}, + {0x3a52, 81}, + {0x3a53, 82}, + {0x3a54, 83}, + {0x3a55, 84}, + {0x3a56, 85}, + {0x3a57, 86}, + {0x3a58, 87}, + {0x3a59, 88}, + {0x3a5a, 89}, + {0x3a5b, 90}, + {0x3a5c, 91}, + {0x3a5d, 92}, + {0x3a5e, 93}, + {0x3a5f, 94}, + {0x3a60, 95}, + {0x3a61, 96}, + {0x3a62, 97}, + {0x3a63, 98}, + {0x3a64, 99}, + {0x3a65, 100}, + {0x3a66, 101}, + {0x3a67, 102}, + {0x3a68, 103}, + {0x3a69, 104}, + {0x3a6a, 105}, + {0x3a6b, 106}, + {0x3a6c, 107}, + {0x3a6d, 108}, + {0x3a6e, 109}, + {0x3a6f, 110}, + {0x3a70, 111}, + {0x3a71, 112}, + {0x3a72, 113}, + {0x3a75, 0}, + {0x3a76, 1}, + {0x3a77, 2}, + {0x3a78, 3}, + {0x3a79, 4}, + {0x3a7a, 5}, + {0x3a7b, 6}, + {0x3a7c, 7}, + {0x3a7d, 8}, + {0x3a7e, 9}, + {0x3a7f, 10}, + {0x3a80, 11}, + {0x3a81, 12}, + {0x3a82, 13}, + {0x3a83, 14}, + {0x3a84, 15}, + {0x3a85, 16}, + {0x3a86, 17}, + {0x3a87, 18}, + {0x3a88, 19}, + {0x3a89, 20}, + {0x3a8a, 21}, + {0x3a8b, 22}, + {0x3a8c, 23}, + {0x3a8d, 24}, + {0x3a8e, 25}, + {0x3a8f, 26}, + {0x3a90, 27}, + {0x3a91, 28}, + {0x3a92, 29}, + {0x3a93, 30}, + {0x3a94, 31}, + {0x3a95, 32}, + {0x3a96, 33}, + {0x3a97, 34}, + {0x3a98, 35}, + {0x3a99, 36}, + {0x3a9a, 37}, + {0x3a9b, 38}, + {0x3a9c, 39}, + {0x3a9d, 40}, + {0x3a9e, 41}, + {0x3a9f, 42}, + {0x3aa0, 43}, + {0x3aa1, 44}, + {0x3aa2, 45}, + {0x3aa3, 46}, + {0x3aa4, 47}, + {0x3aa5, 48}, + {0x3aa6, 49}, + {0x3aa7, 50}, + {0x3aa8, 51}, + {0x3aa9, 52}, + {0x3aaa, 53}, + {0x3aab, 54}, + {0x3aac, 55}, + {0x3aad, 56}, + {0x3aae, 57}, + {0x3aaf, 58}, + {0x3ab0, 59}, + {0x3ab1, 60}, + {0x3ab2, 61}, + {0x3ab3, 62}, + {0x3ab4, 63}, + {0x3ab5, 64}, + {0x3ab6, 65}, + {0x3ab7, 66}, + {0x3ab8, 67}, + {0x3ab9, 68}, + {0x3aba, 69}, + {0x3abb, 70}, + {0x3abc, 71}, + {0x3abd, 72}, + {0x3abe, 73}, + {0x3abf, 74}, + {0x3ac0, 75}, + {0x3ac1, 76}, + {0x3ac2, 77}, + {0x3ac3, 78}, + {0x3ac4, 79}, + {0x3ac5, 80}, + {0x3ac6, 81}, + {0x3ac7, 82}, + {0x3ac8, 83}, + {0x3ac9, 84}, + {0x3aca, 85}, + {0x3acb, 86}, + {0x3acc, 87}, + {0x3acd, 88}, + {0x3ace, 89}, + {0x3acf, 90}, + {0x3ad0, 91}, + {0x3ad1, 92}, + {0x3ad2, 93}, + {0x3ad3, 94}, + {0x3ad4, 95}, + {0x3ad5, 96}, + {0x3ad6, 97}, + {0x3ad7, 98}, + {0x3ad8, 99}, + {0x3ad9, 100}, + {0x3ada, 101}, + {0x3adb, 102}, + {0x3adc, 103}, + {0x3add, 104}, + {0x3ade, 105}, + {0x3adf, 106}, + {0x3ae0, 107}, + {0x3ae1, 108}, + {0x3ae2, 109}, + {0x3ae3, 110}, + {0x3ae4, 111}, + {0x3ae5, 112}, + {0x3ae6, 113}, + {0x3ae7, 114}, + {0x3ae8, 115}, + {0x3ae9, 116}, + {0x3aea, 117}, + {0x3aeb, 118}, + {0x3aec, 119}, + {0x3aed, 120}, + {0x3aee, 121}, + {0x3aef, 122}, + {0x3af0, 123}, + {0x3af1, 124}, + {0x3af2, 125}, + {0x3af3, 126}, + {0x3af4, 127}, + {0x3af5, 128}, + {0x3af6, 129}, + {0x3af7, 130}, + {0x3af8, 131}, + {0x3af9, 132}, + {0x3afa, 133}, + {0x3afb, 134}, + {0x3afc, 135}, + {0x3afd, 136}, + {0x3afe, 137}, + {0x3aff, 138}, + {0x3b01, 0}, + {0x3b02, 1}, + {0x3b03, 2}, + {0x3b04, 3}, + {0x3b05, 4}, + {0x3b06, 5}, + {0x3b07, 6}, + {0x3b08, 7}, + {0x3b09, 8}, + {0x3b0a, 9}, + {0x3b0b, 10}, + {0x3b0c, 11}, + {0x3b0d, 12}, + {0x3b0e, 13}, + {0x3b0f, 14}, + {0x3b10, 15}, + {0x3b11, 16}, + {0x3b12, 17}, + {0x3b13, 18}, + {0x3b14, 19}, + {0x3b15, 20}, + {0x3b16, 21}, + {0x3b17, 22}, + {0x3b18, 23}, + {0x3b19, 24}, + {0x3b1a, 25}, + {0x3b1b, 26}, + {0x3b1c, 27}, + {0x3b1d, 28}, + {0x3b1e, 29}, + {0x3b1f, 30}, + {0x3b20, 31}, + {0x3b21, 32}, + {0x3b22, 33}, + {0x3b23, 34}, + {0x3b24, 35}, + {0x3b25, 36}, + {0x3b26, 37}, + {0x3b27, 38}, + {0x3b28, 39}, + {0x3b29, 40}, + {0x3b2a, 41}, + {0x3b2b, 42}, + {0x3b2c, 43}, + {0x3b2d, 44}, + {0x3b2e, 45}, + {0x3b2f, 46}, + {0x3b30, 47}, + {0x3b31, 48}, + {0x3b32, 49}, + {0x3b33, 50}, + {0x3b34, 51}, + {0x3b35, 52}, + {0x3b36, 53}, + {0x3b37, 54}, + {0x3b38, 55}, + {0x3b39, 56}, + {0x3b3a, 57}, + {0x3b3b, 58}, + {0x3b3c, 59}, + {0x3b3d, 60}, + {0x3b3e, 61}, + {0x3b3f, 62}, + {0x3b40, 63}, + {0x3b41, 64}, + {0x3b42, 65}, + {0x3b43, 66}, + {0x3b44, 67}, + {0x3b45, 68}, + {0x3b46, 69}, + {0x3b47, 70}, + {0x3b48, 71}, + {0x3b49, 72}, + {0x3b4a, 73}, + {0x3b4b, 74}, + {0x3b4c, 75}, + {0x3b4d, 76}, + {0x3b50, 0}, + {0x3b51, 1}, + {0x3b52, 2}, + {0x3b53, 3}, + {0x3b54, 4}, + {0x3b55, 5}, + {0x3b56, 6}, + {0x3b57, 7}, + {0x3b58, 8}, + {0x3b59, 9}, + {0x3b5a, 10}, + {0x3b5b, 11}, + {0x3b5c, 12}, + {0x3b5d, 13}, + {0x3b5e, 14}, + {0x3b5f, 15}, + {0x3b60, 16}, + {0x3b61, 17}, + {0x3b62, 18}, + {0x3b63, 19}, + {0x3b64, 20}, + {0x3b65, 21}, + {0x3b66, 22}, + {0x3b67, 23}, + {0x3b68, 24}, + {0x3b69, 25}, + {0x3b6a, 26}, + {0x3b6b, 27}, + {0x3b6c, 28}, + {0x3b6d, 29}, + {0x3b6e, 30}, + {0x3b6f, 31}, + {0x3b70, 32}, + {0x3b71, 33}, + {0x3b72, 34}, + {0x3b73, 35}, + {0x3b74, 36}, + {0x3b75, 37}, + {0x3b76, 38}, + {0x3b77, 39}, + {0x3b78, 40}, + {0x3b79, 41}, + {0x3b7a, 42}, + {0x3b7b, 43}, + {0x3b7c, 44}, + {0x3b7d, 45}, + {0x3b7e, 46}, + {0x3b7f, 47}, + {0x3b80, 48}, + {0x3b81, 49}, + {0x3b82, 50}, + {0x3b83, 51}, + {0x3b84, 52}, + {0x3b85, 53}, + {0x3b86, 54}, + {0x3b87, 55}, + {0x3b88, 56}, + {0x3b89, 57}, + {0x3b8a, 58}, + {0x3b8b, 59}, + {0x3b8c, 60}, + {0x3b8d, 61}, + {0x3b8e, 62}, + {0x3b8f, 63}, + {0x3b90, 64}, + {0x3b91, 65}, + {0x3b92, 66}, + {0x3b93, 67}, + {0x3b94, 68}, + {0x3b95, 69}, + {0x3b96, 70}, + {0x3b97, 71}, + {0x3b98, 72}, + {0x3b99, 73}, + {0x3b9a, 74}, + {0x3b9b, 75}, + {0x3b9c, 76}, + {0x3b9d, 77}, + {0x3b9e, 78}, + {0x3b9f, 79}, + {0x3ba0, 80}, + {0x3ba1, 81}, + {0x3ba2, 82}, + {0x3ba3, 83}, + {0x3ba4, 84}, + {0x3ba5, 85}, + {0x3ba6, 86}, + {0x3ba7, 87}, + {0x3ba8, 88}, + {0x3ba9, 89}, + {0x3baa, 90}, + {0x3bab, 91}, + {0x3bac, 92}, + {0x3bad, 93}, + {0x3bae, 94}, + {0x3baf, 95}, + {0x3bb0, 96}, + {0x3bb1, 97}, + {0x3bb2, 98}, + {0x3bb3, 99}, + {0x3bb4, 100}, + {0x3bb5, 101}, + {0x3bb6, 102}, + {0x3bb7, 103}, + {0x3bb8, 104}, + {0x3bb9, 105}, + {0x3bba, 106}, + {0x3bbb, 107}, + {0x3bbc, 108}, + {0x3bbd, 109}, + {0x3bbe, 110}, + {0x3bbf, 111}, + {0x3bc0, 112}, + {0x3bc1, 113}, + {0x3bc2, 114}, + {0x3bc3, 115}, + {0x3bc4, 116}, + {0x3bc5, 117}, + {0x3bc6, 118}, + {0x3bc7, 119}, + {0x3bc8, 120}, + {0x3bc9, 121}, + {0x3bca, 122}, + {0x3bcb, 123}, + {0x3bcc, 124}, + {0x3bcd, 125}, + {0x3bce, 126}, + {0x3bcf, 127}, + {0x3bd0, 128}, + {0x3bd1, 129}, + {0x3bd2, 130}, + {0x3bd3, 131}, + {0x3bd4, 132}, + {0x3bd5, 133}, + {0x3bd6, 134}, + {0x3bd7, 135}, + {0x3bd8, 136}, + {0x3bd9, 137}, + {0x3bda, 138}, + {0x3bdb, 139}, + {0x3bdc, 140}, + {0x3bdd, 141}, + {0x3bde, 142}, + {0x3bdf, 143}, + {0x3be0, 144}, + {0x3be1, 145}, + {0x3be2, 146}, + {0x3be3, 147}, + {0x3be4, 148}, + {0x3be5, 149}, + {0x3be6, 150}, + {0x3be7, 151}, + {0x3be8, 152}, + {0x3be9, 153}, + {0x3bea, 154}, + {0x3beb, 155}, + {0x3bec, 156}, + {0x3bed, 157}, + {0x3bee, 158}, + {0x3bef, 159}, + {0x3bf0, 160}, + {0x3bf1, 161}, + {0x3bf2, 162}, + {0x3bf3, 163}, + {0x3bf4, 164}, + {0x3bf5, 165}, + {0x3bf6, 166}, + {0x3bf7, 167}, + {0x3bf8, 168}, + {0x3bf9, 169}, + {0x3bfa, 170}, + {0x3bfb, 171}, + {0x3bfc, 172}, + {0x3bfd, 173}, + {0x3bfe, 174}, + {0x3bff, 175}, + {0x3c01, 0}, + {0x3c02, 1}, + {0x3c03, 2}, + {0x3c04, 3}, + {0x3c05, 4}, + {0x3c06, 5}, + {0x3c07, 6}, + {0x3c08, 7}, + {0x3c09, 8}, + {0x3c0a, 9}, + {0x3c0b, 10}, + {0x3c0c, 11}, + {0x3c0d, 12}, + {0x3c0e, 13}, + {0x3c0f, 14}, + {0x3c10, 15}, + {0x3c11, 16}, + {0x3c12, 17}, + {0x3c13, 18}, + {0x3c14, 19}, + {0x3c15, 20}, + {0x3c16, 21}, + {0x3c17, 22}, + {0x3c18, 23}, + {0x3c19, 24}, + {0x3c1a, 25}, + {0x3c1b, 26}, + {0x3c1c, 27}, + {0x3c1d, 28}, + {0x3c1e, 29}, + {0x3c1f, 30}, + {0x3c20, 31}, + {0x3c21, 32}, + {0x3c22, 33}, + {0x3c23, 34}, + {0x3c24, 35}, + {0x3c25, 36}, + {0x3c26, 37}, + {0x3c27, 38}, + {0x3c28, 39}, + {0x3c29, 40}, + {0x3c2a, 41}, + {0x3c2b, 42}, + {0x3c2c, 43}, + {0x3c2d, 44}, + {0x3c2e, 45}, + {0x3c2f, 46}, + {0x3c30, 47}, + {0x3c31, 48}, + {0x3c32, 49}, + {0x3c33, 50}, + {0x3c34, 51}, + {0x3c35, 52}, + {0x3c36, 53}, + {0x3c37, 54}, + {0x3c38, 55}, + {0x3c39, 56}, + {0x3c3a, 57}, + {0x3c3b, 58}, + {0x3c3c, 59}, + {0x3c3d, 60}, + {0x3c3e, 61}, + {0x3c3f, 62}, + {0x3c40, 63}, + {0x3c41, 64}, + {0x3c42, 65}, + {0x3c43, 66}, + {0x3c44, 67}, + {0x3c45, 68}, + {0x3c46, 69}, + {0x3c47, 70}, + {0x3c48, 71}, + {0x3c49, 72}, + {0x3c4a, 73}, + {0x3c4b, 74}, + {0x3c4c, 75}, + {0x3c4d, 76}, + {0x3c4e, 77}, + {0x3c4f, 78}, + {0x3c50, 79}, + {0x3c51, 80}, + {0x3c52, 81}, + {0x3c53, 82}, + {0x3c54, 83}, + {0x3c55, 84}, + {0x3c56, 85}, + {0x3c57, 86}, + {0x3c58, 87}, + {0x3c59, 88}, + {0x3c5a, 89}, + {0x3c5b, 90}, + {0x3c5c, 91}, + {0x3c5d, 92}, + {0x3c5e, 93}, + {0x3c5f, 94}, + {0x3c60, 95}, + {0x3c61, 96}, + {0x3c62, 97}, + {0x3c63, 98}, + {0x3c64, 99}, + {0x3c65, 100}, + {0x3c66, 101}, + {0x3c67, 102}, + {0x3c68, 103}, + {0x3c69, 104}, + {0x3c6a, 105}, + {0x3c6b, 106}, + {0x3c6c, 107}, + {0x3c6d, 108}, + {0x3c70, 0}, + {0x3c71, 1}, + {0x3c72, 2}, + {0x3c73, 3}, + {0x3c74, 4}, + {0x3c75, 5}, + {0x3c76, 6}, + {0x3c77, 7}, + {0x3c78, 8}, + {0x3c79, 9}, + {0x3c7a, 10}, + {0x3c7b, 11}, + {0x3c7c, 12}, + {0x3c7d, 13}, + {0x3c7e, 14}, + {0x3c7f, 15}, + {0x3c80, 16}, + {0x3c81, 17}, + {0x3c82, 18}, + {0x3c83, 19}, + {0x3c84, 20}, + {0x3c85, 21}, + {0x3c86, 22}, + {0x3c87, 23}, + {0x3c88, 24}, + {0x3c89, 25}, + {0x3c8a, 26}, + {0x3c8b, 27}, + {0x3c8c, 28}, + {0x3c8d, 29}, + {0x3c8e, 30}, + {0x3c8f, 31}, + {0x3c90, 32}, + {0x3c91, 33}, + {0x3c92, 34}, + {0x3c93, 35}, + {0x3c94, 36}, + {0x3c95, 37}, + {0x3c96, 38}, + {0x3c97, 39}, + {0x3c98, 40}, + {0x3c99, 41}, + {0x3c9a, 42}, + {0x3c9b, 43}, + {0x3c9c, 44}, + {0x3c9d, 45}, + {0x3c9e, 46}, + {0x3c9f, 47}, + {0x3ca0, 48}, + {0x3ca1, 49}, + {0x3ca2, 50}, + {0x3ca3, 51}, + {0x3ca4, 52}, + {0x3ca5, 53}, + {0x3ca6, 54}, + {0x3ca7, 55}, + {0x3ca8, 56}, + {0x3ca9, 57}, + {0x3caa, 58}, + {0x3cab, 59}, + {0x3cac, 60}, + {0x3cad, 61}, + {0x3cae, 62}, + {0x3caf, 63}, + {0x3cb0, 64}, + {0x3cb1, 65}, + {0x3cb2, 66}, + {0x3cb3, 67}, + {0x3cb4, 68}, + {0x3cb5, 69}, + {0x3cb6, 70}, + {0x3cb7, 71}, + {0x3cb8, 72}, + {0x3cb9, 73}, + {0x3cba, 74}, + {0x3cbb, 75}, + {0x3cbc, 76}, + {0x3cbd, 77}, + {0x3cbe, 78}, + {0x3cbf, 79}, + {0x3cc0, 80}, + {0x3cc1, 81}, + {0x3cc2, 82}, + {0x3cc3, 83}, + {0x3cc4, 84}, + {0x3cc5, 85}, + {0x3cc6, 86}, + {0x3cc7, 87}, + {0x3cc8, 88}, + {0x3cc9, 89}, + {0x3cca, 90}, + {0x3ccb, 91}, + {0x3ccc, 92}, + {0x3ccd, 93}, + {0x3cce, 94}, + {0x3ccf, 95}, + {0x3cd0, 96}, + {0x3cd1, 97}, + {0x3cd2, 98}, + {0x3cd3, 99}, + {0x3cd4, 100}, + {0x3cd5, 101}, + {0x3cd6, 102}, + {0x3cd7, 103}, + {0x3cd8, 104}, + {0x3cd9, 105}, + {0x3cda, 106}, + {0x3cdb, 107}, + {0x3cdc, 108}, + {0x3cdd, 109}, + {0x3cde, 110}, + {0x3cdf, 111}, + {0x3ce2, 0}, + {0x3ce3, 1}, + {0x3ce4, 2}, + {0x3ce5, 3}, + {0x3ce6, 4}, + {0x3ce7, 5}, + {0x3ce8, 6}, + {0x3ce9, 7}, + {0x3cea, 8}, + {0x3ceb, 9}, + {0x3cec, 10}, + {0x3ced, 11}, + {0x3cee, 12}, + {0x3cef, 13}, + {0x3cf0, 14}, + {0x3cf1, 15}, + {0x3cf2, 16}, + {0x3cf3, 17}, + {0x3cf4, 18}, + {0x3cf5, 19}, + {0x3cf6, 20}, + {0x3cf7, 21}, + {0x3cf8, 22}, + {0x3cf9, 23}, + {0x3cfa, 24}, + {0x3cfb, 25}, + {0x3cfc, 26}, + {0x3cfd, 27}, + {0x3cfe, 28}, + {0x3cff, 29}, + {0x3d01, 0}, + {0x3d02, 1}, + {0x3d03, 2}, + {0x3d04, 3}, + {0x3d05, 4}, + {0x3d06, 5}, + {0x3d07, 6}, + {0x3d08, 7}, + {0x3d09, 8}, + {0x3d0a, 9}, + {0x3d0b, 10}, + {0x3d0c, 11}, + {0x3d0d, 12}, + {0x3d0e, 13}, + {0x3d0f, 14}, + {0x3d10, 15}, + {0x3d11, 16}, + {0x3d12, 17}, + {0x3d13, 18}, + {0x3d14, 19}, + {0x3d15, 20}, + {0x3d16, 21}, + {0x3d17, 22}, + {0x3d18, 23}, + {0x3d19, 24}, + {0x3d1a, 25}, + {0x3d1b, 26}, + {0x3d1c, 27}, + {0x3d1d, 28}, + {0x3d1e, 29}, + {0x3d1f, 30}, + {0x3d20, 31}, + {0x3d21, 32}, + {0x3d22, 33}, + {0x3d23, 34}, + {0x3d24, 35}, + {0x3d25, 36}, + {0x3d26, 37}, + {0x3d27, 38}, + {0x3d28, 39}, + {0x3d29, 40}, + {0x3d2a, 41}, + {0x3d2b, 42}, + {0x3d2c, 43}, + {0x3d2d, 44}, + {0x3d2e, 45}, + {0x3d2f, 46}, + {0x3d30, 47}, + {0x3d31, 48}, + {0x3d32, 49}, + {0x3d33, 50}, + {0x3d34, 51}, + {0x3d35, 52}, + {0x3d36, 53}, + {0x3d37, 54}, + {0x3d38, 55}, + {0x3d39, 56}, + {0x3d3a, 57}, + {0x3d3b, 58}, + {0x3d3c, 59}, + {0x3d3d, 60}, + {0x3d3e, 61}, + {0x3d3f, 62}, + {0x3d40, 63}, + {0x3d41, 64}, + {0x3d42, 65}, + {0x3d43, 66}, + {0x3d44, 67}, + {0x3d45, 68}, + {0x3d46, 69}, + {0x3d47, 70}, + {0x3d48, 71}, + {0x3d49, 72}, + {0x3d4a, 73}, + {0x3d4b, 74}, + {0x3d4c, 75}, + {0x3d4d, 76}, + {0x3d4e, 77}, + {0x3d4f, 78}, + {0x3d50, 79}, + {0x3d51, 80}, + {0x3d52, 81}, + {0x3d53, 82}, + {0x3d54, 83}, + {0x3d55, 84}, + {0x3d56, 85}, + {0x3d57, 86}, + {0x3d58, 87}, + {0x3d59, 88}, + {0x3d5a, 89}, + {0x3d5b, 90}, + {0x3d5c, 91}, + {0x3d5d, 92}, + {0x3d5e, 93}, + {0x3d5f, 94}, + {0x3d60, 95}, + {0x3d61, 96}, + {0x3d62, 97}, + {0x3d63, 98}, + {0x3d64, 99}, + {0x3d65, 100}, + {0x3d66, 101}, + {0x3d67, 102}, + {0x3d68, 103}, + {0x3d69, 104}, + {0x3d6a, 105}, + {0x3d6b, 106}, + {0x3d6c, 107}, + {0x3d6d, 108}, + {0x3d6e, 109}, + {0x3d6f, 110}, + {0x3d70, 111}, + {0x3d71, 112}, + {0x3d72, 113}, + {0x3d73, 114}, + {0x3d74, 115}, + {0x3d75, 116}, + {0x3d76, 117}, + {0x3d77, 118}, + {0x3d78, 119}, + {0x3d79, 120}, + {0x3d7a, 121}, + {0x3d7b, 122}, + {0x3d7c, 123}, + {0x3d7d, 124}, + {0x3d7e, 125}, + {0x3d7f, 126}, + {0x3d80, 127}, + {0x3d81, 128}, + {0x3d82, 129}, + {0x3d83, 130}, + {0x3d84, 131}, + {0x3d85, 132}, + {0x3d86, 133}, + {0x3d87, 134}, + {0x3d88, 135}, + {0x3d89, 136}, + {0x3d8a, 137}, + {0x3d8b, 138}, + {0x3d8c, 139}, + {0x3d8d, 140}, + {0x3d8e, 141}, + {0x3d8f, 142}, + {0x3d90, 143}, + {0x3d91, 144}, + {0x3d92, 145}, + {0x3d93, 146}, + {0x3d94, 147}, + {0x3d95, 148}, + {0x3d96, 149}, + {0x3d97, 150}, + {0x3d98, 151}, + {0x3d99, 152}, + {0x3d9a, 153}, + {0x3d9b, 154}, + {0x3d9c, 155}, + {0x3d9d, 156}, + {0x3d9e, 157}, + {0x3d9f, 158}, + {0x3da0, 159}, + {0x3da1, 160}, + {0x3da2, 161}, + {0x3da3, 162}, + {0x3da4, 163}, + {0x3da5, 164}, + {0x3da6, 165}, + {0x3da7, 166}, + {0x3da8, 167}, + {0x3da9, 168}, + {0x3daa, 169}, + {0x3dab, 170}, + {0x3dac, 171}, + {0x3dad, 172}, + {0x3dae, 173}, + {0x3daf, 174}, + {0x3db0, 175}, + {0x3db1, 176}, + {0x3db2, 177}, + {0x3db3, 178}, + {0x3db4, 179}, + {0x3db5, 180}, + {0x3db6, 181}, + {0x3db7, 182}, + {0x3db8, 183}, + {0x3db9, 184}, + {0x3dba, 185}, + {0x3dbb, 186}, + {0x3dbc, 187}, + {0x3dbd, 188}, + {0x3dbe, 189}, + {0x3dbf, 190}, + {0x3dc0, 191}, + {0x3dc1, 192}, + {0x3dc2, 193}, + {0x3dc3, 194}, + {0x3dc4, 195}, + {0x3dc5, 196}, + {0x3dc6, 197}, + {0x3dc7, 198}, + {0x3dc8, 199}, + {0x3dc9, 200}, + {0x3dca, 201}, + {0x3dcb, 202}, + {0x3dcc, 203}, + {0x3dcd, 204}, + {0x3dce, 205}, + {0x3dcf, 206}, + {0x3dd0, 207}, + {0x3dd1, 208}, + {0x3dd2, 209}, + {0x3dd3, 210}, + {0x3dd4, 211}, + {0x3dd5, 212}, + {0x3dd6, 213}, + {0x3dd7, 214}, + {0x3dd8, 215}, + {0x3dd9, 216}, + {0x3dda, 217}, + {0x3ddb, 218}, + {0x3ddc, 219}, + {0x3ddd, 220}, + {0x3dde, 221}, + {0x3ddf, 222}, + {0x3de0, 223}, + {0x3de1, 224}, + {0x3de2, 225}, + {0x3de3, 226}, + {0x3de4, 227}, + {0x3de5, 228}, + {0x3de6, 229}, + {0x3de7, 230}, + {0x3de8, 231}, + {0x3de9, 232}, + {0x3dea, 233}, + {0x3deb, 234}, + {0x3dec, 235}, + {0x3ded, 236}, + {0x3dee, 237}, + {0x3def, 238}, + {0x3df0, 239}, + {0x3df1, 240}, + {0x3df2, 241}, + {0x3df3, 242}, + {0x3df4, 243}, + {0x3df5, 244}, + {0x3df6, 245}, + {0x3df7, 246}, + {0x3df8, 247}, + {0x3df9, 248}, + {0x3dfa, 249}, + {0x3dfb, 250}, + {0x3dfc, 251}, + {0x3dfd, 252}, + {0x3dfe, 253}, + {0x3dff, 254}, + {0x3e01, 0}, + {0x3e02, 1}, + {0x3e03, 2}, + {0x3e04, 3}, + {0x3e05, 4}, + {0x3e06, 5}, + {0x3e07, 6}, + {0x3e08, 7}, + {0x3e09, 8}, + {0x3e0a, 9}, + {0x3e0b, 10}, + {0x3e0c, 11}, + {0x3e0d, 12}, + {0x3e0e, 13}, + {0x3e0f, 14}, + {0x3e10, 15}, + {0x3e11, 16}, + {0x3e12, 17}, + {0x3e13, 18}, + {0x3e14, 19}, + {0x3e15, 20}, + {0x3e16, 21}, + {0x3e17, 22}, + {0x3e18, 23}, + {0x3e19, 24}, + {0x3e1a, 25}, + {0x3e1b, 26}, + {0x3e1c, 27}, + {0x3e1d, 28}, + {0x3e1e, 29}, + {0x3e1f, 30}, + {0x3e20, 31}, + {0x3e21, 32}, + {0x3e22, 33}, + {0x3e23, 34}, + {0x3e24, 35}, + {0x3e25, 36}, + {0x3e26, 37}, + {0x3e27, 38}, + {0x3e28, 39}, + {0x3e29, 40}, + {0x3e2a, 41}, + {0x3e2b, 42}, + {0x3e2c, 43}, + {0x3e2d, 44}, + {0x3e2e, 45}, + {0x3e2f, 46}, + {0x3e30, 47}, + {0x3e31, 48}, + {0x3e32, 49}, + {0x3e33, 50}, + {0x3e34, 51}, + {0x3e35, 52}, + {0x3e36, 53}, + {0x3e37, 54}, + {0x3e38, 55}, + {0x3e39, 56}, + {0x3e3a, 57}, + {0x3e3b, 58}, + {0x3e3c, 59}, + {0x3e3d, 60}, + {0x3e3e, 61}, + {0x3e3f, 62}, + {0x3e40, 63}, + {0x3e41, 64}, + {0x3e42, 65}, + {0x3e43, 66}, + {0x3e44, 67}, + {0x3e45, 68}, + {0x3e46, 69}, + {0x3e47, 70}, + {0x3e48, 71}, + {0x3e49, 72}, + {0x3e4a, 73}, + {0x3e4b, 74}, + {0x3e4c, 75}, + {0x3e4d, 76}, + {0x3e4e, 77}, + {0x3e4f, 78}, + {0x3e50, 79}, + {0x3e51, 80}, + {0x3e52, 81}, + {0x3e53, 82}, + {0x3e54, 83}, + {0x3e55, 84}, + {0x3e56, 85}, + {0x3e57, 86}, + {0x3e58, 87}, + {0x3e59, 88}, + {0x3e5a, 89}, + {0x3e5b, 90}, + {0x3e5c, 91}, + {0x3e5d, 92}, + {0x3e5e, 93}, + {0x3e5f, 94}, + {0x3e60, 95}, + {0x3e61, 96}, + {0x3e62, 97}, + {0x3e63, 98}, + {0x3e64, 99}, + {0x3e65, 100}, + {0x3e66, 101}, + {0x3e67, 102}, + {0x3e68, 103}, + {0x3e69, 104}, + {0x3e6a, 105}, + {0x3e6b, 106}, + {0x3e6c, 107}, + {0x3e6d, 108}, + {0x3e6e, 109}, + {0x3e6f, 110}, + {0x3e70, 111}, + {0x3e71, 112}, + {0x3e72, 113}, + {0x3e73, 114}, + {0x3e74, 115}, + {0x3e75, 116}, + {0x3e76, 117}, + {0x3e77, 118}, + {0x3e78, 119}, + {0x3e79, 120}, + {0x3e7a, 121}, + {0x3e7b, 122}, + {0x3e7c, 123}, + {0x3e7d, 124}, + {0x3e7e, 125}, + {0x3e7f, 126}, + {0x3e80, 127}, + {0x3e81, 128}, + {0x3e82, 129}, + {0x3e83, 130}, + {0x3e84, 131}, + {0x3e85, 132}, + {0x3e86, 133}, + {0x3e87, 134}, + {0x3e88, 135}, + {0x3e89, 136}, + {0x3e8a, 137}, + {0x3e8b, 138}, + {0x3e8c, 139}, + {0x3e8d, 140}, + {0x3e8e, 141}, + {0x3e8f, 142}, + {0x3e90, 143}, + {0x3e91, 144}, + {0x3e92, 145}, + {0x3e93, 146}, + {0x3e94, 147}, + {0x3e95, 148}, + {0x3e96, 149}, + {0x3e97, 150}, + {0x3e98, 151}, + {0x3e99, 152}, + {0x3e9a, 153}, + {0x3e9b, 154}, + {0x3e9c, 155}, + {0x3e9d, 156}, + {0x3e9e, 157}, + {0x3e9f, 158}, + {0x3ea0, 159}, + {0x3ea1, 160}, + {0x3ea2, 161}, + {0x3ea3, 162}, + {0x3ea4, 163}, + {0x3ea5, 164}, + {0x3ea6, 165}, + {0x3ea7, 166}, + {0x3ea8, 167}, + {0x3ea9, 168}, + {0x3eaa, 169}, + {0x3eab, 170}, + {0x3eac, 171}, + {0x3ead, 172}, + {0x3eae, 173}, + {0x3eaf, 174}, + {0x3eb0, 175}, + {0x3eb1, 176}, + {0x3eb2, 177}, + {0x3eb3, 178}, + {0x3eb4, 179}, + {0x3eb5, 180}, + {0x3eb6, 181}, + {0x3eb7, 182}, + {0x3eb8, 183}, + {0x3eb9, 184}, + {0x3eba, 185}, + {0x3ebb, 186}, + {0x3ebc, 187}, + {0x3ebd, 188}, + {0x3ebe, 189}, + {0x3ebf, 190}, + {0x3ec0, 191}, + {0x3ec1, 192}, + {0x3ec2, 193}, + {0x3ec3, 194}, + {0x3ec4, 195}, + {0x3ec5, 196}, + {0x3ec6, 197}, + {0x3ec7, 198}, + {0x3ec8, 199}, + {0x3ec9, 200}, + {0x3eca, 201}, + {0x3ecb, 202}, + {0x3ecc, 203}, + {0x3ecd, 204}, + {0x3ece, 205}, + {0x3ecf, 206}, + {0x3ed0, 207}, + {0x3ed1, 208}, + {0x3ed2, 209}, + {0x3ed3, 210}, + {0x3ed4, 211}, + {0x3ed5, 212}, + {0x3ed6, 213}, + {0x3ed7, 214}, + {0x3ed8, 215}, + {0x3ed9, 216}, + {0x3eda, 217}, + {0x3edb, 218}, + {0x3edc, 219}, + {0x3edd, 220}, + {0x3ede, 221}, + {0x3edf, 222}, + {0x3ee0, 223}, + {0x3ee1, 224}, + {0x3ee2, 225}, + {0x3ee3, 226}, + {0x3ee4, 227}, + {0x3ee5, 228}, + {0x3ee6, 229}, + {0x3ee7, 230}, + {0x3ee8, 231}, + {0x3ee9, 232}, + {0x3eea, 233}, + {0x3eeb, 234}, + {0x3eec, 235}, + {0x3eed, 236}, + {0x3eee, 237}, + {0x3eef, 238}, + {0x3ef0, 239}, + {0x3ef1, 240}, + {0x3ef2, 241}, + {0x3ef3, 242}, + {0x3ef4, 243}, + {0x3ef5, 244}, + {0x3ef6, 245}, + {0x3ef7, 246}, + {0x3ef8, 247}, + {0x3ef9, 248}, + {0x3efa, 249}, + {0x3efb, 250}, + {0x3efc, 251}, + {0x3efd, 252}, + {0x3efe, 253}, + {0x3eff, 254}, + {0x3f01, 0}, + {0x3f02, 1}, + {0x3f03, 2}, + {0x3f04, 3}, + {0x3f05, 4}, + {0x3f06, 5}, + {0x3f07, 6}, + {0x3f08, 7}, + {0x3f09, 8}, + {0x3f0a, 9}, + {0x3f0b, 10}, + {0x3f0c, 11}, + {0x3f0d, 12}, + {0x3f0e, 13}, + {0x3f0f, 14}, + {0x3f10, 15}, + {0x3f11, 16}, + {0x3f12, 17}, + {0x3f13, 18}, + {0x3f14, 19}, + {0x3f15, 20}, + {0x3f16, 21}, + {0x3f17, 22}, + {0x3f18, 23}, + {0x3f19, 24}, + {0x3f1a, 25}, + {0x3f1b, 26}, + {0x3f1c, 27}, + {0x3f1d, 28}, + {0x3f1e, 29}, + {0x3f1f, 30}, + {0x3f20, 31}, + {0x3f21, 32}, + {0x3f22, 33}, + {0x3f23, 34}, + {0x3f24, 35}, + {0x3f25, 36}, + {0x3f26, 37}, + {0x3f27, 38}, + {0x3f28, 39}, + {0x3f29, 40}, + {0x3f2a, 41}, + {0x3f2b, 42}, + {0x3f2c, 43}, + {0x3f2d, 44}, + {0x3f2e, 45}, + {0x3f2f, 46}, + {0x3f30, 47}, + {0x3f31, 48}, + {0x3f32, 49}, + {0x3f33, 50}, + {0x3f34, 51}, + {0x3f35, 52}, + {0x3f36, 53}, + {0x3f37, 54}, + {0x3f38, 55}, + {0x3f39, 56}, + {0x3f3a, 57}, + {0x3f3b, 58}, + {0x3f3c, 59}, + {0x3f3d, 60}, + {0x3f3e, 61}, + {0x3f3f, 62}, + {0x3f40, 63}, + {0x3f41, 64}, + {0x3f42, 65}, + {0x3f43, 66}, + {0x3f44, 67}, + {0x3f45, 68}, + {0x3f46, 69}, + {0x3f47, 70}, + {0x3f48, 71}, + {0x3f49, 72}, + {0x3f4a, 73}, + {0x3f4b, 74}, + {0x3f4c, 75}, + {0x3f4d, 76}, + {0x3f4e, 77}, + {0x3f4f, 78}, + {0x3f50, 79}, + {0x3f51, 80}, + {0x3f52, 81}, + {0x3f53, 82}, + {0x3f54, 83}, + {0x3f55, 84}, + {0x3f56, 85}, + {0x3f57, 86}, + {0x3f58, 87}, + {0x3f59, 88}, + {0x3f5a, 89}, + {0x3f5b, 90}, + {0x3f5c, 91}, + {0x3f5d, 92}, + {0x3f5e, 93}, + {0x3f5f, 94}, + {0x3f60, 95}, + {0x3f61, 96}, + {0x3f62, 97}, + {0x3f63, 98}, + {0x3f64, 99}, + {0x3f65, 100}, + {0x3f66, 101}, + {0x3f67, 102}, + {0x3f68, 103}, + {0x3f69, 104}, + {0x3f6a, 105}, + {0x3f6b, 106}, + {0x3f6c, 107}, + {0x3f6d, 108}, + {0x3f6e, 109}, + {0x3f6f, 110}, + {0x3f70, 111}, + {0x3f71, 112}, + {0x3f72, 113}, + {0x3f73, 114}, + {0x3f74, 115}, + {0x3f75, 116}, + {0x3f76, 117}, + {0x3f77, 118}, + {0x3f78, 119}, + {0x3f79, 120}, + {0x3f7a, 121}, + {0x3f7b, 122}, + {0x3f7c, 123}, + {0x3f7d, 124}, + {0x3f7e, 125}, + {0x3f7f, 126}, + {0x3f80, 127}, + {0x3f81, 128}, + {0x3f82, 129}, + {0x3f83, 130}, + {0x3f84, 131}, + {0x3f85, 132}, + {0x3f86, 133}, + {0x3f87, 134}, + {0x3f88, 135}, + {0x3f89, 136}, + {0x3f8a, 137}, + {0x3f8b, 138}, + {0x3f8c, 139}, + {0x3f8d, 140}, + {0x3f8e, 141}, + {0x3f8f, 142}, + {0x3f90, 143}, + {0x3f91, 144}, + {0x3f92, 145}, + {0x3f93, 146}, + {0x3f94, 147}, + {0x3f95, 148}, + {0x3f96, 149}, + {0x3f97, 150}, + {0x3f98, 151}, + {0x3f99, 152}, + {0x3f9a, 153}, + {0x3f9b, 154}, + {0x3f9c, 155}, + {0x3f9d, 156}, + {0x3f9e, 157}, + {0x3f9f, 158}, + {0x3fa0, 159}, + {0x3fa1, 160}, + {0x3fa2, 161}, + {0x3fa3, 162}, + {0x3fa4, 163}, + {0x3fa5, 164}, + {0x3fa6, 165}, + {0x3fa7, 166}, + {0x3fa8, 167}, + {0x3fa9, 168}, + {0x3faa, 169}, + {0x3fab, 170}, + {0x3fac, 171}, + {0x3fad, 172}, + {0x3fae, 173}, + {0x3faf, 174}, + {0x3fb0, 175}, + {0x3fb1, 176}, + {0x3fb2, 177}, + {0x3fb3, 178}, + {0x3fb4, 179}, + {0x3fb5, 180}, + {0x3fb6, 181}, + {0x3fb7, 182}, + {0x3fb8, 183}, + {0x3fb9, 184}, + {0x3fba, 185}, + {0x3fbb, 186}, + {0x3fbc, 187}, + {0x3fbd, 188}, + {0x3fbe, 189}, + {0x3fbf, 190}, + {0x3fc0, 191}, + {0x3fc1, 192}, + {0x3fc2, 193}, + {0x3fc3, 194}, + {0x3fc4, 195}, + {0x3fc5, 196}, + {0x3fc6, 197}, + {0x3fc7, 198}, + {0x3fc8, 199}, + {0x3fc9, 200}, + {0x3fca, 201}, + {0x3fcb, 202}, + {0x3fcc, 203}, + {0x3fcd, 204}, + {0x3fce, 205}, + {0x3fcf, 206}, + {0x3fd0, 207}, + {0x3fd1, 208}, + {0x3fd2, 209}, + {0x3fd3, 210}, + {0x3fd4, 211}, + {0x3fd5, 212}, + {0x3fd6, 213}, + {0x3fd7, 214}, + {0x3fd8, 215}, + {0x3fd9, 216}, + {0x3fda, 217}, + {0x3fdb, 218}, + {0x3fdc, 219}, + {0x3fdd, 220}, + {0x3fde, 221}, + {0x3fdf, 222}, + {0x3fe0, 223}, + {0x3fe1, 224}, + {0x3fe2, 225}, + {0x3fe3, 226}, + {0x3fe4, 227}, + {0x3fe5, 228}, + {0x3fe6, 229}, + {0x3fe7, 230}, + {0x3fe8, 231}, + {0x3fe9, 232}, + {0x3fea, 233}, + {0x3feb, 234}, + {0x3fec, 235}, + {0x3fed, 236}, + {0x3fee, 237}, + {0x3fef, 238}, + {0x3ff0, 239}, + {0x3ff1, 240}, + {0x3ff2, 241}, + {0x3ff3, 242}, + {0x3ff4, 243}, + {0x3ff5, 244}, + {0x3ff6, 245}, + {0x3ff7, 246}, + {0x3ff8, 247}, + {0x3ff9, 248}, + {0x3ffa, 249}, + {0x3ffb, 250}, + {0x3ffc, 251}, + {0x3ffd, 252}, + {0x3ffe, 253}, + {0x3fff, 254}, + {0x4001, 0}, + {0x4002, 1}, + {0x4003, 2}, + {0x4004, 3}, + {0x4005, 4}, + {0x4006, 5}, + {0x4007, 6}, + {0x4008, 7}, + {0x4009, 8}, + {0x400a, 9}, + {0x400b, 10}, + {0x400c, 11}, + {0x400d, 12}, + {0x400e, 13}, + {0x400f, 14}, + {0x4010, 15}, + {0x4011, 16}, + {0x4012, 17}, + {0x4013, 18}, + {0x4014, 19}, + {0x4015, 20}, + {0x4016, 21}, + {0x4017, 22}, + {0x4018, 23}, + {0x4019, 24}, + {0x401a, 25}, + {0x401b, 26}, + {0x401c, 27}, + {0x401d, 28}, + {0x401e, 29}, + {0x401f, 30}, + {0x4020, 31}, + {0x4021, 32}, + {0x4022, 33}, + {0x4023, 34}, + {0x4024, 35}, + {0x4025, 36}, + {0x4026, 37}, + {0x4027, 38}, + {0x4028, 39}, + {0x4029, 40}, + {0x402a, 41}, + {0x402b, 42}, + {0x402c, 43}, + {0x402d, 44}, + {0x402e, 45}, + {0x402f, 46}, + {0x4030, 47}, + {0x4031, 48}, + {0x4032, 49}, + {0x4033, 50}, + {0x4034, 51}, + {0x4035, 52}, + {0x4036, 53}, + {0x4037, 54}, + {0x4038, 55}, + {0x4039, 56}, + {0x403a, 57}, + {0x403b, 58}, + {0x403c, 59}, + {0x403d, 60}, + {0x403e, 61}, + {0x403f, 62}, + {0x4040, 63}, + {0x4041, 64}, + {0x4042, 65}, + {0x4043, 66}, + {0x4044, 67}, + {0x4045, 68}, + {0x4046, 69}, + {0x4047, 70}, + {0x4048, 71}, + {0x4049, 72}, + {0x404a, 73}, + {0x404b, 74}, + {0x404c, 75}, + {0x404d, 76}, + {0x404e, 77}, + {0x404f, 78}, + {0x4050, 79}, + {0x4051, 80}, + {0x4052, 81}, + {0x4053, 82}, + {0x4054, 83}, + {0x4055, 84}, + {0x4058, 0}, + {0x4059, 1}, + {0x405a, 2}, + {0x405b, 3}, + {0x405c, 4}, + {0x405d, 5}, + {0x405e, 6}, + {0x405f, 7}, + {0x4060, 8}, + {0x4061, 9}, + {0x4062, 10}, + {0x4063, 11}, + {0x4064, 12}, + {0x4065, 13}, + {0x4066, 14}, + {0x4067, 15}, + {0x4068, 16}, + {0x4069, 17}, + {0x406a, 18}, + {0x406b, 19}, + {0x406c, 20}, + {0x406d, 21}, + {0x406e, 22}, + {0x406f, 23}, + {0x4070, 24}, + {0x4071, 25}, + {0x4072, 26}, + {0x4073, 27}, + {0x4074, 28}, + {0x4075, 29}, + {0x4076, 30}, + {0x4077, 31}, + {0x4078, 32}, + {0x4079, 33}, + {0x407a, 34}, + {0x407b, 35}, + {0x407c, 36}, + {0x407d, 37}, + {0x407e, 38}, + {0x407f, 39}, + {0x4080, 40}, + {0x4081, 41}, + {0x4082, 42}, + {0x4083, 43}, + {0x4084, 44}, + {0x4085, 45}, + {0x4086, 46}, + {0x4087, 47}, + {0x4088, 48}, + {0x4089, 49}, + {0x408a, 50}, + {0x408b, 51}, + {0x408c, 52}, + {0x408d, 53}, + {0x408e, 54}, + {0x408f, 55}, + {0x4090, 56}, + {0x4091, 57}, + {0x4092, 58}, + {0x4093, 59}, + {0x4094, 60}, + {0x4095, 61}, + {0x4096, 62}, + {0x4097, 63}, + {0x4098, 64}, + {0x4099, 65}, + {0x409a, 66}, + {0x409b, 67}, + {0x409c, 68}, + {0x409d, 69}, + {0x409e, 70}, + {0x409f, 71}, + {0x40a0, 72}, + {0x40a1, 73}, + {0x40a2, 74}, + {0x40a3, 75}, + {0x40a4, 76}, + {0x40a5, 77}, + {0x40a6, 78}, + {0x40a7, 79}, + {0x40a8, 80}, + {0x40a9, 81}, + {0x40aa, 82}, + {0x40ab, 83}, + {0x40ac, 84}, + {0x40ad, 85}, + {0x40ae, 86}, + {0x40af, 87}, + {0x40b0, 88}, + {0x40b1, 89}, + {0x40b2, 90}, + {0x40b3, 91}, + {0x40b4, 92}, + {0x40b5, 93}, + {0x40b6, 94}, + {0x40b7, 95}, + {0x40b8, 96}, + {0x40b9, 97}, + {0x40ba, 98}, + {0x40bb, 99}, + {0x40bc, 100}, + {0x40bd, 101}, + {0x40be, 102}, + {0x40bf, 103}, + {0x40c0, 104}, + {0x40c1, 105}, + {0x40c2, 106}, + {0x40c3, 107}, + {0x40c4, 108}, + {0x40c5, 109}, + {0x40c6, 110}, + {0x40c7, 111}, + {0x40c8, 112}, + {0x40c9, 113}, + {0x40ca, 114}, + {0x40cb, 115}, + {0x40cc, 116}, + {0x40cd, 117}, + {0x40ce, 118}, + {0x40cf, 119}, + {0x40d0, 120}, + {0x40d1, 121}, + {0x40d2, 122}, + {0x40d3, 123}, + {0x40d4, 124}, + {0x40d5, 125}, + {0x40d6, 126}, + {0x40d7, 127}, + {0x40d8, 128}, + {0x40d9, 129}, + {0x40da, 130}, + {0x40db, 131}, + {0x40dc, 132}, + {0x40dd, 133}, + {0x40de, 134}, + {0x40df, 135}, + {0x40e0, 136}, + {0x40e1, 137}, + {0x40e2, 138}, + {0x40e3, 139}, + {0x40e4, 140}, + {0x40e5, 141}, + {0x40e6, 142}, + {0x40e7, 143}, + {0x40e8, 144}, + {0x40e9, 145}, + {0x40ea, 146}, + {0x40eb, 147}, + {0x40ec, 148}, + {0x40ed, 149}, + {0x40ee, 150}, + {0x40ef, 151}, + {0x40f0, 152}, + {0x40f1, 153}, + {0x40f2, 154}, + {0x40f3, 155}, + {0x40f4, 156}, + {0x40f5, 157}, + {0x40f6, 158}, + {0x40f7, 159}, + {0x40f8, 160}, + {0x40f9, 161}, + {0x40fa, 162}, + {0x40fb, 163}, + {0x40fc, 164}, + {0x40fd, 165}, + {0x40fe, 166}, + {0x40ff, 167}, + {0x4101, 0}, + {0x4102, 1}, + {0x4103, 2}, + {0x4104, 3}, + {0x4105, 4}, + {0x4106, 5}, + {0x4107, 6}, + {0x4108, 7}, + {0x4109, 8}, + {0x410a, 9}, + {0x410b, 10}, + {0x410c, 11}, + {0x410d, 12}, + {0x410e, 13}, + {0x410f, 14}, + {0x4110, 15}, + {0x4111, 16}, + {0x4112, 17}, + {0x4113, 18}, + {0x4114, 19}, + {0x4115, 20}, + {0x4116, 21}, + {0x4117, 22}, + {0x4118, 23}, + {0x4119, 24}, + {0x411a, 25}, + {0x411b, 26}, + {0x411c, 27}, + {0x411d, 28}, + {0x411e, 29}, + {0x411f, 30}, + {0x4120, 31}, + {0x4121, 32}, + {0x4122, 33}, + {0x4123, 34}, + {0x4124, 35}, + {0x4125, 36}, + {0x4126, 37}, + {0x4127, 38}, + {0x4128, 39}, + {0x4129, 40}, + {0x412a, 41}, + {0x412b, 42}, + {0x412c, 43}, + {0x412d, 44}, + {0x412e, 45}, + {0x412f, 46}, + {0x4130, 47}, + {0x4131, 48}, + {0x4132, 49}, + {0x4133, 50}, + {0x4134, 51}, + {0x4135, 52}, + {0x4136, 53}, + {0x4137, 54}, + {0x4138, 55}, + {0x4139, 56}, + {0x413a, 57}, + {0x413b, 58}, + {0x413c, 59}, + {0x413d, 60}, + {0x413e, 61}, + {0x413f, 62}, + {0x4140, 63}, + {0x4141, 64}, + {0x4142, 65}, + {0x4143, 66}, + {0x4144, 67}, + {0x4145, 68}, + {0x4146, 69}, + {0x4147, 70}, + {0x4148, 71}, + {0x4149, 72}, + {0x414a, 73}, + {0x414b, 74}, + {0x414c, 75}, + {0x414d, 76}, + {0x414e, 77}, + {0x414f, 78}, + {0x4150, 79}, + {0x4151, 80}, + {0x4152, 81}, + {0x4153, 82}, + {0x4154, 83}, + {0x4155, 84}, + {0x4156, 85}, + {0x4157, 86}, + {0x4158, 87}, + {0x4159, 88}, + {0x415a, 89}, + {0x415b, 90}, + {0x415c, 91}, + {0x415d, 92}, + {0x415e, 93}, + {0x4161, 0}, + {0x4162, 1}, + {0x4163, 2}, + {0x4164, 3}, + {0x4165, 4}, + {0x4166, 5}, + {0x4167, 6}, + {0x4168, 7}, + {0x4169, 8}, + {0x416a, 9}, + {0x416b, 10}, + {0x416c, 11}, + {0x416d, 12}, + {0x416e, 13}, + {0x416f, 14}, + {0x4170, 15}, + {0x4171, 16}, + {0x4172, 17}, + {0x4173, 18}, + {0x4174, 19}, + {0x4175, 20}, + {0x4176, 21}, + {0x4177, 22}, + {0x4178, 23}, + {0x4179, 24}, + {0x417a, 25}, + {0x417b, 26}, + {0x417c, 27}, + {0x417d, 28}, + {0x417e, 29}, + {0x417f, 30}, + {0x4180, 31}, + {0x4181, 32}, + {0x4182, 33}, + {0x4183, 34}, + {0x4184, 35}, + {0x4185, 36}, + {0x4186, 37}, + {0x4187, 38}, + {0x4188, 39}, + {0x4189, 40}, + {0x418a, 41}, + {0x418b, 42}, + {0x418c, 43}, + {0x418d, 44}, + {0x418e, 45}, + {0x418f, 46}, + {0x4190, 47}, + {0x4191, 48}, + {0x4192, 49}, + {0x4193, 50}, + {0x4194, 51}, + {0x4195, 52}, + {0x4196, 53}, + {0x4197, 54}, + {0x4198, 55}, + {0x4199, 56}, + {0x419a, 57}, + {0x419b, 58}, + {0x419c, 59}, + {0x419d, 60}, + {0x419e, 61}, + {0x419f, 62}, + {0x41a0, 63}, + {0x41a1, 64}, + {0x41a2, 65}, + {0x41a3, 66}, + {0x41a4, 67}, + {0x41a5, 68}, + {0x41a6, 69}, + {0x41a7, 70}, + {0x41a8, 71}, + {0x41a9, 72}, + {0x41aa, 73}, + {0x41ab, 74}, + {0x41ac, 75}, + {0x41ad, 76}, + {0x41ae, 77}, + {0x41af, 78}, + {0x41b0, 79}, + {0x41b1, 80}, + {0x41b2, 81}, + {0x41b3, 82}, + {0x41b4, 83}, + {0x41b5, 84}, + {0x41b6, 85}, + {0x41b7, 86}, + {0x41b8, 87}, + {0x41b9, 88}, + {0x41ba, 89}, + {0x41bb, 90}, + {0x41bc, 91}, + {0x41bd, 92}, + {0x41be, 93}, + {0x41bf, 94}, + {0x41c0, 95}, + {0x41c1, 96}, + {0x41c2, 97}, + {0x41c3, 98}, + {0x41c4, 99}, + {0x41c5, 100}, + {0x41c6, 101}, + {0x41c7, 102}, + {0x41c8, 103}, + {0x41c9, 104}, + {0x41ca, 105}, + {0x41cb, 106}, + {0x41cc, 107}, + {0x41cd, 108}, + {0x41ce, 109}, + {0x41cf, 110}, + {0x41d0, 111}, + {0x41d1, 112}, + {0x41d2, 113}, + {0x41d3, 114}, + {0x41d4, 115}, + {0x41d5, 116}, + {0x41d6, 117}, + {0x41d7, 118}, + {0x41d8, 119}, + {0x41d9, 120}, + {0x41da, 121}, + {0x41db, 122}, + {0x41dc, 123}, + {0x41dd, 124}, + {0x41de, 125}, + {0x41df, 126}, + {0x41e0, 127}, + {0x41e1, 128}, + {0x41e2, 129}, + {0x41e3, 130}, + {0x41e4, 131}, + {0x41e5, 132}, + {0x41e6, 133}, + {0x41e7, 134}, + {0x41e8, 135}, + {0x41e9, 136}, + {0x41ea, 137}, + {0x41eb, 138}, + {0x41ec, 139}, + {0x41ed, 140}, + {0x41ee, 141}, + {0x41ef, 142}, + {0x41f0, 143}, + {0x41f1, 144}, + {0x41f2, 145}, + {0x41f3, 146}, + {0x41f4, 147}, + {0x41f5, 148}, + {0x41f6, 149}, + {0x41f7, 150}, + {0x41f8, 151}, + {0x41f9, 152}, + {0x41fa, 153}, + {0x41fb, 154}, + {0x41fc, 155}, + {0x41fd, 156}, + {0x41fe, 157}, + {0x41ff, 158}, + {0x4201, 0}, + {0x4202, 1}, + {0x4203, 2}, + {0x4204, 3}, + {0x4205, 4}, + {0x4206, 5}, + {0x4207, 6}, + {0x4208, 7}, + {0x4209, 8}, + {0x420a, 9}, + {0x420b, 10}, + {0x420c, 11}, + {0x420d, 12}, + {0x420e, 13}, + {0x420f, 14}, + {0x4210, 15}, + {0x4211, 16}, + {0x4212, 17}, + {0x4213, 18}, + {0x4214, 19}, + {0x4215, 20}, + {0x4216, 21}, + {0x4217, 22}, + {0x4218, 23}, + {0x4219, 24}, + {0x421a, 25}, + {0x421b, 26}, + {0x421c, 27}, + {0x421d, 28}, + {0x421e, 29}, + {0x421f, 30}, + {0x4220, 31}, + {0x4221, 32}, + {0x4222, 33}, + {0x4223, 34}, + {0x4224, 35}, + {0x4225, 36}, + {0x4226, 37}, + {0x4227, 38}, + {0x4228, 39}, + {0x4229, 40}, + {0x422a, 41}, + {0x422b, 42}, + {0x422c, 43}, + {0x422d, 44}, + {0x422e, 45}, + {0x422f, 46}, + {0x4230, 47}, + {0x4231, 48}, + {0x4232, 49}, + {0x4233, 50}, + {0x4234, 51}, + {0x4235, 52}, + {0x4236, 53}, + {0x4237, 54}, + {0x4238, 55}, + {0x4239, 56}, + {0x423a, 57}, + {0x423b, 58}, + {0x423c, 59}, + {0x423d, 60}, + {0x423e, 61}, + {0x423f, 62}, + {0x4240, 63}, + {0x4241, 64}, + {0x4242, 65}, + {0x4243, 66}, + {0x4244, 67}, + {0x4245, 68}, + {0x4246, 69}, + {0x4247, 70}, + {0x4248, 71}, + {0x4249, 72}, + {0x424a, 73}, + {0x424b, 74}, + {0x424c, 75}, + {0x424d, 76}, + {0x424e, 77}, + {0x424f, 78}, + {0x4250, 79}, + {0x4251, 80}, + {0x4252, 81}, + {0x4253, 82}, + {0x4254, 83}, + {0x4255, 84}, + {0x4256, 85}, + {0x4257, 86}, + {0x4258, 87}, + {0x4259, 88}, + {0x425a, 89}, + {0x425b, 90}, + {0x425c, 91}, + {0x425d, 92}, + {0x425e, 93}, + {0x425f, 94}, + {0x4260, 95}, + {0x4261, 96}, + {0x4262, 97}, + {0x4263, 98}, + {0x4264, 99}, + {0x4265, 100}, + {0x4266, 101}, + {0x4267, 102}, + {0x4268, 103}, + {0x4269, 104}, + {0x426a, 105}, + {0x426b, 106}, + {0x426c, 107}, + {0x426d, 108}, + {0x426e, 109}, + {0x426f, 110}, + {0x4270, 111}, + {0x4271, 112}, + {0x4272, 113}, + {0x4273, 114}, + {0x4274, 115}, + {0x4275, 116}, + {0x4276, 117}, + {0x4277, 118}, + {0x4278, 119}, + {0x4279, 120}, + {0x427a, 121}, + {0x427b, 122}, + {0x427c, 123}, + {0x427d, 124}, + {0x427e, 125}, + {0x427f, 126}, + {0x4280, 127}, + {0x4281, 128}, + {0x4282, 129}, + {0x4283, 130}, + {0x4284, 131}, + {0x4285, 132}, + {0x4286, 133}, + {0x4287, 134}, + {0x4288, 135}, + {0x4289, 136}, + {0x428a, 137}, + {0x428b, 138}, + {0x428c, 139}, + {0x428d, 140}, + {0x428e, 141}, + {0x428f, 142}, + {0x4290, 143}, + {0x4291, 144}, + {0x4292, 145}, + {0x4293, 146}, + {0x4294, 147}, + {0x4295, 148}, + {0x4296, 149}, + {0x4297, 150}, + {0x4298, 151}, + {0x4299, 152}, + {0x429a, 153}, + {0x429b, 154}, + {0x429c, 155}, + {0x429d, 156}, + {0x429e, 157}, + {0x429f, 158}, + {0x42a0, 159}, + {0x42a1, 160}, + {0x42a2, 161}, + {0x42a3, 162}, + {0x42a4, 163}, + {0x42a5, 164}, + {0x42a6, 165}, + {0x42a7, 166}, + {0x42a8, 167}, + {0x42a9, 168}, + {0x42aa, 169}, + {0x42ab, 170}, + {0x42ac, 171}, + {0x42ad, 172}, + {0x42ae, 173}, + {0x42af, 174}, + {0x42b0, 175}, + {0x42b1, 176}, + {0x42b2, 177}, + {0x42b3, 178}, + {0x42b4, 179}, + {0x42b5, 180}, + {0x42b6, 181}, + {0x42b7, 182}, + {0x42b8, 183}, + {0x42b9, 184}, + {0x42ba, 185}, + {0x42bb, 186}, + {0x42bc, 187}, + {0x42bd, 188}, + {0x42be, 189}, + {0x42bf, 190}, + {0x42c0, 191}, + {0x42c1, 192}, + {0x42c2, 193}, + {0x42c3, 194}, + {0x42c4, 195}, + {0x42c5, 196}, + {0x42c6, 197}, + {0x42c7, 198}, + {0x42c8, 199}, + {0x42c9, 200}, + {0x42ca, 201}, + {0x42cb, 202}, + {0x42cc, 203}, + {0x42cd, 204}, + {0x42ce, 205}, + {0x42cf, 206}, + {0x42d0, 207}, + {0x42d1, 208}, + {0x42d2, 209}, + {0x42d3, 210}, + {0x42d4, 211}, + {0x42d5, 212}, + {0x42d6, 213}, + {0x42d7, 214}, + {0x42d8, 215}, + {0x42d9, 216}, + {0x42da, 217}, + {0x42db, 218}, + {0x42dc, 219}, + {0x42dd, 220}, + {0x42de, 221}, + {0x42df, 222}, + {0x42e0, 223}, + {0x42e1, 224}, + {0x42e2, 225}, + {0x42e3, 226}, + {0x42e4, 227}, + {0x42e5, 228}, + {0x42e6, 229}, + {0x42e7, 230}, + {0x42e8, 231}, + {0x42e9, 232}, + {0x42ea, 233}, + {0x42eb, 234}, + {0x42ec, 235}, + {0x42ed, 236}, + {0x42ee, 237}, + {0x42ef, 238}, + {0x42f0, 239}, + {0x42f1, 240}, + {0x42f2, 241}, + {0x42f3, 242}, + {0x42f4, 243}, + {0x42f5, 244}, + {0x42f6, 245}, + {0x42f7, 246}, + {0x42f8, 247}, + {0x42f9, 248}, + {0x42fa, 249}, + {0x42fb, 250}, + {0x42fc, 251}, + {0x42fd, 252}, + {0x42fe, 253}, + {0x42ff, 254}, + {0x4301, 0}, + {0x4302, 1}, + {0x4303, 2}, + {0x4304, 3}, + {0x4305, 4}, + {0x4306, 5}, + {0x4307, 6}, + {0x4308, 7}, + {0x4309, 8}, + {0x430a, 9}, + {0x430b, 10}, + {0x430c, 11}, + {0x430d, 12}, + {0x430e, 13}, + {0x430f, 14}, + {0x4310, 15}, + {0x4311, 16}, + {0x4312, 17}, + {0x4313, 18}, + {0x4314, 19}, + {0x4315, 20}, + {0x4316, 21}, + {0x4317, 22}, + {0x4318, 23}, + {0x4319, 24}, + {0x431a, 25}, + {0x431b, 26}, + {0x431c, 27}, + {0x431d, 28}, + {0x431e, 29}, + {0x431f, 30}, + {0x4320, 31}, + {0x4321, 32}, + {0x4322, 33}, + {0x4323, 34}, + {0x4324, 35}, + {0x4325, 36}, + {0x4326, 37}, + {0x4327, 38}, + {0x4328, 39}, + {0x4329, 40}, + {0x432a, 41}, + {0x432b, 42}, + {0x432c, 43}, + {0x432d, 44}, + {0x432e, 45}, + {0x432f, 46}, + {0x4330, 47}, + {0x4331, 48}, + {0x4332, 49}, + {0x4333, 50}, + {0x4334, 51}, + {0x4335, 52}, + {0x4336, 53}, + {0x4339, 0}, + {0x433a, 1}, + {0x433b, 2}, + {0x433c, 3}, + {0x433d, 4}, + {0x433e, 5}, + {0x433f, 6}, + {0x4340, 7}, + {0x4341, 8}, + {0x4342, 9}, + {0x4343, 10}, + {0x4344, 11}, + {0x4345, 12}, + {0x4346, 13}, + {0x4347, 14}, + {0x4348, 15}, + {0x4349, 16}, + {0x434a, 17}, + {0x434b, 18}, + {0x434c, 19}, + {0x434d, 20}, + {0x434e, 21}, + {0x434f, 22}, + {0x4350, 23}, + {0x4351, 24}, + {0x4352, 25}, + {0x4353, 26}, + {0x4354, 27}, + {0x4355, 28}, + {0x4356, 29}, + {0x4357, 30}, + {0x4358, 31}, + {0x4359, 32}, + {0x435a, 33}, + {0x435b, 34}, + {0x435c, 35}, + {0x435d, 36}, + {0x435e, 37}, + {0x435f, 38}, + {0x4360, 39}, + {0x4361, 40}, + {0x4362, 41}, + {0x4363, 42}, + {0x4364, 43}, + {0x4365, 44}, + {0x4366, 45}, + {0x4367, 46}, + {0x4368, 47}, + {0x4369, 48}, + {0x436a, 49}, + {0x436b, 50}, + {0x436c, 51}, + {0x436d, 52}, + {0x436e, 53}, + {0x436f, 54}, + {0x4370, 55}, + {0x4371, 56}, + {0x4372, 57}, + {0x4373, 58}, + {0x4374, 59}, + {0x4375, 60}, + {0x4376, 61}, + {0x4377, 62}, + {0x4378, 63}, + {0x4379, 64}, + {0x437a, 65}, + {0x437b, 66}, + {0x437c, 67}, + {0x437d, 68}, + {0x437e, 69}, + {0x437f, 70}, + {0x4380, 71}, + {0x4381, 72}, + {0x4382, 73}, + {0x4383, 74}, + {0x4384, 75}, + {0x4385, 76}, + {0x4386, 77}, + {0x4387, 78}, + {0x4388, 79}, + {0x4389, 80}, + {0x438a, 81}, + {0x438b, 82}, + {0x438c, 83}, + {0x438d, 84}, + {0x438e, 85}, + {0x438f, 86}, + {0x4390, 87}, + {0x4391, 88}, + {0x4392, 89}, + {0x4393, 90}, + {0x4394, 91}, + {0x4395, 92}, + {0x4396, 93}, + {0x4397, 94}, + {0x4398, 95}, + {0x4399, 96}, + {0x439a, 97}, + {0x439b, 98}, + {0x439c, 99}, + {0x439d, 100}, + {0x439e, 101}, + {0x439f, 102}, + {0x43a0, 103}, + {0x43a1, 104}, + {0x43a2, 105}, + {0x43a3, 106}, + {0x43a4, 107}, + {0x43a5, 108}, + {0x43a6, 109}, + {0x43a7, 110}, + {0x43a8, 111}, + {0x43a9, 112}, + {0x43aa, 113}, + {0x43ab, 114}, + {0x43ae, 0}, + {0x43af, 1}, + {0x43b0, 2}, + {0x43b3, 0}, + {0x43b4, 1}, + {0x43b5, 2}, + {0x43b6, 3}, + {0x43b7, 4}, + {0x43b8, 5}, + {0x43b9, 6}, + {0x43ba, 7}, + {0x43bb, 8}, + {0x43bc, 9}, + {0x43bd, 10}, + {0x43be, 11}, + {0x43bf, 12}, + {0x43c0, 13}, + {0x43c1, 14}, + {0x43c2, 15}, + {0x43c3, 16}, + {0x43c4, 17}, + {0x43c5, 18}, + {0x43c6, 19}, + {0x43c7, 20}, + {0x43c8, 21}, + {0x43c9, 22}, + {0x43ca, 23}, + {0x43cb, 24}, + {0x43cc, 25}, + {0x43cd, 26}, + {0x43ce, 27}, + {0x43cf, 28}, + {0x43d0, 29}, + {0x43d1, 30}, + {0x43d2, 31}, + {0x43d3, 32}, + {0x43d4, 33}, + {0x43d5, 34}, + {0x43d6, 35}, + {0x43d7, 36}, + {0x43d8, 37}, + {0x43d9, 38}, + {0x43da, 39}, + {0x43db, 40}, + {0x43dc, 41}, + {0x43df, 0}, + {0x43e0, 1}, + {0x43e1, 2}, + {0x43e2, 3}, + {0x43e3, 4}, + {0x43e4, 5}, + {0x43e5, 6}, + {0x43e6, 7}, + {0x43e7, 8}, + {0x43e8, 9}, + {0x43e9, 10}, + {0x43ea, 11}, + {0x43eb, 12}, + {0x43ec, 13}, + {0x43ed, 14}, + {0x43ee, 15}, + {0x43ef, 16}, + {0x43f0, 17}, + {0x43f1, 18}, + {0x43f2, 19}, + {0x43f3, 20}, + {0x43f4, 21}, + {0x43f5, 22}, + {0x43f6, 23}, + {0x43f7, 24}, + {0x43f8, 25}, + {0x43f9, 26}, + {0x43fa, 27}, + {0x43fb, 28}, + {0x43fc, 29}, + {0x43fd, 30}, + {0x43fe, 31}, + {0x43ff, 32}, + {0x4401, 0}, + {0x4402, 1}, + {0x4403, 2}, + {0x4404, 3}, + {0x4405, 4}, + {0x4406, 5}, + {0x4407, 6}, + {0x4408, 7}, + {0x4409, 8}, + {0x440a, 9}, + {0x440b, 10}, + {0x440c, 11}, + {0x440d, 12}, + {0x440e, 13}, + {0x440f, 14}, + {0x4410, 15}, + {0x4411, 16}, + {0x4412, 17}, + {0x4413, 18}, + {0x4414, 19}, + {0x4415, 20}, + {0x4416, 21}, + {0x4417, 22}, + {0x4418, 23}, + {0x4419, 24}, + {0x441a, 25}, + {0x441b, 26}, + {0x441c, 27}, + {0x441d, 28}, + {0x441e, 29}, + {0x441f, 30}, + {0x4420, 31}, + {0x4421, 32}, + {0x4422, 33}, + {0x4423, 34}, + {0x4424, 35}, + {0x4425, 36}, + {0x4426, 37}, + {0x4427, 38}, + {0x4428, 39}, + {0x4429, 40}, + {0x442a, 41}, + {0x442b, 42}, + {0x442c, 43}, + {0x442d, 44}, + {0x442e, 45}, + {0x442f, 46}, + {0x4430, 47}, + {0x4431, 48}, + {0x4432, 49}, + {0x4433, 50}, + {0x4434, 51}, + {0x4435, 52}, + {0x4436, 53}, + {0x4437, 54}, + {0x4438, 55}, + {0x4439, 56}, + {0x443a, 57}, + {0x443b, 58}, + {0x443c, 59}, + {0x443d, 60}, + {0x443e, 61}, + {0x443f, 62}, + {0x4440, 63}, + {0x4441, 64}, + {0x4442, 65}, + {0x4443, 66}, + {0x4444, 67}, + {0x4445, 68}, + {0x4446, 69}, + {0x4447, 70}, + {0x4448, 71}, + {0x4449, 72}, + {0x444a, 73}, + {0x444b, 74}, + {0x444c, 75}, + {0x444d, 76}, + {0x444e, 77}, + {0x444f, 78}, + {0x4450, 79}, + {0x4451, 80}, + {0x4452, 81}, + {0x4453, 82}, + {0x4454, 83}, + {0x4455, 84}, + {0x4456, 85}, + {0x4457, 86}, + {0x4458, 87}, + {0x4459, 88}, + {0x445a, 89}, + {0x445b, 90}, + {0x445c, 91}, + {0x445d, 92}, + {0x445e, 93}, + {0x445f, 94}, + {0x4460, 95}, + {0x4461, 96}, + {0x4462, 97}, + {0x4463, 98}, + {0x4464, 99}, + {0x4465, 100}, + {0x4466, 101}, + {0x4467, 102}, + {0x4468, 103}, + {0x4469, 104}, + {0x446a, 105}, + {0x446b, 106}, + {0x446c, 107}, + {0x446d, 108}, + {0x446e, 109}, + {0x446f, 110}, + {0x4470, 111}, + {0x4471, 112}, + {0x4472, 113}, + {0x4473, 114}, + {0x4474, 115}, + {0x4475, 116}, + {0x4476, 117}, + {0x4477, 118}, + {0x4478, 119}, + {0x4479, 120}, + {0x447a, 121}, + {0x447b, 122}, + {0x447c, 123}, + {0x447d, 124}, + {0x447e, 125}, + {0x447f, 126}, + {0x4480, 127}, + {0x4481, 128}, + {0x4482, 129}, + {0x4483, 130}, + {0x4484, 131}, + {0x4485, 132}, + {0x4486, 133}, + {0x4487, 134}, + {0x4488, 135}, + {0x4489, 136}, + {0x448a, 137}, + {0x448b, 138}, + {0x448c, 139}, + {0x448d, 140}, + {0x448e, 141}, + {0x448f, 142}, + {0x4490, 143}, + {0x4491, 144}, + {0x4492, 145}, + {0x4493, 146}, + {0x4494, 147}, + {0x4495, 148}, + {0x4496, 149}, + {0x4497, 150}, + {0x4498, 151}, + {0x4499, 152}, + {0x449a, 153}, + {0x449b, 154}, + {0x449c, 155}, + {0x449d, 156}, + {0x449e, 157}, + {0x449f, 158}, + {0x44a0, 159}, + {0x44a1, 160}, + {0x44a2, 161}, + {0x44a3, 162}, + {0x44a4, 163}, + {0x44a5, 164}, + {0x44a6, 165}, + {0x44a7, 166}, + {0x44a8, 167}, + {0x44a9, 168}, + {0x44aa, 169}, + {0x44ab, 170}, + {0x44ac, 171}, + {0x44ad, 172}, + {0x44ae, 173}, + {0x44af, 174}, + {0x44b0, 175}, + {0x44b1, 176}, + {0x44b2, 177}, + {0x44b3, 178}, + {0x44b4, 179}, + {0x44b5, 180}, + {0x44b6, 181}, + {0x44b7, 182}, + {0x44b8, 183}, + {0x44b9, 184}, + {0x44ba, 185}, + {0x44bb, 186}, + {0x44bc, 187}, + {0x44bd, 188}, + {0x44be, 189}, + {0x44bf, 190}, + {0x44c0, 191}, + {0x44c1, 192}, + {0x44c2, 193}, + {0x44c3, 194}, + {0x44c4, 195}, + {0x44c5, 196}, + {0x44c6, 197}, + {0x44c7, 198}, + {0x44c8, 199}, + {0x44c9, 200}, + {0x44ca, 201}, + {0x44cb, 202}, + {0x44cc, 203}, + {0x44cd, 204}, + {0x44ce, 205}, + {0x44cf, 206}, + {0x44d0, 207}, + {0x44d1, 208}, + {0x44d2, 209}, + {0x44d3, 210}, + {0x44d4, 211}, + {0x44d5, 212}, + {0x44d8, 0}, + {0x44d9, 1}, + {0x44da, 2}, + {0x44db, 3}, + {0x44dc, 4}, + {0x44dd, 5}, + {0x44de, 6}, + {0x44df, 7}, + {0x44e0, 8}, + {0x44e1, 9}, + {0x44e2, 10}, + {0x44e3, 11}, + {0x44e4, 12}, + {0x44e5, 13}, + {0x44e6, 14}, + {0x44e7, 15}, + {0x44e8, 16}, + {0x44e9, 17}, + {0x44ea, 18}, + {0x44eb, 19}, + {0x44ec, 20}, + {0x44ed, 21}, + {0x44ee, 22}, + {0x44ef, 23}, + {0x44f0, 24}, + {0x44f1, 25}, + {0x44f2, 26}, + {0x44f3, 27}, + {0x44f4, 28}, + {0x44f5, 29}, + {0x44f6, 30}, + {0x44f7, 31}, + {0x44f8, 32}, + {0x44f9, 33}, + {0x44fa, 34}, + {0x44fb, 35}, + {0x44fc, 36}, + {0x44fd, 37}, + {0x44fe, 38}, + {0x44ff, 39}, + {0x4501, 0}, + {0x4502, 1}, + {0x4503, 2}, + {0x4504, 3}, + {0x4505, 4}, + {0x4506, 5}, + {0x4507, 6}, + {0x4508, 7}, + {0x4509, 8}, + {0x450a, 9}, + {0x450b, 10}, + {0x450c, 11}, + {0x450d, 12}, + {0x450e, 13}, + {0x450f, 14}, + {0x4510, 15}, + {0x4511, 16}, + {0x4512, 17}, + {0x4513, 18}, + {0x4514, 19}, + {0x4515, 20}, + {0x4516, 21}, + {0x4517, 22}, + {0x4518, 23}, + {0x4519, 24}, + {0x451a, 25}, + {0x451b, 26}, + {0x451c, 27}, + {0x451d, 28}, + {0x451e, 29}, + {0x451f, 30}, + {0x4520, 31}, + {0x4521, 32}, + {0x4522, 33}, + {0x4523, 34}, + {0x4524, 35}, + {0x4525, 36}, + {0x4526, 37}, + {0x4527, 38}, + {0x4528, 39}, + {0x4529, 40}, + {0x452a, 41}, + {0x452b, 42}, + {0x452c, 43}, + {0x452d, 44}, + {0x452e, 45}, + {0x452f, 46}, + {0x4530, 47}, + {0x4531, 48}, + {0x4532, 49}, + {0x4533, 50}, + {0x4534, 51}, + {0x4535, 52}, + {0x4536, 53}, + {0x4537, 54}, + {0x4538, 55}, + {0x4539, 56}, + {0x453a, 57}, + {0x453b, 58}, + {0x453c, 59}, + {0x453d, 60}, + {0x453e, 61}, + {0x453f, 62}, + {0x4540, 63}, + {0x4541, 64}, + {0x4542, 65}, + {0x4543, 66}, + {0x4544, 67}, + {0x4545, 68}, + {0x4546, 69}, + {0x4547, 70}, + {0x4548, 71}, + {0x4549, 72}, + {0x454a, 73}, + {0x454b, 74}, + {0x454c, 75}, + {0x454d, 76}, + {0x454e, 77}, + {0x454f, 78}, + {0x4550, 79}, + {0x4551, 80}, + {0x4552, 81}, + {0x4553, 82}, + {0x4554, 83}, + {0x4555, 84}, + {0x4556, 85}, + {0x4557, 86}, + {0x4558, 87}, + {0x4559, 88}, + {0x455a, 89}, + {0x455b, 90}, + {0x455c, 91}, + {0x455d, 92}, + {0x455e, 93}, + {0x455f, 94}, + {0x4560, 95}, + {0x4561, 96}, + {0x4562, 97}, + {0x4563, 98}, + {0x4564, 99}, + {0x4565, 100}, + {0x4566, 101}, + {0x4567, 102}, + {0x4568, 103}, + {0x4569, 104}, + {0x456a, 105}, + {0x456b, 106}, + {0x456c, 107}, + {0x456d, 108}, + {0x456e, 109}, + {0x456f, 110}, + {0x4570, 111}, + {0x4571, 112}, + {0x4572, 113}, + {0x4573, 114}, + {0x4574, 115}, + {0x4575, 116}, + {0x4576, 117}, + {0x4577, 118}, + {0x4578, 119}, + {0x4579, 120}, + {0x457a, 121}, + {0x457b, 122}, + {0x457c, 123}, + {0x457d, 124}, + {0x457e, 125}, + {0x457f, 126}, + {0x4580, 127}, + {0x4581, 128}, + {0x4582, 129}, + {0x4583, 130}, + {0x4584, 131}, + {0x4585, 132}, + {0x4586, 133}, + {0x4587, 134}, + {0x4588, 135}, + {0x4589, 136}, + {0x458a, 137}, + {0x458b, 138}, + {0x458c, 139}, + {0x458d, 140}, + {0x458e, 141}, + {0x458f, 142}, + {0x4590, 143}, + {0x4591, 144}, + {0x4592, 145}, + {0x4593, 146}, + {0x4594, 147}, + {0x4595, 148}, + {0x4596, 149}, + {0x4597, 150}, + {0x4598, 151}, + {0x4599, 152}, + {0x459a, 153}, + {0x459b, 154}, + {0x459c, 155}, + {0x459d, 156}, + {0x459e, 157}, + {0x459f, 158}, + {0x45a0, 159}, + {0x45a1, 160}, + {0x45a2, 161}, + {0x45a3, 162}, + {0x45a4, 163}, + {0x45a5, 164}, + {0x45a6, 165}, + {0x45a7, 166}, + {0x45a8, 167}, + {0x45a9, 168}, + {0x45aa, 169}, + {0x45ab, 170}, + {0x45ac, 171}, + {0x45ad, 172}, + {0x45ae, 173}, + {0x45af, 174}, + {0x45b0, 175}, + {0x45b1, 176}, + {0x45b2, 177}, + {0x45b3, 178}, + {0x45b4, 179}, + {0x45b5, 180}, + {0x45b6, 181}, + {0x45b7, 182}, + {0x45b8, 183}, + {0x45b9, 184}, + {0x45ba, 185}, + {0x45bb, 186}, + {0x45bc, 187}, + {0x45bd, 188}, + {0x45be, 189}, + {0x45bf, 190}, + {0x45c0, 191}, + {0x45c1, 192}, + {0x45c2, 193}, + {0x45c3, 194}, + {0x45c4, 195}, + {0x45c5, 196}, + {0x45c6, 197}, + {0x45c7, 198}, + {0x45c8, 199}, + {0x45c9, 200}, + {0x45ca, 201}, + {0x45cb, 202}, + {0x45cc, 203}, + {0x45cd, 204}, + {0x45ce, 205}, + {0x45cf, 206}, + {0x45d0, 207}, + {0x45d1, 208}, + {0x45d2, 209}, + {0x45d3, 210}, + {0x45d4, 211}, + {0x45d5, 212}, + {0x45d6, 213}, + {0x45d7, 214}, + {0x45d8, 215}, + {0x45d9, 216}, + {0x45da, 217}, + {0x45db, 218}, + {0x45dc, 219}, + {0x45dd, 220}, + {0x45de, 221}, + {0x45df, 222}, + {0x45e0, 223}, + {0x45e1, 224}, + {0x45e2, 225}, + {0x45e3, 226}, + {0x45e4, 227}, + {0x45e5, 228}, + {0x45e6, 229}, + {0x45e7, 230}, + {0x45e8, 231}, + {0x45e9, 232}, + {0x45ea, 233}, + {0x45eb, 234}, + {0x45ec, 235}, + {0x45ed, 236}, + {0x45ee, 237}, + {0x45ef, 238}, + {0x45f0, 239}, + {0x45f1, 240}, + {0x45f2, 241}, + {0x45f3, 242}, + {0x45f4, 243}, + {0x45f5, 244}, + {0x45f6, 245}, + {0x45f7, 246}, + {0x45f8, 247}, + {0x45f9, 248}, + {0x45fa, 249}, + {0x45fb, 250}, + {0x45fc, 251}, + {0x45fd, 252}, + {0x45fe, 253}, + {0x45ff, 254}, + {0x4601, 0}, + {0x4602, 1}, + {0x4603, 2}, + {0x4604, 3}, + {0x4605, 4}, + {0x4606, 5}, + {0x4607, 6}, + {0x4608, 7}, + {0x4609, 8}, + {0x460a, 9}, + {0x460b, 10}, + {0x460c, 11}, + {0x460d, 12}, + {0x460e, 13}, + {0x460f, 14}, + {0x4610, 15}, + {0x4611, 16}, + {0x4612, 17}, + {0x4613, 18}, + {0x4614, 19}, + {0x4615, 20}, + {0x4616, 21}, + {0x4617, 22}, + {0x4618, 23}, + {0x4619, 24}, + {0x461a, 25}, + {0x461b, 26}, + {0x461c, 27}, + {0x461d, 28}, + {0x461e, 29}, + {0x461f, 30}, + {0x4620, 31}, + {0x4621, 32}, + {0x4622, 33}, + {0x4623, 34}, + {0x4624, 35}, + {0x4625, 36}, + {0x4626, 37}, + {0x4627, 38}, + {0x4628, 39}, + {0x4629, 40}, + {0x462a, 41}, + {0x462b, 42}, + {0x462c, 43}, + {0x462d, 44}, + {0x462e, 45}, + {0x462f, 46}, + {0x4630, 47}, + {0x4631, 48}, + {0x4632, 49}, + {0x4633, 50}, + {0x4634, 51}, + {0x4635, 52}, + {0x4636, 53}, + {0x4637, 54}, + {0x4638, 55}, + {0x4639, 56}, + {0x463a, 57}, + {0x463b, 58}, + {0x463c, 59}, + {0x463d, 60}, + {0x463e, 61}, + {0x463f, 62}, + {0x4640, 63}, + {0x4641, 64}, + {0x4642, 65}, + {0x4643, 66}, + {0x4644, 67}, + {0x4645, 68}, + {0x4646, 69}, + {0x4647, 70}, + {0x4648, 71}, + {0x4649, 72}, + {0x464a, 73}, + {0x464b, 74}, + {0x464e, 0}, + {0x464f, 1}, + {0x4650, 2}, + {0x4651, 3}, + {0x4652, 4}, + {0x4653, 5}, + {0x4654, 6}, + {0x4655, 7}, + {0x4656, 8}, + {0x4657, 9}, + {0x4658, 10}, + {0x4659, 11}, + {0x465a, 12}, + {0x465b, 13}, + {0x465c, 14}, + {0x465d, 15}, + {0x465e, 16}, + {0x465f, 17}, + {0x4660, 18}, + {0x4663, 0}, + {0x4664, 1}, + {0x4665, 2}, + {0x4666, 3}, + {0x4667, 4}, + {0x4668, 5}, + {0x4669, 6}, + {0x466a, 7}, + {0x466b, 8}, + {0x466c, 9}, + {0x466d, 10}, + {0x466e, 11}, + {0x466f, 12}, + {0x4670, 13}, + {0x4671, 14}, + {0x4672, 15}, + {0x4673, 16}, + {0x4674, 17}, + {0x4675, 18}, + {0x4676, 19}, + {0x4677, 20}, + {0x4678, 21}, + {0x4679, 22}, + {0x467a, 23}, + {0x467b, 24}, + {0x467c, 25}, + {0x467d, 26}, + {0x467e, 27}, + {0x467f, 28}, + {0x4680, 29}, + {0x4681, 30}, + {0x4682, 31}, + {0x4683, 32}, + {0x4684, 33}, + {0x4685, 34}, + {0x4686, 35}, + {0x4687, 36}, + {0x4688, 37}, + {0x4689, 38}, + {0x468a, 39}, + {0x468b, 40}, + {0x468c, 41}, + {0x468d, 42}, + {0x468e, 43}, + {0x468f, 44}, + {0x4690, 45}, + {0x4691, 46}, + {0x4692, 47}, + {0x4693, 48}, + {0x4694, 49}, + {0x4695, 50}, + {0x4696, 51}, + {0x4697, 52}, + {0x4698, 53}, + {0x4699, 54}, + {0x469a, 55}, + {0x469b, 56}, + {0x469c, 57}, + {0x469d, 58}, + {0x469e, 59}, + {0x469f, 60}, + {0x46a0, 61}, + {0x46a1, 62}, + {0x46a2, 63}, + {0x46a3, 64}, + {0x46a4, 65}, + {0x46a5, 66}, + {0x46a6, 67}, + {0x46a7, 68}, + {0x46a8, 69}, + {0x46a9, 70}, + {0x46aa, 71}, + {0x46ab, 72}, + {0x46ac, 73}, + {0x46ad, 74}, + {0x46ae, 75}, + {0x46af, 76}, + {0x46b0, 77}, + {0x46b1, 78}, + {0x46b2, 79}, + {0x46b3, 80}, + {0x46b4, 81}, + {0x46b5, 82}, + {0x46b6, 83}, + {0x46b7, 84}, + {0x46b8, 85}, + {0x46b9, 86}, + {0x46ba, 87}, + {0x46bb, 88}, + {0x46bc, 89}, + {0x46bd, 90}, + {0x46be, 91}, + {0x46bf, 92}, + {0x46c0, 93}, + {0x46c1, 94}, + {0x46c2, 95}, + {0x46c3, 96}, + {0x46c4, 97}, + {0x46c5, 98}, + {0x46c6, 99}, + {0x46c7, 100}, + {0x46c8, 101}, + {0x46c9, 102}, + {0x46ca, 103}, + {0x46cb, 104}, + {0x46cc, 105}, + {0x46cd, 106}, + {0x46ce, 107}, + {0x46cf, 108}, + {0x46d0, 109}, + {0x46d1, 110}, + {0x46d2, 111}, + {0x46d3, 112}, + {0x46d4, 113}, + {0x46d5, 114}, + {0x46d6, 115}, + {0x46d7, 116}, + {0x46d8, 117}, + {0x46d9, 118}, + {0x46da, 119}, + {0x46db, 120}, + {0x46dc, 121}, + {0x46dd, 122}, + {0x46de, 123}, + {0x46df, 124}, + {0x46e0, 125}, + {0x46e1, 126}, + {0x46e2, 127}, + {0x46e3, 128}, + {0x46e4, 129}, + {0x46e5, 130}, + {0x46e6, 131}, + {0x46e7, 132}, + {0x46e8, 133}, + {0x46e9, 134}, + {0x46ea, 135}, + {0x46eb, 136}, + {0x46ec, 137}, + {0x46ed, 138}, + {0x46ee, 139}, + {0x46ef, 140}, + {0x46f0, 141}, + {0x46f1, 142}, + {0x46f2, 143}, + {0x46f3, 144}, + {0x46f4, 145}, + {0x46f5, 146}, + {0x46f6, 147}, + {0x46f7, 148}, + {0x46f8, 149}, + {0x46f9, 150}, + {0x46fa, 151}, + {0x46fb, 152}, + {0x46fc, 153}, + {0x46fd, 154}, + {0x46fe, 155}, + {0x46ff, 156}, + {0x4701, 0}, + {0x4702, 1}, + {0x4703, 2}, + {0x4704, 3}, + {0x4705, 4}, + {0x4706, 5}, + {0x4707, 6}, + {0x4708, 7}, + {0x4709, 8}, + {0x470a, 9}, + {0x470b, 10}, + {0x470c, 11}, + {0x470d, 12}, + {0x470e, 13}, + {0x470f, 14}, + {0x4710, 15}, + {0x4711, 16}, + {0x4712, 17}, + {0x4713, 18}, + {0x4714, 19}, + {0x4715, 20}, + {0x4716, 21}, + {0x4717, 22}, + {0x4718, 23}, + {0x4719, 24}, + {0x471a, 25}, + {0x471b, 26}, + {0x471c, 27}, + {0x471d, 28}, + {0x471e, 29}, + {0x471f, 30}, + {0x4720, 31}, + {0x4721, 32}, + {0x4722, 33}, + {0x4725, 0}, + {0x4726, 1}, + {0x4727, 2}, + {0x4728, 3}, + {0x472b, 0}, + {0x472c, 1}, + {0x472d, 2}, + {0x472e, 3}, + {0x472f, 4}, + {0x4730, 5}, + {0x4731, 6}, + {0x4732, 7}, + {0x4733, 8}, + {0x4734, 9}, + {0x4735, 10}, + {0x4736, 11}, + {0x4737, 12}, + {0x4738, 13}, + {0x4739, 14}, + {0x473a, 15}, + {0x473b, 16}, + {0x473c, 17}, + {0x473d, 18}, + {0x473e, 19}, + {0x473f, 20}, + {0x4740, 21}, + {0x4741, 22}, + {0x4742, 23}, + {0x4743, 24}, + {0x4744, 25}, + {0x4745, 26}, + {0x4746, 27}, + {0x4747, 28}, + {0x4748, 29}, + {0x4749, 30}, + {0x474a, 31}, + {0x474b, 32}, + {0x474c, 33}, + {0x474d, 34}, + {0x474e, 35}, + {0x474f, 36}, + {0x4750, 37}, + {0x4751, 38}, + {0x4752, 39}, + {0x4753, 40}, + {0x4754, 41}, + {0x4755, 42}, + {0x4756, 43}, + {0x4757, 44}, + {0x4758, 45}, + {0x4759, 46}, + {0x475a, 47}, + {0x475b, 48}, + {0x475c, 49}, + {0x475d, 50}, + {0x475e, 51}, + {0x475f, 52}, + {0x4760, 53}, + {0x4761, 54}, + {0x4762, 55}, + {0x4763, 56}, + {0x4764, 57}, + {0x4765, 58}, + {0x4766, 59}, + {0x4767, 60}, + {0x4768, 61}, + {0x4769, 62}, + {0x476a, 63}, + {0x476b, 64}, + {0x476c, 65}, + {0x476d, 66}, + {0x476e, 67}, + {0x476f, 68}, + {0x4770, 69}, + {0x4771, 70}, + {0x4772, 71}, + {0x4773, 72}, + {0x4774, 73}, + {0x4775, 74}, + {0x4776, 75}, + {0x4777, 76}, + {0x4778, 77}, + {0x4779, 78}, + {0x477a, 79}, + {0x477b, 80}, + {0x477e, 0}, + {0x477f, 1}, + {0x4780, 2}, + {0x4781, 3}, + {0x4782, 4}, + {0x4783, 5}, + {0x4784, 6}, + {0x4785, 7}, + {0x4786, 8}, + {0x4787, 9}, + {0x4788, 10}, + {0x4789, 11}, + {0x478a, 12}, + {0x478b, 13}, + {0x478c, 14}, + {0x478f, 0}, + {0x4790, 1}, + {0x4791, 2}, + {0x4792, 3}, + {0x4793, 4}, + {0x4794, 5}, + {0x4795, 6}, + {0x4796, 7}, + {0x4797, 8}, + {0x4798, 9}, + {0x4799, 10}, + {0x479a, 11}, + {0x479b, 12}, + {0x479c, 13}, + {0x479d, 14}, + {0x479e, 15}, + {0x479f, 16}, + {0x47a0, 17}, + {0x47a1, 18}, + {0x47a2, 19}, + {0x47a3, 20}, + {0x47a4, 21}, + {0x47a5, 22}, + {0x47a6, 23}, + {0x47a7, 24}, + {0x47a8, 25}, + {0x47a9, 26}, + {0x47aa, 27}, + {0x47ab, 28}, + {0x47ac, 29}, + {0x47ad, 30}, + {0x47ae, 31}, + {0x47af, 32}, + {0x47b0, 33}, + {0x47b1, 34}, + {0x47b2, 35}, + {0x47b3, 36}, + {0x47b4, 37}, + {0x47b5, 38}, + {0x47b6, 39}, + {0x47b7, 40}, + {0x47b8, 41}, + {0x47b9, 42}, + {0x47ba, 43}, + {0x47bb, 44}, + {0x47bc, 45}, + {0x47bd, 46}, + {0x47be, 47}, + {0x47bf, 48}, + {0x47c0, 49}, + {0x47c1, 50}, + {0x47c2, 51}, + {0x47c3, 52}, + {0x47c4, 53}, + {0x47c5, 54}, + {0x47c6, 55}, + {0x47c7, 56}, + {0x47c8, 57}, + {0x47c9, 58}, + {0x47ca, 59}, + {0x47cb, 60}, + {0x47cc, 61}, + {0x47cd, 62}, + {0x47ce, 63}, + {0x47cf, 64}, + {0x47d0, 65}, + {0x47d1, 66}, + {0x47d2, 67}, + {0x47d3, 68}, + {0x47d4, 69}, + {0x47d5, 70}, + {0x47d6, 71}, + {0x47d7, 72}, + {0x47d8, 73}, + {0x47d9, 74}, + {0x47da, 75}, + {0x47db, 76}, + {0x47dc, 77}, + {0x47dd, 78}, + {0x47de, 79}, + {0x47df, 80}, + {0x47e0, 81}, + {0x47e1, 82}, + {0x47e2, 83}, + {0x47e3, 84}, + {0x47e4, 85}, + {0x47e5, 86}, + {0x47e6, 87}, + {0x47e7, 88}, + {0x47e8, 89}, + {0x47e9, 90}, + {0x47ea, 91}, + {0x47eb, 92}, + {0x47ec, 93}, + {0x47ed, 94}, + {0x47ee, 95}, + {0x47ef, 96}, + {0x47f0, 97}, + {0x47f1, 98}, + {0x47f2, 99}, + {0x47f3, 100}, + {0x47f4, 101}, + {0x47f5, 102}, + {0x47f6, 103}, + {0x47f7, 104}, + {0x47f8, 105}, + {0x47f9, 106}, + {0x47fa, 107}, + {0x47fb, 108}, + {0x47fc, 109}, + {0x47fd, 110}, + {0x47fe, 111}, + {0x47ff, 112}, + {0x4801, 0}, + {0x4802, 1}, + {0x4803, 2}, + {0x4804, 3}, + {0x4805, 4}, + {0x4806, 5}, + {0x4807, 6}, + {0x4808, 7}, + {0x4809, 8}, + {0x480a, 9}, + {0x480b, 10}, + {0x480c, 11}, + {0x480d, 12}, + {0x480e, 13}, + {0x480f, 14}, + {0x4810, 15}, + {0x4811, 16}, + {0x4812, 17}, + {0x4813, 18}, + {0x4814, 19}, + {0x4815, 20}, + {0x4816, 21}, + {0x4817, 22}, + {0x4818, 23}, + {0x4819, 24}, + {0x481a, 25}, + {0x481b, 26}, + {0x481c, 27}, + {0x481d, 28}, + {0x481e, 29}, + {0x481f, 30}, + {0x4820, 31}, + {0x4821, 32}, + {0x4822, 33}, + {0x4823, 34}, + {0x4824, 35}, + {0x4825, 36}, + {0x4826, 37}, + {0x4827, 38}, + {0x4828, 39}, + {0x4829, 40}, + {0x482a, 41}, + {0x482b, 42}, + {0x482c, 43}, + {0x482d, 44}, + {0x482e, 45}, + {0x482f, 46}, + {0x4830, 47}, + {0x4831, 48}, + {0x4832, 49}, + {0x4833, 50}, + {0x4834, 51}, + {0x4835, 52}, + {0x4836, 53}, + {0x4837, 54}, + {0x4838, 55}, + {0x4839, 56}, + {0x483a, 57}, + {0x483b, 58}, + {0x483c, 59}, + {0x483d, 60}, + {0x483e, 61}, + {0x483f, 62}, + {0x4840, 63}, + {0x4841, 64}, + {0x4842, 65}, + {0x4843, 66}, + {0x4844, 67}, + {0x4845, 68}, + {0x4846, 69}, + {0x4847, 70}, + {0x4848, 71}, + {0x4849, 72}, + {0x484a, 73}, + {0x484b, 74}, + {0x484c, 75}, + {0x484d, 76}, + {0x484e, 77}, + {0x484f, 78}, + {0x4850, 79}, + {0x4851, 80}, + {0x4852, 81}, + {0x4853, 82}, + {0x4854, 83}, + {0x4855, 84}, + {0x4856, 85}, + {0x4857, 86}, + {0x4858, 87}, + {0x4859, 88}, + {0x485a, 89}, + {0x485b, 90}, + {0x485c, 91}, + {0x485d, 92}, + {0x485e, 93}, + {0x485f, 94}, + {0x4860, 95}, + {0x4861, 96}, + {0x4862, 97}, + {0x4863, 98}, + {0x4864, 99}, + {0x4865, 100}, + {0x4866, 101}, + {0x4867, 102}, + {0x4868, 103}, + {0x4869, 104}, + {0x486a, 105}, + {0x486b, 106}, + {0x486c, 107}, + {0x486d, 108}, + {0x486e, 109}, + {0x486f, 110}, + {0x4870, 111}, + {0x4871, 112}, + {0x4872, 113}, + {0x4873, 114}, + {0x4874, 115}, + {0x4875, 116}, + {0x4876, 117}, + {0x4877, 118}, + {0x4878, 119}, + {0x4879, 120}, + {0x487a, 121}, + {0x487b, 122}, + {0x487c, 123}, + {0x487d, 124}, + {0x487e, 125}, + {0x487f, 126}, + {0x4880, 127}, + {0x4881, 128}, + {0x4882, 129}, + {0x4883, 130}, + {0x4884, 131}, + {0x4885, 132}, + {0x4886, 133}, + {0x4887, 134}, + {0x4888, 135}, + {0x4889, 136}, + {0x488a, 137}, + {0x488b, 138}, + {0x488c, 139}, + {0x488d, 140}, + {0x488e, 141}, + {0x488f, 142}, + {0x4890, 143}, + {0x4891, 144}, + {0x4892, 145}, + {0x4893, 146}, + {0x4894, 147}, + {0x4895, 148}, + {0x4896, 149}, + {0x4897, 150}, + {0x4898, 151}, + {0x4899, 152}, + {0x489a, 153}, + {0x489b, 154}, + {0x489c, 155}, + {0x489d, 156}, + {0x489e, 157}, + {0x489f, 158}, + {0x48a0, 159}, + {0x48a1, 160}, + {0x48a2, 161}, + {0x48a3, 162}, + {0x48a4, 163}, + {0x48a5, 164}, + {0x48a6, 165}, + {0x48a7, 166}, + {0x48a8, 167}, + {0x48a9, 168}, + {0x48aa, 169}, + {0x48ab, 170}, + {0x48ac, 171}, + {0x48ad, 172}, + {0x48ae, 173}, + {0x48af, 174}, + {0x48b0, 175}, + {0x48b1, 176}, + {0x48b2, 177}, + {0x48b3, 178}, + {0x48b4, 179}, + {0x48b5, 180}, + {0x48b6, 181}, + {0x48b7, 182}, + {0x48b8, 183}, + {0x48b9, 184}, + {0x48ba, 185}, + {0x48bb, 186}, + {0x48bc, 187}, + {0x48bd, 188}, + {0x48be, 189}, + {0x48bf, 190}, + {0x48c0, 191}, + {0x48c1, 192}, + {0x48c2, 193}, + {0x48c3, 194}, + {0x48c4, 195}, + {0x48c5, 196}, + {0x48c6, 197}, + {0x48c7, 198}, + {0x48c8, 199}, + {0x48c9, 200}, + {0x48ca, 201}, + {0x48cb, 202}, + {0x48cc, 203}, + {0x48cd, 204}, + {0x48ce, 205}, + {0x48cf, 206}, + {0x48d0, 207}, + {0x48d1, 208}, + {0x48d2, 209}, + {0x48d3, 210}, + {0x48d4, 211}, + {0x48d5, 212}, + {0x48d6, 213}, + {0x48d7, 214}, + {0x48d8, 215}, + {0x48d9, 216}, + {0x48da, 217}, + {0x48db, 218}, + {0x48dc, 219}, + {0x48dd, 220}, + {0x48de, 221}, + {0x48df, 222}, + {0x48e0, 223}, + {0x48e1, 224}, + {0x48e2, 225}, + {0x48e3, 226}, + {0x48e4, 227}, + {0x48e5, 228}, + {0x48e6, 229}, + {0x48e7, 230}, + {0x48e8, 231}, + {0x48e9, 232}, + {0x48ea, 233}, + {0x48eb, 234}, + {0x48ec, 235}, + {0x48ed, 236}, + {0x48ee, 237}, + {0x48ef, 238}, + {0x48f0, 239}, + {0x48f1, 240}, + {0x48f2, 241}, + {0x48f3, 242}, + {0x48f4, 243}, + {0x48f5, 244}, + {0x48f6, 245}, + {0x48f7, 246}, + {0x48f8, 247}, + {0x48f9, 248}, + {0x48fa, 249}, + {0x48fb, 250}, + {0x48fc, 251}, + {0x48fd, 252}, + {0x48fe, 253}, + {0x48ff, 254}, + {0x4901, 0}, + {0x4902, 1}, + {0x4903, 2}, + {0x4904, 3}, + {0x4905, 4}, + {0x4906, 5}, + {0x4907, 6}, + {0x4908, 7}, + {0x4909, 8}, + {0x490a, 9}, + {0x490b, 10}, + {0x490c, 11}, + {0x490d, 12}, + {0x490e, 13}, + {0x490f, 14}, + {0x4910, 15}, + {0x4911, 16}, + {0x4912, 17}, + {0x4913, 18}, + {0x4914, 19}, + {0x4915, 20}, + {0x4916, 21}, + {0x4917, 22}, + {0x4918, 23}, + {0x4919, 24}, + {0x491a, 25}, + {0x491b, 26}, + {0x491c, 27}, + {0x491d, 28}, + {0x491e, 29}, + {0x491f, 30}, + {0x4920, 31}, + {0x4921, 32}, + {0x4922, 33}, + {0x4923, 34}, + {0x4924, 35}, + {0x4925, 36}, + {0x4926, 37}, + {0x4927, 38}, + {0x4928, 39}, + {0x4929, 40}, + {0x492a, 41}, + {0x492b, 42}, + {0x492c, 43}, + {0x492d, 44}, + {0x492e, 45}, + {0x492f, 46}, + {0x4930, 47}, + {0x4931, 48}, + {0x4932, 49}, + {0x4933, 50}, + {0x4934, 51}, + {0x4935, 52}, + {0x4936, 53}, + {0x4937, 54}, + {0x4938, 55}, + {0x4939, 56}, + {0x493a, 57}, + {0x493b, 58}, + {0x493c, 59}, + {0x493d, 60}, + {0x493e, 61}, + {0x493f, 62}, + {0x4940, 63}, + {0x4941, 64}, + {0x4942, 65}, + {0x4943, 66}, + {0x4944, 67}, + {0x4945, 68}, + {0x4946, 69}, + {0x4949, 0}, + {0x494a, 1}, + {0x494b, 2}, + {0x494c, 3}, + {0x494d, 4}, + {0x494e, 5}, + {0x494f, 6}, + {0x4950, 7}, + {0x4951, 8}, + {0x4952, 9}, + {0x4953, 10}, + {0x4954, 11}, + {0x4955, 12}, + {0x4956, 13}, + {0x4957, 14}, + {0x4958, 15}, + {0x4959, 16}, + {0x495a, 17}, + {0x495b, 18}, + {0x495c, 19}, + {0x495d, 20}, + {0x495e, 21}, + {0x495f, 22}, + {0x4960, 23}, + {0x4961, 24}, + {0x4962, 25}, + {0x4963, 26}, + {0x4964, 27}, + {0x4965, 28}, + {0x4966, 29}, + {0x4967, 30}, + {0x4968, 31}, + {0x4969, 32}, + {0x496a, 33}, + {0x496b, 34}, + {0x496c, 35}, + {0x496d, 36}, + {0x496e, 37}, + {0x496f, 38}, + {0x4970, 39}, + {0x4971, 40}, + {0x4972, 41}, + {0x4973, 42}, + {0x4974, 43}, + {0x4975, 44}, + {0x4976, 45}, + {0x4977, 46}, + {0x4978, 47}, + {0x4979, 48}, + {0x497c, 0}, + {0x497f, 0}, + {0x4980, 1}, + {0x4981, 2}, + {0x4983, 0}, + {0x4986, 0}, + {0x4988, 0}, + {0x4989, 1}, + {0x498a, 2}, + {0x498b, 3}, + {0x498c, 4}, + {0x498d, 5}, + {0x498e, 6}, + {0x498f, 7}, + {0x4990, 8}, + {0x4991, 9}, + {0x4992, 10}, + {0x4993, 11}, + {0x4994, 12}, + {0x4995, 13}, + {0x4996, 14}, + {0x4997, 15}, + {0x4998, 16}, + {0x4999, 17}, + {0x499a, 18}, + {0x499d, 0}, + {0x499e, 1}, + {0x49a1, 0}, + {0x49a2, 1}, + {0x49a3, 2}, + {0x49a4, 3}, + {0x49a5, 4}, + {0x49a6, 5}, + {0x49a7, 6}, + {0x49a8, 7}, + {0x49a9, 8}, + {0x49aa, 9}, + {0x49ab, 10}, + {0x49ac, 11}, + {0x49ad, 12}, + {0x49ae, 13}, + {0x49af, 14}, + {0x49b0, 15}, + {0x49b1, 16}, + {0x49b2, 17}, + {0x49b3, 18}, + {0x49b4, 19}, + {0x49b5, 20}, + {0x49b9, 0}, + {0x49ba, 1}, + {0x49bb, 2}, + {0x49bc, 3}, + {0x49bd, 4}, + {0x49be, 5}, + {0x49bf, 6}, + {0x49c0, 7}, + {0x49c1, 8}, + {0x49c2, 9}, + {0x49c3, 10}, + {0x49c4, 11}, + {0x49c5, 12}, + {0x49c6, 13}, + {0x49c7, 14}, + {0x49c8, 15}, + {0x49c9, 16}, + {0x49ca, 17}, + {0x49cb, 18}, + {0x49cc, 19}, + {0x49cd, 20}, + {0x49ce, 21}, + {0x49cf, 22}, + {0x49d0, 23}, + {0x49d1, 24}, + {0x49d2, 25}, + {0x49d3, 26}, + {0x49d4, 27}, + {0x49d5, 28}, + {0x49d6, 29}, + {0x49d7, 30}, + {0x49d8, 31}, + {0x49d9, 32}, + {0x49da, 33}, + {0x49db, 34}, + {0x49dc, 35}, + {0x49dd, 36}, + {0x49de, 37}, + {0x49df, 38}, + {0x49e0, 39}, + {0x49e1, 40}, + {0x49e2, 41}, + {0x49e3, 42}, + {0x49e4, 43}, + {0x49e5, 44}, + {0x49e6, 45}, + {0x49e7, 46}, + {0x49e8, 47}, + {0x49e9, 48}, + {0x49ea, 49}, + {0x49eb, 50}, + {0x49ec, 51}, + {0x49ed, 52}, + {0x49ee, 53}, + {0x49ef, 54}, + {0x49f0, 55}, + {0x49f1, 56}, + {0x49f2, 57}, + {0x49f3, 58}, + {0x49f4, 59}, + {0x49f5, 60}, + {0x49f6, 61}, + {0x49f7, 62}, + {0x49f8, 63}, + {0x49f9, 64}, + {0x49fa, 65}, + {0x49fb, 66}, + {0x49fc, 67}, + {0x49fd, 68}, + {0x49fe, 69}, + {0x49ff, 70}, + {0x4a01, 0}, + {0x4a02, 1}, + {0x4a03, 2}, + {0x4a04, 3}, + {0x4a05, 4}, + {0x4a06, 5}, + {0x4a07, 6}, + {0x4a08, 7}, + {0x4a09, 8}, + {0x4a0a, 9}, + {0x4a0b, 10}, + {0x4a0c, 11}, + {0x4a0d, 12}, + {0x4a0e, 13}, + {0x4a0f, 14}, + {0x4a10, 15}, + {0x4a11, 16}, + {0x4a12, 17}, + {0x4a13, 18}, + {0x4a14, 19}, + {0x4a15, 20}, + {0x4a16, 21}, + {0x4a17, 22}, + {0x4a18, 23}, + {0x4a19, 24}, + {0x4a1a, 25}, + {0x4a1b, 26}, + {0x4a1c, 27}, + {0x4a1d, 28}, + {0x4a1e, 29}, + {0x4a1f, 30}, + {0x4a20, 31}, + {0x4a21, 32}, + {0x4a22, 33}, + {0x4a23, 34}, + {0x4a24, 35}, + {0x4a25, 36}, + {0x4a26, 37}, + {0x4a27, 38}, + {0x4a28, 39}, + {0x4a29, 40}, + {0x4a2a, 41}, + {0x4a2b, 42}, + {0x4a2c, 43}, + {0x4a2d, 44}, + {0x4a2e, 45}, + {0x4a2f, 46}, + {0x4a30, 47}, + {0x4a31, 48}, + {0x4a32, 49}, + {0x4a33, 50}, + {0x4a34, 51}, + {0x4a35, 52}, + {0x4a36, 53}, + {0x4a37, 54}, + {0x4a38, 55}, + {0x4a39, 56}, + {0x4a3a, 57}, + {0x4a3b, 58}, + {0x4a3c, 59}, + {0x4a3d, 60}, + {0x4a3e, 61}, + {0x4a3f, 62}, + {0x4a40, 63}, + {0x4a41, 64}, + {0x4a42, 65}, + {0x4a43, 66}, + {0x4a44, 67}, + {0x4a45, 68}, + {0x4a46, 69}, + {0x4a47, 70}, + {0x4a48, 71}, + {0x4a49, 72}, + {0x4a4a, 73}, + {0x4a4b, 74}, + {0x4a4c, 75}, + {0x4a4d, 76}, + {0x4a4e, 77}, + {0x4a4f, 78}, + {0x4a50, 79}, + {0x4a51, 80}, + {0x4a52, 81}, + {0x4a53, 82}, + {0x4a54, 83}, + {0x4a55, 84}, + {0x4a56, 85}, + {0x4a57, 86}, + {0x4a58, 87}, + {0x4a59, 88}, + {0x4a5a, 89}, + {0x4a5b, 90}, + {0x4a5c, 91}, + {0x4a5d, 92}, + {0x4a5e, 93}, + {0x4a5f, 94}, + {0x4a60, 95}, + {0x4a61, 96}, + {0x4a62, 97}, + {0x4a63, 98}, + {0x4a64, 99}, + {0x4a65, 100}, + {0x4a66, 101}, + {0x4a67, 102}, + {0x4a68, 103}, + {0x4a69, 104}, + {0x4a6a, 105}, + {0x4a6b, 106}, + {0x4a6c, 107}, + {0x4a6d, 108}, + {0x4a6e, 109}, + {0x4a6f, 110}, + {0x4a70, 111}, + {0x4a71, 112}, + {0x4a72, 113}, + {0x4a73, 114}, + {0x4a74, 115}, + {0x4a75, 116}, + {0x4a76, 117}, + {0x4a77, 118}, + {0x4a78, 119}, + {0x4a79, 120}, + {0x4a7a, 121}, + {0x4a7b, 122}, + {0x4a7c, 123}, + {0x4a7d, 124}, + {0x4a7e, 125}, + {0x4a7f, 126}, + {0x4a80, 127}, + {0x4a81, 128}, + {0x4a82, 129}, + {0x4a83, 130}, + {0x4a84, 131}, + {0x4a85, 132}, + {0x4a86, 133}, + {0x4a87, 134}, + {0x4a88, 135}, + {0x4a89, 136}, + {0x4a8a, 137}, + {0x4a8b, 138}, + {0x4a8c, 139}, + {0x4a8d, 140}, + {0x4a8e, 141}, + {0x4a8f, 142}, + {0x4a90, 143}, + {0x4a91, 144}, + {0x4a92, 145}, + {0x4a93, 146}, + {0x4a94, 147}, + {0x4a95, 148}, + {0x4a96, 149}, + {0x4a97, 150}, + {0x4a98, 151}, + {0x4a99, 152}, + {0x4a9a, 153}, + {0x4a9b, 154}, + {0x4a9c, 155}, + {0x4a9d, 156}, + {0x4a9e, 157}, + {0x4a9f, 158}, + {0x4aa0, 159}, + {0x4aa1, 160}, + {0x4aa2, 161}, + {0x4aa3, 162}, + {0x4aa4, 163}, + {0x4aa5, 164}, + {0x4aa6, 165}, + {0x4aa7, 166}, + {0x4aa8, 167}, + {0x4aa9, 168}, + {0x4aaa, 169}, + {0x4aab, 170}, + {0x4aac, 171}, + {0x4aad, 172}, + {0x4aae, 173}, + {0x4aaf, 174}, + {0x4ab0, 175}, + {0x4ab1, 176}, + {0x4ab2, 177}, + {0x4ab3, 178}, + {0x4ab4, 179}, + {0x4ab5, 180}, + {0x4ab6, 181}, + {0x4ab7, 182}, + {0x4ab8, 183}, + {0x4ab9, 184}, + {0x4aba, 185}, + {0x4abb, 186}, + {0x4abc, 187}, + {0x4abd, 188}, + {0x4abe, 189}, + {0x4abf, 190}, + {0x4ac0, 191}, + {0x4ac1, 192}, + {0x4ac2, 193}, + {0x4ac3, 194}, + {0x4ac4, 195}, + {0x4ac5, 196}, + {0x4ac6, 197}, + {0x4ac7, 198}, + {0x4ac8, 199}, + {0x4ac9, 200}, + {0x4aca, 201}, + {0x4acb, 202}, + {0x4acc, 203}, + {0x4acd, 204}, + {0x4ace, 205}, + {0x4acf, 206}, + {0x4ad0, 207}, + {0x4ad1, 208}, + {0x4ad2, 209}, + {0x4ad3, 210}, + {0x4ad4, 211}, + {0x4ad5, 212}, + {0x4ad6, 213}, + {0x4ad7, 214}, + {0x4ad8, 215}, + {0x4ad9, 216}, + {0x4ada, 217}, + {0x4adb, 218}, + {0x4adc, 219}, + {0x4add, 220}, + {0x4ade, 221}, + {0x4adf, 222}, + {0x4ae0, 223}, + {0x4ae1, 224}, + {0x4ae2, 225}, + {0x4ae3, 226}, + {0x4ae4, 227}, + {0x4ae5, 228}, + {0x4ae6, 229}, + {0x4ae7, 230}, + {0x4ae8, 231}, + {0x4ae9, 232}, + {0x4aea, 233}, + {0x4aeb, 234}, + {0x4aec, 235}, + {0x4aed, 236}, + {0x4aee, 237}, + {0x4aef, 238}, + {0x4af0, 239}, + {0x4af1, 240}, + {0x4af2, 241}, + {0x4af3, 242}, + {0x4af4, 243}, + {0x4af5, 244}, + {0x4af6, 245}, + {0x4af7, 246}, + {0x4af8, 247}, + {0x4af9, 248}, + {0x4afa, 249}, + {0x4afb, 250}, + {0x4afc, 251}, + {0x4afd, 252}, + {0x4afe, 253}, + {0x4aff, 254}, + {0x4b01, 0}, + {0x4b02, 1}, + {0x4b03, 2}, + {0x4b04, 3}, + {0x4b05, 4}, + {0x4b06, 5}, + {0x4b07, 6}, + {0x4b08, 7}, + {0x4b09, 8}, + {0x4b0a, 9}, + {0x4b0b, 10}, + {0x4b0c, 11}, + {0x4b0d, 12}, + {0x4b0e, 13}, + {0x4b0f, 14}, + {0x4b10, 15}, + {0x4b11, 16}, + {0x4b12, 17}, + {0x4b13, 18}, + {0x4b14, 19}, + {0x4b15, 20}, + {0x4b16, 21}, + {0x4b17, 22}, + {0x4b18, 23}, + {0x4b19, 24}, + {0x4b1a, 25}, + {0x4b1b, 26}, + {0x4b1c, 27}, + {0x4b1d, 28}, + {0x4b1e, 29}, + {0x4b1f, 30}, + {0x4b20, 31}, + {0x4b21, 32}, + {0x4b22, 33}, + {0x4b23, 34}, + {0x4b24, 35}, + {0x4b25, 36}, + {0x4b26, 37}, + {0x4b27, 38}, + {0x4b28, 39}, + {0x4b29, 40}, + {0x4b2a, 41}, + {0x4b2b, 42}, + {0x4b2c, 43}, + {0x4b2d, 44}, + {0x4b2e, 45}, + {0x4b2f, 46}, + {0x4b30, 47}, + {0x4b31, 48}, + {0x4b32, 49}, + {0x4b33, 50}, + {0x4b34, 51}, + {0x4b35, 52}, + {0x4b36, 53}, + {0x4b37, 54}, + {0x4b38, 55}, + {0x4b39, 56}, + {0x4b3a, 57}, + {0x4b3b, 58}, + {0x4b3c, 59}, + {0x4b3d, 60}, + {0x4b3e, 61}, + {0x4b3f, 62}, + {0x4b40, 63}, + {0x4b41, 64}, + {0x4b42, 65}, + {0x4b43, 66}, + {0x4b44, 67}, + {0x4b45, 68}, + {0x4b46, 69}, + {0x4b47, 70}, + {0x4b48, 71}, + {0x4b49, 72}, + {0x4b4a, 73}, + {0x4b4b, 74}, + {0x4b4c, 75}, + {0x4b4d, 76}, + {0x4b4e, 77}, + {0x4b4f, 78}, + {0x4b50, 79}, + {0x4b51, 80}, + {0x4b52, 81}, + {0x4b53, 82}, + {0x4b54, 83}, + {0x4b55, 84}, + {0x4b56, 85}, + {0x4b57, 86}, + {0x4b58, 87}, + {0x4b59, 88}, + {0x4b5a, 89}, + {0x4b5b, 90}, + {0x4b5c, 91}, + {0x4b5d, 92}, + {0x4b5e, 93}, + {0x4b5f, 94}, + {0x4b60, 95}, + {0x4b61, 96}, + {0x4b62, 97}, + {0x4b63, 98}, + {0x4b64, 99}, + {0x4b65, 100}, + {0x4b66, 101}, + {0x4b67, 102}, + {0x4b68, 103}, + {0x4b69, 104}, + {0x4b6a, 105}, + {0x4b6b, 106}, + {0x4b6c, 107}, + {0x4b6d, 108}, + {0x4b6e, 109}, + {0x4b6f, 110}, + {0x4b70, 111}, + {0x4b71, 112}, + {0x4b72, 113}, + {0x4b73, 114}, + {0x4b74, 115}, + {0x4b75, 116}, + {0x4b76, 117}, + {0x4b77, 118}, + {0x4b78, 119}, + {0x4b79, 120}, + {0x4b7a, 121}, + {0x4b7b, 122}, + {0x4b7c, 123}, + {0x4b7d, 124}, + {0x4b7e, 125}, + {0x4b7f, 126}, + {0x4b80, 127}, + {0x4b81, 128}, + {0x4b82, 129}, + {0x4b83, 130}, + {0x4b84, 131}, + {0x4b85, 132}, + {0x4b86, 133}, + {0x4b87, 134}, + {0x4b88, 135}, + {0x4b89, 136}, + {0x4b8a, 137}, + {0x4b8b, 138}, + {0x4b8c, 139}, + {0x4b8d, 140}, + {0x4b8e, 141}, + {0x4b8f, 142}, + {0x4b90, 143}, + {0x4b91, 144}, + {0x4b92, 145}, + {0x4b93, 146}, + {0x4b94, 147}, + {0x4b95, 148}, + {0x4b96, 149}, + {0x4b97, 150}, + {0x4b98, 151}, + {0x4b99, 152}, + {0x4b9a, 153}, + {0x4b9b, 154}, + {0x4b9c, 155}, + {0x4b9d, 156}, + {0x4b9e, 157}, + {0x4b9f, 158}, + {0x4ba0, 159}, + {0x4ba1, 160}, + {0x4ba2, 161}, + {0x4ba3, 162}, + {0x4ba4, 163}, + {0x4ba5, 164}, + {0x4ba6, 165}, + {0x4ba7, 166}, + {0x4ba8, 167}, + {0x4ba9, 168}, + {0x4baa, 169}, + {0x4bab, 170}, + {0x4bac, 171}, + {0x4bad, 172}, + {0x4bae, 173}, + {0x4baf, 174}, + {0x4bb0, 175}, + {0x4bb1, 176}, + {0x4bb2, 177}, + {0x4bb3, 178}, + {0x4bb4, 179}, + {0x4bb5, 180}, + {0x4bb6, 181}, + {0x4bb7, 182}, + {0x4bb8, 183}, + {0x4bb9, 184}, + {0x4bba, 185}, + {0x4bbb, 186}, + {0x4bbc, 187}, + {0x4bbd, 188}, + {0x4bbe, 189}, + {0x4bbf, 190}, + {0x4bc0, 191}, + {0x4bc1, 192}, + {0x4bc2, 193}, + {0x4bc3, 194}, + {0x4bc4, 195}, + {0x4bc5, 196}, + {0x4bc6, 197}, + {0x4bc7, 198}, + {0x4bc8, 199}, + {0x4bc9, 200}, + {0x4bca, 201}, + {0x4bcb, 202}, + {0x4bcc, 203}, + {0x4bcd, 204}, + {0x4bce, 205}, + {0x4bcf, 206}, + {0x4bd0, 207}, + {0x4bd1, 208}, + {0x4bd2, 209}, + {0x4bd3, 210}, + {0x4bd4, 211}, + {0x4bd5, 212}, + {0x4bd6, 213}, + {0x4bd7, 214}, + {0x4bd8, 215}, + {0x4bd9, 216}, + {0x4bda, 217}, + {0x4bdb, 218}, + {0x4bdc, 219}, + {0x4bdd, 220}, + {0x4bde, 221}, + {0x4bdf, 222}, + {0x4be0, 223}, + {0x4be1, 224}, + {0x4be2, 225}, + {0x4be3, 226}, + {0x4be4, 227}, + {0x4be5, 228}, + {0x4be6, 229}, + {0x4be7, 230}, + {0x4be8, 231}, + {0x4be9, 232}, + {0x4bea, 233}, + {0x4beb, 234}, + {0x4bec, 235}, + {0x4bed, 236}, + {0x4bee, 237}, + {0x4bef, 238}, + {0x4bf0, 239}, + {0x4bf1, 240}, + {0x4bf2, 241}, + {0x4bf3, 242}, + {0x4bf4, 243}, + {0x4bf5, 244}, + {0x4bf6, 245}, + {0x4bf7, 246}, + {0x4bf8, 247}, + {0x4bf9, 248}, + {0x4bfa, 249}, + {0x4bfb, 250}, + {0x4bfc, 251}, + {0x4bfd, 252}, + {0x4bfe, 253}, + {0x4bff, 254}, + {0x4c01, 0}, + {0x4c02, 1}, + {0x4c03, 2}, + {0x4c04, 3}, + {0x4c05, 4}, + {0x4c06, 5}, + {0x4c07, 6}, + {0x4c08, 7}, + {0x4c09, 8}, + {0x4c0a, 9}, + {0x4c0b, 10}, + {0x4c0c, 11}, + {0x4c0d, 12}, + {0x4c0e, 13}, + {0x4c0f, 14}, + {0x4c10, 15}, + {0x4c11, 16}, + {0x4c12, 17}, + {0x4c13, 18}, + {0x4c14, 19}, + {0x4c15, 20}, + {0x4c16, 21}, + {0x4c17, 22}, + {0x4c18, 23}, + {0x4c19, 24}, + {0x4c1a, 25}, + {0x4c1b, 26}, + {0x4c1c, 27}, + {0x4c1d, 28}, + {0x4c1e, 29}, + {0x4c1f, 30}, + {0x4c20, 31}, + {0x4c21, 32}, + {0x4c22, 33}, + {0x4c23, 34}, + {0x4c24, 35}, + {0x4c25, 36}, + {0x4c26, 37}, + {0x4c27, 38}, + {0x4c28, 39}, + {0x4c29, 40}, + {0x4c2a, 41}, + {0x4c2b, 42}, + {0x4c2c, 43}, + {0x4c2d, 44}, + {0x4c2e, 45}, + {0x4c2f, 46}, + {0x4c30, 47}, + {0x4c31, 48}, + {0x4c32, 49}, + {0x4c33, 50}, + {0x4c34, 51}, + {0x4c35, 52}, + {0x4c36, 53}, + {0x4c37, 54}, + {0x4c38, 55}, + {0x4c39, 56}, + {0x4c3a, 57}, + {0x4c3b, 58}, + {0x4c3c, 59}, + {0x4c3d, 60}, + {0x4c3e, 61}, + {0x4c3f, 62}, + {0x4c40, 63}, + {0x4c41, 64}, + {0x4c42, 65}, + {0x4c43, 66}, + {0x4c44, 67}, + {0x4c45, 68}, + {0x4c46, 69}, + {0x4c47, 70}, + {0x4c48, 71}, + {0x4c49, 72}, + {0x4c4a, 73}, + {0x4c4b, 74}, + {0x4c4c, 75}, + {0x4c4d, 76}, + {0x4c4e, 77}, + {0x4c4f, 78}, + {0x4c50, 79}, + {0x4c51, 80}, + {0x4c52, 81}, + {0x4c53, 82}, + {0x4c54, 83}, + {0x4c55, 84}, + {0x4c56, 85}, + {0x4c57, 86}, + {0x4c58, 87}, + {0x4c59, 88}, + {0x4c5a, 89}, + {0x4c5b, 90}, + {0x4c5c, 91}, + {0x4c5d, 92}, + {0x4c5e, 93}, + {0x4c5f, 94}, + {0x4c60, 95}, + {0x4c61, 96}, + {0x4c62, 97}, + {0x4c63, 98}, + {0x4c64, 99}, + {0x4c65, 100}, + {0x4c66, 101}, + {0x4c67, 102}, + {0x4c68, 103}, + {0x4c69, 104}, + {0x4c6a, 105}, + {0x4c6b, 106}, + {0x4c6c, 107}, + {0x4c6d, 108}, + {0x4c6e, 109}, + {0x4c6f, 110}, + {0x4c70, 111}, + {0x4c71, 112}, + {0x4c72, 113}, + {0x4c73, 114}, + {0x4c74, 115}, + {0x4c75, 116}, + {0x4c76, 117}, + {0x4c79, 0}, + {0x4c7a, 1}, + {0x4c7b, 2}, + {0x4c7c, 3}, + {0x4c7d, 4}, + {0x4c7e, 5}, + {0x4c7f, 6}, + {0x4c80, 7}, + {0x4c81, 8}, + {0x4c82, 9}, + {0x4c83, 10}, + {0x4c84, 11}, + {0x4c85, 12}, + {0x4c86, 13}, + {0x4c87, 14}, + {0x4c88, 15}, + {0x4c89, 16}, + {0x4c8a, 17}, + {0x4c8b, 18}, + {0x4c8c, 19}, + {0x4c8d, 20}, + {0x4c8e, 21}, + {0x4c8f, 22}, + {0x4c90, 23}, + {0x4c91, 24}, + {0x4c92, 25}, + {0x4c93, 26}, + {0x4c94, 27}, + {0x4c95, 28}, + {0x4c96, 29}, + {0x4c97, 30}, + {0x4c98, 31}, + {0x4c99, 32}, + {0x4c9a, 33}, + {0x4c9b, 34}, + {0x4c9c, 35}, + {0x4c9d, 36}, + {0x4c9e, 37}, + {0x4ca0, 0}, + {0x4ca1, 1}, + {0x4ca5, 0}, + {0x4ca6, 1}, + {0x4ca7, 2}, + {0x4ca8, 3}, + {0x4ca9, 4}, + {0x4caa, 5}, + {0x4cab, 6}, + {0x4cac, 7}, + {0x4cad, 8}, + {0x4cae, 9}, + {0x4caf, 10}, + {0x4cb0, 11}, + {0x4cb1, 12}, + {0x4cb2, 13}, + {0x4cb3, 14}, + {0x4cb4, 15}, + {0x4cb5, 16}, + {0x4cb6, 17}, + {0x4cb7, 18}, + {0x4cb8, 19}, + {0x4cb9, 20}, + {0x4cba, 21}, + {0x4cbb, 22}, + {0x4cbc, 23}, + {0x4cbd, 24}, + {0x4cbe, 25}, + {0x4cbf, 26}, + {0x4cc0, 27}, + {0x4cc1, 28}, + {0x4cc2, 29}, + {0x4cc3, 30}, + {0x4cc4, 31}, + {0x4cc5, 32}, + {0x4cc6, 33}, + {0x4cc7, 34}, + {0x4cc8, 35}, + {0x4cc9, 36}, + {0x4cca, 37}, + {0x4ccb, 38}, + {0x4ccc, 39}, + {0x4ccd, 40}, + {0x4cce, 41}, + {0x4ccf, 42}, + {0x4cd0, 43}, + {0x4cd1, 44}, + {0x4cd2, 45}, + {0x4cd3, 46}, + {0x4cd4, 47}, + {0x4cd5, 48}, + {0x4cd6, 49}, + {0x4cd7, 50}, + {0x4cd8, 51}, + {0x4cd9, 52}, + {0x4cda, 53}, + {0x4cdb, 54}, + {0x4cdc, 55}, + {0x4cdd, 56}, + {0x4cde, 57}, + {0x4cdf, 58}, + {0x4ce0, 59}, + {0x4ce1, 60}, + {0x4ce2, 61}, + {0x4ce3, 62}, + {0x4ce4, 63}, + {0x4ce5, 64}, + {0x4ce6, 65}, + {0x4ce7, 66}, + {0x4ce8, 67}, + {0x4ce9, 68}, + {0x4cea, 69}, + {0x4ceb, 70}, + {0x4cec, 71}, + {0x4ced, 72}, + {0x4cee, 73}, + {0x4cef, 74}, + {0x4cf0, 75}, + {0x4cf1, 76}, + {0x4cf2, 77}, + {0x4cf3, 78}, + {0x4cf4, 79}, + {0x4cf5, 80}, + {0x4cf6, 81}, + {0x4cf7, 82}, + {0x4cf8, 83}, + {0x4cf9, 84}, + {0x4cfa, 85}, + {0x4cfb, 86}, + {0x4cfc, 87}, + {0x4cfd, 88}, + {0x4cfe, 89}, + {0x4cff, 90}, + {0x4d01, 0}, + {0x4d02, 1}, + {0x4d03, 2}, + {0x4d04, 3}, + {0x4d05, 4}, + {0x4d06, 5}, + {0x4d07, 6}, + {0x4d08, 7}, + {0x4d09, 8}, + {0x4d0a, 9}, + {0x4d0b, 10}, + {0x4d0c, 11}, + {0x4d0d, 12}, + {0x4d0e, 13}, + {0x4d0f, 14}, + {0x4d10, 15}, + {0x4d11, 16}, + {0x4d12, 17}, + {0x4d14, 0}, + {0x4d15, 1}, + {0x4d16, 2}, + {0x4d17, 3}, + {0x4d18, 4}, + {0x4d19, 5}, + {0x4d1b, 0}, + {0x4d1c, 1}, + {0x4d1d, 2}, + {0x4d1e, 3}, + {0x4d1f, 4}, + {0x4d20, 5}, + {0x4d21, 6}, + {0x4d22, 7}, + {0x4d23, 8}, + {0x4d24, 9}, + {0x4d25, 10}, + {0x4d26, 11}, + {0x4d27, 12}, + {0x4d28, 13}, + {0x4d29, 14}, + {0x4d2a, 15}, + {0x4d2b, 16}, + {0x4d2c, 17}, + {0x4d2d, 18}, + {0x4d2e, 19}, + {0x4d2f, 20}, + {0x4d30, 21}, + {0x4d31, 22}, + {0x4d32, 23}, + {0x4d33, 24}, + {0x4d34, 25}, + {0x4d35, 26}, + {0x4d36, 27}, + {0x4d37, 28}, + {0x4d38, 29}, + {0x4d39, 30}, + {0x4d3a, 31}, + {0x4d3b, 32}, + {0x4d3c, 33}, + {0x4d3d, 34}, + {0x4d3e, 35}, + {0x4d3f, 36}, + {0x4d40, 37}, + {0x4d41, 38}, + {0x4d42, 39}, + {0x4d43, 40}, + {0x4d44, 41}, + {0x4d45, 42}, + {0x4d46, 43}, + {0x4d47, 44}, + {0x4d48, 45}, + {0x4d49, 46}, + {0x4d4a, 47}, + {0x4d4b, 48}, + {0x4d4c, 49}, + {0x4d4d, 50}, + {0x4d4e, 51}, + {0x4d4f, 52}, + {0x4d50, 53}, + {0x4d51, 54}, + {0x4d52, 55}, + {0x4d53, 56}, + {0x4d54, 57}, + {0x4d55, 58}, + {0x4d56, 59}, + {0x4d57, 60}, + {0x4d58, 61}, + {0x4d59, 62}, + {0x4d5a, 63}, + {0x4d5b, 64}, + {0x4d5c, 65}, + {0x4d5d, 66}, + {0x4d5e, 67}, + {0x4d5f, 68}, + {0x4d60, 69}, + {0x4d61, 70}, + {0x4d62, 71}, + {0x4d63, 72}, + {0x4d64, 73}, + {0x4d65, 74}, + {0x4d66, 75}, + {0x4d67, 76}, + {0x4d68, 77}, + {0x4d69, 78}, + {0x4d6a, 79}, + {0x4d6b, 80}, + {0x4d6c, 81}, + {0x4d6d, 82}, + {0x4d6e, 83}, + {0x4d6f, 84}, + {0x4d70, 85}, + {0x4d71, 86}, + {0x4d72, 87}, + {0x4d73, 88}, + {0x4d74, 89}, + {0x4d75, 90}, + {0x4d76, 91}, + {0x4d77, 92}, + {0x4d78, 93}, + {0x4d79, 94}, + {0x4d7a, 95}, + {0x4d7b, 96}, + {0x4d7c, 97}, + {0x4d7d, 98}, + {0x4d7e, 99}, + {0x4d7f, 100}, + {0x4d80, 101}, + {0x4d81, 102}, + {0x4d82, 103}, + {0x4d83, 104}, + {0x4d84, 105}, + {0x4d85, 106}, + {0x4d86, 107}, + {0x4d87, 108}, + {0x4d88, 109}, + {0x4d89, 110}, + {0x4d8a, 111}, + {0x4d8b, 112}, + {0x4d8c, 113}, + {0x4d8d, 114}, + {0x4d8e, 115}, + {0x4d8f, 116}, + {0x4d90, 117}, + {0x4d91, 118}, + {0x4d92, 119}, + {0x4d93, 120}, + {0x4d94, 121}, + {0x4d95, 122}, + {0x4d96, 123}, + {0x4d97, 124}, + {0x4d98, 125}, + {0x4d99, 126}, + {0x4d9a, 127}, + {0x4d9b, 128}, + {0x4d9c, 129}, + {0x4d9d, 130}, + {0x4d9e, 131}, + {0x4d9f, 132}, + {0x4da0, 133}, + {0x4da1, 134}, + {0x4da2, 135}, + {0x4da3, 136}, + {0x4da4, 137}, + {0x4da5, 138}, + {0x4da6, 139}, + {0x4da7, 140}, + {0x4da8, 141}, + {0x4da9, 142}, + {0x4daa, 143}, + {0x4dab, 144}, + {0x4dac, 145}, + {0x4dad, 146}, + {0x4db0, 0}, + {0x4db1, 1}, + {0x4db2, 2}, + {0x4db3, 3}, + {0x4db4, 4}, + {0x4db5, 5}, + {0x4e00, 4162}, + {0x4e01, 1504}, + {0x4e03, 3070}, + {0x4e05, 0}, + {0x4e06, 1}, + {0x4e07, 3747}, + {0x4e08, 4458}, + {0x4e09, 3288}, + {0x4e0a, 3336}, + {0x4e0b, 3887}, + {0x4e0c, 4696}, + {0x4e0d, 1154}, + {0x4e0e, 4304}, + {0x4e10, 4698}, + {0x4e11, 1304}, + {0x4e13, 4613}, + {0x4e14, 3151}, + {0x4e15, 4701}, + {0x4e16, 3415}, + {0x4e18, 3181}, + {0x4e19, 1124}, + {0x4e1a, 4156}, + {0x4e1b, 1367}, + {0x4e1c, 1514}, + {0x4e1d, 3508}, + {0x4e1e, 4703}, + {0x4e20, 0}, + {0x4e21, 1}, + {0x4e22, 1513}, + {0x4e24, 2566}, + {0x4e25, 4088}, + {0x4e27, 3294}, + {0x4e28, 4707}, + {0x4e2a, 1777}, + {0x4e2b, 4071}, + {0x4e2c, 5788}, + {0x4e2d, 4559}, + {0x4e2f, 0}, + {0x4e30, 1662}, + {0x4e32, 1329}, + {0x4e34, 2594}, + {0x4e36, 4722}, + {0x4e38, 3737}, + {0x4e39, 1413}, + {0x4e3a, 3769}, + {0x4e3b, 4598}, + {0x4e3d, 2529}, + {0x4e3e, 2312}, + {0x4e3f, 4709}, + {0x4e41, 0}, + {0x4e42, 1}, + {0x4e43, 2862}, + {0x4e45, 2290}, + {0x4e47, 4711}, + {0x4e48, 2745}, + {0x4e49, 4204}, + {0x4e4b, 4525}, + {0x4e4c, 3817}, + {0x4e4d, 4424}, + {0x4e4e, 1964}, + {0x4e4f, 1603}, + {0x4e50, 2497}, + {0x4e52, 3032}, + {0x4e53, 2963}, + {0x4e54, 3140}, + {0x4e56, 1837}, + {0x4e58, 1264}, + {0x4e59, 4185}, + {0x4e5b, 0}, + {0x4e5c, 4725}, + {0x4e5d, 2292}, + {0x4e5e, 3089}, + {0x4e5f, 4153}, + {0x4e60, 3869}, + {0x4e61, 3924}, + {0x4e63, 0}, + {0x4e64, 1}, + {0x4e65, 2}, + {0x4e66, 3456}, + {0x4e68, 0}, + {0x4e69, 4726}, + {0x4e6b, 0}, + {0x4e6c, 1}, + {0x4e6d, 2}, + {0x4e6e, 3}, + {0x4e6f, 4}, + {0x4e70, 2713}, + {0x4e71, 2681}, + {0x4e73, 3268}, + {0x4e75, 0}, + {0x4e76, 1}, + {0x4e77, 2}, + {0x4e78, 3}, + {0x4e79, 4}, + {0x4e7a, 5}, + {0x4e7b, 6}, + {0x4e7c, 7}, + {0x4e7d, 8}, + {0x4e7e, 3113}, + {0x4e80, 0}, + {0x4e81, 1}, + {0x4e82, 8281}, + {0x4e84, 0}, + {0x4e85, 1}, + {0x4e86, 2580}, + {0x4e88, 4301}, + {0x4e89, 4506}, + {0x4e8b, 3417}, + {0x4e8c, 1597}, + {0x4e8d, 4695}, + {0x4e8e, 4287}, + {0x4e8f, 2436}, + {0x4e91, 4361}, + {0x4e92, 1978}, + {0x4e93, 4727}, + {0x4e94, 3828}, + {0x4e95, 2269}, + {0x4e97, 0}, + {0x4e98, 4702}, + {0x4e9a, 4080}, + {0x4e9b, 3956}, + {0x4e9d, 0}, + {0x4e9e, 8689}, + {0x4e9f, 4723}, + {0x4ea0, 4867}, + {0x4ea1, 3751}, + {0x4ea2, 2375}, + {0x4ea4, 2188}, + {0x4ea5, 1884}, + {0x4ea6, 4199}, + {0x4ea7, 1217}, + {0x4ea8, 1943}, + {0x4ea9, 2841}, + {0x4eab, 3930}, + {0x4eac, 2264}, + {0x4ead, 3669}, + {0x4eae, 2570}, + {0x4eb0, 0}, + {0x4eb1, 1}, + {0x4eb2, 3156}, + {0x4eb3, 4869}, + {0x4eb5, 4872}, + {0x4eb7, 0}, + {0x4eb8, 1}, + {0x4eb9, 2}, + {0x4eba, 3238}, + {0x4ebb, 4767}, + {0x4ebd, 0}, + {0x4ebe, 1}, + {0x4ebf, 4193}, + {0x4ec0, 3401}, + {0x4ec1, 3237}, + {0x4ec2, 4770}, + {0x4ec3, 4768}, + {0x4ec4, 4732}, + {0x4ec5, 2247}, + {0x4ec6, 3052}, + {0x4ec7, 1301}, + {0x4ec9, 4769}, + {0x4eca, 2242}, + {0x4ecb, 2234}, + {0x4ecd, 3247}, + {0x4ece, 1366}, + {0x4ed0, 0}, + {0x4ed1, 2687}, + {0x4ed3, 1181}, + {0x4ed4, 4653}, + {0x4ed5, 3426}, + {0x4ed6, 3568}, + {0x4ed7, 4461}, + {0x4ed8, 1713}, + {0x4ed9, 3894}, + {0x4edb, 0}, + {0x4edc, 1}, + {0x4edd, 4846}, + {0x4ede, 4774}, + {0x4edf, 3111}, + {0x4ee1, 4772}, + {0x4ee3, 1405}, + {0x4ee4, 2615}, + {0x4ee5, 4187}, + {0x4ee7, 0}, + {0x4ee8, 4771}, + {0x4eea, 4174}, + {0x4eeb, 4773}, + {0x4eec, 2764}, + {0x4eee, 0}, + {0x4eef, 1}, + {0x4ef0, 4127}, + {0x4ef2, 4568}, + {0x4ef3, 4776}, + {0x4ef5, 4779}, + {0x4ef6, 2161}, + {0x4ef7, 2126}, + {0x4ef9, 0}, + {0x4efa, 1}, + {0x4efb, 3241}, + {0x4efd, 1658}, + {0x4eff, 1631}, + {0x4f01, 3090}, + {0x4f03, 0}, + {0x4f04, 1}, + {0x4f05, 2}, + {0x4f06, 3}, + {0x4f07, 4}, + {0x4f08, 5}, + {0x4f09, 4782}, + {0x4f0a, 4168}, + {0x4f0c, 0}, + {0x4f0d, 3832}, + {0x4f0e, 2098}, + {0x4f0f, 1689}, + {0x4f10, 1602}, + {0x4f11, 4008}, + {0x4f13, 0}, + {0x4f14, 1}, + {0x4f15, 2}, + {0x4f16, 3}, + {0x4f17, 4569}, + {0x4f18, 4266}, + {0x4f19, 2052}, + {0x4f1a, 2038}, + {0x4f1b, 4775}, + {0x4f1d, 0}, + {0x4f1e, 3290}, + {0x4f1f, 3775}, + {0x4f20, 1326}, + {0x4f22, 4777}, + {0x4f24, 3332}, + {0x4f25, 4780}, + {0x4f26, 2686}, + {0x4f27, 4781}, + {0x4f29, 0}, + {0x4f2a, 3776}, + {0x4f2b, 4783}, + {0x4f2d, 0}, + {0x4f2e, 1}, + {0x4f2f, 1141}, + {0x4f30, 1817}, + {0x4f32, 4791}, + {0x4f34, 1012}, + {0x4f36, 2607}, + {0x4f38, 3365}, + {0x4f3a, 3514}, + {0x4f3c, 3515}, + {0x4f3d, 4792}, + {0x4f3f, 0}, + {0x4f40, 1}, + {0x4f41, 2}, + {0x4f42, 3}, + {0x4f43, 1481}, + {0x4f45, 0}, + {0x4f46, 1420}, + {0x4f48, 0}, + {0x4f49, 1}, + {0x4f4a, 2}, + {0x4f4b, 3}, + {0x4f4c, 4}, + {0x4f4d, 3786}, + {0x4f4e, 1454}, + {0x4f4f, 4606}, + {0x4f50, 4689}, + {0x4f51, 4280}, + {0x4f53, 3640}, + {0x4f55, 1925}, + {0x4f57, 4790}, + {0x4f58, 4848}, + {0x4f59, 4293}, + {0x4f5a, 4787}, + {0x4f5b, 1677}, + {0x4f5c, 4692}, + {0x4f5d, 4788}, + {0x4f5e, 4784}, + {0x4f5f, 4789}, + {0x4f60, 2886}, + {0x4f62, 0}, + {0x4f63, 4251}, + {0x4f64, 4778}, + {0x4f65, 4849}, + {0x4f67, 4785}, + {0x4f69, 2982}, + {0x4f6b, 0}, + {0x4f6c, 2491}, + {0x4f6e, 0}, + {0x4f6f, 4121}, + {0x4f70, 998}, + {0x4f72, 0}, + {0x4f73, 2116}, + {0x4f74, 4794}, + {0x4f76, 4793}, + {0x4f78, 0}, + {0x4f79, 1}, + {0x4f7a, 2}, + {0x4f7b, 4800}, + {0x4f7c, 4802}, + {0x4f7e, 4799}, + {0x4f7f, 3408}, + {0x4f81, 0}, + {0x4f82, 1}, + {0x4f83, 4797}, + {0x4f84, 4533}, + {0x4f86, 8178}, + {0x4f88, 1283}, + {0x4f89, 4796}, + {0x4f8b, 2536}, + {0x4f8d, 3427}, + {0x4f8f, 4798}, + {0x4f91, 4795}, + {0x4f93, 0}, + {0x4f94, 4804}, + {0x4f96, 8285}, + {0x4f97, 1520}, + {0x4f99, 0}, + {0x4f9a, 1}, + {0x4f9b, 1794}, + {0x4f9d, 4167}, + {0x4f9f, 0}, + {0x4fa0, 3885}, + {0x4fa2, 0}, + {0x4fa3, 2665}, + {0x4fa5, 2197}, + {0x4fa6, 4493}, + {0x4fa7, 1191}, + {0x4fa8, 3141}, + {0x4fa9, 2424}, + {0x4faa, 4801}, + {0x4fac, 4803}, + {0x4fae, 3833}, + {0x4faf, 1957}, + {0x4fb1, 0}, + {0x4fb2, 1}, + {0x4fb3, 2}, + {0x4fb4, 3}, + {0x4fb5, 3155}, + {0x4fb7, 0}, + {0x4fb8, 1}, + {0x4fb9, 2}, + {0x4fba, 3}, + {0x4fbb, 4}, + {0x4fbc, 5}, + {0x4fbd, 6}, + {0x4fbe, 7}, + {0x4fbf, 1100}, + {0x4fc1, 0}, + {0x4fc2, 9884}, + {0x4fc3, 1372}, + {0x4fc4, 1580}, + {0x4fc5, 4808}, + {0x4fc7, 0}, + {0x4fc8, 1}, + {0x4fc9, 2}, + {0x4fca, 2350}, + {0x4fcc, 0}, + {0x4fcd, 1}, + {0x4fce, 4850}, + {0x4fcf, 3147}, + {0x4fd0, 2537}, + {0x4fd1, 4812}, + {0x4fd3, 0}, + {0x4fd4, 1}, + {0x4fd5, 2}, + {0x4fd6, 3}, + {0x4fd7, 3532}, + {0x4fd8, 1690}, + {0x4fda, 4809}, + {0x4fdc, 4811}, + {0x4fdd, 1036}, + {0x4fde, 4294}, + {0x4fdf, 4813}, + {0x4fe0, 8629}, + {0x4fe1, 3984}, + {0x4fe3, 4810}, + {0x4fe5, 0}, + {0x4fe6, 4805}, + {0x4fe8, 4806}, + {0x4fe9, 2546}, + {0x4fea, 4807}, + {0x4fec, 0}, + {0x4fed, 2150}, + {0x4fee, 4009}, + {0x4fef, 1700}, + {0x4ff1, 2322}, + {0x4ff3, 4817}, + {0x4ff5, 0}, + {0x4ff6, 1}, + {0x4ff7, 2}, + {0x4ff8, 4814}, + {0x4ffa, 958}, + {0x4ffc, 0}, + {0x4ffd, 1}, + {0x4ffe, 4822}, + {0x5000, 8908}, + {0x5002, 0}, + {0x5003, 1}, + {0x5004, 2}, + {0x5005, 3}, + {0x5006, 8214}, + {0x5008, 0}, + {0x5009, 7778}, + {0x500b, 7968}, + {0x500c, 4824}, + {0x500d, 1055}, + {0x500f, 4819}, + {0x5011, 8319}, + {0x5012, 1434}, + {0x5014, 2338}, + {0x5016, 0}, + {0x5017, 1}, + {0x5018, 3611}, + {0x5019, 1961}, + {0x501a, 4183}, + {0x501c, 4823}, + {0x501e, 0}, + {0x501f, 2233}, + {0x5021, 1232}, + {0x5023, 0}, + {0x5024, 1}, + {0x5025, 4825}, + {0x5026, 2330}, + {0x5028, 4826}, + {0x5029, 4815}, + {0x502a, 2882}, + {0x502b, 8284}, + {0x502c, 4818}, + {0x502d, 4821}, + {0x502e, 4820}, + {0x5030, 0}, + {0x5031, 1}, + {0x5032, 2}, + {0x5033, 3}, + {0x5034, 4}, + {0x5035, 5}, + {0x5036, 6}, + {0x5037, 7}, + {0x5038, 8}, + {0x5039, 9}, + {0x503a, 4431}, + {0x503c, 4532}, + {0x503e, 3168}, + {0x5040, 0}, + {0x5041, 1}, + {0x5042, 2}, + {0x5043, 4828}, + {0x5045, 0}, + {0x5046, 1}, + {0x5047, 2124}, + {0x5048, 4830}, + {0x5049, 8596}, + {0x504b, 0}, + {0x504c, 4816}, + {0x504e, 4831}, + {0x504f, 3018}, + {0x5051, 0}, + {0x5052, 1}, + {0x5053, 2}, + {0x5054, 3}, + {0x5055, 4829}, + {0x5057, 0}, + {0x5058, 1}, + {0x5059, 2}, + {0x505a, 4691}, + {0x505c, 3668}, + {0x505e, 0}, + {0x505f, 1}, + {0x5060, 2}, + {0x5061, 3}, + {0x5062, 4}, + {0x5063, 5}, + {0x5064, 6}, + {0x5065, 2162}, + {0x5067, 0}, + {0x5068, 1}, + {0x5069, 2}, + {0x506a, 3}, + {0x506b, 4}, + {0x506c, 4832}, + {0x506e, 0}, + {0x506f, 1}, + {0x5070, 2}, + {0x5071, 3}, + {0x5072, 4}, + {0x5073, 5}, + {0x5074, 7781}, + {0x5075, 8833}, + {0x5076, 2941}, + {0x5077, 3686}, + {0x5079, 0}, + {0x507a, 1}, + {0x507b, 4833}, + {0x507d, 0}, + {0x507e, 4827}, + {0x507f, 1226}, + {0x5080, 2443}, + {0x5082, 0}, + {0x5083, 1}, + {0x5084, 2}, + {0x5085, 1712}, + {0x5087, 0}, + {0x5088, 2535}, + {0x508a, 0}, + {0x508b, 1}, + {0x508c, 2}, + {0x508d, 1027}, + {0x508f, 0}, + {0x5090, 1}, + {0x5091, 2}, + {0x5092, 3}, + {0x5093, 4}, + {0x5094, 5}, + {0x5095, 6}, + {0x5096, 8909}, + {0x5098, 8458}, + {0x5099, 7742}, + {0x509b, 0}, + {0x509c, 1}, + {0x509d, 2}, + {0x509e, 3}, + {0x509f, 4}, + {0x50a0, 5}, + {0x50a1, 6}, + {0x50a2, 9855}, + {0x50a3, 1401}, + {0x50a5, 4834}, + {0x50a7, 4835}, + {0x50a8, 1317}, + {0x50a9, 4836}, + {0x50ab, 0}, + {0x50ac, 1378}, + {0x50ad, 8750}, + {0x50af, 0}, + {0x50b0, 1}, + {0x50b1, 2}, + {0x50b2, 972}, + {0x50b3, 7830}, + {0x50b4, 8907}, + {0x50b5, 8812}, + {0x50b7, 8471}, + {0x50b9, 0}, + {0x50ba, 4837}, + {0x50bb, 3310}, + {0x50bd, 0}, + {0x50be, 8424}, + {0x50c0, 0}, + {0x50c1, 1}, + {0x50c2, 8916}, + {0x50c4, 0}, + {0x50c5, 8121}, + {0x50c7, 0}, + {0x50c8, 1}, + {0x50c9, 8920}, + {0x50cb, 0}, + {0x50cc, 1}, + {0x50cd, 2}, + {0x50ce, 3}, + {0x50cf, 3934}, + {0x50d1, 8415}, + {0x50d3, 0}, + {0x50d4, 1}, + {0x50d5, 8386}, + {0x50d6, 4838}, + {0x50d8, 0}, + {0x50d9, 1}, + {0x50da, 2574}, + {0x50dc, 0}, + {0x50dd, 1}, + {0x50de, 8597}, + {0x50e0, 0}, + {0x50e1, 1}, + {0x50e2, 2}, + {0x50e3, 3}, + {0x50e4, 4}, + {0x50e5, 8108}, + {0x50e6, 4842}, + {0x50e7, 3303}, + {0x50e8, 8915}, + {0x50ea, 0}, + {0x50eb, 1}, + {0x50ec, 4841}, + {0x50ed, 4840}, + {0x50ee, 4843}, + {0x50f0, 0}, + {0x50f1, 1}, + {0x50f2, 2}, + {0x50f3, 3536}, + {0x50f5, 2170}, + {0x50f7, 0}, + {0x50f8, 1}, + {0x50f9, 8065}, + {0x50fb, 3014}, + {0x50fd, 0}, + {0x50fe, 1}, + {0x50ff, 2}, + {0x5100, 8720}, + {0x5102, 8911}, + {0x5104, 8723}, + {0x5106, 4839}, + {0x5107, 4844}, + {0x5108, 8164}, + {0x5109, 8080}, + {0x510b, 4845}, + {0x510d, 0}, + {0x510e, 1}, + {0x510f, 2}, + {0x5110, 8918}, + {0x5112, 3264}, + {0x5114, 8912}, + {0x5115, 8910}, + {0x5117, 0}, + {0x5118, 9857}, + {0x511a, 0}, + {0x511b, 1}, + {0x511c, 2}, + {0x511d, 3}, + {0x511e, 4}, + {0x511f, 7798}, + {0x5121, 2503}, + {0x5123, 0}, + {0x5124, 1}, + {0x5125, 2}, + {0x5126, 3}, + {0x5127, 4}, + {0x5128, 5}, + {0x5129, 6}, + {0x512a, 8753}, + {0x512c, 0}, + {0x512d, 1}, + {0x512e, 2}, + {0x512f, 3}, + {0x5130, 4}, + {0x5131, 5}, + {0x5132, 7827}, + {0x5134, 0}, + {0x5135, 1}, + {0x5136, 2}, + {0x5137, 8914}, + {0x5139, 0}, + {0x513a, 8919}, + {0x513b, 8917}, + {0x513c, 8913}, + {0x513e, 0}, + {0x513f, 1592}, + {0x5140, 4697}, + {0x5141, 4365}, + {0x5143, 4333}, + {0x5144, 4001}, + {0x5145, 1289}, + {0x5146, 4472}, + {0x5148, 3893}, + {0x5149, 1851}, + {0x514b, 2392}, + {0x514d, 2791}, + {0x514f, 0}, + {0x5150, 1}, + {0x5151, 1553}, + {0x5152, 7909}, + {0x5154, 3700}, + {0x5155, 4866}, + {0x5156, 4868}, + {0x5158, 0}, + {0x5159, 1}, + {0x515a, 1428}, + {0x515c, 1524}, + {0x515e, 0}, + {0x515f, 1}, + {0x5160, 2}, + {0x5161, 3}, + {0x5162, 2259}, + {0x5164, 0}, + {0x5165, 3270}, + {0x5167, 0}, + {0x5168, 3206}, + {0x5169, 8229}, + {0x516b, 982}, + {0x516c, 1796}, + {0x516d, 2626}, + {0x516e, 4854}, + {0x5170, 2471}, + {0x5171, 1803}, + {0x5173, 1841}, + {0x5174, 3990}, + {0x5175, 1121}, + {0x5176, 3075}, + {0x5177, 2318}, + {0x5178, 1477}, + {0x5179, 4645}, + {0x517b, 4129}, + {0x517c, 2137}, + {0x517d, 3445}, + {0x517f, 0}, + {0x5180, 2096}, + {0x5181, 4858}, + {0x5182, 4765}, + {0x5184, 0}, + {0x5185, 2877}, + {0x5187, 0}, + {0x5188, 1743}, + {0x5189, 3224}, + {0x518b, 0}, + {0x518c, 1192}, + {0x518d, 4380}, + {0x518f, 0}, + {0x5190, 1}, + {0x5191, 2}, + {0x5192, 2741}, + {0x5194, 0}, + {0x5195, 2790}, + {0x5196, 4884}, + {0x5197, 3258}, + {0x5199, 3967}, + {0x519b, 2347}, + {0x519c, 2922}, + {0x519e, 0}, + {0x519f, 1}, + {0x51a0, 1843}, + {0x51a2, 4885}, + {0x51a4, 4332}, + {0x51a5, 4886}, + {0x51a7, 0}, + {0x51a8, 1}, + {0x51a9, 2}, + {0x51aa, 3}, + {0x51ab, 4879}, + {0x51ac, 1515}, + {0x51ae, 0}, + {0x51af, 1672}, + {0x51b0, 1122}, + {0x51b1, 4880}, + {0x51b2, 1290}, + {0x51b3, 2341}, + {0x51b5, 2435}, + {0x51b6, 4152}, + {0x51b7, 2511}, + {0x51b9, 0}, + {0x51ba, 1}, + {0x51bb, 1522}, + {0x51bc, 4882}, + {0x51bd, 4881}, + {0x51bf, 0}, + {0x51c0, 2282}, + {0x51c2, 0}, + {0x51c3, 1}, + {0x51c4, 3071}, + {0x51c6, 4633}, + {0x51c7, 4883}, + {0x51c9, 2562}, + {0x51cb, 1491}, + {0x51cc, 2609}, + {0x51cd, 7887}, + {0x51cf, 2152}, + {0x51d1, 1368}, + {0x51d3, 0}, + {0x51d4, 1}, + {0x51d5, 2}, + {0x51d6, 3}, + {0x51d7, 4}, + {0x51d8, 5}, + {0x51d9, 6}, + {0x51da, 7}, + {0x51db, 2598}, + {0x51dd, 2912}, + {0x51df, 0}, + {0x51e0, 2091}, + {0x51e1, 1615}, + {0x51e3, 0}, + {0x51e4, 1676}, + {0x51e6, 0}, + {0x51e7, 1}, + {0x51e8, 2}, + {0x51e9, 3}, + {0x51ea, 4}, + {0x51eb, 4864}, + {0x51ed, 3037}, + {0x51ef, 2362}, + {0x51f0, 2016}, + {0x51f1, 8153}, + {0x51f3, 1451}, + {0x51f5, 5017}, + {0x51f6, 4002}, + {0x51f8, 3690}, + {0x51f9, 967}, + {0x51fa, 1307}, + {0x51fb, 2060}, + {0x51fc, 5018}, + {0x51fd, 1894}, + {0x51ff, 4391}, + {0x5200, 1431}, + {0x5201, 1492}, + {0x5202, 4748}, + {0x5203, 3243}, + {0x5205, 0}, + {0x5206, 1651}, + {0x5207, 3149}, + {0x5208, 4749}, + {0x520a, 2364}, + {0x520c, 0}, + {0x520d, 5003}, + {0x520e, 4750}, + {0x5210, 0}, + {0x5211, 3991}, + {0x5212, 1987}, + {0x5214, 0}, + {0x5215, 1}, + {0x5216, 6510}, + {0x5217, 2585}, + {0x5218, 2622}, + {0x5219, 4405}, + {0x521a, 1744}, + {0x521b, 1335}, + {0x521d, 1306}, + {0x521f, 0}, + {0x5220, 3319}, + {0x5222, 0}, + {0x5223, 1}, + {0x5224, 2961}, + {0x5226, 0}, + {0x5227, 1}, + {0x5228, 2970}, + {0x5229, 2534}, + {0x522b, 1113}, + {0x522d, 4751}, + {0x522e, 1831}, + {0x5230, 1438}, + {0x5232, 0}, + {0x5233, 4752}, + {0x5235, 0}, + {0x5236, 4549}, + {0x5237, 3479}, + {0x5238, 3210}, + {0x5239, 3307}, + {0x523a, 1359}, + {0x523b, 2393}, + {0x523d, 1869}, + {0x523f, 4753}, + {0x5240, 4754}, + {0x5241, 1574}, + {0x5242, 2100}, + {0x5243, 3645}, + {0x5244, 8904}, + {0x5246, 0}, + {0x5247, 8803}, + {0x5249, 0}, + {0x524a, 3940}, + {0x524b, 9859}, + {0x524c, 4755}, + {0x524d, 3117}, + {0x524f, 0}, + {0x5250, 1833}, + {0x5251, 2164}, + {0x5253, 0}, + {0x5254, 3633}, + {0x5256, 3049}, + {0x5258, 0}, + {0x5259, 1}, + {0x525a, 2}, + {0x525b, 7959}, + {0x525c, 4758}, + {0x525e, 4756}, + {0x5260, 0}, + {0x5261, 4757}, + {0x5263, 0}, + {0x5264, 1}, + {0x5265, 1033}, + {0x5267, 2326}, + {0x5269, 3386}, + {0x526a, 2151}, + {0x526c, 0}, + {0x526d, 1}, + {0x526e, 7979}, + {0x526f, 1708}, + {0x5271, 0}, + {0x5272, 1769}, + {0x5274, 8906}, + {0x5275, 7833}, + {0x5277, 0}, + {0x5278, 1}, + {0x5279, 2}, + {0x527a, 3}, + {0x527b, 4}, + {0x527c, 5}, + {0x527d, 4760}, + {0x527f, 2204}, + {0x5281, 4762}, + {0x5282, 4761}, + {0x5283, 8015}, + {0x5285, 0}, + {0x5286, 1}, + {0x5287, 8143}, + {0x5288, 3005}, + {0x5289, 8246}, + {0x528a, 7994}, + {0x528c, 8905}, + {0x528d, 8089}, + {0x528f, 0}, + {0x5290, 4763}, + {0x5291, 8053}, + {0x5293, 4764}, + {0x5295, 0}, + {0x5296, 1}, + {0x5297, 2}, + {0x5298, 3}, + {0x5299, 4}, + {0x529a, 5}, + {0x529b, 2543}, + {0x529d, 3211}, + {0x529e, 1015}, + {0x529f, 1791}, + {0x52a0, 2118}, + {0x52a1, 3840}, + {0x52a2, 5005}, + {0x52a3, 2588}, + {0x52a5, 0}, + {0x52a6, 1}, + {0x52a7, 2}, + {0x52a8, 1518}, + {0x52a9, 4601}, + {0x52aa, 2925}, + {0x52ab, 2218}, + {0x52ac, 5006}, + {0x52ad, 5007}, + {0x52af, 0}, + {0x52b0, 1}, + {0x52b1, 2531}, + {0x52b2, 2257}, + {0x52b3, 2488}, + {0x52b5, 0}, + {0x52b6, 1}, + {0x52b7, 2}, + {0x52b8, 3}, + {0x52b9, 4}, + {0x52ba, 5}, + {0x52bb, 6}, + {0x52bc, 7}, + {0x52bd, 8}, + {0x52be, 5008}, + {0x52bf, 3421}, + {0x52c1, 8126}, + {0x52c3, 1137}, + {0x52c5, 0}, + {0x52c6, 1}, + {0x52c7, 4263}, + {0x52c9, 2792}, + {0x52cb, 4052}, + {0x52cd, 0}, + {0x52ce, 1}, + {0x52cf, 2}, + {0x52d0, 5010}, + {0x52d2, 2496}, + {0x52d4, 0}, + {0x52d5, 7885}, + {0x52d6, 5011}, + {0x52d8, 2366}, + {0x52d9, 8617}, + {0x52db, 8678}, + {0x52dd, 8487}, + {0x52de, 8195}, + {0x52df, 2847}, + {0x52e1, 0}, + {0x52e2, 8498}, + {0x52e4, 3159}, + {0x52e6, 0}, + {0x52e7, 1}, + {0x52e8, 2}, + {0x52e9, 3}, + {0x52ea, 4}, + {0x52eb, 5}, + {0x52ec, 6}, + {0x52ed, 7}, + {0x52ee, 8}, + {0x52ef, 9}, + {0x52f0, 5012}, + {0x52f1, 8995}, + {0x52f3, 0}, + {0x52f4, 1}, + {0x52f5, 8209}, + {0x52f7, 0}, + {0x52f8, 8437}, + {0x52f9, 4860}, + {0x52fa, 3344}, + {0x52fc, 0}, + {0x52fd, 1}, + {0x52fe, 1805}, + {0x52ff, 3839}, + {0x5300, 4363}, + {0x5302, 0}, + {0x5303, 1}, + {0x5304, 2}, + {0x5305, 1031}, + {0x5306, 1365}, + {0x5308, 4004}, + {0x530a, 0}, + {0x530b, 1}, + {0x530c, 2}, + {0x530d, 4861}, + {0x530f, 5301}, + {0x5310, 4863}, + {0x5312, 0}, + {0x5313, 1}, + {0x5314, 2}, + {0x5315, 4710}, + {0x5316, 1988}, + {0x5317, 1050}, + {0x5319, 1276}, + {0x531a, 4740}, + {0x531c, 0}, + {0x531d, 4372}, + {0x531f, 0}, + {0x5320, 2180}, + {0x5321, 2428}, + {0x5323, 3880}, + {0x5325, 0}, + {0x5326, 4742}, + {0x5328, 0}, + {0x5329, 1}, + {0x532a, 1640}, + {0x532c, 0}, + {0x532d, 8901}, + {0x532e, 4743}, + {0x532f, 8030}, + {0x5331, 8902}, + {0x5333, 0}, + {0x5334, 1}, + {0x5335, 2}, + {0x5336, 3}, + {0x5337, 4}, + {0x5338, 5}, + {0x5339, 3012}, + {0x533a, 3189}, + {0x533b, 4164}, + {0x533d, 0}, + {0x533e, 4744}, + {0x533f, 2887}, + {0x5340, 8431}, + {0x5341, 3397}, + {0x5343, 3108}, + {0x5345, 4700}, + {0x5347, 3382}, + {0x5348, 3830}, + {0x5349, 2033}, + {0x534a, 1014}, + {0x534c, 0}, + {0x534d, 1}, + {0x534e, 1983}, + {0x534f, 3960}, + {0x5351, 1049}, + {0x5352, 4673}, + {0x5353, 4636}, + {0x5354, 8656}, + {0x5355, 1414}, + {0x5356, 2715}, + {0x5357, 2866}, + {0x5359, 0}, + {0x535a, 1136}, + {0x535c, 1150}, + {0x535e, 1102}, + {0x535f, 5370}, + {0x5360, 4445}, + {0x5361, 2357}, + {0x5362, 2643}, + {0x5363, 4747}, + {0x5364, 2648}, + {0x5366, 4746}, + {0x5367, 3811}, + {0x5369, 4946}, + {0x536b, 3791}, + {0x536d, 0}, + {0x536e, 4714}, + {0x536f, 2739}, + {0x5370, 4230}, + {0x5371, 3762}, + {0x5373, 2087}, + {0x5374, 3215}, + {0x5375, 2680}, + {0x5377, 2332}, + {0x5378, 3969}, + {0x537a, 4947}, + {0x537c, 0}, + {0x537d, 1}, + {0x537e, 2}, + {0x537f, 3169}, + {0x5381, 0}, + {0x5382, 1228}, + {0x5384, 1585}, + {0x5385, 3663}, + {0x5386, 2533}, + {0x5388, 0}, + {0x5389, 2530}, + {0x538b, 4066}, + {0x538c, 4106}, + {0x538d, 4733}, + {0x538f, 0}, + {0x5390, 1}, + {0x5391, 2}, + {0x5392, 3}, + {0x5393, 4}, + {0x5394, 5}, + {0x5395, 1189}, + {0x5397, 0}, + {0x5398, 2512}, + {0x5399, 8897}, + {0x539a, 1960}, + {0x539c, 0}, + {0x539d, 4734}, + {0x539f, 4336}, + {0x53a0, 7780}, + {0x53a2, 3918}, + {0x53a3, 4735}, + {0x53a5, 4736}, + {0x53a6, 3888}, + {0x53a8, 1309}, + {0x53a9, 2294}, + {0x53ab, 0}, + {0x53ac, 1}, + {0x53ad, 8697}, + {0x53ae, 4737}, + {0x53b0, 0}, + {0x53b1, 1}, + {0x53b2, 8208}, + {0x53b4, 8898}, + {0x53b6, 5020}, + {0x53b8, 0}, + {0x53b9, 1}, + {0x53ba, 2}, + {0x53bb, 3200}, + {0x53bd, 0}, + {0x53be, 1}, + {0x53bf, 3909}, + {0x53c1, 3289}, + {0x53c2, 1173}, + {0x53c3, 7770}, + {0x53c5, 0}, + {0x53c6, 1}, + {0x53c7, 2}, + {0x53c8, 4283}, + {0x53c9, 1197}, + {0x53ca, 2083}, + {0x53cb, 4278}, + {0x53cc, 3488}, + {0x53cd, 1617}, + {0x53cf, 0}, + {0x53d0, 1}, + {0x53d1, 1599}, + {0x53d3, 0}, + {0x53d4, 3452}, + {0x53d6, 3196}, + {0x53d7, 3443}, + {0x53d8, 1101}, + {0x53d9, 4027}, + {0x53db, 2962}, + {0x53dd, 0}, + {0x53de, 1}, + {0x53df, 5013}, + {0x53e0, 1503}, + {0x53e2, 7842}, + {0x53e3, 2407}, + {0x53e4, 1822}, + {0x53e5, 2323}, + {0x53e6, 2614}, + {0x53e8, 5374}, + {0x53e9, 5373}, + {0x53ea, 4538}, + {0x53eb, 2209}, + {0x53ec, 4474}, + {0x53ed, 979}, + {0x53ee, 1506}, + {0x53ef, 2390}, + {0x53f0, 3579}, + {0x53f1, 5371}, + {0x53f2, 3406}, + {0x53f3, 4279}, + {0x53f5, 4741}, + {0x53f6, 4157}, + {0x53f7, 1916}, + {0x53f8, 3507}, + {0x53f9, 3601}, + {0x53fb, 5375}, + {0x53fc, 1489}, + {0x53fd, 5372}, + {0x53ff, 0}, + {0x5401, 4314}, + {0x5403, 1273}, + {0x5404, 1778}, + {0x5406, 5378}, + {0x5408, 1926}, + {0x5409, 2077}, + {0x540a, 1494}, + {0x540c, 3677}, + {0x540d, 2816}, + {0x540e, 1962}, + {0x540f, 2527}, + {0x5410, 3699}, + {0x5411, 3935}, + {0x5412, 5376}, + {0x5413, 3890}, + {0x5415, 2663}, + {0x5416, 5377}, + {0x5417, 2711}, + {0x5419, 0}, + {0x541a, 1}, + {0x541b, 2348}, + {0x541d, 2600}, + {0x541e, 3709}, + {0x541f, 4222}, + {0x5420, 1642}, + {0x5421, 5385}, + {0x5423, 5388}, + {0x5425, 0}, + {0x5426, 1678}, + {0x5427, 980}, + {0x5428, 1557}, + {0x5429, 1649}, + {0x542b, 1891}, + {0x542c, 3664}, + {0x542d, 2401}, + {0x542e, 3494}, + {0x542f, 3091}, + {0x5431, 4519}, + {0x5432, 5389}, + {0x5434, 3825}, + {0x5435, 1240}, + {0x5437, 0}, + {0x5438, 3851}, + {0x5439, 1336}, + {0x543b, 3798}, + {0x543c, 1959}, + {0x543e, 3824}, + {0x5440, 4070}, + {0x5442, 0}, + {0x5443, 5384}, + {0x5445, 0}, + {0x5446, 1399}, + {0x5448, 1263}, + {0x544a, 1761}, + {0x544b, 5379}, + {0x544d, 0}, + {0x544e, 1}, + {0x544f, 2}, + {0x5450, 2856}, + {0x5452, 5380}, + {0x5453, 5381}, + {0x5454, 5382}, + {0x5455, 2940}, + {0x5456, 5383}, + {0x5457, 5386}, + {0x5458, 4340}, + {0x5459, 5387}, + {0x545b, 3127}, + {0x545c, 3815}, + {0x545e, 0}, + {0x545f, 1}, + {0x5460, 2}, + {0x5461, 3}, + {0x5462, 2875}, + {0x5464, 5394}, + {0x5466, 5399}, + {0x5468, 4571}, + {0x546a, 0}, + {0x546b, 1}, + {0x546c, 2}, + {0x546d, 3}, + {0x546e, 4}, + {0x546f, 5}, + {0x5470, 6}, + {0x5471, 5393}, + {0x5472, 5410}, + {0x5473, 3781}, + {0x5475, 1918}, + {0x5476, 5398}, + {0x5477, 5392}, + {0x5478, 2975}, + {0x547a, 0}, + {0x547b, 3364}, + {0x547c, 1963}, + {0x547d, 2817}, + {0x547f, 0}, + {0x5480, 2310}, + {0x5482, 5390}, + {0x5484, 5397}, + {0x5486, 2969}, + {0x5488, 0}, + {0x5489, 1}, + {0x548a, 2}, + {0x548b, 4423}, + {0x548c, 1924}, + {0x548e, 2299}, + {0x548f, 4258}, + {0x5490, 1723}, + {0x5492, 4579}, + {0x5494, 5391}, + {0x5495, 1815}, + {0x5496, 2356}, + {0x5498, 0}, + {0x5499, 2629}, + {0x549a, 5395}, + {0x549b, 5396}, + {0x549d, 5400}, + {0x549f, 0}, + {0x54a0, 1}, + {0x54a1, 2}, + {0x54a2, 3}, + {0x54a3, 5411}, + {0x54a4, 5421}, + {0x54a6, 5407}, + {0x54a7, 5406}, + {0x54a8, 4646}, + {0x54a9, 5419}, + {0x54aa, 5420}, + {0x54ab, 5991}, + {0x54ac, 4142}, + {0x54ad, 5402}, + {0x54af, 2358}, + {0x54b1, 4382}, + {0x54b3, 2389}, + {0x54b4, 5404}, + {0x54b6, 0}, + {0x54b7, 1}, + {0x54b8, 3897}, + {0x54ba, 0}, + {0x54bb, 5413}, + {0x54bc, 9069}, + {0x54bd, 4083}, + {0x54bf, 5414}, + {0x54c0, 946}, + {0x54c1, 3030}, + {0x54c2, 5403}, + {0x54c4, 1948}, + {0x54c6, 1566}, + {0x54c7, 3724}, + {0x54c8, 1879}, + {0x54c9, 4376}, + {0x54cb, 0}, + {0x54cc, 5415}, + {0x54cd, 3929}, + {0x54ce, 944}, + {0x54cf, 5423}, + {0x54d0, 5401}, + {0x54d1, 4079}, + {0x54d2, 5405}, + {0x54d3, 5408}, + {0x54d4, 5409}, + {0x54d5, 5412}, + {0x54d7, 1982}, + {0x54d9, 5416}, + {0x54da, 5417}, + {0x54dc, 5418}, + {0x54dd, 5422}, + {0x54de, 5424}, + {0x54df, 4249}, + {0x54e1, 8775}, + {0x54e3, 0}, + {0x54e4, 1}, + {0x54e5, 1762}, + {0x54e6, 2935}, + {0x54e7, 5426}, + {0x54e8, 3347}, + {0x54e9, 2545}, + {0x54ea, 2855}, + {0x54ec, 0}, + {0x54ed, 2411}, + {0x54ee, 3941}, + {0x54f0, 0}, + {0x54f1, 1}, + {0x54f2, 4477}, + {0x54f3, 5430}, + {0x54f5, 0}, + {0x54f6, 1}, + {0x54f7, 2}, + {0x54f8, 3}, + {0x54f9, 4}, + {0x54fa, 1151}, + {0x54fc, 1942}, + {0x54fd, 5428}, + {0x54ff, 5009}, + {0x5501, 4109}, + {0x5503, 0}, + {0x5504, 9068}, + {0x5506, 3561}, + {0x5507, 1344}, + {0x5509, 945}, + {0x550b, 0}, + {0x550c, 1}, + {0x550d, 2}, + {0x550e, 3}, + {0x550f, 5433}, + {0x5510, 3609}, + {0x5511, 5434}, + {0x5513, 0}, + {0x5514, 5429}, + {0x5516, 0}, + {0x5517, 1}, + {0x5518, 2}, + {0x5519, 3}, + {0x551a, 4}, + {0x551b, 5425}, + {0x551d, 0}, + {0x551e, 1}, + {0x551f, 2}, + {0x5520, 5427}, + {0x5522, 5431}, + {0x5523, 5432}, + {0x5524, 2002}, + {0x5526, 0}, + {0x5527, 5435}, + {0x5529, 0}, + {0x552a, 5436}, + {0x552c, 1976}, + {0x552e, 3442}, + {0x552f, 3767}, + {0x5530, 5453}, + {0x5531, 1231}, + {0x5533, 5452}, + {0x5535, 0}, + {0x5536, 1}, + {0x5537, 5447}, + {0x5539, 0}, + {0x553a, 1}, + {0x553b, 2}, + {0x553c, 5446}, + {0x553e, 3722}, + {0x553f, 5444}, + {0x5541, 5442}, + {0x5543, 2397}, + {0x5544, 4641}, + {0x5546, 3333}, + {0x5548, 0}, + {0x5549, 5440}, + {0x554a, 940}, + {0x554c, 0}, + {0x554d, 1}, + {0x554e, 2}, + {0x554f, 8604}, + {0x5550, 5445}, + {0x5552, 0}, + {0x5553, 8393}, + {0x5555, 5443}, + {0x5556, 5448}, + {0x5558, 0}, + {0x5559, 1}, + {0x555a, 2}, + {0x555b, 3}, + {0x555c, 5454}, + {0x555e, 8688}, + {0x5560, 0}, + {0x5561, 1637}, + {0x5563, 0}, + {0x5564, 3008}, + {0x5565, 3311}, + {0x5566, 2461}, + {0x5567, 5437}, + {0x5569, 0}, + {0x556a, 2943}, + {0x556c, 4730}, + {0x556d, 5441}, + {0x556e, 2905}, + {0x5570, 0}, + {0x5571, 1}, + {0x5572, 2}, + {0x5573, 3}, + {0x5574, 4}, + {0x5575, 5449}, + {0x5576, 5450}, + {0x5577, 5451}, + {0x5578, 3952}, + {0x557a, 0}, + {0x557b, 5466}, + {0x557c, 3639}, + {0x557e, 5463}, + {0x5580, 2355}, + {0x5581, 5461}, + {0x5582, 3784}, + {0x5583, 5457}, + {0x5584, 3327}, + {0x5586, 0}, + {0x5587, 2457}, + {0x5588, 5460}, + {0x5589, 1956}, + {0x558a, 1895}, + {0x558b, 5455}, + {0x558d, 0}, + {0x558e, 1}, + {0x558f, 5438}, + {0x5591, 5465}, + {0x5593, 0}, + {0x5594, 5470}, + {0x5596, 0}, + {0x5597, 1}, + {0x5598, 1328}, + {0x5599, 5471}, + {0x559b, 0}, + {0x559c, 3871}, + {0x559d, 1919}, + {0x559f, 5462}, + {0x55a1, 0}, + {0x55a2, 1}, + {0x55a3, 2}, + {0x55a4, 3}, + {0x55a5, 4}, + {0x55a6, 5}, + {0x55a7, 4037}, + {0x55a9, 0}, + {0x55aa, 8459}, + {0x55ac, 8414}, + {0x55ae, 7850}, + {0x55b0, 0}, + {0x55b1, 5458}, + {0x55b2, 8748}, + {0x55b3, 4414}, + {0x55b5, 5439}, + {0x55b7, 2984}, + {0x55b9, 5459}, + {0x55bb, 4316}, + {0x55bd, 5468}, + {0x55be, 5469}, + {0x55c0, 0}, + {0x55c1, 1}, + {0x55c2, 2}, + {0x55c3, 3}, + {0x55c4, 5482}, + {0x55c5, 4012}, + {0x55c6, 8408}, + {0x55c7, 8896}, + {0x55c9, 5474}, + {0x55cb, 0}, + {0x55cc, 5487}, + {0x55cd, 5488}, + {0x55ce, 8303}, + {0x55d0, 0}, + {0x55d1, 5476}, + {0x55d2, 5456}, + {0x55d3, 3293}, + {0x55d4, 5479}, + {0x55d6, 5464}, + {0x55d8, 0}, + {0x55d9, 1}, + {0x55da, 8609}, + {0x55dc, 3423}, + {0x55dd, 5481}, + {0x55df, 5467}, + {0x55e1, 3802}, + {0x55e3, 3512}, + {0x55e4, 5491}, + {0x55e5, 5484}, + {0x55e6, 5480}, + {0x55e8, 5489}, + {0x55e9, 9081}, + {0x55ea, 5472}, + {0x55eb, 5477}, + {0x55ec, 5478}, + {0x55ee, 0}, + {0x55ef, 5483}, + {0x55f1, 0}, + {0x55f2, 5485}, + {0x55f3, 5486}, + {0x55f5, 5490}, + {0x55f6, 9074}, + {0x55f7, 5473}, + {0x55f9, 0}, + {0x55fa, 1}, + {0x55fb, 2}, + {0x55fc, 3}, + {0x55fd, 3529}, + {0x55fe, 5499}, + {0x5600, 5500}, + {0x5601, 5496}, + {0x5603, 0}, + {0x5604, 1}, + {0x5605, 2}, + {0x5606, 8554}, + {0x5608, 5494}, + {0x5609, 2113}, + {0x560b, 0}, + {0x560c, 5495}, + {0x560d, 9084}, + {0x560e, 1725}, + {0x560f, 4731}, + {0x5611, 0}, + {0x5612, 1}, + {0x5613, 2}, + {0x5614, 8368}, + {0x5616, 9082}, + {0x5617, 7796}, + {0x5618, 4021}, + {0x561a, 0}, + {0x561b, 2710}, + {0x561c, 9079}, + {0x561e, 5493}, + {0x561f, 5475}, + {0x5621, 0}, + {0x5622, 1}, + {0x5623, 5498}, + {0x5624, 5497}, + {0x5626, 0}, + {0x5627, 5501}, + {0x5629, 8012}, + {0x562b, 0}, + {0x562c, 5506}, + {0x562d, 5502}, + {0x562e, 9080}, + {0x562f, 8655}, + {0x5630, 9064}, + {0x5631, 4597}, + {0x5632, 1237}, + {0x5634, 4681}, + {0x5635, 9073}, + {0x5636, 3504}, + {0x5638, 9065}, + {0x5639, 5504}, + {0x563b, 3850}, + {0x563d, 0}, + {0x563e, 1}, + {0x563f, 1936}, + {0x5641, 9844}, + {0x5643, 0}, + {0x5644, 1}, + {0x5645, 2}, + {0x5646, 3}, + {0x5647, 4}, + {0x5648, 5}, + {0x5649, 6}, + {0x564a, 7}, + {0x564b, 8}, + {0x564c, 5511}, + {0x564d, 5507}, + {0x564e, 4148}, + {0x5650, 0}, + {0x5651, 1}, + {0x5652, 2}, + {0x5653, 3}, + {0x5654, 5512}, + {0x5656, 0}, + {0x5657, 5505}, + {0x5658, 5503}, + {0x5659, 5509}, + {0x565b, 0}, + {0x565c, 5510}, + {0x565d, 9071}, + {0x565f, 0}, + {0x5660, 9072}, + {0x5662, 5508}, + {0x5664, 5514}, + {0x5665, 9078}, + {0x5666, 9075}, + {0x5668, 3094}, + {0x5669, 4706}, + {0x566a, 4398}, + {0x566b, 5516}, + {0x566c, 3424}, + {0x566e, 0}, + {0x566f, 9087}, + {0x5671, 5515}, + {0x5672, 9076}, + {0x5674, 8373}, + {0x5676, 1724}, + {0x5678, 7899}, + {0x5679, 9842}, + {0x567b, 5517}, + {0x567c, 5518}, + {0x567e, 0}, + {0x567f, 1}, + {0x5680, 9070}, + {0x5682, 0}, + {0x5683, 1}, + {0x5684, 2}, + {0x5685, 5519}, + {0x5686, 5513}, + {0x5687, 8631}, + {0x5689, 0}, + {0x568a, 1}, + {0x568b, 2}, + {0x568c, 9077}, + {0x568e, 1910}, + {0x568f, 3642}, + {0x5691, 0}, + {0x5692, 1}, + {0x5693, 5520}, + {0x5695, 9090}, + {0x5697, 0}, + {0x5698, 1}, + {0x5699, 8350}, + {0x569b, 0}, + {0x569c, 1}, + {0x569d, 2}, + {0x569e, 3}, + {0x569f, 4}, + {0x56a0, 5}, + {0x56a1, 6}, + {0x56a2, 7}, + {0x56a3, 3942}, + {0x56a5, 0}, + {0x56a6, 9067}, + {0x56a8, 8249}, + {0x56aa, 0}, + {0x56ab, 1}, + {0x56ac, 2}, + {0x56ad, 3}, + {0x56ae, 9887}, + {0x56af, 5521}, + {0x56b1, 0}, + {0x56b2, 1}, + {0x56b3, 9085}, + {0x56b4, 8693}, + {0x56b6, 9089}, + {0x56b7, 3229}, + {0x56b9, 0}, + {0x56ba, 1}, + {0x56bb, 2}, + {0x56bc, 2193}, + {0x56be, 0}, + {0x56bf, 1}, + {0x56c0, 9083}, + {0x56c1, 9086}, + {0x56c2, 8652}, + {0x56c4, 0}, + {0x56c5, 8923}, + {0x56c7, 0}, + {0x56c8, 9066}, + {0x56c9, 9865}, + {0x56ca, 2869}, + {0x56cc, 9879}, + {0x56ce, 0}, + {0x56cf, 1}, + {0x56d0, 2}, + {0x56d1, 8865}, + {0x56d3, 0}, + {0x56d4, 5522}, + {0x56d6, 0}, + {0x56d7, 5523}, + {0x56d9, 0}, + {0x56da, 3185}, + {0x56db, 3513}, + {0x56dd, 5524}, + {0x56de, 2029}, + {0x56df, 4716}, + {0x56e0, 4217}, + {0x56e1, 5525}, + {0x56e2, 3702}, + {0x56e4, 1561}, + {0x56e6, 0}, + {0x56e7, 1}, + {0x56e8, 2}, + {0x56e9, 3}, + {0x56ea, 4}, + {0x56eb, 5527}, + {0x56ed, 4339}, + {0x56ef, 0}, + {0x56f0, 2450}, + {0x56f1, 1364}, + {0x56f3, 0}, + {0x56f4, 3766}, + {0x56f5, 5526}, + {0x56f7, 0}, + {0x56f8, 1}, + {0x56f9, 5528}, + {0x56fa, 1829}, + {0x56fc, 0}, + {0x56fd, 1875}, + {0x56fe, 3693}, + {0x56ff, 5529}, + {0x5701, 0}, + {0x5702, 1}, + {0x5703, 3059}, + {0x5704, 5530}, + {0x5706, 4341}, + {0x5707, 9091}, + {0x5708, 3201}, + {0x5709, 5532}, + {0x570a, 5531}, + {0x570b, 7997}, + {0x570d, 8591}, + {0x570f, 0}, + {0x5710, 1}, + {0x5711, 2}, + {0x5712, 8774}, + {0x5713, 8776}, + {0x5715, 0}, + {0x5716, 8574}, + {0x5718, 8576}, + {0x571a, 0}, + {0x571b, 1}, + {0x571c, 5533}, + {0x571e, 0}, + {0x571f, 3698}, + {0x5721, 0}, + {0x5722, 1}, + {0x5723, 3388}, + {0x5725, 0}, + {0x5726, 1}, + {0x5727, 2}, + {0x5728, 4381}, + {0x5729, 5031}, + {0x572a, 5033}, + {0x572c, 5032}, + {0x572d, 1856}, + {0x572e, 5036}, + {0x572f, 5037}, + {0x5730, 1465}, + {0x5732, 0}, + {0x5733, 5034}, + {0x5735, 0}, + {0x5736, 1}, + {0x5737, 2}, + {0x5738, 3}, + {0x5739, 5035}, + {0x573a, 1222}, + {0x573b, 5039}, + {0x573d, 0}, + {0x573e, 2061}, + {0x5740, 4534}, + {0x5742, 5040}, + {0x5744, 0}, + {0x5745, 1}, + {0x5746, 2}, + {0x5747, 2344}, + {0x5749, 0}, + {0x574a, 1624}, + {0x574c, 5024}, + {0x574d, 3585}, + {0x574e, 2367}, + {0x574f, 1994}, + {0x5750, 4693}, + {0x5751, 2400}, + {0x5753, 0}, + {0x5754, 1}, + {0x5755, 2}, + {0x5756, 3}, + {0x5757, 2422}, + {0x5759, 0}, + {0x575a, 2132}, + {0x575b, 3590}, + {0x575c, 5038}, + {0x575d, 990}, + {0x575e, 3834}, + {0x575f, 1653}, + {0x5760, 4630}, + {0x5761, 3041}, + {0x5763, 0}, + {0x5764, 2447}, + {0x5766, 3596}, + {0x5768, 5047}, + {0x5769, 5041}, + {0x576a, 3033}, + {0x576b, 5043}, + {0x576d, 5048}, + {0x576f, 3000}, + {0x5771, 0}, + {0x5772, 1}, + {0x5773, 5050}, + {0x5775, 0}, + {0x5776, 5049}, + {0x5777, 2381}, + {0x5779, 0}, + {0x577a, 1}, + {0x577b, 5046}, + {0x577c, 5045}, + {0x577e, 0}, + {0x577f, 1}, + {0x5780, 2}, + {0x5781, 3}, + {0x5782, 1340}, + {0x5783, 2455}, + {0x5784, 2633}, + {0x5785, 5042}, + {0x5786, 5044}, + {0x5788, 0}, + {0x5789, 1}, + {0x578a, 2}, + {0x578b, 3992}, + {0x578c, 5053}, + {0x578e, 0}, + {0x578f, 1}, + {0x5790, 2}, + {0x5791, 3}, + {0x5792, 2504}, + {0x5793, 5058}, + {0x5795, 0}, + {0x5796, 1}, + {0x5797, 2}, + {0x5798, 3}, + {0x5799, 4}, + {0x579a, 5}, + {0x579b, 1569}, + {0x579d, 0}, + {0x579e, 1}, + {0x579f, 2}, + {0x57a0, 5059}, + {0x57a1, 5026}, + {0x57a2, 1809}, + {0x57a3, 4334}, + {0x57a4, 5052}, + {0x57a6, 2398}, + {0x57a7, 5056}, + {0x57a9, 5025}, + {0x57ab, 1479}, + {0x57ad, 5051}, + {0x57ae, 2418}, + {0x57b0, 0}, + {0x57b1, 1}, + {0x57b2, 5054}, + {0x57b4, 5057}, + {0x57b6, 0}, + {0x57b7, 1}, + {0x57b8, 5065}, + {0x57ba, 0}, + {0x57bb, 1}, + {0x57bc, 2}, + {0x57bd, 3}, + {0x57be, 4}, + {0x57bf, 5}, + {0x57c0, 6}, + {0x57c1, 7}, + {0x57c2, 1786}, + {0x57c3, 942}, + {0x57c5, 0}, + {0x57c6, 1}, + {0x57c7, 2}, + {0x57c8, 3}, + {0x57c9, 4}, + {0x57ca, 5}, + {0x57cb, 2712}, + {0x57cd, 0}, + {0x57ce, 1260}, + {0x57cf, 5055}, + {0x57d1, 0}, + {0x57d2, 5064}, + {0x57d4, 3057}, + {0x57d5, 5060}, + {0x57d7, 0}, + {0x57d8, 5061}, + {0x57d9, 5063}, + {0x57da, 5062}, + {0x57dc, 0}, + {0x57dd, 5070}, + {0x57df, 4311}, + {0x57e0, 1153}, + {0x57e1, 9002}, + {0x57e3, 0}, + {0x57e4, 5069}, + {0x57e6, 0}, + {0x57e7, 1}, + {0x57e8, 2}, + {0x57e9, 3}, + {0x57ea, 4}, + {0x57eb, 5}, + {0x57ec, 6}, + {0x57ed, 5074}, + {0x57ef, 5067}, + {0x57f1, 0}, + {0x57f2, 1}, + {0x57f3, 2}, + {0x57f4, 5066}, + {0x57f6, 0}, + {0x57f7, 8843}, + {0x57f8, 5068}, + {0x57f9, 2977}, + {0x57fa, 2062}, + {0x57fc, 0}, + {0x57fd, 5073}, + {0x57ff, 0}, + {0x5800, 5075}, + {0x5802, 3606}, + {0x5804, 0}, + {0x5805, 8069}, + {0x5806, 1552}, + {0x5807, 5196}, + {0x5809, 0}, + {0x580a, 8997}, + {0x580b, 5071}, + {0x580d, 5072}, + {0x580f, 0}, + {0x5810, 1}, + {0x5811, 3122}, + {0x5813, 0}, + {0x5814, 1}, + {0x5815, 1576}, + {0x5816, 9004}, + {0x5818, 0}, + {0x5819, 5077}, + {0x581b, 0}, + {0x581c, 1}, + {0x581d, 9006}, + {0x581e, 5076}, + {0x5820, 5079}, + {0x5821, 1037}, + {0x5823, 0}, + {0x5824, 1453}, + {0x5826, 0}, + {0x5827, 1}, + {0x5828, 2}, + {0x5829, 3}, + {0x582a, 2365}, + {0x582c, 0}, + {0x582d, 1}, + {0x582e, 2}, + {0x582f, 8709}, + {0x5830, 4104}, + {0x5831, 7736}, + {0x5833, 0}, + {0x5834, 7795}, + {0x5835, 1537}, + {0x5837, 0}, + {0x5838, 1}, + {0x5839, 2}, + {0x583a, 3}, + {0x583b, 4}, + {0x583c, 5}, + {0x583d, 6}, + {0x583e, 7}, + {0x583f, 8}, + {0x5840, 9}, + {0x5841, 10}, + {0x5842, 11}, + {0x5843, 12}, + {0x5844, 5078}, + {0x5846, 0}, + {0x5847, 1}, + {0x5848, 2}, + {0x5849, 3}, + {0x584a, 8163}, + {0x584b, 9017}, + {0x584c, 3567}, + {0x584d, 6563}, + {0x584f, 9003}, + {0x5851, 3537}, + {0x5852, 9005}, + {0x5854, 3571}, + {0x5856, 0}, + {0x5857, 8575}, + {0x5858, 3604}, + {0x585a, 0}, + {0x585b, 1}, + {0x585c, 2}, + {0x585d, 3}, + {0x585e, 3286}, + {0x5860, 0}, + {0x5861, 1}, + {0x5862, 8615}, + {0x5864, 9007}, + {0x5865, 5080}, + {0x5867, 0}, + {0x5868, 1}, + {0x5869, 2}, + {0x586a, 3}, + {0x586b, 3649}, + {0x586c, 5081}, + {0x586e, 0}, + {0x586f, 1}, + {0x5870, 2}, + {0x5871, 3}, + {0x5872, 4}, + {0x5873, 5}, + {0x5874, 6}, + {0x5875, 7805}, + {0x5877, 0}, + {0x5878, 1}, + {0x5879, 8406}, + {0x587b, 0}, + {0x587c, 1}, + {0x587d, 2}, + {0x587e, 5027}, + {0x5880, 5085}, + {0x5881, 5082}, + {0x5883, 2274}, + {0x5885, 3474}, + {0x5887, 0}, + {0x5888, 1}, + {0x5889, 5083}, + {0x588a, 7874}, + {0x588c, 0}, + {0x588d, 1}, + {0x588e, 2}, + {0x588f, 3}, + {0x5890, 4}, + {0x5891, 5}, + {0x5892, 3331}, + {0x5893, 2844}, + {0x5895, 0}, + {0x5896, 1}, + {0x5897, 2}, + {0x5898, 3}, + {0x5899, 3130}, + {0x589a, 5084}, + {0x589c, 8882}, + {0x589e, 4409}, + {0x589f, 4017}, + {0x58a1, 0}, + {0x58a2, 1}, + {0x58a3, 2}, + {0x58a4, 3}, + {0x58a5, 4}, + {0x58a6, 5}, + {0x58a7, 6}, + {0x58a8, 2830}, + {0x58a9, 1556}, + {0x58ab, 0}, + {0x58ac, 1}, + {0x58ad, 2}, + {0x58ae, 7903}, + {0x58b0, 0}, + {0x58b1, 1}, + {0x58b2, 2}, + {0x58b3, 7929}, + {0x58b5, 0}, + {0x58b6, 1}, + {0x58b7, 2}, + {0x58b8, 3}, + {0x58b9, 4}, + {0x58ba, 5}, + {0x58bb, 8409}, + {0x58bc, 5028}, + {0x58be, 8157}, + {0x58c0, 0}, + {0x58c1, 1091}, + {0x58c3, 0}, + {0x58c4, 1}, + {0x58c5, 5029}, + {0x58c7, 8551}, + {0x58c9, 0}, + {0x58ca, 1}, + {0x58cb, 2}, + {0x58cc, 3}, + {0x58cd, 4}, + {0x58ce, 5}, + {0x58cf, 6}, + {0x58d0, 7}, + {0x58d1, 5030}, + {0x58d3, 8685}, + {0x58d5, 1909}, + {0x58d7, 0}, + {0x58d8, 8199}, + {0x58d9, 8998}, + {0x58da, 9001}, + {0x58dc, 0}, + {0x58dd, 1}, + {0x58de, 8018}, + {0x58df, 8251}, + {0x58e0, 9000}, + {0x58e2, 8999}, + {0x58e4, 3227}, + {0x58e6, 0}, + {0x58e7, 1}, + {0x58e8, 2}, + {0x58e9, 7723}, + {0x58eb, 3414}, + {0x58ec, 3236}, + {0x58ee, 4624}, + {0x58ef, 8878}, + {0x58f0, 3378}, + {0x58f2, 0}, + {0x58f3, 2388}, + {0x58f5, 0}, + {0x58f6, 1967}, + {0x58f8, 0}, + {0x58f9, 4163}, + {0x58fa, 8009}, + {0x58fc, 0}, + {0x58fd, 8504}, + {0x58ff, 0}, + {0x5901, 0}, + {0x5902, 5660}, + {0x5904, 1321}, + {0x5906, 0}, + {0x5907, 1057}, + {0x5909, 0}, + {0x590a, 1}, + {0x590b, 2}, + {0x590c, 3}, + {0x590d, 1711}, + {0x590f, 3889}, + {0x5911, 0}, + {0x5912, 1}, + {0x5913, 2}, + {0x5914, 4859}, + {0x5915, 3859}, + {0x5916, 3731}, + {0x5918, 0}, + {0x5919, 4865}, + {0x591a, 1567}, + {0x591c, 4160}, + {0x591e, 0}, + {0x591f, 1812}, + {0x5921, 0}, + {0x5922, 8321}, + {0x5924, 5659}, + {0x5925, 5657}, + {0x5927, 1398}, + {0x5929, 3647}, + {0x592a, 3582}, + {0x592b, 1679}, + {0x592d, 4712}, + {0x592e, 4116}, + {0x592f, 1906}, + {0x5931, 3390}, + {0x5933, 0}, + {0x5934, 3688}, + {0x5936, 0}, + {0x5937, 4171}, + {0x5938, 2417}, + {0x5939, 2115}, + {0x593a, 1568}, + {0x593c, 5295}, + {0x593e, 8060}, + {0x5940, 0}, + {0x5941, 5296}, + {0x5942, 5004}, + {0x5944, 4098}, + {0x5946, 0}, + {0x5947, 3077}, + {0x5948, 2865}, + {0x5949, 1675}, + {0x594b, 1657}, + {0x594d, 0}, + {0x594e, 2441}, + {0x594f, 4669}, + {0x5951, 3092}, + {0x5953, 0}, + {0x5954, 1061}, + {0x5955, 5298}, + {0x5956, 2178}, + {0x5957, 3626}, + {0x5958, 5300}, + {0x595a, 5299}, + {0x595c, 0}, + {0x595d, 1}, + {0x595e, 2}, + {0x595f, 3}, + {0x5960, 1485}, + {0x5962, 3350}, + {0x5964, 0}, + {0x5965, 973}, + {0x5967, 0}, + {0x5968, 1}, + {0x5969, 9051}, + {0x596a, 7902}, + {0x596c, 8098}, + {0x596e, 7930}, + {0x5970, 0}, + {0x5971, 1}, + {0x5972, 2}, + {0x5973, 2927}, + {0x5974, 2924}, + {0x5976, 2863}, + {0x5978, 2140}, + {0x5979, 3570}, + {0x597b, 0}, + {0x597c, 1}, + {0x597d, 1914}, + {0x597f, 0}, + {0x5980, 1}, + {0x5981, 6005}, + {0x5982, 3266}, + {0x5983, 6006}, + {0x5984, 3758}, + {0x5986, 4622}, + {0x5987, 1721}, + {0x5988, 2703}, + {0x598a, 3244}, + {0x598c, 0}, + {0x598d, 6007}, + {0x598f, 0}, + {0x5990, 1}, + {0x5991, 2}, + {0x5992, 1545}, + {0x5993, 2110}, + {0x5995, 0}, + {0x5996, 4134}, + {0x5997, 6011}, + {0x5999, 2803}, + {0x599b, 0}, + {0x599c, 1}, + {0x599d, 8877}, + {0x599e, 6014}, + {0x59a0, 0}, + {0x59a1, 1}, + {0x59a2, 2}, + {0x59a3, 6010}, + {0x59a4, 6015}, + {0x59a5, 3720}, + {0x59a7, 0}, + {0x59a8, 1630}, + {0x59a9, 6008}, + {0x59aa, 6009}, + {0x59ab, 6013}, + {0x59ad, 0}, + {0x59ae, 2880}, + {0x59af, 6018}, + {0x59b1, 0}, + {0x59b2, 6017}, + {0x59b4, 0}, + {0x59b5, 1}, + {0x59b6, 2}, + {0x59b7, 3}, + {0x59b8, 4}, + {0x59b9, 2760}, + {0x59bb, 3069}, + {0x59bd, 0}, + {0x59be, 6020}, + {0x59c0, 0}, + {0x59c1, 1}, + {0x59c2, 2}, + {0x59c3, 3}, + {0x59c4, 4}, + {0x59c5, 5}, + {0x59c6, 2842}, + {0x59c8, 0}, + {0x59c9, 1}, + {0x59ca, 6012}, + {0x59cb, 3411}, + {0x59cd, 0}, + {0x59ce, 1}, + {0x59cf, 2}, + {0x59d0, 2228}, + {0x59d1, 1820}, + {0x59d2, 6016}, + {0x59d3, 4000}, + {0x59d4, 3774}, + {0x59d6, 0}, + {0x59d7, 6019}, + {0x59d8, 6026}, + {0x59da, 4141}, + {0x59dc, 2171}, + {0x59dd, 6023}, + {0x59df, 0}, + {0x59e0, 1}, + {0x59e1, 2}, + {0x59e2, 3}, + {0x59e3, 6025}, + {0x59e5, 2492}, + {0x59e7, 0}, + {0x59e8, 4179}, + {0x59ea, 0}, + {0x59eb, 1}, + {0x59ec, 2074}, + {0x59ee, 0}, + {0x59ef, 1}, + {0x59f0, 2}, + {0x59f1, 3}, + {0x59f2, 4}, + {0x59f3, 5}, + {0x59f4, 6}, + {0x59f5, 7}, + {0x59f6, 8}, + {0x59f7, 9}, + {0x59f8, 10}, + {0x59f9, 6027}, + {0x59fb, 4221}, + {0x59fd, 0}, + {0x59fe, 1}, + {0x59ff, 4648}, + {0x5a01, 3759}, + {0x5a03, 3727}, + {0x5a04, 2637}, + {0x5a05, 6021}, + {0x5a06, 6022}, + {0x5a07, 2192}, + {0x5a08, 6024}, + {0x5a09, 6029}, + {0x5a0b, 0}, + {0x5a0c, 6028}, + {0x5a0e, 0}, + {0x5a0f, 1}, + {0x5a10, 2}, + {0x5a11, 6032}, + {0x5a13, 6034}, + {0x5a15, 0}, + {0x5a16, 1}, + {0x5a17, 2}, + {0x5a18, 2898}, + {0x5a1a, 0}, + {0x5a1b, 1}, + {0x5a1c, 2859}, + {0x5a1e, 0}, + {0x5a1f, 2329}, + {0x5a20, 3368}, + {0x5a22, 0}, + {0x5a23, 6033}, + {0x5a25, 1583}, + {0x5a27, 0}, + {0x5a28, 1}, + {0x5a29, 2793}, + {0x5a2b, 0}, + {0x5a2c, 1}, + {0x5a2d, 2}, + {0x5a2e, 3}, + {0x5a2f, 4}, + {0x5a30, 5}, + {0x5a31, 4302}, + {0x5a32, 6030}, + {0x5a34, 6031}, + {0x5a36, 3197}, + {0x5a38, 0}, + {0x5a39, 1}, + {0x5a3a, 2}, + {0x5a3b, 3}, + {0x5a3c, 6039}, + {0x5a3e, 0}, + {0x5a3f, 1}, + {0x5a40, 6035}, + {0x5a41, 8255}, + {0x5a43, 0}, + {0x5a44, 1}, + {0x5a45, 2}, + {0x5a46, 3044}, + {0x5a48, 0}, + {0x5a49, 3746}, + {0x5a4a, 6037}, + {0x5a4c, 0}, + {0x5a4d, 1}, + {0x5a4e, 2}, + {0x5a4f, 3}, + {0x5a50, 4}, + {0x5a51, 5}, + {0x5a52, 6}, + {0x5a53, 7}, + {0x5a54, 8}, + {0x5a55, 6038}, + {0x5a57, 0}, + {0x5a58, 1}, + {0x5a59, 2}, + {0x5a5a, 2046}, + {0x5a5c, 0}, + {0x5a5d, 1}, + {0x5a5e, 2}, + {0x5a5f, 3}, + {0x5a60, 4}, + {0x5a61, 5}, + {0x5a62, 6040}, + {0x5a64, 0}, + {0x5a65, 1}, + {0x5a66, 7950}, + {0x5a67, 6036}, + {0x5a69, 0}, + {0x5a6a, 2466}, + {0x5a6c, 0}, + {0x5a6d, 9209}, + {0x5a6f, 0}, + {0x5a70, 1}, + {0x5a71, 2}, + {0x5a72, 3}, + {0x5a73, 4}, + {0x5a74, 4233}, + {0x5a75, 6041}, + {0x5a76, 3373}, + {0x5a77, 6045}, + {0x5a79, 0}, + {0x5a7a, 6046}, + {0x5a7c, 0}, + {0x5a7d, 1}, + {0x5a7e, 2}, + {0x5a7f, 4033}, + {0x5a81, 0}, + {0x5a82, 1}, + {0x5a83, 2}, + {0x5a84, 3}, + {0x5a85, 4}, + {0x5a86, 5}, + {0x5a87, 6}, + {0x5a88, 7}, + {0x5a89, 8}, + {0x5a8a, 9}, + {0x5a8b, 10}, + {0x5a8c, 11}, + {0x5a8d, 12}, + {0x5a8e, 13}, + {0x5a8f, 14}, + {0x5a90, 15}, + {0x5a91, 16}, + {0x5a92, 2754}, + {0x5a94, 0}, + {0x5a95, 1}, + {0x5a96, 2}, + {0x5a97, 3}, + {0x5a98, 4}, + {0x5a99, 5}, + {0x5a9a, 2761}, + {0x5a9b, 6044}, + {0x5a9d, 0}, + {0x5a9e, 1}, + {0x5a9f, 2}, + {0x5aa0, 3}, + {0x5aa1, 4}, + {0x5aa2, 5}, + {0x5aa3, 6}, + {0x5aa4, 7}, + {0x5aa5, 8}, + {0x5aa6, 9}, + {0x5aa7, 9212}, + {0x5aa9, 0}, + {0x5aaa, 6043}, + {0x5aac, 0}, + {0x5aad, 1}, + {0x5aae, 2}, + {0x5aaf, 3}, + {0x5ab0, 4}, + {0x5ab1, 5}, + {0x5ab2, 6049}, + {0x5ab3, 3870}, + {0x5ab5, 6564}, + {0x5ab7, 0}, + {0x5ab8, 6052}, + {0x5aba, 0}, + {0x5abb, 1}, + {0x5abc, 2}, + {0x5abd, 8297}, + {0x5abe, 6047}, + {0x5ac0, 0}, + {0x5ac1, 2129}, + {0x5ac2, 3298}, + {0x5ac4, 0}, + {0x5ac5, 1}, + {0x5ac6, 2}, + {0x5ac7, 3}, + {0x5ac8, 4}, + {0x5ac9, 2088}, + {0x5acb, 0}, + {0x5acc, 3904}, + {0x5ace, 0}, + {0x5acf, 1}, + {0x5ad0, 2}, + {0x5ad1, 3}, + {0x5ad2, 6050}, + {0x5ad4, 6051}, + {0x5ad6, 6056}, + {0x5ad7, 9207}, + {0x5ad8, 6058}, + {0x5ada, 0}, + {0x5adb, 1}, + {0x5adc, 6059}, + {0x5ade, 0}, + {0x5adf, 1}, + {0x5ae0, 6053}, + {0x5ae1, 1462}, + {0x5ae3, 6054}, + {0x5ae5, 0}, + {0x5ae6, 6057}, + {0x5ae8, 0}, + {0x5ae9, 2878}, + {0x5aeb, 6048}, + {0x5aed, 0}, + {0x5aee, 1}, + {0x5aef, 2}, + {0x5af0, 3}, + {0x5af1, 6055}, + {0x5af3, 0}, + {0x5af4, 1}, + {0x5af5, 9206}, + {0x5af7, 0}, + {0x5af8, 1}, + {0x5af9, 2}, + {0x5afa, 3}, + {0x5afb, 9213}, + {0x5afd, 0}, + {0x5afe, 1}, + {0x5aff, 2}, + {0x5b00, 9208}, + {0x5b02, 0}, + {0x5b03, 1}, + {0x5b04, 2}, + {0x5b05, 3}, + {0x5b06, 4}, + {0x5b07, 5}, + {0x5b08, 9210}, + {0x5b09, 6060}, + {0x5b0b, 9214}, + {0x5b0c, 8104}, + {0x5b0e, 0}, + {0x5b0f, 1}, + {0x5b10, 2}, + {0x5b11, 3}, + {0x5b12, 4}, + {0x5b13, 5}, + {0x5b14, 6}, + {0x5b15, 7}, + {0x5b16, 6062}, + {0x5b17, 6061}, + {0x5b19, 9217}, + {0x5b1b, 0}, + {0x5b1c, 1}, + {0x5b1d, 2}, + {0x5b1e, 3}, + {0x5b1f, 4}, + {0x5b20, 5}, + {0x5b21, 9215}, + {0x5b23, 0}, + {0x5b24, 1}, + {0x5b25, 2}, + {0x5b26, 3}, + {0x5b27, 4}, + {0x5b28, 5}, + {0x5b29, 6}, + {0x5b2a, 9216}, + {0x5b2c, 0}, + {0x5b2d, 1}, + {0x5b2e, 2}, + {0x5b2f, 3}, + {0x5b30, 8737}, + {0x5b32, 6063}, + {0x5b34, 4876}, + {0x5b36, 0}, + {0x5b37, 6064}, + {0x5b38, 8482}, + {0x5b3a, 0}, + {0x5b3b, 1}, + {0x5b3c, 2}, + {0x5b3d, 3}, + {0x5b3e, 4}, + {0x5b3f, 5}, + {0x5b40, 6065}, + {0x5b42, 0}, + {0x5b43, 1}, + {0x5b44, 2}, + {0x5b45, 3}, + {0x5b46, 4}, + {0x5b47, 5}, + {0x5b48, 6}, + {0x5b49, 7}, + {0x5b4a, 8}, + {0x5b4b, 9}, + {0x5b4c, 9211}, + {0x5b4e, 0}, + {0x5b4f, 1}, + {0x5b50, 4656}, + {0x5b51, 6071}, + {0x5b53, 6072}, + {0x5b54, 2404}, + {0x5b55, 4371}, + {0x5b57, 4659}, + {0x5b58, 1385}, + {0x5b59, 3556}, + {0x5b5a, 6068}, + {0x5b5b, 4729}, + {0x5b5c, 4651}, + {0x5b5d, 3949}, + {0x5b5f, 2772}, + {0x5b61, 0}, + {0x5b62, 6073}, + {0x5b63, 2097}, + {0x5b64, 1819}, + {0x5b65, 6069}, + {0x5b66, 4048}, + {0x5b68, 0}, + {0x5b69, 1881}, + {0x5b6a, 2678}, + {0x5b6b, 8538}, + {0x5b6c, 4705}, + {0x5b6e, 0}, + {0x5b6f, 1}, + {0x5b70, 3458}, + {0x5b71, 5994}, + {0x5b73, 6070}, + {0x5b75, 1682}, + {0x5b77, 0}, + {0x5b78, 8677}, + {0x5b7a, 3265}, + {0x5b7c, 0}, + {0x5b7d, 2904}, + {0x5b7f, 8279}, + {0x5b80, 5934}, + {0x5b81, 2913}, + {0x5b83, 3569}, + {0x5b84, 5935}, + {0x5b85, 4429}, + {0x5b87, 4307}, + {0x5b88, 3439}, + {0x5b89, 957}, + {0x5b8b, 3523}, + {0x5b8c, 3739}, + {0x5b8e, 0}, + {0x5b8f, 1953}, + {0x5b91, 0}, + {0x5b92, 1}, + {0x5b93, 5937}, + {0x5b95, 5936}, + {0x5b97, 4663}, + {0x5b98, 1842}, + {0x5b99, 4581}, + {0x5b9a, 1511}, + {0x5b9b, 3745}, + {0x5b9c, 4178}, + {0x5b9d, 1039}, + {0x5b9e, 3404}, + {0x5ba0, 1293}, + {0x5ba1, 3372}, + {0x5ba2, 2394}, + {0x5ba3, 4038}, + {0x5ba4, 3433}, + {0x5ba5, 5938}, + {0x5ba6, 2007}, + {0x5ba8, 0}, + {0x5ba9, 1}, + {0x5baa, 3913}, + {0x5bab, 1797}, + {0x5bad, 0}, + {0x5bae, 1}, + {0x5baf, 2}, + {0x5bb0, 4378}, + {0x5bb2, 0}, + {0x5bb3, 1885}, + {0x5bb4, 4112}, + {0x5bb5, 3945}, + {0x5bb6, 2117}, + {0x5bb8, 5939}, + {0x5bb9, 3256}, + {0x5bbb, 0}, + {0x5bbc, 1}, + {0x5bbd, 2426}, + {0x5bbe, 1119}, + {0x5bbf, 3539}, + {0x5bc1, 0}, + {0x5bc2, 2104}, + {0x5bc4, 2103}, + {0x5bc5, 4225}, + {0x5bc6, 2785}, + {0x5bc7, 2409}, + {0x5bc9, 0}, + {0x5bca, 1}, + {0x5bcb, 2}, + {0x5bcc, 1718}, + {0x5bce, 0}, + {0x5bcf, 1}, + {0x5bd0, 2759}, + {0x5bd2, 1893}, + {0x5bd3, 4325}, + {0x5bd5, 0}, + {0x5bd6, 1}, + {0x5bd7, 2}, + {0x5bd8, 3}, + {0x5bd9, 4}, + {0x5bda, 5}, + {0x5bdb, 6}, + {0x5bdc, 7}, + {0x5bdd, 3163}, + {0x5bde, 2834}, + {0x5bdf, 1203}, + {0x5be1, 1834}, + {0x5be2, 8421}, + {0x5be4, 5943}, + {0x5be5, 2577}, + {0x5be6, 8495}, + {0x5be7, 8355}, + {0x5be8, 4432}, + {0x5be9, 8481}, + {0x5beb, 8660}, + {0x5bec, 8165}, + {0x5bee, 5944}, + {0x5bf0, 5946}, + {0x5bf2, 0}, + {0x5bf3, 1}, + {0x5bf4, 2}, + {0x5bf5, 7818}, + {0x5bf6, 7735}, + {0x5bf8, 1386}, + {0x5bf9, 1555}, + {0x5bfa, 3511}, + {0x5bfb, 4057}, + {0x5bfc, 1437}, + {0x5bfe, 0}, + {0x5bff, 3440}, + {0x5c01, 1663}, + {0x5c03, 0}, + {0x5c04, 3357}, + {0x5c06, 2172}, + {0x5c07, 8094}, + {0x5c08, 8870}, + {0x5c09, 3789}, + {0x5c0a, 4685}, + {0x5c0b, 8680}, + {0x5c0d, 7898}, + {0x5c0e, 7865}, + {0x5c0f, 3948}, + {0x5c11, 3346}, + {0x5c13, 0}, + {0x5c14, 1594}, + {0x5c15, 6066}, + {0x5c16, 2133}, + {0x5c18, 1251}, + {0x5c1a, 3337}, + {0x5c1c, 6067}, + {0x5c1d, 1223}, + {0x5c1f, 0}, + {0x5c20, 1}, + {0x5c21, 2}, + {0x5c22, 5302}, + {0x5c24, 4269}, + {0x5c25, 5303}, + {0x5c27, 4137}, + {0x5c29, 0}, + {0x5c2a, 1}, + {0x5c2b, 2}, + {0x5c2c, 5304}, + {0x5c2e, 0}, + {0x5c2f, 1}, + {0x5c30, 2}, + {0x5c31, 2300}, + {0x5c33, 0}, + {0x5c34, 5305}, + {0x5c36, 0}, + {0x5c37, 9052}, + {0x5c38, 3395}, + {0x5c39, 4227}, + {0x5c3a, 1284}, + {0x5c3b, 5990}, + {0x5c3c, 2884}, + {0x5c3d, 2256}, + {0x5c3e, 3777}, + {0x5c3f, 2901}, + {0x5c40, 2309}, + {0x5c41, 3015}, + {0x5c42, 1194}, + {0x5c44, 0}, + {0x5c45, 2306}, + {0x5c47, 0}, + {0x5c48, 3193}, + {0x5c49, 3646}, + {0x5c4a, 2237}, + {0x5c4b, 3820}, + {0x5c4d, 0}, + {0x5c4e, 3409}, + {0x5c4f, 3040}, + {0x5c50, 5992}, + {0x5c51, 3975}, + {0x5c53, 0}, + {0x5c54, 1}, + {0x5c55, 4442}, + {0x5c57, 0}, + {0x5c58, 1}, + {0x5c59, 5993}, + {0x5c5b, 0}, + {0x5c5c, 1}, + {0x5c5d, 2}, + {0x5c5e, 3467}, + {0x5c60, 3697}, + {0x5c61, 2668}, + {0x5c62, 8272}, + {0x5c63, 5995}, + {0x5c64, 7783}, + {0x5c65, 2667}, + {0x5c66, 5996}, + {0x5c68, 9204}, + {0x5c6a, 0}, + {0x5c6b, 1}, + {0x5c6c, 8510}, + {0x5c6e, 6004}, + {0x5c6f, 3710}, + {0x5c71, 3318}, + {0x5c73, 0}, + {0x5c74, 1}, + {0x5c75, 2}, + {0x5c76, 3}, + {0x5c77, 4}, + {0x5c78, 5}, + {0x5c79, 4192}, + {0x5c7a, 5548}, + {0x5c7c, 0}, + {0x5c7d, 1}, + {0x5c7e, 2}, + {0x5c7f, 4305}, + {0x5c81, 3551}, + {0x5c82, 3088}, + {0x5c84, 0}, + {0x5c85, 1}, + {0x5c86, 2}, + {0x5c87, 3}, + {0x5c88, 5552}, + {0x5c8a, 0}, + {0x5c8b, 1}, + {0x5c8c, 5547}, + {0x5c8d, 5549}, + {0x5c8f, 0}, + {0x5c90, 5550}, + {0x5c91, 5555}, + {0x5c93, 0}, + {0x5c94, 1204}, + {0x5c96, 5551}, + {0x5c97, 1749}, + {0x5c98, 5553}, + {0x5c99, 5554}, + {0x5c9a, 5556}, + {0x5c9b, 1435}, + {0x5c9c, 5557}, + {0x5c9e, 0}, + {0x5c9f, 1}, + {0x5ca0, 2}, + {0x5ca1, 7958}, + {0x5ca2, 5559}, + {0x5ca3, 5564}, + {0x5ca5, 0}, + {0x5ca6, 1}, + {0x5ca7, 2}, + {0x5ca8, 3}, + {0x5ca9, 4091}, + {0x5cab, 5562}, + {0x5cac, 5561}, + {0x5cad, 2612}, + {0x5caf, 0}, + {0x5cb0, 1}, + {0x5cb1, 5563}, + {0x5cb3, 4355}, + {0x5cb5, 5558}, + {0x5cb7, 5566}, + {0x5cb8, 961}, + {0x5cba, 0}, + {0x5cbb, 1}, + {0x5cbc, 2}, + {0x5cbd, 5560}, + {0x5cbf, 2438}, + {0x5cc1, 5565}, + {0x5cc3, 0}, + {0x5cc4, 5567}, + {0x5cc6, 0}, + {0x5cc7, 1}, + {0x5cc8, 2}, + {0x5cc9, 3}, + {0x5cca, 4}, + {0x5ccb, 5570}, + {0x5ccd, 0}, + {0x5cce, 1}, + {0x5ccf, 2}, + {0x5cd0, 3}, + {0x5cd1, 4}, + {0x5cd2, 5568}, + {0x5cd4, 0}, + {0x5cd5, 1}, + {0x5cd6, 2}, + {0x5cd7, 3}, + {0x5cd8, 4}, + {0x5cd9, 4548}, + {0x5cdb, 0}, + {0x5cdc, 1}, + {0x5cdd, 2}, + {0x5cde, 3}, + {0x5cdf, 4}, + {0x5ce0, 5}, + {0x5ce1, 3884}, + {0x5ce3, 0}, + {0x5ce4, 5569}, + {0x5ce5, 5571}, + {0x5ce6, 2676}, + {0x5ce8, 1578}, + {0x5cea, 4317}, + {0x5cec, 0}, + {0x5ced, 3146}, + {0x5cef, 0}, + {0x5cf0, 1666}, + {0x5cf2, 0}, + {0x5cf3, 1}, + {0x5cf4, 9097}, + {0x5cf6, 7863}, + {0x5cf8, 0}, + {0x5cf9, 1}, + {0x5cfa, 2}, + {0x5cfb, 2349}, + {0x5cfd, 8628}, + {0x5cff, 0}, + {0x5d01, 0}, + {0x5d02, 5572}, + {0x5d03, 5573}, + {0x5d05, 0}, + {0x5d06, 5579}, + {0x5d07, 1292}, + {0x5d09, 0}, + {0x5d0a, 1}, + {0x5d0b, 2}, + {0x5d0c, 3}, + {0x5d0d, 9103}, + {0x5d0e, 3080}, + {0x5d10, 0}, + {0x5d11, 1}, + {0x5d12, 2}, + {0x5d13, 3}, + {0x5d14, 1377}, + {0x5d16, 4075}, + {0x5d17, 7962}, + {0x5d19, 0}, + {0x5d1a, 1}, + {0x5d1b, 5580}, + {0x5d1d, 0}, + {0x5d1e, 5578}, + {0x5d20, 0}, + {0x5d21, 1}, + {0x5d22, 2}, + {0x5d23, 3}, + {0x5d24, 5577}, + {0x5d26, 5575}, + {0x5d27, 5574}, + {0x5d29, 1065}, + {0x5d2b, 0}, + {0x5d2c, 9099}, + {0x5d2d, 4441}, + {0x5d2e, 5576}, + {0x5d30, 0}, + {0x5d31, 1}, + {0x5d32, 2}, + {0x5d33, 3}, + {0x5d34, 5583}, + {0x5d36, 0}, + {0x5d37, 1}, + {0x5d38, 2}, + {0x5d39, 3}, + {0x5d3a, 4}, + {0x5d3b, 5}, + {0x5d3c, 6}, + {0x5d3d, 5584}, + {0x5d3e, 5582}, + {0x5d40, 0}, + {0x5d41, 1}, + {0x5d42, 2}, + {0x5d43, 3}, + {0x5d44, 4}, + {0x5d45, 5}, + {0x5d46, 6}, + {0x5d47, 6946}, + {0x5d49, 0}, + {0x5d4a, 5591}, + {0x5d4b, 5590}, + {0x5d4c, 3123}, + {0x5d4e, 0}, + {0x5d4f, 1}, + {0x5d50, 9098}, + {0x5d52, 0}, + {0x5d53, 1}, + {0x5d54, 2}, + {0x5d55, 3}, + {0x5d56, 4}, + {0x5d57, 5}, + {0x5d58, 5581}, + {0x5d5a, 0}, + {0x5d5b, 5586}, + {0x5d5d, 5588}, + {0x5d5f, 0}, + {0x5d60, 1}, + {0x5d61, 2}, + {0x5d62, 3}, + {0x5d63, 4}, + {0x5d64, 5}, + {0x5d65, 6}, + {0x5d66, 7}, + {0x5d67, 8}, + {0x5d68, 9}, + {0x5d69, 5592}, + {0x5d6b, 5589}, + {0x5d6c, 5585}, + {0x5d6e, 0}, + {0x5d6f, 5587}, + {0x5d71, 0}, + {0x5d72, 1}, + {0x5d73, 2}, + {0x5d74, 5593}, + {0x5d76, 0}, + {0x5d77, 1}, + {0x5d78, 2}, + {0x5d79, 3}, + {0x5d7a, 4}, + {0x5d7b, 5}, + {0x5d7c, 6}, + {0x5d7d, 7}, + {0x5d7e, 8}, + {0x5d7f, 9}, + {0x5d80, 10}, + {0x5d81, 9105}, + {0x5d82, 5594}, + {0x5d84, 8817}, + {0x5d86, 0}, + {0x5d87, 9096}, + {0x5d89, 0}, + {0x5d8a, 1}, + {0x5d8b, 2}, + {0x5d8c, 3}, + {0x5d8d, 4}, + {0x5d8e, 5}, + {0x5d8f, 6}, + {0x5d90, 7}, + {0x5d91, 8}, + {0x5d92, 9}, + {0x5d93, 10}, + {0x5d94, 11}, + {0x5d95, 12}, + {0x5d96, 13}, + {0x5d97, 9102}, + {0x5d99, 5595}, + {0x5d9b, 0}, + {0x5d9c, 1}, + {0x5d9d, 5596}, + {0x5d9f, 0}, + {0x5da0, 9101}, + {0x5da2, 0}, + {0x5da3, 1}, + {0x5da4, 2}, + {0x5da5, 3}, + {0x5da6, 4}, + {0x5da7, 9100}, + {0x5da9, 0}, + {0x5daa, 1}, + {0x5dab, 2}, + {0x5dac, 3}, + {0x5dad, 4}, + {0x5dae, 5}, + {0x5daf, 6}, + {0x5db0, 7}, + {0x5db1, 8}, + {0x5db2, 9}, + {0x5db3, 10}, + {0x5db4, 11}, + {0x5db5, 12}, + {0x5db6, 13}, + {0x5db7, 5598}, + {0x5db8, 9104}, + {0x5dba, 8243}, + {0x5dbc, 8764}, + {0x5dbe, 0}, + {0x5dbf, 1}, + {0x5dc0, 2}, + {0x5dc1, 3}, + {0x5dc2, 4}, + {0x5dc3, 5}, + {0x5dc4, 6}, + {0x5dc5, 5599}, + {0x5dc7, 0}, + {0x5dc8, 1}, + {0x5dc9, 2}, + {0x5dca, 3}, + {0x5dcb, 8169}, + {0x5dcd, 3760}, + {0x5dcf, 0}, + {0x5dd0, 1}, + {0x5dd1, 2}, + {0x5dd2, 8277}, + {0x5dd4, 9106}, + {0x5dd6, 0}, + {0x5dd7, 1}, + {0x5dd8, 2}, + {0x5dd9, 3}, + {0x5dda, 4}, + {0x5ddb, 6165}, + {0x5ddd, 1323}, + {0x5dde, 4572}, + {0x5de0, 0}, + {0x5de1, 4059}, + {0x5de2, 1239}, + {0x5de4, 0}, + {0x5de5, 1789}, + {0x5de6, 4688}, + {0x5de7, 3142}, + {0x5de8, 2317}, + {0x5de9, 1799}, + {0x5deb, 3814}, + {0x5ded, 0}, + {0x5dee, 1205}, + {0x5def, 5023}, + {0x5df0, 8996}, + {0x5df1, 2093}, + {0x5df2, 4184}, + {0x5df3, 3517}, + {0x5df4, 984}, + {0x5df6, 0}, + {0x5df7, 3932}, + {0x5df9, 0}, + {0x5dfa, 1}, + {0x5dfb, 2}, + {0x5dfc, 3}, + {0x5dfd, 4855}, + {0x5dfe, 2238}, + {0x5e01, 1083}, + {0x5e02, 3431}, + {0x5e03, 1155}, + {0x5e05, 3484}, + {0x5e06, 1608}, + {0x5e08, 3389}, + {0x5e0a, 0}, + {0x5e0b, 1}, + {0x5e0c, 3856}, + {0x5e0e, 0}, + {0x5e0f, 5534}, + {0x5e10, 4459}, + {0x5e11, 5537}, + {0x5e13, 0}, + {0x5e14, 5536}, + {0x5e15, 2946}, + {0x5e16, 3662}, + {0x5e18, 2554}, + {0x5e19, 5535}, + {0x5e1a, 4578}, + {0x5e1b, 1142}, + {0x5e1c, 4547}, + {0x5e1d, 1468}, + {0x5e1f, 0}, + {0x5e20, 1}, + {0x5e21, 2}, + {0x5e22, 3}, + {0x5e23, 4}, + {0x5e24, 5}, + {0x5e25, 8515}, + {0x5e26, 1403}, + {0x5e27, 4512}, + {0x5e29, 0}, + {0x5e2a, 1}, + {0x5e2b, 8489}, + {0x5e2d, 3868}, + {0x5e2e, 1018}, + {0x5e30, 0}, + {0x5e31, 5538}, + {0x5e33, 8823}, + {0x5e35, 0}, + {0x5e36, 7847}, + {0x5e37, 5541}, + {0x5e38, 1224}, + {0x5e3a, 0}, + {0x5e3b, 5539}, + {0x5e3c, 5540}, + {0x5e3d, 2742}, + {0x5e3f, 0}, + {0x5e40, 8837}, + {0x5e42, 2786}, + {0x5e43, 9092}, + {0x5e44, 5542}, + {0x5e45, 1686}, + {0x5e47, 0}, + {0x5e48, 1}, + {0x5e49, 2}, + {0x5e4a, 3}, + {0x5e4b, 4}, + {0x5e4c, 2020}, + {0x5e4e, 0}, + {0x5e4f, 1}, + {0x5e50, 2}, + {0x5e51, 3}, + {0x5e52, 4}, + {0x5e53, 5}, + {0x5e54, 5543}, + {0x5e55, 2846}, + {0x5e57, 9095}, + {0x5e58, 9094}, + {0x5e5a, 0}, + {0x5e5b, 5544}, + {0x5e5d, 0}, + {0x5e5e, 5545}, + {0x5e5f, 8848}, + {0x5e61, 5546}, + {0x5e62, 1332}, + {0x5e63, 7748}, + {0x5e65, 0}, + {0x5e66, 1}, + {0x5e67, 2}, + {0x5e68, 3}, + {0x5e69, 4}, + {0x5e6a, 5}, + {0x5e6b, 7730}, + {0x5e6c, 9093}, + {0x5e6e, 0}, + {0x5e6f, 1}, + {0x5e70, 2}, + {0x5e71, 3}, + {0x5e72, 1732}, + {0x5e73, 3036}, + {0x5e74, 2893}, + {0x5e76, 1129}, + {0x5e78, 3997}, + {0x5e79, 7955}, + {0x5e7a, 6163}, + {0x5e7b, 2008}, + {0x5e7c, 4284}, + {0x5e7d, 4265}, + {0x5e7e, 8051}, + {0x5e7f, 1852}, + {0x5e80, 5681}, + {0x5e82, 0}, + {0x5e83, 1}, + {0x5e84, 4620}, + {0x5e86, 3177}, + {0x5e87, 1084}, + {0x5e89, 0}, + {0x5e8a, 1333}, + {0x5e8b, 5683}, + {0x5e8d, 0}, + {0x5e8e, 1}, + {0x5e8f, 4029}, + {0x5e90, 2645}, + {0x5e91, 5682}, + {0x5e93, 2415}, + {0x5e94, 4235}, + {0x5e95, 1464}, + {0x5e96, 5684}, + {0x5e97, 1483}, + {0x5e99, 2802}, + {0x5e9a, 1784}, + {0x5e9c, 1705}, + {0x5e9e, 2964}, + {0x5e9f, 1644}, + {0x5ea0, 5686}, + {0x5ea2, 0}, + {0x5ea3, 1}, + {0x5ea4, 2}, + {0x5ea5, 5685}, + {0x5ea6, 1543}, + {0x5ea7, 4694}, + {0x5ea9, 0}, + {0x5eaa, 1}, + {0x5eab, 8160}, + {0x5ead, 3670}, + {0x5eaf, 0}, + {0x5eb0, 1}, + {0x5eb1, 2}, + {0x5eb2, 3}, + {0x5eb3, 5690}, + {0x5eb5, 5688}, + {0x5eb6, 3475}, + {0x5eb7, 2370}, + {0x5eb8, 4254}, + {0x5eb9, 5687}, + {0x5ebb, 0}, + {0x5ebc, 1}, + {0x5ebd, 2}, + {0x5ebe, 5689}, + {0x5ec0, 0}, + {0x5ec1, 1}, + {0x5ec2, 2}, + {0x5ec3, 3}, + {0x5ec4, 4}, + {0x5ec5, 5}, + {0x5ec6, 6}, + {0x5ec7, 7}, + {0x5ec8, 8}, + {0x5ec9, 2551}, + {0x5eca, 2483}, + {0x5ecc, 0}, + {0x5ecd, 1}, + {0x5ece, 2}, + {0x5ecf, 3}, + {0x5ed0, 4}, + {0x5ed1, 5693}, + {0x5ed2, 5692}, + {0x5ed3, 2453}, + {0x5ed5, 0}, + {0x5ed6, 2583}, + {0x5ed8, 0}, + {0x5ed9, 1}, + {0x5eda, 2}, + {0x5edb, 5694}, + {0x5edd, 0}, + {0x5ede, 1}, + {0x5edf, 8327}, + {0x5ee0, 7800}, + {0x5ee1, 9134}, + {0x5ee2, 7926}, + {0x5ee3, 7985}, + {0x5ee5, 0}, + {0x5ee6, 1}, + {0x5ee7, 2}, + {0x5ee8, 5695}, + {0x5eea, 5696}, + {0x5eec, 8261}, + {0x5eee, 0}, + {0x5eef, 1}, + {0x5ef0, 2}, + {0x5ef1, 3}, + {0x5ef2, 4}, + {0x5ef3, 8568}, + {0x5ef4, 5016}, + {0x5ef6, 4092}, + {0x5ef7, 3667}, + {0x5ef9, 0}, + {0x5efa, 2169}, + {0x5efc, 0}, + {0x5efd, 1}, + {0x5efe, 5293}, + {0x5eff, 4699}, + {0x5f00, 2359}, + {0x5f01, 5021}, + {0x5f02, 4211}, + {0x5f03, 3097}, + {0x5f04, 2923}, + {0x5f06, 0}, + {0x5f07, 1}, + {0x5f08, 5294}, + {0x5f0a, 1088}, + {0x5f0b, 5366}, + {0x5f0d, 0}, + {0x5f0e, 1}, + {0x5f0f, 3412}, + {0x5f11, 5369}, + {0x5f13, 1798}, + {0x5f15, 4228}, + {0x5f17, 1696}, + {0x5f18, 1954}, + {0x5f1a, 0}, + {0x5f1b, 1279}, + {0x5f1d, 0}, + {0x5f1e, 1}, + {0x5f1f, 1469}, + {0x5f20, 4454}, + {0x5f22, 0}, + {0x5f23, 1}, + {0x5f24, 2}, + {0x5f25, 2779}, + {0x5f26, 3903}, + {0x5f27, 1974}, + {0x5f29, 5999}, + {0x5f2a, 5998}, + {0x5f2c, 0}, + {0x5f2d, 6000}, + {0x5f2f, 3733}, + {0x5f31, 3280}, + {0x5f33, 9205}, + {0x5f35, 8821}, + {0x5f37, 0}, + {0x5f38, 1}, + {0x5f39, 1424}, + {0x5f3a, 3132}, + {0x5f3c, 6002}, + {0x5f3e, 0}, + {0x5f3f, 1}, + {0x5f40, 6590}, + {0x5f42, 0}, + {0x5f43, 1}, + {0x5f44, 2}, + {0x5f45, 3}, + {0x5f46, 9838}, + {0x5f48, 7856}, + {0x5f4a, 0}, + {0x5f4b, 1}, + {0x5f4c, 8323}, + {0x5f4e, 8584}, + {0x5f50, 5986}, + {0x5f52, 1858}, + {0x5f53, 1426}, + {0x5f55, 2659}, + {0x5f56, 5988}, + {0x5f57, 5987}, + {0x5f58, 5989}, + {0x5f59, 9852}, + {0x5f5b, 0}, + {0x5f5c, 1}, + {0x5f5d, 4180}, + {0x5f5f, 0}, + {0x5f60, 1}, + {0x5f61, 5614}, + {0x5f62, 3993}, + {0x5f64, 3679}, + {0x5f66, 4110}, + {0x5f68, 0}, + {0x5f69, 1169}, + {0x5f6a, 1108}, + {0x5f6c, 1115}, + {0x5f6d, 2990}, + {0x5f6f, 0}, + {0x5f70, 4452}, + {0x5f71, 4245}, + {0x5f73, 5600}, + {0x5f75, 0}, + {0x5f76, 1}, + {0x5f77, 5601}, + {0x5f79, 4194}, + {0x5f7b, 1246}, + {0x5f7c, 1076}, + {0x5f7e, 0}, + {0x5f7f, 1}, + {0x5f80, 3754}, + {0x5f81, 4504}, + {0x5f82, 5602}, + {0x5f84, 2277}, + {0x5f85, 1408}, + {0x5f87, 5603}, + {0x5f88, 1939}, + {0x5f89, 5604}, + {0x5f8a, 1991}, + {0x5f8b, 2672}, + {0x5f8c, 5605}, + {0x5f8e, 0}, + {0x5f8f, 1}, + {0x5f90, 4023}, + {0x5f91, 8133}, + {0x5f92, 3694}, + {0x5f94, 0}, + {0x5f95, 5606}, + {0x5f97, 1444}, + {0x5f98, 2952}, + {0x5f99, 5607}, + {0x5f9b, 0}, + {0x5f9c, 5608}, + {0x5f9e, 7841}, + {0x5fa0, 9107}, + {0x5fa1, 4318}, + {0x5fa3, 0}, + {0x5fa4, 1}, + {0x5fa5, 2}, + {0x5fa6, 3}, + {0x5fa7, 4}, + {0x5fa8, 5609}, + {0x5fa9, 7947}, + {0x5faa, 4054}, + {0x5fac, 0}, + {0x5fad, 5610}, + {0x5fae, 3761}, + {0x5fb0, 0}, + {0x5fb1, 1}, + {0x5fb2, 2}, + {0x5fb3, 3}, + {0x5fb4, 4}, + {0x5fb5, 5611}, + {0x5fb7, 1443}, + {0x5fb9, 7804}, + {0x5fbb, 0}, + {0x5fbc, 5612}, + {0x5fbd, 2026}, + {0x5fbf, 0}, + {0x5fc0, 1}, + {0x5fc1, 2}, + {0x5fc2, 3}, + {0x5fc3, 3983}, + {0x5fc4, 5698}, + {0x5fc5, 1089}, + {0x5fc6, 4203}, + {0x5fc8, 0}, + {0x5fc9, 5699}, + {0x5fcb, 0}, + {0x5fcc, 2108}, + {0x5fcd, 3239}, + {0x5fcf, 5701}, + {0x5fd0, 6668}, + {0x5fd1, 6667}, + {0x5fd2, 5367}, + {0x5fd4, 0}, + {0x5fd5, 1}, + {0x5fd6, 5700}, + {0x5fd7, 4541}, + {0x5fd8, 3757}, + {0x5fd9, 2731}, + {0x5fdb, 0}, + {0x5fdc, 1}, + {0x5fdd, 5763}, + {0x5fdf, 0}, + {0x5fe0, 4561}, + {0x5fe1, 5705}, + {0x5fe3, 0}, + {0x5fe4, 5706}, + {0x5fe6, 0}, + {0x5fe7, 4268}, + {0x5fe9, 0}, + {0x5fea, 5710}, + {0x5feb, 2425}, + {0x5fed, 5711}, + {0x5fee, 5703}, + {0x5ff0, 0}, + {0x5ff1, 1253}, + {0x5ff3, 0}, + {0x5ff4, 1}, + {0x5ff5, 2897}, + {0x5ff7, 0}, + {0x5ff8, 5712}, + {0x5ffa, 0}, + {0x5ffb, 3982}, + {0x5ffd, 1965}, + {0x5ffe, 5707}, + {0x5fff, 1659}, + {0x6000, 1992}, + {0x6001, 3583}, + {0x6002, 3520}, + {0x6003, 5702}, + {0x6004, 5704}, + {0x6005, 5708}, + {0x6006, 5709}, + {0x6008, 0}, + {0x6009, 1}, + {0x600a, 5721}, + {0x600c, 0}, + {0x600d, 5718}, + {0x600e, 4408}, + {0x600f, 5717}, + {0x6011, 0}, + {0x6012, 2926}, + {0x6014, 4507}, + {0x6015, 2947}, + {0x6016, 1159}, + {0x6018, 0}, + {0x6019, 5713}, + {0x601b, 5716}, + {0x601c, 2552}, + {0x601d, 3505}, + {0x601f, 0}, + {0x6020, 1410}, + {0x6021, 5723}, + {0x6023, 0}, + {0x6024, 1}, + {0x6025, 2084}, + {0x6026, 5715}, + {0x6027, 3999}, + {0x6028, 4348}, + {0x6029, 5719}, + {0x602a, 1839}, + {0x602b, 5720}, + {0x602d, 0}, + {0x602e, 1}, + {0x602f, 3152}, + {0x6031, 0}, + {0x6032, 1}, + {0x6033, 2}, + {0x6034, 3}, + {0x6035, 5714}, + {0x6037, 0}, + {0x6038, 1}, + {0x6039, 2}, + {0x603a, 3}, + {0x603b, 4665}, + {0x603c, 6669}, + {0x603e, 0}, + {0x603f, 5722}, + {0x6041, 6673}, + {0x6042, 5728}, + {0x6043, 3432}, + {0x6045, 0}, + {0x6046, 1}, + {0x6047, 2}, + {0x6048, 3}, + {0x6049, 4}, + {0x604a, 5}, + {0x604b, 2558}, + {0x604d, 2021}, + {0x604f, 0}, + {0x6050, 2403}, + {0x6052, 1946}, + {0x6054, 0}, + {0x6055, 3478}, + {0x6057, 0}, + {0x6058, 1}, + {0x6059, 6674}, + {0x605a, 6671}, + {0x605c, 0}, + {0x605d, 6670}, + {0x605f, 0}, + {0x6060, 1}, + {0x6061, 2}, + {0x6062, 2027}, + {0x6063, 6675}, + {0x6064, 4031}, + {0x6066, 0}, + {0x6067, 6672}, + {0x6068, 1941}, + {0x6069, 1590}, + {0x606a, 5729}, + {0x606b, 1521}, + {0x606c, 3652}, + {0x606d, 1792}, + {0x606f, 3855}, + {0x6070, 3102}, + {0x6072, 0}, + {0x6073, 2399}, + {0x6075, 0}, + {0x6076, 1584}, + {0x6078, 5724}, + {0x6079, 5725}, + {0x607a, 5727}, + {0x607b, 5726}, + {0x607c, 2872}, + {0x607d, 5730}, + {0x607f, 4262}, + {0x6081, 0}, + {0x6082, 1}, + {0x6083, 5735}, + {0x6084, 3137}, + {0x6086, 0}, + {0x6087, 1}, + {0x6088, 2}, + {0x6089, 3857}, + {0x608b, 0}, + {0x608c, 5737}, + {0x608d, 1902}, + {0x608f, 0}, + {0x6090, 1}, + {0x6091, 2}, + {0x6092, 5736}, + {0x6094, 2031}, + {0x6096, 5731}, + {0x6098, 0}, + {0x6099, 1}, + {0x609a, 5732}, + {0x609b, 5738}, + {0x609d, 5734}, + {0x609f, 3841}, + {0x60a0, 4267}, + {0x60a2, 0}, + {0x60a3, 2001}, + {0x60a5, 0}, + {0x60a6, 4358}, + {0x60a8, 2909}, + {0x60aa, 0}, + {0x60ab, 6676}, + {0x60ac, 4039}, + {0x60ad, 5733}, + {0x60af, 2810}, + {0x60b1, 5741}, + {0x60b2, 1048}, + {0x60b4, 5746}, + {0x60b5, 9140}, + {0x60b6, 8318}, + {0x60b8, 2101}, + {0x60ba, 0}, + {0x60bb, 5740}, + {0x60bc, 1440}, + {0x60be, 0}, + {0x60bf, 1}, + {0x60c0, 2}, + {0x60c1, 3}, + {0x60c2, 4}, + {0x60c3, 5}, + {0x60c4, 6}, + {0x60c5, 3174}, + {0x60c6, 5744}, + {0x60c8, 0}, + {0x60c9, 1}, + {0x60ca, 2265}, + {0x60cb, 3744}, + {0x60cd, 0}, + {0x60ce, 1}, + {0x60cf, 2}, + {0x60d0, 3}, + {0x60d1, 2056}, + {0x60d3, 0}, + {0x60d4, 1}, + {0x60d5, 3643}, + {0x60d7, 0}, + {0x60d8, 5743}, + {0x60da, 5745}, + {0x60dc, 3860}, + {0x60dd, 5742}, + {0x60df, 3768}, + {0x60e0, 2034}, + {0x60e1, 7907}, + {0x60e3, 0}, + {0x60e4, 1}, + {0x60e5, 2}, + {0x60e6, 1484}, + {0x60e7, 2324}, + {0x60e8, 1177}, + {0x60e9, 1266}, + {0x60eb, 1058}, + {0x60ec, 5739}, + {0x60ed, 1176}, + {0x60ee, 1421}, + {0x60ef, 1848}, + {0x60f0, 1575}, + {0x60f1, 8341}, + {0x60f2, 9147}, + {0x60f3, 3928}, + {0x60f4, 5751}, + {0x60f6, 2017}, + {0x60f8, 0}, + {0x60f9, 3234}, + {0x60fa, 3989}, + {0x60fb, 9145}, + {0x60fd, 0}, + {0x60fe, 1}, + {0x60ff, 2}, + {0x6100, 5752}, + {0x6101, 1299}, + {0x6103, 0}, + {0x6104, 1}, + {0x6105, 2}, + {0x6106, 6677}, + {0x6108, 4319}, + {0x6109, 4297}, + {0x610b, 0}, + {0x610c, 1}, + {0x610d, 6678}, + {0x610e, 5753}, + {0x610f, 4201}, + {0x6111, 0}, + {0x6112, 1}, + {0x6113, 2}, + {0x6114, 3}, + {0x6115, 5749}, + {0x6117, 0}, + {0x6118, 1}, + {0x6119, 2}, + {0x611a, 4291}, + {0x611b, 7720}, + {0x611c, 9149}, + {0x611e, 0}, + {0x611f, 1739}, + {0x6120, 5747}, + {0x6122, 0}, + {0x6123, 5750}, + {0x6124, 1660}, + {0x6126, 5748}, + {0x6127, 2445}, + {0x6129, 0}, + {0x612a, 1}, + {0x612b, 5754}, + {0x612d, 0}, + {0x612e, 1}, + {0x612f, 2}, + {0x6130, 3}, + {0x6131, 4}, + {0x6132, 5}, + {0x6133, 6}, + {0x6134, 9141}, + {0x6136, 0}, + {0x6137, 9146}, + {0x6139, 0}, + {0x613a, 1}, + {0x613b, 2}, + {0x613c, 3}, + {0x613d, 4}, + {0x613e, 9139}, + {0x613f, 4347}, + {0x6141, 0}, + {0x6142, 1}, + {0x6143, 2}, + {0x6144, 3}, + {0x6145, 4}, + {0x6146, 5}, + {0x6147, 6}, + {0x6148, 1355}, + {0x614a, 5755}, + {0x614b, 8546}, + {0x614c, 2010}, + {0x614e, 3376}, + {0x6150, 0}, + {0x6151, 3358}, + {0x6153, 0}, + {0x6154, 1}, + {0x6155, 2848}, + {0x6157, 0}, + {0x6158, 7774}, + {0x615a, 7773}, + {0x615c, 0}, + {0x615d, 6679}, + {0x615f, 9143}, + {0x6161, 0}, + {0x6162, 2724}, + {0x6163, 7983}, + {0x6164, 9439}, + {0x6166, 0}, + {0x6167, 2032}, + {0x6168, 2363}, + {0x616a, 9138}, + {0x616b, 8526}, + {0x616d, 0}, + {0x616e, 8274}, + {0x6170, 3790}, + {0x6172, 0}, + {0x6173, 9148}, + {0x6175, 5756}, + {0x6176, 8427}, + {0x6177, 2371}, + {0x6179, 0}, + {0x617a, 1}, + {0x617b, 2}, + {0x617c, 3}, + {0x617d, 4}, + {0x617e, 5}, + {0x617f, 6}, + {0x6180, 7}, + {0x6181, 8}, + {0x6182, 8754}, + {0x6184, 0}, + {0x6185, 1}, + {0x6186, 2}, + {0x6187, 3}, + {0x6188, 4}, + {0x6189, 5}, + {0x618a, 7743}, + {0x618b, 1112}, + {0x618d, 0}, + {0x618e, 4410}, + {0x6190, 8219}, + {0x6191, 8380}, + {0x6192, 9150}, + {0x6194, 5758}, + {0x6196, 0}, + {0x6197, 1}, + {0x6198, 2}, + {0x6199, 3}, + {0x619a, 7854}, + {0x619c, 0}, + {0x619d, 6681}, + {0x619f, 0}, + {0x61a0, 1}, + {0x61a1, 2}, + {0x61a2, 3}, + {0x61a3, 4}, + {0x61a4, 7931}, + {0x61a6, 0}, + {0x61a7, 5759}, + {0x61a8, 1888}, + {0x61a9, 6680}, + {0x61ab, 8329}, + {0x61ac, 5757}, + {0x61ae, 9137}, + {0x61b0, 0}, + {0x61b1, 1}, + {0x61b2, 8644}, + {0x61b4, 0}, + {0x61b5, 1}, + {0x61b6, 8724}, + {0x61b7, 5760}, + {0x61b9, 0}, + {0x61ba, 1}, + {0x61bb, 2}, + {0x61bc, 3}, + {0x61bd, 4}, + {0x61be, 1901}, + {0x61c0, 0}, + {0x61c1, 1}, + {0x61c2, 1517}, + {0x61c4, 0}, + {0x61c5, 1}, + {0x61c6, 2}, + {0x61c7, 8158}, + {0x61c8, 3971}, + {0x61c9, 8739}, + {0x61ca, 974}, + {0x61cb, 6682}, + {0x61cc, 9142}, + {0x61ce, 0}, + {0x61cf, 1}, + {0x61d0, 2}, + {0x61d1, 6683}, + {0x61d2, 2476}, + {0x61d4, 5761}, + {0x61d6, 0}, + {0x61d7, 1}, + {0x61d8, 2}, + {0x61d9, 3}, + {0x61da, 4}, + {0x61db, 5}, + {0x61dc, 6}, + {0x61dd, 7}, + {0x61de, 9868}, + {0x61df, 9438}, + {0x61e1, 0}, + {0x61e2, 1}, + {0x61e3, 9440}, + {0x61e5, 0}, + {0x61e6, 2932}, + {0x61e8, 9144}, + {0x61ea, 0}, + {0x61eb, 1}, + {0x61ec, 2}, + {0x61ed, 3}, + {0x61ee, 4}, + {0x61ef, 5}, + {0x61f0, 6}, + {0x61f1, 7}, + {0x61f2, 7809}, + {0x61f4, 0}, + {0x61f5, 5762}, + {0x61f6, 8190}, + {0x61f7, 8017}, + {0x61f8, 8673}, + {0x61fa, 9136}, + {0x61fc, 8142}, + {0x61fe, 8478}, + {0x61ff, 5088}, + {0x6200, 8225}, + {0x6202, 0}, + {0x6203, 1}, + {0x6204, 2}, + {0x6205, 3}, + {0x6206, 6684}, + {0x6207, 9441}, + {0x6208, 1765}, + {0x620a, 3835}, + {0x620b, 6393}, + {0x620c, 4018}, + {0x620d, 3472}, + {0x620e, 3249}, + {0x620f, 3876}, + {0x6210, 1262}, + {0x6211, 3809}, + {0x6212, 2229}, + {0x6214, 9379}, + {0x6215, 5790}, + {0x6216, 2055}, + {0x6217, 6394}, + {0x6218, 4446}, + {0x621a, 3068}, + {0x621b, 6395}, + {0x621d, 0}, + {0x621e, 1}, + {0x621f, 6396}, + {0x6221, 6398}, + {0x6222, 6397}, + {0x6224, 6400}, + {0x6225, 6399}, + {0x6227, 9380}, + {0x6229, 0}, + {0x622a, 2217}, + {0x622c, 6401}, + {0x622e, 2661}, + {0x6230, 8819}, + {0x6232, 8624}, + {0x6233, 1348}, + {0x6234, 1402}, + {0x6236, 0}, + {0x6237, 1980}, + {0x6239, 0}, + {0x623a, 1}, + {0x623b, 2}, + {0x623c, 3}, + {0x623d, 6644}, + {0x623e, 6643}, + {0x623f, 1628}, + {0x6240, 3566}, + {0x6241, 1099}, + {0x6243, 6645}, + {0x6245, 0}, + {0x6246, 1}, + {0x6247, 3329}, + {0x6248, 6646}, + {0x6249, 6647}, + {0x624b, 3437}, + {0x624c, 5306}, + {0x624d, 1164}, + {0x624e, 4413}, + {0x6250, 0}, + {0x6251, 3050}, + {0x6252, 978}, + {0x6253, 1397}, + {0x6254, 3246}, + {0x6256, 0}, + {0x6257, 1}, + {0x6258, 3713}, + {0x625a, 0}, + {0x625b, 2373}, + {0x625d, 0}, + {0x625e, 1}, + {0x625f, 2}, + {0x6260, 3}, + {0x6261, 4}, + {0x6262, 5}, + {0x6263, 2408}, + {0x6265, 0}, + {0x6266, 3105}, + {0x6267, 4531}, + {0x6269, 2452}, + {0x626a, 5307}, + {0x626b, 3297}, + {0x626c, 4120}, + {0x626d, 2917}, + {0x626e, 1010}, + {0x626f, 1243}, + {0x6270, 3232}, + {0x6272, 0}, + {0x6273, 1005}, + {0x6275, 0}, + {0x6276, 1683}, + {0x6278, 0}, + {0x6279, 3003}, + {0x627b, 0}, + {0x627c, 1586}, + {0x627e, 4467}, + {0x627f, 1269}, + {0x6280, 2095}, + {0x6282, 0}, + {0x6283, 1}, + {0x6284, 1234}, + {0x6286, 0}, + {0x6287, 1}, + {0x6288, 2}, + {0x6289, 2336}, + {0x628a, 988}, + {0x628c, 0}, + {0x628d, 1}, + {0x628e, 2}, + {0x628f, 3}, + {0x6290, 4}, + {0x6291, 4189}, + {0x6292, 3450}, + {0x6293, 4610}, + {0x6295, 3687}, + {0x6296, 1525}, + {0x6297, 2374}, + {0x6298, 4476}, + {0x629a, 1698}, + {0x629b, 2968}, + {0x629d, 0}, + {0x629e, 1}, + {0x629f, 5308}, + {0x62a0, 2406}, + {0x62a1, 2684}, + {0x62a2, 3133}, + {0x62a4, 1977}, + {0x62a5, 1041}, + {0x62a7, 0}, + {0x62a8, 2987}, + {0x62aa, 0}, + {0x62ab, 3004}, + {0x62ac, 3578}, + {0x62ae, 0}, + {0x62af, 1}, + {0x62b0, 2}, + {0x62b1, 1040}, + {0x62b3, 0}, + {0x62b4, 1}, + {0x62b5, 1463}, + {0x62b7, 0}, + {0x62b8, 1}, + {0x62b9, 2827}, + {0x62bb, 5309}, + {0x62bc, 4067}, + {0x62bd, 1294}, + {0x62bf, 2807}, + {0x62c1, 0}, + {0x62c2, 1684}, + {0x62c4, 4595}, + {0x62c5, 1412}, + {0x62c6, 1207}, + {0x62c7, 2839}, + {0x62c8, 2892}, + {0x62c9, 2456}, + {0x62ca, 5310}, + {0x62cc, 1011}, + {0x62cd, 2949}, + {0x62ce, 2601}, + {0x62d0, 1838}, + {0x62d2, 2315}, + {0x62d3, 3721}, + {0x62d4, 985}, + {0x62d6, 3712}, + {0x62d7, 5312}, + {0x62d8, 2303}, + {0x62d9, 4635}, + {0x62da, 5311}, + {0x62db, 4465}, + {0x62dc, 1000}, + {0x62de, 0}, + {0x62df, 2885}, + {0x62e1, 0}, + {0x62e2, 2634}, + {0x62e3, 2147}, + {0x62e5, 4250}, + {0x62e6, 2468}, + {0x62e7, 2914}, + {0x62e8, 1133}, + {0x62e9, 4404}, + {0x62eb, 0}, + {0x62ec, 2451}, + {0x62ed, 3418}, + {0x62ee, 5313}, + {0x62ef, 4509}, + {0x62f1, 1801}, + {0x62f3, 3208}, + {0x62f4, 3486}, + {0x62f6, 5315}, + {0x62f7, 2378}, + {0x62f9, 0}, + {0x62fa, 1}, + {0x62fb, 2}, + {0x62fc, 3027}, + {0x62fd, 4612}, + {0x62fe, 3399}, + {0x62ff, 2854}, + {0x6301, 1275}, + {0x6302, 1835}, + {0x6304, 0}, + {0x6305, 1}, + {0x6306, 2}, + {0x6307, 4535}, + {0x6308, 6478}, + {0x6309, 959}, + {0x630b, 0}, + {0x630c, 1}, + {0x630d, 2}, + {0x630e, 2419}, + {0x6310, 0}, + {0x6311, 3655}, + {0x6313, 0}, + {0x6314, 1}, + {0x6315, 2}, + {0x6316, 3723}, + {0x6318, 0}, + {0x6319, 1}, + {0x631a, 4542}, + {0x631b, 2677}, + {0x631d, 3805}, + {0x631e, 3573}, + {0x631f, 3961}, + {0x6320, 2870}, + {0x6321, 1427}, + {0x6322, 5314}, + {0x6323, 4502}, + {0x6324, 2090}, + {0x6325, 2024}, + {0x6327, 0}, + {0x6328, 943}, + {0x632a, 2931}, + {0x632b, 1391}, + {0x632d, 0}, + {0x632e, 1}, + {0x632f, 4498}, + {0x6331, 0}, + {0x6332, 6479}, + {0x6334, 0}, + {0x6335, 1}, + {0x6336, 2}, + {0x6337, 3}, + {0x6338, 4}, + {0x6339, 5316}, + {0x633a, 3671}, + {0x633c, 0}, + {0x633d, 3741}, + {0x633e, 8657}, + {0x6340, 0}, + {0x6341, 1}, + {0x6342, 3829}, + {0x6343, 5318}, + {0x6345, 3682}, + {0x6346, 2449}, + {0x6348, 0}, + {0x6349, 4634}, + {0x634b, 5317}, + {0x634c, 977}, + {0x634d, 1899}, + {0x634e, 3340}, + {0x634f, 2902}, + {0x6350, 2327}, + {0x6352, 0}, + {0x6353, 1}, + {0x6354, 2}, + {0x6355, 1149}, + {0x6357, 0}, + {0x6358, 1}, + {0x6359, 2}, + {0x635a, 3}, + {0x635b, 4}, + {0x635c, 5}, + {0x635d, 6}, + {0x635e, 2487}, + {0x635f, 3557}, + {0x6361, 2148}, + {0x6362, 2000}, + {0x6363, 1432}, + {0x6365, 0}, + {0x6366, 1}, + {0x6367, 2998}, + {0x6368, 8476}, + {0x6369, 5328}, + {0x636b, 9053}, + {0x636d, 5325}, + {0x636e, 2316}, + {0x6370, 0}, + {0x6371, 5321}, + {0x6372, 9858}, + {0x6374, 0}, + {0x6375, 1}, + {0x6376, 1338}, + {0x6377, 2222}, + {0x6379, 0}, + {0x637a, 5322}, + {0x637b, 2896}, + {0x637d, 0}, + {0x637e, 1}, + {0x637f, 2}, + {0x6380, 3891}, + {0x6382, 1473}, + {0x6383, 8461}, + {0x6384, 8282}, + {0x6386, 0}, + {0x6387, 1565}, + {0x6388, 3441}, + {0x6389, 1493}, + {0x638a, 5327}, + {0x638c, 4455}, + {0x638e, 5323}, + {0x638f, 3616}, + {0x6390, 3101}, + {0x6392, 2950}, + {0x6394, 0}, + {0x6395, 1}, + {0x6396, 4155}, + {0x6398, 2337}, + {0x639a, 0}, + {0x639b, 1}, + {0x639c, 2}, + {0x639d, 3}, + {0x639e, 4}, + {0x639f, 5}, + {0x63a0, 2682}, + {0x63a2, 3600}, + {0x63a3, 1245}, + {0x63a5, 2212}, + {0x63a7, 2405}, + {0x63a8, 3703}, + {0x63a9, 4099}, + {0x63aa, 1390}, + {0x63ac, 5326}, + {0x63ad, 5319}, + {0x63ae, 5329}, + {0x63b0, 6480}, + {0x63b2, 0}, + {0x63b3, 2647}, + {0x63b4, 5324}, + {0x63b6, 0}, + {0x63b7, 4543}, + {0x63b8, 1416}, + {0x63ba, 1211}, + {0x63bc, 5330}, + {0x63be, 5340}, + {0x63c0, 8077}, + {0x63c2, 0}, + {0x63c3, 1}, + {0x63c4, 5335}, + {0x63c6, 5339}, + {0x63c8, 0}, + {0x63c9, 3259}, + {0x63cb, 0}, + {0x63cc, 1}, + {0x63cd, 4670}, + {0x63ce, 5337}, + {0x63cf, 2797}, + {0x63d0, 3636}, + {0x63d2, 1196}, + {0x63d4, 0}, + {0x63d5, 1}, + {0x63d6, 4165}, + {0x63d8, 0}, + {0x63d9, 1}, + {0x63da, 8703}, + {0x63dc, 0}, + {0x63dd, 1}, + {0x63de, 5336}, + {0x63e0, 5333}, + {0x63e1, 3812}, + {0x63e3, 1322}, + {0x63e5, 0}, + {0x63e6, 1}, + {0x63e7, 2}, + {0x63e8, 3}, + {0x63e9, 2360}, + {0x63ea, 2285}, + {0x63ec, 0}, + {0x63ed, 2211}, + {0x63ee, 8024}, + {0x63f0, 0}, + {0x63f1, 1}, + {0x63f2, 5331}, + {0x63f4, 4337}, + {0x63f6, 5320}, + {0x63f8, 5332}, + {0x63fa, 0}, + {0x63fb, 1}, + {0x63fc, 2}, + {0x63fd, 2474}, + {0x63ff, 5334}, + {0x6400, 1210}, + {0x6401, 1764}, + {0x6402, 2638}, + {0x6404, 0}, + {0x6405, 2194}, + {0x6407, 0}, + {0x6408, 1}, + {0x6409, 2}, + {0x640a, 3}, + {0x640b, 5343}, + {0x640c, 5346}, + {0x640d, 8539}, + {0x640f, 1138}, + {0x6410, 1319}, + {0x6412, 0}, + {0x6413, 1389}, + {0x6414, 3295}, + {0x6416, 0}, + {0x6417, 7862}, + {0x6419, 0}, + {0x641a, 1}, + {0x641b, 5344}, + {0x641c, 3526}, + {0x641e, 1758}, + {0x6420, 5345}, + {0x6421, 5348}, + {0x6423, 0}, + {0x6424, 1}, + {0x6425, 2}, + {0x6426, 5347}, + {0x6428, 0}, + {0x6429, 1}, + {0x642a, 3605}, + {0x642c, 1004}, + {0x642d, 1393}, + {0x642f, 0}, + {0x6430, 1}, + {0x6431, 2}, + {0x6432, 3}, + {0x6433, 4}, + {0x6434, 5942}, + {0x6436, 8411}, + {0x6438, 0}, + {0x6439, 1}, + {0x643a, 3962}, + {0x643c, 0}, + {0x643d, 1202}, + {0x643f, 6481}, + {0x6441, 5342}, + {0x6443, 0}, + {0x6444, 3356}, + {0x6445, 5341}, + {0x6446, 997}, + {0x6447, 4136}, + {0x6448, 1120}, + {0x644a, 3586}, + {0x644c, 0}, + {0x644d, 1}, + {0x644e, 2}, + {0x644f, 3}, + {0x6450, 4}, + {0x6451, 9056}, + {0x6452, 5338}, + {0x6454, 3481}, + {0x6456, 0}, + {0x6457, 1}, + {0x6458, 4427}, + {0x645a, 0}, + {0x645b, 1}, + {0x645c, 9057}, + {0x645e, 5349}, + {0x645f, 8256}, + {0x6461, 0}, + {0x6462, 1}, + {0x6463, 2}, + {0x6464, 3}, + {0x6465, 4}, + {0x6466, 5}, + {0x6467, 1376}, + {0x6469, 2825}, + {0x646b, 0}, + {0x646c, 1}, + {0x646d, 5351}, + {0x646f, 8846}, + {0x6471, 0}, + {0x6472, 1}, + {0x6473, 8159}, + {0x6475, 0}, + {0x6476, 9054}, + {0x6478, 2819}, + {0x6479, 2820}, + {0x647a, 5353}, + {0x647b, 7786}, + {0x647d, 0}, + {0x647e, 1}, + {0x647f, 2}, + {0x6480, 3}, + {0x6481, 4}, + {0x6482, 2581}, + {0x6484, 5350}, + {0x6485, 2334}, + {0x6487, 3025}, + {0x6488, 8194}, + {0x648a, 0}, + {0x648b, 1}, + {0x648c, 2}, + {0x648d, 3}, + {0x648e, 4}, + {0x648f, 5}, + {0x6490, 6}, + {0x6491, 1258}, + {0x6492, 3281}, + {0x6493, 8339}, + {0x6495, 3503}, + {0x6496, 5352}, + {0x6498, 0}, + {0x6499, 5356}, + {0x649b, 0}, + {0x649c, 1}, + {0x649d, 2}, + {0x649e, 4623}, + {0x649f, 9055}, + {0x64a1, 0}, + {0x64a2, 1}, + {0x64a3, 7852}, + {0x64a4, 1244}, + {0x64a5, 7764}, + {0x64a7, 0}, + {0x64a8, 1}, + {0x64a9, 2572}, + {0x64ab, 7944}, + {0x64ac, 3144}, + {0x64ad, 1132}, + {0x64ae, 1388}, + {0x64b0, 4616}, + {0x64b2, 8384}, + {0x64b3, 9058}, + {0x64b5, 2895}, + {0x64b7, 5354}, + {0x64b8, 5355}, + {0x64ba, 5357}, + {0x64bb, 8544}, + {0x64bc, 1898}, + {0x64be, 8605}, + {0x64bf, 8078}, + {0x64c0, 5358}, + {0x64c1, 8749}, + {0x64c2, 2505}, + {0x64c4, 8263}, + {0x64c5, 3324}, + {0x64c7, 8802}, + {0x64c9, 0}, + {0x64ca, 8039}, + {0x64cb, 7858}, + {0x64cd, 1184}, + {0x64ce, 3171}, + {0x64d0, 5359}, + {0x64d2, 3161}, + {0x64d4, 7849}, + {0x64d6, 0}, + {0x64d7, 5360}, + {0x64d8, 6482}, + {0x64da, 8140}, + {0x64dc, 0}, + {0x64dd, 1}, + {0x64de, 3528}, + {0x64e0, 8050}, + {0x64e2, 5362}, + {0x64e4, 5361}, + {0x64e6, 1160}, + {0x64e8, 0}, + {0x64e9, 1}, + {0x64ea, 2}, + {0x64eb, 3}, + {0x64ec, 8344}, + {0x64ee, 0}, + {0x64ef, 7762}, + {0x64f0, 8356}, + {0x64f1, 7964}, + {0x64f2, 8847}, + {0x64f4, 8173}, + {0x64f6, 0}, + {0x64f7, 9061}, + {0x64f9, 0}, + {0x64fa, 7725}, + {0x64fb, 8530}, + {0x64fc, 9062}, + {0x64fe, 8442}, + {0x6500, 2955}, + {0x6502, 0}, + {0x6503, 1}, + {0x6504, 9059}, + {0x6506, 8346}, + {0x6508, 0}, + {0x6509, 5363}, + {0x650b, 0}, + {0x650c, 1}, + {0x650d, 2}, + {0x650e, 3}, + {0x650f, 8252}, + {0x6511, 0}, + {0x6512, 4383}, + {0x6514, 8182}, + {0x6516, 9060}, + {0x6518, 3228}, + {0x6519, 7785}, + {0x651b, 9063}, + {0x651d, 8477}, + {0x651f, 0}, + {0x6520, 1}, + {0x6521, 2}, + {0x6522, 8793}, + {0x6523, 8278}, + {0x6524, 8547}, + {0x6525, 5364}, + {0x6527, 0}, + {0x6528, 1}, + {0x6529, 2}, + {0x652a, 8105}, + {0x652b, 2335}, + {0x652c, 8188}, + {0x652e, 5365}, + {0x652f, 4518}, + {0x6531, 0}, + {0x6532, 1}, + {0x6533, 2}, + {0x6534, 6409}, + {0x6535, 6502}, + {0x6536, 3436}, + {0x6538, 4786}, + {0x6539, 1727}, + {0x653b, 1790}, + {0x653d, 0}, + {0x653e, 1634}, + {0x653f, 4511}, + {0x6541, 0}, + {0x6542, 1}, + {0x6543, 2}, + {0x6544, 3}, + {0x6545, 1827}, + {0x6547, 0}, + {0x6548, 3954}, + {0x6549, 7371}, + {0x654b, 0}, + {0x654c, 1457}, + {0x654e, 0}, + {0x654f, 2809}, + {0x6551, 2295}, + {0x6553, 0}, + {0x6554, 1}, + {0x6555, 6503}, + {0x6556, 968}, + {0x6557, 7726}, + {0x6559, 2205}, + {0x655b, 2555}, + {0x655d, 1087}, + {0x655e, 1229}, + {0x6560, 0}, + {0x6561, 1}, + {0x6562, 1741}, + {0x6563, 3291}, + {0x6565, 0}, + {0x6566, 1559}, + {0x6568, 0}, + {0x6569, 1}, + {0x656a, 2}, + {0x656b, 6504}, + {0x656c, 2275}, + {0x656e, 0}, + {0x656f, 1}, + {0x6570, 3476}, + {0x6572, 3136}, + {0x6574, 4508}, + {0x6575, 7868}, + {0x6577, 1680}, + {0x6578, 8514}, + {0x657a, 0}, + {0x657b, 1}, + {0x657c, 2}, + {0x657d, 3}, + {0x657e, 4}, + {0x657f, 5}, + {0x6580, 6}, + {0x6581, 7}, + {0x6582, 8222}, + {0x6583, 7747}, + {0x6585, 0}, + {0x6586, 1}, + {0x6587, 3795}, + {0x6589, 0}, + {0x658a, 1}, + {0x658b, 4428}, + {0x658c, 1116}, + {0x658e, 0}, + {0x658f, 1}, + {0x6590, 6593}, + {0x6591, 1002}, + {0x6593, 6595}, + {0x6595, 9428}, + {0x6597, 1526}, + {0x6599, 2584}, + {0x659b, 7510}, + {0x659c, 3964}, + {0x659e, 0}, + {0x659f, 4486}, + {0x65a1, 3810}, + {0x65a3, 0}, + {0x65a4, 2240}, + {0x65a5, 1287}, + {0x65a7, 1702}, + {0x65a9, 4439}, + {0x65ab, 6697}, + {0x65ac, 8815}, + {0x65ad, 1550}, + {0x65af, 3502}, + {0x65b0, 3981}, + {0x65b2, 0}, + {0x65b3, 1}, + {0x65b4, 2}, + {0x65b5, 3}, + {0x65b6, 4}, + {0x65b7, 7895}, + {0x65b9, 1626}, + {0x65bb, 0}, + {0x65bc, 6596}, + {0x65bd, 3392}, + {0x65bf, 0}, + {0x65c0, 1}, + {0x65c1, 2965}, + {0x65c3, 6599}, + {0x65c4, 6598}, + {0x65c5, 2666}, + {0x65c6, 6597}, + {0x65c8, 0}, + {0x65c9, 1}, + {0x65ca, 2}, + {0x65cb, 4040}, + {0x65cc, 6600}, + {0x65ce, 6601}, + {0x65cf, 4674}, + {0x65d1, 0}, + {0x65d2, 6602}, + {0x65d4, 0}, + {0x65d5, 1}, + {0x65d6, 6603}, + {0x65d7, 3083}, + {0x65d9, 0}, + {0x65da, 1}, + {0x65db, 2}, + {0x65dc, 3}, + {0x65dd, 4}, + {0x65de, 5}, + {0x65df, 6}, + {0x65e0, 3821}, + {0x65e2, 2107}, + {0x65e4, 0}, + {0x65e5, 3248}, + {0x65e6, 1418}, + {0x65e7, 2296}, + {0x65e8, 4539}, + {0x65e9, 4394}, + {0x65eb, 0}, + {0x65ec, 4055}, + {0x65ed, 4028}, + {0x65ee, 6410}, + {0x65ef, 6411}, + {0x65f0, 6412}, + {0x65f1, 1900}, + {0x65f3, 0}, + {0x65f4, 1}, + {0x65f5, 2}, + {0x65f6, 3400}, + {0x65f7, 2434}, + {0x65f9, 0}, + {0x65fa, 3755}, + {0x65fc, 0}, + {0x65fd, 1}, + {0x65fe, 2}, + {0x65ff, 3}, + {0x6600, 6418}, + {0x6602, 965}, + {0x6603, 6416}, + {0x6605, 0}, + {0x6606, 2448}, + {0x6608, 0}, + {0x6609, 1}, + {0x660a, 6413}, + {0x660c, 1220}, + {0x660e, 2812}, + {0x660f, 2045}, + {0x6611, 0}, + {0x6612, 1}, + {0x6613, 4190}, + {0x6614, 3843}, + {0x6615, 6417}, + {0x6617, 0}, + {0x6618, 1}, + {0x6619, 6414}, + {0x661b, 0}, + {0x661c, 1}, + {0x661d, 6421}, + {0x661f, 3986}, + {0x6620, 4248}, + {0x6622, 0}, + {0x6623, 1}, + {0x6624, 2}, + {0x6625, 1341}, + {0x6627, 2758}, + {0x6628, 4687}, + {0x662a, 0}, + {0x662b, 1}, + {0x662c, 2}, + {0x662d, 4466}, + {0x662f, 3422}, + {0x6631, 6423}, + {0x6633, 0}, + {0x6634, 6422}, + {0x6635, 6425}, + {0x6636, 6424}, + {0x6638, 0}, + {0x6639, 1}, + {0x663a, 2}, + {0x663b, 3}, + {0x663c, 4582}, + {0x663e, 3905}, + {0x6640, 0}, + {0x6641, 6429}, + {0x6642, 8493}, + {0x6643, 2019}, + {0x6645, 0}, + {0x6646, 1}, + {0x6647, 2}, + {0x6648, 3}, + {0x6649, 4}, + {0x664a, 5}, + {0x664b, 2251}, + {0x664c, 3335}, + {0x664e, 0}, + {0x664f, 6430}, + {0x6651, 0}, + {0x6652, 3314}, + {0x6653, 3947}, + {0x6654, 6428}, + {0x6655, 4369}, + {0x6656, 6431}, + {0x6657, 6433}, + {0x6659, 0}, + {0x665a, 3742}, + {0x665c, 0}, + {0x665d, 8859}, + {0x665f, 6427}, + {0x6661, 6432}, + {0x6663, 0}, + {0x6664, 3837}, + {0x6666, 2035}, + {0x6668, 1252}, + {0x666a, 0}, + {0x666b, 1}, + {0x666c, 2}, + {0x666d, 3}, + {0x666e, 3060}, + {0x666f, 2271}, + {0x6670, 3849}, + {0x6672, 0}, + {0x6673, 1}, + {0x6674, 3172}, + {0x6676, 2262}, + {0x6677, 6434}, + {0x6679, 0}, + {0x667a, 4550}, + {0x667c, 0}, + {0x667d, 1}, + {0x667e, 2569}, + {0x6680, 0}, + {0x6681, 1}, + {0x6682, 4384}, + {0x6684, 6435}, + {0x6686, 0}, + {0x6687, 3883}, + {0x6688, 8790}, + {0x6689, 9384}, + {0x668b, 0}, + {0x668c, 6436}, + {0x668e, 0}, + {0x668f, 1}, + {0x6690, 2}, + {0x6691, 3461}, + {0x6693, 0}, + {0x6694, 1}, + {0x6695, 2}, + {0x6696, 2928}, + {0x6697, 960}, + {0x6699, 0}, + {0x669a, 1}, + {0x669b, 2}, + {0x669c, 3}, + {0x669d, 6438}, + {0x669f, 0}, + {0x66a0, 1}, + {0x66a1, 2}, + {0x66a2, 7801}, + {0x66a4, 0}, + {0x66a5, 1}, + {0x66a6, 2}, + {0x66a7, 6437}, + {0x66a8, 7389}, + {0x66aa, 0}, + {0x66ab, 8794}, + {0x66ad, 0}, + {0x66ae, 2845}, + {0x66b0, 0}, + {0x66b1, 1}, + {0x66b2, 2}, + {0x66b3, 3}, + {0x66b4, 1042}, + {0x66b6, 0}, + {0x66b7, 1}, + {0x66b8, 2}, + {0x66b9, 5979}, + {0x66bb, 0}, + {0x66bc, 1}, + {0x66bd, 2}, + {0x66be, 6439}, + {0x66c0, 0}, + {0x66c1, 1}, + {0x66c2, 2}, + {0x66c3, 3}, + {0x66c4, 9383}, + {0x66c6, 9862}, + {0x66c7, 9382}, + {0x66c9, 8654}, + {0x66cb, 0}, + {0x66cc, 1}, + {0x66cd, 2}, + {0x66ce, 3}, + {0x66cf, 4}, + {0x66d0, 5}, + {0x66d1, 6}, + {0x66d2, 7}, + {0x66d3, 8}, + {0x66d4, 9}, + {0x66d5, 10}, + {0x66d6, 9385}, + {0x66d8, 0}, + {0x66d9, 3462}, + {0x66db, 6440}, + {0x66dc, 6441}, + {0x66dd, 3063}, + {0x66df, 0}, + {0x66e0, 8167}, + {0x66e2, 0}, + {0x66e3, 1}, + {0x66e4, 2}, + {0x66e5, 3}, + {0x66e6, 6442}, + {0x66e8, 0}, + {0x66e9, 6443}, + {0x66eb, 0}, + {0x66ec, 8466}, + {0x66ee, 0}, + {0x66ef, 1}, + {0x66f0, 4350}, + {0x66f2, 3191}, + {0x66f3, 4158}, + {0x66f4, 1783}, + {0x66f6, 0}, + {0x66f7, 6420}, + {0x66f8, 8508}, + {0x66f9, 1187}, + {0x66fb, 0}, + {0x66fc, 2723}, + {0x66fe, 4411}, + {0x66ff, 3641}, + {0x6700, 4683}, + {0x6702, 0}, + {0x6703, 8028}, + {0x6705, 0}, + {0x6706, 1}, + {0x6707, 2}, + {0x6708, 4357}, + {0x6709, 4277}, + {0x670a, 6515}, + {0x670b, 2996}, + {0x670d, 1691}, + {0x670f, 0}, + {0x6710, 6532}, + {0x6712, 0}, + {0x6713, 1}, + {0x6714, 3500}, + {0x6715, 6542}, + {0x6717, 2485}, + {0x6719, 0}, + {0x671a, 1}, + {0x671b, 3756}, + {0x671d, 1236}, + {0x671f, 3065}, + {0x6721, 0}, + {0x6722, 1}, + {0x6723, 2}, + {0x6724, 3}, + {0x6725, 4}, + {0x6726, 6572}, + {0x6727, 9412}, + {0x6728, 2849}, + {0x672a, 3779}, + {0x672b, 2828}, + {0x672c, 1063}, + {0x672d, 4416}, + {0x672f, 3468}, + {0x6731, 4587}, + {0x6733, 0}, + {0x6734, 3058}, + {0x6735, 1571}, + {0x6737, 0}, + {0x6738, 1}, + {0x6739, 2}, + {0x673a, 2063}, + {0x673c, 0}, + {0x673d, 4011}, + {0x673f, 0}, + {0x6740, 3306}, + {0x6742, 4374}, + {0x6743, 3203}, + {0x6745, 0}, + {0x6746, 1734}, + {0x6748, 6228}, + {0x6749, 3317}, + {0x674b, 0}, + {0x674c, 6225}, + {0x674e, 2521}, + {0x674f, 3998}, + {0x6750, 1163}, + {0x6751, 1384}, + {0x6753, 6226}, + {0x6755, 0}, + {0x6756, 4457}, + {0x6758, 0}, + {0x6759, 1}, + {0x675a, 2}, + {0x675b, 3}, + {0x675c, 1540}, + {0x675e, 6227}, + {0x675f, 3471}, + {0x6760, 1751}, + {0x6761, 3656}, + {0x6763, 0}, + {0x6764, 1}, + {0x6765, 2463}, + {0x6767, 0}, + {0x6768, 4119}, + {0x6769, 6229}, + {0x676a, 6232}, + {0x676c, 0}, + {0x676d, 1907}, + {0x676f, 1046}, + {0x6770, 2221}, + {0x6771, 7884}, + {0x6772, 6415}, + {0x6773, 6233}, + {0x6775, 6236}, + {0x6777, 6241}, + {0x6779, 0}, + {0x677a, 1}, + {0x677b, 2}, + {0x677c, 6242}, + {0x677e, 3518}, + {0x677f, 1008}, + {0x6781, 2078}, + {0x6783, 0}, + {0x6784, 1810}, + {0x6786, 0}, + {0x6787, 6231}, + {0x6789, 3752}, + {0x678b, 6240}, + {0x678d, 0}, + {0x678e, 1}, + {0x678f, 2}, + {0x6790, 3845}, + {0x6792, 0}, + {0x6793, 1}, + {0x6794, 2}, + {0x6795, 4494}, + {0x6797, 2591}, + {0x6798, 6234}, + {0x679a, 2747}, + {0x679c, 1876}, + {0x679d, 4517}, + {0x679e, 6238}, + {0x67a0, 0}, + {0x67a1, 1}, + {0x67a2, 3447}, + {0x67a3, 4393}, + {0x67a5, 6230}, + {0x67a7, 6235}, + {0x67a8, 6237}, + {0x67aa, 3126}, + {0x67ab, 1664}, + {0x67ad, 6239}, + {0x67af, 2410}, + {0x67b0, 6248}, + {0x67b2, 0}, + {0x67b3, 6253}, + {0x67b5, 6251}, + {0x67b6, 2127}, + {0x67b7, 2114}, + {0x67b8, 6257}, + {0x67ba, 0}, + {0x67bb, 1}, + {0x67bc, 2}, + {0x67bd, 3}, + {0x67be, 4}, + {0x67bf, 5}, + {0x67c0, 6}, + {0x67c1, 6260}, + {0x67c3, 6256}, + {0x67c4, 1123}, + {0x67c6, 0}, + {0x67c7, 1}, + {0x67c8, 2}, + {0x67c9, 3}, + {0x67ca, 4}, + {0x67cb, 5}, + {0x67cc, 6}, + {0x67cd, 7}, + {0x67ce, 8}, + {0x67cf, 995}, + {0x67d0, 2838}, + {0x67d1, 1735}, + {0x67d2, 3073}, + {0x67d3, 3225}, + {0x67d4, 3260}, + {0x67d6, 0}, + {0x67d7, 1}, + {0x67d8, 6245}, + {0x67d9, 6250}, + {0x67da, 6252}, + {0x67dc, 1866}, + {0x67dd, 6254}, + {0x67de, 4690}, + {0x67e0, 2910}, + {0x67e2, 6258}, + {0x67e4, 0}, + {0x67e5, 1200}, + {0x67e7, 0}, + {0x67e8, 1}, + {0x67e9, 6247}, + {0x67eb, 0}, + {0x67ec, 2144}, + {0x67ee, 0}, + {0x67ef, 2383}, + {0x67f0, 6243}, + {0x67f1, 4600}, + {0x67f3, 2625}, + {0x67f4, 1208}, + {0x67f6, 0}, + {0x67f7, 1}, + {0x67f8, 2}, + {0x67f9, 3}, + {0x67fa, 4}, + {0x67fb, 5}, + {0x67fc, 6}, + {0x67fd, 6261}, + {0x67ff, 3416}, + {0x6800, 6255}, + {0x6802, 0}, + {0x6803, 1}, + {0x6804, 2}, + {0x6805, 4421}, + {0x6807, 1107}, + {0x6808, 4444}, + {0x6809, 6244}, + {0x680a, 6246}, + {0x680b, 1519}, + {0x680c, 6249}, + {0x680e, 6259}, + {0x680f, 2467}, + {0x6811, 3470}, + {0x6813, 3485}, + {0x6815, 0}, + {0x6816, 3067}, + {0x6817, 2528}, + {0x6819, 0}, + {0x681a, 1}, + {0x681b, 2}, + {0x681c, 3}, + {0x681d, 6271}, + {0x681f, 0}, + {0x6820, 1}, + {0x6821, 3950}, + {0x6823, 0}, + {0x6824, 1}, + {0x6825, 2}, + {0x6826, 3}, + {0x6827, 4}, + {0x6828, 5}, + {0x6829, 6280}, + {0x682a, 4585}, + {0x682c, 0}, + {0x682d, 1}, + {0x682e, 2}, + {0x682f, 3}, + {0x6830, 4}, + {0x6831, 5}, + {0x6832, 6262}, + {0x6833, 6263}, + {0x6835, 0}, + {0x6836, 1}, + {0x6837, 4130}, + {0x6838, 1922}, + {0x6839, 1780}, + {0x683b, 0}, + {0x683c, 1772}, + {0x683d, 4375}, + {0x683e, 6277}, + {0x6840, 6276}, + {0x6841, 6274}, + {0x6842, 1865}, + {0x6843, 3621}, + {0x6844, 6268}, + {0x6845, 3765}, + {0x6846, 2431}, + {0x6848, 963}, + {0x6849, 6279}, + {0x684a, 6278}, + {0x684c, 4637}, + {0x684e, 6266}, + {0x6850, 3674}, + {0x6851, 3292}, + {0x6853, 1997}, + {0x6854, 2220}, + {0x6855, 6272}, + {0x6857, 0}, + {0x6858, 1}, + {0x6859, 2}, + {0x685a, 3}, + {0x685b, 4}, + {0x685c, 5}, + {0x685d, 6}, + {0x685e, 7}, + {0x685f, 8}, + {0x6860, 6264}, + {0x6861, 6265}, + {0x6862, 6267}, + {0x6863, 1430}, + {0x6864, 6269}, + {0x6865, 3138}, + {0x6866, 6273}, + {0x6867, 6275}, + {0x6868, 2177}, + {0x6869, 4619}, + {0x686b, 6286}, + {0x686d, 0}, + {0x686e, 1}, + {0x686f, 2}, + {0x6870, 3}, + {0x6871, 4}, + {0x6872, 5}, + {0x6873, 6}, + {0x6874, 6283}, + {0x6876, 3681}, + {0x6877, 6284}, + {0x6879, 0}, + {0x687a, 1}, + {0x687b, 2}, + {0x687c, 3}, + {0x687d, 4}, + {0x687e, 5}, + {0x687f, 6}, + {0x6880, 7}, + {0x6881, 2563}, + {0x6883, 6270}, + {0x6885, 2748}, + {0x6886, 1019}, + {0x6888, 0}, + {0x6889, 1}, + {0x688a, 2}, + {0x688b, 3}, + {0x688c, 4}, + {0x688d, 5}, + {0x688e, 6}, + {0x688f, 6282}, + {0x6891, 0}, + {0x6892, 1}, + {0x6893, 6285}, + {0x6895, 0}, + {0x6896, 1}, + {0x6897, 1788}, + {0x6898, 9322}, + {0x689a, 0}, + {0x689b, 1}, + {0x689c, 2}, + {0x689d, 8565}, + {0x689f, 9325}, + {0x68a1, 0}, + {0x68a2, 3339}, + {0x68a4, 0}, + {0x68a5, 1}, + {0x68a6, 2771}, + {0x68a7, 3823}, + {0x68a8, 2513}, + {0x68aa, 0}, + {0x68ab, 1}, + {0x68ac, 2}, + {0x68ad, 3560}, + {0x68af, 3632}, + {0x68b0, 3968}, + {0x68b2, 0}, + {0x68b3, 3448}, + {0x68b5, 6281}, + {0x68b7, 0}, + {0x68b8, 1}, + {0x68b9, 2}, + {0x68ba, 3}, + {0x68bb, 4}, + {0x68bc, 5}, + {0x68bd, 6}, + {0x68be, 7}, + {0x68bf, 8}, + {0x68c0, 2143}, + {0x68c2, 6287}, + {0x68c4, 0}, + {0x68c5, 1}, + {0x68c6, 2}, + {0x68c7, 3}, + {0x68c8, 4}, + {0x68c9, 2787}, + {0x68cb, 3076}, + {0x68cd, 1872}, + {0x68cf, 0}, + {0x68d0, 1}, + {0x68d1, 2}, + {0x68d2, 1023}, + {0x68d4, 0}, + {0x68d5, 4661}, + {0x68d6, 9323}, + {0x68d7, 8799}, + {0x68d8, 2079}, + {0x68da, 2992}, + {0x68dc, 0}, + {0x68dd, 1}, + {0x68de, 2}, + {0x68df, 7886}, + {0x68e0, 3607}, + {0x68e2, 0}, + {0x68e3, 6298}, + {0x68e5, 0}, + {0x68e6, 1}, + {0x68e7, 8818}, + {0x68e9, 0}, + {0x68ea, 1}, + {0x68eb, 2}, + {0x68ec, 3}, + {0x68ed, 4}, + {0x68ee, 3302}, + {0x68f0, 6294}, + {0x68f1, 2509}, + {0x68f3, 0}, + {0x68f4, 1}, + {0x68f5, 2384}, + {0x68f7, 0}, + {0x68f8, 1}, + {0x68f9, 6292}, + {0x68fa, 1840}, + {0x68fc, 6289}, + {0x68fe, 0}, + {0x68ff, 1}, + {0x6901, 6296}, + {0x6903, 0}, + {0x6904, 1}, + {0x6905, 4181}, + {0x6907, 0}, + {0x6908, 1}, + {0x6909, 2}, + {0x690a, 3}, + {0x690b, 6295}, + {0x690d, 4529}, + {0x690e, 4626}, + {0x690f, 9331}, + {0x6910, 6299}, + {0x6912, 2184}, + {0x6914, 0}, + {0x6915, 1}, + {0x6916, 2}, + {0x6917, 3}, + {0x6918, 4}, + {0x6919, 5}, + {0x691a, 6}, + {0x691b, 7}, + {0x691c, 8}, + {0x691d, 9}, + {0x691e, 10}, + {0x691f, 6290}, + {0x6920, 6291}, + {0x6922, 0}, + {0x6923, 1}, + {0x6924, 6293}, + {0x6926, 0}, + {0x6927, 1}, + {0x6928, 2}, + {0x6929, 3}, + {0x692a, 4}, + {0x692b, 5}, + {0x692c, 6}, + {0x692d, 3719}, + {0x692f, 0}, + {0x6930, 4147}, + {0x6932, 0}, + {0x6933, 1}, + {0x6934, 6310}, + {0x6936, 0}, + {0x6937, 1}, + {0x6938, 2}, + {0x6939, 6301}, + {0x693b, 0}, + {0x693c, 1}, + {0x693d, 1325}, + {0x693f, 1342}, + {0x6941, 0}, + {0x6942, 6303}, + {0x6944, 0}, + {0x6945, 1}, + {0x6946, 2}, + {0x6947, 3}, + {0x6948, 4}, + {0x6949, 5}, + {0x694a, 8702}, + {0x694c, 0}, + {0x694d, 1}, + {0x694e, 2}, + {0x694f, 3}, + {0x6950, 4}, + {0x6951, 5}, + {0x6952, 6}, + {0x6953, 7934}, + {0x6954, 3955}, + {0x6956, 0}, + {0x6957, 6297}, + {0x6959, 0}, + {0x695a, 1315}, + {0x695c, 0}, + {0x695d, 6304}, + {0x695e, 2510}, + {0x6960, 6302}, + {0x6962, 0}, + {0x6963, 6317}, + {0x6965, 0}, + {0x6966, 6316}, + {0x6968, 9333}, + {0x696a, 0}, + {0x696b, 6306}, + {0x696d, 8714}, + {0x696e, 6288}, + {0x6970, 0}, + {0x6971, 6300}, + {0x6973, 0}, + {0x6974, 1}, + {0x6975, 8047}, + {0x6977, 2361}, + {0x6978, 6309}, + {0x6979, 6318}, + {0x697b, 0}, + {0x697c, 2636}, + {0x697e, 0}, + {0x697f, 1}, + {0x6980, 6307}, + {0x6982, 1728}, + {0x6984, 6305}, + {0x6986, 4289}, + {0x6987, 6312}, + {0x6988, 6313}, + {0x6989, 6315}, + {0x698b, 0}, + {0x698c, 1}, + {0x698d, 6331}, + {0x698f, 0}, + {0x6990, 1}, + {0x6991, 2}, + {0x6992, 3}, + {0x6993, 4}, + {0x6994, 2481}, + {0x6995, 6329}, + {0x6997, 0}, + {0x6998, 6308}, + {0x699a, 0}, + {0x699b, 6319}, + {0x699c, 1020}, + {0x699e, 0}, + {0x699f, 1}, + {0x69a0, 2}, + {0x69a1, 3}, + {0x69a2, 4}, + {0x69a3, 5}, + {0x69a4, 6}, + {0x69a5, 7}, + {0x69a6, 8}, + {0x69a7, 6320}, + {0x69a8, 4422}, + {0x69aa, 9320}, + {0x69ab, 6322}, + {0x69ad, 6323}, + {0x69ae, 8448}, + {0x69b0, 0}, + {0x69b1, 6325}, + {0x69b3, 0}, + {0x69b4, 2618}, + {0x69b6, 0}, + {0x69b7, 3217}, + {0x69b9, 0}, + {0x69ba, 1}, + {0x69bb, 6321}, + {0x69bd, 0}, + {0x69be, 1}, + {0x69bf, 9334}, + {0x69c1, 6326}, + {0x69c3, 0}, + {0x69c4, 1}, + {0x69c5, 2}, + {0x69c6, 3}, + {0x69c7, 4}, + {0x69c8, 5}, + {0x69c9, 6}, + {0x69ca, 6327}, + {0x69cb, 7975}, + {0x69cc, 6311}, + {0x69cd, 8407}, + {0x69ce, 6314}, + {0x69d0, 1990}, + {0x69d2, 0}, + {0x69d3, 1}, + {0x69d4, 6324}, + {0x69d6, 0}, + {0x69d7, 1}, + {0x69d8, 2}, + {0x69d9, 3}, + {0x69da, 4}, + {0x69db, 2154}, + {0x69dd, 0}, + {0x69de, 1}, + {0x69df, 6328}, + {0x69e0, 6330}, + {0x69e2, 0}, + {0x69e3, 1}, + {0x69e4, 2}, + {0x69e5, 3}, + {0x69e6, 4}, + {0x69e7, 9340}, + {0x69e9, 0}, + {0x69ea, 1}, + {0x69eb, 2}, + {0x69ec, 3}, + {0x69ed, 6334}, + {0x69ef, 0}, + {0x69f0, 1}, + {0x69f1, 2}, + {0x69f2, 6338}, + {0x69f3, 8097}, + {0x69f5, 0}, + {0x69f6, 1}, + {0x69f7, 2}, + {0x69f8, 3}, + {0x69f9, 4}, + {0x69fa, 5}, + {0x69fb, 6}, + {0x69fc, 7}, + {0x69fd, 1186}, + {0x69ff, 6332}, + {0x6a01, 8874}, + {0x6a02, 8197}, + {0x6a04, 0}, + {0x6a05, 9324}, + {0x6a07, 0}, + {0x6a08, 1}, + {0x6a09, 2}, + {0x6a0a, 1611}, + {0x6a0c, 0}, + {0x6a0d, 1}, + {0x6a0e, 2}, + {0x6a0f, 3}, + {0x6a10, 4}, + {0x6a11, 5}, + {0x6a12, 6}, + {0x6a13, 8254}, + {0x6a15, 0}, + {0x6a16, 1}, + {0x6a17, 6335}, + {0x6a18, 6336}, + {0x6a19, 7756}, + {0x6a1b, 0}, + {0x6a1c, 1}, + {0x6a1d, 2}, + {0x6a1e, 8506}, + {0x6a1f, 4450}, + {0x6a21, 2822}, + {0x6a23, 8708}, + {0x6a25, 0}, + {0x6a26, 1}, + {0x6a27, 2}, + {0x6a28, 6348}, + {0x6a2a, 1944}, + {0x6a2c, 0}, + {0x6a2d, 1}, + {0x6a2e, 2}, + {0x6a2f, 6333}, + {0x6a31, 4232}, + {0x6a33, 0}, + {0x6a34, 1}, + {0x6a35, 6344}, + {0x6a37, 0}, + {0x6a38, 8387}, + {0x6a39, 8512}, + {0x6a3a, 9335}, + {0x6a3c, 0}, + {0x6a3d, 6347}, + {0x6a3e, 6340}, + {0x6a40, 0}, + {0x6a41, 1}, + {0x6a42, 2}, + {0x6a43, 3}, + {0x6a44, 6339}, + {0x6a46, 0}, + {0x6a47, 3134}, + {0x6a48, 9332}, + {0x6a4a, 0}, + {0x6a4b, 8413}, + {0x6a4d, 0}, + {0x6a4e, 1}, + {0x6a4f, 2}, + {0x6a50, 6342}, + {0x6a52, 0}, + {0x6a53, 1}, + {0x6a54, 2}, + {0x6a55, 3}, + {0x6a56, 4}, + {0x6a57, 5}, + {0x6a58, 6349}, + {0x6a59, 1261}, + {0x6a5b, 6343}, + {0x6a5d, 0}, + {0x6a5e, 1}, + {0x6a5f, 8040}, + {0x6a61, 3933}, + {0x6a62, 8581}, + {0x6a64, 0}, + {0x6a65, 6337}, + {0x6a67, 0}, + {0x6a68, 1}, + {0x6a69, 2}, + {0x6a6a, 3}, + {0x6a6b, 4}, + {0x6a6c, 5}, + {0x6a6d, 6}, + {0x6a6e, 7}, + {0x6a6f, 8}, + {0x6a70, 9}, + {0x6a71, 1308}, + {0x6a73, 0}, + {0x6a74, 1}, + {0x6a75, 2}, + {0x6a76, 3}, + {0x6a77, 4}, + {0x6a78, 5}, + {0x6a79, 6346}, + {0x6a7b, 0}, + {0x6a7c, 6350}, + {0x6a7e, 0}, + {0x6a7f, 1}, + {0x6a80, 3591}, + {0x6a82, 0}, + {0x6a83, 1}, + {0x6a84, 3866}, + {0x6a86, 0}, + {0x6a87, 1}, + {0x6a88, 2}, + {0x6a89, 9330}, + {0x6a8b, 0}, + {0x6a8c, 1}, + {0x6a8d, 2}, + {0x6a8e, 6345}, + {0x6a90, 6352}, + {0x6a91, 6351}, + {0x6a93, 0}, + {0x6a94, 7861}, + {0x6a96, 0}, + {0x6a97, 6354}, + {0x6a99, 0}, + {0x6a9a, 1}, + {0x6a9b, 2}, + {0x6a9c, 9336}, + {0x6a9e, 0}, + {0x6a9f, 1}, + {0x6aa0, 6341}, + {0x6aa2, 8075}, + {0x6aa3, 9348}, + {0x6aa5, 0}, + {0x6aa6, 1}, + {0x6aa7, 2}, + {0x6aa8, 3}, + {0x6aa9, 6353}, + {0x6aab, 6355}, + {0x6aac, 2767}, + {0x6aae, 0}, + {0x6aaf, 9881}, + {0x6ab1, 0}, + {0x6ab2, 1}, + {0x6ab3, 9346}, + {0x6ab5, 0}, + {0x6ab6, 1}, + {0x6ab7, 2}, + {0x6ab8, 8353}, + {0x6aba, 0}, + {0x6abb, 8082}, + {0x6abd, 0}, + {0x6abe, 1}, + {0x6abf, 2}, + {0x6ac0, 3}, + {0x6ac1, 4}, + {0x6ac2, 5}, + {0x6ac3, 7992}, + {0x6ac5, 0}, + {0x6ac6, 1}, + {0x6ac7, 2}, + {0x6ac8, 3}, + {0x6ac9, 4}, + {0x6aca, 5}, + {0x6acb, 6}, + {0x6acc, 7}, + {0x6acd, 8}, + {0x6ace, 9}, + {0x6acf, 10}, + {0x6ad0, 11}, + {0x6ad1, 12}, + {0x6ad2, 13}, + {0x6ad3, 9349}, + {0x6ad5, 0}, + {0x6ad6, 1}, + {0x6ad7, 2}, + {0x6ad8, 3}, + {0x6ad9, 4}, + {0x6ada, 9344}, + {0x6adb, 9326}, + {0x6add, 9339}, + {0x6ade, 9350}, + {0x6adf, 9329}, + {0x6ae1, 0}, + {0x6ae2, 1}, + {0x6ae3, 2}, + {0x6ae4, 3}, + {0x6ae5, 4}, + {0x6ae6, 5}, + {0x6ae7, 9347}, + {0x6ae8, 9328}, + {0x6aea, 9321}, + {0x6aec, 9343}, + {0x6aee, 0}, + {0x6aef, 1}, + {0x6af0, 2}, + {0x6af1, 3}, + {0x6af2, 4}, + {0x6af3, 9327}, + {0x6af5, 0}, + {0x6af6, 1}, + {0x6af7, 2}, + {0x6af8, 9345}, + {0x6afa, 0}, + {0x6afb, 8736}, + {0x6afd, 0}, + {0x6afe, 1}, + {0x6aff, 2}, + {0x6b01, 0}, + {0x6b02, 1}, + {0x6b03, 2}, + {0x6b04, 8181}, + {0x6b06, 0}, + {0x6b07, 1}, + {0x6b08, 2}, + {0x6b09, 3}, + {0x6b0a, 8436}, + {0x6b0c, 0}, + {0x6b0d, 1}, + {0x6b0e, 2}, + {0x6b0f, 9341}, + {0x6b11, 0}, + {0x6b12, 9337}, + {0x6b14, 0}, + {0x6b15, 1}, + {0x6b16, 9342}, + {0x6b18, 0}, + {0x6b19, 1}, + {0x6b1a, 2}, + {0x6b1b, 3}, + {0x6b1c, 4}, + {0x6b1d, 5}, + {0x6b1e, 9338}, + {0x6b20, 3124}, + {0x6b21, 1361}, + {0x6b22, 1995}, + {0x6b23, 3979}, + {0x6b24, 6577}, + {0x6b26, 0}, + {0x6b27, 2936}, + {0x6b29, 0}, + {0x6b2a, 1}, + {0x6b2b, 2}, + {0x6b2c, 3}, + {0x6b2d, 4}, + {0x6b2e, 5}, + {0x6b2f, 6}, + {0x6b30, 7}, + {0x6b31, 8}, + {0x6b32, 4320}, + {0x6b34, 0}, + {0x6b35, 1}, + {0x6b36, 2}, + {0x6b37, 6578}, + {0x6b39, 6579}, + {0x6b3a, 3066}, + {0x6b3c, 0}, + {0x6b3d, 8419}, + {0x6b3e, 2427}, + {0x6b40, 0}, + {0x6b41, 1}, + {0x6b42, 2}, + {0x6b43, 6580}, + {0x6b45, 0}, + {0x6b46, 6581}, + {0x6b47, 3957}, + {0x6b49, 3125}, + {0x6b4b, 0}, + {0x6b4c, 1763}, + {0x6b4e, 0}, + {0x6b4f, 1}, + {0x6b50, 8365}, + {0x6b52, 0}, + {0x6b53, 1}, + {0x6b54, 2}, + {0x6b55, 3}, + {0x6b56, 4}, + {0x6b57, 5}, + {0x6b58, 6}, + {0x6b59, 6582}, + {0x6b5b, 0}, + {0x6b5c, 1}, + {0x6b5d, 2}, + {0x6b5e, 3}, + {0x6b5f, 9419}, + {0x6b61, 8019}, + {0x6b62, 4536}, + {0x6b63, 4510}, + {0x6b64, 1358}, + {0x6b65, 1156}, + {0x6b66, 3827}, + {0x6b67, 3078}, + {0x6b69, 0}, + {0x6b6a, 3730}, + {0x6b6c, 0}, + {0x6b6d, 1}, + {0x6b6e, 2}, + {0x6b6f, 3}, + {0x6b70, 4}, + {0x6b71, 5}, + {0x6b72, 8537}, + {0x6b74, 0}, + {0x6b75, 1}, + {0x6b76, 2}, + {0x6b77, 8211}, + {0x6b78, 7987}, + {0x6b79, 1400}, + {0x6b7b, 3509}, + {0x6b7c, 2130}, + {0x6b7e, 0}, + {0x6b7f, 1}, + {0x6b80, 2}, + {0x6b81, 6358}, + {0x6b82, 6359}, + {0x6b83, 4115}, + {0x6b84, 6361}, + {0x6b86, 1404}, + {0x6b87, 6360}, + {0x6b89, 4060}, + {0x6b8a, 3449}, + {0x6b8b, 1175}, + {0x6b8d, 6364}, + {0x6b8f, 0}, + {0x6b90, 1}, + {0x6b91, 2}, + {0x6b92, 6362}, + {0x6b93, 6363}, + {0x6b95, 0}, + {0x6b96, 4530}, + {0x6b98, 7772}, + {0x6b9a, 6365}, + {0x6b9b, 6366}, + {0x6b9d, 0}, + {0x6b9e, 9352}, + {0x6ba0, 0}, + {0x6ba1, 6367}, + {0x6ba3, 0}, + {0x6ba4, 9351}, + {0x6ba6, 0}, + {0x6ba7, 1}, + {0x6ba8, 2}, + {0x6ba9, 3}, + {0x6baa, 6368}, + {0x6bab, 9354}, + {0x6bad, 0}, + {0x6bae, 9353}, + {0x6baf, 9355}, + {0x6bb1, 0}, + {0x6bb2, 8067}, + {0x6bb3, 6589}, + {0x6bb4, 2938}, + {0x6bb5, 1549}, + {0x6bb7, 4218}, + {0x6bb9, 0}, + {0x6bba, 8463}, + {0x6bbb, 8155}, + {0x6bbd, 0}, + {0x6bbe, 1}, + {0x6bbf, 1487}, + {0x6bc1, 2030}, + {0x6bc2, 6591}, + {0x6bc4, 0}, + {0x6bc5, 4202}, + {0x6bc6, 8367}, + {0x6bc8, 0}, + {0x6bc9, 1}, + {0x6bca, 2}, + {0x6bcb, 3826}, + {0x6bcd, 2843}, + {0x6bcf, 2756}, + {0x6bd1, 0}, + {0x6bd2, 1533}, + {0x6bd3, 4719}, + {0x6bd4, 1073}, + {0x6bd5, 1080}, + {0x6bd6, 1082}, + {0x6bd7, 3007}, + {0x6bd9, 1081}, + {0x6bdb, 2736}, + {0x6bdd, 0}, + {0x6bde, 1}, + {0x6bdf, 2}, + {0x6be0, 3}, + {0x6be1, 4434}, + {0x6be3, 0}, + {0x6be4, 1}, + {0x6be5, 2}, + {0x6be6, 3}, + {0x6be7, 4}, + {0x6be8, 5}, + {0x6be9, 6}, + {0x6bea, 6484}, + {0x6beb, 1912}, + {0x6bed, 0}, + {0x6bee, 1}, + {0x6bef, 3597}, + {0x6bf1, 0}, + {0x6bf2, 1}, + {0x6bf3, 6485}, + {0x6bf5, 6487}, + {0x6bf7, 0}, + {0x6bf8, 1}, + {0x6bf9, 6488}, + {0x6bfb, 0}, + {0x6bfc, 1}, + {0x6bfd, 6486}, + {0x6bff, 9408}, + {0x6c01, 0}, + {0x6c02, 1}, + {0x6c03, 2}, + {0x6c04, 3}, + {0x6c05, 6489}, + {0x6c06, 6491}, + {0x6c07, 6490}, + {0x6c08, 8813}, + {0x6c0a, 0}, + {0x6c0b, 1}, + {0x6c0c, 9409}, + {0x6c0d, 6492}, + {0x6c0f, 3430}, + {0x6c10, 4715}, + {0x6c11, 2806}, + {0x6c13, 2730}, + {0x6c14, 3095}, + {0x6c15, 6493}, + {0x6c16, 2861}, + {0x6c18, 6494}, + {0x6c19, 6495}, + {0x6c1a, 6496}, + {0x6c1b, 1650}, + {0x6c1d, 0}, + {0x6c1e, 1}, + {0x6c1f, 1687}, + {0x6c21, 6497}, + {0x6c22, 3167}, + {0x6c23, 8394}, + {0x6c24, 6499}, + {0x6c26, 1883}, + {0x6c27, 4126}, + {0x6c28, 956}, + {0x6c29, 6498}, + {0x6c2a, 6500}, + {0x6c2b, 8423}, + {0x6c2c, 9410}, + {0x6c2e, 1419}, + {0x6c2f, 2671}, + {0x6c30, 3173}, + {0x6c32, 6501}, + {0x6c34, 3491}, + {0x6c35, 5791}, + {0x6c37, 0}, + {0x6c38, 4261}, + {0x6c3a, 0}, + {0x6c3b, 1}, + {0x6c3c, 2}, + {0x6c3d, 4847}, + {0x6c3f, 0}, + {0x6c40, 3666}, + {0x6c41, 4524}, + {0x6c42, 3184}, + {0x6c44, 0}, + {0x6c45, 1}, + {0x6c46, 4852}, + {0x6c47, 2040}, + {0x6c49, 1905}, + {0x6c4a, 5794}, + {0x6c4c, 0}, + {0x6c4d, 1}, + {0x6c4e, 2}, + {0x6c4f, 3}, + {0x6c50, 3864}, + {0x6c52, 0}, + {0x6c53, 1}, + {0x6c54, 5792}, + {0x6c55, 3328}, + {0x6c57, 1904}, + {0x6c59, 0}, + {0x6c5a, 1}, + {0x6c5b, 4061}, + {0x6c5c, 5793}, + {0x6c5d, 3269}, + {0x6c5e, 1800}, + {0x6c5f, 2174}, + {0x6c60, 1277}, + {0x6c61, 3818}, + {0x6c63, 0}, + {0x6c64, 3603}, + {0x6c66, 0}, + {0x6c67, 1}, + {0x6c68, 5800}, + {0x6c69, 5801}, + {0x6c6a, 3749}, + {0x6c6c, 0}, + {0x6c6d, 1}, + {0x6c6e, 2}, + {0x6c6f, 3}, + {0x6c70, 3584}, + {0x6c72, 2086}, + {0x6c74, 5802}, + {0x6c76, 5803}, + {0x6c78, 0}, + {0x6c79, 4005}, + {0x6c7b, 0}, + {0x6c7c, 1}, + {0x6c7d, 3098}, + {0x6c7e, 1655}, + {0x6c80, 0}, + {0x6c81, 3164}, + {0x6c82, 4177}, + {0x6c83, 3813}, + {0x6c85, 5796}, + {0x6c86, 5804}, + {0x6c88, 3371}, + {0x6c89, 1254}, + {0x6c8b, 0}, + {0x6c8c, 5799}, + {0x6c8e, 0}, + {0x6c8f, 3074}, + {0x6c90, 5797}, + {0x6c92, 0}, + {0x6c93, 6687}, + {0x6c94, 5798}, + {0x6c96, 0}, + {0x6c97, 1}, + {0x6c98, 2}, + {0x6c99, 3308}, + {0x6c9b, 2983}, + {0x6c9d, 0}, + {0x6c9e, 1}, + {0x6c9f, 1806}, + {0x6ca1, 2752}, + {0x6ca3, 5795}, + {0x6ca4, 2942}, + {0x6ca5, 2541}, + {0x6ca6, 2688}, + {0x6ca7, 1182}, + {0x6ca9, 5805}, + {0x6caa, 1979}, + {0x6cab, 2832}, + {0x6cad, 5808}, + {0x6cae, 2313}, + {0x6cb0, 0}, + {0x6cb1, 5819}, + {0x6cb2, 5813}, + {0x6cb3, 1930}, + {0x6cb5, 0}, + {0x6cb6, 1}, + {0x6cb7, 2}, + {0x6cb8, 1645}, + {0x6cb9, 4274}, + {0x6cbb, 4557}, + {0x6cbc, 4468}, + {0x6cbd, 1818}, + {0x6cbe, 4437}, + {0x6cbf, 4097}, + {0x6cc1, 0}, + {0x6cc2, 1}, + {0x6cc3, 2}, + {0x6cc4, 3972}, + {0x6cc5, 3187}, + {0x6cc7, 0}, + {0x6cc8, 1}, + {0x6cc9, 3205}, + {0x6cca, 1147}, + {0x6ccc, 2783}, + {0x6cce, 0}, + {0x6ccf, 1}, + {0x6cd0, 5806}, + {0x6cd2, 0}, + {0x6cd3, 5820}, + {0x6cd4, 5807}, + {0x6cd5, 1605}, + {0x6cd6, 5815}, + {0x6cd7, 5812}, + {0x6cd9, 0}, + {0x6cda, 1}, + {0x6cdb, 1623}, + {0x6cdd, 0}, + {0x6cde, 2915}, + {0x6ce0, 5814}, + {0x6ce1, 2974}, + {0x6ce2, 1135}, + {0x6ce3, 3099}, + {0x6ce5, 2883}, + {0x6ce7, 0}, + {0x6ce8, 4607}, + {0x6cea, 2508}, + {0x6ceb, 5817}, + {0x6ced, 0}, + {0x6cee, 5818}, + {0x6cef, 5821}, + {0x6cf0, 3580}, + {0x6cf1, 5811}, + {0x6cf3, 4259}, + {0x6cf5, 1068}, + {0x6cf6, 6688}, + {0x6cf7, 5809}, + {0x6cf8, 5810}, + {0x6cfa, 5816}, + {0x6cfb, 3973}, + {0x6cfc, 3042}, + {0x6cfd, 4406}, + {0x6cfe, 5822}, + {0x6d01, 2225}, + {0x6d03, 0}, + {0x6d04, 5829}, + {0x6d06, 0}, + {0x6d07, 5828}, + {0x6d09, 0}, + {0x6d0a, 1}, + {0x6d0b, 4124}, + {0x6d0c, 5825}, + {0x6d0e, 5831}, + {0x6d10, 0}, + {0x6d11, 1}, + {0x6d12, 3282}, + {0x6d14, 0}, + {0x6d15, 1}, + {0x6d16, 2}, + {0x6d17, 3873}, + {0x6d19, 5830}, + {0x6d1a, 5836}, + {0x6d1b, 2700}, + {0x6d1d, 0}, + {0x6d1e, 1523}, + {0x6d20, 0}, + {0x6d21, 1}, + {0x6d22, 2}, + {0x6d23, 3}, + {0x6d24, 4}, + {0x6d25, 2243}, + {0x6d27, 5824}, + {0x6d29, 0}, + {0x6d2a, 1952}, + {0x6d2b, 5832}, + {0x6d2d, 0}, + {0x6d2e, 5834}, + {0x6d30, 0}, + {0x6d31, 1596}, + {0x6d32, 4573}, + {0x6d33, 5840}, + {0x6d35, 5835}, + {0x6d37, 0}, + {0x6d38, 1}, + {0x6d39, 5823}, + {0x6d3b, 2051}, + {0x6d3c, 3726}, + {0x6d3d, 3103}, + {0x6d3e, 2954}, + {0x6d40, 0}, + {0x6d41, 2624}, + {0x6d43, 5826}, + {0x6d45, 3120}, + {0x6d46, 2173}, + {0x6d47, 2190}, + {0x6d48, 5827}, + {0x6d4a, 4644}, + {0x6d4b, 1193}, + {0x6d4d, 5833}, + {0x6d4e, 2102}, + {0x6d4f, 5837}, + {0x6d51, 2048}, + {0x6d52, 5838}, + {0x6d53, 2921}, + {0x6d54, 5839}, + {0x6d56, 0}, + {0x6d57, 1}, + {0x6d58, 2}, + {0x6d59, 4484}, + {0x6d5a, 2352}, + {0x6d5c, 5848}, + {0x6d5e, 5845}, + {0x6d60, 5849}, + {0x6d62, 0}, + {0x6d63, 5851}, + {0x6d65, 0}, + {0x6d66, 3061}, + {0x6d68, 0}, + {0x6d69, 1917}, + {0x6d6a, 2486}, + {0x6d6c, 0}, + {0x6d6d, 1}, + {0x6d6e, 1692}, + {0x6d6f, 5842}, + {0x6d71, 0}, + {0x6d72, 1}, + {0x6d73, 2}, + {0x6d74, 4324}, + {0x6d76, 0}, + {0x6d77, 1882}, + {0x6d78, 2255}, + {0x6d79, 9180}, + {0x6d7b, 0}, + {0x6d7c, 5850}, + {0x6d7e, 0}, + {0x6d7f, 1}, + {0x6d80, 2}, + {0x6d81, 3}, + {0x6d82, 3696}, + {0x6d84, 0}, + {0x6d85, 2908}, + {0x6d87, 9179}, + {0x6d88, 3944}, + {0x6d89, 3359}, + {0x6d8b, 0}, + {0x6d8c, 4260}, + {0x6d8e, 3902}, + {0x6d90, 0}, + {0x6d91, 5841}, + {0x6d93, 5846}, + {0x6d94, 5847}, + {0x6d95, 3644}, + {0x6d97, 0}, + {0x6d98, 1}, + {0x6d99, 2}, + {0x6d9a, 3}, + {0x6d9b, 3617}, + {0x6d9d, 2495}, + {0x6d9e, 5843}, + {0x6d9f, 2553}, + {0x6da0, 5844}, + {0x6da1, 3807}, + {0x6da3, 2006}, + {0x6da4, 1460}, + {0x6da6, 3278}, + {0x6da7, 2168}, + {0x6da8, 4456}, + {0x6da9, 3301}, + {0x6daa, 1693}, + {0x6dab, 5864}, + {0x6dad, 0}, + {0x6dae, 5866}, + {0x6daf, 4077}, + {0x6db1, 0}, + {0x6db2, 4161}, + {0x6db4, 0}, + {0x6db5, 1892}, + {0x6db7, 0}, + {0x6db8, 1931}, + {0x6dba, 0}, + {0x6dbb, 1}, + {0x6dbc, 2}, + {0x6dbd, 3}, + {0x6dbe, 4}, + {0x6dbf, 5857}, + {0x6dc0, 1486}, + {0x6dc2, 0}, + {0x6dc3, 1}, + {0x6dc4, 4650}, + {0x6dc5, 5854}, + {0x6dc6, 3946}, + {0x6dc7, 5853}, + {0x6dc9, 0}, + {0x6dca, 1}, + {0x6dcb, 2597}, + {0x6dcc, 3613}, + {0x6dce, 0}, + {0x6dcf, 1}, + {0x6dd0, 2}, + {0x6dd1, 3454}, + {0x6dd3, 0}, + {0x6dd4, 1}, + {0x6dd5, 2}, + {0x6dd6, 2874}, + {0x6dd8, 3623}, + {0x6dd9, 5862}, + {0x6ddb, 0}, + {0x6ddc, 1}, + {0x6ddd, 5861}, + {0x6dde, 5855}, + {0x6de0, 5858}, + {0x6de1, 1422}, + {0x6de3, 0}, + {0x6de4, 4286}, + {0x6de6, 5860}, + {0x6de8, 0}, + {0x6de9, 1}, + {0x6dea, 8286}, + {0x6deb, 4224}, + {0x6dec, 1382}, + {0x6dee, 1993}, + {0x6df0, 0}, + {0x6df1, 3367}, + {0x6df3, 1345}, + {0x6df5, 8772}, + {0x6df6, 9186}, + {0x6df7, 2049}, + {0x6df9, 4086}, + {0x6dfa, 8404}, + {0x6dfb, 3648}, + {0x6dfc, 6689}, + {0x6dfe, 0}, + {0x6dff, 1}, + {0x6e01, 0}, + {0x6e02, 1}, + {0x6e03, 2}, + {0x6e04, 3}, + {0x6e05, 3170}, + {0x6e07, 0}, + {0x6e08, 1}, + {0x6e09, 2}, + {0x6e0a, 4331}, + {0x6e0c, 5865}, + {0x6e0d, 4658}, + {0x6e0e, 5856}, + {0x6e10, 2166}, + {0x6e11, 5859}, + {0x6e13, 0}, + {0x6e14, 4299}, + {0x6e16, 5863}, + {0x6e17, 3377}, + {0x6e19, 0}, + {0x6e1a, 5852}, + {0x6e1c, 0}, + {0x6e1d, 4298}, + {0x6e1f, 0}, + {0x6e20, 3195}, + {0x6e21, 1544}, + {0x6e23, 4415}, + {0x6e24, 1146}, + {0x6e25, 5877}, + {0x6e26, 8607}, + {0x6e28, 0}, + {0x6e29, 3793}, + {0x6e2b, 5867}, + {0x6e2c, 7782}, + {0x6e2d, 3787}, + {0x6e2f, 1750}, + {0x6e31, 0}, + {0x6e32, 5876}, + {0x6e34, 2391}, + {0x6e36, 0}, + {0x6e37, 1}, + {0x6e38, 4275}, + {0x6e3a, 2801}, + {0x6e3c, 0}, + {0x6e3d, 1}, + {0x6e3e, 8035}, + {0x6e40, 0}, + {0x6e41, 1}, + {0x6e42, 2}, + {0x6e43, 2953}, + {0x6e44, 5878}, + {0x6e46, 0}, + {0x6e47, 1}, + {0x6e48, 2}, + {0x6e49, 3}, + {0x6e4a, 4}, + {0x6e4b, 5}, + {0x6e4c, 6}, + {0x6e4d, 3701}, + {0x6e4e, 5869}, + {0x6e50, 0}, + {0x6e51, 1}, + {0x6e52, 2}, + {0x6e53, 5874}, + {0x6e54, 5875}, + {0x6e56, 1973}, + {0x6e58, 3923}, + {0x6e5a, 0}, + {0x6e5b, 4448}, + {0x6e5d, 0}, + {0x6e5e, 9181}, + {0x6e5f, 5872}, + {0x6e61, 0}, + {0x6e62, 1}, + {0x6e63, 2}, + {0x6e64, 3}, + {0x6e65, 4}, + {0x6e66, 5}, + {0x6e67, 6}, + {0x6e68, 7}, + {0x6e69, 8}, + {0x6e6a, 9}, + {0x6e6b, 5870}, + {0x6e6d, 0}, + {0x6e6e, 5868}, + {0x6e6f, 8555}, + {0x6e71, 0}, + {0x6e72, 1}, + {0x6e73, 2}, + {0x6e74, 3}, + {0x6e75, 4}, + {0x6e76, 5}, + {0x6e77, 6}, + {0x6e78, 7}, + {0x6e79, 8}, + {0x6e7a, 9}, + {0x6e7b, 10}, + {0x6e7c, 11}, + {0x6e7d, 12}, + {0x6e7e, 3734}, + {0x6e7f, 3393}, + {0x6e81, 0}, + {0x6e82, 1}, + {0x6e83, 2446}, + {0x6e85, 2167}, + {0x6e86, 5873}, + {0x6e88, 0}, + {0x6e89, 1731}, + {0x6e8b, 0}, + {0x6e8c, 1}, + {0x6e8d, 2}, + {0x6e8e, 3}, + {0x6e8f, 5893}, + {0x6e90, 4343}, + {0x6e92, 0}, + {0x6e93, 1}, + {0x6e94, 2}, + {0x6e95, 3}, + {0x6e96, 8885}, + {0x6e98, 5881}, + {0x6e9a, 0}, + {0x6e9b, 1}, + {0x6e9c, 2616}, + {0x6e9d, 7974}, + {0x6e9f, 5895}, + {0x6ea1, 0}, + {0x6ea2, 4206}, + {0x6ea4, 0}, + {0x6ea5, 5885}, + {0x6ea7, 5886}, + {0x6ea9, 0}, + {0x6eaa, 3863}, + {0x6eac, 0}, + {0x6ead, 1}, + {0x6eae, 2}, + {0x6eaf, 3538}, + {0x6eb1, 5880}, + {0x6eb2, 5871}, + {0x6eb4, 5891}, + {0x6eb6, 3255}, + {0x6eb7, 5889}, + {0x6eb9, 0}, + {0x6eba, 2890}, + {0x6ebb, 5888}, + {0x6ebd, 5887}, + {0x6ebf, 0}, + {0x6ec0, 1}, + {0x6ec1, 1313}, + {0x6ec2, 5894}, + {0x6ec4, 7779}, + {0x6ec5, 8328}, + {0x6ec7, 1474}, + {0x6ec9, 0}, + {0x6eca, 1}, + {0x6ecb, 4649}, + {0x6ecc, 7869}, + {0x6ece, 9025}, + {0x6ecf, 5892}, + {0x6ed1, 1985}, + {0x6ed3, 4655}, + {0x6ed4, 3618}, + {0x6ed5, 6568}, + {0x6ed7, 5890}, + {0x6ed9, 0}, + {0x6eda, 1871}, + {0x6edc, 0}, + {0x6edd, 1}, + {0x6ede, 4556}, + {0x6edf, 5879}, + {0x6ee0, 5882}, + {0x6ee1, 2721}, + {0x6ee2, 5884}, + {0x6ee4, 2674}, + {0x6ee5, 2479}, + {0x6ee6, 2679}, + {0x6ee8, 1118}, + {0x6ee9, 3589}, + {0x6eeb, 0}, + {0x6eec, 8011}, + {0x6eee, 0}, + {0x6eef, 8850}, + {0x6ef1, 0}, + {0x6ef2, 8484}, + {0x6ef4, 1455}, + {0x6ef6, 0}, + {0x6ef7, 8264}, + {0x6ef8, 9184}, + {0x6ef9, 5901}, + {0x6efb, 0}, + {0x6efc, 1}, + {0x6efd, 2}, + {0x6efe, 3}, + {0x6eff, 8311}, + {0x6f01, 8762}, + {0x6f02, 3022}, + {0x6f04, 0}, + {0x6f05, 1}, + {0x6f06, 3072}, + {0x6f08, 0}, + {0x6f09, 5907}, + {0x6f0b, 0}, + {0x6f0c, 1}, + {0x6f0d, 2}, + {0x6f0e, 3}, + {0x6f0f, 2640}, + {0x6f11, 0}, + {0x6f12, 1}, + {0x6f13, 2519}, + {0x6f14, 4102}, + {0x6f15, 5900}, + {0x6f17, 0}, + {0x6f18, 1}, + {0x6f19, 2}, + {0x6f1a, 8369}, + {0x6f1c, 0}, + {0x6f1d, 1}, + {0x6f1e, 2}, + {0x6f1f, 3}, + {0x6f20, 2833}, + {0x6f22, 8001}, + {0x6f23, 8220}, + {0x6f24, 5899}, + {0x6f26, 0}, + {0x6f27, 1}, + {0x6f28, 2}, + {0x6f29, 5908}, + {0x6f2a, 5906}, + {0x6f2b, 2725}, + {0x6f2c, 8888}, + {0x6f2d, 5883}, + {0x6f2f, 5902}, + {0x6f31, 3477}, + {0x6f32, 8822}, + {0x6f33, 4453}, + {0x6f35, 0}, + {0x6f36, 5903}, + {0x6f38, 8091}, + {0x6f3a, 0}, + {0x6f3b, 1}, + {0x6f3c, 2}, + {0x6f3d, 3}, + {0x6f3e, 4131}, + {0x6f3f, 8095}, + {0x6f41, 9674}, + {0x6f43, 0}, + {0x6f44, 1}, + {0x6f45, 2}, + {0x6f46, 5897}, + {0x6f47, 5898}, + {0x6f49, 0}, + {0x6f4a, 1}, + {0x6f4b, 5904}, + {0x6f4d, 3770}, + {0x6f4f, 0}, + {0x6f50, 1}, + {0x6f51, 8382}, + {0x6f53, 0}, + {0x6f54, 8116}, + {0x6f56, 0}, + {0x6f57, 1}, + {0x6f58, 2956}, + {0x6f59, 9175}, + {0x6f5b, 0}, + {0x6f5c, 3118}, + {0x6f5e, 2657}, + {0x6f60, 0}, + {0x6f61, 1}, + {0x6f62, 5896}, + {0x6f64, 8453}, + {0x6f66, 2579}, + {0x6f68, 0}, + {0x6f69, 1}, + {0x6f6a, 2}, + {0x6f6b, 3}, + {0x6f6c, 4}, + {0x6f6d, 3593}, + {0x6f6e, 1238}, + {0x6f6f, 9185}, + {0x6f70, 8172}, + {0x6f72, 5913}, + {0x6f74, 5905}, + {0x6f76, 0}, + {0x6f77, 9194}, + {0x6f78, 5912}, + {0x6f7a, 5915}, + {0x6f7c, 5914}, + {0x6f7e, 0}, + {0x6f7f, 9187}, + {0x6f80, 8462}, + {0x6f82, 0}, + {0x6f83, 1}, + {0x6f84, 1267}, + {0x6f86, 8102}, + {0x6f87, 8196}, + {0x6f88, 1247}, + {0x6f89, 5909}, + {0x6f8b, 0}, + {0x6f8c, 5911}, + {0x6f8d, 5910}, + {0x6f8e, 2989}, + {0x6f90, 0}, + {0x6f91, 1}, + {0x6f92, 2}, + {0x6f93, 3}, + {0x6f94, 4}, + {0x6f95, 5}, + {0x6f96, 6}, + {0x6f97, 8093}, + {0x6f99, 0}, + {0x6f9a, 1}, + {0x6f9b, 2}, + {0x6f9c, 2472}, + {0x6f9e, 0}, + {0x6f9f, 1}, + {0x6fa0, 9189}, + {0x6fa1, 4395}, + {0x6fa3, 0}, + {0x6fa4, 8804}, + {0x6fa6, 0}, + {0x6fa7, 5918}, + {0x6fa9, 9442}, + {0x6fab, 0}, + {0x6fac, 1}, + {0x6fad, 2}, + {0x6fae, 9182}, + {0x6fb0, 0}, + {0x6fb1, 7876}, + {0x6fb3, 975}, + {0x6fb5, 0}, + {0x6fb6, 5920}, + {0x6fb8, 0}, + {0x6fb9, 5919}, + {0x6fbb, 0}, + {0x6fbc, 1}, + {0x6fbd, 2}, + {0x6fbe, 3}, + {0x6fbf, 4}, + {0x6fc0, 2071}, + {0x6fc1, 8886}, + {0x6fc2, 5921}, + {0x6fc3, 8361}, + {0x6fc5, 0}, + {0x6fc6, 1}, + {0x6fc7, 2}, + {0x6fc8, 3}, + {0x6fc9, 5917}, + {0x6fcb, 0}, + {0x6fcc, 1}, + {0x6fcd, 2}, + {0x6fce, 3}, + {0x6fcf, 4}, + {0x6fd0, 5}, + {0x6fd1, 5916}, + {0x6fd2, 1117}, + {0x6fd4, 0}, + {0x6fd5, 8491}, + {0x6fd7, 0}, + {0x6fd8, 8357}, + {0x6fda, 0}, + {0x6fdb, 9867}, + {0x6fdd, 0}, + {0x6fde, 5924}, + {0x6fdf, 8054}, + {0x6fe0, 5925}, + {0x6fe1, 5922}, + {0x6fe3, 0}, + {0x6fe4, 8557}, + {0x6fe6, 0}, + {0x6fe7, 1}, + {0x6fe8, 2}, + {0x6fe9, 3}, + {0x6fea, 4}, + {0x6feb, 8193}, + {0x6fed, 0}, + {0x6fee, 5923}, + {0x6fef, 5926}, + {0x6ff0, 8593}, + {0x6ff1, 7760}, + {0x6ff3, 0}, + {0x6ff4, 1}, + {0x6ff5, 2}, + {0x6ff6, 3}, + {0x6ff7, 4}, + {0x6ff8, 5}, + {0x6ff9, 6}, + {0x6ffa, 8092}, + {0x6ffc, 9178}, + {0x6ffe, 8275}, + {0x7001, 0}, + {0x7002, 1}, + {0x7003, 2}, + {0x7004, 3}, + {0x7005, 9193}, + {0x7006, 9188}, + {0x7008, 0}, + {0x7009, 8661}, + {0x700b, 9190}, + {0x700d, 0}, + {0x700e, 1}, + {0x700f, 9183}, + {0x7011, 3064}, + {0x7013, 0}, + {0x7014, 1}, + {0x7015, 7759}, + {0x7017, 0}, + {0x7018, 9177}, + {0x701a, 5927}, + {0x701b, 5929}, + {0x701d, 8212}, + {0x701f, 9196}, + {0x7020, 9195}, + {0x7022, 0}, + {0x7023, 5928}, + {0x7025, 0}, + {0x7026, 1}, + {0x7027, 9176}, + {0x7028, 9198}, + {0x702a, 0}, + {0x702b, 1}, + {0x702c, 2}, + {0x702d, 3}, + {0x702e, 4}, + {0x702f, 5}, + {0x7030, 9870}, + {0x7032, 9197}, + {0x7034, 0}, + {0x7035, 5931}, + {0x7037, 0}, + {0x7038, 1}, + {0x7039, 5930}, + {0x703b, 0}, + {0x703c, 1}, + {0x703d, 2}, + {0x703e, 8186}, + {0x7040, 0}, + {0x7041, 1}, + {0x7042, 2}, + {0x7043, 9174}, + {0x7044, 9192}, + {0x7046, 0}, + {0x7047, 1}, + {0x7048, 2}, + {0x7049, 3}, + {0x704a, 4}, + {0x704b, 5}, + {0x704c, 1849}, + {0x704e, 0}, + {0x704f, 5932}, + {0x7051, 8454}, + {0x7053, 0}, + {0x7054, 1}, + {0x7055, 8203}, + {0x7057, 0}, + {0x7058, 8550}, + {0x705a, 0}, + {0x705b, 1}, + {0x705c, 2}, + {0x705d, 9199}, + {0x705e, 5933}, + {0x7060, 0}, + {0x7061, 1}, + {0x7062, 2}, + {0x7063, 8585}, + {0x7064, 8280}, + {0x7066, 0}, + {0x7067, 9191}, + {0x7069, 0}, + {0x706a, 1}, + {0x706b, 2053}, + {0x706c, 6639}, + {0x706d, 2805}, + {0x706f, 1447}, + {0x7070, 2023}, + {0x7072, 0}, + {0x7073, 1}, + {0x7074, 2}, + {0x7075, 2610}, + {0x7076, 4401}, + {0x7078, 2291}, + {0x707a, 0}, + {0x707b, 1}, + {0x707c, 4643}, + {0x707e, 4377}, + {0x707f, 1178}, + {0x7080, 6604}, + {0x7082, 0}, + {0x7083, 1}, + {0x7084, 2}, + {0x7085, 6419}, + {0x7087, 0}, + {0x7088, 1}, + {0x7089, 2646}, + {0x708a, 1337}, + {0x708c, 0}, + {0x708d, 1}, + {0x708e, 4096}, + {0x7090, 0}, + {0x7091, 1}, + {0x7092, 1241}, + {0x7094, 3213}, + {0x7095, 2376}, + {0x7096, 6606}, + {0x7098, 0}, + {0x7099, 4554}, + {0x709b, 0}, + {0x709c, 6605}, + {0x709d, 6607}, + {0x709f, 0}, + {0x70a0, 1}, + {0x70a1, 2}, + {0x70a2, 3}, + {0x70a3, 4}, + {0x70a4, 5}, + {0x70a5, 6}, + {0x70a6, 7}, + {0x70a7, 8}, + {0x70a8, 9}, + {0x70a9, 10}, + {0x70aa, 11}, + {0x70ab, 6611}, + {0x70ac, 2325}, + {0x70ad, 3602}, + {0x70ae, 2971}, + {0x70af, 2283}, + {0x70b1, 6612}, + {0x70b3, 1127}, + {0x70b5, 0}, + {0x70b6, 1}, + {0x70b7, 6610}, + {0x70b8, 4425}, + {0x70b9, 1476}, + {0x70bb, 6608}, + {0x70bc, 2559}, + {0x70bd, 1288}, + {0x70bf, 0}, + {0x70c0, 6609}, + {0x70c1, 3501}, + {0x70c2, 2478}, + {0x70c3, 3665}, + {0x70c5, 0}, + {0x70c6, 1}, + {0x70c7, 2}, + {0x70c8, 2587}, + {0x70ca, 6614}, + {0x70cc, 0}, + {0x70cd, 1}, + {0x70ce, 2}, + {0x70cf, 8611}, + {0x70d1, 0}, + {0x70d2, 1}, + {0x70d3, 2}, + {0x70d4, 3}, + {0x70d5, 4}, + {0x70d6, 5}, + {0x70d7, 6}, + {0x70d8, 1949}, + {0x70d9, 2494}, + {0x70db, 4593}, + {0x70dd, 0}, + {0x70de, 1}, + {0x70df, 4085}, + {0x70e1, 0}, + {0x70e2, 1}, + {0x70e3, 2}, + {0x70e4, 2379}, + {0x70e6, 1616}, + {0x70e7, 3342}, + {0x70e8, 6613}, + {0x70e9, 2039}, + {0x70eb, 3615}, + {0x70ec, 2254}, + {0x70ed, 3235}, + {0x70ef, 3862}, + {0x70f1, 0}, + {0x70f2, 1}, + {0x70f3, 2}, + {0x70f4, 8570}, + {0x70f6, 0}, + {0x70f7, 3738}, + {0x70f9, 2988}, + {0x70fb, 0}, + {0x70fc, 1}, + {0x70fd, 1670}, + {0x70ff, 0}, + {0x7101, 0}, + {0x7102, 1}, + {0x7103, 2}, + {0x7104, 3}, + {0x7105, 4}, + {0x7106, 5}, + {0x7107, 6}, + {0x7108, 7}, + {0x7109, 4082}, + {0x710a, 1903}, + {0x710c, 0}, + {0x710d, 1}, + {0x710e, 2}, + {0x710f, 3}, + {0x7110, 6615}, + {0x7112, 0}, + {0x7113, 6616}, + {0x7115, 2005}, + {0x7116, 6617}, + {0x7118, 6640}, + {0x7119, 1059}, + {0x711a, 1654}, + {0x711c, 0}, + {0x711d, 1}, + {0x711e, 2}, + {0x711f, 3}, + {0x7120, 4}, + {0x7121, 8613}, + {0x7123, 0}, + {0x7124, 1}, + {0x7125, 2}, + {0x7126, 2186}, + {0x7128, 0}, + {0x7129, 1}, + {0x712a, 2}, + {0x712b, 3}, + {0x712c, 4}, + {0x712d, 5}, + {0x712e, 6}, + {0x712f, 6618}, + {0x7130, 4111}, + {0x7131, 6619}, + {0x7133, 0}, + {0x7134, 1}, + {0x7135, 2}, + {0x7136, 3222}, + {0x7138, 0}, + {0x7139, 1}, + {0x713a, 2}, + {0x713b, 3}, + {0x713c, 4}, + {0x713d, 5}, + {0x713e, 6}, + {0x713f, 7}, + {0x7140, 8}, + {0x7141, 9}, + {0x7142, 10}, + {0x7143, 11}, + {0x7144, 12}, + {0x7145, 6623}, + {0x7147, 0}, + {0x7148, 1}, + {0x7149, 8226}, + {0x714a, 6625}, + {0x714c, 2018}, + {0x714e, 2136}, + {0x7150, 0}, + {0x7151, 1}, + {0x7152, 9430}, + {0x7154, 0}, + {0x7155, 1}, + {0x7156, 2}, + {0x7157, 3}, + {0x7158, 4}, + {0x7159, 5}, + {0x715a, 6}, + {0x715b, 7}, + {0x715c, 6621}, + {0x715e, 3312}, + {0x7160, 0}, + {0x7161, 1}, + {0x7162, 9018}, + {0x7164, 2751}, + {0x7166, 6641}, + {0x7167, 4470}, + {0x7168, 6622}, + {0x7169, 7918}, + {0x716b, 0}, + {0x716c, 9429}, + {0x716e, 4594}, + {0x7170, 0}, + {0x7171, 1}, + {0x7172, 6624}, + {0x7173, 6620}, + {0x7175, 0}, + {0x7176, 1}, + {0x7177, 2}, + {0x7178, 6626}, + {0x717a, 6627}, + {0x717c, 0}, + {0x717d, 3320}, + {0x717f, 0}, + {0x7180, 1}, + {0x7181, 2}, + {0x7182, 3}, + {0x7183, 4}, + {0x7184, 3861}, + {0x7186, 0}, + {0x7187, 1}, + {0x7188, 2}, + {0x7189, 3}, + {0x718a, 4007}, + {0x718c, 0}, + {0x718d, 1}, + {0x718e, 2}, + {0x718f, 4053}, + {0x7191, 0}, + {0x7192, 8744}, + {0x7194, 3254}, + {0x7196, 0}, + {0x7197, 9431}, + {0x7198, 6628}, + {0x7199, 3844}, + {0x719b, 0}, + {0x719c, 1}, + {0x719d, 2}, + {0x719e, 3}, + {0x719f, 3459}, + {0x71a0, 6632}, + {0x71a2, 0}, + {0x71a3, 1}, + {0x71a4, 2}, + {0x71a5, 3}, + {0x71a6, 4}, + {0x71a7, 5}, + {0x71a8, 6631}, + {0x71aa, 0}, + {0x71ab, 1}, + {0x71ac, 969}, + {0x71ae, 0}, + {0x71af, 1}, + {0x71b0, 2}, + {0x71b1, 8444}, + {0x71b3, 6629}, + {0x71b5, 6630}, + {0x71b7, 0}, + {0x71b8, 1}, + {0x71b9, 6642}, + {0x71bb, 0}, + {0x71bc, 1}, + {0x71bd, 2}, + {0x71be, 7815}, + {0x71c0, 0}, + {0x71c1, 9432}, + {0x71c3, 3223}, + {0x71c5, 0}, + {0x71c6, 1}, + {0x71c7, 2}, + {0x71c8, 7866}, + {0x71ca, 0}, + {0x71cb, 1}, + {0x71cc, 2}, + {0x71cd, 3}, + {0x71ce, 2576}, + {0x71d0, 0}, + {0x71d1, 1}, + {0x71d2, 8473}, + {0x71d4, 6634}, + {0x71d5, 4105}, + {0x71d7, 0}, + {0x71d8, 1}, + {0x71d9, 8556}, + {0x71db, 0}, + {0x71dc, 9433}, + {0x71de, 0}, + {0x71df, 8743}, + {0x71e0, 6633}, + {0x71e2, 0}, + {0x71e3, 1}, + {0x71e4, 2}, + {0x71e5, 4402}, + {0x71e6, 7775}, + {0x71e7, 6635}, + {0x71e9, 0}, + {0x71ea, 1}, + {0x71eb, 2}, + {0x71ec, 3}, + {0x71ed, 8863}, + {0x71ee, 5014}, + {0x71f0, 0}, + {0x71f1, 1}, + {0x71f2, 2}, + {0x71f3, 3}, + {0x71f4, 8029}, + {0x71f6, 0}, + {0x71f7, 1}, + {0x71f8, 2}, + {0x71f9, 6636}, + {0x71fb, 0}, + {0x71fc, 8124}, + {0x71fe, 9434}, + {0x7201, 0}, + {0x7202, 1}, + {0x7203, 2}, + {0x7204, 3}, + {0x7205, 4}, + {0x7206, 1045}, + {0x7208, 0}, + {0x7209, 1}, + {0x720a, 2}, + {0x720b, 3}, + {0x720c, 4}, + {0x720d, 8521}, + {0x720f, 0}, + {0x7210, 8262}, + {0x7212, 0}, + {0x7213, 1}, + {0x7214, 2}, + {0x7215, 3}, + {0x7216, 4}, + {0x7217, 5}, + {0x7218, 6}, + {0x7219, 7}, + {0x721a, 8}, + {0x721b, 8192}, + {0x721d, 6637}, + {0x721f, 0}, + {0x7220, 1}, + {0x7221, 2}, + {0x7222, 3}, + {0x7223, 4}, + {0x7224, 5}, + {0x7225, 6}, + {0x7226, 7}, + {0x7227, 8}, + {0x7228, 6638}, + {0x722a, 4611}, + {0x722c, 2945}, + {0x722e, 0}, + {0x722f, 1}, + {0x7230, 6508}, + {0x7231, 953}, + {0x7232, 8592}, + {0x7234, 0}, + {0x7235, 2339}, + {0x7236, 1715}, + {0x7237, 4150}, + {0x7238, 993}, + {0x7239, 1498}, + {0x723a, 8712}, + {0x723b, 4713}, + {0x723d, 3489}, + {0x723e, 7910}, + {0x723f, 5789}, + {0x7241, 0}, + {0x7242, 1}, + {0x7243, 2}, + {0x7244, 3}, + {0x7245, 4}, + {0x7246, 5}, + {0x7247, 3019}, + {0x7248, 1009}, + {0x724a, 0}, + {0x724b, 1}, + {0x724c, 2951}, + {0x724d, 6505}, + {0x724f, 0}, + {0x7250, 1}, + {0x7251, 2}, + {0x7252, 6506}, + {0x7254, 0}, + {0x7255, 1}, + {0x7256, 6507}, + {0x7258, 9411}, + {0x7259, 4073}, + {0x725b, 2916}, + {0x725d, 6468}, + {0x725f, 2837}, + {0x7261, 2840}, + {0x7262, 2489}, + {0x7264, 0}, + {0x7265, 1}, + {0x7266, 6469}, + {0x7267, 2852}, + {0x7269, 3838}, + {0x726b, 0}, + {0x726c, 1}, + {0x726d, 2}, + {0x726e, 6466}, + {0x726f, 6470}, + {0x7271, 0}, + {0x7272, 3381}, + {0x7274, 0}, + {0x7275, 3104}, + {0x7277, 0}, + {0x7278, 1}, + {0x7279, 3627}, + {0x727a, 3853}, + {0x727c, 0}, + {0x727d, 8396}, + {0x727e, 6471}, + {0x727f, 6472}, + {0x7280, 3865}, + {0x7281, 2514}, + {0x7283, 0}, + {0x7284, 6473}, + {0x7286, 0}, + {0x7287, 1}, + {0x7288, 2}, + {0x7289, 3}, + {0x728a, 1534}, + {0x728b, 6474}, + {0x728d, 6475}, + {0x728f, 6476}, + {0x7291, 0}, + {0x7292, 6477}, + {0x7294, 0}, + {0x7295, 1}, + {0x7296, 9024}, + {0x7298, 0}, + {0x7299, 1}, + {0x729a, 2}, + {0x729b, 3}, + {0x729c, 4}, + {0x729d, 5}, + {0x729e, 6}, + {0x729f, 6467}, + {0x72a1, 0}, + {0x72a2, 7889}, + {0x72a4, 0}, + {0x72a5, 1}, + {0x72a6, 2}, + {0x72a7, 8620}, + {0x72a9, 0}, + {0x72aa, 1}, + {0x72ab, 2}, + {0x72ac, 3209}, + {0x72ad, 5615}, + {0x72af, 1621}, + {0x72b0, 5616}, + {0x72b2, 0}, + {0x72b3, 1}, + {0x72b4, 5617}, + {0x72b6, 4625}, + {0x72b7, 5618}, + {0x72b8, 5619}, + {0x72b9, 4273}, + {0x72bb, 0}, + {0x72bc, 1}, + {0x72bd, 2}, + {0x72be, 3}, + {0x72bf, 4}, + {0x72c0, 8879}, + {0x72c1, 5621}, + {0x72c2, 2430}, + {0x72c3, 5620}, + {0x72c4, 1459}, + {0x72c6, 0}, + {0x72c7, 1}, + {0x72c8, 1056}, + {0x72ca, 0}, + {0x72cb, 1}, + {0x72cc, 2}, + {0x72cd, 5623}, + {0x72ce, 5622}, + {0x72d0, 1971}, + {0x72d2, 5624}, + {0x72d4, 0}, + {0x72d5, 1}, + {0x72d6, 2}, + {0x72d7, 1808}, + {0x72d9, 2304}, + {0x72db, 0}, + {0x72dc, 1}, + {0x72dd, 2}, + {0x72de, 2911}, + {0x72e0, 1940}, + {0x72e1, 2199}, + {0x72e3, 0}, + {0x72e4, 1}, + {0x72e5, 2}, + {0x72e6, 3}, + {0x72e7, 4}, + {0x72e8, 5625}, + {0x72e9, 5627}, + {0x72eb, 0}, + {0x72ec, 1535}, + {0x72ed, 3886}, + {0x72ee, 3391}, + {0x72ef, 5626}, + {0x72f0, 4505}, + {0x72f1, 4321}, + {0x72f2, 5628}, + {0x72f3, 5632}, + {0x72f4, 5629}, + {0x72f6, 0}, + {0x72f7, 5630}, + {0x72f8, 2517}, + {0x72f9, 8630}, + {0x72fa, 5634}, + {0x72fb, 5635}, + {0x72fc, 2482}, + {0x72fd, 7741}, + {0x72ff, 0}, + {0x7301, 5631}, + {0x7303, 5633}, + {0x7305, 0}, + {0x7306, 1}, + {0x7307, 2}, + {0x7308, 3}, + {0x7309, 4}, + {0x730a, 5639}, + {0x730c, 0}, + {0x730d, 1}, + {0x730e, 2589}, + {0x7310, 0}, + {0x7311, 1}, + {0x7312, 2}, + {0x7313, 5637}, + {0x7315, 5642}, + {0x7316, 1221}, + {0x7317, 5636}, + {0x7319, 0}, + {0x731a, 1}, + {0x731b, 2770}, + {0x731c, 1161}, + {0x731d, 5641}, + {0x731e, 5640}, + {0x7320, 0}, + {0x7321, 5638}, + {0x7322, 5643}, + {0x7324, 0}, + {0x7325, 5645}, + {0x7327, 0}, + {0x7328, 1}, + {0x7329, 3988}, + {0x732a, 4588}, + {0x732b, 2733}, + {0x732c, 5646}, + {0x732e, 3908}, + {0x7330, 0}, + {0x7331, 5648}, + {0x7333, 0}, + {0x7334, 1958}, + {0x7336, 8757}, + {0x7337, 6356}, + {0x7338, 5647}, + {0x7339, 5644}, + {0x733b, 9111}, + {0x733d, 0}, + {0x733e, 1984}, + {0x733f, 4342}, + {0x7341, 9109}, + {0x7343, 0}, + {0x7344, 8767}, + {0x7345, 8490}, + {0x7347, 0}, + {0x7348, 1}, + {0x7349, 2}, + {0x734a, 3}, + {0x734b, 4}, + {0x734c, 5}, + {0x734d, 5650}, + {0x734f, 0}, + {0x7350, 5649}, + {0x7352, 6357}, + {0x7354, 0}, + {0x7355, 1}, + {0x7356, 2}, + {0x7357, 5651}, + {0x7359, 0}, + {0x735a, 1}, + {0x735b, 2}, + {0x735c, 3}, + {0x735d, 4}, + {0x735e, 5}, + {0x735f, 6}, + {0x7360, 5652}, + {0x7362, 0}, + {0x7363, 1}, + {0x7364, 2}, + {0x7365, 3}, + {0x7366, 4}, + {0x7367, 5}, + {0x7368, 7890}, + {0x736a, 9110}, + {0x736b, 9112}, + {0x736c, 5653}, + {0x736d, 3572}, + {0x736f, 5654}, + {0x7370, 8354}, + {0x7372, 8036}, + {0x7374, 0}, + {0x7375, 8235}, + {0x7377, 9108}, + {0x7378, 8505}, + {0x737a, 8543}, + {0x737b, 8641}, + {0x737c, 9114}, + {0x737e, 5655}, + {0x7380, 9113}, + {0x7382, 0}, + {0x7383, 1}, + {0x7384, 4041}, + {0x7386, 0}, + {0x7387, 2673}, + {0x7389, 4310}, + {0x738b, 3750}, + {0x738d, 0}, + {0x738e, 6168}, + {0x7390, 0}, + {0x7391, 6169}, + {0x7393, 0}, + {0x7394, 1}, + {0x7395, 2}, + {0x7396, 2288}, + {0x7398, 0}, + {0x7399, 1}, + {0x739a, 2}, + {0x739b, 2705}, + {0x739d, 0}, + {0x739e, 1}, + {0x739f, 6172}, + {0x73a1, 0}, + {0x73a2, 6171}, + {0x73a4, 0}, + {0x73a5, 1}, + {0x73a6, 2}, + {0x73a7, 3}, + {0x73a8, 4}, + {0x73a9, 3735}, + {0x73ab, 2746}, + {0x73ad, 0}, + {0x73ae, 6170}, + {0x73af, 1996}, + {0x73b0, 3907}, + {0x73b2, 2602}, + {0x73b3, 6177}, + {0x73b5, 0}, + {0x73b6, 1}, + {0x73b7, 6176}, + {0x73b9, 0}, + {0x73ba, 6188}, + {0x73bb, 1130}, + {0x73bd, 0}, + {0x73be, 1}, + {0x73bf, 2}, + {0x73c0, 6178}, + {0x73c2, 6174}, + {0x73c4, 0}, + {0x73c5, 1}, + {0x73c6, 2}, + {0x73c7, 3}, + {0x73c8, 6180}, + {0x73c9, 6179}, + {0x73ca, 3315}, + {0x73cc, 0}, + {0x73cd, 4485}, + {0x73cf, 6173}, + {0x73d0, 1606}, + {0x73d1, 6175}, + {0x73d3, 0}, + {0x73d4, 1}, + {0x73d5, 2}, + {0x73d6, 3}, + {0x73d7, 4}, + {0x73d8, 5}, + {0x73d9, 6182}, + {0x73db, 0}, + {0x73dc, 1}, + {0x73dd, 2}, + {0x73de, 6187}, + {0x73e0, 4584}, + {0x73e2, 0}, + {0x73e3, 1}, + {0x73e4, 2}, + {0x73e5, 6181}, + {0x73e7, 6186}, + {0x73e9, 6185}, + {0x73eb, 0}, + {0x73ec, 1}, + {0x73ed, 1003}, + {0x73ef, 0}, + {0x73f0, 1}, + {0x73f1, 2}, + {0x73f2, 6189}, + {0x73f4, 0}, + {0x73f5, 1}, + {0x73f6, 2}, + {0x73f7, 3}, + {0x73f8, 4}, + {0x73f9, 5}, + {0x73fa, 6}, + {0x73fb, 7}, + {0x73fc, 8}, + {0x73fd, 9}, + {0x73fe, 8640}, + {0x7401, 0}, + {0x7402, 1}, + {0x7403, 3183}, + {0x7405, 2480}, + {0x7406, 2520}, + {0x7408, 0}, + {0x7409, 2617}, + {0x740a, 6184}, + {0x740c, 0}, + {0x740d, 1}, + {0x740e, 2}, + {0x740f, 6190}, + {0x7410, 3563}, + {0x7412, 0}, + {0x7413, 1}, + {0x7414, 2}, + {0x7415, 3}, + {0x7416, 4}, + {0x7417, 5}, + {0x7418, 6}, + {0x7419, 7}, + {0x741a, 6200}, + {0x741b, 6199}, + {0x741d, 0}, + {0x741e, 1}, + {0x741f, 2}, + {0x7420, 3}, + {0x7421, 4}, + {0x7422, 4638}, + {0x7424, 0}, + {0x7425, 6194}, + {0x7426, 6193}, + {0x7428, 6195}, + {0x742a, 6191}, + {0x742c, 6198}, + {0x742e, 6197}, + {0x7430, 6196}, + {0x7432, 0}, + {0x7433, 2590}, + {0x7434, 3158}, + {0x7435, 3006}, + {0x7436, 2948}, + {0x7438, 0}, + {0x7439, 1}, + {0x743a, 2}, + {0x743b, 3}, + {0x743c, 3178}, + {0x743e, 0}, + {0x743f, 9312}, + {0x7441, 6201}, + {0x7443, 0}, + {0x7444, 1}, + {0x7445, 2}, + {0x7446, 3}, + {0x7447, 4}, + {0x7448, 5}, + {0x7449, 6}, + {0x744a, 7}, + {0x744b, 9308}, + {0x744d, 0}, + {0x744e, 1}, + {0x744f, 2}, + {0x7450, 3}, + {0x7451, 4}, + {0x7452, 5}, + {0x7453, 6}, + {0x7454, 7}, + {0x7455, 6204}, + {0x7457, 6203}, + {0x7459, 6205}, + {0x745a, 1966}, + {0x745b, 6192}, + {0x745c, 6202}, + {0x745e, 3275}, + {0x745f, 3299}, + {0x7461, 0}, + {0x7462, 1}, + {0x7463, 8541}, + {0x7465, 0}, + {0x7466, 1}, + {0x7467, 2}, + {0x7468, 3}, + {0x7469, 8741}, + {0x746a, 8298}, + {0x746c, 0}, + {0x746d, 6207}, + {0x746f, 0}, + {0x7470, 1854}, + {0x7472, 0}, + {0x7473, 1}, + {0x7474, 2}, + {0x7475, 3}, + {0x7476, 4135}, + {0x7477, 6206}, + {0x7479, 0}, + {0x747a, 1}, + {0x747b, 2}, + {0x747c, 3}, + {0x747d, 4}, + {0x747e, 6208}, + {0x7480, 6211}, + {0x7481, 6212}, + {0x7483, 2544}, + {0x7485, 0}, + {0x7486, 1}, + {0x7487, 6213}, + {0x7489, 9313}, + {0x748b, 6214}, + {0x748d, 0}, + {0x748e, 6210}, + {0x7490, 6218}, + {0x7492, 0}, + {0x7493, 1}, + {0x7494, 2}, + {0x7495, 3}, + {0x7496, 4}, + {0x7497, 5}, + {0x7498, 6}, + {0x7499, 7}, + {0x749a, 8}, + {0x749b, 9}, + {0x749c, 6209}, + {0x749e, 6215}, + {0x74a0, 0}, + {0x74a1, 1}, + {0x74a2, 2}, + {0x74a3, 9307}, + {0x74a5, 0}, + {0x74a6, 9314}, + {0x74a7, 6219}, + {0x74a8, 6216}, + {0x74a9, 6217}, + {0x74ab, 0}, + {0x74ac, 1}, + {0x74ad, 2}, + {0x74ae, 3}, + {0x74af, 4}, + {0x74b0, 8020}, + {0x74b2, 0}, + {0x74b3, 1}, + {0x74b4, 2}, + {0x74b5, 3}, + {0x74b6, 4}, + {0x74b7, 5}, + {0x74b8, 6}, + {0x74b9, 7}, + {0x74ba, 6221}, + {0x74bc, 0}, + {0x74bd, 9311}, + {0x74bf, 0}, + {0x74c0, 1}, + {0x74c1, 2}, + {0x74c2, 3}, + {0x74c3, 4}, + {0x74c4, 5}, + {0x74c5, 6}, + {0x74c6, 7}, + {0x74c7, 8}, + {0x74c8, 9}, + {0x74c9, 10}, + {0x74ca, 8428}, + {0x74cc, 0}, + {0x74cd, 1}, + {0x74ce, 2}, + {0x74cf, 9309}, + {0x74d1, 0}, + {0x74d2, 6220}, + {0x74d4, 9315}, + {0x74d6, 0}, + {0x74d7, 1}, + {0x74d8, 2}, + {0x74d9, 3}, + {0x74da, 9316}, + {0x74dc, 1832}, + {0x74de, 6962}, + {0x74e0, 6963}, + {0x74e2, 3023}, + {0x74e3, 1013}, + {0x74e4, 3226}, + {0x74e6, 3728}, + {0x74e8, 0}, + {0x74e9, 1}, + {0x74ea, 2}, + {0x74eb, 3}, + {0x74ec, 4}, + {0x74ed, 5}, + {0x74ee, 3804}, + {0x74ef, 6403}, + {0x74f1, 0}, + {0x74f2, 1}, + {0x74f3, 2}, + {0x74f4, 6404}, + {0x74f6, 3038}, + {0x74f7, 1356}, + {0x74f9, 0}, + {0x74fa, 1}, + {0x74fb, 2}, + {0x74fc, 3}, + {0x74fd, 4}, + {0x74fe, 5}, + {0x74ff, 6405}, + {0x7501, 0}, + {0x7502, 1}, + {0x7503, 2}, + {0x7504, 4488}, + {0x7506, 0}, + {0x7507, 1}, + {0x7508, 2}, + {0x7509, 3}, + {0x750a, 4}, + {0x750b, 5}, + {0x750c, 9381}, + {0x750d, 5253}, + {0x750f, 6406}, + {0x7511, 6407}, + {0x7513, 6408}, + {0x7515, 0}, + {0x7516, 1}, + {0x7517, 2}, + {0x7518, 1733}, + {0x7519, 5368}, + {0x751a, 3374}, + {0x751c, 3651}, + {0x751e, 0}, + {0x751f, 3379}, + {0x7521, 0}, + {0x7522, 1}, + {0x7523, 7792}, + {0x7525, 3380}, + {0x7527, 0}, + {0x7528, 4264}, + {0x7529, 3483}, + {0x752b, 1697}, + {0x752c, 6964}, + {0x752d, 1067}, + {0x752f, 5940}, + {0x7530, 3650}, + {0x7531, 4270}, + {0x7532, 2122}, + {0x7533, 3363}, + {0x7535, 1480}, + {0x7537, 2867}, + {0x7538, 1482}, + {0x753a, 6776}, + {0x753b, 1986}, + {0x753d, 0}, + {0x753e, 6166}, + {0x7540, 6777}, + {0x7542, 0}, + {0x7543, 1}, + {0x7544, 2}, + {0x7545, 1230}, + {0x7547, 0}, + {0x7548, 6780}, + {0x754a, 0}, + {0x754b, 6779}, + {0x754c, 2232}, + {0x754e, 6778}, + {0x754f, 3782}, + {0x7551, 0}, + {0x7552, 1}, + {0x7553, 2}, + {0x7554, 2960}, + {0x7556, 0}, + {0x7557, 1}, + {0x7558, 2}, + {0x7559, 2621}, + {0x755a, 5022}, + {0x755b, 6781}, + {0x755c, 4030}, + {0x755d, 8335}, + {0x755f, 0}, + {0x7560, 1}, + {0x7561, 2}, + {0x7562, 7746}, + {0x7564, 0}, + {0x7565, 2683}, + {0x7566, 3079}, + {0x7568, 0}, + {0x7569, 1}, + {0x756a, 1609}, + {0x756b, 8014}, + {0x756d, 0}, + {0x756e, 1}, + {0x756f, 2}, + {0x7570, 3}, + {0x7571, 4}, + {0x7572, 6782}, + {0x7574, 1296}, + {0x7576, 7857}, + {0x7578, 2064}, + {0x7579, 6783}, + {0x757b, 0}, + {0x757c, 1}, + {0x757d, 2}, + {0x757e, 3}, + {0x757f, 6164}, + {0x7581, 0}, + {0x7582, 1}, + {0x7583, 6784}, + {0x7585, 0}, + {0x7586, 2175}, + {0x7587, 7819}, + {0x7589, 0}, + {0x758a, 1}, + {0x758b, 7110}, + {0x758d, 0}, + {0x758e, 1}, + {0x758f, 3455}, + {0x7591, 4176}, + {0x7592, 7008}, + {0x7594, 7009}, + {0x7596, 7010}, + {0x7597, 2575}, + {0x7599, 1768}, + {0x759a, 2301}, + {0x759c, 0}, + {0x759d, 7012}, + {0x759f, 2930}, + {0x75a0, 7011}, + {0x75a1, 4122}, + {0x75a3, 7014}, + {0x75a4, 983}, + {0x75a5, 2235}, + {0x75a7, 0}, + {0x75a8, 1}, + {0x75a9, 2}, + {0x75aa, 3}, + {0x75ab, 4198}, + {0x75ac, 7013}, + {0x75ae, 1330}, + {0x75af, 1669}, + {0x75b0, 7020}, + {0x75b1, 7019}, + {0x75b2, 3010}, + {0x75b3, 7015}, + {0x75b4, 7016}, + {0x75b5, 1350}, + {0x75b7, 0}, + {0x75b8, 7017}, + {0x75b9, 4495}, + {0x75bb, 0}, + {0x75bc, 3630}, + {0x75bd, 2305}, + {0x75be, 2085}, + {0x75c0, 0}, + {0x75c1, 1}, + {0x75c2, 7022}, + {0x75c3, 7021}, + {0x75c4, 7018}, + {0x75c5, 1128}, + {0x75c7, 4513}, + {0x75c8, 4253}, + {0x75c9, 2278}, + {0x75ca, 3207}, + {0x75cc, 0}, + {0x75cd, 7024}, + {0x75cf, 0}, + {0x75d0, 1}, + {0x75d1, 2}, + {0x75d2, 4128}, + {0x75d4, 4555}, + {0x75d5, 1938}, + {0x75d6, 7023}, + {0x75d8, 1530}, + {0x75d9, 8134}, + {0x75db, 3685}, + {0x75dd, 0}, + {0x75de, 3013}, + {0x75e0, 0}, + {0x75e1, 1}, + {0x75e2, 2538}, + {0x75e3, 7025}, + {0x75e4, 7028}, + {0x75e6, 7027}, + {0x75e7, 7030}, + {0x75e8, 7026}, + {0x75ea, 2003}, + {0x75eb, 7029}, + {0x75ed, 0}, + {0x75ee, 1}, + {0x75ef, 2}, + {0x75f0, 3592}, + {0x75f1, 7032}, + {0x75f3, 0}, + {0x75f4, 1274}, + {0x75f6, 0}, + {0x75f7, 1}, + {0x75f8, 2}, + {0x75f9, 1085}, + {0x75fb, 0}, + {0x75fc, 7033}, + {0x75fe, 0}, + {0x75ff, 7034}, + {0x7600, 7036}, + {0x7601, 1380}, + {0x7602, 9646}, + {0x7603, 7031}, + {0x7605, 7037}, + {0x7607, 0}, + {0x7608, 1}, + {0x7609, 2}, + {0x760a, 7040}, + {0x760b, 7937}, + {0x760c, 7038}, + {0x760d, 8704}, + {0x760f, 0}, + {0x7610, 7035}, + {0x7612, 0}, + {0x7613, 1}, + {0x7614, 2}, + {0x7615, 7043}, + {0x7617, 7039}, + {0x7618, 7042}, + {0x7619, 7044}, + {0x761b, 7045}, + {0x761d, 0}, + {0x761e, 9650}, + {0x761f, 3792}, + {0x7620, 7048}, + {0x7621, 7831}, + {0x7622, 7047}, + {0x7624, 2623}, + {0x7625, 7041}, + {0x7626, 3444}, + {0x7627, 8363}, + {0x7629, 1396}, + {0x762a, 1114}, + {0x762b, 3588}, + {0x762d, 7050}, + {0x762f, 0}, + {0x7630, 7051}, + {0x7632, 0}, + {0x7633, 7056}, + {0x7634, 4463}, + {0x7635, 7053}, + {0x7637, 0}, + {0x7638, 3214}, + {0x763a, 0}, + {0x763b, 9651}, + {0x763c, 7046}, + {0x763e, 7055}, + {0x763f, 7052}, + {0x7640, 7049}, + {0x7642, 8232}, + {0x7643, 7054}, + {0x7645, 0}, + {0x7646, 9647}, + {0x7647, 9648}, + {0x7649, 9649}, + {0x764b, 0}, + {0x764c, 948}, + {0x764d, 7057}, + {0x764f, 0}, + {0x7650, 1}, + {0x7651, 2}, + {0x7652, 3}, + {0x7653, 4}, + {0x7654, 7059}, + {0x7656, 7061}, + {0x7658, 9644}, + {0x765a, 0}, + {0x765b, 1}, + {0x765c, 7060}, + {0x765e, 7058}, + {0x765f, 7758}, + {0x7661, 0}, + {0x7662, 8706}, + {0x7663, 4043}, + {0x7664, 9643}, + {0x7665, 8838}, + {0x7667, 9645}, + {0x7669, 9654}, + {0x766b, 7062}, + {0x766c, 8675}, + {0x766d, 9652}, + {0x766e, 9653}, + {0x766f, 7063}, + {0x7670, 8751}, + {0x7671, 8549}, + {0x7672, 9655}, + {0x7674, 0}, + {0x7675, 1}, + {0x7676, 2}, + {0x7677, 3}, + {0x7678, 1864}, + {0x767a, 0}, + {0x767b, 1448}, + {0x767c, 7913}, + {0x767d, 994}, + {0x767e, 996}, + {0x7680, 0}, + {0x7681, 1}, + {0x7682, 4400}, + {0x7684, 1445}, + {0x7686, 2213}, + {0x7687, 2015}, + {0x7688, 6957}, + {0x768a, 0}, + {0x768b, 1753}, + {0x768d, 0}, + {0x768e, 6958}, + {0x7690, 0}, + {0x7691, 947}, + {0x7693, 6959}, + {0x7695, 0}, + {0x7696, 3743}, + {0x7698, 0}, + {0x7699, 6960}, + {0x769a, 7717}, + {0x769c, 0}, + {0x769d, 1}, + {0x769e, 2}, + {0x769f, 3}, + {0x76a0, 4}, + {0x76a1, 5}, + {0x76a2, 6}, + {0x76a3, 7}, + {0x76a4, 6961}, + {0x76a6, 0}, + {0x76a7, 1}, + {0x76a8, 2}, + {0x76a9, 3}, + {0x76aa, 4}, + {0x76ab, 5}, + {0x76ac, 6}, + {0x76ad, 7}, + {0x76ae, 3011}, + {0x76b0, 0}, + {0x76b1, 4580}, + {0x76b2, 7112}, + {0x76b4, 7113}, + {0x76b6, 0}, + {0x76b7, 1}, + {0x76b8, 9664}, + {0x76ba, 8858}, + {0x76bc, 0}, + {0x76bd, 1}, + {0x76be, 2}, + {0x76bf, 2808}, + {0x76c1, 0}, + {0x76c2, 4288}, + {0x76c4, 0}, + {0x76c5, 4560}, + {0x76c6, 2985}, + {0x76c8, 4244}, + {0x76ca, 4205}, + {0x76cc, 0}, + {0x76cd, 6795}, + {0x76ce, 966}, + {0x76cf, 4438}, + {0x76d0, 4087}, + {0x76d1, 2131}, + {0x76d2, 1927}, + {0x76d4, 2437}, + {0x76d6, 1730}, + {0x76d7, 1442}, + {0x76d8, 2957}, + {0x76da, 0}, + {0x76db, 3385}, + {0x76dd, 0}, + {0x76de, 8814}, + {0x76df, 2768}, + {0x76e1, 8125}, + {0x76e3, 8068}, + {0x76e4, 8370}, + {0x76e5, 6796}, + {0x76e7, 8259}, + {0x76e9, 0}, + {0x76ea, 1}, + {0x76eb, 2}, + {0x76ec, 3}, + {0x76ed, 4}, + {0x76ee, 2850}, + {0x76ef, 1505}, + {0x76f1, 6744}, + {0x76f2, 2729}, + {0x76f4, 4528}, + {0x76f6, 0}, + {0x76f7, 1}, + {0x76f8, 3917}, + {0x76f9, 6747}, + {0x76fb, 0}, + {0x76fc, 2959}, + {0x76fe, 1563}, + {0x7701, 3384}, + {0x7703, 0}, + {0x7704, 6745}, + {0x7706, 0}, + {0x7707, 6748}, + {0x7708, 6749}, + {0x7709, 2753}, + {0x770b, 2369}, + {0x770d, 6746}, + {0x770f, 0}, + {0x7710, 1}, + {0x7711, 2}, + {0x7712, 3}, + {0x7713, 4}, + {0x7714, 5}, + {0x7715, 6}, + {0x7716, 7}, + {0x7717, 8}, + {0x7718, 9}, + {0x7719, 6752}, + {0x771a, 6750}, + {0x771c, 0}, + {0x771d, 1}, + {0x771e, 2}, + {0x771f, 4487}, + {0x7720, 2788}, + {0x7722, 6751}, + {0x7724, 0}, + {0x7725, 1}, + {0x7726, 6754}, + {0x7728, 4420}, + {0x7729, 4044}, + {0x772b, 0}, + {0x772c, 1}, + {0x772d, 6753}, + {0x772f, 2773}, + {0x7731, 0}, + {0x7732, 1}, + {0x7733, 2}, + {0x7734, 3}, + {0x7735, 6755}, + {0x7736, 2433}, + {0x7737, 2331}, + {0x7738, 6756}, + {0x773a, 3658}, + {0x773c, 4100}, + {0x773e, 0}, + {0x773f, 1}, + {0x7740, 4642}, + {0x7741, 4503}, + {0x7743, 6760}, + {0x7745, 0}, + {0x7746, 1}, + {0x7747, 6759}, + {0x7749, 0}, + {0x774a, 1}, + {0x774b, 2}, + {0x774c, 3}, + {0x774d, 4}, + {0x774e, 5}, + {0x774f, 9860}, + {0x7750, 6757}, + {0x7751, 6758}, + {0x7753, 0}, + {0x7754, 1}, + {0x7755, 2}, + {0x7756, 3}, + {0x7757, 4}, + {0x7758, 5}, + {0x7759, 6}, + {0x775a, 6761}, + {0x775b, 2261}, + {0x775d, 0}, + {0x775e, 9455}, + {0x7760, 0}, + {0x7761, 3492}, + {0x7762, 6763}, + {0x7763, 1532}, + {0x7765, 6764}, + {0x7766, 2851}, + {0x7768, 6762}, + {0x776a, 0}, + {0x776b, 2223}, + {0x776c, 1166}, + {0x776e, 0}, + {0x776f, 1}, + {0x7770, 2}, + {0x7771, 3}, + {0x7772, 4}, + {0x7773, 5}, + {0x7774, 6}, + {0x7775, 7}, + {0x7776, 8}, + {0x7777, 9}, + {0x7778, 10}, + {0x7779, 1538}, + {0x777b, 0}, + {0x777c, 1}, + {0x777d, 6767}, + {0x777e, 4720}, + {0x777f, 6765}, + {0x7780, 6768}, + {0x7782, 0}, + {0x7783, 1}, + {0x7784, 2798}, + {0x7785, 1303}, + {0x7787, 0}, + {0x7788, 1}, + {0x7789, 2}, + {0x778a, 3}, + {0x778b, 4}, + {0x778c, 6769}, + {0x778d, 6766}, + {0x778e, 3878}, + {0x7790, 0}, + {0x7791, 6770}, + {0x7792, 2718}, + {0x7794, 0}, + {0x7795, 1}, + {0x7796, 2}, + {0x7797, 3}, + {0x7798, 9454}, + {0x779a, 0}, + {0x779b, 1}, + {0x779c, 2}, + {0x779d, 3}, + {0x779e, 8308}, + {0x779f, 6771}, + {0x77a0, 6772}, + {0x77a2, 5269}, + {0x77a4, 0}, + {0x77a5, 3026}, + {0x77a7, 3139}, + {0x77a9, 4596}, + {0x77aa, 1450}, + {0x77ac, 3495}, + {0x77ad, 9863}, + {0x77af, 0}, + {0x77b0, 6773}, + {0x77b2, 0}, + {0x77b3, 3676}, + {0x77b5, 6774}, + {0x77b7, 0}, + {0x77b8, 1}, + {0x77b9, 2}, + {0x77ba, 3}, + {0x77bb, 4433}, + {0x77bc, 9456}, + {0x77bd, 6775}, + {0x77bf, 7550}, + {0x77c1, 0}, + {0x77c2, 1}, + {0x77c3, 2}, + {0x77c4, 3}, + {0x77c5, 4}, + {0x77c6, 5}, + {0x77c7, 9869}, + {0x77c9, 0}, + {0x77ca, 1}, + {0x77cb, 2}, + {0x77cc, 3}, + {0x77cd, 5015}, + {0x77cf, 0}, + {0x77d0, 1}, + {0x77d1, 2}, + {0x77d2, 3}, + {0x77d3, 4}, + {0x77d4, 5}, + {0x77d5, 6}, + {0x77d6, 7}, + {0x77d7, 1318}, + {0x77d9, 0}, + {0x77da, 8864}, + {0x77db, 2737}, + {0x77dc, 7114}, + {0x77de, 0}, + {0x77df, 1}, + {0x77e0, 2}, + {0x77e1, 3}, + {0x77e2, 3407}, + {0x77e3, 4186}, + {0x77e5, 4521}, + {0x77e7, 6938}, + {0x77e9, 2311}, + {0x77eb, 2196}, + {0x77ec, 6939}, + {0x77ed, 1547}, + {0x77ee, 950}, + {0x77ef, 8107}, + {0x77f1, 0}, + {0x77f2, 1}, + {0x77f3, 3398}, + {0x77f5, 0}, + {0x77f6, 6690}, + {0x77f8, 6691}, + {0x77fa, 0}, + {0x77fb, 1}, + {0x77fc, 2}, + {0x77fd, 3848}, + {0x77fe, 1612}, + {0x77ff, 2432}, + {0x7800, 6692}, + {0x7801, 2706}, + {0x7802, 3305}, + {0x7804, 0}, + {0x7805, 1}, + {0x7806, 2}, + {0x7807, 3}, + {0x7808, 4}, + {0x7809, 6693}, + {0x780b, 0}, + {0x780c, 3093}, + {0x780d, 2368}, + {0x780f, 0}, + {0x7810, 1}, + {0x7811, 6696}, + {0x7812, 3001}, + {0x7814, 4089}, + {0x7816, 4614}, + {0x7817, 6694}, + {0x7818, 6695}, + {0x781a, 4107}, + {0x781c, 6699}, + {0x781d, 6700}, + {0x781f, 6704}, + {0x7821, 0}, + {0x7822, 1}, + {0x7823, 6708}, + {0x7825, 6706}, + {0x7826, 6714}, + {0x7827, 4489}, + {0x7829, 6709}, + {0x782b, 0}, + {0x782c, 6707}, + {0x782d, 6698}, + {0x782f, 0}, + {0x7830, 2986}, + {0x7832, 0}, + {0x7833, 1}, + {0x7834, 3045}, + {0x7836, 0}, + {0x7837, 3362}, + {0x7838, 4373}, + {0x7839, 6701}, + {0x783a, 6702}, + {0x783b, 6703}, + {0x783c, 6705}, + {0x783e, 2532}, + {0x7840, 1316}, + {0x7842, 0}, + {0x7843, 9896}, + {0x7845, 1857}, + {0x7847, 6716}, + {0x7849, 0}, + {0x784a, 1}, + {0x784b, 2}, + {0x784c, 6717}, + {0x784e, 6710}, + {0x7850, 6715}, + {0x7852, 3847}, + {0x7854, 0}, + {0x7855, 3499}, + {0x7856, 6712}, + {0x7857, 6713}, + {0x7859, 0}, + {0x785a, 1}, + {0x785b, 2}, + {0x785c, 3}, + {0x785d, 3938}, + {0x785f, 0}, + {0x7860, 1}, + {0x7861, 2}, + {0x7862, 3}, + {0x7863, 4}, + {0x7864, 9449}, + {0x7866, 0}, + {0x7867, 1}, + {0x7868, 9445}, + {0x786a, 6718}, + {0x786b, 2619}, + {0x786c, 4247}, + {0x786d, 6711}, + {0x786e, 3218}, + {0x786f, 8698}, + {0x7871, 0}, + {0x7872, 1}, + {0x7873, 2}, + {0x7874, 3}, + {0x7875, 4}, + {0x7876, 5}, + {0x7877, 2146}, + {0x7879, 0}, + {0x787a, 1}, + {0x787b, 2}, + {0x787c, 2993}, + {0x787e, 0}, + {0x787f, 1}, + {0x7880, 2}, + {0x7881, 3}, + {0x7882, 4}, + {0x7883, 5}, + {0x7884, 6}, + {0x7885, 7}, + {0x7886, 8}, + {0x7887, 6722}, + {0x7889, 1488}, + {0x788b, 0}, + {0x788c, 2652}, + {0x788d, 952}, + {0x788e, 3550}, + {0x7890, 0}, + {0x7891, 1047}, + {0x7893, 6720}, + {0x7895, 0}, + {0x7896, 1}, + {0x7897, 3740}, + {0x7898, 1475}, + {0x789a, 6721}, + {0x789b, 6719}, + {0x789c, 6723}, + {0x789e, 0}, + {0x789f, 1499}, + {0x78a1, 6724}, + {0x78a3, 6725}, + {0x78a5, 6728}, + {0x78a7, 1077}, + {0x78a9, 8520}, + {0x78ab, 0}, + {0x78ac, 1}, + {0x78ad, 9444}, + {0x78af, 0}, + {0x78b0, 2999}, + {0x78b1, 2145}, + {0x78b2, 6726}, + {0x78b3, 3599}, + {0x78b4, 1201}, + {0x78b6, 0}, + {0x78b7, 1}, + {0x78b8, 9446}, + {0x78b9, 6727}, + {0x78ba, 8439}, + {0x78bc, 8299}, + {0x78be, 2894}, + {0x78c0, 0}, + {0x78c1, 1352}, + {0x78c3, 0}, + {0x78c4, 1}, + {0x78c5, 1024}, + {0x78c7, 0}, + {0x78c8, 1}, + {0x78c9, 6731}, + {0x78ca, 2501}, + {0x78cb, 1387}, + {0x78cd, 0}, + {0x78ce, 1}, + {0x78cf, 2}, + {0x78d0, 2958}, + {0x78d2, 0}, + {0x78d3, 1}, + {0x78d4, 6729}, + {0x78d5, 2385}, + {0x78d7, 0}, + {0x78d8, 1}, + {0x78d9, 6730}, + {0x78da, 8871}, + {0x78dc, 0}, + {0x78dd, 1}, + {0x78de, 2}, + {0x78df, 3}, + {0x78e0, 4}, + {0x78e1, 5}, + {0x78e2, 6}, + {0x78e3, 9452}, + {0x78e5, 0}, + {0x78e6, 1}, + {0x78e7, 9451}, + {0x78e8, 2824}, + {0x78ea, 0}, + {0x78eb, 1}, + {0x78ec, 6732}, + {0x78ee, 0}, + {0x78ef, 9443}, + {0x78f1, 0}, + {0x78f2, 6733}, + {0x78f4, 6735}, + {0x78f6, 0}, + {0x78f7, 2592}, + {0x78f9, 0}, + {0x78fa, 2012}, + {0x78fc, 0}, + {0x78fd, 9450}, + {0x78ff, 0}, + {0x7901, 2185}, + {0x7903, 0}, + {0x7904, 1}, + {0x7905, 6734}, + {0x7907, 0}, + {0x7908, 1}, + {0x7909, 2}, + {0x790a, 3}, + {0x790b, 4}, + {0x790c, 5}, + {0x790d, 6}, + {0x790e, 7826}, + {0x7910, 0}, + {0x7911, 1}, + {0x7912, 2}, + {0x7913, 6736}, + {0x7915, 0}, + {0x7916, 1}, + {0x7917, 2}, + {0x7918, 3}, + {0x7919, 7719}, + {0x791b, 0}, + {0x791c, 1}, + {0x791d, 2}, + {0x791e, 6738}, + {0x7920, 0}, + {0x7921, 1}, + {0x7922, 2}, + {0x7923, 3}, + {0x7924, 6737}, + {0x7926, 8166}, + {0x7928, 0}, + {0x7929, 1}, + {0x792a, 9447}, + {0x792b, 8210}, + {0x792c, 7916}, + {0x792e, 0}, + {0x792f, 1}, + {0x7930, 2}, + {0x7931, 9448}, + {0x7933, 0}, + {0x7934, 6739}, + {0x7936, 0}, + {0x7937, 1}, + {0x7938, 2}, + {0x7939, 3}, + {0x793a, 3413}, + {0x793b, 6648}, + {0x793c, 2524}, + {0x793e, 3360}, + {0x7940, 6649}, + {0x7941, 3085}, + {0x7943, 0}, + {0x7944, 1}, + {0x7945, 2}, + {0x7946, 6650}, + {0x7948, 3084}, + {0x7949, 6651}, + {0x794b, 0}, + {0x794c, 1}, + {0x794d, 2}, + {0x794e, 3}, + {0x794f, 4}, + {0x7950, 5}, + {0x7951, 6}, + {0x7952, 7}, + {0x7953, 6654}, + {0x7955, 0}, + {0x7956, 4675}, + {0x7957, 6657}, + {0x7959, 0}, + {0x795a, 6655}, + {0x795b, 6652}, + {0x795c, 6653}, + {0x795d, 4608}, + {0x795e, 3370}, + {0x795f, 3555}, + {0x7960, 6658}, + {0x7962, 6656}, + {0x7964, 0}, + {0x7965, 3926}, + {0x7967, 6660}, + {0x7968, 3024}, + {0x796a, 0}, + {0x796b, 1}, + {0x796c, 2}, + {0x796d, 2099}, + {0x796f, 6659}, + {0x7971, 0}, + {0x7972, 1}, + {0x7973, 2}, + {0x7974, 3}, + {0x7975, 4}, + {0x7976, 5}, + {0x7977, 1436}, + {0x7978, 2059}, + {0x797a, 6661}, + {0x797c, 0}, + {0x797d, 1}, + {0x797e, 2}, + {0x797f, 3}, + {0x7980, 4875}, + {0x7981, 2252}, + {0x7983, 0}, + {0x7984, 2658}, + {0x7985, 6662}, + {0x7987, 0}, + {0x7988, 1}, + {0x7989, 2}, + {0x798a, 6663}, + {0x798c, 0}, + {0x798d, 8038}, + {0x798e, 9436}, + {0x798f, 1694}, + {0x7991, 0}, + {0x7992, 1}, + {0x7993, 2}, + {0x7994, 3}, + {0x7995, 4}, + {0x7996, 5}, + {0x7997, 6}, + {0x7998, 7}, + {0x7999, 8}, + {0x799a, 6664}, + {0x799c, 0}, + {0x799d, 1}, + {0x799e, 2}, + {0x799f, 3}, + {0x79a0, 4}, + {0x79a1, 5}, + {0x79a2, 6}, + {0x79a3, 7}, + {0x79a4, 8}, + {0x79a5, 9}, + {0x79a6, 9890}, + {0x79a7, 6665}, + {0x79a9, 0}, + {0x79aa, 9437}, + {0x79ac, 0}, + {0x79ad, 1}, + {0x79ae, 8206}, + {0x79b0, 9435}, + {0x79b1, 7864}, + {0x79b3, 6666}, + {0x79b5, 0}, + {0x79b6, 1}, + {0x79b7, 2}, + {0x79b8, 3}, + {0x79b9, 4306}, + {0x79ba, 4708}, + {0x79bb, 2518}, + {0x79bd, 3162}, + {0x79be, 1923}, + {0x79c0, 4014}, + {0x79c1, 3506}, + {0x79c3, 3691}, + {0x79c5, 0}, + {0x79c6, 1740}, + {0x79c8, 0}, + {0x79c9, 1125}, + {0x79cb, 3180}, + {0x79cd, 4565}, + {0x79cf, 0}, + {0x79d0, 1}, + {0x79d1, 2387}, + {0x79d2, 2800}, + {0x79d4, 0}, + {0x79d5, 6941}, + {0x79d7, 0}, + {0x79d8, 2781}, + {0x79da, 0}, + {0x79db, 1}, + {0x79dc, 2}, + {0x79dd, 3}, + {0x79de, 4}, + {0x79df, 4671}, + {0x79e1, 0}, + {0x79e2, 1}, + {0x79e3, 6943}, + {0x79e4, 1272}, + {0x79e6, 3157}, + {0x79e7, 4118}, + {0x79e9, 4551}, + {0x79eb, 6944}, + {0x79ed, 6942}, + {0x79ef, 2066}, + {0x79f0, 1259}, + {0x79f2, 0}, + {0x79f3, 1}, + {0x79f4, 2}, + {0x79f5, 3}, + {0x79f6, 4}, + {0x79f7, 5}, + {0x79f8, 2214}, + {0x79fa, 0}, + {0x79fb, 4173}, + {0x79fd, 2037}, + {0x79ff, 0}, + {0x7a00, 3854}, + {0x7a02, 6948}, + {0x7a03, 6947}, + {0x7a05, 0}, + {0x7a06, 6945}, + {0x7a08, 0}, + {0x7a09, 1}, + {0x7a0a, 2}, + {0x7a0b, 1265}, + {0x7a0d, 3341}, + {0x7a0e, 3493}, + {0x7a10, 0}, + {0x7a11, 1}, + {0x7a12, 2}, + {0x7a13, 3}, + {0x7a14, 6950}, + {0x7a16, 0}, + {0x7a17, 1001}, + {0x7a19, 0}, + {0x7a1a, 4552}, + {0x7a1c, 0}, + {0x7a1d, 1}, + {0x7a1e, 6949}, + {0x7a20, 1298}, + {0x7a22, 0}, + {0x7a23, 7567}, + {0x7a25, 0}, + {0x7a26, 1}, + {0x7a27, 2}, + {0x7a28, 3}, + {0x7a29, 4}, + {0x7a2a, 5}, + {0x7a2b, 6}, + {0x7a2c, 7}, + {0x7a2d, 8}, + {0x7a2e, 8853}, + {0x7a30, 0}, + {0x7a31, 7808}, + {0x7a33, 3799}, + {0x7a35, 0}, + {0x7a36, 1}, + {0x7a37, 6952}, + {0x7a39, 6951}, + {0x7a3b, 1439}, + {0x7a3c, 2125}, + {0x7a3d, 2065}, + {0x7a3f, 1760}, + {0x7a40, 9847}, + {0x7a42, 0}, + {0x7a43, 1}, + {0x7a44, 2}, + {0x7a45, 3}, + {0x7a46, 2853}, + {0x7a48, 0}, + {0x7a49, 1}, + {0x7a4a, 2}, + {0x7a4b, 3}, + {0x7a4c, 9764}, + {0x7a4d, 8041}, + {0x7a4e, 8747}, + {0x7a50, 0}, + {0x7a51, 6953}, + {0x7a53, 0}, + {0x7a54, 1}, + {0x7a55, 2}, + {0x7a56, 3}, + {0x7a57, 3552}, + {0x7a59, 0}, + {0x7a5a, 1}, + {0x7a5b, 2}, + {0x7a5c, 3}, + {0x7a5d, 4}, + {0x7a5e, 5}, + {0x7a5f, 6}, + {0x7a60, 7}, + {0x7a61, 9599}, + {0x7a62, 8027}, + {0x7a64, 0}, + {0x7a65, 1}, + {0x7a66, 2}, + {0x7a67, 3}, + {0x7a68, 4}, + {0x7a69, 8603}, + {0x7a6b, 9853}, + {0x7a6d, 0}, + {0x7a6e, 1}, + {0x7a6f, 2}, + {0x7a70, 6956}, + {0x7a72, 0}, + {0x7a73, 1}, + {0x7a74, 4049}, + {0x7a76, 2286}, + {0x7a77, 3179}, + {0x7a78, 7066}, + {0x7a79, 7067}, + {0x7a7a, 2402}, + {0x7a7c, 0}, + {0x7a7d, 1}, + {0x7a7e, 2}, + {0x7a7f, 1324}, + {0x7a80, 7068}, + {0x7a81, 3692}, + {0x7a83, 3153}, + {0x7a84, 4430}, + {0x7a86, 7069}, + {0x7a88, 7070}, + {0x7a8a, 0}, + {0x7a8b, 1}, + {0x7a8c, 2}, + {0x7a8d, 3148}, + {0x7a8f, 0}, + {0x7a90, 1}, + {0x7a91, 4139}, + {0x7a92, 4558}, + {0x7a94, 0}, + {0x7a95, 7071}, + {0x7a96, 2210}, + {0x7a97, 1331}, + {0x7a98, 2284}, + {0x7a9a, 0}, + {0x7a9b, 1}, + {0x7a9c, 1375}, + {0x7a9d, 3808}, + {0x7a9f, 2412}, + {0x7aa0, 7073}, + {0x7aa2, 0}, + {0x7aa3, 1}, + {0x7aa4, 2}, + {0x7aa5, 2439}, + {0x7aa6, 7072}, + {0x7aa8, 7075}, + {0x7aa9, 8608}, + {0x7aaa, 8582}, + {0x7aac, 7074}, + {0x7aad, 7076}, + {0x7aae, 8429}, + {0x7ab0, 0}, + {0x7ab1, 1}, + {0x7ab2, 2}, + {0x7ab3, 7077}, + {0x7ab5, 0}, + {0x7ab6, 9657}, + {0x7ab8, 0}, + {0x7ab9, 1}, + {0x7aba, 8170}, + {0x7abc, 0}, + {0x7abd, 1}, + {0x7abe, 2}, + {0x7abf, 2631}, + {0x7ac1, 0}, + {0x7ac2, 1}, + {0x7ac3, 2}, + {0x7ac4, 7844}, + {0x7ac5, 8417}, + {0x7ac7, 9656}, + {0x7ac8, 8800}, + {0x7aca, 8418}, + {0x7acb, 2539}, + {0x7acd, 0}, + {0x7ace, 1}, + {0x7acf, 2}, + {0x7ad0, 3}, + {0x7ad1, 4}, + {0x7ad2, 5}, + {0x7ad3, 6}, + {0x7ad4, 7}, + {0x7ad5, 8}, + {0x7ad6, 3473}, + {0x7ad8, 0}, + {0x7ad9, 4447}, + {0x7adb, 0}, + {0x7adc, 1}, + {0x7add, 2}, + {0x7ade, 2281}, + {0x7adf, 2280}, + {0x7ae0, 4451}, + {0x7ae2, 0}, + {0x7ae3, 2351}, + {0x7ae5, 3680}, + {0x7ae6, 7065}, + {0x7ae8, 0}, + {0x7ae9, 1}, + {0x7aea, 8513}, + {0x7aec, 0}, + {0x7aed, 2224}, + {0x7aef, 1546}, + {0x7af1, 0}, + {0x7af2, 1}, + {0x7af3, 2}, + {0x7af4, 3}, + {0x7af5, 4}, + {0x7af6, 8135}, + {0x7af8, 0}, + {0x7af9, 4592}, + {0x7afa, 7267}, + {0x7afc, 0}, + {0x7afd, 7268}, + {0x7aff, 1736}, + {0x7b01, 0}, + {0x7b02, 1}, + {0x7b03, 7270}, + {0x7b04, 7271}, + {0x7b06, 981}, + {0x7b08, 7269}, + {0x7b0a, 7273}, + {0x7b0b, 3558}, + {0x7b0d, 0}, + {0x7b0e, 1}, + {0x7b0f, 7275}, + {0x7b11, 3953}, + {0x7b13, 0}, + {0x7b14, 1075}, + {0x7b15, 7272}, + {0x7b17, 0}, + {0x7b18, 1}, + {0x7b19, 7279}, + {0x7b1b, 1458}, + {0x7b1d, 0}, + {0x7b1e, 7287}, + {0x7b20, 7282}, + {0x7b22, 0}, + {0x7b23, 1}, + {0x7b24, 7284}, + {0x7b25, 7283}, + {0x7b26, 1688}, + {0x7b28, 1064}, + {0x7b2a, 7278}, + {0x7b2b, 7274}, + {0x7b2c, 1467}, + {0x7b2e, 7280}, + {0x7b30, 0}, + {0x7b31, 7281}, + {0x7b33, 7285}, + {0x7b35, 0}, + {0x7b36, 1}, + {0x7b37, 2}, + {0x7b38, 7277}, + {0x7b3a, 2134}, + {0x7b3c, 2630}, + {0x7b3e, 7286}, + {0x7b40, 0}, + {0x7b41, 1}, + {0x7b42, 2}, + {0x7b43, 3}, + {0x7b44, 4}, + {0x7b45, 7290}, + {0x7b46, 7745}, + {0x7b47, 7276}, + {0x7b49, 1449}, + {0x7b4b, 2239}, + {0x7b4c, 7292}, + {0x7b4e, 0}, + {0x7b4f, 1601}, + {0x7b50, 2429}, + {0x7b51, 4605}, + {0x7b52, 3683}, + {0x7b54, 1395}, + {0x7b56, 1190}, + {0x7b58, 7288}, + {0x7b5a, 7289}, + {0x7b5b, 3313}, + {0x7b5d, 7293}, + {0x7b5f, 0}, + {0x7b60, 7294}, + {0x7b62, 7297}, + {0x7b64, 0}, + {0x7b65, 1}, + {0x7b66, 2}, + {0x7b67, 9700}, + {0x7b69, 0}, + {0x7b6a, 1}, + {0x7b6b, 2}, + {0x7b6c, 3}, + {0x7b6d, 4}, + {0x7b6e, 7295}, + {0x7b70, 0}, + {0x7b71, 7299}, + {0x7b72, 7298}, + {0x7b74, 0}, + {0x7b75, 7291}, + {0x7b77, 2423}, + {0x7b79, 1300}, + {0x7b7b, 7296}, + {0x7b7d, 0}, + {0x7b7e, 3110}, + {0x7b80, 2149}, + {0x7b82, 0}, + {0x7b83, 1}, + {0x7b84, 2}, + {0x7b85, 7307}, + {0x7b87, 0}, + {0x7b88, 1}, + {0x7b89, 2}, + {0x7b8a, 3}, + {0x7b8b, 8070}, + {0x7b8d, 1816}, + {0x7b8f, 0}, + {0x7b90, 7300}, + {0x7b92, 0}, + {0x7b93, 1}, + {0x7b94, 1140}, + {0x7b95, 2067}, + {0x7b97, 3544}, + {0x7b99, 0}, + {0x7b9a, 1}, + {0x7b9b, 2}, + {0x7b9c, 7309}, + {0x7b9d, 7305}, + {0x7b9f, 0}, + {0x7ba0, 1}, + {0x7ba1, 1845}, + {0x7ba2, 7310}, + {0x7ba4, 0}, + {0x7ba5, 1}, + {0x7ba6, 7301}, + {0x7ba7, 7302}, + {0x7ba8, 7306}, + {0x7ba9, 2696}, + {0x7baa, 7308}, + {0x7bab, 7311}, + {0x7bac, 7304}, + {0x7bad, 2160}, + {0x7baf, 0}, + {0x7bb0, 1}, + {0x7bb1, 3921}, + {0x7bb3, 0}, + {0x7bb4, 7312}, + {0x7bb6, 0}, + {0x7bb7, 1}, + {0x7bb8, 7303}, + {0x7bba, 0}, + {0x7bbb, 1}, + {0x7bbc, 2}, + {0x7bbd, 3}, + {0x7bbe, 4}, + {0x7bbf, 5}, + {0x7bc0, 8115}, + {0x7bc1, 7314}, + {0x7bc3, 0}, + {0x7bc4, 7919}, + {0x7bc6, 4618}, + {0x7bc7, 3017}, + {0x7bc9, 8868}, + {0x7bcb, 9704}, + {0x7bcc, 7315}, + {0x7bce, 0}, + {0x7bcf, 1}, + {0x7bd0, 2}, + {0x7bd1, 7313}, + {0x7bd3, 2639}, + {0x7bd5, 0}, + {0x7bd6, 1}, + {0x7bd7, 2}, + {0x7bd8, 3}, + {0x7bd9, 1752}, + {0x7bda, 7317}, + {0x7bdc, 0}, + {0x7bdd, 7316}, + {0x7bdf, 0}, + {0x7be0, 1}, + {0x7be1, 1374}, + {0x7be3, 0}, + {0x7be4, 9699}, + {0x7be5, 7318}, + {0x7be6, 7319}, + {0x7be8, 0}, + {0x7be9, 8465}, + {0x7bea, 7320}, + {0x7bec, 0}, + {0x7bed, 1}, + {0x7bee, 2469}, + {0x7bf0, 0}, + {0x7bf1, 2516}, + {0x7bf3, 9702}, + {0x7bf5, 0}, + {0x7bf6, 1}, + {0x7bf7, 2994}, + {0x7bf9, 0}, + {0x7bfa, 1}, + {0x7bfb, 2}, + {0x7bfc, 7323}, + {0x7bfe, 7322}, + {0x7c00, 9703}, + {0x7c02, 0}, + {0x7c03, 1}, + {0x7c04, 2}, + {0x7c05, 3}, + {0x7c06, 4}, + {0x7c07, 1371}, + {0x7c09, 0}, + {0x7c0a, 1}, + {0x7c0b, 7326}, + {0x7c0c, 7321}, + {0x7c0d, 8257}, + {0x7c0f, 7324}, + {0x7c11, 0}, + {0x7c12, 1}, + {0x7c13, 2}, + {0x7c14, 3}, + {0x7c15, 4}, + {0x7c16, 7325}, + {0x7c18, 0}, + {0x7c19, 1}, + {0x7c1a, 2}, + {0x7c1b, 3}, + {0x7c1c, 4}, + {0x7c1d, 5}, + {0x7c1e, 9706}, + {0x7c1f, 7327}, + {0x7c21, 8079}, + {0x7c23, 9708}, + {0x7c25, 0}, + {0x7c26, 7329}, + {0x7c27, 2014}, + {0x7c29, 0}, + {0x7c2a, 7328}, + {0x7c2b, 9707}, + {0x7c2d, 0}, + {0x7c2e, 1}, + {0x7c2f, 2}, + {0x7c30, 3}, + {0x7c31, 4}, + {0x7c32, 5}, + {0x7c33, 6}, + {0x7c34, 7}, + {0x7c35, 8}, + {0x7c36, 9}, + {0x7c37, 10}, + {0x7c38, 7330}, + {0x7c3a, 0}, + {0x7c3b, 1}, + {0x7c3c, 2}, + {0x7c3d, 8400}, + {0x7c3e, 8221}, + {0x7c3f, 1157}, + {0x7c40, 7332}, + {0x7c41, 7331}, + {0x7c43, 8183}, + {0x7c45, 0}, + {0x7c46, 1}, + {0x7c47, 2}, + {0x7c48, 3}, + {0x7c49, 4}, + {0x7c4a, 5}, + {0x7c4b, 6}, + {0x7c4c, 7821}, + {0x7c4d, 2081}, + {0x7c4f, 0}, + {0x7c50, 1}, + {0x7c51, 2}, + {0x7c52, 3}, + {0x7c53, 4}, + {0x7c54, 5}, + {0x7c55, 6}, + {0x7c56, 7}, + {0x7c57, 8}, + {0x7c58, 9}, + {0x7c59, 10}, + {0x7c5a, 11}, + {0x7c5b, 12}, + {0x7c5c, 9705}, + {0x7c5e, 0}, + {0x7c5f, 9710}, + {0x7c60, 8250}, + {0x7c62, 0}, + {0x7c63, 1}, + {0x7c64, 9875}, + {0x7c66, 0}, + {0x7c67, 1}, + {0x7c68, 2}, + {0x7c69, 9701}, + {0x7c6a, 9709}, + {0x7c6c, 8201}, + {0x7c6e, 8293}, + {0x7c70, 0}, + {0x7c71, 1}, + {0x7c72, 9891}, + {0x7c73, 2780}, + {0x7c74, 4853}, + {0x7c76, 0}, + {0x7c77, 1}, + {0x7c78, 2}, + {0x7c79, 3}, + {0x7c7a, 4}, + {0x7c7b, 2507}, + {0x7c7c, 7370}, + {0x7c7d, 4654}, + {0x7c7f, 0}, + {0x7c80, 1}, + {0x7c81, 2}, + {0x7c82, 3}, + {0x7c83, 4}, + {0x7c84, 5}, + {0x7c85, 6}, + {0x7c86, 7}, + {0x7c87, 8}, + {0x7c88, 9}, + {0x7c89, 1656}, + {0x7c8b, 0}, + {0x7c8c, 1}, + {0x7c8d, 2}, + {0x7c8e, 3}, + {0x7c8f, 4}, + {0x7c90, 5}, + {0x7c91, 7372}, + {0x7c92, 2540}, + {0x7c94, 0}, + {0x7c95, 3048}, + {0x7c97, 1369}, + {0x7c98, 4436}, + {0x7c9a, 0}, + {0x7c9b, 1}, + {0x7c9c, 7374}, + {0x7c9d, 7373}, + {0x7c9e, 7375}, + {0x7c9f, 3535}, + {0x7ca1, 0}, + {0x7ca2, 7376}, + {0x7ca4, 4356}, + {0x7ca5, 4575}, + {0x7ca7, 0}, + {0x7ca8, 1}, + {0x7ca9, 2}, + {0x7caa, 1661}, + {0x7cac, 0}, + {0x7cad, 1}, + {0x7cae, 2561}, + {0x7cb0, 0}, + {0x7cb1, 2564}, + {0x7cb2, 7377}, + {0x7cb3, 2267}, + {0x7cb5, 0}, + {0x7cb6, 1}, + {0x7cb7, 2}, + {0x7cb8, 3}, + {0x7cb9, 1381}, + {0x7cbb, 0}, + {0x7cbc, 7378}, + {0x7cbd, 7379}, + {0x7cbe, 2266}, + {0x7cc0, 0}, + {0x7cc1, 7380}, + {0x7cc3, 0}, + {0x7cc4, 1}, + {0x7cc5, 7385}, + {0x7cc7, 7381}, + {0x7cc8, 7384}, + {0x7cca, 1972}, + {0x7ccc, 7382}, + {0x7ccd, 7383}, + {0x7ccf, 0}, + {0x7cd0, 1}, + {0x7cd1, 2}, + {0x7cd2, 3}, + {0x7cd3, 4}, + {0x7cd4, 5}, + {0x7cd5, 1757}, + {0x7cd6, 3610}, + {0x7cd7, 7386}, + {0x7cd9, 1185}, + {0x7cdb, 0}, + {0x7cdc, 2776}, + {0x7cdd, 9717}, + {0x7cde, 7932}, + {0x7cdf, 4390}, + {0x7ce0, 2372}, + {0x7ce2, 0}, + {0x7ce3, 1}, + {0x7ce4, 2}, + {0x7ce5, 3}, + {0x7ce6, 4}, + {0x7ce7, 8228}, + {0x7ce8, 7387}, + {0x7cea, 0}, + {0x7ceb, 1}, + {0x7cec, 2}, + {0x7ced, 3}, + {0x7cee, 4}, + {0x7cef, 2933}, + {0x7cf0, 9883}, + {0x7cf2, 9715}, + {0x7cf4, 8921}, + {0x7cf6, 9716}, + {0x7cf8, 7399}, + {0x7cf9, 9243}, + {0x7cfb, 3874}, + {0x7cfd, 0}, + {0x7cfe, 8136}, + {0x7d00, 8059}, + {0x7d02, 9245}, + {0x7d04, 8780}, + {0x7d05, 8008}, + {0x7d06, 9244}, + {0x7d07, 9246}, + {0x7d08, 9247}, + {0x7d09, 8447}, + {0x7d0a, 3800}, + {0x7d0b, 8602}, + {0x7d0d, 8337}, + {0x7d0f, 0}, + {0x7d10, 8359}, + {0x7d12, 0}, + {0x7d13, 9251}, + {0x7d14, 7835}, + {0x7d15, 9250}, + {0x7d17, 8464}, + {0x7d19, 8845}, + {0x7d1a, 8049}, + {0x7d1b, 7928}, + {0x7d1c, 9249}, + {0x7d1e, 0}, + {0x7d1f, 1}, + {0x7d20, 3533}, + {0x7d21, 7923}, + {0x7d22, 3564}, + {0x7d24, 0}, + {0x7d25, 1}, + {0x7d26, 2}, + {0x7d27, 2245}, + {0x7d29, 0}, + {0x7d2a, 1}, + {0x7d2b, 4652}, + {0x7d2d, 0}, + {0x7d2e, 1}, + {0x7d2f, 2502}, + {0x7d30, 8625}, + {0x7d31, 9254}, + {0x7d32, 9253}, + {0x7d33, 8480}, + {0x7d35, 0}, + {0x7d36, 1}, + {0x7d37, 2}, + {0x7d38, 3}, + {0x7d39, 8474}, + {0x7d3a, 9252}, + {0x7d3c, 9256}, + {0x7d3e, 0}, + {0x7d3f, 9258}, + {0x7d40, 9257}, + {0x7d42, 8852}, + {0x7d44, 8894}, + {0x7d46, 7729}, + {0x7d48, 0}, + {0x7d49, 1}, + {0x7d4a, 2}, + {0x7d4b, 3}, + {0x7d4c, 4}, + {0x7d4d, 5}, + {0x7d4e, 9260}, + {0x7d50, 8117}, + {0x7d52, 0}, + {0x7d53, 1}, + {0x7d54, 2}, + {0x7d55, 3}, + {0x7d56, 4}, + {0x7d57, 5}, + {0x7d58, 6}, + {0x7d59, 7}, + {0x7d5a, 8}, + {0x7d5b, 9}, + {0x7d5c, 10}, + {0x7d5d, 9259}, + {0x7d5e, 8111}, + {0x7d60, 0}, + {0x7d61, 8296}, + {0x7d62, 8676}, + {0x7d64, 0}, + {0x7d65, 1}, + {0x7d66, 7969}, + {0x7d68, 8449}, + {0x7d6a, 0}, + {0x7d6b, 1}, + {0x7d6c, 2}, + {0x7d6d, 3}, + {0x7d6e, 4032}, + {0x7d70, 0}, + {0x7d71, 8572}, + {0x7d72, 8522}, + {0x7d73, 9261}, + {0x7d75, 0}, + {0x7d76, 8148}, + {0x7d77, 7400}, + {0x7d79, 8145}, + {0x7d7b, 0}, + {0x7d7c, 1}, + {0x7d7d, 2}, + {0x7d7e, 3}, + {0x7d7f, 4}, + {0x7d80, 5}, + {0x7d81, 7731}, + {0x7d83, 9263}, + {0x7d85, 0}, + {0x7d86, 9262}, + {0x7d88, 9264}, + {0x7d89, 8667}, + {0x7d8b, 0}, + {0x7d8c, 1}, + {0x7d8d, 2}, + {0x7d8e, 3}, + {0x7d8f, 8536}, + {0x7d91, 0}, + {0x7d92, 1}, + {0x7d93, 8130}, + {0x7d95, 0}, + {0x7d96, 1}, + {0x7d97, 2}, + {0x7d98, 3}, + {0x7d99, 4}, + {0x7d9a, 5}, + {0x7d9b, 6}, + {0x7d9c, 8889}, + {0x7d9e, 9270}, + {0x7da0, 0}, + {0x7da1, 1}, + {0x7da2, 7822}, + {0x7da3, 9273}, + {0x7da5, 0}, + {0x7da6, 7401}, + {0x7da8, 0}, + {0x7da9, 1}, + {0x7daa, 2}, + {0x7dab, 8645}, + {0x7dac, 9271}, + {0x7dad, 8594}, + {0x7dae, 7402}, + {0x7db0, 9274}, + {0x7db1, 7961}, + {0x7db2, 8588}, + {0x7db3, 7744}, + {0x7db4, 8883}, + {0x7db6, 0}, + {0x7db7, 1}, + {0x7db8, 8287}, + {0x7db9, 9272}, + {0x7dba, 9266}, + {0x7dbb, 8820}, + {0x7dbd, 7836}, + {0x7dbe, 9265}, + {0x7dbf, 8325}, + {0x7dc1, 0}, + {0x7dc2, 1}, + {0x7dc3, 2}, + {0x7dc4, 9269}, + {0x7dc6, 0}, + {0x7dc7, 9275}, + {0x7dc9, 0}, + {0x7dca, 8119}, + {0x7dcb, 9267}, + {0x7dcd, 0}, + {0x7dce, 1}, + {0x7dcf, 2}, + {0x7dd0, 3}, + {0x7dd1, 8276}, + {0x7dd2, 8670}, + {0x7dd4, 9268}, + {0x7dd6, 0}, + {0x7dd7, 9277}, + {0x7dd8, 8073}, + {0x7dd9, 9276}, + {0x7ddb, 0}, + {0x7ddc, 1}, + {0x7ddd, 8046}, + {0x7dde, 7896}, + {0x7de0, 7871}, + {0x7de1, 9285}, + {0x7de3, 8777}, + {0x7de5, 0}, + {0x7de6, 9281}, + {0x7de8, 7751}, + {0x7de9, 8022}, + {0x7deb, 0}, + {0x7dec, 8326}, + {0x7dee, 0}, + {0x7def, 8598}, + {0x7df1, 9283}, + {0x7df2, 9279}, + {0x7df4, 8227}, + {0x7df6, 9282}, + {0x7df8, 0}, + {0x7df9, 9278}, + {0x7dfb, 9894}, + {0x7dfd, 0}, + {0x7dfe, 1}, + {0x7dff, 2}, + {0x7e01, 0}, + {0x7e02, 1}, + {0x7e03, 2}, + {0x7e04, 3}, + {0x7e05, 4}, + {0x7e06, 5}, + {0x7e07, 6}, + {0x7e08, 9038}, + {0x7e09, 9286}, + {0x7e0a, 9291}, + {0x7e0b, 9284}, + {0x7e0d, 0}, + {0x7e0e, 1}, + {0x7e0f, 2}, + {0x7e10, 9255}, + {0x7e11, 9292}, + {0x7e13, 0}, + {0x7e14, 1}, + {0x7e15, 2}, + {0x7e16, 3}, + {0x7e17, 4}, + {0x7e18, 5}, + {0x7e19, 6}, + {0x7e1a, 7}, + {0x7e1b, 7951}, + {0x7e1d, 9287}, + {0x7e1e, 9289}, + {0x7e1f, 9288}, + {0x7e21, 0}, + {0x7e22, 1}, + {0x7e23, 8642}, + {0x7e25, 0}, + {0x7e26, 1}, + {0x7e27, 8558}, + {0x7e29, 0}, + {0x7e2a, 1}, + {0x7e2b, 7939}, + {0x7e2d, 9290}, + {0x7e2e, 8540}, + {0x7e30, 0}, + {0x7e31, 8891}, + {0x7e32, 9296}, + {0x7e34, 9876}, + {0x7e35, 9295}, + {0x7e36, 9718}, + {0x7e37, 8273}, + {0x7e39, 9294}, + {0x7e3b, 7675}, + {0x7e3d, 8890}, + {0x7e3e, 8045}, + {0x7e40, 0}, + {0x7e41, 1614}, + {0x7e43, 0}, + {0x7e44, 1}, + {0x7e45, 9298}, + {0x7e46, 9297}, + {0x7e47, 7403}, + {0x7e49, 0}, + {0x7e4a, 1}, + {0x7e4b, 2}, + {0x7e4c, 3}, + {0x7e4d, 4}, + {0x7e4e, 5}, + {0x7e4f, 6}, + {0x7e50, 7}, + {0x7e51, 8}, + {0x7e52, 9301}, + {0x7e54, 8841}, + {0x7e55, 8470}, + {0x7e57, 0}, + {0x7e58, 1}, + {0x7e59, 2}, + {0x7e5a, 9300}, + {0x7e5c, 0}, + {0x7e5d, 1}, + {0x7e5e, 8443}, + {0x7e60, 0}, + {0x7e61, 1}, + {0x7e62, 9280}, + {0x7e64, 0}, + {0x7e65, 1}, + {0x7e66, 2}, + {0x7e67, 3}, + {0x7e68, 4}, + {0x7e69, 8486}, + {0x7e6a, 8033}, + {0x7e6b, 9885}, + {0x7e6d, 8074}, + {0x7e6e, 9302}, + {0x7e6f, 9305}, + {0x7e70, 9304}, + {0x7e72, 0}, + {0x7e73, 8110}, + {0x7e75, 0}, + {0x7e76, 1}, + {0x7e77, 2}, + {0x7e78, 3}, + {0x7e79, 8730}, + {0x7e7b, 0}, + {0x7e7c, 8058}, + {0x7e7d, 9293}, + {0x7e7e, 9303}, + {0x7e80, 0}, + {0x7e81, 1}, + {0x7e82, 4680}, + {0x7e84, 0}, + {0x7e85, 1}, + {0x7e86, 2}, + {0x7e87, 3}, + {0x7e88, 9299}, + {0x7e8a, 9248}, + {0x7e8c, 8671}, + {0x7e8d, 9861}, + {0x7e8f, 7790}, + {0x7e91, 0}, + {0x7e92, 1}, + {0x7e93, 8740}, + {0x7e94, 9840}, + {0x7e96, 8634}, + {0x7e98, 9306}, + {0x7e9a, 0}, + {0x7e9b, 7404}, + {0x7e9c, 8191}, + {0x7e9e, 0}, + {0x7e9f, 6099}, + {0x7ea0, 2287}, + {0x7ea1, 6100}, + {0x7ea2, 1955}, + {0x7ea3, 6101}, + {0x7ea4, 3896}, + {0x7ea5, 6102}, + {0x7ea6, 4351}, + {0x7ea7, 2089}, + {0x7ea8, 6103}, + {0x7ea9, 6104}, + {0x7eaa, 2112}, + {0x7eab, 3245}, + {0x7eac, 3778}, + {0x7ead, 6105}, + {0x7eaf, 1346}, + {0x7eb0, 6106}, + {0x7eb1, 3309}, + {0x7eb2, 1748}, + {0x7eb3, 2860}, + {0x7eb5, 4666}, + {0x7eb6, 2689}, + {0x7eb7, 1652}, + {0x7eb8, 4540}, + {0x7eb9, 3797}, + {0x7eba, 1633}, + {0x7ebc, 0}, + {0x7ebd, 2919}, + {0x7ebe, 6107}, + {0x7ebf, 3916}, + {0x7ec0, 6108}, + {0x7ec1, 6109}, + {0x7ec2, 6110}, + {0x7ec3, 2560}, + {0x7ec4, 4678}, + {0x7ec5, 3369}, + {0x7ec6, 3877}, + {0x7ec7, 4526}, + {0x7ec8, 4564}, + {0x7ec9, 6111}, + {0x7eca, 1016}, + {0x7ecb, 6112}, + {0x7ecc, 6113}, + {0x7ecd, 3349}, + {0x7ece, 4214}, + {0x7ecf, 2268}, + {0x7ed0, 6114}, + {0x7ed1, 1022}, + {0x7ed2, 3257}, + {0x7ed3, 2226}, + {0x7ed4, 6115}, + {0x7ed5, 3233}, + {0x7ed7, 6116}, + {0x7ed8, 2043}, + {0x7ed9, 1779}, + {0x7eda, 4045}, + {0x7edb, 6117}, + {0x7edc, 2702}, + {0x7edd, 2343}, + {0x7ede, 2203}, + {0x7edf, 3684}, + {0x7ee0, 6118}, + {0x7ee1, 6119}, + {0x7ee2, 2333}, + {0x7ee3, 4016}, + {0x7ee5, 3548}, + {0x7ee6, 3619}, + {0x7ee7, 2111}, + {0x7ee8, 6120}, + {0x7ee9, 2075}, + {0x7eea, 4034}, + {0x7eeb, 6121}, + {0x7eed, 4035}, + {0x7eee, 6122}, + {0x7eef, 6123}, + {0x7ef0, 1349}, + {0x7ef1, 6124}, + {0x7ef2, 6125}, + {0x7ef3, 3383}, + {0x7ef4, 3771}, + {0x7ef5, 2789}, + {0x7ef6, 6127}, + {0x7ef7, 1066}, + {0x7ef8, 1302}, + {0x7efa, 6128}, + {0x7efb, 6129}, + {0x7efc, 4664}, + {0x7efd, 4449}, + {0x7efe, 6130}, + {0x7eff, 2675}, + {0x7f00, 4631}, + {0x7f01, 6131}, + {0x7f02, 6132}, + {0x7f03, 6133}, + {0x7f04, 2141}, + {0x7f05, 2794}, + {0x7f06, 2477}, + {0x7f07, 6134}, + {0x7f08, 6135}, + {0x7f09, 2076}, + {0x7f0b, 6136}, + {0x7f0c, 6137}, + {0x7f0d, 6126}, + {0x7f0e, 1551}, + {0x7f0f, 6138}, + {0x7f11, 6139}, + {0x7f12, 6140}, + {0x7f13, 1999}, + {0x7f14, 1471}, + {0x7f15, 2669}, + {0x7f16, 1097}, + {0x7f17, 6141}, + {0x7f18, 4344}, + {0x7f19, 6142}, + {0x7f1a, 1722}, + {0x7f1b, 6144}, + {0x7f1c, 6143}, + {0x7f1d, 1673}, + {0x7f1f, 6145}, + {0x7f20, 1215}, + {0x7f21, 6146}, + {0x7f22, 6147}, + {0x7f23, 6148}, + {0x7f24, 6149}, + {0x7f25, 6150}, + {0x7f26, 6151}, + {0x7f27, 6152}, + {0x7f28, 4236}, + {0x7f29, 3562}, + {0x7f2a, 6153}, + {0x7f2b, 6154}, + {0x7f2c, 6155}, + {0x7f2d, 6156}, + {0x7f2e, 3330}, + {0x7f2f, 6157}, + {0x7f30, 6158}, + {0x7f31, 6159}, + {0x7f32, 6160}, + {0x7f33, 6161}, + {0x7f34, 2202}, + {0x7f35, 6162}, + {0x7f36, 7262}, + {0x7f38, 1746}, + {0x7f3a, 3212}, + {0x7f3c, 0}, + {0x7f3d, 1}, + {0x7f3e, 2}, + {0x7f3f, 3}, + {0x7f40, 4}, + {0x7f41, 5}, + {0x7f42, 7263}, + {0x7f44, 7264}, + {0x7f45, 7265}, + {0x7f47, 0}, + {0x7f48, 1}, + {0x7f49, 2}, + {0x7f4a, 3}, + {0x7f4b, 4}, + {0x7f4c, 9698}, + {0x7f4e, 9882}, + {0x7f50, 1847}, + {0x7f51, 3753}, + {0x7f53, 0}, + {0x7f54, 4766}, + {0x7f55, 1896}, + {0x7f57, 2693}, + {0x7f58, 6785}, + {0x7f5a, 1600}, + {0x7f5c, 0}, + {0x7f5d, 1}, + {0x7f5e, 2}, + {0x7f5f, 6787}, + {0x7f61, 6786}, + {0x7f62, 992}, + {0x7f64, 0}, + {0x7f65, 1}, + {0x7f66, 2}, + {0x7f67, 3}, + {0x7f68, 6789}, + {0x7f69, 4471}, + {0x7f6a, 4684}, + {0x7f6c, 0}, + {0x7f6d, 1}, + {0x7f6e, 4546}, + {0x7f70, 7914}, + {0x7f71, 6791}, + {0x7f72, 3463}, + {0x7f74, 6790}, + {0x7f76, 0}, + {0x7f77, 7724}, + {0x7f79, 6792}, + {0x7f7b, 0}, + {0x7f7c, 1}, + {0x7f7d, 2}, + {0x7f7e, 6794}, + {0x7f80, 0}, + {0x7f81, 6793}, + {0x7f83, 0}, + {0x7f84, 1}, + {0x7f85, 8290}, + {0x7f86, 9457}, + {0x7f88, 9458}, + {0x7f8a, 4123}, + {0x7f8c, 3129}, + {0x7f8e, 2757}, + {0x7f90, 0}, + {0x7f91, 1}, + {0x7f92, 2}, + {0x7f93, 3}, + {0x7f94, 1756}, + {0x7f96, 0}, + {0x7f97, 1}, + {0x7f98, 2}, + {0x7f99, 3}, + {0x7f9a, 2608}, + {0x7f9c, 0}, + {0x7f9d, 7364}, + {0x7f9e, 4010}, + {0x7f9f, 7365}, + {0x7fa1, 3912}, + {0x7fa3, 0}, + {0x7fa4, 3221}, + {0x7fa5, 9714}, + {0x7fa7, 7366}, + {0x7fa9, 8725}, + {0x7fab, 0}, + {0x7fac, 1}, + {0x7fad, 2}, + {0x7fae, 3}, + {0x7faf, 7367}, + {0x7fb0, 7368}, + {0x7fb2, 7369}, + {0x7fb4, 0}, + {0x7fb5, 1}, + {0x7fb6, 2}, + {0x7fb7, 3}, + {0x7fb8, 4878}, + {0x7fb9, 1785}, + {0x7fbb, 0}, + {0x7fbc, 5997}, + {0x7fbd, 4309}, + {0x7fbf, 7390}, + {0x7fc1, 3803}, + {0x7fc3, 0}, + {0x7fc4, 1}, + {0x7fc5, 1286}, + {0x7fc7, 0}, + {0x7fc8, 1}, + {0x7fc9, 2}, + {0x7fca, 7064}, + {0x7fcc, 4213}, + {0x7fce, 7391}, + {0x7fd0, 0}, + {0x7fd1, 1}, + {0x7fd2, 8622}, + {0x7fd4, 3925}, + {0x7fd5, 7392}, + {0x7fd7, 0}, + {0x7fd8, 3145}, + {0x7fda, 0}, + {0x7fdb, 1}, + {0x7fdc, 2}, + {0x7fdd, 3}, + {0x7fde, 4}, + {0x7fdf, 1461}, + {0x7fe0, 1383}, + {0x7fe1, 7394}, + {0x7fe3, 0}, + {0x7fe4, 1}, + {0x7fe5, 7393}, + {0x7fe6, 7395}, + {0x7fe8, 0}, + {0x7fe9, 7396}, + {0x7feb, 0}, + {0x7fec, 1}, + {0x7fed, 2}, + {0x7fee, 7397}, + {0x7ff0, 1897}, + {0x7ff1, 970}, + {0x7ff3, 7398}, + {0x7ff5, 0}, + {0x7ff6, 1}, + {0x7ff7, 2}, + {0x7ff8, 3}, + {0x7ff9, 8416}, + {0x7ffb, 1610}, + {0x7ffc, 4212}, + {0x7ffe, 0}, + {0x7fff, 1}, + {0x8000, 4146}, + {0x8001, 2490}, + {0x8003, 2377}, + {0x8004, 6483}, + {0x8005, 4480}, + {0x8006, 6426}, + {0x8008, 0}, + {0x8009, 1}, + {0x800a, 2}, + {0x800b, 7127}, + {0x800c, 1591}, + {0x800d, 3480}, + {0x800f, 0}, + {0x8010, 2864}, + {0x8012, 7115}, + {0x8014, 7116}, + {0x8015, 1782}, + {0x8016, 7117}, + {0x8017, 1915}, + {0x8018, 4360}, + {0x8019, 989}, + {0x801b, 0}, + {0x801c, 7118}, + {0x801e, 0}, + {0x801f, 1}, + {0x8020, 7119}, + {0x8022, 7120}, + {0x8024, 0}, + {0x8025, 7121}, + {0x8026, 7122}, + {0x8027, 7123}, + {0x8028, 7125}, + {0x8029, 7124}, + {0x802a, 2966}, + {0x802c, 9666}, + {0x802e, 9665}, + {0x8030, 0}, + {0x8031, 7126}, + {0x8033, 1593}, + {0x8035, 7128}, + {0x8036, 4149}, + {0x8037, 5297}, + {0x8038, 3519}, + {0x803a, 0}, + {0x803b, 1281}, + {0x803d, 1411}, + {0x803f, 1787}, + {0x8041, 0}, + {0x8042, 2903}, + {0x8043, 7129}, + {0x8045, 0}, + {0x8046, 7130}, + {0x8048, 0}, + {0x8049, 1}, + {0x804a, 2573}, + {0x804b, 2628}, + {0x804c, 4527}, + {0x804d, 7131}, + {0x804f, 0}, + {0x8050, 1}, + {0x8051, 2}, + {0x8052, 7132}, + {0x8054, 2547}, + {0x8056, 8488}, + {0x8058, 3031}, + {0x805a, 2314}, + {0x805c, 0}, + {0x805d, 1}, + {0x805e, 8601}, + {0x8060, 0}, + {0x8061, 1}, + {0x8062, 2}, + {0x8063, 3}, + {0x8064, 4}, + {0x8065, 5}, + {0x8066, 6}, + {0x8067, 7}, + {0x8068, 8}, + {0x8069, 7133}, + {0x806a, 1362}, + {0x806c, 0}, + {0x806d, 1}, + {0x806e, 2}, + {0x806f, 8215}, + {0x8070, 7840}, + {0x8071, 7134}, + {0x8072, 8485}, + {0x8073, 8525}, + {0x8075, 9668}, + {0x8076, 8349}, + {0x8077, 8842}, + {0x8079, 9667}, + {0x807b, 0}, + {0x807c, 1}, + {0x807d, 8569}, + {0x807e, 8248}, + {0x807f, 6686}, + {0x8080, 6685}, + {0x8082, 0}, + {0x8083, 3541}, + {0x8084, 4197}, + {0x8085, 8533}, + {0x8086, 3510}, + {0x8087, 4473}, + {0x8089, 3261}, + {0x808b, 2506}, + {0x808c, 2068}, + {0x808e, 0}, + {0x808f, 1}, + {0x8090, 2}, + {0x8091, 3}, + {0x8092, 4}, + {0x8093, 6513}, + {0x8095, 0}, + {0x8096, 3951}, + {0x8098, 4577}, + {0x809a, 1542}, + {0x809b, 1747}, + {0x809c, 6512}, + {0x809d, 1737}, + {0x809f, 6511}, + {0x80a0, 1227}, + {0x80a1, 1826}, + {0x80a2, 4522}, + {0x80a4, 1681}, + {0x80a5, 1639}, + {0x80a7, 0}, + {0x80a8, 1}, + {0x80a9, 2138}, + {0x80aa, 1627}, + {0x80ab, 6518}, + {0x80ad, 6519}, + {0x80ae, 964}, + {0x80af, 2396}, + {0x80b1, 6517}, + {0x80b2, 4322}, + {0x80b4, 6520}, + {0x80b6, 0}, + {0x80b7, 6521}, + {0x80b9, 0}, + {0x80ba, 1643}, + {0x80bc, 6514}, + {0x80bd, 6516}, + {0x80be, 3375}, + {0x80bf, 4566}, + {0x80c0, 4462}, + {0x80c1, 3965}, + {0x80c2, 6527}, + {0x80c3, 3783}, + {0x80c4, 6528}, + {0x80c6, 1417}, + {0x80c8, 0}, + {0x80c9, 1}, + {0x80ca, 2}, + {0x80cb, 3}, + {0x80cc, 1052}, + {0x80cd, 6530}, + {0x80ce, 3576}, + {0x80d0, 0}, + {0x80d1, 1}, + {0x80d2, 2}, + {0x80d3, 3}, + {0x80d4, 4}, + {0x80d5, 5}, + {0x80d6, 2967}, + {0x80d7, 6531}, + {0x80d9, 6529}, + {0x80da, 2976}, + {0x80db, 6526}, + {0x80dc, 3387}, + {0x80dd, 6533}, + {0x80de, 1030}, + {0x80e0, 0}, + {0x80e1, 1969}, + {0x80e3, 0}, + {0x80e4, 4717}, + {0x80e5, 7111}, + {0x80e7, 6522}, + {0x80e8, 6523}, + {0x80e9, 6524}, + {0x80ea, 6525}, + {0x80eb, 6534}, + {0x80ec, 6042}, + {0x80ed, 6537}, + {0x80ef, 2421}, + {0x80f0, 4175}, + {0x80f1, 6535}, + {0x80f2, 6540}, + {0x80f3, 1767}, + {0x80f4, 6536}, + {0x80f6, 2187}, + {0x80f8, 4003}, + {0x80fa, 962}, + {0x80fc, 6541}, + {0x80fd, 2879}, + {0x80ff, 0}, + {0x8101, 0}, + {0x8102, 4523}, + {0x8104, 0}, + {0x8105, 8658}, + {0x8106, 1379}, + {0x8108, 0}, + {0x8109, 2717}, + {0x810a, 2092}, + {0x810c, 0}, + {0x810d, 6538}, + {0x810e, 6539}, + {0x810f, 4387}, + {0x8110, 3081}, + {0x8111, 2871}, + {0x8112, 6543}, + {0x8113, 2920}, + {0x8114, 4873}, + {0x8116, 1144}, + {0x8118, 6548}, + {0x811a, 2198}, + {0x811b, 9415}, + {0x811d, 0}, + {0x811e, 6546}, + {0x8120, 0}, + {0x8121, 1}, + {0x8122, 2}, + {0x8123, 3}, + {0x8124, 4}, + {0x8125, 5}, + {0x8126, 6}, + {0x8127, 7}, + {0x8128, 8}, + {0x8129, 9}, + {0x812a, 10}, + {0x812b, 11}, + {0x812c, 6547}, + {0x812e, 0}, + {0x812f, 1703}, + {0x8131, 3714}, + {0x8132, 6549}, + {0x8134, 0}, + {0x8135, 1}, + {0x8136, 6545}, + {0x8138, 2556}, + {0x8139, 8825}, + {0x813b, 0}, + {0x813c, 1}, + {0x813d, 2}, + {0x813e, 3009}, + {0x8140, 0}, + {0x8141, 1}, + {0x8142, 2}, + {0x8143, 3}, + {0x8144, 4}, + {0x8145, 5}, + {0x8146, 3654}, + {0x8148, 6550}, + {0x814a, 2459}, + {0x814b, 4159}, + {0x814c, 6551}, + {0x814e, 8483}, + {0x8150, 1706}, + {0x8151, 1704}, + {0x8153, 6552}, + {0x8154, 3128}, + {0x8155, 3748}, + {0x8156, 9413}, + {0x8158, 0}, + {0x8159, 6554}, + {0x815a, 6555}, + {0x815c, 0}, + {0x815d, 1}, + {0x815e, 2}, + {0x815f, 3}, + {0x8160, 6557}, + {0x8161, 9417}, + {0x8163, 0}, + {0x8164, 1}, + {0x8165, 3987}, + {0x8166, 8340}, + {0x8167, 6562}, + {0x8169, 6558}, + {0x816b, 8854}, + {0x816d, 6561}, + {0x816e, 3284}, + {0x8170, 4133}, + {0x8171, 6556}, + {0x8173, 0}, + {0x8174, 6553}, + {0x8176, 0}, + {0x8177, 1}, + {0x8178, 7799}, + {0x8179, 1716}, + {0x817a, 3910}, + {0x817b, 2888}, + {0x817c, 6559}, + {0x817d, 6560}, + {0x817e, 3629}, + {0x817f, 3705}, + {0x8180, 1021}, + {0x8182, 6566}, + {0x8184, 0}, + {0x8185, 1}, + {0x8186, 2}, + {0x8187, 3}, + {0x8188, 6565}, + {0x818a, 1145}, + {0x818c, 0}, + {0x818d, 1}, + {0x818e, 2}, + {0x818f, 1755}, + {0x8191, 6567}, + {0x8193, 0}, + {0x8194, 1}, + {0x8195, 2}, + {0x8196, 3}, + {0x8197, 4}, + {0x8198, 1109}, + {0x819a, 7942}, + {0x819b, 3608}, + {0x819c, 2823}, + {0x819d, 3858}, + {0x819f, 0}, + {0x81a0, 8101}, + {0x81a2, 0}, + {0x81a3, 6569}, + {0x81a5, 0}, + {0x81a6, 6576}, + {0x81a8, 2995}, + {0x81a9, 8345}, + {0x81aa, 6570}, + {0x81ac, 0}, + {0x81ad, 1}, + {0x81ae, 2}, + {0x81af, 3}, + {0x81b0, 4}, + {0x81b1, 5}, + {0x81b2, 6}, + {0x81b3, 3326}, + {0x81b5, 0}, + {0x81b6, 1}, + {0x81b7, 2}, + {0x81b8, 3}, + {0x81b9, 4}, + {0x81ba, 5697}, + {0x81bb, 6574}, + {0x81bd, 7853}, + {0x81be, 9416}, + {0x81bf, 8360}, + {0x81c0, 3711}, + {0x81c1, 6575}, + {0x81c2, 1092}, + {0x81c3, 4252}, + {0x81c5, 0}, + {0x81c6, 4195}, + {0x81c8, 0}, + {0x81c9, 8223}, + {0x81ca, 6573}, + {0x81cc, 6571}, + {0x81cd, 8389}, + {0x81cf, 9418}, + {0x81d1, 0}, + {0x81d2, 1}, + {0x81d3, 2}, + {0x81d4, 3}, + {0x81d5, 4}, + {0x81d6, 5}, + {0x81d7, 6}, + {0x81d8, 8176}, + {0x81da, 9414}, + {0x81dc, 0}, + {0x81dd, 1}, + {0x81de, 2}, + {0x81df, 8797}, + {0x81e0, 8926}, + {0x81e2, 0}, + {0x81e3, 1249}, + {0x81e5, 0}, + {0x81e6, 1}, + {0x81e7, 6402}, + {0x81e8, 8236}, + {0x81ea, 4657}, + {0x81ec, 7337}, + {0x81ed, 1305}, + {0x81ef, 0}, + {0x81f0, 1}, + {0x81f1, 2}, + {0x81f2, 3}, + {0x81f3, 4544}, + {0x81f4, 4545}, + {0x81f6, 0}, + {0x81f7, 1}, + {0x81f8, 2}, + {0x81f9, 3}, + {0x81fa, 8545}, + {0x81fb, 4490}, + {0x81fc, 2297}, + {0x81fe, 7333}, + {0x8200, 4143}, + {0x8201, 7334}, + {0x8202, 7335}, + {0x8204, 7336}, + {0x8205, 2298}, + {0x8206, 4292}, + {0x8207, 8763}, + {0x8208, 8665}, + {0x8209, 8139}, + {0x820a, 8137}, + {0x820c, 3353}, + {0x820d, 3354}, + {0x820f, 0}, + {0x8210, 7266}, + {0x8212, 3453}, + {0x8214, 3653}, + {0x8216, 0}, + {0x8217, 1}, + {0x8218, 2}, + {0x8219, 3}, + {0x821a, 4}, + {0x821b, 5656}, + {0x821c, 3497}, + {0x821e, 3831}, + {0x821f, 4570}, + {0x8221, 7339}, + {0x8222, 7340}, + {0x8223, 7341}, + {0x8225, 0}, + {0x8226, 1}, + {0x8227, 2}, + {0x8228, 7344}, + {0x822a, 1908}, + {0x822b, 7345}, + {0x822c, 1006}, + {0x822d, 7342}, + {0x822f, 7343}, + {0x8230, 2163}, + {0x8231, 1180}, + {0x8233, 7348}, + {0x8234, 7349}, + {0x8235, 1573}, + {0x8236, 1143}, + {0x8237, 3900}, + {0x8238, 7346}, + {0x8239, 1327}, + {0x823b, 7347}, + {0x823d, 0}, + {0x823e, 7350}, + {0x8240, 0}, + {0x8241, 1}, + {0x8242, 2}, + {0x8243, 3}, + {0x8244, 7351}, + {0x8246, 0}, + {0x8247, 3672}, + {0x8249, 7352}, + {0x824b, 7353}, + {0x824d, 0}, + {0x824e, 1}, + {0x824f, 7354}, + {0x8251, 0}, + {0x8252, 1}, + {0x8253, 2}, + {0x8254, 3}, + {0x8255, 4}, + {0x8256, 5}, + {0x8257, 6}, + {0x8258, 3527}, + {0x8259, 7777}, + {0x825a, 7355}, + {0x825c, 0}, + {0x825d, 1}, + {0x825e, 2}, + {0x825f, 7356}, + {0x8261, 0}, + {0x8262, 1}, + {0x8263, 2}, + {0x8264, 9711}, + {0x8266, 8088}, + {0x8268, 7357}, + {0x826a, 0}, + {0x826b, 9712}, + {0x826d, 0}, + {0x826e, 7388}, + {0x826f, 2565}, + {0x8270, 2139}, + {0x8271, 8072}, + {0x8272, 3300}, + {0x8273, 4103}, + {0x8274, 6001}, + {0x8276, 0}, + {0x8277, 8696}, + {0x8279, 5089}, + {0x827a, 4188}, + {0x827c, 0}, + {0x827d, 5090}, + {0x827e, 951}, + {0x827f, 5091}, + {0x8281, 0}, + {0x8282, 2219}, + {0x8284, 5095}, + {0x8286, 0}, + {0x8287, 1}, + {0x8288, 4728}, + {0x828a, 5093}, + {0x828b, 4312}, + {0x828d, 3343}, + {0x828e, 5096}, + {0x828f, 5092}, + {0x8291, 5097}, + {0x8292, 2727}, + {0x8294, 0}, + {0x8295, 1}, + {0x8296, 2}, + {0x8297, 5098}, + {0x8298, 5107}, + {0x8299, 5099}, + {0x829b, 0}, + {0x829c, 3822}, + {0x829d, 4516}, + {0x829f, 5117}, + {0x82a1, 5115}, + {0x82a3, 0}, + {0x82a4, 5120}, + {0x82a5, 2231}, + {0x82a6, 2642}, + {0x82a8, 5094}, + {0x82a9, 5113}, + {0x82aa, 5116}, + {0x82ab, 5100}, + {0x82ac, 1647}, + {0x82ad, 976}, + {0x82ae, 5109}, + {0x82af, 3977}, + {0x82b0, 5103}, + {0x82b1, 1981}, + {0x82b3, 1625}, + {0x82b4, 5114}, + {0x82b6, 0}, + {0x82b7, 5108}, + {0x82b8, 5101}, + {0x82b9, 3160}, + {0x82bb, 8994}, + {0x82bd, 4072}, + {0x82be, 5102}, + {0x82c0, 0}, + {0x82c1, 5112}, + {0x82c3, 0}, + {0x82c4, 5118}, + {0x82c6, 0}, + {0x82c7, 3772}, + {0x82c8, 5104}, + {0x82ca, 5105}, + {0x82cb, 5110}, + {0x82cc, 5111}, + {0x82cd, 1179}, + {0x82ce, 5119}, + {0x82cf, 3530}, + {0x82d1, 4346}, + {0x82d2, 5129}, + {0x82d3, 5133}, + {0x82d4, 3577}, + {0x82d5, 5140}, + {0x82d7, 2796}, + {0x82d8, 5130}, + {0x82da, 0}, + {0x82db, 2382}, + {0x82dc, 5127}, + {0x82de, 1029}, + {0x82df, 1807}, + {0x82e0, 5139}, + {0x82e1, 5121}, + {0x82e3, 5106}, + {0x82e4, 5124}, + {0x82e5, 3279}, + {0x82e6, 2413}, + {0x82e7, 9014}, + {0x82e9, 0}, + {0x82ea, 1}, + {0x82eb, 3316}, + {0x82ed, 0}, + {0x82ee, 1}, + {0x82ef, 1062}, + {0x82f1, 4231}, + {0x82f3, 0}, + {0x82f4, 5128}, + {0x82f6, 0}, + {0x82f7, 5123}, + {0x82f9, 3034}, + {0x82fb, 5132}, + {0x82fd, 0}, + {0x82fe, 1}, + {0x82ff, 2}, + {0x8301, 4639}, + {0x8302, 2740}, + {0x8303, 1619}, + {0x8304, 3150}, + {0x8305, 2734}, + {0x8306, 5136}, + {0x8307, 5126}, + {0x8308, 5145}, + {0x8309, 5122}, + {0x830b, 0}, + {0x830c, 5131}, + {0x830e, 2260}, + {0x830f, 5125}, + {0x8311, 5134}, + {0x8313, 0}, + {0x8314, 5137}, + {0x8315, 5138}, + {0x8317, 5158}, + {0x8319, 0}, + {0x831a, 5135}, + {0x831b, 5166}, + {0x831c, 5141}, + {0x831e, 0}, + {0x831f, 1}, + {0x8320, 2}, + {0x8321, 3}, + {0x8322, 4}, + {0x8323, 5}, + {0x8324, 6}, + {0x8325, 7}, + {0x8326, 8}, + {0x8327, 2142}, + {0x8328, 1351}, + {0x832a, 0}, + {0x832b, 2728}, + {0x832c, 1198}, + {0x832d, 5160}, + {0x832f, 5152}, + {0x8331, 5149}, + {0x8333, 5162}, + {0x8334, 5148}, + {0x8335, 4215}, + {0x8336, 1199}, + {0x8338, 3250}, + {0x8339, 3262}, + {0x833a, 5161}, + {0x833c, 5147}, + {0x833e, 0}, + {0x833f, 1}, + {0x8340, 5157}, + {0x8342, 0}, + {0x8343, 5155}, + {0x8345, 0}, + {0x8346, 2258}, + {0x8347, 5154}, + {0x8349, 1188}, + {0x834b, 0}, + {0x834c, 1}, + {0x834d, 2}, + {0x834e, 3}, + {0x834f, 5153}, + {0x8350, 2153}, + {0x8351, 5142}, + {0x8352, 2009}, + {0x8354, 2526}, + {0x8356, 0}, + {0x8357, 1}, + {0x8358, 2}, + {0x8359, 3}, + {0x835a, 2119}, + {0x835b, 5143}, + {0x835c, 5144}, + {0x835e, 5151}, + {0x835f, 5156}, + {0x8360, 5159}, + {0x8361, 1429}, + {0x8363, 3252}, + {0x8364, 2044}, + {0x8365, 5164}, + {0x8366, 5163}, + {0x8367, 4240}, + {0x8368, 5165}, + {0x8369, 5167}, + {0x836a, 5169}, + {0x836b, 4216}, + {0x836c, 5168}, + {0x836d, 5170}, + {0x836e, 5171}, + {0x836f, 4144}, + {0x8371, 0}, + {0x8372, 1}, + {0x8373, 2}, + {0x8374, 3}, + {0x8375, 4}, + {0x8376, 5}, + {0x8377, 1920}, + {0x8378, 5173}, + {0x837a, 0}, + {0x837b, 5186}, + {0x837c, 5181}, + {0x837d, 5184}, + {0x837f, 0}, + {0x8380, 1}, + {0x8381, 2}, + {0x8382, 3}, + {0x8383, 4}, + {0x8384, 5}, + {0x8385, 5180}, + {0x8386, 3053}, + {0x8388, 0}, + {0x8389, 2525}, + {0x838a, 8875}, + {0x838c, 0}, + {0x838d, 1}, + {0x838e, 3304}, + {0x8390, 0}, + {0x8391, 1}, + {0x8392, 5146}, + {0x8393, 5178}, + {0x8395, 0}, + {0x8396, 8127}, + {0x8398, 5187}, + {0x839a, 0}, + {0x839b, 5150}, + {0x839c, 5179}, + {0x839e, 5188}, + {0x83a0, 5176}, + {0x83a2, 8061}, + {0x83a4, 0}, + {0x83a5, 1}, + {0x83a6, 2}, + {0x83a7, 9011}, + {0x83a8, 5189}, + {0x83a9, 5183}, + {0x83aa, 5177}, + {0x83ab, 2829}, + {0x83ad, 0}, + {0x83ae, 1}, + {0x83af, 2}, + {0x83b0, 5172}, + {0x83b1, 2462}, + {0x83b2, 2548}, + {0x83b3, 5174}, + {0x83b4, 5175}, + {0x83b6, 5182}, + {0x83b7, 2054}, + {0x83b8, 5185}, + {0x83b9, 4237}, + {0x83ba, 5190}, + {0x83bc, 5191}, + {0x83bd, 2732}, + {0x83bf, 0}, + {0x83c0, 5214}, + {0x83c1, 5192}, + {0x83c3, 0}, + {0x83c4, 1}, + {0x83c5, 5213}, + {0x83c7, 1814}, + {0x83c9, 0}, + {0x83ca, 2308}, + {0x83cc, 2345}, + {0x83ce, 0}, + {0x83cf, 1921}, + {0x83d1, 0}, + {0x83d2, 1}, + {0x83d3, 2}, + {0x83d4, 5206}, + {0x83d6, 5201}, + {0x83d8, 5195}, + {0x83da, 0}, + {0x83db, 1}, + {0x83dc, 1170}, + {0x83dd, 5199}, + {0x83df, 5207}, + {0x83e0, 1131}, + {0x83e1, 5217}, + {0x83e3, 0}, + {0x83e4, 1}, + {0x83e5, 5194}, + {0x83e7, 0}, + {0x83e8, 1}, + {0x83e9, 3055}, + {0x83ea, 5212}, + {0x83ec, 0}, + {0x83ed, 1}, + {0x83ee, 2}, + {0x83ef, 8013}, + {0x83f0, 5216}, + {0x83f1, 2603}, + {0x83f2, 1635}, + {0x83f4, 0}, + {0x83f5, 1}, + {0x83f6, 2}, + {0x83f7, 3}, + {0x83f8, 5210}, + {0x83f9, 5211}, + {0x83fb, 0}, + {0x83fc, 1}, + {0x83fd, 5200}, + {0x83ff, 0}, + {0x8401, 5193}, + {0x8403, 5209}, + {0x8404, 3620}, + {0x8406, 5205}, + {0x8407, 9012}, + {0x8409, 0}, + {0x840a, 8177}, + {0x840b, 5198}, + {0x840c, 2765}, + {0x840d, 3035}, + {0x840e, 3773}, + {0x840f, 5208}, + {0x8411, 5204}, + {0x8413, 0}, + {0x8414, 1}, + {0x8415, 2}, + {0x8416, 3}, + {0x8417, 4}, + {0x8418, 5197}, + {0x841a, 0}, + {0x841b, 1}, + {0x841c, 5202}, + {0x841d, 2691}, + {0x841f, 0}, + {0x8420, 1}, + {0x8421, 2}, + {0x8422, 3}, + {0x8423, 4}, + {0x8424, 4238}, + {0x8425, 4239}, + {0x8426, 5215}, + {0x8427, 3937}, + {0x8428, 3283}, + {0x842a, 0}, + {0x842b, 1}, + {0x842c, 8587}, + {0x842e, 0}, + {0x842f, 1}, + {0x8430, 2}, + {0x8431, 5234}, + {0x8433, 0}, + {0x8434, 1}, + {0x8435, 9033}, + {0x8437, 0}, + {0x8438, 5203}, + {0x843a, 0}, + {0x843b, 1}, + {0x843c, 5228}, + {0x843d, 2699}, + {0x843f, 0}, + {0x8440, 1}, + {0x8441, 2}, + {0x8442, 3}, + {0x8443, 4}, + {0x8444, 5}, + {0x8445, 6}, + {0x8446, 5229}, + {0x8448, 0}, + {0x8449, 8715}, + {0x844b, 0}, + {0x844c, 1}, + {0x844d, 2}, + {0x844e, 3}, + {0x844f, 4}, + {0x8450, 5}, + {0x8451, 5219}, + {0x8452, 9030}, + {0x8454, 0}, + {0x8455, 1}, + {0x8456, 2}, + {0x8457, 4599}, + {0x8459, 5221}, + {0x845a, 5220}, + {0x845b, 1771}, + {0x845c, 5218}, + {0x845e, 0}, + {0x845f, 1}, + {0x8460, 2}, + {0x8461, 3054}, + {0x8463, 1516}, + {0x8464, 9031}, + {0x8466, 8595}, + {0x8468, 0}, + {0x8469, 5230}, + {0x846b, 1968}, + {0x846c, 4388}, + {0x846d, 5235}, + {0x846f, 9889}, + {0x8471, 1363}, + {0x8473, 5222}, + {0x8475, 2440}, + {0x8476, 5231}, + {0x8477, 8034}, + {0x8478, 5227}, + {0x847a, 5225}, + {0x847c, 0}, + {0x847d, 1}, + {0x847e, 2}, + {0x847f, 3}, + {0x8480, 4}, + {0x8481, 5}, + {0x8482, 1466}, + {0x8484, 0}, + {0x8485, 1}, + {0x8486, 2}, + {0x8487, 5223}, + {0x8488, 5224}, + {0x8489, 5226}, + {0x848b, 2176}, + {0x848c, 5232}, + {0x848e, 5233}, + {0x8490, 0}, + {0x8491, 1}, + {0x8492, 2}, + {0x8493, 9037}, + {0x8494, 9032}, + {0x8496, 0}, + {0x8497, 5249}, + {0x8499, 2766}, + {0x849b, 0}, + {0x849c, 3543}, + {0x849e, 0}, + {0x849f, 1}, + {0x84a0, 2}, + {0x84a1, 5246}, + {0x84a3, 0}, + {0x84a4, 1}, + {0x84a5, 2}, + {0x84a6, 3}, + {0x84a7, 4}, + {0x84a8, 5}, + {0x84a9, 6}, + {0x84aa, 7}, + {0x84ab, 8}, + {0x84ac, 9}, + {0x84ad, 10}, + {0x84ae, 11}, + {0x84af, 4759}, + {0x84b1, 0}, + {0x84b2, 3056}, + {0x84b4, 5248}, + {0x84b6, 0}, + {0x84b7, 1}, + {0x84b8, 4501}, + {0x84b9, 5247}, + {0x84ba, 5244}, + {0x84bc, 7776}, + {0x84bd, 5240}, + {0x84bf, 5243}, + {0x84c0, 9029}, + {0x84c1, 5236}, + {0x84c3, 0}, + {0x84c4, 4025}, + {0x84c6, 0}, + {0x84c7, 1}, + {0x84c8, 2}, + {0x84c9, 3251}, + {0x84ca, 5242}, + {0x84cb, 7954}, + {0x84cd, 5237}, + {0x84cf, 0}, + {0x84d0, 5238}, + {0x84d1, 3559}, + {0x84d3, 5241}, + {0x84d5, 0}, + {0x84d6, 1078}, + {0x84d8, 0}, + {0x84d9, 1}, + {0x84da, 2}, + {0x84db, 3}, + {0x84dc, 4}, + {0x84dd, 2465}, + {0x84df, 2094}, + {0x84e0, 5245}, + {0x84e2, 0}, + {0x84e3, 5251}, + {0x84e5, 5250}, + {0x84e6, 5239}, + {0x84e8, 0}, + {0x84e9, 1}, + {0x84ea, 2}, + {0x84eb, 3}, + {0x84ec, 2991}, + {0x84ee, 8216}, + {0x84ef, 9013}, + {0x84f0, 5255}, + {0x84f2, 0}, + {0x84f3, 1}, + {0x84f4, 2}, + {0x84f5, 3}, + {0x84f6, 4}, + {0x84f7, 5}, + {0x84f8, 6}, + {0x84f9, 7}, + {0x84fa, 8}, + {0x84fb, 9}, + {0x84fc, 5262}, + {0x84fd, 9020}, + {0x84ff, 5261}, + {0x8501, 0}, + {0x8502, 1}, + {0x8503, 2}, + {0x8504, 3}, + {0x8505, 4}, + {0x8506, 5}, + {0x8507, 6}, + {0x8508, 7}, + {0x8509, 8}, + {0x850a, 9}, + {0x850b, 10}, + {0x850c, 5252}, + {0x850e, 0}, + {0x850f, 1}, + {0x8510, 2}, + {0x8511, 2804}, + {0x8513, 2722}, + {0x8514, 9839}, + {0x8516, 0}, + {0x8517, 4482}, + {0x8519, 0}, + {0x851a, 3780}, + {0x851c, 0}, + {0x851d, 1}, + {0x851e, 9041}, + {0x851f, 5257}, + {0x8521, 1171}, + {0x8523, 8096}, + {0x8525, 0}, + {0x8526, 9016}, + {0x8528, 0}, + {0x8529, 1}, + {0x852a, 2}, + {0x852b, 2891}, + {0x852c, 3446}, + {0x852d, 8731}, + {0x852f, 0}, + {0x8530, 1}, + {0x8531, 2}, + {0x8532, 3}, + {0x8533, 4}, + {0x8534, 5}, + {0x8535, 6}, + {0x8536, 7}, + {0x8537, 3131}, + {0x8538, 5254}, + {0x8539, 5256}, + {0x853a, 5258}, + {0x853b, 5260}, + {0x853c, 949}, + {0x853d, 1079}, + {0x853f, 0}, + {0x8540, 1}, + {0x8541, 9026}, + {0x8543, 5270}, + {0x8545, 0}, + {0x8546, 9039}, + {0x8548, 5264}, + {0x8549, 2183}, + {0x854a, 3274}, + {0x854c, 0}, + {0x854d, 1}, + {0x854e, 9021}, + {0x8550, 0}, + {0x8551, 1}, + {0x8552, 9028}, + {0x8553, 9009}, + {0x8555, 9035}, + {0x8556, 5259}, + {0x8558, 9019}, + {0x8559, 5263}, + {0x855b, 0}, + {0x855c, 1}, + {0x855d, 2}, + {0x855e, 5267}, + {0x8560, 0}, + {0x8561, 1}, + {0x8562, 9040}, + {0x8564, 5266}, + {0x8566, 0}, + {0x8567, 1}, + {0x8568, 5265}, + {0x8569, 7860}, + {0x856a, 8614}, + {0x856c, 0}, + {0x856d, 8651}, + {0x856f, 0}, + {0x8570, 1}, + {0x8571, 2}, + {0x8572, 5271}, + {0x8574, 4367}, + {0x8576, 0}, + {0x8577, 9045}, + {0x8579, 5277}, + {0x857a, 5268}, + {0x857b, 5272}, + {0x857d, 0}, + {0x857e, 2500}, + {0x8580, 0}, + {0x8581, 1}, + {0x8582, 2}, + {0x8583, 3}, + {0x8584, 1034}, + {0x8585, 5280}, + {0x8587, 5275}, + {0x8588, 9022}, + {0x858a, 8052}, + {0x858c, 9008}, + {0x858e, 0}, + {0x858f, 5276}, + {0x8591, 9856}, + {0x8593, 0}, + {0x8594, 8410}, + {0x8596, 0}, + {0x8597, 1}, + {0x8598, 2}, + {0x8599, 3}, + {0x859a, 4}, + {0x859b, 4047}, + {0x859c, 5279}, + {0x859e, 0}, + {0x859f, 9034}, + {0x85a1, 0}, + {0x85a2, 1}, + {0x85a3, 2}, + {0x85a4, 5273}, + {0x85a6, 8081}, + {0x85a8, 5274}, + {0x85a9, 8455}, + {0x85aa, 3976}, + {0x85ac, 0}, + {0x85ad, 1}, + {0x85ae, 5278}, + {0x85af, 3460}, + {0x85b0, 5283}, + {0x85b2, 0}, + {0x85b3, 1}, + {0x85b4, 2}, + {0x85b5, 3}, + {0x85b6, 4}, + {0x85b7, 5282}, + {0x85b9, 5281}, + {0x85ba, 9023}, + {0x85bc, 0}, + {0x85bd, 1}, + {0x85be, 2}, + {0x85bf, 3}, + {0x85c0, 4}, + {0x85c1, 5285}, + {0x85c3, 0}, + {0x85c4, 1}, + {0x85c5, 2}, + {0x85c6, 3}, + {0x85c7, 4}, + {0x85c8, 5}, + {0x85c9, 2230}, + {0x85cb, 0}, + {0x85cc, 1}, + {0x85cd, 8180}, + {0x85ce, 9027}, + {0x85cf, 1183}, + {0x85d0, 2799}, + {0x85d2, 0}, + {0x85d3, 5284}, + {0x85d5, 2939}, + {0x85d7, 0}, + {0x85d8, 1}, + {0x85d9, 2}, + {0x85da, 3}, + {0x85db, 4}, + {0x85dc, 5286}, + {0x85dd, 8722}, + {0x85df, 0}, + {0x85e0, 1}, + {0x85e1, 2}, + {0x85e2, 3}, + {0x85e3, 4}, + {0x85e4, 3628}, + {0x85e5, 8711}, + {0x85e7, 0}, + {0x85e8, 1}, + {0x85e9, 1607}, + {0x85ea, 9049}, + {0x85ec, 0}, + {0x85ed, 1}, + {0x85ee, 2}, + {0x85ef, 3}, + {0x85f0, 4}, + {0x85f1, 5}, + {0x85f2, 6}, + {0x85f3, 7}, + {0x85f4, 8788}, + {0x85f6, 9010}, + {0x85f8, 0}, + {0x85f9, 7718}, + {0x85fa, 9047}, + {0x85fb, 4392}, + {0x85fd, 0}, + {0x85fe, 1}, + {0x85ff, 5287}, + {0x8601, 0}, + {0x8602, 1}, + {0x8603, 2}, + {0x8604, 9048}, + {0x8605, 5289}, + {0x8606, 8258}, + {0x8607, 8531}, + {0x8609, 0}, + {0x860a, 1}, + {0x860b, 8379}, + {0x860d, 0}, + {0x860e, 1}, + {0x860f, 2}, + {0x8610, 3}, + {0x8611, 2821}, + {0x8613, 0}, + {0x8614, 1}, + {0x8615, 2}, + {0x8616, 5291}, + {0x8618, 0}, + {0x8619, 1}, + {0x861a, 9050}, + {0x861c, 0}, + {0x861d, 1}, + {0x861e, 9046}, + {0x8620, 0}, + {0x8621, 1}, + {0x8622, 9015}, + {0x8624, 0}, + {0x8625, 1}, + {0x8626, 2}, + {0x8627, 5288}, + {0x8629, 5290}, + {0x862b, 0}, + {0x862c, 1}, + {0x862d, 8185}, + {0x862f, 0}, + {0x8630, 1}, + {0x8631, 2}, + {0x8632, 3}, + {0x8633, 4}, + {0x8634, 5}, + {0x8635, 6}, + {0x8636, 7}, + {0x8637, 8}, + {0x8638, 4443}, + {0x863a, 9043}, + {0x863c, 5292}, + {0x863e, 0}, + {0x863f, 8289}, + {0x8641, 0}, + {0x8642, 1}, + {0x8643, 2}, + {0x8644, 3}, + {0x8645, 4}, + {0x8646, 5}, + {0x8647, 6}, + {0x8648, 7}, + {0x8649, 8}, + {0x864a, 9}, + {0x864b, 10}, + {0x864c, 11}, + {0x864d, 7152}, + {0x864e, 1975}, + {0x864f, 2649}, + {0x8650, 2929}, + {0x8651, 2670}, + {0x8653, 0}, + {0x8654, 7153}, + {0x8655, 7829}, + {0x8657, 0}, + {0x8658, 1}, + {0x8659, 2}, + {0x865a, 4020}, + {0x865c, 8265}, + {0x865e, 4290}, + {0x865f, 8002}, + {0x8661, 0}, + {0x8662, 6509}, + {0x8664, 0}, + {0x8665, 1}, + {0x8666, 2}, + {0x8667, 8168}, + {0x8669, 0}, + {0x866a, 1}, + {0x866b, 1291}, + {0x866c, 7154}, + {0x866e, 7155}, + {0x8670, 0}, + {0x8671, 3396}, + {0x8673, 0}, + {0x8674, 1}, + {0x8675, 2}, + {0x8676, 3}, + {0x8677, 4}, + {0x8678, 5}, + {0x8679, 1950}, + {0x867a, 7157}, + {0x867b, 7159}, + {0x867c, 7158}, + {0x867d, 3545}, + {0x867e, 3879}, + {0x867f, 7156}, + {0x8680, 3403}, + {0x8681, 4182}, + {0x8682, 2707}, + {0x8684, 0}, + {0x8685, 1}, + {0x8686, 2}, + {0x8687, 3}, + {0x8688, 4}, + {0x8689, 5}, + {0x868a, 3794}, + {0x868b, 7162}, + {0x868c, 1025}, + {0x868d, 7161}, + {0x868f, 0}, + {0x8690, 1}, + {0x8691, 2}, + {0x8692, 3}, + {0x8693, 7168}, + {0x8695, 1174}, + {0x8697, 0}, + {0x8698, 1}, + {0x8699, 2}, + {0x869a, 3}, + {0x869b, 4}, + {0x869c, 4074}, + {0x869d, 7164}, + {0x869f, 0}, + {0x86a0, 1}, + {0x86a1, 2}, + {0x86a2, 3}, + {0x86a3, 7166}, + {0x86a4, 4396}, + {0x86a6, 0}, + {0x86a7, 7165}, + {0x86a8, 7160}, + {0x86a9, 7169}, + {0x86aa, 7167}, + {0x86ac, 7163}, + {0x86ae, 0}, + {0x86af, 7177}, + {0x86b0, 7174}, + {0x86b1, 7176}, + {0x86b3, 0}, + {0x86b4, 7180}, + {0x86b5, 7172}, + {0x86b6, 7170}, + {0x86b8, 0}, + {0x86b9, 1}, + {0x86ba, 7175}, + {0x86bc, 0}, + {0x86bd, 1}, + {0x86be, 2}, + {0x86bf, 3}, + {0x86c0, 4602}, + {0x86c2, 0}, + {0x86c3, 1}, + {0x86c4, 7171}, + {0x86c6, 3190}, + {0x86c7, 3352}, + {0x86c9, 7178}, + {0x86ca, 1823}, + {0x86cb, 1425}, + {0x86cd, 0}, + {0x86ce, 7173}, + {0x86cf, 7179}, + {0x86d0, 7186}, + {0x86d1, 7192}, + {0x86d3, 0}, + {0x86d4, 2028}, + {0x86d6, 0}, + {0x86d7, 1}, + {0x86d8, 7191}, + {0x86d9, 3725}, + {0x86db, 4586}, + {0x86dd, 0}, + {0x86de, 7188}, + {0x86df, 7190}, + {0x86e1, 0}, + {0x86e2, 1}, + {0x86e3, 2}, + {0x86e4, 1773}, + {0x86e6, 0}, + {0x86e7, 1}, + {0x86e8, 2}, + {0x86e9, 7181}, + {0x86eb, 0}, + {0x86ec, 1}, + {0x86ed, 7184}, + {0x86ee, 2720}, + {0x86f0, 4478}, + {0x86f1, 7182}, + {0x86f2, 7183}, + {0x86f3, 7185}, + {0x86f4, 7189}, + {0x86f6, 0}, + {0x86f7, 1}, + {0x86f8, 7195}, + {0x86f9, 4257}, + {0x86fa, 9690}, + {0x86fc, 0}, + {0x86fd, 1}, + {0x86fe, 1577}, + {0x8700, 3464}, + {0x8702, 1665}, + {0x8703, 7193}, + {0x8705, 0}, + {0x8706, 9687}, + {0x8707, 7194}, + {0x8708, 7196}, + {0x8709, 7199}, + {0x870a, 7197}, + {0x870c, 0}, + {0x870d, 7198}, + {0x870f, 0}, + {0x8710, 1}, + {0x8711, 2}, + {0x8712, 4090}, + {0x8713, 7187}, + {0x8715, 3706}, + {0x8717, 3806}, + {0x8718, 4520}, + {0x871a, 7205}, + {0x871c, 2784}, + {0x871e, 7202}, + {0x8720, 0}, + {0x8721, 2458}, + {0x8722, 7214}, + {0x8723, 7200}, + {0x8725, 7203}, + {0x8727, 0}, + {0x8728, 1}, + {0x8729, 7210}, + {0x872b, 0}, + {0x872c, 1}, + {0x872d, 2}, + {0x872e, 7204}, + {0x8730, 0}, + {0x8731, 7209}, + {0x8733, 0}, + {0x8734, 7208}, + {0x8736, 0}, + {0x8737, 7211}, + {0x8739, 0}, + {0x873a, 1}, + {0x873b, 7201}, + {0x873d, 0}, + {0x873e, 7206}, + {0x873f, 7212}, + {0x8741, 0}, + {0x8742, 1}, + {0x8743, 2}, + {0x8744, 3}, + {0x8745, 4}, + {0x8746, 5}, + {0x8747, 4241}, + {0x8748, 7207}, + {0x8749, 1212}, + {0x874b, 0}, + {0x874c, 7220}, + {0x874e, 3958}, + {0x8750, 0}, + {0x8751, 1}, + {0x8752, 2}, + {0x8753, 7223}, + {0x8755, 8494}, + {0x8757, 2013}, + {0x8759, 7227}, + {0x875b, 0}, + {0x875c, 1}, + {0x875d, 2}, + {0x875e, 3}, + {0x875f, 4}, + {0x8760, 7218}, + {0x8762, 0}, + {0x8763, 7224}, + {0x8764, 7226}, + {0x8765, 7228}, + {0x8766, 8626}, + {0x8768, 0}, + {0x8769, 1}, + {0x876a, 2}, + {0x876b, 3}, + {0x876c, 4}, + {0x876d, 5}, + {0x876e, 7221}, + {0x8770, 7219}, + {0x8772, 0}, + {0x8773, 1}, + {0x8774, 1970}, + {0x8776, 1500}, + {0x8778, 8606}, + {0x877a, 0}, + {0x877b, 7217}, + {0x877c, 7225}, + {0x877d, 7215}, + {0x877e, 7216}, + {0x8780, 0}, + {0x8781, 1}, + {0x8782, 7213}, + {0x8783, 7238}, + {0x8784, 9692}, + {0x8785, 7235}, + {0x8787, 0}, + {0x8788, 7234}, + {0x878a, 0}, + {0x878b, 7222}, + {0x878d, 3253}, + {0x878f, 0}, + {0x8790, 1}, + {0x8791, 2}, + {0x8792, 3}, + {0x8793, 7229}, + {0x8795, 0}, + {0x8796, 1}, + {0x8797, 7237}, + {0x8799, 0}, + {0x879a, 1}, + {0x879b, 2}, + {0x879c, 3}, + {0x879d, 4}, + {0x879e, 8300}, + {0x879f, 2813}, + {0x87a1, 0}, + {0x87a2, 8742}, + {0x87a4, 0}, + {0x87a5, 1}, + {0x87a6, 2}, + {0x87a7, 3}, + {0x87a8, 7231}, + {0x87aa, 0}, + {0x87ab, 7239}, + {0x87ac, 7241}, + {0x87ad, 7236}, + {0x87af, 7230}, + {0x87b1, 0}, + {0x87b2, 1}, + {0x87b3, 7243}, + {0x87b5, 7242}, + {0x87b7, 0}, + {0x87b8, 1}, + {0x87b9, 2}, + {0x87ba, 2692}, + {0x87bb, 9696}, + {0x87bd, 7246}, + {0x87bf, 0}, + {0x87c0, 7248}, + {0x87c2, 0}, + {0x87c3, 1}, + {0x87c4, 8827}, + {0x87c6, 7233}, + {0x87c8, 9694}, + {0x87ca, 7249}, + {0x87cb, 7244}, + {0x87cd, 0}, + {0x87ce, 9697}, + {0x87d0, 0}, + {0x87d1, 7247}, + {0x87d2, 7232}, + {0x87d3, 7245}, + {0x87d5, 0}, + {0x87d6, 1}, + {0x87d7, 2}, + {0x87d8, 3}, + {0x87d9, 4}, + {0x87da, 5}, + {0x87db, 7250}, + {0x87dd, 0}, + {0x87de, 1}, + {0x87df, 2}, + {0x87e0, 7252}, + {0x87e2, 0}, + {0x87e3, 9685}, + {0x87e5, 7240}, + {0x87e7, 0}, + {0x87e8, 1}, + {0x87e9, 2}, + {0x87ea, 7251}, + {0x87ec, 7787}, + {0x87ee, 7253}, + {0x87ef, 9691}, + {0x87f1, 0}, + {0x87f2, 7817}, + {0x87f4, 0}, + {0x87f5, 1}, + {0x87f6, 9689}, + {0x87f8, 0}, + {0x87f9, 3970}, + {0x87fb, 8721}, + {0x87fd, 0}, + {0x87fe, 7256}, + {0x8801, 0}, + {0x8802, 1}, + {0x8803, 4877}, + {0x8805, 8745}, + {0x8806, 9686}, + {0x8808, 0}, + {0x8809, 1}, + {0x880a, 7257}, + {0x880c, 0}, + {0x880d, 1}, + {0x880e, 2}, + {0x880f, 3}, + {0x8810, 9693}, + {0x8811, 9695}, + {0x8813, 7255}, + {0x8815, 3263}, + {0x8816, 7254}, + {0x8818, 0}, + {0x8819, 1}, + {0x881a, 2}, + {0x881b, 7258}, + {0x881d, 0}, + {0x881e, 1}, + {0x881f, 8175}, + {0x8821, 7259}, + {0x8822, 1347}, + {0x8823, 9688}, + {0x8825, 0}, + {0x8826, 1}, + {0x8827, 2}, + {0x8828, 3}, + {0x8829, 4}, + {0x882a, 5}, + {0x882b, 6}, + {0x882c, 7}, + {0x882d, 8}, + {0x882e, 9}, + {0x882f, 10}, + {0x8830, 11}, + {0x8831, 7977}, + {0x8832, 6797}, + {0x8834, 0}, + {0x8835, 1}, + {0x8836, 7771}, + {0x8838, 0}, + {0x8839, 7260}, + {0x883b, 8310}, + {0x883c, 7261}, + {0x883e, 0}, + {0x883f, 1}, + {0x8840, 4051}, + {0x8842, 0}, + {0x8843, 1}, + {0x8844, 7338}, + {0x8845, 3985}, + {0x8846, 8855}, + {0x8848, 0}, + {0x8849, 1}, + {0x884a, 9872}, + {0x884c, 3995}, + {0x884d, 4101}, + {0x884f, 0}, + {0x8850, 1}, + {0x8851, 2}, + {0x8852, 3}, + {0x8853, 8511}, + {0x8854, 3899}, + {0x8856, 0}, + {0x8857, 2215}, + {0x8859, 4076}, + {0x885b, 8600}, + {0x885d, 7816}, + {0x885f, 0}, + {0x8860, 1}, + {0x8861, 1945}, + {0x8862, 5613}, + {0x8863, 4169}, + {0x8864, 7078}, + {0x8865, 1152}, + {0x8867, 0}, + {0x8868, 1110}, + {0x8869, 7079}, + {0x886b, 3321}, + {0x886c, 1257}, + {0x886e, 4870}, + {0x8870, 3482}, + {0x8872, 7080}, + {0x8874, 0}, + {0x8875, 1}, + {0x8876, 2}, + {0x8877, 4563}, + {0x8879, 8844}, + {0x887b, 0}, + {0x887c, 1}, + {0x887d, 7081}, + {0x887e, 7358}, + {0x887f, 7082}, + {0x8881, 4335}, + {0x8882, 7083}, + {0x8884, 971}, + {0x8885, 7359}, + {0x8887, 0}, + {0x8888, 7360}, + {0x888a, 0}, + {0x888b, 1407}, + {0x888d, 2972}, + {0x888f, 0}, + {0x8890, 1}, + {0x8891, 2}, + {0x8892, 3598}, + {0x8894, 0}, + {0x8895, 1}, + {0x8896, 4015}, + {0x8898, 0}, + {0x8899, 1}, + {0x889a, 2}, + {0x889b, 3}, + {0x889c, 3729}, + {0x889e, 0}, + {0x889f, 1}, + {0x88a0, 2}, + {0x88a1, 3}, + {0x88a2, 7084}, + {0x88a4, 4871}, + {0x88a6, 0}, + {0x88a7, 1}, + {0x88a8, 2}, + {0x88a9, 3}, + {0x88aa, 4}, + {0x88ab, 1060}, + {0x88ad, 3867}, + {0x88af, 0}, + {0x88b0, 1}, + {0x88b1, 1695}, + {0x88b3, 0}, + {0x88b4, 1}, + {0x88b5, 2}, + {0x88b6, 3}, + {0x88b7, 7086}, + {0x88b9, 0}, + {0x88ba, 1}, + {0x88bb, 2}, + {0x88bc, 7087}, + {0x88be, 0}, + {0x88bf, 1}, + {0x88c0, 2}, + {0x88c1, 1162}, + {0x88c2, 2586}, + {0x88c4, 0}, + {0x88c5, 4621}, + {0x88c6, 7085}, + {0x88c8, 0}, + {0x88c9, 7088}, + {0x88ca, 9713}, + {0x88cc, 0}, + {0x88cd, 1}, + {0x88ce, 7090}, + {0x88cf, 8204}, + {0x88d1, 0}, + {0x88d2, 4874}, + {0x88d4, 4200}, + {0x88d5, 4326}, + {0x88d7, 0}, + {0x88d8, 7361}, + {0x88d9, 3220}, + {0x88db, 0}, + {0x88dc, 7768}, + {0x88dd, 8876}, + {0x88df, 7362}, + {0x88e1, 0}, + {0x88e2, 7089}, + {0x88e3, 7091}, + {0x88e4, 2416}, + {0x88e5, 7092}, + {0x88e7, 0}, + {0x88e8, 7096}, + {0x88ea, 0}, + {0x88eb, 1}, + {0x88ec, 2}, + {0x88ed, 3}, + {0x88ee, 4}, + {0x88ef, 5}, + {0x88f0, 7098}, + {0x88f1, 7093}, + {0x88f3, 3338}, + {0x88f4, 2978}, + {0x88f6, 0}, + {0x88f7, 1}, + {0x88f8, 2698}, + {0x88f9, 1877}, + {0x88fb, 0}, + {0x88fc, 7095}, + {0x88fd, 9895}, + {0x88fe, 7097}, + {0x8901, 0}, + {0x8902, 1836}, + {0x8904, 0}, + {0x8905, 1}, + {0x8906, 2}, + {0x8907, 9846}, + {0x8909, 0}, + {0x890a, 7103}, + {0x890c, 0}, + {0x890d, 1}, + {0x890e, 2}, + {0x890f, 3}, + {0x8910, 1933}, + {0x8912, 1032}, + {0x8913, 7101}, + {0x8915, 0}, + {0x8916, 1}, + {0x8917, 2}, + {0x8918, 3}, + {0x8919, 7100}, + {0x891a, 7094}, + {0x891b, 7102}, + {0x891d, 0}, + {0x891e, 1}, + {0x891f, 2}, + {0x8920, 3}, + {0x8921, 7099}, + {0x8923, 0}, + {0x8924, 1}, + {0x8925, 3271}, + {0x8927, 0}, + {0x8928, 1}, + {0x8929, 2}, + {0x892a, 3707}, + {0x892b, 7105}, + {0x892d, 0}, + {0x892e, 1}, + {0x892f, 2}, + {0x8930, 5945}, + {0x8932, 8161}, + {0x8933, 9659}, + {0x8934, 7104}, + {0x8936, 7106}, + {0x8938, 9662}, + {0x893a, 0}, + {0x893b, 8925}, + {0x893d, 0}, + {0x893e, 1}, + {0x893f, 2}, + {0x8940, 3}, + {0x8941, 7107}, + {0x8943, 0}, + {0x8944, 3922}, + {0x8946, 0}, + {0x8947, 9661}, + {0x8949, 0}, + {0x894a, 1}, + {0x894b, 2}, + {0x894c, 3}, + {0x894d, 4}, + {0x894e, 5}, + {0x894f, 6}, + {0x8950, 7}, + {0x8951, 8}, + {0x8952, 9}, + {0x8953, 10}, + {0x8954, 11}, + {0x8955, 12}, + {0x8956, 7722}, + {0x8958, 0}, + {0x8959, 1}, + {0x895a, 2}, + {0x895b, 3}, + {0x895c, 4}, + {0x895d, 9660}, + {0x895e, 7363}, + {0x895f, 2244}, + {0x8960, 9658}, + {0x8962, 0}, + {0x8963, 1}, + {0x8964, 9663}, + {0x8966, 7108}, + {0x8968, 0}, + {0x8969, 1}, + {0x896a, 8583}, + {0x896c, 9835}, + {0x896e, 0}, + {0x896f, 7807}, + {0x8971, 0}, + {0x8972, 8621}, + {0x8974, 0}, + {0x8975, 1}, + {0x8976, 2}, + {0x8977, 3}, + {0x8978, 4}, + {0x8979, 5}, + {0x897a, 6}, + {0x897b, 7109}, + {0x897d, 0}, + {0x897e, 1}, + {0x897f, 3846}, + {0x8981, 4145}, + {0x8983, 7135}, + {0x8985, 0}, + {0x8986, 1709}, + {0x8988, 0}, + {0x8989, 1}, + {0x898a, 2}, + {0x898b, 8086}, + {0x898d, 0}, + {0x898e, 1}, + {0x898f, 7986}, + {0x8991, 0}, + {0x8992, 1}, + {0x8993, 8324}, + {0x8995, 0}, + {0x8996, 8502}, + {0x8998, 9400}, + {0x899a, 0}, + {0x899b, 1}, + {0x899c, 2}, + {0x899d, 3}, + {0x899e, 4}, + {0x899f, 5}, + {0x89a0, 6}, + {0x89a1, 9402}, + {0x89a3, 0}, + {0x89a4, 1}, + {0x89a5, 2}, + {0x89a6, 9404}, + {0x89a8, 0}, + {0x89a9, 1}, + {0x89aa, 8420}, + {0x89ac, 9401}, + {0x89ae, 0}, + {0x89af, 9405}, + {0x89b1, 0}, + {0x89b2, 9406}, + {0x89b4, 0}, + {0x89b5, 1}, + {0x89b6, 2}, + {0x89b7, 9407}, + {0x89b9, 0}, + {0x89ba, 8146}, + {0x89bc, 0}, + {0x89bd, 8189}, + {0x89bf, 9403}, + {0x89c0, 7981}, + {0x89c1, 2158}, + {0x89c2, 1844}, + {0x89c4, 1855}, + {0x89c5, 2782}, + {0x89c6, 3434}, + {0x89c7, 6458}, + {0x89c8, 2475}, + {0x89c9, 2340}, + {0x89ca, 6459}, + {0x89cb, 6460}, + {0x89cc, 6461}, + {0x89ce, 6462}, + {0x89cf, 6463}, + {0x89d0, 6464}, + {0x89d1, 6465}, + {0x89d2, 2200}, + {0x89d4, 0}, + {0x89d5, 1}, + {0x89d6, 7511}, + {0x89d8, 0}, + {0x89d9, 1}, + {0x89da, 7513}, + {0x89dc, 7514}, + {0x89de, 7512}, + {0x89e0, 0}, + {0x89e1, 1}, + {0x89e2, 2}, + {0x89e3, 2227}, + {0x89e5, 7515}, + {0x89e6, 1320}, + {0x89e8, 0}, + {0x89e9, 1}, + {0x89ea, 2}, + {0x89eb, 7516}, + {0x89ed, 0}, + {0x89ee, 1}, + {0x89ef, 7517}, + {0x89f1, 0}, + {0x89f2, 1}, + {0x89f3, 6592}, + {0x89f4, 9737}, + {0x89f6, 9738}, + {0x89f8, 7828}, + {0x89fa, 0}, + {0x89fb, 1}, + {0x89fc, 2}, + {0x89fd, 3}, + {0x89fe, 4}, + {0x89ff, 5}, + {0x8a00, 4093}, + {0x8a01, 8927}, + {0x8a02, 7883}, + {0x8a03, 7949}, + {0x8a05, 0}, + {0x8a06, 1}, + {0x8a07, 4862}, + {0x8a08, 8055}, + {0x8a0a, 8683}, + {0x8a0c, 8929}, + {0x8a0e, 8559}, + {0x8a10, 8928}, + {0x8a12, 0}, + {0x8a13, 8682}, + {0x8a15, 8930}, + {0x8a16, 8395}, + {0x8a18, 8056}, + {0x8a1a, 0}, + {0x8a1b, 7906}, + {0x8a1d, 8690}, + {0x8a1f, 8528}, + {0x8a21, 0}, + {0x8a22, 1}, + {0x8a23, 8147}, + {0x8a25, 8933}, + {0x8a27, 0}, + {0x8a28, 1}, + {0x8a29, 2}, + {0x8a2a, 7922}, + {0x8a2c, 0}, + {0x8a2d, 8479}, + {0x8a2f, 0}, + {0x8a30, 1}, + {0x8a31, 8669}, + {0x8a33, 0}, + {0x8a34, 8532}, + {0x8a36, 8935}, + {0x8a38, 0}, + {0x8a39, 1}, + {0x8a3a, 8834}, + {0x8a3c, 0}, + {0x8a3d, 1}, + {0x8a3e, 7518}, + {0x8a40, 0}, + {0x8a41, 8934}, + {0x8a43, 0}, + {0x8a44, 1}, + {0x8a45, 2}, + {0x8a46, 8936}, + {0x8a48, 6788}, + {0x8a4a, 0}, + {0x8a4b, 1}, + {0x8a4c, 2}, + {0x8a4d, 3}, + {0x8a4e, 8932}, + {0x8a50, 8810}, + {0x8a52, 8939}, + {0x8a54, 8937}, + {0x8a55, 8381}, + {0x8a57, 0}, + {0x8a58, 8938}, + {0x8a5a, 0}, + {0x8a5b, 8893}, + {0x8a5d, 0}, + {0x8a5e, 7838}, + {0x8a60, 0}, + {0x8a61, 8950}, + {0x8a62, 8679}, + {0x8a63, 8726}, + {0x8a65, 0}, + {0x8a66, 8503}, + {0x8a68, 0}, + {0x8a69, 8492}, + {0x8a6b, 7784}, + {0x8a6c, 8946}, + {0x8a6d, 7991}, + {0x8a6e, 8947}, + {0x8a70, 8943}, + {0x8a71, 8016}, + {0x8a72, 7952}, + {0x8a73, 8648}, + {0x8a75, 8945}, + {0x8a77, 0}, + {0x8a78, 1}, + {0x8a79, 4435}, + {0x8a7b, 0}, + {0x8a7c, 8944}, + {0x8a7e, 0}, + {0x8a7f, 8942}, + {0x8a81, 0}, + {0x8a82, 1}, + {0x8a83, 2}, + {0x8a84, 8941}, + {0x8a85, 8862}, + {0x8a86, 8940}, + {0x8a87, 8162}, + {0x8a89, 4323}, + {0x8a8a, 3631}, + {0x8a8c, 0}, + {0x8a8d, 8446}, + {0x8a8f, 0}, + {0x8a90, 1}, + {0x8a91, 8953}, + {0x8a92, 8954}, + {0x8a93, 3419}, + {0x8a95, 7855}, + {0x8a97, 0}, + {0x8a98, 8758}, + {0x8a9a, 8951}, + {0x8a9c, 0}, + {0x8a9d, 1}, + {0x8a9e, 8765}, + {0x8aa0, 7810}, + {0x8aa1, 8118}, + {0x8aa3, 8612}, + {0x8aa4, 8618}, + {0x8aa5, 8952}, + {0x8aa6, 8529}, + {0x8aa8, 8032}, + {0x8aaa, 0}, + {0x8aab, 1}, + {0x8aac, 8519}, + {0x8aae, 0}, + {0x8aaf, 1}, + {0x8ab0, 8517}, + {0x8ab2, 8156}, + {0x8ab4, 0}, + {0x8ab5, 1}, + {0x8ab6, 8961}, + {0x8ab8, 0}, + {0x8ab9, 7925}, + {0x8abb, 0}, + {0x8abc, 8728}, + {0x8abe, 0}, + {0x8abf, 7878}, + {0x8ac1, 0}, + {0x8ac2, 8960}, + {0x8ac4, 8884}, + {0x8ac6, 0}, + {0x8ac7, 8553}, + {0x8ac9, 8957}, + {0x8acb, 8426}, + {0x8acd, 8948}, + {0x8acf, 8955}, + {0x8ad1, 8956}, + {0x8ad2, 8231}, + {0x8ad4, 0}, + {0x8ad5, 1}, + {0x8ad6, 8288}, + {0x8ad7, 8959}, + {0x8ad9, 0}, + {0x8ada, 1}, + {0x8adb, 8958}, + {0x8adc, 7879}, + {0x8ade, 8972}, + {0x8ae0, 0}, + {0x8ae1, 1}, + {0x8ae2, 8949}, + {0x8ae4, 8966}, + {0x8ae6, 8970}, + {0x8ae7, 8659}, + {0x8ae9, 0}, + {0x8aea, 1}, + {0x8aeb, 8963}, + {0x8aed, 8967}, + {0x8aee, 8971}, + {0x8af0, 0}, + {0x8af1, 8031}, + {0x8af3, 8969}, + {0x8af5, 0}, + {0x8af6, 8962}, + {0x8af7, 7940}, + {0x8af8, 8861}, + {0x8afa, 8699}, + {0x8afc, 8968}, + {0x8afe, 8364}, + {0x8b00, 8334}, + {0x8b01, 8965}, + {0x8b02, 8599}, + {0x8b04, 8561}, + {0x8b05, 8856}, + {0x8b07, 5948}, + {0x8b09, 0}, + {0x8b0a, 8023}, + {0x8b0c, 0}, + {0x8b0d, 1}, + {0x8b0e, 8322}, + {0x8b10, 8977}, + {0x8b12, 0}, + {0x8b13, 1}, + {0x8b14, 8964}, + {0x8b16, 8975}, + {0x8b17, 7733}, + {0x8b19, 8401}, + {0x8b1a, 8976}, + {0x8b1b, 8099}, + {0x8b1d, 8662}, + {0x8b1f, 0}, + {0x8b20, 1}, + {0x8b21, 8710}, + {0x8b23, 0}, + {0x8b24, 1}, + {0x8b25, 2}, + {0x8b26, 7519}, + {0x8b28, 8973}, + {0x8b2a, 0}, + {0x8b2b, 8978}, + {0x8b2c, 8333}, + {0x8b2d, 8979}, + {0x8b2f, 0}, + {0x8b30, 1}, + {0x8b31, 2}, + {0x8b32, 3}, + {0x8b33, 8931}, + {0x8b35, 0}, + {0x8b36, 1}, + {0x8b37, 2}, + {0x8b38, 3}, + {0x8b39, 8122}, + {0x8b3b, 0}, + {0x8b3c, 1}, + {0x8b3d, 2}, + {0x8b3e, 8312}, + {0x8b40, 0}, + {0x8b41, 1}, + {0x8b42, 2}, + {0x8b43, 3}, + {0x8b44, 4}, + {0x8b45, 5}, + {0x8b46, 6}, + {0x8b47, 7}, + {0x8b48, 8}, + {0x8b49, 8840}, + {0x8b4b, 0}, + {0x8b4c, 1}, + {0x8b4d, 2}, + {0x8b4e, 8982}, + {0x8b4f, 8043}, + {0x8b51, 0}, + {0x8b52, 1}, + {0x8b53, 2}, + {0x8b54, 3}, + {0x8b55, 4}, + {0x8b56, 8980}, + {0x8b58, 8496}, + {0x8b59, 8981}, + {0x8b5a, 8552}, + {0x8b5c, 8388}, + {0x8b5e, 0}, + {0x8b5f, 1}, + {0x8b60, 2}, + {0x8b61, 3}, + {0x8b62, 4}, + {0x8b63, 5}, + {0x8b64, 6}, + {0x8b65, 7}, + {0x8b66, 2270}, + {0x8b68, 0}, + {0x8b69, 1}, + {0x8b6a, 2}, + {0x8b6b, 8984}, + {0x8b6c, 3016}, + {0x8b6e, 0}, + {0x8b6f, 8729}, + {0x8b70, 8727}, + {0x8b72, 0}, + {0x8b73, 1}, + {0x8b74, 8405}, + {0x8b76, 0}, + {0x8b77, 8010}, + {0x8b79, 0}, + {0x8b7a, 1}, + {0x8b7b, 2}, + {0x8b7c, 3}, + {0x8b7d, 8768}, + {0x8b7f, 0}, + {0x8b80, 7891}, + {0x8b82, 0}, + {0x8b83, 1}, + {0x8b84, 2}, + {0x8b85, 3}, + {0x8b86, 4}, + {0x8b87, 5}, + {0x8b88, 6}, + {0x8b89, 7}, + {0x8b8a, 7753}, + {0x8b8c, 0}, + {0x8b8d, 1}, + {0x8b8e, 9755}, + {0x8b90, 0}, + {0x8b91, 1}, + {0x8b92, 7789}, + {0x8b93, 8440}, + {0x8b95, 8187}, + {0x8b96, 8985}, + {0x8b98, 0}, + {0x8b99, 1}, + {0x8b9a, 2}, + {0x8b9b, 3}, + {0x8b9c, 8974}, + {0x8b9e, 8983}, + {0x8ba0, 4887}, + {0x8ba1, 2105}, + {0x8ba2, 1512}, + {0x8ba3, 1719}, + {0x8ba4, 3242}, + {0x8ba5, 2072}, + {0x8ba6, 4888}, + {0x8ba7, 4889}, + {0x8ba8, 3625}, + {0x8ba9, 3230}, + {0x8baa, 4890}, + {0x8bab, 3100}, + {0x8bad, 4062}, + {0x8bae, 4208}, + {0x8baf, 4063}, + {0x8bb0, 2106}, + {0x8bb2, 2179}, + {0x8bb3, 2041}, + {0x8bb4, 4891}, + {0x8bb5, 4892}, + {0x8bb6, 4081}, + {0x8bb7, 4893}, + {0x8bb8, 4024}, + {0x8bb9, 1582}, + {0x8bba, 2690}, + {0x8bbc, 3524}, + {0x8bbd, 1674}, + {0x8bbe, 3361}, + {0x8bbf, 1632}, + {0x8bc0, 2342}, + {0x8bc1, 4515}, + {0x8bc2, 4894}, + {0x8bc3, 4895}, + {0x8bc4, 3039}, + {0x8bc5, 4676}, + {0x8bc6, 3405}, + {0x8bc8, 4426}, + {0x8bc9, 3540}, + {0x8bca, 4496}, + {0x8bcb, 4896}, + {0x8bcc, 4574}, + {0x8bcd, 1357}, + {0x8bce, 4898}, + {0x8bcf, 4897}, + {0x8bd1, 4210}, + {0x8bd2, 4899}, + {0x8bd3, 4900}, + {0x8bd4, 4901}, + {0x8bd5, 3435}, + {0x8bd6, 4902}, + {0x8bd7, 3394}, + {0x8bd8, 4903}, + {0x8bd9, 4904}, + {0x8bda, 1268}, + {0x8bdb, 4590}, + {0x8bdc, 4905}, + {0x8bdd, 1989}, + {0x8bde, 1423}, + {0x8bdf, 4906}, + {0x8be0, 4907}, + {0x8be1, 1863}, + {0x8be2, 4056}, + {0x8be3, 4207}, + {0x8be4, 4908}, + {0x8be5, 1726}, + {0x8be6, 3927}, + {0x8be7, 1206}, + {0x8be8, 4909}, + {0x8be9, 4910}, + {0x8beb, 2236}, + {0x8bec, 3819}, + {0x8bed, 4308}, + {0x8bee, 4911}, + {0x8bef, 3842}, + {0x8bf0, 4912}, + {0x8bf1, 4282}, + {0x8bf2, 2042}, + {0x8bf3, 4913}, + {0x8bf4, 3498}, + {0x8bf5, 3525}, + {0x8bf6, 4914}, + {0x8bf7, 3176}, + {0x8bf8, 4589}, + {0x8bf9, 4915}, + {0x8bfa, 2934}, + {0x8bfb, 1536}, + {0x8bfc, 4916}, + {0x8bfd, 1641}, + {0x8bfe, 2395}, + {0x8bff, 4917}, + {0x8c00, 4918}, + {0x8c01, 3490}, + {0x8c02, 4919}, + {0x8c03, 1496}, + {0x8c04, 4920}, + {0x8c05, 2571}, + {0x8c06, 4632}, + {0x8c07, 4921}, + {0x8c08, 3595}, + {0x8c0a, 4209}, + {0x8c0b, 2836}, + {0x8c0c, 4922}, + {0x8c0d, 1502}, + {0x8c0e, 2022}, + {0x8c0f, 4923}, + {0x8c10, 3966}, + {0x8c11, 4924}, + {0x8c12, 4925}, + {0x8c13, 3788}, + {0x8c14, 4926}, + {0x8c15, 4927}, + {0x8c16, 4928}, + {0x8c17, 1214}, + {0x8c18, 4931}, + {0x8c19, 4929}, + {0x8c1a, 4113}, + {0x8c1b, 4930}, + {0x8c1c, 2778}, + {0x8c1d, 4932}, + {0x8c1f, 4933}, + {0x8c20, 4934}, + {0x8c21, 4935}, + {0x8c22, 3974}, + {0x8c23, 4140}, + {0x8c24, 1028}, + {0x8c25, 4936}, + {0x8c26, 3112}, + {0x8c27, 4937}, + {0x8c28, 2248}, + {0x8c29, 2726}, + {0x8c2a, 4938}, + {0x8c2b, 4939}, + {0x8c2c, 2818}, + {0x8c2d, 3594}, + {0x8c2e, 4940}, + {0x8c2f, 4941}, + {0x8c30, 2473}, + {0x8c31, 3062}, + {0x8c32, 4942}, + {0x8c33, 4943}, + {0x8c34, 3121}, + {0x8c35, 4944}, + {0x8c36, 4945}, + {0x8c37, 1825}, + {0x8c39, 0}, + {0x8c3a, 1}, + {0x8c3b, 2}, + {0x8c3c, 3}, + {0x8c3d, 4}, + {0x8c3e, 5}, + {0x8c3f, 6}, + {0x8c40, 7}, + {0x8c41, 2050}, + {0x8c43, 0}, + {0x8c44, 1}, + {0x8c45, 2}, + {0x8c46, 1528}, + {0x8c47, 7414}, + {0x8c48, 8392}, + {0x8c49, 7415}, + {0x8c4b, 0}, + {0x8c4c, 3732}, + {0x8c4e, 0}, + {0x8c4f, 1}, + {0x8c50, 7933}, + {0x8c52, 0}, + {0x8c53, 1}, + {0x8c54, 2}, + {0x8c55, 7445}, + {0x8c57, 0}, + {0x8c58, 1}, + {0x8c59, 2}, + {0x8c5a, 6544}, + {0x8c5c, 0}, + {0x8c5d, 1}, + {0x8c5e, 2}, + {0x8c5f, 3}, + {0x8c60, 4}, + {0x8c61, 3936}, + {0x8c62, 2004}, + {0x8c64, 0}, + {0x8c65, 1}, + {0x8c66, 2}, + {0x8c67, 3}, + {0x8c68, 4}, + {0x8c69, 5}, + {0x8c6a, 1911}, + {0x8c6b, 4328}, + {0x8c6d, 0}, + {0x8c6e, 1}, + {0x8c6f, 2}, + {0x8c70, 3}, + {0x8c71, 4}, + {0x8c72, 5}, + {0x8c73, 5597}, + {0x8c75, 0}, + {0x8c76, 1}, + {0x8c77, 2}, + {0x8c78, 7504}, + {0x8c79, 1043}, + {0x8c7a, 1209}, + {0x8c7c, 0}, + {0x8c7d, 1}, + {0x8c7e, 2}, + {0x8c7f, 3}, + {0x8c80, 4}, + {0x8c81, 5}, + {0x8c82, 7505}, + {0x8c84, 0}, + {0x8c85, 7507}, + {0x8c87, 0}, + {0x8c88, 1}, + {0x8c89, 1928}, + {0x8c8a, 7506}, + {0x8c8c, 2743}, + {0x8c8e, 0}, + {0x8c8f, 1}, + {0x8c90, 2}, + {0x8c91, 3}, + {0x8c92, 4}, + {0x8c93, 5}, + {0x8c94, 7509}, + {0x8c96, 0}, + {0x8c97, 1}, + {0x8c98, 7508}, + {0x8c9a, 0}, + {0x8c9b, 1}, + {0x8c9c, 2}, + {0x8c9d, 7739}, + {0x8c9e, 8831}, + {0x8ca0, 7948}, + {0x8ca1, 7769}, + {0x8ca2, 7972}, + {0x8ca4, 0}, + {0x8ca5, 1}, + {0x8ca6, 2}, + {0x8ca7, 8378}, + {0x8ca8, 8037}, + {0x8ca9, 7920}, + {0x8caa, 8548}, + {0x8cab, 7984}, + {0x8cac, 8801}, + {0x8cae, 0}, + {0x8caf, 8866}, + {0x8cb0, 9387}, + {0x8cb2, 9391}, + {0x8cb3, 7912}, + {0x8cb4, 7993}, + {0x8cb6, 7752}, + {0x8cb7, 8304}, + {0x8cb8, 7848}, + {0x8cba, 9388}, + {0x8cbb, 7927}, + {0x8cbc, 8566}, + {0x8cbd, 9389}, + {0x8cbf, 8315}, + {0x8cc0, 8005}, + {0x8cc1, 9386}, + {0x8cc2, 8267}, + {0x8cc3, 8239}, + {0x8cc4, 8026}, + {0x8cc5, 9392}, + {0x8cc7, 8887}, + {0x8cc8, 8063}, + {0x8cca, 8805}, + {0x8ccc, 0}, + {0x8ccd, 1}, + {0x8cce, 2}, + {0x8ccf, 3}, + {0x8cd0, 4}, + {0x8cd1, 9394}, + {0x8cd2, 8475}, + {0x8cd3, 7761}, + {0x8cd5, 9396}, + {0x8cd7, 0}, + {0x8cd8, 1}, + {0x8cd9, 2}, + {0x8cda, 9395}, + {0x8cdc, 7839}, + {0x8cde, 8472}, + {0x8ce0, 8372}, + {0x8ce1, 9135}, + {0x8ce2, 8635}, + {0x8ce3, 8306}, + {0x8ce4, 8085}, + {0x8ce6, 7946}, + {0x8ce7, 9398}, + {0x8ce9, 0}, + {0x8cea, 8849}, + {0x8ceb, 9397}, + {0x8cec, 8824}, + {0x8ced, 7892}, + {0x8cef, 0}, + {0x8cf0, 1}, + {0x8cf1, 2}, + {0x8cf2, 3}, + {0x8cf3, 4}, + {0x8cf4, 8179}, + {0x8cf6, 0}, + {0x8cf7, 1}, + {0x8cf8, 2}, + {0x8cf9, 3}, + {0x8cfa, 8873}, + {0x8cfb, 9399}, + {0x8cfc, 7976}, + {0x8cfd, 8457}, + {0x8cfe, 8903}, + {0x8d01, 0}, + {0x8d02, 1}, + {0x8d03, 2}, + {0x8d04, 9390}, + {0x8d05, 8881}, + {0x8d07, 0}, + {0x8d08, 8806}, + {0x8d0a, 8795}, + {0x8d0b, 8900}, + {0x8d0d, 8469}, + {0x8d0f, 8746}, + {0x8d10, 9393}, + {0x8d12, 0}, + {0x8d13, 1}, + {0x8d14, 2}, + {0x8d15, 3}, + {0x8d16, 8509}, + {0x8d18, 0}, + {0x8d19, 1}, + {0x8d1a, 2}, + {0x8d1b, 7957}, + {0x8d1c, 8796}, + {0x8d1d, 1053}, + {0x8d1e, 4491}, + {0x8d1f, 1717}, + {0x8d21, 1802}, + {0x8d22, 1165}, + {0x8d23, 4403}, + {0x8d24, 3898}, + {0x8d25, 999}, + {0x8d26, 4460}, + {0x8d27, 2058}, + {0x8d28, 4553}, + {0x8d29, 1620}, + {0x8d2a, 3587}, + {0x8d2b, 3029}, + {0x8d2c, 1098}, + {0x8d2d, 1811}, + {0x8d2e, 4603}, + {0x8d2f, 1850}, + {0x8d30, 1598}, + {0x8d31, 2157}, + {0x8d32, 6444}, + {0x8d33, 6445}, + {0x8d34, 3660}, + {0x8d35, 1868}, + {0x8d36, 6446}, + {0x8d37, 1406}, + {0x8d38, 2744}, + {0x8d39, 1646}, + {0x8d3a, 1935}, + {0x8d3b, 6447}, + {0x8d3c, 4407}, + {0x8d3d, 6448}, + {0x8d3e, 2121}, + {0x8d3f, 2036}, + {0x8d40, 6449}, + {0x8d41, 2599}, + {0x8d42, 2655}, + {0x8d43, 4386}, + {0x8d44, 4647}, + {0x8d45, 6450}, + {0x8d46, 6451}, + {0x8d47, 6454}, + {0x8d48, 6452}, + {0x8d49, 6453}, + {0x8d4a, 3351}, + {0x8d4b, 1710}, + {0x8d4c, 1539}, + {0x8d4d, 6455}, + {0x8d4e, 3457}, + {0x8d4f, 3334}, + {0x8d50, 1360}, + {0x8d52, 0}, + {0x8d53, 5691}, + {0x8d54, 2979}, + {0x8d55, 6456}, + {0x8d56, 2464}, + {0x8d58, 4629}, + {0x8d59, 6457}, + {0x8d5a, 4617}, + {0x8d5b, 3287}, + {0x8d5c, 4745}, + {0x8d5d, 4739}, + {0x8d5e, 4385}, + {0x8d60, 4412}, + {0x8d61, 3325}, + {0x8d62, 4243}, + {0x8d63, 1742}, + {0x8d64, 1285}, + {0x8d66, 3355}, + {0x8d67, 7412}, + {0x8d69, 0}, + {0x8d6a, 1}, + {0x8d6b, 1932}, + {0x8d6d, 7413}, + {0x8d6f, 0}, + {0x8d70, 4668}, + {0x8d72, 0}, + {0x8d73, 7407}, + {0x8d74, 1707}, + {0x8d75, 4469}, + {0x8d76, 1738}, + {0x8d77, 3087}, + {0x8d79, 0}, + {0x8d7a, 1}, + {0x8d7b, 2}, + {0x8d7c, 3}, + {0x8d7d, 4}, + {0x8d7e, 5}, + {0x8d7f, 6}, + {0x8d80, 7}, + {0x8d81, 1256}, + {0x8d83, 0}, + {0x8d84, 7408}, + {0x8d85, 1233}, + {0x8d87, 0}, + {0x8d88, 1}, + {0x8d89, 2}, + {0x8d8a, 4352}, + {0x8d8b, 3188}, + {0x8d8d, 0}, + {0x8d8e, 1}, + {0x8d8f, 2}, + {0x8d90, 3}, + {0x8d91, 7410}, + {0x8d93, 0}, + {0x8d94, 7409}, + {0x8d95, 7956}, + {0x8d97, 0}, + {0x8d98, 1}, + {0x8d99, 8826}, + {0x8d9b, 0}, + {0x8d9c, 1}, + {0x8d9d, 2}, + {0x8d9e, 3}, + {0x8d9f, 3614}, + {0x8da1, 0}, + {0x8da2, 1}, + {0x8da3, 3199}, + {0x8da5, 0}, + {0x8da6, 1}, + {0x8da7, 2}, + {0x8da8, 8430}, + {0x8daa, 0}, + {0x8dab, 1}, + {0x8dac, 2}, + {0x8dad, 3}, + {0x8dae, 4}, + {0x8daf, 5}, + {0x8db0, 6}, + {0x8db1, 7411}, + {0x8db2, 9720}, + {0x8db3, 4672}, + {0x8db4, 2944}, + {0x8db5, 7452}, + {0x8db7, 0}, + {0x8db8, 7447}, + {0x8dba, 7455}, + {0x8dbc, 7454}, + {0x8dbe, 4537}, + {0x8dbf, 7453}, + {0x8dc1, 0}, + {0x8dc2, 1}, + {0x8dc3, 4353}, + {0x8dc4, 7456}, + {0x8dc6, 7464}, + {0x8dc8, 0}, + {0x8dc9, 1}, + {0x8dca, 2}, + {0x8dcb, 986}, + {0x8dcc, 1497}, + {0x8dce, 7461}, + {0x8dcf, 7462}, + {0x8dd1, 2973}, + {0x8dd3, 0}, + {0x8dd4, 1}, + {0x8dd5, 2}, + {0x8dd6, 7457}, + {0x8dd7, 7458}, + {0x8dd9, 0}, + {0x8dda, 7459}, + {0x8ddb, 7463}, + {0x8ddd, 2319}, + {0x8dde, 7460}, + {0x8ddf, 1781}, + {0x8de1, 0}, + {0x8de2, 1}, + {0x8de3, 7468}, + {0x8de4, 7471}, + {0x8de6, 0}, + {0x8de7, 1}, + {0x8de8, 2420}, + {0x8dea, 1867}, + {0x8deb, 7448}, + {0x8dec, 7465}, + {0x8dee, 0}, + {0x8def, 2654}, + {0x8df1, 0}, + {0x8df2, 1}, + {0x8df3, 3659}, + {0x8df5, 2156}, + {0x8df7, 7466}, + {0x8df8, 7467}, + {0x8df9, 7469}, + {0x8dfa, 1572}, + {0x8dfb, 7470}, + {0x8dfd, 7473}, + {0x8dff, 0}, + {0x8e01, 0}, + {0x8e02, 1}, + {0x8e03, 2}, + {0x8e04, 3}, + {0x8e05, 7449}, + {0x8e07, 0}, + {0x8e08, 1}, + {0x8e09, 7472}, + {0x8e0a, 4256}, + {0x8e0c, 1297}, + {0x8e0e, 0}, + {0x8e0f, 3575}, + {0x8e10, 8084}, + {0x8e12, 0}, + {0x8e13, 1}, + {0x8e14, 7474}, + {0x8e16, 0}, + {0x8e17, 1}, + {0x8e18, 2}, + {0x8e19, 3}, + {0x8e1a, 4}, + {0x8e1b, 5}, + {0x8e1c, 6}, + {0x8e1d, 7475}, + {0x8e1e, 2320}, + {0x8e1f, 7476}, + {0x8e21, 0}, + {0x8e22, 3634}, + {0x8e23, 7479}, + {0x8e25, 0}, + {0x8e26, 1}, + {0x8e27, 2}, + {0x8e28, 3}, + {0x8e29, 1167}, + {0x8e2a, 4662}, + {0x8e2c, 7477}, + {0x8e2e, 7478}, + {0x8e2f, 7480}, + {0x8e31, 7486}, + {0x8e33, 0}, + {0x8e34, 8752}, + {0x8e35, 7484}, + {0x8e37, 0}, + {0x8e38, 1}, + {0x8e39, 7483}, + {0x8e3a, 7481}, + {0x8e3c, 0}, + {0x8e3d, 7485}, + {0x8e3f, 0}, + {0x8e40, 7482}, + {0x8e41, 7488}, + {0x8e42, 7489}, + {0x8e44, 3638}, + {0x8e46, 0}, + {0x8e47, 5947}, + {0x8e48, 1433}, + {0x8e49, 7487}, + {0x8e4a, 7492}, + {0x8e4b, 3574}, + {0x8e4c, 9725}, + {0x8e4e, 0}, + {0x8e4f, 1}, + {0x8e50, 2}, + {0x8e51, 7490}, + {0x8e52, 7491}, + {0x8e54, 0}, + {0x8e55, 9728}, + {0x8e57, 0}, + {0x8e58, 1}, + {0x8e59, 7450}, + {0x8e5b, 0}, + {0x8e5c, 1}, + {0x8e5d, 2}, + {0x8e5e, 3}, + {0x8e5f, 4}, + {0x8e60, 5}, + {0x8e61, 6}, + {0x8e62, 7}, + {0x8e63, 9734}, + {0x8e65, 0}, + {0x8e66, 1069}, + {0x8e68, 0}, + {0x8e69, 7451}, + {0x8e6b, 0}, + {0x8e6c, 1446}, + {0x8e6d, 1195}, + {0x8e6f, 7496}, + {0x8e70, 7493}, + {0x8e72, 1558}, + {0x8e74, 7497}, + {0x8e76, 7494}, + {0x8e78, 0}, + {0x8e79, 1}, + {0x8e7a, 9727}, + {0x8e7c, 7495}, + {0x8e7e, 0}, + {0x8e7f, 1373}, + {0x8e81, 4397}, + {0x8e83, 0}, + {0x8e84, 1}, + {0x8e85, 7498}, + {0x8e87, 1310}, + {0x8e89, 9724}, + {0x8e8a, 7820}, + {0x8e8b, 9730}, + {0x8e8d, 8781}, + {0x8e8f, 7499}, + {0x8e90, 7501}, + {0x8e91, 9732}, + {0x8e92, 9726}, + {0x8e93, 9731}, + {0x8e94, 7500}, + {0x8e96, 0}, + {0x8e97, 1}, + {0x8e98, 2}, + {0x8e99, 3}, + {0x8e9a, 9729}, + {0x8e9c, 7502}, + {0x8e9e, 7503}, + {0x8ea0, 0}, + {0x8ea1, 9733}, + {0x8ea3, 0}, + {0x8ea4, 1}, + {0x8ea5, 7843}, + {0x8ea6, 9736}, + {0x8ea8, 0}, + {0x8ea9, 1}, + {0x8eaa, 9735}, + {0x8eab, 3366}, + {0x8eac, 1795}, + {0x8eae, 0}, + {0x8eaf, 3192}, + {0x8eb1, 0}, + {0x8eb2, 1570}, + {0x8eb4, 0}, + {0x8eb5, 1}, + {0x8eb6, 2}, + {0x8eb7, 3}, + {0x8eb8, 4}, + {0x8eb9, 5}, + {0x8eba, 3612}, + {0x8ebc, 0}, + {0x8ebd, 1}, + {0x8ebe, 2}, + {0x8ebf, 3}, + {0x8ec0, 8432}, + {0x8ec2, 0}, + {0x8ec3, 1}, + {0x8ec4, 2}, + {0x8ec5, 3}, + {0x8ec6, 4}, + {0x8ec7, 5}, + {0x8ec8, 6}, + {0x8ec9, 7}, + {0x8eca, 7803}, + {0x8ecb, 8807}, + {0x8ecc, 7990}, + {0x8ecd, 8150}, + {0x8ece, 6392}, + {0x8ed0, 0}, + {0x8ed1, 1}, + {0x8ed2, 8672}, + {0x8ed4, 9356}, + {0x8ed6, 0}, + {0x8ed7, 1}, + {0x8ed8, 2}, + {0x8ed9, 3}, + {0x8eda, 4}, + {0x8edb, 9357}, + {0x8edd, 0}, + {0x8ede, 1}, + {0x8edf, 8450}, + {0x8ee1, 0}, + {0x8ee2, 1}, + {0x8ee3, 2}, + {0x8ee4, 9364}, + {0x8ee6, 0}, + {0x8ee7, 1}, + {0x8ee8, 2}, + {0x8ee9, 3}, + {0x8eea, 4}, + {0x8eeb, 9363}, + {0x8eed, 0}, + {0x8eee, 1}, + {0x8eef, 2}, + {0x8ef0, 3}, + {0x8ef1, 4}, + {0x8ef2, 9358}, + {0x8ef4, 0}, + {0x8ef5, 1}, + {0x8ef6, 2}, + {0x8ef7, 3}, + {0x8ef8, 8857}, + {0x8ef9, 9361}, + {0x8efa, 9366}, + {0x8efb, 9359}, + {0x8efc, 9362}, + {0x8efe, 9367}, + {0x8f01, 0}, + {0x8f02, 1}, + {0x8f03, 8113}, + {0x8f05, 9370}, + {0x8f07, 9369}, + {0x8f09, 8792}, + {0x8f0a, 9368}, + {0x8f0c, 0}, + {0x8f0d, 1}, + {0x8f0e, 2}, + {0x8f0f, 3}, + {0x8f10, 4}, + {0x8f11, 5}, + {0x8f12, 9371}, + {0x8f14, 7945}, + {0x8f15, 8422}, + {0x8f17, 0}, + {0x8f18, 1}, + {0x8f19, 2}, + {0x8f1a, 3}, + {0x8f1b, 8230}, + {0x8f1c, 9375}, + {0x8f1d, 8025}, + {0x8f1e, 9373}, + {0x8f1f, 9374}, + {0x8f21, 0}, + {0x8f22, 1}, + {0x8f23, 2}, + {0x8f24, 3}, + {0x8f25, 7995}, + {0x8f26, 9372}, + {0x8f28, 0}, + {0x8f29, 7738}, + {0x8f2a, 8283}, + {0x8f2c, 0}, + {0x8f2d, 1}, + {0x8f2e, 2}, + {0x8f2f, 8048}, + {0x8f31, 0}, + {0x8f32, 1}, + {0x8f33, 9376}, + {0x8f35, 0}, + {0x8f36, 1}, + {0x8f37, 2}, + {0x8f38, 8507}, + {0x8f3a, 0}, + {0x8f3b, 7943}, + {0x8f3d, 0}, + {0x8f3e, 8816}, + {0x8f3f, 8759}, + {0x8f41, 0}, + {0x8f42, 9426}, + {0x8f44, 8627}, + {0x8f45, 8773}, + {0x8f46, 9377}, + {0x8f48, 0}, + {0x8f49, 8872}, + {0x8f4b, 0}, + {0x8f4c, 1}, + {0x8f4d, 8828}, + {0x8f4e, 8112}, + {0x8f50, 0}, + {0x8f51, 1}, + {0x8f52, 2}, + {0x8f53, 3}, + {0x8f54, 9378}, + {0x8f56, 0}, + {0x8f57, 1}, + {0x8f58, 2}, + {0x8f59, 3}, + {0x8f5a, 4}, + {0x8f5b, 5}, + {0x8f5c, 6}, + {0x8f5d, 7}, + {0x8f5e, 8}, + {0x8f5f, 8006}, + {0x8f61, 9088}, + {0x8f62, 9365}, + {0x8f64, 9360}, + {0x8f66, 1242}, + {0x8f67, 4417}, + {0x8f68, 1861}, + {0x8f69, 4036}, + {0x8f6b, 6369}, + {0x8f6c, 4615}, + {0x8f6d, 6370}, + {0x8f6e, 2685}, + {0x8f6f, 3272}, + {0x8f70, 1947}, + {0x8f71, 6371}, + {0x8f72, 6372}, + {0x8f73, 6373}, + {0x8f74, 4576}, + {0x8f75, 6374}, + {0x8f76, 6375}, + {0x8f77, 6377}, + {0x8f78, 6376}, + {0x8f79, 6378}, + {0x8f7a, 6379}, + {0x8f7b, 3166}, + {0x8f7c, 6380}, + {0x8f7d, 4379}, + {0x8f7e, 6381}, + {0x8f7f, 2207}, + {0x8f81, 6382}, + {0x8f82, 6383}, + {0x8f83, 2208}, + {0x8f84, 6384}, + {0x8f85, 1699}, + {0x8f86, 2567}, + {0x8f87, 6385}, + {0x8f88, 1051}, + {0x8f89, 2025}, + {0x8f8a, 1870}, + {0x8f8b, 6386}, + {0x8f8d, 6387}, + {0x8f8e, 6388}, + {0x8f8f, 6389}, + {0x8f90, 1685}, + {0x8f91, 2080}, + {0x8f93, 3451}, + {0x8f94, 5492}, + {0x8f95, 4338}, + {0x8f96, 3882}, + {0x8f97, 4440}, + {0x8f98, 6390}, + {0x8f99, 4479}, + {0x8f9a, 6391}, + {0x8f9b, 3980}, + {0x8f9c, 1813}, + {0x8f9e, 1354}, + {0x8f9f, 1090}, + {0x8fa1, 0}, + {0x8fa2, 1}, + {0x8fa3, 2460}, + {0x8fa5, 0}, + {0x8fa6, 7728}, + {0x8fa8, 1103}, + {0x8fa9, 1104}, + {0x8fab, 1105}, + {0x8fad, 7837}, + {0x8fae, 7755}, + {0x8faf, 7754}, + {0x8fb0, 1250}, + {0x8fb1, 3267}, + {0x8fb2, 8362}, + {0x8fb4, 0}, + {0x8fb5, 1}, + {0x8fb6, 5949}, + {0x8fb8, 0}, + {0x8fb9, 1096}, + {0x8fbb, 0}, + {0x8fbc, 1}, + {0x8fbd, 2578}, + {0x8fbe, 1394}, + {0x8fc0, 0}, + {0x8fc1, 3109}, + {0x8fc2, 4285}, + {0x8fc4, 3096}, + {0x8fc5, 4065}, + {0x8fc7, 1878}, + {0x8fc8, 2716}, + {0x8fca, 0}, + {0x8fcb, 1}, + {0x8fcc, 2}, + {0x8fcd, 3}, + {0x8fce, 4242}, + {0x8fd0, 4366}, + {0x8fd1, 2253}, + {0x8fd3, 5950}, + {0x8fd4, 1618}, + {0x8fd5, 5951}, + {0x8fd7, 0}, + {0x8fd8, 1998}, + {0x8fd9, 4483}, + {0x8fdb, 2249}, + {0x8fdc, 4345}, + {0x8fdd, 3764}, + {0x8fde, 2549}, + {0x8fdf, 1278}, + {0x8fe1, 0}, + {0x8fe2, 3657}, + {0x8fe4, 5954}, + {0x8fe5, 5952}, + {0x8fe6, 5956}, + {0x8fe8, 5958}, + {0x8fe9, 5955}, + {0x8fea, 1456}, + {0x8feb, 3047}, + {0x8fed, 1501}, + {0x8fee, 5953}, + {0x8ff0, 3469}, + {0x8ff2, 0}, + {0x8ff3, 5957}, + {0x8ff4, 9851}, + {0x8ff6, 0}, + {0x8ff7, 2777}, + {0x8ff8, 1070}, + {0x8ff9, 2070}, + {0x8ffb, 0}, + {0x8ffc, 1}, + {0x8ffd, 4628}, + {0x8fff, 0}, + {0x9000, 3708}, + {0x9001, 3522}, + {0x9002, 3425}, + {0x9003, 3622}, + {0x9004, 5960}, + {0x9005, 5959}, + {0x9006, 2889}, + {0x9008, 0}, + {0x9009, 4042}, + {0x900a, 4064}, + {0x900b, 5961}, + {0x900d, 5964}, + {0x900f, 3689}, + {0x9010, 4591}, + {0x9011, 5963}, + {0x9012, 1470}, + {0x9014, 3695}, + {0x9015, 9202}, + {0x9016, 5965}, + {0x9017, 1529}, + {0x9019, 8830}, + {0x901a, 3673}, + {0x901b, 1853}, + {0x901d, 3420}, + {0x901e, 1270}, + {0x901f, 3534}, + {0x9020, 4399}, + {0x9021, 5966}, + {0x9022, 1671}, + {0x9023, 8217}, + {0x9025, 0}, + {0x9026, 5962}, + {0x9028, 0}, + {0x9029, 1}, + {0x902a, 2}, + {0x902b, 3}, + {0x902c, 4}, + {0x902d, 5969}, + {0x902e, 1409}, + {0x902f, 5970}, + {0x9031, 0}, + {0x9032, 8123}, + {0x9034, 0}, + {0x9035, 5967}, + {0x9036, 5968}, + {0x9038, 4196}, + {0x903a, 0}, + {0x903b, 2694}, + {0x903c, 1071}, + {0x903e, 4295}, + {0x9040, 0}, + {0x9041, 1564}, + {0x9042, 3553}, + {0x9044, 5971}, + {0x9046, 0}, + {0x9047, 4315}, + {0x9049, 0}, + {0x904a, 1}, + {0x904b, 8787}, + {0x904d, 1106}, + {0x904e, 7998}, + {0x904f, 1587}, + {0x9050, 5974}, + {0x9051, 5972}, + {0x9052, 5973}, + {0x9053, 1441}, + {0x9054, 7846}, + {0x9055, 8590}, + {0x9057, 4172}, + {0x9058, 5976}, + {0x905a, 0}, + {0x905b, 5978}, + {0x905c, 8684}, + {0x905e, 7870}, + {0x9060, 8778}, + {0x9062, 5977}, + {0x9063, 3119}, + {0x9065, 4138}, + {0x9067, 0}, + {0x9068, 5975}, + {0x9069, 8499}, + {0x906b, 0}, + {0x906c, 1}, + {0x906d, 4389}, + {0x906e, 4475}, + {0x9070, 0}, + {0x9071, 1}, + {0x9072, 7812}, + {0x9074, 5980}, + {0x9075, 4686}, + {0x9077, 8399}, + {0x9078, 8674}, + {0x907a, 8719}, + {0x907c, 8233}, + {0x907d, 5981}, + {0x907f, 1093}, + {0x9080, 4132}, + {0x9081, 8307}, + {0x9082, 5982}, + {0x9083, 5984}, + {0x9084, 8021}, + {0x9086, 0}, + {0x9087, 9201}, + {0x9088, 5983}, + {0x908a, 7750}, + {0x908b, 5985}, + {0x908d, 0}, + {0x908e, 1}, + {0x908f, 8291}, + {0x9090, 9203}, + {0x9091, 4191}, + {0x9093, 1452}, + {0x9095, 6167}, + {0x9097, 4967}, + {0x9099, 4970}, + {0x909b, 4968}, + {0x909d, 4969}, + {0x909f, 0}, + {0x90a0, 1}, + {0x90a1, 4972}, + {0x90a2, 3994}, + {0x90a3, 2858}, + {0x90a5, 0}, + {0x90a6, 1017}, + {0x90a8, 0}, + {0x90a9, 1}, + {0x90aa, 3963}, + {0x90ac, 4971}, + {0x90ae, 4271}, + {0x90af, 1889}, + {0x90b0, 4978}, + {0x90b1, 3182}, + {0x90b3, 4974}, + {0x90b4, 4973}, + {0x90b5, 3348}, + {0x90b6, 4975}, + {0x90b8, 4977}, + {0x90b9, 4667}, + {0x90ba, 4976}, + {0x90bb, 2595}, + {0x90bd, 0}, + {0x90be, 4981}, + {0x90c0, 0}, + {0x90c1, 4313}, + {0x90c3, 0}, + {0x90c4, 4983}, + {0x90c5, 4980}, + {0x90c7, 4984}, + {0x90c9, 0}, + {0x90ca, 2189}, + {0x90cc, 0}, + {0x90cd, 1}, + {0x90ce, 2484}, + {0x90cf, 4979}, + {0x90d0, 4982}, + {0x90d1, 4514}, + {0x90d3, 4985}, + {0x90d5, 0}, + {0x90d6, 1}, + {0x90d7, 4989}, + {0x90d9, 0}, + {0x90da, 1}, + {0x90db, 4990}, + {0x90dc, 4988}, + {0x90dd, 1913}, + {0x90df, 8990}, + {0x90e1, 2353}, + {0x90e2, 4987}, + {0x90e4, 0}, + {0x90e5, 1}, + {0x90e6, 4986}, + {0x90e7, 4362}, + {0x90e8, 1158}, + {0x90ea, 0}, + {0x90eb, 4991}, + {0x90ed, 1874}, + {0x90ef, 4992}, + {0x90f1, 0}, + {0x90f2, 1}, + {0x90f3, 2}, + {0x90f4, 1248}, + {0x90f5, 8755}, + {0x90f7, 0}, + {0x90f8, 1415}, + {0x90fa, 0}, + {0x90fb, 1}, + {0x90fc, 2}, + {0x90fd, 1531}, + {0x90fe, 4993}, + {0x9101, 0}, + {0x9102, 1588}, + {0x9104, 4994}, + {0x9106, 8992}, + {0x9108, 0}, + {0x9109, 8647}, + {0x910b, 0}, + {0x910c, 1}, + {0x910d, 2}, + {0x910e, 3}, + {0x910f, 4}, + {0x9110, 5}, + {0x9111, 6}, + {0x9112, 8892}, + {0x9114, 8988}, + {0x9116, 8785}, + {0x9118, 0}, + {0x9119, 1074}, + {0x911b, 0}, + {0x911c, 1}, + {0x911d, 2}, + {0x911e, 4996}, + {0x9120, 0}, + {0x9121, 1}, + {0x9122, 4995}, + {0x9123, 4997}, + {0x9125, 0}, + {0x9126, 1}, + {0x9127, 7867}, + {0x9129, 0}, + {0x912a, 1}, + {0x912b, 2}, + {0x912c, 3}, + {0x912d, 8839}, + {0x912f, 4999}, + {0x9130, 8237}, + {0x9131, 4998}, + {0x9132, 7851}, + {0x9134, 8989}, + {0x9136, 8991}, + {0x9138, 0}, + {0x9139, 5000}, + {0x913a, 8987}, + {0x913c, 0}, + {0x913d, 1}, + {0x913e, 2}, + {0x913f, 3}, + {0x9140, 4}, + {0x9141, 5}, + {0x9142, 6}, + {0x9143, 5001}, + {0x9145, 0}, + {0x9146, 5002}, + {0x9148, 8993}, + {0x9149, 4276}, + {0x914a, 7416}, + {0x914b, 3186}, + {0x914c, 4640}, + {0x914d, 2981}, + {0x914e, 7418}, + {0x914f, 7419}, + {0x9150, 7417}, + {0x9152, 2293}, + {0x9154, 0}, + {0x9155, 1}, + {0x9156, 2}, + {0x9157, 4026}, + {0x9159, 0}, + {0x915a, 1648}, + {0x915c, 0}, + {0x915d, 4368}, + {0x915e, 3581}, + {0x9160, 0}, + {0x9161, 7422}, + {0x9162, 7421}, + {0x9163, 1887}, + {0x9164, 7420}, + {0x9165, 3531}, + {0x9167, 0}, + {0x9168, 1}, + {0x9169, 7424}, + {0x916a, 2493}, + {0x916c, 1295}, + {0x916e, 3675}, + {0x916f, 7425}, + {0x9170, 7423}, + {0x9171, 2181}, + {0x9172, 7428}, + {0x9174, 7429}, + {0x9175, 2206}, + {0x9176, 2749}, + {0x9177, 2414}, + {0x9178, 3542}, + {0x9179, 7430}, + {0x917b, 0}, + {0x917c, 1}, + {0x917d, 7426}, + {0x917e, 7427}, + {0x917f, 2899}, + {0x9181, 0}, + {0x9182, 1}, + {0x9183, 2}, + {0x9184, 3}, + {0x9185, 7432}, + {0x9187, 1343}, + {0x9189, 4682}, + {0x918b, 1370}, + {0x918c, 7431}, + {0x918d, 7434}, + {0x918f, 0}, + {0x9190, 7433}, + {0x9191, 7435}, + {0x9192, 3996}, + {0x9194, 0}, + {0x9195, 1}, + {0x9196, 8789}, + {0x9198, 0}, + {0x9199, 1}, + {0x919a, 2774}, + {0x919b, 3204}, + {0x919c, 7823}, + {0x919e, 0}, + {0x919f, 1}, + {0x91a0, 2}, + {0x91a1, 3}, + {0x91a2, 7436}, + {0x91a3, 7437}, + {0x91a5, 0}, + {0x91a6, 1}, + {0x91a7, 2}, + {0x91a8, 3}, + {0x91a9, 4}, + {0x91aa, 7438}, + {0x91ab, 8716}, + {0x91ac, 8100}, + {0x91ad, 7439}, + {0x91ae, 7440}, + {0x91af, 7441}, + {0x91b1, 0}, + {0x91b2, 1}, + {0x91b3, 2}, + {0x91b4, 7443}, + {0x91b5, 7442}, + {0x91b7, 0}, + {0x91b8, 1}, + {0x91b9, 2}, + {0x91ba, 7444}, + {0x91bc, 0}, + {0x91bd, 1}, + {0x91be, 2}, + {0x91bf, 3}, + {0x91c0, 8347}, + {0x91c1, 8664}, + {0x91c3, 9722}, + {0x91c5, 9721}, + {0x91c7, 1168}, + {0x91c9, 4281}, + {0x91ca, 3428}, + {0x91cb, 8500}, + {0x91cc, 2522}, + {0x91cd, 4567}, + {0x91ce, 4151}, + {0x91cf, 2568}, + {0x91d1, 2241}, + {0x91d2, 9459}, + {0x91d3, 9460}, + {0x91d4, 9461}, + {0x91d5, 9464}, + {0x91d7, 9463}, + {0x91d8, 7880}, + {0x91d9, 9462}, + {0x91db, 0}, + {0x91dc, 1701}, + {0x91dd, 8832}, + {0x91df, 0}, + {0x91e0, 1}, + {0x91e1, 2}, + {0x91e2, 3}, + {0x91e3, 7877}, + {0x91e4, 9467}, + {0x91e6, 0}, + {0x91e7, 9466}, + {0x91e9, 7917}, + {0x91eb, 0}, + {0x91ec, 1}, + {0x91ed, 2}, + {0x91ee, 3}, + {0x91ef, 4}, + {0x91f0, 5}, + {0x91f1, 6}, + {0x91f2, 7}, + {0x91f3, 8}, + {0x91f4, 9}, + {0x91f5, 9469}, + {0x91f7, 9465}, + {0x91f9, 9470}, + {0x91fa, 8397}, + {0x91fc, 0}, + {0x91fd, 1}, + {0x91fe, 2}, + {0x91ff, 3}, + {0x9200, 9480}, + {0x9201, 9476}, + {0x9203, 0}, + {0x9204, 9478}, + {0x9206, 0}, + {0x9207, 1}, + {0x9208, 9471}, + {0x9209, 8336}, + {0x920b, 0}, + {0x920c, 1}, + {0x920d, 7901}, + {0x920e, 7973}, + {0x9210, 9475}, + {0x9211, 9474}, + {0x9213, 0}, + {0x9214, 7802}, + {0x9215, 8358}, + {0x9217, 0}, + {0x9218, 1}, + {0x9219, 2}, + {0x921a, 3}, + {0x921b, 4}, + {0x921c, 5}, + {0x921d, 6}, + {0x921e, 8149}, + {0x9220, 0}, + {0x9221, 1}, + {0x9222, 2}, + {0x9223, 7953}, + {0x9225, 9479}, + {0x9226, 9472}, + {0x9227, 9477}, + {0x9229, 0}, + {0x922a, 1}, + {0x922b, 2}, + {0x922c, 3}, + {0x922d, 4}, + {0x922e, 9497}, + {0x9230, 9493}, + {0x9232, 0}, + {0x9233, 9484}, + {0x9234, 8241}, + {0x9236, 0}, + {0x9237, 9483}, + {0x9238, 9487}, + {0x9239, 9498}, + {0x923a, 9481}, + {0x923c, 0}, + {0x923d, 9486}, + {0x923e, 8756}, + {0x923f, 9491}, + {0x9240, 8064}, + {0x9242, 0}, + {0x9243, 1}, + {0x9244, 2}, + {0x9245, 9473}, + {0x9247, 0}, + {0x9248, 9495}, + {0x9249, 9494}, + {0x924b, 0}, + {0x924c, 1}, + {0x924d, 9496}, + {0x924f, 0}, + {0x9250, 1}, + {0x9251, 7766}, + {0x9253, 0}, + {0x9254, 1}, + {0x9255, 9485}, + {0x9257, 8403}, + {0x9259, 0}, + {0x925a, 8314}, + {0x925b, 8398}, + {0x925d, 0}, + {0x925e, 9488}, + {0x9260, 0}, + {0x9261, 1}, + {0x9262, 7765}, + {0x9264, 0}, + {0x9265, 1}, + {0x9266, 9482}, + {0x9268, 0}, + {0x9269, 1}, + {0x926a, 2}, + {0x926b, 3}, + {0x926c, 9489}, + {0x926d, 9490}, + {0x926f, 0}, + {0x9270, 1}, + {0x9271, 2}, + {0x9272, 3}, + {0x9273, 4}, + {0x9274, 2155}, + {0x9276, 0}, + {0x9277, 1}, + {0x9278, 8106}, + {0x927a, 9502}, + {0x927b, 7967}, + {0x927d, 0}, + {0x927e, 1}, + {0x927f, 9517}, + {0x9280, 8733}, + {0x9282, 0}, + {0x9283, 9522}, + {0x9285, 8571}, + {0x9287, 0}, + {0x9288, 1}, + {0x9289, 2}, + {0x928a, 3}, + {0x928b, 4}, + {0x928c, 5}, + {0x928d, 6}, + {0x928e, 7552}, + {0x9290, 0}, + {0x9291, 8623}, + {0x9293, 9516}, + {0x9295, 0}, + {0x9296, 9512}, + {0x9298, 8332}, + {0x929a, 9519}, + {0x929c, 8636}, + {0x929e, 0}, + {0x929f, 1}, + {0x92a0, 9501}, + {0x92a2, 0}, + {0x92a3, 9525}, + {0x92a5, 8717}, + {0x92a6, 9510}, + {0x92a8, 9524}, + {0x92a9, 9514}, + {0x92aa, 9503}, + {0x92ab, 9521}, + {0x92ac, 9500}, + {0x92ae, 7553}, + {0x92b0, 0}, + {0x92b1, 9509}, + {0x92b3, 0}, + {0x92b4, 1}, + {0x92b5, 2}, + {0x92b6, 3}, + {0x92b7, 8653}, + {0x92b9, 8666}, + {0x92bb, 8562}, + {0x92bc, 9534}, + {0x92be, 0}, + {0x92bf, 1}, + {0x92c0, 2}, + {0x92c1, 8271}, + {0x92c3, 9539}, + {0x92c5, 8663}, + {0x92c7, 7740}, + {0x92c8, 7554}, + {0x92ca, 0}, + {0x92cb, 1}, + {0x92cc, 9513}, + {0x92ce, 0}, + {0x92cf, 9505}, + {0x92d1, 0}, + {0x92d2, 7935}, + {0x92d4, 0}, + {0x92d5, 1}, + {0x92d6, 2}, + {0x92d7, 3}, + {0x92d8, 4}, + {0x92d9, 5}, + {0x92da, 6}, + {0x92db, 7}, + {0x92dc, 8}, + {0x92dd, 9535}, + {0x92df, 9540}, + {0x92e1, 0}, + {0x92e2, 1}, + {0x92e3, 9507}, + {0x92e4, 7824}, + {0x92e5, 9530}, + {0x92e6, 9541}, + {0x92e8, 9533}, + {0x92ea, 8385}, + {0x92ec, 0}, + {0x92ed, 8451}, + {0x92ee, 9504}, + {0x92ef, 9532}, + {0x92f0, 9531}, + {0x92f1, 9528}, + {0x92f3, 0}, + {0x92f4, 1}, + {0x92f5, 2}, + {0x92f6, 9536}, + {0x92f8, 8141}, + {0x92fa, 0}, + {0x92fb, 1}, + {0x92fc, 7960}, + {0x92fe, 0}, + {0x92ff, 1}, + {0x9301, 9547}, + {0x9303, 0}, + {0x9304, 1}, + {0x9305, 2}, + {0x9306, 9543}, + {0x9307, 9551}, + {0x9308, 9552}, + {0x930a, 0}, + {0x930b, 1}, + {0x930c, 2}, + {0x930d, 3}, + {0x930e, 4}, + {0x930f, 5}, + {0x9310, 8880}, + {0x9312, 9542}, + {0x9314, 0}, + {0x9315, 9548}, + {0x9317, 0}, + {0x9318, 7834}, + {0x9319, 9554}, + {0x931a, 9520}, + {0x931b, 9545}, + {0x931d, 0}, + {0x931e, 1}, + {0x931f, 9553}, + {0x9320, 7882}, + {0x9322, 8402}, + {0x9324, 0}, + {0x9325, 1}, + {0x9326, 8120}, + {0x9328, 8313}, + {0x932a, 0}, + {0x932b, 8619}, + {0x932d, 0}, + {0x932e, 9549}, + {0x932f, 7845}, + {0x9331, 0}, + {0x9332, 8268}, + {0x9333, 8320}, + {0x9335, 0}, + {0x9336, 9837}, + {0x9338, 9527}, + {0x933a, 0}, + {0x933b, 1}, + {0x933c, 2}, + {0x933d, 3}, + {0x933e, 7555}, + {0x9340, 9546}, + {0x9341, 8632}, + {0x9343, 9550}, + {0x9345, 0}, + {0x9346, 9468}, + {0x9347, 9556}, + {0x9349, 0}, + {0x934a, 1}, + {0x934b, 7996}, + {0x934d, 7893}, + {0x934f, 0}, + {0x9350, 1}, + {0x9351, 2}, + {0x9352, 3}, + {0x9353, 4}, + {0x9354, 9558}, + {0x9356, 0}, + {0x9357, 1}, + {0x9358, 8808}, + {0x935a, 0}, + {0x935b, 7894}, + {0x935d, 0}, + {0x935e, 1}, + {0x935f, 2}, + {0x9360, 3}, + {0x9361, 4}, + {0x9362, 5}, + {0x9363, 6}, + {0x9364, 9559}, + {0x9365, 9555}, + {0x9367, 0}, + {0x9368, 1}, + {0x9369, 9544}, + {0x936a, 7556}, + {0x936c, 8412}, + {0x936e, 0}, + {0x936f, 1}, + {0x9370, 9561}, + {0x9372, 0}, + {0x9373, 1}, + {0x9374, 2}, + {0x9375, 8087}, + {0x9376, 9557}, + {0x9378, 0}, + {0x9379, 1}, + {0x937a, 8829}, + {0x937c, 0}, + {0x937d, 1}, + {0x937e, 9598}, + {0x9380, 0}, + {0x9381, 1}, + {0x9382, 8316}, + {0x9384, 9562}, + {0x9386, 0}, + {0x9387, 9566}, + {0x9389, 0}, + {0x938a, 7732}, + {0x938c, 0}, + {0x938d, 1}, + {0x938e, 2}, + {0x938f, 7558}, + {0x9391, 0}, + {0x9392, 1}, + {0x9393, 2}, + {0x9394, 3}, + {0x9395, 4}, + {0x9396, 8542}, + {0x9398, 9568}, + {0x939a, 0}, + {0x939b, 1}, + {0x939c, 2}, + {0x939d, 3}, + {0x939e, 4}, + {0x939f, 5}, + {0x93a0, 6}, + {0x93a1, 7}, + {0x93a2, 8610}, + {0x93a3, 9044}, + {0x93a5, 0}, + {0x93a6, 9571}, + {0x93a7, 9511}, + {0x93a9, 9518}, + {0x93aa, 9560}, + {0x93ac, 7963}, + {0x93ae, 8835}, + {0x93b0, 9572}, + {0x93b2, 0}, + {0x93b3, 8352}, + {0x93b5, 9573}, + {0x93b7, 0}, + {0x93b8, 9569}, + {0x93ba, 0}, + {0x93bb, 1}, + {0x93bc, 2}, + {0x93bd, 3}, + {0x93be, 4}, + {0x93bf, 9570}, + {0x93c1, 0}, + {0x93c2, 1}, + {0x93c3, 9580}, + {0x93c5, 0}, + {0x93c6, 1}, + {0x93c7, 9581}, + {0x93c8, 8224}, + {0x93ca, 7557}, + {0x93cc, 9567}, + {0x93cd, 9578}, + {0x93cf, 0}, + {0x93d0, 1}, + {0x93d1, 9582}, + {0x93d3, 0}, + {0x93d4, 1}, + {0x93d5, 2}, + {0x93d6, 7681}, + {0x93d7, 9529}, + {0x93d8, 9564}, + {0x93da, 0}, + {0x93db, 1}, + {0x93dc, 9576}, + {0x93dd, 9577}, + {0x93de, 9579}, + {0x93df, 7791}, + {0x93e1, 8132}, + {0x93e2, 9575}, + {0x93e4, 9563}, + {0x93e6, 0}, + {0x93e7, 1}, + {0x93e8, 9757}, + {0x93ea, 0}, + {0x93eb, 1}, + {0x93ec, 2}, + {0x93ed, 3}, + {0x93ee, 4}, + {0x93ef, 5}, + {0x93f0, 6}, + {0x93f1, 7}, + {0x93f2, 8}, + {0x93f3, 9}, + {0x93f4, 10}, + {0x93f5, 9515}, + {0x93f7, 9585}, + {0x93f9, 9591}, + {0x93fb, 0}, + {0x93fc, 1}, + {0x93fd, 2}, + {0x93fe, 3}, + {0x93ff, 4}, + {0x9401, 0}, + {0x9402, 1}, + {0x9403, 9506}, + {0x9405, 0}, + {0x9406, 1}, + {0x9407, 2}, + {0x9408, 3}, + {0x9409, 4}, + {0x940a, 5}, + {0x940b, 9523}, + {0x940d, 0}, + {0x940e, 1}, + {0x940f, 2}, + {0x9410, 8234}, + {0x9412, 9526}, + {0x9413, 9587}, + {0x9414, 9583}, + {0x9416, 0}, + {0x9417, 1}, + {0x9418, 8851}, + {0x9419, 9592}, + {0x941b, 0}, + {0x941c, 1}, + {0x941d, 9584}, + {0x941f, 0}, + {0x9420, 9589}, + {0x9422, 0}, + {0x9423, 1}, + {0x9424, 2}, + {0x9425, 3}, + {0x9426, 9537}, + {0x9427, 9538}, + {0x9428, 9565}, + {0x942a, 0}, + {0x942b, 1}, + {0x942c, 2}, + {0x942d, 3}, + {0x942e, 8218}, + {0x9430, 0}, + {0x9431, 1}, + {0x9432, 9594}, + {0x9433, 8198}, + {0x9435, 8567}, + {0x9437, 0}, + {0x9438, 9499}, + {0x943a, 9508}, + {0x943c, 0}, + {0x943d, 1}, + {0x943e, 7559}, + {0x943f, 9595}, + {0x9441, 0}, + {0x9442, 1}, + {0x9443, 2}, + {0x9444, 8867}, + {0x9446, 0}, + {0x9447, 1}, + {0x9448, 2}, + {0x9449, 3}, + {0x944a, 9593}, + {0x944c, 9574}, + {0x944e, 0}, + {0x944f, 1}, + {0x9450, 2}, + {0x9451, 3}, + {0x9452, 8083}, + {0x9454, 9596}, + {0x9456, 0}, + {0x9457, 1}, + {0x9458, 2}, + {0x9459, 3}, + {0x945a, 4}, + {0x945b, 5}, + {0x945c, 6}, + {0x945d, 7}, + {0x945e, 8}, + {0x945f, 9}, + {0x9460, 9492}, + {0x9462, 0}, + {0x9463, 9597}, + {0x9465, 9586}, + {0x9467, 0}, + {0x9468, 1}, + {0x9469, 2}, + {0x946a, 3}, + {0x946b, 7560}, + {0x946d, 9588}, + {0x946f, 0}, + {0x9470, 8782}, + {0x9472, 8646}, + {0x9474, 0}, + {0x9475, 1}, + {0x9476, 2}, + {0x9477, 8351}, + {0x9479, 9590}, + {0x947b, 0}, + {0x947c, 8292}, + {0x947d, 8895}, + {0x947e, 9756}, + {0x947f, 8798}, + {0x9481, 0}, + {0x9482, 1}, + {0x9483, 2}, + {0x9484, 3}, + {0x9485, 6798}, + {0x9486, 6799}, + {0x9487, 6800}, + {0x9488, 4492}, + {0x9489, 1507}, + {0x948a, 6802}, + {0x948b, 6801}, + {0x948c, 6803}, + {0x948d, 6804}, + {0x948e, 3106}, + {0x948f, 6805}, + {0x9490, 6806}, + {0x9492, 1613}, + {0x9493, 1495}, + {0x9494, 6807}, + {0x9495, 6809}, + {0x9497, 6808}, + {0x9499, 1729}, + {0x949a, 6810}, + {0x949b, 6811}, + {0x949c, 6812}, + {0x949d, 1562}, + {0x949e, 1235}, + {0x949f, 4562}, + {0x94a0, 2857}, + {0x94a1, 1054}, + {0x94a2, 1745}, + {0x94a3, 6813}, + {0x94a4, 6814}, + {0x94a5, 4354}, + {0x94a6, 3154}, + {0x94a7, 2346}, + {0x94a8, 3816}, + {0x94a9, 1804}, + {0x94aa, 6816}, + {0x94ab, 6815}, + {0x94ac, 6818}, + {0x94ad, 6817}, + {0x94ae, 2918}, + {0x94af, 6819}, + {0x94b0, 6820}, + {0x94b1, 3115}, + {0x94b2, 6821}, + {0x94b3, 3116}, + {0x94b4, 6822}, + {0x94b5, 1134}, + {0x94b6, 6823}, + {0x94b7, 6824}, + {0x94b8, 6825}, + {0x94b9, 6826}, + {0x94ba, 6827}, + {0x94bb, 4679}, + {0x94bc, 6828}, + {0x94bd, 6829}, + {0x94be, 2123}, + {0x94bf, 6830}, + {0x94c0, 4272}, + {0x94c1, 3661}, + {0x94c2, 1139}, + {0x94c3, 2606}, + {0x94c4, 6831}, + {0x94c5, 3107}, + {0x94c6, 2738}, + {0x94c8, 6832}, + {0x94c9, 6833}, + {0x94ca, 6834}, + {0x94cb, 6835}, + {0x94cc, 6836}, + {0x94cd, 6837}, + {0x94ce, 6838}, + {0x94d0, 6839}, + {0x94d1, 6840}, + {0x94d2, 6841}, + {0x94d4, 0}, + {0x94d5, 6842}, + {0x94d6, 6843}, + {0x94d7, 6844}, + {0x94d8, 6846}, + {0x94d9, 6845}, + {0x94db, 6847}, + {0x94dc, 3678}, + {0x94dd, 2664}, + {0x94de, 6848}, + {0x94df, 6849}, + {0x94e0, 6850}, + {0x94e1, 4418}, + {0x94e2, 6851}, + {0x94e3, 3872}, + {0x94e4, 6852}, + {0x94e5, 6853}, + {0x94e7, 6854}, + {0x94e8, 6855}, + {0x94e9, 6857}, + {0x94ea, 6856}, + {0x94eb, 6858}, + {0x94ec, 1776}, + {0x94ed, 2815}, + {0x94ee, 6859}, + {0x94ef, 6860}, + {0x94f0, 2195}, + {0x94f1, 4166}, + {0x94f2, 1216}, + {0x94f3, 6861}, + {0x94f4, 6862}, + {0x94f5, 6863}, + {0x94f6, 4223}, + {0x94f7, 6864}, + {0x94f8, 4604}, + {0x94f9, 6865}, + {0x94fa, 3051}, + {0x94fc, 6866}, + {0x94fd, 6867}, + {0x94fe, 2557}, + {0x94ff, 6868}, + {0x9500, 3943}, + {0x9501, 3565}, + {0x9502, 6870}, + {0x9503, 6869}, + {0x9504, 1311}, + {0x9505, 1873}, + {0x9506, 6871}, + {0x9507, 6872}, + {0x9508, 4013}, + {0x9509, 6873}, + {0x950a, 6874}, + {0x950b, 1667}, + {0x950c, 3978}, + {0x950d, 6875}, + {0x950e, 6876}, + {0x950f, 6877}, + {0x9510, 3276}, + {0x9511, 3635}, + {0x9512, 6878}, + {0x9513, 6879}, + {0x9514, 6880}, + {0x9515, 6881}, + {0x9516, 6882}, + {0x9517, 4481}, + {0x9518, 6883}, + {0x9519, 1392}, + {0x951a, 2735}, + {0x951b, 6884}, + {0x951d, 6885}, + {0x951e, 6886}, + {0x951f, 6887}, + {0x9521, 3852}, + {0x9522, 6888}, + {0x9523, 2695}, + {0x9524, 1339}, + {0x9525, 4627}, + {0x9526, 2246}, + {0x9528, 3892}, + {0x9529, 6891}, + {0x952a, 6889}, + {0x952b, 6890}, + {0x952c, 6892}, + {0x952d, 1510}, + {0x952e, 2159}, + {0x952f, 2321}, + {0x9530, 2769}, + {0x9531, 6893}, + {0x9532, 6894}, + {0x9534, 6895}, + {0x9535, 6903}, + {0x9536, 6896}, + {0x9537, 6897}, + {0x9538, 6898}, + {0x9539, 3135}, + {0x953a, 6937}, + {0x953b, 1548}, + {0x953c, 6899}, + {0x953e, 6900}, + {0x953f, 6901}, + {0x9540, 1541}, + {0x9541, 2755}, + {0x9542, 6902}, + {0x9544, 6904}, + {0x9545, 6905}, + {0x9546, 6906}, + {0x9547, 4499}, + {0x9549, 6907}, + {0x954a, 2906}, + {0x954c, 6908}, + {0x954d, 2907}, + {0x954e, 6909}, + {0x954f, 6910}, + {0x9550, 1759}, + {0x9551, 1026}, + {0x9552, 6911}, + {0x9553, 6912}, + {0x9554, 6913}, + {0x9556, 6914}, + {0x9557, 6915}, + {0x9558, 6916}, + {0x9559, 6917}, + {0x955b, 6918}, + {0x955c, 2276}, + {0x955d, 6921}, + {0x955e, 6919}, + {0x955f, 6920}, + {0x9561, 6922}, + {0x9562, 6923}, + {0x9563, 2582}, + {0x9564, 6924}, + {0x9565, 6925}, + {0x9566, 6926}, + {0x9567, 6927}, + {0x9568, 6928}, + {0x9569, 6929}, + {0x956a, 6930}, + {0x956b, 6931}, + {0x956c, 6932}, + {0x956d, 2499}, + {0x956f, 6933}, + {0x9570, 2550}, + {0x9571, 6934}, + {0x9572, 6935}, + {0x9573, 6936}, + {0x9575, 0}, + {0x9576, 3919}, + {0x9577, 7797}, + {0x9579, 0}, + {0x957a, 1}, + {0x957b, 2}, + {0x957c, 3}, + {0x957d, 4}, + {0x957e, 5}, + {0x957f, 1225}, + {0x9580, 8317}, + {0x9582, 9151}, + {0x9583, 8467}, + {0x9585, 0}, + {0x9586, 9152}, + {0x9588, 0}, + {0x9589, 7749}, + {0x958b, 8152}, + {0x958c, 9156}, + {0x958e, 9154}, + {0x958f, 8452}, + {0x9591, 8637}, + {0x9593, 8071}, + {0x9594, 9155}, + {0x9596, 0}, + {0x9597, 1}, + {0x9598, 8809}, + {0x959a, 0}, + {0x959b, 1}, + {0x959c, 2}, + {0x959d, 3}, + {0x959e, 4}, + {0x959f, 5}, + {0x95a0, 6}, + {0x95a1, 8003}, + {0x95a3, 7966}, + {0x95a4, 9849}, + {0x95a5, 7915}, + {0x95a7, 0}, + {0x95a8, 7989}, + {0x95a9, 8330}, + {0x95ab, 9159}, + {0x95ac, 9161}, + {0x95ad, 9158}, + {0x95af, 0}, + {0x95b0, 1}, + {0x95b1, 2}, + {0x95b2, 8783}, + {0x95b4, 0}, + {0x95b5, 1}, + {0x95b6, 9163}, + {0x95b8, 0}, + {0x95b9, 8691}, + {0x95bb, 8695}, + {0x95bc, 9167}, + {0x95bd, 9166}, + {0x95be, 9162}, + {0x95bf, 9165}, + {0x95c1, 0}, + {0x95c2, 1}, + {0x95c3, 9168}, + {0x95c5, 0}, + {0x95c6, 9836}, + {0x95c8, 9153}, + {0x95ca, 8174}, + {0x95cb, 9169}, + {0x95cc, 8184}, + {0x95ce, 0}, + {0x95cf, 1}, + {0x95d0, 9171}, + {0x95d2, 0}, + {0x95d3, 1}, + {0x95d4, 9170}, + {0x95d5, 9172}, + {0x95d6, 7832}, + {0x95d8, 0}, + {0x95d9, 1}, + {0x95da, 2}, + {0x95db, 3}, + {0x95dc, 7980}, + {0x95de, 9173}, + {0x95e0, 0}, + {0x95e1, 7793}, + {0x95e2, 9873}, + {0x95e4, 0}, + {0x95e5, 9157}, + {0x95e7, 0}, + {0x95e8, 2762}, + {0x95e9, 5765}, + {0x95ea, 3322}, + {0x95eb, 5766}, + {0x95ed, 1086}, + {0x95ee, 3801}, + {0x95ef, 1334}, + {0x95f0, 3277}, + {0x95f1, 5767}, + {0x95f2, 3901}, + {0x95f3, 5768}, + {0x95f4, 2135}, + {0x95f5, 5769}, + {0x95f6, 5770}, + {0x95f7, 2763}, + {0x95f8, 4419}, + {0x95f9, 2873}, + {0x95fa, 1860}, + {0x95fb, 3796}, + {0x95fc, 5771}, + {0x95fd, 2811}, + {0x95fe, 5772}, + {0x9600, 1604}, + {0x9601, 1774}, + {0x9602, 1929}, + {0x9603, 5773}, + {0x9604, 5774}, + {0x9605, 4359}, + {0x9606, 5775}, + {0x9608, 5776}, + {0x9609, 4084}, + {0x960a, 5777}, + {0x960b, 5778}, + {0x960c, 5779}, + {0x960d, 5780}, + {0x960e, 4095}, + {0x960f, 5781}, + {0x9610, 1218}, + {0x9611, 2470}, + {0x9612, 5782}, + {0x9614, 2454}, + {0x9615, 5783}, + {0x9616, 5784}, + {0x9617, 5785}, + {0x9619, 5786}, + {0x961a, 5787}, + {0x961c, 1714}, + {0x961d, 4948}, + {0x961f, 1554}, + {0x9621, 4950}, + {0x9622, 4949}, + {0x9624, 0}, + {0x9625, 1}, + {0x9626, 2}, + {0x9627, 3}, + {0x9628, 4}, + {0x9629, 5}, + {0x962a, 4952}, + {0x962c, 0}, + {0x962d, 1}, + {0x962e, 3273}, + {0x9630, 0}, + {0x9631, 4951}, + {0x9632, 1629}, + {0x9633, 4125}, + {0x9634, 4220}, + {0x9635, 4500}, + {0x9636, 2216}, + {0x9638, 0}, + {0x9639, 1}, + {0x963a, 2}, + {0x963b, 4677}, + {0x963c, 4954}, + {0x963d, 4953}, + {0x963f, 941}, + {0x9640, 3716}, + {0x9642, 4955}, + {0x9644, 1720}, + {0x9645, 2109}, + {0x9646, 2660}, + {0x9647, 2635}, + {0x9648, 1255}, + {0x9649, 4956}, + {0x964b, 2641}, + {0x964c, 2835}, + {0x964d, 2182}, + {0x964f, 0}, + {0x9650, 3915}, + {0x9652, 0}, + {0x9653, 1}, + {0x9654, 4957}, + {0x9655, 3323}, + {0x9657, 0}, + {0x9658, 8986}, + {0x965a, 0}, + {0x965b, 1094}, + {0x965d, 8468}, + {0x965f, 4958}, + {0x9661, 1527}, + {0x9662, 4349}, + {0x9663, 8836}, + {0x9664, 1314}, + {0x9666, 0}, + {0x9667, 4959}, + {0x9668, 4364}, + {0x9669, 3906}, + {0x966a, 2980}, + {0x966c, 4960}, + {0x966e, 0}, + {0x966f, 1}, + {0x9670, 8732}, + {0x9672, 4961}, + {0x9673, 7806}, + {0x9674, 4962}, + {0x9675, 2611}, + {0x9676, 3624}, + {0x9677, 3914}, + {0x9678, 8269}, + {0x967a, 0}, + {0x967b, 1}, + {0x967c, 2}, + {0x967d, 8705}, + {0x967f, 0}, + {0x9680, 1}, + {0x9681, 2}, + {0x9682, 3}, + {0x9683, 4}, + {0x9684, 5}, + {0x9685, 4300}, + {0x9686, 2632}, + {0x9688, 4963}, + {0x968a, 7897}, + {0x968b, 3546}, + {0x968d, 4964}, + {0x968e, 8114}, + {0x968f, 3547}, + {0x9690, 4229}, + {0x9692, 0}, + {0x9693, 1}, + {0x9694, 1775}, + {0x9695, 8786}, + {0x9697, 4965}, + {0x9698, 954}, + {0x9699, 3875}, + {0x969b, 8057}, + {0x969c, 4464}, + {0x969e, 0}, + {0x969f, 1}, + {0x96a0, 2}, + {0x96a1, 3}, + {0x96a2, 4}, + {0x96a3, 5}, + {0x96a4, 6}, + {0x96a5, 7}, + {0x96a6, 8}, + {0x96a7, 3554}, + {0x96a8, 8535}, + {0x96aa, 8639}, + {0x96ac, 0}, + {0x96ad, 1}, + {0x96ae, 2}, + {0x96af, 3}, + {0x96b0, 4966}, + {0x96b1, 8735}, + {0x96b3, 5764}, + {0x96b4, 8253}, + {0x96b6, 2542}, + {0x96b8, 8213}, + {0x96b9, 7545}, + {0x96bb, 9893}, + {0x96bc, 7546}, + {0x96bd, 7547}, + {0x96be, 2868}, + {0x96c0, 3219}, + {0x96c1, 4108}, + {0x96c3, 0}, + {0x96c4, 4006}, + {0x96c5, 4078}, + {0x96c6, 2082}, + {0x96c7, 1830}, + {0x96c9, 6940}, + {0x96cb, 0}, + {0x96cc, 1353}, + {0x96cd, 4255}, + {0x96ce, 7548}, + {0x96cf, 1312}, + {0x96d1, 0}, + {0x96d2, 7549}, + {0x96d4, 0}, + {0x96d5, 1490}, + {0x96d6, 8534}, + {0x96d8, 0}, + {0x96d9, 8516}, + {0x96db, 7825}, + {0x96dc, 8791}, + {0x96de, 0}, + {0x96df, 1}, + {0x96e0, 7551}, + {0x96e2, 8202}, + {0x96e3, 8338}, + {0x96e5, 0}, + {0x96e6, 1}, + {0x96e7, 2}, + {0x96e8, 4303}, + {0x96e9, 7521}, + {0x96ea, 4050}, + {0x96ec, 0}, + {0x96ed, 1}, + {0x96ee, 2}, + {0x96ef, 7523}, + {0x96f1, 0}, + {0x96f2, 8784}, + {0x96f3, 7522}, + {0x96f5, 0}, + {0x96f6, 2604}, + {0x96f7, 2498}, + {0x96f9, 1035}, + {0x96fb, 7875}, + {0x96fd, 0}, + {0x96fe, 3836}, + {0x9700, 4019}, + {0x9701, 7525}, + {0x9703, 0}, + {0x9704, 3939}, + {0x9706, 7524}, + {0x9707, 4497}, + {0x9708, 7526}, + {0x9709, 2750}, + {0x970b, 0}, + {0x970c, 1}, + {0x970d, 2057}, + {0x970e, 7528}, + {0x970f, 7527}, + {0x9711, 0}, + {0x9712, 1}, + {0x9713, 2881}, + {0x9715, 0}, + {0x9716, 2593}, + {0x9718, 0}, + {0x9719, 1}, + {0x971a, 2}, + {0x971b, 3}, + {0x971c, 3487}, + {0x971e, 3881}, + {0x9720, 0}, + {0x9721, 1}, + {0x9722, 2}, + {0x9723, 3}, + {0x9724, 4}, + {0x9725, 5}, + {0x9726, 6}, + {0x9727, 8616}, + {0x9729, 0}, + {0x972a, 7529}, + {0x972c, 0}, + {0x972d, 7530}, + {0x972f, 0}, + {0x9730, 7531}, + {0x9732, 2653}, + {0x9734, 0}, + {0x9735, 1}, + {0x9736, 2}, + {0x9737, 3}, + {0x9738, 991}, + {0x9739, 3002}, + {0x973b, 0}, + {0x973c, 1}, + {0x973d, 9741}, + {0x973e, 7532}, + {0x9740, 0}, + {0x9741, 1}, + {0x9742, 9740}, + {0x9744, 9742}, + {0x9746, 0}, + {0x9747, 1}, + {0x9748, 8242}, + {0x974a, 0}, + {0x974b, 1}, + {0x974c, 2}, + {0x974d, 3}, + {0x974e, 4}, + {0x974f, 5}, + {0x9750, 6}, + {0x9751, 7}, + {0x9752, 3165}, + {0x9753, 7520}, + {0x9755, 0}, + {0x9756, 2279}, + {0x9758, 0}, + {0x9759, 2273}, + {0x975a, 9739}, + {0x975b, 1478}, + {0x975d, 0}, + {0x975e, 1636}, + {0x9760, 2380}, + {0x9761, 2775}, + {0x9762, 2795}, + {0x9764, 0}, + {0x9765, 4738}, + {0x9767, 0}, + {0x9768, 8899}, + {0x9769, 1770}, + {0x976b, 0}, + {0x976c, 1}, + {0x976d, 2}, + {0x976e, 3}, + {0x976f, 4}, + {0x9770, 5}, + {0x9771, 6}, + {0x9772, 7}, + {0x9773, 2250}, + {0x9774, 4046}, + {0x9776, 987}, + {0x9778, 0}, + {0x9779, 1}, + {0x977a, 2}, + {0x977b, 3}, + {0x977c, 7624}, + {0x977e, 0}, + {0x977f, 1}, + {0x9780, 2}, + {0x9781, 3}, + {0x9782, 4}, + {0x9783, 5}, + {0x9784, 6}, + {0x9785, 7625}, + {0x9787, 0}, + {0x9788, 1}, + {0x9789, 2}, + {0x978a, 3}, + {0x978b, 3959}, + {0x978d, 955}, + {0x978f, 7971}, + {0x9791, 7626}, + {0x9792, 7627}, + {0x9794, 7628}, + {0x9796, 0}, + {0x9797, 1}, + {0x9798, 3143}, + {0x979a, 0}, + {0x979b, 1}, + {0x979c, 2}, + {0x979d, 3}, + {0x979e, 4}, + {0x979f, 5}, + {0x97a0, 2302}, + {0x97a2, 0}, + {0x97a3, 7631}, + {0x97a5, 0}, + {0x97a6, 9877}, + {0x97a8, 0}, + {0x97a9, 1}, + {0x97aa, 2}, + {0x97ab, 7630}, + {0x97ad, 1095}, + {0x97af, 7629}, + {0x97b1, 0}, + {0x97b2, 7632}, + {0x97b4, 7633}, + {0x97b6, 0}, + {0x97b7, 1}, + {0x97b8, 2}, + {0x97b9, 3}, + {0x97ba, 4}, + {0x97bb, 5}, + {0x97bc, 6}, + {0x97bd, 9822}, + {0x97bf, 0}, + {0x97c0, 1}, + {0x97c1, 2}, + {0x97c2, 3}, + {0x97c3, 9821}, + {0x97c5, 0}, + {0x97c6, 9874}, + {0x97c8, 0}, + {0x97c9, 9823}, + {0x97cb, 8589}, + {0x97cc, 8445}, + {0x97ce, 0}, + {0x97cf, 1}, + {0x97d0, 2}, + {0x97d1, 3}, + {0x97d2, 4}, + {0x97d3, 8000}, + {0x97d5, 0}, + {0x97d6, 1}, + {0x97d7, 2}, + {0x97d8, 3}, + {0x97d9, 9317}, + {0x97db, 0}, + {0x97dc, 9319}, + {0x97de, 9318}, + {0x97e0, 0}, + {0x97e1, 1}, + {0x97e2, 2}, + {0x97e3, 3}, + {0x97e4, 4}, + {0x97e5, 5}, + {0x97e6, 3763}, + {0x97e7, 3240}, + {0x97e9, 1890}, + {0x97ea, 6222}, + {0x97eb, 6223}, + {0x97ec, 6224}, + {0x97ed, 2289}, + {0x97ef, 0}, + {0x97f0, 1}, + {0x97f1, 2}, + {0x97f2, 3}, + {0x97f3, 4219}, + {0x97f5, 4370}, + {0x97f6, 3345}, + {0x97f8, 0}, + {0x97f9, 1}, + {0x97fa, 2}, + {0x97fb, 3}, + {0x97fc, 4}, + {0x97fd, 5}, + {0x97fe, 6}, + {0x97ff, 8649}, + {0x9801, 8713}, + {0x9802, 7881}, + {0x9803, 8425}, + {0x9805, 8650}, + {0x9806, 8518}, + {0x9807, 9669}, + {0x9808, 8668}, + {0x980a, 9310}, + {0x980c, 8527}, + {0x980e, 9670}, + {0x980f, 9671}, + {0x9810, 8769}, + {0x9811, 8586}, + {0x9812, 7727}, + {0x9813, 7900}, + {0x9815, 0}, + {0x9816, 1}, + {0x9817, 8383}, + {0x9818, 8244}, + {0x981a, 0}, + {0x981b, 1}, + {0x981c, 9673}, + {0x981e, 0}, + {0x981f, 1}, + {0x9820, 2}, + {0x9821, 9672}, + {0x9823, 0}, + {0x9824, 8718}, + {0x9826, 9675}, + {0x9828, 0}, + {0x9829, 1}, + {0x982a, 2}, + {0x982b, 3}, + {0x982c, 4}, + {0x982d, 8573}, + {0x982f, 0}, + {0x9830, 8062}, + {0x9832, 0}, + {0x9833, 1}, + {0x9834, 2}, + {0x9835, 3}, + {0x9836, 4}, + {0x9837, 9676}, + {0x9838, 8131}, + {0x983a, 0}, + {0x983b, 8377}, + {0x983d, 8577}, + {0x983f, 0}, + {0x9840, 1}, + {0x9841, 2}, + {0x9842, 3}, + {0x9843, 4}, + {0x9844, 5}, + {0x9845, 6}, + {0x9846, 8154}, + {0x9848, 0}, + {0x9849, 1}, + {0x984a, 2}, + {0x984b, 3}, + {0x984c, 8563}, + {0x984d, 7905}, + {0x984e, 9677}, + {0x9850, 0}, + {0x9851, 1}, + {0x9852, 2}, + {0x9853, 9678}, + {0x9854, 8694}, + {0x9856, 0}, + {0x9857, 1}, + {0x9858, 8779}, + {0x9859, 9681}, + {0x985b, 7872}, + {0x985d, 0}, + {0x985e, 8200}, + {0x9860, 0}, + {0x9861, 1}, + {0x9862, 9680}, + {0x9864, 0}, + {0x9865, 9682}, + {0x9867, 7978}, + {0x9869, 0}, + {0x986a, 1}, + {0x986b, 7794}, + {0x986c, 9683}, + {0x986e, 0}, + {0x986f, 8638}, + {0x9870, 9684}, + {0x9871, 8260}, + {0x9873, 9679}, + {0x9874, 8435}, + {0x9875, 4154}, + {0x9876, 1508}, + {0x9877, 3175}, + {0x9878, 7136}, + {0x9879, 3931}, + {0x987a, 3496}, + {0x987b, 4022}, + {0x987c, 6183}, + {0x987d, 3736}, + {0x987e, 1828}, + {0x987f, 1560}, + {0x9880, 7137}, + {0x9881, 1007}, + {0x9882, 3521}, + {0x9883, 7138}, + {0x9884, 4327}, + {0x9885, 2644}, + {0x9886, 2613}, + {0x9887, 3043}, + {0x9888, 2272}, + {0x9889, 7139}, + {0x988a, 2120}, + {0x988c, 7140}, + {0x988d, 7141}, + {0x988f, 7142}, + {0x9890, 4170}, + {0x9891, 3028}, + {0x9893, 3704}, + {0x9894, 7143}, + {0x9896, 4246}, + {0x9897, 2386}, + {0x9898, 3637}, + {0x989a, 7144}, + {0x989b, 7145}, + {0x989c, 4094}, + {0x989d, 1581}, + {0x989e, 7146}, + {0x989f, 7147}, + {0x98a0, 1472}, + {0x98a1, 7148}, + {0x98a2, 7149}, + {0x98a4, 1219}, + {0x98a5, 7150}, + {0x98a6, 7151}, + {0x98a7, 3202}, + {0x98a8, 7936}, + {0x98aa, 0}, + {0x98ab, 1}, + {0x98ac, 2}, + {0x98ad, 3}, + {0x98ae, 9420}, + {0x98af, 9421}, + {0x98b1, 9880}, + {0x98b3, 9848}, + {0x98b5, 0}, + {0x98b6, 9422}, + {0x98b8, 0}, + {0x98b9, 1}, + {0x98ba, 2}, + {0x98bb, 3}, + {0x98bc, 9423}, + {0x98be, 0}, + {0x98bf, 1}, + {0x98c0, 2}, + {0x98c1, 3}, + {0x98c2, 4}, + {0x98c3, 5}, + {0x98c4, 8376}, + {0x98c6, 9424}, + {0x98c8, 9425}, + {0x98ca, 0}, + {0x98cb, 1}, + {0x98cc, 2}, + {0x98cd, 3}, + {0x98ce, 1668}, + {0x98d0, 0}, + {0x98d1, 6583}, + {0x98d2, 6584}, + {0x98d3, 6585}, + {0x98d5, 6586}, + {0x98d7, 0}, + {0x98d8, 3021}, + {0x98d9, 6587}, + {0x98da, 6588}, + {0x98db, 7924}, + {0x98dd, 0}, + {0x98de, 1638}, + {0x98df, 3402}, + {0x98e0, 9115}, + {0x98e2, 9854}, + {0x98e4, 0}, + {0x98e5, 1}, + {0x98e6, 2}, + {0x98e7, 5658}, + {0x98e8, 7655}, + {0x98e9, 9117}, + {0x98ea, 9119}, + {0x98eb, 9120}, + {0x98ed, 9121}, + {0x98ef, 7921}, + {0x98f1, 0}, + {0x98f2, 8734}, + {0x98f4, 9122}, + {0x98f6, 0}, + {0x98f7, 1}, + {0x98f8, 2}, + {0x98f9, 3}, + {0x98fa, 4}, + {0x98fb, 5}, + {0x98fc, 8523}, + {0x98fd, 7734}, + {0x98fe, 8501}, + {0x9901, 0}, + {0x9902, 1}, + {0x9903, 8109}, + {0x9905, 7763}, + {0x9907, 0}, + {0x9908, 1}, + {0x9909, 9123}, + {0x990a, 8707}, + {0x990c, 7911}, + {0x990d, 7656}, + {0x990f, 0}, + {0x9910, 1172}, + {0x9911, 9124}, + {0x9912, 8343}, + {0x9913, 7908}, + {0x9915, 0}, + {0x9916, 1}, + {0x9917, 2}, + {0x9918, 8760}, + {0x991a, 0}, + {0x991b, 9125}, + {0x991d, 0}, + {0x991e, 8090}, + {0x9920, 0}, + {0x9921, 8643}, + {0x9923, 0}, + {0x9924, 1}, + {0x9925, 2}, + {0x9926, 3}, + {0x9927, 4}, + {0x9928, 7982}, + {0x992a, 0}, + {0x992b, 1}, + {0x992c, 2}, + {0x992d, 3}, + {0x992e, 7657}, + {0x9930, 0}, + {0x9931, 1}, + {0x9932, 2}, + {0x9933, 9116}, + {0x9935, 0}, + {0x9936, 1}, + {0x9937, 9126}, + {0x9939, 0}, + {0x993a, 1}, + {0x993b, 2}, + {0x993c, 9118}, + {0x993e, 8245}, + {0x993f, 9127}, + {0x9941, 0}, + {0x9942, 1}, + {0x9943, 9128}, + {0x9945, 8309}, + {0x9947, 0}, + {0x9948, 9129}, + {0x9949, 9130}, + {0x994a, 9131}, + {0x994b, 8171}, + {0x994c, 9132}, + {0x994e, 0}, + {0x994f, 1}, + {0x9950, 2}, + {0x9951, 8042}, + {0x9952, 8441}, + {0x9954, 7659}, + {0x9955, 7658}, + {0x9957, 9830}, + {0x9959, 0}, + {0x995a, 1}, + {0x995b, 2}, + {0x995c, 9831}, + {0x995e, 7788}, + {0x9960, 0}, + {0x9961, 1}, + {0x9962, 9133}, + {0x9963, 5661}, + {0x9965, 2069}, + {0x9967, 5662}, + {0x9968, 5663}, + {0x9969, 5664}, + {0x996a, 5665}, + {0x996b, 5666}, + {0x996c, 5667}, + {0x996d, 1622}, + {0x996e, 4226}, + {0x996f, 2165}, + {0x9970, 3429}, + {0x9971, 1038}, + {0x9972, 3516}, + {0x9974, 5668}, + {0x9975, 1595}, + {0x9976, 3231}, + {0x9977, 5669}, + {0x9979, 0}, + {0x997a, 2201}, + {0x997c, 1126}, + {0x997d, 5670}, + {0x997f, 1589}, + {0x9980, 5671}, + {0x9981, 2876}, + {0x9983, 0}, + {0x9984, 5672}, + {0x9985, 3911}, + {0x9986, 1846}, + {0x9987, 5673}, + {0x9988, 2444}, + {0x998a, 5674}, + {0x998b, 1213}, + {0x998d, 5675}, + {0x998f, 2620}, + {0x9990, 5676}, + {0x9991, 5677}, + {0x9992, 2719}, + {0x9993, 5678}, + {0x9994, 5679}, + {0x9995, 5680}, + {0x9996, 3438}, + {0x9997, 4718}, + {0x9998, 4857}, + {0x9999, 3920}, + {0x999b, 0}, + {0x999c, 1}, + {0x999d, 2}, + {0x999e, 3}, + {0x999f, 4}, + {0x99a0, 5}, + {0x99a1, 6}, + {0x99a2, 7}, + {0x99a3, 8}, + {0x99a4, 9}, + {0x99a5, 6955}, + {0x99a7, 0}, + {0x99a8, 5086}, + {0x99aa, 0}, + {0x99ab, 1}, + {0x99ac, 8301}, + {0x99ad, 8770}, + {0x99ae, 7938}, + {0x99b0, 0}, + {0x99b1, 8579}, + {0x99b3, 7813}, + {0x99b4, 8681}, + {0x99b6, 0}, + {0x99b7, 1}, + {0x99b8, 2}, + {0x99b9, 3}, + {0x99ba, 4}, + {0x99bb, 5}, + {0x99bc, 6}, + {0x99bd, 7}, + {0x99be, 8}, + {0x99bf, 9}, + {0x99c0, 10}, + {0x99c1, 7767}, + {0x99c3, 0}, + {0x99c4, 1}, + {0x99c5, 2}, + {0x99c6, 3}, + {0x99c7, 4}, + {0x99c8, 5}, + {0x99c9, 6}, + {0x99ca, 7}, + {0x99cb, 8}, + {0x99cc, 9}, + {0x99cd, 10}, + {0x99ce, 11}, + {0x99cf, 12}, + {0x99d0, 8869}, + {0x99d1, 9223}, + {0x99d2, 8138}, + {0x99d4, 9218}, + {0x99d5, 8066}, + {0x99d7, 0}, + {0x99d8, 9224}, + {0x99d9, 9220}, + {0x99db, 8497}, + {0x99dd, 8580}, + {0x99df, 9219}, + {0x99e1, 8302}, + {0x99e2, 9227}, + {0x99e4, 0}, + {0x99e5, 1}, + {0x99e6, 2}, + {0x99e7, 3}, + {0x99e8, 4}, + {0x99e9, 5}, + {0x99ea, 6}, + {0x99eb, 7}, + {0x99ec, 8}, + {0x99ed, 7999}, + {0x99ef, 0}, + {0x99f0, 1}, + {0x99f1, 8295}, + {0x99f3, 0}, + {0x99f4, 1}, + {0x99f5, 2}, + {0x99f6, 3}, + {0x99f7, 4}, + {0x99f8, 5}, + {0x99f9, 6}, + {0x99fa, 7}, + {0x99fb, 8}, + {0x99fc, 9}, + {0x99fd, 10}, + {0x99fe, 11}, + {0x99ff, 8151}, + {0x9a01, 7811}, + {0x9a03, 0}, + {0x9a04, 1}, + {0x9a05, 9231}, + {0x9a07, 0}, + {0x9a08, 1}, + {0x9a09, 2}, + {0x9a0a, 3}, + {0x9a0b, 4}, + {0x9a0c, 5}, + {0x9a0d, 9230}, + {0x9a0e, 8391}, + {0x9a0f, 9229}, + {0x9a11, 0}, + {0x9a12, 1}, + {0x9a13, 2}, + {0x9a14, 3}, + {0x9a15, 4}, + {0x9a16, 9234}, + {0x9a18, 0}, + {0x9a19, 8375}, + {0x9a1b, 0}, + {0x9a1c, 1}, + {0x9a1d, 2}, + {0x9a1e, 3}, + {0x9a1f, 4}, + {0x9a20, 5}, + {0x9a21, 6}, + {0x9a22, 7}, + {0x9a23, 8}, + {0x9a24, 9}, + {0x9a25, 10}, + {0x9a26, 11}, + {0x9a27, 12}, + {0x9a28, 13}, + {0x9a29, 14}, + {0x9a2a, 15}, + {0x9a2b, 9200}, + {0x9a2d, 9233}, + {0x9a2e, 9236}, + {0x9a30, 8560}, + {0x9a32, 0}, + {0x9a33, 1}, + {0x9a34, 2}, + {0x9a35, 3}, + {0x9a36, 9221}, + {0x9a37, 8460}, + {0x9a38, 9237}, + {0x9a3a, 0}, + {0x9a3b, 1}, + {0x9a3c, 2}, + {0x9a3d, 3}, + {0x9a3e, 8294}, + {0x9a40, 9042}, + {0x9a41, 9235}, + {0x9a42, 9232}, + {0x9a43, 9238}, + {0x9a44, 9239}, + {0x9a45, 8433}, + {0x9a47, 0}, + {0x9a48, 1}, + {0x9a49, 2}, + {0x9a4a, 9226}, + {0x9a4c, 0}, + {0x9a4d, 9225}, + {0x9a4f, 9240}, + {0x9a51, 0}, + {0x9a52, 1}, + {0x9a53, 2}, + {0x9a54, 3}, + {0x9a55, 8103}, + {0x9a57, 8700}, + {0x9a59, 0}, + {0x9a5a, 8129}, + {0x9a5b, 9222}, + {0x9a5d, 0}, + {0x9a5e, 1}, + {0x9a5f, 8860}, + {0x9a61, 0}, + {0x9a62, 8270}, + {0x9a64, 9242}, + {0x9a65, 9241}, + {0x9a67, 0}, + {0x9a68, 1}, + {0x9a69, 2}, + {0x9a6a, 9228}, + {0x9a6c, 2708}, + {0x9a6d, 4329}, + {0x9a6e, 3717}, + {0x9a6f, 4058}, + {0x9a70, 1280}, + {0x9a71, 3194}, + {0x9a73, 1148}, + {0x9a74, 2662}, + {0x9a75, 6074}, + {0x9a76, 3410}, + {0x9a77, 6075}, + {0x9a78, 6076}, + {0x9a79, 2307}, + {0x9a7a, 6077}, + {0x9a7b, 4609}, + {0x9a7c, 3718}, + {0x9a7d, 6079}, + {0x9a7e, 2128}, + {0x9a7f, 6078}, + {0x9a80, 6080}, + {0x9a81, 6081}, + {0x9a82, 2709}, + {0x9a84, 2191}, + {0x9a85, 6082}, + {0x9a86, 2701}, + {0x9a87, 1886}, + {0x9a88, 6083}, + {0x9a8a, 6084}, + {0x9a8b, 1271}, + {0x9a8c, 4114}, + {0x9a8e, 0}, + {0x9a8f, 2354}, + {0x9a90, 6085}, + {0x9a91, 3086}, + {0x9a92, 6086}, + {0x9a93, 6087}, + {0x9a95, 0}, + {0x9a96, 6088}, + {0x9a97, 3020}, + {0x9a98, 6089}, + {0x9a9a, 3296}, + {0x9a9b, 6090}, + {0x9a9c, 6091}, + {0x9a9d, 6092}, + {0x9a9e, 5941}, + {0x9a9f, 6093}, + {0x9aa0, 6094}, + {0x9aa1, 2697}, + {0x9aa2, 6095}, + {0x9aa3, 6096}, + {0x9aa4, 4583}, + {0x9aa5, 6097}, + {0x9aa7, 6098}, + {0x9aa8, 1824}, + {0x9aaa, 0}, + {0x9aab, 1}, + {0x9aac, 2}, + {0x9aad, 3}, + {0x9aae, 4}, + {0x9aaf, 7721}, + {0x9ab0, 7635}, + {0x9ab1, 7634}, + {0x9ab3, 0}, + {0x9ab4, 1}, + {0x9ab5, 2}, + {0x9ab6, 7638}, + {0x9ab7, 7636}, + {0x9ab8, 1880}, + {0x9aba, 7639}, + {0x9abc, 7640}, + {0x9abe, 0}, + {0x9abf, 1}, + {0x9ac0, 7642}, + {0x9ac1, 7641}, + {0x9ac2, 7644}, + {0x9ac4, 0}, + {0x9ac5, 7643}, + {0x9ac7, 0}, + {0x9ac8, 1}, + {0x9ac9, 2}, + {0x9aca, 3}, + {0x9acb, 7645}, + {0x9acc, 7646}, + {0x9ace, 0}, + {0x9acf, 9825}, + {0x9ad1, 7647}, + {0x9ad2, 9892}, + {0x9ad3, 3549}, + {0x9ad4, 8564}, + {0x9ad5, 9827}, + {0x9ad6, 9826}, + {0x9ad8, 1754}, + {0x9ada, 0}, + {0x9adb, 1}, + {0x9adc, 2}, + {0x9add, 3}, + {0x9ade, 4}, + {0x9adf, 7660}, + {0x9ae1, 7661}, + {0x9ae3, 0}, + {0x9ae4, 1}, + {0x9ae5, 2}, + {0x9ae6, 7662}, + {0x9ae8, 0}, + {0x9ae9, 1}, + {0x9aea, 2}, + {0x9aeb, 7664}, + {0x9aed, 7666}, + {0x9aee, 9845}, + {0x9aef, 7663}, + {0x9af1, 0}, + {0x9af2, 1}, + {0x9af3, 2}, + {0x9af4, 3}, + {0x9af5, 4}, + {0x9af6, 5}, + {0x9af7, 6}, + {0x9af8, 7}, + {0x9af9, 7667}, + {0x9afb, 7665}, + {0x9afd, 0}, + {0x9afe, 1}, + {0x9aff, 2}, + {0x9b01, 0}, + {0x9b02, 1}, + {0x9b03, 4660}, + {0x9b05, 0}, + {0x9b06, 8524}, + {0x9b08, 7668}, + {0x9b0a, 0}, + {0x9b0b, 1}, + {0x9b0c, 2}, + {0x9b0d, 9850}, + {0x9b0f, 7669}, + {0x9b11, 0}, + {0x9b12, 1}, + {0x9b13, 7670}, + {0x9b15, 0}, + {0x9b16, 1}, + {0x9b17, 2}, + {0x9b18, 3}, + {0x9b19, 4}, + {0x9b1a, 9888}, + {0x9b1c, 0}, + {0x9b1d, 1}, + {0x9b1e, 2}, + {0x9b1f, 7671}, + {0x9b21, 0}, + {0x9b22, 9832}, + {0x9b23, 7672}, + {0x9b25, 7888}, + {0x9b27, 8342}, + {0x9b29, 9164}, + {0x9b2b, 0}, + {0x9b2c, 1}, + {0x9b2d, 2}, + {0x9b2e, 9160}, + {0x9b2f, 5019}, + {0x9b31, 8766}, + {0x9b32, 4704}, + {0x9b34, 0}, + {0x9b35, 1}, + {0x9b36, 2}, + {0x9b37, 3}, + {0x9b38, 4}, + {0x9b39, 5}, + {0x9b3a, 6}, + {0x9b3b, 6003}, + {0x9b3c, 1862}, + {0x9b3e, 0}, + {0x9b3f, 1}, + {0x9b40, 2}, + {0x9b41, 2442}, + {0x9b42, 2047}, + {0x9b43, 7649}, + {0x9b44, 3046}, + {0x9b45, 7648}, + {0x9b47, 7650}, + {0x9b48, 7652}, + {0x9b49, 7651}, + {0x9b4b, 0}, + {0x9b4c, 1}, + {0x9b4d, 7653}, + {0x9b4e, 9829}, + {0x9b4f, 3785}, + {0x9b51, 7654}, + {0x9b53, 0}, + {0x9b54, 2826}, + {0x9b56, 0}, + {0x9b57, 1}, + {0x9b58, 9828}, + {0x9b5a, 8761}, + {0x9b5c, 0}, + {0x9b5d, 1}, + {0x9b5e, 2}, + {0x9b5f, 3}, + {0x9b60, 4}, + {0x9b61, 5}, + {0x9b62, 6}, + {0x9b63, 7}, + {0x9b64, 8}, + {0x9b65, 9}, + {0x9b66, 10}, + {0x9b67, 11}, + {0x9b68, 12}, + {0x9b69, 13}, + {0x9b6a, 14}, + {0x9b6b, 15}, + {0x9b6c, 16}, + {0x9b6d, 17}, + {0x9b6e, 18}, + {0x9b6f, 8266}, + {0x9b71, 0}, + {0x9b72, 1}, + {0x9b73, 2}, + {0x9b74, 9759}, + {0x9b76, 0}, + {0x9b77, 9758}, + {0x9b79, 0}, + {0x9b7a, 1}, + {0x9b7b, 2}, + {0x9b7c, 3}, + {0x9b7d, 4}, + {0x9b7e, 5}, + {0x9b7f, 6}, + {0x9b80, 7}, + {0x9b81, 9760}, + {0x9b83, 9761}, + {0x9b85, 0}, + {0x9b86, 1}, + {0x9b87, 2}, + {0x9b88, 3}, + {0x9b89, 4}, + {0x9b8a, 5}, + {0x9b8b, 6}, + {0x9b8c, 7}, + {0x9b8d, 8}, + {0x9b8e, 9762}, + {0x9b90, 9767}, + {0x9b91, 7737}, + {0x9b92, 9765}, + {0x9b94, 0}, + {0x9b95, 1}, + {0x9b96, 2}, + {0x9b97, 3}, + {0x9b98, 4}, + {0x9b99, 5}, + {0x9b9a, 9769}, + {0x9b9c, 0}, + {0x9b9d, 9774}, + {0x9b9e, 9771}, + {0x9ba0, 0}, + {0x9ba1, 1}, + {0x9ba2, 2}, + {0x9ba3, 3}, + {0x9ba4, 4}, + {0x9ba5, 5}, + {0x9ba6, 6}, + {0x9ba7, 7}, + {0x9ba8, 8}, + {0x9ba9, 9}, + {0x9baa, 9770}, + {0x9bab, 9773}, + {0x9bad, 9768}, + {0x9bae, 8633}, + {0x9bb0, 0}, + {0x9bb1, 1}, + {0x9bb2, 2}, + {0x9bb3, 3}, + {0x9bb4, 4}, + {0x9bb5, 5}, + {0x9bb6, 6}, + {0x9bb7, 7}, + {0x9bb8, 8}, + {0x9bb9, 9}, + {0x9bba, 10}, + {0x9bbb, 11}, + {0x9bbc, 12}, + {0x9bbd, 13}, + {0x9bbe, 14}, + {0x9bbf, 15}, + {0x9bc0, 9782}, + {0x9bc1, 9776}, + {0x9bc3, 0}, + {0x9bc4, 1}, + {0x9bc5, 2}, + {0x9bc6, 3}, + {0x9bc7, 9784}, + {0x9bc9, 8205}, + {0x9bca, 9783}, + {0x9bcc, 0}, + {0x9bcd, 1}, + {0x9bce, 2}, + {0x9bcf, 3}, + {0x9bd0, 4}, + {0x9bd1, 5}, + {0x9bd2, 6}, + {0x9bd3, 7}, + {0x9bd4, 9797}, + {0x9bd6, 9786}, + {0x9bd8, 0}, + {0x9bd9, 1}, + {0x9bda, 2}, + {0x9bdb, 9795}, + {0x9bdd, 9792}, + {0x9bdf, 0}, + {0x9be0, 1}, + {0x9be1, 9789}, + {0x9be2, 9793}, + {0x9be4, 9790}, + {0x9be6, 0}, + {0x9be7, 9791}, + {0x9be8, 8128}, + {0x9bea, 9787}, + {0x9beb, 9788}, + {0x9bed, 0}, + {0x9bee, 1}, + {0x9bef, 2}, + {0x9bf0, 9794}, + {0x9bf2, 0}, + {0x9bf3, 1}, + {0x9bf4, 9796}, + {0x9bf6, 0}, + {0x9bf7, 1}, + {0x9bf8, 2}, + {0x9bf9, 3}, + {0x9bfa, 4}, + {0x9bfb, 5}, + {0x9bfc, 6}, + {0x9bfd, 9785}, + {0x9bff, 9804}, + {0x9c01, 0}, + {0x9c02, 1}, + {0x9c03, 2}, + {0x9c04, 3}, + {0x9c05, 4}, + {0x9c06, 5}, + {0x9c07, 6}, + {0x9c08, 9799}, + {0x9c09, 9803}, + {0x9c0b, 0}, + {0x9c0c, 1}, + {0x9c0d, 9801}, + {0x9c0f, 0}, + {0x9c10, 9800}, + {0x9c12, 9802}, + {0x9c13, 8456}, + {0x9c15, 0}, + {0x9c16, 1}, + {0x9c17, 2}, + {0x9c18, 3}, + {0x9c19, 4}, + {0x9c1a, 5}, + {0x9c1b, 6}, + {0x9c1c, 7}, + {0x9c1d, 8}, + {0x9c1e, 9}, + {0x9c1f, 10}, + {0x9c20, 9805}, + {0x9c22, 0}, + {0x9c23, 9780}, + {0x9c25, 9809}, + {0x9c27, 0}, + {0x9c28, 9808}, + {0x9c29, 9810}, + {0x9c2b, 0}, + {0x9c2c, 1}, + {0x9c2d, 9807}, + {0x9c2f, 0}, + {0x9c30, 1}, + {0x9c31, 9778}, + {0x9c32, 9806}, + {0x9c33, 9811}, + {0x9c35, 9815}, + {0x9c37, 9781}, + {0x9c39, 9779}, + {0x9c3b, 9814}, + {0x9c3d, 0}, + {0x9c3e, 9812}, + {0x9c40, 0}, + {0x9c41, 1}, + {0x9c42, 2}, + {0x9c43, 3}, + {0x9c44, 4}, + {0x9c45, 9816}, + {0x9c47, 0}, + {0x9c48, 9813}, + {0x9c49, 7757}, + {0x9c4b, 0}, + {0x9c4c, 1}, + {0x9c4d, 2}, + {0x9c4e, 3}, + {0x9c4f, 4}, + {0x9c50, 5}, + {0x9c51, 6}, + {0x9c52, 9819}, + {0x9c54, 9818}, + {0x9c56, 9817}, + {0x9c57, 8238}, + {0x9c58, 9775}, + {0x9c5a, 0}, + {0x9c5b, 1}, + {0x9c5c, 2}, + {0x9c5d, 9798}, + {0x9c5f, 9766}, + {0x9c61, 0}, + {0x9c62, 1}, + {0x9c63, 2}, + {0x9c64, 3}, + {0x9c65, 4}, + {0x9c66, 5}, + {0x9c67, 9820}, + {0x9c69, 0}, + {0x9c6a, 1}, + {0x9c6b, 2}, + {0x9c6c, 3}, + {0x9c6d, 9772}, + {0x9c6f, 0}, + {0x9c70, 1}, + {0x9c71, 2}, + {0x9c72, 3}, + {0x9c73, 4}, + {0x9c74, 5}, + {0x9c75, 6}, + {0x9c76, 7}, + {0x9c77, 8}, + {0x9c78, 9763}, + {0x9c7a, 9777}, + {0x9c7c, 4296}, + {0x9c7e, 0}, + {0x9c7f, 7561}, + {0x9c81, 2650}, + {0x9c82, 7562}, + {0x9c84, 0}, + {0x9c85, 7563}, + {0x9c86, 7564}, + {0x9c87, 7565}, + {0x9c88, 7566}, + {0x9c8a, 0}, + {0x9c8b, 7568}, + {0x9c8d, 1044}, + {0x9c8e, 7569}, + {0x9c90, 7570}, + {0x9c91, 7571}, + {0x9c92, 7572}, + {0x9c94, 7573}, + {0x9c95, 7574}, + {0x9c97, 0}, + {0x9c98, 1}, + {0x9c99, 2}, + {0x9c9a, 7575}, + {0x9c9b, 7576}, + {0x9c9c, 3895}, + {0x9c9e, 7577}, + {0x9c9f, 7578}, + {0x9ca0, 7579}, + {0x9ca1, 7580}, + {0x9ca2, 7581}, + {0x9ca3, 7582}, + {0x9ca4, 2523}, + {0x9ca5, 7583}, + {0x9ca6, 7584}, + {0x9ca7, 7585}, + {0x9ca8, 7586}, + {0x9ca9, 7587}, + {0x9cab, 7588}, + {0x9cad, 7589}, + {0x9cae, 7590}, + {0x9cb0, 7591}, + {0x9cb1, 7592}, + {0x9cb2, 7593}, + {0x9cb3, 7594}, + {0x9cb4, 7595}, + {0x9cb5, 7596}, + {0x9cb6, 7597}, + {0x9cb7, 7598}, + {0x9cb8, 2263}, + {0x9cba, 7599}, + {0x9cbb, 7600}, + {0x9cbc, 7601}, + {0x9cbd, 7602}, + {0x9cbf, 0}, + {0x9cc0, 1}, + {0x9cc1, 2}, + {0x9cc2, 3}, + {0x9cc3, 3285}, + {0x9cc4, 7603}, + {0x9cc5, 7604}, + {0x9cc6, 7605}, + {0x9cc7, 7606}, + {0x9cc9, 0}, + {0x9cca, 7607}, + {0x9ccb, 7608}, + {0x9ccc, 7609}, + {0x9ccd, 7610}, + {0x9cce, 7611}, + {0x9ccf, 7612}, + {0x9cd0, 7613}, + {0x9cd2, 0}, + {0x9cd3, 7614}, + {0x9cd4, 7615}, + {0x9cd5, 7616}, + {0x9cd6, 1111}, + {0x9cd7, 7617}, + {0x9cd8, 7618}, + {0x9cd9, 7619}, + {0x9cdb, 0}, + {0x9cdc, 7620}, + {0x9cdd, 7621}, + {0x9cde, 2596}, + {0x9cdf, 7622}, + {0x9ce1, 0}, + {0x9ce2, 7623}, + {0x9ce4, 0}, + {0x9ce5, 8348}, + {0x9ce7, 0}, + {0x9ce8, 1}, + {0x9ce9, 9600}, + {0x9ceb, 0}, + {0x9cec, 8924}, + {0x9cee, 0}, + {0x9cef, 1}, + {0x9cf0, 2}, + {0x9cf1, 3}, + {0x9cf2, 4}, + {0x9cf3, 7941}, + {0x9cf4, 8331}, + {0x9cf6, 9601}, + {0x9cf8, 0}, + {0x9cf9, 1}, + {0x9cfa, 2}, + {0x9cfb, 3}, + {0x9cfc, 4}, + {0x9cfd, 5}, + {0x9cfe, 6}, + {0x9cff, 7}, + {0x9d01, 0}, + {0x9d02, 1}, + {0x9d03, 2}, + {0x9d04, 3}, + {0x9d05, 4}, + {0x9d06, 9603}, + {0x9d07, 9602}, + {0x9d09, 8686}, + {0x9d0b, 0}, + {0x9d0c, 1}, + {0x9d0d, 2}, + {0x9d0e, 3}, + {0x9d0f, 4}, + {0x9d10, 5}, + {0x9d11, 6}, + {0x9d12, 7}, + {0x9d13, 8}, + {0x9d14, 9}, + {0x9d15, 8578}, + {0x9d17, 0}, + {0x9d18, 1}, + {0x9d19, 2}, + {0x9d1a, 3}, + {0x9d1b, 8771}, + {0x9d1d, 9607}, + {0x9d1f, 9608}, + {0x9d21, 0}, + {0x9d22, 1}, + {0x9d23, 9604}, + {0x9d25, 0}, + {0x9d26, 8701}, + {0x9d28, 8687}, + {0x9d2a, 0}, + {0x9d2b, 1}, + {0x9d2c, 2}, + {0x9d2d, 3}, + {0x9d2e, 4}, + {0x9d2f, 9610}, + {0x9d30, 9612}, + {0x9d32, 0}, + {0x9d33, 1}, + {0x9d34, 2}, + {0x9d35, 3}, + {0x9d36, 4}, + {0x9d37, 5}, + {0x9d38, 6}, + {0x9d39, 7}, + {0x9d3a, 8}, + {0x9d3b, 8007}, + {0x9d3d, 0}, + {0x9d3e, 1}, + {0x9d3f, 7965}, + {0x9d41, 0}, + {0x9d42, 9613}, + {0x9d44, 0}, + {0x9d45, 1}, + {0x9d46, 2}, + {0x9d47, 3}, + {0x9d48, 4}, + {0x9d49, 5}, + {0x9d4a, 6}, + {0x9d4b, 7}, + {0x9d4c, 8}, + {0x9d4d, 9}, + {0x9d4e, 10}, + {0x9d4f, 11}, + {0x9d50, 12}, + {0x9d51, 8144}, + {0x9d52, 9618}, + {0x9d53, 9615}, + {0x9d55, 0}, + {0x9d56, 1}, + {0x9d57, 2}, + {0x9d58, 3}, + {0x9d59, 4}, + {0x9d5a, 5}, + {0x9d5b, 6}, + {0x9d5c, 9620}, + {0x9d5d, 7904}, + {0x9d5f, 0}, + {0x9d60, 9617}, + {0x9d61, 9621}, + {0x9d63, 0}, + {0x9d64, 1}, + {0x9d65, 2}, + {0x9d66, 3}, + {0x9d67, 4}, + {0x9d68, 5}, + {0x9d69, 6}, + {0x9d6a, 9623}, + {0x9d6c, 8374}, + {0x9d6e, 0}, + {0x9d6f, 9624}, + {0x9d71, 0}, + {0x9d72, 8438}, + {0x9d74, 0}, + {0x9d75, 1}, + {0x9d76, 2}, + {0x9d77, 3}, + {0x9d78, 4}, + {0x9d79, 5}, + {0x9d7a, 6}, + {0x9d7b, 7}, + {0x9d7c, 8}, + {0x9d7d, 9}, + {0x9d7e, 10}, + {0x9d7f, 11}, + {0x9d80, 12}, + {0x9d81, 13}, + {0x9d82, 14}, + {0x9d83, 15}, + {0x9d84, 16}, + {0x9d85, 17}, + {0x9d86, 18}, + {0x9d87, 9605}, + {0x9d89, 9625}, + {0x9d8b, 0}, + {0x9d8c, 1}, + {0x9d8d, 2}, + {0x9d8e, 3}, + {0x9d8f, 4}, + {0x9d90, 5}, + {0x9d91, 6}, + {0x9d92, 7}, + {0x9d93, 9622}, + {0x9d95, 0}, + {0x9d96, 1}, + {0x9d97, 2}, + {0x9d98, 9626}, + {0x9d9a, 9627}, + {0x9d9c, 0}, + {0x9d9d, 1}, + {0x9d9e, 2}, + {0x9d9f, 3}, + {0x9da0, 4}, + {0x9da1, 5}, + {0x9da2, 6}, + {0x9da3, 7}, + {0x9da4, 8}, + {0x9da5, 9629}, + {0x9da7, 0}, + {0x9da8, 1}, + {0x9da9, 9630}, + {0x9dab, 0}, + {0x9dac, 1}, + {0x9dad, 2}, + {0x9dae, 3}, + {0x9daf, 9036}, + {0x9db1, 0}, + {0x9db2, 1}, + {0x9db3, 2}, + {0x9db4, 8004}, + {0x9db6, 0}, + {0x9db7, 1}, + {0x9db8, 2}, + {0x9db9, 3}, + {0x9dba, 4}, + {0x9dbb, 9824}, + {0x9dbc, 9632}, + {0x9dbe, 0}, + {0x9dbf, 1}, + {0x9dc0, 9628}, + {0x9dc2, 9631}, + {0x9dc4, 8044}, + {0x9dc6, 0}, + {0x9dc7, 1}, + {0x9dc8, 2}, + {0x9dc9, 3}, + {0x9dca, 4}, + {0x9dcb, 5}, + {0x9dcc, 6}, + {0x9dcd, 7}, + {0x9dce, 8}, + {0x9dcf, 9}, + {0x9dd0, 10}, + {0x9dd1, 11}, + {0x9dd2, 12}, + {0x9dd3, 9634}, + {0x9dd5, 0}, + {0x9dd6, 1}, + {0x9dd7, 8366}, + {0x9dd9, 9611}, + {0x9dda, 9635}, + {0x9ddc, 0}, + {0x9ddd, 1}, + {0x9dde, 2}, + {0x9ddf, 3}, + {0x9de0, 4}, + {0x9de1, 5}, + {0x9de2, 6}, + {0x9de3, 7}, + {0x9de4, 8}, + {0x9de5, 9609}, + {0x9de6, 9637}, + {0x9de8, 0}, + {0x9de9, 1}, + {0x9dea, 2}, + {0x9deb, 3}, + {0x9dec, 4}, + {0x9ded, 5}, + {0x9dee, 6}, + {0x9def, 9636}, + {0x9df1, 0}, + {0x9df2, 9638}, + {0x9df3, 9619}, + {0x9df5, 0}, + {0x9df6, 1}, + {0x9df7, 2}, + {0x9df8, 9639}, + {0x9df9, 8738}, + {0x9dfa, 9641}, + {0x9dfc, 0}, + {0x9dfd, 1}, + {0x9dfe, 2}, + {0x9dff, 3}, + {0x9e01, 0}, + {0x9e02, 1}, + {0x9e03, 2}, + {0x9e04, 3}, + {0x9e05, 4}, + {0x9e06, 5}, + {0x9e07, 6}, + {0x9e08, 7}, + {0x9e09, 8}, + {0x9e0a, 9}, + {0x9e0b, 10}, + {0x9e0c, 9640}, + {0x9e0e, 0}, + {0x9e0f, 1}, + {0x9e10, 2}, + {0x9e11, 3}, + {0x9e12, 4}, + {0x9e13, 5}, + {0x9e14, 6}, + {0x9e15, 9606}, + {0x9e17, 0}, + {0x9e18, 1}, + {0x9e19, 2}, + {0x9e1a, 9633}, + {0x9e1b, 9642}, + {0x9e1d, 9616}, + {0x9e1e, 9614}, + {0x9e1f, 2900}, + {0x9e20, 6965}, + {0x9e21, 2073}, + {0x9e22, 6966}, + {0x9e23, 2814}, + {0x9e25, 2937}, + {0x9e26, 4068}, + {0x9e28, 6967}, + {0x9e29, 6968}, + {0x9e2a, 6969}, + {0x9e2b, 6970}, + {0x9e2c, 6971}, + {0x9e2d, 4069}, + {0x9e2f, 4117}, + {0x9e31, 6973}, + {0x9e32, 6972}, + {0x9e33, 4330}, + {0x9e35, 3715}, + {0x9e36, 6974}, + {0x9e37, 6976}, + {0x9e38, 6975}, + {0x9e39, 6977}, + {0x9e3a, 6978}, + {0x9e3c, 0}, + {0x9e3d, 1766}, + {0x9e3e, 6979}, + {0x9e3f, 1951}, + {0x9e41, 6980}, + {0x9e42, 6981}, + {0x9e43, 2328}, + {0x9e44, 6982}, + {0x9e45, 1579}, + {0x9e46, 6983}, + {0x9e47, 6984}, + {0x9e48, 6985}, + {0x9e49, 6986}, + {0x9e4a, 3216}, + {0x9e4b, 6987}, + {0x9e4c, 6988}, + {0x9e4e, 6989}, + {0x9e4f, 2997}, + {0x9e51, 6990}, + {0x9e53, 0}, + {0x9e54, 1}, + {0x9e55, 6991}, + {0x9e57, 6992}, + {0x9e58, 7637}, + {0x9e5a, 6993}, + {0x9e5b, 6994}, + {0x9e5c, 6995}, + {0x9e5e, 6996}, + {0x9e60, 0}, + {0x9e61, 1}, + {0x9e62, 2}, + {0x9e63, 6997}, + {0x9e64, 1934}, + {0x9e66, 6998}, + {0x9e67, 6999}, + {0x9e68, 7000}, + {0x9e69, 7001}, + {0x9e6a, 7002}, + {0x9e6b, 7003}, + {0x9e6c, 7004}, + {0x9e6d, 7006}, + {0x9e6f, 0}, + {0x9e70, 4234}, + {0x9e71, 7005}, + {0x9e73, 7007}, + {0x9e75, 9864}, + {0x9e77, 0}, + {0x9e78, 1}, + {0x9e79, 9886}, + {0x9e7a, 9723}, + {0x9e7c, 8076}, + {0x9e7d, 8692}, + {0x9e7e, 7446}, + {0x9e7f, 2656}, + {0x9e81, 0}, + {0x9e82, 7676}, + {0x9e84, 0}, + {0x9e85, 1}, + {0x9e86, 2}, + {0x9e87, 7677}, + {0x9e88, 7678}, + {0x9e8a, 0}, + {0x9e8b, 7679}, + {0x9e8d, 0}, + {0x9e8e, 1}, + {0x9e8f, 2}, + {0x9e90, 3}, + {0x9e91, 4}, + {0x9e92, 7680}, + {0x9e93, 2651}, + {0x9e95, 0}, + {0x9e96, 1}, + {0x9e97, 8207}, + {0x9e99, 0}, + {0x9e9a, 1}, + {0x9e9b, 2}, + {0x9e9c, 3}, + {0x9e9d, 7682}, + {0x9e9f, 7683}, + {0x9ea1, 0}, + {0x9ea2, 1}, + {0x9ea3, 2}, + {0x9ea4, 3}, + {0x9ea5, 8305}, + {0x9ea6, 2714}, + {0x9ea8, 0}, + {0x9ea9, 9719}, + {0x9eab, 0}, + {0x9eac, 1}, + {0x9ead, 2}, + {0x9eae, 3}, + {0x9eaf, 9878}, + {0x9eb1, 0}, + {0x9eb2, 1}, + {0x9eb3, 2}, + {0x9eb4, 7406}, + {0x9eb5, 9871}, + {0x9eb7, 0}, + {0x9eb8, 7405}, + {0x9eba, 0}, + {0x9ebb, 2704}, + {0x9ebd, 7673}, + {0x9ebe, 7674}, + {0x9ec0, 0}, + {0x9ec1, 1}, + {0x9ec2, 2}, + {0x9ec3, 3}, + {0x9ec4, 2011}, + {0x9ec6, 0}, + {0x9ec7, 1}, + {0x9ec8, 2}, + {0x9ec9, 4856}, + {0x9ecb, 0}, + {0x9ecc, 8922}, + {0x9ecd, 3465}, + {0x9ece, 2515}, + {0x9ecf, 6954}, + {0x9ed1, 1937}, + {0x9ed3, 0}, + {0x9ed4, 3114}, + {0x9ed6, 0}, + {0x9ed7, 1}, + {0x9ed8, 2831}, + {0x9eda, 0}, + {0x9edb, 7684}, + {0x9edc, 7685}, + {0x9edd, 7686}, + {0x9ede, 7873}, + {0x9edf, 7688}, + {0x9ee0, 7687}, + {0x9ee2, 7689}, + {0x9ee4, 0}, + {0x9ee5, 7692}, + {0x9ee7, 7691}, + {0x9ee8, 7859}, + {0x9ee9, 7690}, + {0x9eea, 7693}, + {0x9eec, 0}, + {0x9eed, 1}, + {0x9eee, 2}, + {0x9eef, 7694}, + {0x9ef1, 0}, + {0x9ef2, 9834}, + {0x9ef4, 9866}, + {0x9ef6, 0}, + {0x9ef7, 9833}, + {0x9ef9, 6741}, + {0x9efb, 6742}, + {0x9efc, 6743}, + {0x9efd, 9752}, + {0x9efe, 7542}, + {0x9eff, 9753}, + {0x9f01, 0}, + {0x9f02, 1}, + {0x9f03, 2}, + {0x9f04, 3}, + {0x9f05, 4}, + {0x9f06, 5}, + {0x9f07, 6}, + {0x9f08, 7}, + {0x9f09, 9754}, + {0x9f0b, 7543}, + {0x9f0d, 7544}, + {0x9f0e, 1509}, + {0x9f10, 4724}, + {0x9f12, 0}, + {0x9f13, 1821}, + {0x9f15, 9843}, + {0x9f17, 4721}, + {0x9f19, 5087}, + {0x9f1b, 0}, + {0x9f1c, 1}, + {0x9f1d, 2}, + {0x9f1e, 3}, + {0x9f1f, 4}, + {0x9f20, 3466}, + {0x9f22, 7695}, + {0x9f24, 0}, + {0x9f25, 1}, + {0x9f26, 2}, + {0x9f27, 3}, + {0x9f28, 4}, + {0x9f29, 5}, + {0x9f2a, 6}, + {0x9f2b, 7}, + {0x9f2c, 7696}, + {0x9f2e, 0}, + {0x9f2f, 7697}, + {0x9f31, 0}, + {0x9f32, 1}, + {0x9f33, 2}, + {0x9f34, 3}, + {0x9f35, 4}, + {0x9f36, 5}, + {0x9f37, 7699}, + {0x9f39, 7698}, + {0x9f3b, 1072}, + {0x9f3d, 7700}, + {0x9f3e, 7701}, + {0x9f40, 0}, + {0x9f41, 1}, + {0x9f42, 2}, + {0x9f43, 3}, + {0x9f44, 7702}, + {0x9f46, 0}, + {0x9f47, 1}, + {0x9f48, 2}, + {0x9f49, 3}, + {0x9f4a, 8390}, + {0x9f4b, 8811}, + {0x9f4d, 0}, + {0x9f4e, 1}, + {0x9f4f, 9427}, + {0x9f50, 3082}, + {0x9f51, 6594}, + {0x9f52, 7814}, + {0x9f54, 9743}, + {0x9f56, 0}, + {0x9f57, 1}, + {0x9f58, 2}, + {0x9f59, 9745}, + {0x9f5b, 0}, + {0x9f5c, 9747}, + {0x9f5e, 0}, + {0x9f5f, 9744}, + {0x9f60, 9746}, + {0x9f61, 8240}, + {0x9f63, 9841}, + {0x9f65, 0}, + {0x9f66, 9748}, + {0x9f68, 0}, + {0x9f69, 1}, + {0x9f6a, 9750}, + {0x9f6c, 9749}, + {0x9f6e, 0}, + {0x9f6f, 1}, + {0x9f70, 2}, + {0x9f71, 3}, + {0x9f72, 8434}, + {0x9f74, 0}, + {0x9f75, 1}, + {0x9f76, 2}, + {0x9f77, 9751}, + {0x9f79, 0}, + {0x9f7a, 1}, + {0x9f7b, 2}, + {0x9f7c, 3}, + {0x9f7d, 4}, + {0x9f7e, 5}, + {0x9f7f, 1282}, + {0x9f80, 7533}, + {0x9f82, 0}, + {0x9f83, 7534}, + {0x9f84, 2605}, + {0x9f85, 7535}, + {0x9f86, 7536}, + {0x9f87, 7537}, + {0x9f88, 7538}, + {0x9f89, 7539}, + {0x9f8a, 7540}, + {0x9f8b, 3198}, + {0x9f8c, 7541}, + {0x9f8d, 8247}, + {0x9f8f, 0}, + {0x9f90, 8371}, + {0x9f92, 0}, + {0x9f93, 1}, + {0x9f94, 7970}, + {0x9f95, 9453}, + {0x9f97, 0}, + {0x9f98, 1}, + {0x9f99, 2627}, + {0x9f9a, 1793}, + {0x9f9b, 6740}, + {0x9f9c, 7988}, + {0x9f9e, 0}, + {0x9f9f, 1859}, + {0x9fa0, 4851}, + {0x9fa2, 0}, + {0x9fa3, 1}, + {0x9fa4, 2}, + {0x9fa5, 3}, + {0xe817, 0}, + {0xe818, 1}, + {0xe82c, 0}, + {0xe832, 0}, + {0xe855, 0}, + {0xfa0e, 0}, + {0xfa0f, 1}, + {0xfa14, 0}, + {0xfa20, 0}, + {0xfa21, 1}, + {0xfa24, 0}, + {0xfa28, 0}, + {0xfa29, 1}, + {0xfe4a, 0}, + {0xfe4b, 1}, + {0xfe4c, 2}, + {0xfe4d, 3}, + {0xfe4e, 4}, + {0xfe4f, 5}, + {0xfe50, 6}, + {0xfe51, 7}, + {0xfe52, 8}, + {0xfe55, 0}, + {0xfe56, 1}, + {0xfe57, 2}, + {0xfe5a, 0}, + {0xfe5b, 1}, + {0xfe5c, 2}, + {0xfe5d, 3}, + {0xfe5e, 4}, + {0xfe5f, 5}, + {0xfe60, 6}, + {0xfe61, 7}, + {0xfe62, 8}, + {0xfe63, 9}, + {0xfe64, 10}, + {0xfe65, 11}, + {0xfe66, 12}, + {0xfe69, 0}, + {0xfe6a, 1}, + {0xfe6b, 2}, + {0xff01, 262}, + {0xff02, 263}, + {0xff03, 264}, + {0xff04, 166}, + {0xff05, 266}, + {0xff06, 267}, + {0xff07, 268}, + {0xff08, 269}, + {0xff09, 270}, + {0xff0a, 271}, + {0xff0b, 272}, + {0xff0c, 273}, + {0xff0d, 274}, + {0xff0e, 275}, + {0xff0f, 276}, + {0xff10, 277}, + {0xff11, 278}, + {0xff12, 279}, + {0xff13, 280}, + {0xff14, 281}, + {0xff15, 282}, + {0xff16, 283}, + {0xff17, 284}, + {0xff18, 285}, + {0xff19, 286}, + {0xff1a, 287}, + {0xff1b, 288}, + {0xff1c, 289}, + {0xff1d, 290}, + {0xff1e, 291}, + {0xff1f, 292}, + {0xff20, 293}, + {0xff21, 294}, + {0xff22, 295}, + {0xff23, 296}, + {0xff24, 297}, + {0xff25, 298}, + {0xff26, 299}, + {0xff27, 300}, + {0xff28, 301}, + {0xff29, 302}, + {0xff2a, 303}, + {0xff2b, 304}, + {0xff2c, 305}, + {0xff2d, 306}, + {0xff2e, 307}, + {0xff2f, 308}, + {0xff30, 309}, + {0xff31, 310}, + {0xff32, 311}, + {0xff33, 312}, + {0xff34, 313}, + {0xff35, 314}, + {0xff36, 315}, + {0xff37, 316}, + {0xff38, 317}, + {0xff39, 318}, + {0xff3a, 319}, + {0xff3b, 320}, + {0xff3c, 321}, + {0xff3d, 322}, + {0xff3e, 323}, + {0xff3f, 324}, + {0xff40, 325}, + {0xff41, 326}, + {0xff42, 327}, + {0xff43, 328}, + {0xff44, 329}, + {0xff45, 330}, + {0xff46, 331}, + {0xff47, 332}, + {0xff48, 333}, + {0xff49, 334}, + {0xff4a, 335}, + {0xff4b, 336}, + {0xff4c, 337}, + {0xff4d, 338}, + {0xff4e, 339}, + {0xff4f, 340}, + {0xff50, 341}, + {0xff51, 342}, + {0xff52, 343}, + {0xff53, 344}, + {0xff54, 345}, + {0xff55, 346}, + {0xff56, 347}, + {0xff57, 348}, + {0xff58, 349}, + {0xff59, 350}, + {0xff5a, 351}, + {0xff5b, 352}, + {0xff5c, 353}, + {0xff5d, 354}, + {0xff5e, 106}, + {0xffe0, 168}, + {0xffe1, 169}, + {0xffe3, 355}, + {0xffe5, 265}}; + diff --git a/src/add-ons/print/drivers/pdf/source/japanese.h b/src/add-ons/print/drivers/pdf/source/japanese.h new file mode 100644 index 0000000000..156611537f --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/japanese.h @@ -0,0 +1,8478 @@ +// WARNING: MACHINE GENERATED, DON'T CHANGE! +static unicode_to_cid japanese[] = { + {0x20, 1}, + {0x21, 2}, + {0x22, 3}, + {0x23, 4}, + {0x24, 5}, + {0x25, 6}, + {0x26, 7}, + {0x27, 8}, + {0x28, 9}, + {0x29, 10}, + {0x2a, 11}, + {0x2b, 12}, + {0x2c, 13}, + {0x2d, 14}, + {0x2e, 15}, + {0x2f, 16}, + {0x30, 17}, + {0x31, 18}, + {0x32, 19}, + {0x33, 20}, + {0x34, 21}, + {0x35, 22}, + {0x36, 23}, + {0x37, 24}, + {0x38, 25}, + {0x39, 26}, + {0x3a, 27}, + {0x3b, 28}, + {0x3c, 29}, + {0x3d, 30}, + {0x3e, 31}, + {0x3f, 32}, + {0x40, 33}, + {0x41, 34}, + {0x42, 35}, + {0x43, 36}, + {0x44, 37}, + {0x45, 38}, + {0x46, 39}, + {0x47, 40}, + {0x48, 41}, + {0x49, 42}, + {0x4a, 43}, + {0x4b, 44}, + {0x4c, 45}, + {0x4d, 46}, + {0x4e, 47}, + {0x4f, 48}, + {0x50, 49}, + {0x51, 50}, + {0x52, 51}, + {0x53, 52}, + {0x54, 53}, + {0x55, 54}, + {0x56, 55}, + {0x57, 56}, + {0x58, 57}, + {0x59, 58}, + {0x5a, 59}, + {0x5b, 60}, + {0x5c, 97}, + {0x5d, 62}, + {0x5e, 63}, + {0x5f, 64}, + {0x60, 65}, + {0x61, 66}, + {0x62, 67}, + {0x63, 68}, + {0x64, 69}, + {0x65, 70}, + {0x66, 71}, + {0x67, 72}, + {0x68, 73}, + {0x69, 74}, + {0x6a, 75}, + {0x6b, 76}, + {0x6c, 77}, + {0x6d, 78}, + {0x6e, 79}, + {0x6f, 80}, + {0x70, 81}, + {0x71, 82}, + {0x72, 83}, + {0x73, 84}, + {0x74, 85}, + {0x75, 86}, + {0x76, 87}, + {0x77, 88}, + {0x78, 89}, + {0x79, 90}, + {0x7a, 91}, + {0x7b, 92}, + {0x7c, 93}, + {0x7d, 94}, + {0x7e, 95}, + {0xa1, 101}, + {0xa2, 102}, + {0xa3, 103}, + {0xa4, 107}, + {0xa5, 61}, + {0xa6, 99}, + {0xa7, 720}, + {0xa8, 647}, + {0xa9, 152}, + {0xaa, 140}, + {0xab, 109}, + {0xac, 153}, + {0xad, 151}, + {0xae, 154}, + {0xaf, 129}, + {0xb0, 707}, + {0xb1, 694}, + {0xb2, 157}, + {0xb3, 158}, + {0xb4, 645}, + {0xb5, 159}, + {0xb6, 778}, + {0xb7, 117}, + {0xb8, 134}, + {0xb9, 160}, + {0xba, 144}, + {0xbb, 123}, + {0xbc, 161}, + {0xbd, 162}, + {0xbe, 163}, + {0xbf, 126}, + {0xc0, 164}, + {0xc1, 165}, + {0xc2, 166}, + {0xc3, 167}, + {0xc4, 168}, + {0xc5, 169}, + {0xc6, 139}, + {0xc7, 170}, + {0xc8, 171}, + {0xc9, 172}, + {0xca, 173}, + {0xcb, 174}, + {0xcc, 175}, + {0xcd, 176}, + {0xce, 177}, + {0xcf, 178}, + {0xd0, 179}, + {0xd1, 180}, + {0xd2, 181}, + {0xd3, 182}, + {0xd4, 183}, + {0xd5, 184}, + {0xd6, 185}, + {0xd7, 695}, + {0xd8, 142}, + {0xd9, 187}, + {0xda, 188}, + {0xdb, 189}, + {0xdc, 190}, + {0xdd, 191}, + {0xde, 192}, + {0xdf, 150}, + {0xe0, 193}, + {0xe1, 194}, + {0xe2, 195}, + {0xe3, 196}, + {0xe4, 197}, + {0xe5, 198}, + {0xe6, 145}, + {0xe7, 199}, + {0xe8, 200}, + {0xe9, 201}, + {0xea, 202}, + {0xeb, 203}, + {0xec, 204}, + {0xed, 205}, + {0xee, 206}, + {0xef, 207}, + {0xf0, 208}, + {0xf1, 209}, + {0xf2, 210}, + {0xf3, 211}, + {0xf4, 212}, + {0xf5, 213}, + {0xf6, 214}, + {0xf7, 696}, + {0xf8, 148}, + {0xf9, 216}, + {0xfa, 217}, + {0xfb, 218}, + {0xfc, 219}, + {0xfd, 220}, + {0xfe, 221}, + {0xff, 222}, + {0x100, 9366}, + {0x101, 9361}, + {0x112, 9369}, + {0x113, 9364}, + {0x11a, 9395}, + {0x11b, 9407}, + {0x128, 9400}, + {0x129, 9412}, + {0x12a, 9367}, + {0x12b, 9362}, + {0x131, 146}, + {0x141, 141}, + {0x142, 147}, + {0x14b, 9436}, + {0x14c, 9370}, + {0x14d, 9365}, + {0x152, 143}, + {0x153, 149}, + {0x160, 223}, + {0x161, 227}, + {0x168, 9405}, + {0x169, 9417}, + {0x16a, 9368}, + {0x16b, 9363}, + {0x16e, 9404}, + {0x16f, 9416}, + {0x178, 224}, + {0x17d, 225}, + {0x17e, 229}, + {0x1c0, 99}, + {0x1cd, 9394}, + {0x1ce, 9406}, + {0x1cf, 9398}, + {0x1d0, 9410}, + {0x1d1, 9401}, + {0x1d2, 9413}, + {0x1d3, 9403}, + {0x1d4, 9415}, + {0x1fd, 9421}, + {0x251, 9418}, + {0x254, 9423}, + {0x259, 9426}, + {0x25a, 9429}, + {0x25b, 9432}, + {0x275, 9437}, + {0x283, 9442}, + {0x28c, 9438}, + {0x292, 9441}, + {0x2d0, 9443}, + {0x300, 65}, + {0x301, 127}, + {0x302, 128}, + {0x303, 95}, + {0x304, 129}, + {0x305, 226}, + {0x306, 130}, + {0x307, 131}, + {0x308, 132}, + {0x30a, 133}, + {0x30b, 135}, + {0x30c, 137}, + {0x327, 134}, + {0x328, 136}, + {0x332, 64}, + {0x336, 138}, + {0x361, 758}, + {0x391, 1011}, + {0x392, 1012}, + {0x393, 1013}, + {0x394, 1014}, + {0x395, 1015}, + {0x396, 1016}, + {0x397, 1017}, + {0x398, 1018}, + {0x399, 1019}, + {0x39a, 1020}, + {0x39b, 1021}, + {0x39c, 1022}, + {0x39d, 1023}, + {0x39e, 1024}, + {0x39f, 1025}, + {0x3a0, 1026}, + {0x3a1, 1027}, + {0x3a3, 1028}, + {0x3a4, 1029}, + {0x3a5, 1030}, + {0x3a6, 1031}, + {0x3a7, 1032}, + {0x3a8, 1033}, + {0x3a9, 1034}, + {0x3b1, 1035}, + {0x3b2, 1036}, + {0x3b3, 1037}, + {0x3b4, 1038}, + {0x3b5, 1039}, + {0x3b6, 1040}, + {0x3b7, 1041}, + {0x3b8, 1042}, + {0x3b9, 1043}, + {0x3ba, 1044}, + {0x3bb, 1045}, + {0x3bc, 1046}, + {0x3bd, 1047}, + {0x3be, 1048}, + {0x3bf, 1049}, + {0x3c0, 1050}, + {0x3c1, 1051}, + {0x3c3, 1052}, + {0x3c4, 1053}, + {0x3c5, 1054}, + {0x3c6, 1055}, + {0x3c7, 1056}, + {0x3c8, 1057}, + {0x3c9, 1058}, + {0x401, 1065}, + {0x410, 1059}, + {0x411, 1060}, + {0x412, 1061}, + {0x413, 1062}, + {0x414, 1063}, + {0x415, 1064}, + {0x416, 1066}, + {0x417, 1067}, + {0x418, 1068}, + {0x419, 1069}, + {0x41a, 1070}, + {0x41b, 1071}, + {0x41c, 1072}, + {0x41d, 1073}, + {0x41e, 1074}, + {0x41f, 1075}, + {0x420, 1076}, + {0x421, 1077}, + {0x422, 1078}, + {0x423, 1079}, + {0x424, 1080}, + {0x425, 1081}, + {0x426, 1082}, + {0x427, 1083}, + {0x428, 1084}, + {0x429, 1085}, + {0x42a, 1086}, + {0x42b, 1087}, + {0x42c, 1088}, + {0x42d, 1089}, + {0x42e, 1090}, + {0x42f, 1091}, + {0x430, 1092}, + {0x431, 1093}, + {0x432, 1094}, + {0x433, 1095}, + {0x434, 1096}, + {0x435, 1097}, + {0x436, 1099}, + {0x437, 1100}, + {0x438, 1101}, + {0x439, 1102}, + {0x43a, 1103}, + {0x43b, 1104}, + {0x43c, 1105}, + {0x43d, 1106}, + {0x43e, 1107}, + {0x43f, 1108}, + {0x440, 1109}, + {0x441, 1110}, + {0x442, 1111}, + {0x443, 1112}, + {0x444, 1113}, + {0x445, 1114}, + {0x446, 1115}, + {0x447, 1116}, + {0x448, 1117}, + {0x449, 1118}, + {0x44a, 1119}, + {0x44b, 1120}, + {0x44c, 1121}, + {0x44d, 1122}, + {0x44e, 1123}, + {0x44f, 1124}, + {0x451, 1098}, + {0x1ebc, 9397}, + {0x1ebd, 9409}, + {0x2002, 231}, + {0x2003, 633}, + {0x2010, 662}, + {0x2011, 14}, + {0x2012, 114}, + {0x2013, 114}, + {0x2014, 138}, + {0x2015, 661}, + {0x2016, 666}, + {0x2018, 670}, + {0x2019, 671}, + {0x201a, 120}, + {0x201c, 672}, + {0x201d, 673}, + {0x201e, 121}, + {0x2020, 776}, + {0x2021, 777}, + {0x2022, 119}, + {0x2025, 669}, + {0x2026, 668}, + {0x2030, 772}, + {0x2032, 708}, + {0x2033, 709}, + {0x2039, 110}, + {0x203a, 111}, + {0x203b, 734}, + {0x203e, 325}, + {0x2044, 104}, + {0x2070, 9377}, + {0x2074, 9378}, + {0x2075, 9379}, + {0x2076, 9380}, + {0x2077, 9381}, + {0x2078, 9382}, + {0x2079, 9383}, + {0x2080, 9384}, + {0x2081, 9385}, + {0x2082, 9386}, + {0x2083, 9387}, + {0x2084, 9388}, + {0x2085, 9389}, + {0x2086, 9390}, + {0x2087, 9391}, + {0x2088, 9392}, + {0x2089, 9393}, + {0x20ac, 9354}, + {0x20dd, 779}, + {0x2103, 710}, + {0x2109, 8305}, + {0x210a, 8304}, + {0x2113, 8025}, + {0x2116, 7610}, + {0x2121, 8055}, + {0x2122, 228}, + {0x2126, 9355}, + {0x212b, 771}, + {0x2153, 9375}, + {0x2154, 9376}, + {0x215b, 9371}, + {0x215c, 9372}, + {0x215d, 9373}, + {0x215e, 9374}, + {0x2160, 7575}, + {0x2161, 7576}, + {0x2162, 7577}, + {0x2163, 7578}, + {0x2164, 7579}, + {0x2165, 7580}, + {0x2166, 7581}, + {0x2167, 7582}, + {0x2168, 7583}, + {0x2169, 7584}, + {0x216a, 8225}, + {0x216b, 8226}, + {0x2170, 8092}, + {0x2171, 8093}, + {0x2172, 8094}, + {0x2173, 8095}, + {0x2174, 8096}, + {0x2175, 8097}, + {0x2176, 8098}, + {0x2177, 8099}, + {0x2178, 8100}, + {0x2179, 8101}, + {0x217a, 8298}, + {0x217b, 8299}, + {0x217f, 8303}, + {0x2190, 737}, + {0x2191, 738}, + {0x2192, 736}, + {0x2193, 739}, + {0x2197, 0}, + {0x2199, 0}, + {0x21c4, 8310}, + {0x21c5, 8311}, + {0x21c6, 8309}, + {0x21d2, 752}, + {0x21d4, 753}, + {0x21e6, 8013}, + {0x21e7, 8012}, + {0x21e8, 8014}, + {0x21e9, 8011}, + {0x2200, 754}, + {0x2202, 759}, + {0x2203, 755}, + {0x2207, 760}, + {0x2208, 741}, + {0x220b, 742}, + {0x2211, 7625}, + {0x2212, 693}, + {0x221a, 765}, + {0x221d, 767}, + {0x221e, 703}, + {0x221f, 7629}, + {0x2220, 756}, + {0x2225, 666}, + {0x2227, 749}, + {0x2228, 750}, + {0x2229, 748}, + {0x222a, 747}, + {0x222b, 769}, + {0x222c, 770}, + {0x222d, 8195}, + {0x222e, 7624}, + {0x2234, 704}, + {0x2235, 768}, + {0x223c, 665}, + {0x223d, 766}, + {0x2252, 762}, + {0x2260, 698}, + {0x2261, 761}, + {0x2266, 701}, + {0x2267, 702}, + {0x226a, 763}, + {0x226b, 764}, + {0x2273, 0}, + {0x2282, 745}, + {0x2283, 746}, + {0x2286, 743}, + {0x2287, 744}, + {0x22a5, 757}, + {0x22bf, 7630}, + {0x22ee, 7897}, + {0x22ef, 668}, + {0x2312, 758}, + {0x2460, 7555}, + {0x2461, 7556}, + {0x2462, 7557}, + {0x2463, 7558}, + {0x2464, 7559}, + {0x2465, 7560}, + {0x2466, 7561}, + {0x2467, 7562}, + {0x2468, 7563}, + {0x2469, 7564}, + {0x246a, 7565}, + {0x246b, 7566}, + {0x246c, 7567}, + {0x246d, 7568}, + {0x246e, 7569}, + {0x246f, 7570}, + {0x2470, 7571}, + {0x2471, 7572}, + {0x2472, 7573}, + {0x2473, 7574}, + {0x2474, 8071}, + {0x2475, 8072}, + {0x2476, 8073}, + {0x2477, 8074}, + {0x2478, 8075}, + {0x2479, 8076}, + {0x247a, 8077}, + {0x247b, 8078}, + {0x247c, 8079}, + {0x247d, 8080}, + {0x247e, 8081}, + {0x247f, 8082}, + {0x2480, 8083}, + {0x2481, 8084}, + {0x2482, 8085}, + {0x2483, 8086}, + {0x2484, 8087}, + {0x2485, 8088}, + {0x2486, 8089}, + {0x2487, 8090}, + {0x2488, 8062}, + {0x2489, 8063}, + {0x248a, 8064}, + {0x248b, 8065}, + {0x248c, 8066}, + {0x248d, 8067}, + {0x248e, 8068}, + {0x248f, 8069}, + {0x2490, 8070}, + {0x249c, 8112}, + {0x249d, 8113}, + {0x249e, 8114}, + {0x249f, 8115}, + {0x24a0, 8116}, + {0x24a1, 8117}, + {0x24a2, 8118}, + {0x24a3, 8119}, + {0x24a4, 8120}, + {0x24a5, 8121}, + {0x24a6, 8122}, + {0x24a7, 8123}, + {0x24a8, 8124}, + {0x24a9, 8125}, + {0x24aa, 8126}, + {0x24ab, 8127}, + {0x24ac, 8128}, + {0x24ad, 8129}, + {0x24ae, 8130}, + {0x24af, 8131}, + {0x24b0, 8132}, + {0x24b1, 8133}, + {0x24b2, 8134}, + {0x24b3, 8135}, + {0x24b4, 8136}, + {0x24b5, 8137}, + {0x24b7, 0}, + {0x24b8, 1}, + {0x24b9, 2}, + {0x24ba, 3}, + {0x24bb, 4}, + {0x24bc, 5}, + {0x24bd, 6}, + {0x24be, 7}, + {0x24bf, 8}, + {0x24c0, 9}, + {0x24c1, 10}, + {0x24c2, 11}, + {0x24c3, 12}, + {0x24c4, 13}, + {0x24c5, 14}, + {0x24c6, 15}, + {0x24c7, 16}, + {0x24c8, 17}, + {0x24c9, 18}, + {0x24ca, 19}, + {0x24cb, 20}, + {0x24cc, 21}, + {0x24cd, 22}, + {0x24ce, 23}, + {0x24cf, 24}, + {0x24d1, 0}, + {0x24d2, 1}, + {0x24d3, 2}, + {0x24d4, 3}, + {0x24d5, 4}, + {0x24d6, 5}, + {0x24d7, 6}, + {0x24d8, 7}, + {0x24d9, 8}, + {0x24da, 9}, + {0x24db, 10}, + {0x24dc, 11}, + {0x24dd, 12}, + {0x24de, 13}, + {0x24df, 14}, + {0x24e0, 15}, + {0x24e1, 16}, + {0x24e2, 17}, + {0x24e3, 18}, + {0x24e4, 19}, + {0x24e5, 20}, + {0x24e6, 21}, + {0x24e7, 22}, + {0x24e8, 23}, + {0x24e9, 24}, + {0x24ea, 8224}, + {0x2500, 7479}, + {0x2501, 7480}, + {0x2502, 7481}, + {0x2503, 7482}, + {0x2504, 7483}, + {0x2505, 7484}, + {0x2506, 7485}, + {0x2507, 7486}, + {0x2508, 7487}, + {0x2509, 7488}, + {0x250a, 7489}, + {0x250b, 7490}, + {0x250c, 7491}, + {0x250d, 7492}, + {0x250e, 7493}, + {0x250f, 7494}, + {0x2510, 7495}, + {0x2511, 7496}, + {0x2512, 7497}, + {0x2513, 7498}, + {0x2514, 7499}, + {0x2515, 7500}, + {0x2516, 7501}, + {0x2517, 7502}, + {0x2518, 7503}, + {0x2519, 7504}, + {0x251a, 7505}, + {0x251b, 7506}, + {0x251c, 7507}, + {0x251d, 7508}, + {0x251e, 7509}, + {0x251f, 7510}, + {0x2520, 7511}, + {0x2521, 7512}, + {0x2522, 7513}, + {0x2523, 7514}, + {0x2524, 7515}, + {0x2525, 7516}, + {0x2526, 7517}, + {0x2527, 7518}, + {0x2528, 7519}, + {0x2529, 7520}, + {0x252a, 7521}, + {0x252b, 7522}, + {0x252c, 7523}, + {0x252d, 7524}, + {0x252e, 7525}, + {0x252f, 7526}, + {0x2530, 7527}, + {0x2531, 7528}, + {0x2532, 7529}, + {0x2533, 7530}, + {0x2534, 7531}, + {0x2535, 7532}, + {0x2536, 7533}, + {0x2537, 7534}, + {0x2538, 7535}, + {0x2539, 7536}, + {0x253a, 7537}, + {0x253b, 7538}, + {0x253c, 7539}, + {0x253d, 7540}, + {0x253e, 7541}, + {0x253f, 7542}, + {0x2540, 7543}, + {0x2541, 7544}, + {0x2542, 7545}, + {0x2543, 7546}, + {0x2544, 7547}, + {0x2545, 7548}, + {0x2546, 7549}, + {0x2547, 7550}, + {0x2548, 7551}, + {0x2549, 7552}, + {0x254a, 7553}, + {0x254b, 7554}, + {0x2550, 8251}, + {0x255e, 8252}, + {0x2561, 8254}, + {0x256a, 8253}, + {0x256d, 8247}, + {0x256e, 8248}, + {0x256f, 8250}, + {0x2570, 8249}, + {0x2571, 8261}, + {0x2572, 8262}, + {0x2573, 8263}, + {0x2581, 8230}, + {0x2582, 8231}, + {0x2583, 8232}, + {0x2584, 8233}, + {0x2585, 8234}, + {0x2586, 8235}, + {0x2587, 8236}, + {0x2588, 8237}, + {0x2589, 8244}, + {0x258a, 8243}, + {0x258b, 8242}, + {0x258c, 8241}, + {0x258d, 8240}, + {0x258e, 8239}, + {0x258f, 8238}, + {0x2594, 8245}, + {0x2595, 8246}, + {0x25a0, 729}, + {0x25a1, 728}, + {0x25a2, 8015}, + {0x25b2, 731}, + {0x25b3, 730}, + {0x25b7, 8010}, + {0x25bc, 733}, + {0x25bd, 732}, + {0x25c1, 8009}, + {0x25c6, 727}, + {0x25c7, 726}, + {0x25c9, 8210}, + {0x25cb, 723}, + {0x25ce, 725}, + {0x25cf, 724}, + {0x25e2, 8255}, + {0x25e3, 8256}, + {0x25e4, 8258}, + {0x25e5, 8257}, + {0x25ef, 779}, + {0x2600, 8215}, + {0x2601, 8216}, + {0x2602, 8217}, + {0x2603, 8218}, + {0x2605, 722}, + {0x2606, 721}, + {0x260e, 8056}, + {0x261c, 8220}, + {0x261d, 8221}, + {0x261e, 8219}, + {0x261f, 8222}, + {0x2640, 706}, + {0x2642, 705}, + {0x2660, 8211}, + {0x2661, 8017}, + {0x2662, 8019}, + {0x2663, 8213}, + {0x2664, 8018}, + {0x2665, 8212}, + {0x2666, 8214}, + {0x2667, 8016}, + {0x2669, 0}, + {0x266a, 775}, + {0x266d, 774}, + {0x266f, 773}, + {0x2776, 8286}, + {0x2777, 8287}, + {0x2778, 8288}, + {0x2779, 8289}, + {0x277a, 8290}, + {0x277b, 8291}, + {0x277c, 8292}, + {0x277d, 8293}, + {0x277e, 8294}, + {0x27a1, 8206}, + {0x2e8d, 0}, + {0x2e8e, 4209}, + {0x2e90, 4646}, + {0x2e92, 3762}, + {0x2e93, 4739}, + {0x2e94, 4779}, + {0x2e99, 5059}, + {0x2e9b, 5089}, + {0x2e9f, 3644}, + {0x2ea0, 3773}, + {0x2ea2, 0}, + {0x2eac, 2260}, + {0x2ebf, 0}, + {0x2ec0, 1}, + {0x2ec1, 1931}, + {0x2ec4, 2658}, + {0x2ed1, 3029}, + {0x2ed8, 2664}, + {0x2ee4, 1614}, + {0x2ee8, 3380}, + {0x2ee9, 1323}, + {0x2eeb, 2666}, + {0x2eed, 2243}, + {0x2eef, 3965}, + {0x2ef2, 1615}, + {0x2f00, 1200}, + {0x2f01, 8371}, + {0x2f02, 4095}, + {0x2f03, 4097}, + {0x2f04, 1333}, + {0x2f05, 4102}, + {0x2f06, 3275}, + {0x2f07, 4110}, + {0x2f08, 2579}, + {0x2f09, 4208}, + {0x2f0a, 3286}, + {0x2f0b, 3392}, + {0x2f0c, 4219}, + {0x2f0d, 4227}, + {0x2f0e, 4233}, + {0x2f0f, 4243}, + {0x2f10, 4248}, + {0x2f11, 3163}, + {0x2f12, 3991}, + {0x2f13, 4294}, + {0x2f14, 4301}, + {0x2f15, 4302}, + {0x2f16, 4307}, + {0x2f17, 2375}, + {0x2f18, 3708}, + {0x2f19, 4316}, + {0x2f1a, 4321}, + {0x2f1b, 4328}, + {0x2f1c, 3746}, + {0x2f1d, 1969}, + {0x2f1e, 4459}, + {0x2f1f, 3156}, + {0x2f20, 2204}, + {0x2f21, 4538}, + {0x2f22, 4539}, + {0x2f23, 3878}, + {0x2f24, 2887}, + {0x2f25, 2433}, + {0x2f26, 2208}, + {0x2f27, 4622}, + {0x2f28, 2631}, + {0x2f29, 2454}, + {0x2f2a, 4646}, + {0x2f2b, 4648}, + {0x2f2c, 4658}, + {0x2f2d, 2177}, + {0x2f2e, 4716}, + {0x2f2f, 1979}, + {0x2f30, 1918}, + {0x2f31, 1738}, + {0x2f32, 1519}, + {0x2f33, 4739}, + {0x2f34, 4741}, + {0x2f35, 4761}, + {0x2f36, 4763}, + {0x2f37, 4768}, + {0x2f38, 1655}, + {0x2f3a, 4783}, + {0x2f3b, 4785}, + {0x2f3c, 2554}, + {0x2f3d, 4930}, + {0x2f3e, 1921}, + {0x2f3f, 2326}, + {0x2f40, 2215}, + {0x2f41, 5058}, + {0x2f42, 3592}, + {0x2f43, 3143}, + {0x2f44, 1740}, + {0x2f45, 3661}, + {0x2f46, 5088}, + {0x2f47, 3284}, + {0x2f48, 5132}, + {0x2f49, 1860}, + {0x2f4a, 3814}, + {0x2f4b, 1853}, + {0x2f4c, 2221}, + {0x2f4d, 5349}, + {0x2f4e, 5364}, + {0x2f4f, 5368}, + {0x2f50, 3450}, + {0x2f51, 3807}, + {0x2f52, 2223}, + {0x2f53, 5378}, + {0x2f54, 2603}, + {0x2f55, 1360}, + {0x2f56, 3066}, + {0x2f57, 3541}, + {0x2f58, 5604}, + {0x2f59, 5606}, + {0x2f5a, 3618}, + {0x2f5b, 1383}, + {0x2f5c, 1671}, + {0x2f5d, 1880}, + {0x2f5e, 1904}, + {0x2f5f, 1732}, + {0x2f60, 1245}, + {0x2f61, 1504}, + {0x2f62, 1537}, + {0x2f63, 2652}, + {0x2f64, 3899}, + {0x2f65, 3134}, + {0x2f66, 3479}, + {0x2f68, 5783}, + {0x2f69, 3368}, + {0x2f6a, 3453}, + {0x2f6b, 2172}, + {0x2f6c, 3816}, + {0x2f6d, 3779}, + {0x2f6e, 3836}, + {0x2f6f, 2676}, + {0x2f70, 2260}, + {0x2f72, 1363}, + {0x2f73, 1856}, + {0x2f74, 3953}, + {0x2f75, 2971}, + {0x2f76, 3606}, + {0x2f77, 2227}, + {0x2f78, 1544}, + {0x2f79, 6163}, + {0x2f7a, 3901}, + {0x2f7b, 1227}, + {0x2f7c, 4061}, + {0x2f7d, 2261}, + {0x2f7e, 6205}, + {0x2f7f, 2262}, + {0x2f80, 6227}, + {0x2f81, 3281}, + {0x2f82, 2569}, + {0x2f83, 2263}, + {0x2f84, 2232}, + {0x2f85, 1235}, + {0x2f86, 2697}, + {0x2f87, 2726}, + {0x2f88, 2360}, + {0x2f89, 2081}, + {0x2f8a, 2541}, + {0x2f8b, 6322}, + {0x2f8c, 6479}, + {0x2f8d, 2988}, + {0x2f8e, 1858}, + {0x2f8f, 2022}, + {0x2f90, 1189}, + {0x2f91, 6635}, + {0x2f92, 1887}, + {0x2f93, 1455}, + {0x2f94, 1908}, + {0x2f95, 2921}, + {0x2f96, 3198}, + {0x2f97, 6742}, + {0x2f98, 6745}, + {0x2f99, 1419}, + {0x2f9a, 2682}, + {0x2f9b, 2808}, + {0x2f9c, 2829}, + {0x2f9d, 2574}, + {0x2f9e, 2306}, + {0x2f9f, 2575}, + {0x2fa0, 2914}, + {0x2fa2, 3874}, + {0x2fa3, 3243}, + {0x2fa4, 3428}, + {0x2fa5, 3948}, + {0x2fa6, 1754}, + {0x2fa7, 3029}, + {0x2fa8, 3827}, + {0x2fa9, 3550}, + {0x2faa, 7113}, + {0x2fab, 7115}, + {0x2fac, 1229}, + {0x2fad, 8695}, + {0x2fae, 3463}, + {0x2faf, 3800}, + {0x2fb0, 1461}, + {0x2fb1, 7171}, + {0x2fb2, 7173}, + {0x2fb3, 1339}, + {0x2fb4, 3607}, + {0x2fb5, 3561}, + {0x2fb6, 3464}, + {0x2fb7, 2543}, + {0x2fb8, 2335}, + {0x2fb9, 2035}, + {0x2fba, 3333}, + {0x2fbb, 2062}, + {0x2fbc, 2036}, + {0x2fbd, 7276}, + {0x2fbe, 7293}, + {0x2fbf, 7299}, + {0x2fc0, 7300}, + {0x2fc1, 1614}, + {0x2fc2, 1685}, + {0x2fc3, 3031}, + {0x2fc4, 7414}, + {0x2fc5, 2267}, + {0x2fc6, 7425}, + {0x2fc7, 3729}, + {0x2fc9, 1642}, + {0x2fca, 2055}, + {0x2fcb, 7446}, + {0x2fcc, 7449}, + {0x2fcd, 3102}, + {0x2fce, 1937}, + {0x2fcf, 2767}, + {0x2fd0, 3475}, + {0x2fd1, 7457}, + {0x2fd2, 7458}, + {0x2fd3, 3966}, + {0x2fd4, 7472}, + {0x2fd5, 7473}, + {0x3000, 633}, + {0x3001, 634}, + {0x3002, 635}, + {0x3003, 655}, + {0x3004, 8308}, + {0x3005, 657}, + {0x3006, 658}, + {0x3007, 659}, + {0x3008, 682}, + {0x3009, 683}, + {0x300a, 684}, + {0x300b, 685}, + {0x300c, 686}, + {0x300d, 687}, + {0x300e, 688}, + {0x300f, 689}, + {0x3010, 690}, + {0x3011, 691}, + {0x3012, 735}, + {0x3013, 740}, + {0x3014, 676}, + {0x3015, 677}, + {0x301c, 665}, + {0x301d, 7608}, + {0x301f, 7609}, + {0x3020, 8058}, + {0x3034, 0}, + {0x3035, 1}, + {0x3036, 8057}, + {0x3041, 842}, + {0x3042, 843}, + {0x3043, 844}, + {0x3044, 845}, + {0x3045, 846}, + {0x3046, 847}, + {0x3047, 848}, + {0x3048, 849}, + {0x3049, 850}, + {0x304a, 851}, + {0x304b, 852}, + {0x304c, 853}, + {0x304d, 854}, + {0x304e, 855}, + {0x304f, 856}, + {0x3050, 857}, + {0x3051, 858}, + {0x3052, 859}, + {0x3053, 860}, + {0x3054, 861}, + {0x3055, 862}, + {0x3056, 863}, + {0x3057, 864}, + {0x3058, 865}, + {0x3059, 866}, + {0x305a, 867}, + {0x305b, 868}, + {0x305c, 869}, + {0x305d, 870}, + {0x305e, 871}, + {0x305f, 872}, + {0x3060, 873}, + {0x3061, 874}, + {0x3062, 875}, + {0x3063, 876}, + {0x3064, 877}, + {0x3065, 878}, + {0x3066, 879}, + {0x3067, 880}, + {0x3068, 881}, + {0x3069, 882}, + {0x306a, 883}, + {0x306b, 884}, + {0x306c, 885}, + {0x306d, 886}, + {0x306e, 887}, + {0x306f, 888}, + {0x3070, 889}, + {0x3071, 890}, + {0x3072, 891}, + {0x3073, 892}, + {0x3074, 893}, + {0x3075, 894}, + {0x3076, 895}, + {0x3077, 896}, + {0x3078, 897}, + {0x3079, 898}, + {0x307a, 899}, + {0x307b, 900}, + {0x307c, 901}, + {0x307d, 902}, + {0x307e, 903}, + {0x307f, 904}, + {0x3080, 905}, + {0x3081, 906}, + {0x3082, 907}, + {0x3083, 908}, + {0x3084, 909}, + {0x3085, 910}, + {0x3086, 911}, + {0x3087, 912}, + {0x3088, 913}, + {0x3089, 914}, + {0x308a, 915}, + {0x308b, 916}, + {0x308c, 917}, + {0x308d, 918}, + {0x308e, 919}, + {0x308f, 920}, + {0x3090, 921}, + {0x3091, 922}, + {0x3092, 923}, + {0x3093, 924}, + {0x3094, 7958}, + {0x309b, 643}, + {0x309c, 644}, + {0x309d, 653}, + {0x309e, 654}, + {0x30a1, 925}, + {0x30a2, 926}, + {0x30a3, 927}, + {0x30a4, 928}, + {0x30a5, 929}, + {0x30a6, 930}, + {0x30a7, 931}, + {0x30a8, 932}, + {0x30a9, 933}, + {0x30aa, 934}, + {0x30ab, 935}, + {0x30ac, 936}, + {0x30ad, 937}, + {0x30ae, 938}, + {0x30af, 939}, + {0x30b0, 940}, + {0x30b1, 941}, + {0x30b2, 942}, + {0x30b3, 943}, + {0x30b4, 944}, + {0x30b5, 945}, + {0x30b6, 946}, + {0x30b7, 947}, + {0x30b8, 948}, + {0x30b9, 949}, + {0x30ba, 950}, + {0x30bb, 951}, + {0x30bc, 952}, + {0x30bd, 953}, + {0x30be, 954}, + {0x30bf, 955}, + {0x30c0, 956}, + {0x30c1, 957}, + {0x30c2, 958}, + {0x30c3, 959}, + {0x30c4, 960}, + {0x30c5, 961}, + {0x30c6, 962}, + {0x30c7, 963}, + {0x30c8, 964}, + {0x30c9, 965}, + {0x30ca, 966}, + {0x30cb, 967}, + {0x30cc, 968}, + {0x30cd, 969}, + {0x30ce, 970}, + {0x30cf, 971}, + {0x30d0, 972}, + {0x30d1, 973}, + {0x30d2, 974}, + {0x30d3, 975}, + {0x30d4, 976}, + {0x30d5, 977}, + {0x30d6, 978}, + {0x30d7, 979}, + {0x30d8, 980}, + {0x30d9, 981}, + {0x30da, 982}, + {0x30db, 983}, + {0x30dc, 984}, + {0x30dd, 985}, + {0x30de, 986}, + {0x30df, 987}, + {0x30e0, 988}, + {0x30e1, 989}, + {0x30e2, 990}, + {0x30e3, 991}, + {0x30e4, 992}, + {0x30e5, 993}, + {0x30e6, 994}, + {0x30e7, 995}, + {0x30e8, 996}, + {0x30e9, 997}, + {0x30ea, 998}, + {0x30eb, 999}, + {0x30ec, 1000}, + {0x30ed, 1001}, + {0x30ee, 1002}, + {0x30ef, 1003}, + {0x30f0, 1004}, + {0x30f1, 1005}, + {0x30f2, 1006}, + {0x30f3, 1007}, + {0x30f4, 1008}, + {0x30f5, 1009}, + {0x30f6, 1010}, + {0x30f7, 8313}, + {0x30f8, 8314}, + {0x30f9, 8315}, + {0x30fa, 8316}, + {0x30fb, 638}, + {0x30fc, 660}, + {0x30fd, 651}, + {0x30fe, 652}, + {0x3221, 0}, + {0x3222, 1}, + {0x3223, 2}, + {0x3224, 3}, + {0x3225, 4}, + {0x3226, 5}, + {0x3227, 6}, + {0x3228, 7}, + {0x3229, 8}, + {0x322a, 8198}, + {0x322b, 8199}, + {0x322c, 8200}, + {0x322d, 8201}, + {0x322e, 8202}, + {0x322f, 8203}, + {0x3230, 8197}, + {0x3231, 7618}, + {0x3232, 7619}, + {0x3233, 8143}, + {0x3234, 8141}, + {0x3235, 8148}, + {0x3236, 8147}, + {0x3237, 8204}, + {0x3238, 8142}, + {0x3239, 7620}, + {0x323a, 8151}, + {0x323b, 8149}, + {0x323c, 8144}, + {0x323d, 8139}, + {0x323e, 8146}, + {0x323f, 8140}, + {0x3240, 8150}, + {0x3241, 8205}, + {0x3242, 8145}, + {0x3243, 8138}, + {0x3281, 0}, + {0x3282, 1}, + {0x3283, 2}, + {0x3284, 3}, + {0x3285, 4}, + {0x3286, 5}, + {0x3287, 6}, + {0x3288, 7}, + {0x3289, 8}, + {0x328b, 0}, + {0x328c, 1}, + {0x328d, 2}, + {0x328e, 3}, + {0x328f, 4}, + {0x3291, 8161}, + {0x3292, 8160}, + {0x3293, 8162}, + {0x3294, 8156}, + {0x3296, 8165}, + {0x3298, 8158}, + {0x3299, 8223}, + {0x329d, 8319}, + {0x329e, 8191}, + {0x32a1, 0}, + {0x32a4, 7613}, + {0x32a5, 7614}, + {0x32a6, 7615}, + {0x32a7, 7616}, + {0x32a8, 7617}, + {0x32a9, 8154}, + {0x32aa, 8157}, + {0x32ab, 8159}, + {0x32ac, 8163}, + {0x32ad, 8153}, + {0x32ae, 8164}, + {0x32af, 8155}, + {0x32b0, 8152}, + {0x32d1, 0}, + {0x32d2, 1}, + {0x32d3, 2}, + {0x32d4, 3}, + {0x32d5, 4}, + {0x32d6, 5}, + {0x32d7, 6}, + {0x32d8, 7}, + {0x32d9, 8}, + {0x32da, 9}, + {0x32db, 10}, + {0x32dc, 11}, + {0x32dd, 12}, + {0x32de, 13}, + {0x32df, 14}, + {0x32e0, 15}, + {0x32e1, 16}, + {0x32e2, 17}, + {0x32e3, 18}, + {0x32e4, 19}, + {0x32e5, 20}, + {0x32e6, 21}, + {0x32e7, 22}, + {0x32e8, 23}, + {0x32e9, 24}, + {0x32ea, 25}, + {0x32eb, 26}, + {0x32ec, 27}, + {0x32ed, 28}, + {0x32ee, 29}, + {0x32ef, 30}, + {0x32f0, 31}, + {0x32f1, 32}, + {0x32f2, 33}, + {0x32f3, 34}, + {0x32f4, 35}, + {0x32f5, 36}, + {0x32f6, 37}, + {0x32f7, 38}, + {0x32f8, 39}, + {0x32f9, 40}, + {0x32fa, 41}, + {0x32fb, 42}, + {0x32fc, 43}, + {0x32fd, 44}, + {0x32fe, 45}, + {0x3300, 8048}, + {0x3302, 0}, + {0x3303, 8042}, + {0x3305, 8183}, + {0x330d, 7595}, + {0x330f, 0}, + {0x3310, 1}, + {0x3311, 2}, + {0x3312, 3}, + {0x3313, 4}, + {0x3314, 7586}, + {0x3315, 8041}, + {0x3316, 8039}, + {0x3318, 8040}, + {0x331b, 0}, + {0x331c, 1}, + {0x331d, 2}, + {0x331e, 8051}, + {0x3320, 0}, + {0x3321, 1}, + {0x3322, 8038}, + {0x3323, 8043}, + {0x3326, 7596}, + {0x3327, 7590}, + {0x3329, 0}, + {0x332a, 8052}, + {0x332b, 7598}, + {0x332f, 0}, + {0x3330, 1}, + {0x3331, 8049}, + {0x3333, 8327}, + {0x3335, 0}, + {0x3336, 7592}, + {0x3339, 8046}, + {0x333b, 8047}, + {0x333f, 0}, + {0x3340, 1}, + {0x3342, 8045}, + {0x3344, 0}, + {0x3345, 1}, + {0x3346, 2}, + {0x3347, 8050}, + {0x3349, 7585}, + {0x334a, 7599}, + {0x334c, 0}, + {0x334d, 7588}, + {0x334e, 8328}, + {0x3350, 0}, + {0x3351, 7593}, + {0x3356, 0}, + {0x3357, 8044}, + {0x337b, 8323}, + {0x337c, 7623}, + {0x337d, 7622}, + {0x337e, 7621}, + {0x337f, 8054}, + {0x3385, 8031}, + {0x3386, 8032}, + {0x3387, 8033}, + {0x3388, 8192}, + {0x3389, 8193}, + {0x338e, 7604}, + {0x338f, 7605}, + {0x3390, 8035}, + {0x3396, 8037}, + {0x3397, 8024}, + {0x3398, 8026}, + {0x339c, 7601}, + {0x339d, 7602}, + {0x339e, 7603}, + {0x339f, 8186}, + {0x33a0, 8020}, + {0x33a1, 7607}, + {0x33a2, 8021}, + {0x33a3, 8187}, + {0x33a4, 8022}, + {0x33a5, 8023}, + {0x33a6, 8188}, + {0x33b0, 8030}, + {0x33b1, 8029}, + {0x33b2, 8028}, + {0x33b3, 8027}, + {0x33c4, 7606}, + {0x33c8, 8194}, + {0x33cb, 8034}, + {0x33cc, 8182}, + {0x33cd, 7611}, + {0x33d4, 8036}, + {0x33d8, 0}, + {0x4e00, 1200}, + {0x4e01, 3000}, + {0x4e03, 2275}, + {0x4e05, 0}, + {0x4e07, 3754}, + {0x4e08, 2510}, + {0x4e09, 2174}, + {0x4e0a, 2509}, + {0x4e0b, 1340}, + {0x4e0d, 3526}, + {0x4e0e, 3881}, + {0x4e10, 4091}, + {0x4e11, 1233}, + {0x4e14, 1484}, + {0x4e15, 4092}, + {0x4e16, 2632}, + {0x4e17, 4311}, + {0x4e18, 1648}, + {0x4e19, 3594}, + {0x4e1e, 2511}, + {0x4e21, 3974}, + {0x4e26, 3602}, + {0x4e28, 8371}, + {0x4e2a, 4093}, + {0x4e2d, 2980}, + {0x4e30, 0}, + {0x4e31, 4094}, + {0x4e32, 1778}, + {0x4e36, 4095}, + {0x4e38, 1561}, + {0x4e39, 2926}, + {0x4e3b, 2323}, + {0x4e3c, 4096}, + {0x4e3f, 4097}, + {0x4e41, 0}, + {0x4e42, 4098}, + {0x4e43, 3307}, + {0x4e45, 1649}, + {0x4e4b, 3309}, + {0x4e4d, 3259}, + {0x4e4e, 1911}, + {0x4e4f, 3681}, + {0x4e55, 6480}, + {0x4e56, 4099}, + {0x4e57, 2512}, + {0x4e58, 4100}, + {0x4e59, 1333}, + {0x4e5d, 1757}, + {0x4e5e, 1956}, + {0x4e5f, 3829}, + {0x4e62, 4659}, + {0x4e71, 3930}, + {0x4e73, 3285}, + {0x4e7e, 1505}, + {0x4e80, 1615}, + {0x4e82, 4101}, + {0x4e85, 4102}, + {0x4e86, 3971}, + {0x4e88, 3879}, + {0x4e89, 2794}, + {0x4e8a, 4104}, + {0x4e8b, 2244}, + {0x4e8c, 3275}, + {0x4e8e, 4107}, + {0x4e91, 1248}, + {0x4e92, 1939}, + {0x4e94, 1938}, + {0x4e95, 1194}, + {0x4e98, 4081}, + {0x4e99, 4080}, + {0x4e9b, 2083}, + {0x4e9c, 1125}, + {0x4e9e, 4108}, + {0x4e9f, 4109}, + {0x4ea0, 4110}, + {0x4ea1, 3682}, + {0x4ea2, 4111}, + {0x4ea4, 1958}, + {0x4ea5, 1195}, + {0x4ea6, 3744}, + {0x4ea8, 1686}, + {0x4eab, 1687}, + {0x4eac, 1688}, + {0x4ead, 3070}, + {0x4eae, 3972}, + {0x4eb0, 4112}, + {0x4eb3, 4113}, + {0x4eb6, 4114}, + {0x4eba, 2579}, + {0x4ec0, 2372}, + {0x4ec1, 2580}, + {0x4ec2, 4119}, + {0x4ec4, 4117}, + {0x4ec6, 4118}, + {0x4ec7, 1650}, + {0x4eca, 2067}, + {0x4ecb, 1392}, + {0x4ecd, 4116}, + {0x4ece, 4115}, + {0x4ecf, 3577}, + {0x4ed4, 2196}, + {0x4ed5, 2195}, + {0x4ed6, 2846}, + {0x4ed7, 4120}, + {0x4ed8, 3527}, + {0x4ed9, 2699}, + {0x4edd, 656}, + {0x4ede, 4121}, + {0x4edf, 4123}, + {0x4ee1, 8372}, + {0x4ee3, 2885}, + {0x4ee4, 4009}, + {0x4ee5, 1166}, + {0x4eed, 4122}, + {0x4eee, 1342}, + {0x4ef0, 1724}, + {0x4ef2, 2981}, + {0x4ef6, 1861}, + {0x4ef7, 4124}, + {0x4efb, 3290}, + {0x4efc, 8373}, + {0x4f00, 8374}, + {0x4f01, 1575}, + {0x4f03, 8375}, + {0x4f09, 4125}, + {0x4f0a, 1167}, + {0x4f0d, 1940}, + {0x4f0e, 1576}, + {0x4f0f, 3564}, + {0x4f10, 3398}, + {0x4f11, 1651}, + {0x4f1a, 1393}, + {0x4f1c, 4160}, + {0x4f1d, 3131}, + {0x4f2f, 3362}, + {0x4f30, 4127}, + {0x4f34, 3408}, + {0x4f36, 4010}, + {0x4f38, 2547}, + {0x4f39, 8376}, + {0x4f3a, 2197}, + {0x4f3c, 2245}, + {0x4f3d, 1344}, + {0x4f43, 3053}, + {0x4f46, 2912}, + {0x4f47, 4131}, + {0x4f4d, 1168}, + {0x4f4e, 3071}, + {0x4f4f, 2373}, + {0x4f50, 2084}, + {0x4f51, 3854}, + {0x4f53, 2862}, + {0x4f55, 1343}, + {0x4f56, 8377}, + {0x4f57, 4130}, + {0x4f59, 3880}, + {0x4f5a, 4126}, + {0x4f5b, 4128}, + {0x4f5c, 2142}, + {0x4f5d, 4129}, + {0x4f5e, 4563}, + {0x4f69, 4137}, + {0x4f6f, 4140}, + {0x4f70, 4138}, + {0x4f73, 1346}, + {0x4f75, 3595}, + {0x4f76, 4132}, + {0x4f7b, 4136}, + {0x4f7c, 1959}, + {0x4f7e, 0}, + {0x4f7f, 2198}, + {0x4f83, 1506}, + {0x4f86, 4141}, + {0x4f88, 4133}, + {0x4f8a, 8379}, + {0x4f8b, 4011}, + {0x4f8d, 2246}, + {0x4f8f, 4134}, + {0x4f91, 4139}, + {0x4f92, 8378}, + {0x4f94, 8381}, + {0x4f96, 4142}, + {0x4f98, 4135}, + {0x4f9a, 8380}, + {0x4f9b, 1689}, + {0x4f9d, 1169}, + {0x4fa0, 1690}, + {0x4fa1, 1345}, + {0x4fab, 4564}, + {0x4fad, 3751}, + {0x4fae, 3552}, + {0x4faf, 1960}, + {0x4fb5, 2549}, + {0x4fb6, 3967}, + {0x4fbf, 3624}, + {0x4fc2, 1806}, + {0x4fc3, 2821}, + {0x4fc4, 1380}, + {0x4fc9, 8364}, + {0x4fca, 2397}, + {0x4fcd, 8382}, + {0x4fce, 4146}, + {0x4fd0, 4151}, + {0x4fd1, 4149}, + {0x4fd4, 4144}, + {0x4fd7, 2831}, + {0x4fd8, 4147}, + {0x4fda, 4150}, + {0x4fdb, 4148}, + {0x4fdd, 3629}, + {0x4fdf, 4145}, + {0x4fe0, 7660}, + {0x4fe1, 2548}, + {0x4fe3, 3745}, + {0x4fe4, 4152}, + {0x4fe5, 4153}, + {0x4fee, 2350}, + {0x4fef, 4166}, + {0x4ff3, 3334}, + {0x4ff5, 3496}, + {0x4ff6, 4161}, + {0x4ff8, 3648}, + {0x4ffa, 1334}, + {0x4ffe, 4165}, + {0x4fff, 8385}, + {0x5001, 0}, + {0x5005, 4159}, + {0x5006, 4168}, + {0x5009, 2772}, + {0x500b, 1912}, + {0x500d, 3346}, + {0x500f, 5632}, + {0x5011, 4167}, + {0x5012, 3159}, + {0x5014, 4156}, + {0x5016, 1962}, + {0x5019, 1961}, + {0x501a, 4154}, + {0x501e, 8386}, + {0x501f, 2310}, + {0x5021, 4162}, + {0x5022, 8384}, + {0x5023, 3647}, + {0x5024, 2955}, + {0x5025, 4158}, + {0x5026, 1863}, + {0x5028, 4155}, + {0x5029, 4163}, + {0x502a, 4157}, + {0x502b, 3993}, + {0x502c, 4164}, + {0x502d, 4071}, + {0x5036, 1758}, + {0x5039, 1862}, + {0x5040, 8383}, + {0x5042, 8389}, + {0x5043, 4169}, + {0x5046, 8387}, + {0x5047, 4170}, + {0x5048, 4174}, + {0x5049, 1170}, + {0x504f, 3616}, + {0x5050, 4173}, + {0x5055, 4172}, + {0x5056, 4176}, + {0x505a, 4175}, + {0x505c, 3072}, + {0x5065, 1864}, + {0x506c, 4177}, + {0x5070, 8388}, + {0x5072, 2289}, + {0x5074, 2822}, + {0x5075, 3073}, + {0x5076, 1774}, + {0x5078, 4178}, + {0x507d, 1616}, + {0x5080, 4179}, + {0x5085, 4181}, + {0x508d, 3683}, + {0x5091, 1852}, + {0x5094, 8390}, + {0x5098, 2175}, + {0x5099, 3467}, + {0x509a, 4180}, + {0x50ac, 2101}, + {0x50ad, 3885}, + {0x50b2, 4183}, + {0x50b3, 4186}, + {0x50b4, 4182}, + {0x50b5, 2100}, + {0x50b7, 2439}, + {0x50be, 1807}, + {0x50c2, 4187}, + {0x50c5, 1735}, + {0x50c9, 4184}, + {0x50ca, 4185}, + {0x50cd, 3207}, + {0x50cf, 2814}, + {0x50d1, 1691}, + {0x50d5, 3707}, + {0x50d6, 4188}, + {0x50d8, 8392}, + {0x50da, 3973}, + {0x50de, 4189}, + {0x50e3, 4192}, + {0x50e5, 4190}, + {0x50e7, 2768}, + {0x50ed, 4191}, + {0x50ee, 4193}, + {0x50f4, 8391}, + {0x50f5, 4195}, + {0x50f9, 4194}, + {0x50fb, 3608}, + {0x5100, 1617}, + {0x5101, 4197}, + {0x5102, 4198}, + {0x5104, 1327}, + {0x5109, 4196}, + {0x5112, 2336}, + {0x5114, 4201}, + {0x5115, 4200}, + {0x5116, 4199}, + {0x5118, 4143}, + {0x511a, 4202}, + {0x511f, 2440}, + {0x5121, 4203}, + {0x512a, 3855}, + {0x5132, 3813}, + {0x5137, 4205}, + {0x513a, 4204}, + {0x513b, 4207}, + {0x513c, 4206}, + {0x513f, 4208}, + {0x5140, 4209}, + {0x5141, 1208}, + {0x5143, 1897}, + {0x5144, 1809}, + {0x5145, 2374}, + {0x5146, 3001}, + {0x5147, 1692}, + {0x5148, 2700}, + {0x5149, 1963}, + {0x514a, 8393}, + {0x514b, 2048}, + {0x514c, 4211}, + {0x514d, 3796}, + {0x514e, 3136}, + {0x5150, 2247}, + {0x5152, 4210}, + {0x5154, 4212}, + {0x515a, 3160}, + {0x515c, 1491}, + {0x5162, 4213}, + {0x5164, 8394}, + {0x5165, 3286}, + {0x5168, 2742}, + {0x5169, 4215}, + {0x516a, 4216}, + {0x516b, 3392}, + {0x516c, 1964}, + {0x516d, 4065}, + {0x516e, 4217}, + {0x5171, 1694}, + {0x5175, 3596}, + {0x5176, 2838}, + {0x5177, 1769}, + {0x5178, 3119}, + {0x517c, 1865}, + {0x5180, 4218}, + {0x5182, 4219}, + {0x5185, 3258}, + {0x5186, 1281}, + {0x5189, 4222}, + {0x518a, 2157}, + {0x518c, 4221}, + {0x518d, 2102}, + {0x518f, 4223}, + {0x5190, 6235}, + {0x5191, 4224}, + {0x5192, 3695}, + {0x5193, 4225}, + {0x5195, 4226}, + {0x5196, 4227}, + {0x5197, 2513}, + {0x5199, 2296}, + {0x519d, 8395}, + {0x51a0, 1507}, + {0x51a2, 4230}, + {0x51a4, 4228}, + {0x51a5, 3785}, + {0x51a6, 4229}, + {0x51a8, 3532}, + {0x51a9, 4231}, + {0x51aa, 4232}, + {0x51ab, 4233}, + {0x51ac, 3161}, + {0x51b0, 4237}, + {0x51b1, 4235}, + {0x51b2, 4236}, + {0x51b3, 4234}, + {0x51b4, 2131}, + {0x51b5, 4238}, + {0x51b6, 3830}, + {0x51b7, 4012}, + {0x51bd, 4239}, + {0x51be, 8396}, + {0x51c4, 2636}, + {0x51c5, 4240}, + {0x51c6, 2404}, + {0x51c9, 4241}, + {0x51cb, 3002}, + {0x51cc, 3975}, + {0x51cd, 3162}, + {0x51d6, 4314}, + {0x51db, 4242}, + {0x51dc, 8284}, + {0x51dd, 1725}, + {0x51e0, 4243}, + {0x51e1, 3724}, + {0x51e6, 2418}, + {0x51e7, 2908}, + {0x51e9, 4245}, + {0x51ea, 3260}, + {0x51ec, 8397}, + {0x51ed, 4246}, + {0x51f0, 4247}, + {0x51f1, 1420}, + {0x51f5, 4248}, + {0x51f6, 1695}, + {0x51f8, 3236}, + {0x51f9, 1308}, + {0x51fa, 2394}, + {0x51fd, 3381}, + {0x51fe, 4249}, + {0x5200, 3163}, + {0x5202, 0}, + {0x5203, 2581}, + {0x5204, 4250}, + {0x5206, 3580}, + {0x5207, 2686}, + {0x5208, 1502}, + {0x520a, 1509}, + {0x520b, 4251}, + {0x520e, 4253}, + {0x5211, 1808}, + {0x5214, 4252}, + {0x5215, 8398}, + {0x5217, 4027}, + {0x521d, 2419}, + {0x5224, 3409}, + {0x5225, 3612}, + {0x5227, 4254}, + {0x5229, 3938}, + {0x522a, 4255}, + {0x522e, 4256}, + {0x5230, 3192}, + {0x5233, 4257}, + {0x5236, 2637}, + {0x5237, 2158}, + {0x5238, 1866}, + {0x5239, 4258}, + {0x523a, 2199}, + {0x523b, 2049}, + {0x5243, 3074}, + {0x5244, 4260}, + {0x5247, 2823}, + {0x524a, 2143}, + {0x524b, 4261}, + {0x524c, 4262}, + {0x524d, 2738}, + {0x524f, 4259}, + {0x5254, 4264}, + {0x5256, 3684}, + {0x525b, 2038}, + {0x525d, 7774}, + {0x525e, 4263}, + {0x5263, 1867}, + {0x5264, 2126}, + {0x5265, 3363}, + {0x5269, 4267}, + {0x526a, 4265}, + {0x526f, 3565}, + {0x5270, 2514}, + {0x5271, 4274}, + {0x5272, 1474}, + {0x5273, 4268}, + {0x5274, 4266}, + {0x5275, 2769}, + {0x527d, 4270}, + {0x527f, 4269}, + {0x5283, 1442}, + {0x5287, 1846}, + {0x5288, 4275}, + {0x5289, 3957}, + {0x528d, 4271}, + {0x5291, 4276}, + {0x5292, 4273}, + {0x5294, 4272}, + {0x529b, 3991}, + {0x529c, 8399}, + {0x529f, 1965}, + {0x52a0, 1347}, + {0x52a3, 4028}, + {0x52a6, 8400}, + {0x52a9, 2431}, + {0x52aa, 3154}, + {0x52ab, 2039}, + {0x52ac, 4279}, + {0x52ad, 4280}, + {0x52af, 8573}, + {0x52b1, 4013}, + {0x52b4, 4049}, + {0x52b5, 4282}, + {0x52b9, 1966}, + {0x52bc, 4281}, + {0x52be, 1421}, + {0x52c0, 8401}, + {0x52c1, 4283}, + {0x52c3, 3716}, + {0x52c5, 3032}, + {0x52c7, 3856}, + {0x52c9, 3625}, + {0x52cd, 4284}, + {0x52d2, 7150}, + {0x52d5, 3208}, + {0x52d7, 4285}, + {0x52d8, 1510}, + {0x52d9, 3775}, + {0x52db, 8402}, + {0x52dd, 2441}, + {0x52de, 4286}, + {0x52df, 3639}, + {0x52e0, 4290}, + {0x52e2, 2638}, + {0x52e3, 4287}, + {0x52e4, 1736}, + {0x52e6, 4288}, + {0x52e7, 1511}, + {0x52f2, 1796}, + {0x52f3, 4291}, + {0x52f5, 4292}, + {0x52f8, 4293}, + {0x52f9, 4294}, + {0x52fa, 2311}, + {0x52fe, 1967}, + {0x52ff, 3818}, + {0x5300, 8403}, + {0x5301, 3828}, + {0x5302, 3279}, + {0x5305, 3649}, + {0x5306, 4295}, + {0x5307, 8404}, + {0x5308, 4296}, + {0x530b, 0}, + {0x530d, 4298}, + {0x530f, 4300}, + {0x5310, 4299}, + {0x5315, 4301}, + {0x5316, 1341}, + {0x5317, 3706}, + {0x5319, 2156}, + {0x531a, 4302}, + {0x531d, 2779}, + {0x5320, 2442}, + {0x5321, 1697}, + {0x5323, 4303}, + {0x5324, 8405}, + {0x532a, 3439}, + {0x532f, 4304}, + {0x5331, 4305}, + {0x5333, 4306}, + {0x5338, 4307}, + {0x5339, 3478}, + {0x533a, 1760}, + {0x533b, 1193}, + {0x533f, 3223}, + {0x5340, 4308}, + {0x5341, 2375}, + {0x5343, 2701}, + {0x5345, 4310}, + {0x5346, 4309}, + {0x5347, 2443}, + {0x5348, 1941}, + {0x5349, 4312}, + {0x534a, 3410}, + {0x534d, 4313}, + {0x5351, 3440}, + {0x5352, 2836}, + {0x5353, 2894}, + {0x5354, 1696}, + {0x5357, 3270}, + {0x5358, 2927}, + {0x535a, 3364}, + {0x535c, 3708}, + {0x535e, 4315}, + {0x5360, 2702}, + {0x5366, 1803}, + {0x5369, 4316}, + {0x536e, 4317}, + {0x536f, 1230}, + {0x5370, 1209}, + {0x5371, 1577}, + {0x5372, 8406}, + {0x5373, 2824}, + {0x5374, 1643}, + {0x5375, 3931}, + {0x5377, 4320}, + {0x5378, 1335}, + {0x537b, 4319}, + {0x537f, 1698}, + {0x5382, 4321}, + {0x5384, 3837}, + {0x5393, 8407}, + {0x5396, 4322}, + {0x5398, 3994}, + {0x539a, 1968}, + {0x539f, 1898}, + {0x53a0, 4323}, + {0x53a5, 4325}, + {0x53a6, 4324}, + {0x53a8, 2597}, + {0x53a9, 1243}, + {0x53ad, 1280}, + {0x53ae, 4326}, + {0x53b0, 4327}, + {0x53b2, 8408}, + {0x53b3, 1899}, + {0x53b6, 4328}, + {0x53bb, 1672}, + {0x53c2, 2176}, + {0x53c3, 4329}, + {0x53c8, 3746}, + {0x53c9, 2085}, + {0x53ca, 1652}, + {0x53cb, 3857}, + {0x53cc, 2770}, + {0x53cd, 3411}, + {0x53ce, 2345}, + {0x53d4, 2385}, + {0x53d6, 2324}, + {0x53d7, 2337}, + {0x53d9, 2432}, + {0x53db, 3412}, + {0x53dd, 8409}, + {0x53df, 4332}, + {0x53e1, 1253}, + {0x53e2, 2771}, + {0x53e3, 1969}, + {0x53e4, 1913}, + {0x53e5, 1759}, + {0x53e8, 4336}, + {0x53e9, 2911}, + {0x53ea, 2910}, + {0x53eb, 1699}, + {0x53ec, 2444}, + {0x53ed, 4337}, + {0x53ee, 4335}, + {0x53ef, 1348}, + {0x53f0, 2886}, + {0x53f1, 2276}, + {0x53f2, 2201}, + {0x53f3, 1224}, + {0x53f6, 1486}, + {0x53f7, 2040}, + {0x53f8, 2200}, + {0x53fa, 4338}, + {0x5401, 4339}, + {0x5403, 1635}, + {0x5404, 1444}, + {0x5408, 2041}, + {0x5409, 1634}, + {0x540a, 3067}, + {0x540b, 1223}, + {0x540c, 3209}, + {0x540d, 3786}, + {0x540e, 1971}, + {0x540f, 3939}, + {0x5410, 3137}, + {0x5411, 1970}, + {0x541b, 1797}, + {0x541d, 4348}, + {0x541f, 1755}, + {0x5420, 3704}, + {0x5426, 3441}, + {0x5429, 4347}, + {0x542b, 1562}, + {0x542c, 4342}, + {0x542d, 4343}, + {0x542e, 4345}, + {0x5436, 4346}, + {0x5438, 1653}, + {0x5439, 2599}, + {0x543b, 3581}, + {0x543c, 4344}, + {0x543d, 4340}, + {0x543e, 1943}, + {0x5440, 4341}, + {0x5442, 4042}, + {0x5446, 3650}, + {0x5448, 3076}, + {0x5449, 1942}, + {0x544a, 2050}, + {0x544e, 4349}, + {0x5451, 3253}, + {0x545f, 4353}, + {0x5468, 2346}, + {0x546a, 2338}, + {0x5470, 4356}, + {0x5471, 4354}, + {0x5473, 3759}, + {0x5475, 4351}, + {0x5476, 4360}, + {0x5477, 4355}, + {0x547b, 4358}, + {0x547c, 1914}, + {0x547d, 3787}, + {0x5480, 4359}, + {0x5484, 4361}, + {0x5486, 4363}, + {0x548a, 8412}, + {0x548b, 2144}, + {0x548c, 4072}, + {0x548e, 4352}, + {0x548f, 4350}, + {0x5490, 4362}, + {0x5492, 4357}, + {0x549c, 8411}, + {0x54a2, 4365}, + {0x54a4, 4374}, + {0x54a5, 4367}, + {0x54a8, 4371}, + {0x54a9, 8413}, + {0x54ab, 4372}, + {0x54ac, 4368}, + {0x54af, 4401}, + {0x54b2, 2137}, + {0x54b3, 1423}, + {0x54b8, 4366}, + {0x54bc, 4376}, + {0x54bd, 1210}, + {0x54be, 4375}, + {0x54c0, 1129}, + {0x54c1, 3516}, + {0x54c2, 4373}, + {0x54c4, 4369}, + {0x54c7, 4364}, + {0x54c8, 4370}, + {0x54c9, 2104}, + {0x54d8, 4377}, + {0x54e1, 1211}, + {0x54e2, 4386}, + {0x54e5, 4378}, + {0x54e6, 4379}, + {0x54e8, 2445}, + {0x54e9, 3735}, + {0x54ed, 4384}, + {0x54ee, 4383}, + {0x54f2, 3113}, + {0x54fa, 4385}, + {0x54fd, 4382}, + {0x54ff, 8414}, + {0x5504, 1238}, + {0x5506, 2086}, + {0x5507, 2550}, + {0x550f, 4380}, + {0x5510, 3164}, + {0x5514, 4381}, + {0x5516, 1126}, + {0x552e, 4391}, + {0x552f, 3853}, + {0x5531, 2447}, + {0x5533, 4397}, + {0x5538, 4396}, + {0x5539, 4387}, + {0x553e, 2851}, + {0x5540, 4388}, + {0x5544, 2895}, + {0x5545, 4393}, + {0x5546, 2446}, + {0x554c, 4390}, + {0x554f, 3824}, + {0x5553, 1810}, + {0x5556, 4394}, + {0x5557, 4395}, + {0x555c, 4392}, + {0x555d, 4398}, + {0x555e, 7633}, + {0x5561, 0}, + {0x5563, 4389}, + {0x557b, 4404}, + {0x557c, 4409}, + {0x557e, 4405}, + {0x5580, 4400}, + {0x5583, 4410}, + {0x5584, 2739}, + {0x5586, 8415}, + {0x5587, 4412}, + {0x5589, 1972}, + {0x558a, 4402}, + {0x558b, 3003}, + {0x5598, 4406}, + {0x5599, 4399}, + {0x559a, 1513}, + {0x559c, 1578}, + {0x559d, 1475}, + {0x559e, 4407}, + {0x559f, 4403}, + {0x55a7, 1868}, + {0x55a8, 4413}, + {0x55a9, 4411}, + {0x55aa, 2773}, + {0x55ab, 1636}, + {0x55ac, 1700}, + {0x55ae, 4408}, + {0x55b0, 1772}, + {0x55b6, 1254}, + {0x55c4, 4417}, + {0x55c5, 4415}, + {0x55c7, 4472}, + {0x55d4, 4420}, + {0x55da, 4414}, + {0x55dc, 4418}, + {0x55df, 4416}, + {0x55e3, 2202}, + {0x55e4, 4419}, + {0x55f7, 4422}, + {0x55f9, 4427}, + {0x55fd, 4425}, + {0x55fe, 4424}, + {0x5606, 2928}, + {0x5609, 1349}, + {0x560f, 0}, + {0x5614, 4421}, + {0x5616, 4423}, + {0x5617, 2448}, + {0x5618, 1237}, + {0x561b, 4426}, + {0x5629, 1374}, + {0x562f, 4437}, + {0x5631, 2532}, + {0x5632, 4433}, + {0x5634, 4431}, + {0x5636, 4432}, + {0x5638, 4434}, + {0x5642, 1247}, + {0x564c, 2747}, + {0x564e, 4428}, + {0x5650, 4429}, + {0x5653, 7963}, + {0x565b, 1496}, + {0x5664, 4436}, + {0x5668, 1579}, + {0x566a, 4439}, + {0x566b, 4435}, + {0x566c, 4438}, + {0x5672, 0}, + {0x5674, 3582}, + {0x5678, 3245}, + {0x567a, 3404}, + {0x5680, 4441}, + {0x5686, 4440}, + {0x5687, 1443}, + {0x568a, 4442}, + {0x568f, 4445}, + {0x5694, 4444}, + {0x5699, 7654}, + {0x56a0, 4443}, + {0x56a2, 3311}, + {0x56a5, 4446}, + {0x56ad, 0}, + {0x56ae, 4447}, + {0x56b4, 4449}, + {0x56b6, 4448}, + {0x56bc, 4451}, + {0x56c0, 4454}, + {0x56c1, 4452}, + {0x56c2, 4450}, + {0x56c3, 4453}, + {0x56c8, 4455}, + {0x56ca, 7770}, + {0x56ce, 4456}, + {0x56d1, 4457}, + {0x56d3, 4458}, + {0x56d7, 4459}, + {0x56d8, 4220}, + {0x56da, 2344}, + {0x56db, 2203}, + {0x56de, 1395}, + {0x56e0, 1212}, + {0x56e3, 2946}, + {0x56ee, 4460}, + {0x56f0, 2068}, + {0x56f2, 1171}, + {0x56f3, 2596}, + {0x56f9, 4461}, + {0x56fa, 1915}, + {0x56fd, 2051}, + {0x56ff, 4463}, + {0x5700, 4462}, + {0x5703, 3632}, + {0x5704, 4464}, + {0x5708, 4466}, + {0x5709, 4465}, + {0x570b, 4467}, + {0x570d, 4468}, + {0x570f, 1869}, + {0x5712, 1282}, + {0x5713, 4469}, + {0x5716, 4471}, + {0x5718, 4470}, + {0x571c, 4473}, + {0x571f, 3156}, + {0x5726, 4474}, + {0x5727, 1145}, + {0x5728, 2127}, + {0x572d, 1811}, + {0x5730, 2957}, + {0x5734, 0}, + {0x5737, 4475}, + {0x5738, 4476}, + {0x573b, 4478}, + {0x5740, 4479}, + {0x5742, 2132}, + {0x5747, 1737}, + {0x574a, 3685}, + {0x574e, 4477}, + {0x574f, 4480}, + {0x5750, 2097}, + {0x5751, 1973}, + {0x5759, 8416}, + {0x5761, 4484}, + {0x5764, 2069}, + {0x5765, 8417}, + {0x5766, 2929}, + {0x5769, 4481}, + {0x576a, 3062}, + {0x577f, 4485}, + {0x5782, 2600}, + {0x5788, 4483}, + {0x5789, 4486}, + {0x578b, 1813}, + {0x5793, 4487}, + {0x57a0, 4488}, + {0x57a2, 1974}, + {0x57a3, 1438}, + {0x57a4, 4490}, + {0x57aa, 4491}, + {0x57ac, 8418}, + {0x57b0, 4492}, + {0x57b3, 4489}, + {0x57c0, 4482}, + {0x57c3, 4493}, + {0x57c6, 4494}, + {0x57c7, 8420}, + {0x57c8, 8419}, + {0x57cb, 3730}, + {0x57ce, 2515}, + {0x57d2, 4496}, + {0x57d3, 4497}, + {0x57d4, 4495}, + {0x57d6, 4499}, + {0x57dc, 3310}, + {0x57df, 1196}, + {0x57e0, 3528}, + {0x57e3, 4500}, + {0x57f4, 2533}, + {0x57f6, 0}, + {0x57f7, 2277}, + {0x57f9, 3347}, + {0x57fa, 1580}, + {0x57fc, 2139}, + {0x5800, 3719}, + {0x5802, 3210}, + {0x5805, 1870}, + {0x5806, 2863}, + {0x580a, 4498}, + {0x580b, 4501}, + {0x5815, 2852}, + {0x5819, 4502}, + {0x581d, 4503}, + {0x5821, 4505}, + {0x5824, 3077}, + {0x582a, 1514}, + {0x582f, 7474}, + {0x5830, 1283}, + {0x5831, 3651}, + {0x5834, 2516}, + {0x5835, 3138}, + {0x583a, 2134}, + {0x583d, 4511}, + {0x5840, 3597}, + {0x5841, 4005}, + {0x584a, 1396}, + {0x584b, 4507}, + {0x5851, 2748}, + {0x5852, 4510}, + {0x5854, 3165}, + {0x5857, 3139}, + {0x5858, 3166}, + {0x5859, 3405}, + {0x585a, 3049}, + {0x585e, 2105}, + {0x5861, 7751}, + {0x5862, 4506}, + {0x5869, 1304}, + {0x586b, 3120}, + {0x5870, 4508}, + {0x5872, 4504}, + {0x5875, 2582}, + {0x5879, 4512}, + {0x587e, 2392}, + {0x5883, 1701}, + {0x5885, 4513}, + {0x5893, 3640}, + {0x5897, 2815}, + {0x589c, 3042}, + {0x589e, 8423}, + {0x589f, 4515}, + {0x58a8, 3709}, + {0x58ab, 4516}, + {0x58ae, 4521}, + {0x58b2, 8424}, + {0x58b3, 3583}, + {0x58b8, 4520}, + {0x58b9, 4514}, + {0x58ba, 4517}, + {0x58bb, 4519}, + {0x58be, 2070}, + {0x58c1, 3609}, + {0x58c5, 4522}, + {0x58c7, 2947}, + {0x58ca, 1397}, + {0x58cc, 2517}, + {0x58d1, 4524}, + {0x58d3, 4523}, + {0x58d5, 2042}, + {0x58d7, 4525}, + {0x58d8, 4527}, + {0x58d9, 4526}, + {0x58dc, 4529}, + {0x58de, 4518}, + {0x58df, 4531}, + {0x58e4, 4530}, + {0x58e5, 4528}, + {0x58eb, 2204}, + {0x58ec, 2583}, + {0x58ee, 2774}, + {0x58ef, 4532}, + {0x58f0, 2656}, + {0x58f1, 1201}, + {0x58f2, 3354}, + {0x58f7, 3063}, + {0x58f9, 4534}, + {0x58fa, 4533}, + {0x58fb, 4535}, + {0x58fc, 4536}, + {0x58fd, 4537}, + {0x5902, 4538}, + {0x5909, 3617}, + {0x590a, 4539}, + {0x590b, 8425}, + {0x590f, 1350}, + {0x5910, 4540}, + {0x5915, 3878}, + {0x5916, 1422}, + {0x5918, 4318}, + {0x5919, 2386}, + {0x591a, 2847}, + {0x591b, 4541}, + {0x591c, 3831}, + {0x5922, 3776}, + {0x5925, 4543}, + {0x5927, 2887}, + {0x5929, 3121}, + {0x592a, 2848}, + {0x592b, 3529}, + {0x592c, 4544}, + {0x592d, 4545}, + {0x592e, 1309}, + {0x5931, 2278}, + {0x5932, 4546}, + {0x5937, 1172}, + {0x5938, 4547}, + {0x593e, 4548}, + {0x5944, 1284}, + {0x5947, 1581}, + {0x5948, 3256}, + {0x5949, 3652}, + {0x594e, 4552}, + {0x594f, 2775}, + {0x5950, 4551}, + {0x5951, 1814}, + {0x5953, 8426}, + {0x5954, 3721}, + {0x5955, 4550}, + {0x5957, 3167}, + {0x5958, 4554}, + {0x595a, 4553}, + {0x595b, 8427}, + {0x595d, 8428}, + {0x5960, 4556}, + {0x5962, 4555}, + {0x5963, 8429}, + {0x5965, 1310}, + {0x5967, 4557}, + {0x5968, 2449}, + {0x5969, 4559}, + {0x596a, 2915}, + {0x596c, 4558}, + {0x596e, 3587}, + {0x5973, 2433}, + {0x5974, 3157}, + {0x5978, 4560}, + {0x597d, 1975}, + {0x5981, 4561}, + {0x5982, 3287}, + {0x5983, 3442}, + {0x5984, 3805}, + {0x598a, 3291}, + {0x598d, 4570}, + {0x5993, 1618}, + {0x5996, 3887}, + {0x5999, 3771}, + {0x599b, 4665}, + {0x599d, 4562}, + {0x59a3, 4565}, + {0x59a4, 8430}, + {0x59a5, 2853}, + {0x59a8, 3686}, + {0x59ac, 3140}, + {0x59b2, 4566}, + {0x59b9, 3731}, + {0x59ba, 8431}, + {0x59bb, 2106}, + {0x59be, 2450}, + {0x59c6, 4567}, + {0x59c9, 2206}, + {0x59cb, 2205}, + {0x59d0, 1149}, + {0x59d1, 1916}, + {0x59d3, 2639}, + {0x59d4, 1173}, + {0x59d9, 4571}, + {0x59da, 4572}, + {0x59dc, 4569}, + {0x59e4, 0}, + {0x59e5, 1242}, + {0x59e6, 1515}, + {0x59e8, 4568}, + {0x59ea, 3793}, + {0x59eb, 3491}, + {0x59f6, 1132}, + {0x59fb, 1213}, + {0x59ff, 2207}, + {0x5a01, 1174}, + {0x5a03, 1127}, + {0x5a09, 4577}, + {0x5a11, 4575}, + {0x5a18, 3784}, + {0x5a1a, 4578}, + {0x5a1c, 4576}, + {0x5a1f, 4574}, + {0x5a20, 2551}, + {0x5a25, 4573}, + {0x5a29, 3626}, + {0x5a2f, 1944}, + {0x5a35, 4582}, + {0x5a36, 4583}, + {0x5a3c, 2451}, + {0x5a40, 4579}, + {0x5a41, 4050}, + {0x5a46, 3330}, + {0x5a49, 4581}, + {0x5a5a, 2071}, + {0x5a62, 4584}, + {0x5a66, 3530}, + {0x5a6a, 4585}, + {0x5a6c, 4580}, + {0x5a7f, 3783}, + {0x5a92, 3348}, + {0x5a9a, 4586}, + {0x5a9b, 3492}, + {0x5abc, 4587}, + {0x5abd, 4591}, + {0x5abe, 4588}, + {0x5ac1, 1351}, + {0x5ac2, 4590}, + {0x5ac9, 2279}, + {0x5acb, 4589}, + {0x5acc, 1871}, + {0x5ad0, 4603}, + {0x5ad6, 4596}, + {0x5ad7, 4593}, + {0x5ae1, 2978}, + {0x5ae3, 4592}, + {0x5ae6, 4594}, + {0x5ae9, 4595}, + {0x5afa, 4597}, + {0x5afb, 4598}, + {0x5b09, 1582}, + {0x5b0b, 4600}, + {0x5b0c, 4599}, + {0x5b16, 4601}, + {0x5b22, 2518}, + {0x5b2a, 4604}, + {0x5b2c, 3064}, + {0x5b30, 1255}, + {0x5b32, 4602}, + {0x5b36, 4605}, + {0x5b3e, 4606}, + {0x5b40, 4609}, + {0x5b43, 4607}, + {0x5b45, 4608}, + {0x5b50, 2208}, + {0x5b51, 4610}, + {0x5b54, 1976}, + {0x5b55, 4611}, + {0x5b56, 8432}, + {0x5b57, 2248}, + {0x5b58, 2840}, + {0x5b5a, 4612}, + {0x5b5b, 4613}, + {0x5b5c, 2216}, + {0x5b5d, 1977}, + {0x5b5f, 3806}, + {0x5b63, 1602}, + {0x5b64, 1917}, + {0x5b65, 4614}, + {0x5b66, 1462}, + {0x5b69, 4615}, + {0x5b6b, 2841}, + {0x5b70, 4616}, + {0x5b71, 4656}, + {0x5b73, 4617}, + {0x5b75, 4618}, + {0x5b78, 4619}, + {0x5b7a, 4621}, + {0x5b7f, 0}, + {0x5b80, 4622}, + {0x5b83, 4623}, + {0x5b85, 2896}, + {0x5b87, 1225}, + {0x5b88, 2325}, + {0x5b89, 1158}, + {0x5b8b, 2777}, + {0x5b8c, 1516}, + {0x5b8d, 2273}, + {0x5b8f, 1978}, + {0x5b95, 3168}, + {0x5b97, 2347}, + {0x5b98, 1517}, + {0x5b99, 2982}, + {0x5b9a, 3078}, + {0x5b9b, 1148}, + {0x5b9c, 1619}, + {0x5b9d, 3653}, + {0x5b9f, 2286}, + {0x5ba2, 1644}, + {0x5ba3, 2703}, + {0x5ba4, 2280}, + {0x5ba5, 3858}, + {0x5ba6, 4624}, + {0x5bae, 1654}, + {0x5bb0, 2107}, + {0x5bb3, 1424}, + {0x5bb4, 1285}, + {0x5bb5, 2452}, + {0x5bb6, 1352}, + {0x5bb8, 4625}, + {0x5bb9, 3888}, + {0x5bbf, 2387}, + {0x5bc0, 8433}, + {0x5bc2, 2320}, + {0x5bc3, 4626}, + {0x5bc4, 1583}, + {0x5bc5, 3242}, + {0x5bc6, 3765}, + {0x5bc7, 4627}, + {0x5bc9, 4628}, + {0x5bcc, 3531}, + {0x5bd0, 4630}, + {0x5bd2, 1508}, + {0x5bd3, 1775}, + {0x5bd4, 4629}, + {0x5bd8, 8435}, + {0x5bdb, 1518}, + {0x5bdd, 2552}, + {0x5bde, 4634}, + {0x5bdf, 2159}, + {0x5be1, 1353}, + {0x5be2, 4633}, + {0x5be4, 4631}, + {0x5be5, 4635}, + {0x5be6, 4632}, + {0x5be7, 3297}, + {0x5be8, 5262}, + {0x5be9, 2553}, + {0x5beb, 4636}, + {0x5bec, 8436}, + {0x5bee, 3976}, + {0x5bf0, 4637}, + {0x5bf3, 4639}, + {0x5bf5, 3004}, + {0x5bf6, 4638}, + {0x5bf8, 2631}, + {0x5bfa, 2249}, + {0x5bfe, 2864}, + {0x5bff, 2339}, + {0x5c01, 3559}, + {0x5c02, 2704}, + {0x5c04, 2297}, + {0x5c05, 4640}, + {0x5c06, 2453}, + {0x5c07, 4641}, + {0x5c08, 4642}, + {0x5c09, 1175}, + {0x5c0a, 2842}, + {0x5c0b, 2584}, + {0x5c0d, 4643}, + {0x5c0e, 3211}, + {0x5c0f, 2454}, + {0x5c11, 2455}, + {0x5c13, 4644}, + {0x5c16, 2705}, + {0x5c1a, 2456}, + {0x5c1e, 8437}, + {0x5c20, 4645}, + {0x5c22, 4646}, + {0x5c24, 3820}, + {0x5c28, 4647}, + {0x5c2d, 1726}, + {0x5c31, 2348}, + {0x5c38, 4648}, + {0x5c39, 4649}, + {0x5c3a, 2312}, + {0x5c3b, 2546}, + {0x5c3c, 3276}, + {0x5c3d, 2586}, + {0x5c3e, 3468}, + {0x5c3f, 3288}, + {0x5c40, 1729}, + {0x5c41, 4650}, + {0x5c45, 1673}, + {0x5c46, 4651}, + {0x5c48, 1782}, + {0x5c4a, 3239}, + {0x5c4b, 1328}, + {0x5c4d, 2209}, + {0x5c4e, 4652}, + {0x5c4f, 4655}, + {0x5c50, 4654}, + {0x5c51, 1781}, + {0x5c53, 4653}, + {0x5c55, 3122}, + {0x5c5b, 7826}, + {0x5c5e, 2832}, + {0x5c60, 3141}, + {0x5c61, 2292}, + {0x5c62, 7693}, + {0x5c64, 2778}, + {0x5c65, 3940}, + {0x5c6c, 4657}, + {0x5c6e, 4658}, + {0x5c6f, 3246}, + {0x5c71, 2177}, + {0x5c76, 4660}, + {0x5c79, 4661}, + {0x5c8c, 4662}, + {0x5c90, 1584}, + {0x5c91, 4663}, + {0x5c94, 4664}, + {0x5ca1, 1324}, + {0x5ca6, 8438}, + {0x5ca8, 2749}, + {0x5ca9, 1568}, + {0x5cab, 4666}, + {0x5cac, 3764}, + {0x5cb1, 2866}, + {0x5cb3, 1463}, + {0x5cb6, 4668}, + {0x5cb7, 4670}, + {0x5cb8, 1563}, + {0x5cba, 8439}, + {0x5cbb, 4667}, + {0x5cbc, 4669}, + {0x5cbe, 4672}, + {0x5cc5, 4671}, + {0x5cc7, 4673}, + {0x5cd9, 4674}, + {0x5ce0, 3221}, + {0x5ce1, 1702}, + {0x5ce8, 1381}, + {0x5ce9, 4675}, + {0x5cea, 4680}, + {0x5ced, 4678}, + {0x5cef, 3655}, + {0x5cf0, 3654}, + {0x5cf5, 8440}, + {0x5cf6, 3169}, + {0x5cfa, 4677}, + {0x5cfb, 2398}, + {0x5cfd, 4676}, + {0x5d07, 2616}, + {0x5d0b, 4681}, + {0x5d0e, 2138}, + {0x5d11, 4687}, + {0x5d14, 4688}, + {0x5d15, 4682}, + {0x5d16, 1425}, + {0x5d17, 4683}, + {0x5d18, 4692}, + {0x5d19, 4691}, + {0x5d1a, 4690}, + {0x5d1b, 4686}, + {0x5d1f, 4685}, + {0x5d22, 4689}, + {0x5d27, 8441}, + {0x5d29, 3656}, + {0x5d42, 8444}, + {0x5d4b, 4696}, + {0x5d4c, 4693}, + {0x5d4e, 4695}, + {0x5d50, 3932}, + {0x5d52, 4694}, + {0x5d53, 8442}, + {0x5d5c, 4684}, + {0x5d69, 2617}, + {0x5d6c, 4697}, + {0x5d6d, 8445}, + {0x5d6f, 2087}, + {0x5d73, 4698}, + {0x5d76, 4699}, + {0x5d82, 4702}, + {0x5d84, 4701}, + {0x5d87, 4700}, + {0x5d8b, 3170}, + {0x5d8c, 4679}, + {0x5d90, 4708}, + {0x5d9d, 4704}, + {0x5da2, 4703}, + {0x5dac, 4705}, + {0x5dae, 4706}, + {0x5db7, 4709}, + {0x5db8, 8446}, + {0x5db9, 8447}, + {0x5dba, 4014}, + {0x5dbc, 4710}, + {0x5dbd, 4707}, + {0x5dc9, 4711}, + {0x5dcc, 1564}, + {0x5dcd, 4712}, + {0x5dd0, 8448}, + {0x5dd2, 4714}, + {0x5dd3, 4713}, + {0x5dd6, 4715}, + {0x5ddb, 4716}, + {0x5ddd, 2706}, + {0x5dde, 2349}, + {0x5de1, 2414}, + {0x5de3, 2789}, + {0x5de5, 1979}, + {0x5de6, 2088}, + {0x5de7, 1980}, + {0x5de8, 1674}, + {0x5deb, 4717}, + {0x5dee, 2089}, + {0x5df1, 1918}, + {0x5df2, 4718}, + {0x5df3, 3762}, + {0x5df4, 3321}, + {0x5df5, 4719}, + {0x5df7, 1981}, + {0x5dfb, 1512}, + {0x5dfd, 2917}, + {0x5dfe, 1738}, + {0x5e02, 2210}, + {0x5e03, 3533}, + {0x5e06, 3413}, + {0x5e0b, 4720}, + {0x5e0c, 1585}, + {0x5e11, 4723}, + {0x5e15, 0}, + {0x5e16, 3005}, + {0x5e19, 4722}, + {0x5e1a, 4721}, + {0x5e1b, 4724}, + {0x5e1d, 3079}, + {0x5e25, 2601}, + {0x5e2b, 2211}, + {0x5e2d, 2670}, + {0x5e2f, 2867}, + {0x5e30, 1596}, + {0x5e33, 3006}, + {0x5e36, 4725}, + {0x5e37, 4726}, + {0x5e38, 2519}, + {0x5e3d, 3687}, + {0x5e40, 4729}, + {0x5e43, 4728}, + {0x5e44, 4727}, + {0x5e45, 3567}, + {0x5e47, 4736}, + {0x5e4c, 3720}, + {0x5e4e, 4730}, + {0x5e54, 4732}, + {0x5e55, 3737}, + {0x5e57, 4731}, + {0x5e5f, 4733}, + {0x5e61, 3388}, + {0x5e62, 4734}, + {0x5e63, 3598}, + {0x5e64, 4735}, + {0x5e6c, 0}, + {0x5e72, 1519}, + {0x5e73, 3599}, + {0x5e74, 3301}, + {0x5e75, 4737}, + {0x5e76, 4738}, + {0x5e78, 1982}, + {0x5e79, 1520}, + {0x5e7a, 4739}, + {0x5e7b, 1900}, + {0x5e7c, 3886}, + {0x5e7d, 3859}, + {0x5e7e, 1586}, + {0x5e7f, 4741}, + {0x5e81, 3007}, + {0x5e83, 1983}, + {0x5e84, 2457}, + {0x5e87, 3443}, + {0x5e8a, 2458}, + {0x5e8f, 2434}, + {0x5e95, 3080}, + {0x5e96, 3657}, + {0x5e97, 3123}, + {0x5e9a, 1984}, + {0x5e9c, 3534}, + {0x5ea0, 4742}, + {0x5ea6, 3155}, + {0x5ea7, 2098}, + {0x5eab, 1919}, + {0x5ead, 3081}, + {0x5eb5, 1159}, + {0x5eb6, 2424}, + {0x5eb7, 1985}, + {0x5eb8, 3889}, + {0x5ebf, 0}, + {0x5ec1, 4743}, + {0x5ec2, 4744}, + {0x5ec3, 3335}, + {0x5ec8, 4745}, + {0x5ec9, 4031}, + {0x5eca, 4051}, + {0x5ecf, 4747}, + {0x5ed0, 4746}, + {0x5ed3, 1445}, + {0x5ed6, 4748}, + {0x5eda, 4751}, + {0x5edb, 4752}, + {0x5edd, 4750}, + {0x5edf, 3506}, + {0x5ee0, 2459}, + {0x5ee1, 4754}, + {0x5ee2, 4753}, + {0x5ee3, 4749}, + {0x5ee8, 4755}, + {0x5ee9, 4756}, + {0x5eec, 4757}, + {0x5ef0, 4760}, + {0x5ef1, 4758}, + {0x5ef3, 4759}, + {0x5ef4, 4761}, + {0x5ef6, 1286}, + {0x5ef7, 3082}, + {0x5ef8, 4762}, + {0x5efa, 1872}, + {0x5efb, 1398}, + {0x5efc, 3308}, + {0x5efe, 4763}, + {0x5eff, 3283}, + {0x5f01, 3627}, + {0x5f03, 4764}, + {0x5f04, 4052}, + {0x5f09, 4765}, + {0x5f0a, 3600}, + {0x5f0b, 4768}, + {0x5f0c, 4090}, + {0x5f0d, 4106}, + {0x5f0f, 2268}, + {0x5f10, 3277}, + {0x5f11, 4769}, + {0x5f13, 1655}, + {0x5f14, 3008}, + {0x5f15, 1214}, + {0x5f16, 4770}, + {0x5f17, 3574}, + {0x5f18, 1986}, + {0x5f1b, 2958}, + {0x5f1d, 0}, + {0x5f1f, 3083}, + {0x5f21, 8449}, + {0x5f25, 3835}, + {0x5f26, 1901}, + {0x5f27, 1920}, + {0x5f29, 4771}, + {0x5f2d, 4772}, + {0x5f2f, 4778}, + {0x5f31, 2321}, + {0x5f34, 8450}, + {0x5f35, 3009}, + {0x5f37, 1703}, + {0x5f38, 4773}, + {0x5f3c, 3485}, + {0x5f3e, 2948}, + {0x5f41, 4774}, + {0x5f45, 8370}, + {0x5f48, 4775}, + {0x5f4a, 1704}, + {0x5f4c, 4776}, + {0x5f4e, 4777}, + {0x5f51, 4779}, + {0x5f53, 3184}, + {0x5f56, 4780}, + {0x5f57, 4781}, + {0x5f59, 4782}, + {0x5f5c, 4767}, + {0x5f5d, 4766}, + {0x5f61, 4783}, + {0x5f62, 1815}, + {0x5f66, 3481}, + {0x5f67, 8451}, + {0x5f69, 2108}, + {0x5f6a, 3497}, + {0x5f6b, 3010}, + {0x5f6c, 3517}, + {0x5f6d, 4784}, + {0x5f70, 2460}, + {0x5f71, 1256}, + {0x5f73, 4785}, + {0x5f77, 4786}, + {0x5f79, 3838}, + {0x5f7c, 3444}, + {0x5f7f, 4789}, + {0x5f80, 1311}, + {0x5f81, 2640}, + {0x5f82, 4788}, + {0x5f83, 4787}, + {0x5f84, 1816}, + {0x5f85, 2868}, + {0x5f87, 4793}, + {0x5f88, 4791}, + {0x5f8a, 4790}, + {0x5f8b, 3951}, + {0x5f8c, 1945}, + {0x5f90, 2435}, + {0x5f91, 4792}, + {0x5f92, 3142}, + {0x5f93, 2376}, + {0x5f97, 3224}, + {0x5f98, 4796}, + {0x5f99, 4795}, + {0x5f9e, 4794}, + {0x5fa0, 4797}, + {0x5fa1, 1946}, + {0x5fa8, 4798}, + {0x5fa9, 3566}, + {0x5faa, 2405}, + {0x5fad, 4799}, + {0x5fae, 3469}, + {0x5fb3, 3225}, + {0x5fb4, 3011}, + {0x5fb7, 8452}, + {0x5fb9, 3114}, + {0x5fbc, 4800}, + {0x5fbd, 1605}, + {0x5fc3, 2554}, + {0x5fc5, 3486}, + {0x5fcc, 1587}, + {0x5fcd, 3292}, + {0x5fd6, 4801}, + {0x5fd7, 2212}, + {0x5fd8, 3688}, + {0x5fd9, 3689}, + {0x5fdc, 1312}, + {0x5fdd, 4806}, + {0x5fde, 8453}, + {0x5fe0, 2983}, + {0x5fe4, 4803}, + {0x5feb, 1399}, + {0x5ff0, 4854}, + {0x5ff1, 4805}, + {0x5ff5, 3302}, + {0x5ff8, 4804}, + {0x5ffb, 4802}, + {0x5ffd, 2060}, + {0x5fff, 4808}, + {0x600e, 4814}, + {0x600f, 4820}, + {0x6010, 4812}, + {0x6012, 3158}, + {0x6015, 4817}, + {0x6016, 3535}, + {0x6019, 4811}, + {0x601b, 4816}, + {0x601c, 4015}, + {0x601d, 2213}, + {0x6020, 2869}, + {0x6021, 4809}, + {0x6025, 1656}, + {0x6026, 4819}, + {0x6027, 2641}, + {0x6028, 1287}, + {0x6029, 4813}, + {0x602a, 1400}, + {0x602b, 4818}, + {0x602f, 1705}, + {0x6031, 4815}, + {0x603a, 4821}, + {0x6041, 4823}, + {0x6042, 4833}, + {0x6043, 4831}, + {0x6046, 4828}, + {0x604a, 4827}, + {0x604b, 4032}, + {0x604d, 4829}, + {0x6050, 1706}, + {0x6052, 1987}, + {0x6055, 2436}, + {0x6059, 4836}, + {0x605a, 4822}, + {0x605d, 8454}, + {0x605f, 4826}, + {0x6060, 4810}, + {0x6062, 1402}, + {0x6063, 4830}, + {0x6064, 4832}, + {0x6065, 2959}, + {0x6068, 2072}, + {0x6069, 1336}, + {0x606a, 4824}, + {0x606b, 4835}, + {0x606c, 4834}, + {0x606d, 1707}, + {0x606f, 2825}, + {0x6070, 1476}, + {0x6075, 1817}, + {0x6077, 4825}, + {0x6081, 4837}, + {0x6083, 4840}, + {0x6084, 4842}, + {0x6085, 8455}, + {0x6089, 2281}, + {0x608a, 8456}, + {0x608b, 4848}, + {0x608c, 3084}, + {0x608d, 4838}, + {0x6092, 4846}, + {0x6094, 1401}, + {0x6096, 4844}, + {0x6097, 4845}, + {0x609a, 4841}, + {0x609b, 4843}, + {0x609f, 1947}, + {0x60a0, 3860}, + {0x60a3, 1521}, + {0x60a6, 1275}, + {0x60a7, 4847}, + {0x60a9, 3312}, + {0x60aa, 1137}, + {0x60b2, 3445}, + {0x60b3, 4807}, + {0x60b4, 4853}, + {0x60b5, 4857}, + {0x60b6, 3825}, + {0x60b8, 4850}, + {0x60bc, 3171}, + {0x60bd, 4855}, + {0x60c5, 2520}, + {0x60c6, 4856}, + {0x60c7, 3247}, + {0x60d1, 4077}, + {0x60d3, 4852}, + {0x60d5, 8458}, + {0x60d8, 4858}, + {0x60da, 2061}, + {0x60dc, 2671}, + {0x60de, 8457}, + {0x60df, 1176}, + {0x60e0, 4851}, + {0x60e1, 4849}, + {0x60e3, 2780}, + {0x60e7, 4839}, + {0x60e8, 2178}, + {0x60f0, 2854}, + {0x60f1, 4870}, + {0x60f2, 8460}, + {0x60f3, 2781}, + {0x60f4, 4865}, + {0x60f6, 4862}, + {0x60f7, 4863}, + {0x60f9, 2322}, + {0x60fa, 4866}, + {0x60fb, 4869}, + {0x6100, 4864}, + {0x6101, 2351}, + {0x6103, 4867}, + {0x6106, 4861}, + {0x6108, 3848}, + {0x6109, 3847}, + {0x610d, 4871}, + {0x610e, 4872}, + {0x610f, 1177}, + {0x6111, 8461}, + {0x6113, 0}, + {0x6114, 1}, + {0x6115, 4860}, + {0x611a, 1770}, + {0x611b, 1130}, + {0x611f, 1522}, + {0x6120, 8459}, + {0x6121, 4868}, + {0x6127, 4876}, + {0x6128, 4875}, + {0x612c, 4880}, + {0x6130, 8463}, + {0x6134, 4881}, + {0x6137, 8462}, + {0x613c, 4879}, + {0x613d, 4882}, + {0x613e, 4874}, + {0x613f, 4878}, + {0x6142, 4883}, + {0x6144, 4884}, + {0x6147, 4873}, + {0x6148, 2250}, + {0x614a, 4877}, + {0x614b, 2870}, + {0x614c, 1988}, + {0x614d, 4859}, + {0x614e, 2555}, + {0x6153, 4897}, + {0x6155, 3641}, + {0x6158, 4887}, + {0x6159, 4888}, + {0x615a, 4889}, + {0x615d, 4896}, + {0x615f, 4895}, + {0x6162, 3755}, + {0x6163, 1523}, + {0x6165, 4893}, + {0x6167, 1819}, + {0x6168, 1426}, + {0x616b, 4890}, + {0x616e, 3968}, + {0x616f, 4892}, + {0x6170, 1178}, + {0x6171, 4894}, + {0x6173, 4885}, + {0x6174, 4891}, + {0x6175, 4898}, + {0x6176, 1818}, + {0x6177, 4886}, + {0x617e, 3911}, + {0x6182, 3861}, + {0x6187, 4901}, + {0x618a, 4905}, + {0x618e, 2816}, + {0x6190, 4033}, + {0x6191, 4906}, + {0x6194, 4903}, + {0x6196, 4900}, + {0x6198, 8464}, + {0x6199, 4899}, + {0x619a, 4904}, + {0x61a4, 3584}, + {0x61a7, 3212}, + {0x61a9, 1820}, + {0x61ab, 4907}, + {0x61ac, 4902}, + {0x61ae, 4908}, + {0x61b2, 1873}, + {0x61b6, 1329}, + {0x61ba, 4916}, + {0x61be, 1524}, + {0x61c3, 4914}, + {0x61c6, 4915}, + {0x61c7, 2073}, + {0x61c8, 4913}, + {0x61c9, 4911}, + {0x61ca, 4910}, + {0x61cb, 4917}, + {0x61cc, 4909}, + {0x61cd, 4919}, + {0x61d0, 1403}, + {0x61e3, 4921}, + {0x61e6, 4920}, + {0x61f2, 3012}, + {0x61f4, 4924}, + {0x61f6, 4922}, + {0x61f7, 4912}, + {0x61f8, 1874}, + {0x61fa, 4923}, + {0x61fc, 4927}, + {0x61fd, 4926}, + {0x61fe, 4928}, + {0x61ff, 4925}, + {0x6200, 4929}, + {0x6208, 4930}, + {0x6209, 4931}, + {0x620a, 3642}, + {0x620c, 4933}, + {0x620d, 4932}, + {0x620e, 2377}, + {0x6210, 2642}, + {0x6211, 1382}, + {0x6212, 1404}, + {0x6213, 8465}, + {0x6214, 4934}, + {0x6216, 1155}, + {0x621a, 2672}, + {0x621b, 4935}, + {0x621d, 6756}, + {0x621e, 4936}, + {0x621f, 1847}, + {0x6221, 4937}, + {0x6226, 2707}, + {0x622a, 4938}, + {0x622e, 4939}, + {0x622f, 1620}, + {0x6230, 4940}, + {0x6232, 4941}, + {0x6233, 4942}, + {0x6234, 2871}, + {0x6238, 1921}, + {0x623b, 3821}, + {0x623f, 3690}, + {0x6240, 2420}, + {0x6241, 4943}, + {0x6247, 2708}, + {0x6248, 6938}, + {0x6249, 3446}, + {0x624b, 2326}, + {0x624d, 2109}, + {0x624e, 4944}, + {0x6253, 2855}, + {0x6255, 3575}, + {0x6258, 2897}, + {0x625b, 4947}, + {0x625e, 4945}, + {0x6260, 4948}, + {0x6263, 4946}, + {0x6268, 4949}, + {0x626e, 3585}, + {0x6271, 1147}, + {0x6276, 3536}, + {0x6279, 3447}, + {0x627c, 4950}, + {0x627e, 4953}, + {0x627f, 2461}, + {0x6280, 1621}, + {0x6282, 4951}, + {0x6283, 4958}, + {0x6284, 2462}, + {0x6289, 4952}, + {0x628a, 3322}, + {0x6291, 3912}, + {0x6292, 4954}, + {0x6293, 4955}, + {0x6294, 4959}, + {0x6295, 3172}, + {0x6296, 4956}, + {0x6297, 1989}, + {0x6298, 2690}, + {0x629b, 4973}, + {0x629c, 3400}, + {0x629e, 2898}, + {0x62a6, 8466}, + {0x62ab, 3448}, + {0x62ac, 5042}, + {0x62b1, 3658}, + {0x62b5, 3085}, + {0x62b9, 3747}, + {0x62bb, 4962}, + {0x62bc, 1313}, + {0x62bd, 2984}, + {0x62c2, 4971}, + {0x62c5, 2930}, + {0x62c6, 4965}, + {0x62c7, 4972}, + {0x62c8, 4967}, + {0x62c9, 4974}, + {0x62ca, 4970}, + {0x62cc, 4969}, + {0x62cd, 3365}, + {0x62cf, 4963}, + {0x62d0, 1405}, + {0x62d1, 4961}, + {0x62d2, 1675}, + {0x62d3, 2899}, + {0x62d4, 4957}, + {0x62d7, 4960}, + {0x62d8, 1990}, + {0x62d9, 2687}, + {0x62db, 2463}, + {0x62dc, 4968}, + {0x62dd, 3336}, + {0x62e0, 1676}, + {0x62e1, 1446}, + {0x62ec, 1477}, + {0x62ed, 2535}, + {0x62ee, 4976}, + {0x62ef, 4981}, + {0x62f1, 4977}, + {0x62f3, 1875}, + {0x62f5, 4982}, + {0x62f6, 2160}, + {0x62f7, 2043}, + {0x62fe, 2352}, + {0x62ff, 4964}, + {0x6301, 2251}, + {0x6302, 4979}, + {0x6307, 2214}, + {0x6308, 4980}, + {0x6309, 1160}, + {0x630c, 4975}, + {0x6311, 3013}, + {0x6319, 1677}, + {0x631f, 1708}, + {0x6327, 4978}, + {0x6328, 1131}, + {0x632b, 2099}, + {0x632f, 2556}, + {0x633a, 3086}, + {0x633d, 3432}, + {0x633e, 4984}, + {0x633f, 2784}, + {0x6343, 0}, + {0x6349, 2826}, + {0x634c, 2169}, + {0x634d, 4985}, + {0x634f, 4987}, + {0x6350, 4983}, + {0x6355, 3633}, + {0x6357, 3033}, + {0x635c, 2782}, + {0x6367, 3659}, + {0x6368, 2298}, + {0x6369, 4999}, + {0x636b, 4998}, + {0x636e, 2622}, + {0x6372, 1876}, + {0x6376, 4992}, + {0x6377, 2465}, + {0x637a, 3264}, + {0x637b, 3303}, + {0x6380, 4990}, + {0x6383, 2783}, + {0x6388, 2340}, + {0x6389, 4995}, + {0x638c, 2464}, + {0x638e, 4989}, + {0x638f, 4994}, + {0x6392, 3337}, + {0x6396, 4988}, + {0x6398, 1783}, + {0x639b, 1467}, + {0x639f, 4996}, + {0x63a0, 3955}, + {0x63a1, 2110}, + {0x63a2, 2931}, + {0x63a3, 4993}, + {0x63a5, 2688}, + {0x63a7, 1991}, + {0x63a8, 2602}, + {0x63a9, 1288}, + {0x63aa, 2750}, + {0x63ab, 4991}, + {0x63ac, 1631}, + {0x63b2, 1821}, + {0x63b4, 3051}, + {0x63b5, 4997}, + {0x63bb, 2785}, + {0x63be, 5000}, + {0x63c0, 5002}, + {0x63c3, 2839}, + {0x63c4, 5008}, + {0x63c6, 5003}, + {0x63c9, 5005}, + {0x63cf, 3507}, + {0x63d0, 3087}, + {0x63d2, 5006}, + {0x63d6, 3862}, + {0x63da, 3890}, + {0x63db, 1525}, + {0x63e1, 1138}, + {0x63e3, 5004}, + {0x63e9, 5001}, + {0x63ee, 1588}, + {0x63f4, 1289}, + {0x63f5, 8467}, + {0x63f6, 5007}, + {0x63fa, 3891}, + {0x6406, 5011}, + {0x640d, 2843}, + {0x640f, 5018}, + {0x6413, 5012}, + {0x6414, 7724}, + {0x6416, 5009}, + {0x6417, 5016}, + {0x641c, 4986}, + {0x6426, 5013}, + {0x6428, 5017}, + {0x642c, 3414}, + {0x642d, 3173}, + {0x6434, 5010}, + {0x6436, 5014}, + {0x643a, 1822}, + {0x643e, 2145}, + {0x6442, 2689}, + {0x644e, 5022}, + {0x6451, 7747}, + {0x6458, 3104}, + {0x6460, 8468}, + {0x6467, 5019}, + {0x6469, 3726}, + {0x646f, 5020}, + {0x6476, 5021}, + {0x6478, 3802}, + {0x647a, 2630}, + {0x6483, 1848}, + {0x6488, 5028}, + {0x6492, 2179}, + {0x6493, 5025}, + {0x6495, 5024}, + {0x649a, 3304}, + {0x649d, 8469}, + {0x649e, 3213}, + {0x64a4, 3115}, + {0x64a5, 5026}, + {0x64a9, 5027}, + {0x64ab, 3553}, + {0x64ad, 3323}, + {0x64ae, 2161}, + {0x64b0, 2709}, + {0x64b2, 3710}, + {0x64b9, 1447}, + {0x64bb, 5034}, + {0x64bc, 5029}, + {0x64bf, 0}, + {0x64c1, 3892}, + {0x64c2, 5036}, + {0x64c5, 5032}, + {0x64c7, 5033}, + {0x64cd, 2786}, + {0x64ce, 8470}, + {0x64d2, 5031}, + {0x64d4, 4966}, + {0x64d8, 5035}, + {0x64da, 5030}, + {0x64e0, 5040}, + {0x64e1, 5041}, + {0x64e2, 3105}, + {0x64e3, 5043}, + {0x64e6, 2162}, + {0x64e7, 5038}, + {0x64ec, 1622}, + {0x64ef, 5044}, + {0x64f1, 5037}, + {0x64f2, 5048}, + {0x64f4, 5047}, + {0x64f6, 5046}, + {0x64fa, 5049}, + {0x64fd, 5051}, + {0x64fe, 2521}, + {0x6500, 5050}, + {0x6505, 5054}, + {0x6518, 5052}, + {0x651c, 5053}, + {0x651d, 5015}, + {0x6522, 7831}, + {0x6523, 5056}, + {0x6524, 5055}, + {0x652a, 5023}, + {0x652b, 5057}, + {0x652c, 5045}, + {0x652f, 2215}, + {0x6534, 5058}, + {0x6535, 5059}, + {0x6536, 5061}, + {0x6537, 5060}, + {0x6538, 5062}, + {0x6539, 1406}, + {0x653b, 1992}, + {0x653e, 3660}, + {0x653f, 2643}, + {0x6545, 1922}, + {0x6548, 5064}, + {0x654d, 5067}, + {0x654e, 8471}, + {0x654f, 3524}, + {0x6551, 1657}, + {0x6555, 5066}, + {0x6556, 5065}, + {0x6557, 3338}, + {0x6558, 5068}, + {0x6559, 1709}, + {0x655d, 5070}, + {0x655e, 5069}, + {0x6562, 1526}, + {0x6563, 2180}, + {0x6566, 3248}, + {0x656c, 1823}, + {0x6570, 2618}, + {0x6572, 5071}, + {0x6574, 2644}, + {0x6575, 3106}, + {0x6577, 3537}, + {0x6578, 5072}, + {0x6582, 5073}, + {0x6583, 5074}, + {0x6587, 3592}, + {0x6588, 4620}, + {0x6589, 2666}, + {0x658c, 3518}, + {0x658e, 2120}, + {0x6590, 3449}, + {0x6591, 3415}, + {0x6597, 3143}, + {0x6599, 3977}, + {0x659b, 5076}, + {0x659c, 2300}, + {0x659f, 5077}, + {0x65a1, 1146}, + {0x65a4, 1740}, + {0x65a5, 2673}, + {0x65a7, 3538}, + {0x65ab, 5078}, + {0x65ac, 2192}, + {0x65ad, 2949}, + {0x65af, 2217}, + {0x65b0, 2557}, + {0x65b7, 5079}, + {0x65b9, 3661}, + {0x65bc, 1305}, + {0x65bd, 2218}, + {0x65c1, 5082}, + {0x65c3, 5080}, + {0x65c4, 5083}, + {0x65c5, 3969}, + {0x65c6, 5081}, + {0x65cb, 2719}, + {0x65cc, 5084}, + {0x65cf, 2834}, + {0x65d2, 5085}, + {0x65d7, 1590}, + {0x65d9, 5087}, + {0x65db, 5086}, + {0x65e0, 5088}, + {0x65e1, 5089}, + {0x65e2, 1591}, + {0x65e5, 3284}, + {0x65e6, 2932}, + {0x65e7, 1670}, + {0x65e8, 2219}, + {0x65e9, 2787}, + {0x65ec, 2406}, + {0x65ed, 1140}, + {0x65f1, 5090}, + {0x65fa, 1314}, + {0x65fb, 5094}, + {0x6600, 8472}, + {0x6602, 1993}, + {0x6603, 5093}, + {0x6606, 2075}, + {0x6607, 2466}, + {0x6609, 8474}, + {0x660a, 5092}, + {0x660c, 2467}, + {0x660e, 3788}, + {0x660f, 2074}, + {0x6613, 1179}, + {0x6614, 2674}, + {0x6615, 8473}, + {0x661c, 5099}, + {0x661e, 8476}, + {0x661f, 2645}, + {0x6620, 1257}, + {0x6624, 8477}, + {0x6625, 2399}, + {0x6627, 3732}, + {0x6628, 2146}, + {0x662d, 2468}, + {0x662e, 8475}, + {0x662f, 2635}, + {0x6631, 8366}, + {0x6634, 5098}, + {0x6635, 5096}, + {0x6636, 5097}, + {0x663b, 7680}, + {0x663c, 2985}, + {0x663f, 5129}, + {0x6641, 5103}, + {0x6642, 2252}, + {0x6643, 1994}, + {0x6644, 5101}, + {0x6649, 5102}, + {0x664b, 2558}, + {0x664f, 5100}, + {0x6652, 2173}, + {0x6657, 8479}, + {0x6659, 8480}, + {0x665c, 0}, + {0x665d, 5105}, + {0x665e, 5104}, + {0x665f, 5109}, + {0x6662, 5110}, + {0x6664, 5106}, + {0x6665, 8478}, + {0x6666, 1408}, + {0x6667, 5107}, + {0x6668, 5108}, + {0x6669, 3433}, + {0x666e, 3539}, + {0x666f, 1824}, + {0x6670, 5111}, + {0x6673, 8482}, + {0x6674, 2646}, + {0x6676, 2469}, + {0x667a, 2960}, + {0x6681, 1727}, + {0x6683, 5112}, + {0x6684, 5116}, + {0x6687, 1355}, + {0x6688, 5113}, + {0x6689, 5115}, + {0x668e, 5114}, + {0x6691, 2421}, + {0x6696, 2950}, + {0x6697, 1161}, + {0x6698, 5117}, + {0x6699, 8483}, + {0x669d, 5118}, + {0x66a0, 8484}, + {0x66a2, 3014}, + {0x66a6, 4025}, + {0x66ab, 2193}, + {0x66ae, 3643}, + {0x66b2, 8485}, + {0x66b4, 3691}, + {0x66b8, 5125}, + {0x66b9, 5120}, + {0x66bc, 5123}, + {0x66be, 5122}, + {0x66bf, 8486}, + {0x66c1, 5119}, + {0x66c4, 5124}, + {0x66c7, 3254}, + {0x66c9, 5121}, + {0x66d6, 5126}, + {0x66d9, 2422}, + {0x66da, 5127}, + {0x66dc, 3893}, + {0x66dd, 3374}, + {0x66e0, 5128}, + {0x66e6, 5130}, + {0x66e9, 5131}, + {0x66f0, 5132}, + {0x66f2, 1730}, + {0x66f3, 1258}, + {0x66f4, 1995}, + {0x66f5, 5133}, + {0x66f7, 5134}, + {0x66f8, 2427}, + {0x66f9, 2788}, + {0x66fa, 8487}, + {0x66fb, 8369}, + {0x66fc, 4333}, + {0x66fd, 2752}, + {0x66fe, 2751}, + {0x66ff, 2872}, + {0x6700, 2103}, + {0x6703, 4171}, + {0x6708, 1860}, + {0x6709, 3863}, + {0x670b, 3662}, + {0x670d, 3568}, + {0x670e, 8488}, + {0x670f, 5135}, + {0x6714, 2147}, + {0x6715, 3035}, + {0x6716, 5136}, + {0x6717, 4053}, + {0x671b, 3692}, + {0x671d, 3015}, + {0x671e, 5137}, + {0x671f, 1592}, + {0x6726, 5138}, + {0x6727, 5139}, + {0x6728, 3814}, + {0x672a, 3760}, + {0x672b, 3748}, + {0x672c, 3722}, + {0x672d, 2163}, + {0x672e, 5141}, + {0x6731, 2327}, + {0x6734, 3711}, + {0x6736, 5143}, + {0x6737, 5146}, + {0x6738, 5145}, + {0x673a, 1589}, + {0x673d, 1658}, + {0x673f, 5142}, + {0x6741, 5144}, + {0x6746, 5147}, + {0x6749, 2623}, + {0x674e, 3941}, + {0x674f, 1165}, + {0x6750, 2128}, + {0x6751, 2844}, + {0x6753, 2313}, + {0x6756, 2523}, + {0x6759, 5150}, + {0x675c, 3144}, + {0x675e, 5148}, + {0x675f, 2827}, + {0x6760, 5149}, + {0x6761, 2522}, + {0x6762, 3817}, + {0x6763, 5151}, + {0x6764, 5152}, + {0x6765, 3922}, + {0x6766, 8490}, + {0x676a, 5157}, + {0x676d, 1996}, + {0x676f, 3339}, + {0x6770, 5154}, + {0x6771, 3174}, + {0x6772, 5091}, + {0x6773, 5095}, + {0x6775, 1641}, + {0x6777, 3325}, + {0x677c, 5156}, + {0x677e, 2470}, + {0x677f, 3416}, + {0x6785, 5162}, + {0x6787, 3470}, + {0x6789, 5153}, + {0x678b, 5159}, + {0x678c, 5158}, + {0x6790, 2675}, + {0x6795, 3739}, + {0x6797, 3995}, + {0x679a, 3733}, + {0x679c, 1356}, + {0x679d, 2220}, + {0x67a0, 4078}, + {0x67a1, 5161}, + {0x67a2, 2619}, + {0x67a6, 5160}, + {0x67a9, 5155}, + {0x67af, 1923}, + {0x67b3, 5167}, + {0x67b4, 5165}, + {0x67b6, 1357}, + {0x67b7, 5163}, + {0x67b8, 5169}, + {0x67b9, 5175}, + {0x67bb, 8491}, + {0x67c0, 8493}, + {0x67c1, 2856}, + {0x67c4, 3601}, + {0x67c6, 5177}, + {0x67ca, 3476}, + {0x67ce, 5176}, + {0x67cf, 3366}, + {0x67d0, 3693}, + {0x67d1, 1527}, + {0x67d3, 2715}, + {0x67d4, 2378}, + {0x67d8, 3055}, + {0x67da, 3864}, + {0x67dd, 5172}, + {0x67de, 5171}, + {0x67e2, 5173}, + {0x67e4, 5170}, + {0x67e7, 5178}, + {0x67e9, 5168}, + {0x67ec, 5166}, + {0x67ee, 5174}, + {0x67ef, 5164}, + {0x67f1, 2986}, + {0x67f3, 3844}, + {0x67f4, 2290}, + {0x67f5, 2148}, + {0x67fb, 2090}, + {0x67fe, 3741}, + {0x67ff, 1439}, + {0x6801, 8494}, + {0x6802, 3050}, + {0x6803, 3234}, + {0x6804, 1259}, + {0x6805, 7687}, + {0x6813, 2710}, + {0x6816, 2648}, + {0x6817, 1792}, + {0x681e, 5180}, + {0x6821, 1997}, + {0x6822, 1498}, + {0x6829, 5182}, + {0x682a, 1490}, + {0x682b, 5188}, + {0x6831, 0}, + {0x6832, 5185}, + {0x6834, 2711}, + {0x6838, 1449}, + {0x6839, 2076}, + {0x683c, 1448}, + {0x683d, 2111}, + {0x6840, 5183}, + {0x6841, 1851}, + {0x6842, 1825}, + {0x6843, 3175}, + {0x6844, 8495}, + {0x6846, 5181}, + {0x6848, 1162}, + {0x684d, 5184}, + {0x684e, 5186}, + {0x6850, 1733}, + {0x6851, 1794}, + {0x6852, 8492}, + {0x6853, 1528}, + {0x6854, 1637}, + {0x6859, 5189}, + {0x685c, 2153}, + {0x685d, 3743}, + {0x685f, 2181}, + {0x6863, 5190}, + {0x6867, 3490}, + {0x6874, 5202}, + {0x6876, 1331}, + {0x6877, 5191}, + {0x687e, 5208}, + {0x687f, 5192}, + {0x6881, 3978}, + {0x6883, 5199}, + {0x6885, 3349}, + {0x688d, 5207}, + {0x688e, 7836}, + {0x688f, 5194}, + {0x6893, 1144}, + {0x6894, 5196}, + {0x6897, 1998}, + {0x689b, 5198}, + {0x689d, 5197}, + {0x689f, 5193}, + {0x68a0, 5204}, + {0x68a2, 2471}, + {0x68a6, 4542}, + {0x68a7, 1948}, + {0x68a8, 3942}, + {0x68ad, 5195}, + {0x68af, 3088}, + {0x68b0, 1409}, + {0x68b1, 2077}, + {0x68b3, 5187}, + {0x68b5, 5203}, + {0x68b6, 1471}, + {0x68b9, 5201}, + {0x68ba, 5205}, + {0x68bc, 3176}, + {0x68c4, 1594}, + {0x68c6, 5235}, + {0x68c8, 8367}, + {0x68c9, 3797}, + {0x68ca, 5210}, + {0x68cb, 1593}, + {0x68cd, 5217}, + {0x68cf, 8496}, + {0x68d2, 3694}, + {0x68d4, 5218}, + {0x68d5, 5220}, + {0x68d7, 5224}, + {0x68d8, 5212}, + {0x68da, 2920}, + {0x68df, 3177}, + {0x68e0, 5228}, + {0x68e1, 5215}, + {0x68e3, 5225}, + {0x68e7, 5219}, + {0x68ee, 2559}, + {0x68ef, 5229}, + {0x68f1, 0}, + {0x68f2, 2647}, + {0x68f9, 5227}, + {0x68fa, 1529}, + {0x6900, 4086}, + {0x6901, 5209}, + {0x6904, 5223}, + {0x6905, 1180}, + {0x6908, 5211}, + {0x690b, 3782}, + {0x690c, 5216}, + {0x690d, 2536}, + {0x690e, 3043}, + {0x690f, 5206}, + {0x6912, 5222}, + {0x6919, 2624}, + {0x691a, 5232}, + {0x691b, 1487}, + {0x691c, 1877}, + {0x6921, 5234}, + {0x6922, 5213}, + {0x6923, 5233}, + {0x6925, 5226}, + {0x6926, 5214}, + {0x6928, 5230}, + {0x692a, 5231}, + {0x6930, 5248}, + {0x6934, 3238}, + {0x6936, 5221}, + {0x6939, 5244}, + {0x693d, 5246}, + {0x693f, 3060}, + {0x694a, 3894}, + {0x6953, 3560}, + {0x6954, 5241}, + {0x6955, 2858}, + {0x6959, 5247}, + {0x695a, 2753}, + {0x695c, 5238}, + {0x695d, 5251}, + {0x695e, 5250}, + {0x6960, 3271}, + {0x6961, 5249}, + {0x6962, 3266}, + {0x6968, 8498}, + {0x696a, 5253}, + {0x696b, 5240}, + {0x696d, 1728}, + {0x696e, 5243}, + {0x696f, 2407}, + {0x6973, 3350}, + {0x6974, 5245}, + {0x6975, 1731}, + {0x6977, 5237}, + {0x6978, 5239}, + {0x6979, 5236}, + {0x697c, 4054}, + {0x697d, 1464}, + {0x697e, 5242}, + {0x6980, 0}, + {0x6981, 5252}, + {0x6982, 1427}, + {0x698a, 2135}, + {0x698e, 1279}, + {0x6991, 5269}, + {0x6994, 4055}, + {0x6995, 5272}, + {0x6998, 8500}, + {0x699b, 2560}, + {0x699c, 5271}, + {0x69a0, 5270}, + {0x69a7, 5267}, + {0x69ae, 5255}, + {0x69b1, 5284}, + {0x69b2, 5254}, + {0x69b4, 5273}, + {0x69bb, 5265}, + {0x69be, 5260}, + {0x69bf, 5257}, + {0x69c1, 5258}, + {0x69c3, 5266}, + {0x69c7, 7475}, + {0x69ca, 5263}, + {0x69cb, 1999}, + {0x69cc, 3044}, + {0x69cd, 2790}, + {0x69ce, 5261}, + {0x69d0, 5256}, + {0x69d3, 5259}, + {0x69d7, 0}, + {0x69d8, 3895}, + {0x69d9, 3736}, + {0x69dd, 5264}, + {0x69de, 5274}, + {0x69e2, 8501}, + {0x69e7, 5282}, + {0x69e8, 5275}, + {0x69eb, 5288}, + {0x69ed, 5286}, + {0x69f2, 5281}, + {0x69f9, 5280}, + {0x69fb, 3052}, + {0x69fd, 2791}, + {0x69ff, 5278}, + {0x6a02, 5276}, + {0x6a05, 5283}, + {0x6a0a, 5289}, + {0x6a0b, 3465}, + {0x6a0c, 5295}, + {0x6a12, 5290}, + {0x6a13, 5293}, + {0x6a14, 5287}, + {0x6a17, 2994}, + {0x6a19, 3498}, + {0x6a1b, 5277}, + {0x6a1e, 5285}, + {0x6a1f, 2472}, + {0x6a21, 3803}, + {0x6a22, 5305}, + {0x6a23, 5292}, + {0x6a29, 1878}, + {0x6a2a, 1315}, + {0x6a2b, 1469}, + {0x6a2e, 5268}, + {0x6a30, 8502}, + {0x6a35, 2473}, + {0x6a36, 5297}, + {0x6a38, 5304}, + {0x6a39, 2341}, + {0x6a3a, 1488}, + {0x6a3d, 2924}, + {0x6a44, 5294}, + {0x6a46, 8504}, + {0x6a47, 5299}, + {0x6a48, 5303}, + {0x6a4b, 1710}, + {0x6a51, 0}, + {0x6a58, 1638}, + {0x6a59, 5301}, + {0x6a5f, 1595}, + {0x6a61, 3235}, + {0x6a62, 5300}, + {0x6a66, 5302}, + {0x6a6b, 8503}, + {0x6a72, 5296}, + {0x6a73, 8505}, + {0x6a78, 5298}, + {0x6a7e, 8506}, + {0x6a7f, 1470}, + {0x6a80, 2951}, + {0x6a84, 5309}, + {0x6a8d, 5307}, + {0x6a8e, 1949}, + {0x6a90, 5306}, + {0x6a97, 5312}, + {0x6a9c, 5179}, + {0x6a9e, 0}, + {0x6a9f, 1}, + {0x6aa0, 5308}, + {0x6aa2, 5310}, + {0x6aa3, 5311}, + {0x6aaa, 5323}, + {0x6aac, 5319}, + {0x6aae, 5200}, + {0x6ab3, 5318}, + {0x6ab8, 5317}, + {0x6abb, 5314}, + {0x6ac1, 5291}, + {0x6ac2, 5316}, + {0x6ac3, 5315}, + {0x6ad1, 5321}, + {0x6ad3, 4044}, + {0x6ada, 5324}, + {0x6adb, 1779}, + {0x6ade, 5320}, + {0x6adf, 5322}, + {0x6ae2, 8507}, + {0x6ae4, 8508}, + {0x6ae8, 3387}, + {0x6aea, 5325}, + {0x6afa, 5329}, + {0x6afb, 5326}, + {0x6b04, 3933}, + {0x6b05, 5327}, + {0x6b0a, 5279}, + {0x6b12, 5330}, + {0x6b16, 5331}, + {0x6b1d, 1239}, + {0x6b1f, 5333}, + {0x6b20, 1853}, + {0x6b21, 2253}, + {0x6b23, 1741}, + {0x6b27, 1316}, + {0x6b32, 3913}, + {0x6b37, 5335}, + {0x6b38, 5334}, + {0x6b39, 5337}, + {0x6b3a, 1623}, + {0x6b3d, 1742}, + {0x6b3e, 1530}, + {0x6b43, 5340}, + {0x6b47, 5339}, + {0x6b49, 5341}, + {0x6b4c, 1358}, + {0x6b4e, 2933}, + {0x6b50, 5342}, + {0x6b53, 1531}, + {0x6b54, 5344}, + {0x6b59, 5343}, + {0x6b5b, 5345}, + {0x6b5f, 5346}, + {0x6b61, 5347}, + {0x6b62, 2221}, + {0x6b63, 2649}, + {0x6b64, 2065}, + {0x6b66, 3554}, + {0x6b69, 3634}, + {0x6b6a, 4074}, + {0x6b6f, 2243}, + {0x6b73, 2112}, + {0x6b74, 4026}, + {0x6b78, 5348}, + {0x6b79, 5349}, + {0x6b7b, 2222}, + {0x6b7f, 5350}, + {0x6b80, 5351}, + {0x6b83, 5353}, + {0x6b84, 5352}, + {0x6b86, 3718}, + {0x6b89, 2408}, + {0x6b8a, 2328}, + {0x6b8b, 2194}, + {0x6b8d, 5354}, + {0x6b95, 5356}, + {0x6b96, 2537}, + {0x6b98, 5355}, + {0x6b9e, 5357}, + {0x6ba4, 5358}, + {0x6baa, 5359}, + {0x6bab, 5360}, + {0x6baf, 5361}, + {0x6bb1, 5363}, + {0x6bb2, 5362}, + {0x6bb3, 5364}, + {0x6bb4, 1317}, + {0x6bb5, 2952}, + {0x6bb7, 5365}, + {0x6bba, 2164}, + {0x6bbb, 1450}, + {0x6bbc, 5366}, + {0x6bbf, 3132}, + {0x6bc0, 4509}, + {0x6bc5, 1597}, + {0x6bc6, 5367}, + {0x6bcb, 5368}, + {0x6bcd, 3644}, + {0x6bce, 3734}, + {0x6bd2, 3231}, + {0x6bd3, 5369}, + {0x6bd4, 3450}, + {0x6bd6, 8509}, + {0x6bd8, 3471}, + {0x6bdb, 3807}, + {0x6bdf, 5370}, + {0x6beb, 5372}, + {0x6bec, 5371}, + {0x6bef, 5374}, + {0x6bf3, 5373}, + {0x6c08, 5376}, + {0x6c0f, 2223}, + {0x6c11, 3773}, + {0x6c13, 5377}, + {0x6c14, 5378}, + {0x6c17, 1598}, + {0x6c1b, 5379}, + {0x6c23, 5381}, + {0x6c24, 5380}, + {0x6c34, 2603}, + {0x6c37, 3499}, + {0x6c38, 1260}, + {0x6c3e, 3417}, + {0x6c3f, 8510}, + {0x6c40, 3089}, + {0x6c41, 2379}, + {0x6c42, 1659}, + {0x6c4e, 3418}, + {0x6c50, 2266}, + {0x6c55, 5383}, + {0x6c57, 1532}, + {0x6c5a, 1306}, + {0x6c5c, 8511}, + {0x6c5d, 3274}, + {0x6c5e, 5382}, + {0x6c5f, 2000}, + {0x6c60, 2961}, + {0x6c62, 5384}, + {0x6c68, 5392}, + {0x6c6a, 5385}, + {0x6c6f, 8513}, + {0x6c70, 2849}, + {0x6c72, 1660}, + {0x6c73, 5393}, + {0x6c7a, 1854}, + {0x6c7d, 1599}, + {0x6c7e, 5391}, + {0x6c81, 5389}, + {0x6c82, 5386}, + {0x6c83, 3914}, + {0x6c86, 8512}, + {0x6c88, 3036}, + {0x6c8c, 3249}, + {0x6c8d, 5387}, + {0x6c90, 5395}, + {0x6c92, 5394}, + {0x6c93, 1785}, + {0x6c96, 1325}, + {0x6c99, 2091}, + {0x6c9a, 5388}, + {0x6c9b, 5390}, + {0x6ca1, 3717}, + {0x6ca2, 2900}, + {0x6cab, 3749}, + {0x6cae, 5403}, + {0x6cb1, 5404}, + {0x6cb3, 1359}, + {0x6cb8, 3576}, + {0x6cb9, 3849}, + {0x6cba, 5406}, + {0x6cbb, 2255}, + {0x6cbc, 2474}, + {0x6cbd, 5399}, + {0x6cbe, 5405}, + {0x6cbf, 1290}, + {0x6cc1, 1711}, + {0x6cc4, 5396}, + {0x6cc5, 5401}, + {0x6cc9, 2712}, + {0x6cca, 3367}, + {0x6ccc, 3451}, + {0x6cd3, 5398}, + {0x6cd5, 3663}, + {0x6cd7, 5400}, + {0x6cd9, 5409}, + {0x6cda, 8514}, + {0x6cdb, 5407}, + {0x6cdd, 5402}, + {0x6ce1, 3664}, + {0x6ce2, 3326}, + {0x6ce3, 1661}, + {0x6ce5, 3103}, + {0x6ce8, 2987}, + {0x6cea, 5410}, + {0x6cec, 0}, + {0x6cef, 5408}, + {0x6cf0, 2873}, + {0x6cf1, 5397}, + {0x6cf3, 1261}, + {0x6d04, 8515}, + {0x6d0b, 3896}, + {0x6d0c, 5421}, + {0x6d12, 5420}, + {0x6d17, 2714}, + {0x6d19, 5417}, + {0x6d1b, 3926}, + {0x6d1e, 3214}, + {0x6d1f, 5411}, + {0x6d25, 3041}, + {0x6d29, 1262}, + {0x6d2a, 2001}, + {0x6d2b, 5414}, + {0x6d32, 2353}, + {0x6d33, 5419}, + {0x6d35, 5418}, + {0x6d36, 5413}, + {0x6d38, 5416}, + {0x6d3b, 1478}, + {0x6d3d, 5415}, + {0x6d3e, 3327}, + {0x6d41, 3958}, + {0x6d44, 2524}, + {0x6d45, 2713}, + {0x6d59, 5427}, + {0x6d5a, 5425}, + {0x6d5c, 3519}, + {0x6d63, 5422}, + {0x6d64, 5424}, + {0x6d66, 1244}, + {0x6d69, 2002}, + {0x6d6a, 4056}, + {0x6d6c, 1435}, + {0x6d6e, 3540}, + {0x6d6f, 8517}, + {0x6d74, 3915}, + {0x6d77, 1410}, + {0x6d78, 2561}, + {0x6d79, 5426}, + {0x6d85, 5431}, + {0x6d87, 8516}, + {0x6d88, 2475}, + {0x6d8c, 3866}, + {0x6d8e, 5428}, + {0x6d93, 5423}, + {0x6d95, 5429}, + {0x6d96, 8518}, + {0x6d99, 4006}, + {0x6d9b, 3181}, + {0x6d9c, 3226}, + {0x6dac, 8519}, + {0x6daf, 1428}, + {0x6db2, 1271}, + {0x6db5, 5435}, + {0x6db8, 5438}, + {0x6dbc, 3979}, + {0x6dc0, 3918}, + {0x6dc5, 5445}, + {0x6dc6, 5439}, + {0x6dc7, 5436}, + {0x6dcb, 3996}, + {0x6dcc, 5442}, + {0x6dcf, 8520}, + {0x6dd1, 2388}, + {0x6dd2, 5444}, + {0x6dd5, 5449}, + {0x6dd8, 3179}, + {0x6dd9, 5447}, + {0x6dde, 5441}, + {0x6de1, 2934}, + {0x6de4, 5448}, + {0x6de6, 5437}, + {0x6de8, 5443}, + {0x6dea, 5450}, + {0x6deb, 1216}, + {0x6dec, 5440}, + {0x6dee, 5451}, + {0x6df1, 2562}, + {0x6df2, 8522}, + {0x6df3, 2409}, + {0x6df5, 3573}, + {0x6df7, 2078}, + {0x6df8, 8521}, + {0x6df9, 5432}, + {0x6dfa, 5446}, + {0x6dfb, 3124}, + {0x6dfc, 8523}, + {0x6e05, 2650}, + {0x6e07, 1479}, + {0x6e08, 2113}, + {0x6e09, 2476}, + {0x6e0a, 5434}, + {0x6e0b, 2380}, + {0x6e13, 1826}, + {0x6e15, 5433}, + {0x6e19, 5455}, + {0x6e1a, 2423}, + {0x6e1b, 1902}, + {0x6e1d, 5470}, + {0x6e1f, 5464}, + {0x6e20, 1678}, + {0x6e21, 3145}, + {0x6e23, 5459}, + {0x6e24, 5468}, + {0x6e25, 1139}, + {0x6e26, 1236}, + {0x6e27, 8526}, + {0x6e29, 1337}, + {0x6e2b, 5461}, + {0x6e2c, 2828}, + {0x6e2d, 5452}, + {0x6e2e, 5454}, + {0x6e2f, 2003}, + {0x6e38, 5471}, + {0x6e39, 8524}, + {0x6e3a, 5466}, + {0x6e3c, 8527}, + {0x6e3e, 5458}, + {0x6e43, 5465}, + {0x6e4a, 3767}, + {0x6e4d, 5463}, + {0x6e4e, 5467}, + {0x6e56, 1924}, + {0x6e58, 2477}, + {0x6e5b, 2935}, + {0x6e5c, 8525}, + {0x6e5f, 5457}, + {0x6e67, 3865}, + {0x6e6b, 5460}, + {0x6e6e, 5453}, + {0x6e6f, 3180}, + {0x6e72, 5456}, + {0x6e76, 5462}, + {0x6e7e, 4087}, + {0x6e7f, 2282}, + {0x6e80, 3756}, + {0x6e82, 5472}, + {0x6e8c, 3394}, + {0x6e8f, 5484}, + {0x6e90, 1903}, + {0x6e96, 2410}, + {0x6e98, 5474}, + {0x6e9c, 3959}, + {0x6e9d, 2004}, + {0x6e9f, 5487}, + {0x6ea2, 1202}, + {0x6ea5, 5485}, + {0x6eaa, 5473}, + {0x6eaf, 5479}, + {0x6eb2, 5481}, + {0x6eb6, 3897}, + {0x6eb7, 5476}, + {0x6eba, 3112}, + {0x6ebd, 5478}, + {0x6ebf, 8528}, + {0x6ec2, 5486}, + {0x6ec4, 5480}, + {0x6ec5, 3795}, + {0x6ec9, 5475}, + {0x6ecb, 2254}, + {0x6ecc, 5499}, + {0x6ed1, 1480}, + {0x6ed3, 5477}, + {0x6ed4, 5482}, + {0x6ed5, 5483}, + {0x6edd, 2892}, + {0x6ede, 2874}, + {0x6eec, 5491}, + {0x6eef, 5497}, + {0x6ef2, 5495}, + {0x6ef4, 3107}, + {0x6ef7, 5502}, + {0x6ef8, 5492}, + {0x6efe, 5493}, + {0x6eff, 5469}, + {0x6f01, 1683}, + {0x6f02, 3500}, + {0x6f06, 2283}, + {0x6f09, 2057}, + {0x6f0f, 4057}, + {0x6f11, 5489}, + {0x6f13, 5501}, + {0x6f14, 1291}, + {0x6f15, 2792}, + {0x6f20, 3375}, + {0x6f22, 1533}, + {0x6f23, 4034}, + {0x6f2b, 3757}, + {0x6f2c, 3054}, + {0x6f31, 5496}, + {0x6f32, 5498}, + {0x6f38, 2740}, + {0x6f3e, 5500}, + {0x6f3f, 5494}, + {0x6f41, 5488}, + {0x6f45, 1535}, + {0x6f51, 7776}, + {0x6f54, 1855}, + {0x6f58, 5514}, + {0x6f5b, 5509}, + {0x6f5c, 2716}, + {0x6f5f, 1473}, + {0x6f64, 2411}, + {0x6f66, 5518}, + {0x6f6d, 5511}, + {0x6f6e, 3016}, + {0x6f6f, 5508}, + {0x6f70, 3061}, + {0x6f74, 5543}, + {0x6f78, 5505}, + {0x6f7a, 5504}, + {0x6f7c, 5513}, + {0x6f80, 5507}, + {0x6f81, 5506}, + {0x6f82, 5512}, + {0x6f84, 2629}, + {0x6f86, 5503}, + {0x6f88, 8529}, + {0x6f8e, 5515}, + {0x6f91, 5516}, + {0x6f97, 1534}, + {0x6fa1, 5521}, + {0x6fa3, 5520}, + {0x6fa4, 5522}, + {0x6fa8, 0}, + {0x6faa, 5525}, + {0x6fb1, 3133}, + {0x6fb3, 5519}, + {0x6fb5, 8530}, + {0x6fb9, 5523}, + {0x6fc0, 1849}, + {0x6fc1, 2905}, + {0x6fc2, 5517}, + {0x6fc3, 3313}, + {0x6fc6, 5524}, + {0x6fd4, 5529}, + {0x6fd5, 5527}, + {0x6fd8, 5530}, + {0x6fdb, 5533}, + {0x6fdf, 5526}, + {0x6fe0, 2044}, + {0x6fe1, 3294}, + {0x6fe4, 5430}, + {0x6feb, 3934}, + {0x6fec, 5528}, + {0x6fee, 5532}, + {0x6fef, 2901}, + {0x6ff1, 5531}, + {0x6ff3, 5510}, + {0x6ff5, 8531}, + {0x6ff6, 7076}, + {0x6ffa, 5536}, + {0x6ffe, 5540}, + {0x7001, 5538}, + {0x7005, 8532}, + {0x7006, 7760}, + {0x7007, 8533}, + {0x7009, 5534}, + {0x700b, 5535}, + {0x700f, 5539}, + {0x7011, 5537}, + {0x7015, 3520}, + {0x7018, 5545}, + {0x701a, 5542}, + {0x701b, 5541}, + {0x701d, 5544}, + {0x701e, 3244}, + {0x701f, 5546}, + {0x7026, 2995}, + {0x7027, 2893}, + {0x7028, 8534}, + {0x702c, 2633}, + {0x7030, 5547}, + {0x7032, 5549}, + {0x703e, 5548}, + {0x704c, 5490}, + {0x7051, 5550}, + {0x7058, 3263}, + {0x705e, 0}, + {0x7063, 5551}, + {0x706b, 1360}, + {0x706f, 3182}, + {0x7070, 1411}, + {0x7078, 1662}, + {0x707c, 2314}, + {0x707d, 2114}, + {0x7085, 8535}, + {0x7089, 4045}, + {0x708a, 2604}, + {0x708e, 1292}, + {0x7092, 5553}, + {0x7099, 5552}, + {0x70ab, 8536}, + {0x70ac, 5556}, + {0x70ad, 2936}, + {0x70ae, 5559}, + {0x70af, 5554}, + {0x70b3, 5558}, + {0x70b8, 5557}, + {0x70b9, 3130}, + {0x70ba, 1181}, + {0x70bb, 8365}, + {0x70c8, 4029}, + {0x70cb, 5561}, + {0x70cf, 1226}, + {0x70d4, 0}, + {0x70d9, 5563}, + {0x70dd, 5562}, + {0x70df, 5560}, + {0x70f1, 5555}, + {0x70f9, 3665}, + {0x70fd, 5565}, + {0x7104, 8538}, + {0x7109, 5564}, + {0x710f, 8537}, + {0x7114, 1293}, + {0x7119, 5567}, + {0x711a, 3586}, + {0x711c, 5566}, + {0x7121, 3777}, + {0x7126, 2479}, + {0x7130, 7644}, + {0x7136, 2741}, + {0x713c, 2478}, + {0x7146, 8540}, + {0x7147, 8541}, + {0x7149, 4035}, + {0x714c, 5573}, + {0x714e, 2717}, + {0x7155, 5569}, + {0x7156, 5574}, + {0x7159, 1294}, + {0x715c, 8539}, + {0x7162, 5572}, + {0x7164, 3351}, + {0x7165, 5568}, + {0x7166, 5571}, + {0x7167, 2480}, + {0x7169, 3429}, + {0x716c, 5575}, + {0x716e, 2301}, + {0x717d, 2718}, + {0x7184, 5578}, + {0x7188, 5570}, + {0x718a, 1789}, + {0x718f, 5576}, + {0x7194, 3898}, + {0x7195, 5579}, + {0x7199, 8285}, + {0x719f, 2393}, + {0x71a8, 5580}, + {0x71ac, 5581}, + {0x71b1, 3300}, + {0x71b9, 5583}, + {0x71be, 5584}, + {0x71c1, 8543}, + {0x71c3, 3305}, + {0x71c8, 3183}, + {0x71c9, 5586}, + {0x71ce, 5588}, + {0x71d0, 3997}, + {0x71d2, 5585}, + {0x71d4, 5587}, + {0x71d5, 1295}, + {0x71d7, 5582}, + {0x71df, 4430}, + {0x71e0, 5589}, + {0x71e5, 2793}, + {0x71e6, 2182}, + {0x71e7, 5591}, + {0x71ec, 5590}, + {0x71ed, 2538}, + {0x71ee, 4334}, + {0x71f5, 5592}, + {0x71f9, 5594}, + {0x71fb, 5577}, + {0x71fc, 5593}, + {0x71fe, 8544}, + {0x71ff, 5595}, + {0x7206, 3376}, + {0x720d, 5596}, + {0x7210, 5597}, + {0x721b, 5598}, + {0x7228, 5599}, + {0x722a, 3066}, + {0x722c, 5601}, + {0x722d, 5600}, + {0x7230, 5602}, + {0x7232, 5603}, + {0x7235, 2315}, + {0x7236, 3541}, + {0x723a, 3832}, + {0x723b, 5604}, + {0x723c, 5605}, + {0x723d, 2776}, + {0x723e, 2256}, + {0x723f, 5606}, + {0x7240, 5607}, + {0x7246, 5608}, + {0x7247, 3618}, + {0x7248, 3419}, + {0x724b, 5609}, + {0x724c, 3341}, + {0x7252, 3017}, + {0x7256, 0}, + {0x7258, 5610}, + {0x7259, 1383}, + {0x725b, 1671}, + {0x725d, 3794}, + {0x725f, 3778}, + {0x7261, 1332}, + {0x7262, 4058}, + {0x7267, 3712}, + {0x7269, 3578}, + {0x7272, 2651}, + {0x7274, 5611}, + {0x7279, 3227}, + {0x727d, 1879}, + {0x727e, 5612}, + {0x7280, 2116}, + {0x7281, 5614}, + {0x7282, 5613}, + {0x7287, 5615}, + {0x7292, 5616}, + {0x7296, 5617}, + {0x72a0, 1624}, + {0x72a2, 5618}, + {0x72a7, 5619}, + {0x72ac, 1880}, + {0x72af, 3420}, + {0x72b1, 8545}, + {0x72b2, 5621}, + {0x72b6, 2525}, + {0x72b9, 5620}, + {0x72be, 8546}, + {0x72c2, 1712}, + {0x72c3, 5622}, + {0x72c4, 5624}, + {0x72c6, 5623}, + {0x72ce, 5625}, + {0x72d0, 1925}, + {0x72d2, 5626}, + {0x72d7, 1761}, + {0x72d9, 2754}, + {0x72db, 2063}, + {0x72e0, 5628}, + {0x72e1, 5629}, + {0x72e2, 5627}, + {0x72e9, 2329}, + {0x72ec, 3232}, + {0x72ed, 1713}, + {0x72f7, 5631}, + {0x72f8, 2922}, + {0x72f9, 5630}, + {0x72fc, 4059}, + {0x72fd, 3352}, + {0x7305, 0}, + {0x730a, 5634}, + {0x7316, 5636}, + {0x7317, 5633}, + {0x731b, 3808}, + {0x731c, 5635}, + {0x731d, 5637}, + {0x731f, 3980}, + {0x7324, 8547}, + {0x7325, 5641}, + {0x7329, 5640}, + {0x732a, 2996}, + {0x732b, 3299}, + {0x732e, 1881}, + {0x732f, 5639}, + {0x7334, 5638}, + {0x7336, 3867}, + {0x7337, 3868}, + {0x733e, 5642}, + {0x733f, 1296}, + {0x7344, 2056}, + {0x7345, 2224}, + {0x734e, 5643}, + {0x734f, 5644}, + {0x7357, 5646}, + {0x7363, 2381}, + {0x7368, 5648}, + {0x736a, 5647}, + {0x7370, 5649}, + {0x7372, 1451}, + {0x7375, 5651}, + {0x7377, 8549}, + {0x7378, 5650}, + {0x737a, 5653}, + {0x737b, 5652}, + {0x7384, 1904}, + {0x7386, 0}, + {0x7387, 3952}, + {0x7389, 1732}, + {0x738b, 1318}, + {0x7396, 1762}, + {0x739f, 0}, + {0x73a0, 1}, + {0x73a9, 1565}, + {0x73b2, 4016}, + {0x73b3, 5655}, + {0x73bb, 5657}, + {0x73bd, 8550}, + {0x73c0, 5658}, + {0x73c2, 1361}, + {0x73c8, 5654}, + {0x73c9, 8551}, + {0x73ca, 2183}, + {0x73cd, 3037}, + {0x73ce, 5656}, + {0x73d2, 8554}, + {0x73d6, 8552}, + {0x73de, 5661}, + {0x73e0, 2330}, + {0x73e3, 8553}, + {0x73e5, 5659}, + {0x73ea, 1812}, + {0x73ed, 3421}, + {0x73ee, 5660}, + {0x73f1, 5687}, + {0x73f5, 8556}, + {0x73f8, 5666}, + {0x73fe, 1905}, + {0x7403, 1663}, + {0x7405, 5663}, + {0x7406, 3943}, + {0x7407, 8555}, + {0x7409, 3960}, + {0x741b, 0}, + {0x7422, 2902}, + {0x7425, 5665}, + {0x7426, 8557}, + {0x7429, 8559}, + {0x742a, 8558}, + {0x742e, 8560}, + {0x7430, 0}, + {0x7431, 1}, + {0x7432, 5667}, + {0x7433, 3998}, + {0x7434, 1743}, + {0x7435, 3472}, + {0x7436, 3328}, + {0x743a, 5668}, + {0x743f, 5670}, + {0x7441, 5673}, + {0x7455, 5669}, + {0x7459, 5672}, + {0x745a, 1950}, + {0x745b, 1263}, + {0x745c, 5674}, + {0x745e, 2614}, + {0x745f, 5671}, + {0x7460, 4004}, + {0x7462, 8561}, + {0x7463, 5677}, + {0x7464, 7477}, + {0x7469, 5675}, + {0x746a, 5678}, + {0x746f, 5664}, + {0x7470, 5676}, + {0x7473, 2092}, + {0x7476, 5679}, + {0x747e, 5680}, + {0x7483, 3944}, + {0x7486, 0}, + {0x7487, 1}, + {0x7489, 8562}, + {0x748b, 5681}, + {0x749e, 5682}, + {0x749f, 8563}, + {0x74a2, 5662}, + {0x74a7, 5683}, + {0x74b0, 1536}, + {0x74bd, 2257}, + {0x74ca, 5684}, + {0x74cf, 5685}, + {0x74d4, 5686}, + {0x74dc, 1245}, + {0x74e0, 5688}, + {0x74e2, 3501}, + {0x74e3, 5689}, + {0x74e6, 1504}, + {0x74e7, 5690}, + {0x74e9, 5691}, + {0x74ee, 5692}, + {0x74f0, 5694}, + {0x74f1, 5695}, + {0x74f2, 5693}, + {0x74f6, 3525}, + {0x74f7, 5697}, + {0x74f8, 5696}, + {0x7501, 8564}, + {0x7503, 5699}, + {0x7504, 5698}, + {0x7505, 5700}, + {0x750c, 5701}, + {0x750d, 5703}, + {0x750e, 5702}, + {0x7511, 2059}, + {0x7513, 5705}, + {0x7515, 5704}, + {0x7518, 1537}, + {0x751a, 2585}, + {0x751c, 3126}, + {0x751e, 5706}, + {0x751f, 2652}, + {0x7523, 2184}, + {0x7525, 1307}, + {0x7526, 5707}, + {0x7528, 3899}, + {0x752b, 3635}, + {0x752c, 5708}, + {0x752f, 8434}, + {0x7530, 3134}, + {0x7531, 3869}, + {0x7532, 2005}, + {0x7533, 2563}, + {0x7537, 2953}, + {0x7538, 4297}, + {0x753a, 3018}, + {0x753b, 1384}, + {0x753c, 5709}, + {0x7544, 5710}, + {0x7546, 5715}, + {0x7549, 5713}, + {0x754a, 5712}, + {0x754b, 5063}, + {0x754c, 1412}, + {0x754d, 5711}, + {0x754f, 1182}, + {0x7551, 3390}, + {0x7554, 3422}, + {0x7559, 3961}, + {0x755a, 5716}, + {0x755b, 5714}, + {0x755c, 2970}, + {0x755d, 2634}, + {0x7560, 3391}, + {0x7562, 3487}, + {0x7564, 5718}, + {0x7565, 3956}, + {0x7566, 1827}, + {0x7567, 5719}, + {0x7569, 5717}, + {0x756a, 3434}, + {0x756b, 5720}, + {0x756d, 5721}, + {0x756f, 8565}, + {0x7570, 1183}, + {0x7573, 2526}, + {0x7574, 5726}, + {0x7576, 5723}, + {0x7577, 3269}, + {0x7578, 5722}, + {0x757f, 1600}, + {0x7582, 5729}, + {0x7586, 5724}, + {0x7587, 5725}, + {0x7589, 5728}, + {0x758a, 5727}, + {0x758b, 3479}, + {0x758e, 2756}, + {0x758f, 2755}, + {0x7591, 1625}, + {0x7593, 0}, + {0x7594, 5730}, + {0x759a, 5731}, + {0x759d, 5732}, + {0x75a3, 5734}, + {0x75a5, 5733}, + {0x75ab, 1272}, + {0x75b1, 5742}, + {0x75b2, 3452}, + {0x75b3, 5736}, + {0x75b5, 5738}, + {0x75b8, 5740}, + {0x75b9, 2564}, + {0x75bc, 5741}, + {0x75bd, 5739}, + {0x75be, 2284}, + {0x75c2, 5735}, + {0x75c3, 5737}, + {0x75c5, 3508}, + {0x75c7, 2481}, + {0x75ca, 5744}, + {0x75cd, 5743}, + {0x75d2, 5745}, + {0x75d4, 2258}, + {0x75d5, 2079}, + {0x75d8, 3185}, + {0x75d9, 5746}, + {0x75db, 3047}, + {0x75de, 5748}, + {0x75e2, 3945}, + {0x75e3, 5747}, + {0x75e9, 2795}, + {0x75f0, 5753}, + {0x75f2, 5755}, + {0x75f3, 5756}, + {0x75f4, 2962}, + {0x75fa, 5754}, + {0x75fc, 5751}, + {0x75fe, 5749}, + {0x75ff, 5750}, + {0x7601, 5752}, + {0x7609, 5759}, + {0x760b, 5757}, + {0x760d, 5758}, + {0x7616, 0}, + {0x761f, 5760}, + {0x7620, 5762}, + {0x7621, 5763}, + {0x7622, 5764}, + {0x7624, 5765}, + {0x7626, 7725}, + {0x7627, 5761}, + {0x7630, 5767}, + {0x7634, 5766}, + {0x763b, 5768}, + {0x7642, 3981}, + {0x7646, 5771}, + {0x7647, 5769}, + {0x7648, 5770}, + {0x764c, 1566}, + {0x7652, 3850}, + {0x7656, 3610}, + {0x7658, 5773}, + {0x765c, 5772}, + {0x7661, 5774}, + {0x7662, 5775}, + {0x7667, 5779}, + {0x7668, 5776}, + {0x7669, 5777}, + {0x766a, 5778}, + {0x766c, 5780}, + {0x7670, 5781}, + {0x7672, 5782}, + {0x7676, 5783}, + {0x7678, 5784}, + {0x767a, 3395}, + {0x767b, 3146}, + {0x767c, 5785}, + {0x767d, 3368}, + {0x767e, 3494}, + {0x7680, 5786}, + {0x7682, 8566}, + {0x7683, 5787}, + {0x7684, 3108}, + {0x7686, 1413}, + {0x7687, 2006}, + {0x7688, 5788}, + {0x768b, 5789}, + {0x768e, 5790}, + {0x7690, 2167}, + {0x7693, 5792}, + {0x7696, 5791}, + {0x7699, 5793}, + {0x769a, 5794}, + {0x769b, 8569}, + {0x769c, 8567}, + {0x769e, 8568}, + {0x76a5, 0}, + {0x76a6, 8570}, + {0x76ae, 3453}, + {0x76b0, 5795}, + {0x76b4, 5796}, + {0x76b7, 7452}, + {0x76b8, 5797}, + {0x76b9, 5798}, + {0x76ba, 5799}, + {0x76bf, 2172}, + {0x76c2, 5800}, + {0x76c3, 3340}, + {0x76c6, 3725}, + {0x76c8, 1264}, + {0x76ca, 1273}, + {0x76cd, 5801}, + {0x76d2, 5803}, + {0x76d6, 5802}, + {0x76d7, 3178}, + {0x76db, 2653}, + {0x76dc, 5336}, + {0x76de, 5804}, + {0x76df, 3789}, + {0x76e1, 5805}, + {0x76e3, 1538}, + {0x76e4, 3435}, + {0x76e5, 5806}, + {0x76e7, 5807}, + {0x76ea, 5808}, + {0x76ee, 3816}, + {0x76f2, 3809}, + {0x76f4, 3034}, + {0x76f8, 2796}, + {0x76fb, 5810}, + {0x76fe, 2412}, + {0x7701, 2482}, + {0x7704, 5813}, + {0x7707, 5812}, + {0x7708, 5811}, + {0x7709, 3473}, + {0x770b, 1539}, + {0x770c, 1885}, + {0x771b, 5819}, + {0x771e, 5816}, + {0x771f, 2565}, + {0x7720, 3774}, + {0x7724, 5815}, + {0x7725, 5817}, + {0x7726, 5818}, + {0x7729, 5814}, + {0x7737, 5820}, + {0x7738, 5821}, + {0x773a, 3019}, + {0x773c, 1567}, + {0x7740, 2979}, + {0x7746, 8572}, + {0x7747, 5822}, + {0x775a, 5823}, + {0x775b, 5826}, + {0x7760, 0}, + {0x7761, 2605}, + {0x7762, 7877}, + {0x7763, 3228}, + {0x7765, 5827}, + {0x7766, 3713}, + {0x7768, 5824}, + {0x776b, 5825}, + {0x7779, 5830}, + {0x777e, 5829}, + {0x777f, 5828}, + {0x778b, 5832}, + {0x778e, 5831}, + {0x7791, 5833}, + {0x779e, 5835}, + {0x77a0, 5834}, + {0x77a5, 3613}, + {0x77ac, 2400}, + {0x77ad, 3982}, + {0x77b0, 5836}, + {0x77b3, 3215}, + {0x77b6, 5837}, + {0x77b9, 5838}, + {0x77bb, 5842}, + {0x77bc, 5840}, + {0x77bd, 5841}, + {0x77bf, 5839}, + {0x77c7, 5843}, + {0x77cd, 5844}, + {0x77d7, 5845}, + {0x77da, 5846}, + {0x77db, 3779}, + {0x77dc, 5847}, + {0x77e2, 3836}, + {0x77e3, 5848}, + {0x77e5, 2956}, + {0x77e7, 3360}, + {0x77e9, 1763}, + {0x77ed, 2937}, + {0x77ee, 5849}, + {0x77ef, 1714}, + {0x77f3, 2676}, + {0x77fc, 5850}, + {0x7802, 2093}, + {0x780c, 5851}, + {0x7812, 5852}, + {0x7814, 1882}, + {0x7815, 2117}, + {0x7820, 5854}, + {0x7821, 8574}, + {0x7825, 3152}, + {0x7826, 2118}, + {0x7827, 1640}, + {0x782e, 0}, + {0x7832, 3666}, + {0x7834, 3329}, + {0x783a, 3153}, + {0x783f, 2030}, + {0x7845, 5856}, + {0x784e, 8575}, + {0x785d, 2483}, + {0x7864, 8576}, + {0x786b, 3962}, + {0x786c, 2007}, + {0x786f, 1883}, + {0x7872, 3383}, + {0x7874, 5858}, + {0x787a, 8577}, + {0x787c, 5860}, + {0x7881, 1951}, + {0x7886, 5859}, + {0x7887, 3090}, + {0x788c, 5862}, + {0x788d, 1429}, + {0x788e, 5857}, + {0x7891, 3454}, + {0x7893, 1234}, + {0x7895, 2140}, + {0x7897, 4088}, + {0x789a, 5861}, + {0x78a3, 5863}, + {0x78a7, 3611}, + {0x78a9, 2685}, + {0x78aa, 5865}, + {0x78af, 5866}, + {0x78b5, 5864}, + {0x78ba, 1452}, + {0x78bc, 5872}, + {0x78be, 5871}, + {0x78c1, 2259}, + {0x78c5, 5873}, + {0x78c6, 5868}, + {0x78ca, 5874}, + {0x78cb, 5869}, + {0x78d0, 3436}, + {0x78d1, 5867}, + {0x78d4, 5870}, + {0x78da, 5877}, + {0x78e1, 0}, + {0x78e7, 5876}, + {0x78e8, 3727}, + {0x78ec, 5875}, + {0x78ef, 1199}, + {0x78f4, 5879}, + {0x78fd, 5878}, + {0x7901, 2484}, + {0x7907, 5880}, + {0x790e, 2757}, + {0x7911, 5882}, + {0x7912, 5881}, + {0x7919, 5883}, + {0x7926, 5853}, + {0x792a, 5855}, + {0x792b, 5885}, + {0x792c, 5884}, + {0x7930, 8578}, + {0x793a, 2260}, + {0x793c, 4017}, + {0x793e, 2302}, + {0x7940, 5886}, + {0x7941, 1805}, + {0x7947, 1626}, + {0x7948, 1601}, + {0x7949, 2225}, + {0x7950, 3870}, + {0x7953, 5892}, + {0x7955, 5891}, + {0x7956, 2758}, + {0x7957, 5888}, + {0x795a, 5890}, + {0x795c, 0}, + {0x795d, 2389}, + {0x795e, 2566}, + {0x795f, 5889}, + {0x7960, 5887}, + {0x7962, 3296}, + {0x7965, 2485}, + {0x7968, 3502}, + {0x796d, 2119}, + {0x7977, 3186}, + {0x797a, 5893}, + {0x797f, 5894}, + {0x7980, 5916}, + {0x7981, 1744}, + {0x7984, 4067}, + {0x7985, 2743}, + {0x798a, 5895}, + {0x798d, 1362}, + {0x798e, 3091}, + {0x798f, 3569}, + {0x7994, 8582}, + {0x799b, 8584}, + {0x799d, 5896}, + {0x79a6, 1684}, + {0x79a7, 5897}, + {0x79aa, 5899}, + {0x79ae, 5900}, + {0x79b0, 3295}, + {0x79b1, 7758}, + {0x79b3, 5901}, + {0x79b9, 5902}, + {0x79ba, 5903}, + {0x79bd, 1745}, + {0x79be, 1363}, + {0x79bf, 3229}, + {0x79c0, 2354}, + {0x79c1, 2226}, + {0x79c9, 5904}, + {0x79cb, 2355}, + {0x79d1, 1354}, + {0x79d2, 3509}, + {0x79d5, 5905}, + {0x79d8, 3455}, + {0x79df, 2759}, + {0x79e1, 5908}, + {0x79e3, 5909}, + {0x79e4, 3359}, + {0x79e6, 2567}, + {0x79e7, 5906}, + {0x79e9, 2975}, + {0x79ec, 5907}, + {0x79f0, 2486}, + {0x79fb, 1184}, + {0x7a00, 1603}, + {0x7a08, 5910}, + {0x7a0b, 3092}, + {0x7a0d, 5911}, + {0x7a0e, 2667}, + {0x7a14, 3769}, + {0x7a17, 3477}, + {0x7a18, 5912}, + {0x7a19, 5913}, + {0x7a1a, 2963}, + {0x7a1c, 3983}, + {0x7a1f, 5915}, + {0x7a20, 5914}, + {0x7a2e, 2331}, + {0x7a31, 5917}, + {0x7a32, 1204}, + {0x7a37, 5920}, + {0x7a3b, 5918}, + {0x7a3c, 1364}, + {0x7a3d, 1828}, + {0x7a3e, 5919}, + {0x7a3f, 2008}, + {0x7a40, 2052}, + {0x7a42, 3638}, + {0x7a43, 5921}, + {0x7a46, 3714}, + {0x7a49, 5923}, + {0x7a4d, 2677}, + {0x7a4e, 1265}, + {0x7a4f, 1338}, + {0x7a50, 1136}, + {0x7a57, 5922}, + {0x7a61, 5924}, + {0x7a62, 5925}, + {0x7a63, 2527}, + {0x7a69, 5926}, + {0x7a6b, 1453}, + {0x7a70, 5928}, + {0x7a74, 1856}, + {0x7a76, 1664}, + {0x7a79, 5929}, + {0x7a7a, 1773}, + {0x7a7d, 5930}, + {0x7a7f, 2720}, + {0x7a81, 3237}, + {0x7a83, 2692}, + {0x7a84, 2149}, + {0x7a88, 5931}, + {0x7a92, 2976}, + {0x7a93, 2797}, + {0x7a95, 5933}, + {0x7a96, 5935}, + {0x7a97, 5932}, + {0x7a98, 5934}, + {0x7a9f, 1784}, + {0x7aa9, 5936}, + {0x7aaa, 1788}, + {0x7aae, 1665}, + {0x7aaf, 3900}, + {0x7ab0, 5938}, + {0x7ab6, 5939}, + {0x7aba, 1232}, + {0x7abc, 0}, + {0x7abf, 5942}, + {0x7ac3, 1492}, + {0x7ac4, 5941}, + {0x7ac5, 5940}, + {0x7ac7, 5944}, + {0x7ac8, 5937}, + {0x7aca, 5945}, + {0x7acb, 3953}, + {0x7acd, 5946}, + {0x7acf, 5947}, + {0x7ad1, 8585}, + {0x7ad2, 4549}, + {0x7ad3, 5949}, + {0x7ad5, 5948}, + {0x7ad9, 5950}, + {0x7ada, 5951}, + {0x7adc, 3965}, + {0x7add, 5952}, + {0x7adf, 7176}, + {0x7ae0, 2487}, + {0x7ae1, 5953}, + {0x7ae2, 5954}, + {0x7ae3, 2401}, + {0x7ae5, 3216}, + {0x7ae6, 5955}, + {0x7ae7, 8586}, + {0x7aea, 2918}, + {0x7aeb, 8588}, + {0x7aed, 5956}, + {0x7aef, 2938}, + {0x7af0, 5957}, + {0x7af6, 1693}, + {0x7af8, 4214}, + {0x7af9, 2971}, + {0x7afa, 2271}, + {0x7aff, 1540}, + {0x7b02, 5958}, + {0x7b04, 5971}, + {0x7b06, 5961}, + {0x7b08, 1666}, + {0x7b0a, 5960}, + {0x7b0b, 5973}, + {0x7b0f, 5959}, + {0x7b11, 2488}, + {0x7b18, 5963}, + {0x7b19, 5964}, + {0x7b1b, 3109}, + {0x7b1e, 5965}, + {0x7b20, 1468}, + {0x7b25, 2592}, + {0x7b26, 3542}, + {0x7b28, 5967}, + {0x7b2c, 2888}, + {0x7b33, 5962}, + {0x7b35, 5966}, + {0x7b36, 5968}, + {0x7b39, 2155}, + {0x7b45, 5975}, + {0x7b46, 3488}, + {0x7b48, 3386}, + {0x7b49, 3187}, + {0x7b4b, 1746}, + {0x7b4c, 5974}, + {0x7b4d, 5972}, + {0x7b4f, 3401}, + {0x7b50, 5969}, + {0x7b51, 2972}, + {0x7b52, 3189}, + {0x7b54, 3188}, + {0x7b56, 2150}, + {0x7b5d, 5993}, + {0x7b65, 5977}, + {0x7b67, 5979}, + {0x7b6c, 5982}, + {0x7b6e, 5983}, + {0x7b70, 5980}, + {0x7b71, 5981}, + {0x7b74, 5978}, + {0x7b75, 5976}, + {0x7b7a, 5970}, + {0x7b86, 3615}, + {0x7b87, 1365}, + {0x7b8b, 5990}, + {0x7b8d, 5987}, + {0x7b8f, 5992}, + {0x7b92, 5991}, + {0x7b94, 3369}, + {0x7b95, 3763}, + {0x7b97, 2185}, + {0x7b98, 5985}, + {0x7b99, 5994}, + {0x7b9a, 5989}, + {0x7b9c, 5988}, + {0x7b9d, 5984}, + {0x7b9e, 8589}, + {0x7b9f, 5986}, + {0x7ba1, 1541}, + {0x7baa, 2939}, + {0x7bad, 2721}, + {0x7bb1, 3382}, + {0x7bb4, 5999}, + {0x7bb8, 3384}, + {0x7bc0, 2693}, + {0x7bc1, 5996}, + {0x7bc4, 3427}, + {0x7bc6, 6000}, + {0x7bc7, 3619}, + {0x7bc9, 2969}, + {0x7bcb, 5995}, + {0x7bcc, 5997}, + {0x7bcf, 5998}, + {0x7bdd, 6001}, + {0x7be0, 2288}, + {0x7be4, 3230}, + {0x7be5, 6006}, + {0x7be6, 6005}, + {0x7be9, 6002}, + {0x7bed, 4060}, + {0x7bf3, 6011}, + {0x7bf6, 6015}, + {0x7bf7, 6012}, + {0x7c00, 6008}, + {0x7c07, 6009}, + {0x7c0d, 6014}, + {0x7c11, 6003}, + {0x7c12, 4330}, + {0x7c13, 6010}, + {0x7c14, 6004}, + {0x7c17, 6013}, + {0x7c1e, 7739}, + {0x7c1f, 6019}, + {0x7c21, 1542}, + {0x7c23, 6016}, + {0x7c27, 6017}, + {0x7c2a, 6018}, + {0x7c2b, 6021}, + {0x7c37, 6020}, + {0x7c38, 3466}, + {0x7c3d, 6022}, + {0x7c3e, 4036}, + {0x7c3f, 3645}, + {0x7c40, 6027}, + {0x7c43, 6024}, + {0x7c4c, 6023}, + {0x7c4d, 2678}, + {0x7c4f, 6026}, + {0x7c50, 6028}, + {0x7c54, 6025}, + {0x7c56, 6032}, + {0x7c58, 6029}, + {0x7c5f, 6030}, + {0x7c60, 6007}, + {0x7c64, 6031}, + {0x7c65, 6033}, + {0x7c6c, 6034}, + {0x7c73, 3606}, + {0x7c75, 6035}, + {0x7c7e, 3822}, + {0x7c81, 1734}, + {0x7c82, 1791}, + {0x7c83, 6036}, + {0x7c89, 3588}, + {0x7c8b, 2606}, + {0x7c8d, 3772}, + {0x7c90, 6037}, + {0x7c92, 3963}, + {0x7c95, 3370}, + {0x7c97, 2760}, + {0x7c98, 3306}, + {0x7c9b, 2391}, + {0x7c9f, 1156}, + {0x7ca1, 6042}, + {0x7ca2, 6040}, + {0x7ca4, 6038}, + {0x7ca5, 1501}, + {0x7ca7, 2489}, + {0x7ca8, 6043}, + {0x7cab, 6041}, + {0x7cad, 6039}, + {0x7cae, 6047}, + {0x7cb1, 6046}, + {0x7cb2, 6045}, + {0x7cb3, 6044}, + {0x7cb9, 6048}, + {0x7cbd, 6049}, + {0x7cbe, 2654}, + {0x7cc0, 6050}, + {0x7cc2, 6052}, + {0x7cc5, 6051}, + {0x7cc9, 0}, + {0x7cca, 1926}, + {0x7cce, 2746}, + {0x7cd2, 6054}, + {0x7cd6, 3190}, + {0x7cd8, 6053}, + {0x7cdc, 6055}, + {0x7cde, 3589}, + {0x7cdf, 2798}, + {0x7ce0, 2009}, + {0x7ce2, 6056}, + {0x7ce7, 3984}, + {0x7cef, 6058}, + {0x7cf2, 6059}, + {0x7cf4, 6060}, + {0x7cf6, 6061}, + {0x7cf8, 2227}, + {0x7cfa, 6062}, + {0x7cfb, 1829}, + {0x7cfe, 1668}, + {0x7d00, 1604}, + {0x7d02, 6064}, + {0x7d04, 3839}, + {0x7d05, 2010}, + {0x7d06, 6063}, + {0x7d08, 0}, + {0x7d09, 1}, + {0x7d0a, 6067}, + {0x7d0b, 3826}, + {0x7d0d, 3314}, + {0x7d10, 3493}, + {0x7d14, 2413}, + {0x7d15, 6066}, + {0x7d17, 2303}, + {0x7d18, 2011}, + {0x7d19, 2228}, + {0x7d1a, 1667}, + {0x7d1b, 3590}, + {0x7d1c, 6065}, + {0x7d20, 2761}, + {0x7d21, 3696}, + {0x7d22, 2151}, + {0x7d2b, 2229}, + {0x7d2c, 3065}, + {0x7d2e, 6070}, + {0x7d2f, 4007}, + {0x7d30, 2121}, + {0x7d32, 6071}, + {0x7d33, 2568}, + {0x7d35, 6073}, + {0x7d39, 2490}, + {0x7d3a, 2080}, + {0x7d3f, 6072}, + {0x7d42, 2356}, + {0x7d43, 1906}, + {0x7d44, 2762}, + {0x7d45, 6068}, + {0x7d46, 6074}, + {0x7d48, 8591}, + {0x7d4b, 6069}, + {0x7d4c, 1830}, + {0x7d4e, 6077}, + {0x7d4f, 6081}, + {0x7d50, 1857}, + {0x7d56, 6076}, + {0x7d5b, 6085}, + {0x7d5c, 8592}, + {0x7d5e, 2012}, + {0x7d61, 3927}, + {0x7d62, 1152}, + {0x7d63, 6082}, + {0x7d66, 1669}, + {0x7d68, 6079}, + {0x7d6e, 6080}, + {0x7d71, 3191}, + {0x7d72, 6078}, + {0x7d73, 6075}, + {0x7d75, 1414}, + {0x7d76, 2696}, + {0x7d79, 1884}, + {0x7d7d, 6087}, + {0x7d89, 6084}, + {0x7d8c, 0}, + {0x7d8f, 6086}, + {0x7d93, 6083}, + {0x7d99, 1831}, + {0x7d9a, 2835}, + {0x7d9b, 6088}, + {0x7d9c, 2800}, + {0x7d9f, 6101}, + {0x7da0, 8594}, + {0x7da2, 6097}, + {0x7da3, 6091}, + {0x7dab, 6095}, + {0x7dac, 2342}, + {0x7dad, 1185}, + {0x7dae, 6090}, + {0x7daf, 6098}, + {0x7db0, 6102}, + {0x7db1, 2013}, + {0x7db2, 3810}, + {0x7db4, 3058}, + {0x7db5, 6092}, + {0x7db7, 8593}, + {0x7db8, 6100}, + {0x7dba, 6089}, + {0x7dbb, 2940}, + {0x7dbd, 6094}, + {0x7dbe, 1153}, + {0x7dbf, 3798}, + {0x7dc7, 6093}, + {0x7dca, 1747}, + {0x7dcb, 3456}, + {0x7dcf, 2799}, + {0x7dd1, 3992}, + {0x7dd2, 2425}, + {0x7dd5, 6141}, + {0x7dd6, 8595}, + {0x7dd8, 6103}, + {0x7dda, 2722}, + {0x7ddc, 6099}, + {0x7ddd, 6104}, + {0x7dde, 6106}, + {0x7de0, 3093}, + {0x7de1, 6109}, + {0x7de4, 6105}, + {0x7de8, 3620}, + {0x7de9, 1543}, + {0x7dec, 3799}, + {0x7def, 1186}, + {0x7df2, 6108}, + {0x7df4, 4037}, + {0x7dfb, 6107}, + {0x7e01, 1297}, + {0x7e04, 3268}, + {0x7e05, 6110}, + {0x7e09, 6117}, + {0x7e0a, 6111}, + {0x7e0b, 6118}, + {0x7e12, 6114}, + {0x7e1b, 3377}, + {0x7e1e, 2294}, + {0x7e1f, 6116}, + {0x7e21, 6113}, + {0x7e22, 6119}, + {0x7e23, 6112}, + {0x7e26, 2382}, + {0x7e2b, 3667}, + {0x7e2e, 2390}, + {0x7e31, 6115}, + {0x7e32, 6127}, + {0x7e35, 6123}, + {0x7e37, 6126}, + {0x7e39, 6124}, + {0x7e3a, 6128}, + {0x7e3b, 6122}, + {0x7e3d, 6096}, + {0x7e3e, 2679}, + {0x7e41, 3423}, + {0x7e43, 6125}, + {0x7e46, 6120}, + {0x7e4a, 2723}, + {0x7e4b, 1832}, + {0x7e4d, 2357}, + {0x7e52, 8596}, + {0x7e54, 2539}, + {0x7e55, 2744}, + {0x7e56, 6131}, + {0x7e59, 6133}, + {0x7e5a, 6134}, + {0x7e5d, 6130}, + {0x7e5e, 6132}, + {0x7e61, 7697}, + {0x7e66, 6121}, + {0x7e67, 6129}, + {0x7e69, 6137}, + {0x7e6a, 6136}, + {0x7e6b, 7671}, + {0x7e6d, 3752}, + {0x7e70, 1793}, + {0x7e79, 6135}, + {0x7e7b, 6139}, + {0x7e7c, 6138}, + {0x7e7d, 6142}, + {0x7e7f, 6144}, + {0x7e82, 2186}, + {0x7e83, 6140}, + {0x7e88, 6145}, + {0x7e89, 6146}, + {0x7e8a, 8359}, + {0x7e8c, 6147}, + {0x7e8e, 6153}, + {0x7e8f, 3125}, + {0x7e90, 6149}, + {0x7e92, 6148}, + {0x7e93, 6150}, + {0x7e94, 6151}, + {0x7e96, 6152}, + {0x7e9b, 6154}, + {0x7e9c, 6155}, + {0x7f36, 1544}, + {0x7f38, 6156}, + {0x7f3a, 6157}, + {0x7f45, 6158}, + {0x7f47, 8597}, + {0x7f4c, 6159}, + {0x7f4d, 6160}, + {0x7f4e, 6161}, + {0x7f50, 6162}, + {0x7f51, 6163}, + {0x7f53, 0}, + {0x7f54, 6165}, + {0x7f55, 6164}, + {0x7f58, 6166}, + {0x7f5f, 6167}, + {0x7f60, 6168}, + {0x7f67, 6171}, + {0x7f68, 6169}, + {0x7f69, 6170}, + {0x7f6a, 2129}, + {0x7f6b, 1833}, + {0x7f6e, 2964}, + {0x7f70, 3399}, + {0x7f72, 2426}, + {0x7f75, 3331}, + {0x7f77, 3457}, + {0x7f78, 6172}, + {0x7f79, 4918}, + {0x7f82, 6173}, + {0x7f83, 6175}, + {0x7f85, 3919}, + {0x7f86, 6174}, + {0x7f87, 6177}, + {0x7f88, 6176}, + {0x7f8a, 3901}, + {0x7f8c, 6178}, + {0x7f8e, 3474}, + {0x7f94, 6179}, + {0x7f9a, 6182}, + {0x7f9d, 6181}, + {0x7f9e, 6180}, + {0x7fa1, 8598}, + {0x7fa3, 6183}, + {0x7fa4, 1800}, + {0x7fa8, 2724}, + {0x7fa9, 1627}, + {0x7fae, 6187}, + {0x7faf, 6184}, + {0x7fb2, 6185}, + {0x7fb6, 6188}, + {0x7fb8, 6189}, + {0x7fb9, 6186}, + {0x7fbd, 1227}, + {0x7fc1, 1319}, + {0x7fc5, 6191}, + {0x7fc6, 6192}, + {0x7fca, 6193}, + {0x7fcc, 3916}, + {0x7fd2, 2358}, + {0x7fd4, 6195}, + {0x7fd5, 6194}, + {0x7fe0, 2607}, + {0x7fe1, 6196}, + {0x7fe6, 6197}, + {0x7fe9, 6198}, + {0x7feb, 1569}, + {0x7fef, 0}, + {0x7ff0, 1545}, + {0x7ff3, 6199}, + {0x7ff9, 6200}, + {0x7ffb, 3723}, + {0x7ffc, 3917}, + {0x8000, 3902}, + {0x8001, 4061}, + {0x8003, 2015}, + {0x8004, 6203}, + {0x8005, 2304}, + {0x8006, 6202}, + {0x800b, 6204}, + {0x800c, 2261}, + {0x8010, 2865}, + {0x8012, 6205}, + {0x8015, 2014}, + {0x8017, 3811}, + {0x8018, 6206}, + {0x8019, 6207}, + {0x801c, 6208}, + {0x8021, 6209}, + {0x8028, 6210}, + {0x8033, 2262}, + {0x8036, 3833}, + {0x803b, 6212}, + {0x803d, 2941}, + {0x803f, 6211}, + {0x8046, 6214}, + {0x804a, 6213}, + {0x8052, 6215}, + {0x8056, 2655}, + {0x8058, 6216}, + {0x805a, 6217}, + {0x805e, 3593}, + {0x805f, 6218}, + {0x8061, 2801}, + {0x8062, 6219}, + {0x8068, 6220}, + {0x806f, 4038}, + {0x8070, 6223}, + {0x8072, 6222}, + {0x8073, 6221}, + {0x8074, 3020}, + {0x8076, 6224}, + {0x8077, 2540}, + {0x8079, 6225}, + {0x807d, 6226}, + {0x807e, 4062}, + {0x807f, 6227}, + {0x8084, 6228}, + {0x8085, 6230}, + {0x8086, 6229}, + {0x8087, 3385}, + {0x8089, 3281}, + {0x808b, 4068}, + {0x808c, 3389}, + {0x8093, 6232}, + {0x8096, 2491}, + {0x8098, 3484}, + {0x809a, 6233}, + {0x809b, 6231}, + {0x809d, 1546}, + {0x80a1, 1928}, + {0x80a2, 2230}, + {0x80a5, 3458}, + {0x80a9, 1886}, + {0x80aa, 3697}, + {0x80ac, 6236}, + {0x80ad, 6234}, + {0x80af, 2016}, + {0x80b1, 2017}, + {0x80b2, 1197}, + {0x80b4, 2136}, + {0x80ba, 3343}, + {0x80c3, 1187}, + {0x80c4, 6241}, + {0x80c6, 2942}, + {0x80cc, 3342}, + {0x80ce, 2875}, + {0x80d6, 6243}, + {0x80d8, 0}, + {0x80d9, 6239}, + {0x80da, 6242}, + {0x80db, 6237}, + {0x80dd, 6240}, + {0x80de, 3668}, + {0x80e1, 1929}, + {0x80e4, 1217}, + {0x80e5, 6238}, + {0x80ef, 6245}, + {0x80f1, 6246}, + {0x80f4, 3217}, + {0x80f8, 1715}, + {0x80fc, 6257}, + {0x80fd, 3315}, + {0x8102, 2231}, + {0x8105, 1716}, + {0x8106, 2668}, + {0x8107, 4076}, + {0x8108, 3770}, + {0x8109, 6244}, + {0x810a, 2680}, + {0x811a, 1645}, + {0x811b, 6247}, + {0x8123, 6249}, + {0x8129, 6248}, + {0x812f, 6250}, + {0x8131, 2916}, + {0x8133, 3316}, + {0x8139, 3021}, + {0x813e, 6254}, + {0x8146, 6253}, + {0x814b, 6251}, + {0x814e, 2587}, + {0x8150, 3543}, + {0x8151, 6256}, + {0x8153, 6255}, + {0x8154, 2018}, + {0x8155, 4089}, + {0x815f, 6272}, + {0x8165, 6260}, + {0x8166, 6261}, + {0x816b, 2332}, + {0x816e, 6259}, + {0x8170, 2058}, + {0x8171, 6258}, + {0x8174, 6262}, + {0x8178, 3022}, + {0x8179, 3570}, + {0x817a, 2725}, + {0x817f, 2876}, + {0x8180, 6266}, + {0x8182, 6267}, + {0x8183, 6263}, + {0x8188, 6264}, + {0x818a, 6265}, + {0x818f, 2019}, + {0x8193, 6273}, + {0x8195, 6269}, + {0x819a, 3544}, + {0x819c, 3738}, + {0x819d, 3482}, + {0x81a0, 6268}, + {0x81a3, 6271}, + {0x81a4, 6270}, + {0x81a8, 3698}, + {0x81a9, 6274}, + {0x81b0, 6275}, + {0x81b3, 2745}, + {0x81b5, 6276}, + {0x81b8, 6278}, + {0x81ba, 6282}, + {0x81bd, 6279}, + {0x81be, 6277}, + {0x81bf, 3317}, + {0x81c0, 6280}, + {0x81c2, 6281}, + {0x81c6, 1330}, + {0x81c8, 6288}, + {0x81c9, 6283}, + {0x81cd, 6284}, + {0x81d1, 6285}, + {0x81d3, 2817}, + {0x81d8, 6287}, + {0x81d9, 6286}, + {0x81da, 6289}, + {0x81df, 6290}, + {0x81e0, 6291}, + {0x81e3, 2569}, + {0x81e5, 1385}, + {0x81e7, 6292}, + {0x81e8, 3999}, + {0x81ea, 2263}, + {0x81ed, 2359}, + {0x81f3, 2232}, + {0x81f4, 2965}, + {0x81fa, 6293}, + {0x81fb, 6294}, + {0x81fc, 1235}, + {0x81fe, 6295}, + {0x8201, 6296}, + {0x8202, 6297}, + {0x8205, 6298}, + {0x8207, 6299}, + {0x8208, 1717}, + {0x8209, 5039}, + {0x820a, 6300}, + {0x820c, 2697}, + {0x820d, 6301}, + {0x820e, 2295}, + {0x8210, 6302}, + {0x8212, 4105}, + {0x8216, 6303}, + {0x8217, 3630}, + {0x8218, 1560}, + {0x821b, 2726}, + {0x821c, 2402}, + {0x821e, 3555}, + {0x821f, 2360}, + {0x8229, 6304}, + {0x822a, 2020}, + {0x822b, 6305}, + {0x822c, 3424}, + {0x822e, 6319}, + {0x8233, 6307}, + {0x8235, 2857}, + {0x8236, 3371}, + {0x8237, 1907}, + {0x8238, 6306}, + {0x8239, 2727}, + {0x8240, 6308}, + {0x8247, 3094}, + {0x8258, 6310}, + {0x8259, 6309}, + {0x825a, 6312}, + {0x825d, 6311}, + {0x825f, 6313}, + {0x8262, 6315}, + {0x8264, 6314}, + {0x8266, 1547}, + {0x8268, 6316}, + {0x826a, 6317}, + {0x826b, 6318}, + {0x826e, 2081}, + {0x826f, 3985}, + {0x8271, 6320}, + {0x8272, 2541}, + {0x8276, 1298}, + {0x8277, 6321}, + {0x8278, 6322}, + {0x827e, 6323}, + {0x828b, 1206}, + {0x828d, 6324}, + {0x8292, 6325}, + {0x8299, 3545}, + {0x829d, 2291}, + {0x829f, 6327}, + {0x82a5, 1415}, + {0x82a6, 1142}, + {0x82ab, 6326}, + {0x82ac, 6329}, + {0x82ad, 3332}, + {0x82af, 2570}, + {0x82b1, 1366}, + {0x82b3, 3669}, + {0x82b8, 1843}, + {0x82b9, 1748}, + {0x82bb, 6328}, + {0x82bd, 1386}, + {0x82c5, 1503}, + {0x82d1, 1299}, + {0x82d2, 6333}, + {0x82d3, 4018}, + {0x82d4, 2877}, + {0x82d7, 3510}, + {0x82d9, 6345}, + {0x82db, 1367}, + {0x82dc, 6343}, + {0x82de, 6341}, + {0x82df, 6332}, + {0x82e1, 6330}, + {0x82e3, 6331}, + {0x82e5, 2319}, + {0x82e6, 1764}, + {0x82e7, 2997}, + {0x82eb, 3241}, + {0x82f1, 1267}, + {0x82f3, 6335}, + {0x82f4, 6334}, + {0x82f9, 6340}, + {0x82fa, 6336}, + {0x82fb, 6339}, + {0x8301, 8600}, + {0x8302, 3804}, + {0x8303, 6338}, + {0x8304, 1368}, + {0x8305, 1499}, + {0x8306, 6342}, + {0x8309, 6344}, + {0x830e, 1834}, + {0x8316, 6348}, + {0x8317, 6357}, + {0x8318, 6358}, + {0x831c, 1135}, + {0x8323, 6365}, + {0x8328, 1205}, + {0x832b, 6356}, + {0x832f, 6355}, + {0x8331, 6350}, + {0x8332, 6349}, + {0x8334, 6347}, + {0x8335, 6346}, + {0x8336, 2977}, + {0x8338, 2907}, + {0x8339, 6352}, + {0x8340, 6351}, + {0x8345, 6354}, + {0x8349, 2802}, + {0x834a, 1835}, + {0x834f, 1251}, + {0x8350, 6353}, + {0x8352, 2021}, + {0x8358, 2803}, + {0x8362, 8601}, + {0x8373, 6371}, + {0x8375, 6372}, + {0x8377, 1369}, + {0x837b, 1326}, + {0x837c, 6369}, + {0x837f, 8602}, + {0x8385, 6359}, + {0x8387, 6367}, + {0x8389, 6374}, + {0x838a, 6368}, + {0x838e, 6366}, + {0x8393, 6337}, + {0x8396, 6364}, + {0x839a, 6360}, + {0x839e, 1548}, + {0x839f, 6362}, + {0x83a0, 6373}, + {0x83a2, 6363}, + {0x83a8, 6375}, + {0x83aa, 6361}, + {0x83ab, 3378}, + {0x83b1, 3923}, + {0x83b5, 6370}, + {0x83bd, 6392}, + {0x83c0, 0}, + {0x83c1, 6384}, + {0x83c5, 2625}, + {0x83c7, 8603}, + {0x83ca, 1632}, + {0x83cc, 1749}, + {0x83ce, 6379}, + {0x83d3, 1371}, + {0x83d6, 2492}, + {0x83d8, 6382}, + {0x83dc, 2122}, + {0x83df, 3147}, + {0x83e0, 6387}, + {0x83e9, 3646}, + {0x83eb, 6378}, + {0x83ef, 1370}, + {0x83f0, 1930}, + {0x83f1, 3483}, + {0x83f2, 6388}, + {0x83f4, 6376}, + {0x83f6, 8604}, + {0x83f7, 6385}, + {0x83fb, 6395}, + {0x83fd, 6380}, + {0x8403, 6381}, + {0x8404, 3218}, + {0x8407, 6386}, + {0x840a, 7807}, + {0x840b, 6383}, + {0x840c, 3670}, + {0x840d, 6389}, + {0x840e, 1188}, + {0x8413, 6377}, + {0x8420, 6391}, + {0x8422, 6390}, + {0x8429, 3361}, + {0x842a, 6397}, + {0x842c, 6408}, + {0x8431, 1500}, + {0x8435, 6411}, + {0x8438, 6393}, + {0x843c, 6398}, + {0x843d, 3928}, + {0x8446, 6407}, + {0x8448, 8605}, + {0x8449, 3903}, + {0x844e, 3954}, + {0x8457, 2998}, + {0x845b, 1481}, + {0x8461, 3556}, + {0x8462, 6413}, + {0x8463, 3193}, + {0x8466, 1141}, + {0x8469, 6406}, + {0x846b, 6402}, + {0x846c, 2804}, + {0x846d, 6396}, + {0x846e, 6404}, + {0x846f, 6409}, + {0x8471, 3298}, + {0x8475, 1134}, + {0x8477, 6401}, + {0x8479, 6410}, + {0x847a, 3562}, + {0x8482, 6405}, + {0x8484, 6400}, + {0x848b, 2493}, + {0x8490, 2361}, + {0x8494, 2264}, + {0x8499, 3812}, + {0x849c, 3513}, + {0x849f, 6416}, + {0x84a1, 6425}, + {0x84ad, 6403}, + {0x84b2, 1493}, + {0x84b4, 8606}, + {0x84b8, 2528}, + {0x84b9, 6414}, + {0x84bb, 6419}, + {0x84bc, 2805}, + {0x84bf, 6415}, + {0x84c1, 6422}, + {0x84c4, 2973}, + {0x84c6, 6423}, + {0x84c9, 3904}, + {0x84ca, 6412}, + {0x84cb, 1430}, + {0x84cd, 6418}, + {0x84d0, 6421}, + {0x84d1, 3768}, + {0x84d6, 6424}, + {0x84d9, 6417}, + {0x84da, 6420}, + {0x84dc, 8363}, + {0x84ec, 3671}, + {0x84ee, 4039}, + {0x84f4, 6428}, + {0x84fc, 6435}, + {0x84ff, 6427}, + {0x8500, 2287}, + {0x8506, 6394}, + {0x8511, 3614}, + {0x8513, 3758}, + {0x8514, 6434}, + {0x8515, 6433}, + {0x8517, 6429}, + {0x8518, 6430}, + {0x851a, 1240}, + {0x851f, 6432}, + {0x8521, 6426}, + {0x8523, 7706}, + {0x8526, 3057}, + {0x852c, 6431}, + {0x852d, 1218}, + {0x8535, 2818}, + {0x853d, 3603}, + {0x853e, 7861}, + {0x8540, 6436}, + {0x8541, 6440}, + {0x8543, 3437}, + {0x8548, 6439}, + {0x8549, 2494}, + {0x854a, 2293}, + {0x854b, 6442}, + {0x854e, 1718}, + {0x8553, 8607}, + {0x8555, 6443}, + {0x8557, 3563}, + {0x8558, 6438}, + {0x8559, 8608}, + {0x855a, 6399}, + {0x8563, 6437}, + {0x8568, 4085}, + {0x8569, 3194}, + {0x856a, 3557}, + {0x856b, 8609}, + {0x856d, 6450}, + {0x8577, 6456}, + {0x857e, 6457}, + {0x8580, 6444}, + {0x8584, 3372}, + {0x8587, 6454}, + {0x8588, 6446}, + {0x858a, 6448}, + {0x8590, 6458}, + {0x8591, 6447}, + {0x8594, 6451}, + {0x8597, 1300}, + {0x8599, 3261}, + {0x859b, 6452}, + {0x859c, 6455}, + {0x85a4, 6445}, + {0x85a6, 2728}, + {0x85a8, 6449}, + {0x85a9, 2165}, + {0x85aa, 2571}, + {0x85ab, 1798}, + {0x85ac, 3840}, + {0x85ae, 3845}, + {0x85af, 2428}, + {0x85b0, 8611}, + {0x85b9, 6462}, + {0x85ba, 6460}, + {0x85c1, 4084}, + {0x85c9, 6459}, + {0x85cd, 3935}, + {0x85cf, 6461}, + {0x85d0, 6463}, + {0x85d5, 6464}, + {0x85dc, 6467}, + {0x85dd, 6465}, + {0x85e4, 3195}, + {0x85e5, 6466}, + {0x85e9, 3425}, + {0x85ea, 6453}, + {0x85f7, 2429}, + {0x85f9, 6468}, + {0x85fa, 6473}, + {0x85fb, 2806}, + {0x85fe, 6472}, + {0x8602, 6441}, + {0x8606, 6474}, + {0x8607, 2763}, + {0x860a, 6469}, + {0x860b, 6471}, + {0x8613, 6470}, + {0x8616, 5328}, + {0x8617, 5313}, + {0x861a, 6476}, + {0x8622, 6475}, + {0x862d, 3936}, + {0x862f, 5809}, + {0x8630, 6477}, + {0x863f, 6478}, + {0x864d, 6479}, + {0x864e, 1931}, + {0x8650, 1646}, + {0x8654, 6481}, + {0x8655, 4244}, + {0x865a, 1679}, + {0x865c, 3970}, + {0x865e, 1771}, + {0x865f, 6482}, + {0x8667, 6483}, + {0x866b, 2988}, + {0x8671, 6484}, + {0x8679, 3282}, + {0x867b, 1150}, + {0x868a, 1379}, + {0x868b, 6489}, + {0x868c, 6490}, + {0x8693, 6485}, + {0x8695, 2187}, + {0x86a3, 6486}, + {0x86a4, 3320}, + {0x86a8, 0}, + {0x86a9, 6487}, + {0x86aa, 6488}, + {0x86ab, 6498}, + {0x86af, 6492}, + {0x86b0, 6495}, + {0x86b6, 6491}, + {0x86c4, 6493}, + {0x86c6, 6494}, + {0x86c7, 2308}, + {0x86c9, 6496}, + {0x86cb, 2943}, + {0x86cd, 1836}, + {0x86ce, 1440}, + {0x86d4, 6499}, + {0x86d9, 1437}, + {0x86db, 6504}, + {0x86de, 6500}, + {0x86df, 6503}, + {0x86e4, 3406}, + {0x86e9, 6501}, + {0x86ec, 6502}, + {0x86ed, 3514}, + {0x86ee, 3438}, + {0x86ef, 6505}, + {0x86f8, 2909}, + {0x86f9, 6515}, + {0x86fb, 6511}, + {0x86fe, 1387}, + {0x8700, 6509}, + {0x8702, 3672}, + {0x8703, 6510}, + {0x8706, 6507}, + {0x8708, 6508}, + {0x8709, 6513}, + {0x870a, 6516}, + {0x870d, 6514}, + {0x8711, 6512}, + {0x8712, 6506}, + {0x8718, 2966}, + {0x871a, 6523}, + {0x871c, 3766}, + {0x8725, 6521}, + {0x8729, 6522}, + {0x8734, 6517}, + {0x8737, 6519}, + {0x873b, 6520}, + {0x873f, 6518}, + {0x8749, 2698}, + {0x874b, 4063}, + {0x874c, 6527}, + {0x874e, 6528}, + {0x8753, 6534}, + {0x8755, 2544}, + {0x8757, 6530}, + {0x8759, 6533}, + {0x875f, 6525}, + {0x8760, 6524}, + {0x8763, 6535}, + {0x8766, 1372}, + {0x8768, 6531}, + {0x876a, 6536}, + {0x876e, 6532}, + {0x8774, 6529}, + {0x8776, 3023}, + {0x8778, 6526}, + {0x877f, 3358}, + {0x8782, 6540}, + {0x878d, 3877}, + {0x879f, 6539}, + {0x87a2, 6538}, + {0x87ab, 6547}, + {0x87ad, 0}, + {0x87af, 6541}, + {0x87b3, 6549}, + {0x87ba, 3920}, + {0x87bb, 6552}, + {0x87bd, 6543}, + {0x87c0, 6544}, + {0x87c4, 6548}, + {0x87c6, 6551}, + {0x87c7, 6550}, + {0x87cb, 6542}, + {0x87d0, 6545}, + {0x87d2, 6562}, + {0x87e0, 6555}, + {0x87ec, 7715}, + {0x87ef, 6553}, + {0x87f2, 6554}, + {0x87f6, 6559}, + {0x87f7, 6560}, + {0x87f9, 1416}, + {0x87fb, 1628}, + {0x87fe, 6558}, + {0x8805, 6537}, + {0x8807, 8614}, + {0x880d, 6557}, + {0x880e, 6561}, + {0x880f, 6556}, + {0x8811, 6563}, + {0x8815, 6565}, + {0x8816, 6564}, + {0x881f, 7813}, + {0x8821, 6567}, + {0x8822, 6566}, + {0x8823, 6497}, + {0x8827, 6571}, + {0x8831, 6568}, + {0x8836, 6569}, + {0x8839, 6570}, + {0x883b, 6572}, + {0x8840, 1858}, + {0x8842, 6574}, + {0x8844, 6573}, + {0x8846, 2362}, + {0x884c, 2022}, + {0x884d, 5412}, + {0x8852, 6575}, + {0x8853, 2395}, + {0x8857, 1431}, + {0x8859, 6576}, + {0x885b, 1268}, + {0x885d, 2495}, + {0x885e, 6577}, + {0x8861, 2023}, + {0x8862, 6578}, + {0x8863, 1189}, + {0x8868, 3503}, + {0x886b, 6579}, + {0x8870, 2608}, + {0x8872, 6586}, + {0x8875, 6583}, + {0x8877, 2989}, + {0x887d, 6584}, + {0x887e, 6581}, + {0x887f, 1750}, + {0x8881, 6580}, + {0x8882, 6587}, + {0x8888, 1804}, + {0x888b, 2878}, + {0x888d, 6593}, + {0x8892, 6589}, + {0x8896, 2837}, + {0x8897, 6588}, + {0x8899, 6591}, + {0x889e, 6582}, + {0x88a2, 6592}, + {0x88a4, 6594}, + {0x88ab, 3459}, + {0x88ae, 6590}, + {0x88b0, 6595}, + {0x88b1, 6597}, + {0x88b4, 1927}, + {0x88b5, 6585}, + {0x88b7, 1157}, + {0x88be, 0}, + {0x88bf, 6596}, + {0x88c1, 2123}, + {0x88c2, 4030}, + {0x88c3, 6598}, + {0x88c4, 6599}, + {0x88c5, 2807}, + {0x88cf, 3946}, + {0x88d4, 6600}, + {0x88d5, 3871}, + {0x88d8, 6601}, + {0x88d9, 6602}, + {0x88dc, 3636}, + {0x88dd, 6603}, + {0x88df, 2096}, + {0x88e1, 3947}, + {0x88e8, 6608}, + {0x88f1, 0}, + {0x88f2, 6609}, + {0x88f3, 2496}, + {0x88f4, 6607}, + {0x88f5, 8615}, + {0x88f8, 3921}, + {0x88f9, 6604}, + {0x88fc, 6606}, + {0x88fd, 2657}, + {0x88fe, 2628}, + {0x8902, 6605}, + {0x8904, 6610}, + {0x8907, 3571}, + {0x890a, 6612}, + {0x890c, 6611}, + {0x8910, 1482}, + {0x8912, 3673}, + {0x8913, 6613}, + {0x8919, 0}, + {0x891a, 1}, + {0x891c, 8360}, + {0x891d, 6625}, + {0x891e, 6615}, + {0x8925, 6616}, + {0x892a, 6617}, + {0x892b, 6618}, + {0x8936, 6622}, + {0x8938, 6623}, + {0x893b, 6621}, + {0x8941, 6619}, + {0x8943, 6614}, + {0x8944, 6620}, + {0x894c, 6624}, + {0x894d, 7120}, + {0x8956, 1320}, + {0x895e, 6627}, + {0x895f, 1751}, + {0x8960, 6626}, + {0x8964, 6629}, + {0x8966, 6628}, + {0x896a, 6631}, + {0x896d, 6630}, + {0x896f, 6632}, + {0x8972, 2363}, + {0x8974, 6633}, + {0x8977, 6634}, + {0x897e, 6635}, + {0x897f, 2658}, + {0x8981, 3905}, + {0x8983, 6636}, + {0x8986, 3572}, + {0x8987, 3324}, + {0x8988, 6637}, + {0x898a, 6638}, + {0x898b, 1887}, + {0x898f, 1606}, + {0x8993, 6639}, + {0x8996, 2233}, + {0x8997, 3319}, + {0x8998, 6640}, + {0x899a, 1454}, + {0x89a1, 6641}, + {0x89a6, 6643}, + {0x89a7, 3937}, + {0x89a9, 6642}, + {0x89aa, 2572}, + {0x89ac, 6644}, + {0x89af, 6645}, + {0x89b2, 6646}, + {0x89b3, 1549}, + {0x89ba, 6647}, + {0x89bd, 6648}, + {0x89bf, 6649}, + {0x89c0, 6650}, + {0x89d2, 1455}, + {0x89da, 6651}, + {0x89dc, 6652}, + {0x89dd, 6653}, + {0x89e3, 1394}, + {0x89e6, 2542}, + {0x89e7, 6654}, + {0x89f4, 6655}, + {0x89f8, 6656}, + {0x8a00, 1908}, + {0x8a02, 3095}, + {0x8a03, 6657}, + {0x8a08, 1837}, + {0x8a0a, 2588}, + {0x8a0c, 6660}, + {0x8a0e, 3196}, + {0x8a10, 6659}, + {0x8a12, 8616}, + {0x8a13, 1799}, + {0x8a16, 6658}, + {0x8a17, 2903}, + {0x8a18, 1607}, + {0x8a1b, 6661}, + {0x8a1d, 6662}, + {0x8a1f, 2497}, + {0x8a23, 1859}, + {0x8a25, 6663}, + {0x8a2a, 3674}, + {0x8a2d, 2691}, + {0x8a31, 1680}, + {0x8a33, 3841}, + {0x8a34, 2764}, + {0x8a36, 6664}, + {0x8a37, 8617}, + {0x8a3a, 2573}, + {0x8a3b, 2990}, + {0x8a3c, 2498}, + {0x8a41, 6665}, + {0x8a46, 6668}, + {0x8a48, 6669}, + {0x8a50, 2094}, + {0x8a51, 2850}, + {0x8a52, 6667}, + {0x8a54, 2499}, + {0x8a55, 3504}, + {0x8a5b, 6666}, + {0x8a5e, 2234}, + {0x8a60, 1269}, + {0x8a62, 6673}, + {0x8a63, 1838}, + {0x8a66, 2236}, + {0x8a69, 2235}, + {0x8a6b, 4083}, + {0x8a6c, 6672}, + {0x8a6d, 6671}, + {0x8a6e, 2729}, + {0x8a70, 1639}, + {0x8a71, 4073}, + {0x8a72, 1432}, + {0x8a73, 2500}, + {0x8a79, 8618}, + {0x8a7c, 6670}, + {0x8a82, 6675}, + {0x8a84, 6676}, + {0x8a85, 6674}, + {0x8a87, 1932}, + {0x8a89, 3882}, + {0x8a8c, 2237}, + {0x8a8d, 3293}, + {0x8a91, 6679}, + {0x8a93, 2660}, + {0x8a95, 2944}, + {0x8a98, 3872}, + {0x8a9a, 6682}, + {0x8a9e, 1952}, + {0x8aa0, 2659}, + {0x8aa1, 6678}, + {0x8aa3, 6683}, + {0x8aa4, 1953}, + {0x8aa5, 6680}, + {0x8aa6, 6681}, + {0x8aa7, 8619}, + {0x8aa8, 6677}, + {0x8aac, 2694}, + {0x8aad, 3233}, + {0x8ab0, 2925}, + {0x8ab2, 1373}, + {0x8ab9, 3460}, + {0x8abc, 1629}, + {0x8abe, 8620}, + {0x8abf, 3024}, + {0x8ac2, 6686}, + {0x8ac4, 6684}, + {0x8ac7, 2954}, + {0x8acb, 2661}, + {0x8acc, 1550}, + {0x8acd, 6685}, + {0x8acf, 2593}, + {0x8ad2, 3986}, + {0x8ad6, 4070}, + {0x8ada, 6687}, + {0x8adb, 6698}, + {0x8adc, 3025}, + {0x8ade, 6697}, + {0x8adf, 8621}, + {0x8ae0, 6694}, + {0x8ae1, 6702}, + {0x8ae2, 6695}, + {0x8ae4, 6691}, + {0x8ae6, 3096}, + {0x8ae7, 6690}, + {0x8aeb, 6688}, + {0x8aed, 3851}, + {0x8aee, 2238}, + {0x8af1, 6692}, + {0x8af3, 6689}, + {0x8af6, 8623}, + {0x8af7, 6696}, + {0x8af8, 2430}, + {0x8afa, 1909}, + {0x8afe, 2906}, + {0x8b00, 3699}, + {0x8b01, 1276}, + {0x8b02, 1190}, + {0x8b04, 3197}, + {0x8b07, 6700}, + {0x8b0c, 6699}, + {0x8b0e, 3262}, + {0x8b10, 6704}, + {0x8b14, 6693}, + {0x8b16, 6703}, + {0x8b17, 6705}, + {0x8b19, 1888}, + {0x8b1a, 6701}, + {0x8b1b, 2024}, + {0x8b1d, 2305}, + {0x8b20, 6706}, + {0x8b21, 3906}, + {0x8b26, 6709}, + {0x8b28, 6712}, + {0x8b2b, 6710}, + {0x8b2c, 3495}, + {0x8b33, 6707}, + {0x8b39, 1752}, + {0x8b3e, 6711}, + {0x8b41, 6713}, + {0x8b44, 0}, + {0x8b49, 6717}, + {0x8b4c, 6714}, + {0x8b4e, 6716}, + {0x8b4f, 6715}, + {0x8b53, 8624}, + {0x8b56, 6718}, + {0x8b58, 2269}, + {0x8b5a, 6720}, + {0x8b5b, 6719}, + {0x8b5c, 3546}, + {0x8b5f, 6722}, + {0x8b66, 1839}, + {0x8b6b, 6721}, + {0x8b6c, 6723}, + {0x8b6f, 6724}, + {0x8b70, 1630}, + {0x8b71, 6190}, + {0x8b72, 2529}, + {0x8b74, 6725}, + {0x8b77, 1954}, + {0x8b7d, 6726}, + {0x8b7f, 8625}, + {0x8b80, 6727}, + {0x8b83, 2188}, + {0x8b8a, 5075}, + {0x8b8c, 6728}, + {0x8b8e, 6729}, + {0x8b90, 2364}, + {0x8b92, 6730}, + {0x8b93, 6731}, + {0x8b96, 6732}, + {0x8b99, 6733}, + {0x8b9a, 6734}, + {0x8c37, 2921}, + {0x8c3a, 6735}, + {0x8c3f, 6737}, + {0x8c41, 6736}, + {0x8c46, 3198}, + {0x8c48, 6738}, + {0x8c4a, 3675}, + {0x8c4c, 6739}, + {0x8c4e, 6740}, + {0x8c50, 6741}, + {0x8c55, 6742}, + {0x8c5a, 3250}, + {0x8c61, 2501}, + {0x8c62, 6743}, + {0x8c6a, 2045}, + {0x8c6b, 4103}, + {0x8c6c, 6744}, + {0x8c78, 6745}, + {0x8c79, 3505}, + {0x8c7a, 6746}, + {0x8c7c, 6754}, + {0x8c82, 6747}, + {0x8c85, 6749}, + {0x8c89, 6748}, + {0x8c8a, 6750}, + {0x8c8c, 3700}, + {0x8c8d, 6751}, + {0x8c8e, 6752}, + {0x8c94, 6753}, + {0x8c98, 6755}, + {0x8c9d, 1419}, + {0x8c9e, 3075}, + {0x8ca0, 3547}, + {0x8ca1, 2130}, + {0x8ca2, 2025}, + {0x8ca7, 3521}, + {0x8ca8, 1375}, + {0x8ca9, 3426}, + {0x8caa, 6758}, + {0x8cab, 1551}, + {0x8cac, 2681}, + {0x8cad, 6757}, + {0x8cae, 6762}, + {0x8caf, 2999}, + {0x8cb0, 3823}, + {0x8cb2, 6760}, + {0x8cb3, 6761}, + {0x8cb4, 1608}, + {0x8cb6, 6763}, + {0x8cb7, 3353}, + {0x8cb8, 2879}, + {0x8cbb, 3461}, + {0x8cbc, 3127}, + {0x8cbd, 6759}, + {0x8cbf, 3701}, + {0x8cc0, 1388}, + {0x8cc1, 6765}, + {0x8cc2, 4046}, + {0x8cc3, 3038}, + {0x8cc4, 4075}, + {0x8cc7, 2239}, + {0x8cc8, 6764}, + {0x8cca, 2833}, + {0x8ccd, 6781}, + {0x8cce, 2730}, + {0x8cd1, 3280}, + {0x8cd3, 3522}, + {0x8cda, 6768}, + {0x8cdb, 2189}, + {0x8cdc, 2240}, + {0x8cde, 2502}, + {0x8ce0, 3355}, + {0x8ce2, 1889}, + {0x8ce3, 6767}, + {0x8ce4, 6766}, + {0x8ce6, 3548}, + {0x8cea, 2285}, + {0x8ced, 3148}, + {0x8cf0, 8626}, + {0x8cf4, 8627}, + {0x8cfa, 6770}, + {0x8cfb, 6771}, + {0x8cfc, 2026}, + {0x8cfd, 6769}, + {0x8d04, 6772}, + {0x8d05, 6773}, + {0x8d07, 6775}, + {0x8d08, 2819}, + {0x8d0a, 6774}, + {0x8d0b, 1570}, + {0x8d0d, 6777}, + {0x8d0f, 6776}, + {0x8d10, 6778}, + {0x8d12, 8628}, + {0x8d13, 6780}, + {0x8d14, 6782}, + {0x8d16, 6783}, + {0x8d64, 2682}, + {0x8d66, 2299}, + {0x8d67, 6784}, + {0x8d6b, 1456}, + {0x8d6d, 6785}, + {0x8d70, 2808}, + {0x8d71, 6786}, + {0x8d73, 6787}, + {0x8d74, 3549}, + {0x8d76, 8629}, + {0x8d77, 1609}, + {0x8d81, 6788}, + {0x8d85, 3026}, + {0x8d8a, 1277}, + {0x8d99, 6789}, + {0x8da3, 2333}, + {0x8da8, 2620}, + {0x8db3, 2829}, + {0x8dba, 6792}, + {0x8dbe, 6791}, + {0x8dc2, 6790}, + {0x8dcb, 6798}, + {0x8dcc, 6796}, + {0x8dcf, 6793}, + {0x8dd6, 6795}, + {0x8dda, 6794}, + {0x8ddb, 6797}, + {0x8ddd, 1681}, + {0x8ddf, 6801}, + {0x8de1, 2683}, + {0x8de3, 6802}, + {0x8de8, 1933}, + {0x8dea, 6799}, + {0x8deb, 6800}, + {0x8def, 4047}, + {0x8df3, 3027}, + {0x8df5, 2731}, + {0x8dfc, 6803}, + {0x8dff, 6806}, + {0x8e08, 6804}, + {0x8e09, 6805}, + {0x8e0a, 3907}, + {0x8e0f, 3199}, + {0x8e10, 6809}, + {0x8e1d, 6807}, + {0x8e1e, 6808}, + {0x8e1f, 6810}, + {0x8e2a, 6824}, + {0x8e30, 6813}, + {0x8e34, 6814}, + {0x8e35, 6812}, + {0x8e42, 6811}, + {0x8e44, 3097}, + {0x8e47, 6816}, + {0x8e48, 6820}, + {0x8e49, 6817}, + {0x8e4a, 6815}, + {0x8e4c, 6818}, + {0x8e50, 6819}, + {0x8e55, 6826}, + {0x8e59, 6821}, + {0x8e5f, 2684}, + {0x8e60, 6823}, + {0x8e63, 6825}, + {0x8e64, 6822}, + {0x8e72, 6828}, + {0x8e74, 2365}, + {0x8e76, 6827}, + {0x8e7c, 6829}, + {0x8e81, 6830}, + {0x8e84, 6833}, + {0x8e85, 6832}, + {0x8e87, 6831}, + {0x8e8a, 6835}, + {0x8e8b, 6834}, + {0x8e8d, 3842}, + {0x8e91, 6837}, + {0x8e93, 6836}, + {0x8e94, 6838}, + {0x8e99, 6839}, + {0x8ea1, 6841}, + {0x8eaa, 6840}, + {0x8eab, 2574}, + {0x8eac, 6842}, + {0x8eaf, 1765}, + {0x8eb0, 6843}, + {0x8eb1, 6845}, + {0x8ebe, 6846}, + {0x8ec0, 7663}, + {0x8ec5, 6847}, + {0x8ec6, 6844}, + {0x8ec8, 6848}, + {0x8eca, 2306}, + {0x8ecb, 6849}, + {0x8ecc, 1610}, + {0x8ecd, 1801}, + {0x8ecf, 8631}, + {0x8ed2, 1890}, + {0x8edb, 6850}, + {0x8edf, 3272}, + {0x8ee2, 3128}, + {0x8ee3, 6851}, + {0x8eeb, 6854}, + {0x8ef8, 2272}, + {0x8efb, 6853}, + {0x8efc, 6852}, + {0x8efd, 1840}, + {0x8efe, 6855}, + {0x8f03, 1457}, + {0x8f05, 6857}, + {0x8f09, 2124}, + {0x8f0a, 6856}, + {0x8f0c, 6865}, + {0x8f12, 6859}, + {0x8f13, 6861}, + {0x8f14, 3637}, + {0x8f15, 6858}, + {0x8f19, 6860}, + {0x8f1b, 6864}, + {0x8f1c, 6862}, + {0x8f1d, 1611}, + {0x8f1f, 6863}, + {0x8f26, 6866}, + {0x8f29, 3344}, + {0x8f2a, 4000}, + {0x8f2f, 2366}, + {0x8f33, 6867}, + {0x8f38, 3852}, + {0x8f39, 6869}, + {0x8f3b, 6868}, + {0x8f3e, 6872}, + {0x8f3f, 3883}, + {0x8f42, 6871}, + {0x8f44, 1483}, + {0x8f45, 6870}, + {0x8f46, 6875}, + {0x8f49, 6874}, + {0x8f4c, 6873}, + {0x8f4d, 3116}, + {0x8f4e, 6876}, + {0x8f57, 6877}, + {0x8f5c, 6878}, + {0x8f5f, 2046}, + {0x8f61, 1787}, + {0x8f62, 6879}, + {0x8f63, 6880}, + {0x8f64, 6881}, + {0x8f9b, 2575}, + {0x8f9c, 6882}, + {0x8f9e, 2265}, + {0x8f9f, 6883}, + {0x8fa3, 6884}, + {0x8fa7, 4278}, + {0x8fa8, 4277}, + {0x8fad, 6885}, + {0x8fae, 6143}, + {0x8faf, 6886}, + {0x8fb0, 2914}, + {0x8fb1, 2545}, + {0x8fb2, 3318}, + {0x8fb6, 0}, + {0x8fb7, 6887}, + {0x8fba, 3621}, + {0x8fbb, 3056}, + {0x8fbc, 2064}, + {0x8fbf, 2919}, + {0x8fc2, 1228}, + {0x8fc4, 3750}, + {0x8fc5, 2589}, + {0x8fce, 1844}, + {0x8fd1, 1753}, + {0x8fd4, 3622}, + {0x8fda, 6888}, + {0x8fe2, 6890}, + {0x8fe5, 6889}, + {0x8fe6, 1376}, + {0x8fe9, 3278}, + {0x8fea, 6891}, + {0x8feb, 3373}, + {0x8fed, 3117}, + {0x8fef, 6892}, + {0x8ff0, 2396}, + {0x8ff4, 6894}, + {0x8ff7, 3790}, + {0x8ff8, 6909}, + {0x8ff9, 6896}, + {0x8ffa, 6897}, + {0x8ffd, 3045}, + {0x9000, 2880}, + {0x9001, 2809}, + {0x9003, 3200}, + {0x9005, 6895}, + {0x9006, 1647}, + {0x900b, 6904}, + {0x900d, 6901}, + {0x900e, 6914}, + {0x900f, 3201}, + {0x9010, 2974}, + {0x9011, 6898}, + {0x9013, 3098}, + {0x9014, 3149}, + {0x9015, 6899}, + {0x9016, 6903}, + {0x9017, 2598}, + {0x9019, 3357}, + {0x901a, 3048}, + {0x901d, 2662}, + {0x901e, 6902}, + {0x901f, 2830}, + {0x9020, 2820}, + {0x9021, 6900}, + {0x9022, 1133}, + {0x9023, 4040}, + {0x9027, 6905}, + {0x902e, 2881}, + {0x9031, 2367}, + {0x9032, 2576}, + {0x9035, 6907}, + {0x9036, 6906}, + {0x9038, 1203}, + {0x9039, 6908}, + {0x903c, 3489}, + {0x903e, 6916}, + {0x9041, 3251}, + {0x9042, 2609}, + {0x9045, 2967}, + {0x9047, 1776}, + {0x9049, 6915}, + {0x904a, 3873}, + {0x904b, 1249}, + {0x904d, 3623}, + {0x904e, 1377}, + {0x904f, 6910}, + {0x9050, 6911}, + {0x9051, 6912}, + {0x9052, 6913}, + {0x9053, 3219}, + {0x9054, 2913}, + {0x9055, 1191}, + {0x9056, 6917}, + {0x9058, 6918}, + {0x9059, 7476}, + {0x905c, 2845}, + {0x905e, 6919}, + {0x9060, 1301}, + {0x9061, 2766}, + {0x9063, 1891}, + {0x9065, 3908}, + {0x9067, 8634}, + {0x9068, 6920}, + {0x9069, 3110}, + {0x906d, 2810}, + {0x906e, 2307}, + {0x906f, 6921}, + {0x9072, 6924}, + {0x9075, 2415}, + {0x9076, 6922}, + {0x9077, 2733}, + {0x9078, 2732}, + {0x907a, 1192}, + {0x907c, 3987}, + {0x907d, 6926}, + {0x907f, 3462}, + {0x9080, 6928}, + {0x9081, 6927}, + {0x9082, 6925}, + {0x9083, 5943}, + {0x9084, 1552}, + {0x9087, 6893}, + {0x9089, 6930}, + {0x908a, 6929}, + {0x908f, 6931}, + {0x9091, 3874}, + {0x90a3, 3257}, + {0x90a6, 3676}, + {0x90a8, 6932}, + {0x90aa, 2309}, + {0x90af, 6933}, + {0x90b1, 6934}, + {0x90b5, 6935}, + {0x90b8, 3099}, + {0x90c1, 1198}, + {0x90ca, 2027}, + {0x90ce, 4064}, + {0x90db, 6939}, + {0x90de, 8635}, + {0x90e1, 1802}, + {0x90e2, 6936}, + {0x90e4, 6937}, + {0x90e8, 3558}, + {0x90ed, 1458}, + {0x90f5, 3875}, + {0x90f7, 1719}, + {0x90fd, 3150}, + {0x9102, 6940}, + {0x9112, 6941}, + {0x9115, 8637}, + {0x9119, 6942}, + {0x9127, 8638}, + {0x912d, 3100}, + {0x9130, 6944}, + {0x9132, 6943}, + {0x9149, 3243}, + {0x914a, 6945}, + {0x914b, 2368}, + {0x914c, 2316}, + {0x914d, 3345}, + {0x914e, 2991}, + {0x9152, 2334}, + {0x9154, 2610}, + {0x9156, 6946}, + {0x9158, 6947}, + {0x9162, 2595}, + {0x9163, 6948}, + {0x9165, 6949}, + {0x9169, 6950}, + {0x916a, 3929}, + {0x916c, 2369}, + {0x9172, 6952}, + {0x9173, 6951}, + {0x9175, 2028}, + {0x9177, 2053}, + {0x9178, 2190}, + {0x9182, 6955}, + {0x9187, 2416}, + {0x9189, 6954}, + {0x918b, 6953}, + {0x918d, 2889}, + {0x9190, 1955}, + {0x9192, 2663}, + {0x9197, 3396}, + {0x919c, 2371}, + {0x91a2, 6956}, + {0x91a4, 2503}, + {0x91aa, 6959}, + {0x91ab, 6957}, + {0x91ac, 7707}, + {0x91ae, 0}, + {0x91af, 6958}, + {0x91b1, 7777}, + {0x91b4, 6961}, + {0x91b5, 6960}, + {0x91b8, 2530}, + {0x91ba, 6962}, + {0x91c0, 6963}, + {0x91c1, 6964}, + {0x91c6, 3428}, + {0x91c7, 2115}, + {0x91c8, 2317}, + {0x91c9, 6965}, + {0x91cb, 6966}, + {0x91cc, 3948}, + {0x91cd, 2383}, + {0x91ce, 3834}, + {0x91cf, 3988}, + {0x91d0, 6967}, + {0x91d1, 1754}, + {0x91d6, 6968}, + {0x91d7, 8640}, + {0x91d8, 3101}, + {0x91da, 8639}, + {0x91db, 6971}, + {0x91dc, 1494}, + {0x91dd, 2577}, + {0x91de, 8641}, + {0x91df, 6969}, + {0x91e1, 6970}, + {0x91e3, 3068}, + {0x91e4, 8644}, + {0x91e5, 8645}, + {0x91e6, 3715}, + {0x91e7, 1780}, + {0x91ed, 8642}, + {0x91ee, 8643}, + {0x91f5, 6973}, + {0x91f6, 6974}, + {0x91fc, 6972}, + {0x91ff, 6976}, + {0x9206, 8646}, + {0x920a, 8648}, + {0x920d, 3255}, + {0x920e, 1441}, + {0x9210, 8647}, + {0x9211, 6980}, + {0x9214, 6977}, + {0x9215, 6979}, + {0x921e, 6975}, + {0x9229, 7050}, + {0x922c, 6978}, + {0x9234, 4019}, + {0x9237, 1934}, + {0x9239, 8655}, + {0x923a, 8649}, + {0x923c, 8651}, + {0x923f, 6988}, + {0x9240, 8650}, + {0x9244, 3118}, + {0x9245, 6983}, + {0x9248, 6986}, + {0x9249, 6984}, + {0x924b, 6989}, + {0x924e, 8652}, + {0x9250, 6990}, + {0x9251, 8654}, + {0x9257, 6982}, + {0x9259, 8653}, + {0x925a, 6995}, + {0x925b, 1302}, + {0x925e, 6981}, + {0x9262, 3393}, + {0x9264, 6985}, + {0x9266, 2504}, + {0x9267, 8656}, + {0x9271, 2029}, + {0x9277, 8658}, + {0x9278, 8659}, + {0x927e, 3702}, + {0x9280, 1756}, + {0x9283, 2384}, + {0x9285, 3220}, + {0x9288, 8362}, + {0x9291, 2735}, + {0x9293, 6993}, + {0x9295, 6987}, + {0x9296, 6992}, + {0x9298, 3791}, + {0x929a, 3028}, + {0x929b, 6994}, + {0x929c, 6991}, + {0x92a7, 8657}, + {0x92ad, 2734}, + {0x92b7, 6998}, + {0x92b9, 6997}, + {0x92cc, 0}, + {0x92cf, 6996}, + {0x92d0, 8663}, + {0x92d2, 3677}, + {0x92d3, 8667}, + {0x92d5, 8665}, + {0x92d7, 8661}, + {0x92d9, 8662}, + {0x92e0, 8666}, + {0x92e4, 2437}, + {0x92e7, 8660}, + {0x92e9, 6999}, + {0x92ea, 3631}, + {0x92ed, 1270}, + {0x92f2, 3512}, + {0x92f3, 2992}, + {0x92f8, 1682}, + {0x92f9, 8368}, + {0x92fa, 7001}, + {0x92fb, 8670}, + {0x92fc, 2031}, + {0x92ff, 8673}, + {0x9302, 8675}, + {0x9306, 2170}, + {0x930f, 7000}, + {0x9310, 2611}, + {0x9318, 2612}, + {0x9319, 7004}, + {0x931a, 7006}, + {0x931d, 8674}, + {0x931e, 8672}, + {0x9320, 2531}, + {0x9321, 8669}, + {0x9322, 7005}, + {0x9323, 7007}, + {0x9325, 8668}, + {0x9326, 1739}, + {0x9328, 3511}, + {0x932b, 2318}, + {0x932c, 4041}, + {0x932e, 7003}, + {0x932f, 2152}, + {0x9332, 4069}, + {0x9335, 7009}, + {0x933a, 7008}, + {0x933b, 7010}, + {0x9344, 7002}, + {0x9348, 8361}, + {0x934b, 3265}, + {0x934d, 3151}, + {0x9354, 3059}, + {0x9356, 7015}, + {0x9357, 8677}, + {0x935b, 2945}, + {0x935c, 7011}, + {0x9360, 7012}, + {0x936c, 1795}, + {0x936e, 7014}, + {0x9370, 8676}, + {0x9375, 1892}, + {0x937c, 7013}, + {0x937e, 2505}, + {0x938c, 1495}, + {0x9394, 7019}, + {0x9396, 2095}, + {0x9397, 2811}, + {0x939a, 3046}, + {0x93a4, 8678}, + {0x93a7, 1433}, + {0x93ac, 7017}, + {0x93ad, 7018}, + {0x93ae, 3039}, + {0x93b0, 7016}, + {0x93b9, 7020}, + {0x93c3, 7026}, + {0x93c6, 8679}, + {0x93c8, 7029}, + {0x93d0, 7028}, + {0x93d1, 3111}, + {0x93d6, 7021}, + {0x93d7, 7022}, + {0x93d8, 7025}, + {0x93dd, 7027}, + {0x93de, 8680}, + {0x93e1, 1720}, + {0x93e4, 7030}, + {0x93e5, 7024}, + {0x93e8, 7023}, + {0x93f8, 8681}, + {0x9403, 7034}, + {0x9407, 7035}, + {0x9410, 7036}, + {0x9413, 7033}, + {0x9414, 7032}, + {0x9418, 2506}, + {0x9419, 3202}, + {0x941a, 7031}, + {0x9421, 7040}, + {0x942b, 7038}, + {0x9431, 8682}, + {0x9435, 7039}, + {0x9436, 7037}, + {0x9438, 2904}, + {0x943a, 7041}, + {0x9441, 7042}, + {0x9444, 7044}, + {0x9445, 8683}, + {0x9448, 8684}, + {0x9451, 1553}, + {0x9452, 7043}, + {0x9453, 3846}, + {0x945a, 7055}, + {0x945b, 7045}, + {0x945e, 7048}, + {0x9460, 7046}, + {0x9462, 7047}, + {0x946a, 7049}, + {0x9470, 7051}, + {0x9475, 7052}, + {0x9477, 7053}, + {0x947c, 7056}, + {0x947d, 7054}, + {0x947e, 7057}, + {0x947f, 7059}, + {0x9481, 7058}, + {0x9577, 3029}, + {0x9580, 3827}, + {0x9582, 7060}, + {0x9583, 2736}, + {0x9587, 7061}, + {0x9589, 3604}, + {0x958a, 7062}, + {0x958b, 1417}, + {0x958f, 1246}, + {0x9591, 1555}, + {0x9592, 8685}, + {0x9593, 1554}, + {0x9594, 7063}, + {0x9596, 7064}, + {0x9598, 7065}, + {0x9599, 7066}, + {0x95a0, 7067}, + {0x95a2, 1556}, + {0x95a3, 1459}, + {0x95a4, 2032}, + {0x95a5, 3402}, + {0x95a7, 7069}, + {0x95a8, 7068}, + {0x95ad, 7070}, + {0x95b2, 1278}, + {0x95b9, 7073}, + {0x95bb, 7072}, + {0x95bc, 7071}, + {0x95be, 7074}, + {0x95c3, 7077}, + {0x95c7, 1163}, + {0x95ca, 7075}, + {0x95cc, 7079}, + {0x95cd, 7078}, + {0x95d4, 7081}, + {0x95d5, 7080}, + {0x95d6, 7082}, + {0x95d8, 3206}, + {0x95dc, 7083}, + {0x95e1, 7084}, + {0x95e2, 7086}, + {0x95e5, 7085}, + {0x961c, 3550}, + {0x9621, 7087}, + {0x9628, 7088}, + {0x962a, 2133}, + {0x962e, 7089}, + {0x962f, 7090}, + {0x9632, 3703}, + {0x963b, 2765}, + {0x963f, 1128}, + {0x9640, 2859}, + {0x9642, 7091}, + {0x9644, 3551}, + {0x964b, 7094}, + {0x964c, 7092}, + {0x964d, 2033}, + {0x964f, 7093}, + {0x9650, 1910}, + {0x965b, 3605}, + {0x965c, 7096}, + {0x965d, 7098}, + {0x965e, 7097}, + {0x965f, 7099}, + {0x9662, 1219}, + {0x9663, 2590}, + {0x9664, 2438}, + {0x9665, 1557}, + {0x9666, 7100}, + {0x966a, 3356}, + {0x966c, 7102}, + {0x9670, 1220}, + {0x9672, 7101}, + {0x9673, 3040}, + {0x9675, 3989}, + {0x9676, 3203}, + {0x9677, 7095}, + {0x9678, 3950}, + {0x967a, 1893}, + {0x967d, 3909}, + {0x9685, 1777}, + {0x9686, 3964}, + {0x9688, 1790}, + {0x968a, 2882}, + {0x968b, 6252}, + {0x968d, 7103}, + {0x968e, 1418}, + {0x968f, 2613}, + {0x9694, 1460}, + {0x9695, 7105}, + {0x9697, 7106}, + {0x9698, 7104}, + {0x9699, 1850}, + {0x969b, 2125}, + {0x969c, 2507}, + {0x969d, 8688}, + {0x96a0, 1221}, + {0x96a3, 4001}, + {0x96a7, 7108}, + {0x96a8, 6923}, + {0x96aa, 7107}, + {0x96af, 8689}, + {0x96b0, 7111}, + {0x96b1, 7109}, + {0x96b2, 7110}, + {0x96b4, 7112}, + {0x96b6, 7113}, + {0x96b7, 4020}, + {0x96b8, 7114}, + {0x96b9, 7115}, + {0x96bb, 2669}, + {0x96bc, 3407}, + {0x96c0, 2627}, + {0x96c1, 1571}, + {0x96c4, 3876}, + {0x96c5, 1389}, + {0x96c6, 2370}, + {0x96c7, 1935}, + {0x96c9, 7118}, + {0x96cb, 7117}, + {0x96cc, 2241}, + {0x96cd, 7119}, + {0x96ce, 7116}, + {0x96d1, 2166}, + {0x96d5, 7123}, + {0x96d6, 6546}, + {0x96d9, 4331}, + {0x96db, 2621}, + {0x96dc, 7121}, + {0x96e2, 3949}, + {0x96e3, 3273}, + {0x96e8, 1229}, + {0x96ea, 2695}, + {0x96eb, 2274}, + {0x96f0, 3591}, + {0x96f2, 1250}, + {0x96f6, 4021}, + {0x96f7, 3925}, + {0x96f9, 7124}, + {0x96fb, 3135}, + {0x9700, 2343}, + {0x9704, 7125}, + {0x9706, 7126}, + {0x9707, 2578}, + {0x9708, 7127}, + {0x970a, 4022}, + {0x970d, 7122}, + {0x970e, 7129}, + {0x970f, 7131}, + {0x9711, 7130}, + {0x9713, 7128}, + {0x9716, 7132}, + {0x9719, 7133}, + {0x971c, 2812}, + {0x971e, 1378}, + {0x9724, 7134}, + {0x9727, 3780}, + {0x972a, 7135}, + {0x9730, 7136}, + {0x9732, 4048}, + {0x9733, 8690}, + {0x9738, 5140}, + {0x9739, 7137}, + {0x973b, 8691}, + {0x973d, 7138}, + {0x973e, 7139}, + {0x9742, 7143}, + {0x9743, 8692}, + {0x9744, 7140}, + {0x9746, 7141}, + {0x9748, 7142}, + {0x9749, 7144}, + {0x974d, 8693}, + {0x974f, 8694}, + {0x9751, 8695}, + {0x9752, 2664}, + {0x9755, 8696}, + {0x9756, 3843}, + {0x9759, 2665}, + {0x975c, 7145}, + {0x975e, 3463}, + {0x9760, 7146}, + {0x9761, 7430}, + {0x9762, 3800}, + {0x9764, 7147}, + {0x9766, 7148}, + {0x9768, 7149}, + {0x9769, 1461}, + {0x976b, 7151}, + {0x976d, 2591}, + {0x9771, 7152}, + {0x9774, 1786}, + {0x9779, 7153}, + {0x977a, 7157}, + {0x977c, 7155}, + {0x9781, 7156}, + {0x9784, 1489}, + {0x9785, 7154}, + {0x9786, 7158}, + {0x978b, 7159}, + {0x978d, 1164}, + {0x978f, 7160}, + {0x9790, 7161}, + {0x9798, 2508}, + {0x979c, 7162}, + {0x97a0, 1633}, + {0x97a3, 7165}, + {0x97a6, 7164}, + {0x97a8, 7163}, + {0x97ab, 6708}, + {0x97ad, 3628}, + {0x97b3, 7166}, + {0x97b4, 7167}, + {0x97b6, 0}, + {0x97c3, 7168}, + {0x97c6, 7169}, + {0x97c8, 7170}, + {0x97cb, 7171}, + {0x97d3, 1558}, + {0x97dc, 7172}, + {0x97ed, 7173}, + {0x97ee, 3289}, + {0x97f2, 7175}, + {0x97f3, 1339}, + {0x97f5, 7178}, + {0x97f6, 7177}, + {0x97fb, 1222}, + {0x97ff, 1721}, + {0x9801, 3607}, + {0x9802, 3030}, + {0x9803, 2066}, + {0x9805, 2034}, + {0x9806, 2417}, + {0x9808, 2594}, + {0x980c, 7180}, + {0x980f, 7179}, + {0x9810, 3884}, + {0x9811, 1572}, + {0x9812, 3430}, + {0x9813, 3252}, + {0x9817, 2626}, + {0x9818, 3990}, + {0x981a, 1841}, + {0x9821, 7183}, + {0x9824, 7182}, + {0x982c, 3705}, + {0x982d, 3204}, + {0x9830, 7795}, + {0x9834, 1266}, + {0x9837, 7184}, + {0x9838, 7181}, + {0x983b, 3523}, + {0x983c, 3924}, + {0x983d, 7185}, + {0x9846, 7186}, + {0x984b, 7188}, + {0x984c, 2890}, + {0x984d, 1465}, + {0x984e, 1466}, + {0x984f, 7187}, + {0x9853, 0}, + {0x9854, 1573}, + {0x9855, 1894}, + {0x9857, 8697}, + {0x9858, 1574}, + {0x985a, 7752}, + {0x985b, 3129}, + {0x985e, 4008}, + {0x9865, 8698}, + {0x9867, 1936}, + {0x986b, 7189}, + {0x986f, 7190}, + {0x9870, 7191}, + {0x9871, 7192}, + {0x9873, 7194}, + {0x9874, 7193}, + {0x98a8, 3561}, + {0x98aa, 7195}, + {0x98af, 7196}, + {0x98b1, 7197}, + {0x98b6, 7198}, + {0x98c3, 7200}, + {0x98c4, 7199}, + {0x98c6, 7201}, + {0x98db, 3464}, + {0x98dc, 6201}, + {0x98df, 2543}, + {0x98e2, 1612}, + {0x98e9, 7202}, + {0x98eb, 7203}, + {0x98ed, 4289}, + {0x98ee, 5338}, + {0x98ef, 3431}, + {0x98f2, 1215}, + {0x98f4, 1151}, + {0x98fc, 2242}, + {0x98fd, 3678}, + {0x98fe, 2534}, + {0x9903, 7204}, + {0x9905, 3819}, + {0x9909, 7205}, + {0x990a, 3910}, + {0x990c, 1252}, + {0x9910, 2191}, + {0x9912, 7206}, + {0x9913, 1390}, + {0x9914, 7207}, + {0x9918, 7208}, + {0x991d, 7210}, + {0x991e, 7211}, + {0x9920, 7213}, + {0x9921, 7209}, + {0x9924, 7212}, + {0x9927, 8701}, + {0x9928, 1559}, + {0x992c, 7214}, + {0x992e, 7215}, + {0x9933, 0}, + {0x993d, 7216}, + {0x993e, 7217}, + {0x9942, 7218}, + {0x9945, 7220}, + {0x9949, 7219}, + {0x994b, 7222}, + {0x994c, 7225}, + {0x9950, 7221}, + {0x9951, 7223}, + {0x9952, 7224}, + {0x9955, 7226}, + {0x9957, 1722}, + {0x9996, 2335}, + {0x9997, 7227}, + {0x9998, 7228}, + {0x9999, 2035}, + {0x999e, 8703}, + {0x99a5, 7229}, + {0x99a8, 1436}, + {0x99ac, 3333}, + {0x99ad, 7230}, + {0x99ae, 7231}, + {0x99b3, 2968}, + {0x99b4, 3267}, + {0x99ba, 0}, + {0x99bc, 7232}, + {0x99c1, 3379}, + {0x99c4, 2860}, + {0x99c5, 1274}, + {0x99c6, 1766}, + {0x99c8, 1767}, + {0x99d0, 2993}, + {0x99d1, 7237}, + {0x99d2, 1768}, + {0x99d5, 1391}, + {0x99d8, 7236}, + {0x99db, 7234}, + {0x99dd, 7235}, + {0x99df, 7233}, + {0x99e2, 7247}, + {0x99ed, 7238}, + {0x99ee, 7239}, + {0x99f1, 7240}, + {0x99f2, 7241}, + {0x99f8, 7243}, + {0x99fb, 7242}, + {0x99ff, 2403}, + {0x9a01, 7244}, + {0x9a05, 7246}, + {0x9a0e, 1613}, + {0x9a0f, 7245}, + {0x9a12, 2813}, + {0x9a13, 1895}, + {0x9a19, 7248}, + {0x9a28, 2861}, + {0x9a2b, 7249}, + {0x9a2e, 0}, + {0x9a30, 3205}, + {0x9a37, 7250}, + {0x9a3e, 7255}, + {0x9a40, 7253}, + {0x9a42, 7252}, + {0x9a43, 7254}, + {0x9a45, 7251}, + {0x9a4d, 7257}, + {0x9a4e, 8704}, + {0x9a52, 7727}, + {0x9a55, 7256}, + {0x9a57, 7259}, + {0x9a5a, 1723}, + {0x9a5b, 7258}, + {0x9a5f, 7260}, + {0x9a62, 7261}, + {0x9a64, 7263}, + {0x9a65, 7262}, + {0x9a69, 7264}, + {0x9a6a, 7266}, + {0x9a6b, 7265}, + {0x9aa8, 2062}, + {0x9aad, 7267}, + {0x9ab0, 7268}, + {0x9ab6, 0}, + {0x9ab8, 1434}, + {0x9abc, 7269}, + {0x9ac0, 7270}, + {0x9ac4, 2615}, + {0x9acf, 7271}, + {0x9ad1, 7272}, + {0x9ad3, 7273}, + {0x9ad4, 7274}, + {0x9ad8, 2036}, + {0x9ad9, 8705}, + {0x9adc, 8706}, + {0x9ade, 7275}, + {0x9adf, 7276}, + {0x9ae2, 7277}, + {0x9ae3, 7278}, + {0x9ae6, 7279}, + {0x9aea, 3397}, + {0x9aeb, 7281}, + {0x9aed, 3480}, + {0x9aee, 7282}, + {0x9aef, 7280}, + {0x9af1, 7284}, + {0x9af4, 7283}, + {0x9af7, 7285}, + {0x9afb, 7286}, + {0x9b06, 7287}, + {0x9b18, 7288}, + {0x9b1a, 7289}, + {0x9b1f, 7290}, + {0x9b22, 7291}, + {0x9b23, 7292}, + {0x9b25, 7293}, + {0x9b27, 7294}, + {0x9b28, 7295}, + {0x9b29, 7296}, + {0x9b2a, 7297}, + {0x9b2e, 7298}, + {0x9b2f, 7299}, + {0x9b31, 5332}, + {0x9b32, 7300}, + {0x9b34, 0}, + {0x9b3b, 6057}, + {0x9b3c, 1614}, + {0x9b41, 1407}, + {0x9b42, 2082}, + {0x9b43, 7302}, + {0x9b44, 7301}, + {0x9b45, 3761}, + {0x9b4d, 7304}, + {0x9b4e, 7305}, + {0x9b4f, 7303}, + {0x9b51, 7306}, + {0x9b54, 3728}, + {0x9b58, 7307}, + {0x9b5a, 1685}, + {0x9b6f, 4043}, + {0x9b72, 8708}, + {0x9b74, 7308}, + {0x9b75, 8707}, + {0x9b83, 7310}, + {0x9b8e, 1154}, + {0x9b8f, 8709}, + {0x9b91, 7311}, + {0x9b92, 3579}, + {0x9b93, 7309}, + {0x9b96, 7312}, + {0x9b97, 7313}, + {0x9b9f, 7314}, + {0x9ba0, 7315}, + {0x9ba8, 7316}, + {0x9baa, 3740}, + {0x9bab, 2171}, + {0x9bad, 2154}, + {0x9bae, 2737}, + {0x9bb1, 8710}, + {0x9bb4, 7317}, + {0x9bb9, 7320}, + {0x9bbb, 8711}, + {0x9bc0, 7318}, + {0x9bc6, 7321}, + {0x9bc9, 1957}, + {0x9bca, 7319}, + {0x9bcf, 7322}, + {0x9bd1, 7323}, + {0x9bd2, 7324}, + {0x9bd4, 7328}, + {0x9bd6, 2168}, + {0x9bdb, 2884}, + {0x9be1, 7329}, + {0x9be2, 7326}, + {0x9be3, 7325}, + {0x9be4, 7327}, + {0x9be8, 1845}, + {0x9bf0, 7333}, + {0x9bf1, 7332}, + {0x9bf2, 7331}, + {0x9bf5, 1143}, + {0x9c00, 8712}, + {0x9c04, 7343}, + {0x9c06, 7339}, + {0x9c08, 7340}, + {0x9c09, 7336}, + {0x9c0a, 7342}, + {0x9c0c, 7338}, + {0x9c0d, 1472}, + {0x9c10, 4082}, + {0x9c12, 7341}, + {0x9c13, 7337}, + {0x9c14, 7335}, + {0x9c15, 7334}, + {0x9c1b, 7345}, + {0x9c21, 7348}, + {0x9c24, 7347}, + {0x9c25, 7346}, + {0x9c2d, 3515}, + {0x9c2e, 7344}, + {0x9c2f, 1207}, + {0x9c30, 7349}, + {0x9c32, 7351}, + {0x9c39, 1485}, + {0x9c3a, 7330}, + {0x9c3b, 1241}, + {0x9c3e, 7353}, + {0x9c46, 7352}, + {0x9c47, 7350}, + {0x9c48, 2923}, + {0x9c52, 3742}, + {0x9c57, 4002}, + {0x9c5a, 7354}, + {0x9c60, 7355}, + {0x9c67, 7356}, + {0x9c76, 7357}, + {0x9c78, 7358}, + {0x9ce5, 3031}, + {0x9ce7, 7359}, + {0x9ce9, 3403}, + {0x9ceb, 7364}, + {0x9cec, 7360}, + {0x9cf0, 7361}, + {0x9cf3, 3679}, + {0x9cf4, 3792}, + {0x9cf6, 3240}, + {0x9d03, 7365}, + {0x9d06, 7366}, + {0x9d07, 3222}, + {0x9d08, 7363}, + {0x9d09, 7362}, + {0x9d0e, 1322}, + {0x9d12, 7374}, + {0x9d15, 7373}, + {0x9d1b, 1303}, + {0x9d1f, 7371}, + {0x9d23, 7370}, + {0x9d26, 7368}, + {0x9d28, 1497}, + {0x9d2a, 7367}, + {0x9d2b, 2270}, + {0x9d2c, 1321}, + {0x9d3b, 2037}, + {0x9d3e, 7377}, + {0x9d3f, 7376}, + {0x9d41, 7375}, + {0x9d44, 7372}, + {0x9d46, 7378}, + {0x9d48, 7379}, + {0x9d50, 7384}, + {0x9d51, 7383}, + {0x9d59, 7385}, + {0x9d5c, 1231}, + {0x9d5d, 7380}, + {0x9d5e, 7381}, + {0x9d60, 2054}, + {0x9d61, 3781}, + {0x9d64, 7382}, + {0x9d6b, 8714}, + {0x9d6c, 3680}, + {0x9d6f, 7390}, + {0x9d70, 8713}, + {0x9d72, 7386}, + {0x9d7a, 7391}, + {0x9d87, 7388}, + {0x9d89, 7387}, + {0x9d8f, 1842}, + {0x9d9a, 7392}, + {0x9da4, 7393}, + {0x9da9, 7394}, + {0x9dab, 7389}, + {0x9daf, 7369}, + {0x9db2, 7395}, + {0x9db4, 3069}, + {0x9db8, 7399}, + {0x9dba, 7400}, + {0x9dbb, 7398}, + {0x9dc1, 7397}, + {0x9dc2, 7403}, + {0x9dc4, 7396}, + {0x9dc6, 7401}, + {0x9dcf, 7402}, + {0x9dd3, 7405}, + {0x9dd7, 7646}, + {0x9dd9, 7404}, + {0x9de6, 7407}, + {0x9ded, 7408}, + {0x9def, 7409}, + {0x9df2, 4079}, + {0x9df8, 7406}, + {0x9df9, 2891}, + {0x9dfa, 2141}, + {0x9dfd, 7410}, + {0x9e19, 8716}, + {0x9e1a, 7411}, + {0x9e1b, 7412}, + {0x9e1e, 7413}, + {0x9e75, 7414}, + {0x9e78, 1896}, + {0x9e79, 7415}, + {0x9e7c, 7677}, + {0x9e7d, 7416}, + {0x9e7f, 2267}, + {0x9e81, 7417}, + {0x9e88, 7418}, + {0x9e8b, 7419}, + {0x9e8c, 7420}, + {0x9e91, 7423}, + {0x9e92, 7421}, + {0x9e93, 4066}, + {0x9e95, 7422}, + {0x9e97, 4023}, + {0x9e9d, 7424}, + {0x9e9f, 4003}, + {0x9ea5, 7425}, + {0x9ea6, 3380}, + {0x9ea9, 7426}, + {0x9eaa, 7428}, + {0x9ead, 7429}, + {0x9eb4, 7682}, + {0x9eb5, 7797}, + {0x9eb8, 7427}, + {0x9eb9, 2047}, + {0x9eba, 3801}, + {0x9ebb, 3729}, + {0x9ebc, 4740}, + {0x9ebe, 5375}, + {0x9ebf, 3753}, + {0x9ec4, 1323}, + {0x9ecc, 7431}, + {0x9ecd, 1642}, + {0x9ece, 7432}, + {0x9ecf, 7433}, + {0x9ed0, 7434}, + {0x9ed1, 8717}, + {0x9ed2, 2055}, + {0x9ed4, 7435}, + {0x9ed8, 5645}, + {0x9ed9, 3815}, + {0x9edb, 2883}, + {0x9edc, 7436}, + {0x9edd, 7438}, + {0x9ede, 7437}, + {0x9ee0, 7439}, + {0x9ee5, 7440}, + {0x9ee8, 7441}, + {0x9eef, 7442}, + {0x9ef4, 7443}, + {0x9ef6, 7444}, + {0x9ef7, 7445}, + {0x9ef9, 7446}, + {0x9efb, 7447}, + {0x9efc, 7448}, + {0x9efd, 7449}, + {0x9f07, 7450}, + {0x9f08, 7451}, + {0x9f0e, 3102}, + {0x9f13, 1937}, + {0x9f15, 7453}, + {0x9f20, 2767}, + {0x9f21, 7454}, + {0x9f2c, 7455}, + {0x9f3b, 3475}, + {0x9f3e, 7456}, + {0x9f4a, 7457}, + {0x9f4b, 5898}, + {0x9f4e, 6779}, + {0x9f4f, 7174}, + {0x9f52, 7458}, + {0x9f54, 7459}, + {0x9f5f, 7461}, + {0x9f60, 7462}, + {0x9f61, 7463}, + {0x9f62, 4024}, + {0x9f63, 7460}, + {0x9f66, 7464}, + {0x9f67, 7465}, + {0x9f6a, 7467}, + {0x9f6c, 7466}, + {0x9f72, 7469}, + {0x9f76, 7470}, + {0x9f77, 7468}, + {0x9f8d, 3966}, + {0x9f95, 7471}, + {0x9f9c, 7472}, + {0x9f9d, 5927}, + {0x9fa0, 7473}, + {0xf929, 8489}, + {0xf9dc, 8686}, + {0xfa0e, 8410}, + {0xfa0f, 8421}, + {0xfa10, 8422}, + {0xfa11, 8443}, + {0xfa12, 8481}, + {0xfa13, 8497}, + {0xfa14, 8499}, + {0xfa15, 8542}, + {0xfa16, 8548}, + {0xfa17, 8571}, + {0xfa18, 8579}, + {0xfa19, 8580}, + {0xfa1a, 8581}, + {0xfa1b, 8583}, + {0xfa1c, 8587}, + {0xfa1d, 8590}, + {0xfa1e, 8599}, + {0xfa1f, 8610}, + {0xfa20, 8612}, + {0xfa21, 8613}, + {0xfa22, 8622}, + {0xfa23, 8630}, + {0xfa24, 8632}, + {0xfa25, 8633}, + {0xfa26, 8636}, + {0xfa27, 8664}, + {0xfa28, 8671}, + {0xfa29, 8687}, + {0xfa2a, 8699}, + {0xfa2b, 8700}, + {0xfa2c, 8702}, + {0xfa2d, 8715}, + {0xfb00, 9358}, + {0xfb01, 112}, + {0xfb02, 113}, + {0xfb03, 9359}, + {0xfb04, 9360}, + {0xfe30, 7898}, + {0xfe31, 7892}, + {0xfe32, 7893}, + {0xfe33, 7890}, + {0xfe35, 7899}, + {0xfe36, 7900}, + {0xfe37, 7905}, + {0xfe38, 7906}, + {0xfe39, 7901}, + {0xfe3a, 7902}, + {0xfe3b, 7915}, + {0xfe3c, 7916}, + {0xfe3d, 7909}, + {0xfe3e, 7910}, + {0xfe3f, 7907}, + {0xfe40, 7908}, + {0xfe41, 7911}, + {0xfe42, 7912}, + {0xfe43, 7913}, + {0xfe44, 7914}, + {0xff01, 642}, + {0xff02, 8007}, + {0xff03, 716}, + {0xff04, 712}, + {0xff05, 715}, + {0xff06, 717}, + {0xff07, 8006}, + {0xff08, 674}, + {0xff09, 675}, + {0xff0a, 718}, + {0xff0b, 692}, + {0xff0c, 636}, + {0xff0d, 693}, + {0xff0e, 637}, + {0xff0f, 663}, + {0xff10, 780}, + {0xff11, 781}, + {0xff12, 782}, + {0xff13, 783}, + {0xff14, 784}, + {0xff15, 785}, + {0xff16, 786}, + {0xff17, 787}, + {0xff18, 788}, + {0xff19, 789}, + {0xff1a, 639}, + {0xff1b, 640}, + {0xff1c, 699}, + {0xff1d, 697}, + {0xff1e, 700}, + {0xff1f, 641}, + {0xff20, 719}, + {0xff21, 790}, + {0xff22, 791}, + {0xff23, 792}, + {0xff24, 793}, + {0xff25, 794}, + {0xff26, 795}, + {0xff27, 796}, + {0xff28, 797}, + {0xff29, 798}, + {0xff2a, 799}, + {0xff2b, 800}, + {0xff2c, 801}, + {0xff2d, 802}, + {0xff2e, 803}, + {0xff2f, 804}, + {0xff30, 805}, + {0xff31, 806}, + {0xff32, 807}, + {0xff33, 808}, + {0xff34, 809}, + {0xff35, 810}, + {0xff36, 811}, + {0xff37, 812}, + {0xff38, 813}, + {0xff39, 814}, + {0xff3a, 815}, + {0xff3b, 678}, + {0xff3c, 664}, + {0xff3d, 679}, + {0xff3e, 648}, + {0xff3f, 650}, + {0xff40, 646}, + {0xff41, 816}, + {0xff42, 817}, + {0xff43, 818}, + {0xff44, 819}, + {0xff45, 820}, + {0xff46, 821}, + {0xff47, 822}, + {0xff48, 823}, + {0xff49, 824}, + {0xff4a, 825}, + {0xff4b, 826}, + {0xff4c, 827}, + {0xff4d, 828}, + {0xff4e, 829}, + {0xff4f, 830}, + {0xff50, 831}, + {0xff51, 832}, + {0xff52, 833}, + {0xff53, 834}, + {0xff54, 835}, + {0xff55, 836}, + {0xff56, 837}, + {0xff57, 838}, + {0xff58, 839}, + {0xff59, 840}, + {0xff5a, 841}, + {0xff5b, 680}, + {0xff5c, 667}, + {0xff5d, 681}, + {0xff5e, 665}, + {0xff61, 327}, + {0xff62, 328}, + {0xff63, 329}, + {0xff64, 330}, + {0xff65, 331}, + {0xff66, 332}, + {0xff67, 333}, + {0xff68, 334}, + {0xff69, 335}, + {0xff6a, 336}, + {0xff6b, 337}, + {0xff6c, 338}, + {0xff6d, 339}, + {0xff6e, 340}, + {0xff6f, 341}, + {0xff70, 342}, + {0xff71, 343}, + {0xff72, 344}, + {0xff73, 345}, + {0xff74, 346}, + {0xff75, 347}, + {0xff76, 348}, + {0xff77, 349}, + {0xff78, 350}, + {0xff79, 351}, + {0xff7a, 352}, + {0xff7b, 353}, + {0xff7c, 354}, + {0xff7d, 355}, + {0xff7e, 356}, + {0xff7f, 357}, + {0xff80, 358}, + {0xff81, 359}, + {0xff82, 360}, + {0xff83, 361}, + {0xff84, 362}, + {0xff85, 363}, + {0xff86, 364}, + {0xff87, 365}, + {0xff88, 366}, + {0xff89, 367}, + {0xff8a, 368}, + {0xff8b, 369}, + {0xff8c, 370}, + {0xff8d, 371}, + {0xff8e, 372}, + {0xff8f, 373}, + {0xff90, 374}, + {0xff91, 375}, + {0xff92, 376}, + {0xff93, 377}, + {0xff94, 378}, + {0xff95, 379}, + {0xff96, 380}, + {0xff97, 381}, + {0xff98, 382}, + {0xff99, 383}, + {0xff9a, 384}, + {0xff9b, 385}, + {0xff9c, 386}, + {0xff9d, 387}, + {0xff9e, 388}, + {0xff9f, 389}, + {0xffe0, 713}, + {0xffe1, 714}, + {0xffe2, 751}, + {0xffe3, 649}, + {0xffe4, 8005}, + {0xffe5, 711}, + {0xffe8, 323}}; + diff --git a/src/add-ons/print/drivers/pdf/source/korean.h b/src/add-ons/print/drivers/pdf/source/korean.h new file mode 100644 index 0000000000..8edad3f663 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/korean.h @@ -0,0 +1,15848 @@ +// WARNING: MACHINE GENERATED, DON'T CHANGE! +static unicode_to_cid korean[] = { + {0x20, 1}, + {0x21, 2}, + {0x22, 3}, + {0x23, 4}, + {0x24, 5}, + {0x25, 6}, + {0x26, 7}, + {0x27, 8}, + {0x28, 9}, + {0x29, 10}, + {0x2a, 11}, + {0x2b, 12}, + {0x2c, 13}, + {0x2d, 14}, + {0x2e, 15}, + {0x2f, 16}, + {0x30, 17}, + {0x31, 18}, + {0x32, 19}, + {0x33, 20}, + {0x34, 21}, + {0x35, 22}, + {0x36, 23}, + {0x37, 24}, + {0x38, 25}, + {0x39, 26}, + {0x3a, 27}, + {0x3b, 28}, + {0x3c, 29}, + {0x3d, 30}, + {0x3e, 31}, + {0x3f, 32}, + {0x40, 33}, + {0x41, 34}, + {0x42, 35}, + {0x43, 36}, + {0x44, 37}, + {0x45, 38}, + {0x46, 39}, + {0x47, 40}, + {0x48, 41}, + {0x49, 42}, + {0x4a, 43}, + {0x4b, 44}, + {0x4c, 45}, + {0x4d, 46}, + {0x4e, 47}, + {0x4f, 48}, + {0x50, 49}, + {0x51, 50}, + {0x52, 51}, + {0x53, 52}, + {0x54, 53}, + {0x55, 54}, + {0x56, 55}, + {0x57, 56}, + {0x58, 57}, + {0x59, 58}, + {0x5a, 59}, + {0x5b, 60}, + {0x5c, 61}, + {0x5d, 62}, + {0x5e, 63}, + {0x5f, 64}, + {0x60, 65}, + {0x61, 66}, + {0x62, 67}, + {0x63, 68}, + {0x64, 69}, + {0x65, 70}, + {0x66, 71}, + {0x67, 72}, + {0x68, 73}, + {0x69, 74}, + {0x6a, 75}, + {0x6b, 76}, + {0x6c, 77}, + {0x6d, 78}, + {0x6e, 79}, + {0x6f, 80}, + {0x70, 81}, + {0x71, 82}, + {0x72, 83}, + {0x73, 84}, + {0x74, 85}, + {0x75, 86}, + {0x76, 87}, + {0x77, 88}, + {0x78, 89}, + {0x79, 90}, + {0x7a, 91}, + {0x7b, 92}, + {0x7c, 93}, + {0x7d, 94}, + {0x7e, 95}, + {0xa1, 208}, + {0xa4, 214}, + {0xa7, 155}, + {0xa8, 107}, + {0xaa, 668}, + {0xab, 176}, + {0xb0, 138}, + {0xb1, 130}, + {0xb2, 843}, + {0xb3, 844}, + {0xb4, 199}, + {0xb6, 244}, + {0xb8, 206}, + {0xb9, 842}, + {0xba, 675}, + {0xbb, 177}, + {0xbc, 751}, + {0xbd, 748}, + {0xbe, 752}, + {0xbf, 209}, + {0xc6, 666}, + {0xd0, 667}, + {0xd7, 131}, + {0xd8, 673}, + {0xde, 676}, + {0xdf, 768}, + {0xe6, 757}, + {0xf0, 759}, + {0xf7, 132}, + {0xf8, 766}, + {0xfe, 769}, + {0x111, 758}, + {0x126, 669}, + {0x127, 760}, + {0x131, 761}, + {0x132, 670}, + {0x133, 762}, + {0x138, 763}, + {0x13f, 671}, + {0x140, 764}, + {0x141, 672}, + {0x142, 765}, + {0x149, 772}, + {0x14a, 678}, + {0x14b, 771}, + {0x152, 674}, + {0x153, 767}, + {0x166, 677}, + {0x167, 770}, + {0x2bc, 8275}, + {0x2c7, 201}, + {0x2d8, 202}, + {0x2d9, 205}, + {0x2da, 204}, + {0x2db, 207}, + {0x2dc, 200}, + {0x2dd, 203}, + {0x391, 471}, + {0x392, 472}, + {0x393, 473}, + {0x394, 474}, + {0x395, 475}, + {0x396, 476}, + {0x397, 477}, + {0x398, 478}, + {0x399, 479}, + {0x39a, 480}, + {0x39b, 481}, + {0x39c, 482}, + {0x39d, 483}, + {0x39e, 484}, + {0x39f, 485}, + {0x3a0, 486}, + {0x3a1, 487}, + {0x3a3, 488}, + {0x3a4, 489}, + {0x3a5, 490}, + {0x3a6, 491}, + {0x3a7, 492}, + {0x3a8, 493}, + {0x3a9, 494}, + {0x3b1, 495}, + {0x3b2, 496}, + {0x3b3, 497}, + {0x3b4, 498}, + {0x3b5, 499}, + {0x3b6, 500}, + {0x3b7, 501}, + {0x3b8, 502}, + {0x3b9, 503}, + {0x3ba, 504}, + {0x3bb, 505}, + {0x3bc, 506}, + {0x3bd, 507}, + {0x3be, 508}, + {0x3bf, 509}, + {0x3c0, 510}, + {0x3c1, 511}, + {0x3c3, 512}, + {0x3c4, 513}, + {0x3c5, 514}, + {0x3c6, 515}, + {0x3c7, 516}, + {0x3c8, 517}, + {0x3c9, 518}, + {0x401, 1026}, + {0x410, 1020}, + {0x411, 1021}, + {0x412, 1022}, + {0x413, 1023}, + {0x414, 1024}, + {0x415, 1025}, + {0x416, 1027}, + {0x417, 1028}, + {0x418, 1029}, + {0x419, 1030}, + {0x41a, 1031}, + {0x41b, 1032}, + {0x41c, 1033}, + {0x41d, 1034}, + {0x41e, 1035}, + {0x41f, 1036}, + {0x420, 1037}, + {0x421, 1038}, + {0x422, 1039}, + {0x423, 1040}, + {0x424, 1041}, + {0x425, 1042}, + {0x426, 1043}, + {0x427, 1044}, + {0x428, 1045}, + {0x429, 1046}, + {0x42a, 1047}, + {0x42b, 1048}, + {0x42c, 1049}, + {0x42d, 1050}, + {0x42e, 1051}, + {0x42f, 1052}, + {0x430, 1053}, + {0x431, 1054}, + {0x432, 1055}, + {0x433, 1056}, + {0x434, 1057}, + {0x435, 1058}, + {0x436, 1060}, + {0x437, 1061}, + {0x438, 1062}, + {0x439, 1063}, + {0x43a, 1064}, + {0x43b, 1065}, + {0x43c, 1066}, + {0x43d, 1067}, + {0x43e, 1068}, + {0x43f, 1069}, + {0x440, 1070}, + {0x441, 1071}, + {0x442, 1072}, + {0x443, 1073}, + {0x444, 1074}, + {0x445, 1075}, + {0x446, 1076}, + {0x447, 1077}, + {0x448, 1078}, + {0x449, 1079}, + {0x44a, 1080}, + {0x44b, 1081}, + {0x44c, 1082}, + {0x44d, 1083}, + {0x44e, 1084}, + {0x44f, 1085}, + {0x451, 1059}, + {0x2013, 109}, + {0x2014, 110}, + {0x2016, 111}, + {0x2018, 114}, + {0x2019, 115}, + {0x201b, 8238}, + {0x201c, 116}, + {0x201d, 117}, + {0x201f, 8237}, + {0x2020, 245}, + {0x2021, 246}, + {0x2022, 8607}, + {0x2025, 105}, + {0x2026, 106}, + {0x2030, 216}, + {0x2032, 139}, + {0x2033, 140}, + {0x2034, 8582}, + {0x2035, 9326}, + {0x2036, 9324}, + {0x2039, 8612}, + {0x203a, 8613}, + {0x203b, 156}, + {0x203c, 8763}, + {0x2042, 8599}, + {0x2074, 845}, + {0x207a, 8239}, + {0x207b, 8240}, + {0x207c, 8248}, + {0x207d, 8250}, + {0x207e, 8251}, + {0x207f, 846}, + {0x2081, 847}, + {0x2082, 848}, + {0x2083, 849}, + {0x2084, 850}, + {0x2103, 141}, + {0x2109, 215}, + {0x2113, 590}, + {0x2116, 258}, + {0x2121, 263}, + {0x2122, 260}, + {0x2126, 643}, + {0x212b, 142}, + {0x2153, 749}, + {0x2154, 750}, + {0x215b, 753}, + {0x215c, 754}, + {0x215d, 755}, + {0x215e, 756}, + {0x2160, 461}, + {0x2161, 462}, + {0x2162, 463}, + {0x2163, 464}, + {0x2164, 465}, + {0x2165, 466}, + {0x2166, 467}, + {0x2167, 468}, + {0x2168, 469}, + {0x2169, 470}, + {0x2170, 451}, + {0x2171, 452}, + {0x2172, 453}, + {0x2173, 454}, + {0x2174, 455}, + {0x2175, 456}, + {0x2176, 457}, + {0x2177, 458}, + {0x2178, 459}, + {0x2179, 460}, + {0x2190, 171}, + {0x2191, 172}, + {0x2192, 170}, + {0x2193, 173}, + {0x2194, 174}, + {0x2195, 247}, + {0x2196, 250}, + {0x2197, 248}, + {0x2198, 251}, + {0x2199, 249}, + {0x21b0, 8868}, + {0x21b1, 8865}, + {0x21b2, 8864}, + {0x21b3, 8869}, + {0x21b4, 8867}, + {0x21bc, 8884}, + {0x21c0, 8885}, + {0x21c4, 8896}, + {0x21c5, 8897}, + {0x21cd, 8816}, + {0x21cf, 8815}, + {0x21d0, 8814}, + {0x21d1, 8854}, + {0x21d2, 195}, + {0x21d3, 8855}, + {0x21d4, 196}, + {0x21e0, 9190}, + {0x21e1, 9192}, + {0x21e2, 9191}, + {0x21e3, 9193}, + {0x21e6, 9198}, + {0x21e7, 9200}, + {0x21e8, 9199}, + {0x21e9, 9201}, + {0x2200, 197}, + {0x2202, 151}, + {0x2203, 198}, + {0x2206, 8715}, + {0x2207, 152}, + {0x2208, 184}, + {0x2209, 8749}, + {0x220b, 185}, + {0x220c, 8750}, + {0x220f, 213}, + {0x2211, 212}, + {0x2213, 8726}, + {0x221a, 178}, + {0x221d, 180}, + {0x221e, 136}, + {0x221f, 8717}, + {0x2220, 148}, + {0x2222, 8738}, + {0x2225, 8719}, + {0x2226, 8720}, + {0x2227, 192}, + {0x2228, 193}, + {0x2229, 191}, + {0x222a, 190}, + {0x222b, 182}, + {0x222c, 183}, + {0x222e, 211}, + {0x2234, 137}, + {0x2235, 181}, + {0x2236, 210}, + {0x2237, 8321}, + {0x223d, 179}, + {0x2243, 8500}, + {0x2245, 8499}, + {0x2248, 8501}, + {0x2250, 8739}, + {0x2251, 8723}, + {0x2252, 154}, + {0x2253, 8722}, + {0x225a, 8753}, + {0x2260, 133}, + {0x2261, 153}, + {0x2262, 8734}, + {0x2264, 134}, + {0x2265, 135}, + {0x2266, 8724}, + {0x2267, 8725}, + {0x226e, 8745}, + {0x226f, 8746}, + {0x2270, 8481}, + {0x2271, 8482}, + {0x2272, 8483}, + {0x2273, 8484}, + {0x2276, 8489}, + {0x2277, 8490}, + {0x2279, 8491}, + {0x227a, 8475}, + {0x227b, 8476}, + {0x2280, 8479}, + {0x2281, 8480}, + {0x2282, 188}, + {0x2283, 189}, + {0x2284, 8748}, + {0x2285, 8747}, + {0x2286, 186}, + {0x2287, 187}, + {0x228a, 8486}, + {0x228b, 8488}, + {0x2295, 8727}, + {0x2296, 8728}, + {0x2297, 8729}, + {0x22a3, 8742}, + {0x22a4, 8503}, + {0x22a5, 149}, + {0x22bb, 8751}, + {0x22bc, 8752}, + {0x22ce, 8477}, + {0x22cf, 8478}, + {0x22da, 8492}, + {0x22db, 8493}, + {0x22ee, 8320}, + {0x22ef, 106}, + {0x2306, 8754}, + {0x2312, 150}, + {0x2314, 8731}, + {0x2460, 733}, + {0x2461, 734}, + {0x2462, 735}, + {0x2463, 736}, + {0x2464, 737}, + {0x2465, 738}, + {0x2466, 739}, + {0x2467, 740}, + {0x2468, 741}, + {0x2469, 742}, + {0x246a, 743}, + {0x246b, 744}, + {0x246c, 745}, + {0x246d, 746}, + {0x246e, 747}, + {0x246f, 8791}, + {0x2470, 8792}, + {0x2471, 8793}, + {0x2472, 8794}, + {0x2473, 8795}, + {0x2474, 827}, + {0x2475, 828}, + {0x2476, 829}, + {0x2477, 830}, + {0x2478, 831}, + {0x2479, 832}, + {0x247a, 833}, + {0x247b, 834}, + {0x247c, 835}, + {0x247d, 836}, + {0x247e, 837}, + {0x247f, 838}, + {0x2480, 839}, + {0x2481, 840}, + {0x2482, 841}, + {0x2483, 9042}, + {0x2484, 9043}, + {0x2485, 9044}, + {0x2486, 9045}, + {0x2487, 9046}, + {0x249c, 801}, + {0x249d, 802}, + {0x249e, 803}, + {0x249f, 804}, + {0x24a0, 805}, + {0x24a1, 806}, + {0x24a2, 807}, + {0x24a3, 808}, + {0x24a4, 809}, + {0x24a5, 810}, + {0x24a6, 811}, + {0x24a7, 812}, + {0x24a8, 813}, + {0x24a9, 814}, + {0x24aa, 815}, + {0x24ab, 816}, + {0x24ac, 817}, + {0x24ad, 818}, + {0x24ae, 819}, + {0x24af, 820}, + {0x24b0, 821}, + {0x24b1, 822}, + {0x24b2, 823}, + {0x24b3, 824}, + {0x24b4, 825}, + {0x24b5, 826}, + {0x24b6, 8388}, + {0x24b7, 8389}, + {0x24b8, 8390}, + {0x24b9, 8391}, + {0x24ba, 8392}, + {0x24bb, 8393}, + {0x24bc, 8394}, + {0x24bd, 8395}, + {0x24be, 8396}, + {0x24bf, 8397}, + {0x24c0, 8398}, + {0x24c1, 8399}, + {0x24c2, 8400}, + {0x24c3, 8401}, + {0x24c4, 8402}, + {0x24c5, 8403}, + {0x24c6, 8404}, + {0x24c7, 8405}, + {0x24c8, 8406}, + {0x24c9, 8407}, + {0x24ca, 8408}, + {0x24cb, 8409}, + {0x24cc, 8410}, + {0x24cd, 8411}, + {0x24ce, 8412}, + {0x24cf, 8413}, + {0x24d0, 707}, + {0x24d1, 708}, + {0x24d2, 709}, + {0x24d3, 710}, + {0x24d4, 711}, + {0x24d5, 712}, + {0x24d6, 713}, + {0x24d7, 714}, + {0x24d8, 715}, + {0x24d9, 716}, + {0x24da, 717}, + {0x24db, 718}, + {0x24dc, 719}, + {0x24dd, 720}, + {0x24de, 721}, + {0x24df, 722}, + {0x24e0, 723}, + {0x24e1, 724}, + {0x24e2, 725}, + {0x24e3, 726}, + {0x24e4, 727}, + {0x24e5, 728}, + {0x24e6, 729}, + {0x24e7, 730}, + {0x24e8, 731}, + {0x24e9, 732}, + {0x2500, 519}, + {0x2501, 530}, + {0x2502, 520}, + {0x2503, 531}, + {0x250c, 521}, + {0x250d, 558}, + {0x250e, 557}, + {0x250f, 532}, + {0x2510, 522}, + {0x2511, 552}, + {0x2512, 551}, + {0x2513, 533}, + {0x2514, 524}, + {0x2515, 556}, + {0x2516, 555}, + {0x2517, 535}, + {0x2518, 523}, + {0x2519, 554}, + {0x251a, 553}, + {0x251b, 534}, + {0x251c, 525}, + {0x251d, 546}, + {0x251e, 559}, + {0x251f, 560}, + {0x2520, 541}, + {0x2521, 561}, + {0x2522, 562}, + {0x2523, 536}, + {0x2524, 527}, + {0x2525, 548}, + {0x2526, 563}, + {0x2527, 564}, + {0x2528, 543}, + {0x2529, 565}, + {0x252a, 566}, + {0x252b, 538}, + {0x252c, 526}, + {0x252d, 567}, + {0x252e, 568}, + {0x252f, 542}, + {0x2530, 547}, + {0x2531, 569}, + {0x2532, 570}, + {0x2533, 537}, + {0x2534, 528}, + {0x2535, 571}, + {0x2536, 572}, + {0x2537, 544}, + {0x2538, 549}, + {0x2539, 573}, + {0x253a, 574}, + {0x253b, 539}, + {0x253c, 529}, + {0x253d, 575}, + {0x253e, 576}, + {0x253f, 545}, + {0x2540, 577}, + {0x2541, 578}, + {0x2542, 550}, + {0x2543, 579}, + {0x2544, 580}, + {0x2545, 581}, + {0x2546, 582}, + {0x2547, 583}, + {0x2548, 584}, + {0x2549, 585}, + {0x254a, 586}, + {0x254b, 540}, + {0x2592, 232}, + {0x25a0, 165}, + {0x25a1, 164}, + {0x25a3, 229}, + {0x25a4, 233}, + {0x25a5, 234}, + {0x25a6, 237}, + {0x25a7, 236}, + {0x25a8, 235}, + {0x25a9, 238}, + {0x25b1, 8736}, + {0x25b2, 167}, + {0x25b3, 166}, + {0x25b5, 8780}, + {0x25b6, 220}, + {0x25b7, 219}, + {0x25b9, 8781}, + {0x25bc, 169}, + {0x25bd, 168}, + {0x25bf, 8779}, + {0x25c0, 218}, + {0x25c1, 217}, + {0x25c3, 8782}, + {0x25c6, 163}, + {0x25c7, 162}, + {0x25c8, 228}, + {0x25c9, 227}, + {0x25ca, 8787}, + {0x25cb, 159}, + {0x25cc, 8639}, + {0x25ce, 161}, + {0x25cf, 160}, + {0x25d0, 230}, + {0x25d1, 231}, + {0x25e6, 8775}, + {0x25ef, 8633}, + {0x2605, 158}, + {0x2606, 157}, + {0x260e, 241}, + {0x260f, 240}, + {0x261c, 242}, + {0x261d, 9222}, + {0x261e, 243}, + {0x261f, 9223}, + {0x262f, 8664}, + {0x2640, 147}, + {0x2642, 146}, + {0x2660, 222}, + {0x2661, 223}, + {0x2663, 226}, + {0x2664, 221}, + {0x2665, 224}, + {0x2667, 225}, + {0x2668, 239}, + {0x2669, 253}, + {0x266a, 254}, + {0x266c, 255}, + {0x266d, 252}, + {0x266f, 8594}, + {0x2716, 8631}, + {0x271a, 8630}, + {0x273d, 8604}, + {0x2756, 8637}, + {0x2776, 8673}, + {0x2777, 8674}, + {0x2778, 8675}, + {0x2779, 8676}, + {0x277a, 8677}, + {0x277b, 8678}, + {0x277c, 8679}, + {0x277d, 8680}, + {0x277e, 8681}, + {0x277f, 8682}, + {0x278a, 8342}, + {0x278b, 8343}, + {0x278c, 8344}, + {0x278d, 8345}, + {0x278e, 8346}, + {0x278f, 8347}, + {0x2790, 8348}, + {0x2791, 8349}, + {0x2792, 8350}, + {0x2793, 8351}, + {0x3000, 101}, + {0x3001, 102}, + {0x3002, 103}, + {0x3003, 108}, + {0x3008, 120}, + {0x3009, 121}, + {0x300a, 122}, + {0x300b, 123}, + {0x300c, 124}, + {0x300d, 125}, + {0x300e, 126}, + {0x300f, 127}, + {0x3010, 128}, + {0x3011, 129}, + {0x3012, 8700}, + {0x3013, 175}, + {0x3014, 118}, + {0x3015, 119}, + {0x3016, 8219}, + {0x3017, 8220}, + {0x3018, 8221}, + {0x3019, 8222}, + {0x301e, 9322}, + {0x301f, 9323}, + {0x3020, 8671}, + {0x3036, 8701}, + {0x3041, 851}, + {0x3042, 852}, + {0x3043, 853}, + {0x3044, 854}, + {0x3045, 855}, + {0x3046, 856}, + {0x3047, 857}, + {0x3048, 858}, + {0x3049, 859}, + {0x304a, 860}, + {0x304b, 861}, + {0x304c, 862}, + {0x304d, 863}, + {0x304e, 864}, + {0x304f, 865}, + {0x3050, 866}, + {0x3051, 867}, + {0x3052, 868}, + {0x3053, 869}, + {0x3054, 870}, + {0x3055, 871}, + {0x3056, 872}, + {0x3057, 873}, + {0x3058, 874}, + {0x3059, 875}, + {0x305a, 876}, + {0x305b, 877}, + {0x305c, 878}, + {0x305d, 879}, + {0x305e, 880}, + {0x305f, 881}, + {0x3060, 882}, + {0x3061, 883}, + {0x3062, 884}, + {0x3063, 885}, + {0x3064, 886}, + {0x3065, 887}, + {0x3066, 888}, + {0x3067, 889}, + {0x3068, 890}, + {0x3069, 891}, + {0x306a, 892}, + {0x306b, 893}, + {0x306c, 894}, + {0x306d, 895}, + {0x306e, 896}, + {0x306f, 897}, + {0x3070, 898}, + {0x3071, 899}, + {0x3072, 900}, + {0x3073, 901}, + {0x3074, 902}, + {0x3075, 903}, + {0x3076, 904}, + {0x3077, 905}, + {0x3078, 906}, + {0x3079, 907}, + {0x307a, 908}, + {0x307b, 909}, + {0x307c, 910}, + {0x307d, 911}, + {0x307e, 912}, + {0x307f, 913}, + {0x3080, 914}, + {0x3081, 915}, + {0x3082, 916}, + {0x3083, 917}, + {0x3084, 918}, + {0x3085, 919}, + {0x3086, 920}, + {0x3087, 921}, + {0x3088, 922}, + {0x3089, 923}, + {0x308a, 924}, + {0x308b, 925}, + {0x308c, 926}, + {0x308d, 927}, + {0x308e, 928}, + {0x308f, 929}, + {0x3090, 930}, + {0x3091, 931}, + {0x3092, 932}, + {0x3093, 933}, + {0x30a1, 934}, + {0x30a2, 935}, + {0x30a3, 936}, + {0x30a4, 937}, + {0x30a5, 938}, + {0x30a6, 939}, + {0x30a7, 940}, + {0x30a8, 941}, + {0x30a9, 942}, + {0x30aa, 943}, + {0x30ab, 944}, + {0x30ac, 945}, + {0x30ad, 946}, + {0x30ae, 947}, + {0x30af, 948}, + {0x30b0, 949}, + {0x30b1, 950}, + {0x30b2, 951}, + {0x30b3, 952}, + {0x30b4, 953}, + {0x30b5, 954}, + {0x30b6, 955}, + {0x30b7, 956}, + {0x30b8, 957}, + {0x30b9, 958}, + {0x30ba, 959}, + {0x30bb, 960}, + {0x30bc, 961}, + {0x30bd, 962}, + {0x30be, 963}, + {0x30bf, 964}, + {0x30c0, 965}, + {0x30c1, 966}, + {0x30c2, 967}, + {0x30c3, 968}, + {0x30c4, 969}, + {0x30c5, 970}, + {0x30c6, 971}, + {0x30c7, 972}, + {0x30c8, 973}, + {0x30c9, 974}, + {0x30ca, 975}, + {0x30cb, 976}, + {0x30cc, 977}, + {0x30cd, 978}, + {0x30ce, 979}, + {0x30cf, 980}, + {0x30d0, 981}, + {0x30d1, 982}, + {0x30d2, 983}, + {0x30d3, 984}, + {0x30d4, 985}, + {0x30d5, 986}, + {0x30d6, 987}, + {0x30d7, 988}, + {0x30d8, 989}, + {0x30d9, 990}, + {0x30da, 991}, + {0x30db, 992}, + {0x30dc, 993}, + {0x30dd, 994}, + {0x30de, 995}, + {0x30df, 996}, + {0x30e0, 997}, + {0x30e1, 998}, + {0x30e2, 999}, + {0x30e3, 1000}, + {0x30e4, 1001}, + {0x30e5, 1002}, + {0x30e6, 1003}, + {0x30e7, 1004}, + {0x30e8, 1005}, + {0x30e9, 1006}, + {0x30ea, 1007}, + {0x30eb, 1008}, + {0x30ec, 1009}, + {0x30ed, 1010}, + {0x30ee, 1011}, + {0x30ef, 1012}, + {0x30f0, 1013}, + {0x30f1, 1014}, + {0x30f2, 1015}, + {0x30f3, 1016}, + {0x30f4, 1017}, + {0x30f5, 1018}, + {0x30f6, 1019}, + {0x30fb, 104}, + {0x30fc, 9330}, + {0x3131, 358}, + {0x3132, 359}, + {0x3133, 360}, + {0x3134, 361}, + {0x3135, 362}, + {0x3136, 363}, + {0x3137, 364}, + {0x3138, 365}, + {0x3139, 366}, + {0x313a, 367}, + {0x313b, 368}, + {0x313c, 369}, + {0x313d, 370}, + {0x313e, 371}, + {0x313f, 372}, + {0x3140, 373}, + {0x3141, 374}, + {0x3142, 375}, + {0x3143, 376}, + {0x3144, 377}, + {0x3145, 378}, + {0x3146, 379}, + {0x3147, 380}, + {0x3148, 381}, + {0x3149, 382}, + {0x314a, 383}, + {0x314b, 384}, + {0x314c, 385}, + {0x314d, 386}, + {0x314e, 387}, + {0x314f, 388}, + {0x3150, 389}, + {0x3151, 390}, + {0x3152, 391}, + {0x3153, 392}, + {0x3154, 393}, + {0x3155, 394}, + {0x3156, 395}, + {0x3157, 396}, + {0x3158, 397}, + {0x3159, 398}, + {0x315a, 399}, + {0x315b, 400}, + {0x315c, 401}, + {0x315d, 402}, + {0x315e, 403}, + {0x315f, 404}, + {0x3160, 405}, + {0x3161, 406}, + {0x3162, 407}, + {0x3163, 408}, + {0x3164, 101}, + {0x3165, 409}, + {0x3166, 410}, + {0x3167, 411}, + {0x3168, 412}, + {0x3169, 413}, + {0x316a, 414}, + {0x316b, 415}, + {0x316c, 416}, + {0x316d, 417}, + {0x316e, 418}, + {0x316f, 419}, + {0x3170, 420}, + {0x3171, 421}, + {0x3172, 422}, + {0x3173, 423}, + {0x3174, 424}, + {0x3175, 425}, + {0x3176, 426}, + {0x3177, 427}, + {0x3178, 428}, + {0x3179, 429}, + {0x317a, 430}, + {0x317b, 431}, + {0x317c, 432}, + {0x317d, 433}, + {0x317e, 434}, + {0x317f, 435}, + {0x3180, 436}, + {0x3181, 437}, + {0x3182, 438}, + {0x3183, 439}, + {0x3184, 440}, + {0x3185, 441}, + {0x3186, 442}, + {0x3187, 443}, + {0x3188, 444}, + {0x3189, 445}, + {0x318a, 446}, + {0x318b, 447}, + {0x318c, 448}, + {0x318d, 449}, + {0x318e, 450}, + {0x3200, 773}, + {0x3201, 774}, + {0x3202, 775}, + {0x3203, 776}, + {0x3204, 777}, + {0x3205, 778}, + {0x3206, 779}, + {0x3207, 780}, + {0x3208, 781}, + {0x3209, 782}, + {0x320a, 783}, + {0x320b, 784}, + {0x320c, 785}, + {0x320d, 786}, + {0x320e, 787}, + {0x320f, 788}, + {0x3210, 789}, + {0x3211, 790}, + {0x3212, 791}, + {0x3213, 792}, + {0x3214, 793}, + {0x3215, 794}, + {0x3216, 795}, + {0x3217, 796}, + {0x3218, 797}, + {0x3219, 798}, + {0x321a, 799}, + {0x321b, 800}, + {0x321c, 257}, + {0x3231, 8788}, + {0x3239, 8789}, + {0x3260, 679}, + {0x3261, 680}, + {0x3262, 681}, + {0x3263, 682}, + {0x3264, 683}, + {0x3265, 684}, + {0x3266, 685}, + {0x3267, 686}, + {0x3268, 687}, + {0x3269, 688}, + {0x326a, 689}, + {0x326b, 690}, + {0x326c, 691}, + {0x326d, 692}, + {0x326e, 693}, + {0x326f, 694}, + {0x3270, 695}, + {0x3271, 696}, + {0x3272, 697}, + {0x3273, 698}, + {0x3274, 699}, + {0x3275, 700}, + {0x3276, 701}, + {0x3277, 702}, + {0x3278, 703}, + {0x3279, 704}, + {0x327a, 705}, + {0x327b, 706}, + {0x327f, 256}, + {0x328a, 9301}, + {0x328b, 9302}, + {0x328c, 9303}, + {0x328d, 9304}, + {0x328e, 9305}, + {0x328f, 9306}, + {0x3290, 9300}, + {0x3294, 9080}, + {0x329e, 8761}, + {0x32a5, 9096}, + {0x3380, 627}, + {0x3381, 628}, + {0x3382, 629}, + {0x3383, 630}, + {0x3384, 631}, + {0x3388, 612}, + {0x3389, 613}, + {0x338a, 646}, + {0x338b, 647}, + {0x338c, 648}, + {0x338d, 608}, + {0x338e, 609}, + {0x338f, 610}, + {0x3390, 638}, + {0x3391, 639}, + {0x3392, 640}, + {0x3393, 641}, + {0x3394, 642}, + {0x3395, 587}, + {0x3396, 588}, + {0x3397, 589}, + {0x3398, 591}, + {0x3399, 597}, + {0x339a, 598}, + {0x339b, 599}, + {0x339c, 600}, + {0x339d, 601}, + {0x339e, 602}, + {0x339f, 603}, + {0x33a0, 604}, + {0x33a1, 605}, + {0x33a2, 606}, + {0x33a3, 593}, + {0x33a4, 594}, + {0x33a5, 595}, + {0x33a6, 596}, + {0x33a7, 615}, + {0x33a8, 616}, + {0x33a9, 655}, + {0x33aa, 656}, + {0x33ab, 657}, + {0x33ac, 658}, + {0x33ad, 651}, + {0x33ae, 652}, + {0x33af, 653}, + {0x33b0, 617}, + {0x33b1, 618}, + {0x33b2, 619}, + {0x33b3, 620}, + {0x33b4, 621}, + {0x33b5, 622}, + {0x33b6, 623}, + {0x33b7, 624}, + {0x33b8, 625}, + {0x33b9, 626}, + {0x33ba, 632}, + {0x33bb, 633}, + {0x33bc, 634}, + {0x33bd, 635}, + {0x33be, 636}, + {0x33bf, 637}, + {0x33c0, 644}, + {0x33c1, 645}, + {0x33c2, 261}, + {0x33c3, 662}, + {0x33c4, 592}, + {0x33c5, 650}, + {0x33c6, 665}, + {0x33c7, 259}, + {0x33c8, 614}, + {0x33c9, 663}, + {0x33ca, 607}, + {0x33cb, 8790}, + {0x33cf, 611}, + {0x33d0, 660}, + {0x33d3, 661}, + {0x33d6, 649}, + {0x33d8, 262}, + {0x33db, 654}, + {0x33dc, 664}, + {0x33dd, 659}, + {0x4e00, 6460}, + {0x4e01, 6704}, + {0x4e03, 7364}, + {0x4e07, 4670}, + {0x4e08, 6534}, + {0x4e09, 5320}, + {0x4e0a, 5331}, + {0x4e0b, 7616}, + {0x4e0d, 5109}, + {0x4e11, 7288}, + {0x4e14, 7041}, + {0x4e15, 5181}, + {0x4e16, 5492}, + {0x4e18, 3893}, + {0x4e19, 5041}, + {0x4e1e, 5682}, + {0x4e2d, 6922}, + {0x4e32, 3802}, + {0x4e38, 7882}, + {0x4e39, 4192}, + {0x4e3b, 6860}, + {0x4e42, 6029}, + {0x4e43, 4154}, + {0x4e45, 3894}, + {0x4e4b, 6942}, + {0x4e4d, 5241}, + {0x4e4e, 7800}, + {0x4e4f, 7614}, + {0x4e56, 3855}, + {0x4e58, 5683}, + {0x4e59, 6380}, + {0x4e5d, 3895}, + {0x4e5e, 3613}, + {0x4e5f, 5862}, + {0x4e6b, 3500}, + {0x4e6d, 4329}, + {0x4e73, 6309}, + {0x4e76, 5092}, + {0x4e77, 5315}, + {0x4e7e, 3601}, + {0x4e82, 4389}, + {0x4e86, 4551}, + {0x4e88, 5934}, + {0x4e8b, 5242}, + {0x4e8c, 6413}, + {0x4e8e, 6197}, + {0x4e90, 6252}, + {0x4e91, 6238}, + {0x4e92, 7801}, + {0x4e94, 6049}, + {0x4e95, 6705}, + {0x4e98, 4058}, + {0x4e9b, 5243}, + {0x4e9e, 5775}, + {0x4ea1, 4696}, + {0x4ea2, 7670}, + {0x4ea4, 3868}, + {0x4ea5, 7685}, + {0x4ea6, 5947}, + {0x4ea8, 7771}, + {0x4eab, 7710}, + {0x4eac, 3660}, + {0x4ead, 6706}, + {0x4eae, 4427}, + {0x4eb6, 4193}, + {0x4eba, 6443}, + {0x4ec0, 5771}, + {0x4ec1, 6444}, + {0x4ec4, 7331}, + {0x4ec7, 3896}, + {0x4eca, 4038}, + {0x4ecb, 3560}, + {0x4ecd, 6479}, + {0x4ed4, 6483}, + {0x4ed5, 5244}, + {0x4ed6, 7380}, + {0x4ed7, 6535}, + {0x4ed8, 5110}, + {0x4ed9, 5418}, + {0x4edd, 4331}, + {0x4edf, 7148}, + {0x4ee3, 4250}, + {0x4ee4, 4489}, + {0x4ee5, 6414}, + {0x4ef0, 5833}, + {0x4ef2, 6923}, + {0x4ef6, 3602}, + {0x4ef7, 3561}, + {0x4efb, 6469}, + {0x4f01, 4062}, + {0x4f09, 7671}, + {0x4f0a, 6415}, + {0x4f0b, 4051}, + {0x4f0d, 6050}, + {0x4f0e, 4063}, + {0x4f0f, 5074}, + {0x4f10, 5005}, + {0x4f11, 8005}, + {0x4f2f, 4988}, + {0x4f34, 4905}, + {0x4f36, 4490}, + {0x4f38, 5735}, + {0x4f3a, 5245}, + {0x4f3c, 5246}, + {0x4f3d, 3436}, + {0x4f43, 6643}, + {0x4f46, 4194}, + {0x4f47, 6591}, + {0x4f48, 7544}, + {0x4f4d, 6284}, + {0x4f4e, 6592}, + {0x4f4f, 6861}, + {0x4f50, 6854}, + {0x4f51, 6198}, + {0x4f55, 7617}, + {0x4f59, 5935}, + {0x4f5a, 6461}, + {0x4f5b, 5171}, + {0x4f5c, 6509}, + {0x4f69, 7502}, + {0x4f6f, 5879}, + {0x4f70, 4989}, + {0x4f73, 3437}, + {0x4f76, 4127}, + {0x4f7a, 6644}, + {0x4f7e, 6462}, + {0x4f7f, 5247}, + {0x4f81, 5736}, + {0x4f83, 3476}, + {0x4f84, 7015}, + {0x4f86, 4420}, + {0x4f88, 7336}, + {0x4f8a, 3839}, + {0x4f8b, 4506}, + {0x4f8d, 5692}, + {0x4f8f, 6862}, + {0x4f91, 6310}, + {0x4f96, 4594}, + {0x4f98, 7042}, + {0x4f9b, 3786}, + {0x4f9d, 6394}, + {0x4fae, 4764}, + {0x4faf, 7966}, + {0x4fb5, 7367}, + {0x4fb6, 4440}, + {0x4fbf, 7518}, + {0x4fc2, 3705}, + {0x4fc3, 7241}, + {0x4fc4, 5776}, + {0x4fc9, 6051}, + {0x4fca, 6902}, + {0x4fce, 6782}, + {0x4fd1, 6174}, + {0x4fd3, 3661}, + {0x4fd4, 7734}, + {0x4fd7, 5537}, + {0x4fda, 4613}, + {0x4fdd, 5058}, + {0x4fdf, 5248}, + {0x4fe0, 7759}, + {0x4fe1, 5737}, + {0x4fee, 5567}, + {0x4fef, 5111}, + {0x4ff1, 3897}, + {0x4ff3, 4970}, + {0x4ff5, 7576}, + {0x4ff8, 5093}, + {0x4ffa, 5925}, + {0x5002, 5042}, + {0x5006, 4428}, + {0x5009, 7092}, + {0x500b, 3562}, + {0x500d, 4969}, + {0x5011, 4836}, + {0x5012, 4269}, + {0x5016, 7705}, + {0x5019, 7967}, + {0x501a, 6395}, + {0x501c, 7134}, + {0x501e, 3662}, + {0x501f, 7043}, + {0x5021, 7093}, + {0x5023, 4941}, + {0x5024, 7337}, + {0x5026, 3969}, + {0x5027, 6837}, + {0x5028, 3585}, + {0x502a, 6030}, + {0x502b, 4595}, + {0x502c, 7394}, + {0x502d, 6131}, + {0x503b, 5863}, + {0x5043, 5917}, + {0x5047, 3438}, + {0x5048, 3627}, + {0x5049, 6285}, + {0x504f, 7519}, + {0x5055, 7686}, + {0x505a, 6863}, + {0x505c, 6707}, + {0x5065, 3603}, + {0x5074, 7330}, + {0x5075, 6708}, + {0x5076, 6199}, + {0x5078, 7465}, + {0x5080, 3856}, + {0x5085, 5112}, + {0x508d, 4942}, + {0x5091, 3614}, + {0x5098, 5303}, + {0x5099, 5182}, + {0x50ac, 7262}, + {0x50ad, 6175}, + {0x50b2, 6052}, + {0x50b3, 6645}, + {0x50b5, 7114}, + {0x50b7, 5332}, + {0x50be, 3663}, + {0x50c5, 4023}, + {0x50c9, 7177}, + {0x50ca, 5419}, + {0x50cf, 5333}, + {0x50d1, 3869}, + {0x50d5, 5075}, + {0x50d6, 8035}, + {0x50da, 4552}, + {0x50de, 6286}, + {0x50e5, 6140}, + {0x50e7, 5684}, + {0x50ed, 7082}, + {0x50f9, 3439}, + {0x50fb, 5020}, + {0x50ff, 5249}, + {0x5100, 6396}, + {0x5101, 6903}, + {0x5104, 5912}, + {0x5106, 3664}, + {0x5109, 3617}, + {0x5112, 6311}, + {0x511f, 5334}, + {0x5121, 4543}, + {0x512a, 6200}, + {0x5132, 6593}, + {0x5137, 4441}, + {0x513a, 4133}, + {0x513c, 5926}, + {0x5140, 6089}, + {0x5141, 6359}, + {0x5143, 6255}, + {0x5144, 7772}, + {0x5145, 7306}, + {0x5146, 6783}, + {0x5147, 8013}, + {0x5148, 5420}, + {0x5149, 3840}, + {0x514b, 4016}, + {0x514c, 7431}, + {0x514d, 4735}, + {0x514e, 7449}, + {0x5152, 5777}, + {0x515c, 4348}, + {0x5162, 4059}, + {0x5165, 6477}, + {0x5167, 4155}, + {0x5168, 6646}, + {0x5169, 4429}, + {0x516a, 6312}, + {0x516b, 7499}, + {0x516c, 3787}, + {0x516d, 4591}, + {0x516e, 7791}, + {0x5171, 3788}, + {0x5175, 5043}, + {0x5176, 4064}, + {0x5177, 3898}, + {0x5178, 6647}, + {0x517c, 3654}, + {0x5180, 4065}, + {0x5186, 5933}, + {0x518a, 7126}, + {0x518d, 6570}, + {0x5192, 4765}, + {0x5195, 4736}, + {0x5197, 6176}, + {0x51a0, 3819}, + {0x51a5, 4748}, + {0x51aa, 4733}, + {0x51ac, 4332}, + {0x51b6, 5864}, + {0x51b7, 4424}, + {0x51bd, 4477}, + {0x51c4, 7130}, + {0x51c6, 6904}, + {0x51c9, 4430}, + {0x51cb, 6784}, + {0x51cc, 4607}, + {0x51cd, 4333}, + {0x51dc, 4606}, + {0x51dd, 6390}, + {0x51de, 8036}, + {0x51e1, 5009}, + {0x51f0, 7904}, + {0x51f1, 3563}, + {0x51f6, 8014}, + {0x51f8, 7167}, + {0x51f9, 6141}, + {0x51fa, 7303}, + {0x51fd, 7651}, + {0x5200, 4270}, + {0x5203, 6445}, + {0x5206, 5152}, + {0x5207, 6684}, + {0x5208, 6031}, + {0x520a, 3477}, + {0x520e, 4837}, + {0x5211, 7773}, + {0x5217, 4478}, + {0x521d, 7214}, + {0x5224, 7490}, + {0x5225, 5037}, + {0x5229, 4614}, + {0x522a, 5304}, + {0x522e, 3835}, + {0x5230, 4271}, + {0x5236, 6759}, + {0x5237, 5561}, + {0x5238, 3970}, + {0x5239, 7077}, + {0x523a, 6484}, + {0x523b, 3465}, + {0x5243, 7205}, + {0x5247, 7360}, + {0x524a, 5301}, + {0x524b, 4017}, + {0x524c, 4397}, + {0x524d, 6648}, + {0x5254, 7135}, + {0x5256, 5113}, + {0x525b, 3536}, + {0x525d, 4886}, + {0x5261, 5463}, + {0x5269, 6480}, + {0x526a, 6649}, + {0x526f, 5114}, + {0x5272, 7649}, + {0x5275, 7094}, + {0x527d, 7577}, + {0x527f, 7215}, + {0x5283, 7948}, + {0x5287, 4018}, + {0x5288, 5021}, + {0x5289, 4577}, + {0x528d, 3618}, + {0x5291, 6760}, + {0x5292, 3619}, + {0x529b, 4458}, + {0x529f, 3789}, + {0x52a0, 3440}, + {0x52a3, 4479}, + {0x52a4, 4024}, + {0x52a9, 6785}, + {0x52aa, 4169}, + {0x52ab, 3624}, + {0x52be, 7703}, + {0x52c1, 3665}, + {0x52c3, 4930}, + {0x52c5, 7361}, + {0x52c7, 6177}, + {0x52c9, 4737}, + {0x52cd, 3666}, + {0x52d2, 4604}, + {0x52d5, 4334}, + {0x52d6, 6229}, + {0x52d8, 3510}, + {0x52d9, 4812}, + {0x52db, 7979}, + {0x52dd, 5685}, + {0x52de, 4511}, + {0x52df, 4766}, + {0x52e2, 5493}, + {0x52e3, 6619}, + {0x52e4, 4025}, + {0x52f3, 7980}, + {0x52f5, 4442}, + {0x52f8, 3971}, + {0x52fa, 6510}, + {0x52fb, 4009}, + {0x52fe, 3899}, + {0x52ff, 4848}, + {0x5305, 7545}, + {0x5308, 8015}, + {0x530d, 7546}, + {0x530f, 7547}, + {0x5310, 5076}, + {0x5315, 5183}, + {0x5316, 7863}, + {0x5317, 5151}, + {0x5319, 5693}, + {0x5320, 6536}, + {0x5321, 3841}, + {0x5323, 3530}, + {0x532a, 5184}, + {0x532f, 7928}, + {0x5339, 7604}, + {0x533f, 4188}, + {0x5340, 3900}, + {0x5341, 5772}, + {0x5343, 7149}, + {0x5344, 6478}, + {0x5347, 5686}, + {0x5348, 6053}, + {0x5349, 7994}, + {0x534a, 4906}, + {0x534d, 4671}, + {0x5351, 5185}, + {0x5352, 6834}, + {0x5353, 7395}, + {0x5354, 7760}, + {0x5357, 4145}, + {0x535a, 4887}, + {0x535c, 5077}, + {0x535e, 5031}, + {0x5360, 6692}, + {0x5366, 3852}, + {0x5368, 5450}, + {0x536f, 4800}, + {0x5370, 6446}, + {0x5371, 6287}, + {0x5374, 3466}, + {0x5375, 4390}, + {0x5377, 3972}, + {0x537d, 6926}, + {0x537f, 3667}, + {0x5384, 5851}, + {0x5393, 5840}, + {0x5398, 4615}, + {0x539a, 7968}, + {0x539f, 6256}, + {0x53a0, 7332}, + {0x53a5, 3979}, + {0x53a6, 7618}, + {0x53ad, 5989}, + {0x53bb, 3586}, + {0x53c3, 7083}, + {0x53c8, 6201}, + {0x53c9, 7044}, + {0x53ca, 4052}, + {0x53cb, 6202}, + {0x53cd, 4907}, + {0x53d4, 5628}, + {0x53d6, 7316}, + {0x53d7, 5568}, + {0x53db, 4908}, + {0x53e1, 6032}, + {0x53e2, 7251}, + {0x53e3, 3901}, + {0x53e4, 3729}, + {0x53e5, 3902}, + {0x53e9, 3730}, + {0x53ea, 6943}, + {0x53eb, 3994}, + {0x53ec, 5500}, + {0x53ed, 7500}, + {0x53ef, 3441}, + {0x53f0, 7432}, + {0x53f1, 7016}, + {0x53f2, 5250}, + {0x53f3, 6203}, + {0x53f8, 5251}, + {0x5403, 8023}, + {0x5404, 3467}, + {0x5408, 7663}, + {0x5409, 4128}, + {0x540a, 6620}, + {0x540c, 4335}, + {0x540d, 4749}, + {0x540e, 7969}, + {0x540f, 4616}, + {0x5410, 7450}, + {0x5411, 7711}, + {0x541b, 3953}, + {0x541d, 4638}, + {0x541f, 6381}, + {0x5420, 7534}, + {0x5426, 5115}, + {0x5429, 5153}, + {0x542b, 7652}, + {0x5433, 6055}, + {0x5438, 8030}, + {0x5439, 7317}, + {0x543b, 4838}, + {0x543c, 7970}, + {0x543e, 6054}, + {0x5442, 4443}, + {0x5448, 6709}, + {0x544a, 3731}, + {0x5451, 7408}, + {0x5468, 6867}, + {0x546a, 6866}, + {0x5471, 3732}, + {0x5473, 4851}, + {0x5475, 3442}, + {0x547b, 5738}, + {0x547c, 7802}, + {0x547d, 4750}, + {0x5480, 6594}, + {0x5486, 7548}, + {0x548c, 7864}, + {0x548e, 3903}, + {0x5490, 5116}, + {0x54a4, 7381}, + {0x54a8, 6485}, + {0x54ab, 6944}, + {0x54ac, 3870}, + {0x54b3, 7687}, + {0x54b8, 7653}, + {0x54bd, 6447}, + {0x54c0, 5841}, + {0x54c1, 7590}, + {0x54c4, 7853}, + {0x54c8, 7664}, + {0x54c9, 6571}, + {0x54e1, 6257}, + {0x54e5, 3443}, + {0x54e8, 7216}, + {0x54ed, 3767}, + {0x54ee, 7953}, + {0x54f2, 7168}, + {0x54fa, 7549}, + {0x5504, 7503}, + {0x5506, 5252}, + {0x5507, 6980}, + {0x550e, 4617}, + {0x5510, 4239}, + {0x551c, 4689}, + {0x552f, 6313}, + {0x5531, 7095}, + {0x5535, 5821}, + {0x553e, 7382}, + {0x5544, 7396}, + {0x5546, 5335}, + {0x554f, 4839}, + {0x5553, 3706}, + {0x5556, 4217}, + {0x555e, 5778}, + {0x5563, 7654}, + {0x557c, 6761}, + {0x5580, 3579}, + {0x5584, 5421}, + {0x5586, 7169}, + {0x5587, 4374}, + {0x5589, 7971}, + {0x558a, 7655}, + {0x5598, 7150}, + {0x5599, 7995}, + {0x559a, 7883}, + {0x559c, 8037}, + {0x559d, 3501}, + {0x55a7, 7990}, + {0x55a9, 6314}, + {0x55aa, 5336}, + {0x55ab, 4132}, + {0x55ac, 3871}, + {0x55ae, 4195}, + {0x55c5, 7972}, + {0x55c7, 5365}, + {0x55d4, 6981}, + {0x55da, 6056}, + {0x55dc, 4066}, + {0x55df, 7045}, + {0x55e3, 5253}, + {0x55e4, 7338}, + {0x55fd, 5569}, + {0x55fe, 6868}, + {0x5606, 7409}, + {0x5609, 3444}, + {0x5614, 3904}, + {0x5617, 5337}, + {0x562f, 5501}, + {0x5632, 6786}, + {0x5634, 7318}, + {0x5636, 5694}, + {0x5653, 7719}, + {0x5668, 4067}, + {0x566b, 8038}, + {0x5674, 5154}, + {0x5686, 7954}, + {0x56a5, 5956}, + {0x56ac, 5223}, + {0x56ae, 7712}, + {0x56b4, 5927}, + {0x56bc, 6511}, + {0x56ca, 4152}, + {0x56cd, 8039}, + {0x56d1, 7242}, + {0x56da, 5570}, + {0x56db, 5254}, + {0x56de, 7929}, + {0x56e0, 6448}, + {0x56f0, 3774}, + {0x56f9, 4491}, + {0x56fa, 3733}, + {0x5703, 7550}, + {0x5704, 5902}, + {0x5708, 3973}, + {0x570b, 3947}, + {0x570d, 6288}, + {0x5712, 6259}, + {0x5713, 6258}, + {0x5716, 4272}, + {0x5718, 4196}, + {0x571f, 7451}, + {0x5728, 6572}, + {0x572d, 3995}, + {0x5730, 6945}, + {0x573b, 4068}, + {0x5740, 6946}, + {0x5742, 7491}, + {0x5747, 4010}, + {0x574a, 4943}, + {0x574d, 4218}, + {0x574e, 3511}, + {0x5750, 6855}, + {0x5751, 3581}, + {0x5761, 7474}, + {0x5764, 3775}, + {0x5766, 7410}, + {0x576a, 7529}, + {0x576e, 4252}, + {0x5770, 3668}, + {0x5775, 3905}, + {0x577c, 7397}, + {0x5782, 5571}, + {0x5788, 4251}, + {0x578b, 7774}, + {0x5793, 7688}, + {0x57a0, 6373}, + {0x57a2, 3906}, + {0x57a3, 6260}, + {0x57c3, 5842}, + {0x57c7, 6178}, + {0x57c8, 6905}, + {0x57cb, 4708}, + {0x57ce, 5474}, + {0x57df, 5948}, + {0x57e0, 5117}, + {0x57f0, 7115}, + {0x57f4, 5720}, + {0x57f7, 7032}, + {0x57f9, 4971}, + {0x57fa, 4069}, + {0x57fc, 4070}, + {0x5800, 3959}, + {0x5802, 4240}, + {0x5805, 3637}, + {0x5806, 7459}, + {0x5808, 3537}, + {0x5809, 6355}, + {0x580a, 5793}, + {0x581e, 7187}, + {0x5821, 5059}, + {0x5824, 6762}, + {0x5827, 5957}, + {0x582a, 3512}, + {0x582f, 6142}, + {0x5830, 5918}, + {0x5831, 5060}, + {0x5834, 6537}, + {0x5835, 4273}, + {0x583a, 3707}, + {0x584a, 3857}, + {0x584b, 6002}, + {0x584f, 3564}, + {0x5851, 5502}, + {0x5854, 7424}, + {0x5857, 4274}, + {0x5858, 4241}, + {0x585a, 7252}, + {0x585e, 5362}, + {0x5861, 6650}, + {0x5862, 6057}, + {0x5864, 7981}, + {0x5875, 6982}, + {0x5879, 7084}, + {0x587c, 6651}, + {0x587e, 5629}, + {0x5883, 3669}, + {0x5885, 5373}, + {0x5889, 6179}, + {0x5893, 4801}, + {0x589c, 7265}, + {0x589e, 6931}, + {0x589f, 7720}, + {0x58a8, 4834}, + {0x58a9, 4319}, + {0x58ae, 7383}, + {0x58b3, 5155}, + {0x58ba, 6058}, + {0x58bb, 6538}, + {0x58be, 3478}, + {0x58c1, 5022}, + {0x58c5, 6090}, + {0x58c7, 4197}, + {0x58ce, 7982}, + {0x58d1, 7630}, + {0x58d3, 5829}, + {0x58d5, 7803}, + {0x58d8, 4564}, + {0x58d9, 3842}, + {0x58de, 3858}, + {0x58df, 4536}, + {0x58e4, 5880}, + {0x58eb, 5255}, + {0x58ec, 6470}, + {0x58ef, 6539}, + {0x58f9, 6463}, + {0x58fa, 7804}, + {0x58fb, 5374}, + {0x58fd, 5572}, + {0x590f, 7619}, + {0x5914, 4071}, + {0x5915, 5403}, + {0x5916, 6135}, + {0x5919, 5630}, + {0x591a, 4190}, + {0x591c, 5865}, + {0x5922, 4797}, + {0x5927, 4253}, + {0x5929, 7151}, + {0x592a, 7433}, + {0x592b, 5118}, + {0x592d, 6143}, + {0x592e, 5834}, + {0x5931, 5758}, + {0x5937, 6416}, + {0x593e, 7761}, + {0x5944, 5928}, + {0x5947, 4072}, + {0x5948, 4156}, + {0x5949, 5094}, + {0x594e, 3996}, + {0x594f, 6869}, + {0x5950, 7884}, + {0x5951, 3708}, + {0x5954, 5156}, + {0x5955, 7730}, + {0x5957, 7466}, + {0x595a, 7689}, + {0x5960, 6652}, + {0x5962, 5256}, + {0x5967, 6059}, + {0x596a, 7418}, + {0x596b, 6360}, + {0x596c, 6540}, + {0x596d, 5404}, + {0x596e, 5157}, + {0x5973, 4159}, + {0x5974, 4170}, + {0x5978, 3479}, + {0x597d, 7805}, + {0x5982, 5936}, + {0x5983, 5186}, + {0x5984, 4697}, + {0x598a, 6471}, + {0x5993, 4073}, + {0x5996, 6144}, + {0x5997, 4039}, + {0x5999, 4802}, + {0x59a5, 7384}, + {0x59a8, 4944}, + {0x59ac, 7467}, + {0x59b9, 4709}, + {0x59bb, 7131}, + {0x59be, 7188}, + {0x59c3, 6710}, + {0x59c6, 4767}, + {0x59c9, 6486}, + {0x59cb, 5695}, + {0x59d0, 6595}, + {0x59d1, 3734}, + {0x59d3, 5475}, + {0x59d4, 6289}, + {0x59d9, 6472}, + {0x59da, 6145}, + {0x59dc, 3538}, + {0x59dd, 6864}, + {0x59e6, 3480}, + {0x59e8, 6417}, + {0x59ea, 7017}, + {0x59ec, 8040}, + {0x59ee, 7672}, + {0x59f8, 5958}, + {0x59fb, 6449}, + {0x59ff, 6487}, + {0x5a01, 6290}, + {0x5a03, 6132}, + {0x5a11, 5257}, + {0x5a18, 4153}, + {0x5a1b, 6060}, + {0x5a1c, 4134}, + {0x5a1f, 5959}, + {0x5a20, 5739}, + {0x5a25, 5779}, + {0x5a29, 4672}, + {0x5a36, 7319}, + {0x5a3c, 7096}, + {0x5a41, 4565}, + {0x5a46, 7475}, + {0x5a49, 6107}, + {0x5a5a, 7844}, + {0x5a62, 5187}, + {0x5a66, 5119}, + {0x5a92, 4710}, + {0x5a9a, 4852}, + {0x5a9b, 6261}, + {0x5aa4, 5696}, + {0x5ac1, 3445}, + {0x5ac2, 5573}, + {0x5ac4, 6262}, + {0x5ac9, 7018}, + {0x5acc, 7758}, + {0x5ae1, 6621}, + {0x5ae6, 7673}, + {0x5ae9, 4181}, + {0x5b05, 7865}, + {0x5b09, 8041}, + {0x5b0b, 5422}, + {0x5b0c, 3872}, + {0x5b16, 7535}, + {0x5b2a, 5224}, + {0x5b40, 5338}, + {0x5b43, 5881}, + {0x5b50, 6488}, + {0x5b51, 7754}, + {0x5b54, 3790}, + {0x5b55, 6481}, + {0x5b57, 6489}, + {0x5b58, 6832}, + {0x5b5a, 5120}, + {0x5b5c, 6490}, + {0x5b5d, 7955}, + {0x5b5f, 4727}, + {0x5b63, 3709}, + {0x5b64, 3735}, + {0x5b69, 7690}, + {0x5b6b, 5546}, + {0x5b70, 5631}, + {0x5b71, 6522}, + {0x5b75, 5121}, + {0x5b78, 7631}, + {0x5b7a, 6315}, + {0x5b7c, 5923}, + {0x5b85, 4266}, + {0x5b87, 6204}, + {0x5b88, 5574}, + {0x5b89, 5807}, + {0x5b8b, 5553}, + {0x5b8c, 6108}, + {0x5b8f, 3864}, + {0x5b93, 5078}, + {0x5b95, 7427}, + {0x5b96, 7950}, + {0x5b97, 6838}, + {0x5b98, 3820}, + {0x5b99, 6870}, + {0x5b9a, 6711}, + {0x5b9b, 6109}, + {0x5b9c, 6397}, + {0x5ba2, 3580}, + {0x5ba3, 5423}, + {0x5ba4, 5759}, + {0x5ba5, 6316}, + {0x5ba6, 7885}, + {0x5bac, 5476}, + {0x5bae, 3963}, + {0x5bb0, 6573}, + {0x5bb3, 7691}, + {0x5bb4, 5960}, + {0x5bb5, 5503}, + {0x5bb6, 3446}, + {0x5bb8, 5740}, + {0x5bb9, 6180}, + {0x5bbf, 5632}, + {0x5bc0, 7116}, + {0x5bc2, 6622}, + {0x5bc3, 6263}, + {0x5bc4, 4074}, + {0x5bc5, 6450}, + {0x5bc6, 4883}, + {0x5bc7, 3907}, + {0x5bcc, 5122}, + {0x5bd0, 4711}, + {0x5bd2, 7635}, + {0x5bd3, 6205}, + {0x5bd4, 5721}, + {0x5bd7, 4168}, + {0x5bde, 4664}, + {0x5bdf, 7078}, + {0x5be1, 3803}, + {0x5be2, 7368}, + {0x5be4, 6061}, + {0x5be5, 6146}, + {0x5be6, 5760}, + {0x5be7, 4167}, + {0x5be8, 7117}, + {0x5be9, 5762}, + {0x5beb, 5258}, + {0x5bec, 3821}, + {0x5bee, 4553}, + {0x5bef, 6906}, + {0x5bf5, 7253}, + {0x5bf6, 5061}, + {0x5bf8, 7247}, + {0x5bfa, 5259}, + {0x5c01, 5095}, + {0x5c04, 5260}, + {0x5c07, 6541}, + {0x5c08, 6653}, + {0x5c09, 6291}, + {0x5c0a, 6833}, + {0x5c0b, 5763}, + {0x5c0d, 4254}, + {0x5c0e, 4275}, + {0x5c0f, 5504}, + {0x5c11, 5505}, + {0x5c16, 7178}, + {0x5c19, 5339}, + {0x5c24, 6206}, + {0x5c28, 4945}, + {0x5c31, 7320}, + {0x5c38, 5697}, + {0x5c39, 6361}, + {0x5c3a, 7136}, + {0x5c3b, 3736}, + {0x5c3c, 4186}, + {0x5c3e, 4853}, + {0x5c3f, 4180}, + {0x5c40, 3948}, + {0x5c45, 3587}, + {0x5c46, 3710}, + {0x5c48, 3960}, + {0x5c4b, 6078}, + {0x5c4d, 5699}, + {0x5c4e, 5698}, + {0x5c51, 5451}, + {0x5c55, 6654}, + {0x5c5b, 5044}, + {0x5c60, 4276}, + {0x5c62, 4566}, + {0x5c64, 7335}, + {0x5c65, 4618}, + {0x5c6c, 5538}, + {0x5c6f, 4358}, + {0x5c71, 5305}, + {0x5c79, 8024}, + {0x5c90, 4075}, + {0x5c91, 6527}, + {0x5ca1, 3539}, + {0x5ca9, 5822}, + {0x5cab, 5575}, + {0x5cac, 3531}, + {0x5cb1, 4255}, + {0x5cb3, 5794}, + {0x5cb5, 7806}, + {0x5cb7, 4870}, + {0x5cb8, 5808}, + {0x5cba, 4492}, + {0x5cbe, 6693}, + {0x5cc0, 5576}, + {0x5cd9, 7339}, + {0x5ce0, 5340}, + {0x5ce8, 5780}, + {0x5cef, 5096}, + {0x5cf0, 5097}, + {0x5cf4, 7735}, + {0x5cf6, 4277}, + {0x5cfb, 6907}, + {0x5cfd, 7762}, + {0x5d07, 5671}, + {0x5d0d, 4421}, + {0x5d0e, 4076}, + {0x5d11, 3776}, + {0x5d14, 7263}, + {0x5d16, 5843}, + {0x5d17, 3540}, + {0x5d19, 4596}, + {0x5d27, 5672}, + {0x5d29, 5175}, + {0x5d4b, 4854}, + {0x5d4c, 3513}, + {0x5d50, 4399}, + {0x5d69, 5673}, + {0x5d6c, 6136}, + {0x5d6f, 7046}, + {0x5d87, 3908}, + {0x5d8b, 4278}, + {0x5d9d, 4365}, + {0x5da0, 3873}, + {0x5da2, 6147}, + {0x5daa, 5931}, + {0x5db8, 6003}, + {0x5dba, 4493}, + {0x5dbc, 5375}, + {0x5dbd, 5795}, + {0x5dcd, 6137}, + {0x5dd2, 4673}, + {0x5dd6, 5823}, + {0x5ddd, 7152}, + {0x5dde, 6871}, + {0x5de1, 5640}, + {0x5de2, 5506}, + {0x5de5, 3791}, + {0x5de6, 6856}, + {0x5de7, 3874}, + {0x5de8, 3588}, + {0x5deb, 4813}, + {0x5dee, 7047}, + {0x5df1, 4077}, + {0x5df2, 6418}, + {0x5df3, 5261}, + {0x5df4, 7476}, + {0x5df7, 7674}, + {0x5dfd, 5547}, + {0x5dfe, 3604}, + {0x5e02, 5700}, + {0x5e03, 7551}, + {0x5e06, 5010}, + {0x5e0c, 8042}, + {0x5e11, 7428}, + {0x5e16, 7189}, + {0x5e19, 7019}, + {0x5e1b, 4990}, + {0x5e1d, 6763}, + {0x5e25, 5577}, + {0x5e2b, 5262}, + {0x5e2d, 5405}, + {0x5e33, 6542}, + {0x5e36, 4256}, + {0x5e38, 5341}, + {0x5e3d, 4768}, + {0x5e3f, 7973}, + {0x5e40, 6712}, + {0x5e44, 5796}, + {0x5e45, 7571}, + {0x5e47, 4946}, + {0x5e4c, 7905}, + {0x5e55, 4665}, + {0x5e5f, 7340}, + {0x5e61, 4996}, + {0x5e62, 4242}, + {0x5e63, 7536}, + {0x5e72, 3481}, + {0x5e73, 7530}, + {0x5e74, 4160}, + {0x5e77, 5045}, + {0x5e78, 7706}, + {0x5e79, 3482}, + {0x5e7b, 7886}, + {0x5e7c, 6317}, + {0x5e7d, 6318}, + {0x5e7e, 4078}, + {0x5e84, 6543}, + {0x5e87, 5188}, + {0x5e8a, 5342}, + {0x5e8f, 5376}, + {0x5e95, 6596}, + {0x5e97, 6694}, + {0x5e9a, 3670}, + {0x5e9c, 5123}, + {0x5ea0, 5343}, + {0x5ea6, 4279}, + {0x5ea7, 6857}, + {0x5eab, 3737}, + {0x5ead, 6713}, + {0x5eb5, 5824}, + {0x5eb6, 5377}, + {0x5eb7, 3541}, + {0x5eb8, 6181}, + {0x5ebe, 6319}, + {0x5ec2, 5344}, + {0x5ec8, 7620}, + {0x5ec9, 4483}, + {0x5eca, 4412}, + {0x5ed0, 3909}, + {0x5ed3, 3815}, + {0x5ed6, 4554}, + {0x5eda, 6872}, + {0x5edb, 6655}, + {0x5edf, 4803}, + {0x5ee0, 7097}, + {0x5ee2, 7537}, + {0x5ee3, 3843}, + {0x5eec, 4444}, + {0x5ef3, 7197}, + {0x5ef6, 5961}, + {0x5ef7, 6714}, + {0x5efa, 3605}, + {0x5efb, 7930}, + {0x5f01, 5032}, + {0x5f04, 4537}, + {0x5f0a, 7538}, + {0x5f0f, 5722}, + {0x5f11, 5701}, + {0x5f13, 3964}, + {0x5f14, 6787}, + {0x5f15, 6451}, + {0x5f17, 5172}, + {0x5f18, 7854}, + {0x5f1b, 6419}, + {0x5f1f, 6764}, + {0x5f26, 7736}, + {0x5f27, 7807}, + {0x5f29, 4171}, + {0x5f31, 5872}, + {0x5f35, 6544}, + {0x5f3a, 3542}, + {0x5f3c, 7605}, + {0x5f48, 7411}, + {0x5f4a, 3543}, + {0x5f4c, 4855}, + {0x5f4e, 4674}, + {0x5f56, 4198}, + {0x5f57, 7792}, + {0x5f59, 7997}, + {0x5f5b, 6420}, + {0x5f62, 7775}, + {0x5f66, 5919}, + {0x5f67, 6230}, + {0x5f69, 7118}, + {0x5f6a, 7578}, + {0x5f6b, 6788}, + {0x5f6c, 5225}, + {0x5f6d, 7513}, + {0x5f70, 7098}, + {0x5f71, 6004}, + {0x5f77, 4947}, + {0x5f79, 5949}, + {0x5f7c, 7597}, + {0x5f7f, 5173}, + {0x5f80, 6126}, + {0x5f81, 6715}, + {0x5f85, 4257}, + {0x5f87, 5641}, + {0x5f8a, 7931}, + {0x5f8b, 4600}, + {0x5f8c, 7974}, + {0x5f90, 5378}, + {0x5f91, 3671}, + {0x5f92, 4280}, + {0x5f97, 4364}, + {0x5f98, 4972}, + {0x5f99, 5263}, + {0x5f9e, 6839}, + {0x5fa0, 4422}, + {0x5fa1, 5903}, + {0x5fa8, 7906}, + {0x5fa9, 5079}, + {0x5faa, 5642}, + {0x5fae, 4856}, + {0x5fb5, 7038}, + {0x5fb7, 4267}, + {0x5fb9, 7170}, + {0x5fbd, 7998}, + {0x5fc3, 5764}, + {0x5fc5, 7606}, + {0x5fcc, 4079}, + {0x5fcd, 6452}, + {0x5fd6, 7248}, + {0x5fd7, 6947}, + {0x5fd8, 4698}, + {0x5fd9, 4699}, + {0x5fe0, 7307}, + {0x5feb, 7379}, + {0x5ff5, 4163}, + {0x5ffd, 7850}, + {0x5fff, 5158}, + {0x600f, 5835}, + {0x6012, 4172}, + {0x6016, 7552}, + {0x601c, 4494}, + {0x601d, 5264}, + {0x6020, 7434}, + {0x6021, 6421}, + {0x6025, 4053}, + {0x6027, 5477}, + {0x6028, 6264}, + {0x602a, 3859}, + {0x602f, 3625}, + {0x6041, 6473}, + {0x6042, 5643}, + {0x6043, 5702}, + {0x604d, 7907}, + {0x6050, 3792}, + {0x6052, 7675}, + {0x6055, 5379}, + {0x6059, 5882}, + {0x605d, 3836}, + {0x6062, 7932}, + {0x6063, 6491}, + {0x6064, 8010}, + {0x6065, 7341}, + {0x6068, 7636}, + {0x6069, 6374}, + {0x606a, 3468}, + {0x606c, 4164}, + {0x606d, 3793}, + {0x606f, 5723}, + {0x6070, 8031}, + {0x6085, 5985}, + {0x6089, 5761}, + {0x608c, 6765}, + {0x608d, 7637}, + {0x6094, 7933}, + {0x6096, 7504}, + {0x609a, 5554}, + {0x609b, 6656}, + {0x609f, 6062}, + {0x60a0, 6320}, + {0x60a3, 7887}, + {0x60a4, 7254}, + {0x60a7, 4619}, + {0x60b0, 6840}, + {0x60b2, 5189}, + {0x60b3, 4268}, + {0x60b4, 7312}, + {0x60b6, 4871}, + {0x60b8, 3711}, + {0x60bc, 4281}, + {0x60bd, 7132}, + {0x60c5, 6716}, + {0x60c7, 4320}, + {0x60d1, 7841}, + {0x60da, 7851}, + {0x60dc, 5406}, + {0x60df, 6321}, + {0x60e0, 7793}, + {0x60e1, 5797}, + {0x60f0, 7385}, + {0x60f1, 4178}, + {0x60f3, 5345}, + {0x60f6, 7908}, + {0x60f9, 5866}, + {0x60fa, 5478}, + {0x60fb, 7333}, + {0x6101, 5578}, + {0x6106, 3606}, + {0x6108, 6322}, + {0x6109, 6323}, + {0x610d, 4872}, + {0x610e, 7517}, + {0x610f, 6398}, + {0x6115, 5798}, + {0x611a, 6207}, + {0x611b, 5844}, + {0x611f, 3514}, + {0x6127, 3860}, + {0x6130, 7909}, + {0x6134, 7099}, + {0x6137, 3565}, + {0x613c, 5741}, + {0x613e, 3566}, + {0x613f, 6265}, + {0x6142, 6182}, + {0x6144, 4601}, + {0x6147, 6375}, + {0x6148, 6492}, + {0x614a, 3655}, + {0x614b, 7435}, + {0x614c, 7910}, + {0x6153, 7579}, + {0x6155, 4769}, + {0x6158, 7085}, + {0x6159, 7086}, + {0x615d, 7471}, + {0x615f, 7453}, + {0x6162, 4675}, + {0x6163, 3822}, + {0x6164, 3469}, + {0x6167, 7794}, + {0x6168, 3567}, + {0x616b, 6841}, + {0x616e, 4445}, + {0x6170, 6292}, + {0x6176, 3672}, + {0x6177, 3544}, + {0x617d, 7137}, + {0x617e, 6168}, + {0x6181, 7255}, + {0x6182, 6208}, + {0x618a, 5190}, + {0x618e, 6932}, + {0x6190, 4465}, + {0x6191, 5237}, + {0x6194, 7217}, + {0x6198, 8044}, + {0x6199, 8043}, + {0x619a, 7412}, + {0x61a4, 5159}, + {0x61a7, 4336}, + {0x61a9, 3628}, + {0x61ab, 4873}, + {0x61ac, 3673}, + {0x61ae, 4814}, + {0x61b2, 7723}, + {0x61b6, 5913}, + {0x61ba, 4219}, + {0x61be, 3515}, + {0x61c3, 4026}, + {0x61c7, 3483}, + {0x61c8, 7692}, + {0x61c9, 6391}, + {0x61ca, 6063}, + {0x61cb, 4815}, + {0x61e6, 4135}, + {0x61f2, 7039}, + {0x61f6, 4375}, + {0x61f7, 7934}, + {0x61f8, 7737}, + {0x61fa, 7087}, + {0x61fc, 3910}, + {0x61ff, 6399}, + {0x6200, 4466}, + {0x6207, 4243}, + {0x6208, 3804}, + {0x620a, 4816}, + {0x620c, 5667}, + {0x620d, 5579}, + {0x620e, 6369}, + {0x6210, 5479}, + {0x6211, 5781}, + {0x6212, 3712}, + {0x6216, 7842}, + {0x621a, 7138}, + {0x621f, 4019}, + {0x6221, 3516}, + {0x622a, 6685}, + {0x622e, 4592}, + {0x6230, 6657}, + {0x6231, 8045}, + {0x6234, 4258}, + {0x6236, 7808}, + {0x623e, 4446}, + {0x623f, 4948}, + {0x6240, 5507}, + {0x6241, 7520}, + {0x6247, 5424}, + {0x6248, 7809}, + {0x6249, 5191}, + {0x624b, 5580}, + {0x624d, 6574}, + {0x6253, 7386}, + {0x6258, 7398}, + {0x626e, 5160}, + {0x6271, 4054}, + {0x6276, 5124}, + {0x6279, 5192}, + {0x627c, 5852}, + {0x627f, 5687}, + {0x6280, 4080}, + {0x6284, 7218}, + {0x6289, 3648}, + {0x628a, 7477}, + {0x6291, 5914}, + {0x6292, 5380}, + {0x6295, 7468}, + {0x6297, 7676}, + {0x6298, 6686}, + {0x629b, 7553}, + {0x62ab, 7598}, + {0x62b1, 7554}, + {0x62b5, 6597}, + {0x62b9, 4690}, + {0x62bc, 5830}, + {0x62bd, 7266}, + {0x62c2, 5174}, + {0x62c7, 4817}, + {0x62c8, 4165}, + {0x62c9, 4409}, + {0x62cc, 4909}, + {0x62cd, 4888}, + {0x62cf, 4136}, + {0x62d0, 3861}, + {0x62d2, 3589}, + {0x62d3, 7139}, + {0x62d4, 4931}, + {0x62d6, 7387}, + {0x62d7, 6148}, + {0x62d8, 3911}, + {0x62d9, 6835}, + {0x62db, 7219}, + {0x62dc, 4973}, + {0x62ec, 3837}, + {0x62ed, 5724}, + {0x62ee, 4129}, + {0x62ef, 6934}, + {0x62f1, 3794}, + {0x62f3, 3974}, + {0x62f7, 3738}, + {0x62fe, 5678}, + {0x62ff, 4137}, + {0x6301, 6948}, + {0x6307, 6949}, + {0x6309, 5809}, + {0x6311, 4282}, + {0x632b, 6858}, + {0x632f, 6983}, + {0x633a, 6717}, + {0x633b, 5963}, + {0x633d, 4676}, + {0x633e, 7763}, + {0x6349, 7055}, + {0x634c, 7501}, + {0x634f, 4143}, + {0x6350, 5962}, + {0x6355, 7555}, + {0x6367, 5098}, + {0x6368, 5265}, + {0x636e, 3590}, + {0x6372, 3975}, + {0x6377, 7190}, + {0x637a, 4144}, + {0x637b, 4166}, + {0x637f, 5381}, + {0x6383, 5508}, + {0x6388, 5581}, + {0x6389, 4283}, + {0x638c, 6545}, + {0x6392, 4974}, + {0x6396, 5853}, + {0x6398, 3961}, + {0x639b, 3853}, + {0x63a0, 4425}, + {0x63a1, 7119}, + {0x63a2, 7420}, + {0x63a5, 6701}, + {0x63a7, 3795}, + {0x63a8, 7267}, + {0x63a9, 5929}, + {0x63aa, 6789}, + {0x63c0, 3484}, + {0x63c4, 6324}, + {0x63c6, 3997}, + {0x63cf, 4804}, + {0x63d0, 6766}, + {0x63d6, 6387}, + {0x63da, 5883}, + {0x63db, 7888}, + {0x63e1, 5799}, + {0x63ed, 3629}, + {0x63ee, 7999}, + {0x63f4, 6266}, + {0x63f6, 5867}, + {0x63f7, 5327}, + {0x640d, 5548}, + {0x640f, 4889}, + {0x6414, 5509}, + {0x6416, 6149}, + {0x6417, 4284}, + {0x641c, 5582}, + {0x6422, 6984}, + {0x642c, 4910}, + {0x642d, 7425}, + {0x643a, 8006}, + {0x643e, 7056}, + {0x6458, 6623}, + {0x6460, 7256}, + {0x6469, 4656}, + {0x646f, 6950}, + {0x6478, 4770}, + {0x6479, 4771}, + {0x647a, 6702}, + {0x6488, 4512}, + {0x6491, 7447}, + {0x6492, 5316}, + {0x6493, 6150}, + {0x649a, 4161}, + {0x649e, 4244}, + {0x64a4, 7171}, + {0x64a5, 4932}, + {0x64ab, 4818}, + {0x64ad, 7478}, + {0x64ae, 7261}, + {0x64b0, 7062}, + {0x64b2, 4890}, + {0x64bb, 4212}, + {0x64c1, 6091}, + {0x64c4, 4513}, + {0x64c5, 7153}, + {0x64c7, 7445}, + {0x64ca, 3630}, + {0x64cd, 6790}, + {0x64ce, 3674}, + {0x64d2, 4040}, + {0x64d4, 4220}, + {0x64d8, 5023}, + {0x64da, 3591}, + {0x64e1, 4259}, + {0x64e2, 7399}, + {0x64e5, 4400}, + {0x64e6, 7079}, + {0x64e7, 3592}, + {0x64ec, 6400}, + {0x64f2, 7140}, + {0x64f4, 7877}, + {0x64fa, 7479}, + {0x64fe, 6151}, + {0x6500, 4911}, + {0x6504, 7448}, + {0x6518, 5884}, + {0x651d, 5471}, + {0x6523, 4467}, + {0x652a, 3875}, + {0x652b, 7878}, + {0x652c, 4401}, + {0x652f, 6951}, + {0x6536, 5583}, + {0x6537, 3739}, + {0x6538, 6325}, + {0x6539, 3568}, + {0x653b, 3796}, + {0x653e, 4949}, + {0x653f, 6718}, + {0x6545, 3740}, + {0x6548, 7956}, + {0x654d, 5382}, + {0x654e, 3876}, + {0x654f, 4874}, + {0x6551, 3912}, + {0x6556, 6064}, + {0x6557, 7505}, + {0x655e, 7100}, + {0x6562, 3517}, + {0x6563, 5306}, + {0x6566, 4321}, + {0x656c, 3675}, + {0x656d, 5885}, + {0x6572, 3741}, + {0x6574, 6719}, + {0x6575, 6624}, + {0x6577, 5125}, + {0x6578, 5584}, + {0x657e, 5425}, + {0x6582, 4484}, + {0x6583, 7539}, + {0x6585, 7957}, + {0x6587, 4840}, + {0x658c, 5226}, + {0x6590, 5193}, + {0x6591, 4912}, + {0x6597, 4349}, + {0x6599, 4555}, + {0x659b, 3768}, + {0x659c, 5266}, + {0x659f, 7030}, + {0x65a1, 5817}, + {0x65a4, 4027}, + {0x65a5, 7141}, + {0x65a7, 5126}, + {0x65ab, 6512}, + {0x65ac, 7088}, + {0x65af, 5267}, + {0x65b0, 5742}, + {0x65b7, 4199}, + {0x65b9, 4950}, + {0x65bc, 5904}, + {0x65bd, 5703}, + {0x65c1, 4951}, + {0x65c5, 4447}, + {0x65cb, 5426}, + {0x65cc, 6720}, + {0x65cf, 6828}, + {0x65d2, 4578}, + {0x65d7, 4081}, + {0x65e0, 4819}, + {0x65e3, 4082}, + {0x65e5, 6464}, + {0x65e6, 4200}, + {0x65e8, 6952}, + {0x65e9, 6791}, + {0x65ec, 5644}, + {0x65ed, 6231}, + {0x65f1, 7638}, + {0x65f4, 6209}, + {0x65fa, 6127}, + {0x65fb, 4875}, + {0x65fc, 4876}, + {0x65fd, 4322}, + {0x65ff, 6065}, + {0x6606, 3777}, + {0x6607, 5688}, + {0x6609, 4952}, + {0x660a, 7810}, + {0x660c, 7101}, + {0x660e, 4751}, + {0x660f, 7845}, + {0x6610, 5161}, + {0x6611, 4041}, + {0x6613, 5950}, + {0x6614, 5407}, + {0x6615, 8019}, + {0x661e, 5046}, + {0x661f, 5480}, + {0x6620, 6005}, + {0x6625, 7300}, + {0x6627, 4712}, + {0x6628, 6513}, + {0x662d, 5510}, + {0x662f, 5704}, + {0x6630, 7621}, + {0x6631, 6232}, + {0x6634, 4805}, + {0x6636, 7102}, + {0x663a, 5047}, + {0x663b, 5836}, + {0x6641, 6792}, + {0x6642, 5705}, + {0x6643, 7911}, + {0x6644, 7912}, + {0x6649, 6985}, + {0x664b, 6986}, + {0x664f, 5810}, + {0x6659, 6908}, + {0x665b, 7738}, + {0x665d, 6873}, + {0x665e, 8046}, + {0x665f, 5481}, + {0x6664, 6066}, + {0x6665, 7890}, + {0x6666, 7935}, + {0x6667, 7811}, + {0x6668, 5743}, + {0x6669, 4677}, + {0x666b, 7400}, + {0x666e, 5062}, + {0x666f, 3676}, + {0x6673, 5408}, + {0x6674, 7198}, + {0x6676, 6721}, + {0x6677, 3990}, + {0x6678, 6722}, + {0x667a, 6953}, + {0x6684, 7991}, + {0x6687, 3447}, + {0x6688, 7988}, + {0x6689, 8000}, + {0x668e, 6006}, + {0x6690, 6293}, + {0x6691, 5383}, + {0x6696, 4140}, + {0x6697, 5825}, + {0x6698, 5886}, + {0x669d, 4752}, + {0x66a0, 3742}, + {0x66a2, 7103}, + {0x66ab, 6528}, + {0x66ae, 4772}, + {0x66b2, 6546}, + {0x66b3, 7795}, + {0x66b4, 7572}, + {0x66b9, 5464}, + {0x66bb, 3677}, + {0x66be, 4323}, + {0x66c4, 5999}, + {0x66c6, 4459}, + {0x66c7, 4221}, + {0x66c9, 7958}, + {0x66d6, 5845}, + {0x66d9, 5384}, + {0x66dc, 6152}, + {0x66dd, 7573}, + {0x66e0, 3844}, + {0x66e6, 8047}, + {0x66f0, 6125}, + {0x66f2, 3769}, + {0x66f3, 6033}, + {0x66f4, 3678}, + {0x66f7, 3502}, + {0x66f8, 5385}, + {0x66f9, 6794}, + {0x66fa, 6793}, + {0x66fc, 4678}, + {0x66fe, 6933}, + {0x66ff, 7206}, + {0x6700, 7264}, + {0x6703, 7936}, + {0x6708, 6281}, + {0x6709, 6326}, + {0x670b, 5176}, + {0x670d, 5080}, + {0x6714, 5302}, + {0x6715, 7031}, + {0x6717, 4413}, + {0x671b, 4700}, + {0x671d, 6795}, + {0x671e, 4083}, + {0x671f, 4084}, + {0x6726, 4798}, + {0x6727, 4538}, + {0x6728, 4788}, + {0x672a, 4857}, + {0x672b, 4691}, + {0x672c, 5091}, + {0x672d, 7080}, + {0x672e, 7304}, + {0x6731, 6874}, + {0x6734, 4891}, + {0x6736, 7388}, + {0x673a, 3984}, + {0x673d, 7975}, + {0x6746, 3485}, + {0x6749, 5321}, + {0x674e, 4620}, + {0x674f, 7707}, + {0x6750, 6575}, + {0x6751, 7249}, + {0x6753, 7580}, + {0x6756, 6547}, + {0x675c, 4350}, + {0x675e, 4085}, + {0x675f, 5539}, + {0x676d, 7677}, + {0x676f, 4975}, + {0x6770, 3615}, + {0x6771, 4337}, + {0x6773, 4806}, + {0x6775, 6598}, + {0x6777, 7480}, + {0x677b, 4183}, + {0x677e, 5555}, + {0x677f, 7492}, + {0x6787, 5194}, + {0x6789, 6128}, + {0x678b, 4953}, + {0x678f, 4146}, + {0x6790, 5409}, + {0x6793, 4351}, + {0x6795, 7369}, + {0x6797, 4647}, + {0x679a, 4713}, + {0x679c, 3805}, + {0x679d, 6954}, + {0x67af, 3743}, + {0x67b0, 7531}, + {0x67b3, 6955}, + {0x67b6, 3448}, + {0x67b7, 3449}, + {0x67b8, 3913}, + {0x67be, 5706}, + {0x67c4, 5048}, + {0x67cf, 4991}, + {0x67d0, 4773}, + {0x67d1, 3518}, + {0x67d2, 7365}, + {0x67d3, 5990}, + {0x67d4, 6327}, + {0x67da, 6328}, + {0x67dd, 7401}, + {0x67e9, 3914}, + {0x67ec, 3486}, + {0x67ef, 3450}, + {0x67f0, 4157}, + {0x67f1, 6875}, + {0x67f3, 4579}, + {0x67f4, 5707}, + {0x67f5, 7127}, + {0x67f6, 5268}, + {0x67fb, 5269}, + {0x67fe, 6723}, + {0x6812, 5645}, + {0x6813, 6658}, + {0x6816, 5386}, + {0x6817, 4602}, + {0x6821, 3877}, + {0x6822, 4992}, + {0x682a, 6876}, + {0x682f, 6233}, + {0x6838, 7704}, + {0x6839, 4028}, + {0x683c, 3631}, + {0x683d, 6576}, + {0x6840, 3616}, + {0x6841, 7678}, + {0x6842, 3713}, + {0x6843, 4285}, + {0x6848, 5811}, + {0x684e, 7020}, + {0x6850, 4338}, + {0x6851, 5346}, + {0x6853, 7891}, + {0x6854, 4130}, + {0x686d, 6987}, + {0x6876, 7454}, + {0x687f, 3487}, + {0x6881, 4431}, + {0x6885, 4714}, + {0x688f, 3770}, + {0x6893, 6577}, + {0x6894, 7342}, + {0x6897, 3679}, + {0x689d, 6796}, + {0x689f, 7959}, + {0x68a1, 6110}, + {0x68a2, 7220}, + {0x68a7, 6067}, + {0x68a8, 4621}, + {0x68ad, 5270}, + {0x68af, 6767}, + {0x68b0, 3714}, + {0x68b1, 3778}, + {0x68b3, 5511}, + {0x68b5, 5011}, + {0x68b6, 4858}, + {0x68c4, 4087}, + {0x68c5, 5049}, + {0x68c9, 4738}, + {0x68cb, 4086}, + {0x68cd, 3779}, + {0x68d2, 5099}, + {0x68d5, 6842}, + {0x68d7, 6797}, + {0x68d8, 4020}, + {0x68da, 5177}, + {0x68df, 4339}, + {0x68e0, 4245}, + {0x68e7, 6523}, + {0x68e8, 3715}, + {0x68ee, 5322}, + {0x68f2, 5387}, + {0x68f9, 4286}, + {0x68fa, 3823}, + {0x6900, 6111}, + {0x6905, 6401}, + {0x690d, 5725}, + {0x690e, 7268}, + {0x6912, 7221}, + {0x6927, 4753}, + {0x6930, 5868}, + {0x693d, 5964}, + {0x693f, 7301}, + {0x694a, 5887}, + {0x6953, 7592}, + {0x6954, 5452}, + {0x6955, 7389}, + {0x6957, 3607}, + {0x6959, 4820}, + {0x695a, 7222}, + {0x695e, 4608}, + {0x6960, 4147}, + {0x6961, 6329}, + {0x6962, 6330}, + {0x6963, 4859}, + {0x6968, 6724}, + {0x696b, 6928}, + {0x696d, 5932}, + {0x696e, 6599}, + {0x696f, 5646}, + {0x6975, 4021}, + {0x6977, 7693}, + {0x6978, 7269}, + {0x6979, 6007}, + {0x6995, 6183}, + {0x699b, 6988}, + {0x699c, 4954}, + {0x69a5, 7913}, + {0x69a7, 5195}, + {0x69ae, 6008}, + {0x69b4, 4580}, + {0x69bb, 7426}, + {0x69c1, 3744}, + {0x69c3, 4913}, + {0x69cb, 3915}, + {0x69cc, 7460}, + {0x69cd, 7104}, + {0x69d0, 3862}, + {0x69e8, 3816}, + {0x69ea, 3569}, + {0x69fb, 3998}, + {0x69fd, 6798}, + {0x69ff, 4029}, + {0x6a02, 5800}, + {0x6a0a, 4997}, + {0x6a11, 4432}, + {0x6a13, 4567}, + {0x6a17, 6600}, + {0x6a19, 7581}, + {0x6a1e, 7270}, + {0x6a1f, 6548}, + {0x6a21, 4774}, + {0x6a23, 5888}, + {0x6a35, 7223}, + {0x6a38, 4892}, + {0x6a39, 5585}, + {0x6a3a, 7866}, + {0x6a3d, 6909}, + {0x6a44, 3519}, + {0x6a48, 6153}, + {0x6a4b, 3878}, + {0x6a52, 6239}, + {0x6a53, 5647}, + {0x6a58, 4015}, + {0x6a59, 4366}, + {0x6a5f, 4088}, + {0x6a61, 5347}, + {0x6a6b, 7951}, + {0x6a80, 4201}, + {0x6a84, 3632}, + {0x6a89, 6725}, + {0x6a8d, 5915}, + {0x6a8e, 4042}, + {0x6a97, 5024}, + {0x6a9c, 7937}, + {0x6aa2, 3620}, + {0x6aa3, 6549}, + {0x6ab3, 5227}, + {0x6abb, 7656}, + {0x6ac2, 4287}, + {0x6ac3, 3985}, + {0x6ad3, 4514}, + {0x6ada, 4448}, + {0x6adb, 6927}, + {0x6af6, 7724}, + {0x6afb, 5858}, + {0x6b04, 4391}, + {0x6b0a, 3976}, + {0x6b0c, 6550}, + {0x6b12, 4392}, + {0x6b16, 4402}, + {0x6b20, 8027}, + {0x6b21, 7048}, + {0x6b23, 8020}, + {0x6b32, 6169}, + {0x6b3a, 4089}, + {0x6b3d, 8028}, + {0x6b3e, 3824}, + {0x6b46, 8029}, + {0x6b47, 7727}, + {0x6b4c, 3451}, + {0x6b4e, 7413}, + {0x6b50, 3916}, + {0x6b5f, 5937}, + {0x6b61, 7889}, + {0x6b62, 6956}, + {0x6b63, 6726}, + {0x6b64, 7049}, + {0x6b65, 5063}, + {0x6b66, 4821}, + {0x6b6a, 6133}, + {0x6b72, 5494}, + {0x6b77, 4460}, + {0x6b78, 3991}, + {0x6b7b, 5271}, + {0x6b7f, 4795}, + {0x6b83, 5837}, + {0x6b84, 6989}, + {0x6b86, 7436}, + {0x6b89, 5648}, + {0x6b8a, 5586}, + {0x6b96, 5726}, + {0x6b98, 6524}, + {0x6b9e, 6240}, + {0x6bae, 4485}, + {0x6baf, 5228}, + {0x6bb2, 5465}, + {0x6bb5, 4202}, + {0x6bb7, 6376}, + {0x6bba, 5317}, + {0x6bbc, 3470}, + {0x6bbf, 6659}, + {0x6bc1, 7996}, + {0x6bc5, 6402}, + {0x6bc6, 3917}, + {0x6bcb, 4822}, + {0x6bcd, 4775}, + {0x6bcf, 4715}, + {0x6bd2, 4309}, + {0x6bd3, 6356}, + {0x6bd4, 5196}, + {0x6bd6, 5197}, + {0x6bd7, 5198}, + {0x6bd8, 5199}, + {0x6bdb, 4776}, + {0x6beb, 7812}, + {0x6bec, 3918}, + {0x6c08, 6660}, + {0x6c0f, 5774}, + {0x6c11, 4877}, + {0x6c13, 4728}, + {0x6c23, 4090}, + {0x6c34, 5587}, + {0x6c37, 5238}, + {0x6c38, 6009}, + {0x6c3e, 5012}, + {0x6c40, 6727}, + {0x6c41, 6929}, + {0x6c42, 3919}, + {0x6c4e, 5013}, + {0x6c50, 5410}, + {0x6c55, 5307}, + {0x6c57, 7639}, + {0x6c5a, 6068}, + {0x6c5d, 5938}, + {0x6c5e, 7855}, + {0x6c5f, 3545}, + {0x6c60, 6957}, + {0x6c68, 3784}, + {0x6c6a, 6129}, + {0x6c6d, 6034}, + {0x6c70, 7437}, + {0x6c72, 4055}, + {0x6c76, 4841}, + {0x6c7a, 3649}, + {0x6c7d, 4091}, + {0x6c7e, 5162}, + {0x6c81, 5765}, + {0x6c82, 4092}, + {0x6c83, 6079}, + {0x6c85, 6267}, + {0x6c86, 7679}, + {0x6c87, 5965}, + {0x6c88, 7370}, + {0x6c8c, 4324}, + {0x6c90, 4789}, + {0x6c92, 4796}, + {0x6c93, 4234}, + {0x6c94, 4739}, + {0x6c95, 4849}, + {0x6c96, 7308}, + {0x6c99, 5272}, + {0x6c9a, 6958}, + {0x6c9b, 7506}, + {0x6cab, 4692}, + {0x6cae, 6601}, + {0x6cb3, 7622}, + {0x6cb8, 5200}, + {0x6cb9, 6331}, + {0x6cbb, 7343}, + {0x6cbc, 5512}, + {0x6cbd, 3745}, + {0x6cbe, 7179}, + {0x6cbf, 5966}, + {0x6cc1, 7914}, + {0x6cc2, 7776}, + {0x6cc4, 5453}, + {0x6cc9, 7154}, + {0x6cca, 4893}, + {0x6ccc, 7607}, + {0x6cd3, 7856}, + {0x6cd5, 5018}, + {0x6cd7, 5273}, + {0x6cdb, 5014}, + {0x6ce1, 7556}, + {0x6ce2, 7481}, + {0x6ce3, 6388}, + {0x6ce5, 4187}, + {0x6ce8, 6877}, + {0x6ceb, 7739}, + {0x6cee, 4914}, + {0x6cef, 4878}, + {0x6cf0, 7438}, + {0x6cf3, 6010}, + {0x6d0b, 5889}, + {0x6d0c, 4480}, + {0x6d11, 5064}, + {0x6d17, 5495}, + {0x6d19, 5588}, + {0x6d1b, 4382}, + {0x6d1e, 4340}, + {0x6d25, 6990}, + {0x6d27, 6332}, + {0x6d29, 5454}, + {0x6d2a, 7857}, + {0x6d32, 6878}, + {0x6d35, 5649}, + {0x6d36, 8016}, + {0x6d38, 3845}, + {0x6d39, 6268}, + {0x6d3b, 7899}, + {0x6d3d, 8032}, + {0x6d3e, 7482}, + {0x6d41, 4581}, + {0x6d59, 6687}, + {0x6d5a, 6910}, + {0x6d5c, 5229}, + {0x6d63, 6112}, + {0x6d66, 7557}, + {0x6d69, 7813}, + {0x6d6a, 4414}, + {0x6d6c, 4622}, + {0x6d6e, 5127}, + {0x6d74, 6170}, + {0x6d77, 7694}, + {0x6d78, 7371}, + {0x6d79, 7764}, + {0x6d7f, 7507}, + {0x6d85, 5986}, + {0x6d87, 3680}, + {0x6d88, 5513}, + {0x6d89, 5472}, + {0x6d8c, 6184}, + {0x6d8d, 7960}, + {0x6d8e, 5967}, + {0x6d91, 5540}, + {0x6d93, 5968}, + {0x6d95, 7207}, + {0x6daf, 5846}, + {0x6db2, 5854}, + {0x6db5, 7657}, + {0x6dc0, 6728}, + {0x6dc3, 3977}, + {0x6dc4, 7344}, + {0x6dc5, 5411}, + {0x6dc6, 7961}, + {0x6dc7, 4093}, + {0x6dcb, 4648}, + {0x6dcf, 7814}, + {0x6dd1, 5633}, + {0x6dd8, 4288}, + {0x6dd9, 6843}, + {0x6dda, 4568}, + {0x6dde, 5556}, + {0x6de1, 4222}, + {0x6de8, 6729}, + {0x6dea, 4597}, + {0x6deb, 6382}, + {0x6dee, 7938}, + {0x6df1, 5766}, + {0x6df3, 5650}, + {0x6df5, 5969}, + {0x6df7, 7846}, + {0x6df8, 7199}, + {0x6df9, 5930}, + {0x6dfa, 7155}, + {0x6dfb, 7180}, + {0x6e17, 5323}, + {0x6e19, 7892}, + {0x6e1a, 6602}, + {0x6e1b, 3520}, + {0x6e1f, 6730}, + {0x6e20, 3593}, + {0x6e21, 4289}, + {0x6e23, 5274}, + {0x6e24, 4933}, + {0x6e25, 5801}, + {0x6e26, 6099}, + {0x6e2b, 5455}, + {0x6e2c, 7334}, + {0x6e2d, 6294}, + {0x6e2f, 7680}, + {0x6e32, 5427}, + {0x6e34, 3503}, + {0x6e36, 6011}, + {0x6e38, 6333}, + {0x6e3a, 4807}, + {0x6e3c, 4860}, + {0x6e3d, 6578}, + {0x6e3e, 7847}, + {0x6e43, 4976}, + {0x6e44, 4861}, + {0x6e4a, 6879}, + {0x6e4d, 4203}, + {0x6e56, 7815}, + {0x6e58, 5348}, + {0x6e5b, 4223}, + {0x6e5c, 5727}, + {0x6e5e, 6731}, + {0x6e5f, 7915}, + {0x6e67, 6185}, + {0x6e6b, 7271}, + {0x6e6e, 6453}, + {0x6e6f, 7429}, + {0x6e72, 6269}, + {0x6e73, 4148}, + {0x6e7a, 5065}, + {0x6e90, 6270}, + {0x6e96, 6911}, + {0x6e9c, 4582}, + {0x6e9d, 3920}, + {0x6e9f, 4754}, + {0x6ea2, 6465}, + {0x6ea5, 5128}, + {0x6eaa, 3716}, + {0x6eab, 6083}, + {0x6eaf, 5514}, + {0x6eb1, 6991}, + {0x6eb6, 6186}, + {0x6eba, 4189}, + {0x6ec2, 4955}, + {0x6ec4, 7105}, + {0x6ec5, 4746}, + {0x6ec9, 7916}, + {0x6ecb, 6493}, + {0x6ecc, 7142}, + {0x6ece, 7777}, + {0x6ed1, 7900}, + {0x6ed3, 6579}, + {0x6ed4, 4290}, + {0x6eef, 7208}, + {0x6ef4, 6625}, + {0x6ef8, 7816}, + {0x6efe, 3780}, + {0x6eff, 4679}, + {0x6f01, 5905}, + {0x6f02, 7582}, + {0x6f06, 7366}, + {0x6f0f, 4569}, + {0x6f11, 3570}, + {0x6f14, 5970}, + {0x6f15, 6799}, + {0x6f20, 4666}, + {0x6f22, 7640}, + {0x6f23, 4468}, + {0x6f2b, 4680}, + {0x6f2c, 6959}, + {0x6f31, 5589}, + {0x6f32, 7106}, + {0x6f38, 6695}, + {0x6f3f, 6551}, + {0x6f41, 6012}, + {0x6f51, 4934}, + {0x6f54, 3650}, + {0x6f57, 7033}, + {0x6f58, 4915}, + {0x6f5a, 5634}, + {0x6f5b, 6529}, + {0x6f5e, 4515}, + {0x6f5f, 5412}, + {0x6f62, 7917}, + {0x6f64, 6362}, + {0x6f6d, 4224}, + {0x6f6e, 6800}, + {0x6f70, 3986}, + {0x6f7a, 6525}, + {0x6f7c, 4341}, + {0x6f7d, 5066}, + {0x6f7e, 4639}, + {0x6f81, 5328}, + {0x6f84, 7040}, + {0x6f88, 7172}, + {0x6f8d, 6880}, + {0x6f8e, 7514}, + {0x6f90, 6241}, + {0x6f94, 7817}, + {0x6f97, 3488}, + {0x6fa3, 7641}, + {0x6fa4, 7446}, + {0x6fa7, 4507}, + {0x6fae, 7939}, + {0x6faf, 7063}, + {0x6fb1, 6661}, + {0x6fb3, 6069}, + {0x6fb9, 4225}, + {0x6fbe, 4213}, + {0x6fc0, 3633}, + {0x6fc1, 7402}, + {0x6fc2, 4486}, + {0x6fc3, 4175}, + {0x6fca, 6035}, + {0x6fd5, 5677}, + {0x6fda, 6013}, + {0x6fdf, 6768}, + {0x6fe0, 7818}, + {0x6fe1, 6334}, + {0x6fe4, 4291}, + {0x6fe9, 7819}, + {0x6feb, 4403}, + {0x6fec, 6912}, + {0x6fef, 7403}, + {0x6ff1, 5230}, + {0x6ffe, 4449}, + {0x7001, 5890}, + {0x7005, 7778}, + {0x7006, 4310}, + {0x7009, 5275}, + {0x700b, 5767}, + {0x700f, 4583}, + {0x7011, 7574}, + {0x7015, 5231}, + {0x7018, 4516}, + {0x701a, 7642}, + {0x701b, 6014}, + {0x701c, 6370}, + {0x701d, 4461}, + {0x701e, 6732}, + {0x701f, 5515}, + {0x7023, 7695}, + {0x7027, 4539}, + {0x7028, 4544}, + {0x702f, 6015}, + {0x7037, 6437}, + {0x703e, 4393}, + {0x704c, 3825}, + {0x7050, 7779}, + {0x7051, 5562}, + {0x7058, 7414}, + {0x705d, 7820}, + {0x7063, 4681}, + {0x706b, 7867}, + {0x7070, 7940}, + {0x7078, 3921}, + {0x707c, 6514}, + {0x707d, 6580}, + {0x7085, 3681}, + {0x708a, 7321}, + {0x708e, 5991}, + {0x7092, 7224}, + {0x7098, 8021}, + {0x7099, 6494}, + {0x709a, 3846}, + {0x70a1, 6733}, + {0x70a4, 5516}, + {0x70ab, 7740}, + {0x70ac, 3594}, + {0x70ad, 7415}, + {0x70af, 7780}, + {0x70b3, 5050}, + {0x70b7, 6881}, + {0x70b8, 6515}, + {0x70b9, 6696}, + {0x70c8, 4481}, + {0x70cb, 8007}, + {0x70cf, 6070}, + {0x70d8, 7858}, + {0x70d9, 4383}, + {0x70dd, 6935}, + {0x70df, 5971}, + {0x70f1, 3682}, + {0x70f9, 7515}, + {0x70fd, 5100}, + {0x7104, 7983}, + {0x7109, 5920}, + {0x710c, 6913}, + {0x7119, 4977}, + {0x711a, 5163}, + {0x711e, 4325}, + {0x7121, 4823}, + {0x7126, 7225}, + {0x7130, 5992}, + {0x7136, 5972}, + {0x7147, 8001}, + {0x7149, 4469}, + {0x714a, 7992}, + {0x714c, 7918}, + {0x714e, 6662}, + {0x7150, 6016}, + {0x7156, 4141}, + {0x7159, 5973}, + {0x715c, 6234}, + {0x715e, 5318}, + {0x7164, 4716}, + {0x7165, 7893}, + {0x7166, 7976}, + {0x7167, 6801}, + {0x7169, 4998}, + {0x716c, 5891}, + {0x716e, 6495}, + {0x717d, 5428}, + {0x7184, 5728}, + {0x7189, 6242}, + {0x718a, 6253}, + {0x718f, 7984}, + {0x7192, 7781}, + {0x7194, 6187}, + {0x7199, 8048}, + {0x719f, 5635}, + {0x71a2, 5101}, + {0x71ac, 6071}, + {0x71b1, 5987}, + {0x71b9, 8049}, + {0x71ba, 8050}, + {0x71be, 7345}, + {0x71c1, 6000}, + {0x71c3, 5974}, + {0x71c8, 4367}, + {0x71c9, 4326}, + {0x71ce, 4556}, + {0x71d0, 4640}, + {0x71d2, 5517}, + {0x71d4, 4999}, + {0x71d5, 5975}, + {0x71df, 6017}, + {0x71e5, 6802}, + {0x71e6, 7064}, + {0x71e7, 5590}, + {0x71ed, 7243}, + {0x71ee, 5473}, + {0x71fb, 7985}, + {0x71fc, 5744}, + {0x71fe, 4292}, + {0x71ff, 6154}, + {0x7200, 7731}, + {0x7206, 7575}, + {0x7210, 4517}, + {0x721b, 4394}, + {0x722a, 6803}, + {0x722c, 7483}, + {0x722d, 6587}, + {0x7230, 6271}, + {0x7232, 6295}, + {0x7235, 6516}, + {0x7236, 5129}, + {0x723a, 5869}, + {0x723b, 7962}, + {0x723d, 5349}, + {0x723e, 6422}, + {0x7240, 5350}, + {0x7246, 6552}, + {0x7247, 7521}, + {0x7248, 7493}, + {0x724c, 7508}, + {0x7252, 7191}, + {0x7258, 4311}, + {0x7259, 5782}, + {0x725b, 6210}, + {0x725d, 5232}, + {0x725f, 4777}, + {0x7261, 4778}, + {0x7262, 4545}, + {0x7267, 4790}, + {0x7269, 4850}, + {0x7272, 5369}, + {0x7279, 7472}, + {0x727d, 3638}, + {0x7280, 5388}, + {0x7281, 4623}, + {0x72a2, 4312}, + {0x72a7, 8051}, + {0x72ac, 3639}, + {0x72af, 5015}, + {0x72c0, 5351}, + {0x72c2, 3847}, + {0x72c4, 6626}, + {0x72ce, 5831}, + {0x72d0, 7821}, + {0x72d7, 3922}, + {0x72d9, 6603}, + {0x72e1, 3879}, + {0x72e9, 5591}, + {0x72f8, 4624}, + {0x72f9, 7765}, + {0x72fc, 4415}, + {0x72fd, 7509}, + {0x730a, 6036}, + {0x7316, 7107}, + {0x731b, 4729}, + {0x731c, 5708}, + {0x731d, 6836}, + {0x7325, 6138}, + {0x7329, 5482}, + {0x732a, 6604}, + {0x732b, 4808}, + {0x7336, 6335}, + {0x7337, 6336}, + {0x733e, 7901}, + {0x733f, 6272}, + {0x7344, 6080}, + {0x7345, 5276}, + {0x7350, 6553}, + {0x7352, 6072}, + {0x7357, 3980}, + {0x7368, 4313}, + {0x736a, 7941}, + {0x7370, 6018}, + {0x7372, 7949}, + {0x7375, 4488}, + {0x7378, 5592}, + {0x737a, 4214}, + {0x737b, 7725}, + {0x7384, 7741}, + {0x7386, 6496}, + {0x7387, 5552}, + {0x7389, 6081}, + {0x738b, 6130}, + {0x738e, 6734}, + {0x7394, 7156}, + {0x7396, 3923}, + {0x7397, 6211}, + {0x7398, 4094}, + {0x739f, 4879}, + {0x73a7, 6363}, + {0x73a9, 6113}, + {0x73ad, 5233}, + {0x73b2, 4495}, + {0x73b3, 4260}, + {0x73b9, 7742}, + {0x73c0, 4894}, + {0x73c2, 3452}, + {0x73c9, 4880}, + {0x73ca, 5308}, + {0x73cc, 7608}, + {0x73cd, 6992}, + {0x73cf, 3471}, + {0x73d6, 3848}, + {0x73d9, 3797}, + {0x73dd, 7977}, + {0x73de, 4384}, + {0x73e0, 6882}, + {0x73e3, 5651}, + {0x73e4, 5067}, + {0x73e5, 6423}, + {0x73e6, 7713}, + {0x73e9, 7782}, + {0x73ea, 3999}, + {0x73ed, 4916}, + {0x73f7, 4824}, + {0x73f9, 5483}, + {0x73fd, 6735}, + {0x73fe, 7743}, + {0x7401, 5429}, + {0x7403, 3924}, + {0x7405, 4416}, + {0x7406, 4625}, + {0x7407, 5593}, + {0x7409, 4584}, + {0x7413, 6114}, + {0x741b, 7372}, + {0x7420, 6663}, + {0x7421, 5636}, + {0x7422, 7404}, + {0x7425, 7822}, + {0x7426, 4095}, + {0x7428, 3781}, + {0x742a, 4096}, + {0x742b, 5102}, + {0x742c, 6115}, + {0x742e, 6844}, + {0x742f, 3826}, + {0x7430, 5993}, + {0x7433, 4649}, + {0x7434, 4043}, + {0x7435, 5201}, + {0x7436, 7484}, + {0x7438, 7405}, + {0x743a, 5019}, + {0x743f, 7848}, + {0x7440, 6212}, + {0x7441, 4779}, + {0x7443, 7302}, + {0x7444, 5430}, + {0x744b, 6296}, + {0x7455, 7623}, + {0x7457, 6273}, + {0x7459, 4173}, + {0x745a, 7823}, + {0x745b, 6019}, + {0x745c, 6337}, + {0x745e, 5389}, + {0x745f, 5674}, + {0x7460, 4585}, + {0x7462, 6188}, + {0x7464, 6155}, + {0x7465, 6084}, + {0x7468, 6993}, + {0x7469, 7783}, + {0x746a, 4657}, + {0x746f, 4417}, + {0x747e, 4030}, + {0x7482, 4097}, + {0x7483, 4626}, + {0x7487, 5431}, + {0x7489, 4470}, + {0x748b, 6554}, + {0x7498, 4641}, + {0x749c, 7919}, + {0x749e, 4895}, + {0x749f, 3683}, + {0x74a1, 6994}, + {0x74a3, 4098}, + {0x74a5, 3684}, + {0x74a7, 5025}, + {0x74a8, 7065}, + {0x74aa, 6804}, + {0x74b0, 7894}, + {0x74b2, 5594}, + {0x74b5, 5939}, + {0x74b9, 5637}, + {0x74bd, 5363}, + {0x74bf, 5432}, + {0x74c6, 7021}, + {0x74ca, 3685}, + {0x74cf, 4540}, + {0x74d4, 6020}, + {0x74d8, 3827}, + {0x74da, 7066}, + {0x74dc, 3806}, + {0x74e0, 7824}, + {0x74e2, 7583}, + {0x74e3, 7494}, + {0x74e6, 6100}, + {0x74ee, 6092}, + {0x74f7, 6497}, + {0x7501, 5051}, + {0x7504, 3640}, + {0x7511, 6936}, + {0x7515, 6093}, + {0x7518, 3521}, + {0x751a, 5768}, + {0x751b, 7181}, + {0x751f, 5370}, + {0x7523, 5309}, + {0x7525, 5371}, + {0x7526, 5518}, + {0x7528, 6189}, + {0x752b, 5068}, + {0x752c, 6190}, + {0x7530, 6664}, + {0x7531, 6338}, + {0x7532, 3532}, + {0x7533, 5745}, + {0x7537, 4149}, + {0x7538, 6665}, + {0x753a, 6736}, + {0x7547, 4011}, + {0x754c, 3717}, + {0x754f, 6139}, + {0x7551, 6666}, + {0x7553, 4235}, + {0x7554, 4917}, + {0x7559, 4586}, + {0x755b, 6995}, + {0x755c, 7289}, + {0x755d, 4825}, + {0x7562, 7609}, + {0x7565, 4426}, + {0x7566, 8008}, + {0x756a, 5000}, + {0x756f, 6914}, + {0x7570, 6424}, + {0x7575, 7868}, + {0x7576, 4246}, + {0x7578, 4099}, + {0x757a, 3546}, + {0x757f, 4100}, + {0x7586, 3547}, + {0x7587, 6883}, + {0x758a, 7192}, + {0x758b, 7610}, + {0x758e, 5520}, + {0x758f, 5519}, + {0x7591, 6403}, + {0x759d, 5310}, + {0x75a5, 3571}, + {0x75ab, 5951}, + {0x75b1, 7558}, + {0x75b2, 7599}, + {0x75b3, 3522}, + {0x75b5, 6498}, + {0x75b8, 4215}, + {0x75b9, 6996}, + {0x75bc, 4342}, + {0x75bd, 6605}, + {0x75be, 7022}, + {0x75c2, 3453}, + {0x75c5, 5052}, + {0x75c7, 6937}, + {0x75cd, 6425}, + {0x75d2, 5892}, + {0x75d4, 7346}, + {0x75d5, 8022}, + {0x75d8, 4352}, + {0x75d9, 3686}, + {0x75db, 7455}, + {0x75e2, 4627}, + {0x75f0, 4226}, + {0x75f2, 4658}, + {0x75f4, 7347}, + {0x75fa, 5202}, + {0x75fc, 3746}, + {0x7600, 5906}, + {0x760d, 5893}, + {0x7619, 5521}, + {0x761f, 6085}, + {0x7620, 7143}, + {0x7621, 7108}, + {0x7622, 4918}, + {0x7624, 4587}, + {0x7626, 5595}, + {0x763b, 4570}, + {0x7642, 4557}, + {0x764c, 5826}, + {0x764e, 3489}, + {0x7652, 6339}, + {0x7656, 5026}, + {0x7661, 7348}, + {0x7664, 6688}, + {0x7669, 4376}, + {0x766c, 5433}, + {0x7670, 6094}, + {0x7672, 6667}, + {0x7678, 3718}, + {0x767b, 4368}, + {0x767c, 4935}, + {0x767d, 4993}, + {0x767e, 4994}, + {0x7684, 6627}, + {0x7686, 3572}, + {0x7687, 7920}, + {0x768e, 3880}, + {0x7690, 3747}, + {0x7693, 7825}, + {0x76ae, 7600}, + {0x76ba, 7272}, + {0x76bf, 4755}, + {0x76c2, 6213}, + {0x76c3, 4978}, + {0x76c6, 5164}, + {0x76c8, 6021}, + {0x76ca, 6438}, + {0x76d2, 7665}, + {0x76d6, 3573}, + {0x76db, 5484}, + {0x76dc, 4293}, + {0x76de, 6526}, + {0x76df, 4731}, + {0x76e1, 6997}, + {0x76e3, 3523}, + {0x76e4, 4919}, + {0x76e7, 4518}, + {0x76ee, 4791}, + {0x76f2, 4730}, + {0x76f4, 6975}, + {0x76f8, 5352}, + {0x76fc, 4920}, + {0x76fe, 5652}, + {0x7701, 5485}, + {0x7704, 4740}, + {0x7708, 7421}, + {0x7709, 4862}, + {0x770b, 3490}, + {0x771e, 6998}, + {0x7720, 4741}, + {0x7729, 7744}, + {0x7737, 3978}, + {0x7738, 4780}, + {0x773a, 6805}, + {0x773c, 5812}, + {0x7740, 7057}, + {0x774d, 7745}, + {0x775b, 6737}, + {0x7761, 5596}, + {0x7763, 4314}, + {0x7766, 4792}, + {0x776b, 7193}, + {0x7779, 4294}, + {0x777e, 3748}, + {0x777f, 6037}, + {0x778b, 6999}, + {0x7791, 4756}, + {0x779e, 4682}, + {0x77a5, 5038}, + {0x77ac, 5653}, + {0x77ad, 4558}, + {0x77b0, 3524}, + {0x77b3, 4343}, + {0x77bb, 7182}, + {0x77bc, 3621}, + {0x77bf, 3925}, + {0x77d7, 7244}, + {0x77db, 4781}, + {0x77dc, 4060}, + {0x77e2, 5709}, + {0x77e3, 6404}, + {0x77e5, 6960}, + {0x77e9, 3926}, + {0x77ed, 4204}, + {0x77ee, 6134}, + {0x77ef, 3881}, + {0x77f3, 5413}, + {0x7802, 5277}, + {0x7812, 5203}, + {0x7825, 6961}, + {0x7826, 7120}, + {0x7827, 7373}, + {0x782c, 4652}, + {0x7832, 7559}, + {0x7834, 7485}, + {0x7845, 4000}, + {0x784f, 5976}, + {0x785d, 7226}, + {0x786b, 4588}, + {0x786c, 3687}, + {0x786f, 5977}, + {0x787c, 5178}, + {0x7881, 4101}, + {0x7887, 6738}, + {0x788c, 4528}, + {0x788d, 5847}, + {0x788e, 5563}, + {0x7891, 5204}, + {0x7897, 6116}, + {0x78a3, 3504}, + {0x78a7, 5027}, + {0x78a9, 5414}, + {0x78ba, 7879}, + {0x78bb, 7880}, + {0x78bc, 4659}, + {0x78c1, 6499}, + {0x78c5, 4956}, + {0x78ca, 4546}, + {0x78cb, 7050}, + {0x78ce, 3719}, + {0x78d0, 4921}, + {0x78e8, 4660}, + {0x78ec, 3688}, + {0x78ef, 4102}, + {0x78f5, 3491}, + {0x78fb, 4922}, + {0x7901, 7227}, + {0x790e, 7228}, + {0x7916, 5940}, + {0x792a, 4450}, + {0x792b, 4462}, + {0x792c, 4923}, + {0x793a, 5710}, + {0x793e, 5278}, + {0x7940, 5279}, + {0x7941, 4103}, + {0x7947, 4104}, + {0x7948, 4105}, + {0x7949, 6962}, + {0x7950, 6214}, + {0x7956, 6806}, + {0x7957, 6963}, + {0x795a, 6807}, + {0x795b, 3595}, + {0x795c, 7826}, + {0x795d, 7290}, + {0x795e, 5746}, + {0x7960, 5280}, + {0x7965, 5353}, + {0x7968, 7584}, + {0x796d, 6769}, + {0x797a, 4106}, + {0x797f, 4529}, + {0x7981, 4044}, + {0x798d, 7869}, + {0x798e, 6739}, + {0x798f, 5081}, + {0x7991, 6215}, + {0x79a6, 5907}, + {0x79a7, 8052}, + {0x79aa, 5434}, + {0x79ae, 4508}, + {0x79b1, 4295}, + {0x79b3, 5894}, + {0x79b9, 6216}, + {0x79bd, 4045}, + {0x79be, 7870}, + {0x79bf, 4315}, + {0x79c0, 5597}, + {0x79c1, 5281}, + {0x79c9, 5053}, + {0x79ca, 4162}, + {0x79cb, 7273}, + {0x79d1, 3807}, + {0x79d2, 7229}, + {0x79d5, 5205}, + {0x79d8, 5206}, + {0x79df, 6808}, + {0x79e4, 7377}, + {0x79e6, 7000}, + {0x79e7, 5838}, + {0x79e9, 7023}, + {0x79fb, 6426}, + {0x7a00, 8053}, + {0x7a05, 5496}, + {0x7a08, 3492}, + {0x7a0b, 6740}, + {0x7a0d, 7230}, + {0x7a14, 6474}, + {0x7a17, 7510}, + {0x7a19, 6976}, + {0x7a1a, 7349}, + {0x7a1c, 4609}, + {0x7a1f, 7591}, + {0x7a20, 6809}, + {0x7a2e, 6845}, + {0x7a31, 7378}, + {0x7a36, 6235}, + {0x7a37, 6977}, + {0x7a3b, 4296}, + {0x7a3c, 3454}, + {0x7a3d, 3720}, + {0x7a3f, 3749}, + {0x7a40, 3771}, + {0x7a46, 4793}, + {0x7a49, 7350}, + {0x7a4d, 6628}, + {0x7a4e, 6022}, + {0x7a57, 5598}, + {0x7a61, 5366}, + {0x7a62, 6038}, + {0x7a69, 6086}, + {0x7a6b, 7881}, + {0x7a70, 5895}, + {0x7a74, 7755}, + {0x7a76, 3927}, + {0x7a79, 3965}, + {0x7a7a, 3798}, + {0x7a7d, 6741}, + {0x7a7f, 7157}, + {0x7a81, 4330}, + {0x7a84, 7058}, + {0x7a88, 6156}, + {0x7a92, 7024}, + {0x7a93, 7109}, + {0x7a95, 6810}, + {0x7a98, 3954}, + {0x7a9f, 3962}, + {0x7aa9, 6101}, + {0x7aaa, 6102}, + {0x7aae, 3966}, + {0x7aaf, 6157}, + {0x7aba, 4001}, + {0x7ac4, 7067}, + {0x7ac5, 4002}, + {0x7ac7, 4353}, + {0x7aca, 6689}, + {0x7acb, 4653}, + {0x7ad7, 4809}, + {0x7ad9, 7089}, + {0x7add, 5054}, + {0x7adf, 3689}, + {0x7ae0, 6555}, + {0x7ae3, 6915}, + {0x7ae5, 4344}, + {0x7aea, 5599}, + {0x7aed, 3505}, + {0x7aef, 4205}, + {0x7af6, 3690}, + {0x7af9, 6900}, + {0x7afa, 7291}, + {0x7aff, 3493}, + {0x7b0f, 7852}, + {0x7b11, 5522}, + {0x7b19, 5372}, + {0x7b1b, 6629}, + {0x7b1e, 7439}, + {0x7b20, 4654}, + {0x7b26, 5130}, + {0x7b2c, 6770}, + {0x7b2d, 4496}, + {0x7b39, 5497}, + {0x7b46, 7611}, + {0x7b49, 4369}, + {0x7b4b, 4031}, + {0x7b4c, 6668}, + {0x7b4d, 5654}, + {0x7b4f, 5006}, + {0x7b50, 3849}, + {0x7b51, 7292}, + {0x7b52, 7456}, + {0x7b54, 4236}, + {0x7b56, 7128}, + {0x7b60, 4012}, + {0x7b6c, 5486}, + {0x7b6e, 5390}, + {0x7b75, 5978}, + {0x7b7d, 6073}, + {0x7b87, 3574}, + {0x7b8b, 6669}, + {0x7b8f, 6588}, + {0x7b94, 4896}, + {0x7b95, 4107}, + {0x7b97, 5311}, + {0x7b9a, 7051}, + {0x7b9d, 3656}, + {0x7ba1, 3828}, + {0x7bad, 6670}, + {0x7bb1, 5354}, + {0x7bb4, 6530}, + {0x7bb8, 6606}, + {0x7bc0, 6690}, + {0x7bc1, 7921}, + {0x7bc4, 5016}, + {0x7bc6, 6671}, + {0x7bc7, 7522}, + {0x7bc9, 7293}, + {0x7bd2, 5729}, + {0x7be0, 5523}, + {0x7be4, 4316}, + {0x7be9, 5282}, + {0x7c07, 6829}, + {0x7c12, 7068}, + {0x7c1e, 4206}, + {0x7c21, 3494}, + {0x7c27, 7922}, + {0x7c2a, 6531}, + {0x7c2b, 5524}, + {0x7c3d, 7183}, + {0x7c3e, 4487}, + {0x7c3f, 5131}, + {0x7c43, 4404}, + {0x7c4c, 6884}, + {0x7c4d, 6630}, + {0x7c60, 4541}, + {0x7c64, 7184}, + {0x7c6c, 4628}, + {0x7c73, 4863}, + {0x7c83, 5207}, + {0x7c89, 5165}, + {0x7c92, 4655}, + {0x7c95, 4897}, + {0x7c97, 6811}, + {0x7c98, 6697}, + {0x7c9f, 5541}, + {0x7ca5, 6901}, + {0x7ca7, 6556}, + {0x7cae, 4433}, + {0x7cb1, 4434}, + {0x7cb2, 7070}, + {0x7cb3, 3582}, + {0x7cb9, 5600}, + {0x7cbe, 6742}, + {0x7cca, 7827}, + {0x7cd6, 4247}, + {0x7cde, 5166}, + {0x7cdf, 6812}, + {0x7ce0, 3548}, + {0x7ce7, 4435}, + {0x7cfb, 3721}, + {0x7cfe, 4003}, + {0x7d00, 4108}, + {0x7d02, 6885}, + {0x7d04, 5873}, + {0x7d05, 7859}, + {0x7d06, 6217}, + {0x7d07, 8025}, + {0x7d08, 7895}, + {0x7d0a, 4842}, + {0x7d0b, 4843}, + {0x7d0d, 4150}, + {0x7d10, 4184}, + {0x7d14, 5655}, + {0x7d17, 5283}, + {0x7d18, 3865}, + {0x7d19, 6964}, + {0x7d1a, 4056}, + {0x7d1b, 5167}, + {0x7d20, 5525}, + {0x7d21, 4957}, + {0x7d22, 5367}, + {0x7d2b, 6500}, + {0x7d2c, 6886}, + {0x7d2e, 7081}, + {0x7d2f, 4571}, + {0x7d30, 5498}, + {0x7d33, 5747}, + {0x7d35, 6607}, + {0x7d39, 5526}, + {0x7d3a, 3525}, + {0x7d42, 6846}, + {0x7d43, 7746}, + {0x7d44, 6813}, + {0x7d45, 3691}, + {0x7d46, 4924}, + {0x7d50, 3651}, + {0x7d5e, 3882}, + {0x7d61, 4385}, + {0x7d62, 7747}, + {0x7d66, 4057}, + {0x7d68, 6371}, + {0x7d6a, 6454}, + {0x7d6e, 5391}, + {0x7d71, 7457}, + {0x7d72, 5284}, + {0x7d73, 3549}, + {0x7d76, 6691}, + {0x7d79, 3641}, + {0x7d7f, 3928}, + {0x7d8e, 6743}, + {0x7d8f, 5601}, + {0x7d93, 3692}, + {0x7d9c, 6847}, + {0x7da0, 4530}, + {0x7da2, 6887}, + {0x7dac, 5602}, + {0x7dad, 6340}, + {0x7db1, 3550}, + {0x7db2, 4701}, + {0x7db4, 7173}, + {0x7db5, 7121}, + {0x7db8, 4598}, + {0x7dba, 4109}, + {0x7dbb, 7416}, + {0x7dbd, 6517}, + {0x7dbe, 4610}, + {0x7dbf, 4742}, + {0x7dc7, 7351}, + {0x7dca, 4126}, + {0x7dcb, 5208}, + {0x7dd6, 5392}, + {0x7dd8, 7658}, + {0x7dda, 5435}, + {0x7ddd, 7034}, + {0x7dde, 4207}, + {0x7de0, 7209}, + {0x7de1, 4881}, + {0x7de3, 5979}, + {0x7de8, 7523}, + {0x7de9, 6117}, + {0x7dec, 4743}, + {0x7def, 6297}, + {0x7df4, 4471}, + {0x7dfb, 7352}, + {0x7e09, 7001}, + {0x7e0a, 5855}, + {0x7e15, 6087}, + {0x7e1b, 4898}, + {0x7e1d, 7002}, + {0x7e1e, 7828}, + {0x7e1f, 6171}, + {0x7e21, 6581}, + {0x7e23, 7748}, + {0x7e2b, 5103}, + {0x7e2e, 7294}, + {0x7e2f, 5980}, + {0x7e31, 6848}, + {0x7e37, 4572}, + {0x7e3d, 7257}, + {0x7e3e, 6631}, + {0x7e41, 5001}, + {0x7e43, 5179}, + {0x7e46, 4826}, + {0x7e47, 6158}, + {0x7e52, 6938}, + {0x7e54, 6978}, + {0x7e55, 5436}, + {0x7e5e, 6159}, + {0x7e61, 5603}, + {0x7e69, 5689}, + {0x7e6a, 7942}, + {0x7e6b, 3722}, + {0x7e6d, 3642}, + {0x7e70, 6814}, + {0x7e79, 5952}, + {0x7e7c, 3723}, + {0x7e82, 7069}, + {0x7e8c, 5542}, + {0x7e8f, 6672}, + {0x7e93, 6023}, + {0x7e96, 5466}, + {0x7e98, 7071}, + {0x7e9b, 4317}, + {0x7e9c, 4405}, + {0x7f36, 5132}, + {0x7f38, 7681}, + {0x7f3a, 3652}, + {0x7f4c, 5859}, + {0x7f50, 3829}, + {0x7f54, 4702}, + {0x7f55, 7643}, + {0x7f6a, 6859}, + {0x7f6b, 3854}, + {0x7f6e, 7353}, + {0x7f70, 5007}, + {0x7f72, 5393}, + {0x7f75, 4717}, + {0x7f77, 7486}, + {0x7f79, 4629}, + {0x7f85, 4377}, + {0x7f88, 4110}, + {0x7f8a, 5896}, + {0x7f8c, 3551}, + {0x7f8e, 4864}, + {0x7f94, 3750}, + {0x7f9a, 4497}, + {0x7f9e, 5604}, + {0x7fa4, 3955}, + {0x7fa8, 5437}, + {0x7fa9, 6405}, + {0x7fb2, 8054}, + {0x7fb8, 4630}, + {0x7fb9, 3583}, + {0x7fbd, 6218}, + {0x7fc1, 6095}, + {0x7fc5, 5711}, + {0x7fca, 6439}, + {0x7fcc, 6440}, + {0x7fce, 4498}, + {0x7fd2, 5679}, + {0x7fd4, 5355}, + {0x7fd5, 8033}, + {0x7fdf, 6632}, + {0x7fe0, 7322}, + {0x7fe1, 5209}, + {0x7fe9, 7524}, + {0x7feb, 6118}, + {0x7ff0, 7644}, + {0x7ff9, 3883}, + {0x7ffc, 6441}, + {0x8000, 6160}, + {0x8001, 4519}, + {0x8003, 3751}, + {0x8005, 6501}, + {0x8006, 4111}, + {0x8009, 3929}, + {0x800c, 6427}, + {0x8010, 4158}, + {0x8015, 3693}, + {0x8017, 4782}, + {0x8018, 6243}, + {0x802d, 4112}, + {0x8033, 6428}, + {0x8036, 5870}, + {0x803d, 7422}, + {0x803f, 3694}, + {0x8043, 4227}, + {0x8046, 4499}, + {0x804a, 4559}, + {0x8056, 5487}, + {0x8058, 5239}, + {0x805a, 7323}, + {0x805e, 4844}, + {0x806f, 4472}, + {0x8070, 7258}, + {0x8072, 5488}, + {0x8073, 6191}, + {0x8077, 6979}, + {0x807d, 7200}, + {0x807e, 4542}, + {0x807f, 6368}, + {0x8084, 6429}, + {0x8085, 5638}, + {0x8086, 5285}, + {0x8087, 6815}, + {0x8089, 6357}, + {0x808b, 4605}, + {0x808c, 4113}, + {0x8096, 7231}, + {0x809b, 7682}, + {0x809d, 3495}, + {0x80a1, 3752}, + {0x80a2, 6965}, + {0x80a5, 5210}, + {0x80a9, 3643}, + {0x80aa, 4958}, + {0x80af, 4061}, + {0x80b1, 3866}, + {0x80b2, 6358}, + {0x80b4, 7963}, + {0x80ba, 7540}, + {0x80c3, 6298}, + {0x80c4, 6865}, + {0x80cc, 4979}, + {0x80ce, 7440}, + {0x80da, 4980}, + {0x80db, 3533}, + {0x80de, 7560}, + {0x80e1, 7829}, + {0x80e4, 6364}, + {0x80e5, 5394}, + {0x80f1, 3850}, + {0x80f4, 4345}, + {0x80f8, 8017}, + {0x80fd, 4185}, + {0x8102, 6966}, + {0x8105, 7766}, + {0x8106, 7324}, + {0x8107, 7767}, + {0x8108, 4722}, + {0x810a, 7144}, + {0x8118, 6119}, + {0x811a, 3472}, + {0x811b, 3695}, + {0x8123, 5656}, + {0x8129, 5605}, + {0x812b, 7419}, + {0x812f, 7561}, + {0x8139, 7110}, + {0x813e, 5211}, + {0x814b, 5856}, + {0x814e, 5748}, + {0x8150, 5133}, + {0x8151, 5134}, + {0x8154, 3552}, + {0x8155, 6120}, + {0x8165, 5489}, + {0x8166, 4179}, + {0x816b, 6849}, + {0x8170, 6161}, + {0x8171, 3608}, + {0x8178, 6557}, + {0x8179, 5082}, + {0x817a, 5438}, + {0x817f, 7461}, + {0x8180, 4959}, + {0x8188, 3634}, + {0x818a, 4899}, + {0x818f, 3753}, + {0x819a, 5135}, + {0x819c, 4667}, + {0x819d, 5675}, + {0x81a0, 3884}, + {0x81a3, 7025}, + {0x81a8, 7516}, + {0x81b3, 5439}, + {0x81b5, 7313}, + {0x81ba, 6392}, + {0x81bd, 4228}, + {0x81be, 7943}, + {0x81bf, 4176}, + {0x81c0, 4359}, + {0x81c2, 5212}, + {0x81c6, 5916}, + {0x81cd, 6771}, + {0x81d8, 4410}, + {0x81df, 6558}, + {0x81e3, 5749}, + {0x81e5, 6103}, + {0x81e7, 6559}, + {0x81e8, 4650}, + {0x81ea, 6502}, + {0x81ed, 7325}, + {0x81f3, 6967}, + {0x81f4, 7354}, + {0x81fa, 4261}, + {0x81fb, 7003}, + {0x81fc, 3930}, + {0x81fe, 6341}, + {0x8205, 3931}, + {0x8207, 5941}, + {0x8208, 8034}, + {0x820a, 3932}, + {0x820c, 5456}, + {0x820d, 5286}, + {0x8212, 5395}, + {0x821b, 7158}, + {0x821c, 5657}, + {0x821e, 4827}, + {0x821f, 6888}, + {0x8221, 3553}, + {0x822a, 7683}, + {0x822b, 4960}, + {0x822c, 4925}, + {0x8235, 7390}, + {0x8236, 4900}, + {0x8237, 7749}, + {0x8239, 5440}, + {0x8240, 5136}, + {0x8245, 5942}, + {0x8247, 6744}, + {0x8259, 7111}, + {0x8264, 6406}, + {0x8266, 7659}, + {0x826e, 3496}, + {0x826f, 4436}, + {0x8271, 3497}, + {0x8272, 5368}, + {0x8276, 5994}, + {0x8278, 7232}, + {0x827e, 5848}, + {0x828b, 6219}, + {0x828d, 6518}, + {0x828e, 3967}, + {0x8292, 4703}, + {0x8299, 5137}, + {0x829a, 4360}, + {0x829d, 6968}, + {0x829f, 5324}, + {0x82a5, 3575}, + {0x82a6, 7830}, + {0x82a9, 4046}, + {0x82ac, 5168}, + {0x82ad, 7487}, + {0x82ae, 6039}, + {0x82af, 5769}, + {0x82b1, 7871}, + {0x82b3, 4961}, + {0x82b7, 6969}, + {0x82b8, 6244}, + {0x82b9, 4032}, + {0x82bb, 7274}, + {0x82bc, 4783}, + {0x82bd, 5783}, + {0x82bf, 6482}, + {0x82d1, 6274}, + {0x82d2, 5995}, + {0x82d4, 7441}, + {0x82d5, 7233}, + {0x82d7, 4810}, + {0x82db, 3455}, + {0x82de, 7562}, + {0x82df, 3933}, + {0x82e1, 6430}, + {0x82e5, 5874}, + {0x82e6, 3754}, + {0x82e7, 6608}, + {0x82f1, 6024}, + {0x82fd, 3755}, + {0x82fe, 7612}, + {0x8301, 6921}, + {0x8302, 4828}, + {0x8303, 5017}, + {0x8304, 3456}, + {0x8305, 4784}, + {0x8309, 4693}, + {0x8317, 4757}, + {0x8328, 6503}, + {0x832b, 4704}, + {0x832f, 5083}, + {0x8331, 5606}, + {0x8334, 7944}, + {0x8335, 6455}, + {0x8336, 4191}, + {0x8338, 6192}, + {0x8339, 5943}, + {0x8340, 5658}, + {0x8347, 7708}, + {0x8349, 7234}, + {0x834a, 7784}, + {0x834f, 6475}, + {0x8351, 6431}, + {0x8352, 7923}, + {0x8373, 4354}, + {0x8377, 7624}, + {0x837b, 6633}, + {0x8389, 4631}, + {0x838a, 6560}, + {0x838e, 5287}, + {0x8396, 3696}, + {0x8398, 5750}, + {0x839e, 6121}, + {0x83a2, 7768}, + {0x83a9, 5138}, + {0x83aa, 5784}, + {0x83ab, 4668}, + {0x83bd, 4705}, + {0x83c1, 7201}, + {0x83c5, 3830}, + {0x83c9, 4531}, + {0x83ca, 3949}, + {0x83cc, 4013}, + {0x83d3, 3808}, + {0x83d6, 7112}, + {0x83dc, 7122}, + {0x83e9, 5069}, + {0x83eb, 4033}, + {0x83ef, 7872}, + {0x83f0, 3756}, + {0x83f1, 4611}, + {0x83f2, 5213}, + {0x83f4, 5827}, + {0x83f9, 6609}, + {0x83fd, 5639}, + {0x8403, 7314}, + {0x8404, 4297}, + {0x840a, 4423}, + {0x840c, 4732}, + {0x840d, 7532}, + {0x840e, 6299}, + {0x8429, 7275}, + {0x842c, 4683}, + {0x8431, 7993}, + {0x8438, 6342}, + {0x843d, 4386}, + {0x8449, 6001}, + {0x8457, 6610}, + {0x845b, 3506}, + {0x8461, 7563}, + {0x8463, 4346}, + {0x8466, 6300}, + {0x846b, 7831}, + {0x846c, 6561}, + {0x846f, 5875}, + {0x8475, 4004}, + {0x847a, 6930}, + {0x8490, 5607}, + {0x8494, 5712}, + {0x8499, 4799}, + {0x849c, 5312}, + {0x84a1, 4962}, + {0x84b2, 7564}, + {0x84b8, 6939}, + {0x84bb, 5876}, + {0x84bc, 7113}, + {0x84bf, 7832}, + {0x84c0, 5549}, + {0x84c2, 4758}, + {0x84c4, 7295}, + {0x84c6, 5415}, + {0x84c9, 6193}, + {0x84cb, 3576}, + {0x84cd, 5713}, + {0x84d1, 5288}, + {0x84da, 5608}, + {0x84ec, 5104}, + {0x84ee, 4473}, + {0x84f4, 5659}, + {0x84fc, 4560}, + {0x8511, 4747}, + {0x8513, 4684}, + {0x8514, 5084}, + {0x8517, 6504}, + {0x8518, 5325}, + {0x851a, 6250}, + {0x851e, 4573}, + {0x8521, 7123}, + {0x8523, 6562}, + {0x8525, 7259}, + {0x852c, 5527}, + {0x852d, 6383}, + {0x852f, 7004}, + {0x853d, 7541}, + {0x853f, 6301}, + {0x8541, 4229}, + {0x8543, 5002}, + {0x8549, 7235}, + {0x854e, 3885}, + {0x8553, 6245}, + {0x8559, 7796}, + {0x8563, 5660}, + {0x8568, 3981}, + {0x8569, 7430}, + {0x856a, 4829}, + {0x856d, 5528}, + {0x8584, 4901}, + {0x8587, 4865}, + {0x858f, 6407}, + {0x8591, 3554}, + {0x8594, 6563}, + {0x859b, 5457}, + {0x85a6, 7159}, + {0x85a8, 7989}, + {0x85a9, 5319}, + {0x85aa, 5751}, + {0x85af, 5396}, + {0x85b0, 7986}, + {0x85ba, 6772}, + {0x85c1, 3757}, + {0x85c9, 6505}, + {0x85cd, 4406}, + {0x85ce, 5752}, + {0x85cf, 6564}, + {0x85d5, 6220}, + {0x85dc, 4451}, + {0x85dd, 6040}, + {0x85e4, 4370}, + {0x85e5, 5877}, + {0x85e9, 5003}, + {0x85ea, 5609}, + {0x85f7, 6611}, + {0x85fa, 4642}, + {0x85fb, 6816}, + {0x85ff, 3817}, + {0x8602, 6041}, + {0x8606, 4520}, + {0x8607, 5529}, + {0x860a, 6088}, + {0x8616, 5924}, + {0x8617, 5028}, + {0x861a, 5441}, + {0x862d, 4395}, + {0x863f, 4378}, + {0x864e, 7833}, + {0x8650, 7632}, + {0x8654, 3609}, + {0x8655, 7133}, + {0x865b, 7721}, + {0x865c, 4521}, + {0x865e, 6221}, + {0x865f, 7834}, + {0x8667, 8009}, + {0x8679, 7860}, + {0x868a, 4845}, + {0x868c, 4963}, + {0x8693, 6456}, + {0x86a3, 3799}, + {0x86a4, 6817}, + {0x86a9, 7355}, + {0x86c7, 5289}, + {0x86cb, 4208}, + {0x86d4, 7945}, + {0x86d9, 6104}, + {0x86db, 6889}, + {0x86df, 3886}, + {0x86e4, 7666}, + {0x86ed, 7026}, + {0x86fe, 5785}, + {0x8700, 7245}, + {0x8702, 5105}, + {0x8703, 5753}, + {0x8708, 6074}, + {0x8718, 6970}, + {0x871a, 5214}, + {0x871c, 4884}, + {0x874e, 3508}, + {0x8755, 5730}, + {0x8757, 7924}, + {0x875f, 6302}, + {0x8766, 7625}, + {0x8768, 5676}, + {0x8774, 7835}, + {0x8776, 6703}, + {0x8778, 6105}, + {0x8782, 4418}, + {0x878d, 6372}, + {0x879f, 4759}, + {0x87a2, 7785}, + {0x87b3, 4248}, + {0x87ba, 4379}, + {0x87c4, 7376}, + {0x87e0, 4926}, + {0x87ec, 5442}, + {0x87ef, 6162}, + {0x87f2, 7309}, + {0x87f9, 7696}, + {0x87fb, 6408}, + {0x87fe, 5467}, + {0x8805, 5690}, + {0x881f, 4411}, + {0x8822, 6916}, + {0x8823, 4452}, + {0x8831, 3758}, + {0x8836, 6532}, + {0x883b, 4685}, + {0x8840, 7756}, + {0x8846, 6924}, + {0x884c, 7709}, + {0x884d, 5981}, + {0x8852, 7750}, + {0x8853, 5668}, + {0x8857, 3457}, + {0x8859, 5786}, + {0x885b, 6303}, + {0x885d, 7310}, + {0x8861, 7786}, + {0x8862, 3934}, + {0x8863, 6409}, + {0x8868, 7585}, + {0x886b, 5326}, + {0x8870, 5565}, + {0x8872, 4151}, + {0x8877, 7311}, + {0x887e, 4047}, + {0x887f, 4048}, + {0x8881, 6275}, + {0x8882, 4763}, + {0x8888, 3458}, + {0x888b, 4262}, + {0x888d, 7565}, + {0x8892, 4209}, + {0x8896, 5610}, + {0x8897, 7005}, + {0x889e, 3782}, + {0x88ab, 7601}, + {0x88b4, 3759}, + {0x88c1, 6582}, + {0x88c2, 4482}, + {0x88cf, 4632}, + {0x88d4, 6042}, + {0x88d5, 6343}, + {0x88d9, 3956}, + {0x88dc, 5070}, + {0x88dd, 6565}, + {0x88df, 5290}, + {0x88e1, 4633}, + {0x88e8, 5215}, + {0x88f3, 5356}, + {0x88f4, 4981}, + {0x88f5, 4982}, + {0x88f8, 4380}, + {0x88fd, 6773}, + {0x8907, 5085}, + {0x8910, 3507}, + {0x8912, 7566}, + {0x8913, 5071}, + {0x8918, 6304}, + {0x8919, 4983}, + {0x8925, 6172}, + {0x892a, 7462}, + {0x8936, 5680}, + {0x8938, 4574}, + {0x893b, 5458}, + {0x8941, 3555}, + {0x8944, 5897}, + {0x895f, 4049}, + {0x8964, 4407}, + {0x896a, 4694}, + {0x8972, 5681}, + {0x897f, 5397}, + {0x8981, 6163}, + {0x8983, 4230}, + {0x8986, 5086}, + {0x8987, 7511}, + {0x898b, 3644}, + {0x898f, 4005}, + {0x8993, 4734}, + {0x8996, 5714}, + {0x89a1, 3635}, + {0x89a9, 4298}, + {0x89aa, 7363}, + {0x89b2, 4034}, + {0x89ba, 3473}, + {0x89bd, 4408}, + {0x89c0, 3831}, + {0x89d2, 3474}, + {0x89e3, 7697}, + {0x89f4, 5357}, + {0x89f8, 7246}, + {0x8a00, 5921}, + {0x8a02, 6745}, + {0x8a03, 5139}, + {0x8a08, 3724}, + {0x8a0a, 5754}, + {0x8a0c, 7861}, + {0x8a0e, 7452}, + {0x8a13, 7987}, + {0x8a16, 8026}, + {0x8a17, 7406}, + {0x8a18, 4114}, + {0x8a1b, 6106}, + {0x8a1d, 5787}, + {0x8a1f, 5557}, + {0x8a23, 3653}, + {0x8a25, 4182}, + {0x8a2a, 4964}, + {0x8a2d, 5459}, + {0x8a31, 7722}, + {0x8a34, 5530}, + {0x8a36, 3459}, + {0x8a3a, 7006}, + {0x8a3b, 6890}, + {0x8a50, 5291}, + {0x8a54, 6818}, + {0x8a55, 7533}, + {0x8a5b, 6612}, + {0x8a5e, 5292}, + {0x8a60, 6025}, + {0x8a62, 5661}, + {0x8a63, 6043}, + {0x8a66, 5715}, + {0x8a69, 5716}, + {0x8a6d, 3987}, + {0x8a6e, 6673}, + {0x8a70, 8055}, + {0x8a71, 7873}, + {0x8a72, 7698}, + {0x8a73, 5358}, + {0x8a75, 5443}, + {0x8a79, 7185}, + {0x8a85, 6891}, + {0x8a87, 3809}, + {0x8a8c, 6971}, + {0x8a8d, 6457}, + {0x8a93, 5398}, + {0x8a95, 7417}, + {0x8a98, 6344}, + {0x8a9e, 5908}, + {0x8aa0, 5490}, + {0x8aa1, 3725}, + {0x8aa3, 4830}, + {0x8aa4, 6075}, + {0x8aa5, 3760}, + {0x8aa6, 5558}, + {0x8aa8, 7946}, + {0x8aaa, 5460}, + {0x8ab0, 5611}, + {0x8ab2, 3810}, + {0x8ab9, 5216}, + {0x8abc, 6410}, + {0x8abe, 6377}, + {0x8abf, 6819}, + {0x8ac2, 7186}, + {0x8ac4, 5662}, + {0x8ac7, 4231}, + {0x8acb, 7202}, + {0x8acd, 6589}, + {0x8acf, 7276}, + {0x8ad2, 4437}, + {0x8ad6, 4535}, + {0x8adb, 6345}, + {0x8adc, 7194}, + {0x8ae1, 5717}, + {0x8ae6, 7210}, + {0x8ae7, 7699}, + {0x8aea, 6746}, + {0x8aeb, 3498}, + {0x8aed, 6346}, + {0x8aee, 6506}, + {0x8af1, 8002}, + {0x8af6, 5770}, + {0x8af7, 7593}, + {0x8af8, 6774}, + {0x8afa, 5922}, + {0x8afe, 4139}, + {0x8b00, 4785}, + {0x8b01, 5818}, + {0x8b02, 6305}, + {0x8b04, 4371}, + {0x8b0e, 4866}, + {0x8b10, 4885}, + {0x8b14, 7633}, + {0x8b16, 5543}, + {0x8b17, 4965}, + {0x8b19, 3657}, + {0x8b1a, 6442}, + {0x8b1b, 3556}, + {0x8b1d, 5293}, + {0x8b20, 6164}, + {0x8b28, 4786}, + {0x8b2b, 6634}, + {0x8b2c, 4589}, + {0x8b33, 3935}, + {0x8b39, 4035}, + {0x8b41, 7874}, + {0x8b49, 6940}, + {0x8b4e, 8011}, + {0x8b4f, 4115}, + {0x8b58, 5731}, + {0x8b5a, 4232}, + {0x8b5c, 5072}, + {0x8b66, 3697}, + {0x8b6c, 5217}, + {0x8b6f, 5953}, + {0x8b70, 6411}, + {0x8b74, 3645}, + {0x8b77, 7836}, + {0x8b7d, 6044}, + {0x8b80, 4318}, + {0x8b8a, 5033}, + {0x8b90, 5612}, + {0x8b92, 7090}, + {0x8b93, 5898}, + {0x8b96, 7091}, + {0x8b9a, 7072}, + {0x8c37, 3772}, + {0x8c3f, 3726}, + {0x8c41, 7902}, + {0x8c46, 4355}, + {0x8c48, 4116}, + {0x8c4a, 7594}, + {0x8c4c, 6122}, + {0x8c55, 5718}, + {0x8c5a, 4327}, + {0x8c61, 5359}, + {0x8c6a, 7837}, + {0x8c6b, 6045}, + {0x8c79, 7586}, + {0x8c7a, 5719}, + {0x8c82, 7236}, + {0x8c8a, 4723}, + {0x8c8c, 4787}, + {0x8c9d, 7512}, + {0x8c9e, 6747}, + {0x8ca0, 5140}, + {0x8ca1, 6583}, + {0x8ca2, 3800}, + {0x8ca7, 5234}, + {0x8ca8, 7875}, + {0x8ca9, 7495}, + {0x8caa, 7423}, + {0x8cab, 3832}, + {0x8cac, 7129}, + {0x8caf, 6613}, + {0x8cb0, 5499}, + {0x8cb3, 6433}, + {0x8cb4, 3992}, + {0x8cb6, 7528}, + {0x8cb7, 4718}, + {0x8cb8, 4263}, + {0x8cbb, 5218}, + {0x8cbc, 7195}, + {0x8cbd, 6432}, + {0x8cbf, 4831}, + {0x8cc0, 7626}, + {0x8cc1, 5169}, + {0x8cc2, 4547}, + {0x8cc3, 6476}, + {0x8cc4, 7947}, + {0x8cc7, 6507}, + {0x8cc8, 3460}, + {0x8cca, 6635}, + {0x8cd1, 7007}, + {0x8cd3, 5235}, + {0x8cda, 4548}, + {0x8cdc, 5294}, + {0x8cde, 5360}, + {0x8ce0, 4984}, + {0x8ce2, 7751}, + {0x8ce3, 4719}, + {0x8ce4, 7160}, + {0x8ce6, 5141}, + {0x8cea, 7027}, + {0x8ced, 4299}, + {0x8cf4, 4549}, + {0x8cfb, 5142}, + {0x8cfc, 3936}, + {0x8cfd, 5364}, + {0x8d04, 6972}, + {0x8d05, 7315}, + {0x8d07, 6365}, + {0x8d08, 6941}, + {0x8d0a, 7073}, + {0x8d0d, 5468}, + {0x8d13, 6566}, + {0x8d16, 5544}, + {0x8d64, 6636}, + {0x8d66, 5295}, + {0x8d6b, 7732}, + {0x8d70, 6892}, + {0x8d73, 4006}, + {0x8d74, 5143}, + {0x8d77, 4117}, + {0x8d85, 7237}, + {0x8d8a, 6282}, + {0x8d99, 6820}, + {0x8da3, 7326}, + {0x8da8, 7277}, + {0x8db3, 6830}, + {0x8dba, 5144}, + {0x8dbe, 6973}, + {0x8dc6, 7442}, + {0x8dcb, 4936}, + {0x8dcc, 7028}, + {0x8dcf, 3461}, + {0x8ddb, 7488}, + {0x8ddd, 3596}, + {0x8de1, 6637}, + {0x8de3, 5444}, + {0x8de8, 3811}, + {0x8def, 4522}, + {0x8df3, 4300}, + {0x8e0a, 6194}, + {0x8e0f, 4237}, + {0x8e10, 7161}, + {0x8e1e, 3597}, + {0x8e2a, 6850}, + {0x8e30, 6347}, + {0x8e35, 6851}, + {0x8e42, 6348}, + {0x8e44, 6775}, + {0x8e47, 3610}, + {0x8e48, 4301}, + {0x8e49, 7052}, + {0x8e4a, 7797}, + {0x8e59, 7296}, + {0x8e5f, 6638}, + {0x8e60, 7145}, + {0x8e74, 7297}, + {0x8e76, 3982}, + {0x8e81, 6821}, + {0x8e87, 6614}, + {0x8e8a, 6893}, + {0x8e8d, 5878}, + {0x8eaa, 4643}, + {0x8eab, 5755}, + {0x8eac, 3968}, + {0x8ec0, 3937}, + {0x8eca, 7053}, + {0x8ecb, 5819}, + {0x8ecc, 3988}, + {0x8ecd, 3957}, + {0x8ed2, 7726}, + {0x8edf, 5982}, + {0x8eeb, 7008}, + {0x8ef8, 7298}, + {0x8efb, 3462}, + {0x8efe, 5732}, + {0x8f03, 3887}, + {0x8f05, 4523}, + {0x8f09, 6584}, + {0x8f12, 7196}, + {0x8f13, 4686}, + {0x8f14, 5073}, + {0x8f15, 3698}, + {0x8f1b, 4438}, + {0x8f1c, 7356}, + {0x8f1d, 8003}, + {0x8f1e, 4706}, + {0x8f1f, 7174}, + {0x8f26, 4474}, + {0x8f27, 5055}, + {0x8f29, 4985}, + {0x8f2a, 4599}, + {0x8f2f, 7035}, + {0x8f33, 6894}, + {0x8f38, 5613}, + {0x8f39, 5087}, + {0x8f3b, 5088}, + {0x8f3e, 6674}, + {0x8f3f, 5944}, + {0x8f44, 7650}, + {0x8f45, 6276}, + {0x8f49, 6675}, + {0x8f4d, 7175}, + {0x8f4e, 3888}, + {0x8f5d, 5945}, + {0x8f5f, 3867}, + {0x8f62, 4463}, + {0x8f9b, 5756}, + {0x8f9c, 3761}, + {0x8fa3, 4398}, + {0x8fa6, 7496}, + {0x8fa8, 5034}, + {0x8fad, 5296}, + {0x8faf, 5035}, + {0x8fb0, 7009}, + {0x8fb1, 6173}, + {0x8fb2, 4177}, + {0x8fc2, 6222}, + {0x8fc5, 5757}, + {0x8fce, 6026}, + {0x8fd1, 4036}, + {0x8fd4, 4927}, + {0x8fe6, 3463}, + {0x8fea, 6639}, + {0x8feb, 4902}, + {0x8fed, 7029}, + {0x8ff0, 5669}, + {0x8ff2, 3626}, + {0x8ff7, 4867}, + {0x8ff9, 6640}, + {0x8ffd, 7278}, + {0x9000, 7463}, + {0x9001, 5559}, + {0x9002, 3838}, + {0x9003, 4302}, + {0x9005, 7978}, + {0x9006, 5954}, + {0x9008, 7787}, + {0x900b, 7567}, + {0x900d, 5531}, + {0x900f, 7469}, + {0x9010, 7299}, + {0x9011, 3938}, + {0x9014, 4303}, + {0x9015, 3699}, + {0x9017, 4356}, + {0x9019, 6615}, + {0x901a, 7458}, + {0x901d, 5399}, + {0x901e, 4500}, + {0x901f, 5545}, + {0x9020, 6822}, + {0x9021, 6917}, + {0x9022, 5106}, + {0x9023, 4475}, + {0x902e, 7211}, + {0x9031, 6895}, + {0x9032, 7010}, + {0x9035, 4007}, + {0x9038, 6466}, + {0x903c, 7615}, + {0x903e, 6350}, + {0x9041, 4361}, + {0x9042, 5614}, + {0x9047, 6223}, + {0x904a, 6349}, + {0x904b, 6246}, + {0x904d, 7525}, + {0x904e, 3812}, + {0x9050, 7627}, + {0x9051, 7925}, + {0x9053, 4304}, + {0x9054, 4216}, + {0x9055, 6306}, + {0x9059, 6165}, + {0x905c, 5550}, + {0x905d, 4238}, + {0x905e, 7212}, + {0x9060, 6277}, + {0x9061, 5532}, + {0x9063, 3646}, + {0x9069, 6641}, + {0x906d, 6823}, + {0x906e, 7054}, + {0x906f, 4362}, + {0x9072, 6974}, + {0x9075, 6918}, + {0x9077, 7162}, + {0x9078, 5445}, + {0x907a, 6351}, + {0x907c, 4561}, + {0x907d, 3598}, + {0x907f, 7602}, + {0x9080, 6166}, + {0x9081, 4720}, + {0x9082, 7700}, + {0x9083, 5615}, + {0x9084, 7896}, + {0x9087, 6434}, + {0x9088, 4669}, + {0x908a, 5036}, + {0x908f, 4381}, + {0x9091, 6389}, + {0x9095, 6096}, + {0x9099, 4707}, + {0x90a2, 7788}, + {0x90a3, 4138}, + {0x90a6, 4966}, + {0x90a8, 7250}, + {0x90aa, 5297}, + {0x90af, 3526}, + {0x90b0, 7443}, + {0x90b1, 3939}, + {0x90b5, 5533}, + {0x90b8, 6616}, + {0x90c1, 6236}, + {0x90ca, 3889}, + {0x90de, 4419}, + {0x90e1, 3958}, + {0x90e8, 5145}, + {0x90ed, 3818}, + {0x90f5, 6224}, + {0x90fd, 4305}, + {0x9102, 5802}, + {0x9112, 7279}, + {0x9115, 7714}, + {0x9119, 5219}, + {0x9127, 4372}, + {0x912d, 6748}, + {0x9132, 4210}, + {0x9149, 6352}, + {0x914a, 6749}, + {0x914b, 7280}, + {0x914c, 6519}, + {0x914d, 4986}, + {0x914e, 6896}, + {0x9152, 6897}, + {0x9162, 7238}, + {0x9169, 4760}, + {0x916a, 4387}, + {0x916c, 5616}, + {0x9175, 7964}, + {0x9177, 7843}, + {0x9178, 5313}, + {0x9187, 5663}, + {0x9189, 7327}, + {0x918b, 7239}, + {0x918d, 6776}, + {0x9192, 5491}, + {0x919c, 7281}, + {0x91ab, 6412}, + {0x91ac, 6567}, + {0x91ae, 7240}, + {0x91af, 7798}, + {0x91b1, 4937}, + {0x91b4, 4509}, + {0x91b5, 3584}, + {0x91c0, 5899}, + {0x91c7, 7124}, + {0x91c9, 6353}, + {0x91cb, 5416}, + {0x91cc, 4634}, + {0x91cd, 6925}, + {0x91ce, 5871}, + {0x91cf, 4439}, + {0x91d0, 4635}, + {0x91d1, 4131}, + {0x91d7, 5566}, + {0x91d8, 6750}, + {0x91dc, 5146}, + {0x91dd, 7374}, + {0x91e3, 6824}, + {0x91e7, 7163}, + {0x91ea, 6225}, + {0x91f5, 7125}, + {0x920d, 4363}, + {0x9210, 3622}, + {0x9211, 7497}, + {0x9212, 5329}, + {0x9217, 6366}, + {0x921e, 4014}, + {0x9234, 4501}, + {0x923a, 6082}, + {0x923f, 6676}, + {0x9240, 3534}, + {0x9245, 3599}, + {0x9249, 7752}, + {0x9257, 3658}, + {0x925b, 5983}, + {0x925e, 6283}, + {0x9262, 4938}, + {0x9264, 3940}, + {0x9265, 5670}, + {0x9266, 6751}, + {0x9280, 6378}, + {0x9283, 7260}, + {0x9285, 4347}, + {0x9291, 5446}, + {0x9293, 6677}, + {0x9296, 5617}, + {0x9298, 4761}, + {0x929c, 7660}, + {0x92b3, 6046}, + {0x92b6, 3941}, + {0x92b7, 5534}, + {0x92b9, 5618}, + {0x92cc, 6752}, + {0x92cf, 7769}, + {0x92d2, 5107}, + {0x92e4, 5400}, + {0x92ea, 7568}, + {0x92f8, 3600}, + {0x92fc, 3557}, + {0x9304, 4532}, + {0x9310, 7282}, + {0x9318, 7283}, + {0x931a, 6590}, + {0x931e, 5664}, + {0x931f, 4233}, + {0x9320, 6753}, + {0x9321, 4118}, + {0x9322, 6678}, + {0x9324, 4119}, + {0x9326, 4050}, + {0x9328, 4811}, + {0x932b, 5417}, + {0x932e, 3762}, + {0x932f, 7059}, + {0x9348, 6027}, + {0x934a, 4476}, + {0x934b, 3813}, + {0x934d, 4306}, + {0x9354, 5803}, + {0x935b, 4211}, + {0x936e, 6354}, + {0x9375, 3611}, + {0x937c, 7375}, + {0x937e, 6852}, + {0x938c, 3659}, + {0x9394, 6195}, + {0x9396, 5564}, + {0x939a, 7284}, + {0x93a3, 7789}, + {0x93a7, 3577}, + {0x93ac, 7838}, + {0x93ad, 7011}, + {0x93b0, 6467}, + {0x93c3, 6831}, + {0x93d1, 6642}, + {0x93de, 6196}, + {0x93e1, 3700}, + {0x93e4, 4575}, + {0x93f6, 7036}, + {0x9404, 7952}, + {0x9418, 6853}, + {0x9425, 5447}, + {0x942b, 6679}, + {0x9435, 7176}, + {0x9438, 7407}, + {0x9444, 6898}, + {0x9451, 3527}, + {0x9452, 3528}, + {0x945b, 3851}, + {0x947d, 7074}, + {0x947f, 7060}, + {0x9577, 6568}, + {0x9580, 4846}, + {0x9583, 5469}, + {0x9589, 7542}, + {0x958b, 3578}, + {0x958f, 6367}, + {0x9591, 7645}, + {0x9592, 7646}, + {0x9593, 3499}, + {0x9594, 4882}, + {0x9598, 3535}, + {0x95a3, 3475}, + {0x95a4, 7667}, + {0x95a5, 5008}, + {0x95a8, 4008}, + {0x95ad, 4453}, + {0x95b1, 5988}, + {0x95bb, 5996}, + {0x95bc, 5820}, + {0x95c7, 5828}, + {0x95ca, 7903}, + {0x95d4, 7668}, + {0x95d5, 3983}, + {0x95d6, 7473}, + {0x95dc, 3833}, + {0x95e1, 7164}, + {0x95e2, 5029}, + {0x961c, 5147}, + {0x9621, 7165}, + {0x962a, 7498}, + {0x962e, 6123}, + {0x9632, 4967}, + {0x963b, 6825}, + {0x963f, 5788}, + {0x9640, 7391}, + {0x9642, 7603}, + {0x9644, 5148}, + {0x964b, 4576}, + {0x964c, 4724}, + {0x964d, 3558}, + {0x9650, 7647}, + {0x965b, 7543}, + {0x965c, 7669}, + {0x965d, 5470}, + {0x965e, 5691}, + {0x965f, 7146}, + {0x9662, 6278}, + {0x9663, 7012}, + {0x9664, 6777}, + {0x966a, 4987}, + {0x9670, 6384}, + {0x9673, 7013}, + {0x9675, 4612}, + {0x9676, 4307}, + {0x9677, 7661}, + {0x9678, 4593}, + {0x967d, 5900}, + {0x9685, 6226}, + {0x9686, 4603}, + {0x968a, 4264}, + {0x968b, 5619}, + {0x968d, 7926}, + {0x968e, 3727}, + {0x9694, 3636}, + {0x9695, 6247}, + {0x9698, 5849}, + {0x9699, 4022}, + {0x969b, 6778}, + {0x969c, 6569}, + {0x96a3, 4644}, + {0x96a7, 5620}, + {0x96a8, 5621}, + {0x96aa, 7728}, + {0x96b1, 6379}, + {0x96b7, 4510}, + {0x96bb, 7147}, + {0x96c0, 6520}, + {0x96c1, 5813}, + {0x96c4, 6254}, + {0x96c5, 5789}, + {0x96c6, 7037}, + {0x96c7, 3763}, + {0x96c9, 7357}, + {0x96cb, 6919}, + {0x96cc, 6508}, + {0x96cd, 6097}, + {0x96ce, 6617}, + {0x96d5, 6826}, + {0x96d6, 5622}, + {0x96d9, 5773}, + {0x96db, 7285}, + {0x96dc, 6533}, + {0x96e2, 4636}, + {0x96e3, 4142}, + {0x96e8, 6227}, + {0x96e9, 6228}, + {0x96ea, 5461}, + {0x96ef, 4847}, + {0x96f0, 5170}, + {0x96f2, 6248}, + {0x96f6, 4502}, + {0x96f7, 4550}, + {0x96f9, 4903}, + {0x96fb, 6680}, + {0x9700, 5623}, + {0x9706, 6754}, + {0x9707, 7014}, + {0x9711, 6698}, + {0x9713, 6047}, + {0x9716, 4651}, + {0x9719, 6028}, + {0x971c, 5361}, + {0x971e, 7628}, + {0x9727, 4832}, + {0x9730, 5314}, + {0x9732, 4524}, + {0x9739, 5030}, + {0x973d, 6779}, + {0x9742, 4464}, + {0x9744, 5850}, + {0x9748, 4503}, + {0x9751, 7203}, + {0x9756, 6755}, + {0x975c, 6756}, + {0x975e, 5220}, + {0x9761, 4868}, + {0x9762, 4744}, + {0x9769, 7733}, + {0x976d, 6458}, + {0x9774, 7876}, + {0x9777, 6459}, + {0x977a, 4695}, + {0x978b, 7799}, + {0x978d, 5814}, + {0x978f, 3801}, + {0x97a0, 3950}, + {0x97a8, 3509}, + {0x97ab, 3951}, + {0x97ad, 7526}, + {0x97c6, 7166}, + {0x97cb, 6307}, + {0x97d3, 7648}, + {0x97dc, 4308}, + {0x97f3, 6385}, + {0x97f6, 5535}, + {0x97fb, 6249}, + {0x97ff, 7715}, + {0x9800, 7839}, + {0x9801, 7757}, + {0x9802, 6757}, + {0x9803, 3701}, + {0x9805, 7684}, + {0x9806, 5665}, + {0x9808, 5624}, + {0x980a, 6237}, + {0x980c, 5560}, + {0x9810, 6048}, + {0x9811, 6124}, + {0x9812, 4928}, + {0x9813, 4328}, + {0x9817, 7489}, + {0x9818, 4504}, + {0x982d, 4357}, + {0x9830, 7770}, + {0x9838, 3702}, + {0x9839, 7464}, + {0x983b, 5236}, + {0x9846, 3814}, + {0x984c, 6780}, + {0x984d, 5857}, + {0x984e, 5804}, + {0x9854, 5815}, + {0x9858, 6279}, + {0x985a, 6681}, + {0x985e, 4590}, + {0x9865, 7840}, + {0x9867, 3764}, + {0x986b, 6682}, + {0x986f, 7753}, + {0x98a8, 7595}, + {0x98af, 5330}, + {0x98b1, 7444}, + {0x98c4, 7588}, + {0x98c7, 7587}, + {0x98db, 5221}, + {0x98dc, 5004}, + {0x98df, 5733}, + {0x98e1, 5551}, + {0x98e2, 4120}, + {0x98ed, 7362}, + {0x98ee, 6386}, + {0x98ef, 4929}, + {0x98f4, 6435}, + {0x98fc, 5298}, + {0x98fd, 7569}, + {0x98fe, 5734}, + {0x9903, 3890}, + {0x9909, 7716}, + {0x990a, 5901}, + {0x990c, 6436}, + {0x9910, 7075}, + {0x9913, 5790}, + {0x9918, 5946}, + {0x991e, 6683}, + {0x9920, 5056}, + {0x9928, 3834}, + {0x9945, 4687}, + {0x9949, 4037}, + {0x994b, 3989}, + {0x994c, 7076}, + {0x994d, 5448}, + {0x9951, 4121}, + {0x9952, 6167}, + {0x9954, 6098}, + {0x9957, 7717}, + {0x9996, 5625}, + {0x9999, 7718}, + {0x999d, 7613}, + {0x99a5, 5089}, + {0x99a8, 7790}, + {0x99ac, 4661}, + {0x99ad, 5909}, + {0x99ae, 7596}, + {0x99b1, 7392}, + {0x99b3, 7358}, + {0x99b4, 5666}, + {0x99b9, 6468}, + {0x99c1, 4904}, + {0x99d0, 6899}, + {0x99d1, 4174}, + {0x99d2, 3942}, + {0x99d5, 3464}, + {0x99d9, 5149}, + {0x99dd, 7393}, + {0x99df, 5299}, + {0x99ed, 7701}, + {0x99f1, 4388}, + {0x99ff, 6920}, + {0x9a01, 5240}, + {0x9a08, 5057}, + {0x9a0e, 4122}, + {0x9a0f, 4123}, + {0x9a19, 7527}, + {0x9a2b, 3612}, + {0x9a30, 4373}, + {0x9a36, 7286}, + {0x9a37, 5536}, + {0x9a40, 4725}, + {0x9a43, 7589}, + {0x9a45, 3943}, + {0x9a4d, 7965}, + {0x9a55, 3891}, + {0x9a57, 7729}, + {0x9a5a, 3703}, + {0x9a5b, 5955}, + {0x9a5f, 7328}, + {0x9a62, 4454}, + {0x9a65, 4124}, + {0x9a69, 7897}, + {0x9a6a, 4455}, + {0x9aa8, 3785}, + {0x9ab8, 7702}, + {0x9ad3, 5626}, + {0x9ad4, 7213}, + {0x9ad8, 3765}, + {0x9ae5, 5997}, + {0x9aee, 4939}, + {0x9b1a, 5627}, + {0x9b27, 4562}, + {0x9b2a, 7470}, + {0x9b31, 6251}, + {0x9b3c, 3993}, + {0x9b41, 3863}, + {0x9b42, 7849}, + {0x9b43, 4940}, + {0x9b44, 4995}, + {0x9b45, 4721}, + {0x9b4f, 6308}, + {0x9b54, 4662}, + {0x9b5a, 5910}, + {0x9b6f, 4525}, + {0x9b8e, 6699}, + {0x9b91, 7570}, + {0x9b9f, 5816}, + {0x9bab, 3892}, + {0x9bae, 5449}, + {0x9bc9, 4637}, + {0x9bd6, 7204}, + {0x9be4, 3783}, + {0x9be8, 3704}, + {0x9c0d, 7287}, + {0x9c10, 5805}, + {0x9c12, 5090}, + {0x9c15, 7629}, + {0x9c25, 7898}, + {0x9c32, 6076}, + {0x9c3b, 4688}, + {0x9c47, 3559}, + {0x9c49, 5039}, + {0x9c57, 4645}, + {0x9ce5, 6827}, + {0x9ce7, 5150}, + {0x9ce9, 3944}, + {0x9cf3, 5108}, + {0x9cf4, 4762}, + {0x9cf6, 5984}, + {0x9d09, 5791}, + {0x9d1b, 6280}, + {0x9d26, 5839}, + {0x9d28, 5832}, + {0x9d3b, 7862}, + {0x9d51, 3647}, + {0x9d5d, 5792}, + {0x9d60, 3773}, + {0x9d61, 4833}, + {0x9d6c, 5180}, + {0x9d72, 6521}, + {0x9da9, 4794}, + {0x9daf, 5860}, + {0x9db4, 7634}, + {0x9dc4, 3728}, + {0x9dd7, 3945}, + {0x9df2, 7329}, + {0x9df8, 8012}, + {0x9df9, 6393}, + {0x9dfa, 4526}, + {0x9e1a, 5861}, + {0x9e1e, 4396}, + {0x9e75, 4527}, + {0x9e79, 7662}, + {0x9e7d, 5998}, + {0x9e7f, 4533}, + {0x9e92, 4125}, + {0x9e93, 4534}, + {0x9e97, 4456}, + {0x9e9d, 5300}, + {0x9e9f, 4646}, + {0x9ea5, 4726}, + {0x9eb4, 3952}, + {0x9eb5, 4745}, + {0x9ebb, 4663}, + {0x9ebe, 8004}, + {0x9ec3, 7927}, + {0x9ecd, 5401}, + {0x9ece, 4457}, + {0x9ed1, 8018}, + {0x9ed4, 3623}, + {0x9ed8, 4835}, + {0x9edb, 4265}, + {0x9edc, 7305}, + {0x9ede, 6700}, + {0x9ee8, 4249}, + {0x9ef4, 4869}, + {0x9f07, 6077}, + {0x9f08, 5040}, + {0x9f0e, 6758}, + {0x9f13, 3766}, + {0x9f20, 5402}, + {0x9f3b, 5222}, + {0x9f4a, 6781}, + {0x9f4b, 6585}, + {0x9f4e, 6586}, + {0x9f52, 7359}, + {0x9f5f, 6618}, + {0x9f61, 4505}, + {0x9f67, 5462}, + {0x9f6a, 7061}, + {0x9f6c, 5911}, + {0x9f77, 5806}, + {0x9f8d, 4563}, + {0x9f90, 4968}, + {0x9f95, 3529}, + {0x9f9c, 3946}, + {0xac00, 1086}, + {0xac01, 1087}, + {0xac02, 9333}, + {0xac03, 9334}, + {0xac04, 1088}, + {0xac05, 9335}, + {0xac06, 9336}, + {0xac07, 1089}, + {0xac08, 1090}, + {0xac09, 1091}, + {0xac0a, 1092}, + {0xac0b, 9337}, + {0xac0c, 9338}, + {0xac0d, 9339}, + {0xac0e, 9340}, + {0xac0f, 9341}, + {0xac10, 1093}, + {0xac11, 1094}, + {0xac12, 1095}, + {0xac13, 1096}, + {0xac14, 1097}, + {0xac15, 1098}, + {0xac16, 1099}, + {0xac17, 1100}, + {0xac18, 9342}, + {0xac19, 1101}, + {0xac1a, 1102}, + {0xac1b, 1103}, + {0xac1c, 1104}, + {0xac1d, 1105}, + {0xac1e, 9343}, + {0xac1f, 9344}, + {0xac20, 1106}, + {0xac21, 9345}, + {0xac22, 9346}, + {0xac23, 9347}, + {0xac24, 1107}, + {0xac25, 9348}, + {0xac26, 9349}, + {0xac27, 9350}, + {0xac28, 9351}, + {0xac29, 9352}, + {0xac2a, 9353}, + {0xac2b, 9354}, + {0xac2c, 1108}, + {0xac2d, 1109}, + {0xac2e, 9355}, + {0xac2f, 1110}, + {0xac30, 1111}, + {0xac31, 1112}, + {0xac32, 9356}, + {0xac33, 9357}, + {0xac34, 9358}, + {0xac35, 9359}, + {0xac36, 9360}, + {0xac37, 9361}, + {0xac38, 1113}, + {0xac39, 1114}, + {0xac3a, 9362}, + {0xac3b, 9363}, + {0xac3c, 1115}, + {0xac3d, 9364}, + {0xac3e, 9365}, + {0xac3f, 9366}, + {0xac40, 1116}, + {0xac41, 9367}, + {0xac42, 9368}, + {0xac43, 9369}, + {0xac44, 9370}, + {0xac45, 9371}, + {0xac46, 9372}, + {0xac47, 9373}, + {0xac48, 9374}, + {0xac49, 9375}, + {0xac4a, 9376}, + {0xac4b, 1117}, + {0xac4c, 9377}, + {0xac4d, 1118}, + {0xac4e, 9378}, + {0xac4f, 9379}, + {0xac50, 9380}, + {0xac51, 9381}, + {0xac52, 9382}, + {0xac53, 9383}, + {0xac54, 1119}, + {0xac55, 9384}, + {0xac56, 9385}, + {0xac57, 9386}, + {0xac58, 1120}, + {0xac59, 9387}, + {0xac5a, 9388}, + {0xac5b, 9389}, + {0xac5c, 1121}, + {0xac5d, 9390}, + {0xac5e, 9391}, + {0xac5f, 9392}, + {0xac60, 9393}, + {0xac61, 9394}, + {0xac62, 9395}, + {0xac63, 9396}, + {0xac64, 9397}, + {0xac65, 9398}, + {0xac66, 9399}, + {0xac67, 9400}, + {0xac68, 9401}, + {0xac69, 9402}, + {0xac6a, 9403}, + {0xac6b, 9404}, + {0xac6c, 9405}, + {0xac6d, 9406}, + {0xac6e, 9407}, + {0xac6f, 9408}, + {0xac70, 1122}, + {0xac71, 1123}, + {0xac72, 9409}, + {0xac73, 9410}, + {0xac74, 1124}, + {0xac75, 9411}, + {0xac76, 9412}, + {0xac77, 1125}, + {0xac78, 1126}, + {0xac79, 9413}, + {0xac7a, 1127}, + {0xac7b, 9414}, + {0xac7c, 9415}, + {0xac7d, 9416}, + {0xac7e, 9417}, + {0xac7f, 9418}, + {0xac80, 1128}, + {0xac81, 1129}, + {0xac82, 9419}, + {0xac83, 1130}, + {0xac84, 1131}, + {0xac85, 1132}, + {0xac86, 1133}, + {0xac87, 9420}, + {0xac88, 9421}, + {0xac89, 1134}, + {0xac8a, 1135}, + {0xac8b, 1136}, + {0xac8c, 1137}, + {0xac8d, 9422}, + {0xac8e, 9423}, + {0xac8f, 9424}, + {0xac90, 1138}, + {0xac91, 9425}, + {0xac92, 9426}, + {0xac93, 9427}, + {0xac94, 1139}, + {0xac95, 9428}, + {0xac96, 9429}, + {0xac97, 9430}, + {0xac98, 9431}, + {0xac99, 9432}, + {0xac9a, 9433}, + {0xac9b, 9434}, + {0xac9c, 1140}, + {0xac9d, 1141}, + {0xac9e, 9435}, + {0xac9f, 1142}, + {0xaca0, 1143}, + {0xaca1, 1144}, + {0xaca2, 9436}, + {0xaca3, 9437}, + {0xaca4, 9438}, + {0xaca5, 9439}, + {0xaca6, 9440}, + {0xaca7, 9441}, + {0xaca8, 1145}, + {0xaca9, 1146}, + {0xacaa, 1147}, + {0xacab, 9442}, + {0xacac, 1148}, + {0xacad, 9443}, + {0xacae, 9444}, + {0xacaf, 1149}, + {0xacb0, 1150}, + {0xacb1, 9445}, + {0xacb2, 9446}, + {0xacb3, 9447}, + {0xacb4, 9448}, + {0xacb5, 9449}, + {0xacb6, 9450}, + {0xacb7, 9451}, + {0xacb8, 1151}, + {0xacb9, 1152}, + {0xacba, 9452}, + {0xacbb, 1153}, + {0xacbc, 1154}, + {0xacbd, 1155}, + {0xacbe, 9453}, + {0xacbf, 9454}, + {0xacc0, 9455}, + {0xacc1, 1156}, + {0xacc2, 9456}, + {0xacc3, 9457}, + {0xacc4, 1157}, + {0xacc5, 9458}, + {0xacc6, 9459}, + {0xacc7, 9460}, + {0xacc8, 1158}, + {0xacc9, 9461}, + {0xacca, 9462}, + {0xaccb, 9463}, + {0xaccc, 1159}, + {0xaccd, 9464}, + {0xacce, 9465}, + {0xaccf, 9466}, + {0xacd0, 9467}, + {0xacd1, 9468}, + {0xacd2, 9469}, + {0xacd3, 9470}, + {0xacd4, 9471}, + {0xacd5, 1160}, + {0xacd6, 9472}, + {0xacd7, 1161}, + {0xacd8, 9473}, + {0xacd9, 9474}, + {0xacda, 9475}, + {0xacdb, 9476}, + {0xacdc, 9477}, + {0xacdd, 9478}, + {0xacde, 9479}, + {0xacdf, 9480}, + {0xace0, 1162}, + {0xace1, 1163}, + {0xace2, 9481}, + {0xace3, 9482}, + {0xace4, 1164}, + {0xace5, 9483}, + {0xace6, 9484}, + {0xace7, 1165}, + {0xace8, 1166}, + {0xace9, 9485}, + {0xacea, 1167}, + {0xaceb, 9486}, + {0xacec, 1168}, + {0xaced, 9487}, + {0xacee, 9488}, + {0xacef, 1169}, + {0xacf0, 1170}, + {0xacf1, 1171}, + {0xacf2, 9489}, + {0xacf3, 1172}, + {0xacf4, 9490}, + {0xacf5, 1173}, + {0xacf6, 1174}, + {0xacf7, 9491}, + {0xacf8, 9492}, + {0xacf9, 9493}, + {0xacfa, 9494}, + {0xacfb, 9495}, + {0xacfc, 1175}, + {0xacfd, 1176}, + {0xacfe, 9496}, + {0xacff, 9497}, + {0xad00, 1177}, + {0xad01, 9498}, + {0xad02, 9499}, + {0xad03, 9500}, + {0xad04, 1178}, + {0xad05, 9501}, + {0xad06, 1179}, + {0xad07, 9502}, + {0xad08, 9503}, + {0xad09, 9504}, + {0xad0a, 9505}, + {0xad0b, 9506}, + {0xad0c, 1180}, + {0xad0d, 1181}, + {0xad0e, 9507}, + {0xad0f, 1182}, + {0xad10, 9508}, + {0xad11, 1183}, + {0xad12, 9509}, + {0xad13, 9510}, + {0xad14, 9511}, + {0xad15, 9512}, + {0xad16, 9513}, + {0xad17, 9514}, + {0xad18, 1184}, + {0xad19, 9515}, + {0xad1a, 9516}, + {0xad1b, 9517}, + {0xad1c, 1185}, + {0xad1d, 9518}, + {0xad1e, 9519}, + {0xad1f, 9520}, + {0xad20, 1186}, + {0xad21, 9521}, + {0xad22, 9522}, + {0xad23, 9523}, + {0xad24, 9524}, + {0xad25, 9525}, + {0xad26, 9526}, + {0xad27, 9527}, + {0xad28, 9528}, + {0xad29, 1187}, + {0xad2a, 9529}, + {0xad2b, 9530}, + {0xad2c, 1188}, + {0xad2d, 1189}, + {0xad2e, 9531}, + {0xad2f, 9532}, + {0xad30, 9533}, + {0xad31, 9534}, + {0xad32, 9535}, + {0xad33, 9536}, + {0xad34, 1190}, + {0xad35, 1191}, + {0xad36, 9537}, + {0xad37, 9538}, + {0xad38, 1192}, + {0xad39, 9539}, + {0xad3a, 9540}, + {0xad3b, 9541}, + {0xad3c, 1193}, + {0xad3d, 9542}, + {0xad3e, 9543}, + {0xad3f, 9544}, + {0xad40, 9545}, + {0xad41, 9546}, + {0xad42, 9547}, + {0xad43, 9548}, + {0xad44, 1194}, + {0xad45, 1195}, + {0xad46, 9549}, + {0xad47, 1196}, + {0xad48, 9550}, + {0xad49, 1197}, + {0xad4a, 9551}, + {0xad4b, 9552}, + {0xad4c, 9553}, + {0xad4d, 9554}, + {0xad4e, 9555}, + {0xad4f, 9556}, + {0xad50, 1198}, + {0xad51, 9557}, + {0xad52, 9558}, + {0xad53, 9559}, + {0xad54, 1199}, + {0xad55, 9560}, + {0xad56, 9561}, + {0xad57, 9562}, + {0xad58, 1200}, + {0xad59, 9563}, + {0xad5a, 9564}, + {0xad5b, 9565}, + {0xad5c, 9566}, + {0xad5d, 9567}, + {0xad5e, 9568}, + {0xad5f, 9569}, + {0xad60, 9570}, + {0xad61, 1201}, + {0xad62, 9571}, + {0xad63, 1202}, + {0xad64, 9572}, + {0xad65, 9573}, + {0xad66, 9574}, + {0xad67, 9575}, + {0xad68, 9576}, + {0xad69, 9577}, + {0xad6a, 9578}, + {0xad6b, 9579}, + {0xad6c, 1203}, + {0xad6d, 1204}, + {0xad6e, 9580}, + {0xad6f, 9581}, + {0xad70, 1205}, + {0xad71, 9582}, + {0xad72, 9583}, + {0xad73, 1206}, + {0xad74, 1207}, + {0xad75, 1208}, + {0xad76, 1209}, + {0xad77, 9584}, + {0xad78, 9585}, + {0xad79, 9586}, + {0xad7a, 9587}, + {0xad7b, 1210}, + {0xad7c, 1211}, + {0xad7d, 1212}, + {0xad7e, 9588}, + {0xad7f, 1213}, + {0xad80, 9589}, + {0xad81, 1214}, + {0xad82, 1215}, + {0xad83, 9590}, + {0xad84, 9591}, + {0xad85, 9592}, + {0xad86, 9593}, + {0xad87, 9594}, + {0xad88, 1216}, + {0xad89, 1217}, + {0xad8a, 9595}, + {0xad8b, 9596}, + {0xad8c, 1218}, + {0xad8d, 9597}, + {0xad8e, 9598}, + {0xad8f, 9599}, + {0xad90, 1219}, + {0xad91, 9600}, + {0xad92, 9601}, + {0xad93, 9602}, + {0xad94, 9603}, + {0xad95, 9604}, + {0xad96, 9605}, + {0xad97, 9606}, + {0xad98, 9607}, + {0xad99, 9608}, + {0xad9a, 9609}, + {0xad9b, 9610}, + {0xad9c, 1220}, + {0xad9d, 1221}, + {0xad9e, 9611}, + {0xad9f, 9612}, + {0xada0, 9613}, + {0xada1, 9614}, + {0xada2, 9615}, + {0xada3, 9616}, + {0xada4, 1222}, + {0xada5, 9617}, + {0xada6, 9618}, + {0xada7, 9619}, + {0xada8, 9620}, + {0xada9, 9621}, + {0xadaa, 9622}, + {0xadab, 9623}, + {0xadac, 9624}, + {0xadad, 9625}, + {0xadae, 9626}, + {0xadaf, 9627}, + {0xadb0, 9628}, + {0xadb1, 9629}, + {0xadb2, 9630}, + {0xadb3, 9631}, + {0xadb4, 9632}, + {0xadb5, 9633}, + {0xadb6, 9634}, + {0xadb7, 1223}, + {0xadb8, 9635}, + {0xadb9, 9636}, + {0xadba, 9637}, + {0xadbb, 9638}, + {0xadbc, 9639}, + {0xadbd, 9640}, + {0xadbe, 9641}, + {0xadbf, 9642}, + {0xadc0, 1224}, + {0xadc1, 1225}, + {0xadc2, 9643}, + {0xadc3, 9644}, + {0xadc4, 1226}, + {0xadc5, 9645}, + {0xadc6, 9646}, + {0xadc7, 9647}, + {0xadc8, 1227}, + {0xadc9, 9648}, + {0xadca, 9649}, + {0xadcb, 9650}, + {0xadcc, 9651}, + {0xadcd, 9652}, + {0xadce, 9653}, + {0xadcf, 9654}, + {0xadd0, 1228}, + {0xadd1, 1229}, + {0xadd2, 9655}, + {0xadd3, 1230}, + {0xadd4, 9656}, + {0xadd5, 9657}, + {0xadd6, 9658}, + {0xadd7, 9659}, + {0xadd8, 9660}, + {0xadd9, 9661}, + {0xadda, 9662}, + {0xaddb, 9663}, + {0xaddc, 1231}, + {0xaddd, 9664}, + {0xadde, 9665}, + {0xaddf, 9666}, + {0xade0, 1232}, + {0xade1, 9667}, + {0xade2, 9668}, + {0xade3, 9669}, + {0xade4, 1233}, + {0xade5, 9670}, + {0xade6, 9671}, + {0xade7, 9672}, + {0xade8, 9673}, + {0xade9, 9674}, + {0xadea, 9675}, + {0xadeb, 9676}, + {0xadec, 9677}, + {0xaded, 9678}, + {0xadee, 9679}, + {0xadef, 9680}, + {0xadf0, 9681}, + {0xadf1, 9682}, + {0xadf2, 9683}, + {0xadf3, 9684}, + {0xadf4, 9685}, + {0xadf5, 9686}, + {0xadf6, 9687}, + {0xadf7, 9688}, + {0xadf8, 1234}, + {0xadf9, 1235}, + {0xadfa, 9689}, + {0xadfb, 9690}, + {0xadfc, 1236}, + {0xadfd, 9691}, + {0xadfe, 9692}, + {0xadff, 1237}, + {0xae00, 1238}, + {0xae01, 1239}, + {0xae02, 9693}, + {0xae03, 9694}, + {0xae04, 9695}, + {0xae05, 9696}, + {0xae06, 9697}, + {0xae07, 9698}, + {0xae08, 1240}, + {0xae09, 1241}, + {0xae0a, 9699}, + {0xae0b, 1242}, + {0xae0c, 9700}, + {0xae0d, 1243}, + {0xae0e, 9701}, + {0xae0f, 9702}, + {0xae10, 9703}, + {0xae11, 9704}, + {0xae12, 9705}, + {0xae13, 9706}, + {0xae14, 1244}, + {0xae15, 9707}, + {0xae16, 9708}, + {0xae17, 9709}, + {0xae18, 9710}, + {0xae19, 9711}, + {0xae1a, 9712}, + {0xae1b, 9713}, + {0xae1c, 9714}, + {0xae1d, 9715}, + {0xae1e, 9716}, + {0xae1f, 9717}, + {0xae20, 9718}, + {0xae21, 9719}, + {0xae22, 9720}, + {0xae23, 9721}, + {0xae24, 9722}, + {0xae25, 9723}, + {0xae26, 9724}, + {0xae27, 9725}, + {0xae28, 9726}, + {0xae29, 9727}, + {0xae2a, 9728}, + {0xae2b, 9729}, + {0xae2c, 9730}, + {0xae2d, 9731}, + {0xae2e, 9732}, + {0xae2f, 9733}, + {0xae30, 1245}, + {0xae31, 1246}, + {0xae32, 9734}, + {0xae33, 9735}, + {0xae34, 1247}, + {0xae35, 9736}, + {0xae36, 9737}, + {0xae37, 1248}, + {0xae38, 1249}, + {0xae39, 9738}, + {0xae3a, 1250}, + {0xae3b, 9739}, + {0xae3c, 9740}, + {0xae3d, 9741}, + {0xae3e, 9742}, + {0xae3f, 9743}, + {0xae40, 1251}, + {0xae41, 1252}, + {0xae42, 9744}, + {0xae43, 1253}, + {0xae44, 9745}, + {0xae45, 1254}, + {0xae46, 1255}, + {0xae47, 9746}, + {0xae48, 9747}, + {0xae49, 9748}, + {0xae4a, 1256}, + {0xae4b, 9749}, + {0xae4c, 1257}, + {0xae4d, 1258}, + {0xae4e, 1259}, + {0xae4f, 9750}, + {0xae50, 1260}, + {0xae51, 9751}, + {0xae52, 9752}, + {0xae53, 9753}, + {0xae54, 1261}, + {0xae55, 9754}, + {0xae56, 1262}, + {0xae57, 9755}, + {0xae58, 9756}, + {0xae59, 9757}, + {0xae5a, 9758}, + {0xae5b, 9759}, + {0xae5c, 1263}, + {0xae5d, 1264}, + {0xae5e, 9760}, + {0xae5f, 1265}, + {0xae60, 1266}, + {0xae61, 1267}, + {0xae62, 9761}, + {0xae63, 9762}, + {0xae64, 9763}, + {0xae65, 1268}, + {0xae66, 9764}, + {0xae67, 9765}, + {0xae68, 1269}, + {0xae69, 1270}, + {0xae6a, 9766}, + {0xae6b, 9767}, + {0xae6c, 1271}, + {0xae6d, 9768}, + {0xae6e, 9769}, + {0xae6f, 9770}, + {0xae70, 1272}, + {0xae71, 9771}, + {0xae72, 9772}, + {0xae73, 9773}, + {0xae74, 9774}, + {0xae75, 9775}, + {0xae76, 9776}, + {0xae77, 9777}, + {0xae78, 1273}, + {0xae79, 1274}, + {0xae7a, 9778}, + {0xae7b, 1275}, + {0xae7c, 1276}, + {0xae7d, 1277}, + {0xae7e, 9779}, + {0xae7f, 9780}, + {0xae80, 9781}, + {0xae81, 9782}, + {0xae82, 9783}, + {0xae83, 9784}, + {0xae84, 1278}, + {0xae85, 1279}, + {0xae86, 9785}, + {0xae87, 9786}, + {0xae88, 9787}, + {0xae89, 9788}, + {0xae8a, 9789}, + {0xae8b, 9790}, + {0xae8c, 1280}, + {0xae8d, 9791}, + {0xae8e, 9792}, + {0xae8f, 9793}, + {0xae90, 9794}, + {0xae91, 9795}, + {0xae92, 9796}, + {0xae93, 9797}, + {0xae94, 9798}, + {0xae95, 9799}, + {0xae96, 9800}, + {0xae97, 9801}, + {0xae98, 9802}, + {0xae99, 9803}, + {0xae9a, 9804}, + {0xae9b, 9805}, + {0xae9c, 9806}, + {0xae9d, 9807}, + {0xae9e, 9808}, + {0xae9f, 9809}, + {0xaea0, 9810}, + {0xaea1, 9811}, + {0xaea2, 9812}, + {0xaea3, 9813}, + {0xaea4, 9814}, + {0xaea5, 9815}, + {0xaea6, 9816}, + {0xaea7, 9817}, + {0xaea8, 9818}, + {0xaea9, 9819}, + {0xaeaa, 9820}, + {0xaeab, 9821}, + {0xaeac, 9822}, + {0xaead, 9823}, + {0xaeae, 9824}, + {0xaeaf, 9825}, + {0xaeb0, 9826}, + {0xaeb1, 9827}, + {0xaeb2, 9828}, + {0xaeb3, 9829}, + {0xaeb4, 9830}, + {0xaeb5, 9831}, + {0xaeb6, 9832}, + {0xaeb7, 9833}, + {0xaeb8, 9834}, + {0xaeb9, 9835}, + {0xaeba, 9836}, + {0xaebb, 9837}, + {0xaebc, 1281}, + {0xaebd, 1282}, + {0xaebe, 1283}, + {0xaebf, 9838}, + {0xaec0, 1284}, + {0xaec1, 9839}, + {0xaec2, 9840}, + {0xaec3, 9841}, + {0xaec4, 1285}, + {0xaec5, 9842}, + {0xaec6, 9843}, + {0xaec7, 9844}, + {0xaec8, 9845}, + {0xaec9, 9846}, + {0xaeca, 9847}, + {0xaecb, 9848}, + {0xaecc, 1286}, + {0xaecd, 1287}, + {0xaece, 9849}, + {0xaecf, 1288}, + {0xaed0, 1289}, + {0xaed1, 1290}, + {0xaed2, 9850}, + {0xaed3, 9851}, + {0xaed4, 9852}, + {0xaed5, 9853}, + {0xaed6, 9854}, + {0xaed7, 9855}, + {0xaed8, 1291}, + {0xaed9, 1292}, + {0xaeda, 9856}, + {0xaedb, 9857}, + {0xaedc, 1293}, + {0xaedd, 9858}, + {0xaede, 9859}, + {0xaedf, 9860}, + {0xaee0, 9861}, + {0xaee1, 9862}, + {0xaee2, 9863}, + {0xaee3, 9864}, + {0xaee4, 9865}, + {0xaee5, 9866}, + {0xaee6, 9867}, + {0xaee7, 9868}, + {0xaee8, 1294}, + {0xaee9, 9869}, + {0xaeea, 9870}, + {0xaeeb, 1295}, + {0xaeec, 9871}, + {0xaeed, 1296}, + {0xaeee, 9872}, + {0xaeef, 9873}, + {0xaef0, 9874}, + {0xaef1, 9875}, + {0xaef2, 9876}, + {0xaef3, 9877}, + {0xaef4, 1297}, + {0xaef5, 9878}, + {0xaef6, 9879}, + {0xaef7, 9880}, + {0xaef8, 1298}, + {0xaef9, 9881}, + {0xaefa, 9882}, + {0xaefb, 9883}, + {0xaefc, 1299}, + {0xaefd, 9884}, + {0xaefe, 9885}, + {0xaeff, 9886}, + {0xaf00, 9887}, + {0xaf01, 9888}, + {0xaf02, 9889}, + {0xaf03, 9890}, + {0xaf04, 9891}, + {0xaf05, 9892}, + {0xaf06, 9893}, + {0xaf07, 1300}, + {0xaf08, 1301}, + {0xaf09, 9894}, + {0xaf0a, 9895}, + {0xaf0b, 9896}, + {0xaf0c, 9897}, + {0xaf0d, 1302}, + {0xaf0e, 9898}, + {0xaf0f, 9899}, + {0xaf10, 1303}, + {0xaf11, 9900}, + {0xaf12, 9901}, + {0xaf13, 9902}, + {0xaf14, 9903}, + {0xaf15, 9904}, + {0xaf16, 9905}, + {0xaf17, 9906}, + {0xaf18, 9907}, + {0xaf19, 9908}, + {0xaf1a, 9909}, + {0xaf1b, 9910}, + {0xaf1c, 9911}, + {0xaf1d, 9912}, + {0xaf1e, 9913}, + {0xaf1f, 9914}, + {0xaf20, 9915}, + {0xaf21, 9916}, + {0xaf22, 9917}, + {0xaf23, 9918}, + {0xaf24, 9919}, + {0xaf25, 9920}, + {0xaf26, 9921}, + {0xaf27, 9922}, + {0xaf28, 9923}, + {0xaf29, 9924}, + {0xaf2a, 9925}, + {0xaf2b, 9926}, + {0xaf2c, 1304}, + {0xaf2d, 1305}, + {0xaf2e, 9927}, + {0xaf2f, 9928}, + {0xaf30, 1306}, + {0xaf31, 9929}, + {0xaf32, 1307}, + {0xaf33, 9930}, + {0xaf34, 1308}, + {0xaf35, 9931}, + {0xaf36, 9932}, + {0xaf37, 9933}, + {0xaf38, 9934}, + {0xaf39, 9935}, + {0xaf3a, 9936}, + {0xaf3b, 9937}, + {0xaf3c, 1309}, + {0xaf3d, 1310}, + {0xaf3e, 9938}, + {0xaf3f, 1311}, + {0xaf40, 9939}, + {0xaf41, 1312}, + {0xaf42, 1313}, + {0xaf43, 1314}, + {0xaf44, 9940}, + {0xaf45, 9941}, + {0xaf46, 9942}, + {0xaf47, 9943}, + {0xaf48, 1315}, + {0xaf49, 1316}, + {0xaf4a, 9944}, + {0xaf4b, 9945}, + {0xaf4c, 9946}, + {0xaf4d, 9947}, + {0xaf4e, 9948}, + {0xaf4f, 9949}, + {0xaf50, 1317}, + {0xaf51, 9950}, + {0xaf52, 9951}, + {0xaf53, 9952}, + {0xaf54, 9953}, + {0xaf55, 9954}, + {0xaf56, 9955}, + {0xaf57, 9956}, + {0xaf58, 9957}, + {0xaf59, 9958}, + {0xaf5a, 9959}, + {0xaf5b, 9960}, + {0xaf5c, 1318}, + {0xaf5d, 1319}, + {0xaf5e, 9961}, + {0xaf5f, 9962}, + {0xaf60, 9963}, + {0xaf61, 9964}, + {0xaf62, 9965}, + {0xaf63, 9966}, + {0xaf64, 1320}, + {0xaf65, 1321}, + {0xaf66, 9967}, + {0xaf67, 9968}, + {0xaf68, 9969}, + {0xaf69, 9970}, + {0xaf6a, 9971}, + {0xaf6b, 9972}, + {0xaf6c, 9973}, + {0xaf6d, 9974}, + {0xaf6e, 9975}, + {0xaf6f, 9976}, + {0xaf70, 9977}, + {0xaf71, 9978}, + {0xaf72, 9979}, + {0xaf73, 9980}, + {0xaf74, 9981}, + {0xaf75, 9982}, + {0xaf76, 9983}, + {0xaf77, 9984}, + {0xaf78, 9985}, + {0xaf79, 1322}, + {0xaf7a, 9986}, + {0xaf7b, 9987}, + {0xaf7c, 9988}, + {0xaf7d, 9989}, + {0xaf7e, 9990}, + {0xaf7f, 9991}, + {0xaf80, 1323}, + {0xaf81, 9992}, + {0xaf82, 9993}, + {0xaf83, 9994}, + {0xaf84, 1324}, + {0xaf85, 9995}, + {0xaf86, 9996}, + {0xaf87, 9997}, + {0xaf88, 1325}, + {0xaf89, 9998}, + {0xaf8a, 9999}, + {0xaf8b, 10000}, + {0xaf8c, 10001}, + {0xaf8d, 10002}, + {0xaf8e, 10003}, + {0xaf8f, 10004}, + {0xaf90, 1326}, + {0xaf91, 1327}, + {0xaf93, 0}, + {0xaf94, 1}, + {0xaf95, 1328}, + {0xaf97, 0}, + {0xaf98, 1}, + {0xaf99, 2}, + {0xaf9a, 3}, + {0xaf9b, 4}, + {0xaf9c, 1329}, + {0xaf9e, 0}, + {0xaf9f, 1}, + {0xafa0, 2}, + {0xafa1, 3}, + {0xafa2, 4}, + {0xafa3, 5}, + {0xafa4, 6}, + {0xafa5, 7}, + {0xafa6, 8}, + {0xafa7, 9}, + {0xafa8, 10}, + {0xafa9, 11}, + {0xafaa, 12}, + {0xafab, 13}, + {0xafac, 14}, + {0xafad, 15}, + {0xafae, 16}, + {0xafaf, 17}, + {0xafb0, 18}, + {0xafb1, 19}, + {0xafb2, 20}, + {0xafb3, 21}, + {0xafb4, 22}, + {0xafb5, 23}, + {0xafb6, 24}, + {0xafb7, 25}, + {0xafb8, 1330}, + {0xafb9, 1331}, + {0xafbb, 0}, + {0xafbc, 1332}, + {0xafbe, 0}, + {0xafbf, 1}, + {0xafc0, 1333}, + {0xafc2, 0}, + {0xafc3, 1}, + {0xafc4, 2}, + {0xafc5, 3}, + {0xafc6, 4}, + {0xafc7, 1334}, + {0xafc8, 1335}, + {0xafc9, 1336}, + {0xafcb, 1337}, + {0xafcd, 1338}, + {0xafce, 1339}, + {0xafd0, 0}, + {0xafd1, 1}, + {0xafd2, 2}, + {0xafd3, 3}, + {0xafd4, 1340}, + {0xafd6, 0}, + {0xafd7, 1}, + {0xafd8, 2}, + {0xafd9, 3}, + {0xafda, 4}, + {0xafdb, 5}, + {0xafdc, 1341}, + {0xafde, 0}, + {0xafdf, 1}, + {0xafe0, 2}, + {0xafe1, 3}, + {0xafe2, 4}, + {0xafe3, 5}, + {0xafe4, 6}, + {0xafe5, 7}, + {0xafe6, 8}, + {0xafe7, 9}, + {0xafe8, 1342}, + {0xafe9, 1343}, + {0xafeb, 0}, + {0xafec, 1}, + {0xafed, 2}, + {0xafee, 3}, + {0xafef, 4}, + {0xaff0, 1344}, + {0xaff1, 1345}, + {0xaff3, 0}, + {0xaff4, 1346}, + {0xaff6, 0}, + {0xaff7, 1}, + {0xaff8, 1347}, + {0xaffa, 0}, + {0xaffb, 1}, + {0xaffc, 2}, + {0xaffd, 3}, + {0xaffe, 4}, + {0xafff, 5}, + {0xb000, 1348}, + {0xb001, 1349}, + {0xb003, 0}, + {0xb004, 1350}, + {0xb006, 0}, + {0xb007, 1}, + {0xb008, 2}, + {0xb009, 3}, + {0xb00a, 4}, + {0xb00b, 5}, + {0xb00c, 1351}, + {0xb00e, 0}, + {0xb00f, 1}, + {0xb010, 1352}, + {0xb012, 0}, + {0xb013, 1}, + {0xb014, 1353}, + {0xb016, 0}, + {0xb017, 1}, + {0xb018, 2}, + {0xb019, 3}, + {0xb01a, 4}, + {0xb01b, 5}, + {0xb01c, 1354}, + {0xb01d, 1355}, + {0xb01f, 0}, + {0xb020, 1}, + {0xb021, 2}, + {0xb022, 3}, + {0xb023, 4}, + {0xb024, 5}, + {0xb025, 6}, + {0xb026, 7}, + {0xb027, 8}, + {0xb028, 1356}, + {0xb02a, 0}, + {0xb02b, 1}, + {0xb02c, 2}, + {0xb02d, 3}, + {0xb02e, 4}, + {0xb02f, 5}, + {0xb030, 6}, + {0xb031, 7}, + {0xb032, 8}, + {0xb033, 9}, + {0xb034, 10}, + {0xb035, 11}, + {0xb036, 12}, + {0xb037, 13}, + {0xb038, 14}, + {0xb039, 15}, + {0xb03a, 16}, + {0xb03b, 17}, + {0xb03c, 18}, + {0xb03d, 19}, + {0xb03e, 20}, + {0xb03f, 21}, + {0xb040, 22}, + {0xb041, 23}, + {0xb042, 24}, + {0xb043, 25}, + {0xb044, 1357}, + {0xb045, 1358}, + {0xb047, 0}, + {0xb048, 1359}, + {0xb04a, 1360}, + {0xb04c, 1361}, + {0xb04e, 1362}, + {0xb050, 0}, + {0xb051, 1}, + {0xb052, 2}, + {0xb053, 1363}, + {0xb054, 1364}, + {0xb055, 1365}, + {0xb057, 1366}, + {0xb059, 1367}, + {0xb05b, 0}, + {0xb05c, 1}, + {0xb05d, 1368}, + {0xb05f, 0}, + {0xb060, 1}, + {0xb061, 2}, + {0xb062, 3}, + {0xb063, 4}, + {0xb064, 5}, + {0xb065, 6}, + {0xb066, 7}, + {0xb067, 8}, + {0xb068, 9}, + {0xb069, 10}, + {0xb06a, 11}, + {0xb06b, 12}, + {0xb06c, 13}, + {0xb06d, 14}, + {0xb06e, 15}, + {0xb06f, 16}, + {0xb070, 17}, + {0xb071, 18}, + {0xb072, 19}, + {0xb073, 20}, + {0xb074, 21}, + {0xb075, 22}, + {0xb076, 23}, + {0xb077, 24}, + {0xb078, 25}, + {0xb079, 26}, + {0xb07a, 27}, + {0xb07b, 28}, + {0xb07c, 1369}, + {0xb07d, 1370}, + {0xb07f, 0}, + {0xb080, 1371}, + {0xb082, 0}, + {0xb083, 1}, + {0xb084, 1372}, + {0xb086, 0}, + {0xb087, 1}, + {0xb088, 2}, + {0xb089, 3}, + {0xb08a, 4}, + {0xb08b, 5}, + {0xb08c, 1373}, + {0xb08d, 1374}, + {0xb08f, 1375}, + {0xb091, 1376}, + {0xb093, 0}, + {0xb094, 1}, + {0xb095, 2}, + {0xb096, 3}, + {0xb097, 4}, + {0xb098, 1377}, + {0xb099, 1378}, + {0xb09a, 1379}, + {0xb09c, 1380}, + {0xb09e, 0}, + {0xb09f, 1381}, + {0xb0a0, 1382}, + {0xb0a1, 1383}, + {0xb0a2, 1384}, + {0xb0a4, 0}, + {0xb0a5, 1}, + {0xb0a6, 2}, + {0xb0a7, 3}, + {0xb0a8, 1385}, + {0xb0a9, 1386}, + {0xb0ab, 1387}, + {0xb0ac, 1388}, + {0xb0ad, 1389}, + {0xb0ae, 1390}, + {0xb0af, 1391}, + {0xb0b1, 1392}, + {0xb0b3, 1393}, + {0xb0b4, 1394}, + {0xb0b5, 1395}, + {0xb0b7, 0}, + {0xb0b8, 1396}, + {0xb0ba, 0}, + {0xb0bb, 1}, + {0xb0bc, 1397}, + {0xb0be, 0}, + {0xb0bf, 1}, + {0xb0c0, 2}, + {0xb0c1, 3}, + {0xb0c2, 4}, + {0xb0c3, 5}, + {0xb0c4, 1398}, + {0xb0c5, 1399}, + {0xb0c7, 1400}, + {0xb0c8, 1401}, + {0xb0c9, 1402}, + {0xb0cb, 0}, + {0xb0cc, 1}, + {0xb0cd, 2}, + {0xb0ce, 3}, + {0xb0cf, 4}, + {0xb0d0, 1403}, + {0xb0d1, 1404}, + {0xb0d3, 0}, + {0xb0d4, 1405}, + {0xb0d6, 0}, + {0xb0d7, 1}, + {0xb0d8, 1406}, + {0xb0da, 0}, + {0xb0db, 1}, + {0xb0dc, 2}, + {0xb0dd, 3}, + {0xb0de, 4}, + {0xb0df, 5}, + {0xb0e0, 1407}, + {0xb0e2, 0}, + {0xb0e3, 1}, + {0xb0e4, 2}, + {0xb0e5, 1408}, + {0xb0e7, 0}, + {0xb0e8, 1}, + {0xb0e9, 2}, + {0xb0ea, 3}, + {0xb0eb, 4}, + {0xb0ec, 5}, + {0xb0ed, 6}, + {0xb0ee, 7}, + {0xb0ef, 8}, + {0xb0f0, 9}, + {0xb0f1, 10}, + {0xb0f2, 11}, + {0xb0f3, 12}, + {0xb0f4, 13}, + {0xb0f5, 14}, + {0xb0f6, 15}, + {0xb0f7, 16}, + {0xb0f8, 17}, + {0xb0f9, 18}, + {0xb0fa, 19}, + {0xb0fb, 20}, + {0xb0fc, 21}, + {0xb0fd, 22}, + {0xb0fe, 23}, + {0xb0ff, 24}, + {0xb101, 0}, + {0xb102, 1}, + {0xb103, 2}, + {0xb104, 3}, + {0xb105, 4}, + {0xb106, 5}, + {0xb107, 6}, + {0xb108, 1409}, + {0xb109, 1410}, + {0xb10b, 1411}, + {0xb10c, 1412}, + {0xb10e, 0}, + {0xb10f, 1}, + {0xb110, 1413}, + {0xb112, 1414}, + {0xb113, 1415}, + {0xb115, 0}, + {0xb116, 1}, + {0xb117, 2}, + {0xb118, 1416}, + {0xb119, 1417}, + {0xb11b, 1418}, + {0xb11c, 1419}, + {0xb11d, 1420}, + {0xb11f, 0}, + {0xb120, 1}, + {0xb121, 2}, + {0xb122, 3}, + {0xb123, 1421}, + {0xb124, 1422}, + {0xb125, 1423}, + {0xb127, 0}, + {0xb128, 1424}, + {0xb12a, 0}, + {0xb12b, 1}, + {0xb12c, 1425}, + {0xb12e, 0}, + {0xb12f, 1}, + {0xb130, 2}, + {0xb131, 3}, + {0xb132, 4}, + {0xb133, 5}, + {0xb134, 1426}, + {0xb135, 1427}, + {0xb137, 1428}, + {0xb138, 1429}, + {0xb139, 1430}, + {0xb13b, 0}, + {0xb13c, 1}, + {0xb13d, 2}, + {0xb13e, 3}, + {0xb13f, 4}, + {0xb140, 1431}, + {0xb141, 1432}, + {0xb143, 0}, + {0xb144, 1433}, + {0xb146, 0}, + {0xb147, 1}, + {0xb148, 1434}, + {0xb14a, 0}, + {0xb14b, 1}, + {0xb14c, 2}, + {0xb14d, 3}, + {0xb14e, 4}, + {0xb14f, 5}, + {0xb150, 1435}, + {0xb151, 1436}, + {0xb153, 0}, + {0xb154, 1437}, + {0xb155, 1438}, + {0xb157, 0}, + {0xb158, 1439}, + {0xb15a, 0}, + {0xb15b, 1}, + {0xb15c, 1440}, + {0xb15e, 0}, + {0xb15f, 1}, + {0xb160, 1441}, + {0xb162, 0}, + {0xb163, 1}, + {0xb164, 2}, + {0xb165, 3}, + {0xb166, 4}, + {0xb167, 5}, + {0xb168, 6}, + {0xb169, 7}, + {0xb16a, 8}, + {0xb16b, 9}, + {0xb16c, 10}, + {0xb16d, 11}, + {0xb16e, 12}, + {0xb16f, 13}, + {0xb170, 14}, + {0xb171, 15}, + {0xb172, 16}, + {0xb173, 17}, + {0xb174, 18}, + {0xb175, 19}, + {0xb176, 20}, + {0xb177, 21}, + {0xb178, 1442}, + {0xb179, 1443}, + {0xb17b, 0}, + {0xb17c, 1444}, + {0xb17e, 0}, + {0xb17f, 1}, + {0xb180, 1445}, + {0xb182, 1446}, + {0xb184, 0}, + {0xb185, 1}, + {0xb186, 2}, + {0xb187, 3}, + {0xb188, 1447}, + {0xb189, 1448}, + {0xb18b, 1449}, + {0xb18d, 1450}, + {0xb18f, 0}, + {0xb190, 1}, + {0xb191, 2}, + {0xb192, 1451}, + {0xb193, 1452}, + {0xb194, 1453}, + {0xb196, 0}, + {0xb197, 1}, + {0xb198, 1454}, + {0xb19a, 0}, + {0xb19b, 1}, + {0xb19c, 1455}, + {0xb19e, 0}, + {0xb19f, 1}, + {0xb1a0, 2}, + {0xb1a1, 3}, + {0xb1a2, 4}, + {0xb1a3, 5}, + {0xb1a4, 6}, + {0xb1a5, 7}, + {0xb1a6, 8}, + {0xb1a7, 9}, + {0xb1a8, 1456}, + {0xb1aa, 0}, + {0xb1ab, 1}, + {0xb1ac, 2}, + {0xb1ad, 3}, + {0xb1ae, 4}, + {0xb1af, 5}, + {0xb1b0, 6}, + {0xb1b1, 7}, + {0xb1b2, 8}, + {0xb1b3, 9}, + {0xb1b4, 10}, + {0xb1b5, 11}, + {0xb1b6, 12}, + {0xb1b7, 13}, + {0xb1b8, 14}, + {0xb1b9, 15}, + {0xb1ba, 16}, + {0xb1bb, 17}, + {0xb1bc, 18}, + {0xb1bd, 19}, + {0xb1be, 20}, + {0xb1bf, 21}, + {0xb1c0, 22}, + {0xb1c1, 23}, + {0xb1c2, 24}, + {0xb1c3, 25}, + {0xb1c4, 26}, + {0xb1c5, 27}, + {0xb1c6, 28}, + {0xb1c7, 29}, + {0xb1c8, 30}, + {0xb1c9, 31}, + {0xb1ca, 32}, + {0xb1cb, 33}, + {0xb1cc, 1457}, + {0xb1ce, 0}, + {0xb1cf, 1}, + {0xb1d0, 1458}, + {0xb1d2, 0}, + {0xb1d3, 1}, + {0xb1d4, 1459}, + {0xb1d6, 0}, + {0xb1d7, 1}, + {0xb1d8, 2}, + {0xb1d9, 3}, + {0xb1da, 4}, + {0xb1db, 5}, + {0xb1dc, 1460}, + {0xb1dd, 1461}, + {0xb1df, 1462}, + {0xb1e1, 0}, + {0xb1e2, 1}, + {0xb1e3, 2}, + {0xb1e4, 3}, + {0xb1e5, 4}, + {0xb1e6, 5}, + {0xb1e7, 6}, + {0xb1e8, 1463}, + {0xb1e9, 1464}, + {0xb1eb, 0}, + {0xb1ec, 1465}, + {0xb1ee, 0}, + {0xb1ef, 1}, + {0xb1f0, 1466}, + {0xb1f2, 0}, + {0xb1f3, 1}, + {0xb1f4, 2}, + {0xb1f5, 3}, + {0xb1f6, 4}, + {0xb1f7, 5}, + {0xb1f8, 6}, + {0xb1f9, 1467}, + {0xb1fb, 1468}, + {0xb1fd, 1469}, + {0xb1ff, 0}, + {0xb201, 0}, + {0xb202, 1}, + {0xb203, 2}, + {0xb204, 1470}, + {0xb205, 1471}, + {0xb207, 0}, + {0xb208, 1472}, + {0xb20a, 0}, + {0xb20b, 1473}, + {0xb20c, 1474}, + {0xb20e, 0}, + {0xb20f, 1}, + {0xb210, 2}, + {0xb211, 3}, + {0xb212, 4}, + {0xb213, 5}, + {0xb214, 1475}, + {0xb215, 1476}, + {0xb217, 1477}, + {0xb219, 1478}, + {0xb21b, 0}, + {0xb21c, 1}, + {0xb21d, 2}, + {0xb21e, 3}, + {0xb21f, 4}, + {0xb220, 1479}, + {0xb222, 0}, + {0xb223, 1}, + {0xb224, 2}, + {0xb225, 3}, + {0xb226, 4}, + {0xb227, 5}, + {0xb228, 6}, + {0xb229, 7}, + {0xb22a, 8}, + {0xb22b, 9}, + {0xb22c, 10}, + {0xb22d, 11}, + {0xb22e, 12}, + {0xb22f, 13}, + {0xb230, 14}, + {0xb231, 15}, + {0xb232, 16}, + {0xb233, 17}, + {0xb234, 1480}, + {0xb236, 0}, + {0xb237, 1}, + {0xb238, 2}, + {0xb239, 3}, + {0xb23a, 4}, + {0xb23b, 5}, + {0xb23c, 1481}, + {0xb23e, 0}, + {0xb23f, 1}, + {0xb240, 2}, + {0xb241, 3}, + {0xb242, 4}, + {0xb243, 5}, + {0xb244, 6}, + {0xb245, 7}, + {0xb246, 8}, + {0xb247, 9}, + {0xb248, 10}, + {0xb249, 11}, + {0xb24a, 12}, + {0xb24b, 13}, + {0xb24c, 14}, + {0xb24d, 15}, + {0xb24e, 16}, + {0xb24f, 17}, + {0xb250, 18}, + {0xb251, 19}, + {0xb252, 20}, + {0xb253, 21}, + {0xb254, 22}, + {0xb255, 23}, + {0xb256, 24}, + {0xb257, 25}, + {0xb258, 1482}, + {0xb25a, 0}, + {0xb25b, 1}, + {0xb25c, 1483}, + {0xb25e, 0}, + {0xb25f, 1}, + {0xb260, 1484}, + {0xb262, 0}, + {0xb263, 1}, + {0xb264, 2}, + {0xb265, 3}, + {0xb266, 4}, + {0xb267, 5}, + {0xb268, 1485}, + {0xb269, 1486}, + {0xb26b, 0}, + {0xb26c, 1}, + {0xb26d, 2}, + {0xb26e, 3}, + {0xb26f, 4}, + {0xb270, 5}, + {0xb271, 6}, + {0xb272, 7}, + {0xb273, 8}, + {0xb274, 1487}, + {0xb275, 1488}, + {0xb277, 0}, + {0xb278, 1}, + {0xb279, 2}, + {0xb27a, 3}, + {0xb27b, 4}, + {0xb27c, 1489}, + {0xb27e, 0}, + {0xb27f, 1}, + {0xb280, 2}, + {0xb281, 3}, + {0xb282, 4}, + {0xb283, 5}, + {0xb284, 1490}, + {0xb285, 1491}, + {0xb287, 0}, + {0xb288, 1}, + {0xb289, 1492}, + {0xb28b, 0}, + {0xb28c, 1}, + {0xb28d, 2}, + {0xb28e, 3}, + {0xb28f, 4}, + {0xb290, 1493}, + {0xb291, 1494}, + {0xb293, 0}, + {0xb294, 1495}, + {0xb296, 0}, + {0xb297, 1}, + {0xb298, 1496}, + {0xb299, 1497}, + {0xb29a, 1498}, + {0xb29c, 0}, + {0xb29d, 1}, + {0xb29e, 2}, + {0xb29f, 3}, + {0xb2a0, 1499}, + {0xb2a1, 1500}, + {0xb2a3, 1501}, + {0xb2a5, 1502}, + {0xb2a6, 1503}, + {0xb2a8, 0}, + {0xb2a9, 1}, + {0xb2aa, 1504}, + {0xb2ac, 1505}, + {0xb2ae, 0}, + {0xb2af, 1}, + {0xb2b0, 1506}, + {0xb2b2, 0}, + {0xb2b3, 1}, + {0xb2b4, 1507}, + {0xb2b6, 0}, + {0xb2b7, 1}, + {0xb2b8, 2}, + {0xb2b9, 3}, + {0xb2ba, 4}, + {0xb2bb, 5}, + {0xb2bc, 6}, + {0xb2bd, 7}, + {0xb2be, 8}, + {0xb2bf, 9}, + {0xb2c0, 10}, + {0xb2c1, 11}, + {0xb2c2, 12}, + {0xb2c3, 13}, + {0xb2c4, 14}, + {0xb2c5, 15}, + {0xb2c6, 16}, + {0xb2c7, 17}, + {0xb2c8, 1508}, + {0xb2c9, 1509}, + {0xb2cb, 0}, + {0xb2cc, 1510}, + {0xb2ce, 0}, + {0xb2cf, 1}, + {0xb2d0, 1511}, + {0xb2d2, 1512}, + {0xb2d4, 0}, + {0xb2d5, 1}, + {0xb2d6, 2}, + {0xb2d7, 3}, + {0xb2d8, 1513}, + {0xb2d9, 1514}, + {0xb2db, 1515}, + {0xb2dd, 1516}, + {0xb2df, 0}, + {0xb2e0, 1}, + {0xb2e1, 2}, + {0xb2e2, 1517}, + {0xb2e4, 1518}, + {0xb2e5, 1519}, + {0xb2e6, 1520}, + {0xb2e8, 1521}, + {0xb2ea, 0}, + {0xb2eb, 1522}, + {0xb2ec, 1523}, + {0xb2ed, 1524}, + {0xb2ee, 1525}, + {0xb2ef, 1526}, + {0xb2f1, 0}, + {0xb2f2, 1}, + {0xb2f3, 1527}, + {0xb2f4, 1528}, + {0xb2f5, 1529}, + {0xb2f7, 1530}, + {0xb2f8, 1531}, + {0xb2f9, 1532}, + {0xb2fa, 1533}, + {0xb2fb, 1534}, + {0xb2fd, 0}, + {0xb2fe, 1}, + {0xb2ff, 1535}, + {0xb300, 1536}, + {0xb301, 1537}, + {0xb303, 0}, + {0xb304, 1538}, + {0xb306, 0}, + {0xb307, 1}, + {0xb308, 1539}, + {0xb30a, 0}, + {0xb30b, 1}, + {0xb30c, 2}, + {0xb30d, 3}, + {0xb30e, 4}, + {0xb30f, 5}, + {0xb310, 1540}, + {0xb311, 1541}, + {0xb313, 1542}, + {0xb314, 1543}, + {0xb315, 1544}, + {0xb317, 0}, + {0xb318, 1}, + {0xb319, 2}, + {0xb31a, 3}, + {0xb31b, 4}, + {0xb31c, 1545}, + {0xb31e, 0}, + {0xb31f, 1}, + {0xb320, 2}, + {0xb321, 3}, + {0xb322, 4}, + {0xb323, 5}, + {0xb324, 6}, + {0xb325, 7}, + {0xb326, 8}, + {0xb327, 9}, + {0xb328, 10}, + {0xb329, 11}, + {0xb32a, 12}, + {0xb32b, 13}, + {0xb32c, 14}, + {0xb32d, 15}, + {0xb32e, 16}, + {0xb32f, 17}, + {0xb330, 18}, + {0xb331, 19}, + {0xb332, 20}, + {0xb333, 21}, + {0xb334, 22}, + {0xb335, 23}, + {0xb336, 24}, + {0xb337, 25}, + {0xb338, 26}, + {0xb339, 27}, + {0xb33a, 28}, + {0xb33b, 29}, + {0xb33c, 30}, + {0xb33d, 31}, + {0xb33e, 32}, + {0xb33f, 33}, + {0xb340, 34}, + {0xb341, 35}, + {0xb342, 36}, + {0xb343, 37}, + {0xb344, 38}, + {0xb345, 39}, + {0xb346, 40}, + {0xb347, 41}, + {0xb348, 42}, + {0xb349, 43}, + {0xb34a, 44}, + {0xb34b, 45}, + {0xb34c, 46}, + {0xb34d, 47}, + {0xb34e, 48}, + {0xb34f, 49}, + {0xb350, 50}, + {0xb351, 51}, + {0xb352, 52}, + {0xb353, 53}, + {0xb354, 1546}, + {0xb355, 1547}, + {0xb356, 1548}, + {0xb358, 1549}, + {0xb35a, 0}, + {0xb35b, 1550}, + {0xb35c, 1551}, + {0xb35e, 1552}, + {0xb35f, 1553}, + {0xb361, 0}, + {0xb362, 1}, + {0xb363, 2}, + {0xb364, 1554}, + {0xb365, 1555}, + {0xb367, 1556}, + {0xb369, 1557}, + {0xb36b, 1558}, + {0xb36d, 0}, + {0xb36e, 1559}, + {0xb370, 1560}, + {0xb371, 1561}, + {0xb373, 0}, + {0xb374, 1562}, + {0xb376, 0}, + {0xb377, 1}, + {0xb378, 1563}, + {0xb37a, 0}, + {0xb37b, 1}, + {0xb37c, 2}, + {0xb37d, 3}, + {0xb37e, 4}, + {0xb37f, 5}, + {0xb380, 1564}, + {0xb381, 1565}, + {0xb383, 1566}, + {0xb384, 1567}, + {0xb385, 1568}, + {0xb387, 0}, + {0xb388, 1}, + {0xb389, 2}, + {0xb38a, 3}, + {0xb38b, 4}, + {0xb38c, 1569}, + {0xb38e, 0}, + {0xb38f, 1}, + {0xb390, 1570}, + {0xb392, 0}, + {0xb393, 1}, + {0xb394, 1571}, + {0xb396, 0}, + {0xb397, 1}, + {0xb398, 2}, + {0xb399, 3}, + {0xb39a, 4}, + {0xb39b, 5}, + {0xb39c, 6}, + {0xb39d, 7}, + {0xb39e, 8}, + {0xb39f, 9}, + {0xb3a0, 1572}, + {0xb3a1, 1573}, + {0xb3a3, 0}, + {0xb3a4, 1}, + {0xb3a5, 2}, + {0xb3a6, 3}, + {0xb3a7, 4}, + {0xb3a8, 1574}, + {0xb3aa, 0}, + {0xb3ab, 1}, + {0xb3ac, 1575}, + {0xb3ae, 0}, + {0xb3af, 1}, + {0xb3b0, 2}, + {0xb3b1, 3}, + {0xb3b2, 4}, + {0xb3b3, 5}, + {0xb3b4, 6}, + {0xb3b5, 7}, + {0xb3b6, 8}, + {0xb3b7, 9}, + {0xb3b8, 10}, + {0xb3b9, 11}, + {0xb3ba, 12}, + {0xb3bb, 13}, + {0xb3bc, 14}, + {0xb3bd, 15}, + {0xb3be, 16}, + {0xb3bf, 17}, + {0xb3c0, 18}, + {0xb3c1, 19}, + {0xb3c2, 20}, + {0xb3c3, 21}, + {0xb3c4, 1576}, + {0xb3c5, 1577}, + {0xb3c7, 0}, + {0xb3c8, 1578}, + {0xb3ca, 0}, + {0xb3cb, 1579}, + {0xb3cc, 1580}, + {0xb3ce, 1581}, + {0xb3d0, 1582}, + {0xb3d2, 0}, + {0xb3d3, 1}, + {0xb3d4, 1583}, + {0xb3d5, 1584}, + {0xb3d7, 1585}, + {0xb3d9, 1586}, + {0xb3db, 1587}, + {0xb3dd, 1588}, + {0xb3df, 0}, + {0xb3e0, 1589}, + {0xb3e2, 0}, + {0xb3e3, 1}, + {0xb3e4, 1590}, + {0xb3e6, 0}, + {0xb3e7, 1}, + {0xb3e8, 1591}, + {0xb3ea, 0}, + {0xb3eb, 1}, + {0xb3ec, 2}, + {0xb3ed, 3}, + {0xb3ee, 4}, + {0xb3ef, 5}, + {0xb3f0, 6}, + {0xb3f1, 7}, + {0xb3f2, 8}, + {0xb3f3, 9}, + {0xb3f4, 10}, + {0xb3f5, 11}, + {0xb3f6, 12}, + {0xb3f7, 13}, + {0xb3f8, 14}, + {0xb3f9, 15}, + {0xb3fa, 16}, + {0xb3fb, 17}, + {0xb3fc, 1592}, + {0xb3fe, 0}, + {0xb3ff, 1}, + {0xb401, 0}, + {0xb402, 1}, + {0xb403, 2}, + {0xb404, 3}, + {0xb405, 4}, + {0xb406, 5}, + {0xb407, 6}, + {0xb408, 7}, + {0xb409, 8}, + {0xb40a, 9}, + {0xb40b, 10}, + {0xb40c, 11}, + {0xb40d, 12}, + {0xb40e, 13}, + {0xb40f, 14}, + {0xb410, 1593}, + {0xb412, 0}, + {0xb413, 1}, + {0xb414, 2}, + {0xb415, 3}, + {0xb416, 4}, + {0xb417, 5}, + {0xb418, 1594}, + {0xb41a, 0}, + {0xb41b, 1}, + {0xb41c, 1595}, + {0xb41e, 0}, + {0xb41f, 1}, + {0xb420, 1596}, + {0xb422, 0}, + {0xb423, 1}, + {0xb424, 2}, + {0xb425, 3}, + {0xb426, 4}, + {0xb427, 5}, + {0xb428, 1597}, + {0xb429, 1598}, + {0xb42b, 1599}, + {0xb42d, 0}, + {0xb42e, 1}, + {0xb42f, 2}, + {0xb430, 3}, + {0xb431, 4}, + {0xb432, 5}, + {0xb433, 6}, + {0xb434, 1600}, + {0xb436, 0}, + {0xb437, 1}, + {0xb438, 2}, + {0xb439, 3}, + {0xb43a, 4}, + {0xb43b, 5}, + {0xb43c, 6}, + {0xb43d, 7}, + {0xb43e, 8}, + {0xb43f, 9}, + {0xb440, 10}, + {0xb441, 11}, + {0xb442, 12}, + {0xb443, 13}, + {0xb444, 14}, + {0xb445, 15}, + {0xb446, 16}, + {0xb447, 17}, + {0xb448, 18}, + {0xb449, 19}, + {0xb44a, 20}, + {0xb44b, 21}, + {0xb44c, 22}, + {0xb44d, 23}, + {0xb44e, 24}, + {0xb44f, 25}, + {0xb450, 1601}, + {0xb451, 1602}, + {0xb453, 0}, + {0xb454, 1603}, + {0xb456, 0}, + {0xb457, 1}, + {0xb458, 1604}, + {0xb45a, 0}, + {0xb45b, 1}, + {0xb45c, 2}, + {0xb45d, 3}, + {0xb45e, 4}, + {0xb45f, 5}, + {0xb460, 1605}, + {0xb461, 1606}, + {0xb463, 1607}, + {0xb465, 1608}, + {0xb467, 0}, + {0xb468, 1}, + {0xb469, 2}, + {0xb46a, 3}, + {0xb46b, 4}, + {0xb46c, 1609}, + {0xb46e, 0}, + {0xb46f, 1}, + {0xb470, 2}, + {0xb471, 3}, + {0xb472, 4}, + {0xb473, 5}, + {0xb474, 6}, + {0xb475, 7}, + {0xb476, 8}, + {0xb477, 9}, + {0xb478, 10}, + {0xb479, 11}, + {0xb47a, 12}, + {0xb47b, 13}, + {0xb47c, 14}, + {0xb47d, 15}, + {0xb47e, 16}, + {0xb47f, 17}, + {0xb480, 1610}, + {0xb482, 0}, + {0xb483, 1}, + {0xb484, 2}, + {0xb485, 3}, + {0xb486, 4}, + {0xb487, 5}, + {0xb488, 1611}, + {0xb48a, 0}, + {0xb48b, 1}, + {0xb48c, 2}, + {0xb48d, 3}, + {0xb48e, 4}, + {0xb48f, 5}, + {0xb490, 6}, + {0xb491, 7}, + {0xb492, 8}, + {0xb493, 9}, + {0xb494, 10}, + {0xb495, 11}, + {0xb496, 12}, + {0xb497, 13}, + {0xb498, 14}, + {0xb499, 15}, + {0xb49a, 16}, + {0xb49b, 17}, + {0xb49c, 18}, + {0xb49d, 1612}, + {0xb49f, 0}, + {0xb4a0, 1}, + {0xb4a1, 2}, + {0xb4a2, 3}, + {0xb4a3, 4}, + {0xb4a4, 1613}, + {0xb4a6, 0}, + {0xb4a7, 1}, + {0xb4a8, 1614}, + {0xb4aa, 0}, + {0xb4ab, 1}, + {0xb4ac, 1615}, + {0xb4ae, 0}, + {0xb4af, 1}, + {0xb4b0, 2}, + {0xb4b1, 3}, + {0xb4b2, 4}, + {0xb4b3, 5}, + {0xb4b4, 6}, + {0xb4b5, 1616}, + {0xb4b7, 1617}, + {0xb4b9, 1618}, + {0xb4bb, 0}, + {0xb4bc, 1}, + {0xb4bd, 2}, + {0xb4be, 3}, + {0xb4bf, 4}, + {0xb4c0, 1619}, + {0xb4c2, 0}, + {0xb4c3, 1}, + {0xb4c4, 1620}, + {0xb4c6, 0}, + {0xb4c7, 1}, + {0xb4c8, 1621}, + {0xb4ca, 0}, + {0xb4cb, 1}, + {0xb4cc, 2}, + {0xb4cd, 3}, + {0xb4ce, 4}, + {0xb4cf, 5}, + {0xb4d0, 1622}, + {0xb4d2, 0}, + {0xb4d3, 1}, + {0xb4d4, 2}, + {0xb4d5, 1623}, + {0xb4d7, 0}, + {0xb4d8, 1}, + {0xb4d9, 2}, + {0xb4da, 3}, + {0xb4db, 4}, + {0xb4dc, 1624}, + {0xb4dd, 1625}, + {0xb4df, 0}, + {0xb4e0, 1626}, + {0xb4e2, 0}, + {0xb4e3, 1627}, + {0xb4e4, 1628}, + {0xb4e6, 1629}, + {0xb4e8, 0}, + {0xb4e9, 1}, + {0xb4ea, 2}, + {0xb4eb, 3}, + {0xb4ec, 1630}, + {0xb4ed, 1631}, + {0xb4ef, 1632}, + {0xb4f1, 1633}, + {0xb4f3, 0}, + {0xb4f4, 1}, + {0xb4f5, 2}, + {0xb4f6, 3}, + {0xb4f7, 4}, + {0xb4f8, 1634}, + {0xb4fa, 0}, + {0xb4fb, 1}, + {0xb4fc, 2}, + {0xb4fd, 3}, + {0xb4fe, 4}, + {0xb4ff, 5}, + {0xb501, 0}, + {0xb502, 1}, + {0xb503, 2}, + {0xb504, 3}, + {0xb505, 4}, + {0xb506, 5}, + {0xb507, 6}, + {0xb508, 7}, + {0xb509, 8}, + {0xb50a, 9}, + {0xb50b, 10}, + {0xb50c, 11}, + {0xb50d, 12}, + {0xb50e, 13}, + {0xb50f, 14}, + {0xb510, 15}, + {0xb511, 16}, + {0xb512, 17}, + {0xb513, 18}, + {0xb514, 1635}, + {0xb515, 1636}, + {0xb517, 0}, + {0xb518, 1637}, + {0xb51a, 0}, + {0xb51b, 1638}, + {0xb51c, 1639}, + {0xb51e, 0}, + {0xb51f, 1}, + {0xb520, 2}, + {0xb521, 3}, + {0xb522, 4}, + {0xb523, 5}, + {0xb524, 1640}, + {0xb525, 1641}, + {0xb527, 1642}, + {0xb528, 1643}, + {0xb529, 1644}, + {0xb52a, 1645}, + {0xb52c, 0}, + {0xb52d, 1}, + {0xb52e, 2}, + {0xb52f, 3}, + {0xb530, 1646}, + {0xb531, 1647}, + {0xb533, 0}, + {0xb534, 1648}, + {0xb536, 0}, + {0xb537, 1}, + {0xb538, 1649}, + {0xb53a, 0}, + {0xb53b, 1}, + {0xb53c, 2}, + {0xb53d, 3}, + {0xb53e, 4}, + {0xb53f, 5}, + {0xb540, 1650}, + {0xb541, 1651}, + {0xb543, 1652}, + {0xb544, 1653}, + {0xb545, 1654}, + {0xb547, 0}, + {0xb548, 1}, + {0xb549, 2}, + {0xb54a, 3}, + {0xb54b, 1655}, + {0xb54c, 1656}, + {0xb54d, 1657}, + {0xb54f, 0}, + {0xb550, 1658}, + {0xb552, 0}, + {0xb553, 1}, + {0xb554, 1659}, + {0xb556, 0}, + {0xb557, 1}, + {0xb558, 2}, + {0xb559, 3}, + {0xb55a, 4}, + {0xb55b, 5}, + {0xb55c, 1660}, + {0xb55d, 1661}, + {0xb55f, 1662}, + {0xb560, 1663}, + {0xb561, 1664}, + {0xb563, 0}, + {0xb564, 1}, + {0xb565, 2}, + {0xb566, 3}, + {0xb567, 4}, + {0xb568, 5}, + {0xb569, 6}, + {0xb56a, 7}, + {0xb56b, 8}, + {0xb56c, 9}, + {0xb56d, 10}, + {0xb56e, 11}, + {0xb56f, 12}, + {0xb570, 13}, + {0xb571, 14}, + {0xb572, 15}, + {0xb573, 16}, + {0xb574, 17}, + {0xb575, 18}, + {0xb576, 19}, + {0xb577, 20}, + {0xb578, 21}, + {0xb579, 22}, + {0xb57a, 23}, + {0xb57b, 24}, + {0xb57c, 25}, + {0xb57d, 26}, + {0xb57e, 27}, + {0xb57f, 28}, + {0xb580, 29}, + {0xb581, 30}, + {0xb582, 31}, + {0xb583, 32}, + {0xb584, 33}, + {0xb585, 34}, + {0xb586, 35}, + {0xb587, 36}, + {0xb588, 37}, + {0xb589, 38}, + {0xb58a, 39}, + {0xb58b, 40}, + {0xb58c, 41}, + {0xb58d, 42}, + {0xb58e, 43}, + {0xb58f, 44}, + {0xb590, 45}, + {0xb591, 46}, + {0xb592, 47}, + {0xb593, 48}, + {0xb594, 49}, + {0xb595, 50}, + {0xb596, 51}, + {0xb597, 52}, + {0xb598, 53}, + {0xb599, 54}, + {0xb59a, 55}, + {0xb59b, 56}, + {0xb59c, 57}, + {0xb59d, 58}, + {0xb59e, 59}, + {0xb59f, 60}, + {0xb5a0, 1665}, + {0xb5a1, 1666}, + {0xb5a3, 0}, + {0xb5a4, 1667}, + {0xb5a6, 0}, + {0xb5a7, 1}, + {0xb5a8, 1668}, + {0xb5aa, 1669}, + {0xb5ab, 1670}, + {0xb5ad, 0}, + {0xb5ae, 1}, + {0xb5af, 2}, + {0xb5b0, 1671}, + {0xb5b1, 1672}, + {0xb5b3, 1673}, + {0xb5b4, 1674}, + {0xb5b5, 1675}, + {0xb5b7, 0}, + {0xb5b8, 1}, + {0xb5b9, 2}, + {0xb5ba, 3}, + {0xb5bb, 1676}, + {0xb5bc, 1677}, + {0xb5bd, 1678}, + {0xb5bf, 0}, + {0xb5c0, 1679}, + {0xb5c2, 0}, + {0xb5c3, 1}, + {0xb5c4, 1680}, + {0xb5c6, 0}, + {0xb5c7, 1}, + {0xb5c8, 2}, + {0xb5c9, 3}, + {0xb5ca, 4}, + {0xb5cb, 5}, + {0xb5cc, 1681}, + {0xb5cd, 1682}, + {0xb5cf, 1683}, + {0xb5d0, 1684}, + {0xb5d1, 1685}, + {0xb5d3, 0}, + {0xb5d4, 1}, + {0xb5d5, 2}, + {0xb5d6, 3}, + {0xb5d7, 4}, + {0xb5d8, 1686}, + {0xb5da, 0}, + {0xb5db, 1}, + {0xb5dc, 2}, + {0xb5dd, 3}, + {0xb5de, 4}, + {0xb5df, 5}, + {0xb5e0, 6}, + {0xb5e1, 7}, + {0xb5e2, 8}, + {0xb5e3, 9}, + {0xb5e4, 10}, + {0xb5e5, 11}, + {0xb5e6, 12}, + {0xb5e7, 13}, + {0xb5e8, 14}, + {0xb5e9, 15}, + {0xb5ea, 16}, + {0xb5eb, 17}, + {0xb5ec, 1687}, + {0xb5ee, 0}, + {0xb5ef, 1}, + {0xb5f0, 2}, + {0xb5f1, 3}, + {0xb5f2, 4}, + {0xb5f3, 5}, + {0xb5f4, 6}, + {0xb5f5, 7}, + {0xb5f6, 8}, + {0xb5f7, 9}, + {0xb5f8, 10}, + {0xb5f9, 11}, + {0xb5fa, 12}, + {0xb5fb, 13}, + {0xb5fc, 14}, + {0xb5fd, 15}, + {0xb5fe, 16}, + {0xb5ff, 17}, + {0xb601, 0}, + {0xb602, 1}, + {0xb603, 2}, + {0xb604, 3}, + {0xb605, 4}, + {0xb606, 5}, + {0xb607, 6}, + {0xb608, 7}, + {0xb609, 8}, + {0xb60a, 9}, + {0xb60b, 10}, + {0xb60c, 11}, + {0xb60d, 12}, + {0xb60e, 13}, + {0xb60f, 14}, + {0xb610, 1688}, + {0xb611, 1689}, + {0xb613, 0}, + {0xb614, 1690}, + {0xb616, 0}, + {0xb617, 1}, + {0xb618, 1691}, + {0xb61a, 0}, + {0xb61b, 1}, + {0xb61c, 2}, + {0xb61d, 3}, + {0xb61e, 4}, + {0xb61f, 5}, + {0xb620, 6}, + {0xb621, 7}, + {0xb622, 8}, + {0xb623, 9}, + {0xb624, 10}, + {0xb625, 1692}, + {0xb627, 0}, + {0xb628, 1}, + {0xb629, 2}, + {0xb62a, 3}, + {0xb62b, 4}, + {0xb62c, 1693}, + {0xb62e, 0}, + {0xb62f, 1}, + {0xb630, 2}, + {0xb631, 3}, + {0xb632, 4}, + {0xb633, 5}, + {0xb634, 1694}, + {0xb636, 0}, + {0xb637, 1}, + {0xb638, 2}, + {0xb639, 3}, + {0xb63a, 4}, + {0xb63b, 5}, + {0xb63c, 6}, + {0xb63d, 7}, + {0xb63e, 8}, + {0xb63f, 9}, + {0xb640, 10}, + {0xb641, 11}, + {0xb642, 12}, + {0xb643, 13}, + {0xb644, 14}, + {0xb645, 15}, + {0xb646, 16}, + {0xb647, 17}, + {0xb648, 1695}, + {0xb64a, 0}, + {0xb64b, 1}, + {0xb64c, 2}, + {0xb64d, 3}, + {0xb64e, 4}, + {0xb64f, 5}, + {0xb650, 6}, + {0xb651, 7}, + {0xb652, 8}, + {0xb653, 9}, + {0xb654, 10}, + {0xb655, 11}, + {0xb656, 12}, + {0xb657, 13}, + {0xb658, 14}, + {0xb659, 15}, + {0xb65a, 16}, + {0xb65b, 17}, + {0xb65c, 18}, + {0xb65d, 19}, + {0xb65e, 20}, + {0xb65f, 21}, + {0xb660, 22}, + {0xb661, 23}, + {0xb662, 24}, + {0xb663, 25}, + {0xb664, 1696}, + {0xb666, 0}, + {0xb667, 1}, + {0xb668, 1697}, + {0xb66a, 0}, + {0xb66b, 1}, + {0xb66c, 2}, + {0xb66d, 3}, + {0xb66e, 4}, + {0xb66f, 5}, + {0xb670, 6}, + {0xb671, 7}, + {0xb672, 8}, + {0xb673, 9}, + {0xb674, 10}, + {0xb675, 11}, + {0xb676, 12}, + {0xb677, 13}, + {0xb678, 14}, + {0xb679, 15}, + {0xb67a, 16}, + {0xb67b, 17}, + {0xb67c, 18}, + {0xb67d, 19}, + {0xb67e, 20}, + {0xb67f, 21}, + {0xb680, 22}, + {0xb681, 23}, + {0xb682, 24}, + {0xb683, 25}, + {0xb684, 26}, + {0xb685, 27}, + {0xb686, 28}, + {0xb687, 29}, + {0xb688, 30}, + {0xb689, 31}, + {0xb68a, 32}, + {0xb68b, 33}, + {0xb68c, 34}, + {0xb68d, 35}, + {0xb68e, 36}, + {0xb68f, 37}, + {0xb690, 38}, + {0xb691, 39}, + {0xb692, 40}, + {0xb693, 41}, + {0xb694, 42}, + {0xb695, 43}, + {0xb696, 44}, + {0xb697, 45}, + {0xb698, 46}, + {0xb699, 47}, + {0xb69a, 48}, + {0xb69b, 49}, + {0xb69c, 1698}, + {0xb69d, 1699}, + {0xb69f, 0}, + {0xb6a0, 1700}, + {0xb6a2, 0}, + {0xb6a3, 1}, + {0xb6a4, 1701}, + {0xb6a6, 0}, + {0xb6a7, 1}, + {0xb6a8, 2}, + {0xb6a9, 3}, + {0xb6aa, 4}, + {0xb6ab, 1702}, + {0xb6ac, 1703}, + {0xb6ae, 0}, + {0xb6af, 1}, + {0xb6b0, 2}, + {0xb6b1, 1704}, + {0xb6b3, 0}, + {0xb6b4, 1}, + {0xb6b5, 2}, + {0xb6b6, 3}, + {0xb6b7, 4}, + {0xb6b8, 5}, + {0xb6b9, 6}, + {0xb6ba, 7}, + {0xb6bb, 8}, + {0xb6bc, 9}, + {0xb6bd, 10}, + {0xb6be, 11}, + {0xb6bf, 12}, + {0xb6c0, 13}, + {0xb6c1, 14}, + {0xb6c2, 15}, + {0xb6c3, 16}, + {0xb6c4, 17}, + {0xb6c5, 18}, + {0xb6c6, 19}, + {0xb6c7, 20}, + {0xb6c8, 21}, + {0xb6c9, 22}, + {0xb6ca, 23}, + {0xb6cb, 24}, + {0xb6cc, 25}, + {0xb6cd, 26}, + {0xb6ce, 27}, + {0xb6cf, 28}, + {0xb6d0, 29}, + {0xb6d1, 30}, + {0xb6d2, 31}, + {0xb6d3, 32}, + {0xb6d4, 1705}, + {0xb6d6, 0}, + {0xb6d7, 1}, + {0xb6d8, 2}, + {0xb6d9, 3}, + {0xb6da, 4}, + {0xb6db, 5}, + {0xb6dc, 6}, + {0xb6dd, 7}, + {0xb6de, 8}, + {0xb6df, 9}, + {0xb6e0, 10}, + {0xb6e1, 11}, + {0xb6e2, 12}, + {0xb6e3, 13}, + {0xb6e4, 14}, + {0xb6e5, 15}, + {0xb6e6, 16}, + {0xb6e7, 17}, + {0xb6e8, 18}, + {0xb6e9, 19}, + {0xb6ea, 20}, + {0xb6eb, 21}, + {0xb6ec, 22}, + {0xb6ed, 23}, + {0xb6ee, 24}, + {0xb6ef, 25}, + {0xb6f0, 1706}, + {0xb6f2, 0}, + {0xb6f3, 1}, + {0xb6f4, 1707}, + {0xb6f6, 0}, + {0xb6f7, 1}, + {0xb6f8, 1708}, + {0xb6fa, 0}, + {0xb6fb, 1}, + {0xb6fc, 2}, + {0xb6fd, 3}, + {0xb6fe, 4}, + {0xb6ff, 5}, + {0xb700, 1709}, + {0xb701, 1710}, + {0xb703, 0}, + {0xb704, 1}, + {0xb705, 1711}, + {0xb707, 0}, + {0xb708, 1}, + {0xb709, 2}, + {0xb70a, 3}, + {0xb70b, 4}, + {0xb70c, 5}, + {0xb70d, 6}, + {0xb70e, 7}, + {0xb70f, 8}, + {0xb710, 9}, + {0xb711, 10}, + {0xb712, 11}, + {0xb713, 12}, + {0xb714, 13}, + {0xb715, 14}, + {0xb716, 15}, + {0xb717, 16}, + {0xb718, 17}, + {0xb719, 18}, + {0xb71a, 19}, + {0xb71b, 20}, + {0xb71c, 21}, + {0xb71d, 22}, + {0xb71e, 23}, + {0xb71f, 24}, + {0xb720, 25}, + {0xb721, 26}, + {0xb722, 27}, + {0xb723, 28}, + {0xb724, 29}, + {0xb725, 30}, + {0xb726, 31}, + {0xb727, 32}, + {0xb728, 1712}, + {0xb729, 1713}, + {0xb72b, 0}, + {0xb72c, 1714}, + {0xb72e, 0}, + {0xb72f, 1715}, + {0xb730, 1716}, + {0xb732, 0}, + {0xb733, 1}, + {0xb734, 2}, + {0xb735, 3}, + {0xb736, 4}, + {0xb737, 5}, + {0xb738, 1717}, + {0xb739, 1718}, + {0xb73b, 1719}, + {0xb73d, 0}, + {0xb73e, 1}, + {0xb73f, 2}, + {0xb740, 3}, + {0xb741, 4}, + {0xb742, 5}, + {0xb743, 6}, + {0xb744, 1720}, + {0xb746, 0}, + {0xb747, 1}, + {0xb748, 1721}, + {0xb74a, 0}, + {0xb74b, 1}, + {0xb74c, 1722}, + {0xb74e, 0}, + {0xb74f, 1}, + {0xb750, 2}, + {0xb751, 3}, + {0xb752, 4}, + {0xb753, 5}, + {0xb754, 1723}, + {0xb755, 1724}, + {0xb757, 0}, + {0xb758, 1}, + {0xb759, 2}, + {0xb75a, 3}, + {0xb75b, 4}, + {0xb75c, 5}, + {0xb75d, 6}, + {0xb75e, 7}, + {0xb75f, 8}, + {0xb760, 1725}, + {0xb762, 0}, + {0xb763, 1}, + {0xb764, 1726}, + {0xb766, 0}, + {0xb767, 1}, + {0xb768, 1727}, + {0xb76a, 0}, + {0xb76b, 1}, + {0xb76c, 2}, + {0xb76d, 3}, + {0xb76e, 4}, + {0xb76f, 5}, + {0xb770, 1728}, + {0xb771, 1729}, + {0xb773, 1730}, + {0xb775, 1731}, + {0xb777, 0}, + {0xb778, 1}, + {0xb779, 2}, + {0xb77a, 3}, + {0xb77b, 4}, + {0xb77c, 1732}, + {0xb77d, 1733}, + {0xb77f, 0}, + {0xb780, 1734}, + {0xb782, 0}, + {0xb783, 1}, + {0xb784, 1735}, + {0xb786, 0}, + {0xb787, 1}, + {0xb788, 2}, + {0xb789, 3}, + {0xb78a, 4}, + {0xb78b, 5}, + {0xb78c, 1736}, + {0xb78d, 1737}, + {0xb78f, 1738}, + {0xb790, 1739}, + {0xb791, 1740}, + {0xb792, 1741}, + {0xb794, 0}, + {0xb795, 1}, + {0xb796, 1742}, + {0xb797, 1743}, + {0xb798, 1744}, + {0xb799, 1745}, + {0xb79b, 0}, + {0xb79c, 1746}, + {0xb79e, 0}, + {0xb79f, 1}, + {0xb7a0, 1747}, + {0xb7a2, 0}, + {0xb7a3, 1}, + {0xb7a4, 2}, + {0xb7a5, 3}, + {0xb7a6, 4}, + {0xb7a7, 5}, + {0xb7a8, 1748}, + {0xb7a9, 1749}, + {0xb7ab, 1750}, + {0xb7ac, 1751}, + {0xb7ad, 1752}, + {0xb7af, 0}, + {0xb7b0, 1}, + {0xb7b1, 2}, + {0xb7b2, 3}, + {0xb7b3, 4}, + {0xb7b4, 1753}, + {0xb7b5, 1754}, + {0xb7b7, 0}, + {0xb7b8, 1755}, + {0xb7ba, 0}, + {0xb7bb, 1}, + {0xb7bc, 2}, + {0xb7bd, 3}, + {0xb7be, 4}, + {0xb7bf, 5}, + {0xb7c0, 6}, + {0xb7c1, 7}, + {0xb7c2, 8}, + {0xb7c3, 9}, + {0xb7c4, 10}, + {0xb7c5, 11}, + {0xb7c6, 12}, + {0xb7c7, 1756}, + {0xb7c9, 1757}, + {0xb7cb, 0}, + {0xb7cc, 1}, + {0xb7cd, 2}, + {0xb7ce, 3}, + {0xb7cf, 4}, + {0xb7d0, 5}, + {0xb7d1, 6}, + {0xb7d2, 7}, + {0xb7d3, 8}, + {0xb7d4, 9}, + {0xb7d5, 10}, + {0xb7d6, 11}, + {0xb7d7, 12}, + {0xb7d8, 13}, + {0xb7d9, 14}, + {0xb7da, 15}, + {0xb7db, 16}, + {0xb7dc, 17}, + {0xb7dd, 18}, + {0xb7de, 19}, + {0xb7df, 20}, + {0xb7e0, 21}, + {0xb7e1, 22}, + {0xb7e2, 23}, + {0xb7e3, 24}, + {0xb7e4, 25}, + {0xb7e5, 26}, + {0xb7e6, 27}, + {0xb7e7, 28}, + {0xb7e8, 29}, + {0xb7e9, 30}, + {0xb7ea, 31}, + {0xb7eb, 32}, + {0xb7ec, 1758}, + {0xb7ed, 1759}, + {0xb7ef, 0}, + {0xb7f0, 1760}, + {0xb7f2, 0}, + {0xb7f3, 1}, + {0xb7f4, 1761}, + {0xb7f6, 0}, + {0xb7f7, 1}, + {0xb7f8, 2}, + {0xb7f9, 3}, + {0xb7fa, 4}, + {0xb7fb, 5}, + {0xb7fc, 1762}, + {0xb7fd, 1763}, + {0xb7ff, 1764}, + {0xb800, 1765}, + {0xb801, 1766}, + {0xb803, 0}, + {0xb804, 1}, + {0xb805, 2}, + {0xb806, 3}, + {0xb807, 1767}, + {0xb808, 1768}, + {0xb809, 1769}, + {0xb80b, 0}, + {0xb80c, 1770}, + {0xb80e, 0}, + {0xb80f, 1}, + {0xb810, 1771}, + {0xb812, 0}, + {0xb813, 1}, + {0xb814, 2}, + {0xb815, 3}, + {0xb816, 4}, + {0xb817, 5}, + {0xb818, 1772}, + {0xb819, 1773}, + {0xb81b, 1774}, + {0xb81d, 1775}, + {0xb81f, 0}, + {0xb820, 1}, + {0xb821, 2}, + {0xb822, 3}, + {0xb823, 4}, + {0xb824, 1776}, + {0xb825, 1777}, + {0xb827, 0}, + {0xb828, 1778}, + {0xb82a, 0}, + {0xb82b, 1}, + {0xb82c, 1779}, + {0xb82e, 0}, + {0xb82f, 1}, + {0xb830, 2}, + {0xb831, 3}, + {0xb832, 4}, + {0xb833, 5}, + {0xb834, 1780}, + {0xb835, 1781}, + {0xb837, 1782}, + {0xb838, 1783}, + {0xb839, 1784}, + {0xb83b, 0}, + {0xb83c, 1}, + {0xb83d, 2}, + {0xb83e, 3}, + {0xb83f, 4}, + {0xb840, 1785}, + {0xb842, 0}, + {0xb843, 1}, + {0xb844, 1786}, + {0xb846, 0}, + {0xb847, 1}, + {0xb848, 2}, + {0xb849, 3}, + {0xb84a, 4}, + {0xb84b, 5}, + {0xb84c, 6}, + {0xb84d, 7}, + {0xb84e, 8}, + {0xb84f, 9}, + {0xb850, 10}, + {0xb851, 1787}, + {0xb853, 1788}, + {0xb855, 0}, + {0xb856, 1}, + {0xb857, 2}, + {0xb858, 3}, + {0xb859, 4}, + {0xb85a, 5}, + {0xb85b, 6}, + {0xb85c, 1789}, + {0xb85d, 1790}, + {0xb85f, 0}, + {0xb860, 1791}, + {0xb862, 0}, + {0xb863, 1}, + {0xb864, 1792}, + {0xb866, 0}, + {0xb867, 1}, + {0xb868, 2}, + {0xb869, 3}, + {0xb86a, 4}, + {0xb86b, 5}, + {0xb86c, 1793}, + {0xb86d, 1794}, + {0xb86f, 1795}, + {0xb871, 1796}, + {0xb873, 0}, + {0xb874, 1}, + {0xb875, 2}, + {0xb876, 3}, + {0xb877, 4}, + {0xb878, 1797}, + {0xb87a, 0}, + {0xb87b, 1}, + {0xb87c, 1798}, + {0xb87e, 0}, + {0xb87f, 1}, + {0xb880, 2}, + {0xb881, 3}, + {0xb882, 4}, + {0xb883, 5}, + {0xb884, 6}, + {0xb885, 7}, + {0xb886, 8}, + {0xb887, 9}, + {0xb888, 10}, + {0xb889, 11}, + {0xb88a, 12}, + {0xb88b, 13}, + {0xb88c, 14}, + {0xb88d, 1799}, + {0xb88f, 0}, + {0xb890, 1}, + {0xb891, 2}, + {0xb892, 3}, + {0xb893, 4}, + {0xb894, 5}, + {0xb895, 6}, + {0xb896, 7}, + {0xb897, 8}, + {0xb898, 9}, + {0xb899, 10}, + {0xb89a, 11}, + {0xb89b, 12}, + {0xb89c, 13}, + {0xb89d, 14}, + {0xb89e, 15}, + {0xb89f, 16}, + {0xb8a0, 17}, + {0xb8a1, 18}, + {0xb8a2, 19}, + {0xb8a3, 20}, + {0xb8a4, 21}, + {0xb8a5, 22}, + {0xb8a6, 23}, + {0xb8a7, 24}, + {0xb8a8, 1800}, + {0xb8aa, 0}, + {0xb8ab, 1}, + {0xb8ac, 2}, + {0xb8ad, 3}, + {0xb8ae, 4}, + {0xb8af, 5}, + {0xb8b0, 1801}, + {0xb8b2, 0}, + {0xb8b3, 1}, + {0xb8b4, 1802}, + {0xb8b6, 0}, + {0xb8b7, 1}, + {0xb8b8, 1803}, + {0xb8ba, 0}, + {0xb8bb, 1}, + {0xb8bc, 2}, + {0xb8bd, 3}, + {0xb8be, 4}, + {0xb8bf, 5}, + {0xb8c0, 1804}, + {0xb8c1, 1805}, + {0xb8c3, 1806}, + {0xb8c5, 1807}, + {0xb8c7, 0}, + {0xb8c8, 1}, + {0xb8c9, 2}, + {0xb8ca, 3}, + {0xb8cb, 4}, + {0xb8cc, 1808}, + {0xb8ce, 0}, + {0xb8cf, 1}, + {0xb8d0, 1809}, + {0xb8d2, 0}, + {0xb8d3, 1}, + {0xb8d4, 1810}, + {0xb8d6, 0}, + {0xb8d7, 1}, + {0xb8d8, 2}, + {0xb8d9, 3}, + {0xb8da, 4}, + {0xb8db, 5}, + {0xb8dc, 6}, + {0xb8dd, 1811}, + {0xb8df, 1812}, + {0xb8e1, 1813}, + {0xb8e3, 0}, + {0xb8e4, 1}, + {0xb8e5, 2}, + {0xb8e6, 3}, + {0xb8e7, 4}, + {0xb8e8, 1814}, + {0xb8e9, 1815}, + {0xb8eb, 0}, + {0xb8ec, 1816}, + {0xb8ee, 0}, + {0xb8ef, 1}, + {0xb8f0, 1817}, + {0xb8f2, 0}, + {0xb8f3, 1}, + {0xb8f4, 2}, + {0xb8f5, 3}, + {0xb8f6, 4}, + {0xb8f7, 5}, + {0xb8f8, 1818}, + {0xb8f9, 1819}, + {0xb8fb, 1820}, + {0xb8fd, 1821}, + {0xb8ff, 0}, + {0xb901, 0}, + {0xb902, 1}, + {0xb903, 2}, + {0xb904, 1822}, + {0xb906, 0}, + {0xb907, 1}, + {0xb908, 2}, + {0xb909, 3}, + {0xb90a, 4}, + {0xb90b, 5}, + {0xb90c, 6}, + {0xb90d, 7}, + {0xb90e, 8}, + {0xb90f, 9}, + {0xb910, 10}, + {0xb911, 11}, + {0xb912, 12}, + {0xb913, 13}, + {0xb914, 14}, + {0xb915, 15}, + {0xb916, 16}, + {0xb917, 17}, + {0xb918, 1823}, + {0xb91a, 0}, + {0xb91b, 1}, + {0xb91c, 2}, + {0xb91d, 3}, + {0xb91e, 4}, + {0xb91f, 5}, + {0xb920, 1824}, + {0xb922, 0}, + {0xb923, 1}, + {0xb924, 2}, + {0xb925, 3}, + {0xb926, 4}, + {0xb927, 5}, + {0xb928, 6}, + {0xb929, 7}, + {0xb92a, 8}, + {0xb92b, 9}, + {0xb92c, 10}, + {0xb92d, 11}, + {0xb92e, 12}, + {0xb92f, 13}, + {0xb930, 14}, + {0xb931, 15}, + {0xb932, 16}, + {0xb933, 17}, + {0xb934, 18}, + {0xb935, 19}, + {0xb936, 20}, + {0xb937, 21}, + {0xb938, 22}, + {0xb939, 23}, + {0xb93a, 24}, + {0xb93b, 25}, + {0xb93c, 1825}, + {0xb93d, 1826}, + {0xb93f, 0}, + {0xb940, 1827}, + {0xb942, 0}, + {0xb943, 1}, + {0xb944, 1828}, + {0xb946, 0}, + {0xb947, 1}, + {0xb948, 2}, + {0xb949, 3}, + {0xb94a, 4}, + {0xb94b, 5}, + {0xb94c, 1829}, + {0xb94e, 0}, + {0xb94f, 1830}, + {0xb951, 1831}, + {0xb953, 0}, + {0xb954, 1}, + {0xb955, 2}, + {0xb956, 3}, + {0xb957, 4}, + {0xb958, 1832}, + {0xb959, 1833}, + {0xb95b, 0}, + {0xb95c, 1834}, + {0xb95e, 0}, + {0xb95f, 1}, + {0xb960, 1835}, + {0xb962, 0}, + {0xb963, 1}, + {0xb964, 2}, + {0xb965, 3}, + {0xb966, 4}, + {0xb967, 5}, + {0xb968, 1836}, + {0xb969, 1837}, + {0xb96b, 1838}, + {0xb96d, 1839}, + {0xb96f, 0}, + {0xb970, 1}, + {0xb971, 2}, + {0xb972, 3}, + {0xb973, 4}, + {0xb974, 1840}, + {0xb975, 1841}, + {0xb977, 0}, + {0xb978, 1842}, + {0xb97a, 0}, + {0xb97b, 1}, + {0xb97c, 1843}, + {0xb97e, 0}, + {0xb97f, 1}, + {0xb980, 2}, + {0xb981, 3}, + {0xb982, 4}, + {0xb983, 5}, + {0xb984, 1844}, + {0xb985, 1845}, + {0xb987, 1846}, + {0xb989, 1847}, + {0xb98a, 1848}, + {0xb98c, 0}, + {0xb98d, 1849}, + {0xb98e, 1850}, + {0xb990, 0}, + {0xb991, 1}, + {0xb992, 2}, + {0xb993, 3}, + {0xb994, 4}, + {0xb995, 5}, + {0xb996, 6}, + {0xb997, 7}, + {0xb998, 8}, + {0xb999, 9}, + {0xb99a, 10}, + {0xb99b, 11}, + {0xb99c, 12}, + {0xb99d, 13}, + {0xb99e, 14}, + {0xb99f, 15}, + {0xb9a0, 16}, + {0xb9a1, 17}, + {0xb9a2, 18}, + {0xb9a3, 19}, + {0xb9a4, 20}, + {0xb9a5, 21}, + {0xb9a6, 22}, + {0xb9a7, 23}, + {0xb9a8, 24}, + {0xb9a9, 25}, + {0xb9aa, 26}, + {0xb9ab, 27}, + {0xb9ac, 1851}, + {0xb9ad, 1852}, + {0xb9af, 0}, + {0xb9b0, 1853}, + {0xb9b2, 0}, + {0xb9b3, 1}, + {0xb9b4, 1854}, + {0xb9b6, 0}, + {0xb9b7, 1}, + {0xb9b8, 2}, + {0xb9b9, 3}, + {0xb9ba, 4}, + {0xb9bb, 5}, + {0xb9bc, 1855}, + {0xb9bd, 1856}, + {0xb9bf, 1857}, + {0xb9c1, 1858}, + {0xb9c3, 0}, + {0xb9c4, 1}, + {0xb9c5, 2}, + {0xb9c6, 3}, + {0xb9c7, 4}, + {0xb9c8, 1859}, + {0xb9c9, 1860}, + {0xb9cb, 0}, + {0xb9cc, 1861}, + {0xb9ce, 1862}, + {0xb9cf, 1863}, + {0xb9d0, 1864}, + {0xb9d1, 1865}, + {0xb9d2, 1866}, + {0xb9d4, 0}, + {0xb9d5, 1}, + {0xb9d6, 2}, + {0xb9d7, 3}, + {0xb9d8, 1867}, + {0xb9d9, 1868}, + {0xb9db, 1869}, + {0xb9dd, 1870}, + {0xb9de, 1871}, + {0xb9e0, 0}, + {0xb9e1, 1872}, + {0xb9e3, 1873}, + {0xb9e4, 1874}, + {0xb9e5, 1875}, + {0xb9e7, 0}, + {0xb9e8, 1876}, + {0xb9ea, 0}, + {0xb9eb, 1}, + {0xb9ec, 1877}, + {0xb9ee, 0}, + {0xb9ef, 1}, + {0xb9f0, 2}, + {0xb9f1, 3}, + {0xb9f2, 4}, + {0xb9f3, 5}, + {0xb9f4, 1878}, + {0xb9f5, 1879}, + {0xb9f7, 1880}, + {0xb9f8, 1881}, + {0xb9f9, 1882}, + {0xb9fa, 1883}, + {0xb9fc, 0}, + {0xb9fd, 1}, + {0xb9fe, 2}, + {0xb9ff, 3}, + {0xba00, 1884}, + {0xba01, 1885}, + {0xba03, 0}, + {0xba04, 1}, + {0xba05, 2}, + {0xba06, 3}, + {0xba07, 4}, + {0xba08, 1886}, + {0xba0a, 0}, + {0xba0b, 1}, + {0xba0c, 2}, + {0xba0d, 3}, + {0xba0e, 4}, + {0xba0f, 5}, + {0xba10, 6}, + {0xba11, 7}, + {0xba12, 8}, + {0xba13, 9}, + {0xba14, 10}, + {0xba15, 1887}, + {0xba17, 0}, + {0xba18, 1}, + {0xba19, 2}, + {0xba1a, 3}, + {0xba1b, 4}, + {0xba1c, 5}, + {0xba1d, 6}, + {0xba1e, 7}, + {0xba1f, 8}, + {0xba20, 9}, + {0xba21, 10}, + {0xba22, 11}, + {0xba23, 12}, + {0xba24, 13}, + {0xba25, 14}, + {0xba26, 15}, + {0xba27, 16}, + {0xba28, 17}, + {0xba29, 18}, + {0xba2a, 19}, + {0xba2b, 20}, + {0xba2c, 21}, + {0xba2d, 22}, + {0xba2e, 23}, + {0xba2f, 24}, + {0xba30, 25}, + {0xba31, 26}, + {0xba32, 27}, + {0xba33, 28}, + {0xba34, 29}, + {0xba35, 30}, + {0xba36, 31}, + {0xba37, 32}, + {0xba38, 1888}, + {0xba39, 1889}, + {0xba3b, 0}, + {0xba3c, 1890}, + {0xba3e, 0}, + {0xba3f, 1}, + {0xba40, 1891}, + {0xba42, 1892}, + {0xba44, 0}, + {0xba45, 1}, + {0xba46, 2}, + {0xba47, 3}, + {0xba48, 1893}, + {0xba49, 1894}, + {0xba4b, 1895}, + {0xba4d, 1896}, + {0xba4e, 1897}, + {0xba50, 0}, + {0xba51, 1}, + {0xba52, 2}, + {0xba53, 1898}, + {0xba54, 1899}, + {0xba55, 1900}, + {0xba57, 0}, + {0xba58, 1901}, + {0xba5a, 0}, + {0xba5b, 1}, + {0xba5c, 1902}, + {0xba5e, 0}, + {0xba5f, 1}, + {0xba60, 2}, + {0xba61, 3}, + {0xba62, 4}, + {0xba63, 5}, + {0xba64, 1903}, + {0xba65, 1904}, + {0xba67, 1905}, + {0xba68, 1906}, + {0xba69, 1907}, + {0xba6b, 0}, + {0xba6c, 1}, + {0xba6d, 2}, + {0xba6e, 3}, + {0xba6f, 4}, + {0xba70, 1908}, + {0xba71, 1909}, + {0xba73, 0}, + {0xba74, 1910}, + {0xba76, 0}, + {0xba77, 1}, + {0xba78, 1911}, + {0xba7a, 0}, + {0xba7b, 1}, + {0xba7c, 2}, + {0xba7d, 3}, + {0xba7e, 4}, + {0xba7f, 5}, + {0xba80, 6}, + {0xba81, 7}, + {0xba82, 8}, + {0xba83, 1912}, + {0xba84, 1913}, + {0xba85, 1914}, + {0xba87, 1915}, + {0xba89, 0}, + {0xba8a, 1}, + {0xba8b, 2}, + {0xba8c, 1916}, + {0xba8e, 0}, + {0xba8f, 1}, + {0xba90, 2}, + {0xba91, 3}, + {0xba92, 4}, + {0xba93, 5}, + {0xba94, 6}, + {0xba95, 7}, + {0xba96, 8}, + {0xba97, 9}, + {0xba98, 10}, + {0xba99, 11}, + {0xba9a, 12}, + {0xba9b, 13}, + {0xba9c, 14}, + {0xba9d, 15}, + {0xba9e, 16}, + {0xba9f, 17}, + {0xbaa0, 18}, + {0xbaa1, 19}, + {0xbaa2, 20}, + {0xbaa3, 21}, + {0xbaa4, 22}, + {0xbaa5, 23}, + {0xbaa6, 24}, + {0xbaa7, 25}, + {0xbaa8, 1917}, + {0xbaa9, 1918}, + {0xbaab, 1919}, + {0xbaac, 1920}, + {0xbaae, 0}, + {0xbaaf, 1}, + {0xbab0, 1921}, + {0xbab2, 1922}, + {0xbab4, 0}, + {0xbab5, 1}, + {0xbab6, 2}, + {0xbab7, 3}, + {0xbab8, 1923}, + {0xbab9, 1924}, + {0xbabb, 1925}, + {0xbabd, 1926}, + {0xbabf, 0}, + {0xbac0, 1}, + {0xbac1, 2}, + {0xbac2, 3}, + {0xbac3, 4}, + {0xbac4, 1927}, + {0xbac6, 0}, + {0xbac7, 1}, + {0xbac8, 1928}, + {0xbaca, 0}, + {0xbacb, 1}, + {0xbacc, 2}, + {0xbacd, 3}, + {0xbace, 4}, + {0xbacf, 5}, + {0xbad0, 6}, + {0xbad1, 7}, + {0xbad2, 8}, + {0xbad3, 9}, + {0xbad4, 10}, + {0xbad5, 11}, + {0xbad6, 12}, + {0xbad7, 13}, + {0xbad8, 1929}, + {0xbad9, 1930}, + {0xbadb, 0}, + {0xbadc, 1}, + {0xbadd, 2}, + {0xbade, 3}, + {0xbadf, 4}, + {0xbae0, 5}, + {0xbae1, 6}, + {0xbae2, 7}, + {0xbae3, 8}, + {0xbae4, 9}, + {0xbae5, 10}, + {0xbae6, 11}, + {0xbae7, 12}, + {0xbae8, 13}, + {0xbae9, 14}, + {0xbaea, 15}, + {0xbaeb, 16}, + {0xbaec, 17}, + {0xbaed, 18}, + {0xbaee, 19}, + {0xbaef, 20}, + {0xbaf0, 21}, + {0xbaf1, 22}, + {0xbaf2, 23}, + {0xbaf3, 24}, + {0xbaf4, 25}, + {0xbaf5, 26}, + {0xbaf6, 27}, + {0xbaf7, 28}, + {0xbaf8, 29}, + {0xbaf9, 30}, + {0xbafa, 31}, + {0xbafb, 32}, + {0xbafc, 1931}, + {0xbafe, 0}, + {0xbaff, 1}, + {0xbb00, 1932}, + {0xbb02, 0}, + {0xbb03, 1}, + {0xbb04, 1933}, + {0xbb06, 0}, + {0xbb07, 1}, + {0xbb08, 2}, + {0xbb09, 3}, + {0xbb0a, 4}, + {0xbb0b, 5}, + {0xbb0c, 6}, + {0xbb0d, 1934}, + {0xbb0f, 1935}, + {0xbb11, 1936}, + {0xbb13, 0}, + {0xbb14, 1}, + {0xbb15, 2}, + {0xbb16, 3}, + {0xbb17, 4}, + {0xbb18, 1937}, + {0xbb1a, 0}, + {0xbb1b, 1}, + {0xbb1c, 1938}, + {0xbb1e, 0}, + {0xbb1f, 1}, + {0xbb20, 1939}, + {0xbb22, 0}, + {0xbb23, 1}, + {0xbb24, 2}, + {0xbb25, 3}, + {0xbb26, 4}, + {0xbb27, 5}, + {0xbb28, 6}, + {0xbb29, 1940}, + {0xbb2b, 1941}, + {0xbb2d, 0}, + {0xbb2e, 1}, + {0xbb2f, 2}, + {0xbb30, 3}, + {0xbb31, 4}, + {0xbb32, 5}, + {0xbb33, 6}, + {0xbb34, 1942}, + {0xbb35, 1943}, + {0xbb36, 1944}, + {0xbb38, 1945}, + {0xbb3a, 0}, + {0xbb3b, 1946}, + {0xbb3c, 1947}, + {0xbb3d, 1948}, + {0xbb3e, 1949}, + {0xbb40, 0}, + {0xbb41, 1}, + {0xbb42, 2}, + {0xbb43, 3}, + {0xbb44, 1950}, + {0xbb45, 1951}, + {0xbb47, 1952}, + {0xbb49, 1953}, + {0xbb4b, 0}, + {0xbb4c, 1}, + {0xbb4d, 1954}, + {0xbb4f, 1955}, + {0xbb50, 1956}, + {0xbb52, 0}, + {0xbb53, 1}, + {0xbb54, 1957}, + {0xbb56, 0}, + {0xbb57, 1}, + {0xbb58, 1958}, + {0xbb5a, 0}, + {0xbb5b, 1}, + {0xbb5c, 2}, + {0xbb5d, 3}, + {0xbb5e, 4}, + {0xbb5f, 5}, + {0xbb60, 6}, + {0xbb61, 1959}, + {0xbb63, 1960}, + {0xbb65, 0}, + {0xbb66, 1}, + {0xbb67, 2}, + {0xbb68, 3}, + {0xbb69, 4}, + {0xbb6a, 5}, + {0xbb6b, 6}, + {0xbb6c, 1961}, + {0xbb6e, 0}, + {0xbb6f, 1}, + {0xbb70, 2}, + {0xbb71, 3}, + {0xbb72, 4}, + {0xbb73, 5}, + {0xbb74, 6}, + {0xbb75, 7}, + {0xbb76, 8}, + {0xbb77, 9}, + {0xbb78, 10}, + {0xbb79, 11}, + {0xbb7a, 12}, + {0xbb7b, 13}, + {0xbb7c, 14}, + {0xbb7d, 15}, + {0xbb7e, 16}, + {0xbb7f, 17}, + {0xbb80, 18}, + {0xbb81, 19}, + {0xbb82, 20}, + {0xbb83, 21}, + {0xbb84, 22}, + {0xbb85, 23}, + {0xbb86, 24}, + {0xbb87, 25}, + {0xbb88, 1962}, + {0xbb8a, 0}, + {0xbb8b, 1}, + {0xbb8c, 1963}, + {0xbb8e, 0}, + {0xbb8f, 1}, + {0xbb90, 1964}, + {0xbb92, 0}, + {0xbb93, 1}, + {0xbb94, 2}, + {0xbb95, 3}, + {0xbb96, 4}, + {0xbb97, 5}, + {0xbb98, 6}, + {0xbb99, 7}, + {0xbb9a, 8}, + {0xbb9b, 9}, + {0xbb9c, 10}, + {0xbb9d, 11}, + {0xbb9e, 12}, + {0xbb9f, 13}, + {0xbba0, 14}, + {0xbba1, 15}, + {0xbba2, 16}, + {0xbba3, 17}, + {0xbba4, 1965}, + {0xbba6, 0}, + {0xbba7, 1}, + {0xbba8, 1966}, + {0xbbaa, 0}, + {0xbbab, 1}, + {0xbbac, 1967}, + {0xbbae, 0}, + {0xbbaf, 1}, + {0xbbb0, 2}, + {0xbbb1, 3}, + {0xbbb2, 4}, + {0xbbb3, 5}, + {0xbbb4, 1968}, + {0xbbb6, 0}, + {0xbbb7, 1969}, + {0xbbb9, 0}, + {0xbbba, 1}, + {0xbbbb, 2}, + {0xbbbc, 3}, + {0xbbbd, 4}, + {0xbbbe, 5}, + {0xbbbf, 6}, + {0xbbc0, 1970}, + {0xbbc2, 0}, + {0xbbc3, 1}, + {0xbbc4, 1971}, + {0xbbc6, 0}, + {0xbbc7, 1}, + {0xbbc8, 1972}, + {0xbbca, 0}, + {0xbbcb, 1}, + {0xbbcc, 2}, + {0xbbcd, 3}, + {0xbbce, 4}, + {0xbbcf, 5}, + {0xbbd0, 1973}, + {0xbbd2, 0}, + {0xbbd3, 1974}, + {0xbbd5, 0}, + {0xbbd6, 1}, + {0xbbd7, 2}, + {0xbbd8, 3}, + {0xbbd9, 4}, + {0xbbda, 5}, + {0xbbdb, 6}, + {0xbbdc, 7}, + {0xbbdd, 8}, + {0xbbde, 9}, + {0xbbdf, 10}, + {0xbbe0, 11}, + {0xbbe1, 12}, + {0xbbe2, 13}, + {0xbbe3, 14}, + {0xbbe4, 15}, + {0xbbe5, 16}, + {0xbbe6, 17}, + {0xbbe7, 18}, + {0xbbe8, 19}, + {0xbbe9, 20}, + {0xbbea, 21}, + {0xbbeb, 22}, + {0xbbec, 23}, + {0xbbed, 24}, + {0xbbee, 25}, + {0xbbef, 26}, + {0xbbf0, 27}, + {0xbbf1, 28}, + {0xbbf2, 29}, + {0xbbf3, 30}, + {0xbbf4, 31}, + {0xbbf5, 32}, + {0xbbf6, 33}, + {0xbbf7, 34}, + {0xbbf8, 1975}, + {0xbbf9, 1976}, + {0xbbfb, 0}, + {0xbbfc, 1977}, + {0xbbfe, 0}, + {0xbbff, 1978}, + {0xbc00, 1979}, + {0xbc02, 1980}, + {0xbc04, 0}, + {0xbc05, 1}, + {0xbc06, 2}, + {0xbc07, 3}, + {0xbc08, 1981}, + {0xbc09, 1982}, + {0xbc0b, 1983}, + {0xbc0c, 1984}, + {0xbc0d, 1985}, + {0xbc0f, 1986}, + {0xbc11, 1987}, + {0xbc13, 0}, + {0xbc14, 1988}, + {0xbc15, 1989}, + {0xbc16, 1990}, + {0xbc17, 1991}, + {0xbc18, 1992}, + {0xbc1a, 0}, + {0xbc1b, 1993}, + {0xbc1c, 1994}, + {0xbc1d, 1995}, + {0xbc1e, 1996}, + {0xbc1f, 1997}, + {0xbc21, 0}, + {0xbc22, 1}, + {0xbc23, 2}, + {0xbc24, 1998}, + {0xbc25, 1999}, + {0xbc27, 2000}, + {0xbc29, 2001}, + {0xbc2b, 0}, + {0xbc2c, 1}, + {0xbc2d, 2002}, + {0xbc2f, 0}, + {0xbc30, 2003}, + {0xbc31, 2004}, + {0xbc33, 0}, + {0xbc34, 2005}, + {0xbc36, 0}, + {0xbc37, 1}, + {0xbc38, 2006}, + {0xbc3a, 0}, + {0xbc3b, 1}, + {0xbc3c, 2}, + {0xbc3d, 3}, + {0xbc3e, 4}, + {0xbc3f, 5}, + {0xbc40, 2007}, + {0xbc41, 2008}, + {0xbc43, 2009}, + {0xbc44, 2010}, + {0xbc45, 2011}, + {0xbc47, 0}, + {0xbc48, 1}, + {0xbc49, 2012}, + {0xbc4b, 0}, + {0xbc4c, 2013}, + {0xbc4d, 2014}, + {0xbc4f, 0}, + {0xbc50, 2015}, + {0xbc52, 0}, + {0xbc53, 1}, + {0xbc54, 2}, + {0xbc55, 3}, + {0xbc56, 4}, + {0xbc57, 5}, + {0xbc58, 6}, + {0xbc59, 7}, + {0xbc5a, 8}, + {0xbc5b, 9}, + {0xbc5c, 10}, + {0xbc5d, 2016}, + {0xbc5f, 0}, + {0xbc60, 1}, + {0xbc61, 2}, + {0xbc62, 3}, + {0xbc63, 4}, + {0xbc64, 5}, + {0xbc65, 6}, + {0xbc66, 7}, + {0xbc67, 8}, + {0xbc68, 9}, + {0xbc69, 10}, + {0xbc6a, 11}, + {0xbc6b, 12}, + {0xbc6c, 13}, + {0xbc6d, 14}, + {0xbc6e, 15}, + {0xbc6f, 16}, + {0xbc70, 17}, + {0xbc71, 18}, + {0xbc72, 19}, + {0xbc73, 20}, + {0xbc74, 21}, + {0xbc75, 22}, + {0xbc76, 23}, + {0xbc77, 24}, + {0xbc78, 25}, + {0xbc79, 26}, + {0xbc7a, 27}, + {0xbc7b, 28}, + {0xbc7c, 29}, + {0xbc7d, 30}, + {0xbc7e, 31}, + {0xbc7f, 32}, + {0xbc80, 33}, + {0xbc81, 34}, + {0xbc82, 35}, + {0xbc83, 36}, + {0xbc84, 2017}, + {0xbc85, 2018}, + {0xbc87, 0}, + {0xbc88, 2019}, + {0xbc8a, 0}, + {0xbc8b, 2020}, + {0xbc8c, 2021}, + {0xbc8e, 2022}, + {0xbc90, 0}, + {0xbc91, 1}, + {0xbc92, 2}, + {0xbc93, 3}, + {0xbc94, 2023}, + {0xbc95, 2024}, + {0xbc97, 2025}, + {0xbc99, 2026}, + {0xbc9a, 2027}, + {0xbc9c, 0}, + {0xbc9d, 1}, + {0xbc9e, 2}, + {0xbc9f, 3}, + {0xbca0, 2028}, + {0xbca1, 2029}, + {0xbca3, 0}, + {0xbca4, 2030}, + {0xbca6, 0}, + {0xbca7, 2031}, + {0xbca8, 2032}, + {0xbcaa, 0}, + {0xbcab, 1}, + {0xbcac, 2}, + {0xbcad, 3}, + {0xbcae, 4}, + {0xbcaf, 5}, + {0xbcb0, 2033}, + {0xbcb1, 2034}, + {0xbcb3, 2035}, + {0xbcb4, 2036}, + {0xbcb5, 2037}, + {0xbcb7, 0}, + {0xbcb8, 1}, + {0xbcb9, 2}, + {0xbcba, 3}, + {0xbcbb, 4}, + {0xbcbc, 2038}, + {0xbcbd, 2039}, + {0xbcbf, 0}, + {0xbcc0, 2040}, + {0xbcc2, 0}, + {0xbcc3, 1}, + {0xbcc4, 2041}, + {0xbcc6, 0}, + {0xbcc7, 1}, + {0xbcc8, 2}, + {0xbcc9, 3}, + {0xbcca, 4}, + {0xbccb, 5}, + {0xbccc, 6}, + {0xbccd, 2042}, + {0xbccf, 2043}, + {0xbcd0, 2044}, + {0xbcd1, 2045}, + {0xbcd3, 0}, + {0xbcd4, 1}, + {0xbcd5, 2046}, + {0xbcd7, 0}, + {0xbcd8, 2047}, + {0xbcda, 0}, + {0xbcdb, 1}, + {0xbcdc, 2048}, + {0xbcde, 0}, + {0xbcdf, 1}, + {0xbce0, 2}, + {0xbce1, 3}, + {0xbce2, 4}, + {0xbce3, 5}, + {0xbce4, 6}, + {0xbce5, 7}, + {0xbce6, 8}, + {0xbce7, 9}, + {0xbce8, 10}, + {0xbce9, 11}, + {0xbcea, 12}, + {0xbceb, 13}, + {0xbcec, 14}, + {0xbced, 15}, + {0xbcee, 16}, + {0xbcef, 17}, + {0xbcf0, 18}, + {0xbcf1, 19}, + {0xbcf2, 20}, + {0xbcf3, 21}, + {0xbcf4, 2049}, + {0xbcf5, 2050}, + {0xbcf6, 2051}, + {0xbcf8, 2052}, + {0xbcfa, 0}, + {0xbcfb, 1}, + {0xbcfc, 2053}, + {0xbcfe, 0}, + {0xbcff, 1}, + {0xbd01, 0}, + {0xbd02, 1}, + {0xbd03, 2}, + {0xbd04, 2054}, + {0xbd05, 2055}, + {0xbd07, 2056}, + {0xbd09, 2057}, + {0xbd0b, 0}, + {0xbd0c, 1}, + {0xbd0d, 2}, + {0xbd0e, 3}, + {0xbd0f, 4}, + {0xbd10, 2058}, + {0xbd12, 0}, + {0xbd13, 1}, + {0xbd14, 2059}, + {0xbd16, 0}, + {0xbd17, 1}, + {0xbd18, 2}, + {0xbd19, 3}, + {0xbd1a, 4}, + {0xbd1b, 5}, + {0xbd1c, 6}, + {0xbd1d, 7}, + {0xbd1e, 8}, + {0xbd1f, 9}, + {0xbd20, 10}, + {0xbd21, 11}, + {0xbd22, 12}, + {0xbd23, 13}, + {0xbd24, 2060}, + {0xbd26, 0}, + {0xbd27, 1}, + {0xbd28, 2}, + {0xbd29, 3}, + {0xbd2a, 4}, + {0xbd2b, 5}, + {0xbd2c, 2061}, + {0xbd2e, 0}, + {0xbd2f, 1}, + {0xbd30, 2}, + {0xbd31, 3}, + {0xbd32, 4}, + {0xbd33, 5}, + {0xbd34, 6}, + {0xbd35, 7}, + {0xbd36, 8}, + {0xbd37, 9}, + {0xbd38, 10}, + {0xbd39, 11}, + {0xbd3a, 12}, + {0xbd3b, 13}, + {0xbd3c, 14}, + {0xbd3d, 15}, + {0xbd3e, 16}, + {0xbd3f, 17}, + {0xbd40, 2062}, + {0xbd42, 0}, + {0xbd43, 1}, + {0xbd44, 2}, + {0xbd45, 3}, + {0xbd46, 4}, + {0xbd47, 5}, + {0xbd48, 2063}, + {0xbd49, 2064}, + {0xbd4b, 0}, + {0xbd4c, 2065}, + {0xbd4e, 0}, + {0xbd4f, 1}, + {0xbd50, 2066}, + {0xbd52, 0}, + {0xbd53, 1}, + {0xbd54, 2}, + {0xbd55, 3}, + {0xbd56, 4}, + {0xbd57, 5}, + {0xbd58, 2067}, + {0xbd59, 2068}, + {0xbd5b, 0}, + {0xbd5c, 1}, + {0xbd5d, 2}, + {0xbd5e, 3}, + {0xbd5f, 4}, + {0xbd60, 5}, + {0xbd61, 6}, + {0xbd62, 7}, + {0xbd63, 8}, + {0xbd64, 2069}, + {0xbd66, 0}, + {0xbd67, 1}, + {0xbd68, 2070}, + {0xbd6a, 0}, + {0xbd6b, 1}, + {0xbd6c, 2}, + {0xbd6d, 3}, + {0xbd6e, 4}, + {0xbd6f, 5}, + {0xbd70, 6}, + {0xbd71, 7}, + {0xbd72, 8}, + {0xbd73, 9}, + {0xbd74, 10}, + {0xbd75, 11}, + {0xbd76, 12}, + {0xbd77, 13}, + {0xbd78, 14}, + {0xbd79, 15}, + {0xbd7a, 16}, + {0xbd7b, 17}, + {0xbd7c, 18}, + {0xbd7d, 19}, + {0xbd7e, 20}, + {0xbd7f, 21}, + {0xbd80, 2071}, + {0xbd81, 2072}, + {0xbd83, 0}, + {0xbd84, 2073}, + {0xbd86, 0}, + {0xbd87, 2074}, + {0xbd88, 2075}, + {0xbd89, 2076}, + {0xbd8a, 2077}, + {0xbd8c, 0}, + {0xbd8d, 1}, + {0xbd8e, 2}, + {0xbd8f, 3}, + {0xbd90, 2078}, + {0xbd91, 2079}, + {0xbd93, 2080}, + {0xbd95, 2081}, + {0xbd97, 0}, + {0xbd98, 1}, + {0xbd99, 2082}, + {0xbd9a, 2083}, + {0xbd9c, 2084}, + {0xbd9e, 0}, + {0xbd9f, 1}, + {0xbda0, 2}, + {0xbda1, 3}, + {0xbda2, 4}, + {0xbda3, 5}, + {0xbda4, 2085}, + {0xbda6, 0}, + {0xbda7, 1}, + {0xbda8, 2}, + {0xbda9, 3}, + {0xbdaa, 4}, + {0xbdab, 5}, + {0xbdac, 6}, + {0xbdad, 7}, + {0xbdae, 8}, + {0xbdaf, 9}, + {0xbdb0, 2086}, + {0xbdb2, 0}, + {0xbdb3, 1}, + {0xbdb4, 2}, + {0xbdb5, 3}, + {0xbdb6, 4}, + {0xbdb7, 5}, + {0xbdb8, 2087}, + {0xbdba, 0}, + {0xbdbb, 1}, + {0xbdbc, 2}, + {0xbdbd, 3}, + {0xbdbe, 4}, + {0xbdbf, 5}, + {0xbdc0, 6}, + {0xbdc1, 7}, + {0xbdc2, 8}, + {0xbdc3, 9}, + {0xbdc4, 10}, + {0xbdc5, 11}, + {0xbdc6, 12}, + {0xbdc7, 13}, + {0xbdc8, 14}, + {0xbdc9, 15}, + {0xbdca, 16}, + {0xbdcb, 17}, + {0xbdcc, 18}, + {0xbdcd, 19}, + {0xbdce, 20}, + {0xbdcf, 21}, + {0xbdd0, 22}, + {0xbdd1, 23}, + {0xbdd2, 24}, + {0xbdd3, 25}, + {0xbdd4, 2088}, + {0xbdd5, 2089}, + {0xbdd7, 0}, + {0xbdd8, 2090}, + {0xbdda, 0}, + {0xbddb, 1}, + {0xbddc, 2091}, + {0xbdde, 0}, + {0xbddf, 1}, + {0xbde0, 2}, + {0xbde1, 3}, + {0xbde2, 4}, + {0xbde3, 5}, + {0xbde4, 6}, + {0xbde5, 7}, + {0xbde6, 8}, + {0xbde7, 9}, + {0xbde8, 10}, + {0xbde9, 2092}, + {0xbdeb, 0}, + {0xbdec, 1}, + {0xbded, 2}, + {0xbdee, 3}, + {0xbdef, 4}, + {0xbdf0, 2093}, + {0xbdf2, 0}, + {0xbdf3, 1}, + {0xbdf4, 2094}, + {0xbdf6, 0}, + {0xbdf7, 1}, + {0xbdf8, 2095}, + {0xbdfa, 0}, + {0xbdfb, 1}, + {0xbdfc, 2}, + {0xbdfd, 3}, + {0xbdfe, 4}, + {0xbdff, 5}, + {0xbe00, 2096}, + {0xbe02, 0}, + {0xbe03, 2097}, + {0xbe05, 2098}, + {0xbe07, 0}, + {0xbe08, 1}, + {0xbe09, 2}, + {0xbe0a, 3}, + {0xbe0b, 4}, + {0xbe0c, 2099}, + {0xbe0d, 2100}, + {0xbe0f, 0}, + {0xbe10, 2101}, + {0xbe12, 0}, + {0xbe13, 1}, + {0xbe14, 2102}, + {0xbe16, 0}, + {0xbe17, 1}, + {0xbe18, 2}, + {0xbe19, 3}, + {0xbe1a, 4}, + {0xbe1b, 5}, + {0xbe1c, 2103}, + {0xbe1d, 2104}, + {0xbe1f, 2105}, + {0xbe21, 0}, + {0xbe22, 1}, + {0xbe23, 2}, + {0xbe24, 3}, + {0xbe25, 4}, + {0xbe26, 5}, + {0xbe27, 6}, + {0xbe28, 7}, + {0xbe29, 8}, + {0xbe2a, 9}, + {0xbe2b, 10}, + {0xbe2c, 11}, + {0xbe2d, 12}, + {0xbe2e, 13}, + {0xbe2f, 14}, + {0xbe30, 15}, + {0xbe31, 16}, + {0xbe32, 17}, + {0xbe33, 18}, + {0xbe34, 19}, + {0xbe35, 20}, + {0xbe36, 21}, + {0xbe37, 22}, + {0xbe38, 23}, + {0xbe39, 24}, + {0xbe3a, 25}, + {0xbe3b, 26}, + {0xbe3c, 27}, + {0xbe3d, 28}, + {0xbe3e, 29}, + {0xbe3f, 30}, + {0xbe40, 31}, + {0xbe41, 32}, + {0xbe42, 33}, + {0xbe43, 34}, + {0xbe44, 2106}, + {0xbe45, 2107}, + {0xbe47, 0}, + {0xbe48, 2108}, + {0xbe4a, 0}, + {0xbe4b, 1}, + {0xbe4c, 2109}, + {0xbe4e, 2110}, + {0xbe50, 0}, + {0xbe51, 1}, + {0xbe52, 2}, + {0xbe53, 3}, + {0xbe54, 2111}, + {0xbe55, 2112}, + {0xbe57, 2113}, + {0xbe59, 2114}, + {0xbe5a, 2115}, + {0xbe5b, 2116}, + {0xbe5d, 0}, + {0xbe5e, 1}, + {0xbe5f, 2}, + {0xbe60, 2117}, + {0xbe61, 2118}, + {0xbe63, 0}, + {0xbe64, 2119}, + {0xbe66, 0}, + {0xbe67, 1}, + {0xbe68, 2120}, + {0xbe6a, 2121}, + {0xbe6c, 0}, + {0xbe6d, 1}, + {0xbe6e, 2}, + {0xbe6f, 3}, + {0xbe70, 2122}, + {0xbe71, 2123}, + {0xbe73, 2124}, + {0xbe74, 2125}, + {0xbe75, 2126}, + {0xbe77, 0}, + {0xbe78, 1}, + {0xbe79, 2}, + {0xbe7a, 3}, + {0xbe7b, 2127}, + {0xbe7c, 2128}, + {0xbe7d, 2129}, + {0xbe7f, 0}, + {0xbe80, 2130}, + {0xbe82, 0}, + {0xbe83, 1}, + {0xbe84, 2131}, + {0xbe86, 0}, + {0xbe87, 1}, + {0xbe88, 2}, + {0xbe89, 3}, + {0xbe8a, 4}, + {0xbe8b, 5}, + {0xbe8c, 2132}, + {0xbe8d, 2133}, + {0xbe8f, 2134}, + {0xbe90, 2135}, + {0xbe91, 2136}, + {0xbe93, 0}, + {0xbe94, 1}, + {0xbe95, 2}, + {0xbe96, 3}, + {0xbe97, 4}, + {0xbe98, 2137}, + {0xbe99, 2138}, + {0xbe9b, 0}, + {0xbe9c, 1}, + {0xbe9d, 2}, + {0xbe9e, 3}, + {0xbe9f, 4}, + {0xbea0, 5}, + {0xbea1, 6}, + {0xbea2, 7}, + {0xbea3, 8}, + {0xbea4, 9}, + {0xbea5, 10}, + {0xbea6, 11}, + {0xbea7, 12}, + {0xbea8, 2139}, + {0xbeaa, 0}, + {0xbeab, 1}, + {0xbeac, 2}, + {0xbead, 3}, + {0xbeae, 4}, + {0xbeaf, 5}, + {0xbeb0, 6}, + {0xbeb1, 7}, + {0xbeb2, 8}, + {0xbeb3, 9}, + {0xbeb4, 10}, + {0xbeb5, 11}, + {0xbeb6, 12}, + {0xbeb7, 13}, + {0xbeb8, 14}, + {0xbeb9, 15}, + {0xbeba, 16}, + {0xbebb, 17}, + {0xbebc, 18}, + {0xbebd, 19}, + {0xbebe, 20}, + {0xbebf, 21}, + {0xbec0, 22}, + {0xbec1, 23}, + {0xbec2, 24}, + {0xbec3, 25}, + {0xbec4, 26}, + {0xbec5, 27}, + {0xbec6, 28}, + {0xbec7, 29}, + {0xbec8, 30}, + {0xbec9, 31}, + {0xbeca, 32}, + {0xbecb, 33}, + {0xbecc, 34}, + {0xbecd, 35}, + {0xbece, 36}, + {0xbecf, 37}, + {0xbed0, 2140}, + {0xbed1, 2141}, + {0xbed3, 0}, + {0xbed4, 2142}, + {0xbed6, 0}, + {0xbed7, 2143}, + {0xbed8, 2144}, + {0xbeda, 0}, + {0xbedb, 1}, + {0xbedc, 2}, + {0xbedd, 3}, + {0xbede, 4}, + {0xbedf, 5}, + {0xbee0, 2145}, + {0xbee2, 0}, + {0xbee3, 2146}, + {0xbee4, 2147}, + {0xbee5, 2148}, + {0xbee7, 0}, + {0xbee8, 1}, + {0xbee9, 2}, + {0xbeea, 3}, + {0xbeeb, 4}, + {0xbeec, 2149}, + {0xbeee, 0}, + {0xbeef, 1}, + {0xbef0, 2}, + {0xbef1, 3}, + {0xbef2, 4}, + {0xbef3, 5}, + {0xbef4, 6}, + {0xbef5, 7}, + {0xbef6, 8}, + {0xbef7, 9}, + {0xbef8, 10}, + {0xbef9, 11}, + {0xbefa, 12}, + {0xbefb, 13}, + {0xbefc, 14}, + {0xbefd, 15}, + {0xbefe, 16}, + {0xbeff, 17}, + {0xbf01, 2150}, + {0xbf03, 0}, + {0xbf04, 1}, + {0xbf05, 2}, + {0xbf06, 3}, + {0xbf07, 4}, + {0xbf08, 2151}, + {0xbf09, 2152}, + {0xbf0b, 0}, + {0xbf0c, 1}, + {0xbf0d, 2}, + {0xbf0e, 3}, + {0xbf0f, 4}, + {0xbf10, 5}, + {0xbf11, 6}, + {0xbf12, 7}, + {0xbf13, 8}, + {0xbf14, 9}, + {0xbf15, 10}, + {0xbf16, 11}, + {0xbf17, 12}, + {0xbf18, 2153}, + {0xbf19, 2154}, + {0xbf1b, 2155}, + {0xbf1c, 2156}, + {0xbf1d, 2157}, + {0xbf1f, 0}, + {0xbf20, 1}, + {0xbf21, 2}, + {0xbf22, 3}, + {0xbf23, 4}, + {0xbf24, 5}, + {0xbf25, 6}, + {0xbf26, 7}, + {0xbf27, 8}, + {0xbf28, 9}, + {0xbf29, 10}, + {0xbf2a, 11}, + {0xbf2b, 12}, + {0xbf2c, 13}, + {0xbf2d, 14}, + {0xbf2e, 15}, + {0xbf2f, 16}, + {0xbf30, 17}, + {0xbf31, 18}, + {0xbf32, 19}, + {0xbf33, 20}, + {0xbf34, 21}, + {0xbf35, 22}, + {0xbf36, 23}, + {0xbf37, 24}, + {0xbf38, 25}, + {0xbf39, 26}, + {0xbf3a, 27}, + {0xbf3b, 28}, + {0xbf3c, 29}, + {0xbf3d, 30}, + {0xbf3e, 31}, + {0xbf3f, 32}, + {0xbf40, 2158}, + {0xbf41, 2159}, + {0xbf43, 0}, + {0xbf44, 2160}, + {0xbf46, 0}, + {0xbf47, 1}, + {0xbf48, 2161}, + {0xbf4a, 0}, + {0xbf4b, 1}, + {0xbf4c, 2}, + {0xbf4d, 3}, + {0xbf4e, 4}, + {0xbf4f, 5}, + {0xbf50, 2162}, + {0xbf51, 2163}, + {0xbf53, 0}, + {0xbf54, 1}, + {0xbf55, 2164}, + {0xbf57, 0}, + {0xbf58, 1}, + {0xbf59, 2}, + {0xbf5a, 3}, + {0xbf5b, 4}, + {0xbf5c, 5}, + {0xbf5d, 6}, + {0xbf5e, 7}, + {0xbf5f, 8}, + {0xbf60, 9}, + {0xbf61, 10}, + {0xbf62, 11}, + {0xbf63, 12}, + {0xbf64, 13}, + {0xbf65, 14}, + {0xbf66, 15}, + {0xbf67, 16}, + {0xbf68, 17}, + {0xbf69, 18}, + {0xbf6a, 19}, + {0xbf6b, 20}, + {0xbf6c, 21}, + {0xbf6d, 22}, + {0xbf6e, 23}, + {0xbf6f, 24}, + {0xbf70, 25}, + {0xbf71, 26}, + {0xbf72, 27}, + {0xbf73, 28}, + {0xbf74, 29}, + {0xbf75, 30}, + {0xbf76, 31}, + {0xbf77, 32}, + {0xbf78, 33}, + {0xbf79, 34}, + {0xbf7a, 35}, + {0xbf7b, 36}, + {0xbf7c, 37}, + {0xbf7d, 38}, + {0xbf7e, 39}, + {0xbf7f, 40}, + {0xbf80, 41}, + {0xbf81, 42}, + {0xbf82, 43}, + {0xbf83, 44}, + {0xbf84, 45}, + {0xbf85, 46}, + {0xbf86, 47}, + {0xbf87, 48}, + {0xbf88, 49}, + {0xbf89, 50}, + {0xbf8a, 51}, + {0xbf8b, 52}, + {0xbf8c, 53}, + {0xbf8d, 54}, + {0xbf8e, 55}, + {0xbf8f, 56}, + {0xbf90, 57}, + {0xbf91, 58}, + {0xbf92, 59}, + {0xbf93, 60}, + {0xbf94, 2165}, + {0xbf96, 0}, + {0xbf97, 1}, + {0xbf98, 2}, + {0xbf99, 3}, + {0xbf9a, 4}, + {0xbf9b, 5}, + {0xbf9c, 6}, + {0xbf9d, 7}, + {0xbf9e, 8}, + {0xbf9f, 9}, + {0xbfa0, 10}, + {0xbfa1, 11}, + {0xbfa2, 12}, + {0xbfa3, 13}, + {0xbfa4, 14}, + {0xbfa5, 15}, + {0xbfa6, 16}, + {0xbfa7, 17}, + {0xbfa8, 18}, + {0xbfa9, 19}, + {0xbfaa, 20}, + {0xbfab, 21}, + {0xbfac, 22}, + {0xbfad, 23}, + {0xbfae, 24}, + {0xbfaf, 25}, + {0xbfb0, 2166}, + {0xbfb2, 0}, + {0xbfb3, 1}, + {0xbfb4, 2}, + {0xbfb5, 3}, + {0xbfb6, 4}, + {0xbfb7, 5}, + {0xbfb8, 6}, + {0xbfb9, 7}, + {0xbfba, 8}, + {0xbfbb, 9}, + {0xbfbc, 10}, + {0xbfbd, 11}, + {0xbfbe, 12}, + {0xbfbf, 13}, + {0xbfc0, 14}, + {0xbfc1, 15}, + {0xbfc2, 16}, + {0xbfc3, 17}, + {0xbfc4, 18}, + {0xbfc5, 2167}, + {0xbfc7, 0}, + {0xbfc8, 1}, + {0xbfc9, 2}, + {0xbfca, 3}, + {0xbfcb, 4}, + {0xbfcc, 2168}, + {0xbfcd, 2169}, + {0xbfcf, 0}, + {0xbfd0, 2170}, + {0xbfd2, 0}, + {0xbfd3, 1}, + {0xbfd4, 2171}, + {0xbfd6, 0}, + {0xbfd7, 1}, + {0xbfd8, 2}, + {0xbfd9, 3}, + {0xbfda, 4}, + {0xbfdb, 5}, + {0xbfdc, 2172}, + {0xbfde, 0}, + {0xbfdf, 2173}, + {0xbfe1, 2174}, + {0xbfe3, 0}, + {0xbfe4, 1}, + {0xbfe5, 2}, + {0xbfe6, 3}, + {0xbfe7, 4}, + {0xbfe8, 5}, + {0xbfe9, 6}, + {0xbfea, 7}, + {0xbfeb, 8}, + {0xbfec, 9}, + {0xbfed, 10}, + {0xbfee, 11}, + {0xbfef, 12}, + {0xbff0, 13}, + {0xbff1, 14}, + {0xbff2, 15}, + {0xbff3, 16}, + {0xbff4, 17}, + {0xbff5, 18}, + {0xbff6, 19}, + {0xbff7, 20}, + {0xbff8, 21}, + {0xbff9, 22}, + {0xbffa, 23}, + {0xbffb, 24}, + {0xbffc, 25}, + {0xbffd, 26}, + {0xbffe, 27}, + {0xbfff, 28}, + {0xc001, 0}, + {0xc002, 1}, + {0xc003, 2}, + {0xc004, 3}, + {0xc005, 4}, + {0xc006, 5}, + {0xc007, 6}, + {0xc008, 7}, + {0xc009, 8}, + {0xc00a, 9}, + {0xc00b, 10}, + {0xc00c, 11}, + {0xc00d, 12}, + {0xc00e, 13}, + {0xc00f, 14}, + {0xc010, 15}, + {0xc011, 16}, + {0xc012, 17}, + {0xc013, 18}, + {0xc014, 19}, + {0xc015, 20}, + {0xc016, 21}, + {0xc017, 22}, + {0xc018, 23}, + {0xc019, 24}, + {0xc01a, 25}, + {0xc01b, 26}, + {0xc01c, 27}, + {0xc01d, 28}, + {0xc01e, 29}, + {0xc01f, 30}, + {0xc020, 31}, + {0xc021, 32}, + {0xc022, 33}, + {0xc023, 34}, + {0xc024, 35}, + {0xc025, 36}, + {0xc026, 37}, + {0xc027, 38}, + {0xc028, 39}, + {0xc029, 40}, + {0xc02a, 41}, + {0xc02b, 42}, + {0xc02c, 43}, + {0xc02d, 44}, + {0xc02e, 45}, + {0xc02f, 46}, + {0xc030, 47}, + {0xc031, 48}, + {0xc032, 49}, + {0xc033, 50}, + {0xc034, 51}, + {0xc035, 52}, + {0xc036, 53}, + {0xc037, 54}, + {0xc038, 55}, + {0xc039, 56}, + {0xc03a, 57}, + {0xc03b, 58}, + {0xc03c, 2175}, + {0xc03e, 0}, + {0xc03f, 1}, + {0xc040, 2}, + {0xc041, 3}, + {0xc042, 4}, + {0xc043, 5}, + {0xc044, 6}, + {0xc045, 7}, + {0xc046, 8}, + {0xc047, 9}, + {0xc048, 10}, + {0xc049, 11}, + {0xc04a, 12}, + {0xc04b, 13}, + {0xc04c, 14}, + {0xc04d, 15}, + {0xc04e, 16}, + {0xc04f, 17}, + {0xc050, 18}, + {0xc051, 2176}, + {0xc053, 0}, + {0xc054, 1}, + {0xc055, 2}, + {0xc056, 3}, + {0xc057, 4}, + {0xc058, 2177}, + {0xc05a, 0}, + {0xc05b, 1}, + {0xc05c, 2178}, + {0xc05e, 0}, + {0xc05f, 1}, + {0xc060, 2179}, + {0xc062, 0}, + {0xc063, 1}, + {0xc064, 2}, + {0xc065, 3}, + {0xc066, 4}, + {0xc067, 5}, + {0xc068, 2180}, + {0xc069, 2181}, + {0xc06b, 0}, + {0xc06c, 1}, + {0xc06d, 2}, + {0xc06e, 3}, + {0xc06f, 4}, + {0xc070, 5}, + {0xc071, 6}, + {0xc072, 7}, + {0xc073, 8}, + {0xc074, 9}, + {0xc075, 10}, + {0xc076, 11}, + {0xc077, 12}, + {0xc078, 13}, + {0xc079, 14}, + {0xc07a, 15}, + {0xc07b, 16}, + {0xc07c, 17}, + {0xc07d, 18}, + {0xc07e, 19}, + {0xc07f, 20}, + {0xc080, 21}, + {0xc081, 22}, + {0xc082, 23}, + {0xc083, 24}, + {0xc084, 25}, + {0xc085, 26}, + {0xc086, 27}, + {0xc087, 28}, + {0xc088, 29}, + {0xc089, 30}, + {0xc08a, 31}, + {0xc08b, 32}, + {0xc08c, 33}, + {0xc08d, 34}, + {0xc08e, 35}, + {0xc08f, 36}, + {0xc090, 2182}, + {0xc091, 2183}, + {0xc093, 0}, + {0xc094, 2184}, + {0xc096, 0}, + {0xc097, 1}, + {0xc098, 2185}, + {0xc09a, 0}, + {0xc09b, 1}, + {0xc09c, 2}, + {0xc09d, 3}, + {0xc09e, 4}, + {0xc09f, 5}, + {0xc0a0, 2186}, + {0xc0a1, 2187}, + {0xc0a3, 2188}, + {0xc0a5, 2189}, + {0xc0a7, 0}, + {0xc0a8, 1}, + {0xc0a9, 2}, + {0xc0aa, 3}, + {0xc0ab, 4}, + {0xc0ac, 2190}, + {0xc0ad, 2191}, + {0xc0af, 2192}, + {0xc0b0, 2193}, + {0xc0b2, 0}, + {0xc0b3, 2194}, + {0xc0b4, 2195}, + {0xc0b5, 2196}, + {0xc0b6, 2197}, + {0xc0b8, 0}, + {0xc0b9, 1}, + {0xc0ba, 2}, + {0xc0bb, 3}, + {0xc0bc, 2198}, + {0xc0bd, 2199}, + {0xc0bf, 2200}, + {0xc0c0, 2201}, + {0xc0c1, 2202}, + {0xc0c3, 0}, + {0xc0c4, 1}, + {0xc0c5, 2203}, + {0xc0c7, 0}, + {0xc0c8, 2204}, + {0xc0c9, 2205}, + {0xc0cb, 0}, + {0xc0cc, 2206}, + {0xc0ce, 0}, + {0xc0cf, 1}, + {0xc0d0, 2207}, + {0xc0d2, 0}, + {0xc0d3, 1}, + {0xc0d4, 2}, + {0xc0d5, 3}, + {0xc0d6, 4}, + {0xc0d7, 5}, + {0xc0d8, 2208}, + {0xc0d9, 2209}, + {0xc0db, 2210}, + {0xc0dc, 2211}, + {0xc0dd, 2212}, + {0xc0df, 0}, + {0xc0e0, 1}, + {0xc0e1, 2}, + {0xc0e2, 3}, + {0xc0e3, 4}, + {0xc0e4, 2213}, + {0xc0e5, 2214}, + {0xc0e7, 0}, + {0xc0e8, 2215}, + {0xc0ea, 0}, + {0xc0eb, 1}, + {0xc0ec, 2216}, + {0xc0ee, 0}, + {0xc0ef, 1}, + {0xc0f0, 2}, + {0xc0f1, 3}, + {0xc0f2, 4}, + {0xc0f3, 5}, + {0xc0f4, 2217}, + {0xc0f5, 2218}, + {0xc0f7, 2219}, + {0xc0f9, 2220}, + {0xc0fb, 0}, + {0xc0fc, 1}, + {0xc0fd, 2}, + {0xc0fe, 3}, + {0xc0ff, 4}, + {0xc100, 2221}, + {0xc102, 0}, + {0xc103, 1}, + {0xc104, 2222}, + {0xc106, 0}, + {0xc107, 1}, + {0xc108, 2223}, + {0xc10a, 0}, + {0xc10b, 1}, + {0xc10c, 2}, + {0xc10d, 3}, + {0xc10e, 4}, + {0xc10f, 5}, + {0xc110, 2224}, + {0xc112, 0}, + {0xc113, 1}, + {0xc114, 2}, + {0xc115, 2225}, + {0xc117, 0}, + {0xc118, 1}, + {0xc119, 2}, + {0xc11a, 3}, + {0xc11b, 4}, + {0xc11c, 2226}, + {0xc11d, 2227}, + {0xc11e, 2228}, + {0xc11f, 2229}, + {0xc120, 2230}, + {0xc122, 0}, + {0xc123, 2231}, + {0xc124, 2232}, + {0xc126, 2233}, + {0xc127, 2234}, + {0xc129, 0}, + {0xc12a, 1}, + {0xc12b, 2}, + {0xc12c, 2235}, + {0xc12d, 2236}, + {0xc12f, 2237}, + {0xc130, 2238}, + {0xc131, 2239}, + {0xc133, 0}, + {0xc134, 1}, + {0xc135, 2}, + {0xc136, 2240}, + {0xc138, 2241}, + {0xc139, 2242}, + {0xc13b, 0}, + {0xc13c, 2243}, + {0xc13e, 0}, + {0xc13f, 1}, + {0xc140, 2244}, + {0xc142, 0}, + {0xc143, 1}, + {0xc144, 2}, + {0xc145, 3}, + {0xc146, 4}, + {0xc147, 5}, + {0xc148, 2245}, + {0xc149, 2246}, + {0xc14b, 2247}, + {0xc14c, 2248}, + {0xc14d, 2249}, + {0xc14f, 0}, + {0xc150, 1}, + {0xc151, 2}, + {0xc152, 3}, + {0xc153, 4}, + {0xc154, 2250}, + {0xc155, 2251}, + {0xc157, 0}, + {0xc158, 2252}, + {0xc15a, 0}, + {0xc15b, 1}, + {0xc15c, 2253}, + {0xc15e, 0}, + {0xc15f, 1}, + {0xc160, 2}, + {0xc161, 3}, + {0xc162, 4}, + {0xc163, 5}, + {0xc164, 2254}, + {0xc165, 2255}, + {0xc167, 2256}, + {0xc168, 2257}, + {0xc169, 2258}, + {0xc16b, 0}, + {0xc16c, 1}, + {0xc16d, 2}, + {0xc16e, 3}, + {0xc16f, 4}, + {0xc170, 2259}, + {0xc172, 0}, + {0xc173, 1}, + {0xc174, 2260}, + {0xc176, 0}, + {0xc177, 1}, + {0xc178, 2261}, + {0xc17a, 0}, + {0xc17b, 1}, + {0xc17c, 2}, + {0xc17d, 3}, + {0xc17e, 4}, + {0xc17f, 5}, + {0xc180, 6}, + {0xc181, 7}, + {0xc182, 8}, + {0xc183, 9}, + {0xc184, 10}, + {0xc185, 2262}, + {0xc187, 0}, + {0xc188, 1}, + {0xc189, 2}, + {0xc18a, 3}, + {0xc18b, 4}, + {0xc18c, 2263}, + {0xc18d, 2264}, + {0xc18e, 2265}, + {0xc190, 2266}, + {0xc192, 0}, + {0xc193, 1}, + {0xc194, 2267}, + {0xc196, 2268}, + {0xc198, 0}, + {0xc199, 1}, + {0xc19a, 2}, + {0xc19b, 3}, + {0xc19c, 2269}, + {0xc19d, 2270}, + {0xc19f, 2271}, + {0xc1a1, 2272}, + {0xc1a3, 0}, + {0xc1a4, 1}, + {0xc1a5, 2273}, + {0xc1a7, 0}, + {0xc1a8, 2274}, + {0xc1a9, 2275}, + {0xc1ab, 0}, + {0xc1ac, 2276}, + {0xc1ae, 0}, + {0xc1af, 1}, + {0xc1b0, 2277}, + {0xc1b2, 0}, + {0xc1b3, 1}, + {0xc1b4, 2}, + {0xc1b5, 3}, + {0xc1b6, 4}, + {0xc1b7, 5}, + {0xc1b8, 6}, + {0xc1b9, 7}, + {0xc1ba, 8}, + {0xc1bb, 9}, + {0xc1bc, 10}, + {0xc1bd, 2278}, + {0xc1bf, 0}, + {0xc1c0, 1}, + {0xc1c1, 2}, + {0xc1c2, 3}, + {0xc1c3, 4}, + {0xc1c4, 2279}, + {0xc1c6, 0}, + {0xc1c7, 1}, + {0xc1c8, 2280}, + {0xc1ca, 0}, + {0xc1cb, 1}, + {0xc1cc, 2281}, + {0xc1ce, 0}, + {0xc1cf, 1}, + {0xc1d0, 2}, + {0xc1d1, 3}, + {0xc1d2, 4}, + {0xc1d3, 5}, + {0xc1d4, 2282}, + {0xc1d6, 0}, + {0xc1d7, 2283}, + {0xc1d8, 2284}, + {0xc1da, 0}, + {0xc1db, 1}, + {0xc1dc, 2}, + {0xc1dd, 3}, + {0xc1de, 4}, + {0xc1df, 5}, + {0xc1e0, 2285}, + {0xc1e2, 0}, + {0xc1e3, 1}, + {0xc1e4, 2286}, + {0xc1e6, 0}, + {0xc1e7, 1}, + {0xc1e8, 2287}, + {0xc1ea, 0}, + {0xc1eb, 1}, + {0xc1ec, 2}, + {0xc1ed, 3}, + {0xc1ee, 4}, + {0xc1ef, 5}, + {0xc1f0, 2288}, + {0xc1f1, 2289}, + {0xc1f3, 2290}, + {0xc1f5, 0}, + {0xc1f6, 1}, + {0xc1f7, 2}, + {0xc1f8, 3}, + {0xc1f9, 4}, + {0xc1fa, 5}, + {0xc1fb, 6}, + {0xc1fc, 2291}, + {0xc1fd, 2292}, + {0xc1ff, 0}, + {0xc200, 2293}, + {0xc202, 0}, + {0xc203, 1}, + {0xc204, 2294}, + {0xc206, 0}, + {0xc207, 1}, + {0xc208, 2}, + {0xc209, 3}, + {0xc20a, 4}, + {0xc20b, 5}, + {0xc20c, 2295}, + {0xc20d, 2296}, + {0xc20f, 2297}, + {0xc211, 2298}, + {0xc213, 0}, + {0xc214, 1}, + {0xc215, 2}, + {0xc216, 3}, + {0xc217, 4}, + {0xc218, 2299}, + {0xc219, 2300}, + {0xc21b, 0}, + {0xc21c, 2301}, + {0xc21e, 0}, + {0xc21f, 2302}, + {0xc220, 2303}, + {0xc222, 0}, + {0xc223, 1}, + {0xc224, 2}, + {0xc225, 3}, + {0xc226, 4}, + {0xc227, 5}, + {0xc228, 2304}, + {0xc229, 2305}, + {0xc22b, 2306}, + {0xc22d, 2307}, + {0xc22f, 2308}, + {0xc231, 2309}, + {0xc232, 2310}, + {0xc234, 2311}, + {0xc236, 0}, + {0xc237, 1}, + {0xc238, 2}, + {0xc239, 3}, + {0xc23a, 4}, + {0xc23b, 5}, + {0xc23c, 6}, + {0xc23d, 7}, + {0xc23e, 8}, + {0xc23f, 9}, + {0xc240, 10}, + {0xc241, 11}, + {0xc242, 12}, + {0xc243, 13}, + {0xc244, 14}, + {0xc245, 15}, + {0xc246, 16}, + {0xc247, 17}, + {0xc248, 2312}, + {0xc24a, 0}, + {0xc24b, 1}, + {0xc24c, 2}, + {0xc24d, 3}, + {0xc24e, 4}, + {0xc24f, 5}, + {0xc250, 2313}, + {0xc251, 2314}, + {0xc253, 0}, + {0xc254, 2315}, + {0xc256, 0}, + {0xc257, 1}, + {0xc258, 2316}, + {0xc25a, 0}, + {0xc25b, 1}, + {0xc25c, 2}, + {0xc25d, 3}, + {0xc25e, 4}, + {0xc25f, 5}, + {0xc260, 2317}, + {0xc262, 0}, + {0xc263, 1}, + {0xc264, 2}, + {0xc265, 2318}, + {0xc267, 0}, + {0xc268, 1}, + {0xc269, 2}, + {0xc26a, 3}, + {0xc26b, 4}, + {0xc26c, 2319}, + {0xc26d, 2320}, + {0xc26f, 0}, + {0xc270, 2321}, + {0xc272, 0}, + {0xc273, 1}, + {0xc274, 2322}, + {0xc276, 0}, + {0xc277, 1}, + {0xc278, 2}, + {0xc279, 3}, + {0xc27a, 4}, + {0xc27b, 5}, + {0xc27c, 2323}, + {0xc27d, 2324}, + {0xc27f, 2325}, + {0xc281, 2326}, + {0xc283, 0}, + {0xc284, 1}, + {0xc285, 2}, + {0xc286, 3}, + {0xc287, 4}, + {0xc288, 2327}, + {0xc289, 2328}, + {0xc28b, 0}, + {0xc28c, 1}, + {0xc28d, 2}, + {0xc28e, 3}, + {0xc28f, 4}, + {0xc290, 2329}, + {0xc292, 0}, + {0xc293, 1}, + {0xc294, 2}, + {0xc295, 3}, + {0xc296, 4}, + {0xc297, 5}, + {0xc298, 2330}, + {0xc29a, 0}, + {0xc29b, 2331}, + {0xc29d, 2332}, + {0xc29f, 0}, + {0xc2a0, 1}, + {0xc2a1, 2}, + {0xc2a2, 3}, + {0xc2a3, 4}, + {0xc2a4, 2333}, + {0xc2a5, 2334}, + {0xc2a7, 0}, + {0xc2a8, 2335}, + {0xc2aa, 0}, + {0xc2ab, 1}, + {0xc2ac, 2336}, + {0xc2ad, 2337}, + {0xc2af, 0}, + {0xc2b0, 1}, + {0xc2b1, 2}, + {0xc2b2, 3}, + {0xc2b3, 4}, + {0xc2b4, 2338}, + {0xc2b5, 2339}, + {0xc2b7, 2340}, + {0xc2b9, 2341}, + {0xc2bb, 0}, + {0xc2bc, 1}, + {0xc2bd, 2}, + {0xc2be, 3}, + {0xc2bf, 4}, + {0xc2c0, 5}, + {0xc2c1, 6}, + {0xc2c2, 7}, + {0xc2c3, 8}, + {0xc2c4, 9}, + {0xc2c5, 10}, + {0xc2c6, 11}, + {0xc2c7, 12}, + {0xc2c8, 13}, + {0xc2c9, 14}, + {0xc2ca, 15}, + {0xc2cb, 16}, + {0xc2cc, 17}, + {0xc2cd, 18}, + {0xc2ce, 19}, + {0xc2cf, 20}, + {0xc2d0, 21}, + {0xc2d1, 22}, + {0xc2d2, 23}, + {0xc2d3, 24}, + {0xc2d4, 25}, + {0xc2d5, 26}, + {0xc2d6, 27}, + {0xc2d7, 28}, + {0xc2d8, 29}, + {0xc2d9, 30}, + {0xc2da, 31}, + {0xc2db, 32}, + {0xc2dc, 2342}, + {0xc2dd, 2343}, + {0xc2df, 0}, + {0xc2e0, 2344}, + {0xc2e2, 0}, + {0xc2e3, 2345}, + {0xc2e4, 2346}, + {0xc2e6, 0}, + {0xc2e7, 1}, + {0xc2e8, 2}, + {0xc2e9, 3}, + {0xc2ea, 4}, + {0xc2eb, 2347}, + {0xc2ec, 2348}, + {0xc2ed, 2349}, + {0xc2ef, 2350}, + {0xc2f1, 2351}, + {0xc2f3, 0}, + {0xc2f4, 1}, + {0xc2f5, 2}, + {0xc2f6, 2352}, + {0xc2f8, 2353}, + {0xc2f9, 2354}, + {0xc2fb, 2355}, + {0xc2fc, 2356}, + {0xc2fe, 0}, + {0xc2ff, 1}, + {0xc300, 2357}, + {0xc302, 0}, + {0xc303, 1}, + {0xc304, 2}, + {0xc305, 3}, + {0xc306, 4}, + {0xc307, 5}, + {0xc308, 2358}, + {0xc309, 2359}, + {0xc30b, 0}, + {0xc30c, 2360}, + {0xc30d, 2361}, + {0xc30f, 0}, + {0xc310, 1}, + {0xc311, 2}, + {0xc312, 3}, + {0xc313, 2362}, + {0xc314, 2363}, + {0xc315, 2364}, + {0xc317, 0}, + {0xc318, 2365}, + {0xc31a, 0}, + {0xc31b, 1}, + {0xc31c, 2366}, + {0xc31e, 0}, + {0xc31f, 1}, + {0xc320, 2}, + {0xc321, 3}, + {0xc322, 4}, + {0xc323, 5}, + {0xc324, 2367}, + {0xc325, 2368}, + {0xc327, 0}, + {0xc328, 2369}, + {0xc329, 2370}, + {0xc32b, 0}, + {0xc32c, 1}, + {0xc32d, 2}, + {0xc32e, 3}, + {0xc32f, 4}, + {0xc330, 5}, + {0xc331, 6}, + {0xc332, 7}, + {0xc333, 8}, + {0xc334, 9}, + {0xc335, 10}, + {0xc336, 11}, + {0xc337, 12}, + {0xc338, 13}, + {0xc339, 14}, + {0xc33a, 15}, + {0xc33b, 16}, + {0xc33c, 17}, + {0xc33d, 18}, + {0xc33e, 19}, + {0xc33f, 20}, + {0xc340, 21}, + {0xc341, 22}, + {0xc342, 23}, + {0xc343, 24}, + {0xc344, 25}, + {0xc345, 2371}, + {0xc347, 0}, + {0xc348, 1}, + {0xc349, 2}, + {0xc34a, 3}, + {0xc34b, 4}, + {0xc34c, 5}, + {0xc34d, 6}, + {0xc34e, 7}, + {0xc34f, 8}, + {0xc350, 9}, + {0xc351, 10}, + {0xc352, 11}, + {0xc353, 12}, + {0xc354, 13}, + {0xc355, 14}, + {0xc356, 15}, + {0xc357, 16}, + {0xc358, 17}, + {0xc359, 18}, + {0xc35a, 19}, + {0xc35b, 20}, + {0xc35c, 21}, + {0xc35d, 22}, + {0xc35e, 23}, + {0xc35f, 24}, + {0xc360, 25}, + {0xc361, 26}, + {0xc362, 27}, + {0xc363, 28}, + {0xc364, 29}, + {0xc365, 30}, + {0xc366, 31}, + {0xc367, 32}, + {0xc368, 2372}, + {0xc369, 2373}, + {0xc36b, 0}, + {0xc36c, 2374}, + {0xc36e, 0}, + {0xc36f, 1}, + {0xc370, 2375}, + {0xc372, 2376}, + {0xc374, 0}, + {0xc375, 1}, + {0xc376, 2}, + {0xc377, 3}, + {0xc378, 2377}, + {0xc379, 2378}, + {0xc37b, 0}, + {0xc37c, 2379}, + {0xc37d, 2380}, + {0xc37f, 0}, + {0xc380, 1}, + {0xc381, 2}, + {0xc382, 3}, + {0xc383, 4}, + {0xc384, 2381}, + {0xc386, 0}, + {0xc387, 1}, + {0xc388, 2382}, + {0xc38a, 0}, + {0xc38b, 1}, + {0xc38c, 2383}, + {0xc38e, 0}, + {0xc38f, 1}, + {0xc390, 2}, + {0xc391, 3}, + {0xc392, 4}, + {0xc393, 5}, + {0xc394, 6}, + {0xc395, 7}, + {0xc396, 8}, + {0xc397, 9}, + {0xc398, 10}, + {0xc399, 11}, + {0xc39a, 12}, + {0xc39b, 13}, + {0xc39c, 14}, + {0xc39d, 15}, + {0xc39e, 16}, + {0xc39f, 17}, + {0xc3a0, 18}, + {0xc3a1, 19}, + {0xc3a2, 20}, + {0xc3a3, 21}, + {0xc3a4, 22}, + {0xc3a5, 23}, + {0xc3a6, 24}, + {0xc3a7, 25}, + {0xc3a8, 26}, + {0xc3a9, 27}, + {0xc3aa, 28}, + {0xc3ab, 29}, + {0xc3ac, 30}, + {0xc3ad, 31}, + {0xc3ae, 32}, + {0xc3af, 33}, + {0xc3b0, 34}, + {0xc3b1, 35}, + {0xc3b2, 36}, + {0xc3b3, 37}, + {0xc3b4, 38}, + {0xc3b5, 39}, + {0xc3b6, 40}, + {0xc3b7, 41}, + {0xc3b8, 42}, + {0xc3b9, 43}, + {0xc3ba, 44}, + {0xc3bb, 45}, + {0xc3bc, 46}, + {0xc3bd, 47}, + {0xc3be, 48}, + {0xc3bf, 49}, + {0xc3c0, 2384}, + {0xc3c2, 0}, + {0xc3c3, 1}, + {0xc3c4, 2}, + {0xc3c5, 3}, + {0xc3c6, 4}, + {0xc3c7, 5}, + {0xc3c8, 6}, + {0xc3c9, 7}, + {0xc3ca, 8}, + {0xc3cb, 9}, + {0xc3cc, 10}, + {0xc3cd, 11}, + {0xc3ce, 12}, + {0xc3cf, 13}, + {0xc3d0, 14}, + {0xc3d1, 15}, + {0xc3d2, 16}, + {0xc3d3, 17}, + {0xc3d4, 18}, + {0xc3d5, 19}, + {0xc3d6, 20}, + {0xc3d7, 21}, + {0xc3d8, 2385}, + {0xc3d9, 2386}, + {0xc3db, 0}, + {0xc3dc, 2387}, + {0xc3de, 0}, + {0xc3df, 2388}, + {0xc3e0, 2389}, + {0xc3e2, 2390}, + {0xc3e4, 0}, + {0xc3e5, 1}, + {0xc3e6, 2}, + {0xc3e7, 3}, + {0xc3e8, 2391}, + {0xc3e9, 2392}, + {0xc3eb, 0}, + {0xc3ec, 1}, + {0xc3ed, 2393}, + {0xc3ef, 0}, + {0xc3f0, 1}, + {0xc3f1, 2}, + {0xc3f2, 3}, + {0xc3f3, 4}, + {0xc3f4, 2394}, + {0xc3f5, 2395}, + {0xc3f7, 0}, + {0xc3f8, 2396}, + {0xc3fa, 0}, + {0xc3fb, 1}, + {0xc3fc, 2}, + {0xc3fd, 3}, + {0xc3fe, 4}, + {0xc3ff, 5}, + {0xc401, 0}, + {0xc402, 1}, + {0xc403, 2}, + {0xc404, 3}, + {0xc405, 4}, + {0xc406, 5}, + {0xc407, 6}, + {0xc408, 2397}, + {0xc40a, 0}, + {0xc40b, 1}, + {0xc40c, 2}, + {0xc40d, 3}, + {0xc40e, 4}, + {0xc40f, 5}, + {0xc410, 2398}, + {0xc412, 0}, + {0xc413, 1}, + {0xc414, 2}, + {0xc415, 3}, + {0xc416, 4}, + {0xc417, 5}, + {0xc418, 6}, + {0xc419, 7}, + {0xc41a, 8}, + {0xc41b, 9}, + {0xc41c, 10}, + {0xc41d, 11}, + {0xc41e, 12}, + {0xc41f, 13}, + {0xc420, 14}, + {0xc421, 15}, + {0xc422, 16}, + {0xc423, 17}, + {0xc424, 2399}, + {0xc426, 0}, + {0xc427, 1}, + {0xc428, 2}, + {0xc429, 3}, + {0xc42a, 4}, + {0xc42b, 5}, + {0xc42c, 2400}, + {0xc42e, 0}, + {0xc42f, 1}, + {0xc430, 2401}, + {0xc432, 0}, + {0xc433, 1}, + {0xc434, 2402}, + {0xc436, 0}, + {0xc437, 1}, + {0xc438, 2}, + {0xc439, 3}, + {0xc43a, 4}, + {0xc43b, 5}, + {0xc43c, 2403}, + {0xc43d, 2404}, + {0xc43f, 0}, + {0xc440, 1}, + {0xc441, 2}, + {0xc442, 3}, + {0xc443, 4}, + {0xc444, 5}, + {0xc445, 6}, + {0xc446, 7}, + {0xc447, 8}, + {0xc448, 2405}, + {0xc44a, 0}, + {0xc44b, 1}, + {0xc44c, 2}, + {0xc44d, 3}, + {0xc44e, 4}, + {0xc44f, 5}, + {0xc450, 6}, + {0xc451, 7}, + {0xc452, 8}, + {0xc453, 9}, + {0xc454, 10}, + {0xc455, 11}, + {0xc456, 12}, + {0xc457, 13}, + {0xc458, 14}, + {0xc459, 15}, + {0xc45a, 16}, + {0xc45b, 17}, + {0xc45c, 18}, + {0xc45d, 19}, + {0xc45e, 20}, + {0xc45f, 21}, + {0xc460, 22}, + {0xc461, 23}, + {0xc462, 24}, + {0xc463, 25}, + {0xc464, 2406}, + {0xc465, 2407}, + {0xc467, 0}, + {0xc468, 2408}, + {0xc46a, 0}, + {0xc46b, 1}, + {0xc46c, 2409}, + {0xc46e, 0}, + {0xc46f, 1}, + {0xc470, 2}, + {0xc471, 3}, + {0xc472, 4}, + {0xc473, 5}, + {0xc474, 2410}, + {0xc475, 2411}, + {0xc477, 0}, + {0xc478, 1}, + {0xc479, 2412}, + {0xc47b, 0}, + {0xc47c, 1}, + {0xc47d, 2}, + {0xc47e, 3}, + {0xc47f, 4}, + {0xc480, 2413}, + {0xc482, 0}, + {0xc483, 1}, + {0xc484, 2}, + {0xc485, 3}, + {0xc486, 4}, + {0xc487, 5}, + {0xc488, 6}, + {0xc489, 7}, + {0xc48a, 8}, + {0xc48b, 9}, + {0xc48c, 10}, + {0xc48d, 11}, + {0xc48e, 12}, + {0xc48f, 13}, + {0xc490, 14}, + {0xc491, 15}, + {0xc492, 16}, + {0xc493, 17}, + {0xc494, 2414}, + {0xc496, 0}, + {0xc497, 1}, + {0xc498, 2}, + {0xc499, 3}, + {0xc49a, 4}, + {0xc49b, 5}, + {0xc49c, 2415}, + {0xc49e, 0}, + {0xc49f, 1}, + {0xc4a0, 2}, + {0xc4a1, 3}, + {0xc4a2, 4}, + {0xc4a3, 5}, + {0xc4a4, 6}, + {0xc4a5, 7}, + {0xc4a6, 8}, + {0xc4a7, 9}, + {0xc4a8, 10}, + {0xc4a9, 11}, + {0xc4aa, 12}, + {0xc4ab, 13}, + {0xc4ac, 14}, + {0xc4ad, 15}, + {0xc4ae, 16}, + {0xc4af, 17}, + {0xc4b0, 18}, + {0xc4b1, 19}, + {0xc4b2, 20}, + {0xc4b3, 21}, + {0xc4b4, 22}, + {0xc4b5, 23}, + {0xc4b6, 24}, + {0xc4b7, 25}, + {0xc4b8, 2416}, + {0xc4ba, 0}, + {0xc4bb, 1}, + {0xc4bc, 2417}, + {0xc4be, 0}, + {0xc4bf, 1}, + {0xc4c0, 2}, + {0xc4c1, 3}, + {0xc4c2, 4}, + {0xc4c3, 5}, + {0xc4c4, 6}, + {0xc4c5, 7}, + {0xc4c6, 8}, + {0xc4c7, 9}, + {0xc4c8, 10}, + {0xc4c9, 11}, + {0xc4ca, 12}, + {0xc4cb, 13}, + {0xc4cc, 14}, + {0xc4cd, 15}, + {0xc4ce, 16}, + {0xc4cf, 17}, + {0xc4d0, 18}, + {0xc4d1, 19}, + {0xc4d2, 20}, + {0xc4d3, 21}, + {0xc4d4, 22}, + {0xc4d5, 23}, + {0xc4d6, 24}, + {0xc4d7, 25}, + {0xc4d8, 26}, + {0xc4d9, 27}, + {0xc4da, 28}, + {0xc4db, 29}, + {0xc4dc, 30}, + {0xc4dd, 31}, + {0xc4de, 32}, + {0xc4df, 33}, + {0xc4e0, 34}, + {0xc4e1, 35}, + {0xc4e2, 36}, + {0xc4e3, 37}, + {0xc4e4, 38}, + {0xc4e5, 39}, + {0xc4e6, 40}, + {0xc4e7, 41}, + {0xc4e8, 42}, + {0xc4e9, 2418}, + {0xc4eb, 0}, + {0xc4ec, 1}, + {0xc4ed, 2}, + {0xc4ee, 3}, + {0xc4ef, 4}, + {0xc4f0, 2419}, + {0xc4f1, 2420}, + {0xc4f3, 0}, + {0xc4f4, 2421}, + {0xc4f6, 0}, + {0xc4f7, 1}, + {0xc4f8, 2422}, + {0xc4fa, 2423}, + {0xc4fc, 0}, + {0xc4fd, 1}, + {0xc4fe, 2}, + {0xc4ff, 2424}, + {0xc500, 2425}, + {0xc501, 2426}, + {0xc503, 0}, + {0xc504, 1}, + {0xc505, 2}, + {0xc506, 3}, + {0xc507, 4}, + {0xc508, 5}, + {0xc509, 6}, + {0xc50a, 7}, + {0xc50b, 8}, + {0xc50c, 2427}, + {0xc50e, 0}, + {0xc50f, 1}, + {0xc510, 2428}, + {0xc512, 0}, + {0xc513, 1}, + {0xc514, 2429}, + {0xc516, 0}, + {0xc517, 1}, + {0xc518, 2}, + {0xc519, 3}, + {0xc51a, 4}, + {0xc51b, 5}, + {0xc51c, 2430}, + {0xc51e, 0}, + {0xc51f, 1}, + {0xc520, 2}, + {0xc521, 3}, + {0xc522, 4}, + {0xc523, 5}, + {0xc524, 6}, + {0xc525, 7}, + {0xc526, 8}, + {0xc527, 9}, + {0xc528, 2431}, + {0xc529, 2432}, + {0xc52b, 0}, + {0xc52c, 2433}, + {0xc52e, 0}, + {0xc52f, 1}, + {0xc530, 2434}, + {0xc532, 0}, + {0xc533, 1}, + {0xc534, 2}, + {0xc535, 3}, + {0xc536, 4}, + {0xc537, 5}, + {0xc538, 2435}, + {0xc539, 2436}, + {0xc53b, 2437}, + {0xc53d, 2438}, + {0xc53f, 0}, + {0xc540, 1}, + {0xc541, 2}, + {0xc542, 3}, + {0xc543, 4}, + {0xc544, 2439}, + {0xc545, 2440}, + {0xc547, 0}, + {0xc548, 2441}, + {0xc549, 2442}, + {0xc54a, 2443}, + {0xc54c, 2444}, + {0xc54d, 2445}, + {0xc54e, 2446}, + {0xc550, 0}, + {0xc551, 1}, + {0xc552, 2}, + {0xc553, 2447}, + {0xc554, 2448}, + {0xc555, 2449}, + {0xc557, 2450}, + {0xc558, 2451}, + {0xc559, 2452}, + {0xc55b, 0}, + {0xc55c, 1}, + {0xc55d, 2453}, + {0xc55e, 2454}, + {0xc560, 2455}, + {0xc561, 2456}, + {0xc563, 0}, + {0xc564, 2457}, + {0xc566, 0}, + {0xc567, 1}, + {0xc568, 2458}, + {0xc56a, 0}, + {0xc56b, 1}, + {0xc56c, 2}, + {0xc56d, 3}, + {0xc56e, 4}, + {0xc56f, 5}, + {0xc570, 2459}, + {0xc571, 2460}, + {0xc573, 2461}, + {0xc574, 2462}, + {0xc575, 2463}, + {0xc577, 0}, + {0xc578, 1}, + {0xc579, 2}, + {0xc57a, 3}, + {0xc57b, 4}, + {0xc57c, 2464}, + {0xc57d, 2465}, + {0xc57f, 0}, + {0xc580, 2466}, + {0xc582, 0}, + {0xc583, 1}, + {0xc584, 2467}, + {0xc586, 0}, + {0xc587, 2468}, + {0xc589, 0}, + {0xc58a, 1}, + {0xc58b, 2}, + {0xc58c, 2469}, + {0xc58d, 2470}, + {0xc58f, 2471}, + {0xc591, 2472}, + {0xc593, 0}, + {0xc594, 1}, + {0xc595, 2473}, + {0xc597, 2474}, + {0xc598, 2475}, + {0xc59a, 0}, + {0xc59b, 1}, + {0xc59c, 2476}, + {0xc59e, 0}, + {0xc59f, 1}, + {0xc5a0, 2477}, + {0xc5a2, 0}, + {0xc5a3, 1}, + {0xc5a4, 2}, + {0xc5a5, 3}, + {0xc5a6, 4}, + {0xc5a7, 5}, + {0xc5a8, 6}, + {0xc5a9, 2478}, + {0xc5ab, 0}, + {0xc5ac, 1}, + {0xc5ad, 2}, + {0xc5ae, 3}, + {0xc5af, 4}, + {0xc5b0, 5}, + {0xc5b1, 6}, + {0xc5b2, 7}, + {0xc5b3, 8}, + {0xc5b4, 2479}, + {0xc5b5, 2480}, + {0xc5b7, 0}, + {0xc5b8, 2481}, + {0xc5b9, 2482}, + {0xc5bb, 2483}, + {0xc5bc, 2484}, + {0xc5bd, 2485}, + {0xc5be, 2486}, + {0xc5c0, 0}, + {0xc5c1, 1}, + {0xc5c2, 2}, + {0xc5c3, 3}, + {0xc5c4, 2487}, + {0xc5c5, 2488}, + {0xc5c6, 2489}, + {0xc5c7, 2490}, + {0xc5c8, 2491}, + {0xc5c9, 2492}, + {0xc5ca, 2493}, + {0xc5cc, 2494}, + {0xc5ce, 2495}, + {0xc5d0, 2496}, + {0xc5d1, 2497}, + {0xc5d3, 0}, + {0xc5d4, 2498}, + {0xc5d6, 0}, + {0xc5d7, 1}, + {0xc5d8, 2499}, + {0xc5da, 0}, + {0xc5db, 1}, + {0xc5dc, 2}, + {0xc5dd, 3}, + {0xc5de, 4}, + {0xc5df, 5}, + {0xc5e0, 2500}, + {0xc5e1, 2501}, + {0xc5e3, 2502}, + {0xc5e5, 2503}, + {0xc5e7, 0}, + {0xc5e8, 1}, + {0xc5e9, 2}, + {0xc5ea, 3}, + {0xc5eb, 4}, + {0xc5ec, 2504}, + {0xc5ed, 2505}, + {0xc5ee, 2506}, + {0xc5f0, 2507}, + {0xc5f2, 0}, + {0xc5f3, 1}, + {0xc5f4, 2508}, + {0xc5f6, 2509}, + {0xc5f7, 2510}, + {0xc5f9, 0}, + {0xc5fa, 1}, + {0xc5fb, 2}, + {0xc5fc, 2511}, + {0xc5fd, 2512}, + {0xc5fe, 2513}, + {0xc5ff, 2514}, + {0xc600, 2515}, + {0xc601, 2516}, + {0xc603, 0}, + {0xc604, 1}, + {0xc605, 2517}, + {0xc606, 2518}, + {0xc607, 2519}, + {0xc608, 2520}, + {0xc60a, 0}, + {0xc60b, 1}, + {0xc60c, 2521}, + {0xc60e, 0}, + {0xc60f, 1}, + {0xc610, 2522}, + {0xc612, 0}, + {0xc613, 1}, + {0xc614, 2}, + {0xc615, 3}, + {0xc616, 4}, + {0xc617, 5}, + {0xc618, 2523}, + {0xc619, 2524}, + {0xc61b, 2525}, + {0xc61c, 2526}, + {0xc61e, 0}, + {0xc61f, 1}, + {0xc620, 2}, + {0xc621, 3}, + {0xc622, 4}, + {0xc623, 5}, + {0xc624, 2527}, + {0xc625, 2528}, + {0xc627, 0}, + {0xc628, 2529}, + {0xc62a, 0}, + {0xc62b, 1}, + {0xc62c, 2530}, + {0xc62d, 2531}, + {0xc62e, 2532}, + {0xc630, 2533}, + {0xc632, 0}, + {0xc633, 2534}, + {0xc634, 2535}, + {0xc635, 2536}, + {0xc637, 2537}, + {0xc639, 2538}, + {0xc63b, 2539}, + {0xc63d, 0}, + {0xc63e, 1}, + {0xc63f, 2}, + {0xc640, 2540}, + {0xc641, 2541}, + {0xc643, 0}, + {0xc644, 2542}, + {0xc646, 0}, + {0xc647, 1}, + {0xc648, 2543}, + {0xc64a, 0}, + {0xc64b, 1}, + {0xc64c, 2}, + {0xc64d, 3}, + {0xc64e, 4}, + {0xc64f, 5}, + {0xc650, 2544}, + {0xc651, 2545}, + {0xc653, 2546}, + {0xc654, 2547}, + {0xc655, 2548}, + {0xc657, 0}, + {0xc658, 1}, + {0xc659, 2}, + {0xc65a, 3}, + {0xc65b, 4}, + {0xc65c, 2549}, + {0xc65d, 2550}, + {0xc65f, 0}, + {0xc660, 2551}, + {0xc662, 0}, + {0xc663, 1}, + {0xc664, 2}, + {0xc665, 3}, + {0xc666, 4}, + {0xc667, 5}, + {0xc668, 6}, + {0xc669, 7}, + {0xc66a, 8}, + {0xc66b, 9}, + {0xc66c, 2552}, + {0xc66e, 0}, + {0xc66f, 2553}, + {0xc671, 2554}, + {0xc673, 0}, + {0xc674, 1}, + {0xc675, 2}, + {0xc676, 3}, + {0xc677, 4}, + {0xc678, 2555}, + {0xc679, 2556}, + {0xc67b, 0}, + {0xc67c, 2557}, + {0xc67e, 0}, + {0xc67f, 1}, + {0xc680, 2558}, + {0xc682, 0}, + {0xc683, 1}, + {0xc684, 2}, + {0xc685, 3}, + {0xc686, 4}, + {0xc687, 5}, + {0xc688, 2559}, + {0xc689, 2560}, + {0xc68b, 2561}, + {0xc68d, 2562}, + {0xc68f, 0}, + {0xc690, 1}, + {0xc691, 2}, + {0xc692, 3}, + {0xc693, 4}, + {0xc694, 2563}, + {0xc695, 2564}, + {0xc697, 0}, + {0xc698, 2565}, + {0xc69a, 0}, + {0xc69b, 1}, + {0xc69c, 2566}, + {0xc69e, 0}, + {0xc69f, 1}, + {0xc6a0, 2}, + {0xc6a1, 3}, + {0xc6a2, 4}, + {0xc6a3, 5}, + {0xc6a4, 2567}, + {0xc6a5, 2568}, + {0xc6a7, 2569}, + {0xc6a9, 2570}, + {0xc6ab, 0}, + {0xc6ac, 1}, + {0xc6ad, 2}, + {0xc6ae, 3}, + {0xc6af, 4}, + {0xc6b0, 2571}, + {0xc6b1, 2572}, + {0xc6b3, 0}, + {0xc6b4, 2573}, + {0xc6b6, 0}, + {0xc6b7, 1}, + {0xc6b8, 2574}, + {0xc6b9, 2575}, + {0xc6ba, 2576}, + {0xc6bc, 0}, + {0xc6bd, 1}, + {0xc6be, 2}, + {0xc6bf, 3}, + {0xc6c0, 2577}, + {0xc6c1, 2578}, + {0xc6c3, 2579}, + {0xc6c5, 2580}, + {0xc6c7, 0}, + {0xc6c8, 1}, + {0xc6c9, 2}, + {0xc6ca, 3}, + {0xc6cb, 4}, + {0xc6cc, 2581}, + {0xc6cd, 2582}, + {0xc6cf, 0}, + {0xc6d0, 2583}, + {0xc6d2, 0}, + {0xc6d3, 1}, + {0xc6d4, 2584}, + {0xc6d6, 0}, + {0xc6d7, 1}, + {0xc6d8, 2}, + {0xc6d9, 3}, + {0xc6da, 4}, + {0xc6db, 5}, + {0xc6dc, 2585}, + {0xc6dd, 2586}, + {0xc6df, 0}, + {0xc6e0, 2587}, + {0xc6e1, 2588}, + {0xc6e3, 0}, + {0xc6e4, 1}, + {0xc6e5, 2}, + {0xc6e6, 3}, + {0xc6e7, 4}, + {0xc6e8, 2589}, + {0xc6e9, 2590}, + {0xc6eb, 0}, + {0xc6ec, 2591}, + {0xc6ee, 0}, + {0xc6ef, 1}, + {0xc6f0, 2592}, + {0xc6f2, 0}, + {0xc6f3, 1}, + {0xc6f4, 2}, + {0xc6f5, 3}, + {0xc6f6, 4}, + {0xc6f7, 5}, + {0xc6f8, 2593}, + {0xc6f9, 2594}, + {0xc6fb, 0}, + {0xc6fc, 1}, + {0xc6fd, 2595}, + {0xc6ff, 0}, + {0xc701, 0}, + {0xc702, 1}, + {0xc703, 2}, + {0xc704, 2596}, + {0xc705, 2597}, + {0xc707, 0}, + {0xc708, 2598}, + {0xc70a, 0}, + {0xc70b, 1}, + {0xc70c, 2599}, + {0xc70e, 0}, + {0xc70f, 1}, + {0xc710, 2}, + {0xc711, 3}, + {0xc712, 4}, + {0xc713, 5}, + {0xc714, 2600}, + {0xc715, 2601}, + {0xc717, 2602}, + {0xc719, 2603}, + {0xc71b, 0}, + {0xc71c, 1}, + {0xc71d, 2}, + {0xc71e, 3}, + {0xc71f, 4}, + {0xc720, 2604}, + {0xc721, 2605}, + {0xc723, 0}, + {0xc724, 2606}, + {0xc726, 0}, + {0xc727, 1}, + {0xc728, 2607}, + {0xc72a, 0}, + {0xc72b, 1}, + {0xc72c, 2}, + {0xc72d, 3}, + {0xc72e, 4}, + {0xc72f, 5}, + {0xc730, 2608}, + {0xc731, 2609}, + {0xc733, 2610}, + {0xc735, 2611}, + {0xc737, 2612}, + {0xc739, 0}, + {0xc73a, 1}, + {0xc73b, 2}, + {0xc73c, 2613}, + {0xc73d, 2614}, + {0xc73f, 0}, + {0xc740, 2615}, + {0xc742, 0}, + {0xc743, 1}, + {0xc744, 2616}, + {0xc746, 0}, + {0xc747, 1}, + {0xc748, 2}, + {0xc749, 3}, + {0xc74a, 2617}, + {0xc74c, 2618}, + {0xc74d, 2619}, + {0xc74f, 2620}, + {0xc751, 2621}, + {0xc752, 2622}, + {0xc753, 2623}, + {0xc754, 2624}, + {0xc755, 2625}, + {0xc756, 2626}, + {0xc757, 2627}, + {0xc758, 2628}, + {0xc75a, 0}, + {0xc75b, 1}, + {0xc75c, 2629}, + {0xc75e, 0}, + {0xc75f, 1}, + {0xc760, 2630}, + {0xc762, 0}, + {0xc763, 1}, + {0xc764, 2}, + {0xc765, 3}, + {0xc766, 4}, + {0xc767, 5}, + {0xc768, 2631}, + {0xc76a, 0}, + {0xc76b, 2632}, + {0xc76d, 0}, + {0xc76e, 1}, + {0xc76f, 2}, + {0xc770, 3}, + {0xc771, 4}, + {0xc772, 5}, + {0xc773, 6}, + {0xc774, 2633}, + {0xc775, 2634}, + {0xc777, 0}, + {0xc778, 2635}, + {0xc77a, 0}, + {0xc77b, 1}, + {0xc77c, 2636}, + {0xc77d, 2637}, + {0xc77e, 2638}, + {0xc780, 0}, + {0xc781, 1}, + {0xc782, 2}, + {0xc783, 2639}, + {0xc784, 2640}, + {0xc785, 2641}, + {0xc787, 2642}, + {0xc788, 2643}, + {0xc789, 2644}, + {0xc78a, 2645}, + {0xc78c, 0}, + {0xc78d, 1}, + {0xc78e, 2646}, + {0xc790, 2647}, + {0xc791, 2648}, + {0xc793, 0}, + {0xc794, 2649}, + {0xc796, 2650}, + {0xc797, 2651}, + {0xc798, 2652}, + {0xc79a, 2653}, + {0xc79c, 0}, + {0xc79d, 1}, + {0xc79e, 2}, + {0xc79f, 3}, + {0xc7a0, 2654}, + {0xc7a1, 2655}, + {0xc7a3, 2656}, + {0xc7a4, 2657}, + {0xc7a5, 2658}, + {0xc7a6, 2659}, + {0xc7a8, 0}, + {0xc7a9, 1}, + {0xc7aa, 2}, + {0xc7ab, 3}, + {0xc7ac, 2660}, + {0xc7ad, 2661}, + {0xc7af, 0}, + {0xc7b0, 2662}, + {0xc7b2, 0}, + {0xc7b3, 1}, + {0xc7b4, 2663}, + {0xc7b6, 0}, + {0xc7b7, 1}, + {0xc7b8, 2}, + {0xc7b9, 3}, + {0xc7ba, 4}, + {0xc7bb, 5}, + {0xc7bc, 2664}, + {0xc7bd, 2665}, + {0xc7bf, 2666}, + {0xc7c0, 2667}, + {0xc7c1, 2668}, + {0xc7c3, 0}, + {0xc7c4, 1}, + {0xc7c5, 2}, + {0xc7c6, 3}, + {0xc7c7, 4}, + {0xc7c8, 2669}, + {0xc7c9, 2670}, + {0xc7cb, 0}, + {0xc7cc, 2671}, + {0xc7ce, 2672}, + {0xc7d0, 2673}, + {0xc7d2, 0}, + {0xc7d3, 1}, + {0xc7d4, 2}, + {0xc7d5, 3}, + {0xc7d6, 4}, + {0xc7d7, 5}, + {0xc7d8, 2674}, + {0xc7da, 0}, + {0xc7db, 1}, + {0xc7dc, 2}, + {0xc7dd, 2675}, + {0xc7df, 0}, + {0xc7e0, 1}, + {0xc7e1, 2}, + {0xc7e2, 3}, + {0xc7e3, 4}, + {0xc7e4, 2676}, + {0xc7e6, 0}, + {0xc7e7, 1}, + {0xc7e8, 2677}, + {0xc7ea, 0}, + {0xc7eb, 1}, + {0xc7ec, 2678}, + {0xc7ee, 0}, + {0xc7ef, 1}, + {0xc7f0, 2}, + {0xc7f1, 3}, + {0xc7f2, 4}, + {0xc7f3, 5}, + {0xc7f4, 6}, + {0xc7f5, 7}, + {0xc7f6, 8}, + {0xc7f7, 9}, + {0xc7f8, 10}, + {0xc7f9, 11}, + {0xc7fa, 12}, + {0xc7fb, 13}, + {0xc7fc, 14}, + {0xc7fd, 15}, + {0xc7fe, 16}, + {0xc7ff, 17}, + {0xc800, 2679}, + {0xc801, 2680}, + {0xc803, 0}, + {0xc804, 2681}, + {0xc806, 0}, + {0xc807, 1}, + {0xc808, 2682}, + {0xc80a, 2683}, + {0xc80c, 0}, + {0xc80d, 1}, + {0xc80e, 2}, + {0xc80f, 3}, + {0xc810, 2684}, + {0xc811, 2685}, + {0xc813, 2686}, + {0xc815, 2687}, + {0xc816, 2688}, + {0xc818, 0}, + {0xc819, 1}, + {0xc81a, 2}, + {0xc81b, 3}, + {0xc81c, 2689}, + {0xc81d, 2690}, + {0xc81f, 0}, + {0xc820, 2691}, + {0xc822, 0}, + {0xc823, 1}, + {0xc824, 2692}, + {0xc826, 0}, + {0xc827, 1}, + {0xc828, 2}, + {0xc829, 3}, + {0xc82a, 4}, + {0xc82b, 5}, + {0xc82c, 2693}, + {0xc82d, 2694}, + {0xc82f, 2695}, + {0xc831, 2696}, + {0xc833, 0}, + {0xc834, 1}, + {0xc835, 2}, + {0xc836, 3}, + {0xc837, 4}, + {0xc838, 2697}, + {0xc83a, 0}, + {0xc83b, 1}, + {0xc83c, 2698}, + {0xc83e, 0}, + {0xc83f, 1}, + {0xc840, 2699}, + {0xc842, 0}, + {0xc843, 1}, + {0xc844, 2}, + {0xc845, 3}, + {0xc846, 4}, + {0xc847, 5}, + {0xc848, 2700}, + {0xc849, 2701}, + {0xc84b, 0}, + {0xc84c, 2702}, + {0xc84d, 2703}, + {0xc84f, 0}, + {0xc850, 1}, + {0xc851, 2}, + {0xc852, 3}, + {0xc853, 4}, + {0xc854, 2704}, + {0xc856, 0}, + {0xc857, 1}, + {0xc858, 2}, + {0xc859, 3}, + {0xc85a, 4}, + {0xc85b, 5}, + {0xc85c, 6}, + {0xc85d, 7}, + {0xc85e, 8}, + {0xc85f, 9}, + {0xc860, 10}, + {0xc861, 11}, + {0xc862, 12}, + {0xc863, 13}, + {0xc864, 14}, + {0xc865, 15}, + {0xc866, 16}, + {0xc867, 17}, + {0xc868, 18}, + {0xc869, 19}, + {0xc86a, 20}, + {0xc86b, 21}, + {0xc86c, 22}, + {0xc86d, 23}, + {0xc86e, 24}, + {0xc86f, 25}, + {0xc870, 2705}, + {0xc871, 2706}, + {0xc873, 0}, + {0xc874, 2707}, + {0xc876, 0}, + {0xc877, 1}, + {0xc878, 2708}, + {0xc87a, 2709}, + {0xc87c, 0}, + {0xc87d, 1}, + {0xc87e, 2}, + {0xc87f, 3}, + {0xc880, 2710}, + {0xc881, 2711}, + {0xc883, 2712}, + {0xc885, 2713}, + {0xc886, 2714}, + {0xc887, 2715}, + {0xc889, 0}, + {0xc88a, 1}, + {0xc88b, 2716}, + {0xc88c, 2717}, + {0xc88d, 2718}, + {0xc88f, 0}, + {0xc890, 1}, + {0xc891, 2}, + {0xc892, 3}, + {0xc893, 4}, + {0xc894, 2719}, + {0xc896, 0}, + {0xc897, 1}, + {0xc898, 2}, + {0xc899, 3}, + {0xc89a, 4}, + {0xc89b, 5}, + {0xc89c, 6}, + {0xc89d, 2720}, + {0xc89f, 2721}, + {0xc8a1, 2722}, + {0xc8a3, 0}, + {0xc8a4, 1}, + {0xc8a5, 2}, + {0xc8a6, 3}, + {0xc8a7, 4}, + {0xc8a8, 2723}, + {0xc8aa, 0}, + {0xc8ab, 1}, + {0xc8ac, 2}, + {0xc8ad, 3}, + {0xc8ae, 4}, + {0xc8af, 5}, + {0xc8b0, 6}, + {0xc8b1, 7}, + {0xc8b2, 8}, + {0xc8b3, 9}, + {0xc8b4, 10}, + {0xc8b5, 11}, + {0xc8b6, 12}, + {0xc8b7, 13}, + {0xc8b8, 14}, + {0xc8b9, 15}, + {0xc8ba, 16}, + {0xc8bb, 17}, + {0xc8bc, 2724}, + {0xc8bd, 2725}, + {0xc8bf, 0}, + {0xc8c0, 1}, + {0xc8c1, 2}, + {0xc8c2, 3}, + {0xc8c3, 4}, + {0xc8c4, 2726}, + {0xc8c6, 0}, + {0xc8c7, 1}, + {0xc8c8, 2727}, + {0xc8ca, 0}, + {0xc8cb, 1}, + {0xc8cc, 2728}, + {0xc8ce, 0}, + {0xc8cf, 1}, + {0xc8d0, 2}, + {0xc8d1, 3}, + {0xc8d2, 4}, + {0xc8d3, 5}, + {0xc8d4, 2729}, + {0xc8d5, 2730}, + {0xc8d7, 2731}, + {0xc8d9, 2732}, + {0xc8db, 0}, + {0xc8dc, 1}, + {0xc8dd, 2}, + {0xc8de, 3}, + {0xc8df, 4}, + {0xc8e0, 2733}, + {0xc8e1, 2734}, + {0xc8e3, 0}, + {0xc8e4, 2735}, + {0xc8e6, 0}, + {0xc8e7, 1}, + {0xc8e8, 2}, + {0xc8e9, 3}, + {0xc8ea, 4}, + {0xc8eb, 5}, + {0xc8ec, 6}, + {0xc8ed, 7}, + {0xc8ee, 8}, + {0xc8ef, 9}, + {0xc8f0, 10}, + {0xc8f1, 11}, + {0xc8f2, 12}, + {0xc8f3, 13}, + {0xc8f4, 14}, + {0xc8f5, 2736}, + {0xc8f7, 0}, + {0xc8f8, 1}, + {0xc8f9, 2}, + {0xc8fa, 3}, + {0xc8fb, 4}, + {0xc8fc, 2737}, + {0xc8fd, 2738}, + {0xc8ff, 0}, + {0xc900, 2739}, + {0xc902, 0}, + {0xc903, 1}, + {0xc904, 2740}, + {0xc905, 2741}, + {0xc906, 2742}, + {0xc908, 0}, + {0xc909, 1}, + {0xc90a, 2}, + {0xc90b, 3}, + {0xc90c, 2743}, + {0xc90d, 2744}, + {0xc90f, 2745}, + {0xc911, 2746}, + {0xc913, 0}, + {0xc914, 1}, + {0xc915, 2}, + {0xc916, 3}, + {0xc917, 4}, + {0xc918, 2747}, + {0xc91a, 0}, + {0xc91b, 1}, + {0xc91c, 2}, + {0xc91d, 3}, + {0xc91e, 4}, + {0xc91f, 5}, + {0xc920, 6}, + {0xc921, 7}, + {0xc922, 8}, + {0xc923, 9}, + {0xc924, 10}, + {0xc925, 11}, + {0xc926, 12}, + {0xc927, 13}, + {0xc928, 14}, + {0xc929, 15}, + {0xc92a, 16}, + {0xc92b, 17}, + {0xc92c, 2748}, + {0xc92e, 0}, + {0xc92f, 1}, + {0xc930, 2}, + {0xc931, 3}, + {0xc932, 4}, + {0xc933, 5}, + {0xc934, 2749}, + {0xc936, 0}, + {0xc937, 1}, + {0xc938, 2}, + {0xc939, 3}, + {0xc93a, 4}, + {0xc93b, 5}, + {0xc93c, 6}, + {0xc93d, 7}, + {0xc93e, 8}, + {0xc93f, 9}, + {0xc940, 10}, + {0xc941, 11}, + {0xc942, 12}, + {0xc943, 13}, + {0xc944, 14}, + {0xc945, 15}, + {0xc946, 16}, + {0xc947, 17}, + {0xc948, 18}, + {0xc949, 19}, + {0xc94a, 20}, + {0xc94b, 21}, + {0xc94c, 22}, + {0xc94d, 23}, + {0xc94e, 24}, + {0xc94f, 25}, + {0xc950, 2750}, + {0xc951, 2751}, + {0xc953, 0}, + {0xc954, 2752}, + {0xc956, 0}, + {0xc957, 1}, + {0xc958, 2753}, + {0xc95a, 0}, + {0xc95b, 1}, + {0xc95c, 2}, + {0xc95d, 3}, + {0xc95e, 4}, + {0xc95f, 5}, + {0xc960, 2754}, + {0xc961, 2755}, + {0xc963, 2756}, + {0xc965, 0}, + {0xc966, 1}, + {0xc967, 2}, + {0xc968, 3}, + {0xc969, 4}, + {0xc96a, 5}, + {0xc96b, 6}, + {0xc96c, 2757}, + {0xc96e, 0}, + {0xc96f, 1}, + {0xc970, 2758}, + {0xc972, 0}, + {0xc973, 1}, + {0xc974, 2759}, + {0xc976, 0}, + {0xc977, 1}, + {0xc978, 2}, + {0xc979, 3}, + {0xc97a, 4}, + {0xc97b, 5}, + {0xc97c, 2760}, + {0xc97e, 0}, + {0xc97f, 1}, + {0xc980, 2}, + {0xc981, 3}, + {0xc982, 4}, + {0xc983, 5}, + {0xc984, 6}, + {0xc985, 7}, + {0xc986, 8}, + {0xc987, 9}, + {0xc988, 2761}, + {0xc989, 2762}, + {0xc98b, 0}, + {0xc98c, 2763}, + {0xc98e, 0}, + {0xc98f, 1}, + {0xc990, 2764}, + {0xc992, 0}, + {0xc993, 1}, + {0xc994, 2}, + {0xc995, 3}, + {0xc996, 4}, + {0xc997, 5}, + {0xc998, 2765}, + {0xc999, 2766}, + {0xc99b, 2767}, + {0xc99d, 2768}, + {0xc99f, 0}, + {0xc9a0, 1}, + {0xc9a1, 2}, + {0xc9a2, 3}, + {0xc9a3, 4}, + {0xc9a4, 5}, + {0xc9a5, 6}, + {0xc9a6, 7}, + {0xc9a7, 8}, + {0xc9a8, 9}, + {0xc9a9, 10}, + {0xc9aa, 11}, + {0xc9ab, 12}, + {0xc9ac, 13}, + {0xc9ad, 14}, + {0xc9ae, 15}, + {0xc9af, 16}, + {0xc9b0, 17}, + {0xc9b1, 18}, + {0xc9b2, 19}, + {0xc9b3, 20}, + {0xc9b4, 21}, + {0xc9b5, 22}, + {0xc9b6, 23}, + {0xc9b7, 24}, + {0xc9b8, 25}, + {0xc9b9, 26}, + {0xc9ba, 27}, + {0xc9bb, 28}, + {0xc9bc, 29}, + {0xc9bd, 30}, + {0xc9be, 31}, + {0xc9bf, 32}, + {0xc9c0, 2769}, + {0xc9c1, 2770}, + {0xc9c3, 0}, + {0xc9c4, 2771}, + {0xc9c6, 0}, + {0xc9c7, 2772}, + {0xc9c8, 2773}, + {0xc9ca, 2774}, + {0xc9cc, 0}, + {0xc9cd, 1}, + {0xc9ce, 2}, + {0xc9cf, 3}, + {0xc9d0, 2775}, + {0xc9d1, 2776}, + {0xc9d3, 2777}, + {0xc9d5, 2778}, + {0xc9d6, 2779}, + {0xc9d8, 0}, + {0xc9d9, 2780}, + {0xc9da, 2781}, + {0xc9dc, 2782}, + {0xc9dd, 2783}, + {0xc9df, 0}, + {0xc9e0, 2784}, + {0xc9e2, 2785}, + {0xc9e4, 2786}, + {0xc9e6, 0}, + {0xc9e7, 2787}, + {0xc9e9, 0}, + {0xc9ea, 1}, + {0xc9eb, 2}, + {0xc9ec, 2788}, + {0xc9ed, 2789}, + {0xc9ef, 2790}, + {0xc9f0, 2791}, + {0xc9f1, 2792}, + {0xc9f3, 0}, + {0xc9f4, 1}, + {0xc9f5, 2}, + {0xc9f6, 3}, + {0xc9f7, 4}, + {0xc9f8, 2793}, + {0xc9f9, 2794}, + {0xc9fb, 0}, + {0xc9fc, 2795}, + {0xc9fe, 0}, + {0xc9ff, 1}, + {0xca00, 2796}, + {0xca02, 0}, + {0xca03, 1}, + {0xca04, 2}, + {0xca05, 3}, + {0xca06, 4}, + {0xca07, 5}, + {0xca08, 2797}, + {0xca09, 2798}, + {0xca0b, 2799}, + {0xca0c, 2800}, + {0xca0d, 2801}, + {0xca0f, 0}, + {0xca10, 1}, + {0xca11, 2}, + {0xca12, 3}, + {0xca13, 4}, + {0xca14, 2802}, + {0xca16, 0}, + {0xca17, 1}, + {0xca18, 2803}, + {0xca1a, 0}, + {0xca1b, 1}, + {0xca1c, 2}, + {0xca1d, 3}, + {0xca1e, 4}, + {0xca1f, 5}, + {0xca20, 6}, + {0xca21, 7}, + {0xca22, 8}, + {0xca23, 9}, + {0xca24, 10}, + {0xca25, 11}, + {0xca26, 12}, + {0xca27, 13}, + {0xca28, 14}, + {0xca29, 2804}, + {0xca2b, 0}, + {0xca2c, 1}, + {0xca2d, 2}, + {0xca2e, 3}, + {0xca2f, 4}, + {0xca30, 5}, + {0xca31, 6}, + {0xca32, 7}, + {0xca33, 8}, + {0xca34, 9}, + {0xca35, 10}, + {0xca36, 11}, + {0xca37, 12}, + {0xca38, 13}, + {0xca39, 14}, + {0xca3a, 15}, + {0xca3b, 16}, + {0xca3c, 17}, + {0xca3d, 18}, + {0xca3e, 19}, + {0xca3f, 20}, + {0xca40, 21}, + {0xca41, 22}, + {0xca42, 23}, + {0xca43, 24}, + {0xca44, 25}, + {0xca45, 26}, + {0xca46, 27}, + {0xca47, 28}, + {0xca48, 29}, + {0xca49, 30}, + {0xca4a, 31}, + {0xca4b, 32}, + {0xca4c, 2805}, + {0xca4d, 2806}, + {0xca4f, 0}, + {0xca50, 2807}, + {0xca52, 0}, + {0xca53, 1}, + {0xca54, 2808}, + {0xca56, 0}, + {0xca57, 1}, + {0xca58, 2}, + {0xca59, 3}, + {0xca5a, 4}, + {0xca5b, 5}, + {0xca5c, 2809}, + {0xca5d, 2810}, + {0xca5f, 2811}, + {0xca60, 2812}, + {0xca61, 2813}, + {0xca63, 0}, + {0xca64, 1}, + {0xca65, 2}, + {0xca66, 3}, + {0xca67, 4}, + {0xca68, 2814}, + {0xca6a, 0}, + {0xca6b, 1}, + {0xca6c, 2}, + {0xca6d, 3}, + {0xca6e, 4}, + {0xca6f, 5}, + {0xca70, 6}, + {0xca71, 7}, + {0xca72, 8}, + {0xca73, 9}, + {0xca74, 10}, + {0xca75, 11}, + {0xca76, 12}, + {0xca77, 13}, + {0xca78, 14}, + {0xca79, 15}, + {0xca7a, 16}, + {0xca7b, 17}, + {0xca7c, 18}, + {0xca7d, 2815}, + {0xca7f, 0}, + {0xca80, 1}, + {0xca81, 2}, + {0xca82, 3}, + {0xca83, 4}, + {0xca84, 2816}, + {0xca86, 0}, + {0xca87, 1}, + {0xca88, 2}, + {0xca89, 3}, + {0xca8a, 4}, + {0xca8b, 5}, + {0xca8c, 6}, + {0xca8d, 7}, + {0xca8e, 8}, + {0xca8f, 9}, + {0xca90, 10}, + {0xca91, 11}, + {0xca92, 12}, + {0xca93, 13}, + {0xca94, 14}, + {0xca95, 15}, + {0xca96, 16}, + {0xca97, 17}, + {0xca98, 2817}, + {0xca9a, 0}, + {0xca9b, 1}, + {0xca9c, 2}, + {0xca9d, 3}, + {0xca9e, 4}, + {0xca9f, 5}, + {0xcaa0, 6}, + {0xcaa1, 7}, + {0xcaa2, 8}, + {0xcaa3, 9}, + {0xcaa4, 10}, + {0xcaa5, 11}, + {0xcaa6, 12}, + {0xcaa7, 13}, + {0xcaa8, 14}, + {0xcaa9, 15}, + {0xcaaa, 16}, + {0xcaab, 17}, + {0xcaac, 18}, + {0xcaad, 19}, + {0xcaae, 20}, + {0xcaaf, 21}, + {0xcab0, 22}, + {0xcab1, 23}, + {0xcab2, 24}, + {0xcab3, 25}, + {0xcab4, 26}, + {0xcab5, 27}, + {0xcab6, 28}, + {0xcab7, 29}, + {0xcab8, 30}, + {0xcab9, 31}, + {0xcaba, 32}, + {0xcabb, 33}, + {0xcabc, 2818}, + {0xcabd, 2819}, + {0xcabf, 0}, + {0xcac0, 2820}, + {0xcac2, 0}, + {0xcac3, 1}, + {0xcac4, 2821}, + {0xcac6, 0}, + {0xcac7, 1}, + {0xcac8, 2}, + {0xcac9, 3}, + {0xcaca, 4}, + {0xcacb, 5}, + {0xcacc, 2822}, + {0xcacd, 2823}, + {0xcacf, 2824}, + {0xcad1, 2825}, + {0xcad3, 2826}, + {0xcad5, 0}, + {0xcad6, 1}, + {0xcad7, 2}, + {0xcad8, 2827}, + {0xcad9, 2828}, + {0xcadb, 0}, + {0xcadc, 1}, + {0xcadd, 2}, + {0xcade, 3}, + {0xcadf, 4}, + {0xcae0, 2829}, + {0xcae2, 0}, + {0xcae3, 1}, + {0xcae4, 2}, + {0xcae5, 3}, + {0xcae6, 4}, + {0xcae7, 5}, + {0xcae8, 6}, + {0xcae9, 7}, + {0xcaea, 8}, + {0xcaeb, 9}, + {0xcaec, 2830}, + {0xcaee, 0}, + {0xcaef, 1}, + {0xcaf0, 2}, + {0xcaf1, 3}, + {0xcaf2, 4}, + {0xcaf3, 5}, + {0xcaf4, 2831}, + {0xcaf6, 0}, + {0xcaf7, 1}, + {0xcaf8, 2}, + {0xcaf9, 3}, + {0xcafa, 4}, + {0xcafb, 5}, + {0xcafc, 6}, + {0xcafd, 7}, + {0xcafe, 8}, + {0xcaff, 9}, + {0xcb01, 0}, + {0xcb02, 1}, + {0xcb03, 2}, + {0xcb04, 3}, + {0xcb05, 4}, + {0xcb06, 5}, + {0xcb07, 6}, + {0xcb08, 2832}, + {0xcb0a, 0}, + {0xcb0b, 1}, + {0xcb0c, 2}, + {0xcb0d, 3}, + {0xcb0e, 4}, + {0xcb0f, 5}, + {0xcb10, 2833}, + {0xcb12, 0}, + {0xcb13, 1}, + {0xcb14, 2834}, + {0xcb16, 0}, + {0xcb17, 1}, + {0xcb18, 2835}, + {0xcb1a, 0}, + {0xcb1b, 1}, + {0xcb1c, 2}, + {0xcb1d, 3}, + {0xcb1e, 4}, + {0xcb1f, 5}, + {0xcb20, 2836}, + {0xcb21, 2837}, + {0xcb23, 0}, + {0xcb24, 1}, + {0xcb25, 2}, + {0xcb26, 3}, + {0xcb27, 4}, + {0xcb28, 5}, + {0xcb29, 6}, + {0xcb2a, 7}, + {0xcb2b, 8}, + {0xcb2c, 9}, + {0xcb2d, 10}, + {0xcb2e, 11}, + {0xcb2f, 12}, + {0xcb30, 13}, + {0xcb31, 14}, + {0xcb32, 15}, + {0xcb33, 16}, + {0xcb34, 17}, + {0xcb35, 18}, + {0xcb36, 19}, + {0xcb37, 20}, + {0xcb38, 21}, + {0xcb39, 22}, + {0xcb3a, 23}, + {0xcb3b, 24}, + {0xcb3c, 25}, + {0xcb3d, 26}, + {0xcb3e, 27}, + {0xcb3f, 28}, + {0xcb40, 29}, + {0xcb41, 2838}, + {0xcb43, 0}, + {0xcb44, 1}, + {0xcb45, 2}, + {0xcb46, 3}, + {0xcb47, 4}, + {0xcb48, 2839}, + {0xcb49, 2840}, + {0xcb4b, 0}, + {0xcb4c, 2841}, + {0xcb4e, 0}, + {0xcb4f, 1}, + {0xcb50, 2842}, + {0xcb52, 0}, + {0xcb53, 1}, + {0xcb54, 2}, + {0xcb55, 3}, + {0xcb56, 4}, + {0xcb57, 5}, + {0xcb58, 2843}, + {0xcb59, 2844}, + {0xcb5b, 0}, + {0xcb5c, 1}, + {0xcb5d, 2845}, + {0xcb5f, 0}, + {0xcb60, 1}, + {0xcb61, 2}, + {0xcb62, 3}, + {0xcb63, 4}, + {0xcb64, 2846}, + {0xcb66, 0}, + {0xcb67, 1}, + {0xcb68, 2}, + {0xcb69, 3}, + {0xcb6a, 4}, + {0xcb6b, 5}, + {0xcb6c, 6}, + {0xcb6d, 7}, + {0xcb6e, 8}, + {0xcb6f, 9}, + {0xcb70, 10}, + {0xcb71, 11}, + {0xcb72, 12}, + {0xcb73, 13}, + {0xcb74, 14}, + {0xcb75, 15}, + {0xcb76, 16}, + {0xcb77, 17}, + {0xcb78, 2847}, + {0xcb79, 2848}, + {0xcb7b, 0}, + {0xcb7c, 1}, + {0xcb7d, 2}, + {0xcb7e, 3}, + {0xcb7f, 4}, + {0xcb80, 5}, + {0xcb81, 6}, + {0xcb82, 7}, + {0xcb83, 8}, + {0xcb84, 9}, + {0xcb85, 10}, + {0xcb86, 11}, + {0xcb87, 12}, + {0xcb88, 13}, + {0xcb89, 14}, + {0xcb8a, 15}, + {0xcb8b, 16}, + {0xcb8c, 17}, + {0xcb8d, 18}, + {0xcb8e, 19}, + {0xcb8f, 20}, + {0xcb90, 21}, + {0xcb91, 22}, + {0xcb92, 23}, + {0xcb93, 24}, + {0xcb94, 25}, + {0xcb95, 26}, + {0xcb96, 27}, + {0xcb97, 28}, + {0xcb98, 29}, + {0xcb99, 30}, + {0xcb9a, 31}, + {0xcb9b, 32}, + {0xcb9c, 2849}, + {0xcb9e, 0}, + {0xcb9f, 1}, + {0xcba0, 2}, + {0xcba1, 3}, + {0xcba2, 4}, + {0xcba3, 5}, + {0xcba4, 6}, + {0xcba5, 7}, + {0xcba6, 8}, + {0xcba7, 9}, + {0xcba8, 10}, + {0xcba9, 11}, + {0xcbaa, 12}, + {0xcbab, 13}, + {0xcbac, 14}, + {0xcbad, 15}, + {0xcbae, 16}, + {0xcbaf, 17}, + {0xcbb0, 18}, + {0xcbb1, 19}, + {0xcbb2, 20}, + {0xcbb3, 21}, + {0xcbb4, 22}, + {0xcbb5, 23}, + {0xcbb6, 24}, + {0xcbb7, 25}, + {0xcbb8, 2850}, + {0xcbba, 0}, + {0xcbbb, 1}, + {0xcbbc, 2}, + {0xcbbd, 3}, + {0xcbbe, 4}, + {0xcbbf, 5}, + {0xcbc0, 6}, + {0xcbc1, 7}, + {0xcbc2, 8}, + {0xcbc3, 9}, + {0xcbc4, 10}, + {0xcbc5, 11}, + {0xcbc6, 12}, + {0xcbc7, 13}, + {0xcbc8, 14}, + {0xcbc9, 15}, + {0xcbca, 16}, + {0xcbcb, 17}, + {0xcbcc, 18}, + {0xcbcd, 19}, + {0xcbce, 20}, + {0xcbcf, 21}, + {0xcbd0, 22}, + {0xcbd1, 23}, + {0xcbd2, 24}, + {0xcbd3, 25}, + {0xcbd4, 2851}, + {0xcbd6, 0}, + {0xcbd7, 1}, + {0xcbd8, 2}, + {0xcbd9, 3}, + {0xcbda, 4}, + {0xcbdb, 5}, + {0xcbdc, 6}, + {0xcbdd, 7}, + {0xcbde, 8}, + {0xcbdf, 9}, + {0xcbe0, 10}, + {0xcbe1, 11}, + {0xcbe2, 12}, + {0xcbe3, 13}, + {0xcbe4, 2852}, + {0xcbe6, 0}, + {0xcbe7, 2853}, + {0xcbe9, 2854}, + {0xcbeb, 0}, + {0xcbec, 1}, + {0xcbed, 2}, + {0xcbee, 3}, + {0xcbef, 4}, + {0xcbf0, 5}, + {0xcbf1, 6}, + {0xcbf2, 7}, + {0xcbf3, 8}, + {0xcbf4, 9}, + {0xcbf5, 10}, + {0xcbf6, 11}, + {0xcbf7, 12}, + {0xcbf8, 13}, + {0xcbf9, 14}, + {0xcbfa, 15}, + {0xcbfb, 16}, + {0xcbfc, 17}, + {0xcbfd, 18}, + {0xcbfe, 19}, + {0xcbff, 20}, + {0xcc01, 0}, + {0xcc02, 1}, + {0xcc03, 2}, + {0xcc04, 3}, + {0xcc05, 4}, + {0xcc06, 5}, + {0xcc07, 6}, + {0xcc08, 7}, + {0xcc09, 8}, + {0xcc0a, 9}, + {0xcc0b, 10}, + {0xcc0c, 2855}, + {0xcc0d, 2856}, + {0xcc0f, 0}, + {0xcc10, 2857}, + {0xcc12, 0}, + {0xcc13, 1}, + {0xcc14, 2858}, + {0xcc16, 0}, + {0xcc17, 1}, + {0xcc18, 2}, + {0xcc19, 3}, + {0xcc1a, 4}, + {0xcc1b, 5}, + {0xcc1c, 2859}, + {0xcc1d, 2860}, + {0xcc1f, 0}, + {0xcc20, 1}, + {0xcc21, 2861}, + {0xcc22, 2862}, + {0xcc24, 0}, + {0xcc25, 1}, + {0xcc26, 2}, + {0xcc27, 2863}, + {0xcc28, 2864}, + {0xcc29, 2865}, + {0xcc2b, 0}, + {0xcc2c, 2866}, + {0xcc2e, 2867}, + {0xcc30, 2868}, + {0xcc32, 0}, + {0xcc33, 1}, + {0xcc34, 2}, + {0xcc35, 3}, + {0xcc36, 4}, + {0xcc37, 5}, + {0xcc38, 2869}, + {0xcc39, 2870}, + {0xcc3b, 2871}, + {0xcc3c, 2872}, + {0xcc3d, 2873}, + {0xcc3e, 2874}, + {0xcc40, 0}, + {0xcc41, 1}, + {0xcc42, 2}, + {0xcc43, 3}, + {0xcc44, 2875}, + {0xcc45, 2876}, + {0xcc47, 0}, + {0xcc48, 2877}, + {0xcc4a, 0}, + {0xcc4b, 1}, + {0xcc4c, 2878}, + {0xcc4e, 0}, + {0xcc4f, 1}, + {0xcc50, 2}, + {0xcc51, 3}, + {0xcc52, 4}, + {0xcc53, 5}, + {0xcc54, 2879}, + {0xcc55, 2880}, + {0xcc57, 2881}, + {0xcc58, 2882}, + {0xcc59, 2883}, + {0xcc5b, 0}, + {0xcc5c, 1}, + {0xcc5d, 2}, + {0xcc5e, 3}, + {0xcc5f, 4}, + {0xcc60, 2884}, + {0xcc62, 0}, + {0xcc63, 1}, + {0xcc64, 2885}, + {0xcc66, 2886}, + {0xcc68, 2887}, + {0xcc6a, 0}, + {0xcc6b, 1}, + {0xcc6c, 2}, + {0xcc6d, 3}, + {0xcc6e, 4}, + {0xcc6f, 5}, + {0xcc70, 2888}, + {0xcc72, 0}, + {0xcc73, 1}, + {0xcc74, 2}, + {0xcc75, 2889}, + {0xcc77, 0}, + {0xcc78, 1}, + {0xcc79, 2}, + {0xcc7a, 3}, + {0xcc7b, 4}, + {0xcc7c, 5}, + {0xcc7d, 6}, + {0xcc7e, 7}, + {0xcc7f, 8}, + {0xcc80, 9}, + {0xcc81, 10}, + {0xcc82, 11}, + {0xcc83, 12}, + {0xcc84, 13}, + {0xcc85, 14}, + {0xcc86, 15}, + {0xcc87, 16}, + {0xcc88, 17}, + {0xcc89, 18}, + {0xcc8a, 19}, + {0xcc8b, 20}, + {0xcc8c, 21}, + {0xcc8d, 22}, + {0xcc8e, 23}, + {0xcc8f, 24}, + {0xcc90, 25}, + {0xcc91, 26}, + {0xcc92, 27}, + {0xcc93, 28}, + {0xcc94, 29}, + {0xcc95, 30}, + {0xcc96, 31}, + {0xcc97, 32}, + {0xcc98, 2890}, + {0xcc99, 2891}, + {0xcc9b, 0}, + {0xcc9c, 2892}, + {0xcc9e, 0}, + {0xcc9f, 1}, + {0xcca0, 2893}, + {0xcca2, 0}, + {0xcca3, 1}, + {0xcca4, 2}, + {0xcca5, 3}, + {0xcca6, 4}, + {0xcca7, 5}, + {0xcca8, 2894}, + {0xcca9, 2895}, + {0xccab, 2896}, + {0xccac, 2897}, + {0xccad, 2898}, + {0xccaf, 0}, + {0xccb0, 1}, + {0xccb1, 2}, + {0xccb2, 3}, + {0xccb3, 4}, + {0xccb4, 2899}, + {0xccb5, 2900}, + {0xccb7, 0}, + {0xccb8, 2901}, + {0xccba, 0}, + {0xccbb, 1}, + {0xccbc, 2902}, + {0xccbe, 0}, + {0xccbf, 1}, + {0xccc0, 2}, + {0xccc1, 3}, + {0xccc2, 4}, + {0xccc3, 5}, + {0xccc4, 2903}, + {0xccc5, 2904}, + {0xccc7, 2905}, + {0xccc9, 2906}, + {0xcccb, 0}, + {0xcccc, 1}, + {0xcccd, 2}, + {0xccce, 3}, + {0xcccf, 4}, + {0xccd0, 2907}, + {0xccd2, 0}, + {0xccd3, 1}, + {0xccd4, 2908}, + {0xccd6, 0}, + {0xccd7, 1}, + {0xccd8, 2}, + {0xccd9, 3}, + {0xccda, 4}, + {0xccdb, 5}, + {0xccdc, 6}, + {0xccdd, 7}, + {0xccde, 8}, + {0xccdf, 9}, + {0xcce0, 10}, + {0xcce1, 11}, + {0xcce2, 12}, + {0xcce3, 13}, + {0xcce4, 2909}, + {0xcce6, 0}, + {0xcce7, 1}, + {0xcce8, 2}, + {0xcce9, 3}, + {0xccea, 4}, + {0xcceb, 5}, + {0xccec, 2910}, + {0xccee, 0}, + {0xccef, 1}, + {0xccf0, 2911}, + {0xccf2, 0}, + {0xccf3, 1}, + {0xccf4, 2}, + {0xccf5, 3}, + {0xccf6, 4}, + {0xccf7, 5}, + {0xccf8, 6}, + {0xccf9, 7}, + {0xccfa, 8}, + {0xccfb, 9}, + {0xccfc, 10}, + {0xccfd, 11}, + {0xccfe, 12}, + {0xccff, 13}, + {0xcd01, 2912}, + {0xcd03, 0}, + {0xcd04, 1}, + {0xcd05, 2}, + {0xcd06, 3}, + {0xcd07, 4}, + {0xcd08, 2913}, + {0xcd09, 2914}, + {0xcd0b, 0}, + {0xcd0c, 2915}, + {0xcd0e, 0}, + {0xcd0f, 1}, + {0xcd10, 2916}, + {0xcd12, 0}, + {0xcd13, 1}, + {0xcd14, 2}, + {0xcd15, 3}, + {0xcd16, 4}, + {0xcd17, 5}, + {0xcd18, 2917}, + {0xcd19, 2918}, + {0xcd1b, 2919}, + {0xcd1d, 2920}, + {0xcd1f, 0}, + {0xcd20, 1}, + {0xcd21, 2}, + {0xcd22, 3}, + {0xcd23, 4}, + {0xcd24, 2921}, + {0xcd26, 0}, + {0xcd27, 1}, + {0xcd28, 2922}, + {0xcd2a, 0}, + {0xcd2b, 1}, + {0xcd2c, 2923}, + {0xcd2e, 0}, + {0xcd2f, 1}, + {0xcd30, 2}, + {0xcd31, 3}, + {0xcd32, 4}, + {0xcd33, 5}, + {0xcd34, 6}, + {0xcd35, 7}, + {0xcd36, 8}, + {0xcd37, 9}, + {0xcd38, 10}, + {0xcd39, 2924}, + {0xcd3b, 0}, + {0xcd3c, 1}, + {0xcd3d, 2}, + {0xcd3e, 3}, + {0xcd3f, 4}, + {0xcd40, 5}, + {0xcd41, 6}, + {0xcd42, 7}, + {0xcd43, 8}, + {0xcd44, 9}, + {0xcd45, 10}, + {0xcd46, 11}, + {0xcd47, 12}, + {0xcd48, 13}, + {0xcd49, 14}, + {0xcd4a, 15}, + {0xcd4b, 16}, + {0xcd4c, 17}, + {0xcd4d, 18}, + {0xcd4e, 19}, + {0xcd4f, 20}, + {0xcd50, 21}, + {0xcd51, 22}, + {0xcd52, 23}, + {0xcd53, 24}, + {0xcd54, 25}, + {0xcd55, 26}, + {0xcd56, 27}, + {0xcd57, 28}, + {0xcd58, 29}, + {0xcd59, 30}, + {0xcd5a, 31}, + {0xcd5b, 32}, + {0xcd5c, 2925}, + {0xcd5e, 0}, + {0xcd5f, 1}, + {0xcd60, 2926}, + {0xcd62, 0}, + {0xcd63, 1}, + {0xcd64, 2927}, + {0xcd66, 0}, + {0xcd67, 1}, + {0xcd68, 2}, + {0xcd69, 3}, + {0xcd6a, 4}, + {0xcd6b, 5}, + {0xcd6c, 2928}, + {0xcd6d, 2929}, + {0xcd6f, 2930}, + {0xcd71, 2931}, + {0xcd73, 0}, + {0xcd74, 1}, + {0xcd75, 2}, + {0xcd76, 3}, + {0xcd77, 4}, + {0xcd78, 2932}, + {0xcd7a, 0}, + {0xcd7b, 1}, + {0xcd7c, 2}, + {0xcd7d, 3}, + {0xcd7e, 4}, + {0xcd7f, 5}, + {0xcd80, 6}, + {0xcd81, 7}, + {0xcd82, 8}, + {0xcd83, 9}, + {0xcd84, 10}, + {0xcd85, 11}, + {0xcd86, 12}, + {0xcd87, 13}, + {0xcd88, 2933}, + {0xcd8a, 0}, + {0xcd8b, 1}, + {0xcd8c, 2}, + {0xcd8d, 3}, + {0xcd8e, 4}, + {0xcd8f, 5}, + {0xcd90, 6}, + {0xcd91, 7}, + {0xcd92, 8}, + {0xcd93, 9}, + {0xcd94, 2934}, + {0xcd95, 2935}, + {0xcd97, 0}, + {0xcd98, 2936}, + {0xcd9a, 0}, + {0xcd9b, 1}, + {0xcd9c, 2937}, + {0xcd9e, 0}, + {0xcd9f, 1}, + {0xcda0, 2}, + {0xcda1, 3}, + {0xcda2, 4}, + {0xcda3, 5}, + {0xcda4, 2938}, + {0xcda5, 2939}, + {0xcda7, 2940}, + {0xcda9, 2941}, + {0xcdab, 0}, + {0xcdac, 1}, + {0xcdad, 2}, + {0xcdae, 3}, + {0xcdaf, 4}, + {0xcdb0, 2942}, + {0xcdb2, 0}, + {0xcdb3, 1}, + {0xcdb4, 2}, + {0xcdb5, 3}, + {0xcdb6, 4}, + {0xcdb7, 5}, + {0xcdb8, 6}, + {0xcdb9, 7}, + {0xcdba, 8}, + {0xcdbb, 9}, + {0xcdbc, 10}, + {0xcdbd, 11}, + {0xcdbe, 12}, + {0xcdbf, 13}, + {0xcdc0, 14}, + {0xcdc1, 15}, + {0xcdc2, 16}, + {0xcdc3, 17}, + {0xcdc4, 2943}, + {0xcdc6, 0}, + {0xcdc7, 1}, + {0xcdc8, 2}, + {0xcdc9, 3}, + {0xcdca, 4}, + {0xcdcb, 5}, + {0xcdcc, 2944}, + {0xcdce, 0}, + {0xcdcf, 1}, + {0xcdd0, 2945}, + {0xcdd2, 0}, + {0xcdd3, 1}, + {0xcdd4, 2}, + {0xcdd5, 3}, + {0xcdd6, 4}, + {0xcdd7, 5}, + {0xcdd8, 6}, + {0xcdd9, 7}, + {0xcdda, 8}, + {0xcddb, 9}, + {0xcddc, 10}, + {0xcddd, 11}, + {0xcdde, 12}, + {0xcddf, 13}, + {0xcde0, 14}, + {0xcde1, 15}, + {0xcde2, 16}, + {0xcde3, 17}, + {0xcde4, 18}, + {0xcde5, 19}, + {0xcde6, 20}, + {0xcde7, 21}, + {0xcde8, 2946}, + {0xcdea, 0}, + {0xcdeb, 1}, + {0xcdec, 2947}, + {0xcdee, 0}, + {0xcdef, 1}, + {0xcdf0, 2948}, + {0xcdf2, 0}, + {0xcdf3, 1}, + {0xcdf4, 2}, + {0xcdf5, 3}, + {0xcdf6, 4}, + {0xcdf7, 5}, + {0xcdf8, 2949}, + {0xcdf9, 2950}, + {0xcdfb, 2951}, + {0xcdfd, 2952}, + {0xcdff, 0}, + {0xce01, 0}, + {0xce02, 1}, + {0xce03, 2}, + {0xce04, 2953}, + {0xce06, 0}, + {0xce07, 1}, + {0xce08, 2954}, + {0xce0a, 0}, + {0xce0b, 1}, + {0xce0c, 2955}, + {0xce0e, 0}, + {0xce0f, 1}, + {0xce10, 2}, + {0xce11, 3}, + {0xce12, 4}, + {0xce13, 5}, + {0xce14, 2956}, + {0xce16, 0}, + {0xce17, 1}, + {0xce18, 2}, + {0xce19, 2957}, + {0xce1b, 0}, + {0xce1c, 1}, + {0xce1d, 2}, + {0xce1e, 3}, + {0xce1f, 4}, + {0xce20, 2958}, + {0xce21, 2959}, + {0xce23, 0}, + {0xce24, 2960}, + {0xce26, 0}, + {0xce27, 1}, + {0xce28, 2961}, + {0xce2a, 0}, + {0xce2b, 1}, + {0xce2c, 2}, + {0xce2d, 3}, + {0xce2e, 4}, + {0xce2f, 5}, + {0xce30, 2962}, + {0xce31, 2963}, + {0xce33, 2964}, + {0xce35, 2965}, + {0xce37, 0}, + {0xce38, 1}, + {0xce39, 2}, + {0xce3a, 3}, + {0xce3b, 4}, + {0xce3c, 5}, + {0xce3d, 6}, + {0xce3e, 7}, + {0xce3f, 8}, + {0xce40, 9}, + {0xce41, 10}, + {0xce42, 11}, + {0xce43, 12}, + {0xce44, 13}, + {0xce45, 14}, + {0xce46, 15}, + {0xce47, 16}, + {0xce48, 17}, + {0xce49, 18}, + {0xce4a, 19}, + {0xce4b, 20}, + {0xce4c, 21}, + {0xce4d, 22}, + {0xce4e, 23}, + {0xce4f, 24}, + {0xce50, 25}, + {0xce51, 26}, + {0xce52, 27}, + {0xce53, 28}, + {0xce54, 29}, + {0xce55, 30}, + {0xce56, 31}, + {0xce57, 32}, + {0xce58, 2966}, + {0xce59, 2967}, + {0xce5b, 0}, + {0xce5c, 2968}, + {0xce5e, 0}, + {0xce5f, 2969}, + {0xce60, 2970}, + {0xce61, 2971}, + {0xce63, 0}, + {0xce64, 1}, + {0xce65, 2}, + {0xce66, 3}, + {0xce67, 4}, + {0xce68, 2972}, + {0xce69, 2973}, + {0xce6b, 2974}, + {0xce6d, 2975}, + {0xce6f, 0}, + {0xce70, 1}, + {0xce71, 2}, + {0xce72, 3}, + {0xce73, 4}, + {0xce74, 2976}, + {0xce75, 2977}, + {0xce77, 0}, + {0xce78, 2978}, + {0xce7a, 0}, + {0xce7b, 1}, + {0xce7c, 2979}, + {0xce7e, 0}, + {0xce7f, 1}, + {0xce80, 2}, + {0xce81, 3}, + {0xce82, 4}, + {0xce83, 5}, + {0xce84, 2980}, + {0xce85, 2981}, + {0xce87, 2982}, + {0xce89, 2983}, + {0xce8b, 0}, + {0xce8c, 1}, + {0xce8d, 2}, + {0xce8e, 3}, + {0xce8f, 4}, + {0xce90, 2984}, + {0xce91, 2985}, + {0xce93, 0}, + {0xce94, 2986}, + {0xce96, 0}, + {0xce97, 1}, + {0xce98, 2987}, + {0xce9a, 0}, + {0xce9b, 1}, + {0xce9c, 2}, + {0xce9d, 3}, + {0xce9e, 4}, + {0xce9f, 5}, + {0xcea0, 2988}, + {0xcea1, 2989}, + {0xcea3, 2990}, + {0xcea4, 2991}, + {0xcea5, 2992}, + {0xcea7, 0}, + {0xcea8, 1}, + {0xcea9, 2}, + {0xceaa, 3}, + {0xceab, 4}, + {0xceac, 2993}, + {0xcead, 2994}, + {0xceaf, 0}, + {0xceb0, 1}, + {0xceb1, 2}, + {0xceb2, 3}, + {0xceb3, 4}, + {0xceb4, 5}, + {0xceb5, 6}, + {0xceb6, 7}, + {0xceb7, 8}, + {0xceb8, 9}, + {0xceb9, 10}, + {0xceba, 11}, + {0xcebb, 12}, + {0xcebc, 13}, + {0xcebd, 14}, + {0xcebe, 15}, + {0xcebf, 16}, + {0xcec0, 17}, + {0xcec1, 2995}, + {0xcec3, 0}, + {0xcec4, 1}, + {0xcec5, 2}, + {0xcec6, 3}, + {0xcec7, 4}, + {0xcec8, 5}, + {0xcec9, 6}, + {0xceca, 7}, + {0xcecb, 8}, + {0xcecc, 9}, + {0xcecd, 10}, + {0xcece, 11}, + {0xcecf, 12}, + {0xced0, 13}, + {0xced1, 14}, + {0xced2, 15}, + {0xced3, 16}, + {0xced4, 17}, + {0xced5, 18}, + {0xced6, 19}, + {0xced7, 20}, + {0xced8, 21}, + {0xced9, 22}, + {0xceda, 23}, + {0xcedb, 24}, + {0xcedc, 25}, + {0xcedd, 26}, + {0xcede, 27}, + {0xcedf, 28}, + {0xcee0, 29}, + {0xcee1, 30}, + {0xcee2, 31}, + {0xcee3, 32}, + {0xcee4, 2996}, + {0xcee5, 2997}, + {0xcee7, 0}, + {0xcee8, 2998}, + {0xceea, 0}, + {0xceeb, 2999}, + {0xceec, 3000}, + {0xceee, 0}, + {0xceef, 1}, + {0xcef0, 2}, + {0xcef1, 3}, + {0xcef2, 4}, + {0xcef3, 5}, + {0xcef4, 3001}, + {0xcef5, 3002}, + {0xcef7, 3003}, + {0xcef8, 3004}, + {0xcef9, 3005}, + {0xcefb, 0}, + {0xcefc, 1}, + {0xcefd, 2}, + {0xcefe, 3}, + {0xceff, 4}, + {0xcf00, 3006}, + {0xcf01, 3007}, + {0xcf03, 0}, + {0xcf04, 3008}, + {0xcf06, 0}, + {0xcf07, 1}, + {0xcf08, 3009}, + {0xcf0a, 0}, + {0xcf0b, 1}, + {0xcf0c, 2}, + {0xcf0d, 3}, + {0xcf0e, 4}, + {0xcf0f, 5}, + {0xcf10, 3010}, + {0xcf11, 3011}, + {0xcf13, 3012}, + {0xcf15, 3013}, + {0xcf17, 0}, + {0xcf18, 1}, + {0xcf19, 2}, + {0xcf1a, 3}, + {0xcf1b, 4}, + {0xcf1c, 3014}, + {0xcf1e, 0}, + {0xcf1f, 1}, + {0xcf20, 3015}, + {0xcf22, 0}, + {0xcf23, 1}, + {0xcf24, 3016}, + {0xcf26, 0}, + {0xcf27, 1}, + {0xcf28, 2}, + {0xcf29, 3}, + {0xcf2a, 4}, + {0xcf2b, 5}, + {0xcf2c, 3017}, + {0xcf2d, 3018}, + {0xcf2f, 3019}, + {0xcf30, 3020}, + {0xcf31, 3021}, + {0xcf33, 0}, + {0xcf34, 1}, + {0xcf35, 2}, + {0xcf36, 3}, + {0xcf37, 4}, + {0xcf38, 3022}, + {0xcf3a, 0}, + {0xcf3b, 1}, + {0xcf3c, 2}, + {0xcf3d, 3}, + {0xcf3e, 4}, + {0xcf3f, 5}, + {0xcf40, 6}, + {0xcf41, 7}, + {0xcf42, 8}, + {0xcf43, 9}, + {0xcf44, 10}, + {0xcf45, 11}, + {0xcf46, 12}, + {0xcf47, 13}, + {0xcf48, 14}, + {0xcf49, 15}, + {0xcf4a, 16}, + {0xcf4b, 17}, + {0xcf4c, 18}, + {0xcf4d, 19}, + {0xcf4e, 20}, + {0xcf4f, 21}, + {0xcf50, 22}, + {0xcf51, 23}, + {0xcf52, 24}, + {0xcf53, 25}, + {0xcf54, 3023}, + {0xcf55, 3024}, + {0xcf57, 0}, + {0xcf58, 3025}, + {0xcf5a, 0}, + {0xcf5b, 1}, + {0xcf5c, 3026}, + {0xcf5e, 0}, + {0xcf5f, 1}, + {0xcf60, 2}, + {0xcf61, 3}, + {0xcf62, 4}, + {0xcf63, 5}, + {0xcf64, 3027}, + {0xcf65, 3028}, + {0xcf67, 3029}, + {0xcf69, 3030}, + {0xcf6b, 0}, + {0xcf6c, 1}, + {0xcf6d, 2}, + {0xcf6e, 3}, + {0xcf6f, 4}, + {0xcf70, 3031}, + {0xcf71, 3032}, + {0xcf73, 0}, + {0xcf74, 3033}, + {0xcf76, 0}, + {0xcf77, 1}, + {0xcf78, 3034}, + {0xcf7a, 0}, + {0xcf7b, 1}, + {0xcf7c, 2}, + {0xcf7d, 3}, + {0xcf7e, 4}, + {0xcf7f, 5}, + {0xcf80, 3035}, + {0xcf82, 0}, + {0xcf83, 1}, + {0xcf84, 2}, + {0xcf85, 3036}, + {0xcf87, 0}, + {0xcf88, 1}, + {0xcf89, 2}, + {0xcf8a, 3}, + {0xcf8b, 4}, + {0xcf8c, 3037}, + {0xcf8e, 0}, + {0xcf8f, 1}, + {0xcf90, 2}, + {0xcf91, 3}, + {0xcf92, 4}, + {0xcf93, 5}, + {0xcf94, 6}, + {0xcf95, 7}, + {0xcf96, 8}, + {0xcf97, 9}, + {0xcf98, 10}, + {0xcf99, 11}, + {0xcf9a, 12}, + {0xcf9b, 13}, + {0xcf9c, 14}, + {0xcf9d, 15}, + {0xcf9e, 16}, + {0xcf9f, 17}, + {0xcfa0, 18}, + {0xcfa1, 3038}, + {0xcfa3, 0}, + {0xcfa4, 1}, + {0xcfa5, 2}, + {0xcfa6, 3}, + {0xcfa7, 4}, + {0xcfa8, 3039}, + {0xcfaa, 0}, + {0xcfab, 1}, + {0xcfac, 2}, + {0xcfad, 3}, + {0xcfae, 4}, + {0xcfaf, 5}, + {0xcfb0, 3040}, + {0xcfb2, 0}, + {0xcfb3, 1}, + {0xcfb4, 2}, + {0xcfb5, 3}, + {0xcfb6, 4}, + {0xcfb7, 5}, + {0xcfb8, 6}, + {0xcfb9, 7}, + {0xcfba, 8}, + {0xcfbb, 9}, + {0xcfbc, 10}, + {0xcfbd, 11}, + {0xcfbe, 12}, + {0xcfbf, 13}, + {0xcfc0, 14}, + {0xcfc1, 15}, + {0xcfc2, 16}, + {0xcfc3, 17}, + {0xcfc4, 3041}, + {0xcfc6, 0}, + {0xcfc7, 1}, + {0xcfc8, 2}, + {0xcfc9, 3}, + {0xcfca, 4}, + {0xcfcb, 5}, + {0xcfcc, 6}, + {0xcfcd, 7}, + {0xcfce, 8}, + {0xcfcf, 9}, + {0xcfd0, 10}, + {0xcfd1, 11}, + {0xcfd2, 12}, + {0xcfd3, 13}, + {0xcfd4, 14}, + {0xcfd5, 15}, + {0xcfd6, 16}, + {0xcfd7, 17}, + {0xcfd8, 18}, + {0xcfd9, 19}, + {0xcfda, 20}, + {0xcfdb, 21}, + {0xcfdc, 22}, + {0xcfdd, 23}, + {0xcfde, 24}, + {0xcfdf, 25}, + {0xcfe0, 3042}, + {0xcfe1, 3043}, + {0xcfe3, 0}, + {0xcfe4, 3044}, + {0xcfe6, 0}, + {0xcfe7, 1}, + {0xcfe8, 3045}, + {0xcfea, 0}, + {0xcfeb, 1}, + {0xcfec, 2}, + {0xcfed, 3}, + {0xcfee, 4}, + {0xcfef, 5}, + {0xcff0, 3046}, + {0xcff1, 3047}, + {0xcff3, 3048}, + {0xcff5, 3049}, + {0xcff7, 0}, + {0xcff8, 1}, + {0xcff9, 2}, + {0xcffa, 3}, + {0xcffb, 4}, + {0xcffc, 3050}, + {0xcffe, 0}, + {0xcfff, 1}, + {0xd000, 3051}, + {0xd002, 0}, + {0xd003, 1}, + {0xd004, 3052}, + {0xd006, 0}, + {0xd007, 1}, + {0xd008, 2}, + {0xd009, 3}, + {0xd00a, 4}, + {0xd00b, 5}, + {0xd00c, 6}, + {0xd00d, 7}, + {0xd00e, 8}, + {0xd00f, 9}, + {0xd010, 10}, + {0xd011, 3053}, + {0xd013, 0}, + {0xd014, 1}, + {0xd015, 2}, + {0xd016, 3}, + {0xd017, 4}, + {0xd018, 3054}, + {0xd01a, 0}, + {0xd01b, 1}, + {0xd01c, 2}, + {0xd01d, 3}, + {0xd01e, 4}, + {0xd01f, 5}, + {0xd020, 6}, + {0xd021, 7}, + {0xd022, 8}, + {0xd023, 9}, + {0xd024, 10}, + {0xd025, 11}, + {0xd026, 12}, + {0xd027, 13}, + {0xd028, 14}, + {0xd029, 15}, + {0xd02a, 16}, + {0xd02b, 17}, + {0xd02c, 18}, + {0xd02d, 3055}, + {0xd02f, 0}, + {0xd030, 1}, + {0xd031, 2}, + {0xd032, 3}, + {0xd033, 4}, + {0xd034, 3056}, + {0xd035, 3057}, + {0xd037, 0}, + {0xd038, 3058}, + {0xd03a, 0}, + {0xd03b, 1}, + {0xd03c, 3059}, + {0xd03e, 0}, + {0xd03f, 1}, + {0xd040, 2}, + {0xd041, 3}, + {0xd042, 4}, + {0xd043, 5}, + {0xd044, 3060}, + {0xd045, 3061}, + {0xd047, 3062}, + {0xd049, 3063}, + {0xd04b, 0}, + {0xd04c, 1}, + {0xd04d, 2}, + {0xd04e, 3}, + {0xd04f, 4}, + {0xd050, 3064}, + {0xd052, 0}, + {0xd053, 1}, + {0xd054, 3065}, + {0xd056, 0}, + {0xd057, 1}, + {0xd058, 3066}, + {0xd05a, 0}, + {0xd05b, 1}, + {0xd05c, 2}, + {0xd05d, 3}, + {0xd05e, 4}, + {0xd05f, 5}, + {0xd060, 3067}, + {0xd062, 0}, + {0xd063, 1}, + {0xd064, 2}, + {0xd065, 3}, + {0xd066, 4}, + {0xd067, 5}, + {0xd068, 6}, + {0xd069, 7}, + {0xd06a, 8}, + {0xd06b, 9}, + {0xd06c, 3068}, + {0xd06d, 3069}, + {0xd06f, 0}, + {0xd070, 3070}, + {0xd072, 0}, + {0xd073, 1}, + {0xd074, 3071}, + {0xd076, 0}, + {0xd077, 1}, + {0xd078, 2}, + {0xd079, 3}, + {0xd07a, 4}, + {0xd07b, 5}, + {0xd07c, 3072}, + {0xd07d, 3073}, + {0xd07f, 0}, + {0xd080, 1}, + {0xd081, 3074}, + {0xd083, 0}, + {0xd084, 1}, + {0xd085, 2}, + {0xd086, 3}, + {0xd087, 4}, + {0xd088, 5}, + {0xd089, 6}, + {0xd08a, 7}, + {0xd08b, 8}, + {0xd08c, 9}, + {0xd08d, 10}, + {0xd08e, 11}, + {0xd08f, 12}, + {0xd090, 13}, + {0xd091, 14}, + {0xd092, 15}, + {0xd093, 16}, + {0xd094, 17}, + {0xd095, 18}, + {0xd096, 19}, + {0xd097, 20}, + {0xd098, 21}, + {0xd099, 22}, + {0xd09a, 23}, + {0xd09b, 24}, + {0xd09c, 25}, + {0xd09d, 26}, + {0xd09e, 27}, + {0xd09f, 28}, + {0xd0a0, 29}, + {0xd0a1, 30}, + {0xd0a2, 31}, + {0xd0a3, 32}, + {0xd0a4, 3075}, + {0xd0a5, 3076}, + {0xd0a7, 0}, + {0xd0a8, 3077}, + {0xd0aa, 0}, + {0xd0ab, 1}, + {0xd0ac, 3078}, + {0xd0ae, 0}, + {0xd0af, 1}, + {0xd0b0, 2}, + {0xd0b1, 3}, + {0xd0b2, 4}, + {0xd0b3, 5}, + {0xd0b4, 3079}, + {0xd0b5, 3080}, + {0xd0b7, 3081}, + {0xd0b9, 3082}, + {0xd0bb, 0}, + {0xd0bc, 1}, + {0xd0bd, 2}, + {0xd0be, 3}, + {0xd0bf, 4}, + {0xd0c0, 3083}, + {0xd0c1, 3084}, + {0xd0c3, 0}, + {0xd0c4, 3085}, + {0xd0c6, 0}, + {0xd0c7, 1}, + {0xd0c8, 3086}, + {0xd0c9, 3087}, + {0xd0cb, 0}, + {0xd0cc, 1}, + {0xd0cd, 2}, + {0xd0ce, 3}, + {0xd0cf, 4}, + {0xd0d0, 3088}, + {0xd0d1, 3089}, + {0xd0d3, 3090}, + {0xd0d4, 3091}, + {0xd0d5, 3092}, + {0xd0d7, 0}, + {0xd0d8, 1}, + {0xd0d9, 2}, + {0xd0da, 3}, + {0xd0db, 4}, + {0xd0dc, 3093}, + {0xd0dd, 3094}, + {0xd0df, 0}, + {0xd0e0, 3095}, + {0xd0e2, 0}, + {0xd0e3, 1}, + {0xd0e4, 3096}, + {0xd0e6, 0}, + {0xd0e7, 1}, + {0xd0e8, 2}, + {0xd0e9, 3}, + {0xd0ea, 4}, + {0xd0eb, 5}, + {0xd0ec, 3097}, + {0xd0ed, 3098}, + {0xd0ef, 3099}, + {0xd0f0, 3100}, + {0xd0f1, 3101}, + {0xd0f3, 0}, + {0xd0f4, 1}, + {0xd0f5, 2}, + {0xd0f6, 3}, + {0xd0f7, 4}, + {0xd0f8, 3102}, + {0xd0fa, 0}, + {0xd0fb, 1}, + {0xd0fc, 2}, + {0xd0fd, 3}, + {0xd0fe, 4}, + {0xd0ff, 5}, + {0xd101, 0}, + {0xd102, 1}, + {0xd103, 2}, + {0xd104, 3}, + {0xd105, 4}, + {0xd106, 5}, + {0xd107, 6}, + {0xd108, 7}, + {0xd109, 8}, + {0xd10a, 9}, + {0xd10b, 10}, + {0xd10c, 11}, + {0xd10d, 3103}, + {0xd10f, 0}, + {0xd110, 1}, + {0xd111, 2}, + {0xd112, 3}, + {0xd113, 4}, + {0xd114, 5}, + {0xd115, 6}, + {0xd116, 7}, + {0xd117, 8}, + {0xd118, 9}, + {0xd119, 10}, + {0xd11a, 11}, + {0xd11b, 12}, + {0xd11c, 13}, + {0xd11d, 14}, + {0xd11e, 15}, + {0xd11f, 16}, + {0xd120, 17}, + {0xd121, 18}, + {0xd122, 19}, + {0xd123, 20}, + {0xd124, 21}, + {0xd125, 22}, + {0xd126, 23}, + {0xd127, 24}, + {0xd128, 25}, + {0xd129, 26}, + {0xd12a, 27}, + {0xd12b, 28}, + {0xd12c, 29}, + {0xd12d, 30}, + {0xd12e, 31}, + {0xd12f, 32}, + {0xd130, 3104}, + {0xd131, 3105}, + {0xd133, 0}, + {0xd134, 3106}, + {0xd136, 0}, + {0xd137, 1}, + {0xd138, 3107}, + {0xd13a, 3108}, + {0xd13c, 0}, + {0xd13d, 1}, + {0xd13e, 2}, + {0xd13f, 3}, + {0xd140, 3109}, + {0xd141, 3110}, + {0xd143, 3111}, + {0xd144, 3112}, + {0xd145, 3113}, + {0xd147, 0}, + {0xd148, 1}, + {0xd149, 2}, + {0xd14a, 3}, + {0xd14b, 4}, + {0xd14c, 3114}, + {0xd14d, 3115}, + {0xd14f, 0}, + {0xd150, 3116}, + {0xd152, 0}, + {0xd153, 1}, + {0xd154, 3117}, + {0xd156, 0}, + {0xd157, 1}, + {0xd158, 2}, + {0xd159, 3}, + {0xd15a, 4}, + {0xd15b, 5}, + {0xd15c, 3118}, + {0xd15d, 3119}, + {0xd15f, 3120}, + {0xd161, 3121}, + {0xd163, 0}, + {0xd164, 1}, + {0xd165, 2}, + {0xd166, 3}, + {0xd167, 4}, + {0xd168, 3122}, + {0xd16a, 0}, + {0xd16b, 1}, + {0xd16c, 3123}, + {0xd16e, 0}, + {0xd16f, 1}, + {0xd170, 2}, + {0xd171, 3}, + {0xd172, 4}, + {0xd173, 5}, + {0xd174, 6}, + {0xd175, 7}, + {0xd176, 8}, + {0xd177, 9}, + {0xd178, 10}, + {0xd179, 11}, + {0xd17a, 12}, + {0xd17b, 13}, + {0xd17c, 3124}, + {0xd17e, 0}, + {0xd17f, 1}, + {0xd180, 2}, + {0xd181, 3}, + {0xd182, 4}, + {0xd183, 5}, + {0xd184, 3125}, + {0xd186, 0}, + {0xd187, 1}, + {0xd188, 3126}, + {0xd18a, 0}, + {0xd18b, 1}, + {0xd18c, 2}, + {0xd18d, 3}, + {0xd18e, 4}, + {0xd18f, 5}, + {0xd190, 6}, + {0xd191, 7}, + {0xd192, 8}, + {0xd193, 9}, + {0xd194, 10}, + {0xd195, 11}, + {0xd196, 12}, + {0xd197, 13}, + {0xd198, 14}, + {0xd199, 15}, + {0xd19a, 16}, + {0xd19b, 17}, + {0xd19c, 18}, + {0xd19d, 19}, + {0xd19e, 20}, + {0xd19f, 21}, + {0xd1a0, 3127}, + {0xd1a1, 3128}, + {0xd1a3, 0}, + {0xd1a4, 3129}, + {0xd1a6, 0}, + {0xd1a7, 1}, + {0xd1a8, 3130}, + {0xd1aa, 0}, + {0xd1ab, 1}, + {0xd1ac, 2}, + {0xd1ad, 3}, + {0xd1ae, 4}, + {0xd1af, 5}, + {0xd1b0, 3131}, + {0xd1b1, 3132}, + {0xd1b3, 3133}, + {0xd1b5, 3134}, + {0xd1b7, 0}, + {0xd1b8, 1}, + {0xd1b9, 2}, + {0xd1ba, 3135}, + {0xd1bc, 3136}, + {0xd1be, 0}, + {0xd1bf, 1}, + {0xd1c0, 3137}, + {0xd1c2, 0}, + {0xd1c3, 1}, + {0xd1c4, 2}, + {0xd1c5, 3}, + {0xd1c6, 4}, + {0xd1c7, 5}, + {0xd1c8, 6}, + {0xd1c9, 7}, + {0xd1ca, 8}, + {0xd1cb, 9}, + {0xd1cc, 10}, + {0xd1cd, 11}, + {0xd1ce, 12}, + {0xd1cf, 13}, + {0xd1d0, 14}, + {0xd1d1, 15}, + {0xd1d2, 16}, + {0xd1d3, 17}, + {0xd1d4, 18}, + {0xd1d5, 19}, + {0xd1d6, 20}, + {0xd1d7, 21}, + {0xd1d8, 3138}, + {0xd1da, 0}, + {0xd1db, 1}, + {0xd1dc, 2}, + {0xd1dd, 3}, + {0xd1de, 4}, + {0xd1df, 5}, + {0xd1e0, 6}, + {0xd1e1, 7}, + {0xd1e2, 8}, + {0xd1e3, 9}, + {0xd1e4, 10}, + {0xd1e5, 11}, + {0xd1e6, 12}, + {0xd1e7, 13}, + {0xd1e8, 14}, + {0xd1e9, 15}, + {0xd1ea, 16}, + {0xd1eb, 17}, + {0xd1ec, 18}, + {0xd1ed, 19}, + {0xd1ee, 20}, + {0xd1ef, 21}, + {0xd1f0, 22}, + {0xd1f1, 23}, + {0xd1f2, 24}, + {0xd1f3, 25}, + {0xd1f4, 3139}, + {0xd1f6, 0}, + {0xd1f7, 1}, + {0xd1f8, 3140}, + {0xd1fa, 0}, + {0xd1fb, 1}, + {0xd1fc, 2}, + {0xd1fd, 3}, + {0xd1fe, 4}, + {0xd1ff, 5}, + {0xd201, 0}, + {0xd202, 1}, + {0xd203, 2}, + {0xd204, 3}, + {0xd205, 4}, + {0xd206, 5}, + {0xd207, 3141}, + {0xd209, 3142}, + {0xd20b, 0}, + {0xd20c, 1}, + {0xd20d, 2}, + {0xd20e, 3}, + {0xd20f, 4}, + {0xd210, 3143}, + {0xd212, 0}, + {0xd213, 1}, + {0xd214, 2}, + {0xd215, 3}, + {0xd216, 4}, + {0xd217, 5}, + {0xd218, 6}, + {0xd219, 7}, + {0xd21a, 8}, + {0xd21b, 9}, + {0xd21c, 10}, + {0xd21d, 11}, + {0xd21e, 12}, + {0xd21f, 13}, + {0xd220, 14}, + {0xd221, 15}, + {0xd222, 16}, + {0xd223, 17}, + {0xd224, 18}, + {0xd225, 19}, + {0xd226, 20}, + {0xd227, 21}, + {0xd228, 22}, + {0xd229, 23}, + {0xd22a, 24}, + {0xd22b, 25}, + {0xd22c, 3144}, + {0xd22d, 3145}, + {0xd22f, 0}, + {0xd230, 3146}, + {0xd232, 0}, + {0xd233, 1}, + {0xd234, 3147}, + {0xd236, 0}, + {0xd237, 1}, + {0xd238, 2}, + {0xd239, 3}, + {0xd23a, 4}, + {0xd23b, 5}, + {0xd23c, 3148}, + {0xd23d, 3149}, + {0xd23f, 3150}, + {0xd241, 3151}, + {0xd243, 0}, + {0xd244, 1}, + {0xd245, 2}, + {0xd246, 3}, + {0xd247, 4}, + {0xd248, 3152}, + {0xd24a, 0}, + {0xd24b, 1}, + {0xd24c, 2}, + {0xd24d, 3}, + {0xd24e, 4}, + {0xd24f, 5}, + {0xd250, 6}, + {0xd251, 7}, + {0xd252, 8}, + {0xd253, 9}, + {0xd254, 10}, + {0xd255, 11}, + {0xd256, 12}, + {0xd257, 13}, + {0xd258, 14}, + {0xd259, 15}, + {0xd25a, 16}, + {0xd25b, 17}, + {0xd25c, 3153}, + {0xd25e, 0}, + {0xd25f, 1}, + {0xd260, 2}, + {0xd261, 3}, + {0xd262, 4}, + {0xd263, 5}, + {0xd264, 3154}, + {0xd266, 0}, + {0xd267, 1}, + {0xd268, 2}, + {0xd269, 3}, + {0xd26a, 4}, + {0xd26b, 5}, + {0xd26c, 6}, + {0xd26d, 7}, + {0xd26e, 8}, + {0xd26f, 9}, + {0xd270, 10}, + {0xd271, 11}, + {0xd272, 12}, + {0xd273, 13}, + {0xd274, 14}, + {0xd275, 15}, + {0xd276, 16}, + {0xd277, 17}, + {0xd278, 18}, + {0xd279, 19}, + {0xd27a, 20}, + {0xd27b, 21}, + {0xd27c, 22}, + {0xd27d, 23}, + {0xd27e, 24}, + {0xd27f, 25}, + {0xd280, 3155}, + {0xd281, 3156}, + {0xd283, 0}, + {0xd284, 3157}, + {0xd286, 0}, + {0xd287, 1}, + {0xd288, 3158}, + {0xd28a, 0}, + {0xd28b, 1}, + {0xd28c, 2}, + {0xd28d, 3}, + {0xd28e, 4}, + {0xd28f, 5}, + {0xd290, 3159}, + {0xd291, 3160}, + {0xd293, 0}, + {0xd294, 1}, + {0xd295, 3161}, + {0xd297, 0}, + {0xd298, 1}, + {0xd299, 2}, + {0xd29a, 3}, + {0xd29b, 4}, + {0xd29c, 3162}, + {0xd29e, 0}, + {0xd29f, 1}, + {0xd2a0, 3163}, + {0xd2a2, 0}, + {0xd2a3, 1}, + {0xd2a4, 3164}, + {0xd2a6, 0}, + {0xd2a7, 1}, + {0xd2a8, 2}, + {0xd2a9, 3}, + {0xd2aa, 4}, + {0xd2ab, 5}, + {0xd2ac, 3165}, + {0xd2ae, 0}, + {0xd2af, 1}, + {0xd2b0, 2}, + {0xd2b1, 3166}, + {0xd2b3, 0}, + {0xd2b4, 1}, + {0xd2b5, 2}, + {0xd2b6, 3}, + {0xd2b7, 4}, + {0xd2b8, 3167}, + {0xd2b9, 3168}, + {0xd2bb, 0}, + {0xd2bc, 3169}, + {0xd2be, 0}, + {0xd2bf, 3170}, + {0xd2c0, 3171}, + {0xd2c2, 3172}, + {0xd2c4, 0}, + {0xd2c5, 1}, + {0xd2c6, 2}, + {0xd2c7, 3}, + {0xd2c8, 3173}, + {0xd2c9, 3174}, + {0xd2cb, 3175}, + {0xd2cd, 0}, + {0xd2ce, 1}, + {0xd2cf, 2}, + {0xd2d0, 3}, + {0xd2d1, 4}, + {0xd2d2, 5}, + {0xd2d3, 6}, + {0xd2d4, 3176}, + {0xd2d6, 0}, + {0xd2d7, 1}, + {0xd2d8, 3177}, + {0xd2da, 0}, + {0xd2db, 1}, + {0xd2dc, 3178}, + {0xd2de, 0}, + {0xd2df, 1}, + {0xd2e0, 2}, + {0xd2e1, 3}, + {0xd2e2, 4}, + {0xd2e3, 5}, + {0xd2e4, 3179}, + {0xd2e5, 3180}, + {0xd2e7, 0}, + {0xd2e8, 1}, + {0xd2e9, 2}, + {0xd2ea, 3}, + {0xd2eb, 4}, + {0xd2ec, 5}, + {0xd2ed, 6}, + {0xd2ee, 7}, + {0xd2ef, 8}, + {0xd2f0, 3181}, + {0xd2f1, 3182}, + {0xd2f3, 0}, + {0xd2f4, 3183}, + {0xd2f6, 0}, + {0xd2f7, 1}, + {0xd2f8, 3184}, + {0xd2fa, 0}, + {0xd2fb, 1}, + {0xd2fc, 2}, + {0xd2fd, 3}, + {0xd2fe, 4}, + {0xd2ff, 5}, + {0xd300, 3185}, + {0xd301, 3186}, + {0xd303, 3187}, + {0xd305, 3188}, + {0xd307, 0}, + {0xd308, 1}, + {0xd309, 2}, + {0xd30a, 3}, + {0xd30b, 4}, + {0xd30c, 3189}, + {0xd30d, 3190}, + {0xd30e, 3191}, + {0xd310, 3192}, + {0xd312, 0}, + {0xd313, 1}, + {0xd314, 3193}, + {0xd316, 3194}, + {0xd318, 0}, + {0xd319, 1}, + {0xd31a, 2}, + {0xd31b, 3}, + {0xd31c, 3195}, + {0xd31d, 3196}, + {0xd31f, 3197}, + {0xd320, 3198}, + {0xd321, 3199}, + {0xd323, 0}, + {0xd324, 1}, + {0xd325, 3200}, + {0xd327, 0}, + {0xd328, 3201}, + {0xd329, 3202}, + {0xd32b, 0}, + {0xd32c, 3203}, + {0xd32e, 0}, + {0xd32f, 1}, + {0xd330, 3204}, + {0xd332, 0}, + {0xd333, 1}, + {0xd334, 2}, + {0xd335, 3}, + {0xd336, 4}, + {0xd337, 5}, + {0xd338, 3205}, + {0xd339, 3206}, + {0xd33b, 3207}, + {0xd33c, 3208}, + {0xd33d, 3209}, + {0xd33f, 0}, + {0xd340, 1}, + {0xd341, 2}, + {0xd342, 3}, + {0xd343, 4}, + {0xd344, 3210}, + {0xd345, 3211}, + {0xd347, 0}, + {0xd348, 1}, + {0xd349, 2}, + {0xd34a, 3}, + {0xd34b, 4}, + {0xd34c, 5}, + {0xd34d, 6}, + {0xd34e, 7}, + {0xd34f, 8}, + {0xd350, 9}, + {0xd351, 10}, + {0xd352, 11}, + {0xd353, 12}, + {0xd354, 13}, + {0xd355, 14}, + {0xd356, 15}, + {0xd357, 16}, + {0xd358, 17}, + {0xd359, 18}, + {0xd35a, 19}, + {0xd35b, 20}, + {0xd35c, 21}, + {0xd35d, 22}, + {0xd35e, 23}, + {0xd35f, 24}, + {0xd360, 25}, + {0xd361, 26}, + {0xd362, 27}, + {0xd363, 28}, + {0xd364, 29}, + {0xd365, 30}, + {0xd366, 31}, + {0xd367, 32}, + {0xd368, 33}, + {0xd369, 34}, + {0xd36a, 35}, + {0xd36b, 36}, + {0xd36c, 37}, + {0xd36d, 38}, + {0xd36e, 39}, + {0xd36f, 40}, + {0xd370, 41}, + {0xd371, 42}, + {0xd372, 43}, + {0xd373, 44}, + {0xd374, 45}, + {0xd375, 46}, + {0xd376, 47}, + {0xd377, 48}, + {0xd378, 49}, + {0xd379, 50}, + {0xd37a, 51}, + {0xd37b, 52}, + {0xd37c, 3212}, + {0xd37d, 3213}, + {0xd37f, 0}, + {0xd380, 3214}, + {0xd382, 0}, + {0xd383, 1}, + {0xd384, 3215}, + {0xd386, 0}, + {0xd387, 1}, + {0xd388, 2}, + {0xd389, 3}, + {0xd38a, 4}, + {0xd38b, 5}, + {0xd38c, 3216}, + {0xd38d, 3217}, + {0xd38f, 3218}, + {0xd390, 3219}, + {0xd391, 3220}, + {0xd393, 0}, + {0xd394, 1}, + {0xd395, 2}, + {0xd396, 3}, + {0xd397, 4}, + {0xd398, 3221}, + {0xd399, 3222}, + {0xd39b, 0}, + {0xd39c, 3223}, + {0xd39e, 0}, + {0xd39f, 1}, + {0xd3a0, 3224}, + {0xd3a2, 0}, + {0xd3a3, 1}, + {0xd3a4, 2}, + {0xd3a5, 3}, + {0xd3a6, 4}, + {0xd3a7, 5}, + {0xd3a8, 3225}, + {0xd3a9, 3226}, + {0xd3ab, 3227}, + {0xd3ad, 3228}, + {0xd3af, 0}, + {0xd3b0, 1}, + {0xd3b1, 2}, + {0xd3b2, 3}, + {0xd3b3, 4}, + {0xd3b4, 3229}, + {0xd3b6, 0}, + {0xd3b7, 1}, + {0xd3b8, 3230}, + {0xd3ba, 0}, + {0xd3bb, 1}, + {0xd3bc, 3231}, + {0xd3be, 0}, + {0xd3bf, 1}, + {0xd3c0, 2}, + {0xd3c1, 3}, + {0xd3c2, 4}, + {0xd3c3, 5}, + {0xd3c4, 3232}, + {0xd3c5, 3233}, + {0xd3c7, 0}, + {0xd3c8, 3234}, + {0xd3c9, 3235}, + {0xd3cb, 0}, + {0xd3cc, 1}, + {0xd3cd, 2}, + {0xd3ce, 3}, + {0xd3cf, 4}, + {0xd3d0, 3236}, + {0xd3d2, 0}, + {0xd3d3, 1}, + {0xd3d4, 2}, + {0xd3d5, 3}, + {0xd3d6, 4}, + {0xd3d7, 5}, + {0xd3d8, 3237}, + {0xd3da, 0}, + {0xd3db, 1}, + {0xd3dc, 2}, + {0xd3dd, 3}, + {0xd3de, 4}, + {0xd3df, 5}, + {0xd3e0, 6}, + {0xd3e1, 3238}, + {0xd3e3, 3239}, + {0xd3e5, 0}, + {0xd3e6, 1}, + {0xd3e7, 2}, + {0xd3e8, 3}, + {0xd3e9, 4}, + {0xd3ea, 5}, + {0xd3eb, 6}, + {0xd3ec, 3240}, + {0xd3ed, 3241}, + {0xd3ef, 0}, + {0xd3f0, 3242}, + {0xd3f2, 0}, + {0xd3f3, 1}, + {0xd3f4, 3243}, + {0xd3f6, 0}, + {0xd3f7, 1}, + {0xd3f8, 2}, + {0xd3f9, 3}, + {0xd3fa, 4}, + {0xd3fb, 5}, + {0xd3fc, 3244}, + {0xd3fd, 3245}, + {0xd3ff, 3246}, + {0xd401, 3247}, + {0xd403, 0}, + {0xd404, 1}, + {0xd405, 2}, + {0xd406, 3}, + {0xd407, 4}, + {0xd408, 3248}, + {0xd40a, 0}, + {0xd40b, 1}, + {0xd40c, 2}, + {0xd40d, 3}, + {0xd40e, 4}, + {0xd40f, 5}, + {0xd410, 6}, + {0xd411, 7}, + {0xd412, 8}, + {0xd413, 9}, + {0xd414, 10}, + {0xd415, 11}, + {0xd416, 12}, + {0xd417, 13}, + {0xd418, 14}, + {0xd419, 15}, + {0xd41a, 16}, + {0xd41b, 17}, + {0xd41c, 18}, + {0xd41d, 3249}, + {0xd41f, 0}, + {0xd420, 1}, + {0xd421, 2}, + {0xd422, 3}, + {0xd423, 4}, + {0xd424, 5}, + {0xd425, 6}, + {0xd426, 7}, + {0xd427, 8}, + {0xd428, 9}, + {0xd429, 10}, + {0xd42a, 11}, + {0xd42b, 12}, + {0xd42c, 13}, + {0xd42d, 14}, + {0xd42e, 15}, + {0xd42f, 16}, + {0xd430, 17}, + {0xd431, 18}, + {0xd432, 19}, + {0xd433, 20}, + {0xd434, 21}, + {0xd435, 22}, + {0xd436, 23}, + {0xd437, 24}, + {0xd438, 25}, + {0xd439, 26}, + {0xd43a, 27}, + {0xd43b, 28}, + {0xd43c, 29}, + {0xd43d, 30}, + {0xd43e, 31}, + {0xd43f, 32}, + {0xd440, 3250}, + {0xd442, 0}, + {0xd443, 1}, + {0xd444, 3251}, + {0xd446, 0}, + {0xd447, 1}, + {0xd448, 2}, + {0xd449, 3}, + {0xd44a, 4}, + {0xd44b, 5}, + {0xd44c, 6}, + {0xd44d, 7}, + {0xd44e, 8}, + {0xd44f, 9}, + {0xd450, 10}, + {0xd451, 11}, + {0xd452, 12}, + {0xd453, 13}, + {0xd454, 14}, + {0xd455, 15}, + {0xd456, 16}, + {0xd457, 17}, + {0xd458, 18}, + {0xd459, 19}, + {0xd45a, 20}, + {0xd45b, 21}, + {0xd45c, 3252}, + {0xd45e, 0}, + {0xd45f, 1}, + {0xd460, 3253}, + {0xd462, 0}, + {0xd463, 1}, + {0xd464, 3254}, + {0xd466, 0}, + {0xd467, 1}, + {0xd468, 2}, + {0xd469, 3}, + {0xd46a, 4}, + {0xd46b, 5}, + {0xd46c, 6}, + {0xd46d, 3255}, + {0xd46f, 3256}, + {0xd471, 0}, + {0xd472, 1}, + {0xd473, 2}, + {0xd474, 3}, + {0xd475, 4}, + {0xd476, 5}, + {0xd477, 6}, + {0xd478, 3257}, + {0xd479, 3258}, + {0xd47b, 0}, + {0xd47c, 3259}, + {0xd47e, 0}, + {0xd47f, 3260}, + {0xd480, 3261}, + {0xd482, 3262}, + {0xd484, 0}, + {0xd485, 1}, + {0xd486, 2}, + {0xd487, 3}, + {0xd488, 3263}, + {0xd489, 3264}, + {0xd48b, 3265}, + {0xd48d, 3266}, + {0xd48f, 0}, + {0xd490, 1}, + {0xd491, 2}, + {0xd492, 3}, + {0xd493, 4}, + {0xd494, 3267}, + {0xd496, 0}, + {0xd497, 1}, + {0xd498, 2}, + {0xd499, 3}, + {0xd49a, 4}, + {0xd49b, 5}, + {0xd49c, 6}, + {0xd49d, 7}, + {0xd49e, 8}, + {0xd49f, 9}, + {0xd4a0, 10}, + {0xd4a1, 11}, + {0xd4a2, 12}, + {0xd4a3, 13}, + {0xd4a4, 14}, + {0xd4a5, 15}, + {0xd4a6, 16}, + {0xd4a7, 17}, + {0xd4a8, 18}, + {0xd4a9, 3268}, + {0xd4ab, 0}, + {0xd4ac, 1}, + {0xd4ad, 2}, + {0xd4ae, 3}, + {0xd4af, 4}, + {0xd4b0, 5}, + {0xd4b1, 6}, + {0xd4b2, 7}, + {0xd4b3, 8}, + {0xd4b4, 9}, + {0xd4b5, 10}, + {0xd4b6, 11}, + {0xd4b7, 12}, + {0xd4b8, 13}, + {0xd4b9, 14}, + {0xd4ba, 15}, + {0xd4bb, 16}, + {0xd4bc, 17}, + {0xd4bd, 18}, + {0xd4be, 19}, + {0xd4bf, 20}, + {0xd4c0, 21}, + {0xd4c1, 22}, + {0xd4c2, 23}, + {0xd4c3, 24}, + {0xd4c4, 25}, + {0xd4c5, 26}, + {0xd4c6, 27}, + {0xd4c7, 28}, + {0xd4c8, 29}, + {0xd4c9, 30}, + {0xd4ca, 31}, + {0xd4cb, 32}, + {0xd4cc, 3269}, + {0xd4ce, 0}, + {0xd4cf, 1}, + {0xd4d0, 3270}, + {0xd4d2, 0}, + {0xd4d3, 1}, + {0xd4d4, 3271}, + {0xd4d6, 0}, + {0xd4d7, 1}, + {0xd4d8, 2}, + {0xd4d9, 3}, + {0xd4da, 4}, + {0xd4db, 5}, + {0xd4dc, 3272}, + {0xd4de, 0}, + {0xd4df, 3273}, + {0xd4e1, 0}, + {0xd4e2, 1}, + {0xd4e3, 2}, + {0xd4e4, 3}, + {0xd4e5, 4}, + {0xd4e6, 5}, + {0xd4e7, 6}, + {0xd4e8, 3274}, + {0xd4ea, 0}, + {0xd4eb, 1}, + {0xd4ec, 3275}, + {0xd4ee, 0}, + {0xd4ef, 1}, + {0xd4f0, 3276}, + {0xd4f2, 0}, + {0xd4f3, 1}, + {0xd4f4, 2}, + {0xd4f5, 3}, + {0xd4f6, 4}, + {0xd4f7, 5}, + {0xd4f8, 3277}, + {0xd4fa, 0}, + {0xd4fb, 3278}, + {0xd4fd, 3279}, + {0xd4ff, 0}, + {0xd501, 0}, + {0xd502, 1}, + {0xd503, 2}, + {0xd504, 3280}, + {0xd506, 0}, + {0xd507, 1}, + {0xd508, 3281}, + {0xd50a, 0}, + {0xd50b, 1}, + {0xd50c, 3282}, + {0xd50e, 0}, + {0xd50f, 1}, + {0xd510, 2}, + {0xd511, 3}, + {0xd512, 4}, + {0xd513, 5}, + {0xd514, 3283}, + {0xd515, 3284}, + {0xd517, 3285}, + {0xd519, 0}, + {0xd51a, 1}, + {0xd51b, 2}, + {0xd51c, 3}, + {0xd51d, 4}, + {0xd51e, 5}, + {0xd51f, 6}, + {0xd520, 7}, + {0xd521, 8}, + {0xd522, 9}, + {0xd523, 10}, + {0xd524, 11}, + {0xd525, 12}, + {0xd526, 13}, + {0xd527, 14}, + {0xd528, 15}, + {0xd529, 16}, + {0xd52a, 17}, + {0xd52b, 18}, + {0xd52c, 19}, + {0xd52d, 20}, + {0xd52e, 21}, + {0xd52f, 22}, + {0xd530, 23}, + {0xd531, 24}, + {0xd532, 25}, + {0xd533, 26}, + {0xd534, 27}, + {0xd535, 28}, + {0xd536, 29}, + {0xd537, 30}, + {0xd538, 31}, + {0xd539, 32}, + {0xd53a, 33}, + {0xd53b, 34}, + {0xd53c, 3286}, + {0xd53d, 3287}, + {0xd53f, 0}, + {0xd540, 3288}, + {0xd542, 0}, + {0xd543, 1}, + {0xd544, 3289}, + {0xd546, 0}, + {0xd547, 1}, + {0xd548, 2}, + {0xd549, 3}, + {0xd54a, 4}, + {0xd54b, 5}, + {0xd54c, 3290}, + {0xd54d, 3291}, + {0xd54f, 3292}, + {0xd551, 3293}, + {0xd553, 0}, + {0xd554, 1}, + {0xd555, 2}, + {0xd556, 3}, + {0xd557, 4}, + {0xd558, 3294}, + {0xd559, 3295}, + {0xd55b, 0}, + {0xd55c, 3296}, + {0xd55e, 0}, + {0xd55f, 1}, + {0xd560, 3297}, + {0xd562, 0}, + {0xd563, 1}, + {0xd564, 2}, + {0xd565, 3298}, + {0xd567, 0}, + {0xd568, 3299}, + {0xd569, 3300}, + {0xd56b, 3301}, + {0xd56d, 3302}, + {0xd56f, 0}, + {0xd570, 1}, + {0xd571, 2}, + {0xd572, 3}, + {0xd573, 4}, + {0xd574, 3303}, + {0xd575, 3304}, + {0xd577, 0}, + {0xd578, 3305}, + {0xd57a, 0}, + {0xd57b, 1}, + {0xd57c, 3306}, + {0xd57e, 0}, + {0xd57f, 1}, + {0xd580, 2}, + {0xd581, 3}, + {0xd582, 4}, + {0xd583, 5}, + {0xd584, 3307}, + {0xd585, 3308}, + {0xd587, 3309}, + {0xd588, 3310}, + {0xd589, 3311}, + {0xd58b, 0}, + {0xd58c, 1}, + {0xd58d, 2}, + {0xd58e, 3}, + {0xd58f, 4}, + {0xd590, 3312}, + {0xd592, 0}, + {0xd593, 1}, + {0xd594, 2}, + {0xd595, 3}, + {0xd596, 4}, + {0xd597, 5}, + {0xd598, 6}, + {0xd599, 7}, + {0xd59a, 8}, + {0xd59b, 9}, + {0xd59c, 10}, + {0xd59d, 11}, + {0xd59e, 12}, + {0xd59f, 13}, + {0xd5a0, 14}, + {0xd5a1, 15}, + {0xd5a2, 16}, + {0xd5a3, 17}, + {0xd5a4, 18}, + {0xd5a5, 3313}, + {0xd5a7, 0}, + {0xd5a8, 1}, + {0xd5a9, 2}, + {0xd5aa, 3}, + {0xd5ab, 4}, + {0xd5ac, 5}, + {0xd5ad, 6}, + {0xd5ae, 7}, + {0xd5af, 8}, + {0xd5b0, 9}, + {0xd5b1, 10}, + {0xd5b2, 11}, + {0xd5b3, 12}, + {0xd5b4, 13}, + {0xd5b5, 14}, + {0xd5b6, 15}, + {0xd5b7, 16}, + {0xd5b8, 17}, + {0xd5b9, 18}, + {0xd5ba, 19}, + {0xd5bb, 20}, + {0xd5bc, 21}, + {0xd5bd, 22}, + {0xd5be, 23}, + {0xd5bf, 24}, + {0xd5c0, 25}, + {0xd5c1, 26}, + {0xd5c2, 27}, + {0xd5c3, 28}, + {0xd5c4, 29}, + {0xd5c5, 30}, + {0xd5c6, 31}, + {0xd5c7, 32}, + {0xd5c8, 3314}, + {0xd5c9, 3315}, + {0xd5cb, 0}, + {0xd5cc, 3316}, + {0xd5ce, 0}, + {0xd5cf, 1}, + {0xd5d0, 3317}, + {0xd5d2, 3318}, + {0xd5d4, 0}, + {0xd5d5, 1}, + {0xd5d6, 2}, + {0xd5d7, 3}, + {0xd5d8, 3319}, + {0xd5d9, 3320}, + {0xd5db, 3321}, + {0xd5dd, 3322}, + {0xd5df, 0}, + {0xd5e0, 1}, + {0xd5e1, 2}, + {0xd5e2, 3}, + {0xd5e3, 4}, + {0xd5e4, 3323}, + {0xd5e5, 3324}, + {0xd5e7, 0}, + {0xd5e8, 3325}, + {0xd5ea, 0}, + {0xd5eb, 1}, + {0xd5ec, 3326}, + {0xd5ee, 0}, + {0xd5ef, 1}, + {0xd5f0, 2}, + {0xd5f1, 3}, + {0xd5f2, 4}, + {0xd5f3, 5}, + {0xd5f4, 3327}, + {0xd5f5, 3328}, + {0xd5f7, 3329}, + {0xd5f9, 3330}, + {0xd5fb, 0}, + {0xd5fc, 1}, + {0xd5fd, 2}, + {0xd5fe, 3}, + {0xd5ff, 4}, + {0xd600, 3331}, + {0xd601, 3332}, + {0xd603, 0}, + {0xd604, 3333}, + {0xd606, 0}, + {0xd607, 1}, + {0xd608, 3334}, + {0xd60a, 0}, + {0xd60b, 1}, + {0xd60c, 2}, + {0xd60d, 3}, + {0xd60e, 4}, + {0xd60f, 5}, + {0xd610, 3335}, + {0xd611, 3336}, + {0xd613, 3337}, + {0xd614, 3338}, + {0xd615, 3339}, + {0xd617, 0}, + {0xd618, 1}, + {0xd619, 2}, + {0xd61a, 3}, + {0xd61b, 4}, + {0xd61c, 3340}, + {0xd61e, 0}, + {0xd61f, 1}, + {0xd620, 3341}, + {0xd622, 0}, + {0xd623, 1}, + {0xd624, 3342}, + {0xd626, 0}, + {0xd627, 1}, + {0xd628, 2}, + {0xd629, 3}, + {0xd62a, 4}, + {0xd62b, 5}, + {0xd62c, 6}, + {0xd62d, 3343}, + {0xd62f, 0}, + {0xd630, 1}, + {0xd631, 2}, + {0xd632, 3}, + {0xd633, 4}, + {0xd634, 5}, + {0xd635, 6}, + {0xd636, 7}, + {0xd637, 8}, + {0xd638, 3344}, + {0xd639, 3345}, + {0xd63b, 0}, + {0xd63c, 3346}, + {0xd63e, 0}, + {0xd63f, 1}, + {0xd640, 3347}, + {0xd642, 0}, + {0xd643, 1}, + {0xd644, 2}, + {0xd645, 3348}, + {0xd647, 0}, + {0xd648, 3349}, + {0xd649, 3350}, + {0xd64b, 3351}, + {0xd64d, 3352}, + {0xd64f, 0}, + {0xd650, 1}, + {0xd651, 3353}, + {0xd653, 0}, + {0xd654, 3354}, + {0xd655, 3355}, + {0xd657, 0}, + {0xd658, 3356}, + {0xd65a, 0}, + {0xd65b, 1}, + {0xd65c, 3357}, + {0xd65e, 0}, + {0xd65f, 1}, + {0xd660, 2}, + {0xd661, 3}, + {0xd662, 4}, + {0xd663, 5}, + {0xd664, 6}, + {0xd665, 7}, + {0xd666, 8}, + {0xd667, 3358}, + {0xd669, 3359}, + {0xd66b, 0}, + {0xd66c, 1}, + {0xd66d, 2}, + {0xd66e, 3}, + {0xd66f, 4}, + {0xd670, 3360}, + {0xd671, 3361}, + {0xd673, 0}, + {0xd674, 3362}, + {0xd676, 0}, + {0xd677, 1}, + {0xd678, 2}, + {0xd679, 3}, + {0xd67a, 4}, + {0xd67b, 5}, + {0xd67c, 6}, + {0xd67d, 7}, + {0xd67e, 8}, + {0xd67f, 9}, + {0xd680, 10}, + {0xd681, 11}, + {0xd682, 12}, + {0xd683, 3363}, + {0xd685, 3364}, + {0xd687, 0}, + {0xd688, 1}, + {0xd689, 2}, + {0xd68a, 3}, + {0xd68b, 4}, + {0xd68c, 3365}, + {0xd68d, 3366}, + {0xd68f, 0}, + {0xd690, 3367}, + {0xd692, 0}, + {0xd693, 1}, + {0xd694, 3368}, + {0xd696, 0}, + {0xd697, 1}, + {0xd698, 2}, + {0xd699, 3}, + {0xd69a, 4}, + {0xd69b, 5}, + {0xd69c, 6}, + {0xd69d, 3369}, + {0xd69f, 3370}, + {0xd6a1, 3371}, + {0xd6a3, 0}, + {0xd6a4, 1}, + {0xd6a5, 2}, + {0xd6a6, 3}, + {0xd6a7, 4}, + {0xd6a8, 3372}, + {0xd6aa, 0}, + {0xd6ab, 1}, + {0xd6ac, 3373}, + {0xd6ae, 0}, + {0xd6af, 1}, + {0xd6b0, 3374}, + {0xd6b2, 0}, + {0xd6b3, 1}, + {0xd6b4, 2}, + {0xd6b5, 3}, + {0xd6b6, 4}, + {0xd6b7, 5}, + {0xd6b8, 6}, + {0xd6b9, 3375}, + {0xd6bb, 3376}, + {0xd6bd, 0}, + {0xd6be, 1}, + {0xd6bf, 2}, + {0xd6c0, 3}, + {0xd6c1, 4}, + {0xd6c2, 5}, + {0xd6c3, 6}, + {0xd6c4, 3377}, + {0xd6c5, 3378}, + {0xd6c7, 0}, + {0xd6c8, 3379}, + {0xd6ca, 0}, + {0xd6cb, 1}, + {0xd6cc, 3380}, + {0xd6ce, 0}, + {0xd6cf, 1}, + {0xd6d0, 2}, + {0xd6d1, 3381}, + {0xd6d3, 0}, + {0xd6d4, 3382}, + {0xd6d6, 0}, + {0xd6d7, 3383}, + {0xd6d9, 3384}, + {0xd6db, 0}, + {0xd6dc, 1}, + {0xd6dd, 2}, + {0xd6de, 3}, + {0xd6df, 4}, + {0xd6e0, 3385}, + {0xd6e2, 0}, + {0xd6e3, 1}, + {0xd6e4, 3386}, + {0xd6e6, 0}, + {0xd6e7, 1}, + {0xd6e8, 3387}, + {0xd6ea, 0}, + {0xd6eb, 1}, + {0xd6ec, 2}, + {0xd6ed, 3}, + {0xd6ee, 4}, + {0xd6ef, 5}, + {0xd6f0, 3388}, + {0xd6f2, 0}, + {0xd6f3, 1}, + {0xd6f4, 2}, + {0xd6f5, 3389}, + {0xd6f7, 0}, + {0xd6f8, 1}, + {0xd6f9, 2}, + {0xd6fa, 3}, + {0xd6fb, 4}, + {0xd6fc, 3390}, + {0xd6fd, 3391}, + {0xd6ff, 0}, + {0xd700, 3392}, + {0xd702, 0}, + {0xd703, 1}, + {0xd704, 3393}, + {0xd706, 0}, + {0xd707, 1}, + {0xd708, 2}, + {0xd709, 3}, + {0xd70a, 4}, + {0xd70b, 5}, + {0xd70c, 6}, + {0xd70d, 7}, + {0xd70e, 8}, + {0xd70f, 9}, + {0xd710, 10}, + {0xd711, 3394}, + {0xd713, 0}, + {0xd714, 1}, + {0xd715, 2}, + {0xd716, 3}, + {0xd717, 4}, + {0xd718, 3395}, + {0xd719, 3396}, + {0xd71b, 0}, + {0xd71c, 3397}, + {0xd71e, 0}, + {0xd71f, 1}, + {0xd720, 3398}, + {0xd722, 0}, + {0xd723, 1}, + {0xd724, 2}, + {0xd725, 3}, + {0xd726, 4}, + {0xd727, 5}, + {0xd728, 3399}, + {0xd729, 3400}, + {0xd72b, 3401}, + {0xd72d, 3402}, + {0xd72f, 0}, + {0xd730, 1}, + {0xd731, 2}, + {0xd732, 3}, + {0xd733, 4}, + {0xd734, 3403}, + {0xd735, 3404}, + {0xd737, 0}, + {0xd738, 3405}, + {0xd73a, 0}, + {0xd73b, 1}, + {0xd73c, 3406}, + {0xd73e, 0}, + {0xd73f, 1}, + {0xd740, 2}, + {0xd741, 3}, + {0xd742, 4}, + {0xd743, 5}, + {0xd744, 3407}, + {0xd746, 0}, + {0xd747, 3408}, + {0xd749, 3409}, + {0xd74b, 0}, + {0xd74c, 1}, + {0xd74d, 2}, + {0xd74e, 3}, + {0xd74f, 4}, + {0xd750, 3410}, + {0xd751, 3411}, + {0xd753, 0}, + {0xd754, 3412}, + {0xd756, 3413}, + {0xd757, 3414}, + {0xd758, 3415}, + {0xd759, 3416}, + {0xd75b, 0}, + {0xd75c, 1}, + {0xd75d, 2}, + {0xd75e, 3}, + {0xd75f, 4}, + {0xd760, 3417}, + {0xd761, 3418}, + {0xd763, 3419}, + {0xd765, 3420}, + {0xd767, 0}, + {0xd768, 1}, + {0xd769, 3421}, + {0xd76b, 0}, + {0xd76c, 3422}, + {0xd76e, 0}, + {0xd76f, 1}, + {0xd770, 3423}, + {0xd772, 0}, + {0xd773, 1}, + {0xd774, 3424}, + {0xd776, 0}, + {0xd777, 1}, + {0xd778, 2}, + {0xd779, 3}, + {0xd77a, 4}, + {0xd77b, 5}, + {0xd77c, 3425}, + {0xd77d, 3426}, + {0xd77f, 0}, + {0xd780, 1}, + {0xd781, 3427}, + {0xd783, 0}, + {0xd784, 1}, + {0xd785, 2}, + {0xd786, 3}, + {0xd787, 4}, + {0xd788, 3428}, + {0xd789, 3429}, + {0xd78b, 0}, + {0xd78c, 3430}, + {0xd78e, 0}, + {0xd78f, 1}, + {0xd790, 3431}, + {0xd792, 0}, + {0xd793, 1}, + {0xd794, 2}, + {0xd795, 3}, + {0xd796, 4}, + {0xd797, 5}, + {0xd798, 3432}, + {0xd799, 3433}, + {0xd79b, 3434}, + {0xd79d, 3435}, + {0xd79f, 0}, + {0xd7a0, 1}, + {0xd7a1, 2}, + {0xd7a2, 3}, + {0xd7a3, 4}, + {0xf900, 4116}, + {0xf901, 3678}, + {0xf902, 7053}, + {0xf903, 3460}, + {0xf904, 7900}, + {0xf905, 3802}, + {0xf906, 3902}, + {0xf907, 3946}, + {0xf908, 3946}, + {0xf909, 3708}, + {0xf90a, 4131}, + {0xf90b, 4374}, + {0xf90c, 4156}, + {0xf90d, 4375}, + {0xf90e, 4376}, + {0xf90f, 4377}, + {0xf910, 4378}, + {0xf911, 4379}, + {0xf912, 4380}, + {0xf913, 4381}, + {0xf914, 5800}, + {0xf915, 4382}, + {0xf916, 4383}, + {0xf917, 4384}, + {0xf918, 4386}, + {0xf919, 4387}, + {0xf91a, 4388}, + {0xf91b, 4389}, + {0xf91c, 4390}, + {0xf91d, 4391}, + {0xf91e, 4394}, + {0xf91f, 4395}, + {0xf920, 4396}, + {0xf921, 4399}, + {0xf922, 4403}, + {0xf923, 4406}, + {0xf924, 4407}, + {0xf925, 4409}, + {0xf926, 4410}, + {0xf927, 4411}, + {0xf928, 4412}, + {0xf929, 4413}, + {0xf92a, 4414}, + {0xf92b, 4415}, + {0xf92c, 4419}, + {0xf92d, 4420}, + {0xf92e, 4424}, + {0xf92f, 4511}, + {0xf930, 4513}, + {0xf931, 4514}, + {0xf932, 4517}, + {0xf933, 4518}, + {0xf934, 4519}, + {0xf935, 4520}, + {0xf936, 4521}, + {0xf937, 4522}, + {0xf938, 4524}, + {0xf939, 4525}, + {0xf93a, 4526}, + {0xf93b, 4528}, + {0xf93c, 4529}, + {0xf93d, 4530}, + {0xf93e, 4531}, + {0xf93f, 4532}, + {0xf940, 4533}, + {0xf941, 4535}, + {0xf942, 4536}, + {0xf943, 4537}, + {0xf944, 4541}, + {0xf945, 4542}, + {0xf946, 4545}, + {0xf947, 4546}, + {0xf948, 4547}, + {0xf949, 4550}, + {0xf94a, 4564}, + {0xf94b, 4566}, + {0xf94c, 4567}, + {0xf94d, 4568}, + {0xf94e, 4569}, + {0xf94f, 4571}, + {0xf950, 4572}, + {0xf951, 4576}, + {0xf952, 4604}, + {0xf953, 4605}, + {0xf954, 4606}, + {0xf955, 4607}, + {0xf956, 4609}, + {0xf957, 4610}, + {0xf958, 4611}, + {0xf959, 4612}, + {0xf95a, 4318}, + {0xf95b, 4136}, + {0xf95c, 5800}, + {0xf95d, 4139}, + {0xf95e, 4192}, + {0xf95f, 4167}, + {0xf960, 4172}, + {0xf961, 5552}, + {0xf962, 6424}, + {0xf963, 5151}, + {0xf964, 4922}, + {0xf965, 7518}, + {0xf966, 5079}, + {0xf967, 5109}, + {0xf968, 7607}, + {0xf969, 5584}, + {0xf96a, 5367}, + {0xf96b, 7083}, + {0xf96c, 5362}, + {0xf96d, 5485}, + {0xf96e, 6001}, + {0xf96f, 5460}, + {0xf970, 5317}, + {0xf971, 7009}, + {0xf972, 7370}, + {0xf973, 5678}, + {0xf974, 5874}, + {0xf975, 4425}, + {0xf976, 4426}, + {0xf977, 4427}, + {0xf978, 4429}, + {0xf979, 4430}, + {0xf97a, 4431}, + {0xf97b, 4435}, + {0xf97c, 4436}, + {0xf97d, 4437}, + {0xf97e, 4439}, + {0xf97f, 4442}, + {0xf980, 4443}, + {0xf981, 4159}, + {0xf982, 4444}, + {0xf983, 4447}, + {0xf984, 4449}, + {0xf985, 4450}, + {0xf986, 4453}, + {0xf987, 4455}, + {0xf988, 4456}, + {0xf989, 4457}, + {0xf98a, 4458}, + {0xf98b, 4459}, + {0xf98c, 4460}, + {0xf98d, 4463}, + {0xf98e, 4160}, + {0xf98f, 4465}, + {0xf990, 4466}, + {0xf991, 4161}, + {0xf992, 4468}, + {0xf993, 4469}, + {0xf994, 4470}, + {0xf995, 4162}, + {0xf996, 4471}, + {0xf997, 4472}, + {0xf998, 4474}, + {0xf999, 4473}, + {0xf99a, 4475}, + {0xf99b, 4476}, + {0xf99c, 4478}, + {0xf99d, 4479}, + {0xf99e, 6447}, + {0xf99f, 4481}, + {0xf9a0, 4482}, + {0xf9a1, 5460}, + {0xf9a2, 4483}, + {0xf9a3, 4163}, + {0xf9a4, 4166}, + {0xf9a5, 4485}, + {0xf9a6, 4487}, + {0xf9a7, 4488}, + {0xf9a8, 4489}, + {0xf9a9, 4491}, + {0xf9aa, 4167}, + {0xf9ab, 4493}, + {0xf9ac, 4494}, + {0xf9ad, 4495}, + {0xf9ae, 7783}, + {0xf9af, 4497}, + {0xf9b0, 4499}, + {0xf9b1, 4501}, + {0xf9b2, 4502}, + {0xf9b3, 4503}, + {0xf9b4, 4504}, + {0xf9b5, 4506}, + {0xf9b6, 4508}, + {0xf9b7, 4509}, + {0xf9b8, 4510}, + {0xf9b9, 5797}, + {0xf9ba, 4551}, + {0xf9bb, 4552}, + {0xf9bc, 4553}, + {0xf9bd, 4180}, + {0xf9be, 4555}, + {0xf9bf, 5800}, + {0xf9c0, 4556}, + {0xf9c1, 4557}, + {0xf9c2, 4560}, + {0xf9c3, 4561}, + {0xf9c4, 4563}, + {0xf9c5, 7988}, + {0xf9c6, 6123}, + {0xf9c7, 4577}, + {0xf9c8, 4183}, + {0xf9c9, 4579}, + {0xf9ca, 4581}, + {0xf9cb, 4582}, + {0xf9cc, 4584}, + {0xf9cd, 4586}, + {0xf9ce, 4588}, + {0xf9cf, 4184}, + {0xf9d0, 4590}, + {0xf9d1, 4591}, + {0xf9d2, 4592}, + {0xf9d3, 4593}, + {0xf9d4, 4595}, + {0xf9d5, 4596}, + {0xf9d6, 4597}, + {0xf9d7, 4599}, + {0xf9d8, 4600}, + {0xf9d9, 4601}, + {0xf9da, 4602}, + {0xf9db, 5552}, + {0xf9dc, 4603}, + {0xf9dd, 4614}, + {0xf9de, 4616}, + {0xf9df, 4618}, + {0xf9e0, 5950}, + {0xf9e1, 4620}, + {0xf9e2, 4621}, + {0xf9e3, 4187}, + {0xf9e4, 4625}, + {0xf9e5, 4627}, + {0xf9e6, 4629}, + {0xf9e7, 4632}, + {0xf9e8, 4633}, + {0xf9e9, 4634}, + {0xf9ea, 4636}, + {0xf9eb, 4188}, + {0xf9ec, 4189}, + {0xf9ed, 4638}, + {0xf9ee, 4640}, + {0xf9ef, 4641}, + {0xf9f0, 4642}, + {0xf9f1, 4644}, + {0xf9f2, 4645}, + {0xf9f3, 4646}, + {0xf9f4, 4647}, + {0xf9f5, 4648}, + {0xf9f6, 4650}, + {0xf9f7, 4653}, + {0xf9f8, 4654}, + {0xf9f9, 4655}, + {0xf9fa, 5351}, + {0xf9fb, 6494}, + {0xf9fc, 5731}, + {0xf9fd, 5771}, + {0xf9fe, 4191}, + {0xf9ff, 6484}, + {0xfa00, 6684}, + {0xfa01, 4279}, + {0xfa02, 7139}, + {0xfa03, 4247}, + {0xfa04, 4266}, + {0xfa05, 4340}, + {0xfa06, 7572}, + {0xfa07, 5088}, + {0xfa08, 7709}, + {0xfa09, 3558}, + {0xfa0a, 3644}, + {0xfa0b, 3815}, + {0xff01, 264}, + {0xff02, 265}, + {0xff03, 266}, + {0xff04, 267}, + {0xff05, 268}, + {0xff06, 269}, + {0xff07, 270}, + {0xff08, 271}, + {0xff09, 272}, + {0xff0a, 273}, + {0xff0b, 274}, + {0xff0c, 275}, + {0xff0d, 276}, + {0xff0e, 277}, + {0xff0f, 278}, + {0xff10, 279}, + {0xff11, 280}, + {0xff12, 281}, + {0xff13, 282}, + {0xff14, 283}, + {0xff15, 284}, + {0xff16, 285}, + {0xff17, 286}, + {0xff18, 287}, + {0xff19, 288}, + {0xff1a, 289}, + {0xff1b, 290}, + {0xff1c, 291}, + {0xff1d, 292}, + {0xff1e, 293}, + {0xff1f, 294}, + {0xff20, 295}, + {0xff21, 296}, + {0xff22, 297}, + {0xff23, 298}, + {0xff24, 299}, + {0xff25, 300}, + {0xff26, 301}, + {0xff27, 302}, + {0xff28, 303}, + {0xff29, 304}, + {0xff2a, 305}, + {0xff2b, 306}, + {0xff2c, 307}, + {0xff2d, 308}, + {0xff2e, 309}, + {0xff2f, 310}, + {0xff30, 311}, + {0xff31, 312}, + {0xff32, 313}, + {0xff33, 314}, + {0xff34, 315}, + {0xff35, 316}, + {0xff36, 317}, + {0xff37, 318}, + {0xff38, 319}, + {0xff39, 320}, + {0xff3a, 321}, + {0xff3b, 322}, + {0xff3c, 112}, + {0xff3d, 324}, + {0xff3e, 325}, + {0xff3f, 326}, + {0xff40, 327}, + {0xff41, 328}, + {0xff42, 329}, + {0xff43, 330}, + {0xff44, 331}, + {0xff45, 332}, + {0xff46, 333}, + {0xff47, 334}, + {0xff48, 335}, + {0xff49, 336}, + {0xff4a, 337}, + {0xff4b, 338}, + {0xff4c, 339}, + {0xff4d, 340}, + {0xff4e, 341}, + {0xff4f, 342}, + {0xff50, 343}, + {0xff51, 344}, + {0xff52, 345}, + {0xff53, 346}, + {0xff54, 347}, + {0xff55, 348}, + {0xff56, 349}, + {0xff57, 350}, + {0xff58, 351}, + {0xff59, 352}, + {0xff5a, 353}, + {0xff5b, 354}, + {0xff5c, 355}, + {0xff5d, 356}, + {0xff5e, 113}, + {0xffe0, 143}, + {0xffe1, 144}, + {0xffe2, 194}, + {0xffe3, 357}, + {0xffe5, 145}, + {0xffe6, 323}}; + diff --git a/src/add-ons/print/drivers/pdf/source/pdflib.h b/src/add-ons/print/drivers/pdf/source/pdflib.h new file mode 100644 index 0000000000..c296f7e4d7 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/pdflib.h @@ -0,0 +1,943 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2002 PDFlib GmbH and Thomas Merz. All rights reserved. | + +---------------------------------------------------------------------------+ + | This software is NOT in the public domain. It can be used under two | + | substantially different licensing terms: | + | | + | The commercial license is available for a fee, and allows you to | + | - ship a commercial product based on PDFlib | + | - implement commercial Web services with PDFlib | + | - distribute (free or commercial) software when the source code is | + | not made available | + | Details can be found in the file PDFlib-license.pdf. | + | | + | The "Aladdin Free Public License" doesn't require any license fee, | + | and allows you to | + | - develop and distribute PDFlib-based software for which the complete | + | source code is made available | + | - redistribute PDFlib non-commercially under certain conditions | + | - redistribute PDFlib on digital media for a fee if the complete | + | contents of the media are freely redistributable | + | Details can be found in the file aladdin-license.pdf. | + | | + | These conditions extend to ports to other programming languages. | + | PDFlib is distributed with no warranty of any kind. Commercial users, | + | however, will receive warranty and support statements in writing. | + *---------------------------------------------------------------------------*/ + +/* $Id: pdflib.h,v 1.1 2002/07/09 12:24:37 ejakowatz Exp $ + * + * PDFlib public function and constant declarations + * + */ + +#ifndef PDFLIB_H +#define PDFLIB_H + +/* + * ---------------------------------------------------------------------- + * Setup, mostly Windows calling conventions and DLL stuff + * ---------------------------------------------------------------------- + */ + +#include + +#ifdef WIN32 + +#define PDFLIB_CALL __cdecl + +#ifdef PDFLIB_EXPORTS +#define PDFLIB_API __declspec(dllexport) /* prepare a DLL (internal use only) */ + +#elif defined(PDFLIB_DLL) +#define PDFLIB_API __declspec(dllimport) /* PDFlib clients: import PDFlib DLL */ + +#else /* !PDFLIB_DLL */ +#define PDFLIB_API /* */ /* default: generate or use static library */ + +#endif /* !PDFLIB_DLL */ + +#else /* !WIN32 */ + +#if ((defined __IBMC__ || defined __IBMCPP__) && defined __DLL__ && defined OS2) + #define PDFLIB_CALL _Export + #define PDFLIB_API +#endif /* IBM VisualAge C++ DLL */ + +#ifndef PDFLIB_CALL +#define PDFLIB_CALL +#endif +#ifndef PDFLIB_API +#define PDFLIB_API +#endif + +#endif /* !WIN32 */ + +/* export all symbols for a shared library on the Mac */ +#if defined(__MWERKS__) && defined(PDFLIB_EXPORTS) +#pragma export on +#endif + +/* Make our declarations C++ compatible */ +#ifdef __cplusplus +extern "C" { +#endif + +/* Define the basic PDF type. This is used opaquely at the API level. */ +typedef struct PDF_s PDF; + +/* The API structure with function pointers. */ +typedef struct PDFlib_api_s PDFlib_api; + + +/* + * ---------------------------------------------------------------------- + * p_basic.c: general functions + * ---------------------------------------------------------------------- + */ + +/* + * The version defines below may be used to check the version of the + * include file against the library. + */ + +/* do not change this (version.sh will do it for you :) */ +#define PDFLIB_MAJORVERSION 4 /* PDFlib major version number */ +#define PDFLIB_MINORVERSION 0 /* PDFlib minor version number */ +#define PDFLIB_REVISION 3 /* PDFlib revision number */ +#define PDFLIB_VERSIONSTRING "4.0.3" /* The whole bunch */ + +/* + * Allow for the external and internal float type to be easily redefined. + * This is only for special applications which require improved accuracy, + * and not supported in the general case due to platform and binary + * compatibility issues. +*/ +/* #define float double */ + +/* Retrieve a structure with PDFlib API function pointers (mainly for DLLs) */ +PDFLIB_API PDFlib_api * PDFLIB_CALL +PDF_get_api(void); + +/* Returns the PDFlib major version number. */ +PDFLIB_API int PDFLIB_CALL +PDF_get_majorversion(void); + +/* Returns the PDFlib minor version number. */ +PDFLIB_API int PDFLIB_CALL +PDF_get_minorversion(void); + +/* Boot PDFlib (recommended although currently not required). */ +PDFLIB_API void PDFLIB_CALL +PDF_boot(void); + +/* Shut down PDFlib (recommended although currently not required). */ +PDFLIB_API void PDFLIB_CALL +PDF_shutdown(void); + +/* Create a new PDF object with client-supplied error handling and memory + allocation routines. */ +typedef void (*errorproc_t)(PDF *p1, int type, const char *msg); +typedef void* (*allocproc_t)(PDF *p2, size_t size, const char *caller); +typedef void* (*reallocproc_t)(PDF *p3, + void *mem, size_t size, const char *caller); +typedef void (*freeproc_t)(PDF *p4, void *mem); + +PDFLIB_API PDF * PDFLIB_CALL +PDF_new2(errorproc_t errorhandler, allocproc_t allocproc, + reallocproc_t reallocproc, freeproc_t freeproc, void *opaque); + +/* Fetch opaque application pointer stored in PDFlib (for multi-threading). */ +PDFLIB_API void * PDFLIB_CALL +PDF_get_opaque(PDF *p); + +/* Create a new PDF object, using default error handling and memory + management. */ +PDFLIB_API PDF * PDFLIB_CALL +PDF_new(void); + +/* Delete the PDF object, and free all internal resources. */ +PDFLIB_API void PDFLIB_CALL +PDF_delete(PDF *p); + +/* Create a new PDF file using the supplied file name. */ +PDFLIB_API int PDFLIB_CALL +PDF_open_file(PDF *p, const char *filename); + +/* Open a new PDF file associated with p, using the supplied file handle. */ +PDFLIB_API int PDFLIB_CALL +PDF_open_fp(PDF *p, FILE *fp); + +/* Open a new PDF in memory, and install a callback for fetching the data. */ +typedef size_t (*writeproc_t)(PDF *p1, void *data, size_t size); +PDFLIB_API void PDFLIB_CALL +PDF_open_mem(PDF *p, writeproc_t writeproc); + +/* Close the generated PDF file, and release all document-related resources. */ +PDFLIB_API void PDFLIB_CALL +PDF_close(PDF *p); + +/* Add a new page to the document. */ +PDFLIB_API void PDFLIB_CALL +PDF_begin_page(PDF *p, float width, float height); + +/* Finish the page. */ +PDFLIB_API void PDFLIB_CALL +PDF_end_page(PDF *p); + +/* PDFlib exceptions which may be handled by a user-supplied error handler */ +#define PDF_MemoryError 1 +#define PDF_IOError 2 +#define PDF_RuntimeError 3 +#define PDF_IndexError 4 +#define PDF_TypeError 5 +#define PDF_DivisionByZero 6 +#define PDF_OverflowError 7 +#define PDF_SyntaxError 8 +#define PDF_ValueError 9 +#define PDF_SystemError 10 +#define PDF_NonfatalError 11 +#define PDF_UnknownError 12 + + +/* + * ---------------------------------------------------------------------- + * p_params.c: parameter handling + * ---------------------------------------------------------------------- + */ + +/* Set some PDFlib parameter with string type. */ +PDFLIB_API void PDFLIB_CALL +PDF_set_parameter(PDF *p, const char *key, const char *value); + +/* Set the value of some PDFlib parameter with float type. */ +PDFLIB_API void PDFLIB_CALL +PDF_set_value(PDF *p, const char *key, float value); + +/* Get the contents of some PDFlib parameter with string type. */ +PDFLIB_API const char * PDFLIB_CALL +PDF_get_parameter(PDF *p, const char *key, float modifier); + +/* Get the value of some PDFlib parameter with float type. */ +PDFLIB_API float PDFLIB_CALL +PDF_get_value(PDF *p, const char *key, float modifier); + + +/* + * ---------------------------------------------------------------------- + * p_font.c: text and font handling + * ---------------------------------------------------------------------- + */ + +/* Search a font, and prepare it for later use. The metrics will be + loaded, and if embed is nonzero, the font file will be checked, but not + yet used. Encoding is one of "builtin", "macroman", "winansi", "host", or + a user-defined encoding name, or the name of a CMap. */ +PDFLIB_API int PDFLIB_CALL +PDF_findfont(PDF *p, const char *fontname, const char *encoding, int embed); + +/* Set the current font in the given size, using a font handle returned by + PDF_findfont(). */ +PDFLIB_API void PDFLIB_CALL +PDF_setfont(PDF *p, int font, float fontsize); + +/* Request a glyph name from a custom encoding (unsupported). */ +PDFLIB_API const char * PDFLIB_CALL +PDF_encoding_get_name(PDF *p, const char *encoding, int slot); + +/* + * ---------------------------------------------------------------------- + * p_text.c: text output + * ---------------------------------------------------------------------- + */ + +/* Print text in the current font and size at the current position. */ +PDFLIB_API void PDFLIB_CALL +PDF_show(PDF *p, const char *text); + +/* Print text in the current font at (x, y). */ +PDFLIB_API void PDFLIB_CALL +PDF_show_xy(PDF *p, const char *text, float x, float y); + +/* Print text at the next line. The spacing between lines is determined by + the "leading" parameter. */ +PDFLIB_API void PDFLIB_CALL +PDF_continue_text(PDF *p, const char *text); + +/* Format text in the current font and size into the supplied text box + according to the requested formatting mode, which must be one of + "left", "right", "center", "justify", or "fulljustify". If width and height + are 0, only a single line is placed at the point (left, top) in the + requested mode. */ +PDFLIB_API int PDFLIB_CALL +PDF_show_boxed(PDF *p, const char *text, float left, float top, + float width, float height, const char *hmode, const char *feature); + +/* This function is unsupported, and not considered part of the PDFlib API! */ +PDFLIB_API void PDFLIB_CALL +PDF_set_text_matrix(PDF *p, + float a, float b, float c, float d, float e, float f); + +/* Set the text output position. */ +PDFLIB_API void PDFLIB_CALL +PDF_set_text_pos(PDF *p, float x, float y); + +/* Return the width of text in an arbitrary font. */ +PDFLIB_API float PDFLIB_CALL +PDF_stringwidth(PDF *p, const char *text, int font, float size); + +/* Function duplicates with explicit string length for use with +strings containing null characters. These are for C and C++ clients only, +but are used internally for the other language bindings. */ + +/* Same as PDF_show() but with explicit string length. */ +PDFLIB_API void PDFLIB_CALL +PDF_show2(PDF *p, const char *text, int len); + +/* Same as PDF_show_xy() but with explicit string length. */ +PDFLIB_API void PDFLIB_CALL +PDF_show_xy2(PDF *p, const char *text, int len, float x, float y); + +/* Same as PDF_continue_text but with explicit string length. */ +PDFLIB_API void PDFLIB_CALL +PDF_continue_text2(PDF *p, const char *text, int len); + +/* Same as PDF_stringwidth but with explicit string length. */ +PDFLIB_API float PDFLIB_CALL +PDF_stringwidth2(PDF *p, const char *text, int len, int font, float size); + + +/* + * ---------------------------------------------------------------------- + * p_gstate.c: graphics state + * ---------------------------------------------------------------------- + */ + +/* Maximum length of dash arrays */ +#define MAX_DASH_LENGTH 8 + +/* Set the current dash pattern to b black and w white units. */ +PDFLIB_API void PDFLIB_CALL +PDF_setdash(PDF *p, float b, float w); + +/* Set a more complicated dash pattern defined by an array. */ +PDFLIB_API void PDFLIB_CALL +PDF_setpolydash(PDF *p, float *dasharray, int length); + +/* Set the flatness to a value between 0 and 100 inclusive. */ +PDFLIB_API void PDFLIB_CALL +PDF_setflat(PDF *p, float flatness); + +/* Set the line join parameter to a value between 0 and 2 inclusive. */ +PDFLIB_API void PDFLIB_CALL +PDF_setlinejoin(PDF *p, int linejoin); + +/* Set the linecap parameter to a value between 0 and 2 inclusive. */ +PDFLIB_API void PDFLIB_CALL +PDF_setlinecap(PDF *p, int linecap); + +/* Set the miter limit to a value greater than or equal to 1. */ +PDFLIB_API void PDFLIB_CALL +PDF_setmiterlimit(PDF *p, float miter); + +/* Set the current linewidth to width. */ +PDFLIB_API void PDFLIB_CALL +PDF_setlinewidth(PDF *p, float width); + +/* Reset all color and graphics state parameters to their defaults. */ +PDFLIB_API void PDFLIB_CALL +PDF_initgraphics(PDF *p); + +/* Save the current graphics state. */ +PDFLIB_API void PDFLIB_CALL +PDF_save(PDF *p); + +/* Restore the most recently saved graphics state. */ +PDFLIB_API void PDFLIB_CALL +PDF_restore(PDF *p); + +/* Translate the origin of the coordinate system. */ +PDFLIB_API void PDFLIB_CALL +PDF_translate(PDF *p, float tx, float ty); + +/* Scale the coordinate system. */ +PDFLIB_API void PDFLIB_CALL +PDF_scale(PDF *p, float sx, float sy); + +/* Rotate the coordinate system by phi degrees. */ +PDFLIB_API void PDFLIB_CALL +PDF_rotate(PDF *p, float phi); + +/* Skew the coordinate system in x and y direction by alpha and beta degrees. */ +PDFLIB_API void PDFLIB_CALL +PDF_skew(PDF *p, float alpha, float beta); + +/* Concatenate a matrix to the current transformation matrix. */ +PDFLIB_API void PDFLIB_CALL +PDF_concat(PDF *p, float a, float b, float c, float d, float e, float f); + +/* Explicitly set the current transformation matrix. */ +PDFLIB_API void PDFLIB_CALL +PDF_setmatrix(PDF *p, float a, float b, float c, float d, float e, float f); + + +/* + * ---------------------------------------------------------------------- + * p_draw.c: path construction, painting, and clipping + * ---------------------------------------------------------------------- + */ + +/* Set the current point. */ +PDFLIB_API void PDFLIB_CALL +PDF_moveto(PDF *p, float x, float y); + +/* Draw a line from the current point to (x, y). */ +PDFLIB_API void PDFLIB_CALL +PDF_lineto(PDF *p, float x, float y); + +/* Draw a Bezier curve from the current point, using 3 more control points. */ +PDFLIB_API void PDFLIB_CALL +PDF_curveto(PDF *p, float x1, float y1, float x2, float y2, float x3, float y3); + +/* Draw a circle with center (x, y) and radius r. */ +PDFLIB_API void PDFLIB_CALL +PDF_circle(PDF *p, float x, float y, float r); + +/* Draw a counterclockwise circular arc from alpha to beta degrees. */ +PDFLIB_API void PDFLIB_CALL +PDF_arc(PDF *p, float x, float y, float r, float alpha, float beta); + +/* Draw a clockwise circular arc from alpha to beta degrees. */ +PDFLIB_API void PDFLIB_CALL +PDF_arcn(PDF *p, float x, float y, float r, float alpha, float beta); + +/* Draw a rectangle at lower left (x, y) with width and height. */ +PDFLIB_API void PDFLIB_CALL +PDF_rect(PDF *p, float x, float y, float width, float height); + +/* Close the current path. */ +PDFLIB_API void PDFLIB_CALL +PDF_closepath(PDF *p); + +/* Stroke the path with the current color and line width, and clear it. */ +PDFLIB_API void PDFLIB_CALL +PDF_stroke(PDF *p); + +/* Close the path, and stroke it. */ +PDFLIB_API void PDFLIB_CALL +PDF_closepath_stroke(PDF *p); + +/* Fill the interior of the path with the current fill color. */ +PDFLIB_API void PDFLIB_CALL +PDF_fill(PDF *p); + +/* Fill and stroke the path with the current fill and stroke color. */ +PDFLIB_API void PDFLIB_CALL +PDF_fill_stroke(PDF *p); + +/* Close the path, fill, and stroke it. */ +PDFLIB_API void PDFLIB_CALL +PDF_closepath_fill_stroke(PDF *p); + +/* End the current path without filling or stroking it. */ +PDFLIB_API void PDFLIB_CALL +PDF_endpath(PDF *p); + +/* Use the current path as clipping path. */ +PDFLIB_API void PDFLIB_CALL +PDF_clip(PDF *p); + + +/* + * ---------------------------------------------------------------------- + * p_color.c: color handling + * ---------------------------------------------------------------------- + */ + +/* Deprecated, use PDF_setcolor(p, "fill", "gray", g, 0, 0, 0) instead. */ +PDFLIB_API void PDFLIB_CALL +PDF_setgray_fill(PDF *p, float gray); + +/* Deprecated, use PDF_setcolor(p, "stroke", "gray", g, 0, 0, 0) instead. */ +PDFLIB_API void PDFLIB_CALL +PDF_setgray_stroke(PDF *p, float gray); + +/* Deprecated, use PDF_setcolor(p, "both", "gray", g, 0, 0, 0) instead. */ +PDFLIB_API void PDFLIB_CALL +PDF_setgray(PDF *p, float gray); + +/* Deprecated, use PDF_setcolor(p, "fill", "rgb", red, green, blue, 0). */ +PDFLIB_API void PDFLIB_CALL +PDF_setrgbcolor_fill(PDF *p, float red, float green, float blue); + +/* Deprecated, use PDF_setcolor(p, "stroke", "rgb", red, green, blue, 0). */ +PDFLIB_API void PDFLIB_CALL +PDF_setrgbcolor_stroke(PDF *p, float red, float green, float blue); + +/* Deprecated, use PDF_setcolor(p, "both", "rgb", red, green, blue, 0). */ +PDFLIB_API void PDFLIB_CALL +PDF_setrgbcolor(PDF *p, float red, float green, float blue); + +/* Make a named spot color from the current color. */ +PDFLIB_API int PDFLIB_CALL +PDF_makespotcolor(PDF *p, const char *spotname, int len); + +/* Set the current color space and color. type is "fill", "stroke", or "both".*/ +PDFLIB_API void PDFLIB_CALL +PDF_setcolor(PDF *p, const char *fstype, const char *colorspace, + float c1, float c2, float c3, float c4); + + +/* + * ---------------------------------------------------------------------- + * p_pattern.c: pattern definition + * ---------------------------------------------------------------------- + */ + +/* Start a new pattern definition. */ +PDFLIB_API int PDFLIB_CALL +PDF_begin_pattern(PDF *p, + float width, float height, float xstep, float ystep, int painttype); + +/* Finish a pattern definition. */ +PDFLIB_API void PDFLIB_CALL +PDF_end_pattern(PDF *p); + + +/* + * ---------------------------------------------------------------------- + * p_template.c: template definition + * ---------------------------------------------------------------------- + */ + +/* Start a new template definition. */ +PDFLIB_API int PDFLIB_CALL +PDF_begin_template(PDF *p, float width, float height); + +/* Finish a template definition. */ +PDFLIB_API void PDFLIB_CALL +PDF_end_template(PDF *p); + + +/* + * ---------------------------------------------------------------------- + * p_image.c: image handling + * ---------------------------------------------------------------------- + */ + +/* Place an image or template with the lower left corner at (x, y), + and scale it. */ +PDFLIB_API void PDFLIB_CALL +PDF_place_image(PDF *p, int image, float x, float y, float scale); + +/* Use image data from a variety of data sources. Supported types are + "jpeg", "ccitt", "raw". Supported sources are "memory", "fileref", "url". + len is only used for type="raw", params is only used for type="ccitt". */ +PDFLIB_API int PDFLIB_CALL +PDF_open_image(PDF *p, const char *imagetype, const char *source, + const char *data, long length, int width, int height, int components, + int bpc, const char *params); + +/* Open an image file. Supported types are "jpeg", "tiff", "gif", and "png" + stringparam is either "", "mask", "masked", or "page". intparam is either 0, + the image number of the applied mask, or the page. */ +PDFLIB_API int PDFLIB_CALL +PDF_open_image_file(PDF *p, const char *imagetype, const char *filename, + const char *stringparam, int intparam); + +/* Close an image retrieved with one of the PDF_open_image*() functions. */ +PDFLIB_API void PDFLIB_CALL +PDF_close_image(PDF *p, int image); + +/* Add an existing image as thumbnail for the current page. */ +PDFLIB_API void PDFLIB_CALL +PDF_add_thumbnail(PDF *p, int image); + + +/* + * ---------------------------------------------------------------------- + * p_ccitt.c: fax-compressed data processing + * ---------------------------------------------------------------------- + */ + +/* Open a raw CCITT image. */ +PDFLIB_API int PDFLIB_CALL +PDF_open_CCITT(PDF *p, const char *filename, int width, int height, + int BitReverse, int K, int BlackIs1); + + +/* + * ---------------------------------------------------------------------- + * p_hyper.c: bookmarks and document info fields + * ---------------------------------------------------------------------- + */ + +/* Add a nested bookmark under parent, or a new top-level bookmark if + parent = 0. Returns a bookmark descriptor which may be + used as parent for subsequent nested bookmarks. If open = 1, child + bookmarks will be folded out, and invisible if open = 0. */ +PDFLIB_API int PDFLIB_CALL +PDF_add_bookmark(PDF *p, const char *text, int parent, int open); + + +/* Fill document information field key with value. key is one of "Subject", + "Title", "Creator", "Author", "Keywords", or a user-defined key. */ +PDFLIB_API void PDFLIB_CALL +PDF_set_info(PDF *p, const char *key, const char *value); + + +/* + * ---------------------------------------------------------------------- + * p_annots.c: file attachments, notes, and links + * ---------------------------------------------------------------------- + */ + +/* Add a file attachment annotation. icon is one of "graph", "paperclip", + "pushpin", or "tag". */ +PDFLIB_API void PDFLIB_CALL +PDF_attach_file(PDF *p, float llx, float lly, float urx, float ury, + const char *filename, const char *description, const char *author, + const char *mimetype, const char *icon); + +/* Add a note annotation. icon is one of of "comment", "insert", "note", + "paragraph", "newparagraph", "key", or "help". */ +PDFLIB_API void PDFLIB_CALL +PDF_add_note(PDF *p, float llx, float lly, float urx, float ury, + const char *contents, const char *title, const char *icon, int open); + +/* Add a file link annotation (to a PDF target). */ +PDFLIB_API void PDFLIB_CALL +PDF_add_pdflink(PDF *p, float llx, float lly, float urx, float ury, + const char *filename, int page, const char *dest); + +/* Add a launch annotation (to a target of arbitrary file type). */ +PDFLIB_API void PDFLIB_CALL +PDF_add_launchlink(PDF *p, float llx, float lly, float urx, float ury, + const char *filename); + +/* Add a link annotation to a target within the current PDF file. */ +PDFLIB_API void PDFLIB_CALL +PDF_add_locallink(PDF *p, float llx, float lly, float urx, float ury, + int page, const char *dest); + +/* Add a weblink annotation to a target URL on the Web. */ +PDFLIB_API void PDFLIB_CALL +PDF_add_weblink(PDF *p, float llx, float lly, float urx, float ury, + const char *url); + +/* Set the border style for all kinds of annotations. style is "solid" or + "dashed". */ +PDFLIB_API void PDFLIB_CALL +PDF_set_border_style(PDF *p, const char *style, float width); + +/* Set the border color for all kinds of annotations. */ +PDFLIB_API void PDFLIB_CALL +PDF_set_border_color(PDF *p, float red, float green, float blue); + +/* Set the border dash style for all kinds of annotations. See PDF_setdash(). */ +PDFLIB_API void PDFLIB_CALL +PDF_set_border_dash(PDF *p, float b, float w); + + +/* + * ---------------------------------------------------------------------- + * p_pdi.c: PDF import (requires the PDI library) + * ---------------------------------------------------------------------- + */ + +/* Open an existing PDF document and prepare it for later use. */ +PDFLIB_API int PDFLIB_CALL +PDF_open_pdi(PDF *p, const char *filename, const char *stringparam, + int intparam); + +/* Close all open page handles, and close the input PDF document. */ +PDFLIB_API void PDFLIB_CALL +PDF_close_pdi(PDF *p, int doc); + +/* Prepare a page for later use with PDF_place_pdi_page(). */ +PDFLIB_API int PDFLIB_CALL +PDF_open_pdi_page(PDF *p, int doc, int page, const char *label); + +/* Place a PDF page with the lower left corner at (x, y), and scale it. */ +PDFLIB_API void PDFLIB_CALL +PDF_place_pdi_page(PDF *p, int page, float x, float y, float sx, float sy); + +/* Close the page handle, and free all page-related resources. */ +PDFLIB_API void PDFLIB_CALL +PDF_close_pdi_page(PDF *p, int page); + +/* Get the contents of some PDI document parameter with string type. */ +PDFLIB_API const char *PDFLIB_CALL +PDF_get_pdi_parameter(PDF *p, const char *key, int doc, int page, + int index, int *len); + +/* Get the contents of some PDI document parameter with numerical type. */ +PDFLIB_API float PDFLIB_CALL +PDF_get_pdi_value(PDF *p, const char *key, int doc, int page, int index); + + +/* + * ---------------------------------------------------------------------- + * p_stream.c: output stream handling + * ---------------------------------------------------------------------- + */ + +/* Get the contents of the PDF output buffer. The result must be used by + the client before calling any other PDFlib function. */ +PDFLIB_API const char * PDFLIB_CALL +PDF_get_buffer(PDF *p, long *size); + + +/* + * ---------------------------------------------------------------------- + * page size formats + * ---------------------------------------------------------------------- + */ + +/* +Although PDF doesn´t impose any restrictions on the usable page size, +Acrobat implementations suffer from architectural limits concerning +the page size. +Although PDFlib will generate PDF documents with page sizes outside +these limits, the default error handler will issue a warning message. + +Acrobat 3 minimum page size: 1" = 72 pt = 2.54 cm +Acrobat 3 maximum page size: 45" = 3240 pt = 114.3 cm +Acrobat 4 minimum page size: 0.25" = 18 pt = 0.635 cm +Acrobat 4 maximum page size: 200" = 14400 pt = 508 cm +*/ + +/* The page sizes are only available to the C and C++ bindings */ +#define a0_width (float) 2380.0 +#define a0_height (float) 3368.0 +#define a1_width (float) 1684.0 +#define a1_height (float) 2380.0 +#define a2_width (float) 1190.0 +#define a2_height (float) 1684.0 +#define a3_width (float) 842.0 +#define a3_height (float) 1190.0 +#define a4_width (float) 595.0 +#define a4_height (float) 842.0 +#define a5_width (float) 421.0 +#define a5_height (float) 595.0 +#define a6_width (float) 297.0 +#define a6_height (float) 421.0 +#define b5_width (float) 501.0 +#define b5_height (float) 709.0 +#define letter_width (float) 612.0 +#define letter_height (float) 792.0 +#define legal_width (float) 612.0 +#define legal_height (float) 1008.0 +#define ledger_width (float) 1224.0 +#define ledger_height (float) 792.0 +#define p11x17_width (float) 792.0 +#define p11x17_height (float) 1224.0 + +/* The API structure with pointers to all PDFlib API functions */ +struct PDFlib_api_s { + /* general functions */ + PDFlib_api * (PDFLIB_CALL * const PDF_get_api)(void); + int (PDFLIB_CALL * const PDF_get_majorversion)(void); + int (PDFLIB_CALL * const PDF_get_minorversion)(void); + void (PDFLIB_CALL * const PDF_boot)(void); + void (PDFLIB_CALL * const PDF_shutdown)(void); + PDF* (PDFLIB_CALL * const PDF_new2)(errorproc_t errorhandler, + allocproc_t allocproc, + reallocproc_t reallocproc, + freeproc_t freeproc, void *opaque); + void * (PDFLIB_CALL * const PDF_get_opaque)(PDF *p); + PDF* (PDFLIB_CALL * const PDF_new)(void); + void (PDFLIB_CALL * const PDF_delete)(PDF *); + int (PDFLIB_CALL * const PDF_open_file)(PDF *p, const char *filename); + int (PDFLIB_CALL * const PDF_open_fp)(PDF *p, FILE *fp); + void (PDFLIB_CALL * const PDF_open_mem)(PDF *p, writeproc_t writeproc); + void (PDFLIB_CALL * const PDF_close)(PDF *p); + void (PDFLIB_CALL * const PDF_begin_page)(PDF *p, float width, + float height); + void (PDFLIB_CALL * const PDF_end_page)(PDF *p); + + /* parameter handling */ + void (PDFLIB_CALL * const PDF_set_parameter)(PDF *p, + const char *key, const char *value); + void (PDFLIB_CALL * const PDF_set_value)(PDF *p, const char *key, + float value); + const char* (PDFLIB_CALL * const PDF_get_parameter)(PDF *p, + const char *key, float modifier); + float (PDFLIB_CALL * const PDF_get_value)(PDF *p, const char *key, + float modifier); + + /* text and font handling */ + int (PDFLIB_CALL * const PDF_findfont)(PDF *p, const char *fontname, + const char *encoding, int embed); + void (PDFLIB_CALL * const PDF_setfont)(PDF *p, int font, float fontsize); + const char * (PDFLIB_CALL * const PDF_encoding_get_name)(PDF *p, + const char *encoding, int slot); + + /* text output */ + void (PDFLIB_CALL * const PDF_show)(PDF *p, const char *text); + void (PDFLIB_CALL * const PDF_show_xy)(PDF *p, const char *text, float x, + float y); + void (PDFLIB_CALL * const PDF_continue_text)(PDF *p, const char *text); + int (PDFLIB_CALL * const PDF_show_boxed)(PDF *p, const char *text, + float left, float top, float width, float height, + const char *hmode, const char *feature); + void (PDFLIB_CALL * const PDF_set_text_matrix)(PDF *p, float a, float b, + float c, float d, float e, float f); + void (PDFLIB_CALL * const PDF_set_text_pos)(PDF *p, float x, float y); + float (PDFLIB_CALL * const PDF_stringwidth)(PDF *p, + const char *text, int font, float size); + void (PDFLIB_CALL * const PDF_show2)(PDF *p, const char *text, int len); + void (PDFLIB_CALL * const PDF_show_xy2)(PDF *p, const char *text, + int len, float x, float y); + void (PDFLIB_CALL * const PDF_continue_text2)(PDF *p, const char *text, + int len); + float (PDFLIB_CALL * const PDF_stringwidth2)(PDF *p, const char *text, + int len, int font, float size); + /* graphics state */ + void (PDFLIB_CALL * const PDF_setdash)(PDF *p, float b, float w); + void (PDFLIB_CALL * const PDF_setpolydash)(PDF *p, float *dasharray, + int length); + void (PDFLIB_CALL * const PDF_setflat)(PDF *p, float flatness); + void (PDFLIB_CALL * const PDF_setlinejoin)(PDF *p, int linejoin); + void (PDFLIB_CALL * const PDF_setlinecap)(PDF *p, int linecap); + void (PDFLIB_CALL * const PDF_setmiterlimit)(PDF *p, float miter); + void (PDFLIB_CALL * const PDF_setlinewidth)(PDF *p, float width); + void (PDFLIB_CALL * const PDF_initgraphics)(PDF *p); + void (PDFLIB_CALL * const PDF_save)(PDF *p); + void (PDFLIB_CALL * const PDF_restore)(PDF *p); + void (PDFLIB_CALL * const PDF_translate)(PDF *p, float tx, float ty); + void (PDFLIB_CALL * const PDF_scale)(PDF *p, float sx, float sy); + void (PDFLIB_CALL * const PDF_rotate)(PDF *p, float phi); + void (PDFLIB_CALL * const PDF_skew)(PDF *p, float alpha, float beta); + void (PDFLIB_CALL * const PDF_concat)(PDF *p, float a, float b, + float c, float d, float e, float f); + void (PDFLIB_CALL * const PDF_setmatrix)(PDF *p, float a, float b, + float c, float d, float e, float f); + + /* path construction, painting, and clipping */ + void (PDFLIB_CALL * const PDF_moveto)(PDF *p, float x, float y); + void (PDFLIB_CALL * const PDF_lineto)(PDF *p, float x, float y); + void (PDFLIB_CALL * const PDF_curveto)(PDF *p, float x1, float y1, + float x2, float y2, float x3, float y3); + void (PDFLIB_CALL * const PDF_circle)(PDF *p, float x, float y, float r); + void (PDFLIB_CALL * const PDF_arc)(PDF *p, float x, float y, + float r, float alpha, float beta); + void (PDFLIB_CALL * const PDF_arcn)(PDF *p, float x, float y, + float r, float alpha, float beta); + void (PDFLIB_CALL * const PDF_rect)(PDF *p, float x, float y, + float width, float height); + void (PDFLIB_CALL * const PDF_closepath)(PDF *p); + void (PDFLIB_CALL * const PDF_stroke)(PDF *p); + void (PDFLIB_CALL * const PDF_closepath_stroke)(PDF *p); + void (PDFLIB_CALL * const PDF_fill)(PDF *p); + void (PDFLIB_CALL * const PDF_fill_stroke)(PDF *p); + void (PDFLIB_CALL * const PDF_closepath_fill_stroke)(PDF *p); + void (PDFLIB_CALL * const PDF_endpath)(PDF *p); + void (PDFLIB_CALL * const PDF_clip)(PDF *p); + + /* color handling */ + void (PDFLIB_CALL * const PDF_setgray_fill)(PDF *p, float gray); + void (PDFLIB_CALL * const PDF_setgray_stroke)(PDF *p, float gray); + void (PDFLIB_CALL * const PDF_setgray)(PDF *p, float gray); + void (PDFLIB_CALL * const PDF_setrgbcolor_fill)(PDF *p, + float red, float green, float blue); + void (PDFLIB_CALL * const PDF_setrgbcolor_stroke)(PDF *p, + float red, float green, float blue); + void (PDFLIB_CALL * const PDF_setrgbcolor)(PDF *p, float red, float green, + float blue); + int (PDFLIB_CALL * const PDF_makespotcolor)(PDF *p, const char *spotname, + int len); + void (PDFLIB_CALL * const PDF_setcolor)(PDF *p, + const char *fstype, const char *colorspace, + float c1, float c2, float c3, float c4); + + /* pattern definition */ + int (PDFLIB_CALL * const PDF_begin_pattern)(PDF *p, + float width, float height, + float xstep, float ystep, int painttype); + void (PDFLIB_CALL * const PDF_end_pattern)(PDF *p); + + /* template definition */ + int (PDFLIB_CALL * const PDF_begin_template)(PDF *p, + float width, float height); + void (PDFLIB_CALL * const PDF_end_template)(PDF *p); + + /* image handling */ + void (PDFLIB_CALL * const PDF_place_image)(PDF *p, int image, + float x, float y, float scale); + int (PDFLIB_CALL * const PDF_open_image)(PDF *p, const char *imagetype, + const char *source, const char *data, long length, int width, + int height, int components, int bpc, const char *params); + int (PDFLIB_CALL * const PDF_open_image_file)(PDF *p, const char *imagetype, + const char *filename, const char *stringparam, int intparam); + void (PDFLIB_CALL * const PDF_close_image)(PDF *p, int image); + void (PDFLIB_CALL * const PDF_add_thumbnail)(PDF *p, int image); + + /* fax-compressed data processing */ + int (PDFLIB_CALL * const PDF_open_CCITT)(PDF *p, const char *filename, + int width, int height, + int BitReverse, int K, int BlackIs1); + + /* bookmarks and document info fields */ + int (PDFLIB_CALL * const PDF_add_bookmark)(PDF *p, + const char *text, int parent, int open); + void (PDFLIB_CALL * const PDF_set_info)(PDF *p, + const char *key, const char *value); + + /* file attachments, notes, and links */ + void (PDFLIB_CALL * const PDF_attach_file)(PDF *p, float llx, float lly, + float urx, float ury, const char *filename, + const char *description, + const char *author, const char *mimetype, const char *icon); + void (PDFLIB_CALL * const PDF_add_note)(PDF *p, float llx, float lly, + float urx, float ury, const char *contents, const char *title, + const char *icon, int open); + void (PDFLIB_CALL * const PDF_add_pdflink)(PDF *p, + float llx, float lly, float urx, + float ury, const char *filename, int page, const char *dest); + void (PDFLIB_CALL * const PDF_add_launchlink)(PDF *p, + float llx, float lly, float urx, + float ury, const char *filename); + void (PDFLIB_CALL * const PDF_add_locallink)(PDF *p, + float llx, float lly, float urx, + float ury, int page, const char *dest); + void (PDFLIB_CALL * const PDF_add_weblink)(PDF *p, + float llx, float lly, float urx, float ury, const char *url); + void (PDFLIB_CALL * const PDF_set_border_style)(PDF *p, + const char *style, float width); + void (PDFLIB_CALL * const PDF_set_border_color)(PDF *p, + float red, float green, float blue); + void (PDFLIB_CALL * const PDF_set_border_dash)(PDF *p, float b, float w); + + /* PDF import (requires the PDI library) */ + int (PDFLIB_CALL * const PDF_open_pdi)(PDF *p, const char *filename, + const char *stringparam, int intparam); + void (PDFLIB_CALL * const PDF_close_pdi)(PDF *p, int doc); + int (PDFLIB_CALL * const PDF_open_pdi_page)(PDF *p, + int doc, int page, const char *label); + void (PDFLIB_CALL * const PDF_place_pdi_page)(PDF *p, int page, + float x, float y, float sx, float sy); + void (PDFLIB_CALL * const PDF_close_pdi_page)(PDF *p, int page); + const char * (PDFLIB_CALL * const PDF_get_pdi_parameter)(PDF *p, + const char *key, int doc, int page, int index, int *len); + float (PDFLIB_CALL * const PDF_get_pdi_value)(PDF *p, const char *key, + int doc, int page, int index); + + /* output stream handling */ + const char * (PDFLIB_CALL * const PDF_get_buffer)(PDF *p, long *size); + + /* this is considered private */ + void *handle; +}; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#if defined(__MWERKS__) && defined(PDFLIB_EXPORTS) +#pragma export off +#endif + +#endif /* PDFLIB_H */ diff --git a/src/add-ons/print/drivers/pdf/source/unicode0.h b/src/add-ons/print/drivers/pdf/source/unicode0.h new file mode 100644 index 0000000000..2bdaac5174 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/unicode0.h @@ -0,0 +1,260 @@ +// WARNING: MACHINE GENERATED DON'T CHANGE! +static uint16 unicode0[] = { +0x20, +0x21, +0x22, +0x23, +0x24, +0x25, +0x26, +0x27, +0x28, +0x29, +0x2a, +0x2b, +0x2c, +0x2d, +0x2e, +0x2f, +0x30, +0x31, +0x32, +0x33, +0x34, +0x35, +0x36, +0x37, +0x38, +0x39, +0x3a, +0x3b, +0x3c, +0x3d, +0x3e, +0x3f, +0x40, +0x41, +0x42, +0x43, +0x44, +0x45, +0x46, +0x47, +0x48, +0x49, +0x4a, +0x4b, +0x4c, +0x4d, +0x4e, +0x4f, +0x50, +0x51, +0x52, +0x53, +0x54, +0x55, +0x56, +0x57, +0x58, +0x59, +0x5a, +0x5b, +0x5c, +0x5d, +0x5e, +0x5f, +0x60, +0x61, +0x62, +0x63, +0x64, +0x65, +0x66, +0x67, +0x68, +0x69, +0x6a, +0x6b, +0x6c, +0x6d, +0x6e, +0x6f, +0x70, +0x71, +0x72, +0x73, +0x74, +0x75, +0x76, +0x77, +0x78, +0x79, +0x7a, +0x7b, +0x7c, +0x7d, +0x7e, +0xa0, +0xa1, +0xa2, +0xa3, +0xa4, +0xa5, +0xa6, +0xa7, +0xa8, +0xa9, +0xaa, +0xab, +0xac, +0xad, +0xae, +0xaf, +0xb0, +0xb1, +0xb2, +0xb3, +0xb4, +0xb5, +0xb6, +0xb7, +0xb8, +0xb9, +0xba, +0xbb, +0xbc, +0xbd, +0xbe, +0xbf, +0xc0, +0xc1, +0xc2, +0xc3, +0xc4, +0xc5, +0xc6, +0xc7, +0xc8, +0xc9, +0xca, +0xcb, +0xcc, +0xcd, +0xce, +0xcf, +0xd0, +0xd1, +0xd2, +0xd3, +0xd4, +0xd5, +0xd6, +0xd7, +0xd8, +0xd9, +0xda, +0xdb, +0xdc, +0xdd, +0xde, +0xdf, +0xe0, +0xe1, +0xe2, +0xe3, +0xe4, +0xe5, +0xe6, +0xe7, +0xe8, +0xe9, +0xea, +0xeb, +0xec, +0xed, +0xee, +0xef, +0xf0, +0xf1, +0xf2, +0xf3, +0xf4, +0xf5, +0xf6, +0xf7, +0xf8, +0xf9, +0xfa, +0xfb, +0xfc, +0xfd, +0xfe, +0xff, +0x100, +0x101, +0x102, +0x103, +0x104, +0x105, +0x106, +0x107, +0x108, +0x109, +0x10a, +0x10b, +0x10c, +0x10d, +0x10e, +0x10f, +0x110, +0x111, +0x112, +0x113, +0x114, +0x115, +0x116, +0x117, +0x118, +0x119, +0x11a, +0x11b, +0x11c, +0x11d, +0x11e, +0x11f, +0x120, +0x121, +0x122, +0x123, +0x124, +0x125, +0x126, +0x127, +0x128, +0x129, +0x12a, +0x12b, +0x12c, +0x12d, +0x12e, +0x12f, +0x130, +0x131, +0x132, +0x133, +0x134, +0x135, +0x136, +0x137, +0x138, +0x139, +0x13a, +0x13b, +0x13c, +0x13d, +0x13e, +0x13f, +0x140 +}; + diff --git a/src/add-ons/print/drivers/pdf/source/unicode1.h b/src/add-ons/print/drivers/pdf/source/unicode1.h new file mode 100644 index 0000000000..ae7e073e16 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/unicode1.h @@ -0,0 +1,260 @@ +// WARNING: MACHINE GENERATED DON'T CHANGE! +static uint16 unicode1[] = { +0x141, +0x142, +0x143, +0x144, +0x145, +0x146, +0x147, +0x148, +0x149, +0x14a, +0x14b, +0x14c, +0x14d, +0x14e, +0x14f, +0x150, +0x151, +0x152, +0x153, +0x154, +0x155, +0x156, +0x157, +0x158, +0x159, +0x15a, +0x15b, +0x15c, +0x15d, +0x15e, +0x15f, +0x160, +0x161, +0x162, +0x163, +0x164, +0x165, +0x166, +0x167, +0x168, +0x169, +0x16a, +0x16b, +0x16c, +0x16d, +0x16e, +0x16f, +0x170, +0x171, +0x172, +0x173, +0x174, +0x175, +0x176, +0x177, +0x178, +0x179, +0x17a, +0x17b, +0x17c, +0x17d, +0x17e, +0x17f, +0x192, +0x1a0, +0x1a1, +0x1af, +0x1b0, +0x1e6, +0x1e7, +0x1fa, +0x1fb, +0x1fc, +0x1fd, +0x1fe, +0x1ff, +0x218, +0x219, +0x21a, +0x21b, +0x2bc, +0x2bd, +0x2c6, +0x2c7, +0x2c9, +0x2d8, +0x2d9, +0x2da, +0x2db, +0x2dc, +0x2dd, +0x300, +0x301, +0x303, +0x309, +0x323, +0x384, +0x385, +0x386, +0x387, +0x388, +0x389, +0x38a, +0x38c, +0x38e, +0x38f, +0x390, +0x391, +0x392, +0x393, +0x394, +0x395, +0x396, +0x397, +0x398, +0x399, +0x39a, +0x39b, +0x39c, +0x39d, +0x39e, +0x39f, +0x3a0, +0x3a1, +0x3a3, +0x3a4, +0x3a5, +0x3a6, +0x3a7, +0x3a8, +0x3a9, +0x3aa, +0x3ab, +0x3ac, +0x3ad, +0x3ae, +0x3af, +0x3b0, +0x3b1, +0x3b2, +0x3b3, +0x3b4, +0x3b5, +0x3b6, +0x3b7, +0x3b8, +0x3b9, +0x3ba, +0x3bb, +0x3bc, +0x3bd, +0x3be, +0x3bf, +0x3c0, +0x3c1, +0x3c2, +0x3c3, +0x3c4, +0x3c5, +0x3c6, +0x3c7, +0x3c8, +0x3c9, +0x3ca, +0x3cb, +0x3cc, +0x3cd, +0x3ce, +0x3d1, +0x3d2, +0x3d5, +0x3d6, +0x401, +0x402, +0x403, +0x404, +0x405, +0x406, +0x407, +0x408, +0x409, +0x40a, +0x40b, +0x40c, +0x40e, +0x40f, +0x410, +0x411, +0x412, +0x413, +0x414, +0x415, +0x416, +0x417, +0x418, +0x419, +0x41a, +0x41b, +0x41c, +0x41d, +0x41e, +0x41f, +0x420, +0x421, +0x422, +0x423, +0x424, +0x425, +0x426, +0x427, +0x428, +0x429, +0x42a, +0x42b, +0x42c, +0x42d, +0x42e, +0x42f, +0x430, +0x431, +0x432, +0x433, +0x434, +0x435, +0x436, +0x437, +0x438, +0x439, +0x43a, +0x43b, +0x43c, +0x43d, +0x43e, +0x43f, +0x440, +0x441, +0x442, +0x443, +0x444, +0x445, +0x446, +0x447, +0x448, +0x449, +0x44a, +0x44b, +0x44c, +0x44d, +0x44e, +0x44f, +0x451, +0x452, +0x453, +0x454, +0x455, +0x456 +}; + diff --git a/src/add-ons/print/drivers/pdf/source/unicode2.h b/src/add-ons/print/drivers/pdf/source/unicode2.h new file mode 100644 index 0000000000..f13eebd3ae --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/unicode2.h @@ -0,0 +1,260 @@ +// WARNING: MACHINE GENERATED DON'T CHANGE! +static uint16 unicode2[] = { +0x457, +0x458, +0x459, +0x45a, +0x45b, +0x45c, +0x45e, +0x45f, +0x462, +0x463, +0x472, +0x473, +0x474, +0x475, +0x490, +0x491, +0x4d9, +0x5b0, +0x5b1, +0x5b2, +0x5b3, +0x5b4, +0x5b5, +0x5b6, +0x5b7, +0x5b8, +0x5b9, +0x5bb, +0x5bc, +0x5bd, +0x5be, +0x5bf, +0x5c0, +0x5c1, +0x5c2, +0x5c3, +0x5d0, +0x5d1, +0x5d2, +0x5d3, +0x5d4, +0x5d5, +0x5d6, +0x5d7, +0x5d8, +0x5d9, +0x5da, +0x5db, +0x5dc, +0x5dd, +0x5de, +0x5df, +0x5e0, +0x5e1, +0x5e2, +0x5e3, +0x5e4, +0x5e5, +0x5e6, +0x5e7, +0x5e8, +0x5e9, +0x5ea, +0x5f0, +0x5f1, +0x5f2, +0x60c, +0x61b, +0x61f, +0x621, +0x622, +0x623, +0x624, +0x625, +0x626, +0x627, +0x628, +0x629, +0x62a, +0x62b, +0x62c, +0x62d, +0x62e, +0x62f, +0x630, +0x631, +0x632, +0x633, +0x634, +0x635, +0x636, +0x637, +0x638, +0x639, +0x63a, +0x640, +0x641, +0x642, +0x643, +0x644, +0x645, +0x646, +0x647, +0x648, +0x649, +0x64a, +0x64b, +0x64c, +0x64d, +0x64e, +0x64f, +0x650, +0x651, +0x652, +0x660, +0x661, +0x662, +0x663, +0x664, +0x665, +0x666, +0x667, +0x668, +0x669, +0x66a, +0x66d, +0x679, +0x67e, +0x686, +0x688, +0x691, +0x698, +0x6a4, +0x6af, +0x6ba, +0x6d2, +0x6d5, +0x1e80, +0x1e81, +0x1e82, +0x1e83, +0x1e84, +0x1e85, +0x1ef2, +0x1ef3, +0x200c, +0x200d, +0x200e, +0x200f, +0x2012, +0x2013, +0x2014, +0x2015, +0x2017, +0x2018, +0x2019, +0x201a, +0x201b, +0x201c, +0x201d, +0x201e, +0x2020, +0x2021, +0x2022, +0x2024, +0x2025, +0x2026, +0x202c, +0x202d, +0x202e, +0x2030, +0x2032, +0x2033, +0x2039, +0x203a, +0x203c, +0x2044, +0x2070, +0x2074, +0x2075, +0x2076, +0x2077, +0x2078, +0x2079, +0x207d, +0x207e, +0x207f, +0x2080, +0x2081, +0x2082, +0x2083, +0x2084, +0x2085, +0x2086, +0x2087, +0x2088, +0x2089, +0x208d, +0x208e, +0x20a1, +0x20a3, +0x20a4, +0x20a7, +0x20aa, +0x20ab, +0x20ac, +0x2105, +0x2111, +0x2113, +0x2116, +0x2118, +0x211c, +0x211e, +0x2122, +0x2126, +0x212e, +0x2135, +0x2153, +0x2154, +0x215b, +0x215c, +0x215d, +0x215e, +0x2190, +0x2191, +0x2192, +0x2193, +0x2194, +0x2195, +0x21a8, +0x21b5, +0x21d0, +0x21d1, +0x21d2, +0x21d3, +0x21d4, +0x2200, +0x2202, +0x2203, +0x2205, +0x2206, +0x2207, +0x2208, +0x2209, +0x220b, +0x220f, +0x2211, +0x2212, +0x2215, +0x2217, +0x2219, +0x221a, +0x221d, +0x221e, +0x221f, +0x2220 +}; + diff --git a/src/add-ons/print/drivers/pdf/source/unicode3.h b/src/add-ons/print/drivers/pdf/source/unicode3.h new file mode 100644 index 0000000000..55f5364135 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/unicode3.h @@ -0,0 +1,260 @@ +// WARNING: MACHINE GENERATED DON'T CHANGE! +static uint16 unicode3[] = { +0x2227, +0x2228, +0x2229, +0x222a, +0x222b, +0x2234, +0x223c, +0x2245, +0x2248, +0x2260, +0x2261, +0x2264, +0x2265, +0x2282, +0x2283, +0x2284, +0x2286, +0x2287, +0x2295, +0x2297, +0x22a5, +0x22c5, +0x2302, +0x2310, +0x2320, +0x2321, +0x2329, +0x232a, +0x2500, +0x2502, +0x250c, +0x2510, +0x2514, +0x2518, +0x251c, +0x2524, +0x252c, +0x2534, +0x253c, +0x2550, +0x2551, +0x2552, +0x2553, +0x2554, +0x2555, +0x2556, +0x2557, +0x2558, +0x2559, +0x255a, +0x255b, +0x255c, +0x255d, +0x255e, +0x255f, +0x2560, +0x2561, +0x2562, +0x2563, +0x2564, +0x2565, +0x2566, +0x2567, +0x2568, +0x2569, +0x256a, +0x256b, +0x256c, +0x2580, +0x2584, +0x2588, +0x258c, +0x2590, +0x2591, +0x2592, +0x2593, +0x25a0, +0x25a1, +0x25aa, +0x25ab, +0x25ac, +0x25b2, +0x25ba, +0x25bc, +0x25c4, +0x25ca, +0x25cb, +0x25cf, +0x25d8, +0x25d9, +0x25e6, +0x263a, +0x263b, +0x263c, +0x2640, +0x2642, +0x2660, +0x2663, +0x2665, +0x2666, +0x266a, +0x266b, +0xf6be, +0xf6bf, +0xf6c0, +0xf6c1, +0xf6c2, +0xf6c3, +0xf6c4, +0xf6c5, +0xf6c6, +0xf6c7, +0xf6c8, +0xf6c9, +0xf6ca, +0xf6cb, +0xf6cc, +0xf6cd, +0xf6ce, +0xf6cf, +0xf6d0, +0xf6d1, +0xf6d2, +0xf6d3, +0xf6d4, +0xf6d5, +0xf6d6, +0xf6d7, +0xf6d8, +0xf6d9, +0xf6da, +0xf6db, +0xf6dc, +0xf6dd, +0xf6de, +0xf6df, +0xf6e0, +0xf6e1, +0xf6e2, +0xf6e3, +0xf6e4, +0xf6e5, +0xf6e6, +0xf6e7, +0xf6e8, +0xf6e9, +0xf6ea, +0xf6eb, +0xf6ec, +0xf6ed, +0xf6ee, +0xf6ef, +0xf6f0, +0xf6f1, +0xf6f2, +0xf6f3, +0xf6f4, +0xf6f5, +0xf6f6, +0xf6f7, +0xf6f8, +0xf6f9, +0xf6fa, +0xf6fb, +0xf6fc, +0xf6fd, +0xf6fe, +0xf6ff, +0xf721, +0xf724, +0xf726, +0xf730, +0xf731, +0xf732, +0xf733, +0xf734, +0xf735, +0xf736, +0xf737, +0xf738, +0xf739, +0xf73f, +0xf760, +0xf761, +0xf762, +0xf763, +0xf764, +0xf765, +0xf766, +0xf767, +0xf768, +0xf769, +0xf76a, +0xf76b, +0xf76c, +0xf76d, +0xf76e, +0xf76f, +0xf770, +0xf771, +0xf772, +0xf773, +0xf774, +0xf775, +0xf776, +0xf777, +0xf778, +0xf779, +0xf77a, +0xf7a1, +0xf7a2, +0xf7a8, +0xf7af, +0xf7b4, +0xf7b8, +0xf7bf, +0xf7e0, +0xf7e1, +0xf7e2, +0xf7e3, +0xf7e4, +0xf7e5, +0xf7e6, +0xf7e7, +0xf7e8, +0xf7e9, +0xf7ea, +0xf7eb, +0xf7ec, +0xf7ed, +0xf7ee, +0xf7ef, +0xf7f0, +0xf7f1, +0xf7f2, +0xf7f3, +0xf7f4, +0xf7f5, +0xf7f6, +0xf7f8, +0xf7f9, +0xf7fa, +0xf7fb, +0xf7fc, +0xf7fd, +0xf7fe, +0xf7ff, +0xf8e5, +0xf8e6, +0xf8e7, +0xf8e8, +0xf8e9, +0xf8ea, +0xf8eb, +0xf8ec, +0xf8ed +}; + diff --git a/src/add-ons/print/drivers/pdf/source/unicode4.h b/src/add-ons/print/drivers/pdf/source/unicode4.h new file mode 100644 index 0000000000..edd8a58478 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/source/unicode4.h @@ -0,0 +1,31 @@ +// WARNING: MACHINE GENERATED DON'T CHANGE! +static uint16 unicode4[] = { +0xf8ee, +0xf8ef, +0xf8f0, +0xf8f1, +0xf8f2, +0xf8f3, +0xf8f4, +0xf8f5, +0xf8f6, +0xf8f7, +0xf8f8, +0xf8f9, +0xf8fa, +0xf8fb, +0xf8fc, +0xf8fd, +0xf8fe, +0xfb00, +0xfb01, +0xfb02, +0xfb03, +0xfb04, +0xfb1f, +0xfb2a, +0xfb2b, +0xfb35, +0xfb4b +}; + diff --git a/src/add-ons/print/drivers/pdf/xrefs/Deutsch b/src/add-ons/print/drivers/pdf/xrefs/Deutsch new file mode 100644 index 0000000000..c2240928a7 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/xrefs/Deutsch @@ -0,0 +1,7 @@ +CrossReferences 1.0 +"[sS]iehe Tabelle ([0-9]+ )" -> "Tabelle ([0-9]+)". + +"[sS]iehe Abbildung ([0-9]+ )", "[sS]iehe Abb. ([0-9]+ )" +-> +"Abbildung ([0-9]+)", "Abb. ([0-9]+ )". + diff --git a/src/add-ons/print/drivers/pdf/xrefs/English b/src/add-ons/print/drivers/pdf/xrefs/English new file mode 100644 index 0000000000..23f1ff8a66 --- /dev/null +++ b/src/add-ons/print/drivers/pdf/xrefs/English @@ -0,0 +1,18 @@ +CrossReferences 1.0 +# Table +"[sS]ee [tT]able ([0-9]+)", "see [tT]bl. ([0-9]+)" + -> +"[tT]able ([0-9]+)", "[tT]bl. ([0-9]+)". + +# Figure +"[sS]ee [fF]igure ([0-9]+)", "[sS]ee [fF]ig. ([0-9]+)" + -> +"[fF]igure ([0-9]+)", "[fF]ig. ([0-9]+)". + +# Page, Table of contents +"[pP]age ([0-9]+)" + -> +"- ?([0-9]+) ?-". + +# Cite +". \[([a-zA-Z0-9]+)\]" -> "\[([a-zA-Z0-9]+)\]". diff --git a/src/add-ons/print/transports/ipp/HttpURLConnection.cpp b/src/add-ons/print/transports/ipp/HttpURLConnection.cpp new file mode 100644 index 0000000000..d34f5bf242 --- /dev/null +++ b/src/add-ons/print/transports/ipp/HttpURLConnection.cpp @@ -0,0 +1,327 @@ +// Sun, 18 Jun 2000 +// Y.Takagi + +#include +#include +#include + +#ifdef WIN32 +#include +#else +#define stricmp strcasecmp +#endif + +#include "HttpURLConnection.h" +#include "Socket.h" + +using namespace std; + +#define DEFAULT_PORT 80; + +Field::Field(char *field) +{ + char *p = strtok(field, ": \t\r\n"); + key = p ? p : ""; + p = strtok(NULL, " \t\r\n"); + value = p ? p : ""; +} + +Field::Field(const char *k, const char *v) +{ + key = k ? k : ""; + value = v ? v : ""; +} + +Field::Field(const Field &o) +{ + key = o.key; + value = o.value; +} + +Field &Field::operator = (const Field &o) +{ + key = o.key; + value = o.value; + return *this; +} + +bool Field::operator == (const Field &o) +{ + return (key == o.key) && (value == o.value); +} + +HttpURLConnection::HttpURLConnection(const URL &Url) + : connected(false), doInput(true), doOutput(false), url(Url) +{ + __sock = NULL; + __method = "GET"; + __request = NULL; + __response = NULL; + __response_code = HTTP_UNKNOWN; +} + +HttpURLConnection::~HttpURLConnection() +{ + disconnect(); + + if (__sock) { + delete __sock; + } + + if (__request) { + delete __request; + } + + if (__response) { + delete __response; + } +} + +void HttpURLConnection::disconnect() +{ + if (connected) { + connected = false; + __sock->close(); + } +} + +const char *HttpURLConnection::getRequestMethod() const +{ + return __method.c_str(); +} + +void HttpURLConnection::setRequestMethod(const char *method) +{ + __method = method; +} + +void HttpURLConnection::setRequestProperty(const char *key, const char *value) +{ + if (__request == NULL) { + __request = new Fields; + } + __request->push_back(Field(key, value)); +} + +istream &HttpURLConnection::getInputStream() +{ + if (!connected) { + connect(); + setRequest(); + } + return __sock->getInputStream(); +} + +ostream &HttpURLConnection::getOutputStream() +{ + if (!connected) { + connect(); + } + return __sock->getOutputStream(); +} + +void HttpURLConnection::setDoInput(bool doinput) +{ + doinput = doinput; +} + +void HttpURLConnection::setDoOutput(bool dooutput) +{ + dooutput = dooutput; +} + +void HttpURLConnection::connect() +{ + if (!connected) { + int port = url.getPort(); + if (port < 0) { + const char *protocol = url.getProtocol(); + if (!stricmp(protocol, "http")) { + port = DEFAULT_PORT; + } else if (!stricmp(protocol, "ipp")) { + port = 631; + } else { + port = DEFAULT_PORT; + } + } + __sock = new Socket(url.getHost(), port); + if (__sock->fail()) { + __error_msg = __sock->getLastError(); + } else { + connected = true; + } + } +} + +const char *HttpURLConnection::getContentType() +{ + return getHeaderField("Content-Type"); +} + +const char *HttpURLConnection::getContentEncoding() +{ + return getHeaderField("Content-Encoding"); +} + +int HttpURLConnection::getContentLength() +{ + const char *p = getHeaderField("Content-Length"); + return p ? atoi(p) : -1; +} + +const char *HttpURLConnection::getHeaderField(const char *s) +{ + if (__response == NULL) { + action(); + } + if (__response) { + for (Fields::iterator it = __response->begin(); it != __response->end(); it++) { + if ((*it).key == s) { + return (*it).value.c_str(); + } + } + } + return NULL; +} + +HTTP_RESPONSECODE HttpURLConnection::getResponseCode() +{ + if (__response == NULL) { + action(); + } + return __response_code; +} + +const char *HttpURLConnection::getResponseMessage() +{ + if (__response == NULL) { + action(); + } + return __response_message.c_str(); +} + +void HttpURLConnection::action() +{ + if (!connected) { + connect(); + } + if (connected) { + setRequest(); + } + if (connected) { + getResponse(); + } +} + +void HttpURLConnection::setRequest() +{ + if (connected) { + setRequestProperty("Host", url.getHost()); + ostream &os = getOutputStream(); + os << __method << ' ' << url.getFile() << " HTTP/1.1" << '\r' << '\n'; + for (Fields::iterator it = __request->begin(); it != __request->end(); it++) { + os << (*it).key << ": " << (*it).value << '\r' << '\n'; + } + os << '\r' << '\n'; + + setContent(); + + if (!doOutput) { + os.flush(); + } + + if (__response) { + delete __response; + __response = NULL; + } + } +} + +void HttpURLConnection::setContent() +{ +} + +void HttpURLConnection::getResponse() +{ + if (connected) { + + if (__response == NULL) { + __response = new Fields; + + istream &is = getInputStream(); + + char buffer[1024]; + + if (!is.getline(buffer, sizeof(buffer))) { + __error_msg = __sock->getLastError(); + return; + } + buffer[is.gcount() - 2] = '\0'; + __response_message = buffer; + strtok(buffer, " "); + char *p = strtok(NULL, " "); + __response_code = p ? (HTTP_RESPONSECODE)atoi(p) : HTTP_UNKNOWN; + + while (is.getline(buffer, sizeof(buffer))) { + if (buffer[0] == '\r') { + break; + } + buffer[is.gcount() - 2] = '\0'; + __response->push_back(Field(buffer)); + } + + int size = getContentLength(); + if (size > 0) { + getContent(); + } + + if (__response_code != HTTP_CONTINUE) { + const char *s = getHeaderField("Connection"); + if (s == NULL) { + connected = false; + __error_msg = "cannot found \"Connection\" field"; + } else if (stricmp(s, "Keep-Alive")) { + connected = false; + } + } + + switch (__response_code) { + case HTTP_MOVED_TEMP: + { + const char *p = getHeaderField("Location"); + if (p) { + URL trueUrl(p); + url = trueUrl; + delete __response; + __response = NULL; + action(); + } + } + break; + case HTTP_CONTINUE: + delete __response; + __response = NULL; + getResponse(); + break; + default: + break; + } + } + } +} + +void HttpURLConnection::getContent() +{ + const int maxBufSize = 1024; + if (connected) { + int size = getContentLength(); + if (size > 0) { + istream &is = getInputStream(); + int bufsize = min(size, maxBufSize); + char buf[maxBufSize]; + while (size > 0 && is.read(buf, bufsize)) { + size -= bufsize; + } + } + } +} diff --git a/src/add-ons/print/transports/ipp/HttpURLConnection.h b/src/add-ons/print/transports/ipp/HttpURLConnection.h new file mode 100644 index 0000000000..02cdf69dee --- /dev/null +++ b/src/add-ons/print/transports/ipp/HttpURLConnection.h @@ -0,0 +1,148 @@ +// Sun, 18 Jun 2000 +// Y.Takagi + +#ifndef __HttpURLConnection_H +#define __HttpURLConnection_H + +#ifdef WIN32 +#include +#include +#else +#include +#include +#endif + +#include +#include + +#include "URL.h" + +using namespace std; + +class Socket; + +enum HTTP_RESPONSECODE { + HTTP_UNKNOWN = -1, // + + HTTP_CONTINUE = 100, // Everything OK, keep going... + HTTP_SWITCH_PROC = 101, // Switching Protocols + + HTTP_OK = 200, // OPTIONS/GET/HEAD/POST/TRACE command was successful + HTTP_CREATED, // PUT command was successful + HTTP_ACCEPTED, // DELETE command was successful + HTTP_NOT_AUTHORITATIVE, // Information isn't authoritative + HTTP_NO_CONTENT, // Successful command, no new data + HTTP_RESET, // Content was reset/recreated + HTTP_PARTIAL, // Only a partial file was recieved/sent + + HTTP_MULTI_CHOICE = 300, // Multiple files match request + HTTP_MOVED_PERM, // Document has moved permanently + HTTP_MOVED_TEMP, // Document has moved temporarily + HTTP_SEE_OTHER, // See this other link... + HTTP_NOT_MODIFIED, // File not modified + HTTP_USE_PROXY, // Must use a proxy to access this URI + + HTTP_BAD_REQUEST = 400, // Bad request + HTTP_UNAUTHORIZED, // Unauthorized to access host + HTTP_PAYMENT_REQUIRED, // Payment required + HTTP_FORBIDDEN, // Forbidden to access this URI + HTTP_NOT_FOUND, // URI was not found + HTTP_BAD_METHOD, // Method is not allowed + HTTP_NOT_ACCEPTABLE, // Not Acceptable + HTTP_PROXY_AUTH, // Proxy Authentication is Required + HTTP_REQUEST_TIMEOUT, // Request timed out + HTTP_CONFLICT, // Request is self-conflicting + HTTP_GONE, // Server has gone away + HTTP_LENGTH_REQUIRED, // A content length or encoding is required + HTTP_PRECON_FAILED, // Precondition failed + HTTP_ENTITY_TOO_LARGE, // URI too long + HTTP_REQ_TOO_LONG, // Request entity too large + HTTP_UNSUPPORTED_TYPE, // The requested media type is unsupported + + HTTP_SERVER_ERROR = 500, // Internal server error + HTTP_INTERNAL_ERROR, // Feature not implemented + HTTP_BAD_GATEWAY, // Bad gateway + HTTP_UNAVAILABLE, // Service is unavailable + HTTP_GATEWAY_TIMEOUT, // Gateway connection timed out + HTTP_VERSION // HTTP version not supported +}; + +struct Field { + string key; + string value; + Field() {} + Field(char *field); + Field(const char *k, const char *v); + Field(const Field &); + Field &operator = (const Field &); + bool operator == (const Field &); +}; + +typedef list Fields; + +class HttpURLConnection { +public: + HttpURLConnection(const URL &url); + virtual ~HttpURLConnection(); + + virtual void connect(); + void disconnect(); + + void setRequestMethod(const char *method); + const char *getRequestMethod() const; + void setRequestProperty(const char *key, const char *value); + + const char *getContentType(); + const char *getContentEncoding(); + int getContentLength(); + long getDate(); + const char *getHeaderField(int n); + const char *getHeaderField(const char *); + const URL &getURL() const; + HTTP_RESPONSECODE getResponseCode(); + const char *getResponseMessage(); + + bool getDoInput() const; + bool getDoOutput() const; + void setDoInput(bool doinput); + void setDoOutput(bool dooutput); + + istream &getInputStream(); + ostream &getOutputStream(); + + const char *getLastError() const; + void setLastError(const char *); + +protected: + bool connected; + bool doInput; + bool doOutput; + URL url; + + virtual void action(); + virtual void setRequest(); + virtual void setContent(); + virtual void getResponse(); + virtual void getContent(); + +private: + Fields *__request; + Fields *__response; + Socket *__sock; + string __method; + string __response_message; + HTTP_RESPONSECODE __response_code; + string __error_msg; +}; + +inline const char *HttpURLConnection::getLastError() const +{ + return __error_msg.c_str(); +} + +inline void HttpURLConnection::setLastError(const char *e) +{ + __error_msg = e; +} + +#endif // __HttpURLConnection_H diff --git a/src/add-ons/print/transports/ipp/Ipp.cpp b/src/add-ons/print/transports/ipp/Ipp.cpp new file mode 100644 index 0000000000..a992716a06 --- /dev/null +++ b/src/add-ons/print/transports/ipp/Ipp.cpp @@ -0,0 +1,31 @@ +// Sun, 18 Jun 2000 +// Y.Takagi + +#include "IppTransport.h" +#include "DbgMsg.h" + +IppTransport *transport = NULL; + +extern "C" _EXPORT void exit_transport() +{ + DBGMSG(("> exit_transport\n")); + if (transport) { + delete transport; + transport = NULL; + } + DBGMSG(("< exit_transport\n")); +} + +extern "C" _EXPORT BDataIO *init_transport(BMessage *msg) +{ + DBGMSG(("> init_transport\n")); + + transport = new IppTransport(msg); + + if (transport->fail()) { + exit_transport(); + } + + DBGMSG(("< init_transport\n")); + return transport; +} diff --git a/src/add-ons/print/transports/ipp/IppContent.cpp b/src/add-ons/print/transports/ipp/IppContent.cpp new file mode 100644 index 0000000000..4b9350a9a7 --- /dev/null +++ b/src/add-ons/print/transports/ipp/IppContent.cpp @@ -0,0 +1,1061 @@ +// Sun, 18 Jun 2000 +// Y.Takagi + +#ifdef WIN32 +#include +#else +#include +#endif + +#include +#include +#include + +#include "IppContent.h" + +/*----------------------------------------------------------------------*/ + +short readLength(istream &is) +{ + short len = 0; + is.read((char *)&len, sizeof(short)); + len = ntohs(len); + return len; +} + +void writeLength(ostream &os, short len) +{ + len = htons(len); + os.write((char *)&len, sizeof(short)); +} + +/*----------------------------------------------------------------------*/ + +DATETIME::DATETIME() +{ + memset(this, 0, sizeof(DATETIME)); +} + +DATETIME::DATETIME(const DATETIME &dt) +{ + memcpy(this, &dt.datetime, sizeof(DATETIME)); +} + +DATETIME & DATETIME::operator = (const DATETIME &dt) +{ + memcpy(this, &dt.datetime, sizeof(DATETIME)); + return *this; +} + +istream& operator >> (istream &is, DATETIME &attr) +{ + return is; +} + +ostream& operator << (ostream &os, const DATETIME &attr) +{ + return os; +} + + +/*----------------------------------------------------------------------*/ + +IppAttribute::IppAttribute(IPP_TAG t) + : tag(t) +{ +} + +int IppAttribute::length() const +{ + return 1; +} + +istream &IppAttribute::input(istream &is) +{ + return is; +} + +ostream &IppAttribute::output(ostream &os) const +{ + os << (unsigned char)tag; + return os; +} + +ostream &IppAttribute::print(ostream &os) const +{ + os << "Tag: " << hex << (int)tag << '\n'; + return os; +} + +/*----------------------------------------------------------------------*/ + +IppNamedAttribute::IppNamedAttribute(IPP_TAG t) + : IppAttribute(t) +{ +} + +IppNamedAttribute::IppNamedAttribute(IPP_TAG t, const char *s) + : IppAttribute(t), name(s ? s : "") +{ +} + +int IppNamedAttribute::length() const +{ + return IppAttribute::length() + 2 + name.length(); +} + +istream &IppNamedAttribute::input(istream &is) +{ + short len = readLength(is); + + if (0 < len) { + char *buffer = new char[len + 1]; + is.read(buffer, len); + buffer[len] = '\0'; + name = buffer; + delete [] buffer; + } + + return is; +} + +ostream &IppNamedAttribute::output(ostream &os) const +{ + IppAttribute::output(os); + + writeLength(os, name.length()); + os << name; + + return os; +} + +ostream &IppNamedAttribute::print(ostream &os) const +{ + IppAttribute::print(os); + os << '\t' << "Name: " << name << '\n'; + return os; +} + +/*----------------------------------------------------------------------*/ + +IppNoValueAttribute::IppNoValueAttribute(IPP_TAG t) + : IppNamedAttribute(t) +{ +} + +IppNoValueAttribute::IppNoValueAttribute(IPP_TAG t, const char *n) + : IppNamedAttribute(t, n) +{ +} + +int IppNoValueAttribute::length() const +{ + return IppAttribute::length() + 2; +} + +istream &IppNoValueAttribute::input(istream &is) +{ + IppNamedAttribute::input(is); + + short len = readLength(is); + + if (0 < len) { + is.seekg(len, ios::cur); + } + + return is; +} + +ostream &IppNoValueAttribute::output(ostream &os) const +{ + IppAttribute::output(os); + + writeLength(os, 0); + + return os; +} + +ostream &IppNoValueAttribute::print(ostream &os) const +{ + return IppNamedAttribute::print(os); +} + +/*----------------------------------------------------------------------*/ + +IppIntegerAttribute::IppIntegerAttribute(IPP_TAG t) + : IppNamedAttribute(t), value(0) +{ +} + +IppIntegerAttribute::IppIntegerAttribute(IPP_TAG t, const char *n, int v) + : IppNamedAttribute(t, n), value(v) +{ +} + +int IppIntegerAttribute::length() const +{ + return IppNamedAttribute::length() + 2 + 4; +} + +istream &IppIntegerAttribute::input(istream &is) +{ + IppNamedAttribute::input(is); + + short len = readLength(is); + + if (0 < len && len <= 4) { + is.read((char *)&value, sizeof(value)); + value = ntohl(value); + } else { + is.seekg(len, ios::cur); + } + + return is; +} + +ostream &IppIntegerAttribute::output(ostream &os) const +{ + IppNamedAttribute::output(os); + + writeLength(os, 4); + unsigned long val = htonl(value); + os.write((char *)&val, sizeof(val)); + return os; +} + +ostream &IppIntegerAttribute::print(ostream &os) const +{ + IppNamedAttribute::print(os); + os << '\t' << "Value: " << dec << value << '\n'; + return os; +} + +/*----------------------------------------------------------------------*/ + +IppBooleanAttribute::IppBooleanAttribute(IPP_TAG t) + : IppNamedAttribute(t), value(false) +{ +} + +IppBooleanAttribute::IppBooleanAttribute(IPP_TAG t, const char *n, bool f) + : IppNamedAttribute(t, n), value(f) +{ +} + +int IppBooleanAttribute::length() const +{ + return IppNamedAttribute::length() + 2 + 1; +} + + +istream &IppBooleanAttribute::input(istream &is) +{ + IppNamedAttribute::input(is); + + short len = readLength(is); + + if (0 < len && len <= 1) { + char c; + is.read((char *)&c, sizeof(c)); + value = c ? true : false; + } else { + is.seekg(len, ios::cur); + } + + return is; +} + +ostream &IppBooleanAttribute::output(ostream &os) const +{ + IppNamedAttribute::output(os); + + writeLength(os, 1); + char c = (char)value; + os.write((char *)&c, sizeof(c)); + + return os; +} + +ostream &IppBooleanAttribute::print(ostream &os) const +{ + IppNamedAttribute::print(os); + os << '\t' << "Value: " << value << '\n'; + return os; +} + +/*----------------------------------------------------------------------*/ + +IppDatetimeAttribute::IppDatetimeAttribute(IPP_TAG t) + : IppNamedAttribute(t) +{ +} + +IppDatetimeAttribute::IppDatetimeAttribute(IPP_TAG t, const char *n, const DATETIME *dt) + : IppNamedAttribute(t, n), datetime(*dt) +{ +} + +int IppDatetimeAttribute::length() const +{ + return IppNamedAttribute::length() + 2 + 11; +} + +istream &IppDatetimeAttribute::input(istream &is) +{ + IppNamedAttribute::input(is); + + short len = readLength(is); + + if (0 < len) { + if (len == 11) { + is >> datetime; + } else { + is.seekg(len, ios::cur); + } + } + + return is; +} + +ostream &IppDatetimeAttribute::output(ostream &os) const +{ + IppNamedAttribute::output(os); + + writeLength(os, 11); + os << datetime; + + return os; +} + +ostream &IppDatetimeAttribute::print(ostream &os) const +{ + IppNamedAttribute::print(os); + os << '\t' << "Value(DateTime): " << datetime << '\n'; + return os; +} + +/*----------------------------------------------------------------------*/ + +IppStringAttribute::IppStringAttribute(IPP_TAG t) + : IppNamedAttribute(t) +{ +} + +IppStringAttribute::IppStringAttribute(IPP_TAG t, const char *n, const char *s) +: IppNamedAttribute(t, n), text(s ? s : "") +{ +} + +int IppStringAttribute::length() const +{ + return IppNamedAttribute::length() + 2 + text.length(); +} + +istream &IppStringAttribute::input(istream &is) +{ + IppNamedAttribute::input(is); + + short len = readLength(is); + + if (0 < len) { + char *buffer = new char[len + 1]; + is.read(buffer, len); + buffer[len] = '\0'; + text = buffer; + delete [] buffer; + } + + return is; +} + +ostream &IppStringAttribute::output(ostream &os) const +{ + IppNamedAttribute::output(os); + + writeLength(os, text.length()); + os << text; + + return os; +} + +ostream &IppStringAttribute::print(ostream &os) const +{ + IppNamedAttribute::print(os); + os << '\t' << "Value: " << text << '\n'; + return os; +} + +/*----------------------------------------------------------------------*/ + +IppDoubleStringAttribute::IppDoubleStringAttribute(IPP_TAG t) + : IppNamedAttribute(t) +{ +} + +IppDoubleStringAttribute::IppDoubleStringAttribute(IPP_TAG t, const char *n, const char *s1, const char *s2) +: IppNamedAttribute(t, n), text1(s1 ? s1 : ""), text2(s2 ? s2 : "") +{ +} + +int IppDoubleStringAttribute::length() const +{ + return IppNamedAttribute::length() + 2 + text1.length() + 2 + text2.length(); +} + +istream &IppDoubleStringAttribute::input(istream &is) +{ + IppNamedAttribute::input(is); + + short len = readLength(is); + + if (0 < len) { + char *buffer = new char[len + 1]; + is.read(buffer, len); + buffer[len] = '\0'; + text1 = buffer; + delete [] buffer; + } + + len = readLength(is); + + if (0 < len) { + char *buffer = new char[len + 1]; + is.read(buffer, len); + buffer[len] = '\0'; + text2 = buffer; + delete [] buffer; + } + + return is; +} + +ostream &IppDoubleStringAttribute::output(ostream &os) const +{ + IppNamedAttribute::output(os); + + writeLength(os, text1.length()); + os << text1; + + writeLength(os, text2.length()); + os << text2; + + return os; +} + +ostream &IppDoubleStringAttribute::print(ostream &os) const +{ + IppNamedAttribute::print(os); + os << '\t' << "Value1: " << text1 << '\n'; + os << '\t' << "Value2: " << text2 << '\n'; + return os; +} + +/*----------------------------------------------------------------------*/ + +IppResolutionAttribute::IppResolutionAttribute(IPP_TAG t) + : IppNamedAttribute(t), xres(0), yres(0), resolution_units((IPP_RESOLUTION_UNITS)0) +{ +} + +IppResolutionAttribute::IppResolutionAttribute(IPP_TAG t, const char *n, int x, int y, IPP_RESOLUTION_UNITS u) + : IppNamedAttribute(t, n), xres(x), yres(y), resolution_units(u) +{ +} + +int IppResolutionAttribute::length() const +{ + return IppNamedAttribute::length() + 2 + 4 + 2 + 4 + 2 + 1; +} + +istream &IppResolutionAttribute::input(istream &is) +{ + IppNamedAttribute::input(is); + + short len = readLength(is); + + if (0 < len && len <= 4) { + is.read((char *)&xres, sizeof(xres)); + xres = ntohl(xres); + } else { + is.seekg(len, ios::cur); + } + + len = readLength(is); + + if (0 < len && len <= 4) { + is.read((char *)&yres, sizeof(yres)); + yres = ntohl(yres); + } else { + is.seekg(len, ios::cur); + } + + len = readLength(is); + + if (len == 1) { + char c; + is.read((char *)&c, sizeof(c)); + resolution_units = (IPP_RESOLUTION_UNITS)c; + } else { + is.seekg(len, ios::cur); + } + + return is; +} + +ostream &IppResolutionAttribute::output(ostream &os) const +{ + IppNamedAttribute::output(os); + + writeLength(os, 4); + unsigned long val = htonl(xres); + os.write((char *)&val, sizeof(val)); + + writeLength(os, 4); + val = htonl(yres); + os.write((char *)&val, sizeof(val)); + + writeLength(os, 1); + unsigned char c = (unsigned char)resolution_units; + os.write((char *)&c, sizeof(c)); + + return os; +} + +ostream &IppResolutionAttribute::print(ostream &os) const +{ + IppNamedAttribute::print(os); + os << '\t' << "Value(xres): " << dec << xres << '\n'; + os << '\t' << "Value(yres): " << dec << yres << '\n'; + os << '\t' << "Value(unit): " << dec << resolution_units << '\n'; + return os; +} + +/*----------------------------------------------------------------------*/ + +IppRangeOfIntegerAttribute::IppRangeOfIntegerAttribute(IPP_TAG t) + : IppNamedAttribute(t), lower(0), upper(0) +{ +} + +IppRangeOfIntegerAttribute::IppRangeOfIntegerAttribute(IPP_TAG t, const char *n, int l, int u) + : IppNamedAttribute(t, n), lower(l), upper(u) +{ +} + +int IppRangeOfIntegerAttribute::length() const +{ + return IppNamedAttribute::length() + 2 + 4 + 2 + 4; +} + +istream &IppRangeOfIntegerAttribute::input(istream &is) +{ + IppNamedAttribute::input(is); + + short len = readLength(is); + + if (0 < len && len <= 4) { + is.read((char *)&lower, sizeof(lower)); + lower = ntohl(lower); + } else { + is.seekg(len, ios::cur); + } + + len = readLength(is); + + if (0 < len && len <= 4) { + is.read((char *)&upper, sizeof(upper)); + upper = ntohl(upper); + } else { + is.seekg(len, ios::cur); + } + + return is; +} + +ostream &IppRangeOfIntegerAttribute::output(ostream &os) const +{ + IppNamedAttribute::output(os); + + writeLength(os, 4); + unsigned long val = htonl(lower); + os.write((char *)&val, sizeof(val)); + + writeLength(os, 4); + val = htonl(upper); + os.write((char *)&val, sizeof(val)); + + return os; +} + +ostream &IppRangeOfIntegerAttribute::print(ostream &os) const +{ + IppNamedAttribute::print(os); + os << '\t' << "Value(lower): " << dec << lower << '\n'; + os << '\t' << "Value(upper): " << dec << upper << '\n'; + return os; +} + +/*----------------------------------------------------------------------*/ + +IppContent::IppContent() +{ + version = 0x0100; + operation_id = IPP_GET_PRINTER_ATTRIBUTES; + request_id = 0x00000001; + + is = NULL; + size = -1; +} + +IppContent::~IppContent() +{ + for (list::const_iterator it = attrs.begin(); it != attrs.end(); it++) { + delete (*it); + } +} + +unsigned short IppContent::getVersion() const +{ + return version; +} + +void IppContent::setVersion(unsigned short i) +{ + version = i; +} + + +IPP_OPERATION_ID IppContent::getOperationId() const +{ + return (IPP_OPERATION_ID)operation_id; +} + +void IppContent::setOperationId(IPP_OPERATION_ID i) +{ + operation_id = i; +} + +IPP_STATUS_CODE IppContent::getStatusCode() const +{ + return (IPP_STATUS_CODE)operation_id; +} + +unsigned long IppContent::getRequestId() const +{ + return request_id; +} + +void IppContent::setRequestId(unsigned long i) +{ + request_id = i; +} + +istream &IppContent::input(istream &is) +{ + if (!is.read((char *)&version, sizeof(version))) { + return is; + } + + version = ntohs(version); + + if (!is.read((char *)&operation_id, sizeof(operation_id))) { + return is; + } + + operation_id = ntohs(operation_id); + + if (!is.read((char *)&request_id, sizeof(request_id))) { + return is; + } + + request_id = ntohl(request_id); + char tag; + + while (1) { + + if (!is.read((char *)&tag, sizeof(tag))) { + return is; + } + + if (tag <= 0x0F) { // delimiter + +// case IPP_OPERATION_ATTRIBUTES_TAG: +// case IPP_JOB_ATTRIBUTES_TAG: +// case IPP_END_OF_ATTRIBUTES_TAG: +// case IPP_PRINTER_ATTRIBUTES_TAG: +// case IPP_UNSUPPORTED_ATTRIBUTES_TAG: + + attrs.push_back(new IppAttribute((IPP_TAG)tag)); + if (tag == IPP_END_OF_ATTRIBUTES_TAG) { + break; + } + + } else if (tag <= 0x1F) { + + IppNoValueAttribute *attr = new IppNoValueAttribute((IPP_TAG)tag); + is >> *attr; + attrs.push_back(attr); + + } else if (tag <= 0x2F) { // integer values + + switch (tag) { + case IPP_INTEGER: + case IPP_ENUM: + { + IppIntegerAttribute *attr = new IppIntegerAttribute((IPP_TAG)tag); + is >> *attr; + attrs.push_back(attr); + } + break; + case IPP_BOOLEAN: + { + IppBooleanAttribute *attr = new IppBooleanAttribute((IPP_TAG)tag); + is >> *attr; + attrs.push_back(attr); + } + break; + default: + { + short len = readLength(is); + is.seekg(len, ios::cur); + len = readLength(is); + is.seekg(len, ios::cur); + } + break; + } + + } else if (tag <= 0x3F) { // octetString values + + switch (tag) { + case IPP_STRING: + { + IppStringAttribute *attr = new IppStringAttribute((IPP_TAG)tag); + is >> *attr; + attrs.push_back(attr); + } + break; + case IPP_DATETIME: + { + IppDatetimeAttribute *attr = new IppDatetimeAttribute((IPP_TAG)tag); + is >> *attr; + attrs.push_back(attr); + } + break; + case IPP_RESOLUTION: + { + IppResolutionAttribute *attr = new IppResolutionAttribute((IPP_TAG)tag); + is >> *attr; + attrs.push_back(attr); + } + break; + case IPP_RANGE_OF_INTEGER: + { + IppRangeOfIntegerAttribute *attr = new IppRangeOfIntegerAttribute((IPP_TAG)tag); + is >> *attr; + attrs.push_back(attr); + } + break; + case IPP_TEXT_WITH_LANGUAGE: + case IPP_NAME_WITH_LANGUAGE: + { + IppDoubleStringAttribute *attr = new IppDoubleStringAttribute((IPP_TAG)tag); + is >> *attr; + attrs.push_back(attr); + } + break; + default: + { + short len = readLength(is); + is.seekg(len, ios::cur); + len = readLength(is); + is.seekg(len, ios::cur); + } + break; + } + + } else if (tag <= 0x5F) { // character-string values + +// case IPP_TEXT_WITHOUT_LANGUAGE: +// case IPP_NAME_WITHOUT_LANGUAGE: +// case IPP_KEYWORD: +// case IPP_URI: +// case IPP_URISCHEME: +// case IPP_CHARSET: +// case IPP_NATURAL_LANGUAGE: +// case IPP_MIME_MEDIA_TYPE: + + IppStringAttribute *attr = new IppStringAttribute((IPP_TAG)tag); + is >> *attr; + attrs.push_back(attr); + } + } + return is; +} + +ostream &IppContent::output(ostream &os) const +{ + unsigned short ns_version = htons(version); // version-number + os.write((char *)&ns_version, sizeof(ns_version)); // version-number + + unsigned short ns_operation_id = htons(operation_id); // operation-id + os.write((char *)&ns_operation_id, sizeof(ns_operation_id)); // operation-id + + unsigned long ns_request_id = htonl(request_id); // request-id + os.write((char *)&ns_request_id, sizeof(ns_request_id)); // request-id + + for (list::const_iterator it = attrs.begin(); it != attrs.end(); it++) { + os << *(*it); + } + + ifstream ifs; + istream *iss = is; + if (iss == NULL) { + if (!file_path.empty()) { + ifs.open(file_path.c_str(), ios::in | ios::binary); + iss = &ifs; + } + } + if (iss && iss->good()) { + if (iss->good()) { + char c; + while (iss->get(c)) { + os.put(c); + } + } + } + + return os; +} + +void IppContent::setDelimiter(IPP_TAG tag) +{ + attrs.push_back(new IppAttribute(tag)); +} + +void IppContent::setInteger(const char *name, int value) +{ + attrs.push_back(new IppIntegerAttribute(IPP_INTEGER, name, value)); +} + +void IppContent::setBoolean(const char *name, bool value) +{ + attrs.push_back(new IppBooleanAttribute(IPP_BOOLEAN, name, value)); +} + +void IppContent::setString(const char *name, const char *value) +{ + attrs.push_back(new IppStringAttribute(IPP_STRING, name, value)); +} + +void IppContent::setDateTime(const char *name, const DATETIME *dt) +{ + attrs.push_back(new IppDatetimeAttribute(IPP_DATETIME, name, dt)); +} + +void IppContent::setResolution(const char *name, int x, int y, IPP_RESOLUTION_UNITS u) +{ + attrs.push_back(new IppResolutionAttribute(IPP_RESOLUTION, name, x, y, u)); +} + +void IppContent::setRangeOfInteger(const char *name, int lower, int upper) +{ + attrs.push_back(new IppRangeOfIntegerAttribute(IPP_RANGE_OF_INTEGER, name, lower, upper)); +} + +void IppContent::setTextWithLanguage(const char *name, const char *s1, const char *s2) +{ + attrs.push_back(new IppDoubleStringAttribute(IPP_TEXT_WITH_LANGUAGE, name, s1, s2)); +} + +void IppContent::setNameWithLanguage(const char *name, const char *s1, const char *s2) +{ + attrs.push_back(new IppDoubleStringAttribute(IPP_NAME_WITH_LANGUAGE, name, s1, s2)); +} + +void IppContent::setTextWithoutLanguage(const char *name, const char *value) +{ + attrs.push_back(new IppStringAttribute(IPP_TEXT_WITHOUT_LANGUAGE, name, value)); +} + +void IppContent::setNameWithoutLanguage(const char *name, const char *value) +{ + attrs.push_back(new IppStringAttribute(IPP_NAME_WITHOUT_LANGUAGE, name, value)); +} + +void IppContent::setKeyword(const char *name, const char *value) +{ + attrs.push_back(new IppStringAttribute(IPP_KEYWORD, name, value)); +} + +void IppContent::setURI(const char *name, const char *value) +{ + attrs.push_back(new IppStringAttribute(IPP_URI, name, value)); +} + +void IppContent::setURIScheme(const char *name, const char *value) +{ + attrs.push_back(new IppStringAttribute(IPP_URISCHEME, name, value)); +} + +void IppContent::setCharset(const char *name, const char *value) +{ + attrs.push_back(new IppStringAttribute(IPP_CHARSET, name, value)); +} + +void IppContent::setNaturalLanguage(const char *name, const char *value) +{ + attrs.push_back(new IppStringAttribute(IPP_NATURAL_LANGUAGE, name, value)); +} + +void IppContent::setMimeMediaType(const char *name, const char *value) +{ + attrs.push_back(new IppStringAttribute(IPP_MIME_MEDIA_TYPE, name, value)); +} + +int IppContent::length() const +{ + int length = 8; // sizeof(version-number + operation-id + request-id) + + for (list::const_iterator it = attrs.begin(); it != attrs.end(); it++) { + length += (*it)->length(); + } + + ifstream ifs; + istream *iss = is; + if (iss == NULL) { + if (!file_path.empty()) { + ifs.open(file_path.c_str(), ios::in | ios::binary); + iss = &ifs; + } + } + if (iss && iss->good()) { + int fsize = size; + if (fsize < 0) { + streampos pos = iss->tellg(); + iss->seekg(0, ios::end); + fsize = iss->tellg(); + iss->seekg(pos, ios::beg); + } + if (fsize > 0) { + length += fsize; + } + } + + return length; +} + +void IppContent::setRawData(const char *file, int n) +{ + file_path = file; + size = n; +} + +void IppContent::setRawData(istream &ifs, int n) +{ + is = &ifs; + size = n; +} + +ostream &IppContent::print(ostream &os) const +{ + os << "version: " << hex << version << '\n'; + os << "operation_id: " << hex << operation_id << '\n'; + os << "request_id: " << hex << request_id << '\n'; + + for (list::const_iterator it = attrs.begin(); it != attrs.end(); it++) { + (*it)->print(os); + } + + return os; +} + +bool IppContent::fail() const +{ + return !good(); +} + +bool IppContent::good() const +{ + return (IPP_SUCCESSFUL_OK_S <= operation_id) && (operation_id <= IPP_SUCCESSFUL_OK_E); +} + +bool IppContent::operator !() const +{ + return fail(); +} + +const char *IppContent::getStatusMessage() const +{ + if (good()) { + switch (operation_id) { + case IPP_SUCCESSFUL_OK: + return "successful-ok"; + case IPP_SUCCESSFUL_OK_IGNORED_OR_SUBSTITUTED_ATTRIBUTES: + return "successful-ok-ignored-or-substituted-attributes"; + case IPP_SUCCESSFUL_OK_CONFLICTING_ATTRIBUTES: + return "successful-ok-conflicting-attributes"; + default: + return "successful-ok-???"; + } + } else if (IPP_CLIENT_ERROR_S <= operation_id && operation_id <= IPP_CLIENT_ERROR_E) { + switch (operation_id) { + case IPP_CLIENT_ERROR_BAD_REQUEST: + return "client-error-bad-request"; + case IPP_CLIENT_ERROR_FORBIDDEN: + return "client-error-forbidden"; + case IPP_CLIENT_ERROR_NOT_AUTHENTICATED: + return "client-error-not-authenticated"; + case IPP_CLIENT_ERROR_NOT_AUTHORIZED: + return "client-error-not-authorized"; + case IPP_CLIENT_ERROR_NOT_POSSIBLE: + return "client-error-not-possible"; + case IPP_CLIENT_ERROR_TIMEOUT: + return "client-error-timeout"; + case IPP_CLIENT_ERROR_NOT_FOUND: + return "client-error-not-found"; + case IPP_CLIENT_ERROR_GONE: + return "client-error-gone"; + case IPP_CLIENT_ERROR_REQUEST_ENTITY_TOO_LARGE: + return "client-error-request-entity-too-large"; + case IPP_CLIENT_ERROR_REQUEST_VALUE_TOO_LONG: + return "client-error-request-value-too-long"; + case IPP_CLIENT_ERROR_DOCUMENT_FORMAT_NOT_SUPPORTED: + return "client-error-document-format-not-supported"; + case IPP_CLIENT_ERROR_ATTRIBUTES_OR_VALUES_NOT_SUPPORTED: + return "client-error-attributes-or-values-not-supported"; + case IPP_CLIENT_ERROR_URI_SCHEME_NOT_SUPPORTED: + return "client-error-uri-scheme-not-supported"; + case IPP_CLIENT_ERROR_CHARSET_NOT_SUPPORTED: + return "client-error-charset-not-supported"; + case IPP_CLIENT_ERROR_CONFLICTING_ATTRIBUTES: + return "client-error-conflicting-attributes"; + default: + return "client-error-???"; + } + } else if (IPP_SERVER_ERROR_S <= operation_id && operation_id <= IPP_SERVER_ERROR_E) { + switch (operation_id) { + case IPP_SERVER_ERROR_INTERNAL_ERROR: + return "server-error-internal-error"; + case IPP_SERVER_ERROR_OPERATION_NOT_SUPPORTED: + return "server-error-operation-not-supported"; + case IPP_SERVER_ERROR_SERVICE_UNAVAILABLE: + return "server-error-service-unavailable"; + case IPP_SERVER_ERROR_VERSION_NOT_SUPPORTED: + return "server-error-version-not-supported"; + case IPP_SERVER_ERROR_DEVICE_ERROR: + return "server-error-device-error"; + case IPP_SERVER_ERROR_TEMPORARY_ERROR: + return "server-error-temporary-error"; + case IPP_SERVER_ERROR_NOT_ACCEPTING_JOBS: + return "server-error-not-accepting-jobs"; + case IPP_SERVER_ERROR_BUSY: + return "server-error-busy"; + case IPP_SERVER_ERROR_JOB_CANCELED: + return "server-error-job-canceled"; + default: + return "server-error-???"; + } + } else { + return "unknown error."; + } +} diff --git a/src/add-ons/print/transports/ipp/IppContent.h b/src/add-ons/print/transports/ipp/IppContent.h new file mode 100644 index 0000000000..f3fc9f5fb2 --- /dev/null +++ b/src/add-ons/print/transports/ipp/IppContent.h @@ -0,0 +1,455 @@ +// Sun, 18 Jun 2000 +// Y.Takagi + +#ifndef __IppContent_H +#define __IppContent_H + +#ifdef WIN32 +#include +#include +#else +#include +#include +#endif +#include +#include + +#if (!__MWERKS__ || defined(WIN32)) +using namespace std; +#else +#define std +#endif + +enum IPP_OPERATION_ID { + + /* reserved, not used: 0x0000 */ + /* reserved, not used: 0x0001 */ + + IPP_PRINT_JOB = 0x0002, // printer operation + IPP_PRINT_URI = 0x0003, // printer operation + IPP_VALIDATE_JOB = 0x0004, // printer operation + IPP_CREATE_JOB = 0x0005, // printer operation + + IPP_SEND_DOCUMENT = 0x0006, // job operation + IPP_SEND_URI = 0x0007, // job operation + IPP_CANCEL_JOB = 0x0008, // job operation + IPP_GET_JOB_ATTRIBUTES = 0x0009, // job operation + + IPP_GET_JOBS = 0x000A, // printer operation + IPP_GET_PRINTER_ATTRIBUTES = 0x000B // printer operation + + /* reserved for future operations: 0x000C-0x3FFF */ + /* reserved for private extensions: 0x4000-0x8FFF */ +}; + +enum IPP_STATUS_CODE { + + IPP_SUCCESSFUL_OK_S = 0x0000, // successful + IPP_SUCCESSFUL_OK = 0x0000, // successful + IPP_SUCCESSFUL_OK_IGNORED_OR_SUBSTITUTED_ATTRIBUTES = 0x0001, // successful + IPP_SUCCESSFUL_OK_CONFLICTING_ATTRIBUTES = 0x0002, // successful + IPP_SUCCESSFUL_OK_E = 0x00FF, // successful + + IPP_INFORMATIONAL_S = 0x0100, // informational + IPP_INFORMATIONAL_E = 0x01FF, // informational + + IPP_REDIRECTION_S = 0x0200, // redirection + IPP_REDIRECTION_SE = 0x02FF, // redirection + + IPP_CLIENT_ERROR_S = 0x0400, // client-error + IPP_CLIENT_ERROR_BAD_REQUEST = 0x0400, // client-error + IPP_CLIENT_ERROR_FORBIDDEN = 0x0401, // client-error + IPP_CLIENT_ERROR_NOT_AUTHENTICATED = 0x0402, // client-error + IPP_CLIENT_ERROR_NOT_AUTHORIZED = 0x0403, // client-error + IPP_CLIENT_ERROR_NOT_POSSIBLE = 0x0404, // client-error + IPP_CLIENT_ERROR_TIMEOUT = 0x0405, // client-error + IPP_CLIENT_ERROR_NOT_FOUND = 0x0406, // client-error + IPP_CLIENT_ERROR_GONE = 0x0407, // client-error + IPP_CLIENT_ERROR_REQUEST_ENTITY_TOO_LARGE = 0x0408, // client-error + IPP_CLIENT_ERROR_REQUEST_VALUE_TOO_LONG = 0x0409, // client-error + IPP_CLIENT_ERROR_DOCUMENT_FORMAT_NOT_SUPPORTED = 0x040A, // client-error + IPP_CLIENT_ERROR_ATTRIBUTES_OR_VALUES_NOT_SUPPORTED = 0x040B, // client-error + IPP_CLIENT_ERROR_URI_SCHEME_NOT_SUPPORTED = 0x040C, // client-error + IPP_CLIENT_ERROR_CHARSET_NOT_SUPPORTED = 0x040D, // client-error + IPP_CLIENT_ERROR_CONFLICTING_ATTRIBUTES = 0x040E, // client-error + IPP_CLIENT_ERROR_E = 0x04FF, // client-error + + IPP_SERVER_ERROR_S = 0x0500, // server-error + IPP_SERVER_ERROR_INTERNAL_ERROR = 0x0500, // server-error + IPP_SERVER_ERROR_OPERATION_NOT_SUPPORTED = 0x0501, // server-error + IPP_SERVER_ERROR_SERVICE_UNAVAILABLE = 0x0502, // server-error + IPP_SERVER_ERROR_VERSION_NOT_SUPPORTED = 0x0503, // server-error + IPP_SERVER_ERROR_DEVICE_ERROR = 0x0504, // server-error + IPP_SERVER_ERROR_TEMPORARY_ERROR = 0x0505, // server-error + IPP_SERVER_ERROR_NOT_ACCEPTING_JOBS = 0x0506, // server-error + IPP_SERVER_ERROR_BUSY = 0x0507, // server-error + IPP_SERVER_ERROR_JOB_CANCELED = 0x0508, // server-error + IPP_SERVER_ERROR_E = 0x05FF // server-error +}; + +enum IPP_TAG { + /* reserved: 0x00 */ + IPP_OPERATION_ATTRIBUTES_TAG = 0x01, + IPP_JOB_ATTRIBUTES_TAG = 0x02, + IPP_END_OF_ATTRIBUTES_TAG = 0x03, + IPP_PRINTER_ATTRIBUTES_TAG = 0x04, + IPP_UNSUPPORTED_ATTRIBUTES_TAG = 0x05, + /* reserved for future delimiters: 0x06-0x0e */ + /* reserved for future chunking-end-of-attributes-tag: 0x0F */ + + IPP_UNSUPPORTED = 0x10, + /* reserved for future 'default': 0x11 */ + IPP_UNKNOWN = 0x12, + IPP_NO_VALUE = 0x13, + /* reserved for future "out-of-band" values: 0x14-0x1F */ + /* reserved: 0x20 */ + IPP_INTEGER = 0x21, + IPP_BOOLEAN = 0x22, + IPP_ENUM = 0x23, + /* reserved for future integer types: 0x24-0x2F */ + IPP_STRING = 0x30, + IPP_DATETIME = 0x31, + IPP_RESOLUTION = 0x32, + IPP_RANGE_OF_INTEGER = 0x33, + /* reserved for collection (in the future): 0x34 */ + IPP_TEXT_WITH_LANGUAGE = 0x35, + IPP_NAME_WITH_LANGUAGE = 0x36, + /* reserved for future octetString types: 0x37-0x3F */ + /* reserved: 0x40 */ + IPP_TEXT_WITHOUT_LANGUAGE = 0x41, + IPP_NAME_WITHOUT_LANGUAGE = 0x42, + /* reserved: 0x43 */ + IPP_KEYWORD = 0x44, + IPP_URI = 0x45, + IPP_URISCHEME = 0x46, + IPP_CHARSET = 0x47, + IPP_NATURAL_LANGUAGE = 0x48, + IPP_MIME_MEDIA_TYPE = 0x49 + /* reserved for future character string types: 0x4A-0x5F */ +}; + +enum IPP_RESOLUTION_UNITS { + IPP_DOTS_PER_INCH = 3, + IPP_DOTS_PER_CENTIMETER = 4 +}; + +enum IPP_FINISHINGS { + IPP_NONE = 3, + IPP_STAPLE = 4, + IPP_PUNCH = 5, + IPP_COVER = 6, + IPP_BIND = 7 +}; + +enum IPP_ORIENTATION_REQUESTED { + IPP_PORTRAIT = 3, + IPP_LANDSCAPE = 4, + IPP_REVERSE_LANDSCAPE = 5, + IPP_REVERSE_PORTRAIT = 6 +}; + +enum IPP_PRINT_QUALITY { + IPP_DRAFT = 3, + IPP_NORMAL = 4, + IPP_HIGH = 5 +}; + +enum IPP_JOB_STATE { + IPP_JOB_STATE_PENDING = 3, + IPP_JOB_STATE_PENDING_HELD = 4, + IPP_JOB_STATE_PROCESSING = 5, + IPP_JOB_STATE_PROCESSING_STOPPED= 6, + IPP_JOB_STATE_CANCELED = 7, + IPP_JOB_STATE_ABORTED = 8, + IPP_JOB_STATE_COMPLETED = 9 +}; + +enum IPP_PRINTER_STATE { + IPP_PRINTER_STATEIDLE = 3, + IPP_PRINTER_STATEPROCESSING = 4, + IPP_PRINTER_STATESTOPPED = 5 +}; + + +class IppAttribute { +public: + IppAttribute(IPP_TAG); + virtual ~IppAttribute() {} + virtual int length() const; + virtual istream &input(istream &is); + virtual ostream &output(ostream &os) const; + virtual ostream &print(ostream &) const; + friend istream& operator >> (istream &is, IppAttribute &attr) + { + return attr.input(is); + } + friend ostream& operator << (ostream &os, const IppAttribute &attr) + { + return attr.output(os); + } + + IPP_TAG tag; +}; + +class IppNamedAttribute : public IppAttribute { +public: + IppNamedAttribute(IPP_TAG t); + IppNamedAttribute(IPP_TAG t, const char *n); + virtual ~IppNamedAttribute() {} + virtual int length() const; + virtual istream &input(istream &is); + virtual ostream &output(ostream &os) const; + string name; + friend istream& operator >> (istream &is, IppNamedAttribute &attr) + { + return attr.input(is); + } + friend ostream& operator << (ostream &os, const IppNamedAttribute &attr) + { + return attr.output(os); + } + virtual ostream &print(ostream &) const; +}; + +class IppNoValueAttribute : public IppNamedAttribute { +public: + IppNoValueAttribute(IPP_TAG t); + IppNoValueAttribute(IPP_TAG t, const char *n); + virtual ~IppNoValueAttribute() {} + virtual int length() const; + virtual istream &input(istream &is); + virtual ostream &output(ostream &os) const; + virtual ostream &print(ostream &) const; + friend istream& operator >> (istream &is, IppNoValueAttribute &attr) + { + return attr.input(is); + } + friend ostream& operator << (ostream &os, const IppNoValueAttribute &attr) + { + return attr.output(os); + } +}; + +class IppBooleanAttribute : public IppNamedAttribute { +public: + IppBooleanAttribute(IPP_TAG t); + IppBooleanAttribute(IPP_TAG t, const char *n, bool f); + virtual ~IppBooleanAttribute() {} + virtual int length() const; + virtual istream &input(istream &is); + virtual ostream &output(ostream &os) const; + virtual ostream &print(ostream &) const; + friend istream& operator >> (istream &is, IppBooleanAttribute &attr) + { + return attr.input(is); + } + friend ostream& operator << (ostream &os, const IppBooleanAttribute &attr) + { + return attr.output(os); + } + + bool value; +}; + +class IppIntegerAttribute : public IppNamedAttribute { +public: + IppIntegerAttribute(IPP_TAG t); + IppIntegerAttribute(IPP_TAG t, const char *n, int v); + virtual ~IppIntegerAttribute() {} + virtual int length() const; + virtual istream &input(istream &is); + virtual ostream &output(ostream &os) const; + virtual ostream &print(ostream &) const; + friend istream& operator >> (istream &is, IppIntegerAttribute &attr) + { + return attr.input(is); + } + friend ostream& operator << (ostream &os, const IppIntegerAttribute &attr) + { + return attr.output(os); + } + + long value; +}; + +class DATETIME { +public: + DATETIME(); + DATETIME(const DATETIME &); + DATETIME & operator = (const DATETIME &); + friend istream& operator >> (istream &is, DATETIME &attr); + friend ostream& operator << (ostream &os, const DATETIME &attr); + + unsigned char datetime[11]; +}; + +class IppDatetimeAttribute : public IppNamedAttribute { +public: + IppDatetimeAttribute(IPP_TAG t); + IppDatetimeAttribute(IPP_TAG t, const char *n, const DATETIME *dt); + virtual ~IppDatetimeAttribute() {} + virtual int length() const; + virtual istream &input(istream &is); + virtual ostream &output(ostream &os) const; + virtual ostream &print(ostream &) const; + friend istream& operator >> (istream &is, IppDatetimeAttribute &attr) + { + return attr.input(is); + } + friend ostream& operator << (ostream &os, const IppDatetimeAttribute &attr) + { + return attr.output(os); + } + + DATETIME datetime; +}; + +class IppStringAttribute : public IppNamedAttribute { +public: + IppStringAttribute(IPP_TAG t); + IppStringAttribute(IPP_TAG t, const char *s, const char *s1); + virtual ~IppStringAttribute() {} + virtual int length() const; + virtual istream &input(istream &is); + virtual ostream &output(ostream &os) const; + virtual ostream &print(ostream &) const; + friend istream& operator >> (istream &is, IppStringAttribute &attr) + { + return attr.input(is); + } + friend ostream& operator << (ostream &os, const IppStringAttribute &attr) + { + return attr.output(os); + } + + string text; +}; + +class IppDoubleStringAttribute : public IppNamedAttribute { +public: + IppDoubleStringAttribute(IPP_TAG t); + IppDoubleStringAttribute(IPP_TAG t, const char *n, const char *s1, const char *s2); + virtual ~IppDoubleStringAttribute() {} + virtual int length() const; + virtual istream &input(istream &is); + virtual ostream &output(ostream &os) const; + friend istream& operator >> (istream &is, IppDoubleStringAttribute &attr) + { + return attr.input(is); + } + friend ostream& operator << (ostream &os, const IppDoubleStringAttribute &attr) + { + return attr.output(os); + } + virtual ostream &print(ostream &) const; + + string text1; + string text2; +}; + +class IppResolutionAttribute : public IppNamedAttribute { +public: + IppResolutionAttribute(IPP_TAG t); + IppResolutionAttribute(IPP_TAG t, const char *n, int, int, IPP_RESOLUTION_UNITS); + virtual ~IppResolutionAttribute() {} + virtual int length() const; + virtual istream &input(istream &is); + virtual ostream &output(ostream &os) const; + virtual ostream &print(ostream &) const; + friend istream& operator >> (istream &is, IppResolutionAttribute &attr) + { + return attr.input(is); + } + friend ostream& operator << (ostream &os, const IppResolutionAttribute &attr) + { + return attr.output(os); + } + + int xres; + int yres; + IPP_RESOLUTION_UNITS resolution_units; +}; + +class IppRangeOfIntegerAttribute : public IppNamedAttribute { +public: + IppRangeOfIntegerAttribute(IPP_TAG t); + IppRangeOfIntegerAttribute(IPP_TAG t, const char *n, int, int); + virtual ~IppRangeOfIntegerAttribute() {} + virtual int length() const; + virtual istream &input(istream &is); + virtual ostream &output(ostream &os) const; + virtual ostream &print(ostream &) const; + friend istream& operator >> (istream &is, IppRangeOfIntegerAttribute &attr) + { + return attr.input(is); + } + friend ostream& operator << (ostream &os, const IppRangeOfIntegerAttribute &attr) + { + return attr.output(os); + } + + long lower; + long upper; +}; + +class IppContent { +public: + IppContent(); + ~IppContent(); + int length() const; + istream &input(istream &); + ostream &output(ostream &) const; + friend istream& operator >> (istream &is, IppContent &ic) + { + return ic.input(is); + } + friend ostream& operator << (ostream &os, const IppContent &ic) + { + return ic.output(os); + } + void setVersion(unsigned short); + unsigned short getVersion() const; + void setOperationId(IPP_OPERATION_ID); + IPP_OPERATION_ID getOperationId() const; + void setRequestId(unsigned long); + unsigned long getRequestId() const; + IPP_STATUS_CODE getStatusCode() const; + const char *getStatusMessage() const; + + void setDelimiter(IPP_TAG tag); + void setInteger(const char *name, int value); + void setBoolean(const char *name, bool value); + void setString(const char *name, const char *value); + void setDateTime(const char *name, const DATETIME *dt); + void setResolution(const char *name, int x, int y, IPP_RESOLUTION_UNITS u); + void setRangeOfInteger(const char *name, int lower, int upper); + void setTextWithLanguage(const char *name, const char *s1, const char *s2); + void setNameWithLanguage(const char *name, const char *s1, const char *s2); + void setTextWithoutLanguage(const char *name, const char *value); + void setNameWithoutLanguage(const char *name, const char *value); + void setKeyword(const char *name, const char *value); + void setURI(const char *name, const char *value); + void setURIScheme(const char *name, const char *value); + void setCharset(const char *name, const char *value); + void setNaturalLanguage(const char *name, const char *value); + void setMimeMediaType(const char *name, const char *value); + + void setRawData(const char *file, int size = -1); + void setRawData(istream &is, int size = -1); + ostream &print(ostream &) const; + + bool operator !() const; + bool good() const; + bool fail() const; + +private: + list attrs; + unsigned short version; + unsigned short operation_id; + unsigned long request_id; + string file_path; + istream *is; + int size; +}; + +#endif // __IppContent_H diff --git a/src/add-ons/print/transports/ipp/IppDefs.h b/src/add-ons/print/transports/ipp/IppDefs.h new file mode 100644 index 0000000000..56601dcd0c --- /dev/null +++ b/src/add-ons/print/transports/ipp/IppDefs.h @@ -0,0 +1,11 @@ +// Sun, 18 Jun 2000 +// Y.Takagi + +#ifndef __IppDefs_H +#define __IppDefs_H + +#define SPOOL_PATH "printer_file" +#define IPP_URL "_ipp/URL" +#define IPP_JOB_ID "_ipp/job_id" + +#endif //__IppDefs_H diff --git a/src/add-ons/print/transports/ipp/IppSetupDlg.cpp b/src/add-ons/print/transports/ipp/IppSetupDlg.cpp new file mode 100644 index 0000000000..49838b285e --- /dev/null +++ b/src/add-ons/print/transports/ipp/IppSetupDlg.cpp @@ -0,0 +1,203 @@ +// Sun, 18 Jun 2000 +// Y.Takagi + +#include +#include +#include +#include +#include +#include + +#include "URL.h" +#include "IppContent.h" +#include "IppURLConnection.h" +#include "IppSetupDlg.h" +#include "IppDefs.h" +#include "DbgMsg.h" + +#define DLG_WIDTH 350 +#define DLG_HEIGHT 80 + +#define BUTTON_WIDTH 70 +#define BUTTON_HEIGHT 20 + +#define URL_H 10 +#define URL_V 10 +#define URL_WIDTH (DLG_WIDTH - URL_H - URL_H) +#define URL_HEIGHT 20 +#define URL_TEXT "URL" + +#define OK_H (DLG_WIDTH - BUTTON_WIDTH - 11) +#define OK_V (DLG_HEIGHT - BUTTON_HEIGHT - 11) +#define OK_TEXT "OK" + +#define CANCEL_H (OK_H - BUTTON_WIDTH - 12) +#define CANCEL_V OK_V +#define CANCEL_TEXT "Cancel" + + +const BRect URL_RECT( + URL_H, + URL_V, + URL_H + URL_WIDTH, + URL_V + URL_HEIGHT); + +const BRect OK_RECT( + OK_H, + OK_V, + OK_H + BUTTON_WIDTH, + OK_V + BUTTON_HEIGHT); + +const BRect CANCEL_RECT( + CANCEL_H, + CANCEL_V, + CANCEL_H + BUTTON_WIDTH, + CANCEL_V + BUTTON_HEIGHT); + +enum MSGS { + M_CANCEL = 1, + M_OK +}; + + +class IppSetupView : public BView { +public: + IppSetupView(BRect, BDirectory *); + ~IppSetupView() {} + virtual void AttachedToWindow(); + bool UpdateViewData(); + +private: + BTextControl *url; + BDirectory *dir; +}; + +IppSetupView::IppSetupView(BRect frame, BDirectory *d) + : BView(frame, "", B_FOLLOW_ALL, B_WILL_DRAW), dir(d) +{ + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); +} + +void IppSetupView::AttachedToWindow() +{ + /* url box */ + + url = new BTextControl(URL_RECT, "", URL_TEXT, "", NULL); + AddChild(url); + url->SetDivider(StringWidth(URL_TEXT) + 10); + + /* cancel */ + + BButton *button = new BButton(CANCEL_RECT, "", CANCEL_TEXT, new BMessage(M_CANCEL)); + AddChild(button); + + /* ok */ + + button = new BButton(OK_RECT, "", OK_TEXT, new BMessage(M_OK)); + AddChild(button); + button->MakeDefault(true); +} + +bool IppSetupView::UpdateViewData() +{ + string error_msg; + + if (*url->Text()) { + IppContent *request = new IppContent; + request->setOperationId(IPP_GET_PRINTER_ATTRIBUTES); + request->setDelimiter(IPP_OPERATION_ATTRIBUTES_TAG); + request->setCharset("attributes-charset", "utf-8"); + request->setNaturalLanguage("attributes-natural-language", "en-us"); + request->setURI("printer-uri", url->Text()); + request->setDelimiter(IPP_END_OF_ATTRIBUTES_TAG); + + IppURLConnection conn(URL(url->Text())); + conn.setIppRequest(request); + conn.setRequestProperty("Connection", "close"); + + HTTP_RESPONSECODE response_code = conn.getResponseCode(); + if (response_code == HTTP_OK) { + const char *content_type = conn.getContentType(); + if (content_type && !strncasecmp(content_type, "application/ipp", 15)) { + const IppContent *ipp_response = conn.getIppResponse(); + if (ipp_response->good()) { + dir->WriteAttr(IPP_URL, B_STRING_TYPE, 0, url->Text(), strlen(url->Text()) + 1); + return true; + } else { + error_msg = ipp_response->getStatusMessage(); + } + } else { + error_msg = "cannot get a IPP response."; + } + } else if (response_code != HTTP_UNKNOWN) { + error_msg = conn.getResponseMessage(); + } else { + error_msg = "cannot connect to the IPP server."; + } + } else { + error_msg = "please input the printer URL."; + } + + BAlert *alert = new BAlert("", error_msg.c_str(), "OK"); + alert->Go(); + return false; +} + +IppSetupDlg::IppSetupDlg(BDirectory *dir) + : BWindow(BRect(100, 100, 100 + DLG_WIDTH, 100 + DLG_HEIGHT), + "IPP Setup", B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL, + B_NOT_RESIZABLE | B_NOT_MINIMIZABLE | B_NOT_ZOOMABLE) +{ + result = 0; + + Lock(); + IppSetupView *view = new IppSetupView(Bounds(), dir); + AddChild(view); + Unlock(); + + semaphore = create_sem(0, "IppSetupSem"); +} + +bool IppSetupDlg::QuitRequested() +{ + result = B_ERROR; + release_sem(semaphore); + return true; +} + +void IppSetupDlg::MessageReceived(BMessage *msg) +{ + bool success; + + switch (msg->what) { + case M_OK: + Lock(); + success = ((IppSetupView *)ChildAt(0))->UpdateViewData(); + Unlock(); + if (success) { + result = B_NO_ERROR; + release_sem(semaphore); + } + break; + + case M_CANCEL: + result = B_ERROR; + release_sem(semaphore); + break; + + default: + BWindow::MessageReceived(msg); + break; + } +} + +int IppSetupDlg::Go() +{ + Show(); + acquire_sem(semaphore); + delete_sem(semaphore); + int value = result; + Lock(); + Quit(); + return value; +} diff --git a/src/add-ons/print/transports/ipp/IppSetupDlg.h b/src/add-ons/print/transports/ipp/IppSetupDlg.h new file mode 100644 index 0000000000..02e6c89089 --- /dev/null +++ b/src/add-ons/print/transports/ipp/IppSetupDlg.h @@ -0,0 +1,24 @@ +// Sun, 18 Jun 2000 +// Y.Takagi + +#ifndef __IppSetupDlg_H +#define __IppSetupDlg_H + +#include + +class BDirectory; + +class IppSetupDlg : public BWindow { +public: + IppSetupDlg(BDirectory *); + ~IppSetupDlg() {} + virtual bool QuitRequested(); + virtual void MessageReceived(BMessage *message); + int Go(); + +private: + int result; + long semaphore; +}; + +#endif // __IppSetupDlg_H diff --git a/src/add-ons/print/transports/ipp/IppTransport.cpp b/src/add-ons/print/transports/ipp/IppTransport.cpp new file mode 100644 index 0000000000..716f1cc4c4 --- /dev/null +++ b/src/add-ons/print/transports/ipp/IppTransport.cpp @@ -0,0 +1,148 @@ +// Sun, 18 Jun 2000 +// Y.Takagi + +#include +#include +#include +#include +#include +#include +#include + +#include "URL.h" +#include "IppContent.h" +#include "IppURLConnection.h" +#include "IppSetupDlg.h" +#include "IppTransport.h" +#include "IppDefs.h" +#include "DbgMsg.h" + +#if (!__MWERKS__ || defined(WIN32)) +using namespace std; +#else +#define std +#endif + +IppTransport::IppTransport(BMessage *msg) + : BDataIO() +{ + __url[0] = '\0'; + __user[0] = '\0'; + __file[0] = '\0'; + __jobid = 0; + __error = false; + + DUMP_BMESSAGE(msg); + + const char *spool_path = msg->FindString(SPOOL_PATH); + if (spool_path && *spool_path) { + BDirectory dir(spool_path); + DUMP_BDIRECTORY(&dir); + + dir.ReadAttr(IPP_URL, B_STRING_TYPE, 0, __url, sizeof(__url)); + if (__url[0] == '\0') { + IppSetupDlg *dlg = new IppSetupDlg(&dir); + if (dlg->Go() == B_ERROR) { + __error = true; + return; + } + } + + dir.ReadAttr(IPP_URL, B_STRING_TYPE, 0, __url, sizeof(__url)); + dir.ReadAttr(IPP_JOB_ID, B_INT32_TYPE, 0, &__jobid, sizeof(__jobid)); + __jobid++; + if (__jobid > 255) { + __jobid = 1; + } + dir.WriteAttr(IPP_JOB_ID, B_INT32_TYPE, 0, &__jobid, sizeof(__jobid)); + + getusername(__user, sizeof(__user)); + if (__user[0] == '\0') { + strcpy(__user, "baron"); + } + + sprintf(__file, "%s/%s@ipp.%ld", spool_path, __user, __jobid); + + __fs.open(__file, ios::in | ios::out | ios::binary | ios::trunc); + if (__fs.good()) { + DBGMSG(("spool_file: %s\n", __file)); + return; + } + } + __error = true; +} + +IppTransport::~IppTransport() +{ + string error_msg; + + if (!__error && __fs.good()) { + DBGMSG(("create IppContent\n")); + IppContent *request = new IppContent; + request->setOperationId(IPP_PRINT_JOB); + request->setDelimiter(IPP_OPERATION_ATTRIBUTES_TAG); + request->setCharset("attributes-charset", "utf-8"); + request->setNaturalLanguage("attributes-natural-language", "en-us"); + request->setURI("printer-uri", __url); + request->setMimeMediaType("document-format", "application/octet-stream"); + request->setNameWithoutLanguage("requesting-user-name", __user); +// request->setNameWithoutLanguage("job-name", __file); // optional + request->setDelimiter(IPP_END_OF_ATTRIBUTES_TAG); + + long fssize = __fs.tellg(); + __fs.seekg(0, ios::beg); + request->setRawData(__fs, fssize); + + URL url(__url); + IppURLConnection conn(url); + conn.setIppRequest(request); + conn.setRequestProperty("Connection", "close"); + + DBGMSG(("do connect\n")); + + HTTP_RESPONSECODE response_code = conn.getResponseCode(); + if (response_code == HTTP_OK) { + const char *content_type = conn.getContentType(); + if (content_type && !strncasecmp(content_type, "application/ipp", 15)) { + const IppContent *ipp_response = conn.getIppResponse(); + if (ipp_response->fail()) { + __error = true; + error_msg = ipp_response->getStatusMessage(); + } + } else { + __error = true; + error_msg = "cannot get a IPP response."; + } + } else if (response_code != HTTP_UNKNOWN) { + __error = true; + error_msg = conn.getResponseMessage(); + } else { + __error = true; + error_msg = "cannot connect to the IPP server."; + } + } + + unlink(__file); + + if (__error) { + BAlert *alert = new BAlert("", error_msg.c_str(), "OK"); + alert->Go(); + } +} + +ssize_t IppTransport::Read(void *, size_t) +{ + return 0; +} + +ssize_t IppTransport::Write(const void *buffer, size_t size) +{ +// DBGMSG(("write: %d\n", size)); + + if (!__fs.write(buffer, size)) { + __error = true; + return 0; + } +// return __fs.pcount(); + return size; +} diff --git a/src/add-ons/print/transports/ipp/IppTransport.h b/src/add-ons/print/transports/ipp/IppTransport.h new file mode 100644 index 0000000000..f5f80712a3 --- /dev/null +++ b/src/add-ons/print/transports/ipp/IppTransport.h @@ -0,0 +1,47 @@ +// Sun, 18 Jun 2000 +// Y.Takagi + +#ifndef __IppTransport_H +#define __IppTransport_H + +#include +#include +#include +#include + +#if (!__MWERKS__ || defined(WIN32)) +using namespace std; +#else +#define std +#endif + +class IppTransport : public BDataIO { +public: + IppTransport(BMessage *msg); + virtual ~IppTransport(); + virtual ssize_t Read(void *buffer, size_t size); + virtual ssize_t Write(const void *buffer, size_t size); + + bool operator !() const; + bool fail() const; + +private: + char __url[256]; + char __user[256]; + char __file[256]; + int32 __jobid; + bool __error; + fstream __fs; +}; + +inline bool IppTransport::fail() const +{ + return __error; +} + +inline bool IppTransport::operator !() const +{ + return fail(); +} + +#endif // __IppTransport_H diff --git a/src/add-ons/print/transports/ipp/IppURLConnection.cpp b/src/add-ons/print/transports/ipp/IppURLConnection.cpp new file mode 100644 index 0000000000..a210da2b8a --- /dev/null +++ b/src/add-ons/print/transports/ipp/IppURLConnection.cpp @@ -0,0 +1,108 @@ +// Sun, 18 Jun 2000 +// Y.Takagi + +#ifdef WIN32 +#include +#include +#include +#else +#include +#include +#include +#include +char *itoa(int i, char *buf, int unit) +{ + sprintf(buf, "%d", i); + return buf; +} +#define stricmp strcasecmp +#define strnicmp strncasecmp +#endif // WIN32 + +#include +#include "IppURLConnection.h" +#include "IppContent.h" + +IppURLConnection::IppURLConnection(const URL &Url) + : HttpURLConnection(Url) +{ + __ippRequest = NULL; + __ippResponse = new IppContent; + setRequestMethod("POST"); + setRequestProperty("Content-Type", "application/ipp"); + setRequestProperty("Cache-Control", "no-cache"); + setRequestProperty("Pragma", "no-cache"); +} + +IppURLConnection::~IppURLConnection() +{ + if (__ippRequest) { + delete __ippRequest; + } + + if (__ippResponse) { + delete __ippResponse; + } +} + +void IppURLConnection::setIppRequest(IppContent *obj) +{ + if (__ippRequest) { + delete __ippRequest; + } + __ippRequest = obj; +} + + +const IppContent *IppURLConnection::getIppResponse() const +{ + return __ippResponse; +} + +void IppURLConnection::setRequest() +{ + if (connected) { + char buf[64]; + itoa(__ippRequest->length(), buf, 10); + setRequestProperty("Content-Length", buf); + HttpURLConnection::setRequest(); + } +} + +void IppURLConnection::setContent() +{ + if (connected && __ippRequest) { + ostream &os = getOutputStream(); + os << *__ippRequest; + } +} + +inline bool is_contenttype_ipp(const char *s) +{ + return strnicmp(s, "application/ipp", 15) ? false : true; +} + +void IppURLConnection::getContent() +{ + if (connected) { + if (getResponseCode() == HTTP_OK && is_contenttype_ipp(getContentType())) { + istream &is = getInputStream(); + is >> *__ippResponse; + } else { + HttpURLConnection::getContent(); + } + } +} + +ostream &IppURLConnection::printIppRequest(ostream &os) +{ + return __ippRequest->print(os); +} + +ostream &IppURLConnection::printIppResponse(ostream &os) +{ + if (getResponseCode() == HTTP_OK && is_contenttype_ipp(getContentType())) { + return __ippResponse->print(os); + } + return os; +} diff --git a/src/add-ons/print/transports/ipp/IppURLConnection.h b/src/add-ons/print/transports/ipp/IppURLConnection.h new file mode 100644 index 0000000000..5322906a9c --- /dev/null +++ b/src/add-ons/print/transports/ipp/IppURLConnection.h @@ -0,0 +1,34 @@ +// Sun, 18 Jun 2000 +// Y.Takagi + +#ifndef __IppURLConnection_H +#define __IppURLConnection_H + +#include "HttpURLConnection.h" + +class IppContent; + +class IppURLConnection : public HttpURLConnection { +public: + IppURLConnection(const URL &url); + ~IppURLConnection(); + + void setIppRequest(IppContent *); + const IppContent *getIppResponse() const; + + int length(); + + ostream &printIppRequest(ostream &); + ostream &printIppResponse(ostream &); + +protected: + virtual void setRequest(); + virtual void setContent(); + virtual void getContent(); + +private: + IppContent *__ippRequest; + IppContent *__ippResponse; +}; + +#endif // __IppURLConnection_H diff --git a/src/add-ons/print/transports/ipp/URL.cpp b/src/add-ons/print/transports/ipp/URL.cpp new file mode 100644 index 0000000000..fe50e66458 --- /dev/null +++ b/src/add-ons/print/transports/ipp/URL.cpp @@ -0,0 +1,102 @@ +// Sun, 18 Jun 2000 +// Y.Takagi + +#include +#include "URL.h" + +URL::URL(const char *spec) +{ +// __protocol = "http"; +// __host = "localhost"; +// __file = "/"; + __port = -1; + + if (spec) { + char *temp_spec = new char[strlen(spec) + 1]; + strcpy(temp_spec, spec); + + char *p1; + char *p2; + char *p3; + char *p4; + + p1 = strstr(temp_spec, "//"); + if (p1) { + *p1 = '\0'; + p1 += 2; + __protocol = temp_spec; + } else { + p1 = temp_spec; + } + + p3 = strstr(p1, "/"); + if (p3) { + p4 = strstr(p3, "#"); + if (p4) { + __ref = p4 + 1; + *p4 = '\0'; + } + __file = p3; + *p3 = '\0'; + } else { + __file = "/"; + } + + p2 = strstr(p1, ":"); + if (p2) { + __port = atoi(p2 + 1); + *p2 = '\0'; + } + + __host = p1; + delete [] temp_spec; + } + +// if (__port == -1) { +// if (__protocol == "http") { +// __port = 80; +// } else if (__protocol == "ipp") { +// __port = 631; +// } +// } +} + +URL::URL(const char *protocol, const char *host, int port, const char *file) +{ + __protocol = protocol; + __host = host; + __file = file; + __port = port; +} + +URL::URL(const char *protocol, const char *host, const char *file) +{ + __protocol = protocol; + __host = host; + __file = file; +} + +URL::URL(const URL &url) +{ + __protocol = url.__protocol; + __host = url.__host; + __file = url.__file; + __ref = url.__ref; + __port = url.__port; +} + +URL &URL::operator = (const URL &url) +{ + __protocol = url.__protocol; + __host = url.__host; + __file = url.__file; + __ref = url.__ref; + __port = url.__port; + return *this; +} + +bool URL::operator == (const URL &url) +{ + return (__protocol == url.__protocol) && (__host == url.__host) && (__file == url.__file) && + (__ref == url.__ref) && (__port == url.__port); +} diff --git a/src/add-ons/print/transports/ipp/URL.h b/src/add-ons/print/transports/ipp/URL.h new file mode 100644 index 0000000000..25be792889 --- /dev/null +++ b/src/add-ons/print/transports/ipp/URL.h @@ -0,0 +1,68 @@ +// Sun, 18 Jun 2000 +// Y.Takagi + +#ifndef __URL_H +#define __URL_H + +#include + +#if (!__MWERKS__ || defined(WIN32)) +using namespace std; +#else +#define std +#endif + +class URL { +public: + URL(const char *spec); + URL(const char *protocol, const char *host, int port, const char *file); + URL(const char *protocol, const char *host, const char *file); +// URL(URL &, const char *spec); + + int getPort() const; + const char *getProtocol() const; + const char *getHost() const; + const char *getFile() const; + const char *getRef() const; + + URL(const URL &); + URL &operator = (const URL &); + bool operator == (const URL &); + +protected: +// void set(const char *protocol, const char *host, int port, const char *file, const char *ref); + +private: + string __protocol; + string __host; + string __file; + string __ref; + int __port; +}; + +inline int URL::getPort() const +{ + return __port; +} + +inline const char *URL::getProtocol() const +{ + return __protocol.c_str(); +} + +inline const char *URL::getHost() const +{ + return __host.c_str(); +} + +inline const char *URL::getFile() const +{ + return __file.c_str(); +} + +inline const char *URL::getRef() const +{ + return __ref.c_str(); +} + +#endif // __URL_H diff --git a/src/add-ons/print/transports/lpr/Lpr.cpp b/src/add-ons/print/transports/lpr/Lpr.cpp new file mode 100644 index 0000000000..dfee68360c --- /dev/null +++ b/src/add-ons/print/transports/lpr/Lpr.cpp @@ -0,0 +1,31 @@ +// Sun, 18 Jun 2000 +// Y.Takagi + +#include "LprTransport.h" +#include "DbgMsg.h" + +LprTransport *transport = NULL; + +extern "C" _EXPORT void exit_transport() +{ + DBGMSG(("> exit_transport\n")); + if (transport) { + delete transport; + transport = NULL; + } + DBGMSG(("< exit_transport\n")); +} + +extern "C" _EXPORT BDataIO *init_transport(BMessage *msg) +{ + DBGMSG(("> init_transport\n")); + + transport = new LprTransport(msg); + + if (transport->fail()) { + exit_transport(); + } + + DBGMSG(("< init_transport\n")); + return transport; +} diff --git a/src/add-ons/print/transports/lpr/LprDefs.h b/src/add-ons/print/transports/lpr/LprDefs.h new file mode 100644 index 0000000000..adfcc474fa --- /dev/null +++ b/src/add-ons/print/transports/lpr/LprDefs.h @@ -0,0 +1,12 @@ +// Sun, 18 Jun 2000 +// Y.Takagi + +#ifndef __LprDefs_H +#define __LprDefs_H + +#define SPOOL_PATH "printer_file" +#define LPR_SERVER_NAME "_lpr/server_name" +#define LPR_QUEUE_NAME "_lpr/queue_name" +#define LPR_JOB_ID "_lpr/job_id" + +#endif //__LprDefs_H diff --git a/src/add-ons/print/transports/lpr/LprSetupDlg.cpp b/src/add-ons/print/transports/lpr/LprSetupDlg.cpp new file mode 100644 index 0000000000..1de893524b --- /dev/null +++ b/src/add-ons/print/transports/lpr/LprSetupDlg.cpp @@ -0,0 +1,203 @@ +// Sun, 18 Jun 2000 +// Y.Takagi + +#include +#include +#include +#include +#include +#include + +#include + +#include "LpsClient.h" +#include "LprSetupDlg.h" +#include "LprDefs.h" +#include "DbgMsg.h" + +#define DLG_WIDTH 370 +#define DLG_HEIGHT 100 + +#define BUTTON_WIDTH 70 +#define BUTTON_HEIGHT 20 + +#define SERVER_H 10 +#define SERVER_V 10 +#define SERVER_WIDTH (DLG_WIDTH - SERVER_H - SERVER_H) +#define SERVER_HEIGHT 20 +#define SERVER_TEXT "Server name" + +#define QUEUE_H 10 +#define QUEUE_V SERVER_V + SERVER_HEIGHT + 2 +#define QUEUE_WIDTH (DLG_WIDTH - QUEUE_H - QUEUE_H) +#define QUEUE_HEIGHT 20 +#define QUEUE_TEXT "Queue name" + +#define OK_H (DLG_WIDTH - BUTTON_WIDTH - 11) +#define OK_V (DLG_HEIGHT - BUTTON_HEIGHT - 11) +#define OK_TEXT "OK" + +#define CANCEL_H (OK_H - BUTTON_WIDTH - 12) +#define CANCEL_V OK_V +#define CANCEL_TEXT "Cancel" + +const BRect SERVER_RECT( + SERVER_H, + SERVER_V, + SERVER_H + SERVER_WIDTH, + SERVER_V + SERVER_HEIGHT); + +const BRect QUEUE_RECT( + QUEUE_H, + QUEUE_V, + QUEUE_H + QUEUE_WIDTH, + QUEUE_V + QUEUE_HEIGHT); + +const BRect OK_RECT( + OK_H, + OK_V, + OK_H + BUTTON_WIDTH, + OK_V + BUTTON_HEIGHT); + +const BRect CANCEL_RECT( + CANCEL_H, + CANCEL_V, + CANCEL_H + BUTTON_WIDTH, + CANCEL_V + BUTTON_HEIGHT); + +enum MSGS { + M_CANCEL = 1, + M_OK +}; + + +class LprSetupView : public BView { +public: + LprSetupView(BRect, BDirectory *); + ~LprSetupView() {} + virtual void AttachedToWindow(); + bool UpdateViewData(); + +private: + BTextControl *server; + BTextControl *queue; + BDirectory *dir; +}; + +LprSetupView::LprSetupView(BRect frame, BDirectory *d) + : BView(frame, "", B_FOLLOW_ALL, B_WILL_DRAW), dir(d) +{ + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); +} + +void LprSetupView::AttachedToWindow() +{ + float width = max(StringWidth(SERVER_TEXT), StringWidth(QUEUE_TEXT)) + 10; + + /* server name box */ + + server = new BTextControl(SERVER_RECT, "", SERVER_TEXT, "", NULL); + AddChild(server); + server->SetDivider(width); + + /* queue name box */ + + queue = new BTextControl(QUEUE_RECT, "", QUEUE_TEXT, "", NULL); + AddChild(queue); + queue->SetDivider(width); + + /* cancel */ + + BButton *button = new BButton(CANCEL_RECT, "", CANCEL_TEXT, new BMessage(M_CANCEL)); + AddChild(button); + + /* ok */ + + button = new BButton(OK_RECT, "", OK_TEXT, new BMessage(M_OK)); + AddChild(button); + button->MakeDefault(true); +} + +bool LprSetupView::UpdateViewData() +{ + if (*server->Text() && *queue->Text()) { + + try { + LpsClient lpr(server->Text()); + lpr.connect(); + } + + catch (LPSException &err) { + BAlert *alert = new BAlert("", err.what(), "OK"); + alert->Go(); + return false; + } + + dir->WriteAttr(LPR_SERVER_NAME, B_STRING_TYPE, 0, server->Text(), strlen(server->Text()) + 1); + dir->WriteAttr(LPR_QUEUE_NAME, B_STRING_TYPE, 0, queue->Text(), strlen(queue->Text()) + 1); + return true; + } + + BAlert *alert = new BAlert("", "please input parameters.", "OK"); + alert->Go(); + return false; +} + +LprSetupDlg::LprSetupDlg(BDirectory *dir) + : BWindow(BRect(100, 100, 100 + DLG_WIDTH, 100 + DLG_HEIGHT), + "LPR Setup", B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL, + B_NOT_RESIZABLE | B_NOT_MINIMIZABLE | B_NOT_ZOOMABLE) +{ + result = 0; + + Lock(); + LprSetupView *view = new LprSetupView(Bounds(), dir); + AddChild(view); + Unlock(); + + semaphore = create_sem(0, "lprSetupSem"); +} + +bool LprSetupDlg::QuitRequested() +{ + result = B_ERROR; + release_sem(semaphore); + return true; +} + +void LprSetupDlg::MessageReceived(BMessage *msg) +{ + bool success; + + switch (msg->what) { + case M_OK: + Lock(); + success = ((LprSetupView *)ChildAt(0))->UpdateViewData(); + Unlock(); + if (success) { + result = B_NO_ERROR; + release_sem(semaphore); + } + break; + + case M_CANCEL: + result = B_ERROR; + release_sem(semaphore); + break; + + default: + BWindow::MessageReceived(msg); + break; + } +} + +int LprSetupDlg::Go() +{ + Show(); + acquire_sem(semaphore); + delete_sem(semaphore); + int value = result; + Lock(); + Quit(); + return value; +} diff --git a/src/add-ons/print/transports/lpr/LprSetupDlg.h b/src/add-ons/print/transports/lpr/LprSetupDlg.h new file mode 100644 index 0000000000..11eb27af01 --- /dev/null +++ b/src/add-ons/print/transports/lpr/LprSetupDlg.h @@ -0,0 +1,24 @@ +// Sun, 18 Jun 2000 +// Y.Takagi + +#ifndef __LprSetupDlg_H +#define __LprSetupDlg_H + +#include + +class BDirectory; + +class LprSetupDlg : public BWindow { +public: + LprSetupDlg(BDirectory *); + ~LprSetupDlg() {} + virtual bool QuitRequested(); + virtual void MessageReceived(BMessage *message); + int Go(); + +private: + int result; + long semaphore; +}; + +#endif // __LprSetupDlg_H diff --git a/src/add-ons/print/transports/lpr/LprTransport.cpp b/src/add-ons/print/transports/lpr/LprTransport.cpp new file mode 100644 index 0000000000..9c1ccd07e3 --- /dev/null +++ b/src/add-ons/print/transports/lpr/LprTransport.cpp @@ -0,0 +1,144 @@ +// Sun, 18 Jun 2000 +// Y.Takagi + +#include +#include +#include +#include +#include +#include +#include +#include +#include "_sstream" + +#include "LpsClient.h" +#include "LprSetupDlg.h" +#include "LprTransport.h" +#include "LprDefs.h" +#include "DbgMsg.h" + +#if (!__MWERKS__ || defined(WIN32)) +using namespace std; +#else +#define std +#endif + +LprTransport::LprTransport(BMessage *msg) + : BDataIO() +{ + __server[0] = '\0'; + __queue[0] = '\0'; + __file[0] = '\0'; + __user[0] = '\0'; + __jobid = 0; + __error = false; + + DUMP_BMESSAGE(msg); + + const char *spool_path = msg->FindString(SPOOL_PATH); + if (spool_path && *spool_path) { + BDirectory dir(spool_path); + DUMP_BDIRECTORY(&dir); + + dir.ReadAttr(LPR_SERVER_NAME, B_STRING_TYPE, 0, __server, sizeof(__server)); + if (__server[0] == '\0') { + LprSetupDlg *dlg = new LprSetupDlg(&dir); + if (dlg->Go() == B_ERROR) { + __error = true; + return; + } + } + + dir.ReadAttr(LPR_SERVER_NAME, B_STRING_TYPE, 0, __server, sizeof(__server)); + dir.ReadAttr(LPR_QUEUE_NAME, B_STRING_TYPE, 0, __queue, sizeof(__queue)); + dir.ReadAttr(LPR_JOB_ID, B_INT32_TYPE, 0, &__jobid, sizeof(__jobid)); + __jobid++; + if (__jobid > 255) { + __jobid = 1; + } + dir.WriteAttr(LPR_JOB_ID, B_INT32_TYPE, 0, &__jobid, sizeof(__jobid)); + + getusername(__user, sizeof(__user)); + if (__user[0] == '\0') { + strcpy(__user, "baron"); + } + + sprintf(__file, "%s/%s@ipp.%ld", spool_path, __user, __jobid); + + __fs.open(__file, ios::in | ios::out | ios::binary | ios::trunc); + if (__fs.good()) { + DBGMSG(("spool_file: %s\n", __file)); + return; + } + } + __error = true; +} + +LprTransport::~LprTransport() +{ + char hostname[128]; + gethostname(hostname, sizeof(hostname)); + + char username[128]; +#ifdef WIN32 + unsigned long length = sizeof(hostname); + GetUserName(username, &length); +#else + getusername(username, sizeof(username)); +#endif + + ostringstream cfname; + cfname << "cfA" << setw(3) << setfill('0') << __jobid << hostname; + + ostringstream dfname; + dfname << "dfA" << setw(3) << setfill('0') << __jobid << hostname; + + ostringstream cf; + cf << 'H' << hostname << '\n'; + cf << 'P' << username << '\n'; + cf << 'l' << dfname.str() << '\n'; + cf << 'U' << dfname.str() << '\n'; + + long cfsize = cf.str().length(); + long dfsize = __fs.tellg(); + __fs.seekg(0, ios::beg); + + try { + LpsClient lpr(__server); + + lpr.connect(); + lpr.receiveJob(__queue); + + lpr.receiveControlFile(cfsize, cfname.str().c_str()); + lpr.transferData(cf.str().c_str(), cfsize); + lpr.endTransfer(); + + lpr.receiveDataFile(dfsize, dfname.str().c_str()); + lpr.transferData(__fs, dfsize); + lpr.endTransfer(); + } + + catch (LPSException &err) { + DBGMSG(("error: %s\n", err.what())); + BAlert *alert = new BAlert("", err.what(), "OK"); + alert->Go(); + } + + unlink(__file); +} + +ssize_t LprTransport::Read(void *, size_t) +{ + return 0; +} + +ssize_t LprTransport::Write(const void *buffer, size_t size) +{ +// DBGMSG(("write: %d\n", size)); + if (!__fs.write(buffer, size)) { + __error = true; + return 0; + } +// return __fs.pcount(); + return size; +} diff --git a/src/add-ons/print/transports/lpr/LprTransport.h b/src/add-ons/print/transports/lpr/LprTransport.h new file mode 100644 index 0000000000..948090b219 --- /dev/null +++ b/src/add-ons/print/transports/lpr/LprTransport.h @@ -0,0 +1,48 @@ +// Sun, 18 Jun 2000 +// Y.Takagi + +#ifndef __LprTransport_H +#define __LprTransport_H + +#include +#include +#include +#include + +#if (!__MWERKS__ || defined(WIN32)) +using namespace std; +#else +#define std +#endif + +class LprTransport : public BDataIO { +public: + LprTransport(BMessage *msg); + virtual ~LprTransport(); + virtual ssize_t Read(void *buffer, size_t size); + virtual ssize_t Write(const void *buffer, size_t size); + + bool operator !() const; + bool fail() const; + +private: + char __server[256]; + char __queue[256]; + char __file[256]; + char __user[256]; + int32 __jobid; + fstream __fs; + bool __error; +}; + +inline bool LprTransport::fail() const +{ + return __error; +} + +inline bool LprTransport::operator !() const +{ + return fail(); +} + +#endif // __LprTransport_H diff --git a/src/add-ons/print/transports/lpr/LpsClient.cpp b/src/add-ons/print/transports/lpr/LpsClient.cpp new file mode 100644 index 0000000000..fb6e69ca04 --- /dev/null +++ b/src/add-ons/print/transports/lpr/LpsClient.cpp @@ -0,0 +1,221 @@ +// Sun, 18 Jun 2000 +// Y.Takagi + +#ifdef WIN32 + #include + #include + #include +#else /* BeOS */ + #include + #include + #include + #include "_sstream" +#endif + +#include +#include +#include "LpsClient.h" +#include "Socket.h" +//#include "DbgMsg.h" + +#if (!__MWERKS__ || defined(WIN32)) +using namespace std; +#else +#define std +#endif + +#define LPS_SERVER_PORT 515 +#define LPS_CLIENT_PORT_S 721 +#define LPS_CLIENT_PORT_E 731 + +#define LPS_CHECK_QUEUE '\001' +#define LPS_PRINT_JOB '\002' +#define LPS_DISPLAY_SHORT_QUEUE '\003' +#define LPS_DISPLAY_LONG_QUEUE '\004' +#define LPS_REMOVE_JOB '\005' +#define LPS_END_TRANSFER '\000' +#define LPS_ABORT '\001' +#define LPS_RECEIVE_CONTROL_FILE '\002' +#define LPS_RECEIVE_DATA_FILE '\003' + +#define LPS_OK '\0' +#define LPS_ERROR '\1' +#define LPS_NO_SPOOL_SPACE '\2' + +#ifndef INADDR_NONE +#define INADDR_NONE 0xffffffff +#endif + +#ifdef WIN32 + #define EADDRINUSE WSAEADDRINUSE + #define ERRNO WSAGetLastError() +#else + #define ERRNO errno +#endif + + +LpsClient::LpsClient(const char *host) + : __host(host), __sock(NULL), connected(false) +{ +} + +LpsClient::~LpsClient() +{ + close(); +} + +void LpsClient::connect() throw(LPSException) +{ +// DBGMSG(("connect\n")); + + for (int localPort = LPS_CLIENT_PORT_S ; localPort <= LPS_CLIENT_PORT_E ; localPort++) { + if (__sock) { + delete __sock; + } + __sock = new Socket(__host.c_str(), LPS_SERVER_PORT, localPort); + if (__sock->good()) { + __is = &__sock->getInputStream(); + __os = &__sock->getOutputStream(); + connected = true; + return; + } + } + + throw(LPSException(__sock->getLastError())); +} + +void LpsClient::close() +{ +// DBGMSG(("close\n")); + + connected = false; + if (__sock) { + delete __sock; + __sock = NULL; + } +} + +void LpsClient::receiveJob(const char *printer) throw(LPSException) +{ +// DBGMSG(("tell_receive_job\n")); + + if (connected) { + *__os << LPS_PRINT_JOB << printer << '\n' << flush; + checkAck(); + } +} + +void LpsClient::receiveControlFile(int size, const char *name) throw(LPSException) +{ +// DBGMSG(("tell_receive_control_file\n")); + + if (connected) { + + char cfname[32]; + strncpy(cfname, name, sizeof(cfname)); + cfname[sizeof(cfname) - 1] = '\0'; + + *__os << LPS_RECEIVE_CONTROL_FILE << size << ' ' << cfname << '\n' << flush; + + checkAck(); + } +} + +void LpsClient::receiveDataFile(int size, const char *name) throw(LPSException) +{ +// DBGMSG(("tell_receive_data_file\n")); + + if (connected) { + + char dfname[32]; + strncpy(dfname, name, sizeof(dfname)); + dfname[sizeof(dfname) - 1] = '\0'; + + *__os << LPS_RECEIVE_DATA_FILE << size << ' ' << dfname << '\n' << flush; + + checkAck(); + } +} + +void LpsClient::transferData(const char *buffer, int size) throw(LPSException) +{ +// DBGMSG(("send: %d\n", size)); + + if (connected) { + + if (size < 0) { + size = strlen(buffer); + } + + if (!__os->write(buffer, size)) { + close(); + throw(LPSException("error talking to lpd server")); + } + } +} + +void LpsClient::transferData(istream &is, int size) throw(LPSException) +{ +// DBGMSG(("send: %d\n", size)); + + if (connected) { + + if (size < 0) { + is.seekg(0, ios::end); +#if __MWERKS__ + size = is.tellg().offset(); +#else + size = is.tellg(); +#endif + is.seekg(0, ios::beg); + } + + char c; + while (is.get(c)) { + if (!__os->put(c)) { + close(); + throw(LPSException("error reading file.")); + return; + } + } + } +} + +void LpsClient::endTransfer() throw(LPSException) +{ +// DBGMSG(("tell_end_transfer\n")); + + if (connected) { + *__os << LPS_END_TRANSFER << flush; + checkAck(); + } +} + +void LpsClient::checkAck() throw(LPSException) +{ +// DBGMSG(("check_ack\n")); + + if (connected) { + + char c; + + if (!__is->get(c)) { + close(); + throw(LPSException("server not responding.")); + return; + } + + switch (c) { + case LPS_OK: + break; + case LPS_ERROR: + close(); + throw(LPSException("server error.")); + break; + case LPS_NO_SPOOL_SPACE: + close(); + throw(LPSException("not enough spool space on server.")); + break; + } + } +} diff --git a/src/add-ons/print/transports/lpr/LpsClient.h b/src/add-ons/print/transports/lpr/LpsClient.h new file mode 100644 index 0000000000..9c7c6977cf --- /dev/null +++ b/src/add-ons/print/transports/lpr/LpsClient.h @@ -0,0 +1,56 @@ +// Sun, 18 Jun 2000 +// Y.Takagi + +#ifndef __LPSCLIENT_H +#define __LPSCLIENT_H + +#ifdef WIN32 +#include +#include +#else +#include +#include +#endif +#include + +#if (!__MWERKS__ || defined(WIN32)) +using namespace std; +#else +#define std +#endif + +class Socket; + +class LPSException { +private: + string str; +public: + LPSException(const string &what_arg) : str(what_arg) {} + const char *what() const { return str.c_str(); } +}; + +class LpsClient { +public: + LpsClient(const char *host); + ~LpsClient(); + void connect() throw(LPSException); + void close(); + void receiveJob(const char *queue) throw(LPSException); + void receiveControlFile(int cfsize, const char *cfname) throw(LPSException); + void receiveDataFile(int dfsize, const char *dfname) throw(LPSException); + void transferData(const char *buffer, int size = -1) throw(LPSException); + void transferData(istream &is, int size = -1) throw(LPSException); + void endTransfer() throw(LPSException); + void checkAck() throw(LPSException); + +protected: + bool connected; + +private: + string __host; + Socket *__sock; + istream *__is; + ostream *__os; +}; + +#endif /* __LPSCLIENT_H */ diff --git a/src/add-ons/print/transports/print_to_file/FileSelector.cpp b/src/add-ons/print/transports/print_to_file/FileSelector.cpp new file mode 100644 index 0000000000..c01c7380c0 --- /dev/null +++ b/src/add-ons/print/transports/print_to_file/FileSelector.cpp @@ -0,0 +1,91 @@ +#include + +#include + +#include "FileSelector.h" + +FileSelector::FileSelector(void) + : BWindow(BRect(0,0,320,160), "printtofile", B_TITLED_WINDOW, + B_NOT_ZOOMABLE, B_CURRENT_WORKSPACE) +{ + m_exit_sem = create_sem(0, "FileSelector"); + m_result = B_ERROR; + m_save_panel = NULL; +} + +FileSelector::~FileSelector() +{ + delete m_save_panel; + delete_sem(m_exit_sem); +} + + +bool FileSelector::QuitRequested() +{ + release_sem(m_exit_sem); + return true; +} + + +void FileSelector::MessageReceived(BMessage * msg) +{ + switch (msg->what) + { + case START_MSG: + m_save_panel = new BFilePanel(B_SAVE_PANEL, + new BMessenger(this), NULL, 0, false); + + m_save_panel->Window()->SetWorkspaces(B_CURRENT_WORKSPACE); + m_save_panel->Show(); + break; + + case B_SAVE_REQUESTED: + { + entry_ref dir; + + if ( msg->FindRef("directory", &dir) == B_OK) + { + const char * name; + + BDirectory bdir(&dir); + if ( msg->FindString("name", &name) == B_OK) + { + if ( name != NULL ) + m_result = m_entry.SetTo(&bdir, name); + }; + }; + + release_sem(m_exit_sem); + break; + }; + + case B_CANCEL: + release_sem(m_exit_sem); + break; + + default: + inherited::MessageReceived(msg); + break; + }; +} + + +status_t FileSelector::Go(entry_ref * ref) +{ + MoveTo(300,300); + Hide(); + Show(); + PostMessage(START_MSG); + acquire_sem(m_exit_sem); + + if ( m_result == B_OK && ref) + m_result = m_entry.GetRef(ref); + + Lock(); + Quit(); + + return m_result; +} + + + diff --git a/src/add-ons/print/transports/print_to_file/FileSelector.h b/src/add-ons/print/transports/print_to_file/FileSelector.h new file mode 100644 index 0000000000..b94f65ca26 --- /dev/null +++ b/src/add-ons/print/transports/print_to_file/FileSelector.h @@ -0,0 +1,38 @@ +#ifndef FILESELECTOR_H +#define FILESELECTOR_H + +#include +#include + +class FileSelector : public BWindow +{ + public: + // Constructors, destructors, operators... + + FileSelector(void); + ~FileSelector(void); + + typedef BWindow inherited; + + // public constantes + enum { + START_MSG = 'strt', + SAVE_INTO_MSG = 'save' + }; + + // Virtual function overrides + public: + virtual void MessageReceived(BMessage * msg); + virtual bool QuitRequested(); + status_t Go(entry_ref * ref); + + // From here, it's none of your business! ;-) + private: + BEntry m_entry; + volatile status_t m_result; + long m_exit_sem; + BFilePanel * m_save_panel; +}; + +#endif // FILESELECTOR_H + diff --git a/src/add-ons/print/transports/print_to_file/print_transport.cpp b/src/add-ons/print/transports/print_to_file/print_transport.cpp new file mode 100644 index 0000000000..4f6dc13c61 --- /dev/null +++ b/src/add-ons/print/transports/print_to_file/print_transport.cpp @@ -0,0 +1,84 @@ +#include + +#include +#include + +#include "FileSelector.h" + +static BList * g_files_list = NULL; +static uint32 g_nb_files = 0; + +status_t AddFile(BFile * file); +status_t RemoveFile(); + +extern "C" _EXPORT void exit_transport() +{ + printf("exit_transport\n"); + RemoveFile(); +} + +extern "C" _EXPORT BDataIO * init_transport + ( + BMessage * msg + ) +{ + BFile * file; + FileSelector * selector; + entry_ref ref; + + printf("init_transport\n"); + + selector = new FileSelector(); + if (selector->Go(&ref) != B_OK) + return NULL; + + file = new BFile(&ref, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); + if ( file->InitCheck() != B_OK ) + { + delete file; + return NULL; + }; + + AddFile(file); + return file; +} + +status_t AddFile(BFile * file) +{ + if (!file) + return B_ERROR; + + if (!g_files_list) + { + g_files_list = new BList(); + g_nb_files = 0; + }; + + g_files_list->AddItem(file); + g_nb_files++; + + printf("AddFile: %ld file transport(s) instanciated\n", g_nb_files); + + return B_OK; +} + +status_t RemoveFile() +{ + void * file; + int32 i; + + g_nb_files--; + + printf("RemoveFile: %ld file transport(s) still instanciated\n", g_nb_files); + + if (g_nb_files) + return B_OK; + + printf("RemoveFile: deleting files list...\n"); + + for (i = 0; (file = g_files_list->ItemAt(i)); i++) + delete file; + + delete g_files_list; + return B_OK; +} diff --git a/src/add-ons/print/transports/shared/DbgMsg.cpp b/src/add-ons/print/transports/shared/DbgMsg.cpp new file mode 100644 index 0000000000..726eb51156 --- /dev/null +++ b/src/add-ons/print/transports/shared/DbgMsg.cpp @@ -0,0 +1,237 @@ +// Sun, 18 Jun 2000 +// Y.Takagi + +#include +#include + +#include +#include +#include +#include + +#include "DbgMsg.h" + +#ifdef _DEBUG + +#if (!__MWERKS__ || defined(MSIPL_USING_NAMESPACE)) +using namespace std; +#else +#define std +#endif + +void write_debug_stream(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + FILE *f = fopen("/boot/home/transport.log", "aw+"); + vfprintf(f, format, ap); + fclose(f); + va_end(ap); +} + + +void DUMP_BFILE(BFile *in, const char *path) +{ + off_t size; + if (B_NO_ERROR == in->GetSize(&size)) { + uchar *buffer = new uchar[size]; + in->Read(buffer, size); + BFile out(path, B_WRITE_ONLY | B_CREATE_FILE); + out.Write(buffer, size); + in->Seek(0, SEEK_SET); + delete [] buffer; + } +} + + +void DUMP_BMESSAGE(BMessage *msg) +{ + uint32 i; + int32 j; + char *name = ""; + uint32 type = 0; + int32 count = 0; + + DBGMSG(("\t************ START - DUMP BMessage ***********\n")); + DBGMSG(("\taddress: 0x%x\n", (int)msg)); + if (!msg) + return; + +#if (!__MWERKS__) + DBGMSG(("\tmsg->what: %c%c%c%c\n", + *((char *)&msg->what + 3), + *((char *)&msg->what + 2), + *((char *)&msg->what + 1), + *((char *)&msg->what + 0))); +#else + DBGMSG(("\tmsg->what: %c%c%c%c\n", + *((char *)&msg->what + 0), + *((char *)&msg->what + 1), + *((char *)&msg->what + 2), + *((char *)&msg->what + 3))); +#endif + + for (i= 0; msg->GetInfo(B_ANY_TYPE, i, &name, &type, &count) == B_OK; i++) { + switch (type) { + case B_BOOL_TYPE: + for (j = 0; j < count; j++) { + bool aBool; + aBool = msg->FindBool(name, j); + DBGMSG(("\t%s, B_BOOL_TYPE[%d]: %s\n", + name, j, aBool ? "true" : "false")); + } + break; + + case B_INT8_TYPE: + for (j = 0; j < count; j++) { + int8 anInt8; + msg->FindInt8(name, j, &anInt8); + DBGMSG(("\t%s, B_INT8_TYPE[%d]: %d\n", name, j, (int)anInt8)); + } + break; + + case B_INT16_TYPE: + for (j = 0; j < count; j++) { + int16 anInt16; + msg->FindInt16(name, j, &anInt16); + DBGMSG(("\t%s, B_INT16_TYPE[%d]: %d\n", name, j, (int)anInt16)); + } + break; + + case B_INT32_TYPE: + for (j = 0; j < count; j++) { + int32 anInt32; + msg->FindInt32(name, j, &anInt32); + DBGMSG(("\t%s, B_INT32_TYPE[%d]: %d\n", name, j, (int)anInt32)); + } + break; + + case B_INT64_TYPE: + for (j = 0; j < count; j++) { + int64 anInt64; + msg->FindInt64(name, j, &anInt64); + DBGMSG(("\t%s, B_INT64_TYPE[%d]: %d\n", name, j, (int)anInt64)); + } + break; + + case B_FLOAT_TYPE: + for (j = 0; j < count; j++) { + float aFloat; + msg->FindFloat(name, j, &aFloat); + DBGMSG(("\t%s, B_FLOAT_TYPE[%d]: %f\n", name, j, aFloat)); + } + break; + + case B_DOUBLE_TYPE: + for (j = 0; j < count; j++) { + double aDouble; + msg->FindDouble(name, j, &aDouble); + DBGMSG(("\t%s, B_DOUBLE_TYPE[%d]: %f\n", name, j, (float)aDouble)); + } + break; + + case B_STRING_TYPE: + for (j = 0; j < count; j++) { + const char *string; + msg->FindString(name, j, &string); + DBGMSG(("\t%s, B_STRING_TYPE[%d]: %s\n", name, j, string)); + } + break; + + case B_POINT_TYPE: + for (j = 0; j < count; j++) { + BPoint aPoint; + msg->FindPoint(name, j, &aPoint); + DBGMSG(("\t%s, B_POINT_TYPE[%d]: %f, %f\n", + name, j, aPoint.x, aPoint.y)); + } + break; + + case B_RECT_TYPE: + for (j = 0; j < count; j++) { + BRect aRect; + msg->FindRect(name, j, &aRect); + DBGMSG(("\t%s, B_RECT_TYPE[%d]: %f, %f, %f, %f\n", + name, j, aRect.left, aRect.top, aRect.right, aRect.bottom)); + } + break; + + case B_REF_TYPE: + case B_MESSAGE_TYPE: + case B_MESSENGER_TYPE: + case B_POINTER_TYPE: + DBGMSG(("\t%s, 0x%x, count: %d\n", + name ? name : "(null)", type, count)); + break; + default: + DBGMSG(("\t%s, 0x%x, count: %d\n", + name ? name : "(null)", type, count)); + break; + } + + name = ""; + type = 0; + count = 0; + } + DBGMSG(("\t************ END - DUMP BMessage ***********\n")); +} + +#define PD_DRIVER_NAME "Driver Name" +#define PD_PRINTER_NAME "Printer Name" +#define PD_COMMENTS "Comments" + +void DUMP_BDIRECTORY(BDirectory *dir) +{ + char buffer1[256]; + char buffer2[256]; + attr_info info; + int32 i; + float f; + BRect rc; + bool b; + + DBGMSG(("\t************ STRAT - DUMP BDirectory ***********\n")); + + dir->RewindAttrs(); + while (dir->GetNextAttrName(buffer1) == B_NO_ERROR) { + dir->GetAttrInfo(buffer1, &info); + switch (info.type) { + case B_ASCII_TYPE: + dir->ReadAttr(buffer1, info.type, 0, buffer2, sizeof(buffer2)); + DBGMSG(("\t%s, B_ASCII_TYPE: %s\n", buffer1, buffer2)); + break; + case B_STRING_TYPE: + dir->ReadAttr(buffer1, info.type, 0, buffer2, sizeof(buffer2)); + DBGMSG(("\t%s, B_STRING_TYPE: %s\n", buffer1, buffer2)); + break; + case B_INT32_TYPE: + dir->ReadAttr(buffer1, info.type, 0, &i, sizeof(i)); + DBGMSG(("\t%s, B_INT32_TYPE: %d\n", buffer1, i)); + break; + case B_FLOAT_TYPE: + dir->ReadAttr(buffer1, info.type, 0, &f, sizeof(f)); + DBGMSG(("\t%s, B_FLOAT_TYPE: %f\n", buffer1, f)); + break; + case B_RECT_TYPE: + dir->ReadAttr(buffer1, info.type, 0, &rc, sizeof(rc)); + DBGMSG(("\t%s, B_RECT_TYPE: %f, %f, %f, %f\n", buffer1, rc.left, rc.top, rc.right, rc.bottom)); + break; + case B_BOOL_TYPE: + dir->ReadAttr(buffer1, info.type, 0, &b, sizeof(b)); + DBGMSG(("\t%s, B_BOOL_TYPE: %d\n", buffer1, (int)b)); + break; + default: + DBGMSG(("\t%s, %c%c%c%c\n", + buffer1, + *((char *)&info.type + 3), + *((char *)&info.type + 2), + *((char *)&info.type + 1), + *((char *)&info.type + 0))); + break; + } + } + + DBGMSG(("\t************ END - DUMP BDirectory ***********\n")); +} + +#endif /* _DEBUG */ diff --git a/src/add-ons/print/transports/shared/DbgMsg.h b/src/add-ons/print/transports/shared/DbgMsg.h new file mode 100644 index 0000000000..85bde9af43 --- /dev/null +++ b/src/add-ons/print/transports/shared/DbgMsg.h @@ -0,0 +1,20 @@ +// Sun, 18 Jun 2000 +// Y.Takagi + +#ifndef __DBGMSG_H +#define __DBGMSG_H + +#ifdef _DEBUG + void write_debug_stream(const char *, ...); + void DUMP_BFILE(BFile *file, const char *name); + void DUMP_BMESSAGE(BMessage *msg); + void DUMP_BDIRECTORY(BDirectory *dir); + #define DBGMSG(args) write_debug_stream args +#else + #define DUMP_BFILE(file, name) (void)0 + #define DUMP_BMESSAGE(msg) (void)0 + #define DUMP_BDIRECTORY(dir) (void)0 + #define DBGMSG(args) (void)0 +#endif + +#endif /* __DBGMSG_H */ diff --git a/src/add-ons/print/transports/shared/Socket.cpp b/src/add-ons/print/transports/shared/Socket.cpp new file mode 100644 index 0000000000..13c342a165 --- /dev/null +++ b/src/add-ons/print/transports/shared/Socket.cpp @@ -0,0 +1,193 @@ +// Sun, 18 Jun 2000 +// Y.Takagi + +#ifdef WIN32 +#include +#else +#include +#include +#endif // WIN32 + +#include +#include "Socket.h" +#include "SocketStream.h" + +#ifndef INADDR_NONE +#define INADDR_NONE 0xffffffff +#endif + +#ifdef WIN32 + #define EADDRINUSE WSAEADDRINUSE + #define errno WSAGetLastError() +#else + #include +#endif + +#ifdef WIN32 +class WIN32SOCKET { +public: + WIN32SOCKET() + { + WSADATA winsockdata; + WSAStartup(MAKEWORD(1,1), &winsockdata); + } + ~WIN32SOCKET() + { + WSACleanup(); + } +}; + +WIN32SOCKET win32socket; +#endif + +Socket::Socket(const char *host, int port) + : __sock(-1), __is(NULL), __os(NULL), __error(false) +{ + __host = host; + __port = port; + __localPort = -1; + __error_msg[0] = '\0'; + + open(); +} + +Socket::Socket(const char *host, int port, int localPort) + : __sock(-1), __is(NULL), __os(NULL), __error(false) +{ + __host = host; + __port = port; + __localPort = localPort; + __error_msg[0] = '\0'; + + open(); +} + +Socket::~Socket() +{ + close(); + if (__is) { + delete __is; + } + if (__os) { + delete __os; + } +} + +istream &Socket::getInputStream() +{ + if (__is == NULL) { + __is = new isocketstream(this); + } + return *__is; +} + +ostream &Socket::getOutputStream() +{ + if (__os == NULL) { + __os = new osocketstream(this); + } + return *__os; +} + +void Socket::open() +{ + if (__sock == -1 && !__error) { + + sockaddr_in sin; + memset(&sin, 0, sizeof(sin)); + + unsigned long inaddr; + hostent *host_info; + + if ((inaddr = inet_addr(__host.c_str())) != INADDR_NONE) { + memcpy(&sin.sin_addr, &inaddr, sizeof(inaddr)); + sin.sin_family = AF_INET; + } else if ((host_info = gethostbyname(__host.c_str())) != NULL) { + memcpy(&sin.sin_addr, host_info->h_addr, host_info->h_length); + sin.sin_family = host_info->h_addrtype; + } else { + sprintf(__error_msg, "gethostbyname failed. errno = %d", errno); + __error = true; + return; + } + + if ((__sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + sprintf(__error_msg, "socket failed. errno = %d", errno); + __error = true; + } else { + if (__localPort >= 0) { + sockaddr_in cin; + memset(&cin, 0, sizeof(cin)); + cin.sin_family = AF_INET; + cin.sin_port = htons(__localPort); + if (::bind(__sock, (sockaddr *)&cin, sizeof(cin)) != 0) { + sprintf(__error_msg, "bind failed. errno = %d", errno); + ::closesocket(__sock); + __sock = -1; + __error = true; + } + } + sin.sin_port = htons(__port); + if (::connect(__sock, (sockaddr *)&(sin), sizeof(sin)) != 0) { + sprintf(__error_msg, "connect failed. errno = %d", errno); + ::closesocket(__sock); + __sock = -1; + __error = true; + } + } + } +} + +void Socket::close() +{ + if (__sock != -1) { + ::shutdown(__sock, 2); + ::closesocket(__sock); + __sock = -1; + } +} + +bool Socket::fail() const +{ + return __sock == -1 || __error; +} + +bool Socket::good() const +{ + return !fail(); +} + +bool Socket::operator !() const +{ + return fail(); +} + +int Socket::read(char *buffer, int size, int flags) +{ + if (fail()) { + size = 0; + } else { + size = ::recv(__sock, buffer, size, flags); + if (size <= 0) { + sprintf(__error_msg, "recv failed. errno = %d", errno); + __error = true; + close(); + } + } + return size; +} + +int Socket::write(const char *buffer, int size, int flags) +{ + if (fail()) { + size = 0; + } else { + size = ::send(__sock, buffer, size, flags); + if (size <= 0) { + sprintf(__error_msg, "send failed. errno = %d", errno); + __error = true; + close(); + } + } + return size; +} diff --git a/src/add-ons/print/transports/shared/Socket.h b/src/add-ons/print/transports/shared/Socket.h new file mode 100644 index 0000000000..844fa52d16 --- /dev/null +++ b/src/add-ons/print/transports/shared/Socket.h @@ -0,0 +1,68 @@ +// Sun, 18 Jun 2000 +// Y.Takagi + +#ifndef __Socket_H +#define __Socket_H + +#ifdef WIN32 +#include +#include +#else +#include +#include +#endif // WIN32 + +#include + +#if (!__MWERKS__ || defined(WIN32)) +using namespace std; +#else +#define std +#endif + +class Socket { +public: + Socket(const char *host, int port); + Socket(const char *host, int port, int localPort); + ~Socket(); + + bool operator !() const; + bool good() const; + bool fail() const; + + void close(); + int read(char *buffer, int size, int flags = 0); + int write(const char *buffer, int size, int flags = 0); + + istream &getInputStream(); + ostream &getOutputStream(); + + int getPort() const; + const char *getLastError() const; + +private: + Socket(const Socket &); + Socket &operator = (const Socket &); + void open(); + + string __host; + int __port; + int __localPort; + int __sock; + istream *__is; + ostream *__os; + bool __error; + char __error_msg[256]; +}; + +inline int Socket::getPort() const +{ + return __port; +} + +inline const char *Socket::getLastError() const +{ + return __error_msg; +} + +#endif // __Socket_H diff --git a/src/add-ons/print/transports/shared/SocketStream.h b/src/add-ons/print/transports/shared/SocketStream.h new file mode 100644 index 0000000000..9f32693c03 --- /dev/null +++ b/src/add-ons/print/transports/shared/SocketStream.h @@ -0,0 +1,8 @@ +// Sun, 18 Jun 2000 +// Y.Takagi + +#ifdef WIN32 +#include "SocketStream1.h" +#else +#include "SocketStream2.h" +#endif diff --git a/src/add-ons/print/transports/shared/SocketStream1.cpp b/src/add-ons/print/transports/shared/SocketStream1.cpp new file mode 100644 index 0000000000..d2e69b0ae2 --- /dev/null +++ b/src/add-ons/print/transports/shared/SocketStream1.cpp @@ -0,0 +1,124 @@ +// Sun, 18 Jun 2000 +// Y.Takagi + +#ifdef WIN32 +#include + +#ifdef _DEBUG +#include +#include +#endif + +#include "Socket.h" +#include "SocketStream.h" + +namespace std { + +/*-----------------------------------------------------------------*/ + +socketstreambuf::socketstreambuf(Socket *sock, streamsize n) + : basic_streambuf(), __alsize(n), __sock(sock), __pu(NULL), __po(NULL) +{ + setg(0, 0, 0); + setp(0, 0); +} + +socketstreambuf::~socketstreambuf() +{ + if (__pu) + delete [] __pu; + if (__po) + delete [] __po; +} + + +socketstreambuf::int_type socketstreambuf::underflow() +{ +// cout << "***** underflow" << endl; + + if (__pu == NULL) { + __pu = new char[__alsize]; + } + + int bytes = __sock->read(__pu, __alsize); + if (bytes > 0) { +#ifdef _DEBUG + ofstream ofs("recv.log", ios::binary | ios::app); + ofs.write(__pu, bytes); +#endif + setg(__pu, __pu, __pu + bytes); + return traits::to_int_type(*gptr()); + } + + return traits::eof(); +} + +socketstreambuf::int_type socketstreambuf::overflow(socketstreambuf::int_type c) +{ +// cout << "***** overflow" << endl; + + if (__po == NULL) { + __po = new char[__alsize]; + setp(__po, __po + __alsize); + } else if (sync() != 0) { + return traits::eof(); + } + return sputc(c); +} + +int socketstreambuf::sync() +{ +// cout << "***** sync" << endl; + + if (__po) { + int length = pptr() - pbase(); + if (length > 0) { + const char *buffer = pbase(); + int bytes; + while (length > 0) { + bytes = __sock->write(buffer, length); + if (bytes <= 0) { + return EOF; + } +#ifdef _DEBUG + ofstream ofs("send.log", ios::binary | ios::app); + ofs.write(buffer, bytes); +#endif + length -= bytes; + buffer += bytes; + } + pbump(pbase() - pptr()); + } + } + + return 0; +} + +/*-----------------------------------------------------------------*/ + +isocketstream::isocketstream(Socket *sock, streamsize n) + : basic_istream(&ssb_), ssb_(sock, n) +{ +} + +isocketstream::~isocketstream() +{ +} + +/*-----------------------------------------------------------------*/ + +osocketstream::osocketstream(Socket *sock, streamsize n) + : basic_ostream(&ssb_), ssb_(sock, n) +{ +} + +osocketstream::~osocketstream() +{ + flush(); +} + +/*-----------------------------------------------------------------*/ + +} + +#endif // WIN32 diff --git a/src/add-ons/print/transports/shared/SocketStream1.h b/src/add-ons/print/transports/shared/SocketStream1.h new file mode 100644 index 0000000000..79359886a9 --- /dev/null +++ b/src/add-ons/print/transports/shared/SocketStream1.h @@ -0,0 +1,81 @@ +// Sun, 18 Jun 2000 +// Y.Takagi + +#ifndef __SocketStream1_H +#define __SocketStream1_H + +#include +#include +#include + +class Socket; + +namespace std { + +class socketstreambuf : public basic_streambuf< char, char_traits > { +public: + typedef char char_type; + typedef char_traits traits; + typedef traits::int_type int_type; + typedef traits::pos_type pos_type; + typedef traits::off_type off_type; + + explicit socketstreambuf(Socket *sock, streamsize n); + virtual ~socketstreambuf(); + +protected: + virtual int_type underflow(); + virtual int_type overflow(int_type c = traits::eof()); + virtual int sync(); + +private: + Socket *__sock; + streamsize __alsize; + char *__pu; + char *__po; +}; + +class isocketstream : public basic_istream< char, char_traits > { +public: + typedef char char_type; + typedef char_traits traits; + typedef traits::int_type int_type; + typedef traits::pos_type pos_type; + typedef traits::off_type off_type; + + explicit isocketstream(Socket *sock, streamsize n = 4096); + virtual ~isocketstream(); + + socketstreambuf *rdbuf() const + { + return (socketstreambuf *)basic_ios::rdbuf(); + } + +private: + socketstreambuf ssb_; +}; + + +class osocketstream : public basic_ostream< char, char_traits > { +public: + typedef char char_type; + typedef char_traits traits; + typedef traits::int_type int_type; + typedef traits::pos_type pos_type; + typedef traits::off_type off_type; + + explicit osocketstream(Socket *sock, streamsize n = 4096); + virtual ~osocketstream(); + + socketstreambuf *rdbuf() const + { + return (socketstreambuf *)basic_ios::rdbuf(); + } + +private: + socketstreambuf ssb_; +}; + +} + +#endif // __SocketStream1_H diff --git a/src/add-ons/print/transports/shared/SocketStream2.cpp b/src/add-ons/print/transports/shared/SocketStream2.cpp new file mode 100644 index 0000000000..9802fd1ae8 --- /dev/null +++ b/src/add-ons/print/transports/shared/SocketStream2.cpp @@ -0,0 +1,127 @@ +// Sun, 18 Jun 2000 +// Y.Takagi + +#ifndef WIN32 +#include + +#ifdef _DEBUG +#include +#include +#endif + +#include "Socket.h" +#include "SocketStream.h" + +/*-----------------------------------------------------------------*/ + +socketstreambuf::socketstreambuf(Socket *sock, streamsize n) + : streambuf(), __alsize(n), __sock(sock), __pu(NULL), __po(NULL) +{ + setg(0, 0, 0); + setp(0, 0); +} + +socketstreambuf::~socketstreambuf() +{ + if (__pu) + delete [] __pu; + if (__po) + delete [] __po; +} + +int socketstreambuf::underflow() +{ +// cout << "***** underflow" << endl; + + int bytes; + + if (__pu == NULL) { + __pu = new char[__alsize]; + } + + bytes = __sock->read(__pu, __alsize); + if (bytes > 0) { +#ifdef _DEBUG + ofstream ofs("recv.log", ios::binary | ios::app); + ofs.write(__pu, bytes); +#endif + setg(__pu, __pu, __pu + bytes); + return *gptr(); + } + + return EOF; +} + +int socketstreambuf::overflow(int c) +{ +// cout << "***** overflow" << endl; + + if (__po == NULL) { + __po = new char[__alsize]; + setp(__po, __po + __alsize); + } else if (sync() != 0) { + return EOF; + } + return sputc(c); +} + +int socketstreambuf::sync() +{ +// cout << "***** sync" << endl; + + if (__po) { + int length = pptr() - pbase(); + if (length > 0) { + const char *buffer = pbase(); + int bytes; + while (length > 0) { + bytes = __sock->write(buffer, length); + if (bytes <= 0) { + return EOF; + } +#ifdef _DEBUG + ofstream ofs("send.log", ios::binary | ios::app); + ofs.write(buffer, bytes); +#endif + length -= bytes; + buffer += bytes; + } + pbump(pbase() - pptr()); + } + } + + return 0; +} + +/* -------------------------------------------------------------- */ + +socketstreambase::socketstreambase(Socket *sock, streamsize n) + : buf(sock, n) +{ + ios::init(&this->buf); +} + +/*-----------------------------------------------------------------*/ + +isocketstream::isocketstream(Socket *sock, streamsize n) + : socketstreambase(sock, n), istream(socketstreambase::rdbuf()) +{ +} + +isocketstream::~isocketstream() +{ +} + +/*-----------------------------------------------------------------*/ + +osocketstream::osocketstream(Socket *sock, streamsize n) + : socketstreambase(sock, n), ostream(socketstreambase::rdbuf()) +{ +} + +osocketstream::~osocketstream() +{ + flush(); +} + +#endif // !WIN32 diff --git a/src/add-ons/print/transports/shared/SocketStream2.h b/src/add-ons/print/transports/shared/SocketStream2.h new file mode 100644 index 0000000000..1c8e3d05e4 --- /dev/null +++ b/src/add-ons/print/transports/shared/SocketStream2.h @@ -0,0 +1,60 @@ +// Sun, 18 Jun 2000 +// Y.Takagi + +#ifndef __SocketStream2_H +#define __SocketStream2_H + +#include +#include +#include + +class Socket; + +class socketstreambuf : public streambuf { +public: + explicit socketstreambuf(Socket *sock, streamsize n); + ~socketstreambuf(); + +protected: + virtual int underflow(); + virtual int overflow(int); + virtual int sync(); + +private: + Socket *__sock; + streamsize __alsize; + char *__pu; + char *__po; +}; + +class socketstreambase : public virtual ios { +public: + socketstreambuf *rdbuf(); + +protected: + socketstreambase(Socket *sock, streamsize n); + ~socketstreambase() {} + +private: + socketstreambuf buf; +}; + +inline socketstreambuf *socketstreambase::rdbuf() +{ + return &this->buf; +} + +class isocketstream : public socketstreambase, public istream { +public: + explicit isocketstream(Socket *sock, streamsize n = 4096); + virtual ~isocketstream(); +}; + + +class osocketstream : public socketstreambase, public ostream { +public: + explicit osocketstream(Socket *sock, streamsize n = 4096); + virtual ~osocketstream(); +}; + +#endif // __SocketStream2_H diff --git a/src/apps/Jamfile b/src/apps/Jamfile new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/apps/bin/alert.cpp b/src/apps/bin/alert.cpp new file mode 100644 index 0000000000..09cc26719f --- /dev/null +++ b/src/apps/bin/alert.cpp @@ -0,0 +1,228 @@ +/********************************************************************* +** Alert Applet +********************************************************************** +** 2002-04-28 Mathew Hounsell Created. +*/ + +#include +#include + +#include +#include +#include +#include + +/********************************************************************* +*/ + +// #define SIGNATURE "application/x-vnd.Be-cmd-alert" +#define SIGNATURE "application/x-vnd.OBOS.cmd-alert" +#define APP_NAME "alert" + +#define BUTTON_DEFAULT "OK" + +#define ERR_INIT_FAIL 127 +#define ERR_ARGS_FAIL 126 +#define ERR_NONE 0 + +/********************************************************************* +*/ +class Arguments { + bool ok, recved, modal; + alert_type icon; + char *arg_text, *arg_but0, *arg_but1, *arg_but2; + char *choice_text; + int32 choice; +public: + Arguments( void ) { + ok = recved = modal = false; + icon = B_INFO_ALERT; + arg_text = arg_but0 = arg_but1 = arg_but2 = 0; + choice = 0; + } + ~Arguments( void ) { + std::free( arg_text ); + std::free( arg_but0 ); + std::free( arg_but1 ); + std::free( arg_but2 ); + } + + inline bool Good( void ) const { return ok; } + inline bool Bad( void ) const { return ! ok; } + + void ArgvReceived( int32 argc, char **argv ) + { + recved = true; + + if( argc < 2 ) return; + + int32 start = 1; + bool flag_icon = false; + + // Look for '--' options' + for( int32 i = 1; i < argc; ++i, ++start ) { + if( '-' == argv[i][0] && '-' == argv[i][1] ) { + if( 0 == strcmp( argv[i] + 2, "modal" ) ) { + modal = true; +// } else if( 0 == strcmp( argv[i] + 2, "empty" ) +// || 0 == strcmp( argv[i] + 2, "none" ) ) { + } else if( 0 == strcmp( argv[i] + 2, "empty" ) ) { + if( flag_icon ) return; + icon = B_EMPTY_ALERT; + flag_icon = true; + } else if( 0 == strcmp( argv[i] + 2, "info" ) ) { + if( flag_icon ) return; + icon = B_INFO_ALERT; + flag_icon = true; + } else if( 0 == strcmp( argv[i] + 2, "idea" ) ) { + if( flag_icon ) return; + icon = B_IDEA_ALERT; + flag_icon = true; +// } else if( 0 == strcmp( argv[i] + 2, "warning" ) +// || 0 == strcmp( argv[i] + 2, "warn" ) ) { + } else if( 0 == strcmp( argv[i] + 2, "warning" ) ) { + if( flag_icon ) return; + icon = B_WARNING_ALERT; + flag_icon = true; + } else if( 0 == strcmp( argv[i] + 2, "stop" ) ) { + if( flag_icon ) return; + icon = B_STOP_ALERT; + flag_icon = true; + } else { + return; + } + } else break; + } + + if( start >= argc ) { // Nothing but --modal + return; + } + + arg_text = strdup( argv[start++] ); + if( start < argc ) arg_but0 = strdup( argv[start++] ); + else arg_but0 = strdup( BUTTON_DEFAULT ); + if( start < argc ) arg_but1 = strdup( argv[start++] ); + if( start < argc ) arg_but2 = strdup( argv[start++] ); + + ok = true; + } + + inline char const * Title( void ) const { return APP_NAME; } + + inline char const * Text( void ) const { return arg_text; } + inline char const * ButtonZero( void ) const { return arg_but0; } + inline char const * ButtonOne( void ) const { return arg_but1; } + inline char const * ButtonTwo( void ) const { return arg_but2; } + + inline alert_type Type( void ) const { return icon; } + + inline bool IsModal( void ) const { return modal; } + + inline bool Received( void ) const { return recved; } + + inline int32 ChoiceNumber( void ) const { return choice; } + inline char const * ChoiceText( void ) const { return choice_text; } + + void SetChoice( int32 but ) + { + assert( but >= 0 && but <= 2 ); + + choice = but; + switch( choice ) { + case 0: choice_text = arg_but0; break; + case 1: choice_text = arg_but1; break; + case 2: choice_text = arg_but2; break; + } + } + + void Usage( void ) + { + fprintf( + stderr, + "usage: " APP_NAME " ] [ --modal ] [ --help ] text [ button1 [ button2 [ button3 ]]]\n" + " is --empty | --info | --idea | --warning | --stop\n" + "--modal makes the alert system modal and shows it in all workspaces.\n" + "If any button argument is given, exit status is button number (starting with 0)\n" + " and '" APP_NAME "' will print the title of the button pressed to stdout.\n" + ); + } + +} arguments; + +/********************************************************************* +*/ +class AlertApplication : public BApplication { + typedef BApplication super; + +public: + AlertApplication( void ) : super( SIGNATURE ) { } + // No destructor as it crashes app. + + virtual void ArgvReceived( int32 argc, char **argv ) + { + if( ! arguments.Received() ) { + arguments.ArgvReceived( argc, argv ); + } + } + + // Prepare to Run + virtual void ReadyToRun(void) { + + if( arguments.Good() ) { + BAlert * alert_p + = new BAlert( + arguments.Title(), + arguments.Text(), + arguments.ButtonZero(), + arguments.ButtonOne(), + arguments.ButtonTwo(), + B_WIDTH_AS_USUAL, + arguments.Type() + ); + + if( arguments.IsModal() ) { + alert_p->SetFeel( B_MODAL_ALL_WINDOW_FEEL ); + } + + arguments.SetChoice( alert_p->Go() ); + } + + Quit(); + } +}; + +/********************************************************************* +** Acording to the BeBook youm should use the message handling in +** BApplication for arguments. However that requires the app to +** be created. +*/ +int main( int argc, char ** argv ) +{ + arguments.ArgvReceived( int32(argc), argv ); + if( ! arguments.Good() ) { + arguments.Usage(); + return ERR_ARGS_FAIL; + } + + int errorlevel = ERR_NONE; + + // App is Automatically assigned to be_app + new AlertApplication(); + + if( B_OK != be_app->InitCheck() ) { + // Cast for the right version. + errorlevel = ERR_INIT_FAIL; + } else { + // Run + be_app->Run(); + if( ! arguments.Good() ) { // In case of Roster start. + arguments.Usage(); + errorlevel = ERR_ARGS_FAIL; + } else { + fprintf( stdout, "%s\n", arguments.ChoiceText() ); + errorlevel = arguments.ChoiceNumber(); + } + } + + return errorlevel; +} \ No newline at end of file diff --git a/src/apps/bin/chop.c b/src/apps/bin/chop.c new file mode 100644 index 0000000000..a5b5cc6111 --- /dev/null +++ b/src/apps/bin/chop.c @@ -0,0 +1,260 @@ +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ +// +// Copyright (c) 2001-2002, OpenBeOS +// +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// +// File: chop.c +// Author: Daniel Reinhold (danielre@users.sf.net) +// Description: splits one file into a collection of smaller files +// +// Notes: +// This program was written such that it would have identical output as from +// the original chop program included with BeOS R5. However, there are a few +// minor differences: +// +// a) using "chop -n" (with no other args) crashes the original version, +// but not this one. +// +// b) filenames are enclosed in single quotes here, but are not in the original. +// It is generally better to enquote filenames for error messages so that +// problems with the name (e.g extra space chars) can be more easily detected. +// +// c) this version checks for validity of the input file (including file size) +// before there is any attempt to open it -- this changes the error output +// slightly from the original in some situations. It can also prevent some +// weirdness. For example, the original version will take a command such as: +// +// chop /dev/ports/serial1 +// +// and attempt to open the device. If serial1 is unused, this will actually +// block while waiting for data from the serial port. This version will never +// encounter that because the device will be found to have size 0 which will +// abort immediately. Since the semantics of chop don't make sense for such +// devices as the source, this is really the better behavior (provided that +// anyone ever attempts to use such strange arguments, which is unlikely). +// +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ + +#include +#include +#include +#include +#include +#include +#include + + +void usage (void); +void do_chop (char *); +void chop_file (int, char *, off_t); + + + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// globals + +#define BLOCKSIZE 64 * 1024 // file data is read in BLOCKSIZE blocks +static char Block[BLOCKSIZE]; // and stored in the global Block array + +static int KBytesPerChunk = 1400; // determines size of output files + + +void +usage () + { + puts ("usage: chop [-n kbyte_per_chunk] file"); + puts ("Splits file into smaller files named file00, file01..."); + puts ("Default split size is 1400k"); + } + + + +int +main (int argc, char *argv[]) + { + char *arg = NULL; + char *first; + + if ((argc < 2) || (argc > 4)) + { + usage (); + return 0; + } + + first = *++argv; + + if (strcmp (first, "--help") == 0) + { + usage (); + return 0; + } + + if (strcmp (first, "-n") == 0) + { + if (--argc > 1) + { + char *num = *++argv; + + if (!isdigit (*num)) + printf ("-n option needs a numeric argument\n"); + else + { + int b = atoi (num); + + if (b < 1) b = 1; + KBytesPerChunk = b; + + if (--argc > 1) + arg = *++argv; + else + printf ("no file specified\n"); + } + } + else + printf ("-n option needs a numeric argument\n"); + } + else + arg = first; + + if (arg) + do_chop (arg); + + putchar ('\n'); + return 0; + } + + +void +do_chop (char *fname) + { + // do some checks for validity + // then call chop_file() to do the actual read/writes + + struct stat e; + off_t fsize; + int fd; + + // input file must exist + if (stat (fname, &e) == -1) + { + fprintf (stderr, "'%s': no such file or directory\n", fname); + return; + } + + // and it must be not be a directory + if (S_ISDIR (e.st_mode)) + { + fprintf (stderr, "'%s' is a directory\n", fname); + return; + } + + // needs to be big enough such that splitting it actually does something + fsize = e.st_size; + if (fsize < (KBytesPerChunk * 1024)) + { + fprintf (stderr, "'%s': file is already small enough\n", fname); + return; + } + + // also, don't chop up if chunk files are already present + { + char buf[256]; + strcpy (buf, fname); + strcat (buf, "00"); + + if (stat (buf, &e) >= 0) + { + fprintf (stderr, "'%s' already exists - aborting\n", buf); + return; + } + } + + // finally! chop up the file + fd = open (fname, O_RDONLY); + if (fd < 0) + fprintf (stderr, "can't open '%s': %s\n", fname, strerror (errno)); + else + { + chop_file (fd, fname, fsize); + close (fd); + } + } + + +void +chop_file (int fdin, char *fname, off_t fsize) + { + const off_t chunk_size = KBytesPerChunk * 1024; // max bytes written to any output file + + bool open_next_file = true; // when to open a new output file + char fnameN[256]; // name of the current output file (file01, file02, etc.) + int index = 0; // used to generate the next output file name + int fdout; // output file descriptor + + ssize_t got; // size of the current data block -- i.e. from the last read() + ssize_t put; // number of bytes just written -- i.e. from the last write() + ssize_t needed; // how many bytes we can safely write to the current output file + ssize_t avail; // how many bytes we can safely grab from the current data block + off_t curr_written; // number of bytes written to the current output file + off_t total_written = 0; // total bytes written out to all output files + + char *beg = Block; // pointer to the beginning of the block data to be written out + char *end = Block; // end of the current block (init to beginning to force first block read) + + printf ("Chopping up %s into %d kbyte chunks\n", fname, KBytesPerChunk); + + while (total_written < fsize) + { + if (beg >= end) + { + // read in another block + got = read (fdin, Block, BLOCKSIZE); + if (got <= 0) + break; + + beg = Block; + end = Block + got - 1; + } + + if (open_next_file) + { + // start a new output file + sprintf (fnameN, "%s%02d", fname, index++); + fdout = open (fnameN, O_WRONLY|O_CREAT); + if (fdout < 0) + { + fprintf (stderr, "unable to create chunk file '%s': %s\n", fnameN, strerror (errno)); + return; + } + curr_written = 0; + open_next_file = false; + } + + needed = chunk_size - curr_written; + avail = end - beg + 1; + if (needed > avail) + needed = avail; + + if (needed > 0) + { + put = write (fdout, beg, needed); + beg += put; + } + + curr_written += put; + total_written += put; + + if (curr_written >= chunk_size) + { + // the current output file is full + close (fdout); + open_next_file = true; + } + } + + // close up the last output file + close (fdout); + } diff --git a/src/apps/bin/clipboard.cpp b/src/apps/bin/clipboard.cpp new file mode 100644 index 0000000000..cfe56ea2ae --- /dev/null +++ b/src/apps/bin/clipboard.cpp @@ -0,0 +1,175 @@ +/*=============================================================== +** Clipboard - Applet - Code File +**=============================================================== +** 24 June 2002 - Mathew Hounsell - Created +*/ +#include "be/app/Clipboard.h" + +#include +#include + +#include + +/*=============================================================== +** Status +*/ +namespace Status { + + status_t Code = B_OK; +} + +/*=============================================================== +** Clipboard +*/ +namespace Clipboard { + + // Use system clipboard by default. + char const * Name = "system"; + bool InstanceExists = false; + + //----------------------------------------------------------- + class Locker { + private: BClipboard *clip; + public: Locker( BClipboard * nclip ) + : clip( nclip ) + { + if( ! ( InstanceExists = clip->Lock() ) ) + Status::Code = B_NAME_NOT_FOUND ; + } + public: ~Locker( void ) + { clip->Unlock(); } + }; + + //----------------------------------------------------------- + BClipboard * Instance = NULL; + + // Open or Create clipboard. + bool ConnectOrCreate( void ) { + Instance = new( std::nothrow ) BClipboard( Name ); + if( ! ( InstanceExists = ( Instance != NULL ) ) ) { + Status::Code = B_NO_MEMORY; + } + return InstanceExists; + } + + //----------------------------------------------------------- + bool Print( void ) { + // Retrieve Data - Concurrent Access Possible. + Locker clip_lock( Instance ); // Unlocks on destruction. + if( InstanceExists ) { + BMessage *data = NULL; + if( 0 == ( data = Instance->Data() ) ) { + Status::Code = B_NO_INIT; + } else { + // Clipboard fills in message + // Then tell message to print itself. + data->PrintToStream(); + } + } + } + + //----------------------------------------------------------- + bool Read( char const * entry_name ) { + // Retrieve Data - Concurrent Access Possible. + Locker clip_lock( Instance ); // Unlocks on destruction. + if( InstanceExists ) { + BMessage *data = NULL; + if( 0 == ( data = Instance->Data() ) ) { + Status::Code = B_NO_INIT; + } else { + type_code entry_type = 0; + int32 entry_count = 0; + + if( B_OK == ( Status::Code = data->GetInfo( entry_name, & entry_type, & entry_count ) ) ) { + ssize_t entry_size = 0; + void const * entry_data = 0; + + if( B_OK == ( Status::Code = data->FindData( entry_name, entry_type, & entry_data, & entry_size ) ) ) { + fwrite( entry_data, entry_size, 1, stdout ); + } + } + } + } + } +} + +/*=============================================================== +** Arguments +*/ +namespace Arguments { + enum { NONE, PRINT, READ, WRITE } Operation; + char const * ProgramName = ""; + + //----------------------------------------------------------- + void Usage( void ) + { + printf( "USAGE : %s -p [clipboard-name]\n", ProgramName ); + printf( "USAGE : %s -r [entry] [clipboard-name]\n", ProgramName ); + // printf( "USAGE : %s -w [entry] [clipboard-name]\n", ProgramName ); + } + + //----------------------------------------------------------- + void Decode( int const argc, char const * const * const argv ) + { + ProgramName = argv[0]; + Operation = NONE; + + // Test arguments. + if( argc < 2 || argc > 3 ) { + Usage(); + } else if( argv[1][0] != '-' ) { + Usage(); + } else if( argv[1][1] == 'p' && ( argc == 2 || argc == 3 ) ) { + Operation = PRINT; + } else if( argv[1][1] == 'r' && ( argc == 3 || argc == 4 ) ) { + Operation = READ; + // } else if( argv[1][1] == 'w' && ( argc == 3 || argc == 4 ) ) { + // op = WRITE; + } else { + Usage(); + } + + if( Operation == PRINT && argc == 3 ) { + // Use user clipboard. + Clipboard::Name = argv[2]; + } else if( ( Operation == READ || Operation == WRITE ) && argc == 4 ) { + // Use user clipboard. + Clipboard::Name = argv[3]; + } + } +} + +/*=============================================================== +** Main Routine +*/ +int main( int argc, char **argv ) +{ + Arguments::Decode( argc, argv ); + + if( Arguments::NONE == Arguments::Operation ) { + Status::Code = B_BAD_VALUE; + } else { + // Open or Create clipboard. + if( Clipboard::ConnectOrCreate() ) { + switch( Arguments::Operation ) { + case Arguments::PRINT: + Clipboard::Print(); + break; + case Arguments::READ: + Clipboard::Read( argv[2] ); + break; + } + } + } + + if( B_OK != Status::Code ) { + fputs( strerror( Status::Code ), stderr ); + fputc( '\n', stderr ); + return Status::Code; + } + return 0; +} + +/*=============================================================== +** End Of Code +*/ diff --git a/src/apps/bin/echo.c b/src/apps/bin/echo.c new file mode 100644 index 0000000000..1c6bc4156b --- /dev/null +++ b/src/apps/bin/echo.c @@ -0,0 +1,48 @@ +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ +// +// Copyright (c) 2001-2002, OpenBeOS +// +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// +// File: echo.c +// Author: Daniel Reinhold (danielre@users.sf.net) +// Description: standard Unix echo command +// +// Notes: +// the only command line option is "-n" which, if present, must appear +// before all the other command line args, and specifies to leave off +// the normal end-of-line character +// +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ + +#include +#include + + +int +main (int argc, char **argv) +{ + int eol = 1; + + if (argc > 1) { + char *first = *++argv; + + if (strcmp (first, "-n") == 0) + eol = 0; + + if (--argc) { + if (eol) + fprintf (stdout, "%s ", first); + while (--argc) + fprintf (stdout, "%s ", *++argv); + } + } + + if (eol) + fputc ('\n', stdout); + + fflush (stdout); + return 0; +} diff --git a/src/apps/bin/gnu/chgrp.c b/src/apps/bin/gnu/chgrp.c new file mode 100644 index 0000000000..60a18a63d0 --- /dev/null +++ b/src/apps/bin/gnu/chgrp.c @@ -0,0 +1,233 @@ +/* chgrp -- change group ownership of files + Copyright (C) 89, 90, 91, 1995-2001 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by David MacKenzie . */ + +#include +#include +#include +#include +#include + +#include "system.h" +#include "error.h" +#include "lchown.h" +#include "group-member.h" +#include "quote.h" +#include "savedir.h" +#include "xstrtol.h" +#include "chown-core.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "chgrp" + +#define AUTHORS "David MacKenzie" + +/* MAXUID may come from limits.h *or* sys/params.h (via system.h) above. */ +#ifndef MAXUID +# define MAXUID UID_T_MAX +#endif +#ifndef MAXGID +# define MAXGID GID_T_MAX +#endif + +#ifndef _POSIX_VERSION +struct group *getgrnam (); +#endif + +#if ! HAVE_ENDGRENT +# define endgrent() ((void) 0) +#endif + +/* The name the program was run with. */ +char *program_name; + +/* The argument to the --reference option. Use the group ID of this file. + This file must exist. */ +static char *reference_file; + +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + REFERENCE_FILE_OPTION = CHAR_MAX + 1, + DEREFERENCE_OPTION +}; + +static struct option const long_options[] = +{ + {"recursive", no_argument, 0, 'R'}, + {"changes", no_argument, 0, 'c'}, + {"dereference", no_argument, 0, DEREFERENCE_OPTION}, + {"no-dereference", no_argument, 0, 'h'}, + {"quiet", no_argument, 0, 'f'}, + {"silent", no_argument, 0, 'f'}, + {"reference", required_argument, 0, REFERENCE_FILE_OPTION}, + {"verbose", no_argument, 0, 'v'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {0, 0, 0, 0} +}; + +/* Set *G according to NAME. */ + +static void +parse_group (const char *name, gid_t *g) +{ + struct group *grp; + + if (*name == '\0') + error (1, 0, _("cannot change to null group")); + + grp = getgrnam (name); + if (grp == NULL) + { + strtol_error s_err; + unsigned long int tmp_long; + + if (!ISDIGIT (*name)) + error (1, 0, _("invalid group name %s"), quote (name)); + + s_err = xstrtoul (name, NULL, 0, &tmp_long, NULL); + if (s_err != LONGINT_OK) + STRTOL_FATAL_ERROR (name, _("group number"), s_err); + + if (tmp_long > MAXGID) + error (1, 0, _("invalid group number %s"), quote (name)); + + *g = tmp_long; + } + else + *g = grp->gr_gid; + endgrent (); /* Save a file descriptor. */ +} + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... GROUP FILE...\n\ + or: %s [OPTION]... --reference=RFILE FILE...\n\ +"), + program_name, program_name); + printf (_("\ +Change the group membership of each FILE to GROUP.\n\ +\n\ + -c, --changes like verbose but report only when a change is made\n\ + --dereference affect the referent of each symbolic link, rather\n\ + than the symbolic link itself\n\ + -h, --no-dereference affect symbolic links instead of any referenced file\n\ + (available only on systems that can change the\n\ + ownership of a symlink)\n\ + -f, --silent, --quiet suppress most error messages\n\ + --reference=RFILE use RFILE's group rather than the specified\n\ + GROUP value\n\ + -R, --recursive operate on files and directories recursively\n\ + -v, --verbose output a diagnostic for every file processed\n\ + --help display this help and exit\n\ + --version output version information and exit\n\ +")); + puts (_("\nReport bugs to .")); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + gid_t gid; + int errors = 0; + int optc; + struct Chown_option chopt; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + chopt_init (&chopt); + + while ((optc = getopt_long (argc, argv, "Rcfhv", long_options, NULL)) != -1) + { + switch (optc) + { + case 0: + break; + case REFERENCE_FILE_OPTION: + reference_file = optarg; + break; + case DEREFERENCE_OPTION: + chopt.dereference = DEREF_ALWAYS; + break; + case 'R': + chopt.recurse = 1; + break; + case 'c': + chopt.verbosity = V_changes_only; + break; + case 'f': + chopt.force_silent = 1; + break; + case 'h': + chopt.dereference = DEREF_NEVER; + break; + case 'v': + chopt.verbosity = V_high; + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (1); + } + } + + if (argc - optind + (reference_file ? 1 : 0) <= 1) + { + error (0, 0, _("too few arguments")); + usage (1); + } + + if (reference_file) + { + struct stat ref_stats; + if (stat (reference_file, &ref_stats)) + error (1, errno, _("getting attributes of %s"), quote (reference_file)); + + chopt.group_name = gid_to_name (ref_stats.st_gid); + gid = ref_stats.st_gid; + } + else + { + chopt.group_name = argv[optind++]; + parse_group (chopt.group_name, &gid); + } + + for (; optind < argc; ++optind) + errors |= change_file_owner (1, argv[optind], (uid_t) -1, gid, + (uid_t) -1, (gid_t) -1, &chopt); + + chopt_free (&chopt); + + exit (errors); +} diff --git a/src/apps/bin/gnu/chmod.c b/src/apps/bin/gnu/chmod.c new file mode 100644 index 0000000000..dd3c42dcdf --- /dev/null +++ b/src/apps/bin/gnu/chmod.c @@ -0,0 +1,396 @@ +/* chmod -- change permission modes of files + Copyright (C) 89, 90, 91, 1995-2000 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by David MacKenzie */ + +#include +#include +#include +#include + +#include "system.h" +#include "error.h" +#include "filemode.h" +#include "modechange.h" +#include "quote.h" +#include "savedir.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "chmod" + +#define AUTHORS "David MacKenzie" + +enum Change_status +{ + CH_SUCCEEDED, + CH_FAILED, + CH_NO_CHANGE_REQUESTED +}; + +enum Verbosity +{ + /* Print a message for each file that is processed. */ + V_high, + + /* Print a message for each file whose attributes we change. */ + V_changes_only, + + /* Do not be verbose. This is the default. */ + V_off +}; + +void strip_trailing_slashes (); + +static int change_dir_mode PARAMS ((const char *dir, + const struct mode_change *changes, + const struct stat *statp)); + +/* The name the program was run with. */ +char *program_name; + +/* If nonzero, change the modes of directories recursively. */ +static int recurse; + +/* If nonzero, force silence (no error messages). */ +static int force_silent; + +/* Level of verbosity. */ +static enum Verbosity verbosity = V_off; + +/* The argument to the --reference option. Use the owner and group IDs + of this file. This file must exist. */ +static char *reference_file; + +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + REFERENCE_FILE_OPTION = CHAR_MAX + 1 +}; + +static struct option const long_options[] = +{ + {"recursive", no_argument, 0, 'R'}, + {"changes", no_argument, 0, 'c'}, + {"silent", no_argument, 0, 'f'}, + {"quiet", no_argument, 0, 'f'}, + {"reference", required_argument, 0, REFERENCE_FILE_OPTION}, + {"verbose", no_argument, 0, 'v'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {0, 0, 0, 0} +}; + +static int +mode_changed (const char *file, mode_t old_mode) +{ + struct stat new_stats; + + if (lstat (file, &new_stats)) + { + if (force_silent == 0) + error (0, errno, _("getting new attributes of %s"), quote (file)); + return 0; + } + +#ifdef S_ISLNK + if (S_ISLNK (new_stats.st_mode) + && stat (file, &new_stats)) + { + if (force_silent == 0) + error (0, errno, _("getting new attributes of %s"), quote (file)); + return 0; + } +#endif + + return old_mode != new_stats.st_mode; +} + +/* Tell the user how/if the MODE of FILE has been changed. + CHANGED describes what (if anything) has happened. */ + +static void +describe_change (const char *file, mode_t mode, + enum Change_status changed) +{ + char perms[11]; /* "-rwxrwxrwx" ls-style modes. */ + const char *fmt; + + mode_string (mode, perms); + perms[10] = '\0'; /* `mode_string' does not null terminate. */ + switch (changed) + { + case CH_SUCCEEDED: + fmt = _("mode of %s changed to %04lo (%s)\n"); + break; + case CH_FAILED: + fmt = _("failed to change mode of %s to %04lo (%s)\n"); + break; + case CH_NO_CHANGE_REQUESTED: + fmt = _("mode of %s retained as %04lo (%s)\n"); + break; + default: + abort (); + } + printf (fmt, quote (file), + (unsigned long) (mode & CHMOD_MODE_BITS), &perms[1]); +} + +/* Change the mode of FILE according to the list of operations CHANGES. + If DEREF_SYMLINK is nonzero and FILE is a symbolic link, change the + mode of the referenced file. If DEREF_SYMLINK is zero, ignore symbolic + links. Return 0 if successful, 1 if errors occurred. */ + +static int +change_file_mode (const char *file, const struct mode_change *changes, + const int deref_symlink) +{ + struct stat file_stats; + mode_t newmode; + int errors = 0; + int fail; + int saved_errno; + + if (lstat (file, &file_stats)) + { + if (force_silent == 0) + error (0, errno, _("getting attributes of %s"), quote (file)); + return 1; + } +#ifdef S_ISLNK + if (S_ISLNK (file_stats.st_mode)) + { + if (! deref_symlink) + return 0; + else + if (stat (file, &file_stats)) + { + if (force_silent == 0) + error (0, errno, _("getting attributes of %s"), quote (file)); + return 1; + } + } +#endif + + newmode = mode_adjust (file_stats.st_mode, changes); + + fail = chmod (file, newmode); + saved_errno = errno; + + if (verbosity == V_high + || (verbosity == V_changes_only + && !fail && mode_changed (file, file_stats.st_mode))) + describe_change (file, newmode, (fail ? CH_FAILED : CH_SUCCEEDED)); + + if (fail) + { + if (force_silent == 0) + error (0, saved_errno, _("changing permissions of %s"), + quote (file)); + errors = 1; + } + + if (recurse && S_ISDIR (file_stats.st_mode)) + errors |= change_dir_mode (file, changes, &file_stats); + return errors; +} + +/* Recursively change the modes of the files in directory DIR + according to the list of operations CHANGES. + STATP points to the results of lstat on DIR. + Return 0 if successful, 1 if errors occurred. */ + +static int +change_dir_mode (const char *dir, const struct mode_change *changes, + const struct stat *statp) +{ + char *name_space, *namep; + char *path; /* Full path of each entry to process. */ + unsigned dirlength; /* Length of DIR and '\0'. */ + unsigned filelength; /* Length of each pathname to process. */ + unsigned pathlength; /* Bytes allocated for `path'. */ + int errors = 0; + + name_space = savedir (dir, statp->st_size); + if (name_space == NULL) + { + if (force_silent == 0) + error (0, errno, "%s", quote (dir)); + return 1; + } + + dirlength = strlen (dir) + 1; /* + 1 is for the trailing '/'. */ + pathlength = dirlength + 1; + /* Give `path' a dummy value; it will be reallocated before first use. */ + path = xmalloc (pathlength); + strcpy (path, dir); + path[dirlength - 1] = '/'; + + for (namep = name_space; *namep; namep += filelength - dirlength) + { + filelength = dirlength + strlen (namep) + 1; + if (filelength > pathlength) + { + pathlength = filelength * 2; + path = xrealloc (path, pathlength); + } + strcpy (path + dirlength, namep); + errors |= change_file_mode (path, changes, 0); + } + free (path); + free (name_space); + return errors; +} + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... MODE[,MODE]... FILE...\n\ + or: %s [OPTION]... OCTAL-MODE FILE...\n\ + or: %s [OPTION]... --reference=RFILE FILE...\n\ +"), + program_name, program_name, program_name); + printf (_("\ +Change the mode of each FILE to MODE.\n\ +\n\ + -c, --changes like verbose but report only when a change is made\n\ + -f, --silent, --quiet suppress most error messages\n\ + -v, --verbose output a diagnostic for every file processed\n\ + --reference=RFILE use RFILE's mode instead of MODE values\n\ + -R, --recursive change files and directories recursively\n\ + --help display this help and exit\n\ + --version output version information and exit\n\ +\n\ +Each MODE is one or more of the letters ugoa, one of the symbols +-= and\n\ +one or more of the letters rwxXstugo.\n\ +")); + puts (_("\nReport bugs to .")); + } + exit (status); +} + +/* Parse the ASCII mode given on the command line into a linked list + of `struct mode_change' and apply that to each file argument. */ + +int +main (int argc, char **argv) +{ + struct mode_change *changes; + int errors = 0; + int modeind = 0; /* Index of the mode argument in `argv'. */ + int thisind; + int c; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + recurse = force_silent = 0; + + while (1) + { + thisind = optind ? optind : 1; + + c = getopt_long (argc, argv, "RcfvrwxXstugoa,+-=", long_options, NULL); + if (c == -1) + break; + + switch (c) + { + case 0: + break; + case 'r': + case 'w': + case 'x': + case 'X': + case 's': + case 't': + case 'u': + case 'g': + case 'o': + case 'a': + case ',': + case '+': + case '-': + case '=': + if (modeind != 0 && modeind != thisind) + { + static char char_string[2] = {0, 0}; + char_string[0] = c; + error (1, 0, _("invalid character %s in mode string %s"), + quote_n (0, char_string), quote_n (1, argv[thisind])); + } + modeind = thisind; + break; + case REFERENCE_FILE_OPTION: + reference_file = optarg; + break; + case 'R': + recurse = 1; + break; + case 'c': + verbosity = V_changes_only; + break; + case 'f': + force_silent = 1; + break; + case 'v': + verbosity = V_high; + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (1); + } + } + + if (modeind == 0 && reference_file == NULL) + modeind = optind++; + + if (optind >= argc) + { + error (0, 0, _("too few arguments")); + usage (1); + } + + changes = (reference_file ? mode_create_from_ref (reference_file) + : mode_compile (argv[modeind], MODE_MASK_ALL)); + + if (changes == MODE_INVALID) + error (1, 0, _("invalid mode string: %s"), quote (argv[modeind])); + else if (changes == MODE_MEMORY_EXHAUSTED) + xalloc_die (); + else if (changes == MODE_BAD_REFERENCE) + error (1, errno, _("getting attributes of %s"), quote (reference_file)); + + for (; optind < argc; ++optind) + { + strip_trailing_slashes (argv[optind]); + errors |= change_file_mode (argv[optind], changes, 1); + } + + exit (errors); +} diff --git a/src/apps/bin/gnu/chown-core.c b/src/apps/bin/gnu/chown-core.c new file mode 100644 index 0000000000..cb6a45858c --- /dev/null +++ b/src/apps/bin/gnu/chown-core.c @@ -0,0 +1,366 @@ +/* chown-core.c -- core functions for changing ownership. + Copyright (C) 2000 Free Software Foundation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Extracted from chown.c/chgrp.c and librarified by Jim Meyering. */ + +#include +#include +#include +#include +#include + +#include "system.h" +#include "error.h" +#include "lchown.h" +#include "quote.h" +#include "savedir.h" +#include "chown-core.h" +#include "xalloc.h" + +/* The number of decimal digits required to represent the largest value of + type `unsigned int'. This is enough for an 8-byte unsigned int type. */ +#define UINT_MAX_DECIMAL_DIGITS 20 + +#ifndef _POSIX_VERSION +struct group *getgrnam (); +struct group *getgrgid (); +#endif + +int lstat (); + +void +chopt_init (struct Chown_option *chopt) +{ + chopt->verbosity = V_off; + chopt->dereference = DEREF_NEVER; + chopt->recurse = 0; + chopt->force_silent = 0; + chopt->user_name = 0; + chopt->group_name = 0; +} + +void +chopt_free (struct Chown_option *chopt) +{ + /* Deliberately do not free chopt->user_name or ->group_name. + They're not always allocated. */ +} + +/* Convert N to a string, and return a pointer to that string in memory + allocated from the heap. */ + +static char * +uint_to_string (unsigned int n) +{ + char buf[UINT_MAX_DECIMAL_DIGITS + 1]; + char *p = buf + sizeof buf; + + *--p = '\0'; + + do + *--p = '0' + (n % 10); + while ((n /= 10) != 0); + + return xstrdup (p); +} + +/* Convert the numeric group-id, GID, to a string stored in xmalloc'd memory, + and return it. If there's no corresponding group name, use the decimal + representation of the ID. */ + +char * +gid_to_name (gid_t gid) +{ + struct group *grp = getgrgid (gid); + return grp ? xstrdup (grp->gr_name) : uint_to_string (gid); +} + +/* Convert the numeric user-id, UID, to a string stored in xmalloc'd memory, + and return it. If there's no corresponding user name, use the decimal + representation of the ID. */ + +char * +uid_to_name (uid_t uid) +{ + struct passwd *pwd = getpwuid (uid); + return pwd ? xstrdup (pwd->pw_name) : uint_to_string (uid); +} + +/* Tell the user how/if the user and group of FILE have been changed. + If USER is NULL, give the group-oriented messages. + CHANGED describes what (if anything) has happened. */ + +static void +describe_change (const char *file, enum Change_status changed, + char const *user, char const *group) +{ + const char *fmt; + char *spec; + int spec_allocated = 0; + + if (changed == CH_NOT_APPLIED) + { + printf (_("neither symbolic link %s nor referent has been changed\n"), + quote (file)); + return; + } + + if (user) + { + if (group) + { + spec = xmalloc (strlen (user) + 1 + strlen (group) + 1); + stpcpy (stpcpy (stpcpy (spec, user), ":"), group); + spec_allocated = 1; + } + else + { + spec = (char *) user; + } + } + else + { + spec = (char *) group; + } + + switch (changed) + { + case CH_SUCCEEDED: + fmt = (user + ? _("changed ownership of %s to %s\n") + : _("changed group of %s to %s\n")); + break; + case CH_FAILED: + fmt = (user + ? _("failed to change ownership of %s to %s\n") + : _("failed to change group of %s to %s\n")); + break; + case CH_NO_CHANGE_REQUESTED: + fmt = (user + ? _("ownership of %s retained as %s\n") + : _("group of %s retained as %s\n")); + break; + default: + abort (); + } + + printf (fmt, quote (file), spec); + + if (spec_allocated) + free (spec); +} + +/* Recursively change the ownership of the files in directory DIR to user-id, + UID, and group-id, GID, according to the options specified by CHOPT. + STATP points to the results of lstat on DIR. + Return 0 if successful, 1 if errors occurred. */ + +static int +change_dir_owner (const char *dir, uid_t uid, gid_t gid, + uid_t old_uid, gid_t old_gid, + const struct stat *statp, + struct Chown_option const *chopt) +{ + char *name_space, *namep; + char *path; /* Full path of each entry to process. */ + unsigned dirlength; /* Length of `dir' and '\0'. */ + unsigned filelength; /* Length of each pathname to process. */ + unsigned pathlength; /* Bytes allocated for `path'. */ + int errors = 0; + + name_space = savedir (dir, statp->st_size); + if (name_space == NULL) + { + if (chopt->force_silent == 0) + error (0, errno, "%s", quote (dir)); + return 1; + } + + dirlength = strlen (dir) + 1; /* + 1 is for the trailing '/'. */ + pathlength = dirlength + 1; + /* Give `path' a dummy value; it will be reallocated before first use. */ + path = xmalloc (pathlength); + strcpy (path, dir); + path[dirlength - 1] = '/'; + + for (namep = name_space; *namep; namep += filelength - dirlength) + { + filelength = dirlength + strlen (namep) + 1; + if (filelength > pathlength) + { + pathlength = filelength * 2; + path = xrealloc (path, pathlength); + } + strcpy (path + dirlength, namep); + errors |= change_file_owner (0, path, uid, gid, old_uid, old_gid, + chopt); + } + free (path); + free (name_space); + return errors; +} + +/* Change the ownership of FILE to user-id, UID, and group-id, GID, + provided it presently has owner OLD_UID and group OLD_GID. + Honor the options specified by CHOPT. + If FILE is a directory and -R is given, recurse. + Return 0 if successful, 1 if errors occurred. */ + +int +change_file_owner (int cmdline_arg, const char *file, uid_t uid, gid_t gid, + uid_t old_uid, gid_t old_gid, + struct Chown_option const *chopt) +{ + struct stat file_stats; + uid_t new_uid; + gid_t new_gid; + int errors = 0; + int is_symlink; + int is_directory; + + if (lstat (file, &file_stats)) + { + if (chopt->force_silent == 0) + error (0, errno, _("getting attributes of %s"), quote (file)); + return 1; + } + + /* If it's a symlink and we're dereferencing, then use stat + to get the attributes of the referent. */ + if (S_ISLNK (file_stats.st_mode)) + { + if (chopt->dereference == DEREF_ALWAYS + && stat (file, &file_stats)) + { + if (chopt->force_silent == 0) + error (0, errno, _("getting attributes of %s"), quote (file)); + return 1; + } + + is_symlink = 1; + + /* With -R, don't traverse through symlinks-to-directories. + But of course, this will all change with POSIX's new + -H, -L, -P options. */ + is_directory = 0; + } + else + { + is_symlink = 0; + is_directory = S_ISDIR (file_stats.st_mode); + } + + if ((old_uid == (uid_t) -1 || file_stats.st_uid == old_uid) + && (old_gid == (gid_t) -1 || file_stats.st_gid == old_gid)) + { + new_uid = (uid == (uid_t) -1 ? file_stats.st_uid : uid); + new_gid = (gid == (gid_t) -1 ? file_stats.st_gid : gid); + if (new_uid != file_stats.st_uid || new_gid != file_stats.st_gid) + { + int fail; + int symlink_changed = 1; + int saved_errno; + int called_lchown = 0; + + if (is_symlink) + { + if (chopt->dereference == DEREF_NEVER) + { + called_lchown = 1; + fail = lchown (file, new_uid, new_gid); + + /* Ignore the failure if it's due to lack of support (ENOSYS) + and this is not a command line argument. */ + if (!cmdline_arg && fail && errno == ENOSYS) + { + fail = 0; + symlink_changed = 0; + } + } + else if (chopt->dereference == DEREF_ALWAYS) + { + /* Applying chown to a symlink and expecting it to affect + the referent is not portable. So instead, open the + file and use fchown on the resulting descriptor. */ + int fd = open (file, O_RDONLY | O_NONBLOCK | O_NOCTTY); + fail = (fd == -1 ? 1 : fchown (fd, new_uid, new_gid)); + } + else + { + /* FIXME */ + abort (); + } + } + else + { + fail = chown (file, new_uid, new_gid); + } + saved_errno = errno; + + if (chopt->verbosity == V_high + || (chopt->verbosity == V_changes_only && !fail)) + { + enum Change_status ch_status = (! symlink_changed + ? CH_NOT_APPLIED + : (fail + ? CH_FAILED : CH_SUCCEEDED)); + describe_change (file, ch_status, + chopt->user_name, chopt->group_name); + } + + if (fail) + { + if (chopt->force_silent == 0) + error (0, saved_errno, (uid != (uid_t) -1 + ? _("changing ownership of %s") + : _("changing group of %s")), + quote (file)); + errors = 1; + } + else + { + /* The change succeeded. On some systems, the chown function + resets the `special' permission bits. When run by a + `privileged' user, this program must ensure that at least + the set-uid and set-group ones are still set. */ + if (file_stats.st_mode & ~(S_IFMT | S_IRWXUGO) + /* If we called lchown above (which means this is a symlink), + then skip it. */ + && ! called_lchown) + { + if (chmod (file, file_stats.st_mode)) + { + error (0, saved_errno, + _("unable to restore permissions of %s"), + quote (file)); + fail = 1; + } + } + } + } + else if (chopt->verbosity == V_high) + { + describe_change (file, CH_NO_CHANGE_REQUESTED, + chopt->user_name, chopt->group_name); + } + } + + if (chopt->recurse && is_directory) + errors |= change_dir_owner (file, uid, gid, + old_uid, old_gid, &file_stats, chopt); + return errors; +} diff --git a/src/apps/bin/gnu/chown-core.h b/src/apps/bin/gnu/chown-core.h new file mode 100644 index 0000000000..1da12a79c4 --- /dev/null +++ b/src/apps/bin/gnu/chown-core.h @@ -0,0 +1,89 @@ +/* chown-core.h -- types and prototypes shared by chown and chgrp. + Copyright (C) 2000 Free Software Foundation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef CHOWN_CORE_H +# define CHOWN_CORE_H + +enum Change_status +{ + CH_NOT_APPLIED = 1, + CH_SUCCEEDED, + CH_FAILED, + CH_NO_CHANGE_REQUESTED +}; + +enum Verbosity +{ + /* Print a message for each file that is processed. */ + V_high, + + /* Print a message for each file whose attributes we change. */ + V_changes_only, + + /* Do not be verbose. This is the default. */ + V_off +}; + +enum Dereference_symlink +{ + DEREF_UNDEFINED = 1, + DEREF_NEVER, /* -P */ + DEREF_COMMAND_LINE_ARGUMENTS, /* -H */ + DEREF_ALWAYS /* -L */ +}; + +struct Chown_option +{ + /* Level of verbosity. */ + enum Verbosity verbosity; + + /* If nonzero, change the ownership of directories recursively. */ + int recurse; + + /* This is useful only on systems with support for changing the + ownership of symbolic links. */ + enum Dereference_symlink dereference; + + /* If nonzero, force silence (no error messages). */ + int force_silent; + + /* The name of the user to which ownership of the files is being given. */ + char *user_name; + + /* The name of the group to which ownership of the files is being given. */ + char *group_name; +}; + +void +chopt_init (struct Chown_option *); + +void +chopt_free (struct Chown_option *); + +char * +gid_to_name (gid_t); + +char * +uid_to_name (uid_t); + +int +change_file_owner PARAMS ((int, const char *, + uid_t, gid_t, + uid_t, gid_t, + struct Chown_option const *)); + +#endif /* CHOWN_CORE_H */ diff --git a/src/apps/bin/gnu/chown.c b/src/apps/bin/gnu/chown.c new file mode 100644 index 0000000000..3b9a656de5 --- /dev/null +++ b/src/apps/bin/gnu/chown.c @@ -0,0 +1,247 @@ +/* chown -- change user and group ownership of files + Copyright (C) 89, 90, 91, 1995-2001 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* + | user + | unchanged explicit + -------------|-------------------------+-------------------------| + g unchanged | --- | chown u | + r |-------------------------+-------------------------| + o explicit | chgrp g or chown .g | chown u.g | + u |-------------------------+-------------------------| + p from passwd| --- | chown u. | + |-------------------------+-------------------------| + + Written by David MacKenzie . */ + +#include +#include +#include +#include + +#include "system.h" +#include "error.h" +#include "lchown.h" +#include "quote.h" +#include "savedir.h" +#include "chown-core.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "chown" + +#define AUTHORS "David MacKenzie" + +#ifndef _POSIX_VERSION +struct passwd *getpwnam (); +struct group *getgrnam (); +struct group *getgrgid (); +#endif + +#if ! HAVE_ENDPWENT +# define endpwent() ((void) 0) +#endif + +char *parse_user_spec (); +void strip_trailing_slashes (); + +/* The name the program was run with. */ +char *program_name; + +/* The argument to the --reference option. Use the owner and group IDs + of this file. This file must exist. */ +static char *reference_file; + +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + REFERENCE_FILE_OPTION = CHAR_MAX + 1, + DEREFERENCE_OPTION, + FROM_OPTION +}; + +static struct option const long_options[] = +{ + {"recursive", no_argument, 0, 'R'}, + {"changes", no_argument, 0, 'c'}, + {"dereference", no_argument, 0, DEREFERENCE_OPTION}, + {"from", required_argument, 0, FROM_OPTION}, + {"no-dereference", no_argument, 0, 'h'}, + {"quiet", no_argument, 0, 'f'}, + {"silent", no_argument, 0, 'f'}, + {"reference", required_argument, 0, REFERENCE_FILE_OPTION}, + {"verbose", no_argument, 0, 'v'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {0, 0, 0, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... OWNER[:[GROUP]] FILE...\n\ + or: %s [OPTION]... :GROUP FILE...\n\ + or: %s [OPTION]... --reference=RFILE FILE...\n\ +"), + program_name, program_name, program_name); + printf (_("\ +Change the owner and/or group of each FILE to OWNER and/or GROUP.\n\ +\n\ + -c, --changes like verbose but report only when a change is made\n\ + --dereference affect the referent of each symbolic link, rather\n\ + than the symbolic link itself\n\ + -h, --no-dereference affect symbolic links instead of any referenced file\n\ + (available only on systems that can change the\n\ + ownership of a symlink)\n\ + --from=CURRENT_OWNER:CURRENT_GROUP\n\ + change the owner and/or group of each file only if\n\ + its current owner and/or group match those specified\n\ + here. Either may be omitted, in which case a match\n\ + is not required for the omitted attribute.\n\ + -f, --silent, --quiet suppress most error messages\n\ + --reference=RFILE use RFILE's owner and group rather than\n\ + the specified OWNER:GROUP values\n\ + -R, --recursive operate on files and directories recursively\n\ + -v, --verbose output a diagnostic for every file processed\n\ + --help display this help and exit\n\ + --version output version information and exit\n\ +\n\ +")); + printf (_("\ +Owner is unchanged if missing. Group is unchanged if missing, but changed\n\ +to login group if implied by a `:'. OWNER and GROUP may be numeric as well\n\ +as symbolic.\n\ +")); + puts (_("\nReport bugs to .")); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + uid_t uid = (uid_t) -1; /* New uid; -1 if not to be changed. */ + gid_t gid = (uid_t) -1; /* New gid; -1 if not to be changed. */ + uid_t old_uid = (uid_t) -1; /* Old uid; -1 if unrestricted. */ + gid_t old_gid = (uid_t) -1; /* Old gid; -1 if unrestricted. */ + struct Chown_option chopt; + + int errors = 0; + int optc; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + chopt_init (&chopt); + + while ((optc = getopt_long (argc, argv, "Rcfhv", long_options, NULL)) != -1) + { + switch (optc) + { + case 0: + break; + case REFERENCE_FILE_OPTION: + reference_file = optarg; + break; + case DEREFERENCE_OPTION: + chopt.dereference = DEREF_ALWAYS; + break; + case FROM_OPTION: + { + char *u_dummy, *g_dummy; + const char *e = parse_user_spec (argv[optind], + &old_uid, &old_gid, + &u_dummy, &g_dummy); + if (e) + error (1, 0, "%s: %s", quote (argv[optind]), e); + break; + } + case 'R': + chopt.recurse = 1; + break; + case 'c': + chopt.verbosity = V_changes_only; + break; + case 'f': + chopt.force_silent = 1; + break; + case 'h': + chopt.dereference = DEREF_NEVER; + break; + case 'v': + chopt.verbosity = V_high; + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (1); + } + } + + if (argc - optind + (reference_file ? 1 : 0) <= 1) + { + error (0, 0, _("too few arguments")); + usage (1); + } + + if (reference_file) + { + struct stat ref_stats; + + if (stat (reference_file, &ref_stats)) + error (1, errno, _("getting attributes of %s"), quote (reference_file)); + + uid = ref_stats.st_uid; + gid = ref_stats.st_gid; + chopt.user_name = uid_to_name (ref_stats.st_uid); + chopt.group_name = gid_to_name (ref_stats.st_gid); + } + else + { + const char *e = parse_user_spec (argv[optind], &uid, &gid, + &chopt.user_name, &chopt.group_name); + if (e) + error (1, 0, "%s: %s", quote (argv[optind]), e); + + /* FIXME: set it to the empty string? */ + if (chopt.user_name == NULL) + chopt.user_name = ""; + + optind++; + } + + for (; optind < argc; ++optind) + { + strip_trailing_slashes (argv[optind]); + errors |= change_file_owner (1, argv[optind], uid, gid, + old_uid, old_gid, &chopt); + } + + chopt_free (&chopt); + + exit (errors); +} diff --git a/src/apps/bin/gnu/copy.c b/src/apps/bin/gnu/copy.c new file mode 100644 index 0000000000..1f8c40a20b --- /dev/null +++ b/src/apps/bin/gnu/copy.c @@ -0,0 +1,1219 @@ +/* copy.c -- core functions for copying files and directories + Copyright (C) 89, 90, 91, 1995-2001 Free Software Foundation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Extracted from cp.c and librarified by Jim Meyering. */ + +#ifdef _AIX + #pragma alloca +#endif + +#include +#include +#include +#include + +#include "system.h" +#include "error.h" +#include "backupfile.h" +#include "savedir.h" +#include "copy.h" +#include "cp-hash.h" +#include "dirname.h" +#include "path-concat.h" +#include "quote.h" +#include "same.h" + +#define DO_CHOWN(Chown, File, New_uid, New_gid) \ + (Chown (File, New_uid, New_gid) \ + /* If non-root uses -p, it's ok if we can't preserve ownership. \ + But root probably wants to know, e.g. if NFS disallows it, \ + or if the target system doesn't support file ownership. */ \ + && ((errno != EPERM && errno != EINVAL) || x->myeuid == 0)) + +#define SAME_OWNER(A, B) ((A).st_uid == (B).st_uid) +#define SAME_GROUP(A, B) ((A).st_gid == (B).st_gid) +#define SAME_OWNER_AND_GROUP(A, B) (SAME_OWNER (A, B) && SAME_GROUP (A, B)) + +struct dir_list +{ + struct dir_list *parent; + ino_t ino; + dev_t dev; +}; + +int full_write (); +int euidaccess (); +int yesno (); + +static int copy_internal PARAMS ((const char *src_path, const char *dst_path, + int new_dst, dev_t device, + struct dir_list *ancestors, + const struct cp_options *x, + int move_mode, + int *copy_into_self, + int *rename_succeeded)); + +/* Pointers to the file names: they're used in the diagnostic that is issued + when we detect the user is trying to copy a directory into itself. */ +static char const *top_level_src_path; +static char const *top_level_dst_path; + +/* The invocation name of this program. */ +extern char *program_name; + +/* Encapsulate selection of the file mode to be applied to + new non-directories. */ + +static mode_t +get_dest_mode (const struct cp_options *option, mode_t mode) +{ + /* In some applications (e.g., install), use precisely the + specified mode. */ + if (option->set_mode) + return option->mode; + + /* Honor the umask for `cp', but not for `mv' or `cp -p'. */ + if (!option->move_mode && !option->preserve_chmod_bits) + mode &= option->umask_kill; + + return mode; +} + +/* FIXME: describe */ +/* FIXME: rewrite this to use a hash table so we avoid the quadratic + performance hit that's probably noticeable only on trees deeper + than a few hundred levels. See use of active_dir_map in remove.c */ + +static int +is_ancestor (const struct stat *sb, const struct dir_list *ancestors) +{ + while (ancestors != 0) + { + if (ancestors->ino == sb->st_ino && ancestors->dev == sb->st_dev) + return 1; + ancestors = ancestors->parent; + } + return 0; +} + +/* Read the contents of the directory SRC_PATH_IN, and recursively + copy the contents to DST_PATH_IN. NEW_DST is nonzero if + DST_PATH_IN is a directory that was created previously in the + recursion. SRC_SB and ANCESTORS describe SRC_PATH_IN. + Set *COPY_INTO_SELF to nonzero if SRC_PATH_IN is a parent of + (or the same as) DST_PATH_IN; otherwise, set it to zero. + Return 0 if successful, -1 if an error occurs. */ + +static int +copy_dir (const char *src_path_in, const char *dst_path_in, int new_dst, + const struct stat *src_sb, struct dir_list *ancestors, + const struct cp_options *x, int *copy_into_self) +{ + char *name_space; + char *namep; + struct cp_options non_command_line_options = *x; + int ret = 0; + + name_space = savedir (src_path_in, src_sb->st_size); + if (name_space == NULL) + { + /* This diagnostic is a bit vague because savedir can fail in + several different ways. */ + error (0, errno, _("cannot access %s"), quote (src_path_in)); + return -1; + } + + /* For cp's -H option, dereference command line arguments, but do not + dereference symlinks that are found via recursive traversal. */ + if (x->dereference == DEREF_COMMAND_LINE_ARGUMENTS) + non_command_line_options.xstat = lstat; + + namep = name_space; + while (*namep != '\0') + { + int local_copy_into_self; + char *src_path = path_concat (src_path_in, namep, NULL); + char *dst_path = path_concat (dst_path_in, namep, NULL); + + if (dst_path == NULL || src_path == NULL) + xalloc_die (); + + ret |= copy_internal (src_path, dst_path, new_dst, src_sb->st_dev, + ancestors, &non_command_line_options, 0, + &local_copy_into_self, NULL); + *copy_into_self |= local_copy_into_self; + + /* Free the memory for `src_path'. The memory for `dst_path' + cannot be deallocated, since it is used to create multiple + hard links. */ + + free (src_path); + + namep += strlen (namep) + 1; + } + free (name_space); + return -ret; +} + +/* Copy a regular file from SRC_PATH to DST_PATH. + If the source file contains holes, copies holes and blocks of zeros + in the source file as holes in the destination file. + (Holes are read as zeroes by the `read' system call.) + Use DST_MODE as the 3rd argument in the call to open. + X provides many option settings. + Return 0 if successful, -1 if an error occurred. + *NEW_DST is as in copy_internal. */ + +static int +copy_reg (const char *src_path, const char *dst_path, + const struct cp_options *x, mode_t dst_mode, int *new_dst) +{ + char *buf; + int buf_size; + int dest_desc; + int source_desc; + struct stat sb; + char *cp; + int *ip; + int return_val = 0; + off_t n_read_total = 0; + int last_write_made_hole = 0; + int make_holes = (x->sparse_mode == SPARSE_ALWAYS); + + source_desc = open (src_path, O_RDONLY); + if (source_desc < 0) + { + /* If SRC_PATH doesn't exist, then chances are good that the + user did something like this `cp --backup foo foo': and foo + existed to start with, but copy_internal renamed DST_PATH + with the backup suffix, thus also renaming SRC_PATH. */ + if (errno == ENOENT) + error (0, 0, _("%s and %s are the same file"), + quote_n (0, src_path), quote_n (1, dst_path)); + else + error (0, errno, _("cannot open %s for reading"), quote (src_path)); + + return -1; + } + + /* These semantics are required for cp. + The if-block will be taken in move_mode. */ + if (*new_dst) + { + dest_desc = open (dst_path, O_WRONLY | O_CREAT, dst_mode); + } + else + { + dest_desc = open (dst_path, O_WRONLY | O_TRUNC, dst_mode); + + if (dest_desc < 0 && x->unlink_dest_after_failed_open) + { + if (unlink (dst_path)) + { + error (0, errno, _("cannot remove %s"), quote (dst_path)); + return_val = -1; + goto close_src_desc; + } + + /* Tell caller that the destination file was unlinked. */ + *new_dst = 1; + + /* Try the open again, but this time with different flags. */ + dest_desc = open (dst_path, O_WRONLY | O_CREAT, dst_mode); + } + } + + if (dest_desc < 0) + { + error (0, errno, _("cannot create regular file %s"), quote (dst_path)); + return_val = -1; + goto close_src_desc; + } + + /* Find out the optimal buffer size. */ + + if (fstat (dest_desc, &sb)) + { + error (0, errno, _("cannot fstat %s"), quote (dst_path)); + return_val = -1; + goto close_src_and_dst_desc; + } + + buf_size = ST_BLKSIZE (sb); + +#if HAVE_STRUCT_STAT_ST_BLOCKS + if (x->sparse_mode == SPARSE_AUTO && S_ISREG (sb.st_mode)) + { + /* Use a heuristic to determine whether SRC_PATH contains any + sparse blocks. */ + + if (fstat (source_desc, &sb)) + { + error (0, errno, _("cannot fstat %s"), quote (src_path)); + return_val = -1; + goto close_src_and_dst_desc; + } + + /* If the file has fewer blocks than would normally + be needed for a file of its size, then + at least one of the blocks in the file is a hole. */ + if (S_ISREG (sb.st_mode) + && sb.st_size / ST_NBLOCKSIZE > ST_NBLOCKS (sb)) + make_holes = 1; + } +#endif + + /* Make a buffer with space for a sentinel at the end. */ + + buf = (char *) alloca (buf_size + sizeof (int)); + + for (;;) + { + int n_read = read (source_desc, buf, buf_size); + if (n_read < 0) + { +#ifdef EINTR + if (errno == EINTR) + continue; +#endif + error (0, errno, _("reading %s"), quote (src_path)); + return_val = -1; + goto close_src_and_dst_desc; + } + if (n_read == 0) + break; + + n_read_total += n_read; + + ip = 0; + if (make_holes) + { + buf[n_read] = 1; /* Sentinel to stop loop. */ + + /* Find first nonzero *word*, or the word with the sentinel. */ + + ip = (int *) buf; + while (*ip++ == 0) + ; + + /* Find the first nonzero *byte*, or the sentinel. */ + + cp = (char *) (ip - 1); + while (*cp++ == 0) + ; + + /* If we found the sentinel, the whole input block was zero, + and we can make a hole. */ + + if (cp > buf + n_read) + { + /* Make a hole. */ + if (lseek (dest_desc, (off_t) n_read, SEEK_CUR) < 0L) + { + error (0, errno, _("cannot lseek %s"), quote (dst_path)); + return_val = -1; + goto close_src_and_dst_desc; + } + last_write_made_hole = 1; + } + else + /* Clear to indicate that a normal write is needed. */ + ip = 0; + } + if (ip == 0) + { + if (full_write (dest_desc, buf, n_read) < 0) + { + error (0, errno, _("writing %s"), quote (dst_path)); + return_val = -1; + goto close_src_and_dst_desc; + } + last_write_made_hole = 0; + } + } + + /* If the file ends with a `hole', something needs to be written at + the end. Otherwise the kernel would truncate the file at the end + of the last write operation. */ + + if (last_write_made_hole) + { +#if HAVE_FTRUNCATE + /* Write a null character and truncate it again. */ + if (full_write (dest_desc, "", 1) < 0 + || ftruncate (dest_desc, n_read_total) < 0) +#else + /* Seek backwards one character and write a null. */ + if (lseek (dest_desc, (off_t) -1, SEEK_CUR) < 0L + || full_write (dest_desc, "", 1) < 0) +#endif + { + error (0, errno, _("writing %s"), quote (dst_path)); + return_val = -1; + } + } + +close_src_and_dst_desc: + if (close (dest_desc) < 0) + { + error (0, errno, _("closing %s"), quote (dst_path)); + return_val = -1; + } +close_src_desc: + if (close (source_desc) < 0) + { + error (0, errno, _("closing %s"), quote (src_path)); + return_val = -1; + } + + return return_val; +} + +/* Return nonzero if it's ok that the source and destination + files are the `same' by some measure. The goal is to avoid + making the `copy' operation remove both copies of the file + in that case, while still allowing the user to e.g., move or + copy a regular file onto a symlink that points to it. + Try to minimize the cost of this function in the common case. */ + +static int +same_file_ok (const char *src_path, const struct stat *src_sb, + const char *dst_path, const struct stat *dst_sb, + const struct cp_options *x, int *return_now) +{ + const struct stat *src_sb_link; + const struct stat *dst_sb_link; + struct stat tmp_dst_sb; + struct stat tmp_src_sb; + + int same_link; + int same = (SAME_INODE (*src_sb, *dst_sb)); + + *return_now = 0; + + /* FIXME: this should (at the very least) be moved into the following + if-block. More likely, it should be removed, because it inhibits + making backups. But removing it will result in a change in behavior + that will probably have to be documented -- and tests will have to + be updated. */ + if (same && x->hard_link) + { + *return_now = 1; + return 1; + } + + if (x->xstat == lstat) + { + same_link = same; + + /* If both the source and destination files are symlinks (and we'll + know this here IFF preserving symlinks (aka xstat == lstat), + then it's ok -- as long as they are distinct. */ + if (S_ISLNK (src_sb->st_mode) && S_ISLNK (dst_sb->st_mode)) + return ! same_name (src_path, dst_path); + + src_sb_link = src_sb; + dst_sb_link = dst_sb; + } + else + { + if (!same) + return 1; + + if (lstat (dst_path, &tmp_dst_sb) + || lstat (src_path, &tmp_src_sb)) + return 1; + + src_sb_link = &tmp_src_sb; + dst_sb_link = &tmp_dst_sb; + + same_link = SAME_INODE (*src_sb_link, *dst_sb_link); + + /* If both are symlinks, then it's ok, but only if the destination + will be unlinked before being opened. This is like the test + above, but with the addition of the unlink_dest_before_opening + conjunct because otherwise, with two symlinks to the same target, + we'd end up truncating the source file. */ + if (S_ISLNK (src_sb_link->st_mode) && S_ISLNK (dst_sb_link->st_mode) + && x->unlink_dest_before_opening) + return 1; + } + + /* The backup code ensures there's a copy, so it's ok to remove + any destination file. But there's one exception: when both + source and destination are the same directory entry. In that + case, moving the destination file aside (in making the backup) + would also rename the source file and result in an error. */ + if (x->backup_type != none) + { + if (!same_link) + return 1; + + return ! same_name (src_path, dst_path); + } + +#if 0 + /* FIXME: use or remove */ + + /* If we're making a backup, we'll detect the problem case in + copy_reg because SRC_PATH will no longer exist. Allowing + the test to be deferred lets cp do some useful things. + But when creating hardlinks and SRC_PATH is a symlink + but DST_PATH is not we must test anyway. */ + if (x->hard_link + || !S_ISLNK (src_sb_link->st_mode) + || S_ISLNK (dst_sb_link->st_mode)) + return 1; + + if (x->dereference != DEREF_NEVER) + return 1; +#endif + + /* They may refer to the same file if we're in move mode and the + target is a symlink. That is ok, since we remove any existing + destination file before opening it -- via `rename' if they're on + the same file system, via `unlink (DST_PATH)' otherwise. + It's also ok if they're distinct hard links to the same file. */ + if ((x->move_mode || x->unlink_dest_before_opening) + && (S_ISLNK (dst_sb_link->st_mode) + || (same_link && !same_name (src_path, dst_path)))) + return 1; + + /* If neither is a symlink, then it's ok as long as they aren't + hard links to the same file. */ + if (!S_ISLNK (src_sb_link->st_mode) && !S_ISLNK (dst_sb_link->st_mode)) + { + if (!SAME_INODE (*src_sb_link, *dst_sb_link)) + return 1; + + /* If they are the same file, it's ok if we're making hard links. */ + if (x->hard_link) + { + *return_now = 1; + return 1; + } + } + + /* It's ok to remove a destination symlink. But that works only when we + unlink before opening the destination and when the source and destination + files are on the same partition. */ + if (x->unlink_dest_before_opening + && S_ISLNK (dst_sb_link->st_mode)) + return dst_sb_link->st_dev == src_sb_link->st_dev; + + if (x->xstat == lstat) + { + if ( ! S_ISLNK (src_sb_link->st_mode)) + tmp_src_sb = *src_sb_link; + else if (stat (src_path, &tmp_src_sb)) + return 1; + + if ( ! S_ISLNK (dst_sb_link->st_mode)) + tmp_dst_sb = *dst_sb_link; + else if (stat (dst_path, &tmp_dst_sb)) + return 1; + + if ( ! SAME_INODE (tmp_src_sb, tmp_dst_sb)) + return 1; + + /* FIXME: shouldn't this be testing whether we're making symlinks? */ + if (x->hard_link) + { + *return_now = 1; + return 1; + } + } + + return 0; +} + +/* Copy the file SRC_PATH to the file DST_PATH. The files may be of + any type. NEW_DST should be nonzero if the file DST_PATH cannot + exist because its parent directory was just created; NEW_DST should + be zero if DST_PATH might already exist. DEVICE is the device + number of the parent directory, or 0 if the parent of this file is + not known. ANCESTORS points to a linked, null terminated list of + devices and inodes of parent directories of SRC_PATH. + Set *COPY_INTO_SELF to nonzero if SRC_PATH is a parent of (or the + same as) DST_PATH; otherwise, set it to zero. + Return 0 if successful, 1 if an error occurs. */ + +static int +copy_internal (const char *src_path, const char *dst_path, + int new_dst, + dev_t device, + struct dir_list *ancestors, + const struct cp_options *x, + int move_mode, + int *copy_into_self, + int *rename_succeeded) +{ + struct stat src_sb; + struct stat dst_sb; + mode_t src_mode; + mode_t src_type; + char *earlier_file; + char *dst_backup = NULL; + int backup_succeeded = 0; + int rename_errno; + int delayed_fail; + int copied_as_regular = 0; + int ran_chown = 0; + + if (move_mode && rename_succeeded) + *rename_succeeded = 0; + + *copy_into_self = 0; + if ((*(x->xstat)) (src_path, &src_sb)) + { + error (0, errno, _("cannot stat %s"), quote (src_path)); + return 1; + } + + /* We wouldn't insert a node unless nlink > 1, except that we need to + find created files so as to not copy infinitely if a directory is + copied into itself. */ + + /* Associate the destination path with the source device and inode + so that if we encounter a matching dev/ino pair in the source tree + we can arrange to create a hard link between the corresponding names + in the destination tree. */ + earlier_file = remember_copied (dst_path, src_sb.st_ino, src_sb.st_dev); + + src_mode = src_sb.st_mode; + src_type = src_sb.st_mode; + + if (S_ISDIR (src_type) && !x->recursive) + { + error (0, 0, _("omitting directory %s"), quote (src_path)); + return 1; + } + + if (!new_dst) + { + if ((*(x->xstat)) (dst_path, &dst_sb)) + { + if (errno != ENOENT) + { + error (0, errno, _("cannot stat %s"), quote (dst_path)); + return 1; + } + else + { + new_dst = 1; + } + } + else + { + int return_now; + int ok = same_file_ok (src_path, &src_sb, dst_path, &dst_sb, + x, &return_now); + if (return_now) + return 0; + + if (! ok) + { + error (0, 0, _("%s and %s are the same file"), + quote_n (0, src_path), quote_n (1, dst_path)); + return 1; + } + + if (S_ISDIR (src_type) && !S_ISDIR (dst_sb.st_mode)) + { + error (0, 0, + _("cannot overwrite non-directory %s with directory %s"), + quote_n (0, dst_path), quote_n (1, src_path)); + return 1; + } + + if (!S_ISDIR (src_type)) + { + if (S_ISDIR (dst_sb.st_mode)) + { + error (0, 0, + _("cannot overwrite directory %s with non-directory"), + quote (dst_path)); + return 1; + } + + if (x->update && MTIME_CMP (src_sb, dst_sb) <= 0) + return 0; + } + + if (!S_ISDIR (src_type) && x->interactive) + { + if (euidaccess (dst_path, W_OK) != 0) + { + fprintf (stderr, + _("%s: overwrite %s, overriding mode %04lo? "), + program_name, quote (dst_path), + (unsigned long) (dst_sb.st_mode & CHMOD_MODE_BITS)); + } + else + { + fprintf (stderr, _("%s: overwrite %s? "), + program_name, quote (dst_path)); + } + if (!yesno ()) + return (move_mode ? 1 : 0); + } + + if (move_mode) + { + /* In move_mode, DEST may not be an existing directory. */ + if (S_ISDIR (dst_sb.st_mode)) + { + error (0, 0, _("cannot overwrite directory %s"), + quote (dst_path)); + return 1; + } + + /* Don't allow user to move a directory onto a non-directory. */ + if (S_ISDIR (src_sb.st_mode) && !S_ISDIR (dst_sb.st_mode)) + { + error (0, 0, + _("cannot move directory onto non-directory: %s -> %s"), + quote_n (0, src_path), quote_n (0, dst_path)); + return 1; + } + } + + if (x->backup_type != none && !S_ISDIR (dst_sb.st_mode)) + { + char *tmp_backup = find_backup_file_name (dst_path, + x->backup_type); + if (tmp_backup == NULL) + xalloc_die (); + + /* Detect (and fail) when creating the backup file would + destroy the source file. Before, running the commands + cd /tmp; rm -f a a~; : > a; echo A > a~; cp -b -V simple a~ a + would leave two zero-length files: a and a~. */ + if (STREQ (tmp_backup, src_path)) + { + const char *fmt; + fmt = (move_mode + ? _("backing up %s would destroy source; %s not moved") + : _("backing up %s would destroy source; %s not copied")); + error (0, 0, fmt, + quote_n (0, dst_path), + quote_n (1, src_path)); + free (tmp_backup); + return 1; + } + + dst_backup = (char *) alloca (strlen (tmp_backup) + 1); + strcpy (dst_backup, tmp_backup); + free (tmp_backup); + if (rename (dst_path, dst_backup)) + { + if (errno != ENOENT) + { + error (0, errno, _("cannot backup %s"), quote (dst_path)); + return 1; + } + else + { + dst_backup = NULL; + } + } + else + { + backup_succeeded = 1; + } + new_dst = 1; + } + else if (! S_ISDIR (dst_sb.st_mode) + && (x->unlink_dest_before_opening + || (x->xstat == lstat + && ! S_ISREG (src_sb.st_mode)))) + { + if (unlink (dst_path) && errno != ENOENT) + { + error (0, errno, _("cannot remove %s"), quote (dst_path)); + return 1; + } + new_dst = 1; + } + } + } + + /* If the source is a directory, we don't always create the destination + directory. So --verbose should not announce anything until we're + sure we'll create a directory. */ + if (x->verbose && !S_ISDIR (src_type)) + { + printf ("%s -> %s", quote_n (0, src_path), quote_n (1, dst_path)); + if (backup_succeeded) + printf (_(" (backup: %s)"), quote (dst_backup)); + putchar ('\n'); + } + + /* Did we copy this inode somewhere else (in this command line argument) + and therefore this is a second hard link to the inode? */ + + if (x->dereference == DEREF_NEVER && src_sb.st_nlink > 1 && earlier_file) + { + /* Avoid damaging the destination filesystem by refusing to preserve + hard-linked directories (which are found at least in Netapp snapshot + directories). */ + if (S_ISDIR (src_type)) + { + /* If src_path and earlier_file refer to the same directory entry, + then warn about copying a directory into itself. */ + if (same_name (src_path, earlier_file)) + { + error (0, 0, _("cannot copy a directory, %s, into itself, %s"), + quote_n (0, top_level_src_path), + quote_n (1, top_level_dst_path)); + *copy_into_self = 1; + } + else + { + error (0, 0, _("will not create hard link %s to directory %s"), + quote_n (0, dst_path), quote_n (1, earlier_file)); + } + + goto un_backup; + } + + if (link (earlier_file, dst_path)) + { + error (0, errno, _("cannot create hard link %s to %s"), + quote_n (0, dst_path), quote_n (1, earlier_file)); + goto un_backup; + } + + return 0; + } + + if (move_mode) + { + if (rename (src_path, dst_path) == 0) + { + if (x->verbose && S_ISDIR (src_type)) + printf ("%s -> %s\n", quote_n (0, src_path), quote_n (1, dst_path)); + if (rename_succeeded) + *rename_succeeded = 1; + return 0; + } + + /* FIXME: someday, consider what to do when moving a directory into + itself but when source and destination are on different devices. */ + + /* This happens when attempting to rename a directory to a + subdirectory of itself. */ + if (errno == EINVAL + + /* When src_path is on an NFS file system, some types of + clients, e.g., SunOS4.1.4 and IRIX-5.3, set errno to EIO + instead. Testing for this here risks misinterpreting a real + I/O error as an attempt to move a directory into itself, so + FIXME: consider not doing this. */ + || errno == EIO + + /* And with SunOS-4.1.4 client and OpenBSD-2.3 server, + we get ENOTEMPTY. */ + || errno == ENOTEMPTY) + { + /* FIXME: this is a little fragile in that it relies on rename(2) + failing with a specific errno value. Expect problems on + non-POSIX systems. */ + error (0, 0, _("cannot move %s to a subdirectory of itself, %s"), + quote_n (0, top_level_src_path), + quote_n (1, top_level_dst_path)); + *copy_into_self = 1; + /* FIXME-cleanup: Don't return zero here; adjust mv.c accordingly. + The only caller that uses this code (mv.c) ends up setting its + exit status to nonzero when copy_into_self is nonzero. */ + return 0; + } + + /* Ignore other types of failure (e.g. EXDEV), since the following + code will try to perform a copy, then remove. */ + + /* Save this value of errno to use in case the unlink fails. */ + rename_errno = errno; + + /* The rename attempt has failed. Remove any existing destination + file so that a cross-device `mv' acts as if it were really using + the rename syscall. */ + if (unlink (dst_path) && errno != ENOENT) + { + /* Use the value of errno from the failed rename. */ + error (0, rename_errno, _("cannot move %s to %s"), + quote_n (0, src_path), quote_n (1, dst_path)); + return 1; + } + + new_dst = 1; + } + + delayed_fail = 0; + if (S_ISDIR (src_type)) + { + struct dir_list *dir; + + /* If this directory has been copied before during the + recursion, there is a symbolic link to an ancestor + directory of the symbolic link. It is impossible to + continue to copy this, unless we've got an infinite disk. */ + + if (is_ancestor (&src_sb, ancestors)) + { + error (0, 0, _("cannot copy cyclic symbolic link %s"), + quote (src_path)); + goto un_backup; + } + + /* Insert the current directory in the list of parents. */ + + dir = (struct dir_list *) alloca (sizeof (struct dir_list)); + dir->parent = ancestors; + dir->ino = src_sb.st_ino; + dir->dev = src_sb.st_dev; + + if (new_dst || !S_ISDIR (dst_sb.st_mode)) + { + /* Create the new directory writable and searchable, so + we can create new entries in it. */ + + if (mkdir (dst_path, (src_mode & x->umask_kill) | S_IRWXU)) + { + error (0, errno, _("cannot create directory %s"), + quote (dst_path)); + goto un_backup; + } + + /* Insert the created directory's inode and device + numbers into the search structure, so that we can + avoid copying it again. */ + + if (remember_created (dst_path)) + goto un_backup; + + if (x->verbose) + printf ("%s -> %s\n", quote_n (0, src_path), quote_n (1, dst_path)); + } + + /* Are we crossing a file system boundary? */ + if (x->one_file_system && device != 0 && device != src_sb.st_dev) + return 0; + + /* Copy the contents of the directory. */ + + if (copy_dir (src_path, dst_path, new_dst, &src_sb, dir, x, + copy_into_self)) + { + /* Don't just return here -- otherwise, the failure to read a + single file in a source directory would cause the containing + destination directory not to have owner/perms set properly. */ + delayed_fail = 1; + } + } +#ifdef S_ISLNK + else if (x->symbolic_link) + { + if (*src_path != '/') + { + /* Check that DST_PATH denotes a file in the current directory. */ + struct stat dot_sb; + struct stat dst_parent_sb; + char *dst_parent; + int in_current_dir; + + dst_parent = dir_name (dst_path); + if (dst_parent == NULL) + xalloc_die (); + + in_current_dir = (STREQ (".", dst_parent) + /* If either stat call fails, it's ok not to report + the failure and say dst_path is in the current + directory. Other things will fail later. */ + || stat (".", &dot_sb) + || stat (dst_parent, &dst_parent_sb) + || SAME_INODE (dot_sb, dst_parent_sb)); + free (dst_parent); + + if (! in_current_dir) + { + error (0, 0, + _("%s: can make relative symbolic links only in current directory"), + quote (dst_path)); + goto un_backup; + } + } + if (symlink (src_path, dst_path)) + { + error (0, errno, _("cannot create symbolic link %s to %s"), + quote_n (0, dst_path), quote_n (1, src_path)); + goto un_backup; + } + + return 0; + } +#endif + else if (x->hard_link) + { + if (link (src_path, dst_path)) + { + error (0, errno, _("cannot create link %s"), quote (dst_path)); + goto un_backup; + } + return 0; + } + else if (S_ISREG (src_type) + || (x->copy_as_regular && !S_ISDIR (src_type) +#ifdef S_ISLNK + && !S_ISLNK (src_type) +#endif + )) + { + copied_as_regular = 1; + /* POSIX says the permission bits of the source file must be + used as the 3rd argument in the open call, but that's not consistent + with historical practice. */ + if (copy_reg (src_path, dst_path, x, + get_dest_mode (x, src_mode), &new_dst)) + goto un_backup; + } + else +#ifdef S_ISFIFO + if (S_ISFIFO (src_type)) + { + if (mkfifo (dst_path, get_dest_mode (x, src_mode))) + { + error (0, errno, _("cannot create fifo %s"), quote (dst_path)); + goto un_backup; + } + } + else +#endif + if (S_ISBLK (src_type) || S_ISCHR (src_type) +#ifdef S_ISSOCK + || S_ISSOCK (src_type) +#endif + ) + { + if (mknod (dst_path, get_dest_mode (x, src_mode), src_sb.st_rdev)) + { + error (0, errno, _("cannot create special file %s"), + quote (dst_path)); + goto un_backup; + } + } + else +#ifdef S_ISLNK + if (S_ISLNK (src_type)) + { + char *link_val; + int link_size; + + link_val = (char *) alloca (PATH_MAX + 2); + link_size = readlink (src_path, link_val, PATH_MAX + 1); + if (link_size < 0) + { + error (0, errno, _("cannot read symbolic link %s"), quote (src_path)); + goto un_backup; + } + link_val[link_size] = '\0'; + + if (symlink (link_val, dst_path)) + { + int saved_errno = errno; + int same_link = 0; + if (x->update && !new_dst && S_ISLNK (dst_sb.st_mode)) + { + /* See if the destination is already the desired symlink. */ + char *dest_link_name = (char *) alloca (PATH_MAX + 2); + int dest_link_len = readlink (dst_path, dest_link_name, + PATH_MAX + 1); + if (dest_link_len > 0) + { + dest_link_name[dest_link_len] = '\0'; + if (STREQ (dest_link_name, link_val)) + same_link = 1; + } + } + + if (! same_link) + { + error (0, saved_errno, _("cannot create symbolic link %s"), + quote (dst_path)); + goto un_backup; + } + } + + if (x->preserve_owner_and_group) + { + /* Preserve the owner and group of the just-`copied' + symbolic link, if possible. */ +# if HAVE_LCHOWN + if (DO_CHOWN (lchown, dst_path, src_sb.st_uid, src_sb.st_gid)) + { + error (0, errno, _("preserving ownership for %s"), dst_path); + goto un_backup; + } +# else + /* Can't preserve ownership of symlinks. + FIXME: maybe give a warning or even error for symlinks + in directories with the sticky bit set -- there, not + preserving owner/group is a potential security problem. */ +# endif + } + + return 0; + } + else +#endif + { + error (0, 0, _("%s has unknown file type"), quote (src_path)); + goto un_backup; + } + + /* POSIX says that `cp -p' must restore the following: + - permission bits + - setuid, setgid bits + - owner and group + If it fails to restore any of those, we may give a warning but + the destination must not be removed. + FIXME: implement the above. */ + + /* Adjust the times (and if possible, ownership) for the copy. + chown turns off set[ug]id bits for non-root, + so do the chmod last. */ + + if (x->preserve_timestamps) + { + struct utimbuf utb; + + /* There's currently no interface to set file timestamps with + better than 1-second resolution, so discard any fractional + part of the source timestamp. */ + + utb.actime = src_sb.st_atime; + utb.modtime = src_sb.st_mtime; + + if (utime (dst_path, &utb)) + { + error (0, errno, _("preserving times for %s"), quote (dst_path)); + if (x->require_preserve) + return 1; + } + } + + /* Avoid calling chown if we know it's not necessary. */ + if (x->preserve_owner_and_group + && (new_dst || !SAME_OWNER_AND_GROUP (src_sb, dst_sb))) + { + ran_chown = 1; + if (DO_CHOWN (chown, dst_path, src_sb.st_uid, src_sb.st_gid)) + { + error (0, errno, _("preserving ownership for %s"), quote (dst_path)); + if (x->require_preserve) + return 1; + } + } + + /* Permissions of newly-created regular files were set upon `open' in + copy_reg. But don't return early if there were any special bits and + we had to run chown, because the chown must have reset those bits. */ + if ((new_dst && copied_as_regular) + && !(ran_chown && (src_mode & ~S_IRWXUGO))) + return delayed_fail; + + if ((x->preserve_chmod_bits || new_dst) + && (x->copy_as_regular || S_ISREG (src_type) || S_ISDIR (src_type))) + { + if (chmod (dst_path, get_dest_mode (x, src_mode))) + { + error (0, errno, _("setting permissions for %s"), quote (dst_path)); + if (x->set_mode || x->require_preserve) + return 1; + } + } + + return delayed_fail; + +un_backup: + if (dst_backup) + { + if (rename (dst_backup, dst_path)) + error (0, errno, _("cannot un-backup %s"), quote (dst_path)); + else + { + if (x->verbose) + printf (_("%s -> %s (unbackup)\n"), + quote_n (0, dst_backup), quote_n (1, dst_path)); + } + } + return 1; +} + +static int +valid_options (const struct cp_options *co) +{ + assert (co != NULL); + + assert (VALID_BACKUP_TYPE (co->backup_type)); + + /* FIXME: for some reason this assertion always fails, + at least on Solaris2.5.1. Just disable it for now. */ + /* assert (co->xstat == lstat || co->xstat == stat); */ + + /* Make sure xstat and dereference are consistent. */ + /* FIXME */ + + assert (VALID_SPARSE_MODE (co->sparse_mode)); + + return 1; +} + +/* Copy the file SRC_PATH to the file DST_PATH. The files may be of + any type. NONEXISTENT_DST should be nonzero if the file DST_PATH + is known not to exist (e.g., because its parent directory was just + created); NONEXISTENT_DST should be zero if DST_PATH might already + exist. OPTIONS is ... FIXME-describe + Set *COPY_INTO_SELF to nonzero if SRC_PATH is a parent of (or the + same as) DST_PATH; otherwise, set it to zero. + Return 0 if successful, 1 if an error occurs. */ + +int +copy (const char *src_path, const char *dst_path, + int nonexistent_dst, const struct cp_options *options, + int *copy_into_self, int *rename_succeeded) +{ + /* move_mode is set to the value from the `options' parameter for the + first copy_internal call. For all subsequent calls (if any), it must + be zero. */ + int move_mode = options->move_mode; + + assert (valid_options (options)); + + /* Record the file names: they're used in case of error, when copying + a directory into itself. I don't like to make these tools do *any* + extra work in the common case when that work is solely to handle + exceptional cases, but in this case, I don't see a way to derive the + top level source and destination directory names where they're used. + An alternative is to use COPY_INTO_SELF and print the diagnostic + from every caller -- but I don't wan't to do that. */ + top_level_src_path = src_path; + top_level_dst_path = dst_path; + + return copy_internal (src_path, dst_path, nonexistent_dst, 0, NULL, + options, move_mode, copy_into_self, rename_succeeded); +} diff --git a/src/apps/bin/gnu/copy.h b/src/apps/bin/gnu/copy.h new file mode 100644 index 0000000000..9cc4e4cd3e --- /dev/null +++ b/src/apps/bin/gnu/copy.h @@ -0,0 +1,161 @@ +#ifndef COPY_H +# define COPY_H + +/* Control creation of sparse files (files with holes). */ +enum Sparse_type +{ + SPARSE_UNUSED, + + /* Never create holes in DEST. */ + SPARSE_NEVER, + + /* This is the default. Use a crude (and sometimes inaccurate) + heuristic to determine if SOURCE has holes. If so, try to create + holes in DEST. */ + SPARSE_AUTO, + + /* For every sufficiently long sequence of bytes in SOURCE, try to + create a corresponding hole in DEST. There is a performance penalty + here because CP has to search for holes in SRC. But if the holes are + big enough, that penalty can be offset by the decrease in the amount + of data written to disk. */ + SPARSE_ALWAYS +}; + +enum Dereference_symlink +{ + DEREF_UNDEFINED = 1, + DEREF_ALWAYS, + DEREF_NEVER, + DEREF_COMMAND_LINE_ARGUMENTS +}; + +# define VALID_SPARSE_MODE(Mode) \ + ((Mode) == SPARSE_NEVER \ + || (Mode) == SPARSE_AUTO \ + || (Mode) == SPARSE_ALWAYS) + +struct cp_options +{ + enum backup_type backup_type; + + /* If nonzero, copy all files except (directories and, if not dereferencing + them, symbolic links,) as if they were regular files. */ + int copy_as_regular; + + /* If nonzero, dereference symbolic links (copy the files they point to). */ + enum Dereference_symlink dereference; + + /* If nonzero, remove each existing destination nondirectory before + trying to open it. */ + int unlink_dest_before_opening; + + /* If nonzero, first try to open each existing destination nondirectory, + then, if the open fails, unlink and try again. + This option must be set for `cp -f', in case the destination file + exists when the open is attempted. It is irrelevant to `mv' since + any destination is sure to be removed before the open. */ + int unlink_dest_after_failed_open; + + /* Setting this member is meaningful only if FORCE is also set. + If nonzero, copy returns nonzero upon failed unlink. + Otherwise, the failure still elicits a diagnostic, but it doesn't + change copy's return value. This is nonzero for cp and mv, and zero + for install. */ + /* FIXME: this is now unused. */ + int failed_unlink_is_fatal; + + /* If nonzero, create hard links instead of copying files. + Create destination directories as usual. */ + int hard_link; + + /* If nonzero, query before overwriting existing destinations + with regular files. */ + int interactive; + + /* If nonzero, rather than copying, first attempt to use rename. + If that fails, then resort to copying. */ + int move_mode; + + /* This process's effective user ID. */ + uid_t myeuid; + + /* If nonzero, when copying recursively, skip any subdirectories that are + on different filesystems from the one we started on. */ + int one_file_system; + + /* If nonzero, attempt to give the copies the original files' permissions, + owner, group, and timestamps. */ + int preserve_owner_and_group; + int preserve_chmod_bits; + int preserve_timestamps; + + /* If nonzero and any of the above (for preserve) file attributes cannot + be applied to a destination file, treat it as a failure and return + nonzero immediately. E.g. cp -p requires this be nonzero, mv requires + it be zero. */ + int require_preserve; + + /* If nonzero, copy directories recursively and copy special files + as themselves rather than copying their contents. */ + int recursive; + + /* If nonzero, set file mode to value of MODE. Otherwise, + set it based on current umask modified by UMASK_KILL. */ + int set_mode; + + /* Set the mode of the destination file to exactly this value + if USE_MODE is nonzero. */ + mode_t mode; + + /* Control creation of sparse files. */ + enum Sparse_type sparse_mode; + + /* If nonzero, create symbolic links instead of copying files. + Create destination directories as usual. */ + int symbolic_link; + + /* The bits to preserve in created files' modes. */ + mode_t umask_kill; + + /* If nonzero, do not copy a nondirectory that has an existing destination + with the same or newer modification time. */ + int update; + + /* If nonzero, display the names of the files before copying them. */ + int verbose; + + /* A pointer to either lstat or stat, depending on + whether the copy should dereference symlinks. */ + int (*xstat) (); +}; + +int stat (); +int lstat (); + +/* Arrange to make lstat calls go through the wrapper function + on systems with an lstat function that does not dereference symlinks + that are specified with a trailing slash. */ +# if ! LSTAT_FOLLOWS_SLASHED_SYMLINK +int rpl_lstat PARAMS((const char *, struct stat *)); +# undef lstat +# define lstat rpl_lstat +# endif + +int rename (); + +/* Arrange to make rename calls go through the wrapper function + on systems with a rename function that fails for a source path + specified with a trailing slash. */ +# if RENAME_TRAILING_SLASH_BUG +int rpl_rename PARAMS((const char *, const char *)); +# undef rename +# define rename rpl_rename +# endif + +int +copy PARAMS ((const char *src_path, const char *dst_path, + int nonexistent_dst, const struct cp_options *options, + int *copy_into_self, int *rename_succeeded)); + +#endif diff --git a/src/apps/bin/gnu/cp-hash.c b/src/apps/bin/gnu/cp-hash.c new file mode 100644 index 0000000000..a064efcaeb --- /dev/null +++ b/src/apps/bin/gnu/cp-hash.c @@ -0,0 +1,235 @@ +/* cp-hash.c -- file copying (hash search routines) + Copyright (C) 89, 90, 91, 1995-2001 Free Software Foundation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Written by Torbjorn Granlund, Sweden (tege@sics.se). */ + +#include + +#if HAVE_INTTYPES_H +# include +#endif +#include +#include +#include "system.h" +#include "error.h" +#include "cp-hash.h" +#include "quote.h" + +struct entry +{ + ino_t ino; + dev_t dev; + /* Destination path name (of non-directory or pre-existing directory) + corresponding to the dev/ino of a copied file, or the destination path + name corresponding to a dev/ino pair for a newly-created directory. */ + char *node; + + struct entry *coll_link; /* 0 = entry not occupied. */ +}; + +struct htab +{ + unsigned modulus; /* Size of the `hash' pointer vector. */ + struct entry *entry_tab; /* Pointer to dynamically growing vector. */ + unsigned entry_tab_size; /* Size of current `entry_tab' allocation. */ + unsigned first_free_entry; /* Index in `entry_tab'. */ + struct entry *hash[1]; /* Vector of pointers in `entry_tab'. */ +}; + +static struct htab *htab; + +static char *cph_hash_insert PARAMS ((ino_t ino, dev_t dev, const char *node)); + +/* Add PATH to the list of files that we have created. + Return 0 if successful, 1 if not. */ + +int +remember_created (const char *path) +{ + struct stat sb; + + if (stat (path, &sb) < 0) + { + error (0, errno, "%s", quote (path)); + return 1; + } + + cph_hash_insert (sb.st_ino, sb.st_dev, path); + return 0; +} + +/* Add path NODE, copied from inode number INO and device number DEV, + to the list of files we have copied. + Return NULL if inserted, otherwise non-NULL. */ + +char * +remember_copied (const char *node, ino_t ino, dev_t dev) +{ + return cph_hash_insert (ino, dev, node); +} + +/* Allocate space for the hash structures, and set the global + variable `htab' to point to it. The initial hash module is specified in + MODULUS, and the number of entries are specified in ENTRY_TAB_SIZE. (The + hash structure will be rebuilt when ENTRY_TAB_SIZE entries have been + inserted, and MODULUS and ENTRY_TAB_SIZE in the global `htab' will be + doubled.) */ + +void +hash_init (unsigned int modulus, unsigned int entry_tab_size) +{ + struct htab *htab_r; + + htab_r = (struct htab *) + xmalloc (sizeof (struct htab) + sizeof (struct entry *) * modulus); + + htab_r->entry_tab = (struct entry *) + xmalloc (sizeof (struct entry) * entry_tab_size); + + htab_r->modulus = modulus; + htab_r->entry_tab_size = entry_tab_size; + htab = htab_r; + + forget_all (); +} + +/* Reset the hash structure in the global variable `htab' to + contain no entries. */ + +void +forget_all (void) +{ + int i; + struct entry **p; + + htab->first_free_entry = 0; + + p = htab->hash; + for (i = htab->modulus; i > 0; i--) + *p++ = NULL; +} + +/* Insert path NODE, copied from inode number INO and device number DEV, + into the hash structure HTAB, if not already present. + Return NULL if inserted, otherwise non-NULL. */ + +static char * +hash_insert2 (struct htab *ht, ino_t ino, dev_t dev, const char *node) +{ + struct entry **hp, *ep2, *ep; + + /* The cast to uintmax_t prevents negative remainders if ino is negative. */ + hp = &ht->hash[(uintmax_t) ino % ht->modulus]; + + ep2 = *hp; + + /* Collision? */ + + if (ep2 != NULL) + { + ep = ep2; + + /* Search for an entry with the same data. */ + + do + { + if (ep->ino == ino && ep->dev == dev) + return ep->node; /* Found an entry with the same data. */ + ep = ep->coll_link; + } + while (ep != NULL); + + /* Did not find it. */ + + } + + ep = *hp = &ht->entry_tab[ht->first_free_entry++]; + ep->ino = ino; + ep->dev = dev; + ep->node = (char *) node; + ep->coll_link = ep2; /* ep2 is NULL if not collision. */ + + return NULL; +} + +/* Insert path NODE, copied from inode number INO and device number DEV, + into the hash structure in the global variable `htab', if an entry with + the same inode and device was not found already. + Return NULL if inserted, otherwise non-NULL. */ + +static char * +cph_hash_insert (ino_t ino, dev_t dev, const char *node) +{ + struct htab *htab_r = htab; + + if (htab_r->first_free_entry >= htab_r->entry_tab_size) + { + int i; + struct entry *ep; + unsigned modulus; + unsigned entry_tab_size; + + /* Increase the number of hash entries, and re-hash the data. + The method of shrinking and increasing is made to compactify + the heap. If twice as much data would be allocated + straightforwardly, we would never re-use a byte of memory. */ + + /* Let htab shrink. Keep only the header, not the pointer vector. */ + + htab_r = (struct htab *) + xrealloc ((char *) htab_r, sizeof (struct htab)); + + modulus = 2 * htab_r->modulus; + entry_tab_size = 2 * htab_r->entry_tab_size; + + /* Increase the number of possible entries. */ + + htab_r->entry_tab = (struct entry *) + xrealloc ((char *) htab_r->entry_tab, + sizeof (struct entry) * entry_tab_size); + + /* Increase the size of htab again. */ + + htab_r = (struct htab *) + xrealloc ((char *) htab_r, + sizeof (struct htab) + sizeof (struct entry *) * modulus); + + htab_r->modulus = modulus; + htab_r->entry_tab_size = entry_tab_size; + htab = htab_r; + + i = htab_r->first_free_entry; + + /* Make the increased hash table empty. The entries are still + available in htab->entry_tab. */ + + forget_all (); + + /* Go through the entries and install them in the pointer vector + htab->hash. The items are actually inserted in htab->entry_tab at + the position where they already are. The htab->coll_link need + however be updated. Could be made a little more efficient. */ + + for (ep = htab_r->entry_tab; i > 0; i--) + { + hash_insert2 (htab_r, ep->ino, ep->dev, ep->node); + ep++; + } + } + + return hash_insert2 (htab_r, ino, dev, node); +} diff --git a/src/apps/bin/gnu/cp-hash.h b/src/apps/bin/gnu/cp-hash.h new file mode 100644 index 0000000000..6bde1cc9b6 --- /dev/null +++ b/src/apps/bin/gnu/cp-hash.h @@ -0,0 +1,8 @@ +/* For created inodes, a pointer in the search structure to this + character identifies the inode as being new. */ +extern char new_file; + +void hash_init PARAMS ((unsigned int modulus, unsigned int entry_tab_size)); +void forget_all PARAMS ((void)); +char *remember_copied PARAMS ((const char *node, ino_t ino, dev_t dev)); +int remember_created PARAMS ((const char *path)); diff --git a/src/apps/bin/gnu/cp.c b/src/apps/bin/gnu/cp.c new file mode 100644 index 0000000000..d98dfd72e6 --- /dev/null +++ b/src/apps/bin/gnu/cp.c @@ -0,0 +1,911 @@ +/* cp.c -- file copying (main routines) + Copyright (C) 89, 90, 91, 1995-2001 Free Software Foundation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Written by Torbjorn Granlund, David MacKenzie, and Jim Meyering. */ + +#ifdef _AIX + #pragma alloca +#endif + +#include +#include +#include +#include +#include + +#include "system.h" +#include "argmatch.h" +#include "backupfile.h" +#include "copy.h" +#include "cp-hash.h" +#include "error.h" +#include "dirname.h" +#include "path-concat.h" +#include "quote.h" + +#define ASSIGN_BASENAME_STRDUPA(Dest, File_name) \ + do \ + { \ + char *tmp_abns_; \ + ASSIGN_STRDUPA (tmp_abns_, (File_name)); \ + strip_trailing_slashes (tmp_abns_); \ + Dest = base_name (tmp_abns_); \ + } \ + while (0) + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "cp" + +#define AUTHORS "Torbjorn Granlund, David MacKenzie, and Jim Meyering" + +#ifndef _POSIX_VERSION +uid_t geteuid (); +#endif + +/* Used by do_copy, make_path_private, and re_protect + to keep a list of leading directories whose protections + need to be fixed after copying. */ +struct dir_attr +{ + int is_new_dir; + int slash_offset; + struct dir_attr *next; +}; + +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + TARGET_DIRECTORY_OPTION = CHAR_MAX + 1, + SPARSE_OPTION, + STRIP_TRAILING_SLASHES_OPTION, + PARENTS_OPTION, + UNLINK_DEST_BEFORE_OPENING +}; + +void strip_trailing_slashes (); + +/* Initial number of entries in each hash table entry's table of inodes. */ +#define INITIAL_HASH_MODULE 100 + +/* Initial number of entries in the inode hash table. */ +#define INITIAL_ENTRY_TAB_SIZE 70 + +/* The invocation name of this program. */ +char *program_name; + +/* If nonzero, the command "cp x/e_file e_dir" uses "e_dir/x/e_file" + as its destination instead of the usual "e_dir/e_file." */ +static int flag_path = 0; + +/* Remove any trailing slashes from each SOURCE argument. */ +static int remove_trailing_slashes; + +static char const *const sparse_type_string[] = +{ + "never", "auto", "always", 0 +}; + +static enum Sparse_type const sparse_type[] = +{ + SPARSE_NEVER, SPARSE_AUTO, SPARSE_ALWAYS +}; + +/* The error code to return to the system. */ +static int exit_status = 0; + +static struct option const long_opts[] = +{ + {"archive", no_argument, NULL, 'a'}, + {"backup", optional_argument, NULL, 'b'}, + {"dereference", no_argument, NULL, 'L'}, + {"force", no_argument, NULL, 'f'}, + {"sparse", required_argument, NULL, SPARSE_OPTION}, + {"interactive", no_argument, NULL, 'i'}, + {"link", no_argument, NULL, 'l'}, + {"no-dereference", no_argument, NULL, 'd'}, + {"one-file-system", no_argument, NULL, 'x'}, + {"parents", no_argument, NULL, PARENTS_OPTION}, + {"path", no_argument, NULL, PARENTS_OPTION}, /* Deprecated. */ + {"preserve", no_argument, NULL, 'p'}, + {"recursive", no_argument, NULL, 'R'}, + {"remove-destination", no_argument, NULL, UNLINK_DEST_BEFORE_OPENING}, + {"strip-trailing-slashes", no_argument, NULL, STRIP_TRAILING_SLASHES_OPTION}, + {"suffix", required_argument, NULL, 'S'}, + {"symbolic-link", no_argument, NULL, 's'}, + {"target-directory", required_argument, NULL, TARGET_DIRECTORY_OPTION}, + {"update", no_argument, NULL, 'u'}, + {"verbose", no_argument, NULL, 'v'}, + {"version-control", required_argument, NULL, 'V'}, /* Deprecated. FIXME. */ + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... SOURCE DEST\n\ + or: %s [OPTION]... SOURCE... DIRECTORY\n\ + or: %s [OPTION]... --target-directory=DIRECTORY SOURCE...\n\ +"), + program_name, program_name, program_name); + printf (_("\ +Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n\ +\n\ + -a, --archive same as -dpR\n\ + --backup[=CONTROL] make a backup of each existing destination file\n\ + -b like --backup but does not accept an argument\n\ + -d, --no-dereference never follow symbolic links\n\ + -f, --force if an existing destination file cannot be\n\ + opened, remove it and try again\n\ + -i, --interactive prompt before overwrite\n\ + -H follow command-line symbolic links\n\ + -l, --link link files instead of copying\n\ + -L, --dereference always follow symbolic links\n\ + -p, --preserve preserve file attributes if possible\n\ + --parents append source path to DIRECTORY\n\ + -P same as `--parents' for now; soon to change to\n\ + `--no-dereference' to conform to POSIX\n\ + -r copy recursively, non-directories as files\n\ + WARNING: use -R instead when you might copy\n\ + special files like FIFOs or /dev/zero\n\ + --remove-destination remove each existing destination file before\n\ + attempting to open it (contrast with --force)\n\ +")); + printf (_("\ + --sparse=WHEN control creation of sparse files\n\ + -R, --recursive copy directories recursively\n\ + --strip-trailing-slashes remove any trailing slashes from each SOURCE\n\ + argument\n\ + -s, --symbolic-link make symbolic links instead of copying\n\ + -S, --suffix=SUFFIX override the usual backup suffix\n\ + --target-directory=DIRECTORY move all SOURCE arguments into DIRECTORY\n\ + -u, --update copy only when the SOURCE file is newer\n\ + than the destination file or when the\n\ + destination file is missing\n\ + -v, --verbose explain what is being done\n\ + -x, --one-file-system stay on this file system\n\ + --help display this help and exit\n\ + --version output version information and exit\n\ +\n\ +By default, sparse SOURCE files are detected by a crude heuristic and the\n\ +corresponding DEST file is made sparse as well. That is the behavior\n\ +selected by --sparse=auto. Specify --sparse=always to create a sparse DEST\n\ +file whenever the SOURCE file contains a long enough sequence of zero bytes.\n\ +Use --sparse=never to inhibit creation of sparse files.\n\ +\n\ +")); + printf (_("\ +The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\ +The version control method may be selected via the --backup option or through\n\ +the VERSION_CONTROL environment variable. Here are the values:\n\ +\n\ + none, off never make backups (even if --backup is given)\n\ + numbered, t make numbered backups\n\ + existing, nil numbered if numbered backups exist, simple otherwise\n\ + simple, never always make simple backups\n\ +")); + printf (_("\ +\n\ +As a special case, cp makes a backup of SOURCE when the force and backup\n\ +options are given and SOURCE and DEST are the same name for an existing,\n\ +regular file.\n\ +")); + puts (_("\nReport bugs to .")); + } + exit (status); +} + +/* Ensure that the parent directories of CONST_DST_PATH have the + correct protections, for the --parents option. This is done + after all copying has been completed, to allow permissions + that don't include user write/execute. + + SRC_OFFSET is the index in CONST_DST_PATH of the beginning of the + source directory name. + + ATTR_LIST is a null-terminated linked list of structures that + indicates the end of the filename of each intermediate directory + in CONST_DST_PATH that may need to have its attributes changed. + The command `cp --parents --preserve a/b/c d/e_dir' changes the + attributes of the directories d/e_dir/a and d/e_dir/a/b to match + the corresponding source directories regardless of whether they + existed before the `cp' command was given. + + Return 0 if the parent of CONST_DST_PATH and any intermediate + directories specified by ATTR_LIST have the proper permissions + when done, otherwise 1. */ + +static int +re_protect (const char *const_dst_path, int src_offset, + struct dir_attr *attr_list, const struct cp_options *x) +{ + struct dir_attr *p; + char *dst_path; /* A copy of CONST_DST_PATH we can change. */ + char *src_path; /* The source name in `dst_path'. */ + uid_t myeuid = geteuid (); + + dst_path = (char *) alloca (strlen (const_dst_path) + 1); + strcpy (dst_path, const_dst_path); + src_path = dst_path + src_offset; + + for (p = attr_list; p; p = p->next) + { + struct stat src_sb; + + dst_path[p->slash_offset] = '\0'; + + if ((*(x->xstat)) (src_path, &src_sb)) + { + error (0, errno, _("getting attributes of %s"), + quote (src_path)); + return 1; + } + + /* Adjust the times (and if possible, ownership) for the copy. + chown turns off set[ug]id bits for non-root, + so do the chmod last. */ + + if (x->preserve_timestamps) + { + struct utimbuf utb; + + /* There's currently no interface to set file timestamps with + better than 1-second resolution, so discard any fractional + part of the source timestamp. */ + + utb.actime = src_sb.st_atime; + utb.modtime = src_sb.st_mtime; + + if (utime (dst_path, &utb)) + { + error (0, errno, _("preserving times for %s"), quote (dst_path)); + return 1; + } + } + + if (x->preserve_owner_and_group) + { + /* If non-root uses -p, it's ok if we can't preserve ownership. + But root probably wants to know, e.g. if NFS disallows it, + or if the target system doesn't support file ownership. */ + if (chown (dst_path, src_sb.st_uid, src_sb.st_gid) + && ((errno != EPERM && errno != EINVAL) || myeuid == 0)) + { + error (0, errno, _("preserving ownership for %s"), + quote (dst_path)); + return 1; + } + } + + if (x->preserve_chmod_bits || p->is_new_dir) + { + if (chmod (dst_path, src_sb.st_mode & x->umask_kill)) + { + error (0, errno, _("preserving permissions for %s"), + quote (dst_path)); + return 1; + } + } + + dst_path[p->slash_offset] = '/'; + } + return 0; +} + +/* Ensure that the parent directory of CONST_DIRPATH exists, for + the --parents option. + + SRC_OFFSET is the index in CONST_DIRPATH (which is a destination + path) of the beginning of the source directory name. + Create any leading directories that don't already exist, + giving them permissions MODE. + If VERBOSE_FMT_STRING is nonzero, use it as a printf format + string for printing a message after successfully making a directory. + The format should take two string arguments: the names of the + source and destination directories. + Creates a linked list of attributes of intermediate directories, + *ATTR_LIST, for re_protect to use after calling copy. + Sets *NEW_DST to 1 if this function creates parent of CONST_DIRPATH. + + Return 0 if parent of CONST_DIRPATH exists as a directory with the proper + permissions when done, otherwise 1. */ + +/* FIXME: find a way to synch this function with the one in lib/makepath.c. */ + +static int +make_path_private (const char *const_dirpath, int src_offset, int mode, + const char *verbose_fmt_string, struct dir_attr **attr_list, + int *new_dst, int (*xstat)()) +{ + struct stat stats; + char *dirpath; /* A copy of CONST_DIRPATH we can change. */ + char *src; /* Source name in `dirpath'. */ + char *tmp_dst_dirname; /* Leading path of `dirpath', malloc. */ + char *dst_dirname; /* Leading path of `dirpath', alloca. */ + + dirpath = (char *) alloca (strlen (const_dirpath) + 1); + strcpy (dirpath, const_dirpath); + + src = dirpath + src_offset; + + tmp_dst_dirname = dir_name (dirpath); + dst_dirname = (char *) alloca (strlen (tmp_dst_dirname) + 1); + strcpy (dst_dirname, tmp_dst_dirname); + free (tmp_dst_dirname); + + *attr_list = NULL; + + if ((*xstat) (dst_dirname, &stats)) + { + /* Parent of CONST_DIRNAME does not exist. + Make all missing intermediate directories. */ + char *slash; + + slash = src; + while (*slash == '/') + slash++; + while ((slash = strchr (slash, '/'))) + { + /* Add this directory to the list of directories whose modes need + fixing later. */ + struct dir_attr *new = + (struct dir_attr *) xmalloc (sizeof (struct dir_attr)); + new->slash_offset = slash - dirpath; + new->next = *attr_list; + *attr_list = new; + + *slash = '\0'; + if ((*xstat) (dirpath, &stats)) + { + /* This element of the path does not exist. We must set + *new_dst and new->is_new_dir inside this loop because, + for example, in the command `cp --parents ../a/../b/c e_dir', + make_path_private creates only e_dir/../a if ./b already + exists. */ + *new_dst = 1; + new->is_new_dir = 1; + if (mkdir (dirpath, mode)) + { + error (0, errno, _("cannot make directory %s"), + quote (dirpath)); + return 1; + } + else + { + if (verbose_fmt_string != NULL) + printf (verbose_fmt_string, src, dirpath); + } + } + else if (!S_ISDIR (stats.st_mode)) + { + error (0, 0, _("%s exists but is not a directory"), + quote (dirpath)); + return 1; + } + else + { + new->is_new_dir = 0; + *new_dst = 0; + } + *slash++ = '/'; + + /* Avoid unnecessary calls to `stat' when given + pathnames containing multiple adjacent slashes. */ + while (*slash == '/') + slash++; + } + } + + /* We get here if the parent of `dirpath' already exists. */ + + else if (!S_ISDIR (stats.st_mode)) + { + error (0, 0, _("%s exists but is not a directory"), quote (dst_dirname)); + return 1; + } + else + { + *new_dst = 0; + } + return 0; +} + +/* Scan the arguments, and copy each by calling copy. + Return 0 if successful, 1 if any errors occur. */ + +static int +do_copy (int n_files, char **file, const char *target_directory, + const struct cp_options *x) +{ + const char *dest; + struct stat sb; + int new_dst = 0; + int ret = 0; + int dest_is_dir = 0; + + if (n_files <= 0) + { + error (0, 0, _("missing file arguments")); + usage (1); + } + if (n_files == 1 && !target_directory) + { + error (0, 0, _("missing destination file")); + usage (1); + } + + if (target_directory) + dest = target_directory; + else + { + dest = file[n_files - 1]; + --n_files; + } + + if (lstat (dest, &sb)) + { + if (errno != ENOENT) + { + error (0, errno, _("accessing %s"), quote (dest)); + return 1; + } + + new_dst = 1; + } + else + { + struct stat sbx; + + /* If `dest' is not a symlink to a nonexistent file, use + the results of stat instead of lstat, so we can copy files + into symlinks to directories. */ + if (stat (dest, &sbx) == 0) + sb = sbx; + + dest_is_dir = S_ISDIR (sb.st_mode); + } + + if (!dest_is_dir) + { + if (target_directory) + { + error (0, 0, _("specified target, %s is not a directory"), + quote (dest)); + usage (1); + } + + if (n_files > 1) + { + error (0, 0, + _("copying multiple files, but last argument %s is not a directory"), + quote (dest)); + usage (1); + } + } + + if (dest_is_dir) + { + /* cp file1...filen edir + Copy the files `file1' through `filen' + to the existing directory `edir'. */ + int i; + + for (i = 0; i < n_files; i++) + { + char *dst_path; + int parent_exists = 1; /* True if dir_name (dst_path) exists. */ + struct dir_attr *attr_list; + char *arg_in_concat = NULL; + char *arg = file[i]; + + /* Trailing slashes are meaningful (i.e., maybe worth preserving) + only in the source file names. */ + if (remove_trailing_slashes) + strip_trailing_slashes (arg); + + if (flag_path) + { + char *arg_no_trailing_slash; + + /* Use `arg' without trailing slashes in constructing destination + file names. Otherwise, we can end up trying to create a + directory via `mkdir ("dst/foo/"...', which is not portable. + It fails, due to the trailing slash, on at least + NetBSD 1.[34] systems. */ + ASSIGN_STRDUPA (arg_no_trailing_slash, arg); + strip_trailing_slashes (arg_no_trailing_slash); + + /* Append all of `arg' (minus any trailing slash) to `dest'. */ + dst_path = path_concat (dest, arg_no_trailing_slash, + &arg_in_concat); + if (dst_path == NULL) + xalloc_die (); + + /* For --parents, we have to make sure that the directory + dir_name (dst_path) exists. We may have to create a few + leading directories. */ + parent_exists = !make_path_private (dst_path, + arg_in_concat - dst_path, + S_IRWXU, + (x->verbose + ? "%s -> %s\n" : NULL), + &attr_list, &new_dst, + x->xstat); + } + else + { + char *arg_base; + /* Append the last component of `arg' to `dest'. */ + + ASSIGN_BASENAME_STRDUPA (arg_base, arg); + /* For `cp -R source/.. dest', don't copy into `dest/..'. */ + dst_path = (STREQ (arg_base, "..") + ? xstrdup (dest) + : path_concat (dest, arg_base, NULL)); + } + + if (!parent_exists) + { + /* make_path_private failed, so don't even attempt the copy. */ + ret = 1; + } + else + { + int copy_into_self; + ret |= copy (arg, dst_path, new_dst, x, ©_into_self, NULL); + forget_all (); + + if (flag_path) + { + ret |= re_protect (dst_path, arg_in_concat - dst_path, + attr_list, x); + } + } + + free (dst_path); + } + return ret; + } + else /* if (n_files == 1) */ + { + char *new_dest; + char *source; + int unused; + struct stat source_stats; + + if (flag_path) + { + error (0, 0, + _("when preserving paths, the destination must be a directory")); + usage (1); + } + + source = file[0]; + + /* When the force and backup options have been specified and + the source and destination are the same name for an existing + regular file, convert the user's command, e.g., + `cp --force --backup foo foo' to `cp --force foo fooSUFFIX' + where SUFFIX is determined by any version control options used. */ + + if (x->unlink_dest_after_failed_open + && x->backup_type != none + && STREQ (source, dest) + && !new_dst && S_ISREG (sb.st_mode)) + { + static struct cp_options x_tmp; + + new_dest = find_backup_file_name (dest, x->backup_type); + /* Set x->backup_type to `none' so that the normal backup + mechanism is not used when performing the actual copy. + backup_type must be set to `none' only *after* the above + call to find_backup_file_name -- that function uses + backup_type to determine the suffix it applies. */ + x_tmp = *x; + x_tmp.backup_type = none; + x = &x_tmp; + + if (new_dest == NULL) + xalloc_die (); + } + + /* When the destination is specified with a trailing slash and the + source exists but is not a directory, convert the user's command + `cp source dest/' to `cp source dest/basename(source)'. Doing + this ensures that the command `cp non-directory file/' will now + fail rather than performing the copy. COPY diagnoses the case of + `cp directory non-directory'. */ + + else if (dest[strlen (dest) - 1] == '/' + && lstat (source, &source_stats) == 0 + && !S_ISDIR (source_stats.st_mode)) + { + char *source_base; + + ASSIGN_BASENAME_STRDUPA (source_base, source); + new_dest = (char *) alloca (strlen (dest) + + strlen (source_base) + 1); + stpcpy (stpcpy (new_dest, dest), source_base); + } + else + { + new_dest = (char *) dest; + } + + return copy (source, new_dest, new_dst, x, &unused, NULL); + } + + /* unreachable */ +} + +static void +cp_option_init (struct cp_options *x) +{ + x->copy_as_regular = 1; + x->dereference = DEREF_UNDEFINED; + x->unlink_dest_before_opening = 0; + x->unlink_dest_after_failed_open = 0; + x->failed_unlink_is_fatal = 1; + x->hard_link = 0; + x->interactive = 0; + x->myeuid = geteuid (); + x->move_mode = 0; + x->one_file_system = 0; + + x->preserve_owner_and_group = 0; + x->preserve_chmod_bits = 0; + x->preserve_timestamps = 0; + + x->require_preserve = 0; + x->recursive = 0; + x->sparse_mode = SPARSE_AUTO; + x->symbolic_link = 0; + x->set_mode = 0; + x->mode = 0; + + /* Find out the current file creation mask, to knock the right bits + when using chmod. The creation mask is set to be liberal, so + that created directories can be written, even if it would not + have been allowed with the mask this process was started with. */ + x->umask_kill = ~ umask (0); + + x->update = 0; + x->verbose = 0; +} + +int +main (int argc, char **argv) +{ + int c; + int make_backups = 0; + char *backup_suffix_string; + char *version_control_string = NULL; + struct cp_options x; + char *target_directory = NULL; + int used_P_option = 0; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + cp_option_init (&x); + + /* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless + we'll actually use backup_suffix_string. */ + backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); + + while ((c = getopt_long (argc, argv, "abdfHilLprsuvxPRS:V:", long_opts, NULL)) + != -1) + { + switch (c) + { + case 0: + break; + + case SPARSE_OPTION: + x.sparse_mode = XARGMATCH ("--sparse", optarg, + sparse_type_string, sparse_type); + break; + + case 'a': /* Like -dpR. */ + x.dereference = DEREF_NEVER; + x.preserve_owner_and_group = 1; + x.preserve_chmod_bits = 1; + x.preserve_timestamps = 1; + x.require_preserve = 1; + x.recursive = 1; + x.copy_as_regular = 0; + break; + + case 'V': /* FIXME: this is deprecated. Remove it in 2001. */ + error (0, 0, + _("warning: --version-control (-V) is obsolete; support for\ + it\nwill be removed in some future release. Use --backup=%s instead." + ), optarg); + /* Fall through. */ + + case 'b': + make_backups = 1; + if (optarg) + version_control_string = optarg; + break; + + case 'd': + x.dereference = DEREF_NEVER; + break; + + case 'f': + x.unlink_dest_after_failed_open = 1; + break; + + case 'H': + x.dereference = DEREF_COMMAND_LINE_ARGUMENTS; + break; + + case 'i': + x.interactive = 1; + break; + + case 'l': + x.hard_link = 1; + break; + + case 'L': + x.dereference = DEREF_ALWAYS; + break; + + case 'p': + x.preserve_owner_and_group = 1; + x.preserve_chmod_bits = 1; + x.preserve_timestamps = 1; + x.require_preserve = 1; + break; + + case 'P': + used_P_option = 1; + /* fall through */ + case PARENTS_OPTION: + flag_path = 1; + break; + + case 'r': + x.recursive = 1; + x.copy_as_regular = 1; + break; + + case 'R': + x.recursive = 1; + x.copy_as_regular = 0; + break; + + case UNLINK_DEST_BEFORE_OPENING: + x.unlink_dest_before_opening = 1; + break; + + case STRIP_TRAILING_SLASHES_OPTION: + remove_trailing_slashes = 1; + break; + + case 's': +#ifdef S_ISLNK + x.symbolic_link = 1; +#else + error (1, 0, _("symbolic links are not supported on this system")); +#endif + break; + + case TARGET_DIRECTORY_OPTION: + target_directory = optarg; + break; + + case 'u': + x.update = 1; + break; + + case 'v': + x.verbose = 1; + break; + + case 'x': + x.one_file_system = 1; + break; + + case 'S': + make_backups = 1; + backup_suffix_string = optarg; + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (1); + } + } + + if (x.hard_link && x.symbolic_link) + { + error (0, 0, _("cannot make both hard and symbolic links")); + usage (1); + } + + if (used_P_option) + { + error (0, 0, + _("\ +Warning: the meaning of `-P' will change in the future to conform to POSIX.\n\ +Use `--parents' for the old meaning, and `--no-dereference' for the new one.")); + } + + if (backup_suffix_string) + simple_backup_suffix = xstrdup (backup_suffix_string); + + x.backup_type = (make_backups + ? xget_version (_("backup type"), + version_control_string) + : none); + + if (x.preserve_chmod_bits == 1) + x.umask_kill = ~ (mode_t) 0; + + if (x.dereference == DEREF_UNDEFINED) + { + if (x.recursive) + /* This is compatible with FreeBSD. */ + x.dereference = DEREF_NEVER; + else + x.dereference = DEREF_ALWAYS; + } + + /* The key difference between -d (--no-dereference) and not is the version + of `stat' to call. */ + + if (x.dereference == DEREF_NEVER) + x.xstat = lstat; + else + { + /* For DEREF_COMMAND_LINE_ARGUMENTS, x.xstat must be stat for + each command line argument, but must later be `lstat' for + any symlinks that are found via recursive traversal. */ + x.xstat = stat; + } + + /* If --force (-f) was specified and we're in link-creation mode, + first remove any existing destination file. */ + if (x.unlink_dest_after_failed_open && (x.hard_link || x.symbolic_link)) + x.unlink_dest_before_opening = 1; + + /* Allocate space for remembering copied and created files. */ + + hash_init (INITIAL_HASH_MODULE, INITIAL_ENTRY_TAB_SIZE); + + exit_status |= do_copy (argc - optind, argv + optind, target_directory, &x); + + exit (exit_status); +} diff --git a/src/apps/bin/gnu/dd.c b/src/apps/bin/gnu/dd.c new file mode 100644 index 0000000000..b493accf4b --- /dev/null +++ b/src/apps/bin/gnu/dd.c @@ -0,0 +1,1202 @@ +/* dd -- convert a file while copying it. + Copyright (C) 85, 90, 91, 1995-2001 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Paul Rubin, David MacKenzie, and Stuart Kemp. */ + +#include +#include + +#define SWAB_ALIGN_OFFSET 2 + +#if HAVE_INTTYPES_H +# include +#endif +#include +#include +#include + +#include "system.h" +#include "closeout.h" +#include "error.h" +#include "getpagesize.h" +#include "human.h" +#include "long-options.h" +#include "quote.h" +#include "safe-read.h" +#include "xstrtol.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "dd" + +#define AUTHORS "Paul Rubin, David MacKenzie, and Stuart Kemp" + +#ifndef SIGINFO +# define SIGINFO SIGUSR1 +#endif + +#ifndef S_TYPEISSHM +# define S_TYPEISSHM(Stat_ptr) 0 +#endif + +#define ROUND_UP_OFFSET(X, M) ((M) - 1 - (((X) + (M) - 1) % (M))) +#define PTR_ALIGN(Ptr, M) ((Ptr) \ + + ROUND_UP_OFFSET ((char *)(Ptr) - (char *)0, (M))) + +#define max(a, b) ((a) > (b) ? (a) : (b)) +#define output_char(c) \ + do \ + { \ + obuf[oc++] = (c); \ + if (oc >= output_blocksize) \ + write_output (); \ + } \ + while (0) + +/* Default input and output blocksize. */ +#define DEFAULT_BLOCKSIZE 512 + +/* Conversions bit masks. */ +#define C_ASCII 01 +#define C_EBCDIC 02 +#define C_IBM 04 +#define C_BLOCK 010 +#define C_UNBLOCK 020 +#define C_LCASE 040 +#define C_UCASE 0100 +#define C_SWAB 0200 +#define C_NOERROR 0400 +#define C_NOTRUNC 01000 +#define C_SYNC 02000 +/* Use separate input and output buffers, and combine partial input blocks. */ +#define C_TWOBUFS 04000 + +int full_write (); + +/* The name this program was run with. */ +char *program_name; + +/* The name of the input file, or NULL for the standard input. */ +static char *input_file = NULL; + +/* The name of the output file, or NULL for the standard output. */ +static char *output_file = NULL; + +/* The number of bytes in which atomic reads are done. */ +static size_t input_blocksize = 0; + +/* The number of bytes in which atomic writes are done. */ +static size_t output_blocksize = 0; + +/* Conversion buffer size, in bytes. 0 prevents conversions. */ +static size_t conversion_blocksize = 0; + +/* Skip this many records of `input_blocksize' bytes before input. */ +static uintmax_t skip_records = 0; + +/* Skip this many records of `output_blocksize' bytes before output. */ +static uintmax_t seek_records = 0; + +/* Copy only this many records. The default is effectively infinity. */ +static uintmax_t max_records = (uintmax_t) -1; + +/* Bit vector of conversions to apply. */ +static int conversions_mask = 0; + +/* If nonzero, filter characters through the translation table. */ +static int translation_needed = 0; + +/* Number of partial blocks written. */ +static uintmax_t w_partial = 0; + +/* Number of full blocks written. */ +static uintmax_t w_full = 0; + +/* Number of partial blocks read. */ +static uintmax_t r_partial = 0; + +/* Number of full blocks read. */ +static uintmax_t r_full = 0; + +/* Records truncated by conv=block. */ +static uintmax_t r_truncate = 0; + +/* Output representation of newline and space characters. + They change if we're converting to EBCDIC. */ +static unsigned char newline_character = '\n'; +static unsigned char space_character = ' '; + +/* Output buffer. */ +static unsigned char *obuf; + +/* Current index into `obuf'. */ +static size_t oc = 0; + +/* Index into current line, for `conv=block' and `conv=unblock'. */ +static size_t col = 0; + +struct conversion +{ + char *convname; + int conversion; +}; + +static struct conversion conversions[] = +{ + {"ascii", C_ASCII | C_TWOBUFS}, /* EBCDIC to ASCII. */ + {"ebcdic", C_EBCDIC | C_TWOBUFS}, /* ASCII to EBCDIC. */ + {"ibm", C_IBM | C_TWOBUFS}, /* Slightly different ASCII to EBCDIC. */ + {"block", C_BLOCK | C_TWOBUFS}, /* Variable to fixed length records. */ + {"unblock", C_UNBLOCK | C_TWOBUFS}, /* Fixed to variable length records. */ + {"lcase", C_LCASE | C_TWOBUFS}, /* Translate upper to lower case. */ + {"ucase", C_UCASE | C_TWOBUFS}, /* Translate lower to upper case. */ + {"swab", C_SWAB | C_TWOBUFS}, /* Swap bytes of input. */ + {"noerror", C_NOERROR}, /* Ignore i/o errors. */ + {"notrunc", C_NOTRUNC}, /* Do not truncate output file. */ + {"sync", C_SYNC}, /* Pad input records to ibs with NULs. */ + {NULL, 0} +}; + +/* Translation table formed by applying successive transformations. */ +static unsigned char trans_table[256]; + +static unsigned char const ascii_to_ebcdic[] = +{ + 0, 01, 02, 03, 067, 055, 056, 057, + 026, 05, 045, 013, 014, 015, 016, 017, + 020, 021, 022, 023, 074, 075, 062, 046, + 030, 031, 077, 047, 034, 035, 036, 037, + 0100, 0117, 0177, 0173, 0133, 0154, 0120, 0175, + 0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141, + 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, + 0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157, + 0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307, + 0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326, + 0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346, + 0347, 0350, 0351, 0112, 0340, 0132, 0137, 0155, + 0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207, + 0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226, + 0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246, + 0247, 0250, 0251, 0300, 0152, 0320, 0241, 07, + 040, 041, 042, 043, 044, 025, 06, 027, + 050, 051, 052, 053, 054, 011, 012, 033, + 060, 061, 032, 063, 064, 065, 066, 010, + 070, 071, 072, 073, 04, 024, 076, 0341, + 0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110, + 0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127, + 0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147, + 0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165, + 0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215, + 0216, 0217, 0220, 0232, 0233, 0234, 0235, 0236, + 0237, 0240, 0252, 0253, 0254, 0255, 0256, 0257, + 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, + 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, + 0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333, + 0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355, + 0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377 +}; + +static unsigned char const ascii_to_ibm[] = +{ + 0, 01, 02, 03, 067, 055, 056, 057, + 026, 05, 045, 013, 014, 015, 016, 017, + 020, 021, 022, 023, 074, 075, 062, 046, + 030, 031, 077, 047, 034, 035, 036, 037, + 0100, 0132, 0177, 0173, 0133, 0154, 0120, 0175, + 0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141, + 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, + 0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157, + 0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307, + 0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326, + 0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346, + 0347, 0350, 0351, 0255, 0340, 0275, 0137, 0155, + 0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207, + 0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226, + 0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246, + 0247, 0250, 0251, 0300, 0117, 0320, 0241, 07, + 040, 041, 042, 043, 044, 025, 06, 027, + 050, 051, 052, 053, 054, 011, 012, 033, + 060, 061, 032, 063, 064, 065, 066, 010, + 070, 071, 072, 073, 04, 024, 076, 0341, + 0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110, + 0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127, + 0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147, + 0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165, + 0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215, + 0216, 0217, 0220, 0232, 0233, 0234, 0235, 0236, + 0237, 0240, 0252, 0253, 0254, 0255, 0256, 0257, + 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, + 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, + 0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333, + 0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355, + 0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377 +}; + +static unsigned char const ebcdic_to_ascii[] = +{ + 0, 01, 02, 03, 0234, 011, 0206, 0177, + 0227, 0215, 0216, 013, 014, 015, 016, 017, + 020, 021, 022, 023, 0235, 0205, 010, 0207, + 030, 031, 0222, 0217, 034, 035, 036, 037, + 0200, 0201, 0202, 0203, 0204, 012, 027, 033, + 0210, 0211, 0212, 0213, 0214, 05, 06, 07, + 0220, 0221, 026, 0223, 0224, 0225, 0226, 04, + 0230, 0231, 0232, 0233, 024, 025, 0236, 032, + 040, 0240, 0241, 0242, 0243, 0244, 0245, 0246, + 0247, 0250, 0133, 056, 074, 050, 053, 041, + 046, 0251, 0252, 0253, 0254, 0255, 0256, 0257, + 0260, 0261, 0135, 044, 052, 051, 073, 0136, + 055, 057, 0262, 0263, 0264, 0265, 0266, 0267, + 0270, 0271, 0174, 054, 045, 0137, 076, 077, + 0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301, + 0302, 0140, 072, 043, 0100, 047, 075, 042, + 0303, 0141, 0142, 0143, 0144, 0145, 0146, 0147, + 0150, 0151, 0304, 0305, 0306, 0307, 0310, 0311, + 0312, 0152, 0153, 0154, 0155, 0156, 0157, 0160, + 0161, 0162, 0313, 0314, 0315, 0316, 0317, 0320, + 0321, 0176, 0163, 0164, 0165, 0166, 0167, 0170, + 0171, 0172, 0322, 0323, 0324, 0325, 0326, 0327, + 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337, + 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347, + 0173, 0101, 0102, 0103, 0104, 0105, 0106, 0107, + 0110, 0111, 0350, 0351, 0352, 0353, 0354, 0355, + 0175, 0112, 0113, 0114, 0115, 0116, 0117, 0120, + 0121, 0122, 0356, 0357, 0360, 0361, 0362, 0363, + 0134, 0237, 0123, 0124, 0125, 0126, 0127, 0130, + 0131, 0132, 0364, 0365, 0366, 0367, 0370, 0371, + 060, 061, 062, 063, 064, 065, 066, 067, + 070, 071, 0372, 0373, 0374, 0375, 0376, 0377 +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]...\n"), program_name); + printf (_("\ +Copy a file, converting and formatting according to the options.\n\ +\n\ + bs=BYTES force ibs=BYTES and obs=BYTES\n\ + cbs=BYTES convert BYTES bytes at a time\n\ + conv=KEYWORDS convert the file as per the comma separated keyword list\n\ + count=BLOCKS copy only BLOCKS input blocks\n\ + ibs=BYTES read BYTES bytes at a time\n\ + if=FILE read from FILE instead of stdin\n\ + obs=BYTES write BYTES bytes at a time\n\ + of=FILE write to FILE instead of stdout\n\ + seek=BLOCKS skip BLOCKS obs-sized blocks at start of output\n\ + skip=BLOCKS skip BLOCKS ibs-sized blocks at start of input\n\ + --help display this help and exit\n\ + --version output version information and exit\n\ +\n\ +BLOCKS and BYTES may be followed by the following multiplicative suffixes:\n\ +xM M, c 1, w 2, b 512, kD 1000, k 1024, MD 1,000,000, M 1,048,576,\n\ +GD 1,000,000,000, G 1,073,741,824, and so on for T, P, E, Z, Y.\n\ +Each KEYWORD may be:\n\ +\n\ + ascii from EBCDIC to ASCII\n\ + ebcdic from ASCII to EBCDIC\n\ + ibm from ASCII to alternated EBCDIC\n\ + block pad newline-terminated records with spaces to cbs-size\n\ + unblock replace trailing spaces in cbs-size records with newline\n\ + lcase change upper case to lower case\n\ + notrunc do not truncate the output file\n\ + ucase change lower case to upper case\n\ + swab swap every pair of input bytes\n\ + noerror continue after read errors\n\ + sync pad every input block with NULs to ibs-size; when used\n\ + with block or unblock, pad with spaces rather than NULs\n\ +")); + puts (_("\nReport bugs to .")); + } + exit (status); +} + +static void +translate_charset (const unsigned char *new_trans) +{ + unsigned int i; + + for (i = 0; i < 256; i++) + trans_table[i] = new_trans[trans_table[i]]; + translation_needed = 1; +} + +/* Return the number of 1 bits in `i'. */ + +static int +bit_count (register unsigned int i) +{ + register int set_bits; + + for (set_bits = 0; i != 0; set_bits++) + i &= i - 1; + return set_bits; +} + +static void +print_stats (void) +{ + char buf[2][LONGEST_HUMAN_READABLE + 1]; + fprintf (stderr, _("%s+%s records in\n"), + human_readable (r_full, buf[0], 1, 1), + human_readable (r_partial, buf[1], 1, 1)); + fprintf (stderr, _("%s+%s records out\n"), + human_readable (w_full, buf[0], 1, 1), + human_readable (w_partial, buf[1], 1, 1)); + if (r_truncate > 0) + { + fprintf (stderr, "%s %s\n", + human_readable (r_truncate, buf[0], 1, 1), + (r_truncate == 1 + ? _("truncated record") + : _("truncated records"))); + } +} + +static void +cleanup (void) +{ + print_stats (); + if (close (STDIN_FILENO) < 0) + error (1, errno, _("closing input file %s"), quote (input_file)); + if (close (STDOUT_FILENO) < 0) + error (1, errno, _("closing output file %s"), quote (output_file)); +} + +static inline void +quit (int code) +{ + cleanup (); + exit (code); +} + +static RETSIGTYPE +interrupt_handler (int sig) +{ +#ifdef SA_NOCLDSTOP + struct sigaction sigact; + + sigact.sa_handler = SIG_DFL; + sigemptyset (&sigact.sa_mask); + sigact.sa_flags = 0; + sigaction (sig, &sigact, NULL); +#else + signal (sig, SIG_DFL); +#endif + cleanup (); + kill (getpid (), sig); +} + +static RETSIGTYPE +siginfo_handler (int sig ATTRIBUTE_UNUSED) +{ + print_stats (); +} + +/* Encapsulate portability mess of establishing signal handlers. */ + +static void +install_handler (int sig_num, RETSIGTYPE (*sig_handler) (int sig)) +{ +#ifdef SA_NOCLDSTOP + struct sigaction sigact; + sigaction (sig_num, NULL, &sigact); + if (sigact.sa_handler != SIG_IGN) + { + sigact.sa_handler = sig_handler; + sigemptyset (&sigact.sa_mask); + sigact.sa_flags = 0; + sigaction (sig_num, &sigact, NULL); + } +#else + if (signal (sig_num, SIG_IGN) != SIG_IGN) + signal (sig_num, sig_handler); +#endif +} + +/* Open a file to a particular file descriptor. This is like standard + `open', except it always returns DESIRED_FD if successful. */ +static int +open_fd (int desired_fd, char const *filename, int options, mode_t mode) +{ + int fd; + close (desired_fd); + fd = open (filename, options, mode); + if (fd < 0) + return -1; + + if (fd != desired_fd) + { + if (dup2 (fd, desired_fd) != desired_fd) + desired_fd = -1; + if (close (fd) != 0) + return -1; + } + + return desired_fd; +} + +/* Write, then empty, the output buffer `obuf'. */ + +static void +write_output (void) +{ + int nwritten = full_write (STDOUT_FILENO, obuf, output_blocksize); + if (nwritten != output_blocksize) + { + error (0, errno, _("writing to %s"), quote (output_file)); + if (nwritten > 0) + w_partial++; + quit (1); + } + else + w_full++; + oc = 0; +} + +/* Interpret one "conv=..." option. + As a by product, this function replaces each `,' in STR with a NUL byte. */ + +static void +parse_conversion (char *str) +{ + char *new; + unsigned int i; + + do + { + new = strchr (str, ','); + if (new != NULL) + *new++ = '\0'; + for (i = 0; conversions[i].convname != NULL; i++) + if (STREQ (conversions[i].convname, str)) + { + conversions_mask |= conversions[i].conversion; + break; + } + if (conversions[i].convname == NULL) + { + error (0, 0, _("invalid conversion: %s"), quote (str)); + usage (1); + } + str = new; + } while (new != NULL); +} + +/* Return the value of STR, interpreted as a non-negative decimal integer, + optionally multiplied by various values. + Assign nonzero to *INVALID if STR does not represent a number in + this format. */ + +static uintmax_t +parse_integer (const char *str, int *invalid) +{ + uintmax_t n; + char *suffix; + enum strtol_error e = xstrtoumax (str, &suffix, 10, &n, "bcEGkMPTwYZ0"); + + if (e == LONGINT_INVALID_SUFFIX_CHAR && *suffix == 'x') + { + uintmax_t multiplier = parse_integer (suffix + 1, invalid); + + if (multiplier != 0 && n * multiplier / multiplier != n) + { + *invalid = 1; + return 0; + } + + n *= multiplier; + } + else if (e != LONGINT_OK) + { + *invalid = 1; + return 0; + } + + return n; +} + +static void +scanargs (int argc, char **argv) +{ + int i; + + --argc; + ++argv; + + for (i = optind; i < argc; i++) + { + char *name, *val; + + name = argv[i]; + val = strchr (name, '='); + if (val == NULL) + { + error (0, 0, _("unrecognized option %s"), quote (name)); + usage (1); + } + *val++ = '\0'; + + if (STREQ (name, "if")) + input_file = val; + else if (STREQ (name, "of")) + output_file = val; + else if (STREQ (name, "conv")) + parse_conversion (val); + else + { + int invalid = 0; + uintmax_t n = parse_integer (val, &invalid); + + if (STREQ (name, "ibs")) + { + input_blocksize = n; + invalid |= input_blocksize != n || input_blocksize == 0; + conversions_mask |= C_TWOBUFS; + } + else if (STREQ (name, "obs")) + { + output_blocksize = n; + invalid |= output_blocksize != n || output_blocksize == 0; + conversions_mask |= C_TWOBUFS; + } + else if (STREQ (name, "bs")) + { + output_blocksize = input_blocksize = n; + invalid |= output_blocksize != n || output_blocksize == 0; + } + else if (STREQ (name, "cbs")) + { + conversion_blocksize = n; + invalid |= (conversion_blocksize != n + || conversion_blocksize == 0); + } + else if (STREQ (name, "skip")) + skip_records = n; + else if (STREQ (name, "seek")) + seek_records = n; + else if (STREQ (name, "count")) + max_records = n; + else + { + error (0, 0, _("unrecognized option %s=%s"), + quote_n (0, name), quote_n (1, val)); + usage (1); + } + + if (invalid) + error (1, 0, _("invalid number %s"), quote (val)); + } + } + + /* If bs= was given, both `input_blocksize' and `output_blocksize' will + have been set to positive values. If either has not been set, + bs= was not given, so make sure two buffers are used. */ + if (input_blocksize == 0 || output_blocksize == 0) + conversions_mask |= C_TWOBUFS; + if (input_blocksize == 0) + input_blocksize = DEFAULT_BLOCKSIZE; + if (output_blocksize == 0) + output_blocksize = DEFAULT_BLOCKSIZE; + if (conversion_blocksize == 0) + conversions_mask &= ~(C_BLOCK | C_UNBLOCK); +} + +/* Fix up translation table. */ + +static void +apply_translations (void) +{ + unsigned int i; + +#define MX(a) (bit_count (conversions_mask & (a))) + if ((MX (C_ASCII | C_EBCDIC | C_IBM) > 1) + || (MX (C_BLOCK | C_UNBLOCK) > 1) + || (MX (C_LCASE | C_UCASE) > 1) + || (MX (C_UNBLOCK | C_SYNC) > 1)) + { + error (1, 0, _("\ +only one conv in {ascii,ebcdic,ibm}, {lcase,ucase}, {block,unblock}, {unblock,sync}")); + } +#undef MX + + if (conversions_mask & C_ASCII) + translate_charset (ebcdic_to_ascii); + + if (conversions_mask & C_UCASE) + { + for (i = 0; i < 256; i++) + if (ISLOWER (trans_table[i])) + trans_table[i] = TOUPPER (trans_table[i]); + translation_needed = 1; + } + else if (conversions_mask & C_LCASE) + { + for (i = 0; i < 256; i++) + if (ISUPPER (trans_table[i])) + trans_table[i] = TOLOWER (trans_table[i]); + translation_needed = 1; + } + + if (conversions_mask & C_EBCDIC) + { + translate_charset (ascii_to_ebcdic); + newline_character = ascii_to_ebcdic['\n']; + space_character = ascii_to_ebcdic[' ']; + } + else if (conversions_mask & C_IBM) + { + translate_charset (ascii_to_ibm); + newline_character = ascii_to_ibm['\n']; + space_character = ascii_to_ibm[' ']; + } +} + +/* Apply the character-set translations specified by the user + to the NREAD bytes in BUF. */ + +static void +translate_buffer (unsigned char *buf, size_t nread) +{ + unsigned char *cp; + size_t i; + + for (i = nread, cp = buf; i; i--, cp++) + *cp = trans_table[*cp]; +} + +/* If nonnzero, the last char from the previous call to `swab_buffer' + is saved in `saved_char'. */ +static int char_is_saved = 0; + +/* Odd char from previous call. */ +static unsigned char saved_char; + +/* Swap NREAD bytes in BUF, plus possibly an initial char from the + previous call. If NREAD is odd, save the last char for the + next call. Return the new start of the BUF buffer. */ + +static unsigned char * +swab_buffer (unsigned char *buf, size_t *nread) +{ + unsigned char *bufstart = buf; + register unsigned char *cp; + register int i; + + /* Is a char left from last time? */ + if (char_is_saved) + { + *--bufstart = saved_char; + (*nread)++; + char_is_saved = 0; + } + + if (*nread & 1) + { + /* An odd number of chars are in the buffer. */ + saved_char = bufstart[--*nread]; + char_is_saved = 1; + } + + /* Do the byte-swapping by moving every second character two + positions toward the end, working from the end of the buffer + toward the beginning. This way we only move half of the data. */ + + cp = bufstart + *nread; /* Start one char past the last. */ + for (i = *nread / 2; i; i--, cp -= 2) + *cp = *(cp - 2); + + return ++bufstart; +} + +/* Return nonzero iff the file referenced by FDESC is of a type for + which lseek's return value is known to be invalid on some systems. + Otherwise, return zero. + For example, return nonzero if FDESC references a character device + (on any system) because the lseek on many Linux systems incorrectly + returns an offset implying it succeeds for tape devices, even though + the function fails to perform the requested operation. In that case, + lseek should return nonzero and set errno. */ + +static int +buggy_lseek_support (int fdesc) +{ + /* We have to resort to this because on some systems, lseek doesn't work + on some special files but doesn't return an error, either. + In particular, the Linux tape drivers are a problem. + For example, when I did the following using dd-4.0y or earlier on a + Linux-2.2.17 system with an Exabyte SCSI tape drive: + + dev=/dev/nst0 + reset='mt -f $dev rewind; mt -f $dev fsf 1' + eval $reset; dd if=$dev bs=32k of=out1 + eval $reset; dd if=$dev bs=32k of=out2 skip=1 + + the resulting files, out1 and out2, would compare equal. */ + + struct stat stats; + + return (fstat (fdesc, &stats) == 0 + && (S_ISCHR (stats.st_mode))); +} + +/* Throw away RECORDS blocks of BLOCKSIZE bytes on file descriptor FDESC, + which is open with read permission for FILE. Store up to BLOCKSIZE + bytes of the data at a time in BUF, if necessary. RECORDS must be + nonzero. */ + +static void +skip (int fdesc, char *file, uintmax_t records, size_t blocksize, + unsigned char *buf) +{ + off_t offset = records * blocksize; + + /* Try lseek and if an error indicates it was an inappropriate + operation, fall back on using read. Some broken versions of + lseek may return zero, so count that as an error too as a valid + zero return is not possible here. */ + + if (offset / blocksize != records + || buggy_lseek_support (fdesc) + || lseek (fdesc, offset, SEEK_CUR) <= 0) + { + while (records--) + { + ssize_t nread = safe_read (fdesc, buf, blocksize); + if (nread < 0) + { + error (0, errno, _("reading %s"), quote (file)); + quit (1); + } + /* POSIX doesn't say what to do when dd detects it has been + asked to skip past EOF, so I assume it's non-fatal. + FIXME: maybe give a warning. */ + if (nread == 0) + break; + } + } +} + +/* Copy NREAD bytes of BUF, with no conversions. */ + +static void +copy_simple (unsigned char const *buf, int nread) +{ + int nfree; /* Number of unused bytes in `obuf'. */ + const unsigned char *start = buf; /* First uncopied char in BUF. */ + + do + { + nfree = output_blocksize - oc; + if (nfree > nread) + nfree = nread; + + memcpy ((char *) (obuf + oc), (char *) start, nfree); + + nread -= nfree; /* Update the number of bytes left to copy. */ + start += nfree; + oc += nfree; + if (oc >= output_blocksize) + write_output (); + } + while (nread > 0); +} + +/* Copy NREAD bytes of BUF, doing conv=block + (pad newline-terminated records to `conversion_blocksize', + replacing the newline with trailing spaces). */ + +static void +copy_with_block (unsigned char const *buf, size_t nread) +{ + size_t i; + + for (i = nread; i; i--, buf++) + { + if (*buf == newline_character) + { + if (col < conversion_blocksize) + { + size_t j; + for (j = col; j < conversion_blocksize; j++) + output_char (space_character); + } + col = 0; + } + else + { + if (col == conversion_blocksize) + r_truncate++; + else if (col < conversion_blocksize) + output_char (*buf); + col++; + } + } +} + +/* Copy NREAD bytes of BUF, doing conv=unblock + (replace trailing spaces in `conversion_blocksize'-sized records + with a newline). */ + +static void +copy_with_unblock (unsigned char const *buf, size_t nread) +{ + size_t i; + unsigned char c; + static int pending_spaces = 0; + + for (i = 0; i < nread; i++) + { + c = buf[i]; + + if (col++ >= conversion_blocksize) + { + col = pending_spaces = 0; /* Wipe out any pending spaces. */ + i--; /* Push the char back; get it later. */ + output_char (newline_character); + } + else if (c == space_character) + pending_spaces++; + else + { + /* `c' is the character after a run of spaces that were not + at the end of the conversion buffer. Output them. */ + while (pending_spaces) + { + output_char (space_character); + --pending_spaces; + } + output_char (c); + } + } +} + +/* The main loop. */ + +static int +dd_copy (void) +{ + unsigned char *ibuf, *bufstart; /* Input buffer. */ + unsigned char *real_buf; /* real buffer address before alignment */ + unsigned char *real_obuf; + ssize_t nread; /* Bytes read in the current block. */ + int exit_status = 0; + size_t page_size = getpagesize (); + size_t n_bytes_read; + + /* Leave at least one extra byte at the beginning and end of `ibuf' + for conv=swab, but keep the buffer address even. But some peculiar + device drivers work only with word-aligned buffers, so leave an + extra two bytes. */ + + /* Some devices require alignment on a sector or page boundary + (e.g. character disk devices). Align the input buffer to a + page boundary to cover all bases. Note that due to the swab + algorithm, we must have at least one byte in the page before + the input buffer; thus we allocate 2 pages of slop in the + real buffer. 8k above the blocksize shouldn't bother anyone. + + The page alignment is necessary on any linux system that supports + either the SGI raw I/O patch or Steven Tweedies raw I/O patch. + It is necessary when accessing raw (i.e. character special) disk + devices on Unixware or other SVR4-derived system. */ + + real_buf = (unsigned char *) xmalloc (input_blocksize + + 2 * SWAB_ALIGN_OFFSET + + 2 * page_size - 1); + ibuf = real_buf; + ibuf += SWAB_ALIGN_OFFSET; /* allow space for swab */ + + ibuf = PTR_ALIGN (ibuf, page_size); + + if (conversions_mask & C_TWOBUFS) + { + /* Page-align the output buffer, too. */ + real_obuf = (unsigned char *) xmalloc (output_blocksize + page_size - 1); + obuf = PTR_ALIGN (real_obuf, page_size); + } + else + { + real_obuf = NULL; + obuf = ibuf; + } + + if (skip_records != 0) + skip (STDIN_FILENO, input_file, skip_records, input_blocksize, ibuf); + + if (seek_records != 0) + { + /* FIXME: this loses for + % ./dd if=dd seek=1 |: + ./dd: standard output: Bad file descriptor + 0+0 records in + 0+0 records out + */ + + skip (STDOUT_FILENO, output_file, seek_records, output_blocksize, obuf); + } + + if (max_records == 0) + quit (exit_status); + + while (1) + { + if (r_partial + r_full >= max_records) + break; + + /* Zero the buffer before reading, so that if we get a read error, + whatever data we are able to read is followed by zeros. + This minimizes data loss. */ + if ((conversions_mask & C_SYNC) && (conversions_mask & C_NOERROR)) + memset ((char *) ibuf, + (conversions_mask & (C_BLOCK | C_UNBLOCK)) ? ' ' : '\0', + input_blocksize); + + nread = safe_read (STDIN_FILENO, ibuf, input_blocksize); + + if (nread == 0) + break; /* EOF. */ + + if (nread < 0) + { + error (0, errno, _("reading %s"), quote (input_file)); + if (conversions_mask & C_NOERROR) + { + print_stats (); + /* Seek past the bad block if possible. */ + lseek (STDIN_FILENO, (off_t) input_blocksize, SEEK_CUR); + if (conversions_mask & C_SYNC) + /* Replace the missing input with null bytes and + proceed normally. */ + nread = 0; + else + continue; + } + else + { + /* Write any partial block. */ + exit_status = 2; + break; + } + } + + n_bytes_read = nread; + + if (n_bytes_read < input_blocksize) + { + r_partial++; + if (conversions_mask & C_SYNC) + { + if (!(conversions_mask & C_NOERROR)) + /* If C_NOERROR, we zeroed the block before reading. */ + memset ((char *) (ibuf + n_bytes_read), + (conversions_mask & (C_BLOCK | C_UNBLOCK)) ? ' ' : '\0', + input_blocksize - n_bytes_read); + n_bytes_read = input_blocksize; + } + } + else + r_full++; + + if (ibuf == obuf) /* If not C_TWOBUFS. */ + { + int nwritten = full_write (STDOUT_FILENO, obuf, n_bytes_read); + if (nwritten < 0) + { + error (0, errno, _("writing %s"), quote (output_file)); + quit (1); + } + else if (n_bytes_read == input_blocksize) + w_full++; + else + w_partial++; + continue; + } + + /* Do any translations on the whole buffer at once. */ + + if (translation_needed) + translate_buffer (ibuf, n_bytes_read); + + if (conversions_mask & C_SWAB) + bufstart = swab_buffer (ibuf, &n_bytes_read); + else + bufstart = ibuf; + + if (conversions_mask & C_BLOCK) + copy_with_block (bufstart, n_bytes_read); + else if (conversions_mask & C_UNBLOCK) + copy_with_unblock (bufstart, n_bytes_read); + else + copy_simple (bufstart, n_bytes_read); + } + + /* If we have a char left as a result of conv=swab, output it. */ + if (char_is_saved) + { + if (conversions_mask & C_BLOCK) + copy_with_block (&saved_char, 1); + else if (conversions_mask & C_UNBLOCK) + copy_with_unblock (&saved_char, 1); + else + output_char (saved_char); + } + + if ((conversions_mask & C_BLOCK) && col > 0) + { + /* If the final input line didn't end with a '\n', pad + the output block to `conversion_blocksize' chars. */ + unsigned int i; + for (i = col; i < conversion_blocksize; i++) + output_char (space_character); + } + + if ((conversions_mask & C_UNBLOCK) && col == conversion_blocksize) + /* Add a final '\n' if there are exactly `conversion_blocksize' + characters in the final record. */ + output_char (newline_character); + + /* Write out the last block. */ + if (oc != 0) + { + int nwritten = full_write (STDOUT_FILENO, obuf, oc); + if (nwritten > 0) + w_partial++; + if (nwritten < 0) + { + error (0, errno, _("writing %s"), quote (output_file)); + quit (1); + } + } + + free (real_buf); + if (real_obuf) + free (real_obuf); + + return exit_status; +} + +/* This is gross, but necessary, because of the way close_stdout + works and because this program closes STDOUT_FILENO directly. */ +static void (*closeout_func) (void) = close_stdout; + +static void +close_stdout_wrapper (void) +{ + if (closeout_func) + (*closeout_func) (); +} + +int +main (int argc, char **argv) +{ + int i; + int exit_status; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + /* Arrange to close stdout if parse_long_options exits. */ + atexit (close_stdout_wrapper); + + parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE, VERSION, + AUTHORS, usage); + + /* Don't close stdout on exit from here on. */ + closeout_func = NULL; + + /* Initialize translation table to identity translation. */ + for (i = 0; i < 256; i++) + trans_table[i] = i; + + /* Decode arguments. */ + scanargs (argc, argv); + + apply_translations (); + + if (input_file != NULL) + { + if (open_fd (STDIN_FILENO, input_file, O_RDONLY, 0) < 0) + error (1, errno, _("opening %s"), quote (input_file)); + } + else + input_file = _("standard input"); + + if (output_file != NULL) + { + mode_t perms = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; + int opts + = (O_CREAT + | (seek_records || (conversions_mask & C_NOTRUNC) ? 0 : O_TRUNC)); + + /* Open the output file with *read* access only if we might + need to read to satisfy a `seek=' request. If we can't read + the file, go ahead with write-only access; it might work. */ + if ((! seek_records + || open_fd (STDOUT_FILENO, output_file, O_RDWR | opts, perms) < 0) + && open_fd (STDOUT_FILENO, output_file, O_WRONLY | opts, perms) < 0) + error (1, errno, _("opening %s"), quote (output_file)); + +#if HAVE_FTRUNCATE + if (seek_records != 0 && !(conversions_mask & C_NOTRUNC)) + { + struct stat stdout_stat; + off_t o = seek_records * output_blocksize; + if (o / output_blocksize != seek_records) + error (1, 0, _("file offset out of range")); + + if (fstat (STDOUT_FILENO, &stdout_stat) != 0) + error (1, errno, _("cannot fstat %s"), quote (output_file)); + + /* Complain only when ftruncate fails on a regular file, a + directory, or a shared memory object, as the 2000-08 + POSIX draft specifies ftruncate's behavior only for these + file types. For example, do not complain when Linux 2.4 + ftruncate fails on /dev/fd0. */ + if (ftruncate (STDOUT_FILENO, o) != 0 + && (S_ISREG (stdout_stat.st_mode) + || S_ISDIR (stdout_stat.st_mode) + || S_TYPEISSHM (&stdout_stat))) + { + char buf[LONGEST_HUMAN_READABLE + 1]; + error (1, errno, _("advancing past %s bytes in output file %s"), + human_readable (o, buf, 1, 1), + quote (output_file)); + } + } +#endif + } + else + { + output_file = _("standard output"); + } + + install_handler (SIGINT, interrupt_handler); + install_handler (SIGQUIT, interrupt_handler); + install_handler (SIGPIPE, interrupt_handler); + install_handler (SIGINFO, siginfo_handler); + + exit_status = dd_copy (); + + quit (exit_status); +} diff --git a/src/apps/bin/gnu/df.c b/src/apps/bin/gnu/df.c new file mode 100644 index 0000000000..ad49e4244a --- /dev/null +++ b/src/apps/bin/gnu/df.c @@ -0,0 +1,952 @@ +/* df - summarize free disk space + Copyright (C) 91, 1995-2000 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by David MacKenzie . + --human-readable and --megabyte options added by lm@sgi.com. + --si and large file support added by eggert@twinsun.com. */ + +#ifdef _AIX + #pragma alloca +#endif + +#include +#if HAVE_INTTYPES_H +# include +#endif +#include +#include +#include +#include + +#include "system.h" +#include "dirname.h" +#include "error.h" +#include "fsusage.h" +#include "human.h" +#include "mountlist.h" +#include "path-concat.h" +#include "quote.h" +#include "save-cwd.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "df" + +#define AUTHORS \ + "Torbjorn Granlund, David MacKenzie, Larry McVoy, and Paul Eggert" + +void strip_trailing_slashes (); +char *xgetcwd (); + +/* Name this program was run with. */ +char *program_name; + +/* If nonzero, show inode information. */ +static int inode_format; + +/* If nonzero, show even filesystems with zero size or + uninteresting types. */ +static int show_all_fs; + +/* If nonzero, show only local filesystems. */ +static int show_local_fs; + +/* If nonzero, output data for each filesystem corresponding to a + command line argument -- even if it's a dummy (automounter) entry. */ +static int show_listed_fs; + +/* If positive, the units to use when printing sizes; + if negative, the human-readable base. */ +static int output_block_size; + +/* If nonzero, use the POSIX output format. */ +static int posix_format; + +/* If nonzero, invoke the `sync' system call before getting any usage data. + Using this option can make df very slow, especially with many or very + busy disks. Note that this may make a difference on some systems -- + SunOs4.1.3, for one. It is *not* necessary on Linux. */ +static int require_sync = 0; + +/* Nonzero if errors have occurred. */ +static int exit_status; + +/* A filesystem type to display. */ + +struct fs_type_list +{ + char *fs_name; + struct fs_type_list *fs_next; +}; + +/* Linked list of filesystem types to display. + If `fs_select_list' is NULL, list all types. + This table is generated dynamically from command-line options, + rather than hardcoding into the program what it thinks are the + valid filesystem types; let the user specify any filesystem type + they want to, and if there are any filesystems of that type, they + will be shown. + + Some filesystem types: + 4.2 4.3 ufs nfs swap ignore io vm efs dbg */ + +static struct fs_type_list *fs_select_list; + +/* Linked list of filesystem types to omit. + If the list is empty, don't exclude any types. */ + +static struct fs_type_list *fs_exclude_list; + +/* Linked list of mounted filesystems. */ +static struct mount_entry *mount_list; + +/* If nonzero, print filesystem type as well. */ +static int print_type; + +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + SYNC_OPTION = CHAR_MAX + 1, + NO_SYNC_OPTION, + BLOCK_SIZE_OPTION +}; + +static struct option const long_options[] = +{ + {"all", no_argument, NULL, 'a'}, + {"block-size", required_argument, NULL, BLOCK_SIZE_OPTION}, + {"inodes", no_argument, NULL, 'i'}, + {"human-readable", no_argument, NULL, 'h'}, + {"si", no_argument, NULL, 'H'}, + {"kilobytes", no_argument, NULL, 'k'}, + {"local", no_argument, NULL, 'l'}, + {"megabytes", no_argument, NULL, 'm'}, + {"portability", no_argument, NULL, 'P'}, + {"print-type", no_argument, NULL, 'T'}, + {"sync", no_argument, NULL, SYNC_OPTION}, + {"no-sync", no_argument, NULL, NO_SYNC_OPTION}, + {"type", required_argument, NULL, 't'}, + {"exclude-type", required_argument, NULL, 'x'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +static void +print_header (void) +{ + printf (_("Filesystem ")); + + if (print_type) + printf (_(" Type")); + else + printf (" "); + + if (inode_format) + printf (_(" Inodes IUsed IFree IUse%%")); + else if (output_block_size < 0) + printf (_(" Size Used Avail Use%%")); + else if (posix_format) + printf (_(" %4d-blocks Used Available Capacity"), output_block_size); + else + { + char buf[LONGEST_HUMAN_READABLE + 1]; + char *p = human_readable (output_block_size, buf, 1, -1024); + + /* Replace e.g. "1.0k" by "1k". */ + size_t plen = strlen (p); + if (3 <= plen && strncmp (p + plen - 3, ".0", 2) == 0) + strcpy (p + plen - 3, p + plen - 1); + + printf (_(" %4s-blocks Used Available Use%%"), p); + } + + printf (_(" Mounted on\n")); +} + +/* If FSTYPE is a type of filesystem that should be listed, + return nonzero, else zero. */ + +static int +selected_fstype (const char *fstype) +{ + const struct fs_type_list *fsp; + + if (fs_select_list == NULL || fstype == NULL) + return 1; + for (fsp = fs_select_list; fsp; fsp = fsp->fs_next) + if (STREQ (fstype, fsp->fs_name)) + return 1; + return 0; +} + +/* If FSTYPE is a type of filesystem that should be omitted, + return nonzero, else zero. */ + +static int +excluded_fstype (const char *fstype) +{ + const struct fs_type_list *fsp; + + if (fs_exclude_list == NULL || fstype == NULL) + return 0; + for (fsp = fs_exclude_list; fsp; fsp = fsp->fs_next) + if (STREQ (fstype, fsp->fs_name)) + return 1; + return 0; +} + +/* Like human_readable_inexact, except return "-" if the argument is -1, + and if NEGATIVE is 1 then N represents a negative number, expressed + in two's complement. */ +static char const * +df_readable (int negative, uintmax_t n, char *buf, + int from_block_size, int t_output_block_size, + enum human_inexact_style s) +{ + if (n == -1) + return "-"; + else + { + char *p = human_readable_inexact (negative ? - n : n, + buf + negative, from_block_size, + t_output_block_size, + negative ? - s : s); + if (negative) + *--p = '-'; + return p; + } +} + +/* Display a space listing for the disk device with absolute path DISK. + If MOUNT_POINT is non-NULL, it is the path of the root of the + filesystem on DISK. + If FSTYPE is non-NULL, it is the type of the filesystem on DISK. + If MOUNT_POINT is non-NULL, then DISK may be NULL -- certain systems may + not be able to produce statistics in this case. + ME_DUMMY and ME_REMOTE are the mount entry flags. */ + +static void +show_dev (const char *disk, const char *mount_point, const char *fstype, + int me_dummy, int me_remote) +{ + struct fs_usage fsu; + const char *stat_file; + char buf[3][LONGEST_HUMAN_READABLE + 2]; + int width; + int use_width; + int input_units; + int output_units; + uintmax_t total; + uintmax_t available; + int negate_available; + uintmax_t available_to_root; + uintmax_t used; + int negate_used; + double pct = -1; + + if (me_remote && show_local_fs) + return; + + if (me_dummy && show_all_fs == 0 && !show_listed_fs) + return; + + if (!selected_fstype (fstype) || excluded_fstype (fstype)) + return; + + /* If MOUNT_POINT is NULL, then the filesystem is not mounted, and this + program reports on the filesystem that the special file is on. + It would be better to report on the unmounted filesystem, + but statfs doesn't do that on most systems. */ + stat_file = mount_point ? mount_point : disk; + + if (get_fs_usage (stat_file, disk, &fsu)) + { + error (0, errno, "%s", quote (stat_file)); + exit_status = 1; + return; + } + + if (fsu.fsu_blocks == 0 && !show_all_fs && !show_listed_fs) + return; + + if (! disk) + disk = "-"; /* unknown */ + if (! fstype) + fstype = "-"; /* unknown */ + + /* df.c reserved 5 positions for fstype, + but that does not suffice for type iso9660 */ + if (print_type) + { + int disk_name_len = (int) strlen (disk); + int fstype_len = (int) strlen (fstype); + if (disk_name_len + fstype_len + 2 < 20) + printf ("%s%*s ", disk, 18 - disk_name_len, fstype); + else if (!posix_format) + printf ("%s\n%18s ", disk, fstype); + else + printf ("%s %s", disk, fstype); + } + else + { + if ((int) strlen (disk) > 20 && !posix_format) + printf ("%s\n%20s", disk, ""); + else + printf ("%-20s", disk); + } + + if (inode_format) + { + width = 7; + use_width = 5; + input_units = 1; + output_units = output_block_size < 0 ? output_block_size : 1; + total = fsu.fsu_files; + available = fsu.fsu_ffree; + negate_available = 0; + available_to_root = available; + } + else + { + width = output_block_size < 0 ? 5 : 9; + use_width = posix_format ? 8 : 4; + input_units = fsu.fsu_blocksize; + output_units = output_block_size; + total = fsu.fsu_blocks; + available = fsu.fsu_bavail; + negate_available = fsu.fsu_bavail_top_bit_set; + available_to_root = fsu.fsu_bfree; + } + + used = -1; + negate_used = 0; + if (total != -1 && available_to_root != -1) + { + used = total - available_to_root; + if (total < available_to_root) + { + negate_used = 1; + used = - used; + } + } + + printf (" %*s %*s %*s ", + width, df_readable (0, total, + buf[0], input_units, output_units, + (posix_format + ? human_ceiling + : human_round_to_even)), + width, df_readable (negate_used, used, + buf[1], input_units, output_units, + human_ceiling), + width, df_readable (negate_available, available, + buf[2], input_units, output_units, + posix_format ? human_ceiling : human_floor)); + + if (used == -1 || available == -1) + ; + else if (!negate_used + && used <= TYPE_MAXIMUM (uintmax_t) / 100 + && used + available != 0 + && (used + available < used) == negate_available) + { + uintmax_t u100 = used * 100; + uintmax_t nonroot_total = used + available; + pct = u100 / nonroot_total + (u100 % nonroot_total != 0); + } + else + { + /* The calculation cannot be done easily with integer + arithmetic. Fall back on floating point. This can suffer + from minor rounding errors, but doing it exactly requires + multiple precision arithmetic, and it's not worth the + aggravation. */ + double u = negate_used ? - (double) - used : used; + double a = negate_available ? - (double) - available : available; + double nonroot_total = u + a; + if (nonroot_total) + { + double ipct; + pct = u * 100 / nonroot_total; + ipct = (long) pct; + + /* Like `pct = ceil (dpct);', but avoid ceil so that + the math library needn't be linked. */ + if (ipct - 1 < pct && pct <= ipct + 1) + pct = ipct + (ipct < pct); + } + } + + if (0 <= pct) + printf ("%*.0f%%", use_width - 1, pct); + else + printf ("%*s", use_width, "- "); + + if (mount_point) + { +#ifdef HIDE_AUTOMOUNT_PREFIX + /* Don't print the first directory name in MOUNT_POINT if it's an + artifact of an automounter. This is a bit too aggressive to be + the default. */ + if (strncmp ("/auto/", mount_point, 6) == 0) + mount_point += 5; + else if (strncmp ("/tmp_mnt/", mount_point, 9) == 0) + mount_point += 8; +#endif + printf (" %s", mount_point); + } + putchar ('\n'); +} + +/* Identify the directory, if any, that device + DISK is mounted on, and show its disk usage. */ + +static void +show_disk (const char *disk) +{ + struct mount_entry *me; + + for (me = mount_list; me; me = me->me_next) + if (STREQ (disk, me->me_devname)) + { + show_dev (me->me_devname, me->me_mountdir, me->me_type, + me->me_dummy, me->me_remote); + return; + } + /* No filesystem is mounted on DISK. */ + show_dev (disk, (char *) NULL, (char *) NULL, 0, 0); +} + +/* Return the root mountpoint of the filesystem on which FILE exists, in + malloced storage. FILE_STAT should be the result of stating FILE. */ +static char * +find_mount_point (const char *file, const struct stat *file_stat) +{ + struct saved_cwd cwd; + struct stat last_stat; + char *mp = 0; /* The malloced mount point path. */ + + if (save_cwd (&cwd)) + return NULL; + + if (S_ISDIR (file_stat->st_mode)) + /* FILE is a directory, so just chdir there directly. */ + { + last_stat = *file_stat; + if (chdir (file) < 0) + return NULL; + } + else + /* FILE is some other kind of file, we need to use its directory. */ + { + int rv; + char *tmp = xstrdup (file); + char *dir; + + strip_trailing_slashes (tmp); + dir = dir_name (tmp); + free (tmp); + rv = chdir (dir); + free (dir); + + if (rv < 0) + return NULL; + + if (stat (".", &last_stat) < 0) + goto done; + } + + /* Now walk up FILE's parents until we find another filesystem or /, + chdiring as we go. LAST_STAT holds stat information for the last place + we visited. */ + for (;;) + { + struct stat st; + if (stat ("..", &st) < 0) + goto done; + if (st.st_dev != last_stat.st_dev || st.st_ino == last_stat.st_ino) + /* cwd is the mount point. */ + break; + if (chdir ("..") < 0) + goto done; + last_stat = st; + } + + /* Finally reached a mount point, see what it's called. */ + mp = xgetcwd (); + +done: + /* Restore the original cwd. */ + { + int save_errno = errno; + if (restore_cwd (&cwd, 0, mp)) + exit (1); /* We're scrod. */ + free_cwd (&cwd); + errno = save_errno; + } + + return mp; +} + +/* Figure out which device file or directory POINT is mounted on + and show its disk usage. + STATP is the results of `stat' on POINT. */ +static void +show_point (const char *point, const struct stat *statp) +{ + struct stat disk_stats; + struct mount_entry *me; + struct mount_entry *matching_dummy = NULL; + char *needs_freeing = NULL; + + /* If POINT is an absolute path name, see if we can find the + mount point without performing any extra stat calls at all. */ + if (*point == '/') + { + for (me = mount_list; me; me = me->me_next) + { + if (STREQ (me->me_mountdir, point) && !STREQ (me->me_type, "lofs")) + { + /* Prefer non-dummy entries. */ + if (! me->me_dummy) + goto show_me; + matching_dummy = me; + } + } + + if (matching_dummy) + goto show_matching_dummy; + } + +#if HAVE_REALPATH || HAVE_RESOLVEPATH + /* Calculate the real absolute path for POINT, and use that to find + the mount point. This avoids statting unavailable mount points, + which can hang df. */ + { + char const *abspoint = point; + char *resolved; + ssize_t resolved_len; + struct mount_entry *best_match = NULL; + +# if HAVE_RESOLVEPATH + /* All known hosts with resolvepath (e.g. Solaris 7) don't turn + relative names into absolute ones, so prepend the working + directory if the path is not absolute. */ + + if (*point != '/') + { + static char const *wd; + + if (! wd) + { + struct stat pwd_stats; + struct stat dot_stats; + + /* Use PWD if it is correct; this is usually cheaper than + xgetcwd. */ + wd = getenv ("PWD"); + if (! (wd + && stat (wd, &pwd_stats) == 0 + && stat (".", &dot_stats) == 0 + && SAME_INODE (pwd_stats, dot_stats))) + wd = xgetcwd (); + } + + if (wd) + { + needs_freeing = path_concat (wd, point, NULL); + if (needs_freeing) + abspoint = needs_freeing; + } + } +# endif + +# if HAVE_RESOLVEPATH + { + size_t resolved_size = strlen (abspoint); + do + { + resolved_size = 2 * resolved_size + 1; + resolved = alloca (resolved_size); + resolved_len = resolvepath (abspoint, resolved, resolved_size); + } + while (resolved_len == resolved_size); + } +# else + resolved = alloca (PATH_MAX + 1); + resolved = (char *) realpath (abspoint, resolved); + resolved_len = resolved ? strlen (resolved) : -1; +# endif + + if (1 <= resolved_len && resolved[0] == '/') + { + size_t best_match_len = 0; + + for (me = mount_list; me; me = me->me_next) + if (! me->me_dummy) + { + size_t len = strlen (me->me_mountdir); + if (best_match_len < len && len <= resolved_len + && (len == 1 /* root file system */ + || ((len == resolved_len || resolved[len] == '/') + && strncmp (me->me_mountdir, resolved, len) == 0))) + { + best_match = me; + best_match_len = len; + } + } + } + + if (best_match && !STREQ (best_match->me_type, "lofs") + && stat (best_match->me_mountdir, &disk_stats) == 0 + && disk_stats.st_dev == statp->st_dev) + { + me = best_match; + goto show_me; + } + } +#endif + + for (me = mount_list; me; me = me->me_next) + { + if (me->me_dev == (dev_t) -1) + { + if (stat (me->me_mountdir, &disk_stats) == 0) + me->me_dev = disk_stats.st_dev; + else + { + error (0, errno, "%s", quote (me->me_mountdir)); + exit_status = 1; + /* So we won't try and fail repeatedly. */ + me->me_dev = (dev_t) -2; + } + } + + if (statp->st_dev == me->me_dev) + { + /* Skip bogus mtab entries. */ + if (stat (me->me_mountdir, &disk_stats) != 0 + || disk_stats.st_dev != me->me_dev) + { + me->me_dev = (dev_t) -2; + continue; + } + + /* Prefer non-dummy entries. */ + if (! me->me_dummy) + goto show_me; + matching_dummy = me; + } + } + + if (matching_dummy) + goto show_matching_dummy; + + /* We couldn't find the mount entry corresponding to POINT. Go ahead and + print as much info as we can; methods that require the device to be + present will fail at a later point. */ + { + /* Find the actual mount point. */ + char *mp = find_mount_point (point, statp); + if (mp) + { + show_dev (0, mp, 0, 0, 0); + free (mp); + } + else + error (0, errno, "%s", quote (point)); + } + + goto free_then_return; + + show_matching_dummy: + me = matching_dummy; + show_me: + show_dev (me->me_devname, me->me_mountdir, me->me_type, me->me_dummy, + me->me_remote); + free_then_return: + if (needs_freeing) + free (needs_freeing); +} + +/* Determine what kind of node PATH is and show the disk usage + for it. STATP is the results of `stat' on PATH. */ + +static void +show_entry (const char *path, const struct stat *statp) +{ + if (S_ISBLK (statp->st_mode) || S_ISCHR (statp->st_mode)) + show_disk (path); + else + show_point (path, statp); +} + +/* Show all mounted filesystems, except perhaps those that are of + an unselected type or are empty. */ + +static void +show_all_entries (void) +{ + struct mount_entry *me; + + for (me = mount_list; me; me = me->me_next) + show_dev (me->me_devname, me->me_mountdir, me->me_type, + me->me_dummy, me->me_remote); +} + +/* Add FSTYPE to the list of filesystem types to display. */ + +static void +add_fs_type (const char *fstype) +{ + struct fs_type_list *fsp; + + fsp = (struct fs_type_list *) xmalloc (sizeof (struct fs_type_list)); + fsp->fs_name = (char *) fstype; + fsp->fs_next = fs_select_list; + fs_select_list = fsp; +} + +/* Add FSTYPE to the list of filesystem types to be omitted. */ + +static void +add_excluded_fs_type (const char *fstype) +{ + struct fs_type_list *fsp; + + fsp = (struct fs_type_list *) xmalloc (sizeof (struct fs_type_list)); + fsp->fs_name = (char *) fstype; + fsp->fs_next = fs_exclude_list; + fs_exclude_list = fsp; +} + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name); + printf (_("\ +Show information about the filesystem on which each FILE resides,\n\ +or all filesystems by default.\n\ +\n\ + -a, --all include filesystems having 0 blocks\n\ + --block-size=SIZE use SIZE-byte blocks\n\ + -h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)\n\ + -H, --si likewise, but use powers of 1000 not 1024\n\ + -i, --inodes list inode information instead of block usage\n\ + -k, --kilobytes like --block-size=1024\n\ + -l, --local limit listing to local filesystems\n\ + -m, --megabytes like --block-size=1048576\n\ + --no-sync do not invoke sync before getting usage info (default)\n\ + -P, --portability use the POSIX output format\n\ + --sync invoke sync before getting usage info\n\ + -t, --type=TYPE limit listing to filesystems of type TYPE\n\ + -T, --print-type print filesystem type\n\ + -x, --exclude-type=TYPE limit listing to filesystems not of type TYPE\n\ + -v (ignored)\n\ + --help display this help and exit\n\ + --version output version information and exit\n\ +")); + puts (_("\nReport bugs to .")); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + int c; + struct stat *stats IF_LINT (= 0); + int n_valid_args = 0; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + fs_select_list = NULL; + fs_exclude_list = NULL; + inode_format = 0; + show_all_fs = 0; + show_listed_fs = 0; + + human_block_size (getenv ("DF_BLOCK_SIZE"), 0, &output_block_size); + + print_type = 0; + posix_format = 0; + exit_status = 0; + + while ((c = getopt_long (argc, argv, "aiF:hHklmPTt:vx:", long_options, NULL)) + != -1) + { + switch (c) + { + case 0: /* Long option. */ + break; + case 'a': + show_all_fs = 1; + break; + case 'i': + inode_format = 1; + break; + case 'h': + output_block_size = -1024; + break; + case 'H': + output_block_size = -1000; + break; + case 'k': + output_block_size = 1024; + break; + case 'l': + show_local_fs = 1; + break; + case 'm': + output_block_size = 1024 * 1024; + break; + case 'T': + print_type = 1; + break; + case 'P': + posix_format = 1; + break; + case SYNC_OPTION: + require_sync = 1; + break; + case NO_SYNC_OPTION: + require_sync = 0; + break; + + case BLOCK_SIZE_OPTION: + human_block_size (optarg, 1, &output_block_size); + break; + + case 'F': + /* Accept -F as a synonym for -t for compatibility with Solaris. */ + case 't': + add_fs_type (optarg); + break; + + case 'v': /* For SysV compatibility. */ + /* ignore */ + break; + case 'x': + add_excluded_fs_type (optarg); + break; + + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (1); + } + } + + /* Fail if the same file system type was both selected and excluded. */ + { + int match = 0; + struct fs_type_list *fs_incl; + for (fs_incl = fs_select_list; fs_incl; fs_incl = fs_incl->fs_next) + { + struct fs_type_list *fs_excl; + for (fs_excl = fs_exclude_list; fs_excl; fs_excl = fs_excl->fs_next) + { + if (STREQ (fs_incl->fs_name, fs_excl->fs_name)) + { + error (0, 0, + _("file system type %s both selected and excluded"), + quote (fs_incl->fs_name)); + match = 1; + break; + } + } + } + if (match) + exit (1); + } + + { + int i; + + /* stat all the given entries to make sure they get automounted, + if necessary, before reading the filesystem table. */ + stats = (struct stat *) + xmalloc ((argc - optind) * sizeof (struct stat)); + for (i = optind; i < argc; ++i) + { + if (stat (argv[i], &stats[i - optind])) + { + error (0, errno, "%s", quote (argv[i])); + exit_status = 1; + argv[i] = NULL; + } + else + { + ++n_valid_args; + } + } + } + + mount_list = + read_filesystem_list ((fs_select_list != NULL + || fs_exclude_list != NULL + || print_type + || show_local_fs)); + + if (mount_list == NULL) + { + /* Couldn't read the table of mounted filesystems. + Fail if df was invoked with no file name arguments; + Otherwise, merely give a warning and proceed. */ + const char *warning = (optind == argc ? "" : _("Warning: ")); + int status = (optind == argc ? 1 : 0); + error (status, errno, + _("%scannot read table of mounted filesystems"), warning); + } + + if (require_sync) + sync (); + + if (optind == argc) + { + print_header (); + show_all_entries (); + } + else + { + int i; + + /* Display explicitly requested empty filesystems. */ + show_listed_fs = 1; + + if (n_valid_args > 0) + print_header (); + + for (i = optind; i < argc; ++i) + if (argv[i]) + show_entry (argv[i], &stats[i - optind]); + } + + exit (exit_status); +} diff --git a/src/apps/bin/gnu/du.c b/src/apps/bin/gnu/du.c new file mode 100644 index 0000000000..ab47a620f9 --- /dev/null +++ b/src/apps/bin/gnu/du.c @@ -0,0 +1,794 @@ +/* du -- summarize disk usage + Copyright (C) 88, 89, 90, 91, 1995-2000 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Differences from the Unix du: + * Doesn't simply ignore the names of regular files given as arguments + when -a is given. + * Additional options: + -l Count the size of all files, even if they have appeared + already in another hard link. + -x Do not cross file-system boundaries during the recursion. + -c Write a grand total of all of the arguments after all + arguments have been processed. This can be used to find + out the disk usage of a directory, with some files excluded. + -h Print sizes in human readable format (1k 234M 2G, etc). + -H Similar, but use powers of 1000 not 1024. + -k Print sizes in kilobytes. + -m Print sizes in megabytes. + -b Print sizes in bytes. + -S Count the size of each directory separately, not including + the sizes of subdirectories. + -D Dereference only symbolic links given on the command line. + -L Dereference all symbolic links. + --exclude=PAT Exclude files that match PAT. + -X FILE Exclude files that match patterns taken from FILE. + + By tege@sics.se, Torbjorn Granlund, + and djm@ai.mit.edu, David MacKenzie. + Variable blocks added by lm@sgi.com and eggert@twinsun.com. +*/ + +#include +#if HAVE_INTTYPES_H +# include +#endif +#include +#include +#include +#include + +#include "system.h" +#include "error.h" +#include "exclude.h" +#include "human.h" +#include "quote.h" +#include "save-cwd.h" +#include "savedir.h" +#include "xstrtol.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "du" + +#define AUTHORS \ + "Torbjorn Granlund, David MacKenzie, Larry McVoy, and Paul Eggert" + +/* Initial number of entries in each hash table entry's table of inodes. */ +#define INITIAL_HASH_MODULE 100 + +/* Initial number of entries in the inode hash table. */ +#define INITIAL_ENTRY_TAB_SIZE 70 + +/* Initial size to allocate for `path'. */ +#define INITIAL_PATH_SIZE 100 + +/* Hash structure for inode and device numbers. The separate entry + structure makes it easier to rehash "in place". */ + +struct entry +{ + ino_t ino; + dev_t dev; + struct entry *coll_link; +}; + +/* Structure for a hash table for inode numbers. */ + +struct htab +{ + unsigned modulus; /* Size of the `hash' pointer vector. */ + struct entry *entry_tab; /* Pointer to dynamically growing vector. */ + unsigned entry_tab_size; /* Size of current `entry_tab' allocation. */ + unsigned first_free_entry; /* Index in `entry_tab'. */ + struct entry *hash[1]; /* Vector of pointers in `entry_tab'. */ +}; + + +/* Structure for dynamically resizable strings. */ + +struct String +{ + unsigned alloc; /* Size of allocation for the text. */ + unsigned length; /* Length of the text currently. */ + char *text; /* Pointer to the text. */ +}; +typedef struct String String; + +int stat (); +int lstat (); + +/* Name under which this program was invoked. */ +char *program_name; + +/* If nonzero, display counts for all files, not just directories. */ +static int opt_all = 0; + +/* If nonzero, count each hard link of files with multiple links. */ +static int opt_count_all = 0; + +/* If nonzero, do not cross file-system boundaries. */ +static int opt_one_file_system = 0; + +/* If nonzero, print a grand total at the end. */ +static int print_totals = 0; + +/* If nonzero, do not add sizes of subdirectories. */ +static int opt_separate_dirs = 0; + +/* If nonzero, dereference symlinks that are command line arguments. */ +static int opt_dereference_arguments = 0; + +/* Show the total for each directory (and file if --all) that is at + most MAX_DEPTH levels down from the root of the hierarchy. The root + is at level 0, so `du --max-depth=0' is equivalent to `du -s'. */ +static int max_depth = INT_MAX; + +/* If positive, the units to use when printing sizes; + if negative, the human-readable base. */ +static int output_block_size; + +/* Accumulated path for file or directory being processed. */ +static String *path; + +/* Pointer to hash structure, used by the hash routines. */ +static struct htab *htab; + +/* A pointer to either lstat or stat, depending on whether + dereferencing of all symbolic links is to be done. */ +static int (*xstat) (); + +/* The exit status to use if we don't get any fatal errors. */ +static int exit_status; + +/* File name patterns to exclude. */ +static struct exclude *exclude; + +/* Grand total size of all args, in units of ST_NBLOCKSIZE-byte blocks. */ +static uintmax_t tot_size = 0; + +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + EXCLUDE_OPTION = CHAR_MAX + 1, + BLOCK_SIZE_OPTION, + MAX_DEPTH_OPTION +}; + +static struct option const long_options[] = +{ + {"all", no_argument, NULL, 'a'}, + {"block-size", required_argument, 0, BLOCK_SIZE_OPTION}, + {"bytes", no_argument, NULL, 'b'}, + {"count-links", no_argument, NULL, 'l'}, + {"dereference", no_argument, NULL, 'L'}, + {"dereference-args", no_argument, NULL, 'D'}, + {"exclude", required_argument, 0, EXCLUDE_OPTION}, + {"exclude-from", required_argument, 0, 'X'}, + {"human-readable", no_argument, NULL, 'h'}, + {"si", no_argument, 0, 'H'}, + {"kilobytes", no_argument, NULL, 'k'}, + {"max-depth", required_argument, NULL, MAX_DEPTH_OPTION}, + {"megabytes", no_argument, NULL, 'm'}, + {"one-file-system", no_argument, NULL, 'x'}, + {"separate-dirs", no_argument, NULL, 'S'}, + {"summarize", no_argument, NULL, 's'}, + {"total", no_argument, NULL, 'c'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name); + printf (_("\ +Summarize disk usage of each FILE, recursively for directories.\n\ +\n\ + -a, --all write counts for all files, not just directories\n\ + --block-size=SIZE use SIZE-byte blocks\n\ + -b, --bytes print size in bytes\n\ + -c, --total produce a grand total\n\ + -D, --dereference-args dereference PATHs when symbolic link\n\ + -h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)\n\ + -H, --si likewise, but use powers of 1000 not 1024\n\ + -k, --kilobytes like --block-size=1024\n\ + -l, --count-links count sizes many times if hard linked\n\ + -L, --dereference dereference all symbolic links\n\ + -m, --megabytes like --block-size=1048576\n\ + -S, --separate-dirs do not include size of subdirectories\n\ + -s, --summarize display only a total for each argument\n\ + -x, --one-file-system skip directories on different filesystems\n\ + -X FILE, --exclude-from=FILE Exclude files that match any pattern in FILE.\n\ + --exclude=PAT Exclude files that match PAT.\n\ + --max-depth=N print the total for a directory (or file, with --all)\n\ + only if it is N or fewer levels below the command\n\ + line argument; --max-depth=0 is the same as\n\ + --summarize\n\ + --help display this help and exit\n\ + --version output version information and exit\n\ +")); + puts (_("\nReport bugs to .")); + } + exit (status); +} + +/* Initialize string S1 to hold SIZE characters. */ + +static void +str_init (String **s1, unsigned int size) +{ + String *s; + + s = (String *) xmalloc (sizeof (struct String)); + s->text = xmalloc (size + 1); + + s->alloc = size; + *s1 = s; +} + +static void +ensure_space (String *s, unsigned int size) +{ + if (s->alloc < size) + { + s->text = xrealloc (s->text, size + 1); + s->alloc = size; + } +} + +/* Assign the null-terminated C-string CSTR to S1. */ + +static void +str_copyc (String *s1, const char *cstr) +{ + unsigned l = strlen (cstr); + ensure_space (s1, l); + strcpy (s1->text, cstr); + s1->length = l; +} + +static void +str_concatc (String *s1, const char *cstr) +{ + unsigned l1 = s1->length; + unsigned l2 = strlen (cstr); + unsigned l = l1 + l2; + + ensure_space (s1, l); + strcpy (s1->text + l1, cstr); + s1->length = l; +} + +/* Truncate the string S1 to have length LENGTH. */ + +static void +str_trunc (String *s1, unsigned int length) +{ + if (s1->length > length) + { + s1->text[length] = 0; + s1->length = length; + } +} + +/* Print N_BLOCKS followed by STRING on a line. NBLOCKS is the number of + ST_NBLOCKSIZE-byte blocks; convert it to OUTPUT_BLOCK_SIZE units before + printing. If OUTPUT_BLOCK_SIZE is negative, use a human readable + notation instead. */ + +static void +print_size (uintmax_t n_blocks, const char *string) +{ + char buf[LONGEST_HUMAN_READABLE + 1]; + printf ("%s\t%s\n", + human_readable_inexact (n_blocks, buf, ST_NBLOCKSIZE, + output_block_size, human_ceiling), + string); + fflush (stdout); +} + +/* Reset the hash structure in the global variable `htab' to + contain no entries. */ + +static void +hash_reset (void) +{ + int i; + struct entry **p; + + htab->first_free_entry = 0; + + p = htab->hash; + for (i = htab->modulus; i > 0; i--) + *p++ = NULL; +} + +/* Allocate space for the hash structures, and set the global + variable `htab' to point to it. The initial hash module is specified in + MODULUS, and the number of entries are specified in ENTRY_TAB_SIZE. (The + hash structure will be rebuilt when ENTRY_TAB_SIZE entries have been + inserted, and MODULUS and ENTRY_TAB_SIZE in the global `htab' will be + doubled.) */ + +static void +hash_init (unsigned int modulus, unsigned int entry_tab_size) +{ + struct htab *htab_r; + + htab_r = (struct htab *) + xmalloc (sizeof (struct htab) + sizeof (struct entry *) * modulus); + + htab_r->entry_tab = (struct entry *) + xmalloc (sizeof (struct entry) * entry_tab_size); + + htab_r->modulus = modulus; + htab_r->entry_tab_size = entry_tab_size; + htab = htab_r; + + hash_reset (); +} + +/* Insert INO and DEV in the hash structure HTAB, if not + already present. Return zero if inserted and nonzero if it + already existed. */ + +static int +hash_insert2 (struct htab *ht, ino_t ino, dev_t dev) +{ + struct entry **hp, *ep2, *ep; + hp = &ht->hash[ino % ht->modulus]; + ep2 = *hp; + + /* Collision? */ + + if (ep2 != NULL) + { + ep = ep2; + + /* Search for an entry with the same data. */ + + do + { + if (ep->ino == ino && ep->dev == dev) + return 1; /* Found an entry with the same data. */ + ep = ep->coll_link; + } + while (ep != NULL); + + /* Did not find it. */ + + } + + ep = *hp = &ht->entry_tab[ht->first_free_entry++]; + ep->ino = ino; + ep->dev = dev; + ep->coll_link = ep2; /* `ep2' is NULL if no collision. */ + + return 0; +} + +/* Insert an item (inode INO and device DEV) in the hash + structure in the global variable `htab', if an entry with the same data + was not found already. Return zero if the item was inserted and nonzero + if it wasn't. */ + +static int +hash_insert (ino_t ino, dev_t dev) +{ + struct htab *htab_r = htab; /* Initially a copy of the global `htab'. */ + + if (htab_r->first_free_entry >= htab_r->entry_tab_size) + { + int i; + struct entry *ep; + unsigned modulus; + unsigned entry_tab_size; + + /* Increase the number of hash entries, and re-hash the data. + The method of shrimping and increasing is made to compactify + the heap. If twice as much data would be allocated + straightforwardly, we would never re-use a byte of memory. */ + + /* Let `htab' shrimp. Keep only the header, not the pointer vector. */ + + htab_r = (struct htab *) + xrealloc ((char *) htab_r, sizeof (struct htab)); + + modulus = 2 * htab_r->modulus; + entry_tab_size = 2 * htab_r->entry_tab_size; + + /* Increase the number of possible entries. */ + + htab_r->entry_tab = (struct entry *) + xrealloc ((char *) htab_r->entry_tab, + sizeof (struct entry) * entry_tab_size); + + /* Increase the size of htab again. */ + + htab_r = (struct htab *) + xrealloc ((char *) htab_r, + sizeof (struct htab) + sizeof (struct entry *) * modulus); + + htab_r->modulus = modulus; + htab_r->entry_tab_size = entry_tab_size; + htab = htab_r; + + i = htab_r->first_free_entry; + + /* Make the increased hash table empty. The entries are still + available in htab->entry_tab. */ + + hash_reset (); + + /* Go through the entries and install them in the pointer vector + htab->hash. The items are actually inserted in htab->entry_tab at + the position where they already are. The htab->coll_link need + however be updated. Could be made a little more efficient. */ + + for (ep = htab_r->entry_tab; i > 0; i--) + { + hash_insert2 (htab_r, ep->ino, ep->dev); + ep++; + } + } + + return hash_insert2 (htab_r, ino, dev); +} + +/* Restore the previous working directory or exit. + If CWD is null, simply call `chdir ("..")'. Otherwise, + use CWD and free it. CURR_DIR_NAME is the name of the current directory + and is used solely in failure diagnostics. */ + +static void +pop_dir (struct saved_cwd *cwd, const char *curr_dir_name) +{ + if (cwd) + { + if (restore_cwd (cwd, "..", curr_dir_name)) + exit (1); + free_cwd (cwd); + } + else if (chdir ("..") < 0) + { + error (1, errno, _("cannot change to `..' from directory %s"), + quote (curr_dir_name)); + } +} + +/* Print (if appropriate) the size (in units determined by `output_block_size') + of file or directory ENT. Return the size of ENT in units of 512-byte + blocks. TOP is one for external calls, zero for recursive calls. + LAST_DEV is the device that the parent directory of ENT is on. + DEPTH is the number of levels (in hierarchy) down from a command + line argument. Don't print if DEPTH > max_depth. + An important invariant is that when this function returns, the current + working directory is the same as when it was called. */ + +static uintmax_t +count_entry (const char *ent, int top, dev_t last_dev, int depth) +{ + uintmax_t size; + struct stat stat_buf; + + if (((top && opt_dereference_arguments) + ? stat (ent, &stat_buf) + : (*xstat) (ent, &stat_buf)) < 0) + { + error (0, errno, "%s", quote (path->text)); + exit_status = 1; + return 0; + } + + if (!opt_count_all + && stat_buf.st_nlink > 1 + && hash_insert (stat_buf.st_ino, stat_buf.st_dev)) + return 0; /* Have counted this already. */ + + size = ST_NBLOCKS (stat_buf); + tot_size += size; + + if (S_ISDIR (stat_buf.st_mode)) + { + unsigned pathlen; + dev_t dir_dev; + char *name_space; + char *namep; + struct saved_cwd *cwd; + struct saved_cwd cwd_buf; + struct stat e_buf; + + dir_dev = stat_buf.st_dev; + + /* Return `0' here, not SIZE, since the SIZE bytes + would reside in the new filesystem. */ + if (opt_one_file_system && !top && last_dev != dir_dev) + return 0; /* Don't enter a new file system. */ + +#ifndef S_ISLNK +# define S_ISLNK(s) 0 +#endif + /* If we're traversing more than one level, or if we're + dereferencing symlinks and we're about to chdir through a + symlink, remember the current directory so we can return to + it later. In other cases, chdir ("..") works fine. + Treat `.' and `..' like multi-level paths, since `chdir ("..")' + wont't restore the current working directory after a `chdir' + to one of those. */ + if (strchr (ent, '/') + || DOT_OR_DOTDOT (ent) + || (xstat == stat + && lstat (ent, &e_buf) == 0 + && S_ISLNK (e_buf.st_mode))) + { + if (save_cwd (&cwd_buf)) + exit (1); + cwd = &cwd_buf; + } + else + cwd = NULL; + + if (chdir (ent) < 0) + { + error (0, errno, _("cannot change to directory %s"), + quote (path->text)); + if (cwd) + free_cwd (cwd); + exit_status = 1; + /* Do return SIZE, here, since even though we can't chdir into ENT, + we *can* count the blocks used by its directory entry. */ + return opt_separate_dirs ? 0 : size; + } + + name_space = savedir (".", stat_buf.st_size); + if (name_space == NULL) + { + error (0, errno, "%s", quote (path->text)); + pop_dir (cwd, path->text); + exit_status = 1; + /* Do count the SIZE bytes. */ + return opt_separate_dirs ? 0 : size; + } + + /* Remember the current path. */ + + str_concatc (path, "/"); + pathlen = path->length; + + for (namep = name_space; *namep; namep += strlen (namep) + 1) + { + if (!excluded_filename (exclude, namep, 0)) + { + str_concatc (path, namep); + size += count_entry (namep, 0, dir_dev, depth + 1); + str_trunc (path, pathlen); + } + } + + free (name_space); + pop_dir (cwd, path->text); + + str_trunc (path, pathlen - 1); /* Remove the "/" we added. */ + if (depth <= max_depth || top) + print_size (size, path->length > 0 ? path->text : "/"); + return opt_separate_dirs ? 0 : size; + } + else if ((opt_all && depth <= max_depth) || top) + { + /* FIXME: make this an option. */ + int print_only_dir_size = 0; + if (!print_only_dir_size) + print_size (size, path->length > 0 ? path->text : "/"); + } + + return size; +} + +/* Recursively print the sizes of the directories (and, if selected, files) + named in FILES, the last entry of which is NULL. */ + +static void +du_files (char **files) +{ + int i; /* Index in FILES. */ + + for (i = 0; files[i]; i++) + { + char *arg; + int s; + + arg = files[i]; + + /* Delete final slash in the argument, unless the slash is alone. */ + s = strlen (arg) - 1; + if (s != 0) + { + if (arg[s] == '/') + arg[s] = 0; + + str_copyc (path, arg); + } + else if (arg[0] == '/') + str_trunc (path, 0); /* Null path for root directory. */ + else + str_copyc (path, arg); + + if (!print_totals) + hash_reset (); + + count_entry (arg, 1, 0, 0); + } + + if (print_totals) + print_size (tot_size, _("total")); +} + +int +main (int argc, char **argv) +{ + int c; + char *cwd_only[2]; + int max_depth_specified = 0; + + /* If nonzero, display only a total for each argument. */ + int opt_summarize_only = 0; + + cwd_only[0] = "."; + cwd_only[1] = NULL; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + exclude = new_exclude (); + xstat = lstat; + + human_block_size (getenv ("DU_BLOCK_SIZE"), 0, &output_block_size); + + while ((c = getopt_long (argc, argv, "abchHklmsxDLSX:", long_options, NULL)) + != -1) + { + long int tmp_long; + switch (c) + { + case 0: /* Long option. */ + break; + + case 'a': + opt_all = 1; + break; + + case 'b': + output_block_size = 1; + break; + + case 'c': + print_totals = 1; + break; + + case 'h': + output_block_size = -1024; + break; + + case 'H': + output_block_size = -1000; + break; + + case 'k': + output_block_size = 1024; + break; + + case MAX_DEPTH_OPTION: /* --max-depth=N */ + if (xstrtol (optarg, NULL, 0, &tmp_long, NULL) != LONGINT_OK + || tmp_long < 0 || tmp_long > INT_MAX) + error (1, 0, _("invalid maximum depth %s"), quote (optarg)); + + max_depth_specified = 1; + max_depth = (int) tmp_long; + break; + + case 'm': + output_block_size = 1024 * 1024; + break; + + case 'l': + opt_count_all = 1; + break; + + case 's': + opt_summarize_only = 1; + break; + + case 'x': + opt_one_file_system = 1; + break; + + case 'D': + opt_dereference_arguments = 1; + break; + + case 'L': + xstat = stat; + break; + + case 'S': + opt_separate_dirs = 1; + break; + + case 'X': + if (add_exclude_file (add_exclude, exclude, optarg, '\n') != 0) + error (1, errno, "%s", quote (optarg)); + break; + + case EXCLUDE_OPTION: + add_exclude (exclude, optarg); + break; + + case BLOCK_SIZE_OPTION: + human_block_size (optarg, 1, &output_block_size); + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (1); + } + } + + if (opt_all && opt_summarize_only) + { + error (0, 0, _("cannot both summarize and show all entries")); + usage (1); + } + + if (opt_summarize_only && max_depth_specified && max_depth == 0) + { + error (0, 0, + _("warning: summarizing is the same as using --max-depth=0")); + } + + if (opt_summarize_only && max_depth_specified && max_depth != 0) + { + error (0, 0, + _("warning: summarizing conflicts with --max-depth=%d"), + max_depth); + usage (1); + } + + if (opt_summarize_only) + max_depth = 0; + + /* Initialize the hash structure for inode numbers. */ + hash_init (INITIAL_HASH_MODULE, INITIAL_ENTRY_TAB_SIZE); + + str_init (&path, INITIAL_PATH_SIZE); + + du_files (optind == argc ? cwd_only : argv + optind); + + exit (exit_status); +} diff --git a/src/apps/bin/gnu/install.c b/src/apps/bin/gnu/install.c new file mode 100644 index 0000000000..5b919c44df --- /dev/null +++ b/src/apps/bin/gnu/install.c @@ -0,0 +1,643 @@ +/* install - copy files and set attributes + Copyright (C) 89, 90, 91, 1995-2000 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by David MacKenzie */ + +#ifdef _AIX + #pragma alloca +#endif + +#include +#include +#include +#include +#include +#include + +#include "system.h" +#include "backupfile.h" +#include "error.h" +#include "cp-hash.h" +#include "copy.h" +#include "dirname.h" +#include "makepath.h" +#include "modechange.h" +#include "path-concat.h" +#include "quote.h" +#include "xstrtol.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "install" + +#define AUTHORS "David MacKenzie" + +#if HAVE_SYS_WAIT_H +# include +#endif + +#if HAVE_VALUES_H +# include +#endif + +struct passwd *getpwnam (); +struct group *getgrnam (); + +#ifndef _POSIX_VERSION +uid_t getuid (); +gid_t getgid (); +#endif + +#if ! HAVE_ENDGRENT +# define endgrent() ((void) 0) +#endif + +#if ! HAVE_ENDPWENT +# define endpwent() ((void) 0) +#endif + +/* Initial number of entries in each hash table entry's table of inodes. */ +#define INITIAL_HASH_MODULE 100 + +/* Initial number of entries in the inode hash table. */ +#define INITIAL_ENTRY_TAB_SIZE 70 + +/* Number of bytes of a file to copy at a time. */ +#define READ_SIZE (32 * 1024) + +int full_write (); +int isdir (); + +int stat (); + +static int change_timestamps PARAMS ((const char *from, const char *to)); +static int change_attributes PARAMS ((const char *path)); +static int copy_file PARAMS ((const char *from, const char *to, + const struct cp_options *x)); +static int install_file_to_path PARAMS ((const char *from, const char *to, + const struct cp_options *x)); +static int install_file_in_dir PARAMS ((const char *from, const char *to_dir, + const struct cp_options *x)); +static int install_file_in_file PARAMS ((const char *from, const char *to, + const struct cp_options *x)); +static void get_ids PARAMS ((void)); +static void strip PARAMS ((const char *path)); +void usage PARAMS ((int status)); + +/* The name this program was run with, for error messages. */ +char *program_name; + +/* The user name that will own the files, or NULL to make the owner + the current user ID. */ +static char *owner_name; + +/* The user ID corresponding to `owner_name'. */ +static uid_t owner_id; + +/* The group name that will own the files, or NULL to make the group + the current group ID. */ +static char *group_name; + +/* The group ID corresponding to `group_name'. */ +static gid_t group_id; + +/* The permissions to which the files will be set. The umask has + no effect. */ +static mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; + +/* If nonzero, strip executable files after copying them. */ +static int strip_files; + +/* If nonzero, install a directory instead of a regular file. */ +static int dir_arg; + +static struct option const long_options[] = +{ + {"backup", optional_argument, NULL, 'b'}, + {"directory", no_argument, NULL, 'd'}, + {"group", required_argument, NULL, 'g'}, + {"mode", required_argument, NULL, 'm'}, + {"owner", required_argument, NULL, 'o'}, + {"preserve-timestamps", no_argument, NULL, 'p'}, + {"strip", no_argument, NULL, 's'}, + {"suffix", required_argument, NULL, 'S'}, + {"version-control", required_argument, NULL, 'V'}, /* Deprecated. FIXME. */ + {"verbose", no_argument, NULL, 'v'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +static void +cp_option_init (struct cp_options *x) +{ + x->copy_as_regular = 1; + x->dereference = DEREF_ALWAYS; + x->unlink_dest_before_opening = 1; + x->unlink_dest_after_failed_open = 0; + + /* If unlink fails, try to proceed anyway. */ + x->failed_unlink_is_fatal = 0; + + x->hard_link = 0; + x->interactive = 0; + x->move_mode = 0; + x->myeuid = geteuid (); + x->one_file_system = 0; + x->preserve_owner_and_group = 0; + x->preserve_chmod_bits = 0; + x->preserve_timestamps = 0; + x->require_preserve = 0; + x->recursive = 0; + x->sparse_mode = SPARSE_AUTO; + x->symbolic_link = 0; + x->backup_type = none; + + /* Create destination files initially writable so we can run strip on them. + Although GNU strip works fine on read-only files, some others + would fail. */ + x->set_mode = 1; + x->mode = S_IRUSR | S_IWUSR; + + x->umask_kill = 0; + x->update = 0; + x->verbose = 0; + x->xstat = stat; +} + +int +main (int argc, char **argv) +{ + int optc; + int errors = 0; + const char *specified_mode = NULL; + int make_backups = 0; + char *backup_suffix_string; + char *version_control_string = NULL; + int mkdir_and_install = 0; + struct cp_options x; + int n_files; + char **file; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + cp_option_init (&x); + + owner_name = NULL; + group_name = NULL; + strip_files = 0; + dir_arg = 0; + umask (0); + + /* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless + we'll actually use backup_suffix_string. */ + backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); + + while ((optc = getopt_long (argc, argv, "bcsDdg:m:o:pvV:S:", long_options, + NULL)) != -1) + { + switch (optc) + { + case 0: + break; + + case 'V': /* FIXME: this is deprecated. Remove it in 2001. */ + error (0, 0, + _("warning: --version-control (-V) is obsolete; support for\ + it\nwill be removed in some future release. Use --backup=%s instead." + ), optarg); + /* Fall through. */ + + case 'b': + make_backups = 1; + if (optarg) + version_control_string = optarg; + break; + case 'c': + break; + case 's': + strip_files = 1; + break; + case 'd': + dir_arg = 1; + break; + case 'D': + mkdir_and_install = 1; + break; + case 'v': + x.verbose = 1; + break; + case 'g': + group_name = optarg; + break; + case 'm': + specified_mode = optarg; + break; + case 'o': + owner_name = optarg; + break; + case 'p': + x.preserve_timestamps = 1; + break; + case 'S': + make_backups = 1; + backup_suffix_string = optarg; + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (1); + } + } + + /* Check for invalid combinations of arguments. */ + if (dir_arg && strip_files) + error (1, 0, + _("the strip option may not be used when installing a directory")); + + if (backup_suffix_string) + simple_backup_suffix = xstrdup (backup_suffix_string); + + x.backup_type = (make_backups + ? xget_version (_("backup type"), + version_control_string) + : none); + + n_files = argc - optind; + file = argv + optind; + + if (n_files == 0 || (n_files == 1 && !dir_arg)) + { + error (0, 0, _("too few arguments")); + usage (1); + } + + if (specified_mode) + { + struct mode_change *change = mode_compile (specified_mode, 0); + if (change == MODE_INVALID) + error (1, 0, _("invalid mode %s"), quote (specified_mode)); + else if (change == MODE_MEMORY_EXHAUSTED) + xalloc_die (); + mode = mode_adjust (0, change); + } + + get_ids (); + + if (dir_arg) + { + int i; + for (i = 0; i < n_files; i++) + { + errors |= + make_path (file[i], mode, mode, owner_id, group_id, 0, + (x.verbose ? _("creating directory %s") : NULL)); + } + } + else + { + /* FIXME: it's a little gross that this initialization is + required by copy.c::copy. */ + hash_init (INITIAL_HASH_MODULE, INITIAL_ENTRY_TAB_SIZE); + + if (n_files == 2) + { + if (mkdir_and_install) + errors = install_file_to_path (file[0], file[1], &x); + else if (!isdir (file[1])) + errors = install_file_in_file (file[0], file[1], &x); + else + errors = install_file_in_dir (file[0], file[1], &x); + } + else + { + int i; + const char *dest = file[n_files - 1]; + if (!isdir (dest)) + { + error (0, 0, + _("installing multiple files, but last argument, %s \ +is not a directory"), + quote (dest)); + usage (1); + } + for (i = 0; i < n_files - 1; i++) + { + errors |= install_file_in_dir (file[i], dest, &x); + } + } + } + + exit (errors); +} + +/* Copy file FROM onto file TO, creating any missing parent directories of TO. + Return 0 if successful, 1 if an error occurs */ + +static int +install_file_to_path (const char *from, const char *to, + const struct cp_options *x) +{ + char *dest_dir; + int fail = 0; + + dest_dir = dir_name (to); + + /* check to make sure this is a path (not install a b ) */ + if (!STREQ (dest_dir, ".") + && !isdir (dest_dir)) + { + /* Someone will probably ask for a new option or three to specify + owner, group, and permissions for parent directories. Remember + that this option is intended mainly to help installers when the + distribution doesn't provide proper install rules. */ +#define DIR_MODE (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) + fail = make_path (dest_dir, DIR_MODE, DIR_MODE, owner_id, group_id, 0, + (x->verbose ? _("creating directory %s") : NULL)); + } + + if (fail == 0) + fail = install_file_in_file (from, to, x); + + free (dest_dir); + + return fail; +} + +/* Copy file FROM onto file TO and give TO the appropriate + attributes. + Return 0 if successful, 1 if an error occurs. */ + +static int +install_file_in_file (const char *from, const char *to, + const struct cp_options *x) +{ + if (copy_file (from, to, x)) + return 1; + if (strip_files) + strip (to); + if (change_attributes (to)) + return 1; + if (x->preserve_timestamps) + return change_timestamps (from, to); + return 0; +} + +/* Copy file FROM into directory TO_DIR, keeping its same name, + and give the copy the appropriate attributes. + Return 0 if successful, 1 if not. */ + +static int +install_file_in_dir (const char *from, const char *to_dir, + const struct cp_options *x) +{ + const char *from_base; + char *to; + int ret; + + from_base = base_name (from); + to = path_concat (to_dir, from_base, NULL); + ret = install_file_in_file (from, to, x); + free (to); + return ret; +} + +/* Copy file FROM onto file TO, creating TO if necessary. + Return 0 if the copy is successful, 1 if not. */ + +static int +copy_file (const char *from, const char *to, const struct cp_options *x) +{ + int fail; + int nonexistent_dst = 0; + int copy_into_self; + + /* Allow installing from non-regular files like /dev/null. + Charles Karney reported that some Sun version of install allows that + and that sendmail's installation process relies on the behavior. */ + if (isdir (from)) + { + error (0, 0, _("%s is a directory"), quote (from)); + return 1; + } + + fail = copy (from, to, nonexistent_dst, x, ©_into_self, NULL); + + return fail; +} + +/* Set the attributes of file or directory PATH. + Return 0 if successful, 1 if not. */ + +static int +change_attributes (const char *path) +{ + int err = 0; + + /* chown must precede chmod because on some systems, + chown clears the set[ug]id bits for non-superusers, + resulting in incorrect permissions. + On System V, users can give away files with chown and then not + be able to chmod them. So don't give files away. + + We don't normally ignore errors from chown because the idea of + the install command is that the file is supposed to end up with + precisely the attributes that the user specified (or defaulted). + If the file doesn't end up with the group they asked for, they'll + want to know. But AFS returns EPERM when you try to change a + file's group; thus the kludge. */ + + if (chown (path, owner_id, group_id) +#ifdef AFS + && errno != EPERM +#endif + ) + { + error (0, errno, "cannot change ownership of %s", quote (path)); + err = 1; + } + + if (!err && chmod (path, mode)) + { + error (0, errno, "cannot change permissions of %s", quote (path)); + err = 1; + } + + return err; +} + +/* Set the timestamps of file TO to match those of file FROM. + Return 0 if successful, 1 if not. */ + +static int +change_timestamps (const char *from, const char *to) +{ + struct stat stb; + struct utimbuf utb; + + if (stat (from, &stb)) + { + error (0, errno, _("cannot obtain time stamps for %s"), quote (from)); + return 1; + } + + /* There's currently no interface to set file timestamps with + better than 1-second resolution, so discard any fractional + part of the source timestamp. */ + + utb.actime = stb.st_atime; + utb.modtime = stb.st_mtime; + if (utime (to, &utb)) + { + error (0, errno, _("cannot set time stamps for %s"), quote (to)); + return 1; + } + return 0; +} + +/* Strip the symbol table from the file PATH. + We could dig the magic number out of the file first to + determine whether to strip it, but the header files and + magic numbers vary so much from system to system that making + it portable would be very difficult. Not worth the effort. */ + +static void +strip (const char *path) +{ + int status; + pid_t pid = fork (); + + switch (pid) + { + case -1: + error (1, errno, _("cannot fork")); + break; + case 0: /* Child. */ + execlp ("strip", "strip", path, NULL); + error (1, errno, _("cannot run strip")); + break; + default: /* Parent. */ + /* Parent process. */ + while (pid != wait (&status)) /* Wait for kid to finish. */ + /* Do nothing. */ ; + if (status) + error (1, 0, _("strip failed")); + break; + } +} + +/* Initialize the user and group ownership of the files to install. */ + +static void +get_ids (void) +{ + struct passwd *pw; + struct group *gr; + + if (owner_name) + { + pw = getpwnam (owner_name); + if (pw == NULL) + { + long int tmp_long; + if (xstrtol (owner_name, NULL, 0, &tmp_long, NULL) != LONGINT_OK + || tmp_long < 0 || tmp_long > UID_T_MAX) + error (1, 0, _("invalid user %s"), quote (owner_name)); + owner_id = (uid_t) tmp_long; + } + else + owner_id = pw->pw_uid; + endpwent (); + } + else + owner_id = (uid_t) -1; + + if (group_name) + { + gr = getgrnam (group_name); + if (gr == NULL) + { + long int tmp_long; + if (xstrtol (group_name, NULL, 0, &tmp_long, NULL) != LONGINT_OK + || tmp_long < 0 || tmp_long > GID_T_MAX) + error (1, 0, _("invalid group %s"), quote (group_name)); + group_id = (gid_t) tmp_long; + } + else + group_id = gr->gr_gid; + endgrent (); + } + else + group_id = (gid_t) -1; +} + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... SOURCE DEST (1st format)\n\ + or: %s [OPTION]... SOURCE... DIRECTORY (2nd format)\n\ + or: %s -d [OPTION]... DIRECTORY... (3rd format)\n\ +"), + program_name, program_name, program_name); + printf (_("\ +In the first two formats, copy SOURCE to DEST or multiple SOURCE(s) to\n\ +the existing DIRECTORY, while setting permission modes and owner/group.\n\ +In the third format, create all components of the given DIRECTORY(ies).\n\ +\n\ + --backup[=CONTROL] make a backup of each existing destination file\n\ + -b like --backup but does not accept an argument\n\ + -c (ignored)\n\ + -d, --directory treat all arguments as directory names; create all\n\ + components of the specified directories\n\ + -D create all leading components of DEST except the last,\n\ + then copy SOURCE to DEST; useful in the 1st format\n\ + -g, --group=GROUP set group ownership, instead of process' current group\n\ + -m, --mode=MODE set permission mode (as in chmod), instead of rwxr-xr-x\n\ + -o, --owner=OWNER set ownership (super-user only)\n\ + -p, --preserve-timestamps apply access/modification times of SOURCE files\n\ + to corresponding destination files\n\ + -s, --strip strip symbol tables, only for 1st and 2nd formats\n\ + -S, --suffix=SUFFIX override the usual backup suffix\n\ + -v, --verbose print the name of each directory as it is created\n\ + --help display this help and exit\n\ + --version output version information and exit\n\ +\n\ +")); + printf (_("\ +The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\ +The version control method may be selected via the --backup option or through\n\ +the VERSION_CONTROL environment variable. Here are the values:\n\ +\n\ + none, off never make backups (even if --backup is given)\n\ + numbered, t make numbered backups\n\ + existing, nil numbered if numbered backups exist, simple otherwise\n\ + simple, never always make simple backups\n\ +")); + puts (_("\nReport bugs to .")); + } + exit (status); +} diff --git a/src/apps/bin/gnu/ln.c b/src/apps/bin/gnu/ln.c new file mode 100644 index 0000000000..21f55dcd6f --- /dev/null +++ b/src/apps/bin/gnu/ln.c @@ -0,0 +1,563 @@ +/* `ln' program to create links between files. + Copyright (C) 86, 89, 90, 91, 1995-2001 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Mike Parker and David MacKenzie. */ + +#ifdef _AIX + #pragma alloca +#endif + +#include +#include +#include +#include + +#include "system.h" +#include "same.h" +#include "backupfile.h" +#include "error.h" +#include "quote.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "ln" + +#define AUTHORS "Mike Parker and David MacKenzie" + +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + TARGET_DIRECTORY_OPTION = CHAR_MAX + 1 +}; + +int link (); /* Some systems don't declare this anywhere. */ + +#ifdef S_ISLNK +int symlink (); +#endif + +/* In being careful not even to try to make hard links to directories, + we have to know whether link(2) follows symlinks. If it does, then + we have to *stat* the `source' to see if the resulting link would be + to a directory. Otherwise, we have to use *lstat* so that we allow + users to make hard links to symlinks-that-point-to-directories. */ + +#if LINK_FOLLOWS_SYMLINKS +# define STAT_LIKE_LINK(File, Stat_buf) \ + stat (File, Stat_buf) +#else +# define STAT_LIKE_LINK(File, Stat_buf) \ + lstat (File, Stat_buf) +#endif + +/* Construct a string NEW_DEST by concatenating DEST, a slash, and + basename(SOURCE) in alloca'd memory. Don't modify DEST or SOURCE. */ + +#define PATH_BASENAME_CONCAT(new_dest, dest, source) \ + do \ + { \ + const char *source_base; \ + char *tmp_source; \ + \ + tmp_source = (char *) alloca (strlen ((source)) + 1); \ + strcpy (tmp_source, (source)); \ + strip_trailing_slashes (tmp_source); \ + source_base = base_name (tmp_source); \ + \ + (new_dest) = (char *) alloca (strlen ((dest)) + 1 \ + + strlen (source_base) + 1); \ + stpcpy (stpcpy (stpcpy ((new_dest), (dest)), "/"), source_base);\ + } \ + while (0) + +int isdir (); +int yesno (); +void strip_trailing_slashes (); + +/* The name by which the program was run, for error messages. */ +char *program_name; + +/* FIXME: document */ +enum backup_type backup_type; + +/* A pointer to the function used to make links. This will point to either + `link' or `symlink'. */ +static int (*linkfunc) (); + +/* If nonzero, make symbolic links; otherwise, make hard links. */ +static int symbolic_link; + +/* If nonzero, ask the user before removing existing files. */ +static int interactive; + +/* If nonzero, remove existing files unconditionally. */ +static int remove_existing_files; + +/* If nonzero, list each file as it is moved. */ +static int verbose; + +/* If nonzero, allow the superuser to make hard links to directories. */ +static int hard_dir_link; + +/* If nonzero, and the specified destination is a symbolic link to a + directory, treat it just as if it were a directory. Otherwise, the + command `ln --force --no-dereference file symlink-to-dir' deletes + symlink-to-dir before creating the new link. */ +static int dereference_dest_dir_symlinks = 1; + +static struct option const long_options[] = +{ + {"backup", optional_argument, NULL, 'b'}, + {"directory", no_argument, NULL, 'F'}, + {"no-dereference", no_argument, NULL, 'n'}, + {"force", no_argument, NULL, 'f'}, + {"interactive", no_argument, NULL, 'i'}, + {"suffix", required_argument, NULL, 'S'}, + {"target-directory", required_argument, NULL, TARGET_DIRECTORY_OPTION}, + {"symbolic", no_argument, NULL, 's'}, + {"verbose", no_argument, NULL, 'v'}, + {"version-control", required_argument, NULL, 'V'}, /* Deprecated. FIXME. */ + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +/* Make a link DEST to the (usually) existing file SOURCE. + Symbolic links to nonexistent files are allowed. + If DEST is a directory, put the link to SOURCE in that directory. + Return 1 if there is an error, otherwise 0. */ + +static int +do_link (const char *source, const char *dest) +{ + struct stat source_stats; + struct stat dest_stats; + char *dest_backup = NULL; + int lstat_status; + int backup_succeeded = 0; + + /* Use stat here instead of lstat. + On SVR4, link does not follow symlinks, so this check disallows + making hard links to symlinks that point to directories. Big deal. + On other systems, link follows symlinks, so this check is right. */ + if (!symbolic_link) + { + if (STAT_LIKE_LINK (source, &source_stats) != 0) + { + error (0, errno, _("accessing %s"), quote (source)); + return 1; + } + + if (S_ISLNK (source_stats.st_mode)) + { + error (0, 0, _("%s: warning: making a hard link to a symbolic link\ + is not portable"), + quote (source)); + } + + if (!hard_dir_link && S_ISDIR (source_stats.st_mode)) + { + error (0, 0, _("%s: hard link not allowed for directory"), + quote (source)); + return 1; + } + } + + lstat_status = lstat (dest, &dest_stats); + if (lstat_status != 0 && errno != ENOENT) + { + error (0, errno, _("accessing %s"), quote (dest)); + return 1; + } + + /* If the destination is a directory or (it is a symlink to a directory + and the user has not specified --no-dereference), then form the + actual destination name by appending base_name (source) to the + specified destination directory. */ + if ((lstat_status == 0 + && S_ISDIR (dest_stats.st_mode)) +#ifdef S_ISLNK + || (dereference_dest_dir_symlinks + && (lstat_status == 0 + && S_ISLNK (dest_stats.st_mode) + && isdir (dest))) +#endif + ) + { + /* Target is a directory; build the full filename. */ + char *new_dest; + PATH_BASENAME_CONCAT (new_dest, dest, source); + dest = new_dest; + + /* Get stats for new DEST. */ + lstat_status = lstat (dest, &dest_stats); + if (lstat_status != 0 && errno != ENOENT) + { + error (0, errno, _("accessing %s"), quote (dest)); + return 1; + } + } + + /* If --force (-f) has been specified without --backup, then before + making a link ln must remove the destination file if it exists. + (with --backup, it just renames any existing destination file) + But if the source and destination are the same, don't remove + anything and fail right here. */ + if (remove_existing_files + && lstat_status == 0 + /* Allow `ln -sf --backup k k' to succeed in creating the + self-referential symlink, but don't allow the hard-linking + equivalent: `ln -f k k' (with or without --backup) to get + beyond this point, because the error message you'd get is + misleading. */ + && (backup_type == none || !symlink) + && (!symbolic_link || stat (source, &source_stats) == 0) + && source_stats.st_dev == dest_stats.st_dev + && source_stats.st_ino == dest_stats.st_ino + /* The following detects whether removing DEST will also remove + SOURCE. If the file has only one link then both are surely + the same link. Otherwise check whether they point to the same + name in the same directory. */ + && (source_stats.st_nlink == 1 || same_name (source, dest))) + { + error (0, 0, _("%s and %s are the same file"), + quote_n (0, source), quote_n (1, dest)); + return 1; + } + + if (lstat_status == 0 || lstat (dest, &dest_stats) == 0) + { + if (S_ISDIR (dest_stats.st_mode)) + { + error (0, 0, _("%s: cannot overwrite directory"), quote (dest)); + return 1; + } + if (interactive) + { + fprintf (stderr, _("%s: replace %s? "), program_name, quote (dest)); + if (!yesno ()) + return 0; + } + else if (!remove_existing_files && backup_type == none) + { + error (0, 0, _("%s: File exists"), quote (dest)); + return 1; + } + + if (backup_type != none) + { + char *tmp_backup = find_backup_file_name (dest, backup_type); + if (tmp_backup == NULL) + xalloc_die (); + dest_backup = (char *) alloca (strlen (tmp_backup) + 1); + strcpy (dest_backup, tmp_backup); + free (tmp_backup); + if (rename (dest, dest_backup)) + { + if (errno != ENOENT) + { + error (0, errno, _("cannot backup %s"), quote (dest)); + return 1; + } + else + dest_backup = NULL; + } + else + { + backup_succeeded = 1; + } + } + + /* Try to unlink DEST even if we may have renamed it. In some unusual + cases (when DEST and DEST_BACKUP are hard-links that refer to the + same file), rename succeeds and DEST remains. If we didn't remove + DEST in that case, the subsequent LINKFUNC call would fail. */ + if (unlink (dest) && errno != ENOENT) + { + error (0, errno, _("cannot remove %s"), quote (dest)); + return 1; + } + } + else if (errno != ENOENT) + { + error (0, errno, _("accessing %s"), quote (dest)); + return 1; + } + + if (verbose) + { + printf ((symbolic_link + ? _("create symbolic link %s to %s") + : _("create hard link %s to %s")), + quote_n (0, dest), quote_n (1, source)); + if (backup_succeeded) + printf (_(" (backup: %s)"), quote (dest_backup)); + putchar ('\n'); + } + + if ((*linkfunc) (source, dest) == 0) + { + return 0; + } + + error (0, errno, + (symbolic_link + ? _("creating symbolic link %s to %s") + : _("creating hard link %s to %s")), + quote_n (0, dest), quote_n (1, source)); + + if (dest_backup) + { + if (rename (dest_backup, dest)) + error (0, errno, _("cannot un-backup %s"), quote (dest)); + } + return 1; +} + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... TARGET [LINK_NAME]\n\ + or: %s [OPTION]... TARGET... DIRECTORY\n\ + or: %s [OPTION]... --target-directory=DIRECTORY TARGET...\n\ +"), + program_name, program_name, program_name); + printf (_("\ +Create a link to the specified TARGET with optional LINK_NAME.\n\ +If LINK_NAME is omitted, a link with the same basename as the TARGET is\n\ +created in the current directory. When using the second form with more\n\ +than one TARGET, the last argument must be a directory; create links\n\ +in DIRECTORY to each TARGET. Create hard links by default, symbolic\n\ +links with --symbolic. When creating hard links, each TARGET must exist.\n\ +\n\ + --backup[=CONTROL] make a backup of each existing destination file\n\ + -b like --backup but does not accept an argument\n\ + -d, -F, --directory hard link directories (super-user only)\n\ + -f, --force remove existing destination files\n\ + -n, --no-dereference treat destination that is a symlink to a\n\ + directory as if it were a normal file\n\ + -i, --interactive prompt whether to remove destinations\n\ + -s, --symbolic make symbolic links instead of hard links\n\ + -S, --suffix=SUFFIX override the usual backup suffix\n\ + --target-directory=DIRECTORY specify the DIRECTORY in which to create\n\ + the links\n\ + -v, --verbose print name of each file before linking\n\ + --help display this help and exit\n\ + --version output version information and exit\n\ +\n\ +")); + printf (_("\ +The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\ +The version control method may be selected via the --backup option or through\n\ +the VERSION_CONTROL environment variable. Here are the values:\n\ +\n\ + none, off never make backups (even if --backup is given)\n\ + numbered, t make numbered backups\n\ + existing, nil numbered if numbered backups exist, simple otherwise\n\ + simple, never always make simple backups\n\ +")); + puts (_("\nReport bugs to .")); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + int c; + int errors; + int make_backups = 0; + char *backup_suffix_string; + char *version_control_string = NULL; + char *target_directory = NULL; + int target_directory_specified; + unsigned int n_files; + char **file; + int dest_is_dir; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + /* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless + we'll actually use backup_suffix_string. */ + backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); + + symbolic_link = remove_existing_files = interactive = verbose + = hard_dir_link = 0; + errors = 0; + + while ((c = getopt_long (argc, argv, "bdfinsvFS:V:", long_options, NULL)) + != -1) + { + switch (c) + { + case 0: /* Long-named option. */ + break; + + case 'V': /* FIXME: this is deprecated. Remove it in 2001. */ + error (0, 0, + _("warning: --version-control (-V) is obsolete; support for\ + it\nwill be removed in some future release. Use --backup=%s instead." + ), optarg); + /* Fall through. */ + + case 'b': + make_backups = 1; + if (optarg) + version_control_string = optarg; + break; + case 'd': + case 'F': + hard_dir_link = 1; + break; + case 'f': + remove_existing_files = 1; + interactive = 0; + break; + case 'i': + remove_existing_files = 0; + interactive = 1; + break; + case 'n': + dereference_dest_dir_symlinks = 0; + break; + case 's': +#ifdef S_ISLNK + symbolic_link = 1; +#else + error (1, 0, _("symbolic links are not supported on this system")); +#endif + break; + case TARGET_DIRECTORY_OPTION: + target_directory = optarg; + break; + case 'v': + verbose = 1; + break; + case 'S': + make_backups = 1; + backup_suffix_string = optarg; + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (1); + break; + } + } + + n_files = argc - optind; + file = argv + optind; + + if (n_files == 0) + { + error (0, 0, _("missing file argument")); + usage (1); + } + + target_directory_specified = (target_directory != NULL); + if (!target_directory) + target_directory = file[n_files - 1]; + + /* If there's only one file argument, then pretend `.' was given + as the second argument. */ + if (n_files == 1) + { + static char *dummy[2]; + dummy[0] = file[0]; + dummy[1] = "."; + file = dummy; + n_files = 2; + dest_is_dir = 1; + } + else + { + dest_is_dir = isdir (target_directory); + } + + if (symbolic_link) + linkfunc = symlink; + else + linkfunc = link; + + if (target_directory_specified && !dest_is_dir) + { + error (0, 0, _("specified target directory, %s is not a directory"), + quote (target_directory)); + usage (1); + } + + if (backup_suffix_string) + simple_backup_suffix = xstrdup (backup_suffix_string); + + backup_type = (make_backups + ? xget_version (_("backup type"), version_control_string) + : none); + + if (target_directory_specified || n_files > 2) + { + unsigned int i; + unsigned int last_file_idx = (target_directory_specified + ? n_files - 1 + : n_files - 2); + + if (!target_directory_specified && !dest_is_dir) + error (1, 0, + _("when making multiple links, last argument must be a directory")); + for (i = 0; i <= last_file_idx; ++i) + errors += do_link (file[i], target_directory); + } + else + { + struct stat source_stats; + const char *source; + char *dest; + char *new_dest; + + source = file[0]; + dest = file[1]; + + /* When the destination is specified with a trailing slash and the + source exists but is not a directory, convert the user's command + `ln source dest/' to `ln source dest/basename(source)'. */ + + if (dest[strlen (dest) - 1] == '/' + && lstat (source, &source_stats) == 0 + && !S_ISDIR (source_stats.st_mode)) + { + PATH_BASENAME_CONCAT (new_dest, dest, source); + } + else + { + new_dest = dest; + } + + errors = do_link (source, new_dest); + } + + exit (errors != 0); +} diff --git a/src/apps/bin/gnu/ls-dir.c b/src/apps/bin/gnu/ls-dir.c new file mode 100644 index 0000000000..85fe242ebf --- /dev/null +++ b/src/apps/bin/gnu/ls-dir.c @@ -0,0 +1,2 @@ +#include "ls.h" +int ls_mode = LS_MULTI_COL; diff --git a/src/apps/bin/gnu/ls-ls.c b/src/apps/bin/gnu/ls-ls.c new file mode 100644 index 0000000000..f33fbbc061 --- /dev/null +++ b/src/apps/bin/gnu/ls-ls.c @@ -0,0 +1,2 @@ +#include "ls.h" +int ls_mode = LS_LS; diff --git a/src/apps/bin/gnu/ls-vdir.c b/src/apps/bin/gnu/ls-vdir.c new file mode 100644 index 0000000000..36ebf913bc --- /dev/null +++ b/src/apps/bin/gnu/ls-vdir.c @@ -0,0 +1,2 @@ +#include "ls.h" +int ls_mode = LS_LONG_FORMAT; diff --git a/src/apps/bin/gnu/ls.c b/src/apps/bin/gnu/ls.c new file mode 100644 index 0000000000..efc5611bcb --- /dev/null +++ b/src/apps/bin/gnu/ls.c @@ -0,0 +1,3338 @@ +/* `dir', `vdir' and `ls' directory listing programs for GNU. + Copyright (C) 85, 88, 90, 91, 1995-2001 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* If ls_mode is LS_MULTI_COL, + the multi-column format is the default regardless + of the type of output device. + This is for the `dir' program. + + If ls_mode is LS_LONG_FORMAT, + the long format is the default regardless of the + type of output device. + This is for the `vdir' program. + + If ls_mode is LS_LS, + the output format depends on whether the output + device is a terminal. + This is for the `ls' program. */ + +/* Written by Richard Stallman and David MacKenzie. */ + +/* Color support by Peter Anvin and Dennis + Flaherty based on original patches by + Greg Lee . */ + +#ifdef _AIX + #pragma alloca +#endif + +#include +#include + +#if HAVE_INTTYPES_H +# include +#endif + +#if HAVE_TERMIOS_H +# include +#endif + +#ifdef GWINSZ_IN_SYS_IOCTL +# include +#endif + +#ifdef WINSIZE_IN_PTEM +# include +# include +#endif + +#if HAVE_SYS_ACL_H +# include +#endif + +#include +#include +#include +#include +#include + +/* Get MB_CUR_MAX. */ +#if HAVE_STDLIB_H +# include +#endif + +/* Get mbstate_t, mbrtowc(), mbsinit(), wcwidth(). */ +#if HAVE_WCHAR_H +# include +#endif + +/* Get iswprint(). */ +#if HAVE_WCTYPE_H +# include +#endif +#if !defined iswprint && !HAVE_ISWPRINT +# define iswprint(wc) 1 +#endif + +#ifndef HAVE_DECL_WCWIDTH +"this configure-time declaration test was not run" +#endif +#if !HAVE_DECL_WCWIDTH +int wcwidth (); +#endif + +/* If wcwidth() doesn't exist, assume all printable characters have + width 1. */ +#ifndef wcwidth +# if !HAVE_WCWIDTH +# define wcwidth(wc) ((wc) == 0 ? 0 : iswprint (wc) ? 1 : -1) +# endif +#endif + +#include "system.h" +#include + +#include "argmatch.h" +#include "error.h" +#include "human.h" +#include "filemode.h" +#include "ls.h" +#include "mbswidth.h" +#include "obstack.h" +#include "path-concat.h" +#include "quotearg.h" +#include "strverscmp.h" +#include "xstrtol.h" + +/* Use access control lists only under all the following conditions. + Some systems (OSF4, Irix5, Irix6) have the acl function, but not + sys/acl.h or don't define the GETACLCNT macro. */ +#if HAVE_SYS_ACL_H && HAVE_ACL && defined GETACLCNT +# define USE_ACL 1 +#endif + +#define PROGRAM_NAME (ls_mode == LS_LS ? "ls" \ + : (ls_mode == LS_MULTI_COL \ + ? "dir" : "vdir")) + +#define AUTHORS "Richard Stallman and David MacKenzie" + +#define obstack_chunk_alloc malloc +#define obstack_chunk_free free + +/* Return an int indicating the result of comparing two integers. + Subtracting doesn't always work, due to overflow. */ +#define longdiff(a, b) ((a) < (b) ? -1 : (a) > (b)) + +/* The field width for inode numbers. On some hosts inode numbers are + 64 bits, so columns won't line up exactly when a huge inode number + is encountered, but in practice 7 digits is usually enough. */ +#ifndef INODE_DIGITS +# define INODE_DIGITS 7 +#endif + +#ifdef S_ISLNK +# define HAVE_SYMLINKS 1 +#else +# define HAVE_SYMLINKS 0 +#endif + +/* If any of the S_* macros are undefined, define them here so each + use doesn't have to be guarded with e.g., #ifdef S_ISLNK. */ +#ifndef S_ISLNK +# define S_ISLNK(Mode) 0 +#endif + +#ifndef S_ISFIFO +# define S_ISFIFO(Mode) 0 +#endif + +#ifndef S_ISSOCK +# define S_ISSOCK(Mode) 0 +#endif + +#ifndef S_ISCHR +# define S_ISCHR(Mode) 0 +#endif + +#ifndef S_ISBLK +# define S_ISBLK(Mode) 0 +#endif + +#ifndef S_ISDOOR +# define S_ISDOOR(Mode) 0 +#endif + +/* Arrange to make lstat calls go through the wrapper function + on systems with an lstat function that does not dereference symlinks + that are specified with a trailing slash. */ +#if ! LSTAT_FOLLOWS_SLASHED_SYMLINK +int rpl_lstat PARAMS((const char *, struct stat *)); +# undef lstat +# define lstat(Name, Stat_buf) rpl_lstat(Name, Stat_buf) +#endif + +#if defined _DIRENT_HAVE_D_TYPE || defined DTTOIF +# define HAVE_STRUCT_DIRENT_D_TYPE 1 +# define DT_INIT(Val) = Val +#else +# define HAVE_STRUCT_DIRENT_D_TYPE 0 +# define DT_INIT(Val) /* empty */ +#endif + +#ifdef ST_MTIM_NSEC +# define TIMESPEC_NS(timespec) ((timespec).ST_MTIM_NSEC) +#else +# define TIMESPEC_NS(timespec) 0 +#endif + +enum filetype + { + unknown DT_INIT (DT_UNKNOWN), + fifo DT_INIT (DT_FIFO), + chardev DT_INIT (DT_CHR), + directory DT_INIT (DT_DIR), + blockdev DT_INIT (DT_BLK), + normal DT_INIT (DT_REG), + symbolic_link DT_INIT (DT_LNK), + sock DT_INIT (DT_SOCK), + arg_directory DT_INIT (2 * (DT_UNKNOWN | DT_FIFO | DT_CHR | DT_DIR | DT_BLK + | DT_REG | DT_LNK | DT_SOCK)) + }; + +struct fileinfo + { + /* The file name. */ + char *name; + + struct stat stat; + + /* For symbolic link, name of the file linked to, otherwise zero. */ + char *linkname; + + /* For symbolic link and long listing, st_mode of file linked to, otherwise + zero. */ + unsigned int linkmode; + + /* For symbolic link and color printing, 1 if linked-to file + exists, otherwise 0. */ + int linkok; + + enum filetype filetype; + +#if USE_ACL + /* For long listings, nonzero if the file has an access control list, + otherwise zero. */ + int have_acl; +#endif + }; + +#if USE_ACL +# define FILE_HAS_ACL(F) ((F)->have_acl) +#else +# define FILE_HAS_ACL(F) 0 +#endif + +#define LEN_STR_PAIR(s) sizeof (s) - 1, s + +/* Null is a valid character in a color indicator (think about Epson + printers, for example) so we have to use a length/buffer string + type. */ + +struct bin_str + { + int len; /* Number of bytes */ + const char *string; /* Pointer to the same */ + }; + +#ifndef STDC_HEADERS +time_t time (); +#endif + +char *getgroup (); +char *getuser (); + +static size_t quote_name PARAMS ((FILE *out, const char *name, + struct quoting_options const *options)); +static char *make_link_path PARAMS ((const char *path, const char *linkname)); +static int compare_atime PARAMS ((const struct fileinfo *file1, + const struct fileinfo *file2)); +static int rev_cmp_atime PARAMS ((const struct fileinfo *file2, + const struct fileinfo *file1)); +static int compare_ctime PARAMS ((const struct fileinfo *file1, + const struct fileinfo *file2)); +static int rev_cmp_ctime PARAMS ((const struct fileinfo *file2, + const struct fileinfo *file1)); +static int compare_mtime PARAMS ((const struct fileinfo *file1, + const struct fileinfo *file2)); +static int rev_cmp_mtime PARAMS ((const struct fileinfo *file2, + const struct fileinfo *file1)); +static int compare_size PARAMS ((const struct fileinfo *file1, + const struct fileinfo *file2)); +static int rev_cmp_size PARAMS ((const struct fileinfo *file2, + const struct fileinfo *file1)); +static int compare_name PARAMS ((const struct fileinfo *file1, + const struct fileinfo *file2)); +static int rev_cmp_name PARAMS ((const struct fileinfo *file2, + const struct fileinfo *file1)); +static int compare_extension PARAMS ((const struct fileinfo *file1, + const struct fileinfo *file2)); +static int rev_cmp_extension PARAMS ((const struct fileinfo *file2, + const struct fileinfo *file1)); +static int compare_version PARAMS ((const struct fileinfo *file1, + const struct fileinfo *file2)); +static int rev_cmp_version PARAMS ((const struct fileinfo *file2, + const struct fileinfo *file1)); +static int decode_switches PARAMS ((int argc, char **argv)); +static int file_interesting PARAMS ((const struct dirent *next)); +static uintmax_t gobble_file PARAMS ((const char *name, enum filetype type, + int explicit_arg, const char *dirname)); +static void print_color_indicator PARAMS ((const char *name, unsigned int mode, + int linkok)); +static void put_indicator PARAMS ((const struct bin_str *ind)); +static int length_of_file_name_and_frills PARAMS ((const struct fileinfo *f)); +static void add_ignore_pattern PARAMS ((const char *pattern)); +static void attach PARAMS ((char *dest, const char *dirname, const char *name)); +static void clear_files PARAMS ((void)); +static void extract_dirs_from_files PARAMS ((const char *dirname, + int recursive)); +static void get_link_name PARAMS ((const char *filename, struct fileinfo *f)); +static void indent PARAMS ((int from, int to)); +static void init_column_info PARAMS ((void)); +static void print_current_files PARAMS ((void)); +static void print_dir PARAMS ((const char *name, const char *realname)); +static void print_file_name_and_frills PARAMS ((const struct fileinfo *f)); +static void print_horizontal PARAMS ((void)); +static void print_long_format PARAMS ((const struct fileinfo *f)); +static void print_many_per_line PARAMS ((void)); +static void print_name_with_quoting PARAMS ((const char *p, unsigned int mode, + int linkok, + struct obstack *stack)); +static void prep_non_filename_text PARAMS ((void)); +static void print_type_indicator PARAMS ((unsigned int mode)); +static void print_with_commas PARAMS ((void)); +static void queue_directory PARAMS ((const char *name, const char *realname)); +static void sort_files PARAMS ((void)); +static void parse_ls_color PARAMS ((void)); +void usage PARAMS ((int status)); + +/* The name the program was run with, stripped of any leading path. */ +char *program_name; + +/* The table of files in the current directory: + + `files' points to a vector of `struct fileinfo', one per file. + `nfiles' is the number of elements space has been allocated for. + `files_index' is the number actually in use. */ + +/* Address of block containing the files that are described. */ +static struct fileinfo *files; /* FIXME: rename this to e.g. cwd_file */ + +/* Length of block that `files' points to, measured in files. */ +static int nfiles; /* FIXME: rename this to e.g. cwd_n_alloc */ + +/* Index of first unused in `files'. */ +static int files_index; /* FIXME: rename this to e.g. cwd_n_used */ + +/* When nonzero, in a color listing, color each symlink name according to the + type of file it points to. Otherwise, color them according to the `ln' + directive in LS_COLORS. Dangling (orphan) symlinks are treated specially, + regardless. This is set when `ln=target' appears in LS_COLORS. */ + +static int color_symlink_as_referent; + +/* mode of appropriate file for colorization */ +#define FILE_OR_LINK_MODE(File) \ + ((color_symlink_as_referent && (File)->linkok) \ + ? (File)->linkmode : (File)->stat.st_mode) + + +/* Record of one pending directory waiting to be listed. */ + +struct pending + { + char *name; + /* If the directory is actually the file pointed to by a symbolic link we + were told to list, `realname' will contain the name of the symbolic + link, otherwise zero. */ + char *realname; + struct pending *next; + }; + +static struct pending *pending_dirs; + +/* Current time in seconds and nanoseconds since 1970, updated as + needed when deciding whether a file is recent. */ + +static time_t current_time = TYPE_MINIMUM (time_t); +static int current_time_ns = -1; + +/* The number of digits to use for block sizes. + 4, or more if needed for bigger numbers. */ + +static int block_size_size; + +/* Option flags */ + +/* long_format for lots of info, one per line. + one_per_line for just names, one per line. + many_per_line for just names, many per line, sorted vertically. + horizontal for just names, many per line, sorted horizontally. + with_commas for just names, many per line, separated by commas. + + -l, -1, -C, -x and -m control this parameter. */ + +enum format + { + long_format, /* -l */ + one_per_line, /* -1 */ + many_per_line, /* -C */ + horizontal, /* -x */ + with_commas /* -m */ + }; + +static enum format format; + +/* Type of time to print or sort by. Controlled by -c and -u. */ + +enum time_type + { + time_mtime, /* default */ + time_ctime, /* -c */ + time_atime /* -u */ + }; + +static enum time_type time_type; + +/* print the full time, otherwise the standard unix heuristics. */ + +static int full_time; + +/* The file characteristic to sort by. Controlled by -t, -S, -U, -X, -v. */ + +enum sort_type + { + sort_none, /* -U */ + sort_name, /* default */ + sort_extension, /* -X */ + sort_time, /* -t */ + sort_size, /* -S */ + sort_version /* -v */ + }; + +static enum sort_type sort_type; + +/* Direction of sort. + 0 means highest first if numeric, + lowest first if alphabetic; + these are the defaults. + 1 means the opposite order in each case. -r */ + +static int sort_reverse; + +/* Nonzero means to NOT display group information. -G */ + +static int inhibit_group; + +/* Nonzero means print the user and group id's as numbers rather + than as names. -n */ + +static int numeric_ids; + +/* Nonzero means mention the size in blocks of each file. -s */ + +static int print_block_size; + +/* If positive, the units to use when printing sizes; + if negative, the human-readable base. */ +static int output_block_size; + +/* Precede each line of long output (per file) with a string like `m,n:' + where M is the number of characters after the `:' and before the + filename and N is the length of the filename. Using this format, + Emacs' dired mode starts up twice as fast, and can handle all + strange characters in file names. */ +static int dired; + +/* `none' means don't mention the type of files. + `classify' means mention file types and mark executables. + `file_type' means mention only file types. + + Controlled by -F, -p, and --indicator-style. */ + +enum indicator_style + { + none, /* --indicator-style=none */ + classify, /* -F, --indicator-style=classify */ + file_type /* -p, --indicator-style=file-type */ + }; + +static enum indicator_style indicator_style; + +/* Names of indicator styles. */ +static char const *const indicator_style_args[] = +{ + "none", "classify", "file-type", 0 +}; + +static enum indicator_style const indicator_style_types[]= +{ + none, classify, file_type +}; + +/* Nonzero means use colors to mark types. Also define the different + colors as well as the stuff for the LS_COLORS environment variable. + The LS_COLORS variable is now in a termcap-like format. */ + +static int print_with_color; + +enum color_type + { + color_never, /* 0: default or --color=never */ + color_always, /* 1: --color=always */ + color_if_tty /* 2: --color=tty */ + }; + +enum indicator_no + { + C_LEFT, C_RIGHT, C_END, C_NORM, C_FILE, C_DIR, C_LINK, C_FIFO, C_SOCK, + C_BLK, C_CHR, C_MISSING, C_ORPHAN, C_EXEC, C_DOOR + }; + +static const char *const indicator_name[]= + { + "lc", "rc", "ec", "no", "fi", "di", "ln", "pi", "so", + "bd", "cd", "mi", "or", "ex", "do", NULL + }; + +struct color_ext_type + { + struct bin_str ext; /* The extension we're looking for */ + struct bin_str seq; /* The sequence to output when we do */ + struct color_ext_type *next; /* Next in list */ + }; + +static struct bin_str color_indicator[] = + { + { LEN_STR_PAIR ("\033[") }, /* lc: Left of color sequence */ + { LEN_STR_PAIR ("m") }, /* rc: Right of color sequence */ + { 0, NULL }, /* ec: End color (replaces lc+no+rc) */ + { LEN_STR_PAIR ("0") }, /* no: Normal */ + { LEN_STR_PAIR ("0") }, /* fi: File: default */ + { LEN_STR_PAIR ("01;34") }, /* di: Directory: bright blue */ + { LEN_STR_PAIR ("01;36") }, /* ln: Symlink: bright cyan */ + { LEN_STR_PAIR ("33") }, /* pi: Pipe: yellow/brown */ + { LEN_STR_PAIR ("01;35") }, /* so: Socket: bright magenta */ + { LEN_STR_PAIR ("01;33") }, /* bd: Block device: bright yellow */ + { LEN_STR_PAIR ("01;33") }, /* cd: Char device: bright yellow */ + { 0, NULL }, /* mi: Missing file: undefined */ + { 0, NULL }, /* or: Orphanned symlink: undefined */ + { LEN_STR_PAIR ("01;32") }, /* ex: Executable: bright green */ + { LEN_STR_PAIR ("01;35") } /* do: Door: bright magenta */ + }; + +/* FIXME: comment */ +static struct color_ext_type *color_ext_list = NULL; + +/* Buffer for color sequences */ +static char *color_buf; + +/* Nonzero means to check for orphaned symbolic link, for displaying + colors. */ + +static int check_symlink_color; + +/* Nonzero means mention the inode number of each file. -i */ + +static int print_inode; + +/* Nonzero means when a symbolic link is found, display info on + the file linked to. -L */ + +static int trace_links; + +/* Nonzero means when a directory is found, display info on its + contents. -R */ + +static int trace_dirs; + +/* Nonzero means when an argument is a directory name, display info + on it itself. -d */ + +static int immediate_dirs; + +/* Nonzero means don't omit files whose names start with `.'. -A */ + +static int all_files; + +/* Nonzero means don't omit files `.' and `..' + This flag implies `all_files'. -a */ + +static int really_all_files; + +/* A linked list of shell-style globbing patterns. If a non-argument + file name matches any of these patterns, it is omitted. + Controlled by -I. Multiple -I options accumulate. + The -B option adds `*~' and `.*~' to this list. */ + +struct ignore_pattern + { + const char *pattern; + struct ignore_pattern *next; + }; + +static struct ignore_pattern *ignore_patterns; + +/* Nonzero means output nongraphic chars in file names as `?'. + (-q, --hide-control-chars) + qmark_funny_chars and the quoting style (-Q, --quoting-style=WORD) are + independent. The algorithm is: first, obey the quoting style to get a + string representing the file name; then, if qmark_funny_chars is set, + replace all nonprintable chars in that string with `?'. It's necessary + to replace nonprintable chars even in quoted strings, because we don't + want to mess up the terminal if control chars get sent to it, and some + quoting methods pass through control chars as-is. */ +static int qmark_funny_chars; + +/* Quoting options for file and dir name output. */ + +static struct quoting_options *filename_quoting_options; +static struct quoting_options *dirname_quoting_options; + +/* The number of chars per hardware tab stop. Setting this to zero + inhibits the use of TAB characters for separating columns. -T */ +static int tabsize; + +/* Nonzero means we are listing the working directory because no + non-option arguments were given. */ + +static int dir_defaulted; + +/* Nonzero means print each directory name before listing it. */ + +static int print_dir_name; + +/* The line length to use for breaking lines in many-per-line format. + Can be set with -w. */ + +static int line_length; + +/* If nonzero, the file listing format requires that stat be called on + each file. */ + +static int format_needs_stat; + +/* Similar to `format_needs_stat', but set if only the file type is + needed. */ + +static int format_needs_type; + +/* strftime formats for non-recent and recent files, respectively, in + -l output. */ + +static char const *long_time_format[2]; + +/* The exit status to use if we don't get any fatal errors. */ + +static int exit_status; + +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + BLOCK_SIZE_OPTION = CHAR_MAX + 1, + COLOR_OPTION, + FORMAT_OPTION, + FULL_TIME_OPTION, + INDICATOR_STYLE_OPTION, + QUOTING_STYLE_OPTION, + SHOW_CONTROL_CHARS_OPTION, + SI_OPTION, + SORT_OPTION, + TIME_OPTION +}; + +static struct option const long_options[] = +{ + {"all", no_argument, 0, 'a'}, + {"escape", no_argument, 0, 'b'}, + {"directory", no_argument, 0, 'd'}, + {"dired", no_argument, 0, 'D'}, + {"full-time", no_argument, 0, FULL_TIME_OPTION}, + {"human-readable", no_argument, 0, 'h'}, + {"inode", no_argument, 0, 'i'}, + {"kilobytes", no_argument, 0, 'k'}, + {"numeric-uid-gid", no_argument, 0, 'n'}, + {"no-group", no_argument, 0, 'G'}, + {"hide-control-chars", no_argument, 0, 'q'}, + {"reverse", no_argument, 0, 'r'}, + {"size", no_argument, 0, 's'}, + {"width", required_argument, 0, 'w'}, + {"almost-all", no_argument, 0, 'A'}, + {"ignore-backups", no_argument, 0, 'B'}, + {"classify", no_argument, 0, 'F'}, + {"file-type", no_argument, 0, 'p'}, + {"si", no_argument, 0, SI_OPTION}, + {"ignore", required_argument, 0, 'I'}, + {"indicator-style", required_argument, 0, INDICATOR_STYLE_OPTION}, + {"dereference", no_argument, 0, 'L'}, + {"literal", no_argument, 0, 'N'}, + {"quote-name", no_argument, 0, 'Q'}, + {"quoting-style", required_argument, 0, QUOTING_STYLE_OPTION}, + {"recursive", no_argument, 0, 'R'}, + {"format", required_argument, 0, FORMAT_OPTION}, + {"show-control-chars", no_argument, 0, SHOW_CONTROL_CHARS_OPTION}, + {"sort", required_argument, 0, SORT_OPTION}, + {"tabsize", required_argument, 0, 'T'}, + {"time", required_argument, 0, TIME_OPTION}, + {"color", optional_argument, 0, COLOR_OPTION}, + {"block-size", required_argument, 0, BLOCK_SIZE_OPTION}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +static char const *const format_args[] = +{ + "verbose", "long", "commas", "horizontal", "across", + "vertical", "single-column", 0 +}; + +static enum format const format_types[] = +{ + long_format, long_format, with_commas, horizontal, horizontal, + many_per_line, one_per_line +}; + +static char const *const sort_args[] = +{ + "none", "time", "size", "extension", "version", 0 +}; + +static enum sort_type const sort_types[] = +{ + sort_none, sort_time, sort_size, sort_extension, sort_version +}; + +static char const *const time_args[] = +{ + "atime", "access", "use", "ctime", "status", 0 +}; + +static enum time_type const time_types[] = +{ + time_atime, time_atime, time_atime, time_ctime, time_ctime +}; + +static char const *const color_args[] = +{ + /* force and none are for compatibility with another color-ls version */ + "always", "yes", "force", + "never", "no", "none", + "auto", "tty", "if-tty", 0 +}; + +static enum color_type const color_types[] = +{ + color_always, color_always, color_always, + color_never, color_never, color_never, + color_if_tty, color_if_tty, color_if_tty +}; + +/* Information about filling a column. */ +struct column_info +{ + int valid_len; + int line_len; + int *col_arr; +}; + +/* Array with information about column filledness. */ +static struct column_info *column_info; + +/* Maximum number of columns ever possible for this display. */ +static int max_idx; + +/* The minimum width of a colum is 3: 1 character for the name and 2 + for the separating white space. */ +#define MIN_COLUMN_WIDTH 3 + + +/* This zero-based index is used solely with the --dired option. + When that option is in effect, this counter is incremented for each + character of output generated by this program so that the beginning + and ending indices (in that output) of every file name can be recorded + and later output themselves. */ +static size_t dired_pos; + +#define DIRED_PUTCHAR(c) do {putchar ((c)); ++dired_pos;} while (0) + +/* Write S to STREAM and increment DIRED_POS by S_LEN. */ +#define DIRED_FPUTS(s, stream, s_len) \ + do {fputs ((s), (stream)); dired_pos += s_len;} while (0) + +/* Like DIRED_FPUTS, but for use when S is a literal string. */ +#define DIRED_FPUTS_LITERAL(s, stream) \ + do {fputs ((s), (stream)); dired_pos += sizeof((s)) - 1;} while (0) + +#define DIRED_INDENT() \ + do \ + { \ + /* FIXME: remove the `&& format == long_format' clause. */ \ + if (dired && format == long_format) \ + DIRED_FPUTS_LITERAL (" ", stdout); \ + } \ + while (0) + +/* With --dired, store pairs of beginning and ending indices of filenames. */ +static struct obstack dired_obstack; + +/* With --dired, store pairs of beginning and ending indices of any + directory names that appear as headers (just before `total' line) + for lists of directory entries. Such directory names are seen when + listing hierarchies using -R and when a directory is listed with at + least one other command line argument. */ +static struct obstack subdired_obstack; + +/* Save the current index on the specified obstack, OBS. */ +#define PUSH_CURRENT_DIRED_POS(obs) \ + do \ + { \ + /* FIXME: remove the `&& format == long_format' clause. */ \ + if (dired && format == long_format) \ + obstack_grow ((obs), &dired_pos, sizeof (dired_pos)); \ + } \ + while (0) + + +/* Write to standard output PREFIX, followed by the quoting style and + a space-separated list of the integers stored in OS all on one line. */ + +static void +dired_dump_obstack (const char *prefix, struct obstack *os) +{ + int n_pos; + + n_pos = obstack_object_size (os) / sizeof (dired_pos); + if (n_pos > 0) + { + int i; + size_t *pos; + + pos = (size_t *) obstack_finish (os); + fputs (prefix, stdout); + for (i = 0; i < n_pos; i++) + printf (" %d", (int) pos[i]); + fputs ("\n", stdout); + } +} + +int +main (int argc, char **argv) +{ + register int i; + register struct pending *thispend; + unsigned int n_files; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + +#define N_ENTRIES(Array) (sizeof Array / sizeof *(Array)) + assert (N_ENTRIES (color_indicator) + 1 == N_ENTRIES (indicator_name)); + + exit_status = 0; + dir_defaulted = 1; + print_dir_name = 1; + pending_dirs = 0; + + i = decode_switches (argc, argv); + + if (print_with_color) + { + parse_ls_color (); + prep_non_filename_text (); + /* Avoid following symbolic links when possible. */ + if (color_indicator[C_ORPHAN].string != NULL + || (color_indicator[C_MISSING].string != NULL + && format == long_format)) + check_symlink_color = 1; + } + + format_needs_stat = sort_type == sort_time || sort_type == sort_size + || format == long_format + || trace_links || trace_dirs || print_block_size || print_inode; + format_needs_type = (format_needs_stat == 0 + && (print_with_color || indicator_style != none)); + + if (dired && format == long_format) + { + obstack_init (&dired_obstack); + obstack_init (&subdired_obstack); + } + + nfiles = 100; + files = (struct fileinfo *) xmalloc (sizeof (struct fileinfo) * nfiles); + files_index = 0; + + clear_files (); + + n_files = argc - i; + if (0 < n_files) + dir_defaulted = 0; + + for (; i < argc; i++) + { + gobble_file (argv[i], unknown, 1, ""); + } + + if (dir_defaulted) + { + if (immediate_dirs) + gobble_file (".", directory, 1, ""); + else + queue_directory (".", 0); + } + + if (files_index) + { + sort_files (); + if (!immediate_dirs) + extract_dirs_from_files ("", 0); + /* `files_index' might be zero now. */ + } + if (files_index) + { + print_current_files (); + if (pending_dirs) + DIRED_PUTCHAR ('\n'); + } + else if (n_files <= 1 && pending_dirs && pending_dirs->next == 0) + print_dir_name = 0; + + while (pending_dirs) + { + thispend = pending_dirs; + pending_dirs = pending_dirs->next; + print_dir (thispend->name, thispend->realname); + free (thispend->name); + if (thispend->realname) + free (thispend->realname); + free (thispend); + print_dir_name = 1; + } + + if (dired && format == long_format) + { + /* No need to free these since we're about to exit. */ + dired_dump_obstack ("//DIRED//", &dired_obstack); + dired_dump_obstack ("//SUBDIRED//", &subdired_obstack); + printf ("//DIRED-OPTIONS// --quoting-style=%s\n", + ARGMATCH_TO_ARGUMENT (filename_quoting_options, + quoting_style_args, quoting_style_vals)); + } + + /* Restore default color before exiting */ + if (print_with_color) + { + put_indicator (&color_indicator[C_LEFT]); + put_indicator (&color_indicator[C_RIGHT]); + } + + exit (exit_status); +} + +/* Set all the option flags according to the switches specified. + Return the index of the first non-option argument. */ + +static int +decode_switches (int argc, char **argv) +{ + register char const *p; + int c; + int i; + long int tmp_long; + + /* Record whether there is an option specifying sort type. */ + int sort_type_specified = 0; + + qmark_funny_chars = 0; + + /* initialize all switches to default settings */ + + switch (ls_mode) + { + case LS_MULTI_COL: + /* This is for the `dir' program. */ + format = many_per_line; + set_quoting_style (NULL, escape_quoting_style); + break; + + case LS_LONG_FORMAT: + /* This is for the `vdir' program. */ + format = long_format; + set_quoting_style (NULL, escape_quoting_style); + break; + + case LS_LS: + /* This is for the `ls' program. */ + if (isatty (STDOUT_FILENO)) + { + format = many_per_line; + /* See description of qmark_funny_chars, above. */ + qmark_funny_chars = 1; + } + else + { + format = one_per_line; + qmark_funny_chars = 0; + } + break; + + default: + abort (); + } + + time_type = time_mtime; + full_time = 0; + sort_type = sort_name; + sort_reverse = 0; + numeric_ids = 0; + print_block_size = 0; + indicator_style = none; + print_inode = 0; + trace_links = 0; + trace_dirs = 0; + immediate_dirs = 0; + all_files = 0; + really_all_files = 0; + ignore_patterns = 0; + + /* FIXME: Shouldn't we complain on wrong values? */ + if ((p = getenv ("QUOTING_STYLE")) + && 0 <= (i = ARGCASEMATCH (p, quoting_style_args, quoting_style_vals))) + set_quoting_style (NULL, quoting_style_vals[i]); + + human_block_size (getenv ("LS_BLOCK_SIZE"), 0, &output_block_size); + + line_length = 80; + if ((p = getenv ("COLUMNS")) && *p) + { + if (xstrtol (p, NULL, 0, &tmp_long, NULL) == LONGINT_OK + && 0 < tmp_long && tmp_long <= INT_MAX) + { + line_length = (int) tmp_long; + } + else + { + error (0, 0, + _("ignoring invalid width in environment variable COLUMNS: %s"), + quotearg (p)); + } + } + +#ifdef TIOCGWINSZ + { + struct winsize ws; + + if (ioctl (STDOUT_FILENO, TIOCGWINSZ, &ws) != -1 && ws.ws_col != 0) + line_length = ws.ws_col; + } +#endif + + /* Using the TABSIZE environment variable is not POSIX-approved. + Ignore it when POSIXLY_CORRECT is set. */ + tabsize = 8; + if (!getenv ("POSIXLY_CORRECT") && (p = getenv ("TABSIZE"))) + { + if (xstrtol (p, NULL, 0, &tmp_long, NULL) == LONGINT_OK + && 0 <= tmp_long && tmp_long <= INT_MAX) + { + tabsize = (int) tmp_long; + } + else + { + error (0, 0, + _("ignoring invalid tab size in environment variable TABSIZE: %s"), + quotearg (p)); + } + } + + while ((c = getopt_long (argc, argv, + "abcdfghiklmnopqrstuvw:xABCDFGHI:LNQRST:UX1", + long_options, NULL)) != -1) + { + switch (c) + { + case 0: + break; + + case 'a': + all_files = 1; + really_all_files = 1; + break; + + case 'b': + set_quoting_style (NULL, escape_quoting_style); + break; + + case 'c': + time_type = time_ctime; + break; + + case 'd': + immediate_dirs = 1; + break; + + case 'f': + /* Same as enabling -a -U and disabling -l -s. */ + all_files = 1; + really_all_files = 1; + sort_type = sort_none; + sort_type_specified = 1; + /* disable -l */ + if (format == long_format) + format = (isatty (STDOUT_FILENO) ? many_per_line : one_per_line); + print_block_size = 0; /* disable -s */ + print_with_color = 0; /* disable --color */ + break; + + case 'g': + /* No effect. For BSD compatibility. */ + break; + + case 'h': + output_block_size = -1024; + break; + + case 'H': + error (0, 0, + _("\ +Warning: the meaning of `-H' will change in the future to conform to POSIX.\n\ +Use `--si' for the old meaning.")); + /* Fall through. */ + case SI_OPTION: + output_block_size = -1000; + break; + + case 'i': + print_inode = 1; + break; + + case 'k': + output_block_size = 1024; + break; + + case 'l': + format = long_format; + break; + + case 'm': + format = with_commas; + break; + + case 'n': + numeric_ids = 1; + break; + + case 'o': /* Just like -l, but don't display group info. */ + format = long_format; + inhibit_group = 1; + break; + + case 'p': + indicator_style = file_type; + break; + + case 'q': + qmark_funny_chars = 1; + break; + + case 'r': + sort_reverse = 1; + break; + + case 's': + print_block_size = 1; + break; + + case 't': + sort_type = sort_time; + sort_type_specified = 1; + break; + + case 'u': + time_type = time_atime; + break; + + case 'v': + sort_type = sort_version; + sort_type_specified = 1; + break; + + case 'w': + if (xstrtol (optarg, NULL, 0, &tmp_long, NULL) != LONGINT_OK + || tmp_long <= 0 || tmp_long > INT_MAX) + error (EXIT_FAILURE, 0, _("invalid line width: %s"), + quotearg (optarg)); + line_length = (int) tmp_long; + break; + + case 'x': + format = horizontal; + break; + + case 'A': + really_all_files = 0; + all_files = 1; + break; + + case 'B': + add_ignore_pattern ("*~"); + add_ignore_pattern (".*~"); + break; + + case 'C': + format = many_per_line; + break; + + case 'D': + dired = 1; + break; + + case 'F': + indicator_style = classify; + break; + + case 'G': /* inhibit display of group info */ + inhibit_group = 1; + break; + + case 'I': + add_ignore_pattern (optarg); + break; + + case 'L': + trace_links = 1; + break; + + case 'N': + set_quoting_style (NULL, literal_quoting_style); + break; + + case 'Q': + set_quoting_style (NULL, c_quoting_style); + break; + + case 'R': + trace_dirs = 1; + break; + + case 'S': + sort_type = sort_size; + sort_type_specified = 1; + break; + + case 'T': + if (xstrtol (optarg, NULL, 0, &tmp_long, NULL) != LONGINT_OK + || tmp_long < 0 || tmp_long > INT_MAX) + error (EXIT_FAILURE, 0, _("invalid tab size: %s"), + quotearg (optarg)); + tabsize = (int) tmp_long; + break; + + case 'U': + sort_type = sort_none; + sort_type_specified = 1; + break; + + case 'X': + sort_type = sort_extension; + sort_type_specified = 1; + break; + + case '1': + /* -1 has no effect after -l. */ + if (format != long_format) + format = one_per_line; + break; + + case SORT_OPTION: + sort_type = XARGMATCH ("--sort", optarg, sort_args, sort_types); + sort_type_specified = 1; + break; + + case TIME_OPTION: + time_type = XARGMATCH ("--time", optarg, time_args, time_types); + break; + + case FORMAT_OPTION: + format = XARGMATCH ("--format", optarg, format_args, format_types); + break; + + case FULL_TIME_OPTION: + format = long_format; + full_time = 1; + break; + + case COLOR_OPTION: + if (optarg) + i = XARGMATCH ("--color", optarg, color_args, color_types); + else + /* Using --color with no argument is equivalent to using + --color=always. */ + i = color_always; + + print_with_color = (i == color_always + || (i == color_if_tty + && isatty (STDOUT_FILENO))); + + if (print_with_color) + { + /* Don't use TAB characters in output. Some terminal + emulators can't handle the combination of tabs and + color codes on the same line. */ + tabsize = 0; + } + break; + + case INDICATOR_STYLE_OPTION: + indicator_style = XARGMATCH ("--indicator-style", optarg, + indicator_style_args, + indicator_style_types); + break; + + case QUOTING_STYLE_OPTION: + set_quoting_style (NULL, + XARGMATCH ("--quoting-style", optarg, + quoting_style_args, + quoting_style_vals)); + break; + + case SHOW_CONTROL_CHARS_OPTION: + qmark_funny_chars = 0; + break; + + case BLOCK_SIZE_OPTION: + human_block_size (optarg, 1, &output_block_size); + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (EXIT_FAILURE); + } + } + + filename_quoting_options = clone_quoting_options (NULL); + if (get_quoting_style (filename_quoting_options) == escape_quoting_style) + set_char_quoting (filename_quoting_options, ' ', 1); + if (indicator_style != none) + for (p = "*=@|" + (int) indicator_style - 1; *p; p++) + set_char_quoting (filename_quoting_options, *p, 1); + + dirname_quoting_options = clone_quoting_options (NULL); + set_char_quoting (dirname_quoting_options, ':', 1); + + /* If -c or -u is specified and not -l (or any other option that implies -l), + and no sort-type was specified, then sort by the ctime (-c) or atime (-u). + The behavior of ls when using either -c or -u but with neither -l nor -t + appears to be unspecified by POSIX. So, with GNU ls, `-u' alone means + sort by atime (this is the one that's not specified by the POSIX spec), + -lu means show atime and sort by name, -lut means show atime and sort + by atime. */ + + if ((time_type == time_ctime || time_type == time_atime) + && !sort_type_specified && format != long_format) + { + sort_type = sort_time; + } + + if (format == long_format) + { + if (full_time) + long_time_format[0] = long_time_format[1] = + dcgettext (NULL, "%a %b %d %H:%M:%S %Y", LC_TIME); + else + { + long_time_format[0] = dcgettext (NULL, "%b %e %Y", LC_TIME); + long_time_format[1] = dcgettext (NULL, "%b %e %H:%M", LC_TIME); + } + } + + return optind; +} + +/* Parse a string as part of the LS_COLORS variable; this may involve + decoding all kinds of escape characters. If equals_end is set an + unescaped equal sign ends the string, otherwise only a : or \0 + does. Returns the number of characters output, or -1 on failure. + + The resulting string is *not* null-terminated, but may contain + embedded nulls. + + Note that both dest and src are char **; on return they point to + the first free byte after the array and the character that ended + the input string, respectively. */ + +static int +get_funky_string (char **dest, const char **src, int equals_end) +{ + int num; /* For numerical codes */ + int count; /* Something to count with */ + enum { + ST_GND, ST_BACKSLASH, ST_OCTAL, ST_HEX, ST_CARET, ST_END, ST_ERROR + } state; + const char *p; + char *q; + + p = *src; /* We don't want to double-indirect */ + q = *dest; /* the whole darn time. */ + + count = 0; /* No characters counted in yet. */ + num = 0; + + state = ST_GND; /* Start in ground state. */ + while (state < ST_END) + { + switch (state) + { + case ST_GND: /* Ground state (no escapes) */ + switch (*p) + { + case ':': + case '\0': + state = ST_END; /* End of string */ + break; + case '\\': + state = ST_BACKSLASH; /* Backslash scape sequence */ + ++p; + break; + case '^': + state = ST_CARET; /* Caret escape */ + ++p; + break; + case '=': + if (equals_end) + { + state = ST_END; /* End */ + break; + } + /* else fall through */ + default: + *(q++) = *(p++); + ++count; + break; + } + break; + + case ST_BACKSLASH: /* Backslash escaped character */ + switch (*p) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + state = ST_OCTAL; /* Octal sequence */ + num = *p - '0'; + break; + case 'x': + case 'X': + state = ST_HEX; /* Hex sequence */ + num = 0; + break; + case 'a': /* Bell */ + num = 7; /* Not all C compilers know what \a means */ + break; + case 'b': /* Backspace */ + num = '\b'; + break; + case 'e': /* Escape */ + num = 27; + break; + case 'f': /* Form feed */ + num = '\f'; + break; + case 'n': /* Newline */ + num = '\n'; + break; + case 'r': /* Carriage return */ + num = '\r'; + break; + case 't': /* Tab */ + num = '\t'; + break; + case 'v': /* Vtab */ + num = '\v'; + break; + case '?': /* Delete */ + num = 127; + break; + case '_': /* Space */ + num = ' '; + break; + case '\0': /* End of string */ + state = ST_ERROR; /* Error! */ + break; + default: /* Escaped character like \ ^ : = */ + num = *p; + break; + } + if (state == ST_BACKSLASH) + { + *(q++) = num; + ++count; + state = ST_GND; + } + ++p; + break; + + case ST_OCTAL: /* Octal sequence */ + if (*p < '0' || *p > '7') + { + *(q++) = num; + ++count; + state = ST_GND; + } + else + num = (num << 3) + (*(p++) - '0'); + break; + + case ST_HEX: /* Hex sequence */ + switch (*p) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + num = (num << 4) + (*(p++) - '0'); + break; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + num = (num << 4) + (*(p++) - 'a') + 10; + break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + num = (num << 4) + (*(p++) - 'A') + 10; + break; + default: + *(q++) = num; + ++count; + state = ST_GND; + break; + } + break; + + case ST_CARET: /* Caret escape */ + state = ST_GND; /* Should be the next state... */ + if (*p >= '@' && *p <= '~') + { + *(q++) = *(p++) & 037; + ++count; + } + else if (*p == '?') + { + *(q++) = 127; + ++count; + } + else + state = ST_ERROR; + break; + + default: + abort (); + } + } + + *dest = q; + *src = p; + + return state == ST_ERROR ? -1 : count; +} + +static void +parse_ls_color (void) +{ + const char *p; /* Pointer to character being parsed */ + char *buf; /* color_buf buffer pointer */ + int state; /* State of parser */ + int ind_no; /* Indicator number */ + char label[3]; /* Indicator label */ + struct color_ext_type *ext; /* Extension we are working on */ + + if ((p = getenv ("LS_COLORS")) == NULL || *p == '\0') + return; + + ext = NULL; + strcpy (label, "??"); + + /* This is an overly conservative estimate, but any possible + LS_COLORS string will *not* generate a color_buf longer than + itself, so it is a safe way of allocating a buffer in + advance. */ + buf = color_buf = xstrdup (p); + + state = 1; + while (state > 0) + { + switch (state) + { + case 1: /* First label character */ + switch (*p) + { + case ':': + ++p; + break; + + case '*': + /* Allocate new extension block and add to head of + linked list (this way a later definition will + override an earlier one, which can be useful for + having terminal-specific defs override global). */ + + ext = (struct color_ext_type *) + xmalloc (sizeof (struct color_ext_type)); + ext->next = color_ext_list; + color_ext_list = ext; + + ++p; + ext->ext.string = buf; + + state = (ext->ext.len = + get_funky_string (&buf, &p, 1)) < 0 ? -1 : 4; + break; + + case '\0': + state = 0; /* Done! */ + break; + + default: /* Assume it is file type label */ + label[0] = *(p++); + state = 2; + break; + } + break; + + case 2: /* Second label character */ + if (*p) + { + label[1] = *(p++); + state = 3; + } + else + state = -1; /* Error */ + break; + + case 3: /* Equal sign after indicator label */ + state = -1; /* Assume failure... */ + if (*(p++) == '=')/* It *should* be... */ + { + for (ind_no = 0; indicator_name[ind_no] != NULL; ++ind_no) + { + if (STREQ (label, indicator_name[ind_no])) + { + color_indicator[ind_no].string = buf; + state = ((color_indicator[ind_no].len = + get_funky_string (&buf, &p, 0)) < 0 ? -1 : 1); + break; + } + } + if (state == -1) + error (0, 0, _("unrecognized prefix: %s"), quotearg (label)); + } + break; + + case 4: /* Equal sign after *.ext */ + if (*(p++) == '=') + { + ext->seq.string = buf; + state = (ext->seq.len = + get_funky_string (&buf, &p, 0)) < 0 ? -1 : 1; + } + else + state = -1; + break; + } + } + + if (state < 0) + { + struct color_ext_type *e; + struct color_ext_type *e2; + + error (0, 0, + _("unparsable value for LS_COLORS environment variable")); + free (color_buf); + for (e = color_ext_list; e != NULL; /* empty */) + { + e2 = e; + e = e->next; + free (e2); + } + print_with_color = 0; + } + + if (color_indicator[C_LINK].len == 6 + && !strncmp (color_indicator[C_LINK].string, "target", 6)) + color_symlink_as_referent = 1; +} + +/* Request that the directory named `name' have its contents listed later. + If `realname' is nonzero, it will be used instead of `name' when the + directory name is printed. This allows symbolic links to directories + to be treated as regular directories but still be listed under their + real names. */ + +static void +queue_directory (const char *name, const char *realname) +{ + struct pending *new; + + new = (struct pending *) xmalloc (sizeof (struct pending)); + new->next = pending_dirs; + pending_dirs = new; + new->name = xstrdup (name); + if (realname) + new->realname = xstrdup (realname); + else + new->realname = 0; +} + +/* Read directory `name', and list the files in it. + If `realname' is nonzero, print its name instead of `name'; + this is used for symbolic links to directories. */ + +static void +print_dir (const char *name, const char *realname) +{ + register DIR *reading; + register struct dirent *next; + register uintmax_t total_blocks = 0; + + errno = 0; + reading = opendir (name); + if (!reading) + { + error (0, errno, "%s", quotearg_colon (name)); + exit_status = 1; + return; + } + + /* Read the directory entries, and insert the subfiles into the `files' + table. */ + + clear_files (); + + while ((next = readdir (reading)) != NULL) + if (file_interesting (next)) + { + enum filetype type = unknown; + +#if HAVE_STRUCT_DIRENT_D_TYPE + if (next->d_type == DT_DIR || next->d_type == DT_CHR + || next->d_type == DT_BLK || next->d_type == DT_SOCK + || next->d_type == DT_FIFO) + type = next->d_type; +#endif + total_blocks += gobble_file (next->d_name, type, 0, name); + } + + if (CLOSEDIR (reading)) + { + error (0, errno, "%s", quotearg_colon (name)); + exit_status = 1; + /* Don't return; print whatever we got. */ + } + + /* Sort the directory contents. */ + sort_files (); + + /* If any member files are subdirectories, perhaps they should have their + contents listed rather than being mentioned here as files. */ + + if (trace_dirs) + extract_dirs_from_files (name, 1); + + if (trace_dirs || print_dir_name) + { + DIRED_INDENT (); + PUSH_CURRENT_DIRED_POS (&subdired_obstack); + dired_pos += quote_name (stdout, realname ? realname : name, + dirname_quoting_options); + PUSH_CURRENT_DIRED_POS (&subdired_obstack); + DIRED_FPUTS_LITERAL (":\n", stdout); + } + + if (format == long_format || print_block_size) + { + const char *p; + char buf[LONGEST_HUMAN_READABLE + 1]; + + DIRED_INDENT (); + p = _("total"); + DIRED_FPUTS (p, stdout, strlen (p)); + DIRED_PUTCHAR (' '); + p = human_readable_inexact (total_blocks, buf, ST_NBLOCKSIZE, + output_block_size, human_ceiling); + DIRED_FPUTS (p, stdout, strlen (p)); + DIRED_PUTCHAR ('\n'); + } + + if (files_index) + print_current_files (); + + if (pending_dirs) + DIRED_PUTCHAR ('\n'); +} + +/* Add `pattern' to the list of patterns for which files that match are + not listed. */ + +static void +add_ignore_pattern (const char *pattern) +{ + register struct ignore_pattern *ignore; + + ignore = (struct ignore_pattern *) xmalloc (sizeof (struct ignore_pattern)); + ignore->pattern = pattern; + /* Add it to the head of the linked list. */ + ignore->next = ignore_patterns; + ignore_patterns = ignore; +} + +/* Return nonzero if the file in `next' should be listed. */ + +static int +file_interesting (const struct dirent *next) +{ + register struct ignore_pattern *ignore; + + for (ignore = ignore_patterns; ignore; ignore = ignore->next) + if (fnmatch (ignore->pattern, next->d_name, FNM_PERIOD) == 0) + return 0; + + if (really_all_files + || next->d_name[0] != '.' + || (all_files + && next->d_name[1] != '\0' + && (next->d_name[1] != '.' || next->d_name[2] != '\0'))) + return 1; + + return 0; +} + +/* Enter and remove entries in the table `files'. */ + +/* Empty the table of files. */ + +static void +clear_files (void) +{ + register int i; + + for (i = 0; i < files_index; i++) + { + free (files[i].name); + if (files[i].linkname) + free (files[i].linkname); + } + + files_index = 0; + block_size_size = 4; +} + +/* Add a file to the current table of files. + Verify that the file exists, and print an error message if it does not. + Return the number of blocks that the file occupies. */ + +static uintmax_t +gobble_file (const char *name, enum filetype type, int explicit_arg, + const char *dirname) +{ + register uintmax_t blocks; + register char *path; + + if (files_index == nfiles) + { + nfiles *= 2; + files = (struct fileinfo *) xrealloc ((char *) files, + sizeof (*files) * nfiles); + } + + files[files_index].linkname = 0; + files[files_index].linkmode = 0; + files[files_index].linkok = 0; + + /* FIXME: this use of ls: `mkdir a; touch a/{b,c,d}; ls -R a' + shouldn't require that ls stat b, c, and d -- at least + not on systems with usable d_type. The problem is that + format_needs_stat is set, because of the -R. */ + if (explicit_arg || format_needs_stat + || (format_needs_type && type == unknown)) + { + /* `path' is the absolute pathname of this file. */ + int val; + + if (name[0] == '/' || dirname[0] == 0) + path = (char *) name; + else + { + path = (char *) alloca (strlen (name) + strlen (dirname) + 2); + attach (path, dirname, name); + } + + val = (trace_links + ? stat (path, &files[files_index].stat) + : lstat (path, &files[files_index].stat)); + + if (val < 0) + { + error (0, errno, "%s", quotearg_colon (path)); + exit_status = 1; + return 0; + } + +#if USE_ACL + if (format == long_format) + files[files_index].have_acl = + (! S_ISLNK (files[files_index].stat.st_mode) + && 4 < acl (path, GETACLCNT, 0, NULL)); +#endif + + if (S_ISLNK (files[files_index].stat.st_mode) + && (explicit_arg || format == long_format || check_symlink_color)) + { + char *linkpath; + struct stat linkstats; + + get_link_name (path, &files[files_index]); + linkpath = make_link_path (path, files[files_index].linkname); + + /* Avoid following symbolic links when possible, ie, when + they won't be traced and when no indicator is needed. */ + if (linkpath + && ((explicit_arg && format != long_format) + || indicator_style != none + || check_symlink_color) + && stat (linkpath, &linkstats) == 0) + { + files[files_index].linkok = 1; + + /* Symbolic links to directories that are mentioned on the + command line are automatically traced if not being + listed as files. */ + if (explicit_arg && format != long_format + && S_ISDIR (linkstats.st_mode)) + { + /* Substitute the linked-to directory's name, but + save the real name in `linkname' for printing. */ + if (!immediate_dirs) + { + const char *tempname = name; + name = linkpath; + linkpath = files[files_index].linkname; + files[files_index].linkname = (char *) tempname; + } + files[files_index].stat = linkstats; + } + else + { + /* Get the linked-to file's mode for the filetype indicator + in long listings. */ + files[files_index].linkmode = linkstats.st_mode; + files[files_index].linkok = 1; + } + } + if (linkpath) + free (linkpath); + } + + if (S_ISLNK (files[files_index].stat.st_mode)) + files[files_index].filetype = symbolic_link; + else if (S_ISDIR (files[files_index].stat.st_mode)) + { + if (explicit_arg && !immediate_dirs) + files[files_index].filetype = arg_directory; + else + files[files_index].filetype = directory; + } + else + files[files_index].filetype = normal; + + blocks = ST_NBLOCKS (files[files_index].stat); + { + char buf[LONGEST_HUMAN_READABLE + 1]; + int len = strlen (human_readable_inexact (blocks, buf, ST_NBLOCKSIZE, + output_block_size, + human_ceiling)); + if (block_size_size < len) + block_size_size = len < 7 ? len : 7; + } + } + else + { + files[files_index].filetype = type; +#if HAVE_STRUCT_DIRENT_D_TYPE + files[files_index].stat.st_mode = DTTOIF (type); +#endif + blocks = 0; + } + + files[files_index].name = xstrdup (name); + files_index++; + + return blocks; +} + +#if HAVE_SYMLINKS + +/* Put the name of the file that `filename' is a symbolic link to + into the `linkname' field of `f'. */ + +static void +get_link_name (const char *filename, struct fileinfo *f) +{ + char *linkbuf; + register int linksize; + + linkbuf = (char *) alloca (PATH_MAX + 2); + /* Some automounters give incorrect st_size for mount points. + I can't think of a good workaround for it, though. */ + linksize = readlink (filename, linkbuf, PATH_MAX + 1); + if (linksize < 0) + { + error (0, errno, "%s", quotearg_colon (filename)); + exit_status = 1; + } + else + { + linkbuf[linksize] = '\0'; + f->linkname = xstrdup (linkbuf); + } +} + +/* If `linkname' is a relative path and `path' contains one or more + leading directories, return `linkname' with those directories + prepended; otherwise, return a copy of `linkname'. + If `linkname' is zero, return zero. */ + +static char * +make_link_path (const char *path, const char *linkname) +{ + char *linkbuf; + int bufsiz; + + if (linkname == 0) + return 0; + + if (*linkname == '/') + return xstrdup (linkname); + + /* The link is to a relative path. Prepend any leading path + in `path' to the link name. */ + linkbuf = strrchr (path, '/'); + if (linkbuf == 0) + return xstrdup (linkname); + + bufsiz = linkbuf - path + 1; + linkbuf = xmalloc (bufsiz + strlen (linkname) + 1); + strncpy (linkbuf, path, bufsiz); + strcpy (linkbuf + bufsiz, linkname); + return linkbuf; +} +#endif + +/* Return nonzero if base_name (NAME) ends in `.' or `..' + This is so we don't try to recurse on `././././. ...' */ + +static int +basename_is_dot_or_dotdot (const char *name) +{ + char *base = base_name (name); + return DOT_OR_DOTDOT (base); +} + +/* Remove any entries from `files' that are for directories, + and queue them to be listed as directories instead. + `dirname' is the prefix to prepend to each dirname + to make it correct relative to ls's working dir. + `recursive' is nonzero if we should not treat `.' and `..' as dirs. + This is desirable when processing directories recursively. */ + +static void +extract_dirs_from_files (const char *dirname, int recursive) +{ + register int i, j; + + /* Queue the directories last one first, because queueing reverses the + order. */ + for (i = files_index - 1; i >= 0; i--) + if ((files[i].filetype == directory || files[i].filetype == arg_directory) + && (!recursive || !basename_is_dot_or_dotdot (files[i].name))) + { + if (files[i].name[0] == '/' || dirname[0] == 0) + { + queue_directory (files[i].name, files[i].linkname); + } + else + { + char *path = path_concat (dirname, files[i].name, NULL); + queue_directory (path, files[i].linkname); + free (path); + } + if (files[i].filetype == arg_directory) + free (files[i].name); + } + + /* Now delete the directories from the table, compacting all the remaining + entries. */ + + for (i = 0, j = 0; i < files_index; i++) + if (files[i].filetype != arg_directory) + files[j++] = files[i]; + files_index = j; +} + +/* Sort the files now in the table. */ + +static void +sort_files (void) +{ + int (*func) (); + + switch (sort_type) + { + case sort_none: + return; + case sort_time: + switch (time_type) + { + case time_ctime: + func = sort_reverse ? rev_cmp_ctime : compare_ctime; + break; + case time_mtime: + func = sort_reverse ? rev_cmp_mtime : compare_mtime; + break; + case time_atime: + func = sort_reverse ? rev_cmp_atime : compare_atime; + break; + default: + abort (); + } + break; + case sort_name: + func = sort_reverse ? rev_cmp_name : compare_name; + break; + case sort_extension: + func = sort_reverse ? rev_cmp_extension : compare_extension; + break; + case sort_size: + func = sort_reverse ? rev_cmp_size : compare_size; + break; + case sort_version: + func = sort_reverse ? rev_cmp_version : compare_version; + break; + default: + abort (); + } + + qsort (files, files_index, sizeof (struct fileinfo), func); +} + +/* Comparison routines for sorting the files. */ + +static int +compare_ctime (const struct fileinfo *file1, const struct fileinfo *file2) +{ + int diff = CTIME_CMP (file2->stat, file1->stat); + if (diff == 0) + diff = strcoll (file1->name, file2->name); + return diff; +} + +static int +rev_cmp_ctime (const struct fileinfo *file2, const struct fileinfo *file1) +{ + int diff = CTIME_CMP (file2->stat, file1->stat); + if (diff == 0) + diff = strcoll (file1->name, file2->name); + return diff; +} + +static int +compare_mtime (const struct fileinfo *file1, const struct fileinfo *file2) +{ + int diff = MTIME_CMP (file2->stat, file1->stat); + if (diff == 0) + diff = strcoll (file1->name, file2->name); + return diff; +} + +static int +rev_cmp_mtime (const struct fileinfo *file2, const struct fileinfo *file1) +{ + int diff = MTIME_CMP (file2->stat, file1->stat); + if (diff == 0) + diff = strcoll (file1->name, file2->name); + return diff; +} + +static int +compare_atime (const struct fileinfo *file1, const struct fileinfo *file2) +{ + int diff = ATIME_CMP (file2->stat, file1->stat); + if (diff == 0) + diff = strcoll (file1->name, file2->name); + return diff; +} + +static int +rev_cmp_atime (const struct fileinfo *file2, const struct fileinfo *file1) +{ + int diff = ATIME_CMP (file2->stat, file1->stat); + if (diff == 0) + diff = strcoll (file1->name, file2->name); + return diff; +} + +static int +compare_size (const struct fileinfo *file1, const struct fileinfo *file2) +{ + int diff = longdiff (file2->stat.st_size, file1->stat.st_size); + if (diff == 0) + diff = strcoll (file1->name, file2->name); + return diff; +} + +static int +rev_cmp_size (const struct fileinfo *file2, const struct fileinfo *file1) +{ + int diff = longdiff (file2->stat.st_size, file1->stat.st_size); + if (diff == 0) + diff = strcoll (file1->name, file2->name); + return diff; +} + +static int +compare_version (const struct fileinfo *file1, const struct fileinfo *file2) +{ + return strverscmp (file1->name, file2->name); +} + +static int +rev_cmp_version (const struct fileinfo *file2, const struct fileinfo *file1) +{ + return strverscmp (file1->name, file2->name); +} + +static int +compare_name (const struct fileinfo *file1, const struct fileinfo *file2) +{ + return strcoll (file1->name, file2->name); +} + +static int +rev_cmp_name (const struct fileinfo *file2, const struct fileinfo *file1) +{ + return strcoll (file1->name, file2->name); +} + +/* Compare file extensions. Files with no extension are `smallest'. + If extensions are the same, compare by filenames instead. */ + +static int +compare_extension (const struct fileinfo *file1, const struct fileinfo *file2) +{ + register char *base1, *base2; + register int cmp; + + base1 = strrchr (file1->name, '.'); + base2 = strrchr (file2->name, '.'); + if (base1 == 0 && base2 == 0) + return strcoll (file1->name, file2->name); + if (base1 == 0) + return -1; + if (base2 == 0) + return 1; + cmp = strcoll (base1, base2); + if (cmp == 0) + return strcoll (file1->name, file2->name); + return cmp; +} + +static int +rev_cmp_extension (const struct fileinfo *file2, const struct fileinfo *file1) +{ + register char *base1, *base2; + register int cmp; + + base1 = strrchr (file1->name, '.'); + base2 = strrchr (file2->name, '.'); + if (base1 == 0 && base2 == 0) + return strcoll (file1->name, file2->name); + if (base1 == 0) + return -1; + if (base2 == 0) + return 1; + cmp = strcoll (base1, base2); + if (cmp == 0) + return strcoll (file1->name, file2->name); + return cmp; +} + +/* List all the files now in the table. */ + +static void +print_current_files (void) +{ + register int i; + + switch (format) + { + case one_per_line: + for (i = 0; i < files_index; i++) + { + print_file_name_and_frills (files + i); + putchar ('\n'); + } + break; + + case many_per_line: + init_column_info (); + print_many_per_line (); + break; + + case horizontal: + init_column_info (); + print_horizontal (); + break; + + case with_commas: + print_with_commas (); + break; + + case long_format: + for (i = 0; i < files_index; i++) + { + print_long_format (files + i); + DIRED_PUTCHAR ('\n'); + } + break; + } +} + +/* Return the expected number of columns in a long-format time stamp, + or zero if it cannot be calculated. */ + +static int +long_time_expected_width (void) +{ + static int width = -1; + + if (width < 0) + { + time_t epoch = 0; + struct tm const *tm = localtime (&epoch); + char const *fmt = long_time_format[0]; + char initbuf[100]; + char *buf = initbuf; + size_t bufsize = sizeof initbuf; + size_t len; + + for (;;) + { + *buf = '\1'; + len = strftime (buf, bufsize, fmt, tm); + if (len || ! *buf) + break; + buf = alloca (bufsize *= 2); + } + + width = mbsnwidth (buf, len, 0); + if (width < 0) + width = 0; + } + + return width; +} + +/* Get the current time. */ + +static void +get_current_time (void) +{ +#if HAVE_CLOCK_GETTIME && defined CLOCK_REALTIME + { + struct timespec timespec; + if (clock_gettime (CLOCK_REALTIME, ×pec) == 0) + { + current_time = timespec.tv_sec; + current_time_ns = timespec.tv_nsec; + return; + } + } +#endif + + /* The clock does not have nanosecond resolution, so get the maximum + possible value for the current time that is consistent with the + reported clock. That way, files are not considered to be in the + future merely because their time stamps have higher resolution + than the clock resolution. */ + +#if HAVE_GETTIMEOFDAY + { + struct timeval timeval; + if (gettimeofday (&timeval, NULL) == 0) + { + current_time = timeval.tv_sec; + current_time_ns = timeval.tv_usec * 1000 + 999; + return; + } + } +#endif + + current_time = time (NULL); + current_time_ns = 999999999; +} + +static void +print_long_format (const struct fileinfo *f) +{ + char modebuf[12]; + + /* 7 fields that may require LONGEST_HUMAN_READABLE bytes, + 1 10-byte mode string, + 1 24-byte time string (may be longer in some locales -- see below) + or LONGEST_HUMAN_READABLE integer, + 9 spaces, one following each of these fields, and + 1 trailing NUL byte. */ + char init_bigbuf[7 * LONGEST_HUMAN_READABLE + 10 + + (LONGEST_HUMAN_READABLE < 24 ? 24 : LONGEST_HUMAN_READABLE) + + 9 + 1]; + char *buf = init_bigbuf; + size_t bufsize = sizeof (init_bigbuf); + size_t s; + char *p; + time_t when; + int when_ns IF_LINT (= 0); + struct tm *when_local; + char *user_name; + +#if HAVE_ST_DM_MODE + /* Cray DMF: look at the file's migrated, not real, status */ + mode_string (f->stat.st_dm_mode, modebuf); +#else + mode_string (f->stat.st_mode, modebuf); +#endif + + modebuf[10] = (FILE_HAS_ACL (f) ? '+' : ' '); + modebuf[11] = '\0'; + + switch (time_type) + { + case time_ctime: + when = f->stat.st_ctime; + when_ns = TIMESPEC_NS (f->stat.st_ctim); + break; + case time_mtime: + when = f->stat.st_mtime; + when_ns = TIMESPEC_NS (f->stat.st_mtim); + break; + case time_atime: + when = f->stat.st_atime; + when_ns = TIMESPEC_NS (f->stat.st_atim); + break; + } + + p = buf; + + if (print_inode) + { + char hbuf[LONGEST_HUMAN_READABLE + 1]; + sprintf (p, "%*s ", INODE_DIGITS, + human_readable ((uintmax_t) f->stat.st_ino, hbuf, 1, 1)); + p += strlen (p); + } + + if (print_block_size) + { + char hbuf[LONGEST_HUMAN_READABLE + 1]; + sprintf (p, "%*s ", block_size_size, + human_readable_inexact ((uintmax_t) ST_NBLOCKS (f->stat), hbuf, + ST_NBLOCKSIZE, output_block_size, + human_ceiling)); + p += strlen (p); + } + + /* The last byte of the mode string is the POSIX + "optional alternate access method flag". */ + sprintf (p, "%s %3u ", modebuf, (unsigned int) f->stat.st_nlink); + p += strlen (p); + + user_name = (numeric_ids ? NULL : getuser (f->stat.st_uid)); + if (user_name) + sprintf (p, "%-8.8s ", user_name); + else + sprintf (p, "%-8u ", (unsigned int) f->stat.st_uid); + p += strlen (p); + + if (!inhibit_group) + { + char *group_name = (numeric_ids ? NULL : getgroup (f->stat.st_gid)); + if (group_name) + sprintf (p, "%-8.8s ", group_name); + else + sprintf (p, "%-8u ", (unsigned int) f->stat.st_gid); + p += strlen (p); + } + + if (S_ISCHR (f->stat.st_mode) || S_ISBLK (f->stat.st_mode)) + sprintf (p, "%3u, %3u ", (unsigned) major (f->stat.st_rdev), + (unsigned) minor (f->stat.st_rdev)); + else + { + char hbuf[LONGEST_HUMAN_READABLE + 1]; + sprintf (p, "%8s ", + human_readable ((uintmax_t) f->stat.st_size, hbuf, 1, + output_block_size < 0 ? output_block_size : 1)); + } + + p += strlen (p); + + if ((when_local = localtime (&when))) + { + time_t six_months_ago; + int recent; + char const *fmt; + + /* If the file appears to be in the future, update the current + time, in case the file happens to have been modified since + the last time we checked the clock. */ + if (current_time < when + || (current_time == when && current_time_ns < when_ns)) + get_current_time (); + + /* Consider a time to be recent if it is within the past six + months. A Gregorian year has 365.2425 * 24 * 60 * 60 == + 31556952 seconds on the average. Write this value as an + integer constant to avoid floating point hassles. */ + six_months_ago = current_time - 31556952 / 2; + recent = (six_months_ago <= when + && (when < current_time + || (when == current_time && when_ns <= current_time_ns))); + fmt = long_time_format[recent]; + + for (;;) + { + char *newbuf; + *p = '\1'; + s = strftime (p, buf + bufsize - p - 1, fmt, when_local); + if (s || ! *p) + break; + newbuf = alloca (bufsize *= 2); + memcpy (newbuf, buf, p - buf); + p = newbuf + (p - buf); + buf = newbuf; + } + + p += s; + *p++ = ' '; + + /* NUL-terminate the string -- fputs (via DIRED_FPUTS) requires it. */ + *p = '\0'; + } + else + { + /* The time cannot be represented as a local time; + print it as a huge integer number of seconds. */ + char hbuf[LONGEST_HUMAN_READABLE + 1]; + int width = long_time_expected_width (); + + if (when < 0) + { + const char *num = human_readable (- (uintmax_t) when, hbuf, 1, 1); + int sign_width = width - strlen (num); + sprintf (p, "%*s%s ", sign_width < 0 ? 0 : sign_width, "-", num); + } + else + sprintf (p, "%*s ", width, + human_readable ((uintmax_t) when, hbuf, 1, 1)); + + p += strlen (p); + } + + DIRED_INDENT (); + DIRED_FPUTS (buf, stdout, p - buf); + print_name_with_quoting (f->name, FILE_OR_LINK_MODE (f), f->linkok, + &dired_obstack); + + if (f->filetype == symbolic_link) + { + if (f->linkname) + { + DIRED_FPUTS_LITERAL (" -> ", stdout); + print_name_with_quoting (f->linkname, f->linkmode, f->linkok - 1, + NULL); + if (indicator_style != none) + print_type_indicator (f->linkmode); + } + } + else if (indicator_style != none) + print_type_indicator (f->stat.st_mode); +} + +/* Output to OUT a quoted representation of the file name NAME, + using OPTIONS to control quoting. Produce no output if OUT is NULL. + Return the number of screen columns occupied by NAME's quoted + representation. */ + +static size_t +quote_name (FILE *out, const char *name, struct quoting_options const *options) +{ + char smallbuf[BUFSIZ]; + size_t len = quotearg_buffer (smallbuf, sizeof smallbuf, name, -1, options); + char *buf; + int displayed_width; + + if (len < sizeof smallbuf) + buf = smallbuf; + else + { + buf = (char *) alloca (len + 1); + quotearg_buffer (buf, len + 1, name, -1, options); + } + + if (qmark_funny_chars) + { +#if HAVE_MBRTOWC + if (MB_CUR_MAX > 1) + { + const char *p = buf; + char *plimit = buf + len; + char *q = buf; + displayed_width = 0; + + while (p < plimit) + switch (*p) + { + case ' ': case '!': case '"': case '#': case '%': + case '&': case '\'': case '(': case ')': case '*': + case '+': case ',': case '-': case '.': case '/': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case ':': case ';': case '<': case '=': case '>': + case '?': + case 'A': case 'B': case 'C': case 'D': case 'E': + case 'F': case 'G': case 'H': case 'I': case 'J': + case 'K': case 'L': case 'M': case 'N': case 'O': + case 'P': case 'Q': case 'R': case 'S': case 'T': + case 'U': case 'V': case 'W': case 'X': case 'Y': + case 'Z': + case '[': case '\\': case ']': case '^': case '_': + case 'a': case 'b': case 'c': case 'd': case 'e': + case 'f': case 'g': case 'h': case 'i': case 'j': + case 'k': case 'l': case 'm': case 'n': case 'o': + case 'p': case 'q': case 'r': case 's': case 't': + case 'u': case 'v': case 'w': case 'x': case 'y': + case 'z': case '{': case '|': case '}': case '~': + /* These characters are printable ASCII characters. */ + *q++ = *p++; + displayed_width += 1; + break; + default: + /* If we have a multibyte sequence, copy it until we + reach its end, replacing each non-printable multibyte + character with a single question mark. */ + { + mbstate_t mbstate; + memset (&mbstate, 0, sizeof mbstate); + do + { + wchar_t wc; + size_t bytes; + int w; + + bytes = mbrtowc (&wc, p, plimit - p, &mbstate); + + if (bytes == (size_t) -1) + { + /* An invalid multibyte sequence was + encountered. Skip one input byte, and + put a question mark. */ + p++; + *q++ = '?'; + displayed_width += 1; + break; + } + + if (bytes == (size_t) -2) + { + /* An incomplete multibyte character + at the end. Replace it entirely with + a question mark. */ + p = plimit; + *q++ = '?'; + displayed_width += 1; + break; + } + + if (bytes == 0) + /* A null wide character was encountered. */ + bytes = 1; + + w = wcwidth (wc); + if (w >= 0) + { + /* A printable multibyte character. + Keep it. */ + for (; bytes > 0; --bytes) + *q++ = *p++; + displayed_width += w; + } + else + { + /* An unprintable multibyte character. + Replace it entirely with a question + mark. */ + p += bytes; + *q++ = '?'; + displayed_width += 1; + } + } + while (! mbsinit (&mbstate)); + } + break; + } + + /* The buffer may have shrunk. */ + len = q - buf; + } + else +#endif + { + char *p = buf; + char *plimit = buf + len; + + while (p < plimit) + { + if (! ISPRINT ((unsigned char) *p)) + *p = '?'; + p++; + } + displayed_width = len; + } + } + else + { + /* Assume unprintable characters have a displayed_width of 1. */ +#if HAVE_MBRTOWC + if (MB_CUR_MAX > 1) + displayed_width = mbsnwidth (buf, len, + (MBSW_ACCEPT_INVALID + | MBSW_ACCEPT_UNPRINTABLE)); + else +#endif + displayed_width = len; + } + + if (out != NULL) + fwrite (buf, 1, len, out); + return displayed_width; +} + +static void +print_name_with_quoting (const char *p, unsigned int mode, int linkok, + struct obstack *stack) +{ + if (print_with_color) + print_color_indicator (p, mode, linkok); + + if (stack) + PUSH_CURRENT_DIRED_POS (stack); + + dired_pos += quote_name (stdout, p, filename_quoting_options); + + if (stack) + PUSH_CURRENT_DIRED_POS (stack); + + if (print_with_color) + prep_non_filename_text (); +} + +static void +prep_non_filename_text (void) +{ + if (color_indicator[C_END].string != NULL) + put_indicator (&color_indicator[C_END]); + else + { + put_indicator (&color_indicator[C_LEFT]); + put_indicator (&color_indicator[C_NORM]); + put_indicator (&color_indicator[C_RIGHT]); + } +} + +/* Print the file name of `f' with appropriate quoting. + Also print file size, inode number, and filetype indicator character, + as requested by switches. */ + +static void +print_file_name_and_frills (const struct fileinfo *f) +{ + char buf[LONGEST_HUMAN_READABLE + 1]; + + if (print_inode) + printf ("%*s ", INODE_DIGITS, + human_readable ((uintmax_t) f->stat.st_ino, buf, 1, 1)); + + if (print_block_size) + printf ("%*s ", block_size_size, + human_readable_inexact ((uintmax_t) ST_NBLOCKS (f->stat), buf, + ST_NBLOCKSIZE, output_block_size, + human_ceiling)); + + print_name_with_quoting (f->name, FILE_OR_LINK_MODE (f), f->linkok, NULL); + + if (indicator_style != none) + print_type_indicator (f->stat.st_mode); +} + +static void +print_type_indicator (unsigned int mode) +{ + int c; + + if (S_ISREG (mode)) + { + if (indicator_style == classify && (mode & S_IXUGO)) + c ='*'; + else + c = 0; + } + else + { + if (S_ISDIR (mode)) + c = '/'; + else if (S_ISLNK (mode)) + c = '@'; + else if (S_ISFIFO (mode)) + c = '|'; + else if (S_ISSOCK (mode)) + c = '='; + else if (S_ISDOOR (mode)) + c = '>'; + else + c = 0; + } + + if (c) + DIRED_PUTCHAR (c); +} + +static void +print_color_indicator (const char *name, unsigned int mode, int linkok) +{ + int type = C_FILE; + struct color_ext_type *ext; /* Color extension */ + size_t len; /* Length of name */ + + /* Is this a nonexistent file? If so, linkok == -1. */ + + if (linkok == -1 && color_indicator[C_MISSING].string != NULL) + { + ext = NULL; + type = C_MISSING; + } + else + { + if (S_ISDIR (mode)) + type = C_DIR; + else if (S_ISLNK (mode)) + type = ((!linkok && color_indicator[C_ORPHAN].string) + ? C_ORPHAN : C_LINK); + else if (S_ISFIFO (mode)) + type = C_FIFO; + else if (S_ISSOCK (mode)) + type = C_SOCK; + else if (S_ISBLK (mode)) + type = C_BLK; + else if (S_ISCHR (mode)) + type = C_CHR; + else if (S_ISDOOR (mode)) + type = C_DOOR; + + if (type == C_FILE && (mode & S_IXUGO) != 0) + type = C_EXEC; + + /* Check the file's suffix only if still classified as C_FILE. */ + ext = NULL; + if (type == C_FILE) + { + /* Test if NAME has a recognized suffix. */ + + len = strlen (name); + name += len; /* Pointer to final \0. */ + for (ext = color_ext_list; ext != NULL; ext = ext->next) + { + if ((size_t) ext->ext.len <= len + && strncmp (name - ext->ext.len, ext->ext.string, + ext->ext.len) == 0) + break; + } + } + } + + put_indicator (&color_indicator[C_LEFT]); + put_indicator (ext ? &(ext->seq) : &color_indicator[type]); + put_indicator (&color_indicator[C_RIGHT]); +} + +/* Output a color indicator (which may contain nulls). */ +static void +put_indicator (const struct bin_str *ind) +{ + register int i; + register const char *p; + + p = ind->string; + + for (i = ind->len; i > 0; --i) + putchar (*(p++)); +} + +static int +length_of_file_name_and_frills (const struct fileinfo *f) +{ + register int len = 0; + + if (print_inode) + len += INODE_DIGITS + 1; + + if (print_block_size) + len += 1 + block_size_size; + + len += quote_name (NULL, f->name, filename_quoting_options); + + if (indicator_style != none) + { + unsigned filetype = f->stat.st_mode; + + if (S_ISREG (filetype)) + { + if (indicator_style == classify + && (f->stat.st_mode & S_IXUGO)) + len += 1; + } + else if (S_ISDIR (filetype) + || S_ISLNK (filetype) + || S_ISFIFO (filetype) + || S_ISSOCK (filetype) + || S_ISDOOR (filetype) + ) + len += 1; + } + + return len; +} + +static void +print_many_per_line (void) +{ + struct column_info *line_fmt; + int filesno; /* Index into files. */ + int row; /* Current row. */ + int max_name_length; /* Length of longest file name + frills. */ + int name_length; /* Length of each file name + frills. */ + int pos; /* Current character column. */ + int cols; /* Number of files across. */ + int rows; /* Maximum number of files down. */ + int max_cols; + + /* Normally the maximum number of columns is determined by the + screen width. But if few files are available this might limit it + as well. */ + max_cols = max_idx > files_index ? files_index : max_idx; + + /* Compute the maximum number of possible columns. */ + for (filesno = 0; filesno < files_index; ++filesno) + { + int i; + + name_length = length_of_file_name_and_frills (files + filesno); + + for (i = 0; i < max_cols; ++i) + { + if (column_info[i].valid_len) + { + int idx = filesno / ((files_index + i) / (i + 1)); + int real_length = name_length + (idx == i ? 0 : 2); + + if (real_length > column_info[i].col_arr[idx]) + { + column_info[i].line_len += (real_length + - column_info[i].col_arr[idx]); + column_info[i].col_arr[idx] = real_length; + column_info[i].valid_len = column_info[i].line_len < line_length; + } + } + } + } + + /* Find maximum allowed columns. */ + for (cols = max_cols; cols > 1; --cols) + { + if (column_info[cols - 1].valid_len) + break; + } + + line_fmt = &column_info[cols - 1]; + + /* Calculate the number of rows that will be in each column except possibly + for a short column on the right. */ + rows = files_index / cols + (files_index % cols != 0); + + for (row = 0; row < rows; row++) + { + int col = 0; + filesno = row; + pos = 0; + /* Print the next row. */ + while (1) + { + print_file_name_and_frills (files + filesno); + name_length = length_of_file_name_and_frills (files + filesno); + max_name_length = line_fmt->col_arr[col++]; + + filesno += rows; + if (filesno >= files_index) + break; + + indent (pos + name_length, pos + max_name_length); + pos += max_name_length; + } + putchar ('\n'); + } +} + +static void +print_horizontal (void) +{ + struct column_info *line_fmt; + int filesno; + int max_name_length; + int name_length; + int cols; + int pos; + int max_cols; + + /* Normally the maximum number of columns is determined by the + screen width. But if few files are available this might limit it + as well. */ + max_cols = max_idx > files_index ? files_index : max_idx; + + /* Compute the maximum file name length. */ + max_name_length = 0; + for (filesno = 0; filesno < files_index; ++filesno) + { + int i; + + name_length = length_of_file_name_and_frills (files + filesno); + + for (i = 0; i < max_cols; ++i) + { + if (column_info[i].valid_len) + { + int idx = filesno % (i + 1); + int real_length = name_length + (idx == i ? 0 : 2); + + if (real_length > column_info[i].col_arr[idx]) + { + column_info[i].line_len += (real_length + - column_info[i].col_arr[idx]); + column_info[i].col_arr[idx] = real_length; + column_info[i].valid_len = column_info[i].line_len < line_length; + } + } + } + } + + /* Find maximum allowed columns. */ + for (cols = max_cols; cols > 1; --cols) + { + if (column_info[cols - 1].valid_len) + break; + } + + line_fmt = &column_info[cols - 1]; + + pos = 0; + + /* Print first entry. */ + print_file_name_and_frills (files); + name_length = length_of_file_name_and_frills (files); + max_name_length = line_fmt->col_arr[0]; + + /* Now the rest. */ + for (filesno = 1; filesno < files_index; ++filesno) + { + int col = filesno % cols; + + if (col == 0) + { + putchar ('\n'); + pos = 0; + } + else + { + indent (pos + name_length, pos + max_name_length); + pos += max_name_length; + } + + print_file_name_and_frills (files + filesno); + + name_length = length_of_file_name_and_frills (files + filesno); + max_name_length = line_fmt->col_arr[col]; + } + putchar ('\n'); +} + +static void +print_with_commas (void) +{ + int filesno; + int pos, old_pos; + + pos = 0; + + for (filesno = 0; filesno < files_index; filesno++) + { + old_pos = pos; + + pos += length_of_file_name_and_frills (files + filesno); + if (filesno + 1 < files_index) + pos += 2; /* For the comma and space */ + + if (old_pos != 0 && pos >= line_length) + { + putchar ('\n'); + pos -= old_pos; + } + + print_file_name_and_frills (files + filesno); + if (filesno + 1 < files_index) + { + putchar (','); + putchar (' '); + } + } + putchar ('\n'); +} + +/* Assuming cursor is at position FROM, indent up to position TO. + Use a TAB character instead of two or more spaces whenever possible. */ + +static void +indent (int from, int to) +{ + while (from < to) + { + if (tabsize > 0 && to / tabsize > (from + 1) / tabsize) + { + putchar ('\t'); + from += tabsize - from % tabsize; + } + else + { + putchar (' '); + from++; + } + } +} + +/* Put DIRNAME/NAME into DEST, handling `.' and `/' properly. */ +/* FIXME: maybe remove this function someday. See about using a + non-malloc'ing version of path_concat. */ + +static void +attach (char *dest, const char *dirname, const char *name) +{ + const char *dirnamep = dirname; + + /* Copy dirname if it is not ".". */ + if (dirname[0] != '.' || dirname[1] != 0) + { + while (*dirnamep) + *dest++ = *dirnamep++; + /* Add '/' if `dirname' doesn't already end with it. */ + if (dirnamep > dirname && dirnamep[-1] != '/') + *dest++ = '/'; + } + while (*name) + *dest++ = *name++; + *dest = 0; +} + +static void +init_column_info (void) +{ + int i; + int allocate = 0; + + max_idx = line_length / MIN_COLUMN_WIDTH; + if (max_idx == 0) + max_idx = 1; + + if (column_info == NULL) + { + column_info = (struct column_info *) xmalloc (max_idx + * sizeof (struct column_info)); + allocate = 1; + } + + for (i = 0; i < max_idx; ++i) + { + int j; + + column_info[i].valid_len = 1; + column_info[i].line_len = (i + 1) * MIN_COLUMN_WIDTH; + + if (allocate) + column_info[i].col_arr = (int *) xmalloc ((i + 1) * sizeof (int)); + + for (j = 0; j <= i; ++j) + column_info[i].col_arr[j] = MIN_COLUMN_WIDTH; + } +} + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name); + printf (_("\ +List information about the FILEs (the current directory by default).\n\ +Sort entries alphabetically if none of -cftuSUX nor --sort.\n\ +\n\ + -a, --all do not hide entries starting with .\n\ + -A, --almost-all do not list implied . and ..\n\ + -b, --escape print octal escapes for nongraphic characters\n\ + --block-size=SIZE use SIZE-byte blocks\n\ + -B, --ignore-backups do not list implied entries ending with ~\n\ + -c with -lt: sort by, and show, ctime (time of last\n\ + modification of file status information)\n\ + with -l: show ctime and sort by name\n\ + otherwise: sort by ctime\n\ + -C list entries by columns\n\ + --color[=WHEN] control whether color is used to distinguish file\n\ + types. WHEN may be `never', `always', or `auto'\n\ + -d, --directory list directory entries instead of contents\n\ + -D, --dired generate output designed for Emacs' dired mode\n\ + -f do not sort, enable -aU, disable -lst\n\ + -F, --classify append indicator (one of */=@|) to entries\n\ + --format=WORD across -x, commas -m, horizontal -x, long -l,\n\ + single-column -1, verbose -l, vertical -C\n\ + --full-time list both full date and full time\n")); + + printf (_("\ + -g (ignored)\n\ + -G, --no-group inhibit display of group information\n\ + -h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)\n\ + --si likewise, but use powers of 1000 not 1024\n\ + -H same as `--si' for now; soon to change\n\ + to conform to POSIX\n\ + --indicator-style=WORD append indicator with style WORD to entry names:\n\ + none (default), classify (-F), file-type (-p)\n\ + -i, --inode print index number of each file\n\ + -I, --ignore=PATTERN do not list implied entries matching shell PATTERN\n\ + -k, --kilobytes like --block-size=1024\n\ + -l use a long listing format\n\ + -L, --dereference list entries pointed to by symbolic links\n\ + -m fill width with a comma separated list of entries\n\ + -n, --numeric-uid-gid list numeric UIDs and GIDs instead of names\n\ + -N, --literal print raw entry names (don't treat e.g. control\n\ + characters specially)\n\ + -o use long listing format without group info\n\ + -p, --file-type append indicator (one of /=@|) to entries\n\ + -q, --hide-control-chars print ? instead of non graphic characters\n\ + --show-control-chars show non graphic characters as-is (default\n\ + unless program is `ls' and output is a terminal)\n\ + -Q, --quote-name enclose entry names in double quotes\n\ + --quoting-style=WORD use quoting style WORD for entry names:\n\ + literal, locale, shell, shell-always, c, escape\n\ + -r, --reverse reverse order while sorting\n\ + -R, --recursive list subdirectories recursively\n\ + -s, --size print size of each file, in blocks\n")); + + printf (_("\ + -S sort by file size\n\ + --sort=WORD extension -X, none -U, size -S, time -t,\n\ + version -v\n\ + status -c, time -t, atime -u, access -u, use -u\n\ + --time=WORD show time as WORD instead of modification time:\n\ + atime, access, use, ctime or status; use\n\ + specified time as sort key if --sort=time\n\ + -t sort by modification time\n\ + -T, --tabsize=COLS assume tab stops at each COLS instead of 8\n\ + -u with -lt: sort by, and show, access time\n\ + with -l: show access time and sort by name\n\ + otherwise: sort by access time\n\ + -U do not sort; list entries in directory order\n\ + -v sort by version\n\ + -w, --width=COLS assume screen width instead of current value\n\ + -x list entries by lines instead of by columns\n\ + -X sort alphabetically by entry extension\n\ + -1 list one file per line\n\ + --help display this help and exit\n\ + --version output version information and exit\n\ +\n\ +By default, color is not used to distinguish types of files. That is\n\ +equivalent to using --color=none. Using the --color option without the\n\ +optional WHEN argument is equivalent to using --color=always. With\n\ +--color=auto, color codes are output only if standard output is connected\n\ +to a terminal (tty).\n\ +")); + puts (_("\nReport bugs to .")); + } + exit (status); +} diff --git a/src/apps/bin/gnu/ls.h b/src/apps/bin/gnu/ls.h new file mode 100644 index 0000000000..028271f574 --- /dev/null +++ b/src/apps/bin/gnu/ls.h @@ -0,0 +1,10 @@ +/* This is for the `ls' program. */ +#define LS_LS 1 + +/* This is for the `dir' program. */ +#define LS_MULTI_COL 2 + +/* This is for the `vdir' program. */ +#define LS_LONG_FORMAT 3 + +extern int ls_mode; diff --git a/src/apps/bin/gnu/mkdir.c b/src/apps/bin/gnu/mkdir.c new file mode 100644 index 0000000000..419bda75d9 --- /dev/null +++ b/src/apps/bin/gnu/mkdir.c @@ -0,0 +1,205 @@ +/* mkdir -- make directories + Copyright (C) 90, 1995-2001 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* David MacKenzie */ + +#include +#include +#include +#include + +#include "system.h" +#include "dirname.h" +#include "error.h" +#include "makepath.h" +#include "modechange.h" +#include "quote.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "mkdir" + +#define AUTHORS "David MacKenzie" + +void strip_trailing_slashes (); + +/* The name this program was run with. */ +char *program_name; + +/* If nonzero, ensure that all parents of the specified directory exist. */ +static int create_parents; + +static struct option const longopts[] = +{ + {"mode", required_argument, NULL, 'm'}, + {"parents", no_argument, NULL, 'p'}, + {"verbose", no_argument, NULL, 'v'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION] DIRECTORY...\n"), program_name); + printf (_("\ +Create the DIRECTORY(ies), if they do not already exist.\n\ +\n\ + -m, --mode=MODE set permission mode (as in chmod), not rwxrwxrwx - umask\n\ + -p, --parents no error if existing, make parent directories as needed\n\ + -v, --verbose print a message for each created directory\n\ + --help display this help and exit\n\ + --version output version information and exit\n\ +")); + puts (_("\nReport bugs to .")); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + mode_t newmode; + mode_t parent_mode; + const char *specified_mode = NULL; + const char *verbose_fmt_string = NULL; + int errors = 0; + int optc; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + create_parents = 0; + + while ((optc = getopt_long (argc, argv, "pm:v", longopts, NULL)) != -1) + { + switch (optc) + { + case 0: /* Long option. */ + break; + case 'p': + create_parents = 1; + break; + case 'm': + specified_mode = optarg; + break; + case 'v': /* --verbose */ + verbose_fmt_string = _("created directory %s"); + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (1); + } + } + + if (optind == argc) + { + error (0, 0, _("too few arguments")); + usage (1); + } + + newmode = S_IRWXUGO; + { + mode_t umask_value = umask (0); + umask (umask_value); /* Restore the old value. */ + parent_mode = (newmode & (~ umask_value)) | S_IWUSR | S_IXUSR; + } + + if (specified_mode) + { + struct mode_change *change = mode_compile (specified_mode, 0); + newmode &= ~ umask (0); + if (change == MODE_INVALID) + error (1, 0, _("invalid mode %s"), quote (specified_mode)); + else if (change == MODE_MEMORY_EXHAUSTED) + xalloc_die (); + newmode = mode_adjust (newmode, change); + } + + for (; optind < argc; ++optind) + { + int fail = 0; + + /* Remove any trailing slashes. Not removing them would lead to calling + `mkdir ("dir/", mode)' for e.g., the commands `mkdir dir/' and + `mkdir -p dir/', and such a call fails on NetBSD systems when `dir' + doesn't already exist. */ + strip_trailing_slashes (argv[optind]); + + if (create_parents) + { + char *parents = dir_name (argv[optind]); + fail = make_path (parents, parent_mode, parent_mode, + -1, -1, 1, verbose_fmt_string); + free (parents); + } + + if (fail == 0) + { + const char *dir = argv[optind]; + int dir_created; + fail = make_dir (dir, dir, newmode, &dir_created); + if (fail) + { + /* make_dir already gave a diagnostic. */ + } + else if (!create_parents && !dir_created) + { + /* make_dir `succeeds' when DIR already exists. + In that case, mkdir must fail, unless --parents (-p) + was specified. */ + error (0, EEXIST, _("cannot create directory %s"), + quote (dir)); + fail = 1; + } + else if (verbose_fmt_string) + error (0, 0, verbose_fmt_string, quote (dir)); + + /* mkdir(2) is required to honor only the file permission bits. + In particular, it needn't do anything about `special' bits, + so if any were set in newmode, apply them with chmod. + This extra step is necessary in some cases when the containing + directory has a default ACL. */ + + /* Set the permissions only if this directory has just + been created. */ + + if (fail == 0 && specified_mode && dir_created) + { + fail = chmod (dir, newmode); + if (fail) + error (0, errno, _("cannot set permissions of directory %s"), + quote (dir)); + } + } + + if (fail) + errors = 1; + } + + exit (errors); +} diff --git a/src/apps/bin/gnu/mkfifo.c b/src/apps/bin/gnu/mkfifo.c new file mode 100644 index 0000000000..b5ce392aa1 --- /dev/null +++ b/src/apps/bin/gnu/mkfifo.c @@ -0,0 +1,147 @@ +/* mkfifo -- make fifo's (named pipes) + Copyright (C) 90, 91, 1995-2000 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* David MacKenzie */ + +#include +#include +#include +#include + +#include "system.h" +#include "error.h" +#include "modechange.h" +#include "quote.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "mkfifo" + +#define AUTHORS "David MacKenzie" + +/* The name this program was run with. */ +char *program_name; + +static struct option const longopts[] = +{ + {"mode", required_argument, NULL, 'm'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +#ifdef S_ISFIFO +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION] NAME...\n"), program_name); + printf (_("\ +Create named pipes (FIFOs) with the given NAMEs.\n\ +\n\ + -m, --mode=MODE set permission mode (as in chmod), not a=rw - umask\n\ + --help display this help and exit\n\ + --version output version information and exit\n\ +")); + puts (_("\nReport bugs to .")); + } + exit (status); +} +#endif + +int +main (int argc, char **argv) +{ + mode_t newmode; + struct mode_change *change; + const char *specified_mode; + int errors = 0; + int optc; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + specified_mode = NULL; + +#ifndef S_ISFIFO + error (4, 0, _("fifo files not supported")); +#else + while ((optc = getopt_long (argc, argv, "m:", longopts, NULL)) != -1) + { + switch (optc) + { + case 0: + break; + case 'm': + specified_mode = optarg; + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (1); + } + } + + if (optind == argc) + { + error (0, 0, _("too few arguments")); + usage (1); + } + + newmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + if (specified_mode) + { + newmode &= ~ umask (0); + change = mode_compile (specified_mode, 0); + if (change == MODE_INVALID) + error (1, 0, _("invalid mode")); + else if (change == MODE_MEMORY_EXHAUSTED) + xalloc_die (); + newmode = mode_adjust (newmode, change); + } + + for (; optind < argc; ++optind) + { + int fail = mkfifo (argv[optind], newmode); + if (fail) + error (0, errno, _("cannot create fifo `%s'"), quote (argv[optind])); + + /* If the containing directory happens to have a default ACL, chmod + ensures the file mode permission bits are still set as desired. */ + + if (fail == 0 && specified_mode) + { + fail = chmod (argv[optind], newmode); + if (fail) + error (0, errno, _("cannot set permissions of fifo `%s'"), + quote (argv[optind])); + } + + if (fail) + errors = 1; + } + + exit (errors); +#endif +} diff --git a/src/apps/bin/gnu/mknod.c b/src/apps/bin/gnu/mknod.c new file mode 100644 index 0000000000..fac49c9dab --- /dev/null +++ b/src/apps/bin/gnu/mknod.c @@ -0,0 +1,238 @@ +/* mknod -- make special files + Copyright (C) 90, 91, 1995-2000 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Usage: mknod [-m mode] [--mode=mode] path {bcu} major minor + make a block or character device node + mknod [-m mode] [--mode=mode] path p + make a FIFO (named pipe) + + Options: + -m, --mode=mode Set the mode of created nodes to MODE, which is + symbolic as in chmod and uses the umask as a point of + departure. + + David MacKenzie */ + +#include +#include +#include +#include + +#include "system.h" +#include "error.h" +#include "modechange.h" +#include "quote.h" +#include "xstrtol.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "mknod" + +#define AUTHORS "David MacKenzie" + +/* The name this program was run with. */ +char *program_name; + +static struct option const longopts[] = +{ + {"mode", required_argument, NULL, 'm'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]... NAME TYPE [MAJOR MINOR]\n"), program_name); + printf (_("\ +Create the special file NAME of the given TYPE.\n\ +\n\ + -m, --mode=MODE set permission mode (as in chmod), not a=rw - umask\n\ + --help display this help and exit\n\ + --version output version information and exit\n\ +\n\ +MAJOR MINOR are forbidden for TYPE p, mandatory otherwise. TYPE may be:\n\ +\n\ + b create a block (buffered) special file\n\ + c, u create a character (unbuffered) special file\n\ + p create a FIFO\n\ +")); + puts (_("\nReport bugs to .")); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + mode_t newmode; + struct mode_change *change; + const char *specified_mode; + int optc; + int i_major, i_minor; + long int tmp_major, tmp_minor; + char *s; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + specified_mode = NULL; + + while ((optc = getopt_long (argc, argv, "m:", longopts, NULL)) != -1) + { + switch (optc) + { + case 0: + break; + case 'm': + specified_mode = optarg; + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (1); + } + } + + newmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + if (specified_mode) + { + newmode &= ~ umask (0); + change = mode_compile (specified_mode, 0); + if (change == MODE_INVALID) + error (1, 0, _("invalid mode")); + else if (change == MODE_MEMORY_EXHAUSTED) + xalloc_die (); + newmode = mode_adjust (newmode, change); + } + + if (argc - optind != 2 && argc - optind != 4) + { + const char *msg; + if (argc - optind < 2) + msg = _("too few arguments"); + else if (argc - optind > 4) + msg = _("too many arguments"); + else + msg = _("wrong number of arguments"); + error (0, 0, msg); + usage (1); + } + + /* Only check the first character, to allow mnemonic usage like + `mknod /dev/rst0 character 18 0'. */ + + switch (argv[optind + 1][0]) + { + case 'b': /* `block' or `buffered' */ +#ifndef S_IFBLK + error (4, 0, _("block special files not supported")); +#else + if (argc - optind != 4) + { + error (0, 0, _("\ +when creating block special files, major and minor device\n\ +numbers must be specified")); + usage (1); + } + + s = argv[optind + 2]; + if (xstrtol (s, NULL, 0, &tmp_major, NULL) != LONGINT_OK) + error (1, 0, _("invalid major device number %s"), quote (s)); + + s = argv[optind + 3]; + if (xstrtol (s, NULL, 0, &tmp_minor, NULL) != LONGINT_OK) + error (1, 0, _("invalid minor device number %s"), quote (s)); + + i_major = (int) tmp_major; + i_minor = (int) tmp_minor; + + if (mknod (argv[optind], newmode | S_IFBLK, makedev (i_major, i_minor))) + error (1, errno, "%s", quote (argv[optind])); +#endif + break; + + case 'c': /* `character' */ + case 'u': /* `unbuffered' */ +#ifndef S_IFCHR + error (4, 0, _("character special files not supported")); +#else + if (argc - optind != 4) + { + error (0, 0, _("\ +when creating character special files, major and minor device\n\ +numbers must be specified")); + usage (1); + } + + s = argv[optind + 2]; + if (xstrtol (s, NULL, 0, &tmp_major, NULL) != LONGINT_OK) + error (1, 0, _("invalid major device number %s"), quote (s)); + + s = argv[optind + 3]; + if (xstrtol (s, NULL, 0, &tmp_minor, NULL) != LONGINT_OK) + error (1, 0, _("invalid minor device number %s"), quote (s)); + + i_major = (int) tmp_major; + i_minor = (int) tmp_minor; + + if (mknod (argv[optind], newmode | S_IFCHR, makedev (i_major, i_minor))) + error (1, errno, "%s", quote (argv[optind])); +#endif + break; + + case 'p': /* `pipe' */ +#ifndef S_ISFIFO + error (4, 0, _("fifo files not supported")); +#else + if (argc - optind != 2) + { + error (0, 0, _("\ +major and minor device numbers may not be specified for fifo files")); + usage (1); + } + if (mkfifo (argv[optind], newmode)) + error (1, errno, "%s", quote (argv[optind])); +#endif + break; + + default: + usage (1); + } + + /* Perform an explicit chmod to ensure the file mode permission bits + are set as specified. This extra step is necessary in some cases + when the containing directory has a default ACL. */ + + if (specified_mode) + { + if (chmod (argv[optind], newmode)) + error (0, errno, _("cannot set permissions of `%s'"), + quote (argv[optind])); + } + + exit (0); +} diff --git a/src/apps/bin/gnu/mv.c b/src/apps/bin/gnu/mv.c new file mode 100644 index 0000000000..a429558710 --- /dev/null +++ b/src/apps/bin/gnu/mv.c @@ -0,0 +1,495 @@ +/* mv -- move or rename files + Copyright (C) 86, 89, 90, 91, 1995-2001 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Mike Parker, David MacKenzie, and Jim Meyering */ + +#ifdef _AIX + #pragma alloca +#endif + +#include +#include +#include +#include +#include + +#include "system.h" +#include "backupfile.h" +#include "copy.h" +#include "cp-hash.h" +#include "error.h" +#include "path-concat.h" +#include "quote.h" +#include "remove.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "mv" + +#define AUTHORS "Mike Parker, David MacKenzie, and Jim Meyering" + +/* Initial number of entries in each hash table entry's table of inodes. */ +#define INITIAL_HASH_MODULE 100 + +/* Initial number of entries in the inode hash table. */ +#define INITIAL_ENTRY_TAB_SIZE 70 + +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + TARGET_DIRECTORY_OPTION = CHAR_MAX + 1, + STRIP_TRAILING_SLASHES_OPTION +}; + +int euidaccess (); +int full_write (); +int isdir (); +int lstat (); +int yesno (); + +/* The name this program was run with. */ +char *program_name; + +/* Remove any trailing slashes from each SOURCE argument. */ +static int remove_trailing_slashes; + +static struct option const long_options[] = +{ + {"backup", optional_argument, NULL, 'b'}, + {"force", no_argument, NULL, 'f'}, + {"interactive", no_argument, NULL, 'i'}, + {"strip-trailing-slashes", no_argument, NULL, STRIP_TRAILING_SLASHES_OPTION}, + {"suffix", required_argument, NULL, 'S'}, + {"target-directory", required_argument, NULL, TARGET_DIRECTORY_OPTION}, + {"update", no_argument, NULL, 'u'}, + {"verbose", no_argument, NULL, 'v'}, + {"version-control", required_argument, NULL, 'V'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +static void +rm_option_init (struct rm_options *x) +{ + x->unlink_dirs = 0; + + x->ignore_missing_files = 0; + + x->recursive = 1; + + /* Should we prompt for removal, too? No. Prompting for the `move' + part is enough. It implies removal. */ + x->interactive = 0; + x->stdin_tty = 0; + + x->verbose = 0; +} + +static void +cp_option_init (struct cp_options *x) +{ + x->copy_as_regular = 0; /* FIXME: maybe make this an option */ + x->dereference = DEREF_NEVER; + x->unlink_dest_before_opening = 0; + x->unlink_dest_after_failed_open = 0; + x->failed_unlink_is_fatal = 1; + x->hard_link = 0; + x->interactive = 0; + x->move_mode = 1; + x->myeuid = geteuid (); + x->one_file_system = 0; + x->preserve_owner_and_group = 1; + x->preserve_chmod_bits = 1; + x->preserve_timestamps = 1; + x->require_preserve = 0; /* FIXME: maybe make this an option */ + x->recursive = 1; + x->sparse_mode = SPARSE_AUTO; /* FIXME: maybe make this an option */ + x->symbolic_link = 0; + x->set_mode = 0; + x->mode = 0; + + /* Find out the current file creation mask, to knock the right bits + when using chmod. The creation mask is set to be liberal, so + that created directories can be written, even if it would not + have been allowed with the mask this process was started with. */ + x->umask_kill = ~ umask (0); + + x->update = 0; + x->verbose = 0; + x->xstat = lstat; +} + +/* If PATH is an existing directory, return nonzero, else 0. */ + +static int +is_real_dir (const char *path) +{ + struct stat stats; + + return lstat (path, &stats) == 0 && S_ISDIR (stats.st_mode); +} + +static int +strip_trailing_slashes_2 (char *path) +{ + char *end_p = path + strlen (path) - 1; + char *slash = end_p; + + while (slash > path && *slash == '/') + *slash-- = '\0'; + + return slash < end_p; +} + +/* Move SOURCE onto DEST. Handles cross-filesystem moves. + If SOURCE is a directory, DEST must not exist. + Return 0 if successful, non-zero if an error occurred. */ + +static int +do_move (const char *source, const char *dest, const struct cp_options *x) +{ + static int first = 1; + int copy_into_self; + int rename_succeeded; + int fail; + + if (first) + { + first = 0; + + /* Allocate space for remembering copied and created files. */ + hash_init (INITIAL_HASH_MODULE, INITIAL_ENTRY_TAB_SIZE); + } + + fail = copy (source, dest, 0, x, ©_into_self, &rename_succeeded); + + if (!fail) + { + const char *dir_to_remove; + if (copy_into_self) + { + /* In general, when copy returns with copy_into_self set, SOURCE is + the same as, or a parent of DEST. In this case we know it's a + parent. It doesn't make sense to move a directory into itself, and + besides in some situations doing so would give highly nonintuitive + results. Run this `mkdir b; touch a c; mv * b' in an empty + directory. Here's the result of running echo `find b -print`: + b b/a b/b b/b/a b/c. Notice that only file `a' was copied + into b/b. Handle this by giving a diagnostic, removing the + copied-into-self directory, DEST (`b/b' in the example), + and failing. */ + + dir_to_remove = NULL; + fail = 1; + } + else if (rename_succeeded) + { + /* No need to remove anything. SOURCE was successfully + renamed to DEST. */ + dir_to_remove = NULL; + } + else + { + /* This may mean SOURCE and DEST referred to different devices. + It may also conceivably mean that even though they referred + to the same device, rename wasn't implemented for that device. + + E.g., (from Joel N. Weber), + [...] there might someday be cases where you can't rename + but you can copy where the device name is the same, especially + on Hurd. Consider an ftpfs with a primitive ftp server that + supports uploading, downloading and deleting, but not renaming. + + Also, note that comparing device numbers is not a reliable + check for `can-rename'. Some systems can be set up so that + files from many different physical devices all have the same + st_dev field. This is a feature of some NFS mounting + configurations. + + We reach this point if SOURCE has been successfully copied + to DEST. Now we have to remove SOURCE. + + This function used to resort to copying only when rename + failed and set errno to EXDEV. */ + + dir_to_remove = source; + } + + if (dir_to_remove != NULL) + { + struct rm_options rm_options; + struct File_spec fs; + enum RM_status status; + + rm_option_init (&rm_options); + rm_options.verbose = x->verbose; + + remove_init (); + + fspec_init_file (&fs, dir_to_remove); + + /* Remove any trailing slashes. This is necessary if we + took the else branch of movefile. */ + strip_trailing_slashes_2 (fs.filename); + + status = rm (&fs, 1, &rm_options); + assert (VALID_STATUS (status)); + if (status == RM_ERROR) + fail = 1; + + remove_fini (); + + if (fail) + error (0, errno, _("cannot remove %s"), quote (dir_to_remove)); + } + } + + return fail; +} + +/* Move file SOURCE onto DEST. Handles the case when DEST is a directory. + DEST_IS_DIR must be nonzero when DEST is a directory or a symlink to a + directory and zero otherwise. + Return 0 if successful, non-zero if an error occurred. */ + +static int +movefile (char *source, char *dest, int dest_is_dir, + const struct cp_options *x) +{ + int dest_had_trailing_slash = strip_trailing_slashes_2 (dest); + int fail; + + /* This code was introduced to handle the ambiguity in the semantics + of mv that is induced by the varying semantics of the rename function. + Some systems (e.g., Linux) have a rename function that honors a + trailing slash, while others (like Solaris 5,6,7) have a rename + function that ignores a trailing slash. I believe the Linux + rename semantics are POSIX and susv2 compliant. */ + + if (remove_trailing_slashes) + strip_trailing_slashes_2 (source); + + /* In addition to when DEST is a directory, if DEST has a trailing + slash and neither SOURCE nor DEST is a directory, presume the target + is DEST/`basename source`. This converts `mv x y/' to `mv x y/x'. + This change means that the command `mv any file/' will now fail + rather than performing the move. The case when SOURCE is a + directory and DEST is not is properly diagnosed by do_move. */ + + if (dest_is_dir || (dest_had_trailing_slash && !is_real_dir (source))) + { + /* DEST is a directory; build full target filename. */ + char *src_basename; + char *new_dest; + + /* Remove trailing slashes before taking base_name. + Otherwise, base_name ("a/") returns "". */ + strip_trailing_slashes_2 (source); + + src_basename = base_name (source); + new_dest = path_concat (dest, src_basename, NULL); + if (new_dest == NULL) + xalloc_die (); + fail = do_move (source, new_dest, x); + + /* Do not free new_dest. It may have been squirreled away by + the remember_copied function. */ + } + else + { + fail = do_move (source, dest, x); + } + + return fail; +} + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... SOURCE DEST\n\ + or: %s [OPTION]... SOURCE... DIRECTORY\n\ + or: %s [OPTION]... --target-directory=DIRECTORY SOURCE...\n\ +"), + program_name, program_name, program_name); + printf (_("\ +Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.\n\ +\n\ + --backup[=CONTROL] make a backup of each existing destination file\n\ + -b like --backup but does not accept an argument\n\ + -f, --force never prompt before overwriting\n\ + -i, --interactive prompt before overwrite\n\ + --strip-trailing-slashes remove any trailing slashes from each SOURCE\n\ + argument\n\ + -S, --suffix=SUFFIX override the usual backup suffix\n\ + --target-directory=DIRECTORY move all SOURCE arguments into DIRECTORY\n\ + -u, --update move only older or brand new non-directories\n\ + -v, --verbose explain what is being done\n\ + --help display this help and exit\n\ + --version output version information and exit\n\ +\n\ +")); + printf (_("\ +The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\ +The version control method may be selected via the --backup option or through\n\ +the VERSION_CONTROL environment variable. Here are the values:\n\ +\n\ + none, off never make backups (even if --backup is given)\n\ + numbered, t make numbered backups\n\ + existing, nil numbered if numbered backups exist, simple otherwise\n\ + simple, never always make simple backups\n\ +")); + puts (_("\nReport bugs to .")); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + int c; + int errors; + int make_backups = 0; + int dest_is_dir; + char *backup_suffix_string; + char *version_control_string = NULL; + struct cp_options x; + char *target_directory = NULL; + int target_directory_specified; + unsigned int n_files; + char **file; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + cp_option_init (&x); + + /* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless + we'll actually use backup_suffix_string. */ + backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); + + errors = 0; + + while ((c = getopt_long (argc, argv, "bfiuvS:V:", long_options, NULL)) != -1) + { + switch (c) + { + case 0: + break; + + case 'V': /* FIXME: this is deprecated. Remove it in 2001. */ + error (0, 0, + _("warning: --version-control (-V) is obsolete; support for\ + it\nwill be removed in some future release. Use --backup=%s instead." + ), optarg); + /* Fall through. */ + + case 'b': + make_backups = 1; + if (optarg) + version_control_string = optarg; + break; + case 'f': + x.interactive = 0; + break; + case 'i': + x.interactive = 1; + break; + case STRIP_TRAILING_SLASHES_OPTION: + remove_trailing_slashes = 1; + break; + case TARGET_DIRECTORY_OPTION: + target_directory = optarg; + break; + case 'u': + x.update = 1; + break; + case 'v': + x.verbose = 1; + break; + case 'S': + make_backups = 1; + backup_suffix_string = optarg; + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (1); + } + } + + n_files = argc - optind; + file = argv + optind; + + target_directory_specified = (target_directory != NULL); + if (target_directory == NULL && n_files != 0) + target_directory = file[n_files - 1]; + + dest_is_dir = (n_files > 0 && isdir (target_directory)); + + if (n_files == 0 || (n_files == 1 && !target_directory_specified)) + { + error (0, 0, _("missing file argument")); + usage (1); + } + + if (target_directory_specified) + { + if (!dest_is_dir) + { + error (0, 0, _("specified target, %s is not a directory"), + quote (target_directory)); + usage (1); + } + } + else if (n_files > 2 && !dest_is_dir) + { + error (0, 0, + _("when moving multiple files, last argument must be a directory")); + usage (1); + } + + if (backup_suffix_string) + simple_backup_suffix = xstrdup (backup_suffix_string); + + x.backup_type = (make_backups + ? xget_version (_("backup type"), + version_control_string) + : none); + + /* Move each arg but the last into the target_directory. */ + { + unsigned int last_file_idx = (target_directory_specified + ? n_files - 1 + : n_files - 2); + unsigned int i; + for (i = 0; i <= last_file_idx; ++i) + errors |= movefile (file[i], target_directory, dest_is_dir, &x); + } + + exit (errors); +} diff --git a/src/apps/bin/gnu/remove.c b/src/apps/bin/gnu/remove.c new file mode 100644 index 0000000000..0536893e7f --- /dev/null +++ b/src/apps/bin/gnu/remove.c @@ -0,0 +1,946 @@ +/* remove.c -- core functions for removing files and directories + Copyright (C) 88, 90, 91, 1994-2001 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Extracted from rm.c and librarified by Jim Meyering. */ + +#ifdef _AIX + #pragma alloca +#endif + +#include +#include +#include +#include + +#if HAVE_STDBOOL_H +# include +#else +typedef enum {false = 0, true = 1} bool; +#endif + +#include "save-cwd.h" +#include "system.h" +#include "error.h" +#include "obstack.h" +#include "hash.h" +#include "quote.h" +#include "remove.h" + +#define obstack_chunk_alloc malloc +#define obstack_chunk_free free + +#ifndef PARAMS +# if defined (__GNUC__) || __STDC__ +# define PARAMS(args) args +# else +# define PARAMS(args) () +# endif +#endif + +/* On systems with an lstat function that accepts the empty string, + arrange to make lstat calls go through the wrapper function. */ +#if HAVE_LSTAT_EMPTY_STRING_BUG +int rpl_lstat PARAMS((const char *, struct stat *)); +# define lstat(Name, Stat_buf) rpl_lstat(Name, Stat_buf) +#endif + +#ifdef D_INO_IN_DIRENT +# define D_INO(dp) ((dp)->d_ino) +# define ENABLE_CYCLE_CHECK +#else +/* Some systems don't have inodes, so fake them to avoid lots of ifdefs. */ +# define D_INO(dp) 1 +#endif + +#if !defined S_ISLNK +# define S_ISLNK(Mode) 0 +#endif + +/* Initial capacity of per-directory hash table of entries that have + been processed but not been deleted. */ +#define HT_INITIAL_CAPACITY 13 + +/* Initial capacity of the active directory hash table. This table will + be resized only for hierarchies more than about 45 levels deep. */ +#define ACTIVE_DIR_INITIAL_CAPACITY 53 + +int euidaccess (); +int yesno (); + +extern char *program_name; + +/* state initialized by remove_init, freed by remove_fini */ + +/* An entry in the active_dir_map. */ +struct active_dir_ent +{ + ino_t st_ino; + dev_t st_dev; + unsigned int depth; +}; + +/* The name of the directory (starting with and relative to a command + line argument) being processed. When a subdirectory is entered, a new + component is appended (pushed). When RM chdir's out of a directory, + the top component is removed (popped). This is used to form a full + file name when necessary. */ +static struct obstack dir_stack; + +/* Stack of lengths of directory names (including trailing slash) + appended to dir_stack. We have to have a separate stack of lengths + (rather than just popping back to previous slash) because the first + element pushed onto the dir stack may contain slashes. */ +static struct obstack len_stack; + +/* Set of `active' directories from the current command-line argument + to the level in the hierarchy at which files are being removed. + A directory is added to the active set when RM begins removing it + (or its entries), and it is removed from the set just after RM has + finished processing it. + + This is actually a map (not a set), implemented with a hash table. + For each active directory, it maps the directory's inode number to the + depth of that directory relative to the root of the tree being deleted. + A directory specified on the command line has depth zero. + This construct is used to detect directory cycles so that RM can warn + about them rather than iterating endlessly. */ +#ifdef ENABLE_CYCLE_CHECK +static struct hash_table *active_dir_map; +#endif + +static inline unsigned int +current_depth (void) +{ + return obstack_object_size (&len_stack) / sizeof (size_t); +} + +static void +print_nth_dir (FILE *stream, unsigned int depth) +{ + size_t *length = (size_t *) obstack_base (&len_stack); + char *dir_name = (char *) obstack_base (&dir_stack); + unsigned int sum = 0; + unsigned int i; + + assert (depth < current_depth ()); + + for (i = 0; i <= depth; i++) + { + sum += length[i]; + } + + fwrite (dir_name, 1, sum - 1, stream); +} + +static inline struct active_dir_ent * +make_active_dir_ent (ino_t inum, dev_t device, unsigned int depth) +{ + struct active_dir_ent *ent; + ent = (struct active_dir_ent *) xmalloc (sizeof *ent); + ent->st_ino = inum; + ent->st_dev = device; + ent->depth = depth; + return ent; +} + +static unsigned int +hash_active_dir_ent (void const *x, unsigned int table_size) +{ + struct active_dir_ent const *ade = x; + + /* Ignoring the device number here should be fine. */ + return ade->st_ino % table_size; +} + +static bool +hash_compare_active_dir_ents (void const *x, void const *y) +{ + struct active_dir_ent const *a = x; + struct active_dir_ent const *b = y; + return SAME_INODE (*a, *b) ? true : false; +} + +/* A hash function for null-terminated char* strings using + the method described in Aho, Sethi, & Ullman, p 436. */ + +static unsigned int +hash_pjw (const void *x, unsigned int tablesize) +{ + const char *s = x; + unsigned int h = 0; + unsigned int g; + + while (*s != 0) + { + h = (h << 4) + *s++; + if ((g = h & (unsigned int) 0xf0000000) != 0) + h = (h ^ (g >> 24)) ^ g; + } + + return (h % tablesize); +} + +static bool +hash_compare_strings (void const *x, void const *y) +{ + return STREQ (x, y) ? true : false; +} + +static inline void +push_dir (const char *dir_name) +{ + size_t len; + + len = strlen (dir_name); + + /* Append the string onto the stack. */ + obstack_grow (&dir_stack, dir_name, len); + + /* Append a trailing slash. */ + obstack_1grow (&dir_stack, '/'); + + /* Add one for the slash. */ + ++len; + + /* Push the length (including slash) onto its stack. */ + obstack_grow (&len_stack, &len, sizeof (len)); +} + +static inline void +pop_dir (void) +{ + int n_lengths = obstack_object_size (&len_stack) / sizeof (size_t); + size_t *length = (size_t *) obstack_base (&len_stack); + size_t top_len; + + assert (n_lengths > 0); + top_len = length[n_lengths - 1]; + assert (top_len >= 2); + + /* Pop off the specified length of pathname. */ + assert (obstack_object_size (&dir_stack) >= top_len); + obstack_blank (&dir_stack, -top_len); + + /* Pop the length stack, too. */ + assert (obstack_object_size (&len_stack) >= sizeof (size_t)); + obstack_blank (&len_stack, (int) -(sizeof (size_t))); +} + +/* Copy the SRC_LEN bytes of data beginning at SRC into the DST_LEN-byte + buffer, DST, so that the last source byte is at the end of the destination + buffer. If SRC_LEN is longer than DST_LEN, then set *TRUNCATED to non-zero. + Set *RESULT to point to the beginning of (the portion of) the source data + in DST. Return the number of bytes remaining in the destination buffer. */ + +static size_t +right_justify (char *dst, size_t dst_len, const char *src, size_t src_len, + char **result, int *truncated) +{ + const char *sp; + char *dp; + + if (src_len <= dst_len) + { + sp = src; + dp = dst + (dst_len - src_len); + *truncated = 0; + } + else + { + sp = src + (src_len - dst_len); + dp = dst; + src_len = dst_len; + *truncated = 1; + } + + *result = memcpy (dp, sp, src_len); + return dst_len - src_len; +} + +/* Using the global directory name obstack, create the full path to FILENAME. + Return it in sometimes-realloc'd space that should not be freed by the + caller. Realloc as necessary. If realloc fails, use a static buffer + and put as long a suffix in that buffer as possible. */ + +static char * +full_filename (const char *filename) +{ + static char *buf = NULL; + static size_t n_allocated = 0; + + int dir_len = obstack_object_size (&dir_stack); + char *dir_name = (char *) obstack_base (&dir_stack); + size_t n_bytes_needed; + size_t filename_len; + + filename_len = strlen (filename); + n_bytes_needed = dir_len + filename_len + 1; + + if (n_bytes_needed > n_allocated) + { + /* This code requires that realloc accept NULL as the first arg. + This function must not use xrealloc. Otherwise, an out-of-memory + error involving a file name to be expanded here wouldn't ever + be issued. Use realloc and fall back on using a static buffer + if memory allocation fails. */ + buf = realloc (buf, n_bytes_needed); + n_allocated = n_bytes_needed; + + if (buf == NULL) + { +#define SBUF_SIZE 512 +#define ELLIPSES_PREFIX "[...]" + static char static_buf[SBUF_SIZE]; + int truncated; + size_t len; + char *p; + + len = right_justify (static_buf, SBUF_SIZE, filename, + filename_len + 1, &p, &truncated); + right_justify (static_buf, len, dir_name, dir_len, &p, &truncated); + if (truncated) + { + memcpy (static_buf, ELLIPSES_PREFIX, + sizeof (ELLIPSES_PREFIX) - 1); + } + return p; + } + } + + /* Copy directory part, including trailing slash, and then + append the filename part, including a trailing zero byte. */ + memcpy (mempcpy (buf, dir_name, dir_len), filename, filename_len + 1); + + assert (strlen (buf) + 1 == n_bytes_needed); + + return buf; +} + +static inline void +fspec_init_common (struct File_spec *fs) +{ + fs->have_full_mode = 0; + fs->have_filetype_mode = 0; + fs->have_device = 0; +} + +void +fspec_init_file (struct File_spec *fs, const char *filename) +{ + fs->filename = (char *) filename; + fspec_init_common (fs); +} + +static inline void +fspec_init_dp (struct File_spec *fs, struct dirent *dp) +{ + fs->filename = dp->d_name; + fspec_init_common (fs); + fs->st_ino = D_INO (dp); + +#if D_TYPE_IN_DIRENT && defined DT_UNKNOWN && defined DTTOIF + if (dp->d_type != DT_UNKNOWN) + { + fs->have_filetype_mode = 1; + fs->mode = DTTOIF (dp->d_type); + } +#endif +} + +static inline int +fspec_get_full_mode (struct File_spec *fs) +{ + struct stat stat_buf; + + if (fs->have_full_mode) + return 0; + + if (lstat (fs->filename, &stat_buf)) + return 1; + + fs->have_full_mode = 1; + fs->have_filetype_mode = 1; + fs->mode = stat_buf.st_mode; + fs->st_ino = stat_buf.st_ino; + fs->have_device = 1; + fs->st_dev = stat_buf.st_dev; + + return 0; +} + +static inline int +fspec_get_device_number (struct File_spec *fs) +{ + struct stat stat_buf; + + if (fs->have_device) + return 0; + + if (lstat (fs->filename, &stat_buf)) + return 1; + + fs->have_full_mode = 1; + fs->have_filetype_mode = 1; + fs->mode = stat_buf.st_mode; + fs->st_ino = stat_buf.st_ino; + fs->have_device = 1; + fs->st_dev = stat_buf.st_dev; + + return 0; +} + +static inline int +fspec_get_filetype_mode (struct File_spec *fs, mode_t *filetype_mode) +{ + int fail; + + fail = fs->have_filetype_mode ? 0 : fspec_get_full_mode (fs); + if (!fail) + *filetype_mode = fs->mode; + + return fail; +} + +static inline mode_t +fspec_filetype_mode (const struct File_spec *fs) +{ + assert (fs->have_filetype_mode); + return fs->mode; +} + +static int +same_file (const char *file_1, const char *file_2) +{ + struct stat sb1, sb2; + return (lstat (file_1, &sb1) == 0 + && lstat (file_2, &sb2) == 0 + && SAME_INODE (sb1, sb2)); +} + + +/* Recursively remove all of the entries in the current directory. + Return an indication of the success of the operation. */ + +static enum RM_status +remove_cwd_entries (const struct rm_options *x) +{ + /* NOTE: this is static. */ + static DIR *dirp = NULL; + + /* NULL or a malloc'd and initialized hash table of entries in the + current directory that have been processed but not removed -- + due either to an error or to an interactive `no' response. */ + struct hash_table *ht = NULL; + + /* FIXME: describe */ + static struct obstack entry_name_pool; + static int first_call = 1; + + enum RM_status status = RM_OK; + + if (first_call) + { + first_call = 0; + obstack_init (&entry_name_pool); + } + + if (dirp) + { + if (CLOSEDIR (dirp)) + { + /* FIXME-someday: but this is actually the previously opened dir. */ + error (0, errno, "%s", quote (full_filename ("."))); + status = RM_ERROR; + } + dirp = NULL; + } + + do + { + /* FIXME: why do this? */ + errno = 0; + + dirp = opendir ("."); + if (dirp == NULL) + { + if (errno != ENOENT || !x->ignore_missing_files) + { + error (0, errno, _("cannot open directory %s"), + quote (full_filename ("."))); + status = RM_ERROR; + } + break; + } + + while (1) + { + char *entry_name; + struct File_spec fs; + enum RM_status tmp_status; + struct dirent *dp; + +/* FILE should be skipped if it is `.' or `..', or if it is in + the table, HT, of entries we've already processed. */ +#define SKIPPABLE(Ht, File) \ + (DOT_OR_DOTDOT(File) || (Ht && hash_lookup (Ht, File))) + + /* FIXME: use readdir_r directly into an obstack to avoid + the obstack_copy0 below -- + Suggestion from Uli. Be careful -- there are different + prototypes on e.g. Solaris. + + Do something like this: + #define NAME_MAX_FOR(Parent_dir) pathconf ((Parent_dir), + _PC_NAME_MAX); + dp = obstack_alloc (sizeof (struct dirent) + + NAME_MAX_FOR (".") + 1); + fail = xreaddir (dirp, dp); + where xreaddir is ... + + But what about systems like the hurd where NAME_MAX is supposed + to be effectively unlimited. We don't want to have to allocate + a huge buffer to accommodate maximum possible entry name. */ + + dp = readdir (dirp); + +#if ! HAVE_WORKING_READDIR + if (dp == NULL) + { + /* Since we have probably modified the directory since it + was opened, readdir returning NULL does not necessarily + mean we have read the last entry. Rewind it and check + again. This happens on SunOS4.1.4 with 254 or more files + in a directory. */ + rewinddir (dirp); + while ((dp = readdir (dirp)) && SKIPPABLE (ht, dp->d_name)) + { + /* empty */ + } + } +#endif + + if (dp == NULL) + break; + + if (SKIPPABLE (ht, dp->d_name)) + continue; + + fspec_init_dp (&fs, dp); + + /* Save a copy of the name of this entry, in case we have + to add it to the set of unremoved entries below. */ + entry_name = obstack_copy0 (&entry_name_pool, + dp->d_name, NLENGTH (dp)); + + /* CAUTION: after this call to rm, DP may not be valid -- + it may have been freed due to a close in a recursive call + (through rm and remove_dir) to this function. */ + tmp_status = rm (&fs, 0, x); + + /* Update status. */ + if (tmp_status > status) + status = tmp_status; + assert (VALID_STATUS (status)); + + /* If this entry was not removed (due either to an error or to + an interactive `no' response), record it in the hash table so + we don't consider it again if we reopen this directory later. */ + if (status != RM_OK) + { + if (ht == NULL) + { + ht = hash_initialize (HT_INITIAL_CAPACITY, NULL, hash_pjw, + hash_compare_strings, NULL); + if (ht == NULL) + xalloc_die (); + } + if (! hash_insert (ht, entry_name)) + xalloc_die (); + } + else + { + /* This entry was not saved in the hash table. Free it. */ + obstack_free (&entry_name_pool, entry_name); + } + + if (dirp == NULL) + break; + } + } + while (dirp == NULL); + + if (dirp) + { + if (CLOSEDIR (dirp)) + { + error (0, errno, _("closing directory %s"), + quote (full_filename ("."))); + status = RM_ERROR; + } + dirp = NULL; + } + + if (ht) + { + hash_free (ht); + } + + if (obstack_object_size (&entry_name_pool) > 0) + obstack_free (&entry_name_pool, obstack_base (&entry_name_pool)); + + return status; +} + +/* Query the user if appropriate, and if ok try to remove the + file or directory specified by FS. Return RM_OK if it is removed, + and RM_ERROR or RM_USER_DECLINED if not. */ + +static enum RM_status +remove_file (struct File_spec *fs, const struct rm_options *x) +{ + int asked = 0; + char *pathname = fs->filename; + + if (!x->ignore_missing_files && (x->interactive || x->stdin_tty) + && euidaccess (pathname, W_OK)) + { + if (!S_ISLNK (fspec_filetype_mode (fs))) + { + fprintf (stderr, + (S_ISDIR (fspec_filetype_mode (fs)) + ? _("%s: remove write-protected directory %s? ") + : _("%s: remove write-protected file %s? ")), + program_name, quote (full_filename (pathname))); + if (!yesno ()) + return RM_USER_DECLINED; + + asked = 1; + } + } + + if (!asked && x->interactive) + { + /* FIXME: use a variant of error (instead of fprintf) that doesn't + append a newline. Then we won't have to declare program_name in + this file. */ + fprintf (stderr, + (S_ISDIR (fspec_filetype_mode (fs)) + ? _("%s: remove directory %s? ") + : _("%s: remove %s? ")), + program_name, quote (full_filename (pathname))); + if (!yesno ()) + return RM_USER_DECLINED; + } + + if (x->verbose) + printf (_("removing %s\n"), quote (full_filename (pathname))); + + if (unlink (pathname) && (errno != ENOENT || !x->ignore_missing_files)) + { + error (0, errno, _("cannot unlink %s"), quote (full_filename (pathname))); + return RM_ERROR; + } + return RM_OK; +} + +/* If not in recursive mode, print an error message and return RM_ERROR. + Otherwise, query the user if appropriate, then try to recursively + remove the directory specified by FS. Return RM_OK if it is removed, + and RM_ERROR or RM_USER_DECLINED if not. + FIXME: describe need_save_cwd parameter. */ + +static enum RM_status +remove_dir (struct File_spec *fs, int need_save_cwd, const struct rm_options *x) +{ + enum RM_status status; + struct saved_cwd cwd; + char *dir_name = fs->filename; + const char *fmt = NULL; + + if (!x->recursive) + { + error (0, 0, _("%s is a directory"), quote (full_filename (dir_name))); + return RM_ERROR; + } + + if (!x->ignore_missing_files && (x->interactive || x->stdin_tty) + && euidaccess (dir_name, W_OK)) + { + fmt = _("%s: directory %s is write protected; descend into it anyway? "); + } + else if (x->interactive) + { + fmt = _("%s: descend into directory %s? "); + } + + if (fmt) + { + fprintf (stderr, fmt, program_name, quote (full_filename (dir_name))); + if (!yesno ()) + return RM_USER_DECLINED; + } + + if (x->verbose) + printf (_("removing all entries of directory %s\n"), + quote (full_filename (dir_name))); + + /* Save cwd if needed. */ + if (need_save_cwd && save_cwd (&cwd)) + return RM_ERROR; + + /* Make target directory the current one. */ + if (chdir (dir_name) < 0) + { + error (0, errno, _("cannot change to directory %s"), + quote (full_filename (dir_name))); + if (need_save_cwd) + free_cwd (&cwd); + return RM_ERROR; + } + + /* Verify that the device and inode numbers of `.' are the same as + the ones we recorded for dir_name before we cd'd into it. This + detects the scenario in which an attacker tries to make Bob's rm + command remove some other directory belonging to Bob. The method + would be to replace an existing lstat'd but-not-yet-removed directory + with a symlink to the target directory. */ + { + struct stat sb; + if (lstat (".", &sb)) + error (EXIT_FAILURE, errno, + _("cannot lstat `.' in %s"), quote (full_filename (dir_name))); + + assert (fs->have_device); + if (!SAME_INODE (sb, *fs)) + { + error (EXIT_FAILURE, 0, + _("ERROR: the directory %s initially had device/inode\n\ +numbers %lu/%lu, but now (after a chdir into it), the numbers for `.'\n\ +are %lu/%lu. That means that while rm was running, the directory\n\ +was replaced with either another directory or a link to another directory."), + quote (full_filename (dir_name)), + (unsigned long)(fs->st_dev), + (unsigned long)(fs->st_ino), + (unsigned long)(sb.st_dev), + (unsigned long)(sb.st_ino)); + } + } + + push_dir (dir_name); + + /* Save a copy of dir_name. Otherwise, remove_cwd_entries may clobber + it because it is just a pointer to the dir entry's d_name field, and + remove_cwd_entries may close the directory. */ + ASSIGN_STRDUPA (dir_name, dir_name); + + status = remove_cwd_entries (x); + + pop_dir (); + + /* Restore cwd. */ + if (need_save_cwd) + { + if (restore_cwd (&cwd, NULL, NULL)) + { + free_cwd (&cwd); + return RM_ERROR; + } + free_cwd (&cwd); + } + else if (chdir ("..") < 0) + { + error (0, errno, _("cannot change back to directory %s via `..'"), + quote (full_filename (dir_name))); + return RM_ERROR; + } + + if (x->interactive) + { + fprintf (stderr, _("%s: remove directory %s%s? "), + program_name, + quote (full_filename (dir_name)), + (status != RM_OK ? _(" (might be nonempty)") : "")); + if (!yesno ()) + { + return RM_USER_DECLINED; + } + } + + if (x->verbose) + printf (_("removing the directory itself: %s\n"), + quote (full_filename (dir_name))); + + if (rmdir (dir_name) && (errno != ENOENT || !x->ignore_missing_files)) + { + int saved_errno = errno; + +#ifndef EINVAL +# define EINVAL 0 +#endif + /* See if rmdir just failed because DIR_NAME is the current directory. + If so, give a better diagnostic than `rm: cannot remove directory + `...': Invalid argument' */ + if (errno == EINVAL && same_file (".", dir_name)) + { + error (0, 0, _("cannot remove current directory %s"), + quote (full_filename (dir_name))); + } + else + { + error (0, saved_errno, _("cannot remove directory %s"), + quote (full_filename (dir_name))); + } + return RM_ERROR; + } + + return status; +} + +/* Remove the file or directory specified by FS after checking appropriate + things. Return RM_OK if it is removed, and RM_ERROR or RM_USER_DECLINED + if not. If USER_SPECIFIED_NAME is non-zero, then the name part of FS may + be `.', `..', or may contain slashes. Otherwise, it must be a simple file + name (and hence must specify a file in the current directory). */ + +enum RM_status +rm (struct File_spec *fs, int user_specified_name, const struct rm_options *x) +{ + mode_t filetype_mode; + + if (user_specified_name) + { + /* CAUTION: this use of base_name works only because any + trailing slashes in fs->filename have already been removed. */ + char *base = base_name (fs->filename); + + if (DOT_OR_DOTDOT (base)) + { + error (0, 0, _("cannot remove `.' or `..'")); + return RM_ERROR; + } + } + + if (fspec_get_filetype_mode (fs, &filetype_mode)) + { + if (x->ignore_missing_files && errno == ENOENT) + return RM_OK; + + error (0, errno, _("cannot remove %s"), + quote (full_filename (fs->filename))); + return RM_ERROR; + } + +#ifdef ENABLE_CYCLE_CHECK + if (S_ISDIR (filetype_mode)) + { + struct active_dir_ent *old_ent; + struct active_dir_ent *new_ent; + + /* If there is already a directory in the map with the same device + and inode numbers, then there is a directory cycle. */ + + if (fspec_get_device_number (fs)) + { + error (0, errno, _("cannot stat %s"), + quote (full_filename (fs->filename))); + return RM_ERROR; + } + new_ent = make_active_dir_ent (fs->st_ino, fs->st_dev, current_depth ()); + old_ent = hash_lookup (active_dir_map, new_ent); + if (old_ent) + { + error (0, 0, _("\ +WARNING: Circular directory structure.\n\ +This almost certainly means that you have a corrupted file system.\n\ +NOTIFY YOUR SYSTEM MANAGER.\n\ +The following two directories have the same inode number:\n")); + print_nth_dir (stderr, old_ent->depth); + fprintf (stderr, "\n%s\n", quote (full_filename (fs->filename))); + fflush (stderr); + + if (x->interactive) + { + error (0, 0, _("continue? ")); + if (yesno ()) + return RM_ERROR; + } + exit (1); + } + + /* Put this directory in the active_dir_map. */ + if (! hash_insert (active_dir_map, new_ent)) + xalloc_die (); + } +#endif + + if (!S_ISDIR (filetype_mode) || x->unlink_dirs) + { + return remove_file (fs, x); + } + else + { + int need_save_cwd = user_specified_name; + enum RM_status status; + + if (need_save_cwd) + need_save_cwd = (strchr (fs->filename, '/') != NULL); + + status = remove_dir (fs, need_save_cwd, x); + +#ifdef ENABLE_CYCLE_CHECK + { + struct active_dir_ent tmp; + struct active_dir_ent *old_ent; + + /* Remove this directory from the active_dir_map. */ + tmp.st_ino = fs->st_ino; + assert (fs->have_device); + tmp.st_dev = fs->st_dev; + old_ent = hash_delete (active_dir_map, &tmp); + assert (old_ent != NULL); + free (old_ent); + } +#endif + + return status; + } +} + +void +remove_init (void) +{ + /* Initialize dir-stack obstacks. */ + obstack_init (&dir_stack); + obstack_init (&len_stack); + +#ifdef ENABLE_CYCLE_CHECK + active_dir_map = hash_initialize (ACTIVE_DIR_INITIAL_CAPACITY, NULL, + hash_active_dir_ent, + hash_compare_active_dir_ents, free); +#endif +} + +void +remove_fini (void) +{ +#ifdef ENABLE_CYCLE_CHECK + hash_free (active_dir_map); +#endif + + obstack_free (&dir_stack, NULL); + obstack_free (&len_stack, NULL); +} diff --git a/src/apps/bin/gnu/remove.h b/src/apps/bin/gnu/remove.h new file mode 100644 index 0000000000..deb5d628c3 --- /dev/null +++ b/src/apps/bin/gnu/remove.h @@ -0,0 +1,51 @@ + +struct rm_options +{ + /* If nonzero, ignore nonexistent files. */ + int ignore_missing_files; + + /* If nonzero, query the user about whether to remove each file. */ + int interactive; + + /* If nonzero, recursively remove directories. */ + int recursive; + + /* If nonzero, stdin is a tty. */ + int stdin_tty; + + /* If nonzero, remove directories with unlink instead of rmdir, and don't + require a directory to be empty before trying to unlink it. + Only works for the super-user. */ + int unlink_dirs; + + /* If nonzero, display the name of each file removed. */ + int verbose; +}; + +enum RM_status +{ + /* These must be listed in order of increasing seriousness. */ + RM_OK = 1, + RM_USER_DECLINED, + RM_ERROR +}; + +#define VALID_STATUS(S) \ + ((S) == RM_OK || (S) == RM_USER_DECLINED || (S) == RM_ERROR) + +struct File_spec +{ + char *filename; + unsigned int have_filetype_mode:1; + unsigned int have_full_mode:1; + unsigned int have_device:1; + mode_t mode; + ino_t st_ino; + dev_t st_dev; +}; + +enum RM_status rm PARAMS ((struct File_spec *fs, int user_specified_name, + const struct rm_options *x)); +void fspec_init_file PARAMS ((struct File_spec *fs, const char *filename)); +void remove_init PARAMS ((void)); +void remove_fini PARAMS ((void)); diff --git a/src/apps/bin/gnu/rm.c b/src/apps/bin/gnu/rm.c new file mode 100644 index 0000000000..0000c70b7b --- /dev/null +++ b/src/apps/bin/gnu/rm.c @@ -0,0 +1,205 @@ +/* `rm' file deletion utility for GNU. + Copyright (C) 88, 90, 91, 1994-2001 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Paul Rubin, David MacKenzie, and Richard Stallman. + Reworked to use chdir and hash tables by Jim Meyering. */ + +/* Implementation overview: + + In the `usual' case, RM saves no state for directories it is processing. + When a removal fails (either due to an error or to an interactive `no' + reply), the failure is noted (see description of `ht' in remove.c's + remove_cwd_entries function) so that when/if the containing directory + is reopened, RM doesn't try to remove the entry again. + + RM may delete arbitrarily deep hierarchies -- even ones in which file + names (from root to leaf) are longer than the system-imposed maximum. + It does this by using chdir to change to each directory in turn before + removing the entries in that directory. + + RM detects directory cycles by maintaining a table of the currently + active directories. See the description of active_dir_map in remove.c. + + RM is careful to avoid forming full file names whenever possible. + A full file name is formed only when it is about to be used -- e.g. + in a diagnostic or in an interactive-mode prompt. + + RM minimizes the number of lstat system calls it makes. On systems + that have valid d_type data in directory entries, RM makes only one + lstat call per command line argument -- regardless of the depth of + the hierarchy. */ + +#include +#include +#include +#include +#include + +#include "system.h" +#include "error.h" +#include "remove.h" +#include "save-cwd.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "rm" + +#define AUTHORS \ + "Paul Rubin, David MacKenzie, Richard Stallman, and Jim Meyering" + +void strip_trailing_slashes (); + +/* Name this program was run with. */ +char *program_name; + +static struct option const long_opts[] = +{ + {"directory", no_argument, NULL, 'd'}, + {"force", no_argument, NULL, 'f'}, + {"interactive", no_argument, NULL, 'i'}, + {"recursive", no_argument, NULL, 'r'}, + {"verbose", no_argument, NULL, 'v'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]... FILE...\n"), program_name); + printf (_("\ +Remove (unlink) the FILE(s).\n\ +\n\ + -d, --directory unlink directory, even if non-empty (super-user only)\n\ + -f, --force ignore nonexistent files, never prompt\n\ + -i, --interactive prompt before any removal\n\ + -r, -R, --recursive remove the contents of directories recursively\n\ + -v, --verbose explain what is being done\n\ + --help display this help and exit\n\ + --version output version information and exit\n\ +\n\ +To remove a file whose name starts with a `-', for example `-foo',\n\ +use one of these commands:\n\ + %s -- -foo\n\ +\n\ + %s ./-foo\n\ +\n\ +Note that if you use rm to remove a file, it is usually possible to recover\n\ +the contents of that file. If you want more assurance that the contents are\n\ +truly unrecoverable, consider using shred.\n\ +"), + program_name, program_name); + puts (_("\nReport bugs to .")); + } + exit (status); +} + +static void +rm_option_init (struct rm_options *x) +{ + x->unlink_dirs = 0; + x->ignore_missing_files = 0; + x->interactive = 0; + x->recursive = 0; + x->stdin_tty = isatty (STDIN_FILENO); + x->verbose = 0; +} + +int +main (int argc, char **argv) +{ + struct rm_options x; + int fail = 0; + int c; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + rm_option_init (&x); + + while ((c = getopt_long (argc, argv, "dfirvR", long_opts, NULL)) != -1) + { + switch (c) + { + case 0: /* Long option. */ + break; + case 'd': + x.unlink_dirs = 1; + break; + case 'f': + x.interactive = 0; + x.ignore_missing_files = 1; + break; + case 'i': + x.interactive = 1; + x.ignore_missing_files = 0; + break; + case 'r': + case 'R': + x.recursive = 1; + break; + case 'v': + x.verbose = 1; + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (1); + } + } + + if (optind == argc) + { + if (x.ignore_missing_files) + exit (0); + else + { + error (0, 0, _("too few arguments")); + usage (1); + } + } + + remove_init (); + + for (; optind < argc; optind++) + { + struct File_spec fs; + enum RM_status status; + + /* Stripping slashes is harmless for rmdir; + if the arg is not a directory, it will fail with ENOTDIR. */ + strip_trailing_slashes (argv[optind]); + fspec_init_file (&fs, argv[optind]); + status = rm (&fs, 1, &x); + assert (VALID_STATUS (status)); + if (status == RM_ERROR) + fail = 1; + } + + remove_fini (); + + exit (fail); +} diff --git a/src/apps/bin/gnu/rmdir.c b/src/apps/bin/gnu/rmdir.c new file mode 100644 index 0000000000..260205c3c2 --- /dev/null +++ b/src/apps/bin/gnu/rmdir.c @@ -0,0 +1,239 @@ +/* rmdir -- remove directories + Copyright (C) 90, 91, 1995-2000 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Options: + -p, --parent Remove any parent dirs that are explicitly mentioned + in an argument, if they become empty after the + argument file is removed. + + David MacKenzie */ + +#include +#include +#include +#include + +#include "system.h" +#include "error.h" +#include "quote.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "rmdir" + +#define AUTHORS "David MacKenzie" + +#ifndef EEXIST +# define EEXIST 0 +#endif + +#ifndef ENOTEMPTY +# define ENOTEMPTY 0 +#endif + +void strip_trailing_slashes (); + +/* The name this program was run with. */ +char *program_name; + +/* If nonzero, remove empty parent directories. */ +static int empty_paths; + +/* If nonzero, don't treat failure to remove a nonempty directory + as an error. */ +static int ignore_fail_on_non_empty; + +/* If nonzero, output a diagnostic for every directory processed. */ +static int verbose; + +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + IGNORE_FAIL_ON_NON_EMPTY_OPTION = CHAR_MAX + 1 +}; + +static struct option const longopts[] = +{ + /* Don't name this `--force' because it's not close enough in meaning + to e.g. rm's -f option. */ + {"ignore-fail-on-non-empty", no_argument, NULL, + IGNORE_FAIL_ON_NON_EMPTY_OPTION}, + + {"path", no_argument, NULL, 'p'}, + {"parents", no_argument, NULL, 'p'}, + {"verbose", no_argument, NULL, 'v'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + +/* Return nonzero if ERROR_NUMBER is one of the values associated + with a failed rmdir due to non-empty target directory. */ + +static int +errno_rmdir_non_empty (int error_number) +{ + return (error_number == RMDIR_ERRNO_NOT_EMPTY); +} + +/* Remove any empty parent directories of PATH. + If PATH contains slash characters, at least one of them + (beginning with the rightmost) is replaced with a NUL byte. */ + +static int +remove_parents (char *path) +{ + char *slash; + int fail = 0; + + while (1) + { + slash = strrchr (path, '/'); + if (slash == NULL) + break; + /* Remove any characters after the slash, skipping any extra + slashes in a row. */ + while (slash > path && *slash == '/') + --slash; + slash[1] = 0; + + /* Give a diagnostic for each attempted removal if --verbose. */ + if (verbose) + error (0, 0, _("removing directory, %s"), path); + + fail = rmdir (path); + + if (fail) + { + /* Stop quietly if --ignore-fail-on-non-empty. */ + if (ignore_fail_on_non_empty + && errno_rmdir_non_empty (errno)) + { + fail = 0; + } + else + { + error (0, errno, "%s", quote (path)); + } + break; + } + } + return fail; +} + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]... DIRECTORY...\n"), program_name); + printf (_("\ +Remove the DIRECTORY(ies), if they are empty.\n\ +\n\ + --ignore-fail-on-non-empty\n\ + ignore each failure that is solely because a directory\n\ + is non-empty\n\ + -p, --parents remove DIRECTORY, then try to remove each directory\n\ + component of that path name. E.g., `rmdir -p a/b/c' is\n\ + similar to `rmdir a/b/c a/b a'.\n\ + -v, --verbose output a diagnostic for every directory processed\n\ + --help display this help and exit\n\ + --version output version information and exit\n\ +")); + puts (_("\nReport bugs to .")); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + int errors = 0; + int optc; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + empty_paths = 0; + + while ((optc = getopt_long (argc, argv, "pv", longopts, NULL)) != -1) + { + switch (optc) + { + case 0: /* Long option. */ + break; + case 'p': + empty_paths = 1; + break; + case IGNORE_FAIL_ON_NON_EMPTY_OPTION: + ignore_fail_on_non_empty = 1; + break; + case 'v': + verbose = 1; + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (1); + } + } + + if (optind == argc) + { + error (0, 0, _("too few arguments")); + usage (1); + } + + for (; optind < argc; ++optind) + { + int fail; + char *dir = argv[optind]; + + /* Stripping slashes is harmless for rmdir; + if the arg is not a directory, it will fail with ENOTDIR. */ + strip_trailing_slashes (dir); + + /* Give a diagnostic for each attempted removal if --verbose. */ + if (verbose) + error (0, 0, _("removing directory, %s"), dir); + + fail = rmdir (dir); + + if (fail) + { + if (ignore_fail_on_non_empty + && errno_rmdir_non_empty (errno)) + continue; + + error (0, errno, "%s", quote (dir)); + errors = 1; + } + else if (empty_paths) + { + errors += remove_parents (dir); + } + } + + exit (errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} diff --git a/src/apps/bin/gnu/sync.c b/src/apps/bin/gnu/sync.c new file mode 100644 index 0000000000..1afc5d9276 --- /dev/null +++ b/src/apps/bin/gnu/sync.c @@ -0,0 +1,74 @@ +/* sync - update the super block + Copyright (C) 1994-2001 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Jim Meyering */ + +#include +#include +#include + +#include "system.h" +#include "error.h" +#include "long-options.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "sync" + +#define AUTHORS "Jim Meyering" + +/* The name this program was run with. */ +char *program_name; + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]\n"), program_name); + printf (_("\ +Force changed blocks to disk, update the super block.\n\ +\n\ + --help display this help and exit\n\ + --version output version information and exit\n\ +")); + puts (_("\nReport bugs to .")); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE, VERSION, + AUTHORS, usage); + + if (argc != 1) + error (0, 0, _("ignoring all arguments")); + + sync (); + exit (0); +} diff --git a/src/apps/bin/gnu/sys2.h b/src/apps/bin/gnu/sys2.h new file mode 100644 index 0000000000..48af648c30 --- /dev/null +++ b/src/apps/bin/gnu/sys2.h @@ -0,0 +1,606 @@ +/* WARNING -- this file is temporary. It is shared between the + sh-utils, fileutils, and textutils packages. Once I find a little + more time, I'll merge the remaining things in system.h and everything + in this file will go back there. */ + +#if STAT_MACROS_BROKEN +# undef S_ISBLK +# undef S_ISCHR +# undef S_ISDIR +# undef S_ISDOOR +# undef S_ISFIFO +# undef S_ISLNK +# undef S_ISMPB +# undef S_ISMPC +# undef S_ISNWK +# undef S_ISREG +# undef S_ISSOCK +#endif /* STAT_MACROS_BROKEN. */ + +#ifndef S_IFMT +# define S_IFMT 0170000 +#endif +#if !defined(S_ISBLK) && defined(S_IFBLK) +# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +#endif +#if !defined(S_ISCHR) && defined(S_IFCHR) +# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#endif +#if !defined(S_ISDIR) && defined(S_IFDIR) +# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif +#if !defined(S_ISREG) && defined(S_IFREG) +# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#endif +#if !defined(S_ISFIFO) && defined(S_IFIFO) +# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +#endif +#if !defined(S_ISLNK) && defined(S_IFLNK) +# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#endif +#if !defined(S_ISSOCK) && defined(S_IFSOCK) +# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) +#endif +#if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */ +# define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB) +# define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC) +#endif +#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */ +# define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK) +#endif +#if !defined(S_ISDOOR) && defined(S_IFDOOR) /* Solaris 2.5 and up */ +# define S_ISDOOR(m) (((m) & S_IFMT) == S_IFDOOR) +#endif + +#if !S_ISUID +# define S_ISUID 04000 +#endif +#if !S_ISGID +# define S_ISGID 02000 +#endif + +/* S_ISVTX is a common extension to POSIX.1. */ +#ifndef S_ISVTX +# define S_ISVTX 01000 +#endif + +#if !S_IRUSR && S_IREAD +# define S_IRUSR S_IREAD +#endif +#if !S_IRUSR +# define S_IRUSR 00400 +#endif +#if !S_IRGRP +# define S_IRGRP (S_IRUSR >> 3) +#endif +#if !S_IROTH +# define S_IROTH (S_IRUSR >> 6) +#endif + +#if !S_IWUSR && S_IWRITE +# define S_IWUSR S_IWRITE +#endif +#if !S_IWUSR +# define S_IWUSR 00200 +#endif +#if !S_IWGRP +# define S_IWGRP (S_IWUSR >> 3) +#endif +#if !S_IWOTH +# define S_IWOTH (S_IWUSR >> 6) +#endif + +#if !S_IXUSR && S_IEXEC +# define S_IXUSR S_IEXEC +#endif +#if !S_IXUSR +# define S_IXUSR 00100 +#endif +#if !S_IXGRP +# define S_IXGRP (S_IXUSR >> 3) +#endif +#if !S_IXOTH +# define S_IXOTH (S_IXUSR >> 6) +#endif + +#if !S_IRWXU +# define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif +#if !S_IRWXG +# define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) +#endif +#if !S_IRWXO +# define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#endif + +/* S_IXUGO is a common extension to POSIX.1. */ +#if !S_IXUGO +# define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH) +#endif + +#ifndef S_IRWXUGO +# define S_IRWXUGO (S_IRWXU | S_IRWXG | S_IRWXO) +#endif + +/* All the mode bits that can be affected by chmod. */ +#define CHMOD_MODE_BITS \ + (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO) + +#ifdef ST_MTIM_NSEC +# define ST_TIME_CMP_NS(a, b, ns) ((a).ns < (b).ns ? -1 : (a).ns > (b).ns) +#else +# define ST_TIME_CMP_NS(a, b, ns) 0 +#endif +#define ST_TIME_CMP(a, b, s, ns) \ + ((a).s < (b).s ? -1 : (a).s > (b).s ? 1 : ST_TIME_CMP_NS(a, b, ns)) +#define ATIME_CMP(a, b) ST_TIME_CMP (a, b, st_atime, st_atim.ST_MTIM_NSEC) +#define CTIME_CMP(a, b) ST_TIME_CMP (a, b, st_ctime, st_ctim.ST_MTIM_NSEC) +#define MTIME_CMP(a, b) ST_TIME_CMP (a, b, st_mtime, st_mtim.ST_MTIM_NSEC) + +#ifndef RETSIGTYPE +# define RETSIGTYPE void +#endif + +#ifndef __GNUC__ +# if HAVE_ALLOCA_H +# include +# else +# ifdef _AIX + # pragma alloca +# else +# ifdef _WIN32 +# include +# include +# else +# ifndef alloca +char *alloca (); +# endif +# endif +# endif +# endif +#endif + +#ifdef __DJGPP__ + /* We need the declaration of setmode. */ +# include + /* We need the declaration of __djgpp_set_ctrl_c. */ +# include +#endif + +#if HAVE_STDINT_H +# include +#endif + +#if HAVE_INTTYPES_H +# include /* for the definition of UINTMAX_MAX */ +#endif + +#include + +/* Jim Meyering writes: + + "... Some ctype macros are valid only for character codes that + isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when + using /bin/cc or gcc but without giving an ansi option). So, all + ctype uses should be through macros like ISPRINT... If + STDC_HEADERS is defined, then autoconf has verified that the ctype + macros don't need to be guarded with references to isascii. ... + Defining isascii to 1 should let any compiler worth its salt + eliminate the && through constant folding." + + Bruno Haible adds: + + "... Furthermore, isupper(c) etc. have an undefined result if c is + outside the range -1 <= c <= 255. One is tempted to write isupper(c) + with c being of type `char', but this is wrong if c is an 8-bit + character >= 128 which gets sign-extended to a negative value. + The macro ISUPPER protects against this as well." */ + +#if STDC_HEADERS || (!defined (isascii) && !HAVE_ISASCII) +# define IN_CTYPE_DOMAIN(c) 1 +#else +# define IN_CTYPE_DOMAIN(c) isascii(c) +#endif + +#ifdef isblank +# define ISBLANK(c) (IN_CTYPE_DOMAIN (c) && isblank (c)) +#else +# define ISBLANK(c) ((c) == ' ' || (c) == '\t') +#endif +#ifdef isgraph +# define ISGRAPH(c) (IN_CTYPE_DOMAIN (c) && isgraph (c)) +#else +# define ISGRAPH(c) (IN_CTYPE_DOMAIN (c) && isprint (c) && !isspace (c)) +#endif + +/* This is defined in on at least Solaris2.6 systems. */ +#undef ISPRINT + +#define ISPRINT(c) (IN_CTYPE_DOMAIN (c) && isprint (c)) +#define ISALNUM(c) (IN_CTYPE_DOMAIN (c) && isalnum (c)) +#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c)) +#define ISCNTRL(c) (IN_CTYPE_DOMAIN (c) && iscntrl (c)) +#define ISLOWER(c) (IN_CTYPE_DOMAIN (c) && islower (c)) +#define ISPUNCT(c) (IN_CTYPE_DOMAIN (c) && ispunct (c)) +#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c)) +#define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c)) +#define ISXDIGIT(c) (IN_CTYPE_DOMAIN (c) && isxdigit (c)) +#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c)) + +#if STDC_HEADERS +# define TOLOWER(Ch) tolower (Ch) +# define TOUPPER(Ch) toupper (Ch) +#else +# define TOLOWER(Ch) (ISUPPER (Ch) ? tolower (Ch) : (Ch)) +# define TOUPPER(Ch) (ISLOWER (Ch) ? toupper (Ch) : (Ch)) +#endif + +/* ISDIGIT differs from ISDIGIT_LOCALE, as follows: + - Its arg may be any int or unsigned int; it need not be an unsigned char. + - It's guaranteed to evaluate its argument exactly once. + - It's typically faster. + Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that + only '0' through '9' are digits. Prefer ISDIGIT to ISDIGIT_LOCALE unless + it's important to use the locale's definition of `digit' even when the + host does not conform to Posix. */ +#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9) + +#ifndef PARAMS +# if PROTOTYPES +# define PARAMS(Args) Args +# else +# define PARAMS(Args) () +# endif +#endif + +/* Take care of NLS matters. */ + +#if HAVE_LOCALE_H +# include +#endif +#if !HAVE_SETLOCALE +# define setlocale(Category, Locale) /* empty */ +#endif + +#if ENABLE_NLS +# include +# if HAVE_GETTEXT && !HAVE_DCGETTEXT && !defined dcgettext +# define dcgettext(Domain, Text, Category) Text +# endif +# define _(Text) gettext (Text) +#else +# undef bindtextdomain +# define bindtextdomain(Domain, Directory) /* empty */ +# undef textdomain +# define textdomain(Domain) /* empty */ +# undef dcgettext +# define dcgettext(Domainname, Text, Category) Text +# define _(Text) Text +#endif +#define N_(Text) Text + +#define STREQ(a, b) (strcmp ((a), (b)) == 0) + +#if !HAVE_DECL_FREE +void free (); +#endif + +#if !HAVE_DECL_MALLOC +char *malloc (); +#endif + +#if !HAVE_DECL_MEMCHR +char *memchr (); +#endif + +#if !HAVE_DECL_REALLOC +char *realloc (); +#endif + +#if !HAVE_DECL_STPCPY +# ifndef stpcpy +char *stpcpy (); +# endif +#endif + +#if !HAVE_DECL_STRNDUP +char *strndup (); +#endif + +#if !HAVE_DECL_STRSTR +char *strstr (); +#endif + +#if !HAVE_DECL_GETENV +char *getenv (); +#endif + +#if !HAVE_DECL_LSEEK +off_t lseek (); +#endif + +/* This is needed on some AIX systems. */ +#if !HAVE_DECL_STRTOUL +unsigned long strtoul (); +#endif + +/* This is needed on some AIX systems. */ +#if !HAVE_DECL_STRTOULL && HAVE_UNSIGNED_LONG_LONG +unsigned long long strtoull (); +#endif + +#if !HAVE_DECL_GETLOGIN +char *getlogin (); +#endif + +#if !HAVE_DECL_TTYNAME +char *ttyname (); +#endif + +#if !HAVE_DECL_GETEUID +uid_t geteuid (); +#endif + +#if !HAVE_DECL_GETPWUID +struct passwd *getpwuid (); +#endif + +#if !HAVE_DECL_GETGRGID +struct group *getgrgid (); +#endif + +#if !HAVE_DECL_GETUID +uid_t getuid (); +#endif + +#include "xalloc.h" + +#if ! defined HAVE_MEMPCPY && ! defined mempcpy +/* Be CAREFUL that there are no side effects in N. */ +# define mempcpy(D, S, N) ((void *) ((char *) memcpy (D, S, N) + (N))) +#endif + +/* These are wrappers for functions/macros from GNU libc. + The standard I/O functions are thread-safe. These *_unlocked ones + are more efficient but not thread-safe. That they're not thread-safe + is fine since all these applications are single threaded. */ + +#if HAVE_CLEARERR_UNLOCKED +# undef clearerr +# define clearerr(S) clearerr_unlocked (S) +#endif + +#if HAVE_FEOF_UNLOCKED +# undef feof +# define feof(S) feof_unlocked (S) +#endif + +#if HAVE_FERROR_UNLOCKED +# undef ferror +# define ferror(S) ferror_unlocked (S) +#endif + +#if HAVE_FFLUSH_UNLOCKED +# undef fflush +# define fflush(S) fflush_unlocked (S) +#endif + +#if HAVE_FPUTC_UNLOCKED +# undef fputc +# define fputc(C, S) fputc_unlocked (C, S) +#endif + +#if HAVE_FREAD_UNLOCKED +# undef fread +# define fread(P, Z, N, S) fread_unlocked (P, Z, N, S) +#endif + +#if HAVE_FWRITE_UNLOCKED +# undef fwrite +# define fwrite(P, Z, N, S) fwrite_unlocked (P, Z, N, S) +#endif + +#if HAVE_GETC_UNLOCKED +# undef getc +# define getc(S) getc_unlocked (S) +#endif + +#if HAVE_GETCHAR_UNLOCKED +# undef getchar +# define getchar(S) getchar_unlocked (S) +#endif + +#if HAVE_PUTC_UNLOCKED +# undef putc +# define putc(C, S) putc_unlocked (C, S) +#endif + +#if HAVE_PUTCHAR_UNLOCKED +# undef putchar +# define putchar(C) putchar_unlocked (C) +#endif + +#define SAME_INODE(Stat_buf_1, Stat_buf_2) \ + ((Stat_buf_1).st_ino == (Stat_buf_2).st_ino \ + && (Stat_buf_1).st_dev == (Stat_buf_2).st_dev) + +#define DOT_OR_DOTDOT(Basename) \ + (Basename[0] == '.' && (Basename[1] == '\0' \ + || (Basename[1] == '.' && Basename[2] == '\0'))) + +#if SETVBUF_REVERSED +# define SETVBUF(Stream, Buffer, Type, Size) \ + setvbuf (Stream, Type, Buffer, Size) +#else +# define SETVBUF(Stream, Buffer, Type, Size) \ + setvbuf (Stream, Buffer, Type, Size) +#endif + +char *base_name PARAMS ((char const *)); + +/* Factor out some of the common --help and --version processing code. */ + +/* These enum values cannot possibly conflict with the option values + ordinarily used by commands, including CHAR_MAX + 1, etc. Avoid + CHAR_MIN - 1, as it may equal -1, the getopt end-of-options value. */ +enum +{ + GETOPT_HELP_CHAR = (CHAR_MIN - 2), + GETOPT_VERSION_CHAR = (CHAR_MIN - 3) +}; + +#define GETOPT_HELP_OPTION_DECL \ + "help", no_argument, 0, GETOPT_HELP_CHAR +#define GETOPT_VERSION_OPTION_DECL \ + "version", no_argument, 0, GETOPT_VERSION_CHAR + +#define case_GETOPT_HELP_CHAR \ + case GETOPT_HELP_CHAR: \ + usage (EXIT_SUCCESS); \ + break; + +#include "closeout.h" +#include "version-etc.h" + +#define case_GETOPT_VERSION_CHAR(Program_name, Authors) \ + case GETOPT_VERSION_CHAR: \ + version_etc (stdout, Program_name, PACKAGE, VERSION, Authors); \ + exit (EXIT_SUCCESS); \ + break; + +#ifndef MAX +# define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef MIN +# define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef CHAR_BIT +# define CHAR_BIT 8 +#endif + +/* The extra casts work around common compiler bugs. */ +#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) +/* The outer cast is needed to work around a bug in Cray C 5.0.3.0. + It is necessary at least when t == time_t. */ +#define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \ + ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0)) +#define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t))) + +/* Upper bound on the string length of an integer converted to string. + 302 / 1000 is ceil (log10 (2.0)). Subtract 1 for the sign bit; + add 1 for integer division truncation; add 1 more for a minus sign. */ +#define INT_STRLEN_BOUND(t) ((sizeof (t) * CHAR_BIT - 1) * 302 / 1000 + 2) + +#ifndef CHAR_MIN +# define CHAR_MIN TYPE_MINIMUM (char) +#endif + +#ifndef CHAR_MAX +# define CHAR_MAX TYPE_MAXIMUM (char) +#endif + +#ifndef SCHAR_MIN +# define SCHAR_MIN (-1 - SCHAR_MAX) +#endif + +#ifndef SCHAR_MAX +# define SCHAR_MAX (CHAR_MAX == UCHAR_MAX ? CHAR_MAX / 2 : CHAR_MAX) +#endif + +#ifndef UCHAR_MAX +# define UCHAR_MAX TYPE_MAXIMUM (unsigned char) +#endif + +#ifndef SHRT_MIN +# define SHRT_MIN TYPE_MINIMUM (short int) +#endif + +#ifndef SHRT_MAX +# define SHRT_MAX TYPE_MAXIMUM (short int) +#endif + +#ifndef INT_MAX +# define INT_MAX TYPE_MAXIMUM (int) +#endif + +#ifndef UINT_MAX +# define UINT_MAX TYPE_MAXIMUM (unsigned int) +#endif + +#ifndef LONG_MAX +# define LONG_MAX TYPE_MAXIMUM (long) +#endif + +#ifndef ULONG_MAX +# define ULONG_MAX TYPE_MAXIMUM (unsigned long) +#endif + +#ifndef SIZE_MAX +# define SIZE_MAX TYPE_MAXIMUM (size_t) +#endif + +#ifndef UINTMAX_MAX +# define UINTMAX_MAX TYPE_MAXIMUM (uintmax_t) +#endif + +#ifndef OFF_T_MIN +# define OFF_T_MIN TYPE_MINIMUM (off_t) +#endif + +#ifndef OFF_T_MAX +# define OFF_T_MAX TYPE_MAXIMUM (off_t) +#endif + +#ifndef UID_T_MAX +# define UID_T_MAX TYPE_MAXIMUM (uid_t) +#endif + +#ifndef GID_T_MAX +# define GID_T_MAX TYPE_MAXIMUM (gid_t) +#endif + +#ifndef PID_T_MAX +# define PID_T_MAX TYPE_MAXIMUM (pid_t) +#endif + +#ifndef CHAR_BIT +# define CHAR_BIT 8 +#endif + +/* Use this to suppress gcc's `...may be used before initialized' warnings. */ +#ifdef lint +# define IF_LINT(Code) Code +#else +# define IF_LINT(Code) /* empty */ +#endif + +#ifndef __attribute__ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__ +# define __attribute__(x) +# endif +#endif + +#ifndef ATTRIBUTE_NORETURN +# define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__)) +#endif + +#ifndef ATTRIBUTE_UNUSED +# define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +#endif + +#if defined strdupa +# define ASSIGN_STRDUPA(DEST, S) \ + do { DEST = strdupa(S); } while (0) +#else +# define ASSIGN_STRDUPA(DEST, S) \ + do \ + { \ + const char *s_ = (S); \ + size_t len_ = strlen (s_) + 1; \ + char *tmp_dest_ = (char *) alloca (len_); \ + DEST = memcpy (tmp_dest_, (s_), len_); \ + } \ + while (0) +#endif diff --git a/src/apps/bin/gnu/system.h b/src/apps/bin/gnu/system.h new file mode 100644 index 0000000000..582fd7c514 --- /dev/null +++ b/src/apps/bin/gnu/system.h @@ -0,0 +1,278 @@ +/* system-dependent definitions for fileutils, textutils, and sh-utils packages. + Copyright (C) 1989, 1991-2000 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Include sys/types.h before this file. */ + +#include + +#if !defined(HAVE_MKFIFO) +# define mkfifo(path, mode) (mknod ((path), (mode) | S_IFIFO, 0)) +#endif + +#if HAVE_SYS_PARAM_H +# include +#endif + +/* should be included before any preprocessor test + of _POSIX_VERSION. */ +#if HAVE_UNISTD_H +# include +#endif + +#ifndef STDIN_FILENO +# define STDIN_FILENO 0 +#endif + +#ifndef STDOUT_FILENO +# define STDOUT_FILENO 1 +#endif + +#ifndef STDERR_FILENO +# define STDERR_FILENO 2 +#endif + + +#if HAVE_LIMITS_H +/* limits.h must come before pathmax.h because limits.h on some systems + undefs PATH_MAX, whereas pathmax.h sets PATH_MAX. */ +# include +#endif + +#include "pathmax.h" + +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +/* Since major is a function on SVR4, we can't use `ifndef major'. */ +#if MAJOR_IN_MKDEV +# include +# define HAVE_MAJOR +#endif +#if MAJOR_IN_SYSMACROS +# include +# define HAVE_MAJOR +#endif +#ifdef major /* Might be defined in sys/types.h. */ +# define HAVE_MAJOR +#endif + +#ifndef HAVE_MAJOR +# define major(dev) (((dev) >> 8) & 0xff) +# define minor(dev) ((dev) & 0xff) +# define makedev(maj, min) (((maj) << 8) | (min)) +#endif +#undef HAVE_MAJOR + +#if HAVE_UTIME_H +# include +#endif + +/* Some systems (even some that do have ) don't declare this + structure anywhere. */ +#ifndef HAVE_STRUCT_UTIMBUF +struct utimbuf +{ + long actime; + long modtime; +}; +#endif + +/* Don't use bcopy! Use memmove if source and destination may overlap, + memcpy otherwise. */ + +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include +# endif +# include +#else +# include +#endif + +#include +#ifndef errno +extern int errno; +#endif + +#if HAVE_STDLIB_H +# define getopt system_getopt +# include +# undef getopt +#endif + +/* The following test is to work around the gross typo in + systems like Sony NEWS-OS Release 4.0C, whereby EXIT_FAILURE + is defined to 0, not 1. */ +#if !EXIT_FAILURE +# undef EXIT_FAILURE +# define EXIT_FAILURE 1 +#endif + +#ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +#endif + +#if HAVE_FCNTL_H +# include +#else +# include +#endif + +#if !defined (SEEK_SET) +# define SEEK_SET 0 +# define SEEK_CUR 1 +# define SEEK_END 2 +#endif +#ifndef F_OK +# define F_OK 0 +# define X_OK 1 +# define W_OK 2 +# define R_OK 4 +#endif + +/* For systems that distinguish between text and binary I/O. + O_BINARY is usually declared in fcntl.h */ +#if !defined O_BINARY && defined _O_BINARY + /* For MSC-compatible compilers. */ +# define O_BINARY _O_BINARY +# define O_TEXT _O_TEXT +#endif + +#ifdef __BEOS__ + /* BeOS 5 has O_BINARY and O_TEXT, but they have no effect. */ +# undef O_BINARY +# undef O_TEXT +#endif + +#if O_BINARY +# ifndef __DJGPP__ +# define setmode _setmode +# define fileno(_fp) _fileno (_fp) +# endif /* not DJGPP */ +# define SET_BINARY(_f) do {if (!isatty(_f)) setmode (_f, O_BINARY);} while (0) +# define SET_BINARY2(_f1, _f2) \ + do { \ + if (!isatty (_f1)) \ + { \ + setmode (_f1, O_BINARY); \ + if (!isatty (_f2)) \ + setmode (_f2, O_BINARY); \ + } \ + } while(0) +#else +# define SET_BINARY(f) (void)0 +# define SET_BINARY2(f1,f2) (void)0 +# define O_BINARY 0 +# define O_TEXT 0 +#endif /* O_BINARY */ + +#if HAVE_DIRENT_H +# include +# define NLENGTH(direct) (strlen((direct)->d_name)) +#else /* not HAVE_DIRENT_H */ +# define dirent direct +# define NLENGTH(direct) ((direct)->d_namlen) +# if HAVE_SYS_NDIR_H +# include +# endif /* HAVE_SYS_NDIR_H */ +# if HAVE_SYS_DIR_H +# include +# endif /* HAVE_SYS_DIR_H */ +# if HAVE_NDIR_H +# include +# endif /* HAVE_NDIR_H */ +#endif /* HAVE_DIRENT_H */ + +#if CLOSEDIR_VOID +/* Fake a return value. */ +# define CLOSEDIR(d) (closedir (d), 0) +#else +# define CLOSEDIR(d) closedir (d) +#endif + +/* Get or fake the disk device blocksize. + Usually defined by sys/param.h (if at all). */ +#if !defined DEV_BSIZE && defined BSIZE +# define DEV_BSIZE BSIZE +#endif +#if !defined DEV_BSIZE && defined BBSIZE /* SGI */ +# define DEV_BSIZE BBSIZE +#endif +#ifndef DEV_BSIZE +# define DEV_BSIZE 4096 +#endif + +/* Extract or fake data from a `struct stat'. + ST_BLKSIZE: Preferred I/O blocksize for the file, in bytes. + ST_NBLOCKS: Number of blocks in the file, including indirect blocks. + ST_NBLOCKSIZE: Size of blocks used when calculating ST_NBLOCKS. */ +#ifndef HAVE_STRUCT_STAT_ST_BLOCKS +# define ST_BLKSIZE(statbuf) DEV_BSIZE +# if defined(_POSIX_SOURCE) || !defined(BSIZE) /* fileblocks.c uses BSIZE. */ +# define ST_NBLOCKS(statbuf) \ + (S_ISREG ((statbuf).st_mode) \ + || S_ISDIR ((statbuf).st_mode) \ + ? (statbuf).st_size / ST_NBLOCKSIZE + ((statbuf).st_size % ST_NBLOCKSIZE != 0) : 0) +# else /* !_POSIX_SOURCE && BSIZE */ +# define ST_NBLOCKS(statbuf) \ + (S_ISREG ((statbuf).st_mode) \ + || S_ISDIR ((statbuf).st_mode) \ + ? st_blocks ((statbuf).st_size) : 0) +# endif /* !_POSIX_SOURCE && BSIZE */ +#else /* HAVE_STRUCT_STAT_ST_BLOCKS */ +/* Some systems, like Sequents, return st_blksize of 0 on pipes. */ +# define ST_BLKSIZE(statbuf) ((statbuf).st_blksize > 0 \ + ? (statbuf).st_blksize : DEV_BSIZE) +# if defined(hpux) || defined(__hpux__) || defined(__hpux) +/* HP-UX counts st_blocks in 1024-byte units. + This loses when mixing HP-UX and BSD filesystems with NFS. */ +# define ST_NBLOCKSIZE 1024 +# else /* !hpux */ +# if defined(_AIX) && defined(_I386) +/* AIX PS/2 counts st_blocks in 4K units. */ +# define ST_NBLOCKSIZE (4 * 1024) +# else /* not AIX PS/2 */ +# if defined(_CRAY) +# define ST_NBLOCKS(statbuf) \ + (S_ISREG ((statbuf).st_mode) \ + || S_ISDIR ((statbuf).st_mode) \ + ? (statbuf).st_blocks * ST_BLKSIZE(statbuf)/ST_NBLOCKSIZE : 0) +# endif /* _CRAY */ +# endif /* not AIX PS/2 */ +# endif /* !hpux */ +#endif /* HAVE_STRUCT_STAT_ST_BLOCKS */ + +#ifndef ST_NBLOCKS +# define ST_NBLOCKS(statbuf) \ + (S_ISREG ((statbuf).st_mode) \ + || S_ISDIR ((statbuf).st_mode) \ + ? (statbuf).st_blocks : 0) +#endif + +#ifndef ST_NBLOCKSIZE +# define ST_NBLOCKSIZE 512 +#endif + +#include "sys2.h" diff --git a/src/apps/bin/gnu/touch.c b/src/apps/bin/gnu/touch.c new file mode 100644 index 0000000000..35fa58f4d1 --- /dev/null +++ b/src/apps/bin/gnu/touch.c @@ -0,0 +1,366 @@ +/* touch -- change modification and access times of files + Copyright (C) 87, 1989-1991, 1995-2001 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Paul Rubin, Arnold Robbins, Jim Kingdon, David MacKenzie, + and Randy Smith. */ + +#include +#include +#include +#include + +#include "system.h" +#include "argmatch.h" +#include "error.h" +#include "getdate.h" +#include "posixtm.h" +#include "quote.h" +#include "safe-read.h" + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "touch" + +#define AUTHORS \ + "Paul Rubin, Arnold Robbins, Jim Kingdon, David MacKenzie, and Randy Smith" + +#ifndef STDC_HEADERS +time_t time (); +#endif + +/* Bitmasks for `change_times'. */ +#define CH_ATIME 1 +#define CH_MTIME 2 + +#if !defined O_NDELAY +# define O_NDELAY 0 +#endif + +#if !defined O_NONBLOCK +# define O_NONBLOCK O_NDELAY +#endif + +#if !defined O_NOCTTY +# define O_NOCTTY 0 +#endif + +/* The name by which this program was run. */ +char *program_name; + +/* Which timestamps to change. */ +static int change_times; + +/* (-c) If nonzero, don't create if not already there. */ +static int no_create; + +/* (-d) If nonzero, date supplied on command line in get_date formats. */ +static int flexible_date; + +/* (-r) If nonzero, use times from a reference file. */ +static int use_ref; + +/* (-t) If nonzero, date supplied on command line in POSIX format. */ +static int posix_date; + +/* If nonzero, the only thing we have to do is change both the + modification and access time to the current time, so we don't + have to own the file, just be able to read and write it. + On some systems, we can do this if we own the file, even though + we have neither read nor write access to it. */ +static int amtime_now; + +/* New time to use when setting time. */ +static time_t newtime; + +/* File to use for -r. */ +static char *ref_file; + +/* Info about the reference file. */ +static struct stat ref_stats; + +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + TIME_OPTION = CHAR_MAX + 1 +}; + +static struct option const longopts[] = +{ + {"time", required_argument, 0, TIME_OPTION}, + {"no-create", no_argument, 0, 'c'}, + {"date", required_argument, 0, 'd'}, + {"file", required_argument, 0, 'r'}, /* FIXME: phase out --file */ + {"reference", required_argument, 0, 'r'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {0, 0, 0, 0} +}; + +/* Valid arguments to the `--time' option. */ +static char const* const time_args[] = +{ + "atime", "access", "use", "mtime", "modify", 0 +}; + +/* The bits in `change_times' that those arguments set. */ +static int const time_masks[] = +{ + CH_ATIME, CH_ATIME, CH_ATIME, CH_MTIME, CH_MTIME +}; + +/* Update the time of file FILE according to the options given. + Return 0 if successful, 1 if an error occurs. */ + +static int +touch (const char *file) +{ + int status; + struct stat sbuf; + int fd = -1; + int open_errno = 0; + + if (! no_create) + { + /* Try to open FILE, creating it if necessary. */ + fd = open (file, O_WRONLY | O_CREAT | O_NONBLOCK | O_NOCTTY, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + if (fd == -1) + open_errno = errno; + } + + if (! amtime_now) + { + /* We're setting only one of the time values. stat the target to get + the other one. If we have the file descriptor already, use fstat. + Otherwise, either we're in no-create mode (and hence didn't call open) + or FILE is inaccessible or a directory, so we have to use stat. */ + if (fd != -1 ? fstat (fd, &sbuf) : stat (file, &sbuf)) + { + if (open_errno) + error (0, open_errno, _("creating %s"), quote (file)); + else + error (0, errno, _("getting attributes of %s"), quote (file)); + close (fd); + return 1; + } + } + + if (fd != -1 && close (fd) < 0) + { + error (0, errno, _("creating %s"), quote (file)); + return 1; + } + + if (amtime_now) + { + /* Pass NULL to utime so it will not fail if we just have + write access to the file, but don't own it. */ + status = utime (file, NULL); + } + else + { + struct utimbuf utb; + + /* There's currently no interface to set file timestamps with + better than 1-second resolution, so discard any fractional + part of the source timestamp. */ + + if (use_ref) + { + utb.actime = ref_stats.st_atime; + utb.modtime = ref_stats.st_mtime; + } + else + utb.actime = utb.modtime = newtime; + + if (!(change_times & CH_ATIME)) + utb.actime = sbuf.st_atime; + + if (!(change_times & CH_MTIME)) + utb.modtime = sbuf.st_mtime; + + status = utime (file, &utb); + } + + if (status) + { + if (open_errno) + error (0, open_errno, _("creating %s"), quote (file)); + else + error (0, errno, _("setting times of %s"), quote (file)); + return 1; + } + + return 0; +} + +void +usage (int status) +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]... FILE...\n"), program_name); + printf (_(" or: %s [-acm] MMDDhhmm[YY] FILE... (obsolescent)\n"), + program_name); + printf (_("\ +Update the access and modification times of each FILE to the current time.\n\ +\n\ + -a change only the access time\n\ + -c, --no-create do not create any files\n\ + -d, --date=STRING parse STRING and use it instead of current time\n\ + -f (ignored)\n\ + -m change only the modification time\n\ + -r, --reference=FILE use this file's times instead of current time\n\ + -t STAMP use [[CC]YY]MMDDhhmm[.ss] instead of current time\n\ + --time=WORD set time given by WORD: access atime use (same as -a)\n\ + modify mtime (same as -m)\n\ + --help display this help and exit\n\ + --version output version information and exit\n\ +\n\ +Note that the three time-date formats recognized for the -d and -t options\n\ +and for the obsolescent argument are all different.\n\ +")); + puts (_("\nReport bugs to .")); + } + exit (status); +} + +int +main (int argc, char **argv) +{ + int c; + int date_set = 0; + int err = 0; + + program_name = argv[0]; + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + atexit (close_stdout); + + change_times = no_create = use_ref = posix_date = flexible_date = 0; + newtime = (time_t) -1; + + while ((c = getopt_long (argc, argv, "acd:fmr:t:", longopts, NULL)) != -1) + { + switch (c) + { + case 0: + break; + + case 'a': + change_times |= CH_ATIME; + break; + + case 'c': + no_create++; + break; + + case 'd': + flexible_date++; + newtime = get_date (optarg, NULL); + if (newtime == (time_t) -1) + error (1, 0, _("invalid date format %s"), quote (optarg)); + date_set++; + break; + + case 'f': + break; + + case 'm': + change_times |= CH_MTIME; + break; + + case 'r': + use_ref++; + ref_file = optarg; + break; + + case 't': + posix_date++; + newtime = posixtime (optarg, + PDS_LEADING_YEAR | PDS_CENTURY | PDS_SECONDS); + if (newtime == (time_t) -1) + error (1, 0, _("invalid date format %s"), quote (optarg)); + date_set++; + break; + + case TIME_OPTION: /* --time */ + change_times |= XARGMATCH ("--time", optarg, + time_args, time_masks); + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (1); + } + } + + if (change_times == 0) + change_times = CH_ATIME | CH_MTIME; + + if ((use_ref && (posix_date || flexible_date)) + || (posix_date && flexible_date)) + { + error (0, 0, _("cannot specify times from more than one source")); + usage (1); + } + + if (use_ref) + { + if (stat (ref_file, &ref_stats)) + error (1, errno, _("getting attributes of %s"), quote (ref_file)); + date_set++; + } + + /* The obsolescent `MMDDhhmm[YY]' form is valid IFF there are + two or more non-option arguments. */ + if (!date_set && 2 <= argc - optind && !STREQ (argv[optind - 1], "--")) + { + newtime = posixtime (argv[optind], PDS_TRAILING_YEAR); + if (newtime != (time_t) -1) + { + optind++; + date_set++; + } + } + if (!date_set) + { + if ((change_times & (CH_ATIME | CH_MTIME)) == (CH_ATIME | CH_MTIME)) + amtime_now = 1; + else + time (&newtime); + } + + if (optind == argc) + { + error (0, 0, _("file arguments missing")); + usage (1); + } + + for (; optind < argc; ++optind) + err += touch (argv[optind]); + + exit (err != 0); +} diff --git a/src/apps/bin/hd.c b/src/apps/bin/hd.c new file mode 100644 index 0000000000..896c15f1f8 --- /dev/null +++ b/src/apps/bin/hd.c @@ -0,0 +1,206 @@ +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ +// +// Copyright (c) 2001-2002, OpenBeOS +// +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// +// File: hd.c +// Author: Daniel Reinhold (danielre@users.sf.net) +// Description: hex dump utility +// +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ + +#include +#include +#include +#include +#include + + +void do_hd (char *); +void dump_file (FILE *); +void display (uint32, uint8 *); +char *hexbytes (uint8 *); +char *printable (uint8 *); +void usage (); + + +int BytesBetweenSpaces = 1; + + +void +usage () + { + printf ("usage:\thd [-n N] [file]\n"); + puts ("\t-n expects a number between 1 and 16 and specifies"); + puts ("\tthe number of bytes between spaces."); + puts (""); + puts ("\tIf no file is specified, input is read from stdin"); + } + + +int +main (int argc, char *argv[]) + { + char *arg = NULL; + + if (argc == 1) + { + dump_file (stdin); + } + else + { + char *first = *++argv; + + if (strcmp (first, "--help") == 0) + { + usage (); + return 0; + } + + if (strcmp (first, "-n") == 0) + { + if (--argc > 1) + { + char *num = *++argv; + + if (!isdigit (*num)) + printf ("-n option needs a numeric argument\n"); + else + { + int b = atoi (num); + + if (b < 1) b = 1; + if (b > 16) b = 16; + BytesBetweenSpaces = b; + + if (--argc > 1) + arg = *++argv; + else + printf ("no file specified\n"); + } + } + else + printf ("-n option needs a numeric argument\n"); + } + else + arg = first; + + if (arg) + do_hd (arg); + } + + putchar ('\n'); + return 0; + } + + +void +do_hd (char *fname) + { + struct stat e; + + if (stat (fname, &e) == -1) + { + fprintf (stderr, "'%s': no such file or directory\n", fname); + return; + } + + if (S_ISDIR (e.st_mode)) + fprintf (stderr, "'%s' is a directory\n", fname); + else + { + FILE *fp = fopen (fname, "rb"); + if (fp) + { + dump_file (fp); + fclose (fp); + } + else + fprintf (stderr, "'%s': %s\n", fname, strerror (errno)); + } + } + + +void +dump_file (FILE *fp) + { + size_t got; + uint32 offset = 0; + uint8 data[16]; + + while ((got = fread (data, 1, 16, fp)) == 16) + { + display (offset, data); + offset += 16; + } + + if (got > 0) + { + memset (data+got, ' ', 16-got); + display (offset, data); + } + } + + +void +display (uint32 offset, uint8 *data) + { + printf ("%08x ", offset); + printf (" %s ", hexbytes (data)); + printf ("%16s ", printable (data)); + + putchar ('\n'); + } + + +char * +hexbytes (uint8 *s) + { + static char buf[64]; + char *p = buf; + uint8 c; + int i; + int n = 0; + + for (i = 0; i < 16; ++i) + { + c = *s++; + *p++ = "0123456789abcdef"[c/16]; + *p++ = "0123456789abcdef"[c%16]; + + if (++n == BytesBetweenSpaces) + { + *p++ = ' '; + n = 0; + } + + if ((i == 7) && (BytesBetweenSpaces == 1)) + *p++ = ' '; + } + *p++ = ' '; + *p = 0; + + return buf; + } + + +char * +printable (uint8 *s) + { + static char buf[16]; + int n = 16; + char *p = buf; + uint8 c; + + while (n--) + { + c = *s++; + *p++ = (isgraph (c) ? c : '.'); + } + *p = 0; + + return buf; + } diff --git a/src/apps/bin/listarea.c b/src/apps/bin/listarea.c new file mode 100644 index 0000000000..188902ac0d --- /dev/null +++ b/src/apps/bin/listarea.c @@ -0,0 +1,102 @@ +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ +// +// Copyright (c) 2001-2002, OpenBeOS +// +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// +// File: listarea.c +// Author: Daniel Reinhold (danielre@users.sf.net) +// Description: lists area info for all currently running teams +// +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ + +#include +#include +#include + + +void list_area_info (team_id id); +void show_memory_totals (void); + + + +int +main (int argc, char **argv) + { + // + show_memory_totals (); + + if (argc == 1) + { + // list for all teams + int32 cookie = 0; + team_info info; + + while (get_next_team_info (&cookie, &info) >= B_OK) + { + list_area_info (info.team); + } + } + else + // list for each team_id on the command line + while (--argc) + { + list_area_info (atoi (*++argv)); + } + + return 0; + } + + +void +show_memory_totals () + { + int32 max = 0, used = 0, left; + system_info sys; + + if (get_system_info (&sys) == B_OK) + { + // pages are 4KB + max = sys.max_pages * 4; + used = sys.used_pages * 4; + } + + left = max - used; + + printf ("memory: total: %4dKB, used: %4dKB, left: %4dKB\n", max, used, left); + } + + +void +list_area_info (team_id id) + { + int32 cookie = 0; + team_info this_team; + area_info this_area; + + if (get_team_info (id, &this_team) == B_BAD_TEAM_ID) + { + printf ("\nteam %d unknown\n", id); + return; + } + + printf ("\nTEAM %4d (%s):\n", id, this_team.args); + printf (" ID name address size alloc. #-cow #-in #-out\n"); + printf ("--------------------------------------------------------------------------------\n"); + + while (get_next_area_info (id, &cookie, &this_area) == B_OK) + { + printf ("%5d %29s %.8x %8x %8x %5d %5d %5d\n", + this_area.area, + this_area.name, + this_area.address, + this_area.size, + this_area.ram_size, + this_area.copy_count, + this_area.in_count, + this_area.out_count); + } + } + diff --git a/src/apps/bin/listdev/cm_wrapper.c b/src/apps/bin/listdev/cm_wrapper.c new file mode 100644 index 0000000000..9e5bcba92e --- /dev/null +++ b/src/apps/bin/listdev/cm_wrapper.c @@ -0,0 +1,142 @@ +#include +#include +#include +#include + +#include + +#include "config_driver.h" + +static int fd; + +status_t init_cm_wrapper(void) +{ + static const char device[] = "/dev/" CM_DEVICE_NAME; + + fd = open(device, 0); + if (fd < 0) + return errno; + return B_OK; +} + +status_t uninit_cm_wrapper(void) +{ + close(fd); + return B_OK; +} + +status_t get_next_device_info(bus_type bus, uint64 *cookie, + struct device_info *info, uint32 size) +{ + status_t result; + struct cm_ioctl_data params; + + params.magic = CM_GET_NEXT_DEVICE_INFO; + params.bus = bus; + params.cookie = *cookie; + params.data = (void *)info; + params.data_len = size; + + result = ioctl(fd, params.magic, ¶ms, sizeof(params)); + + if (result == B_OK) *cookie = params.cookie; + + return result; +} + +status_t get_device_info_for(uint64 id, struct device_info *info, + uint32 size) +{ + struct cm_ioctl_data params; + + params.magic = CM_GET_DEVICE_INFO_FOR; + params.cookie = id; + params.data = (void *)info; + params.data_len = size; + + return ioctl(fd, params.magic, ¶ms, sizeof(params)); +} + +status_t get_size_of_current_configuration_for(uint64 id) +{ + struct cm_ioctl_data params; + + params.magic = CM_GET_SIZE_OF_CURRENT_CONFIGURATION_FOR; + params.cookie = id; + + return ioctl(fd, params.magic, ¶ms, sizeof(params)); +} + +status_t get_current_configuration_for(uint64 id, + struct device_configuration *current, uint32 size) +{ + struct cm_ioctl_data params; + + params.magic = CM_GET_CURRENT_CONFIGURATION_FOR; + params.cookie = id; + params.data = (void *)current; + params.data_len = size; + + return ioctl(fd, params.magic, ¶ms, sizeof(params)); +} + +status_t get_size_of_possible_configurations_for(uint64 id) +{ + struct cm_ioctl_data params; + + params.magic = CM_GET_SIZE_OF_POSSIBLE_CONFIGURATIONS_FOR; + params.cookie = id; + + return ioctl(fd, params.magic, ¶ms, sizeof(params)); +} + +status_t get_possible_configurations_for(uint64 id, + struct possible_device_configurations *possible, uint32 size) +{ + struct cm_ioctl_data params; + + params.magic = CM_GET_POSSIBLE_CONFIGURATIONS_FOR; + params.cookie = id; + params.data = (void *)possible; + params.data_len = size; + + return ioctl(fd, params.magic, ¶ms, sizeof(params)); +} + + +status_t count_resource_descriptors_of_type( + struct device_configuration *c, resource_type type) +{ + struct cm_ioctl_data params; + + params.magic = CM_COUNT_RESOURCE_DESCRIPTORS_OF_TYPE; + params.config = c; + params.type = type; + + return ioctl(fd, params.magic, ¶ms, sizeof(params)); +} + +status_t get_nth_resource_descriptor_of_type( + struct device_configuration *c, uint32 n, + resource_type type, resource_descriptor *d, uint32 size) +{ + struct cm_ioctl_data params; + + params.magic = CM_GET_NTH_RESOURCE_DESCRIPTOR_OF_TYPE; + params.config = c; + params.n = n; + params.type = type; + params.data = d; + params.data_len = size; + + return ioctl(fd, params.magic, ¶ms, sizeof(params)); +} + +uchar mask_to_value(uint32 mask) +{ + uchar value; + if (!mask) return 0; + for (value=0,mask>>=1;mask;value++,mask>>=1) + ; + return value; +} diff --git a/src/apps/bin/listdev/cm_wrapper.h b/src/apps/bin/listdev/cm_wrapper.h new file mode 100644 index 0000000000..a923105427 --- /dev/null +++ b/src/apps/bin/listdev/cm_wrapper.h @@ -0,0 +1,25 @@ +#ifndef _CM_WRAPPER_H_ +#define _CM_WRAPPER_H_ + +status_t init_cm_wrapper(void); +status_t uninit_cm_wrapper(void); + +status_t get_next_device_info(bus_type bus, uint64 *cookie, + struct device_info *info, uint32 size); +status_t get_device_info_for(uint64 id, struct device_info *info, + uint32 size); +status_t get_size_of_current_configuration_for(uint64 id); +status_t get_current_configuration_for(uint64 id, + struct device_configuration *current, uint32 size); +status_t get_size_of_possible_configurations_for(uint64 id); +status_t get_possible_configurations_for(uint64 id, + struct possible_device_configurations *possible, uint32 size); +status_t count_resource_descriptors_of_type( + struct device_configuration *c, resource_type type); +status_t get_nth_resource_descriptor_of_type( + struct device_configuration *c, uint32 n, resource_type type, + resource_descriptor *d, uint32 size); + +uchar mask_to_value(uint32 mask); + +#endif diff --git a/src/apps/bin/listdev/config_driver.h b/src/apps/bin/listdev/config_driver.h new file mode 100644 index 0000000000..bd70f0411b --- /dev/null +++ b/src/apps/bin/listdev/config_driver.h @@ -0,0 +1,29 @@ +#ifndef _CONFIG_MANAGER_DRIVER_H_ +#define _CONFIG_MANAGER_DRIVER_H_ + +/* the magic is the ioctl */ + +#define CM_GET_NEXT_DEVICE_INFO 'GNDI' +#define CM_GET_DEVICE_INFO_FOR 'GDIF' +#define CM_GET_SIZE_OF_CURRENT_CONFIGURATION_FOR 'GSCC' +#define CM_GET_CURRENT_CONFIGURATION_FOR 'GCCF' +#define CM_GET_SIZE_OF_POSSIBLE_CONFIGURATIONS_FOR 'GSPC' +#define CM_GET_POSSIBLE_CONFIGURATIONS_FOR 'GPCF' + +#define CM_COUNT_RESOURCE_DESCRIPTORS_OF_TYPE 'CRDT' +#define CM_GET_NTH_RESOURCE_DESCRIPTOR_OF_TYPE 'GNRD' + +struct cm_ioctl_data { + uint32 magic; + bus_type bus; + uint64 cookie; + void *config; + uint32 n; + uint32 type; + void *data; + uint32 data_len; +}; + +#define CM_DEVICE_NAME "misc/config" + +#endif diff --git a/src/apps/bin/listdev/listdev.c b/src/apps/bin/listdev/listdev.c new file mode 100644 index 0000000000..97895b914a --- /dev/null +++ b/src/apps/bin/listdev/listdev.c @@ -0,0 +1,305 @@ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "config_driver.h" + +#define NEXT_POSSIBLE(c) \ + (c) = (void *)((uchar *)(c) + sizeof(struct device_configuration) \ + + (c)->num_resources * sizeof(resource_descriptor)); + + +static void +dump_mask(uint32 mask) +{ + bool first = true; + int i = 0; + printf("["); + if (!mask) + printf("none"); + for (;mask;mask>>=1,i++) + if (mask & 1) { + printf("%s%d", first ? "" : ",", i); + first = false; + } + printf("]"); +} + +static void +dump_device_configuration(struct device_configuration *c) +{ + int i, num; + resource_descriptor r; + + num = count_resource_descriptors_of_type(c, B_IRQ_RESOURCE); + if (num) { + printf("irq%s ", (num == 1) ? "" : "s"); + for (i=0;idevtype.base < 13) ? base_desc[info->devtype.base] : "Unknown"); + if (info->devtype.subtype == 0x80) + printf(" (Other)"); + else { + struct subtype_descriptions *s = subtype_desc; + + while (s->name) { + if ((info->devtype.base == s->base) && (info->devtype.subtype == s->subtype)) + break; + s++; + } + printf(" (%s)", (s->name) ? s->name : "Unknown"); + } + printf(" [%x|%x|%x]\n", info->devtype.base, info->devtype.subtype, info->devtype.interface); + + if (!(info->flags & B_DEVICE_INFO_ENABLED)) { + printf("Device is disabled (%s)\n", strerror(info->config_status)); + } else if (info->flags & B_DEVICE_INFO_CONFIGURED) { + printf("Current configuration: "); + dump_device_configuration(current); + } else { + printf("Currently unconfigured.\n"); + } + + printf("%x configurations\n", possible->num_possible); + config = possible->possible + 0; + for (i=0;inum_possible;i++) { + printf("\nPossible configuration #%d: ", i); + dump_device_configuration(config); + NEXT_POSSIBLE(config); + } + + printf("\n"); +} + +static void +dump_isa_info(struct device_info *info) +{ + struct isa_info *isa = (struct isa_info *) + ((uchar *)info + info->bus_dependent_info_offset); + + printf("CSN %x LDN %x %s %s\n", isa->csn, + isa->ldn, isa->card_name, isa->logical_device_name); +} + +static void +dump_pci_info(struct device_info *info) +{ + struct pci_info *pci = (struct pci_info *) + ((uchar *)info + info->bus_dependent_info_offset); + + printf("vendor id: %x, device id: %x\n", pci->vendor_id, pci->device_id); +} + +static void +dump_devices_for_bus(bus_type bus, void (*f)(struct device_info *)) +{ + status_t size; + uint64 cookie; + int index = 0; + void *current, *possible; + struct device_info dummy, *info; + + cookie = 0; + while (get_next_device_info(bus, &cookie, &dummy, sizeof(dummy)) == B_OK) { + info = (struct device_info *)malloc(dummy.size); + if (!info) { + printf("Out of core\n"); + break; + } + + if (get_device_info_for(cookie, info, dummy.size) != B_OK) { + printf("Error getting device information\n"); + break; + } + + size = get_size_of_current_configuration_for(cookie); + if (size < B_OK) { + printf("Error getting the size of the current configuration\n"); + break; + } + current = malloc(size); + if (!current) { + printf("Out of core\n"); + break; + } + + if (get_current_configuration_for(cookie, current, size) != B_OK) { + printf("Error getting the current configuration\n"); + break; + } + + size = get_size_of_possible_configurations_for(cookie); + if (size < B_OK) { + printf("Error getting the size of the possible configurations\n"); + break; + } + possible = malloc(size); + if (!possible) { + printf("Out of core\n"); + break; + } + + if (get_possible_configurations_for(cookie, possible, size) != B_OK) { + printf("Error getting the possible configurations\n"); + break; + } + + switch (info->bus) { + case B_ISA_BUS : printf("ISA"); break; + case B_PCI_BUS : printf("PCI"); break; + default : printf("unknown"); break; + } + printf(" bus, device #%d: ", index++); + + dump_device_info(info, current, possible); + if (f) { + printf("Bus-dependent information:\n"); + (*f)(info); + } + printf("\n"); + + free(possible); + free(current); + free(info); + } +} + +int main() +{ + status_t error; + + if ((error = init_cm_wrapper()) < 0) { + printf("Error initializing configuration manager (%s)\n", strerror(error)); + return error; + } + + dump_devices_for_bus(B_ISA_BUS, dump_isa_info); + dump_devices_for_bus(B_PCI_BUS, dump_pci_info); + + uninit_cm_wrapper(); + + return 0; +} diff --git a/src/apps/bin/listimage.c b/src/apps/bin/listimage.c new file mode 100644 index 0000000000..3e3f449699 --- /dev/null +++ b/src/apps/bin/listimage.c @@ -0,0 +1,79 @@ +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ +// +// Copyright (c) 2001-2002, OpenBeOS +// +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// +// File: listimage.c +// Author: Daniel Reinhold (danielre@users.sf.net) +// Description: lists image info for all currently running teams +// +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ + +#include +#include +#include +#include + + +void list_image_info (team_id id); + + + +int +main (int argc, char **argv) + { + // + if (argc == 1) + { + // list for all teams + int32 cookie = 0; + team_info info; + + while (get_next_team_info (&cookie, &info) >= B_OK) + { + list_image_info (info.team); + } + } + else + // list for each team_id on the command line + while (--argc) + { + list_image_info (atoi (*++argv)); + } + + return 0; + } + + +void +list_image_info (team_id id) + { + int32 cookie = 0; + team_info this_team; + image_info this_image; + + if (get_team_info (id, &this_team) == B_BAD_TEAM_ID) + { + printf ("\nteam %d unknown\n", id); + return; + } + + printf ("\nTEAM %4d (%s):\n", id, this_team.args); + printf (" ID name text data seq# init#\n"); + printf ("--------------------------------------------------------------------------------------------------------\n"); + + while (get_next_image_info (id, &cookie, &this_image) == B_OK) + { + printf ("%5d %64s %.8x %.8x %4d %10u\n", + this_image.id, + this_image.name, + this_image.text, + this_image.data, + this_image.sequence, + this_image.init_order); + } + } + diff --git a/src/apps/bin/listport.c b/src/apps/bin/listport.c new file mode 100644 index 0000000000..1347f57128 --- /dev/null +++ b/src/apps/bin/listport.c @@ -0,0 +1,97 @@ +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ +// +// Copyright (c) 2001-2002, OpenBeOS +// +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// +// File: listport.c +// Author: Daniel Reinhold (danielre@users.sf.net) +// Description: lists all open ports in the system, organized by team +// +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ + +#include +#include +#include + + +void list_team_ports (team_id id); +void show_port_totals (void); + + + +int +main (int argc, char **argv) + { + // + show_port_totals (); + + if (argc == 1) + { + // list for all teams + int32 cookie = 0; + team_info info; + + while (get_next_team_info (&cookie, &info) >= B_OK) + { + list_team_ports (info.team); + } + } + else + // list for each team_id on the command line + while (--argc) + { + list_team_ports (atoi (*++argv)); + } + + return 0; + } + + +void +show_port_totals () + { + int32 max = 0, used = 0, left; + system_info sys; + + if (get_system_info (&sys) == B_OK) + { + max = sys.max_ports; + used = sys.used_ports; + } + + left = max - used; + + printf ("port: total: %5d, used: %5d, left: %5d\n", max, used, left); + } + + +void +list_team_ports (team_id id) + { + int32 cookie = 0; + port_info this_port; + team_info this_team; + + if (get_team_info (id, &this_team) == B_BAD_TEAM_ID) + { + printf ("\nteam %d unknown\n", id); + return; + } + + printf ("\nTEAM %4d (%s):\n", id, this_team.args); + printf (" ID name capacity queued\n"); + printf ("----------------------------------------------------\n"); + + while (get_next_port_info (id, &cookie, &this_port) == B_OK) + { + printf ("%5d %28s %8d %6d\n", + this_port.port, + this_port.name, + this_port.capacity, + this_port.queue_count); + } + } + diff --git a/src/apps/bin/listsem.c b/src/apps/bin/listsem.c new file mode 100644 index 0000000000..5e7cb4f19c --- /dev/null +++ b/src/apps/bin/listsem.c @@ -0,0 +1,91 @@ +/* + * listsem.c + * + * Lists all semaphores in all Teams. + * by O.Siebenmarck. + * + * 04-27-2002 - mmu_man + * added command line args + * + * Legal stuff follows: + + Copyright (c) 2002 Oliver Siebenmarck , OpenBeOS project + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#include +#include + +void list_sems(team_info *tinfo) +{ + sem_info info; + int32 cookie = 0; + + printf("TEAM %d (%s):\n", tinfo->team, tinfo->args ); + printf(" ID name count\n"); + printf("---------------------------------------------\n"); + + while (get_next_sem_info(tinfo->team, &cookie, &info) == B_OK) + { + printf("%7d%31s%7d\n", info.sem ,info.name , info.count ); + } + printf("\n"); +} + +int main(int argc, char **argv) +{ + team_info tinfo; + int32 cook = 0; + int i; + system_info sysinfo; + + // show up some stats first... + get_system_info(&sysinfo); + printf("sem: total: %5i, used: %5i, left: %5i\n\n", sysinfo.max_sems, sysinfo.used_sems, sysinfo.max_sems - sysinfo.used_sems); + + if (argc == 1) { + while (get_next_team_info( &cook, &tinfo) == B_OK) + { + list_sems(&tinfo); + } + return 0; + } + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "-h")) { + fprintf(stderr, "Usage: %s [-s semid] [teamid]\n", argv[0]); + fputs(" List the semaphores allocated by the specified\n", stderr); + fputs(" team, or all teams if none is specified.\n", stderr); + fputs("\n", stderr); + fputs(" The -s option displays the sem_info data for a\n", stderr); + fputs(" specified semaphore.\n", stderr); + return 0; + } else { + int t; + t = atoi(argv[i]); + if (get_team_info(t, &tinfo) == B_OK) + list_sems(&tinfo); + else + printf("team %i unknown\n\n", t); + } + } + return 0; +} + diff --git a/src/apps/bin/mkdos/fat.h b/src/apps/bin/mkdos/fat.h new file mode 100644 index 0000000000..235ca61eb7 --- /dev/null +++ b/src/apps/bin/mkdos/fat.h @@ -0,0 +1,169 @@ +/* + +mkdos shell tool + +Initialize FAT16 or FAT32 partitions, FAT12 floppy disks not supported + +Copyright (c) 2002 Marcus Overhagen , OpenBeOS project + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#define ATTRIBUTE_PACKED __attribute__((packed)) + +struct bootsector1216 { + uint8 BS_jmpBoot[3]; + uint8 BS_OEMName[8]; + uint16 BPB_BytsPerSec; + uint8 BPB_SecPerClus; + uint16 BPB_RsvdSecCnt; + uint8 BPB_NumFATs; + uint16 BPB_RootEntCnt; + uint16 BPB_TotSec16; + uint8 BPB_Media; + uint16 BPB_FATSz16; + uint16 BPB_SecPerTrk; + uint16 BPB_NumHeads; + uint32 BPB_HiddSec; + uint32 BPB_TotSec32; + uint8 BS_DrvNum; + uint8 BS_Reserved1; + uint8 BS_BootSig; + uint8 BS_VolID[4]; + uint8 BS_VolLab[11]; + uint8 BS_FilSysType[8]; + uint8 bootcode[448]; + uint16 signature; +} ATTRIBUTE_PACKED; + +struct bootsector32 { + uint8 BS_jmpBoot[3]; + uint8 BS_OEMName[8]; + uint16 BPB_BytsPerSec; + uint8 BPB_SecPerClus; + uint16 BPB_RsvdSecCnt; + uint8 BPB_NumFATs; + uint16 BPB_RootEntCnt; + uint16 BPB_TotSec16; + uint8 BPB_Media; + uint16 BPB_FATSz16; + uint16 BPB_SecPerTrk; + uint16 BPB_NumHeads; + uint32 BPB_HiddSec; + uint32 BPB_TotSec32; + uint32 BPB_FATSz32; + uint16 BPB_ExtFlags; + uint16 BPB_FSVer; + uint32 BPB_RootClus; + uint16 BPB_FSInfo; + uint16 BPB_BkBootSec; + uint8 BPB_Reserved[12]; + uint8 BS_DrvNum; + uint8 BS_Reserved1; + uint8 BS_BootSig; + uint8 BS_VolID[4]; + uint8 BS_VolLab[11]; + uint8 BS_FilSysType[8]; + uint8 bootcode[420]; + uint16 signature; +} ATTRIBUTE_PACKED; + +struct fsinfosector32 { + uint32 FSI_LeadSig; + uint8 FSI_Reserved1[480]; + uint32 FSI_StrucSig; + uint32 FSI_Free_Count; + uint32 FSI_Nxt_Free; + uint8 FSI_Reserved2[12]; + uint32 FSI_TrailSig; +} ATTRIBUTE_PACKED; + + +// a FAT directory entry +struct dirent { + uint8 Name[11]; + uint8 Attr; + uint8 NTRes; + uint8 CrtTimeTenth; + uint16 CrtTime; + uint16 CrtDate; + uint16 LstAccDate; + uint16 FstClusHI; + uint16 WrtTime; + uint16 WrtDate; + uint16 FstClusLO; + uint32 FileSize; +} ATTRIBUTE_PACKED; + + +//maximum size of a 2,88 MB floppy +#define FLOPPY_MAX_SIZE (2 * 80 * 36 * 512) + +//maximum size of a cluster +#define CLUSTER_MAX_SIZE 32768 + +//not sure if that's correct +#define FAT12_CLUSTER_MAX_SIZE 1024 + +//limits +#define FAT12_MAX_CLUSTER_COUNT 4084LL +#define FAT16_MAX_CLUSTER_COUNT 65524LL +#define FAT32_MAX_CLUSTER_COUNT 0x0fffffffLL + + +#define BOOTJMP_START_OFFSET 0x00 +uint8 bootjmp[] = { + 0xeb, 0x7e, 0x90 +}; + +#define BOOTCODE_START_OFFSET 0x80 +uint8 bootcode[] = { + 0x31, 0xc0, 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0x8e, + 0xd8, 0xb4, 0x0e, 0x31, 0xdb, 0xbe, 0x00, 0x7d, + 0xfc, 0xac, 0x08, 0xc0, 0x74, 0x04, 0xcd, 0x10, + 0xeb, 0xf7, 0xb4, 0x00, 0xcd, 0x16, 0xcd, 0x19, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x53, 0x6f, 0x72, 0x72, 0x79, 0x2c, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x20, 0x64, 0x69, 0x73, 0x6b, + 0x20, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, + 0x62, 0x6f, 0x6f, 0x74, 0x61, 0x62, 0x6c, 0x65, + 0x2e, 0x0d, 0x0a, 0x50, 0x6c, 0x65, 0x61, 0x73, + 0x65, 0x20, 0x70, 0x72, 0x65, 0x73, 0x73, 0x20, + 0x61, 0x6e, 0x79, 0x20, 0x6b, 0x65, 0x79, 0x20, + 0x74, 0x6f, 0x20, 0x72, 0x65, 0x62, 0x6f, 0x6f, + 0x74, 0x2e, 0x0d, 0x0a, 0x00 +}; + +#define BOOT_SECTOR_NUM 0 +#define FSINFO_SECTOR_NUM 1 +#define BACKUP_SECTOR_NUM 6 +#define FAT32_ROOT_CLUSTER 2 + diff --git a/src/apps/bin/mkdos/mkdos.cpp b/src/apps/bin/mkdos/mkdos.cpp new file mode 100644 index 0000000000..b021c0b6d6 --- /dev/null +++ b/src/apps/bin/mkdos/mkdos.cpp @@ -0,0 +1,620 @@ +/* + +mkdos shell tool + +Initialize FAT16 or FAT32 partitions, FAT12 floppy disks not supported + +Copyright (c) 2002 Marcus Overhagen , OpenBeOS project + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fat.h" + +void PrintUsage(); +void CreateVolumeLabel(void *sector, const char *label); +status_t Initialize(int fatbits, const char *device, const char *label, bool noprompt, bool testmode); + +int main(int argc, char *argv[]) +{ + if (sizeof(bootsector1216) != 512 || sizeof(bootsector32) != 512 || sizeof(fsinfosector32) != 512) { + printf("compilation error: struct alignment wrong\n"); + return 1; + } + + const char *device = NULL; + const char *label = NULL; + bool noprompt = false; + bool test = false; + int fat = 0; + + while (1) { + int c; + int option_index = 0; + static struct option long_options[] = + { + {"noprompt", no_argument, 0, 'n'}, + {"test", no_argument, 0, 't'}, + {"fat", required_argument, 0, 'f'}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "ntf:",long_options, &option_index); + if (c == -1) + break; + + switch (c) { + case 'n': + noprompt = true; + break; + + case 't': + test = true; + break; + + case 'f': + fat = strtol(optarg, NULL, 10); + if (fat == 0) + fat = -1; + break; + + default: + printf("\n"); + PrintUsage(); + return 1; + } + } + + if (optind < argc) + device = argv[optind]; + if ((optind + 1) < argc) + label = argv[optind + 1]; + + if (fat != 0 && fat != 12 && fat != 16 && fat != 32) { + printf("mkdos error: fat must be 12, 16, or 32 bits\n"); + PrintUsage(); + return 1; + } + + if (device == NULL) { + printf("mkdos error: you must specify a device or partition\n"); + printf(" such as /dev/disk/ide/ata/1/master/0/0_0\n"); + PrintUsage(); + return 1; + } + + if (label == NULL) { + label = "no name"; + } + + if (noprompt) + printf("will not prompt for confirmation\n"); + + if (test) + printf("test mode enabled (no writes will occur)\n"); + + status_t s; + s = Initialize(fat, device, label, noprompt, test); + + if (s != 0) { + printf("Initializing failed!\n"); + } + + return (s == B_OK) ? 0 : 1; +} + +status_t Initialize(int fatbits, const char *device, const char *label, bool noprompt, bool testmode) +{ + if (fatbits != 0 && fatbits != 12 && fatbits != 16 && fatbits != 32) { + fprintf(stderr,"Error: don't know how to create a %d bit fat\n",fatbits); + return B_ERROR; + } + //XXX the following two checks can be removed when this is fixed: + if (0 != strstr(device,"floppy")) { + fprintf(stderr,"Error: floppy B_GET_GEOMETRY and B_GET_BIOS_GEOMETRY calls are broken, floppy not supported\n"); + return B_ERROR; + } + if (fatbits == 12) { + fprintf(stderr,"Error: can't create a 12 bit fat on a device other than floppy\n"); + return B_ERROR; + } + + printf("device = %s\n",device); + + BFile file(device,B_READ_WRITE); + status_t result = file.InitCheck(); + if (result != B_OK) { + fprintf(stderr,"Error: couldn't open device %s\n",device); + return result; + } + + int fd = file.Dup(); + if (fd < 0) { + fprintf(stderr,"Error: couldn't open file descriptor for device %s\n",device); + return B_ERROR; + } + + bool IsRawDevice; + bool HasBiosGeometry; + bool HasDeviceGeometry; + bool HasPartitionInfo; + device_geometry BiosGeometry; + device_geometry DeviceGeometry; + partition_info PartitionInfo; + + IsRawDevice = 0 != strstr(device,"/raw"); + HasBiosGeometry = B_OK == ioctl(fd,B_GET_BIOS_GEOMETRY,&BiosGeometry); + HasDeviceGeometry = B_OK == ioctl(fd,B_GET_GEOMETRY,&DeviceGeometry); + HasPartitionInfo = B_OK == ioctl(fd,B_GET_PARTITION_INFO,&PartitionInfo); + + if (HasBiosGeometry) { + printf("bios geometry: %ld heads, %ld cylinders, %ld sectors/track, %ld bytes/sector\n", + BiosGeometry.head_count,BiosGeometry.cylinder_count,BiosGeometry.sectors_per_track,BiosGeometry.bytes_per_sector); + } + if (HasBiosGeometry) { + printf("device geometry: %ld heads, %ld cylinders, %ld sectors/track, %ld bytes/sector\n", + DeviceGeometry.head_count,DeviceGeometry.cylinder_count,DeviceGeometry.sectors_per_track,DeviceGeometry.bytes_per_sector); + } + if (HasPartitionInfo) { + printf("partition info: start at %Ld bytes (%Ld sectors), %Ld KB, %Ld MB, %Ld GB\n", + PartitionInfo.offset, + PartitionInfo.offset / 512, + PartitionInfo.offset / 1024, + PartitionInfo.offset / (1024 * 1024), + PartitionInfo.offset / (1024 * 1024 * 1024)); + printf("partition info: size %Ld bytes, %Ld KB, %Ld MB, %Ld GB\n", + PartitionInfo.size, + PartitionInfo.size / 1024, + PartitionInfo.size / (1024 * 1024), + PartitionInfo.size / (1024 * 1024 * 1024)); + } + + if (!HasBiosGeometry && !HasDeviceGeometry && !HasPartitionInfo) { + fprintf(stderr,"Error: couldn't get device partition or geometry information\n"); + close(fd); + return B_ERROR; + } + + if (!IsRawDevice && !HasPartitionInfo) { + fprintf(stderr,"Warning: couldn't get partition information\n"); + } + if ( (HasPartitionInfo && PartitionInfo.logical_block_size != 512) + || (HasBiosGeometry && BiosGeometry.bytes_per_sector != 512) + || (HasDeviceGeometry && DeviceGeometry.bytes_per_sector != 512)) { + fprintf(stderr,"Error: block size not 512 bytes\n"); + close(fd); + return B_ERROR; + } + if (HasDeviceGeometry && DeviceGeometry.read_only) { + fprintf(stderr,"Error: this is a read-only device\n"); + close(fd); + return B_ERROR; + } + if (HasDeviceGeometry && DeviceGeometry.write_once) { + fprintf(stderr,"Error: this is a write-once device\n"); + close(fd); + return B_ERROR; + } + uint64 size = 0; + + if (HasPartitionInfo) { + size = PartitionInfo.size; + } else if (HasDeviceGeometry) { + size = uint64(DeviceGeometry.bytes_per_sector) * DeviceGeometry.sectors_per_track * DeviceGeometry.cylinder_count * DeviceGeometry.head_count; + } else if (HasBiosGeometry) { + size = uint64(BiosGeometry.bytes_per_sector) * BiosGeometry.sectors_per_track * BiosGeometry.cylinder_count * BiosGeometry.head_count; + } + + if (IsRawDevice && size > FLOPPY_MAX_SIZE) { + fprintf(stderr,"Error: device too large for floppy, or raw devices not supported\n"); + close(fd); + return B_ERROR; + } + + printf("size = %Ld bytes (%Ld sectors), %Ld KB, %Ld MB, %Ld GB\n", + size, + size / 512, + size / 1024, + size / (1024 * 1024), + size / (1024 * 1024 * 1024)); + + if (fatbits == 0) { + //auto determine fat type + if (IsRawDevice && size <= FLOPPY_MAX_SIZE && (size / FAT12_CLUSTER_MAX_SIZE) < FAT12_MAX_CLUSTER_COUNT) { + fatbits = 12; + } else if ((size / CLUSTER_MAX_SIZE) < FAT16_MAX_CLUSTER_COUNT) { + fatbits = 16; + } else if ((size / CLUSTER_MAX_SIZE) < FAT32_MAX_CLUSTER_COUNT) { + fatbits = 32; + } + } + + if (fatbits == 0) { + fprintf(stderr,"Error: device too large for 32 bit fat\n"); + close(fd); + return B_ERROR; + } + + int SectorPerCluster; + + SectorPerCluster = 0; + if (fatbits == 12) { + SectorPerCluster = 0; + if (size <= 4182016LL) + SectorPerCluster = 2; // XXX don't know the correct value + if (size <= 2091008LL) + SectorPerCluster = 1; // XXX don't know the correct value + } else if (fatbits == 16) { + // special BAD_CLUSTER value is 0xFFF7, + // but this should work anyway, since space required by + // two FATs will make maximum cluster count smaller. + // at least, this is what I think *should* happen + SectorPerCluster = 0; //larger than 2 GB must fail + if (size <= (2048 * 1024 * 1024LL)) // up to 2GB, use 32k clusters + SectorPerCluster = 64; + if (size <= (1024 * 1024 * 1024LL)) // up to 1GB, use 16k clusters + SectorPerCluster = 32; + if (size <= (512 * 1024 * 1024LL)) // up to 512MB, use 8k clusters + SectorPerCluster = 16; + if (size <= (256 * 1024 * 1024LL)) // up to 256MB, use 4k clusters + SectorPerCluster = 8; + if (size <= (128 * 1024 * 1024LL)) // up to 128MB, use 2k clusters + SectorPerCluster = 4; + if (size <= (16 * 1024 * 1024LL)) // up to 16MB, use 2k clusters + SectorPerCluster = 2; + if (size <= 4182016LL) // smaller than fat32 must fail + SectorPerCluster = 0; + } if (fatbits == 32) { + SectorPerCluster = 64; // default is 32k clusters + if (size <= (32 * 1024 * 1024 * 1024LL)) // up to 32GB, use 16k clusters + SectorPerCluster = 32; + if (size <= (16 * 1024 * 1024 * 1024LL)) // up to 16GB, use 8k clusters + SectorPerCluster = 16; + if (size <= (8 * 1024 * 1024 * 1024LL)) // up to 8B, use 4k clusters + SectorPerCluster = 8; + if (size <= (532480 * 512LL)) // up to 260 MB, use 0.5k clusters + SectorPerCluster = 1; + if (size <= (66600 * 512LL)) // smaller than 32.5 MB must fail + SectorPerCluster = 0; + } + + if (SectorPerCluster == 0) { + fprintf(stderr,"Error: failed to determine sector per cluster value, partition too large for %d bit fat\n",fatbits); + close(fd); + return B_ERROR; + } + + int ReservedSectorCount = 0; // avoid compiler warning + int RootEntryCount = 0; // avoid compiler warning + int NumFATs; + int SectorSize; + uint8 BiosDriveId; + + // get bios drive-id, or use 0x80 + if (B_OK != ioctl(fd,B_GET_BIOS_DRIVE_ID,&BiosDriveId)) { + BiosDriveId = 0x80; + } else { + printf("bios drive id: 0x%02x\n",(int)BiosDriveId); + } + + // default parameters for the bootsector + NumFATs = 2; + SectorSize = 512; + if (fatbits == 12 || fatbits == 16) + ReservedSectorCount = 1; + if (fatbits == 32) + ReservedSectorCount = 32; + if (fatbits == 12) + RootEntryCount = 128; // XXX don't know the correct value + if (fatbits == 16) + RootEntryCount = 512; + if (fatbits == 32) + RootEntryCount = 0; + + // Determine FATSize + // calculation done as MS recommends + uint64 DskSize = size / SectorSize; + uint32 RootDirSectors = ((RootEntryCount * 32) + (SectorSize - 1)) / SectorSize; + uint64 TmpVal1 = DskSize - (ReservedSectorCount + RootDirSectors); + uint64 TmpVal2 = (256 * SectorPerCluster) + NumFATs; + if (fatbits == 32) + TmpVal2 = TmpVal2 / 2; + uint32 FATSize = (TmpVal1 + (TmpVal2 - 1)) / TmpVal2; + // FATSize should now contain the size of *one* FAT, measured in sectors + // RootDirSectors should now contain the size of the fat12/16 root directory, measured in sectors + + printf("fatbits = %d, clustersize = %d\n",fatbits,SectorPerCluster * 512); + printf("FAT size is %ld sectors\n",FATSize); + printf("disk label: %s\n",label); + + char bootsector[512]; + memset(bootsector,0x00,512); + memcpy(bootsector + BOOTJMP_START_OFFSET,bootjmp,sizeof(bootjmp)); + memcpy(bootsector + BOOTCODE_START_OFFSET,bootcode,sizeof(bootcode)); + + if (fatbits == 32) { + bootsector32 *bs = (bootsector32 *)bootsector; + uint16 temp16; + uint32 temp32; + memcpy(bs->BS_OEMName,"OpenBeOS",8); + bs->BPB_BytsPerSec = B_HOST_TO_LENDIAN_INT16(SectorSize); + bs->BPB_SecPerClus = SectorPerCluster; + bs->BPB_RsvdSecCnt = B_HOST_TO_LENDIAN_INT16(ReservedSectorCount); + bs->BPB_NumFATs = NumFATs; + bs->BPB_RootEntCnt = B_HOST_TO_LENDIAN_INT16(RootEntryCount); + bs->BPB_TotSec16 = B_HOST_TO_LENDIAN_INT16(0); + bs->BPB_Media = 0xF8; + bs->BPB_FATSz16 = B_HOST_TO_LENDIAN_INT16(0); + temp16 = HasBiosGeometry ? BiosGeometry.sectors_per_track : 63; + bs->BPB_SecPerTrk = B_HOST_TO_LENDIAN_INT16(temp16); + temp16 = HasBiosGeometry ? BiosGeometry.head_count : 255; + bs->BPB_NumHeads = B_HOST_TO_LENDIAN_INT16(temp16); + temp32 = HasPartitionInfo ? (PartitionInfo.size / 512) : 0; + bs->BPB_HiddSec = B_HOST_TO_LENDIAN_INT32(temp32); + temp32 = size / 512; + bs->BPB_TotSec32 = B_HOST_TO_LENDIAN_INT32(temp32); + bs->BPB_FATSz32 = B_HOST_TO_LENDIAN_INT32(FATSize); + bs->BPB_ExtFlags = B_HOST_TO_LENDIAN_INT16(0); + bs->BPB_FSVer = B_HOST_TO_LENDIAN_INT16(0); + bs->BPB_RootClus = B_HOST_TO_LENDIAN_INT32(FAT32_ROOT_CLUSTER); + bs->BPB_FSInfo = B_HOST_TO_LENDIAN_INT16(FSINFO_SECTOR_NUM); + bs->BPB_BkBootSec = B_HOST_TO_LENDIAN_INT16(BACKUP_SECTOR_NUM); + memset(bs->BPB_Reserved,0,12); + bs->BS_DrvNum = BiosDriveId; + bs->BS_Reserved1 = 0x00; + bs->BS_BootSig = 0x29; + *(uint32*)bs->BS_VolID = (uint32)system_time(); + memcpy(bs->BS_VolLab,"NO NAME ",11); + memcpy(bs->BS_FilSysType,"FAT32 ",8); + bs->signature = B_HOST_TO_LENDIAN_INT16(0xAA55); + } else { + bootsector1216 *bs = (bootsector1216 *)bootsector; + uint16 temp16; + uint32 temp32; + uint32 sectorcount = size / 512; + memcpy(bs->BS_OEMName,"OpenBeOS",8); + bs->BPB_BytsPerSec = B_HOST_TO_LENDIAN_INT16(SectorSize); + bs->BPB_SecPerClus = SectorPerCluster; + bs->BPB_RsvdSecCnt = B_HOST_TO_LENDIAN_INT16(ReservedSectorCount); + bs->BPB_NumFATs = NumFATs; + bs->BPB_RootEntCnt = B_HOST_TO_LENDIAN_INT16(RootEntryCount); + temp16 = (sectorcount <= 65535) ? sectorcount : 0; + bs->BPB_TotSec16 = B_HOST_TO_LENDIAN_INT16(temp16); + bs->BPB_Media = 0xF8; + bs->BPB_FATSz16 = B_HOST_TO_LENDIAN_INT16(FATSize); + temp16 = HasBiosGeometry ? BiosGeometry.sectors_per_track : 63; + bs->BPB_SecPerTrk = B_HOST_TO_LENDIAN_INT16(temp16); + temp16 = HasBiosGeometry ? BiosGeometry.head_count : 255; + bs->BPB_NumHeads = B_HOST_TO_LENDIAN_INT16(temp16); + temp32 = HasPartitionInfo ? (PartitionInfo.size / 512) : 0; + bs->BPB_HiddSec = B_HOST_TO_LENDIAN_INT32(temp32); + temp32 = (sectorcount <= 65535) ? 0 : sectorcount; + bs->BPB_TotSec32 = B_HOST_TO_LENDIAN_INT32(temp32); + bs->BS_DrvNum = BiosDriveId; + bs->BS_Reserved1 = 0x00; + bs->BS_BootSig = 0x29; + *(uint32*)bs->BS_VolID = (uint32)system_time(); + memcpy(bs->BS_VolLab,"NO NAME ",11); + memcpy(bs->BS_FilSysType,(fatbits == 12) ? "FAT12 " : "FAT16 ",8); + bs->signature = B_HOST_TO_LENDIAN_INT16(0xAA55); + } + + if (!noprompt) { + printf("\n"); + printf("Initializing will erase all existing data on the drive.\n"); + printf("Do you wish to proceed? "); + char answer[1000]; + scanf("%s",answer); //XXX who wants to fix this buffer overflow? + if (0 != strcasecmp(answer,"yes")) { + printf("drive NOT initialized\n"); + close(fd); + return B_OK; + } + } + if (testmode) { + close(fd); + return B_OK; + } + + // Disk layout: + // 0) reserved sectors, this includes the bootsector, fsinfosector and bootsector backup + // 1) FAT + // 2) root directory (not on fat32) + // 3) file & directory data + + ssize_t written; + + // initialize everything with zero first + // avoid doing 512 byte writes here, they are slow + printf("Writing FAT\n"); + char * zerobuffer = (char *)malloc(65536); + memset(zerobuffer,0,65536); + int64 bytes_to_write = 512LL * (ReservedSectorCount + (NumFATs * FATSize) + RootDirSectors); + int64 pos = 0; + while (bytes_to_write > 0) { + ssize_t writesize = min_c(bytes_to_write,65536); + written = file.WriteAt(pos,zerobuffer,writesize); + if (written != writesize) { + fprintf(stderr,"Error: write error near sector %Ld\n",pos / 512); + close(fd); + return B_ERROR; + } + bytes_to_write -= writesize; + pos += writesize; + } + free(zerobuffer); + + //write boot sector + printf("Writing boot block\n"); + written = file.WriteAt(BOOT_SECTOR_NUM * 512,bootsector,512); + if (written != 512) { + fprintf(stderr,"Error: write error at sector %d\n",BOOT_SECTOR_NUM); + close(fd); + return B_ERROR; + } + + if (fatbits == 32) { + written = file.WriteAt(BACKUP_SECTOR_NUM * 512,bootsector,512); + if (written != 512) { + fprintf(stderr,"Error: write error at sector %d\n",BACKUP_SECTOR_NUM); + close(fd); + return B_ERROR; + } + } + + //write first fat sector + printf("Writing first FAT sector\n"); + uint8 sec[512]; + memset(sec,0,512); + if (fatbits == 12) { + //FAT[0] contains media byte in lower 8 bits, all other bits set to 1 + //FAT[1] contains EOF marker + sec[0] = 0xF8; + sec[1] = 0xFF; + sec[2] = 0xFF; + } else if (fatbits == 16) { + //FAT[0] contains media byte in lower 8 bits, all other bits set to 1 + sec[0] = 0xF8; + sec[1] = 0xFF; + //FAT[1] contains EOF marker + sec[2] = 0xFF; + sec[3] = 0xFF; + } else if (fatbits == 32) { + //FAT[0] contains media byte in lower 8 bits, all other bits set to 1 + sec[0] = 0xF8; + sec[1] = 0xFF; + sec[2] = 0xFF; + sec[3] = 0xFF; + //FAT[1] contains EOF marker + sec[4] = 0xFF; + sec[5] = 0xFF; + sec[6] = 0xFF; + sec[7] = 0x0F; + //FAT[2] contains EOF marker, used to terminate root directory + sec[8] = 0xFF; + sec[9] = 0xFF; + sec[10] = 0xFF; + sec[11] = 0x0F; + } + written = file.WriteAt(ReservedSectorCount * 512,sec,512); + if (written != 512) { + fprintf(stderr,"Error: write error at sector %d\n",ReservedSectorCount); + close(fd); + return B_ERROR; + } + if (NumFATs > 1) { + written = file.WriteAt((ReservedSectorCount + FATSize) * 512,sec,512); + if (written != 512) { + fprintf(stderr,"Error: write error at sector %ld\n",ReservedSectorCount + FATSize); + close(fd); + return B_ERROR; + } + } + + //write fsinfo sector + if (fatbits == 32) { + printf("Writing boot info\n"); + //calculate total sector count first + uint64 free_count = size / 512; + //now account for already by metadata used sectors + free_count -= ReservedSectorCount + (NumFATs * FATSize) + RootDirSectors; + //convert from sector to clustercount + free_count /= SectorPerCluster; + //and account for 1 already used cluster of root directory + free_count -= 1; + fsinfosector32 fsinfosector; + memset(&fsinfosector,0x00,512); + fsinfosector.FSI_LeadSig = B_HOST_TO_LENDIAN_INT32(0x41615252); + fsinfosector.FSI_StrucSig = B_HOST_TO_LENDIAN_INT32(0x61417272); + fsinfosector.FSI_Free_Count = B_HOST_TO_LENDIAN_INT32((uint32)free_count); + fsinfosector.FSI_Nxt_Free = B_HOST_TO_LENDIAN_INT32(3); + fsinfosector.FSI_TrailSig = B_HOST_TO_LENDIAN_INT32(0xAA550000); + written = file.WriteAt(FSINFO_SECTOR_NUM * 512,&fsinfosector,512); + if (written != 512) { + fprintf(stderr,"Error: write error at sector %d\n",FSINFO_SECTOR_NUM); + close(fd); + return B_ERROR; + } + } + + //write volume label into root directory + printf("Writing root directory\n"); + if (fatbits == 12 || fatbits == 16) { + uint8 data[512]; + memset(data,0,512); + CreateVolumeLabel(data,label); + uint32 RootDirSector = ReservedSectorCount + (NumFATs * FATSize); + written = file.WriteAt(RootDirSector * 512,data,512); + if (written != 512) { + fprintf(stderr,"Error: write error at sector %ld\n",RootDirSector); + close(fd); + return B_ERROR; + } + } else if (fatbits == 32) { + int size = 512 * SectorPerCluster; + uint8 *cluster = (uint8*)malloc(size); + memset(cluster,0,size); + CreateVolumeLabel(cluster,label); + uint32 RootDirSector = ReservedSectorCount + (NumFATs * FATSize) + RootDirSectors; + written = file.WriteAt(RootDirSector * 512,cluster,size); + free(cluster); + if (written != size) { + fprintf(stderr,"Error: write error at sector %ld\n",RootDirSector); + close(fd); + return B_ERROR; + } + } + + ioctl(fd,B_FLUSH_DRIVE_CACHE); + close(fd); + + return B_OK; +} + +void CreateVolumeLabel(void *sector, const char *label) +{ + // create a volume name directory entry in the 512 byte sector + // XXX convert from UTF8, and check for valid characters + // XXX this could be changed to use long file name entrys, + // XXX but the dosfs would have to be updated, too + + dirent *d = (dirent *)sector; + memset(d,0,sizeof(*d)); + memset(d->Name,0x20,11); + memcpy(d->Name,label,min_c(11,strlen(label))); + d->Attr = 0x08; +} + +void PrintUsage() +{ + printf("\n"); + printf("usage: mkdos [-n] [-t] [-f 12|16|32] device [volume_label]\n"); + printf(" -n, --noprompt do not prompt before writing\n"); + printf(" -t, --test enable test mode (will not write to disk)\n"); + printf(" -f, --fat use FAT entries of the specified size\n"); +} diff --git a/src/apps/bin/pc/lex.h b/src/apps/bin/pc/lex.h new file mode 100644 index 0000000000..a1d29cb069 --- /dev/null +++ b/src/apps/bin/pc/lex.h @@ -0,0 +1,32 @@ +#define PLUS '+' +#define MINUS '-' +#define OR '|' +#define SHIFT_L '<' +#define SHIFT_R '>' + +#define TIMES '*' +#define DIVISION '/' +#define MODULO '%' +#define AND '&' +#define XOR '^' + +#define NEGATIVE '-' +#define BANG '!' +#define TWIDDLE '~' + +#define NOTHING '\0' + +#define LPAREN '(' +#define RPAREN ')' + +#define EQUAL '=' + +#define LESS_THAN '<' +#define GREATER_THAN '>' + +#define SEMI_COLON ';' +#define COMMA ',' + +#define SINGLE_QUOTE '\'' + +#define USE_LAST_RESULT '.' diff --git a/src/apps/bin/pc/pc.c b/src/apps/bin/pc/pc.c new file mode 100644 index 0000000000..2c2192cc68 --- /dev/null +++ b/src/apps/bin/pc/pc.c @@ -0,0 +1,1113 @@ +/* + PC -- programmer's calculator. + + This program implements a simple recursive descent parser that +understands pretty much all standard C language math and logic +expressions. It handles the usual add, subtract, multiply, divide, +and mod sort of stuff. It can also deal with logical/relational +operations and expressions. The logic/relational operations AND, OR, +NOT, and EXCLUSIVE OR, &&, ||, ==, !=, <, >, <=, and >= are all +supported. It also handles parens and nested expresions as well as +left and right shifts. There are variables and assignments (as well +as assignment operators like "*="). + + The other useful feature is that you can use "." in an expression +to refer to the value from the previous expression (just like bc). + + Multiple statements can be separated by semi-colons (;) on a single +line (though a single statement can't span multiple lines). + + This calculator is mainly a programmers calculator because it +doesn't work in floating point and only deals with integers. + + I wrote this because the standard unix calculator (bc) doesn't +offer a useful modulo, it doesn't have left and right shifts and +sometimes it is a pain in the ass to use (but I still use bc for +things that require any kind of floating point). This program is +great when you have to do address calculations and bit-wise +masking/shifting as you do when working on kernel type code. It's +also handy for doing quick conversions between decimal, hex and ascii +(and if you want to see octal for some reason, just put it in the +printf string). + + The parser is completely separable and could be spliced into other +code very easy. The routine parse_expression() just expects a char +pointer and returns the value. Implementing command line editing +would be easy using a readline() type of library. + + This isn't the world's best parser or anything, but it works and +suits my needs. It faithfully implements C style precedence of +operators for: + + ++ -- ~ ! * / % + - << >> < > <= >= == != & ^ | && || + +(in that order, from greatest to least precedence). + + Note: The ! unary operator is a logical negation, not a bitwise +negation (if you want bitwise negation, use ~). + + I've been working on adding variables and assignments, and I've +just (10/26/94) got it working right and with code I'm not ashamed of. +Now you can have variables (no restrictions on length) and assign to +them and use them in expressions. Variable names have the usual C +rules (i.e. alpha or underscore followed by alpha-numeric and +underscore). Variables are initialized to zero and created as needed. +You can have any number of variables. Here are some examples: + + x = 5 + x = y = 10 + x = (y + 5) * 2 + (y * 2) + (x & 0xffeef) + + + Assignment operators also work. The allowable assignment operators +are (just as in C): + + +=, -=, *=, /=, %=, &=, ^=, |=, <<=, and >>= + + + The basic ideas for this code came from the book "Compiler Design +in C", by Allen I. Holub, but I've extended them significantly. + + If you find bugs or parsing bogosites, I'd like to know about them +so I can fix them. Other comments and criticism of the code are +welcome as well. + + Thanks go to Joel Tesler (joel@engr.sgi.com) for adding the ability +to pass command line arguments and have pc evaluate them instead of reading +from stdin. + + Dominic Giampaolo + dbg@be.com (though this was written while I was at sgi) + */ +#include +#include +#include +#include +#include +#include "lex.h" + + +/* + * You should #define USE_LONG_LONG if your compiler supports the long long + * data type, has strtoull(), and a %lld conversion specifier for printf. + * Otherwise just comment out the #define and pc will use plain longs. + */ + +#define USE_LONG_LONG + + +#ifdef USE_LONG_LONG +#define LONG long long +#define ULONG unsigned long long +#define STRTOUL strtoull +#define STR1 "%20llu 0x%.16llx signed: %20lld" +#define STR2 "%20llu 0x%.16llx" +#define STR3 " char: " +#define STR4 "%20lu 0x%-16.8lx signed: %20ld" +#define STR5 "%20lu 0x%-16.8lx" +#else +#define LONG long +#define ULONG unsigned long +#define STRTOUL strtoul +#define STR1 "%10lu\t 0x%.8lx\t signed: %10ld" +#define STR2 "%10lu\t 0x%.8lx" +#define STR3 " char: " +#define STR4 STR1 +#define STR5 STR2 +#endif + + +ULONG parse_expression(char *str); /* top-level interface to parser */ +ULONG assignment_expr(char **str); /* assignments =, +=, *=, etc */ +ULONG do_assignment_operator(char **str, char *var_name); +ULONG logical_or_expr(char **str); /* logical OR `||' */ +ULONG logical_and_expr(char **str); /* logical AND `&&' */ +ULONG or_expr(char **str); /* OR `|' */ +ULONG xor_expr(char **str); /* XOR `^' */ +ULONG and_expr(char **str); /* AND `&' */ +ULONG equality_expr(char **str); /* equality ==, != */ +ULONG relational_expr(char **str); /* relational <, >, <=, >= */ +ULONG shift_expr(char **str); /* shifts <<, >> */ +ULONG add_expression(char **str); /* addition/subtraction +, - */ +ULONG term(char **str); /* multiplication/division *,%,/ */ +ULONG factor(char **str); /* negation, logical not ~, ! */ +ULONG get_value(char **str); +int get_var(char *name, ULONG *val); /* external interfaces to vars */ +ULONG set_var(char *name, ULONG val); + +void do_input(void); /* reads stdin and calls parser */ +char *skipwhite(char *str); /* skip over input white space */ + + + +/* + * Variables are kept in a simple singly-linked list. Not high + * performance, but it's also an extremely small implementation. + * + * New variables get added to the head of the list. Variables are + * never deleted, though it wouldn't be hard to do that. + * + */ +typedef struct variable +{ + char *name; + ULONG value; + struct variable *next; +}variable; + +variable dummy = { NULL, 0L, NULL }; +variable *vars=&dummy; + +variable *lookup_var(char *name); +variable *add_var(char *name, ULONG value); +char *get_var_name(char **input_str); +void parse_args(int argc, char *argv[]); +int (*set_var_lookup_hook(int (*func)(char *name, ULONG *val))) + (char *name, ULONG *val); + +/* + * last_result is equal to the result of the last expression and + * expressions can refer to it as `.' (just like bc). + */ +ULONG last_result = 0; + + +int +special_vars(char *name, ULONG *val) +{ + if (strcmp(name, "time") == 0) + *val = (ULONG)time(NULL); + else if (strcmp(name, "rand") == 0) + *val = (ULONG)rand(); + else if (strcmp(name, "dbg") == 0) + *val = 0x82969; + else + return 0; + + return 1; +} + + +int +main(int argc, char *argv[]) +{ + + set_var_lookup_hook(special_vars); + + if (argc > 1) + parse_args(argc, argv); + else + do_input(); + + return 0; +} + +/* + This function prints the result of the expression. + It tries to be smart about printing numbers so it + only uses the necessary number of digits. If you + have long long (i.e. 64 bit numbers) it's very + annoying to have lots of leading zeros when they + aren't necessary. By doing the somewhat bizarre + casting and comparisons we can determine if a value + will fit in a 32 bit quantity and only print that. +*/ +void +print_result(ULONG value) +{ + int i; + ULONG ch, shift; + + if ((signed LONG)value < 0) + { + if ((signed LONG)value < (signed LONG)(LONG_MIN)) + printf(STR1, value, value, value); + else + printf(STR4, (long)value, (long)value, (long)value); + } + else if ((ULONG)value <= (ULONG)ULONG_MAX) + printf(STR5, (long)value, (long)value); + else + printf(STR2, value, value); + + /* + Print any printable character (and print dots for unprintable chars + */ + printf(STR3); + for(i=sizeof(ULONG)-1; i >= 0; i--) + { + shift = i * 8; + ch = ((ULONG)value & ((ULONG)0xff << shift)) >> shift; + + if (isprint((int)ch)) + printf("%c", (char)(ch)); + else + printf("."); + } + + printf("\n"); +} + +void +parse_args(int argc, char *argv[]) +{ + int i, len; + char *buff, *fmt_str; + ULONG value; + + for(i=1, len=0; i < argc; i++) + len += strlen(argv[i]); + len++; + + buff = malloc(len*sizeof(char)); + if (buff == NULL) + return; + + buff[0] = '\0'; + while (--argc > 0) + { + strcat(buff, *++argv); + } + value = parse_expression(buff); + + print_result(value); + + free(buff); +} + +void +do_input(void) +{ + int ret; + ULONG value; + char buff[256], *ptr; + + while(fgets(buff, 256, stdin) != NULL) + { + if (buff[strlen(buff)-1] == '\n') + buff[strlen(buff)-1] = '\0'; /* kill the newline character */ + + for(ptr=buff; isspace(*ptr) && *ptr; ptr++) + /* skip whitespace */; + + if (*ptr == '\0') /* hmmm, an empty line, just skip it */ + continue; + + value = parse_expression(buff); + + print_result(value); + } +} + + +ULONG +parse_expression(char *str) +{ + ULONG val; + char *ptr = str; + + ptr = skipwhite(ptr); + if (*ptr == '\0') + return last_result; + + val = assignment_expr(&ptr); + + ptr = skipwhite(ptr); + while (*ptr == SEMI_COLON && *ptr != '\0') + { + ptr++; + if (*ptr == '\0') /* reached the end of the string, stop parsing */ + continue; + + val = assignment_expr(&ptr); + } + + last_result = val; + return val; +} + + +ULONG +assignment_expr(char **str) +{ + ULONG val, sum = 0; + char op, *orig_str; + char *var_name; + variable *v; + + *str = skipwhite(*str); + orig_str = *str; + + var_name = get_var_name(str); + + *str = skipwhite(*str); + if (**str == EQUAL && *(*str+1) != EQUAL) + { + *str = skipwhite(*str + 1); /* skip the equal sign */ + + val = assignment_expr(str); /* go recursive! */ + + if ((v = lookup_var(var_name)) == NULL) + add_var(var_name, val); + else + v->value = val; + } + else if (((**str == PLUS || **str == MINUS || **str == OR || + **str == TIMES || **str == DIVISION || **str == MODULO || + **str == AND || **str == XOR) && *(*str+1) == EQUAL) || + strncmp(*str, "<<=", 3) == 0 || strncmp(*str, ">>=", 3) == 0) + { + val = do_assignment_operator(str, var_name); + } + else + { + *str = orig_str; + val = logical_or_expr(str); /* no equal sign, just get var value */ + + *str = skipwhite(*str); + if (**str == EQUAL) + { + fprintf(stderr, "Left hand side of expression is not assignable.\n"); + } + } + + if (var_name) + free(var_name); + + return val; +} + + +ULONG +do_assignment_operator(char **str, char *var_name) +{ + ULONG val; + variable *v; + char operator; + + operator = **str; + + if (operator == SHIFT_L || operator == SHIFT_R) + *str = skipwhite(*str + 3); + else + *str = skipwhite(*str + 2); /* skip the assignment operator */ + + val = assignment_expr(str); /* go recursive! */ + + v = lookup_var(var_name); + if (v == NULL) + { + v = add_var(var_name, 0); + if (v == NULL) + return 0; + } + + if (operator == PLUS) + v->value += val; + else if (operator == MINUS) + v->value -= val; + else if (operator == AND) + v->value &= val; + else if (operator == XOR) + v->value ^= val; + else if (operator == OR) + v->value |= val; + else if (operator == SHIFT_L) + v->value <<= val; + else if (operator == SHIFT_R) + v->value >>= val; + else if (operator == TIMES) + v->value *= val; + else if (operator == DIVISION) + { + if (val == 0) /* check for it, but still get the result */ + fprintf(stderr, "Divide by zero!\n"); + + v->value /= val; + } + else if (operator == MODULO) + { + if (val == 0) /* check for it, but still get the result */ + fprintf(stderr, "Modulo by zero!\n"); + + v->value %= val; + } + else + { + fprintf(stderr, "Unknown operator: %c\n", operator); + v->value = 0; + } + + return v->value; +} + + +ULONG +logical_or_expr(char **str) +{ + ULONG val, sum = 0; + + *str = skipwhite(*str); + + sum = logical_and_expr(str); + + *str = skipwhite(*str); + while(**str == OR && *(*str + 1) == OR) + { + *str = skipwhite(*str + 2); /* advance over the operator */ + + val = logical_and_expr(str); + + sum = (val || sum); + } + + return sum; +} + + + +ULONG +logical_and_expr(char **str) +{ + ULONG val, sum = 0; + + *str = skipwhite(*str); + + sum = or_expr(str); + + *str = skipwhite(*str); + while(**str == AND && *(*str + 1) == AND) + { + *str = skipwhite(*str + 2); /* advance over the operator */ + + val = or_expr(str); + + sum = (val && sum); + } + + return sum; +} + + +ULONG +or_expr(char **str) +{ + ULONG val, sum = 0; + + *str = skipwhite(*str); + + sum = xor_expr(str); + + *str = skipwhite(*str); + while(**str == OR && *(*str+1) != OR) + { + *str = skipwhite(*str + 1); /* advance over the operator */ + + val = xor_expr(str); + + sum |= val; + } + + return sum; +} + + + +ULONG +xor_expr(char **str) +{ + ULONG val, sum = 0; + + *str = skipwhite(*str); + + sum = and_expr(str); + + *str = skipwhite(*str); + while(**str == XOR) + { + *str = skipwhite(*str + 1); /* advance over the operator */ + + val = and_expr(str); + + sum ^= val; + } + + return sum; +} + + + +ULONG +and_expr(char **str) +{ + ULONG val, sum = 0; + + *str = skipwhite(*str); + + sum = equality_expr(str); + + *str = skipwhite(*str); + while(**str == AND && *(*str+1) != AND) + { + *str = skipwhite(*str + 1); /* advance over the operator */ + + val = equality_expr(str); + + sum &= val; + } + + return sum; +} + + +ULONG +equality_expr(char **str) +{ + ULONG val, sum = 0; + char op; + + *str = skipwhite(*str); + + sum = relational_expr(str); + + *str = skipwhite(*str); + while((**str == EQUAL && *(*str+1) == EQUAL) || + (**str == BANG && *(*str+1) == EQUAL)) + { + op = **str; + + *str = skipwhite(*str + 2); /* advance over the operator */ + + val = relational_expr(str); + + if (op == EQUAL) + sum = (sum == val); + else if (op == BANG) + sum = (sum != val); + } + + return sum; +} + + +ULONG +relational_expr(char **str) +{ + ULONG val, sum = 0; + char op, equal_to=0; + + *str = skipwhite(*str); + + sum = shift_expr(str); + + *str = skipwhite(*str); + while(**str == LESS_THAN || **str == GREATER_THAN) + { + equal_to = 0; + op = **str; + + if (*(*str+1) == EQUAL) + { + equal_to = 1; + *str = *str+1; /* skip initial operator */ + } + + *str = skipwhite(*str + 1); /* advance over the operator */ + + val = shift_expr(str); + + /* + Notice that we do the relational expressions as signed + comparisons. This is because of expressions like: + 0 > -1 + which would not return the expected value if we did the + comparison as unsigned. This may not always be the + desired behavior, but aside from adding casting to epxressions, + there isn't much of a way around it. + */ + if (op == LESS_THAN && equal_to == 0) + sum = ((LONG)sum < (LONG)val); + else if (op == LESS_THAN && equal_to == 1) + sum = ((LONG)sum <= (LONG)val); + else if (op == GREATER_THAN && equal_to == 0) + sum = ((LONG)sum > (LONG)val); + else if (op == GREATER_THAN && equal_to == 1) + sum = ((LONG)sum >= (LONG)val); + } + + return sum; +} + + +ULONG +shift_expr(char **str) +{ + ULONG val, sum = 0; + char op; + + *str = skipwhite(*str); + + sum = add_expression(str); + + *str = skipwhite(*str); + while((strncmp(*str, "<<", 2) == 0) || (strncmp(*str, ">>", 2) == 0)) + { + op = **str; + + *str = skipwhite(*str + 2); /* advance over the operator */ + + val = add_expression(str); + + if (op == SHIFT_L) + sum <<= val; + else if (op == SHIFT_R) + sum >>= val; + } + + return sum; +} + + + + +ULONG +add_expression(char **str) +{ + ULONG val, sum = 0; + char op; + + *str = skipwhite(*str); + + sum = term(str); + + *str = skipwhite(*str); + while(**str == PLUS || **str == MINUS) + { + op = **str; + + *str = skipwhite(*str + 1); /* advance over the operator */ + + val = term(str); + + if (op == PLUS) + sum += val; + else if (op == MINUS) + sum -= val; + } + + return sum; +} + + + + +ULONG +term(char **str) +{ + ULONG val, sum = 0; + char op; + + + sum = factor(str); + *str = skipwhite(*str); + + /* + * We're at the bottom of the parse. At this point we either have + * an operator or we're through with this string. Otherwise it's + * an error and we print a message. + */ + if (**str != TIMES && **str != DIVISION && **str != MODULO && + **str != PLUS && **str != MINUS && **str != OR && + **str != AND && **str != XOR && **str != BANG && + **str != NEGATIVE && **str != TWIDDLE && **str != RPAREN && + **str != LESS_THAN && **str != GREATER_THAN && **str != SEMI_COLON && + strncmp(*str, "<<", 2) != 0 && strncmp(*str, ">>", 2) && + **str != EQUAL && **str != '\0') + { + fprintf(stderr, "Parsing stopped: unknown operator %s\n", *str); + return sum; + } + + while(**str == TIMES || **str == DIVISION || **str == MODULO) + { + op = **str; + *str = skipwhite(*str + 1); + val = factor(str); + + if (op == TIMES) + sum *= val; + else if (op == DIVISION) + { + if (val == 0) + fprintf(stderr, "Divide by zero!\n"); + + sum /= val; + } + else if (op == MODULO) + { + if (val == 0) + fprintf(stderr, "Modulo by zero!\n"); + + sum %= val; + } + } + + return sum; +} + + +ULONG +factor(char **str) +{ + ULONG val=0; + char op = NOTHING, have_special=0; + char *var_name, *var_name_ptr; + variable *v; + + if (**str == NEGATIVE || **str == PLUS || **str == TWIDDLE || **str == BANG) + { + op = **str; /* must be a unary op */ + + if ((op == NEGATIVE && *(*str + 1) == NEGATIVE) || /* look for ++/-- */ + (op == PLUS && *(*str + 1) == PLUS)) + { + *str = *str + 1; + have_special = 1; + } + + *str = skipwhite(*str + 1); + var_name_ptr = *str; /* save where the varname should be */ + } + + val = get_value(str); + + *str = skipwhite(*str); + + /* + * Now is the time to actually do the unary operation if one + * was present. + */ + if (have_special) /* we've got a ++ or -- */ + { + var_name = get_var_name(&var_name_ptr); + if (var_name == NULL) + { + fprintf(stderr, "Can only use ++/-- on variables.\n"); + return val; + } + if ((v = lookup_var(var_name)) == NULL) + { + v = add_var(var_name, 0); + if (v == NULL) + return val; + } + free(var_name); + + if (op == PLUS) + val = ++v->value; + else + val = --v->value; + } + else /* normal unary operator */ + { + switch(op) + { + case NEGATIVE : val *= -1; + break; + + case BANG : val = !val; + break; + + case TWIDDLE : val = ~val; + break; + } + } + + return val; +} + + + +ULONG +get_value(char **str) +{ + ULONG val; + char *var_name; + variable *v; + + if (**str == SINGLE_QUOTE) /* a character constant */ + { + int i; + + *str = *str + 1; /* advance over the leading quote */ + val = 0; + for(i=0; **str && **str != SINGLE_QUOTE && i < sizeof(LONG); *str+=1,i++) + { + if (**str == '\\') /* escape the next char */ + *str += 1; + + val <<= 8; + val |= (ULONG)((unsigned)**str); + } + + if (**str != SINGLE_QUOTE) /* constant must have been too long */ + { + fprintf(stderr, "Warning: character constant not terminated or too " + "long (max len == %d bytes)\n", sizeof(LONG)); + while(**str && **str != SINGLE_QUOTE) + *str += 1; + } + else if (**str != '\0') + *str += 1; + } + else if (isdigit(**str)) /* a regular number */ + { + val = STRTOUL(*str, str, 0); + + *str = skipwhite(*str); + } + else if (**str == USE_LAST_RESULT) /* a `.' meaning use the last result */ + { + val = last_result; + *str = skipwhite(*str+1); + } + else if (**str == LPAREN) /* a parenthesized expression */ + { + *str = skipwhite(*str + 1); + + val = assignment_expr(str); /* start at top and come back down */ + + if (**str == RPAREN) + *str = *str + 1; + else + fprintf(stderr, "Mismatched paren's\n"); + } + else if (isalpha(**str) || **str == '_') /* a variable name */ + { + if ((var_name = get_var_name(str)) == NULL) + { + fprintf(stderr, "Can't get var name!\n"); + return 0; + } + + if (get_var(var_name, &val) == 0) + { + fprintf(stderr, "No such variable: %s (assigning value of zero)\n", + var_name); + + val = 0; + v = add_var(var_name, val); + if (v == NULL) + return 0; + } + + *str = skipwhite(*str); + if (strncmp(*str, "++", 2) == 0 || strncmp(*str, "--", 2) == 0) + { + if ((v = lookup_var(var_name)) != NULL) + { + val = v->value; + if (**str == '+') + v->value++; + else + v->value--; + *str = *str + 2; + } + else + { + fprintf(stderr, "%s is a read-only variable\n", var_name); + } + } + + free(var_name); + } + else + { + fprintf(stderr, "Expecting left paren, unary op, constant or variable."); + fprintf(stderr, " Got: `%s'\n", *str); + return 0; + } + + + return val; +} + + +/* + * Here are the functions that manipulate variables. + */ + +/* + this is a hook function for external read-only + variables. If it is set and we don't find a + variable name in our name space, we call it to + look for the variable. If it finds the name, it + fills in val and returns 1. If it returns 0, it + didn't find the variable. +*/ +static int (*external_var_lookup)(char *name, ULONG *val) = NULL; + +/* + this very ugly function declaration is for the function + set_var_lookup_hook which accepts one argument, "func", which + is a pointer to a function that returns int (and accepts a + char * and ULONG *). set_var_lookup_hook returns a pointer to + a function that returns int and accepts char * and ULONG *. + + It's very ugly looking but fairly basic in what it does. You + pass in a function to set as the variable name lookup up hook + and it passes back to you the old function (which you should + call if it is non-null and your function fails to find the + variable name). +*/ +int (*set_var_lookup_hook(int (*func)(char *name, ULONG *val)))(char *name, ULONG *val) +{ + int (*old_func)(char *name, ULONG *val) = external_var_lookup; + + external_var_lookup = func; + + return old_func; +} + + +variable * +lookup_var(char *name) +{ + variable *v; + + for(v=vars; v; v=v->next) + if (v->name && strcmp(v->name, name) == 0) + return v; + + return NULL; +} + + +variable * +add_var(char *name, ULONG value) +{ + variable *v; + ULONG tmp; + + /* first make sure this isn't an external read-only variable */ + if (external_var_lookup) + if (external_var_lookup(name, &tmp) != 0) + { + fprintf(stderr, "Can't assign/create %s, it is a read-only var\n",name); + return NULL; + } + + + v = (variable *)malloc(sizeof(variable)); + if (v == NULL) + { + fprintf(stderr, "No memory to add variable: %s\n", name); + return NULL; + } + + v->name = strdup(name); + v->value = value; + v->next = vars; + + vars = v; /* set head of list to the new guy */ + + return v; +} + +/* + This routine and the companion get_var() are external + interfaces to the variable manipulation routines. +*/ +ULONG +set_var(char *name, ULONG val) +{ + variable *v; + + v = lookup_var(name); + if (v != NULL) + v->value = val; + else + add_var(name, val); +} + + +/* + This function returns 1 on success of finding + a variable and 0 on failure to find a variable. + If a variable is found, val is filled with its + value. +*/ +int +get_var(char *name, ULONG *val) +{ + variable *v; + + v = lookup_var(name); + if (v != NULL) + { + *val = v->value; + return 1; + } + else if (external_var_lookup != NULL) + { + return external_var_lookup(name, val); + } + + return 0; +} + +#define DEFAULT_LEN 32 + +char * +get_var_name(char **str) +{ + int i, len=DEFAULT_LEN; + char *buff; + + if (isalpha(**str) == 0 && **str != '_') + return NULL; + + buff = (char *)malloc(len*sizeof(char)); + if (buff == NULL) + return NULL; + + /* + * First get the variable name + */ + i=0; + while(**str && (isalnum(**str) || **str == '_')) + { + if (i >= len-1) + { + len *= 2; + buff = (char *)realloc(buff, len); + if (buff == NULL) + return NULL; + } + + buff[i++] = **str; + *str = *str+1; + } + + buff[i] = '\0'; /* null terminate */ + + while (isalnum(**str) || **str == '_') /* skip over any remaining junk */ + *str = *str+1; + + return buff; +} + + + +char * +skipwhite(char *str) +{ + if (str == NULL) + return NULL; + + while(*str && (*str == ' ' || *str == '\t' || *str == '\n' || *str == '\f')) + str++; + + return str; +} diff --git a/src/apps/bin/prio.c b/src/apps/bin/prio.c new file mode 100644 index 0000000000..94788f74a3 --- /dev/null +++ b/src/apps/bin/prio.c @@ -0,0 +1,39 @@ +/* prio.c - prio command for BeOs, change priority of a given thread + * (c) 2001, 2002, François Revol (mmu_man) for OpenBeOS + * released under the MIT licence. + * + * ChangeLog: + * 04-26-2002 v1.2 + * fixed a typo on error (Priority changed failed.) + * 04-25-2002 v1.1 + * Initial. Used my renice.c code to rewrite 'prio' BeOS command for OpenBeOS. + * + * prio is a stripped-down version of renice + * seems to behave the same way as the original BeOS version. :) + */ + +#include +#include + +int main(int argc, char **argv) +{ + thread_id th; + int32 prio; + status_t ret; + + if (argc != 3) { + puts("Usage: prio pid newpriority"); + return 1; + } + + th = atoi(argv[1]); + prio = atoi(argv[2]); + + // ret > 0 means successful, and is the previous priority + ret = set_thread_priority(th, prio); + if (ret >= B_OK) + return 0; + puts("Priority change failed."); + return 1; +} + diff --git a/src/apps/bin/ps.c b/src/apps/bin/ps.c new file mode 100644 index 0000000000..0308ae7a38 --- /dev/null +++ b/src/apps/bin/ps.c @@ -0,0 +1,59 @@ +/* ps.c - process list + * (c) 2002, François Revol (mmu_man) for OpenBeOS + * released under the MIT licence. + * + * ChangeLog: + * 04-26-2002 v1.0 + * Initial. + * + */ + +#include +#include + +#define SNOOZE_TIME 100000 + +#define PS_HEADER " thread name state prio user kernel semaphore" +#define PS_SEP "-----------------------------------------------------------------------" + +int main(int argc, char **argv) +{ + status_t ret; + team_info teaminfo; + thread_info thinfo; + uint32 teamcookie = 0; + int32 thcookie; + sem_info sinfo; + char *thstate; + char *states[] = {"run", "rdy", "msg", "zzz", "sus", "sem" }; + system_info sysinfo; + + puts(""); + puts(PS_HEADER); + puts(PS_SEP); + while ((ret = get_next_team_info(&teamcookie, &teaminfo)) >= B_OK) { + printf("%s (team %d) (uid %d) (gid %d)\n", teaminfo.args, teaminfo.team, teaminfo.uid, teaminfo.gid); + thcookie = 0; + while ((ret = get_next_thread_info(teaminfo.team, &thcookie, &thinfo)) >= B_OK) { + if (thinfo.state < B_THREAD_RUNNING || thinfo.state >B_THREAD_WAITING) + thstate = "???"; + else + thstate = states[thinfo.state-1]; + printf("%7ld %20s %3s %3d %7lli %7lli ", thinfo.thread, thinfo.name, thstate, thinfo.priority, thinfo.user_time/1000, thinfo.kernel_time/1000); + if (thinfo.state == B_THREAD_WAITING) { + get_sem_info(thinfo.sem, &sinfo); + printf("%s(%d)\n", sinfo.name, sinfo.sem); + } else + puts(""); + } + } + puts(""); + // system stats + get_system_info(&sysinfo); + printf("%ik (%li bytes) total memory\n", sysinfo.max_pages*B_PAGE_SIZE/1024, sysinfo.max_pages*B_PAGE_SIZE); + printf("%ik (%li bytes) currently committed\n", sysinfo.used_pages*B_PAGE_SIZE/1024, sysinfo.used_pages*B_PAGE_SIZE); + printf("%ik (%li bytes) currently available\n", (sysinfo.max_pages-sysinfo.used_pages)*B_PAGE_SIZE/1024, (sysinfo.max_pages-sysinfo.used_pages)*B_PAGE_SIZE); + printf("%2.1f%% memory utilisation\n", (float)100 * sysinfo.used_pages / sysinfo.max_pages); + return 0; +} + diff --git a/src/apps/bin/renice.c b/src/apps/bin/renice.c new file mode 100644 index 0000000000..9f676f5d7a --- /dev/null +++ b/src/apps/bin/renice.c @@ -0,0 +1,125 @@ +/* renice.c - unixish renice command for BeOs + * (c) 2001, 2002, François Revol (mmu_man) for OpenBeOS + * released under the MIT licence. + * + * How did I live without it before ??? ;) + * ChangeLog: + * 04-25-2002 v1.2 + * Cleanup for inclusion in OpenBeOS, + * Used the code to rewrite the 'prio' BeOS command for OpenBeOS. + * 04-14-2002 v1.1 + * Added -f upon suggestion from Idéfix on BeShare + * 2001 v1.0 + * Initial. + */ + +#include +#include + +/* + Notes: + +From man renice: +/usr/sbin/renice [-n increment] [-p] [-g | -u] ID ... /usr/sbin/renice priority [-p] pid ... [-g pgrp ...] [-u user ...] + + +#define B_LOW_PRIORITY 5 +#define B_NORMAL_PRIORITY 10 +#define B_DISPLAY_PRIORITY 15 +#define B_URGENT_DISPLAY_PRIORITY 20 +#define B_REAL_TIME_DISPLAY_PRIORITY 100 +#define B_URGENT_PRIORITY 110 +#define B_REAL_TIME_PRIORITY 120 + +BeOs priorities: +High Prio (realtime) Default Low Prio +120 10 1 (0 only for idle_thread) + +UNIX Priorities: +-20 0 20 + +Note that however this isn't perfect, since priorities +beyond 100 in BeOS move the thread into the real-time class. +Linux for example, has a separate API for doing this, +and even a process set to -20 can be in the normal scheduling class. + +renice can be given more than one pid on the command line. +prio is locked into one pid, then the priority. + +*/ + +// returns an equivalent UNIX priority for a given BeOS priority. +int32 prio_be_to_unix(int32 prio) +{ + return (prio > 10)?(- (20 * (prio - 10)) / 110):(2 * (10 - prio)); +} + +// returns an equivalent BeOS priority for a given UNIX priority. +int32 prio_unix_to_be(int32 prio) +{ + return (prio > 0)?(10 - (prio/2)):(10 + 110 * (-prio) / 20); +} + +int main(int argc, char **argv) +{ + thread_id th = -1; + int32 prio, increment; + thread_info thinfo; + bool use_be_prio = false; + bool next_is_prio = true; + bool next_is_increment = false; + bool use_increment = false; + bool find_by_name = false; + int i = 0; + + prio = 9; // default UNIX priority for nice + // convert it to beos + if (!use_be_prio) + prio = prio_unix_to_be(prio); + + while (++i < argc) { + if (!strcmp(argv[i], "-p")) { // ignored option + } else if (!strcmp(argv[i], "-n")) { + next_is_prio = false; + next_is_increment = true; + use_increment = true; + } else if (!strcmp(argv[i], "-b")) { + use_be_prio = true; + } else if (!strcmp(argv[i], "-f")) { + find_by_name = true; + } else if (next_is_increment) { + next_is_increment = false; + sscanf(argv[i], "%ld", (long *)&increment); + } else if (next_is_prio) { + next_is_prio = false; + sscanf(argv[i], "%ld", (long *)&prio); + if (!use_be_prio) + prio = prio_unix_to_be(prio); + } else { + if (find_by_name) + th = find_thread(argv[i]); + else + sscanf(argv[i], "%ld", (long *)&th); + if (use_increment) { + get_thread_info(th, &thinfo); + prio = thinfo.priority; + if (!use_be_prio) + prio = prio_be_to_unix(prio); + prio += increment; + if (!use_be_prio) + prio = prio_unix_to_be(prio); + } + set_thread_priority(th, prio); + } + } + if (th == -1) { + puts("Usage:"); + puts("renice [-b] [-n increment | prio] [-f thname thname...|thid thid ...]"); + puts(" -b : use BeOS priorities instead of UNIX priorities"); + puts(" -n : adds increment to the current priority instead of assigning it"); + puts(" -f : find threads by name instead of by id"); + return 1; + } + return 0; +} + diff --git a/src/apps/bin/rescan.c b/src/apps/bin/rescan.c new file mode 100644 index 0000000000..b67b8f13bc --- /dev/null +++ b/src/apps/bin/rescan.c @@ -0,0 +1,32 @@ +#include +// for O_WRONLY +#include + +// 2002, François Revol +// technical reference: +// http://bedriven.be-in.org/document/280-serial_port_driver.html +// please add standard header before putting into the OBOS CVS :) + +int main(int argc, char **argv) +{ + char *default_scan[] = { "scsi_dsk", "scsi_cd", "ata", "atapi" }; // not really sure here... + char *default_scan_names[] = { "scsi disks", "scsi cdroms", "ide ata", "ide atapi" }; + char **scan = default_scan; + char **scan_names = default_scan_names; + int scan_count = 4; + int scan_index = 0; + int fd_dev; + + if (argc > 1) { + scan = scan_names = argv; + scan_count = argc; + scan_index++; // not argv[0] + } + for (; scan_index < scan_count; scan_index++) { + printf("scanning %s...\n", scan_names[scan_index]); + fd_dev = open("/dev", O_WRONLY); + write(fd_dev, scan[scan_index], strlen(scan[scan_index])); + close(fd_dev); + } +} + diff --git a/src/apps/bin/roster.cpp b/src/apps/bin/roster.cpp new file mode 100644 index 0000000000..c8f146d027 --- /dev/null +++ b/src/apps/bin/roster.cpp @@ -0,0 +1,92 @@ +/********************************************************************* +** Roster Applet +********************************************************************** +** 2002-04-30 Mathew Hounsell Created. +*/ + +#include + +#include +#include + +#include + +#include +#include + +#include +#include +#include + +/********************************************************************* +*/ +bool OutputTeam( void * item_p ) +{ + static uint32 i = 0u; // counter + + app_info info; + app_info *pinfo = &info; + + // Roster stores team_id not team_id * + team_id id = reinterpret_cast( item_p ); + + // Get info on team + if( be_roster->GetRunningAppInfo( id, &info ) == B_OK ) { + + // Allocate a entry and get it's path. + // - works as they are independant (?) + BEntry entry( & info.ref ); + BPath path( & entry ); + + // Output - leave the work to ostream + std::cout + << setw(2) << i << ' ' +// short << setw(32) << info.ref.name << ' ' + << setw(32) << path.Path() << ' ' + << setw(6) << info.thread << ' ' + << setw(4) << info.team << ' ' + << setw(4) << info.port << ' ' + << setw(4) + ; + // Go hex, output, the go dec + hex( std::cout ); + std::cout << info.flags; + dec( std::cout ); + + // Output a signture + std::cout + << " (" << info.signature << ')' + << std::endl + ; + + /* NOW */ ++i; + } + return false; +} + +/********************************************************************* +*/ +int main( int argc, char ** argv ) +{ + // Don't have an BApplication as it is a waste. + + // Access Roster + // - address automatically assigned to be_roster as it's a singleton + new BRoster(); + + cout + << " path thread team port flags\n" + "-- -------------------------------- ------ ---- ---- -----" + << std::endl + ; + + // Retriev the running list. + BList applist( 0 ); + be_roster->GetAppList( & applist ); + + // Iterate through the list. + // void DoForEach(bool (*func)(void *) ) + applist.DoForEach( OutputTeam ); + + return 0; +} diff --git a/src/apps/bin/unchop.c b/src/apps/bin/unchop.c new file mode 100644 index 0000000000..4ad20b7e6b --- /dev/null +++ b/src/apps/bin/unchop.c @@ -0,0 +1,189 @@ +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ +// +// Copyright (c) 2001-2002, OpenBeOS +// +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// +// File: unchop.c +// Author: Daniel Reinhold (danielre@users.sf.net) +// Description: recreates a file previously split with chop +// +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ + +#include +#include +#include +#include +#include +#include + + +void usage (void); +void do_unchop (char *, char *); +void concatenate (int, int); +bool valid_file (char *); +void replace (char *, char *); +char *temp_file (); + + + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// globals + +#define BLOCKSIZE 64 * 1024 // file data is read in BLOCKSIZE blocks +static char Block[BLOCKSIZE]; // and stored in the global Block array + +static int Errors = 0; + + + +void +usage () + { + puts ("usage: unchop file"); + puts ("Concatenates files named file00, file01... into file"); + } + + +int +main (int argc, char *argv[]) + { + if (argc != 2) + { + usage (); + return 0; + } + else + { + char *origfile = argv[1]; + char *tmpfile = origfile; + bool needs_replace = false; + + if (valid_file (origfile)) + { + // output file already exists -- write to temp file + tmpfile = temp_file (); + needs_replace = true; + } + + do_unchop (tmpfile, origfile); + + if (needs_replace) + { + if (Errors == 0) + replace (origfile, tmpfile); + else + remove (tmpfile); + } + } + + putchar ('\n'); + return Errors; + } + + +void +do_unchop (char *outfile, char *basename) + { + int fdout = open (outfile, O_WRONLY|O_CREAT|O_APPEND); + if (fdout < 0) + fprintf (stderr, "can't open '%s': %s\n", outfile, strerror (errno)); + else + { + int i; + char fnameN[256]; + + for (i = 0; i < 999999; ++i) + { + sprintf (fnameN, "%s%02d", basename, i); + + if (valid_file (fnameN)) + { + int fdin = open (fnameN, O_RDONLY); + if (fdin < 0) + { + fprintf (stderr, "can't open '%s': %s\n", fnameN, strerror (errno)); + ++Errors; + } + else + { + concatenate (fdin, fdout); + close (fdin); + } + } + else + { + if (i == 0) + printf ("No chunk files present (%s)", fnameN); + break; + } + } + close (fdout); + } + } + + +void +concatenate (int fdin, int fdout) + { + ssize_t got; + + for (;;) + { + got = read (fdin, Block, BLOCKSIZE); + if (got <= 0) + break; + + write (fdout, Block, got); + } + } + + +bool +valid_file (char *fname) + { + // for this program, a valid file is one that: + // a) exists (that always helps) + // b) is a regular file (not a directory, link, etc.) + + struct stat e; + + if (stat (fname, &e) == -1) + { + // no such file + return false; + } + + return (S_ISREG (e.st_mode)); + } + + +void +replace (char *origfile, char *newfile) + { + // replace the contents of the original file + // with the contents of the new file + + char buf[1000]; + + // delete the original file + remove (origfile); + + // rename the new file to the original file name + sprintf (buf, "mv \"%s\" \"%s\"", newfile, origfile); + system (buf); + } + + +char * +temp_file () + { + char *tmp = tmpnam (NULL); + + FILE *fp = fopen (tmp, "w"); + fclose (fp); + + return tmp; + } diff --git a/src/apps/bin/waitfor.c b/src/apps/bin/waitfor.c new file mode 100644 index 0000000000..8035267c1e --- /dev/null +++ b/src/apps/bin/waitfor.c @@ -0,0 +1,33 @@ +/* waitfor.c - waits for a given threadname + * (c) 2002, François Revol (mmu_man) for OpenBeOS + * released under the MIT licence. + * + * ChangeLog: + * 04-26-2002 v1.0 + * Initial. + * + * waitfor threadname + * thesnooze() time is the same as the original, found using bdb waitfor foobar, + * and stepping until the snooze() call returns, the value is at the push + * instruction just before the call. + */ + +#include +#include + +#define SNOOZE_TIME 100000 + +int main(int argc, char **argv) +{ + status_t ret; + + if (argc != 2) { + fprintf(stderr, "Usage: %s thread_name\n", argv[0]); + return 1; + } + while (find_thread(argv[1]) < 0) + if ((ret = snooze(SNOOZE_TIME)) < B_OK) + return 1; + return 0; +} + diff --git a/src/apps/bin/wc.c b/src/apps/bin/wc.c new file mode 100644 index 0000000000..d3ba04cadc --- /dev/null +++ b/src/apps/bin/wc.c @@ -0,0 +1,172 @@ +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ +// +// Copyright (c) 2001-2002, OpenBeOS +// +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// +// File: wc.c +// Author: Daniel Reinhold (danielre@users.sf.net) +// Description: standard Unix wc (word count) command +// +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ + +#include +#include +#include +#include + + +int do_wc (char *); +void wc_file (FILE *, char *); +void display (int, int, int, char *); + + +// a few globals to brighten your day + +int TotalLines = 0; +int TotalWords = 0; +int TotalBytes = 0; + +int ShowLines = 1; +int ShowWords = 1; +int ShowBytes = 1; + + + + +int +main (int argc, char *argv[]) + { + if (argc == 1) + { + wc_file (stdin, ""); + } + else + { + int i; + int file_count = 0; + int reset_opts = 0; + char *arg; + char c; + + // pass 1: collect and set the options + for (i = 1; i < argc; ++i) + { + arg = argv[i]; + if (arg[0] == '-') + { + if (!reset_opts) + { + ShowLines = ShowWords = ShowBytes = 0; + reset_opts = 1; + } + while (c = *++arg) + { + if (c == 'l') ShowLines = 1; + else if (c == 'w') ShowWords = 1; + else if (c == 'c') ShowBytes = 1; + } + } + } + + // pass 2: process filename args + for (i = 1; i < argc; ++i) + { + arg = argv[i]; + if (arg[0] != '-') + file_count += do_wc (arg); + } + + if (file_count > 1) + display (TotalLines, TotalWords, TotalBytes, "total"); + } + + putchar ('\n'); + return 0; + } + + +int +do_wc (char *fname) + { + struct stat e; + + if (stat (fname, &e) == -1) + { + fprintf (stderr, "'%s': no such file or directory\n", fname); + return 0; + } + + if (S_ISDIR (e.st_mode)) + { + fprintf (stderr, "'%s' is a directory\n", fname); + display (0, 0, 0, fname); + return 1; + } + else + { + FILE *fp = fopen (fname, "rb"); + if (fp) + { + wc_file (fp, fname); + fclose (fp); + return 1; + } + else + { + fprintf (stderr, "'%s': %s\n", fname, strerror (errno)); + return 0; + } + } + } + + +void +wc_file (FILE *fp, char *fname) + { + int lc = 0; // line count + int wc = 0; // word count + int bc = 0; // byte count + + int ns = 0; // non-spaces (consecutive count) + int c; + + while ((c = fgetc (fp)) != EOF) + { + ++bc; + if (c == '\n') + ++lc; + + if (isspace (c)) + { + if (ns > 0) + ++wc, ns = 0; + } + else + ++ns; + } + + if (ns > 0) + ++wc; + + TotalLines += lc; + TotalWords += wc; + TotalBytes += bc; + + display (lc, wc, bc, fname); + } + + +void +display (int lc, int wc, int bc, char *fname) + { + if (ShowLines) printf ("%7d", lc); + if (ShowWords) printf ("%8d", wc); + if (ShowBytes) printf ("%8d", bc); + if (*fname) printf (" %s", fname); + + putchar ('\n'); + } + diff --git a/src/apps/clock/Clock.rsrc b/src/apps/clock/Clock.rsrc new file mode 100644 index 0000000000..4dce3a3133 Binary files /dev/null and b/src/apps/clock/Clock.rsrc differ diff --git a/src/apps/clock/LICENSE b/src/apps/clock/LICENSE new file mode 100644 index 0000000000..86a4268fa9 --- /dev/null +++ b/src/apps/clock/LICENSE @@ -0,0 +1,31 @@ +---------------------- +Be Sample Code License +---------------------- + +Copyright 1991-1999, Be Incorporated. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions, and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions, and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/apps/clock/README.Clock b/src/apps/clock/README.Clock new file mode 100644 index 0000000000..c6a615f6a0 --- /dev/null +++ b/src/apps/clock/README.Clock @@ -0,0 +1,22 @@ +Clock Project README +==================== + +This project creates the standard clock application, and is a good example +of using graphics on the BeOS. + +Files +===== + +The archive should contain the following files: + +README.Clock -- This file +Clock.proj -- Metrowerks project file +Clock.rsrc -- Application resource file +makefile -- project makefile + +clock.cpp -- Source files +clock.h +cl_wind.cpp +cl_wind.h +cl_view.cpp +cl_view.h diff --git a/src/apps/clock/cl_view.cpp b/src/apps/clock/cl_view.cpp new file mode 100644 index 0000000000..41da730579 --- /dev/null +++ b/src/apps/clock/cl_view.cpp @@ -0,0 +1,415 @@ +/* + + cl_view.cpp + +*/ + +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. +*/ + +#define DEBUG 1 +#include +#include + +#include +#include "clock.h" +#include "cl_view.h" +#include +#include + +#include +#include +#include +#include +#include +#include + +/* ---------------------------------------------------------------- */ + +TOffscreenView::TOffscreenView(BRect frame, char *name, short mRadius, + short hRadius, short offset, long face, bool show) + :BView(frame, name, B_NOT_RESIZABLE, B_WILL_DRAW) +{ + BRect theRect; + short loop; + void *picH; + size_t len; + float counter; + short index; + float x,y; + entry_ref ref; + long error; + + fFace = face; + theRect.Set(0,0,82,82); + + for (index = 0; index <= 8; index++) + fClockFace[index] = NULL; + +//+ error = get_ref_for_path("/boot/apps/Clock", &ref); + error = be_roster->FindApp(app_signature, &ref); + + if (error == B_NO_ERROR) { + BFile file(&ref, O_RDONLY); + if (file.InitCheck() == B_NO_ERROR) { + BResources rsrcs(&file); + error = 0; + + for (loop = 0; loop <= 8; loop++) { + if ((picH = rsrcs.FindResource('PICT', loop+4, &len))) { + fClockFace[loop] = new BBitmap(theRect,B_COLOR_8_BIT); + fClockFace[loop]->SetBits(picH,len,0,B_COLOR_8_BIT); + free(picH); + } else { + error = 1; + } + } + + theRect.Set(0,0,15,15); + if ((picH = rsrcs.FindResource('MICN', "center", &len))) { + fCenter = new BBitmap(theRect,B_COLOR_8_BIT); + fCenter->SetBits(picH,len,0,B_COLOR_8_BIT); + free(picH); + } else { + error = 1; + } + + theRect.Set(0,0,2,2); + if ((picH = rsrcs.FindResource('PICT', 13, &len))) { + fInner = new BBitmap(theRect,B_COLOR_8_BIT); + fInner->SetBits(picH,len,0,B_COLOR_8_BIT); + free(picH); + } else { + error = 1; + } + + if (error) { + // ??? yikes. This is terrible. No good way to signal error + // from here. How do we properly cleanup up here? Need to + // make sure the app_server side also gets cleaned up! + + BAlert *alert = new BAlert("Error", "Clock: Could not find necessary resources.", "Quit"); + alert->Go(); + delete this; + exit(1); + } + } + } else { + exit(1); + } + + fMinutesRadius = mRadius; + fHoursRadius = hRadius; + fOffset = offset; + fHours = 0; + fMinutes = 0; + fSeconds = 0; + fShowSeconds = show; + + index = 0; + + // + // Generate minutes points array + // + for (counter = 90; counter >= 0; counter -= 6,index++) { + x = mRadius * cos(((360 - counter)/180.0) * 3.1415); + x += 41; + y = mRadius * sin(((360 - counter)/180.0) * 3.1415); + y += 41; + fMinutePoints[index].Set(x,y); + x = hRadius * cos(((360 - counter)/180.0) * 3.1415); + x += 41; + y = hRadius * sin(((360 - counter)/180.0) * 3.1415); + y += 41; + fHourPoints[index].Set(x,y); + } + for (counter = 354; counter > 90; counter -= 6,index++) { + x = mRadius * cos(((360 - counter)/180.0) * 3.1415); + x += 41; + y = mRadius * sin(((360 - counter)/180.0) * 3.1415); + y += 41; + fMinutePoints[index].Set(x,y); + x = hRadius * cos(((360 - counter)/180.0) * 3.1415); + x += 41; + y = hRadius * sin(((360 - counter)/180.0) * 3.1415); + y += 41; + fHourPoints[index].Set(x,y); + } +} + +/* ---------------------------------------------------------------- */ + +void TOffscreenView::NextFace() +{ + fFace++; + if (fFace > 8) + fFace = 1; +}; + +/* ---------------------------------------------------------------- */ + +void TOffscreenView::AttachedToWindow() +{ + SetFontSize(18); + SetFont(be_plain_font); +} + +/* ---------------------------------------------------------------- */ + +void TOffscreenView::DrawX() +{ +//BRect bound; +short hours; + + ASSERT(Window()); + + if (Window()->Lock()) { + DrawBitmap(fClockFace[fFace],BPoint(0,0)); + + // + // Draw hands + // + SetHighColor(0,0,0); + hours = fHours; + if (hours >= 12) + hours -= 12; + hours *= 5; + hours += (fMinutes / 12); + StrokeLine(BPoint(fOffset,fOffset),fHourPoints[hours]); + SetDrawingMode(B_OP_OVER); + + DrawBitmap(fCenter,BPoint(fOffset-3,fOffset-3)); + SetDrawingMode(B_OP_COPY); + StrokeLine(BPoint(fOffset,fOffset),fMinutePoints[fMinutes]); + SetHighColor(180,180,180); + if (fShowSeconds) + StrokeLine(BPoint(fOffset,fOffset),fMinutePoints[fSeconds]); + DrawBitmap(fInner,BPoint(fOffset-1,fOffset-1)); + Sync(); + Window()->Unlock(); + } +} + +/* ---------------------------------------------------------------- */ + +TOffscreenView::~TOffscreenView() +{ + short counter; + + for (counter = 0; counter <= 8; counter++) + delete fClockFace[counter]; +}; + +/* ---------------------------------------------------------------- */ +/* ---------------------------------------------------------------- */ +/* ---------------------------------------------------------------- */ + +#include + +/* + * Onscreen view object + */ +TOnscreenView::TOnscreenView(BRect rect, char *title, + short mRadius, short hRadius, short offset) + :BView(rect, title, B_NOT_RESIZABLE, + B_WILL_DRAW | B_PULSE_NEEDED | B_DRAW_ON_CHILDREN) +{ + InitObject(rect, mRadius, hRadius, offset, 1, TRUE); + + BRect r = rect; + r.OffsetTo(B_ORIGIN); + r.top = r.bottom - 7; + r.left = r.right - 7; + + BDragger *dw = new BDragger(r, this, 0); + AddChild(dw); +} + +void TOnscreenView::InitObject(BRect rect, short mRadius, short hRadius, + short offset, long face, bool show) +{ + fmRadius = mRadius; + fhRadius = hRadius; + fOffset = offset; + fRect = rect; + OffscreenView = NULL; + Offscreen = NULL; + +#if 1 + OffscreenView = new TOffscreenView(rect, "freqd",mRadius,hRadius, + offset, face, show); + Offscreen = new BBitmap(rect, B_COLOR_8_BIT, TRUE); + Offscreen->Lock(); + Offscreen->AddChild(OffscreenView); + Offscreen->Unlock(); + OffscreenView->DrawX(); +#endif +} + +/* ---------------------------------------------------------------- */ + +TOnscreenView::~TOnscreenView() +{ + delete Offscreen; +} + +/* ---------------------------------------------------------------- */ + +TOnscreenView::TOnscreenView(BMessage *data) + : BView(data) +{ + InitObject(data->FindRect("bounds"), data->FindInt32("mRadius"), + data->FindInt32("hRadius"), data->FindInt32("offset"), + data->FindInt32("face"), data->FindBool("seconds")); +} + +/* ---------------------------------------------------------------- */ + +status_t TOnscreenView::Archive(BMessage *data, bool deep) const +{ + inherited::Archive(data, deep); + data->AddString("add_on", app_signature); +//+ data->AddString("add_on_path", "/boot/apps/Clock"); + + data->AddRect("bounds", Bounds()); + data->AddInt32("mRadius", OffscreenView->fMinutesRadius); + data->AddInt32("hRadius", OffscreenView->fHoursRadius); + data->AddInt32("offset", OffscreenView->fOffset); + data->AddBool("seconds", OffscreenView->fShowSeconds); + data->AddInt32("face", OffscreenView->fFace); + return 0; +} + +/* ---------------------------------------------------------------- */ + +BArchivable *TOnscreenView::Instantiate(BMessage *data) +{ + if (!validate_instantiation(data, "TOnscreenView")) + return NULL; + return new TOnscreenView(data); +} + +/* ---------------------------------------------------------------- */ + +void TOnscreenView::AttachedToWindow() +{ +//+ PRINT(("InitData m=%d, h=%d, offset=%d\n", fmRadius, fhRadius, fOffset)); +//+ PRINT_OBJECT(fRect); +} + +/* ---------------------------------------------------------------- */ + +void TOnscreenView::Pulse() +{ + short hours,minutes,seconds; + struct tm *loctime; + time_t current; + + ASSERT(Offscreen); + ASSERT(OffscreenView); + current = time(0); + loctime = localtime(¤t); + hours = loctime->tm_hour; + minutes = loctime->tm_min; + seconds = loctime->tm_sec; + + if ((OffscreenView->fShowSeconds && (seconds != OffscreenView->fSeconds)) || + (minutes != OffscreenView->fMinutes)) { + OffscreenView->fHours = hours; + OffscreenView->fMinutes = minutes; + OffscreenView->fSeconds = seconds; + BRect b = Bounds(); + b.InsetBy(12,12); + Draw(b); + } +} + +/* ---------------------------------------------------------------- */ + +void TOnscreenView::UseFace( short face ) +{ + OffscreenView->fFace = face; + BRect b = Bounds(); + b.InsetBy(12,12); + Draw(b); +} + +/* ---------------------------------------------------------------- */ + +void TOnscreenView::ShowSecs( bool secs ) +{ + OffscreenView->fShowSeconds = secs; + BRect b = Bounds(); + b.InsetBy(12,12); + Invalidate(b); +} + +/* ---------------------------------------------------------------- */ + +short TOnscreenView::ReturnFace( void ) +{ + return(OffscreenView->fFace); +} + +/* ---------------------------------------------------------------- */ + +short TOnscreenView::ReturnSeconds( void ) +{ + return(OffscreenView->fShowSeconds); +} + +/* ---------------------------------------------------------------- */ + +void TOnscreenView::Draw(BRect rect) +{ + time_t current; + ASSERT(Offscreen); + ASSERT(OffscreenView); + + bool b = Offscreen->Lock(); + ASSERT(b); + OffscreenView->DrawX(); // Composite the clock offscreen... + DrawBitmap(Offscreen, rect, rect); + Offscreen->Unlock(); + + current = time(0); +}; + +/* ---------------------------------------------------------------- */ + +void TOnscreenView::MouseDown( BPoint point ) +{ + BPoint cursor; + ulong buttons; + BRect bounds = Bounds(); + + GetMouse(&cursor,&buttons); + if (buttons & 0x2) { + OffscreenView->fShowSeconds = !OffscreenView->fShowSeconds; + be_app->PostMessage(SHOW_SECONDS); + bounds.InsetBy(12,12); + Draw(bounds); + } else { + OffscreenView->NextFace(); + Draw(bounds); + BView *c = ChildAt(0); + if (c) + c->Draw(c->Bounds()); + } +}; + +/* ---------------------------------------------------------------- */ + +void +TOnscreenView::MessageReceived(BMessage *msg) +{ + switch(msg->what) { + case B_ABOUT_REQUESTED: + (new BAlert("About Clock", "Clock (The Replicant version)\n\n(C)2002 OpenBeOS\n\nOriginally coded by the folks at Be.\n Copyright Be Inc., 1991-1998","OK"))->Go(); + break; + default: + inherited::MessageReceived(msg); + } +} diff --git a/src/apps/clock/cl_view.h b/src/apps/clock/cl_view.h new file mode 100644 index 0000000000..c6fe6b1342 --- /dev/null +++ b/src/apps/clock/cl_view.h @@ -0,0 +1,91 @@ +/* + + cl_view.h + +*/ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. +*/ + +#ifndef _CL_VIEW_H_ +#define _CL_VIEW_H_ + +#ifndef _APPLICATION_H +#include +#endif +#ifndef _WINDOW_H +#include +#endif +#ifndef _VIEW_H +#include +#endif +#ifndef _BITMAP_H +#include +#endif + +#include + +class TOffscreenView : public BView { + +public: + TOffscreenView(BRect frame, char *name, short mRadius, + short hRadius, short offset, long face, bool show); +virtual ~TOffscreenView(); +virtual void AttachedToWindow(); +virtual void DrawX(); + void NextFace(); + +BBitmap *fClockFace[9]; +BBitmap *fCenter; +BBitmap *fInner; +short fFace; +BPoint fMinutePoints[60]; +BPoint fHourPoints[60]; +short fMinutesRadius; +short fHoursRadius; +short fOffset; +short fHours; +short fMinutes; +short fSeconds; +bool fShowSeconds; +}; + + +class _EXPORT TOnscreenView : public BView { + +public: + TOnscreenView(BRect frame, char *name, short mRadius, + short hRadius, short offset); +virtual ~TOnscreenView(); + TOnscreenView(BMessage *data); +static BArchivable *Instantiate(BMessage *data); +virtual status_t Archive(BMessage *data, bool deep = true) const; + void InitObject(BRect frame, short mRadius, short hRadius, + short offset, long face, bool show); + +//+virtual void AllAttached(); +virtual void AttachedToWindow(); +virtual void Draw(BRect updateRect); +virtual void MouseDown( BPoint point); +virtual void MessageReceived(BMessage *msg); +virtual void Pulse(); + void UseFace( short face ); + void ShowSecs( bool secs ); + short ReturnFace( void ); + short ReturnSeconds( void ); + + +private: + + typedef BView inherited; + +BBitmap *Offscreen; +TOffscreenView *OffscreenView; +short fmRadius; +short fhRadius; +short fOffset; +BRect fRect; +}; + +#endif diff --git a/src/apps/clock/cl_wind.cpp b/src/apps/clock/cl_wind.cpp new file mode 100644 index 0000000000..e2787dcbef --- /dev/null +++ b/src/apps/clock/cl_wind.cpp @@ -0,0 +1,55 @@ +/* + + cl_wind.cpp + +*/ + +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. +*/ + +#include "cl_wind.h" +#include +#include +#include +#include +#include +#include + +#include + +TClockWindow::TClockWindow(BRect r, const char* t) + :BWindow(r, t, B_TITLED_WINDOW, + B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_AVOID_FRONT, + B_ALL_WORKSPACES) +{ + SetPulseRate(500000); // half second pulse rate +} + +bool TClockWindow::QuitRequested( void ) +{ + int ref; + BPoint lefttop; + short face; + bool seconds; + BPath path; +// int len; + + + if (find_directory (B_USER_SETTINGS_DIRECTORY, &path, true) == B_OK) { + path.Append("Clock_settings"); + ref = creat(path.Path(), 0777); + if (ref >= 0) { + lefttop = Frame().LeftTop(); + write(ref, (char *)&lefttop, sizeof(BPoint)); + face = theOnscreenView->ReturnFace(); + write(ref, (char *)&face, sizeof(short)); + seconds = theOnscreenView->ReturnSeconds(); + write(ref, (char *)&seconds, sizeof(bool)); + close(ref); + } + } + be_app->PostMessage(B_QUIT_REQUESTED); + return(TRUE); +} diff --git a/src/apps/clock/cl_wind.h b/src/apps/clock/cl_wind.h new file mode 100644 index 0000000000..4341cd857f --- /dev/null +++ b/src/apps/clock/cl_wind.h @@ -0,0 +1,26 @@ +/* + + cl_wind.h + +*/ + +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. +*/ + +#ifndef _WINDOW_H +#include +#endif +#ifndef _CL_VIEW_H_ +#include "cl_view.h" +#endif + +class TClockWindow : public BWindow { + +public: + TClockWindow(BRect, const char*); +virtual bool QuitRequested( void ); + +TOnscreenView *theOnscreenView; +}; diff --git a/src/apps/clock/clock.cpp b/src/apps/clock/clock.cpp new file mode 100644 index 0000000000..c1a6d0b01e --- /dev/null +++ b/src/apps/clock/clock.cpp @@ -0,0 +1,114 @@ +/* + + Clock.cpp + + 13 apr 94 elr new today + +*/ + +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. +*/ + +#include + +#include "clock.h" +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +int main(int argc, char* argv[]) +{ + THelloApplication *myApplication; + + myApplication = new THelloApplication(); + myApplication->Run(); + + delete myApplication; + return 0; +} + +const char *app_signature = "application/x-vnd.Be-simpleclock"; + +THelloApplication::THelloApplication() + :BApplication(app_signature) +{ + BRect windowRect, viewRect; + BPoint wind_loc; + int ref; + short face; + bool secs; + BPath path; + + viewRect.Set(0, 0, 82, 82); + myView = new TOnscreenView(viewRect, "Clock",22,15,41); + windowRect.Set(100, 100, 182, 182); + myWindow = new TClockWindow(windowRect, "Clock"); + face = 1; + if (find_directory (B_USER_SETTINGS_DIRECTORY, &path) == B_OK) { + path.Append("Clock_settings"); + ref = open(path.Path(), O_RDONLY); + if (ref >= 0) { + read(ref, (char *)&wind_loc, sizeof(wind_loc)); + read(ref, (char *)&face, sizeof(short)); + read(ref, (char *)&secs, sizeof(bool)); + close(ref); + myWindow->MoveTo(wind_loc); + + BRect frame = myWindow->Frame(); + frame.InsetBy(-4, -4); + if (!frame.Intersects(BScreen(myWindow).Frame())) { + // it's not visible so reposition. I'm not going to get + // fancy here, just place in the default location + myWindow->MoveTo(100, 100); + } + } + } + +//+ BPopUpMenu *menu = MainMenu(); +//+ BMenuItem *item = new BMenuItem("Show Seconds", new BMessage(SHOW_SECONDS)); +//+ item->SetTarget(this); +//+ item->SetMarked(secs); +//+ +//+ menu->AddItem(new BSeparatorItem(), 1); +//+ menu->AddItem(item, 2); +//+ menu->AddItem(new BSeparatorItem(), 3); + + myWindow->Lock(); + myWindow->AddChild(myView); + myWindow->theOnscreenView = myView; + +//+ BRect r = myView->Frame(); +//+ r.top = r.bottom - 7; +//+ r.left = r.right - 7; +//+ BDragger *dw = new BDragger(r, myView, 0); +//+ myWindow->AddChild(dw); + + myView->UseFace( face ); + myView->ShowSecs( secs ); + myView->Pulse(); // Force update + myWindow->Show(); + myWindow->Unlock(); +} + +void THelloApplication::MessageReceived(BMessage *msg) +{ + if (msg->what == SHOW_SECONDS) { +//+ if (myWindow->Lock()) { +//+ BMenuItem *item = MainMenu()->FindItem(SHOW_SECONDS); +//+ item->SetMarked(!item->IsMarked()); +//+//+ myView->ShowSecs(item->IsMarked()); +//+ myWindow->Unlock(); +//+ } + } else { + BApplication::MessageReceived(msg); + } +} diff --git a/src/apps/clock/clock.h b/src/apps/clock/clock.h new file mode 100644 index 0000000000..ed6ab63995 --- /dev/null +++ b/src/apps/clock/clock.h @@ -0,0 +1,32 @@ +/* + + clock.h + +*/ + +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. +*/ + +#ifndef _APPLICATION_H +#include +#endif + +#include "cl_view.h" +#include "cl_wind.h" + +#define SHOW_SECONDS 'ssec' + +extern const char *app_signature; + +class THelloApplication : public BApplication { + +public: + THelloApplication(); +virtual void MessageReceived(BMessage *msg); + +private: + TClockWindow* myWindow; + TOnscreenView *myView; +}; diff --git a/src/apps/magnify/LICENSE b/src/apps/magnify/LICENSE new file mode 100644 index 0000000000..86a4268fa9 --- /dev/null +++ b/src/apps/magnify/LICENSE @@ -0,0 +1,31 @@ +---------------------- +Be Sample Code License +---------------------- + +Copyright 1991-1999, Be Incorporated. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions, and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions, and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/apps/magnify/Magnify.rsrc b/src/apps/magnify/Magnify.rsrc new file mode 100644 index 0000000000..76a135c91b Binary files /dev/null and b/src/apps/magnify/Magnify.rsrc differ diff --git a/src/apps/magnify/main.cpp b/src/apps/magnify/main.cpp new file mode 100644 index 0000000000..4ae464728d --- /dev/null +++ b/src/apps/magnify/main.cpp @@ -0,0 +1,2010 @@ +/* + +"Magnify" compiled and updated by Sikosis (beos@gravity24hr.com) + +(C)2002 OpenBeOS under MIT license + +Copyright 1999, Be Incorporated. All Rights Reserved. +This file may be used under the terms of the Be Sample Code License. + +*/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "main.h" + +#if __MWERKS__ +#define _UNUSED(x) +#endif + +#if __GNUC__ +#define _UNUSED(x) x +#endif + +static const char *kPrefsFileName = "Magnify_prefs"; + +const int32 msg_help = 'help'; +const int32 msg_update_info = 'info'; +const int32 msg_show_info = 'show'; +const int32 msg_toggle_grid = 'grid'; +const int32 msg_shrink = 'shnk'; +const int32 msg_grow = 'grow'; +const int32 msg_make_square = 'sqar'; +const int32 msg_shrink_pixel = 'pshk'; +const int32 msg_grow_pixel = 'pgrw'; + +const int32 msg_new_color = 'colr'; +const int32 msg_toggle_ruler = 'rulr'; +const int32 msg_copy_image = 'copy'; +const int32 msg_track_color = 'trak'; +const int32 msg_freeze = 'frez'; +const int32 msg_dump = 'dump'; +const int32 msg_add_cross_hair = 'acrs'; +const int32 msg_remove_cross_hair = 'rcrs'; + +#ifndef B_BEOS_VERSION_4 +#define PR31 +#endif + +#ifdef PR31 +extern void _get_screen_bitmap_(BBitmap *offscreen,BRect src, bool enable = TRUE); +#endif + +//****************************************************************************** + +static float +FontHeight(BView* target, bool full) +{ + font_height finfo; + target->GetFontHeight(&finfo); + float h = ceil(finfo.ascent) + ceil(finfo.descent); + + if (full) + h += ceil(finfo.leading); + + return h; +} + +static color_map* +ColorMap() +{ + color_map* cmap; + + BScreen screen(B_MAIN_SCREEN_ID); + cmap = (color_map*)screen.ColorMap(); + + return cmap; +} + +static void +CenterWindowOnScreen(BWindow* w) +{ + BRect screenFrame = (BScreen(B_MAIN_SCREEN_ID).Frame()); + BPoint pt; + pt.x = screenFrame.Width()/2 - w->Bounds().Width()/2; + pt.y = screenFrame.Height()/2 - w->Bounds().Height()/2; + + if (screenFrame.Contains(pt)) + w->MoveTo(pt); +} + +//****************************************************************************** + +int +main(long argc, char* argv[]) +{ + int32 pixelCount=-1; + + if (argc > 2) { + printf("usage: magnify [size] (magnify size * size pixels)\n"); + exit(1); + } else { + if (argc == 2) { + pixelCount = abs(atoi(argv[1])); + + if ((pixelCount > 100) || (pixelCount < 4)) { + printf("usage: magnify [size] (magnify size * size pixels)\n"); + printf(" size must be > 4 and a multiple of 4\n"); + exit(1); + } + + if (pixelCount % 4) { + printf("magnify: size must be a multiple of 4\n"); + exit(1); + } + } + } + + TApp app(pixelCount); + app.Run(); + return(0); +} + +// ************************************************************************** + +// pass in pixelCount to maintain backward compatibility of setting +// the pixelcount from the command line +TApp::TApp(int32 pixelCount) + :BApplication("application/x-vnd.OBOS.Magnify") +{ + TWindow* magWindow = new TWindow(pixelCount); + magWindow->Show(); +} + +void +TApp::MessageReceived(BMessage* msg) +{ + switch (msg->what) { + case B_ABOUT_REQUESTED: + AboutRequested(); + break; + default: + BApplication::MessageReceived(msg); + break; + } +} + +void +TApp::ReadyToRun() +{ + BApplication::ReadyToRun(); +} + +void +TApp::AboutRequested(void) +{ + (new BAlert("", "Magnify!\n\n(C)2002 OBOS\n(C)1999 Be Inc.\n\nNow with even more features and recompiled for OpenBeOS.", "OK"))->Go(); +} + +//****************************************************************************** + +// each info region will be: +// top-bottom: 5 fontheight 5 fontheight 5 +// left-right: 10 minwindowwidth 10 + +const int32 kBorderSize = 10; + +TWindow::TWindow(int32 pixelCount) + : BWindow( BRect(0,0,0,0), "OBOS Magnify", B_TITLED_WINDOW, + B_OUTLINE_RESIZE) +{ + GetPrefs(pixelCount); + + // add info view + BRect infoRect(Bounds()); + infoRect.InsetBy(-1, -1); + fInfo = new TInfoView(infoRect); + AddChild(fInfo); + + fFontHeight = FontHeight(fInfo, true); + fInfoHeight = (fFontHeight * 2) + (3 * 5); + + BRect fbRect(0, 0, (fHPixelCount*fPixelSize), (fHPixelCount*fPixelSize)); + if (InfoIsShowing()) + fbRect.OffsetBy(10, fInfoHeight); + fFatBits = new TMagnify(fbRect, this); + fInfo->AddChild(fFatBits); + + fFatBits->SetSelection(fShowInfo); + fInfo->SetMagView(fFatBits); + + ResizeWindow(fHPixelCount, fVPixelCount); + + AddShortcut('I', B_COMMAND_KEY, new BMessage(B_ABOUT_REQUESTED)); + AddShortcut('S', B_COMMAND_KEY, new BMessage(msg_save)); + AddShortcut('C', B_COMMAND_KEY, new BMessage(msg_copy_image)); + AddShortcut('T', B_COMMAND_KEY, new BMessage(msg_show_info)); + AddShortcut('H', B_COMMAND_KEY, new BMessage(msg_add_cross_hair)); + AddShortcut('H', B_SHIFT_KEY, new BMessage(msg_remove_cross_hair)); + AddShortcut('G', B_COMMAND_KEY, new BMessage(msg_toggle_grid)); + AddShortcut('F', B_COMMAND_KEY, new BMessage(msg_freeze)); + AddShortcut('-', B_COMMAND_KEY, new BMessage(msg_shrink)); + AddShortcut('=', B_COMMAND_KEY, new BMessage(msg_grow)); + AddShortcut('/', B_COMMAND_KEY, new BMessage(msg_make_square)); + AddShortcut(',', B_COMMAND_KEY, new BMessage(msg_shrink_pixel)); + AddShortcut('.', B_COMMAND_KEY, new BMessage(msg_grow_pixel)); +} + +TWindow::~TWindow() +{ +} + +void +TWindow::MessageReceived(BMessage* m) +{ + bool active = fFatBits->Active(); + + switch (m->what) { + case B_ABOUT_REQUESTED: + be_app->MessageReceived(m); + break; + + case msg_help: + ShowHelp(); + break; + + case msg_show_info: + if (active) + ShowInfo(!fShowInfo); + break; + + case msg_toggle_grid: + if (active) + SetGrid(!fShowGrid); + break; + + case msg_grow: + if (active) + ResizeWindow(true); + break; + case msg_shrink: + if (active) + ResizeWindow(false); + break; + case msg_make_square: + if (active) { + if (fHPixelCount == fVPixelCount) + break; + int32 big = (fHPixelCount > fVPixelCount) ? fHPixelCount : fVPixelCount; + ResizeWindow(big, big); + } + break; + + case msg_shrink_pixel: + if (active) + SetPixelSize(false); + break; + case msg_grow_pixel: + if (active) + SetPixelSize(true); + break; + + case msg_add_cross_hair: + if (active && fShowInfo) + AddCrossHair(); + break; + case msg_remove_cross_hair: + if (active && fShowInfo) + RemoveCrossHair(); + break; + + case msg_freeze: + if (active) + SetFlags(B_OUTLINE_RESIZE | B_NOT_ZOOMABLE | B_NOT_RESIZABLE); + else + SetFlags(B_OUTLINE_RESIZE | B_NOT_ZOOMABLE); + + fFatBits->MakeActive(!fFatBits->Active()); + break; + + case msg_save: + // freeze the image here, unfreeze after dump or cancel + fFatBits->StartSave(); + + fSavePanel = new BFilePanel(B_SAVE_PANEL, new BMessenger(NULL, this), + 0, 0, false, new BMessage(msg_dump)); + fSavePanel->SetSaveText("Bitmaps.h"); + fSavePanel->Show(); + break; + case msg_dump: + { + delete fSavePanel; + + entry_ref dirRef; + char* name; + m->FindRef("directory", &dirRef); + m->FindString((const char*)"name",(const char**) &name); + + fFatBits->SaveImage(&dirRef, name); + } + break; + case B_CANCEL: + // image is frozen before the FilePanel is shown + fFatBits->EndSave(); + break; + + case msg_copy_image: + fFatBits->CopyImage(); + break; + default: + BWindow::MessageReceived(m); + break; + } +} + +bool +TWindow::QuitRequested() +{ + SetPrefs(); + be_app->PostMessage(B_QUIT_REQUESTED); + return true; +} + +// prefs are: +// name = Magnify +// version +// show grid +// show info (rgb, location) +// pixel count +// pixel size +const char* const kAppName = "OBOS Magnify"; +const bool kDefaultShowGrid = true; +const bool kDefaultShowInfo = true; +const int32 kDefaultPixelCount = 32; +const int32 kDefaultPixelSize = 8; +void +TWindow::GetPrefs(int32 overridePixelCount) +{ + BPath path; + char name[8]; + float version; + bool haveLoc=false; + BPoint loc; + bool showGrid = kDefaultShowGrid; + bool showInfo = kDefaultShowInfo; + bool ch1Showing=false; + bool ch2Showing=false; + int32 hPixelCount = kDefaultPixelCount; + int32 vPixelCount = kDefaultPixelCount; + int32 pixelSize = kDefaultPixelSize; + + if (find_directory (B_USER_SETTINGS_DIRECTORY, &path) == B_OK) { + int ref = -1; + path.Append(kPrefsFileName); + if ((ref = open(path.Path(), 0)) >= 0) { + + if (read(ref, name, 7) != 7) + goto ALMOST_DONE; + + name[7] = 0; + if (strcmp(name, kAppName) != 0) + goto ALMOST_DONE; + + read(ref, &version, sizeof(float)); + + if (read(ref, &loc, sizeof(BPoint)) != sizeof(BPoint)) + goto ALMOST_DONE; + else + haveLoc = true; + + if (read(ref, &showGrid, sizeof(bool)) != sizeof(bool)) { + showGrid = kDefaultShowGrid; + goto ALMOST_DONE; + } + + if (read(ref, &showInfo, sizeof(bool)) != sizeof(bool)) { + showInfo = kDefaultShowInfo; + goto ALMOST_DONE; + } + + if (read(ref, &ch1Showing, sizeof(bool)) != sizeof(bool)) { + ch1Showing = false; + goto ALMOST_DONE; + } + + if (read(ref, &ch2Showing, sizeof(bool)) != sizeof(bool)) { + ch2Showing = false; + goto ALMOST_DONE; + } + + if (read(ref, &hPixelCount, sizeof(int32)) != sizeof(int32)) { + hPixelCount = kDefaultPixelCount; + goto ALMOST_DONE; + } + if (read(ref, &vPixelCount, sizeof(int32)) != sizeof(int32)) { + vPixelCount = kDefaultPixelCount; + goto ALMOST_DONE; + } + + if (read(ref, &pixelSize, sizeof(int32)) != sizeof(int32)) { + pixelSize = kDefaultPixelSize; + goto ALMOST_DONE; + } + +ALMOST_DONE: // clean up and try to position the window + close(ref); + + if (haveLoc && BScreen(B_MAIN_SCREEN_ID).Frame().Contains(loc)) { + MoveTo(loc); + goto DONE; + } + } + } + + // if prefs dont yet exist or the window is not onscreen, center the window + CenterWindowOnScreen(this); + + // set all the settings to defaults if we get here +DONE: + fShowGrid = showGrid; + fShowInfo = showInfo; + fHPixelCount = (overridePixelCount == -1) ? hPixelCount : overridePixelCount; + fVPixelCount = (overridePixelCount == -1) ? vPixelCount : overridePixelCount; + fPixelSize = pixelSize; +} + +const float kCurrentVersion = 1.2; +void +TWindow::SetPrefs() +{ + BPath path; + + if (find_directory (B_USER_SETTINGS_DIRECTORY, &path, true) == B_OK) { + long ref; + + path.Append (kPrefsFileName); + if ((ref = creat(path.Path(), O_RDWR)) >= 0) { + float version = kCurrentVersion; + + lseek (ref, 0, SEEK_SET); + write(ref, kAppName, 7); + write(ref, &version, sizeof(float)); + + BPoint loc = Frame().LeftTop(); + write(ref, &loc, sizeof(BPoint)); + + write(ref, &fShowGrid, sizeof(bool)); + write(ref, &fShowInfo, sizeof(bool)); + bool ch1, ch2; + CrossHairsShowing(&ch1, &ch2); + write(ref, &ch1, sizeof(bool)); + write(ref, &ch2, sizeof(bool)); + + write(ref, &fHPixelCount, sizeof(int32)); + write(ref, &fVPixelCount, sizeof(int32)); + write(ref, &fPixelSize, sizeof(int32)); + + close(ref); + + } + } +} + +void +TWindow::FrameResized(float w, float h) +{ + CalcViewablePixels(); + + float width; + float height; + GetPreferredSize(&width, &height); + ResizeTo(width, height); + + fFatBits->InitBuffers(fHPixelCount, fVPixelCount, fPixelSize, ShowGrid()); +} + +void +TWindow::ScreenChanged(BRect screen_size, color_space depth) +{ + BWindow::ScreenChanged(screen_size, depth); + // reset all bitmaps + fFatBits->ScreenChanged(screen_size,depth); +} + +void +TWindow::Minimize(bool m) +{ + BWindow::Minimize(m); +} + +void +TWindow::Zoom(BPoint _UNUSED(rec_position), float _UNUSED(rec_width), float _UNUSED(rec_height)) +{ + if (fFatBits->Active()) + ShowInfo(!fShowInfo); +} + +void +TWindow::CalcViewablePixels() +{ + + float w = Bounds().Width(); + float h = Bounds().Height(); + + if (InfoIsShowing()) { + w -= 20; // remove the gutter + h = h-fInfoHeight-10; // remove info and gutter + } + + bool ch1, ch2; + fFatBits->CrossHairsShowing(&ch1, &ch2); + if (ch1) + h -= fFontHeight; + if (ch2) + h -= fFontHeight + 5; + + fHPixelCount = (int32)w / fPixelSize; // calc h pixels + if (fHPixelCount < 16) + fHPixelCount = 16; + + fVPixelCount = (int32)h / fPixelSize; // calc v pixels + if (fVPixelCount < 4) + fVPixelCount = 4; +} + +void +TWindow::GetPreferredSize(float* width, float* height) +{ + *width = fHPixelCount * fPixelSize; // calc window width + *height = fVPixelCount * fPixelSize; // calc window height + if (InfoIsShowing()) { + *width += 20; + *height += fInfoHeight + 10; + } + + bool ch1, ch2; + fFatBits->CrossHairsShowing(&ch1, &ch2); + if (ch1) + *height += fFontHeight; + if (ch2) + *height += fFontHeight + 5; +} + +void +TWindow::ResizeWindow(int32 hPixelCount, int32 vPixelCount) +{ + fHPixelCount = hPixelCount; + fVPixelCount = vPixelCount; + + float width, height; + GetPreferredSize(&width, &height); + + ResizeTo(width, height); +} + +void +TWindow::ResizeWindow(bool direction) +{ + int32 x = fHPixelCount; + int32 y = fVPixelCount; + + if (direction) { + x += 4; + y += 4; + } else { + x -= 4; + y -= 4; + } + + if (x < 4) + x = 4; + + if (y < 4) + y = 4; + + ResizeWindow(x, y); +} + +void +TWindow::SetGrid(bool s) +{ + if (s == fShowGrid) + return; + + fShowGrid = s; + fFatBits->SetUpdate(true); +} + +bool +TWindow::ShowGrid() +{ + return fShowGrid; +} + +void +TWindow::ShowInfo(bool i) +{ + if (i == fShowInfo) + return; + + fShowInfo = i; + + if (fShowInfo) + fFatBits->MoveTo(10, fInfoHeight); + else { + fFatBits->MoveTo(1,1); + fFatBits->SetCrossHairsShowing(false, false); + } + + fFatBits->SetSelection(fShowInfo); + ResizeWindow(fHPixelCount, fVPixelCount); +} + +bool +TWindow::InfoIsShowing() +{ + return fShowInfo; +} + +void +TWindow::UpdateInfo() +{ + fInfo->Draw(fInfo->Bounds()); +} + +void +TWindow::AddCrossHair() +{ + fFatBits->AddCrossHair(); + + // crosshair info needs to be added + // window resizes accordingly + float width; + float height; + GetPreferredSize(&width, &height); + ResizeTo(width, height); +} + +void +TWindow::RemoveCrossHair() +{ + fFatBits->RemoveCrossHair(); + + // crosshair info needs to be removed + // window resizes accordingly + float width; + float height; + GetPreferredSize(&width, &height); + ResizeTo(width, height); +} + +void +TWindow::CrossHairsShowing(bool* ch1, bool* ch2) +{ + fFatBits->CrossHairsShowing(ch1, ch2); +} + +void +TWindow::PixelCount(int32* h, int32 *v) +{ + *h = fHPixelCount; + *v = fVPixelCount; +} + +void +TWindow::SetPixelSize(int32 s) +{ + if (s == fPixelSize) + return; + + fPixelSize = s; + // resize window + // tell info that size has changed + // tell mag that size has changed + + CalcViewablePixels(); + ResizeWindow(fHPixelCount, fVPixelCount); +} + +void +TWindow::SetPixelSize(bool d) +{ + if (d) { // grow + fPixelSize++; + if (fPixelSize > 16) + fPixelSize = 16; + } else { + fPixelSize--; + if (fPixelSize < 1) + fPixelSize = 1; + } + + float w = Bounds().Width(); + float h = Bounds().Height(); + CalcViewablePixels(); + ResizeWindow(fHPixelCount, fVPixelCount); + + // the window might not actually change in size + // in that case force the buffers to the new dimension + if (w == Bounds().Width() && h == Bounds().Height()) + fFatBits->InitBuffers(fHPixelCount, fVPixelCount, fPixelSize, ShowGrid()); +} + +int32 +TWindow::PixelSize() +{ + return fPixelSize; +} + +void +TWindow::ShowHelp() +{ + BRect r(0,0,375,240); + BWindow* w = new BWindow(r, "Magnify Help", B_TITLED_WINDOW, + B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_NOT_RESIZABLE); + + r.right -= B_V_SCROLL_BAR_WIDTH; + r.bottom -= B_H_SCROLL_BAR_HEIGHT; + BRect r2(r); + r2.InsetBy(4,4); + BTextView* text = new BTextView(r, "text", r2, B_FOLLOW_ALL, B_WILL_DRAW); + text->MakeSelectable(false); + text->MakeEditable(false); + + BScrollView* scroller = new BScrollView("", text, B_FOLLOW_ALL, 0, true, true); + w->AddChild(scroller); + + text->Insert("General:\n"); + text->Insert(" 32 x 32 - the top left numbers are the number of visible\n"); + text->Insert(" pixels (width x height)\n"); + text->Insert(" 8 pixels/pixel - represents the number of pixels that are\n"); + text->Insert(" used to magnify a pixel\n"); + text->Insert(" R:152 G:52 B:10 - the RGB values for the pixel under\n"); + text->Insert(" the red square\n"); + text->Insert("\n\n"); + text->Insert("Copy/Save:\n"); + text->Insert(" copy - copies the current image to the clipboard\n"); + text->Insert(" save - prompts the user for a file to save to and writes out\n"); + text->Insert(" the bits of the image\n"); + text->Insert("\n\n"); + text->Insert("Info:\n"); + text->Insert(" hide/show info - hides/shows all these new features\n"); + text->Insert(" note: when showing, a red square will appear which signifies\n"); + text->Insert(" which pixel's rgb values will be displayed\n"); + text->Insert(" add/remove crosshairs - 2 crosshairs can be added (or removed)\n"); + text->Insert(" to aid in the alignment and placement of objects.\n"); + text->Insert(" The crosshairs are represented by blue squares and blue lines.\n"); + text->Insert(" hide/show grid - hides/shows the grid that separates each pixel\n"); + text->Insert("\n\n"); + text->Insert(" freeze - freezes/unfreezes magnification of whatever the\n"); + text->Insert(" cursor is currently over\n"); + text->Insert("\n\n"); + text->Insert("Sizing & Resizing:\n"); + text->Insert(" make square - sets the width and the height to the larger\n"); + text->Insert(" of the two making a square image\n"); + text->Insert(" increase/decrease window size - grows or shrinks the window\n"); + text->Insert(" size by 4 pixels.\n"); + text->Insert(" note: this window can also be resized to any size via the\n"); + text->Insert(" resizing region of the window\n"); + text->Insert(" increase/decrease pixel size - increases or decreases the number\n"); + text->Insert(" of pixels used to magnify a 'real' pixel. Range is 1 to 16.\n"); + text->Insert("\n\n"); + text->Insert("Navigation:\n"); + text->Insert(" arrow keys - move the current selection (rgb indicator or crosshair)\n"); + text->Insert(" around 1 pixel at a time\n"); + text->Insert(" option-arrow key - moves the mouse location 1 pixel at a time\n"); + text->Insert(" x marks the selection - the current selection has an 'x' in it\n"); + + CenterWindowOnScreen(w); + w->Show(); +} + +bool +TWindow::IsActive() +{ + return fFatBits->Active(); +} + +//****************************************************************************** + +TInfoView::TInfoView(BRect frame) + : BBox(frame, "rgb", B_FOLLOW_ALL, + B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS, + B_NO_BORDER) +{ + SetFont(be_plain_font); + fFontHeight = FontHeight(this, true); + fMagView = NULL; + + fSelectionColor = kBlack; + fCH1Loc.x = fCH1Loc.y = fCH2Loc.x = fCH2Loc.y = 0; + + fInfoStr[0] = 0; + fRGBStr[0] = 0; + fCH1Str[0] = 0; + fCH2Str[0] = 0; +} + +TInfoView::~TInfoView() +{ +} + +void +TInfoView::AttachedToWindow() +{ + BBox::AttachedToWindow(); + + dynamic_cast(Window())->PixelCount(&fHPixelCount, &fVPixelCount); + fPixelSize = dynamic_cast(Window())->PixelSize(); + + AddMenu(); +} + +void +TInfoView::Draw(BRect updateRect) +{ + PushState(); + + char str[64]; + + SetLowColor(ViewColor()); + + BRect invalRect; + + int32 hPixelCount, vPixelCount; + dynamic_cast(Window())->PixelCount(&hPixelCount, &vPixelCount); + int32 pixelSize = dynamic_cast(Window())->PixelSize(); + + MovePenTo(10, fFontHeight+5); + sprintf(str, "%li x %li @ %li pixels/pixel", hPixelCount, vPixelCount, + pixelSize); + invalRect.Set(10, 5, 10 + StringWidth(fInfoStr), fFontHeight+7); + SetHighColor(ViewColor()); + FillRect(invalRect); + SetHighColor(0,0,0,255); + strcpy(fInfoStr,str); + DrawString(fInfoStr); + + rgb_color c = { 0,0,0, 255 }; + uchar index = 0; + if (fMagView) { + c = fMagView->SelectionColor(); + BScreen s; + index = s.IndexForColor(c); + } + MovePenTo(10, fFontHeight*2+5); + sprintf(str, "R: %i G: %i B: %i (0x%x)", + c.red, c.green, c.blue, index); + invalRect.Set(10, fFontHeight+7, 10 + StringWidth(fRGBStr), fFontHeight*2+7); + SetHighColor(ViewColor()); + FillRect(invalRect); + SetHighColor(0,0,0,255); + strcpy(fRGBStr,str); + DrawString(fRGBStr); + + bool ch1Showing, ch2Showing; + dynamic_cast(Window())->CrossHairsShowing(&ch1Showing, &ch2Showing); + + if (fMagView) { + BPoint pt1(fMagView->CrossHair1Loc()); + BPoint pt2(fMagView->CrossHair2Loc()); + + float h = Bounds().Height(); + if (ch2Showing) { + MovePenTo(10, h-12); + sprintf(str, "2) x: %li y: %li y: %i", (int32)pt2.x, (int32)pt2.y, + abs((int)(pt1.y - pt2.y))); + invalRect.Set(10, h-12-fFontHeight, 10 + StringWidth(fCH2Str), h-10); + SetHighColor(ViewColor()); + FillRect(invalRect); + SetHighColor(0,0,0,255); + strcpy(fCH2Str,str); + DrawString(fCH2Str); + } + + if (ch1Showing && ch2Showing) { + MovePenTo(10, h-10-fFontHeight-2); + sprintf(str, "1) x: %li y: %li x: %i", (int32)pt1.x, (int32)pt1.y, + abs((int)(pt1.x - pt2.x))); + invalRect.Set(10, h-10-2*fFontHeight-2, 10 + StringWidth(fCH1Str), h-10-fFontHeight); + SetHighColor(ViewColor()); + FillRect(invalRect); + SetHighColor(0,0,0,255); + strcpy(fCH1Str,str); + DrawString(fCH1Str); + } else if (ch1Showing) { + MovePenTo(10, h-10); + sprintf(str, "x: %li y: %li", (int32)pt1.x, (int32)pt1.y); + invalRect.Set(10, h-10-fFontHeight, 10 + StringWidth(fCH1Str), h-8); + SetHighColor(ViewColor()); + FillRect(invalRect); + SetHighColor(0,0,0,255); + strcpy(fCH1Str,str); + DrawString(fCH1Str); + } + } + + PopState(); +} + +void +TInfoView::FrameResized(float width, float height) +{ + BBox::FrameResized(width, height); +} + +static void +BuildInfoMenu(BMenu *menu) +{ + BMenuItem* menuItem; + + menuItem = new BMenuItem("About Magnify...", new BMessage(B_ABOUT_REQUESTED)); + menu->AddItem(menuItem); + menuItem = new BMenuItem("Help...", new BMessage(msg_help)); + menu->AddItem(menuItem); + menu->AddSeparatorItem(); + + menuItem = new BMenuItem("Save Image", new BMessage(msg_save),'S'); + menu->AddItem(menuItem); +// menuItem = new BMenuItem("Save Selection", new BMessage(msg_save),'S'); +// menu->AddItem(menuItem); + menuItem = new BMenuItem("Copy Image", new BMessage(msg_copy_image),'C'); + menu->AddItem(menuItem); + menu->AddSeparatorItem(); + + menuItem = new BMenuItem("Hide/Show Info", new BMessage(msg_show_info),'T'); + menu->AddItem(menuItem); + menuItem = new BMenuItem("Add a Crosshair", new BMessage(msg_add_cross_hair),'H'); + menu->AddItem(menuItem); + menuItem = new BMenuItem("Remove a Crosshair", new BMessage(msg_remove_cross_hair), 'H', + B_SHIFT_KEY); + menu->AddItem(menuItem); + menuItem = new BMenuItem("Hide/Show Grid", new BMessage(msg_toggle_grid),'G'); + menu->AddItem(menuItem); + menu->AddSeparatorItem(); + + menuItem = new BMenuItem("Freeze/Unfreeze image", new BMessage(msg_freeze),'F'); + menu->AddItem(menuItem); + menu->AddSeparatorItem(); + + menuItem = new BMenuItem("Make Square", new BMessage(msg_make_square),'/'); + menu->AddItem(menuItem); + menuItem = new BMenuItem("Decrease Window Size", new BMessage(msg_shrink),'-'); + menu->AddItem(menuItem); + menuItem = new BMenuItem("Increase Window Size", new BMessage(msg_grow),'+'); + menu->AddItem(menuItem); + menuItem = new BMenuItem("Decrease Pixel Size", new BMessage(msg_shrink_pixel),','); + menu->AddItem(menuItem); + menuItem = new BMenuItem("Increase Pixel Size", new BMessage(msg_grow_pixel),'.'); + menu->AddItem(menuItem); +} + +void +TInfoView::AddMenu() +{ + fMenu = new TMenu(dynamic_cast(Window()), ""); + BuildInfoMenu(fMenu); + + BRect r(Bounds().Width()-27, 11, Bounds().Width()-11, 27); + fPopUp = new BMenuField( r, "region menu", NULL, fMenu, true, + B_FOLLOW_RIGHT | B_FOLLOW_TOP); + AddChild(fPopUp); +} + +void +TInfoView::SetMagView(TMagnify* magView) +{ + fMagView = magView; +} + +// + + +TMenu::TMenu(TWindow *mainWindow, const char *title, menu_layout layout) + : BMenu(title, layout), + fMainWindow(mainWindow) +{ +} + + +TMenu::~TMenu() +{ +} + +void +TMenu::AttachedToWindow() +{ + bool state=true; + if (fMainWindow) + state = fMainWindow->IsActive(); + + BMenuItem* menuItem = FindItem("Hide/Show Info"); + if (menuItem) + menuItem->SetEnabled(state); + menuItem = FindItem("Add a Crosshair"); + if (menuItem) + menuItem->SetEnabled(state); + menuItem = FindItem("Remove a Crosshair"); + if (menuItem) + menuItem->SetEnabled(state); + menuItem = FindItem("Hide/Show Grid"); + if (menuItem) + menuItem->SetEnabled(state); + menuItem = FindItem("Make Square"); + if (menuItem) + menuItem->SetEnabled(state); + menuItem = FindItem("Decrease Window Size"); + if (menuItem) + menuItem->SetEnabled(state); + menuItem = FindItem("Increase Window Size"); + if (menuItem) + menuItem->SetEnabled(state); + menuItem = FindItem("Decrease Pixel Size"); + if (menuItem) + menuItem->SetEnabled(state); + menuItem = FindItem("Increase Pixel Size"); + if (menuItem) + menuItem->SetEnabled(state); + + BMenu::AttachedToWindow(); +} + + +//****************************************************************************** + +TMagnify::TMagnify(BRect r, TWindow* parent) + :BView(r, "MagView", B_FOLLOW_NONE, B_WILL_DRAW | B_FRAME_EVENTS), + fParent(parent) +{ + fLastLoc.Set(-1, -1); + fSelectionLoc.x = 0; fSelectionLoc.y = 0; + fActive = true; + fShowSelection = false; + fShowCrossHair1 = false; + fCrossHair1.x = -1; fCrossHair1.y = -1; + fShowCrossHair2 = false; + fCrossHair2.x = -1; fCrossHair2.y = -1; + fSelection = -1; + + fImageBuf = NULL; + fImageView = NULL; +} + +TMagnify::~TMagnify() +{ + kill_thread(fThread); + delete(fImageBuf); +} + +void +TMagnify::AttachedToWindow() +{ + SetViewColor(B_TRANSPARENT_32_BIT); + + int32 width, height; + fParent->PixelCount(&width, &height); + InitBuffers(width, height, fParent->PixelSize(), fParent->ShowGrid()); + + fThread = spawn_thread(TMagnify::MagnifyTask, "MagnifyTask", + B_NORMAL_PRIORITY, this); + + resume_thread(fThread); + + MakeFocus(); +} + +void +TMagnify::InitBuffers(int32 hPixelCount, int32 vPixelCount, + int32 pixelSize, bool showGrid) +{ + color_space colorSpace = BScreen(Window()).ColorSpace(); + + BRect r(0, 0, (pixelSize * hPixelCount)-1, (pixelSize * vPixelCount)-1); + if (Bounds().Width() != r.Width() || Bounds().Height() != r.Height()) + ResizeTo(r.Width(), r.Height()); + + if (fImageView) { + fImageBuf->Lock(); + fImageView->RemoveSelf(); + fImageBuf->Unlock(); + + fImageView->Resize((int32)r.Width(), (int32)r.Height()); + fImageView->SetSpace(colorSpace); + } else + fImageView = new TOSMagnify(r, this, colorSpace); + + delete(fImageBuf); + fImageBuf = new BBitmap(r, colorSpace, true); + fImageBuf->Lock(); + fImageBuf->AddChild(fImageView); + fImageBuf->Unlock(); +} + +void +TMagnify::Draw(BRect) +{ + BRect bounds(Bounds()); + DrawBitmap(fImageBuf, bounds, bounds); + dynamic_cast(Window())->UpdateInfo(); +} + +void +TMagnify::KeyDown(const char *key, int32 numBytes) +{ + if (!fShowSelection) + BView::KeyDown(key,numBytes); + + uint32 mods = modifiers(); + + switch (key[0]) { + case B_TAB: + if (fShowCrossHair1) { + fSelection++; + + if (fShowCrossHair2) { + if (fSelection > 2) + fSelection = 0; + } else if (fShowCrossHair1) { + if (fSelection > 1) + fSelection = 0; + } + fNeedToUpdate = true; + Draw(Bounds()); + } + break; + + case B_LEFT_ARROW: + if (mods & B_OPTION_KEY) + NudgeMouse(-1,0); + else + MoveSelection(-1,0); + break; + case B_RIGHT_ARROW: + if (mods & B_OPTION_KEY) + NudgeMouse(1, 0); + else + MoveSelection(1,0); + break; + case B_UP_ARROW: + if (mods & B_OPTION_KEY) + NudgeMouse(0, -1); + else + MoveSelection(0,-1); + break; + case B_DOWN_ARROW: + if (mods & B_OPTION_KEY) + NudgeMouse(0, 1); + else + MoveSelection(0,1); + break; + + default: + BView::KeyDown(key,numBytes); + break; + } +} + +void +TMagnify::FrameResized(float newW, float newH) +{ + int32 w, h; + PixelCount(&w, &h); + + if (fSelectionLoc.x >= w) + fSelectionLoc.x = 0; + if (fSelectionLoc.y >= h) + fSelectionLoc.y = 0; + + if (fShowCrossHair1) { + + if (fCrossHair1.x >= w) { + fCrossHair1.x = fSelectionLoc.x + 2; + if (fCrossHair1.x >= w) + fCrossHair1.x = 0; + } + if (fCrossHair1.y >= h) { + fCrossHair1.y = fSelectionLoc.y + 2; + if (fCrossHair1.y >= h) + fCrossHair1.y = 0; + } + + if (fShowCrossHair2) { + if (fCrossHair2.x >= w) { + fCrossHair2.x = fCrossHair1.x + 2; + if (fCrossHair2.x >= w) + fCrossHair2.x = 0; + } + if (fCrossHair2.y >= h) { + fCrossHair2.y = fCrossHair1.y + 2; + if (fCrossHair2.y >= h) + fCrossHair2.y = 0; + } + } + } +} + +void +TMagnify::MouseDown(BPoint where) +{ + BMessage *currentMsg = Window()->CurrentMessage(); + if (currentMsg->what == B_MOUSE_DOWN) { + uint32 buttons = 0; + currentMsg->FindInt32("buttons", (int32 *)&buttons); + + uint32 modifiers = 0; + currentMsg->FindInt32("modifiers", (int32 *)&modifiers); + + if ((buttons & B_SECONDARY_MOUSE_BUTTON) || (modifiers & B_CONTROL_KEY)) { + // secondary button was clicked or control key was down, show menu and return + + BPopUpMenu *menu = new BPopUpMenu("Info"); + menu->SetFont(be_plain_font); + BuildInfoMenu(menu); + + BMenuItem *selected = menu->Go(ConvertToScreen(where)); + if (selected) + Window()->PostMessage(selected->Message()->what); + return; + } + + // add a mousedown looper here + + int32 pixelSize = PixelSize(); + float x = where.x / pixelSize; + float y = where.y / pixelSize; + + MoveSelectionTo(x, y); + + // draw the frozen image + // update the info region + + fNeedToUpdate = true; + Draw(Bounds()); + } +} + +void +TMagnify::ScreenChanged(BRect, color_space) +{ + int32 width, height; + fParent->PixelCount(&width, &height); + InitBuffers(width, height, fParent->PixelSize(), fParent->ShowGrid()); +} + +void +TMagnify::SetSelection(bool state) +{ + if (fShowSelection == state) + return; + + fShowSelection = state; + fSelection = 0; + Draw(Bounds()); +} + +static void +BoundsSelection(int32 incX, int32 incY, float* x, float* y, + int32 xCount, int32 yCount) +{ + *x += incX; + *y += incY; + + if (*x < 0) + *x = xCount-1; + if (*x >= xCount) + *x = 0; + + if (*y < 0) + *y = yCount-1; + if (*y >= yCount) + *y = 0; +} + +void +TMagnify::MoveSelection(int32 x, int32 y) +{ + if (!fShowSelection) + return; + + int32 xCount, yCount; + PixelCount(&xCount, &yCount); + + float xloc, yloc; + if (fSelection == 0) { + xloc = fSelectionLoc.x; + yloc = fSelectionLoc.y; + BoundsSelection(x, y, &xloc, &yloc, xCount, yCount); + fSelectionLoc.x = xloc; + fSelectionLoc.y = yloc; + } else if (fSelection == 1) { + xloc = fCrossHair1.x; + yloc = fCrossHair1.y; + BoundsSelection(x, y, &xloc, &yloc, xCount, yCount); + fCrossHair1.x = xloc; + fCrossHair1.y = yloc; + } else if (fSelection == 2) { + xloc = fCrossHair2.x; + yloc = fCrossHair2.y; + BoundsSelection(x, y, &xloc, &yloc, xCount, yCount); + fCrossHair2.x = xloc; + fCrossHair2.y = yloc; + } + + fNeedToUpdate = true; + Draw(Bounds()); +} + +void +TMagnify::MoveSelectionTo(int32 x, int32 y) +{ + if (!fShowSelection) + return; + + int32 xCount, yCount; + PixelCount(&xCount, &yCount); + if (x >= xCount) + x = 0; + if (y >= yCount) + y = 0; + + if (fSelection == 0) { + fSelectionLoc.x = x; + fSelectionLoc.y = y; + } else if (fSelection == 1) { + fCrossHair1.x = x; + fCrossHair1.y = y; + } else if (fSelection == 2) { + fCrossHair2.x = x; + fCrossHair2.y = y; + } + + fNeedToUpdate = true; + Draw(Bounds()); +} + +void +TMagnify::ShowSelection() +{ +} + +short +TMagnify::Selection() +{ + return fSelection; +} + +bool +TMagnify::SelectionIsShowing() +{ + return fShowSelection; +} + +void +TMagnify::SelectionLoc(float* x, float* y) +{ + *x = fSelectionLoc.x; + *y = fSelectionLoc.y; +} + +void +TMagnify::SetSelectionLoc(float x, float y) +{ + fSelectionLoc.x = x; + fSelectionLoc.y = y; +} + +rgb_color +TMagnify::SelectionColor() +{ + return fImageView->ColorAtSelection(); +} + +void +TMagnify::CrossHair1Loc(float* x, float* y) +{ + *x = fCrossHair1.x; + *y = fCrossHair1.y; +} + +void +TMagnify::CrossHair2Loc(float* x, float* y) +{ + *x = fCrossHair2.x; + *y = fCrossHair2.y; +} + +BPoint +TMagnify::CrossHair1Loc() +{ + return fCrossHair1; +} + +BPoint +TMagnify::CrossHair2Loc() +{ + return fCrossHair2; +} + +#include +void +TMagnify::NudgeMouse(float x, float y) +{ + BPoint loc; + ulong button; + + GetMouse(&loc, &button); + ConvertToScreen(&loc); + loc.x += x; + loc.y += y; + + set_mouse_position((int32)loc.x, (int32)loc.y); +} + +void +TMagnify::WindowActivated(bool active) +{ + if (active) + MakeFocus(); +} + +long +TMagnify::MagnifyTask(void *arg) +{ + TMagnify* view = (TMagnify*)arg; + + // static data members can't access members, methods without + // a pointer to an instance of the class + TWindow* window = (TWindow*)view->Window(); + + while (true) { + if (window->Lock()) { + +// if (!window->Minimized() && view->Active() || view->NeedToUpdate()) + if (view->NeedToUpdate() || view->Active()) + view->Update(view->NeedToUpdate()); + + window->Unlock(); + } + snooze(35000); + } + + return B_NO_ERROR; +} + +void +TMagnify::Update(bool force) +{ + BPoint loc; + ulong button; + static long counter = 0; + + GetMouse(&loc, &button); + + ConvertToScreen(&loc); + if (force || (fLastLoc != loc) || (counter++ % 35 == 0)) { + + if (fImageView->CreateImage(loc, force)) + Draw(Bounds()); + + counter = 0; + if (force) + SetUpdate(false); + + } + fLastLoc = loc; +} + +bool +TMagnify::NeedToUpdate() +{ + return fNeedToUpdate; +} + +void +TMagnify::SetUpdate(bool s) +{ + fNeedToUpdate = s; +} + +const char* const kBitmapMimeType = "image/x-vnd.Be-bitmap"; + +void +TMagnify::CopyImage() +{ + StartSave(); + be_clipboard->Lock(); + be_clipboard->Clear(); + + BMessage *message = be_clipboard->Data(); + if (!message) { + printf("no clip msg\n"); + return; + } + + BMessage *embeddedBitmap = new BMessage(); + (fImageView->Bitmap())->Archive(embeddedBitmap,false); + status_t err = message->AddMessage(kBitmapMimeType, embeddedBitmap); + ASSERT(err == B_OK); + err = message->AddRect("rect", (fImageView->Bitmap())->Bounds()); + ASSERT(err == B_OK); + + be_clipboard->Commit(); + be_clipboard->Unlock(); + EndSave(); +} + +void +TMagnify::AddCrossHair() +{ + if (fShowCrossHair1 && fShowCrossHair2) + return; + + int32 w, h; + PixelCount(&w, &h); + + if (fShowCrossHair1) { + fSelection = 2; + fShowCrossHair2 = true; + fCrossHair2.x = fCrossHair1.x + 2; + if (fCrossHair2.x >= w) + fCrossHair2.x = 0; + fCrossHair2.y = fCrossHair1.y + 2; + if (fCrossHair2.y >= h) + fCrossHair2.y = 0; + } else { + fSelection = 1; + fShowCrossHair1 = true; + fCrossHair1.x = fSelectionLoc.x + 2; + if (fCrossHair1.x >= w) + fCrossHair1.x = 0; + fCrossHair1.y = fSelectionLoc.y + 2; + if (fCrossHair1.y >= h) + fCrossHair1.y = 0; + } + Draw(Bounds()); +} + +void +TMagnify::RemoveCrossHair() +{ + if (!fShowCrossHair1 && !fShowCrossHair2) + return; + + if (fShowCrossHair2) { + fSelection = 1; + fShowCrossHair2 = false; + } else if (fShowCrossHair1) { + fSelection = 0; + fShowCrossHair1 = false; + } + Draw(Bounds()); +} + +void +TMagnify::SetCrossHairsShowing(bool ch1, bool ch2) +{ + fShowCrossHair1 = ch1; + fShowCrossHair2 = ch2; +} + +void +TMagnify::CrossHairsShowing(bool* ch1, bool* ch2) +{ + *ch1 = fShowCrossHair1; + *ch2 = fShowCrossHair2; +} + +void +TMagnify::MakeActive(bool s) +{ + fActive = s; +} + +void +TMagnify::PixelCount(int32* width, int32* height) +{ + fParent->PixelCount(width, height); +} + +int32 +TMagnify::PixelSize() +{ + return fParent->PixelSize(); +} + +bool +TMagnify::ShowGrid() +{ + return fParent->ShowGrid(); +} + +void +TMagnify::StartSave() +{ + fImageFrozenOnSave = Active(); + if (fImageFrozenOnSave) + MakeActive(false); +} + +void +TMagnify::EndSave() +{ + if (fImageFrozenOnSave) + MakeActive(true); +} + +void +TMagnify::SaveImage(entry_ref* ref, char* name, bool selectionOnly) +{ + // create a new file + BFile file; + BDirectory parentDir(ref); + parentDir.CreateFile(name, &file); + + // write off the bitmaps bits to the file + SaveBits(&file, fImageView->Bitmap(), "Data"); + + // unfreeze the image, image was frozen before invoke of FilePanel + EndSave(); +} + +void +TMagnify::SaveBits(BFile* file, const BBitmap *bitmap, char* name) const +{ + int32 bytesPerPixel; + const char *kColorSpaceName; + + switch (bitmap->ColorSpace()) { + case B_GRAY8: + bytesPerPixel = 1; + kColorSpaceName = "B_GRAY8"; + break; + + case B_CMAP8: + bytesPerPixel = 1; + kColorSpaceName = "B_CMAP8"; + break; + + case B_RGB15: + case B_RGBA15: + case B_RGB15_BIG: + case B_RGBA15_BIG: + bytesPerPixel = 2; + kColorSpaceName = "B_RGB15"; + break; + + case B_RGB16: + case B_RGB16_BIG: + bytesPerPixel = 2; + kColorSpaceName = "B_RGB16"; + break; + + case B_RGB32: + case B_RGBA32: + case B_RGBA32_BIG: + case B_BIG_RGB_32_BIT: + bytesPerPixel = 3; + kColorSpaceName = "B_RGB32"; + break; + + default: + printf("dump: usupported ColorSpace\n"); + return; + } + + char str[1024]; + // stream out the width, height and ColorSpace + sprintf(str, "const int32 k%sWidth = %ld;\n", name, (int32)bitmap->Bounds().Width()+1); + file->Write(str, strlen(str)); + sprintf(str, "const int32 k%sHeight = %ld;\n", name, (int32)bitmap->Bounds().Height()+1); + file->Write(str, strlen(str)); + sprintf(str, "const color_space k%sColorSpace = %s;\n\n", name, kColorSpaceName); + file->Write(str, strlen(str)); + + // stream out the constant name for this array + sprintf(str, "const unsigned char k%sBits [] = {", name); + file->Write(str, strlen(str)); + + const unsigned char *bits = (const unsigned char *)bitmap->Bits(); + const int32 kMaxColumnWidth = 16; + int32 bytesPerRow = bitmap->BytesPerRow(); + int32 columnWidth = (bytesPerRow < kMaxColumnWidth) ? bytesPerRow : kMaxColumnWidth; + + for (int32 remaining = bitmap->BitsLength(); remaining; ) { + + sprintf(str, "\n\t"); + file->Write(str, strlen(str)); + + // stream out each row, based on the number of bytes required per row + // padding is in the bitmap and will be streamed as 0xff + for (int32 column = 0; column < columnWidth; column++) { + + // stream out individual pixel components + for (int32 count = 0; count < bytesPerPixel; count++) { + --remaining; + sprintf(str, "0x%02x", *bits++); + file->Write(str, strlen(str)); + + if (remaining) { + sprintf(str, ","); + file->Write(str, strlen(str)); + } else + break; + } + + // make sure we don't walk off the end of the bits array + if (!remaining) + break; + + } + } + sprintf(str, "\n};\n\n"); + file->Write(str, strlen(str)); +} + +//****************************************************************************** + +TOSMagnify::TOSMagnify(BRect r, TMagnify* parent, color_space space) + :BView(r, "ImageView", B_FOLLOW_NONE, B_WILL_DRAW | B_FRAME_EVENTS), + fColorSpace(space), fParent(parent) +{ + fColorMap = ColorMap(); + + switch (space) { + case B_COLOR_8_BIT: + fBytesPerPixel = 1; + break; + case B_RGB15: + case B_RGBA15: + case B_RGB15_BIG: + case B_RGBA15_BIG: + case B_RGB16: + case B_RGB16_BIG: + fBytesPerPixel = 2; + break; + case B_RGB32: + case B_RGBA32: + case B_RGB32_BIG: + case B_RGBA32_BIG: + fBytesPerPixel = 4; + break; + default: + // uh, oh -- a color space we don't support + fprintf(stderr, "Tried to run in an unsupported color space; exiting\n"); + exit(1); + break; + } + + fPixel = NULL; + fBitmap = NULL; + fOldBits = NULL; + InitObject(); +} + +TOSMagnify::~TOSMagnify() +{ + delete fPixel; + delete(fBitmap); + free(fOldBits); +} + +void TOSMagnify::SetSpace(color_space space) +{ + fColorSpace = space; + InitObject(); +}; + +void TOSMagnify::InitObject() +{ + int32 w, h; + fParent->PixelCount(&w, &h); + + if (fBitmap) delete fBitmap; + BRect bitsRect(0, 0, w-1, h-1); + fBitmap = new BBitmap(bitsRect, fColorSpace); + + if (fOldBits) free(fOldBits); + fOldBits = (char*)malloc(fBitmap->BitsLength()); + + if (!fPixel) { + #if B_HOST_IS_BENDIAN + #define native B_RGBA32_BIG + #else + #define native B_RGBA32_LITTLE + #endif + fPixel = new BBitmap(BRect(0,0,0,0), native, true); + #undef native + fPixelView = new BView(BRect(0,0,0,0),NULL,0,0); + fPixel->Lock(); + fPixel->AddChild(fPixelView); + fPixel->Unlock(); + }; +} + +void +TOSMagnify::FrameResized(float width, float height) +{ + BView::FrameResized(width, height); + InitObject(); +} + +void +TOSMagnify::Resize(int32 width, int32 height) +{ + ResizeTo(width, height); + InitObject(); +} + +bool +TOSMagnify::CreateImage(BPoint mouseLoc, bool force) +{ + bool created = false; + if (Window() && Window()->Lock()) { + int32 width, height; + fParent->PixelCount(&width, &height); + int32 pixelSize = fParent->PixelSize(); + + BRect srcRect(0, 0, width - 1, height - 1); + srcRect.OffsetBy( mouseLoc.x - (width / 2), + mouseLoc.y - (height / 2)); + if (force || CopyScreenRect(srcRect)) { + + srcRect.OffsetTo(BPoint(0, 0)); + BRect destRect(Bounds()); + + DrawBitmap(fBitmap, srcRect, destRect); + + DrawGrid(width, height, destRect, pixelSize); + DrawSelection(); + + Sync(); + created = true; + } + Window()->Unlock(); + } else + printf("window problem\n"); + + return(created); +} + +bool +TOSMagnify::CopyScreenRect(BRect srcRect) +{ + // constrain src rect to legal screen rect + BScreen screen( Window() ); + BRect scrnframe = screen.Frame(); + + if (srcRect.right > scrnframe.right) + srcRect.OffsetTo(scrnframe.right - srcRect.Width(), + srcRect.top); + if (srcRect.top < 0) + srcRect.OffsetTo(srcRect.left, 0); + + if (srcRect.bottom > scrnframe.bottom) + srcRect.OffsetTo(srcRect.left, + scrnframe.bottom - srcRect.Height()); + if (srcRect.left < 0) + srcRect.OffsetTo(0, srcRect.top); + + // save a copy of the bits for comparison later + memcpy(fOldBits, fBitmap->Bits(), fBitmap->BitsLength()); + +#ifdef PR31 + _get_screen_bitmap_(fBitmap, srcRect); +#else + screen.ReadBitmap(fBitmap, false, &srcRect); +#endif + + // let caller know whether bits have actually changed + return(memcmp(fBitmap->Bits(), fOldBits, fBitmap->BitsLength()) != 0); +} + +void +TOSMagnify::DrawGrid(int32 width, int32 height, BRect destRect, int32 pixelSize) +{ + // draw grid + if (fParent->ShowGrid() && fParent->PixelSize() > 2) { + BeginLineArray(width * height); + + // horizontal lines + for (int32 i = pixelSize; i < (height * pixelSize); i += pixelSize) + AddLine(BPoint(0, i), BPoint(destRect.right, i), kGridGray); + + // vertical lines + for (int32 i = pixelSize; i < (width * pixelSize); i += pixelSize) + AddLine(BPoint(i, 0), BPoint(i, destRect.bottom), kGridGray); + + EndLineArray(); + } + + SetHighColor(kGridGray); + StrokeRect(destRect); +} + +void +TOSMagnify::DrawSelection() +{ + if (!fParent->SelectionIsShowing()) + return; + + float x, y; + int32 pixelSize = fParent->PixelSize(); + int32 squareSize = pixelSize - 2; + + fParent->SelectionLoc(&x, &y); + x *= pixelSize; x++; + y *= pixelSize; y++; + BRect selRect(x, y, x+squareSize, y+squareSize); + + short selection = fParent->Selection(); + + PushState(); + SetLowColor(ViewColor()); + SetHighColor(kRedColor); + StrokeRect(selRect); + if (selection == 0) { + StrokeLine(BPoint(x,y), BPoint(x+squareSize,y+squareSize)); + StrokeLine(BPoint(x,y+squareSize), BPoint(x+squareSize,y)); + } + + bool ch1Showing, ch2Showing; + fParent->CrossHairsShowing(&ch1Showing, &ch2Showing); + if (ch1Showing) { + SetHighColor(kBlueColor); + fParent->CrossHair1Loc(&x, &y); + x *= pixelSize; x++; + y *= pixelSize; y++; + selRect.Set(x, y,x+squareSize, y+squareSize); + StrokeRect(selRect); + BeginLineArray(4); + AddLine(BPoint(0, y+(squareSize/2)), + BPoint(x, y+(squareSize/2)), kBlueColor); // left + AddLine(BPoint(x+squareSize,y+(squareSize/2)), + BPoint(Bounds().Width(), y+(squareSize/2)), kBlueColor); // right + AddLine(BPoint(x+(squareSize/2), 0), + BPoint(x+(squareSize/2), y), kBlueColor); // top + AddLine(BPoint(x+(squareSize/2), y+squareSize), + BPoint(x+(squareSize/2), Bounds().Height()), kBlueColor); // bottom + EndLineArray(); + if (selection == 1) { + StrokeLine(BPoint(x,y), BPoint(x+squareSize,y+squareSize)); + StrokeLine(BPoint(x,y+squareSize), BPoint(x+squareSize,y)); + } + } + if (ch2Showing) { + SetHighColor(kBlueColor); + fParent->CrossHair2Loc(&x, &y); + x *= pixelSize; x++; + y *= pixelSize; y++; + selRect.Set(x, y,x+squareSize, y+squareSize); + StrokeRect(selRect); + BeginLineArray(4); + AddLine(BPoint(0, y+(squareSize/2)), + BPoint(x, y+(squareSize/2)), kBlueColor); // left + AddLine(BPoint(x+squareSize,y+(squareSize/2)), + BPoint(Bounds().Width(), y+(squareSize/2)), kBlueColor); // right + AddLine(BPoint(x+(squareSize/2), 0), + BPoint(x+(squareSize/2), y), kBlueColor); // top + AddLine(BPoint(x+(squareSize/2), y+squareSize), + BPoint(x+(squareSize/2), Bounds().Height()), kBlueColor); // bottom + EndLineArray(); + if (selection == 2) { + StrokeLine(BPoint(x,y), BPoint(x+squareSize,y+squareSize)); + StrokeLine(BPoint(x,y+squareSize), BPoint(x+squareSize,y)); + } + } + + PopState(); +} + +rgb_color +TOSMagnify::ColorAtSelection() +{ + float x, y; + fParent->SelectionLoc(&x, &y); + BRect srcRect(x,y,x,y); + BRect dstRect(0,0,0,0); + fPixel->Lock(); + fPixelView->DrawBitmap(fBitmap,srcRect,dstRect); + fPixelView->Sync(); + fPixel->Unlock(); + + uint32 pixel = *((uint32*)fPixel->Bits()); + rgb_color c; + c.alpha = pixel >> 24; + c.red = (pixel >> 16) & 0xFF; + c.green = (pixel >> 8) & 0xFF; + c.blue = pixel & 0xFF; + + return c; +} diff --git a/src/apps/magnify/main.h b/src/apps/magnify/main.h new file mode 100644 index 0000000000..a333f72c34 --- /dev/null +++ b/src/apps/magnify/main.h @@ -0,0 +1,270 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. +*/ + +#include +#include +#include +#include +#include +#include + +const int32 msg_save = 'save'; + +const rgb_color kViewGray = { 216, 216, 216, 255}; +const rgb_color kGridGray = {130, 130, 130, 255 }; +const rgb_color kWhite = { 255, 255, 255, 255}; +const rgb_color kBlack = { 0, 0, 0, 255}; +const rgb_color kDarkGray = { 96, 96, 96, 255}; +const rgb_color kRedColor = { 255, 10, 50, 255 }; +const rgb_color kGreenColor = { 10, 255, 50, 255 }; +const rgb_color kBlueColor = { 10, 50, 255, 255 }; + +//****************************************************************************** + +class TMagnify; +class TOSMagnify : public BView { +public: + TOSMagnify(BRect, TMagnify* parent, color_space space); + ~TOSMagnify(); + + void InitObject(); + void FrameResized(float width, float height); + void SetSpace(color_space space); + + void Resize(int32 width, int32 height); + + bool CreateImage(BPoint, bool force=false); + bool CopyScreenRect(BRect); + + void DrawGrid(int32 width, int32 height, + BRect dest, int32 pixelSize); + void DrawSelection(); + + rgb_color ColorAtSelection(); + + BBitmap* Bitmap() { return fBitmap; } + +private: + color_map* fColorMap; + color_space fColorSpace; + char* fOldBits; + long fBytesPerPixel; + + TMagnify* fParent; + BBitmap* fBitmap; + BBitmap* fPixel; + BView* fPixelView; +}; + +//****************************************************************************** + +class TWindow; +class TMagnify : public BView { +public: + TMagnify(BRect, TWindow*); + ~TMagnify(); + void AttachedToWindow(); + void InitBuffers(int32 hPixelCount, int32 vPixelCount, + int32 pixelSize, bool showGrid); + + void Draw(BRect); + + void KeyDown(const char *bytes, int32 numBytes); + void FrameResized(float, float); + void MouseDown(BPoint where); + void ScreenChanged(BRect bounds, color_space cs); + + void SetSelection(bool state); + void MoveSelection(int32 x, int32 y); + void MoveSelectionTo(int32 x, int32 y); + void ShowSelection(); + + short Selection(); + bool SelectionIsShowing(); + void SelectionLoc(float* x, float* y); + void SetSelectionLoc(float, float); + rgb_color SelectionColor(); + + void CrossHair1Loc(float* x, float* y); + void CrossHair2Loc(float* x, float* y); + BPoint CrossHair1Loc(); + BPoint CrossHair2Loc(); + + void NudgeMouse(float x, float y); + + void WindowActivated(bool); + +static long MagnifyTask(void *); + + void Update(bool force); + bool NeedToUpdate(); + void SetUpdate(bool); + + void CopyImage(); + + long ThreadID() { return fThread; } + + void MakeActive(bool); + bool Active() { return fActive; } + + void AddCrossHair(); + void RemoveCrossHair(); + void SetCrossHairsShowing(bool ch1=false, bool ch2=false); + void CrossHairsShowing(bool*, bool*); + + void PixelCount(int32* width, int32* height); + int32 PixelSize(); + bool ShowGrid(); + + void StartSave(); + void SaveImage(entry_ref* ref, char* name, bool selectionOnly=false); + void SaveBits(BFile* file, const BBitmap *bitmap, char* name) const; + void EndSave(); + +private: + bool fNeedToUpdate; + long fThread; // magnify thread id + bool fActive; // magnifying toggle + + + BBitmap* fImageBuf; // os buffer + TOSMagnify* fImageView; // os view + BPoint fLastLoc; + + short fSelection; + + bool fShowSelection; + BPoint fSelectionLoc; + + bool fShowCrossHair1; + BPoint fCrossHair1; + bool fShowCrossHair2; + BPoint fCrossHair2; + + TWindow* fParent; + + bool fImageFrozenOnSave; +}; + +//****************************************************************************** + +class TWindow; +class TMenu : public BMenu { +public: + TMenu(TWindow* mainWindow, const char *title=NULL, + menu_layout layout = B_ITEMS_IN_COLUMN); + ~TMenu(); + + void AttachedToWindow(); + +private: + TWindow* fMainWindow; +}; + +class TInfoView : public BBox { +public: + TInfoView(BRect frame); + ~TInfoView(); + + void AttachedToWindow(); + void Draw(BRect updateRect); + void FrameResized(float width, float height); + + void AddMenu(); + void SetMagView(TMagnify* magView); + +private: + float fFontHeight; + TMagnify* fMagView; + BMenuField* fPopUp; + TMenu* fMenu; + + int32 fHPixelCount; + int32 fVPixelCount; + int32 fPixelSize; + + rgb_color fSelectionColor; + + BPoint fCH1Loc; + BPoint fCH2Loc; + + char fInfoStr[64]; + char fRGBStr[64]; + char fCH1Str[64]; + char fCH2Str[64]; +}; + +//****************************************************************************** + +class TWindow : public BWindow { +public: + TWindow(int32 pixelCount=-1); + ~TWindow(); + + void MessageReceived(BMessage*); + bool QuitRequested(); + + void GetPrefs(int32 pixelCount=-1); + void SetPrefs(); + + void FrameResized(float w, float h); + void ScreenChanged(BRect screen_size, color_space depth); + + void Minimize(bool); + void Zoom(BPoint rec_position, float rec_width, float rec_height); + + void CalcViewablePixels(); + void GetPreferredSize(float* width, float* height); + + void ResizeWindow(int32 rowCount, int32 columnCount); + void ResizeWindow(bool direction); + + void SetGrid(bool); + bool ShowGrid(); + + void ShowInfo(bool); + bool InfoIsShowing(); + void UpdateInfo(); + + void AddCrossHair(); + void RemoveCrossHair(); + void CrossHairsShowing(bool* ch1, bool* ch2); + + void PixelCount(int32* h, int32 *v); + + void SetPixelSize(int32); + void SetPixelSize(bool); + int32 PixelSize(); + + void ShowHelp(); + + bool IsActive(); + +private: + float fInfoHeight; + bool fShowInfo; + float fFontHeight; + + bool fShowGrid; + + int32 fHPixelCount; + int32 fVPixelCount; + int32 fPixelSize; + + TMagnify* fFatBits; + TInfoView* fInfo; + + BFilePanel* fSavePanel; +}; + +//****************************************************************************** + +class TApp : public BApplication { +public: + TApp(int32 pixelCount=-1); + void MessageReceived(BMessage*); + void ReadyToRun(); + void AboutRequested(); +}; diff --git a/src/apps/pulse/BottomPrefsView.cpp b/src/apps/pulse/BottomPrefsView.cpp new file mode 100644 index 0000000000..dae5a58ada --- /dev/null +++ b/src/apps/pulse/BottomPrefsView.cpp @@ -0,0 +1,53 @@ +//**************************************************************************************** +// +// File: BottomPrefsView.cpp +// +// Written by: Daniel Switkin +// +// Copyright 1999, Be Incorporated +// +//**************************************************************************************** + +#include "BottomPrefsView.h" +#include "Common.h" +#include +#include + +BottomPrefsView::BottomPrefsView(BRect rect, const char *name) : + BView(rect, name, B_FOLLOW_NONE, B_WILL_DRAW) { + + // Set the background color dynamically, don't hardcode 216, 216, 216 + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + + BRect r = Bounds(); + r.right -= 13; + float width = be_plain_font->StringWidth("OK") + 20; + r.left = (width > 75) ? (r.right - width) : (r.right - 75); + r.top += 10; + r.bottom = r.top + 24; + BButton *ok = new BButton(r, "OKButton", "OK", new BMessage(PRV_BOTTOM_OK)); + AddChild(ok); + + r.right = r.left - 10; + width = be_plain_font->StringWidth("Defaults") + 20; + r.left = (width > 75) ? (r.right - width) : (r.right - 75); + BButton *defaults = new BButton(r, "DefaultsButton", "Defaults", new BMessage(PRV_BOTTOM_DEFAULTS)); + AddChild(defaults); + + ok->MakeDefault(true); +} + +// Do a little drawing to fit better with BTabView +void BottomPrefsView::Draw(BRect rect) { + PushState(); + + BRect bounds = Bounds(); + SetHighColor(255, 255, 255, 255); + StrokeLine(BPoint(0, 0), BPoint(bounds.right - 1, 0)); + StrokeLine(BPoint(0, 0), BPoint(0, bounds.bottom - 1)); + SetHighColor(96, 96, 96, 255); + StrokeLine(BPoint(bounds.right, 0), BPoint(bounds.right, bounds.bottom)); + StrokeLine(BPoint(0, bounds.bottom), BPoint(bounds.right, bounds.bottom)); + + PopState(); +} \ No newline at end of file diff --git a/src/apps/pulse/BottomPrefsView.h b/src/apps/pulse/BottomPrefsView.h new file mode 100644 index 0000000000..7e8d9bde20 --- /dev/null +++ b/src/apps/pulse/BottomPrefsView.h @@ -0,0 +1,22 @@ +//**************************************************************************************** +// +// File: BottomPrefsView.h +// +// Written by: Daniel Switkin +// +// Copyright 1999, Be Incorporated +// +//**************************************************************************************** + +#ifndef BOTTOMPREFSVIEW_H +#define BOTTOMPREFSVIEW_H + +#include + +class BottomPrefsView : public BView { + public: + BottomPrefsView(BRect rect, const char *name); + void Draw(BRect rect); +}; + +#endif \ No newline at end of file diff --git a/src/apps/pulse/CPUButton.cpp b/src/apps/pulse/CPUButton.cpp new file mode 100644 index 0000000000..2267534e34 --- /dev/null +++ b/src/apps/pulse/CPUButton.cpp @@ -0,0 +1,200 @@ +//**************************************************************************************** +// +// File: CPUButton.cpp +// +// Written by: Daniel Switkin +// +// Copyright 1999, Be Incorporated +// +//**************************************************************************************** + +#include "CPUButton.h" +#include "PulseApp.h" +#include "PulseView.h" +#include "Common.h" +#include +#include + +CPUButton::CPUButton(BRect rect, const char *name, const char *label, BMessage *message) : + BControl(rect, name, label, message, B_FOLLOW_NONE, B_WILL_DRAW) { + + off_color.red = off_color.green = off_color.blue = 184; + off_color.alpha = 255; + SetValue(B_CONTROL_ON); + SetViewColor(B_TRANSPARENT_COLOR); + replicant = false; +} + +CPUButton::CPUButton(BMessage *message) : BControl(message) { + off_color.red = off_color.green = off_color.blue = 184; + off_color.alpha = 255; + replicant = true; +} + +// Redraw the button depending on whether it's up or down +void CPUButton::Draw(BRect rect) { + bool value = (bool)Value(); + if (value) SetHighColor(on_color); + else SetHighColor(off_color); + + BRect bounds = Bounds(); + BRect color_rect(bounds); + color_rect.InsetBy(2, 2); + if (value) { + color_rect.bottom -= 1; + color_rect.right -= 1; + } + FillRect(bounds); + + if (value) SetHighColor(80, 80, 80); + else SetHighColor(255, 255, 255); + BPoint start(0, 0); + BPoint end(bounds.right, 0); + StrokeLine(start, end); + end.Set(0, bounds.bottom); + StrokeLine(start, end); + + if (value) SetHighColor(32, 32, 32); + else SetHighColor(216, 216, 216); + start.Set(1, 1); + end.Set(bounds.right - 1, 1); + StrokeLine(start, end); + end.Set(1, bounds.bottom - 1); + StrokeLine(start, end); + + if (value) SetHighColor(216, 216, 216); + else SetHighColor(80, 80, 80); + start.Set(bounds.left + 1, bounds.bottom - 1); + end.Set(bounds.right - 1, bounds.bottom - 1); + StrokeLine(start, end); + start.Set(bounds.right - 1, bounds.top + 1); + StrokeLine(start, end); + + if (value) SetHighColor(255, 255, 255); + else SetHighColor(32, 32, 32); + start.Set(bounds.left, bounds.bottom); + end.Set(bounds.right, bounds.bottom); + StrokeLine(start, end); + start.Set(bounds.right, bounds.top); + StrokeLine(start, end); + + if (value) { + SetHighColor(0, 0, 0); + start.Set(bounds.left + 2, bounds.bottom - 2); + end.Set(bounds.right - 2, bounds.bottom - 2); + StrokeLine(start, end); + start.Set(bounds.right - 2, bounds.top + 2); + StrokeLine(start, end); + } + + // Try to keep the text centered + BFont font; + GetFont(&font); + int label_width = (int)font.StringWidth(Label()); + int rect_width = bounds.IntegerWidth() - 1; + int rect_height = bounds.IntegerHeight(); + font_height fh; + font.GetHeight(&fh); + int label_height = (int)fh.ascent; + int x_pos = (int)(((double)(rect_width - label_width) / 2.0) + 0.5); + int y_pos = (rect_height - label_height) / 2 + label_height; + + MovePenTo(x_pos, y_pos); + SetHighColor(0, 0, 0); + SetDrawingMode(B_OP_OVER); + DrawString(Label()); +} + +// Track the mouse without blocking the window +void CPUButton::MouseDown(BPoint point) { + SetValue(!Value()); + SetTracking(true); + SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS); +} + +void CPUButton::MouseUp(BPoint point) { + if (Bounds().Contains(point)) Invoke(); + SetTracking(false); +} + +void CPUButton::MouseMoved(BPoint point, uint32 transit, const BMessage *message) { + if (IsTracking()) { + if (transit == B_ENTERED_VIEW || transit == B_EXITED_VIEW) SetValue(!Value()); + } +} + +status_t CPUButton::Invoke(BMessage *message) { + int my_cpu = atoi(Label()) - 1; + + if (!LastEnabledCPU(my_cpu)) { + _kset_cpu_state_(my_cpu, Value()); + } else { + BAlert *alert = new BAlert(NULL, "You can't disable the last active CPU.", "OK"); + alert->Go(NULL); + SetValue(!Value()); + } + + return B_OK; +} + +CPUButton *CPUButton::Instantiate(BMessage *data) { + if (!validate_instantiation(data, "CPUButton")) return NULL; + return new CPUButton(data); +} + +status_t CPUButton::Archive(BMessage *data, bool deep) const { + BControl::Archive(data, deep); + data->AddString("add_on", APP_SIGNATURE); + data->AddString("class", "CPUButton"); + return B_OK; +} + +void CPUButton::MessageReceived(BMessage *message) { + switch(message->what) { + case B_ABOUT_REQUESTED: { + BAlert *alert = new BAlert("Info", "Pulse\n\nBy David Ramsey and Arve HjønnevÃ¥g\nRevised by Daniel Switkin", "OK"); + // Use the asynchronous version so we don't block the window's thread + alert->Go(NULL); + break; + } + case PV_REPLICANT_PULSE: { + // Make sure we're consistent with our CPU + int my_cpu = atoi(Label()) - 1; + if (_kget_cpu_state_(my_cpu) != Value() && !IsTracking()) SetValue(!Value()); + break; + } + default: + BControl::MessageReceived(message); + break; + } +} + +void CPUButton::UpdateColors(int32 color) { + on_color.red = (color & 0xff000000) >> 24; + on_color.green = (color & 0x00ff0000) >> 16; + on_color.blue = (color & 0x0000ff00) >> 8; + Draw(Bounds()); +} + +void CPUButton::AttachedToWindow() { + SetTarget(this); + SetFont(be_plain_font); + SetFontSize(10); + + if (replicant) { + Prefs *prefs = new Prefs(); + UpdateColors(prefs->normal_bar_color); + delete prefs; + } else { + PulseApp *pulseapp = (PulseApp *)be_app; + UpdateColors(pulseapp->prefs->normal_bar_color); + } + + BMessenger messenger(this); + messagerunner = new BMessageRunner(messenger, new BMessage(PV_REPLICANT_PULSE), + 200000, -1); +} + +CPUButton::~CPUButton() { + delete messagerunner; +} \ No newline at end of file diff --git a/src/apps/pulse/CPUButton.h b/src/apps/pulse/CPUButton.h new file mode 100644 index 0000000000..0ad3aa55ca --- /dev/null +++ b/src/apps/pulse/CPUButton.h @@ -0,0 +1,42 @@ +//**************************************************************************************** +// +// File: CPUButton.h +// +// Written by: Daniel Switkin +// +// Copyright 1999, Be Incorporated +// +//**************************************************************************************** + +#ifndef CPUBUTTON_H +#define CPUBUTTON_H + +#include +#include + +class CPUButton : public BControl { + public: + CPUButton(BRect rect, const char *name, const char *label, BMessage *message); + CPUButton(BMessage *message); + void Draw(BRect rect); + void MouseDown(BPoint point); + void MouseUp(BPoint point); + void MouseMoved(BPoint point, uint32 transit, const BMessage *message); + ~CPUButton(); + + status_t Invoke(BMessage *message = NULL); + static CPUButton *Instantiate(BMessage *data); + status_t Archive(BMessage *data, bool deep = true) const; + void MessageReceived(BMessage *message); + + void UpdateColors(int32 color); + void AttachedToWindow(); + + private: + rgb_color on_color, off_color; + bool replicant; + BMessageRunner *messagerunner; +}; + +#endif + \ No newline at end of file diff --git a/src/apps/pulse/Common.h b/src/apps/pulse/Common.h new file mode 100644 index 0000000000..54d87e89bc --- /dev/null +++ b/src/apps/pulse/Common.h @@ -0,0 +1,69 @@ +//**************************************************************************************** +// +// File: Common.h +// +// Written by: Daniel Switkin +// +// Copyright 1999, Be Incorporated +// +//**************************************************************************************** + +#ifndef COMMON_H +#define COMMON_H + +enum { + NORMAL_WINDOW_MODE = 0, + MINI_WINDOW_MODE, + DESKBAR_MODE +}; + +enum { + PULSEVIEW_WIDTH = 263, + PULSEVIEW_MIN_HEIGHT = 82, + PROGRESS_MLEFT = 101, + PROGRESS_MTOP = 18, + PROGRESS_MBOTTOM = 10, + CPUBUTTON_MLEFT = 79, + CPUBUTTON_MTOP = 20, + CPUBUTTON_WIDTH = 16, + CPUBUTTON_HEIGHT = 16, + ITEM_OFFSET = 27 +}; + +#define APP_SIGNATURE "application/x-vnd.Be-PULS" + +#define PV_NORMAL_MODE 'pvnm' +#define PV_MINI_MODE 'pvmm' +#define PV_DESKBAR_MODE 'pvdm' +#define PV_PREFERENCES 'pvpr' +#define PV_ABOUT 'pvab' +#define PV_QUIT 'pvqt' +#define PV_CPU_MENU_ITEM 'pvcm' +#define PV_REPLICANT_PULSE 'pvrp' + +#define PRV_NORMAL_FADE_COLORS 'prnf' +#define PRV_NORMAL_CHANGE_COLOR 'prnc' +#define PRV_MINI_ACTIVE 'prma' +#define PRV_MINI_IDLE 'prmi' +#define PRV_MINI_FRAME 'prmf' +#define PRV_MINI_CHANGE_COLOR 'prmc' +#define PRV_DESKBAR_ACTIVE 'prda' +#define PRV_DESKBAR_IDLE 'prdi' +#define PRV_DESKBAR_FRAME 'prdf' +#define PRV_DESKBAR_ICON_WIDTH 'prdw' +#define PRV_DESKBAR_CHANGE_COLOR 'prdc' +#define PRV_BOTTOM_OK 'prbo' +#define PRV_BOTTOM_DEFAULTS 'prbd' +#define PRV_QUIT 'prvq' + +#define DEFAULT_NORMAL_BAR_COLOR 0x00f00000 +#define DEFAULT_MINI_ACTIVE_COLOR 0x20c02000 +#define DEFAULT_MINI_IDLE_COLOR 0x20402000 +#define DEFAULT_MINI_FRAME_COLOR 0x20202000 +#define DEFAULT_DESKBAR_ACTIVE_COLOR 0x20c02000 +#define DEFAULT_DESKBAR_IDLE_COLOR 0x20402000 +#define DEFAULT_DESKBAR_FRAME_COLOR 0x20202000 +#define DEFAULT_NORMAL_FADE_COLORS true +#define DEFAULT_DESKBAR_ICON_WIDTH 9 + +#endif diff --git a/src/apps/pulse/ConfigView.cpp b/src/apps/pulse/ConfigView.cpp new file mode 100644 index 0000000000..0e16274d45 --- /dev/null +++ b/src/apps/pulse/ConfigView.cpp @@ -0,0 +1,309 @@ +//**************************************************************************************** +// +// File: ConfigView.cpp +// +// Written by: Daniel Switkin +// +// Copyright 1999, Be Incorporated +// +//**************************************************************************************** + +#include "ConfigView.h" +#include "Common.h" +#include "PulseApp.h" +#include "PrefsWindow.h" +#include +#include +#include + +RTColorControl::RTColorControl(BPoint point, BMessage *message) + : BColorControl(point, B_CELLS_32x8, 6, "ColorControl", message, false) { + +} + +// Send a message every time the color changes, not just +// when the mouse button is released +void RTColorControl::SetValue(int32 color) { + BColorControl::SetValue(color); + Invoke(); +} + +// A single class for all three prefs views, needs to be +// customized below to give each control the right message +ConfigView::ConfigView(BRect rect, const char *name, int mode, Prefs *prefs) : + BView(rect, name, B_FOLLOW_NONE, B_WILL_DRAW) { + + this->mode = mode; + first_time_attached = true; + fadecolors = NULL; + active = idle = frame = NULL; + iconwidth = NULL; + + BRect r(6, 5, 296, 115); + BBox *bbox = new BBox(r, "BBox"); + bbox->SetLabel("Bar Colors"); + AddChild(bbox); + + if (mode == NORMAL_WINDOW_MODE) { + colorcontrol = new RTColorControl(BPoint(10, 20), + new BMessage(PRV_NORMAL_CHANGE_COLOR)); + } else if (mode == MINI_WINDOW_MODE) { + colorcontrol = new RTColorControl(BPoint(10, 20), + new BMessage(PRV_MINI_CHANGE_COLOR)); + } else { + colorcontrol = new RTColorControl(BPoint(10, 20), + new BMessage(PRV_DESKBAR_CHANGE_COLOR)); + } + + bbox->AddChild(colorcontrol); + r = colorcontrol->Frame(); + r.top = r.bottom + 10; + r.bottom = r.top + 15; + + if (mode == NORMAL_WINDOW_MODE) { + r.right = r.left + be_plain_font->StringWidth("Fade colors") + 20; + fadecolors = new BCheckBox(r, "FadeColors", "Fade colors", + new BMessage(PRV_NORMAL_FADE_COLORS)); + bbox->AddChild(fadecolors); + + colorcontrol->SetValue(prefs->normal_bar_color); + fadecolors->SetValue(prefs->normal_fade_colors); + } else if (mode == MINI_WINDOW_MODE) { + r.right = r.left + be_plain_font->StringWidth("Active color") + 20; + active = new BRadioButton(r, "ActiveColor", "Active color", + new BMessage(PRV_MINI_ACTIVE)); + bbox->AddChild(active); + active->SetValue(B_CONTROL_ON); + + r.left = r.right + 5; + r.right = r.left + be_plain_font->StringWidth("Idle color") + 20; + idle = new BRadioButton(r, "IdleColor", "Idle color", + new BMessage(PRV_MINI_IDLE)); + bbox->AddChild(idle); + + r.left = r.right + 5; + r.right = r.left + be_plain_font->StringWidth("Frame color") + 20; + frame = new BRadioButton(r, "FrameColor", "Frame color", + new BMessage(PRV_MINI_FRAME)); + bbox->AddChild(frame); + + colorcontrol->SetValue(prefs->mini_active_color); + } else { + bbox->ResizeBy(0, 20); + + r.right = r.left + be_plain_font->StringWidth("Active color") + 20; + active = new BRadioButton(r, "ActiveColor", "Active color", + new BMessage(PRV_DESKBAR_ACTIVE)); + bbox->AddChild(active); + active->SetValue(B_CONTROL_ON); + + r.left = r.right + 5; + r.right = r.left + be_plain_font->StringWidth("Idle color") + 20; + idle = new BRadioButton(r, "IdleColor", "Idle color", + new BMessage(PRV_DESKBAR_IDLE)); + bbox->AddChild(idle); + + r.left = r.right + 5; + r.right = r.left + be_plain_font->StringWidth("Frame color") + 20; + frame = new BRadioButton(r, "FrameColor", "Frame color", + new BMessage(PRV_DESKBAR_FRAME)); + bbox->AddChild(frame); + + r.top = active->Frame().bottom + 1; + r.bottom = r.top + 15; + r.left = 10; + r.right = r.left + be_plain_font->StringWidth("Width of icon:") + 5 + 30; + char temp[10]; + sprintf(temp, "%d", prefs->deskbar_icon_width); + iconwidth = new BTextControl(r, "Width", "Width of icon:", temp, + new BMessage(PRV_DESKBAR_ICON_WIDTH)); + bbox->AddChild(iconwidth); + iconwidth->SetDivider(be_plain_font->StringWidth("Width of icon:") + 5); + //iconwidth->SetModificationMessage(new BMessage(PRV_DESKBAR_ICON_WIDTH)); + + for (int x = 0; x < 256; x++) { + if (x < '0' || x > '9') iconwidth->TextView()->DisallowChar(x); + } + iconwidth->TextView()->SetMaxBytes(2); + + colorcontrol->SetValue(prefs->deskbar_active_color); + } +} + +void ConfigView::AttachedToWindow() { + BView::AttachedToWindow(); + + // AttachedToWindow() gets called every time this tab is brought + // to the front, but we only want this initialization to happen once + if (first_time_attached) { + BMessenger messenger(this); + colorcontrol->SetTarget(messenger); + if (fadecolors != NULL) fadecolors->SetTarget(messenger); + if (active != NULL) active->SetTarget(messenger); + if (idle != NULL) idle->SetTarget(messenger); + if (frame != NULL) frame->SetTarget(messenger); + if (iconwidth != NULL) iconwidth->SetTarget(messenger); + + first_time_attached = false; + } +} + +void ConfigView::MessageReceived(BMessage *message) { + PrefsWindow *prefswindow = (PrefsWindow *)Window(); + if (prefswindow == NULL) return; + Prefs *prefs = prefswindow->prefs; + BMessenger *messenger = prefswindow->messenger; + + switch (message->what) { + // These two send the color and the status of the fade checkbox together + case PRV_NORMAL_FADE_COLORS: + case PRV_NORMAL_CHANGE_COLOR: { + bool fade_colors = (bool)fadecolors->Value(); + int32 bar_color = colorcontrol->Value(); + message->AddInt32("color", bar_color); + message->AddBool("fade", fade_colors); + prefs->normal_fade_colors = fade_colors; + prefs->normal_bar_color = bar_color; + messenger->SendMessage(message); + break; + } + // Share the single color control among three values + case PRV_MINI_ACTIVE: + colorcontrol->SetValue(prefs->mini_active_color); + break; + case PRV_MINI_IDLE: + colorcontrol->SetValue(prefs->mini_idle_color); + break; + case PRV_MINI_FRAME: + colorcontrol->SetValue(prefs->mini_frame_color); + break; + case PRV_MINI_CHANGE_COLOR: { + int32 color = colorcontrol->Value(); + if (active->Value()) { + prefs->mini_active_color = color; + } else if (idle->Value()) { + prefs->mini_idle_color = color; + } else { + prefs->mini_frame_color = color; + } + message->AddInt32("active_color", prefs->mini_active_color); + message->AddInt32("idle_color", prefs->mini_idle_color); + message->AddInt32("frame_color", prefs->mini_frame_color); + messenger->SendMessage(message); + break; + } + case PRV_DESKBAR_ACTIVE: + colorcontrol->SetValue(prefs->deskbar_active_color); + break; + case PRV_DESKBAR_IDLE: + colorcontrol->SetValue(prefs->deskbar_idle_color); + break; + case PRV_DESKBAR_FRAME: + colorcontrol->SetValue(prefs->deskbar_frame_color); + break; + case PRV_DESKBAR_ICON_WIDTH: + UpdateDeskbarIconWidth(); + break; + case PRV_DESKBAR_CHANGE_COLOR: { + int32 color = colorcontrol->Value(); + if (active->Value()) { + prefs->deskbar_active_color = color; + } else if (idle->Value()) { + prefs->deskbar_idle_color = color; + } else { + prefs->deskbar_frame_color = color; + } + message->AddInt32("active_color", prefs->deskbar_active_color); + message->AddInt32("idle_color", prefs->deskbar_idle_color); + message->AddInt32("frame_color", prefs->deskbar_frame_color); + messenger->SendMessage(message); + break; + } + case PRV_BOTTOM_DEFAULTS: + ResetDefaults(); + break; + default: + BView::MessageReceived(message); + break; + } +} + +void ConfigView::UpdateDeskbarIconWidth() { + PrefsWindow *prefswindow = (PrefsWindow *)Window(); + if (prefswindow == NULL) return; + Prefs *prefs = prefswindow->prefs; + BMessenger *messenger = prefswindow->messenger; + + // Make sure the width shows at least one pixel per CPU and + // that it will fit in the tray in any Deskbar orientation + int width = atoi(iconwidth->Text()); + int min_width = GetMinimumViewWidth(); + if (width < min_width || width > 50) { + char temp[10]; + if (width < min_width) { + sprintf(temp, "%d", min_width); + width = min_width; + } else { + strcpy(temp, "50"); + width = 50; + } + iconwidth->SetText(temp); + } + + BMessage *message = new BMessage(PRV_DESKBAR_ICON_WIDTH); + message->AddInt32("width", width); + prefs->deskbar_icon_width = width; + messenger->SendMessage(message); + delete message; +} + +// Only reset our own controls to default +void ConfigView::ResetDefaults() { + PrefsWindow *prefswindow = (PrefsWindow *)Window(); + if (prefswindow == NULL) return; + Prefs *prefs = prefswindow->prefs; + BMessenger *messenger = prefswindow->messenger; + + if (mode == NORMAL_WINDOW_MODE) { + colorcontrol->SetValue(DEFAULT_NORMAL_BAR_COLOR); + fadecolors->SetValue(DEFAULT_NORMAL_FADE_COLORS); + } else if (mode == MINI_WINDOW_MODE) { + prefs->mini_active_color = DEFAULT_MINI_ACTIVE_COLOR; + prefs->mini_idle_color = DEFAULT_MINI_IDLE_COLOR; + prefs->mini_frame_color = DEFAULT_MINI_FRAME_COLOR; + if (active->Value()) { + colorcontrol->SetValue(DEFAULT_MINI_ACTIVE_COLOR); + } else if (idle->Value()) { + colorcontrol->SetValue(DEFAULT_MINI_IDLE_COLOR); + } else { + colorcontrol->SetValue(DEFAULT_MINI_FRAME_COLOR); + } + BMessage *message = new BMessage(PRV_MINI_CHANGE_COLOR); + message->AddInt32("active_color", DEFAULT_MINI_ACTIVE_COLOR); + message->AddInt32("idle_color", DEFAULT_MINI_IDLE_COLOR); + message->AddInt32("frame_color", DEFAULT_MINI_FRAME_COLOR); + messenger->SendMessage(message); + } else { + prefs->deskbar_active_color = DEFAULT_DESKBAR_ACTIVE_COLOR; + prefs->deskbar_idle_color = DEFAULT_DESKBAR_IDLE_COLOR; + prefs->deskbar_frame_color = DEFAULT_DESKBAR_FRAME_COLOR; + if (active->Value()) { + colorcontrol->SetValue(DEFAULT_DESKBAR_ACTIVE_COLOR); + } else if (idle->Value()) { + colorcontrol->SetValue(DEFAULT_DESKBAR_IDLE_COLOR); + } else { + colorcontrol->SetValue(DEFAULT_DESKBAR_FRAME_COLOR); + } + BMessage *message = new BMessage(PRV_DESKBAR_CHANGE_COLOR); + message->AddInt32("active_color", DEFAULT_DESKBAR_ACTIVE_COLOR); + message->AddInt32("idle_color", DEFAULT_DESKBAR_IDLE_COLOR); + message->AddInt32("frame_color", DEFAULT_DESKBAR_FRAME_COLOR); + messenger->SendMessage(message); + + char temp[10]; + sprintf(temp, "%d", DEFAULT_DESKBAR_ICON_WIDTH); + iconwidth->SetText(temp); + // Need to force the model message to be sent + iconwidth->Invoke(); + } +} \ No newline at end of file diff --git a/src/apps/pulse/ConfigView.h b/src/apps/pulse/ConfigView.h new file mode 100644 index 0000000000..30eda81a26 --- /dev/null +++ b/src/apps/pulse/ConfigView.h @@ -0,0 +1,47 @@ +//**************************************************************************************** +// +// File: ConfigView.h +// +// Written by: Daniel Switkin +// +// Copyright 1999, Be Incorporated +// +//**************************************************************************************** + +#ifndef CONFIGVIEW_H +#define CONFIGVIEW_H + +#include +#include +#include +#include +#include "Prefs.h" + +class RTColorControl : public BColorControl { + public: + RTColorControl(BPoint point, BMessage *message); + void SetValue(int32 color); +}; + +class ConfigView : public BView { + public: + ConfigView(BRect rect, const char *name, int mode, Prefs *prefs); + void AttachedToWindow(); + void MessageReceived(BMessage *message); + void UpdateDeskbarIconWidth(); + + private: + void ResetDefaults(); + bool first_time_attached; + int mode; + + RTColorControl *colorcontrol; + // For Normal + BCheckBox *fadecolors; + // For Mini and Deskbar + BRadioButton *active, *idle, *frame; + // For Deskbar + BTextControl *iconwidth; +}; + +#endif diff --git a/src/apps/pulse/DeskbarPulseView.cpp b/src/apps/pulse/DeskbarPulseView.cpp new file mode 100644 index 0000000000..ea3910a779 --- /dev/null +++ b/src/apps/pulse/DeskbarPulseView.cpp @@ -0,0 +1,189 @@ +//**************************************************************************************** +// +// File: DeskbarPulseView.cpp +// +// Written by: Daniel Switkin +// +// Copyright 1999, Be Incorporated +// +//**************************************************************************************** + +#include "DeskbarPulseView.h" +#include "Common.h" +#include "Prefs.h" +#include +#include +#include +#include +#include +#include +#include + +DeskbarPulseView::DeskbarPulseView(BRect rect) : MiniPulseView(rect, "DeskbarPulseView") { + messagerunner = NULL; + prefs = NULL; + prefswindow = NULL; +} + +DeskbarPulseView::DeskbarPulseView(BMessage *message) : MiniPulseView(message) { + mode1->SetLabel("Normal Mode"); + mode1->SetMessage(new BMessage(PV_NORMAL_MODE)); + mode2->SetLabel("Mini Mode"); + mode2->SetMessage(new BMessage(PV_MINI_MODE)); + quit = new BMenuItem("Quit", new BMessage(PV_QUIT), 0, 0); + popupmenu->AddSeparatorItem(); + popupmenu->AddItem(quit); + + SetViewColor(B_TRANSPARENT_COLOR); + + prefs = new Prefs(); + active_color.red = (prefs->deskbar_active_color & 0xff000000) >> 24; + active_color.green = (prefs->deskbar_active_color & 0x00ff0000) >> 16; + active_color.blue = (prefs->deskbar_active_color & 0x0000ff00) >> 8; + + idle_color.red = (prefs->deskbar_idle_color & 0xff000000) >> 24; + idle_color.green = (prefs->deskbar_idle_color & 0x00ff0000) >> 16; + idle_color.blue = (prefs->deskbar_idle_color & 0x0000ff00) >> 8; + + frame_color.red = (prefs->deskbar_frame_color & 0xff000000) >> 24; + frame_color.green = (prefs->deskbar_frame_color & 0x00ff0000) >> 16; + frame_color.blue = (prefs->deskbar_frame_color & 0x0000ff00) >> 8; + SetViewColor(idle_color); + + messagerunner = NULL; + prefswindow = NULL; +} + +void DeskbarPulseView::AttachedToWindow() { + BMessenger messenger(this); + mode1->SetTarget(messenger); + mode2->SetTarget(messenger); + preferences->SetTarget(messenger); + about->SetTarget(messenger); + quit->SetTarget(messenger); + + system_info sys_info; + get_system_info(&sys_info); + if (sys_info.cpu_count >= 2) { + for (int x = 0; x < sys_info.cpu_count; x++) { + cpu_menu_items[x]->SetTarget(messenger); + } + } + + // Use a BMessageRunner to deliver periodic messsages instead + // of Pulse() events from the Deskbar - this is to avoid changing + // the current pulse rate and affecting other replicants + messagerunner = new BMessageRunner(messenger, new BMessage(PV_REPLICANT_PULSE), + 200000, -1); +} + +void DeskbarPulseView::MouseDown(BPoint point) { + BPoint cursor; + uint32 buttons; + MakeFocus(true); + GetMouse(&cursor, &buttons, true); + + if (buttons & B_PRIMARY_MOUSE_BUTTON) { + BMessage *message = Window()->CurrentMessage(); + int32 clicks = message->FindInt32("clicks"); + if (clicks >= 2) { + BMessenger messenger(this); + BMessage *m = new BMessage(PV_NORMAL_MODE); + messenger.SendMessage(m); + } + } else MiniPulseView::MouseDown(point); +} + +void DeskbarPulseView::Pulse() { + // Override and do nothing here +} + +void DeskbarPulseView::MessageReceived(BMessage *message) { + switch (message->what) { + case PV_NORMAL_MODE: + SetMode(true); + Remove(); + break; + case PV_MINI_MODE: + SetMode(false); + Remove(); + break; + case PV_PREFERENCES: + if (prefswindow != NULL) { + prefswindow->Activate(true); + break; + } + prefswindow = new PrefsWindow(prefs->prefs_window_rect, "Pulse Preferences", + new BMessenger(this), prefs); + prefswindow->Show(); + break; + case PV_ABOUT: { + BAlert *alert = new BAlert("Info", "Pulse\n\nBy David Ramsey and Arve HjønnevÃ¥g\nRevised by Daniel Switkin", "OK"); + alert->Go(NULL); + break; + } + case PV_QUIT: + Remove(); + break; + case PRV_DESKBAR_CHANGE_COLOR: + UpdateColors(message); + break; + case PRV_DESKBAR_ICON_WIDTH: { + int width = message->FindInt32("width"); + ResizeTo(width - 1, 15); + Draw(Bounds()); + break; + } + case PV_REPLICANT_PULSE: + Update(); + Draw(Bounds()); + break; + case PRV_QUIT: + prefswindow = NULL; + break; + case PV_CPU_MENU_ITEM: + ChangeCPUState(message); + break; + default: + BView::MessageReceived(message); + break; + } +} + +DeskbarPulseView *DeskbarPulseView::Instantiate(BMessage *data) { + if (!validate_instantiation(data, "DeskbarPulseView")) return NULL; + return new DeskbarPulseView(data); +} + +status_t DeskbarPulseView::Archive(BMessage *data, bool deep) const { + PulseView::Archive(data, deep); + data->AddString("add_on", APP_SIGNATURE); + data->AddString("class", "DeskbarPulseView"); + return B_OK; +} + +void DeskbarPulseView::Remove() { + // Remove ourselves from the deskbar by name + BDeskbar *deskbar = new BDeskbar(); + status_t err = deskbar->RemoveItem("DeskbarPulseView"); + if (err != B_OK) { + char temp[255]; + sprintf(temp, "Remove(): %s", strerror(err)); + BAlert *alert = new BAlert("Info", temp, "OK"); + alert->Go(NULL); + } + delete deskbar; +} + +void DeskbarPulseView::SetMode(bool normal) { + if (normal) prefs->window_mode = NORMAL_WINDOW_MODE; + else prefs->window_mode = MINI_WINDOW_MODE; + prefs->Save(); + be_roster->Launch(APP_SIGNATURE); +} + +DeskbarPulseView::~DeskbarPulseView() { + if (messagerunner != NULL) delete messagerunner; + if (prefswindow != NULL && prefswindow->Lock()) prefswindow->Quit(); + if (prefs != NULL) delete prefs; +} \ No newline at end of file diff --git a/src/apps/pulse/DeskbarPulseView.h b/src/apps/pulse/DeskbarPulseView.h new file mode 100644 index 0000000000..a4a5f03d9f --- /dev/null +++ b/src/apps/pulse/DeskbarPulseView.h @@ -0,0 +1,40 @@ +//**************************************************************************************** +// +// File: DeskbarPulseView.h +// +// Written by: Daniel Switkin +// +// Copyright 1999, Be Incorporated +// +//**************************************************************************************** + +#ifndef DESKBARPULSEVIEW_H +#define DESKBARPULSEVIEW_H + +#include "MiniPulseView.h" +#include "PrefsWindow.h" +#include + +class DeskbarPulseView : public MiniPulseView { + public: + DeskbarPulseView(BRect rect); + DeskbarPulseView(BMessage *message); + ~DeskbarPulseView(); + void MouseDown(BPoint point); + void AttachedToWindow(); + void Pulse(); + + void MessageReceived(BMessage *message); + static DeskbarPulseView *Instantiate(BMessage *data); + virtual status_t Archive(BMessage *data, bool deep = true) const; + + private: + void Remove(); + void SetMode(bool normal); + + PrefsWindow *prefswindow; + Prefs *prefs; + BMessageRunner *messagerunner; +}; + +#endif \ No newline at end of file diff --git a/src/apps/pulse/LICENSE b/src/apps/pulse/LICENSE new file mode 100644 index 0000000000..86a4268fa9 --- /dev/null +++ b/src/apps/pulse/LICENSE @@ -0,0 +1,31 @@ +---------------------- +Be Sample Code License +---------------------- + +Copyright 1991-1999, Be Incorporated. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions, and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions, and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/apps/pulse/MiniPulseView.cpp b/src/apps/pulse/MiniPulseView.cpp new file mode 100644 index 0000000000..157c329532 --- /dev/null +++ b/src/apps/pulse/MiniPulseView.cpp @@ -0,0 +1,149 @@ +//**************************************************************************************** +// +// File: MiniPulseView.cpp +// +// Written by: Arve Hjonnevag and Daniel Switkin +// +// Copyright 1999, Be Incorporated +// +//**************************************************************************************** + +#include "MiniPulseView.h" +#include "Common.h" +#include + +MiniPulseView::MiniPulseView(BRect rect, const char *name, Prefs *prefs) : + PulseView(rect, name) { + + mode1->SetLabel("Normal Mode"); + mode1->SetMessage(new BMessage(PV_NORMAL_MODE)); + mode2->SetLabel("Deskbar Mode"); + mode2->SetMessage(new BMessage(PV_DESKBAR_MODE)); + quit = new BMenuItem("Quit", new BMessage(PV_QUIT), 0, 0); + popupmenu->AddSeparatorItem(); + popupmenu->AddItem(quit); + + // Our drawing covers every pixel in the view, so no reason to + // take the time (and to flicker) by resetting the view color + SetViewColor(B_TRANSPARENT_COLOR); + + active_color.red = (prefs->mini_active_color & 0xff000000) >> 24; + active_color.green = (prefs->mini_active_color & 0x00ff0000) >> 16; + active_color.blue = (prefs->mini_active_color & 0x0000ff00) >> 8; + + idle_color.red = (prefs->mini_idle_color & 0xff000000) >> 24; + idle_color.green = (prefs->mini_idle_color & 0x00ff0000) >> 16; + idle_color.blue = (prefs->mini_idle_color & 0x0000ff00) >> 8; + + frame_color.red = (prefs->mini_frame_color & 0xff000000) >> 24; + frame_color.green = (prefs->mini_frame_color & 0x00ff0000) >> 16; + frame_color.blue = (prefs->mini_frame_color & 0x0000ff00) >> 8; +} + +// These two are only used by DeskbarPulseView, and so do nothing +MiniPulseView::MiniPulseView(BRect rect, const char *name) : PulseView(rect, name) { + +} + +MiniPulseView::MiniPulseView(BMessage *message) : PulseView(message) { + +} + +// This method is used by DeskbarPulseView as well +void MiniPulseView::Draw(BRect rect) { + system_info sys_info; + get_system_info(&sys_info); + if (sys_info.cpu_count > B_MAX_CPU_COUNT || sys_info.cpu_count <= 0) return; + + BRect bounds(Bounds()); + SetDrawingMode(B_OP_COPY); + + int h = bounds.IntegerHeight() - 2; + float top = 1, left = 1; + float bottom = top + h; + float bar_width = (bounds.Width()) / sys_info.cpu_count - 2; + float right = bar_width + left; + + for (int x = 0; x < sys_info.cpu_count; x++) { + int bar_height = (int)(cpu_times[x] * (h + 1)); + if (bar_height > h) bar_height = h; + double rem = cpu_times[x] * (h + 1) - bar_height; + + rgb_color fraction_color; + fraction_color.red = (uint8)(idle_color.red + rem * (active_color.red - idle_color.red)); + fraction_color.green = (uint8)(idle_color.green + rem * (active_color.green - idle_color.green)); + fraction_color.blue = (uint8)(idle_color.blue + rem * (active_color.blue - idle_color.blue)); + fraction_color.alpha = 0xff; + + int idle_height = h - bar_height; + SetHighColor(frame_color); + StrokeRect(BRect(left - 1, top - 1, right + 1, bottom + 1)); + if (idle_height > 0) { + SetHighColor(idle_color); + FillRect(BRect(left, top, right, top + idle_height - 1)); + } + SetHighColor(fraction_color); + FillRect(BRect(left, bottom - bar_height, right, bottom - bar_height)); + if (bar_height > 0) { + SetHighColor(active_color); + FillRect(BRect(left, bottom - bar_height + 1, right, bottom)); + } + left += bar_width + 2; + right += bar_width + 2; + } +} + +void MiniPulseView::Pulse() { + // Don't recalculate and redraw if this view is hidden + if (!IsHidden()) { + Update(); + Draw(Bounds()); + } +} + +void MiniPulseView::FrameResized(float width, float height) { + Draw(Bounds()); +} + +void MiniPulseView::AttachedToWindow() { + BMessenger messenger(Window()); + mode1->SetTarget(messenger); + mode2->SetTarget(messenger); + preferences->SetTarget(messenger); + about->SetTarget(messenger); + quit->SetTarget(messenger); + + system_info sys_info; + get_system_info(&sys_info); + if (sys_info.cpu_count >= 2) { + for (int x = 0; x < sys_info.cpu_count; x++) { + cpu_menu_items[x]->SetTarget(messenger); + } + } +} + +// Redraw the view with the new colors but do not call +// Update() again - we don't want to recalculate activity +void MiniPulseView::UpdateColors(BMessage *message) { + int32 ac = message->FindInt32("active_color"); + int32 ic = message->FindInt32("idle_color"); + int32 fc = message->FindInt32("frame_color"); + + active_color.red = (ac & 0xff000000) >> 24; + active_color.green = (ac & 0x00ff0000) >> 16; + active_color.blue = (ac & 0x0000ff00) >> 8; + + idle_color.red = (ic & 0xff000000) >> 24; + idle_color.green = (ic & 0x00ff0000) >> 16; + idle_color.blue = (ic & 0x0000ff00) >> 8; + + frame_color.red = (fc & 0xff000000) >> 24; + frame_color.green = (fc & 0x00ff0000) >> 16; + frame_color.blue = (fc & 0x0000ff00) >> 8; + + Draw(Bounds()); +} + +MiniPulseView::~MiniPulseView() { + +} \ No newline at end of file diff --git a/src/apps/pulse/MiniPulseView.h b/src/apps/pulse/MiniPulseView.h new file mode 100644 index 0000000000..b529df2b72 --- /dev/null +++ b/src/apps/pulse/MiniPulseView.h @@ -0,0 +1,34 @@ +//**************************************************************************************** +// +// File: MiniPulseView.h +// +// Written by: Arve Hjonnevag and Daniel Switkin +// +// Copyright 1999, Be Incorporated +// +//**************************************************************************************** + +#ifndef MINIPULSEVIEW_H +#define MINIPULSEVIEW_H + +#include "PulseView.h" +#include "Prefs.h" + +class MiniPulseView : public PulseView { + public: + MiniPulseView(BRect rect, const char *name, Prefs *prefs); + MiniPulseView(BRect rect, const char *name); + MiniPulseView(BMessage *message); + ~MiniPulseView(); + void Draw(BRect rect); + void AttachedToWindow(); + void Pulse(); + void FrameResized(float width, float height); + void UpdateColors(BMessage *message); + + protected: + BMenuItem *quit; + rgb_color frame_color, active_color, idle_color; +}; + +#endif diff --git a/src/apps/pulse/NormalPulseView.cpp b/src/apps/pulse/NormalPulseView.cpp new file mode 100644 index 0000000000..03caa50521 --- /dev/null +++ b/src/apps/pulse/NormalPulseView.cpp @@ -0,0 +1,344 @@ +//**************************************************************************************** +// +// File: NormalPulseView.cpp +// +// Written by: Daniel Switkin +// +// Copyright 1999, Be Incorporated +// +//**************************************************************************************** + +#include "NormalPulseView.h" +#include "Common.h" +#include "Pictures" +#include +#include +#include +#include +#include + +NormalPulseView::NormalPulseView(BRect rect) : PulseView(rect, "NormalPulseView") { + rgb_color color = { 168, 168, 168, 0xff }; + SetViewColor(color); + SetLowColor(color); + + mode1->SetLabel("Mini Mode"); + mode1->SetMessage(new BMessage(PV_MINI_MODE)); + mode2->SetLabel("Deskbar Mode"); + mode2->SetMessage(new BMessage(PV_DESKBAR_MODE)); + + DetermineVendorAndProcessor(); + + // Allocate progress bars and button pointers + system_info sys_info; + get_system_info(&sys_info); + progress_bars = new ProgressBar *[sys_info.cpu_count]; + cpu_buttons = new CPUButton *[sys_info.cpu_count]; + + // Set up the CPU activity bars and buttons + for (int x = 0; x < sys_info.cpu_count; x++) { + BRect r(PROGRESS_MLEFT, PROGRESS_MTOP + ITEM_OFFSET * x, + PROGRESS_MLEFT + ProgressBar::PROGRESS_WIDTH, + PROGRESS_MTOP + ITEM_OFFSET * x + ProgressBar::PROGRESS_HEIGHT); + progress_bars[x] = new ProgressBar(r, "CPU Progress Bar"); + AddChild(progress_bars[x]); + + r.Set(CPUBUTTON_MLEFT, CPUBUTTON_MTOP + ITEM_OFFSET * x, + CPUBUTTON_MLEFT + CPUBUTTON_WIDTH, + CPUBUTTON_MTOP + ITEM_OFFSET * x + CPUBUTTON_HEIGHT); + char temp[4]; + sprintf(temp, "%d", x + 1); + cpu_buttons[x] = new CPUButton(r, "CPUButton", temp, NULL); + AddChild(cpu_buttons[x]); + + // If there is only 1 cpu it will be hidden below + // thus, no need to add the dragger as it will still + // be visible when replicants are turned on + if (sys_info.cpu_count > 1) { + BRect dragger_rect; + dragger_rect = r; + dragger_rect.top = dragger_rect.bottom; + dragger_rect.left = dragger_rect.right; + dragger_rect.bottom += 7; + dragger_rect.right += 7; + dragger_rect.OffsetBy(-1, -1); + BDragger *dragger = new BDragger(dragger_rect, cpu_buttons[x], 0); + AddChild(dragger); + } + } + + if (sys_info.cpu_count == 1) { + progress_bars[0]->MoveBy(-3, 12); + cpu_buttons[0]->Hide(); + } +} + +int NormalPulseView::CalculateCPUSpeed() { + system_info sys_info; + get_system_info(&sys_info); + + int target = sys_info.cpu_clock_speed / 1000000; + int frac = target % 100; + int delta = -frac; + int at = 0; + int freqs[] = { 100, 50, 25, 75, 33, 67, 20, 40, 60, 80, 10, 30, 70, 90 }; + + for (uint x = 0; x < sizeof(freqs) / sizeof(freqs[0]); x++) { + int ndelta = freqs[x] - frac; + if (abs(ndelta) < abs(delta)) { + at = freqs[x]; + delta = ndelta; + } + } + return target + delta; +} + +void NormalPulseView::DetermineVendorAndProcessor() { + system_info sys_info; + get_system_info(&sys_info); + + // Initialize logos + BRect r(0, 0, 63, 62); + cpu_logo = new BBitmap(r, B_COLOR_8_BIT); +#if __POWERPC__ + cpu_logo->SetBits(Anim1, 11718, 0, B_COLOR_8_BIT); +#endif +#if __INTEL__ + if (sys_info.cpu_type < B_CPU_AMD_X86) { + cpu_logo->SetBits(IntelLogo, 11718, 0, B_COLOR_8_BIT); + } else { + cpu_logo->SetBits(BlankLogo, 11718, 0, B_COLOR_8_BIT); + } +#endif + +#if __INTEL__ + // Determine x86 vendor name - Intel just set for completeness + switch (sys_info.cpu_type & B_CPU_X86_VENDOR_MASK) { + case B_CPU_INTEL_X86: + strcpy(vendor, "Intel"); + break; + case B_CPU_AMD_X86: + strcpy(vendor, "AMD"); + break; + case B_CPU_CYRIX_X86: + strcpy(vendor, "CYRIX"); + break; + case B_CPU_IDT_X86: + strcpy(vendor, "IDT"); + break; + case B_CPU_RISE_X86: + strcpy(vendor, "RISE"); + break; + default: + strcpy(vendor, "Unknown"); + break; + } +#endif + + // Determine CPU type + switch(sys_info.cpu_type) { +#if __POWERPC__ + case B_CPU_PPC_603: + strcpy(processor, "603"); + break; + case B_CPU_PPC_603e: + strcpy(processor, "603e"); + break; + case B_CPU_PPC_750: + strcpy(processor, "750"); + break; + case B_CPU_PPC_604: + strcpy(processor, "604"); + break; + case B_CPU_PPC_604e: + strcpy(processor, "604e"); + break; +#endif + +#if __INTEL__ + case B_CPU_X86: + strcpy(processor, "Unknown x86"); + break; + case B_CPU_INTEL_PENTIUM: + case B_CPU_INTEL_PENTIUM75: + strcpy(processor, "Pentium"); + break; + case B_CPU_INTEL_PENTIUM_486_OVERDRIVE: + case B_CPU_INTEL_PENTIUM75_486_OVERDRIVE: + strcpy(processor, "Pentium OD"); + break; + case B_CPU_INTEL_PENTIUM_MMX: + case B_CPU_INTEL_PENTIUM_MMX_MODEL_8: + strcpy(processor, "Pentium MMX"); + break; + case B_CPU_INTEL_PENTIUM_PRO: + strcpy(processor, "Pentium Pro"); + break; + case B_CPU_INTEL_PENTIUM_II_MODEL_3: + case B_CPU_INTEL_PENTIUM_II_MODEL_5: + strcpy(processor, "Pentium II"); + break; + case B_CPU_INTEL_CELERON: + strcpy(processor, "Celeron"); + break; + case B_CPU_INTEL_PENTIUM_III: + strcpy(processor, "Pentium III"); + break; + case B_CPU_AMD_K5_MODEL0: + case B_CPU_AMD_K5_MODEL1: + case B_CPU_AMD_K5_MODEL2: + case B_CPU_AMD_K5_MODEL3: + strcpy(processor, "K5"); + break; + case B_CPU_AMD_K6_MODEL6: + case B_CPU_AMD_K6_MODEL7: + strcpy(processor, "K6"); + break; + case B_CPU_AMD_K6_2: + strcpy(processor, "K6-2"); + break; + case B_CPU_AMD_K6_III: + strcpy(processor, "K6-III"); + break; + case B_CPU_AMD_ATHLON_MODEL1: + strcpy(processor, "Athlon"); + break; + case B_CPU_CYRIX_GXm: + strcpy(processor, "GXm"); + break; + case B_CPU_CYRIX_6x86MX: + strcpy(processor, "6x86MX"); + break; + case B_CPU_IDT_WINCHIP_C6: + strcpy(processor, "WinChip C6"); + break; + case B_CPU_IDT_WINCHIP_2: + strcpy(processor, "WinChip 2"); + break; + case B_CPU_RISE_mP6: + strcpy(processor, "mP6"); + break; +#endif + default: + strcpy(processor, "Unknown"); + break; + } +} + +void NormalPulseView::Draw(BRect rect) { + PushState(); + + // Black frame + SetHighColor(0, 0, 0); + BRect frame = Bounds(); + frame.right--; + frame.bottom--; + StrokeRect(frame); + + // Bevelled edges + SetHighColor(255, 255, 255); + StrokeLine(BPoint(1, 1), BPoint(frame.right - 1, 1)); + StrokeLine(BPoint(1, 1), BPoint(1, frame.bottom - 1)); + SetHighColor(80, 80, 80); + StrokeLine(BPoint(frame.right, 1), BPoint(frame.right, frame.bottom)); + StrokeLine(BPoint(2, frame.bottom), BPoint(frame.right - 1, frame.bottom)); + + // Dividing line + SetHighColor(96, 96, 96); + StrokeLine(BPoint(1, frame.bottom + 1), BPoint(frame.right, frame.bottom + 1)); + SetHighColor(255, 255, 255); + StrokeLine(BPoint(1, frame.bottom + 2), BPoint(frame.right, frame.bottom + 2)); + + // Processor picture + DrawBitmap(cpu_logo, BPoint(10, 10)); + +#if __INTEL__ + // Do nothing in the case of Intel CPUs - they already have a logo + if (strcmp(vendor, "Intel") != 0) { + SetDrawingMode(B_OP_OVER); + SetHighColor(240,240,240); + + float width = StringWidth(vendor); + MovePenTo(10 + (32 - width / 2), 30); + DrawString(vendor); + } +#endif + + // Draw processor type and speed + char buf[500]; + sprintf(buf, "%d MHz", CalculateCPUSpeed()); + SetDrawingMode(B_OP_OVER); + SetHighColor(240, 240, 240); + + float width = StringWidth(processor); + MovePenTo(10 + (32 - width / 2), 48); + DrawString(processor); + + width = StringWidth(buf); + MovePenTo(10 + (32 - width / 2), 60); + DrawString(buf); + + PopState(); +} + +void NormalPulseView::Pulse() { + // Don't recalculate and redraw if this view is hidden + if (!IsHidden()) { + Update(); + if (Window()->Lock()) { + system_info sys_info; + get_system_info(&sys_info); + + // Set the value of each CPU bar + for (int x = 0; x < sys_info.cpu_count; x++) { + progress_bars[x]->Set(max_c(0, cpu_times[x] * 100)); + } + + Sync(); + Window()->Unlock(); + } + } +} + +void NormalPulseView::AttachedToWindow() { + // Use a smaller font on x86 to accomodate longer processor names + SetFont(be_bold_font); +#if __INTEL__ + SetFontSize(7); +#else + SetFontSize(9); +#endif + prev_time = system_time(); + + BMessenger messenger(Window()); + mode1->SetTarget(messenger); + mode2->SetTarget(messenger); + preferences->SetTarget(messenger); + about->SetTarget(messenger); + + system_info sys_info; + get_system_info(&sys_info); + if (sys_info.cpu_count >= 2) { + for (int x = 0; x < sys_info.cpu_count; x++) { + cpu_menu_items[x]->SetTarget(messenger); + } + } +} + +void NormalPulseView::UpdateColors(BMessage *message) { + int32 color = message->FindInt32("color"); + bool fade = message->FindBool("fade"); + system_info sys_info; + get_system_info(&sys_info); + + for (int x = 0; x < sys_info.cpu_count; x++) { + progress_bars[x]->UpdateColors(color, fade); + cpu_buttons[x]->UpdateColors(color); + } +} + +NormalPulseView::~NormalPulseView() { + delete cpu_logo; + delete cpu_buttons; + delete progress_bars; +} \ No newline at end of file diff --git a/src/apps/pulse/NormalPulseView.h b/src/apps/pulse/NormalPulseView.h new file mode 100644 index 0000000000..a02391bdab --- /dev/null +++ b/src/apps/pulse/NormalPulseView.h @@ -0,0 +1,38 @@ +//**************************************************************************************** +// +// File: NormalPulseView.h +// +// Written by: Daniel Switkin +// +// Copyright 1999, Be Incorporated +// +//**************************************************************************************** + +#ifndef NORMALPULSEVIEW_H +#define NORMALPULSEVIEW_H + +#include "PulseView.h" +#include "ProgressBar.h" +#include "CPUButton.h" + +class NormalPulseView : public PulseView { + public: + NormalPulseView(BRect rect); + ~NormalPulseView(); + void Draw(BRect rect); + void Pulse(); + void AttachedToWindow(); + void UpdateColors(BMessage *message); + + private: + int CalculateCPUSpeed(); + void DetermineVendorAndProcessor(); + + char vendor[32], processor[32]; + bigtime_t prev_time; + ProgressBar **progress_bars; + CPUButton **cpu_buttons; + BBitmap *cpu_logo; +}; + +#endif diff --git a/src/apps/pulse/Pictures b/src/apps/pulse/Pictures new file mode 100644 index 0000000000..7065aa0028 --- /dev/null +++ b/src/apps/pulse/Pictures @@ -0,0 +1,763 @@ +unsigned char Ram[] = { +0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a, +0x9f,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a, +0x3a,0x9f,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b, +0x3a,0x3a,0x9f,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f, +0x3b,0x3a,0x3a,0x9f,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f, +0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a, +0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a, +0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b, +0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f, +0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f, +0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x9f,0x3b,0x3a,0x3a, +0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x9f,0x3b,0x3a, +0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x9f,0x3b, +0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x9f, +0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f, +0x9f,0x3b,0x3a,0x3a,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x4,0x4,0x4,0x4,0x5,0x4,0x0,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x9f, +0x3b,0x4,0x4,0x5,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x4,0x4,0x4,0x0,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x9f,0x3b, +0x4,0x12,0x11,0x12,0x11,0x12,0x11,0x12,0x11,0x12,0x11,0x12,0x11,0x12,0x11, +0x12,0x11,0x0,0x0,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x4,0x12,0x11, +0x12,0x11,0x12,0x11,0x12,0x11,0x12,0x11,0x12,0x11,0x12,0x11,0x12,0x11,0x0, +0x0,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x0,0x12,0x8,0x8, +0x8,0x9,0x8,0x8,0x8,0x9,0x8,0x8,0x8,0x9,0x8,0x8,0x8,0x0,0x0, +0x3a,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x9f,0x0,0x12,0x8,0x8,0x9,0x8,0x8, +0x8,0x9,0x8,0x8,0x8,0x9,0x8,0x8,0x8,0x9,0x0,0x0,0x9f,0x9f,0x3b, +0x3a,0x3a,0x9f,0x9f,0xe,0x16,0x1d,0x5,0x11,0x8,0x4,0x5,0x4,0x4,0x4, +0x0,0x2,0x2,0x8,0x4,0x4,0x5,0x4,0x8,0x0,0x0,0x16,0x1d,0xb,0x9f, +0x3b,0xf,0x15,0x1e,0x4,0x12,0x8,0x4,0x4,0x4,0x5,0x4,0x0,0x2,0x2, +0x8,0x4,0x4,0x4,0x4,0x9,0x0,0x0,0x15,0x1e,0xa,0x3a,0x3a,0x9f,0x9f, +0x4,0x4,0x5,0x0,0x11,0x8,0x5,0x4,0x4,0x4,0x4,0x0,0x2,0x2,0x8, +0x4,0x5,0x4,0x4,0x8,0x0,0x0,0x4,0x4,0x0,0x3a,0x9f,0x4,0x4,0x4, +0x1,0x11,0x8,0x4,0x5,0x4,0x4,0x4,0x0,0x2,0x2,0x8,0x4,0x5,0x4, +0x4,0x8,0x0,0x0,0x4,0x4,0x0,0x9f,0x9f,0x3b,0x3a,0xf,0x15,0x3f,0x4, +0x11,0x8,0x5,0x4,0x4,0x4,0x4,0x4,0x0,0x8,0x5,0x4,0x4,0x4,0x4, +0x8,0x0,0x0,0x16,0x3f,0xa,0x9f,0x9f,0xe,0x16,0x3f,0x4,0x11,0x8,0x5, +0x4,0x4,0x4,0x4,0x4,0x0,0x8,0x5,0x4,0x4,0x4,0x4,0x8,0x0,0x0, +0x16,0x3f,0xa,0x9f,0x9f,0x3b,0x3a,0x4,0x4,0x4,0x0,0x12,0x8,0x4,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x8,0x0,0x0,0x4, +0x4,0x0,0x3a,0x9f,0x4,0x4,0x4,0x0,0x12,0x8,0x4,0x4,0x5,0x4,0x4, +0x4,0x4,0x4,0x4,0x4,0x5,0x4,0x4,0x8,0x0,0x0,0x4,0x4,0x0,0x9f, +0x9f,0x9f,0x3b,0xf,0x15,0x3f,0x4,0x11,0x8,0x5,0x4,0x4,0x4,0x4,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x4,0x8,0x0,0x0,0x16,0x3f,0xa,0x9f,0x9f, +0xe,0x16,0x3f,0x4,0x11,0x8,0x5,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x4,0x8,0x0,0x0,0x16,0x3f,0xa,0x9f,0x9f,0x3b,0x3a,0x4, +0x4,0x4,0x0,0x12,0x8,0x4,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x4,0x4, +0x4,0x4,0x5,0x8,0x0,0x0,0x4,0x4,0x0,0x3a,0x9f,0x4,0x4,0x4,0x0, +0x12,0x8,0x4,0x4,0x5,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x4,0x4, +0x8,0x0,0x0,0x4,0x4,0x0,0x9f,0x9f,0x9f,0x3b,0xf,0x15,0x3f,0x4,0x11, +0x8,0x5,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x4,0x8, +0x0,0x0,0x16,0x3f,0xa,0x9f,0x9f,0xe,0x16,0x3f,0x4,0x11,0x8,0x5,0x4, +0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x4,0x8,0x0,0x0,0x16, +0x3f,0xa,0x9f,0x9f,0x3b,0x3a,0x4,0x4,0x4,0x0,0x12,0x8,0x4,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x8,0x0,0x0,0x4,0x4, +0x0,0x3a,0x9f,0x4,0x4,0x4,0x0,0x12,0x8,0x4,0x4,0x5,0x4,0x4,0x4, +0x4,0x4,0x4,0x4,0x5,0x4,0x4,0x8,0x0,0x0,0x4,0x4,0x0,0x9f,0x9f, +0x9f,0x3b,0xf,0x15,0x3f,0x4,0x11,0x8,0x5,0x4,0x4,0x4,0x4,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x4,0x8,0x0,0x0,0x16,0x3f,0xa,0x9f,0x9f,0xe, +0x16,0x3f,0x4,0x11,0x8,0x5,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x4,0x8,0x0,0x0,0x16,0x3f,0xa,0x9f,0x9f,0x3b,0x3a,0x4,0x4, +0x4,0x0,0x12,0x8,0x4,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x4,0x4,0x4, +0x4,0x5,0x8,0x0,0x0,0x4,0x4,0x0,0x3a,0x9f,0x4,0x4,0x4,0x0,0x12, +0x8,0x4,0x4,0x5,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x4,0x4,0x8, +0x0,0x0,0x4,0x4,0x0,0x9f,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x4,0x12,0x8, +0x4,0x4,0x5,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x4,0x4,0x8,0x0, +0x0,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x4,0x12,0x8,0x4,0x4,0x5, +0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x4,0x4,0x8,0x0,0x0,0x3a,0x3a, +0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x0,0x12,0x8,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x4,0x8,0x0,0x0,0x3a,0x3a,0x9f, +0x3b,0x3a,0x3a,0x9f,0x9f,0x0,0x11,0x8,0x4,0x5,0x4,0x4,0x4,0x4,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x8,0x0,0x0,0x3a,0x9f,0x3b,0x3a,0x3a,0x9f, +0x9f,0x9f,0x3b,0x3a,0x4,0x12,0x8,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x4, +0x4,0x4,0x4,0x5,0x4,0x8,0x0,0x0,0x3a,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f, +0x9f,0x4,0x11,0x9,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x4, +0x4,0x4,0x9,0x0,0x0,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a, +0x0,0x11,0x8,0x5,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x4,0x8,0x0,0x0,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x0,0x12,0x8, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x4,0x8,0x0, +0x0,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x4,0x12,0x8,0x4, +0x4,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x9,0x0,0x0, +0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x4,0x12,0x8,0x4,0x4,0x5,0x4, +0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x4,0x4,0x8,0x0,0x0,0x3a,0x3a,0x9f, +0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x0,0x12,0x8,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x4,0x8,0x0,0x0,0x3a,0x3a,0x9f,0x3b, +0x3a,0x3a,0x9f,0x9f,0x0,0x11,0x8,0x4,0x5,0x4,0x4,0x4,0x4,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x8,0x0,0x0,0x3a,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f, +0x9f,0x3b,0x3a,0x4,0x12,0x8,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x4,0x4, +0x4,0x4,0x5,0x4,0x8,0x0,0x0,0x3a,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x9f, +0x4,0x11,0x9,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x4,0x4, +0x4,0x9,0x0,0x0,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x0, +0x11,0x8,0x5,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x4, +0x8,0x0,0x0,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x0,0x12,0x8,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x4,0x8,0x0,0x0, +0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x4,0x12,0x8,0x4,0x4, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x9,0x0,0x0,0x9f, +0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x4,0x12,0x8,0x4,0x4,0x5,0x4,0x4, +0x4,0x4,0x4,0x4,0x4,0x5,0x4,0x4,0x8,0x0,0x0,0x3a,0x3a,0x9f,0x9f, +0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x0,0x12,0x8,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x4,0x4,0x4,0x4,0x5,0x4,0x8,0x0,0x0,0x3a,0x3a,0x9f,0x3b,0x3a, +0x3a,0x9f,0x9f,0x0,0x11,0x8,0x4,0x5,0x4,0x4,0x4,0x4,0x4,0x4,0x4, +0x5,0x4,0x4,0x4,0x8,0x0,0x0,0x3a,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x9f, +0x3b,0x3a,0x4,0x12,0x8,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x4,0x4,0x4, +0x4,0x5,0x4,0x8,0x0,0x0,0x3a,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x9f,0x4, +0x11,0x9,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x4,0x4,0x4, +0x9,0x0,0x0,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0xe,0x16,0x1e,0x0,0x11, +0x8,0x4,0x5,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x8, +0x0,0x0,0x16,0x1e,0xa,0x9f,0x9f,0xe,0x16,0x1e,0x0,0x11,0x9,0x4,0x4, +0x4,0x4,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x4,0x4,0x8,0x0,0x0,0x16, +0x1e,0xa,0x9f,0x9f,0x9f,0x3b,0x4,0x4,0x5,0x4,0x11,0x8,0x5,0x4,0x4, +0x4,0x4,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x4,0x8,0x0,0x0,0x4,0x5, +0x0,0x3a,0x9f,0x4,0x4,0x4,0x4,0x12,0x8,0x4,0x4,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x9,0x0,0x0,0x4,0x4,0x0,0x9f,0x9f, +0x3b,0x3a,0xe,0x16,0x3f,0x0,0x11,0x8,0x4,0x5,0x4,0x4,0x4,0x4,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x8,0x0,0x0,0x16,0x3f,0xa,0x9f,0x9f,0xe, +0x16,0x3f,0x0,0x11,0x8,0x4,0x5,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x8,0x0,0x0,0x16,0x3f,0xa,0x9f,0x9f,0x3b,0x3a,0x4,0x4, +0x4,0x4,0x12,0x8,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x4,0x4,0x4,0x4, +0x5,0x4,0x8,0x0,0x0,0x4,0x4,0x0,0x3a,0x3a,0x4,0x4,0x5,0x4,0x11, +0x8,0x5,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x4,0x8, +0x0,0x0,0x4,0x5,0x0,0x9f,0x9f,0x3b,0x3a,0xe,0x16,0x3f,0x0,0x11,0x8, +0x4,0x5,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x8,0x0, +0x0,0x16,0x3f,0xa,0x9f,0x9f,0xe,0x16,0x3f,0x0,0x11,0x8,0x4,0x5,0x4, +0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x8,0x0,0x0,0x16,0x3f, +0xa,0x9f,0x9f,0x3b,0x3a,0x4,0x4,0x4,0x4,0x12,0x8,0x4,0x4,0x0,0x0, +0x4,0x5,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x9,0x0,0x0,0x4,0x4,0x0, +0x3a,0x9f,0x4,0x4,0x4,0x4,0x12,0x8,0x4,0x4,0x0,0x0,0x5,0x4,0x4, +0x4,0x4,0x4,0x4,0x4,0x5,0x8,0x0,0x0,0x4,0x4,0x0,0x9f,0x9f,0x3b, +0x3a,0xe,0x16,0x3f,0x0,0x11,0x8,0x4,0x0,0x2,0x2,0x9,0x4,0x4,0x4, +0x4,0x4,0x4,0x5,0x4,0x8,0x0,0x0,0x16,0x3f,0xa,0x9f,0x9f,0xe,0x16, +0x3f,0x0,0x11,0x8,0x4,0x0,0x2,0x2,0x9,0x4,0x4,0x4,0x4,0x4,0x4, +0x5,0x4,0x8,0x0,0x0,0x16,0x3f,0xa,0x9f,0x9f,0x3b,0x3a,0x4,0x4,0x4, +0x4,0x12,0x8,0x4,0x0,0x2,0x2,0x8,0x5,0x4,0x4,0x4,0x4,0x4,0x4, +0x4,0x9,0x0,0x0,0x4,0x4,0x0,0x3a,0x9f,0x4,0x4,0x4,0x4,0x12,0x8, +0x4,0x0,0x2,0x2,0x9,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x8,0x0, +0x0,0x4,0x4,0x0,0x9f,0x9f,0x3b,0x3a,0xe,0x16,0x3f,0x4,0x11,0x8,0x5, +0x4,0x8,0x8,0x4,0x4,0x5,0x4,0x4,0x4,0x4,0x4,0x4,0x9,0x0,0x0, +0x15,0x3f,0xa,0x9f,0x9f,0xe,0x16,0x3f,0x4,0x11,0x8,0x5,0x4,0x8,0x8, +0x4,0x4,0x5,0x4,0x4,0x4,0x4,0x4,0x4,0x9,0x0,0x0,0x15,0x3f,0xa, +0x9f,0x9f,0x3b,0x3a,0x4,0x4,0x4,0x4,0x12,0x8,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x4,0x4,0x4,0x4,0x5,0x4,0x8,0x0,0x0,0x4,0x4,0x0,0x3a, +0x3a,0x4,0x4,0x5,0x4,0x11,0x8,0x5,0x4,0x4,0x4,0x4,0x4,0x4,0x4, +0x5,0x4,0x4,0x4,0x4,0x8,0x0,0x0,0x4,0x5,0x0,0x9f,0x9f,0x3b,0x3a, +0x3a,0x9f,0x9f,0x4,0x11,0x8,0x9,0x8,0x8,0x8,0x9,0x8,0x8,0x8,0x9, +0x8,0x8,0x8,0x9,0x8,0x0,0x0,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b, +0x4,0x12,0x8,0x8,0x9,0x8,0x8,0x8,0x9,0x8,0x8,0x8,0x9,0x8,0x8, +0x8,0x9,0x0,0x0,0x3a,0x9f,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x4, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x3a,0x3a,0x9f,0x9f,0x9f,0x3b,0x3a,0x3a,0x4,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x9f,0x3b,0x3a,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3a, +0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x9f,0x9f,0x3b,0x3a, +0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x9f,0x3b, +0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x9f, +0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f, +0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f, +0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a, +0x9f,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a, +0x3a,0x9f,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b, +0x3a,0x3a,0x9f,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f, +0x3b,0x3a,0x3a,0x9f,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f, +0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a, +0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a, +0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b, +0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f, +0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f, +0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x3b,0x3a,0x3a,0x9f,0x9f,0x9f,0x3b,0x3a,0x3a}; + +#if __POWERPC__ +unsigned char Anim1[] = { +0x15,0x15,0x15,0x16,0x15,0x15,0x15,0x16,0xa,0x4,0xb,0x4,0xb,0x4,0xb, +0x4,0xb,0x4,0xb,0x4,0xa,0x5,0xa,0x5,0xa,0x4,0xb,0x4,0xb,0x4, +0xb,0x4,0xb,0x4,0xb,0x4,0xa,0x5,0xa,0x5,0xa,0x4,0xb,0x4,0xb, +0x4,0xb,0x4,0xb,0x4,0xb,0x4,0xa,0x5,0xa,0x5,0x15,0x15,0x15,0x16, +0x15,0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15,0x4,0x15, +0x5,0x15,0x4,0x15,0x5,0x15,0x4,0x15,0x5,0x15,0x4,0x15,0x5,0x15,0x4, +0x15,0x5,0x15,0x4,0x15,0x5,0x15,0x4,0x15,0x5,0x15,0x4,0x15,0x5,0x15, +0x4,0x15,0x5,0x15,0x4,0x15,0x5,0x15,0x4,0x15,0x5,0x15,0x4,0x15,0x5, +0x15,0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15,0x15,0x15, +0x16,0x15,0x4,0x1e,0x4,0x3f,0x4,0x3f,0x4,0x3f,0x4,0x3f,0x4,0x3f,0x4, +0x3f,0x4,0x3f,0x4,0x3f,0x4,0x3f,0x4,0x3f,0x4,0x3f,0x4,0x3f,0x4,0x3f, +0x4,0x3f,0x4,0x3f,0x4,0x3f,0x4,0x3f,0x4,0x3f,0x4,0x3f,0x4,0x3f,0x4, +0x3f,0x4,0x3f,0x4,0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15,0x15,0x15,0x16, +0x15,0x15,0x0,0x0,0x0,0x4,0x1,0x5,0x1,0x4,0x1,0x4,0x1,0x4,0x1, +0x5,0x1,0x4,0x1,0x4,0x1,0x4,0x1,0x5,0x1,0x4,0x1,0x4,0x1,0x4, +0x1,0x5,0x1,0x4,0x1,0x4,0x1,0x4,0x1,0x5,0x1,0x4,0x1,0x4,0x1, +0x4,0x1,0x5,0x1,0x4,0x1,0x4,0x1,0x0,0x0,0x0,0x15,0x16,0x15,0x15, +0x15,0x16,0x15,0x15,0x15,0x1,0xf,0xf,0xf,0xf,0xf,0xf,0xe,0xf,0xf, +0xf,0xf,0xf,0xf,0xf,0xe,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xe,0xf, +0xf,0xf,0xf,0xf,0xf,0xf,0xe,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xe, +0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xe,0xf,0xf,0xf,0xf,0xf,0xf,0x4, +0x0,0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15,0x4,0xf,0x9,0x8,0x9,0x8, +0x9,0x8,0x9,0x8,0x9,0x8,0x9,0x8,0x9,0x8,0x9,0x8,0x9,0x8,0x9, +0x8,0x9,0x8,0x9,0x8,0x9,0x8,0x9,0x8,0x9,0x8,0x9,0x8,0x9,0x8, +0x9,0x8,0x9,0x8,0x9,0x8,0x9,0x8,0x9,0x8,0x9,0x8,0x9,0x8,0x9, +0x8,0x9,0x8,0x4,0x0,0x16,0x15,0x15,0x15,0x16,0x15,0x15,0x15,0x1,0xf, +0x9,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x9,0x4,0x0,0x15,0x15,0x16,0x15,0x15,0xb, +0x15,0x15,0x2,0xf,0x9,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x9,0x4,0x4,0x15,0x16, +0x15,0x15,0x15,0x5,0x4,0x4,0x1,0xf,0x9,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x9, +0x4,0x1,0x4,0x4,0x5,0x15,0x15,0xb,0x15,0x3f,0x4,0xf,0x8,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x8,0x4,0x5,0x15,0x3f,0xa,0x15,0x16,0x4,0x4,0x4,0x1, +0xf,0x9,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x9,0x4,0x1,0x4,0x5,0x4,0x15,0x15, +0xb,0x15,0x3f,0x4,0xf,0x8,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x8,0x4,0x5,0x15, +0x3f,0xa,0x15,0x16,0x4,0x4,0x4,0x1,0xf,0x9,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x9,0x4,0x1,0x4,0x5,0x4,0x15,0x15,0xb,0x15,0x3f,0x4,0xf,0x8,0x4, +0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x8,0x4,0x5,0x15,0x3f,0xa,0x15,0x16,0x4,0x4,0x4, +0x1,0xf,0x9,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x9,0x4,0x1,0x4,0x5,0x4,0x15, +0x15,0xb,0x15,0x3f,0x4,0xf,0x8,0x4,0x5,0x4,0x4,0x4,0x18,0x1e,0x1d, +0x1e,0xb,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x18, +0x1e,0x1d,0x1e,0x4,0x5,0x4,0xa,0x1e,0x1e,0x4,0x4,0x5,0x8,0x4,0x5, +0x15,0x3f,0xa,0x15,0x16,0x4,0x4,0x4,0x1,0xf,0x9,0x4,0x4,0x5,0x4, +0x4,0x1e,0x1e,0x1d,0x1e,0x1e,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x1d,0x1e,0x1e,0x1e,0x1d,0x5,0x17,0x1e,0x1d,0x1e,0x4,0x5, +0x4,0x8,0x5,0x1,0x4,0x4,0x4,0x16,0x15,0xb,0x15,0x3f,0x4,0xf,0x8, +0x4,0x5,0x4,0x4,0xb,0x1e,0xa,0x4,0x1e,0x1e,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0xb,0x1e,0xa,0x5,0x1d,0x1e,0xb,0x1e,0x1d, +0xb,0x4,0x4,0x5,0x4,0x8,0x5,0x4,0x15,0x3f,0xa,0x15,0x16,0x4,0x4, +0x4,0x1,0xf,0x9,0x4,0x4,0x5,0x4,0x17,0x1e,0x17,0xb,0x1e,0xa,0x5, +0xa,0x1e,0x1e,0x1d,0xb,0x4,0x1e,0x1e,0x4,0x1e,0x1e,0x4,0x1e,0x1d,0x5, +0x4,0x1e,0x1d,0x5,0x4,0x1e,0x1d,0x5,0x17,0x4,0x18,0x1d,0x18,0xa,0x1e, +0xb,0x1d,0x1e,0xb,0x4,0x4,0x5,0x4,0x4,0x9,0x4,0x1,0x4,0x4,0x5, +0x15,0x15,0xb,0x15,0x3f,0x4,0xf,0x8,0x4,0x5,0x4,0x4,0x1e,0x1e,0x4, +0x3f,0xa,0x4,0x5,0x1d,0x1e,0x4,0x1e,0x1e,0x4,0x1e,0x1e,0x4,0x1e,0x1d, +0x5,0x1d,0x1e,0x4,0x1e,0x1e,0x4,0x3f,0x4,0x1e,0x1d,0x1e,0x1e,0x4,0x1e, +0x1e,0x4,0x3f,0xa,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x9,0x4, +0x4,0x16,0x3f,0xa,0x15,0x16,0x4,0x4,0x4,0x1,0xf,0x9,0x4,0x4,0x5, +0xa,0x1e,0x1e,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x1e, +0x1e,0x1e,0x1d,0x1e,0x1e,0x1e,0xa,0x1e,0x1e,0x4,0x3f,0x3f,0xa,0x1e,0x17, +0x5,0x4,0xa,0x1e,0x1e,0x4,0x4,0x5,0x4,0x1e,0x1d,0xb,0x4,0x5,0x4, +0x4,0x4,0x9,0x4,0x1,0x4,0x5,0x4,0x15,0x15,0xb,0x15,0x3f,0x4,0xf, +0x8,0x4,0x5,0x4,0x17,0x1e,0x17,0x5,0x4,0x4,0x4,0x1e,0x1e,0x4,0x1e, +0x1e,0x4,0x4,0xb,0x1e,0x1d,0x5,0x1d,0x1e,0xb,0x4,0x1e,0x1d,0x5,0x4, +0x4,0x1e,0x1e,0x4,0x4,0x4,0x18,0x1e,0x17,0x4,0x4,0x5,0x4,0x1e,0x1d, +0x1e,0x1e,0x4,0x4,0x5,0x4,0x8,0x5,0x4,0x15,0x3f,0xa,0x15,0x16,0x4, +0x4,0x4,0x1,0xf,0x9,0x4,0x4,0x5,0x1d,0x1e,0xb,0x4,0x4,0x4,0x5, +0xa,0x1e,0x1e,0x1e,0xa,0x4,0x5,0x4,0x1e,0x1d,0x5,0x1d,0x1e,0x4,0x5, +0x4,0x1e,0x1d,0x1e,0x4,0x1e,0x1e,0x4,0x4,0x5,0x1d,0x1e,0xb,0x4,0x4, +0x5,0x4,0xa,0x1e,0x1e,0x1e,0x4,0x4,0x4,0x5,0x8,0x4,0x1,0x5,0x4, +0x4,0x15,0x16,0xa,0x16,0x3f,0x4,0xf,0x8,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x8, +0x4,0x5,0x15,0x3f,0xa,0x15,0x16,0x4,0x4,0x4,0x1,0xf,0x9,0x4,0x4, +0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x9,0x4,0x1,0x4,0x5,0x4,0x15,0x15,0xb,0x15,0x3f,0x4, +0xf,0x8,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x8,0x4,0x5,0x15,0x3f,0xa,0x15,0x16, +0x4,0x4,0x4,0x1,0xf,0x9,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x9,0x4,0x1,0x4, +0x5,0x4,0x15,0x15,0xb,0x15,0x3f,0x4,0xf,0x8,0x4,0x5,0x4,0x4,0x4, +0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x8,0x4,0x5,0x15,0x3f,0xa,0x15,0x16,0x4,0x4,0x4,0x1,0xf,0x9,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x5,0x4,0x4,0x4,0x9,0x4,0x1,0x4,0x5,0x4,0x15,0x15,0xb,0x15,0x3f, +0x4,0xf,0x8,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x8,0x4,0x5,0x15,0x3f,0xa,0x15, +0x16,0x4,0x4,0x4,0x1,0xf,0x9,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x9,0x4,0x1, +0x4,0x5,0x4,0x15,0x15,0xb,0x15,0x3f,0x4,0xf,0x8,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x5,0x8,0x4,0x5,0x15,0x3f,0xa,0x15,0x16,0x4,0x4,0x4,0x1,0xf,0x9, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x9,0x4,0x1,0x4,0x5,0x4,0x15,0x15,0xb,0x15, +0x3f,0x4,0xf,0x8,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x8,0x4,0x5,0x15,0x3f,0xa, +0x15,0x16,0x4,0x4,0x4,0x1,0xf,0x9,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x9,0x4, +0x1,0x4,0x5,0x4,0x15,0x15,0xb,0x15,0x3f,0x4,0xf,0x8,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x8,0x4,0x5,0x15,0x3f,0xa,0x15,0x16,0x4,0x4,0x4,0x1,0xf, +0x9,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x9,0x4,0x1,0x4,0x5,0x4,0x15,0x15,0xb, +0x15,0x3f,0x4,0xf,0x8,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x8,0x4,0x5,0x15,0x3f, +0xa,0x15,0x16,0x4,0x4,0x4,0x1,0xf,0x9,0x4,0x4,0x5,0x4,0x4,0x4, +0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x9, +0x4,0x1,0x4,0x5,0x4,0x15,0x15,0xb,0x15,0x3f,0x4,0xf,0x8,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x8,0x4,0x5,0x15,0x3f,0xa,0x15,0x16,0x4,0x4,0x4,0x1, +0xf,0x9,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x9,0x4,0x1,0x4,0x5,0x4,0x15,0x15, +0xb,0x15,0x3f,0x4,0xf,0x8,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x8,0x4,0x5,0x15, +0x3f,0xa,0x15,0x16,0x4,0x4,0x4,0x1,0xf,0x9,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x9,0x4,0x1,0x4,0x5,0x4,0x15,0x15,0xb,0x15,0x3f,0x4,0xf,0x8,0x4, +0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x8,0x4,0x5,0x15,0x3f,0xa,0x15,0x16,0x4,0x4,0x4, +0x1,0xf,0x9,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x9,0x4,0x1,0x4,0x5,0x4,0x15, +0x15,0xb,0x15,0x3f,0x4,0xf,0x8,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x8,0x4,0x5, +0x15,0x3f,0xa,0x15,0x16,0x4,0x4,0x4,0x1,0xf,0x9,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x9,0x4,0x1,0x4,0x5,0x4,0x15,0x15,0xb,0x15,0x3f,0x4,0xf,0x8, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x5,0x4,0x4,0x4,0x5,0x8,0x4,0x5,0x15,0x3f,0xa,0x15,0x16,0x4,0x4, +0x4,0x1,0xf,0x9,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x9,0x4,0x1,0x4,0x5,0x4, +0x15,0x15,0xb,0x15,0x3f,0x4,0xf,0x8,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x8,0x4, +0x5,0x15,0x3f,0xa,0x15,0x16,0x4,0x4,0x4,0x1,0xf,0x9,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x9,0x4,0x1,0x4,0x5,0x4,0x15,0x15,0xb,0x15,0x3f,0x4,0xf, +0x8,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x8,0x4,0x5,0x15,0x3f,0xa,0x15,0x16,0x4, +0x4,0x4,0x1,0xf,0x9,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x9,0x4,0x1,0x4,0x5, +0x4,0x15,0x15,0xb,0x15,0x3f,0x4,0xf,0x8,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x8, +0x4,0x5,0x15,0x3f,0xa,0x15,0x16,0x4,0x4,0x4,0x1,0xf,0x9,0x4,0x4, +0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x9,0x4,0x1,0x4,0x5,0x4,0x15,0x15,0x16,0x15,0x15,0x4, +0xf,0x9,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x9,0x4,0x0,0x15,0x15,0x16,0x15,0x15, +0x15,0x16,0x15,0x1,0xf,0x8,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4, +0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x8,0x5,0x0,0x15, +0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x4,0xf,0x8,0x9,0x8,0x9,0x8,0x9, +0x8,0x9,0x8,0x9,0x8,0x9,0x8,0x9,0x8,0x9,0x8,0x9,0x8,0x9,0x8, +0x9,0x8,0x9,0x8,0x9,0x8,0x9,0x8,0x9,0x8,0x9,0x8,0x9,0x8,0x9, +0x8,0x9,0x8,0x9,0x8,0x9,0x8,0x9,0x8,0x9,0x8,0x9,0x8,0x9,0x8, +0x9,0x4,0x0,0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15,0x1,0xf,0x4,0x4, +0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4, +0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4, +0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5,0x4,0x4,0x4,0x5, +0x4,0x4,0x4,0x5,0x4,0x4,0x0,0x15,0x16,0x15,0x15,0x15,0x16,0x15,0x15, +0x15,0x5,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x15,0x15,0x15,0x16,0x15, +0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15,0x15,0x4,0x16,0x4,0x15,0x4,0x16, +0x4,0x15,0x4,0x16,0x4,0x15,0x4,0x16,0x4,0x15,0x4,0x16,0x4,0x15,0x4, +0x16,0x4,0x15,0x4,0x16,0x4,0x15,0x4,0x16,0x4,0x15,0x4,0x16,0x4,0x15, +0x4,0x16,0x4,0x15,0x4,0x16,0x4,0x15,0x4,0x16,0x4,0x15,0x15,0x16,0x15, +0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15,0x15,0x4,0x3f, +0x4,0x3f,0x4,0x3f,0x4,0x3f,0x4,0x3f,0x4,0x3f,0x4,0x3f,0x4,0x3f,0x4, +0x3f,0x4,0x3f,0x4,0x3f,0x4,0x3f,0x4,0x3f,0x4,0x3f,0x4,0x3f,0x4,0x3f, +0x4,0x3f,0x4,0x3f,0x4,0x3f,0x4,0x3f,0x4,0x3f,0x4,0x3f,0x4,0x3f,0x4, +0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15,0x15,0x15,0x16, +0x15,0xa,0x1,0xb,0x1,0xb,0x1,0xa,0x1,0xb,0x1,0xb,0x1,0xa,0x1, +0xb,0x1,0xa,0x1,0xb,0x1,0xb,0x1,0xa,0x1,0xb,0x1,0xb,0x1,0xa, +0x1,0xb,0x1,0xa,0x1,0xb,0x1,0xb,0x1,0xa,0x1,0xb,0x1,0xb,0x1, +0xa,0x1,0xb,0x1,0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15}; +#endif + +#if __INTEL__ +unsigned char IntelLogo[] = { +0x15,0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x0a,0x04,0x0b,0x04,0x0b,0x04,0x0b,0x04, +0x0b,0x04,0x0b,0x04,0x0a,0x05,0x0a,0x05,0x0a,0x04,0x0b,0x04,0x0b,0x04,0x0b,0x04, +0x0b,0x04,0x0b,0x04,0x0a,0x05,0x0a,0x05,0x0a,0x04,0x0b,0x04,0x0b,0x04,0x0b,0x04, +0x0b,0x04,0x0b,0x04,0x0a,0x05,0x0a,0x05,0x15,0x15,0x15,0x16,0x15,0x15,0x15,0x16, +0x15,0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15,0x04,0x15,0x05,0x15,0x04,0x15,0x05, +0x15,0x04,0x15,0x05,0x15,0x04,0x15,0x05,0x15,0x04,0x15,0x05,0x15,0x04,0x15,0x05, +0x15,0x04,0x15,0x05,0x15,0x04,0x15,0x05,0x15,0x04,0x15,0x05,0x15,0x04,0x15,0x05, +0x15,0x04,0x15,0x05,0x15,0x04,0x15,0x05,0x15,0x15,0x15,0x16,0x15,0x15,0x15,0x16, +0x15,0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15,0x04,0x1e,0x04,0x3f,0x04,0x3f,0x04, +0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04, +0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04, +0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15, +0x15,0x15,0x16,0x15,0x15,0x00,0x00,0x00,0x04,0x01,0x05,0x01,0x04,0x01,0x04,0x01, +0x04,0x01,0x05,0x01,0x04,0x01,0x04,0x01,0x04,0x01,0x05,0x01,0x04,0x01,0x04,0x01, +0x04,0x01,0x05,0x01,0x04,0x01,0x04,0x01,0x04,0x01,0x05,0x01,0x04,0x01,0x04,0x01, +0x04,0x01,0x05,0x01,0x04,0x01,0x04,0x01,0x00,0x00,0x00,0x15,0x16,0x15,0x15,0x15, +0x16,0x15,0x15,0x15,0x01,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0e,0x0f,0x0f,0x0f,0x0f, +0x0f,0x0f,0x0f,0x0e,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0e,0x0f,0x0f,0x0f,0x0f, +0x0f,0x0f,0x0f,0x0e,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0e,0x0f,0x0f,0x0f,0x0f, +0x0f,0x0f,0x0f,0x0e,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x04,0x00,0x15,0x15,0x16,0x15, +0x15,0x15,0x16,0x15,0x04,0x0f,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08, +0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08, +0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08, +0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x04,0x00,0x16,0x15,0x15,0x15, +0x16,0x15,0x15,0x15,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x00,0x15,0x15,0x16,0x15, +0x15,0x0b,0x15,0x15,0x02,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x04,0x15,0x16,0x15,0x15, +0x15,0x05,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x04,0x05,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x16,0x3f,0x0e,0x00,0x04,0x05,0x04,0x04,0x04,0x04,0x05,0x03,0x05,0x00,0x0f, +0x3f,0x11,0x00,0x05,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00,0x0e,0x3f,0x12,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x1b,0x3f,0x13,0x00,0x04,0x04,0x05,0x05,0x03,0x04,0x05,0x04,0x05,0x00,0x15, +0x3f,0x13,0x00,0x05,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00,0x12,0x3f,0x14,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x03,0x09,0x04,0x03,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x05,0x05,0x00,0x0d, +0x3f,0x10,0x00,0x02,0x05,0x04,0x04,0x04,0x04,0x04,0x03,0x00,0x12,0x3f,0x13,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x03,0x07,0x05,0x01,0x08,0x0f,0x02,0x00,0x0f,0x12,0x09,0x29,0x01,0x08,0x16, +0x1f,0x19,0x09,0x07,0x02,0x04,0x04,0x04,0x04,0x04,0x04,0x00,0x12,0x3f,0x13,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x1c,0x3f,0x12,0x00,0x1b,0x3f,0x1d,0x1c,0x3f,0x3f,0x3f,0x0b,0x00,0x3f,0x3f, +0x3f,0x3f,0x3f,0x16,0x00,0x04,0x04,0x05,0x04,0x04,0x03,0x00,0x12,0x3f,0x13,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x1b,0x3f,0x10,0x00,0x19,0x3f,0x3f,0x3f,0x16,0x3f,0x3f,0x3f,0x06,0x09,0x1d, +0x3f,0x1b,0x11,0x09,0x01,0x05,0x04,0x04,0x04,0x05,0x03,0x29,0x11,0x3f,0x13,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x19,0x3f,0x0f,0x00,0x18,0x3f,0x1c,0x00,0x00,0xd6,0x3f,0x3f,0x0c,0x00,0x11, +0x3f,0x15,0x00,0x01,0x05,0x02,0x00,0x00,0x00,0x01,0x03,0x00,0x12,0x3f,0x13,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x05,0x01,0x04,0x04,0x04,0x16, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x19,0x3f,0x0f,0x00,0x18,0x3f,0x11,0x00,0x00,0x00,0x1e,0x3f,0x11,0x00,0x12, +0x3f,0x17,0x00,0x03,0x00,0x01,0x0d,0x15,0x10,0x04,0x29,0x00,0x12,0x3f,0x13,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x05,0x04,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x19,0x3f,0x0f,0x00,0x18,0x3f,0x11,0x00,0x03,0x01,0x1a,0x3f,0x10,0x00,0x13, +0x3f,0x18,0x00,0x00,0x08,0x3f,0x3f,0x3f,0x3f,0x3f,0x0a,0x00,0x11,0x3f,0x13,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x04,0x05,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x19,0x3f,0x0f,0x00,0x18,0x3f,0x12,0x00,0x02,0x01,0x1a,0x3f,0x10,0x00,0x13, +0x3f,0x17,0x00,0x03,0x3f,0x3f,0x18,0x08,0x15,0x3f,0x3f,0x04,0x0c,0x3f,0x13,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x04,0x16,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x19,0x3f,0x0f,0x00,0x18,0x3f,0x12,0x00,0x02,0x01,0x1b,0x3f,0x10,0x00,0x13, +0x3f,0x17,0x00,0x11,0x3f,0x1e,0x00,0x00,0x00,0x10,0x3f,0x1d,0x15,0x3f,0x13,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x61,0x3f,0x10,0x00,0x18,0x3f,0x13,0x00,0x02,0x01,0x1b,0x3f,0x11,0x00,0x15, +0x3f,0x3f,0x0f,0x1e,0x3f,0x1c,0xaf,0x11,0x0c,0x15,0x1f,0x3f,0x1f,0x1f,0x13,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x05,0x04,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x1c,0x3f,0x12,0x00,0x1b,0x3f,0x14,0x00,0x02,0x01,0x3f,0x3f,0x11,0x00,0x09, +0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x16,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x01,0x05,0x04,0x04,0x15, +0x16,0x0a,0x16,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x09,0x11,0x08,0x00,0x0a,0x13,0x07,0x02,0x03,0x03,0x0d,0x11,0x04,0x03,0x29, +0x0c,0x13,0x12,0x3f,0x3f,0x14,0x09,0x0e,0x0e,0x0a,0xd5,0x0a,0xaf,0x10,0x09,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x1f,0x09,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x00,0x00,0x02,0x05,0x00,0x00,0x02,0x05,0x04,0x04,0x00,0x00,0x02,0x04,0x04, +0x00,0x00,0x00,0x19,0x3f,0x15,0x00,0x00,0x00,0x00,0x0a,0x07,0x29,0x00,0x00,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x05,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x05,0x04,0x04,0x04, +0x05,0x04,0x00,0xd6,0x3f,0x3f,0x11,0x02,0x09,0x3f,0x3f,0x17,0x00,0x03,0x05,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x05,0x04,0x00,0x0e,0x3f,0x3f,0x3f,0x3f,0x3f,0x61,0x01,0x02,0x05,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x03,0x05,0x03,0x00,0xd6,0x16,0x3f,0x1e,0x09,0x00,0x01,0x05,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x16,0x15,0x15,0x04,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x00,0x15,0x15,0x16,0x15, +0x15,0x15,0x16,0x15,0x01,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x05,0x00,0x15,0x15,0x15,0x16, +0x15,0x15,0x15,0x16,0x04,0x0f,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09, +0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09, +0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09, +0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x04,0x00,0x15,0x15,0x16,0x15, +0x15,0x15,0x16,0x15,0x01,0x0f,0x04,0x04,0x05,0x04,0x04,0x04,0x05,0x04,0x04,0x04, +0x05,0x04,0x04,0x04,0x05,0x04,0x04,0x04,0x05,0x04,0x04,0x04,0x05,0x04,0x04,0x04, +0x05,0x04,0x04,0x04,0x05,0x04,0x04,0x04,0x05,0x04,0x04,0x04,0x05,0x04,0x04,0x04, +0x05,0x04,0x04,0x04,0x05,0x04,0x04,0x04,0x05,0x04,0x04,0x00,0x15,0x16,0x15,0x15, +0x15,0x16,0x15,0x15,0x15,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x15,0x15,0x16,0x15, +0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15,0x15,0x04,0x16,0x04,0x15,0x04,0x16,0x04, +0x15,0x04,0x16,0x04,0x15,0x04,0x16,0x04,0x15,0x04,0x16,0x04,0x15,0x04,0x16,0x04, +0x15,0x04,0x16,0x04,0x15,0x04,0x16,0x04,0x15,0x04,0x16,0x04,0x15,0x04,0x16,0x04, +0x15,0x04,0x16,0x04,0x15,0x04,0x16,0x04,0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15, +0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15,0x15,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04, +0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04, +0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04, +0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15, +0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15,0x0a,0x01,0x0b,0x01,0x0b,0x01,0x0a,0x01, +0x0b,0x01,0x0b,0x01,0x0a,0x01,0x0b,0x01,0x0a,0x01,0x0b,0x01,0x0b,0x01,0x0a,0x01, +0x0b,0x01,0x0b,0x01,0x0a,0x01,0x0b,0x01,0x0a,0x01,0x0b,0x01,0x0b,0x01,0x0a,0x01, +0x0b,0x01,0x0b,0x01,0x0a,0x01,0x0b,0x01,0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15}; + +unsigned char BlankLogo[] = { +0x15,0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x0a,0x04,0x0b,0x04,0x0b,0x04,0x0b,0x04,0x0b,0x04,0x0b,0x04,0x0a,0x05,0x0a,0x05,0x0a,0x04,0x0b,0x04,0x0b,0x04,0x0b,0x04,0x0b,0x04,0x0b,0x04,0x0a,0x05,0x0a,0x05,0x0a,0x04,0x0b,0x04,0x0b,0x04,0x0b,0x04,0x0b,0x04,0x0b,0x04,0x0a,0x05,0x0a,0x05,0x15,0x15,0x15,0x16,0x15,0x15,0x15,0x16, +0x15,0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15,0x04,0x15,0x05,0x15,0x04,0x15,0x05,0x15,0x04,0x15,0x05,0x15,0x04,0x15,0x05,0x15,0x04,0x15,0x05,0x15,0x04,0x15,0x05,0x15,0x04,0x15,0x05,0x15,0x04,0x15,0x05,0x15,0x04,0x15,0x05,0x15,0x04,0x15,0x05,0x15,0x04,0x15,0x05,0x15,0x04,0x15,0x05,0x15,0x15,0x15,0x16,0x15,0x15,0x15,0x16, +0x15,0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15,0x04,0x1e,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15, +0x15,0x15,0x16,0x15,0x15,0x00,0x00,0x00,0x04,0x01,0x05,0x01,0x04,0x01,0x04,0x01,0x04,0x01,0x05,0x01,0x04,0x01,0x04,0x01,0x04,0x01,0x05,0x01,0x04,0x01,0x04,0x01,0x04,0x01,0x05,0x01,0x04,0x01,0x04,0x01,0x04,0x01,0x05,0x01,0x04,0x01,0x04,0x01,0x04,0x01,0x05,0x01,0x04,0x01,0x04,0x01,0x00,0x00,0x00,0x15,0x16,0x15,0x15,0x15, +0x16,0x15,0x15,0x15,0x01,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0e,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0e,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0e,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0e,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0e,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0e,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x04,0x00,0x15,0x15,0x16,0x15, +0x15,0x15,0x16,0x15,0x04,0x0f,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x04,0x00,0x16,0x15,0x15,0x15, +0x16,0x15,0x15,0x15,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x00,0x15,0x15,0x16,0x15, +0x15,0x0b,0x15,0x15,0x02,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x04,0x15,0x16,0x15,0x15, +0x15,0x05,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x04,0x05,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x0b,0x15,0x3f,0x04,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x05,0x15,0x3f,0x0a,0x15, +0x16,0x04,0x04,0x04,0x01,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x01,0x04,0x05,0x04,0x15, +0x15,0x16,0x15,0x15,0x04,0x0f,0x09,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x04,0x00,0x15,0x15,0x16,0x15, +0x15,0x15,0x16,0x15,0x01,0x0f,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x05,0x00,0x15,0x15,0x15,0x16, +0x15,0x15,0x15,0x16,0x04,0x0f,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x08,0x09,0x04,0x00,0x15,0x15,0x16,0x15, +0x15,0x15,0x16,0x15,0x01,0x0f,0x04,0x04,0x05,0x04,0x04,0x04,0x05,0x04,0x04,0x04,0x05,0x04,0x04,0x04,0x05,0x04,0x04,0x04,0x05,0x04,0x04,0x04,0x05,0x04,0x04,0x04,0x05,0x04,0x04,0x04,0x05,0x04,0x04,0x04,0x05,0x04,0x04,0x04,0x05,0x04,0x04,0x04,0x05,0x04,0x04,0x04,0x05,0x04,0x04,0x04,0x05,0x04,0x04,0x00,0x15,0x16,0x15,0x15, +0x15,0x16,0x15,0x15,0x15,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x15,0x15,0x16,0x15, +0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15,0x15,0x04,0x16,0x04,0x15,0x04,0x16,0x04,0x15,0x04,0x16,0x04,0x15,0x04,0x16,0x04,0x15,0x04,0x16,0x04,0x15,0x04,0x16,0x04,0x15,0x04,0x16,0x04,0x15,0x04,0x16,0x04,0x15,0x04,0x16,0x04,0x15,0x04,0x16,0x04,0x15,0x04,0x16,0x04,0x15,0x04,0x16,0x04,0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15, +0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15,0x15,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x3f,0x04,0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15, +0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15,0x0a,0x01,0x0b,0x01,0x0b,0x01,0x0a,0x01,0x0b,0x01,0x0b,0x01,0x0a,0x01,0x0b,0x01,0x0a,0x01,0x0b,0x01,0x0b,0x01,0x0a,0x01,0x0b,0x01,0x0b,0x01,0x0a,0x01,0x0b,0x01,0x0a,0x01,0x0b,0x01,0x0b,0x01,0x0a,0x01,0x0b,0x01,0x0b,0x01,0x0a,0x01,0x0b,0x01,0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15}; +#endif diff --git a/src/apps/pulse/Prefs.cpp b/src/apps/pulse/Prefs.cpp new file mode 100644 index 0000000000..9317cb1370 --- /dev/null +++ b/src/apps/pulse/Prefs.cpp @@ -0,0 +1,235 @@ +//**************************************************************************************** +// +// File: Prefs.cpp +// +// Written by: Daniel Switkin +// +// Copyright 1999, Be Incorporated +// +//**************************************************************************************** + +#include "Prefs.h" +#include "Common.h" +#include "PulseApp.h" +#include +#include +#include +#include +#include +#include + +Prefs::Prefs() { + BPath path; + find_directory(B_USER_SETTINGS_DIRECTORY, &path); + path.Append("Pulse_settings"); + file = new BFile(path.Path(), B_READ_WRITE | B_CREATE_FILE); + + int i = NORMAL_WINDOW_MODE; + if (!GetInt("window_mode", &window_mode, &i)) { + fatalerror = true; + return; + } + + // These three prefs require a connection to the app_server + BRect r = GetNormalWindowRect(); + if (!GetRect("normal_window_rect", &normal_window_rect, &r)) { + fatalerror = true; + return; + } + + r = GetMiniWindowRect(); + if (!GetRect("mini_window_rect", &mini_window_rect, &r)) { + fatalerror = true; + return; + } + + r.Set(100, 100, 415, 329); + if (!GetRect("prefs_window_rect", &prefs_window_rect, &r)) { + fatalerror = true; + return; + } + + i = DEFAULT_NORMAL_BAR_COLOR; + if (!GetInt("normal_bar_color", &normal_bar_color, &i)) { + fatalerror = true; + return; + } + + i = DEFAULT_MINI_ACTIVE_COLOR; + if (!GetInt("mini_active_color", &mini_active_color, &i)) { + fatalerror = true; + return; + } + + i = DEFAULT_MINI_IDLE_COLOR; + if (!GetInt("mini_idle_color", &mini_idle_color, &i)) { + fatalerror = true; + return; + } + + i = DEFAULT_MINI_FRAME_COLOR; + if (!GetInt("mini_frame_color", &mini_frame_color, &i)) { + fatalerror = true; + return; + } + + i = DEFAULT_DESKBAR_ACTIVE_COLOR; + if (!GetInt("deskbar_active_color", &deskbar_active_color, &i)) { + fatalerror = true; + return; + } + + i = DEFAULT_DESKBAR_IDLE_COLOR; + if (!GetInt("deskbar_idle_color", &deskbar_idle_color, &i)) { + fatalerror = true; + return; + } + + i = DEFAULT_DESKBAR_FRAME_COLOR; + if (!GetInt("deskbar_frame_color", &deskbar_frame_color, &i)) { + fatalerror = true; + return; + } + + bool b = DEFAULT_NORMAL_FADE_COLORS; + if (!GetBool("normal_fade_colors", &normal_fade_colors, &b)) { + fatalerror = true; + return; + } + + // Use the default size unless it would prevent having at least + // a one pixel wide display per CPU... this will only happen with > quad + i = DEFAULT_DESKBAR_ICON_WIDTH; + if (i < GetMinimumViewWidth()) i = GetMinimumViewWidth(); + if (!GetInt("deskbar_icon_width", &deskbar_icon_width, &i)) { + fatalerror = true; + return; + } +} + +BRect Prefs::GetNormalWindowRect() { + system_info sys_info; + get_system_info(&sys_info); + + float height = PROGRESS_MTOP + PROGRESS_MBOTTOM + sys_info.cpu_count * ITEM_OFFSET; + if (PULSEVIEW_MIN_HEIGHT > height) { + height = PULSEVIEW_MIN_HEIGHT; + } + + // Dock the window in the lower right hand corner just like the original + BRect r(0, 0, PULSEVIEW_WIDTH, height); + BRect screen_rect = BScreen(B_MAIN_SCREEN_ID).Frame(); + r.OffsetTo(screen_rect.right - r.Width() - 5, screen_rect.bottom - r.Height() - 5); + return r; +} + +BRect Prefs::GetMiniWindowRect() { + // Lower right hand corner by default + BRect screen_rect = BScreen(B_MAIN_SCREEN_ID).Frame(); + screen_rect.left = screen_rect.right - 30; + screen_rect.top = screen_rect.bottom - 150; + screen_rect.OffsetBy(-5, -5); + return screen_rect; +} + +bool Prefs::GetInt(char *name, int *value, int *defaultvalue) { + status_t err = file->ReadAttr(name, B_INT32_TYPE, 0, value, 4); + if (err == B_ENTRY_NOT_FOUND) { + *value = *defaultvalue; + if (file->WriteAttr(name, B_INT32_TYPE, 0, defaultvalue, 4) < 0) { + printf("WriteAttr on %s died\n", name); + fatalerror = true; + return false; + } + } else if (err < 0) { + printf("Unknown error reading %s:\n%s\n", name, strerror(err)); + fatalerror = true; + return false; + } + return true; +} + +bool Prefs::GetBool(char *name, bool *value, bool *defaultvalue) { + status_t err = file->ReadAttr(name, B_BOOL_TYPE, 0, value, 1); + if (err == B_ENTRY_NOT_FOUND) { + *value = *defaultvalue; + if (file->WriteAttr(name, B_BOOL_TYPE, 0, defaultvalue, 1) < 0) { + printf("WriteAttr on %s died\n", name); + fatalerror = true; + return false; + } + } else if (err < 0) { + printf("Unknown error reading %s:\n%s\n", name, strerror(err)); + fatalerror = true; + return false; + } + return true; +} + +bool Prefs::GetRect(char *name, BRect *value, BRect *defaultvalue) { + status_t err = file->ReadAttr(name, B_RECT_TYPE, 0, value, sizeof(BRect)); + if (err == B_ENTRY_NOT_FOUND) { + *value = *defaultvalue; + if (file->WriteAttr(name, B_RECT_TYPE, 0, defaultvalue, sizeof(BRect)) < 0) { + printf("WriteAttr on %s died\n", name); + fatalerror = true; + return false; + } + } else if (err < 0) { + printf("Unknown error reading %s:\n%s\n", name, strerror(err)); + fatalerror = true; + return false; + } + return true; +} + +bool Prefs::PutInt(char *name, int *value){ + status_t err = file->WriteAttr(name, B_INT32_TYPE, 0, value, 4); + if (err < 0) { + printf("Unknown error writing %s:\n%s\n", name, strerror(err)); + fatalerror = true; + return false; + } + return true; +} + +bool Prefs::PutBool(char *name, bool *value) { + status_t err = file->WriteAttr(name, B_BOOL_TYPE, 0, value, 1); + if (err < 0) { + printf("Unknown error writing %s:\n%s\n", name, strerror(err)); + fatalerror = true; + return false; + } + return true; +} + +bool Prefs::PutRect(char *name, BRect *value) { + status_t err = file->WriteAttr(name, B_RECT_TYPE, 0, value, sizeof(BRect)); + if (err < 0) { + printf("Unknown error writing %s:\n%s\n", name, strerror(err)); + fatalerror = true; + return false; + } + return true; +} + +bool Prefs::Save() { + if (!PutInt("window_mode", &window_mode)) return false; + if (!PutRect("normal_window_rect", &normal_window_rect)) return false; + if (!PutRect("mini_window_rect", &mini_window_rect)) return false; + if (!PutRect("prefs_window_rect", &prefs_window_rect)) return false; + if (!PutInt("normal_bar_color", &normal_bar_color)) return false; + if (!PutInt("mini_active_color", &mini_active_color)) return false; + if (!PutInt("mini_idle_color", &mini_idle_color)) return false; + if (!PutInt("mini_frame_color", &mini_frame_color)) return false; + if (!PutInt("deskbar_active_color", &deskbar_active_color)) return false; + if (!PutInt("deskbar_idle_color", &deskbar_idle_color)) return false; + if (!PutInt("deskbar_frame_color", &deskbar_frame_color)) return false; + if (!PutBool("normal_fade_colors", &normal_fade_colors)) return false; + if (!PutInt("deskbar_icon_width", &deskbar_icon_width)) return false; + return true; +} + +Prefs::~Prefs() { + delete file; +} \ No newline at end of file diff --git a/src/apps/pulse/Prefs.h b/src/apps/pulse/Prefs.h new file mode 100644 index 0000000000..1dff0cde34 --- /dev/null +++ b/src/apps/pulse/Prefs.h @@ -0,0 +1,45 @@ +//**************************************************************************************** +// +// File: Prefs.h +// +// Written by: Daniel Switkin +// +// Copyright 1999, Be Incorporated +// +//**************************************************************************************** + +#ifndef PREFS_H +#define PREFS_H + +#include +#include + +class Prefs { + public: + Prefs(); + bool Save(); + ~Prefs(); + + int window_mode, deskbar_icon_width; + BRect normal_window_rect, mini_window_rect, prefs_window_rect; + int normal_bar_color, mini_active_color, mini_idle_color, mini_frame_color, + deskbar_active_color, deskbar_idle_color, deskbar_frame_color; + bool normal_fade_colors; + + bool fatalerror; + + private: + BFile *file; + + bool GetInt(char *name, int *value, int *defaultvalue); + bool GetBool(char *name, bool *value, bool *defaultvalue); + bool GetRect(char *name, BRect *value, BRect *defaultvalue); + bool PutInt(char *name, int *value); + bool PutBool(char *name, bool *value); + bool PutRect(char *name, BRect *value); + + BRect GetNormalWindowRect(); + BRect GetMiniWindowRect(); +}; + +#endif diff --git a/src/apps/pulse/PrefsWindow.cpp b/src/apps/pulse/PrefsWindow.cpp new file mode 100644 index 0000000000..c54e87e28a --- /dev/null +++ b/src/apps/pulse/PrefsWindow.cpp @@ -0,0 +1,98 @@ +//**************************************************************************************** +// +// File: PrefsWindow.cpp +// +// Written by: Daniel Switkin +// +// Copyright 1999, Be Incorporated +// +//**************************************************************************************** + +#include "PrefsWindow.h" +#include "Common.h" +#include "PulseApp.h" +#include "BottomPrefsView.h" +#include "ConfigView.h" +#include +#include +#include +#include +#include + +PrefsWindow::PrefsWindow(BRect rect, const char *name, BMessenger *messenger, Prefs *prefs) : + BWindow(rect, name, B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE | + B_NOT_MINIMIZABLE | B_ASYNCHRONOUS_CONTROLS) { + + this->messenger = messenger; + this->prefs = prefs; + + // This gives a nice look, and sets the background color correctly + BRect bounds = Bounds(); + BBox *parent = new BBox(bounds, "ParentView", B_FOLLOW_NONE, B_PLAIN_BORDER); + AddChild(parent); + + bounds.top += 10; + bounds.bottom -= 45; + BTabView *tabview = new BTabView(bounds, "TabView"); + tabview->SetFont(be_plain_font); + tabview->SetViewColor(parent->ViewColor()); + tabview->ContainerView()->SetViewColor(parent->ViewColor()); + parent->AddChild(tabview); + + BRect viewsize = tabview->ContainerView()->Bounds(); + viewsize.InsetBy(5, 5); + + ConfigView *normal = new ConfigView(viewsize, "Normal Mode", NORMAL_WINDOW_MODE, prefs); + normal->SetViewColor(tabview->ViewColor()); + tabview->AddTab(normal); + + ConfigView *mini = new ConfigView(viewsize, "Mini Mode", MINI_WINDOW_MODE, prefs); + mini->SetViewColor(tabview->ViewColor()); + tabview->AddTab(mini); + + ConfigView *deskbar = new ConfigView(viewsize, "Deskbar Mode", DESKBAR_MODE, prefs); + deskbar->SetViewColor(tabview->ViewColor()); + tabview->AddTab(deskbar); + + tabview->Select(0); + + bounds.top = bounds.bottom + 1; + bounds.bottom += 45; + BottomPrefsView *bottomprefsview = new BottomPrefsView(bounds, "BottomPrefsView"); + parent->AddChild(bottomprefsview); +} + +void PrefsWindow::MessageReceived(BMessage *message) { + switch (message->what) { + case PRV_BOTTOM_OK: { + Hide(); + BTabView *tabview = (BTabView *)FindView("TabView"); + tabview->Select(2); + ConfigView *deskbar = (ConfigView *)FindView("Deskbar Mode"); + deskbar->UpdateDeskbarIconWidth(); + if (Lock()) Quit(); + break; + } + case PRV_BOTTOM_DEFAULTS: { + BTabView *tabview = (BTabView *)FindView("TabView"); + BTab *tab = tabview->TabAt(tabview->Selection()); + BView *view = tab->View(); + view->MessageReceived(message); + break; + } + default: + BWindow::MessageReceived(message); + break; + } +} + +void PrefsWindow::Quit() { + messenger->SendMessage(new BMessage(PRV_QUIT)); + BWindow::Quit(); +} + +PrefsWindow::~PrefsWindow() { + prefs->prefs_window_rect = Frame(); + prefs->Save(); + delete messenger; +} \ No newline at end of file diff --git a/src/apps/pulse/PrefsWindow.h b/src/apps/pulse/PrefsWindow.h new file mode 100644 index 0000000000..ef47db12e3 --- /dev/null +++ b/src/apps/pulse/PrefsWindow.h @@ -0,0 +1,29 @@ +//**************************************************************************************** +// +// File: PrefsWindow.h +// +// Written by: Daniel Switkin +// +// Copyright 1999, Be Incorporated +// +//**************************************************************************************** + +#ifndef PREFSWINDOW_H +#define PREFSWINDOW_H + +#include +#include +#include "Prefs.h" + +class PrefsWindow : public BWindow { + public: + PrefsWindow(BRect rect, const char *name, BMessenger *messenger, Prefs *prefs); + void MessageReceived(BMessage *message); + ~PrefsWindow(); + void Quit(); + + Prefs *prefs; + BMessenger *messenger; +}; + +#endif \ No newline at end of file diff --git a/src/apps/pulse/ProgressBar.cpp b/src/apps/pulse/ProgressBar.cpp new file mode 100644 index 0000000000..ae234f6bab --- /dev/null +++ b/src/apps/pulse/ProgressBar.cpp @@ -0,0 +1,137 @@ +//**************************************************************************************** +// +// File: ProgressBar.cpp +// +// Written by: David Ramsey and Daniel Switkin +// +// Copyright 1999, Be Incorporated +// +//**************************************************************************************** + +#include "ProgressBar.h" +#include "PulseApp.h" + +ProgressBar::ProgressBar(BRect r, char *name) : BView(r, name, B_FOLLOW_NONE, B_WILL_DRAW) { + previous_value = current_value = 0; + + // Create 20 segments + float height = (r.bottom - r.top) - 8; + for (int32 counter = 0; counter < 20; counter++) { + segments[counter].rect.Set(r.left + (counter * 7), r.top, + (r.left + (counter * 7) + 5), r.top + height); + segments[counter].rect.OffsetTo(BPoint((counter * 7) + 4, 4)); + } + SetLowColor(255, 0, 0); + SetViewColor(B_TRANSPARENT_COLOR); +} + +// New - real time updating of bar colors +void ProgressBar::UpdateColors(int32 color, bool fade) { + unsigned char red = (color & 0xff000000) >> 24; + unsigned char green = (color & 0x00ff0000) >> 16; + unsigned char blue = (color & 0x0000ff00) >> 8; + + if (fade) { + unsigned char red_base = red / 3; + unsigned char green_base = green / 3; + unsigned char blue_base = blue / 3; + + for (int x = 0; x < 20; x++) { + segments[x].color.red = (uint8)(red_base + ((red - red_base) * ((float)x / 19.0))); + segments[x].color.green = (uint8)(green_base + ((green - green_base) * ((float)x / 19.0))); + segments[x].color.blue = (uint8)(blue_base + ((blue - blue_base) * ((float)x / 19.0))); + segments[x].color.alpha = 0xff; + } + } else { + for (int x = 0; x < 20; x++) { + segments[x].color.red = red; + segments[x].color.green = green; + segments[x].color.blue = blue; + segments[x].color.alpha = 0xff; + } + } + Render(true); +} + +void ProgressBar::AttachedToWindow() { + Prefs *prefs = ((PulseApp *)be_app)->prefs; + UpdateColors(prefs->normal_bar_color, prefs->normal_fade_colors); +} + +void ProgressBar::Set(int32 value) { + // How many segments to light up + current_value = (int32)(value / 4.9); + if (current_value > 20) current_value = 20; + Render(false); +} + +// Draws the progress bar. If "all" is true the entire bar is redrawn rather +// than just the part that changed. +void ProgressBar::Render(bool all) { + if (all) { + // Black border + BRect bounds = Bounds(); + bounds.InsetBy(2, 2); + SetHighColor(0, 0, 0); + StrokeRect(bounds); + bounds.InsetBy(1, 1); + StrokeRect(bounds); + + // Black dividers + float left = bounds.left; + BPoint start, end; + for (int x = 0; x < 19; x++) { + left += 7; + start.Set(left, bounds.top); + end.Set(left, bounds.bottom); + StrokeLine(start, end); + } + + for (int x = 0; x < current_value; x++) { + SetHighColor(segments[x].color.red, segments[x].color.green, + segments[x].color.blue); + FillRect(segments[x].rect); + } + + SetHighColor(75, 75, 75); + if (current_value < 20) { + for (int x = 19; x >= current_value; x--) { + FillRect(segments[x].rect); + } + } + } else if (current_value > previous_value) { + for (int x = previous_value; x < current_value; x++) { + SetHighColor(segments[x].color.red, segments[x].color.green, + segments[x].color.blue); + FillRect(segments[x].rect); + } + } else if (current_value < previous_value) { + SetHighColor(75, 75, 75); + for (int x = previous_value - 1; x >= current_value; x--) { + FillRect(segments[x].rect); + } + // Special case to make sure the lowest light gets turned off + if (current_value == 0) FillRect(segments[0].rect); + } + + Sync(); + previous_value = current_value; +} + +void ProgressBar::Draw(BRect rect) { + // Add bevels + SetHighColor(dkgray, dkgray, dkgray); + BRect frame = Bounds(); + StrokeLine(BPoint(frame.left, frame.top), BPoint(frame.right, frame.top)); + StrokeLine(BPoint(frame.left, frame.top + 1), BPoint(frame.right, frame.top + 1)); + StrokeLine(BPoint(frame.left, frame.top), BPoint(frame.left, frame.bottom)); + StrokeLine(BPoint(frame.left + 1, frame.top), BPoint(frame.left + 1, frame.bottom)); + + SetHighColor(ltgray, ltgray, ltgray); + StrokeLine(BPoint(frame.right-1, frame.top + 2), BPoint(frame.right - 1, frame.bottom)); + StrokeLine(BPoint(frame.right, frame.top + 1), BPoint(frame.right, frame.bottom)); + StrokeLine(BPoint(frame.left+1, frame.bottom - 1), BPoint(frame.right - 1, frame.bottom - 1)); + StrokeLine(BPoint(frame.left, frame.bottom), BPoint(frame.right, frame.bottom)); + + Render(true); +} diff --git a/src/apps/pulse/ProgressBar.h b/src/apps/pulse/ProgressBar.h new file mode 100644 index 0000000000..24fc511e59 --- /dev/null +++ b/src/apps/pulse/ProgressBar.h @@ -0,0 +1,44 @@ +//**************************************************************************************** +// +// File: ProgressBar.h +// +// Written by: David Ramsey and Daniel Switkin +// +// Copyright 1999, Be Incorporated +// +//**************************************************************************************** + +#ifndef PROGRESSBAR_H +#define PROGRESSBAR_H + +#include + +typedef struct { + rgb_color color; + BRect rect; +} segment; + +#define ltgray 216 +#define dkgray 80 + +class ProgressBar : public BView { + public: + ProgressBar(BRect r, char* name); + void Draw(BRect rect); + void Set(int32 value); + void UpdateColors(int32 color, bool fade); + void AttachedToWindow(); + + enum { + PROGRESS_WIDTH = 146, + PROGRESS_HEIGHT = 20 + }; + + private: + void Render(bool all = false); + + segment segments[20]; + int32 current_value, previous_value; +}; + +#endif diff --git a/src/apps/pulse/Pulse.rsrc b/src/apps/pulse/Pulse.rsrc new file mode 100644 index 0000000000..f6cf9af8f0 Binary files /dev/null and b/src/apps/pulse/Pulse.rsrc differ diff --git a/src/apps/pulse/PulseApp.cpp b/src/apps/pulse/PulseApp.cpp new file mode 100644 index 0000000000..b4aee02f8e --- /dev/null +++ b/src/apps/pulse/PulseApp.cpp @@ -0,0 +1,206 @@ +/* + +"Pulse" Updated by Sikosis (beos@gravity24hr.com) + +(C)2002 OpenBeOS under MIT license + +Copyright 1999, Be Incorporated. All Rights Reserved. +This file may be used under the terms of the Be Sample Code License. + +*/ + +//**************************************************************************************** +// +// File: PulseApp.cpp +// +// Written by: Daniel Switkin +// +// Copyright 1999, Be Incorporated +// +//**************************************************************************************** + +#include "PulseApp.h" +#include "Common.h" +#include "PulseWindow.h" +#include "DeskbarPulseView.h" +#include +#include +#include +#include +#include +#include +#include + +// Make sure we don't disable the last CPU - this is needed by +// descendants of PulseView for the popup menu and for CPUButton +// both as a replicant and not +bool LastEnabledCPU(int my_cpu) { + system_info sys_info; + get_system_info(&sys_info); + if (sys_info.cpu_count == 1) return true; + + for (int x = 0; x < sys_info.cpu_count; x++) { + if (x == my_cpu) continue; + if (_kget_cpu_state_(x) == 1) return false; + } + return true; +} + +// Ensure that the mini mode and deskbar mode always show an indicator +// for each CPU, at least one pixel wide +int GetMinimumViewWidth() { + system_info sys_info; + get_system_info(&sys_info); + return (sys_info.cpu_count * 2) + 1; +} + +void Usage() { + printf("Usage: Pulse [--mini] [-w width] [--width=width]\n" + "\t[--deskbar] [--normal] [--framecolor 0xrrggbb]\n" + "\t[--activecolor 0xrrggbb] [--idlecolor 0xrrggbb]\n"); + exit(0); +} + +bool LoadInDeskbar() { + PulseApp *pulseapp = (PulseApp *)be_app; + BDeskbar *deskbar = new BDeskbar(); + // Don't allow two copies in the Deskbar at once + if (deskbar->HasItem("DeskbarPulseView")) { + delete deskbar; + return false; + } + + // Must be 16 pixels high, the width is retrieved from the Prefs class + int width = pulseapp->prefs->deskbar_icon_width; + int min_width = GetMinimumViewWidth(); + if (width < min_width) { + pulseapp->prefs->deskbar_icon_width = min_width; + width = min_width; + } + + BRect rect(0, 0, width - 1, 15); + DeskbarPulseView *replicant = new DeskbarPulseView(rect); + status_t err = deskbar->AddItem(replicant); + delete replicant; + delete deskbar; + if (err != B_OK) { + BAlert *alert = new BAlert(NULL, strerror(err), "OK"); + alert->Go(NULL); + return false; + } else return true; +} + +PulseApp::PulseApp(int argc, char **argv) : BApplication(APP_SIGNATURE) { + prefs = new Prefs(); + + int mini = false, deskbar = false, normal = false; + uint32 framecolor = 0, activecolor = 0, idlecolor = 0; + + while (1) { + int option_index = 0; + static struct option long_options[] = { + {"deskbar", 0, &deskbar, true}, + {"width", 1, 0, 'w'}, + {"framecolor", 1, 0, 0}, + {"activecolor", 1, 0, 0}, + {"idlecolor", 1, 0, 0}, + {"mini", 0, &mini, true}, + {"normal", 0, &normal, true}, + {"help", 0, 0, 'h'}, + {0,0,0,0} + }; + int c = getopt_long (argc, argv, "hw:", long_options, &option_index); + if (c == -1) break; + + switch (c) { + case 0: + switch(option_index) { + case 2: /* framecolor */ + case 3: /* activecolor */ + case 4: /* idlecolor */ + uint32 rgb = strtoul(optarg, NULL, 0); + rgb = rgb << 8; + rgb |= 0x000000ff; + + switch (option_index) { + case 2: + framecolor = rgb; + break; + case 3: + activecolor = rgb; + break; + case 4: + idlecolor = rgb; + break; + } + break; + } + break; + case 'w': + prefs->deskbar_icon_width = atoi(optarg); + if (prefs->deskbar_icon_width < GetMinimumViewWidth()) + prefs->deskbar_icon_width = GetMinimumViewWidth(); + else if (prefs->deskbar_icon_width > 50) prefs->deskbar_icon_width = 50; + break; + case 'h': + case '?': + Usage(); + break; + default: + printf ("?? getopt returned character code 0%o ??\n", c); + break; + } + } + + if (deskbar) { + prefs->window_mode = DESKBAR_MODE; + if (activecolor != 0) prefs->deskbar_active_color = activecolor; + if (idlecolor != 0) prefs->deskbar_idle_color = idlecolor; + if (framecolor != 0) prefs->deskbar_frame_color = framecolor; + } else if (mini) { + prefs->window_mode = MINI_WINDOW_MODE; + if (activecolor != 0) prefs->mini_active_color = activecolor; + if (idlecolor != 0) prefs->mini_idle_color = idlecolor; + if (framecolor != 0) prefs->mini_frame_color = framecolor; + } else if (normal) prefs->window_mode = NORMAL_WINDOW_MODE; + + prefs->Save(); + BuildPulse(); +} + +void PulseApp::BuildPulse() { + PulseWindow *pulsewindow = NULL; + if (prefs->window_mode == NORMAL_WINDOW_MODE) { + pulsewindow = new PulseWindow(prefs->normal_window_rect); + } else if (prefs->window_mode == MINI_WINDOW_MODE) { + pulsewindow = new PulseWindow(prefs->mini_window_rect); + // Remove this case for Deskbar add on API + } else if (prefs->window_mode == DESKBAR_MODE) { + if (LoadInDeskbar()) { + PostMessage(new BMessage(B_QUIT_REQUESTED)); + return; + } else { + // If loading the replicant fails, launch the app instead + // This allows having the replicant and the app open simultaneously + prefs->window_mode = NORMAL_WINDOW_MODE; + pulsewindow = new PulseWindow(prefs->normal_window_rect); + } + } + + pulsewindow->Show(); +} + +PulseApp::~PulseApp() { + // Load the replicant after we save our preferences so they don't + // get overwritten by DeskbarPulseView's instance + prefs->Save(); + if (prefs->window_mode == DESKBAR_MODE) LoadInDeskbar(); + delete prefs; +} + +int main(int argc, char **argv) { + PulseApp *pulseapp = new PulseApp(argc, argv); + pulseapp->Run(); + delete pulseapp; + return 0; +} \ No newline at end of file diff --git a/src/apps/pulse/PulseApp.h b/src/apps/pulse/PulseApp.h new file mode 100644 index 0000000000..fc19930b71 --- /dev/null +++ b/src/apps/pulse/PulseApp.h @@ -0,0 +1,33 @@ +//**************************************************************************************** +// +// File: PulseApp.h +// +// Written by: Daniel Switkin +// +// Copyright 1999, Be Incorporated +// +//**************************************************************************************** + +#ifndef PULSEAPP_H +#define PULSEAPP_H + +#include +#include "Prefs.h" + +bool LastEnabledCPU(int my_cpu); +int GetMinimumViewWidth(); +bool LoadInDeskbar(); +void Usage(); + +class PulseApp : public BApplication { + public: + PulseApp(int argc, char **argv); + ~PulseApp(); + + Prefs *prefs; + + private: + void BuildPulse(); +}; + +#endif diff --git a/src/apps/pulse/PulseView.cpp b/src/apps/pulse/PulseView.cpp new file mode 100644 index 0000000000..9b0f5cd2c3 --- /dev/null +++ b/src/apps/pulse/PulseView.cpp @@ -0,0 +1,126 @@ +//**************************************************************************************** +// +// File: PulseView.cpp +// +// Written by: David Ramsey and Daniel Switkin +// +// Copyright 1999, Be Incorporated +// +//**************************************************************************************** + +#include "PulseView.h" +#include "Common.h" +#include "PulseApp.h" +#include +#include +#include +#include + +PulseView::PulseView(BRect rect, const char *name) : + BView(rect, name, B_FOLLOW_ALL_SIDES, B_WILL_DRAW | B_PULSE_NEEDED | B_FRAME_EVENTS) { + + popupmenu = NULL; + cpu_menu_items = NULL; + + // Don't init the menus for the DeskbarPulseView, because this instance + // will only be used to archive the replicant + if (strcmp(name, "DeskbarPulseView") != 0) { + Init(); + } +} + +// This version will be used by the instantiated replicant +PulseView::PulseView(BMessage *message) : BView(message) { + SetResizingMode(B_FOLLOW_ALL_SIDES); + SetFlags(B_WILL_DRAW | B_PULSE_NEEDED); + + popupmenu = NULL; + cpu_menu_items = NULL; + Init(); +} + +void PulseView::Init() { + popupmenu = new BPopUpMenu("PopUpMenu", false, false, B_ITEMS_IN_COLUMN); + popupmenu->SetFont(be_plain_font); + mode1 = new BMenuItem("", NULL, 0, 0); + mode2 = new BMenuItem("", NULL, 0, 0); + preferences = new BMenuItem("Preferences...", new BMessage(PV_PREFERENCES), 0, 0); + about = new BMenuItem("About...", new BMessage(PV_ABOUT), 0, 0); + + popupmenu->AddItem(mode1); + popupmenu->AddItem(mode2); + popupmenu->AddSeparatorItem(); + + system_info sys_info; + get_system_info(&sys_info); + + // Only add menu items to control CPUs on an SMP machine + if (sys_info.cpu_count >= 2) { + cpu_menu_items = new BMenuItem *[sys_info.cpu_count]; + char temp[20]; + for (int x = 0; x < sys_info.cpu_count; x++) { + sprintf(temp, "CPU %d", x + 1); + BMessage *message = new BMessage(PV_CPU_MENU_ITEM); + message->AddInt32("which", x); + cpu_menu_items[x] = new BMenuItem(temp, message, 0, 0); + popupmenu->AddItem(cpu_menu_items[x]); + } + popupmenu->AddSeparatorItem(); + } + + popupmenu->AddItem(preferences); + popupmenu->AddItem(about); +} + +void PulseView::MouseDown(BPoint point) { + BPoint cursor; + uint32 buttons; + MakeFocus(true); + GetMouse(&cursor, &buttons, true); + + if (buttons & B_SECONDARY_MOUSE_BUTTON) { + ConvertToScreen(&point); + // Use the asynchronous version so we don't interfere with + // the window responding to Pulse() events + popupmenu->Go(point, true, false, true); + } +} + +void PulseView::Update() { + system_info sys_info; + get_system_info(&sys_info); + bigtime_t now = system_time(); + + // Calculate work done since last call to Update() for each CPU + for (int x = 0; x < sys_info.cpu_count; x++) { + double cpu_time = (double)(sys_info.cpu_infos[x].active_time - prev_active[x]) / (now - prev_time); + prev_active[x] = sys_info.cpu_infos[x].active_time; + if (cpu_time < 0) cpu_time = 0; + if (cpu_time > 1) cpu_time = 1; + cpu_times[x] = cpu_time; + + if (sys_info.cpu_count >= 2) { + if (!_kget_cpu_state_(x) && cpu_menu_items[x]->IsMarked()) + cpu_menu_items[x]->SetMarked(false); + if (_kget_cpu_state_(x) && !cpu_menu_items[x]->IsMarked()) + cpu_menu_items[x]->SetMarked(true); + } + } + prev_time = now; +} + +void PulseView::ChangeCPUState(BMessage *message) { + int which = message->FindInt32("which"); + + if (!LastEnabledCPU(which)) { + _kset_cpu_state_(which, (int)!cpu_menu_items[which]->IsMarked()); + } else { + BAlert *alert = new BAlert(NULL, "You can't disable the last active CPU.", "OK"); + alert->Go(NULL); + } +} + +PulseView::~PulseView() { + if (popupmenu != NULL) delete popupmenu; + if (cpu_menu_items != NULL) delete cpu_menu_items; +} \ No newline at end of file diff --git a/src/apps/pulse/PulseView.h b/src/apps/pulse/PulseView.h new file mode 100644 index 0000000000..992b12737e --- /dev/null +++ b/src/apps/pulse/PulseView.h @@ -0,0 +1,42 @@ +//**************************************************************************************** +// +// File: PulseView.h +// +// Written by: David Ramsey and Daniel Switkin +// +// Copyright 1999, Be Incorporated +// +//**************************************************************************************** + +#ifndef PULSEVIEW_H +#define PULSEVIEW_H + +#include +#include +#include + +extern "C" int _kget_cpu_state_(int cpu); +extern "C" int _kset_cpu_state_(int cpu, int enabled); + +class PulseView : public BView { + public: + PulseView(BRect rect, const char *name); + PulseView(BMessage *message); + ~PulseView(); + virtual void MouseDown(BPoint point); + void ChangeCPUState(BMessage *message); + + protected: + void Init(); + void Update(); + + BPopUpMenu *popupmenu; + BMenuItem *mode1, *mode2, *preferences, *about; + BMenuItem **cpu_menu_items; + + double cpu_times[B_MAX_CPU_COUNT]; + bigtime_t prev_active[B_MAX_CPU_COUNT]; + bigtime_t prev_time; +}; + +#endif \ No newline at end of file diff --git a/src/apps/pulse/PulseWindow.cpp b/src/apps/pulse/PulseWindow.cpp new file mode 100644 index 0000000000..6279d8000d --- /dev/null +++ b/src/apps/pulse/PulseWindow.cpp @@ -0,0 +1,152 @@ +//**************************************************************************************** +// +// File: PulseWindow.cpp +// +// Written by: Daniel Switkin +// +// Copyright 1999, Be Incorporated +// +//**************************************************************************************** + +#include "PulseWindow.h" +#include "PulseApp.h" +#include "Common.h" +#include "DeskbarPulseView.h" +#include +#include +#include +#include + +PulseWindow::PulseWindow(BRect rect) : + BWindow(rect, "Pulse", B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE) { + + SetPulseRate(200000); + + PulseApp *pulseapp = (PulseApp *)be_app; + BRect bounds = Bounds(); + normalpulseview = new NormalPulseView(bounds); + AddChild(normalpulseview); + + minipulseview = new MiniPulseView(bounds, "MiniPulseView", pulseapp->prefs); + AddChild(minipulseview); + + mode = pulseapp->prefs->window_mode; + if (mode == MINI_WINDOW_MODE) { + SetLook(B_MODAL_WINDOW_LOOK); + SetFeel(B_NORMAL_WINDOW_FEEL); + SetFlags(B_NOT_ZOOMABLE); + normalpulseview->Hide(); + SetSizeLimits(GetMinimumViewWidth() - 1, 4096, 2, 4096); + ResizeTo(rect.Width(), rect.Height()); + } else minipulseview->Hide(); + + prefswindow = NULL; +} + +void PulseWindow::MessageReceived(BMessage *message) { + switch(message->what) { + case PV_NORMAL_MODE: + case PV_MINI_MODE: + case PV_DESKBAR_MODE: + SetMode(message->what); + break; + case PRV_NORMAL_FADE_COLORS: + case PRV_NORMAL_CHANGE_COLOR: + normalpulseview->UpdateColors(message); + break; + case PRV_MINI_CHANGE_COLOR: + minipulseview->UpdateColors(message); + break; + case PRV_QUIT: + prefswindow = NULL; + break; + case PV_PREFERENCES: { + // If the window is already open, bring it to the front + if (prefswindow != NULL) { + prefswindow->Activate(true); + break; + } + // Otherwise launch a new preferences window + PulseApp *pulseapp = (PulseApp *)be_app; + prefswindow = new PrefsWindow(pulseapp->prefs->prefs_window_rect, + "Pulse Preferences", new BMessenger(this), pulseapp->prefs); + prefswindow->Show(); + break; + } + case PV_ABOUT: { + BAlert *alert = new BAlert("Info", "Pulse\n\nBy David Ramsey and Arve HjønnevÃ¥g\nRevised by Daniel Switkin", "OK"); + // Use the asynchronous version so we don't block the window's thread + alert->Go(NULL); + break; + } + case PV_QUIT: + PostMessage(B_QUIT_REQUESTED); + break; + case PV_CPU_MENU_ITEM: + // Call the correct version based on whose menu sent the message + if (minipulseview->IsHidden()) normalpulseview->ChangeCPUState(message); + else minipulseview->ChangeCPUState(message); + break; + default: + BWindow::MessageReceived(message); + break; + } +} + +void PulseWindow::SetMode(int newmode) { + PulseApp *pulseapp = (PulseApp *)be_app; + switch (newmode) { + case PV_NORMAL_MODE: + if (mode == MINI_WINDOW_MODE) { + pulseapp->prefs->mini_window_rect = Frame(); + pulseapp->prefs->window_mode = NORMAL_WINDOW_MODE; + pulseapp->prefs->Save(); + } + minipulseview->Hide(); + normalpulseview->Show(); + mode = NORMAL_WINDOW_MODE; + SetType(B_TITLED_WINDOW); + SetFlags(B_NOT_RESIZABLE | B_NOT_ZOOMABLE); + ResizeTo(pulseapp->prefs->normal_window_rect.IntegerWidth(), + pulseapp->prefs->normal_window_rect.IntegerHeight()); + MoveTo(pulseapp->prefs->normal_window_rect.left, + pulseapp->prefs->normal_window_rect.top); + break; + case PV_MINI_MODE: + if (mode == NORMAL_WINDOW_MODE) { + pulseapp->prefs->normal_window_rect = Frame(); + pulseapp->prefs->window_mode = MINI_WINDOW_MODE; + pulseapp->prefs->Save(); + } + normalpulseview->Hide(); + minipulseview->Show(); + mode = MINI_WINDOW_MODE; + SetLook(B_MODAL_WINDOW_LOOK); + SetFeel(B_NORMAL_WINDOW_FEEL); + SetFlags(B_NOT_ZOOMABLE); + SetSizeLimits(GetMinimumViewWidth() - 1, 4096, 2, 4096); + ResizeTo(pulseapp->prefs->mini_window_rect.IntegerWidth(), + pulseapp->prefs->mini_window_rect.IntegerHeight()); + MoveTo(pulseapp->prefs->mini_window_rect.left, + pulseapp->prefs->mini_window_rect.top); + break; + case PV_DESKBAR_MODE: + // Do not set window's mode to DESKBAR_MODE because the + // destructor needs to save the correct BRect. ~PulseApp() + // will handle launching the replicant after our prefs are saved. + pulseapp->prefs->window_mode = DESKBAR_MODE; + PostMessage(B_QUIT_REQUESTED); + break; + } +} + +PulseWindow::~PulseWindow() { + PulseApp *pulseapp = (PulseApp *)be_app; + if (mode == NORMAL_WINDOW_MODE) pulseapp->prefs->normal_window_rect = Frame(); + else if (mode == MINI_WINDOW_MODE) pulseapp->prefs->mini_window_rect = Frame(); +} + +bool PulseWindow::QuitRequested() { + be_app->PostMessage(B_QUIT_REQUESTED); + return true; +} \ No newline at end of file diff --git a/src/apps/pulse/PulseWindow.h b/src/apps/pulse/PulseWindow.h new file mode 100644 index 0000000000..384bf5b736 --- /dev/null +++ b/src/apps/pulse/PulseWindow.h @@ -0,0 +1,34 @@ +//**************************************************************************************** +// +// File: PulseWindow.h +// +// Written by: Daniel Switkin +// +// Copyright 1999, Be Incorporated +// +//**************************************************************************************** + +#ifndef PULSEWINDOW_H +#define PULSEWINDOW_H + +#include +#include "NormalPulseView.h" +#include "MiniPulseView.h" +#include "PrefsWindow.h" + +class PulseWindow : public BWindow { + public: + PulseWindow(BRect rect); + ~PulseWindow(); + bool QuitRequested(); + void MessageReceived(BMessage *message); + void SetMode(int newmode); + + private: + NormalPulseView *normalpulseview; + MiniPulseView *minipulseview; + PrefsWindow *prefswindow; + int mode; +}; + +#endif diff --git a/src/kernel/Jamfile b/src/kernel/Jamfile new file mode 100644 index 0000000000..cbb114e1aa --- /dev/null +++ b/src/kernel/Jamfile @@ -0,0 +1,867 @@ +SubDir OBOS_TOP sources os kits kernel ; + +KernelStaticLibraryObjects libkern.a : + <$(SOURCE_GRIST)!libc!locale>ctype.o + + <$(SOURCE_GRIST)!libc!stdio>kvsprintf.o + + <$(SOURCE_GRIST)!libc!stdlib>assert.o + <$(SOURCE_GRIST)!libc!stdlib>atoi.o + <$(SOURCE_GRIST)!libc!stdlib>bsearch.o + <$(SOURCE_GRIST)!libc!stdlib>heapsort.o + <$(SOURCE_GRIST)!libc!stdlib>merge.o + <$(SOURCE_GRIST)!libc!stdlib>multibyte.o + <$(SOURCE_GRIST)!libc!stdlib>qsort.o + <$(SOURCE_GRIST)!libc!stdlib>rand.o + <$(SOURCE_GRIST)!libc!stdlib>random.o + + <$(SOURCE_GRIST)!libc!string>bcopy.o + <$(SOURCE_GRIST)!libc!string>bzero.o + <$(SOURCE_GRIST)!libc!string>memchr.o + <$(SOURCE_GRIST)!libc!string>memcmp.o + <$(SOURCE_GRIST)!libc!string>memcpy.o + <$(SOURCE_GRIST)!libc!string>memmove.o + <$(SOURCE_GRIST)!libc!string>memset.o + <$(SOURCE_GRIST)!libc!string>strcat.o + <$(SOURCE_GRIST)!libc!string>strchr.o + <$(SOURCE_GRIST)!libc!string>strcmp.o + <$(SOURCE_GRIST)!libc!string>strcpy.o + <$(SOURCE_GRIST)!libc!string>strerror.o + <$(SOURCE_GRIST)!libc!string>strlcat.o + <$(SOURCE_GRIST)!libc!string>strlcpy.o + <$(SOURCE_GRIST)!libc!string>strlen.o + <$(SOURCE_GRIST)!libc!string>strncat.o + <$(SOURCE_GRIST)!libc!string>strncmp.o + <$(SOURCE_GRIST)!libc!string>strncpy.o + <$(SOURCE_GRIST)!libc!string>strnicmp.o + <$(SOURCE_GRIST)!libc!string>strnlen.o + <$(SOURCE_GRIST)!libc!string>strpbrk.o + <$(SOURCE_GRIST)!libc!string>strrchr.o + <$(SOURCE_GRIST)!libc!string>strspn.o + <$(SOURCE_GRIST)!libc!string>strstr.o + <$(SOURCE_GRIST)!libc!string>strtok.o + + <$(SOURCE_GRIST)!libc!system>rlimit.o + <$(SOURCE_GRIST)!libc!system!arch!$(OBOS_ARCH)>atomic.o + ; + +KernelStaticLibraryObjects libm.a : + <$(SOURCE_GRIST)!libm!arch!$(OBOS_ARCH)>fabs.o + <$(SOURCE_GRIST)!libm!arch!$(OBOS_ARCH)>frexp.o + <$(SOURCE_GRIST)!libm!arch!$(OBOS_ARCH)>isinf.o + <$(SOURCE_GRIST)!libm!arch!$(OBOS_ARCH)>ldexp.o + + <$(SOURCE_GRIST)!libm!common>atan2.o + <$(SOURCE_GRIST)!libm!common>sincos.o + <$(SOURCE_GRIST)!libm!common>tan.o + + <$(SOURCE_GRIST)!libm!common_source>acosh.o + <$(SOURCE_GRIST)!libm!common_source>asincos.o + <$(SOURCE_GRIST)!libm!common_source>asinh.o + <$(SOURCE_GRIST)!libm!common_source>atan.o + <$(SOURCE_GRIST)!libm!common_source>atanh.o + <$(SOURCE_GRIST)!libm!common_source>cosh.o + <$(SOURCE_GRIST)!libm!common_source>erf.o + <$(SOURCE_GRIST)!libm!common_source>exp.o + <$(SOURCE_GRIST)!libm!common_source>exp__E.o + <$(SOURCE_GRIST)!libm!common_source>expm1.o + <$(SOURCE_GRIST)!libm!common_source>floor.o + <$(SOURCE_GRIST)!libm!common_source>fmod.o + <$(SOURCE_GRIST)!libm!common_source>gamma.o + <$(SOURCE_GRIST)!libm!common_source>j0.o + <$(SOURCE_GRIST)!libm!common_source>j1.o + <$(SOURCE_GRIST)!libm!common_source>jn.o + <$(SOURCE_GRIST)!libm!common_source>lgamma.o + <$(SOURCE_GRIST)!libm!common_source>log.o + <$(SOURCE_GRIST)!libm!common_source>log10.o + <$(SOURCE_GRIST)!libm!common_source>log1p.o + <$(SOURCE_GRIST)!libm!common_source>log__L.o + <$(SOURCE_GRIST)!libm!common_source>pow.o + <$(SOURCE_GRIST)!libm!common_source>sinh.o + <$(SOURCE_GRIST)!libm!common_source>tanh.o + + <$(SOURCE_GRIST)!libm!ieee>cabs.o + <$(SOURCE_GRIST)!libm!ieee>cbrt.o + <$(SOURCE_GRIST)!libm!ieee>support.o + ; + +KernelLd stage2 + : + <$(SOURCE_GRIST)!boot!arch!$(OBOS_ARCH)>stage2.o + <$(SOURCE_GRIST)!boot!arch!$(OBOS_ARCH)>stage2_asm.o + <$(SOURCE_GRIST)!boot!arch!$(OBOS_ARCH)>smp_boot.o + <$(SOURCE_GRIST)!boot!arch!$(OBOS_ARCH)>smp_trampoline.o + libkern.a + : + $(SUBDIR)/boot/arch/$(OBOS_ARCH)/stage2.ld + : + -dN + : + : + bootstrap + ; + +KernelLd kernel + : + <$(SOURCE_GRIST)!core>cbuf.o + <$(SOURCE_GRIST)!core>console.o + <$(SOURCE_GRIST)!core>cpu.o + <$(SOURCE_GRIST)!core>debug.o + <$(SOURCE_GRIST)!core>elf.o + <$(SOURCE_GRIST)!core>faults.o + <$(SOURCE_GRIST)!core>fd.o + <$(SOURCE_GRIST)!core>gdb.o + <$(SOURCE_GRIST)!core>heap.o + <$(SOURCE_GRIST)!core>int.o + <$(SOURCE_GRIST)!core>khash.o + <$(SOURCE_GRIST)!core>lock.o + <$(SOURCE_GRIST)!core>main.o + <$(SOURCE_GRIST)!core>misc.o + <$(SOURCE_GRIST)!core>module.o + <$(SOURCE_GRIST)!core>port.o + <$(SOURCE_GRIST)!core>queue.o + <$(SOURCE_GRIST)!core>sem.o + <$(SOURCE_GRIST)!core>smp.o + <$(SOURCE_GRIST)!core>syscalls.o + <$(SOURCE_GRIST)!core>sysctl.o + <$(SOURCE_GRIST)!core>thread.o + <$(SOURCE_GRIST)!core>timer.o + + <$(SOURCE_GRIST)!core!net>pools.o + <$(SOURCE_GRIST)!core!net>nhash.o + <$(SOURCE_GRIST)!core!net>mbuf.o + <$(SOURCE_GRIST)!core!net>net.o + <$(SOURCE_GRIST)!core!net>socket.o + + linkhack.so + + libbus.a + libfs.a + libvm.a + lib$(OBOS_ARCH).a + libdrivers.a + libkern.a + : + $(SUBDIR)/core/arch/$(OBOS_ARCH)/kernel.ld + : + -Bdynamic -export-dynamic -dynamic-linker /foo/bar + : + : + kernel + ; + +KernelLd kernel.so + : + <$(SOURCE_GRIST)!core>cbuf.o + <$(SOURCE_GRIST)!core>console.o + <$(SOURCE_GRIST)!core>cpu.o + <$(SOURCE_GRIST)!core>debug.o + <$(SOURCE_GRIST)!core>elf.o + <$(SOURCE_GRIST)!core>faults.o + <$(SOURCE_GRIST)!core>fd.o + <$(SOURCE_GRIST)!core>gdb.o + <$(SOURCE_GRIST)!core>heap.o + <$(SOURCE_GRIST)!core>int.o + <$(SOURCE_GRIST)!core>khash.o + <$(SOURCE_GRIST)!core>lock.o + <$(SOURCE_GRIST)!core>main.o + <$(SOURCE_GRIST)!core>misc.o + <$(SOURCE_GRIST)!core>module.o + <$(SOURCE_GRIST)!core>port.o + <$(SOURCE_GRIST)!core>queue.o + <$(SOURCE_GRIST)!core>sem.o + <$(SOURCE_GRIST)!core>smp.o + <$(SOURCE_GRIST)!core>syscalls.o + <$(SOURCE_GRIST)!core>sysctl.o + <$(SOURCE_GRIST)!core>thread.o + <$(SOURCE_GRIST)!core>timer.o + + <$(SOURCE_GRIST)!core!net>pools.o + <$(SOURCE_GRIST)!core!net>nhash.o + <$(SOURCE_GRIST)!core!net>mbuf.o + <$(SOURCE_GRIST)!core!net>net.o + <$(SOURCE_GRIST)!core!net>socket.o + + linkhack.so + + libbus.a + libfs.a + libvm.a + lib$(OBOS_ARCH).a + libdrivers.a + libkern.a + : + $(SUBDIR)/core/arch/$(OBOS_ARCH)/kernel.ld + : + -Bdynamic -shared -export-dynamic -dynamic-linker /foo/bar + ; + +KernelLd iso9660 + : + <$(SOURCE_GRIST)!core!addons!fs!iso9660>isofs.o + kernel.so + : + $(SUBDIR)/core/addons/ldscripts/$(OBOS_ARCH)/addon.ld + : + -Bdynamic -shared + : + : + addons/fs/iso9660 + ; + +KernelLd isa + : + <$(SOURCE_GRIST)!core!addons!bus_managers!isa>isa.o + kernel.so + : + $(SUBDIR)/core/addons/ldscripts/$(OBOS_ARCH)/addon.ld + : + -Bdynamic -shared + : + : + addons/bus_managers/isa user-addons/bus_managers/isa + ; + +KernelLd libglue.o : + <$(SOURCE_GRIST)!glue>lib0.o + : + : + -r + : + no_gcc + ; + +KernelLd libm.so + : + libglue.o + <$(SOURCE_GRIST)!libm!arch!$(OBOS_ARCH)>fabs.o + <$(SOURCE_GRIST)!libm!arch!$(OBOS_ARCH)>frexp.o + <$(SOURCE_GRIST)!libm!arch!$(OBOS_ARCH)>isinf.o + <$(SOURCE_GRIST)!libm!arch!$(OBOS_ARCH)>ldexp.o + + <$(SOURCE_GRIST)!libm!common>atan2.o + <$(SOURCE_GRIST)!libm!common>sincos.o + <$(SOURCE_GRIST)!libm!common>tan.o + + <$(SOURCE_GRIST)!libm!common_source>acosh.o + <$(SOURCE_GRIST)!libm!common_source>asincos.o + <$(SOURCE_GRIST)!libm!common_source>asinh.o + <$(SOURCE_GRIST)!libm!common_source>atan.o + <$(SOURCE_GRIST)!libm!common_source>atanh.o + <$(SOURCE_GRIST)!libm!common_source>cosh.o + <$(SOURCE_GRIST)!libm!common_source>erf.o + <$(SOURCE_GRIST)!libm!common_source>exp.o + <$(SOURCE_GRIST)!libm!common_source>exp__E.o + <$(SOURCE_GRIST)!libm!common_source>expm1.o + <$(SOURCE_GRIST)!libm!common_source>floor.o + <$(SOURCE_GRIST)!libm!common_source>fmod.o + <$(SOURCE_GRIST)!libm!common_source>gamma.o + <$(SOURCE_GRIST)!libm!common_source>j0.o + <$(SOURCE_GRIST)!libm!common_source>j1.o + <$(SOURCE_GRIST)!libm!common_source>jn.o + <$(SOURCE_GRIST)!libm!common_source>lgamma.o + <$(SOURCE_GRIST)!libm!common_source>log.o + <$(SOURCE_GRIST)!libm!common_source>log10.o + <$(SOURCE_GRIST)!libm!common_source>log1p.o + <$(SOURCE_GRIST)!libm!common_source>log__L.o + <$(SOURCE_GRIST)!libm!common_source>pow.o + <$(SOURCE_GRIST)!libm!common_source>sinh.o + <$(SOURCE_GRIST)!libm!common_source>tanh.o + + <$(SOURCE_GRIST)!libm!ieee>cabs.o + <$(SOURCE_GRIST)!libm!ieee>cbrt.o + <$(SOURCE_GRIST)!libm!ieee>support.o + : + $(SUBDIR)/ldscripts/$(OBOS_ARCH)/library.ld + : + -shared -soname libm.so + : + no_gcc + : + lib/libm.so + ; + +KernelStaticLibraryObjects libc.a : + <$(SOURCE_GRIST)!libc>nulibc_init.o + <$(SOURCE_GRIST)!libc>errno.o + + <$(SOURCE_GRIST)!libc!hoard>arch-specific.o + <$(SOURCE_GRIST)!libc!hoard>heap.o + <$(SOURCE_GRIST)!libc!hoard>processheap.o + <$(SOURCE_GRIST)!libc!hoard>superblock.o + <$(SOURCE_GRIST)!libc!hoard>threadheap.o + <$(SOURCE_GRIST)!libc!hoard>wrapper.o + + <$(SOURCE_GRIST)!libc!locale>ctype.o + + <$(SOURCE_GRIST)!libc!stdio>fclose.o + <$(SOURCE_GRIST)!libc!stdio>feof.o + <$(SOURCE_GRIST)!libc!stdio>fflush.o + <$(SOURCE_GRIST)!libc!stdio>fgetc.o + <$(SOURCE_GRIST)!libc!stdio>fgetln.o + <$(SOURCE_GRIST)!libc!stdio>fgets.o + <$(SOURCE_GRIST)!libc!stdio>findfp.o + <$(SOURCE_GRIST)!libc!stdio>flags.o + <$(SOURCE_GRIST)!libc!stdio>flockfile.o + <$(SOURCE_GRIST)!libc!stdio>fopen.o + <$(SOURCE_GRIST)!libc!stdio>fprintf.o + <$(SOURCE_GRIST)!libc!stdio>fputc.o + <$(SOURCE_GRIST)!libc!stdio>fputs.o + <$(SOURCE_GRIST)!libc!stdio>fread.o + <$(SOURCE_GRIST)!libc!stdio>fwrite.o + <$(SOURCE_GRIST)!libc!stdio>fvwrite.o + <$(SOURCE_GRIST)!libc!stdio>fwalk.o + <$(SOURCE_GRIST)!libc!stdio>getc.o + <$(SOURCE_GRIST)!libc!stdio>getchar.o + <$(SOURCE_GRIST)!libc!stdio>gets.o + <$(SOURCE_GRIST)!libc!stdio>getw.o + <$(SOURCE_GRIST)!libc!stdio>makebuf.o + <$(SOURCE_GRIST)!libc!stdio>printf.o + <$(SOURCE_GRIST)!libc!stdio>putc.o + <$(SOURCE_GRIST)!libc!stdio>putchar.o + <$(SOURCE_GRIST)!libc!stdio>puts.o + <$(SOURCE_GRIST)!libc!stdio>putw.o + <$(SOURCE_GRIST)!libc!stdio>refill.o + <$(SOURCE_GRIST)!libc!stdio>rget.o + <$(SOURCE_GRIST)!libc!stdio>sscanf.o + <$(SOURCE_GRIST)!libc!stdio>sprintf.o + <$(SOURCE_GRIST)!libc!stdio>stdio.o + <$(SOURCE_GRIST)!libc!stdio>ungetc.o + <$(SOURCE_GRIST)!libc!stdio>vfprintf.o + <$(SOURCE_GRIST)!libc!stdio>vfscanf.o + <$(SOURCE_GRIST)!libc!stdio>vscanf.o + <$(SOURCE_GRIST)!libc!stdio>vsprintf.o + <$(SOURCE_GRIST)!libc!stdio>wbuf.o + <$(SOURCE_GRIST)!libc!stdio>wsetup.o + + <$(SOURCE_GRIST)!libc!stdlib>assert.o + <$(SOURCE_GRIST)!libc!stdlib>atoi.o + <$(SOURCE_GRIST)!libc!stdlib>bsearch.o + <$(SOURCE_GRIST)!libc!stdlib>heapsort.o + <$(SOURCE_GRIST)!libc!stdlib>merge.o + <$(SOURCE_GRIST)!libc!stdlib>multibyte.o + <$(SOURCE_GRIST)!libc!stdlib>qsort.o + <$(SOURCE_GRIST)!libc!stdlib>radixsort.o + <$(SOURCE_GRIST)!libc!stdlib>rand.o + <$(SOURCE_GRIST)!libc!stdlib>random.o + <$(SOURCE_GRIST)!libc!stdlib>strtoq.o + <$(SOURCE_GRIST)!libc!stdlib>strtouq.o + + <$(SOURCE_GRIST)!libc!string>bcopy.o + <$(SOURCE_GRIST)!libc!string>bzero.o + <$(SOURCE_GRIST)!libc!string>memchr.o + <$(SOURCE_GRIST)!libc!string>memcmp.o + <$(SOURCE_GRIST)!libc!string>memcpy.o + <$(SOURCE_GRIST)!libc!string>memmove.o + <$(SOURCE_GRIST)!libc!string>memset.o + <$(SOURCE_GRIST)!libc!string>strcat.o + <$(SOURCE_GRIST)!libc!string>strchr.o + <$(SOURCE_GRIST)!libc!string>strcmp.o + <$(SOURCE_GRIST)!libc!string>strcpy.o + <$(SOURCE_GRIST)!libc!string>strerror.o + <$(SOURCE_GRIST)!libc!string>strlcat.o + <$(SOURCE_GRIST)!libc!string>strlcpy.o + <$(SOURCE_GRIST)!libc!string>strlen.o + <$(SOURCE_GRIST)!libc!string>strncat.o + <$(SOURCE_GRIST)!libc!string>strncmp.o + <$(SOURCE_GRIST)!libc!string>strncpy.o + <$(SOURCE_GRIST)!libc!string>strnicmp.o + <$(SOURCE_GRIST)!libc!string>strnlen.o + <$(SOURCE_GRIST)!libc!string>strpbrk.o + <$(SOURCE_GRIST)!libc!string>strrchr.o + <$(SOURCE_GRIST)!libc!string>strspn.o + <$(SOURCE_GRIST)!libc!string>strstr.o + <$(SOURCE_GRIST)!libc!string>strtok.o + + <$(SOURCE_GRIST)!libc!system>dlfcn.o + <$(SOURCE_GRIST)!libc!system>rlimit.o + <$(SOURCE_GRIST)!libc!system>syscalls.o + <$(SOURCE_GRIST)!libc!system>wrappers.o + <$(SOURCE_GRIST)!libc!system!arch!$(OBOS_ARCH)>atomic.o + + <$(SOURCE_GRIST)!libc!unistd>close.o + <$(SOURCE_GRIST)!libc!unistd>dup.o + <$(SOURCE_GRIST)!libc!unistd>dup2.o + <$(SOURCE_GRIST)!libc!unistd>getopt.o + <$(SOURCE_GRIST)!libc!unistd>lseek.o + <$(SOURCE_GRIST)!libc!unistd>open.o + <$(SOURCE_GRIST)!libc!unistd>opendir.o + <$(SOURCE_GRIST)!libc!unistd>pread.o + <$(SOURCE_GRIST)!libc!unistd>pwrite.o + <$(SOURCE_GRIST)!libc!unistd>read.o + <$(SOURCE_GRIST)!libc!unistd>sleep.o + <$(SOURCE_GRIST)!libc!unistd>usleep.o + <$(SOURCE_GRIST)!libc!unistd>write.o + ; + +KernelLd libc.so : + libglue.o + + <$(SOURCE_GRIST)!libc>nulibc_init.o + <$(SOURCE_GRIST)!libc>errno.o + + <$(SOURCE_GRIST)!libc!hoard>arch-specific.o + <$(SOURCE_GRIST)!libc!hoard>heap.o + <$(SOURCE_GRIST)!libc!hoard>processheap.o + <$(SOURCE_GRIST)!libc!hoard>superblock.o + <$(SOURCE_GRIST)!libc!hoard>threadheap.o + <$(SOURCE_GRIST)!libc!hoard>wrapper.o + + <$(SOURCE_GRIST)!libc!locale>ctype.o + + <$(SOURCE_GRIST)!libc!stdio>fclose.o + <$(SOURCE_GRIST)!libc!stdio>feof.o + <$(SOURCE_GRIST)!libc!stdio>fflush.o + <$(SOURCE_GRIST)!libc!stdio>fgetc.o + <$(SOURCE_GRIST)!libc!stdio>fgetln.o + <$(SOURCE_GRIST)!libc!stdio>fgets.o + <$(SOURCE_GRIST)!libc!stdio>findfp.o + <$(SOURCE_GRIST)!libc!stdio>flags.o + <$(SOURCE_GRIST)!libc!stdio>flockfile.o + <$(SOURCE_GRIST)!libc!stdio>fopen.o + <$(SOURCE_GRIST)!libc!stdio>fprintf.o + <$(SOURCE_GRIST)!libc!stdio>fputc.o + <$(SOURCE_GRIST)!libc!stdio>fputs.o + <$(SOURCE_GRIST)!libc!stdio>fread.o + <$(SOURCE_GRIST)!libc!stdio>fwrite.o + <$(SOURCE_GRIST)!libc!stdio>fvwrite.o + <$(SOURCE_GRIST)!libc!stdio>fwalk.o + <$(SOURCE_GRIST)!libc!stdio>getc.o + <$(SOURCE_GRIST)!libc!stdio>getchar.o + <$(SOURCE_GRIST)!libc!stdio>gets.o + <$(SOURCE_GRIST)!libc!stdio>getw.o + <$(SOURCE_GRIST)!libc!stdio>makebuf.o + <$(SOURCE_GRIST)!libc!stdio>printf.o + <$(SOURCE_GRIST)!libc!stdio>putc.o + <$(SOURCE_GRIST)!libc!stdio>putchar.o + <$(SOURCE_GRIST)!libc!stdio>puts.o + <$(SOURCE_GRIST)!libc!stdio>putw.o + <$(SOURCE_GRIST)!libc!stdio>refill.o + <$(SOURCE_GRIST)!libc!stdio>rget.o + <$(SOURCE_GRIST)!libc!stdio>sscanf.o + <$(SOURCE_GRIST)!libc!stdio>sprintf.o + <$(SOURCE_GRIST)!libc!stdio>stdio.o + <$(SOURCE_GRIST)!libc!stdio>ungetc.o + <$(SOURCE_GRIST)!libc!stdio>vfprintf.o + <$(SOURCE_GRIST)!libc!stdio>vfscanf.o + <$(SOURCE_GRIST)!libc!stdio>vscanf.o + <$(SOURCE_GRIST)!libc!stdio>vsprintf.o + <$(SOURCE_GRIST)!libc!stdio>wbuf.o + <$(SOURCE_GRIST)!libc!stdio>wsetup.o + + <$(SOURCE_GRIST)!libc!stdlib>assert.o + <$(SOURCE_GRIST)!libc!stdlib>atoi.o + <$(SOURCE_GRIST)!libc!stdlib>bsearch.o + <$(SOURCE_GRIST)!libc!stdlib>heapsort.o + <$(SOURCE_GRIST)!libc!stdlib>merge.o + <$(SOURCE_GRIST)!libc!stdlib>multibyte.o + <$(SOURCE_GRIST)!libc!stdlib>qsort.o + <$(SOURCE_GRIST)!libc!stdlib>radixsort.o + <$(SOURCE_GRIST)!libc!stdlib>rand.o + <$(SOURCE_GRIST)!libc!stdlib>random.o + <$(SOURCE_GRIST)!libc!stdlib>strtoq.o + <$(SOURCE_GRIST)!libc!stdlib>strtouq.o + + <$(SOURCE_GRIST)!libc!string>bcopy.o + <$(SOURCE_GRIST)!libc!string>bzero.o + <$(SOURCE_GRIST)!libc!string>memchr.o + <$(SOURCE_GRIST)!libc!string>memcmp.o + <$(SOURCE_GRIST)!libc!string>memcpy.o + <$(SOURCE_GRIST)!libc!string>memmove.o + <$(SOURCE_GRIST)!libc!string>memset.o + <$(SOURCE_GRIST)!libc!string>strcat.o + <$(SOURCE_GRIST)!libc!string>strchr.o + <$(SOURCE_GRIST)!libc!string>strcmp.o + <$(SOURCE_GRIST)!libc!string>strcpy.o + <$(SOURCE_GRIST)!libc!string>strerror.o + <$(SOURCE_GRIST)!libc!string>strlcat.o + <$(SOURCE_GRIST)!libc!string>strlcpy.o + <$(SOURCE_GRIST)!libc!string>strlen.o + <$(SOURCE_GRIST)!libc!string>strncat.o + <$(SOURCE_GRIST)!libc!string>strncmp.o + <$(SOURCE_GRIST)!libc!string>strncpy.o + <$(SOURCE_GRIST)!libc!string>strnicmp.o + <$(SOURCE_GRIST)!libc!string>strnlen.o + <$(SOURCE_GRIST)!libc!string>strpbrk.o + <$(SOURCE_GRIST)!libc!string>strrchr.o + <$(SOURCE_GRIST)!libc!string>strspn.o + <$(SOURCE_GRIST)!libc!string>strstr.o + <$(SOURCE_GRIST)!libc!string>strtok.o + + <$(SOURCE_GRIST)!libc!system>dlfcn.o + <$(SOURCE_GRIST)!libc!system>rlimit.o + <$(SOURCE_GRIST)!libc!system>syscalls.o + <$(SOURCE_GRIST)!libc!system>wrappers.o + <$(SOURCE_GRIST)!libc!system!arch!$(OBOS_ARCH)>atomic.o + + <$(SOURCE_GRIST)!libc!unistd>close.o + <$(SOURCE_GRIST)!libc!unistd>dup.o + <$(SOURCE_GRIST)!libc!unistd>dup2.o + <$(SOURCE_GRIST)!libc!unistd>getopt.o + <$(SOURCE_GRIST)!libc!unistd>lseek.o + <$(SOURCE_GRIST)!libc!unistd>open.o + <$(SOURCE_GRIST)!libc!unistd>opendir.o + <$(SOURCE_GRIST)!libc!unistd>pread.o + <$(SOURCE_GRIST)!libc!unistd>pwrite.o + <$(SOURCE_GRIST)!libc!unistd>read.o + <$(SOURCE_GRIST)!libc!unistd>sleep.o + <$(SOURCE_GRIST)!libc!unistd>usleep.o + <$(SOURCE_GRIST)!libc!unistd>write.o + : + $(SUBDIR)/ldscripts/$(OBOS_ARCH)/library.ld + : + -shared -soname libc.so + : + no_gcc + : + lib/libc.so + ; + +KernelLd libroot.so : + libglue2.o + <$(SOURCE_GRIST)!libroot>libroot.o + : + $(SUBDIR)/ldscripts/$(OBOS_ARCH)/library.ld + : + -shared -soname libroot.so + : + no_gcc + : + lib/libroot.so + ; + +KernelLd libglue2.o : + <$(SOURCE_GRIST)!glue>crt0.o + : + : + -r + : + no_gcc + ; + +KernelLd init : + libglue2.o + <$(SOURCE_GRIST)!apps>init.o + libc.so + libm.so + : + $(SUBDIR)/ldscripts/$(OBOS_ARCH)/app.ld + : + : + : + bin/init + ; + +KernelLd false : + libglue2.o + <$(SOURCE_GRIST)!apps>false_main.o + libc.so + libm.so + : + $(SUBDIR)/ldscripts/$(OBOS_ARCH)/app.ld + : + : + : + bin/false + ; + +KernelLd true : + libglue2.o + <$(SOURCE_GRIST)!apps>true_main.o + libc.so + libm.so + : + $(SUBDIR)/ldscripts/$(OBOS_ARCH)/app.ld + : + : + : + bin/true + ; + +KernelLd fibo : + libglue2.o + <$(SOURCE_GRIST)!apps>fibo_main.o + libc.so + libm.so + : + $(SUBDIR)/ldscripts/$(OBOS_ARCH)/app.ld + : + : + : + bin/fibo + ; + +KernelLd fortune : + libglue2.o + <$(SOURCE_GRIST)!apps!fortune>main.o + libc.so + libm.so + : + $(SUBDIR)/ldscripts/$(OBOS_ARCH)/app.ld + : + : + : + bin/fortune + ; + +KernelConfigSection etc/fortunes : data : $(SUBDIR)/apps/fortune/fortunes ; + +KernelLd ls : + libglue2.o + <$(SOURCE_GRIST)!apps!ls>main.o + libc.so + libm.so + : + $(SUBDIR)/ldscripts/$(OBOS_ARCH)/app.ld + : + : + : + bin/ls + ; + +# Note: shell is a built in target, thus we need the grist. +KernelLd obos_shell : + libglue2.o + <$(SOURCE_GRIST)!apps!shell>main.o + <$(SOURCE_GRIST)!apps!shell>args.o + <$(SOURCE_GRIST)!apps!shell>commands.o + <$(SOURCE_GRIST)!apps!shell>file_utils.o + <$(SOURCE_GRIST)!apps!shell>parse.o + <$(SOURCE_GRIST)!apps!shell>script.o + <$(SOURCE_GRIST)!apps!shell>shell_vars.o + <$(SOURCE_GRIST)!apps!shell>statements.o + <$(SOURCE_GRIST)!apps!shell>shell_history.o + libc.so + libm.so + : + $(SUBDIR)/ldscripts/$(OBOS_ARCH)/app.ld + : + : + : + bin/shell + ; + +KernelLd rld.so : + <$(SOURCE_GRIST)!apps!rld>rld0.o + <$(SOURCE_GRIST)!apps!rld>rld.o + <$(SOURCE_GRIST)!apps!rld>rldelf.o + <$(SOURCE_GRIST)!apps!rld>rldunix.o + <$(SOURCE_GRIST)!apps!rld>rldbeos.o + <$(SOURCE_GRIST)!apps!rld>rldheap.o + <$(SOURCE_GRIST)!apps!rld>rldaux.o + libc.a + : + $(SUBDIR)/apps/rld/arch/$(OBOS_ARCH)/rld.ld + : + : + : + libexec/rld.so + ; + +KernelLd mount : + libglue2.o + <$(SOURCE_GRIST)!apps!mount>main.o + libc.so + libm.so + : + $(SUBDIR)/ldscripts/$(OBOS_ARCH)/app.ld + : + : + : + bin/mount + ; + +KernelLd unmount : + libglue2.o + <$(SOURCE_GRIST)!apps!unmount>main.o + libc.so + libm.so + : + $(SUBDIR)/ldscripts/$(OBOS_ARCH)/app.ld + : + : + : + bin/unmount + ; + +KernelLd testapp : + libglue2.o + <$(SOURCE_GRIST)!apps!testapp>main.o + libc.so + libm.so + : + $(SUBDIR)/ldscripts/$(OBOS_ARCH)/app.ld + : + : + : + bin/testapp + ; + +KernelLd hostname : + libglue2.o + <$(SOURCE_GRIST)!apps!hostname>main.o + libc.so + libm.so + : + $(SUBDIR)/ldscripts/$(OBOS_ARCH)/app.ld + : + : + : + bin/hostname + ; + +KernelLd filetest : + libglue2.o + <$(SOURCE_GRIST)!apps!filetest>main.o + libc.so + libm.so + : + $(SUBDIR)/ldscripts/$(OBOS_ARCH)/app.ld + : + : + : + bin/filetest + ; + +KernelLd sockettest : + libglue2.o + <$(SOURCE_GRIST)!apps!sockettest>main.o + libc.so + libm.so + : + $(SUBDIR)/ldscripts/$(OBOS_ARCH)/app.ld + : + : + : + bin/sockettest + ; + +KernelLd loop : + <$(SOURCE_GRIST)!add-ons!net!loopback>loop.o + kernel.so + : + $(SUBDIR)/core/addons/ldscripts/$(OBOS_ARCH)/addon.ld + : + -Bdynamic -shared + : + : + addons/network/interface/loop + ; + +KernelLd digit : + <$(SOURCE_GRIST)!drivers!common>digit.o + kernel.so + : + $(SUBDIR)/core/addons/ldscripts/$(OBOS_ARCH)/addon.ld + : + -Bdynamic -shared + : + : + addons/drivers/dev/misc/digit + ; + +if $(OS) = "BEOS" +{ + KernelConfigSection addons/drivers/dev/misc/speaker + : + elf32 + : + /boot/beos/system/add-ons/kernel/drivers/bin/speaker + ; + + KernelConfigSection addons/drivers/dev/net/tulip + : + elf32 + : + /boot/beos/system/add-ons/kernel/drivers/bin/tulip + ; +} + +KernelLd testdigit : + libglue2.o + <$(SOURCE_GRIST)!apps!testdigit>main.o + libc.so + : + $(SUBDIR)/ldscripts/$(OBOS_ARCH)/app.ld + : + : + : + bin/testdigit + ; + +KernelLd thread_test : + libglue2.o + <$(SOURCE_GRIST)!apps!tests>thread_test.o + libc.so + : + $(SUBDIR)/ldscripts/$(OBOS_ARCH)/app.ld + : + : + : + bin/thread_test + ; + +KernelLd fops_test : + libglue2.o + <$(SOURCE_GRIST)!apps!tests>fops_test.o + libc.so + : + $(SUBDIR)/ldscripts/$(OBOS_ARCH)/app.ld + : + : + : + bin/fops_test + ; + +KernelLd ps : + libglue2.o + <$(SOURCE_GRIST)!apps!ps>main.o + libc.so + : + $(SUBDIR)/ldscripts/$(OBOS_ARCH)/app.ld + : + : + : + bin/ps + ; + +KernelLd echo : + libglue2.o + <$(SOURCE_GRIST)!apps!echo>main.o + libc.so + : + $(SUBDIR)/ldscripts/$(OBOS_ARCH)/app.ld + : + : + : + bin/echo + ; + +KernelLd uname : + libglue2.o + <$(SOURCE_GRIST)!apps!uname>main.o + libc.so + : + $(SUBDIR)/ldscripts/$(OBOS_ARCH)/app.ld + : + : + : + bin/uname + ; + +WriteKernelConfig $(OBOS_KERNEL_CONFIG) ; + +BuildKernel $(OBOS_KERNEL) : $(OBOS_KERNEL_CONFIG) ; + +KernelFloppyImage $(OBOS_FLOPPY) : $(OBOS_KERNEL) : $(SUBDIR)/boot/arch/$(OBOS_ARCH)/bootblock.bin ; + +SubInclude OBOS_TOP sources os kits kernel boot ; +SubInclude OBOS_TOP sources os kits kernel core ; +SubInclude OBOS_TOP sources os kits kernel drivers ; +SubInclude OBOS_TOP sources os kits kernel global ; +SubInclude OBOS_TOP sources os kits kernel glue ; +SubInclude OBOS_TOP sources os kits kernel libc ; +SubInclude OBOS_TOP sources os kits kernel libm ; +SubInclude OBOS_TOP sources os kits kernel apps ; +SubInclude OBOS_TOP sources os kits kernel add-ons ; +SubInclude OBOS_TOP sources os kits kernel libroot ; diff --git a/src/kernel/TODO b/src/kernel/TODO new file mode 100644 index 0000000000..66d25db0f8 --- /dev/null +++ b/src/kernel/TODO @@ -0,0 +1,42 @@ + +Implement: + +process environment variables +scheduler updates: + better quantum handling + priority boost on sem block +improved kernel debugger support: + symbol lookups + stack tracing +kernel slab allocator +Rewrite VFS +VM: + Allow alteration of region's attributes + cache layer + better region creation args (range of virtual addresses, etc) + reserve regions + page out (changes to mmap and swapfile) +Block Drivers +Work on Driver system, overall +POSIX +New Booting method +more on the user space libs +Improved bus managers (BeOS style) +Fully relocatable kernel, stage2 relocates + +signals +tty layer +Integrate OBFS +Integrate Networking +kernel module loading: +RLD + lazy binding + so initialization + dl_open() and load_addon() +Work on PCI +libRoot +IDE bus manager +use fxsave instead of fsave where appropriate +move more per-cpu stuff to the global cpu[] array +Places in kernel where page fault with ints off happens +Random reboot on heavy fibo usage diff --git a/src/kernel/apps/Jamfile b/src/kernel/apps/Jamfile new file mode 100644 index 0000000000..fd1450a0f7 --- /dev/null +++ b/src/kernel/apps/Jamfile @@ -0,0 +1,19 @@ +SubDir OBOS_TOP sources os kits kernel apps ; + +KernelObjects false_main.c fibo_main.c init.c true_main.c ; + +SubInclude OBOS_TOP sources os kits kernel apps uname ; +SubInclude OBOS_TOP sources os kits kernel apps echo ; +SubInclude OBOS_TOP sources os kits kernel apps filetest ; +SubInclude OBOS_TOP sources os kits kernel apps fortune ; +SubInclude OBOS_TOP sources os kits kernel apps hostname ; +SubInclude OBOS_TOP sources os kits kernel apps ls ; +SubInclude OBOS_TOP sources os kits kernel apps mount ; +SubInclude OBOS_TOP sources os kits kernel apps ps ; +SubInclude OBOS_TOP sources os kits kernel apps rld ; +SubInclude OBOS_TOP sources os kits kernel apps shell ; +SubInclude OBOS_TOP sources os kits kernel apps sockettest ; +SubInclude OBOS_TOP sources os kits kernel apps testapp ; +SubInclude OBOS_TOP sources os kits kernel apps testdigit ; +SubInclude OBOS_TOP sources os kits kernel apps tests ; +SubInclude OBOS_TOP sources os kits kernel apps unmount ; diff --git a/src/kernel/apps/echo/Jamfile b/src/kernel/apps/echo/Jamfile new file mode 100644 index 0000000000..a8eb79fc76 --- /dev/null +++ b/src/kernel/apps/echo/Jamfile @@ -0,0 +1,3 @@ +SubDir OBOS_TOP sources os kits kernel apps echo ; + +KernelObjects <$(SOURCE_GRIST)>main.c : -fpic -Wno-unused ; diff --git a/src/kernel/apps/echo/main.c b/src/kernel/apps/echo/main.c new file mode 100644 index 0000000000..1c12223b75 --- /dev/null +++ b/src/kernel/apps/echo/main.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include + +#include +#include +#include + +int +main(int argc , char *argv[]) +{ + int nflag; /* if not set, output a trailing newline. */ + + /* This utility may NOT do getopt(3) option parsing. */ + if (*++argv && !strcmp(*argv, "-n")) { + ++argv; + nflag = 1; + } + else + nflag = 0; + + while (argv[0] != NULL) { + + /* + * If the next argument is NULL then this is this + * the last argument, therefore we need to check + * for a trailing \c. + */ + if (argv[1] == NULL) { + size_t len; + + len = strlen(argv[0]); + /* is there room for a '\c' and is there one? */ + if (len >= 2 && + argv[0][len - 2] == '\\' && + argv[0][len - 1] == 'c') { + /* chop it and set the no-newline flag. */ + argv[0][len - 2] = '\0'; + nflag = 1; + } + } + (void)printf("%s", argv[0]); + if (*++argv) + putchar(' '); + } + if (!nflag) + putchar('\n'); + return 0; +} diff --git a/src/kernel/apps/false_main.c b/src/kernel/apps/false_main.c new file mode 100644 index 0000000000..9128fb0be9 --- /dev/null +++ b/src/kernel/apps/false_main.c @@ -0,0 +1,13 @@ +/* +** Copyright 2002, Manuel J. Petit. All rights reserved. +** Contains portions of: +** +** /boot/bin/true, Copyright 2001 Travis K. Geiselbrecht +** +** Distributed under the terms of the NewOS License. +*/ +int main(void) +{ + return 1; +} + diff --git a/src/kernel/apps/fibo_main.c b/src/kernel/apps/fibo_main.c new file mode 100644 index 0000000000..207e2a8b0b --- /dev/null +++ b/src/kernel/apps/fibo_main.c @@ -0,0 +1,69 @@ +/* +** Copyright 2002, Manuel J. Petit. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#include +#include +#include +#include + +static +void +usage(char const *app) +{ + printf("usage: %s [-s] ###\n", app); + sys_exit(-1); +} + +int +main(int argc, char *argv[]) +{ + int num= 0; + int silent= 0; + int result; + + switch(argc) { + case 2: + num= atoi(argv[1]); + break; + case 3: + if(strcmp(argv[1], "-s")== 0) { + num= atoi(argv[2]); + silent= 1; + } else { + usage(argv[0]); + } + break; + default: + usage(argv[0]); + break; + } + + if(num < 2) { + result= 1; + } else { + proc_id pid; + int retcode; + char buffer[64]; + char *aaargv[]= { "/boot/bin/fibo", "-s", buffer, NULL }; + int aaargc= 3; + + sprintf(buffer, "%d", num-1); + pid= sys_proc_create_proc(aaargv[0], aaargv[0], aaargv, aaargc, 5); + sys_proc_wait_on_proc(pid, &retcode); + result= retcode; + + sprintf(buffer, "%d", num-2); + pid= sys_proc_create_proc(aaargv[0], aaargv[0], aaargv, aaargc, 5); + sys_proc_wait_on_proc(pid, &retcode); + result+= retcode; + } + + if(silent) { + return result; + } else { + printf("%d\n", result); + return 0; + } +} diff --git a/src/kernel/apps/filetest/Jamfile b/src/kernel/apps/filetest/Jamfile new file mode 100644 index 0000000000..595f390a5a --- /dev/null +++ b/src/kernel/apps/filetest/Jamfile @@ -0,0 +1,3 @@ +SubDir OBOS_TOP sources os kits kernel apps filetest ; + +KernelObjects <$(SOURCE_GRIST)>main.c : -fpic -Wno-unused ; diff --git a/src/kernel/apps/filetest/main.c b/src/kernel/apps/filetest/main.c new file mode 100644 index 0000000000..04a022b4da --- /dev/null +++ b/src/kernel/apps/filetest/main.c @@ -0,0 +1,51 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#define FORTUNES "/boot/etc/fortunes" + +int main(int argc, char **argv) +{ + int rc = 0, fd[3]; + int cnt, i; + int on = 1; + + printf("File Test!!!\n"); + + for (i=0;i<3;i++) { + printf("%d : ", i + 1); + fd[i] = open(FORTUNES, O_RDONLY, 0); + printf("fd %d\n", fd[i]); + } + + printf("closing the 3 fd's\n"); + for (i=0;i<3;i++) { + close(fd[i]); + } + + printf("\nNow we have no open fd's so next socket should be 3\n"); + fd[0] = open(FORTUNES, O_RDONLY, 0); + printf("new fd %d\n", fd[0]); + + printf("Trying ioctl to set non-blocking: "); + rc = ioctl(fd[0], FIONBIO, &on, sizeof(on)); + if (rc == EINVAL) { + printf("OK\n"); + } else { + printf("failed\n"); + printf("error was %s\n", strerror(errno)); + } + + close(fd[0]); + + return 0; +} diff --git a/src/kernel/apps/fortune/Jamfile b/src/kernel/apps/fortune/Jamfile new file mode 100644 index 0000000000..b3dc0c7dc7 --- /dev/null +++ b/src/kernel/apps/fortune/Jamfile @@ -0,0 +1,3 @@ +SubDir OBOS_TOP sources os kits kernel apps fortune ; + +KernelObjects <$(SOURCE_GRIST)>main.c : -fpic ; diff --git a/src/kernel/apps/fortune/fortunes b/src/kernel/apps/fortune/fortunes new file mode 100644 index 0000000000..168166bd09 --- /dev/null +++ b/src/kernel/apps/fortune/fortunes @@ -0,0 +1,9 @@ +#@# +Magic is real... unless declared integer. +#@# +System is up and running. +#@# +Open source thesis that thousand of eyes looking thu the code +increases software quality is completely wrong. The amount of +bugs per line of code is an universal constant. The bazaar +model only achieves a quick bug turnover. diff --git a/src/kernel/apps/fortune/main.c b/src/kernel/apps/fortune/main.c new file mode 100644 index 0000000000..5ec96e3854 --- /dev/null +++ b/src/kernel/apps/fortune/main.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define FORTUNES "/boot/etc/fortunes" + +int +main(void) +{ + int fd; + int rc; + char *buf; + unsigned i; + unsigned found; + struct stat stat; + + fd = open(FORTUNES, O_RDONLY, 0); + if (fd < 0) { + printf("Couldn't open %s: %s\n", FORTUNES, strerror(errno)); + return -1; + } + + rc = fstat(fd, &stat); + if(rc < 0) { + printf("Cookie monster was here!!!\n"); + sys_exit(1); + } + + buf= malloc(stat.st_size + 1); + + read(fd, buf, stat.st_size); + buf[stat.st_size]= 0; + close(fd); + + found= 0; + for(i= 0; i< stat.st_size; i++) { + if(strncmp(buf+i, "#@#", 3)== 0) { + found+= 1; + } + } + + found = 1 + (sys_system_time() % found); + + for(i = 0; i < stat.st_size; i++) { + if(strncmp(buf+i, "#@#", 3)== 0) { + found-= 1; + } + if(found== 0) { + unsigned j; + + for(j= i+1; j< stat.st_size; j++) { + if(strncmp(buf+j, "#@#", 3)== 0) { + buf[j]= 0; + } + } + + printf("%s\n", buf+i+3); + break; + } + } + + return 0; +} diff --git a/src/kernel/apps/hostname/Jamfile b/src/kernel/apps/hostname/Jamfile new file mode 100644 index 0000000000..7291006765 --- /dev/null +++ b/src/kernel/apps/hostname/Jamfile @@ -0,0 +1,3 @@ +SubDir OBOS_TOP sources os kits kernel apps hostname ; + +KernelObjects <$(SOURCE_GRIST)>main.c : -fpic -Wno-unused ; diff --git a/src/kernel/apps/hostname/main.c b/src/kernel/apps/hostname/main.c new file mode 100644 index 0000000000..2630de5369 --- /dev/null +++ b/src/kernel/apps/hostname/main.c @@ -0,0 +1,42 @@ +/* naive implementation of hostname + * + * This mainly serves as a testbed for sysctl, part of the kernel + * just added. + */ + +#include +#include +#include +#include +#include + +#define MAXHOSTNAMELEN 256 + +int main(int argc, char *argv[]) +{ + char buffer[MAXHOSTNAMELEN]; + size_t buflen = MAXHOSTNAMELEN; + int mib[2]; + int rc = -1; + char *newname = NULL; + size_t newnamelen = 0; + + if (argc >= 2) { + newname = argv[1]; + newnamelen = strlen(newname); + } + + buffer[0] = '\0'; + mib[0] = CTL_KERN; + mib[1] = KERN_HOSTNAME; + + rc = sysctl(mib, 2, &buffer, &buflen, newname, newnamelen); + + if (rc == 0 && !newname) { + printf("%s\n", buffer); + } + + return 0; +} + + diff --git a/src/kernel/apps/init.c b/src/kernel/apps/init.c new file mode 100644 index 0000000000..a9050dcd93 --- /dev/null +++ b/src/kernel/apps/init.c @@ -0,0 +1,63 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include + +static void setup_io() +{ + int i; + + for(i= 0; i< 256; i++) { + close(i); + } + + /* XXX - open currently ignores these flags, but they + * should be checked once it doesn't :) + * Is STDERR really O_WRONLY? + */ + open("/dev/console", O_RDONLY, 0); /* stdin */ + open("/dev/console", O_WRONLY, 0); /* stdout */ + open("/dev/console", O_WRONLY, 0); /* stderr */ +} + +int main() +{ + setup_io(); + + printf("Welcome to OpenBeOS!\n"); + + if(1) { + proc_id pid; + + pid = sys_proc_create_proc("/boot/bin/fortune", "/boot/bin/fortune", NULL, 0, 5); + if (pid >= 0) { + int retcode; + sys_proc_wait_on_proc(pid, &retcode); + } else { + printf("Failed to create a proc for fortune.\n"); + } + } + + + while(1) { + proc_id pid; + + pid = sys_proc_create_proc("/boot/bin/shell", "/boot/bin/shell", NULL, 0, 5); + if(pid >= 0) { + int retcode; + printf("init: spawned shell, pid 0x%x\n", pid); + sys_proc_wait_on_proc(pid, &retcode); + printf("init: shell exited with return code %d\n", retcode); + } else { + printf("Failed to start a shell :(\n"); + } + } + + printf("init exiting\n"); + + return 0; +} diff --git a/src/kernel/apps/ls/Jamfile b/src/kernel/apps/ls/Jamfile new file mode 100644 index 0000000000..a27c6b97d9 --- /dev/null +++ b/src/kernel/apps/ls/Jamfile @@ -0,0 +1,3 @@ +SubDir OBOS_TOP sources os kits kernel apps ls ; + +KernelObjects <$(SOURCE_GRIST)>main.c : -fpic -Wno-unused ; diff --git a/src/kernel/apps/ls/main.c b/src/kernel/apps/ls/main.c new file mode 100644 index 0000000000..034f922ae0 --- /dev/null +++ b/src/kernel/apps/ls/main.c @@ -0,0 +1,148 @@ +/* +** Copyright 2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include + +extern char *__progname; + +void (*disp_func)(const char *, struct stat *) = NULL; +static int show_all = 0; + +mode_t perms [9] = { + S_IRUSR, + S_IWUSR, + S_IXUSR, + S_IRGRP, + S_IWGRP, + S_IXGRP, + S_IROTH, + S_IWOTH, + S_IXOTH +}; + +static void display_l(const char *filename, struct stat *stat) +{ + const char *type; + char perm[11]; + int i; + memset(perm, '-', 10); + perm[10] = '\0'; + + for (i=0; i < sizeof(perms) / sizeof(mode_t); i++) { + if (stat->st_mode & perms[i]) { + switch(i % 3) { + case 0: + perm[i + 1] = 'r'; + break; + case 1: + perm[i+1] = 'w'; + break; + case 2: + perm[i+1] = 'x'; + } + } + } + if (S_ISDIR(stat->st_mode)) + perm[0] = 'd'; + + printf("%10s %12lld %s\n" ,perm ,stat->st_size ,filename); +} + +static void display(const char *filename, struct stat *stat) +{ + printf("%s\n", filename); +} + +int main(int argc, char *argv[]) +{ + int rc; + int rc2; + int count = 0; + struct stat st; + char *arg; + int ch; + uint64 totbytes = 0; + + disp_func = display; + + while ((ch = getopt(argc, argv, "al")) != -1) { + switch (ch) { + case 'a': + show_all = 1; + break; + case 'l': + disp_func = display_l; + break; + } + } + argc -= optind; + argv += optind; + + if(*argv == NULL) { + arg = "."; + } else { + arg = *argv; + } + + rc = stat(arg, &st); + if(rc < 0) { + printf("%s: %s: %s\n", __progname, + arg, strerror(rc)); + goto err_ls; + } + + if (S_ISDIR(st.st_mode)) { + char buf[1024]; + DIR *thedir = opendir(arg); + + if (!thedir) { + printf("ls: %s: %s\n", arg, strerror(errno)); + } else { + if (show_all) { + /* process the '.' entry */ + rc = stat(arg, &st); + if (rc == 0) { + (*disp_func)(".", &st); + totbytes += st.st_size; + } + } + + for(;;) { + char buf2[1024]; + struct dirent *de = readdir(thedir); + + if (!de) + break; + + memset(buf2, 0, sizeof(buf2)); + if (strcmp(arg, ".") != 0) { + strlcpy(buf2, arg, sizeof(buf2)); + strlcat(buf2, "/", sizeof(buf2)); + } + strlcat(buf2, de->d_name, sizeof(buf2)); + + rc2 = stat(buf2, &st); + if (rc2 == 0) { + (*disp_func)(de->d_name, &st); + totbytes += st.st_size; + } + count++; + } + closedir(thedir); + } + + printf("%lld bytes in %d files\n", totbytes, count); + } else { + (*disp_func)(arg, &st); + } + +err_ls: + return 0; +} diff --git a/src/kernel/apps/mount/Jamfile b/src/kernel/apps/mount/Jamfile new file mode 100644 index 0000000000..2e40082364 --- /dev/null +++ b/src/kernel/apps/mount/Jamfile @@ -0,0 +1,3 @@ +SubDir OBOS_TOP sources os kits kernel apps mount ; + +KernelObjects <$(SOURCE_GRIST)>main.c : -fpic ; diff --git a/src/kernel/apps/mount/main.c b/src/kernel/apps/mount/main.c new file mode 100644 index 0000000000..3d67e4fd42 --- /dev/null +++ b/src/kernel/apps/mount/main.c @@ -0,0 +1,28 @@ +/* +** Copyright 2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include + +int main(int argc, char *argv[]) +{ + int rc; + + if(argc < 4) { + printf("not enough arguments to mount:\n"); + printf("usage: mount \n"); + return 0; + } + + rc = sys_mount(argv[1], argv[2], argv[3], NULL); + if (rc < 0) { + printf("sys_mount() returned error: %s\n", strerror(rc)); + } else { + printf("%s successfully mounted on %s.\n", argv[2], argv[1]); + } + + return 0; +} + diff --git a/src/kernel/apps/ps/Jamfile b/src/kernel/apps/ps/Jamfile new file mode 100644 index 0000000000..4fec2f9922 --- /dev/null +++ b/src/kernel/apps/ps/Jamfile @@ -0,0 +1,3 @@ +SubDir OBOS_TOP sources os kits kernel apps ps ; + +KernelObjects <$(SOURCE_GRIST)>main.c ; diff --git a/src/kernel/apps/ps/main.c b/src/kernel/apps/ps/main.c new file mode 100644 index 0000000000..963577284b --- /dev/null +++ b/src/kernel/apps/ps/main.c @@ -0,0 +1,74 @@ +/* +** Copyright 2002, Dan Sinclair. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +/* + * This code was originally in the shell/command.c file and + * was written by: + * Damien Guard + * I just split it out into its own file +*/ + +#include +#include +#include +#include + + +#define MAX_PROCESSES 1024 + +typedef struct proc_info proc_info; + + +inline const char *proc_state_string (int state); + +inline +const char * +proc_state_string (int state) +{ + switch (state) { + case 0: return "normal"; + case 1: return "birth"; + case 2: return "death"; + default: + return "???"; + } +} + + +int +main(int argc, char ** argv) +{ + size_t table_size = MAX_PROCESSES * sizeof(proc_info); + proc_info *table = (proc_info *) malloc(table_size); + + if (table) { + int num_procs = sys_proc_get_table(table, table_size); + + if (num_procs <= 0) + printf("ps: sys_get_proc_table() returned error %s!\n", strerror(num_procs)); + + else { + int n = num_procs; + proc_info *p = table; + + printf("process list\n\n"); + printf("id\tstate\tthreads\tname\n"); + + while (n--) { + printf("%d\t%s\t%d\t%s\n", + p->id, + proc_state_string(p->state), + p->num_threads, + p->name); + p += sizeof(proc_info); + } + printf("\n%d processes listed\n", num_procs); + } + + free(table); + } + + return 0; +} + diff --git a/src/kernel/apps/rld/Jamfile b/src/kernel/apps/rld/Jamfile new file mode 100644 index 0000000000..b53a5d0aee --- /dev/null +++ b/src/kernel/apps/rld/Jamfile @@ -0,0 +1,10 @@ +SubDir OBOS_TOP sources os kits kernel apps rld ; + +KernelObjects <$(SOURCE_GRIST)>rld.c + <$(SOURCE_GRIST)>rld0.c + <$(SOURCE_GRIST)>rldaux.c + <$(SOURCE_GRIST)>rldbeos.c + <$(SOURCE_GRIST)>rldelf.c + <$(SOURCE_GRIST)>rldheap.c + <$(SOURCE_GRIST)>rldunix.c + : -fpic ; diff --git a/src/kernel/apps/rld/arch/rldreloc.inc b/src/kernel/apps/rld/arch/rldreloc.inc new file mode 100644 index 0000000000..7a91805f51 --- /dev/null +++ b/src/kernel/apps/rld/arch/rldreloc.inc @@ -0,0 +1,21 @@ +#ifdef ARCH_x86 +#include "x86/rldreloc.inc" +#endif +#ifdef ARCH_alpha +#include "alpha/rldreloc.inc" +#endif +#ifdef ARCH_sh4 +#include "sh4/rldreloc.inc" +#endif +#ifdef ARCH_sparc +#include "sparc/rldreloc.inc" +#endif +#ifdef ARCH_sparc64 +#include "sparc64/rldreloc.inc" +#endif +#ifdef ARCH_mips +#include "mips/rldreloc.inc" +#endif +#ifdef ARCH_ppc +#include "ppc/rldreloc.inc" +#endif diff --git a/src/kernel/apps/rld/arch/x86/rld.ld b/src/kernel/apps/rld/arch/x86/rld.ld new file mode 100644 index 0000000000..97119f3727 --- /dev/null +++ b/src/kernel/apps/rld/arch/x86/rld.ld @@ -0,0 +1,63 @@ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) + +ENTRY(RLD_STARTUP) +SEARCH_DIR("libgcc"); +SECTIONS +{ + . = 0x00100000 + SIZEOF_HEADERS; + + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0x9090 + .plt : { *(.plt) } + + /* text/read-only data */ + .text : { *(.text .gnu.linkonce.t.*) } + + .rodata : { *(.rodata) } + + /* writable data */ + . = ALIGN(0x1000) + (. & (0x1000 - 1)); + __data_start = .; + PROVIDE(_data_start = .); + .data : { *(.data .gnu.linkonce.d.*) } + + __ctor_list = .; + PROVIDE (_ctor_list = .); + .ctors : { *(.ctors) } + PROVIDE (__ctor_end = .); + + + /* unintialized data (in same segment as writable data) */ + PROVIDE (__bss_start = .); + .bss : { *(.bss) } + + . = ALIGN(0x1000); + PROVIDE (_end = .); + + /* Strip unnecessary stuff */ + /DISCARD/ : { *(.comment .note .eh_frame .dtors) } +} diff --git a/src/kernel/apps/rld/arch/x86/rldreloc.inc b/src/kernel/apps/rld/arch/x86/rldreloc.inc new file mode 100644 index 0000000000..c1a25f0bd0 --- /dev/null +++ b/src/kernel/apps/rld/arch/x86/rldreloc.inc @@ -0,0 +1,132 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Copyright 2002, Manuel J. Petit. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +static +int +relocate_rel(image_t *image, struct Elf32_Rel *rel, int rel_len ) +{ + int i; + struct Elf32_Sym *sym; + int vlErr; + addr S; + addr final_val; + +# define P ((addr *)(image->regions[0].delta + rel[i].r_offset)) +# define A (*(P)) +# define B (image->regions[0].delta) + + for(i = 0; i * (int)sizeof(struct Elf32_Rel) < rel_len; i++) { + + unsigned type= ELF32_R_TYPE(rel[i].r_info); + + switch(ELF32_R_TYPE(rel[i].r_info)) { + case R_386_32: + case R_386_PC32: + case R_386_GLOB_DAT: + case R_386_JMP_SLOT: + case R_386_GOTOFF: + sym = SYMBOL(image, ELF32_R_SYM(rel[i].r_info)); + + vlErr = resolve_symbol(image, sym, &S); + if(vlErr<0) { + return vlErr; + } + } + switch(type) { + case R_386_NONE: + continue; + case R_386_32: + final_val= S+A; + break; + case R_386_PC32: + final_val=S+A-(addr)P; + break; +#if 0 + case R_386_GOT32: + final_val= G+A; + break; + case R_386_PLT32: + final_val= L+A-(addr)P; + break; +#endif + case R_386_COPY: + /* what ? */ + continue; + case R_386_GLOB_DAT: + final_val= S; + break; + case R_386_JMP_SLOT: + final_val= S; + break; + case R_386_RELATIVE: + final_val= B+A; + break; +#if 0 + case R_386_GOTOFF: + final_val= S+A-GOT; + break; + case R_386_GOTPC: + final_val= GOT+A-P; + break; +#endif + default: + printf("unhandled relocation type %d\n", ELF32_R_TYPE(rel[i].r_info)); + return ERR_NOT_ALLOWED; + } + + *P= final_val; + } + +# undef P +# undef A +# undef B + + + return B_NO_ERROR; +} + +/* + * rldelf.c requires this function to be implemented on a per-cpu basis + */ +static +bool +relocate_image(image_t *image) +{ + int res = B_NO_ERROR; + int i; + + if(image->flags & RFLAG_RELOCATED) { + return true; + } + image->flags|= RFLAG_RELOCATED; + + // deal with the rels first + if(image->rel) { + res= relocate_rel( image, image->rel, image->rel_len ); + + if(res) { + return false; + } + } + + if(image->pltrel) { + res= relocate_rel(image, image->pltrel, image->pltrel_len); + + if(res) { + return false; + } + } + + if(image->rela) { + printf("RELA relocations not supported\n"); + return ERR_NOT_ALLOWED; + for(i = 1; i * (int)sizeof(struct Elf32_Rela) < image->rela_len; i++) { + printf("rela: type %d\n", ELF32_R_TYPE(image->rela[i].r_info)); + } + } + + return true; +} diff --git a/src/kernel/apps/rld/rld.c b/src/kernel/apps/rld/rld.c new file mode 100644 index 0000000000..5fedc2569c --- /dev/null +++ b/src/kernel/apps/rld/rld.c @@ -0,0 +1,57 @@ +/* +** Copyright 2002, Manuel J. Petit. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#include +#include +#include +#include "rld_priv.h" + + + +static struct rld_export_t exports= +{ + /* + * Unix like stuff + */ + export_dl_open, + export_dl_close, + export_dl_sym, + + + /* + * BeOS like stuff + */ + export_load_addon, + export_unload_addon, + export_addon_symbol +}; + + +int +rldmain(void *arg) +{ + int retval; + unsigned long entry; + struct uspace_prog_args_t *uspa= (struct uspace_prog_args_t *)arg; + + rldheap_init(); + + entry= 0; + + uspa->rld_export= &exports; + + rldelf_init(uspa); + + load_program(uspa->prog_path, (void**)&entry); + + if(entry) { + retval= ((int(*)(void*))(entry))(uspa); + } else { + return -1; + } + + return retval; +} + diff --git a/src/kernel/apps/rld/rld0.c b/src/kernel/apps/rld/rld0.c new file mode 100644 index 0000000000..e98b1a7581 --- /dev/null +++ b/src/kernel/apps/rld/rld0.c @@ -0,0 +1,16 @@ +/* +** Copyright 2002, Manuel J. Petit. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#include "rld_priv.h" + +int RLD_STARTUP(void *args) +{ +#if DEBUG_RLD + sys_close(0); open("/dev/console", 0); /* stdin */ + sys_close(1); open("/dev/console", 0); /* stdout */ + sys_close(2); open("/dev/console", 0); /* stderr */ +#endif + rldmain(args); +} diff --git a/src/kernel/apps/rld/rld_priv.h b/src/kernel/apps/rld/rld_priv.h new file mode 100644 index 0000000000..522d55d139 --- /dev/null +++ b/src/kernel/apps/rld/rld_priv.h @@ -0,0 +1,45 @@ +/* +** Copyright 2002, Manuel J. Petit. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#ifndef __newos__run_time_linker__hh__ +#define __newos__run_time_linker__hh__ + + +#include +#include + + +#define NEWOS_MAGIC_APPNAME "__NEWOS_APP__" + +typedef unsigned dynmodule_id; +int RLD_STARTUP(void *); +int rldmain(void *arg); + +dynmodule_id load_program(char const *path, void **entry); +dynmodule_id load_library(char const *path); +dynmodule_id load_addon(char const *path); +dynmodule_id unload_program(dynmodule_id imid); +dynmodule_id unload_library(dynmodule_id imid); +dynmodule_id unload_addon(dynmodule_id imid); + +void *dynamic_symbol(dynmodule_id imid, char const *symbol); + + +void rldelf_init(struct uspace_prog_args_t const *uspa); + +void rldheap_init(void); +void *rldalloc(size_t); +void rldfree(void *p); + +int export_dl_open(char const *, unsigned); +int export_dl_close(int, unsigned); +void *export_dl_sym(int, char const *, unsigned); + +int export_load_addon(char const *, unsigned); +int export_unload_addon(int, unsigned); +void *export_addon_symbol(int, char const *, unsigned); + +#endif + diff --git a/src/kernel/apps/rld/rldaux.c b/src/kernel/apps/rld/rldaux.c new file mode 100644 index 0000000000..c987dcdf16 --- /dev/null +++ b/src/kernel/apps/rld/rldaux.c @@ -0,0 +1,22 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include + +int printf(const char *fmt, ...) +{ + va_list args; + char buf[1024]; + int i; + + va_start(args, fmt); + i = vsprintf(buf, fmt, args); + va_end(args); + + sys_write(2, buf, 0, strlen(buf)); + + return i; +} diff --git a/src/kernel/apps/rld/rldbeos.c b/src/kernel/apps/rld/rldbeos.c new file mode 100644 index 0000000000..f1f47fc787 --- /dev/null +++ b/src/kernel/apps/rld/rldbeos.c @@ -0,0 +1,34 @@ +/* +** Copyright 2002, Manuel J. Petit. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#include "rld_priv.h" + +int +export_load_addon(char const *name, unsigned flags) +{ + (void)(name); + (void)(flags); + + return -1; +} + +int +export_unload_addon(int lib, unsigned flags) +{ + (void)(lib); + (void)(flags); + + return -1; +} + +void * +export_addon_symbol(int lib, char const *sym, unsigned flags) +{ + (void)(lib); + (void)(sym); + (void)(flags); + + return 0; +} diff --git a/src/kernel/apps/rld/rldelf.c b/src/kernel/apps/rld/rldelf.c new file mode 100644 index 0000000000..43f04d2b9f --- /dev/null +++ b/src/kernel/apps/rld/rldelf.c @@ -0,0 +1,1066 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Copyright 2002, Manuel J. Petit. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rld_priv.h" + + +#define PAGE_SIZE 4096 +#define PAGE_MASK ((PAGE_SIZE)-1) +#define PAGE_OFFS(y) ((y)&(PAGE_MASK)) +#define PAGE_BASE(y) ((y)&~(PAGE_MASK)) + +/* david - added '_' to avoid macro's in kernel.h */ +#define _ROUNDOWN(x,y) ((x)&~((y)-1)) +#define _ROUNDUP(x,y) ROUNDOWN(x+y-1,y) + + +enum { + RFLAG_RW = 0x0001, + RFLAG_ANON = 0x0002, + + RFLAG_SORTED = 0x0400, + RFLAG_SYMBOLIC = 0x0800, + RFLAG_RELOCATED = 0x1000, + RFLAG_PROTECTED = 0x2000, + RFLAG_INITIALIZED = 0x4000, + RFLAG_NEEDAGIRLFRIEND= 0x8000 +}; + + +typedef +struct elf_region_t { + region_id id; + addr start; + addr size; + addr vmstart; + addr vmsize; + addr fdstart; + addr fdsize; + long delta; + unsigned flags; +} elf_region_t; + + +typedef +struct image_t { + /* + * image identification + */ + char name[SYS_MAX_OS_NAME_LEN]; + dynmodule_id imageid; + + struct image_t *next; + struct image_t *prev; + int refcount; + unsigned flags; + + addr entry_point; + addr dynamic_ptr; // pointer to the dynamic section + + + // pointer to symbol participation data structures + unsigned int *symhash; + struct Elf32_Sym *syms; + char *strtab; + struct Elf32_Rel *rel; + int rel_len; + struct Elf32_Rela *rela; + int rela_len; + struct Elf32_Rel *pltrel; + int pltrel_len; + + unsigned num_needed; + struct image_t **needed; + + // describes the text and data regions + unsigned num_regions; + elf_region_t regions[1]; +} image_t; + + +typedef +struct image_queue_t { + image_t *head; + image_t *tail; +} image_queue_t; + + +static image_queue_t loaded_images= { 0, 0 }; +static image_queue_t loading_images= { 0, 0 }; +static image_queue_t disposable_images= { 0, 0 }; +static unsigned loaded_image_count= 0; +static unsigned imageid_count= 0; + +static sem_id rld_sem; +static struct uspace_prog_args_t const *uspa; + + +#define STRING(image, offset) ((char *)(&(image)->strtab[(offset)])) +#define SYMNAME(image, sym) STRING(image, (sym)->st_name) +#define SYMBOL(image, num) ((struct Elf32_Sym *)&(image)->syms[num]) +#define HASHTABSIZE(image) ((image)->symhash[0]) +#define HASHBUCKETS(image) ((unsigned int *)&(image)->symhash[2]) +#define HASHCHAINS(image) ((unsigned int *)&(image)->symhash[2+HASHTABSIZE(image)]) + + +/* + * This macro is non ISO compliant, but a gcc extension + */ +#define FATAL(x,y...) \ + if(x) { \ + printf("rld.so: " y); \ + sys_exit(0); \ + } + + + +static +void +enqueue_image(image_queue_t *queue, image_t *img) +{ + img->next= 0; + + img->prev= queue->tail; + if(queue->tail) { + queue->tail->next= img; + } + queue->tail= img; + if(!queue->head) { + queue->head= img; + } +} + +static +void +dequeue_image(image_queue_t *queue, image_t *img) +{ + if(img->next) { + img->next->prev= img->prev; + } else { + queue->tail= img->prev; + } + + if(img->prev) { + img->prev->next= img->next; + } else { + queue->head= img->next; + } + + img->prev= 0; + img->next= 0; +} + +static +unsigned long +elf_hash(const unsigned char *name) +{ + unsigned long hash = 0; + unsigned long temp; + + while(*name) { + hash = (hash << 4) + *name++; + if((temp = hash & 0xf0000000)) { + hash ^= temp >> 24; + } + hash &= ~temp; + } + return hash; +} + +static +image_t * +find_image(char const *name) +{ + image_t *iter; + + iter= loaded_images.head; + while(iter) { + if(strncmp(iter->name, name, sizeof(iter->name)) == 0) { + return iter; + } + iter= iter->next; + } + + iter= loading_images.head; + while(iter) { + if(strncmp(iter->name, name, sizeof(iter->name)) == 0) { + return iter; + } + iter= iter->next; + } + + return 0; +} + +static +int +parse_eheader(struct Elf32_Ehdr *eheader) +{ + if(memcmp(eheader->e_ident, ELF_MAGIC, 4) != 0) + return ERR_INVALID_BINARY; + + if(eheader->e_ident[4] != ELFCLASS32) + return ERR_INVALID_BINARY; + + if(eheader->e_phoff == 0) + return ERR_INVALID_BINARY; + + if(eheader->e_phentsize < sizeof(struct Elf32_Phdr)) + return ERR_INVALID_BINARY; + + return eheader->e_phentsize*eheader->e_phnum; +} + +static +int +count_regions(char const *buff, int phnum, int phentsize) +{ + int i; + int retval; + struct Elf32_Phdr *pheaders; + + retval= 0; + for(i= 0; i< phnum; i++) { + pheaders= (struct Elf32_Phdr *)(buff+i*phentsize); + + switch(pheaders->p_type) { + case PT_NULL: + /* NOP header */ + break; + case PT_LOAD: + retval+= 1; + if(pheaders->p_memsz!= pheaders->p_filesz) { + unsigned A= pheaders->p_vaddr+pheaders->p_memsz; + unsigned B= pheaders->p_vaddr+pheaders->p_filesz; + + A= PAGE_BASE(A); + B= PAGE_BASE(B); + + if(A!= B) { + retval+= 1; + } + } + break; + case PT_DYNAMIC: + /* will be handled at some other place */ + break; + case PT_INTERP: + /* should check here for appropiate interpreter */ + break; + case PT_NOTE: + /* unsupported */ + break; + case PT_SHLIB: + /* undefined semantics */ + break; + case PT_PHDR: + /* we don't use it */ + break; + default: + FATAL(true, "unhandled pheader type 0x%x\n", pheaders[i].p_type); + break; + } + } + + return retval; +} + + + +/* + * create_image() & destroy_image() + * + * Create and destroy image_t structures. The destroyer makes sure that the + * memory buffers are full of garbage before freeing. + */ +static +image_t * +create_image(char const *name, int num_regions) +{ + image_t *retval; + size_t alloc_size; + + alloc_size= sizeof(image_t)+(num_regions-1)*sizeof(elf_region_t); + + retval= rldalloc(alloc_size); + + memset(retval, 0, alloc_size); + + strlcpy(retval->name, name, sizeof(retval->name)); + retval->imageid= imageid_count; + retval->refcount= 1; + retval->num_regions= num_regions; + + imageid_count+= 1; + + return retval; +} + +static +void +destroy_image(image_t *image) +{ + size_t alloc_size; + + alloc_size= sizeof(image_t)+(image->num_regions-1)*sizeof(elf_region_t); + + memset(image->needed, 0xa5, sizeof(image->needed[0])*image->num_needed); + rldfree(image->needed); + + memset(image, 0xa5, alloc_size); + rldfree(image); +} + + + +static +void +parse_program_headers(image_t *image, char *buff, int phnum, int phentsize) +{ + int i; + int regcount; + struct Elf32_Phdr *pheaders; + + regcount= 0; + for(i= 0; i< phnum; i++) { + pheaders= (struct Elf32_Phdr *)(buff+i*phentsize); + + switch(pheaders->p_type) { + case PT_NULL: + /* NOP header */ + break; + case PT_LOAD: + if(pheaders->p_memsz== pheaders->p_filesz) { + /* + * everything in one area + */ + image->regions[regcount].start = pheaders->p_vaddr; + image->regions[regcount].size = pheaders->p_memsz; + image->regions[regcount].vmstart= _ROUNDOWN(pheaders->p_vaddr, PAGE_SIZE); + image->regions[regcount].vmsize = _ROUNDUP (pheaders->p_memsz + (pheaders->p_vaddr % PAGE_SIZE), PAGE_SIZE); + image->regions[regcount].fdstart= pheaders->p_offset; + image->regions[regcount].fdsize = pheaders->p_filesz; + image->regions[regcount].delta= 0; + image->regions[regcount].flags= 0; + if(pheaders->p_flags & PF_W) { + // this is a writable segment + image->regions[regcount].flags|= RFLAG_RW; + } + } else { + /* + * may require splitting + */ + unsigned A= pheaders->p_vaddr+pheaders->p_memsz; + unsigned B= pheaders->p_vaddr+pheaders->p_filesz; + + A= PAGE_BASE(A); + B= PAGE_BASE(B); + + image->regions[regcount].start = pheaders->p_vaddr; + image->regions[regcount].size = pheaders->p_filesz; + image->regions[regcount].vmstart= _ROUNDOWN(pheaders->p_vaddr, PAGE_SIZE); + image->regions[regcount].vmsize = _ROUNDUP (pheaders->p_filesz + (pheaders->p_vaddr % PAGE_SIZE), PAGE_SIZE); + image->regions[regcount].fdstart= pheaders->p_offset; + image->regions[regcount].fdsize = pheaders->p_filesz; + image->regions[regcount].delta= 0; + image->regions[regcount].flags= 0; + if(pheaders->p_flags & PF_W) { + // this is a writable segment + image->regions[regcount].flags|= RFLAG_RW; + } + + if(A!= B) { + /* + * yeah, it requires splitting + */ + regcount+= 1; + image->regions[regcount].start = pheaders->p_vaddr; + image->regions[regcount].size = pheaders->p_memsz - pheaders->p_filesz; + image->regions[regcount].vmstart= image->regions[regcount-1].vmstart + image->regions[regcount-1].vmsize; + image->regions[regcount].vmsize = _ROUNDUP (pheaders->p_memsz + (pheaders->p_vaddr % PAGE_SIZE), PAGE_SIZE) - image->regions[regcount-1].vmsize; + image->regions[regcount].fdstart= 0; + image->regions[regcount].fdsize = 0; + image->regions[regcount].delta= 0; + image->regions[regcount].flags= RFLAG_ANON; + if(pheaders->p_flags & PF_W) { + // this is a writable segment + image->regions[regcount].flags|= RFLAG_RW; + } + } + } + regcount+= 1; + break; + case PT_DYNAMIC: + image->dynamic_ptr = pheaders->p_vaddr; + break; + case PT_INTERP: + /* should check here for appropiate interpreter */ + break; + case PT_NOTE: + /* unsupported */ + break; + case PT_SHLIB: + /* undefined semantics */ + break; + case PT_PHDR: + /* we don't use it */ + break; + default: + FATAL(true, "unhandled pheader type 0x%x\n", pheaders[i].p_type); + break; + } + } +} + +static +bool +assert_dynamic_loadable(image_t *image) +{ + unsigned i; + + if(!image->dynamic_ptr) { + return true; + } + + for(i= 0; i< image->num_regions; i++) { + if(image->dynamic_ptr>= image->regions[i].start) { + if(image->dynamic_ptr< image->regions[i].start+image->regions[i].size) { + return true; + } + } + } + + return false; +} + +static +bool +map_image(int fd, char const *path, image_t *image, bool fixed) +{ + unsigned i; + + (void)(fd); + + for(i= 0; i< image->num_regions; i++) { + char region_name[256]; + addr load_address; + unsigned addr_specifier; + + sprintf( + region_name, + "%s:seg_%d(%s)", + path, + i, + (image->regions[i].flags&RFLAG_RW)?"RW":"RO" + ); + + if(image->dynamic_ptr && !fixed) { + /* + * relocatable image... we can afford to place wherever + */ + if(i== 0) { + /* + * but only the first segment gets a free ride + */ + load_address= 0; + addr_specifier= REGION_ADDR_ANY_ADDRESS; + } else { + load_address= image->regions[i].vmstart + image->regions[i-1].delta; + addr_specifier= REGION_ADDR_EXACT_ADDRESS; + } + } else { + /* + * not relocatable, put it where it asks or die trying + */ + load_address= image->regions[i].vmstart; + addr_specifier= REGION_ADDR_EXACT_ADDRESS; + } + + if(image->regions[i].flags & RFLAG_ANON) { + image->regions[i].id= sys_vm_create_anonymous_region( + region_name, + (void **)&load_address, + addr_specifier, + image->regions[i].vmsize, + REGION_WIRING_LAZY, + LOCK_RW + ); + + if(image->regions[i].id < 0) { + goto error; + } + image->regions[i].delta = load_address - image->regions[i].vmstart; + image->regions[i].vmstart= load_address; + } else { + image->regions[i].id= sys_vm_map_file( + region_name, + (void **)&load_address, + addr_specifier, + image->regions[i].vmsize, + LOCK_RW, + REGION_PRIVATE_MAP, + path, + _ROUNDOWN(image->regions[i].fdstart, PAGE_SIZE) + ); + if(image->regions[i].id < 0) { + goto error; + } + image->regions[i].delta = load_address - image->regions[i].vmstart; + image->regions[i].vmstart= load_address; + + /* + * handle trailer bits in data segment + */ + if(image->regions[i].flags & RFLAG_RW) { + unsigned start_clearing; + unsigned to_clear; + + start_clearing= + image->regions[i].vmstart + + PAGE_OFFS(image->regions[i].start) + + image->regions[i].size; + to_clear= + image->regions[i].vmsize + - PAGE_OFFS(image->regions[i].start) + - image->regions[i].size; + memset((void*)start_clearing, 0, to_clear); + } + } + } + + if(image->dynamic_ptr) { + image->dynamic_ptr+= image->regions[0].delta; + } + + return true; + +error: + return false; +} + +static +void +unmap_image(image_t *image) +{ + unsigned i; + + for(i= 0; i< image->num_regions; i++) { + sys_vm_delete_region(image->regions[i].id); + + image->regions[i].id= -1; + } +} + +static +bool +parse_dynamic_segment(image_t *image) +{ + struct Elf32_Dyn *d; + int i; + + image->symhash = 0; + image->syms = 0; + image->strtab = 0; + + d = (struct Elf32_Dyn *)image->dynamic_ptr; + if(!d) { + return true; + } + + for(i=0; d[i].d_tag != DT_NULL; i++) { + switch(d[i].d_tag) { + case DT_NEEDED: + image->num_needed+= 1; + break; + case DT_HASH: + image->symhash = (unsigned int *)(d[i].d_un.d_ptr + image->regions[0].delta); + break; + case DT_STRTAB: + image->strtab = (char *)(d[i].d_un.d_ptr + image->regions[0].delta); + break; + case DT_SYMTAB: + image->syms = (struct Elf32_Sym *)(d[i].d_un.d_ptr + image->regions[0].delta); + break; + case DT_REL: + image->rel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta); + break; + case DT_RELSZ: + image->rel_len = d[i].d_un.d_val; + break; + case DT_RELA: + image->rela = (struct Elf32_Rela *)(d[i].d_un.d_ptr + image->regions[0].delta); + break; + case DT_RELASZ: + image->rela_len = d[i].d_un.d_val; + break; + // TK: procedure linkage table + case DT_JMPREL: + image->pltrel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta); + break; + case DT_PLTRELSZ: + image->pltrel_len = d[i].d_un.d_val; + break; + default: + continue; + } + } + + // lets make sure we found all the required sections + if(!image->symhash || !image->syms || !image->strtab) { + return false; + } + + return true; +} + +static +struct Elf32_Sym * +find_symbol_xxx(image_t *img, const char *name) +{ + unsigned int hash; + unsigned int i; + + if(img->dynamic_ptr) { + hash = elf_hash(name) % HASHTABSIZE(img); + for(i = HASHBUCKETS(img)[hash]; i != STN_UNDEF; i = HASHCHAINS(img)[i]) { + if(img->syms[i].st_shndx!= SHN_UNDEF) { + if((ELF32_ST_BIND(img->syms[i].st_info)== STB_GLOBAL) || (ELF32_ST_BIND(img->syms[i].st_info)== STB_WEAK)) { + if(!strcmp(SYMNAME(img, &img->syms[i]), name)) { + return &img->syms[i]; + } + } + } + } + } + + return NULL; +} + +static +struct Elf32_Sym * +find_symbol(image_t **shimg, const char *name) +{ + image_t *iter; + unsigned int hash; + unsigned int i; + + iter= loaded_images.head; + while(iter) { + if(iter->dynamic_ptr) { + hash = elf_hash(name) % HASHTABSIZE(iter); + for(i = HASHBUCKETS(iter)[hash]; i != STN_UNDEF; i = HASHCHAINS(iter)[i]) { + if(iter->syms[i].st_shndx!= SHN_UNDEF) { + if((ELF32_ST_BIND(iter->syms[i].st_info)== STB_GLOBAL) || (ELF32_ST_BIND(iter->syms[i].st_info)== STB_WEAK)) { + if(!strcmp(SYMNAME(iter, &iter->syms[i]), name)) { + *shimg= iter; + return &iter->syms[i]; + } + } + } + } + } + + iter= iter->next; + } + + return NULL; +} + +static +int +resolve_symbol(image_t *image, struct Elf32_Sym *sym, addr *sym_addr) +{ + struct Elf32_Sym *sym2; + char *symname; + image_t *shimg; + + switch(sym->st_shndx) { + case SHN_UNDEF: + // patch the symbol name + symname= SYMNAME(image, sym); + + // it's undefined, must be outside this image, try the other image + sym2 = find_symbol(&shimg, symname); + if(!sym2) { + printf("elf_resolve_symbol: could not resolve symbol '%s'\n", symname); + return ERR_ELF_RESOLVING_SYMBOL; + } + + // make sure they're the same type + if(ELF32_ST_TYPE(sym->st_info)!= STT_NOTYPE) { + if(ELF32_ST_TYPE(sym->st_info) != ELF32_ST_TYPE(sym2->st_info)) { + printf("elf_resolve_symbol: found symbol '%s' in shared image but wrong type\n", symname); + return ERR_ELF_RESOLVING_SYMBOL; + } + } + + if(ELF32_ST_BIND(sym2->st_info) != STB_GLOBAL && ELF32_ST_BIND(sym2->st_info) != STB_WEAK) { + printf("elf_resolve_symbol: found symbol '%s' but not exported\n", symname); + return ERR_ELF_RESOLVING_SYMBOL; + } + + *sym_addr = sym2->st_value + shimg->regions[0].delta; + return B_NO_ERROR; + case SHN_ABS: + *sym_addr = sym->st_value + image->regions[0].delta; + return B_NO_ERROR; + case SHN_COMMON: + // XXX finish this + printf("elf_resolve_symbol: COMMON symbol, finish me!\n"); + return ERR_NOT_IMPLEMENTED_YET; + default: + // standard symbol + *sym_addr = sym->st_value + image->regions[0].delta; + return B_NO_ERROR; + } +} + + +#include "arch/rldreloc.inc" + + +static +image_t * +load_container(char const *path, char const *name, bool fixed) +{ + int fd; + int len; + int ph_len; + char ph_buff[4096]; + int num_regions; + bool map_success; + bool dynamic_success; + image_t *found; + image_t *image; + + struct Elf32_Ehdr eheader; + + found= find_image(name); + if(found) { + found->refcount+= 1; + return found; + } + + fd= sys_open(path, STREAM_TYPE_FILE, 0); + FATAL((fd< 0), "cannot open file %s\n", path); + + len= sys_read(fd, &eheader, 0, sizeof(eheader)); + FATAL((len!= sizeof(eheader)), "troubles reading ELF header\n"); + + ph_len= parse_eheader(&eheader); + FATAL((ph_len<= 0), "incorrect ELF header\n"); + FATAL((ph_len> (int)sizeof(ph_buff)), "cannot handle Program headers bigger than %lu\n", (long unsigned)sizeof(ph_buff)); + + len= sys_read(fd, ph_buff, eheader.e_phoff, ph_len); + FATAL((len!= ph_len), "troubles reading Program headers\n"); + + num_regions= count_regions(ph_buff, eheader.e_phnum, eheader.e_phentsize); + FATAL((num_regions<= 0), "troubles parsing Program headers, num_regions= %d\n", num_regions); + + image= create_image(name, num_regions); + FATAL((!image), "failed to allocate image_t control block\n"); + + parse_program_headers(image, ph_buff, eheader.e_phnum, eheader.e_phentsize); + FATAL(!assert_dynamic_loadable(image), "dynamic segment must be loadable (implementation restriction)\n"); + + map_success= map_image(fd, path, image, fixed); + FATAL(!map_success, "troubles reading image\n"); + + dynamic_success= parse_dynamic_segment(image); + FATAL(!dynamic_success, "troubles handling dynamic section\n"); + + image->entry_point= eheader.e_entry + image->regions[0].delta; + + sys_close(fd); + + enqueue_image(&loaded_images, image); + + return image; +} + + +static +void +load_dependencies(image_t *img) +{ + unsigned i; + unsigned j; + + struct Elf32_Dyn *d; + addr needed_offset; + char path[256]; + + d = (struct Elf32_Dyn *)img->dynamic_ptr; + if(!d) { + return; + } + + img->needed= rldalloc(img->num_needed*sizeof(image_t*)); + FATAL((!img->needed), "failed to allocate needed struct\n"); + memset(img->needed, 0, img->num_needed*sizeof(image_t*)); + + for(i=0, j= 0; d[i].d_tag != DT_NULL; i++) { + switch(d[i].d_tag) { + case DT_NEEDED: + needed_offset = d[i].d_un.d_ptr; + sprintf(path, "/boot/lib/%s", STRING(img, needed_offset)); + img->needed[j]= load_container(path, STRING(img, needed_offset), false); + j+= 1; + + break; + default: + /* + * ignore any other tag + */ + continue; + } + } + + FATAL((j!= img->num_needed), "Internal error at load_dependencies()"); + + return; +} + +static +unsigned +topological_sort(image_t *img, unsigned slot, image_t **init_list) +{ + unsigned i; + + img->flags|= RFLAG_SORTED; /* make sure we don't visit this one */ + for(i= 0; i< img->num_needed; i++) { + if(!(img->needed[i]->flags & RFLAG_SORTED)) { + slot= topological_sort(img->needed[i], slot, init_list); + } + } + + init_list[slot]= img; + return slot+1; +} + +static +void +init_dependencies(image_t *img, bool init_head) +{ + unsigned i; + unsigned slot; + image_t **init_list; + + init_list= rldalloc(loaded_image_count*sizeof(image_t*)); + FATAL((!init_list), "memory shortage in init_dependencies()"); + memset(init_list, 0, loaded_image_count*sizeof(image_t*)); + + img->flags|= RFLAG_SORTED; /* make sure we don't visit this one */ + slot= 0; + for(i= 0; i< img->num_needed; i++) { + if(!(img->needed[i]->flags & RFLAG_SORTED)) { + slot= topological_sort(img->needed[i], slot, init_list); + } + } + + if(init_head) { + init_list[slot]= img; + slot+= 1; + } + + for(i= 0; i< slot; i++) { + addr _initf= init_list[i]->entry_point; + libinit_f *initf= (libinit_f *)(_initf); + + if(initf) { + initf(init_list[i]->imageid, uspa); + } + } + + rldfree(init_list); +} + + +static +void +put_image(image_t *img) +{ + img->refcount-= 1; + if(img->refcount== 0) { + size_t i; + + dequeue_image(&loaded_images, img); + enqueue_image(&disposable_images, img); + + for(i= 0; i< img->num_needed; i++) { + put_image(img->needed[i]); + } + } +} + + +/* + * exported functions: + * + * + load_program() + * + load_library() + * + load_addon() + * + unload_program() + * + unload_library() + * + unload_addon() + * + dynamic_symbol() + */ +dynmodule_id +load_program(char const *path, void **entry) +{ + image_t *image; + image_t *iter; + + + image = load_container(path, NEWOS_MAGIC_APPNAME, true); + + iter= loaded_images.head; + while(iter) { + load_dependencies(iter); + + iter= iter->next; + }; + + iter= loaded_images.head; + while(iter) { + bool relocate_success; + + relocate_success= relocate_image(iter); + FATAL(!relocate_success, "troubles relocating\n"); + + iter= iter->next; + }; + + init_dependencies(loaded_images.head, false); + + *entry= (void*)(image->entry_point); + return image->imageid; +} + +dynmodule_id +load_library(char const *path) +{ + image_t *image; + image_t *iter; + + + image = find_image(path); + if(image) { + image->refcount+= 1; + return image->imageid; + } + + image = load_container(path, path, false); + + iter= loaded_images.head; + while(iter) { + load_dependencies(iter); + + iter= iter->next; + }; + + iter= loaded_images.head; + while(iter) { + bool relocate_success; + + relocate_success= relocate_image(iter); + FATAL(!relocate_success, "troubles relocating\n"); + + iter= iter->next; + }; + + init_dependencies(image, true); + + return image->imageid; +} + +dynmodule_id +unload_library(dynmodule_id imid) +{ + int retval; + image_t *iter; + + /* + * we only check images that have been already initialized + */ + iter= loaded_images.head; + while(iter) { + if(iter->imageid== imid) { + /* + * do the unloading + */ + put_image(iter); + + break; + } + + iter= iter->next; + } + + if(iter) { + retval= 0; + } else { + retval= -1; + } + + iter= disposable_images.head; + while(iter) { + // call image fini here... + + dequeue_image(&disposable_images, iter); + unmap_image(iter); + + destroy_image(iter); + iter= disposable_images.head; + } + + + return retval; +} + +void * +dynamic_symbol(dynmodule_id imid, char const *symname) +{ + image_t *iter; + + /* + * we only check images that have been already initialized + */ + iter= loaded_images.head; + while(iter) { + if(iter->imageid== imid) { + struct Elf32_Sym *sym= find_symbol_xxx(iter, symname); + + if(sym) { + return (void*)(sym->st_value + iter->regions[0].delta); + } + } + + iter= iter->next; + } + + return NULL; +} + +/* + * init routine, just get hold of the uspa args + */ +void +rldelf_init(struct uspace_prog_args_t const *_uspa) +{ + uspa= _uspa; + + rld_sem= create_sem(1, "rld_lock\n"); +} diff --git a/src/kernel/apps/rld/rldheap.c b/src/kernel/apps/rld/rldheap.c new file mode 100644 index 0000000000..f9b85cabc9 --- /dev/null +++ b/src/kernel/apps/rld/rldheap.c @@ -0,0 +1,84 @@ +/* +** Copyright 2002, Manuel J. Petit. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#include +#include +#include "rld_priv.h" + + + +char const * const names[]= +{ + "I'm too sexy!", + "BEWARE OF THE DUCK!", + "B_DONT_DO_THAT", + "I need a girlfriend!", + "assert(C++--!=C)", + "5038 RIP Nov. 2001", + "1.e4 e5 2.Nf3 Nc6 3.Bb5", + "Press any key..." +}; +#define RLD_SCRATCH_SIZE 65536 +#define RLD_PROGRAM_BASE 0x00200000 /* keep in sync with app ldscript */ + + + +static region_id rld_region; +static region_id rld_region_2; +static char *rld_base; +static char *rld_base_2; +static char *rld_ptr; + +void +rldheap_init(void) +{ + rld_region= sys_vm_create_anonymous_region( + (char*)names[sys_get_current_proc_id()%(sizeof(names)/sizeof(names[0]))], + (void**)&rld_base, + REGION_ADDR_ANY_ADDRESS, + RLD_SCRATCH_SIZE, + REGION_WIRING_LAZY, + LOCK_RW + ); + + /* + * Fill in the gap upto RLD_PROGRAM_BASE, + * + * NOTE: this will be required only untile the vm finally + * support REGION_ADDR_ANY_ABOVE and REGION_ADDR_ANY_BELOW. + * Not doing these leads to some funny troubles with some + * libraries. + */ + rld_region_2= sys_vm_create_anonymous_region( + "RLD_padding", + (void**)&rld_base_2, + REGION_ADDR_ANY_ADDRESS, + RLD_PROGRAM_BASE - ((unsigned)(rld_base+RLD_SCRATCH_SIZE)), + REGION_WIRING_LAZY, + LOCK_RW + ); + + rld_ptr= rld_base; +} + +void * +rldalloc(size_t s) +{ + void *retval; + + s= (s+15)&~15; + + retval= rld_ptr; + rld_ptr+= s; + + return retval; +} + +void +rldfree(void *p) +{ + (void)(p); +} + diff --git a/src/kernel/apps/rld/rldunix.c b/src/kernel/apps/rld/rldunix.c new file mode 100644 index 0000000000..14f6f68b0d --- /dev/null +++ b/src/kernel/apps/rld/rldunix.c @@ -0,0 +1,33 @@ +/* +** Copyright 2002, Manuel J. Petit. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#include "rld_priv.h" + +int +export_dl_open(char const *name, unsigned flags) +{ + (void)(name); + (void)(flags); + + return load_library(name); +} + +int +export_dl_close(int lib, unsigned flags) +{ + (void)(flags); + + return unload_library(lib); +} + +void * +export_dl_sym(int lib, char const *sym, unsigned flags) +{ + (void)(lib); + (void)(sym); + (void)(flags); + + return dynamic_symbol(lib, sym); +} diff --git a/src/kernel/apps/shell/Jamfile b/src/kernel/apps/shell/Jamfile new file mode 100644 index 0000000000..238260df13 --- /dev/null +++ b/src/kernel/apps/shell/Jamfile @@ -0,0 +1,12 @@ +SubDir OBOS_TOP sources os kits kernel apps shell ; + +KernelObjects <$(SOURCE_GRIST)>main.c + <$(SOURCE_GRIST)>args.c + <$(SOURCE_GRIST)>commands.c + <$(SOURCE_GRIST)>file_utils.c + <$(SOURCE_GRIST)>parse.c + <$(SOURCE_GRIST)>script.c + <$(SOURCE_GRIST)>shell_vars.c + <$(SOURCE_GRIST)>statements.c + <$(SOURCE_GRIST)>shell_history.c + : -fpic ; diff --git a/src/kernel/apps/shell/args.c b/src/kernel/apps/shell/args.c new file mode 100644 index 0000000000..5a33ac2301 --- /dev/null +++ b/src/kernel/apps/shell/args.c @@ -0,0 +1,59 @@ +//#include +#include +#include +#include +#include + +#include "args.h" +#include "shell_defs.h" +#include "shell_vars.h" + +bool af_exit_after_script; +char *af_script_file_name; + + +static void handle_option(char *option){ + + switch(option[1]){ + case 's':// setup script + if(option[2] == 0){ + af_exit_after_script = false; + } + } + + printf("wrong option : %s \n",option); +} + +void init_arguments(int argc,char **argv){ + + int cnt = 1; + int shell_argc = 0; + char name[255]; + + af_exit_after_script = true; + af_script_file_name = NULL; + + while((cnt < argc) && (argv[cnt][0] == '-')){ + handle_option(argv[cnt]); + cnt++; + } + + if(cnt < argc){ + + af_script_file_name = argv[cnt]; + cnt++; + + while(cnt < argc){ + + sprintf(name,NAME_PAR_PRFX,cnt-1); + shell_var_set_text(name,argv[cnt]); + shell_argc++; + cnt++; + } + + shell_var_set_number(NAME_VAR_ARGC,shell_argc); + + } + + +} diff --git a/src/kernel/apps/shell/args.h b/src/kernel/apps/shell/args.h new file mode 100644 index 0000000000..869de56d4c --- /dev/null +++ b/src/kernel/apps/shell/args.h @@ -0,0 +1,9 @@ +#ifndef _args_h_ +#define _args_h_ + +extern int af_exit_after_script; +extern char *af_script_file_name; + +void init_arguments(int argc,char **argv); + +#endif diff --git a/src/kernel/apps/shell/commands.c b/src/kernel/apps/shell/commands.c new file mode 100644 index 0000000000..56cb77fd36 --- /dev/null +++ b/src/kernel/apps/shell/commands.c @@ -0,0 +1,205 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include + +#include "commands.h" +#include "file_utils.h" +#include "shell_defs.h" + +struct command cmds[] = { + {"exec", &cmd_exec}, + {"stat", &cmd_stat}, + {"mkdir", &cmd_mkdir}, + {"cat", &cmd_cat}, + {"cd", &cmd_cd}, + {"pwd", &cmd_pwd}, + {"help", &cmd_help}, + {NULL, NULL} +}; + +int cmd_exec(int argc, char *argv[]) +{ + return cmd_create_proc(argc - 1,argv+1); +} + +int cmd_create_proc(int argc,char *argv[]) +{ + bool must_wait=true; + proc_id pid; + + int arg_len; + char *tmp; + char filename[SCAN_SIZE+1]; + + if(argc <1){ + printf("not enough args to exec\n"); + return 0; + } + + tmp = argv[argc - 1]; + + if( !find_file_in_path(argv[0],filename,SCAN_SIZE)){ + printf("can't find '%s' \n",argv[0]); + return 0; + } + + + // a hack to support the unix '&' + if(argc >= 1) { + arg_len = strlen(tmp); + if(arg_len > 0){ + tmp += arg_len -1; + if(*tmp == '&'){ + if(arg_len == 1){ + argc --; + } else { + *tmp = 0; + } + must_wait = false; + } + } + } + + pid = sys_proc_create_proc(filename,filename, argv, argc, 5); + if(pid >= 0) { + int retcode; + + if(must_wait) { + sys_proc_wait_on_proc(pid, &retcode); + } + } else { + printf("Error: cannot execute '%s'\n", filename); + return 0; // should be -1, but the shell would exit + } + + return 0; +} + +int cmd_mkdir(int argc, char *argv[]) +{ + int rc; + + if(argc < 2) { + printf("not enough arguments to mkdir\n"); + return 0; + } + + rc = sys_create(argv[1], STREAM_TYPE_DIR); + if (rc < 0) { + printf("sys_mkdir() returned error: %s\n", strerror(rc)); + } else { + printf("%s successfully created.\n", argv[1]); + } + + return 0; +} + +int cmd_cat(int argc, char *argv[]) +{ + int rc; + int fd; + char buf[257]; + + if(argc < 2) { + printf("not enough arguments to cat\n"); + return 0; + } + + fd = sys_open(argv[1], STREAM_TYPE_FILE, 0); + if(fd < 0) { + printf("cat: sys_open() returned error: %s!\n", strerror(fd)); + goto done_cat; + } + + for(;;) { + rc = sys_read(fd, buf, -1, sizeof(buf) -1); + if(rc <= 0) + break; + + buf[rc] = '\0'; + printf("%s", buf); + } + sys_close(fd); + +done_cat: + return 0; +} + +int cmd_cd(int argc, char *argv[]) +{ + int rc; + + if(argc < 2) { + printf("not enough arguments to cd\n"); + return 0; + } + + rc = sys_setcwd(argv[1]); + if (rc < 0) { + printf("cd: sys_setcwd() returned error: %s!\n", strerror(rc)); + } + + return 0; +} + +int cmd_pwd(int argc, char *argv[]) +{ + char buf[257]; + char *rc; + + rc = sys_getcwd(buf,256); + if (rc != NULL) { + printf("cd: sys_getcwd() returned error!\n"); + } + buf[256] = 0; + + printf("%s\n", buf); + + return 0; +} + +int cmd_stat(int argc, char *argv[]) +{ + int rc; + struct stat stat; + + if(argc < 2) { + printf("not enough arguments to stat\n"); + return 0; + } + + rc = sys_rstat(argv[1], &stat); + if(rc >= 0) { + printf("stat of file '%s': \n", argv[1]); + printf("vnid 0x%x\n", (unsigned int)stat.st_ino); +// printf("type %d\n", stat.type); + printf("size %d\n", (int)stat.st_size); + } else { + printf("stat failed for file '%s'\n", argv[1]); + } + return 0; +} + +int cmd_help(int argc, char *argv[]) +{ + printf("command list:\n\n"); + printf("exit : quits this copy of the shell\n"); + printf("exec : load this file as a binary and run it\n"); + printf("mkdir : makes a directory at \n"); + printf("cd : sets the current working directory at \n"); + printf("ls : directory list of . If no path given it lists the current dir\n"); + printf("stat : gives detailed file statistics of \n"); + printf("help : this command\n"); + printf("cat : dumps the file to stdout\n"); + printf("mount : tries to mount at \n"); + printf("unmount : tries to unmount at \n"); + + return 0; +} + + diff --git a/src/kernel/apps/shell/commands.h b/src/kernel/apps/shell/commands.h new file mode 100644 index 0000000000..8621241878 --- /dev/null +++ b/src/kernel/apps/shell/commands.h @@ -0,0 +1,21 @@ +#ifndef _COMMANDS_H +#define _COMMANDS_H + +int cmd_exit(int argc, char *argv[]); +int cmd_exec(int argc, char *argv[]); +int cmd_stat(int argc, char *argv[]); +int cmd_mkdir(int argc, char *argv[]); +int cmd_cat(int argc, char *argv[]); +int cmd_cd(int argc, char *argv[]); +int cmd_pwd(int argc, char *argv[]); +int cmd_help(int argc, char *argv[]); +int cmd_create_proc(int argc,char *argv[]); +typedef int(cmd_handler_proc)(int argc,char *argv[]); + +struct command { + char *cmd_text; + cmd_handler_proc *cmd_handler; +}; + +extern struct command cmds[]; +#endif diff --git a/src/kernel/apps/shell/file_utils.c b/src/kernel/apps/shell/file_utils.c new file mode 100644 index 0000000000..de3969227b --- /dev/null +++ b/src/kernel/apps/shell/file_utils.c @@ -0,0 +1,113 @@ +//#include +#include +#include +#include +#include +#include +#include +#include + +#include "file_utils.h" +#include "statements.h" +#include "shell_defs.h" + +bool combine_path(const char *path1,const char *path2,char *out,unsigned int max_len) +{ + unsigned int cur_len = 0; + + cur_len = strlen(path1); + if(cur_len > max_len) return false; + strcpy(out,path1); + + if(*path1 != 0){ + if(out[cur_len-1] != '/'){ + if(cur_len >= max_len) return false; + out[cur_len] = '/'; + out[cur_len+1] = 0; + cur_len++; + } + } + if(strlen(path2)+cur_len > max_len) return false; + strcat(out,path2); + return true; +} + +bool exists_file(const char *file_name) +{ + int handle = sys_open(file_name,STREAM_TYPE_FILE,0); + bool exists; + exists =( handle >= 0); + if(exists) sys_close(handle); + return exists; +} + +bool find_file_in_path(const char *file_name,char *found_name,unsigned int max_size) +{ + char path[SCAN_SIZE+1]; + int cnt=0; + + if(strchr(file_name,'/') != NULL){ + strncpy(found_name,file_name,max_size); + found_name[max_size] = 0; + if(exists_file(found_name)) return true; + found_name[0] = 0; + return false; + } + while(get_path(cnt,path,SCAN_SIZE)){ + if(combine_path(path,file_name,found_name,max_size)){ + if(exists_file(found_name)) return true; + } + cnt++; + } + found_name[0] =0; + return(false); +} + + +int exec_file(int argc,char *argv[],int *retcode) +{ + char filename[255]; + int pid; + + if( !find_file_in_path(argv[0],filename,SCAN_SIZE)) return SHE_FILE_NOT_FOUND; + + pid = sys_proc_create_proc(filename,filename, argv, argc, 5); + + if(pid < 0) return SHE_CANT_EXECUTE; + + sys_proc_wait_on_proc(pid, retcode); + + return SHE_NO_ERROR; +} + + +int read_file_in_buffer(const char *filename,char **buffer) +{ + struct stat stat; + int file_no; + int err; + int size; + + *buffer = NULL; + + file_no = open(filename, O_RDONLY); + if (file_no < 0){ + return file_no; + } + + err = fstat(file_no,&stat); + if (err < 0) + return err; + + *buffer = malloc(stat.st_size + 1); + if(*buffer == NULL) return ERR_NO_MEMORY; + + size = sys_read(file_no,*buffer,0,stat.st_size); + + sys_close(file_no); + + if (size < 0) + free(*buffer); + + return size; +} diff --git a/src/kernel/apps/shell/file_utils.h b/src/kernel/apps/shell/file_utils.h new file mode 100644 index 0000000000..51de69b7bb --- /dev/null +++ b/src/kernel/apps/shell/file_utils.h @@ -0,0 +1,10 @@ +#ifndef _file_utils_h_ +#define _file_utils_h_ + +bool combine_path(const char *path1,const char *path2,char *out,unsigned int max_len); +bool exists_file(const char *file_name); +bool find_file_in_path(const char *file_name,char *found_name,unsigned int max_size); +int exec_file(int argc,char *argv[],int *retcode); +int read_file_in_buffer(const char *filename,char **buffer); + +#endif diff --git a/src/kernel/apps/shell/main.c b/src/kernel/apps/shell/main.c new file mode 100644 index 0000000000..da6a84eb3e --- /dev/null +++ b/src/kernel/apps/shell/main.c @@ -0,0 +1,98 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#include +#include +#include +#include +#include +#include + +#include "commands.h" +#include "parse.h" +#include "statements.h" +#include "shell_defs.h" +#include "shell_vars.h" +#include "args.h" +#include "shell_history.h" + + +static int readline(char *buf, int len) +{ + int i = 0; + char ch; + + while (true) { + ch = getchar(); + + switch (ch) { + case 27: + // ESC -- used to display command history: + // erase all characters on the current line, + // then display the previously saved command + while (i--) { + printf("\b"); + } + + strcpy (buf, fetch_history_command()); + i = printf("%s", buf); + break; + + case '\b': + // backspace: + // erase the last character written + if (i > 0) { + printf("\b"); + --i; + } + break; + + case '\n': + buf[i] = 0; + store_history_command(buf); + printf("\n"); + return i; + + default: + buf[i] = ch; + printf("%c", ch); + i++; + } + } +} + + +int main(int argc, char *argv[]) +{ + char buf[1024]; + + init_vars(); + init_statements(); + init_arguments(argc, argv); + + if (af_script_file_name) { + run_script(af_script_file_name); + if (af_exit_after_script) + sys_exit(0); + } + + printf("Welcome to the OpenBeOS shell\n"); + + for (;;) { + int chars_read; + + printf("$ "); + + chars_read = readline(buf, sizeof(buf)); + if (chars_read > 0) { + parse_string(buf); + } + } + + printf("shell exiting\n"); + return 0; +} + + diff --git a/src/kernel/apps/shell/parse.c b/src/kernel/apps/shell/parse.c new file mode 100644 index 0000000000..2dd9fa2de8 --- /dev/null +++ b/src/kernel/apps/shell/parse.c @@ -0,0 +1,585 @@ +#include +#include +#include +#include +#include + +#include "parse.h" +#include "commands.h" +#include "shell_defs.h" +#include "shell_vars.h" +#include "script.h" + + + +struct token_info{ + char *token; + int code; +}; + +struct token_info tokens[]={ +{"echo",SVO_ECHO}, +{"exec",SVO_EXEC}, +{"exit",SVO_EXIT}, +{"if",SVO_IF}, +{"goto",SVO_GOTO}, +{"number",SVO_NUMBER_CAST}, +{"string",SVO_STRING_CAST}, +{"+",SVO_ADD}, +{"-",SVO_SUB}, +{"*",SVO_MUL}, +{"/",SVO_DIV}, +{"=",SVO_LOAD}, +{"==",SVO_EQUAL}, +{"!=",SVO_NOT_EQUAL}, +{">",SVO_BIGGER}, +{">=",SVO_BIGGER_E}, +{"<",SVO_LESS}, +{"<=",SVO_LESS_E}, +{"$",SVO_DOLLAR}, +{",",SVO_COMMA}, +{"(",SVO_PARENL}, +{")",SVO_PARENR}, +{":",SVO_DOTDOT}, +{NULL,SVO_NONE} +}; + + +static int token_to_id(const char *token) +{ + int cnt = 0; + + while((tokens[cnt].token != NULL) && (strcmp(tokens[cnt].token,token) != 0)) cnt++; + + return tokens[cnt].code; +} + +char *id_to_token(int id) +{ + int cnt = 0; + + switch(id){ + + case SVO_IDENT :return "ident"; + case SVO_SQ_STRING : + case SVO_DQ_STRING :return "string"; + case SVO_NUMBER :return "number"; + case SVO_END :return "end"; + } + + while((tokens[cnt].token != NULL) && (tokens[cnt].code != id)) cnt++; + + if(tokens[cnt].token != NULL){ + + return tokens[cnt].token; + + } else { + + return "unkown"; + + } +} + +static bool scan_string(scan_info *info,int max_len) +{ + const char **in=&(info->scanner); + char ch=**in; + char *scan=info->token; + int len_cnt = max_len; + bool err = false; + + (*in)++; + + while((**in != 0) && (**in != ch)){ + + if(len_cnt > 0){ + + *scan = **in; + scan++; + len_cnt--; + + } + + (*in)++; + + } + + if(**in != 0) { + (*in)++; + } else { + info->scan_error = SHE_MISSING_QOUTE; + err = true; + } + + *scan = 0; + return err; +} + + + +int parse_line(const char *buf, char *argv[], int max_args, char *redirect_in, char *redirect_out) +{ + const char *scan=buf; + const char *type_char; + const char *start; + char out[SCAN_SIZE+1]; + char tmp[SCAN_SIZE+1]; + char *arg_tmp; + int arg_cnt = 0; + int len = 0; + bool replace; + bool param; + redirect_in[0] = 0; + redirect_out[0] = 0; + + while(true){ + + while((*scan != 0) && (isspace(*scan))) scan++; + + if(*scan == 0) break; + + replace = true; + type_char = scan; + start = scan; + param = true; + + switch(*type_char){ + case '\'': + replace = false; + + case '"': + scan++; + start++; + while((*scan != 0) && (*scan != *start)) scan++; + break; + + case '>': + case '<': + start++; + while((*start != 0) && (isspace(*start))) start++; + scan = start; + + default: + + while((*scan != 0) && (!isspace(*scan))) scan++; + + } + + len = scan - start; + if(*scan != 0) scan++; + + if(replace){ + + memcpy(tmp,start,len); + tmp[len]=0; + parse_vars_in_string(tmp,out,SCAN_SIZE); + + } else { + + memcpy(out,start,len); + out[len]=0; + + } + + switch(*type_char){ + + case '>': + strcpy(redirect_out,out); + break; + + case '<': + strcpy(redirect_in,out); + break; + + default: + if(arg_cnt < max_args){ + + arg_tmp = shell_strdup(out); + if(arg_tmp != NULL) argv[arg_cnt++] = arg_tmp; + + } + + } + } + + return arg_cnt; +} + + + +static void scan_ident(const char **in,char *out,int max_len) +{ + char *scan = out; + int len_cnt = max_len; + + while ((**in != 0) && (IS_IDENT_CHAR(**in))){ + if(len_cnt > 0){ + *scan = **in; + scan++; + len_cnt--; + } + (*in)++; + } + *scan = 0; +} + +static void scan_number(const char **in,char *out,int max_len) +{ + char *scan = out; + int len_cnt = max_len; + + while ( (**in != 0) && (isdigit(**in)) ){ + + if(len_cnt > 0){ + + *scan = **in; + scan++; + len_cnt--; + + } + + (*in)++; + + } + *scan = 0; +} + + +static void scan_comp(const char **in,char *out,int max_len) +{ + int num_cnt = max_len; + char *out_scan = out; + + *out_scan = **in; + out_scan++; + (*in)++; + num_cnt--; + + if(num_cnt > 0) { + + if(**in == '='){ + + *out_scan = **in; + out_scan++; + (*in)++; + num_cnt--; + + } + } + *out_scan = 0; +} + +bool expect(scan_info *info,int check) +{ + if(info->sym_code == check){ + + scan(info); + return false; + + } else { + + return true; + + } +} + + +bool scan_info_next_line(scan_info *info) +{ + if(info->current == NULL) return false; + + info->current = info->current->next; + + if(info->current == NULL) return false; + + info->line_no++; + + return set_scan_info_line(info); +} + +bool scan_info_home(scan_info *info) +{ + info->current = info->data.list; + info->line_no = 1; + return set_scan_info_line(info); +} + + +bool init_scan_info_by_file(const char *file_name,scan_info *info) +{ + int err = SHE_NO_ERROR; + + err = read_text_file(file_name,&(info->data)); + + if(err != SHE_NO_ERROR) return err; + + info->scanner = NULL; + info->scan_error = SHE_NO_ERROR; + + if(scan_info_home(info)) err = SHE_SCAN_ERROR; + + return err; + +} + +bool set_scan_info_line(scan_info *info) +{ + + if(info->current == NULL) return true; + + strcpy(info->input_line,info->current->text); + info->scanner = (info->input_line); + return scan(info); + +} + +// fetch next token +// **in scan string +// *out token +// return token type (STY_<> vars) + + +void init_scan_info(const char*in,scan_info *info){ + + strncpy(info->input_line,in,SCAN_SIZE); + + info->input_line[SCAN_SIZE] = 0; + info->scanner=(const char*)info->input_line; + info->scan_error = SHE_NO_ERROR; + info->current = NULL; + info->line_no = 1; + + scan(info); + +} + +bool scan(scan_info *info) +{ + bool err = false; + int sym_code = SVO_NONE; + const char **in = &(info->scanner); + char tmp[SCAN_SIZE+1]; + + while((**in != 0) && (isspace(**in))) (*in)++; + + if(isalpha(**in)){ + + scan_ident(in,info->token,SCAN_SIZE); + + sym_code = token_to_id(info->token); + if(sym_code == SVO_NONE) sym_code = SVO_IDENT; + + } else if(isdigit(**in)){ + + scan_number(in,info->token,SCAN_SIZE); + sym_code = SVO_NUMBER; + } else{ + switch(**in){ + case '#': + sym_code = SVO_END; + break; + case '>': + case '<': + case '=': + case '!': + + scan_comp(in,info->token,SCAN_SIZE); + break; + + case '"': + + err = scan_string(info,SCAN_SIZE); + + if(err != SHE_NO_ERROR){ + parse_vars_in_string(info->token,tmp,SCAN_SIZE); + strncpy(info->token,tmp,SCAN_SIZE); + info->token[SCAN_SIZE] = 0; + } + + sym_code = SVO_DQ_STRING; + break; + case '\'': + + sym_code = SVO_SQ_STRING; + err =scan_string(info,SCAN_SIZE); + break; + case 0: + + *(info->token) = 0; + sym_code = SVO_END; + break; + default: + info->token[0] = **in; + info->token[1] = 0; + (*in)++; + break; + + } + if(sym_code == SVO_NONE) sym_code = token_to_id(info->token); + + } + + info->sym_code = sym_code; + + return err; +} + +void parse_vars_in_string(const char *string,char *out,int max_len) +{ + const char *scan= string; + char buf[SCAN_SIZE + 1]; + char *dest; + char *out_scan = out; + shell_value *value; + int out_len = 0; + int len_cnt; + int out_max_len= max_len; + int can_move; + char *text; + + while((*scan != 0) && (*scan != '\'') && (out_max_len > 0)){ + if(*scan == '$'){ + scan++; + dest = buf; + len_cnt = SCAN_SIZE; + + while ((*scan != 0) && (IS_IDENT_CHAR(*scan)) &&(len_cnt > 0)){ + + *dest = *scan; + dest++; + scan++; + len_cnt--; + + } + + *dest = 0; + value = get_value_by_name(buf); + + if(value != NULL){ + + text = shell_value_to_char(value); + can_move = strlen(text); + + if(can_move > out_max_len) can_move = out_max_len; + + memcpy(out_scan,text,can_move); + out_max_len -= can_move; + out_scan += can_move; + + free(text); + + } + + } else{ + + *out_scan = *scan; + out_len++; + out_scan++; + scan ++; + out_max_len--; + + } + } + *out_scan= 0; +} + + + + +static int launch(int (*cmd)(int, char **), int argc, char **argv, char *r_in, char *r_out) +{ + int saved_in; + int saved_out; + int new_in; + int new_out; + int retval= 0; + int err; + + if(strcmp(r_in, "")!= 0) { + new_in = sys_open(r_in, STREAM_TYPE_ANY, 0); + if(new_in < 0) { + new_in = sys_create(r_in,STREAM_TYPE_FILE); + } + } else { + new_in = sys_dup(0); + } + if(new_in < 0) { + err = new_in; + goto err_1; + } + + if(strcmp(r_out, "")!= 0) { + new_out = sys_open(r_out, STREAM_TYPE_ANY, 0); + if(new_out < 0){ + new_out = sys_create(r_out,STREAM_TYPE_FILE); + } + } else { + new_out = sys_dup(1); + } + if(new_out < 0) { + err = new_out; + goto err_2; + } + + + saved_in = sys_dup(0); + saved_out= sys_dup(1); + + sys_dup2(new_in, 0); + sys_dup2(new_out, 1); + sys_close(new_in); + sys_close(new_out); + + retval= cmd(argc, argv); + + sys_dup2(saved_in, 0); + sys_dup2(saved_out, 1); + sys_close(saved_in); + sys_close(saved_out); + + return 0; + +err_2: + sys_close(new_in); +err_1: + return err; +} + + +int shell_parse(const char *buf, int len) +{ + int i; +// bool found_command = false; + int argc; + char *argv[64]; + char redirect_in[256]; + char redirect_out[256]; + cmd_handler_proc *handler = NULL; + int cnt; + int err; + + // search for the command + argc = parse_line(buf, argv, 64, redirect_in, redirect_out); + + if(argc == 0) return 0; + + handler = &cmd_create_proc; + + for(i=0; cmds[i].cmd_handler != NULL; i++) { + if(strcmp(cmds[i].cmd_text,argv[0]) == 0){ + handler = cmds[i].cmd_handler; + break; + } + } + + err = launch(handler, argc, argv, redirect_in, redirect_out); + + for(cnt = 0;cnt +#include +#include +#include +#include +#include + +#include "statements.h" +#include "file_utils.h" +#include "shell_defs.h" +#include "script.h" +#include "parse.h" +#include "statements.h" + +static int add_string_to_list(text_file *data,char *text) +{ + text_item *item; + + item = malloc(sizeof(text_item)); + if(item == NULL) return SHE_NO_MEMORY; + + item->text = text; + item->next = NULL; + + if(data->top != NULL) data->top->next = item; + if(data->list == NULL) data->list = item; + + data->top = item; + + return SHE_NO_ERROR; +} + +void free_text_file(text_file *data) +{ + text_item *current; + text_item *next; + + current = data->list; + + while(current != NULL){ + + next = current->next; + free(current); + current = next; + + } + + free(data->buffer); + data->buffer = NULL; + data->list = NULL; + data->top = NULL; +} + + +int read_text_file(const char *filename,text_file *data) +{ + char *scan; + char *old; + int err; + int size; + char realfilename[256]; + + if( !find_file_in_path(filename,realfilename,SCAN_SIZE)){ + + printf("can't find '%s' \n",filename); + return SHE_FILE_NOT_FOUND; + + } + + size = read_file_in_buffer(realfilename,&(data->buffer)); + + if(size < 0) return size; + + scan = data->buffer; + data->top = NULL; + data->list = NULL; + + while(size >0){ + + err = add_string_to_list(data, scan); + if(err <0) goto err; + + old = scan; + + while((size > 0) && (*scan != 10)) { + scan++; + size--; + } + + *scan=0; + scan++; + size--; + } + return B_NO_ERROR; +err: + printf("error\n"); + free_text_file(data); + return err; +} + + +int run_script(const char *file_name) +{ + scan_info info; + int err = init_scan_info_by_file(file_name,&info); + if(err != SHE_NO_ERROR) return err; + + while(info.current != NULL){ + + err = parse_info(&info); + if(err != SHE_NO_ERROR) break; + + if(scan_info_next_line(&info)) { + err = SHE_SCAN_ERROR; + break; + } + + } + +//err: + free_text_file(&(info.data)); + return err; +} + diff --git a/src/kernel/apps/shell/script.h b/src/kernel/apps/shell/script.h new file mode 100644 index 0000000000..e4f1b8b20a --- /dev/null +++ b/src/kernel/apps/shell/script.h @@ -0,0 +1,27 @@ +#ifndef _script_h_ + +#define _script_h_ + +#include + +struct _text_item{ + struct _text_item *next; + char *text; +}; + +typedef struct _text_item text_item; + + +struct _text_file{ + char *buffer; + text_item *list; + text_item *top; +}; + +typedef struct _text_file text_file; + + +int read_text_file(const char *filename,text_file *data); +void free_text_file(text_file *data); +int run_script(const char *file_name); +#endif diff --git a/src/kernel/apps/shell/shell_defs.h b/src/kernel/apps/shell/shell_defs.h new file mode 100644 index 0000000000..19371d3db5 --- /dev/null +++ b/src/kernel/apps/shell/shell_defs.h @@ -0,0 +1,70 @@ +#ifndef _shell_defs_h_ +#define _shell_defs_h_ + +#include "script.h" + +#define NAME_VAR_PATH "path" +#define NAME_VAR_ARGC "argc" +#define NAME_PAR_PRFX "p%d" + +#define SVO_ADD 0 +#define SVO_SUB 1 +#define SVO_MUL 2 +#define SVO_DIV 3 +#define SVO_BIGGER 4 +#define SVO_EQUAL 5 +#define SVO_LESS 6 +#define SVO_LESS_E 7 +#define SVO_BIGGER_E 8 +#define SVO_NOT_EQUAL 9 +#define SVO_PARENL 10 +#define SVO_PARENR 11 +#define SVO_COMMA 12 +#define SVO_LOAD 13 +#define SVO_EXEC 14 +#define SVO_ECHO 15 +#define SVO_DOLLAR 16 +#define SVO_IDENT 17 +#define SVO_SQ_STRING 18 +#define SVO_DQ_STRING 19 +#define SVO_NUMBER 20 +#define SVO_CHAR 21 +#define SVO_END 22 +#define SVO_NONE 23 +#define SVO_EXIT 24 +#define SVO_IF 25 +#define SVO_DOTDOT 26 +#define SVO_GOTO 27 +#define SVO_NUMBER_CAST 28 +#define SVO_STRING_CAST 29 +#define SVO_MAX 30 + +#define SHE_NO_ERROR 0 // no error +#define SHE_NO_MEMORY SVO_MAX+2 // not enough memory +#define SHE_PARSE_ERROR SVO_MAX+3 // parse error +#define SHE_FILE_NOT_FOUND SVO_MAX+4 +#define SHE_CANT_EXECUTE SVO_MAX+5 +#define SHE_INVALID_TYPE SVO_MAX+6 +#define SHE_INVALID_NUMBER SVO_MAX+7 +#define SHE_INVALID_OPERATION SVO_MAX+8 +#define SHE_SCAN_ERROR SVO_MAX+9 +#define SHE_MISSING_QOUTE SVO_MAX+10 +#define SHE_LABEL_NOT_FOUND SVO_MAX+11 + + +#define SCAN_SIZE 255 // size of output strings in parser + +struct _scan_info{ + char input_line[SCAN_SIZE+1]; + char token[SCAN_SIZE+1]; + const char *scanner; + int sym_code; + int scan_error; + int line_no; + text_item *current; + text_file data; +}; + +typedef struct _scan_info scan_info; + +#endif diff --git a/src/kernel/apps/shell/shell_history.c b/src/kernel/apps/shell/shell_history.c new file mode 100644 index 0000000000..c3aae76388 --- /dev/null +++ b/src/kernel/apps/shell/shell_history.c @@ -0,0 +1,69 @@ +#include +#include + +#include "shell_history.h" + + + +static char Table[MAX_HISTORY_DEPTH][120]; // holds MAX_HISTORY_DEPTH slots + // each slot up to 120 chars long + +static int NumEntries = 0; // current number of filled entries in Table +static int Slot = 0; // index of next slot in Table to look at + + + + +void store_history_command(char *cmd_string) +{ + // store the command string in the next available slot + + char *next = Table[0]; + int i; + + // find the next empty slot (if there is one) + // + for (i = 0; i < MAX_HISTORY_DEPTH; ++i) { + + if (Slot == MAX_HISTORY_DEPTH) + // wrap around + Slot = 0; + + next = Table[Slot++]; + if (*next == '\0') + // found empty slot + break; + } + + // copy in the command string + strcpy (next, cmd_string); + + + // update count + ++NumEntries; + if (NumEntries > MAX_HISTORY_DEPTH) + NumEntries = MAX_HISTORY_DEPTH; +} + + +char *fetch_history_command(void) +{ + // fetch the previous command string + + char *prev = ""; + int i; + + for (i = 0; i < NumEntries; ++i) { + + if (Slot == 0) + // wrap around + Slot = NumEntries; + + prev = Table[--Slot]; + if (*prev) + // found non-blank entry + break; + } + + return prev; +} diff --git a/src/kernel/apps/shell/shell_history.h b/src/kernel/apps/shell/shell_history.h new file mode 100644 index 0000000000..820789a065 --- /dev/null +++ b/src/kernel/apps/shell/shell_history.h @@ -0,0 +1,16 @@ +#ifndef _SHELL_HISTORY_H_ +#define _SHELL_HISTORY_H_ + + +// you can store up to this many commands in the history table + +#define MAX_HISTORY_DEPTH 20 + + +// the only two history operations: + +void store_history_command(char *cmd_string); +char *fetch_history_command(void); + + +#endif diff --git a/src/kernel/apps/shell/shell_vars.c b/src/kernel/apps/shell/shell_vars.c new file mode 100644 index 0000000000..07285c4f76 --- /dev/null +++ b/src/kernel/apps/shell/shell_vars.c @@ -0,0 +1,372 @@ +//#include +#include +#include +#include +#include +#include + +#include "shell_vars.h" +#include "statements.h" +#include "shell_defs.h" + + +struct _shell_var{ + struct _shell_var *next; + char *name; + shell_value *value; +} +; + +typedef struct _shell_var shell_var; + +static shell_var *var_list; + +char *shell_strdup(const char *some_str) +{ + char *result; + + result = malloc(strlen(some_str) + 1); + + if(result != NULL){ + strcpy(result,some_str); + } + + return result; +} + +bool string_to_long_int(const char *str,long int *out) +{ + const char *scanner = str; + bool do_neg = false; + + *out = 0; + + if(*scanner == '-'){ + do_neg = true; + scanner++; + } + + while ((*scanner != 0) && (isdigit(*scanner))){ + + (*out) = (*out)*10 + (*scanner)-48; + scanner++; + + } + + if(do_neg) *out = -(*out); + + return (*scanner != 0); +} + +void shell_value_free(shell_value *value) +{ + if(!value->isnumber) free(value->value.val_text); + free(value); +} + + +char *shell_value_to_char(shell_value *value) +{ + if(value->isnumber){ + char tmp[255]; + sprintf(tmp,"%ld",value->value.val_number); + return shell_strdup(tmp); + } else { + return shell_strdup(value->value.val_text); + } +} + +int shell_value_to_number(shell_value *value,long int *number) +{ + if(value->isnumber){ + *number = value->value.val_number; + return SHE_NO_ERROR; + } else { + return string_to_long_int(value->value.val_text,number); + } +} + +int shell_value_get_text(shell_value * value,char **text){ + if(value->isnumber) return SHE_INVALID_TYPE; + *text = value->value.val_text; + return SHE_NO_ERROR; +} + +int shell_value_get_number(shell_value *value,long int *number) +{ + if(!value->isnumber) return SHE_INVALID_TYPE; + *number = value->value.val_number; + return SHE_NO_ERROR; +} + +/* XXX - unused and static +static void shell_var_free(shell_var *var) +{ + shell_value_free(var->value); + free(var->name); + free(var); +} +*/ + +shell_value *shell_value_init_number(long int value) +{ + shell_value *current; + + current = malloc(sizeof(shell_value)); + if(current == NULL) return NULL; + + current->isnumber = true; + current->value.val_number = value; + + return current; +} + + +shell_value *shell_value_init_text(const char *value) +{ + shell_value *current; + + current = malloc(sizeof(shell_value)); + if(current == NULL) goto err; + + current->value.val_text = shell_strdup(value); + if(current->value.val_text == NULL) goto err1; + + current->isnumber = false; + + return current; +err1: + free(current); +err: + return NULL; +} + + +int shell_value_set_text(shell_value *value,const char *new_value) +{ + char *val = shell_strdup(new_value); + if(val == NULL) return SHE_NO_MEMORY; + + if(!value->isnumber) free(value->value.val_text); + + value->value.val_text = val; + value->isnumber = false; + + return SHE_NO_ERROR; +} + +int shell_value_set_number(shell_value *value,long int new_value) +{ + if(!value->isnumber) free(value->value.val_text); + + value->value.val_number = new_value; + value->isnumber = true; + + return SHE_NO_ERROR; +} + + + +shell_value *shell_value_clone(shell_value *var) +{ + if(var->isnumber){ + return shell_value_init_number(var->value.val_number); + } else { + return shell_value_init_text(var->value.val_text); + } +} + + + + + + +int shell_value_neg(shell_value *out) +{ + long int value; + int err; + + err = shell_value_get_number(out,&value); + if(err != SHE_NO_ERROR) return err; + + err = shell_value_set_number(out,-value); + return err; +} + + +// out = out .op. out + +int shell_value_do_operation(shell_value *out,const shell_value *other,int oper_type) +{ + long int i1; + long int i2; + long int i3; + int err; + + if(out->isnumber != other->isnumber) return SHE_INVALID_TYPE; + if(out->isnumber){ + + i1 = out->value.val_number; + i2 = other->value.val_number; + printf("%ld %ld %d",i1,i2,oper_type); + switch(oper_type){ + case SVO_ADD : i3 = i1+i2 ;break; + case SVO_SUB : i3 = i1-i2 ;break; + case SVO_MUL : i3 = i1*i2 ;break; + case SVO_DIV : i3 = i1/i2 ;break; + case SVO_BIGGER : i3 = i1>i2 ;break; + case SVO_LESS : i3 = i1=i2 ;break; + case SVO_LESS_E : i3 = i1 <= i2 ;break; + case SVO_NOT_EQUAL : i3 = i1 != i2 ;break; + default: return SHE_INVALID_OPERATION; + } + + } else { + + i1 = strcmp(out->value.val_text,other->value.val_text); + + switch(oper_type){ + case SVO_EQUAL : i3 = i1 == 0;break; + case SVO_BIGGER : i3 = i1 > 0;break; + case SVO_LESS : i3 = i1 < 0;break; + case SVO_BIGGER_E : i3 = i1 >= 0;break; + case SVO_LESS_E : i3 = i1 <= 0;break; + case SVO_NOT_EQUAL: i3 = i1 != 0;break; + default : return SHE_INVALID_OPERATION; + } + } + + err = shell_value_set_number(out,i3); + return err; +} + + +// +// init shell var +// + +static shell_var *shell_var_init_value(const char *name,shell_value *value) +{ + shell_var *current; + + current = malloc(sizeof(shell_var)); + if(current == NULL) goto err; + + current->name = shell_strdup(name); + if(current->name == NULL) goto err2; + + current->value = value; + + return current; + + free(current->name); +err2: + free(current); +err: + return NULL; +} + + + + +// +// Add shell variable +// + +static int shell_var_add(const char *var_name,shell_value *value) +{ + shell_var *current; + + current = shell_var_init_value(var_name,value); + + current->next = var_list; + var_list = current; + + return SHE_NO_ERROR; + + free(current->name); + + free(current); + return SHE_NO_MEMORY; +} + + +static shell_var * find_shell_var_by_name(const char *name) +{ + shell_var *current; + + current = var_list; + + while((current != NULL) && (strcmp(current->name,name) != 0)) current = current->next; + + return current; +} + + + + + +static int shell_var_set(const char *var_name,shell_value *value) +{ + shell_var *current; + + current = find_shell_var_by_name(var_name); + + if(current == NULL){ + + return shell_var_add(var_name,value); + + } + + shell_value_free(current->value); + current->value = value; + + return SHE_NO_ERROR; +} + +int shell_var_set_number(const char *var_name,long int number) +{ + shell_value *value; + + value = shell_value_init_number(number); + if(value == NULL) return SHE_NO_MEMORY; + + return shell_var_set(var_name,value); +} + + +int shell_var_set_text(const char *var_name,const char *text) +{ + shell_value *value; + + value = shell_value_init_text(text); + if(value == NULL) return SHE_NO_MEMORY; + + return shell_var_set(var_name,value); +} + + + +int set_shell_var_with_value(const char *var_name,shell_value *value) +{ + return shell_var_set(var_name,shell_value_clone(value)); +} + +shell_value *get_value_by_name(const char *name) +{ + shell_var *current; + shell_value *result = NULL; + + current = find_shell_var_by_name(name); + + if(current != NULL) result = current->value; + + return result; +} + + +void init_vars(void){ + var_list = NULL; +} diff --git a/src/kernel/apps/shell/shell_vars.h b/src/kernel/apps/shell/shell_vars.h new file mode 100644 index 0000000000..10f4479332 --- /dev/null +++ b/src/kernel/apps/shell/shell_vars.h @@ -0,0 +1,45 @@ +#ifndef _shell_var_h_ +#define _shell_vars_h_ + +//#include + +struct _shell_value{ + bool isnumber; + union{ + char *val_text; + long int val_number; + } value; +}; + +typedef struct _shell_value shell_value; + +char *shell_strdup(const char *some_str); +shell_value *get_value_by_name(const char *name); + +int shell_var_set_number(const char *var_name,long int number); +int shell_var_set_text(const char *var_name,const char *text); + +int set_shell_var_with_value(const char *var_name,shell_value *value); + +void init_vars(void); + + +void shell_value_free(shell_value *value); +int shell_value_do_operation(shell_value *out,const shell_value *other,int oper_type); +int shell_value_neg(shell_value *out); +char *shell_value_to_char(shell_value *value); +shell_value *shell_value_init_number(long int value); +shell_value *shell_value_init_text(const char *value); +int shell_value_to_number(shell_value *value,long int *number); +int shell_value_set_text(shell_value *value,const char *new_value); +int shell_value_set_number(shell_value *value,long int new_value); +int shell_value_get_number(shell_value *value,long int *number); +int shell_value_get_text(shell_value * value,char **text); +shell_value *shell_value_clone(shell_value *var); + + +bool string_to_long_int(const char *str,long int *out); + + +#endif + diff --git a/src/kernel/apps/shell/statements.c b/src/kernel/apps/shell/statements.c new file mode 100644 index 0000000000..8826a3ee9f --- /dev/null +++ b/src/kernel/apps/shell/statements.c @@ -0,0 +1,767 @@ +#include +#include +#include +#include +#include + +#include "parse.h" +#include "statements.h" +#include "shell_vars.h" +#include "shell_defs.h" +#include "file_utils.h" + +static bool parse_value(scan_info *info,shell_value **out); +static int handle_exec(scan_info *info,shell_value **out); +static int parse_rvl_expr(scan_info *info,shell_value **out); + +struct _oper_level{ + int sym_code; + int level; + +}; + +typedef struct _oper_level oper_level; + +#define MAX_LEVEL 3 + +oper_level oper_levels[]= +{{SVO_EQUAL,3} +,{SVO_LESS,3} +,{SVO_LESS_E,3} +,{SVO_BIGGER,3} +,{SVO_BIGGER_E,3} +,{SVO_NOT_EQUAL,3} +,{SVO_ADD,2} +,{SVO_SUB,2} +,{SVO_MUL,1} +,{SVO_DIV,1} +,{0,-1} +}; + + +static int get_oper_level(int oper) +{ + int cnt = 0; + while((oper_levels[cnt].level != 0) && (oper_levels[cnt].sym_code != oper)) cnt++; + return oper_levels[cnt].level; +} + + +static int parse_neg(scan_info *info,shell_value **out) +{ + int err; + bool do_neg = false; + + if(info->sym_code == SVO_SUB){ + + do_neg = true; + if(scan(info)) return SHE_SCAN_ERROR; + + } + + err = parse_value(info,out); + if(err != SHE_NO_ERROR) return err; + + if(do_neg){ + + err = shell_value_neg(*out); + if(err != SHE_NO_ERROR) { + + shell_value_free(*out); + *out = NULL; + + } + + } + + return err; +} + + +static int parse_oper(scan_info *info,shell_value **out,int level) +{ + int err; + int oper_code; + shell_value *other; + + + if(level > 1){ + + err = parse_oper(info,out,level - 1); + + } else { + + err = parse_neg(info,out); + + } + + + if(err != SHE_NO_ERROR) return err; + + + oper_code = info->sym_code; + + while(get_oper_level(info->sym_code) == level){ + + if(scan(info)){ + + err = SHE_SCAN_ERROR; + goto err; + + } + + if(level > 1){ + + err = parse_oper(info,&other,level - 1); + + } else { + + err = parse_neg(info,&other); + + } + + if(err != SHE_NO_ERROR) goto err; + + err = shell_value_do_operation(*out,other,oper_code); + if(err != SHE_NO_ERROR) goto err_2; + + shell_value_free(other); + + } + + return SHE_NO_ERROR; + +err_2: + shell_value_free(other); + +err: + shell_value_free(*out); + *out = NULL; + return err; + +} + + +static int parse_expression(scan_info *info,shell_value **out) +{ + (*out) = NULL; + return parse_oper(info,out,MAX_LEVEL); +} + + +static int parse_cast(scan_info * info,shell_value **out) +{ + int err; + long int dummy; + char *text; + bool to_number = info->sym_code == SVO_NUMBER_CAST; + + if(scan(info)) return SHE_SCAN_ERROR; + + + err = parse_rvl_expr(info,out); + if(err != SHE_NO_ERROR) return err; + +//place cast in shell_vars=>change type direct + + if(to_number){ + + err = shell_value_to_number(*out,&dummy); + if(err != SHE_NO_ERROR) goto err; + + err = shell_value_set_number(*out,dummy); + if(err != SHE_NO_ERROR) goto err; + + } else { + + text = shell_value_to_char(*out); + + err = shell_value_set_text(*out,text); + + free(text); + + } + return SHE_NO_ERROR; + +err: + + shell_value_free(*out); + *out = NULL; + + return err; +} + +static int parse_value(scan_info *info,shell_value **out) +{ + char buf2[SCAN_SIZE+1]; + int err = SHE_NO_ERROR; + long int val; + shell_value *value; + + *out = NULL; + + switch(info->sym_code){ + + case SVO_DQ_STRING: + + parse_vars_in_string(info->token,buf2,SCAN_SIZE); + *out = shell_value_init_text(buf2); + break; + + case SVO_NUMBER: + err = string_to_long_int(info->token,&val); + if(err == SHE_NO_ERROR) *out = shell_value_init_number(val); + break; + + case SVO_SQ_STRING: + + *out = shell_value_init_text(info->token); + break; + + case SVO_EXEC : + err = handle_exec(info,out); + break; + + case SVO_NUMBER_CAST: + case SVO_STRING_CAST: + err = parse_cast(info,out); + break; + + case SVO_PARENL: + err = parse_rvl_expr(info,out); + if(err) return err; + + break; + + + case SVO_DOLLAR: + if(scan(info)) return SHE_SCAN_ERROR; + + if(info->sym_code == SVO_IDENT){ + + value =get_value_by_name(info->token); + + if(value != NULL){ + + *out = shell_value_clone(value); + + } else { + + *out = shell_value_init_text(""); + + } + + } else { + + err = SVO_IDENT; + + } + break; + + default: + return SHE_PARSE_ERROR; + } + + + + if(err == SHE_NO_ERROR){ + + if(scan(info)){ + if(*out != NULL) shell_value_free(*out); + return SHE_SCAN_ERROR; + } + + if(*out == NULL) err = SHE_NO_MEMORY; + + } + + return err; +} + +static int handle_exit(scan_info *info) +{ + long int exit_value = 0; + int err = SHE_NO_ERROR; + shell_value *expr; + + if(info->sym_code == SVO_PARENL){ + + if(scan(info)) return SHE_SCAN_ERROR; + + err = parse_expression(info,&expr); + if(err != SHE_NO_ERROR) return err; + + if(!(expr->isnumber)){ + err = SHE_INVALID_TYPE; + goto err; + } + + err = shell_value_get_number(expr,&exit_value); + if(err != SHE_NO_ERROR) goto err; + + if(expect(info,SVO_PARENR)){ + err = SVO_PARENR; + goto err; + } + + } + + sys_exit(exit_value); + + +err: + shell_value_free(expr); + return err; +} + +static int parse_rvl_expr(scan_info *info,shell_value **out) +{ + int err = SHE_NO_ERROR; + + *out = NULL; + + if(expect(info,SVO_PARENL)) return SVO_PARENL; + + err = parse_expression(info,out); + + if(err != SHE_NO_ERROR) return err; + + if(expect(info,SVO_PARENR)) { + + err = SVO_PARENR; + goto err; + + } + + return SHE_NO_ERROR; +err: + shell_value_free(*out); + + return err; +} + +static int handle_if(scan_info *info) +{ + int err = SHE_NO_ERROR; + long int value; + + shell_value *expr; + + err = parse_rvl_expr(info,&expr); + if(err != SHE_NO_ERROR) return err; + + if(!expr->isnumber){ + + err = SHE_INVALID_TYPE; + goto err; + + } + + err = shell_value_get_number(expr,&value); + if(err != SHE_NO_ERROR) goto err; + + if(value != 0) err = parse_info(info); + +err: + shell_value_free(expr); + return err; +} + + +// +// Parse exec function +// + +static int handle_exec(scan_info *info,shell_value **out) +{ + shell_value *state; + int argc; + char *argv[64]; + char redirect_in[SCAN_SIZE+1]; + char redirect_out[SCAN_SIZE+1]; + int err = SHE_NO_ERROR; + int retcode; + char *statement; + + *out = NULL; + + if(scan(info)) return SHE_SCAN_ERROR; + + err = parse_rvl_expr(info,&state); + if(err != SHE_NO_ERROR) return err; + + err = shell_value_get_text(state,&statement); + if(err != SHE_NO_ERROR) return err; + + argc = parse_line(statement,argv,64,redirect_in,redirect_out); + + err = exec_file(argc,argv,&retcode); + + if(err != SHE_NO_ERROR) goto err; + + *out = shell_value_init_number(retcode); + +err: + shell_value_free(state); + return err; +} + +// +// Parse load statement +// + +static int handle_load(scan_info *info) +{ + char var_name[SCAN_SIZE+1]; + shell_value *value; + int err = SHE_NO_ERROR; + + if(info->sym_code != SVO_IDENT) return SVO_IDENT; + + strcpy(var_name,info->token); + if(scan(info)) return SHE_SCAN_ERROR; + + if(expect(info,SVO_LOAD)) return SVO_LOAD; + + err = parse_expression(info,&value); + if(err != SHE_NO_ERROR) return err; + + set_shell_var_with_value(var_name,value); + + shell_value_free(value); + + return SHE_NO_ERROR; +} + + +// +// Parse echo statement +// + +static int handle_echo(scan_info *info) +{ + shell_value *value; + int err = SHE_NO_ERROR; + char *text; + + while(info->sym_code != SVO_END){ + + err = parse_expression(info,&value); + + if(err != SHE_NO_ERROR) return err; + + text = shell_value_to_char(value); + printf("%s",text); + shell_value_free(value); + free(text); + + if(info->sym_code == SVO_END) break; + + if(expect(info,SVO_COMMA)) { + err = SHE_SCAN_ERROR; + break; + } + + } + + printf("\n"); + return err; +} + + +// +// Convert error code too string. +// + +void ste_error_to_str(int error,char *descr) +{ + + char *err_txt; + if(error < 0){ + strcpy(descr,strerror(error)); + return; + } + if(error <= SVO_MAX){ + sprintf(descr,"'%s' expected",id_to_token(error)); + return; + } + switch(error){ + case SHE_NO_ERROR: + err_txt = "No error"; + break; + + case SHE_NO_MEMORY: + err_txt = "Not enough memory"; + break; + + case SHE_PARSE_ERROR: + err_txt = "Parse error"; + break; + + case SHE_FILE_NOT_FOUND: + err_txt = "File not found"; + break; + + case SHE_CANT_EXECUTE: + err_txt = "Can't execute"; + break; + + case SHE_INVALID_TYPE: + err_txt = "Invalid type"; + break; + + case SHE_INVALID_NUMBER: + err_txt = "Invalid number"; + break; + + case SHE_INVALID_OPERATION: + err_txt = "Invalid operation"; + break; + + case SHE_MISSING_QOUTE: + err_txt = "Missing Qoute"; + break; + + case SHE_LABEL_NOT_FOUND: + err_txt = "Label not found"; + break; + + default: + err_txt = "Unkown error"; + } + strcpy(descr,err_txt); +} + +// get an directory from path shell variable +// no : number of path +// name : return buffer +// max_len : max size of text in return buffer + +bool get_path(int no,char *name,int max_len) +{ + int cnt=no; + int len_cnt = max_len; + shell_value *var_value=get_value_by_name(NAME_VAR_PATH); + char *scan=name; + char *value; + int err; + if(var_value == NULL) return false; + + err = shell_value_get_text(var_value,&value); + if(err != SHE_NO_ERROR) return false; + + while((cnt > 0) && (*value != 0)){ + + while (*value != ':'){ + + if(*value == 0){ + *name = 0; + return false; + } + value++; + + } + value++; + cnt --; + } + + if(*value == 0) return false; + + while((*value != 0) && (*value != ':') && (len_cnt > 0)){ + + *scan = *value; + scan ++; + value++; + len_cnt--; + + } + + *scan = 0; + return true; + +} + + +static int handle_ident(scan_info *info,bool *is_label) +{ + char ch = *(info->scanner); + *is_label = false; + + if(ch == ':'){ + *is_label = true; + if(scan(info)) return SHE_SCAN_ERROR; + if(scan(info)) return SHE_SCAN_ERROR; + if(expect(info,SVO_END)) return SVO_END; + } + + return SHE_NO_ERROR; + +} + + +static int is_label_with_name(scan_info *info,char *check_label ,bool *is_label) +{ + char *begin = info->input_line; + char *scanner = begin; + *is_label = false; + + if(*scanner == 0) return SHE_NO_ERROR; + + scanner += strlen(scanner) -1; + + while((scanner != begin) && (isspace(*scanner))) scanner--; + + if(*scanner == ':'){ + + if(info->sym_code != SVO_IDENT) return SVO_IDENT; + + if(strcmp(check_label , info->token) == 0) *is_label = true; + + } + + return SHE_NO_ERROR; + +} + + +static int scan_until_label(scan_info *info,char *label_name) +{ + int err; + bool is_label; + + if(scan_info_home(info)) return SHE_SCAN_ERROR; + while(info->current != NULL){ + + err = is_label_with_name(info,label_name,&is_label); + + if(is_label) return SHE_NO_ERROR; + + if(scan_info_next_line(info)) return SHE_SCAN_ERROR; + + } + + return SHE_LABEL_NOT_FOUND; +} + +static int handle_goto(scan_info *info) +{ + int err; + + char label_name[SCAN_SIZE + 1]; + if(scan(info)) return SHE_SCAN_ERROR; + + if(info->sym_code != SVO_IDENT) return SVO_IDENT; + + strcpy(label_name,info->token); + + err = scan_until_label(info,label_name); + + return err; +} + + + +int parse_string(char *in) +{ + scan_info info; + init_scan_info(in,&info); + return parse_info(&info); +} + +int parse_info(scan_info *info) +{ + char err_txt[255]; + int err = SHE_NO_ERROR; + bool is_label; + + switch(info->sym_code){ + + case SVO_DOLLAR : + + if(scan(info)){ + + err = SHE_SCAN_ERROR; + break; + + } + err = handle_load(info); + break; + + case SVO_GOTO: + + err = handle_goto(info); + break; + + case SVO_IDENT: + + err = handle_ident(info,&is_label); + + if(!is_label){ + err = shell_parse(info->input_line,strlen(info->input_line)); + } + break; + + case SVO_ECHO : + if(scan(info)){ + + err = SHE_SCAN_ERROR; + break; + } + err = handle_echo(info); + break; + + case SVO_IF : + + if(scan(info)){ + + err = SHE_SCAN_ERROR; + + } else { + + err = handle_if(info); + + } + + break; + + case SVO_EXIT : + if(scan(info)){ + + err = SHE_SCAN_ERROR; + + } else { + + err = handle_exit(info); + + } + + break; + + default: + return shell_parse(info->input_line,strlen(info->input_line)); + + } + + if(err != SHE_NO_ERROR){ + + if(err == SHE_SCAN_ERROR) err = info->scan_error; + ste_error_to_str(err,err_txt); + printf("error :%d:%ld, %d-%s \n",info->line_no, + info->scanner - info->input_line - strlen(info->token), + err, + err_txt); + + } + return err; +} + + + +void init_statements(void){ + + shell_var_set_text(NAME_VAR_PATH,".:/:/boot:/boot/bin"); + +} + + + diff --git a/src/kernel/apps/shell/statements.h b/src/kernel/apps/shell/statements.h new file mode 100644 index 0000000000..03244b77f0 --- /dev/null +++ b/src/kernel/apps/shell/statements.h @@ -0,0 +1,18 @@ +#ifndef __STATEMENTS_H_ +#define __STATEMENTS_H_ + +//#include +#include "shell_defs.h" + + + + +void init_statements(void); +bool get_path(int no,char *name,int max_len); + +void ste_error_to_str(int error,char *descr); + +int parse_string(char *in); +int parse_info(scan_info *info); + +#endif diff --git a/src/kernel/apps/sockettest/Jamfile b/src/kernel/apps/sockettest/Jamfile new file mode 100644 index 0000000000..1c61a67902 --- /dev/null +++ b/src/kernel/apps/sockettest/Jamfile @@ -0,0 +1,3 @@ +SubDir OBOS_TOP sources os kits kernel apps sockettest ; + +KernelObjects <$(SOURCE_GRIST)>main.c : -fpic -Wno-unused ; diff --git a/src/kernel/apps/sockettest/main.c b/src/kernel/apps/sockettest/main.c new file mode 100644 index 0000000000..b9f45714c2 --- /dev/null +++ b/src/kernel/apps/sockettest/main.c @@ -0,0 +1,56 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + int rc = 0, fd[3]; + int cnt, i; + int on = 1; + + printf("Socket Test!!!\n"); + printf("This test doesn't do much but test that we can create a socket descriptor\n\n"); + + for (i=0;i<3;i++) { + printf("%d : ", i + 1); + fd[i] = socket(PF_INET, SOCK_DGRAM, 0); + printf("socket is fd %d\n", fd[i]); + + if (fd[i] > 0) { + rc = read(fd[i], NULL, 0); + + printf(" read on fd %d gave %d (expecting 0)\n", fd[i], rc); + } + } + + printf("closing the 3 fd's\n"); + for (i=0;i<3;i++) { + close(fd[i]); + } + + printf("\nNow we have no open fd's so next socket should be 3\n"); + fd[0] = socket(PF_INET, SOCK_DGRAM, 0); + printf("new socket = fd %d\n", fd[0]); + + printf("trying ioctl to set non blocking: "); + rc = ioctl(fd[0], FIONBIO, &on, sizeof(on)); + if (rc == 0) { + printf("OK\n"); + } else { + printf("failed\n"); + printf("Error was %s\n", strerror(errno)); + } + + close(fd[0]); + + return 0; +} diff --git a/src/kernel/apps/testapp/Jamfile b/src/kernel/apps/testapp/Jamfile new file mode 100644 index 0000000000..f95db9689c --- /dev/null +++ b/src/kernel/apps/testapp/Jamfile @@ -0,0 +1,3 @@ +SubDir OBOS_TOP sources os kits kernel apps testapp ; + +KernelObjects <$(SOURCE_GRIST)>main.c : -fpic -Wno-unused ; diff --git a/src/kernel/apps/testapp/main.c b/src/kernel/apps/testapp/main.c new file mode 100644 index 0000000000..3ca49a2c73 --- /dev/null +++ b/src/kernel/apps/testapp/main.c @@ -0,0 +1,505 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include +#include + +static void port_test(void); +static int port_test_thread_func(void* arg); + +static int test_thread(void *args) +{ + int i = (int)args; + + sys_snooze(1000000); + for(;;) { + printf("%c", 'a' + i); + } + return 0; +} + +static int dummy_thread(void *args) +{ + return 1; +} + +static int cpu_eater_thread(void *args) +{ + for(;;) + ; +} + +static int fpu_cruncher_thread(void *args) +{ + double y = *(double *)args; + double z; + + for(;;) { + z = y * 1.47; + y = z / 1.47; + if(y != *(double *)args) + printf("error: y %f\n", y); + } +} + +int main(int argc, char **argv) +{ + int rc = 0; + int cnt; + + printf("testapp\n"); + + for(cnt = 0; cnt< argc; cnt++) { + printf("arg %d = %s \n",cnt,argv[cnt]); + } + + printf("my thread id is %d\n", find_thread(NULL)); +#if 0 + { + char c; + printf("enter something: "); + + for(;;) { + c = getchar(); + printf("%c", c); + } + } +#endif +#if 0 + for(;;) { + sys_snooze(100000); + printf("booyah!"); + } + + for(;;); +#endif +#if 0 + printf("waiting 5 seconds\n"); + sys_snooze(5000000); +#endif +#if 0 + fd = sys_open("/dev/net/rtl8139/0", "", STREAM_TYPE_DEVICE); + if(fd >= 0) { + for(;;) { + size_t len; + static char buf[] = { + 0x00, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0x0F, 0x00, 0x0F, 0x00, 0x0F, + 0x00, 0x08, 0x00, 0x45, 0x00, 0x00, 0x28, 0xF9, 0x55, 0x40, 0x00, + 0x40, 0x06, 0xC0, 0x02, 0xC0, 0xA8, 0x00, 0x01, 0xC0, 0xA8, 0x00, + 0x26, 0x00, 0x50, 0x0B, 0x5C, 0x81, 0xD6, 0xFA, 0x48, 0xBB, 0x17, + 0x03, 0xC9, 0x50, 0x10, 0x7B, 0xB0, 0x6C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + len = sizeof(buf); + sys_write(fd, buf, 0, &len); + } + } +#endif +#if 0 + fd = sys_open("/dev/net/rtl8139/0", "", STREAM_TYPE_DEVICE); + if(fd >= 0) { + int foo = 0; + for(;;) { + size_t len; + char buf[1500]; + + len = sizeof(buf); + sys_read(fd, buf, 0, &len); + printf("%d read %d bytes\n", foo++, len); + } + } +#endif + +// XXX dangerous! This overwrites the beginning of your hard drive +#if 0 + { + char buf[512]; + size_t bytes_read; + + printf("opening /dev/bus/ide/0/0/raw\n"); + fd = sys_open("/dev/bus/ide/0/0/raw", "", STREAM_TYPE_DEVICE); + printf("fd = %d\n", fd); + + bytes_read = 512; + rc = sys_read(fd, buf, 0, &bytes_read); + printf("rc = %d, bytes_read = %d\n", rc, bytes_read); + + buf[0] = 'f'; + buf[1] = 'o'; + buf[2] = 'o'; + buf[3] = '2'; + buf[4] = 0; + + bytes_read = 512; + rc = sys_write(fd, buf, 1024, &bytes_read); + printf("rc = %d, bytes_read = %d\n", rc, bytes_read); + + sys_close(fd); + } +#endif +#if 0 + { + thread_id tids[10]; + int i; + + for(i=0; i<10; i++) { + tids[i] = spawn_thread(&test_thread, "foo", THREAD_MEDIUM_PRIORITY, (void *)i); + resume_thread(tids[i]); + } + + sys_snooze(5000000); + sys_proc_kill_proc(sys_get_current_proc_id()); +/* + sys_snooze(3000000); + for(i=0; i<10; i++) { + kill_thread(tids[i]); + } + printf("thread_is dead\n"); + sys_snooze(5000000); +*/ + } +#endif +#if 0 + { + for(;;) + sys_proc_create_proc("/boot/bin/true", "true", 32); + } +#endif +#if 0 + { + void *buf = (void *)0x60000000; + int fd; + int rc; + int len = 512; + + fd = sys_open("/boot/testapp", "", STREAM_TYPE_FILE); + + rc = sys_read(fd, buf, 0, &len); + printf("rc from read = 0x%x\n", rc); + sys_close(fd); + } +#endif +#if 0 + { + char data; + int fd; + + fd = sys_open("/dev/audio/pcbeep/1", STREAM_TYPE_DEVICE, 0); + if(fd >= 0) { + printf("writing to the speaker\n"); + data = 3; + sys_write(fd, &data, 0, 1); + sys_snooze(1000000); + data = 0; + sys_write(fd, &data, 0, 1); + sys_close(fd); + } + } +#endif + +#if 1 + { + port_test(); + } +#endif +#if 0 + { + int fd, bytes_read; + char buf[3]; + + fd = sys_open("/dev/ps2mouse", STREAM_TYPE_DEVICE, 0); + if(fd < 0) { + printf("failed to open device\n"); + return -1; + } + + bytes_read = sys_read(fd, buf, -1, 3); + if(bytes_read < 3) { + printf("failed to read device\n"); + return -1; + } + + printf("Status: %X\nDelta X: %d\nDelta Y: %d\n", buf[0], buf[1], buf[2]); + } +#endif +#if 0 + { + int fd; + int buf[512/4]; + int i, j; + + fd = sys_open("/dev/disk/netblock/0/raw", STREAM_TYPE_DEVICE, 0); + if(fd < 0) { + printf("could not open netblock\n"); + return -1; + } + + sys_ioctl(fd, 90001, NULL, 0); + + for(i=0; i<1*1024*1024; i += 512) { + for(j=0; j<512/4; j++) + buf[j] = i + j*4; + sys_write(fd, buf, -1, sizeof(buf)); + } + +// sys_read(fd, buf, 0, sizeof(buf)); +// sys_write(fd, buf, 512, sizeof(buf)); + } +#endif +#if 0 + +#define NUM_FDS 150 + { + int fds[NUM_FDS], i; + struct rlimit rl; + + rc = getrlimit(RLIMIT_NOFILE, &rl); + if (rc < 0) { + printf("error in getrlimit\n"); + return -1; + } + + printf("RLIMIT_NOFILE = %lu\n", rl.rlim_cur); + + for(i = 0; i < NUM_FDS; i++) { + fds[i] = open("/boot/bin/testapp", 0); + if (fds[i] < 0) { + break; + } + } + + printf("opened %d files\n", i); + + rl.rlim_cur += 15; + + printf("Setting RLIMIT_NOFILE to %lu\n", rl.rlim_cur); + rc = setrlimit(RLIMIT_NOFILE, &rl); + if (rc < 0) { + printf("error in setrlimit\n"); + return -1; + } + + rl.rlim_cur = 0; + rc = getrlimit(RLIMIT_NOFILE, &rl); + if (rc < 0) { + printf("error in getrlimit\n"); + return -1; + } + + printf("RLIMIT_NOFILE = %lu\n", rl.rlim_cur); + + for(;i < NUM_FDS; i++) { + fds[i] = open("/boot/bin/testapp", 0); + if (fds[i] < 0) { + break; + } + } + + printf("opened a total of %d files\n", i); + } +#endif +#if 0 + { + region_id rid; + void *ptr; + + rid = sys_vm_map_file("netblock", &ptr, REGION_ADDR_ANY_ADDRESS, 16*1024, LOCK_RW, + REGION_NO_PRIVATE_MAP, "/dev/disk/netblock/0/raw", 0); + if(rid < 0) { + printf("error mmaping device\n"); + return -1; + } + + // play around with it + printf("mmaped device at %p\n", ptr); + printf("%d\n", *(int *)ptr); + printf("%d\n", *((int *)ptr + 1)); + printf("%d\n", *((int *)ptr + 2)); + printf("%d\n", *((int *)ptr + 3)); + } +#endif +#if 0 + { + int i; + +// printf("spawning %d copies of true\n", 10000); + + for(i=0; ; i++) { + proc_id id; + bigtime_t t; + + printf("%d...", i); + + t = sys_system_time(); + + id = sys_proc_create_proc("/boot/bin/true", "true", NULL, 0, 20); + if(id <= 0x2) { + printf("new proc returned 0x%x!\n", id); + return -1; + } + sys_proc_wait_on_proc(id, NULL); + + printf("done (%Ld usecs)\n", sys_system_time() - t); + } + } +#endif +#if 0 + { + int i; + + printf("spawning two cpu eaters\n"); + +// resume_thread(spawn_thread("cpu eater 1", &cpu_eater_thread, 0)); +// resume_thread(spawn_thread(&cpu_eater_thread, "cpu eater 2", &cpu_eater_thread, 0)); + + printf("spawning %d threads\n", 10000); + + for(i=0; i<10000; i++) { + thread_id id; + bigtime_t t; + + printf("%d...", i); + + t = sys_system_time(); + + id = spawn_thread(&dummy_thread, "testthread", THREAD_MEDIUM_PRIORITY, NULL); + if (id > 0) + resume_thread(id); + + sys_thread_wait_on_thread(id, NULL); + + printf("done (%Ld usecs)\n", sys_system_time() - t); + } + } +#endif +#if 1 + { + thread_id id; + static double f[5] = { 2.43, 5.23, 342.34, 234123.2, 1.4 }; + + printf("spawning a few floating point crunchers\n"); + + id = spawn_thread(&fpu_cruncher_thread, "fpu thread0", THREAD_MEDIUM_PRIORITY, &f[0]); + resume_thread(id); + + id = spawn_thread(&fpu_cruncher_thread, "fpu thread1", THREAD_MEDIUM_PRIORITY, &f[1]); + resume_thread(id); + + id = spawn_thread(&fpu_cruncher_thread, "fpu thread2", THREAD_MEDIUM_PRIORITY, &f[2]); + resume_thread(id); + + id = spawn_thread(&fpu_cruncher_thread, "fpu thread3", THREAD_MEDIUM_PRIORITY, &f[3]); + resume_thread(id); + + id = spawn_thread(&fpu_cruncher_thread, "fpu thread4", THREAD_MEDIUM_PRIORITY, &f[4]); + resume_thread(id); + + getchar(); + printf("passed the test\n"); + } +#endif + + printf("exiting w/return code %d\n", rc); + return rc; +} + +/* + * testcode ports + */ + +port_id test_p1, test_p2, test_p3, test_p4; + +static void port_test(void) +{ + char testdata[5]; + thread_id t; + int res; + int32 dummy; + int32 dummy2; + + strcpy(testdata, "abcd"); + + printf("porttest: port_create()\n"); + test_p1 = sys_port_create(1, "test port #1"); + test_p2 = sys_port_create(10, "test port #2"); + test_p3 = sys_port_create(1024, "test port #3"); + test_p4 = sys_port_create(1024, "test port #4"); + + printf("porttest: port_find()\n"); + printf("'test port #1' has id %d (should be %d)\n", sys_port_find("test port #1"), test_p1); + + printf("porttest: port_write() on 1, 2 and 3\n"); + sys_port_write(test_p1, 1, &testdata, sizeof(testdata)); + sys_port_write(test_p2, 666, &testdata, sizeof(testdata)); + sys_port_write(test_p3, 999, &testdata, sizeof(testdata)); + printf("porttest: port_count(test_p1) = %d\n", sys_port_count(test_p1)); + + printf("porttest: port_write() on 1 with timeout of 1 sec (blocks 1 sec)\n"); + sys_port_write_etc(test_p1, 1, &testdata, sizeof(testdata), B_TIMEOUT, 1000000); + printf("porttest: port_write() on 2 with timeout of 1 sec (wont block)\n"); + res = sys_port_write_etc(test_p2, 777, &testdata, sizeof(testdata), B_TIMEOUT, 1000000); + printf("porttest: res=%d, %s\n", res, res == 0 ? "ok" : "BAD"); + + printf("porttest: port_read() on empty port 4 with timeout of 1 sec (blocks 1 sec)\n"); + res = sys_port_read_etc(test_p4, &dummy, &dummy2, sizeof(dummy2), B_TIMEOUT, 1000000); + printf("porttest: res=%d, %s\n", res, res == ETIMEDOUT ? "ok" : "BAD"); + + printf("porttest: spawning thread for port 1\n"); + t = spawn_thread(port_test_thread_func, "port_test", THREAD_MEDIUM_PRIORITY, NULL); + // resume thread + resume_thread(t); + + printf("porttest: write\n"); + sys_port_write(test_p1, 1, &testdata, sizeof(testdata)); + + // now we can write more (no blocking) + printf("porttest: write #2\n"); + sys_port_write(test_p1, 2, &testdata, sizeof(testdata)); + printf("porttest: write #3\n"); + sys_port_write(test_p1, 3, &testdata, sizeof(testdata)); + + printf("porttest: waiting on spawned thread\n"); + sys_thread_wait_on_thread(t, NULL); + + printf("porttest: close p1\n"); + sys_port_close(test_p2); + printf("porttest: attempt write p1 after close\n"); + res = sys_port_write(test_p2, 4, &testdata, sizeof(testdata)); + printf("porttest: port_write ret %s (should give Bad port id)\n", strerror(res)); + + printf("porttest: testing delete p2\n"); + sys_port_delete(test_p2); + + printf("porttest: end test main thread\n"); +} + +static int port_test_thread_func(void* arg) +{ + int msg_code; + int n; + char buf[5]; + + printf("porttest: port_test_thread_func()\n"); + + n = sys_port_read(test_p1, &msg_code, &buf, 3); + printf("port_read #1 code %d len %d buf %3s\n", msg_code, n, buf); + n = sys_port_read(test_p1, &msg_code, &buf, 4); + printf("port_read #1 code %d len %d buf %4s\n", msg_code, n, buf); + buf[4] = 'X'; + n = sys_port_read(test_p1, &msg_code, &buf, 5); + printf("port_read #1 code %d len %d buf %5s\n", msg_code, n, buf); + + printf("porttest: testing delete p1 from other thread\n"); + sys_port_delete(test_p1); + printf("porttest: end port_test_thread_func()\n"); + + return 0; +} + diff --git a/src/kernel/apps/testdigit/Jamfile b/src/kernel/apps/testdigit/Jamfile new file mode 100644 index 0000000000..8f89cf797f --- /dev/null +++ b/src/kernel/apps/testdigit/Jamfile @@ -0,0 +1,3 @@ +SubDir OBOS_TOP sources os kits kernel apps testdigit ; + +KernelObjects <$(SOURCE_GRIST)>main.c : -fpic -Wno-unused ; diff --git a/src/kernel/apps/testdigit/main.c b/src/kernel/apps/testdigit/main.c new file mode 100644 index 0000000000..49a4ea7a64 --- /dev/null +++ b/src/kernel/apps/testdigit/main.c @@ -0,0 +1,47 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#include +#include +#include +#include +#include +#include + +#define DIGIT "/dev/misc/digit" + +int main(int argc, char **argv) +{ + int rc = 0, fd, i; + char buffer[128]; + size_t len = 128; + + printf("Digit Test!!!\n"); + printf("\nDigit was one of the example device drivers that Be\n" + "provided, so this test basically justs runs a simple test\n" + "to make sure it works with OpenBeOS.\n" + "\nNB This is a simple test :)\n\n"); + + fd = open(DIGIT, O_RDONLY, 0); + if (fd < 0) { + printf("Failed at first hurdle :( Couldn't open the device!\n"); + return -1; + } + + rc = read(fd, buffer, len); + printf("Read on device gave %d\n", rc); + for (i = 0; i < rc; i++) { + printf("%02x ", buffer[i]); + if ((i & 15) == 15) + printf("\n"); + } + printf("\n"); + + close(fd); + + printf("closed device.\n"); + + return 0; +} diff --git a/src/kernel/apps/tests/Jamfile b/src/kernel/apps/tests/Jamfile new file mode 100644 index 0000000000..e9c061801c --- /dev/null +++ b/src/kernel/apps/tests/Jamfile @@ -0,0 +1,8 @@ +SubDir OBOS_TOP sources os kits kernel apps tests ; + +KernelObjects + <$(SOURCE_GRIST)>thread_test.c + <$(SOURCE_GRIST)>fops_test.c + : + -fpic -Wno-unused + ; diff --git a/src/kernel/apps/tests/fops_test.c b/src/kernel/apps/tests/fops_test.c new file mode 100644 index 0000000000..589d9415f5 --- /dev/null +++ b/src/kernel/apps/tests/fops_test.c @@ -0,0 +1,67 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TEST_FILE "/boot/etc/fortunes" +#define RD_LINES 5 +#define NEW_FORTUNE "The path has been shown - we are the ones who must walk it" + + +static void read_file(FILE *f) +{ + int lines = 0; + char *buffer, *tmp; + size_t bytes = 0; + + while ((buffer = fgetln(f, &bytes)) != NULL) { + if (*buffer == '#') + continue; + tmp = (char*) malloc(bytes + 1); + if (!tmp) + break; + memcpy(tmp, buffer, bytes); + if (tmp[bytes - 1] != '\n') + tmp[bytes - 1] = '\n'; + fprintf(stdout, "%d: %s", ++lines, tmp); + } +} + +int main(int argc, char **argv) +{ + FILE *f; + + f = fopen(TEST_FILE, "rw"); + if (!f) { + printf("Failed to open %s :( [%s]\n", TEST_FILE, + strerror(errno)); + return -1; + } + + read_file(f); + fputs("#@#\n", f); + fputs(NEW_FORTUNE, f); + + fprintf(stdout, "File added to.\n"); + + fclose(f); + printf("File opened and closed\n"); + + f = fopen(TEST_FILE, "r"); + if (!f) { + printf("Failed to open %s :( [%s]\n", TEST_FILE, + strerror(errno)); + return -1; + } + + read_file(f); + fclose(f); + printf("File opened and closed\n"); + + return 0; +} diff --git a/src/kernel/apps/tests/thread_test.c b/src/kernel/apps/tests/thread_test.c new file mode 100644 index 0000000000..a488cedc22 --- /dev/null +++ b/src/kernel/apps/tests/thread_test.c @@ -0,0 +1,64 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define THREADS 5 +#define START_VAL 1 + +struct the_test { + int *current_val; + int thread_mult; + sem_id the_lock; +}; + +static int counter_thread(void *data) +{ + struct the_test *tt = (struct the_test*)data; + free(data); + + acquire_sem(tt->the_lock); + + *(tt->current_val) *= tt->thread_mult; + + release_sem(tt->the_lock); +} + +int main(int argc, char **argv) +{ + thread_id t[THREADS]; + sem_id lock; + int i; + int expected = START_VAL, current_val = START_VAL; + + printf("OpenBeOS Thread Test - Simple\n" + "=============================\n"); + + lock = create_sem(1, "test_lock"); + + for (i=0;ithe_lock = lock; + my_test->current_val = ¤t_val; + my_test->thread_mult = i + 1; + + t[i] = spawn_thread(counter_thread, "counter", THREAD_MEDIUM_PRIORITY, my_test); + if (t[i] > 0) { + resume_thread(t[i]); + expected *= (i + 1); + } + } + + sys_thread_wait_on_thread(t[THREADS - 1], NULL); + + printf("Test value = %d vs expected of %d\n", current_val, expected); + + delete_sem(lock); + + return 0; +} diff --git a/src/kernel/apps/true_main.c b/src/kernel/apps/true_main.c new file mode 100644 index 0000000000..9128fb0be9 --- /dev/null +++ b/src/kernel/apps/true_main.c @@ -0,0 +1,13 @@ +/* +** Copyright 2002, Manuel J. Petit. All rights reserved. +** Contains portions of: +** +** /boot/bin/true, Copyright 2001 Travis K. Geiselbrecht +** +** Distributed under the terms of the NewOS License. +*/ +int main(void) +{ + return 1; +} + diff --git a/src/kernel/apps/uname/Jamfile b/src/kernel/apps/uname/Jamfile new file mode 100644 index 0000000000..19c9ccdc6e --- /dev/null +++ b/src/kernel/apps/uname/Jamfile @@ -0,0 +1,3 @@ +SubDir OBOS_TOP sources os kits kernel apps uname ; + +KernelObjects <$(SOURCE_GRIST)>main.c : -fpic -Wno-unused ; diff --git a/src/kernel/apps/uname/main.c b/src/kernel/apps/uname/main.c new file mode 100644 index 0000000000..b8fc6c5ebf --- /dev/null +++ b/src/kernel/apps/uname/main.c @@ -0,0 +1,193 @@ +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include + +//#include +#include + +//#include +#include +#include +#include +#include + +void usage(void); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + +#define MFLAG 0x01 +#define NFLAG 0x02 +#define PFLAG 0x04 +#define RFLAG 0x08 +#define SFLAG 0x10 +#define VFLAG 0x20 + u_int flags; + int ch, mib[2]; + size_t len, tlen; + char *p, buf[1024]; + const char *prefix; + + flags = 0; + while ((ch = getopt(argc, argv, "amnprsv")) != -1) + switch(ch) { + case 'a': + flags |= (MFLAG | NFLAG | RFLAG | SFLAG | VFLAG); + break; + case 'm': + flags |= MFLAG; + break; + case 'n': + flags |= NFLAG; + break; + case 'p': + flags |= PFLAG; + break; + case 'r': + flags |= RFLAG; + break; + case 's': + flags |= SFLAG; + break; + case 'v': + flags |= VFLAG; + break; + case '?': + default: + usage(); + } + + argc -= optind; + argv += optind; + + if (argc) + usage(); + + if (!flags) + flags |= SFLAG; + + prefix = ""; + + if (flags & SFLAG) { + mib[0] = CTL_KERN; + mib[1] = KERN_OSTYPE; + len = sizeof(buf); + if (sysctl(mib, 2, &buf, &len, NULL, 0) == -1) { + // err(1, "sysctl"); + printf("An error occured\n"); + return -1; + } + (void)printf("%s%.*s", prefix, (int)len, buf); + prefix = " "; + } + if (flags & NFLAG) { + mib[0] = CTL_KERN; + mib[1] = KERN_HOSTNAME; + len = sizeof(buf); + if (sysctl(mib, 2, &buf, &len, NULL, 0) == -1) { + // err(1, "sysctl"); + printf("An error occured\n"); + return -1; + } + (void)printf("%s%.*s", prefix, (int)len, buf); + prefix = " "; + } + if (flags & RFLAG) { + mib[0] = CTL_KERN; + mib[1] = KERN_OSRELEASE; + len = sizeof(buf); + if (sysctl(mib, 2, &buf, &len, NULL, 0) == -1) { + // err(1, "sysctl"); + printf("An error occured\n"); + return -1; + } + (void)printf("%s%.*s", prefix, (int)len, buf); + prefix = " "; + } + if (flags & VFLAG) { + mib[0] = CTL_KERN; + mib[1] = KERN_VERSION; + len = sizeof(buf); + if (sysctl(mib, 2, &buf, &len, NULL, 0) == -1){ + // err(1, "sysctl"); + printf("An error occured\n"); + return -1; + } + for (p = buf, tlen = len; tlen--; ++p) + if (*p == '\n' || *p == '\t') + *p = ' '; + (void)printf("%s%.*s", prefix, (int)len, buf); + prefix = " "; + } + if (flags & MFLAG) { + mib[0] = CTL_HW; + mib[1] = HW_MACHINE; + len = sizeof(buf); + if (sysctl(mib, 2, &buf, &len, NULL, 0) == -1) { + // err(1, "sysctl"); + printf("An error occured\n"); + return -1; + } + (void)printf("%s%.*s", prefix, (int)len, buf); + prefix = " "; + } + if (flags & PFLAG) { + mib[0] = CTL_HW; + mib[1] = HW_MODEL; + len = sizeof(buf); + if (sysctl(mib, 2, &buf, &len, NULL, 0) == -1) { + // err(1, "sysctl"); + printf("An error occured\n"); + return -1; + } + (void)printf("%s%.*s", prefix, (int)len, buf); + prefix = " "; + } + (void)printf("\n"); + //exit (0); + return B_NO_ERROR; +} + +void +usage() +{ + (void)fprintf(stderr, "usage: uname [-amnprsv]\n"); + //exit(1); +} + diff --git a/src/kernel/apps/unmount/Jamfile b/src/kernel/apps/unmount/Jamfile new file mode 100644 index 0000000000..d1e6fce2d6 --- /dev/null +++ b/src/kernel/apps/unmount/Jamfile @@ -0,0 +1,3 @@ +SubDir OBOS_TOP sources os kits kernel apps unmount ; + +KernelObjects <$(SOURCE_GRIST)>main.c : -fpic ; diff --git a/src/kernel/apps/unmount/main.c b/src/kernel/apps/unmount/main.c new file mode 100644 index 0000000000..44e625856a --- /dev/null +++ b/src/kernel/apps/unmount/main.c @@ -0,0 +1,27 @@ +/* +** Copyright 2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include + +int main(int argc, char *argv[]) +{ + int rc; + + if(argc < 2) { + printf("not enough arguments to unmount\n"); + return 0; + } + + rc = sys_unmount(argv[1]); + if (rc < 0) { + printf("sys_unmount() returned error: %s\n", strerror(rc)); + } else { + printf("%s successfully unmounted.\n", argv[1]); + } + + return 0; +} + diff --git a/src/kernel/boot/Jamfile b/src/kernel/boot/Jamfile new file mode 100644 index 0000000000..2e1929ea15 --- /dev/null +++ b/src/kernel/boot/Jamfile @@ -0,0 +1,8 @@ +SubDir OBOS_TOP sources os kits kernel boot ; + +SystemMain bootmaker : bootmaker.c : $(OBOS_KERNEL) ; +SystemMain bin2h : bin2h.c ; +SystemMain bin2asm : bin2asm.c ; +SystemMain makeflop : makeflop.c : $(OBOS_FLOPPY) ; + +SubInclude OBOS_TOP sources os kits kernel boot arch ; diff --git a/src/kernel/boot/arch/Jamfile b/src/kernel/boot/arch/Jamfile new file mode 100644 index 0000000000..d553565187 --- /dev/null +++ b/src/kernel/boot/arch/Jamfile @@ -0,0 +1,10 @@ +SubDir OBOS_TOP sources os kits kernel boot arch ; + +SubInclude OBOS_TOP sources os kits kernel boot arch alpha ; +SubInclude OBOS_TOP sources os kits kernel boot arch x86 ; +SubInclude OBOS_TOP sources os kits kernel boot arch m68k ; +SubInclude OBOS_TOP sources os kits kernel boot arch mips ; +SubInclude OBOS_TOP sources os kits kernel boot arch ppc ; +SubInclude OBOS_TOP sources os kits kernel boot arch sh4 ; +SubInclude OBOS_TOP sources os kits kernel boot arch sparc ; +SubInclude OBOS_TOP sources os kits kernel boot arch sparc64 ; diff --git a/src/kernel/boot/arch/alpha/Jamfile b/src/kernel/boot/arch/alpha/Jamfile new file mode 100644 index 0000000000..d04c1a1887 --- /dev/null +++ b/src/kernel/boot/arch/alpha/Jamfile @@ -0,0 +1,2 @@ +SubDir OBOS_TOP sources os kits kernel boot arch alpha ; + diff --git a/src/kernel/boot/arch/alpha/stage2.c b/src/kernel/boot/arch/alpha/stage2.c new file mode 100644 index 0000000000..7736169cf2 --- /dev/null +++ b/src/kernel/boot/arch/alpha/stage2.c @@ -0,0 +1,11 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +int _start() +{ + + return 0; +} + diff --git a/src/kernel/boot/arch/alpha/stage2.ld b/src/kernel/boot/arch/alpha/stage2.ld new file mode 100644 index 0000000000..e74ea5d3c0 --- /dev/null +++ b/src/kernel/boot/arch/alpha/stage2.ld @@ -0,0 +1,32 @@ +OUTPUT_FORMAT("elf64-alpha", "elf64-alpha", "elf64-alpha") +OUTPUT_ARCH(alpha) + +ENTRY(_start) +SECTIONS +{ + . = 0x101000 + SIZEOF_HEADERS; + + /* text/read-only data */ + .text : { *(.text .gnu.linkonce.t.*) } + + __ctor_list = .; + .ctors : { *(.ctors) } + __ctor_end = .; + + .rodata : { *(.rodata) } + + /* writable data */ + . = ALIGN(0x1000); + __data_start = .; + .data : { *(.data .gnu.linkonce.d.*) } + + /* unintialized data (in same segment as writable data) */ + __bss_start = .; + .bss : { *(.bss) } + + . = ALIGN(0x1000); + _end = . ; + + /* Strip unnecessary stuff */ + /DISCARD/ : { *(.comment .note .eh_frame .dtors) } +} diff --git a/src/kernel/boot/arch/alpha/stage2.mk b/src/kernel/boot/arch/alpha/stage2.mk new file mode 100644 index 0000000000..8784439755 --- /dev/null +++ b/src/kernel/boot/arch/alpha/stage2.mk @@ -0,0 +1,31 @@ + +STAGE2_DIR = boot/$(ARCH) +STAGE2_OBJ_DIR = $(STAGE2_DIR)/$(OBJ_DIR) +STAGE2_OBJS = $(STAGE2_OBJ_DIR)/stage2.o +DEPS += $(STAGE2_OBJS:.o=.d) + +STAGE2 = $(STAGE2_OBJ_DIR)/stage2 + +$(STAGE2): $(STAGE2_OBJS) $(LIBC) + $(LD) -dN --script=$(STAGE2_DIR)/stage2.ld -L $(LIBGCC_PATH) $(LIBGCC) $(STAGE2_OBJS) $(LIBC) -o $@ + +stage2clean: + rm -f $(STAGE2_OBJS) $(STAGE2_ARCH) + +$(STAGE2_OBJ_DIR)/%.o: $(STAGE2_DIR)/%.c + @mkdir -p $(STAGE2_OBJ_DIR) + $(CC) $(GLOBAL_CFLAGS) -Iinclude -I$(STAGE2_DIR) -c $< -o $@ + +$(STAGE2_OBJ_DIR)/%.d: $(STAGE2_DIR)/%.c + @mkdir -p $(STAGE2_OBJ_DIR) + @echo "making deps for $<..." + @($(ECHO) -n $(dir $@);$(CC) $(GLOBAL_CFLAGS) -Iinclude -I$(STAGE2_DIR) -M -MG $<) > $@ + +$(STAGE2_OBJ_DIR)/%.d: $(STAGE2_DIR)/%.S + @mkdir -p $(STAGE2_OBJ_DIR) + @echo "making deps for $<..." + @($(ECHO) -n $(dir $@);$(CC) $(GLOBAL_CFLAGS) -Iinclude -I$(STAGE2_DIR) -M -MG $<) > $@ + +$(STAGE2_OBJ_DIR)/%.o: $(STAGE2_DIR)/%.S + @mkdir -p $(STAGE2_OBJ_DIR) + $(CC) $(GLOBAL_CFLAGS) -Iinclude -I$(STAGE2_DIR) -c $< -o $@ diff --git a/src/kernel/boot/arch/m68k/Jamfile b/src/kernel/boot/arch/m68k/Jamfile new file mode 100644 index 0000000000..1806f798b2 --- /dev/null +++ b/src/kernel/boot/arch/m68k/Jamfile @@ -0,0 +1,2 @@ +SubDir OBOS_TOP sources os kits kernel boot arch m68k ; + diff --git a/src/kernel/boot/arch/m68k/boot.mk b/src/kernel/boot/arch/m68k/boot.mk new file mode 100644 index 0000000000..34cd6c5c29 --- /dev/null +++ b/src/kernel/boot/arch/m68k/boot.mk @@ -0,0 +1,93 @@ +ifneq ($(_BOOT_MAKE),1) +_BOOT_MAKE = 1 + +# include targets we depend on +include lib/lib.mk +include kernel/kernel.mk +include apps/apps.mk + +BOOT_DIR = boot/$(ARCH) +BOOT_OBJ_DIR = $(BOOT_DIR)/$(OBJ_DIR) + +STAGE2_OBJS = \ + $(BOOT_OBJ_DIR)/stage2.o \ + $(BOOT_OBJ_DIR)/stage2_asm.o \ + $(BOOT_OBJ_DIR)/stage2_nextmon.o \ + $(BOOT_OBJ_DIR)/stage2_text.o \ + +DEPS += $(STAGE2_OBJS:.o=.d) + +STAGE2 = $(BOOT_OBJ_DIR)/stage2 + +$(STAGE2): $(STAGE2_OBJS) $(KLIBS) + $(LD) -dN --script=$(BOOT_DIR)/stage2.ld -L $(LIBGCC_PATH) $(STAGE2_OBJS) $(LINK_KLIBS) $(LIBGCC) -o $@ + +stage2: $(STAGE2) + +stage2clean: + rm -f $(STAGE2_OBJS) $(STAGE2) + +CLEAN += stage2clean + +SEMIFINAL = $(BOOT_DIR)/final.bootdir + +#$(SEMIFINAL): $(STAGE2) $(KERNEL) $(APPS) tools +$(SEMIFINAL): $(STAGE2) tools + $(BOOTMAKER) --bigendian $(BOOT_DIR)/config.ini -o $(SEMIFINAL) + +STAGE1_OBJS = \ + $(BOOT_OBJ_DIR)/stage1.o + +DEPS += $(STAGE1_OBJS:.o=.d) + +FINAL = $(BOOT_DIR)/final + +AWKPROG='\ +{ \ + printf "\0\207\01\07"; \ + printf "\0%c%c%c", $$1 / 65536, $$1 / 256, $$1; \ + printf "\0%c%c%c", $$2 / 65536, $$2 / 256, $$2; \ + printf "\0%c%c%c", $$3 / 65536, $$3 / 256, $$3; \ + printf "\0\0\0\0\04\070\0\0\0\0\0\0\0\0\0\0" \ +}' + +$(FINAL): $(STAGE1_OBJS) + $(LD) -dN --script=$(BOOT_DIR)/stage1.ld $(STAGE1_OBJS) -o $@.elf + @${SIZE} $@.elf + @${OBJCOPY} -O binary $@.elf $@.raw + @(${SIZE} $@.elf | tail +2 | ${AWK} ${AWKPROG} ; cat $@.raw) > $@ + +FINAL_ASMINCLUDE = $(BOOT_DIR)/final.asminclude + +$(FINAL_ASMINCLUDE): $(SEMIFINAL) tools + $(BIN2ASM) < $(SEMIFINAL) > $(FINAL_ASMINCLUDE) + +finalclean: + rm -f $(STAGE1_OBJS) $(FINAL) $(SEMIFINAL) $(FINAL_ASMINCLUDE) + +CLEAN += finalclean + +# +$(BOOT_OBJ_DIR)/stage1.o: $(BOOT_DIR)/stage1.S + @if [ ! -d $(BOOT_OBJ_DIR) ]; then mkdir -p $(BOOT_OBJ_DIR); fi + $(CC) -c $< $(GLOBAL_CFLAGS) -I. -Iinclude -o $@ + +$(BOOT_OBJ_DIR)/%.o: $(BOOT_DIR)/%.c + @if [ ! -d $(BOOT_OBJ_DIR) ]; then mkdir -p $(BOOT_OBJ_DIR); fi + $(CC) -c $< $(GLOBAL_CFLAGS) $(KERNEL_CFLAGS) -Iinclude -Iinclude/nulibc -o $@ + +$(BOOT_OBJ_DIR)/%.d: $(BOOT_DIR)/%.c + @if [ ! -d $(BOOT_OBJ_DIR) ]; then mkdir -p $(BOOT_OBJ_DIR); fi + @echo "making deps for $<..." + @($(ECHO) -n $(dir $@);$(CC) $(KERNEL_CFLAGS) -Iinclude -Iinclude/nulibc -M -MG $<) > $@ + +$(BOOT_OBJ_DIR)/%.d: $(BOOT_DIR)/%.S + @if [ ! -d $(BOOT_OBJ_DIR) ]; then mkdir -p $(BOOT_OBJ_DIR); fi + @echo "making deps for $<..." + @($(ECHO) -n $(dir $@);$(CC) $(KERNEL_CFLAGS) -Iinclude -Iinclude/nulibc -M -MG $<) > $@ + +$(BOOT_OBJ_DIR)/%.o: $(BOOT_DIR)/%.S + @if [ ! -d $(BOOT_OBJ_DIR) ]; then mkdir -p $(BOOT_OBJ_DIR); fi + $(CC) -c $< $(GLOBAL_CFLAGS) $(KERNEL_CFLAGS) -Iinclude -Iinclude/nulibc -o $@ + +endif diff --git a/src/kernel/boot/arch/m68k/config.ini b/src/kernel/boot/arch/m68k/config.ini new file mode 100644 index 0000000000..be5b9587a7 --- /dev/null +++ b/src/kernel/boot/arch/m68k/config.ini @@ -0,0 +1,14 @@ +# --------------------------------------------------------------- +# The bootstrap code is where control starts once netboot, boot.com, +# etc loads the image. It creates a page table to map the kernel in +# at 0x80000000 and then jumps to the kernel entrypoint where things +# really start happening. This MUST be the first entry in the .ini +# +[bootstrap] +type=elf32 +file=boot/m68k/obj.m68k/stage2 + +#[kernel] +#type=elf32 +#file=kernel/obj.m68k/system + diff --git a/src/kernel/boot/arch/m68k/stage1.S b/src/kernel/boot/arch/m68k/stage1.S new file mode 100644 index 0000000000..8575256bbf --- /dev/null +++ b/src/kernel/boot/arch/m68k/stage1.S @@ -0,0 +1,51 @@ +/* +** Copyright 2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#define BASE 0x4380000 +#define BOOTDIR_BASE (BASE + 0x1000) +#define STAGE2_BOOTDIR_PAGE (BOOTDIR_BASE + 0x60) +#define STAGE2_OFFSET (BOOTDIR_BASE + 0x74) + +.globl _start +_start: + nop + + /* load the base of the bootdir */ + movel #BOOTDIR_BASE,%a0 + + /* load the offset the stage2 will start into the bootdir */ + movel (STAGE2_BOOTDIR_PAGE),%d0 + mulul #4096,%d0 + movel %d0,%a1 + + /* load the offset into that page the stage2 entry point will be */ + movel (STAGE2_OFFSET),%a2 + + /* add them together */ + addl %a2,%a1 + addl %a1,%a0 + + /* look in the vector table and find the monitor vector */ + movec %vbr,%a3 + movel %a3@(4),%sp@- + + /* copy the arg we got */ + movel %sp@(8),%sp@- + + /* make the call */ + jsr (%a0) + + addql #8,%sp + + rts + +.align 4 +tempstack: + .skip 0x800 + tempstack_end: + +.align 0x1000 +.data +#include "boot/m68k/final.asminclude" diff --git a/src/kernel/boot/arch/m68k/stage1.ld b/src/kernel/boot/arch/m68k/stage1.ld new file mode 100644 index 0000000000..5413160666 --- /dev/null +++ b/src/kernel/boot/arch/m68k/stage1.ld @@ -0,0 +1,44 @@ +OUTPUT_FORMAT("elf32-m68k", "elf32-m68k", "elf32-m68k") +OUTPUT_ARCH(m68k) + +/* +PHDRS +{ + reginfo 0x70000000; + text PT_LOAD; +} +*/ + +ENTRY(_start) +SECTIONS +{ + + . = 0x4380000; + + /* text/read-only data */ + .text : { *(.text .gnu.linkonce.t.*) } + + __ctor_list = .; + .ctors : { *(.ctors) } + __ctor_end = .; + + .rodata : + { + *(.rodata) + . = ALIGN(0x1000); + } =0x9000 + + /* writable data */ + __data_start = .; + .data : { *(.data .gnu.linkonce.d.*) } + + /* unintialized data (in same segment as writable data) */ + __bss_start = .; + .bss : { *(.bss) } + + . = ALIGN(0x1000); + _end = . ; + + /* Strip unnecessary stuff */ + /DISCARD/ : { *(.reginfo .comment .note .eh_frame .dtors) } +} diff --git a/src/kernel/boot/arch/m68k/stage2.c b/src/kernel/boot/arch/m68k/stage2.c new file mode 100644 index 0000000000..ccb418017a --- /dev/null +++ b/src/kernel/boot/arch/m68k/stage2.c @@ -0,0 +1,67 @@ +/* +** Copyright 2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include "stage2_priv.h" +#include +#include +#include + +static kernel_args ka = { 0 }; + +#define BOOTDIR_ADDR 0x4381000 +static const boot_entry *bootdir = (boot_entry*)BOOTDIR_ADDR; + +int _start(char *boot_args, char *monitor); +int _start(char *boot_args, char *monitor) +{ + unsigned int bootdir_pages; + + init_nextmon(monitor); + dprintf("\nNewOS stage2: args '%s', monitor %p\n", boot_args, monitor); + + probe_memory(&ka); + + dprintf("tc 0x%x\n", get_tc()); + dprintf("urp 0x%x\n", get_urp()); + dprintf("srp 0x%x\n", get_srp()); + + // calculate how big the bootdir is + { + int entry; + bootdir_pages = 0; + for (entry = 0; entry < BOOTDIR_MAX_ENTRIES; entry++) { + if (bootdir[entry].be_type == BE_TYPE_NONE) + break; + + bootdir_pages += bootdir[entry].be_size; + } + ka.bootdir_addr.start = (unsigned long)bootdir; + ka.bootdir_addr.size = bootdir_pages * PAGE_SIZE; + dprintf("bootdir: start %p, size 0x%x\n", (char *)ka.bootdir_addr.start, ka.bootdir_addr.size); + } + + // begin to set up the physical page allocation range data structures + ka.num_phys_alloc_ranges = 1; + ka.phys_alloc_range[0].start = ka.bootdir_addr.start; + ka.phys_alloc_range[0].size = ka.bootdir_addr.size; + + // allocate a stack for the kernel when we jump into it + ka.cpu_kstack[0].start = allocate_page(&ka); + ka.cpu_kstack[0].size = PAGE_SIZE; + + ka.num_cpus = 0; + + return 0; +} + +unsigned long allocate_page(kernel_args *ka) +{ + unsigned long page; + + page = ka->phys_alloc_range[0].start + ka->phys_alloc_range[0].size; + ka->phys_alloc_range[0].size += PAGE_SIZE; + + return page; +} + diff --git a/src/kernel/boot/arch/m68k/stage2.ld b/src/kernel/boot/arch/m68k/stage2.ld new file mode 100644 index 0000000000..ae708f3eba --- /dev/null +++ b/src/kernel/boot/arch/m68k/stage2.ld @@ -0,0 +1,43 @@ +OUTPUT_FORMAT("elf32-m68k", "elf32-m68k", "elf32-m68k") +OUTPUT_ARCH(m68k) + +/* +PHDRS +{ + reginfo 0x70000000; + text PT_LOAD; +} +*/ + +ENTRY(_start) +SECTIONS +{ + . = 0x4382000 + SIZEOF_HEADERS; + + /* text/read-only data */ + .text : { *(.text .gnu.linkonce.t.*) } + + __ctor_list = .; + .ctors : { *(.ctors) } + __ctor_end = .; + + .rodata : + { + *(.rodata) + . = ALIGN(0x1000); + } =0x9000 + + /* writable data */ + __data_start = .; + .data : { *(.data .gnu.linkonce.d.*) } + + /* unintialized data (in same segment as writable data) */ + __bss_start = .; + .bss : { *(.bss) } + + . = ALIGN(0x1000); + _end = . ; + + /* Strip unnecessary stuff */ + /DISCARD/ : { *(.reginfo .comment .note .eh_frame .dtors) } +} diff --git a/src/kernel/boot/arch/m68k/stage2_asm.S b/src/kernel/boot/arch/m68k/stage2_asm.S new file mode 100644 index 0000000000..50d00ccbb1 --- /dev/null +++ b/src/kernel/boot/arch/m68k/stage2_asm.S @@ -0,0 +1,37 @@ +/* +** Copyright 2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +.text + +.globl get_tc +get_tc: + .long 0x4e7a0003 // movec %tc,%d0 + rts + +.globl set_tc +set_tc: + .long 0x4e7b0003 // movec %d0,%tc + rts + +.globl get_urp +get_urp: + .long 0x4e7a0806 // movec %urp,%d0 + rts + +.globl set_urp +set_urp: + .long 0x4e7b0806 // movec %d0,%urp + rts + +.globl get_srp +get_srp: + .long 0x4e7a0807 // movec %srp,%d0 + rts + +.globl set_srp +set_srp: + .long 0x4e7b0807 // movec %d0,%srp + rts + diff --git a/src/kernel/boot/arch/m68k/stage2_nextmon.c b/src/kernel/boot/arch/m68k/stage2_nextmon.c new file mode 100644 index 0000000000..5bea63feee --- /dev/null +++ b/src/kernel/boot/arch/m68k/stage2_nextmon.c @@ -0,0 +1,184 @@ +/* +** Copyright 2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include "stage2_priv.h" + +#define MG_simm 0 +#define MG_flags 4 +#define MG_sid 6 +#define MG_pagesize 10 +#define MG_mon_stack 14 +#define MG_vbr 18 +#define MG_nvram 22 +#define MG_inetntoa 54 +#define MG_inputline 72 +#define MG_region 200 +#define MG_alloc_base 232 +#define MG_alloc_brk 236 +#define MG_boot_dev 240 +#define MG_boot_arg 244 +#define MG_boot_info 248 +#define MG_boot_file 252 +#define MG_bootfile 256 +#define MG_boot_how 320 +#define MG_km 324 +#define MG_km_flags 368 +#define MG_mon_init 370 +#define MG_si 374 +#define MG_time 378 +#define MG_sddp 382 +#define MG_dgp 386 +#define MG_s5cp 390 +#define MG_odc 394 +#define MG_odd 398 +#define MG_radix 402 +#define MG_dmachip 404 +#define MG_diskchip 408 +#define MG_intrstat 412 +#define MG_intrmask 416 +#define MG_nofault 420 +#define MG_fmt 424 +#define MG_addr 426 +#define MG_na 458 +#define MG_mx 462 +#define MG_my 466 +#define MG_cursor_save 470 +#define MG_getc 726 +#define MG_try_getc 730 +#define MG_putc 734 +#define MG_alert 738 +#define MG_alert_confirm 742 +#define MG_alloc 746 +#define MG_boot_slider 750 +#define MG_eventc 754 +#define MG_event_high 758 +#define MG_animate 762 +#define MG_anim_time 766 +#define MG_scsi_intr 770 +#define MG_scsi_intrarg 774 +#define MG_minor 778 +#define MG_seq 780 +#define MG_anim_run 782 +#define MG_major 786 +#define MG_con_slot 844 +#define MG_con_fbnum 845 +#define MG_con_map_vaddr0 860 +#define MG_con_map_vaddr1 872 +#define MG_con_map_vaddr2 884 +#define MG_con_map_vaddr3 896 +#define MG_con_map_vaddr4 908 +#define MG_con_map_vaddr5 920 + +#define MG_clientetheraddr 788 +#define MG_machine_type 936 +#define MG_board_rev 937 + +#define N_SIMM 4 /* number of SIMMs in machine */ + +/* SIMM types */ +#define SIMM_SIZE 0x03 +#define SIMM_SIZE_EMPTY 0x00 +#define SIMM_SIZE_16MB 0x01 +#define SIMM_SIZE_4MB 0x02 +#define SIMM_SIZE_1MB 0x03 +#define SIMM_PAGE_MODE 0x04 +#define SIMM_PARITY 0x08 /* ?? */ + +#define NEXT_RAMBASE 0x4000000 + +/* Machine types */ +#define NeXT_CUBE 0 +#define NeXT_WARP9 1 +#define NeXT_X15 2 +#define NeXT_WARP9C 3 +#define NeXT_TURBO 4 +#define NeXT_TURBO_COLOR 5 + +typedef int (*getcptr)(void); +typedef int (*putcptr)(int); + +#define MON(type, off) (*(type *)((unsigned int) (mg) + off)) + +static char *mg = 0; + +int init_nextmon(char *monitor) +{ + mg = monitor; + + return 0; +} + +int probe_memory(kernel_args *ka) +{ + int i, r; + char machine_type = MON(char,MG_machine_type); + int msize1, msize4, msize16; + + /* depending on the machine, the bank layout is different */ + dprintf("machine type: 0x%x\n", machine_type); + switch(machine_type) { + case NeXT_WARP9: + case NeXT_X15: + msize16 = 0x10000000; + msize4 = 0x400000; + msize1 = 0x100000; + break; + case NeXT_WARP9C: + msize16 = 0x800000; + msize4 = 0x200000; + msize1 = 0x80000; + break; + case NeXT_TURBO: + case NeXT_TURBO_COLOR: + msize16 = 0x2000000; + msize4 = 0x800000; + msize1 = 0x200000; + break; + default: + msize16 = 0x100000; + msize4 = 0x100000; + msize1 = 0x100000; + } + + /* start probing ram */ + dprintf("memory probe:\n"); + ka->num_phys_mem_ranges = 0; + for(i=0; iphys_mem_range[ka->num_phys_mem_ranges].start = NEXT_RAMBASE + (msize16 * i); + } + switch(probe & SIMM_SIZE) { + case SIMM_SIZE_16MB: + ka->phys_mem_range[ka->num_phys_mem_ranges].size = msize16; + break; + case SIMM_SIZE_4MB: + ka->phys_mem_range[ka->num_phys_mem_ranges].size = msize4; + break; + case SIMM_SIZE_1MB: + ka->phys_mem_range[ka->num_phys_mem_ranges].size = msize1; + break; + } + dprintf("bank %i: start 0x%x, size 0x%x\n", i, + ka->phys_mem_range[ka->num_phys_mem_ranges].start, ka->phys_mem_range[ka->num_phys_mem_ranges].size); + ka->num_phys_mem_ranges++; + } + + dprintf("alloc_base: 0x%x\n", MON(int, MG_alloc_base)); + dprintf("alloc_brk: 0x%x\n", MON(int, MG_alloc_brk)); + dprintf("mon_stack: 0x%x\n", MON(int, MG_mon_stack)); + + return 0; +} + +void putc(int c) +{ + MON(putcptr,MG_putc)(c); +} + +int getc(void) +{ + return(MON(getcptr,MG_getc)()); +} diff --git a/src/kernel/boot/arch/m68k/stage2_text.c b/src/kernel/boot/arch/m68k/stage2_text.c new file mode 100644 index 0000000000..ce517e23db --- /dev/null +++ b/src/kernel/boot/arch/m68k/stage2_text.c @@ -0,0 +1,30 @@ +/* +** Copyright 2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include "stage2_priv.h" + +#include +#include +#include + +void puts(const char *str) +{ + while (*str) + putc(*str++); +} + +int dprintf(const char *fmt, ...) +{ + int ret; + va_list args; + char temp[256]; + + va_start(args, fmt); + ret = vsprintf(temp,fmt,args); + va_end(args); + + puts(temp); + return ret; +} + diff --git a/src/kernel/boot/arch/mips/Jamfile b/src/kernel/boot/arch/mips/Jamfile new file mode 100644 index 0000000000..8e70e9ca3b --- /dev/null +++ b/src/kernel/boot/arch/mips/Jamfile @@ -0,0 +1,2 @@ +SubDir OBOS_TOP sources os kits kernel boot arch mips ; + diff --git a/src/kernel/boot/arch/mips/boot.mk b/src/kernel/boot/arch/mips/boot.mk new file mode 100644 index 0000000000..8d062f7d3e --- /dev/null +++ b/src/kernel/boot/arch/mips/boot.mk @@ -0,0 +1,78 @@ +ifneq ($(_BOOT_MAKE),1) +_BOOT_MAKE = 1 + +# include targets we depend on +include lib/lib.mk +include kernel/kernel.mk +include apps/apps.mk + +# mips stage2 makefile +BOOT_DIR = boot/$(ARCH) +BOOT_OBJ_DIR = $(BOOT_DIR)/$(OBJ_DIR) + +STAGE2_OBJS = \ + $(BOOT_OBJ_DIR)/stage2.o + +DEPS += $(STAGE2_OBJS:.o=.d) + +STAGE2 = $(BOOT_OBJ_DIR)/stage2 + +$(STAGE2): $(STAGE2_OBJS) $(KLIBS) + $(LD) -dN --script=$(BOOT_DIR)/stage2.ld -L $(LIBGCC_PATH) $(STAGE2_OBJS) $(KLIBS) $(LIBGCC) -o $@ + +stage2: $(STAGE2) + +stage2clean: + rm -f $(STAGE2_OBJS) $(STAGE2) + +CLEAN += stage2clean + +SEMIFINAL = $(BOOT_DIR)/final.bootdir + +$(SEMIFINAL): $(STAGE2) $(KERNEL) $(APPS) tools + $(BOOTMAKER) $(BOOT_DIR)/config.ini -o $(SEMIFINAL) + +STAGE1_OBJS = \ + $(BOOT_OBJ_DIR)/stage1.o + +DEPS += $(STAGE1_OBJS:.o=.d) + +FINAL = $(BOOT_DIR)/final + +$(FINAL): $(STAGE1_OBJS) + $(LD) -dN --script=$(BOOT_DIR)/stage1.ld $(STAGE1_OBJS) -o $@ + +FINAL_ASMINCLUDE = $(BOOT_DIR)/final.asminclude + +$(BOOT_OBJ_DIR)/stage1.o: $(BOOT_DIR)/stage1.S + @if [ ! -d $(BOOT_OBJ_DIR) ]; then mkdir -p $(BOOT_OBJ_DIR); fi + $(CC) -c $< $(GLOBAL_CFLAGS) -I. -Iinclude -o $@ + +$(FINAL_ASMINCLUDE): $(SEMIFINAL) tools + $(BIN2ASM) < $(SEMIFINAL) > $(FINAL_ASMINCLUDE) + +finalclean: + rm -f $(STAGE1_OBJS) $(FINAL) $(SEMIFINAL) $(FINAL_ASMINCLUDE) + +CLEAN += finalclean + +# +$(BOOT_OBJ_DIR)/%.o: $(BOOT_DIR)/%.c + @if [ ! -d $(BOOT_OBJ_DIR) ]; then mkdir -p $(BOOT_OBJ_DIR); fi + $(CC) -c $< $(GLOBAL_CFLAGS) -Iinclude -o $@ + +$(BOOT_OBJ_DIR)/%.d: $(BOOT_DIR)/%.c + @if [ ! -d $(BOOT_OBJ_DIR) ]; then mkdir -p $(BOOT_OBJ_DIR); fi + @echo "making deps for $<..." + @($(ECHO) -n $(dir $@);$(CC) $(GLOBAL_CFLAGS) -Iinclude -M -MG $<) > $@ + +$(BOOT_OBJ_DIR)/%.d: $(BOOT_DIR)/%.S + @if [ ! -d $(BOOT_OBJ_DIR) ]; then mkdir -p $(BOOT_OBJ_DIR); fi + @echo "making deps for $<..." + @($(ECHO) -n $(dir $@);$(CC) $(GLOBAL_CFLAGS) -Iinclude -M -MG $<) > $@ + +$(BOOT_OBJ_DIR)/%.o: $(BOOT_DIR)/%.S + @if [ ! -d $(BOOT_OBJ_DIR) ]; then mkdir -p $(BOOT_OBJ_DIR); fi + $(CC) -c $< $(GLOBAL_CFLAGS) -Iinclude -o $@ + +endif diff --git a/src/kernel/boot/arch/mips/config.ini b/src/kernel/boot/arch/mips/config.ini new file mode 100644 index 0000000000..90aa979ac1 --- /dev/null +++ b/src/kernel/boot/arch/mips/config.ini @@ -0,0 +1,24 @@ +# --------------------------------------------------------------- +# The bootstrap code is where control starts once netboot, boot.com, +# etc loads the image. It creates a page table to map the kernel in +# at 0x80000000 and then jumps to the kernel entrypoint where things +# really start happening. This MUST be the first entry in the .ini +# +[bootstrap] +type=boot +file=boot/mips/obj.mips/stage2 +ventry=128 + +[kernel] +type=code +file=kernel/obj.mips/system +ventry=128 + +[testapp] +type=code +file=apps/testapp/obj.mips/testapp +ventry=116 + +[testfile] +type=data +file=boot/testfile diff --git a/src/kernel/boot/arch/mips/stage1.S b/src/kernel/boot/arch/mips/stage1.S new file mode 100644 index 0000000000..ceb8480e75 --- /dev/null +++ b/src/kernel/boot/arch/mips/stage1.S @@ -0,0 +1,14 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +.text +.globl _start +_start: + j 0x88004074; // start of the stage2 bootloader + nop + +.data +foo: +#include "boot/mips/final.asminclude" + diff --git a/src/kernel/boot/arch/mips/stage1.ld b/src/kernel/boot/arch/mips/stage1.ld new file mode 100644 index 0000000000..e403469394 --- /dev/null +++ b/src/kernel/boot/arch/mips/stage1.ld @@ -0,0 +1,44 @@ +OUTPUT_FORMAT("elf32-bigmips", "elf32-bigmips", "elf32-bigmips") +OUTPUT_ARCH(mips) + +/* +PHDRS +{ + reginfo 0x70000000; + text PT_LOAD; +} +*/ + +ENTRY(_start) +SECTIONS +{ + + . = 0x88002000; + + /* text/read-only data */ + .text : { *(.text .gnu.linkonce.t.*) } + + __ctor_list = .; + .ctors : { *(.ctors) } + __ctor_end = .; + + .rodata : + { + *(.rodata) + . = ALIGN(0x1000); + } =0x9000 + + /* writable data */ + __data_start = .; + .data : { *(.data .gnu.linkonce.d.*) } + + /* unintialized data (in same segment as writable data) */ + __bss_start = .; + .bss : { *(.bss) } + + . = ALIGN(0x1000); + _end = . ; + + /* Strip unnecessary stuff */ + /DISCARD/ : { *(.reginfo .comment .note .eh_frame .dtors) } +} diff --git a/src/kernel/boot/arch/mips/stage2.c b/src/kernel/boot/arch/mips/stage2.c new file mode 100644 index 0000000000..6785475238 --- /dev/null +++ b/src/kernel/boot/arch/mips/stage2.c @@ -0,0 +1,28 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +static int stack[1024]; + +asm(" +.text +.globl _start +_start: + lw $sp,_stack_end_addr + j start + nop +_stack_end_addr: + .word stack+(1024*4) + +"); + +void start() +{ + int *a = stack; + int *b = 0; + *b = 4; + for(;;); +} + + diff --git a/src/kernel/boot/arch/mips/stage2.ld b/src/kernel/boot/arch/mips/stage2.ld new file mode 100644 index 0000000000..ce0e4ef9d1 --- /dev/null +++ b/src/kernel/boot/arch/mips/stage2.ld @@ -0,0 +1,40 @@ +OUTPUT_FORMAT("elf32-bigmips", "elf32-bigmips", "elf32-bigmips") +OUTPUT_ARCH(mips) + +ENTRY(_start) +SECTIONS +{ + + /* this is the starting address the SGI Indy puts the image at + + the size of the stage1 bootloader + + the size of the bootdir + + the size of the program headers */ + . = 0x88002000 + 0x2000 + SIZEOF_HEADERS; + + /* text/read-only data */ + .text : { *(.text .gnu.linkonce.t.*) } + + __ctor_list = .; + .ctors : { *(.ctors) } + __ctor_end = .; + + .rodata : + { + *(.rodata) + . = ALIGN(0x1000); + } =0x9000 + + /* writable data */ + __data_start = .; + .data : { *(.data .gnu.linkonce.d.*) } + + /* unintialized data (in same segment as writable data) */ + __bss_start = .; + .bss : { *(.bss) } + + . = ALIGN(0x1000); + _end = . ; + + /* Strip unnecessary stuff */ + /DISCARD/ : { *(.reginfo .comment .note .eh_frame .dtors) } +} diff --git a/src/kernel/boot/arch/ppc/Jamfile b/src/kernel/boot/arch/ppc/Jamfile new file mode 100644 index 0000000000..f01bdf8c45 --- /dev/null +++ b/src/kernel/boot/arch/ppc/Jamfile @@ -0,0 +1,2 @@ +SubDir OBOS_TOP sources os kits kernel boot arch ppc ; + diff --git a/src/kernel/boot/arch/ppc/boot.mk b/src/kernel/boot/arch/ppc/boot.mk new file mode 100644 index 0000000000..f252f29344 --- /dev/null +++ b/src/kernel/boot/arch/ppc/boot.mk @@ -0,0 +1,80 @@ +ifneq ($(_BOOT_MAKE),1) +_BOOT_MAKE = 1 + +# include targets we depend on +include lib/lib.mk +include kernel/kernel.mk +include apps/apps.mk + +# sh4 stage2 makefile +BOOT_DIR = boot/$(ARCH) +BOOT_OBJ_DIR = $(BOOT_DIR)/$(OBJ_DIR) +STAGE2_OBJS = $(BOOT_OBJ_DIR)/stage2.o \ + $(BOOT_OBJ_DIR)/stage2_asm.o \ + $(BOOT_OBJ_DIR)/stage2_mmu.o \ + $(BOOT_OBJ_DIR)/stage2_of.o \ + $(BOOT_OBJ_DIR)/stage2_text.o \ + $(BOOT_OBJ_DIR)/stage2_faults.o + +DEPS += $(STAGE2_OBJS:.o=.d) + +STAGE2 = $(BOOT_OBJ_DIR)/stage2 + +$(STAGE2): $(STAGE2_OBJS) $(LIBC) + $(LD) $(GLOBAL_LDFLAGS) -dN --script=$(BOOT_DIR)/stage2.ld -L $(LIBGCC_PATH) $(STAGE2_OBJS) $(LIBC) $(LIBGCC) -o $@ + +stage2: $(STAGE2) + +stage2clean: + rm -f $(STAGE2_OBJS) $(STAGE2) + +CLEAN += stage2clean + +SEMIFINAL = $(BOOT_DIR)/final.bootdir + +$(SEMIFINAL): $(STAGE2) $(KERNEL) $(APPS) tools + $(BOOTMAKER) --bigendian $(BOOT_DIR)/config.ini -o $(SEMIFINAL) + +STAGE1_OBJS = \ + $(BOOT_OBJ_DIR)/stage1.o + +DEPS += $(STAGE1_OBJS:.o=.d) + +FINAL = $(BOOT_DIR)/final + +$(FINAL): $(STAGE1_OBJS) + $(LD) $(GLOBAL_LDFLAGS) -dN --script=$(BOOT_DIR)/stage1.ld $(STAGE1_OBJS) -o $@ + +FINAL_ASMINCLUDE = $(BOOT_DIR)/final.asminclude + +$(FINAL_ASMINCLUDE): $(SEMIFINAL) tools + $(BIN2ASM) < $(SEMIFINAL) > $(FINAL_ASMINCLUDE) + +finalclean: + rm -f $(STAGE1_OBJS) $(FINAL) $(SEMIFINAL) $(FINAL_ASMINCLUDE) + +CLEAN += finalclean + +# +$(BOOT_OBJ_DIR)/stage1.o: $(BOOT_DIR)/stage1.S + @mkdir -p $(BOOT_OBJ_DIR) + $(CC) $(GLOBAL_CFLAGS) -g -I. -Iinclude -I$(BOOT_DIR) -c $< -o $@ + +$(BOOT_OBJ_DIR)/%.o: $(BOOT_DIR)/%.c + @mkdir -p $(BOOT_OBJ_DIR) + $(CC) $(GLOBAL_CFLAGS) -g -Iinclude -I$(BOOT_DIR) -c $< -o $@ + +$(BOOT_OBJ_DIR)/%.d: $(BOOT_DIR)/%.c + @mkdir -p $(BOOT_OBJ_DIR) + @echo "making deps for $<..." + @($(ECHO) -n $(dir $@);$(CC) $(GLOBAL_CFLAGS) -g -Iinclude -I$(BOOT_DIR) -M -MG $<) > $@ + +$(BOOT_OBJ_DIR)/%.d: $(BOOT_DIR)/%.S + @mkdir -p $(BOOT_OBJ_DIR) + @echo "making deps for $<..." + @($(ECHO) -n $(dir $@);$(CC) $(GLOBAL_CFLAGS) -g -Iinclude -I$(BOOT_DIR) -M -MG $<) > $@ + +$(BOOT_OBJ_DIR)/%.o: $(BOOT_DIR)/%.S + @mkdir -p $(BOOT_OBJ_DIR) + $(CC) $(GLOBAL_CFLAGS) -g -Iinclude -I$(BOOT_DIR) -c $< -o $@ +endif diff --git a/src/kernel/boot/arch/ppc/config.ini b/src/kernel/boot/arch/ppc/config.ini new file mode 100644 index 0000000000..d21922d74c --- /dev/null +++ b/src/kernel/boot/arch/ppc/config.ini @@ -0,0 +1,33 @@ +# --------------------------------------------------------------- +# The bootstrap code is where control starts once netboot, boot.com, +# etc loads the image. It creates a page table to map the kernel in +# at 0x80000000 and then jumps to the kernel entrypoint where things +# really start happening. This MUST be the first entry in the .ini +# +[bootstrap] +type=elf32 +file=boot/ppc/obj.ppc/stage2 + +#[kernel] +#type=elf32 +#file=kernel/obj.ppc/system + +#[init] +#type=elf32 +#file=apps/init/obj.ppc/init + +#[shell] +#type=elf32 +#file=apps/shell/obj.ppc/shell + +#[testapp] +#type=elf32 +#file=apps/testapp/obj.ppc/testapp + +#[vmtest] +#type=elf32 +#file=apps/vmtest/obj.ppc/vmtest + +#[testfile] +#type=data +#file=boot/testfile diff --git a/src/kernel/boot/arch/ppc/stage1.S b/src/kernel/boot/arch/ppc/stage1.S new file mode 100644 index 0000000000..fbf698f512 --- /dev/null +++ b/src/kernel/boot/arch/ppc/stage1.S @@ -0,0 +1,47 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#define BASE 0x100000 +#define BOOTDIR_BASE (BASE + 0x1000) +#define STAGE2_BOOTDIR_PAGE (BOOTDIR_BASE + 0x60) +#define STAGE2_OFFSET (BOOTDIR_BASE + 0x74) + +.text +.globl _start +_start: + lis 1,tempstack_end@ha /* load the new stack */ + ori 1,1,tempstack_end@l + + /* load the base of the bootdir */ + lis 8,BOOTDIR_BASE@ha + ori 8,8,BOOTDIR_BASE@l + + /* load the offset the stage2 will start into the bootdir */ + lis 9,STAGE2_BOOTDIR_PAGE@ha + ori 9,9,STAGE2_BOOTDIR_PAGE@l + lwz 9,0(9) + mulli 9,9,4096 + + /* load the offset into that page the stage2 entry point will be */ + lis 10,STAGE2_OFFSET@ha + ori 10,10,STAGE2_OFFSET@l + lwz 10,0(10) + + /* add them all together */ + add 11,8,9 + add 11,11,10 + + /* jump there */ + mtlr 11 + blr + +.align 4 +tempstack: + .skip 0x800 +tempstack_end: + +.data +#include "boot/ppc/final.asminclude" + diff --git a/src/kernel/boot/arch/ppc/stage1.ld b/src/kernel/boot/arch/ppc/stage1.ld new file mode 100644 index 0000000000..7cb34c95ef --- /dev/null +++ b/src/kernel/boot/arch/ppc/stage1.ld @@ -0,0 +1,32 @@ +OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc", "elf32-powerpc") +OUTPUT_ARCH(powerpc) + +ENTRY(_start) +SECTIONS +{ + . = 0x100000 + SIZEOF_HEADERS; + + /* text/read-only data */ + .text : { *(.text .gnu.linkonce.t.*) } + + __ctor_list = .; + .ctors : { *(.ctors) } + __ctor_end = .; + + .rodata : { *(.rodata) } + + /* writable data */ + . = ALIGN(0x1000); + __data_start = .; + .data : { *(.data .gnu.linkonce.d.*) } + + /* unintialized data (in same segment as writable data) */ + __bss_start = .; + .bss : { *(.bss) } + + . = ALIGN(0x1000); + _end = . ; + + /* Strip unnecessary stuff */ + /DISCARD/ : { *(.comment .note .eh_frame .dtors) } +} diff --git a/src/kernel/boot/arch/ppc/stage2.c b/src/kernel/boot/arch/ppc/stage2.c new file mode 100644 index 0000000000..b208c2d37e --- /dev/null +++ b/src/kernel/boot/arch/ppc/stage2.c @@ -0,0 +1,34 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include "stage2_priv.h" + +void _start(int arg1, int arg2, void *openfirmware); + +static kernel_args ka = {0}; + +void _start(int arg1, int arg2, void *openfirmware) +{ + int handle; + + memset(&ka, 0, sizeof(ka)); + + of_init(openfirmware); + s2_text_init(&ka); + + printf("Welcome to the stage2 bootloader!\n"); + + printf("arg1 0x%x, arg2 0x%x, openfirmware 0x%x\n", arg1, arg2, openfirmware); + + printf("msr = 0x%x\n", getmsr()); + + s2_mmu_init(&ka); + + for(;;); +} + diff --git a/src/kernel/boot/arch/ppc/stage2.ld b/src/kernel/boot/arch/ppc/stage2.ld new file mode 100644 index 0000000000..dcdbe62384 --- /dev/null +++ b/src/kernel/boot/arch/ppc/stage2.ld @@ -0,0 +1,32 @@ +OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc", "elf32-powerpc") +OUTPUT_ARCH(powerpc) + +ENTRY(_start) +SECTIONS +{ + . = 0x102000 + SIZEOF_HEADERS; + + /* text/read-only data */ + .text : { *(.text .gnu.linkonce.t.*) } + + __ctor_list = .; + .ctors : { *(.ctors) } + __ctor_end = .; + + .rodata : { *(.rodata) } + + /* writable data */ + . = ALIGN(0x1000); + __data_start = .; + .data : { *(.data .gnu.linkonce.d.*) } + + /* unintialized data (in same segment as writable data) */ + __bss_start = .; + .bss : { *(.bss) } + + . = ALIGN(0x1000); + _end = . ; + + /* Strip unnecessary stuff */ + /DISCARD/ : { *(.comment .note .eh_frame .dtors) } +} diff --git a/src/kernel/boot/arch/ppc/stage2_asm.S b/src/kernel/boot/arch/ppc/stage2_asm.S new file mode 100644 index 0000000000..89cf2daf32 --- /dev/null +++ b/src/kernel/boot/arch/ppc/stage2_asm.S @@ -0,0 +1,242 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +.text +// void getibats(int bats[8]); +.globl getibats +getibats: + mfibatu 0,0 + stw 0,0(3) + mfibatl 0,0 + stwu 0,4(3) + mfibatu 0,1 + stwu 0,4(3) + mfibatl 0,1 + stwu 0,4(3) + mfibatu 0,2 + stwu 0,4(3) + mfibatl 0,2 + stwu 0,4(3) + mfibatu 0,3 + stwu 0,4(3) + mfibatl 0,3 + stwu 0,4(3) + blr + +// void setibats(int bats[8]); +.globl setibats +setibats: + mfmsr 8 + li 0,0 + mtmsr 0 + + lwz 0,0(3) + mtibatu 0,0 + isync + lwzu 0,4(3) + mtibatl 0,0 + isync + lwzu 0,4(3) + mtibatu 1,0 + isync + lwzu 0,4(3) + mtibatl 1,0 + isync + lwzu 0,4(3) + mtibatu 2,0 + isync + lwzu 0,4(3) + mtibatl 2,0 + isync + lwzu 0,4(3) + mtibatu 3,0 + isync + lwzu 0,4(3) + mtibatl 3,0 + + isync + + mtmsr 8 + isync + blr + +// void getdbats(int bats[8]); +.globl getdbats +getdbats: + mfdbatu 0,0 + stw 0,0(3) + mfdbatl 0,0 + stwu 0,4(3) + mfdbatu 0,1 + stwu 0,4(3) + mfdbatl 0,1 + stwu 0,4(3) + mfdbatu 0,2 + stwu 0,4(3) + mfdbatl 0,2 + stwu 0,4(3) + mfdbatu 0,3 + stwu 0,4(3) + mfdbatl 0,3 + stwu 0,4(3) + blr + +// void setdbats(int bats[8]); +.globl setdbats +setdbats: + mfmsr 8 + li 0,0 + mtmsr 0 + + lwz 0,0(3) + mtdbatu 0,0 + lwzu 0,4(3) + mtdbatl 0,0 + lwzu 0,4(3) + mtdbatu 1,0 + lwzu 0,4(3) + mtdbatl 1,0 + lwzu 0,4(3) + mtdbatu 2,0 + lwzu 0,4(3) + mtdbatl 2,0 + lwzu 0,4(3) + mtdbatu 3,0 + lwzu 0,4(3) + mtdbatl 3,0 + + mtmsr 8 + sync + blr + +// unsigned int getsdr1(); +.globl getsdr1 +getsdr1: + mfsdr1 3 + blr + +// void setsdr1(unsigned int sdr); +.globl setsdr1 +setsdr1: + sync + mtsdr1 3 + sync + blr + +// unsigned int getsr(int sr); +.globl getsr +getsr: + mfsrin 3,3 + blr + +// unsigned int getmsr(); +.globl getmsr +getmsr: + mfmsr 3 + blr + +// void setmsr(unsigned int msr); +.globl setmsr +setmsr: + mtmsr 3 + blr + +.globl system_reset_exception_entry +system_reset_exception_entry: + lis 3,system_reset_exception@ha + ori 3,3,system_reset_exception@l + mtlr 3 + blr +.globl system_reset_exception_entry_end +system_reset_exception_entry_end: + +.globl machine_check_exception_entry +machine_check_exception_entry: + lis 3,machine_check_exception@ha + ori 3,3,machine_check_exception@l + mtlr 3 + blr +.globl machine_check_exception_entry_end +machine_check_exception_entry_end: + +.globl dsi_exception_entry +dsi_exception_entry: + lis 3,dsi_exception@ha + ori 3,3,dsi_exception@l + mtlr 3 + blr +.globl dsi_exception_entry_end +dsi_exception_entry_end: + +.globl isi_exception_entry +isi_exception_entry: + lis 3,isi_exception@ha + ori 3,3,isi_exception@l + mtlr 3 + blr +.globl isi_exception_entry_end +isi_exception_entry_end: + +.globl external_interrupt_entry +external_interrupt_entry: + lis 3,external_interrupt@ha + ori 3,3,external_interrupt@l + mtlr 3 + blr +.globl external_interrupt_entry_end +external_interrupt_entry_end: + +.globl alignment_exception_entry +alignment_exception_entry: + lis 3,alignment_exception@ha + ori 3,3,alignment_exception@l + mtlr 3 + blr +.globl alignment_exception_entry_end +alignment_exception_entry_end: + +.globl program_exception_entry +program_exception_entry: + lis 3,program_exception@ha + ori 3,3,program_exception@l + mtlr 3 + blr +.globl program_exception_entry_end +program_exception_entry_end: + +.globl decrementer_exception_entry +decrementer_exception_entry: + lis 3,decrementer_exception@ha + ori 3,3,decrementer_exception@l + mtlr 3 + blr +.globl decrementer_exception_entry_end +decrementer_exception_entry_end: + +.globl system_call_exception_entry +system_call_exception_entry: + lis 3,system_call_exception@ha + ori 3,3,system_call_exception@l + mtlr 3 + blr +.globl system_call_exception_entry_end +system_call_exception_entry_end: + +.globl trace_exception_entry +trace_exception_entry: + lis 3,trace_exception@ha + ori 3,3,trace_exception@l + mtlr 3 + blr +.globl trace_exception_entry_end +trace_exception_entry_end: + +.globl floating_point_assist_exception_entry +floating_point_assist_exception_entry: + lis 3,floating_point_assist_exception@ha + ori 3,3,floating_point_assist_exception@l + mtlr 3 + blr +.globl floating_point_assist_exception_entry_end +floating_point_assist_exception_entry_end: diff --git a/src/kernel/boot/arch/ppc/stage2_faults.c b/src/kernel/boot/arch/ppc/stage2_faults.c new file mode 100644 index 0000000000..d77ac17cd5 --- /dev/null +++ b/src/kernel/boot/arch/ppc/stage2_faults.c @@ -0,0 +1,141 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include "stage2_priv.h" + +void system_reset_exception_entry(); +extern int system_reset_exception_entry_end; +void machine_check_exception_entry(); +extern int machine_check_exception_entry_end; +void dsi_exception_entry(); +extern int dsi_exception_entry_end; +void isi_exception_entry(); +extern int isi_exception_entry_end; +void external_interrupt_entry(); +extern int external_interrupt_entry_end; +void alignment_exception_entry(); +extern int alignment_exception_entry_end; +void program_exception_entry(); +extern int program_exception_entry_end; +void decrementer_exception_entry(); +extern int decrementer_exception_entry_end; +void system_call_exception_entry(); +extern int system_call_exception_entry_end; +void trace_exception_entry(); +extern int trace_exception_entry_end; +void floating_point_assist_exception_entry(); +extern int floating_point_assist_exception_entry_end; + +void s2_faults_init(kernel_args *ka) +{ + printf("s2_faults_init: entry\n"); + setmsr(getmsr() & ~0x00000040); // make it look for exceptions in the zero page + printf("s2_faults_init: foo\n"); + printf("0x%x\n", *(unsigned int *)0x00000100); + printf("0x%x\n", *(unsigned int *)0x00000104); + printf("0x%x\n", *(unsigned int *)0x00000108); + printf("0x%x\n", *(unsigned int *)0x0000010c); + printf("%d\n", (int)&system_reset_exception_entry_end - (int)&system_reset_exception_entry); + memcpy((void *)0x00000100, &system_reset_exception_entry, + (int)&system_reset_exception_entry_end - (int)&system_reset_exception_entry); + printf("%d\n", + memcmp((void *)0x00000100, &system_reset_exception_entry, + (int)&system_reset_exception_entry_end - (int)&system_reset_exception_entry)); + printf("0x%x\n", *(unsigned int *)0x00000100); + printf("0x%x\n", *(unsigned int *)0x00000104); + printf("0x%x\n", *(unsigned int *)0x00000108); + printf("0x%x\n", *(unsigned int *)0x0000010c); + memcpy((void *)0x00000200, &machine_check_exception_entry, + (int)&machine_check_exception_entry_end - (int)&machine_check_exception_entry); + memcpy((void *)0x00000300, &dsi_exception_entry, + (int)&dsi_exception_entry_end - (int)&dsi_exception_entry); + memcpy((void *)0x00000400, &isi_exception_entry, + (int)&isi_exception_entry_end - (int)&isi_exception_entry); + memcpy((void *)0x00000500, &external_interrupt_entry, + (int)&external_interrupt_entry_end - (int)&external_interrupt_entry); + memcpy((void *)0x00000600, &alignment_exception_entry, + (int)&alignment_exception_entry_end - (int)&alignment_exception_entry); + memcpy((void *)0x00000700, &program_exception_entry, + (int)&program_exception_entry_end - (int)&program_exception_entry); + memcpy((void *)0x00000900, &decrementer_exception_entry, + (int)&decrementer_exception_entry_end - (int)&decrementer_exception_entry); + memcpy((void *)0x00000c00, &system_call_exception_entry, + (int)&system_call_exception_entry_end - (int)&system_call_exception_entry); + memcpy((void *)0x00000d00, &trace_exception_entry, + (int)&trace_exception_entry_end - (int)&trace_exception_entry); + memcpy((void *)0x00000e00, &floating_point_assist_exception_entry, + (int)&floating_point_assist_exception_entry_end - (int)&floating_point_assist_exception_entry); + printf("s2_faults_init: exit\n"); + + syncicache(0, 0x1000); +} + +void system_reset_exception() +{ + printf("system_reset_exception\n"); + for(;;); +} + +void machine_check_exception() +{ + printf("machine_check_exception\n"); + for(;;); +} + +void dsi_exception() +{ + *(int *)0x16008190 = 0xffffff; + printf("dsi_exception\n"); + for(;;); +} + +void isi_exception() +{ + printf("isi_exception\n"); + for(;;); +} + +void external_interrupt() +{ + printf("external_interrupt\n"); + for(;;); +} + +void alignment_exception() +{ + printf("alignment_exception\n"); + for(;;); +} + +void program_exception() +{ + printf("program_exception\n"); + for(;;); +} + +void decrementer_exception() +{ + printf("decrementer_exception\n"); + for(;;); +} + +void system_call_exception() +{ + printf("system_call_exception\n"); + for(;;); +} + +void trace_exception() +{ + printf("trace_exception\n"); + for(;;); +} + +void floating_point_assist_exception() +{ + printf("floating_point_assist_exception\n"); + for(;;); +} + diff --git a/src/kernel/boot/arch/ppc/stage2_mmu.c b/src/kernel/boot/arch/ppc/stage2_mmu.c new file mode 100644 index 0000000000..806bd925ad --- /dev/null +++ b/src/kernel/boot/arch/ppc/stage2_mmu.c @@ -0,0 +1,355 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include "stage2_priv.h" + +#define PAGE_SIZE 4096 + +static unsigned int primary_hash(unsigned int vsid, unsigned int vaddr); +static unsigned int secondary_hash(unsigned int primary_hash); + +// BAT register defs +#define BATU_BEPI_MASK 0xfffe0000 +#define BATU_LEN_256M 0x1ffc +#define BATU_VS 0x2 +#define BATU_VP 0x1 + +#define BATL_BRPN_MASK 0xfffe0000 +#define BATL_WIMG_MASK 0x78 +#define BATL_WT 0x40 +#define BATL_CI 0x20 +#define BATL_MC 0x10 +#define BATL_G 0x08 +#define BATL_PP_MASK 0x3 +#define BATL_PP_RO 0x1 +#define BATL_PP_RW 0x2 + +struct pte { + // pte lower word + unsigned int v : 1; + unsigned int vsid : 24; + unsigned int hash : 1; + unsigned int api : 6; + // pte upper word + unsigned int ppn : 20; + unsigned int unused : 3; + unsigned int r : 1; + unsigned int c : 1; + unsigned int wimg : 4; + unsigned int unused1 : 1; + unsigned int pp : 2; +}; +struct pteg { + struct pte pte[8]; +}; +static struct pteg *ptable = 0; +static int ptable_size = 0; +static unsigned int ptable_hash_mask = 0; + + +static unsigned long total_ram_size = 0; + +static void find_phys_memory_map(kernel_args *ka) +{ + int handle; + int i; + struct mem_region { + unsigned long pa; + int len; + } mem_regions[33]; + int mem_regions_len = 0; + + // get the physical memory map of the system + handle = of_finddevice("/memory"); + memset(mem_regions, 0, sizeof(mem_regions)); + mem_regions_len = of_getprop(handle, "reg", mem_regions, sizeof(mem_regions[0]) * 32); + mem_regions_len /= sizeof(struct mem_region); + + // copy these regions over to the kernel args structure + ka->num_phys_mem_ranges = 0; + for(i=0; i 0) { + total_ram_size += mem_regions[i].len; + if(i > 0) { + if(mem_regions[i].pa == ka->phys_mem_range[ka->num_phys_mem_ranges-1].start + ka->phys_mem_range[ka->num_phys_mem_ranges-1].size) { + // this range just extends the old one + ka->phys_mem_range[ka->num_phys_mem_ranges-1].size += mem_regions[i].len; + break; + } + } + ka->phys_mem_range[ka->num_phys_mem_ranges].start = mem_regions[i].pa; + ka->phys_mem_range[ka->num_phys_mem_ranges].size = mem_regions[i].len; + ka->num_phys_mem_ranges++; + if(ka->num_phys_mem_ranges == MAX_PHYS_MEM_ADDR_RANGE) { + printf("too many physical memory maps, increase MAX_PHYS_MEM_ADDR_RANGE\n"); + for(;;); + } + } + } + for(i=0; inum_phys_mem_ranges; i++) { + printf("phys map %d: pa 0x%x, len %d\n", i, ka->phys_mem_range[i].start, ka->phys_mem_range[i].size); + } +} + +static void find_used_phys_memory_map(kernel_args *ka) +{ + int handle; + int i; + struct translation_map { + unsigned long va; + int len; + unsigned long pa; + int mode; + } memmap[64]; + int translation_map_len = 0; + + // get the current translation map of the system, + // to find how much memory was mapped to load the stage1 and bootdir + handle = of_finddevice("/chosen"); + of_getprop(handle, "mmu", &handle, sizeof(handle)); + handle = of_instance_to_package(handle); + memset(&memmap, 0, sizeof(memmap)); + translation_map_len = of_getprop(handle, "translations", memmap, sizeof(memmap)); + translation_map_len /= sizeof(struct translation_map); + for(i=0; iphys_alloc_range[0].start = memmap[i].pa; + ka->phys_alloc_range[0].size = memmap[i].len; + ka->num_phys_alloc_ranges = 1; + } + } +} + +static void tlbia() +{ + unsigned long i; + + asm volatile("sync"); + for(i=0; i< 0x40000; i += 0x1000) { + asm volatile("tlbie %0" :: "r" (i)); + } + asm volatile("tlbsync"); + asm volatile("sync"); +} + +#define CACHELINE 64 + +void syncicache(void *address, int len) +{ + int l, off; + char *p; + + off = (unsigned int)address & (CACHELINE - 1); + len += off; + + l = len; + p = (char *)address - off; + do { + asm volatile ("dcbst 0,%0" :: "r"(p)); + p += CACHELINE; + } while((l -= CACHELINE) > 0); + asm volatile ("sync"); + p = (char *)address - off; + do { + asm volatile ("icbi 0,%0" :: "r"(p)); + p += CACHELINE; + } while((len -= CACHELINE) > 0); + asm volatile ("sync"); + asm volatile ("isync"); +} + +int s2_mmu_init(kernel_args *ka) +{ + unsigned int ibats[8]; + unsigned int dbats[8]; + int i; + + getibats(ibats); + getdbats(dbats); + + for(i=0; i<8; i++) { + ibats[0] = 0; + dbats[0] = 0; + } + // identity map the first 256Mb of RAM + ibats[0] = BATU_LEN_256M | BATU_VS; + dbats[0] = BATU_LEN_256M | BATU_VS; + ibats[1] = BATL_MC | BATL_PP_RW; + dbats[1] = BATL_MC | BATL_PP_RW; + + // XXX remove + ibats[2] = 0x10000000 | BATU_LEN_256M | BATU_VS; + dbats[2] = 0x10000000 | BATU_LEN_256M | BATU_VS; + ibats[3] = 0x90000000 | BATL_CI | BATL_PP_RW; + dbats[3] = 0x90000000 | BATL_CI | BATL_PP_RW; + + setibats(ibats); + setdbats(dbats); + + tlbia(); + + s2_faults_init(ka); + + // XXX remove + s2_change_framebuffer_addr(0x16008000); + + printf("msr = 0x%x\n", getmsr()); +// setmsr(getmsr() | 0x400); + printf("foo\n"); + + *(int *)0x30000000 = 5; + printf("here\n"); + + for(;;); + + // figure out where physical memory is and what is being used + find_phys_memory_map(ka); + find_used_phys_memory_map(ka); + + // allocate a page table + { + unsigned long top_ram = 0; + + // find the largest address of physical memory, but with a max of 256 MB, + // so it'll be within our 256 MB BAT window + for(i=0; inum_phys_mem_ranges; i++) { + if(ka->phys_mem_range[i].start + ka->phys_mem_range[i].size > top_ram) { + if(ka->phys_mem_range[i].start + ka->phys_mem_range[i].size > 256*1024*1024) { + if(ka->phys_mem_range[i].start < 256*1024*1024) { + top_ram = 256*1024*1024; + break; + } + } + top_ram = ka->phys_mem_range[i].start + ka->phys_mem_range[i].size; + } + } + printf("top of ram (but under 256Mb) is 0x%x\n", top_ram); + + // figure the size of the new pagetable, as recommended by Motorola + if(total_ram_size <= 8*1024*1024) { + ptable_size = 64*1024; + ptable_hash_mask = 0x0; + } else if(total_ram_size <= 16*1024*1024) { + ptable_size = 128*1024; + ptable_hash_mask = 0x1; + } else if(total_ram_size <= 32*1024*1024) { + ptable_size = 256*1024; + ptable_hash_mask = 0x3; + } else if(total_ram_size <= 64*1024*1024) { + ptable_size = 512*1024; + ptable_hash_mask = 0x7; + } else if(total_ram_size <= 128*1024*1024) { + ptable_size = 1024*1024; + ptable_hash_mask = 0xf; + } else if(total_ram_size <= 256*1024*1024) { + ptable_size = 2*1024*1024; + ptable_hash_mask = 0x1f; + } else if(total_ram_size <= 512*1024*1024) { + ptable_size = 4*1024*1024; + ptable_hash_mask = 0x3f; + } else if(total_ram_size <= 1024*1024*1024) { + ptable_size = 8*1024*1024; + ptable_hash_mask = 0x7f; + } else if(total_ram_size <= 2*1024*1024*1024) { + ptable_size = 16*1024*1024; + ptable_hash_mask = 0xff; + } else { + ptable_size = 32*1024*1024; + ptable_hash_mask = 0x1ff; + } + + ptable = (struct pteg *)(top_ram - ptable_size - 0x100000); + printf("ptable at pa 0x%x, size 0x%x\n", ptable, ptable_size); + printf("mask = 0x%x\n", ptable_hash_mask); + + printf("sdr1 = 0x%x\n", getsdr1()); + printf("msr = 0x%x\n", getmsr()); + + for(i=0; i<16; i++) { + printf("sr[%i] = 0x%x\n", i, getsr(i)); + } + printf("memsetting pagetable and performing switch\n"); + memset(ptable, 0, ptable_size); + + mmu_map_page(0, 0x96008000, 0x96008000); + mmu_map_page(0, 0x96009000, 0x96009000); + mmu_map_page(0, 0x9600a000, 0x9600a000); + mmu_map_page(0, 0x0, 0x30000000); + + printf("done, setting sdr1\n"); + setsdr1(((unsigned int)ptable & 0xffff0000) | ptable_hash_mask); + tlbia(); + printf("hello\n"); + printf("sdr1 = 0x%x\n", getsdr1()); + printf("%d\n", *(int *)0x30000000); + printf("%d\n", *(int *)0x96008000); + printf("hello2\n"); + + for(i=0; i<64; i++) { + *(char *)(0x96008000 + i) = i; + } + printf("foo\n"); + + } + return 0; +} + +void mmu_map_page(unsigned int vsid, unsigned long pa, unsigned long va) +{ + unsigned int hash; + struct pteg *pteg; + int i; + + printf("mmu_map_page: vsid %d, pa 0x%x, va 0x%x\n", vsid, pa, va); + + hash = primary_hash(0, va); + printf("hash = 0x%x\n", hash); + + pteg = &ptable[hash]; + printf("pteg @ 0x%x\n", pteg); + + // search for the first free slot for this pte + for(i=0; i<8; i++) { + printf("trying pteg[%i]\n", i); + if(pteg->pte[i].v == 0) { + // upper word + pteg->pte[i].ppn = pa / PAGE_SIZE; + pteg->pte[i].unused = 0; + pteg->pte[i].r = 0; + pteg->pte[i].c = 0; + pteg->pte[i].wimg = 0x4; + pteg->pte[i].unused1 = 0; + pteg->pte[i].pp = 0x2; // RW + asm volatile("eieio"); + // lower word + pteg->pte[i].vsid = vsid; + pteg->pte[i].hash = 0; // primary + pteg->pte[i].api = (va >> 22) & 0x3f; + pteg->pte[i].v = 1; + tlbia(); + printf("set pteg to 0x%x 0x%x\n", *((int *)&pteg->pte[i]), *(((int *)&pteg->pte[i])+1)); + return; + } + } +} + +static unsigned int primary_hash(unsigned int vsid, unsigned int vaddr) +{ + unsigned int page_index; + + vsid &= 0x7ffff; + page_index = (vaddr >> 12) & 0xffff; + + return (vsid ^ page_index) & ptable_hash_mask; +} + +static unsigned int secondary_hash(unsigned int primary_hash) +{ + return ~primary_hash; +} + diff --git a/src/kernel/boot/arch/ppc/stage2_of.c b/src/kernel/boot/arch/ppc/stage2_of.c new file mode 100644 index 0000000000..79d41bab2e --- /dev/null +++ b/src/kernel/boot/arch/ppc/stage2_of.c @@ -0,0 +1,197 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include "stage2_priv.h" + +static int (*of)(void *) = 0; // openfirmware entry + +int of_init(void *of_entry) +{ + of = of_entry; + return 0; +} + +int of_open(const char *node_name) +{ + struct { + const char *name; + int num_args; + int num_returns; + const char *node_name; + int handle; + } args; + + args.name = "open"; + args.num_args = 1; + args.num_returns = 1; + args.node_name = node_name; + + of(&args); + + return args.handle; +} + +int of_finddevice(const char *dev) +{ + struct { + const char *name; + int num_args; + int num_returns; + const char *device; + int handle; + } args; + + args.name = "finddevice"; + args.num_args = 1; + args.num_returns = 1; + args.device = dev; + + of(&args); + + return args.handle; +} + +int of_instance_to_package(int in_handle) +{ + struct { + const char *name; + int num_args; + int num_returns; + int in_handle; + int handle; + } args; + + args.name = "instance-to-package"; + args.num_args = 1; + args.num_returns = 1; + args.in_handle = in_handle; + + of(&args); + + return args.handle; +} + +int of_getprop(int handle, const char *prop, void *buf, int buf_len) +{ + struct { + const char *name; + int num_args; + int num_returns; + int handle; + const char *prop; + void *buf; + int buf_len; + int size; + } args; + + args.name = "getprop"; + args.num_args = 4; + args.num_returns = 1; + args.handle = handle; + args.prop = prop; + args.buf = buf; + args.buf_len = buf_len; + + of(&args); + + return args.size; +} + +int of_setprop(int handle, const char *prop, const void *buf, int buf_len) +{ + struct { + const char *name; + int num_args; + int num_returns; + int handle; + const char *prop; + const void *buf; + int buf_len; + int size; + } args; + + args.name = "setprop"; + args.num_args = 4; + args.num_returns = 1; + args.handle = handle; + args.prop = prop; + args.buf = buf; + args.buf_len = buf_len; + + of(&args); + + return args.size; +} + +int of_read(int handle, void *buf, int buf_len) +{ + struct { + const char *name; + int num_args; + int num_returns; + int handle; + void *buf; + int buf_len; + int size; + } args; + + args.name = "read"; + args.num_args = 3; + args.num_returns = 1; + args.handle = handle; + args.buf = buf; + args.buf_len = buf_len; + + of(&args); + + return args.size; +} + +int of_write(int handle, void *buf, int buf_len) +{ + struct { + const char *name; + int num_args; + int num_returns; + int handle; + void *buf; + int buf_len; + int size; + } args; + + args.name = "write"; + args.num_args = 3; + args.num_returns = 1; + args.handle = handle; + args.buf = buf; + args.buf_len = buf_len; + + of(&args); + + return args.size; +} + +int of_seek(int handle, long long pos) +{ + struct { + const char *name; + int num_args; + int num_returns; + int handle; + long long pos; + int status; + } args; + + args.name= "seek"; + args.num_args = 3; + args.num_returns = 1; + args.handle = handle; + args.pos = pos; + + of(&args); + + return args.status; +} + diff --git a/src/kernel/boot/arch/ppc/stage2_text.c b/src/kernel/boot/arch/ppc/stage2_text.c new file mode 100644 index 0000000000..f36b9ea25d --- /dev/null +++ b/src/kernel/boot/arch/ppc/stage2_text.c @@ -0,0 +1,242 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include "stage2_priv.h" + +unsigned char FONT[] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, /* '!' */ +0x00, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* '"' */ +0x00, 0x00, 0x14, 0x14, 0x3e, 0x14, 0x3e, 0x14, 0x14, 0x00, 0x00, 0x00, /* '#' */ +0x00, 0x00, 0x08, 0x3c, 0x0a, 0x1c, 0x28, 0x1e, 0x08, 0x00, 0x00, 0x00, /* '$' */ +0x00, 0x00, 0x06, 0x26, 0x10, 0x08, 0x04, 0x32, 0x30, 0x00, 0x00, 0x00, /* '%' */ +0x00, 0x00, 0x1c, 0x02, 0x02, 0x04, 0x2a, 0x12, 0x2c, 0x00, 0x00, 0x00, /* '&' */ +0x00, 0x18, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ''' */ +0x20, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, 0x10, 0x20, 0x00, /* '(' */ +0x02, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x02, 0x00, /* ')' */ +0x00, 0x00, 0x00, 0x08, 0x2a, 0x1c, 0x2a, 0x08, 0x00, 0x00, 0x00, 0x00, /* '*' */ +0x00, 0x00, 0x00, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* '+' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x08, 0x04, 0x00, /* ',' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* '-' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, /* '.' */ +0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x04, 0x02, 0x02, 0x00, 0x00, /* '/' */ +0x00, 0x1c, 0x22, 0x32, 0x2a, 0x26, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* '0' */ +0x00, 0x08, 0x0c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, /* '1' */ +0x00, 0x1c, 0x22, 0x20, 0x10, 0x08, 0x04, 0x02, 0x3e, 0x00, 0x00, 0x00, /* '2' */ +0x00, 0x1c, 0x22, 0x20, 0x18, 0x20, 0x20, 0x22, 0x1c, 0x00, 0x00, 0x00, /* '3' */ +0x00, 0x10, 0x18, 0x18, 0x14, 0x14, 0x3e, 0x10, 0x38, 0x00, 0x00, 0x00, /* '4' */ +0x00, 0x3e, 0x02, 0x02, 0x1e, 0x20, 0x20, 0x22, 0x1c, 0x00, 0x00, 0x00, /* '5' */ +0x00, 0x18, 0x04, 0x02, 0x1e, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* '6' */ +0x00, 0x3e, 0x22, 0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x00, 0x00, 0x00, /* '7' */ +0x00, 0x1c, 0x22, 0x22, 0x1c, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* '8' */ +0x00, 0x1c, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x10, 0x0c, 0x00, 0x00, 0x00, /* '9' */ +0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, /* ':' */ +0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x08, 0x04, 0x00, /* ';' */ +0x00, 0x00, 0x00, 0x30, 0x0c, 0x03, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00, /* '<' */ +0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, /* '=' */ +0x00, 0x00, 0x00, 0x03, 0x0c, 0x30, 0x0c, 0x03, 0x00, 0x00, 0x00, 0x00, /* '>' */ +0x00, 0x1c, 0x22, 0x20, 0x10, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, /* '?' */ +0x00, 0x00, 0x1c, 0x22, 0x3a, 0x3a, 0x1a, 0x02, 0x1c, 0x00, 0x00, 0x00, /* '@' */ +0x00, 0x00, 0x08, 0x14, 0x22, 0x22, 0x3e, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'A' */ +0x00, 0x00, 0x1e, 0x22, 0x22, 0x1e, 0x22, 0x22, 0x1e, 0x00, 0x00, 0x00, /* 'B' */ +0x00, 0x00, 0x1c, 0x22, 0x02, 0x02, 0x02, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'C' */ +0x00, 0x00, 0x0e, 0x12, 0x22, 0x22, 0x22, 0x12, 0x0e, 0x00, 0x00, 0x00, /* 'D' */ +0x00, 0x00, 0x3e, 0x02, 0x02, 0x1e, 0x02, 0x02, 0x3e, 0x00, 0x00, 0x00, /* 'E' */ +0x00, 0x00, 0x3e, 0x02, 0x02, 0x1e, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, /* 'F' */ +0x00, 0x00, 0x1c, 0x22, 0x02, 0x32, 0x22, 0x22, 0x3c, 0x00, 0x00, 0x00, /* 'G' */ +0x00, 0x00, 0x22, 0x22, 0x22, 0x3e, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'H' */ +0x00, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, /* 'I' */ +0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'J' */ +0x00, 0x00, 0x22, 0x12, 0x0a, 0x06, 0x0a, 0x12, 0x22, 0x00, 0x00, 0x00, /* 'K' */ +0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x3e, 0x00, 0x00, 0x00, /* 'L' */ +0x00, 0x00, 0x22, 0x36, 0x2a, 0x2a, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'M' */ +0x00, 0x00, 0x22, 0x26, 0x26, 0x2a, 0x32, 0x32, 0x22, 0x00, 0x00, 0x00, /* 'N' */ +0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'O' */ +0x00, 0x00, 0x1e, 0x22, 0x22, 0x1e, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, /* 'P' */ +0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1c, 0x30, 0x00, 0x00, /* 'Q' */ +0x00, 0x00, 0x1e, 0x22, 0x22, 0x1e, 0x0a, 0x12, 0x22, 0x00, 0x00, 0x00, /* 'R' */ +0x00, 0x00, 0x1c, 0x22, 0x02, 0x1c, 0x20, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'S' */ +0x00, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, /* 'T' */ +0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'U' */ +0x00, 0x00, 0x22, 0x22, 0x22, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00, 0x00, /* 'V' */ +0x00, 0x00, 0x22, 0x22, 0x22, 0x2a, 0x2a, 0x36, 0x22, 0x00, 0x00, 0x00, /* 'W' */ +0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'X' */ +0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, /* 'Y' */ +0x00, 0x00, 0x3e, 0x20, 0x10, 0x08, 0x04, 0x02, 0x3e, 0x00, 0x00, 0x00, /* 'Z' */ +0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, /* '[' */ +0x02, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x00, 0x00, /* '\' */ +0x0e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0e, 0x00, /* ']' */ +0x00, 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* '^' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, /* '_' */ +0x00, 0x0c, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* '`' */ +0x00, 0x00, 0x00, 0x00, 0x3c, 0x22, 0x22, 0x32, 0x2c, 0x00, 0x00, 0x00, /* 'a' */ +0x00, 0x02, 0x02, 0x02, 0x1e, 0x22, 0x22, 0x22, 0x1e, 0x00, 0x00, 0x00, /* 'b' */ +0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x02, 0x02, 0x3c, 0x00, 0x00, 0x00, /* 'c' */ +0x00, 0x20, 0x20, 0x20, 0x3c, 0x22, 0x22, 0x22, 0x3c, 0x00, 0x00, 0x00, /* 'd' */ +0x00, 0x00, 0x00, 0x00, 0x1c, 0x22, 0x3e, 0x02, 0x1c, 0x00, 0x00, 0x00, /* 'e' */ +0x00, 0x38, 0x04, 0x04, 0x1e, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, /* 'f' */ +0x00, 0x00, 0x00, 0x00, 0x3c, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x20, 0x1c, /* 'g' */ +0x00, 0x02, 0x02, 0x02, 0x1e, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'h' */ +0x00, 0x08, 0x08, 0x00, 0x0c, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, /* 'i' */ +0x00, 0x10, 0x10, 0x00, 0x1c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0e, /* 'j' */ +0x00, 0x02, 0x02, 0x02, 0x12, 0x0a, 0x06, 0x0a, 0x12, 0x00, 0x00, 0x00, /* 'k' */ +0x00, 0x0c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, /* 'l' */ +0x00, 0x00, 0x00, 0x00, 0x16, 0x2a, 0x2a, 0x2a, 0x22, 0x00, 0x00, 0x00, /* 'm' */ +0x00, 0x00, 0x00, 0x00, 0x1a, 0x26, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'n' */ +0x00, 0x00, 0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'o' */ +0x00, 0x00, 0x00, 0x00, 0x1e, 0x22, 0x22, 0x22, 0x1e, 0x02, 0x02, 0x02, /* 'p' */ +0x00, 0x00, 0x00, 0x00, 0x3c, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x20, 0x20, /* 'q' */ +0x00, 0x00, 0x00, 0x00, 0x1a, 0x06, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, /* 'r' */ +0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x1c, 0x20, 0x1e, 0x00, 0x00, 0x00, /* 's' */ +0x00, 0x08, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x08, 0x30, 0x00, 0x00, 0x00, /* 't' */ +0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x32, 0x2c, 0x00, 0x00, 0x00, /* 'u' */ +0x00, 0x00, 0x00, 0x00, 0x36, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00, 0x00, /* 'v' */ +0x00, 0x00, 0x00, 0x00, 0x22, 0x2a, 0x2a, 0x2a, 0x14, 0x00, 0x00, 0x00, /* 'w' */ +0x00, 0x00, 0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, /* 'x' */ +0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x20, 0x1c, /* 'y' */ +0x00, 0x00, 0x00, 0x00, 0x3e, 0x10, 0x08, 0x04, 0x3e, 0x00, 0x00, 0x00, /* 'z' */ +0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x10, 0x10, 0x10, 0x10, 0x20, 0x00, /* '{' */ +0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, /* '|' */ +0x02, 0x04, 0x04, 0x04, 0x04, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x00, /* '}' */ +0x00, 0x04, 0x2a, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* '~' */ +0x00, 0x00, 0x00, 0x08, 0x08, 0x14, 0x14, 0x22, 0x3e, 0x00, 0x00, 0x00, /* '' */ +}; + +static unsigned char *framebuffer; +static unsigned char draw_color; +static unsigned char back_color; +static int char_x,char_y; +static int screen_size_x, screen_size_y; +static int num_cols, num_rows; + +#define CHAR_WIDTH 6 +#define CHAR_HEIGHT 12 + +static void draw_char(unsigned char c, int x, int y) +{ + int i,j; + unsigned char *base = &framebuffer[y*screen_size_x + x]; + unsigned char line; + + for(i=0; i> 1; + } + base += screen_size_x; + } +} + +int printf(const char *fmt, ...) +{ + int ret; + va_list args; + char temp[256]; + + va_start(args, fmt); + ret = vsprintf(temp,fmt,args); + va_end(args); + + puts(temp); + return ret; +} + +void puts(char *str) +{ + while(*str) { + putchar(*str); + str++; + } +} + +void putchar(char c) +{ + if(c == '\n') { + char_x = 0; + char_y++; + } else { + draw_char(c, char_x * CHAR_WIDTH, char_y * CHAR_HEIGHT); + char_x++; + } + if(char_x >= num_cols) { + char_x = 0; + char_y++; + } + if(char_y >= num_rows) { + // scroll up + memcpy(framebuffer, framebuffer + screen_size_x*CHAR_HEIGHT, screen_size_x * screen_size_y - screen_size_x*CHAR_HEIGHT); + memset(framebuffer + (screen_size_y-CHAR_HEIGHT)*screen_size_x, back_color, screen_size_x*CHAR_HEIGHT); + char_y--; + } + } + +int s2_text_init(kernel_args *ka) +{ + int i; + + framebuffer = (unsigned char *)0x96008000; + screen_size_x = 1024; + screen_size_y = 768; + back_color = 0x0; + draw_color = 0xff; + char_x = char_y = 0; + + num_cols = screen_size_x / CHAR_WIDTH; + num_rows = screen_size_y / CHAR_HEIGHT; + + for(i = 0; iarch_args.screen_x = 1024; + ka->arch_args.screen_y = 768; + ka->arch_args.screen_depth = 8; + ka->arch_args.framebuffer.start = (unsigned long)framebuffer; + ka->arch_args.framebuffer.size = ka->arch_args.screen_x * ka->arch_args.screen_y * ka->arch_args.screen_depth / 8; + + return 0; +} + +void s2_change_framebuffer_addr(unsigned int address) +{ + framebuffer = (unsigned char *)address; +} + diff --git a/src/kernel/boot/arch/sh4/Jamfile b/src/kernel/boot/arch/sh4/Jamfile new file mode 100644 index 0000000000..80748a5b29 --- /dev/null +++ b/src/kernel/boot/arch/sh4/Jamfile @@ -0,0 +1,2 @@ +SubDir OBOS_TOP sources os kits kernel boot arch sh4 ; + diff --git a/src/kernel/boot/arch/sh4/boot.mk b/src/kernel/boot/arch/sh4/boot.mk new file mode 100644 index 0000000000..ebbf8ea8ce --- /dev/null +++ b/src/kernel/boot/arch/sh4/boot.mk @@ -0,0 +1,80 @@ +ifneq ($(_BOOT_MAKE),1) +_BOOT_MAKE = 1 + +# include targets we depend on +include lib/lib.mk +include kernel/kernel.mk +include apps/apps.mk + +# sh4 stage2 makefile +BOOT_DIR = boot/$(ARCH) +BOOT_OBJ_DIR = $(BOOT_DIR)/$(OBJ_DIR) +STAGE2_OBJS = $(BOOT_OBJ_DIR)/stage2.o \ + $(BOOT_OBJ_DIR)/serial.o \ + $(BOOT_OBJ_DIR)/mmu.o \ + $(BOOT_OBJ_DIR)/vcpu.o \ + $(BOOT_OBJ_DIR)/vcpu_c.o +DEPS += $(STAGE2_OBJS:.o=.d) + +STAGE2 = $(BOOT_OBJ_DIR)/stage2 + +$(STAGE2): $(STAGE2_OBJS) $(KLIBS) + $(LD) $(GLOBAL_LDFLAGS) -dN --script=$(BOOT_DIR)/stage2.ld -L $(LIBGCC_PATH) $(STAGE2_OBJS) $(LINK_KLIBS) $(LIBGCC) -o $@ + +stage2: $(STAGE2) + +stage2clean: + rm -f $(STAGE2_OBJS) $(STAGE2) + +CLEAN += stage2clean + +SEMIFINAL = $(BOOT_DIR)/final.bootdir + +$(SEMIFINAL): $(STAGE2) $(KERNEL) $(KERNEL_ADDONS) $(APPS) tools + $(BOOTMAKER) $(BOOT_DIR)/config.ini -o $(SEMIFINAL) + +STAGE1_OBJS = \ + $(BOOT_OBJ_DIR)/stage1.o + +DEPS += $(STAGE1_OBJS:.o=.d) + +STAGE1 = $(BOOT_OBJ_DIR)/stage1 + +$(STAGE1): $(STAGE1_OBJS) + $(LD) $(GLOBAL_LDFLAGS) -N -Ttext 0x8c000000 $(STAGE1_OBJS) -o $(STAGE1) + +$(STAGE1).bin: $(STAGE1) + $(OBJCOPY) -O binary $(STAGE1) $@1 + dd if=/dev/zero of=$(STAGE1).bin bs=4096 count=1 2> /dev/null + dd if=$(STAGE1).bin1 of=$(STAGE1).bin conv=notrunc 2> /dev/null + rm $(STAGE1).bin1 + +stage1clean: + rm -f $(STAGE1_OBJS) $(STAGE1) $(STAGE1).bin $(STAGE1).bin1 + +CLEAN += stage1clean + +FINAL = $(BOOT_DIR)/final + +$(FINAL): $(SEMIFINAL) $(STAGE1).bin + cat $(STAGE1).bin $(SEMIFINAL) > $(FINAL) + +# +$(BOOT_OBJ_DIR)/%.o: $(BOOT_DIR)/%.c + @mkdir -p $(BOOT_OBJ_DIR) + $(CC) $(GLOBAL_CFLAGS) -Iinclude -Iinclude/nulibc -I$(BOOT_DIR) -c $< -o $@ + +$(BOOT_OBJ_DIR)/%.d: $(BOOT_DIR)/%.c + @mkdir -p $(BOOT_OBJ_DIR) + @echo "making deps for $<..." + @($(ECHO) -n $(dir $@);$(CC) $(GLOBAL_CFLAGS) -Iinclude -Iinclude/nulibc -I$(BOOT_DIR) -M -MG $<) > $@ + +$(BOOT_OBJ_DIR)/%.d: $(BOOT_DIR)/%.S + @mkdir -p $(BOOT_OBJ_DIR) + @echo "making deps for $<..." + @($(ECHO) -n $(dir $@);$(CC) $(GLOBAL_CFLAGS) -Iinclude -Iinclude/nulibc -I$(BOOT_DIR) -M -MG $<) > $@ + +$(BOOT_OBJ_DIR)/%.o: $(BOOT_DIR)/%.S + @mkdir -p $(BOOT_OBJ_DIR) + $(CC) $(GLOBAL_CFLAGS) -Iinclude -Iinclude/nulibc -I$(BOOT_DIR) -c $< -o $@ +endif diff --git a/src/kernel/boot/arch/sh4/config.ini b/src/kernel/boot/arch/sh4/config.ini new file mode 100644 index 0000000000..538a98ead4 --- /dev/null +++ b/src/kernel/boot/arch/sh4/config.ini @@ -0,0 +1,102 @@ +# --------------------------------------------------------------- +# The bootstrap code is where control starts once netboot, boot.com, +# etc loads the image. It creates a page table to map the kernel in +# at 0x80000000 and then jumps to the kernel entrypoint where things +# really start happening. This MUST be the first entry in the .ini +# +[bootstrap] +type=elf32 +file=build/sh4/boot/stage2 + +[kernel] +type=elf32 +file=build/sh4/kernel/kernel + +[addons/fs/iso9660] +type=elf32 +file=build/sh4/kernel/addons/fs/iso9660/iso9660 + +[addons/fs/zfs] +type=elf32 +file=build/sh4/kernel/addons/fs/zfs/zfs + +[bin/init] +type=elf32 +file=build/sh4/apps/init/init + +[bin/shell] +type=elf32 +file=build/sh4/apps/shell/shell + +[bin/ls] +type=elf32 +file=build/sh4/apps/ls/ls + +[bin/mount] +type=elf32 +file=build/sh4/apps/mount/mount + +[bin/unmount] +type=elf32 +file=build/sh4/apps/unmount/unmount + +[bin/fortune] +type=elf32 +file=build/sh4/apps/fortune/fortune + +[etc/fortunes] +type=data +file=apps/fortune/fortunes + +[bin/testapp] +type=elf32 +file=build/sh4/apps/testapp/testapp + +[bin/true] +type=elf32 +file=build/sh4/apps/true/true + +[bin/false] +type=elf32 +file=build/sh4/apps/false/false + +[bin/vmtest] +type=elf32 +file=build/sh4/apps/vmtest/vmtest + +[bin/fibo] +type=elf32 +file=build/sh4/apps/fibo/fibo + +[libexec/rld.so] +type=elf32 +file=build/sh4/apps/rld/rld.so + +[bin/rldtest] +type=elf32 +file=build/sh4/apps/rldtest/rldtest + +[lib/librldtest.so] +type=elf32 +file=build/sh4/apps/rldtest/librldtest.so + +[lib/girlfriend.so] +type=elf32 +file=build/sh4/apps/rldtest/girlfriend.so + +[lib/libc.so] +type=elf32 +file=build/sh4/lib/libc/libc.so + +[lib/libm.so] +type=elf32 +file=build/sh4/lib/libm/libm.so + +[testfile] +type=data +file=boot/testfile + +[test.iso] +type=data +file=boot/test.iso + diff --git a/src/kernel/boot/arch/sh4/mmu.c b/src/kernel/boot/arch/sh4/mmu.c new file mode 100644 index 0000000000..7ab24125d6 --- /dev/null +++ b/src/kernel/boot/arch/sh4/mmu.c @@ -0,0 +1,81 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include + +#include +#include +#include +#include +#include "serial.h" +#include "mmu.h" + +#define KERNEL_LOAD_ADDR 0xc0000000 + +struct pdent *pd = 0; + +void mmu_map_page(unsigned int vaddr, unsigned int paddr) +{ + struct ptent *pt; + int index; + + vaddr &= 0xfffff000; + paddr &= 0xfffff000; + dprintf("mmu_map_page: mapping 0x%x to 0x%x\n", paddr, vaddr); + + if(vaddr < P1_AREA) { + dprintf("mmu_map_page: cannot map user space now!\n"); + for(;;); + } + + vaddr &= 0x7fffffff; + + index = vaddr >> 22; + if(pd[index].v == 0) { + dprintf("mmu_map_page: no page dir exists for this address\n"); + for(;;); + } + + pt = (struct ptent *)PHYS_ADDR_TO_P1(pd[index].ppn << 12); + + index = (vaddr >> 12) & 0x00000fff; + pt[index].wt = 0; + pt[index].pr = 1; // rw, supervisor only + pt[index].ppn = paddr >> 12; + pt[index].tlb_ent = 0; + pt[index].c = 1; + pt[index].sz = 1; // 4k page + pt[index].sh = 0; + pt[index].d = 0; + pt[index].v = 1; +} + +void mmu_init(kernel_args *ka, unsigned int *next_paddr) +{ + struct ptent *pt; + int index; + + dprintf("mmu_init: entry\n"); + + // allocate a kernel pgdir + ka->arch_args.vcpu->kernel_pgdir = (unsigned int *)PHYS_ADDR_TO_P1(*next_paddr); + (*next_paddr) += PAGE_SIZE; + + pd = (struct pdent *)ka->arch_args.vcpu->kernel_pgdir; + memset(pd, 0, sizeof(struct pdent) * 512); + + dprintf("kernel_pgdir = 0x%x\n", ka->arch_args.vcpu->kernel_pgdir); + + // allocate an initial page table + pt = (struct ptent *)PHYS_ADDR_TO_P1(*next_paddr); + memset(pt, 0, sizeof(struct ptent) * 1024); + (*next_paddr) += PAGE_SIZE; + + dprintf("intial page table = 0x%x\n", pt); + + index = (KERNEL_LOAD_ADDR & 0x7fffffff) >> 22; + pd[index].ppn = (unsigned int)pt >> 12; + pd[index].v = 1; +} + diff --git a/src/kernel/boot/arch/sh4/serial.c b/src/kernel/boot/arch/sh4/serial.c new file mode 100644 index 0000000000..289c5196ba --- /dev/null +++ b/src/kernel/boot/arch/sh4/serial.c @@ -0,0 +1,109 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include "serial.h" + +int dprintf(const char *fmt, ...) +{ + int ret = 0; + va_list args; + char temp[128]; + + va_start(args, fmt); + ret = vsprintf(temp, fmt, args); + va_end(args); + + serial_puts(temp); + return ret; +} + +int serial_init() +{ + volatile unsigned short *scif16 = (unsigned short*)0xffe80000; + volatile unsigned char *scif8 = (unsigned char*)0xffe80000; + int x; + + /* Disable interrupts, transmit/receive, and use internal clock */ + scif16[8/2] = 0; + + /* 8N1, use P0 clock */ + scif16[0] = 0; + + /* Set baudrate, N = P0/(32*B)-1 */ +// scif8[4] = (50000000 / (32 * baud_rate)) - 1; + +// scif8[4] = 80; // 19200 +// scif8[4] = 40; // 38400 +// scif8[4] = 26; // 57600 + scif8[4] = 13; // 115200 + + /* Reset FIFOs, enable hardware flow control */ + scif16[24/2] = 4; //12; + + for(x = 0; x < 100000; x++); + scif16[24/2] = 0; //8; + + /* Disable manual pin control */ + scif16[32/2] = 0; + + /* Clear status */ + scif16[16/2] = 0x60; + scif16[36/2] = 0; + + /* Enable transmit/receive */ + scif16[8/2] = 0x30; + + for(x = 0; x < 100000; x++); + + serial_puts("serial initted\n"); + + return 0; +} + +/* Flush all FIFO'd bytes out of the serial port buffer */ +static void serial_flush() { + volatile unsigned short *ack = (unsigned short*)0xffe80010; + + *ack &= 0xbf; + while (!(*ack & 0x40)) + ; + *ack &= 0xbf; +} + +static void _serial_putch(const char c) +{ + volatile unsigned short *ack = (unsigned short*)0xffe80010; + volatile unsigned char *fifo = (unsigned char*)0xffe8000c; + + /* Wait until the transmit buffer has space */ + while (!(*ack & 0x20)) + ; + /* Send the char */ + *fifo = c; + + /* Clear status */ + *ack &= 0x9f; +} + +char serial_putch(const char c) +{ + if (c == '\n') { + _serial_putch('\r'); + _serial_putch('\n'); + } else if (c != '\r') + _serial_putch(c); + + return c; +} + +void serial_puts(const char *s) +{ + while(*s != '\0') { + serial_putch(*s); + s++; + } +} + diff --git a/src/kernel/boot/arch/sh4/stage1.S b/src/kernel/boot/arch/sh4/stage1.S new file mode 100644 index 0000000000..24d3b1467d --- /dev/null +++ b/src/kernel/boot/arch/sh4/stage1.S @@ -0,0 +1,39 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +/* addresses of values stored in the bootdir, which starts on the next + page after this code. */ +#define BASE 0x8c000000 +#define BOOTDIR_BASE (BASE + 0x1000) +#define STAGE2_BOOTDIR_PAGE (BOOTDIR_BASE + 0x60) +#define STAGE2_OFFSET (BOOTDIR_BASE + 0x74) +.text + +start: + mov.l bootdir_base,r0 + + /* load and calculate the offset of the stage2 bootloader into the bootdir */ + mov.l page_addr_addr,r1 + mov.l @r1,r1 + shll8 r1 + shll2 r1 + shll2 r1 /* multiply the offset address by 4096 */ + + /* find the offset into the stage2 bootloader where the entry point is */ + mov.l offset_addr,r2 + mov.l @r2,r2 + + /* add all of these numbers together and jump to it */ + add r1,r0 + add r2,r0 + jmp @r0 + nop + +.align 2 +bootdir_base: + .long BOOTDIR_BASE +page_addr_addr: + .long STAGE2_BOOTDIR_PAGE +offset_addr: + .long STAGE2_OFFSET diff --git a/src/kernel/boot/arch/sh4/stage2.c b/src/kernel/boot/arch/sh4/stage2.c new file mode 100644 index 0000000000..1eefce08b8 --- /dev/null +++ b/src/kernel/boot/arch/sh4/stage2.c @@ -0,0 +1,213 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "serial.h" +#include "mmu.h" + +#define BOOTDIR 0x8c001000 +#define P2_AREA 0x8c000000 +#define PHYS_ADDR_START 0x0c000000 + +#define ROUNDUP(a, b) (((a) + ((b)-1)) & ~((b)-1)) +#define ROUNDOWN(a, b) (((a) / (b)) * (b)) + +void test_interrupt(); +void switch_stacks_and_call(unsigned int stack, unsigned int call_addr, unsigned int call_arg, unsigned int call_arg2); + +void load_elf_image(void *data, unsigned int *next_paddr, addr_range *ar0, addr_range *ar1, unsigned int *start_addr, addr_range *dynamic_section); + +int _start() +{ + unsigned int i; + boot_entry *bootdir = (boot_entry *)BOOTDIR; + unsigned int bootdir_len; + unsigned int next_vaddr; + unsigned int next_paddr; + unsigned int kernel_entry; + kernel_args *ka; + + serial_init(); + + serial_puts("Stage 2 loader entry\n"); + + // look at the bootdir + bootdir_len = 1; // account for bootdir directory + for(i=0; i<64; i++) { + if(bootdir[i].be_type == BE_TYPE_NONE) + break; + bootdir_len += bootdir[i].be_size; + } + + dprintf("bootdir is %d pages long\n", bootdir_len); + next_paddr = PHYS_ADDR_START + bootdir_len * PAGE_SIZE; + + // find a location for the kernel args + ka = (kernel_args *)(P2_AREA + bootdir_len * PAGE_SIZE); + memset(ka, 0, sizeof(kernel_args)); + next_paddr += PAGE_SIZE; + + // initialize the vcpu + vcpu_init(ka); + mmu_init(ka, &next_paddr); + + // map the kernel text & data + load_elf_image((void *)(bootdir[2].be_offset * PAGE_SIZE + BOOTDIR), &next_paddr, + &ka->kernel_seg0_addr, &ka->kernel_seg1_addr, &kernel_entry, &ka->kernel_dynamic_section_addr); + dprintf("mapped kernel from 0x%x to 0x%x\n", ka->kernel_seg0_addr.start, ka->kernel_seg1_addr.start + ka->kernel_seg1_addr.size); + dprintf("kernel entry @ 0x%x\n", kernel_entry); + +#if 0 + dprintf("diffing the mapped memory\n"); + dprintf("memcmp = %d\n", memcmp((void *)KERNEL_LOAD_ADDR, (void *)BOOTDIR + bootdir[2].be_offset * PAGE_SIZE, PAGE_SIZE)); + dprintf("done diffing the memory\n"); +#endif + + next_vaddr = ROUNDUP(ka->kernel_seg1_addr.start + ka->kernel_seg1_addr.size, PAGE_SIZE); + + // map in a kernel stack + ka->cpu_kstack[0].start = next_vaddr; + for(i=0; i<2; i++) { + mmu_map_page(next_vaddr, next_paddr); + next_vaddr += PAGE_SIZE; + next_paddr += PAGE_SIZE; + } + ka->cpu_kstack[0].size = next_vaddr - ka->cpu_kstack[0].start; + + // record this first region of allocation space + ka->phys_alloc_range[0].start = PHYS_ADDR_START; + ka->phys_alloc_range[0].size = next_paddr - PHYS_ADDR_START; + ka->num_phys_alloc_ranges = 1; + ka->virt_alloc_range[0].start = ka->kernel_seg0_addr.start; + ka->virt_alloc_range[0].size = next_vaddr - ka->virt_alloc_range[0].start; + ka->virt_alloc_range[1].start = ka->kernel_seg1_addr.start; + ka->virt_alloc_range[1].size = next_vaddr - ka->virt_alloc_range[1].start; + ka->num_virt_alloc_ranges = 2; + + ka->fb.enabled = 1; + ka->fb.x_size = 640; + ka->fb.y_size = 480; + ka->fb.bit_depth = 16; + ka->fb.mapping.start = 0xa5000000; + ka->fb.mapping.size = ka->fb.x_size * ka->fb.y_size * 2; + ka->fb.already_mapped = 1; + + ka->cons_line = 0; + ka->str = 0; + ka->bootdir_addr.start = P1_TO_PHYS_ADDR(BOOTDIR); + ka->bootdir_addr.size = bootdir_len * PAGE_SIZE; + ka->phys_mem_range[0].start = PHYS_ADDR_START; + ka->phys_mem_range[0].size = 16*1024*1024; + ka->num_phys_mem_ranges = 1; + ka->num_cpus = 1; + + for(i=0; inum_phys_alloc_ranges; i++) { + dprintf("prange %d start = 0x%x, size = 0x%x\n", + i, ka->phys_alloc_range[i].start, ka->phys_alloc_range[i].size); + } + + for(i=0; inum_virt_alloc_ranges; i++) { + dprintf("vrange %d start = 0x%x, size = 0x%x\n", + i, ka->virt_alloc_range[i].start, ka->virt_alloc_range[i].size); + } + + dprintf("switching stack to 0x%x and calling 0x%x\n", + ka->cpu_kstack[0].start + ka->cpu_kstack[0].size - 4, kernel_entry); + switch_stacks_and_call(ka->cpu_kstack[0].start + ka->cpu_kstack[0].size - 4, + kernel_entry, + (unsigned int)ka, + 0); + return 0; +} + +asm(".text\n" +".align 2\n" +"_switch_stacks_and_call:\n" +" mov r4,r15\n" +" mov r5,r1\n" +" mov r6,r4\n" +" jsr @r1\n" +" mov r7,r5"); + +void load_elf_image(void *data, unsigned int *next_paddr, addr_range *ar0, addr_range *ar1, unsigned int *start_addr, addr_range *dynamic_section) +{ + struct Elf32_Ehdr *imageHeader = (struct Elf32_Ehdr*) data; + struct Elf32_Phdr *segments = (struct Elf32_Phdr*)(imageHeader->e_phoff + (unsigned) imageHeader); + int segmentIndex; + int foundSegmentIndex = 0; + + ar0->size = 0; + ar1->size = 0; + dynamic_section->size = 0; + + for (segmentIndex = 0; segmentIndex < imageHeader->e_phnum; segmentIndex++) { + struct Elf32_Phdr *segment = &segments[segmentIndex]; + unsigned segmentOffset; + + switch(segment->p_type) { + case PT_LOAD: + break; + case PT_DYNAMIC: + dynamic_section->start = segment->p_vaddr; + dynamic_section->size = segment->p_memsz; + default: + continue; + } + + dprintf("segment %d\n", segmentIndex); + dprintf("p_offset 0x%x p_vaddr 0x%x p_paddr 0x%x p_filesz 0x%x p_memsz 0x%x\n", + segment->p_offset, segment->p_vaddr, segment->p_paddr, segment->p_filesz, segment->p_memsz); + + /* Map initialized portion */ + for (segmentOffset = 0; + segmentOffset < ROUNDUP(segment->p_filesz, PAGE_SIZE); + segmentOffset += PAGE_SIZE) { + + mmu_map_page(segment->p_vaddr + segmentOffset, *next_paddr); + memcpy((void *)ROUNDOWN(segment->p_vaddr + segmentOffset, PAGE_SIZE), + (void *)ROUNDOWN((unsigned)data + segment->p_offset + segmentOffset, PAGE_SIZE), PAGE_SIZE); + (*next_paddr) += PAGE_SIZE; + } + + /* Clean out the leftover part of the last page */ + if(((segment->p_vaddr + segment->p_filesz) % PAGE_SIZE) > 0) { + dprintf("memsetting 0 to va 0x%x, size %d\n", (void*)((unsigned)segment->p_vaddr + segment->p_filesz), + PAGE_SIZE - ((segment->p_vaddr + segment->p_filesz) % PAGE_SIZE)); + memset((void*)((unsigned)segment->p_vaddr + segment->p_filesz), 0, + PAGE_SIZE - ((segment->p_vaddr + segment->p_filesz) % PAGE_SIZE)); + } + + /* Map uninitialized portion */ + for (; segmentOffset < ROUNDUP(segment->p_memsz, PAGE_SIZE); segmentOffset += PAGE_SIZE) { + dprintf("mapping zero page at va 0x%x\n", segment->p_vaddr + segmentOffset); + mmu_map_page(segment->p_vaddr + segmentOffset, *next_paddr); + memset((void *)(segment->p_vaddr + segmentOffset), 0, PAGE_SIZE); + (*next_paddr) += PAGE_SIZE; + } + switch(foundSegmentIndex) { + case 0: + ar0->start = segment->p_vaddr; + ar0->size = segment->p_memsz; + break; + case 1: + ar1->start = segment->p_vaddr; + ar1->size = segment->p_memsz; + break; + default: + ; + } + foundSegmentIndex++; + } + *start_addr = imageHeader->e_entry; +} + diff --git a/src/kernel/boot/arch/sh4/stage2.ld b/src/kernel/boot/arch/sh4/stage2.ld new file mode 100644 index 0000000000..ebe352c1a0 --- /dev/null +++ b/src/kernel/boot/arch/sh4/stage2.ld @@ -0,0 +1,38 @@ +OUTPUT_FORMAT("elf32-shl", "elf32-shl", "elf32-shl") +OUTPUT_ARCH(sh) + PHDRS + { + text PT_LOAD; + data PT_LOAD; + } + +ENTRY(__start) +SECTIONS +{ +/* . = 0x8c100000 + 0x1200 + SIZEOF_HEADERS; */ + . = 0x8c000000 + 0x2000 + 0x80; + + /* text/read-only data */ + .text : { *(.text .gnu.linkonce.t.*) } + + .rodata : { *(.rodata) } + + /* writable data */ +/* . = ALIGN(0x1000);*/ + __ctor_list = .; + .ctors : { *(.ctors) } + __ctor_end = .; + + __data_start = .; + .data : { *(.data .gnu.linkonce.d.*) } + + /* unintialized data (in same segment as writable data) */ + __bss_start = .; + .bss : { *(.bss) } + + . = ALIGN(0x1000); + _end = . ; + + /* Strip unnecessary stuff */ + /DISCARD/ : { *(.comment .note .eh_frame .dtors) } +} diff --git a/src/kernel/boot/arch/sh4/vcpu.S b/src/kernel/boot/arch/sh4/vcpu.S new file mode 100644 index 0000000000..f307e77ac2 --- /dev/null +++ b/src/kernel/boot/arch/sh4/vcpu.S @@ -0,0 +1,575 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#define SAVE_CPU_STATE 0 + +.text +.align 2 + +.globl _vector_base +_vector_base: + .skip 0x100 +exception_ent_1: + mov.l expevt_addr1,r0 + mov.l @r0,r0 + shlr2 r0 + shlr r0 /* shift the exception code over 3 bits */ + + cmp/eq #0x10,r0 /* test if its a initial page write */ + bt _tlb_ipw + nop + + /* not a inital page write exception */ + /* just enter the kernel and let it deal with it */ + bra switch_banks_and_enter_kernel + nop + +_tlb_ipw: + /* deal with inital page write exception */ + /* we can stay on reg bank 1, switch to a tlb stack */ + mov.l tlb_stack_addr1,r15 + + /* save some of the floating point registers */ + /* they seem to be used by some of the libgcc stuff */ + /* saving: fpscr, fpul, dr0, dr2, dr4 */ + fmov.s fr0,@-r15 + fmov.s fr1,@-r15 + fmov.s fr2,@-r15 + fmov.s fr3,@-r15 + fmov.s fr4,@-r15 + fmov.s fr5,@-r15 + sts.l fpul,@-r15 + sts.l fpscr,@-r15 + + mov r0,r4 /* arg 1, excode */ + shlr2 r4 /* shift arg 1 over two more bits */ + mov.l r4,@-r15 /* save the excode for after the call */ + sts.l pr,@-r15 /* save the pr reg */ + stc spc,r5 /* arg 2, spc */ + mov.l initial_page_write_handler,r1 + jsr @r1 + nop + + /* restore regs */ + lds.l @r15+,pr + mov.l @r15+,r1 + lds.l @r15+,fpscr + lds.l @r15+,fpul + fmov.s @r15+,fr5 + fmov.s @r15+,fr4 + fmov.s @r15+,fr3 + fmov.s @r15+,fr2 + fmov.s @r15+,fr1 + fmov.s @r15+,fr0 + + /* see if the tlb handler returned another exception code */ + /* if so, the tlb ipw just elevated to a page fault or other such */ + /* 'soft' faults. */ + + cmp/eq r0,r1 + bf _soft_fault + nop + + /* return from the tlb miss */ + stc sgr,r15 + rte + nop + +_soft_fault: + /* the tlb ipw handler returned another exception code */ + /* we now need to enter the kernel with the soft fault */ + shll2 r0 + mov.l tea_addr1,r1 + mov.l @r1,r1 /* load the faulted address */ + bra switch_banks_and_enter_kernel + nop + +.align 2 +tea_addr1: .long 0xff00000c +expevt_addr1: .long 0xff000024 +initial_page_write_handler: .long _tlb_initial_page_write +tlb_stack_addr1: .long tlb_stack_end-4 + +exception_ent_1_end: + .skip 0x300-(exception_ent_1_end-exception_ent_1) +TLB_miss_ent: + mov.l expevt_addr2,r4 + mov.l @r4,r4 + shlr2 r4 + shlr2 r4 + shlr r4 /* shift the exception code over 5 bits */ + +#if SAVE_CPU_STATE + /* dump the entire cpu state */ + mov.l cpu_state_addr,r0 + + stc r0_bank,r1 + mov.l r1,@(0,r0) + stc r1_bank,r1 + mov.l r1,@(4,r0) + stc r2_bank,r1 + mov.l r1,@(8,r0) + stc r3_bank,r1 + mov.l r1,@(12,r0) + stc r4_bank,r1 + mov.l r1,@(16,r0) + stc r5_bank,r1 + mov.l r1,@(20,r0) + stc r6_bank,r1 + mov.l r1,@(24,r0) + stc r7_bank,r1 + mov.l r1,@(28,r0) + + mov.l r8,@(32,r0) + mov.l r9,@(36,r0) + mov.l r10,@(40,r0) + mov.l r11,@(44,r0) + mov.l r12,@(48,r0) + mov.l r13,@(52,r0) + mov.l r14,@(56,r0) + + mov.l r15,@(60,r0) + + add #64,r0 + + stc gbr,r1 + mov.l r1,@(0,r0) + sts mach,r1 + mov.l r1,@(4,r0) + sts macl,r1 + mov.l r1,@(8,r0) + sts pr,r1 + mov.l r1,@(12,r0) + + stc spc,r1 + mov.l r1,@(16,r0) + stc sgr,r1 + mov.l r1,@(20,r0) + stc ssr,r1 + mov.l r1,@(24,r0) + + sts fpul,r1 + mov.l r1,@(28,r0) + sts fpscr,r1 + mov.l r1,@(32,r0) + +#endif + + /* we can stay on reg bank 1, switch to a tlb stack */ + mov.l tlb_stack_addr2,r15 + + /* save some of the floating point registers */ + /* they seem to be used by some of the libgcc stuff */ + /* saving: fpscr, fpul, dr0, dr2, dr4 */ + fmov.s fr0,@-r15 + fmov.s fr1,@-r15 + fmov.s fr2,@-r15 + fmov.s fr3,@-r15 + fmov.s fr4,@-r15 + fmov.s fr5,@-r15 + sts.l fpul,@-r15 + sts.l fpscr,@-r15 + + mov.l r4,@-r15 /* save the exception code */ + sts.l pr,@-r15 /* save the pr reg */ + + /* arg 1 is exception code already in r4 */ + stc spc,r5 /* arg 2, spc */ + mov.l tlb_miss_handler,r1 + jsr @r1 + nop + + /* see if the tlb miss handler returned another exception code */ + /* if so, the tlb miss just elevated to a page fault or other such */ + /* 'soft' faults. */ + lds.l @r15+,pr /* restore pr */ + mov.l @r15+,r1 /* restore the original exception code */ + + /* restore the saved floating point registers */ + lds.l @r15+,fpscr + lds.l @r15+,fpul + fmov.s @r15+,fr5 + fmov.s @r15+,fr4 + fmov.s @r15+,fr3 + fmov.s @r15+,fr2 + fmov.s @r15+,fr1 + fmov.s @r15+,fr0 + + cmp/eq r0,r1 /* check against the stored original exception code */ + bf _soft_fault1 + nop + + /* return from the tlb miss */ + stc sgr,r15 + rte + nop + +_soft_fault1: + /* the tlb miss handler returned another exception code */ + /* we now need to enter the kernel with the soft fault */ + + shll2 r0 + mov.l tea_addr2,r1 + mov.l @r1,r1 /* load the faulted address */ + bra switch_banks_and_enter_kernel + nop + +.align 2 +tea_addr2: .long 0xff00000c +expevt_addr2: .long 0xff000024 +tlb_miss_handler: .long _tlb_miss +tlb_stack_addr2: .long tlb_stack_end-4 +#if SAVE_CPU_STATE +cpu_state_addr: .long _last_ex_cpu_state +#endif + +TLB_miss_ent_end: + .skip 0x200-(TLB_miss_ent_end-TLB_miss_ent) +interrupt_ent: + mov.l intevt_addr,r0 + mov.l @r0,r0 + shlr2 r0 + shlr r0 /* shift the exception code over 3 bits */ + + /* + ** args to here are + ** r0: exception number (shifted left 3 bits from the cpus version + ** r1: page fault address (if applicable, it still gets saved) + */ +switch_banks_and_enter_kernel: + /* disable interrupts */ + mov.l imask,r3 + stc sr,r2 + or r3,r2 + ldc r2,sr + + /* check to see if we are not already using the saved_* locations */ + mov.l is_pushing_registers,r2 + mov #1,r3 + and r2,r3 + bf _save_regs + + /* okay, we are in a bad state right now. + ** apparently we were already in the process of moving saved registers + ** from the saved_* locations. This will happen if we take a page fault + ** while pushing registers to the kernel stack, for example. We are toast. + */ + mov.l tlb_stack_addr3,r15 + mov.l reentrant_fault_handler,r2 + jsr @r2 + nop + +_save_regs: + /* save the saved registers into memory */ + /* this ends up with the important registers in saved_spc and friends */ + mov.l is_pushing_registers_addr,r2 + mov #1,r3 + mov.l r3,@r2 + + mov.l save_stack,r2 + stc.l spc,@-r2 + stc.l ssr,@-r2 + stc.l sgr,@-r2 + mov.l r0,@-r2 /* put the modified exception code there too */ + mov.l r1,@-r2 /* put the saved page fault address */ + + /* see if we need to load the kernel stack or stay on the current one */ + stc ssr,r0 + mov.l md_bit_mask,r1 + and r1,r0 + cmp/eq r1,r0 + bt _keep_current_stack + nop + + /* we need to set the stack because we came from user space */ + mov.l kstack,r15 + bra _have_set_stack + nop + +_keep_current_stack: + stc sgr,r15 + +_have_set_stack: + /* enable exceptions & swap banks back to 0 */ + mov.l bl_rb_bit_mask,r0 + stc sr,r1 + and r0,r1 + ldc r1,sr + + /* + ** From now on we can take exceptions, though taking any between now + ** and the time at which we move saved stuff out of saved_sgr and other + ** fixed save points would be fatal. We are only pushing it on the kernel + ** stack, which has to be present always anyway, so its not a problem, since + ** a page fault is the only one we can realistically take right now anyway. + */ + + /* start pushing registers */ + mov.l r8,@-r15 + mov.l r9,@-r15 + mov.l r10,@-r15 + mov.l r11,@-r15 + mov.l r12,@-r15 + mov.l r13,@-r15 + mov.l r14,@-r15 + + /* push r0-r7 */ + mov.l r0,@-r15 + mov.l r1,@-r15 + mov.l r2,@-r15 + mov.l r3,@-r15 + mov.l r4,@-r15 + mov.l r5,@-r15 + mov.l r6,@-r15 + mov.l r7,@-r15 + +_after_r0r7_save: + /* save the floating point registers */ + /* XXX see about optimizing this later */ + fmov.s fr0,@-r15 + fmov.s fr1,@-r15 + fmov.s fr2,@-r15 + fmov.s fr3,@-r15 + fmov.s fr4,@-r15 + fmov.s fr5,@-r15 + fmov.s fr6,@-r15 + fmov.s fr7,@-r15 + fmov.s fr8,@-r15 + fmov.s fr9,@-r15 + fmov.s fr10,@-r15 + fmov.s fr11,@-r15 + fmov.s fr12,@-r15 + fmov.s fr13,@-r15 + fmov.s fr14,@-r15 + fmov.s fr15,@-r15 + frchg + fmov.s fr0,@-r15 + fmov.s fr1,@-r15 + fmov.s fr2,@-r15 + fmov.s fr3,@-r15 + fmov.s fr4,@-r15 + fmov.s fr5,@-r15 + fmov.s fr6,@-r15 + fmov.s fr7,@-r15 + fmov.s fr8,@-r15 + fmov.s fr9,@-r15 + fmov.s fr10,@-r15 + fmov.s fr11,@-r15 + fmov.s fr12,@-r15 + fmov.s fr13,@-r15 + fmov.s fr14,@-r15 + fmov.s fr15,@-r15 + frchg + sts.l fpul,@-r15 + sts.l fpscr,@-r15 + + /* can save most of the special registers we need in r8-r14 */ + /* the abi we are working with saves r8-14 on function calls */ + stc.l gbr,@-r15 + sts.l mach,@-r15 + sts.l macl,@-r15 + sts.l pr,@-r15 + mov.l saved_sgr,r12 + mov.l r12,@-r15 + mov.l saved_ssr,r12 + mov.l r12,@-r15 + mov.l saved_spc,r12 + mov.l r12,@-r15 + mov.l saved_excode,r12 + shlr2 r12 + mov.l r12,@-r15 + mov.l saved_pfault,r12 + mov.l r12,@-r15 + + /* record that we are not in a critical section now where we cant */ + /* take an exception */ + mov.l is_pushing_registers_addr,r2 + mov #0,r3 + mov.l r3,@r2 + + /* arg1: address of the iframe */ + mov r15,r4 + + /* jump through the vector table into the kernel */ + mov.l vector_table_addr,r0 + mov.l saved_excode,r2 + mov.l @(r0,r2),r1 + jsr @r1 + nop + + /* entering a critical section now where we cant */ + /* take an exception */ + mov.l is_pushing_registers_addr,r2 + mov #1,r3 + mov.l r3,@r2 + + /* restore everything and get outta here */ + add #0x8,r15 /* pop the pfault and excode data from the stack */ + mov.l saved_spc_addr,r1 + mov.l @r15+,r2 + mov.l r2,@r1 + mov.l saved_ssr_addr,r1 + mov.l @r15+,r2 + mov.l r2,@r1 + mov.l saved_sgr_addr,r1 + mov.l @r15+,r2 + mov.l r2,@r1 + lds.l @r15+,pr + lds.l @r15+,macl + lds.l @r15+,mach + ldc.l @r15+,gbr + + /* restore the floating point registers */ + lds.l @r15+,fpscr + lds.l @r15+,fpul + frchg + fmov.s @r15+,fr15 + fmov.s @r15+,fr14 + fmov.s @r15+,fr13 + fmov.s @r15+,fr12 + fmov.s @r15+,fr11 + fmov.s @r15+,fr10 + fmov.s @r15+,fr9 + fmov.s @r15+,fr8 + fmov.s @r15+,fr7 + fmov.s @r15+,fr6 + fmov.s @r15+,fr5 + fmov.s @r15+,fr4 + fmov.s @r15+,fr3 + fmov.s @r15+,fr2 + fmov.s @r15+,fr1 + fmov.s @r15+,fr0 + frchg + fmov.s @r15+,fr15 + fmov.s @r15+,fr14 + fmov.s @r15+,fr13 + fmov.s @r15+,fr12 + fmov.s @r15+,fr11 + fmov.s @r15+,fr10 + fmov.s @r15+,fr9 + fmov.s @r15+,fr8 + fmov.s @r15+,fr7 + fmov.s @r15+,fr6 + fmov.s @r15+,fr5 + fmov.s @r15+,fr4 + fmov.s @r15+,fr3 + fmov.s @r15+,fr2 + fmov.s @r15+,fr1 + fmov.s @r15+,fr0 + + mov.l @r15+,r7 + mov.l @r15+,r6 + mov.l @r15+,r5 + mov.l @r15+,r4 + mov.l @r15+,r3 + mov.l @r15+,r2 + mov.l @r15+,r1 + mov.l @r15+,r0 + +_after_r0r7_restore: + /* We need to calculate a new sr with exceptions off & register bank 1*/ + mov.l bl_rb_bit_mask,r8 + not r8,r8 + stc sr,r9 + or r9,r8 + mov.l modified_sr_addr,r9 + mov.l r8,@r9 + + /* pop the last few registers */ + mov.l @r15+,r14 + mov.l @r15+,r13 + mov.l @r15+,r12 + mov.l @r15+,r11 + mov.l @r15+,r10 + mov.l @r15+,r9 + mov.l @r15+,r8 + + /* now we only have r15 to use */ + mov.l modified_sr,r15 + ldc r15,sr + + /* restore the ssr & spc registers */ + mov.l saved_spc,r15 + ldc r15,spc + mov.l saved_ssr,r15 + ldc r15,ssr + mov.l saved_sgr,r15 + + /* record that we are not in a critical section now where we cant */ + /* take an exception */ + mov.l is_pushing_registers_addr,r2 + mov #0,r3 + mov.l r3,@r2 + + /* get out of here */ + rte + nop + +.align 2 +reentrant_fault_handler: .long _reentrant_fault +modified_sr_addr: .long modified_sr +vector_table_addr: .long vector_table +trap_exception: .long 0x2c +vector_base_addr: .long _vector_base +md_bit_mask: .long 0x40000000 +bl_rb_bit_mask: .long 0xcfffffff +saved_page_fault_addr: .long saved_pfault +saved_excode_addr: .long saved_excode +saved_spc_addr: .long saved_spc +saved_ssr_addr: .long saved_ssr +saved_sgr_addr: .long saved_sgr +tlb_stack_addr3: .long tlb_stack_end-4 +intevt_addr: .long 0xff000028 +tra_addr: .long 0xff000020 +imask: .long 0x000000f0 + +/* the next memory addresses are used for temporary storage or + data structures for the kernel to write in. They are in the + text segment, I know, but its much faster if we can reference + them pcrel. */ +saved_pfault: .long 0 +saved_excode: .long 0 +saved_sgr: .long 0 +saved_ssr: .long 0 +saved_spc: .long 0 /* these four addresses are used to + save the saved registers while we switch to another + stack and register set */ +save_stack: .long saved_spc+4 +modified_sr: .long 0 + +/* stores whether or not we are in a state at which we cannot take a fault */ +is_pushing_registers: .long 0 +is_pushing_registers_addr: .long is_pushing_registers + +/* These memory locations are written to by the kernel */ +.globl _kernel_struct +_kernel_struct: +kernel_pgdir: .long 0 +user_pgdir: .long 0 +kernel_asid: .long 0 +user_asid: .long 0 +kstack: .long 0 +vector_table: + .rep 0x100 + .long 0 + .endr + +.data +.align 4 +tlb_stack: + .rep 0x1000 + .long 0 + .endr +tlb_stack_end: + +#if SAVE_CPU_STATE +.align 4 +.global _last_ex_cpu_state +_last_ex_cpu_state: + .rep 0x1000 + .long 99 + .endr +#endif + diff --git a/src/kernel/boot/arch/sh4/vcpu_c.c b/src/kernel/boot/arch/sh4/vcpu_c.c new file mode 100644 index 0000000000..312ddd01cf --- /dev/null +++ b/src/kernel/boot/arch/sh4/vcpu_c.c @@ -0,0 +1,448 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include "serial.h" +#include +#include +#include + +#define SAVE_CPU_STATE 0 + +#define ROUNDUP(a, b) (((a) + ((b)-1)) & ~((b)-1)) + +#define CHATTY_TLB 0 + +extern vcpu_struct kernel_struct; +#if SAVE_CPU_STATE +extern unsigned int last_ex_cpu_state[]; +#endif +unsigned int next_utlb_ent = 0; + +unsigned int vector_base(); +unsigned int boot_stack[256] = { 0, }; + +void vcpu_clear_all_itlb_entries(); +void vcpu_clear_all_utlb_entries(); +void vcpu_dump_utlb_entry(int ent); +void vcpu_dump_all_itlb_entries(); +void vcpu_dump_all_utlb_entries(); + +unsigned int get_sr(); +void set_sr(unsigned int sr); +unsigned int get_vbr(); +void set_vbr(unsigned int vbr); +unsigned int get_sgr(); +unsigned int get_ssr(); +unsigned int get_spc(); +asm( +".globl _get_sr,_set_sr\n" +".globl _get_vbr,_set_vbr\n" +".globl _get_sgr\n" + +"_get_sr:\n" +" stc sr,r0\n" +" rts\n" +" nop\n" + +"_set_sr:\n" +" ldc r4,sr\n" +" rts\n" +" nop\n" + +"_get_vbr:\n" +" stc vbr,r0\n" +" rts\n" +" nop\n" + +"_set_vbr:\n" +" ldc r4,vbr\n" +" rts\n" +" nop\n" + +"_get_sgr:\n" +" stc sgr,r0\n" +" rts\n" +" nop\n" + +"_get_ssr:\n" +" stc ssr,r0\n" +" rts\n" +" nop\n" + +"_get_spc:\n" +" stc spc,r0\n" +" rts\n" +" nop\n" +); + +#if SAVE_CPU_STATE +static void dump_cpu_state() +{ + int i; + unsigned int *stack; + unsigned int *stack_top; + + dprintf("dump_cpu_state entry\n"); + + dprintf("registers:\n"); + for(i=0; i<16; i++) { + dprintf("r%d 0x%x\n", i, last_ex_cpu_state[i]); + } + dprintf("gbr 0x%x\n", last_ex_cpu_state[16]); + dprintf("mach 0x%x\n", last_ex_cpu_state[17]); + dprintf("macl 0x%x\n", last_ex_cpu_state[18]); + dprintf("pr 0x%x\n", last_ex_cpu_state[19]); + dprintf("spc 0x%x\n", last_ex_cpu_state[20]); + dprintf("sgr 0x%x\n", last_ex_cpu_state[21]); + dprintf("ssr 0x%x\n", last_ex_cpu_state[22]); + dprintf("fpul 0x%x\n", last_ex_cpu_state[23]); + dprintf("fpscr 0x%x\n", last_ex_cpu_state[24]); + + stack = (unsigned int *)(get_sgr() - 0x200); + stack_top = (unsigned int *)ROUNDUP((unsigned int)stack, PAGE_SIZE); + dprintf("stack at 0x%x to 0x%x\n", stack, stack_top); + // dump the stack + for(;stack < stack_top; stack++) + dprintf("0x%x\n", *stack); + + dprintf("utlb entries:\n"); + vcpu_dump_all_utlb_entries(); + dprintf("itlb entries:\n"); + vcpu_dump_all_itlb_entries(); + + + for(;;); +} +#endif +int reentrant_fault() +{ + dprintf("bad reentrancy fault\n"); + dprintf("spinning forever\n"); + for(;;); + return 0; +} + +static int default_vector(void *_frame) +{ + struct iframe *frame = (struct iframe *)_frame; + + dprintf("default_vector: ex_code 0x%x, pc 0x%x\n", frame->excode, frame->spc); + dprintf("sgr = 0x%x\n", frame->sgr); + dprintf("spinning forever\n"); + for(;;); + return 0; +} + +int vcpu_init(kernel_args *ka) +{ + int i; + unsigned int sr; + unsigned int vbr; + + dprintf("vcpu_init: entry\n"); + + memset(&kernel_struct, 0, sizeof(kernel_struct)); + for(i=0; i<256; i++) { + kernel_struct.vt[i].func = &default_vector; + } + kernel_struct.kstack = (unsigned int *)((int)boot_stack + sizeof(boot_stack) - 4); + + // set the vbr + vbr = (unsigned int)&vector_base; + set_vbr(vbr); + dprintf("vbr = 0x%x\n", get_vbr()); + + // disable exceptions + sr = get_sr(); + sr |= 0x10000000; + set_sr(sr); + + if((sr & 0x20000000) != 0) { + // we're using register bank 1 now + dprintf("using bank 1, switching register banks\n"); + // this switches in the bottom 8 registers. + // dont have to do anything more, since the bottom 8 are + // not saved in the call. + set_sr(sr & 0xdfffffff); + } + + // enable exceptions + sr = get_sr(); + sr &= 0xefffffff; + set_sr(sr); + + ka->arch_args.vcpu = &kernel_struct; + + // enable the mmu + vcpu_clear_all_itlb_entries(); + vcpu_clear_all_utlb_entries(); + *(int *)PTEH = 0; + *(int *)MMUCR = 0x00000105; + + return 0; +} + +static struct ptent *get_ptent(struct pdent *pd, unsigned int fault_address) +{ + struct ptent *pt; + +#if CHATTY_TLB + dprintf("get_ptent: fault_address 0x%x\n", fault_address); +#endif + + if((unsigned int)pd < P1_PHYS_MEM_START || (unsigned int)pd >= P1_PHYS_MEM_END) { +#if CHATTY_TLB + dprintf("get_ptent: bad pdent 0x%x\n", pd); +#endif + return 0; + } + + if(pd[fault_address >> 22].v == 0) { + return 0; + } + pt = (struct ptent *)PHYS_ADDR_TO_P1(pd[fault_address >> 22].ppn << 12); +#if CHATTY_TLB + dprintf("get_ptent: found ptent 0x%x\n", pt); +#endif + + return &pt[(fault_address >> 12) & 0x000003ff]; +} + +static void tlb_map(unsigned int vpn, struct ptent *ptent, unsigned int tlb_ent, unsigned int asid) +{ + union { + struct utlb_data data; + unsigned int n[3]; + } u; + + ptent->tlb_ent = tlb_ent; + + u.n[0] = 0; + u.data.a.asid = asid; + u.data.a.vpn = vpn << 2; + u.data.a.dirty = ptent->d; + u.data.a.valid = 1; + + u.n[1] = 0; + u.data.da1.ppn = ptent->ppn << 2; + u.data.da1.valid = 1; + u.data.da1.psize1 = (ptent->sz & 0x2) ? 1 : 0; + u.data.da1.prot_key = ptent->pr; + u.data.da1.psize0 = ptent->sz & 0x1; + u.data.da1.cacheability = ptent->c; + u.data.da1.dirty = ptent->d; + u.data.da1.sh = ptent->sh; + u.data.da1.wt = ptent->wt; + + u.n[2] = 0; + + *((unsigned int *)(UTLB | (next_utlb_ent << UTLB_ADDR_SHIFT))) = u.n[0]; + *((unsigned int *)(UTLB1 | (next_utlb_ent << UTLB_ADDR_SHIFT))) = u.n[1]; + *((unsigned int *)(UTLB2 | (next_utlb_ent << UTLB_ADDR_SHIFT))) = u.n[2]; +} + +unsigned int tlb_miss(unsigned int excode, unsigned int pc) +{ + struct pdent *pd; + struct ptent *ent; + unsigned int fault_addr = *(unsigned int *)TEA; + unsigned int shifted_fault_addr; + unsigned int asid; + +#if CHATTY_TLB + dprintf("tlb_miss: excode 0x%x, pc 0x%x, sgr 0x%x, fault_address 0x%x\n", excode, pc, get_sgr(), fault_addr); +#endif + +// if(fault_addr == 0 || pc == 0 || get_sgr() == 0) +// dump_cpu_state(); + + if(fault_addr >= P1_AREA) { + pd = (struct pdent *)kernel_struct.kernel_pgdir; + asid = kernel_struct.kernel_asid; + shifted_fault_addr = fault_addr & 0x7fffffff; + } else { + pd = (struct pdent *)kernel_struct.user_pgdir; + asid = kernel_struct.user_asid; + shifted_fault_addr = fault_addr; + } + + ent = get_ptent(pd, shifted_fault_addr); + if(ent == NULL || ent->v == 0) { + if(excode == 0x2) + return EXCEPTION_PAGE_FAULT_READ; + else + return EXCEPTION_PAGE_FAULT_WRITE; + } + +#if CHATTY_TLB + dprintf("found entry. vaddr 0x%x maps to paddr 0x%x\n", + fault_addr, ent->ppn << 12); +#endif + + + if(excode == 0x3) { + // this is a tlb miss because of a write, so + // go ahead and mark it dirty + ent->d = 1; + } + +#if 0 + // XXX hack! + if(fault_addr == 0x7ffffff8) { + dprintf("sr = 0x%x\n", get_sr()); + dprintf("ssr = 0x%x sgr = 0x%x spc = 0x%x\n", get_ssr(), get_sgr(), get_spc()); + dprintf("kernel_struct: kpgdir 0x%x upgdir 0x%x kasid 0x%x uasid 0x%x kstack 0x%x\n", + kernel_struct.kernel_pgdir, kernel_struct.user_pgdir, kernel_struct.kernel_asid, + kernel_struct.user_asid, kernel_struct.kstack); + } +#endif +#if 0 + { + static int clear_all = 0; + if(fault_addr == 0x7ffffff8) + clear_all = 1; + if(clear_all) + vcpu_clear_all_utlb_entries(); + } +#endif + + tlb_map(fault_addr >> 12, ent, next_utlb_ent, asid); +#if CHATTY_TLB + vcpu_dump_utlb_entry(next_utlb_ent); +#endif + next_utlb_ent++; + if(next_utlb_ent >= UTLB_COUNT) + next_utlb_ent = 0; + +#if CHATTY_TLB + dprintf("tlb_miss exit\n"); +#endif + return excode; +} + +unsigned int tlb_initial_page_write(unsigned int excode, unsigned int pc) +{ + struct pdent *pd; + struct ptent *ent; + unsigned int fault_addr = *(unsigned int *)TEA; + unsigned int shifted_fault_addr; + unsigned int asid; + +#if CHATTY_TLB + dprintf("tlb_initial_page_write: excode 0x%x, pc 0x%x, fault_address 0x%x\n", + excode, pc, fault_addr); +#endif + + if(fault_addr >= P1_AREA) { + pd = (struct pdent *)kernel_struct.kernel_pgdir; + asid = kernel_struct.kernel_asid; + shifted_fault_addr = fault_addr & 0x7fffffff; + } else { + pd = (struct pdent *)kernel_struct.user_pgdir; + asid = kernel_struct.user_asid; + shifted_fault_addr = fault_addr; + } + + ent = get_ptent(pd, shifted_fault_addr); + if(ent == NULL || ent->v == 0) { + // if we're here, the page table is + // out of sync with the tlb cache. + // time to die. + dprintf("tlb_ipw exception called but no page table ent exists!\n"); + for(;;); + } + + { + struct utlb_addr_array *a; + struct utlb_data_array_1 *da1; + + a = (struct utlb_addr_array *)(UTLB | (ent->tlb_ent << UTLB_ADDR_SHIFT)); + da1 = (struct utlb_data_array_1 *)(UTLB1 | (ent->tlb_ent << UTLB_ADDR_SHIFT)); + + // inspect this tlb entry to make sure it's the right one + if(asid != a->asid || (ent->ppn << 2) != da1->ppn || ((fault_addr >> 12) << 2) != a->vpn) { + dprintf("tlb_ipw exception found that the page table out of sync with tlb\n"); + dprintf("page_table entry: 0x%x\n", *(unsigned int *)ent); + vcpu_dump_utlb_entry(ent->tlb_ent); + for(;;); + } + a->dirty = 1; + ent->d = 1; + } + + return excode; +} + +void vcpu_dump_itlb_entry(int ent) +{ + struct itlb_data data; + + *(int *)&data.a = *((int *)(ITLB | (ent << ITLB_ADDR_SHIFT))); + *(int *)&data.da1 = *((int *)(ITLB1 | (ent << ITLB_ADDR_SHIFT))); + *(int *)&data.da2 = *((int *)(ITLB2 | (ent << ITLB_ADDR_SHIFT))); + + dprintf("itlb[%d] = \n", ent); + dprintf(" asid = %d\n", data.a.asid); + dprintf(" valid = %d\n", data.a.valid); + dprintf(" vpn = 0x%x\n", data.a.vpn << 10); + dprintf(" ppn = 0x%x\n", data.da1.ppn << 10); +} + +void vcpu_clear_all_itlb_entries() +{ + int i; + for(i=0; i<4; i++) { + *((int *)(ITLB | (i << ITLB_ADDR_SHIFT))) = 0; + *((int *)(ITLB1 | (i << ITLB_ADDR_SHIFT))) = 0; + *((int *)(ITLB2 | (i << ITLB_ADDR_SHIFT))) = 0; + } +} + +void vcpu_dump_all_itlb_entries() +{ + int i; + + for(i=0; i<4; i++) { + vcpu_dump_itlb_entry(i); + } +} + +void vcpu_dump_utlb_entry(int ent) +{ + struct utlb_data data; + + *(int *)&data.a = *((int *)(UTLB | (ent << UTLB_ADDR_SHIFT))); + *(int *)&data.da1 = *((int *)(UTLB1 | (ent << UTLB_ADDR_SHIFT))); + *(int *)&data.da2 = *((int *)(UTLB2 | (ent << UTLB_ADDR_SHIFT))); + + dprintf("utlb[%d] = \n", ent); + dprintf(" asid = %d\n", data.a.asid); + dprintf(" valid = %d\n", data.a.valid); + dprintf(" dirty = %d\n", data.a.dirty); + dprintf(" vpn = 0x%x\n", data.a.vpn << 10); + dprintf(" ppn = 0x%x\n", data.da1.ppn << 10); +} + +void vcpu_clear_all_utlb_entries() +{ + int i; + for(i=0; i<64; i++) { + *((int *)(UTLB | (i << UTLB_ADDR_SHIFT))) = 0; + *((int *)(UTLB1 | (i << UTLB_ADDR_SHIFT))) = 0; + *((int *)(UTLB2 | (i << UTLB_ADDR_SHIFT))) = 0; + } +} + +void vcpu_dump_all_utlb_entries() +{ + int i; + + for(i=0; i<64; i++) { + vcpu_dump_utlb_entry(i); + } +} + diff --git a/src/kernel/boot/arch/sparc/Jamfile b/src/kernel/boot/arch/sparc/Jamfile new file mode 100644 index 0000000000..6c1a37ced3 --- /dev/null +++ b/src/kernel/boot/arch/sparc/Jamfile @@ -0,0 +1,2 @@ +SubDir OBOS_TOP sources os kits kernel boot arch sparc ; + diff --git a/src/kernel/boot/arch/sparc/closeall.c b/src/kernel/boot/arch/sparc/closeall.c new file mode 100644 index 0000000000..b3aac8f10e --- /dev/null +++ b/src/kernel/boot/arch/sparc/closeall.c @@ -0,0 +1,7 @@ +/* $OpenBSD: closeall.c,v 1.1 1997/09/17 10:46:16 downsj Exp $ */ + +void +closeall() +{ +} + diff --git a/src/kernel/boot/arch/sparc/dvma.c b/src/kernel/boot/arch/sparc/dvma.c new file mode 100644 index 0000000000..03e801926c --- /dev/null +++ b/src/kernel/boot/arch/sparc/dvma.c @@ -0,0 +1,122 @@ +/* $OpenBSD: dvma.c,v 1.1 1997/09/17 10:46:18 downsj Exp $ */ +/* $NetBSD: dvma.c,v 1.2 1995/09/17 00:50:56 pk Exp $ */ +/* + * Copyright (c) 1995 Gordon W. Ross + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * 4. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Gordon Ross + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * The easiest way to deal with the need for DVMA mappings is + * to just map the entire third megabyte of RAM into DVMA space. + * That way, dvma_mapin can just compute the DVMA alias address, + * and dvma_mapout does nothing. Note that this assumes all + * standalone programs stay in the range SA_MIN_VA .. SA_MAX_VA + */ + +#include +#include +#include + +#include + +#define DVMA_BASE 0xFFF00000 +#define DVMA_MAPLEN 0xE0000 /* 1 MB - 128K (save MONSHORTSEG) */ + +#define SA_MIN_VA (RELOC - 0x40000) /* XXX - magic constant */ +#define SA_MAX_VA (SA_MIN_VA + DVMA_MAPLEN) + +void +dvma_init() +{ + register int segva, dmava; + + dmava = DVMA_BASE; + for (segva = SA_MIN_VA; segva < SA_MAX_VA; segva += NBPSG) { + setsegmap(dmava, getsegmap(segva)); + dmava += NBPSG; + } +} + +/* + * Convert a local address to a DVMA address. + */ +char * +dvma_mapin(char *addr, size_t len) +{ + register int va = (int)addr; + + /* Make sure the address is in the DVMA map. */ + if ((va < SA_MIN_VA) || (va >= SA_MAX_VA)) + panic("dvma_mapin"); + + va += DVMA_BASE - SA_MIN_VA; + + return ((char *)va); +} + +/* + * Convert a DVMA address to a local address. + */ +char * +dvma_mapout(char *addr, size_t len) +{ + int va = (int)addr; + + /* Make sure the address is in the DVMA map. */ + if ((va < DVMA_BASE) || (va >= (DVMA_BASE + DVMA_MAPLEN))) + panic("dvma_mapout"); + + va -= DVMA_BASE - SA_MIN_VA; + + return ((char *)va); +} + +extern char *alloc __P((int)); + +char * +dvma_alloc(int len) +{ + char *mem; + + mem = alloc(len); + if (!mem) + return (mem); + return (dvma_mapin(mem, len)); +} + +extern void free(void *ptr, int len); +void +dvma_free(char *dvma, int len) +{ + char *mem; + + mem = dvma_mapout(dvma, len); + if (mem) + free(mem, len); +} + diff --git a/src/kernel/boot/arch/sparc/libkern/__main.c b/src/kernel/boot/arch/sparc/libkern/__main.c new file mode 100644 index 0000000000..352716cd23 --- /dev/null +++ b/src/kernel/boot/arch/sparc/libkern/__main.c @@ -0,0 +1,42 @@ +/* $OpenBSD: __main.c,v 1.2 1996/04/19 16:09:17 niklas Exp $ */ +/* $NetBSD: __main.c,v 1.4 1996/03/14 18:52:03 christos Exp $ */ + +/* + * Copyright (c) 1993 Christopher G. Demetriou + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Christopher G. Demetriou. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +void __main __P((void)); + +void +__main() +{ +} + diff --git a/src/kernel/boot/arch/sparc/libkern/bzero.c b/src/kernel/boot/arch/sparc/libkern/bzero.c new file mode 100644 index 0000000000..b86fe9758e --- /dev/null +++ b/src/kernel/boot/arch/sparc/libkern/bzero.c @@ -0,0 +1,60 @@ +/* $OpenBSD: bzero.c,v 1.3 1997/11/07 15:56:38 niklas Exp $ */ + +/* + * Copyright (c) 1987 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +/*static char *sccsid = "from: @(#)bzero.c 5.7 (Berkeley) 2/24/91";*/ +static char *rcsid = "$OpenBSD: bzero.c,v 1.3 1997/11/07 15:56:38 niklas Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#ifndef _KERNEL +#include +#else +#include +#endif + +/* + * bzero -- vax movc5 instruction + */ +void +bzero(b, length) + void *b; + register size_t length; +{ + register char *p; + + for (p = b; length--;) + *p++ = '\0'; +} + diff --git a/src/kernel/boot/arch/sparc/libkern/udiv.S b/src/kernel/boot/arch/sparc/libkern/udiv.S new file mode 100644 index 0000000000..e302ab237d --- /dev/null +++ b/src/kernel/boot/arch/sparc/libkern/udiv.S @@ -0,0 +1,428 @@ + +/* $OpenBSD: divrem.m4,v 1.4 2000/03/03 11:17:03 art Exp $ */ +/* $NetBSD: divrem.m4,v 1.3 1995/04/22 09:37:39 pk Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS `AS IS' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Header: divrem.m4,v 1.4 92/06/25 13:23:57 torek Exp + */ + +/* + * Division and remainder, from Appendix E of the Sparc Version 8 + * Architecture Manual, with fixes from Gordon Irlam. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +#ifdef notdef + .asciz "@(#)divrem.m4 8.1 (Berkeley) 6/4/93" +#endif + .asciz "$OpenBSD: divrem.m4,v 1.4 2000/03/03 11:17:03 art Exp $" +#endif /* LIBC_SCCS and not lint */ + +/* + * Input: dividend and divisor in %o0 and %o1 respectively. + * + * m4 parameters: + * .udiv name of function to generate + * __udiv secondary name of function to generate + * div div=div => %o0 / %o1; div=rem => %o0 % %o1 + * false false=true => signed; false=false => unsigned + * + * Algorithm parameters: + * N how many bits per iteration we try to get (4) + * WORDSIZE total number of bits (32) + * + * Derived constants: + * TWOSUPN 2^N, for label generation (m4 exponentiation currently broken) + * TOPBITS number of bits in the top decade of a number + * + * Important variables: + * Q the partial quotient under development (initially 0) + * R the remainder so far, initially the dividend + * ITER number of main division loop iterations required; + * equal to ceil(log2(quotient) / N). Note that this + * is the log base (2^N) of the quotient. + * V the current comparand, initially divisor*2^(ITER*N-1) + * + * Cost: + * Current estimate for non-large dividend is + * ceil(log2(quotient) / N) * (10 + 7N/2) + C + * A large dividend is one greater than 2^(31-TOPBITS) and takes a + * different path, as the upper bits of the quotient must be developed + * one bit at a time. + */ + + + + + + + + + + + + + +/* m4 reminder: d => if a is b, then c, else d */ + + + + +/* + * This is the recursive definition for developing quotient digits. + * + * Parameters: + * $1 the current depth, 1 <= $1 <= 4 + * $2 the current accumulation of quotient bits + * 4 max depth + * + * We add a new bit to $2 and either recurse or insert the bits in + * the quotient. %o3, %o2, and %o5 are inputs and outputs as defined above; + * the condition codes are expected to reflect the input %o3, and are + * modified to reflect the output %o3. + */ + + +#include "DEFS.h" +#include + + .globl __udiv +__udiv: +FUNC(.udiv) + + ! Ready to divide. Compute size of quotient; scale comparand. + orcc %o1, %g0, %o5 + bnz 1f + mov %o0, %o3 + + ! Divide by zero trap. If it returns, return 0 (about as + ! wrong as possible, but that is what SunOS does...). + t ST_DIV0 + retl + clr %o0 + +1: + cmp %o3, %o5 ! if %o1 exceeds %o0, done + blu Lgot_result ! (and algorithm fails otherwise) + clr %o2 + sethi %hi(1 << (32 - 4 - 1)), %g1 + cmp %o3, %g1 + blu Lnot_really_big + clr %o4 + + ! Here the dividend is >= 2^(31-N) or so. We must be careful here, + ! as our usual N-at-a-shot divide step will cause overflow and havoc. + ! The number of bits in the result here is N*ITER+SC, where SC <= N. + ! Compute ITER in an unorthodox manner: know we need to shift V into + ! the top decade: so do not even bother to compare to R. + 1: + cmp %o5, %g1 + bgeu 3f + mov 1, %g7 + sll %o5, 4, %o5 + b 1b + inc %o4 + + ! Now compute %g7. + 2: addcc %o5, %o5, %o5 + bcc Lnot_too_big + inc %g7 + + ! We get here if the %o1 overflowed while shifting. + ! This means that %o3 has the high-order bit set. + ! Restore %o5 and subtract from %o3. + sll %g1, 4, %g1 ! high order bit + srl %o5, 1, %o5 ! rest of %o5 + add %o5, %g1, %o5 + b Ldo_single_div + dec %g7 + + Lnot_too_big: + 3: cmp %o5, %o3 + blu 2b + nop + be Ldo_single_div + nop + /* NB: these are commented out in the V8-Sparc manual as well */ + /* (I do not understand this) */ + ! %o5 > %o3: went too far: back up 1 step + ! srl %o5, 1, %o5 + ! dec %g7 + ! do single-bit divide steps + ! + ! We have to be careful here. We know that %o3 >= %o5, so we can do the + ! first divide step without thinking. BUT, the others are conditional, + ! and are only done if %o3 >= 0. Because both %o3 and %o5 may have the high- + ! order bit set in the first step, just falling into the regular + ! division loop will mess up the first time around. + ! So we unroll slightly... + Ldo_single_div: + deccc %g7 + bl Lend_regular_divide + nop + sub %o3, %o5, %o3 + mov 1, %o2 + b Lend_single_divloop + nop + Lsingle_divloop: + sll %o2, 1, %o2 + bl 1f + srl %o5, 1, %o5 + ! %o3 >= 0 + sub %o3, %o5, %o3 + b 2f + inc %o2 + 1: ! %o3 < 0 + add %o3, %o5, %o3 + dec %o2 + 2: + Lend_single_divloop: + deccc %g7 + bge Lsingle_divloop + tst %o3 + b,a Lend_regular_divide + +Lnot_really_big: +1: + sll %o5, 4, %o5 + cmp %o5, %o3 + bleu 1b + inccc %o4 + be Lgot_result + dec %o4 + + tst %o3 ! set up for initial iteration +Ldivloop: + sll %o2, 4, %o2 + ! depth 1, accumulated bits 0 + bl L.1.16 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 2, accumulated bits 1 + bl L.2.17 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 3, accumulated bits 3 + bl L.3.19 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 4, accumulated bits 7 + bl L.4.23 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (7*2+1), %o2 + +L.4.23: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (7*2-1), %o2 + + +L.3.19: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 4, accumulated bits 5 + bl L.4.21 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (5*2+1), %o2 + +L.4.21: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (5*2-1), %o2 + + + +L.2.17: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 3, accumulated bits 1 + bl L.3.17 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 4, accumulated bits 3 + bl L.4.19 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (3*2+1), %o2 + +L.4.19: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (3*2-1), %o2 + + +L.3.17: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 4, accumulated bits 1 + bl L.4.17 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (1*2+1), %o2 + +L.4.17: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (1*2-1), %o2 + + + + +L.1.16: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 2, accumulated bits -1 + bl L.2.15 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 3, accumulated bits -1 + bl L.3.15 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 4, accumulated bits -1 + bl L.4.15 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (-1*2+1), %o2 + +L.4.15: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (-1*2-1), %o2 + + +L.3.15: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 4, accumulated bits -3 + bl L.4.13 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (-3*2+1), %o2 + +L.4.13: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (-3*2-1), %o2 + + + +L.2.15: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 3, accumulated bits -3 + bl L.3.13 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 4, accumulated bits -5 + bl L.4.11 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (-5*2+1), %o2 + +L.4.11: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (-5*2-1), %o2 + + +L.3.13: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 4, accumulated bits -7 + bl L.4.9 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (-7*2+1), %o2 + +L.4.9: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (-7*2-1), %o2 + + + + + 9: +Lend_regular_divide: + deccc %o4 + bge Ldivloop + tst %o3 + bl,a Lgot_result + ! non-restoring fixup here (one instruction only!) + dec %o2 + + +Lgot_result: + + retl + mov %o2, %o0 + diff --git a/src/kernel/boot/arch/sparc/libkern/urem.S b/src/kernel/boot/arch/sparc/libkern/urem.S new file mode 100644 index 0000000000..1cc9e77b3e --- /dev/null +++ b/src/kernel/boot/arch/sparc/libkern/urem.S @@ -0,0 +1,428 @@ + +/* $OpenBSD: divrem.m4,v 1.4 2000/03/03 11:17:03 art Exp $ */ +/* $NetBSD: divrem.m4,v 1.3 1995/04/22 09:37:39 pk Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS `AS IS' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Header: divrem.m4,v 1.4 92/06/25 13:23:57 torek Exp + */ + +/* + * Division and remainder, from Appendix E of the Sparc Version 8 + * Architecture Manual, with fixes from Gordon Irlam. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +#ifdef notdef + .asciz "@(#)divrem.m4 8.1 (Berkeley) 6/4/93" +#endif + .asciz "$OpenBSD: divrem.m4,v 1.4 2000/03/03 11:17:03 art Exp $" +#endif /* LIBC_SCCS and not lint */ + +/* + * Input: dividend and divisor in %o0 and %o1 respectively. + * + * m4 parameters: + * .urem name of function to generate + * __urem secondary name of function to generate + * rem rem=div => %o0 / %o1; rem=rem => %o0 % %o1 + * false false=true => signed; false=false => unsigned + * + * Algorithm parameters: + * N how many bits per iteration we try to get (4) + * WORDSIZE total number of bits (32) + * + * Derived constants: + * TWOSUPN 2^N, for label generation (m4 exponentiation currently broken) + * TOPBITS number of bits in the top decade of a number + * + * Important variables: + * Q the partial quotient under development (initially 0) + * R the remainder so far, initially the dividend + * ITER number of main division loop iterations required; + * equal to ceil(log2(quotient) / N). Note that this + * is the log base (2^N) of the quotient. + * V the current comparand, initially divisor*2^(ITER*N-1) + * + * Cost: + * Current estimate for non-large dividend is + * ceil(log2(quotient) / N) * (10 + 7N/2) + C + * A large dividend is one greater than 2^(31-TOPBITS) and takes a + * different path, as the upper bits of the quotient must be developed + * one bit at a time. + */ + + + + + + + + + + + + + +/* m4 reminder: d => if a is b, then c, else d */ + + + + +/* + * This is the recursive definition for developing quotient digits. + * + * Parameters: + * $1 the current depth, 1 <= $1 <= 4 + * $2 the current accumulation of quotient bits + * 4 max depth + * + * We add a new bit to $2 and either recurse or insert the bits in + * the quotient. %o3, %o2, and %o5 are inputs and outputs as defined above; + * the condition codes are expected to reflect the input %o3, and are + * modified to reflect the output %o3. + */ + + +#include "DEFS.h" +#include + + .globl __urem +__urem: +FUNC(.urem) + + ! Ready to divide. Compute size of quotient; scale comparand. + orcc %o1, %g0, %o5 + bnz 1f + mov %o0, %o3 + + ! Divide by zero trap. If it returns, return 0 (about as + ! wrong as possible, but that is what SunOS does...). + t ST_DIV0 + retl + clr %o0 + +1: + cmp %o3, %o5 ! if %o1 exceeds %o0, done + blu Lgot_result ! (and algorithm fails otherwise) + clr %o2 + sethi %hi(1 << (32 - 4 - 1)), %g1 + cmp %o3, %g1 + blu Lnot_really_big + clr %o4 + + ! Here the dividend is >= 2^(31-N) or so. We must be careful here, + ! as our usual N-at-a-shot divide step will cause overflow and havoc. + ! The number of bits in the result here is N*ITER+SC, where SC <= N. + ! Compute ITER in an unorthodox manner: know we need to shift V into + ! the top decade: so do not even bother to compare to R. + 1: + cmp %o5, %g1 + bgeu 3f + mov 1, %g7 + sll %o5, 4, %o5 + b 1b + inc %o4 + + ! Now compute %g7. + 2: addcc %o5, %o5, %o5 + bcc Lnot_too_big + inc %g7 + + ! We get here if the %o1 overflowed while shifting. + ! This means that %o3 has the high-order bit set. + ! Restore %o5 and subtract from %o3. + sll %g1, 4, %g1 ! high order bit + srl %o5, 1, %o5 ! rest of %o5 + add %o5, %g1, %o5 + b Ldo_single_div + dec %g7 + + Lnot_too_big: + 3: cmp %o5, %o3 + blu 2b + nop + be Ldo_single_div + nop + /* NB: these are commented out in the V8-Sparc manual as well */ + /* (I do not understand this) */ + ! %o5 > %o3: went too far: back up 1 step + ! srl %o5, 1, %o5 + ! dec %g7 + ! do single-bit divide steps + ! + ! We have to be careful here. We know that %o3 >= %o5, so we can do the + ! first divide step without thinking. BUT, the others are conditional, + ! and are only done if %o3 >= 0. Because both %o3 and %o5 may have the high- + ! order bit set in the first step, just falling into the regular + ! division loop will mess up the first time around. + ! So we unroll slightly... + Ldo_single_div: + deccc %g7 + bl Lend_regular_divide + nop + sub %o3, %o5, %o3 + mov 1, %o2 + b Lend_single_divloop + nop + Lsingle_divloop: + sll %o2, 1, %o2 + bl 1f + srl %o5, 1, %o5 + ! %o3 >= 0 + sub %o3, %o5, %o3 + b 2f + inc %o2 + 1: ! %o3 < 0 + add %o3, %o5, %o3 + dec %o2 + 2: + Lend_single_divloop: + deccc %g7 + bge Lsingle_divloop + tst %o3 + b,a Lend_regular_divide + +Lnot_really_big: +1: + sll %o5, 4, %o5 + cmp %o5, %o3 + bleu 1b + inccc %o4 + be Lgot_result + dec %o4 + + tst %o3 ! set up for initial iteration +Ldivloop: + sll %o2, 4, %o2 + ! depth 1, accumulated bits 0 + bl L.1.16 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 2, accumulated bits 1 + bl L.2.17 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 3, accumulated bits 3 + bl L.3.19 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 4, accumulated bits 7 + bl L.4.23 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (7*2+1), %o2 + +L.4.23: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (7*2-1), %o2 + + +L.3.19: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 4, accumulated bits 5 + bl L.4.21 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (5*2+1), %o2 + +L.4.21: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (5*2-1), %o2 + + + +L.2.17: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 3, accumulated bits 1 + bl L.3.17 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 4, accumulated bits 3 + bl L.4.19 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (3*2+1), %o2 + +L.4.19: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (3*2-1), %o2 + + +L.3.17: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 4, accumulated bits 1 + bl L.4.17 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (1*2+1), %o2 + +L.4.17: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (1*2-1), %o2 + + + + +L.1.16: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 2, accumulated bits -1 + bl L.2.15 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 3, accumulated bits -1 + bl L.3.15 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 4, accumulated bits -1 + bl L.4.15 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (-1*2+1), %o2 + +L.4.15: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (-1*2-1), %o2 + + +L.3.15: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 4, accumulated bits -3 + bl L.4.13 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (-3*2+1), %o2 + +L.4.13: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (-3*2-1), %o2 + + + +L.2.15: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 3, accumulated bits -3 + bl L.3.13 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 4, accumulated bits -5 + bl L.4.11 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (-5*2+1), %o2 + +L.4.11: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (-5*2-1), %o2 + + +L.3.13: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 4, accumulated bits -7 + bl L.4.9 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (-7*2+1), %o2 + +L.4.9: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (-7*2-1), %o2 + + + + + 9: +Lend_regular_divide: + deccc %o4 + bge Ldivloop + tst %o3 + bl,a Lgot_result + ! non-restoring fixup here (one instruction only!) + add %o3, %o1, %o3 + + +Lgot_result: + + retl + mov %o3, %o0 + diff --git a/src/kernel/boot/arch/sparc/libsa/alloc.c b/src/kernel/boot/arch/sparc/libsa/alloc.c new file mode 100644 index 0000000000..6e1a9d85c8 --- /dev/null +++ b/src/kernel/boot/arch/sparc/libsa/alloc.c @@ -0,0 +1,233 @@ +/* $OpenBSD: alloc.c,v 1.5 1997/08/01 21:57:09 pefo Exp $ */ +/* $NetBSD: alloc.c,v 1.6 1997/02/04 18:36:33 thorpej Exp $ */ + +/* + * Copyright (c) 1997 Christopher G. Demetriou. All rights reserved. + * Copyright (c) 1996 + * Matthias Drochner. All rights reserved. + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * The Mach Operating System project at Carnegie-Mellon University. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)alloc.c 8.1 (Berkeley) 6/11/93 + * + * + * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University + * All Rights Reserved. + * + * Author: Alessandro Forin + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +/* + * Dynamic memory allocator. + * + * Compile options: + * + * ALLOC_TRACE enable tracing of allocations/deallocations + * + * ALLOC_FIRST_FIT use a first-fit allocation algorithm, rather than + * the default best-fit algorithm. + * + * HEAP_LIMIT heap limit address (defaults to "no limit"). + * + * HEAP_START start address of heap (defaults to '&end'). + * + * DEBUG enable debugging sanity checks. + */ + +#include + +/* + * Each block actually has ALIGN(unsigned) + ALIGN(size) bytes allocated + * to it, as follows: + * + * 0 ... (sizeof(unsigned) - 1) + * allocated or unallocated: holds size of user-data part of block. + * + * sizeof(unsigned) ... (ALIGN(sizeof(unsigned)) - 1) + * allocated: unused + * unallocated: depends on packing of struct fl + * + * ALIGN(sizeof(unsigned)) ... (ALIGN(sizeof(unsigned)) + ALIGN(data size) - 1) + * allocated: user data + * unallocated: depends on packing of struct fl + * + * 'next' is only used when the block is unallocated (i.e. on the free list). + * However, note that ALIGN(sizeof(unsigned)) + ALIGN(data size) must + * be at least 'sizeof(struct fl)', so that blocks can be used as structures + * when on the free list. + */ + +#include "stand.h" + +struct fl { + unsigned size; + struct fl *next; +} *freelist = (struct fl *)0; + +#ifdef HEAP_START +static char *top = (char*)HEAP_START; +#else +extern char end[]; +static char *top = end; +#endif + +void * +alloc(size) + unsigned size; +{ + register struct fl **f = &freelist, **bestf = NULL; +#ifndef ALLOC_FIRST_FIT + unsigned bestsize = 0xffffffff; /* greater than any real size */ +#endif + char *help; + int failed; + +#ifdef ALLOC_TRACE + printf("alloc(%u)", size); +#endif + +#ifdef ALLOC_FIRST_FIT + while (*f != (struct fl *)0 && (*f)->size < size) + f = &((*f)->next); + bestf = f; + failed = (*bestf == (struct fl *)0); +#else + /* scan freelist */ + while (*f) { + if ((*f)->size >= size) { + if ((*f)->size == size) /* exact match */ + goto found; + + if ((*f)->size < bestsize) { + /* keep best fit */ + bestf = f; + bestsize = (*f)->size; + } + } + f = &((*f)->next); + } + + /* no match in freelist if bestsize unchanged */ + failed = (bestsize == 0xffffffff); +#endif + + if (failed) { /* nothing found */ + /* + * allocate from heap, keep chunk len in + * first word + */ + help = top; + + /* make _sure_ the region can hold a struct fl. */ + if (size < ALIGN(sizeof (struct fl *))) + size = ALIGN(sizeof (struct fl *)); + top += ALIGN(sizeof(unsigned)) + ALIGN(size); +#ifdef HEAP_LIMIT + if (top > (char*)HEAP_LIMIT) + panic("heap full (0x%lx+%u)", help, size); +#endif + *(unsigned *)help = ALIGN(size); +#ifdef ALLOC_TRACE + printf("=%p\n", help + ALIGN(sizeof(unsigned))); +#endif + return(help + ALIGN(sizeof(unsigned))); + } + + /* we take the best fit */ + f = bestf; + +#ifndef ALLOC_FIRST_FIT +found: +#endif + /* remove from freelist */ + help = (char*)*f; + *f = (*f)->next; +#ifdef ALLOC_TRACE + printf("=%p (origsize %u)\n", help + ALIGN(sizeof(unsigned)), + *(unsigned *)help); +#endif + return(help + ALIGN(sizeof(unsigned))); +} + +void +free(ptr, size) + void *ptr; + unsigned size; /* only for consistence check */ +{ + register struct fl *f = + (struct fl *)((char*)ptr - ALIGN(sizeof(unsigned))); +#ifdef ALLOC_TRACE + printf("free(%p, %u) (origsize %u)\n", ptr, size, f->size); +#endif +#ifdef DEBUG + if (size > f->size) + printf("free %u bytes @%p, should be <=%u\n", + size, ptr, f->size); +#ifdef HEAP_START + if (ptr < (void *)HEAP_START) +#else + if (ptr < (void *)end) +#endif + printf("free: %lx before start of heap.\n", (u_long)ptr); + +#ifdef HEAP_LIMIT + if (ptr > (void *)HEAP_LIMIT) + printf("free: %lx beyond end of heap.\n", (u_long)ptr); +#endif +#endif /* DEBUG */ + /* put into freelist */ + f->next = freelist; + freelist = f; +} + diff --git a/src/kernel/boot/arch/sparc/libsa/exit.c b/src/kernel/boot/arch/sparc/libsa/exit.c new file mode 100644 index 0000000000..de62d8ebbe --- /dev/null +++ b/src/kernel/boot/arch/sparc/libsa/exit.c @@ -0,0 +1,74 @@ +/* $OpenBSD: exit.c,v 1.4 1997/07/25 18:21:56 mickey Exp $ */ +/* $NetBSD: exit.c,v 1.11 1996/12/01 20:22:19 pk Exp $ */ + +/*- + * Copyright (c) 1993 John Brezak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifdef __STDC__ +#include +#else +#include +#endif + +#include "stand.h" + +__dead void +#ifdef __STDC__ +panic(const char *fmt, ...) +#else +panic(fmt /*, va_alist */) + char *fmt; +#endif +{ + extern void closeall __P((void)); + va_list ap; + static int paniced; + + if (!paniced) { + paniced = 1; + closeall(); + } + +#ifdef __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + vprintf(fmt, ap); + printf("\n"); + va_end(ap); + _rtt(); + /*NOTREACHED*/ +} + +void +exit() +{ + panic("exit"); + /*NOTREACHED*/ +} + diff --git a/src/kernel/boot/arch/sparc/libsa/memcmp.c b/src/kernel/boot/arch/sparc/libsa/memcmp.c new file mode 100644 index 0000000000..cf93550d71 --- /dev/null +++ b/src/kernel/boot/arch/sparc/libsa/memcmp.c @@ -0,0 +1,61 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: memcmp.c,v 1.4 1997/04/07 05:59:30 millert Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include "stand.h" + +/* + * Compare memory regions. + */ +int +memcmp(s1, s2, n) + const void *s1, *s2; + size_t n; +{ + if (n != 0) { + register const unsigned char *p1 = s1, *p2 = s2; + + do { + if (*p1++ != *p2++) + return (*--p1 - *--p2); + } while (--n != 0); + } + return (0); +} + diff --git a/src/kernel/boot/arch/sparc/libsa/memcpy.c b/src/kernel/boot/arch/sparc/libsa/memcpy.c new file mode 100644 index 0000000000..4f99e6b052 --- /dev/null +++ b/src/kernel/boot/arch/sparc/libsa/memcpy.c @@ -0,0 +1,64 @@ +/* $OpenBSD: memcpy.c,v 1.3 1996/10/16 11:32:07 mickey Exp $ */ +/* $NetBSD: bcopy.c,v 1.5 1995/04/22 13:46:50 cgd Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)bcopy.c 8.1 (Berkeley) 6/11/93 + */ + +#include +#include "stand.h" + +/* + * This is designed to be small, not fast. + */ +void * +memcpy(s1, s2, n) + void *s1; + const void *s2; + size_t n; +{ + register const char *f = s2; + register char *t = s1; + + if (f < t) { + f += n; + t += n; + while (n-- > 0) + *--t = *--f; + } else + while (n-- > 0) + *t++ = *f++; + return s1; +} + diff --git a/src/kernel/boot/arch/sparc/libsa/memset.c b/src/kernel/boot/arch/sparc/libsa/memset.c new file mode 100644 index 0000000000..3f0ec9b860 --- /dev/null +++ b/src/kernel/boot/arch/sparc/libsa/memset.c @@ -0,0 +1,52 @@ +/* $OpenBSD: memset.c,v 1.1 1996/10/15 09:41:55 mickey Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)bcopy.c 8.1 (Berkeley) 6/11/93 + */ + +#include +#include "stand.h" + +void * +memset(s1, c, n) + void *s1; + int c; + size_t n; +{ + register char *p = s1; + while (n--) + *p++ = c; + return s1; +} + diff --git a/src/kernel/boot/arch/sparc/libsa/printf.c b/src/kernel/boot/arch/sparc/libsa/printf.c new file mode 100644 index 0000000000..672f1f3cf7 --- /dev/null +++ b/src/kernel/boot/arch/sparc/libsa/printf.c @@ -0,0 +1,257 @@ +/* $OpenBSD: printf.c,v 1.14 1999/08/16 09:21:38 downsj Exp $ */ +/* $NetBSD: printf.c,v 1.10 1996/11/30 04:19:21 gwr Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)printf.c 8.1 (Berkeley) 6/11/93 + */ + +/* + * Scaled down version of printf(3). + * + * One additional format: + * + * The format %b is supported to decode error registers. + * Its usage is: + * + * printf("reg=%b\n", regval, "*"); + * + * where is the output base expressed as a control character, e.g. + * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, + * the first of which gives the bit number to be inspected (origin 1), and + * the next characters (up to a control character, i.e. a character <= 32), + * give the name of the register. Thus: + * + * printf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); + * + * would produce output: + * + * reg=3 + */ + +#include +#include +#ifdef __STDC__ +#include +#else +#include +#endif + +#include "stand.h" + +static void kprintn __P((void (*)(int), u_long, int)); +static void kdoprnt __P((void (*)(int), const char *, va_list)); + +#ifndef STRIPPED +static void sputchar __P((int)); +static char *sbuf; + +static void +sputchar(c) + int c; +{ + *sbuf++ = c; +} + +void +#ifdef __STDC__ +sprintf(char *buf, const char *fmt, ...) +#else +sprintf(buf, fmt, va_alist) + char *buf, *fmt; +#endif +{ + va_list ap; + + sbuf = buf; +#ifdef __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + kdoprnt(sputchar, fmt, ap); + va_end(ap); + *sbuf = '\0'; +} +#endif /* NO_SPRINTF */ + +void +#ifdef __STDC__ +printf(const char *fmt, ...) +#else +printf(fmt, va_alist) + char *fmt; +#endif +{ + va_list ap; + +#ifdef __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + kdoprnt(putchar, fmt, ap); + va_end(ap); +} + +void +vprintf(const char *fmt, va_list ap) +{ + kdoprnt(putchar, fmt, ap); +} + +static void +kdoprnt(put, fmt, ap) + void (*put)__P((int)); + const char *fmt; + va_list ap; +{ + register char *p; + register int ch; + unsigned long ul; + int lflag; + + for (;;) { + while ((ch = *fmt++) != '%') { + if (ch == '\0') + return; + put(ch); + } + lflag = 0; +reswitch: switch (ch = *fmt++) { + case 'l': + lflag = 1; + goto reswitch; +#ifndef STRIPPED + case 'b': + { + register int set, n; + ul = va_arg(ap, int); + p = va_arg(ap, char *); + kprintn(put, ul, *p++); + + if (!ul) + break; + + for (set = 0; (n = *p++);) { + if (ul & (1 << (n - 1))) { + put(set ? ',' : '<'); + for (; (n = *p) > ' '; ++p) + put(n); + set = 1; + } else + for (; *p > ' '; ++p); + } + if (set) + put('>'); + } + break; +#endif + case 'c': + ch = va_arg(ap, int); + put(ch & 0x7f); + break; + case 's': + p = va_arg(ap, char *); + while ((ch = *p++)) + put(ch); + break; + case 'd': + ul = lflag ? + va_arg(ap, long) : va_arg(ap, int); + if ((long)ul < 0) { + put('-'); + ul = -(long)ul; + } + kprintn(put, ul, 10); + break; + case 'o': + ul = lflag ? + va_arg(ap, u_long) : va_arg(ap, u_int); + kprintn(put, ul, 8); + break; + case 'u': + ul = lflag ? + va_arg(ap, u_long) : va_arg(ap, u_int); + kprintn(put, ul, 10); + break; + case 'p': + put('0'); + put('x'); + lflag += sizeof(void *)==sizeof(u_long)? 1 : 0; + case 'x': + ul = lflag ? + va_arg(ap, u_long) : va_arg(ap, u_int); + kprintn(put, ul, 16); + break; + default: + put('%'); + if (lflag) + put('l'); + put(ch); + } + } + va_end(ap); +} + +static void +kprintn(put, ul, base) + void (*put)__P((int)); + unsigned long ul; + int base; +{ + /* hold a long in base 8 */ + char *p, buf[(sizeof(long) * NBBY / 3) + 1]; + + p = buf; + do { + *p++ = "0123456789abcdef"[ul % base]; + } while (ul /= base); + do { + put(*--p); + } while (p > buf); +} + +int donottwiddle = 0; + +void +twiddle() +{ + static int pos; + + if (!donottwiddle) { + putchar("|/-\\"[pos++ & 3]); + putchar('\b'); + } +} + diff --git a/src/kernel/boot/arch/sparc/libsa/strcmp.c b/src/kernel/boot/arch/sparc/libsa/strcmp.c new file mode 100644 index 0000000000..655efca72b --- /dev/null +++ b/src/kernel/boot/arch/sparc/libsa/strcmp.c @@ -0,0 +1,47 @@ +/* $OpenBSD: strcmp.c,v 1.2 1996/10/16 11:32:07 mickey Exp $ */ + +/*- + * Copyright (c) 1996 Michael Shalayeff + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Michael Shalayeff. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include "stand.h" + +int +strcmp(s1, s2) + register const char *s1; + register const char *s2; +{ + while(*s1 && *s2 && *s1 == *s2) + s1++, s2++; + return *s1 - *s2; +} + diff --git a/src/kernel/boot/arch/sparc/promdev.c b/src/kernel/boot/arch/sparc/promdev.c new file mode 100644 index 0000000000..6af09c95d4 --- /dev/null +++ b/src/kernel/boot/arch/sparc/promdev.c @@ -0,0 +1,806 @@ +/* $OpenBSD: promdev.c,v 1.2 1999/01/11 05:12:00 millert Exp $ */ +/* $NetBSD: promdev.c,v 1.16 1995/11/14 15:04:01 pk Exp $ */ + +/* + * Copyright (c) 1993 Paul Kranenburg + * Copyright (c) 1995 Gordon W. Ross + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Paul Kranenburg. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Note: the `#ifndef BOOTXX' in here serve to queeze the code size + * of the 1st-stage boot program. + */ +#include +#include +#include +#include +#include + +#include + +#include + +/* u_long _randseed = 1; */ + + +int obp_close __P((struct open_file *)); +int obp_strategy __P((void *, int, daddr_t, size_t, void *, size_t *)); +ssize_t obp_xmit __P((struct promdata *, void *, size_t)); +ssize_t obp_recv __P((struct promdata *, void *, size_t)); +int prom0_close __P((struct open_file *)); +int prom0_strategy __P((void *, int, daddr_t, size_t, void *, size_t *)); +void prom0_iclose __P((struct saioreq *)); +int prom0_iopen __P((struct promdata *)); +ssize_t prom0_xmit __P((struct promdata *, void *, size_t)); +ssize_t prom0_recv __P((struct promdata *, void *, size_t)); + +static char *prom_mapin __P((u_long, int, int)); + +int getdevtype __P((int, char *)); +int getprop __P((int, char *, void *, int)); +char *getpropstring __P((int, char *)); + +static void prom0_fake __P((void)); + +extern struct filesystem file_system_nfs[]; +extern struct filesystem file_system_cd9660[]; +extern struct filesystem file_system_ufs[]; + +int prom_open __P((struct open_file *f, ...)) { return 0; } +int prom_ioctl __P((struct open_file *f, u_long c, void *d)) { return EIO; } + +struct devsw devsw[] = { + { "prom0", prom0_strategy, prom_open, prom0_close, prom_ioctl }, + { "prom", obp_strategy, prom_open, obp_close, prom_ioctl } +}; + +int ndevs = (sizeof(devsw)/sizeof(devsw[0])); + +char *prom_bootdevice; +char *prom_bootfile; +int prom_boothow; + +struct promvec *promvec; +static int saveecho; + +void +prom_init() +{ + register char *ap, *cp, *dp; + + if (cputyp == CPU_SUN4) + prom0_fake(); + + if (promvec->pv_romvec_vers >= 2) { + static char filestore[16]; + + prom_bootdevice = *promvec->pv_v2bootargs.v2_bootpath; + +#ifndef BOOTXX + cp = *promvec->pv_v2bootargs.v2_bootargs; + dp = prom_bootfile = filestore; + while (*cp && *cp != '-') + *dp++ = *cp++; + while (dp > prom_bootfile && *--dp == ' '); + *++dp = '\0'; + ap = cp; +#endif + } else { + static char bootstore[16]; + dp = prom_bootdevice = bootstore; + cp = (*promvec->pv_v0bootargs)->ba_argv[0]; + while (*cp) { + *dp++ = *cp; + if (*cp++ == ')') + break; + } + *dp = '\0'; +#ifndef BOOTXX + prom_bootfile = (*promvec->pv_v0bootargs)->ba_kernel; + ap = (*promvec->pv_v0bootargs)->ba_argv[1]; +#endif + } + +#ifndef BOOTXX + if (ap == NULL || *ap != '-') + return; + + while (*ap) { + switch (*ap++) { + case 'a': + prom_boothow |= RB_ASKNAME; + break; + case 's': + prom_boothow |= RB_SINGLE; + break; + case 'd': + prom_boothow |= RB_KDB; + debug = 1; + break; + } + } +#endif +} + +int +devopen(f, fname, file) + struct open_file *f; + const char *fname; + char **file; +{ + int error = 0, fd; + struct promdata *pd; + + pd = (struct promdata *)alloc(sizeof *pd); + + if (cputyp == CPU_SUN4) { + error = prom0_iopen(pd); +#ifndef BOOTXX + pd->xmit = prom0_xmit; + pd->recv = prom0_recv; +#endif + } else { + fd = (promvec->pv_romvec_vers >= 2) + ? (*promvec->pv_v2devops.v2_open)(prom_bootdevice) + : (*promvec->pv_v0devops.v0_open)(prom_bootdevice); + if (fd == 0) { + error = ENXIO; + } else { + pd->fd = fd; +#ifndef BOOTXX + pd->xmit = obp_xmit; + pd->recv = obp_recv; +#endif + } + } + + if (error) { + printf("Can't open device `%s'\n", prom_bootdevice); + return (error); + } + +#ifdef BOOTXX + pd->devtype = DT_BLOCK; +#else /* BOOTXX */ + pd->devtype = getdevtype(fd, prom_bootdevice); + /* Assume type BYTE is a raw device */ + if (pd->devtype != DT_BYTE) + *file = (char *)fname; + + if (pd->devtype == DT_NET) { + bcopy(file_system_nfs, file_system, sizeof(struct fs_ops)); + if ((error = net_open(pd)) != 0) { + printf("Can't open network device `%s'\n", + prom_bootdevice); + return error; + } + } else { + bcopy(file_system_ufs, file_system, sizeof(struct fs_ops)); + bcopy(&file_system_cd9660, file_system + 1, sizeof file_system[0]); + nfsys = 2; + } +#endif /* BOOTXX */ + + f->f_dev = &devsw[cputyp == CPU_SUN4 ? 0 : 1]; + f->f_devdata = (void *)pd; + return 0; +} + +int +obp_strategy(devdata, flag, dblk, size, buf, rsize) + void *devdata; + int flag; + daddr_t dblk; + size_t size; + void *buf; + size_t *rsize; +{ + int error = 0; + struct promdata *pd = (struct promdata *)devdata; + int fd = pd->fd; + +#ifdef DEBUG_PROM + printf("promstrategy: size=%d dblk=%d\n", size, dblk); +#endif + + if (promvec->pv_romvec_vers >= 2) { + if (pd->devtype == DT_BLOCK) + (*promvec->pv_v2devops.v2_seek)(fd, 0, dbtob(dblk)); + + *rsize = (*((flag == F_READ) + ? (u_int (*)())promvec->pv_v2devops.v2_read + : (u_int (*)())promvec->pv_v2devops.v2_write + ))(fd, buf, size); + } else { + int n = (*((flag == F_READ) + ? (u_int (*)())promvec->pv_v0devops.v0_rbdev + : (u_int (*)())promvec->pv_v0devops.v0_wbdev + ))(fd, btodb(size), dblk, buf); + *rsize = dbtob(n); + } + +#ifdef DEBUG_PROM + printf("rsize = %x\n", *rsize); +#endif + return error; +} + +/* + * On old-monitor machines, things work differently. + */ +int +prom0_strategy(devdata, flag, dblk, size, buf, rsize) + void *devdata; + int flag; + daddr_t dblk; + size_t size; + void *buf; + size_t *rsize; +{ + struct promdata *pd = devdata; + struct saioreq *si; + struct om_boottable *ops; + char *dmabuf; + int si_flag; + size_t xcnt; + + si = pd->si; + ops = si->si_boottab; + +#ifdef DEBUG_PROM + printf("prom_strategy: size=%d dblk=%d\n", size, dblk); +#endif + + dmabuf = dvma_mapin(buf, size); + + si->si_bn = dblk; + si->si_ma = dmabuf; + si->si_cc = size; + + si_flag = (flag == F_READ) ? SAIO_F_READ : SAIO_F_WRITE; + xcnt = (*ops->b_strategy)(si, si_flag); + dvma_mapout(dmabuf, size); + +#ifdef DEBUG_PROM + printf("disk_strategy: xcnt = %x\n", xcnt); +#endif + + if (xcnt <= 0) + return (EIO); + + *rsize = xcnt; + return (0); +} + +int +obp_close(f) + struct open_file *f; +{ + struct promdata *pd = f->f_devdata; + register int fd = pd->fd; + +#ifndef BOOTXX + if (pd->devtype == DT_NET) + net_close(pd); +#endif + if (promvec->pv_romvec_vers >= 2) + (void)(*promvec->pv_v2devops.v2_close)(fd); + else + (void)(*promvec->pv_v0devops.v0_close)(fd); + return 0; +} + +int +prom0_close(f) + struct open_file *f; +{ + struct promdata *pd = f->f_devdata; + +#ifndef BOOTXX + if (pd->devtype == DT_NET) + net_close(pd); +#endif + prom0_iclose(pd->si); + pd->si = NULL; + *romp->echo = saveecho; /* Hmm, probably must go somewhere else */ + return 0; +} + +#ifndef BOOTXX +ssize_t +obp_xmit(pd, buf, len) + struct promdata *pd; + void *buf; + size_t len; +{ + return (promvec->pv_romvec_vers >= 2 + ? (*promvec->pv_v2devops.v2_write)(pd->fd, buf, len) + : (*promvec->pv_v0devops.v0_wnet)(pd->fd, len, buf)); +} + +ssize_t +obp_recv(pd, buf, len) + struct promdata *pd; + void *buf; + size_t len; +{ + int n; + + n = (promvec->pv_romvec_vers >= 2 + ? (*promvec->pv_v2devops.v2_read)(pd->fd, buf, len) + : (*promvec->pv_v0devops.v0_rnet)(pd->fd, len, buf)); + return (n == -2 ? 0 : n); +} + +ssize_t +prom0_xmit(pd, buf, len) + struct promdata *pd; + void *buf; + size_t len; +{ + struct saioreq *si; + struct saif *sif; + char *dmabuf; + int rv; + + si = pd->si; + sif = si->si_sif; + if (sif == NULL) { + printf("xmit: not a network device\n"); + return (-1); + } + dmabuf = dvma_mapin(buf, len); + rv = sif->sif_xmit(si->si_devdata, dmabuf, len); + dvma_mapout(dmabuf, len); + + return (ssize_t)(rv ? -1 : len); +} + +ssize_t +prom0_recv(pd, buf, len) + struct promdata *pd; + void *buf; + size_t len; +{ + struct saioreq *si; + struct saif *sif; + char *dmabuf; + int rv; + + si = pd->si; + sif = si->si_sif; + dmabuf = dvma_mapin(buf, len); + rv = sif->sif_poll(si->si_devdata, dmabuf); + dvma_mapout(dmabuf, len); + + return (ssize_t)rv; +} + +int +getchar() +{ + char c; + register int n; + + if (promvec->pv_romvec_vers > 2) + while ((n = (*promvec->pv_v2devops.v2_read) + (*promvec->pv_v2bootargs.v2_fd0, (caddr_t)&c, 1)) != 1); + else + c = (*promvec->pv_getchar)(); + + if (c == '\r') + c = '\n'; + return (c); +} + +int +cngetc() +{ + return getchar(); +} + +int +peekchar() +{ + char c; + register int n; + + if (promvec->pv_romvec_vers > 2) { + n = (*promvec->pv_v2devops.v2_read) + (*promvec->pv_v2bootargs.v2_fd0, (caddr_t)&c, 1); + if (n < 0) + return -1; + } else + c = (*promvec->pv_nbgetchar)(); + + if (c == '\r') + c = '\n'; + return (c); +} +#endif + +static void +pv_putchar(c) + int c; +{ + char c0 = c; + + if (promvec->pv_romvec_vers > 2) + (*promvec->pv_v2devops.v2_write) + (*promvec->pv_v2bootargs.v2_fd1, &c0, 1); + else + (*promvec->pv_putchar)(c); +} + +void +putchar(c) + int c; +{ + + if (c == '\n') + pv_putchar('\r'); + pv_putchar(c); +} + +void +_rtt() +{ + promvec->pv_halt(); +} + +#ifndef BOOTXX +int hz = 1000; + +time_t +getsecs() +{ + register int ticks = getticks(); + return ((time_t)(ticks / hz)); +} + +int +getticks() +{ + if (promvec->pv_romvec_vers >= 2) { + char c; + (void)(*promvec->pv_v2devops.v2_read) + (*promvec->pv_v2bootargs.v2_fd0, (caddr_t)&c, 0); + } else { + (void)(*promvec->pv_nbgetchar)(); + } + return *(promvec->pv_ticks); +} + +void +prom_getether(fd, ea) + u_char *ea; +{ + if (cputyp == CPU_SUN4) { + static struct idprom sun4_idprom; + u_char *src, *dst; + int len, x; + + if (sun4_idprom.id_format == 0) { + dst = (char*)&sun4_idprom; + src = (char*)AC_IDPROM; + len = sizeof(struct idprom); + do { + x = lduba(src++, ASI_CONTROL); + *dst++ = x; + } while (--len > 0); + } + bcopy(sun4_idprom.id_ether, ea, 6); + } else if (promvec->pv_romvec_vers <= 2) { + (void)(*promvec->pv_enaddr)(fd, (char *)ea); + } else { + char buf[64]; + sprintf(buf, "%x mac-address drop swap 6 cmove", ea); + promvec->pv_fortheval.v2_eval(buf); + } +} + + +/* + * A number of well-known devices on sun4s. + */ +static struct dtab { + char *name; + int type; +} dtab[] = { + { "sd", DT_BLOCK }, + { "st", DT_BLOCK }, + { "xd", DT_BLOCK }, + { "xy", DT_BLOCK }, + { "fd", DT_BLOCK }, + { "le", DT_NET }, + { "ie", DT_NET }, + { NULL, 0 } +}; + +int +getdevtype(fd, name) + int fd; + char *name; +{ + if (promvec->pv_romvec_vers >= 2) { + int node = (*promvec->pv_v2devops.v2_fd_phandle)(fd); + char *cp = getpropstring(node, "device_type"); + if (strcmp(cp, "block") == 0) + return DT_BLOCK; + else if (strcmp(cp, "network") == 0) + return DT_NET; + else if (strcmp(cp, "byte") == 0) + return DT_BYTE; + } else { + struct dtab *dp; + for (dp = dtab; dp->name; dp++) { + if (name[0] == dp->name[0] && + name[1] == dp->name[1]) + return dp->type; + } + } + return 0; +} + +/* + * OpenPROM nodes & property routines (from ). + */ +int +getprop(node, name, buf, bufsiz) + int node; + char *name; + void *buf; + register int bufsiz; +{ + register struct nodeops *no; + register int len; + + no = promvec->pv_nodeops; + len = no->no_proplen(node, name); + if (len > bufsiz) { + printf("node %x property %s length %d > %d\n", + node, name, len, bufsiz); + return (0); + } + no->no_getprop(node, name, buf); + return (len); +} + +/* + * Return a string property. There is a (small) limit on the length; + * the string is fetched into a static buffer which is overwritten on + * subsequent calls. + */ +char * +getpropstring(node, name) + int node; + char *name; +{ + register int len; + static char stringbuf[64]; + + len = getprop(node, name, (void *)stringbuf, sizeof stringbuf - 1); + if (len == -1) + len = 0; + stringbuf[len] = '\0'; /* usually unnecessary */ + return (stringbuf); +} +#endif /* BOOTXX */ + +/* + * Old monitor routines + */ + +#include + +struct saioreq prom_si; +static int promdev_inuse; + +int +prom0_iopen(pd) + struct promdata *pd; +{ + struct om_bootparam *bp; + struct om_boottable *ops; + struct devinfo *dip; + struct saioreq *si; + int error; + + if (promdev_inuse) + return(EMFILE); + + bp = *romp->bootParam; + ops = bp->bootTable; + dip = ops->b_devinfo; + +#ifdef DEBUG_PROM + printf("Boot device type: %s\n", ops->b_desc); + printf("d_devbytes=%d\n", dip->d_devbytes); + printf("d_dmabytes=%d\n", dip->d_dmabytes); + printf("d_localbytes=%d\n", dip->d_localbytes); + printf("d_stdcount=%d\n", dip->d_stdcount); + printf("d_stdaddrs[%d]=%x\n", bp->ctlrNum, dip->d_stdaddrs[bp->ctlrNum]); + printf("d_devtype=%d\n", dip->d_devtype); + printf("d_maxiobytes=%d\n", dip->d_maxiobytes); +#endif + + dvma_init(); + + si = &prom_si; + bzero((caddr_t)si, sizeof(*si)); + si->si_boottab = ops; + si->si_ctlr = bp->ctlrNum; + si->si_unit = bp->unitNum; + si->si_boff = bp->partNum; + + if (si->si_ctlr > dip->d_stdcount) { + printf("Invalid controller number\n"); + return(ENXIO); + } + + if (dip->d_devbytes) { + si->si_devaddr = prom_mapin(dip->d_stdaddrs[si->si_ctlr], + dip->d_devbytes, dip->d_devtype); +#ifdef DEBUG_PROM + printf("prom_iopen: devaddr=0x%x pte=0x%x\n", + si->si_devaddr, + getpte((u_long)si->si_devaddr & ~PGOFSET)); +#endif + } + + if (dip->d_dmabytes) { + si->si_dmaaddr = dvma_alloc(dip->d_dmabytes); +#ifdef DEBUG_PROM + printf("prom_iopen: dmaaddr=0x%x\n", si->si_dmaaddr); +#endif + } + + if (dip->d_localbytes) { + si->si_devdata = alloc(dip->d_localbytes); +#ifdef DEBUG_PROM + printf("prom_iopen: devdata=0x%x\n", si->si_devdata); +#endif + } + + /* OK, call the PROM device open routine. */ + error = (*ops->b_open)(si); + if (error != 0) { + printf("prom_iopen: \"%s\" error=%d\n", + ops->b_desc, error); + return (ENXIO); + } +#ifdef DEBUG_PROM + printf("prom_iopen: succeeded, error=%d\n", error); +#endif + + pd->si = si; + promdev_inuse++; + return (0); +} + +void +prom0_iclose(si) + struct saioreq *si; +{ + struct om_boottable *ops; + struct devinfo *dip; + + if (promdev_inuse == 0) + return; + + ops = si->si_boottab; + dip = ops->b_devinfo; + + (*ops->b_close)(si); + + if (si->si_dmaaddr) { + dvma_free(si->si_dmaaddr, dip->d_dmabytes); + si->si_dmaaddr = NULL; + } + + promdev_inuse = 0; +} + +static struct mapinfo { + int maptype; + int pgtype; + int base; +} prom_mapinfo[] = { + { MAP_MAINMEM, PG_OBMEM, 0 }, + { MAP_OBIO, PG_OBIO, 0 }, + { MAP_MBMEM, PG_VME16, 0xFF000000 }, + { MAP_MBIO, PG_VME16, 0xFFFF0000 }, + { MAP_VME16A16D, PG_VME16, 0xFFFF0000 }, + { MAP_VME16A32D, PG_VME32, 0xFFFF0000 }, + { MAP_VME24A16D, PG_VME16, 0xFF000000 }, + { MAP_VME24A32D, PG_VME32, 0xFF000000 }, + { MAP_VME32A16D, PG_VME16, 0 }, + { MAP_VME32A32D, PG_VME32, 0 }, +}; +static prom_mapinfo_cnt = sizeof(prom_mapinfo) / sizeof(prom_mapinfo[0]); + +/* The virtual address we will use for PROM device mappings. */ +static u_long prom_devmap = MONSHORTSEG; + +static char * +prom_mapin(physaddr, length, maptype) + u_long physaddr; + int length, maptype; +{ + int i, pa, pte, va; + + if (length > (4*NBPG)) + panic("prom_mapin: length=%d", length); + + for (i = 0; i < prom_mapinfo_cnt; i++) + if (prom_mapinfo[i].maptype == maptype) + goto found; + panic("prom_mapin: invalid maptype %d", maptype); +found: + + pte = prom_mapinfo[i].pgtype; + pte |= (PG_V|PG_W|PG_S|PG_NC); + pa = prom_mapinfo[i].base; + pa += physaddr; + pte |= ((pa >> PGSHIFT) & PG_PFNUM); + + va = prom_devmap; + do { + setpte(va, pte); + va += NBPG; + pte += 1; + length -= NBPG; + } while (length > 0); + return ((char*)(prom_devmap | (pa & PGOFSET))); +} + +void +prom0_fake() +{ +static struct promvec promvecstore; + + promvec = &promvecstore; + + promvec->pv_stdin = romp->inSource; + promvec->pv_stdout = romp->outSink; + promvec->pv_putchar = romp->putChar; + promvec->pv_putstr = romp->fbWriteStr; + promvec->pv_nbgetchar = romp->mayGet; + promvec->pv_getchar = romp->getChar; + promvec->pv_romvec_vers = 0; /* eek! */ + promvec->pv_reboot = romp->reBoot; + promvec->pv_abort = romp->abortEntry; + promvec->pv_setctxt = romp->setcxsegmap; + promvec->pv_v0bootargs = (struct v0bootargs **)(romp->bootParam); + promvec->pv_halt = romp->exitToMon; + promvec->pv_ticks = romp->nmiClock; + saveecho = *romp->echo; + *romp->echo = 0; +} + diff --git a/src/kernel/boot/arch/sparc/srt0.S b/src/kernel/boot/arch/sparc/srt0.S new file mode 100644 index 0000000000..f52f03105c --- /dev/null +++ b/src/kernel/boot/arch/sparc/srt0.S @@ -0,0 +1,180 @@ +/* $OpenBSD: srt0.S,v 1.1 1997/09/17 10:46:20 downsj Exp $ */ +/* $NetBSD: srt0.S,v 1.5.4.2 1996/07/17 01:51:46 jtc Exp $ */ + +/* + * Copyright (c) 1994 Paul Kranenburg + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Paul Kranenburg. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + + .file "str0.s" + + .data + .global cputyp, nbpg, pgofset, pgshift +cputyp: + .word 1 +nbpg: + .word 1 +pgofset: + .word 1 +pgshift: + .word 1 +#define STACK_SIZE 2048 +tstack: + .fill STACK_SIZE + + .text + .globl start + +start: + /* + * Set up a stack. + */ + set tstack, %o1 + save %o1, STACK_SIZE-4, %sp + +4: +#ifdef notyet + /* + * Enable traps + */ + wr %g0, 0, %wim ! make sure we can set psr + nop; nop; nop + wr %g0, PSR_S|PSR_PS|PSR_PIL, %psr ! set initial psr + nop; nop; nop + wr %g0, 2, %wim ! set initial %wim (w1 invalid) + + rd %psr, %l0 + wr %l0, PSR_ET, %psr + nop; nop; nop +#endif + + /* + * Clear BSS + */ + set _edata, %o0 ! bzero(edata, end - edata) + set _end, %o1 + call bzero + sub %o1, %o0, %o1 + + /* + * Enable interrupts, but only above level 11. This enables "L1-A", + * but avoids spurious interrupt bites from most other devices. + */ + rd %psr, %o0 + andn %o0, PSR_PIL, %o0 + wr %o0, 0xb00, %psr ! (11 << 8) + nop; nop; nop + + /* + * Set CPU type that we are running on. + */ + sethi %hi(cputyp), %o0 + set 0x4000, %g7 + cmp %i0, %g7 + beq 5f + nop + + /* + * Save address of PROM vector (passed in %i0). + */ + sethi %hi(promvec), %o1 + st %i0, [%o1 + %lo(promvec)] + + mov CPU_SUN4C, %g4 + mov SUN4CM_PGSHIFT, %g5 + b,a 6f + +5: + mov CPU_SUN4, %g4 + mov SUN4_PGSHIFT, %g5 + +6: + st %g4, [%o0 + %lo(cputyp)] + sethi %hi(pgshift), %o0 ! pgshift = log2(nbpg) + st %g5, [%o0 + %lo(pgshift)] + + mov 1, %o0 ! nbpg = 1 << pgshift + sll %o0, %g5, %g5 + sethi %hi(nbpg), %o0 ! nbpg = bytes in a page + st %g5, [%o0 + %lo(nbpg)] + + sub %g5, 1, %g5 + sethi %hi(pgofset), %o0 ! page offset = bytes in a page - 1 + st %g5, [%o0 + %lo(pgofset)] + + call main + mov %i0, %o0 + + ret + restore + + +#ifdef TIGHT + +/* + * XXX - Space saving .div & .rem routines (small & non-negative numbres only) + */ + .align 4 + .global .div, .udiv +! int n = 0; while (a >= b) { a -= b; n++; }; return n; +.div: +.udiv: + cmp %o0, %o1 + bl 2f + mov 0, %o5 +1: + sub %o0, %o1, %o0 + cmp %o0, %o1 + bge 1b + add %o5, 1, %o5 +2: + retl + mov %o5, %o0 + + .align 4 + .global .rem, .urem +! while (a>=b) a -= b; return a; +.rem: +.urem: + cmp %o0, %o1 + bl 2f + nop + sub %o0, %o1, %o0 +1: + cmp %o0, %o1 + bge,a 1b + sub %o0, %o1, %o0 +2: + retl + nop + +#endif /* TIGHT */ + diff --git a/src/kernel/boot/arch/sparc/stage2.c b/src/kernel/boot/arch/sparc/stage2.c new file mode 100644 index 0000000000..cbf9c44319 --- /dev/null +++ b/src/kernel/boot/arch/sparc/stage2.c @@ -0,0 +1,263 @@ +/* $OpenBSD: bootxx.c,v 1.1 1997/09/17 10:46:16 downsj Exp $ */ +/* $NetBSD: bootxx.c,v 1.2 1997/09/14 19:28:17 pk Exp $ */ + +/* + * Copyright (c) 1994 Paul Kranenburg + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Paul Kranenburg. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include + +#include + +int debug; +int netif_debug; + +/* + * Boot device is derived from ROM provided information. + */ +const char progname[] = "bootxx"; +struct open_file io; + +/* + * The contents of the block_* variables below is set by installboot(8) + * to hold the the filesystem data of the second-stage boot program + * (typically `/boot'): filesystem block size, # of filesystem blocks and + * the block numbers themselves. + */ +#define MAXBLOCKNUM 256 /* enough for a 2MB boot program (bs 8K) */ +int32_t block_size = 0; +int32_t block_count = MAXBLOCKNUM; +daddr_t block_table[MAXBLOCKNUM] = { 0 }; + +int memory_node = 0; + +void loadboot __P((struct open_file *, caddr_t)); + +void scan_node(int node, char *buf, int recurse, int level) +{ + char *ptr; + int node1; + + do { +// printf("%dnode 0x%x\n", level, node); + ptr = NULL; + for(ptr = promvec->pv_nodeops->no_nextprop(node, NULL); + ptr != NULL && ptr[0] != '\0'; + ptr = promvec->pv_nodeops->no_nextprop(node, ptr)) { + +// printf("%d\tproperty '%s'\n", level, ptr); + + if(!strcmp(ptr, "name")) { + promvec->pv_nodeops->no_getprop(node, ptr, buf); +// printf("%d\t\tname = '%s'\n", level, buf); + if(!strcmp(buf, "memory")) { + memory_node = node; + } + } + + } + node1 = promvec->pv_nodeops->no_child(node); +// printf("%d\tchild = 0x%x\n", level, node1); + if(node1 != 0 && recurse != 0) { + scan_node(node1, buf, recurse, level+1); + } + node = promvec->pv_nodeops->no_nextnode(node); + } while(node != 0); +} + +void scan_nodes() +{ + char buf[64]; + + // Walk through the nodes + { + int node = 0; + + node = promvec->pv_nodeops->no_nextnode(node); + scan_node(node, buf, 1, 0); + } +} + +/* + * Internal form of getprop(). Returns the actual length. + */ +int +getprop(node, name, buf, bufsiz) + int node; + char *name; + void *buf; + register int bufsiz; +{ +#if defined(SUN4C) || defined(SUN4M) + register struct nodeops *no; + register int len; +#endif + +#if defined(SUN4) + if (CPU_ISSUN4) { + printf("WARNING: getprop not valid on sun4! %s\n", name); + return (0); + } +#endif + +#if defined(SUN4C) || defined(SUN4M) + no = promvec->pv_nodeops; + len = no->no_proplen(node, name); + if (len > bufsiz) { + printf("node 0x%x property %s length %d > %d\n", + node, name, len, bufsiz); +#ifdef DEBUG + panic("getprop"); +#else + return (0); +#endif + } + no->no_getprop(node, name, buf); + return (len); +#endif +} + +int +main() +{ + char *dummy; + size_t n; + register void (*entry)__P((caddr_t)) = (void (*)__P((caddr_t)))LOADADDR; + + prom_init(); + + printf("Welcome to second stage bootloader!\n"); + + printf("cputyp = %d\n", cputyp); + printf("nbpg = %d\n", nbpg); + printf("pgofset = %d\n", pgofset); + printf("pgshift = %d\n", pgshift); + printf("promvec = 0x%x\n", (unsigned int)promvec); + + printf("Scanning nodes..."); + scan_nodes(); + printf("done\n"); + printf("memory_node = 0x%x\n", memory_node); + + // Look at how memory is laid out + { + struct openprom_addr addr[64]; + int len; + int i; + + len = getprop(memory_node, "reg", &addr, sizeof(addr)) / + sizeof(struct openprom_addr); + printf("retrieved physical memory layout struct. size %d:\n", len); + + for(i=0; idv_close)(&io); + (*entry)(cputyp == CPU_SUN4 ? LOADADDR : (caddr_t)promvec); +*/ + _rtt(); +} + +void +loadboot(f, addr) + register struct open_file *f; + register char *addr; +{ + return; +} + +#if 0 +void +loadboot(f, addr) + register struct open_file *f; + register char *addr; +{ + register int i; + register char *buf; + size_t n; + daddr_t blk; + + /* + * Allocate a buffer that we can map into DVMA space; only + * needed for sun4 architecture, but use it for all machines + * to keep code size down as much as possible. + */ + buf = alloc(block_size); + if (buf == NULL) + panic("%s: alloc failed", progname); + + for (i = 0; i < block_count; i++) { + if ((blk = block_table[i]) == 0) + panic("%s: block table corrupt", progname); + +#ifdef DEBUG + printf("%s: block # %d = %d\n", progname, i, blk); +#endif + if ((f->f_dev->dv_strategy)(f->f_devdata, F_READ, + blk, block_size, buf, &n)) { + panic("%s: read failure", progname); + } + bcopy(buf, addr, block_size); + if (n != block_size) + panic("%s: short read", progname); + if (i == 0) { + register int m = N_GETMAGIC(*(struct exec *)addr); + if (m == ZMAGIC || m == NMAGIC || m == OMAGIC) { + /* Move exec header out of the way */ + bcopy(addr, addr - sizeof(struct exec), n); + addr -= sizeof(struct exec); + } + } + addr += n; + } + +} +#endif + diff --git a/src/kernel/boot/arch/sparc/stage2.mk b/src/kernel/boot/arch/sparc/stage2.mk new file mode 100644 index 0000000000..f7103b305c --- /dev/null +++ b/src/kernel/boot/arch/sparc/stage2.mk @@ -0,0 +1,58 @@ +CFLAGS = -O3 -DBOOTXX -D_STANDALONE -DSTANDALONE -DRELOC=0x380000 -DSUN4M -DSUN_BOOTPARAMS -DDEBUG -DDEBUG_PROM -Iboot/$(ARCH)/include +LIBSACFLAGS = -O3 -D_STANDALONE -D__INTERNAL_LIBSA_CREAD -Iboot/$(ARCH)/include +LIBKERNCFLAGS = -O3 -D_KERNEL -Iboot/$(ARCH)/include + +STAGE2_OBJS = boot/$(ARCH)/srt0.o \ + boot/$(ARCH)/promdev.o \ + boot/$(ARCH)/closeall.o \ + boot/$(ARCH)/dvma.o \ + boot/$(ARCH)/stage2.o \ + boot/$(ARCH)/libsa/alloc.o \ + boot/$(ARCH)/libsa/exit.o \ + boot/$(ARCH)/libsa/printf.o \ + boot/$(ARCH)/libsa/memset.o \ + boot/$(ARCH)/libsa/memcpy.o \ + boot/$(ARCH)/libsa/memcmp.o \ + boot/$(ARCH)/libsa/strcmp.o \ + boot/$(ARCH)/libkern/bzero.o \ + boot/$(ARCH)/libkern/udiv.o \ + boot/$(ARCH)/libkern/urem.o \ + boot/$(ARCH)/libkern/__main.o + +DEPS += $(STAGE2_OBJS:.o=.d) + +boot/$(ARCH)/stage2: $(STAGE2_OBJS) + ld -dN -Ttext 0x381278 -e start $(STAGE2_OBJS) -o $@ + +boot/$(ARCH)/libsa/%.o: boot/$(ARCH)/libsa/%.c + $(CC) $(LIBSACFLAGS) -c $< -o $@ + +boot/$(ARCH)/libsa/%.d: boot/$(ARCH)/libsa/%.c + @($(ECHO) -n $(dir $@);$(CC) $(LIBSACFLAGS) -M -MG $<) > $@ + +boot/$(ARCH)/libkern/%.o: boot/$(ARCH)/libkern/%.c + $(CC) $(LIBKERNCFLAGS) -c $< -o $@ + +boot/$(ARCH)/libkern/%.d: boot/$(ARCH)/libkern/%.c + @($(ECHO) -n $(dir $@);$(CC) $(LIBKERNCFLAGS) -M -MG $<) > $@ + +boot/$(ARCH)/libkern/%.o: boot/$(ARCH)/libkern/%.S + $(CC) $(LIBKERNCFLAGS) -c $< -o $@ + +boot/$(ARCH)/libkern/%.d: boot/$(ARCH)/libkern/%.S + @($(ECHO) -n $(dir $@);$(CC) $(LIBKERNCFLAGS) -M -MG $<) > $@ + +boot/$(ARCH)/%.o: boot/$(ARCH)/%.S + $(CC) $(CFLAGS) -D_LOCORE -c $< -o $@ + +boot/$(ARCH)/%.d: boot/$(ARCH)/%.S + @($(ECHO) -n $(dir $@);$(CC) $(CFLAGS) -D_LOCORE -M -MG $<) > $@ + +boot/$(ARCH)/%.o: boot/$(ARCH)/%.c + $(CC) $(CFLAGS) -c $< -o $@ + +boot/$(ARCH)/%.d: boot/$(ARCH)/%.c + @($(ECHO) -n $(dir $@);$(CC) $(CFLAGS) -M -MG $<) > $@ + +stage2clean: + rm -f $(STAGE2_OBJS) boot/$(ARCH)/stage2 boot/$(ARCH)/a.out diff --git a/src/kernel/boot/arch/sparc64/Jamfile b/src/kernel/boot/arch/sparc64/Jamfile new file mode 100644 index 0000000000..5f7813cd83 --- /dev/null +++ b/src/kernel/boot/arch/sparc64/Jamfile @@ -0,0 +1,2 @@ +SubDir OBOS_TOP sources os kits kernel boot arch sparc64 ; + diff --git a/src/kernel/boot/arch/sparc64/stage2.mk b/src/kernel/boot/arch/sparc64/stage2.mk new file mode 100644 index 0000000000..3b913e226c --- /dev/null +++ b/src/kernel/boot/arch/sparc64/stage2.mk @@ -0,0 +1,33 @@ +# i386 stage2 makefile +STAGE2_DIR = boot/$(ARCH) +STAGE2_OBJ_DIR = $(STAGE2_DIR)/$(OBJ_DIR) +STAGE2_OBJS = \ + +DEPS += $(STAGE2_OBJS:.o=.d) + +STAGE2 = $(STAGE2_OBJ_DIR)/stage2 + +$(STAGE2): $(STAGE2_OBJS) $(KLIBS) + $(LD) -dN --script=$(STAGE2_DIR)/stage2.ld -L $(LIBGCC_PATH) $(STAGE2_OBJS) $(KLIBS) $(LIBGCC) -o $@ + +stage2clean: + rm -f $(STAGE2_OBJS) $(STAGE2) + +# +$(STAGE2_OBJ_DIR)/%.o: $(STAGE2_DIR)/%.c + @mkdir -p $(STAGE2_OBJ_DIR) + $(CC) -c $< $(GLOBAL_CFLAGS) -Iinclude -I$(STAGE2_DIR) -o $@ + +$(STAGE2_OBJ_DIR)/%.d: $(STAGE2_DIR)/%.c + @mkdir -p $(STAGE2_OBJ_DIR) + @echo "making deps for $<..." + @($(ECHO) -n $(dir $@);$(CC) $(GLOBAL_CFLAGS) -Iinclude -I$(STAGE2_DIR) -M -MG $<) > $@ + +$(STAGE2_OBJ_DIR)/%.d: $(STAGE2_DIR)/%.S + @mkdir -p $(STAGE2_OBJ_DIR) + @echo "making deps for $<..." + @($(ECHO) -n $(dir $@);$(CC) $(GLOBAL_CFLAGS) -Iinclude -I$(STAGE2_DIR) -M -MG $<) > $@ + +$(STAGE2_OBJ_DIR)/%.o: $(STAGE2_DIR)/%.S + @mkdir -p $(STAGE2_OBJ_DIR) + $(CC) -c $< $(GLOBAL_CFLAGS) -Iinclude -I$(STAGE2_DIR) -o $@ diff --git a/src/kernel/boot/arch/x86/Jamfile b/src/kernel/boot/arch/x86/Jamfile new file mode 100644 index 0000000000..b89cef5354 --- /dev/null +++ b/src/kernel/boot/arch/x86/Jamfile @@ -0,0 +1,10 @@ +SubDir OBOS_TOP sources os kits kernel boot arch x86 ; + +KernelObjects + <$(SOURCE_GRIST)>stage2.c + <$(SOURCE_GRIST)>stage2_asm.S + <$(SOURCE_GRIST)>smp_boot.c + <$(SOURCE_GRIST)>smp_trampoline.S + : + -fno-pic + ; diff --git a/src/kernel/boot/arch/x86/bootblock.asm b/src/kernel/boot/arch/x86/bootblock.asm new file mode 100644 index 0000000000..999caf044e --- /dev/null +++ b/src/kernel/boot/arch/x86/bootblock.asm @@ -0,0 +1,360 @@ +; ** +; ** Copyright 1998 Brian J. Swetland +; ** All rights reserved. +; ** +; ** Redistribution and use in source and binary forms, with or without +; ** modification, are permitted provided that the following conditions +; ** are met: +; ** 1. Redistributions of source code must retain the above copyright +; ** notice, this list of conditions, and the following disclaimer. +; ** 2. Redistributions in binary form must reproduce the above copyright +; ** notice, this list of conditions, and the following disclaimer in the +; ** documentation and/or other materials provided with the distribution. +; ** 3. The name of the author may not be used to endorse or promote products +; ** derived from this software without specific prior written permission. +; ** +; ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +; ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +; ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +; ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +; ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +; ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +; ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +; ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +; ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +; ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +; /* +; ** Copyright 2001, Travis Geiselbrecht. All rights reserved. +; ** Distributed under the terms of the NewOS License. +; */ + +; /* +; ** Reviewed, documented and some minor modifications and bug-fixes +; ** applied by Michael Noisternig on 2001-09-02. +; */ + +%define VESA_X_TARGET 800 +%define VESA_Y_TARGET 600 +%define VESA_BIT_DEPTH_TARGET 32 + +SECTION +CODE16 +ORG 0x7c00 ; start code at 0x7c00 + jmp short start +sectors dw 800 ; this is interpreted as data (bytes 3 and 4) + ; and patched from outside to the size of the bootcode (in sectors) +start: + cli ; no interrupts please + cld + xor ax,ax + mov ss,ax ; setup stack from 0 - 0x7c00 + mov sp,0x7c00 ; stack pointer to top of stack + call enable_a20 ; enable a20 gate + lgdt [ss:gdt] ; load global descriptor table + mov eax,cr0 ; switch to protected mode + or al,0x1 ; by setting 'protected mode enable' bit + mov cr0,eax ; and writing back + jmp dword 0x8:unreal32 ; do the actual switch into protected mode + ; The switch into protected mode and back is to get the processor into 'unreal' mode + ; where it is in 16-bit mode but with segments that are larger than 64k. + ; this way, the floppy code can load the image directly into memory >1Mb. +unreal32: + mov bx,0x10 ; load all of the data segments with large 32-bit segment + mov ds,bx + mov es,bx + mov ss,bx + and al,0xfe ; switch back to real mode + mov cr0,eax + jmp 0x7c0:unreal-0x7c00 ; actually go back to 16-bit +unreal: + xor ax,ax ; load NULL-descriptor (base 0) into ds, es, ss + mov es,ax ; the processor doesn't clear the internal high size bits on these descriptors + mov ds,ax ; so the descriptors can now reference 4Gb of memory, with size extensions + mov ss,ax + + ; read in the second half of this stage of the bootloader + xor dx,dx ; start at head 0 + mov bx,0x2 ; start at sector 2 for the second half of this loader + mov cx,1 ; one sector + mov edi,0x7e00 ; right after this one + sti + call load_floppy + + ; read in the rest of the disk + mov edi,0x100000 ; destination buffer (at 1 MB) for sector reading in load_floppy + mov bx,0x3 ; start at sector 3 (and cylinder 0) + mov cx,[sectors] ; read that much sectors + xor dx,dx ; start at head 0 + sti + mov si,loadmsg + call print + dec cx ; TK: one sector is already read as second part of boot block + call load_floppy ; read remaining sectors at address edi + call disable_floppy_motor + mov si,okmsg + call print + cli + + ; call enable_vesa + mov [in_vesa],al + + mov ebx,[dword 0x100074] ; load dword at rel. address 0x74 from read-destination-buffer + add ebx,0x101000 ; for stage2 entry + mov al,0xcf + mov [ds:gdt+14],al ; set desc. 1 and 2 + mov [ds:gdt+22],al ; to 32-bit segment + lgdt [ds:gdt] ; load global descriptor table + + mov eax,1 + mov cr0,eax ; enter protected mode + jmp dword 0x8:code32 ; flush prefetch queue +code32: +BITS 32 + mov ax,0x10 ; load descriptor 2 in all segment selectors (except cs) + mov ds,ax + mov es,ax + mov fs,ax + mov gs,ax + mov ss,ax + mov ebp,0x10000 + mov esp,ebp + + mov eax,[vesa_info] + push eax + + xor eax,eax + mov al,[in_vesa] + push eax + + call find_mem_size + push eax + + call ebx ; jump to stage2 entry +inf:jmp short inf + +; find memory size by testing +; OUT: eax = memory size +find_mem_size: + mov eax,0x31323738 ; test value + mov esi,0x100ff0 ; start above conventional mem + HMA = 1 MB + 1024 Byte +_fms_loop: + mov edx,[esi] ; read value + mov [esi],eax ; write test value + mov ecx,[esi] ; read it again + mov [esi],edx ; write back old value + cmp ecx,eax + jnz _fms_loop_out ; read value != test value -> above mem limit + add esi,0x1000 ; test next page (4 K) + jmp short _fms_loop +_fms_loop_out: + mov eax,esi + sub eax,0x1000 + add eax,byte +0x10 + ret + +BITS 16 +; read sectors into memory +; IN: bx = sector # to start with: should be 2 as sector 1 (bootsector) was read by BIOS +; cx = # of sectors to read +; edi = buffer +load_floppy: + push bx + push cx +tryagain: + mov al,0x13 ; read a maximum of 18 sectors + sub al,bl ; substract first sector (to prevent wrap-around ???) + + xor ah,ah ; TK: don't read more then required, VMWare doesn't like that + cmp ax,cx + jl shorten + mov ax,cx +shorten: + + mov cx,bx ; -> sector/cylinder # to read from + mov bx,0x8000 ; buffer address + mov ah,0x2 ; command 'read sectors' + push ax + int 0x13 ; call BIOS + pop ax ; TK: should return number of transferred sectors in al + ; but VMWare 3 clobbers it, so we (re-)load al manually + jnc okok ; no error -> proceed as usual + dec byte [retrycnt] + jz fail + xor ah,ah ; reset disk controller + int 0x13 + jmp tryagain ; retry +okok: + mov byte [retrycnt], 3 ; reload retrycnt + mov si,dot + call print + mov esi,0x8000 ; source + xor ecx,ecx + mov cl,al ; copy # of read sectors (al) + shl cx,0x7 ; of size 128*4 bytes + rep a32 movsd ; to destination (edi) setup before func3 was called + pop cx + pop bx + xor dh,0x1 ; read: next head + jnz bar6 + inc bh ; read: next cylinder +bar6: + mov bl,0x1 ; read: sector 1 + xor ah,ah + sub cx,ax ; substract # of read sectors + jg load_floppy ; sectors left to read ? + ret + +disable_floppy_motor: + xor al,al + mov dx,0x3f2 ; disable floppy motor + out dx,al + ret + +; prints message in reg. si +print: + pusha +_n: + lodsb + or al,al + jz short _e + mov ah,0x0E + mov bx,7 + int 0x10 + jmp _n +_e: + popa + ret + +; print errormsg, wait for keypress and reboot +fail: + mov si,errormsg + call print + xor ax, ax + int 0x16 + int 0x19 + +; enables the a20 gate +; the usual keyboard-enable-a20-gate-stuff +enable_a20: + call _a20_loop + jnz _enable_a20_done + mov al,0xd1 + out 0x64,al + call _a20_loop + jnz _enable_a20_done + mov al,0xdf + out 0x60,al +_a20_loop: + mov ecx,0x20000 +_loop2: + jmp short _c +_c: + in al,0x64 + test al,0x2 + loopne _loop2 +_enable_a20_done: + ret + +loadmsg db "Loading",0 +errormsg db 0x0a,0x0d,"Error reading disk.",0x0a,0x0d,0 +okmsg db "OK",0x0a,0x0d,0 +dot db ".",0 +gdt: + ; the first entry serves 2 purposes: as the GDT header and as the first descriptor + ; note that the first descriptor (descriptor 0) is always a NULL-descriptor + db 0xFF ; full size of GDT used + db 0xff ; which means 8192 descriptors * 8 bytes = 2^16 bytes + dw gdt ; address of GDT (dword) + dd 0 + ; descriptor 1: + dd 0x0000ffff ; base - limit: 0 - 0xfffff * 4K + dd 0x008f9a00 ; type: 16 bit, exec-only conforming, , privilege 0 + ; descriptor 2: + dd 0x0000ffff ; base - limit: 0 - 0xfffff * 4K + dd 0x008f9200 ; type: 16 bit, data read/write, , privilege 0 + +retrycnt db 3 +in_vesa db 0 +vesa_info dw 0 + + times 510-($-$$) db 0 ; filler for boot sector + dw 0xaa55 ; magic number for boot sector + +; Starting here is the second sector of the boot code + +; fool around with vesa mode +enable_vesa: + ; put the VBEInfo struct at 0x30000 + mov eax,0x30000 + mov [vesa_info],eax + mov dx,0x3000 + mov es,dx + mov ax,0x4f00 + mov di,0 + int 0x10 + + ; check the return code + cmp al,0x4f + jne done_vesa_bad + cmp ah,0x00 + jne done_vesa_bad + + ; check the signature on the data structure + mov eax,[es:00] + cmp eax,0x41534556 ; 'VESA' + je vesa_sig_ok + cmp eax,0x32454256 ; 'VBE2' + jne done_vesa_bad + +vesa_sig_ok: + ; scan through each mode and grab the info on them + les bx,[es:14] ; calculate the pointer to the mode list + mov di,0x200 ; push the buffer up a little to be past the VBEInfo struct + +mode_loop: + mov cx,[es:bx] ; grab the next mode in the list + cmp cx,0xffff + je done_vesa_bad + and cx,0x01ff + mov ax,0x4f01 + int 0x10 + + ; if it's 1024x768x32, go for it + mov ax,[es:di] + test ax,0x1 ; test the supported bit + jz next_mode + test ax,0x08 ; test the linear frame mode bit + mov ax,[es:di+18] + cmp ax,VESA_X_TARGET ; x + jne next_mode + mov ax,[es:di+20] + cmp ax,VESA_Y_TARGET ; y + jne next_mode + mov al,[es:di+25] + cmp al,VESA_BIT_DEPTH_TARGET ; bit_depth + jne next_mode + + ; looks good, switch into it + mov ax,0x4f02 + mov bx,cx + or bx,0x4000 ; add the linear mode bit + int 0x10 + jmp done_vesa_good + +next_mode: + ; get ready to try the next mode + inc bx + inc bx + jmp mode_loop + +done_vesa_good: + mov ax,0x1 + ret + +done_vesa_bad: + xor ax,ax + ret + + times 1024-($-$$) db 0 ; filler for second sector of the loader + diff --git a/src/kernel/boot/arch/x86/bootblock.bin b/src/kernel/boot/arch/x86/bootblock.bin new file mode 100644 index 0000000000..d5682be040 Binary files /dev/null and b/src/kernel/boot/arch/x86/bootblock.bin differ diff --git a/src/kernel/boot/arch/x86/smp_boot.c b/src/kernel/boot/arch/x86/smp_boot.c new file mode 100644 index 0000000000..9abd7e4302 --- /dev/null +++ b/src/kernel/boot/arch/x86/smp_boot.c @@ -0,0 +1,518 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include + +#include + +#define NO_SMP 0 +#define CHATTY_SMP 0 + +static unsigned int mp_mem_phys = 0; +static unsigned int mp_mem_virt = 0; +static struct mp_flt_struct *mp_flt_ptr = NULL; +static kernel_args *saved_ka = NULL; +static unsigned int kernel_entry_point = 0; + +static int smp_get_current_cpu(kernel_args *ka); + +static unsigned int map_page(kernel_args *ka, unsigned int paddr, unsigned int vaddr) +{ + unsigned int *pentry; + unsigned int *pgdir = (unsigned int *)(ka->arch_args.page_hole + (4*1024*1024-PAGE_SIZE)); + + // check to see if a page table exists for this range + if(pgdir[vaddr / PAGE_SIZE / 1024] == 0) { + unsigned int pgtable; + // we need to allocate a pgtable + pgtable = ka->phys_alloc_range[0].start + ka->phys_alloc_range[0].size; + ka->phys_alloc_range[0].size += PAGE_SIZE; + ka->arch_args.pgtables[ka->arch_args.num_pgtables++] = pgtable; + + // put it in the pgdir + pgdir[vaddr / PAGE_SIZE / 1024] = (pgtable & ADDR_MASK) | DEFAULT_PAGE_FLAGS; + + // zero it out in it's new mapping + memset((unsigned int *)((unsigned int *)ka->arch_args.page_hole + (vaddr / PAGE_SIZE / 1024) * PAGE_SIZE), 0, PAGE_SIZE); + } + // now, fill in the pentry + pentry = (unsigned int *)((unsigned int *)ka->arch_args.page_hole + vaddr / PAGE_SIZE); + + *pentry = (paddr & ADDR_MASK) | DEFAULT_PAGE_FLAGS; + + asm volatile("invlpg (%0)" : : "r" (vaddr)); + + return 0; +} + +static unsigned int apic_read(unsigned int *addr) +{ + return *addr; +} + +static void apic_write(unsigned int *addr, unsigned int data) +{ + *addr = data; +} + +/* +static void *mp_virt_to_phys(void *ptr) +{ + return ((void *)(((unsigned int)ptr - mp_mem_virt) + mp_mem_phys)); +} +*/ +static void *mp_phys_to_virt(void *ptr) +{ + return ((void *)(((unsigned int)ptr - mp_mem_phys) + mp_mem_virt)); +} + +static unsigned int *smp_probe(unsigned int base, unsigned int limit) +{ + unsigned int *ptr; + +// dprintf("smp_probe: entry base 0x%x, limit 0x%x\n", base, limit); + + for (ptr = (unsigned int *) base; (unsigned int) ptr < limit; ptr++) { + if (*ptr == MP_FLT_SIGNATURE) { +// dprintf("smp_probe: found floating pointer structure at 0x%x\n", ptr); + return ptr; + } + } + return NULL; +} + +static void smp_do_config(kernel_args *ka) +{ + char *ptr; + int i; + struct mp_config_table *mpc; + struct mp_ext_pe *pe; + struct mp_ext_ioapic *io; + struct mp_ext_bus *bus; +// const char *cpu_family[] = { "", "", "", "", "Intel 486", +// "Intel Pentium", "Intel Pentium Pro", "Intel Pentium II" }; + + /* + * we are not running in standard configuration, so we have to look through + * all of the mp configuration table crap to figure out how many processors + * we have, where our apics are, etc. + */ + ka->num_cpus = 0; + + mpc = mp_phys_to_virt(mp_flt_ptr->mpc); + + /* print out our new found configuration. */ + ptr = (char *) &(mpc->oem[0]); +#if CHATTY_SMP + dprintf ("smp: oem id: %c%c%c%c%c%c%c%c product id: " + "%c%c%c%c%c%c%c%c%c%c%c%c\n", ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], + ptr[5], ptr[6], ptr[7], ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], + ptr[13], ptr[14], ptr[15], ptr[16], ptr[17], ptr[18], ptr[19], + ptr[20]); + dprintf("smp: base table has %d entries, extended section %d bytes\n", + mpc->num_entries, mpc->ext_len); +#endif + ka->arch_args.apic_phys = (unsigned int)mpc->apic; + + ptr = (char *) ((unsigned int) mpc + sizeof (struct mp_config_table)); + for (i = 0; i < mpc->num_entries; i++) { + switch (*ptr) { + case MP_EXT_PE: + pe = (struct mp_ext_pe *) ptr; + ka->arch_args.cpu_apic_id[ka->num_cpus] = pe->apic_id; + ka->arch_args.cpu_os_id[pe->apic_id] = ka->num_cpus; + ka->arch_args.cpu_apic_version[ka->num_cpus] = pe->apic_version; +#if CHATTY_SMP + dprintf ("smp: cpu#%d: %s, apic id %d, version %d%s\n", + ka->num_cpus, cpu_family[(pe->signature & 0xf00) >> 8], + pe->apic_id, pe->apic_version, (pe->cpu_flags & 0x2) ? + ", BSP" : ""); +#endif + ptr += 20; + ka->num_cpus++; + break; + case MP_EXT_BUS: + bus = (struct mp_ext_bus *)ptr; +#if CHATTY_SMP + dprintf("smp: bus%d: %c%c%c%c%c%c\n", bus->bus_id, + bus->name[0], bus->name[1], bus->name[2], bus->name[3], + bus->name[4], bus->name[5]); +#endif + ptr += 8; + break; + case MP_EXT_IO_APIC: + io = (struct mp_ext_ioapic *) ptr; + ka->arch_args.ioapic_phys = (unsigned int)io->addr; +#if CHATTY_SMP + dprintf("smp: found io apic with apic id %d, version %d\n", + io->ioapic_id, io->ioapic_version); +#endif + ptr += 8; + break; + case MP_EXT_IO_INT: + ptr += 8; + break; + case MP_EXT_LOCAL_INT: + ptr += 8; + break; + } + } + dprintf("smp: apic @ 0x%x, i/o apic @ 0x%x, total %d processors detected\n", + (unsigned int)ka->arch_args.apic_phys, (unsigned int)ka->arch_args.ioapic_phys, ka->num_cpus); + + // this BIOS looks broken, because it didn't report any cpus (VMWare) + if(ka->num_cpus == 0) { + ka->num_cpus = 1; + } +} + +struct smp_scan_spots_struct { + unsigned int start; + unsigned int stop; + unsigned int len; +}; + +static struct smp_scan_spots_struct smp_scan_spots[] = { + { 0x9fc00, 0xa0000, 0xa0000 - 0x9fc00 }, + { 0xf0000, 0x100000, 0x100000 - 0xf0000 }, + { 0, 0, 0 } +}; + +static int smp_find_mp_config(kernel_args *ka) +{ + int i; + + // XXX for now, assume the memory is identity mapped by the 1st stage + for(i=0; smp_scan_spots[i].len > 0; i++) { + mp_flt_ptr = (struct mp_flt_struct *)smp_probe(smp_scan_spots[i].start, + smp_scan_spots[i].stop); + if(mp_flt_ptr != NULL) + break; + } +#if NO_SMP + if(0) { +#else + if(mp_flt_ptr != NULL) { +#endif + mp_mem_phys = smp_scan_spots[i].start; + mp_mem_virt = smp_scan_spots[i].start; + +#if CHATTY_SMP + dprintf ("smp_boot: intel mp version %s, %s", (mp_flt_ptr->mp_rev == 1) ? "1.1" : + "1.4", (mp_flt_ptr->mp_feature_2 & 0x80) ? + "imcr and pic compatibility mode.\n" : "virtual wire compatibility mode.\n"); +#endif + if (mp_flt_ptr->mpc == 0) { + // XXX need to implement +#if 1 + ka->num_cpus = 1; + return 1; +#else + /* this system conforms to one of the default configurations */ +// mp_num_def_config = mp_flt_ptr->mp_feature_1; + dprintf ("smp: standard configuration %d\n", mp_flt_ptr->mp_feature_1); +/* num_cpus = 2; + ka->cpu_apic_id[0] = 0; + ka->cpu_apic_id[1] = 1; + apic_phys = (unsigned int *) 0xfee00000; + ioapic_phys = (unsigned int *) 0xfec00000; + kprintf ("smp: WARNING: standard configuration code is untested"); +*/ +#endif + } else { + smp_do_config(ka); + } + return ka->num_cpus; + } else { + ka->num_cpus = 1; + return 1; + } +} + +static int smp_setup_apic(kernel_args *ka) +{ + unsigned int config; +// dprintf("setting up the apic..."); + + /* set spurious interrupt vector to 0xff */ + config = apic_read(APIC_SIVR) & 0xfffffc00; + config |= APIC_ENABLE | 0xff; + apic_write(APIC_SIVR, config); +#if 0 + /* setup LINT0 as ExtINT */ + config = (apic_read(APIC_LINT0) & 0xffff1c00); + config |= APIC_LVT_DM_ExtINT | APIC_LVT_IIPP | APIC_LVT_TM; + apic_write(APIC_LINT0, config); + + /* setup LINT1 as NMI */ + config = (apic_read(APIC_LINT1) & 0xffff1c00); + config |= APIC_LVT_DM_NMI | APIC_LVT_IIPP; + apic_write(APIC_LINT1, config); +#endif + + /* setup timer */ + config = apic_read(APIC_LVTT) & ~APIC_LVTT_MASK; + config |= 0xfb | APIC_LVTT_M; // vector 0xfb, timer masked + apic_write(APIC_LVTT, config); + + apic_write(APIC_ICRT, 0); // zero out the clock + + config = apic_read(APIC_TDCR) & ~0x0000000f; + config |= APIC_TDCR_1; // clock division by 1 + apic_write(APIC_TDCR, config); + + /* setup error vector to 0xfe */ + config = (apic_read(APIC_LVT3) & 0xffffff00) | 0xfe; + apic_write(APIC_LVT3, config); + + /* accept all interrupts */ + config = apic_read(APIC_TPRI) & 0xffffff00; + apic_write(APIC_TPRI, config); + + config = apic_read(APIC_SIVR); + apic_write(APIC_EOI, 0); + +// dprintf("done\n"); + return 0; +} + +// target function of the trampoline code +// The trampoline code should have the pgdir and a gdt set up for us, +// along with us being on the final stack for this processor. We need +// to set up the local APIC and load the global idt and gdt. When we're +// done, we'll jump into the kernel with the cpu number as an argument. +static int smp_cpu_ready(void) +{ + kernel_args *ka = saved_ka; + unsigned int curr_cpu = smp_get_current_cpu(ka); + struct gdt_idt_descr idt_descr; + struct gdt_idt_descr gdt_descr; + +// dprintf("smp_cpu_ready: entry cpu %d\n", curr_cpu); + + // Important. Make sure supervisor threads can fault on read only pages... + asm("movl %%eax, %%cr0" : : "a" ((1 << 31) | (1 << 16) | (1 << 5) | 1)); + asm("cld"); + asm("fninit"); + + smp_setup_apic(ka); + + // Set up the final idt + idt_descr.a = IDT_LIMIT - 1; + idt_descr.b = (unsigned int *)ka->arch_args.vir_idt; + + asm("lidt %0;" + : : "m" (idt_descr)); + + // Set up the final gdt + gdt_descr.a = GDT_LIMIT - 1; + gdt_descr.b = (unsigned int *)ka->arch_args.vir_gdt; + + asm("lgdt %0;" + : : "m" (gdt_descr)); + + asm("pushl %0; " // push the cpu number + "pushl %1; " // kernel args + "pushl $0x0;" // dummy retval for call to main + "pushl %2; " // this is the start address + "ret; " // jump. + : : "r" (curr_cpu), "m" (ka), "g" (kernel_entry_point)); + + // no where to return to + return 0; +} + +static int smp_boot_all_cpus(kernel_args *ka) +{ + unsigned int trampoline_code; + unsigned int trampoline_stack; + unsigned int i; + + // XXX assume low 1 meg is identity mapped by the 1st stage bootloader + // and nothing important is in 0x9e000 & 0x9f000 + + // allocate a stack and a code area for the smp trampoline + // (these have to be < 1M physical) + trampoline_code = 0x9f000; // 640kB - 4096 == 0x9f000 + trampoline_stack = 0x9e000; // 640kB - 8192 == 0x9e000 + map_page(ka, 0x9f000, 0x9f000); + map_page(ka, 0x9e000, 0x9e000); + + // copy the trampoline code over + memcpy((char *)trampoline_code, &smp_trampoline, + (unsigned int)&smp_trampoline_end - (unsigned int)&smp_trampoline); + + // boot the cpus + for(i = 1; i < ka->num_cpus; i++) { + unsigned int *final_stack; + unsigned int *final_stack_ptr; + unsigned int *tramp_stack_ptr; + unsigned int config; + unsigned int num_startups; + unsigned int j; + + // create a final stack the trampoline code will put the ap processor on + ka->cpu_kstack[i].start = ka->virt_alloc_range[0].start + ka->virt_alloc_range[0].size; + ka->cpu_kstack[i].size = STACK_SIZE * PAGE_SIZE; + for(j=0; jcpu_kstack[i].size/PAGE_SIZE; j++) { + // map the pages in + map_page(ka, ka->phys_alloc_range[0].start + ka->phys_alloc_range[0].size, + ka->virt_alloc_range[0].start + ka->virt_alloc_range[0].size); + ka->phys_alloc_range[0].size += PAGE_SIZE; + ka->virt_alloc_range[0].size += PAGE_SIZE; + } + + // set this stack up + final_stack = (unsigned int *)ka->cpu_kstack[i].start; + memset(final_stack, 0, STACK_SIZE * PAGE_SIZE); + final_stack_ptr = (final_stack + (STACK_SIZE * PAGE_SIZE) / sizeof(unsigned int)) - 1; + *final_stack_ptr = (unsigned int)&smp_cpu_ready; + final_stack_ptr--; + + // set the trampoline stack up + tramp_stack_ptr = (unsigned int *)(trampoline_stack + PAGE_SIZE - 4); + // final location of the stack + *tramp_stack_ptr = ((unsigned int)final_stack) + STACK_SIZE * PAGE_SIZE - sizeof(unsigned int); + tramp_stack_ptr--; + // page dir + *tramp_stack_ptr = ka->arch_args.phys_pgdir; + tramp_stack_ptr--; + + // put a gdt descriptor at the bottom of the stack + *((unsigned short *)trampoline_stack) = 0x18-1; // LIMIT + *((unsigned int *)(trampoline_stack + 2)) = trampoline_stack + 8; + // put the gdt at the bottom + memcpy(&((unsigned int *)trampoline_stack)[2], (void *)ka->arch_args.vir_gdt, 6*4); + + /* clear apic errors */ + if(ka->arch_args.cpu_apic_version[i] & 0xf0) { + apic_write(APIC_ESR, 0); + apic_read(APIC_ESR); + } + + /* send (aka assert) INIT IPI */ + config = (apic_read(APIC_ICR2) & 0x00ffffff) | (ka->arch_args.cpu_apic_id[i] << 24); + apic_write(APIC_ICR2, config); /* set target pe */ + config = (apic_read(APIC_ICR1) & 0xfff00000) | 0x0000c500; + apic_write(APIC_ICR1, config); + + // wait for pending to end + while((apic_read(APIC_ICR1) & 0x00001000) == 0x00001000); + + /* deassert INIT */ + config = (apic_read(APIC_ICR2) & 0x00ffffff) | (ka->arch_args.cpu_apic_id[i] << 24); + apic_write(APIC_ICR2, config); + config = (apic_read(APIC_ICR1) & 0xfff00000) | 0x00008500; + + // wait for pending to end + while((apic_read(APIC_ICR1) & 0x00001000) == 0x00001000); +// dprintf("0x%x\n", apic_read(APIC_ICR1)); + + /* wait 10ms */ + sleep(10000); + + /* is this a local apic or an 82489dx ? */ + num_startups = (ka->arch_args.cpu_apic_version[i] & 0xf0) ? 2 : 0; + for (j = 0; j < num_startups; j++) { + /* it's a local apic, so send STARTUP IPIs */ + apic_write(APIC_ESR, 0); + + /* set target pe */ + config = (apic_read(APIC_ICR2) & 0xf0ffffff) | (ka->arch_args.cpu_apic_id[i] << 24); + apic_write(APIC_ICR2, config); + + /* send the IPI */ + config = (apic_read(APIC_ICR1) & 0xfff0f800) | APIC_DM_STARTUP | + (0x9f000 >> 12); + apic_write(APIC_ICR1, config); + + /* wait */ + sleep(200); + + while((apic_read(APIC_ICR1)& 0x00001000) == 0x00001000); + } + } + + return 0; +} + +static void calculate_apic_timer_conversion_factor(kernel_args *ka) +{ + long long t1, t2; + unsigned int config; + unsigned int count; + + // setup the timer + config = apic_read(APIC_LVTT); + config = (config & ~APIC_LVTT_MASK) + APIC_LVTT_M; // timer masked, vector 0 + apic_write(APIC_LVTT, config); + + config = (apic_read(APIC_TDCR) & ~0x0000000f) + 0xb; // divide clock by one + apic_write(APIC_TDCR, config); + + t1 = system_time(); + apic_write(APIC_ICRT, 0xffffffff); // start the counter + + execute_n_instructions(128*20000); + + count = apic_read(APIC_CCRT); + t2 = system_time(); + + count = 0xffffffff - count; + + ka->arch_args.apic_time_cv_factor = (unsigned int)((1000000.0/(t2 - t1)) * count); + + dprintf("APIC ticks/sec = %d\n", ka->arch_args.apic_time_cv_factor); +} + +int smp_boot(kernel_args *ka, unsigned int kernel_entry) +{ +// dprintf("smp_boot: entry\n"); + + kernel_entry_point = kernel_entry; + saved_ka = ka; + + if(smp_find_mp_config(ka) > 1) { +// dprintf("smp_boot: had found > 1 cpus\n"); +// dprintf("post config:\n"); +// dprintf("num_cpus = 0x%p\n", ka->num_cpus); +// dprintf("apic_phys = 0x%p\n", ka->arch_args.apic_phys); +// dprintf("ioapic_phys = 0x%p\n", ka->arch_args.ioapic_phys); + + // map in the apic & ioapic + map_page(ka, ka->arch_args.apic_phys, ka->virt_alloc_range[0].start + ka->virt_alloc_range[0].size); + ka->arch_args.apic = (unsigned int *)(ka->virt_alloc_range[0].start + ka->virt_alloc_range[0].size); + ka->virt_alloc_range[0].size += PAGE_SIZE; + + map_page(ka, ka->arch_args.ioapic_phys, ka->virt_alloc_range[0].start + ka->virt_alloc_range[0].size); + ka->arch_args.ioapic = (unsigned int *)(ka->virt_alloc_range[0].start + ka->virt_alloc_range[0].size); + ka->virt_alloc_range[0].size += PAGE_SIZE; + +// dprintf("apic = 0x%p\n", ka->arch_args.apic); +// dprintf("ioapic = 0x%p\n", ka->arch_args.ioapic); + + // set up the apic + smp_setup_apic(ka); + + // calculate how fast the apic timer is + calculate_apic_timer_conversion_factor(ka); + +// dprintf("trampolining other cpus\n"); + smp_boot_all_cpus(ka); +// dprintf("done trampolining\n"); + } + +// dprintf("smp_boot: exit\n"); + + return 0; +} + +static int smp_get_current_cpu(kernel_args *ka) +{ + if(ka->arch_args.apic == NULL) + return 0; + else + return ka->arch_args.cpu_os_id[(apic_read(APIC_ID) & 0xffffffff) >> 24]; +} diff --git a/src/kernel/boot/arch/x86/smp_trampoline.S b/src/kernel/boot/arch/x86/smp_trampoline.S new file mode 100644 index 0000000000..480f453b57 --- /dev/null +++ b/src/kernel/boot/arch/x86/smp_trampoline.S @@ -0,0 +1,69 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +// expects a stack page like this: +// (stack has to be at (0x9e000) +// 0x9effc : final esp +// 0x9eff8 : page dir +// +// 0x9e000 - 0x9e006 : gdt descriptor +// 0x9e008 - 0x9e020 : gdt +// +// smp_trampoline must be located at 0x9f000 +.globl smp_trampoline +.globl smp_trampoline_end +.globl foo + +.code16 +smp_trampoline: + cli + + mov $0x9e00,%ax + mov %ax,%ds + +// lgdt 0x9e000 # load the gdt +.byte 0x66, 0x0f, 0x01, 0x15, 0x00, 0xe0, 0x09, 0x00 + + movl %cr0,%eax + orl $0x01,%eax + movl %eax,%cr0 # switch into protected mode + +.code32 +_trampoline_32: + .byte 0x66 + ljmp $0x08,$(trampoline_32 - smp_trampoline + 0x9f000) +trampoline_32: + mov $0x10, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + mov %ax, %ss + + movl $0x9eff8,%esp # set up the stack pointer + + popl %eax # get the page dir + movl %eax,%cr3 # set the page dir + + popl %eax # get the final stack location + movl %eax,%esp + + // load an address for an indirect jump + movl $trampoline_after_paging,%ecx + + movl %cr0,%eax + orl $0x80000000,%eax + movl %eax,%cr0 # enable paging + + // jump to the address previously loaded. NOTE: + // this address is the address at which the code is originally linked, + // which is > 1MB. We will be out of the low memory at this point. + jmp *%ecx +trampoline_after_paging: + // just return, the bsp would have set the return address to the + // target function at the top of the passed stack + ret + +smp_trampoline_end: + diff --git a/src/kernel/boot/arch/x86/stage2.c b/src/kernel/boot/arch/x86/stage2.c new file mode 100644 index 0000000000..4fa2654ec7 --- /dev/null +++ b/src/kernel/boot/arch/x86/stage2.c @@ -0,0 +1,550 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include "arch/x86/stage2_priv.h" +#include "vesa.h" + +#include +#include +#include +#include + +const unsigned kBSSSize = 0x9000; + + +// we're running out of the first 'file' contained in the bootdir, which is +// a set of binaries and data packed back to back, described by an array +// of boot_entry structures at the beginning. The load address is fixed. +#define BOOTDIR_ADDR 0x100000 +static const boot_entry *bootdir = (boot_entry*)BOOTDIR_ADDR; + +// stick the kernel arguments in a pseudo-random page that will be mapped +// at least during the call into the kernel. The kernel should copy the +// data out and unmap the page. +static kernel_args *ka = (kernel_args *)0x20000; + +// needed for message +static unsigned short *kScreenBase = (unsigned short*) 0xb8000; +static unsigned screenOffset = 0; +static unsigned int line = 0; + +unsigned int cv_factor = 0; + +// size of bootdir in pages +static unsigned int bootdir_pages = 0; + +// working pagedir and pagetable +static unsigned int *pgdir = 0; +static unsigned int *pgtable = 0; + +// function decls for this module +static void calculate_cpu_conversion_factor(void); +static void load_elf_image(void *data, unsigned int *next_paddr, + addr_range *ar0, addr_range *ar1, unsigned int *start_addr, addr_range *dynamic_section); +static int mmu_init(kernel_args *ka, unsigned int *next_paddr); +static void mmu_map_page(unsigned int vaddr, unsigned int paddr); +static int check_cpu(void); + +// called by the stage1 bootloader. +// State: +// 32-bit +// mmu disabled +// stack somewhere below 1 MB +// supervisor mode +void _start(unsigned int mem, int in_vesa, unsigned int vesa_ptr) +{ + unsigned int *idt; + unsigned int *gdt; + unsigned int next_vaddr; + unsigned int next_paddr; + unsigned int i; + unsigned int kernel_entry; + + asm("cld"); // Ain't nothing but a GCC thang. + asm("fninit"); // initialize floating point unit + + clearscreen(); + dprintf("stage2 bootloader entry.\n"); + dprintf("memsize = 0x%x, in_vesa %d, vesa_ptr 0x%x\n", mem, in_vesa, vesa_ptr); + + // verify we can run on this cpu + if(check_cpu() < 0) { + dprintf("\nSorry, this computer appears to be lacking some of the features\n"); + dprintf("needed by OpenBeOS. It is currently only able to run on\n"); + dprintf("Pentium class cpus and above, with a few exceptions to\n"); + dprintf("that rule.\n"); + dprintf("\nPlease reset your computer to continue."); + + for(;;); + } + + // calculate the conversion factor that translates rdtsc time to real microseconds + calculate_cpu_conversion_factor(); + + // calculate how big the bootdir is so we know where we can start grabbing pages + { + int entry; + for (entry = 0; entry < 64; entry++) { + if (bootdir[entry].be_type == BE_TYPE_NONE) + break; + + bootdir_pages += bootdir[entry].be_size; + } + +// nmessage("bootdir is ", bootdir_pages, " pages long\n"); + } + + ka->bootdir_addr.start = (unsigned long)bootdir; + ka->bootdir_addr.size = bootdir_pages * PAGE_SIZE; + + next_paddr = BOOTDIR_ADDR + bootdir_pages * PAGE_SIZE; + + if(in_vesa) { + struct VBEModeInfoBlock *mode_info = (struct VBEModeInfoBlock *)(vesa_ptr + 0x200); + + ka->fb.enabled = 1; + ka->fb.x_size = mode_info->x_resolution; + ka->fb.y_size = mode_info->y_resolution; + ka->fb.bit_depth = mode_info->bits_per_pixel; + ka->fb.mapping.start = mode_info->phys_base_ptr; + ka->fb.mapping.size = ka->fb.x_size * ka->fb.y_size * (ka->fb.bit_depth/8); + ka->fb.already_mapped = 0; + } else { + ka->fb.enabled = 0; + } + + mmu_init(ka, &next_paddr); + + // load the kernel (3rd entry in the bootdir) + load_elf_image((void *)(bootdir[2].be_offset * PAGE_SIZE + BOOTDIR_ADDR), &next_paddr, + &ka->kernel_seg0_addr, &ka->kernel_seg1_addr, &kernel_entry, &ka->kernel_dynamic_section_addr); + + if(ka->kernel_seg1_addr.size > 0) + next_vaddr = ROUNDUP(ka->kernel_seg1_addr.start + ka->kernel_seg1_addr.size, PAGE_SIZE); + else + next_vaddr = ROUNDUP(ka->kernel_seg0_addr.start + ka->kernel_seg0_addr.size, PAGE_SIZE); + + // map in a kernel stack + ka->cpu_kstack[0].start = next_vaddr; + for(i=0; icpu_kstack[0].size = next_vaddr - ka->cpu_kstack[0].start; + +// dprintf("new stack at 0x%x to 0x%x\n", ka->cpu_kstack[0].start, ka->cpu_kstack[0].start + ka->cpu_kstack[0].size); + + // set up a new idt + { + struct gdt_idt_descr idt_descr; + + // find a new idt + idt = (unsigned int *)next_paddr; + ka->arch_args.phys_idt = (unsigned int)idt; + next_paddr += PAGE_SIZE; + +// nmessage("idt at ", (unsigned int)idt, "\n"); + + // clear it out + for(i=0; iarch_args.vir_idt = (unsigned int)next_vaddr; + next_vaddr += PAGE_SIZE; + + // load the idt + idt_descr.a = IDT_LIMIT - 1; + idt_descr.b = (unsigned int *)ka->arch_args.vir_idt; + + asm("lidt %0;" + : : "m" (idt_descr)); + +// nmessage("idt at virtual address ", next_vpage, "\n"); + } + + // set up a new gdt + { + struct gdt_idt_descr gdt_descr; + + // find a new gdt + gdt = (unsigned int *)next_paddr; + ka->arch_args.phys_gdt = (unsigned int)gdt; + next_paddr += PAGE_SIZE; + +// nmessage("gdt at ", (unsigned int)gdt, "\n"); + + // put segment descriptors in it + gdt[0] = 0; + gdt[1] = 0; + gdt[2] = 0x0000ffff; // seg 0x8 -- kernel 4GB code + gdt[3] = 0x00cf9a00; + gdt[4] = 0x0000ffff; // seg 0x10 -- kernel 4GB data + gdt[5] = 0x00cf9200; + gdt[6] = 0x0000ffff; // seg 0x1b -- ring 3 4GB code + gdt[7] = 0x00cffa00; + gdt[8] = 0x0000ffff; // seg 0x23 -- ring 3 4GB data + gdt[9] = 0x00cff200; + // gdt[10] & gdt[11] will be filled later by the kernel + + // map the gdt into virtual space + mmu_map_page(next_vaddr, (unsigned int)gdt); + ka->arch_args.vir_gdt = (unsigned int)next_vaddr; + next_vaddr += PAGE_SIZE; + + // load the GDT + gdt_descr.a = GDT_LIMIT - 1; + gdt_descr.b = (unsigned int *)ka->arch_args.vir_gdt; + + asm("lgdt %0;" + : : "m" (gdt_descr)); + +// nmessage("gdt at virtual address ", next_vpage, "\n"); + } + + // Map the pg_dir into kernel space at 0xffc00000-0xffffffff + // this enables a mmu trick where the 4 MB region that this pgdir entry + // represents now maps the 4MB of potential pagetables that the pgdir + // points to. Thrown away later in VM bringup, but useful for now. + pgdir[1023] = (unsigned int)pgdir | DEFAULT_PAGE_FLAGS; + + // also map it on the next vpage + mmu_map_page(next_vaddr, (unsigned int)pgdir); + ka->arch_args.vir_pgdir = next_vaddr; + next_vaddr += PAGE_SIZE; + + // save the kernel args + ka->arch_args.system_time_cv_factor = cv_factor; + ka->phys_mem_range[0].start = 0; + ka->phys_mem_range[0].size = mem; + ka->num_phys_mem_ranges = 1; + ka->str = NULL; + ka->phys_alloc_range[0].start = BOOTDIR_ADDR; + ka->phys_alloc_range[0].size = next_paddr - BOOTDIR_ADDR; + ka->num_phys_alloc_ranges = 1; + ka->virt_alloc_range[0].start = KERNEL_BASE; + ka->virt_alloc_range[0].size = next_vaddr - KERNEL_BASE; + ka->num_virt_alloc_ranges = 1; + ka->arch_args.page_hole = 0xffc00000; + ka->num_cpus = 1; +#if 0 + dprintf("kernel args at 0x%x\n", ka); + dprintf("pgdir = 0x%x\n", ka->pgdir); + dprintf("pgtables[0] = 0x%x\n", ka->pgtables[0]); + dprintf("phys_idt = 0x%x\n", ka->phys_idt); + dprintf("vir_idt = 0x%x\n", ka->vir_idt); + dprintf("phys_gdt = 0x%x\n", ka->phys_gdt); + dprintf("vir_gdt = 0x%x\n", ka->vir_gdt); + dprintf("mem_size = 0x%x\n", ka->mem_size); + dprintf("str = 0x%x\n", ka->str); + dprintf("bootdir = 0x%x\n", ka->bootdir); + dprintf("bootdir_size = 0x%x\n", ka->bootdir_size); + dprintf("phys_alloc_range_low = 0x%x\n", ka->phys_alloc_range_low); + dprintf("phys_alloc_range_high = 0x%x\n", ka->phys_alloc_range_high); + dprintf("virt_alloc_range_low = 0x%x\n", ka->virt_alloc_range_low); + dprintf("virt_alloc_range_high = 0x%x\n", ka->virt_alloc_range_high); + dprintf("page_hole = 0x%x\n", ka->page_hole); +#endif +// dprintf("finding and booting other cpus...\n"); + smp_boot(ka, kernel_entry); + + dprintf("jumping into kernel at 0x%x\n", kernel_entry); + + ka->cons_line = line; + + asm("movl %0, %%eax; " // move stack out of way + "movl %%eax, %%esp; " + : : "m" (ka->cpu_kstack[0].start + ka->cpu_kstack[0].size)); + asm("pushl $0x0; " // we're the BSP cpu (0) + "pushl %0; " // kernel args + "pushl $0x0;" // dummy retval for call to main + "pushl %1; " // this is the start address + "ret; " // jump. + : : "g" (ka), "g" (kernel_entry)); +} + +static void load_elf_image(void *data, unsigned int *next_paddr, addr_range *ar0, addr_range *ar1, unsigned int *start_addr, addr_range *dynamic_section) +{ + struct Elf32_Ehdr *imageHeader = (struct Elf32_Ehdr*) data; + struct Elf32_Phdr *segments = (struct Elf32_Phdr*)(imageHeader->e_phoff + (unsigned) imageHeader); + int segmentIndex; + int foundSegmentIndex = 0; + + ar0->size = 0; + ar1->size = 0; + dynamic_section->size = 0; + + for (segmentIndex = 0; segmentIndex < imageHeader->e_phnum; segmentIndex++) { + struct Elf32_Phdr *segment = &segments[segmentIndex]; + unsigned segmentOffset; + + switch(segment->p_type) { + case PT_LOAD: + break; + case PT_DYNAMIC: + dynamic_section->start = segment->p_vaddr; + dynamic_section->size = segment->p_memsz; + default: + continue; + } + +// dprintf("segment %d\n", segmentIndex); +// dprintf("p_vaddr 0x%x p_paddr 0x%x p_filesz 0x%x p_memsz 0x%x\n", +// segment->p_vaddr, segment->p_paddr, segment->p_filesz, segment->p_memsz); + + /* Map initialized portion */ + for (segmentOffset = 0; + segmentOffset < ROUNDUP(segment->p_filesz, PAGE_SIZE); + segmentOffset += PAGE_SIZE) { + + mmu_map_page(segment->p_vaddr + segmentOffset, *next_paddr); + memcpy((void *)ROUNDOWN(segment->p_vaddr + segmentOffset, PAGE_SIZE), + (void *)ROUNDOWN((unsigned)data + segment->p_offset + segmentOffset, PAGE_SIZE), PAGE_SIZE); + (*next_paddr) += PAGE_SIZE; + } + + /* Clean out the leftover part of the last page */ + if(segment->p_filesz % PAGE_SIZE > 0) { +// dprintf("memsetting 0 to va 0x%x, size %d\n", (void*)((unsigned)segment->p_vaddr + segment->p_filesz), PAGE_SIZE - (segment->p_filesz % PAGE_SIZE)); + memset((void*)((unsigned)segment->p_vaddr + segment->p_filesz), 0, PAGE_SIZE + - (segment->p_filesz % PAGE_SIZE)); + } + + /* Map uninitialized portion */ + for (; segmentOffset < ROUNDUP(segment->p_memsz, PAGE_SIZE); segmentOffset += PAGE_SIZE) { +// dprintf("mapping zero page at va 0x%x\n", segment->p_vaddr + segmentOffset); + mmu_map_page(segment->p_vaddr + segmentOffset, *next_paddr); + memset((void *)(segment->p_vaddr + segmentOffset), 0, PAGE_SIZE); + (*next_paddr) += PAGE_SIZE; + } + switch(foundSegmentIndex) { + case 0: + ar0->start = segment->p_vaddr; + ar0->size = segment->p_memsz; + break; + case 1: + ar1->start = segment->p_vaddr; + ar1->size = segment->p_memsz; + break; + default: + ; + } + foundSegmentIndex++; + } + *start_addr = imageHeader->e_entry; +} + +// allocate a page directory and page table to facilitate mapping +// pages to the 0x80000000 - 0x80400000 region. +// also identity maps the first 4MB of memory +static int mmu_init(kernel_args *ka, unsigned int *next_paddr) +{ + int i; + + // allocate a new pgdir + pgdir = (unsigned int *)*next_paddr; + (*next_paddr) += PAGE_SIZE; + ka->arch_args.phys_pgdir = (unsigned int)pgdir; + + // clear out the pgdir + for(i = 0; i < 1024; i++) + pgdir[i] = 0; + + // make a pagetable at this random spot + pgtable = (unsigned int *)0x11000; + + for (i = 0; i < 1024; i++) { + pgtable[i] = (i * 0x1000) | DEFAULT_PAGE_FLAGS; + } // pkx: create first 4 MB one-to-one mapping + + pgdir[0] = (unsigned int)pgtable | DEFAULT_PAGE_FLAGS; + // pkx: put the one-to-one mapping into the page dir. + + // Get new page table and clear it out + pgtable = (unsigned int *)*next_paddr; + ka->arch_args.pgtables[0] = (unsigned int)pgtable; + ka->arch_args.num_pgtables = 1; + + (*next_paddr) += PAGE_SIZE; + for (i = 0; i < 1024; i++) + pgtable[i] = 0; + + // put the new page table into the page directory + // this maps the kernel at KERNEL_BASE + pgdir[KERNEL_BASE/(4*1024*1024)] = (unsigned int)pgtable | DEFAULT_PAGE_FLAGS; + + // switch to the new pgdir + asm("movl %0, %%eax;" + "movl %%eax, %%cr3;" :: "m" (pgdir) : "eax"); + // Important. Make sure supervisor threads can fault on read only pages... + asm("movl %%eax, %%cr0" : : "a" ((1 << 31) | (1 << 16) | (1 << 5) | 1)); + // pkx: moved the paging turn-on to here. + + return 0; +} + +// can only map the 4 meg region right after KERNEL_BASE, may fix this later +// if need arises. +static void mmu_map_page(unsigned int vaddr, unsigned int paddr) +{ +// dprintf("mmu_map_page: vaddr 0x%x, paddr 0x%x\n", vaddr, paddr); + if(vaddr < KERNEL_BASE || vaddr >= (KERNEL_BASE + 4096*1024)) { + dprintf("mmu_map_page: asked to map invalid page!\n"); + for(;;); + } + paddr &= ~(PAGE_SIZE-1); +// dprintf("paddr 0x%x @ index %d\n", paddr, (vaddr % (PAGE_SIZE * 1024)) / PAGE_SIZE); + pgtable[(vaddr % (PAGE_SIZE * 1024)) / PAGE_SIZE] = paddr | DEFAULT_PAGE_FLAGS; +} + +static int check_cpu(void) +{ +// unsigned int i; + unsigned int data[4]; + char str[17]; + + // check the eflags register to see if the cpuid instruction exists + if((get_eflags() & 1<<21) == 0) { + set_eflags(get_eflags() | 1<<21); + if((get_eflags() & 1<<21) == 0) { + // we couldn't set the ID bit of the eflags register, this cpu is old + return -1; + } + } + + // we can safely call cpuid + + // print some fun data + cpuid(0, data); + + // build the vendor string + memset(str, 0, sizeof(str)); + *(unsigned int *)&str[0] = data[1]; + *(unsigned int *)&str[4] = data[3]; + *(unsigned int *)&str[8] = data[2]; + + // get the family, model, stepping + cpuid(1, data); + dprintf("CPU: family %d model %d stepping %d, string '%s'\n", + (data[0] >> 8) & 0xf, (data[0] >> 4) & 0xf, data[0] & 0xf, str); + + // check for bits we need + cpuid(1, data); + if(!(data[3] & 1<<4)) return -1; // check for rdtsc + + return 0; +} + +void sleep(long long time) +{ + long long start = system_time(); + + while(system_time() - start <= time) + ; +} + +#define outb(value,port) \ + asm("outb %%al,%%dx"::"a" (value),"d" (port)) + + +#define inb(port) ({ \ + unsigned char _v; \ + asm volatile("inb %%dx,%%al":"=a" (_v):"d" (port)); \ + _v; \ + }) + +#define TIMER_CLKNUM_HZ 1193167 + +static void calculate_cpu_conversion_factor(void) +{ + unsigned char low, high; + unsigned long expired; + long long t1, t2; + long long time_base_ticks; + double timer_usecs; + + /* program the timer to count down mode */ + outb(0x34, 0x43); + + outb(0xff, 0x40); /* low and then high */ + outb(0xff, 0x40); + + t1 = rdtsc(); + + execute_n_instructions(32*20000); + + t2 = rdtsc(); + + outb(0x00, 0x43); /* latch counter value */ + low = inb(0x40); + high = inb(0x40); + + expired = (unsigned long)0xffff - ((((unsigned long)high) << 8) + low); + + timer_usecs = (expired * 1.0) / (TIMER_CLKNUM_HZ/1000000.0); + time_base_ticks = t2 -t1; + + dprintf("CPU at %d Hz\n", (int)((time_base_ticks / timer_usecs) * 1000000)); + + system_time_setup((int)((time_base_ticks / timer_usecs) * 1000000)); +} + +void clearscreen() +{ + int i; + + for(i=0; i< SCREEN_WIDTH*SCREEN_HEIGHT*2; i++) { + kScreenBase[i] = 0xf20; + } +} + +static void scrup() +{ + int i; + memcpy(kScreenBase, kScreenBase + SCREEN_WIDTH, + SCREEN_WIDTH * SCREEN_HEIGHT * 2 - SCREEN_WIDTH * 2); + screenOffset = (SCREEN_HEIGHT - 1) * SCREEN_WIDTH; + for(i=0; i SCREEN_HEIGHT - 1) + scrup(); + else + screenOffset += SCREEN_WIDTH - (screenOffset % 80); + } else { + kScreenBase[screenOffset++] = 0xf00 | *str; + } + if (screenOffset > SCREEN_WIDTH * SCREEN_HEIGHT) + scrup(); + + str++; + } +} + +int dprintf(const char *fmt, ...) +{ + int ret; + va_list args; + char temp[256]; + + va_start(args, fmt); + ret = vsprintf(temp,fmt,args); + va_end(args); + + kputs(temp); + return ret; +} + diff --git a/src/kernel/boot/arch/x86/stage2.ld b/src/kernel/boot/arch/x86/stage2.ld new file mode 100644 index 0000000000..6b8963f2a8 --- /dev/null +++ b/src/kernel/boot/arch/x86/stage2.ld @@ -0,0 +1,32 @@ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) + +ENTRY(_start) +SECTIONS +{ + . = 0x101000 + SIZEOF_HEADERS; + + /* text/read-only data */ + .text : { *(.text .gnu.linkonce.t.*) } + + __ctor_list = .; + .ctors : { *(.ctors) } + __ctor_end = .; + + .rodata : { *(.rodata) } + + /* writable data */ + . = ALIGN(0x1000); + __data_start = .; + .data : { *(.data .gnu.linkonce.d.*) } + + /* unintialized data (in same segment as writable data) */ + __bss_start = .; + .bss : { *(.bss) } + + . = ALIGN(0x1000); + _end = . ; + + /* Strip unnecessary stuff */ + /DISCARD/ : { *(.comment .note .eh_frame .dtors) } +} diff --git a/src/kernel/boot/arch/x86/stage2_asm.S b/src/kernel/boot/arch/x86/stage2_asm.S new file mode 100644 index 0000000000..f88c8fa091 --- /dev/null +++ b/src/kernel/boot/arch/x86/stage2_asm.S @@ -0,0 +1,95 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +/* long long rdtsc() */ +.global rdtsc +rdtsc: + rdtsc + ret + +.global execute_n_instructions +execute_n_instructions: + movl 4(%esp), %ecx + shrl $4, %ecx +.again: + xorl %eax, %eax + xorl %eax, %eax + xorl %eax, %eax + xorl %eax, %eax + xorl %eax, %eax + xorl %eax, %eax + xorl %eax, %eax + xorl %eax, %eax + xorl %eax, %eax + xorl %eax, %eax + xorl %eax, %eax + xorl %eax, %eax + xorl %eax, %eax + xorl %eax, %eax + xorl %eax, %eax + xorl %eax, %eax + loop .again + ret + +.global system_time_setup +system_time_setup: + /* First divide 1M * 2^32 by proc_clock */ + movl $0x0F4240, %ecx + movl %ecx, %edx + subl %eax, %eax + movl 4(%esp), %ebx + divl %ebx, %eax /* should be 64 / 32 */ + movl %eax, cv_factor + ret + +.global system_time +system_time: + /* load 64-bit factor into %eax (low), %edx (high) */ + /* hand-assemble rdtsc -- read time stamp counter */ + rdtsc /* time in %edx,%eax */ + + pushl %ebx + pushl %ecx + movl cv_factor, %ebx + movl %edx, %ecx /* save high half */ + mull %ebx /* truncate %eax, but keep %edx */ + movl %ecx, %eax + movl %edx, %ecx /* save high half of low */ + mull %ebx /*, %eax*/ + /* now compute [%edx, %eax] + [%ecx], propagating carry */ + subl %ebx, %ebx /* need zero to propagate carry */ + addl %ecx, %eax + adc %ebx, %edx + popl %ecx + popl %ebx + ret + +.global cpuid +cpuid: + pushl %ebx + pushl %edi + movl 12(%esp),%eax + movl 16(%esp),%edi + cpuid + movl %eax,0(%edi) + movl %ebx,4(%edi) + movl %ecx,8(%edi) + movl %edx,12(%edi) + popl %edi + popl %ebx + ret + +.global get_eflags +get_eflags: + pushfl + popl %eax + ret + +.global set_eflags +set_eflags: + pushl 4(%esp) + popfl + ret + + diff --git a/src/kernel/boot/bin2asm.c b/src/kernel/boot/bin2asm.c new file mode 100644 index 0000000000..8395edaa4b --- /dev/null +++ b/src/kernel/boot/bin2asm.c @@ -0,0 +1,42 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include + +#define NUM_COLUMNS 16 + +int main(int argc, char **argv) +{ + FILE *infp = stdin; + char c; + int column = 0; + int start = 1; + + while(!feof(infp)) { + int err; + err = fread(&c, sizeof(c), 1, infp); + if(err != 1) + break; + + if((column % NUM_COLUMNS) == 0) { + if(!start) { + printf("\n"); + } else { + start = 0; + } + printf(".byte\t"); + } else { + printf(","); + } + + printf("0x%02x", ((int)c) & 0xff); + + column++; + } + printf("\n"); + + return 0; +} + diff --git a/src/kernel/boot/bin2h.c b/src/kernel/boot/bin2h.c new file mode 100644 index 0000000000..f2decae232 --- /dev/null +++ b/src/kernel/boot/bin2h.c @@ -0,0 +1,30 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include + +#define NUM_COLUMNS 16 + +int main(int argc, char **argv) +{ + FILE *infp = stdin; + char c; + int column = 0; + + while(!feof(infp)) { + int err; + err = fread(&c, sizeof(c), 1, infp); + if(err != 1) + break; + + printf("0x%02x,", ((int)c) & 0xff); + if((++column % NUM_COLUMNS) == 0) { + printf("\n"); + } + } + + return 0; +} + diff --git a/src/kernel/boot/bootmaker.c b/src/kernel/boot/bootmaker.c new file mode 100644 index 0000000000..f29cd93370 --- /dev/null +++ b/src/kernel/boot/bootmaker.c @@ -0,0 +1,563 @@ +/* +** Some Portions Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +/* +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include "../../../../../headers/obos/private/kernel/bootdir.h" + +//#include "sparcbootblock.h" + +#include +#include +#include +#include +#include +#include + +#ifdef sparc +#define xBIG_ENDIAN 1 +#endif +#ifdef i386 +#define xLITTLE_ENDIAN 1 +#endif +#ifdef __ppc__ +#define xBIG_ENDIAN 1 +#endif + +#define SWAP32(x) \ + ((((x) & 0xff) << 24) | (((x) & 0xff00) << 8) | (((x) & 0xff0000) >> 8) | (((x) & 0xff000000) >> 24)) + +#if xBIG_ENDIAN +#define HOST_TO_BENDIAN32(x) (x) +#define BENDIAN_TO_HOST32(x) (x) +#define HOST_TO_LENDIAN32(x) SWAP32(x) +#define LENDIAN_TO_HOST32(x) SWAP32(x) +#endif +#if xLITTLE_ENDIAN +#define HOST_TO_BENDIAN32(x) SWAP32(x) +#define BENDIAN_TO_HOST32(x) SWAP32(x) +#define HOST_TO_LENDIAN32(x) (x) +#define LENDIAN_TO_HOST32(x) (x) +#endif + +#if !xBIG_ENDIAN && !xLITTLE_ENDIAN +#error not sure which endian the host processor is, please edit bootmaker.c +#endif + +// ELF stuff +#define ELF_MAGIC "\x7f""ELF" +#define EI_MAG0 0 +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_PAD 7 +#define EI_NIDENT 16 + +#define ELFCLASS32 1 +#define ELFCLASS64 2 +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +// XXX not safe across all build architectures +typedef unsigned int Elf32_Addr; +typedef unsigned short Elf32_Half; +typedef unsigned int Elf32_Off; +typedef int Elf32_Sword; +typedef unsigned int Elf32_Word; + +struct Elf32_Ehdr { + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +}; + +struct Elf32_Phdr { + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +}; + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#define LE 0 +#define BE 1 + +static int target_endian = LE; + +#define fix(x) ((target_endian == BE) ? HOST_TO_BENDIAN32(x) : HOST_TO_LENDIAN32(x)) + +static int make_sparcboot = 0; +static int strip_debug = 0; +static char *strip_binary = "strip"; + +void die(char *s, char *a) +{ + fprintf(stderr,"error: "); + fprintf(stderr,s,a); + fprintf(stderr,"\n"); + exit(1); +} + +void *loadfile(char *file, int *size) +{ + int fd; + char *data; + struct stat info; + + if((fd = open(file,O_BINARY|O_RDONLY)) != -1){ + if(fstat(fd,&info)){ + close(fd); + *size = 0; + return NULL; + } + data = (char *) malloc(info.st_size); + if(read(fd, data, info.st_size) != info.st_size) { + close(fd); + *size = 0; + return NULL; + } + close(fd); + *size = info.st_size; + return data; + } + *size = 0; + return NULL; +} + +void *loadstripfile(char *file, int *size) +{ + char temp[256]; + char cmd[4096]; + void *retval; + + + if(strip_debug) { + strcpy(temp, "/tmp/mkboot.XXXXXXXX"); + mktemp(temp); + sprintf(cmd, "cp %s %s; %s %s", file, temp, strip_binary, temp); + system(cmd); + + retval = loadfile(temp, size); + + unlink(temp); + } else { + retval = loadfile(file, size); + } + + return retval; +} + +// write a boot block to the head of the dir. +// note: the first 0x20 bytes are removed by the sparc prom +// which makes the whole file off by 0x20 bytes +/* +int writesparcbootblock(int fd, unsigned int blocks) +{ + unsigned char bb[0x200+0x20]; + + memset(bb, 0, sizeof(bb)); + memcpy(bb, sparcbootblock, sizeof(sparcbootblock)); + + return write(fd, bb, sizeof(bb)); +} +*/ + +typedef struct _nvpair +{ + struct _nvpair *next; + char *name; + char *value; +} nvpair; + + +typedef struct _section +{ + struct _section *next; + char *name; + struct _nvpair *firstnv; +} section; + +void print_sections(section *first) +{ + nvpair *p; + + while(first){ + printf("\n[%s]\n",first->name); + for(p = first->firstnv; p; p = p->next){ + printf("%s=%s\n",p->name,p->value); + } + first = first->next; + } +} + +#define stNEWLINE 0 +#define stSKIPLINE 1 +#define stHEADER 2 +#define stLHS 3 +#define stRHS 4 + +section *first = NULL; +section *last = NULL; + +section *load_ini(char *file) +{ + char *data,*end; + int size; + int state = stNEWLINE; + section *cur; + + char *lhs,*rhs; + + if(!(data = loadfile(file,&size))){ + return NULL; + } + end = data+size; + + while(data < end){ + switch(state){ + case stSKIPLINE: + if(*data == '\n' || *data == '\r'){ + state = stNEWLINE; + } + data++; + break; + + case stNEWLINE: + if(*data == '\n' || *data == '\r'){ + data++; + break; + } + if(*data == '['){ + lhs = data+1; + state = stHEADER; + data++; + break; + } + if(*data == '#' || *data <= ' '){ + state = stSKIPLINE; + data++; + break; + } + lhs = data; + data++; + state = stLHS; + break; + case stHEADER: + if(*data == ']'){ + cur = (section *) malloc(sizeof(section)); + cur->name = lhs; + cur->firstnv = NULL; + cur->next = NULL; + if(last){ + last->next = cur; + last = cur; + } else { + last = first = cur; + } + *data = 0; + state = stSKIPLINE; + } + data++; + break; + case stLHS: + if(*data == '\n' || *data == '\r'){ + state = stNEWLINE; + } + if(*data == '='){ + *data = 0; + rhs = data+1; + state = stRHS; + } + data++; + continue; + case stRHS: + if(*data == '\n' || *data == '\r'){ + nvpair *p = (nvpair *) malloc(sizeof(nvpair)); + p->name = lhs; + p->value = rhs; + *data = 0; + p->next = cur->firstnv; + cur->firstnv = p; + state = stNEWLINE; + } + data++; + break; + } + } + return first; + +} + + +char *getval(section *s, char *name) +{ + nvpair *p; + for(p = s->firstnv; p; p = p->next){ + if(!strcmp(p->name,name)) return p->value; + } + return NULL; +} + +char *getvaldef(section *s, char *name, char *def) +{ + nvpair *p; + for(p = s->firstnv; p; p = p->next){ + if(!strcmp(p->name,name)) return p->value; + } + return def; +} + +Elf32_Addr elf_find_entry(void *buf, int size) +{ + struct Elf32_Ehdr *header; + struct Elf32_Phdr *pheader; + char *cbuf = buf; + int byte_swap; + int index; + +#define SWAPIT(x) ((byte_swap) ? SWAP32(x) : (x)) + + if(memcmp(cbuf, ELF_MAGIC, sizeof(ELF_MAGIC)-1) != 0) + return 0; + + if(cbuf[EI_CLASS] != ELFCLASS32) + return 0; + + byte_swap = 0; +#if xBIG_ENDIAN + if(cbuf[EI_DATA] == ELFDATA2LSB) { + byte_swap = 1; + } +#else + if(cbuf[EI_DATA] == ELFDATA2MSB) { + byte_swap = 1; + } +#endif + + header = (struct Elf32_Ehdr *)cbuf; + pheader = (struct Elf32_Phdr *)&cbuf[SWAPIT(header->e_phoff)]; + + // XXX only looking at the first program header. Should be ok + return SWAPIT(pheader->p_offset); +} +#undef SWAPIT + +#define centry bdir.bd_entry[c] +void makeboot(section *s, char *outfile) +{ + int fd; + void *rawdata[64]; + int rawsize[64]; + char fill[4096]; + boot_dir bdir; + int i,c; + int nextpage = 1; /* page rel offset of next loaded object */ + + memset(fill,0,4096); + + memset(&bdir, 0, 4096); + for(i=0;i<64;i++){ + rawdata[i] = NULL; + rawsize[i] = 0; + } + + c = 1; + + bdir.bd_entry[0].be_type = fix(BE_TYPE_DIRECTORY); + bdir.bd_entry[0].be_size = fix(1); + bdir.bd_entry[0].be_vsize = fix(1); + rawdata[0] = (void *) &bdir; + rawsize[0] = 4096; + + strcpy(bdir.bd_entry[0].be_name,"SBBB/Directory"); + + while(s){ + char *type = getvaldef(s,"type","NONE"); + char *file = getval(s,"file"); + int vsize; + int size; + struct stat statbuf; + + if(!type) die("section %s has no type",s->name); + + strncpy(centry.be_name,s->name,32); + centry.be_name[31] = 0; + + if(!file) die("section %s has no file",s->name); + rawdata[c]= ((strcmp(type, "elf32")==0)?loadstripfile:loadfile)(file,&rawsize[c]); + if(!rawdata[c]) + die("cannot load \"%s\"",file); + + if(stat(file,&statbuf)) + die("cannot stat \"%s\"",file); + vsize = statbuf.st_size; + + centry.be_size = rawsize[c] / 4096 + (rawsize[c] % 4096 ? 1 : 0); + centry.be_vsize = + (vsize < centry.be_size) ? centry.be_size : vsize; + + centry.be_offset = nextpage; + nextpage += centry.be_size; + + centry.be_size = fix(centry.be_size); + centry.be_vsize = fix(centry.be_vsize); + centry.be_offset = fix(centry.be_offset); + + if(!strcmp(type,"boot")){ + centry.be_type = fix(BE_TYPE_BOOTSTRAP); + centry.be_code_vaddr = fix(atoi(getvaldef(s,"vaddr","0"))); + centry.be_code_ventr = fix(atoi(getvaldef(s,"ventry","0"))); + } + if(!strcmp(type,"code")){ + centry.be_type = fix(BE_TYPE_CODE); + centry.be_code_vaddr = fix(atoi(getvaldef(s,"vaddr","0"))); + centry.be_code_ventr = fix(atoi(getvaldef(s,"ventry","0"))); + } + if(!strcmp(type,"data")){ + centry.be_type = fix(BE_TYPE_DATA); + } + if(!strcmp(type,"elf32")){ + centry.be_type = fix(BE_TYPE_ELF32); + centry.be_code_vaddr = 0; + centry.be_code_ventr = fix(elf_find_entry(rawdata[c], rawsize[c])); + } + + if(centry.be_type == BE_TYPE_NONE){ + die("unrecognized section type \"%s\"",type); + } + + c++; + s = s->next; + + if(c==64) die("too many sections (>63)",NULL); + } + + if((fd = open(outfile, O_BINARY|O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) { + die("cannot write to \"%s\"",outfile); + } + +/* XXX - Hope this isn't needed :( + if(make_sparcboot) { + writesparcbootblock(fd, nextpage+1); + } +*/ + for(i=0;i ... ] -o \n",argv[0]); + return 1; + } + + argc--; + argv++; + + while(argc){ + if(!strcmp(*argv,"--sparc")) { + make_sparcboot = 1; + } else if(!strcmp(*argv, "--bigendian")) { + target_endian = BE; + } else if(!strcmp(*argv,"-o")) { + argc--; + argv++; + if(argc) { + file = *argv; + } else { + goto usage; + } + } else if(!strcmp(*argv, "--strip-binary")) { + argc--; + argv++; + if(argc) { + strip_binary = *argv; + } else { + goto usage; + } + } else if(!strcmp(*argv, "--strip-debug")) { + strip_debug = 1; + } else { + if(load_ini(*argv) == NULL) { + fprintf(stderr,"warning: cannot load '%s'\n",*argv); + } + } + argc--; + argv++; + } + + + if((argc > 3) && !strcmp(argv[3],"-sparc")){ + make_sparcboot = 1; + } + + if(!file){ + fprintf(stderr,"error: no output specified\n"); + goto usage; + } + + if(!first){ + fprintf(stderr,"error: no data to write?!\n"); + goto usage; + } + + makeboot(first,file); + + return 0; +} + diff --git a/src/kernel/boot/makeflop.c b/src/kernel/boot/makeflop.c new file mode 100644 index 0000000000..bb9d40bfea --- /dev/null +++ b/src/kernel/boot/makeflop.c @@ -0,0 +1,84 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +void usage(char **argv) +{ + printf("usage: %s bootblock payload outfile\n", argv[0]); +} + +int main(int argc, char *argv[]) +{ + struct stat st; + int err; + unsigned int blocks; + unsigned char bootsector[1024]; + unsigned char buf[512]; + size_t read_size; + int infd; + int outfd; + + if(argc < 4) { + printf("insufficient args\n"); + usage(argv); + return -1; + } + + err = stat(argv[2], &st); + if(err < 0) { + printf("error stating file '%s'\n", argv[2]); + return -1; + } + + outfd = open(argv[3], O_BINARY|O_WRONLY|O_CREAT|O_TRUNC, 0666); + if(outfd < 0) { + printf("error: cannot open output file '%s'\n", argv[3]); + return -1; + } + + // first read the bootblock + infd = open(argv[1], O_BINARY|O_RDONLY); + if(infd < 0) { + printf("error: cannot open bootblock file '%s'\n", argv[1]); + return -1; + } + if(read(infd, bootsector, sizeof(bootsector)) < sizeof(bootsector) + || lseek(infd, 0, SEEK_END) != sizeof(bootsector)) { + printf ("error: size of bootblock file '%s' must match %d bytes.\n", argv[1], sizeof(bootsector)); + return -1; + } + close(infd); + + // patch the size of the output into bytes 3 & 4 of the bootblock + blocks = st.st_size / 512; + blocks++; + bootsector[2] = (blocks & 0x00ff); + bootsector[3] = (blocks & 0xff00) >> 8; + + write(outfd, bootsector, sizeof(bootsector)); + + infd = open(argv[2], O_BINARY|O_RDONLY); + if(infd < 0) { + printf("error: cannot open input file '%s'\n", argv[1]); + return -1; + } + + while((read_size = read(infd, buf, sizeof(buf))) > 0) { + write(outfd, buf, read_size); + } + + close(outfd); + close(infd); + + return 0; +} + diff --git a/src/kernel/core/Jamfile b/src/kernel/core/Jamfile new file mode 100644 index 0000000000..b43af8fc1e --- /dev/null +++ b/src/kernel/core/Jamfile @@ -0,0 +1,43 @@ +SubDir OBOS_TOP sources os kits kernel core ; + +KernelObjects + <$(SOURCE_GRIST)>cbuf.c + <$(SOURCE_GRIST)>console.c + <$(SOURCE_GRIST)>cpu.c + <$(SOURCE_GRIST)>debug.c + <$(SOURCE_GRIST)>elf.c + <$(SOURCE_GRIST)>faults.c + <$(SOURCE_GRIST)>fd.c + <$(SOURCE_GRIST)>gdb.c + <$(SOURCE_GRIST)>heap.c + <$(SOURCE_GRIST)>int.c + <$(SOURCE_GRIST)>khash.c + <$(SOURCE_GRIST)>linkhack.c + <$(SOURCE_GRIST)>lock.c + <$(SOURCE_GRIST)>main.c + <$(SOURCE_GRIST)>misc.c + <$(SOURCE_GRIST)>module.c + <$(SOURCE_GRIST)>port.c + <$(SOURCE_GRIST)>queue.c + <$(SOURCE_GRIST)>sem.c + <$(SOURCE_GRIST)>smp.c + <$(SOURCE_GRIST)>syscalls.c + <$(SOURCE_GRIST)>sysctl.c + <$(SOURCE_GRIST)>thread.c + <$(SOURCE_GRIST)>timer.c + : + -fno-pic -D_KERNEL_MODE + ; + +KernelLd linkhack.so : + <$(SOURCE_GRIST)>linkhack.o + : + : + -shared -Bdynamic + ; + +SubInclude OBOS_TOP sources os kits kernel core addons ; +SubInclude OBOS_TOP sources os kits kernel core arch ; +SubInclude OBOS_TOP sources os kits kernel core fs ; +SubInclude OBOS_TOP sources os kits kernel core vm ; +SubInclude OBOS_TOP sources os kits kernel core net ; diff --git a/src/kernel/core/addons/Jamfile b/src/kernel/core/addons/Jamfile new file mode 100644 index 0000000000..8876afa2a7 --- /dev/null +++ b/src/kernel/core/addons/Jamfile @@ -0,0 +1,4 @@ +SubDir OBOS_TOP sources os kits kernel core addons ; + +SubInclude OBOS_TOP sources os kits kernel core addons bus_managers ; +SubInclude OBOS_TOP sources os kits kernel core addons fs ; diff --git a/src/kernel/core/addons/bus_managers/Jamfile b/src/kernel/core/addons/bus_managers/Jamfile new file mode 100644 index 0000000000..1e13a82eaf --- /dev/null +++ b/src/kernel/core/addons/bus_managers/Jamfile @@ -0,0 +1,13 @@ +SubDir OBOS_TOP sources os kits kernel core addons bus_managers ; + +KernelStaticLibrary libbus : + <$(SOURCE_GRIST)>bus_init.c + <$(SOURCE_GRIST)>bus_man.c + + <$(SOURCE_GRIST)>pci/pci.c + <$(SOURCE_GRIST)>pci/pci_bus.c + : + -fno-pic + ; + +SubInclude OBOS_TOP sources os kits kernel core addons bus_managers isa ; diff --git a/src/kernel/core/addons/bus_managers/bus_init.c b/src/kernel/core/addons/bus_managers/bus_init.c new file mode 100755 index 0000000000..1b70cb091e --- /dev/null +++ b/src/kernel/core/addons/bus_managers/bus_init.c @@ -0,0 +1,47 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include + +#ifdef ARCH_x86 +#include +#endif + +int bus_init(kernel_args *ka) +{ + bus_man_init(ka); + +#ifdef ARCH_x86 + pci_bus_init(ka); +#endif + +#if 0 + { + id_list *vendor_ids; + id_list *device_ids; + device dev; + int rc; + + vendor_ids = kmalloc(sizeof(id_list) + sizeof(uint32)); + vendor_ids->num_ids = 1; + vendor_ids->id[0] = 0x10ec; + + device_ids = kmalloc(sizeof(id_list) + sizeof(uint32)); + device_ids->num_ids = 1; + device_ids->id[0] = 0x8139; + + rc = bus_find_device(1, vendor_ids, device_ids, &dev); + if(rc >= 0) { + dprintf("found device : v 0x%x, d 0x%x, irq 0x%x\n", dev.vendor_id, dev.device_id, dev.irq); + } + kfree(vendor_ids); + kfree(device_ids); + } +#endif + + return 0; +} diff --git a/src/kernel/core/addons/bus_managers/bus_man.c b/src/kernel/core/addons/bus_managers/bus_man.c new file mode 100755 index 0000000000..24321ca36d --- /dev/null +++ b/src/kernel/core/addons/bus_managers/bus_man.c @@ -0,0 +1,183 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +typedef struct bus { + struct bus *next; + const char *path; +} bus; + +static bus *bus_list; +static mutex bus_lock; + +int bus_man_init(kernel_args *ka) +{ + mutex_init(&bus_lock, "bus_lock"); + + bus_list = NULL; + + return 0; +} + +static bus *find_bus(const char *path) +{ + bus *b; + + for(b = bus_list; b != NULL; b = b->next) { + if(!strcmp(b->path, path)) + break; + } + return b; +} + +int bus_register_bus(const char *path) +{ + bus *b; + int err = 0; + + dprintf("bus_register_bus: path '%s'\n", path); + + mutex_lock(&bus_lock); + + if(!find_bus(path)) { + b = (bus *)kmalloc(sizeof(bus)); + if(b == NULL) { + err = ERR_NO_MEMORY; + goto err; + } + + b->path = kmalloc(strlen(path)+1); + if(b->path == NULL) { + err = ERR_NO_MEMORY; + kfree(b); + goto err; + } + strcpy((char *)b->path, path); + + b->next = bus_list; + bus_list = b; + } else { + err = ERR_NOT_FOUND; + } + + err = 0; +err: + mutex_unlock(&bus_lock); + return err; +} + +static int bus_find_device_recurse(int *n, char *base_path, int base_fd, id_list *vendor_ids, id_list *device_ids) +{ + char leaf[256]; + int base_path_len = strlen(base_path); + ssize_t len; + int fd; + int err; + struct stat stat; + + while((len = sys_read(base_fd, &leaf, -1, sizeof(leaf))) > 0) { + // reset the base_path to the original string passed in + base_path[base_path_len] = 0; + + strlcat(base_path, leaf, sizeof(leaf)); + fd = sys_open(base_path, STREAM_TYPE_ANY, 0); + if(fd < 0) + continue; + err = sys_rstat(base_path, &stat); + if(err < 0) { + sys_close(fd); + continue; + } + if(S_ISDIR(stat.st_mode)) { + strcat(base_path, "/"); /* XXXfreston... this is unsafe!!!! */ + err = bus_find_device_recurse(n, base_path, fd, vendor_ids, device_ids); + sys_close(fd); + if(err >= 0) + return err; + continue; + } else if(S_ISREG(stat.st_mode)) { + // we opened the device + // XXX assumes PCI + struct pci_cfg cfg; + uint32 i, j; + + err = sys_ioctl(fd, PCI_GET_CFG, &cfg, sizeof(struct pci_cfg)); + if(err >= 0) { + // see if the vendor & device id matches + for(i=0; inum_ids; i++) { + if(cfg.vendor_id == vendor_ids->id[i]) { + for(j=0; jnum_ids; j++) { + if(cfg.device_id == device_ids->id[j]) { + // found it + (*n)--; + if(*n <= 0) + return fd; + } + } + } + } + } + sys_close(fd); + } + } + return ERR_NOT_FOUND; +} + +int bus_find_device(int n, id_list *vendor_ids, id_list *device_ids, device *dev) +{ + int base_fd; + int fd; + char path[256]; + bus *b; + int err = -1; + + for(b = bus_list; b != NULL && err < 0; b = b->next) { + base_fd = sys_open(b->path, STREAM_TYPE_DIR, 0); + if(base_fd < 0) + continue; + + strlcpy(path, b->path, sizeof(path)); + strlcat(path, "/", sizeof(path)); + fd = bus_find_device_recurse(&n, path, base_fd, vendor_ids, device_ids); + if(fd >= 0) { + // we have a device! + // XXX assumes pci + struct pci_cfg cfg; + int i; + + err = sys_ioctl(fd, PCI_GET_CFG, &cfg, sizeof(struct pci_cfg)); + if(err >= 0) { + // copy the relevant data from the pci config to the more generic config + memset(dev, 0, sizeof(device)); + dev->vendor_id = cfg.vendor_id; + dev->device_id = cfg.device_id; + dev->irq = cfg.irq; + for(i=0; i<6; i++) { + dev->base[i] = cfg.base[i]; + dev->size[i] = cfg.size[i]; + } + strcpy(dev->dev_path, path); + } + sys_close(fd); + } + sys_close(base_fd); + } + + return err; +} + + diff --git a/src/kernel/core/addons/bus_managers/isa/Jamfile b/src/kernel/core/addons/bus_managers/isa/Jamfile new file mode 100644 index 0000000000..38e968bc31 --- /dev/null +++ b/src/kernel/core/addons/bus_managers/isa/Jamfile @@ -0,0 +1,3 @@ +SubDir OBOS_TOP sources os kits kernel core addons bus_managers isa ; + +KernelObjects isa.c : -fno-pic ; diff --git a/src/kernel/core/addons/bus_managers/isa/isa.c b/src/kernel/core/addons/bus_managers/isa/isa.c new file mode 100755 index 0000000000..284815ac26 --- /dev/null +++ b/src/kernel/core/addons/bus_managers/isa/isa.c @@ -0,0 +1,136 @@ +/* +** Copyright 2002, Thomas Kurschel. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#include +#include +#include +#include +#include + +static int isa_init( void ) +{ + dprintf( "ISA: init\n" ); + return B_NO_ERROR; +} + +static status_t isa_rescan(void) +{ + dprintf("isa_rescan()\n"); + return 0; +} + +static int isa_uninit( void ) +{ + dprintf( "ISA: uninit\n" ); + return B_NO_ERROR; +} + +static uint8 isa_read_io_8(int mapped_io_addr) +{ + return in8( mapped_io_addr ); +} + +static void isa_write_io_8(int mapped_io_addr, uint8 value) +{ + out8( value, mapped_io_addr ); +} + +static uint16 isa_read_io_16( int mapped_io_addr ) +{ + return in16( mapped_io_addr ); +} + +static void isa_write_io_16( int mapped_io_addr, uint16 value ) +{ + out16( value, mapped_io_addr ); +} + +static uint32 isa_read_io_32( int mapped_io_addr ) +{ + return in32( mapped_io_addr ); +} + +static void isa_write_io_32( int mapped_io_addr, uint32 value ) +{ + out32( value, mapped_io_addr ); +} + +static void *ram_address(const void *physical_address_in_system_memory) +{ + dprintf("isa: ram_address\n"); + return NULL; +} + +static long make_isa_dma_table(const void *buffer, long buffer_size, + ulong num_bits, isa_dma_entry *table, + long num_entries) +{ + return ENOSYS; +} + +static long start_isa_dma(long channel, void *buf, long transfer_count, + uchar mode, uchar e_mode) +{ + return ENOSYS; +} + +static long start_scattered_isa_dma(long channel, const isa_dma_entry *table, + uchar mode, uchar emode) +{ + return ENOSYS; +} + +static long lock_isa_dma_channel(long channel) +{ + return ENOSYS; +} + +static long unlock_isa_dma_channel(long channel) +{ + return ENOSYS; +} + +static int std_ops(int32 op, ...) +{ + switch(op) { + case B_MODULE_INIT: + isa_init(); + break; + case B_MODULE_UNINIT: + isa_uninit(); + break; + default: + return EINVAL; + } + return 0; +} + +static isa_bus_manager isa_module = { + { + { + ISA_MODULE_NAME, + B_KEEP_LOADED, + std_ops + }, + &isa_rescan + }, + &isa_read_io_8, + &isa_write_io_8, + &isa_read_io_16, + &isa_write_io_16, + &isa_read_io_32, + &isa_write_io_32, + &ram_address, + &make_isa_dma_table, + &start_isa_dma, + &start_scattered_isa_dma, + &lock_isa_dma_channel, + &unlock_isa_dma_channel +}; + +module_info *modules[] = { + (module_info*) &isa_module, + NULL +}; diff --git a/src/kernel/core/addons/bus_managers/pci/Jamfile b/src/kernel/core/addons/bus_managers/pci/Jamfile new file mode 100644 index 0000000000..f876df7ab0 --- /dev/null +++ b/src/kernel/core/addons/bus_managers/pci/Jamfile @@ -0,0 +1,3 @@ +SubDir OBOS_TOP sources os kits kernel core addons bus_managers pci ; + +KernelStaticLibrary libbuspci : pci.c pci_bus.c ; diff --git a/src/kernel/core/addons/bus_managers/pci/pci.c b/src/kernel/core/addons/bus_managers/pci/pci.c new file mode 100755 index 0000000000..e7728cf2e6 --- /dev/null +++ b/src/kernel/core/addons/bus_managers/pci/pci.c @@ -0,0 +1,193 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include "pci_p.h" // private includes + +struct pci_config { + struct pci_config *next; + char *full_path; + struct pci_cfg *cfg; +}; + +struct pci_config *pci_list; + +static int pci_open(const char *name, uint32 flags, void * *_cookie) +{ +// struct pci_cookie *cookie; + struct pci_config *c = (struct pci_config *)kmalloc(sizeof(struct pci_config)); + + /* name points at the devfs_vnode so this is safe as we have to have a shorter + * lifetime than the vnode and the devfs_vnode + */ + c->full_path = (char*)name; + dprintf("pci_open: entry on '%s'\n", c->full_path); + + *_cookie = c; + + return 0; +} + +static int pci_freecookie(void * cookie) +{ + kfree(cookie); + return 0; +} + +/* +static int pci_seek(void * cookie, off_t pos, seek_type st) +{ + return ERR_NOT_ALLOWED; +} +*/ + +static int pci_close(void * cookie) +{ + return 0; +} + +static ssize_t pci_read(void *cookie, off_t pos, void *buf, size_t *len) +{ + *len = 0; + return ERR_NOT_ALLOWED; +} + +static ssize_t pci_write(void * cookie, off_t pos, const void *buf, size_t *len) +{ + return ERR_NOT_ALLOWED; +} + +static int pci_ioctl(void * _cookie, uint32 op, void *buf, size_t len) +{ + struct pci_config *cookie = _cookie; + int err = 0; + + switch(op) { + case PCI_GET_CFG: + if(len < sizeof(struct pci_cfg)) { + err= -1; + goto err; + } + + err = user_memcpy(buf, cookie->cfg, sizeof(struct pci_cfg)); + break; + case PCI_DUMP_CFG: + dump_pci_config(cookie->cfg); + break; + default: + err = ERR_INVALID_ARGS; + goto err; + } + +err: + return err; +} + +device_hooks pci_hooks = { + &pci_open, + &pci_close, + &pci_freecookie, + &pci_ioctl, + &pci_read, + &pci_write, + NULL, /* select */ + NULL, /* deselect */ +// NULL, /* readv */ +// NULL /* writev */ +}; + +static int pci_create_config_structs() +{ + int bus, unit, function; + struct pci_cfg *cfg = NULL; + struct pci_config *config; + char char_buf[SYS_MAX_PATH_LEN]; + + dprintf("pcifs_create_vnode_tree: entry\n"); + + for(bus = 0; bus < 256; bus++) { + char bus_txt[4]; + sprintf(bus_txt, "%d", bus); + for(unit = 0; unit < 32; unit++) { + char unit_txt[3]; + sprintf(unit_txt, "%d", unit); + for(function = 0; function < 8; function++) { + char func_txt[2]; + sprintf(func_txt, "%d", function); + + if(cfg == NULL) + cfg = kmalloc(sizeof(struct pci_cfg)); + if(pci_probe(bus, unit, function, cfg) < 0) { + // not possible for a unit to have a hole in functions + // if we dont find one in this unit, there are no more + break; + } + + config = kmalloc(sizeof(struct pci_config)); + if(!config) + panic("pci_create_config_structs: error allocating pci config struct\n"); + + sprintf(char_buf, "bus/pci/%s/%s/%s/ctrl", bus_txt, unit_txt, func_txt); + dprintf("created node '%s'\n", char_buf); + + config->full_path = kmalloc(strlen(char_buf)+1); + strcpy(config->full_path, char_buf); + + config->cfg = cfg; + config->next = NULL; + + config->next = pci_list; + pci_list = config; + + cfg = NULL; + } + } + } + + if(cfg != NULL) + kfree(cfg); + + return 0; +} + +int pci_bus_init(kernel_args *ka) +{ + struct pci_config *c; + + pci_list = NULL; + + dprintf("PCI: pci_bus_init()\n"); + + pci_create_config_structs(); + + // create device nodes + for(c = pci_list; c; c = c->next) { + devfs_publish_device(c->full_path, c, &pci_hooks); + } + + // register with the bus manager + bus_register_bus("/dev/bus/pci"); + + return 0; +} + diff --git a/src/kernel/core/addons/bus_managers/pci/pci_bus.c b/src/kernel/core/addons/bus_managers/pci/pci_bus.c new file mode 100755 index 0000000000..d3fed561ca --- /dev/null +++ b/src/kernel/core/addons/bus_managers/pci/pci_bus.c @@ -0,0 +1,328 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include + +#include + +#include + +#include "pci_p.h" // private includes + +/* While this will now print details of all the PCI devices it finds, for a full + * description of the devices you'll need to add the information. As the header is + * 275k I haven't just included it while we're still working on a floppy image, + * but rather it's inclusion is optional. + * + * If you want to include the header for more information, you'll need to + * 1) get a copy of pcihdr.h from http://www.yourvote.com/pci/ and modify it + * or get pcihdr.h.zip from http://beos.jetnet.co.uk/kernel/ + * 2) copy it into the pci directory (ie here) + * 3) change the define of USE_PCIHDR from 0 to 1 + * 4) rebuild + */ +#define USE_PCIHDR 0 +#if USE_PCIHDR +#include "pcihdr.h" +#endif + +int pci_scan_all(); + +struct pci_fs { + fs_id id; + mutex lock; + void *covered_vnode; + void *redir_vnode; + int root_vnode; /* just a placeholder to return a pointer to */ +}; + +static unsigned int pci_read_data(uint8 bus, uint8 unit, uint8 function, int reg, int bytes) +{ + struct pci_config_address addr; + addr.enable = 1; + addr.reserved = 0; + addr.bus = bus; + addr.unit = unit; + addr.function = function; + addr.reg = reg & 0xfc; + + out32(*(unsigned int *)&addr, CONFIG_ADDRESS); + switch(bytes) { + case 1: + return in8(CONFIG_DATA + (reg & 3)); + case 2: + return in16(CONFIG_DATA + (reg & 3)); + case 4: + return in32(CONFIG_DATA + (reg & 3)); + default: + return 0; + } +} + +static void pci_write_data(uint8 bus, uint8 unit, uint8 function, int reg, uint32 data, int bytes) +{ + struct pci_config_address addr; + addr.enable = 1; + addr.reserved = 0; + addr.bus = bus; + addr.unit = unit; + addr.function = function; + addr.reg = reg & 0xfc; + + out32(*(unsigned int *)&addr, CONFIG_ADDRESS); + switch(bytes) { + case 1: + out8(data, CONFIG_DATA + (reg & 3)); + break; + case 2: + out16(data, CONFIG_DATA + (reg & 3)); + break; + case 4: + out32(data, CONFIG_DATA + (reg & 3)); + break; + } + return; +} + +static int pci_read_config(uint8 bus, uint8 unit, uint8 func, struct pci_cfg *cfg) +{ + union { + struct pci_cfg cfg; + uint32 word[4]; + } u; + int i; + + for(i=0; i<4; i++) { + u.word[i] = pci_read_data(bus, unit, func, 4*i, 4); + } + if(u.cfg.vendor_id == 0xffff) + return -1; + + // move over to the passed in config structure + memcpy(cfg, &u.cfg, sizeof(struct pci_cfg)); + cfg->bus = bus; + cfg->unit = unit; + cfg->func = func; + + switch(cfg->header_type & 0x7f) { + case 0: { // normal device + uint32 v; + for(i=0; i<6; i++) { + v = pci_read_data(bus, unit, func, i*4 + 0x10, 4); + if(v) { + int v2; + pci_write_data(bus, unit, func, i*4 + 0x10, 0xffffffff, 4); + v2 = pci_read_data(bus, unit, func, i*4 + 0x10, 4) & 0xfffffff0; + pci_write_data(bus, unit, func, i*4 + 0x10, v, 4); + v2 = 1 + ~v2; + if(v & 1) { + cfg->base[i] = v & 0xfff0; + cfg->size[i] = v2 & 0xffff; + } else { + cfg->base[i] = v & 0xfffffff0; + cfg->size[i] = v2; + } + } else { + cfg->base[i] = 0; + cfg->size[i] = 0; + } + } + v = pci_read_data(bus, unit, func, 0x3c, 1); + cfg->irq = (v == 0xff ? 0 : v); + break; + } + case 1: // PCI <-> PCI bridge + break; + default: + break; + } + return 0; +} + +static const char *pci_class_to_string(uint8 base_class) +{ + switch(base_class) { + case 0x00: return "legacy"; + case 0x01: return "mass storage"; + case 0x02: return "network"; + case 0x03: return "video"; + case 0x04: return "multimedia"; + case 0x05: return "memory"; + case 0x06: return "bridge"; + case 0x07: return "comms"; + case 0x08: return "system"; + case 0x09: return "input"; + case 0x0a: return "docking station"; + case 0x0b: return "processor"; + case 0x0c: return "serial bus controller"; + case 0x0d: return "wireless"; + case 0x0e: return "intelligent i/o ??"; + case 0x0f: return "satellite"; + case 0x10: return "encryption"; + case 0x11: return "signal processing"; + default: return "unknown"; + } +} + +static const char *pci_subclass_to_string(uint8 base_class, uint8 sub_class) +{ + switch(base_class) { + case 0: // legacy + return "unknown"; + case 1: // mass storage + switch(sub_class) { + case 0: return "scsi"; + case 1: return "ide"; + case 2: return "floppy"; + case 3: return "ipi"; + default: return "unknown"; + } + case 2: // network + switch(sub_class) { + case 0: return "ethernet"; + case 1: return "token_ring"; + case 2: return "fddi"; + default: return "unknown"; + } + case 3: // video + switch(sub_class) { + case 0: return "vga"; + case 1: return "xga"; + default: return "unknown"; + } + case 4: // multimedia + return "unknown"; + case 5: // memory + switch(sub_class) { + case 1: return "ram"; + default: return "unknown"; + } + case 6: // bridge + switch(sub_class) { + case 0: return "host"; + case 1: return "isa"; + case 2: return "eisa"; + case 3: return "mca"; + case 4: return "pcipci"; + case 5: return "pcmcia"; + case 0x80: return "other"; + default: return "unknown"; + } + default: return "unknown"; + } +} + +void dump_pci_config(struct pci_cfg *cfg) +{ + int i; + + dprintf("dump_pci_config: dumping cfg structure at %p\n", cfg); + + dprintf("\tbus: %d, unit: %d, function: %d\n", cfg->bus, cfg->unit, cfg->func); + + dprintf("\tvendor id: %d\n", cfg->vendor_id); + dprintf("\tdevice id: %d\n", cfg->device_id); + dprintf("\tcommand: %d\n", cfg->command); + dprintf("\tstatus: %d\n", cfg->status); + + dprintf("\trevision id: %d\n", cfg->revision_id); + dprintf("\tinterface: %d\n", cfg->interface); + dprintf("\tsub class: %d '%s'\n", cfg->sub_class, pci_subclass_to_string(cfg->base_class, cfg->sub_class)); + + dprintf("\tcache line size: %d\n", cfg->cache_line_size); + dprintf("\tlatency timer: %d\n", cfg->latency_timer); + dprintf("\theader type: %d\n", cfg->header_type); + dprintf("\tbist: %d\n", cfg->bist); + + dprintf("\tirq: %d\n", cfg->irq); + + for(i=0; i<6; i++) { + dprintf("\tbase[%d] = 0x%x\n", i, cfg->base[i]); + dprintf("\tsize[%d] = 0x%x\n", i, cfg->size[i]); + } +} + +static void dump_short_pci_config(struct pci_cfg *cfg) +{ +#if !USE_PCIHDR + dprintf("PCI: vendor id %d, device id %d ", cfg->vendor_id, cfg->device_id); + dprintf(", base class: %d '%s'\n", cfg->base_class, pci_class_to_string(cfg->base_class)); +#else + int i,j; + for (i=0; i < PCI_VENTABLE_LEN; i++) { + if (PciVenTable[i].VenId == cfg->vendor_id) { + dprintf("PCI: %s: ", PciVenTable[i].VenFull); + for (j=0; j < PCI_DEVTABLE_LEN; j++) { + if (PciDevTable[j].VenId == cfg->vendor_id && + PciDevTable[j].DevId == cfg->device_id) + dprintf("%s %s", PciDevTable[j].Chip, PciDevTable[j].ChipDesc); + } + dprintf("\n"); + } + } +#endif +} + +int pci_probe(uint8 bus, uint8 unit, uint8 function, struct pci_cfg *cfg) +{ + if(function > 0) { + struct pci_cfg cfg1; + + // read info about the first unit + if(pci_probe(bus, unit, 0, &cfg1) < 0) + return -1; + + if(!(cfg1.header_type & 0x80)) { + // no multiple functions for this dev + return -1; + } + } + + if(pci_read_data(bus, unit, function, 0, 2) == 0xffff) + return -1; + + if(pci_read_config(bus, unit, function, cfg) < 0) + return -1; + + dump_short_pci_config(cfg); + + return 0; +} + +#if 0 + +int pci_scan_all() +{ + int bus; + int unit; + int function; + + dprintf("pci_scan_all: entry\n"); + + for(bus = 0; bus < 255; bus++) { + for(unit = 0; unit < 32; unit++) { + for(function = 0; function < 8; function++) { + struct pci_cfg cfg; + + if(pci_read_data(bus, unit, function, 0, 2) == 0xffff) + break; + + if(pci_read_config(bus, unit, function, &cfg) < 0) + break; + + dump_short_pci_config(&cfg); + + if(!(cfg.header_type & 0x80)) { + // no multiple functions + break; + } + } + } + } + return 0; +} +#endif + diff --git a/src/kernel/core/arch/Jamfile b/src/kernel/core/arch/Jamfile new file mode 100755 index 0000000000..e0ae3861c9 --- /dev/null +++ b/src/kernel/core/arch/Jamfile @@ -0,0 +1,3 @@ +SubDir OBOS_TOP sources os kits kernel core arch ; + +SubInclude OBOS_TOP sources os kits kernel core arch $(OBOS_TARGET_DIR) ; diff --git a/src/kernel/core/arch/m68k/arch_kernel.mk b/src/kernel/core/arch/m68k/arch_kernel.mk new file mode 100755 index 0000000000..3df489f1b7 --- /dev/null +++ b/src/kernel/core/arch/m68k/arch_kernel.mk @@ -0,0 +1,25 @@ +# m68k kernel makefile +# included from kernel.mk +KERNEL_ARCH_OBJ_DIR = $(KERNEL_ARCH_DIR)/$(OBJ_DIR) +KERNEL_OBJS += \ + + +KERNEL_ARCH_INCLUDES = $(KERNEL_INCLUDES) + +$(KERNEL_ARCH_OBJ_DIR)/%.o: $(KERNEL_ARCH_DIR)/%.c + @mkdir -p $(KERNEL_ARCH_OBJ_DIR) + $(CC) -c $< $(GLOBAL_CFLAGS) $(KERNEL_ARCH_INCLUDES) -o $@ + +$(KERNEL_ARCH_OBJ_DIR)/%.d: $(KERNEL_ARCH_DIR)/%.c + @mkdir -p $(KERNEL_ARCH_OBJ_DIR) + @echo "making deps for $<..." + @($(ECHO) -n $(dir $@); $(CC) $(GLOBAL_CFLAGS) $(KERNEL_ARCH_INCLUDES) -M -MG $<) > $@ + +$(KERNEL_ARCH_OBJ_DIR)/%.d: $(KERNEL_ARCH_DIR)/%.S + @mkdir -p $(KERNEL_ARCH_OBJ_DIR) + @echo "making deps for $<..." + @($(ECHO) -n $(dir $@);$(CC) $(GLOBAL_CFLAGS) $(KERNEL_ARCH_INCLUDES) -M -MG $<) > $@ + +$(KERNEL_ARCH_OBJ_DIR)/%.o: $(KERNEL_ARCH_DIR)/%.S + @mkdir -p $(KERNEL_ARCH_OBJ_DIR) + $(CC) -c $< $(GLOBAL_CFLAGS) $(KERNEL_ARCH_INCLUDES) -o $@ diff --git a/src/kernel/core/arch/m68k/kernel.ld b/src/kernel/core/arch/m68k/kernel.ld new file mode 100755 index 0000000000..30b02996db --- /dev/null +++ b/src/kernel/core/arch/m68k/kernel.ld @@ -0,0 +1,65 @@ +OUTPUT_FORMAT("elf32-m68k", "elf32-m68k", "elf32-m68k") +OUTPUT_ARCH(m68k) + +ENTRY(_start) +SEARCH_DIR("libgcc"); +SECTIONS +{ + . = 0x80000000 + SIZEOF_HEADERS; + + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0x9090 + .plt : { *(.plt) } + + /* text/read-only data */ + .text : { *(.text .gnu.linkonce.t.*) } =0x9090 + + .rodata : { *(.rodata) } + + /* writable data */ + . = ALIGN(0x1000); + __data_start = .; + .data : { *(.data .gnu.linkonce.d.*) } + + __ctor_list = .; + .ctors : { *(.ctors) } + __ctor_end = .; + __dtor_list = .; + .dtors : { *(.dtors) } + __dtor_end = .; + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + + /* unintialized data (in same segment as writable data) */ + __bss_start = .; + .bss : { *(.bss) } + + . = ALIGN(0x1000); + _end = . ; + + /* Strip unnecessary stuff */ + /DISCARD/ : { *(.comment .note .eh_frame) } +} diff --git a/src/kernel/core/arch/mips/arch_asm.S b/src/kernel/core/arch/mips/arch_asm.S new file mode 100755 index 0000000000..c537b2161f --- /dev/null +++ b/src/kernel/core/arch/mips/arch_asm.S @@ -0,0 +1,28 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#define FUNC(name) .align 2 ; .globl name ; name: + +.text +FUNC(reboot) + +FUNC(atomic_add) + +FUNC(atomic_and) + +FUNC(atomic_or) + +/* XXX finish */ +FUNC(test_and_set) + +FUNC(disable_exceptions) + +FUNC(enable_exceptions) + +FUNC(arch_int_restore_interrupts) + +FUNC(arch_int_enable_interrupts) + +FUNC(arch_int_disable_interrupts) + diff --git a/src/kernel/core/arch/mips/arch_cpu.c b/src/kernel/core/arch/mips/arch_cpu.c new file mode 100755 index 0000000000..5259c43903 --- /dev/null +++ b/src/kernel/core/arch/mips/arch_cpu.c @@ -0,0 +1,18 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include + +int arch_cpu_init(kernel_args *ka) +{ + return 0; +} + +int arch_cpu_init2(kernel_args *ka) +{ + return 0; +} + diff --git a/src/kernel/core/arch/mips/arch_dbg_console.c b/src/kernel/core/arch/mips/arch_dbg_console.c new file mode 100755 index 0000000000..8d9c88bc3d --- /dev/null +++ b/src/kernel/core/arch/mips/arch_dbg_console.c @@ -0,0 +1,47 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include + +#include + +int arch_dbg_con_init(kernel_args *ka) +{ + return 0; +} + +char arch_dbg_con_read() +{ + return 0; +} + +/* Flush all FIFO'd bytes out of the serial port buffer */ +static void arch_dbg_con_flush() +{ +} + +static void _arch_dbg_con_putch(const char c) +{ +} + +char arch_dbg_con_putch(const char c) +{ + if (c == '\n') { + _arch_dbg_con_putch('\r'); + _arch_dbg_con_putch('\n'); + } else if (c != '\r') + _arch_dbg_con_putch(c); + + return c; +} + +void arch_dbg_con_puts(const char *s) +{ + while(*s != '\0') { + arch_dbg_con_putch(*s); + s++; + } +} + diff --git a/src/kernel/core/arch/mips/arch_debug.c b/src/kernel/core/arch/mips/arch_debug.c new file mode 100755 index 0000000000..ee123c627e --- /dev/null +++ b/src/kernel/core/arch/mips/arch_debug.c @@ -0,0 +1,8 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include + diff --git a/src/kernel/core/arch/mips/arch_faults.c b/src/kernel/core/arch/mips/arch_faults.c new file mode 100755 index 0000000000..67698c01a5 --- /dev/null +++ b/src/kernel/core/arch/mips/arch_faults.c @@ -0,0 +1,11 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include + +int arch_faults_init(kernel_args *ka) +{ + return 0; +} + diff --git a/src/kernel/core/arch/mips/arch_int.c b/src/kernel/core/arch/mips/arch_int.c new file mode 100755 index 0000000000..ab4febb53a --- /dev/null +++ b/src/kernel/core/arch/mips/arch_int.c @@ -0,0 +1,35 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include + +#include + +struct vector *vector_table; + +void arch_int_enable_io_interrupt(int irq) +{ + return; +} + +void arch_int_disable_io_interrupt(int irq) +{ + return; +} + +int arch_int_init(kernel_args *ka) +{ + int i; + + dprintf("arch_int_init: entry\n"); + + return 0; +} + +int arch_int_init2(kernel_args *ka) +{ + return 0; +} + diff --git a/src/kernel/core/arch/mips/arch_kernel.mk b/src/kernel/core/arch/mips/arch_kernel.mk new file mode 100755 index 0000000000..cb7baf4ecc --- /dev/null +++ b/src/kernel/core/arch/mips/arch_kernel.mk @@ -0,0 +1,35 @@ +# mips kernel makefile +# included from kernel.mk +KERNEL_ARCH_OBJ_DIR = $(KERNEL_ARCH_DIR)/$(OBJ_DIR) +KERNEL_OBJS += \ + $(KERNEL_ARCH_OBJ_DIR)/arch_asm.o \ + $(KERNEL_ARCH_OBJ_DIR)/arch_cpu.o \ + $(KERNEL_ARCH_OBJ_DIR)/arch_dbg_console.o \ + $(KERNEL_ARCH_OBJ_DIR)/arch_debug.o \ + $(KERNEL_ARCH_OBJ_DIR)/arch_faults.o \ + $(KERNEL_ARCH_OBJ_DIR)/arch_int.o \ + $(KERNEL_ARCH_OBJ_DIR)/arch_pmap.o \ + $(KERNEL_ARCH_OBJ_DIR)/arch_smp.o \ + $(KERNEL_ARCH_OBJ_DIR)/arch_thread.o \ + $(KERNEL_ARCH_OBJ_DIR)/arch_timer.o \ + $(KERNEL_ARCH_OBJ_DIR)/arch_vm.o + +KERNEL_ARCH_INCLUDES = $(KERNEL_INCLUDES) + +$(KERNEL_ARCH_OBJ_DIR)/%.o: $(KERNEL_ARCH_DIR)/%.c + @if [ ! -d $(KERNEL_ARCH_OBJ_DIR) ]; then mkdir -p $(KERNEL_ARCH_OBJ_DIR); fi + $(CC) -c $< $(GLOBAL_CFLAGS) $(KERNEL_ARCH_INCLUDES) -o $@ + +$(KERNEL_ARCH_OBJ_DIR)/%.d: $(KERNEL_ARCH_DIR)/%.c + @if [ ! -d $(KERNEL_ARCH_OBJ_DIR) ]; then mkdir -p $(KERNEL_ARCH_OBJ_DIR); fi + @echo "making deps for $<..." + @($(ECHO) -n $(dir $@); $(CC) $(GLOBAL_CFLAGS) $(KERNEL_ARCH_INCLUDES) -M -MG $<) > $@ + +$(KERNEL_ARCH_OBJ_DIR)/%.d: $(KERNEL_ARCH_DIR)/%.S + @if [ ! -d $(KERNEL_ARCH_OBJ_DIR) ]; then mkdir -p $(KERNEL_ARCH_OBJ_DIR); fi + @echo "making deps for $<..." + @($(ECHO) -n $(dir $@);$(CC) $(GLOBAL_CFLAGS) $(KERNEL_ARCH_INCLUDES) -M -MG $<) > $@ + +$(KERNEL_ARCH_OBJ_DIR)/%.o: $(KERNEL_ARCH_DIR)/%.S + @if [ ! -d $(KERNEL_ARCH_OBJ_DIR) ]; then mkdir -p $(KERNEL_ARCH_OBJ_DIR); fi + $(CC) -c $< $(GLOBAL_CFLAGS) $(KERNEL_ARCH_INCLUDES) -o $@ diff --git a/src/kernel/core/arch/mips/arch_pmap.c b/src/kernel/core/arch/mips/arch_pmap.c new file mode 100755 index 0000000000..8b39bb1203 --- /dev/null +++ b/src/kernel/core/arch/mips/arch_pmap.c @@ -0,0 +1,55 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include + +#include + +#include + +#define CHATTY_PMAP 0 + +int arch_pmap_init(kernel_args *ka) +{ + dprintf("arch_pmap_init: entry\n"); + + return 0; +} + +int arch_pmap_init2(kernel_args *ka) +{ + return 0; +} + +int pmap_map_page(addr paddr, addr vaddr, int lock) +{ +#if CHATTY_PMAP + dprintf("pmap_map_page: entry paddr 0x%x vaddr 0x%x lock 0x%x\n", paddr, vaddr, lock); +#endif + + arch_pmap_invl_page(vaddr); + + return 0; +} + +int pmap_unmap_page(addr vaddr) +{ + panic("pmap_unmap_page unimplemented!\n"); + return 0; +} + +void arch_pmap_invl_page(addr vaddr) +{ +#if CHATTY_PMAP + dprintf("arch_pmap_invl_page: vaddr 0x%x\n", vaddr); +#endif + return; +} + +int pmap_get_page_mapping(addr vaddr, addr *paddr) +{ + + return 0; +} diff --git a/src/kernel/core/arch/mips/arch_smp.c b/src/kernel/core/arch/mips/arch_smp.c new file mode 100755 index 0000000000..241a2c75bd --- /dev/null +++ b/src/kernel/core/arch/mips/arch_smp.c @@ -0,0 +1,27 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include + +int arch_smp_init(kernel_args *ka) +{ + return 0; +} + +int arch_smp_get_current_cpu() +{ + return 0; +} + +void arch_smp_send_ici(int target_cpu) +{ + panic("called arch_smp_send_ici!\n"); +} + +void arch_smp_send_broadcast_ici() +{ + panic("called arch_smp_send_broadcast_ici\n"); +} + diff --git a/src/kernel/core/arch/mips/arch_thread.c b/src/kernel/core/arch/mips/arch_thread.c new file mode 100755 index 0000000000..c9a1b79c65 --- /dev/null +++ b/src/kernel/core/arch/mips/arch_thread.c @@ -0,0 +1,51 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include + +int arch_proc_init_proc_struct(struct proc *p, bool kernel) +{ + return 0; +} + +int arch_thread_init_thread_struct(struct thread *t) +{ + return 0; +} + +int arch_thread_initialize_kthread_stack(struct thread *t, int (*start_func)(void), void (*entry_func)(void)) +{ + return 0; +} + +void arch_thread_context_switch(struct thread *t_from, struct thread *t_to) +{ +#if 0 + int i; + dprintf("arch_thread_context_switch: 0x%x->0x%x to sp 0x%x\n", + t_from->id, t_to->id, t_to->arch_info.sp); +#endif +#if 0 + for(i=0; i<8; i++) { + dprintf("sp[%d] = 0x%x\n", i, t_to->arch_info.sp[i]); + } +#endif +#if 0 + sh4_set_kstack(t_to->kernel_stack_area->base + KSTACK_SIZE); + + if(t_from->proc->arch_info.pgdir != t_to->proc->arch_info.pgdir) + sh4_set_user_pgdir((addr)t_to->proc->arch_info.pgdir); + sh4_context_switch(&t_from->arch_info.sp, t_to->arch_info.sp); +#endif +} + +void arch_thread_dump_info(void *info) +{ +} + +void arch_thread_enter_uspace(addr entry, addr ustack_top) +{ +} + diff --git a/src/kernel/core/arch/mips/arch_timer.c b/src/kernel/core/arch/mips/arch_timer.c new file mode 100755 index 0000000000..b37183528a --- /dev/null +++ b/src/kernel/core/arch/mips/arch_timer.c @@ -0,0 +1,25 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include + +time_t system_time() +{ + return 0; +} + +void arch_timer_set_hardware_timer(time_t timeout) +{ +} + +void arch_timer_clear_hardware_timer() +{ +} + +int arch_init_timer(kernel_args *ka) +{ + return 0; +} + diff --git a/src/kernel/core/arch/mips/arch_vm.c b/src/kernel/core/arch/mips/arch_vm.c new file mode 100755 index 0000000000..751a17c1dc --- /dev/null +++ b/src/kernel/core/arch/mips/arch_vm.c @@ -0,0 +1,24 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include + +int arch_vm_init(kernel_args *ka) +{ + return 0; +} + +int arch_vm_init2(kernel_args *ka) +{ + return 0; +} + +int map_page_into_kspace(addr paddr, addr kaddr, int lock) +{ + panic("map_page_into_kspace: XXX finish or dont use!\n"); + return 0; +} + diff --git a/src/kernel/core/arch/mips/kernel.ld b/src/kernel/core/arch/mips/kernel.ld new file mode 100755 index 0000000000..e2230059c1 --- /dev/null +++ b/src/kernel/core/arch/mips/kernel.ld @@ -0,0 +1,42 @@ +OUTPUT_FORMAT("elf32-bigmips", "elf32-bigmips", "elf32-bigmips") +OUTPUT_ARCH(mips) + +PHDRS +{ + text PT_LOAD; + data PT_LOAD; +} + +ENTRY(__start) +SECTIONS +{ + + . = 0xc0000000 + SIZEOF_HEADERS; + + /* text/read-only data */ + .text : { *(.text .gnu.linkonce.t.*) } :text + + __ctor_list = .; + .ctors : { *(.ctors) } :text + __ctor_end = .; + + .rodata : + { + *(.rodata) + . = ALIGN(0x1000); + } =0x9000 + + /* writable data */ + __data_start = .; + .data : { *(.data .gnu.linkonce.d.*) } :data + + /* unintialized data (in same segment as writable data) */ + __bss_start = .; + .bss : { *(.bss) } :data + + . = ALIGN(0x1000); + _end = . ; + + /* Strip unnecessary stuff */ + /DISCARD/ : { *(.comment .note .eh_frame .dtors) } +} diff --git a/src/kernel/core/arch/ppc/arch_asm.S b/src/kernel/core/arch/ppc/arch_asm.S new file mode 100755 index 0000000000..14d76ac419 --- /dev/null +++ b/src/kernel/core/arch/ppc/arch_asm.S @@ -0,0 +1,37 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#define FUNC(name) .align 4 ; .globl ##name ; ##name: + +.text +.globl reboot +reboot: + +.globl atomic_add +atomic_add: + +.globl atomic_and +atomic_and: + +.globl atomic_or +atomic_or: + +.globl atomic_set +atomic_set: + +.globl test_and_set +test_and_set: + +.globl arch_int_restore_interrupts +arch_int_restore_interrupts: + +.globl arch_int_enable_interrupts +arch_int_enable_interrupts: + +.globl arch_int_disable_interrupts +arch_int_disable_interrupts: + +.global dbg_save_registers +dbg_save_registers: + diff --git a/src/kernel/core/arch/ppc/arch_cpu.c b/src/kernel/core/arch/ppc/arch_cpu.c new file mode 100755 index 0000000000..d852350135 --- /dev/null +++ b/src/kernel/core/arch/ppc/arch_cpu.c @@ -0,0 +1,101 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include + +int arch_cpu_init(kernel_args *ka) +{ + return 0; +} + +int arch_cpu_init2(kernel_args *ka) +{ + return 0; +} + +void arch_cpu_invalidate_TLB_range(addr start, addr end) +{ +} + +void arch_cpu_invalidate_TLB_list(addr pages[], int num_pages) +{ +} + +void arch_cpu_global_TLB_invalidate(void) +{ +} + +long long system_time(void) +{ + return 0; +} + +int arch_cpu_user_memcpy(void *to, const void *from, size_t size, addr *fault_handler) +{ + char *tmp = (char *)to; + char *s = (char *)from; + + *fault_handler = (addr)&&error; + + while(size--) + *tmp++ = *s++; + + *fault_handler = 0; + + return 0; +error: + *fault_handler = 0; + return ERR_VM_BAD_USER_MEMORY; +} + +int arch_cpu_user_strcpy(char *to, const char *from, addr *fault_handler) +{ + *fault_handler = (addr)&&error; + + while((*to++ = *from++) != '\0') + ; + + *fault_handler = 0; + + return 0; +error: + *fault_handler = 0; + return ERR_VM_BAD_USER_MEMORY; +} + +int arch_cpu_user_strncpy(char *to, const char *from, size_t size, addr *fault_handler) +{ + *fault_handler = (addr)&&error; + + while(size-- && (*to++ = *from++) != '\0') + ; + + *fault_handler = 0; + + return 0; +error: + *fault_handler = 0; + return ERR_VM_BAD_USER_MEMORY; +} + +int arch_cpu_user_memset(void *s, char c, size_t count, addr *fault_handler) +{ + char *xs = (char *) s; + + *fault_handler = (addr)&&error; + + while (count--) + *xs++ = c; + + *fault_handler = 0; + + return 0; +error: + *fault_handler = 0; + return ERR_VM_BAD_USER_MEMORY; +} + + diff --git a/src/kernel/core/arch/ppc/arch_dbg_console.c b/src/kernel/core/arch/ppc/arch_dbg_console.c new file mode 100755 index 0000000000..5c44ffedab --- /dev/null +++ b/src/kernel/core/arch/ppc/arch_dbg_console.c @@ -0,0 +1,30 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include + +int arch_dbg_con_init(kernel_args *ka) +{ + return 0; +} + +char arch_dbg_con_read() +{ + return 0; +} + +static void _arch_dbg_con_putch(const char c) +{ +} + +char arch_dbg_con_putch(const char c) +{ + return c; +} + +void arch_dbg_con_puts(const char *s) +{ +} + diff --git a/src/kernel/core/arch/ppc/arch_debug.c b/src/kernel/core/arch/ppc/arch_debug.c new file mode 100755 index 0000000000..c602109b2b --- /dev/null +++ b/src/kernel/core/arch/ppc/arch_debug.c @@ -0,0 +1,9 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include + +// XXX will put stack trace and disassembly routines here diff --git a/src/kernel/core/arch/ppc/arch_faults.c b/src/kernel/core/arch/ppc/arch_faults.c new file mode 100755 index 0000000000..67698c01a5 --- /dev/null +++ b/src/kernel/core/arch/ppc/arch_faults.c @@ -0,0 +1,11 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include + +int arch_faults_init(kernel_args *ka) +{ + return 0; +} + diff --git a/src/kernel/core/arch/ppc/arch_int.c b/src/kernel/core/arch/ppc/arch_int.c new file mode 100755 index 0000000000..16b36a8e35 --- /dev/null +++ b/src/kernel/core/arch/ppc/arch_int.c @@ -0,0 +1,33 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include + +#include + +bool arch_int_is_interrupts_enabled(void) +{ + return true; +} + +void arch_int_enable_io_interrupt(int irq) +{ + return; +} + +void arch_int_disable_io_interrupt(int irq) +{ + return; +} + +int arch_int_init(kernel_args *ka) +{ + return 0; +} + +int arch_int_init2(kernel_args *ka) +{ + return 0; +} + diff --git a/src/kernel/core/arch/ppc/arch_kernel.mk b/src/kernel/core/arch/ppc/arch_kernel.mk new file mode 100755 index 0000000000..e44e653ff8 --- /dev/null +++ b/src/kernel/core/arch/ppc/arch_kernel.mk @@ -0,0 +1,35 @@ +# ppc kernel makefile +# included from kernel.mk +KERNEL_ARCH_OBJ_DIR = $(KERNEL_ARCH_DIR)/$(OBJ_DIR) +KERNEL_OBJS += \ + $(KERNEL_ARCH_OBJ_DIR)/arch_asm.o \ + $(KERNEL_ARCH_OBJ_DIR)/arch_cpu.o \ + $(KERNEL_ARCH_OBJ_DIR)/arch_dbg_console.o \ + $(KERNEL_ARCH_OBJ_DIR)/arch_debug.o \ + $(KERNEL_ARCH_OBJ_DIR)/arch_faults.o \ + $(KERNEL_ARCH_OBJ_DIR)/arch_int.o \ + $(KERNEL_ARCH_OBJ_DIR)/arch_smp.o \ + $(KERNEL_ARCH_OBJ_DIR)/arch_thread.o \ + $(KERNEL_ARCH_OBJ_DIR)/arch_timer.o \ + $(KERNEL_ARCH_OBJ_DIR)/arch_vm.o \ + $(KERNEL_ARCH_OBJ_DIR)/arch_vm_translation_map.o + +KERNEL_ARCH_INCLUDES = $(KERNEL_INCLUDES) + +$(KERNEL_ARCH_OBJ_DIR)/%.o: $(KERNEL_ARCH_DIR)/%.c + @mkdir -p $(KERNEL_ARCH_OBJ_DIR) + $(CC) -c $< $(GLOBAL_CFLAGS) $(KERNEL_ARCH_INCLUDES) -o $@ + +$(KERNEL_ARCH_OBJ_DIR)/%.d: $(KERNEL_ARCH_DIR)/%.c + @mkdir -p $(KERNEL_ARCH_OBJ_DIR) + @echo "making deps for $<..." + @($(ECHO) -n $(dir $@); $(CC) $(GLOBAL_CFLAGS) $(KERNEL_ARCH_INCLUDES) -M -MG $<) > $@ + +$(KERNEL_ARCH_OBJ_DIR)/%.d: $(KERNEL_ARCH_DIR)/%.S + @mkdir -p $(KERNEL_ARCH_OBJ_DIR) + @echo "making deps for $<..." + @($(ECHO) -n $(dir $@);$(CC) $(GLOBAL_CFLAGS) $(KERNEL_ARCH_INCLUDES) -M -MG $<) > $@ + +$(KERNEL_ARCH_OBJ_DIR)/%.o: $(KERNEL_ARCH_DIR)/%.S + @mkdir -p $(KERNEL_ARCH_OBJ_DIR) + $(CC) -c $< $(GLOBAL_CFLAGS) $(KERNEL_ARCH_INCLUDES) -o $@ diff --git a/src/kernel/core/arch/ppc/arch_smp.c b/src/kernel/core/arch/ppc/arch_smp.c new file mode 100755 index 0000000000..e4970229d1 --- /dev/null +++ b/src/kernel/core/arch/ppc/arch_smp.c @@ -0,0 +1,28 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include + +int arch_smp_init(kernel_args *ka) +{ + return 0; +} + +int arch_smp_get_current_cpu() +{ + return 0; +} + +void arch_smp_send_ici(int target_cpu) +{ + panic("called arch_smp_send_ici!\n"); +} + +void arch_smp_send_broadcast_ici() +{ + panic("called arch_smp_send_broadcast_ici\n"); +} + diff --git a/src/kernel/core/arch/ppc/arch_thread.c b/src/kernel/core/arch/ppc/arch_thread.c new file mode 100755 index 0000000000..27d490755b --- /dev/null +++ b/src/kernel/core/arch/ppc/arch_thread.c @@ -0,0 +1,39 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include + +int arch_proc_init_proc_struct(struct proc *p, bool kernel) +{ + return 0; +} + +int arch_thread_init_thread_struct(struct thread *t) +{ + return 0; +} + +int arch_thread_initialize_kthread_stack(struct thread *t, int (*start_func)(void), void (*entry_func)(void), void (*exit_func)(void)) +{ + return 0; +} + +void arch_thread_switch_kstack_and_call(struct thread *t, addr new_kstack, void (*func)(void *), void *arg) +{ +} + +void arch_thread_context_switch(struct thread *t_from, struct thread *t_to) +{ +} + +void arch_thread_dump_info(void *info) +{ +} + +void arch_thread_enter_uspace(addr entry, addr ustack_top) +{ +} + diff --git a/src/kernel/core/arch/ppc/arch_timer.c b/src/kernel/core/arch/ppc/arch_timer.c new file mode 100755 index 0000000000..dfa3e87971 --- /dev/null +++ b/src/kernel/core/arch/ppc/arch_timer.c @@ -0,0 +1,21 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include + +#include + +void arch_timer_set_hardware_timer(time_t timeout) +{ +} + +void arch_timer_clear_hardware_timer() +{ +} + +int arch_init_timer(kernel_args *ka) +{ + return 0; +} diff --git a/src/kernel/core/arch/ppc/arch_vm.c b/src/kernel/core/arch/ppc/arch_vm.c new file mode 100755 index 0000000000..564d75897c --- /dev/null +++ b/src/kernel/core/arch/ppc/arch_vm.c @@ -0,0 +1,22 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include + +int arch_vm_init(kernel_args *ka) +{ + return 0; +} + +int arch_vm_init2(kernel_args *ka) +{ + return 0; +} + +int arch_vm_init_endvm(kernel_args *ka) +{ + return 0; +} + diff --git a/src/kernel/core/arch/ppc/arch_vm_translation_map.c b/src/kernel/core/arch/ppc/arch_vm_translation_map.c new file mode 100755 index 0000000000..4e97941fea --- /dev/null +++ b/src/kernel/core/arch/ppc/arch_vm_translation_map.c @@ -0,0 +1,107 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include + +static int lock_tmap(vm_translation_map *map) +{ + return 0; +} + +static int unlock_tmap(vm_translation_map *map) +{ + return 0; +} + +static void destroy_tmap(vm_translation_map *map) +{ +} + +static int map_tmap(vm_translation_map *map, addr va, addr pa, unsigned int attributes) +{ + return 0; +} + +static int unmap_tmap(vm_translation_map *map, addr start, addr end) +{ + return 0; +} + +static int query_tmap(vm_translation_map *map, addr va, addr *out_physical, unsigned int *out_flags) +{ + return 0; +} + +static addr get_mapped_size_tmap(vm_translation_map *map) +{ + return 0; +} + +static int protect_tmap(vm_translation_map *map, addr base, addr top, unsigned int attributes) +{ + // XXX finish + return -1; +} + +static int get_physical_page_tmap(addr pa, addr *va, int flags) +{ + return 0; +} + +static int put_physical_page_tmap(addr va) +{ + return 0; +} + +static vm_translation_map_ops tmap_ops = { + destroy_tmap, + lock_tmap, + unlock_tmap, + map_tmap, + unmap_tmap, + query_tmap, + get_mapped_size_tmap, + protect_tmap, + get_physical_page_tmap, + put_physical_page_tmap +}; + +int vm_translation_map_create(vm_translation_map *new_map, bool kernel) +{ + return 0; +} + +int vm_translation_map_module_init(kernel_args *ka) +{ + return 0; +} + +void vm_translation_map_module_init_post_sem(kernel_args *ka) +{ + return 0; +} + +int vm_translation_map_module_init2(kernel_args *ka) +{ + return 0; +} + +// XXX horrible back door to map a page quickly regardless of translation map object, etc. +// used only during VM setup. +// uses a 'page hole' set up in the stage 2 bootloader. The page hole is created by pointing one of +// the pgdir entries back at itself, effectively mapping the contents of all of the 4MB of pagetables +// into a 4 MB region. It's only used here, and is later unmapped. +int vm_translation_map_quick_map(kernel_args *ka, addr va, addr pa, unsigned int attributes, addr (*get_free_page)(kernel_args *)) +{ + return 0; +} + +// XXX currently assumes this translation map is active +static int vm_translation_map_quick_query(addr va, addr *out_physical) +{ + return 0; +} + diff --git a/src/kernel/core/arch/ppc/kernel.ld b/src/kernel/core/arch/ppc/kernel.ld new file mode 100755 index 0000000000..f44b23950d --- /dev/null +++ b/src/kernel/core/arch/ppc/kernel.ld @@ -0,0 +1,33 @@ +OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc", "elf32-powerpc") +OUTPUT_ARCH(powerpc) + +ENTRY(_start) +SEARCH_DIR("libgcc"); +SECTIONS +{ + . = 0x80000000 + SIZEOF_HEADERS; + + /* text/read-only data */ + .text : { *(.text .gnu.linkonce.t.*) } + + __ctor_list = .; + .ctors : { *(.ctors) } + __ctor_end = .; + + .rodata : { *(.rodata) } + + /* writable data */ + . = ALIGN(0x1000); + __data_start = .; + .data : { *(.data .gnu.linkonce.d.*) } + + /* unintialized data (in same segment as writable data) */ + __bss_start = .; + .bss : { *(.bss) } + + . = ALIGN(0x1000); + _end = . ; + + /* Strip unnecessary stuff */ + /DISCARD/ : { *(.comment .note .eh_frame .dtors) } +} diff --git a/src/kernel/core/arch/sh4/addon.ld b/src/kernel/core/arch/sh4/addon.ld new file mode 100755 index 0000000000..8bf42c5b06 --- /dev/null +++ b/src/kernel/core/arch/sh4/addon.ld @@ -0,0 +1,69 @@ +OUTPUT_FORMAT("elf32-shl", "elf32-shl", "elf32-shl") +OUTPUT_ARCH(sh) + +ENTRY(__start) +SEARCH_DIR("libgcc"); +SECTIONS +{ + . = 0xc0000000 + SIZEOF_HEADERS; + + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0x9090 + .plt : { *(.plt) } + + /* text/read-only data */ + .text : { *(.text .gnu.linkonce.t.*) } =0x9090 + + .rodata : + { + *(.rodata) + . = ALIGN(0x1000); + } =0x9000 + + /* writable data */ + . = ALIGN(0x1000) + (. & (0x1000 - 1)); + ___data_start = .; + .data : { *(.data .gnu.linkonce.d.*) } + + ___ctor_list = .; + .ctors : { *(.ctors) } + ___ctor_end = .; + ___dtor_list = .; + .dtors : { *(.dtors) } + ___dtor_end = .; + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + + /* unintialized data (in same segment as writable data) */ + ___bss_start = .; + .bss : { *(.bss) } + + . = ALIGN(0x1000); + _end = . ; + + /* Strip unnecessary stuff */ + /DISCARD/ : { *(.comment .note .eh_frame) } +} diff --git a/src/kernel/core/arch/sh4/arch_asm.S b/src/kernel/core/arch/sh4/arch_asm.S new file mode 100755 index 0000000000..87cdefa369 --- /dev/null +++ b/src/kernel/core/arch/sh4/arch_asm.S @@ -0,0 +1,312 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#define FUNCTION(name) .align 2 ; .globl _##name ; .type _##name,@function ; _##name + +.text +FUNCTION(reboot): + mov.l disable_exceptions_addr,r1 + jsr @r1 + nop + + mov.l reboot_vector,r0 + jmp @r0 + nop + +FUNCTION(dbg_save_registers): + rts + nop + +.align 2 +reboot_vector: .long 0xa0000000 +disable_exceptions_addr: .long _disable_exceptions + +FUNCTION(atomic_add): + mov.l r8,@-r15 + sts.l pr,@-r15 + + /* disable interrupts */ + mov.l disable_interrupts_addr,r1 + jsr @r1 + nop + + /* load the value, save it, add to it, and store it back */ + mov.l @r4,r3 + mov r3,r8 + add r5,r3 + mov.l r3,@r4 + + /* restore interrupts */ + mov.l restore_interrupts_addr,r1 + jsr @r1 + mov r0,r4 + + /* return value will be old value */ + mov r8,r0 + + /* restore the stack */ + lds.l @r15+,pr + rts + mov.l @r15+,r8 + +FUNCTION(atomic_and): + mov.l r8,@-r15 + sts.l pr,@-r15 + + /* disable interrupts */ + mov.l disable_interrupts_addr,r1 + jsr @r1 + nop + + /* load the value, save it, and it, and store it back */ + mov.l @r4,r3 + mov r3,r8 + and r5,r3 + mov.l r3,@r4 + + /* restore interrupts */ + mov.l restore_interrupts_addr,r1 + jsr @r1 + mov r0,r4 + + /* return value will be old value */ + mov r8,r0 + + /* restore the stack */ + lds.l @r15+,pr + rts + mov.l @r15+,r8 + +FUNCTION(atomic_or): + mov.l r8,@-r15 + sts.l pr,@-r15 + + /* disable interrupts */ + mov.l disable_interrupts_addr,r1 + jsr @r1 + nop + + /* load the value, save it, or it, and store it back */ + mov.l @r4,r3 + mov r3,r8 + or r5,r3 + mov.l r3,@r4 + + /* restore interrupts */ + mov.l restore_interrupts_addr,r1 + jsr @r1 + mov r0,r4 + + /* return value will be old value */ + mov r8,r0 + + /* restore the stack */ + lds.l @r15+,pr + rts + mov.l @r15+,r8 + +FUNCTION(atomic_set): + mov.l r8,@-r15 + sts.l pr,@-r15 + + /* disable interrupts */ + mov.l disable_interrupts_addr,r1 + jsr @r1 + nop + + /* load the value, save it, and store the new value */ + mov.l @r4,r8 + mov.l r5,@r4 + + /* restore interrupts */ + mov.l restore_interrupts_addr,r1 + jsr @r1 + mov r0,r4 + + /* return value will be old value */ + mov r8,r0 + + /* restore the stack */ + lds.l @r15+,pr + rts + mov.l @r15+,r8 + +/* int test_and_set(int *val, int set_to, int test_val) */ +FUNCTION(test_and_set): + mov.l r8,@-r15 + sts.l pr,@-r15 + + /* disable interrupts */ + mov.l disable_interrupts_addr,r1 + jsr @r1 + nop + + /* load the value, save it, and store the new value */ + mov.l @r4,r8 /* load the dest, it will be the return value */ + cmp/eq r8,r6 /* compare against the test_val */ + bf _not_equal + + mov.l r5,@r4 /* put the set_to value into the target */ + +_not_equal: + /* restore interrupts */ + mov.l restore_interrupts_addr,r1 + jsr @r1 + mov r0,r4 + + /* return value will be old value */ + mov r8,r0 + + /* restore the stack */ + lds.l @r15+,pr + rts + mov.l @r15+,r8 + +.align 2 +disable_interrupts_addr: .long _arch_int_disable_interrupts +restore_interrupts_addr: .long _arch_int_restore_interrupts + +FUNCTION(disable_exceptions): + mov.l bl_bit_mask,r0 + stc sr,r1 + or r0,r1 + ldc r1,sr /* turn off interrupts/exceptions */ + rts + nop + +FUNCTION(enable_exceptions): + mov.l bl_bit_mask,r0 + not r0,r0 + stc sr,r1 + and r0,r1 + ldc r1,sr + rts + nop + +.align 2 +bl_bit_mask: .long 0x10000000 + +FUNCTION(arch_int_restore_interrupts): + mov.l inverse_imask_bit_mask,r0 + stc sr,r1 /* get the sr register */ + and r0,r1 /* zero out the imask part */ + or r4,r1 /* or in the passed in imask, should only contain imask bits */ + ldc r1,sr /* put the new status into the sr register */ + rts + nop + +FUNCTION(arch_int_enable_interrupts): + mov.l inverse_imask_bit_mask,r0 + stc sr,r1 /* load the sr register */ + and r0,r1 /* set the imask to 0 */ + ldc r1,sr /* put the new status into the sr register */ + rts + nop + +.align 2 +inverse_imask_bit_mask: .long 0xffffff0f + +FUNCTION(arch_int_disable_interrupts): + mov.l imask_bit_mask,r2 + stc sr,r1 /* load the sr register */ + mov r1,r0 /* save the old sr register */ + or r2,r1 /* or in 0xf for the imask */ + ldc r1,sr /* set the new sr register with the interrupts masked */ + rts + and r2,r0 /* make sure the return value contains only the imask part */ + +FUNCTION(arch_int_is_interrupts_enabled): + mov.l imask_bit_mask,r2 + stc sr,r0 /* load the sr register */ + and r2,r0 /* mask out just the interrupt level */ + cmp/eq #0,r0 /* check for zero */ + bt _ints_is_enabled + nop + + rts + mov #0,r0 /* return false */ + +_ints_is_enabled: + rts + mov #1,r0 /* return true */ + +.align 2 +imask_bit_mask: .long 0x000000f0 + +FUNCTION(get_sr): + stc sr,r0 + rts + nop + +FUNCTION(get_fpscr): + sts fpscr,r0 + rts + nop + +// void sh4_context_switch(unsigned int **old_esp, unsigned int *new_esp); +FUNCTION(sh4_context_switch): + fmov.s fr12,@-r15 + fmov.s fr13,@-r15 + fmov.s fr14,@-r15 + fmov.s fr15,@-r15 + sts.l fpscr,@-r15 + sts.l mach,@-r15 + sts.l macl,@-r15 + mov.l r8,@-r15 + mov.l r9,@-r15 + mov.l r10,@-r15 + mov.l r11,@-r15 + mov.l r12,@-r15 + mov.l r13,@-r15 + mov.l r14,@-r15 + sts.l pr,@-r15 + + mov.l r15,@r4 + mov r5,r15 + + lds.l @r15+,pr + mov.l @r15+,r14 + mov.l @r15+,r13 + mov.l @r15+,r12 + mov.l @r15+,r11 + mov.l @r15+,r10 + mov.l @r15+,r9 + mov.l @r15+,r8 + lds.l @r15+,macl + lds.l @r15+,mach + lds.l @r15+,fpscr + fmov.s @r15+,fr15 + fmov.s @r15+,fr14 + fmov.s @r15+,fr13 + fmov.s @r15+,fr12 + + rts + nop + +FUNCTION(sh4_function_caller): +_fc_loop: + mov.l @r15+,r2 + jsr @r2 + nop + bra _fc_loop + nop + +// void sh4_switch_stack_and_call(addr stack, void (*func)(void *), void *arg); +FUNCTION(sh4_switch_stack_and_call): + mov r4,r15 + jsr @r5 + mov r6,r4 + +// void sh4_enter_uspace(addr entry, void *args, addr ustack_top); +FUNCTION(sh4_enter_uspace): + ldc r4,spc // load the program counter it will switch to + mov r5,r4 // load the args + mov r6,r15 // restore the user stack + mov.l uspace_sr,r0 + ldc r0,ssr + rte + nop + +uspace_sr: .long 0x00000000 + diff --git a/src/kernel/core/arch/sh4/arch_cpu.c b/src/kernel/core/arch/sh4/arch_cpu.c new file mode 100755 index 0000000000..990b76867d --- /dev/null +++ b/src/kernel/core/arch/sh4/arch_cpu.c @@ -0,0 +1,173 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include + +static vcpu_struct *vcpu; + +int arch_cpu_preboot_init(kernel_args *ka) +{ + return 0; +} + +int arch_cpu_init(kernel_args *ka) +{ + vcpu = ka->arch_args.vcpu; + + vcpu->kernel_asid = 0; + vcpu->user_asid = 0; + + return 0; +} + +int arch_cpu_init2(kernel_args *ka) +{ + return 0; +} + +void sh4_set_kstack(addr kstack) +{ +// dprintf("sh4_set_kstack: setting kstack to 0x%x\n", kstack); + vcpu->kstack = (unsigned int *)kstack; +} + +void sh4_set_user_pgdir(addr pgdir) +{ +// dprintf("sh4_set_user_pgdir: setting pgdir to 0x%x\n", pgdir); + if((addr)vcpu->user_pgdir != pgdir) + arch_cpu_global_TLB_invalidate(); + vcpu->user_pgdir = (unsigned int *)pgdir; +} + +void sh4_invl_page(addr va) +{ + int state; + int i; + + va = ROUNDOWN(va, PAGE_SIZE); + + state = int_disable_interrupts(); + + // wipe it out of the data tlbs + for(i=0; ivpn == (va >> 10)) + ua->valid = 0; + } + + // wipe it out of the instruction tlbs + for(i=0; ivpn == (va >> 10)) + ia->valid = 0; + } + + int_restore_interrupts(state); +} + +void arch_cpu_invalidate_TLB_range(addr start, addr end) +{ + for(; start < end; start += PAGE_SIZE) { + sh4_invl_page(start); + } +} + +void arch_cpu_invalidate_TLB_list(addr pages[], int num_pages) +{ + int i; + for(i=0; ivalid = 0; + } + + // wipe out the instruction tlbs + for(i=0; ivalid = 0; + } + + int_restore_interrupts(state); +} + +int arch_cpu_user_memcpy(void *to, const void *from, size_t size, addr *fault_handler) +{ + char *tmp = (char *)to; + char *s = (char *)from; + + *fault_handler = (addr)&&error; + + while(size--) + *tmp++ = *s++; + + *fault_handler = 0; + + return 0; +error: + *fault_handler = 0; + return ERR_VM_BAD_USER_MEMORY; +} + +int arch_cpu_user_strcpy(char *to, const char *from, addr *fault_handler) +{ + *fault_handler = (addr)&&error; + + while((*to++ = *from++) != '\0') + ; + + *fault_handler = 0; + + return 0; +error: + *fault_handler = 0; + return ERR_VM_BAD_USER_MEMORY; +} + +int arch_cpu_user_strncpy(char *to, const char *from, size_t size, addr *fault_handler) +{ + *fault_handler = (addr)&&error; + + while(size-- && (*to++ = *from++) != '\0') + ; + + *fault_handler = 0; + + return 0; +error: + *fault_handler = 0; + return ERR_VM_BAD_USER_MEMORY; +} + +int arch_cpu_user_memset(void *s, char c, size_t count, addr *fault_handler) +{ + char *xs = (char *) s; + + *fault_handler = (addr)&&error; + + while (count--) + *xs++ = c; + + *fault_handler = 0; + + return 0; +error: + *fault_handler = 0; + return ERR_VM_BAD_USER_MEMORY; +} + diff --git a/src/kernel/core/arch/sh4/arch_dbg_console.c b/src/kernel/core/arch/sh4/arch_dbg_console.c new file mode 100755 index 0000000000..629b16ca57 --- /dev/null +++ b/src/kernel/core/arch/sh4/arch_dbg_console.c @@ -0,0 +1,115 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include + +#include + +int arch_dbg_con_init(kernel_args *ka) +{ + volatile uint16 *scif16 = (uint16*)0xffe80000; + volatile uint8 *scif8 = (uint8*)0xffe80000; + int x; + + /* Disable interrupts, transmit/receive, and use internal clock */ + scif16[8/2] = 0; + + /* 8N1, use P0 clock */ + scif16[0] = 0; + + /* Set baudrate, N = P0/(32*B)-1 */ +// scif8[4] = (50000000 / (32 * baud_rate)) - 1; + +// scif8[4] = 80; // 19200 +// scif8[4] = 40; // 38400 +// scif8[4] = 26; // 57600 + scif8[4] = 13; // 115200 + + /* Reset FIFOs, enable hardware flow control */ + scif16[24/2] = 4; //12; + + for(x = 0; x < 100000; x++); + scif16[24/2] = 0; //8; + + /* Disable manual pin control */ + scif16[32/2] = 0; + + /* Clear status */ + scif16[16/2] = 0x60; + scif16[36/2] = 0; + + /* Enable transmit/receive */ + scif16[8/2] = 0x30; + + for(x = 0; x < 100000; x++); + + arch_dbg_con_puts("serial initted\n"); + + return 0; +} + +char arch_dbg_con_read() +{ + volatile uint16 *status = (uint16*)0xffe8001c; + volatile uint16 *ack = (uint16*)0xffe80010; + volatile uint8 *fifo = (uint8*)0xffe80014; + char c; + + /* Check input FIFO */ + while ((*status & 0x1f) == 0); + + /* Get the input char */ + c = *fifo; + + /* Ack */ + *ack &= 0x6d; + + return c; +} + +/* Flush all FIFO'd bytes out of the serial port buffer */ +static void arch_dbg_con_flush() { + volatile uint16 *ack = (uint16*)0xffe80010; + + *ack &= 0xbf; + while (!(*ack & 0x40)) + ; + *ack &= 0xbf; +} + +static void _arch_dbg_con_putch(const char c) +{ + volatile uint16 *ack = (uint16*)0xffe80010; + volatile uint8 *fifo = (uint8*)0xffe8000c; + + /* Wait until the transmit buffer has space */ + while (!(*ack & 0x20)) + ; + /* Send the char */ + *fifo = c; + + /* Clear status */ + *ack &= 0x9f; +} + +char arch_dbg_con_putch(const char c) +{ + if (c == '\n') { + _arch_dbg_con_putch('\r'); + _arch_dbg_con_putch('\n'); + } else if (c != '\r') + _arch_dbg_con_putch(c); + + return c; +} + +void arch_dbg_con_puts(const char *s) +{ + while(*s != '\0') { + arch_dbg_con_putch(*s); + s++; + } +} + diff --git a/src/kernel/core/arch/sh4/arch_debug.c b/src/kernel/core/arch/sh4/arch_debug.c new file mode 100755 index 0000000000..ee123c627e --- /dev/null +++ b/src/kernel/core/arch/sh4/arch_debug.c @@ -0,0 +1,8 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include + diff --git a/src/kernel/core/arch/sh4/arch_faults.c b/src/kernel/core/arch/sh4/arch_faults.c new file mode 100755 index 0000000000..67698c01a5 --- /dev/null +++ b/src/kernel/core/arch/sh4/arch_faults.c @@ -0,0 +1,11 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include + +int arch_faults_init(kernel_args *ka) +{ + return 0; +} + diff --git a/src/kernel/core/arch/sh4/arch_int.c b/src/kernel/core/arch/sh4/arch_int.c new file mode 100755 index 0000000000..3bd062c359 --- /dev/null +++ b/src/kernel/core/arch/sh4/arch_int.c @@ -0,0 +1,176 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#define MAX_ARGS 16 + +struct vector *vector_table; + +void arch_int_enable_io_interrupt(int irq) +{ + return; +} + +void arch_int_disable_io_interrupt(int irq) +{ + return; +} + + +static int sh4_handle_exception(void *_frame) +//static int sh4_handle_exception(unsigned int code, unsigned int pc, unsigned int trap, unsigned int page_fault_addr) +{ + struct iframe *frame = (struct iframe *)_frame; + int ret; + + // NOTE: not safe to do anything that may involve the FPU before + // it is certain it is not an fpu exception + +// dprintf("sh4_handle_exception: frame 0x%x code 0x%x, pc 0x%x, ssr 0x%x, sr 0x%x, pr 0x%x\n", +// frame, frame->excode, frame->spc, frame->ssr, get_sr(), frame->pr); +// dprintf("regs: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", +// frame->r0, frame->r1, frame->r2, frame->r3, frame->r4, frame->r5, frame->r6, frame->r7, +// frame->r8, frame->r9, frame->r10, frame->r11, frame->r12, frame->r13, frame->r14, frame->sgr); + switch(frame->excode) { + case 0: // reset + case 1: // manual reset + case 5: // TLB protection violation (read) + case 6: // TLB protection violation (write) + case 7: // data address error (read) + case 8: // data address error (write) + case 10: // TLB multi hit + case 12: // illegal instruction + case 13: // slot illegal instruction + dprintf("about to gpf at pc 0x%x, excode %d\n", frame->spc, frame->excode); + ret = general_protection_fault(frame->excode); + break; + case 11: { // TRAPA + /* + ** arg layout: + ** r4-r7: arg 1 - 4 + ** r0-r3: arg 5 - 8 + ** r8-r13: arg 8 - 13 + */ + unsigned int *trap = (unsigned int *)0xff000020; + uint64 retcode; + unsigned int args[MAX_ARGS]; + + int_enable_interrupts(); + + thread_atkernel_entry(); + + // XXX redo this to be stack-based + args[0] = frame->r4; + args[1] = frame->r5; + args[2] = frame->r6; + args[3] = frame->r7; + args[4] = frame->r0; + args[5] = frame->r1; + args[6] = frame->r2; + args[7] = frame->r3; + args[8] = frame->r8; + + ret = syscall_dispatcher(*trap >> 2, args, &retcode); + frame->r0 = retcode & 0xffffffff; + frame->r1 = retcode >> 32; + break; + } + case 9: { // FPU exception + int fpu_fault_code; + switch(frame->fpscr & 0x0003f000) { + case 0x1000: + fpu_fault_code = FPU_FAULT_CODE_INEXACT; + break; + case 0x2000: + fpu_fault_code = FPU_FAULT_CODE_UNDERFLOW; + break; + case 0x4000: + fpu_fault_code = FPU_FAULT_CODE_OVERFLOW; + break; + case 0x8000: + fpu_fault_code = FPU_FAULT_CODE_DIVBYZERO; + break; + case 0x10000: + fpu_fault_code = FPU_FAULT_CODE_INVALID_OP; + break; + case 0x20000: + fpu_fault_code = FPU_FAULT_CODE_UNKNOWN; + break; + default: + // XXX handle better + fpu_fault_code = FPU_FAULT_CODE_UNKNOWN; + } + ret = fpu_fault(fpu_fault_code); + break; + } + case 64: // FPU disable exception + case 65: // Slot FPU disable exception + ret = fpu_disable_fault(); + break; + case EXCEPTION_PAGE_FAULT_READ: + case EXCEPTION_PAGE_FAULT_WRITE: { + addr newip; + if((frame->ssr & 0x000000f0) == 0) { +// dprintf("page_fault: enabling interrupts\n"); + int_enable_interrupts(); + } + ret = vm_page_fault(frame->page_fault_addr, frame->spc, + frame->excode == EXCEPTION_PAGE_FAULT_WRITE, (frame->ssr & 0x40000000) == 0, &newip); + if(newip != 0) + frame->spc = newip; + break; + } + default: + ret = int_io_interrupt_handler(frame->excode); + } + if(ret == INT_RESCHEDULE) { + int state = int_disable_interrupts(); + GRAB_THREAD_LOCK(); + thread_resched(); + RELEASE_THREAD_LOCK(); + int_restore_interrupts(state); + } + if(!(frame->ssr & 0x40000000) || (frame->excode == 11)) { + thread_atkernel_exit(); + } + +// dprintf("sh4_handle_exception: exit\n"); + + return 0; +} + +int arch_int_init(kernel_args *ka) +{ + int i; + + dprintf("arch_int_init: entry\n"); + + vector_table = (struct vector *)ka->arch_args.vcpu->vt; + dprintf("arch_int_init: vector table 0x%x\n", vector_table); + + // set up the vectors + // handle all of them + for(i=0; i<256; i++) + vector_table[i].func = &sh4_handle_exception; + + return 0; +} + +int arch_int_init2(kernel_args *ka) +{ + return 0; +} + diff --git a/src/kernel/core/arch/sh4/arch_pmap.c b/src/kernel/core/arch/sh4/arch_pmap.c new file mode 100755 index 0000000000..e1e8a2073d --- /dev/null +++ b/src/kernel/core/arch/sh4/arch_pmap.c @@ -0,0 +1,151 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include + +#define CHATTY_PMAP 0 + +static vcpu_struct *vcpu; + +#define PHYS_TO_P1(x) ((x) + P1_AREA) + +int arch_pmap_init(kernel_args *ka) +{ + dprintf("arch_pmap_init: entry\n"); + + vcpu = ka->arch_args.vcpu; + + dprintf("examining vcpu structure @ 0x%x:\n", vcpu); + dprintf("kernel_pgdir = 0x%x\n", vcpu->kernel_pgdir); + dprintf("user_pgdir = 0x%x\n", vcpu->user_pgdir); + dprintf("kernel_asid = 0x%x\n", vcpu->kernel_asid); + dprintf("user_asid = 0x%x\n", vcpu->user_asid); + + return 0; +} + +int arch_pmap_init2(kernel_args *ka) +{ + return 0; +} + +int pmap_map_page(addr paddr, addr vaddr, int lock) +{ + struct pdent *pd = NULL; + struct ptent *pt; + unsigned int index = 0; + +#if CHATTY_PMAP + dprintf("pmap_map_page: entry paddr 0x%x vaddr 0x%x lock 0x%x\n", paddr, vaddr, lock); +#endif + + if(vaddr < P1_AREA) { + pd = (struct pdent *)vcpu->user_pgdir; + index = vaddr >> 22; + } else if(vaddr >= P3_AREA && vaddr < P4_AREA) { + pd = (struct pdent *)vcpu->kernel_pgdir; + index = (vaddr & 0x7fffffff) >> 22; + } else { + // invalid area to map pages + panic("pmap_map_page: invalid vaddr 0x%x\n", vaddr); + } + + if(pd[index].v == 0) { + // need to allocate a pagetable + unsigned int pgtable; + + // get a free page for a pagetable + vm_get_free_page(&pgtable); + pgtable *= PAGE_SIZE; + + // zero out the page + memset((void *)PHYS_TO_P1(pgtable), 0, PAGE_SIZE); + + // stick it in the page dir + pd[index].ppn = pgtable >> 12; + pd[index].v = 1; + } + + // get the pagetable + pt = (struct ptent *)PHYS_TO_P1(pd[index].ppn << 12); + index = (vaddr >> 12) & 0x000003ff; + + // insert the mapping + pt[index].wt = 0; + pt[index].pr = (lock & LOCK_KERNEL) ? (lock & 0x1) : (lock | 0x2); + pt[index].ppn = paddr >> 12; + pt[index].tlb_ent = 0; + pt[index].c = 1; + pt[index].sz = 0x1; // 4k page + pt[index].sh = 0; // XXX shared? + pt[index].d = 0; + pt[index].v = 1; + + arch_pmap_invl_page(vaddr); + + return 0; +} + +int pmap_unmap_page(addr vaddr) +{ + panic("pmap_unmap_page unimplemented!\n"); + return 0; +} + +void arch_pmap_invl_page(addr vaddr) +{ +#if CHATTY_PMAP + dprintf("arch_pmap_invl_page: vaddr 0x%x\n", vaddr); +#endif + return; +} + +int pmap_get_page_mapping(addr vaddr, addr *paddr) +{ + struct pdent *pd = NULL; + struct ptent *pt; + unsigned int index = 0; + + if(vaddr < P1_AREA) { + pd = (struct pdent *)vcpu->user_pgdir; + index = vaddr >> 22; + } else if(vaddr >= P3_AREA && vaddr < P4_AREA) { + pd = (struct pdent *)vcpu->kernel_pgdir; + index = (vaddr & 0x7fffffff) >> 22; + } else if(vaddr >= P1_AREA && vaddr < P2_AREA) { + // this region is identity mapped with a shift + *paddr = vaddr - P1_AREA; + return 0; + } else if(vaddr >= P2_AREA && vaddr < P3_AREA) { + // this region is identity mapped with a shift + *paddr = vaddr - P2_AREA; + return 0; + } + + if(pd[index].v == 0) { + return -1; + } + + // get the pagetable + pt = (struct ptent *)PHYS_TO_P1(pd[index].ppn << 12); + index = (vaddr >> 12) & 0x000003ff; + + if(pt[index].v == 0) { + return -1; + } + *paddr = pt[index].ppn << 12; + + return 0; +} diff --git a/src/kernel/core/arch/sh4/arch_smp.c b/src/kernel/core/arch/sh4/arch_smp.c new file mode 100755 index 0000000000..241a2c75bd --- /dev/null +++ b/src/kernel/core/arch/sh4/arch_smp.c @@ -0,0 +1,27 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include + +int arch_smp_init(kernel_args *ka) +{ + return 0; +} + +int arch_smp_get_current_cpu() +{ + return 0; +} + +void arch_smp_send_ici(int target_cpu) +{ + panic("called arch_smp_send_ici!\n"); +} + +void arch_smp_send_broadcast_ici() +{ + panic("called arch_smp_send_broadcast_ici\n"); +} + diff --git a/src/kernel/core/arch/sh4/arch_thread.c b/src/kernel/core/arch/sh4/arch_thread.c new file mode 100755 index 0000000000..4eb5caf8e9 --- /dev/null +++ b/src/kernel/core/arch/sh4/arch_thread.c @@ -0,0 +1,134 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include + +static struct thread *curr_thread = NULL; + +int arch_proc_init_proc_struct(struct proc *p, bool kernel) +{ +#if 0 + if(!kernel) { + unsigned int page; + if(vm_get_free_page(&page) < 0) { + panic("arch_proc_init_proc_struct: could not find free frame for page dir\n"); + } + p->arch_info.pgdir = (unsigned int *)PHYS_ADDR_TO_P1(page * PAGE_SIZE); + memset(p->arch_info.pgdir, 0, PAGE_SIZE); + } else { + p->arch_info.pgdir = NULL; + } +#endif + return 0; +} + +int arch_thread_init_thread_struct(struct thread *t) +{ + t->arch_info.sp = NULL; + + return 0; +} + +int arch_thread_initialize_kthread_stack(struct thread *t, int (*start_func)(void), void (*entry_func)(void), void (*exit_func)(void)) +{ + unsigned int *kstack = (unsigned int *)t->kernel_stack_base; + unsigned int kstack_size = KSTACK_SIZE; + unsigned int *kstack_top = kstack + kstack_size / sizeof(unsigned int); + int i; + + // clear the kernel stack + memset(kstack, 0, kstack_size); + + // set the final return address to be thread_kthread_exit + kstack_top--; + *kstack_top = (unsigned int)exit_func; + + // set the return address to be the start of the first function + kstack_top--; + *kstack_top = (unsigned int)start_func; + + // set the return address to be the start of the entry (thread setup) function + kstack_top--; + *kstack_top = (unsigned int)entry_func; + + // simulate the important registers being pushed + for(i=0; i<7+2+5; i++) { + kstack_top--; + *kstack_top = 0; + } + + // set the address of the function caller function + // that will in turn call all of the above functions + // pushed onto the stack + kstack_top--; + *kstack_top = (unsigned int)sh4_function_caller; + + // save the sp + t->arch_info.sp = kstack_top; + + return 0; +} + +void arch_thread_context_switch(struct thread *t_from, struct thread *t_to) +{ +#if 0 + int i; + dprintf("arch_thread_context_switch: 0x%x->0x%x to sp 0x%x\n", + t_from->id, t_to->id, t_to->arch_info.sp); +#endif +#if 0 + for(i=0; i<8; i++) { + dprintf("sp[%d] = 0x%x\n", i, t_to->arch_info.sp[i]); + } +#endif + sh4_set_kstack(t_to->kernel_stack_base + KSTACK_SIZE); + + if(t_to->proc->aspace != NULL) { + sh4_set_user_pgdir(vm_translation_map_get_pgdir(&t_to->proc->aspace->translation_map)); + } else { + sh4_set_user_pgdir(NULL); + } + sh4_context_switch(&t_from->arch_info.sp, t_to->arch_info.sp); +} + +void arch_thread_dump_info(void *info) +{ + struct arch_thread *at = (struct arch_thread *)info; + dprintf("\tsp: 0x%x\n", at->sp); +} + +void arch_thread_enter_uspace(addr entry, void *args, addr ustack_top) +{ + dprintf("arch_thread_entry_uspace: entry 0x%x, ustack_top 0x%x\n", + entry, ustack_top); + + int_disable_interrupts(); + + sh4_set_kstack(thread_get_current_thread()->kernel_stack_base + KSTACK_SIZE); + + sh4_enter_uspace(entry, args, ustack_top - 4); + // never get to here +} + +void arch_thread_switch_kstack_and_call(struct thread *t, addr new_kstack, void (*func)(void *), void *arg) +{ + sh4_switch_stack_and_call(new_kstack, func, arg); +} + +struct thread *arch_thread_get_current_thread(void) +{ + return curr_thread; +} + +void arch_thread_set_current_thread(struct thread *t) +{ + curr_thread = t; +} + diff --git a/src/kernel/core/arch/sh4/arch_timer.c b/src/kernel/core/arch/sh4/arch_timer.c new file mode 100755 index 0000000000..aa70e0b1d6 --- /dev/null +++ b/src/kernel/core/arch/sh4/arch_timer.c @@ -0,0 +1,147 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include + +#define timer_rate 12500000 +#define max_timer_interval ((bigtime_t)0xffffffff * 1000000 / timer_rate) +#define min_timer_interval ((bigtime_t)0x1000) + +#define SYSTEM_TIME_TIMER_QUANTA 0xffffffff +static const bigtime_t system_time_timer_period = (bigtime_t)SYSTEM_TIME_TIMER_QUANTA * timer_rate / 1000000; +static volatile bigtime_t base_system_time = 0; + +bigtime_t system_time() +{ + bigtime_t outtime; + uint32 timer_val; + int state = int_disable_interrupts(); + +restart: + timer_val = SYSTEM_TIME_TIMER_QUANTA - *(uint32 *)TCNT1; + + if(*(uint16 *)TCR1 & 0x0100) { + // underflow has occurred already + outtime = base_system_time + system_time_timer_period + (bigtime_t)timer_val * 1000000 / timer_rate; + } else { + outtime = base_system_time + (bigtime_t)timer_val * 1000000 / timer_rate; + if(*(uint16 *)TCR1 & 0x0100) { + // an underflow must have happened since we checked last, redo + goto restart; + } + } + + int_restore_interrupts(state); + + return outtime; +} + +static void start_timer(int timer) +{ + uint8 old_val = *(uint8 *)TSTR; + *(uint8 *)TSTR = old_val | (0x1 << timer % 3); +} + +static void stop_timer(int timer) +{ + uint8 old_val = *(uint8 *)TSTR; + *(uint8 *)TSTR = old_val & ~(0x1 << timer %3); +} + +static void setup_timer(int timer, bigtime_t relative_timeout) +{ + uint32 timer_val; + + if(relative_timeout < min_timer_interval) { + timer_val = min_timer_interval * timer_rate / 1000000; + } else if(relative_timeout < max_timer_interval) { + timer_val = relative_timeout * timer_rate / 1000000; + } else { + timer_val = 0xffffffff; + } + + switch(timer) { + case 0: + *(uint16 *)TCR0 = 0x0020; + *(uint32 *)TCNT0 = timer_val; + *(uint32 *)TCOR0 = timer_val; + break; + case 1: + *(uint16 *)TCR1 = 0x0020; + *(uint32 *)TCNT1 = timer_val; + *(uint32 *)TCOR1 = timer_val; + break; + case 2: + *(uint16 *)TCR2 = 0x0020; + *(uint32 *)TCNT2 = timer_val; + *(uint32 *)TCOR2 = timer_val; + break; + default: + break; + } +} + +void arch_timer_set_hardware_timer(bigtime_t timeout) +{ + stop_timer(0); + setup_timer(0, timeout); + start_timer(0); +} + +void arch_timer_clear_hardware_timer() +{ + stop_timer(0); +} + +static int timer_interrupt0() +{ + stop_timer(0); + return timer_interrupt(); +} + +static void setup_system_time_timer() +{ + *(uint16 *)TCR1 = 0x0020; + *(uint32 *)TCNT1 = SYSTEM_TIME_TIMER_QUANTA; + *(uint32 *)TCOR1 = SYSTEM_TIME_TIMER_QUANTA; +} + +static int timer_interrupt1() +{ + base_system_time += system_time_timer_period; + *(uint16 *)TCR1 = 0x0020; // mask out the underflow bit + return INT_NO_RESCHEDULE; +} + +int arch_init_timer(kernel_args *ka) +{ + int i; + uint8 old_val8; + uint16 old_val16; + dprintf("arch_init_timer: entry\n"); + + int_set_io_interrupt_handler(32, &timer_interrupt0, NULL); + int_set_io_interrupt_handler(33, &timer_interrupt1, NULL); + + // stop all of the timers + *(uint8 *)TSTR = 0; + + // enable the interrupt on timer 0 & 1 & disable 2 + old_val16 = *(uint16 *)IPRA; + *(uint16 *)IPRA = (old_val16 & 0x000f) | 0xef00; + + // start timer 1 counting forever + base_system_time = 0; + setup_system_time_timer(); + start_timer(1); + + return 0; +} + diff --git a/src/kernel/core/arch/sh4/arch_vm.c b/src/kernel/core/arch/sh4/arch_vm.c new file mode 100755 index 0000000000..060f84112e --- /dev/null +++ b/src/kernel/core/arch/sh4/arch_vm.c @@ -0,0 +1,33 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include + +int arch_vm_init(kernel_args *ka) +{ + return 0; +} + +int arch_vm_init2(kernel_args *ka) +{ + return 0; +} + +int arch_vm_init_endvm(kernel_args *ka) +{ + + dprintf("arch_vm_init_endvm: entry\n"); + + return 0; +} + +void arch_vm_aspace_swap(vm_address_space *aspace) +{ + sh4_set_user_pgdir(vm_translation_map_get_pgdir(&aspace->translation_map)); +} + diff --git a/src/kernel/core/arch/sh4/arch_vm_translation_map.c b/src/kernel/core/arch/sh4/arch_vm_translation_map.c new file mode 100755 index 0000000000..82fad7541c --- /dev/null +++ b/src/kernel/core/arch/sh4/arch_vm_translation_map.c @@ -0,0 +1,424 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +typedef struct vm_translation_map_arch_info_struct { + addr pgdir_virt; + addr pgdir_phys; + bool is_user; +} vm_translation_map_arch_info; + +static vcpu_struct *vcpu; + +#define CHATTY_TMAP 0 + +#define PHYS_TO_P1(x) ((x) + P1_AREA) + +static void destroy_tmap(vm_translation_map *map) +{ + int state; + vm_translation_map *entry; + vm_translation_map *last = NULL; + + if(map == NULL) + return; + + if(map->arch_data->pgdir_virt != NULL) + kfree((void *)map->arch_data->pgdir_virt); + + kfree(map->arch_data); +} + +static int lock_tmap(vm_translation_map *map) +{ +// dprintf("lock_tmap: map 0x%x\n", map); + if(recursive_lock_lock(&map->lock) == true) { + // we were the first one to grab the lock +// dprintf("clearing invalidated page count\n"); +// map->arch_data->num_invalidate_pages = 0; + } + + return 0;} + +static int unlock_tmap(vm_translation_map *map) +{ + if(recursive_lock_get_recursion(&map->lock) == 1) { + // XXX flush any TLB ents we wanted to + } + recursive_lock_unlock(&map->lock); + return -1; +} + +static int map_tmap(vm_translation_map *map, addr va, addr pa, unsigned int lock) +{ + struct pdent *pd = NULL; + struct ptent *pt; + unsigned int index; + +#if CHATTY_TMAP + dprintf("map_tmap: va 0x%x pa 0x%x lock 0x%x\n", va, pa, lock); +#endif + + if(map->arch_data->is_user) { + if(va >= P1_AREA) { + // invalid + panic("map_tmap: asked to map va 0x%x in user space aspace\n", va); + } + pd = (struct pdent *)map->arch_data->pgdir_phys; + index = va >> 22; + } else { + if(va < P3_AREA && va >= P4_AREA) { + panic("map_tmap: asked to map va 0x%x in kernel space aspace\n", va); + } + pd = (struct pdent *)vcpu->kernel_pgdir; + index = (va & 0x7fffffff) >> 22; + } + + if(pd[index].v == 0) { + vm_page *page; + unsigned int pgtable; + + page = vm_page_allocate_page(PAGE_STATE_CLEAR); + pgtable = page->ppn * PAGE_SIZE; + + // XXX remove when real clear pages support is there + memset((void *)PHYS_TO_P1(pgtable), 0, PAGE_SIZE); + + pd[index].ppn = pgtable >> 12; + pd[index].v = 1; + } + + // get the pagetable + pt = (struct ptent *)PHYS_TO_P1(pd[index].ppn << 12); + index = (va >> 12) & 0x000003ff; + + if(pt[index].v) + panic("map_tmap: va 0x%x already mapped to pa 0x%x\n", va, pt[index].ppn << 12); + + // insert the mapping + pt[index].wt = 0; + pt[index].pr = (lock & LOCK_KERNEL) ? (lock & 0x1) : (lock | 0x2); + pt[index].ppn = pa >> 12; + pt[index].tlb_ent = 0; + pt[index].c = 1; + pt[index].sz = 0x1; // 4k page + pt[index].sh = 0; + pt[index].d = 0; + pt[index].v = 1; + + sh4_invl_page(va); + + return 0; +} + +static int unmap_tmap(vm_translation_map *map, addr start, addr end) +{ + struct pdent *pd; + struct ptent *pt; + unsigned int index; + + start = ROUNDOWN(start, PAGE_SIZE); + end = ROUNDUP(end, PAGE_SIZE); + +#if CHATTY_TMAP + dprintf("unmap_tmap: asked to free pages 0x%x to 0x%x\n", start, end); +#endif + + for(; start < end; start += PAGE_SIZE) { + if(map->arch_data->is_user) { + if(start >= P1_AREA) { + // invalid + panic("unmap_tmap: asked to unmap va 0x%x in user space aspace\n", start); + } + pd = (struct pdent *)map->arch_data->pgdir_phys; + index = start >> 22; + } else { + if(start < P3_AREA && start >= P4_AREA) { + panic("unmap_tmap: asked to unmap va 0x%x in kernel space aspace\n", start); + } + pd = (struct pdent *)vcpu->kernel_pgdir; + index = (start & 0x7fffffff) >> 22; + } + + if(pd[index].v == 0) + continue; + + // get the pagetable + pt = (struct ptent *)PHYS_TO_P1(pd[index].ppn << 12); + index = (start >> 12) & 0x000003ff; + + if(pt[index].v == 0) + continue; + + pt[index].v = 0; + + sh4_invl_page(start); + } + return 0; +} + +static int query_tmap(vm_translation_map *map, addr va, addr *out_physical, unsigned int *out_flags) +{ + struct pdent *pd; + struct ptent *pt; + unsigned int index; + + // default the flags to not present + *out_flags = 0; + *out_physical = 0; + + if(map->arch_data->is_user) { + if(va >= P1_AREA) { + // invalid + return ERR_VM_GENERAL; + } + pd = (struct pdent *)map->arch_data->pgdir_phys; + index = va >> 22; + } else { + if(va < P3_AREA && va >= P4_AREA) { + return ERR_VM_GENERAL; + } + pd = (struct pdent *)vcpu->kernel_pgdir; + index = (va & 0x7fffffff) >> 22; + } + + if(pd[index].v == 0) { + return NO_ERROR; + } + + // get the pagetable + pt = (struct ptent *)PHYS_TO_P1(pd[index].ppn << 12); + index = (va >> 12) & 0x000003ff; + + *out_physical = pt[index].ppn << 12; + + // read in the page state flags, clearing the modified and accessed flags in the process + *out_flags = 0; + *out_flags |= (pt[index].pr & 0x1) ? LOCK_RW : LOCK_RO; + *out_flags |= (pt[index].pr & 0x2) ? 0 : LOCK_KERNEL; + *out_flags |= pt[index].d ? PAGE_MODIFIED : 0; +// *out_flags |= pt[index].accessed ? PAGE_ACCESSED : 0; // not emulating the accessed bit yet + *out_flags |= pt[index].v ? PAGE_PRESENT : 0; + + return 0; +} + +static addr get_mapped_size_tmap(vm_translation_map *map) +{ + return map->map_count; +} + +static int protect_tmap(vm_translation_map *map, addr base, addr top, unsigned int attributes) +{ + // XXX finish + return -1; +} + +static int clear_flags_tmap(vm_translation_map *map, addr va, unsigned int flags) +{ + struct pdent *pd; + struct ptent *pt; + unsigned int index; + int tlb_flush = false; + + if(map->arch_data->is_user) { + if(va >= P1_AREA) { + // invalid + return ERR_VM_GENERAL; + } + pd = (struct pdent *)map->arch_data->pgdir_phys; + index = va >> 22; + } else { + if(va < P3_AREA && va >= P4_AREA) { + return ERR_VM_GENERAL; + } + pd = (struct pdent *)vcpu->kernel_pgdir; + index = (va & 0x7fffffff) >> 22; + } + + if(pd[index].v == 0) { + return NO_ERROR; + } + + // get the pagetable + pt = (struct ptent *)PHYS_TO_P1(pd[index].ppn << 12); + index = (va >> 12) & 0x000003ff; + + // clear out the flags we've been requested to clear + if(flags & PAGE_MODIFIED) { + pt[index].d = 0; + tlb_flush = true; + } + if(flags & PAGE_ACCESSED) { +// pt[index].accessed = 0; +// tlb_flush = true; + } + + if(tlb_flush) + sh4_invl_page(va); + + return 0; +} + +static void flush_tmap(vm_translation_map *map) +{ + // no-op, we aren't caching any tlb invalidations +} + +static int get_physical_page_tmap(addr pa, addr *va, int flags) +{ + if(pa >= PHYS_ADDR_SIZE) + panic("get_physical_page_tmap: passed invalid address 0x%x\n", pa); + *va = PHYS_ADDR_TO_P1(pa); + return NO_ERROR; +} + +static int put_physical_page_tmap(addr va) +{ + if(va < P1_AREA && va >= P2_AREA) + panic("put_physical_page_tmap: bad address passed 0x%x\n", va); + return NO_ERROR; +} + +static vm_translation_map_ops tmap_ops = { + destroy_tmap, + lock_tmap, + unlock_tmap, + map_tmap, + unmap_tmap, + query_tmap, + get_mapped_size_tmap, + protect_tmap, + clear_flags_tmap, + flush_tmap, + get_physical_page_tmap, + put_physical_page_tmap +}; + +int vm_translation_map_create(vm_translation_map *new_map, bool kernel) +{ + if(new_map == NULL) + return -1; + + // initialize the new object + new_map->ops = &tmap_ops; + new_map->map_count = 0; + if(recursive_lock_create(&new_map->lock) < 0) + return ERR_NO_MEMORY; + + new_map->arch_data = kmalloc(sizeof(vm_translation_map_arch_info)); + if(new_map == NULL) + panic("error allocating translation map object!\n"); + + if(!kernel) { + // user + // allocate a pgdir + new_map->arch_data->pgdir_virt = (addr)kmalloc(PAGE_SIZE); + if(new_map->arch_data->pgdir_virt == NULL) { + kfree(new_map->arch_data); + return -1; + } + if(((addr)new_map->arch_data->pgdir_virt % PAGE_SIZE) != 0) + panic("vm_translation_map_create: malloced pgdir and found it wasn't aligned!\n"); + vm_get_page_mapping(vm_get_kernel_aspace_id(), (addr)new_map->arch_data->pgdir_virt, (addr *)&new_map->arch_data->pgdir_phys); + new_map->arch_data->pgdir_phys = PHYS_TO_P1(new_map->arch_data->pgdir_phys); + // zero out the new pgdir + memset((void *)new_map->arch_data->pgdir_virt, 0, PAGE_SIZE); + new_map->arch_data->is_user = true; + } else { + // kernel + // we already know the kernel pgdir mapping + (addr)new_map->arch_data->pgdir_virt = NULL; + (addr)new_map->arch_data->pgdir_phys = vcpu->kernel_pgdir; + new_map->arch_data->is_user = false; + } + + return 0; +} + +int vm_translation_map_module_init(kernel_args *ka) +{ + vcpu = ka->arch_args.vcpu; + + return 0; +} + +int vm_translation_map_module_init2(kernel_args *ka) +{ + return 0; +} + +void vm_translation_map_module_init_post_sem(kernel_args *ka) +{ +} + +// XXX horrible back door to map a page quickly regardless of translation map object, etc. +// used only during VM setup +int vm_translation_map_quick_map(kernel_args *ka, addr va, addr pa, unsigned int lock, addr (*get_free_page)(kernel_args *)) +{ + struct pdent *pd = NULL; + struct ptent *pt; + unsigned int index; + +#if CHATTY_TMAP + dprintf("quick_tmap: va 0x%x pa 0x%x lock 0x%x\n", va, pa, lock); +#endif + + if(va < P3_AREA && va >= P4_AREA) { + panic("quick_tmap: asked to map invalid va 0x%x\n", va); + } + pd = (struct pdent *)vcpu->kernel_pgdir; + index = (va & 0x7fffffff) >> 22; + + if(pd[index].v == 0) { + vm_page *page; + unsigned int pgtable; + + pgtable = (*get_free_page)(ka) * PAGE_SIZE; + + memset((void *)PHYS_TO_P1(pgtable), 0, PAGE_SIZE); + + pd[index].ppn = pgtable >> 12; + pd[index].v = 1; + } + + // get the pagetable + pt = (struct ptent *)PHYS_TO_P1(pd[index].ppn << 12); + index = (va >> 12) & 0x000003ff; + + // insert the mapping + pt[index].wt = 0; + pt[index].pr = (lock & LOCK_KERNEL) ? (lock & 0x1) : (lock | 0x2); + pt[index].ppn = pa >> 12; + pt[index].tlb_ent = 0; + pt[index].c = 1; + pt[index].sz = 0x1; // 4k page + pt[index].sh = 0; + pt[index].d = 0; + pt[index].v = 1; + + sh4_invl_page(va); + + return 0; +} + +addr vm_translation_map_get_pgdir(vm_translation_map *map) +{ + return (addr)map->arch_data->pgdir_phys; +} diff --git a/src/kernel/core/arch/sh4/kernel.ld b/src/kernel/core/arch/sh4/kernel.ld new file mode 100755 index 0000000000..a375510f58 --- /dev/null +++ b/src/kernel/core/arch/sh4/kernel.ld @@ -0,0 +1,69 @@ +OUTPUT_FORMAT("elf32-shl", "elf32-shl", "elf32-shl") +OUTPUT_ARCH(sh) + +ENTRY(__start) +SEARCH_DIR("libgcc"); +SECTIONS +{ + . = 0xc0000000 + SIZEOF_HEADERS; + + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0x9090 + .plt : { *(.plt) } + + /* text/read-only data */ + .text : { *(.text .gnu.linkonce.t.*) } =0x9090 + + .rodata : + { + *(.rodata) + . = ALIGN(0x1000); + } =0x9000 + + /* writable data */ + . = ALIGN(0x1000); + ___data_start = .; + .data : { *(.data .gnu.linkonce.d.*) } + + ___ctor_list = .; + .ctors : { *(.ctors) } + ___ctor_end = .; + ___dtor_list = .; + .dtors : { *(.dtors) } + ___dtor_end = .; + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + + /* unintialized data (in same segment as writable data) */ + ___bss_start = .; + .bss : { *(.bss) } + + . = ALIGN(0x1000); + _end = . ; + + /* Strip unnecessary stuff */ + /DISCARD/ : { *(.comment .note .eh_frame) } +} diff --git a/src/kernel/core/arch/sparc/arch_kernel.mk b/src/kernel/core/arch/sparc/arch_kernel.mk new file mode 100755 index 0000000000..b67e33c90e --- /dev/null +++ b/src/kernel/core/arch/sparc/arch_kernel.mk @@ -0,0 +1,24 @@ +# sparc kernel makefile +# included from kernel.mk +KERNEL_ARCH_OBJ_DIR = $(KERNEL_ARCH_DIR)/$(OBJ_DIR) +KERNEL_OBJS += \ + +KERNEL_ARCH_INCLUDES = $(KERNEL_INCLUDES) + +$(KERNEL_ARCH_OBJ_DIR)/%.o: $(KERNEL_ARCH_DIR)/%.c + @mkdir -p $(KERNEL_ARCH_OBJ_DIR) + $(CC) -c $< $(GLOBAL_CFLAGS) $(KERNEL_ARCH_INCLUDES) -o $@ + +$(KERNEL_ARCH_OBJ_DIR)/%.d: $(KERNEL_ARCH_DIR)/%.c + @mkdir -p $(KERNEL_ARCH_OBJ_DIR) + @echo "making deps for $<..." + @(echo -n $(dir $@); $(CC) $(GLOBAL_CFLAGS) $(KERNEL_ARCH_INCLUDES) -M -MG $<) > $@ + +$(KERNEL_ARCH_OBJ_DIR)/%.d: $(KERNEL_ARCH_DIR)/%.S + @mkdir -p $(KERNEL_ARCH_OBJ_DIR) + @echo "making deps for $<..." + @(echo -n $(dir $@);$(CC) $(GLOBAL_CFLAGS) $(KERNEL_ARCH_INCLUDES) -M -MG $<) > $@ + +$(KERNEL_ARCH_OBJ_DIR)/%.o: $(KERNEL_ARCH_DIR)/%.S + @mkdir -p $(KERNEL_ARCH_OBJ_DIR) + $(CC) -c $< $(GLOBAL_CFLAGS) $(KERNEL_ARCH_INCLUDES) -o $@ diff --git a/src/kernel/core/arch/sparc64/arch_kernel.mk b/src/kernel/core/arch/sparc64/arch_kernel.mk new file mode 100755 index 0000000000..2819f3c308 --- /dev/null +++ b/src/kernel/core/arch/sparc64/arch_kernel.mk @@ -0,0 +1,24 @@ +# sparc64 kernel makefile +# included from kernel.mk +KERNEL_ARCH_OBJ_DIR = $(KERNEL_ARCH_DIR)/$(OBJ_DIR) +KERNEL_OBJS += \ + +KERNEL_ARCH_INCLUDES = $(KERNEL_INCLUDES) + +$(KERNEL_ARCH_OBJ_DIR)/%.o: $(KERNEL_ARCH_DIR)/%.c + @mkdir -p $(KERNEL_ARCH_OBJ_DIR) + $(CC) -c $< $(GLOBAL_CFLAGS) $(KERNEL_ARCH_INCLUDES) -o $@ + +$(KERNEL_ARCH_OBJ_DIR)/%.d: $(KERNEL_ARCH_DIR)/%.c + @mkdir -p $(KERNEL_ARCH_OBJ_DIR) + @echo "making deps for $<..." + @($(ECHO) -n $(dir $@); $(CC) $(GLOBAL_CFLAGS) $(KERNEL_ARCH_INCLUDES) -M -MG $<) > $@ + +$(KERNEL_ARCH_OBJ_DIR)/%.d: $(KERNEL_ARCH_DIR)/%.S + @mkdir -p $(KERNEL_ARCH_OBJ_DIR) + @echo "making deps for $<..." + @($(ECHO) -n $(dir $@);$(CC) $(GLOBAL_CFLAGS) $(KERNEL_ARCH_INCLUDES) -M -MG $<) > $@ + +$(KERNEL_ARCH_OBJ_DIR)/%.o: $(KERNEL_ARCH_DIR)/%.S + @mkdir -p $(KERNEL_ARCH_OBJ_DIR) + $(CC) -c $< $(GLOBAL_CFLAGS) $(KERNEL_ARCH_INCLUDES) -o $@ diff --git a/src/kernel/core/arch/x86/Jamfile b/src/kernel/core/arch/x86/Jamfile new file mode 100644 index 0000000000..c2f0bd16bb --- /dev/null +++ b/src/kernel/core/arch/x86/Jamfile @@ -0,0 +1,18 @@ +SubDir OBOS_TOP sources os kits kernel core arch x86 ; + +KernelStaticLibrary libx86 : + <$(SOURCE_GRIST)>arch_cpu.c + <$(SOURCE_GRIST)>arch_dbg_console.c + <$(SOURCE_GRIST)>arch_debug.c + <$(SOURCE_GRIST)>arch_faults.c + <$(SOURCE_GRIST)>arch_int.c + <$(SOURCE_GRIST)>arch_smp.c + <$(SOURCE_GRIST)>arch_thread.c + <$(SOURCE_GRIST)>arch_timer.c + <$(SOURCE_GRIST)>arch_vm.c + <$(SOURCE_GRIST)>arch_vm_translation_map.c + <$(SOURCE_GRIST)>arch_x86.S + <$(SOURCE_GRIST)>arch_interrupts.S + : + -fno-pic -Wno-unused + ; diff --git a/src/kernel/core/arch/x86/addon.ld b/src/kernel/core/arch/x86/addon.ld new file mode 100755 index 0000000000..6e85ced1b8 --- /dev/null +++ b/src/kernel/core/arch/x86/addon.ld @@ -0,0 +1,65 @@ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) + +ENTRY(_start) +SEARCH_DIR("libgcc"); +SECTIONS +{ + . = 0x00000000 + SIZEOF_HEADERS; + + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0x9090 + .plt : { *(.plt) } + + /* text/read-only data */ + .text : { *(.text .gnu.linkonce.t.*) } =0x9090 + + .rodata : { *(.rodata) } + + /* writable data */ + . = ALIGN(0x1000) + (. & (0x1000 - 1)); + __data_start = .; + .data : { *(.data .gnu.linkonce.d.*) } + + __ctor_list = .; + .ctors : { *(.ctors) } + __ctor_end = .; + __dtor_list = .; + .dtors : { *(.dtors) } + __dtor_end = .; + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + + /* unintialized data (in same segment as writable data) */ + __bss_start = .; + .bss : { *(.bss) } + + . = ALIGN(0x1000); + _end = . ; + + /* Strip unnecessary stuff */ + /DISCARD/ : { *(.comment .note .eh_frame) } +} diff --git a/src/kernel/core/arch/x86/arch_cpu.c b/src/kernel/core/arch/x86/arch_cpu.c new file mode 100755 index 0000000000..089b2bab33 --- /dev/null +++ b/src/kernel/core/arch/x86/arch_cpu.c @@ -0,0 +1,188 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +static struct tss **tss; +static int *tss_loaded; + +static unsigned int *gdt = 0; + +int arch_cpu_preboot_init(kernel_args *ka) +{ + write_dr3(0); + return 0; +} + +int arch_cpu_init(kernel_args *ka) +{ + setup_system_time(ka->arch_args.system_time_cv_factor); + + return 0; +} + +int arch_cpu_init2(kernel_args *ka) +{ + region_id rid; + struct tss_descriptor *tss_d; + unsigned int i; + + // account for the segment descriptors + gdt = (unsigned int *)ka->arch_args.vir_gdt; + vm_create_anonymous_region(vm_get_kernel_aspace_id(), "gdt", (void **)&gdt, + REGION_ADDR_EXACT_ADDRESS, PAGE_SIZE, REGION_WIRING_WIRED_ALREADY, LOCK_RW|LOCK_KERNEL); + + tss = kmalloc(sizeof(struct tss *) * ka->num_cpus); + if(tss == NULL) { + panic("arch_cpu_init2: could not allocate buffer for tss pointers\n"); + return ERR_NO_MEMORY; + } + + tss_loaded = kmalloc(sizeof(int) * ka->num_cpus); + if(tss == NULL) { + panic("arch_cpu_init2: could not allocate buffer for tss booleans\n"); + return ERR_NO_MEMORY; + } + memset(tss_loaded, 0, sizeof(int) * ka->num_cpus); + + for(i=0; inum_cpus; i++) { + char tss_name[16]; + + sprintf(tss_name, "tss%d", i); + rid = vm_create_anonymous_region(vm_get_kernel_aspace_id(), tss_name, (void **)&tss[i], + REGION_ADDR_ANY_ADDRESS, PAGE_SIZE, REGION_WIRING_WIRED, LOCK_RW|LOCK_KERNEL); + if(rid < 0) { + panic("arch_cpu_init2: unable to create region for tss\n"); + return ERR_NO_MEMORY; + } + + memset(tss[i], 0, sizeof(struct tss)); + tss[i]->ss0 = KERNEL_DATA_SEG; + + // add TSS descriptor for this new TSS + tss_d = (struct tss_descriptor *)&gdt[10 + i*2]; + tss_d->limit_00_15 = sizeof(struct tss) & 0xffff; + tss_d->limit_19_16 = 0; // not this long + tss_d->base_00_15 = (addr)tss[i] & 0xffff; + tss_d->base_23_16 = ((addr)tss[i] >> 16) & 0xff; + tss_d->base_31_24 = (addr)tss[i] >> 24; + tss_d->type = 0x9; + tss_d->zero = 0; + tss_d->dpl = 0; + tss_d->present = 1; + tss_d->avail = 0; + tss_d->zero1 = 0; + tss_d->zero2 = 1; + tss_d->granularity = 1; + } + return 0; +} + +void i386_set_kstack(addr kstack) +{ + int curr_cpu = smp_get_current_cpu(); + +// dprintf("i386_set_kstack: kstack 0x%x, cpu %d\n", kstack, curr_cpu); + if(tss_loaded[curr_cpu] == 0) { + short seg = (0x28 + 8*curr_cpu); + asm("movw %0, %%ax;" + "ltr %%ax;" : : "r" (seg) : "eax"); + tss_loaded[curr_cpu] = 1; + } + + tss[curr_cpu]->sp0 = kstack; +// dprintf("done\n"); +} + +void arch_cpu_invalidate_TLB_range(addr start, addr end) +{ + for(; start < end; start += PAGE_SIZE) { + invalidate_TLB(start); + } +} + +void arch_cpu_invalidate_TLB_list(addr pages[], int num_pages) +{ + int i; + for(i=0; i +*/ +#include +#include +#include +#include + +#include + +#include + +#define BOCHS_E9_HACK 0 + +// Select between COM1 and COM2 for debug output +#define USE_COM1 1 + +static const int dbg_baud_rate = 115200; + +int arch_dbg_con_init(kernel_args *ka) +{ + short divisor = 115200 / dbg_baud_rate; + +#if USE_COM1 + out8(0x80, 0x3fb); /* set up to load divisor latch */ + out8(divisor & 0xf, 0x3f8); /* LSB */ + out8(divisor >> 8, 0x3f9); /* MSB */ + out8(3, 0x3fb); /* 8N1 */ +#else // COM2 + out8(0x80, 0x2fb); /* set up to load divisor latch */ + out8(divisor & 0xf, 0x2f8); /* LSB */ + out8(divisor >> 8, 0x2f9); /* MSB */ + out8(3, 0x2fb); /* 8N1 */ +#endif + + return 0; +} + +char arch_dbg_con_read(void) +{ +#if USE_COM1 + while ((in8(0x3fd) & 1) == 0) + ; + return in8(0x3f8); +#else + while ((in8(0x2fd) & 1) == 0) + ; + return in8(0x2f8); +#endif +} + +static void _arch_dbg_con_putch(const char c) +{ +#if BOCHS_E9_HACK + out8(c, 0xe9); +#else + +#if USE_COM1 + while ((in8(0x3fd) & 0x20) == 0) + ; + out8(c, 0x3f8); +#else // COM2 + while ((in8(0x2fd) & 0x20) == 0) + ; + out8(c, 0x2f8); +#endif + +#endif +} + +char arch_dbg_con_putch(const char c) +{ + if (c == '\n') { + _arch_dbg_con_putch('\r'); + _arch_dbg_con_putch('\n'); + } else if (c != '\r') + _arch_dbg_con_putch(c); + + return c; +} + +void arch_dbg_con_puts(const char *s) +{ + while(*s != '\0') { + arch_dbg_con_putch(*s); + s++; + } +} + diff --git a/src/kernel/core/arch/x86/arch_debug.c b/src/kernel/core/arch/x86/arch_debug.c new file mode 100755 index 0000000000..218995e243 --- /dev/null +++ b/src/kernel/core/arch/x86/arch_debug.c @@ -0,0 +1,9 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include + +// XXX will put stack trace and disassembly routines here diff --git a/src/kernel/core/arch/x86/arch_faults.c b/src/kernel/core/arch/x86/arch_faults.c new file mode 100755 index 0000000000..4ebb0c61ae --- /dev/null +++ b/src/kernel/core/arch/x86/arch_faults.c @@ -0,0 +1,43 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include + +// XXX this module is largely outdated. Will probably be removed later. + +int arch_faults_init(kernel_args *ka) +{ + return 0; +} + +int i386_general_protection_fault(int errorcode) +{ + return general_protection_fault(errorcode); +} + +int i386_double_fault(int errorcode) +{ + kprintf("double fault! errorcode = 0x%x\n", errorcode); + dprintf("double fault! errorcode = 0x%x\n", errorcode); + for(;;); + return INT_NO_RESCHEDULE; +} + diff --git a/src/kernel/core/arch/x86/arch_int.c b/src/kernel/core/arch/x86/arch_int.c new file mode 100755 index 0000000000..b6b268dce8 --- /dev/null +++ b/src/kernel/core/arch/x86/arch_int.c @@ -0,0 +1,326 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#define MAX_ARGS 16 + +struct int_frame { + unsigned int gs; + unsigned int fs; + unsigned int es; + unsigned int ds; + unsigned int edi; + unsigned int esi; + unsigned int ebp; + unsigned int esp; + unsigned int ebx; + unsigned int edx; + unsigned int ecx; + unsigned int eax; + unsigned int vector; + unsigned int error_code; + unsigned int eip; + unsigned int cs; + unsigned int flags; + unsigned int user_esp; + unsigned int user_ss; +}; + +static desc_table *idt = NULL; + +static void interrupt_ack(int n) +{ + if(n >= 0x20 && n < 0x30) { + // 8239 controlled interrupt + if(n > 0x27) + out8(0x20, 0xa0); // EOI to pic 2 + out8(0x20, 0x20); // EOI to pic 1 + } +} + +static void _set_gate(desc_table *gate_addr, unsigned int addr, int type, int dpl) +{ + unsigned int gate1; // first byte of gate desc + unsigned int gate2; // second byte of gate desc + + gate1 = (KERNEL_CODE_SEG << 16) | (0x0000ffff & addr); + gate2 = (0xffff0000 & addr) | 0x8000 | (dpl << 13) | (type << 8); + + gate_addr->a = gate1; + gate_addr->b = gate2; +} + +void arch_int_enable_io_interrupt(int irq) +{ + if(irq < 0x20 || irq >= 0x30) return; + irq -= 0x20; + // if this is a external interrupt via 8239, enable it here + if (irq < 8) + out8(in8(0x21) & ~(1 << irq), 0x21); + else + out8(in8(0xa1) & ~(1 << (irq - 8)), 0xa1); +} + +void arch_int_disable_io_interrupt(int irq) +{ + if(irq < 0x20 || irq >= 0x30) return; + irq -= 0x20; + // if this is a external interrupt via 8239, disable it here + if (irq < 8) + out8(in8(0x21) | (1 << irq), 0x21); + else + out8(in8(0xa1) | (1 << (irq - 8)), 0xa1); +} + +static void set_intr_gate(int n, void *addr) +{ + _set_gate(&idt[n], (unsigned int)addr, 14, 0); +} + +/* XXX - currently unused and static... +static void set_trap_gate(int n, void *addr) +{ + _set_gate(&idt[n], (unsigned int)addr, 15, 0); +} +*/ + +static void set_system_gate(int n, void *addr) +{ + _set_gate(&idt[n], (unsigned int)addr, 15, 3); +} + +void arch_int_enable_interrupts(void) +{ + asm("sti"); +} + +int arch_int_disable_interrupts(void) +{ + int flags; + + asm("pushfl;\n" + "popl %0;\n" + "cli" : "=g" (flags)); + return flags & 0x200 ? 1 : 0; +} + +void arch_int_restore_interrupts(int oldstate) +{ + int flags = oldstate ? 0x200 : 0; + + asm ( + "pushfl;\n" + "popl %1;\n" + "andl $0xfffffdff,%1;\n" + "orl %0,%1;\n" + "pushl %1;\n" + "popfl\n" + : : "r" (flags), "r" (0)); +} + +bool arch_int_is_interrupts_enabled(void) +{ + int flags; + + asm("pushfl;\n" + "popl %0;\n" : "=g" (flags)); + return flags & 0x200 ? 1 : 0; +} + +void i386_handle_trap(struct int_frame frame); /* keep the compiler happy, this function must be called only from assembly */ +void i386_handle_trap(struct int_frame frame) +{ + int ret = INT_NO_RESCHEDULE; + +// if(frame.vector != 0x20) +// dprintf("i386_handle_trap: vector 0x%x, ip 0x%x, cpu %d\n", frame.vector, frame.eip, smp_get_current_cpu()); + switch(frame.vector) { + case 8: + ret = i386_double_fault(frame.error_code); + break; + case 13: + ret = i386_general_protection_fault(frame.error_code); + break; + case 14: { + unsigned int cr2; + addr newip; + + asm ("movl %%cr2, %0" : "=r" (cr2) ); + + // get the old interrupt enable/disable state and restore to that + if(frame.flags & 0x200) { +// dprintf("page_fault: enabling interrupts\n"); + int_enable_interrupts(); + } + ret = vm_page_fault(cr2, frame.eip, + (frame.error_code & 0x2) != 0, + (frame.error_code & 0x4) != 0, + &newip); + if(newip != 0) { + // the page fault handler wants us to modify the iframe to set the + // IP the cpu will return to to be this ip + frame.eip = newip; + } + break; + } + case 99: { + uint64 retcode; + unsigned int args[MAX_ARGS]; + int rc; + + thread_atkernel_entry(); +#if 0 +{ + int i; + dprintf("i386_handle_trap: syscall %d, count %d, ptr 0x%x\n", frame.eax, frame.ecx, frame.edx); + dprintf(" call stack:\n"); + for(i=0; i= KERNEL_BASE && (addr)frame.edx <= KERNEL_TOP) { + retcode = ERR_VM_BAD_USER_MEMORY; + } else { + rc = user_memcpy(args, (void *)frame.edx, frame.ecx * sizeof(unsigned int)); + if(rc < 0) + retcode = ERR_VM_BAD_USER_MEMORY; + else + ret = syscall_dispatcher(frame.eax, (void *)args, &retcode); + } + } else { + // want to pass too many args into the system + retcode = ERR_INVALID_ARGS; + } + frame.eax = retcode & 0xffffffff; + frame.edx = retcode >> 32; + break; + } + default: + if(frame.vector >= 0x20) { + interrupt_ack(frame.vector); // ack the 8239 (if applicable) + ret = int_io_interrupt_handler(frame.vector); + } else { + panic("i386_handle_trap: unhandled cpu trap 0x%x at ip 0x%x!\n", frame.vector, frame.eip); + ret = INT_NO_RESCHEDULE; + } + break; + } + + if(ret == INT_RESCHEDULE) { + int state = int_disable_interrupts(); + GRAB_THREAD_LOCK(); + thread_resched(); + RELEASE_THREAD_LOCK(); + int_restore_interrupts(state); + } + + if(frame.cs == USER_CODE_SEG || frame.vector == 99) { + thread_atkernel_exit(); + } +// dprintf("0x%x cpu %d!\n", thread_get_current_thread_id(), smp_get_current_cpu()); +} + +int arch_int_init(kernel_args *ka) +{ + idt = (desc_table *)ka->arch_args.vir_idt; + + // setup the interrupt controller + out8(0x11, 0x20); // Start initialization sequence for #1. + out8(0x11, 0xa0); // ...and #2. + out8(0x20, 0x21); // Set start of interrupts for #1 (0x20). + out8(0x28, 0xa1); // Set start of interrupts for #2 (0x28). + out8(0x04, 0x21); // Set #1 to be the master. + out8(0x02, 0xa1); // Set #2 to be the slave. + out8(0x01, 0x21); // Set both to operate in 8086 mode. + out8(0x01, 0xa1); + out8(0xfb, 0x21); // Mask off all interrupts (except slave pic line). + out8(0xff, 0xa1); // Mask off interrupts on the slave. + + set_intr_gate(0, &trap0); + set_intr_gate(1, &trap1); + set_intr_gate(2, &trap2); + set_intr_gate(3, &trap3); + set_intr_gate(4, &trap4); + set_intr_gate(5, &trap5); + set_intr_gate(6, &trap6); + set_intr_gate(7, &trap7); + set_intr_gate(8, &trap8); + set_intr_gate(9, &trap9); + set_intr_gate(10, &trap10); + set_intr_gate(11, &trap11); + set_intr_gate(12, &trap12); + set_intr_gate(13, &trap13); + set_intr_gate(14, &trap14); +// set_intr_gate(15, &trap15); + set_intr_gate(16, &trap16); + set_intr_gate(17, &trap17); + set_intr_gate(18, &trap18); + + set_intr_gate(32, &trap32); + set_intr_gate(33, &trap33); + set_intr_gate(34, &trap34); + set_intr_gate(35, &trap35); + set_intr_gate(36, &trap36); + set_intr_gate(37, &trap37); + set_intr_gate(38, &trap38); + set_intr_gate(39, &trap39); + set_intr_gate(40, &trap40); + set_intr_gate(41, &trap41); + set_intr_gate(42, &trap42); + set_intr_gate(43, &trap43); + set_intr_gate(44, &trap44); + set_intr_gate(45, &trap45); + set_intr_gate(46, &trap46); + set_intr_gate(47, &trap47); + + set_system_gate(99, &trap99); + + set_intr_gate(251, &trap251); + set_intr_gate(252, &trap252); + set_intr_gate(253, &trap253); + set_intr_gate(254, &trap254); + set_intr_gate(255, &trap255); + + return 0; +} + +int arch_int_init2(kernel_args *ka) +{ + idt = (desc_table *)ka->arch_args.vir_idt; + vm_create_anonymous_region(vm_get_kernel_aspace_id(), "idt", (void *)&idt, + REGION_ADDR_EXACT_ADDRESS, PAGE_SIZE, REGION_WIRING_WIRED_ALREADY, LOCK_RW|LOCK_KERNEL); + return 0; +} diff --git a/src/kernel/core/arch/x86/arch_interrupts.S b/src/kernel/core/arch/x86/arch_interrupts.S new file mode 100755 index 0000000000..5cbe6da4d8 --- /dev/null +++ b/src/kernel/core/arch/x86/arch_interrupts.S @@ -0,0 +1,85 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +.text + +#define TRAP_ERRC(name, vector) \ +.globl name; \ +.align 8; \ +name: \ + pushl $vector; \ + jmp int_bottom + +#define TRAP(name, vector) \ +.globl name; \ +.align 8; \ +name: \ + pushl $0; \ + pushl $vector; \ + jmp int_bottom + +TRAP(trap0, 0) +TRAP(trap1, 1) +TRAP(trap2, 2) +TRAP(trap3, 3) +TRAP(trap4, 4) +TRAP(trap5, 5) +TRAP(trap6, 6) +TRAP(trap7, 7) +TRAP_ERRC(trap8, 8) +TRAP(trap9, 9) +TRAP_ERRC(trap10, 10) +TRAP_ERRC(trap11, 11) +TRAP_ERRC(trap12, 12) +TRAP_ERRC(trap13, 13) +TRAP_ERRC(trap14, 14) +/*TRAP(trap15, 15)*/ +TRAP(trap16, 16) +TRAP_ERRC(trap17, 17) +TRAP(trap18, 18) + +TRAP(trap32, 32) +TRAP(trap33, 33) +TRAP(trap34, 34) +TRAP(trap35, 35) +TRAP(trap36, 36) +TRAP(trap37, 37) +TRAP(trap38, 38) +TRAP(trap39, 39) +TRAP(trap40, 40) +TRAP(trap41, 41) +TRAP(trap42, 42) +TRAP(trap43, 43) +TRAP(trap44, 44) +TRAP(trap45, 45) +TRAP(trap46, 46) +TRAP(trap47, 47) + +TRAP(trap99, 99) + +TRAP(trap251, 251) +TRAP(trap252, 252) +TRAP(trap253, 253) +TRAP(trap254, 254) +TRAP(trap255, 255) + +.align 8 +.globl int_bottom +int_bottom: + pusha + push %ds + push %es + push %fs + push %gs + movw $0x10,%ax + movw %ax,%ds + cld + call i386_handle_trap + pop %gs + pop %fs + pop %es + pop %ds + popa + addl $8,%esp + iret diff --git a/src/kernel/core/arch/x86/arch_smp.c b/src/kernel/core/arch/x86/arch_smp.c new file mode 100755 index 0000000000..f0c90f2772 --- /dev/null +++ b/src/kernel/core/arch/x86/arch_smp.c @@ -0,0 +1,192 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +static int num_cpus = 1; +static unsigned int *apic = NULL; +static unsigned int cpu_apic_id[SMP_MAX_CPUS] = { 0, 0}; +static unsigned int cpu_os_id[SMP_MAX_CPUS] = { 0, 0}; +static unsigned int cpu_apic_version[SMP_MAX_CPUS] = { 0, 0}; +static unsigned int *ioapic = NULL; +static unsigned int apic_timer_tics_per_sec = 0; + +static int i386_timer_interrupt(void* data) +{ + arch_smp_ack_interrupt(); + + return apic_timer_interrupt(); +} + +static int i386_ici_interrupt(void* data) +{ + // gin-u-wine inter-cpu interrupt +// dprintf("inter-cpu interrupt on cpu %d\n", arch_smp_get_current_cpu()); + arch_smp_ack_interrupt(); + + return smp_intercpu_int_handler(); +} + +static int i386_spurious_interrupt(void* data) +{ + // spurious interrupt +// dprintf("spurious interrupt on cpu %d\n", arch_smp_get_current_cpu()); + arch_smp_ack_interrupt(); + return INT_NO_RESCHEDULE; +} + +static int i386_smp_error_interrupt(void* data) +{ + // smp error interrupt +// dprintf("smp error interrupt on cpu %d\n", arch_smp_get_current_cpu()); + arch_smp_ack_interrupt(); + return INT_NO_RESCHEDULE; +} + +static unsigned int apic_read(unsigned int *addr) +{ + return *addr; +} + +static void apic_write(unsigned int *addr, unsigned int data) +{ + *addr = data; +} + +int arch_smp_init(kernel_args *ka) +{ + dprintf("arch_smp_init: entry\n"); + + if(ka->num_cpus > 1) { + // setup some globals + num_cpus = ka->num_cpus; + apic = ka->arch_args.apic; + ioapic = ka->arch_args.ioapic; + memcpy(cpu_apic_id, ka->arch_args.cpu_apic_id, sizeof(ka->arch_args.cpu_apic_id)); + memcpy(cpu_os_id, ka->arch_args.cpu_os_id, sizeof(ka->arch_args.cpu_os_id)); + memcpy(cpu_apic_version, ka->arch_args.cpu_apic_version, sizeof(ka->arch_args.cpu_apic_version)); + apic_timer_tics_per_sec = ka->arch_args.apic_time_cv_factor; + + // setup regions that represent the apic & ioapic + vm_create_anonymous_region(vm_get_kernel_aspace_id(), "local_apic", (void *)&apic, + REGION_ADDR_EXACT_ADDRESS, PAGE_SIZE, REGION_WIRING_WIRED_ALREADY, LOCK_RW|LOCK_KERNEL); + vm_create_anonymous_region(vm_get_kernel_aspace_id(), "ioapic", (void *)&ioapic, + REGION_ADDR_EXACT_ADDRESS, PAGE_SIZE, REGION_WIRING_WIRED_ALREADY, LOCK_RW|LOCK_KERNEL); + + int_set_io_interrupt_handler(0xfb, &i386_timer_interrupt, NULL); + int_set_io_interrupt_handler(0xfd, &i386_ici_interrupt, NULL); + int_set_io_interrupt_handler(0xfe, &i386_smp_error_interrupt, NULL); + int_set_io_interrupt_handler(0xff, &i386_spurious_interrupt, NULL); + } else { + num_cpus = 1; + } + return 0; +} + +void arch_smp_send_broadcast_ici(void) +{ + int config; + int state; + + state = int_disable_interrupts(); + + config = apic_read(APIC_ICR1) & APIC_ICR1_WRITE_MASK; + apic_write(APIC_ICR1, config | 0xfd | APIC_ICR1_DELMODE_FIXED | APIC_ICR1_DESTMODE_PHYS | APIC_ICR1_DEST_ALL_BUT_SELF); + + int_restore_interrupts(state); +} + +void arch_smp_send_ici(int target_cpu) +{ + int config; + int state; + + state = int_disable_interrupts(); + + config = apic_read(APIC_ICR2) & APIC_ICR2_MASK; + apic_write(APIC_ICR2, config | cpu_apic_id[target_cpu] << 24); + + config = apic_read(APIC_ICR1) & APIC_ICR1_WRITE_MASK; + apic_write(APIC_ICR1, config | 0xfd | APIC_ICR1_DELMODE_FIXED | APIC_ICR1_DESTMODE_PHYS | APIC_ICR1_DEST_FIELD); + + int_restore_interrupts(state); +} + +void arch_smp_ack_interrupt(void) +{ + apic_write(APIC_EOI, 0); +} + +#define MIN_TIMEOUT 1000 + +int arch_smp_set_apic_timer(bigtime_t relative_timeout) +{ + unsigned int config; + int state; + unsigned int ticks; + + if(apic == NULL) + return -1; + + if(relative_timeout < MIN_TIMEOUT) + relative_timeout = MIN_TIMEOUT; + + // calculation should be ok, since it's going to be 64-bit + ticks = ((relative_timeout * apic_timer_tics_per_sec) / 1000000); + + state = int_disable_interrupts(); + + config = apic_read(APIC_LVTT) | APIC_LVTT_M; // mask the timer + apic_write(APIC_LVTT, config); + + apic_write(APIC_ICRT, 0); // zero out the timer + + config = apic_read(APIC_LVTT) & ~APIC_LVTT_M; // unmask the timer + apic_write(APIC_LVTT, config); + + apic_write(APIC_ICRT, ticks); // start it up + + int_restore_interrupts(state); + + return 0; +} + +int arch_smp_clear_apic_timer(void) +{ + unsigned int config; + int state; + + if(apic == NULL) + return -1; + + state = int_disable_interrupts(); + + config = apic_read(APIC_LVTT) | APIC_LVTT_M; // mask the timer + apic_write(APIC_LVTT, config); + + apic_write(APIC_ICRT, 0); // zero out the timer + + int_restore_interrupts(state); + + return 0; +} + diff --git a/src/kernel/core/arch/x86/arch_thread.c b/src/kernel/core/arch/x86/arch_thread.c new file mode 100755 index 0000000000..154cd08151 --- /dev/null +++ b/src/kernel/core/arch/x86/arch_thread.c @@ -0,0 +1,156 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int arch_proc_init_proc_struct(struct proc *p, bool kernel) +{ + return 0; +} + +int arch_thread_init_thread_struct(struct thread *t) +{ + t->arch_info.esp = NULL; + + // set up an initial fpu state + memset(&t->arch_info.fpu_state[0], 0, sizeof(t->arch_info.fpu_state)); + + return 0; +} + +int arch_thread_initialize_kthread_stack(struct thread *t, int (*start_func)(void), void (*entry_func)(void), void (*exit_func)(void)) +{ + unsigned int *kstack = (unsigned int *)t->kernel_stack_base; + unsigned int kstack_size = KSTACK_SIZE; + unsigned int *kstack_top = kstack + kstack_size / sizeof(unsigned int); + int i; + +// dprintf("arch_thread_initialize_kthread_stack: kstack 0x%p, start_func 0x%p, entry_func 0x%p\n", +// kstack, start_func, entry_func); + + // clear the kernel stack + memset(kstack, 0, kstack_size); + + // set the final return address to be thread_kthread_exit + kstack_top--; + *kstack_top = (unsigned int)exit_func; + + // set the return address to be the start of the first function + kstack_top--; + *kstack_top = (unsigned int)start_func; + + // set the return address to be the start of the entry (thread setup) function + kstack_top--; + *kstack_top = (unsigned int)entry_func; + + // simulate pushfl +// kstack_top--; +// *kstack_top = 0x00; // interrupts still disabled after the switch + + // simulate initial popad + for(i=0; i<8; i++) { + kstack_top--; + *kstack_top = 0; + } + + // save the esp + t->arch_info.esp = kstack_top; + + return 0; +} + +void arch_thread_switch_kstack_and_call(struct thread *t, addr new_kstack, void (*func)(void *), void *arg) +{ + i386_switch_stack_and_call(new_kstack, func, arg); +} + +void arch_thread_context_switch(struct thread *t_from, struct thread *t_to) +{ + addr new_pgdir; +#if 0 + int i; + + dprintf("arch_thread_context_switch: cpu %d 0x%x -> 0x%x, aspace 0x%x -> 0x%x, &old_esp = 0x%p, esp = 0x%p\n", + smp_get_current_cpu(), t_from->id, t_to->id, + t_from->proc->aspace, t_to->proc->aspace, + &t_from->arch_info.esp, t_to->arch_info.esp); +#endif +#if 0 + for(i=0; i<11; i++) + dprintf("*esp[%d] (0x%x) = 0x%x\n", i, ((unsigned int *)new_at->esp + i), *((unsigned int *)new_at->esp + i)); +#endif + i386_set_kstack(t_to->kernel_stack_base + KSTACK_SIZE); + +#if 0 +{ + int a = *(int *)(t_to->kernel_stack_base + KSTACK_SIZE - 4); +} +#endif + + if(t_from->proc->_aspace_id >= 0 && t_to->proc->_aspace_id >= 0) { + // they are both uspace threads + if(t_from->proc->_aspace_id == t_to->proc->_aspace_id) { + // dont change the pgdir, same address space + new_pgdir = NULL; + } else { + // switching to a new address space + new_pgdir = vm_translation_map_get_pgdir(&t_to->proc->aspace->translation_map); + } + } else if(t_from->proc->_aspace_id < 0 && t_to->proc->_aspace_id < 0) { + // they must both be kspace threads + new_pgdir = NULL; + } else if(t_to->proc->_aspace_id < 0) { + // the one we're switching to is kspace + new_pgdir = vm_translation_map_get_pgdir(&t_to->proc->kaspace->translation_map); + } else { + new_pgdir = vm_translation_map_get_pgdir(&t_to->proc->aspace->translation_map); + } +#if 0 + dprintf("new_pgdir is 0x%x\n", new_pgdir); +#endif + +#if 0 +{ + int a = *(int *)(t_to->arch_info.esp - 4); +} +#endif + + if((new_pgdir % PAGE_SIZE) != 0) + panic("arch_thread_context_switch: bad pgdir 0x%lx\n", new_pgdir); + + i386_fsave_swap(t_from->arch_info.fpu_state, t_to->arch_info.fpu_state); + i386_context_switch(&t_from->arch_info.esp, t_to->arch_info.esp, new_pgdir); +} + +void arch_thread_dump_info(void *info) +{ + struct arch_thread *at = (struct arch_thread *)info; + + dprintf("\tesp: %p\n", at->esp); + dprintf("\tfpu_state at %p\n", at->fpu_state); +} + +void arch_thread_enter_uspace(addr entry, void *args, addr ustack_top) +{ + dprintf("arch_thread_entry_uspace: entry 0x%lx, args %p, ustack_top 0x%lx\n", + entry, args, ustack_top); + + // make sure the fpu is in a good state + asm("fninit"); + + int_disable_interrupts(); + + i386_set_kstack(thread_get_current_thread()->kernel_stack_base + KSTACK_SIZE); + + i386_enter_uspace(entry, args, ustack_top - 4); +} + diff --git a/src/kernel/core/arch/x86/arch_timer.c b/src/kernel/core/arch/x86/arch_timer.c new file mode 100755 index 0000000000..87238c05aa --- /dev/null +++ b/src/kernel/core/arch/x86/arch_timer.c @@ -0,0 +1,79 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#define pit_clock_rate 1193180 +#define pit_max_timer_interval ((long long)0xffff * 1000000 / pit_clock_rate) + +static void set_isa_hardware_timer(long long relative_timeout) +{ + unsigned short next_event_clocks; + + if (relative_timeout <= 0) + next_event_clocks = 2; + else if (relative_timeout < pit_max_timer_interval) + next_event_clocks = relative_timeout * pit_clock_rate / 1000000; + else + next_event_clocks = 0xffff; + + out8(0x30, 0x43); + out8(next_event_clocks & 0xff, 0x40); + out8((next_event_clocks >> 8) & 0xff, 0x40); +} + +static void clear_isa_hardware_timer() +{ + // XXX do something here +} + +static int isa_timer_interrupt(void* data) +{ + return timer_interrupt(); +} + +int apic_timer_interrupt() +{ + return timer_interrupt(); +} + +void arch_timer_set_hardware_timer(bigtime_t timeout) +{ + // try the apic timer first + if(arch_smp_set_apic_timer(timeout) < 0) { + set_isa_hardware_timer(timeout); + } +} + +void arch_timer_clear_hardware_timer() +{ + if(arch_smp_clear_apic_timer() < 0) { + clear_isa_hardware_timer(); + } +} + +int arch_init_timer(kernel_args *ka) +{ + dprintf("arch_init_timer: entry\n"); + + int_set_io_interrupt_handler(0x20, &isa_timer_interrupt, NULL); + // apic timer interrupt set up by smp code + + return 0; +} diff --git a/src/kernel/core/arch/x86/arch_vm.c b/src/kernel/core/arch/x86/arch_vm.c new file mode 100755 index 0000000000..29e384e767 --- /dev/null +++ b/src/kernel/core/arch/x86/arch_vm.c @@ -0,0 +1,60 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +int arch_vm_init(kernel_args *ka) +{ + dprintf("arch_vm_init: entry\n"); + return 0; +} + +int arch_vm_init2(kernel_args *ka) +{ + dprintf("arch_vm_init2: entry\n"); + + // account for BIOS area and mark the pages unusable + vm_mark_page_range_inuse(0xa0000 / PAGE_SIZE, (0x100000 - 0xa0000) / PAGE_SIZE); + + // account for DMA area and mark the pages unusable + vm_mark_page_range_inuse(0x0, 0xa0000 / PAGE_SIZE); + + return 0; +} + +int arch_vm_init_endvm(kernel_args *ka) +{ + region_id id; + void *ptr; + + dprintf("arch_vm_init_endvm: entry\n"); + + // map 0 - 0xa0000 directly + id = vm_map_physical_memory(vm_get_kernel_aspace_id(), "dma_region", &ptr, + REGION_ADDR_ANY_ADDRESS, 0xa0000, LOCK_RW|LOCK_KERNEL, 0x0); + if(id < 0) { + panic("arch_vm_init_endvm: unable to map dma region\n"); + return ERR_NO_MEMORY; + } + return 0; +} + +void arch_vm_aspace_swap(vm_address_space *aspace) +{ + i386_swap_pgdir(vm_translation_map_get_pgdir(&aspace->translation_map)); +} + + diff --git a/src/kernel/core/arch/x86/arch_vm_translation_map.c b/src/kernel/core/arch/x86/arch_vm_translation_map.c new file mode 100755 index 0000000000..52a35e49ee --- /dev/null +++ b/src/kernel/core/arch/x86/arch_vm_translation_map.c @@ -0,0 +1,815 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +// 256 MB of iospace +#define IOSPACE_SIZE (256*1024*1024) +// put it 256 MB into kernel space +#define IOSPACE_BASE (KERNEL_BASE + IOSPACE_SIZE) +// 4 MB chunks, to optimize for 4 MB pages +#define IOSPACE_CHUNK_SIZE (4*1024*1024) + +// data and structures used to represent physical pages mapped into iospace +typedef struct paddr_chunk_descriptor { + struct paddr_chunk_descriptor *next_q; // must remain first in structure, queue code uses it + int ref_count; + addr va; +} paddr_chunk_desc; + +static paddr_chunk_desc *paddr_desc; // will be one per physical chunk +static paddr_chunk_desc **virtual_pmappings; // will be one ptr per virtual chunk in iospace +static int first_free_vmapping; +static int num_virtual_chunks; +static queue mapped_paddr_lru; +static ptentry *iospace_pgtables = NULL; +static mutex iospace_mutex; +static sem_id iospace_full_sem; + +#define PAGE_INVALIDATE_CACHE_SIZE 64 + +// vm_translation object stuff +typedef struct vm_translation_map_arch_info_struct { + pdentry *pgdir_virt; + pdentry *pgdir_phys; + int num_invalidate_pages; + addr pages_to_invalidate[PAGE_INVALIDATE_CACHE_SIZE]; +} vm_translation_map_arch_info; + +static ptentry *page_hole = NULL; +static pdentry *page_hole_pgdir = NULL; +static pdentry *kernel_pgdir_phys = NULL; +static pdentry *kernel_pgdir_virt = NULL; + +static vm_translation_map *tmap_list; +static spinlock_t tmap_list_lock; + +#define CHATTY_TMAP 0 + +#define ADDR_SHIFT(x) ((x)>>12) +#define ADDR_REVERSE_SHIFT(x) ((x)<<12) + +#define VADDR_TO_PDENT(va) (((va) / PAGE_SIZE) / 1024) +#define VADDR_TO_PTENT(va) (((va) / PAGE_SIZE) % 1024) + +#define FIRST_USER_PGDIR_ENT (VADDR_TO_PDENT(USER_BASE)) +#define NUM_USER_PGDIR_ENTS (VADDR_TO_PDENT(USER_SIZE)) +#define FIRST_KERNEL_PGDIR_ENT (VADDR_TO_PDENT(KERNEL_BASE)) +#define NUM_KERNEL_PGDIR_ENTS (VADDR_TO_PDENT(KERNEL_SIZE)) + +static int vm_translation_map_quick_query(addr va, addr *out_physical); + +static void flush_tmap(vm_translation_map *map); + +static void init_pdentry(pdentry *e) +{ + *(int *)e = 0; +} + +static void init_ptentry(ptentry *e) +{ + *(int *)e = 0; +} + +static void _update_all_pgdirs(int index, pdentry e) +{ + unsigned int state; + vm_translation_map *entry; + + state = int_disable_interrupts(); + acquire_spinlock(&tmap_list_lock); + + for(entry = tmap_list; entry != NULL; entry = entry->next) + entry->arch_data->pgdir_virt[index] = e; + + release_spinlock(&tmap_list_lock); + int_restore_interrupts(state); +} + +static int lock_tmap(vm_translation_map *map) +{ +// dprintf("lock_tmap: map 0x%x\n", map); + if(recursive_lock_lock(&map->lock) == true) { + // we were the first one to grab the lock +// dprintf("clearing invalidated page count\n"); + map->arch_data->num_invalidate_pages = 0; + } + + return 0; +} + +static int unlock_tmap(vm_translation_map *map) +{ +// dprintf("unlock_tmap: map 0x%x\n", map); + + if(recursive_lock_get_recursion(&map->lock) == 1) { + // we're about to release it for the last time + flush_tmap(map); + } + recursive_lock_unlock(&map->lock); + return 0; +} + +static void destroy_tmap(vm_translation_map *map) +{ + int state; + vm_translation_map *entry; + vm_translation_map *last = NULL; + unsigned int i; + + if(map == NULL) + return; + + // remove it from the tmap list + state = int_disable_interrupts(); + acquire_spinlock(&tmap_list_lock); + + entry = tmap_list; + while(entry != NULL) { + if(entry == map) { + if(last != NULL) { + last->next = entry->next; + } else { + tmap_list = entry->next; + } + break; + } + last = entry; + entry = entry->next; + } + + release_spinlock(&tmap_list_lock); + int_restore_interrupts(state); + + + if(map->arch_data->pgdir_virt != NULL) { + // cycle through and free all of the user space pgtables + for(i = VADDR_TO_PDENT(USER_BASE); i < VADDR_TO_PDENT(USER_BASE + (USER_SIZE - 1)); i++) { + addr pgtable_addr; + vm_page *page; + + if(map->arch_data->pgdir_virt[i].present == 1) { + pgtable_addr = map->arch_data->pgdir_virt[i].addr; + page = vm_lookup_page(pgtable_addr); + if(!page) + panic("destroy_tmap: didn't find pgtable page\n"); + vm_page_set_state(page, PAGE_STATE_FREE); + } + } + kfree(map->arch_data->pgdir_virt); + } + + kfree(map->arch_data); + recursive_lock_destroy(&map->lock); +} + +static void put_pgtable_in_pgdir(pdentry *e, addr pgtable_phys, int attributes) +{ + // put it in the pgdir + init_pdentry(e); + e->addr = ADDR_SHIFT(pgtable_phys); + e->user = !(attributes & LOCK_KERNEL); + e->rw = attributes & LOCK_RW; + e->present = 1; +} + +static int map_tmap(vm_translation_map *map, addr va, addr pa, unsigned int attributes) +{ + pdentry *pd; + ptentry *pt; + unsigned int index; + int err; + +#if CHATTY_TMAP + dprintf("map_tmap: entry pa 0x%x va 0x%x\n", pa, va); +#endif +/* + dprintf("pgdir at 0x%x\n", pgdir); + dprintf("index is %d\n", va / PAGE_SIZE / 1024); + dprintf("final at 0x%x\n", &pgdir[va / PAGE_SIZE / 1024]); + dprintf("value is 0x%x\n", *(int *)&pgdir[va / PAGE_SIZE / 1024]); + dprintf("present bit is %d\n", pgdir[va / PAGE_SIZE / 1024].present); + dprintf("addr is %d\n", pgdir[va / PAGE_SIZE / 1024].addr); +*/ + pd = map->arch_data->pgdir_virt; + + // check to see if a page table exists for this range + index = VADDR_TO_PDENT(va); + if(pd[index].present == 0) { + addr pgtable; + vm_page *page; + + // we need to allocate a pgtable + page = vm_page_allocate_page(PAGE_STATE_CLEAR); + pgtable = page->ppn * PAGE_SIZE; +#if CHATTY_TMAP + dprintf("map_tmap: asked for free page for pgtable. 0x%x\n", pgtable); +#endif + // put it in the pgdir + put_pgtable_in_pgdir(&pd[index], pgtable, attributes | LOCK_RW); + + // update any other page directories, if it maps kernel space + if(index >= FIRST_KERNEL_PGDIR_ENT && index < (FIRST_KERNEL_PGDIR_ENT + NUM_KERNEL_PGDIR_ENTS)) + _update_all_pgdirs(index, pd[index]); + + map->map_count++; + } + + // now, fill in the pentry + do { + err = vm_get_physical_page(ADDR_REVERSE_SHIFT(pd[index].addr), (addr *)&pt, PHYSICAL_PAGE_NO_WAIT); + } while(err < 0); + index = VADDR_TO_PTENT(va); + + init_ptentry(&pt[index]); + pt[index].addr = ADDR_SHIFT(pa); + pt[index].user = !(attributes & LOCK_KERNEL); + pt[index].rw = attributes & LOCK_RW; + pt[index].present = 1; + + vm_put_physical_page((addr)pt); + + if(map->arch_data->num_invalidate_pages < PAGE_INVALIDATE_CACHE_SIZE) { + map->arch_data->pages_to_invalidate[map->arch_data->num_invalidate_pages] = va; + } + map->arch_data->num_invalidate_pages++; + + map->map_count++; + + return 0; +} + +static int unmap_tmap(vm_translation_map *map, addr start, addr end) +{ + ptentry *pt; + pdentry *pd = map->arch_data->pgdir_virt; + int index; + int err; + + start = ROUNDOWN(start, PAGE_SIZE); + end = ROUNDUP(end, PAGE_SIZE); + +#if CHATTY_TMAP + dprintf("unmap_tmap: asked to free pages 0x%x to 0x%x\n", start, end); +#endif + +restart: + if(start >= end) + return 0; + + index = VADDR_TO_PDENT(start); + if(pd[index].present == 0) { + // no pagetable here, move the start up to access the next page table + start = ROUNDUP(start + 1, PAGE_SIZE); + goto restart; + } + + do { + err = vm_get_physical_page(ADDR_REVERSE_SHIFT(pd[index].addr), (addr *)&pt, PHYSICAL_PAGE_NO_WAIT); + } while(err < 0); + + for(index = VADDR_TO_PTENT(start); (index < 1024) && (start < end); index++, start += PAGE_SIZE) { + if(pt[index].present == 0) { + // page mapping not valid + continue; + } +#if CHATTY_TMAP + dprintf("unmap_tmap: removing page 0x%x\n", start); +#endif + pt[index].present = 0; + map->map_count--; + + if(map->arch_data->num_invalidate_pages < PAGE_INVALIDATE_CACHE_SIZE) { + map->arch_data->pages_to_invalidate[map->arch_data->num_invalidate_pages] = start; + } + map->arch_data->num_invalidate_pages++; + } + + vm_put_physical_page((addr)pt); + + goto restart; +} + +static int query_tmap(vm_translation_map *map, addr va, addr *out_physical, unsigned int *out_flags) +{ + ptentry *pt; + pdentry *pd = map->arch_data->pgdir_virt; + int index; + int err; + + // default the flags to not present + *out_flags = 0; + *out_physical = 0; + + index = VADDR_TO_PDENT(va); + if(pd[index].present == 0) { + // no pagetable here + return B_NO_ERROR; + } + + do { + err = vm_get_physical_page(ADDR_REVERSE_SHIFT(pd[index].addr), (addr *)&pt, PHYSICAL_PAGE_NO_WAIT); + } while(err < 0); + index = VADDR_TO_PTENT(va); + + *out_physical = ADDR_REVERSE_SHIFT(pt[index].addr); + + // read in the page state flags, clearing the modified and accessed flags in the process + *out_flags = 0; + *out_flags |= pt[index].rw ? LOCK_RW : LOCK_RO; + *out_flags |= pt[index].user ? 0 : LOCK_KERNEL; + *out_flags |= pt[index].dirty ? PAGE_MODIFIED : 0; + *out_flags |= pt[index].accessed ? PAGE_ACCESSED : 0; + *out_flags |= pt[index].present ? PAGE_PRESENT : 0; + + vm_put_physical_page((addr)pt); + +// dprintf("query_tmap: returning pa 0x%x for va 0x%x\n", *out_physical, va); + + return 0; +} + +static addr get_mapped_size_tmap(vm_translation_map *map) +{ + return map->map_count; +} + +static int protect_tmap(vm_translation_map *map, addr base, addr top, unsigned int attributes) +{ + // XXX finish + panic("protect_tmap called, not implemented\n"); + return ERR_UNIMPLEMENTED; +} + +static int clear_flags_tmap(vm_translation_map *map, addr va, unsigned int flags) +{ + ptentry *pt; + pdentry *pd = map->arch_data->pgdir_virt; + int index; + int err; + int tlb_flush = false; + + index = VADDR_TO_PDENT(va); + if(pd[index].present == 0) { + // no pagetable here + return B_NO_ERROR; + } + + do { + err = vm_get_physical_page(ADDR_REVERSE_SHIFT(pd[index].addr), (addr *)&pt, PHYSICAL_PAGE_NO_WAIT); + } while(err < 0); + index = VADDR_TO_PTENT(va); + + // clear out the flags we've been requested to clear + if(flags & PAGE_MODIFIED) { + pt[index].dirty = 0; + tlb_flush = true; + } + if(flags & PAGE_ACCESSED) { + pt[index].accessed = 0; + tlb_flush = true; + } + + vm_put_physical_page((addr)pt); + + if(tlb_flush) { + if(map->arch_data->num_invalidate_pages < PAGE_INVALIDATE_CACHE_SIZE) { + map->arch_data->pages_to_invalidate[map->arch_data->num_invalidate_pages] = va; + } + map->arch_data->num_invalidate_pages++; + } + +// dprintf("query_tmap: returning pa 0x%x for va 0x%x\n", *out_physical, va); + + return 0; +} + + +static void flush_tmap(vm_translation_map *map) +{ + int state; + + if(map->arch_data->num_invalidate_pages <= 0) + return; + + state = int_disable_interrupts(); + if(map->arch_data->num_invalidate_pages > PAGE_INVALIDATE_CACHE_SIZE) { + // invalidate all pages +// dprintf("flush_tmap: %d pages to invalidate, doing global invalidation\n", map->arch_data->num_invalidate_pages); + arch_cpu_global_TLB_invalidate(); + smp_send_broadcast_ici(SMP_MSG_GLOBAL_INVL_PAGE, 0, 0, 0, NULL, SMP_MSG_FLAG_SYNC); + } else { +// dprintf("flush_tmap: %d pages to invalidate, doing local invalidation\n", map->arch_data->num_invalidate_pages); + arch_cpu_invalidate_TLB_list(map->arch_data->pages_to_invalidate, map->arch_data->num_invalidate_pages); + smp_send_broadcast_ici(SMP_MSG_INVL_PAGE_LIST, (unsigned long)map->arch_data->pages_to_invalidate, + map->arch_data->num_invalidate_pages, 0, NULL, SMP_MSG_FLAG_SYNC); + } + map->arch_data->num_invalidate_pages = 0; + int_restore_interrupts(state); +} + +static int map_iospace_chunk(addr va, addr pa) +{ + int i; + ptentry *pt; + addr ppn; + int state; + + pa &= ~(PAGE_SIZE - 1); // make sure it's page aligned + va &= ~(PAGE_SIZE - 1); // make sure it's page aligned + if(va < IOSPACE_BASE || va >= (IOSPACE_BASE + IOSPACE_SIZE)) + panic("map_iospace_chunk: passed invalid va 0x%lx\n", va); + + ppn = ADDR_SHIFT(pa); + pt = &iospace_pgtables[(va - IOSPACE_BASE)/PAGE_SIZE]; + for(i=0; i<1024; i++) { + init_ptentry(&pt[i]); + pt[i].addr = ppn + i; + pt[i].user = 0; + pt[i].rw = 1; + pt[i].present = 1; + } + + state = int_disable_interrupts(); + arch_cpu_invalidate_TLB_range(va, va + (IOSPACE_CHUNK_SIZE - PAGE_SIZE)); + smp_send_broadcast_ici(SMP_MSG_INVL_PAGE_RANGE, va, va + (IOSPACE_CHUNK_SIZE - PAGE_SIZE), 0, + NULL, SMP_MSG_FLAG_SYNC); + int_restore_interrupts(state); + + return 0; +} + +static int get_physical_page_tmap(addr pa, addr *va, int flags) +{ + int index; + paddr_chunk_desc *replaced_pchunk; + +restart: + + mutex_lock(&iospace_mutex); + + // see if the page is already mapped + index = pa / IOSPACE_CHUNK_SIZE; + if(paddr_desc[index].va != 0) { + if(paddr_desc[index].ref_count++ == 0) { + // pull this descriptor out of the lru list + queue_remove_item(&mapped_paddr_lru, &paddr_desc[index]); + } + *va = paddr_desc[index].va + pa % IOSPACE_CHUNK_SIZE; + mutex_unlock(&iospace_mutex); + return 0; + } + + // map it + if(first_free_vmapping < num_virtual_chunks) { + // there's a free hole + paddr_desc[index].va = first_free_vmapping * IOSPACE_CHUNK_SIZE + IOSPACE_BASE; + *va = paddr_desc[index].va + pa % IOSPACE_CHUNK_SIZE; + virtual_pmappings[first_free_vmapping] = &paddr_desc[index]; + paddr_desc[index].ref_count++; + + // push up the first_free_vmapping pointer + for(; first_free_vmapping < num_virtual_chunks; first_free_vmapping++) { + if(virtual_pmappings[first_free_vmapping] == NULL) + break; + } + + map_iospace_chunk(paddr_desc[index].va, index * IOSPACE_CHUNK_SIZE); + mutex_unlock(&iospace_mutex); + + return 0; + } + + // replace an earlier mapping + if(queue_peek(&mapped_paddr_lru) == NULL) { + // no free slots available + if(flags == PHYSICAL_PAGE_NO_WAIT) { + // punt back to the caller and let them handle this + mutex_unlock(&iospace_mutex); + return ERR_NO_MEMORY; + } else { + mutex_unlock(&iospace_mutex); + acquire_sem(iospace_full_sem); + goto restart; + } + } + + replaced_pchunk = queue_dequeue(&mapped_paddr_lru); + paddr_desc[index].va = replaced_pchunk->va; + replaced_pchunk->va = 0; + *va = paddr_desc[index].va + pa % IOSPACE_CHUNK_SIZE; + paddr_desc[index].ref_count++; + + map_iospace_chunk(paddr_desc[index].va, index * IOSPACE_CHUNK_SIZE); + + mutex_unlock(&iospace_mutex); + return 0; +} + +static int put_physical_page_tmap(addr va) +{ + paddr_chunk_desc *desc; + + if(va < IOSPACE_BASE || va >= IOSPACE_BASE + IOSPACE_SIZE) + panic("someone called put_physical_page on an invalid va 0x%lx\n", va); + va -= IOSPACE_BASE; + + mutex_lock(&iospace_mutex); + + desc = virtual_pmappings[va / IOSPACE_CHUNK_SIZE]; + if(desc == NULL) { + mutex_unlock(&iospace_mutex); + panic("put_physical_page called on page at va 0x%lx which is not checked out\n", va); + return ERR_VM_GENERAL; + } + + if(--desc->ref_count == 0) { + // put it on the mapped lru list + queue_enqueue(&mapped_paddr_lru, desc); + // no sense rescheduling on this one, there's likely a race in the waiting + // thread to grab the iospace_mutex, which would block and eventually get back to + // this thread. waste of time. + release_sem_etc(iospace_full_sem, 1, B_DO_NOT_RESCHEDULE); + } + + mutex_unlock(&iospace_mutex); + + return 0; +} + +static vm_translation_map_ops tmap_ops = { + destroy_tmap, + lock_tmap, + unlock_tmap, + map_tmap, + unmap_tmap, + query_tmap, + get_mapped_size_tmap, + protect_tmap, + clear_flags_tmap, + flush_tmap, + get_physical_page_tmap, + put_physical_page_tmap +}; + +int vm_translation_map_create(vm_translation_map *new_map, bool kernel) +{ + if(new_map == NULL) + return ERR_INVALID_ARGS; + +dprintf("vm_translation_map_create\n"); + // initialize the new object + new_map->ops = &tmap_ops; + new_map->map_count = 0; + if(recursive_lock_create(&new_map->lock) < 0) + return ERR_NO_MEMORY; + + new_map->arch_data = (vm_translation_map_arch_info *)kmalloc(sizeof(vm_translation_map_arch_info)); + if(new_map == NULL) + return ERR_NO_MEMORY; + + new_map->arch_data->num_invalidate_pages = 0; + + if(!kernel) { + // user + // allocate a pgdir + new_map->arch_data->pgdir_virt = kmalloc(PAGE_SIZE); + if(new_map->arch_data->pgdir_virt == NULL) { + kfree(new_map->arch_data); + return ERR_NO_MEMORY; + } + if(((addr)new_map->arch_data->pgdir_virt % PAGE_SIZE) != 0) + panic("vm_translation_map_create: malloced pgdir and found it wasn't aligned!\n"); + vm_get_page_mapping(vm_get_kernel_aspace_id(), (addr)new_map->arch_data->pgdir_virt, (addr *)&new_map->arch_data->pgdir_phys); + } else { + // kernel + // we already know the kernel pgdir mapping + (addr)new_map->arch_data->pgdir_virt = kernel_pgdir_virt; + (addr)new_map->arch_data->pgdir_phys = kernel_pgdir_phys; + } + + // zero out the bottom portion of the new pgdir + memset(new_map->arch_data->pgdir_virt + FIRST_USER_PGDIR_ENT, 0, NUM_USER_PGDIR_ENTS * sizeof(pdentry)); + + // insert this new map into the map list + { + int state = int_disable_interrupts(); + acquire_spinlock(&tmap_list_lock); + + // copy the top portion of the pgdir from the current one + memcpy(new_map->arch_data->pgdir_virt + FIRST_KERNEL_PGDIR_ENT, kernel_pgdir_virt + FIRST_KERNEL_PGDIR_ENT, + NUM_KERNEL_PGDIR_ENTS * sizeof(pdentry)); + + new_map->next = tmap_list; + tmap_list = new_map; + + release_spinlock(&tmap_list_lock); + int_restore_interrupts(state); + } + + return 0; +} + +int vm_translation_map_module_init(kernel_args *ka) +{ + int i; + + dprintf("vm_translation_map_module_init: entry\n"); + + // page hole set up in stage2 + page_hole = (ptentry *)ka->arch_args.page_hole; + // calculate where the pgdir would be + page_hole_pgdir = (pdentry *)(((unsigned int)ka->arch_args.page_hole) + (PAGE_SIZE * 1024 - PAGE_SIZE)); + // clear out the bottom 2 GB, unmap everything + memset(page_hole_pgdir + FIRST_USER_PGDIR_ENT, 0, sizeof(pdentry) * NUM_USER_PGDIR_ENTS); + + kernel_pgdir_phys = (pdentry *)ka->arch_args.phys_pgdir; + kernel_pgdir_virt = (pdentry *)ka->arch_args.vir_pgdir; + + tmap_list_lock = 0; + tmap_list = NULL; + + // allocate some space to hold physical page mapping info + paddr_desc = (paddr_chunk_desc *)vm_alloc_from_ka_struct(ka, + sizeof(paddr_chunk_desc) * 1024, LOCK_RW|LOCK_KERNEL); + num_virtual_chunks = IOSPACE_SIZE / IOSPACE_CHUNK_SIZE; + virtual_pmappings = (paddr_chunk_desc **)vm_alloc_from_ka_struct(ka, + sizeof(paddr_chunk_desc *) * num_virtual_chunks, LOCK_RW|LOCK_KERNEL); + iospace_pgtables = (ptentry *)vm_alloc_from_ka_struct(ka, + PAGE_SIZE * (IOSPACE_SIZE / (PAGE_SIZE * 1024)), LOCK_RW|LOCK_KERNEL); + + dprintf("paddr_desc %p, virtual_pmappings %p, iospace_pgtables %p\n", + paddr_desc, virtual_pmappings, iospace_pgtables); + + // initialize our data structures + memset(paddr_desc, 0, sizeof(paddr_chunk_desc) * 1024); + memset(virtual_pmappings, 0, sizeof(paddr_chunk_desc *) * num_virtual_chunks); + first_free_vmapping = 0; + queue_init(&mapped_paddr_lru); + memset(iospace_pgtables, 0, PAGE_SIZE * (IOSPACE_SIZE / (PAGE_SIZE * 1024))); + iospace_mutex.sem = -1; + iospace_mutex.count = 0; + iospace_full_sem = -1; + + dprintf("mapping iospace_pgtables\n"); + + // put the array of pgtables directly into the kernel pagedir + // these will be wired and kept mapped into virtual space to be easy to get to + { + addr phys_pgtable; + addr virt_pgtable; + pdentry *e; + + virt_pgtable = (addr)iospace_pgtables; + for(i = 0; i < (IOSPACE_SIZE / (PAGE_SIZE * 1024)); i++, virt_pgtable += PAGE_SIZE) { + vm_translation_map_quick_query(virt_pgtable, &phys_pgtable); + e = &page_hole_pgdir[(IOSPACE_BASE / (PAGE_SIZE * 1024)) + i]; + put_pgtable_in_pgdir(e, phys_pgtable, LOCK_RW|LOCK_KERNEL); + } + } + + dprintf("vm_translation_map_module_init: done\n"); + + return 0; +} + + +void vm_translation_map_module_init_post_sem(kernel_args *ka) +{ + mutex_init(&iospace_mutex, "iospace_mutex"); + iospace_full_sem = create_sem(1, "iospace_full_sem"); +} + +int vm_translation_map_module_init2(kernel_args *ka) +{ + // now that the vm is initialized, create an region that represents + // the page hole + void *temp; + + dprintf("vm_translation_map_module_init2: entry\n"); + + // unmap the page hole hack we were using before + kernel_pgdir_virt[1023].present = 0; + page_hole_pgdir = NULL; + page_hole = NULL; + + temp = (void *)kernel_pgdir_virt; + vm_create_anonymous_region(vm_get_kernel_aspace_id(), "kernel_pgdir", &temp, + REGION_ADDR_EXACT_ADDRESS, PAGE_SIZE, REGION_WIRING_WIRED_ALREADY, LOCK_RW|LOCK_KERNEL); + + temp = (void *)paddr_desc; + vm_create_anonymous_region(vm_get_kernel_aspace_id(), "physical_page_mapping_descriptors", &temp, + REGION_ADDR_EXACT_ADDRESS, ROUNDUP(sizeof(paddr_chunk_desc) * 1024, PAGE_SIZE), + REGION_WIRING_WIRED_ALREADY, LOCK_RW|LOCK_KERNEL); + + temp = (void *)virtual_pmappings; + vm_create_anonymous_region(vm_get_kernel_aspace_id(), "iospace_virtual_chunk_descriptors", &temp, + REGION_ADDR_EXACT_ADDRESS, ROUNDUP(sizeof(paddr_chunk_desc *) * num_virtual_chunks, PAGE_SIZE), + REGION_WIRING_WIRED_ALREADY, LOCK_RW|LOCK_KERNEL); + + temp = (void *)iospace_pgtables; + vm_create_anonymous_region(vm_get_kernel_aspace_id(), "iospace_pgtables", &temp, + REGION_ADDR_EXACT_ADDRESS, PAGE_SIZE * (IOSPACE_SIZE / (PAGE_SIZE * 1024)), + REGION_WIRING_WIRED_ALREADY, LOCK_RW|LOCK_KERNEL); + + dprintf("vm_translation_map_module_init2: creating iospace\n"); + temp = (void *)IOSPACE_BASE; + vm_create_null_region(vm_get_kernel_aspace_id(), "iospace", &temp, + REGION_ADDR_EXACT_ADDRESS, IOSPACE_SIZE); + + dprintf("vm_translation_map_module_init2: done\n"); + + return 0; +} + +// XXX horrible back door to map a page quickly regardless of translation map object, etc. +// used only during VM setup. +// uses a 'page hole' set up in the stage 2 bootloader. The page hole is created by pointing one of +// the pgdir entries back at itself, effectively mapping the contents of all of the 4MB of pagetables +// into a 4 MB region. It's only used here, and is later unmapped. +int vm_translation_map_quick_map(kernel_args *ka, addr va, addr pa, unsigned int attributes, addr (*get_free_page)(kernel_args *)) +{ + ptentry *pentry; + int index; + +#if CHATTY_TMAP + dprintf("quick_tmap: entry pa 0x%x va 0x%x\n", pa, va); +#endif + + // check to see if a page table exists for this range + index = VADDR_TO_PDENT(va); + if(page_hole_pgdir[index].present == 0) { + addr pgtable; + pdentry *e; + // we need to allocate a pgtable + pgtable = get_free_page(ka); + // pgtable is in pages, convert to physical address + pgtable *= PAGE_SIZE; +#if CHATTY_TMAP + dprintf("quick_map: asked for free page for pgtable. 0x%x\n", pgtable); +#endif + + // put it in the pgdir + e = &page_hole_pgdir[index]; + put_pgtable_in_pgdir(e, pgtable, attributes); + + // zero it out in it's new mapping + memset((unsigned int *)((unsigned int)page_hole + (va / PAGE_SIZE / 1024) * PAGE_SIZE), 0, PAGE_SIZE); + } + // now, fill in the pentry + pentry = page_hole + va / PAGE_SIZE; + + init_ptentry(pentry); + pentry->addr = ADDR_SHIFT(pa); + pentry->user = !(attributes & LOCK_KERNEL); + pentry->rw = attributes & LOCK_RW; + pentry->present = 1; + + arch_cpu_invalidate_TLB_range(va, va+1); + + return 0; +} + +// XXX currently assumes this translation map is active +static int vm_translation_map_quick_query(addr va, addr *out_physical) +{ + ptentry *pentry; + + if(page_hole_pgdir[VADDR_TO_PDENT(va)].present == 0) { + // no pagetable here + return ERR_VM_PAGE_NOT_PRESENT; + } + + pentry = page_hole + va / PAGE_SIZE; + if(pentry->present == 0) { + // page mapping not valid + return ERR_VM_PAGE_NOT_PRESENT; + } + + *out_physical = pentry->addr << 12; + + return 0; +} + +addr vm_translation_map_get_pgdir(vm_translation_map *map) +{ + return (addr)map->arch_data->pgdir_phys; +} diff --git a/src/kernel/core/arch/x86/arch_x86.S b/src/kernel/core/arch/x86/arch_x86.S new file mode 100755 index 0000000000..454b2ef277 --- /dev/null +++ b/src/kernel/core/arch/x86/arch_x86.S @@ -0,0 +1,244 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#define FUNCTION(x) .global x; .type x,@function; x + +.text + +/* int atomic_add(int *val, int incr) */ +FUNCTION(atomic_add): + movl 4(%esp),%edx + movl 8(%esp),%eax + lock + xaddl %eax,(%edx) + ret + +/* int atomic_and(int *val, int incr) */ +FUNCTION(atomic_and): + movl 4(%esp),%edx + +_atomic_and1: + movl 8(%esp),%ecx + movl (%edx),%eax + andl %eax,%ecx + + lock + cmpxchgl %ecx,(%edx) + + jnz _atomic_and1 + + ret + +/* int atomic_or(int *val, int incr) */ +FUNCTION(atomic_or): + movl 4(%esp),%edx + +_atomic_or1: + movl 8(%esp),%ecx + movl (%edx),%eax + orl %eax,%ecx + + lock + cmpxchgl %ecx,(%edx) + + jnz _atomic_or1 + + ret + +/* int atomic_set(int *val, int set_to) */ +FUNCTION(atomic_set): + movl 4(%esp),%edx + movl 8(%esp),%eax + xchg %eax,(%edx) + ret + +/* int test_and_set(int *val, int set_to, int test_val) */ +FUNCTION(test_and_set): + movl 4(%esp),%edx + movl 8(%esp),%ecx + movl 12(%esp),%eax + + lock + cmpxchgl %ecx,(%edx) + + ret + +/* saves the conversion factor needed for system_time */ +.global cv_factor +cv_factor: + .word 0 + +FUNCTION(setup_system_time): + movl 4(%esp),%eax + movl %eax,cv_factor + ret + +/* long long system_time(); */ +FUNCTION(system_time): + /* load 64-bit factor into %eax (low), %edx (high) */ + rdtsc /* time in %edx,%eax */ + + pushl %ebx + pushl %ecx + movl cv_factor, %ebx + movl %edx, %ecx /* save high half */ + mull %ebx /* truncate %eax, but keep %edx */ + movl %ecx, %eax + movl %edx, %ecx /* save high half of low */ + mull %ebx /*, %eax*/ + /* now compute [%edx, %eax] + [%ecx], propagating carry */ + subl %ebx, %ebx /* need zero to propagate carry */ + addl %ecx, %eax + adc %ebx, %edx + popl %ecx + popl %ebx + ret + +/* void arch_cpu_global_TLB_invalidate(); */ +FUNCTION(arch_cpu_global_TLB_invalidate): + movl %cr3,%eax + movl %eax,%cr3 + ret + +/* void i386_fsave_swap(void *old_fpu_state, void *new_fpu_state); */ +FUNCTION(i386_fsave_swap): + movl 4(%esp),%eax + fsave (%eax) + movl 8(%esp),%eax + frstor (%eax) + ret + +/* void i386_fxsave_swap(void *old_fpu_state, void *new_fpu_state); */ +FUNCTION(i386_fxsave_swap): + movl 4(%esp),%eax + fxsave (%eax) + movl 8(%esp),%eax + fxrstor (%eax) + ret + +/* void i386_context_switch(unsigned int **old_esp, unsigned int *new_esp, addr new_pgdir); */ +FUNCTION(i386_context_switch): + pusha /* pushes 8 words onto the stack */ + movl 36(%esp),%eax + movl %esp,(%eax) + movl 44(%esp),%eax /* get possible new pgdir */ + cmpl $0x0,%eax /* is it null? */ + je skip_pgdir_swap + movl %eax,%cr3 +skip_pgdir_swap: + movl 40(%esp),%eax + movl %eax,%esp + popa + ret + +/* void i386_swap_pgdir(addr new_pgdir); */ +FUNCTION(i386_swap_pgdir): + movl 4(%esp),%eax + movl %eax,%cr3 + ret + +/* thread exit stub */ + .align 4 +i386_uspace_exit_stub: + pushl %eax + movl $1, %ecx + lea (%esp), %edx + movl $25, %eax; + int $99 + .align 4 +i386_uspace_exit_stub_end: + + +/* void i386_enter_uspace(addr entry, void *args, addr ustack_top); */ +FUNCTION(i386_enter_uspace): + movl 4(%esp),%eax // get entry point + movl 8(%esp),%edx // get arguments + movl 12(%esp),%ebx // get user stack + movw $0x23,%cx + movw %cx,%ds + movw %cx,%es + movw %cx,%fs + movw %cx,%gs + + // copy exit stub to stack + movl $i386_uspace_exit_stub_end, %esi +_copy_more: + lea -4(%esi), %esi + lea -4(%ebx), %ebx + mov (%esi), %ecx + mov %ecx, (%ebx) + cmp $i386_uspace_exit_stub, %esi + jg _copy_more + + + // push the args onto the user stack + movl %edx,-4(%ebx) // args + movl %ebx,-8(%ebx) // fake return address to copied exit stub + sub $8,%ebx + + pushl $0x23 // user data segment + pushl %ebx // user stack + pushl $(1 << 9) | 2 // user flags + pushl $0x1b // user code segment + pushl %eax // user IP + iret + +/* void i386_switch_stack_and_call(addr stack, void (*func)(void *), void *arg); */ +FUNCTION(i386_switch_stack_and_call): + movl 4(%esp),%eax // new stack + movl 8(%esp),%ecx // func + movl 12(%esp),%edx // args + + movl %eax,%esp // switch the stack + pushl %edx // push the argument + call *%ecx // call the target function +_loop: + jmp _loop + +null_idt_descr: + .word 0 + .word 0,0 + +FUNCTION(reboot): + lidt null_idt_descr + int $0 +done: + jmp done + + +FUNCTION(dbg_save_registers): + pushl %esi + pushl %eax + movl 12(%esp), %esi + + movl %eax, 0(%esi) + movl %ebx, 4(%esi) + movl %ecx, 8(%esi) + movl %edx, 12(%esi) + + lea 16(%esp), %eax + movl %eax, 16(%esi) // caller's %esp + movl %ebp, 20(%esi) + + movl 4(%esp), %eax + movl %eax, 24(%esi) // caller's %esi + movl %edi, 28(%esi) + + movl 8(%esp), %eax + movl %eax, 32(%esi) // caller's %ebp + + + pushfl + popl %eax + mov %eax, 36(%esi) + + movl %cs, 40(%esi) + movl %ss, 44(%esi) + movl %ds, 48(%esi) + movl %es, 52(%esi) + + popl %eax + popl %esi + ret diff --git a/src/kernel/core/arch/x86/int.c b/src/kernel/core/arch/x86/int.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/kernel/core/arch/x86/kernel.ld b/src/kernel/core/arch/x86/kernel.ld new file mode 100644 index 0000000000..35b934189a --- /dev/null +++ b/src/kernel/core/arch/x86/kernel.ld @@ -0,0 +1,65 @@ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) + +ENTRY(_start) +SEARCH_DIR("libgcc"); +SECTIONS +{ + . = 0x80000000 + SIZEOF_HEADERS; + + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0x9090 + .plt : { *(.plt) } + + /* text/read-only data */ + .text : { *(.text .gnu.linkonce.t.*) } =0x9090 + + .rodata : { *(.rodata) } + + /* writable data */ + . = ALIGN(0x1000); + __data_start = .; + .data : { *(.data .gnu.linkonce.d.*) } + + __ctor_list = .; + .ctors : { *(.ctors) } + __ctor_end = .; + __dtor_list = .; + .dtors : { *(.dtors) } + __dtor_end = .; + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + + /* unintialized data (in same segment as writable data) */ + __bss_start = .; + .bss : { *(.bss) } + + . = ALIGN(0x1000); + _end = . ; + + /* Strip unnecessary stuff */ + /DISCARD/ : { *(.comment .note .eh_frame) } +} diff --git a/src/kernel/core/cbuf.c b/src/kernel/core/cbuf.c new file mode 100644 index 0000000000..0abaac033f --- /dev/null +++ b/src/kernel/core/cbuf.c @@ -0,0 +1,876 @@ +/* This file contains the cbuf functions. Cbuf is a memory allocator, currently not used for anything in kernel land other than ports.*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define ALLOCATE_CHUNK (PAGE_SIZE * 16) +#define CBUF_REGION_SIZE (4*1024*1024) +#define CBUF_BITMAP_SIZE (CBUF_REGION_SIZE / CBUF_LEN) + +static cbuf *cbuf_free_list; +static sem_id free_list_sem; +static cbuf *cbuf_free_noblock_list; +static spinlock_t noblock_spin; + +static spinlock_t cbuf_lowlevel_spinlock; +static region_id cbuf_region_id; +static cbuf *cbuf_region; +static region_id cbuf_bitmap_region_id; +static uint8 *cbuf_bitmap; + +/* Declarations we need that aren't in header files */ +uint16 ones_sum16(uint32, const void *, int); + +static void initialize_cbuf(cbuf *buf) +{ + buf->len = sizeof(buf->dat); + buf->data = buf->dat; + buf->flags = 0; + buf->total_len = 0; +} + +static void *_cbuf_alloc(size_t *size) +{ + int state; + void *buf; + int i; + int start; + size_t len_found = 0; + +// dprintf("cbuf_alloc: asked to allocate size %d\n", *size); + + state = int_disable_interrupts(); + acquire_spinlock(&cbuf_lowlevel_spinlock); + + // scan through the allocation bitmap, looking for the first free block + // XXX not optimal + start = -1; + for(i=0; i= *size) { + // we're done + break; + } + } else if(start >= 0) { + // we've found a start of a run before, so we're done now + break; + } + } + + if(start < 0) { + // couldn't find any memory + buf = NULL; + *size = 0; + } else { + buf = &cbuf_region[start]; + *size = len_found; + } + + release_spinlock(&cbuf_lowlevel_spinlock); + int_restore_interrupts(state); + + return buf; +} + +static cbuf *allocate_cbuf_mem(size_t size) +{ + void *_buf; + cbuf *buf = NULL; + cbuf *last_buf = NULL; + cbuf *head_buf = NULL; + int i; + int count; + size_t found_size; + + size = PAGE_ALIGN(size); + + while(size > 0) { + found_size = size; + _buf = _cbuf_alloc(&found_size); + if(!_buf) { + // couldn't allocate, lets bail with what we have + break; + } + size -= found_size; + count = found_size / CBUF_LEN; +// dprintf("allocate_cbuf_mem: returned %d of memory, %d left\n", found_size, size); + + buf = (cbuf *)_buf; + if(!head_buf) + head_buf = buf; + for(i=0; inext = buf; + if(buf == head_buf) { + buf->flags |= CBUF_FLAG_CHAIN_HEAD; + buf->total_len = (size / CBUF_LEN) * sizeof(buf->dat); + } + last_buf = buf; + buf++; + } + } + if(buf) { + buf->next = NULL; + buf->flags |= CBUF_FLAG_CHAIN_TAIL; + } + + return head_buf; +} + +static void _clear_chain(cbuf *head, cbuf **tail) +{ + cbuf *buf; + + buf = head; + *tail = NULL; + while(buf) { + initialize_cbuf(buf); // doesn't touch the next ptr + *tail = buf; + buf = buf->next; + } + + return; +} + +void cbuf_free_chain_noblock(cbuf *buf) +{ + cbuf *head, *last; + int state; + + if(buf == NULL) + return; + + head = buf; + _clear_chain(head, &last); + + state = int_disable_interrupts(); + acquire_spinlock(&noblock_spin); + + last->next = cbuf_free_noblock_list; + cbuf_free_noblock_list = head; + + release_spinlock(&noblock_spin); + int_restore_interrupts(state); +} + +void cbuf_free_chain(cbuf *buf) +{ + cbuf *head, *last; + + if(buf == NULL) + return; + + head = buf; + _clear_chain(head, &last); + + acquire_sem(free_list_sem); + + last->next = cbuf_free_list; + cbuf_free_list = head; + + release_sem(free_list_sem); +} + +cbuf *cbuf_get_chain(size_t len) +{ + cbuf *chain = NULL; + cbuf *tail = NULL; + cbuf *temp; + size_t chain_len = 0; + + if(len == 0) + panic("cbuf_get_chain: passed size 0\n"); + + acquire_sem(free_list_sem); + + while(chain_len < len) { + if(cbuf_free_list == NULL) { + // we need to allocate some more cbufs + release_sem(free_list_sem); + temp = allocate_cbuf_mem(ALLOCATE_CHUNK); + if(!temp) { + // no more ram + if(chain) + cbuf_free_chain(chain); + return NULL; + } + cbuf_free_chain(temp); + acquire_sem(free_list_sem); + continue; + } + + temp = cbuf_free_list; + cbuf_free_list = cbuf_free_list->next; + temp->next = chain; + if(chain == NULL) + tail = temp; + chain = temp; + + chain_len += chain->len; + } + release_sem(free_list_sem); + + // now we have a chain, fixup the first and last entry + chain->total_len = len; + chain->flags |= CBUF_FLAG_CHAIN_HEAD; + tail->len -= chain_len - len; + tail->flags |= CBUF_FLAG_CHAIN_TAIL; + + return chain; +} + +cbuf *cbuf_get_chain_noblock(size_t len) +{ + cbuf *chain = NULL; + cbuf *tail = NULL; + cbuf *temp; + size_t chain_len = 0; + int state; + + state = int_disable_interrupts(); + acquire_spinlock(&noblock_spin); + + while(chain_len < len) { + if(cbuf_free_noblock_list == NULL) { + dprintf("cbuf_get_chain_noblock: not enough cbufs\n"); + release_spinlock(&noblock_spin); + int_restore_interrupts(state); + + if(chain != NULL) + cbuf_free_chain_noblock(chain); + + return NULL; + } + + temp = cbuf_free_noblock_list; + cbuf_free_noblock_list = cbuf_free_noblock_list->next; + temp->next = chain; + if(chain == NULL) + tail = temp; + chain = temp; + + chain_len += chain->len; + } + release_spinlock(&noblock_spin); + int_restore_interrupts(state); + + // now we have a chain, fixup the first and last entry + chain->total_len = len; + chain->flags |= CBUF_FLAG_CHAIN_HEAD; + tail->len -= chain_len - len; + tail->flags |= CBUF_FLAG_CHAIN_TAIL; + + return chain; +} + +int cbuf_memcpy_to_chain(cbuf *chain, size_t offset, const void *_src, size_t len) +{ + cbuf *buf; + char *src = (char *)_src; + int buf_offset; + + if((chain->flags & CBUF_FLAG_CHAIN_HEAD) == 0) { + dprintf("cbuf_memcpy_to_chain: chain at %p not head\n", chain); + return ERR_INVALID_ARGS; + } + + if(len + offset > chain->total_len) { + dprintf("cbuf_memcpy_to_chain: len + offset > size of cbuf chain\n"); + return ERR_INVALID_ARGS; + } + + // find the starting cbuf in the chain to copy to + buf = chain; + buf_offset = 0; + while(offset > 0) { + if(buf == NULL) { + dprintf("cbuf_memcpy_to_chain: end of chain reached too early!\n"); + return ERR_GENERAL; + } + if(offset < buf->len) { + // this is the one + buf_offset = offset; + break; + } + offset -= buf->len; + buf = buf->next; + } + + while(len > 0) { + int to_copy; + + if(buf == NULL) { + dprintf("cbuf_memcpy_to_chain: end of chain reached too early!\n"); + return ERR_GENERAL; + } + to_copy = min(len, buf->len - buf_offset); + memcpy((char *)buf->data + buf_offset, src, to_copy); + + buf_offset = 0; + len -= to_copy; + src += to_copy; + buf = buf->next; + } + + return B_NO_ERROR; +} + +int cbuf_user_memcpy_to_chain(cbuf *chain, size_t offset, const void *_src, size_t len) +{ + cbuf *buf; + char *src = (char *)_src; + int buf_offset; + int err; + + if((chain->flags & CBUF_FLAG_CHAIN_HEAD) == 0) { + dprintf("cbuf_memcpy_to_chain: chain at %p not head\n", chain); + return ERR_INVALID_ARGS; + } + + if(len + offset > chain->total_len) { + dprintf("cbuf_memcpy_to_chain: len + offset > size of cbuf chain\n"); + return ERR_INVALID_ARGS; + } + + // find the starting cbuf in the chain to copy to + buf = chain; + buf_offset = 0; + while(offset > 0) { + if(buf == NULL) { + dprintf("cbuf_memcpy_to_chain: end of chain reached too early!\n"); + return ERR_GENERAL; + } + if(offset < buf->len) { + // this is the one + buf_offset = offset; + break; + } + offset -= buf->len; + buf = buf->next; + } + + err = B_NO_ERROR; + while(len > 0) { + int to_copy; + + if(buf == NULL) { + dprintf("cbuf_memcpy_to_chain: end of chain reached too early!\n"); + return ERR_GENERAL; + } + to_copy = min(len, buf->len - buf_offset); + if ((err = user_memcpy((char *)buf->data + buf_offset, src, to_copy) < 0)) + break; // memory exception + + buf_offset = 0; + len -= to_copy; + src += to_copy; + buf = buf->next; + } + + return err; +} + + +int cbuf_memcpy_from_chain(void *_dest, cbuf *chain, size_t offset, size_t len) +{ + cbuf *buf; + char *dest = (char *)_dest; + int buf_offset; + + if((chain->flags & CBUF_FLAG_CHAIN_HEAD) == 0) { + dprintf("cbuf_memcpy_from_chain: chain at %p not head\n", chain); + return ERR_INVALID_ARGS; + } + + if(len + offset > chain->total_len) { + dprintf("cbuf_memcpy_from_chain: len + offset > size of cbuf chain\n"); + return ERR_INVALID_ARGS; + } + + // find the starting cbuf in the chain to copy from + buf = chain; + buf_offset = 0; + while(offset > 0) { + if(buf == NULL) { + dprintf("cbuf_memcpy_from_chain: end of chain reached too early!\n"); + return ERR_GENERAL; + } + if(offset < buf->len) { + // this is the one + buf_offset = offset; + break; + } + offset -= buf->len; + buf = buf->next; + } + + while(len > 0) { + int to_copy; + + if(buf == NULL) { + dprintf("cbuf_memcpy_from_chain: end of chain reached too early!\n"); + return ERR_GENERAL; + } + + to_copy = min(len, buf->len - buf_offset); + memcpy(dest, (char *)buf->data + buf_offset, to_copy); + + buf_offset = 0; + len -= to_copy; + dest += to_copy; + buf = buf->next; + } + + return B_NO_ERROR; +} + +int cbuf_user_memcpy_from_chain(void *_dest, cbuf *chain, size_t offset, size_t len) +{ + cbuf *buf; + char *dest = (char *)_dest; + int buf_offset; + int err; + + if((chain->flags & CBUF_FLAG_CHAIN_HEAD) == 0) { + dprintf("cbuf_memcpy_from_chain: chain at %p not head\n", chain); + return ERR_INVALID_ARGS; + } + + if(len + offset > chain->total_len) { + dprintf("cbuf_memcpy_from_chain: len + offset > size of cbuf chain\n"); + return ERR_INVALID_ARGS; + } + + // find the starting cbuf in the chain to copy from + buf = chain; + buf_offset = 0; + while(offset > 0) { + if(buf == NULL) { + dprintf("cbuf_memcpy_from_chain: end of chain reached too early!\n"); + return ERR_GENERAL; + } + if(offset < buf->len) { + // this is the one + buf_offset = offset; + break; + } + offset -= buf->len; + buf = buf->next; + } + + err = B_NO_ERROR; + while(len > 0) { + int to_copy; + + if(buf == NULL) { + dprintf("cbuf_memcpy_from_chain: end of chain reached too early!\n"); + return ERR_GENERAL; + } + + to_copy = min(len, buf->len - buf_offset); + if ((err = user_memcpy(dest, (char *)buf->data + buf_offset, to_copy) < 0)) + break; + + buf_offset = 0; + len -= to_copy; + dest += to_copy; + buf = buf->next; + } + + return err; +} + +cbuf *cbuf_duplicate_chain(cbuf *chain, size_t offset, size_t len) +{ + cbuf *buf; + cbuf *newbuf; + cbuf *destbuf; + int dest_buf_offset; + int buf_offset; + + if(!chain) + return NULL; + if((chain->flags & CBUF_FLAG_CHAIN_HEAD) == 0) + return NULL; + if(offset >= chain->total_len) + return NULL; + len = min(len, chain->total_len - offset); + + newbuf = cbuf_get_chain(len); + if(!newbuf) + return NULL; + + // find the starting cbuf in the chain to copy from + buf = chain; + buf_offset = 0; + while(offset > 0) { + if(buf == NULL) { + cbuf_free_chain(newbuf); + dprintf("cbuf_duplicate_chain: end of chain reached too early!\n"); + return NULL; + } + if(offset < buf->len) { + // this is the one + buf_offset = offset; + break; + } + offset -= buf->len; + buf = buf->next; + } + + destbuf = newbuf; + dest_buf_offset = 0; + while(len > 0) { + size_t to_copy; + + if(buf == NULL) { + cbuf_free_chain(newbuf); + dprintf("cbuf_duplicate_chain: end of source chain reached too early!\n"); + return NULL; + } + if(destbuf == NULL) { + cbuf_free_chain(newbuf); + dprintf("cbuf_duplicate_chain: end of destination chain reached too early!\n"); + return NULL; + } + + to_copy = min(destbuf->len - dest_buf_offset, buf->len - buf_offset); + to_copy = min(to_copy, len); + memcpy((char *)destbuf->data + dest_buf_offset, (char *)buf->data + buf_offset, to_copy); + + len -= to_copy; + if(to_copy + buf_offset == buf->len) { + buf = buf->next; + buf_offset = 0; + } else { + buf_offset += to_copy; + } + if(to_copy + dest_buf_offset == destbuf->len) { + destbuf = destbuf->next; + dest_buf_offset = 0; + } else { + dest_buf_offset += to_copy; + } + } + + return newbuf; +} + + +cbuf *cbuf_merge_chains(cbuf *chain1, cbuf *chain2) +{ + cbuf *buf; + + if(!chain1 && !chain2) + return NULL; + if(!chain1) + return chain2; + if(!chain2) + return chain1; + + if((chain1->flags & CBUF_FLAG_CHAIN_HEAD) == 0) { + dprintf("cbuf_merge_chain: chain at %p not head\n", chain1); + return NULL; + } + + if((chain2->flags & CBUF_FLAG_CHAIN_HEAD) == 0) { + dprintf("cbuf_merge_chain: chain at %p not head\n", chain2); + return NULL; + } + + // walk to the end of the first chain and tag the second one on + buf = chain1; + while(buf->next) + buf = buf->next; + + buf->next = chain2; + + // modify the flags on the chain headers + buf->flags &= ~CBUF_FLAG_CHAIN_TAIL; + chain1->total_len += chain2->total_len; + chain2->flags &= ~CBUF_FLAG_CHAIN_HEAD; + + return chain1; +} + +size_t cbuf_get_len(cbuf *buf) +{ + if(!buf) + return ERR_INVALID_ARGS; + + if(buf->flags & CBUF_FLAG_CHAIN_HEAD) { + return buf->total_len; + } else { + int len = 0; + while(buf) { + len += buf->len; + buf = buf->next; + } + return len; + } +} + +void *cbuf_get_ptr(cbuf *buf, size_t offset) +{ + while(buf) { + if(buf->len > offset) + return (void *)((int)buf->data + offset); + if(buf->len > offset) + return NULL; + offset -= buf->len; + buf = buf->next; + } + return NULL; +} + +int cbuf_is_contig_region(cbuf *buf, size_t start, size_t end) +{ + while(buf) { + if(buf->len > start) { + if(buf->len - start >= end) + return 1; + else + return 0; + } + start -= buf->len; + end -= buf->len; + buf = buf->next; + } + return 0; +} + +uint16 cbuf_ones_cksum16(cbuf *buf, size_t offset, size_t len) +{ + uint16 sum = 0; + int swapped = 0; + + if(!buf) + return 0; + if((buf->flags & CBUF_FLAG_CHAIN_HEAD) == 0) + return 0; + + // find the start ptr + while(buf) { + if(buf->len > offset) + break; + if(buf->len > offset) + return 0; + offset -= buf->len; + buf = buf->next; + } + + // start checksumming + while(buf && len > 0) { + void *ptr = (void *)((addr)buf->data + offset); + size_t plen = min(len, buf->len - offset); + + sum = ones_sum16(sum, ptr, plen); + + len -= plen; + buf = buf->next; + + // if the pointer was odd, or the length was odd, but not both, + // the checksum was swapped + if((buf && len > 0) && (((offset % 2) && ((plen % 2) == 0)) || (((offset % 2) == 0) && (plen % 2)))) { + swapped ^= 1; + sum = ((sum & 0xff) << 8) | ((sum >> 8) & 0xff); + } + offset = 0; + } + + if (swapped) + sum = ((sum & 0xff) << 8) | ((sum >> 8) & 0xff); + + return ~sum; +} + +int cbuf_truncate_head(cbuf *buf, size_t trunc_bytes) +{ + cbuf *head = buf; + + if(!buf) + return ERR_INVALID_ARGS; + if((buf->flags & CBUF_FLAG_CHAIN_HEAD) == 0) + return ERR_INVALID_ARGS; + + while(buf && trunc_bytes > 0) { + int to_trunc; + + to_trunc = min(trunc_bytes, buf->len); + + buf->len -= to_trunc; + buf->data = (void *)((int)buf->data + to_trunc); + + trunc_bytes -= to_trunc; + head->total_len -= to_trunc; + buf = buf->next; + } + + return 0; +} + +int cbuf_truncate_tail(cbuf *buf, size_t trunc_bytes) +{ + size_t offset; + size_t buf_offset; + cbuf *head = buf; + + if(!buf) + return ERR_INVALID_ARGS; + if((buf->flags & CBUF_FLAG_CHAIN_HEAD) == 0) + return ERR_INVALID_ARGS; + + offset = buf->total_len - trunc_bytes; + buf_offset = 0; + while(buf && offset > 0) { + if(offset < buf->len) { + // this is the one + buf_offset = offset; + break; + } + offset -= buf->len; + buf = buf->next; + } + if(!buf) + return ERR_GENERAL; + + head->total_len -= buf->len - buf_offset; + buf->len -= buf->len - buf_offset; + + // clear out the rest of the buffers in this chain + buf = buf->next; + while(buf) { + head->total_len -= buf->len; + buf->len = 0; + buf = buf->next; + } + + return B_NO_ERROR; +} + +static void dbg_dump_cbuf_freelists(int argc, char **argv) +{ + cbuf *buf; + + dprintf("cbuf_free_list:\n"); + for(buf = cbuf_free_list; buf; buf = buf->next) + dprintf("%p ", buf); + dprintf("\n"); + + dprintf("cbuf_free_noblock_list:\n"); + for(buf = cbuf_free_noblock_list; buf; buf = buf->next) + dprintf("%p ", buf); + dprintf("\n"); +} + +void cbuf_test() +{ + cbuf *buf, *buf2; + char temp[1024]; + unsigned int i; + + dprintf("starting cbuffer test\n"); + + buf = cbuf_get_chain(32); + if(!buf) + panic("cbuf_test: failed allocation of 32\n"); + + buf2 = cbuf_get_chain(3*1024*1024); + if(!buf2) + panic("cbuf_test: failed allocation of 3mb\n"); + + buf = cbuf_merge_chains(buf2, buf); + + cbuf_free_chain(buf); + + dprintf("allocating too much...\n"); + + buf = cbuf_get_chain(128*1024*1024); + if(buf) + panic("cbuf_test: should have failed to allocate 128mb\n"); + + dprintf("touching memory allocated by cbuf\n"); + + buf = cbuf_get_chain(7*1024*1024); + if(!buf) + panic("cbuf_test: failed allocation of 7mb\n"); + + for(i=0; i < sizeof(temp); i++) + temp[i] = i; + for(i=0; i<7*1024*1024 / sizeof(temp); i++) { + if(i % 128 == 0) dprintf("%Lud\n", (long long)(i*sizeof(temp))); + cbuf_memcpy_to_chain(buf, i*sizeof(temp), temp, sizeof(temp)); + } + cbuf_free_chain(buf); + + dprintf("finished cbuffer test\n"); +} + +int cbuf_init() +{ + cbuf *buf; + int i; + + cbuf_free_list = NULL; + cbuf_free_noblock_list = NULL; + noblock_spin = 0; + cbuf_lowlevel_spinlock = 0; + + // add the debug command + dbg_add_command(&dbg_dump_cbuf_freelists, "cbuf_freelist", "Dumps the cbuf free lists"); + + free_list_sem = create_sem(1, "cbuf_free_list_sem"); + if(free_list_sem < 0) { + panic("cbuf_init: error creating cbuf_free_list_sem\n"); + return ENOMEM; + } + + cbuf_region_id = vm_create_anonymous_region(vm_get_kernel_aspace_id(), "cbuf region", + (void **)&cbuf_region, REGION_ADDR_ANY_ADDRESS, CBUF_REGION_SIZE, REGION_WIRING_LAZY, LOCK_RW|LOCK_KERNEL); + if(cbuf_region_id < 0) { + panic("cbuf_init: error creating cbuf region\n"); + return ENOMEM; + } + + cbuf_bitmap_region_id = vm_create_anonymous_region(vm_get_kernel_aspace_id(), "cbuf bitmap region", + (void **)&cbuf_bitmap, REGION_ADDR_ANY_ADDRESS, + CBUF_BITMAP_SIZE / 8, REGION_WIRING_WIRED, LOCK_RW|LOCK_KERNEL); + if(cbuf_region_id < 0) { + panic("cbuf_init: error creating cbuf bitmap region\n"); + return ENOMEM; + } + + // initialize the bitmap + for(i=0; i +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +// from con.h +enum { + CONSOLE_OP_WRITEXY = 2376 +}; + +struct console_op_xy_struct { + int x; + int y; + char buf[256]; +}; + +static int console_fd = -1; + +int kprintf(const char *fmt, ...) +{ + int ret = 0; + va_list args; + char temp[256]; + + if(console_fd >= 0) { + va_start(args, fmt); + ret = vsprintf(temp,fmt,args); + va_end(args); + + sys_write(console_fd, temp, 0, ret); + } + return ret; +} + +int kprintf_xy(int x, int y, const char *fmt, ...) +{ + int ret = 0; + va_list args; + struct console_op_xy_struct buf; + + if(console_fd >= 0) { + va_start(args, fmt); + ret = vsprintf(buf.buf,fmt,args); + va_end(args); + + buf.x = x; + buf.y = y; + sys_ioctl(console_fd, CONSOLE_OP_WRITEXY, &buf, ret + sizeof(buf.x) + sizeof(buf.y)); + } + return ret; +} + +int con_init(kernel_args *ka) +{ + dprintf("con_init: entry\n"); + + console_fd = sys_open("/dev/console", STREAM_TYPE_DEVICE, 0); + dprintf("console_fd = %d\n", console_fd); + + return 0; +} diff --git a/src/kernel/core/cpu.c b/src/kernel/core/cpu.c new file mode 100644 index 0000000000..b216af7320 --- /dev/null +++ b/src/kernel/core/cpu.c @@ -0,0 +1,156 @@ +/* This file contains the atomic_* and cpu functions (init, etc). */ + +/* +** Copyright 2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include + +#include + +/* global per-cpu structure */ +cpu_ent cpu[MAX_BOOT_CPUS]; + +int cpu_init(kernel_args *ka) +{ + int i; + + memset(cpu, 0, sizeof(cpu)); + for(i = 0; i < MAX_BOOT_CPUS; i++) { + cpu[i].info.cpu_num = i; + } + + return arch_cpu_init(ka); +} + +int cpu_preboot_init(kernel_args *ka) +{ + return arch_cpu_preboot_init(ka); +} + +int user_atomic_add(int *uval, int incr) +{ + int val; + int ret; + + if((addr)uval >= KERNEL_BASE && (addr)uval <= KERNEL_TOP) + goto error; + + if(user_memcpy(&val, uval, sizeof(val)) < 0) + goto error; + + ret = val; + val += incr; + + if(user_memcpy(uval, &val, sizeof(val)) < 0) + goto error; + + return ret; + +error: + // XXX kill the app + return -1; +} + +int user_atomic_and(int *uval, int incr) +{ + int val; + int ret; + + if((addr)uval >= KERNEL_BASE && (addr)uval <= KERNEL_TOP) + goto error; + + if(user_memcpy(&val, uval, sizeof(val)) < 0) + goto error; + + ret = val; + val &= incr; + + if(user_memcpy(uval, &val, sizeof(val)) < 0) + goto error; + + return ret; + +error: + // XXX kill the app + return -1; +} + +int user_atomic_or(int *uval, int incr) +{ + int val; + int ret; + + if((addr)uval >= KERNEL_BASE && (addr)uval <= KERNEL_TOP) + goto error; + + if(user_memcpy(&val, uval, sizeof(val)) < 0) + goto error; + + ret = val; + val |= incr; + + if(user_memcpy(uval, &val, sizeof(val)) < 0) + goto error; + + return ret; + +error: + // XXX kill the app + return -1; +} + +int user_atomic_set(int *uval, int set_to) +{ + int val; + int ret; + + if((addr)uval >= KERNEL_BASE && (addr)uval <= KERNEL_TOP) + goto error; + + if(user_memcpy(&val, uval, sizeof(val)) < 0) + goto error; + + ret = val; + val = set_to; + + if(user_memcpy(uval, &val, sizeof(val)) < 0) + goto error; + + return ret; + +error: + // XXX kill the app + return -1; +} + +int user_test_and_set(int *uval, int set_to, int test_val) +{ + int val; + int ret; + + if((addr)uval >= KERNEL_BASE && (addr)uval <= KERNEL_TOP) + goto error; + + if(user_memcpy(&val, uval, sizeof(val)) < 0) + goto error; + + ret = val; + if(val == test_val) { + val = set_to; + if(user_memcpy(uval, &val, sizeof(val)) < 0) + goto error; + } + + return ret; + +error: + // XXX kill the app + return -1; +} + diff --git a/src/kernel/core/debug.c b/src/kernel/core/debug.c new file mode 100644 index 0000000000..8d5e82e090 --- /dev/null +++ b/src/kernel/core/debug.c @@ -0,0 +1,380 @@ +/* This file contains the debugger */ + +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + + +int dbg_register_file[2][14]; /* XXXmpetit -- must be made generic */ + + +static bool serial_debug_on = false; +static spinlock_t dbg_spinlock = 0; +static int debugger_on_cpu = -1; + +struct debugger_command +{ + struct debugger_command *next; + void (*func)(int, char **); + const char *cmd; + const char *description; +}; + +static struct debugger_command *commands; + +#define LINE_BUF_SIZE 1024 +#define MAX_ARGS 16 +#define HISTORY_SIZE 16 + +static char line_buf[HISTORY_SIZE][LINE_BUF_SIZE] = { "", }; +static char parse_line[LINE_BUF_SIZE] = ""; +static int cur_line = 0; +static char *args[MAX_ARGS] = { NULL, }; + +#define distance(a, b) ((a) < (b) ? (b) - (a) : (a) - (b)) + +static int debug_read_line(char *buf, int max_len) +{ + char c; + int ptr = 0; + bool done = false; + int cur_history_spot = cur_line; + + while(!done) { + c = arch_dbg_con_read(); + switch(c) { + case '\n': + case '\r': + buf[ptr++] = '\0'; + dbg_puts("\n"); + done = true; + break; + case 8: // backspace + if(ptr > 0) { + dbg_puts("\x1b[1D"); // move to the left one + dbg_putch(' '); + dbg_puts("\x1b[1D"); // move to the left one + ptr--; + } + break; + case 27: // escape sequence + c = arch_dbg_con_read(); // should be '[' + c = arch_dbg_con_read(); + switch(c) { + case 67: // right arrow acts like space + buf[ptr++] = ' '; + dbg_putch(' '); + break; + case 68: // left arrow acts like backspace + if(ptr > 0) { + dbg_puts("\x1b[1D"); // move to the left one + dbg_putch(' '); + dbg_puts("\x1b[1D"); // move to the left one + ptr--; + } + break; + case 65: // up arrow + case 66: // down arrow + { + int history_line = 0; + +// dprintf("1c %d h %d ch %d\n", cur_line, history_line, cur_history_spot); + + if(c == 65) { + // up arrow + history_line = cur_history_spot - 1; + if(history_line < 0) + history_line = HISTORY_SIZE - 1; + } else { + // down arrow + if(cur_history_spot != cur_line) { + history_line = cur_history_spot + 1; + if(history_line >= HISTORY_SIZE) + history_line = 0; + } else { + break; // nothing to do here + } + } + +// dprintf("2c %d h %d ch %d\n", cur_line, history_line, cur_history_spot); + + // swap the current line with something from the history + if(ptr > 0) + dprintf("\x1b[%dD", ptr); // move to beginning of line + + strcpy(buf, line_buf[history_line]); + ptr = strlen(buf); + dprintf("%s\x1b[K", buf); // print the line and clear the rest + cur_history_spot = history_line; + break; + } + default: + break; + } + break; + case '$': + case '+': + /* HACK ALERT!!! + * + * If we get a $ at the beginning of the line + * we assume we are talking with GDB + */ + if(ptr == 0) { + strcpy(buf, "gdb"); + ptr= 4; + done= true; + break; + } else { + /* fall thru */ + } + default: + buf[ptr++] = c; + dbg_putch(c); + } + if(ptr >= max_len - 2) { + buf[ptr++] = '\0'; + dbg_puts("\n"); + done = true; + break; + } + } + return ptr; +} + +static int debug_parse_line(char *buf, char **argv, int *argc, int max_args) +{ + int pos = 0; + + strcpy(parse_line, buf); + + if(!isspace(parse_line[0])) { + argv[0] = parse_line; + *argc = 1; + } else { + *argc = 0; + } + + while(parse_line[pos] != '\0') { + if(isspace(parse_line[pos])) { + parse_line[pos] = '\0'; + // scan all of the whitespace out of this + while(isspace(parse_line[++pos])) + ; + if(parse_line[pos] == '\0') + break; + argv[*argc] = &parse_line[pos]; + (*argc)++; + + if(*argc >= max_args - 1) + break; + } + pos++; + } + + return *argc; +} + +static void kernel_debugger_loop() +{ + int argc; + struct debugger_command *cmd; + + int_disable_interrupts(); + + dprintf("kernel debugger on cpu %d\n", smp_get_current_cpu()); + debugger_on_cpu = smp_get_current_cpu(); + + for(;;) { + dprintf("> "); + debug_read_line(line_buf[cur_line], LINE_BUF_SIZE); + debug_parse_line(line_buf[cur_line], args, &argc, MAX_ARGS); + if(argc <= 0) + continue; + + debugger_on_cpu = smp_get_current_cpu(); + + cmd = commands; + while(cmd != NULL) { + if(strcmp(args[0], cmd->cmd) == 0) { + cmd->func(argc, args); + } + cmd = cmd->next; + } + cur_line++; + if(cur_line >= HISTORY_SIZE) + cur_line = 0; + } +} + +void kernel_debugger() +{ + dbg_save_registers(&(dbg_register_file[smp_get_current_cpu()][0])); + + kernel_debugger_loop(); +} + +int panic(const char *fmt, ...) +{ + int ret = 0; + va_list args; + char temp[128]; + int state; + + dbg_set_serial_debug(true); + + state = int_disable_interrupts(); + + va_start(args, fmt); + ret = vsprintf(temp, fmt, args); + va_end(args); + + dprintf("PANIC%d: %s", smp_get_current_cpu(), temp); + + if(debugger_on_cpu != smp_get_current_cpu()) { + // halt all of the other cpus + + // XXX need to flush current smp mailbox to make sure this goes + // through. Otherwise it'll hang + smp_send_broadcast_ici(SMP_MSG_CPU_HALT, 0, 0, 0, NULL, SMP_MSG_FLAG_SYNC); + } + + kernel_debugger(); + + int_restore_interrupts(state); + return ret; +} + +int dprintf(const char *fmt, ...) +{ + va_list args; + char temp[512]; + int ret = 0; + + if(serial_debug_on) { + va_start(args, fmt); + ret = vsprintf(temp, fmt, args); + va_end(args); + + dbg_puts(temp); + } + return ret; +} + +char dbg_putch(char c) +{ + char ret; + int flags = int_disable_interrupts(); + acquire_spinlock(&dbg_spinlock); + + if(serial_debug_on) + ret = arch_dbg_con_putch(c); + else + ret = c; + + release_spinlock(&dbg_spinlock); + int_restore_interrupts(flags); + + return ret; +} + +void dbg_puts(const char *s) +{ + int flags = int_disable_interrupts(); + acquire_spinlock(&dbg_spinlock); + + if(serial_debug_on) + arch_dbg_con_puts(s); + + release_spinlock(&dbg_spinlock); + int_restore_interrupts(flags); +} + +int dbg_add_command(void (*func)(int, char **), const char *name, const char *desc) +{ + int flags; + struct debugger_command *cmd; + + cmd = (struct debugger_command *)kmalloc(sizeof(struct debugger_command)); + if(cmd == NULL) + return ENOMEM; + + cmd->func = func; + cmd->cmd = name; + cmd->description = desc; + + flags = int_disable_interrupts(); + acquire_spinlock(&dbg_spinlock); + + cmd->next = commands; + commands = cmd; + + release_spinlock(&dbg_spinlock); + int_restore_interrupts(flags); + + return B_NO_ERROR; +} + +static void cmd_reboot(int argc, char **argv) +{ + reboot(); +} + +static void cmd_help(int argc, char **argv) +{ + struct debugger_command *cmd; + + dprintf("debugger commands:\n"); + cmd = commands; + while(cmd != NULL) { + dprintf("%-32s\t\t%s\n", cmd->cmd, cmd->description); + cmd = cmd->next; + } +} + +int dbg_init(kernel_args *ka) +{ + commands = NULL; + + return arch_dbg_con_init(ka); +} + +int dbg_init2(kernel_args *ka) +{ + dbg_add_command(&cmd_help, "help", "List all debugger commands"); + dbg_add_command(&cmd_reboot, "reboot", "Reboot"); + dbg_add_command(&cmd_gdb, "gdb", "Connect to remote gdb"); + + return B_NO_ERROR; +} + +bool dbg_set_serial_debug(bool new_val) +{ + int temp = serial_debug_on; + serial_debug_on = new_val; + return temp; +} + +bool dbg_get_serial_debug() +{ + return serial_debug_on; +} + diff --git a/src/kernel/core/elf.c b/src/kernel/core/elf.c new file mode 100644 index 0000000000..6bfec1a312 --- /dev/null +++ b/src/kernel/core/elf.c @@ -0,0 +1,977 @@ +/* Contains the ELF loader */ + +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + +struct elf_region { + region_id id; + addr start; + addr size; + long delta; +}; + +struct elf_image_info { + struct elf_image_info *next; + image_id id; + int ref_count; + void *vnode; + struct elf_region regions[2]; // describes the text and data regions + addr dynamic_ptr; // pointer to the dynamic section + struct elf_linked_image *linked_images; + + struct Elf32_Ehdr *eheader; + + // pointer to symbol participation data structures + char *needed; + unsigned int *symhash; + struct Elf32_Sym *syms; + char *strtab; + struct Elf32_Rel *rel; + int rel_len; + struct Elf32_Rela *rela; + int rela_len; + struct Elf32_Rel *pltrel; + int pltrel_len; +}; + +// XXX TK this shall contain a list of linked images +// (don't know enough about ELF how to get this list) +typedef struct elf_linked_image { + struct elf_linked_image *next; + struct elf_image_info *image; +} elf_linked_image; + +static struct elf_image_info *kernel_images = NULL; +static struct elf_image_info *kernel_image = NULL; +static mutex image_lock; +static mutex image_load_lock; +static image_id next_image_id = 0; + +#define STRING(image, offset) ((char *)(&(image)->strtab[(offset)])) +#define SYMNAME(image, sym) STRING(image, (sym)->st_name) +#define SYMBOL(image, num) ((struct Elf32_Sym *)&(image)->syms[num]) +#define HASHTABSIZE(image) ((image)->symhash[0]) +#define HASHBUCKETS(image) ((unsigned int *)&(image)->symhash[2]) +#define HASHCHAINS(image) ((unsigned int *)&(image)->symhash[2+HASHTABSIZE(image)]) + +static void insert_image_in_list(struct elf_image_info *image) +{ + mutex_lock(&image_lock); + + image->next = kernel_images; + kernel_images = image; + + mutex_unlock(&image_lock); +} + +static void remove_image_from_list(struct elf_image_info *image) +{ + struct elf_image_info **ptr; + + mutex_lock(&image_lock); + + for(ptr = &kernel_images; *ptr; ptr = &(*ptr)->next) { + if(*ptr == image) { + *ptr = image->next; + image->next = 0; + break; + } + } + + mutex_unlock(&image_lock); +} + +static struct elf_image_info *find_image(image_id id) +{ + struct elf_image_info *image; + + mutex_lock(&image_lock); + + for(image = kernel_images; image; image = image->next) { + if(image->id == id) + break; + } + mutex_unlock(&image_lock); + + return image; +} + +static struct elf_image_info *find_image_by_vnode(void *vnode) +{ + struct elf_image_info *image; + + mutex_lock(&image_lock); + + for(image = kernel_images; image; image = image->next) { + if(image->vnode == vnode) + break; + } + mutex_unlock(&image_lock); + + return image; +} + +static struct elf_image_info *create_image_struct() +{ + struct elf_image_info *image; + + image = (struct elf_image_info *)kmalloc(sizeof(struct elf_image_info)); + if(!image) + return NULL; + memset(image, 0, sizeof(struct elf_image_info)); + image->regions[0].id = -1; + image->regions[1].id = -1; + image->id = atomic_add(&next_image_id, 1); + image->ref_count = 1; + image->linked_images = NULL; + return image; +} + +static unsigned long elf_hash(const unsigned char *name) +{ + unsigned long hash = 0; + unsigned long temp; + + while(*name) { + hash = (hash << 4) + *name++; + if((temp = hash & 0xf0000000)) + hash ^= temp >> 24; + hash &= ~temp; + } + return hash; +} + +static void dump_image_info(struct elf_image_info *image) +{ + int i; + + dprintf("elf_image_info at %p:\n", image); + dprintf(" next %p\n", image->next); + dprintf(" id 0x%x\n", image->id); + for(i=0; i<2; i++) { + dprintf(" regions[%d].id 0x%x\n", i, image->regions[i].id); + dprintf(" regions[%d].start 0x%lx\n", i, image->regions[i].start); + dprintf(" regions[%d].size 0x%lx\n", i, image->regions[i].size); + dprintf(" regions[%d].delta %ld\n", i, image->regions[i].delta); + } + dprintf(" dynamic_ptr 0x%lx\n", image->dynamic_ptr); + dprintf(" needed %p\n", image->needed); + dprintf(" symhash %p\n", image->symhash); + dprintf(" syms %p\n", image->syms); + dprintf(" strtab %p\n", image->strtab); + dprintf(" rel %p\n", image->rel); + dprintf(" rel_len 0x%x\n", image->rel_len); + dprintf(" rela %p\n", image->rela); + dprintf(" rela_len 0x%x\n", image->rela_len); +} + +/* XXX - Currently unused +static void dump_symbol(struct elf_image_info *image, struct Elf32_Sym *sym) +{ + + dprintf("symbol at %p, in image %p\n", sym, image); + + dprintf(" name index %d, '%s'\n", sym->st_name, SYMNAME(image, sym)); + dprintf(" st_value 0x%x\n", sym->st_value); + dprintf(" st_size %d\n", sym->st_size); + dprintf(" st_info 0x%x\n", sym->st_info); + dprintf(" st_other 0x%x\n", sym->st_other); + dprintf(" st_shndx %d\n", sym->st_shndx); +} +*/ + +static struct Elf32_Sym *elf_find_symbol(struct elf_image_info *image, const char *name) +{ + unsigned int hash; + unsigned int i; + + if(!image->dynamic_ptr) + return NULL; + + hash = elf_hash(name) % HASHTABSIZE(image); + for(i = HASHBUCKETS(image)[hash]; i != STN_UNDEF; i = HASHCHAINS(image)[i]) { + if(!strcmp(SYMNAME(image, &image->syms[i]), name)) { + return &image->syms[i]; + } + } + + return NULL; +} + +addr elf_lookup_symbol(image_id id, const char *symbol) +{ + struct elf_image_info *image; + struct Elf32_Sym *sym; + + //dprintf( "elf_lookup_symbol: %s\n", symbol ); + + image = find_image(id); + if(!image) + return 0; + + sym = elf_find_symbol(image, symbol); + if(!sym) + return 0; + + if(sym->st_shndx == SHN_UNDEF) { + return 0; + } + + /*dprintf( "found: %x (%x + %x)\n", sym->st_value + image->regions[0].delta, + sym->st_value, image->regions[0].delta );*/ + return sym->st_value + image->regions[0].delta; +} + +static int elf_parse_dynamic_section(struct elf_image_info *image) +{ + struct Elf32_Dyn *d; + int i; + int needed_offset = -1; + +// dprintf("top of elf_parse_dynamic_section\n"); + + image->symhash = 0; + image->syms = 0; + image->strtab = 0; + + d = (struct Elf32_Dyn *)image->dynamic_ptr; + if(!d) + return ERR_GENERAL; + + for(i=0; d[i].d_tag != DT_NULL; i++) { + switch(d[i].d_tag) { + case DT_NEEDED: + needed_offset = d[i].d_un.d_ptr + image->regions[0].delta; + break; + case DT_HASH: + image->symhash = (unsigned int *)(d[i].d_un.d_ptr + image->regions[0].delta); + break; + case DT_STRTAB: + image->strtab = (char *)(d[i].d_un.d_ptr + image->regions[0].delta); + break; + case DT_SYMTAB: + image->syms = (struct Elf32_Sym *)(d[i].d_un.d_ptr + image->regions[0].delta); + break; + case DT_REL: + image->rel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta); + break; + case DT_RELSZ: + image->rel_len = d[i].d_un.d_val; + break; + case DT_RELA: + image->rela = (struct Elf32_Rela *)(d[i].d_un.d_ptr + image->regions[0].delta); + break; + case DT_RELASZ: + image->rela_len = d[i].d_un.d_val; + break; + // TK: procedure linkage table + case DT_JMPREL: + image->pltrel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta); + break; + case DT_PLTRELSZ: + image->pltrel_len = d[i].d_un.d_val; + break; + default: + continue; + } + } + + // lets make sure we found all the required sections + if(!image->symhash || !image->syms || !image->strtab) + return ERR_GENERAL; + +// dprintf("needed_offset = %d\n", needed_offset); + + if(needed_offset >= 0) + image->needed = STRING(image, needed_offset); + + return B_NO_ERROR; +} + +// this function first tries to see if the first image and it's already resolved symbol is okay, otherwise +// it tries to link against the shared_image +// XXX gross hack and needs to be done better +static int elf_resolve_symbol(struct elf_image_info *image, struct Elf32_Sym *sym, struct elf_image_info *shared_image, const char *sym_prepend,addr *sym_addr) +{ + struct Elf32_Sym *sym2; + char new_symname[512]; + + switch(sym->st_shndx) { + case SHN_UNDEF: + // patch the symbol name + strlcpy(new_symname, sym_prepend, sizeof(new_symname)); + strlcat(new_symname, SYMNAME(image, sym), sizeof(new_symname)); + + // it's undefined, must be outside this image, try the other image + sym2 = elf_find_symbol(shared_image, new_symname); + if(!sym2) { + dprintf("!sym2: elf_resolve_symbol: could not resolve symbol '%s'\n", new_symname); + return ERR_ELF_RESOLVING_SYMBOL; + } + + // make sure they're the same type + if(ELF32_ST_TYPE(sym->st_info) != ELF32_ST_TYPE(sym2->st_info)) { + dprintf("elf_resolve_symbol: found symbol '%s' in shared image but wrong type\n", new_symname); + return ERR_ELF_RESOLVING_SYMBOL; + } + + if(ELF32_ST_BIND(sym2->st_info) != STB_GLOBAL && ELF32_ST_BIND(sym2->st_info) != STB_WEAK) { +// dprintf("elf_resolve_symbol: found symbol '%s' but not exported\n", new_symname); + return ERR_ELF_RESOLVING_SYMBOL; + } + + *sym_addr = sym2->st_value + shared_image->regions[0].delta; + return B_NO_ERROR; + case SHN_ABS: + *sym_addr = sym->st_value; + return B_NO_ERROR; + case SHN_COMMON: + // XXX finish this +// dprintf("elf_resolve_symbol: COMMON symbol, finish me!\n"); + return ERR_NOT_IMPLEMENTED_YET; + default: + // standard symbol + *sym_addr = sym->st_value + image->regions[0].delta; + return B_NO_ERROR; + } +} + +static int elf_relocate_rel(struct elf_image_info *image, const char *sym_prepend, + struct Elf32_Rel *rel, int rel_len ) +{ + int i; + struct Elf32_Sym *sym; + int vlErr; + addr S; + addr A; + addr P; + addr final_val; + + S = A = P = 0; + + for(i = 0; i * (int)sizeof(struct Elf32_Rel) < rel_len; i++) { + //dprintf("looking at rel type %d, offset 0x%x\n", ELF32_R_TYPE(rel[i].r_info), rel[i].r_offset); + + // calc S + switch(ELF32_R_TYPE(rel[i].r_info)) { + case R_386_32: + case R_386_PC32: + case R_386_GLOB_DAT: + case R_386_JMP_SLOT: + case R_386_GOTOFF: + sym = SYMBOL(image, ELF32_R_SYM(rel[i].r_info)); + + vlErr = elf_resolve_symbol(image, sym, kernel_image, sym_prepend, &S); + if (vlErr < 0) + return vlErr; +// dprintf("S 0x%x\n", S); + } + // calc A + switch(ELF32_R_TYPE(rel[i].r_info)) { + case R_386_32: + case R_386_PC32: + case R_386_GOT32: + case R_386_PLT32: + case R_386_RELATIVE: + case R_386_GOTOFF: + case R_386_GOTPC: + A = *(addr *)(image->regions[0].delta + rel[i].r_offset); +// dprintf("A 0x%x\n", A); + break; + } + // calc P + switch(ELF32_R_TYPE(rel[i].r_info)) { + case R_386_PC32: + case R_386_GOT32: + case R_386_PLT32: + case R_386_GOTPC: + P = image->regions[0].delta + rel[i].r_offset; +// dprintf("P 0x%x\n", P); + break; + } + + switch(ELF32_R_TYPE(rel[i].r_info)) { + case R_386_NONE: + continue; + case R_386_32: + final_val = S + A; + break; + case R_386_PC32: + final_val = S + A - P; + break; + case R_386_RELATIVE: + // B + A; + final_val = image->regions[0].delta + A; + break; + case R_386_JMP_SLOT: + case R_386_GLOB_DAT: + final_val = S; + sym = SYMBOL(image, ELF32_R_SYM(rel[i].r_info)); + break; + default: + sym = SYMBOL(image, ELF32_R_SYM(rel[i].r_info)); + dprintf("%s: unhandled relocation type %d\n", SYMNAME(image, sym), ELF32_R_TYPE(rel[i].r_info)); + return EPERM; + } + *(addr *)(image->regions[0].delta + rel[i].r_offset) = final_val; + } + + return B_NO_ERROR; +} + +// XXX for now just link against the kernel +static int elf_relocate(struct elf_image_info *image, const char *sym_prepend) +{ + int res = B_NO_ERROR; + int i; +// dprintf("top of elf_relocate\n"); + + // deal with the rels first + if( image->rel ) { + dprintf( "total %i relocs\n", image->rel_len / (int)sizeof(struct Elf32_Rel) ); + res = elf_relocate_rel( image, sym_prepend, image->rel, image->rel_len ); + + if(res) + return res; + } + + if( image->pltrel ) { + dprintf( "total %i plt-relocs\n", image->pltrel_len / (int)sizeof(struct Elf32_Rel) ); + res = elf_relocate_rel( image, sym_prepend, image->pltrel, image->pltrel_len ); + + if( res ) + return res; + } + + if(image->rela) { + dprintf("RELA relocations not supported\n"); + return ERR_NOT_ALLOWED; + for(i = 1; i * (int)sizeof(struct Elf32_Rela) < image->rela_len; i++) { + dprintf("rela: type %d\n", ELF32_R_TYPE(image->rela[i].r_info)); + } + } + return res; +} + +static int verify_eheader(struct Elf32_Ehdr *eheader) +{ + if(memcmp(eheader->e_ident, ELF_MAGIC, 4) != 0) + return ERR_INVALID_BINARY; + + if(eheader->e_ident[4] != ELFCLASS32) + return ERR_INVALID_BINARY; + + if(eheader->e_phoff == 0) + return ERR_INVALID_BINARY; + + if(eheader->e_phentsize < sizeof(struct Elf32_Phdr)) + return ERR_INVALID_BINARY; + + return 0; +} + +int elf_load_uspace(const char *path, struct proc *p, int flags, addr *entry) +{ + struct Elf32_Ehdr eheader; + struct Elf32_Phdr *pheaders = NULL; + int fd; + int err; + int i; + ssize_t len; + + dprintf("elf_load: entry path '%s', proc %p\n", path, p); + + fd = sys_open(path, STREAM_TYPE_FILE, 0); + if(fd < 0) + return fd; + + len = sys_read(fd, &eheader, 0, sizeof(eheader)); + if(len < 0) { + err = len; + goto error; + } + if(len != sizeof(eheader)) { + // short read + err = ERR_INVALID_BINARY; + goto error; + } + err = verify_eheader(&eheader); + if(err < 0) + goto error; + + pheaders = (struct Elf32_Phdr *)kmalloc(eheader.e_phnum * eheader.e_phentsize); + if(pheaders == NULL) { + dprintf("error allocating space for program headers\n"); + err = ERR_NO_MEMORY; + goto error; + } + + dprintf("reading in program headers at 0x%x, len 0x%x\n", eheader.e_phoff, eheader.e_phnum * eheader.e_phentsize); + len = sys_read(fd, pheaders, eheader.e_phoff, eheader.e_phnum * eheader.e_phentsize); + if(len < 0) { + err = len; + dprintf("error reading in program headers\n"); + goto error; + } + if(len != eheader.e_phnum * eheader.e_phentsize) { + dprintf("short read while reading in program headers\n"); + err = -1; + goto error; + } + + for(i=0; i < eheader.e_phnum; i++) { + char region_name[64]; + region_id id; + char *region_addr; + + sprintf(region_name, "%s_seg%d", path, i); + + region_addr = (char *)ROUNDOWN(pheaders[i].p_vaddr, PAGE_SIZE); + if(pheaders[i].p_flags & PF_W) { + /* + * rw segment + */ + unsigned start_clearing; + unsigned to_clear; + unsigned A= pheaders[i].p_vaddr+pheaders[i].p_memsz; + unsigned B= pheaders[i].p_vaddr+pheaders[i].p_filesz; + + A= ROUNDOWN(A, PAGE_SIZE); + B= ROUNDOWN(B, PAGE_SIZE); + + id= vm_map_file( + p->_aspace_id, + region_name, + (void **)®ion_addr, + REGION_ADDR_EXACT_ADDRESS, + ROUNDUP(pheaders[i].p_filesz+ (pheaders[i].p_vaddr % PAGE_SIZE), PAGE_SIZE), + LOCK_RW, + REGION_PRIVATE_MAP, + path, + ROUNDOWN(pheaders[i].p_offset, PAGE_SIZE) + ); + if(id < 0) { + dprintf("error allocating region!\n"); + err = ERR_INVALID_BINARY; + goto error; + } + + + /* + * clean garbage brought by mmap + */ + start_clearing= + (unsigned)region_addr + + (pheaders[i].p_vaddr % PAGE_SIZE) + + pheaders[i].p_filesz; + to_clear= + ROUNDUP(pheaders[i].p_filesz+ (pheaders[i].p_vaddr % PAGE_SIZE), PAGE_SIZE) + - (pheaders[i].p_vaddr % PAGE_SIZE) + - (pheaders[i].p_filesz); + memset((void*)start_clearing, 0, to_clear); + + /* + * check if we need extra storage for the bss + */ + if(A != B) { + /* XXX - this is broken! The final comma on the 1st line means we don't do the + * subtraction? What's actually desired here? + */ + size_t bss_size= + ROUNDUP(pheaders[i].p_memsz+ (pheaders[i].p_vaddr % PAGE_SIZE), PAGE_SIZE)/*, */ + - ROUNDUP(pheaders[i].p_filesz+ (pheaders[i].p_vaddr % PAGE_SIZE), PAGE_SIZE); + + sprintf(region_name, "%s_bss%d", path, 'X'); + + region_addr+= ROUNDUP(pheaders[i].p_filesz+ (pheaders[i].p_vaddr % PAGE_SIZE), PAGE_SIZE), + id= vm_create_anonymous_region( + p->_aspace_id, + region_name, + (void **)®ion_addr, + REGION_ADDR_EXACT_ADDRESS, + bss_size, + REGION_WIRING_LAZY, + LOCK_RW + ); + if(id < 0) { + dprintf("error allocating region!\n"); + err = ERR_INVALID_BINARY; + goto error; + } + } + } else { + /* + * assume rx segment + */ + id= vm_map_file( + p->_aspace_id, + region_name, + (void **)®ion_addr, + REGION_ADDR_EXACT_ADDRESS, + ROUNDUP(pheaders[i].p_memsz + (pheaders[i].p_vaddr % PAGE_SIZE), PAGE_SIZE), + LOCK_RO, + REGION_PRIVATE_MAP, + path, + ROUNDOWN(pheaders[i].p_offset, PAGE_SIZE) + ); + if(id < 0) { + dprintf("error mapping text!\n"); + err = ERR_INVALID_BINARY; + goto error; + } + } + } + + dprintf("elf_load: done!\n"); + + *entry = eheader.e_entry; + + err = 0; + +error: + if(pheaders) + kfree(pheaders); + sys_close(fd); + + return err; +} + +image_id elf_load_kspace(const char *path, const char *sym_prepend) +{ + struct Elf32_Ehdr *eheader; + struct Elf32_Phdr *pheaders; + struct elf_image_info *image; + void *vnode = NULL; + int fd; + int err; + int i; + ssize_t len; + +// dprintf("elf_load_kspace: entry path '%s'\n", path); + + fd = sys_open(path, STREAM_TYPE_FILE, 0); + if(fd < 0) + return fd; + + err = vfs_get_vnode_from_fd(fd, true, &vnode); + if(err < 0) + goto error0; + + // XXX awful hack to keep someone else from trying to load this image + // probably not a bad thing, shouldn't be too many races + mutex_lock(&image_load_lock); + + // make sure it's not loaded already. Search by vnode + image = find_image_by_vnode(vnode); + if( image ) { + atomic_add( &image->ref_count, 1 ); + //err = ERR_NOT_ALLOWED; + goto done; + } + + eheader = (struct Elf32_Ehdr *)kmalloc( sizeof( *eheader )); + if( !eheader ) { + err = ERR_NO_MEMORY; + goto error; + } + + len = sys_read(fd, eheader, 0, sizeof(*eheader)); + if(len < 0) { + err = len; + goto error1; + } + if(len != sizeof(*eheader)) { + // short read + err = ERR_INVALID_BINARY; + goto error1; + } + err = verify_eheader(eheader); + if(err < 0) + goto error1; + + image = create_image_struct(); + if(!image) { + err = ERR_NO_MEMORY; + goto error1; + } + image->vnode = vnode; + image->eheader = eheader; + + pheaders = (struct Elf32_Phdr *)kmalloc(eheader->e_phnum * eheader->e_phentsize); + if(pheaders == NULL) { + dprintf("error allocating space for program headers\n"); + err = ERR_NO_MEMORY; + goto error2; + } + +// dprintf("reading in program headers at 0x%x, len 0x%x\n", eheader.e_phoff, eheader.e_phnum * eheader.e_phentsize); + len = sys_read(fd, pheaders, eheader->e_phoff, eheader->e_phnum * eheader->e_phentsize); + if(len < 0) { + err = len; +// dprintf("error reading in program headers\n"); + goto error3; + } + if(len != eheader->e_phnum * eheader->e_phentsize) { +// dprintf("short read while reading in program headers\n"); + err = -1; + goto error3; + } + + for(i=0; i < eheader->e_phnum; i++) { + char region_name[64]; + bool ro_segment_handled = false; + bool rw_segment_handled = false; + int image_region; + int lock; + +// dprintf("looking at program header %d\n", i); + + switch(pheaders[i].p_type) { + case PT_LOAD: + break; + case PT_DYNAMIC: + image->dynamic_ptr = pheaders[i].p_vaddr; + continue; + default: + dprintf("unhandled pheader type 0x%x\n", pheaders[i].p_type); + continue; + } + + // we're here, so it must be a PT_LOAD segment + if((pheaders[i].p_flags & (PF_R | PF_W | PF_X)) == (PF_R | PF_W)) { + // this is the writable segment + if(rw_segment_handled) { + // we've already created this segment + continue; + } + rw_segment_handled = true; + image_region = 1; + lock = LOCK_RW|LOCK_KERNEL; + sprintf(region_name, "%s_rw", path); + } else if((pheaders[i].p_flags & (PF_R | PF_W | PF_X)) == (PF_R | PF_X)) { + // this is the non-writable segment + if(ro_segment_handled) { + // we've already created this segment + continue; + } + ro_segment_handled = true; + image_region = 0; +// lock = LOCK_RO|LOCK_KERNEL; + lock = LOCK_RW|LOCK_KERNEL; + sprintf(region_name, "%s_ro", path); + } else { + dprintf("weird program header flags 0x%x\n", pheaders[i].p_flags); + continue; + } + image->regions[image_region].size = ROUNDUP(pheaders[i].p_memsz + (pheaders[i].p_vaddr % PAGE_SIZE), PAGE_SIZE); + image->regions[image_region].id = vm_create_anonymous_region(vm_get_kernel_aspace_id(), region_name, + (void **)&image->regions[image_region].start, REGION_ADDR_ANY_ADDRESS, + image->regions[image_region].size, REGION_WIRING_WIRED, lock); + if(image->regions[image_region].id < 0) { + dprintf("error allocating region!\n"); + err = ERR_INVALID_BINARY; + goto error3; + } + image->regions[image_region].delta = image->regions[image_region].start - ROUNDOWN(pheaders[i].p_vaddr, PAGE_SIZE); + +// dprintf("elf_load_kspace: created a region at 0x%x\n", image->regions[image_region].start); + + len = sys_read(fd, (void *)(image->regions[image_region].start + (pheaders[i].p_vaddr % PAGE_SIZE)), + pheaders[i].p_offset, pheaders[i].p_filesz); + if(len < 0) { + err = len; + dprintf("error reading in seg %d\n", i); + goto error4; + } + } + + if(image->regions[1].start != 0) { + if(image->regions[0].delta != image->regions[1].delta) { + dprintf("could not load binary, fix the region problem!\n"); + dump_image_info(image); + err = ERR_NO_MEMORY; + goto error4; + } + } + + // modify the dynamic ptr by the delta of the regions + image->dynamic_ptr += image->regions[0].delta; + + err = elf_parse_dynamic_section(image); + if(err < 0) + goto error4; + + err = elf_relocate(image, sym_prepend); + if(err < 0) + goto error4; + + err = 0; + + kfree(pheaders); + sys_close(fd); + + insert_image_in_list(image); + +done: + mutex_unlock(&image_load_lock); + + return image->id; + +error4: + if(image->regions[1].id >= 0) + vm_delete_region(vm_get_kernel_aspace_id(), image->regions[1].id); + if(image->regions[0].id >= 0) + vm_delete_region(vm_get_kernel_aspace_id(), image->regions[0].id); +error3: + kfree(image); +error2: + kfree(pheaders); +error1: + kfree(eheader); +error: + mutex_unlock(&image_load_lock); +error0: + if(vnode) + vfs_put_vnode_ptr(vnode); + sys_close(fd); + + return err; +} + +static int elf_unload_image( struct elf_image_info *image ); + +static int elf_unlink_relocs( struct elf_image_info *image ) +{ + elf_linked_image *link, *next_link; + + for( link = image->linked_images; link; link = next_link ) { + next_link = link->next; + elf_unload_image( link->image ); + kfree( link ); + } + + return B_NO_ERROR; +} + +static void elf_unload_image_final( struct elf_image_info *image ) +{ + int i; + + for( i = 0; i < 2; ++i ) { + vm_delete_region( vm_get_kernel_aspace_id(), image->regions[i].id ); + } + + if( image->vnode ) + vfs_put_vnode_ptr( image->vnode ); + + remove_image_from_list(image); + kfree( image->eheader ); + kfree( image ); +} + +static int elf_unload_image( struct elf_image_info *image ) +{ + if( atomic_add( &image->ref_count, -1 ) > 0 ) + return B_NO_ERROR; + + elf_unlink_relocs( image ); + elf_unload_image_final( image ); + + return B_NO_ERROR; +} + +int elf_unload_kspace( const char *path ) +{ + int fd; + int err; + void *vnode; + struct elf_image_info *image; + + fd = sys_open(path, STREAM_TYPE_FILE, 0); + if(fd < 0) + return fd; + + err = vfs_get_vnode_from_fd(fd, true, &vnode); + if(err < 0) + goto error0; + + mutex_lock(&image_load_lock); + + image = find_image_by_vnode(vnode); + if( !image ) { + dprintf( "Tried to unload image that wasn't loaded (%s)\n", path ); + err = ERR_NOT_FOUND; + goto error; + } + + err = elf_unload_image( image ); + +error: + mutex_unlock(&image_load_lock); +error0: + if(vnode) + vfs_put_vnode_ptr(vnode); + sys_close(fd); + + return err; +} + +int elf_init(kernel_args *ka) +{ + vm_region_info rinfo; + + // build a image structure for the kernel, which has already been loaded + kernel_image = create_image_struct(); + + // text segment + kernel_image->regions[0].id = vm_find_region_by_name(vm_get_kernel_aspace_id(), "kernel_ro"); + if(kernel_image->regions[0].id < 0) + panic("elf_init: could not look up kernel text segment region\n"); + vm_get_region_info(kernel_image->regions[0].id, &rinfo); + kernel_image->regions[0].start = rinfo.base; + kernel_image->regions[0].size = rinfo.size; + + // data segment + kernel_image->regions[1].id = vm_find_region_by_name(vm_get_kernel_aspace_id(), "kernel_rw"); + if(kernel_image->regions[1].id < 0) + panic("elf_init: could not look up kernel data segment region\n"); + vm_get_region_info(kernel_image->regions[1].id, &rinfo); + kernel_image->regions[1].start = rinfo.base; + kernel_image->regions[1].size = rinfo.size; + + // we know where the dynamic section is + kernel_image->dynamic_ptr = (addr)ka->kernel_dynamic_section_addr.start; + + // parse the dynamic section + if(elf_parse_dynamic_section(kernel_image) < 0) + dprintf("elf_init: WARNING elf_parse_dynamic_section couldn't find dynamic section.\n"); + + // insert it first in the list of kernel images loaded + kernel_images = NULL; + insert_image_in_list(kernel_image); + + mutex_init(&image_lock, "kimages_lock"); + mutex_init(&image_load_lock, "kimages_load_lock"); + + return 0; +} + diff --git a/src/kernel/core/faults.c b/src/kernel/core/faults.c new file mode 100644 index 0000000000..6bcbb4b435 --- /dev/null +++ b/src/kernel/core/faults.c @@ -0,0 +1,64 @@ +/* Contains the basic code for fault handling. */ + +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int faults_init(kernel_args *ka) +{ + dprintf("init_fault_handlers: entry\n"); + return arch_faults_init(ka); +} + + +int general_protection_fault(int errorcode) +{ + panic("GENERAL PROTECTION FAULT: errcode 0x%x. Killing system.\n", errorcode); + + return INT_NO_RESCHEDULE; +} + +static const char *fpu_fault_to_str(enum fpu_faults fpu_fault) +{ + switch(fpu_fault) { + default: + case FPU_FAULT_CODE_UNKNOWN: + return "unknown"; + case FPU_FAULT_CODE_DIVBYZERO: + return "divbyzero"; + case FPU_FAULT_CODE_INVALID_OP: + return "invalid op"; + case FPU_FAULT_CODE_OVERFLOW: + return "overflow"; + case FPU_FAULT_CODE_UNDERFLOW: + return "underflow"; + case FPU_FAULT_CODE_INEXACT: + return "inexact"; + } +} + +int fpu_fault(int fpu_fault) +{ + panic("FPU FAULT: errcode 0x%x (%s), Killing system.\n", fpu_fault, fpu_fault_to_str(fpu_fault)); + + return INT_NO_RESCHEDULE; +} + +int fpu_disable_fault(void) +{ + panic("FPU DISABLE FAULT: Killing system.\n"); + + return INT_NO_RESCHEDULE; +} + diff --git a/src/kernel/core/fd.c b/src/kernel/core/fd.c new file mode 100644 index 0000000000..fef2f6f4b5 --- /dev/null +++ b/src/kernel/core/fd.c @@ -0,0 +1,456 @@ +/* fd.c + * + * Operations on file descriptors... + * see fd.h for the definitions + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define CHECK_USER_ADDR(x) \ + if ((addr)(x) >= KERNEL_BASE && (addr)(x) <= KERNEL_TOP) \ + return EINVAL; + +#define CHECK_SYS_ADDR(x) \ + if ((addr)(x) < KERNEL_BASE && (addr)(x) >= KERNEL_TOP) \ + return EINVAL; + + +#define PRINT(x) dprintf x + + +/*** General fd routines ***/ + + +/** Allocates and initializes a new file_descriptor */ + +struct file_descriptor * +alloc_fd(void) +{ + struct file_descriptor *f; + + f = kmalloc(sizeof(struct file_descriptor)); + if(f) { + f->vnode = NULL; + f->cookie = NULL; + f->ref_count = 1; + } + return f; +} + + +int +new_fd(struct io_context *ioctx, struct file_descriptor *f) +{ + int fd = -1; + int i; + + mutex_lock(&ioctx->io_mutex); + + for (i = 0; i < ioctx->table_size; i++) { + if (!ioctx->fds[i]) { + fd = i; + break; + } + } + if (fd < 0) { + fd = ERR_NO_MORE_HANDLES; + goto err; + } + + ioctx->fds[fd] = f; + ioctx->num_used_fds++; + +err: + mutex_unlock(&ioctx->io_mutex); + + return fd; +} + + +void +put_fd(struct file_descriptor *f) +{ + /* Run a cleanup (fd_free) routine if there is one and free structure, but only + * if we've just removed the final reference to it :) + */ + if (atomic_add(&f->ref_count, -1) == 1) { + if (f->ops->fd_free) + f->ops->fd_free(f); + kfree(f); + } +} + + +struct file_descriptor * +get_fd(struct io_context *ioctx, int fd) +{ + struct file_descriptor *f; + + mutex_lock(&ioctx->io_mutex); + + if (fd >= 0 && fd < ioctx->table_size && ioctx->fds[fd]) { + // valid fd + f = ioctx->fds[fd]; + atomic_add(&f->ref_count, 1); + } else { + f = NULL; + } + + mutex_unlock(&ioctx->io_mutex); + return f; +} + + +void +remove_fd(struct io_context *ioctx, int fd) +{ + struct file_descriptor *f; + + mutex_lock(&ioctx->io_mutex); + + if (fd >= 0 && fd < ioctx->table_size && ioctx->fds[fd]) { + // valid fd + f = ioctx->fds[fd]; + ioctx->fds[fd] = NULL; + ioctx->num_used_fds--; + } else { + f = NULL; + } + + mutex_unlock(&ioctx->io_mutex); + + if (f) + put_fd(f); +} + + +// #pragma mark - +/*** USER routines ***/ + + +ssize_t +user_read(int fd, void *buffer, off_t pos, size_t length) +{ + struct file_descriptor *descriptor; + ssize_t retval; + + /* This is a user_function, so abort if we have a kernel address */ + CHECK_USER_ADDR(buffer) + + descriptor = get_fd(get_current_io_context(false), fd); + if (!descriptor) + return EBADF; + + if (descriptor->ops->fd_read) { + retval = descriptor->ops->fd_read(descriptor, buffer, pos, &length); + if (retval >= 0) + retval = (ssize_t)length; + } else + retval = EINVAL; + + put_fd(descriptor); + return retval; +} + + +ssize_t +user_write(int fd, const void *buffer, off_t pos, size_t length) +{ + struct file_descriptor *descriptor; + ssize_t retval = 0; + + CHECK_USER_ADDR(buffer) + + descriptor = get_fd(get_current_io_context(false), fd); + if (!descriptor) + return EBADF; + + if (descriptor->ops->fd_write) { + retval = descriptor->ops->fd_write(descriptor, buffer, pos, &length); + if (retval >= 0) + retval = (ssize_t)length; + } else + retval = EINVAL; + + put_fd(descriptor); + return retval; +} + + +int +user_ioctl(int fd, ulong op, void *buffer, size_t length) +{ + struct file_descriptor *descriptor; + int status; + + CHECK_USER_ADDR(buffer) + + PRINT(("user_ioctl: fd %d\n", fd)); + + descriptor = get_fd(get_current_io_context(false), fd); + if (!descriptor) + return EBADF; + + if (descriptor->ops->fd_ioctl) + status = descriptor->ops->fd_ioctl(descriptor, op, buffer, length); + else + status = EOPNOTSUPP; + + return status; +} + + +ssize_t +user_read_dir(int fd, struct dirent *buffer,size_t bufferSize) +{ + struct file_descriptor *descriptor; + ssize_t retval; + + CHECK_USER_ADDR(buffer) + + PRINT(("user_read_dir(fd = %d, buffer = 0x%p, bufferSize = %ld)\n",fd,buffer,bufferSize)); + + descriptor = get_fd(get_current_io_context(false), fd); + if (descriptor == NULL) + return EBADF; + + if (descriptor->ops->fd_read_dir) { + uint32 count; + retval = descriptor->ops->fd_read_dir(descriptor,buffer,bufferSize,&count); + if (retval >= 0) + retval = count; + } else + retval = EOPNOTSUPP; + + put_fd(descriptor); + return retval; +} + + +status_t +user_rewind_dir(int fd) +{ + struct file_descriptor *descriptor; + status_t status; + + PRINT(("user_rewind_dir(fd = %d)\n",fd)); + + descriptor = get_fd(get_current_io_context(false), fd); + if (descriptor == NULL) + return EBADF; + + if (descriptor->ops->fd_rewind_dir) + status = descriptor->ops->fd_rewind_dir(descriptor); + else + status = EOPNOTSUPP; + + put_fd(descriptor); + return status; +} + + +int +user_fstat(int fd, struct stat *stat) +{ + struct file_descriptor *descriptor; + ssize_t retval; + + /* This is a user_function, so abort if we have a kernel address */ + CHECK_USER_ADDR(stat) + + descriptor = get_fd(get_current_io_context(false), fd); + if (descriptor == NULL) + return EBADF; + + if (descriptor->ops->fd_stat) { + // we're using the stat buffer on the stack to not have to + // lock the given stat buffer in memory + struct stat kstat; + + retval = descriptor->ops->fd_stat(descriptor, &kstat); + if (retval >= 0) + retval = user_memcpy(stat, &kstat, sizeof(*stat)); + } else + retval = EOPNOTSUPP; + + put_fd(descriptor); + return retval; +} + + +int +user_close(int fd) +{ + struct io_context *ioContext = get_current_io_context(false); + struct file_descriptor *descriptor = get_fd(ioContext, fd); + int retval; + + if (descriptor == NULL) + return EBADF; + + if (descriptor->ops->fd_close) + retval = descriptor->ops->fd_close(descriptor, fd, ioContext); + else + retval = EOPNOTSUPP; + + put_fd(descriptor); + return retval; +} + + +// #pragma mark - +/*** SYSTEM functions ***/ + + +ssize_t +sys_read(int fd, void *buffer, off_t pos, size_t length) +{ + struct file_descriptor *descriptor; + ssize_t retval; + + /* This is a sys_function, so abort if we have a kernel address */ + // I've removed those checks because we have to be able to load things + // into user memory as well -- axeld. + //CHECK_SYS_ADDR(buffer) + + descriptor = get_fd(get_current_io_context(true), fd); + if (!descriptor) + return EBADF; + + if (descriptor->ops->fd_read) { + retval = descriptor->ops->fd_read(descriptor, buffer, pos, &length); + if (retval >= 0) + retval = (ssize_t)length; + } else + retval = EINVAL; + + put_fd(descriptor); + return retval; +} + + +ssize_t +sys_write(int fd, const void *buffer, off_t pos, size_t length) +{ + struct file_descriptor *descriptor; + ssize_t retval; + +// dprintf("sys_write: fd %d\n", fd); +// CHECK_SYS_ADDR(buffer) + + descriptor = get_fd(get_current_io_context(true), fd); + if (descriptor == NULL) + return EBADF; + + if (descriptor->ops->fd_write) { + retval = descriptor->ops->fd_write(descriptor, buffer, pos, &length); + if (retval >= 0) + retval = (ssize_t)length; + + PRINT(("sys_write(%d) = %ld (rlen = %ld)\n", fd, retval, length)); + } else + retval = EINVAL; + + put_fd(descriptor); + return retval; +} + + +int +sys_ioctl(int fd, ulong op, void *buffer, size_t length) +{ + struct file_descriptor *descriptor; + int status; + + PRINT(("sys_ioctl: fd %d\n", fd)); + + CHECK_SYS_ADDR(buffer) + + descriptor = get_fd(get_current_io_context(true), fd); + if (descriptor == NULL) + return EBADF; + + if (descriptor->ops->fd_ioctl) + status = descriptor->ops->fd_ioctl(descriptor, op, buffer, length); + else + status = EOPNOTSUPP; + + put_fd(descriptor); + return status; +} + + +ssize_t +sys_read_dir(int fd, struct dirent *buffer,size_t bufferSize) +{ + struct file_descriptor *descriptor; + ssize_t retval; + + PRINT(("sys_read_dir(fd = %d, buffer = 0x%p, bufferSize = %ld)\n",fd,buffer,bufferSize)); + + descriptor = get_fd(get_current_io_context(false), fd); + if (descriptor == NULL) + return EBADF; + + if (descriptor->ops->fd_read_dir) { + uint32 count; + retval = descriptor->ops->fd_read_dir(descriptor,buffer,bufferSize,&count); + if (retval >= 0) + retval = count; + } else + retval = EOPNOTSUPP; + + put_fd(descriptor); + return retval; +} + + +status_t +sys_rewind_dir(int fd) +{ + struct file_descriptor *descriptor; + status_t status; + + PRINT(("user_rewind_dir(fd = %d)\n",fd)); + + descriptor = get_fd(get_current_io_context(false), fd); + if (descriptor == NULL) + return EBADF; + + if (descriptor->ops->fd_rewind_dir) + status = descriptor->ops->fd_rewind_dir(descriptor); + else + status = EOPNOTSUPP; + + put_fd(descriptor); + return status; +} + + +int +sys_close(int fd) +{ + struct io_context *ioContext = get_current_io_context(true); + struct file_descriptor *descriptor = get_fd(ioContext, fd); + int status; + + if (descriptor == NULL) + return EBADF; + + if (descriptor->ops->fd_close) + status = descriptor->ops->fd_close(descriptor, fd, ioContext); + else + status = EOPNOTSUPP; + + put_fd(descriptor); + return status; +} + diff --git a/src/kernel/core/fs/Jamfile b/src/kernel/core/fs/Jamfile new file mode 100644 index 0000000000..09504b4480 --- /dev/null +++ b/src/kernel/core/fs/Jamfile @@ -0,0 +1,10 @@ +SubDir OBOS_TOP sources os kits kernel core fs ; + +KernelStaticLibrary libfs : + <$(SOURCE_GRIST)>bootfs.c + <$(SOURCE_GRIST)>devfs.c + <$(SOURCE_GRIST)>rootfs.c + <$(SOURCE_GRIST)>vfs.c + : + -fno-pic -Wno-unused -D_KERNEL_ + ; diff --git a/src/kernel/core/fs/bootfs.c b/src/kernel/core/fs/bootfs.c new file mode 100755 index 0000000000..20be101883 --- /dev/null +++ b/src/kernel/core/fs/bootfs.c @@ -0,0 +1,959 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + +#define BOOTFS_TRACE 0 + +#if BOOTFS_TRACE +#define TRACE(x) dprintf x +#else +#define TRACE(x) +#endif + +static char *bootdir = NULL; +static off_t bootdir_len = 0; +static region_id bootdir_region = -1; + +struct bootfs_stream { + stream_type type; + union { + struct stream_dir { + struct bootfs_vnode *dir_head; + struct bootfs_cookie *jar_head; + } dir; + struct stream_file { + void *start; + off_t len; + } file; + } u; +}; + +struct bootfs_vnode { + struct bootfs_vnode *all_next; + vnode_id id; + char *name; + void *redir_vnode; + struct bootfs_vnode *parent; + struct bootfs_vnode *dir_next; + struct bootfs_stream stream; +}; + +struct bootfs { + fs_id id; + mutex lock; + int next_vnode_id; + void *vnode_list_hash; + struct bootfs_vnode *root_vnode; +}; + +struct bootfs_cookie { + struct bootfs_stream *s; + int oflags; + union { + struct cookie_dir { + struct bootfs_cookie *next; + struct bootfs_cookie *prev; + struct bootfs_vnode *ptr; + } dir; + struct cookie_file { + off_t pos; + } file; + } u; +}; + +#define BOOTFS_HASH_SIZE 16 +static unsigned int bootfs_vnode_hash_func(void *_v, const void *_key, unsigned int range) +{ + struct bootfs_vnode *v = _v; + const vnode_id *key = _key; + + if(v != NULL) + return v->id % range; + else + return (*key) % range; +} + +static int bootfs_vnode_compare_func(void *_v, const void *_key) +{ + struct bootfs_vnode *v = _v; + const vnode_id *key = _key; + + if(v->id == *key) + return 0; + else + return -1; +} + +static struct bootfs_vnode *bootfs_create_vnode(struct bootfs *fs, const char *name) +{ + struct bootfs_vnode *v; + + v = kmalloc(sizeof(struct bootfs_vnode)); + if(v == NULL) + return NULL; + + memset(v, 0, sizeof(struct bootfs_vnode)); + v->id = fs->next_vnode_id++; + + v->name = kstrdup(name); + if(v->name == NULL) { + kfree(v); + return NULL; + } + + return v; +} + +static int bootfs_delete_vnode(struct bootfs *fs, struct bootfs_vnode *v, bool force_delete) +{ + // cant delete it if it's in a directory or is a directory + // and has children + if(!force_delete && ((v->stream.type == STREAM_TYPE_DIR && v->stream.u.dir.dir_head != NULL) || v->dir_next != NULL)) { + return ERR_NOT_ALLOWED; + } + + // remove it from the global hash table + hash_remove(fs->vnode_list_hash, v); + + if(v->name != NULL) + kfree(v->name); + kfree(v); + + return 0; +} + +static void insert_cookie_in_jar(struct bootfs_vnode *dir, struct bootfs_cookie *cookie) +{ + cookie->u.dir.next = dir->stream.u.dir.jar_head; + dir->stream.u.dir.jar_head = cookie; + cookie->u.dir.prev = NULL; +} + +static void remove_cookie_from_jar(struct bootfs_vnode *dir, struct bootfs_cookie *cookie) +{ + if(cookie->u.dir.next) + cookie->u.dir.next->u.dir.prev = cookie->u.dir.prev; + if(cookie->u.dir.prev) + cookie->u.dir.prev->u.dir.next = cookie->u.dir.next; + if(dir->stream.u.dir.jar_head == cookie) + dir->stream.u.dir.jar_head = cookie->u.dir.next; + + cookie->u.dir.prev = cookie->u.dir.next = NULL; +} + +/* makes sure none of the dircookies point to the vnode passed in */ +static void update_dircookies(struct bootfs_vnode *dir, struct bootfs_vnode *v) +{ + struct bootfs_cookie *cookie; + + for(cookie = dir->stream.u.dir.jar_head; cookie; cookie = cookie->u.dir.next) { + if(cookie->u.dir.ptr == v) { + cookie->u.dir.ptr = v->dir_next; + } + } +} + + +static struct bootfs_vnode *bootfs_find_in_dir(struct bootfs_vnode *dir, const char *path) +{ + struct bootfs_vnode *v; + + if(dir->stream.type != STREAM_TYPE_DIR) + return NULL; + + if(!strcmp(path, ".")) + return dir; + if(!strcmp(path, "..")) + return dir->parent; + + for(v = dir->stream.u.dir.dir_head; v; v = v->dir_next) { +// dprintf("bootfs_find_in_dir: looking at entry '%s'\n", v->name); + if(strcmp(v->name, path) == 0) { +// dprintf("bootfs_find_in_dir: found it at 0x%x\n", v); + return v; + } + } + return NULL; +} + +static int bootfs_insert_in_dir(struct bootfs_vnode *dir, struct bootfs_vnode *v) +{ + if(dir->stream.type != STREAM_TYPE_DIR) + return ERR_INVALID_ARGS; + + v->dir_next = dir->stream.u.dir.dir_head; + dir->stream.u.dir.dir_head = v; + + v->parent = dir; + return 0; +} + +static int bootfs_remove_from_dir(struct bootfs_vnode *dir, struct bootfs_vnode *findit) +{ + struct bootfs_vnode *v; + struct bootfs_vnode *last_v; + + for(v = dir->stream.u.dir.dir_head, last_v = NULL; v; last_v = v, v = v->dir_next) { + if(v == findit) { + /* make sure all dircookies dont point to this vnode */ + update_dircookies(dir, v); + + if(last_v) + last_v->dir_next = v->dir_next; + else + dir->stream.u.dir.dir_head = v->dir_next; + v->dir_next = NULL; + return 0; + } + } + return -1; +} + +static int bootfs_is_dir_empty(struct bootfs_vnode *dir) +{ + if(dir->stream.type != STREAM_TYPE_DIR) + return false; + return !dir->stream.u.dir.dir_head; +} + +// creates a path of vnodes up to the last part of the passed in path. +// returns the vnode the last segment should be a part of and +// a pointer to the leaf of the path. +// clobbers the path string passed in +static struct bootfs_vnode *bootfs_create_path(struct bootfs *fs, char *path, struct bootfs_vnode *base, char **path_leaf) +{ + struct bootfs_vnode *v; + char *temp; + bool done; + + // strip off any leading '/' or spaces + for(; *path == '/' || *path == ' '; path++) + ; + + // first, find the leaf + *path_leaf = strrchr(path, '/'); + if(*path_leaf == NULL) { + // didn't find it, so this path only is a leaf + *path_leaf = path; + return base; + } + + // this is a multipart path, seperate the leaf off + **path_leaf = '\0'; + (*path_leaf)++; + if(**path_leaf == '\0') { + // the path ended with '/'. That's invalid + return NULL; + } + + // now, lets walk down the path, building vnodes as we need em + done = false; + for(; !done; path = temp+1) { + // find the next seperator and knock it out + temp = strchr(path, '/'); + if(temp) { + *temp = '\0'; + } else { + done = true; + } + + if(*path == '\0') { + // zero length path segment, continue + continue; + } + + v = bootfs_find_in_dir(base, path); + if(!v) { + v = bootfs_create_vnode(fs, path); + if(!v) + return NULL; + + v->stream.type = STREAM_TYPE_DIR; + v->stream.u.dir.dir_head = NULL; + v->stream.u.dir.jar_head = NULL; + + bootfs_insert_in_dir(base, v); + hash_insert(fs->vnode_list_hash, v); + } else { + // we found one + if(v->stream.type != STREAM_TYPE_DIR) + return NULL; + } + base = v; + } + return base; +} + +static int bootfs_create_vnode_tree(struct bootfs *fs, struct bootfs_vnode *root) +{ + int i; + boot_entry *entry; + int err; + struct bootfs_vnode *new_vnode; + struct bootfs_vnode *dir; + char path[SYS_MAX_PATH_LEN]; + char *leaf; + + entry = (boot_entry *)bootdir; + for(i=0; istream.type = STREAM_TYPE_FILE; + new_vnode->stream.u.file.start = bootdir + entry[i].be_offset * PAGE_SIZE; + new_vnode->stream.u.file.len = entry[i].be_vsize; + + dprintf("bootfs_create_vnode_tree: added entry '%s', start %p, len 0x%Lx\n", new_vnode->name, + new_vnode->stream.u.file.start, new_vnode->stream.u.file.len); + + // insert it into the parent dir + bootfs_insert_in_dir(dir, new_vnode); + + hash_insert(fs->vnode_list_hash, new_vnode); + } + } + + return 0; +} + +static int bootfs_mount(fs_cookie *_fs, fs_id id, const char *device, void *args, vnode_id *root_vnid) +{ + struct bootfs *fs; + struct bootfs_vnode *v; + int err; + + TRACE(("bootfs_mount: entry\n")); + + fs = kmalloc(sizeof(struct bootfs)); + if(fs == NULL) { + err = ERR_NO_MEMORY; + goto err; + } + + fs->id = id; + fs->next_vnode_id = 0; + + err = mutex_init(&fs->lock, "bootfs_mutex"); + if(err < 0) { + goto err1; + } + + fs->vnode_list_hash = hash_init(BOOTFS_HASH_SIZE, (addr)&v->all_next - (addr)v, + &bootfs_vnode_compare_func, &bootfs_vnode_hash_func); + if(fs->vnode_list_hash == NULL) { + err = ERR_NO_MEMORY; + goto err2; + } + + // create a vnode + v = bootfs_create_vnode(fs, ""); + if(v == NULL) { + err = ERR_NO_MEMORY; + goto err3; + } + + // set it up + v->parent = v; + + // create a dir stream for it to hold + v->stream.type = STREAM_TYPE_DIR; + v->stream.u.dir.dir_head = NULL; + fs->root_vnode = v; + + hash_insert(fs->vnode_list_hash, v); + + err = bootfs_create_vnode_tree(fs, fs->root_vnode); + if(err < 0) { + goto err4; + } + + *root_vnid = v->id; + *_fs = fs; + + return 0; + +err4: + bootfs_delete_vnode(fs, v, true); +err3: + hash_uninit(fs->vnode_list_hash); +err2: + mutex_destroy(&fs->lock); +err1: + kfree(fs); +err: + return err; +} + +static int bootfs_unmount(fs_cookie _fs) +{ + struct bootfs *fs = _fs; + struct bootfs_vnode *v; + struct hash_iterator i; + + TRACE(("bootfs_unmount: entry fs = 0x%x\n", fs)); + + // delete all of the vnodes + hash_open(fs->vnode_list_hash, &i); + while((v = (struct bootfs_vnode *)hash_next(fs->vnode_list_hash, &i)) != NULL) { + bootfs_delete_vnode(fs, v, true); + } + hash_close(fs->vnode_list_hash, &i, false); + + hash_uninit(fs->vnode_list_hash); + mutex_destroy(&fs->lock); + kfree(fs); + + return 0; +} + +static int bootfs_sync(fs_cookie fs) +{ + TRACE(("bootfs_sync: entry\n")); + + return 0; +} + +static int bootfs_lookup(fs_cookie _fs, fs_vnode _dir, const char *name, vnode_id *id) +{ + struct bootfs *fs = (struct bootfs *)_fs; + struct bootfs_vnode *dir = (struct bootfs_vnode *)_dir; + struct bootfs_vnode *v; + struct bootfs_vnode *v1; + int err; + + TRACE(("bootfs_lookup: entry dir 0x%x, name '%s'\n", dir, name)); + + if(dir->stream.type != STREAM_TYPE_DIR) + return ERR_VFS_NOT_DIR; + + mutex_lock(&fs->lock); + + // look it up + v = bootfs_find_in_dir(dir, name); + if(!v) { + err = ENOENT; + goto err; + } + + err = vfs_get_vnode(fs->id, v->id, (fs_vnode *)&v1); + if(err < 0) { + goto err; + } + + *id = v->id; + + err = B_NO_ERROR; + +err: + mutex_unlock(&fs->lock); + + return err; +} + +static int bootfs_getvnode(fs_cookie _fs, vnode_id id, fs_vnode *v, bool r) +{ + struct bootfs *fs = (struct bootfs *)_fs; + int err; + + TRACE(("bootfs_getvnode: asking for vnode 0x%x 0x%x, r %d\n", id, r)); + + if(!r) + mutex_lock(&fs->lock); + + *v = hash_lookup(fs->vnode_list_hash, &id); + + if(!r) + mutex_unlock(&fs->lock); + + TRACE(("bootfs_getnvnode: looked it up at 0x%x\n", *v)); + + if(*v) + return 0; + else + return ENOENT; +} + +static int bootfs_putvnode(fs_cookie _fs, fs_vnode _v, bool r) +{ + struct bootfs_vnode *v = (struct bootfs_vnode *)_v; + + TRACE(("bootfs_putvnode: entry on vnode 0x%x 0x%x, r %d\n", v->id, r)); + + return 0; // whatever +} + +static int bootfs_removevnode(fs_cookie _fs, fs_vnode _v, bool r) +{ + struct bootfs *fs = (struct bootfs *)_fs; + struct bootfs_vnode *v = (struct bootfs_vnode *)_v; + struct bootfs_vnode dummy; + int err; + + TRACE(("bootfs_removevnode: remove 0x%x (0x%x 0x%x), r %d\n", v, v->id, r)); + + if(!r) + mutex_lock(&fs->lock); + + if(v->dir_next) { + // can't remove node if it's linked to the dir + panic("bootfs_removevnode: vnode %p asked to be removed is present in dir\n", v); + } + + bootfs_delete_vnode(fs, v, false); + + err = 0; + +err: + if(!r) + mutex_unlock(&fs->lock); + + return err; +} + +static int bootfs_open(fs_cookie _fs, fs_vnode _v, file_cookie *_cookie, stream_type st, int oflags) +{ + struct bootfs *fs = _fs; + struct bootfs_vnode *v = _v; + struct bootfs_cookie *cookie; + int err = 0; + int start = 0; +dprintf("bootfs_open: \n"); + TRACE(("bootfs_open: vnode 0x%x, stream_type %d, oflags 0x%x\n", v, st, oflags)); + + if(st != STREAM_TYPE_ANY && st != v->stream.type) { + err = ERR_VFS_WRONG_STREAM_TYPE; + goto err; + } + + cookie = kmalloc(sizeof(struct bootfs_cookie)); + if(cookie == NULL) { + err = ERR_NO_MEMORY; + goto err; + } + + mutex_lock(&fs->lock); + + cookie->s = &v->stream; + switch(v->stream.type) { + case STREAM_TYPE_DIR: + cookie->u.dir.ptr = v->stream.u.dir.dir_head; + break; + case STREAM_TYPE_FILE: + cookie->u.file.pos = 0; + break; + default: + err = ERR_VFS_WRONG_STREAM_TYPE; + kfree(cookie); + } + + *_cookie = cookie; + +err1: + mutex_unlock(&fs->lock); +err: + return err; +} + +static int bootfs_close(fs_cookie _fs, fs_vnode _v, file_cookie _cookie) +{ + struct bootfs *fs = _fs; + struct bootfs_vnode *v = _v; + struct bootfs_cookie *cookie = _cookie; + + TRACE(("bootfs_close: entry vnode 0x%x, cookie 0x%x\n", v, cookie)); + + return 0; +} + +static int bootfs_freecookie(fs_cookie _fs, fs_vnode _v, file_cookie _cookie) +{ + struct bootfs *fs = _fs; + struct bootfs_vnode *v = _v; + struct bootfs_cookie *cookie = _cookie; + + TRACE(("bootfs_freecookie: entry vnode 0x%x, cookie 0x%x\n", v, cookie)); + + if(cookie) + kfree(cookie); + + return 0; +} + +static int bootfs_fsync(fs_cookie _fs, fs_vnode _v) +{ + return 0; +} + +static ssize_t bootfs_read(fs_cookie _fs, fs_vnode _v, file_cookie _cookie, void *buf, off_t pos, size_t *len) +{ + struct bootfs *fs = _fs; + struct bootfs_vnode *v = _v; + struct bootfs_cookie *cookie = _cookie; + ssize_t err = 0; + + TRACE(("bootfs_read: vnode 0x%x, cookie 0x%x, pos 0x%x 0x%x, len 0x%x\n", v, cookie, pos, len)); + + mutex_lock(&fs->lock); + + switch(cookie->s->type) { + case STREAM_TYPE_DIR: { + if(cookie->u.dir.ptr == NULL) { + *len = 0; + err = ENOENT; + break; + } + + if((ssize_t)strlen(cookie->u.dir.ptr->name) + 1 > *len) { + err = ERR_VFS_INSUFFICIENT_BUF; + goto err; + } + + err = user_strcpy(buf, cookie->u.dir.ptr->name); + if(err < 0) + goto err; + + err = strlen(cookie->u.dir.ptr->name) + 1; + + cookie->u.dir.ptr = cookie->u.dir.ptr->dir_next; + break; + } + case STREAM_TYPE_FILE: + if(*len <= 0) { + err = 0; + break; + } + if(pos < 0) { + // we'll read where the cookie is at + pos = cookie->u.file.pos; + } + if(pos >= cookie->s->u.file.len) { + *len = 0; + err = ESPIPE; + break; + } + if(pos + *len > cookie->s->u.file.len) { + // trim the read + *len = cookie->s->u.file.len - pos; + } + err = user_memcpy(buf, cookie->s->u.file.start + pos, *len); + if(err < 0) { + goto err; + } + cookie->u.file.pos = pos + *len; + err = 0; + break; + default: + *len = 0; + err = EINVAL; + } +err: + mutex_unlock(&fs->lock); + + return err; +} + +static ssize_t bootfs_write(fs_cookie fs, fs_vnode v, file_cookie cookie, const void *buf, off_t pos, size_t *len) +{ + TRACE(("bootfs_write: vnode 0x%x, cookie 0x%x, pos 0x%x 0x%x, len 0x%x\n", v, cookie, pos, *len)); + + return EROFS; +} + +static int bootfs_seek(fs_cookie _fs, fs_vnode _v, file_cookie _cookie, off_t pos, int st) +{ + struct bootfs *fs = _fs; + struct bootfs_vnode *v = _v; + struct bootfs_cookie *cookie = _cookie; + int err = 0; + + TRACE(("bootfs_seek: vnode 0x%x, cookie 0x%x, pos 0x%x 0x%x, seek_type %d\n", v, cookie, pos, st)); + + mutex_lock(&fs->lock); + + switch(cookie->s->type) { + case STREAM_TYPE_DIR: + switch(st) { + // only valid args are seek_type SEEK_SET, pos 0. + // this rewinds to beginning of directory + case SEEK_SET: + if(pos == 0) { + cookie->u.dir.ptr = cookie->s->u.dir.dir_head; + } else { + err = ESPIPE; + } + break; + case SEEK_CUR: + case SEEK_END: + default: + err = ESPIPE; + } + break; + case STREAM_TYPE_FILE: + switch(st) { + case SEEK_SET: + if(pos < 0) + pos = 0; + if(pos > cookie->s->u.file.len) + pos = cookie->s->u.file.len; + cookie->u.file.pos = pos; + break; + case SEEK_CUR: + if(pos + cookie->u.file.pos > cookie->s->u.file.len) + cookie->u.file.pos = cookie->s->u.file.len; + else if(pos + cookie->u.file.pos < 0) + cookie->u.file.pos = 0; + else + cookie->u.file.pos += pos; + break; + case SEEK_END: + if(pos > 0) + cookie->u.file.pos = cookie->s->u.file.len; + else if(pos + cookie->s->u.file.len < 0) + cookie->u.file.pos = 0; + else + cookie->u.file.pos = pos + cookie->s->u.file.len; + break; + default: + err = ERR_INVALID_ARGS; + + } + break; + default: + err = ERR_INVALID_ARGS; + } + + mutex_unlock(&fs->lock); + + return err; +} + + +static int +bootfs_read_dir(fs_cookie _fs, fs_vnode _vnode, file_cookie _cookie, struct dirent *buffer, size_t bufferSize, uint32 *_num) +{ + // ToDo: implement me! + return B_OK; +} + + +static int +bootfs_rewind_dir(fs_cookie _fs, fs_vnode _vnode, file_cookie _cookie) +{ + // ToDo: me too! + return B_OK; +} + + +static int +bootfs_ioctl(fs_cookie _fs, fs_vnode _v, file_cookie _cookie, ulong op, void *buf, size_t len) +{ + TRACE(("bootfs_ioctl: vnode 0x%x, cookie 0x%x, op %d, buf 0x%x, len 0x%x\n", _v, _cookie, op, buf, len)); + return EINVAL; +} + + +static int +bootfs_canpage(fs_cookie _fs, fs_vnode _v) +{ + struct bootfs_vnode *v = _v; + + TRACE(("bootfs_canpage: vnode 0x%x\n", v)); + + if(v->stream.type == STREAM_TYPE_FILE) + return 1; + else + return 0; +} + +static ssize_t bootfs_readpage(fs_cookie _fs, fs_vnode _v, iovecs *vecs, off_t pos) +{ + struct bootfs *fs = _fs; + struct bootfs_vnode *v = _v; + unsigned int i; + + TRACE(("bootfs_readpage: vnode 0x%x, vecs 0x%x, pos 0x%x 0x%x\n", v, vecs, pos)); + + for(i=0; inum; i++) { + if(pos >= v->stream.u.file.len) { + memset(vecs->vec[i].iov_base, 0, vecs->vec[i].iov_len); + pos += vecs->vec[i].iov_len; + } else { + unsigned int copy_len; + + copy_len = min(vecs->vec[i].iov_len, v->stream.u.file.len - pos); + + memcpy(vecs->vec[i].iov_base, v->stream.u.file.start + pos, copy_len); + + if(copy_len < vecs->vec[i].iov_len) + memset((char *)vecs->vec[i].iov_base + copy_len, 0, vecs->vec[i].iov_len - copy_len); + + pos += vecs->vec[i].iov_len; + } + } + + return EPERM; +} + +static ssize_t bootfs_writepage(fs_cookie _fs, fs_vnode _v, iovecs *vecs, off_t pos) +{ + struct bootfs *fs = _fs; + struct bootfs_vnode *v = _v; + + TRACE(("bootfs_writepage: vnode 0x%x, vecs 0x%x, pos 0x%x 0x%x\n", v, vecs, pos)); + + return ERR_NOT_ALLOWED; +} + +static int bootfs_create(fs_cookie _fs, fs_vnode _dir, const char *name, stream_type st, void *create_args, vnode_id *new_vnid) +{ + return ERR_VFS_READONLY_FS; +} + +static int bootfs_unlink(fs_cookie _fs, fs_vnode _dir, const char *name) +{ + return ERR_VFS_READONLY_FS; +} + +static int bootfs_rename(fs_cookie _fs, fs_vnode _olddir, const char *oldname, fs_vnode _newdir, const char *newname) +{ + return ERR_VFS_READONLY_FS; +} + +static int bootfs_rstat(fs_cookie _fs, fs_vnode _v, struct stat *stat) +{ + struct bootfs *fs = _fs; + struct bootfs_vnode *v = _v; + int err = 0; +//dprintf("bootfs_rstat:\n"); + TRACE(("bootfs_rstat: vnode 0x%x (0x%x 0x%x), stat 0x%x\n", v, v->id, stat)); + + mutex_lock(&fs->lock); + + /* Read Only File System */ + /** XXX - no pretense at access control, just tell people + * they can read it :) + */ + stat->st_mode = (S_IRUSR | S_IRGRP | S_IROTH); + stat->st_size = 0; + stat->st_ino = v->id; + + switch(v->stream.type) { + case STREAM_TYPE_DIR: + stat->st_mode |= S_IFDIR; + break; + case STREAM_TYPE_FILE: + stat->st_size = v->stream.u.file.len; + stat->st_mode |= S_IFREG; + break; + default: + err = EINVAL; + break; + } + +err: + mutex_unlock(&fs->lock); + + return err; +} + + +static int bootfs_wstat(fs_cookie _fs, fs_vnode _v, struct stat *stat, int stat_mask) +{ + struct bootfs *fs = _fs; + struct bootfs_vnode *v = _v; + + TRACE(("bootfs_wstat: vnode 0x%x (0x%x 0x%x), stat 0x%x\n", v, v->id, stat)); + + // cannot change anything + return ERR_VFS_READONLY_FS; +} + +static struct fs_calls bootfs_calls = { + &bootfs_mount, + &bootfs_unmount, + &bootfs_sync, + + &bootfs_lookup, + + &bootfs_getvnode, + &bootfs_putvnode, + &bootfs_removevnode, + + &bootfs_open, + &bootfs_close, + &bootfs_freecookie, + &bootfs_fsync, + + &bootfs_read, + &bootfs_write, + &bootfs_seek, + + &bootfs_read_dir, + &bootfs_rewind_dir, + + &bootfs_ioctl, + + &bootfs_canpage, + &bootfs_readpage, + &bootfs_writepage, + + &bootfs_create, + &bootfs_unlink, + &bootfs_rename, + + &bootfs_rstat, + &bootfs_wstat, +}; + + +int +bootstrap_bootfs(void) +{ + region_id rid; + vm_region_info rinfo; + + dprintf("bootstrap_bootfs: entry\n"); + + // find the bootdir and set it up + rid = vm_find_region_by_name(vm_get_kernel_aspace_id(), "bootdir"); + if(rid < 0) + panic("bootstrap_bootfs: no bootdir area found!\n"); + vm_get_region_info(rid, &rinfo); + bootdir = (char *)rinfo.base; + bootdir_len = rinfo.size; + bootdir_region = rinfo.id; + + dprintf("bootstrap_bootfs: found bootdir at %p\n", bootdir); + + return vfs_register_filesystem("bootfs", &bootfs_calls); +} + diff --git a/src/kernel/core/fs/devfs.c b/src/kernel/core/fs/devfs.c new file mode 100755 index 0000000000..3871606407 --- /dev/null +++ b/src/kernel/core/fs/devfs.c @@ -0,0 +1,1108 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +// 280202 TK: added partition support + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + + +#define DEVFS_TRACE 0 + +#if DEVFS_TRACE +#define TRACE(x) dprintf x +#else +#define TRACE(x) +#endif + +struct devfs_part_map { + off_t offset; + off_t size; + uint32 logical_block_size; + struct devfs_vnode *raw_vnode; + + // following info could be recreated on the fly, but it's not worth it + uint32 session; + uint32 partition; +}; + +struct devfs_stream { + stream_type type; + union { + struct stream_dir { + struct devfs_vnode *dir_head; + struct devfs_cookie *jar_head; + } dir; + struct stream_dev { + void * ident; + device_hooks *calls; + struct devfs_part_map *part_map; + } dev; + } u; +}; + +struct devfs_vnode { + struct devfs_vnode *all_next; + vnode_id id; + char *name; + void *redir_vnode; + struct devfs_vnode *parent; + struct devfs_vnode *dir_next; + struct devfs_stream stream; +}; + +struct devfs { + fs_id id; + mutex lock; + int next_vnode_id; + void *vnode_list_hash; + struct devfs_vnode *root_vnode; +}; + +struct devfs_cookie { + struct devfs_stream *s; + int oflags; + union { + struct cookie_dir { + struct devfs_cookie *next; + struct devfs_cookie *prev; + struct devfs_vnode *ptr; + } dir; + struct cookie_dev { + void *dcookie; + } dev; + } u; +}; + +/* the one and only allowed devfs instance */ +static struct devfs *thedevfs = NULL; + +#define BOOTFS_HASH_SIZE 16 +static unsigned int devfs_vnode_hash_func(void *_v, const void *_key, unsigned int range) +{ + struct devfs_vnode *v = _v; + const vnode_id *key = _key; + + if(v != NULL) + return v->id % range; + else + return (*key) % range; +} + +static int devfs_vnode_compare_func(void *_v, const void *_key) +{ + struct devfs_vnode *v = _v; + const vnode_id *key = _key; + + if(v->id == *key) + return 0; + else + return -1; +} + +static struct devfs_vnode *devfs_create_vnode(struct devfs *fs, const char *name) +{ + struct devfs_vnode *v; + + v = kmalloc(sizeof(struct devfs_vnode)); + if(v == NULL) + return NULL; + + memset(v, 0, sizeof(struct devfs_vnode)); + v->id = fs->next_vnode_id++; + + v->name = kstrdup(name); + if(v->name == NULL) { + kfree(v); + return NULL; + } + + return v; +} + +static int devfs_delete_vnode(struct devfs *fs, struct devfs_vnode *v, bool force_delete) +{ + // cant delete it if it's in a directory or is a directory + // and has children + if(!force_delete && ((v->stream.type == STREAM_TYPE_DIR && v->stream.u.dir.dir_head != NULL) || v->dir_next != NULL)) { + return EPERM; + } + + // remove it from the global hash table + hash_remove(fs->vnode_list_hash, v); + + // TK: for partitions, we have to release the raw device + if( v->stream.type == STREAM_TYPE_DEVICE && v->stream.u.dev.part_map ) + vfs_put_vnode( fs->id, v->stream.u.dev.part_map->raw_vnode->id ); + + if(v->name != NULL) + kfree(v->name); + kfree(v); + + return 0; +} + +static void insert_cookie_in_jar(struct devfs_vnode *dir, struct devfs_cookie *cookie) +{ + cookie->u.dir.next = dir->stream.u.dir.jar_head; + dir->stream.u.dir.jar_head = cookie; + cookie->u.dir.prev = NULL; +} + +static void remove_cookie_from_jar(struct devfs_vnode *dir, struct devfs_cookie *cookie) +{ + if(cookie->u.dir.next) + cookie->u.dir.next->u.dir.prev = cookie->u.dir.prev; + if(cookie->u.dir.prev) + cookie->u.dir.prev->u.dir.next = cookie->u.dir.next; + if(dir->stream.u.dir.jar_head == cookie) + dir->stream.u.dir.jar_head = cookie->u.dir.next; + + cookie->u.dir.prev = cookie->u.dir.next = NULL; +} + +/* makes sure none of the dircookies point to the vnode passed in */ +static void update_dircookies(struct devfs_vnode *dir, struct devfs_vnode *v) +{ + struct devfs_cookie *cookie; + + for(cookie = dir->stream.u.dir.jar_head; cookie; cookie = cookie->u.dir.next) { + if(cookie->u.dir.ptr == v) { + cookie->u.dir.ptr = v->dir_next; + } + } +} + + +static struct devfs_vnode *devfs_find_in_dir(struct devfs_vnode *dir, const char *path) +{ + struct devfs_vnode *v; + + if(dir->stream.type != STREAM_TYPE_DIR) + return NULL; + + if(!strcmp(path, ".")) + return dir; + if(!strcmp(path, "..")) + return dir->parent; + + for(v = dir->stream.u.dir.dir_head; v; v = v->dir_next) { +// dprintf("devfs_find_in_dir: looking at entry '%s'\n", v->name); + if(strcmp(v->name, path) == 0) { +// dprintf("devfs_find_in_dir: found it at 0x%x\n", v); + return v; + } + } + return NULL; +} + +static int devfs_insert_in_dir(struct devfs_vnode *dir, struct devfs_vnode *v) +{ + if(dir->stream.type != STREAM_TYPE_DIR) + return EINVAL; + + v->dir_next = dir->stream.u.dir.dir_head; + dir->stream.u.dir.dir_head = v; + + v->parent = dir; + return 0; +} + +static int devfs_remove_from_dir(struct devfs_vnode *dir, struct devfs_vnode *findit) +{ + struct devfs_vnode *v; + struct devfs_vnode *last_v; + + for(v = dir->stream.u.dir.dir_head, last_v = NULL; v; last_v = v, v = v->dir_next) { + if(v == findit) { + /* make sure all dircookies dont point to this vnode */ + update_dircookies(dir, v); + + if(last_v) + last_v->dir_next = v->dir_next; + else + dir->stream.u.dir.dir_head = v->dir_next; + v->dir_next = NULL; + return 0; + } + } + return -1; +} + +static int devfs_is_dir_empty(struct devfs_vnode *dir) +{ + if(dir->stream.type != STREAM_TYPE_DIR) + return false; + return !dir->stream.u.dir.dir_head; +} + + +static int devfs_get_partition_info( struct devfs *fs, struct devfs_vnode *v, + struct devfs_cookie *cookie, void *buf, size_t len) +{ + devfs_partition_info *info = (devfs_partition_info *)buf; + struct devfs_part_map *part_map = v->stream.u.dev.part_map; + + if( v->stream.type != STREAM_TYPE_DEVICE || part_map == NULL ) + return EINVAL; + + info->offset = part_map->offset; + info->size = part_map->size; + info->logical_block_size = part_map->logical_block_size; + info->session = part_map->session; + info->partition = part_map->partition; + + // XXX: todo - create raw device name out of raw_vnode + // we need vfs support for that (see vfs_get_cwd) + strcpy( info->raw_device, "something_raw" ); + + return B_NO_ERROR; +} + +static int devfs_set_partition( struct devfs *fs, struct devfs_vnode *v, + struct devfs_cookie *cookie, void *buf, size_t len) +{ + struct devfs_part_map *part_map; + struct devfs_vnode *part_node; + int res; + char part_name[30]; + devfs_partition_info info; + + info = *(devfs_partition_info *)buf; + + if( v->stream.type != STREAM_TYPE_DEVICE ) + return EINVAL; + + // we don't support nested partitions + if( v->stream.u.dev.part_map ) + return EINVAL; + + // reduce checks to a minimum - things like negative offsets could be useful + if( info.size < 0) + return EINVAL; + + // create partition map + part_map = kmalloc( sizeof( *part_map )); + if( !part_map ) + return ENOMEM; + + part_map->offset = info.offset; + part_map->size = info.size; + part_map->logical_block_size = info.logical_block_size; + part_map->session = info.session; + part_map->partition = info.partition; + + sprintf( part_name, "%i_%i", info.session, info.partition ); + + mutex_lock(&thedevfs->lock); + + // you cannot change a partition once set + if( devfs_find_in_dir( v->parent, part_name )) { + res = EINVAL; + goto err1; + } + + // increase reference count of raw device - + // the partition device really needs it + // (at least to resolve its name on GET_PARTITION_INFO) + res = vfs_get_vnode( fs->id, v->id, (fs_vnode *)&part_map->raw_vnode ); + if( res < 0 ) + goto err1; + + // now create the partition node + part_node = devfs_create_vnode( fs, part_name ); + + if( part_node == NULL ) { + res = ENOMEM; + goto err2; + } + + part_node->stream.type = STREAM_TYPE_DEVICE; + part_node->stream.u.dev.ident = v->stream.u.dev.ident; + part_node->stream.u.dev.calls = v->stream.u.dev.calls; + part_node->stream.u.dev.part_map = part_map; + + hash_insert( fs->vnode_list_hash, part_node ); + + devfs_insert_in_dir( v->parent, part_node ); + + mutex_unlock(&thedevfs->lock); + + dprintf( "SET_PARTITION: Added partition\n" ); + + return B_NO_ERROR; + +err1: + mutex_unlock(&thedevfs->lock); + + kfree( part_map ); + return res; + +err2: + mutex_unlock(&thedevfs->lock); + + vfs_put_vnode( fs->id, v->id ); + kfree( part_map ); + return res; +} + +static int devfs_mount(fs_cookie *_fs, fs_id id, const char *devfs, void *args, vnode_id *root_vnid) +{ + struct devfs *fs; + struct devfs_vnode *v; + int err; + + TRACE(("devfs_mount: entry\n")); + + if(thedevfs) { + dprintf("double mount of devfs attempted\n"); + err = ERR_GENERAL; + goto err; + } + + fs = kmalloc(sizeof(struct devfs)); + if(fs == NULL) { + err = ENOMEM; + goto err; + } + + fs->id = id; + fs->next_vnode_id = 0; + + err = mutex_init(&fs->lock, "devfs_mutex"); + if(err < 0) { + goto err1; + } + + fs->vnode_list_hash = hash_init(BOOTFS_HASH_SIZE, (addr)&v->all_next - (addr)v, + &devfs_vnode_compare_func, &devfs_vnode_hash_func); + if(fs->vnode_list_hash == NULL) { + err = ENOMEM; + goto err2; + } + + // create a vnode + v = devfs_create_vnode(fs, ""); + if(v == NULL) { + err = ENOMEM; + goto err3; + } + + // set it up + v->parent = v; + + // create a dir stream for it to hold + v->stream.type = STREAM_TYPE_DIR; + v->stream.u.dir.dir_head = NULL; + v->stream.u.dir.jar_head = NULL; + fs->root_vnode = v; + + hash_insert(fs->vnode_list_hash, v); + + *root_vnid = v->id; + *_fs = fs; + + thedevfs = fs; + + return 0; + + devfs_delete_vnode(fs, v, true); +err3: + hash_uninit(fs->vnode_list_hash); +err2: + mutex_destroy(&fs->lock); +err1: + kfree(fs); +err: + return err; +} + +static int devfs_unmount(fs_cookie _fs) +{ + struct devfs *fs = _fs; + struct devfs_vnode *v; + struct hash_iterator i; + + TRACE(("devfs_unmount: entry fs = 0x%x\n", fs)); + + // delete all of the vnodes + hash_open(fs->vnode_list_hash, &i); + while((v = (struct devfs_vnode *)hash_next(fs->vnode_list_hash, &i)) != NULL) { + devfs_delete_vnode(fs, v, true); + } + hash_close(fs->vnode_list_hash, &i, false); + + hash_uninit(fs->vnode_list_hash); + mutex_destroy(&fs->lock); + kfree(fs); + + return 0; +} + +static int devfs_sync(fs_cookie fs) +{ + TRACE(("devfs_sync: entry\n")); + + return 0; +} + +static int devfs_lookup(fs_cookie _fs, fs_vnode _dir, const char *name, vnode_id *id) +{ + struct devfs *fs = (struct devfs *)_fs; + struct devfs_vnode *dir = (struct devfs_vnode *)_dir; + struct devfs_vnode *v; + struct devfs_vnode *v1; + int err; + + TRACE(("devfs_lookup: entry dir 0x%x, name '%s'\n", dir, name)); + + if(dir->stream.type != STREAM_TYPE_DIR) + return ENOTDIR; + + mutex_lock(&fs->lock); + + // look it up + v = devfs_find_in_dir(dir, name); + if(!v) { + err = ERR_NOT_FOUND; + goto err; + } + + err = vfs_get_vnode(fs->id, v->id, (fs_vnode *)&v1); + if(err < 0) { + goto err; + } + + *id = v->id; + + err = B_NO_ERROR; + +err: + mutex_unlock(&fs->lock); + + return err; +} + +static int devfs_getvnode(fs_cookie _fs, vnode_id id, fs_vnode *v, bool r) +{ + struct devfs *fs = (struct devfs *)_fs; + + TRACE(("devfs_getvnode: asking for vnode 0x%x 0x%x, r %d\n", id, r)); + + if(!r) + mutex_lock(&fs->lock); + + *v = hash_lookup(fs->vnode_list_hash, &id); + + if(!r) + mutex_unlock(&fs->lock); + + TRACE(("devfs_getnvnode: looked it up at 0x%x\n", *v)); + + if(*v) + return 0; + else + return ERR_NOT_FOUND; +} + +static int devfs_putvnode(fs_cookie _fs, fs_vnode _v, bool r) +{ +#if DEVFS_TRACE + struct devfs_vnode *v = (struct devfs_vnode *)_v; + + TRACE(("devfs_putvnode: entry on vnode 0x%x 0x%x, r %d\n", v->id, r)); +#endif + + return 0; // whatever +} + +static int devfs_removevnode(fs_cookie _fs, fs_vnode _v, bool r) +{ + struct devfs *fs = (struct devfs *)_fs; + struct devfs_vnode *v = (struct devfs_vnode *)_v; + int err; + + TRACE(("devfs_removevnode: remove 0x%x (0x%x 0x%x), r %d\n", v, v->id, r)); + + if(!r) + mutex_lock(&fs->lock); + + if(v->dir_next) { + // can't remove node if it's linked to the dir + panic("devfs_removevnode: vnode %p asked to be removed is present in dir\n", v); + } + + devfs_delete_vnode(fs, v, false); + + err = 0; + + if(!r) + mutex_unlock(&fs->lock); + + return err; +} + +static int devfs_open(fs_cookie _fs, fs_vnode _v, file_cookie *_cookie, stream_type st, int oflags) +{ + struct devfs *fs = _fs; + struct devfs_vnode *v = _v; + struct devfs_cookie *cookie; + int err = 0; + + TRACE(("devfs_open: vnode 0x%x, oflags 0x%x\n", v, oflags)); + + if(st != STREAM_TYPE_ANY && st != v->stream.type) { + err = ERR_VFS_WRONG_STREAM_TYPE; + goto err; + } + + cookie = kmalloc(sizeof(struct devfs_cookie)); + if(cookie == NULL) { + err = ENOMEM; + goto err; + } + + mutex_lock(&fs->lock); + + cookie->s = &v->stream; + switch(v->stream.type) { + case STREAM_TYPE_DIR: + cookie->u.dir.ptr = v->stream.u.dir.dir_head; + break; + case STREAM_TYPE_DEVICE: + // call the device call, but unlock the devfs first + mutex_unlock(&fs->lock); + err = v->stream.u.dev.calls->open(v->name, oflags, &cookie->u.dev.dcookie); + mutex_lock(&fs->lock); + break; + default: + err = ERR_VFS_WRONG_STREAM_TYPE; + kfree(cookie); + } + + *_cookie = cookie; + + mutex_unlock(&fs->lock); +err: + return err; +} + +static int devfs_close(fs_cookie _fs, fs_vnode _v, file_cookie _cookie) +{ + struct devfs_vnode *v = _v; + struct devfs_cookie *cookie = _cookie; + int err; + + TRACE(("devfs_close: entry vnode 0x%x, cookie 0x%x\n", v, cookie)); + + if(v->stream.type == STREAM_TYPE_DEVICE) { + // pass the call through to the underlying device + err = v->stream.u.dev.calls->close(cookie->u.dev.dcookie); + } else { + err = 0; + } + + return err; +} + +static int devfs_freecookie(fs_cookie _fs, fs_vnode _v, file_cookie _cookie) +{ + struct devfs_vnode *v = _v; + struct devfs_cookie *cookie = _cookie; + + TRACE(("devfs_freecookie: entry vnode 0x%x, cookie 0x%x\n", v, cookie)); + + if(v->stream.type == STREAM_TYPE_DEVICE) { + // pass the call through to the underlying device + v->stream.u.dev.calls->free(cookie->u.dev.dcookie); + } + + if(cookie) + kfree(cookie); + + return 0; +} + +static int devfs_fsync(fs_cookie _fs, fs_vnode _v) +{ + return 0; +} + +static ssize_t devfs_read(fs_cookie _fs, fs_vnode _v, file_cookie _cookie, void *buf, off_t pos, size_t *len) +{ + struct devfs *fs = _fs; + struct devfs_vnode *v = _v; + struct devfs_cookie *cookie = _cookie; + bool is_locked = false; + ssize_t err = 0; + + TRACE(("devfs_read: vnode 0x%x, cookie 0x%x, pos 0x%x 0x%x, len 0x%x\n", v, cookie, pos, len)); + + switch(cookie->s->type) { + case STREAM_TYPE_DIR: { + mutex_lock(&fs->lock); + is_locked = true; + + if(cookie->u.dir.ptr == NULL) { + *len = 0; + err = ENOENT; + break; + } + + if((ssize_t)strlen(cookie->u.dir.ptr->name) + 1 > *len) { + err = ENOBUFS; + goto err; + } + + err = user_strcpy(buf, cookie->u.dir.ptr->name); + if(err < 0) + goto err; + + err = strlen(cookie->u.dir.ptr->name) + 1; + + cookie->u.dir.ptr = cookie->u.dir.ptr->dir_next; + break; + } + case STREAM_TYPE_DEVICE: { + struct devfs_part_map *part_map = v->stream.u.dev.part_map; + + if( part_map ) { + if( pos < 0 ) + pos = 0; + + if( pos > part_map->size ) + return 0; + + *len = min(*len, part_map->size - pos ); + pos += part_map->offset; + } + + // pass the call through to the device + err = v->stream.u.dev.calls->read(cookie->u.dev.dcookie, pos, buf, len); + break; + } + default: + err = EINVAL; + } +err: + if(is_locked) + mutex_unlock(&fs->lock); + + return err; +} + +static ssize_t devfs_write(fs_cookie _fs, fs_vnode _v, file_cookie _cookie, const void *buf, + off_t pos, size_t *len) +{ + struct devfs_vnode *v = _v; + struct devfs_cookie *cookie = _cookie; + + TRACE(("devfs_write: vnode 0x%x, cookie 0x%x, pos 0x%x 0x%x, len 0x%x\n", v, cookie, pos, len)); + + if(v->stream.type == STREAM_TYPE_DEVICE) { + struct devfs_part_map *part_map = v->stream.u.dev.part_map; + + if( part_map ) { + if( pos < 0 ) + pos = 0; + + if( pos > part_map->size ) + return 0; + + *len = min(*len, part_map->size - pos); + pos += part_map->offset; + } + + return v->stream.u.dev.calls->write(cookie->u.dev.dcookie, pos, buf, len); + } else { + return EROFS; + } +} + +static int devfs_seek(fs_cookie _fs, fs_vnode _v, file_cookie _cookie, off_t pos, int st) +{ + struct devfs *fs = _fs; + struct devfs_vnode *v = _v; + struct devfs_cookie *cookie = _cookie; + int err = 0; + + TRACE(("devfs_seek: vnode 0x%x, cookie 0x%x, pos 0x%x 0x%x, seek_type %d\n", v, cookie, pos, st)); + + switch(cookie->s->type) { + case STREAM_TYPE_DIR: + mutex_lock(&fs->lock); + switch(st) { + // only valid args are seek_type SEEK_SET, pos 0. + // this rewinds to beginning of directory + case SEEK_SET: + if(pos == 0) { + cookie->u.dir.ptr = cookie->s->u.dir.dir_head; + } else { + err = ESPIPE; + } + break; + case SEEK_CUR: + case SEEK_END: + default: + err = EINVAL; + } + mutex_unlock(&fs->lock); + break; + case STREAM_TYPE_DEVICE: + dprintf("seek not supported!\n"); + //err = v->stream.u.dev.calls->dev_seek(cookie->u.dev.dcookie, pos, st); + break; + default: + err = EINVAL; + } + + return err; +} + + +static int +devfs_read_dir(fs_cookie _fs, fs_vnode _vnode, file_cookie _cookie, struct dirent *buffer, size_t bufferSize, uint32 *_num) +{ + // ToDo: implement me! + return B_OK; +} + + +static int +devfs_rewind_dir(fs_cookie _fs, fs_vnode _vnode, file_cookie _cookie) +{ + // ToDo: me too! + return B_OK; +} + + +static int +devfs_ioctl(fs_cookie _fs, fs_vnode _v, file_cookie _cookie, ulong op, void *buf, size_t len) +{ + struct devfs *fs = _fs; + struct devfs_vnode *v = _v; + struct devfs_cookie *cookie = _cookie; + + TRACE(("devfs_ioctl: vnode 0x%x, cookie 0x%x, op %d, buf 0x%x, len 0x%x\n", _v, _cookie, op, buf, len)); + + if (v->stream.type == STREAM_TYPE_DEVICE) { + switch( op ) { + case IOCTL_DEVFS_GET_PARTITION_INFO: + return devfs_get_partition_info( fs, v, cookie, buf, len ); + + case IOCTL_DEVFS_SET_PARTITION: + return devfs_set_partition( fs, v, cookie, buf, len ); + } + + return v->stream.u.dev.calls->control(cookie->u.dev.dcookie, op, buf, len); + } else { + return EINVAL; + } +} + +/* +static int devfs_canpage(fs_cookie _fs, fs_vnode _v) +{ + struct devfs_vnode *v = _v; + + TRACE(("devfs_canpage: vnode 0x%x\n", v)); + + if(v->stream.type == STREAM_TYPE_DEVICE) { + if(!v->stream.u.dev.calls->dev_canpage) + return 0; + return v->stream.u.dev.calls->dev_canpage(v->stream.u.dev.ident); + } else { + return 0; + } +} + +static ssize_t devfs_readpage(fs_cookie _fs, fs_vnode _v, iovecs *vecs, off_t pos) +{ + struct devfs_vnode *v = _v; + + TRACE(("devfs_readpage: vnode 0x%x, vecs 0x%x, pos 0x%x 0x%x\n", v, vecs, pos)); + + if(v->stream.type == STREAM_TYPE_DEVICE) { + struct devfs_part_map *part_map = v->stream.u.dev.part_map; + + if(!v->stream.u.dev.calls->dev_readpage) + return ERR_NOT_ALLOWED; + + if( part_map ) { + if( pos < 0 ) + return ERR_INVALID_ARGS; + + if( pos > part_map->size ) + return 0; + + // XXX we modify a passed-in structure + vecs->total_len = min( vecs->total_len, part_map->size - pos ); + pos += part_map->offset; + } + + return v->stream.u.dev.calls->dev_readpage(v->stream.u.dev.ident, vecs, pos); + } else { + return ERR_NOT_ALLOWED; + } +} + +static ssize_t devfs_writepage(fs_cookie _fs, fs_vnode _v, iovecs *vecs, off_t pos) +{ + struct devfs_vnode *v = _v; + + TRACE(("devfs_writepage: vnode 0x%x, vecs 0x%x, pos 0x%x 0x%x\n", v, vecs, pos)); + + if(v->stream.type == STREAM_TYPE_DEVICE) { + struct devfs_part_map *part_map = v->stream.u.dev.part_map; + + if(!v->stream.u.dev.calls->dev_writepage) + return ERR_NOT_ALLOWED; + + if( part_map ) { + if( pos < 0 ) + return ERR_INVALID_ARGS; + + if( pos > part_map->size ) + return 0; + + // XXX we modify a passed-in structure + vecs->total_len = min( vecs->total_len, part_map->size - pos ); + pos += part_map->offset; + } + + return v->stream.u.dev.calls->dev_writepage(v->stream.u.dev.ident, vecs, pos); + } else { + return ERR_NOT_ALLOWED; + } +} +*/ +static int devfs_create(fs_cookie _fs, fs_vnode _dir, const char *name, stream_type st, void *create_args, vnode_id *new_vnid) +{ + return EROFS; +} + +static int devfs_unlink(fs_cookie _fs, fs_vnode _dir, const char *name) +{ + struct devfs *fs = _fs; + struct devfs_vnode *dir = _dir; + struct devfs_vnode *v; + int res = B_NO_ERROR; + + mutex_lock(&fs->lock); + + v = devfs_find_in_dir( dir, name ); + if(!v) { + res = ERR_NOT_FOUND; + goto err; + } + + // you can unlink partitions only + if( v->stream.type != STREAM_TYPE_DEVICE || !v->stream.u.dev.part_map ) { + res = EROFS; + goto err; + } + + res = devfs_remove_from_dir( v->parent, v ); + if( res ) + goto err; + + res = vfs_remove_vnode( fs->id, v->id ); + +err: + mutex_unlock(&fs->lock); + + return res; +} + +static int devfs_rename(fs_cookie _fs, fs_vnode _olddir, const char *oldname, fs_vnode _newdir, const char *newname) +{ + return EROFS; +} + +static int devfs_rstat(fs_cookie _fs, fs_vnode _v, struct stat *stat) +{ + struct devfs_vnode *v = _v; + + TRACE(("devfs_rstat: vnode 0x%x (0x%x 0x%x), stat 0x%x\n", v, v->id, stat)); + +//dprintf("devfs_rstat\n"); + + stat->st_ino = v->id; + stat->st_mode = DEFFILEMODE; + stat->st_size = 0; + + if (v->stream.type == STREAM_TYPE_DIR) + stat->st_mode |= S_IFDIR; + else + stat->st_mode |= S_IFCHR; + + return 0; +} + + +static int devfs_wstat(fs_cookie _fs, fs_vnode _v, struct stat *stat, int stat_mask) +{ +#if DEVFS_TRACE + struct devfs_vnode *v = _v; + + TRACE(("devfs_wstat: vnode 0x%x (0x%x 0x%x), stat 0x%x\n", v, v->id, stat)); +#endif + // cannot change anything + return EPERM; +} + +static struct fs_calls devfs_calls = { + &devfs_mount, + &devfs_unmount, + &devfs_sync, + + &devfs_lookup, + + &devfs_getvnode, + &devfs_putvnode, + &devfs_removevnode, + + &devfs_open, + &devfs_close, + &devfs_freecookie, + &devfs_fsync, + + &devfs_read, + &devfs_write, + &devfs_seek, + + &devfs_read_dir, + &devfs_rewind_dir, + + &devfs_ioctl, + + NULL, + NULL, + NULL, + + &devfs_create, + &devfs_unlink, + &devfs_rename, + + &devfs_rstat, + &devfs_wstat, +}; + +int bootstrap_devfs(void) +{ + + dprintf("bootstrap_devfs: entry\n"); + + return vfs_register_filesystem("devfs", &devfs_calls); +} + +int devfs_publish_device(const char *path, void *ident, device_hooks *calls) +{ + int err = 0; + int i, last; + char temp[SYS_MAX_PATH_LEN+1]; + struct devfs_vnode *dir; + struct devfs_vnode *v; + bool at_leaf; + + TRACE(("devfs_publish_device: entry path '%s', hooks 0x%x\n", path, calls)); + + if(!thedevfs) { + panic("devfs_publish_device called before devfs mounted\n"); + return ERR_GENERAL; + } + + // copy the path over to a temp buffer so we can munge it + strncpy(temp, path, SYS_MAX_PATH_LEN); + temp[SYS_MAX_PATH_LEN] = 0; + + mutex_lock(&thedevfs->lock); + + // create the path leading to the device + // parse the path passed in, stripping out '/' + dir = thedevfs->root_vnode; + v = NULL; + i = 0; + last = 0; + at_leaf = false; + for(;;) { + if(temp[i] == 0) { + at_leaf = true; // we'll be done after this one + } else if(temp[i] == '/') { + temp[i] = 0; + i++; + } else { + i++; + continue; + } + + TRACE(("\tpath component '%s'\n", &temp[last])); + + // we have a path component + v = devfs_find_in_dir(dir, &temp[last]); + if(v) { + if(!at_leaf) { + // we are not at the leaf of the path, so as long as + // this is a dir we're okay + if(v->stream.type == STREAM_TYPE_DIR) { + last = i; + dir = v; + continue; + } + } + // we are at the leaf and hit another node + // or we aren't but hit a non-dir node. + // we're screwed + err = ERR_VFS_ALREADY_EXISTS; + goto err; + } else { + v = devfs_create_vnode(thedevfs, &temp[last]); + if(!v) { + err = ENOMEM; + goto err; + } + } + + // set up the new vnode + if(at_leaf) { + // this is the last component + v->stream.type = STREAM_TYPE_DEVICE; + v->stream.u.dev.ident = ident; + v->stream.u.dev.calls = calls; + } else { + // this is a dir + v->stream.type = STREAM_TYPE_DIR; + v->stream.u.dir.dir_head = NULL; + v->stream.u.dir.jar_head = NULL; + } + + hash_insert(thedevfs->vnode_list_hash, v); + + devfs_insert_in_dir(dir, v); + + if(at_leaf) + break; + last = i; + dir = v; + } + +err: + mutex_unlock(&thedevfs->lock); + return err; +} diff --git a/src/kernel/core/fs/rootfs.c b/src/kernel/core/fs/rootfs.c new file mode 100755 index 0000000000..733a2a9c88 --- /dev/null +++ b/src/kernel/core/fs/rootfs.c @@ -0,0 +1,813 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#define ROOTFS_TRACE 0 + +#if ROOTFS_TRACE +#define TRACE(x) dprintf x +#else +#define TRACE(x) +#endif + +struct rootfs_stream { + // only type of stream supported by rootfs + struct stream_dir { + struct rootfs_vnode *dir_head; + struct rootfs_cookie *jar_head; + } dir; +}; + +struct rootfs_vnode { + struct rootfs_vnode *all_next; + vnode_id id; + char *name; + void *redir_vnode; + struct rootfs_vnode *parent; + struct rootfs_vnode *dir_next; + struct rootfs_stream stream; +}; + +struct rootfs { + fs_id id; + mutex lock; + vnode_id next_vnode_id; + void *vnode_list_hash; + struct rootfs_vnode *root_vnode; +}; + +// dircookie, dirs are only types of streams supported by rootfs +struct rootfs_cookie { + struct rootfs_cookie *next; + struct rootfs_cookie *prev; + struct rootfs_vnode *ptr; + int oflags; +}; + +#define ROOTFS_HASH_SIZE 16 +static unsigned int rootfs_vnode_hash_func(void *_v, const void *_key, unsigned int range) +{ + struct rootfs_vnode *v = _v; + const vnode_id *key = _key; + + if(v != NULL) + return v->id % range; + else + return (*key) % range; +} + +static int rootfs_vnode_compare_func(void *_v, const void *_key) +{ + struct rootfs_vnode *v = _v; + const vnode_id *key = _key; + + if(v->id == *key) + return 0; + else + return -1; +} + +static struct rootfs_vnode *rootfs_create_vnode(struct rootfs *fs) +{ + struct rootfs_vnode *v; + + v = kmalloc(sizeof(struct rootfs_vnode)); + if(v == NULL) + return NULL; + + memset(v, 0, sizeof(struct rootfs_vnode)); + v->id = fs->next_vnode_id++; + + return v; +} + +static int rootfs_delete_vnode(struct rootfs *fs, struct rootfs_vnode *v, bool force_delete) +{ + // cant delete it if it's in a directory or is a directory + // and has children + if(!force_delete && (v->stream.dir.dir_head != NULL || v->dir_next != NULL)) { + return ERR_NOT_ALLOWED; + } + + // remove it from the global hash table + hash_remove(fs->vnode_list_hash, v); + + if(v->name != NULL) + kfree(v->name); + kfree(v); + + return 0; +} + +static void insert_cookie_in_jar(struct rootfs_vnode *dir, struct rootfs_cookie *cookie) +{ + cookie->next = dir->stream.dir.jar_head; + dir->stream.dir.jar_head = cookie; + cookie->prev = NULL; +} + +static void remove_cookie_from_jar(struct rootfs_vnode *dir, struct rootfs_cookie *cookie) +{ + if(cookie->next) + cookie->next->prev = cookie->prev; + if(cookie->prev) + cookie->prev->next = cookie->next; + if(dir->stream.dir.jar_head == cookie) + dir->stream.dir.jar_head = cookie->next; + + cookie->prev = cookie->next = NULL; +} + +/* makes sure none of the dircookies point to the vnode passed in */ +static void update_dircookies(struct rootfs_vnode *dir, struct rootfs_vnode *v) +{ + struct rootfs_cookie *cookie; + + for(cookie = dir->stream.dir.jar_head; cookie; cookie = cookie->next) { + if(cookie->ptr == v) { + cookie->ptr = v->dir_next; + } + } +} + +static struct rootfs_vnode *rootfs_find_in_dir(struct rootfs_vnode *dir, const char *path) +{ + struct rootfs_vnode *v; + + if(!strcmp(path, ".")) + return dir; + if(!strcmp(path, "..")) + return dir->parent; + + for(v = dir->stream.dir.dir_head; v; v = v->dir_next) { + if(strcmp(v->name, path) == 0) { + return v; + } + } + return NULL; +} + +static int rootfs_insert_in_dir(struct rootfs_vnode *dir, struct rootfs_vnode *v) +{ + v->dir_next = dir->stream.dir.dir_head; + dir->stream.dir.dir_head = v; + return 0; +} + +static int rootfs_remove_from_dir(struct rootfs_vnode *dir, struct rootfs_vnode *findit) +{ + struct rootfs_vnode *v; + struct rootfs_vnode *last_v; + + for(v = dir->stream.dir.dir_head, last_v = NULL; v; last_v = v, v = v->dir_next) { + if(v == findit) { + /* make sure all dircookies dont point to this vnode */ + update_dircookies(dir, v); + + if(last_v) + last_v->dir_next = v->dir_next; + else + dir->stream.dir.dir_head = v->dir_next; + v->dir_next = NULL; + return 0; + } + } + return -1; +} + +static int rootfs_is_dir_empty(struct rootfs_vnode *dir) +{ + return !dir->stream.dir.dir_head; +} + +static int rootfs_mount(fs_cookie *_fs, fs_id id, const char *device, void *args, vnode_id *root_vnid) +{ + struct rootfs *fs; + struct rootfs_vnode *v; + int err; + + TRACE(("rootfs_mount: entry\n")); + + fs = kmalloc(sizeof(struct rootfs)); + if(fs == NULL) { + err = ERR_NO_MEMORY; + goto err; + } + + fs->id = id; + fs->next_vnode_id = 0; + + err = mutex_init(&fs->lock, "rootfs_mutex"); + if(err < 0) { + goto err1; + } + + fs->vnode_list_hash = hash_init(ROOTFS_HASH_SIZE, (addr)&v->all_next - (addr)v, + &rootfs_vnode_compare_func, &rootfs_vnode_hash_func); + if(fs->vnode_list_hash == NULL) { + err = ERR_NO_MEMORY; + goto err2; + } + + // create a vnode + v = rootfs_create_vnode(fs); + if(v == NULL) { + err = ERR_NO_MEMORY; + goto err3; + } + + // set it up + v->parent = v; + v->name = kstrdup(""); + if(v->name == NULL) { + err = ERR_NO_MEMORY; + goto err4; + } + + v->stream.dir.dir_head = NULL; + fs->root_vnode = v; + hash_insert(fs->vnode_list_hash, v); + + *root_vnid = v->id; + *_fs = fs; + + return 0; + +err4: + rootfs_delete_vnode(fs, v, true); +err3: + hash_uninit(fs->vnode_list_hash); +err2: + mutex_destroy(&fs->lock); +err1: + kfree(fs); +err: + return err; +} + +static int rootfs_unmount(fs_cookie _fs) +{ + struct rootfs *fs = (struct rootfs *)_fs; + struct rootfs_vnode *v; + struct hash_iterator i; + + TRACE(("rootfs_unmount: entry fs = 0x%x\n", fs)); + + // put_vnode on the root to release the ref to it + vfs_put_vnode(fs->id, fs->root_vnode->id); + + // delete all of the vnodes + hash_open(fs->vnode_list_hash, &i); + while((v = (struct rootfs_vnode *)hash_next(fs->vnode_list_hash, &i)) != NULL) { + rootfs_delete_vnode(fs, v, true); + } + hash_close(fs->vnode_list_hash, &i, false); + + hash_uninit(fs->vnode_list_hash); + mutex_destroy(&fs->lock); + kfree(fs); + + return 0; +} + +static int rootfs_sync(fs_cookie fs) +{ + TRACE(("rootfs_sync: entry\n")); + + return 0; +} + +static int rootfs_lookup(fs_cookie _fs, fs_vnode _dir, const char *name, vnode_id *id) +{ + struct rootfs *fs = (struct rootfs *)_fs; + struct rootfs_vnode *dir = (struct rootfs_vnode *)_dir; + struct rootfs_vnode *v; + struct rootfs_vnode *v1; + int err; + + TRACE(("rootfs_lookup: entry dir 0x%x, name '%s'\n", dir, name)); + + mutex_lock(&fs->lock); + + // look it up + v = rootfs_find_in_dir(dir, name); + if(!v) { + err = ENOENT; + goto err; + } + + err = vfs_get_vnode(fs->id, v->id, (fs_vnode *)&v1); + if(err < 0) { + goto err; + } + + *id = v->id; + + err = B_NO_ERROR; + +err: + mutex_unlock(&fs->lock); + + return err; +} + +static int rootfs_getvnode(fs_cookie _fs, vnode_id id, fs_vnode *v, bool r) +{ + struct rootfs *fs = (struct rootfs *)_fs; + + TRACE(("rootfs_getvnode: asking for vnode 0x%x 0x%x, r %d\n", id, r)); + + if(!r) + mutex_lock(&fs->lock); + + *v = hash_lookup(fs->vnode_list_hash, &id); + + if(!r) + mutex_unlock(&fs->lock); + + TRACE(("rootfs_getnvnode: looked it up at 0x%x\n", *v)); + + if(*v) + return 0; + else + return ERR_NOT_FOUND; +} + +static int rootfs_putvnode(fs_cookie _fs, fs_vnode _v, bool r) +{ +#if ROOTFS_TRACE + struct rootfs_vnode *v = (struct rootfs_vnode *)_v; + + TRACE(("rootfs_putvnode: entry on vnode 0x%x 0x%x, r %d\n", v->id, r)); +#endif + return 0; // whatever +} + +static int rootfs_removevnode(fs_cookie _fs, fs_vnode _v, bool r) +{ + struct rootfs *fs = (struct rootfs *)_fs; + struct rootfs_vnode *v = (struct rootfs_vnode *)_v; + int err; + + TRACE(("rootfs_removevnode: remove 0x%x (0x%x 0x%x), r %d\n", v, v->id, r)); + + if(!r) + mutex_lock(&fs->lock); + + if(v->dir_next) { + // can't remove node if it's linked to the dir + panic("rootfs_removevnode: vnode %p asked to be removed is present in dir\n", v); + } + + rootfs_delete_vnode(fs, v, false); + + err = 0; + + if(!r) + mutex_unlock(&fs->lock); + + return err; +} + +static int rootfs_open(fs_cookie _fs, fs_vnode _v, file_cookie *_cookie, stream_type st, int oflags) +{ + struct rootfs *fs = (struct rootfs *)_fs; + struct rootfs_vnode *v = (struct rootfs_vnode *)_v; + struct rootfs_cookie *cookie; + int err = 0; + + TRACE(("rootfs_open: vnode 0x%x, stream_type %d, oflags 0x%x\n", v, st, oflags)); + + if(st != STREAM_TYPE_ANY && st != STREAM_TYPE_DIR) { + err = ERR_VFS_WRONG_STREAM_TYPE; + goto err; + } + + cookie = kmalloc(sizeof(struct rootfs_cookie)); + if(cookie == NULL) { + err = ERR_NO_MEMORY; + goto err; + } + + mutex_lock(&fs->lock); + + cookie->ptr = v->stream.dir.dir_head; + cookie->oflags = oflags; + + insert_cookie_in_jar(v, cookie); + + *_cookie = cookie; + + mutex_unlock(&fs->lock); +err: + return err; +} + +static int rootfs_close(fs_cookie _fs, fs_vnode _v, file_cookie _cookie) +{ +#if ROOTFS_TRACE + struct rootfs_vnode *v = _v; + struct rootfs_cookie *cookie = _cookie; + + TRACE(("rootfs_close: entry vnode 0x%x, cookie 0x%x\n", v, cookie)); +#endif + return 0; +} + +static int rootfs_freecookie(fs_cookie _fs, fs_vnode _v, file_cookie _cookie) +{ + struct rootfs_cookie *cookie = _cookie; +#if ROOTFS_TRACE + struct rootfs_vnode *v = _v; + + TRACE(("rootfs_freecookie: entry vnode 0x%x, cookie 0x%x\n", v, cookie)); +#endif + if(cookie) + kfree(cookie); + + return 0; +} + +static int rootfs_fsync(fs_cookie _fs, fs_vnode _v) +{ + return 0; +} + +static ssize_t rootfs_read(fs_cookie _fs, fs_vnode _v, file_cookie _cookie, void *buf, off_t pos, size_t *len) +{ + struct rootfs *fs = _fs; +#if ROOTFS_TRACE + struct rootfs_vnode *v = _v; +#endif + struct rootfs_cookie *cookie = _cookie; + int err = 0; + + TRACE(("rootfs_read: vnode 0x%x, cookie 0x%x, pos 0x%x 0x%x, len 0x%x\n", v, cookie, pos, *len)); + + mutex_lock(&fs->lock); + + if(cookie->ptr == NULL) { + *len = 0; + err = 0; + goto err; + } + + if((ssize_t)strlen(cookie->ptr->name) + 1 > *len) { + err = ERR_VFS_INSUFFICIENT_BUF; + goto err; + } + + err = user_strcpy(buf, cookie->ptr->name); + if(err < 0) + goto err; + + *len = strlen(cookie->ptr->name) + 1; + + cookie->ptr = cookie->ptr->dir_next; + +err: + mutex_unlock(&fs->lock); + + return err; +} + +static ssize_t rootfs_write(fs_cookie fs, fs_vnode v, file_cookie cookie, const void *buf, off_t pos, size_t *len) +{ + TRACE(("rootfs_write: vnode 0x%x, cookie 0x%x, pos 0x%x 0x%x, len 0x%x\n", v, cookie, pos, *len)); + + return ERR_NOT_ALLOWED; +} + +static int rootfs_seek(fs_cookie _fs, fs_vnode _v, file_cookie _cookie, off_t pos, int st) +{ + struct rootfs *fs = _fs; + struct rootfs_vnode *v = _v; + struct rootfs_cookie *cookie = _cookie; + int err = 0; + + TRACE(("rootfs_seek: vnode 0x%x, cookie 0x%x, pos 0x%x 0x%x, seek_type %d\n", v, cookie, pos, st)); + + mutex_lock(&fs->lock); + + switch(st) { + // only valid args are seek_type SEEK_SET, pos 0. + // this rewinds to beginning of directory + case SEEK_SET: + if(pos == 0) { + cookie->ptr = v->stream.dir.dir_head; + } else { + err = ESPIPE; + } + break; + case SEEK_CUR: + case SEEK_END: + default: + err = EINVAL; + } + + mutex_unlock(&fs->lock); + + return err; +} + + +static int +rootfs_read_dir(fs_cookie _fs, fs_vnode _vnode, file_cookie _cookie, struct dirent *buffer, size_t bufferSize, uint32 *_num) +{ + // ToDo: implement me! + return B_OK; +} + + +static int +rootfs_rewind_dir(fs_cookie _fs, fs_vnode _vnode, file_cookie _cookie) +{ + // ToDo: me too! + return B_OK; +} + + +static int +rootfs_ioctl(fs_cookie _fs, fs_vnode _v, file_cookie _cookie, ulong op, void *buf, size_t len) +{ + TRACE(("rootfs_ioctl: vnode 0x%x, cookie 0x%x, op %d, buf 0x%x, len 0x%x\n", _v, _cookie, op, buf, len)); + + return EINVAL; +} + + +static int +rootfs_canpage(fs_cookie _fs, fs_vnode _v) +{ + return -1; +} + + +static ssize_t +rootfs_readpage(fs_cookie _fs, fs_vnode _v, iovecs *vecs, off_t pos) +{ + return EPERM; +} + + +static ssize_t +rootfs_writepage(fs_cookie _fs, fs_vnode _v, iovecs *vecs, off_t pos) +{ + return EPERM; +} + + +static int +rootfs_create(fs_cookie _fs, fs_vnode _dir, const char *name, stream_type st, void *create_args, vnode_id *new_vnid) +{ + struct rootfs *fs = _fs; + struct rootfs_vnode *dir = _dir; + struct rootfs_vnode *new_vnode; + struct rootfs_stream *s; + int err = 0; + bool created_vnode = false; + + TRACE(("rootfs_create: dir 0x%x, name = '%s', stream_type = %d\n", dir, name, st)); + + // we only support stream types of STREAM_TYPE_DIR + if (st != STREAM_TYPE_DIR) { + err = EPERM; + goto err; + } + + mutex_lock(&fs->lock); + + new_vnode = rootfs_find_in_dir(dir, name); + if (new_vnode == NULL) { + dprintf("rootfs_create: creating new vnode\n"); + new_vnode = rootfs_create_vnode(fs); + if(new_vnode == NULL) { + err = ENOMEM; + goto err; + } + created_vnode = true; + new_vnode->name = kstrdup(name); + if(new_vnode->name == NULL) { + err = ENOMEM; + goto err1; + } + new_vnode->parent = dir; + rootfs_insert_in_dir(dir, new_vnode); + + hash_insert(fs->vnode_list_hash, new_vnode); + + s = &new_vnode->stream; + } else { + // we found the vnode + err = ERR_VFS_ALREADY_EXISTS; + goto err; + } + + new_vnode->stream.dir.dir_head = NULL; + new_vnode->stream.dir.jar_head = NULL; + + mutex_unlock(&fs->lock); + return 0; + +err1: + if(created_vnode) + rootfs_delete_vnode(fs, new_vnode, false); +err: + mutex_unlock(&fs->lock); + + return err; +} + +static int rootfs_unlink(fs_cookie _fs, fs_vnode _dir, const char *name) +{ + struct rootfs *fs = _fs; + struct rootfs_vnode *dir = _dir; + struct rootfs_vnode *v; + int err; + + TRACE(("rootfs_unlink: dir 0x%x (0x%x 0x%x), name '%s'\n", dir, dir->id, name)); + + mutex_lock(&fs->lock); + + v = rootfs_find_in_dir(dir, name); + if(!v) { + err = ERR_VFS_PATH_NOT_FOUND; + goto err; + } + + // do some checking to see if we can delete it + if(!rootfs_is_dir_empty(v)) { + err = ERR_VFS_DIR_NOT_EMPTY; + goto err; + } + + rootfs_remove_from_dir(dir, v); + + // schedule this vnode to be removed when it's ref goes to zero + vfs_remove_vnode(fs->id, v->id); + + err = 0; + +err: + mutex_unlock(&fs->lock); + + return err; +} + +static int rootfs_rename(fs_cookie _fs, fs_vnode _olddir, const char *oldname, fs_vnode _newdir, const char *newname) +{ + struct rootfs *fs = _fs; + struct rootfs_vnode *olddir = _olddir; + struct rootfs_vnode *newdir = _newdir; + struct rootfs_vnode *v1, *v2; + int err; + + TRACE(("rootfs_rename: olddir 0x%x (0x%x 0x%x), oldname '%s', newdir 0x%x (0x%x 0x%x), newname '%s'\n", + olddir, olddir->id, oldname, newdir, newdir->id, newname)); + + mutex_lock(&fs->lock); + + v1 = rootfs_find_in_dir(olddir, oldname); + if(!v1) { + err = ERR_VFS_PATH_NOT_FOUND; + goto err; + } + + v2 = rootfs_find_in_dir(newdir, newname); + + if(olddir == newdir) { + // rename to a different name in the same dir + if(v2) { + // target node exists + err = ERR_VFS_ALREADY_EXISTS; + goto err; + } + + // change the name on this node + if(strlen(oldname) >= strlen(newname)) { + // reuse the old name buffer + strcpy(v1->name, newname); + } else { + char *ptr = v1->name; + + v1->name = kstrdup(newname); + if(!v1->name) { + // bad place to be, at least restore + v1->name = ptr; + err = ENOMEM; + goto err; + } + kfree(ptr); + } + + /* no need to remove and add it unless the dir is sorting */ +#if 0 + // remove it from the dir + rootfs_remove_from_dir(olddir, v1); + + // add it back to the dir with the new name + rootfs_insert_in_dir(newdir, v1); +#endif + } else { + // different target dir from source + + rootfs_remove_from_dir(olddir, v1); + + rootfs_insert_in_dir(newdir, v1); + } + + err = 0; + +err: + mutex_unlock(&fs->lock); + + return err; +} + +static int rootfs_rstat(fs_cookie _fs, fs_vnode _v, struct stat *stat) +{ + struct rootfs_vnode *v = _v; + + TRACE(("rootfs_rstat: vnode 0x%x (0x%x 0x%x), stat 0x%x\n", v, v->id, stat)); + +//dprintf("rootfs_rstat\n"); + + // stream exists, but we know to return size 0, since we can only hold directories + stat->st_ino = v->id; + stat->st_size = 0; + stat->st_mode = (S_IFDIR | DEFFILEMODE); + + return 0; +} + +static int rootfs_wstat(fs_cookie _fs, fs_vnode _v, struct stat *stat, int stat_mask) +{ +#if ROOTFS_TRACE + struct rootfs *fs = _fs; + struct rootfs_vnode *v = _v; + + TRACE(("rootfs_wstat: vnode 0x%x (0x%x 0x%x), stat 0x%x\n", v, v->id, stat)); +#endif + // cannot change anything + return EINVAL; +} + +static struct fs_calls rootfs_calls = { + &rootfs_mount, + &rootfs_unmount, + &rootfs_sync, + + &rootfs_lookup, + + &rootfs_getvnode, + &rootfs_putvnode, + &rootfs_removevnode, + + &rootfs_open, + &rootfs_close, + &rootfs_freecookie, + &rootfs_fsync, + + &rootfs_read, + &rootfs_write, + &rootfs_seek, + + &rootfs_read_dir, + &rootfs_rewind_dir, + + &rootfs_ioctl, + + &rootfs_canpage, + &rootfs_readpage, + &rootfs_writepage, + + &rootfs_create, + &rootfs_unlink, + &rootfs_rename, + + &rootfs_rstat, + &rootfs_wstat, +}; + +int bootstrap_rootfs(void) +{ + dprintf("bootstrap_rootfs: entry\n"); + + return vfs_register_filesystem("rootfs", &rootfs_calls); +} diff --git a/src/kernel/core/fs/vfs.c b/src/kernel/core/fs/vfs.c new file mode 100755 index 0000000000..2d211d1cfb --- /dev/null +++ b/src/kernel/core/fs/vfs.c @@ -0,0 +1,2521 @@ +/* Virtual File System */ + +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#ifndef MAKE_NOIZE +# define MAKE_NOIZE 0 +#endif +#if MAKE_NOIZE +# define PRINT(x) dprintf x +# define FUNCTION(x) dprintf x +#else +# define PRINT(x) ; +# define FUNCTION(x) ; +#endif + + +struct vnode { + struct vnode *next; + struct vnode *mount_prev; + struct vnode *mount_next; + struct vm_cache *cache; + fs_id fsid; + vnode_id vnid; + fs_vnode priv_vnode; + struct fs_mount *mount; + struct vnode *covered_by; + int ref_count; + bool delete_me; + bool busy; +}; + +struct vnode_hash_key { + fs_id fsid; + vnode_id vnid; +}; + +struct fs_container { + struct fs_container *next; + struct fs_calls *calls; + const char *name; +}; +#define FS_CALL(vnode,call) (vnode->mount->fs->calls->call) +static struct fs_container *fs_list; + +struct fs_mount { + struct fs_mount *next; + struct fs_container *fs; + fs_id id; + void *cookie; + char *mount_point; + recursive_lock rlock; + struct vnode *root_vnode; + struct vnode *covers_vnode; + struct vnode *vnodes_head; + struct vnode *vnodes_tail; + bool unmounting; +}; + +static mutex vfs_mutex; +static mutex vfs_mount_mutex; +static mutex vfs_mount_op_mutex; +static mutex vfs_vnode_mutex; + +/* function declarations */ +static int vfs_mount(char *path, const char *device, const char *fs_name, void *args, bool kernel); +static int vfs_unmount(char *path, bool kernel); +static int vfs_open(char *path, stream_type st, int omode, bool kernel); +static int vfs_seek(int fd, off_t pos, int seek_type, bool kernel); + +static ssize_t vfs_read(struct file_descriptor *, void *, off_t, size_t *); +static ssize_t vfs_write(struct file_descriptor *, const void *, off_t, size_t *); +static int vfs_ioctl(struct file_descriptor *, ulong, void *buf, size_t len); +static status_t vfs_read_dir(struct file_descriptor *,struct dirent *buffer,size_t bufferSize,uint32 *_count); +static status_t vfs_rewind_dir(struct file_descriptor *); +static int vfs_rstat(struct file_descriptor *, struct stat *); +static int vfs_close(struct file_descriptor *, int, struct io_context *); +static void vfs_free_fd(struct file_descriptor *); + +static int vfs_create(char *path, stream_type stream_type, void *args, bool kernel); + +/* the vfs fd_ops structure */ +struct fd_ops vfsops = { + "vfs", + vfs_read, + vfs_write, + vfs_ioctl, + vfs_read_dir, + vfs_rewind_dir, + vfs_rstat, + vfs_close, + vfs_free_fd +}; + +#define VNODE_HASH_TABLE_SIZE 1024 +static void *vnode_table; +static struct vnode *root_vnode; +static vnode_id next_vnode_id = 0; + +#define MOUNTS_HASH_TABLE_SIZE 16 +static void *mounts_table; +static fs_id next_fsid = 0; + + +static int +mount_compare(void *_m, const void *_key) +{ + struct fs_mount *mount = _m; + const fs_id *id = _key; + + if(mount->id == *id) + return 0; + else + return -1; +} + + +static unsigned int +mount_hash(void *_m, const void *_key, unsigned int range) +{ + struct fs_mount *mount = _m; + const fs_id *id = _key; + + if(mount) + return mount->id % range; + else + return *id % range; +} + + +static struct fs_mount * +fsid_to_mount(fs_id id) +{ + struct fs_mount *mount; + + mutex_lock(&vfs_mount_mutex); + + mount = hash_lookup(mounts_table, &id); + + mutex_unlock(&vfs_mount_mutex); + + return mount; +} + + +static int +vnode_compare(void *_v, const void *_key) +{ + struct vnode *v = _v; + const struct vnode_hash_key *key = _key; + + if(v->fsid == key->fsid && v->vnid == key->vnid) + return 0; + else + return -1; +} + + +static unsigned int +vnode_hash(void *_v, const void *_key, unsigned int range) +{ + struct vnode *v = _v; + const struct vnode_hash_key *key = _key; + +#define VHASH(fsid, vnid) (((uint32)((vnid)>>32) + (uint32)(vnid)) ^ (uint32)(fsid)) + + if (v != NULL) + return (VHASH(v->fsid, v->vnid) % range); + else + return (VHASH(key->fsid, key->vnid) % range); + +#undef VHASH +} + +/* +static int init_vnode(struct vnode *v) +{ + v->next = NULL; + v->mount_prev = NULL; + v->mount_next = NULL; + v->priv_vnode = NULL; + v->cache = NULL; + v->ref_count = 0; + v->vnid = 0; + v->fsid = 0; + v->delete_me = false; + v->busy = false; + v->covered_by = NULL; + v->mount = NULL; + + return 0; +} +*/ + + +static void +add_vnode_to_mount_list(struct vnode *v, struct fs_mount *mount) +{ + recursive_lock_lock(&mount->rlock); + + v->mount_next = mount->vnodes_head; + v->mount_prev = NULL; + mount->vnodes_head = v; + if(!mount->vnodes_tail) + mount->vnodes_tail = v; + + recursive_lock_unlock(&mount->rlock); +} + + +static void +remove_vnode_from_mount_list(struct vnode *v, struct fs_mount *mount) +{ + recursive_lock_lock(&mount->rlock); + + if(v->mount_next) + v->mount_next->mount_prev = v->mount_prev; + else + mount->vnodes_tail = v->mount_prev; + if(v->mount_prev) + v->mount_prev->mount_next = v->mount_next; + else + mount->vnodes_head = v->mount_next; + + v->mount_prev = v->mount_next = NULL; + + recursive_lock_unlock(&mount->rlock); +} + + +static struct vnode * +create_new_vnode(void) +{ + struct vnode *v; + + v = (struct vnode *)kmalloc(sizeof(struct vnode)); + if (v == NULL) + return NULL; + + memset(v, 0, sizeof(struct vnode));//max_commit - old_store_commitment + commitment(v); + return v; +} + + +static int +dec_vnode_ref_count(struct vnode *v, bool free_mem, bool r) +{ + int err; + int old_ref; + + mutex_lock(&vfs_vnode_mutex); + + if (v->busy == true) + panic("dec_vnode_ref_count called on vnode that was busy! vnode %p\n", v); + + old_ref = atomic_add(&v->ref_count, -1); + + PRINT(("dec_vnode_ref_count: vnode 0x%x, ref now %d\n", v, v->ref_count)); + + if (old_ref == 1) { + v->busy = true; + + mutex_unlock(&vfs_vnode_mutex); + + /* if we have a vm_cache attached, remove it */ + if (v->cache) + vm_cache_release_ref((vm_cache_ref *)v->cache); + v->cache = NULL; + + if (v->delete_me) + v->mount->fs->calls->fs_removevnode(v->mount->cookie, v->priv_vnode, r); + else + v->mount->fs->calls->fs_putvnode(v->mount->cookie, v->priv_vnode, r); + + remove_vnode_from_mount_list(v, v->mount); + + mutex_lock(&vfs_vnode_mutex); + hash_remove(vnode_table, v); + mutex_unlock(&vfs_vnode_mutex); + + if (free_mem) + kfree(v); + err = 1; + } else { + mutex_unlock(&vfs_vnode_mutex); + err = 0; + } + return err; +} + + +static int +inc_vnode_ref_count(struct vnode *v) +{ + atomic_add(&v->ref_count, 1); + PRINT(("inc_vnode_ref_count: vnode 0x%x, ref now %d\n", v, v->ref_count)); + return 0; +} + + +static struct vnode * +lookup_vnode(fs_id fsid, vnode_id vnid) +{ + struct vnode_hash_key key; + + key.fsid = fsid; + key.vnid = vnid; + + return hash_lookup(vnode_table, &key); +} + + +static int +get_vnode(fs_id fsid, vnode_id vnid, struct vnode **outv, int r) +{ + struct vnode *v; + int err; + + FUNCTION(("get_vnode: fsid %d vnid 0x%x 0x%x\n", fsid, vnid)); + + mutex_lock(&vfs_vnode_mutex); + + do { + v = lookup_vnode(fsid, vnid); + if (v) { + if (v->busy) { + mutex_unlock(&vfs_vnode_mutex); + thread_snooze(10000); // 10 ms + mutex_lock(&vfs_vnode_mutex); + continue; + } + } + } while(0); + + PRINT(("get_vnode: tried to lookup vnode, got 0x%x\n", v)); + + if (v) { + inc_vnode_ref_count(v); + } else { + // we need to create a new vnode and read it in + v = create_new_vnode(); + if(!v) { + err = ENOMEM; + goto err; + } + v->fsid = fsid; + v->vnid = vnid; + v->mount = fsid_to_mount(fsid); + if(!v->mount) { + err = ERR_INVALID_HANDLE; + goto err; + } + v->busy = true; + hash_insert(vnode_table, v); + mutex_unlock(&vfs_vnode_mutex); + + add_vnode_to_mount_list(v, v->mount); + + err = v->mount->fs->calls->fs_getvnode(v->mount->cookie, vnid, &v->priv_vnode, r); + + if(err < 0) + remove_vnode_from_mount_list(v, v->mount); + + mutex_lock(&vfs_vnode_mutex); + if(err < 0) + goto err1; + + v->busy = false; + v->ref_count = 1; + } + + mutex_unlock(&vfs_vnode_mutex); + + PRINT(("get_vnode: returning 0x%x\n", v)); + + *outv = v; + return B_NO_ERROR; + +err1: + hash_remove(vnode_table, v); +err: + mutex_unlock(&vfs_vnode_mutex); + if(v) + kfree(v); + + return err; +} + + +static void +put_vnode(struct vnode *v) +{ + dec_vnode_ref_count(v, true, false); +} + + +int +vfs_get_vnode(fs_id fsid, vnode_id vnid, fs_vnode *fsv) +{ + int err; + struct vnode *v; + + err = get_vnode(fsid, vnid, &v, true); + if (err < 0) + return err; + + *fsv = v->priv_vnode; + return B_NO_ERROR; +} + + +int +vfs_put_vnode(fs_id fsid, vnode_id vnid) +{ + struct vnode *v; + + mutex_lock(&vfs_vnode_mutex); + + v = lookup_vnode(fsid, vnid); + + mutex_unlock(&vfs_vnode_mutex); + if (v) + dec_vnode_ref_count(v, true, true); + + return B_NO_ERROR; +} + + +void +vfs_vnode_acquire_ref(void *v) +{ + FUNCTION(("vfs_vnode_acquire_ref: vnode 0x%x\n", v)); + inc_vnode_ref_count((struct vnode *)v); +} + + +void +vfs_vnode_release_ref(void *v) +{ + FUNCTION(("vfs_vnode_release_ref: vnode 0x%x\n", v)); + dec_vnode_ref_count((struct vnode *)v, true, false); +} + + +int +vfs_remove_vnode(fs_id fsid, vnode_id vnid) +{ + struct vnode *v; + + mutex_lock(&vfs_vnode_mutex); + + v = lookup_vnode(fsid, vnid); + if(v) + v->delete_me = true; + + mutex_unlock(&vfs_vnode_mutex); + return 0; +} + + +void * +vfs_get_cache_ptr(void *vnode) +{ + return ((struct vnode *)vnode)->cache; +} + + +int +vfs_set_cache_ptr(void *vnode, void *cache) +{ + if(test_and_set((int *)&(((struct vnode *)vnode)->cache), (int)cache, 0) == 0) + return 0; + else + return -1; +} + + +static void +vfs_free_fd(struct file_descriptor *f) +{ + if (f->vnode) { + f->vnode->mount->fs->calls->fs_close(f->vnode->mount->cookie, f->vnode->priv_vnode, f->cookie); + f->vnode->mount->fs->calls->fs_freecookie(f->vnode->mount->cookie, f->vnode->priv_vnode, f->cookie); + dec_vnode_ref_count(f->vnode, true, false); + } +} + + +static struct vnode * +get_vnode_from_fd(struct io_context *ioctx, int fd) +{ + struct file_descriptor *f; + struct vnode *v; + + f = get_fd(ioctx, fd); + if (!f) + return NULL; + + v = f->vnode; + if (!v) + goto out; + inc_vnode_ref_count(v); + +out: + put_fd(f); + + return v; +} + + +static struct fs_container * +find_fs(const char *fs_name) +{ + struct fs_container *fs = fs_list; + while(fs != NULL) { + if(strcmp(fs_name, fs->name) == 0) { + return fs; + } + fs = fs->next; + } + return NULL; +} + + +static int +path_to_vnode(char *path, struct vnode **v, bool kernel) +{ + char *p = path; + char *next_p; + struct vnode *curr_v; + struct vnode *next_v; + vnode_id vnid; + int err = 0; + + if (!p) + return EINVAL; + + // figure out if we need to start at root or at cwd + if (*p == '/') { + while (*++p == '/') + ; + curr_v = root_vnode; + inc_vnode_ref_count(curr_v); + } else { + struct io_context *ioctx = get_current_io_context(kernel); + mutex_lock(&ioctx->io_mutex); + curr_v = ioctx->cwd; + inc_vnode_ref_count(curr_v); + mutex_unlock(&ioctx->io_mutex); + } + + for (;;) { +// dprintf("path_to_vnode: top of loop. p 0x%x, *p = %c, p = '%s'\n", p, *p, p); + + // done? + if(*p == '\0') { + err = 0; + break; + } + + // walk to find the next component + for (next_p = p+1; *next_p != '\0' && *next_p != '/'; next_p++); + + if (*next_p == '/') { + *next_p = '\0'; + do + next_p++; + while (*next_p == '/'); + } + + // see if the .. is at the root of a mount + if (strcmp("..", p) == 0 && curr_v->mount->root_vnode == curr_v) { + // move to the covered vnode so we pass the '..' parse to the underlying filesystem + if (curr_v->mount->covers_vnode) { + next_v = curr_v->mount->covers_vnode; + inc_vnode_ref_count(next_v); + dec_vnode_ref_count(curr_v, true, false); + curr_v = next_v; + } + } + + // tell the filesystem to parse this path + err = curr_v->mount->fs->calls->fs_lookup(curr_v->mount->cookie, curr_v->priv_vnode, p, &vnid); + if (err < 0) { + dec_vnode_ref_count(curr_v, true, false); + goto out; + } + + // lookup the vnode, the call to fs_lookup should have caused a get_vnode to be called + // from inside the filesystem, thus the vnode would have to be in the list and it's + // ref count incremented at this point + mutex_lock(&vfs_vnode_mutex); + next_v = lookup_vnode(curr_v->fsid, vnid); + mutex_unlock(&vfs_vnode_mutex); + + if (!next_v) { + // pretty screwed up here + panic("path_to_vnode: could not lookup vnode (fsid 0x%x vnid 0x%Lx)\n", curr_v->fsid, vnid); + err = ERR_VFS_PATH_NOT_FOUND; + dec_vnode_ref_count(curr_v, true, false); + goto out; + } + + // decrease the ref count on the old dir we just looked up into + dec_vnode_ref_count(curr_v, true, false); + + p = next_p; + curr_v = next_v; + + // see if we hit a mount point + if (curr_v->covered_by) { + next_v = curr_v->covered_by; + inc_vnode_ref_count(next_v); + dec_vnode_ref_count(curr_v, true, false); + curr_v = next_v; + } + } + + *v = curr_v; + +out: + return err; +} + + +/** Returns the vnode in the next to last segment of the path, and returns + * the last portion in filename. + */ + +static int +path_to_dir_vnode(char *path, struct vnode **v, char *filename, bool kernel) +{ + char *p; + + p = strrchr(path, '/'); + if (!p) { + // this path is single segment with no '/' in it + // ex. "foo" + strcpy(filename, path); + strcpy(path, "."); + } else { + // replace the filename portion of the path with a '.' + strcpy(filename, p+1); + + if(p[1] != '\0'){ + p[1] = '.'; + p[2] = '\0'; + } + + } + return path_to_vnode(path, v, kernel); +} + + +////////////////////////////////////////////////////////////////////////////////// +// +// XXX -- Warning: horrible hack, just ahead! +// +// the following code implements a version of vnode_to_path() +// which takes an arbitrary vnode and generates the full file path string. +// this is used by vfs_get_cwd() so that the user shell can implement 'pwd' +// +// however... +// +// the method used is to peek into the private vnodes of the filesystem modules. +// this is *BAD MOJO* and only works because all of the current filesystems +// were implemented with a common structure, mimicked by the struct below. +// +// the hack was required because the VFS layer, as it was forked from NewOS, +// did not have a means of acquiring the path info thru a standard method. +// Once we have our own proper implementation of the VFS layer, then the +// gross hack below can be removed... +// + +int vnode_to_path(struct vnode *, char *, int); + + +typedef struct generic_vnode { + struct generic_vnode *all_next; + vnode_id id; + char *name; + void *redir_vnode; + struct generic_vnode *parent; + struct generic_vnode *dir_next; +} +generic_vnode; + + +int vnode_to_path(struct vnode *v, char *buf, int buflen) +{ + int rc; // return code + + if ((v == NULL) || (buf == NULL) || (buflen <= 0)) + return EINVAL; + + // + // ask the filesystem containing the given vnode to fetch + // its local vnode structure for us (returned in v->priv_vnode). + // this fs vnode contains the leaf name and parent link required + // + rc = v->mount-> + fs->calls-> + fs_getvnode(v->mount->cookie, v->vnid, &v->priv_vnode, true); + if (rc < 0) + return rc; + + else { + // + // construct the full path, which is: + // {mount_point}/{relative_path} + // + // the mount point has already been stored, + // but the relative path has to be generated on-the-fly + // + generic_vnode *g = (generic_vnode *) v->priv_vnode; + + char *mpoint = v->mount->mount_point; + int mpointlen = strlen (mpoint); + + char rpath[SYS_MAX_NAME_LEN]; // buffer to hold relative path + int i = sizeof rpath; // current insertion point + int rpathlen = 0; + int len; + + // + // generate relative path: + // start with given leaf vnode and back up to mount point, + // copying leaf names into buffer (right to left) as we go + // + rpath[--i] = '\0'; + + for (; g; g = g->parent) { + // + if (g->name[0]) { + len = strlen (g->name); + i -= len; + memcpy (rpath+i, g->name, len); + rpathlen += len; + } + if (g->parent) { + if (g->parent->id == g->id) + // hit mount point + break; + + rpath[--i] = '/'; + ++rpathlen; + } + } + + if ((mpointlen + rpathlen) > buflen) + return ENOBUFS; + + // + // copy results to output buffer + // + strcpy (buf, mpoint); + if (rpathlen > 0) + strcat (buf, rpath+i); + + return B_OK; + } +} + + +// +// +// XXX - end of the vnode_to_path() hack +// +////////////////////////////////////////////////////////////////////////////////// + + +/** Sets up a new io_control structure, and inherits the properties + * of the parent io_control if it is given. + */ + +void * +vfs_new_io_context(void *_parent_ioctx) +{ + size_t table_size; + struct io_context *ioctx; + struct io_context *parent_ioctx; + + parent_ioctx = (struct io_context *)_parent_ioctx; + if (parent_ioctx) + table_size = parent_ioctx->table_size; + else + table_size = DEFAULT_FD_TABLE_SIZE; + + ioctx = kmalloc(sizeof(struct io_context)); + if (ioctx == NULL) + return NULL; + + memset(ioctx, 0, sizeof(struct io_context)); + + ioctx->fds = kmalloc(sizeof(struct file_descriptor *) * table_size); + if (ioctx->fds == NULL) { + kfree(ioctx); + return NULL; + } + + memset(ioctx->fds, 0, sizeof(struct file_descriptor *) * table_size); + + if (mutex_init(&ioctx->io_mutex, "ioctx_mutex") < 0) { + kfree(ioctx->fds); + kfree(ioctx); + return NULL; + } + + /* + * copy parent files + */ + if (parent_ioctx) { + size_t i; + + mutex_lock(&parent_ioctx->io_mutex); + + ioctx->cwd= parent_ioctx->cwd; + if (ioctx->cwd) { + inc_vnode_ref_count(ioctx->cwd); + } + + + for (i = 0; i< table_size; i++) { + if (parent_ioctx->fds[i]) { + ioctx->fds[i]= parent_ioctx->fds[i]; + atomic_add(&ioctx->fds[i]->ref_count, 1); + } + } + + mutex_unlock(&parent_ioctx->io_mutex); + } else { + ioctx->cwd = root_vnode; + + if (ioctx->cwd) { + inc_vnode_ref_count(ioctx->cwd); + } + } + + ioctx->table_size = table_size; + + return ioctx; +} + + +int +vfs_free_io_context(void *_ioctx) +{ + struct io_context *ioctx = (struct io_context *)_ioctx; + int i; + + if (ioctx->cwd) + dec_vnode_ref_count(ioctx->cwd, true, false); + + mutex_lock(&ioctx->io_mutex); + + for (i = 0; i < ioctx->table_size; i++) { + if (ioctx->fds[i]) + put_fd(ioctx->fds[i]); + } + + mutex_unlock(&ioctx->io_mutex); + + mutex_destroy(&ioctx->io_mutex); + + kfree(ioctx->fds); + kfree(ioctx); + return 0; +} + + +static int +vfs_mount(char *path, const char *device, const char *fs_name, void *args, bool kernel) +{ + struct fs_mount *mount; + int err = 0; + struct vnode *covered_vnode = NULL; + vnode_id root_id; + +#if MAKE_NOIZE + dprintf("vfs_mount: entry. path = '%s', fs_name = '%s'\n", path, fs_name); +#endif + + mutex_lock(&vfs_mount_op_mutex); + + mount = (struct fs_mount *)kmalloc(sizeof(struct fs_mount)); + if(mount == NULL) { + err = ENOMEM; + goto err; + } + + mount->mount_point = kstrdup(path); + if(mount->mount_point == NULL) { + err = ENOMEM; + goto err1; + } + + mount->fs = find_fs(fs_name); + if(mount->fs == NULL) { + err = ERR_VFS_INVALID_FS; + goto err2; + } + + recursive_lock_create(&mount->rlock); + mount->id = next_fsid++; + mount->unmounting = false; + + if(!root_vnode) { + // we haven't mounted anything yet + if(strcmp(path, "/") != 0) { + err = ERR_VFS_GENERAL; + goto err3; + } + + err = mount->fs->calls->fs_mount(&mount->cookie, mount->id, device, NULL, &root_id); + if(err < 0) { + err = ERR_VFS_GENERAL; + goto err3; + } + + mount->covers_vnode = NULL; // this is the root mount + } else { + err = path_to_vnode(path,&covered_vnode,kernel); + if(err < 0) { + goto err2; + } + + if(!covered_vnode) { + err = ERR_VFS_GENERAL; + goto err2; + } + + // XXX insert check to make sure covered_vnode is a DIR, or maybe it's okay for it not to be + + if((covered_vnode != root_vnode) && (covered_vnode->mount->root_vnode == covered_vnode)){ + err = ERR_VFS_ALREADY_MOUNTPOINT; + goto err2; + } + + mount->covers_vnode = covered_vnode; + + // mount it + err = mount->fs->calls->fs_mount(&mount->cookie, mount->id, device, NULL, &root_id); + if(err < 0) + goto err4; + } + + mutex_lock(&vfs_mount_mutex); + + // insert mount struct into list + hash_insert(mounts_table, mount); + + mutex_unlock(&vfs_mount_mutex); + + err = get_vnode(mount->id, root_id, &mount->root_vnode, 0); + if(err < 0) + goto err5; + + // XXX may be a race here + if(mount->covers_vnode) + mount->covers_vnode->covered_by = mount->root_vnode; + + if(!root_vnode) + root_vnode = mount->root_vnode; + + mutex_unlock(&vfs_mount_op_mutex); + + return 0; + +err5: + mount->fs->calls->fs_unmount(mount->cookie); +err4: + if(mount->covers_vnode) + dec_vnode_ref_count(mount->covers_vnode, true, false); +err3: + recursive_lock_destroy(&mount->rlock); +err2: + kfree(mount->mount_point); +err1: + kfree(mount); +err: + mutex_unlock(&vfs_mount_op_mutex); + + return err; +} + + +static int +vfs_unmount(char *path, bool kernel) +{ + struct vnode *v; + struct fs_mount *mount; + int err; + +#if MAKE_NOIZE + dprintf("vfs_unmount: entry. path = '%s', kernel %d\n", path, kernel); +#endif + + err = path_to_vnode(path, &v, kernel); + if(err < 0) { + err = ERR_VFS_PATH_NOT_FOUND; + goto err; + } + + mutex_lock(&vfs_mount_op_mutex); + + mount = fsid_to_mount(v->fsid); + if(!mount) { + panic("vfs_unmount: fsid_to_mount failed on root vnode @%p of mount\n", v); + } + + if(mount->root_vnode != v) { + // not mountpoint + dec_vnode_ref_count(v, true, false); + err = ERR_VFS_NOT_MOUNTPOINT; + goto err1; + } + + /* grab the vnode master mutex to keep someone from creating a vnode + while we're figuring out if we can continue */ + mutex_lock(&vfs_vnode_mutex); + + /* simulate the root vnode having it's refcount decremented */ + mount->root_vnode->ref_count -= 2; + + /* cycle through the list of vnodes associated with this mount and + make sure all of them are not busy or have refs on them */ + err = 0; + for(v = mount->vnodes_head; v; v = v->mount_next) { + if(v->busy || v->ref_count != 0) { + mount->root_vnode->ref_count += 2; + mutex_unlock(&vfs_vnode_mutex); + dec_vnode_ref_count(mount->root_vnode, true, false); + err = EBUSY; + goto err1; + } + } + + /* we can safely continue, mark all of the vnodes busy and this mount + structure in unmounting state */ + for(v = mount->vnodes_head; v; v = v->mount_next) + if(v != mount->root_vnode) + v->busy = true; + mount->unmounting = true; + + mutex_unlock(&vfs_vnode_mutex); + + mount->covers_vnode->covered_by = NULL; + dec_vnode_ref_count(mount->covers_vnode, true, false); + + /* release the ref on the root vnode twice */ + dec_vnode_ref_count(mount->root_vnode, true, false); + dec_vnode_ref_count(mount->root_vnode, true, false); + + // XXX when full vnode cache in place, will need to force + // a putvnode/removevnode here + + /* remove the mount structure from the hash table */ + mutex_lock(&vfs_mount_mutex); + hash_remove(mounts_table, mount); + mutex_unlock(&vfs_mount_mutex); + + mutex_unlock(&vfs_mount_op_mutex); + + mount->fs->calls->fs_unmount(mount->cookie); + + kfree(mount->mount_point); + kfree(mount); + + return 0; + +err1: + mutex_unlock(&vfs_mount_op_mutex); +err: + return err; +} + + +static int +vfs_sync(void) +{ + struct hash_iterator iter; + struct fs_mount *mount; + +#if MAKE_NOIZE + dprintf("vfs_sync: entry.\n"); +#endif + + /* cycle through and call sync on each mounted fs */ + mutex_lock(&vfs_mount_op_mutex); + mutex_lock(&vfs_mount_mutex); + + hash_open(mounts_table, &iter); + while((mount = hash_next(mounts_table, &iter))) { + mount->fs->calls->fs_sync(mount->cookie); + } + hash_close(mounts_table, &iter, false); + + mutex_unlock(&vfs_mount_mutex); + mutex_unlock(&vfs_mount_op_mutex); + + return 0; +} + + +static int +vfs_open(char *path, stream_type st, int omode, bool kernel) +{ + int fd; + struct vnode *v; + file_cookie cookie; + struct file_descriptor *f; + int err; + +//dprintf("vfs_open: %s: omode = %d\n", path, omode); +#if MAKE_NOIZE + dprintf("vfs_open: entry. path = '%s', omode %d, kernel %d\n", path, omode, kernel); +#endif + + err = path_to_vnode(path, &v, kernel); + if (err < 0) + goto err; + +//dprintf("calling fs_open, v= %p\n", v); + + err = v->mount->fs->calls->fs_open(v->mount->cookie, v->priv_vnode, &cookie, st, omode); + if (err < 0) + goto err1; + + // file is opened, create a fd + f = alloc_fd(); + if (!f) { + // xxx leaks + err = ENOMEM; + goto err1; + } + f->vnode = v; + f->cookie = cookie; + f->ops = &vfsops; + f->type = FDTYPE_VNODE; + + fd = new_fd(get_current_io_context(kernel), f); + if (fd < 0) { + err = ERR_VFS_FD_TABLE_FULL; + goto err1; + } + + return fd; + + /* ??? - will this ever be called??? */ + vfs_free_fd(f); +err1: + dec_vnode_ref_count(v, true, false); +err: + return err; +} + + +static int +vfs_close(struct file_descriptor *f, int fd, struct io_context *io) +{ + remove_fd(io, fd); + + return 0; +} + + +static int +vfs_fsync(int fd, bool kernel) +{ + struct file_descriptor *f; + struct vnode *v; + int err; + +#if MAKE_NOIZE + dprintf("vfs_fsync: entry. fd %d kernel %d\n", fd, kernel); +#endif + + f = get_fd(get_current_io_context(kernel), fd); + if (!f) + return ERR_INVALID_HANDLE; + + v = f->vnode; + err = v->mount->fs->calls->fs_fsync(v->mount->cookie, v->priv_vnode); + + put_fd(f); + + return err; +} + + +static ssize_t +vfs_read(struct file_descriptor *f, void *buffer, off_t pos, size_t *length) +{ + struct vnode *v = f->vnode; + + FUNCTION(("vfs_read: fd = %d, buf 0x%x, pos 0x%x 0x%x, len 0x%x, kernel %d\n", fd, buffer, pos, length, kernel)); + + return v->mount->fs->calls->fs_read(v->mount->cookie, v->priv_vnode, f->cookie, buffer, pos, length); +} + + +static ssize_t +vfs_write(struct file_descriptor *f, const void *buffer, off_t pos, size_t *length) +{ + struct vnode *v = f->vnode; + + FUNCTION(("vfs_write: fd = %d, buf 0x%x, pos 0x%x 0x%x, len 0x%x\n", fd, buffer, pos, length)); + + return v->mount->fs->calls->fs_write(v->mount->cookie, v->priv_vnode, f->cookie, buffer, pos, length); +} + + +static int +vfs_seek(int fd, off_t pos, int seek_type, bool kernel) +{ + struct vnode *v; + struct file_descriptor *f; + int err; + +#if MAKE_NOIZE + dprintf("vfs_seek: fd = %d, pos 0x%x 0x%x, seek_type %d, kernel %d\n", fd, pos, seek_type, kernel); +#endif + + f = get_fd(get_current_io_context(kernel), fd); + if(!f) { + err = EBADF; + goto err; + } + + v = f->vnode; + err = v->mount->fs->calls->fs_seek(v->mount->cookie, v->priv_vnode, f->cookie, pos, seek_type); + + put_fd(f); + +err: + return err; +} + + +static status_t +vfs_read_dir(struct file_descriptor *descriptor, struct dirent *buffer, size_t bufferSize, uint32 *_count) +{ + struct vnode *vnode = descriptor->vnode; + + if (FS_CALL(vnode,fs_read_dir)) + return FS_CALL(vnode,fs_read_dir)(vnode->mount->cookie,vnode->priv_vnode,descriptor->cookie,buffer,bufferSize,_count); + + return EOPNOTSUPP; +} + + +static status_t +vfs_rewind_dir(struct file_descriptor *descriptor) +{ + struct vnode *vnode = descriptor->vnode; + + if (FS_CALL(vnode,fs_rewind_dir)) + return FS_CALL(vnode,fs_rewind_dir)(vnode->mount->cookie,vnode->priv_vnode,descriptor->cookie); + + return EOPNOTSUPP; +} + + +static int +vfs_ioctl(struct file_descriptor *f, ulong op, void *buf, size_t len) +{ + struct vnode *v = f->vnode; + + FUNCTION(("vfs_ioctl: f = %p, op 0x%x, buf 0x%x, len 0x%x\n", f, op, buffer, length)); + + return v->mount->fs->calls->fs_ioctl(v->mount->cookie, v->priv_vnode, f->cookie, op, buf, len); +} + + +static int +vfs_create(char *path, stream_type stream_type, void *args, bool kernel) +{ + int err; + struct vnode *v; + char filename[SYS_MAX_NAME_LEN]; + vnode_id vnid; + + FUNCTION(("vfs_create: path '%s', stream_type %d, args 0x%x, kernel %d\n", path, stream_type, args, kernel)); + + err = path_to_dir_vnode(path, &v, filename, kernel); + if(err < 0) + goto err; + + err = v->mount->fs->calls->fs_create(v->mount->cookie, v->priv_vnode, filename, stream_type, args, &vnid); + + dec_vnode_ref_count(v, true, false); +err: + return err; +} + + +static int +vfs_unlink(char *path, bool kernel) +{ + int err; + struct vnode *v; + char filename[SYS_MAX_NAME_LEN]; + + FUNCTION(("vfs_unlink: path '%s', kernel %d\n", path, kernel)); + + err = path_to_dir_vnode(path, &v, filename, kernel); + if(err < 0) + goto err; + + err = v->mount->fs->calls->fs_unlink(v->mount->cookie, v->priv_vnode, filename); + dec_vnode_ref_count(v, true, false); +err: + return err; +} + + +static int +vfs_rename(char *path, char *newpath, bool kernel) +{ + struct vnode *v1, *v2; + char filename1[SYS_MAX_NAME_LEN]; + char filename2[SYS_MAX_NAME_LEN]; + int err; + + err = path_to_dir_vnode(path, &v1, filename1, kernel); + if (err < 0) + goto err; + + err = path_to_dir_vnode(newpath, &v2, filename2, kernel); + if (err < 0) + goto err1; + + if (v1->fsid != v2->fsid) { + err = ERR_VFS_CROSS_FS_RENAME; + goto err2; + } + + if (v1->mount->fs->calls->fs_rename != NULL) + err = v1->mount->fs->calls->fs_rename(v1->mount->cookie, v1->priv_vnode, filename1, v2->priv_vnode, filename2); + else + err = EINVAL; + +err2: + dec_vnode_ref_count(v2, true, false); +err1: + dec_vnode_ref_count(v1, true, false); +err: + return err; +} + + +static int +vfs_rstat(struct file_descriptor *f, struct stat *stat) +{ + int err; + struct vnode *v = f->vnode; + + FUNCTION(("vfs_rstat: path '%s', stat 0x%x\n", path, stat)); + + dprintf("vfs_rstat (%p, %p)\n", f, stat); + err = v->mount->fs->calls->fs_rstat(v->mount->cookie, v->priv_vnode, stat); + dprintf("vfs_rstat: fs_stat gave %d\n", err); + return err; +} + + +static int +vfs_wstat(char *path, struct stat *stat, int stat_mask, bool kernel) +{ + int err; + struct vnode *v; + + FUNCTION(("vfs_wstat: path '%s', stat 0x%x, stat_mask %d, kernel %d\n", path, stat, stat_mask, kernel)); + + err = path_to_vnode(path, &v, kernel); + if (err < 0) + goto err; + + err = v->mount->fs->calls->fs_wstat(v->mount->cookie, v->priv_vnode, stat, stat_mask); + + dec_vnode_ref_count(v, true, false); +err: + return err; +} + + +int +vfs_get_vnode_from_fd(int fd, bool kernel, void **vnode) +{ + struct io_context *ioctx; + + ioctx = get_current_io_context(kernel); + *vnode = get_vnode_from_fd(ioctx, fd); + + if (*vnode == NULL) + return ERR_INVALID_HANDLE; + + return B_NO_ERROR; +} + + +int +vfs_get_vnode_from_path(const char *path, bool kernel, void **vnode) +{ + struct vnode *v; + int err; + char buf[SYS_MAX_PATH_LEN+1]; + +#if MAKE_NOIZE + dprintf("vfs_get_vnode_from_path: entry. path = '%s', kernel %d\n", path, kernel); +#endif + + strncpy(buf, path, SYS_MAX_PATH_LEN); + buf[SYS_MAX_PATH_LEN] = 0; + + err = path_to_vnode(buf, &v, kernel); + if(err < 0) + goto err; + + *vnode = v; + +err: + return err; +} + + +int +vfs_put_vnode_ptr(void *vnode) +{ + struct vnode *v = vnode; + + put_vnode(v); + + return 0; +} + + +ssize_t +vfs_canpage(void *_v) +{ + struct vnode *v = _v; + +#if MAKE_NOIZE + dprintf("vfs_canpage: vnode 0x%x\n", v); +#endif + + return v->mount->fs->calls->fs_canpage(v->mount->cookie, v->priv_vnode); +} + + +ssize_t +vfs_readpage(void *_v, iovecs *vecs, off_t pos) +{ + struct vnode *v = _v; + +#if MAKE_NOIZE + dprintf("vfs_readpage: vnode 0x%x, vecs 0x%x, pos 0x%x 0x%x\n", v, vecs, pos); +#endif + + return v->mount->fs->calls->fs_readpage(v->mount->cookie, v->priv_vnode, vecs, pos); +} + + +ssize_t +vfs_writepage(void *_v, iovecs *vecs, off_t pos) +{ + struct vnode *v = _v; + +#if MAKE_NOIZE + dprintf("vfs_writepage: vnode 0x%x, vecs 0x%x, pos 0x%x 0x%x\n", v, vecs, pos); +#endif + + return v->mount->fs->calls->fs_writepage(v->mount->cookie, v->priv_vnode, vecs, pos); +} + + +// +// XXX -- Fixme: uses vnode_to_path() hack +// + +static int +vfs_get_cwd(char* buf, size_t size, bool kernel) +{ + // Get current working directory from io context + +#if MAKE_NOIZE + dprintf("vfs_get_cwd: buf 0x%x, 0x%x\n", buf, size); +#endif + + { + struct vnode* cwd = get_current_io_context(kernel)->cwd; + if (cwd) + // + // vnode_to_path() takes the cwd vnode and computes + // a full path string from it, which is then copied + // into the given buffer. + // + // WARNING: the current version of this function + // utilizes a gross hack and will be removed and/or + // replaced in the future... + // + return vnode_to_path(cwd, buf, size); + else + return B_ERROR; + } +} + + +static int +vfs_set_cwd(char* path, bool kernel) +{ + struct io_context* curr_ioctx; + struct vnode* v = NULL; + struct vnode* old_cwd; + struct stat stat; + int rc; + +#if MAKE_NOIZE + dprintf("vfs_set_cwd: path=\'%s\'\n", path); +#endif + + // Get vnode for passed path, and bail if it failed + rc = path_to_vnode(path, &v, kernel); + if (rc < 0) { + goto err; + } + + rc = v->mount->fs->calls->fs_rstat(v->mount->cookie, v->priv_vnode, &stat); + if(rc < 0) { + goto err1; + } + + if(!S_ISDIR(stat.st_mode)) { + // nope, can't cwd to here + rc = ERR_VFS_WRONG_STREAM_TYPE; + goto err1; + } + + // Get current io context and lock + curr_ioctx = get_current_io_context(kernel); + mutex_lock(&curr_ioctx->io_mutex); + + // save the old cwd + old_cwd = curr_ioctx->cwd; + + // Set the new vnode + curr_ioctx->cwd = v; + + // Unlock the ioctx + mutex_unlock(&curr_ioctx->io_mutex); + + // Decrease ref count of previous working dir (as the ref is being replaced) + if (old_cwd) + dec_vnode_ref_count(old_cwd, true, false); + + return B_NO_ERROR; + +err1: + dec_vnode_ref_count(v, true, false); +err: + return rc; +} + + +static int +vfs_dup(int fd, bool kernel) +{ + struct io_context *io = get_current_io_context(kernel); + struct file_descriptor *f; + int rc; + +#if MAKE_NOIZE + dprintf("vfs_dup: fd=%d\n", fd); +#endif + + // Try to get the fd structure + f = get_fd(io, fd); + if (!f) { + rc = ERR_INVALID_HANDLE; + goto err; + } + + // now put the fd in place + rc = new_fd(io, f); + + if (rc < 0) + put_fd(f); + +err: + return rc; +} + + +static int +vfs_dup2(int ofd, int nfd, bool kernel) +{ + struct io_context *curr_ioctx; + struct file_descriptor *evicted; + int rc; + +#if MAKE_NOIZE + dprintf("vfs_dup2: ofd=%d nfd=%d\n", ofd, nfd); +#endif + + // quick check + if ((ofd < 0) || (nfd < 0)) { + rc = ERR_INVALID_HANDLE; + goto err; + } + + // Get current io context and lock + curr_ioctx = get_current_io_context(kernel); + mutex_lock(&curr_ioctx->io_mutex); + + // Check for upper boundary, we do in the locked part + // because in the future the fd table might be resizeable + if ((ofd >= curr_ioctx->table_size) || !curr_ioctx->fds[ofd]) { + rc = ERR_INVALID_HANDLE; + goto err_1; + } + if ((nfd >= curr_ioctx->table_size)) { + rc = ERR_INVALID_HANDLE; + goto err_1; + } + + // Check for identity, note that it cannot be made above + // because we always want to return an error on invalid + // handles + if (ofd == nfd) + // ToDo: this is buggy and doesn't unlock the io mutex! + goto success; + + // Now do the work + evicted = curr_ioctx->fds[nfd]; + curr_ioctx->fds[nfd] = curr_ioctx->fds[ofd]; + atomic_add(&curr_ioctx->fds[ofd]->ref_count, 1); + + // Unlock the ioctx + mutex_unlock(&curr_ioctx->io_mutex); + + // Say bye bye to the evicted fd + if (evicted) + put_fd(evicted); + +success: + rc = nfd; + return nfd; + +err_1: + mutex_unlock(&curr_ioctx->io_mutex); +err: + return rc; +} + + +// #pragma mark - +// Calls from within the kernel + + +int +sys_mount(const char *path, const char *device, const char *fs_name, void *args) +{ + char buf[SYS_MAX_PATH_LEN+1]; + + strncpy(buf, path, SYS_MAX_PATH_LEN); + buf[SYS_MAX_PATH_LEN] = 0; + + return vfs_mount(buf, device, fs_name, args, true); +} + + +int +sys_unmount(const char *path) +{ + char buf[SYS_MAX_PATH_LEN+1]; + + strncpy(buf, path, SYS_MAX_PATH_LEN); + buf[SYS_MAX_PATH_LEN] = 0; + + return vfs_unmount(buf, true); +} + + +int +sys_sync(void) +{ + return vfs_sync(); +} + + +int +sys_open(const char *path, stream_type st, int omode) +{ + char buf[SYS_MAX_PATH_LEN+1]; + + strncpy(buf, path, SYS_MAX_PATH_LEN); + buf[SYS_MAX_PATH_LEN] = 0; + + return vfs_open(buf, st, omode, true); +} + + +int +sys_fsync(int fd) +{ + return vfs_fsync(fd, true); +} + + +int +sys_seek(int fd, off_t pos, int seek_type) +{ + return vfs_seek(fd, pos, seek_type, true); +} + + +int +sys_create(const char *path, stream_type stream_type) +{ + char buf[SYS_MAX_PATH_LEN+1]; + + strncpy(buf, path, SYS_MAX_PATH_LEN); + buf[SYS_MAX_PATH_LEN] = 0; + + return vfs_create(buf, stream_type, NULL, true); +} + + +int +sys_unlink(const char *path) +{ + char buf[SYS_MAX_PATH_LEN+1]; + + strncpy(buf, path, SYS_MAX_PATH_LEN); + buf[SYS_MAX_PATH_LEN] = 0; + + return vfs_unlink(buf, true); +} + + +int +sys_rename(const char *oldpath, const char *newpath) +{ + char buf1[SYS_MAX_PATH_LEN+1]; + char buf2[SYS_MAX_PATH_LEN+1]; + + strncpy(buf1, oldpath, SYS_MAX_PATH_LEN); + buf1[SYS_MAX_PATH_LEN] = 0; + + strncpy(buf2, newpath, SYS_MAX_PATH_LEN); + buf2[SYS_MAX_PATH_LEN] = 0; + + return vfs_rename(buf1, buf2, true); +} + + +int +sys_rstat(const char *path, struct stat *stat) +{ + char buf[SYS_MAX_PATH_LEN+1]; + int err; + struct vnode *v; + + strncpy(buf, path, SYS_MAX_PATH_LEN); + buf[SYS_MAX_PATH_LEN] = 0; + +#if MAKE_NOIZE + dprintf("sys_rstat: path '%s', stat 0x%x,\n", path, stat); +#endif + err = path_to_vnode(buf, &v, true); + if(err < 0) + goto err; + + err = v->mount->fs->calls->fs_rstat(v->mount->cookie, v->priv_vnode, stat); + + dec_vnode_ref_count(v, true, false); +err: + return err; +} + + +int +sys_wstat(const char *path, struct stat *stat, int stat_mask) +{ + char buf[SYS_MAX_PATH_LEN+1]; + + strncpy(buf, path, SYS_MAX_PATH_LEN); + buf[SYS_MAX_PATH_LEN] = 0; + + return vfs_wstat(buf, stat, stat_mask, true); +} + + +char * +sys_getcwd(char *buf, size_t size) +{ + char path[SYS_MAX_PATH_LEN]; + int rc; + +#if MAKE_NOIZE + dprintf("sys_getcwd: buf 0x%x, 0x%x\n", buf, size); +#endif + + // Call vfs to get current working directory + rc = vfs_get_cwd(path,SYS_MAX_PATH_LEN-1,true); + path[SYS_MAX_PATH_LEN-1] = 0; + + // Copy back the result + strncpy(buf,path,size); + + // Return either NULL or the buffer address to indicate failure or success + return (rc < 0) ? NULL : buf; +} + + +int +sys_setcwd(const char* _path) +{ + char path[SYS_MAX_PATH_LEN]; + +#if MAKE_NOIZE + dprintf("sys_setcwd: path=0x%x\n", _path); +#endif + + // Copy new path to kernel space + strncpy(path, _path, SYS_MAX_PATH_LEN-1); + path[SYS_MAX_PATH_LEN-1] = 0; + + // Call vfs to set new working directory + return vfs_set_cwd(path,true); +} + + +int +sys_dup(int fd) +{ + return vfs_dup(fd, true); +} + + +int +sys_dup2(int ofd, int nfd) +{ + return vfs_dup2(ofd, nfd, true); +} + + +// #pragma mark - +// Calls from userland (with extra address checks) + + +int +user_mount(const char *upath, const char *udevice, const char *ufs_name, void *args) +{ + char path[SYS_MAX_PATH_LEN+1]; + char fs_name[SYS_MAX_OS_NAME_LEN+1]; + char device[SYS_MAX_PATH_LEN+1]; + int rc; + + if ((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + if ((addr)ufs_name >= KERNEL_BASE && (addr)ufs_name <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + if (udevice) { + if((addr)udevice >= KERNEL_BASE && (addr)udevice <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + } + + rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN); + if (rc < 0) + return rc; + path[SYS_MAX_PATH_LEN] = 0; + + rc = user_strncpy(fs_name, ufs_name, SYS_MAX_OS_NAME_LEN); + if (rc < 0) + return rc; + fs_name[SYS_MAX_OS_NAME_LEN] = 0; + + if (udevice) { + rc = user_strncpy(device, udevice, SYS_MAX_PATH_LEN); + if(rc < 0) + return rc; + device[SYS_MAX_PATH_LEN] = 0; + } else { + device[0] = 0; + } + + return vfs_mount(path, device, fs_name, args, false); +} + + +int +user_unmount(const char *upath) +{ + char path[SYS_MAX_PATH_LEN+1]; + int rc; + + rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN); + if (rc < 0) + return rc; + path[SYS_MAX_PATH_LEN] = 0; + + return vfs_unmount(path, false); +} + + +int +user_sync(void) +{ + return vfs_sync(); +} + + +int +user_open(const char *upath, stream_type st, int omode) +{ + char path[SYS_MAX_PATH_LEN]; + int rc; + +dprintf("user_open\n"); + + if ((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN-1); + if(rc < 0) + return rc; + path[SYS_MAX_PATH_LEN-1] = 0; +dprintf("calling vfs_open(%s)\n", path); + + return vfs_open(path, st, omode, false); +} + + +int +user_fsync(int fd) +{ + return vfs_fsync(fd, false); +} + + +int +user_seek(int fd, off_t pos, int seek_type) +{ + return vfs_seek(fd, pos, seek_type, false); +} + + +int +user_create(const char *upath, stream_type stream_type) +{ + char path[SYS_MAX_PATH_LEN]; + int rc; + + if((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN-1); + if(rc < 0) + return rc; + path[SYS_MAX_PATH_LEN-1] = 0; + + return vfs_create(path, stream_type, NULL, false); +} + + +int +user_unlink(const char *upath) +{ + char path[SYS_MAX_PATH_LEN+1]; + int rc; + + if((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN); + if(rc < 0) + return rc; + path[SYS_MAX_PATH_LEN] = 0; + + return vfs_unlink(path, false); +} + + +int +user_rename(const char *uoldpath, const char *unewpath) +{ + char oldpath[SYS_MAX_PATH_LEN+1]; + char newpath[SYS_MAX_PATH_LEN+1]; + int rc; + + if((addr)uoldpath >= KERNEL_BASE && (addr)uoldpath <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + if((addr)unewpath >= KERNEL_BASE && (addr)unewpath <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + rc = user_strncpy(oldpath, uoldpath, SYS_MAX_PATH_LEN); + if(rc < 0) + return rc; + oldpath[SYS_MAX_PATH_LEN] = 0; + + rc = user_strncpy(newpath, unewpath, SYS_MAX_PATH_LEN); + if(rc < 0) + return rc; + newpath[SYS_MAX_PATH_LEN] = 0; + + return vfs_rename(oldpath, newpath, false); +} + + +int +user_rstat(const char *upath, struct stat *ustat) +{ + char path[SYS_MAX_PATH_LEN]; + struct stat stat; + int rc, rc2; + struct vnode *v = NULL; + + if((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + if((addr)ustat >= KERNEL_BASE && (addr)ustat <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN-1); + if(rc < 0) + return rc; + path[SYS_MAX_PATH_LEN-1] = 0; + + rc = path_to_vnode(path, &v, false); + if (rc < 0) + return rc; + + rc = v->mount->fs->calls->fs_rstat(v->mount->cookie, v->priv_vnode, &stat); + + dec_vnode_ref_count(v, true, false); + + rc2 = user_memcpy(ustat, &stat, sizeof(struct stat)); + if(rc2 < 0) + return rc2; + + return rc; +} + + +int +user_wstat(const char *upath, struct stat *ustat, int stat_mask) +{ + char path[SYS_MAX_PATH_LEN+1]; + struct stat stat; + int rc; + + if((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + if((addr)ustat >= KERNEL_BASE && (addr)ustat <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN); + if(rc < 0) + return rc; + path[SYS_MAX_PATH_LEN] = 0; + + rc = user_memcpy(&stat, ustat, sizeof(struct stat)); + if(rc < 0) + return rc; + + return vfs_wstat(path, &stat, stat_mask, false); +} + + +int +user_getcwd(char *buf, size_t size) +{ + char path[SYS_MAX_PATH_LEN]; + int rc, rc2; + +#if MAKE_NOIZE + dprintf("user_getcwd: buf 0x%x, 0x%x\n", buf, size); +#endif + + // Check if userspace address is inside "shared" kernel space + if((addr)buf >= KERNEL_BASE && (addr)buf <= KERNEL_TOP) + return NULL; //ERR_VM_BAD_USER_MEMORY; + + // Call vfs to get current working directory + rc = vfs_get_cwd(path, SYS_MAX_PATH_LEN-1, false); + if(rc < 0) + return rc; + + // Copy back the result + rc2 = user_strncpy(buf, path, size); + if(rc2 < 0) + return rc2; + + return rc; +} + + +int +user_setcwd(const char* upath) +{ + char path[SYS_MAX_PATH_LEN]; + int rc; + +#if MAKE_NOIZE + dprintf("user_setcwd: path=0x%x\n", upath); +#endif + + // Check if userspace address is inside "shared" kernel space + if((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + // Copy new path to kernel space + rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN-1); + if (rc < 0) { + return rc; + } + path[SYS_MAX_PATH_LEN-1] = 0; + + // Call vfs to set new working directory + return vfs_set_cwd(path,false); +} + + +int +user_dup(int fd) +{ + return vfs_dup(fd, false); +} + + +int +user_dup2(int ofd, int nfd) +{ + return vfs_dup2(ofd, nfd, false); +} + + +// #pragma mark - + + +static int +vfs_resize_fd_table(struct io_context *ioctx, const int new_size) +{ + void * new_fds; + int ret; + + if (new_size < 0 || new_size > MAX_FD_TABLE_SIZE) + return -1; + + mutex_lock(&ioctx->io_mutex); + + if (new_size < ioctx->table_size) { + int i; + + /* Make sure none of the fds being dropped are in use */ + for(i = new_size; i < ioctx->table_size; i++) { + if (ioctx->fds[i]) { + ret = -1; + goto error; + } + } + + new_fds = kmalloc(sizeof(struct file_descriptor *) * new_size); + if (!new_fds) { + ret = -1; + goto error; + } + + memcpy(new_fds, ioctx->fds, sizeof(struct file_descriptor *) * new_size); + } else { + new_fds = kmalloc(sizeof(struct file_descriptor *) * new_size); + if (!new_fds) { + ret = -1; + goto error; + } + + memcpy(new_fds, ioctx->fds, sizeof(struct file_descriptor *) * ioctx->table_size); + memset(((char *)new_fds) + (sizeof(struct file_descriptor *) * ioctx->table_size), 0, + (sizeof(struct file_descriptor *) * new_size) - (sizeof(struct file_descriptor *) * ioctx->table_size)); + } + + kfree(ioctx->fds); + ioctx->fds = new_fds; + ioctx->table_size = new_size; + + mutex_unlock(&ioctx->io_mutex); + + return 0; + +error: + mutex_unlock(&ioctx->io_mutex); + + return ret; +} + + +int +vfs_getrlimit(int resource, struct rlimit * rlp) +{ + if (!rlp) { + return -1; + } + + switch (resource) { + case RLIMIT_NOFILE: + { + struct io_context *ioctx = get_current_io_context(false); + + mutex_lock(&ioctx->io_mutex); + + rlp->rlim_cur = ioctx->table_size; + rlp->rlim_max = MAX_FD_TABLE_SIZE; + + mutex_unlock(&ioctx->io_mutex); + + return 0; + } + + default: + return -1; + } +} + + +int +vfs_setrlimit(int resource, const struct rlimit * rlp) +{ + if (!rlp) + return -1; + + switch (resource) { + case RLIMIT_NOFILE: + return vfs_resize_fd_table(get_current_io_context(false), rlp->rlim_cur); + + default: + return -1; + } +} + + +#ifdef DEBUG + +int +vfs_test(void) +{ + int fd; + int err; + + dprintf("vfs_test() entry\n"); + + fd = sys_open("/", STREAM_TYPE_DIR, 0); + dprintf("fd = %d\n", fd); + sys_close(fd); + + fd = sys_open("/", STREAM_TYPE_DIR, 0); + dprintf("fd = %d\n", fd); + + sys_create("/foo", STREAM_TYPE_DIR); + sys_create("/foo/bar", STREAM_TYPE_DIR); + sys_create("/foo/bar/gar", STREAM_TYPE_DIR); + sys_create("/foo/bar/tar", STREAM_TYPE_DIR); + +#if 1 + fd = sys_open("/foo/bar", STREAM_TYPE_DIR, 0); + if(fd < 0) + panic("unable to open /foo/bar\n"); + + { + char buf[64]; + ssize_t len; + + sys_seek(fd, 0, SEEK_SET); + for(;;) { + len = sys_read(fd, buf, -1, sizeof(buf)); +// if(len <= 0) +// panic("readdir returned %Ld\n", (long long)len); + if(len > 0) + dprintf("readdir returned name = '%s'\n", buf); + else { + dprintf("readdir returned %s\n", strerror(len)); + break; + } + } + } + + // do some unlink tests + err = sys_unlink("/foo/bar"); + if(err == B_NO_ERROR) + panic("unlink of full directory should not have passed\n"); + sys_unlink("/foo/bar/gar"); + sys_unlink("/foo/bar/tar"); + err = sys_unlink("/foo/bar"); + if(err != B_NO_ERROR) + panic("unlink of empty directory should have worked\n"); + + sys_create("/test", STREAM_TYPE_DIR); + sys_create("/test", STREAM_TYPE_DIR); + err = sys_mount("/test", NULL, "rootfs", NULL); + if(err < 0) + panic("failed mount test\n"); + +#endif +#if 1 + + fd = sys_open("/boot", STREAM_TYPE_DIR, 0); + sys_close(fd); + + fd = sys_open("/boot", STREAM_TYPE_DIR, 0); + if(fd < 0) + panic("unable to open dir /boot\n"); + { + char buf[64]; + ssize_t len; + + sys_seek(fd, 0, SEEK_SET); + for(;;) { + len = sys_read(fd, buf, -1, sizeof(buf)); +// if(len < 0) +// panic("readdir returned %Ld\n", (long long)len); + if(len > 0) + dprintf("sys_read returned name = '%s'\n", buf); + else { + dprintf("sys_read returned %s\n", strerror(len)); + break; + } + } + } + sys_close(fd); + + fd = sys_open("/boot/kernel", STREAM_TYPE_FILE, 0); + if(fd < 0) + panic("unable to open kernel file '/boot/kernel'\n"); + { + char buf[64]; + ssize_t len; + + len = sys_read(fd, buf, 0, sizeof(buf)); + if(len < 0) + panic("failed on read\n"); + dprintf("read returned %Ld\n", (long long)len); + } + sys_close(fd); + { + struct stat stat; + + err = sys_rstat("/boot/kernel", &stat); + if(err < 0) + panic("err stating '/boot/kernel'\n"); + dprintf("stat results:\n"); + dprintf("\tvnid 0x%Lx\n\ttype %d\n\tsize 0x%Lx\n", stat.st_ino, stat.st_mode, stat.st_size); + } + +#endif + dprintf("vfs_test() done\n"); +// panic("foo\n"); + return 0; +} + +#endif + + +image_id +vfs_load_fs_module(const char *name) +{ + image_id id; + void (*bootstrap)(); + char path[SYS_MAX_PATH_LEN]; + +// sprintf(path, "/boot/addons/fs/%s", name); + + id = elf_load_kspace(path, ""); + if(id < 0) + return id; + + bootstrap = (void *)elf_lookup_symbol(id, "fs_bootstrap"); + if(!bootstrap) + return ERR_VFS_INVALID_FS; + + bootstrap(); + + return id; +} + + +int +vfs_bootstrap_all_filesystems(void) +{ + int err; + int fd; + + // bootstrap the root filesystem + bootstrap_rootfs(); + + err = sys_mount("/", NULL, "rootfs", NULL); + if(err < 0) + panic("error mounting rootfs!\n"); + + sys_setcwd("/"); + + // bootstrap the bootfs + bootstrap_bootfs(); + + sys_create("/boot", STREAM_TYPE_DIR); + err = sys_mount("/boot", NULL, "bootfs", NULL); + if(err < 0) + panic("error mounting bootfs\n"); + + // bootstrap the devfs + bootstrap_devfs(); + + sys_create("/dev", STREAM_TYPE_DIR); + err = sys_mount("/dev", NULL, "devfs", NULL); + if(err < 0) + panic("error mounting devfs\n"); + + fd = sys_open("/boot/addons/fs", STREAM_TYPE_DIR, 0); + if (fd >= 0) { + ssize_t len; + char buf[SYS_MAX_NAME_LEN]; + + while ((len = sys_read(fd, buf, 0, sizeof(buf))) > 0) { + vfs_load_fs_module(buf); + } + sys_close(fd); + } + + return B_NO_ERROR; +} + + +int +vfs_register_filesystem(const char *name, struct fs_calls *calls) +{ + struct fs_container *container; + + container = (struct fs_container *)kmalloc(sizeof(struct fs_container)); + if(container == NULL) + return ENOMEM; + + container->name = name; + container->calls = calls; + + mutex_lock(&vfs_mutex); + + container->next = fs_list; + fs_list = container; + + mutex_unlock(&vfs_mutex); + return 0; +} + + +int +vfs_init(kernel_args *ka) +{ + { + struct vnode *v; + vnode_table = hash_init(VNODE_HASH_TABLE_SIZE, (addr)&v->next - (addr)v, + &vnode_compare, &vnode_hash); + if(vnode_table == NULL) + panic("vfs_init: error creating vnode hash table\n"); + } + { + struct fs_mount *mount; + mounts_table = hash_init(MOUNTS_HASH_TABLE_SIZE, (addr)&mount->next - (addr)mount, + &mount_compare, &mount_hash); + if(mounts_table == NULL) + panic("vfs_init: error creating mounts hash table\n"); + } + fs_list = NULL; + root_vnode = NULL; + + if(mutex_init(&vfs_mutex, "vfs_lock") < 0) + panic("vfs_init: error allocating vfs lock\n"); + + if(mutex_init(&vfs_mount_op_mutex, "vfs_mount_op_lock") < 0) + panic("vfs_init: error allocating vfs_mount_op lock\n"); + + if(mutex_init(&vfs_mount_mutex, "vfs_mount_lock") < 0) + panic("vfs_init: error allocating vfs_mount lock\n"); + + if(mutex_init(&vfs_vnode_mutex, "vfs_vnode_lock") < 0) + panic("vfs_init: error allocating vfs_vnode lock\n"); + + return 0; +} diff --git a/src/kernel/core/gdb.c b/src/kernel/core/gdb.c new file mode 100644 index 0000000000..5dc3194e9d --- /dev/null +++ b/src/kernel/core/gdb.c @@ -0,0 +1,532 @@ +/* Contains the code to interface with a remote GDB */ + +/* +** Copyright 2002, Manuel J. Petit. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include +#include + + +enum { INIT= 0, CMDREAD, CKSUM1, CKSUM2, WAITACK, QUIT, GDBSTATES }; + + +static char cmd[512]; +static int cmd_ptr; +static int checksum; + +static char reply[512]; + +static char safe_mem[512]; + + +/* + * utility functions + */ +static +int +htons(short value) +{ + return ((value>>8)&0xff) | ((value&0xff)<<8); +} + +static +int +htonl(int value) +{ + return htons((value>>16)&0xffff) | (htons(value&0xffff)<<16); +} + +static +int +parse_nibble(int input) +{ + int nibble= 0xff; + + if((input>= '0') && (input<= '9')) { + nibble= input-'0'; + } + if((input>= 'A') && (input<= 'F')) { + nibble= 0x0a+(input-'A'); + } + if((input>= 'a') && (input<= 'f')) { + nibble= 0x0a+(input-'a'); + } + + return nibble; +} + + + +/* + * GDB protocol ACK & NAK & Reply + * + */ +static +void +gdb_ack(void) +{ + dbg_putch('+'); +} + +static +void +gdb_nak(void) +{ + dbg_putch('-'); +} + +static +void +gdb_resend_reply(void) +{ + dbg_puts(reply); +} + +static +void +gdb_reply(char const *fmt, ...) +{ + int i; + int len; + int sum; + va_list args; + + va_start(args, fmt); + reply[0]= '$'; + vsprintf(reply+1, fmt, args); + va_end(args); + + len= strlen(reply); + sum= 0; + for(i= 1; i< len; i++) { + sum+= reply[i]; + } + sum%= 256; + + sprintf(reply+len, "#%02x", sum); + + gdb_resend_reply(); +} + +static +void +gdb_regreply(int const *regs, int numregs) +{ + int i; + int len; + int sum; + + reply[0]= '$'; + for(i= 0; i< numregs; i++) { + sprintf(reply+1+8*i, "%08x", htonl(regs[i])); + } + + len= strlen(reply); + sum= 0; + for(i= 1; i< len; i++) { + sum+= reply[i]; + } + sum%= 256; + + sprintf(reply+len, "#%02x", sum); + + gdb_resend_reply(); +} + +static +void +gdb_memreply(char const *bytes, int numbytes) +{ + int i; + int len; + int sum; + + reply[0]= '$'; + for(i= 0; i< numbytes; i++) { + sprintf(reply+1+2*i, "%02x", (unsigned char)bytes[i]); + } + + len= strlen(reply); + sum= 0; + for(i= 1; i< len; i++) { + sum+= reply[i]; + } + sum%= 256; + + sprintf(reply+len, "#%02x", sum); + + gdb_resend_reply(); +} + + + +/* + * checksum verification + */ +static +int +gdb_verify_checksum(void) +{ + int i; + int len; + int sum; + + len= strlen(cmd); + sum= 0; + for(i= 0; i< len; i++) { + sum+= cmd[i]; + } + sum%= 256; + + return (sum==checksum)?1:0; +} + + +/* + * command parsing an dispatching + */ +static +int +gdb_parse_command(void) +{ +// int retval; + + if(!gdb_verify_checksum()) { + gdb_nak(); + return INIT; + } else { + gdb_ack(); + } + + switch(cmd[0]) { + + case 'H': + { + /* + * Command H (actually Hct) is used to select + * the current thread (-1 meaning all threads) + * We just fake we recognize the the command + * and send an 'OK' response. + */ + gdb_reply("OK"); + } break; + + case 'q': + { +// extern unsigned _start; + extern unsigned __data_start; + extern unsigned __bss_start; + + /* + * There are several q commands: + * + * qXXXX Request info about XXXX. + * QXXXX=yyyy Set value of XXXX to yyyy. + * qOffsets Get segment offsets + * + * Currently we only support the 'qOffsets' + * form. + * + * *Note* that we actually have to lie, + * At first thought looks like we should + * return '_start', '__data_start' & + * '__bss_start', however gdb gets + * confused because the kernel link script + * pre-links at 0x80000000. To keep gdb + * gdb happy we just substract that amount. + */ + if(strcmp(cmd+1, "Offsets")== 0) { + gdb_reply( + "Text=%x;Data=%x;Bss=%x", + 0, + ((unsigned)(&__data_start))-0x80000000, + ((unsigned)(&__bss_start))-0x80000000 + ); + } else { + gdb_reply("ENS"); + } + } break; + + case '?': + { + /* + * command '?' is used for retrieving the signal + * that stopped the program. Fully implemeting + * this command requires help from the debugger, + * by now we just fake a SIGKILL + */ + gdb_reply("S09"); /* SIGKILL = 9 */ + } break; + + case 'g': + { + int cpu; + + /* + * command 'g' is used for reading the register + * file. Faked by now. + * + * For x86 the register order is: + * + * eax, ebx, ecx, edx, + * esp, ebp, esi, edi, + * eip, eflags, + * cs, ss, ds, es + * + * Note that even thought the segment descriptors + * are actually 16 bits wide, gdb requires them + * as 32 bit integers. Note also that for some + * reason (unknown to me) gdb wants the register + * dump in *big endian* format. + */ + cpu= smp_get_current_cpu(); + gdb_regreply(dbg_register_file[cpu], 14); + } break; + + case 'm': + { + char *ptr; + unsigned address; + unsigned len; + + /* + * The 'm' command has the form mAAA,LLL + * where AAA is the address and LLL is the + * number of bytes. + */ + ptr= cmd+1; + address= 0; + len= 0; + while(ptr && *ptr && (*ptr!= ',')) { + address<<= 4; + address+= parse_nibble(*ptr); + ptr+= 1; + } + if(*ptr== ',') { + ptr+= 1; + } + while(ptr && *ptr) { + len<<= 4; + len+= parse_nibble(*ptr); + ptr+= 1; + } + + if(len> 128) { + len= 128; + } + + /* + * We cannot directly access the requested memory + * for gdb may be trying to access an stray pointer + * We copy the memory to a safe buffer using + * the bulletproof user_memcpy(). + */ + if(user_memcpy(safe_mem, (char*)address, len)< 0) { + gdb_reply("E02"); + } else { + gdb_memreply(safe_mem, len); + } + } break; + + case 'k': + { + /* + * Command 'k' actual semantics is 'kill the damn thing'. + * However gdb sends that command when you disconnect + * from a debug session. I guess that 'kill' for the + * kernel would map to reboot... however that's a + * a very mean thing to do, instead we just quit + * the gdb state machine and fallback to the regular + * kernel debugger command prompt. + */ + return QUIT; + } break; + + default: + { + gdb_reply("E01"); + } break; + } + + return WAITACK; +} + + + +/* + * GDB protocol state machine + */ +static +int +gdb_init_handler(int input) +{ + switch(input) { + case '$': + memset(cmd, 0, sizeof(cmd)); + cmd_ptr= 0; + return CMDREAD; + default: +#if 0 + gdb_nak(); +#else + /* + * looks to me like we should send + * a NAK here but it kinda works + * better if we just gobble all + * junk chars silently + */ +#endif + return INIT; + } +} + +static +int +gdb_cmdread_handler(int input) +{ + switch(input) { + case '#': + return CKSUM1; + default: + cmd[cmd_ptr]= input; + cmd_ptr+= 1; + return CMDREAD; + } +} + +static +int +gdb_cksum1_handler(int input) +{ + int nibble= parse_nibble(input); + + if(nibble== 0xff) { +#if 0 + gdb_nak(); + return INIT; +#else + /* + * looks to me like we should send + * a NAK here but it kinda works + * better if we just gobble all + * junk chars silently + */ +#endif + } + + checksum= nibble<< 4; + + return CKSUM2; +} + +static +int +gdb_cksum2_handler(int input) +{ + int nibble= parse_nibble(input); + + if(nibble== 0xff) { +#if 0 + gdb_nak(); + return INIT; +#else + /* + * looks to me like we should send + * a NAK here but it kinda works + * better if we just gobble all + * junk chars silently + */ +#endif + } + + checksum+= nibble; + + return gdb_parse_command(); +} + +static +int +gdb_waitack_handler(int input) +{ + switch(input) { + case '+': + return INIT; + case '-': + gdb_resend_reply(); + return WAITACK; + default: + /* + * looks like gdb and us are out of synch, + * send a NAK and retry from INIT state. + */ + gdb_nak(); + return INIT; + } +} + +static +int +gdb_quit_handler(int input) +{ + (void)(input); + + /* + * actually we should never be here + */ + return QUIT; +} + +static int (*dispatch_table[GDBSTATES])(int)= +{ + &gdb_init_handler, + &gdb_cmdread_handler, + &gdb_cksum1_handler, + &gdb_cksum2_handler, + &gdb_waitack_handler, + &gdb_quit_handler +}; + +static +int +gdb_state_dispatch(int curr, int input) +{ + if(curr< INIT) { + return QUIT; + } + if(curr>= GDBSTATES) { + return QUIT; + } + + return dispatch_table[curr](input); +} + +static +int +gdb_state_machine(void) +{ + int state= INIT; + int c; + + while(state!= QUIT) { + c= arch_dbg_con_read(); + state= gdb_state_dispatch(state, c); + } + + return 0; +} + +void +cmd_gdb(int argc, char **argv) +{ + (void)(argc); + (void)(argv); + + gdb_state_machine(); +} diff --git a/src/kernel/core/heap.c b/src/kernel/core/heap.c new file mode 100644 index 0000000000..a22a59a0c8 --- /dev/null +++ b/src/kernel/core/heap.c @@ -0,0 +1,289 @@ +/* Heap + other assorted stuff. Needs cleanup */ + +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include + +#include + +#include + +#include + +#define PARANOID_KFREE 1 +#define MAKE_NOIZE 0 + +// heap stuff +// ripped mostly from nujeffos + +struct heap_page { + unsigned short bin_index : 5; + unsigned short free_count : 9; + unsigned short cleaning : 1; + unsigned short in_use : 1; +} PACKED; + +static struct heap_page *heap_alloc_table; +static addr heap_base_ptr; +static addr heap_base; +static addr heap_size; + +struct heap_bin { + unsigned int element_size; + unsigned int grow_size; + unsigned int alloc_count; + void *free_list; + unsigned int free_count; + char *raw_list; + unsigned int raw_count; +}; +static struct heap_bin bins[] = { + {16, PAGE_SIZE, 0, 0, 0, 0, 0}, + {32, PAGE_SIZE, 0, 0, 0, 0, 0}, + {64, PAGE_SIZE, 0, 0, 0, 0, 0}, + {128, PAGE_SIZE, 0, 0, 0, 0, 0}, + {256, PAGE_SIZE, 0, 0, 0, 0, 0}, + {512, PAGE_SIZE, 0, 0, 0, 0, 0}, + {1024, PAGE_SIZE, 0, 0, 0, 0, 0}, + {2048, PAGE_SIZE, 0, 0, 0, 0, 0}, + {0x1000, 0x1000, 0, 0, 0, 0, 0}, + {0x2000, 0x2000, 0, 0, 0, 0, 0}, + {0x3000, 0x3000, 0, 0, 0, 0, 0}, + {0x4000, 0x4000, 0, 0, 0, 0, 0}, + {0x5000, 0x5000, 0, 0, 0, 0, 0}, + {0x6000, 0x6000, 0, 0, 0, 0, 0}, + {0x7000, 0x7000, 0, 0, 0, 0, 0}, + {0x8000, 0x8000, 0, 0, 0, 0, 0}, + {0x9000, 0x9000, 0, 0, 0, 0, 0}, + {0xa000, 0xa000, 0, 0, 0, 0, 0}, + {0xb000, 0xb000, 0, 0, 0, 0, 0}, + {0xc000, 0xc000, 0, 0, 0, 0, 0}, + {0xd000, 0xd000, 0, 0, 0, 0, 0}, + {0xe000, 0xe000, 0, 0, 0, 0, 0}, + {0xf000, 0xf000, 0, 0, 0, 0, 0}, + {0x10000, 0x10000, 0, 0, 0, 0, 0} // 64k +}; + +static const int bin_count = sizeof(bins) / sizeof(struct heap_bin); +static mutex heap_lock; + +static void dump_bin(int bin_index) +{ + struct heap_bin *bin = &bins[bin_index]; + unsigned int *temp; + + dprintf("%d:\tesize %d\tgrow_size %d\talloc_count %d\tfree_count %d\traw_count %d\traw_list %p\n", + bin_index, bin->element_size, bin->grow_size, bin->alloc_count, bin->free_count, bin->raw_count, bin->raw_list); + dprintf("free_list: "); + for(temp = bin->free_list; temp != NULL; temp = (unsigned int *)*temp) { + dprintf("%p ", temp); + } + dprintf("NULL\n"); +} + +static void dump_bin_list(int argc, char **argv) +{ + int i; + + dprintf("%d heap bins at %p:\n", bin_count, bins); + + for(i=0; i heap_base + heap_size) { + panic("heap overgrew itself!\n"); + } + + for(addr = heap_base_ptr; addr < new_heap_ptr; addr += PAGE_SIZE) { + page = &heap_alloc_table[(addr - heap_base) / PAGE_SIZE]; + page->in_use = 1; + page->cleaning = 0; + page->bin_index = bin_index; + if (bin_index < bin_count && bins[bin_index].element_size < PAGE_SIZE) + page->free_count = PAGE_SIZE / bins[bin_index].element_size; + else + page->free_count = 1; + } + + retval = (char *)heap_base_ptr; + heap_base_ptr = new_heap_ptr; + return retval; +} + +void *kmalloc(unsigned int size) +{ + void *address = NULL; + int bin_index; + unsigned int i; + struct heap_page *page; + +#if MAKE_NOIZE + dprintf("kmalloc: asked to allocate size %d\n", size); +#endif + + mutex_lock(&heap_lock); + + for (bin_index = 0; bin_index < bin_count; bin_index++) + if (size <= bins[bin_index].element_size) + break; + + if (bin_index == bin_count) { + // XXX fix the raw alloc later. + //address = raw_alloc(size, bin_index); + panic("kmalloc: asked to allocate too much for now!\n"); + goto out; + } else { + if (bins[bin_index].free_list != NULL) { + address = bins[bin_index].free_list; + bins[bin_index].free_list = (void *)(*(unsigned int *)bins[bin_index].free_list); + bins[bin_index].free_count--; + } else { + if (bins[bin_index].raw_count == 0) { + bins[bin_index].raw_list = raw_alloc(bins[bin_index].grow_size, bin_index); + bins[bin_index].raw_count = bins[bin_index].grow_size / bins[bin_index].element_size; + } + + bins[bin_index].raw_count--; + address = bins[bin_index].raw_list; + bins[bin_index].raw_list += bins[bin_index].element_size; + } + + bins[bin_index].alloc_count++; + page = &heap_alloc_table[((unsigned int)address - heap_base) / PAGE_SIZE]; + page[0].free_count--; +#if MAKE_NOIZE + dprintf("kmalloc0: page 0x%x: bin_index %d, free_count %d\n", page, page->bin_index, page->free_count); +#endif + for(i = 1; i < bins[bin_index].element_size / PAGE_SIZE; i++) { + page[i].free_count--; +#if MAKE_NOIZE + dprintf("kmalloc1: page 0x%x: bin_index %d, free_count %d\n", page[i], page[i].bin_index, page[i].free_count); +#endif + } + } + +out: + mutex_unlock(&heap_lock); + +#if MAKE_NOIZE + dprintf("kmalloc: asked to allocate size %d, returning ptr = %p\n", size, address); +#endif + return address; +} + +void kfree(void *address) +{ + struct heap_page *page; + struct heap_bin *bin; + unsigned int i; + + if (address == NULL) + return; + + if ((addr)address < heap_base || (addr)address >= (heap_base + heap_size)) + panic("kfree: asked to free invalid address %p\n", address); + + mutex_lock(&heap_lock); + +#if MAKE_NOIZE + dprintf("kfree: asked to free at ptr = %p\n", address); +#endif + + page = &heap_alloc_table[((unsigned)address - heap_base) / PAGE_SIZE]; + +#if MAKE_NOIZE + dprintf("kfree: page 0x%x: bin_index %d, free_count %d\n", page, page->bin_index, page->free_count); +#endif + + if(page[0].bin_index >= bin_count) + panic("kfree: page %p: invalid bin_index %d\n", page, page->bin_index); + + bin = &bins[page[0].bin_index]; + +// if((addr)address % bin->element_size != 0) +// panic("kfree: passed invalid pointer 0x%x! Supposed to be in bin for esize 0x%x\n", address, bin->element_size); + + for(i = 0; i < bin->element_size / PAGE_SIZE; i++) { + if(page[i].bin_index != page[0].bin_index) + panic("kfree: not all pages in allocation match bin_index\n"); + page[i].free_count++; + } + +#if PARANOID_KFREE + // walk the free list on this bin to make sure this address doesn't exist already + { + unsigned int *temp; + for(temp = bin->free_list; temp != NULL; temp = (unsigned int *)*temp) { + if(temp == (unsigned int *)address) { + panic("kfree: address %p already exists in bin free list\n", address); + } + } + } +#endif + + *(unsigned int *)address = (unsigned int)bin->free_list; + bin->free_list = address; + bin->alloc_count--; + bin->free_count++; + +//out: + mutex_unlock(&heap_lock); +} + +char *kstrdup(const char *text) +{ + char *buf = (char *)kmalloc(strlen(text) + 1); + + if(buf != NULL) + strcpy(buf,text); + return buf; +} + diff --git a/src/kernel/core/int.c b/src/kernel/core/int.c new file mode 100644 index 0000000000..2707307d59 --- /dev/null +++ b/src/kernel/core/int.c @@ -0,0 +1,146 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NUM_IO_VECTORS 256 + +struct io_handler { + struct io_handler *next; + int (*func)(void*); + void* data; +}; + +struct io_vector { + struct io_handler *handler_list; + spinlock_t vector_lock; +}; + +static struct io_vector *io_vectors = NULL; + +int int_init(kernel_args *ka) +{ + dprintf("init_int_handlers: entry\n"); + + return arch_int_init(ka); +} + +int int_init2(kernel_args *ka) +{ + io_vectors = (struct io_vector *)kmalloc(sizeof(struct io_vectors *) * NUM_IO_VECTORS); + if(io_vectors == NULL) + panic("int_init2: could not create io vector table!\n"); + + memset(io_vectors, 0, sizeof(struct io_vector *) * NUM_IO_VECTORS); + + return arch_int_init2(ka); +} + +int int_set_io_interrupt_handler(int vector, int (*func)(void*), void* data) +{ + struct io_handler *io; + int state; + + // insert this io handler in the chain of interrupt + // handlers registered for this io interrupt + + io = (struct io_handler *)kmalloc(sizeof(struct io_handler)); + if(io == NULL) + return ERR_NO_MEMORY; + io->func = func; + io->data = data; + + state = int_disable_interrupts(); + acquire_spinlock(&io_vectors[vector].vector_lock); + io->next = io_vectors[vector].handler_list; + io_vectors[vector].handler_list = io; + release_spinlock(&io_vectors[vector].vector_lock); + int_restore_interrupts(state); + + arch_int_enable_io_interrupt(vector); + + return NO_ERROR; +} + +int int_remove_io_interrupt_handler(int vector, int (*func)(void*), void* data) +{ + struct io_handler *io, *prev = NULL; + int state; + + // lock the structures down so it is not modified while we search + state = int_disable_interrupts(); + acquire_spinlock(&io_vectors[vector].vector_lock); + + // start at the beginning + io = io_vectors[vector].handler_list; + + // while not at end + while(io != NULL) { + // see if we match both the function & data + if (io->func == func && io->data == data) + break; + + // Store our backlink and move to next + prev = io; + io = io->next; + } + + // If we found it + if (io != NULL) { + // unlink it, taking care of the change it was the first in line + if (prev != NULL) + prev->next = io->next; + else + io_vectors[vector].handler_list = io->next; + } + + // release our lock as we're done with the vector + release_spinlock(&io_vectors[vector].vector_lock); + int_restore_interrupts(state); + + // and disable the IRQ if nothing left + if (io != NULL) { + if (prev == NULL && io->next == NULL) + arch_int_disable_io_interrupt(vector); + + kfree(io); + } + + return (io != NULL) ? NO_ERROR : ERR_INVALID_ARGS; +} + +int int_io_interrupt_handler(int vector) +{ + int ret = INT_NO_RESCHEDULE; + + acquire_spinlock(&io_vectors[vector].vector_lock); + + if(io_vectors[vector].handler_list == NULL) { + dprintf("unhandled io interrupt %d\n", vector); + } else { + struct io_handler *io; + int temp_ret; + + io = io_vectors[vector].handler_list; + while(io != NULL) { + temp_ret = io->func(io->data); + if(temp_ret == INT_RESCHEDULE) + ret = INT_RESCHEDULE; + io = io->next; + } + } + + release_spinlock(&io_vectors[vector].vector_lock); + + return ret; +} \ No newline at end of file diff --git a/src/kernel/core/khash.c b/src/kernel/core/khash.c new file mode 100644 index 0000000000..61028e0e58 --- /dev/null +++ b/src/kernel/core/khash.c @@ -0,0 +1,210 @@ +/* Generic hash table. No real clue where hash_elem is defined...*/ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#include +#include +#include +#include +#include + +#define malloc kmalloc +#define free kfree + +struct hash_table { + struct hash_elem **table; + int next_ptr_offset; + unsigned int table_size; + int num_elems; + int flags; + int (*compare_func)(void *e, const void *key); + unsigned int (*hash_func)(void *e, const void *key, unsigned int range); +}; + +// XXX gross hack +#define NEXT_ADDR(t, e) ((void *)(((unsigned long)(e)) + (t)->next_ptr_offset)) +#define NEXT(t, e) ((void *)(*(unsigned long *)NEXT_ADDR(t, e))) +#define PUT_IN_NEXT(t, e, val) (*(unsigned long *)NEXT_ADDR(t, e) = (long)(val)) + +void *hash_init(unsigned int table_size, int next_ptr_offset, + int compare_func(void *e, const void *key), + unsigned int hash_func(void *e, const void *key, unsigned int range)) +{ + struct hash_table *t; + unsigned int i; + + t = (struct hash_table *)malloc(sizeof(struct hash_table)); + if(t == NULL) { + return NULL; + } + + t->table = (struct hash_elem **)malloc(sizeof(void *) * table_size); + for(i = 0; itable[i] = NULL; + t->table_size = table_size; + t->next_ptr_offset = next_ptr_offset; + t->flags = 0; + t->num_elems = 0; + t->compare_func = compare_func; + t->hash_func = hash_func; + +// dprintf("hash_init: created table 0x%x, next_ptr_offset %d, compare_func 0x%x, hash_func 0x%x\n", +// t, next_ptr_offset, compare_func, hash_func); + + return t; +} + +int hash_uninit(void *_hash_table) +{ + struct hash_table *t = (struct hash_table *)_hash_table; + +#if 0 + if(t->num_elems > 0) { + return -1; + } +#endif + + free(t->table); + free(t); + + return 0; +} + +int hash_insert(void *_hash_table, void *e) +{ + struct hash_table *t = (struct hash_table *)_hash_table; + unsigned int hash; + +// dprintf("hash_insert: table 0x%x, element 0x%x\n", t, e); + + hash = t->hash_func(e, NULL, t->table_size); + PUT_IN_NEXT(t, e, t->table[hash]); + t->table[hash] = (struct hash_elem *)e; + t->num_elems++; + + return 0; +} + +int hash_remove(void *_hash_table, void *e) +{ + struct hash_table *t = (struct hash_table *)_hash_table; + void *i, *last_i; + unsigned int hash; + + hash = t->hash_func(e, NULL, t->table_size); + last_i = NULL; + for(i = t->table[hash]; i != NULL; last_i = i, i = NEXT(t, i)) { + if(i == e) { + if(last_i != NULL) + PUT_IN_NEXT(t, last_i, NEXT(t, i)); + else + t->table[hash] = (struct hash_elem *)NEXT(t, i); + t->num_elems--; + return B_NO_ERROR; + } + } + + return ERR_GENERAL; +} + +void *hash_find(void *_hash_table, void *e) +{ + struct hash_table *t = (struct hash_table *)_hash_table; + void *i; + unsigned int hash; + + hash = t->hash_func(e, NULL, t->table_size); + for(i = t->table[hash]; i != NULL; i = NEXT(t, i)) { + if(i == e) { + return i; + } + } + + return NULL; +} + +void *hash_lookup(void *_hash_table, const void *key) +{ + struct hash_table *t = (struct hash_table *)_hash_table; + void *i; + unsigned int hash; + + if(t->compare_func == NULL) + return NULL; + + hash = t->hash_func(NULL, key, t->table_size); + for(i = t->table[hash]; i != NULL; i = NEXT(t, i)) { + if(t->compare_func(i, key) == 0) { + return i; + } + } + + return NULL; +} + +struct hash_iterator *hash_open(void *_hash_table, struct hash_iterator *i) +{ + struct hash_table *t = (struct hash_table *)_hash_table; + + if(i == NULL) { + i = (struct hash_iterator *)malloc(sizeof(struct hash_iterator)); + if(i == NULL) + return NULL; + } + + hash_rewind(t, i); + + return i; +} + +void hash_close(void *_hash_table, struct hash_iterator *i, bool free_iterator) +{ + if(free_iterator) + free(i); +} + +void hash_rewind(void *_hash_table, struct hash_iterator *i) +{ + i->ptr = NULL; + i->bucket = -1; +} + +void *hash_next(void *_hash_table, struct hash_iterator *i) +{ + struct hash_table *t = (struct hash_table *)_hash_table; + unsigned int index; + +restart: + if(!i->ptr) { + for(index = (unsigned int)(i->bucket + 1); index < t->table_size; index++) { + if(t->table[index]) { + i->bucket = index; + i->ptr = t->table[index]; + break; + } + } + } else { + i->ptr = NEXT(t, i->ptr); + if(!i->ptr) + goto restart; + } + + return i->ptr; +} + +unsigned int hash_hash_str( const char *str ) +{ + char ch; + unsigned int hash = 0; + + // we assume hash to be at least 32 bits + while( (ch = *str++) != 0 ) { + hash ^= hash >> 28; + hash <<= 4; + hash ^= ch; + } + + return hash; +} diff --git a/src/kernel/core/linkhack.c b/src/kernel/core/linkhack.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/kernel/core/lock.c b/src/kernel/core/lock.c new file mode 100644 index 0000000000..698a513b37 --- /dev/null +++ b/src/kernel/core/lock.c @@ -0,0 +1,120 @@ +/* Mutex and recursive_lock code */ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include +#include + +int recursive_lock_get_recursion(recursive_lock *lock) +{ + thread_id thid = thread_get_current_thread_id(); + + if(lock->holder == thid) { + return lock->recursion; + } else { + return -1; + } +} + +int recursive_lock_create(recursive_lock *lock) +{ + if(lock == NULL) + return ERR_INVALID_ARGS; + lock->holder = -1; + lock->recursion = 0; + lock->sem = create_sem(1, "recursive_lock_sem"); +// if(lock->sem < 0) +// return -1; + return B_NO_ERROR; +} + +void recursive_lock_destroy(recursive_lock *lock) +{ + if(lock == NULL) + return; + if(lock->sem > 0) + delete_sem(lock->sem); + lock->sem = -1; +} + +bool recursive_lock_lock(recursive_lock *lock) +{ + thread_id thid = thread_get_current_thread_id(); + bool retval = false; + + if(thid != lock->holder) { + acquire_sem(lock->sem); + + lock->holder = thid; + retval = true; + } + lock->recursion++; + return retval; +} + +bool recursive_lock_unlock(recursive_lock *lock) +{ + thread_id thid = thread_get_current_thread_id(); + bool retval = false; + + if(thid != lock->holder) + panic("recursive_lock %p unlocked by non-holder thread!\n", lock); + + if(--lock->recursion == 0) { + lock->holder = -1; + release_sem(lock->sem); + retval = true; + } + return retval; +} + +int mutex_init(mutex *m, const char *in_name) +{ + const char *name; + + if(m == NULL) + return ERR_INVALID_ARGS; + + if(in_name == NULL) + name = "mutex_sem"; + else + name = in_name; + + m->count = 0; + + m->sem = create_sem(0, name); + if(m->sem < 0) + return m->sem; + + return 0; +} + +void mutex_destroy(mutex *m) +{ + if(m == NULL) + return; + + if(m->sem >= 0) { + delete_sem(m->sem); + } +} + +void mutex_lock(mutex *m) +{ + if(atomic_add(&m->count, 1) >= 1) + acquire_sem(m->sem); +} + +void mutex_unlock(mutex *m) +{ + if(atomic_add(&m->count, -1) > 1) + release_sem(m->sem); +} + diff --git a/src/kernel/core/main.c b/src/kernel/core/main.c new file mode 100644 index 0000000000..aed0ab82f7 --- /dev/null +++ b/src/kernel/core/main.c @@ -0,0 +1,164 @@ +/* This is main - initializes processors and starts init */ + +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +static kernel_args ka; + +static int main2(void *); + +int net_init(kernel_args *ka); + +int _start(kernel_args *oldka, int cpu); /* keep compiler happy */ +int _start(kernel_args *oldka, int cpu_num) +{ + memcpy(&ka, oldka, sizeof(kernel_args)); + + smp_set_num_cpus(ka.num_cpus); + + // do any pre-booting cpu config + cpu_preboot_init(&ka); + + // if we're not a boot cpu, spin here until someone wakes us up + if(smp_trap_non_boot_cpus(&ka, cpu_num) == B_NO_ERROR) { + // we're the boot processor, so wait for all of the APs to enter the kernel + smp_wait_for_ap_cpus(&ka); + + // setup debug output + dbg_init(&ka); + dbg_set_serial_debug(true); + dprintf("Welcome to kernel debugger output!\n"); + + // init modules + cpu_init(&ka); + int_init(&ka); + + vm_init(&ka); + dprintf("vm up\n"); + + // now we can use the heap and create areas + dbg_init2(&ka); + int_init2(&ka); + + faults_init(&ka); + smp_init(&ka); + timer_init(&ka); + + arch_cpu_init2(&ka); + + sem_init(&ka); + + // now we can create and use semaphores + vm_init_postsem(&ka); + cbuf_init(); + vfs_init(&ka); + thread_init(&ka); + port_init(&ka); + + vm_init_postthread(&ka); + elf_init(&ka); + + // start a thread to finish initializing the rest of the system + { + thread_id tid; + tid = thread_create_kernel_thread("main2", &main2, NULL); + thread_resume_thread(tid); + } + + smp_wake_up_all_non_boot_cpus(); + smp_enable_ici(); // ici's were previously being ignored + thread_start_threading(); + } else { + // this is run per cpu for each AP processor after they've been set loose + thread_init_percpu(cpu_num); + } + int_enable_interrupts(); + + dprintf("main: done... begin idle loop on cpu %d\n", cpu_num); + for(;;); + + return 0; +} + +static int main2(void *unused) +{ +// int err; + + (void)(unused); + + dprintf("start of main2: initializing devices\n"); + + // bootstrap all the filesystems + vfs_bootstrap_all_filesystems(); + + //net_init(&ka); + dev_init(&ka); + module_init(&ka, NULL); + bus_init(&ka); + devs_init(&ka); + con_init(&ka); + net_init(&ka); + + //net_init_postdev(&ka); + +#if 0 + // XXX remove + vfs_test(); +#endif +#if 0 + // XXX remove + thread_test(); +#endif +#if 0 + vm_test(); +#endif +#if 0 + panic("debugger_test\n"); +#endif +#if 0 + cbuf_test(); +#endif +#if 0 + port_test(); +#endif + // start the init process + { + proc_id pid; + pid = proc_create_proc("/boot/bin/init", "init", NULL, 0, 5); + if(pid < 0) + kprintf("error starting 'init' error = %d \n",pid); + } + + return 0; +} + diff --git a/src/kernel/core/misc.c b/src/kernel/core/misc.c new file mode 100644 index 0000000000..7b3b2ccd7a --- /dev/null +++ b/src/kernel/core/misc.c @@ -0,0 +1,50 @@ +/* This includes some functions that were part of the net piece */ + +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include + +/* XXX - keep the compiler happy. */ +uint16 ones_sum16(uint32 sum, const void *_buf, int len); +uint16 cksum16(void *_buf, int len); +uint16 cksum16_2(void *buf1, int len1, void *buf2, int len2); + +uint16 ones_sum16(uint32 sum, const void *_buf, int len) +{ + const uint16 *buf = _buf; + + while(len >= 2) { + sum += *buf++; + if(sum & 0x80000000) + sum = (sum & 0xffff) + (sum >> 16); + len -= 2; + } + + if (len) { + uint8 temp[2]; + temp[0] = *(uint8 *) buf; + temp[1] = 0; + sum += *(uint16 *) temp; + } + + while(sum >> 16) + sum = (sum & 0xffff) + (sum >> 16); + + return sum; +} + +uint16 cksum16(void *_buf, int len) +{ + return ~ones_sum16(0, _buf, len); +} + +uint16 cksum16_2(void *buf1, int len1, void *buf2, int len2) +{ + uint32 sum; + + sum = ones_sum16(0, buf1, len1); + return ~ones_sum16(sum, buf2, len2); +} diff --git a/src/kernel/core/module.c b/src/kernel/core/module.c new file mode 100644 index 0000000000..ed3caa172b --- /dev/null +++ b/src/kernel/core/module.c @@ -0,0 +1,1098 @@ +/* Module manager. Uses hash.c */ + +/* +** Copyright 2001, Thomas Kurschel. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +// TODO: +// - "offsetof" macro is missing +// -> move it to a public place + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 1 +#include +#endif + +static bool modules_disable_user_addons = false; + +#define debug_level_flow 0 +#define debug_level_error 1 +#define debug_level_info 1 + +#define WAIT +#define WAIT_ERROR +#define MSG_PREFIX "MODULE -- " + +#define FUNC_NAME MSG_PREFIX __FUNCTION__ ": " + +#define SHOW_FLOW(seriousness, format, param...) \ + do { if (debug_level_flow > seriousness ) { \ + dprintf( "%s"##format, FUNC_NAME, param ); WAIT \ + }} while( 0 ) + +#define SHOW_FLOW0(seriousness, format) \ + do { if (debug_level_flow > seriousness ) { \ + dprintf( "%s"##format, FUNC_NAME); WAIT \ + }} while( 0 ) + +#define SHOW_ERROR(seriousness, format, param...) \ + do { if (debug_level_error > seriousness ) { \ + dprintf( "%s"##format, FUNC_NAME, param ); WAIT_ERROR \ + }} while( 0 ) + +#define SHOW_ERROR0(seriousness, format) \ + do { if (debug_level_error > seriousness ) { \ + dprintf( "%s"##format, FUNC_NAME); WAIT_ERROR \ + }} while( 0 ) + +#define SHOW_INFO(seriousness, format, param...) \ + do { if (debug_level_info > seriousness ) { \ + dprintf( "%s"##format, FUNC_NAME, param ); WAIT \ + }} while( 0 ) + +#define SHOW_INFO0(seriousness, format) \ + do { if (debug_level_info > seriousness ) { \ + dprintf( "%s"##format, FUNC_NAME); WAIT \ + }} while( 0 ) + + +typedef enum { + MOD_QUERIED = 0, + MOD_LOADED, + MOD_INIT, + MOD_RDY, + MOD_UNINIT, + MOD_ERROR +} module_state; + +/* This represents the actual loaded module. The module is loaded and + * may have more than one exported images, + * i.e. the module foo may actually have module_info structures for foo and bar + * To allow for this each module_info structure within the module loaded is represented + * by a loaded_module_info structure. + */ +typedef struct loaded_module { + struct loaded_module *next; + struct loaded_module *prev; + module_info **info; /* the module_info we use */ + char *path; /* the full path for the module */ + int ref_cnt; /* how many ref's to this file */ +} loaded_module; +struct loaded_module loaded_modules; + +/* This is used to keep a list of module and the file it's found + * in. It's used when we do searches to record that a module_info for + * a particular module is found in a particular file which covers us for + * the case where we have a single file exporting a number of modules. + */ +typedef struct module { + struct module *next; + struct module *prev; + struct loaded_module *module; + char *name; + char *file; + int ref_cnt; + module_info *ptr; /* will only be valid if ref_cnt > 0 */ + int offset; /* this is the offset in the headers */ + int state; /* state of module */ + bool keep_loaded; +} module; + +/* This is used to provide a list of modules we know about */ +static struct module known_modules; + +#define INC_MOD_REF_COUNT(x) \ + x->ref_cnt++; \ + x->module->ref_cnt++; + +#define DEC_MOD_REF_COUNT(x) \ + x->ref_cnt--; \ + x->module->ref_cnt--; + + +typedef struct module_iterator { + char *prefix; + int base_path_id; + struct module_dir_iterator *base_dir; + struct module_dir_iterator *cur_dir; + int err; + int module_pos; /* This is used to keep track of which module_info + * within a module we're addressing. */ + module_info **cur_header; + char *cur_path; +} module_iterator; + +typedef struct module_dir_iterator { + struct module_dir_iterator *parent_dir; + struct module_dir_iterator *sub_dir; + char *name; + int file; + int hdr_prefix; +} module_dir_iterator; + + +/* XXX - These should really be in a header so they are system wide... */ +/* These are GCC only, so we'll need PPC version eventually... */ +struct quehead { + struct quehead *qh_link; + struct quehead *qh_rlink; +}; + +__inline void +insque(void *a, void *b) +{ + struct quehead *element = (struct quehead *)a, + *head = (struct quehead *)b; + + element->qh_link = head->qh_link; + element->qh_rlink = head; + head->qh_link = element; + element->qh_link->qh_rlink = element; +} + +__inline void +remque(void *a) +{ + struct quehead *element = (struct quehead *)a; + + element->qh_link->qh_rlink = element->qh_rlink; + element->qh_rlink->qh_link = element->qh_link; + element->qh_rlink = 0; +} + +/* XXX locking scheme: there is a global lock only; having several locks + * makes trouble if dependent modules get loaded concurrently -> + * they have to wait for each other, i.e. we need one lock per module; + * also we must detect circular references during init and not dead-lock + */ +static recursive_lock modules_lock; + +/* These are the standard paths that we look on for mdoules to load. + * By default we only look on these plus the prefix, though we do search + * below the prefix. + * i.e. using media as the prefix will match + * /boot/user-addons/media + * /boot/addons/media + * /boot/addons/media/encoders + * but will NOT match + * /boot/addons/kernel/media + */ +const char *const module_paths[] = { + "/boot/user-addons", + "/boot/addons" +}; + +#define num_module_paths (sizeof( module_paths ) / sizeof( module_paths[0] )) + +#define MODULES_HASH_SIZE 16 + +/* the hash tables we use */ +void *module_files; +void *modules_list; + +static int module_compare(void *a, const void *key) +{ + module *mod = a; + + return strcmp(mod->name, (const char*)key); +} + +static unsigned int module_hash(void *a, const void *key, unsigned int range) +{ + module *module = a; + + if (module != NULL ) + return hash_hash_str(module->name) % range; + else + return hash_hash_str(key) % range; +} + +static int mod_files_compare(void *a, const void *key) +{ + loaded_module *module = a; + const char *name = key; + + return strcmp(module->path, name); +} + +static unsigned int mod_files_hash(void *a, const void *key, unsigned int range) +{ + loaded_module *module = a; + + if (module != NULL ) + return hash_hash_str(module->path) % range; + else + return hash_hash_str(key) % range; +} + +/* load_module_file + * Try to load the module file we've found into memory. + * This may fail if all the symbols can't be resolved. + * Returns 0 on success, -1 on failure. + * + * NB hdrs can be passed as a NULL if the modules ** header + * pointer isn't required. + * + * Returns + * NULL on failure + * pointer to modules symbol on success + */ +static module_info **load_module_file(const char *path) +{ + image_id file_image = elf_load_kspace(path, ""); + loaded_module *lm; + + if (file_image < 0 ) { + SHOW_FLOW( 3, "couldn't load image %s (%s)\n", path, strerror(file_image)); + dprintf("load_module_file failed! returned %d\n", file_image); + return NULL; + } + + lm = (loaded_module*)kmalloc(sizeof(loaded_module)); + if (!lm) + return NULL; + + lm->info = (module_info**) elf_lookup_symbol(file_image, "modules"); + if (!lm->info) { + dprintf("Failed to load %s due to lack of 'modules' symbol\n", path); + kfree(lm); + return NULL; + } + + lm->path = (char*)kmalloc(strlen(path)); + if (!lm->path) { + kfree(lm); + return NULL; + } + memcpy(lm->path, path, strlen(path)); + lm->ref_cnt = 0; + + recursive_lock_lock(&modules_lock); + + /* NB NB NB The call to insque MUST be done before insertion into + * the hash list + */ + insque(lm, &loaded_modules); + hash_insert(module_files, lm); + + recursive_lock_unlock(&modules_lock); + + return lm->info; +} + +static inline void unload_module_file(const char *path) +{ + loaded_module *themod; + themod = (loaded_module*)hash_lookup(module_files, path); + if (!themod) { + return; + } + + if (themod->ref_cnt != 0) { + dprintf("Can't unload %s due to ref_cnt = %d\n", themod->path, themod->ref_cnt); + return; + } + + recursive_lock_lock(&modules_lock); + remque(themod); + hash_remove(module_files, themod); + + recursive_lock_unlock(&modules_lock); + + elf_unload_kspace(themod->path); + kfree(themod->path); + kfree(themod); +} + +/* simple_module_info() + * Extract the information from the module_info structure pointed at + * by mod and create the entries required for access to it's details. + * + * Returns + * -1 if error + * 0 if ok + */ +static int simple_module_info(module_info *mod, const char *file, int offset) +{ + module *m; + + m = (module*)hash_lookup(modules_list, mod->name); + if (m) { + dprintf("Duplicate module name detected...ignoring\n"); + return -1; + } + + if ((m = (module*)kmalloc(sizeof(module))) == NULL) { + return -1; + } + if (!mod->name) { + return -1; + } + + SHOW_FLOW(3, "simple_module_info(%s, %s)\n", mod->name, file); + + m->module = NULL; /* back pointer */ + m->name = (char*)kmalloc(strlen(mod->name)); + if (!m->name) { + kfree(m); + return -1; + } + memcpy(m->name, mod->name, strlen(mod->name));//strdup(mod->name); + m->state = MOD_QUERIED; + /* Record where the module_info can be found */ + m->offset = offset; + m->file = (char*)kstrdup(file); + /* set the keep_loaded flag */ + if (mod->flags & B_KEEP_LOADED) { + dprintf("module %s wants to be kept loaded\n", m->name); + m->keep_loaded = true; + } + + recursive_lock_lock(&modules_lock); + + /* Insert into linked list */ + /* NB NB NB The call to insque MUST be done before insertion into + * the hash list + */ + insque(m, &known_modules); + hash_insert(modules_list, m); + + recursive_lock_unlock(&modules_lock); + + return 0; +} + +/* recurse_check_file + * Load the file filepath and check to see if we have a module within it + * that matches srcfile. + * + * NB srcfile can be NULL if we're just scanning the modules. + * + * Return + * -1 on error + * 0 on no match + * 1 on match + */ +static int recurse_check_file(const char *filepath, const char *srcfile) +{ + module_info **hdr = NULL, **chk; + int res = 0, i = 0; + + hdr = load_module_file(filepath); + + if (!hdr) { + return -1; + } + + for (chk = hdr; *chk; chk++) { + if ((res = simple_module_info(*chk, filepath, i++)) != 0) + continue; + if (srcfile && strcmp((*chk)->name, srcfile) == 0) + res = 1; + } + + if (res != 1) + unload_module_file(filepath); + + return res; +} + +/* recurse_directory + * Enter the directory and try every entry, entering directories if + * we encounter them. + * + * NB match can be NULL if we're just doing a scan of the modules + * to build our cache. + * + * The recurse loop has these values + * -1 for error + * 0 for no match + * 1 for match + */ +static int recurse_directory(const char *path, const char *match) +{ + struct stat stat; + int res = 0, file; + char *name; + + if ((file = sys_open(path, STREAM_TYPE_DIR, 0)) < 0) { + return -1; + } + + name = (char*)kmalloc(SYS_MAX_NAME_LEN); + if (!name) + return -1; + + /* loop until we have a match or we run out of entries */ + while (res <= 0) { + char *newpath; + size_t slen = 0; + SHOW_FLOW(3, "scanning %s\n", path); + + name[0] = '\0'; + if ((res = sys_read(file, name, 0, SYS_MAX_NAME_LEN)) <= 0) { + break; + } + + slen = strlen(path) + strlen(name) + 2; + newpath = (char*)kmalloc(slen); + strlcpy(newpath, path, slen); + strlcat(newpath, "/", slen); + strlcat(newpath, name, slen); + + if ((res = sys_rstat(newpath, &stat)) != B_NO_ERROR) { + kfree(newpath); + break; + } + + /* If we got here, we have either a file or a directory. + * If it's a file, do we have the details on record? + * If we don't, then load the file and record it's details. + * If it matches our search path we'll return afterwards. + */ + if (S_ISREG(stat.st_mode)) { + /* do we already know about this file? + * If we do res = 0 and we'll just carry on, if + * not, it's a new file so we need to read in the + * file details via recurse_file_check() function. + */ + if (hash_lookup(module_files, newpath) != NULL) + res = 0; + else + res = recurse_check_file(newpath, match); + + } else if (S_ISDIR(stat.st_mode)) { + res = recurse_directory(newpath, match); + } + kfree(newpath); + } + + kfree(name); + sys_close(file); + + return res; +} + +/* This is only called if we fail to find a module already in our cache...saves us + * some extra checking here :) + */ +static module *search_module(const char *name) +{ + int i, res = 0; + SHOW_FLOW(3, "search_module(%s)\n", name); + + for (i = 0; i < (int)num_module_paths; ++i) { + if ((res = recurse_directory(module_paths[i], name)) == 1) + break; + } + + if (res != 1) { + return NULL; + } + + return (module*)hash_lookup(modules_list, name); +} + + +static inline int init_module(module *module) +{ + int res = 0; + + switch(module->state) { + case MOD_QUERIED: + case MOD_LOADED: + module->state = MOD_INIT; + SHOW_FLOW( 3, "initing module %s... \n", module->name ); + res = module->ptr->std_ops(B_MODULE_INIT); + SHOW_FLOW(3, "...done (%s)\n", strerror(res)); + + if (!res ) + module->state = MOD_RDY; + else + module->state = MOD_LOADED; + break; + + case MOD_RDY: + res = B_NO_ERROR; + break; + + case MOD_INIT: + SHOW_ERROR( 0, "circular reference to %s\n", module->name ); + res = ERR_GENERAL; + break; + + case MOD_UNINIT: + SHOW_ERROR( 0, "tried to load module %s which is currently unloading\n", module->name ); + res = ERR_GENERAL; + break; + + case MOD_ERROR: + SHOW_INFO( 0, "cannot load module %s because its earlier unloading failed\n", module->name ); + res = ERR_GENERAL; + break; + + default: + res = ERR_GENERAL; + } + + return res; +} + +static inline int uninit_module(module *module) +{ + switch( module->state ) { + case MOD_QUERIED: + case MOD_LOADED: + return B_NO_ERROR; + + case MOD_INIT: + panic( "Trying to unload module %s which is initializing\n", + module->name ); + return ERR_GENERAL; + + case MOD_UNINIT: + panic( "Trying to unload module %s which is un-initializing\n", module->name ); + return ERR_GENERAL; + + case MOD_RDY: + { + int res; + + module->state = MOD_UNINIT; + + SHOW_FLOW( 2, "uniniting module %s...\n", module->name ); + res = module->ptr->std_ops(B_MODULE_UNINIT); + SHOW_FLOW( 2, "...done (%s)\n", strerror( res )); + + if (res == B_NO_ERROR ) { + module->state = MOD_LOADED; + return 0; + } + + SHOW_ERROR( 0, "Error unloading module %s (%i)\n", module->name, res ); + } + + module->state = MOD_ERROR; + module->keep_loaded = true; + + // fall through + default: + return ERR_GENERAL; + } +} + +static int process_module_info(module_iterator *iter, char *buf, size_t *bufsize) +{ + module *m; + module_info **mod; + int res = B_NO_ERROR; + + mod = iter->cur_header; + if (!mod || !(*mod)) { + res = EINVAL; + } else { + res = simple_module_info(*mod, iter->cur_path, iter->module_pos++); + + m = (module*)hash_lookup(modules_list, (*mod)->name); + if (m) { + strlcpy(buf, m->name, *bufsize); + *bufsize = strlen(m->name); + } + } + + /* Deal with the header pointer! + * Basically if we have a valid pointer (mod) and the next (++mod) is NOT null, + * then we advance the cur_header pointer, otherwise we specify it as + * NULL to make sure we don't have trouble :) + */ + if (mod && *(++mod) != NULL) + iter->cur_header++; + else + iter->cur_header = NULL; + + return res; +} + +static inline int module_create_dir_iterator( module_iterator *iter, int file, const char *name ) +{ + module_dir_iterator *dir; + + /* if we're creating a dir_iterator, there is no way that the + * cur_header value can be valid, so make sure and reset it + * here. + */ + iter->cur_header = NULL; + + dir = (struct module_dir_iterator *)kmalloc( sizeof( *dir )); + if (dir == NULL ) + return ERR_NO_MEMORY; + + dir->name = (char *)kstrdup( name ); + if (dir->name == NULL ) { + kfree( dir ); + return ERR_NO_MEMORY; + } + + dir->file = file; + dir->sub_dir = NULL; + dir->parent_dir = iter->cur_dir; + + if (iter->cur_dir ) + iter->cur_dir->sub_dir = dir; + else + iter->base_dir = dir; + + iter->cur_dir = dir; + + SHOW_FLOW( 3, "created dir iterator for %s\n", name ); + return B_NO_ERROR; +} + +static inline int module_enter_dir(module_iterator *iter, const char *path) +{ + int file; + int res; + + file = sys_open( path, STREAM_TYPE_DIR, 0 ); + if (file < 0 ) { + SHOW_FLOW( 3, "couldn't open directory %s (%s)\n", path, strerror( file )); + + // there are so many errors for "not found" that we don't bother + // and always assume that the directory suddenly disappeared + return B_NO_ERROR; + } + + res = module_create_dir_iterator(iter, file, path); + if (res != B_NO_ERROR) { + sys_close(file); + return ENOMEM; + } + + SHOW_FLOW( 3, "entered directory %s\n", path ); + return B_NO_ERROR; +} + + +static inline void destroy_dir_iterator( module_iterator *iter ) +{ + module_dir_iterator *dir; + + dir = iter->cur_dir; + + SHOW_FLOW( 3, "destroying directory iterator for sub-dir %s\n", dir->name ); + + if (dir->parent_dir ) + dir->parent_dir->sub_dir = NULL; + + iter->cur_dir = dir->parent_dir; + + kfree(dir->name); + kfree(dir); +} + + +static inline void module_leave_dir( module_iterator *iter ) +{ + module_dir_iterator *parent_dir; + + SHOW_FLOW( 3, "leaving directory %s\n", iter->cur_dir->name ); + + parent_dir = iter->cur_dir->parent_dir; + iter->cur_header = NULL; + sys_close( iter->cur_dir->file ); + destroy_dir_iterator( iter ); + + iter->cur_dir = parent_dir; +} + +static void compose_path( char *path, module_iterator *iter, const char *name, bool full_path ) +{ + module_dir_iterator *dir; + + if (full_path ) { + strlcpy( path, iter->base_dir->name, SYS_MAX_PATH_LEN ); + strlcat( path, "/", SYS_MAX_PATH_LEN ); + } else { + strlcpy( path, iter->prefix, SYS_MAX_PATH_LEN ); + if (*iter->prefix ) + strlcat( path, "/", SYS_MAX_PATH_LEN ); + } + + for( dir = iter->base_dir->sub_dir; dir; dir = dir->sub_dir ) { + strlcat( path, dir->name, SYS_MAX_PATH_LEN ); + strlcat( path, "/", SYS_MAX_PATH_LEN ); + } + + strlcat( path, name, SYS_MAX_PATH_LEN ); + + SHOW_FLOW( 3, "name: %s, %s -> %s\n", name, + full_path ? "full path" : "relative path", + path ); +} + +/* module_traverse_directory + * Logic as follows... + * If we have a headers pointer, + * - check if the next structure is NULL, if not process that module_info structure + * - if it's null, close the file, NULL the headers pointer and fall through + * + * This function tries to find the next module filename and then set the headers + * pointer in the cur_dir structure. + */ +static inline int module_traverse_dir(module_iterator *iter) +{ + int res; + struct stat stat; + char name[SYS_MAX_NAME_LEN]; + char path[SYS_MAX_PATH_LEN]; + + /* If (*iter->cur_header) != NULL we have another module within + * the existing file to return, so just return. + * Otherwise, actually find the next file to read. + */ + if (iter->cur_header) { + if (*iter->cur_header == NULL) + unload_module_file(iter->cur_path); + else + return B_NO_ERROR; + } + + SHOW_FLOW( 3, "scanning %s\n", iter->cur_dir->name ); + if ((res = sys_read(iter->cur_dir->file, name, 0, sizeof(name))) <= 0) { + SHOW_FLOW(3, "got error: %s\n", strerror(res)); + module_leave_dir(iter); + return B_NO_ERROR; + } + + SHOW_FLOW( 3, "got %s\n", name ); + + if (strcmp( name, "." ) == 0 || + strcmp( name, ".." ) == 0 ) + return B_NO_ERROR; + + /* currently, sys_read returns an error if buffer is too small + * I don't know the official specification, so it's always safe + * to add a trailing end-of-string + */ + name[sizeof(name) - 1] = 0; + compose_path(path, iter, name, true); + + /* As we're doing a new file, reset the pointers that might get + * screwed up... + */ + iter->cur_header = NULL; + iter->module_pos = 0; + + if ((res = sys_rstat(path, &stat)) != B_NO_ERROR ) + return res; + + if (S_ISREG(stat.st_mode)) { + module_info **hdrs = NULL; + if ((hdrs = load_module_file(path)) != NULL) { + iter->cur_header = hdrs; + iter->cur_path = (char*)kstrdup(path); + return B_NO_ERROR; + } + return EINVAL; /* not sure what we should return here */ + } + + if (S_ISDIR(stat.st_mode)) + return module_enter_dir(iter, path); + + SHOW_FLOW( 3, "entry %s not a file nor a directory - ignored\n", name ); + return B_NO_ERROR; +} + +/* module_enter_base_path + * Basically try each of the directories we have listed as module paths, + * trying each with the prefix we've been allocated. + */ +static inline int module_enter_base_path(module_iterator *iter) +{ + char path[SYS_MAX_PATH_LEN]; + + ++iter->base_path_id; + + if (iter->base_path_id >= (int)num_module_paths ) { + SHOW_FLOW0( 3, "no locations left\n" ); + return ERR_NOT_FOUND; + } + + SHOW_FLOW(3, "trying base path (%s)\n", module_paths[iter->base_path_id]); + + if (iter->base_path_id == 0 && modules_disable_user_addons) { + SHOW_FLOW0( 3, "ignoring user add-ons (they are disabled)\n" ); + return B_NO_ERROR; + } + strcpy(path, module_paths[iter->base_path_id]); + if (*iter->prefix) { + strcat(path, "/"); + strlcat(path, iter->prefix, sizeof(path)); + } + + return module_enter_dir(iter, path); +} + +/* open_module_list + * This returns a pointer to a structure that can be used to + * iterate through a list of all modules available under + * a given prefix. + * All paths will be searched and the returned list will + * contain all modules available under the prefix. + * The structure is then used by the read_next_module_name function + * and MUST be freed or memory will be leaked. + */ +void *open_module_list(const char *prefix) +{ + module_iterator *iter; + + SHOW_FLOW( 3, "prefix: %s\n", prefix ); + + iter = (module_iterator *)kmalloc(sizeof( module_iterator)); + if (!iter) + return NULL; + + iter->prefix = (char *)kstrdup( prefix ); + if(iter->prefix == NULL) { + kfree(iter); + return NULL; + } + + iter->base_path_id = -1; + iter->base_dir = iter->cur_dir = NULL; + iter->err = B_NO_ERROR; + iter->module_pos = 0; + + return (void *)iter; +} + +/* read_next_module_name + * Return the next module name from the available list, using + * a structure previously created by a call to open_module_list. + * Returns 0 if a module was available. + */ +int read_next_module_name(void *cookie, char *buf, size_t *bufsize ) +{ + module_iterator *iter = (module_iterator *)cookie; + int res; + + *buf = '\0'; + + if(!iter) + return EINVAL; + + res = iter->err; + + SHOW_FLOW0(3, "looking for next module\n"); + while (res == B_NO_ERROR) { + SHOW_FLOW0(3, "searching for module\n"); + if (iter->cur_dir == NULL) { + res = module_enter_base_path(iter); + } else { + if ((res = module_traverse_dir(iter)) == B_NO_ERROR) { + /* By this point we should have a valid pointer to a module_info structure + * in iter->cur_header + */ + if (process_module_info(iter, buf, bufsize) == B_NO_ERROR) + break; + } + } + } + + /* did we get something?? */ + if (*buf == '\0') + res = ENOENT; + + iter->err = res; + + SHOW_FLOW(3, "finished with status %s\n", strerror(iter->err)); + return iter->err; +} + + +int close_module_list(void *cookie) +{ + module_iterator *iter = (module_iterator *)cookie; + + SHOW_FLOW0( 3, "\n" ); + + if (!iter ) + return EINVAL; + + while(iter->cur_dir) + module_leave_dir(iter); + + kfree(iter->prefix); + kfree(iter); + + return 0; +} + +/* module_init + * setup module structures and data for use + */ +int module_init( kernel_args *ka, module_info **sys_module_headers ) +{ + int res; + + SHOW_FLOW0( 0, "\n" ); + recursive_lock_create( &modules_lock ); + + modules_list = hash_init(MODULES_HASH_SIZE, offsetof(module, next), + module_compare, module_hash); + + module_files = hash_init(MODULES_HASH_SIZE, offsetof(loaded_module, next), + mod_files_compare, mod_files_hash); + + if (modules_list == NULL || module_files == NULL) + return ENOMEM; + + loaded_modules.next = loaded_modules.prev = &loaded_modules; + known_modules.next = known_modules.prev = &known_modules; + +/* + if (sys_module_headers) { + if (register_module_image("", "(built-in)", 0, sys_module_headers) == NULL) + return ENOMEM; + } +*/ + #if 1 + { + isa_bus_manager *isa_interface; + int i; + char module_name[SYS_MAX_PATH_LEN]; + size_t name_len; + const char prefix[] = "bus_managers"; + void *modules_cookie; + + if ((res = get_module(ISA_MODULE_NAME, (module_info **)&isa_interface)) != 0) + dprintf( "Cannot load isa module (%s)\n", strerror( res )); + else { + + dprintf("ISA: Test : "); + for (i = 'A'; i <= 'Z'; ++i) + isa_interface->write_io_8(0xe9, i); + dprintf("\n"); + + put_module(ISA_MODULE_NAME); + } + + modules_cookie = open_module_list( prefix ); + + name_len = sizeof(module_name); + while(read_next_module_name( modules_cookie, module_name, &name_len ) == 0) + { + dprintf( "Found module %s\n", module_name ); + name_len = sizeof(module_name); + get_module(module_name, (module_info**)&isa_interface); + } + + close_module_list( modules_cookie ); + dprintf( "done\n" ); + } + #endif + + return B_NO_ERROR; +} + + +/* BeOS Compatibility... */ +int get_module(const char *path, module_info **vec) +{ + module *m = (module *)hash_lookup(modules_list, path); + loaded_module *lm; + int res = B_NO_ERROR, do_init = 0; + *vec = NULL; + +dprintf("*** get_module: %s\n", path); + + if (!m) { + m = search_module(path); + if (!m) { + dprintf("Search for %s failed.\n", path); + return ENOENT; + } + } + + /* If we've got here then we basically have a pointer to the + * module structure representing the requested module in m; + */ + + recursive_lock_lock(&modules_lock); + + /* We now need to find the module_file structure. This should + * be in memory if we have just run search_modules, but may not be + * if we are used cached information. + */ + lm = (loaded_module*)hash_lookup(module_files, m->file); + if (!lm) { + if (load_module_file(m->file) == NULL) + return ENOENT; + + lm = (loaded_module*)hash_lookup(module_files, m->file); + if (!lm) + return ENOENT; + /* just been loaded, run the init routine */ + do_init = 1; + } + + /* We have the module file required in memory! */ + m->ptr = lm->info[m->offset]; + m->module = lm; + INC_MOD_REF_COUNT(m); + *vec = m->ptr; + /* The state will be adjusted by the call to init_module */ + + recursive_lock_unlock(&modules_lock); + + if (res != B_NO_ERROR) { + vec = NULL; + return res; + } + + /* Only run the init routine after we are loaded. */ + if (do_init) + res = init_module(m); + + return res; +} + +int put_module(const char *path) +{ + module *m = (module *)hash_lookup(modules_list, path); + + if (!m) { + dprintf("We don't seem to have a reference to module %s\n", path); + return EINVAL; + } + DEC_MOD_REF_COUNT(m); + + if (m->ref_cnt == 0) { + /* We have no more references to this module. Next, do we need to + * keep_loaded? If we do just return; + */ + if (m->keep_loaded == false) { + /* so we should be OK to unload the actual module file, but just + * check first if ir provides any other modules that are still in use. + */ + uninit_module(m); + if (m->module->ref_cnt == 0) + unload_module_file(m->file); + } + } + return B_NO_ERROR; +} diff --git a/src/kernel/core/port.c b/src/kernel/core/port.c new file mode 100644 index 0000000000..d005095abd --- /dev/null +++ b/src/kernel/core/port.c @@ -0,0 +1,1187 @@ +/* ports for IPC */ +/* +** Copyright 2001, Mark-Jan Bastian. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +struct port_msg { + int msg_code; + cbuf* data_cbuf; + size_t data_len; +}; + +struct port_entry { + port_id id; + proc_id owner; + int32 capacity; + int lock; + char *name; + sem_id read_sem; + sem_id write_sem; + int head; + int tail; + int total_count; + bool closed; + struct port_msg* msg_queue; +}; + +// internal API +void dump_port_list(int argc, char **argv); +static void _dump_port_info(struct port_entry *port); +static void dump_port_info(int argc, char **argv); + + +// MAX_PORTS must be power of 2 +#define MAX_PORTS 4096 +#define MAX_QUEUE_LENGTH 4096 +#define PORT_MAX_MESSAGE_SIZE 65536 + +static struct port_entry *ports = NULL; +static region_id port_region = 0; +static bool ports_active = false; + +static port_id next_port = 0; + +static int port_spinlock = 0; +#define GRAB_PORT_LIST_LOCK() acquire_spinlock(&port_spinlock) +#define RELEASE_PORT_LIST_LOCK() release_spinlock(&port_spinlock) +#define GRAB_PORT_LOCK(s) acquire_spinlock(&(s).lock) +#define RELEASE_PORT_LOCK(s) release_spinlock(&(s).lock) + +int port_init(kernel_args *ka) +{ + int i; + int sz; + + sz = sizeof(struct port_entry) * MAX_PORTS; + + // create and initialize semaphore table + port_region = vm_create_anonymous_region(vm_get_kernel_aspace_id(), "port_table", (void **)&ports, + REGION_ADDR_ANY_ADDRESS, sz, REGION_WIRING_WIRED, LOCK_RW|LOCK_KERNEL); + if(port_region < 0) { + panic("unable to allocate kernel port table!\n"); + } + + memset(ports, 0, sz); + for(i=0; i= 0) { + dprintf("%p\tid: 0x%x\t\tname: '%s'\n", &ports[i], ports[i].id, ports[i].name); + } + } +} + +static void _dump_port_info(struct port_entry *port) +{ + int cnt; + dprintf("PORT: %p\n", port); + dprintf("name: '%s'\n", port->name); + dprintf("owner: 0x%x\n", port->owner); + dprintf("cap: %d\n", port->capacity); + dprintf("head: %d\n", port->head); + dprintf("tail: %d\n", port->tail); + get_sem_count(port->read_sem, &cnt); + dprintf("read_sem: %d\n", cnt); + get_sem_count(port->read_sem, &cnt); + dprintf("write_sem: %d\n", cnt); +} + +static void dump_port_info(int argc, char **argv) +{ + int i; + + if(argc < 2) { + dprintf("port: not enough arguments\n"); + return; + } + + // if the argument looks like a hex number, treat it as such + if(strlen(argv[1]) > 2 && argv[1][0] == '0' && argv[1][1] == 'x') { + unsigned long num = atoul(argv[1]); + + if(num > KERNEL_BASE && num <= (KERNEL_BASE + (KERNEL_SIZE - 1))) { + // XXX semi-hack + // one can use either address or a port_id, since KERNEL_BASE > MAX_PORTS assumed + _dump_port_info((struct port_entry *)num); + return; + } else { + unsigned slot = num % MAX_PORTS; + if(ports[slot].id != (int)num) { + dprintf("port 0x%lx doesn't exist!\n", num); + return; + } + _dump_port_info(&ports[slot]); + return; + } + } + + // walk through the ports list, trying to match name + for(i=0; i MAX_QUEUE_LENGTH) + return EINVAL; + q = (void *)kmalloc( queue_length * sizeof(struct port_msg) ); + if (q == NULL) { + kfree(temp_name); // dealloc name, too + return ENOMEM; + } + + // create sem_r with owner set to -1 + sem_r = create_sem_etc(0, temp_name, -1); + if (sem_r < 0) { + // cleanup + kfree(temp_name); + kfree(q); + return sem_r; + } + + // create sem_w + sem_w = create_sem_etc(queue_length, temp_name, -1); + if (sem_w < 0) { + // cleanup + delete_sem(sem_r); + kfree(temp_name); + kfree(q); + return sem_w; + } + owner = proc_get_current_proc_id(); + + state = int_disable_interrupts(); + GRAB_PORT_LIST_LOCK(); + + // find the first empty spot + for(i=0; i= next_port % MAX_PORTS) { + next_port += i - next_port % MAX_PORTS; + } else { + next_port += MAX_PORTS - (next_port % MAX_PORTS - i); + } + ports[i].id = next_port++; + ports[i].lock = 0; + GRAB_PORT_LOCK(ports[i]); + RELEASE_PORT_LIST_LOCK(); + + ports[i].capacity = queue_length; + ports[i].name = temp_name; + + // assign sem + ports[i].read_sem = sem_r; + ports[i].write_sem = sem_w; + ports[i].msg_queue = q; + ports[i].head = 0; + ports[i].tail = 0; + ports[i].total_count= 0; + ports[i].owner = owner; + retval = ports[i].id; + RELEASE_PORT_LOCK(ports[i]); + goto out; + } + } + // not enough ports... + RELEASE_PORT_LIST_LOCK(); + kfree(q); + kfree(temp_name); + retval = B_NO_MORE_PORTS; + dprintf("create_port(): B_NO_MORE_PORTS\n"); + + // cleanup + delete_sem(sem_w); + delete_sem(sem_r); + kfree(temp_name); + kfree(q); + +out: + int_restore_interrupts(state); + + return retval; +} + +int +close_port(port_id id) +{ + int state; + int slot; + + if(ports_active == false) + return B_BAD_PORT_ID; + if(id < 0) + return B_BAD_PORT_ID; + slot = id % MAX_PORTS; + + // walk through the sem list, trying to match name + state = int_disable_interrupts(); + GRAB_PORT_LOCK(ports[slot]); + + if (ports[slot].id != id) { + RELEASE_PORT_LOCK(ports[slot]); + int_restore_interrupts(state); + return B_BAD_PORT_ID; + } + + // mark port to disable writing + ports[slot].closed = true; + + RELEASE_PORT_LOCK(ports[slot]); + int_restore_interrupts(state); + + return B_NO_ERROR; +} + +int +delete_port(port_id id) +{ + int slot; + int state; + sem_id r_sem, w_sem; + int capacity; + int i; + + char *old_name; + struct port_msg *q; + + if(ports_active == false) + return B_BAD_PORT_ID; + if(id < 0) + return B_BAD_PORT_ID; + + slot = id % MAX_PORTS; + + state = int_disable_interrupts(); + GRAB_PORT_LOCK(ports[slot]); + + if(ports[slot].id != id) { + RELEASE_PORT_LOCK(ports[slot]); + int_restore_interrupts(state); + dprintf("delete_port: invalid port_id %d\n", id); + return B_BAD_PORT_ID; + } + + /* mark port as invalid */ + ports[slot].id = -1; + old_name = ports[slot].name; + q = ports[slot].msg_queue; + r_sem = ports[slot].read_sem; + w_sem = ports[slot].write_sem; + capacity = ports[slot].capacity; + ports[slot].name = NULL; + + RELEASE_PORT_LOCK(ports[slot]); + int_restore_interrupts(state); + + // delete the cbuf's that are left in the queue (if any) + for (i=0; iport = ports[slot].id; +// info->owner = ports[slot].owner; + strncpy(info->name, ports[slot].name, min(strlen(ports[slot].name),SYS_MAX_OS_NAME_LEN-1)); + info->capacity = ports[slot].capacity; + get_sem_count(ports[slot].read_sem, &info->queue_count); + info->total_count = ports[slot].total_count; + + RELEASE_PORT_LOCK(ports[slot]); + int_restore_interrupts(state); + + // from our port_entry + return B_NO_ERROR; +} + +int +_get_next_port_info(team_id proc, int32 *cookie, struct port_info *info, + size_t size) +{ + int state; + int slot; + + if(ports_active == false) + return B_BAD_PORT_ID; + if (cookie == NULL) + return EINVAL; + + if (*cookie == NULL) { + // return first found + slot = 0; + } else { + // start at index cookie, but check cookie against MAX_PORTS + slot = *cookie; + if (slot >= MAX_PORTS) + return B_BAD_PORT_ID; + } + + // spinlock + state = int_disable_interrupts(); + GRAB_PORT_LIST_LOCK(); + + info->port = -1; // used as found flag + while (slot < MAX_PORTS) { + GRAB_PORT_LOCK(ports[slot]); + if (ports[slot].id != -1) + if (ports[slot].owner == proc) { + // found one! + // copy the info + info->port = ports[slot].id; +// info->owner = ports[slot].owner; + strncpy(info->name, ports[slot].name, min(strlen(ports[slot].name),SYS_MAX_OS_NAME_LEN-1)); + info->capacity = ports[slot].capacity; + get_sem_count(ports[slot].read_sem, &info->queue_count); + info->total_count = ports[slot].total_count; + RELEASE_PORT_LOCK(ports[slot]); + slot++; + break; + } + RELEASE_PORT_LOCK(ports[slot]); + slot++; + } + RELEASE_PORT_LIST_LOCK(); + int_restore_interrupts(state); + + if (info->port == -1) + return B_BAD_PORT_ID; + *cookie = slot; + return B_NO_ERROR; +} + +ssize_t +port_buffer_size(port_id id) +{ + return port_buffer_size_etc(id, 0, 0); +} + +ssize_t +port_buffer_size_etc(port_id id, + uint32 flags, + bigtime_t timeout) +{ + int slot; + int res; + int t; + int len; + int state; + + if(ports_active == false) + return B_BAD_PORT_ID; + if(id < 0) + return B_BAD_PORT_ID; + + slot = id % MAX_PORTS; + + state = int_disable_interrupts(); + GRAB_PORT_LOCK(ports[slot]); + + if(ports[slot].id != id) { + RELEASE_PORT_LOCK(ports[slot]); + int_restore_interrupts(state); + dprintf("get_port_info: invalid port_id %d\n", id); + return B_BAD_PORT_ID; + } + RELEASE_PORT_LOCK(ports[slot]); + int_restore_interrupts(state); + + // block if no message, + // if TIMEOUT flag set, block with timeout + + // XXX - is it a race condition to acquire a sem just after we + // unlocked the port ? + // XXX: call an acquire_sem which does the release lock, restore int & block the right way + res = acquire_sem_etc(ports[slot].read_sem, 1, flags & (B_TIMEOUT | B_CAN_INTERRUPT), timeout); + + GRAB_PORT_LOCK(ports[slot]); + if (res == ERR_SEM_DELETED) { + // somebody deleted the port + RELEASE_PORT_LOCK(ports[slot]); + return B_BAD_PORT_ID; + } + if (res == ERR_SEM_TIMED_OUT) { + RELEASE_PORT_LOCK(ports[slot]); + return B_TIMED_OUT; + } + + // once message arrived, read data's length + + // determine tail + // read data's head length + t = ports[slot].head; + if (t < 0) + panic("port %id: tail < 0", ports[slot].id); + if (t > ports[slot].capacity) + panic("port %id: tail > cap %d", ports[slot].id, ports[slot].capacity); + len = ports[slot].msg_queue[t].data_len; + + // restore readsem + release_sem(ports[slot].read_sem); + + RELEASE_PORT_LOCK(ports[slot]); + + // return length of item at end of queue + return len; +} + +ssize_t +port_count(port_id id) +{ + int slot; + int state; + int count; + + if(ports_active == false) + return B_BAD_PORT_ID; + if(id < 0) + return B_BAD_PORT_ID; + + slot = id % MAX_PORTS; + + state = int_disable_interrupts(); + GRAB_PORT_LOCK(ports[slot]); + + if(ports[slot].id != id) { + RELEASE_PORT_LOCK(ports[slot]); + int_restore_interrupts(state); + dprintf("port_count: invalid port_id %d\n", id); + return B_BAD_PORT_ID; + } + + get_sem_count(ports[slot].read_sem, &count); + // do not return negative numbers + if (count < 0) + count = 0; + + RELEASE_PORT_LOCK(ports[slot]); + int_restore_interrupts(state); + + // return count of messages (sem_count) + return count; +} + +int +read_port(port_id port, + int32 *msg_code, + void *msg_buffer, + size_t buffer_size) +{ + return read_port_etc(port, msg_code, msg_buffer, buffer_size, 0, 0); +} + +int +read_port_etc(port_id id, + int32 *msg_code, + void *msg_buffer, + size_t buffer_size, + uint32 flags, + bigtime_t timeout) +{ + int slot; + int state; + sem_id cached_semid; + size_t siz; + int res; + int t; + cbuf* msg_store; + int32 code; + int err; + + if(ports_active == false) + return B_BAD_PORT_ID; + if(id < 0) + return B_BAD_PORT_ID; + if(msg_code == NULL) + return EINVAL; + if((msg_buffer == NULL) && (buffer_size > 0)) + return EINVAL; + if (timeout < 0) + return EINVAL; + + flags = flags & (PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT | B_TIMEOUT); + + slot = id % MAX_PORTS; + + state = int_disable_interrupts(); + GRAB_PORT_LOCK(ports[slot]); + + if(ports[slot].id != id) { + RELEASE_PORT_LOCK(ports[slot]); + int_restore_interrupts(state); + dprintf("read_port_etc: invalid port_id %d\n", id); + return B_BAD_PORT_ID; + } + // store sem_id in local variable + cached_semid = ports[slot].read_sem; + + // unlock port && enable ints/ + RELEASE_PORT_LOCK(ports[slot]); + int_restore_interrupts(state); + + // XXX -> possible race condition if port gets deleted (->sem deleted too), therefore + // sem_id is cached in local variable up here + + // get 1 entry from the queue, block if needed + res = acquire_sem_etc(cached_semid, 1, flags, timeout); + + // XXX: possible race condition if port read by two threads... + // both threads will read in 2 different slots allocated above, simultaneously + // slot is a thread-local variable + + if (res == ERR_SEM_DELETED || res == EINTR) { + /* somebody deleted the port or the sem went away */ + return B_BAD_PORT_ID; + } + + if (res == ERR_SEM_TIMED_OUT) { + // timed out, or, if timeout=0, 'would block' + return B_BAD_PORT_ID; + } + + if (res != B_NO_ERROR) { + dprintf("write_port_etc: res unknown error %d\n", res); + return res; + } + + state = int_disable_interrupts(); + GRAB_PORT_LOCK(ports[slot]); + + t = ports[slot].tail; + if (t < 0) + panic("port %id: tail < 0", ports[slot].id); + if (t > ports[slot].capacity) + panic("port %id: tail > cap %d", ports[slot].id, ports[slot].capacity); + + ports[slot].tail = (ports[slot].tail + 1) % ports[slot].capacity; + + msg_store = ports[slot].msg_queue[t].data_cbuf; + code = ports[slot].msg_queue[t].msg_code; + + // mark queue entry unused + ports[slot].msg_queue[t].data_cbuf = NULL; + + // check output buffer size + siz = min(buffer_size, ports[slot].msg_queue[t].data_len); + + cached_semid = ports[slot].write_sem; + + RELEASE_PORT_LOCK(ports[slot]); + int_restore_interrupts(state); + + // copy message + *msg_code = code; + if (siz > 0) { + if (flags & PORT_FLAG_USE_USER_MEMCPY) { + if ((err = cbuf_user_memcpy_from_chain(msg_buffer, msg_store, 0, siz) < 0)) { + // leave the port intact, for other threads that might not crash + cbuf_free_chain(msg_store); + release_sem(cached_semid); + return err; + } + } else + cbuf_memcpy_from_chain(msg_buffer, msg_store, 0, siz); + } + // free the cbuf + cbuf_free_chain(msg_store); + + // make one spot in queue available again for write + release_sem(cached_semid); + + return siz; +} + +int +set_port_owner(port_id id, proc_id proc) +{ + int slot; + int state; + + if(ports_active == false) + return B_BAD_PORT_ID; + if(id < 0) + return B_BAD_PORT_ID; + + slot = id % MAX_PORTS; + + state = int_disable_interrupts(); + GRAB_PORT_LOCK(ports[slot]); + + if(ports[slot].id != id) { + RELEASE_PORT_LOCK(ports[slot]); + int_restore_interrupts(state); + dprintf("set_port_owner: invalid port_id %d\n", id); + return B_BAD_PORT_ID; + } + + // transfer ownership to other process + ports[slot].owner = proc; + + // unlock port + RELEASE_PORT_LOCK(ports[slot]); + int_restore_interrupts(state); + + return B_NO_ERROR; +} + +int +write_port(port_id id, + int32 msg_code, + const void *msg_buffer, + size_t buffer_size) +{ + return write_port_etc(id, msg_code, msg_buffer, buffer_size, 0, 0); +} + +int +write_port_etc(port_id id, + int32 msg_code, + const void *msg_buffer, + size_t buffer_size, + uint32 flags, + bigtime_t timeout) +{ + int slot; + int state; + int res; + sem_id cached_semid; + int h; + cbuf* msg_store; + int c1, c2; + int err; + + if(ports_active == false) + return B_BAD_PORT_ID; + if(id < 0) + return B_BAD_PORT_ID; + + // mask irrelevant flags + flags = flags & (PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT | B_TIMEOUT); + + slot = id % MAX_PORTS; + + // check buffer_size + if (buffer_size > PORT_MAX_MESSAGE_SIZE) + return EINVAL; + + state = int_disable_interrupts(); + GRAB_PORT_LOCK(ports[slot]); + + if(ports[slot].id != id) { + RELEASE_PORT_LOCK(ports[slot]); + int_restore_interrupts(state); + dprintf("write_port_etc: invalid port_id %d\n", id); + return B_BAD_PORT_ID; + } + + if (ports[slot].closed) { + RELEASE_PORT_LOCK(ports[slot]); + int_restore_interrupts(state); + dprintf("write_port_etc: port %d closed\n", id); + return B_BAD_PORT_ID; + } + + // store sem_id in local variable + cached_semid = ports[slot].write_sem; + + RELEASE_PORT_LOCK(ports[slot]); + int_restore_interrupts(state); + + // XXX -> possible race condition if port gets deleted (->sem deleted too), + // and queue is full therefore sem_id is cached in local variable up here + + // get 1 entry from the queue, block if needed + // assumes flags + res = acquire_sem_etc(cached_semid, 1, + flags & (B_TIMEOUT | B_CAN_INTERRUPT), timeout); + + // XXX: possible race condition if port written by two threads... + // both threads will write in 2 different slots allocated above, simultaneously + // slot is a thread-local variable + + if (res == ERR_SEM_DELETED || res == EINTR) { + /* somebody deleted the port or the sem while we were waiting */ + return B_BAD_PORT_ID; + } + + if (res == ERR_SEM_TIMED_OUT) { + // timed out, or, if timeout=0, 'would block' + return B_TIMED_OUT; + } + + if (res != B_NO_ERROR) { + dprintf("write_port_etc: res unknown error %d\n", res); + return res; + } + + if (buffer_size > 0) { + msg_store = cbuf_get_chain(buffer_size); + if (msg_store == NULL) + return ENOMEM; + if (flags & PORT_FLAG_USE_USER_MEMCPY) { + // copy from user memory + if ((err = cbuf_user_memcpy_to_chain(msg_store, 0, msg_buffer, buffer_size)) < 0) + return err; // memory exception + } else + // copy from kernel memory + if ((err = cbuf_memcpy_to_chain(msg_store, 0, msg_buffer, buffer_size)) < 0) + return err; // memory exception + } else { + msg_store = NULL; + } + + // attach copied message to queue + state = int_disable_interrupts(); + GRAB_PORT_LOCK(ports[slot]); + + h = ports[slot].head; + if (h < 0) + panic("port %id: head < 0", ports[slot].id); + if (h >= ports[slot].capacity) + panic("port %id: head > cap %d", ports[slot].id, ports[slot].capacity); + ports[slot].msg_queue[h].msg_code = msg_code; + ports[slot].msg_queue[h].data_cbuf = msg_store; + ports[slot].msg_queue[h].data_len = buffer_size; + ports[slot].head = (ports[slot].head + 1) % ports[slot].capacity; + ports[slot].total_count++; + + // store sem_id in local variable + cached_semid = ports[slot].read_sem; + + RELEASE_PORT_LOCK(ports[slot]); + int_restore_interrupts(state); + + get_sem_count(ports[slot].read_sem, &c1); + get_sem_count(ports[slot].write_sem, &c2); + + // release sem, allowing read (might reschedule) + release_sem(cached_semid); + + return B_NO_ERROR; +} + +/* this function cycles through the ports table, deleting all the ports that are owned by + the passed proc_id */ +int delete_owned_ports(proc_id owner) +{ + int state; + int i; + int count = 0; + + if(ports_active == false) + return B_BAD_PORT_ID; + + state = int_disable_interrupts(); + GRAB_PORT_LIST_LOCK(); + + for(i=0; i= KERNEL_BASE && (addr)uname <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + rc = user_strncpy(name, uname, SYS_MAX_OS_NAME_LEN-1); + if(rc < 0) + return rc; + name[SYS_MAX_OS_NAME_LEN-1] = 0; + + return create_port(queue_length, name); + } else { + return create_port(queue_length, NULL); + } +} + +int user_close_port(port_id id) +{ + return close_port(id); +} + +int user_delete_port(port_id id) +{ + return delete_port(id); +} + +port_id user_find_port(const char *port_name) +{ + if(port_name != NULL) { + char name[SYS_MAX_OS_NAME_LEN]; + int rc; + + if((addr)port_name >= KERNEL_BASE && (addr)port_name <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + rc = user_strncpy(name, port_name, SYS_MAX_OS_NAME_LEN-1); + if(rc < 0) + return rc; + name[SYS_MAX_OS_NAME_LEN-1] = 0; + + return find_port(name); + } else { + return EINVAL; + } +} + +int user_get_port_info(port_id id, struct port_info *uinfo) +{ + int res; + struct port_info info; + int rc; + + if (uinfo == NULL) + return EINVAL; + if((addr)uinfo >= KERNEL_BASE && (addr)uinfo <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + res = get_port_info(id, &info); + // copy to userspace + rc = user_memcpy(uinfo, &info, sizeof(struct port_info)); + if(rc < 0) + return rc; + return res; +} + +int user_get_next_port_info(proc_id uproc, + uint32 *ucookie, + struct port_info *uinfo) +{ + int res; + struct port_info info; + uint32 cookie; + int rc; + + if (ucookie == NULL) + return EINVAL; + if (uinfo == NULL) + return EINVAL; + if((addr)ucookie >= KERNEL_BASE && (addr)ucookie <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + if((addr)uinfo >= KERNEL_BASE && (addr)uinfo <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + // copy from userspace + rc = user_memcpy(&cookie, ucookie, sizeof(uint32)); + if(rc < 0) + return rc; + + res = get_next_port_info(uproc, &cookie, &info); + // copy to userspace + rc = user_memcpy(ucookie, &info, sizeof(uint32)); + if(rc < 0) + return rc; + rc = user_memcpy(uinfo, &info, sizeof(struct port_info)); + if(rc < 0) + return rc; + return res; +} + +ssize_t user_port_buffer_size_etc(port_id port, uint32 flags, bigtime_t timeout) +{ + return port_buffer_size_etc(port, flags | B_CAN_INTERRUPT, timeout); +} + +int32 user_port_count(port_id port) +{ + return port_count(port); +} + +ssize_t user_read_port_etc(port_id uport, int32 *umsg_code, void *umsg_buffer, + size_t ubuffer_size, uint32 uflags, bigtime_t utimeout) +{ + ssize_t res; + int32 msg_code; + int rc; + + if (umsg_code == NULL) + return EINVAL; + if (umsg_buffer == NULL) + return EINVAL; + + if((addr)umsg_code >= KERNEL_BASE && (addr)umsg_code <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + if((addr)umsg_buffer >= KERNEL_BASE && (addr)umsg_buffer <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + res = read_port_etc(uport, &msg_code, umsg_buffer, ubuffer_size, + uflags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT, utimeout); + + rc = user_memcpy(umsg_code, &msg_code, sizeof(int32)); + if(rc < 0) + return rc; + + return res; +} + +int user_set_port_owner(port_id port, proc_id proc) +{ + return set_port_owner(port, proc); +} + +int user_write_port_etc(port_id uport, int32 umsg_code, void *umsg_buffer, + size_t ubuffer_size, uint32 uflags, bigtime_t utimeout) +{ + if (umsg_buffer == NULL) + return EINVAL; + if((addr)umsg_buffer >= KERNEL_BASE && (addr)umsg_buffer <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + return write_port_etc(uport, umsg_code, umsg_buffer, ubuffer_size, + uflags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT, utimeout); +} + diff --git a/src/kernel/core/queue.c b/src/kernel/core/queue.c new file mode 100644 index 0000000000..66b9c8ae7a --- /dev/null +++ b/src/kernel/core/queue.c @@ -0,0 +1,152 @@ +/* Standard queue */ + +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include + +typedef struct queue_element { + void *next; +} queue_element; + +typedef struct queue_typed { + queue_element *head; + queue_element *tail; + int count; +} queue_typed; + +int queue_init(queue *q) +{ + q->head = q->tail = NULL; + q->count = 0; + return 0; +} + +int queue_remove_item(queue *_q, void *e) +{ + queue_typed *q = (queue_typed *)_q; + queue_element *elem = (queue_element *)e; + queue_element *temp, *last = NULL; + + temp = (queue_element *)q->head; + while(temp) { + if(temp == elem) { + if(last) { + last->next = temp->next; + } else { + q->head = temp->next; + } + if(q->tail == temp) + q->tail = last; + q->count--; + return 0; + } + last = temp; + temp = temp->next; + } + + return -1; +} + +int queue_enqueue(queue *_q, void *e) +{ + queue_typed *q = (queue_typed *)_q; + queue_element *elem = (queue_element *)e; + + if(q->tail == NULL) { + q->tail = elem; + q->head = elem; + } else { + q->tail->next = elem; + q->tail = elem; + } + elem->next = NULL; + q->count++; + return 0; +} + +void *queue_dequeue(queue *_q) +{ + queue_typed *q = (queue_typed *)_q; + queue_element *elem; + + elem = q->head; + if(q->head != NULL) + q->head = q->head->next; + if(q->tail == elem) + q->tail = NULL; + + if(elem != NULL) + q->count--; + + return elem; +} + +void *queue_peek(queue *q) +{ + return q->head; +} + +/* fixed queue stuff */ + +int fixed_queue_init(fixed_queue *q, int size) +{ + if(size <= 0) + return ERR_INVALID_ARGS; + + q->table = kmalloc(size * sizeof(void *)); + if(!q->table) + return ERR_NO_MEMORY; + q->head = 0; + q->tail = 0; + q->count = 0; + q->size = size; + + return B_NO_ERROR; +} + +void fixed_queue_destroy(fixed_queue *q) +{ + if(q->table) + kfree(q->table); +} + +int fixed_queue_enqueue(fixed_queue *q, void *e) +{ + if(q->count == q->size) + return ERR_NO_MEMORY; + + q->table[q->head++] = e; + if(q->head >= q->size) q->head = 0; + q->count++; + + return B_NO_ERROR; +} + +void *fixed_queue_dequeue(fixed_queue *q) +{ + void *e; + + if(q->count <= 0) + return NULL; + + e = q->table[q->tail++]; + if(q->tail >= q->size) q->tail = 0; + q->count--; + + return e; +} + +void *fixed_queue_peek(fixed_queue *q) +{ + if(q->count <= 0) + return NULL; + + return q->table[q->tail]; +} + + diff --git a/src/kernel/core/sem.c b/src/kernel/core/sem.c new file mode 100644 index 0000000000..f5326595a7 --- /dev/null +++ b/src/kernel/core/sem.c @@ -0,0 +1,893 @@ +/* Semaphore code. Lots of "todo" items*/ + +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +struct sem_entry { + sem_id id; + int count; + struct thread_queue q; + char *name; + int lock; + proc_id owner; // if set to -1, means owned by a port +}; + +#define MAX_SEMS 4096 + +static struct sem_entry *sems = NULL; +static region_id sem_region = 0; +static bool sems_active = false; + +static sem_id next_sem = 0; + +static int sem_spinlock = 0; +#define GRAB_SEM_LIST_LOCK() acquire_spinlock(&sem_spinlock) +#define RELEASE_SEM_LIST_LOCK() release_spinlock(&sem_spinlock) +#define GRAB_SEM_LOCK(s) acquire_spinlock(&(s).lock) +#define RELEASE_SEM_LOCK(s) release_spinlock(&(s).lock) + +// used in functions that may put a bunch of threads in the run q at once +#define READY_THREAD_CACHE_SIZE 16 + +static int remove_thread_from_sem(struct thread *t, struct sem_entry *sem, struct thread_queue *queue, int sem_errcode); + +struct sem_timeout_args { + thread_id blocked_thread; + sem_id blocked_sem_id; + int sem_count; +}; + +static void dump_sem_list(int argc, char **argv) +{ + int i; + + for(i=0; i= 0) { + dprintf("%p\tid: 0x%x\t\tname: '%s'\n", &sems[i], sems[i].id, sems[i].name); + } + } +} + +static void _dump_sem_info(struct sem_entry *sem) +{ + dprintf("SEM: %p\n", sem); + dprintf("name: '%s'\n", sem->name); + dprintf("owner: 0x%x\n", sem->owner); + dprintf("count: 0x%x\n", sem->count); + dprintf("queue: head %p tail %p\n", sem->q.head, sem->q.tail); +} + +static void dump_sem_info(int argc, char **argv) +{ + int i; + + if(argc < 2) { + dprintf("sem: not enough arguments\n"); + return; + } + + // if the argument looks like a hex number, treat it as such + if(strlen(argv[1]) > 2 && argv[1][0] == '0' && argv[1][1] == 'x') { + unsigned long num = atoul(argv[1]); + + if(num > KERNEL_BASE && num <= (KERNEL_BASE + (KERNEL_SIZE - 1))) { + // XXX semi-hack + _dump_sem_info((struct sem_entry *)num); + return; + } else { + unsigned slot = num % MAX_SEMS; + if(sems[slot].id != (int)num) { + dprintf("sem 0x%lx doesn't exist!\n", num); + return; + } + _dump_sem_info(&sems[slot]); + return; + } + } + + // walk through the sem list, trying to match name + for(i=0; i= next_sem % MAX_SEMS) { + next_sem += i - next_sem % MAX_SEMS; + } else { + next_sem += MAX_SEMS - (next_sem % MAX_SEMS - i); + } + sems[i].id = next_sem++; + + sems[i].lock = 0; + GRAB_SEM_LOCK(sems[i]); + RELEASE_SEM_LIST_LOCK(); + + sems[i].q.tail = NULL; + sems[i].q.head = NULL; + sems[i].count = count; + sems[i].name = temp_name; + sems[i].owner = owner; + retval = sems[i].id; + + RELEASE_SEM_LOCK(sems[i]); + goto out; + } + } + +//err: + RELEASE_SEM_LIST_LOCK(); + kfree(temp_name); + +out: + int_restore_interrupts(state); + + return retval; +} + +sem_id create_sem(int count, const char *name) +{ + return create_sem_etc(count, name, proc_get_kernel_proc_id()); +} + +int delete_sem(sem_id id) +{ + return delete_sem_etc(id, 0); +} + +int delete_sem_etc(sem_id id, int return_code) +{ + int slot; + int state; + int err = B_NO_ERROR; + struct thread *t; + int released_threads; + char *old_name; + struct thread_queue release_queue; + + if(sems_active == false) + return B_NO_MORE_SEMS; + if(id < 0) + return B_BAD_SEM_ID; + + slot = id % MAX_SEMS; + + state = int_disable_interrupts(); + GRAB_SEM_LOCK(sems[slot]); + + if(sems[slot].id != id) { + RELEASE_SEM_LOCK(sems[slot]); + int_restore_interrupts(state); + dprintf("delete_sem: invalid sem_id %d\n", id); + return B_BAD_SEM_ID; + } + + released_threads = 0; + release_queue.head = release_queue.tail = NULL; + + // free any threads waiting for this semaphore + while((t = thread_dequeue(&sems[slot].q)) != NULL) { + t->state = THREAD_STATE_READY; + t->sem_errcode = B_BAD_SEM_ID; + t->sem_deleted_retcode = return_code; + t->sem_count = 0; + thread_enqueue(t, &release_queue); + released_threads++; + } + + sems[slot].id = -1; + old_name = sems[slot].name; + sems[slot].name = NULL; + + RELEASE_SEM_LOCK(sems[slot]); + + if(released_threads > 0) { + GRAB_THREAD_LOCK(); + while((t = thread_dequeue(&release_queue)) != NULL) { + thread_enqueue_run_q(t); + } + thread_resched(); + RELEASE_THREAD_LOCK(); + } + + int_restore_interrupts(state); + + kfree(old_name); + + return err; +} + +// Called from a timer handler. Wakes up a semaphore +static int sem_timeout(void *data) +{ + struct sem_timeout_args *args = (struct sem_timeout_args *)data; + struct thread *t; + int slot; + int state; + struct thread_queue wakeup_queue; + + t = thread_get_thread_struct(args->blocked_thread); + if(t == NULL) + return INT_NO_RESCHEDULE; + slot = args->blocked_sem_id % MAX_SEMS; + + state = int_disable_interrupts(); + GRAB_SEM_LOCK(sems[slot]); + +// dprintf("sem_timeout: called on 0x%x sem %d, tid %d\n", to, to->sem_id, to->thread_id); + + if(sems[slot].id != args->blocked_sem_id) { + // this thread was not waiting on this semaphore + panic("sem_timeout: thid %d was trying to wait on sem %d which doesn't exist!\n", + args->blocked_thread, args->blocked_sem_id); + } + + wakeup_queue.head = wakeup_queue.tail = NULL; + remove_thread_from_sem(t, &sems[slot], &wakeup_queue, B_TIMED_OUT); + + RELEASE_SEM_LOCK(sems[slot]); + + GRAB_THREAD_LOCK(); + // put the threads in the run q here to make sure we dont deadlock in sem_interrupt_thread + while((t = thread_dequeue(&wakeup_queue)) != NULL) { + thread_enqueue_run_q(t); + } + RELEASE_THREAD_LOCK(); + + int_restore_interrupts(state); + + return INT_RESCHEDULE; +} + + +int acquire_sem(sem_id id) +{ + return acquire_sem_etc(id, 1, 0, 0); +} + +int acquire_sem_etc(sem_id id, int count, int flags, bigtime_t timeout) +{ + int slot = id % MAX_SEMS; + int state; + int err = 0; + + if(sems_active == false) + return B_NO_MORE_SEMS; + + if(id < 0) { + dprintf("acquire_sem_etc: invalid sem handle %d\n", id); + return B_BAD_SEM_ID; + } + + if(count <= 0) + return ERR_INVALID_ARGS; + + state = int_disable_interrupts(); + GRAB_SEM_LOCK(sems[slot]); + + if(sems[slot].id != id) { + dprintf("acquire_sem_etc: bad sem_id %d\n", id); + err = B_BAD_SEM_ID; + goto err; + } + + if(sems[slot].count - count < 0 && (flags & B_TIMEOUT) != 0 && timeout <= 0) { + // immediate timeout + err = ERR_SEM_TIMED_OUT; + goto err; + } + + if((sems[slot].count -= count) < 0) { + // we need to block + struct thread *t = thread_get_current_thread(); + struct timer_event timer; // stick it on the stack, since we may be blocking here + struct sem_timeout_args args; + + // do a quick check to see if the thread has any pending kill signals + // this should catch most of the cases where the thread had a signal + if((flags & B_CAN_INTERRUPT) && (t->pending_signals & SIG_KILL)) { + sems[slot].count += count; + err = EINTR; + goto err; + } + + t->next_state = THREAD_STATE_WAITING; + t->sem_flags = flags; + t->sem_blocking = id; + t->sem_acquire_count = count; + t->sem_count = min(-sems[slot].count, count); // store the count we need to restore upon release + t->sem_deleted_retcode = 0; + t->sem_errcode = B_NO_ERROR; + thread_enqueue(t, &sems[slot].q); + + if((flags & (B_TIMEOUT | B_ABSOLUTE_TIMEOUT)) != 0) { + int the_timeout = timeout; +// dprintf("sem_acquire_etc: setting timeout sem for %d %d usecs, semid %d, tid %d\n", +// timeout, sem_id, t->id); + // set up an event to go off with the thread struct as the data + if (flags & B_ABSOLUTE_TIMEOUT) + the_timeout -= system_time(); + + args.blocked_sem_id = id; + args.blocked_thread = t->id; + args.sem_count = count; + + timer_setup_timer(&sem_timeout, &args, &timer); + timer_set_event(the_timeout, TIMER_MODE_ONESHOT, &timer); + } + + RELEASE_SEM_LOCK(sems[slot]); + GRAB_THREAD_LOCK(); + // check again to see if a kill signal is pending. + // it may have been delivered while setting up the sem, though it's pretty unlikely + if((flags & B_CAN_INTERRUPT) && (t->pending_signals & SIG_KILL)) { + struct thread_queue wakeup_queue; + // ok, so a tiny race happened where a signal was delivered to this thread while + // it was setting up the sem. We can only be sure a signal wasn't delivered + // here, since the threadlock is held. The previous check would have found most + // instances, but there was a race, so we have to handle it. It'll be more messy... + wakeup_queue.head = wakeup_queue.tail = NULL; + GRAB_SEM_LOCK(sems[slot]); + if(sems[slot].id == id) { + remove_thread_from_sem(t, &sems[slot], &wakeup_queue, EINTR); + } + RELEASE_SEM_LOCK(sems[slot]); + while((t = thread_dequeue(&wakeup_queue)) != NULL) { + thread_enqueue_run_q(t); + } + // fall through and reschedule since another thread with a higher priority may have been woken up + } + thread_resched(); + RELEASE_THREAD_LOCK(); + + if((flags & B_TIMEOUT) != 0) { + if(t->sem_errcode != ERR_SEM_TIMED_OUT) { + // cancel the timer event, the sem may have been deleted or interrupted + // with the timer still active + timer_cancel_event(&timer); + } + } + + int_restore_interrupts(state); + + return t->sem_errcode; + } + +err: + RELEASE_SEM_LOCK(sems[slot]); + int_restore_interrupts(state); + + return err; +} + +int release_sem(sem_id id) +{ + return release_sem_etc(id, 1, 0); +} + + +int release_sem_etc(sem_id id, int count, int flags) +{ + int slot = id % MAX_SEMS; + int state; + int released_threads = 0; + int err = 0; + struct thread_queue release_queue; + + if(sems_active == false) + return B_NO_MORE_SEMS; + + if(id < 0) + return B_BAD_SEM_ID; + + if(count <= 0) + return ERR_INVALID_ARGS; + + state = int_disable_interrupts(); + GRAB_SEM_LOCK(sems[slot]); + + if(sems[slot].id != id) { + dprintf("sem_release_etc: invalid sem_id %d\n", id); + err = B_BAD_SEM_ID; + goto err; + } + + // clear out a queue we will use to hold all of the threads that we will have to + // put back into the run list. This is done so the thread lock wont be held + // while this sems lock is held since the two locks are grabbed in the other + // order in sem_interrupt_thread. + release_queue.head = release_queue.tail = NULL; + + while(count > 0) { + int delta = count; + if(sems[slot].count < 0) { + struct thread *t = thread_lookat_queue(&sems[slot].q); + + delta = min(count, t->sem_count); + t->sem_count -= delta; + if(t->sem_count <= 0) { + // release this thread + t = thread_dequeue(&sems[slot].q); + thread_enqueue(t, &release_queue); + t->state = THREAD_STATE_READY; + released_threads++; + t->sem_count = 0; + t->sem_deleted_retcode = 0; + } + } + + sems[slot].count += delta; + count -= delta; + } + RELEASE_SEM_LOCK(sems[slot]); + + // pull off any items in the release queue and put them in the run queue + if(released_threads > 0) { + struct thread *t; + GRAB_THREAD_LOCK(); + while((t = thread_dequeue(&release_queue)) != NULL) { + thread_enqueue_run_q(t); + } + if((flags & B_DO_NOT_RESCHEDULE) == 0) { + thread_resched(); + } + RELEASE_THREAD_LOCK(); + } + goto outnolock; + +err: + RELEASE_SEM_LOCK(sems[slot]); +outnolock: + int_restore_interrupts(state); + + return err; +} + +int get_sem_count(sem_id id, int32* thread_count) +{ + int slot; + int state; +// int count; + + if(sems_active == false) + return B_NO_MORE_SEMS; + if(id < 0) + return B_BAD_SEM_ID; + if (thread_count == NULL) + return ERR_INVALID_ARGS; + + slot = id % MAX_SEMS; + + state = int_disable_interrupts(); + GRAB_SEM_LOCK(sems[slot]); + + if(sems[slot].id != id) { + RELEASE_SEM_LOCK(sems[slot]); + int_restore_interrupts(state); + dprintf("sem_get_count: invalid sem_id %d\n", id); + return B_BAD_SEM_ID; + } + + *thread_count = sems[slot].count; + + RELEASE_SEM_LOCK(sems[slot]); + int_restore_interrupts(state); + + return B_NO_ERROR; +} + +int _get_sem_info(sem_id id, struct sem_info *info, size_t sz) +{ + int state; + int slot; + + if(sems_active == false) + return B_NO_MORE_SEMS; + if(id < 0) + return B_BAD_SEM_ID; + if (info == NULL) + return ERR_INVALID_ARGS; + + slot = id % MAX_SEMS; + + state = int_disable_interrupts(); + GRAB_SEM_LOCK(sems[slot]); + + if(sems[slot].id != id) { + RELEASE_SEM_LOCK(sems[slot]); + int_restore_interrupts(state); + dprintf("get_sem_info: invalid sem_id %d\n", id); + return B_BAD_SEM_ID; + } + + info->sem = sems[slot].id; + info->proc = sems[slot].owner; + strncpy(info->name, sems[slot].name, SYS_MAX_OS_NAME_LEN-1); + info->count = sems[slot].count; + info->latest_holder = sems[slot].q.head->id; // XXX not sure if this is correct + + RELEASE_SEM_LOCK(sems[slot]); + int_restore_interrupts(state); + + return B_NO_ERROR; +} + +int _get_next_sem_info(proc_id proc, uint32 *cookie, struct sem_info *info, size_t sz) +{ + int state; + int slot; + + if(sems_active == false) + return B_NO_MORE_SEMS; + + if (cookie == NULL) + return ERR_INVALID_ARGS; + if (proc < 0) + return ERR_INVALID_ARGS; // prevents sems[].owner == -1 >= means owned by a port + + if (*cookie == NULL) { + // return first found + slot = 0; + } else { + // start at index cookie, but check cookie against MAX_PORTS + slot = *cookie; + if (slot >= MAX_SEMS) + return B_BAD_SEM_ID; + } + // spinlock + state = int_disable_interrupts(); + GRAB_SEM_LIST_LOCK(); + + while (slot < MAX_SEMS) { + GRAB_SEM_LOCK(sems[slot]); + if (sems[slot].id != -1) + if (sems[slot].owner == proc) { + // found one! + info->sem = sems[slot].id; + info->proc = sems[slot].owner; + strncpy(info->name, sems[slot].name, SYS_MAX_OS_NAME_LEN-1); + info->count = sems[slot].count; + info->latest_holder = sems[slot].q.head->id; // XXX not sure if this is the latest holder, or the next holder... + + RELEASE_SEM_LOCK(sems[slot]); + slot++; + break; + } + RELEASE_SEM_LOCK(sems[slot]); + slot++; + } + RELEASE_SEM_LIST_LOCK(); + int_restore_interrupts(state); + + if (slot == MAX_SEMS) + return ERR_SEM_NOT_FOUND; + *cookie = slot; + return B_NO_ERROR; +} + +int set_sem_owner(sem_id id, proc_id proc) +{ + int state; + int slot; + + if(sems_active == false) + return B_NO_MORE_SEMS; + if(id < 0) + return B_BAD_SEM_ID; + if (proc < NULL) + return ERR_INVALID_ARGS; + + // XXX: todo check if proc exists +// if (proc_get_proc_struct(proc) == NULL) +// return B_BAD_SEM_ID; // proc_id doesn't exist right now + + slot = id % MAX_SEMS; + + state = int_disable_interrupts(); + GRAB_SEM_LOCK(sems[slot]); + + if(sems[slot].id != id) { + RELEASE_SEM_LOCK(sems[slot]); + int_restore_interrupts(state); + dprintf("set_sem_owner: invalid sem_id %d\n", id); + return B_BAD_SEM_ID; + } + + sems[slot].owner = proc; + + RELEASE_SEM_LOCK(sems[slot]); + int_restore_interrupts(state); + + return B_NO_ERROR; +} + +// Wake up a thread that's blocked on a semaphore +// this function must be entered with interrupts disabled and THREADLOCK held +int sem_interrupt_thread(struct thread *t) +{ +// struct thread *t1; + int slot; +// int state; + struct thread_queue wakeup_queue; + +// dprintf("sem_interrupt_thread: called on thread %p (%d), blocked on sem 0x%x\n", t, t->id, t->sem_blocking); + + if(t->state != THREAD_STATE_WAITING) + return ERR_INVALID_ARGS; + if(t->sem_blocking < 0) + return ERR_INVALID_ARGS; + if((t->sem_flags & B_CAN_INTERRUPT) == 0) + return ERR_SEM_NOT_INTERRUPTABLE; + + slot = t->sem_blocking % MAX_SEMS; + + GRAB_SEM_LOCK(sems[slot]); + + if(sems[slot].id != t->sem_blocking) { + panic("sem_interrupt_thread: thread 0x%x sez it's blocking on sem 0x%x, but that sem doesn't exist!\n", t->id, t->sem_blocking); + } + + wakeup_queue.head = wakeup_queue.tail = NULL; + if(remove_thread_from_sem(t, &sems[slot], &wakeup_queue, EINTR) == ERR_NOT_FOUND) + panic("sem_interrupt_thread: thread 0x%x not found in sem 0x%x's wait queue\n", t->id, t->sem_blocking); + + RELEASE_SEM_LOCK(sems[slot]); + + while((t = thread_dequeue(&wakeup_queue)) != NULL) { + thread_enqueue_run_q(t); + } + + return B_NO_ERROR; +} + +// forcibly removes a thread from a semaphores wait q. May have to wake up other threads in the +// process. All threads that need to be woken up are added to the passed in thread_queue. +// must be called with sem lock held +static int remove_thread_from_sem(struct thread *t, struct sem_entry *sem, struct thread_queue *queue, int sem_errcode) +{ + struct thread *t1; + + // remove the thread from the queue and place it in the supplied queue + t1 = thread_dequeue_id(&sem->q, t->id); + if(t != t1) + return ERR_NOT_FOUND; + sem->count += t->sem_acquire_count; + t->state = THREAD_STATE_READY; + t->sem_errcode = sem_errcode; + thread_enqueue(t, queue); + + // now see if more threads need to be woken up + while(sem->count > 0 && (t1 = thread_lookat_queue(&sem->q))) { + int delta = min(t->sem_count, sem->count); + + t->sem_count -= delta; + if(t->sem_count <= 0) { + t = thread_dequeue(&sem->q); + t->state = THREAD_STATE_READY; + thread_enqueue(t, queue); + } + sem->count -= delta; + } + return B_NO_ERROR; +} + +/* this function cycles through the sem table, deleting all the sems that are owned by + the passed proc_id */ +int sem_delete_owned_sems(proc_id owner) +{ + int state; + int i; + int count = 0; + + if (owner < 0) + return B_BAD_SEM_ID; + + state = int_disable_interrupts(); + GRAB_SEM_LIST_LOCK(); + + for(i=0; i= KERNEL_BASE && (addr)uname <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + rc = user_strncpy(name, uname, SYS_MAX_OS_NAME_LEN-1); + if(rc < 0) + return rc; + name[SYS_MAX_OS_NAME_LEN-1] = 0; + + return create_sem_etc(count, name, proc_get_current_proc_id()); + } else { + return create_sem_etc(count, NULL, proc_get_current_proc_id()); + } +} + +int user_delete_sem(sem_id id) +{ + return delete_sem(id); +} + +int user_delete_sem_etc(sem_id id, int return_code) +{ + return delete_sem_etc(id, return_code); +} + +int user_acquire_sem(sem_id id) +{ + return user_acquire_sem_etc(id, 1, 0, 0); +} + +int user_acquire_sem_etc(sem_id id, int count, int flags, bigtime_t timeout) +{ + flags = flags | B_CAN_INTERRUPT; + + return acquire_sem_etc(id, count, flags, timeout); +} + +int user_release_sem(sem_id id) +{ + return release_sem_etc(id, 1, 0); +} + +int user_release_sem_etc(sem_id id, int count, int flags) +{ + return release_sem_etc(id, count, flags); +} + +int user_get_sem_count(sem_id uid, int32* uthread_count) +{ + int32 thread_count; + int rc, rc2; + rc = get_sem_count(uid, &thread_count); + rc2 = user_memcpy(uthread_count, &thread_count, sizeof(int32)); + if(rc2 < 0) + return rc2; + return rc; +} + +int user_get_sem_info(sem_id uid, struct sem_info *uinfo, size_t sz) +{ + struct sem_info info; + int rc, rc2; + + if((addr)uinfo >= KERNEL_BASE && (addr)uinfo <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + rc = _get_sem_info(uid, &info, sz); + rc2 = user_memcpy(uinfo, &info, sz); + if(rc2 < 0) + return rc2; + return rc; +} + +int user_get_next_sem_info(proc_id uproc, uint32 *ucookie, struct sem_info *uinfo, size_t sz) +{ + struct sem_info info; + uint32 cookie; + int rc, rc2; + + if((addr)uinfo >= KERNEL_BASE && (addr)uinfo <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + rc2 = user_memcpy(&cookie, ucookie, sizeof(uint32)); + if(rc2 < 0) + return rc2; + rc = _get_next_sem_info(uproc, &cookie, &info, sz); + rc2 = user_memcpy(uinfo, &info, sz); + if(rc2 < 0) + return rc2; + rc2 = user_memcpy(ucookie, &cookie, sizeof(uint32)); + if(rc2 < 0) + return rc2; + return rc; +} + +int user_set_sem_owner(sem_id uid, proc_id uproc) +{ + return set_sem_owner(uid, uproc); +} diff --git a/src/kernel/core/smp.c b/src/kernel/core/smp.c new file mode 100644 index 0000000000..bf8ca150be --- /dev/null +++ b/src/kernel/core/smp.c @@ -0,0 +1,501 @@ +/* Functionality for symetrical multi-processors */ + +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +//#include + +#include + +#define MSG_POOL_SIZE (SMP_MAX_CPUS * 4) + +struct smp_msg { + struct smp_msg *next; + int message; + unsigned long data; + unsigned long data2; + unsigned long data3; + void *data_ptr; + int flags; + int ref_count; + volatile bool done; + unsigned int proc_bitmap; + int lock; +}; + +#define MAILBOX_LOCAL 1 +#define MAILBOX_BCAST 2 + +static spinlock_t boot_cpu_spin[SMP_MAX_CPUS] = { 0, }; + +static struct smp_msg *free_msgs = NULL; +static volatile int free_msg_count = 0; +static spinlock_t free_msg_spinlock = 0; + +static struct smp_msg *smp_msgs[SMP_MAX_CPUS] = { NULL, }; +static spinlock_t cpu_msg_spinlock[SMP_MAX_CPUS] = { 0, }; + +static struct smp_msg *smp_broadcast_msgs = NULL; +static spinlock_t broadcast_msg_spinlock = 0; + +static bool ici_enabled = false; + +static int smp_num_cpus = 1; + +static int smp_process_pending_ici(int curr_cpu); + +void acquire_spinlock(spinlock_t *lock) +{ + if(smp_num_cpus > 1) { + int curr_cpu = smp_get_current_cpu(); + if(int_is_interrupts_enabled()) + panic("acquire_spinlock: attempt to acquire lock %p with interrupts enabled\n", lock); + while(1) { + while(*lock != 0) + smp_process_pending_ici(curr_cpu); + if(atomic_set(lock, 1) == 0) + break; + } + } +} + +static void acquire_spinlock_nocheck(spinlock_t *lock) +{ + if(smp_num_cpus > 1) { + while(1) { + while(*lock != 0) + ; + if(atomic_set(lock, 1) == 0) + break; + } + } +} + +void release_spinlock(spinlock_t *lock) +{ + *lock = 0; +} + +// finds a free message and gets it +// NOTE: has side effect of disabling interrupts +// return value is interrupt state +static int find_free_message(struct smp_msg **msg) +{ + int state; + +// dprintf("find_free_message: entry\n"); + +retry: + while(free_msg_count <= 0) + ; + state = int_disable_interrupts(); + acquire_spinlock(&free_msg_spinlock); + + if(free_msg_count <= 0) { + // someone grabbed one while we were getting the lock, + // go back to waiting for it + release_spinlock(&free_msg_spinlock); + int_restore_interrupts(state); + goto retry; + } + + *msg = free_msgs; + free_msgs = (*msg)->next; + free_msg_count--; + + release_spinlock(&free_msg_spinlock); + +// dprintf("find_free_message: returning msg 0x%x\n", *msg); + + return state; +} + +static void return_free_message(struct smp_msg *msg) +{ +// dprintf("return_free_message: returning msg 0x%x\n", msg); + acquire_spinlock_nocheck(&free_msg_spinlock); + msg->next = free_msgs; + free_msgs = msg; + free_msg_count++; + release_spinlock(&free_msg_spinlock); +} + +static struct smp_msg *smp_check_for_message(int curr_cpu, int *source_mailbox) +{ + struct smp_msg *msg; + + acquire_spinlock_nocheck(&cpu_msg_spinlock[curr_cpu]); + msg = smp_msgs[curr_cpu]; + if(msg != NULL) { + smp_msgs[curr_cpu] = msg->next; + release_spinlock(&cpu_msg_spinlock[curr_cpu]); +// dprintf(" found msg 0x%x in cpu mailbox\n", msg); + *source_mailbox = MAILBOX_LOCAL; + } else { + // try getting one from the broadcast mailbox + + release_spinlock(&cpu_msg_spinlock[curr_cpu]); + acquire_spinlock_nocheck(&broadcast_msg_spinlock); + + msg = smp_broadcast_msgs; + while(msg != NULL) { + if(CHECK_BIT(msg->proc_bitmap, curr_cpu) != 0) { + // we have handled this one already + msg = msg->next; + continue; + } + + // mark it so we wont try to process this one again + msg->proc_bitmap = SET_BIT(msg->proc_bitmap, curr_cpu); + *source_mailbox = MAILBOX_BCAST; + break; + } + release_spinlock(&broadcast_msg_spinlock); +// dprintf(" found msg 0x%x in broadcast mailbox\n", msg); + } + return msg; +} + +static void smp_finish_message_processing(int curr_cpu, struct smp_msg *msg, int source_mailbox) +{ + int old_refcount; + + old_refcount = atomic_add(&msg->ref_count, -1); + if(old_refcount == 1) { + // we were the last one to decrement the ref_count + // it's our job to remove it from the list & possibly clean it up + struct smp_msg **mbox = NULL; + spinlock_t *spinlock = NULL; + + // clean up the message from one of the mailboxes + switch(source_mailbox) { + case MAILBOX_BCAST: + mbox = &smp_broadcast_msgs; + spinlock = &broadcast_msg_spinlock; + break; + case MAILBOX_LOCAL: + mbox = &smp_msgs[curr_cpu]; + spinlock = &cpu_msg_spinlock[curr_cpu]; + break; + } + + acquire_spinlock_nocheck(spinlock); + +// dprintf("cleaning up message 0x%x\n", msg); + + if(msg == *mbox) { + (*mbox) = msg->next; + } else { + // we need to walk to find the message in the list. + // we can't use any data found when previously walking through + // the list, since the list may have changed. But, we are guaranteed + // to at least have msg in it. + struct smp_msg *last = NULL; + struct smp_msg *msg1; + + msg1 = *mbox; + while(msg1 != NULL && msg1 != msg) { + last = msg1; + msg1 = msg1->next; + } + + // by definition, last must be something + if(msg1 == msg && last != NULL) { + last->next = msg->next; + } else { + dprintf("last == NULL or msg != msg1!!!\n"); + } + } + + release_spinlock(spinlock); + + if(msg->data_ptr != NULL) + kfree(msg->data_ptr); + + if(msg->flags == SMP_MSG_FLAG_SYNC) { + msg->done = true; + // the caller cpu should now free the message + } else { + // in the !SYNC case, we get to free the message + return_free_message(msg); + } + } +} + +static int smp_process_pending_ici(int curr_cpu) +{ + struct smp_msg *msg; + bool halt = false; + int source_mailbox = 0; + int retval = INT_NO_RESCHEDULE; + + msg = smp_check_for_message(curr_cpu, &source_mailbox); + if(msg == NULL) + return retval; + +// dprintf(" message = %d\n", msg->message); + switch(msg->message) { + case SMP_MSG_INVL_PAGE_RANGE: + arch_cpu_invalidate_TLB_range((addr)msg->data, (addr)msg->data2); + break; + case SMP_MSG_INVL_PAGE_LIST: + arch_cpu_invalidate_TLB_list((addr *)msg->data, (int)msg->data2); + break; + case SMP_MSG_GLOBAL_INVL_PAGE: + arch_cpu_global_TLB_invalidate(); + break; + case SMP_MSG_RESCHEDULE: + retval = INT_RESCHEDULE; + break; + case SMP_MSG_CPU_HALT: + halt = true; + dprintf("cpu %d halted!\n", curr_cpu); + break; + case SMP_MSG_1: + default: + dprintf("smp_intercpu_int_handler: got unknown message %d\n", msg->message); + } + + // finish dealing with this message, possibly removing it from the list + smp_finish_message_processing(curr_cpu, msg, source_mailbox); + + // special case for the halt message + // we otherwise wouldn't have gotten the opportunity to clean up + if(halt) { + int_disable_interrupts(); + for(;;); + } + + return retval; +} + +int smp_intercpu_int_handler(void) +{ + int retval; + int curr_cpu = smp_get_current_cpu(); + +// dprintf("smp_intercpu_int_handler: entry on cpu %d\n", curr_cpu); + + retval = smp_process_pending_ici(curr_cpu); + +// dprintf("smp_intercpu_int_handler: done\n"); + + return retval; +} + +void smp_send_ici(int target_cpu, int message, unsigned long data, unsigned long data2, unsigned long data3, void *data_ptr, int flags) +{ + struct smp_msg *msg; + +// dprintf("smp_send_ici: target 0x%x, mess 0x%x, data 0x%x, data2 0x%x, data3 0x%x, ptr 0x%x, flags 0x%x\n", +// target_cpu, message, data, data2, data3, data_ptr, flags); + + if(ici_enabled) { + int state; + int curr_cpu; + + // find_free_message leaves interrupts disabled + state = find_free_message(&msg); + + curr_cpu = smp_get_current_cpu(); + if(target_cpu == curr_cpu) { + return_free_message(msg); + int_restore_interrupts(state); + return; // nope, cant do that + } + + // set up the message + msg->message = message; + msg->data = data; + msg->data = data2; + msg->data = data3; + msg->data_ptr = data_ptr; + msg->ref_count = 1; + msg->flags = flags; + msg->done = false; + + // stick it in the appropriate cpu's mailbox + acquire_spinlock_nocheck(&cpu_msg_spinlock[target_cpu]); + msg->next = smp_msgs[target_cpu]; + smp_msgs[target_cpu] = msg; + release_spinlock(&cpu_msg_spinlock[target_cpu]); + + arch_smp_send_ici(target_cpu); + + if(flags == SMP_MSG_FLAG_SYNC) { + // wait for the other cpu to finish processing it + // the interrupt handler will ref count it to <0 + // if the message is sync after it has removed it from the mailbox + while(msg->done == false) + smp_process_pending_ici(curr_cpu); + // for SYNC messages, it's our responsibility to put it + // back into the free list + return_free_message(msg); + } + + int_restore_interrupts(state); + } +} + +void smp_send_broadcast_ici(int message, unsigned long data, unsigned long data2, unsigned long data3, void *data_ptr, int flags) +{ + struct smp_msg *msg; + +// dprintf("smp_send_broadcast_ici: cpu %d mess 0x%x, data 0x%x, data2 0x%x, data3 0x%x, ptr 0x%x, flags 0x%x\n", +// smp_get_current_cpu(), message, data, data2, data3, data_ptr, flags); + + if(ici_enabled) { + int state; + int curr_cpu; + + // find_free_message leaves interrupts disabled + state = find_free_message(&msg); + + curr_cpu = smp_get_current_cpu(); + + msg->message = message; + msg->data = data; + msg->data2 = data2; + msg->data3 = data3; + msg->data_ptr = data_ptr; + msg->ref_count = smp_num_cpus - 1; + msg->flags = flags; + msg->proc_bitmap = SET_BIT(0, curr_cpu); + msg->done = false; + +// dprintf("smp_send_broadcast_ici%d: inserting msg 0x%x into broadcast mbox\n", smp_get_current_cpu(), msg); + + // stick it in the appropriate cpu's mailbox + acquire_spinlock_nocheck(&broadcast_msg_spinlock); + msg->next = smp_broadcast_msgs; + smp_broadcast_msgs = msg; + release_spinlock(&broadcast_msg_spinlock); + + arch_smp_send_broadcast_ici(); + +// dprintf("smp_send_broadcast_ici: sent interrupt\n"); + + if(flags == SMP_MSG_FLAG_SYNC) { + // wait for the other cpus to finish processing it + // the interrupt handler will ref count it to <0 + // if the message is sync after it has removed it from the mailbox +// dprintf("smp_send_broadcast_ici: waiting for ack\n"); + while(msg->done == false) + smp_process_pending_ici(curr_cpu); +// dprintf("smp_send_broadcast_ici: returning message to free list\n"); + // for SYNC messages, it's our responsibility to put it + // back into the free list + return_free_message(msg); + } + + int_restore_interrupts(state); + } +// dprintf("smp_send_broadcast_ici: done\n"); +} + +int smp_trap_non_boot_cpus(kernel_args *ka, int cpu) +{ + if(cpu > 0) { + boot_cpu_spin[cpu] = 1; + acquire_spinlock(&boot_cpu_spin[cpu]); + return 1; + } else { + return 0; + } +} + +void smp_wake_up_all_non_boot_cpus() +{ + int i; + for(i=1; i < smp_num_cpus; i++) { + release_spinlock(&boot_cpu_spin[i]); + } +} + +void smp_wait_for_ap_cpus(kernel_args *ka) +{ + unsigned int i; + int retry; + do { + retry = 0; + for(i=1; i < ka->num_cpus; i++) { + if(boot_cpu_spin[i] != 1) + retry = 1; + } + } while(retry == 1); +} + +int smp_init(kernel_args *ka) +{ + struct smp_msg *msg; + int i; + + dprintf("smp_init: entry\n"); + + if(ka->num_cpus > 1) { + free_msgs = NULL; + free_msg_count = 0; + for(i=0; inext = free_msgs; + free_msgs = msg; + free_msg_count++; + } + smp_num_cpus = ka->num_cpus; + } + dprintf("smp_init: calling arch_smp_init\n"); + return arch_smp_init(ka); +} + +void smp_set_num_cpus(int num_cpus) +{ + smp_num_cpus = num_cpus; +} + +int smp_get_num_cpus() +{ + return smp_num_cpus; +} + +int smp_get_current_cpu(void) +{ + struct thread *t = thread_get_current_thread(); + if(t) + return t->cpu->info.cpu_num; + else + return 0; +} + +int smp_enable_ici() +{ + if(smp_num_cpus > 1) // dont actually do it if we only have one cpu + ici_enabled = true; + return B_NO_ERROR; +} + +int smp_disable_ici() +{ + ici_enabled = false; + return B_NO_ERROR; +} diff --git a/src/kernel/core/syscalls.c b/src/kernel/core/syscalls.c new file mode 100644 index 0000000000..987b350ad8 --- /dev/null +++ b/src/kernel/core/syscalls.c @@ -0,0 +1,301 @@ +/* Big case statment for dispatching syscalls */ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define INT32TOINT64(x, y) ((int64)(x) | ((int64)(y) << 32)) + +#define arg0 (((uint32 *)arg_buffer)[0]) +#define arg1 (((uint32 *)arg_buffer)[1]) +#define arg2 (((uint32 *)arg_buffer)[2]) +#define arg3 (((uint32 *)arg_buffer)[3]) +#define arg4 (((uint32 *)arg_buffer)[4]) +#define arg5 (((uint32 *)arg_buffer)[5]) +#define arg6 (((uint32 *)arg_buffer)[6]) +#define arg7 (((uint32 *)arg_buffer)[7]) +#define arg8 (((uint32 *)arg_buffer)[8]) +#define arg9 (((uint32 *)arg_buffer)[9]) +#define arg10 (((uint32 *)arg_buffer)[10]) +#define arg11 (((uint32 *)arg_buffer)[11]) +#define arg12 (((uint32 *)arg_buffer)[12]) +#define arg13 (((uint32 *)arg_buffer)[13]) +#define arg14 (((uint32 *)arg_buffer)[14]) +#define arg15 (((uint32 *)arg_buffer)[15]) + +int syscall_dispatcher(unsigned long call_num, void *arg_buffer, uint64 *call_ret) +{ +// dprintf("syscall_dispatcher: thread 0x%x call 0x%x, arg0 0x%x, arg1 0x%x arg2 0x%x arg3 0x%x arg4 0x%x\n", +// thread_get_current_thread_id(), call_num, arg0, arg1, arg2, arg3, arg4); + + switch(call_num) { + case SYSCALL_NULL: + *call_ret = 0; + break; + case SYSCALL_MOUNT: + *call_ret = user_mount((const char *)arg0, (const char *)arg1, (const char *)arg2, (void *)arg3); + break; + case SYSCALL_UNMOUNT: + *call_ret = user_unmount((const char *)arg0); + break; + case SYSCALL_SYNC: + *call_ret = user_sync(); + break; + case SYSCALL_OPEN: + *call_ret = user_open((const char *)arg0, (stream_type)arg1, (int)arg2); + break; + case SYSCALL_CLOSE: + *call_ret = user_close((int)arg0); + break; + case SYSCALL_FSYNC: + *call_ret = user_fsync((int)arg0); + break; + case SYSCALL_READ: + *call_ret = user_read((int)arg0, (void *)arg1, (off_t)INT32TOINT64(arg2, arg3), (ssize_t)arg4); + break; + case SYSCALL_WRITE: + *call_ret = user_write((int)arg0, (const void *)arg1, (off_t)INT32TOINT64(arg2, arg3), (ssize_t)arg4); + break; + case SYSCALL_SEEK: + *call_ret = user_seek((int)arg0, (off_t)INT32TOINT64(arg1, arg2), (int)arg3); + break; + case SYSCALL_IOCTL: + // ToDo: this is not correct; IOCPARM is only valid for calls to the networking stack + // The socket/fd_ioctl should do this, but I think we have to pass 0 here -- axeld. + // currently ignoring arg3 (which is supposed to be the length, but currently + // always 0 - in libc/system/wrappers.c + *call_ret = user_ioctl((int)arg0, (ulong)arg1, (void *)arg2, (size_t)IOCPARM_LEN((ulong)arg1)); + break; + case SYSCALL_CREATE: + *call_ret = user_create((const char *)arg0, (stream_type)arg1); + break; + case SYSCALL_UNLINK: + *call_ret = user_unlink((const char *)arg0); + break; + case SYSCALL_RENAME: + *call_ret = user_rename((const char *)arg0, (const char *)arg1); + break; + case SYSCALL_RSTAT: + *call_ret = user_rstat((const char *)arg0, (struct stat *)arg1); + break; + case SYSCALL_FSTAT: + *call_ret = user_fstat((int)arg0, (struct stat*)arg1); + break; + case SYSCALL_WSTAT: + *call_ret = user_wstat((const char *)arg0, (struct stat *)arg1, (int)arg2); + break; + case SYSCALL_SYSTEM_TIME: + *call_ret = system_time(); + break; + case SYSCALL_SNOOZE: + *call_ret = user_thread_snooze((bigtime_t)INT32TOINT64(arg0, arg1)); + break; + case SYSCALL_SEM_CREATE: + *call_ret = user_create_sem((int)arg0, (const char *)arg1); + break; + case SYSCALL_SEM_DELETE: + *call_ret = user_delete_sem((sem_id)arg0); + break; + case SYSCALL_SEM_ACQUIRE: + *call_ret = user_acquire_sem_etc((sem_id)arg0, 1, 0, 0); + break; + case SYSCALL_SEM_ACQUIRE_ETC: + *call_ret = user_acquire_sem_etc((sem_id)arg0, (int)arg1, (int)arg2, (bigtime_t)INT32TOINT64(arg3, arg4)); + break; + case SYSCALL_SEM_RELEASE: + *call_ret = user_release_sem((sem_id)arg0); + break; + case SYSCALL_SEM_RELEASE_ETC: + *call_ret = user_release_sem_etc((sem_id)arg0, (int)arg1, (int)arg2); + break; + case SYSCALL_GET_CURRENT_THREAD_ID: + *call_ret = thread_get_current_thread_id(); + break; + case SYSCALL_EXIT_THREAD: + thread_exit((int)arg0); + *call_ret = 0; + break; + case SYSCALL_PROC_CREATE_PROC: + *call_ret = user_proc_create_proc((const char *)arg0, (const char *)arg1, (char **)arg2, (int )arg3, (int)arg4); + break; + case SYSCALL_THREAD_WAIT_ON_THREAD: + *call_ret = user_thread_wait_on_thread((thread_id)arg0, (int *)arg1); + break; + case SYSCALL_PROC_WAIT_ON_PROC: + *call_ret = user_proc_wait_on_proc((proc_id)arg0, (int *)arg1); + break; + case SYSCALL_VM_CREATE_ANONYMOUS_REGION: + *call_ret = user_vm_create_anonymous_region( + (char *)arg0, (void **)arg1, (int)arg2, + (addr)arg3, (int)arg4, (int)arg5); + break; + case SYSCALL_VM_CLONE_REGION: + *call_ret = user_vm_clone_region( + (char *)arg0, (void **)arg1, (int)arg2, + (region_id)arg3, (int)arg4, (int)arg5); + break; + case SYSCALL_VM_MAP_FILE: + *call_ret = user_vm_map_file( + (char *)arg0, (void **)arg1, (int)arg2, + (addr)arg3, (int)arg4, (int)arg5, (const char *)arg6, + (off_t)INT32TOINT64(arg7, arg8)); + break; + case SYSCALL_VM_FIND_REGION_BY_NAME: + *call_ret = find_region_by_name((const char *)arg0); + break; + case SYSCALL_VM_DELETE_REGION: + *call_ret = vm_delete_region(vm_get_current_user_aspace_id(), (region_id)arg0); + break; + case SYSCALL_VM_GET_REGION_INFO: + *call_ret = user_vm_get_region_info((region_id)arg0, (vm_region_info *)arg1); + break; + case SYSCALL_SPAWN_THREAD: + *call_ret = user_thread_create_user_thread((addr)arg0, thread_get_current_thread()->proc->id, + (const char*)arg1, (int)arg2, (void *)arg3); + break; + case SYSCALL_KILL_THREAD: + *call_ret = thread_kill_thread((thread_id)arg0); + break; + case SYSCALL_SUSPEND_THREAD: + *call_ret = thread_suspend_thread((thread_id)arg0); + break; + case SYSCALL_RESUME_THREAD: + *call_ret = thread_resume_thread((thread_id)arg0); + break; + case SYSCALL_PROC_KILL_PROC: + *call_ret = proc_kill_proc((proc_id)arg0); + break; + case SYSCALL_GET_CURRENT_PROC_ID: + *call_ret = proc_get_current_proc_id(); + break; + case SYSCALL_GETCWD: + *call_ret = user_getcwd((char*)arg0, (size_t)arg1); + break; + case SYSCALL_SETCWD: + *call_ret = user_setcwd((const char*)arg0); + break; + case SYSCALL_PORT_CREATE: + *call_ret = user_create_port((int32)arg0, (const char *)arg1); + break; + case SYSCALL_PORT_CLOSE: + *call_ret = user_close_port((port_id)arg0); + break; + case SYSCALL_PORT_DELETE: + *call_ret = user_delete_port((port_id)arg0); + break; + case SYSCALL_PORT_FIND: + *call_ret = user_find_port((const char *)arg0); + break; + case SYSCALL_PORT_GET_INFO: + *call_ret = user_get_port_info((port_id)arg0, (struct port_info *)arg1); + break; + case SYSCALL_PORT_GET_NEXT_PORT_INFO: + *call_ret = user_get_next_port_info((port_id)arg0, (uint32 *)arg1, (struct port_info *)arg2); + break; + case SYSCALL_PORT_BUFFER_SIZE: + *call_ret = user_port_buffer_size_etc((port_id)arg0, B_CAN_INTERRUPT, 0); + break; + case SYSCALL_PORT_BUFFER_SIZE_ETC: + *call_ret = user_port_buffer_size_etc((port_id)arg0, (uint32)arg1 | B_CAN_INTERRUPT, (bigtime_t)INT32TOINT64(arg2, arg3)); + break; + case SYSCALL_PORT_COUNT: + *call_ret = user_port_count((port_id)arg0); + break; + case SYSCALL_PORT_READ: + *call_ret = user_read_port_etc((port_id)arg0, (int32*)arg1, (void*)arg2, (size_t)arg3, B_CAN_INTERRUPT, 0); + break; + case SYSCALL_PORT_READ_ETC: + *call_ret = user_read_port_etc((port_id)arg0, (int32*)arg1, (void*)arg2, (size_t)arg3, (uint32)arg4 | B_CAN_INTERRUPT, (bigtime_t)INT32TOINT64(arg5, arg6)); + break; + case SYSCALL_PORT_SET_OWNER: + *call_ret = user_set_port_owner((port_id)arg0, (proc_id)arg1); + break; + case SYSCALL_PORT_WRITE: + *call_ret = user_write_port_etc((port_id)arg0, (int32)arg1, (void *)arg2, (size_t)arg3, B_CAN_INTERRUPT, 0); + break; + case SYSCALL_PORT_WRITE_ETC: + *call_ret = user_write_port_etc((port_id)arg0, (int32)arg1, (void *)arg2, (size_t)arg3, (uint32)arg4 | B_CAN_INTERRUPT, (bigtime_t)INT32TOINT64(arg5, arg6)); + break; + case SYSCALL_SEM_GET_COUNT: + *call_ret = user_get_sem_count((sem_id)arg0, (int32*)arg1); + break; + case SYSCALL_SEM_GET_SEM_INFO: + *call_ret = user_get_sem_info((sem_id)arg0, (struct sem_info *)arg1, (size_t)arg2); + break; + case SYSCALL_SEM_GET_NEXT_SEM_INFO: + *call_ret = user_get_next_sem_info((proc_id)arg0, (uint32 *)arg1, (struct sem_info *)arg2, + (size_t)arg3); + break; + case SYSCALL_SEM_SET_SEM_OWNER: + *call_ret = user_set_sem_owner((sem_id)arg0, (proc_id)arg1); + break; + case SYSCALL_FDDUP: + *call_ret = user_dup(arg0); + break; + case SYSCALL_FDDUP2: + *call_ret = user_dup2(arg0, arg1); + break; + case SYSCALL_GET_PROC_TABLE: + *call_ret = user_proc_get_table((struct proc_info *)arg0, (size_t)arg1); + break; + case SYSCALL_GETRLIMIT: + *call_ret = user_getrlimit((int)arg0, (struct rlimit *)arg1); + break; + case SYSCALL_SETRLIMIT: + *call_ret = user_setrlimit((int)arg0, (const struct rlimit *)arg1); + break; + case SYSCALL_ATOMIC_ADD: + *call_ret = user_atomic_add((int *)arg0, (int)arg1); + break; + case SYSCALL_ATOMIC_AND: + *call_ret = user_atomic_and((int *)arg0, (int)arg1); + break; + case SYSCALL_ATOMIC_OR: + *call_ret = user_atomic_or((int *)arg0, (int)arg1); + break; + case SYSCALL_ATOMIC_SET: + *call_ret = user_atomic_set((int *)arg0, (int)arg1); + break; + case SYSCALL_TEST_AND_SET: + *call_ret = user_test_and_set((int *)arg0, (int)arg1, (int)arg2); + break; + case SYSCALL_SYSCTL: + *call_ret = user_sysctl((int *)arg0, (uint)arg1, (void *)arg2, + (size_t *)arg3, (void *)arg4, + (size_t)arg5); + break; + case SYSCALL_SOCKET: + *call_ret = socket((int)arg0, (int)arg1, (int)arg2, false); + break; + case SYSCALL_GETDTABLESIZE: + // ToDo: the correct way would be to lock the io_context + // or just call vfs_getrlimit() + *call_ret = (get_current_io_context(false))->table_size; + break; + default: + *call_ret = -1; + } + +// dprintf("syscall_dispatcher: done with syscall 0x%x\n", call_num); + + return INT_RESCHEDULE; +} diff --git a/src/kernel/core/sysctl.c b/src/kernel/core/sysctl.c new file mode 100644 index 0000000000..eaeb0ecbb5 --- /dev/null +++ b/src/kernel/core/sysctl.c @@ -0,0 +1,253 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Not sure where to put this definition yet (sys/param.h?), + * so just add it here + * XXX - horrible hack! + */ +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 256 /* max hostname size */ +#endif + +/* This is the place we store a few of the "global variables" that the OS + * needs. + */ +char hostname[MAXHOSTNAMELEN] = "openbeos\0"; +int hostnamelen = 9; +char domainname[MAXHOSTNAMELEN] = "rocks.my.world.com\0"; +int domainnamelen = 19; + +/* These really don't belong here, but just for the moment until we figure out where + * these should live... + */ + +char ostype[] = "OpenBeOS"; +char osrelease[] = "0.01"; +char osversion[] = "alpha"; +char version[] = "0.0.1"; +char kernel[] = "DEV"; + +char machine[] = "Intel"; +char model[] = "MODEL"; + +int sysctl(int *name, uint namelen, void *oldp, size_t *oldlenp, + void *newp, size_t newlen) +{ + sysctlfn *fn = NULL; + int error = 0; + + switch (name[0]) { + case CTL_KERN: + fn = kern_sysctl; + break; + case CTL_HW: + fn = hw_sysctl; + break; + default: + dprintf("sysctl: no suppport added yet for %d\n", name[0]); + return EOPNOTSUPP; + } + error = (fn)(name + 1, namelen - 1, oldp, oldlenp, newp, newlen); + + return B_NO_ERROR; + +} + +int kern_sysctl(int *name, uint namelen, void *oldp, size_t *oldlenp, + void *newp, size_t newlen) +{ + int error = 0; +/* This will need to be uncommented when the definitions above have been removed and + * we have these defined elsewhere... + extern char ostype[], osrelease[], osversion[], version[]; + */ + switch (name[0]) { + case KERN_OSTYPE: + return sysctl_rdstring(oldp, oldlenp, newp, ostype); + case KERN_OSRELEASE: + return sysctl_rdstring(oldp, oldlenp, newp, osrelease); + case KERN_OSVERSION: + return sysctl_rdstring(oldp, oldlenp, newp, osversion); + case KERN_HOSTNAME: + error = sysctl_tstring(oldp, oldlenp, newp, newlen, + hostname, sizeof(hostname)); + if (newp && !error) + hostnamelen = newlen; + return (error); + case KERN_DOMAINNAME: + error = sysctl_tstring(oldp, oldlenp, newp, newlen, + domainname, sizeof(domainname)); + if (newp && !error) + domainnamelen = newlen; + return (error); + case KERN_VERSION: + return sysctl_rdstring(oldp, oldlenp, newp, kernel); + default: + return EOPNOTSUPP; + } + /* If we get here we're in trouble... */ +} + +int hw_sysctl(int *name, uint namelen, void *oldp, size_t *oldlenp, + void *newp, size_t newlen) +{ +/* This will need to be uncommented when the definitions above have been removed and + * we have these defined elsewhere... + extern char machine[], model[]; + */ + + switch (name[0]) { + case HW_MACHINE: + return sysctl_rdstring(oldp, oldlenp, newp, machine); + case HW_MODEL: + return sysctl_rdstring(oldp, oldlenp, newp, model); + default: + return EOPNOTSUPP; + } + /* If we get here we're in trouble... */ +} + +int sysctl_int (void *oldp, size_t *oldlenp, void *newp, size_t newlen, + int *valp) +{ + if (oldp && *oldlenp < sizeof(int)) + return ENOMEM; + if (newp && newlen != sizeof(int)) + return EINVAL; + *oldlenp = sizeof(int); + if (oldp) + *(int*)oldp = *valp; + if (newp) + *valp = *(int*)newp; + return 0; +} + +int sysctl_rdint (void *oldp, size_t *oldlenp, void *newp, int val) +{ + if (oldp && *oldlenp < sizeof(int)) + return ENOMEM; + if (newp) + return EPERM; + *oldlenp = sizeof(int); + if (oldp) + *(int*)oldp = val; + return 0; +} + +/* Copy string, truncating if required */ +int sysctl_tstring(void *oldp, size_t *oldlenp, void *newp, size_t newlen, + char *str, int maxlen) +{ + return sysctl__string(oldp, oldlenp, newp, newlen, str, maxlen, 1); +} + +int sysctl__string(void *oldp, size_t *oldlenp, void *newp, size_t newlen, + char *str, int maxlen, int trunc) +{ + int len = strlen(str) + 1; + int c; + + if (oldp && *oldlenp < len) { + if (trunc == 0 || *oldlenp == 0) + return ENOMEM; + } + if (newp && newlen >= maxlen) + return EINVAL; + if (oldp) { + if (trunc && *oldlenp < len) { + /* need to truncate */ + c = str[*oldlenp - 1]; + str[*oldlenp - 1] = '\0'; + memcpy(oldp, str, *oldlenp); + str[*oldlenp - 1] = c; + } else { + /* just copy */ + *oldlenp = len; + memcpy(oldp, str, len); + } + } + if (newp) { + memcpy(str, newp, newlen); + str[newlen] = 0; + } + return 0; +} + +int sysctl_rdstring(void *oldp, size_t *oldlenp, void *newp, char *str) +{ + int len = strlen(str) + 1; + if (oldp && *oldlenp < len) + return ENOMEM; + if (newp) + return EPERM; + *oldlenp = len; + if (oldp) + memcpy(oldp, str, len); + return 0; +} + +int user_sysctl(int *name, uint namelen, void *oldp, size_t *oldlenp, + void *newp, size_t newlen) +{ + void *a1 = NULL, *a2 = NULL; + int *nam = NULL, rc; + size_t olen = *oldlenp, *ov=NULL; + + if (namelen < 2 || namelen > CTL_MAXNAME) + return EINVAL; + + if (name && namelen > 0) { + nam = (int*)kmalloc(namelen * sizeof(int)); + if (!nam) + return ENOMEM; + user_memcpy(nam, name, namelen * sizeof(int)); + } + if (oldp && oldlenp) { + a1 = kmalloc(olen); + user_memcpy(a1, oldp, olen); + } + if (oldlenp) { + ov = (size_t*)kmalloc(sizeof(oldlenp)); + user_memcpy(ov, oldlenp, sizeof(oldlenp)); + } + if (newp && newlen > 0) { + a2 = kmalloc(newlen); + user_memcpy(a2, newp, newlen); + } + + rc = sysctl(nam, namelen, a1, ov, a2, newlen); + + if (nam) + kfree(nam); + + if (rc != 0) + goto bailout; + + /* We don't need to copy back the name settings as they won't have changed. */ + if (oldp && *ov > 0) { + memcpy(oldp, a1, *ov); + memcpy(oldlenp, ov, sizeof(oldlenp)); + } + if (newp && newlen > 0) { + /* We passed namelen thru so don't worry about updating it here... */ + memcpy(newp, a2, newlen); + } + + +bailout: + if (a1) + kfree(a1); + if (a2) + kfree(a2); + if (ov) + kfree(ov); + + return rc; +} diff --git a/src/kernel/core/thread.c b/src/kernel/core/thread.c new file mode 100644 index 0000000000..8f9c1d5d56 --- /dev/null +++ b/src/kernel/core/thread.c @@ -0,0 +1,2086 @@ +/* Threading and process information */ + +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct proc_key { + proc_id id; +}; + +struct thread_key { + thread_id id; +}; + +struct proc_arg { + char *path; + char **args; + unsigned int argc; +}; + +static struct proc *create_proc_struct(const char *name, bool kernel); +static int proc_struct_compare(void *_p, const void *_key); +static unsigned int proc_struct_hash(void *_p, const void *_key, unsigned int range); + +// global +spinlock_t thread_spinlock = 0; + +// proc list +static void *proc_hash = NULL; +static struct proc *kernel_proc = NULL; +static proc_id next_proc_id = 0; +static spinlock_t proc_spinlock = 0; + // NOTE: PROC lock can be held over a THREAD lock acquisition, + // but not the other way (to avoid deadlock) +#define GRAB_PROC_LOCK() acquire_spinlock(&proc_spinlock) +#define RELEASE_PROC_LOCK() release_spinlock(&proc_spinlock) + +// thread list +static struct thread *idle_threads[MAX_BOOT_CPUS]; +static void *thread_hash = NULL; +static thread_id next_thread_id = 0; + +static sem_id snooze_sem = -1; + +// death stacks - used temporarily as a thread cleans itself up +struct death_stack { + region_id rid; + addr address; + bool in_use; +}; +static struct death_stack *death_stacks; +static unsigned int num_death_stacks; +static unsigned int volatile death_stack_bitmap; +static sem_id death_stack_sem; + +// thread queues +static struct thread_queue run_q[THREAD_NUM_PRIORITY_LEVELS] = { { NULL, NULL }, }; +static struct thread_queue dead_q; + +static int _rand(void); +static void thread_entry(void); +static struct thread *thread_get_thread_struct_locked(thread_id id); +/* XXX - not currently used, so commented out +static struct proc *proc_get_proc_struct(proc_id id); + */ +static struct proc *proc_get_proc_struct_locked(proc_id id); +static void thread_kthread_exit(void); +static void deliver_signal(struct thread *t, int signal); + +// insert a thread onto the tail of a queue +void thread_enqueue(struct thread *t, struct thread_queue *q) +{ + t->q_next = NULL; + if(q->head == NULL) { + q->head = t; + q->tail = t; + } else { + q->tail->q_next = t; + q->tail = t; + } +} + +struct thread *thread_lookat_queue(struct thread_queue *q) +{ + return q->head; +} + +struct thread *thread_dequeue(struct thread_queue *q) +{ + struct thread *t; + + t = q->head; + if(t != NULL) { + q->head = t->q_next; + if(q->tail == t) + q->tail = NULL; + } + return t; +} + +struct thread *thread_dequeue_id(struct thread_queue *q, thread_id thr_id) +{ + struct thread *t; + struct thread *last = NULL; + + t = q->head; + while(t != NULL) { + if(t->id == thr_id) { + if(last == NULL) { + q->head = t->q_next; + } else { + last->q_next = t->q_next; + } + if(q->tail == t) + q->tail = last; + break; + } + last = t; + t = t->q_next; + } + return t; +} + +struct thread *thread_lookat_run_q(int priority) +{ + return thread_lookat_queue(&run_q[priority]); +} + +void thread_enqueue_run_q(struct thread *t) +{ + // these shouldn't exist + if(t->priority > THREAD_MAX_PRIORITY) + t->priority = THREAD_MAX_PRIORITY; + if(t->priority < 0) + t->priority = 0; + + thread_enqueue(t, &run_q[t->priority]); +} + +struct thread *thread_dequeue_run_q(int priority) +{ + return thread_dequeue(&run_q[priority]); +} + +static void insert_thread_into_proc(struct proc *p, struct thread *t) +{ + t->proc_next = p->thread_list; + p->thread_list = t; + p->num_threads++; + if(p->num_threads == 1) { + // this was the first thread + p->main_thread = t; + } + t->proc = p; +} + +static void remove_thread_from_proc(struct proc *p, struct thread *t) +{ + struct thread *temp, *last = NULL; + + for(temp = p->thread_list; temp != NULL; temp = temp->proc_next) { + if(temp == t) { + if(last == NULL) { + p->thread_list = temp->proc_next; + } else { + last->proc_next = temp->proc_next; + } + p->num_threads--; + break; + } + last = temp; + } +} + +static int thread_struct_compare(void *_t, const void *_key) +{ + struct thread *t = _t; + const struct thread_key *key = _key; + + if(t->id == key->id) return 0; + else return 1; +} + +// Frees the argument list +// Parameters +// args argument list. +// args number of arguments + +static void free_arg_list(char **args, int argc) +{ + int cnt = argc; + + if(args != NULL) { + for(cnt = 0; cnt < argc; cnt++){ + kfree(args[cnt]); + } + + kfree(args); + } +} + +// Copy argument list from userspace to kernel space +// Parameters +// args userspace parameters +// argc number of parameters +// kargs usespace parameters +// return < 0 on error and **kargs = NULL + +static int user_copy_arg_list(char **args, int argc, char ***kargs) +{ + char **largs; + int err; + int cnt; + char *source; + char buf[SYS_THREAD_ARG_LENGTH_MAX]; + + *kargs = NULL; + + if((addr)args >= KERNEL_BASE && (addr)args <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + largs = (char **)kmalloc((argc + 1) * sizeof(char *)); + if(largs == NULL){ + return ERR_NO_MEMORY; + } + + // scan all parameters and copy to kernel space + + for(cnt = 0; cnt < argc; cnt++) { + err = user_memcpy(&source, &(args[cnt]), sizeof(char *)); + if(err < 0) + goto error; + + if((addr)source >= KERNEL_BASE && (addr)source <= KERNEL_TOP){ + err = ERR_VM_BAD_USER_MEMORY; + goto error; + } + + err = user_strncpy(buf,source, SYS_THREAD_ARG_LENGTH_MAX - 1); + if(err < 0) + goto error; + buf[SYS_THREAD_ARG_LENGTH_MAX - 1] = 0; + + largs[cnt] = (char *)kstrdup(buf); + if(largs[cnt] == NULL){ + err = ERR_NO_MEMORY; + goto error; + } + } + + largs[argc] = NULL; + + *kargs = largs; + return B_NO_ERROR; + +error: + free_arg_list(largs,cnt); + dprintf("user_copy_arg_list failed %d \n",err); + return err; +} + +static unsigned int thread_struct_hash(void *_t, const void *_key, unsigned int range) +{ + struct thread *t = _t; + const struct thread_key *key = _key; + + if(t != NULL) + return (t->id % range); + else + return (key->id % range); +} + +static struct thread *create_thread_struct(const char *name) +{ + struct thread *t; + int state; + + state = int_disable_interrupts(); + GRAB_THREAD_LOCK(); + t = thread_dequeue(&dead_q); + RELEASE_THREAD_LOCK(); + int_restore_interrupts(state); + + if(t == NULL) { + t = (struct thread *)kmalloc(sizeof(struct thread)); + if(t == NULL) + goto err; + } + + strncpy(&t->name[0], name, SYS_MAX_OS_NAME_LEN-1); + t->name[SYS_MAX_OS_NAME_LEN-1] = 0; + + t->id = atomic_add(&next_thread_id, 1); + t->proc = NULL; + t->cpu = NULL; + t->sem_blocking = -1; + t->fault_handler = 0; + t->kernel_stack_region_id = -1; + t->kernel_stack_base = 0; + t->user_stack_region_id = -1; + t->user_stack_base = 0; + t->proc_next = NULL; + t->q_next = NULL; + t->priority = -1; + t->args = NULL; + t->pending_signals = SIG_NONE; + t->in_kernel = true; + t->user_time = 0; + t->kernel_time = 0; + t->last_time = 0; + { + char temp[64]; + + sprintf(temp, "thread_0x%x_retcode_sem", t->id); + t->return_code_sem = create_sem(0, temp); + if(t->return_code_sem < 0) + goto err1; + } + + if(arch_thread_init_thread_struct(t) < 0) + goto err2; + + return t; + +err2: + delete_sem_etc(t->return_code_sem, -1); +err1: + kfree(t); +err: + return NULL; +} + +static void delete_thread_struct(struct thread *t) +{ + if(t->return_code_sem >= 0) + delete_sem_etc(t->return_code_sem, -1); + kfree(t); +} + +static int _create_user_thread_kentry(void) +{ + struct thread *t; + + t = thread_get_current_thread(); + + // a signal may have been delivered here + thread_atkernel_exit(); + + // jump to the entry point in user space + arch_thread_enter_uspace((addr)t->entry, t->args, t->user_stack_base + STACK_SIZE); + + // never get here + return 0; +} + +static int _create_kernel_thread_kentry(void) +{ + int (*func)(void *args); + struct thread *t; + + t = thread_get_current_thread(); + + // call the entry function with the appropriate args + func = (void *)t->entry; + + return func(t->args); +} + +static thread_id _create_thread(const char *name, proc_id pid, addr entry, void *args, + int priority, bool kernel) +{ + struct thread *t; + struct proc *p; + int state; + char stack_name[64]; + bool abort = false; + + t = create_thread_struct(name); + if(t == NULL) + return ERR_NO_MEMORY; + + t->priority = priority == -1 ? THREAD_MEDIUM_PRIORITY : priority; + t->state = THREAD_STATE_BIRTH; + t->next_state = THREAD_STATE_SUSPENDED; + + state = int_disable_interrupts(); + GRAB_THREAD_LOCK(); + + // insert into global list + hash_insert(thread_hash, t); + RELEASE_THREAD_LOCK(); + + GRAB_PROC_LOCK(); + // look at the proc, make sure it's not being deleted + p = proc_get_proc_struct_locked(pid); + if(p != NULL && p->state != PROC_STATE_DEATH) { + insert_thread_into_proc(p, t); + } else { + abort = true; + } + RELEASE_PROC_LOCK(); + if(abort) { + GRAB_THREAD_LOCK(); + hash_remove(thread_hash, t); + RELEASE_THREAD_LOCK(); + } + int_restore_interrupts(state); + if(abort) { + delete_thread_struct(t); + return ERR_TASK_PROC_DELETED; + } + + sprintf(stack_name, "%s_kstack", name); + t->kernel_stack_region_id = vm_create_anonymous_region(vm_get_kernel_aspace_id(), stack_name, + (void **)&t->kernel_stack_base, REGION_ADDR_ANY_ADDRESS, KSTACK_SIZE, + REGION_WIRING_WIRED, LOCK_RW|LOCK_KERNEL); + if(t->kernel_stack_region_id < 0) + panic("_create_thread: error creating kernel stack!\n"); + + t->args = args; + t->entry = entry; + + if(kernel) { + // this sets up an initial kthread stack that runs the entry + arch_thread_initialize_kthread_stack(t, &_create_kernel_thread_kentry, &thread_entry, &thread_kthread_exit); + } else { + // create user stack + // XXX make this better. For now just keep trying to create a stack + // until we find a spot. + t->user_stack_base = (USER_STACK_REGION - STACK_SIZE) + USER_STACK_REGION_SIZE; + while(t->user_stack_base > USER_STACK_REGION) { + sprintf(stack_name, "%s_stack%d", p->name, t->id); + t->user_stack_region_id = vm_create_anonymous_region(p->_aspace_id, stack_name, + (void **)&t->user_stack_base, + REGION_ADDR_ANY_ADDRESS, STACK_SIZE, REGION_WIRING_LAZY, LOCK_RW); + if(t->user_stack_region_id < 0) { + t->user_stack_base -= STACK_SIZE; + } else { + // we created a region + break; + } + } + if(t->user_stack_region_id < 0) + panic("_create_thread: unable to create user stack!\n"); + + // copy the user entry over to the args field in the thread struct + // the function this will call will immediately switch the thread into + // user space. + arch_thread_initialize_kthread_stack(t, &_create_user_thread_kentry, &thread_entry, &thread_kthread_exit); + } + + t->state = THREAD_STATE_SUSPENDED; + + return t->id; +} + +thread_id user_thread_create_user_thread(addr entry, proc_id pid, const char *uname, int priority, + void *args) +{ + char name[SYS_MAX_OS_NAME_LEN]; + int rc; + + if((addr)uname >= KERNEL_BASE && (addr)uname <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + if(entry >= KERNEL_BASE && entry <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + rc = user_strncpy(name, uname, SYS_MAX_OS_NAME_LEN-1); + if(rc < 0) + return rc; + name[SYS_MAX_OS_NAME_LEN-1] = 0; + + return _create_thread(name, pid, entry, args, priority, false); +} + +thread_id thread_create_user_thread(char *name, proc_id pid, addr entry, void *args) +{ + return _create_thread(name, pid, entry, args, -1, false); +} + +thread_id thread_create_kernel_thread(const char *name, int (*func)(void *), void *args) +{ + return _create_thread(name, proc_get_kernel_proc()->id, (addr)func, args, -1, true); +} + +static thread_id thread_create_kernel_thread_etc(const char *name, int (*func)(void *), void *args, struct proc *p) +{ + return _create_thread(name, p->id, (addr)func, args, -1, true); +} + +int thread_suspend_thread(thread_id id) +{ + int state; + struct thread *t; + int retval; + bool global_resched = false; + + state = int_disable_interrupts(); + GRAB_THREAD_LOCK(); + + t = thread_get_current_thread(); + if(t->id != id) { + t = thread_get_thread_struct_locked(id); + } + + if (t != NULL) { + if (t->proc == kernel_proc) { + // no way + retval = ERR_NOT_ALLOWED; + } else if (t->in_kernel == true) { + t->pending_signals |= SIG_SUSPEND; + retval = B_NO_ERROR; + } else { + t->next_state = THREAD_STATE_SUSPENDED; + global_resched = true; + retval = B_NO_ERROR; + } + } else { + retval = ERR_INVALID_HANDLE; + } + + RELEASE_THREAD_LOCK(); + int_restore_interrupts(state); + + if(global_resched) { + smp_send_broadcast_ici(SMP_MSG_RESCHEDULE, 0, 0, 0, NULL, SMP_MSG_FLAG_SYNC); + } + + return retval; +} + +int thread_resume_thread(thread_id id) +{ + int state; + struct thread *t; + int retval; + + state = int_disable_interrupts(); + GRAB_THREAD_LOCK(); + + t = thread_get_thread_struct_locked(id); + if(t != NULL && t->state == THREAD_STATE_SUSPENDED) { + t->state = THREAD_STATE_READY; + t->next_state = THREAD_STATE_READY; + + thread_enqueue_run_q(t); + retval = B_NO_ERROR; + } else { + retval = ERR_INVALID_HANDLE; + } + + RELEASE_THREAD_LOCK(); + int_restore_interrupts(state); + + return retval; +} + +int thread_set_priority(thread_id id, int priority) +{ + struct thread *t; + int retval; + + // make sure the passed in priority is within bounds + if(priority > THREAD_MAX_PRIORITY) + priority = THREAD_MAX_PRIORITY; + if(priority < THREAD_MIN_PRIORITY) + priority = THREAD_MIN_PRIORITY; + + t = thread_get_current_thread(); + if(t->id == id) { + // it's ourself, so we know we aren't in a run queue, and we can manipulate + // our structure directly + t->priority = priority; + retval = B_NO_ERROR; + } else { + int state = int_disable_interrupts(); + GRAB_THREAD_LOCK(); + + t = thread_get_thread_struct_locked(id); + if(t) { + if(t->state == THREAD_STATE_READY && t->priority != priority) { + // this thread is in a ready queue right now, so it needs to be reinserted + thread_dequeue_id(&run_q[t->priority], t->id); + t->priority = priority; + thread_enqueue_run_q(t); + } else { + t->priority = priority; + } + retval = B_NO_ERROR; + } else { + retval = ERR_INVALID_HANDLE; + } + + RELEASE_THREAD_LOCK(); + int_restore_interrupts(state); + } + + return retval; +} + +static void _dump_proc_info(struct proc *p) +{ + dprintf("PROC: %p\n", p); + dprintf("id: 0x%x\n", p->id); + dprintf("name: '%s'\n", p->name); + dprintf("next: %p\n", p->next); + dprintf("num_threads: %d\n", p->num_threads); + dprintf("state: %d\n", p->state); + dprintf("pending_signals: 0x%x\n", p->pending_signals); + dprintf("ioctx: %p\n", p->ioctx); + dprintf("path: '%s'\n", p->path); + dprintf("aspace_id: 0x%x\n", p->_aspace_id); + dprintf("aspace: %p\n", p->aspace); + dprintf("kaspace: %p\n", p->kaspace); + dprintf("main_thread: %p\n", p->main_thread); + dprintf("thread_list: %p\n", p->thread_list); +} + +static void dump_proc_info(int argc, char **argv) +{ + struct proc *p; + int id = -1; + unsigned long num; + struct hash_iterator i; + + if(argc < 2) { + dprintf("proc: not enough arguments\n"); + return; + } + + // if the argument looks like a hex number, treat it as such + if(strlen(argv[1]) > 2 && argv[1][0] == '0' && argv[1][1] == 'x') { + num = atoul(argv[1]); + if(num > vm_get_kernel_aspace()->virtual_map.base) { + // XXX semi-hack + _dump_proc_info((struct proc*)num); + return; + } else { + id = num; + } + } + + // walk through the thread list, trying to match name or id + hash_open(proc_hash, &i); + while((p = hash_next(proc_hash, &i)) != NULL) { + if((p->name && strcmp(argv[1], p->name) == 0) || p->id == id) { + _dump_proc_info(p); + break; + } + } + hash_close(proc_hash, &i, false); +} + + +static const char *state_to_text(int state) +{ + switch(state) { + case THREAD_STATE_READY: + return "READY"; + case THREAD_STATE_RUNNING: + return "RUNNING"; + case THREAD_STATE_WAITING: + return "WAITING"; + case THREAD_STATE_SUSPENDED: + return "SUSPEND"; + case THREAD_STATE_FREE_ON_RESCHED: + return "DEATH"; + case THREAD_STATE_BIRTH: + return "BIRTH"; + default: + return "UNKNOWN"; + } +} + +static struct thread *last_thread_dumped = NULL; + +static void _dump_thread_info(struct thread *t) +{ + dprintf("THREAD: %p\n", t); + dprintf("id: 0x%x\n", t->id); + dprintf("name: '%s'\n", t->name); + dprintf("all_next: %p\nproc_next: %p\nq_next: %p\n", + t->all_next, t->proc_next, t->q_next); + dprintf("priority: 0x%x\n", t->priority); + dprintf("state: %s\n", state_to_text(t->state)); + dprintf("next_state: %s\n", state_to_text(t->next_state)); + dprintf("cpu: %p ", t->cpu); + if(t->cpu) + dprintf("(%d)\n", t->cpu->info.cpu_num); + else + dprintf("\n"); + dprintf("pending_signals: 0x%x\n", t->pending_signals); + dprintf("in_kernel: %d\n", t->in_kernel); + dprintf("sem_blocking:0x%x\n", t->sem_blocking); + dprintf("sem_count: 0x%x\n", t->sem_count); + dprintf("sem_deleted_retcode: 0x%x\n", t->sem_deleted_retcode); + dprintf("sem_errcode: 0x%x\n", t->sem_errcode); + dprintf("sem_flags: 0x%x\n", t->sem_flags); + dprintf("fault_handler: 0x%lx\n", t->fault_handler); + dprintf("args: %p\n", t->args); + dprintf("entry: 0x%lx\n", t->entry); + dprintf("proc: %p\n", t->proc); + dprintf("return_code_sem: 0x%x\n", t->return_code_sem); + dprintf("kernel_stack_region_id: 0x%x\n", t->kernel_stack_region_id); + dprintf("kernel_stack_base: 0x%lx\n", t->kernel_stack_base); + dprintf("user_stack_region_id: 0x%x\n", t->user_stack_region_id); + dprintf("user_stack_base: 0x%lx\n", t->user_stack_base); + dprintf("kernel_time: %Ld\n", t->kernel_time); + dprintf("user_time: %Ld\n", t->user_time); + dprintf("architecture dependant section:\n"); + arch_thread_dump_info(&t->arch_info); + + last_thread_dumped = t; +} + +static void dump_thread_info(int argc, char **argv) +{ + struct thread *t; + int id = -1; + unsigned long num; + struct hash_iterator i; + + if(argc < 2) { + dprintf("thread: not enough arguments\n"); + return; + } + + // if the argument looks like a hex number, treat it as such + if(strlen(argv[1]) > 2 && argv[1][0] == '0' && argv[1][1] == 'x') { + num = atoul(argv[1]); + if(num > vm_get_kernel_aspace()->virtual_map.base) { + // XXX semi-hack + _dump_thread_info((struct thread *)num); + return; + } else { + id = num; + } + } + + // walk through the thread list, trying to match name or id + hash_open(thread_hash, &i); + while((t = hash_next(thread_hash, &i)) != NULL) { + if((t->name && strcmp(argv[1], t->name) == 0) || t->id == id) { + _dump_thread_info(t); + break; + } + } + hash_close(thread_hash, &i, false); +} + +static void dump_thread_list(int argc, char **argv) +{ + struct thread *t; + struct hash_iterator i; + + hash_open(thread_hash, &i); + while((t = hash_next(thread_hash, &i)) != NULL) { + dprintf("%p", t); + if(t->name != NULL) + dprintf("\t%32s", t->name); + else + dprintf("\t%32s", ""); + dprintf("\t0x%x", t->id); + dprintf("\t%16s", state_to_text(t->state)); + if(t->cpu) + dprintf("\t%d", t->cpu->info.cpu_num); + else + dprintf("\tNOCPU"); + dprintf("\t0x%lx\n", t->kernel_stack_base); + } + hash_close(thread_hash, &i, false); +} + +static void dump_next_thread_in_q(int argc, char **argv) +{ + struct thread *t = last_thread_dumped; + + if(t == NULL) { + dprintf("no thread previously dumped. Examine a thread first.\n"); + return; + } + + dprintf("next thread in queue after thread @ %p\n", t); + if(t->q_next != NULL) { + _dump_thread_info(t->q_next); + } else { + dprintf("NULL\n"); + } +} + +static void dump_next_thread_in_all_list(int argc, char **argv) +{ + struct thread *t = last_thread_dumped; + + if(t == NULL) { + dprintf("no thread previously dumped. Examine a thread first.\n"); + return; + } + + dprintf("next thread in global list after thread @ %p\n", t); + if(t->all_next != NULL) { + _dump_thread_info(t->all_next); + } else { + dprintf("NULL\n"); + } +} + +static void dump_next_thread_in_proc(int argc, char **argv) +{ + struct thread *t = last_thread_dumped; + + if(t == NULL) { + dprintf("no thread previously dumped. Examine a thread first.\n"); + return; + } + + dprintf("next thread in proc after thread @ %p\n", t); + if(t->proc_next != NULL) { + _dump_thread_info(t->proc_next); + } else { + dprintf("NULL\n"); + } +} + +static int get_death_stack(void) +{ + int i; + unsigned int bit; + int state; + + acquire_sem(death_stack_sem); + + // grap the thread lock, find a free spot and release + state = int_disable_interrupts(); + GRAB_THREAD_LOCK(); + bit = death_stack_bitmap; + bit = (~bit)&~((~bit)-1); + death_stack_bitmap |= bit; + RELEASE_THREAD_LOCK(); + + + // sanity checks + if( !bit ) { + panic("get_death_stack: couldn't find free stack!\n"); + } + if( bit & (bit-1)) { + panic("get_death_stack: impossible bitmap result!\n"); + } + + + // bit to number + i= -1; + while(bit) { + bit >>= 1; + i += 1; + } + +// dprintf("get_death_stack: returning 0x%lx\n", death_stacks[i].address); + + return i; +} + +static void put_death_stack_and_reschedule(unsigned int index) +{ +// dprintf("put_death_stack...: passed %d\n", index); + + if(index >= num_death_stacks) + panic("put_death_stack: passed invalid stack index %d\n", index); + + if(!(death_stack_bitmap & (1 << index))) + panic("put_death_stack: passed invalid stack index %d\n", index); + + int_disable_interrupts(); + GRAB_THREAD_LOCK(); + + death_stack_bitmap &= ~(1 << index); + + release_sem_etc(death_stack_sem, 1, B_DO_NOT_RESCHEDULE); + + thread_resched(); +} + +int thread_init(kernel_args *ka) +{ + struct thread *t; + unsigned int i; + +// dprintf("thread_init: entry\n"); + + // create the process hash table + proc_hash = hash_init(15, (addr)&kernel_proc->next - (addr)kernel_proc, + &proc_struct_compare, &proc_struct_hash); + + // create the kernel process + kernel_proc = create_proc_struct("kernel_proc", true); + if(kernel_proc == NULL) + panic("could not create kernel proc!\n"); + kernel_proc->state = PROC_STATE_NORMAL; + + kernel_proc->ioctx = vfs_new_io_context(NULL); + if(kernel_proc->ioctx == NULL) + panic("could not create ioctx for kernel proc!\n"); + + //XXX should initialize kernel_proc->path here. Set it to "/"? + + // stick it in the process hash + hash_insert(proc_hash, kernel_proc); + + // create the thread hash table + thread_hash = hash_init(15, (addr)&t->all_next - (addr)t, + &thread_struct_compare, &thread_struct_hash); + + // zero out the run queues + memset(run_q, 0, sizeof(run_q)); + + // zero out the dead thread structure q + memset(&dead_q, 0, sizeof(dead_q)); + + // allocate a snooze sem + snooze_sem = create_sem(0, "snooze sem"); + if(snooze_sem < 0) { + panic("error creating snooze sem\n"); + return snooze_sem; + } + + // create an idle thread for each cpu + for(i=0; inum_cpus; i++) { + char temp[64]; + vm_region *region; + + sprintf(temp, "idle_thread%d", i); + t = create_thread_struct(temp); + if(t == NULL) { + panic("error creating idle thread struct\n"); + return ERR_NO_MEMORY; + } + t->proc = proc_get_kernel_proc(); + t->priority = THREAD_IDLE_PRIORITY; + t->state = THREAD_STATE_RUNNING; + t->next_state = THREAD_STATE_READY; + sprintf(temp, "idle_thread%d_kstack", i); + t->kernel_stack_region_id = vm_find_region_by_name(vm_get_kernel_aspace_id(), temp); + region = vm_get_region_by_id(t->kernel_stack_region_id); + if(!region) { + panic("error finding idle kstack region\n"); + } + t->kernel_stack_base = region->base; + vm_put_region(region); + hash_insert(thread_hash, t); + insert_thread_into_proc(t->proc, t); + idle_threads[i] = t; + if(i == 0) + arch_thread_set_current_thread(t); + t->cpu = &cpu[i]; + } + + // create a set of death stacks + num_death_stacks = smp_get_num_cpus(); + if(num_death_stacks > 8*sizeof(death_stack_bitmap)) { + /* + * clamp values for really beefy machines + */ + num_death_stacks = 8*sizeof(death_stack_bitmap); + } + death_stack_bitmap = 0; + death_stacks = (struct death_stack *)kmalloc(num_death_stacks * sizeof(struct death_stack)); + if(death_stacks == NULL) { + panic("error creating death stacks\n"); + return ERR_NO_MEMORY; + } + { + char temp[64]; + + for(i=0; ikernel_stack_base); + + // delete the old kernel stack region +// dprintf("thread_exit2: deleting old kernel stack id 0x%x for thread 0x%x\n", args.old_kernel_stack, args.t->id); + vm_delete_region(vm_get_kernel_aspace_id(), args.old_kernel_stack); + +// dprintf("thread_exit2: removing thread 0x%x from global lists\n", args.t->id); + + // remove this thread from all of the global lists + int_disable_interrupts(); + GRAB_PROC_LOCK(); + remove_thread_from_proc(kernel_proc, args.t); + RELEASE_PROC_LOCK(); + GRAB_THREAD_LOCK(); + hash_remove(thread_hash, args.t); + RELEASE_THREAD_LOCK(); + +// dprintf("thread_exit2: done removing thread from lists\n"); + + // set the next state to be gone. Will return the thread structure to a ready pool upon reschedule + args.t->next_state = THREAD_STATE_FREE_ON_RESCHED; + + // return the death stack and reschedule one last time + put_death_stack_and_reschedule(args.death_stack); + // never get to here + panic("thread_exit2: made it where it shouldn't have!\n"); +} + +void thread_exit(int retcode) +{ + int state; + struct thread *t = thread_get_current_thread(); + struct proc *p = t->proc; + bool delete_proc = false; + unsigned int death_stack; + + dprintf("thread 0x%x exiting w/return code 0x%x\n", t->id, retcode); + + // boost our priority to get this over with + thread_set_priority(t->id, THREAD_HIGH_PRIORITY); + + // delete the user stack region first + if(p->_aspace_id >= 0 && t->user_stack_region_id >= 0) { + region_id rid = t->user_stack_region_id; + t->user_stack_region_id = -1; + vm_delete_region(p->_aspace_id, rid); + } + + if(p != kernel_proc) { + // remove this thread from the current process and add it to the kernel + // put the thread into the kernel proc until it dies + state = int_disable_interrupts(); + GRAB_PROC_LOCK(); + remove_thread_from_proc(p, t); + insert_thread_into_proc(kernel_proc, t); + if(p->main_thread == t) { + // this was main thread in this process + delete_proc = true; + hash_remove(proc_hash, p); + p->state = PROC_STATE_DEATH; + } + RELEASE_PROC_LOCK(); + // swap address spaces, to make sure we're running on the kernel's pgdir + vm_aspace_swap(kernel_proc->kaspace); + int_restore_interrupts(state); + +// dprintf("thread_exit: thread 0x%x now a kernel thread!\n", t->id); + } + + // delete the process + if(delete_proc) { + if(p->num_threads > 0) { + // there are other threads still in this process, + // cycle through and signal kill on each of the threads + // XXX this can be optimized. There's got to be a better solution. + struct thread *temp_thread; + + state = int_disable_interrupts(); + GRAB_PROC_LOCK(); + // we can safely walk the list because of the lock. no new threads can be created + // because of the PROC_STATE_DEATH flag on the process + temp_thread = p->thread_list; + while(temp_thread) { + struct thread *next = temp_thread->proc_next; + thread_kill_thread_nowait(temp_thread->id); + temp_thread = next; + } + RELEASE_PROC_LOCK(); + int_restore_interrupts(state); + + // Now wait for all of the threads to die + // XXX block on a semaphore + while((volatile int)p->num_threads > 0) { + thread_snooze(10000); // 10 ms + } + } + vm_put_aspace(p->aspace); + vm_delete_aspace(p->_aspace_id); + delete_owned_ports(p->id); + sem_delete_owned_sems(p->id); + vfs_free_io_context(p->ioctx); + kfree(p); + } + + // delete the sem that others will use to wait on us and get the retcode + { + sem_id s = t->return_code_sem; + + t->return_code_sem = -1; + delete_sem_etc(s, retcode); + } + + death_stack = get_death_stack(); + { + struct thread_exit_args args; + + args.t = t; + args.old_kernel_stack = t->kernel_stack_region_id; + args.death_stack = death_stack; + + // disable the interrupts. Must remain disabled until the kernel stack pointer can be officially switched + args.int_state = int_disable_interrupts(); + + // set the new kernel stack officially to the death stack, wont be really switched until + // the next function is called. This bookkeeping must be done now before a context switch + // happens, or the processor will interrupt to the old stack + t->kernel_stack_region_id = death_stacks[death_stack].rid; + t->kernel_stack_base = death_stacks[death_stack].address; + + // we will continue in thread_exit2(), on the new stack + arch_thread_switch_kstack_and_call(t, t->kernel_stack_base + KSTACK_SIZE, thread_exit2, &args); + } + + panic("never can get here\n"); +} + +static int _thread_kill_thread(thread_id id, bool wait_on) +{ + int state; + struct thread *t; + int rc; + +// dprintf("_thread_kill_thread: id %d, wait_on %d\n", id, wait_on); + + state = int_disable_interrupts(); + GRAB_THREAD_LOCK(); + + t = thread_get_thread_struct_locked(id); + if(t != NULL) { + if(t->proc == kernel_proc) { + // can't touch this + rc = ERR_NOT_ALLOWED; + } else { + deliver_signal(t, SIG_KILL); + rc = B_NO_ERROR; + if(t->id == thread_get_current_thread()->id) + wait_on = false; // can't wait on ourself + } + } else { + rc = ERR_INVALID_HANDLE; + } + + RELEASE_THREAD_LOCK(); + int_restore_interrupts(state); + if(rc < 0) + return rc; + + if(wait_on) + thread_wait_on_thread(id, NULL); + + return rc; +} + +int thread_kill_thread(thread_id id) +{ + return _thread_kill_thread(id, true); +} + +int thread_kill_thread_nowait(thread_id id) +{ + return _thread_kill_thread(id, false); +} + +static void thread_kthread_exit(void) +{ + thread_exit(0); +} + +int user_thread_wait_on_thread(thread_id id, int *uretcode) +{ + int retcode; + int rc, rc2; + + if((addr)uretcode >= KERNEL_BASE && (addr)uretcode <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + rc = thread_wait_on_thread(id, &retcode); + + rc2 = user_memcpy(uretcode, &retcode, sizeof(retcode)); + if(rc2 < 0) + return rc2; + + return rc; +} + +int thread_wait_on_thread(thread_id id, int *retcode) +{ + sem_id sem; + int state; + struct thread *t; + int rc; + + state = int_disable_interrupts(); + GRAB_THREAD_LOCK(); + + t = thread_get_thread_struct_locked(id); + if(t != NULL) { + sem = t->return_code_sem; + } else { + sem = ERR_INVALID_HANDLE; + } + + RELEASE_THREAD_LOCK(); + int_restore_interrupts(state); + + rc = acquire_sem(sem); + + /* This thread died the way it should, dont ripple a non-error up */ + if (rc == ERR_SEM_DELETED) + rc = B_NO_ERROR; + + return rc; +} + +int user_proc_wait_on_proc(proc_id id, int *uretcode) +{ + int retcode; + int rc, rc2; + + if((addr)uretcode >= KERNEL_BASE && (addr)uretcode <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + rc = proc_wait_on_proc(id, &retcode); + if(rc < 0) + return rc; + + rc2 = user_memcpy(uretcode, &retcode, sizeof(retcode)); + if(rc2 < 0) + return rc2; + + return rc; +} + +int proc_wait_on_proc(proc_id id, int *retcode) +{ + struct proc *p; + thread_id tid; + int state; + + state = int_disable_interrupts(); + GRAB_PROC_LOCK(); + p = proc_get_proc_struct_locked(id); + if(p && p->main_thread) { + tid = p->main_thread->id; + } else { + tid = ERR_INVALID_HANDLE; + } + RELEASE_PROC_LOCK(); + int_restore_interrupts(state); + + if(tid < 0) + return tid; + + return thread_wait_on_thread(tid, retcode); +} + +struct thread *thread_get_thread_struct(thread_id id) +{ + struct thread *t; + int state; + + state = int_disable_interrupts(); + GRAB_THREAD_LOCK(); + + t = thread_get_thread_struct_locked(id); + + RELEASE_THREAD_LOCK(); + int_restore_interrupts(state); + + return t; +} + +static struct thread *thread_get_thread_struct_locked(thread_id id) +{ + struct thread_key key; + + key.id = id; + + return hash_lookup(thread_hash, &key); +} + +/* XXX - static but unused +static struct proc *proc_get_proc_struct(proc_id id) +{ + struct proc *p; + int state; + + state = int_disable_interrupts(); + GRAB_PROC_LOCK(); + + p = proc_get_proc_struct_locked(id); + + RELEASE_PROC_LOCK(); + int_restore_interrupts(state); + + return p; +} +*/ + +static struct proc *proc_get_proc_struct_locked(proc_id id) +{ + struct proc_key key; + + key.id = id; + + return hash_lookup(proc_hash, &key); +} + +static void thread_context_switch(struct thread *t_from, struct thread *t_to) +{ + bigtime_t now; + + // track kernel time + now = system_time(); + t_from->kernel_time += now - t_from->last_time; + t_to->last_time = now; + + t_to->cpu = t_from->cpu; + arch_thread_set_current_thread(t_to); + t_from->cpu = NULL; + arch_thread_context_switch(t_from, t_to); +} + +static int _rand(void) +{ + static int next = 0; + + if(next == 0) + next = system_time(); + + next = next * 1103515245 + 12345; + return((next >> 16) & 0x7FFF); +} + +static int reschedule_event(void *unused) +{ + // this function is called as a result of the timer event set by the scheduler + // returning this causes a reschedule on the timer event + thread_get_current_thread()->cpu->info.preempted= 1; + return INT_RESCHEDULE; +} + +// NOTE: expects thread_spinlock to be held +void thread_resched(void) +{ + struct thread *next_thread = NULL; + int last_thread_pri = -1; + struct thread *old_thread = thread_get_current_thread(); + int i; + bigtime_t quantum; + struct timer_event *quantum_timer; + +// dprintf("top of thread_resched: cpu %d, cur_thread = 0x%x\n", smp_get_current_cpu(), thread_get_current_thread()); + + switch(old_thread->next_state) { + case THREAD_STATE_RUNNING: + case THREAD_STATE_READY: +// dprintf("enqueueing thread 0x%x into run q. pri = %d\n", old_thread, old_thread->priority); + thread_enqueue_run_q(old_thread); + break; + case THREAD_STATE_SUSPENDED: + dprintf("suspending thread 0x%x\n", old_thread->id); + break; + case THREAD_STATE_FREE_ON_RESCHED: + thread_enqueue(old_thread, &dead_q); + break; + default: +// dprintf("not enqueueing thread 0x%x into run q. next_state = %d\n", old_thread, old_thread->next_state); + ; + } + old_thread->state = old_thread->next_state; + + // search the real-time queue + for(i = THREAD_MAX_RT_PRIORITY; i >= THREAD_MIN_RT_PRIORITY; i--) { + next_thread = thread_dequeue_run_q(i); + if(next_thread) + goto found_thread; + } + + // search the regular queue + for(i = THREAD_MAX_PRIORITY; i > THREAD_IDLE_PRIORITY; i--) { + next_thread = thread_lookat_run_q(i); + if(next_thread != NULL) { + // skip it sometimes + if(_rand() > 0x3000) { + next_thread = thread_dequeue_run_q(i); + goto found_thread; + } + last_thread_pri = i; + next_thread = NULL; + } + } + if(next_thread == NULL) { + if(last_thread_pri != -1) { + next_thread = thread_dequeue_run_q(last_thread_pri); + if(next_thread == NULL) + panic("next_thread == NULL! last_thread_pri = %d\n", last_thread_pri); + } else { + next_thread = thread_dequeue_run_q(THREAD_IDLE_PRIORITY); + if(next_thread == NULL) + panic("next_thread == NULL! no idle priorities!\n"); + } + } + +found_thread: + next_thread->state = THREAD_STATE_RUNNING; + next_thread->next_state = THREAD_STATE_READY; + + // XXX should only reset the quantum timer if we are switching to a new thread, + // or we got here as a result of a quantum expire. + + // XXX calculate quantum + quantum = 10000; + + // get the quantum timer for this cpu + quantum_timer = &old_thread->cpu->info.quantum_timer; + if(!old_thread->cpu->info.preempted) { + _local_timer_cancel_event(old_thread->cpu->info.cpu_num, quantum_timer); + } + old_thread->cpu->info.preempted= 0; + timer_setup_timer(&reschedule_event, NULL, quantum_timer); + timer_set_event(quantum, TIMER_MODE_ONESHOT, quantum_timer); + + if(next_thread != old_thread) { +// dprintf("thread_resched: cpu %d switching from thread %d to %d\n", +// smp_get_current_cpu(), old_thread->id, next_thread->id); + thread_context_switch(old_thread, next_thread); + } +} + +static int proc_struct_compare(void *_p, const void *_key) +{ + struct proc *p = _p; + const struct proc_key *key = _key; + + if(p->id == key->id) return 0; + else return 1; +} + +static unsigned int proc_struct_hash(void *_p, const void *_key, unsigned int range) +{ + struct proc *p = _p; + const struct proc_key *key = _key; + + if(p != NULL) + return (p->id % range); + else + return (key->id % range); +} + +struct proc *proc_get_kernel_proc(void) +{ + return kernel_proc; +} + +proc_id proc_get_kernel_proc_id(void) +{ + if(!kernel_proc) + return 0; + else + return kernel_proc->id; +} + +proc_id proc_get_current_proc_id(void) +{ + return thread_get_current_thread()->proc->id; +} + +static struct proc *create_proc_struct(const char *name, bool kernel) +{ + struct proc *p; + + p = (struct proc *)kmalloc(sizeof(struct proc)); + if(p == NULL) + goto error; + p->id = atomic_add(&next_proc_id, 1); + strncpy(&p->name[0], name, SYS_MAX_OS_NAME_LEN-1); + p->name[SYS_MAX_OS_NAME_LEN-1] = 0; + p->num_threads = 0; + p->ioctx = NULL; + p->path[0] = 0; + p->_aspace_id = -1; + p->aspace = NULL; + p->kaspace = vm_get_kernel_aspace(); + vm_put_aspace(p->kaspace); + p->thread_list = NULL; + p->main_thread = NULL; + p->state = PROC_STATE_BIRTH; + p->pending_signals = SIG_NONE; + + if(arch_proc_init_proc_struct(p, kernel) < 0) + goto error1; + + return p; + +error1: + kfree(p); +error: + return NULL; +} + +static void delete_proc_struct(struct proc *p) +{ + kfree(p); +} + +static int get_arguments_data_size(char **args,int argc) +{ + int cnt; + int tot_size = 0; + + for(cnt = 0; cnt < argc; cnt++) + tot_size += strlen(args[cnt]) + 1; + tot_size += (argc + 1) * sizeof(char *); + + return tot_size + sizeof(struct uspace_prog_args_t); +} + +static int proc_create_proc2(void *args) +{ + int err; + struct thread *t; + struct proc *p; + struct proc_arg *pargs = args; + char *path; + addr entry; + char ustack_name[128]; + int tot_top_size; + char **uargs; + char *udest; + struct uspace_prog_args_t *uspa; + unsigned int cnt; + + t = thread_get_current_thread(); + p = t->proc; + + dprintf("proc_create_proc2: entry thread %d\n", t->id); + + // create an initial primary stack region + + tot_top_size = STACK_SIZE + PAGE_ALIGN(get_arguments_data_size(pargs->args,pargs->argc)); + t->user_stack_base = ((USER_STACK_REGION - tot_top_size) + USER_STACK_REGION_SIZE); + sprintf(ustack_name, "%s_primary_stack", p->name); + t->user_stack_region_id = vm_create_anonymous_region(p->_aspace_id, ustack_name, (void **)&t->user_stack_base, + REGION_ADDR_EXACT_ADDRESS, tot_top_size, REGION_WIRING_LAZY, LOCK_RW); + if(t->user_stack_region_id < 0) { + panic("proc_create_proc2: could not create default user stack region\n"); + return t->user_stack_region_id; + } + + uspa = (struct uspace_prog_args_t *)(t->user_stack_base + STACK_SIZE); + uargs = (char **)(uspa + 1); + udest = (char *)(uargs + pargs->argc + 1); +// dprintf("addr: stack base=0x%x uargs = 0x%x udest=0x%x tot_top_size=%d \n\n",t->user_stack_base,uargs,udest,tot_top_size); + + for(cnt = 0;cnt < pargs->argc;cnt++){ + uargs[cnt] = udest; + user_strcpy(udest, pargs->args[cnt]); + udest += strlen(pargs->args[cnt]) + 1; + } + uargs[cnt] = NULL; + + user_memcpy(uspa->prog_name, p->name, sizeof(uspa->prog_name)); + user_memcpy(uspa->prog_path, pargs->path, sizeof(uspa->prog_path)); + uspa->argc = cnt; + uspa->argv = uargs; + uspa->envc = 0; + uspa->envp = 0; + + if(pargs->args != NULL) + free_arg_list(pargs->args,pargs->argc); + + path = pargs->path; + dprintf("proc_create_proc2: loading elf binary '%s'\n", path); + + err = elf_load_uspace("/boot/libexec/rld.so", p, 0, &entry); + if(err < 0){ + // XXX clean up proc + return err; + } + + // free the args + kfree(pargs->path); + kfree(pargs); + + dprintf("proc_create_proc2: loaded elf. entry = 0x%lx\n", entry); + + p->state = PROC_STATE_NORMAL; + + // jump to the entry point in user space + arch_thread_enter_uspace(entry, uspa, t->user_stack_base + STACK_SIZE); + + // never gets here + return 0; +} + +proc_id proc_create_proc(const char *path, const char *name, char **args, int argc, int priority) +{ + struct proc *p; + thread_id tid; + proc_id pid; + int err; + unsigned int state; +// int sem_retcode; + struct proc_arg *pargs; + + dprintf("proc_create_proc: entry '%s', name '%s' args = %p argc = %d\n", path, name, args, argc); + + p = create_proc_struct(name, false); + if(p == NULL) + return ERR_NO_MEMORY; + + pid = p->id; + + state = int_disable_interrupts(); + GRAB_PROC_LOCK(); + hash_insert(proc_hash, p); + RELEASE_PROC_LOCK(); + int_restore_interrupts(state); + + // copy the args over + pargs = (struct proc_arg *)kmalloc(sizeof(struct proc_arg)); + if(pargs == NULL){ + err = ERR_NO_MEMORY; + goto err1; + } + pargs->path = (char *)kstrdup(path); + if(pargs->path == NULL){ + err = ERR_NO_MEMORY; + goto err2; + } + pargs->argc = argc; + pargs->args = args; + + // create a new ioctx for this process + p->ioctx = vfs_new_io_context(thread_get_current_thread()->proc->ioctx); + if(!p->ioctx) { + err = ERR_NO_MEMORY; + goto err3; + } + + //XXX should set p->path to path(?) here. + + // create an address space for this process + p->_aspace_id = vm_create_aspace(p->name, USER_BASE, USER_SIZE, false); + if (p->_aspace_id < 0) { + err = p->_aspace_id; + goto err4; + } + p->aspace = vm_get_aspace_by_id(p->_aspace_id); + + // create a kernel thread, but under the context of the new process + tid = thread_create_kernel_thread_etc(name, proc_create_proc2, pargs, p); + if (tid < 0) { + err = tid; + goto err5; + } + + thread_resume_thread(tid); + + return pid; + +err5: + vm_put_aspace(p->aspace); + vm_delete_aspace(p->_aspace_id); +err4: + vfs_free_io_context(p->ioctx); +err3: + kfree(pargs->path); +err2: + kfree(pargs); +err1: + // remove the proc structure from the proc hash table and delete the proc structure + state = int_disable_interrupts(); + GRAB_PROC_LOCK(); + hash_remove(proc_hash, p); + RELEASE_PROC_LOCK(); + int_restore_interrupts(state); + delete_proc_struct(p); +//err: + return err; +} + +proc_id user_proc_create_proc(const char *upath, const char *uname, char **args, int argc, int priority) +{ + char path[SYS_MAX_PATH_LEN]; + char name[SYS_MAX_OS_NAME_LEN]; + char **kargs; + int rc; + + dprintf("user_proc_create_proc : argc=%d \n",argc); + + if((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + if((addr)uname >= KERNEL_BASE && (addr)uname <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + rc = user_copy_arg_list(args, argc, &kargs); + if(rc < 0) + goto error; + + rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN-1); + if(rc < 0) + goto error; + + path[SYS_MAX_PATH_LEN-1] = 0; + + rc = user_strncpy(name, uname, SYS_MAX_OS_NAME_LEN-1); + if(rc < 0) + goto error; + + name[SYS_MAX_OS_NAME_LEN-1] = 0; + + return proc_create_proc(path, name, kargs, argc, priority); +error: + free_arg_list(kargs,argc); + return rc; +} + + +// used by PS command and anything else interested in a process list +int user_proc_get_table(struct proc_info *pbuf, size_t len) +{ + struct proc *p; + struct hash_iterator i; + struct proc_info pi; + int state; + int count=0; + int max = (len / sizeof(struct proc_info)); + + if((addr)pbuf >= KERNEL_BASE && (addr)pbuf <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + state = int_disable_interrupts(); + GRAB_PROC_LOCK(); + + hash_open(proc_hash, &i); + while(((p = hash_next(proc_hash, &i)) != NULL) && (count < max)) { + pi.id = p->id; + strcpy(pi.name, p->name); + pi.state = p->state; + pi.num_threads = p->num_threads; + count++; + user_memcpy(pbuf, &pi, sizeof(struct proc_info)); + pbuf=pbuf + sizeof(struct proc_info); + } + hash_close(proc_hash, &i, false); + + RELEASE_PROC_LOCK(); + int_restore_interrupts(state); + + if (count < max) + return count; + else + return ERR_NO_MEMORY; +} + + +int proc_kill_proc(proc_id id) +{ + int state; + struct proc *p; +// struct thread *t; + thread_id tid = -1; + int retval = 0; + + state = int_disable_interrupts(); + GRAB_PROC_LOCK(); + + p = proc_get_proc_struct_locked(id); + if(p != NULL) { + tid = p->main_thread->id; + } else { + retval = ERR_INVALID_HANDLE; + } + + RELEASE_PROC_LOCK(); + int_restore_interrupts(state); + if(retval < 0) + return retval; + + // just kill the main thread in the process. The cleanup code there will + // take care of the process + return thread_kill_thread(tid); +} + +// sets the pending signal flag on a thread and possibly does some work to wake it up, etc. +// expects the thread lock to be held +static void deliver_signal(struct thread *t, int signal) +{ +// dprintf("deliver_signal: thread %p (%d), signal %d\n", t, t->id, signal); + switch(signal) { + case SIG_KILL: + t->pending_signals |= SIG_KILL; + switch(t->state) { + case THREAD_STATE_SUSPENDED: + t->state = THREAD_STATE_READY; + t->next_state = THREAD_STATE_READY; + + thread_enqueue_run_q(t); + break; + case THREAD_STATE_WAITING: + sem_interrupt_thread(t); + break; + default: + ; + } + break; + default: + t->pending_signals |= signal; + } +} + +// expects the thread lock to be held +static void _check_for_thread_sigs(struct thread *t, int state) +{ + if(t->pending_signals == SIG_NONE) + return; + + if(t->pending_signals & SIG_KILL) { + t->pending_signals &= ~SIG_KILL; + + RELEASE_THREAD_LOCK(); + int_restore_interrupts(state); + thread_exit(0); + // never gets to here + } + if(t->pending_signals & SIG_SUSPEND) { + t->pending_signals &= ~SIG_SUSPEND; + t->next_state = THREAD_STATE_SUSPENDED; + // XXX will probably want to delay this + thread_resched(); + } +} + +// called in the int handler code when a thread enters the kernel for any reason +void thread_atkernel_entry(void) +{ + int state; + struct thread *t; + bigtime_t now; + +// dprintf("thread_atkernel_entry: entry thread 0x%x\n", t->id); + + t = thread_get_current_thread(); + + state = int_disable_interrupts(); + + // track user time + now = system_time(); + t->user_time += now - t->last_time; + t->last_time = now; + + GRAB_THREAD_LOCK(); + + t->in_kernel = true; + + _check_for_thread_sigs(t, state); + + RELEASE_THREAD_LOCK(); + int_restore_interrupts(state); +} + +// called when a thread exits kernel space to user space +void thread_atkernel_exit(void) +{ + int state; + struct thread *t; + bigtime_t now; + +// dprintf("thread_atkernel_exit: entry\n"); + + t = thread_get_current_thread(); + + state = int_disable_interrupts(); + GRAB_THREAD_LOCK(); + + _check_for_thread_sigs(t, state); + + t->in_kernel = false; + + RELEASE_THREAD_LOCK(); + + // track kernel time + now = system_time(); + t->kernel_time += now - t->last_time; + t->last_time = now; + + int_restore_interrupts(state); +} + +int user_getrlimit(int resource, struct rlimit * urlp) +{ + int ret; + struct rlimit rl; + + if (urlp == NULL) { + return ERR_INVALID_ARGS; + } + if((addr)urlp >= KERNEL_BASE && (addr)urlp <= KERNEL_TOP) { + return ERR_VM_BAD_USER_MEMORY; + } + + ret = getrlimit(resource, &rl); + + if (ret == 0) { + ret = user_memcpy(urlp, &rl, sizeof(struct rlimit)); + if (ret < 0) { + return ret; + } + return 0; + } + + return ret; +} + +int getrlimit(int resource, struct rlimit * rlp) +{ + if (!rlp) { + return -1; + } + + switch(resource) { + case RLIMIT_NOFILE: + return vfs_getrlimit(resource, rlp); + + default: + return -1; + } + + return 0; +} + +int user_setrlimit(int resource, const struct rlimit * urlp) +{ + int err; + struct rlimit rl; + + if (urlp == NULL) { + return ERR_INVALID_ARGS; + } + if((addr)urlp >= KERNEL_BASE && (addr)urlp <= KERNEL_TOP) { + return ERR_VM_BAD_USER_MEMORY; + } + + err = user_memcpy(&rl, urlp, sizeof(struct rlimit)); + if (err < 0) { + return err; + } + + return setrlimit(resource, &rl); +} + +int setrlimit(int resource, const struct rlimit * rlp) +{ + if (!rlp) { + return -1; + } + + switch(resource) { + case RLIMIT_NOFILE: + return vfs_setrlimit(resource, rlp); + + default: + return -1; + } + + return 0; +} diff --git a/src/kernel/core/timer.c b/src/kernel/core/timer.c new file mode 100644 index 0000000000..40a3d5b89e --- /dev/null +++ b/src/kernel/core/timer.c @@ -0,0 +1,270 @@ +/* Policy info for timers */ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static struct timer_event * volatile events[SMP_MAX_CPUS] = { NULL, }; +static spinlock_t timer_spinlock[SMP_MAX_CPUS] = { 0, }; + +int timer_init(kernel_args *ka) +{ + dprintf("init_timer: entry\n"); + + return arch_init_timer(ka); +} + +// NOTE: expects interrupts to be off +static void add_event_to_list(struct timer_event *event, struct timer_event * volatile *list) +{ + struct timer_event *next; + struct timer_event *last = NULL; + + // stick it in the event list + next = *list; + while(next != NULL && next->sched_time < event->sched_time) { + last = next; + next = next->next; + } + + if(last != NULL) { + event->next = last->next; + last->next = event; + } else { + event->next = next; + *list = event; + } +} + +int timer_interrupt() +{ + bigtime_t curr_time = system_time(); + struct timer_event *event; + spinlock_t *spinlock; + int curr_cpu = smp_get_current_cpu(); + int rc = INT_NO_RESCHEDULE; + +// dprintf("timer_interrupt: time 0x%x 0x%x, cpu %d\n", system_time(), smp_get_current_cpu()); + + spinlock = &timer_spinlock[curr_cpu]; + + acquire_spinlock(spinlock); + +restart_scan: + event = events[curr_cpu]; + if(event != NULL && event->sched_time < curr_time) { + // this event needs to happen + int mode = event->mode; + + events[curr_cpu] = event->next; + event->sched_time = 0; + + release_spinlock(spinlock); + + // call the callback + // note: if the event is not periodic, it is ok + // to delete the event structure inside the callback + if(event->func != NULL) { + if(event->func(event->data) == INT_RESCHEDULE) + rc = INT_RESCHEDULE; + } + + acquire_spinlock(spinlock); + + if(mode == TIMER_MODE_PERIODIC) { + // we need to adjust it and add it back to the list + event->sched_time = system_time() + event->periodic_time; + if(event->sched_time == 0) + event->sched_time = 1; // if we wrapped around and happen + // to hit zero, set it to one, since + // zero represents not scheduled + add_event_to_list(event, &events[curr_cpu]); + } + + goto restart_scan; // the list may have changed + } + + // setup the next hardware timer + if(events[curr_cpu] != NULL) + arch_timer_set_hardware_timer(events[curr_cpu]->sched_time - system_time()); + + release_spinlock(spinlock); + + return rc; +} + +void timer_setup_timer(timer_callback func, void *data, struct timer_event *event) +{ + event->func = func; + event->data = data; + event->sched_time = 0; +} + +int timer_set_event(bigtime_t relative_time, timer_mode mode, struct timer_event *event) +{ + int state; + int curr_cpu; + + if(event == NULL) + return ERR_INVALID_ARGS; + + if(relative_time < 0) + relative_time = 0; + + if(event->sched_time != 0) + panic("timer_set_event: event %p in list already!\n", event); + + event->sched_time = system_time() + relative_time; + if(event->sched_time == 0) + event->sched_time = 1; // if we wrapped around and happen + // to hit zero, set it to one, since + // zero represents not scheduled + event->mode = mode; + if(event->mode == TIMER_MODE_PERIODIC) + event->periodic_time = relative_time; + + state = int_disable_interrupts(); + + curr_cpu = smp_get_current_cpu(); + + acquire_spinlock(&timer_spinlock[curr_cpu]); + + add_event_to_list(event, &events[curr_cpu]); + + // if we were stuck at the head of the list, set the hardware timer + if(event == events[curr_cpu]) { + arch_timer_set_hardware_timer(relative_time); + } + + release_spinlock(&timer_spinlock[curr_cpu]); + int_restore_interrupts(state); + + return 0; +} + +/* this is a fast path to be called from reschedule and from timer_cancel_event */ +/* must always be invoked with interrupts disabled */ +int _local_timer_cancel_event(int curr_cpu, struct timer_event *event) +{ + struct timer_event *last = NULL; + struct timer_event *e; + bool foundit = false; + + acquire_spinlock(&timer_spinlock[curr_cpu]); + e = events[curr_cpu]; + while(e != NULL) { + if(e == event) { + // we found it + foundit = true; + if(e == events[curr_cpu]) { + events[curr_cpu] = e->next; + } else { + last->next = e->next; + } + e->next = NULL; + // break out of the whole thing + goto done; + } + last = e; + e = e->next; + } + release_spinlock(&timer_spinlock[curr_cpu]); +done: + + if(events[curr_cpu] == NULL) { + arch_timer_clear_hardware_timer(); + } else { + arch_timer_set_hardware_timer(events[curr_cpu]->sched_time - system_time()); + } + + if(foundit) { + release_spinlock(&timer_spinlock[curr_cpu]); + } + + return (foundit ? 0 : ERR_GENERAL); +} + +int local_timer_cancel_event(struct timer_event *event) +{ + return _local_timer_cancel_event(smp_get_current_cpu(), event); +} + +int timer_cancel_event(struct timer_event *event) +{ + int state; + struct timer_event *last = NULL; + struct timer_event *e; + bool foundit = false; + int num_cpus = smp_get_num_cpus(); + int cpu= 0; + int curr_cpu; + + if(event->sched_time == 0) + return 0; // it's not scheduled + + state = int_disable_interrupts(); + curr_cpu = smp_get_current_cpu(); + + // walk through all of the cpu's timer queues + // + // We start by peeking our own queue, aiming for + // a cheap match. If this fails, we start harassing + // other cpus. + // + if(_local_timer_cancel_event(curr_cpu, event) < 0) { + for(cpu = 0; cpu < num_cpus; cpu++) { + if(cpu== curr_cpu) continue; + acquire_spinlock(&timer_spinlock[cpu]); + e = events[cpu]; + while(e != NULL) { + if(e == event) { + // we found it + foundit = true; + if(e == events[cpu]) { + events[cpu] = e->next; + } else { + last->next = e->next; + } + e->next = NULL; + // break out of the whole thing + goto done; + } + last = e; + e = e->next; + } + release_spinlock(&timer_spinlock[cpu]); + } + } +done: + + if(foundit) { + release_spinlock(&timer_spinlock[cpu]); + } + int_restore_interrupts(state); + + return (foundit ? 0 : ERR_GENERAL); +} + +void spin(bigtime_t microseconds) +{ + bigtime_t time = system_time(); + + while((system_time() - time) < microseconds) + ; +} + diff --git a/src/kernel/core/vm/Jamfile b/src/kernel/core/vm/Jamfile new file mode 100644 index 0000000000..1a93487084 --- /dev/null +++ b/src/kernel/core/vm/Jamfile @@ -0,0 +1,15 @@ +SubDir OBOS_TOP sources os kits kernel core vm ; + +KernelStaticLibrary libvm : + <$(SOURCE_GRIST)>vm.c + <$(SOURCE_GRIST)>vm_cache.c + <$(SOURCE_GRIST)>vm_daemons.c + <$(SOURCE_GRIST)>vm_page.c + <$(SOURCE_GRIST)>vm_store_anonymous_noswap.c + <$(SOURCE_GRIST)>vm_store_device.c + <$(SOURCE_GRIST)>vm_store_null.c + <$(SOURCE_GRIST)>vm_store_vnode.c + <$(SOURCE_GRIST)>vm_tests.c + : + -fno-pic -Wno-unused -D_KERNEL_ + ; diff --git a/src/kernel/core/vm/vm.c b/src/kernel/core/vm/vm.c new file mode 100755 index 0000000000..fa8b79ca19 --- /dev/null +++ b/src/kernel/core/vm/vm.c @@ -0,0 +1,2179 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include + +#define HEAP_SIZE 0x00400000 + +#define ROUNDUP(a, b) (((a) + ((b)-1)) & ~((b)-1)) +#define ROUNDOWN(a, b) (((a) / (b)) * (b)) + +#define min(a, b) ((a) < (b) ? (a) : (b)) +#define max(a, b) ((a) > (b) ? (a) : (b)) + +static vm_address_space *kernel_aspace; + +#define REGION_HASH_TABLE_SIZE 1024 +static region_id next_region_id; +static void *region_table; +static sem_id region_hash_sem; + +#define ASPACE_HASH_TABLE_SIZE 1024 +static aspace_id next_aspace_id; +static void *aspace_table; +static sem_id aspace_hash_sem; + +static int max_commit; +static spinlock_t max_commit_lock; + +// function declarations +static vm_region *_vm_create_region_struct(vm_address_space *aspace, const char *name, int wiring, int lock); +static int map_backing_store(vm_address_space *aspace, vm_store *store, void **vaddr, + off_t offset, addr size, int addr_type, int wiring, int lock, int mapping, vm_region **_region, const char *region_name); +static int vm_soft_fault(addr address, bool is_write, bool is_user); +static vm_region *vm_virtual_map_lookup(vm_virtual_map *map, addr address); +//static int vm_region_acquire_ref(vm_region *region); +//static void vm_region_release_ref(vm_region *region); +//static void vm_region_release_ref2(vm_region *region); + +static int region_compare(void *_r, const void *key) +{ + vm_region *r = _r; + const region_id *id = key; + + if(r->id == *id) + return 0; + else + return -1; +} + +static unsigned int region_hash(void *_r, const void *key, unsigned int range) +{ + vm_region *r = _r; + const region_id *id = key; + + if(r != NULL) + return (r->id % range); + else + return (*id % range); +} + +static int aspace_compare(void *_a, const void *key) +{ + vm_address_space *aspace = _a; + const aspace_id *id = key; + + if(aspace->id == *id) + return 0; + else + return -1; +} + +static unsigned int aspace_hash(void *_a, const void *key, unsigned int range) +{ + vm_address_space *aspace = _a; + const aspace_id *id = key; + + if(aspace != NULL) + return (aspace->id % range); + else + return (*id % range); +} + +vm_address_space *vm_get_aspace_by_id(aspace_id aid) +{ + vm_address_space *aspace; + + acquire_sem_etc(aspace_hash_sem, READ_COUNT, 0, 0); + aspace = hash_lookup(aspace_table, &aid); + if(aspace) + atomic_add(&aspace->ref_count, 1); + release_sem_etc(aspace_hash_sem, READ_COUNT, 0); + + return aspace; +} + +vm_region *vm_get_region_by_id(region_id rid) +{ + vm_region *region; + + acquire_sem_etc(region_hash_sem, READ_COUNT, 0, 0); + region = hash_lookup(region_table, &rid); + if(region) + atomic_add(®ion->ref_count, 1); + release_sem_etc(region_hash_sem, READ_COUNT, 0); + + return region; +} + +region_id vm_find_region_by_name(aspace_id aid, const char *name) +{ + vm_region *region = NULL; + vm_address_space *aspace; + region_id id = B_NAME_NOT_FOUND; + + aspace = vm_get_aspace_by_id(aid); + if(aspace == NULL) + return ERR_VM_INVALID_ASPACE; + + acquire_sem_etc(aspace->virtual_map.sem, READ_COUNT, 0, 0); + + region = aspace->virtual_map.region_list; + while(region != NULL) { + if(strcmp(region->name, name) == 0) { + id = region->id; + break; + } + region = region->aspace_next; + } + + release_sem_etc(aspace->virtual_map.sem, READ_COUNT, 0); + vm_put_aspace(aspace); + return id; +} + +static vm_region *_vm_create_region_struct(vm_address_space *aspace, const char *name, int wiring, int lock) +{ + vm_region *region = NULL; + + region = (vm_region *)kmalloc(sizeof(vm_region)); + if(region == NULL) + return NULL; + region->name = (char *)kmalloc(strlen(name) + 1); + if(region->name == NULL) { + kfree(region); + return NULL; + } + strcpy(region->name, name); + region->id = atomic_add(&next_region_id, 1); + region->base = 0; + region->size = 0; + region->lock = lock; + region->wiring = wiring; + region->ref_count = 1; + + region->cache_ref = NULL; + region->cache_offset = 0; + + region->aspace = aspace; + region->aspace_next = NULL; + region->map = &aspace->virtual_map; + region->cache_next = region->cache_prev = NULL; + region->hash_next = NULL; + + return region; +} + +// must be called with this address space's virtual_map.sem held +static int find_and_insert_region_slot(vm_virtual_map *map, addr start, addr size, addr end, int addr_type, vm_region *region) +{ + vm_region *last_r = NULL; + vm_region *next_r; + bool foundspot = false; + + dprintf("find_and_insert_region_slot: map %p, start 0x%lx, size %ld, end 0x%lx, addr_type %d, region %p\n", + map, start, size, end, addr_type, region); +// dprintf("map->base 0x%x, map->size 0x%x\n", map->base, map->size); + + // do some sanity checking + if(start < map->base || size == 0 || (end - 1) > (map->base + (map->size - 1)) || start + size > end) + return ERR_VM_BAD_ADDRESS; + + // walk up to the spot where we should start searching + next_r = map->region_list; + while(next_r) { + if(next_r->base >= start + size) { + // we have a winner + break; + } + last_r = next_r; + next_r = next_r->aspace_next; + } + +#if 0 + dprintf("last_r 0x%x, next_r 0x%x\n", last_r, next_r); + if(last_r) dprintf("last_r->base 0x%x, last_r->size 0x%x\n", last_r->base, last_r->size); + if(next_r) dprintf("next_r->base 0x%x, next_r->size 0x%x\n", next_r->base, next_r->size); +#endif + + switch(addr_type) { + case REGION_ADDR_ANY_ADDRESS: + // find a hole big enough for a new region + if(!last_r) { + // see if we can build it at the beginning of the virtual map + if(!next_r || (next_r->base >= map->base + size)) { + foundspot = true; + region->base = map->base; + break; + } + last_r = next_r; + next_r = next_r->aspace_next; + } + // keep walking + while(next_r) { + if(next_r->base >= last_r->base + last_r->size + size) { + // we found a spot + foundspot = true; + region->base = last_r->base + last_r->size; + break; + } + last_r = next_r; + next_r = next_r->aspace_next; + } + if((map->base + (map->size - 1)) >= (last_r->base + last_r->size + (size - 1))) { + // found a spot + foundspot = true; + region->base = last_r->base + last_r->size; + break; + } + break; + case REGION_ADDR_EXACT_ADDRESS: + // see if we can create it exactly here + if(!last_r) { + if(!next_r || (next_r->base >= start + size)) { + foundspot = true; + region->base = start; + break; + } + } else { + if(next_r) { + if(last_r->base + last_r->size <= start && next_r->base >= start + size) { + foundspot = true; + region->base = start; + break; + } + } else { + if((last_r->base + (last_r->size - 1)) <= start - 1) { + foundspot = true; + region->base = start; + } + } + } + break; + default: + return EINVAL; + } + + if(foundspot) { + region->size = size; + if(last_r) { + region->aspace_next = last_r->aspace_next; + last_r->aspace_next = region; + } else { + region->aspace_next = map->region_list; + map->region_list = region; + } + map->change_count++; + return B_NO_ERROR; + } else { + return ERR_VM_NO_REGION_SLOT; + } +} + +// a ref to the cache holding this store must be held before entering here +static int map_backing_store(vm_address_space *aspace, vm_store *store, + void **vaddr, off_t offset, addr size, + int addr_type, int wiring, int lock, int mapping, + vm_region **_region, const char *region_name) +{ + vm_cache *cache; + vm_cache_ref *cache_ref; + vm_region *region; + vm_cache *nu_cache; + vm_cache_ref *nu_cache_ref = NULL; + vm_store *nu_store; + + int err; + +// dprintf("map_backing_store: aspace 0x%x, store 0x%x, *vaddr 0x%x, offset 0x%Lx, size %d, addr_type %d, wiring %d, lock %d, _region 0x%x, region_name '%s'\n", +// aspace, store, *vaddr, offset, size, addr_type, wiring, lock, _region, region_name); + + region = _vm_create_region_struct(aspace, region_name, wiring, lock); + if(!region) + return ENOMEM; + + cache = store->cache; + cache_ref = cache->ref; + + // if this is a private map, we need to create a new cache & store object + // pair to handle the private copies of pages as they are written to + if(mapping == REGION_PRIVATE_MAP) { + // create an anonymous store object + nu_store = vm_store_create_anonymous_noswap(); + if(nu_store == NULL) + panic("map_backing_store: vm_create_store_anonymous_noswap returned NULL"); + nu_cache = vm_cache_create(nu_store); + if(nu_cache == NULL) + panic("map_backing_store: vm_cache_create returned NULL"); + nu_cache_ref = vm_cache_ref_create(nu_cache); + if(nu_cache_ref == NULL) + panic("map_backing_store: vm_cache_ref_create returned NULL"); + nu_cache->temporary = 1; + nu_cache->scan_skip = 0; + + nu_cache->source = cache; + + // grab a ref to the cache object we're now linked to as a source + vm_cache_acquire_ref(cache_ref, true); + + cache = nu_cache; + cache_ref = cache->ref; + store = nu_store; + } + + mutex_lock(&cache_ref->lock); + // If we don't have enough committed space to cover through to the new end of region... + if(store->committed_size < offset + size) { + // try to commit more memory + off_t old_store_commitment = store->committed_size; // Note what we had + off_t commitment = (store->ops->commit)(store, offset + size); // Commit through to the new end + if(commitment < offset + size) { // Uh oh - didn't work + if(cache->temporary) { // If this is a temporary cache, Check to see if we ran out of space and return error. + int state = int_disable_interrupts(); + acquire_spinlock(&max_commit_lock); + + if (max_commit - old_store_commitment + commitment < offset + size) { + release_spinlock(&max_commit_lock); + int_restore_interrupts(state); + mutex_unlock(&cache_ref->lock); + err = ERR_VM_WOULD_OVERCOMMIT; + goto err1a; + } + + max_commit += (commitment - old_store_commitment) - (offset + size - cache->virtual_size); + cache->virtual_size = offset + size; + release_spinlock(&max_commit_lock); + int_restore_interrupts(state); + } else { + mutex_unlock(&cache_ref->lock); + err = ENOMEM; + goto err1a; + } + } + } + + mutex_unlock(&cache_ref->lock); + + vm_cache_acquire_ref(cache_ref, true); + + acquire_sem_etc(aspace->virtual_map.sem, WRITE_COUNT, 0, 0); + + // check to see if this aspace has entered DELETE state + if(aspace->state == VM_ASPACE_STATE_DELETION) { + // okay, someone is trying to delete this aspace now, so we can't + // insert the region, so back out + err = ERR_VM_INVALID_ASPACE; + goto err1b; + } + + { + addr search_addr, search_end; + + if(addr_type == REGION_ADDR_EXACT_ADDRESS) { + search_addr = (addr)*vaddr; + search_end = (addr)*vaddr + size; + } else if(addr_type == REGION_ADDR_ANY_ADDRESS) { + search_addr = aspace->virtual_map.base; + search_end = aspace->virtual_map.base + (aspace->virtual_map.size - 1); + } else { + err = EINVAL; + goto err1b; + } + + err = find_and_insert_region_slot(&aspace->virtual_map, + search_addr, size, + search_end, addr_type, + region); + if(err < 0) + goto err1b; + *vaddr = (addr *)region->base; + } + + // attach the cache to the region + region->cache_ref = cache_ref; + region->cache_offset = offset; + // point the cache back to the region + vm_cache_insert_region(cache_ref, region); + + // insert the region in the global region hash table + acquire_sem_etc(region_hash_sem, WRITE_COUNT, 0 ,0); + hash_insert(region_table, region); + release_sem_etc(region_hash_sem, WRITE_COUNT, 0); + + // grab a ref to the aspace (the region holds this) + atomic_add(&aspace->ref_count, 1); + + release_sem_etc(aspace->virtual_map.sem, WRITE_COUNT, 0); + + *_region = region; + + return B_NO_ERROR; + +err1b: + release_sem_etc(aspace->virtual_map.sem, WRITE_COUNT, 0); + vm_cache_release_ref(cache_ref); + goto err; +err1a: + if(nu_cache_ref) { + // had never acquired it's initial ref, so acquire and then release it + // this should clean up all the objects it references + vm_cache_acquire_ref(cache_ref, true); + vm_cache_release_ref(cache_ref); + } +err: + kfree(region->name); + kfree(region); + return err; +} + +region_id user_vm_create_anonymous_region(char *uname, void **uaddress, int addr_type, + addr size, int wiring, int lock) +{ + char name[SYS_MAX_OS_NAME_LEN]; + void *address; + int rc, rc2; + + if((addr)uname >= KERNEL_BASE && (addr)uname <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + rc = user_strncpy(name, uname, SYS_MAX_OS_NAME_LEN-1); + if(rc < 0) + return rc; + name[SYS_MAX_OS_NAME_LEN-1] = 0; + + rc = user_memcpy(&address, uaddress, sizeof(address)); + if(rc < 0) + return rc; + + rc = vm_create_anonymous_region(vm_get_current_user_aspace_id(), name, &address, addr_type, size, wiring, lock); + if(rc < 0) + return rc; + + rc2 = user_memcpy(uaddress, &address, sizeof(address)); + if(rc2 < 0) + return rc2; + + return rc; +} + +region_id vm_create_anonymous_region(aspace_id aid, char *name, void **address, + int addr_type, addr size, int wiring, + int lock) +{ + int err; + vm_region *region; + vm_cache *cache; + vm_store *store; + vm_address_space *aspace; + vm_cache_ref *cache_ref; + + dprintf("create_anonymous_region: %s: size 0x%lx\n", name, size); + + aspace = vm_get_aspace_by_id(aid); + if(aspace == NULL) + return ERR_VM_INVALID_ASPACE; + + size = PAGE_ALIGN(size); + + // create an anonymous store object + store = vm_store_create_anonymous_noswap(); + if(store == NULL) + panic("vm_create_anonymous_region: vm_create_store_anonymous_noswap returned NULL"); + cache = vm_cache_create(store); + if(cache == NULL) + panic("vm_create_anonymous_region: vm_cache_create returned NULL"); + cache_ref = vm_cache_ref_create(cache); + if(cache_ref == NULL) + panic("vm_create_anonymous_region: vm_cache_ref_create returned NULL"); + cache->temporary = 1; + cache->scan_skip = 0; + +// dprintf("create_anonymous_region: calling map_backing store\n"); + + vm_cache_acquire_ref(cache_ref, true); + err = map_backing_store(aspace, store, address, 0, size, addr_type, wiring, lock, REGION_NO_PRIVATE_MAP, ®ion, name); + vm_cache_release_ref(cache_ref); + if(err < 0) { + vm_put_aspace(aspace); + return err; + } + +// dprintf("create_anonymous_region: done calling map_backing store\n"); + + cache_ref = store->cache->ref; + switch(wiring) { + case REGION_WIRING_LAZY: + break; // do nothing + case REGION_WIRING_WIRED: { + // pages aren't mapped at this point, but we just simulate a fault on + // every page, which should allocate them + addr va; + // XXX remove + for(va = region->base; va < region->base + region->size; va += PAGE_SIZE) { +// dprintf("mapping wired pages: region 0x%x, cache_ref 0x%x 0x%x\n", region, cache_ref, region->cache_ref); + vm_soft_fault(va, false, false); + } + break; + } + case REGION_WIRING_WIRED_ALREADY: { + // the pages should already be mapped. This is only really useful during + // boot time. Find the appropriate vm_page objects and stick them in + // the cache object. + addr va; + addr pa; + unsigned int flags; + int err; + vm_page *page; + off_t offset = 0; + + mutex_lock(&cache_ref->lock); + (*aspace->translation_map.ops->lock)(&aspace->translation_map); + for(va = region->base; va < region->base + region->size; va += PAGE_SIZE, offset += PAGE_SIZE) { + err = (*aspace->translation_map.ops->query)(&aspace->translation_map, + va, &pa, &flags); + if(err < 0) { +// dprintf("vm_create_anonymous_region: error looking up mapping for va 0x%x\n", va); + continue; + } + page = vm_lookup_page(pa / PAGE_SIZE); + if(page == NULL) { +// dprintf("vm_create_anonymous_region: error looking up vm_page structure for pa 0x%x\n", pa); + continue; + } + atomic_add(&page->ref_count, 1); + vm_page_set_state(page, PAGE_STATE_WIRED); + vm_cache_insert_page(cache_ref, page, offset); + } + (*aspace->translation_map.ops->unlock)(&aspace->translation_map); + mutex_unlock(&cache_ref->lock); + break; + } + case REGION_WIRING_WIRED_CONTIG: { + addr va; + addr phys_addr; + int err; + vm_page *page; + off_t offset = 0; + + page = vm_page_allocate_page_run(PAGE_STATE_CLEAR, ROUNDUP(region->size, PAGE_SIZE) / PAGE_SIZE); + if(page == NULL) { + // XXX back out of this + panic("couldn't allocate page run of size %ld\n", region->size); + } + phys_addr = page->ppn * PAGE_SIZE; + + mutex_lock(&cache_ref->lock); + (*aspace->translation_map.ops->lock)(&aspace->translation_map); + for(va = region->base; va < region->base + region->size; va += PAGE_SIZE, offset += PAGE_SIZE, phys_addr += PAGE_SIZE) { + page = vm_lookup_page(phys_addr / PAGE_SIZE); + if(page == NULL) { + panic("couldn't lookup physical page just allocated\n"); + } + atomic_add(&page->ref_count, 1); + err = (*aspace->translation_map.ops->map)(&aspace->translation_map, va, phys_addr, lock); + if(err < 0) { + panic("couldn't map physical page in page run\n"); + } + vm_page_set_state(page, PAGE_STATE_WIRED); + vm_cache_insert_page(cache_ref, page, offset); + } + (*aspace->translation_map.ops->unlock)(&aspace->translation_map); + mutex_unlock(&cache_ref->lock); + + break; + } + default: + ; + } + vm_put_aspace(aspace); + +// dprintf("create_anonymous_region: done\n"); + + if(region) + return region->id; + else + return ENOMEM; +} + +region_id vm_map_physical_memory(aspace_id aid, char *name, void **address, int addr_type, + addr size, int lock, addr phys_addr) +{ + vm_region *region; + vm_cache *cache; + vm_cache_ref *cache_ref; + vm_store *store; + addr map_offset; + int err; + + vm_address_space *aspace = vm_get_aspace_by_id(aid); + if(aspace == NULL) + return ERR_VM_INVALID_ASPACE; + + // if the physical address is somewhat inside a page, + // move the actual region down to align on a page boundary + map_offset = phys_addr % PAGE_SIZE; + size += map_offset; + phys_addr -= map_offset; + + size = PAGE_ALIGN(size); + + // create an device store object + store = vm_store_create_device(phys_addr); + if(store == NULL) + panic("vm_map_physical_memory: vm_store_create_device returned NULL"); + cache = vm_cache_create(store); + if(cache == NULL) + panic("vm_map_physical_memory: vm_cache_create returned NULL"); + cache_ref = vm_cache_ref_create(cache); + if(cache_ref == NULL) + panic("vm_map_physical_memory: vm_cache_ref_create returned NULL"); + // tell the page scanner to skip over this region, it's pages are special + cache->scan_skip = 1; + + vm_cache_acquire_ref(cache_ref, true); + err = map_backing_store(aspace, store, address, 0, size, addr_type, 0, lock, REGION_NO_PRIVATE_MAP, ®ion, name); + vm_cache_release_ref(cache_ref); + vm_put_aspace(aspace); + if(err < 0) { + return err; + } + + // modify the pointer returned to be offset back into the new region + // the same way the physical address in was offset + (*address) += map_offset; + return region->id; +} + +region_id vm_create_null_region(aspace_id aid, char *name, void **address, int addr_type, addr size) +{ + vm_region *region; + vm_cache *cache; + vm_cache_ref *cache_ref; + vm_store *store; +// addr map_offset; + int err; + + vm_address_space *aspace = vm_get_aspace_by_id(aid); + if(aspace == NULL) + return ERR_VM_INVALID_ASPACE; + + size = PAGE_ALIGN(size); + + // create an null store object + store = vm_store_create_null(); + if(store == NULL) + panic("vm_map_physical_memory: vm_store_create_null returned NULL"); + cache = vm_cache_create(store); + if(cache == NULL) + panic("vm_map_physical_memory: vm_cache_create returned NULL"); + cache_ref = vm_cache_ref_create(cache); + if(cache_ref == NULL) + panic("vm_map_physical_memory: vm_cache_ref_create returned NULL"); + // tell the page scanner to skip over this region, no pages will be mapped here + cache->scan_skip = 1; + + vm_cache_acquire_ref(cache_ref, true); + err = map_backing_store(aspace, store, address, 0, size, addr_type, 0, LOCK_RO, REGION_NO_PRIVATE_MAP, ®ion, name); + vm_cache_release_ref(cache_ref); + vm_put_aspace(aspace); + if(err < 0) + return err; + + return region->id; +} + +static region_id _vm_map_file(aspace_id aid, char *name, void **address, int addr_type, + addr size, int lock, int mapping, const char *path, off_t offset, bool kernel) +{ + vm_region *region; + vm_cache *cache; + vm_cache_ref *cache_ref; + vm_store *store; + void *v; +// addr map_offset; + int err; + + + vm_address_space *aspace = vm_get_aspace_by_id(aid); + if(aspace == NULL) + return ERR_VM_INVALID_ASPACE; + + offset = ROUNDOWN(offset, PAGE_SIZE); + size = PAGE_ALIGN(size); + +restart: + // get the vnode for the object, this also grabs a ref to it + err = vfs_get_vnode_from_path(path, kernel, &v); + if(err < 0) { + vm_put_aspace(aspace); + return err; + } + + cache_ref = vfs_get_cache_ptr(v); + if(!cache_ref) { + // create a vnode store object + store = vm_store_create_vnode(v); + if(store == NULL) + panic("vm_map_file: couldn't create vnode store"); + cache = vm_cache_create(store); + if(cache == NULL) + panic("vm_map_physical_memory: vm_cache_create returned NULL"); + cache_ref = vm_cache_ref_create(cache); + if(cache_ref == NULL) + panic("vm_map_physical_memory: vm_cache_ref_create returned NULL"); + + // acquire the cache ref once to represent the ref that the vnode will have + // this is one of the only places where we dont want to ref to ripple down to the store + vm_cache_acquire_ref(cache_ref, false); + + // try to set the cache ptr in the vnode + if(vfs_set_cache_ptr(v, cache_ref) < 0) { + // the cache pointer was set between here and then + // this can only happen if someone else tries to map it + // at the same time. Rare enough to not worry about the + // performance impact of undoing what we just did and retrying + + // this will delete the cache object and release the ref to the vnode we have + vm_cache_release_ref(cache_ref); + goto restart; + } + } else { + cache = cache_ref->cache; + store = cache->store; + } + + // acquire a ref to the cache before we do work on it. Dont ripple the ref acquision to the vnode + // below because we'll have to release it later anyway, since we grabbed a ref to the vnode at + // vfs_get_vnode_from_path(). This puts the ref counts in sync. + vm_cache_acquire_ref(cache_ref, false); + err = map_backing_store(aspace, store, address, offset, size, addr_type, 0, lock, mapping, ®ion, name); + vm_cache_release_ref(cache_ref); + vm_put_aspace(aspace); + if(err < 0) { + return err; + } + + // modify the pointer returned to be offset back into the new region + // the same way the physical address in was offset + return region->id; +} + +region_id vm_map_file(aspace_id aid, char *name, void **address, int addr_type, + addr size, int lock, int mapping, const char *path, off_t offset) +{ + return _vm_map_file(aid, name, address, addr_type, size, lock, mapping, path, offset, true); +} + +region_id user_vm_map_file(char *uname, void **uaddress, int addr_type, + addr size, int lock, int mapping, const char *upath, off_t offset) +{ + char name[SYS_MAX_OS_NAME_LEN]; + void *address; + char path[SYS_MAX_PATH_LEN]; + int rc, rc2; + + if((addr)uname >= KERNEL_BASE && (addr)uname <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + if((addr)uaddress >= KERNEL_BASE && (addr)uaddress <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + if((addr)upath >= KERNEL_BASE && (addr)upath <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + rc = user_strncpy(name, uname, SYS_MAX_OS_NAME_LEN-1); + if(rc < 0) + return rc; + name[SYS_MAX_OS_NAME_LEN-1] = 0; + + rc = user_strncpy(path, upath, SYS_MAX_PATH_LEN-1); + if(rc < 0) + return rc; + path[SYS_MAX_PATH_LEN-1] = 0; + + rc = user_memcpy(&address, uaddress, sizeof(address)); + if(rc < 0) + return rc; + + rc = _vm_map_file(vm_get_current_user_aspace_id(), name, &address, addr_type, size, lock, mapping, path, offset, false); + if(rc < 0) + return rc; + + rc2 = user_memcpy(uaddress, &address, sizeof(address)); + if(rc2 < 0) + return rc2; + + return rc; +} + +region_id user_vm_clone_region(char *uname, void **uaddress, int addr_type, + region_id source_region, int mapping, int lock) +{ + char name[SYS_MAX_OS_NAME_LEN]; + void *address; + int rc, rc2; + + if((addr)uname >= KERNEL_BASE && (addr)uname <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + if((addr)uaddress >= KERNEL_BASE && (addr)uaddress <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + rc = user_strncpy(name, uname, SYS_MAX_OS_NAME_LEN-1); + if(rc < 0) + return rc; + name[SYS_MAX_OS_NAME_LEN-1] = 0; + + rc = user_memcpy(&address, uaddress, sizeof(address)); + if(rc < 0) + return rc; + + rc = vm_clone_region(vm_get_current_user_aspace_id(), name, &address, addr_type, source_region, mapping, lock); + if(rc < 0) + return rc; + + rc2 = user_memcpy(uaddress, &address, sizeof(address)); + if(rc2 < 0) + return rc2; + + return rc; +} + +region_id vm_clone_region(aspace_id aid, char *name, void **address, int addr_type, + region_id source_region, int mapping, int lock) +{ + vm_region *new_region; + vm_region *src_region; + int err; + + vm_address_space *aspace = vm_get_aspace_by_id(aid); + if(aspace == NULL) + return ERR_VM_INVALID_ASPACE; + + src_region = vm_get_region_by_id(source_region); + if(src_region == NULL) { + vm_put_aspace(aspace); + return ERR_VM_INVALID_REGION; + } + + vm_cache_acquire_ref(src_region->cache_ref, true); + err = map_backing_store(aspace, src_region->cache_ref->cache->store, address, src_region->cache_offset, src_region->size, + addr_type, src_region->wiring, lock, mapping, &new_region, name); + vm_cache_release_ref(src_region->cache_ref); + + // release the ref on the old region + vm_put_region(src_region); + + vm_put_aspace(aspace); + + if(err < 0) + return err; + else + return new_region->id; +} + +static int __vm_delete_region(vm_address_space *aspace, vm_region *region) +{ + if(region->aspace == aspace) + vm_put_region(region); + return B_NO_ERROR; +} + +static int _vm_delete_region(vm_address_space *aspace, region_id rid) +{ +// vm_region *temp, *last = NULL; + vm_region *region; + + dprintf("vm_delete_region: aspace id 0x%x, region id 0x%x\n", aspace->id, rid); + + region = vm_get_region_by_id(rid); + if(region == NULL) + return ERR_VM_INVALID_REGION; + + __vm_delete_region(aspace, region); + vm_put_region(region); + + return 0; +} + +int vm_delete_region(aspace_id aid, region_id rid) +{ + vm_address_space *aspace; + int err; + + aspace = vm_get_aspace_by_id(aid); + if(aspace == NULL) + return ERR_VM_INVALID_ASPACE; + + err = _vm_delete_region(aspace, rid); + vm_put_aspace(aspace); + return err; +} + +static void _vm_put_region(vm_region *region, bool aspace_locked) +{ + vm_region *temp, *last = NULL; + vm_address_space *aspace; + bool removeit = false; + + acquire_sem_etc(region_hash_sem, WRITE_COUNT, 0, 0); + if(atomic_add(®ion->ref_count, -1) == 1) { + hash_remove(region_table, region); + removeit = true; + } + release_sem_etc(region_hash_sem, WRITE_COUNT, 0); + + if(!removeit) + return; + + aspace = region->aspace; + + // remove the region from the aspace's virtual map + if(!aspace_locked) + acquire_sem_etc(aspace->virtual_map.sem, WRITE_COUNT, 0, 0); + temp = aspace->virtual_map.region_list; + while(temp != NULL) { + if(region == temp) { + if(last != NULL) { + last->aspace_next = temp->aspace_next; + } else { + aspace->virtual_map.region_list = temp->aspace_next; + } + aspace->virtual_map.change_count++; + break; + } + last = temp; + temp = temp->aspace_next; + } + if(region == aspace->virtual_map.region_hint) + aspace->virtual_map.region_hint = NULL; + if(!aspace_locked) + release_sem_etc(aspace->virtual_map.sem, WRITE_COUNT, 0); + + if(temp == NULL) + panic("vm_region_release_ref: region not found in aspace's region_list\n"); + + vm_cache_remove_region(region->cache_ref, region); + vm_cache_release_ref(region->cache_ref); + + (*aspace->translation_map.ops->lock)(&aspace->translation_map); + (*aspace->translation_map.ops->unmap)(&aspace->translation_map, region->base, + region->base + (region->size - 1)); + (*aspace->translation_map.ops->unlock)(&aspace->translation_map); + + // now we can give up the last ref to the aspace + vm_put_aspace(aspace); + + if(region->name) + kfree(region->name); + kfree(region); + + return; +} + +void vm_put_region(vm_region *region) +{ + return _vm_put_region(region, false); +} + +int user_vm_get_region_info(region_id id, vm_region_info *uinfo) +{ + vm_region_info info; + int rc, rc2; + + if((addr)uinfo >= KERNEL_BASE && (addr)uinfo <= KERNEL_TOP) + return ERR_VM_BAD_USER_MEMORY; + + rc = vm_get_region_info(id, &info); + if(rc < 0) + return rc; + + rc2 = user_memcpy(uinfo, &info, sizeof(info)); + if(rc2 < 0) + return rc2; + + return rc; +} + +int vm_get_region_info(region_id id, vm_region_info *info) +{ + vm_region *region; + + if(info == NULL) + return EINVAL; + + region = vm_get_region_by_id(id); + if(region == NULL) + return ERR_VM_INVALID_REGION; + + info->id = region->id; + info->base = region->base; + info->size = region->size; + info->lock = region->lock; + info->wiring = region->wiring; + strncpy(info->name, region->name, SYS_MAX_OS_NAME_LEN-1); + info->name[SYS_MAX_OS_NAME_LEN-1] = 0; + + vm_put_region(region); + + return 0; +} + +int vm_get_page_mapping(aspace_id aid, addr vaddr, addr *paddr) +{ + vm_address_space *aspace; + unsigned int null_flags; + int err; + + aspace = vm_get_aspace_by_id(aid); + if(aspace == NULL) + return ERR_VM_INVALID_ASPACE; + + err = aspace->translation_map.ops->query(&aspace->translation_map, + vaddr, paddr, &null_flags); + vm_put_aspace(aspace); + return err; +} + +static void display_mem(int argc, char **argv) +{ + int item_size; + int display_width; + int num = 1; + addr address; + int i; + int j; + + if(argc < 2) { + dprintf("not enough arguments\n"); + return; + } + + address = atoul(argv[1]); + + if(argc >= 3) { + num = -1; + num = atoi(argv[2]); + } + + // build the format string + if(strcmp(argv[0], "db") == 0) { + item_size = 1; + display_width = 16; + } else if(strcmp(argv[0], "ds") == 0) { + item_size = 2; + display_width = 8; + } else if(strcmp(argv[0], "dw") == 0) { + item_size = 4; + display_width = 4; + } else { + dprintf("display_mem called in an invalid way!\n"); + return; + } + + dprintf("[0x%lx] '", address); + for(j=0; jcache); + dprintf("lock.count: %d\n", cache_ref->lock.count); + dprintf("lock.sem: 0x%x\n", cache_ref->lock.sem); + dprintf("region_list:\n"); + for(region = cache_ref->region_list; region != NULL; region = region->cache_next) { + dprintf(" region 0x%x: ", region->id); + dprintf("base_addr = 0x%lx ", region->base); + dprintf("size = 0x%lx ", region->size); + dprintf("name = '%s' ", region->name); + dprintf("lock = 0x%x\n", region->lock); + } + dprintf("ref_count: %d\n", cache_ref->ref_count); +} + +static const char *page_state_to_text(int state) +{ + switch(state) { + case PAGE_STATE_ACTIVE: + return "active"; + case PAGE_STATE_INACTIVE: + return "inactive"; + case PAGE_STATE_BUSY: + return "busy"; + case PAGE_STATE_MODIFIED: + return "modified"; + case PAGE_STATE_FREE: + return "free"; + case PAGE_STATE_CLEAR: + return "clear"; + case PAGE_STATE_WIRED: + return "wired"; + case PAGE_STATE_UNUSED: + return "unused"; + default: + return "unknown"; + } +} + +static void dump_cache(int argc, char **argv) +{ + addr address; + vm_cache *cache; + vm_page *page; + + if(argc < 2) { + dprintf("cache: not enough arguments\n"); + return; + } + if(strlen(argv[1]) < 2 || argv[1][0] != '0' || argv[1][1] != 'x') { + dprintf("cache: invalid argument, pass address\n"); + return; + } + + address = atoul(argv[1]); + cache = (vm_cache *)address; + + dprintf("cache at %p:\n", cache); + dprintf("cache_ref: %p\n", cache->ref); + dprintf("source: %p\n", cache->source); + dprintf("store: %p\n", cache->store); + // XXX 64-bit + dprintf("virtual_size: 0x%Lx\n", cache->virtual_size); + dprintf("temporary: %d\n", cache->temporary); + dprintf("scan_skip: %d\n", cache->scan_skip); + dprintf("page_list:\n"); + for(page = cache->page_list; page != NULL; page = page->cache_next) { + // XXX offset is 64-bit + if(page->type == PAGE_TYPE_PHYSICAL) + dprintf(" %p ppn 0x%lx offset 0x%Lx type %d state %d (%s) ref_count %d\n", + page, page->ppn, page->offset, page->type, page->state, page_state_to_text(page->state), page->ref_count); + else if(page->type == PAGE_TYPE_DUMMY) + dprintf(" %p DUMMY PAGE state %d (%s)\n", page, page->state, page_state_to_text(page->state)); + else + dprintf(" %p UNKNOWN PAGE type %d\n", page, page->type); + } +} + +static void _dump_region(vm_region *region) +{ + dprintf("dump of region at %p:\n", region); + dprintf("name: '%s'\n", region->name); + dprintf("id: 0x%x\n", region->id); + dprintf("base: 0x%lx\n", region->base); + dprintf("size: 0x%lx\n", region->size); + dprintf("lock: 0x%x\n", region->lock); + dprintf("wiring: 0x%x\n", region->wiring); + dprintf("ref_count: %d\n", region->ref_count); + dprintf("cache_ref: %p\n", region->cache_ref); + // XXX 64-bit + dprintf("cache_offset: 0x%Lx\n", region->cache_offset); + dprintf("cache_next: %p\n", region->cache_next); + dprintf("cache_prev: %p\n", region->cache_prev); +} + +static void dump_region(int argc, char **argv) +{ +// int i; + vm_region *region; + + if(argc < 2) { + dprintf("region: not enough arguments\n"); + return; + } + + // if the argument looks like a hex number, treat it as such + if(strlen(argv[1]) > 2 && argv[1][0] == '0' && argv[1][1] == 'x') { + unsigned long num = atoul(argv[1]); + region_id id = num; + + region = hash_lookup(region_table, &id); + if(region == NULL) { + dprintf("invalid region id\n"); + } else { + _dump_region(region); + } + return; + } else { + // walk through the region list, looking for the arguments as a name + struct hash_iterator iter; + + hash_open(region_table, &iter); + while((region = hash_next(region_table, &iter)) != NULL) { + if(region->name != NULL && strcmp(argv[1], region->name) == 0) { + _dump_region(region); + } + } + } +} + +region_id find_region_by_address (addr vaddress) +{ + vm_address_space *aspace; + vm_region *region; + region_id result=B_ERROR; + + aspace = vm_get_current_user_aspace(); + for(region = aspace->virtual_map.region_list; region != NULL; region = region->aspace_next) + { + if ((vaddress>=region->base) && (vaddress<=(region->base+region->size))) + result=region->id; + } + vm_put_aspace(aspace); + return result; +} + +region_id find_region_by_name(const char *name) +{ + vm_region *region; + struct hash_iterator iter; + hash_open(region_table, &iter); + while((region = hash_next(region_table, &iter)) != NULL) + { + if (!strcmp(region->name,name)) + return region->id; + } + hash_close(region_table, &iter, false); + return B_NAME_NOT_FOUND; +} + +static void dump_region_list(int argc, char **argv) +{ + vm_region *region; + struct hash_iterator iter; + + dprintf("addr\tid\t%32s\tbase\t\tsize\tlock\twiring\n", "name"); + + hash_open(region_table, &iter); + while((region = hash_next(region_table, &iter)) != NULL) { + dprintf("%p\t0x%x\t%32s\t0x%lx\t\t0x%lx\t%d\t%d\n", + region, region->id, region->name, region->base, region->size, region->lock, region->wiring); + } + hash_close(region_table, &iter, false); +} + +static void _dump_aspace(vm_address_space *aspace) +{ + vm_region *region; + + dprintf("dump of address space at %p:\n", aspace); + dprintf("name: '%s'\n", aspace->name); + dprintf("id: 0x%x\n", aspace->id); + dprintf("ref_count: %d\n", aspace->ref_count); + dprintf("fault_count: %d\n", aspace->fault_count); + dprintf("working_set_size: 0x%lx\n", aspace->working_set_size); + dprintf("translation_map: %p\n", &aspace->translation_map); + dprintf("virtual_map.base: 0x%lx\n", aspace->virtual_map.base); + dprintf("virtual_map.size: 0x%lx\n", aspace->virtual_map.size); + dprintf("virtual_map.change_count: 0x%x\n", aspace->virtual_map.change_count); + dprintf("virtual_map.sem: 0x%x\n", aspace->virtual_map.sem); + dprintf("virtual_map.region_hint: %p\n", aspace->virtual_map.region_hint); + dprintf("virtual_map.region_list:\n"); + for(region = aspace->virtual_map.region_list; region != NULL; region = region->aspace_next) { + dprintf(" region 0x%x: ", region->id); + dprintf("base_addr = 0x%lx ", region->base); + dprintf("size = 0x%lx ", region->size); + dprintf("name = '%s' ", region->name); + dprintf("lock = 0x%x\n", region->lock); + } +} + +static void dump_aspace(int argc, char **argv) +{ +// int i; + vm_address_space *aspace; + + if(argc < 2) { + dprintf("aspace: not enough arguments\n"); + return; + } + + // if the argument looks like a hex number, treat it as such + if(strlen(argv[1]) > 2 && argv[1][0] == '0' && argv[1][1] == 'x') { + unsigned long num = atoul(argv[1]); + aspace_id id = num; + + aspace = hash_lookup(aspace_table, &id); + if(aspace == NULL) { + dprintf("invalid aspace id\n"); + } else { + _dump_aspace(aspace); + } + return; + } else { + // walk through the aspace list, looking for the arguments as a name + struct hash_iterator iter; + + hash_open(aspace_table, &iter); + while((aspace = hash_next(aspace_table, &iter)) != NULL) { + if(aspace->name != NULL && strcmp(argv[1], aspace->name) == 0) { + _dump_aspace(aspace); + } + } + } +} + +static void dump_aspace_list(int argc, char **argv) +{ + vm_address_space *as; + struct hash_iterator iter; + + dprintf("addr\tid\t%32s\tbase\t\tsize\n", "name"); + + hash_open(aspace_table, &iter); + while((as = hash_next(aspace_table, &iter)) != NULL) { + dprintf("%p\t0x%x\t%32s\t0x%lx\t\t0x%lx\n", + as, as->id, as->name, as->virtual_map.base, as->virtual_map.size); + } + hash_close(aspace_table, &iter, false); +} + +vm_address_space *vm_get_kernel_aspace(void) +{ + /* we can treat this one a little differently since it can't be deleted */ + acquire_sem_etc(aspace_hash_sem, READ_COUNT, 0, 0); + atomic_add(&kernel_aspace->ref_count, 1); + release_sem_etc(aspace_hash_sem, READ_COUNT, 0); + return kernel_aspace; +} + +aspace_id vm_get_kernel_aspace_id(void) +{ + return kernel_aspace->id; +} + +vm_address_space *vm_get_current_user_aspace(void) +{ + return vm_get_aspace_by_id(vm_get_current_user_aspace_id()); +} + +aspace_id vm_get_current_user_aspace_id(void) +{ + struct thread *t = thread_get_current_thread(); + + if(t) + return t->proc->_aspace_id; + else + return -1; +} + +void vm_put_aspace(vm_address_space *aspace) +{ +// vm_region *region; + bool removeit = false; + + acquire_sem_etc(aspace_hash_sem, WRITE_COUNT, 0, 0); + if(atomic_add(&aspace->ref_count, -1) == 1) { + hash_remove(aspace_table, aspace); + removeit = true; + } + release_sem_etc(aspace_hash_sem, WRITE_COUNT, 0); + + if(!removeit) + return; + + dprintf("vm_put_aspace: reached zero ref, deleting aspace\n"); + + if(aspace == kernel_aspace) + panic("vm_put_aspace: tried to delete the kernel aspace!\n"); + + if(aspace->virtual_map.region_list) + panic("vm_put_aspace: aspace at %p has zero ref count, but region list isn't empty!\n", aspace); + + (*aspace->translation_map.ops->destroy)(&aspace->translation_map); + + kfree(aspace->name); + delete_sem(aspace->virtual_map.sem); + kfree(aspace); + + return; +} + +aspace_id vm_create_aspace(const char *name, addr base, addr size, bool kernel) +{ + vm_address_space *aspace; + int err; + + + aspace = (vm_address_space *)kmalloc(sizeof(vm_address_space)); + if(aspace == NULL) + return ENOMEM; + + dprintf("vm_create_aspace: %s: %lx bytes starting at 0x%lx => %p\n", name, size, base, aspace); + + aspace->name = (char *)kmalloc(strlen(name) + 1); + if(aspace->name == NULL ) { + kfree(aspace); + return ENOMEM; + } + strcpy(aspace->name, name); + + aspace->id = next_aspace_id++; + aspace->ref_count = 1; + aspace->state = VM_ASPACE_STATE_NORMAL; + aspace->fault_count = 0; + aspace->scan_va = base; + aspace->working_set_size = kernel ? DEFAULT_KERNEL_WORKING_SET : DEFAULT_WORKING_SET; + aspace->max_working_set = DEFAULT_MAX_WORKING_SET; + aspace->min_working_set = DEFAULT_MIN_WORKING_SET; + aspace->last_working_set_adjust = system_time(); + + // initialize the corresponding translation map + err = vm_translation_map_create(&aspace->translation_map, kernel); + if(err < 0) { + kfree(aspace->name); + kfree(aspace); + return err; + } + + // initialize the virtual map + aspace->virtual_map.base = base; + aspace->virtual_map.size = size; + aspace->virtual_map.region_list = NULL; + aspace->virtual_map.region_hint = NULL; + aspace->virtual_map.change_count = 0; + aspace->virtual_map.sem = create_sem(WRITE_COUNT, "aspacelock"); + aspace->virtual_map.aspace = aspace; + + // add the aspace to the global hash table + acquire_sem_etc(aspace_hash_sem, WRITE_COUNT, 0, 0); + hash_insert(aspace_table, aspace); + release_sem_etc(aspace_hash_sem, WRITE_COUNT, 0); + + return aspace->id; +} + +int vm_delete_aspace(aspace_id aid) +{ + vm_region *region; + vm_region *next; + vm_address_space *aspace; + + aspace = vm_get_aspace_by_id(aid); + if(aspace == NULL) + return ERR_VM_INVALID_ASPACE; + + dprintf("vm_delete_aspace: called on aspace 0x%x\n", aid); + + // put this aspace in the deletion state + // this guarantees that no one else will add regions to the list + acquire_sem_etc(aspace->virtual_map.sem, WRITE_COUNT, 0, 0); + if(aspace->state == VM_ASPACE_STATE_DELETION) { + // abort, someone else is already deleting this aspace + release_sem_etc(aspace->virtual_map.sem, WRITE_COUNT, 0); + vm_put_aspace(aspace); + return B_NO_ERROR; + } + aspace->state = VM_ASPACE_STATE_DELETION; + + // delete all the regions in this aspace + region = aspace->virtual_map.region_list; + while(region) { + next = region->aspace_next; + // decrement the ref on this region, may actually push the ref < 0, but that's okay + _vm_put_region(region, true); + region = next; + } + + // unlock + release_sem_etc(aspace->virtual_map.sem, WRITE_COUNT, 0); + + // release two refs on the address space + vm_put_aspace(aspace); + vm_put_aspace(aspace); + + return B_NO_ERROR; +} + +int vm_resize_region (aspace_id aid, region_id rid, size_t newSize) +{ + vm_cache_ref *myCacheRef; + vm_region *myRegion,*current; + size_t oldSize; + bool failed=false; +// Steps: +//1) Get the vm_cache_ref for the region + myRegion=vm_get_region_by_id(rid); + + if (!myRegion) + return B_ERROR; + + myCacheRef=myRegion->cache_ref; +// 2) Resize all of the regions from the vm_cache_ref (fix them all and fail if they can't be resized) + oldSize = myRegion->size; + for (current=myCacheRef->region_list;current;current=current->cache_next) + { + if (current->aspace_next->base<=(current->base+newSize)) + { + failed=true; + break; + } + current->size=newSize; + } + if (failed) // OH NO! Go back and fix all of the broken ones... + { + for (current=myCacheRef->region_list;current;current=current->cache_next) + current->size=oldSize; + return B_ERROR; + } +// 3) Update the vm_cache size + myCacheRef->cache->virtual_size=newSize; +} + +int vm_aspace_walk_start(struct hash_iterator *i) +{ + hash_open(aspace_table, i); + return 0; +} + +vm_address_space *vm_aspace_walk_next(struct hash_iterator *i) +{ + vm_address_space *aspace; + + acquire_sem_etc(aspace_hash_sem, READ_COUNT, 0, 0); + aspace = hash_next(aspace_table, i); + if(aspace) + atomic_add(&aspace->ref_count, 1); + release_sem_etc(aspace_hash_sem, READ_COUNT, 0); + return aspace; +} + +static int vm_thread_dump_max_commit(void *unused) +{ + int oldmax = -1; + + (void)(unused); + + for(;;) { + thread_snooze(1000000); + if(oldmax != max_commit) + dprintf("max_commit 0x%x\n", max_commit); + oldmax = max_commit; + } +} + +int vm_init(kernel_args *ka) +{ + int err = 0; + unsigned int i; +// int last_used_virt_range = -1; +// int last_used_phys_range = -1; + addr heap_base; + void *null_addr; + + dprintf("vm_init: entry\n"); + err = vm_translation_map_module_init(ka); + err = arch_vm_init(ka); + + // initialize some globals + kernel_aspace = NULL; + next_region_id = 0; + region_hash_sem = -1; + next_aspace_id = 0; + aspace_hash_sem = -1; + max_commit = 0; // will be increased in vm_page_init + max_commit_lock = 0; + + // map in the new heap and initialize it + heap_base = vm_alloc_from_ka_struct(ka, HEAP_SIZE, LOCK_KERNEL|LOCK_RW); + dprintf("heap at 0x%lx\n", heap_base); + heap_init(heap_base, HEAP_SIZE); + + // initialize the free page list and physical page mapper + vm_page_init(ka); + + // initialize the hash table that stores the pages mapped to caches + vm_cache_init(ka); + + // create the region and address space hash tables + { + vm_address_space *aspace; + aspace_table = hash_init(ASPACE_HASH_TABLE_SIZE, (addr)&aspace->hash_next - (addr)aspace, + &aspace_compare, &aspace_hash); + if(aspace_table == NULL) + panic("vm_init: error creating aspace hash table\n"); + } + { + vm_region *region; + region_table = hash_init(REGION_HASH_TABLE_SIZE, (addr)®ion->hash_next - (addr)region, + ®ion_compare, ®ion_hash); + if(region_table == NULL) + panic("vm_init: error creating aspace hash table\n"); + } + + + // create the initial kernel address space + { + aspace_id aid; + aid = vm_create_aspace("kernel_land", KERNEL_BASE, KERNEL_SIZE, true); + if(aid < 0) + panic("vm_init: error creating kernel address space!\n"); + kernel_aspace = vm_get_aspace_by_id(aid); + vm_put_aspace(kernel_aspace); + } + + // do any further initialization that the architecture dependant layers may need now + vm_translation_map_module_init2(ka); + arch_vm_init2(ka); + vm_page_init2(ka); + + // allocate regions to represent stuff that already exists + null_addr = (void *)ROUNDOWN(heap_base, PAGE_SIZE); + vm_create_anonymous_region(vm_get_kernel_aspace_id(), "kernel_heap", &null_addr, REGION_ADDR_EXACT_ADDRESS, + HEAP_SIZE, REGION_WIRING_WIRED_ALREADY, LOCK_RW|LOCK_KERNEL); + + null_addr = (void *)ROUNDOWN(ka->kernel_seg0_addr.start, PAGE_SIZE); + vm_create_anonymous_region(vm_get_kernel_aspace_id(), "kernel_ro", &null_addr, REGION_ADDR_EXACT_ADDRESS, + PAGE_ALIGN(ka->kernel_seg0_addr.size), REGION_WIRING_WIRED_ALREADY, LOCK_RW|LOCK_KERNEL); + + if(ka->kernel_seg1_addr.size > 0) { + null_addr = (void *)ROUNDOWN(ka->kernel_seg1_addr.start, PAGE_SIZE); + vm_create_anonymous_region(vm_get_kernel_aspace_id(), "kernel_rw", &null_addr, REGION_ADDR_EXACT_ADDRESS, + PAGE_ALIGN(ka->kernel_seg1_addr.size), REGION_WIRING_WIRED_ALREADY, LOCK_RW|LOCK_KERNEL); + } + for(i=0; i < ka->num_cpus; i++) { + char temp[64]; + + sprintf(temp, "idle_thread%d_kstack", i); + null_addr = (void *)ka->cpu_kstack[i].start; + vm_create_anonymous_region(vm_get_kernel_aspace_id(), temp, &null_addr, REGION_ADDR_EXACT_ADDRESS, + ka->cpu_kstack[i].size, REGION_WIRING_WIRED_ALREADY, LOCK_RW|LOCK_KERNEL); + } + { + void *null; + vm_map_physical_memory(vm_get_kernel_aspace_id(), "bootdir", &null, REGION_ADDR_ANY_ADDRESS, + ka->bootdir_addr.size, LOCK_RO|LOCK_KERNEL, ka->bootdir_addr.start); + } + + arch_vm_init_endvm(ka); + + // add some debugger commands + dbg_add_command(&dump_region_list, "regions", "Dump a list of all regions"); + dbg_add_command(&dump_region, "region", "Dump info about a particular region"); + dbg_add_command(&dump_aspace_list, "aspaces", "Dump a list of all address spaces"); + dbg_add_command(&dump_aspace, "aspace", "Dump info about a particular address space"); + dbg_add_command(&dump_cache_ref, "cache_ref", "Dump cache_ref data structure"); + dbg_add_command(&dump_cache, "cache", "Dump cache_ref data structure"); +// dbg_add_command(&display_mem, "dl", "dump memory long words (64-bit)"); + dbg_add_command(&display_mem, "dw", "dump memory words (32-bit)"); + dbg_add_command(&display_mem, "ds", "dump memory shorts (16-bit)"); + dbg_add_command(&display_mem, "db", "dump memory bytes (8-bit)"); + + dprintf("vm_init: exit\n"); + + return err; +} + +int vm_init_postsem(kernel_args *ka) +{ + vm_region *region; + + // fill in all of the semaphores that were not allocated before + // since we're still single threaded and only the kernel address space exists, + // it isn't that hard to find all of the ones we need to create + vm_translation_map_module_init_post_sem(ka); + kernel_aspace->virtual_map.sem = create_sem(WRITE_COUNT, "kernel_aspacelock"); + kernel_aspace->translation_map.lock.sem = create_sem(1, "recursive_lock"); + + for(region = kernel_aspace->virtual_map.region_list; region; region = region->aspace_next) { + if(region->cache_ref->lock.sem < 0) { + region->cache_ref->lock.sem = create_sem(1, "cache_ref_mutex"); + } + } + + region_hash_sem = create_sem(WRITE_COUNT, "region_hash_sem"); + aspace_hash_sem = create_sem(WRITE_COUNT, "aspace_hash_sem"); + + return heap_init_postsem(ka); +} + +int vm_init_postthread(kernel_args *ka) +{ + vm_page_init_postthread(ka); + + { + thread_id tid = thread_create_kernel_thread("max_commit_thread", &vm_thread_dump_max_commit, NULL); + thread_resume_thread(tid); + } + + vm_daemon_init(); + + return 0; +} + +int vm_page_fault(addr address, addr fault_address, bool is_write, bool is_user, addr *newip) +{ + int err; + +// dprintf("vm_page_fault: page fault at 0x%x, ip 0x%x\n", address, fault_address); + + *newip = 0; + + err = vm_soft_fault(address, is_write, is_user); + if(err < 0) { + dprintf("vm_page_fault: vm_soft_fault returned error %d on fault at 0x%lx, ip 0x%lx, write %d, user %d, thread 0x%x\n", + err, address, fault_address, is_write, is_user, thread_get_current_thread_id()); + if(!is_user) { + struct thread *t = thread_get_current_thread(); + if(t && t->fault_handler != 0) { + // this will cause the arch dependant page fault handler to + // modify the IP on the interrupt frame or whatever to return + // to this address + *newip = t->fault_handler; + } else { + // unhandled page fault in the kernel + panic("vm_page_fault: unhandled page fault in kernel space at 0x%lx, ip 0x%lx\n", + address, fault_address); + } + } else { + dprintf("vm_page_fault: killing process 0x%x\n", thread_get_current_thread()->proc->id); + proc_kill_proc(thread_get_current_thread()->proc->id); + } + } + + return INT_NO_RESCHEDULE; +} + +#define TRACE_PFAULT 0 + +#if TRACE_PFAULT +#define TRACE dprintf("in pfault at line %d\n", __LINE__) +#else +#define TRACE +#endif + +static int vm_soft_fault(addr address, bool is_write, bool is_user) +{ + vm_address_space *aspace; + vm_virtual_map *map; + vm_region *region; + vm_cache_ref *cache_ref; + vm_cache_ref *last_cache_ref; + vm_cache_ref *top_cache_ref; + off_t cache_offset; + vm_page dummy_page; + vm_page *page = NULL; + int change_count; + int err; + +// dprintf("vm_soft_fault: thid 0x%x address 0x%x, is_write %d, is_user %d\n", +// thread_get_current_thread_id(), address, is_write, is_user); + + address = ROUNDOWN(address, PAGE_SIZE); + + if(address >= KERNEL_BASE && address <= KERNEL_TOP) { + aspace = vm_get_kernel_aspace(); + } else if(address >= USER_BASE && address <= USER_TOP) { + aspace = vm_get_current_user_aspace(); + if(aspace == NULL) { + if(is_user == false) { + dprintf("vm_soft_fault: kernel thread accessing invalid user memory!\n"); + return ERR_VM_PF_FATAL; + } else { + // XXX weird state. + panic("vm_soft_fault: non kernel thread accessing user memory that doesn't exist!\n"); + } + } + } else { + // the hit was probably in the 64k DMZ between kernel and user space + // this keeps a user space thread from passing a buffer that crosses into kernel space + return ERR_VM_PF_FATAL; + } + map = &aspace->virtual_map; + atomic_add(&aspace->fault_count, 1); + + acquire_sem_etc(map->sem, READ_COUNT, 0, 0); + region = vm_virtual_map_lookup(map, address); + if(region == NULL) { + release_sem_etc(map->sem, READ_COUNT, 0); + vm_put_aspace(aspace); + dprintf("vm_soft_fault: va 0x%lx not covered by region in address space\n", address); + return ERR_VM_PF_BAD_ADDRESS; // BAD_ADDRESS + } + + // check permissions + if(is_user && (region->lock & LOCK_KERNEL) == LOCK_KERNEL) { + release_sem_etc(map->sem, READ_COUNT, 0); + vm_put_aspace(aspace); + dprintf("user access on kernel region\n"); + return ERR_VM_PF_BAD_PERM; // BAD_PERMISSION + } + if(is_write && (region->lock & LOCK_RW) == 0) { + release_sem_etc(map->sem, READ_COUNT, 0); + vm_put_aspace(aspace); + dprintf("write access attempted on read-only region\n"); + return ERR_VM_PF_BAD_PERM; // BAD_PERMISSION + } + + TRACE; + + top_cache_ref = region->cache_ref; + cache_offset = address - region->base + region->cache_offset; + vm_cache_acquire_ref(top_cache_ref, true); + change_count = map->change_count; + release_sem_etc(map->sem, READ_COUNT, 0); + + // see if this cache has a fault handler + if(top_cache_ref->cache->store->ops->fault) { + int err = (*top_cache_ref->cache->store->ops->fault)(top_cache_ref->cache->store, aspace, cache_offset); + vm_cache_release_ref(top_cache_ref); + vm_put_aspace(aspace); + return err; + } + + TRACE; + + dummy_page.state = PAGE_STATE_INACTIVE; + dummy_page.type = PAGE_TYPE_DUMMY; + + last_cache_ref = top_cache_ref; + for(cache_ref = top_cache_ref; cache_ref; cache_ref = (cache_ref->cache->source) ? cache_ref->cache->source->ref : NULL) { + mutex_lock(&cache_ref->lock); + + TRACE; + + for(;;) { + page = vm_cache_lookup_page(cache_ref, cache_offset); + if(page != NULL && page->state != PAGE_STATE_BUSY) { + vm_page_set_state(page, PAGE_STATE_BUSY); + mutex_unlock(&cache_ref->lock); + break; + } + + if(page == NULL) + break; + + TRACE; + + // page must be busy + mutex_unlock(&cache_ref->lock); + thread_snooze(20000); + mutex_lock(&cache_ref->lock); + } + + TRACE; + + if(page != NULL) + break; + + TRACE; + + // insert this dummy page here to keep other threads from faulting on the + // same address and chasing us up the cache chain + if(cache_ref == top_cache_ref) { + dummy_page.state = PAGE_STATE_BUSY; + vm_cache_insert_page(cache_ref, &dummy_page, cache_offset); + } + + // see if the vm_store has it + if(cache_ref->cache->store->ops->has_page) { + if(cache_ref->cache->store->ops->has_page(cache_ref->cache->store, cache_offset)) { + IOVECS(vecs, 1); + + TRACE; + + mutex_unlock(&cache_ref->lock); + + vecs->num = 1; + vecs->total_len = PAGE_SIZE; + vecs->vec[0].iov_len = PAGE_SIZE; + + page = vm_page_allocate_page(PAGE_STATE_FREE); + (*aspace->translation_map.ops->get_physical_page)(page->ppn * PAGE_SIZE, (addr *)&vecs->vec[0].iov_base, PHYSICAL_PAGE_CAN_WAIT); + // handle errors here + err = cache_ref->cache->store->ops->read(cache_ref->cache->store, cache_offset, vecs); + (*aspace->translation_map.ops->put_physical_page)((addr)vecs->vec[0].iov_base); + + mutex_lock(&cache_ref->lock); + + if(cache_ref == top_cache_ref) { + vm_cache_remove_page(cache_ref, &dummy_page); + dummy_page.state = PAGE_STATE_INACTIVE; + } + vm_cache_insert_page(cache_ref, page, cache_offset); + mutex_unlock(&cache_ref->lock); + break; + } + } + mutex_unlock(&cache_ref->lock); + last_cache_ref = cache_ref; + TRACE; + } + + TRACE; + + // we rolled off the end of the cache chain, so we need to decide which + // cache will get the new page we're about to create + if(!cache_ref) { + if(!is_write) + cache_ref = last_cache_ref; // put it in the deepest cache + else + cache_ref = top_cache_ref; // put it in the topmost cache + } + + TRACE; + + if(page == NULL) { + // still haven't found a page, so zero out a new one + page = vm_page_allocate_page(PAGE_STATE_CLEAR); +// dprintf("vm_soft_fault: just allocated page 0x%x\n", page->ppn); + mutex_lock(&cache_ref->lock); + if(dummy_page.state == PAGE_STATE_BUSY && dummy_page.cache_ref == cache_ref) { + vm_cache_remove_page(cache_ref, &dummy_page); + dummy_page.state = PAGE_STATE_INACTIVE; + } + vm_cache_insert_page(cache_ref, page, cache_offset); + mutex_unlock(&cache_ref->lock); + if(dummy_page.state == PAGE_STATE_BUSY) { + vm_cache_ref *temp_cache = dummy_page.cache_ref; + mutex_lock(&temp_cache->lock); + vm_cache_remove_page(temp_cache, &dummy_page); + mutex_unlock(&temp_cache->lock); + dummy_page.state = PAGE_STATE_INACTIVE; + } + } + + TRACE; + + if(page->cache_ref != top_cache_ref && is_write) { + // now we have a page that has the data we want, but in the wrong cache object + // so we need to copy it and stick it into the top cache + vm_page *src_page = page; + void *src, *dest; + + page = vm_page_allocate_page(PAGE_STATE_FREE); + + // try to get a mapping for the src and dest page so we can copy it + for(;;) { + (*aspace->translation_map.ops->get_physical_page)(src_page->ppn * PAGE_SIZE, (addr *)&src, PHYSICAL_PAGE_CAN_WAIT); + err = (*aspace->translation_map.ops->get_physical_page)(page->ppn * PAGE_SIZE, (addr *)&dest, PHYSICAL_PAGE_NO_WAIT); + if(err == B_NO_ERROR) + break; + + // it couldn't map the second one, so sleep and retry + // keeps an extremely rare deadlock from occuring + (*aspace->translation_map.ops->put_physical_page)((addr)src); + thread_snooze(5000); + } + + memcpy(dest, src, PAGE_SIZE); + (*aspace->translation_map.ops->put_physical_page)((addr)src); + (*aspace->translation_map.ops->put_physical_page)((addr)dest); + + vm_page_set_state(src_page, PAGE_STATE_ACTIVE); + + mutex_lock(&top_cache_ref->lock); + if(dummy_page.state == PAGE_STATE_BUSY && dummy_page.cache_ref == top_cache_ref) { + vm_cache_remove_page(top_cache_ref, &dummy_page); + dummy_page.state = PAGE_STATE_INACTIVE; + } + vm_cache_insert_page(top_cache_ref, page, cache_offset); + mutex_unlock(&top_cache_ref->lock); + + if(dummy_page.state == PAGE_STATE_BUSY) { + vm_cache_ref *temp_cache = dummy_page.cache_ref; + mutex_lock(&temp_cache->lock); + vm_cache_remove_page(temp_cache, &dummy_page); + mutex_unlock(&temp_cache->lock); + dummy_page.state = PAGE_STATE_INACTIVE; + } + } + + TRACE; + + err = 0; + acquire_sem_etc(map->sem, READ_COUNT, 0, 0); + if(change_count != map->change_count) { + // something may have changed, see if the address is still valid + region = vm_virtual_map_lookup(map, address); + if(region == NULL + || region->cache_ref != top_cache_ref + || (address - region->base + region->cache_offset) != cache_offset) { + dprintf("vm_soft_fault: address space layout changed effecting ongoing soft fault\n"); + err = ERR_VM_PF_BAD_ADDRESS; // BAD_ADDRESS + } + } + + TRACE; + + if(err == 0) { + int new_lock = region->lock; + if(page->cache_ref != top_cache_ref && !is_write) + new_lock &= ~LOCK_RW; + + atomic_add(&page->ref_count, 1); + (*aspace->translation_map.ops->lock)(&aspace->translation_map); + (*aspace->translation_map.ops->map)(&aspace->translation_map, address, + page->ppn * PAGE_SIZE, new_lock); + (*aspace->translation_map.ops->unlock)(&aspace->translation_map); + } + + TRACE; + + release_sem_etc(map->sem, READ_COUNT, 0); + + TRACE; + + if(dummy_page.state == PAGE_STATE_BUSY) { + vm_cache_ref *temp_cache = dummy_page.cache_ref; + mutex_lock(&temp_cache->lock); + vm_cache_remove_page(temp_cache, &dummy_page); + mutex_unlock(&temp_cache->lock); + dummy_page.state = PAGE_STATE_INACTIVE; + } + + TRACE; + + vm_page_set_state(page, PAGE_STATE_ACTIVE); + + vm_cache_release_ref(top_cache_ref); + vm_put_aspace(aspace); + + TRACE; + + return err; +} + +static vm_region *vm_virtual_map_lookup(vm_virtual_map *map, addr address) +{ + vm_region *region; + + // check the region_list region first + region = map->region_hint; + if(region && region->base <= address && (region->base + region->size) > address) + return region; + + for(region = map->region_list; region != NULL; region = region->aspace_next) { + if(region->base <= address && (region->base + region->size) > address) + break; + } + + if(region) + map->region_hint = region; + return region; +} + +int vm_get_physical_page(addr paddr, addr *vaddr, int flags) +{ + return (*kernel_aspace->translation_map.ops->get_physical_page)(paddr, vaddr, flags); +} + +int vm_put_physical_page(addr vaddr) +{ + return (*kernel_aspace->translation_map.ops->put_physical_page)(vaddr); +} + +void vm_increase_max_commit(addr delta) +{ + int state; + +// dprintf("vm_increase_max_commit: delta 0x%x\n", delta); + + state = int_disable_interrupts(); + acquire_spinlock(&max_commit_lock); + max_commit += delta; + release_spinlock(&max_commit_lock); + int_restore_interrupts(state); +} + +int user_memcpy(void *to, const void *from, size_t size) +{ + return arch_cpu_user_memcpy(to, from, size, &thread_get_current_thread()->fault_handler); +} + +int user_strcpy(char *to, const char *from) +{ + return arch_cpu_user_strcpy(to, from, &thread_get_current_thread()->fault_handler); +} + +int user_strncpy(char *to, const char *from, size_t size) +{ + return arch_cpu_user_strncpy(to, from, size, &thread_get_current_thread()->fault_handler); +} + +int user_memset(void *s, char c, size_t count) +{ + return arch_cpu_user_memset(s, c, count, &thread_get_current_thread()->fault_handler); +} + diff --git a/src/kernel/core/vm/vm_cache.c b/src/kernel/core/vm/vm_cache.c new file mode 100755 index 0000000000..9b6dbe5e91 --- /dev/null +++ b/src/kernel/core/vm/vm_cache.c @@ -0,0 +1,282 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* hash table of pages keyed by cache they're in and offset */ +#define PAGE_TABLE_SIZE 1024 /* make this dynamic */ +static void *page_cache_table; +static spinlock_t page_cache_table_lock; + +struct page_lookup_key { + off_t offset; + vm_cache_ref *ref; +}; + +static int page_compare_func(void *_p, const void *_key) +{ + vm_page *p = _p; + const struct page_lookup_key *key = _key; + +// dprintf("page_compare_func: p 0x%x, key 0x%x\n", p, key); + + if(p->cache_ref == key->ref && p->offset == key->offset) + return 0; + else + return -1; +} + +#define HASH(offset, ref) ((unsigned int)(offset >> 12) ^ ((unsigned int)(ref)>>4)) + +static unsigned int page_hash_func(void *_p, const void *_key, unsigned int range) +{ + vm_page *p = _p; + const struct page_lookup_key *key = _key; +#if 0 + if(p) + dprintf("page_hash_func: p 0x%x, key 0x%x, HASH = 0x%x\n", p, key, HASH(p->offset, p->cache_ref) % range); + else + dprintf("page_hash_func: p 0x%x, key 0x%x, HASH = 0x%x\n", p, key, HASH(key->offset, key->ref) % range); +#endif + if(p) + return HASH(p->offset, p->cache_ref) % range; + else + return HASH(key->offset, key->ref) % range; +} + +int vm_cache_init(kernel_args *ka) +{ + vm_page p; + + page_cache_table = hash_init(PAGE_TABLE_SIZE, + (int)&p.hash_next - (int)&p, + &page_compare_func, + &page_hash_func); + if(!page_cache_table) + panic("vm_cache_init: cannot allocate memory for page cache hash table\n"); + page_cache_table_lock = 0; + + return 0; +} + +vm_cache *vm_cache_create(vm_store *store) +{ + vm_cache *cache; + + cache = kmalloc(sizeof(vm_cache)); + if(cache == NULL) + return NULL; + + cache->page_list = NULL; + cache->ref = NULL; + cache->source = NULL; + cache->store = store; + if(store != NULL) + store->cache = cache; + cache->virtual_size = 0; + cache->temporary = 0; + cache->scan_skip = 0; + + return cache; +} + +vm_cache_ref *vm_cache_ref_create(vm_cache *cache) +{ + vm_cache_ref *ref; + + ref = kmalloc(sizeof(vm_cache_ref)); + if(ref == NULL) + return NULL; + + ref->cache = cache; + mutex_init(&ref->lock, "cache_ref_mutex"); + ref->region_list = NULL; + ref->ref_count = 0; + cache->ref = ref; + + return ref; +} + +void vm_cache_acquire_ref(vm_cache_ref *cache_ref, bool acquire_store_ref) +{ +// dprintf("vm_cache_acquire_ref: cache_ref 0x%x, ref will be %d\n", cache_ref, cache_ref->ref_count+1); + + if(cache_ref == NULL) + panic("vm_cache_acquire_ref: passed NULL\n"); + if(acquire_store_ref && cache_ref->cache->store->ops->acquire_ref) { + cache_ref->cache->store->ops->acquire_ref(cache_ref->cache->store); + } + atomic_add(&cache_ref->ref_count, 1); +} + +void vm_cache_release_ref(vm_cache_ref *cache_ref) +{ + vm_page *page; + +// dprintf("vm_cache_release_ref: cache_ref 0x%x, ref will be %d\n", cache_ref, cache_ref->ref_count-1); + + if(cache_ref == NULL) + panic("vm_cache_release_ref: passed NULL\n"); + if(atomic_add(&cache_ref->ref_count, -1) == 1) { + // delete this cache + // delete the cache's backing store, if it has one + off_t store_committed_size = 0; + if(cache_ref->cache->store) { + store_committed_size = cache_ref->cache->store->committed_size; + (*cache_ref->cache->store->ops->destroy)(cache_ref->cache->store); + } + + // free all of the pages in the cache + page = cache_ref->cache->page_list; + while(page) { + vm_page *old_page = page; + int state; + + page = page->cache_next; + + // remove it from the hash table + state = int_disable_interrupts(); + acquire_spinlock(&page_cache_table_lock); + + hash_remove(page_cache_table, old_page); + + release_spinlock(&page_cache_table_lock); + int_restore_interrupts(state); + +// dprintf("vm_cache_release_ref: freeing page 0x%x\n", old_page->ppn); + vm_page_set_state(old_page, PAGE_STATE_FREE); + } + vm_increase_max_commit(cache_ref->cache->virtual_size - store_committed_size); + + // remove the ref to the source + if(cache_ref->cache->source) + vm_cache_release_ref(cache_ref->cache->source->ref); + + mutex_destroy(&cache_ref->lock); + kfree(cache_ref->cache); + kfree(cache_ref); + + return; + } + if(cache_ref->cache->store->ops->release_ref) { + cache_ref->cache->store->ops->release_ref(cache_ref->cache->store); + } +} + +vm_page *vm_cache_lookup_page(vm_cache_ref *cache_ref, off_t offset) +{ + vm_page *page; + int state; + struct page_lookup_key key; + + key.offset = offset; + key.ref = cache_ref; + + state = int_disable_interrupts(); + acquire_spinlock(&page_cache_table_lock); + + page = hash_lookup(page_cache_table, &key); + + release_spinlock(&page_cache_table_lock); + int_restore_interrupts(state); + + return page; +} + +void vm_cache_insert_page(vm_cache_ref *cache_ref, vm_page *page, off_t offset) +{ + int state; + +// dprintf("vm_cache_insert_page: cache 0x%x, page 0x%x, offset 0x%x 0x%x\n", cache_ref, page, offset); + + page->offset = offset; + + if(cache_ref->cache->page_list != NULL) { + cache_ref->cache->page_list->cache_prev = page; + } + page->cache_next = cache_ref->cache->page_list; + page->cache_prev = NULL; + cache_ref->cache->page_list = page; + + page->cache_ref = cache_ref; + + state = int_disable_interrupts(); + acquire_spinlock(&page_cache_table_lock); + + hash_insert(page_cache_table, page); + + release_spinlock(&page_cache_table_lock); + int_restore_interrupts(state); + +} + +void vm_cache_remove_page(vm_cache_ref *cache_ref, vm_page *page) +{ + int state; + +// dprintf("vm_cache_remove_page: cache 0x%x, page 0x%x\n", cache_ref, page); + + state = int_disable_interrupts(); + acquire_spinlock(&page_cache_table_lock); + + hash_remove(page_cache_table, page); + + release_spinlock(&page_cache_table_lock); + int_restore_interrupts(state); + + if(cache_ref->cache->page_list == page) { + if(page->cache_next != NULL) + page->cache_next->cache_prev = NULL; + cache_ref->cache->page_list = page->cache_next; + } else { + if(page->cache_prev != NULL) + page->cache_prev->cache_next = page->cache_next; + if(page->cache_next != NULL) + page->cache_next->cache_prev = page->cache_prev; + } + page->cache_ref = NULL; +} + +int vm_cache_insert_region(vm_cache_ref *cache_ref, vm_region *region) +{ + mutex_lock(&cache_ref->lock); + + region->cache_next = cache_ref->region_list; + if(region->cache_next) + region->cache_next->cache_prev = region; + region->cache_prev = NULL; + cache_ref->region_list = region; + + mutex_unlock(&cache_ref->lock); + return 0; +} + +int vm_cache_remove_region(vm_cache_ref *cache_ref, vm_region *region) +{ + mutex_lock(&cache_ref->lock); + + if(region->cache_prev) + region->cache_prev->cache_next = region->cache_next; + if(region->cache_next) + region->cache_next->cache_prev = region->cache_prev; + if(cache_ref->region_list == region) + cache_ref->region_list = region->cache_next; + + mutex_unlock(&cache_ref->lock); + return 0; +} diff --git a/src/kernel/core/vm/vm_daemons.c b/src/kernel/core/vm/vm_daemons.c new file mode 100755 index 0000000000..43bab94c63 --- /dev/null +++ b/src/kernel/core/vm/vm_daemons.c @@ -0,0 +1,209 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +bool trimming_cycle; +static addr free_memory_low_water; +static addr free_memory_high_water; + +static void scan_pages(vm_address_space *aspace, addr free_target) +{ + vm_region *first_region; + vm_region *region; + vm_page *page; + addr va; + addr pa; + unsigned int flags, flags2; +// int err; + int quantum = PAGE_SCAN_QUANTUM; + +// dprintf("scan_pages called on aspace 0x%x, id 0x%x, free_target %d\n", aspace, aspace->id, free_target); + + acquire_sem_etc(aspace->virtual_map.sem, READ_COUNT, 0, 0); + + first_region = aspace->virtual_map.region_list; + while(first_region && (first_region->base + (first_region->size - 1)) < aspace->scan_va) + first_region = first_region->aspace_next; + + if(!first_region) + first_region = aspace->virtual_map.region_list; + + if(!first_region) { + release_sem_etc(aspace->virtual_map.sem, READ_COUNT, 0); + return; + } + + region = first_region; + for(;;) { + // scan the pages in this region + mutex_lock(®ion->cache_ref->lock); + if(!region->cache_ref->cache->scan_skip) { + for(va = region->base; va < (region->base + region->size); va += PAGE_SIZE) { + aspace->translation_map.ops->lock(&aspace->translation_map); + aspace->translation_map.ops->query(&aspace->translation_map, va, &pa, &flags); + if((flags & PAGE_PRESENT) == 0) { + aspace->translation_map.ops->unlock(&aspace->translation_map); + continue; + } + + page = vm_lookup_page(pa); + if(!page) { + aspace->translation_map.ops->unlock(&aspace->translation_map); + continue; + } + + // see if this page is busy, if it is lets forget it and move on + if(page->state == PAGE_STATE_BUSY || page->state == PAGE_STATE_WIRED) { + aspace->translation_map.ops->unlock(&aspace->translation_map); + continue; + } + + flags2 = 0; + if(free_target > 0) { + // look for a page we can steal + if(!(flags & PAGE_ACCESSED) && page->state == PAGE_STATE_ACTIVE) { + // unmap the page + aspace->translation_map.ops->unmap(&aspace->translation_map, va, va + PAGE_SIZE); + + // flush the tlbs of all cpus + aspace->translation_map.ops->flush(&aspace->translation_map); + + // re-query the flags on the old pte, to make sure we have accurate modified bit data + aspace->translation_map.ops->query(&aspace->translation_map, va, &pa, &flags2); + + // clear the modified and accessed bits on the entries + aspace->translation_map.ops->clear_flags(&aspace->translation_map, va, PAGE_MODIFIED|PAGE_ACCESSED); + + // decrement the ref count on the page. If we just unmapped it for the last time, + // put the page on the inactive list + if(atomic_add(&page->ref_count, -1) == 1) { + vm_page_set_state(page, PAGE_STATE_INACTIVE); + free_target--; + } + } + } + + // if the page is modified, but the state is active or inactive, put it on the modified list + if(((flags & PAGE_MODIFIED) || (flags2 & PAGE_MODIFIED)) + && (page->state == PAGE_STATE_ACTIVE || page->state == PAGE_STATE_INACTIVE)) { + vm_page_set_state(page, PAGE_STATE_MODIFIED); + } + + aspace->translation_map.ops->unlock(&aspace->translation_map); + if(--quantum == 0) + break; + } + } + mutex_unlock(®ion->cache_ref->lock); + // move to the next region, wrapping around and stopping if we get back to the first region + region = region->aspace_next ? region->aspace_next : aspace->virtual_map.region_list; + if(region == first_region) + break; + + if(quantum == 0) + break; + } + + aspace->scan_va = region ? (first_region->base + first_region->size) : aspace->virtual_map.base; + release_sem_etc(aspace->virtual_map.sem, READ_COUNT, 0); + +// dprintf("exiting scan_pages\n"); +} + +static int page_daemon() +{ + struct hash_iterator i; + vm_address_space *old_aspace; + vm_address_space *aspace; + addr mapped_size; + addr free_memory_target; + int faults_per_second; + bigtime_t now; + + dprintf("page daemon starting\n"); + + for(;;) { + thread_snooze(PAGE_DAEMON_INTERVAL); + + // scan through all of the address spaces + vm_aspace_walk_start(&i); + aspace = vm_aspace_walk_next(&i); + while(aspace) { + mapped_size = aspace->translation_map.ops->get_mapped_size(&aspace->translation_map); + +// dprintf("page_daemon: looking at aspace 0x%x, id 0x%x, mapped size %d\n", aspace, aspace->id, mapped_size); + + now = system_time(); + if(now - aspace->last_working_set_adjust > WORKING_SET_ADJUST_INTERVAL) { + faults_per_second = (aspace->fault_count * 1000000) / (now - aspace->last_working_set_adjust); +// dprintf(" faults_per_second = %d\n", faults_per_second); + aspace->last_working_set_adjust = now; + aspace->fault_count = 0; + + if(faults_per_second > MAX_FAULTS_PER_SECOND + && mapped_size >= aspace->working_set_size + && aspace->working_set_size < aspace->max_working_set) { + + aspace->working_set_size += WORKING_SET_INCREMENT; +// dprintf(" new working set size = %d\n", aspace->working_set_size); + } else if(faults_per_second < MIN_FAULTS_PER_SECOND + && mapped_size <= aspace->working_set_size + && aspace->working_set_size > aspace->min_working_set) { + + aspace->working_set_size -= WORKING_SET_DECREMENT; +// dprintf(" new working set size = %d\n", aspace->working_set_size); + } + } + + // decide if we need to enter or leave the trimming cycle + if(!trimming_cycle && vm_page_num_free_pages() < free_memory_low_water) + trimming_cycle = true; + else if(trimming_cycle && vm_page_num_free_pages() > free_memory_high_water) + trimming_cycle = false; + + // scan some pages, trying to free some if needed + free_memory_target = 0; + if(trimming_cycle && mapped_size > aspace->working_set_size) + free_memory_target = mapped_size - aspace->working_set_size; + + scan_pages(aspace, free_memory_target); + + // must hold a ref to the old aspace while we grab the next one, + // otherwise the iterator becomes out of date. + old_aspace = aspace; + aspace = vm_aspace_walk_next(&i); + vm_put_aspace(old_aspace); + } + } +} + +int vm_daemon_init() +{ + thread_id tid; + + trimming_cycle = false; + + // calculate the free memory low and high water at which point we enter/leave trimming phase + free_memory_low_water = vm_page_num_pages() / 8; + free_memory_high_water = vm_page_num_pages() / 4; + + // create a kernel thread to select pages for pageout + tid = thread_create_kernel_thread("page daemon", &page_daemon, NULL); + thread_set_priority(tid, THREAD_MIN_RT_PRIORITY); + thread_resume_thread(tid); + + return 0; +} + diff --git a/src/kernel/core/vm/vm_page.c b/src/kernel/core/vm/vm_page.c new file mode 100755 index 0000000000..3dd1a43293 --- /dev/null +++ b/src/kernel/core/vm/vm_page.c @@ -0,0 +1,797 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +typedef struct page_queue { + vm_page *head; + vm_page *tail; + int count; +} page_queue; + +extern bool trimming_cycle; + +static page_queue page_free_queue; +static page_queue page_clear_queue; +static page_queue page_modified_queue; +static page_queue page_active_queue; + +static vm_page *all_pages; +static addr physical_page_offset; +static unsigned int num_pages; + +static spinlock_t page_lock; + +static sem_id modified_pages_available; + +void dump_page_stats(int argc, char **argv); +void dump_free_page_table(int argc, char **argv); +static int vm_page_set_state_nolock(vm_page *page, int page_state); +static void clear_page(addr pa); +static int page_scrubber(void *); + +static vm_page *dequeue_page(page_queue *q) +{ + vm_page *page; + + page = q->tail; + if(page != NULL) { + if(q->head == page) + q->head = NULL; + if(page->queue_prev != NULL) { + page->queue_prev->queue_next = NULL; + } + q->tail = page->queue_prev; + q->count--; + } + return page; +} + +static void enqueue_page(page_queue *q, vm_page *page) +{ + if(q->head != NULL) + q->head->queue_prev = page; + page->queue_next = q->head; + q->head = page; + page->queue_prev = NULL; + if(q->tail == NULL) + q->tail = page; + q->count++; + if(q == &page_modified_queue) { + if(q->count == 1) + release_sem_etc(modified_pages_available, 1, B_DO_NOT_RESCHEDULE); + } +} + +static void remove_page_from_queue(page_queue *q, vm_page *page) +{ + if(page->queue_prev != NULL) { + page->queue_prev->queue_next = page->queue_next; + } else { + q->head = page->queue_next; + } + if(page->queue_next != NULL) { + page->queue_next->queue_prev = page->queue_prev; + } else { + q->tail = page->queue_prev; + } + q->count--; +} + +static void move_page_to_queue(page_queue *from_q, page_queue *to_q, vm_page *page) +{ + if(from_q != to_q) { + remove_page_from_queue(from_q, page); + enqueue_page(to_q, page); + } +} + +static int pageout_daemon() +{ + int state; + vm_page *page; + vm_region *region; + IOVECS(vecs, 1); + ssize_t err; + + dprintf("pageout daemon starting\n"); + + for(;;) { + acquire_sem(modified_pages_available); + + dprintf("here\n"); + + state = int_disable_interrupts(); + acquire_spinlock(&page_lock); + page = dequeue_page(&page_modified_queue); + page->state = PAGE_STATE_BUSY; + vm_cache_acquire_ref(page->cache_ref, true); + release_spinlock(&page_lock); + int_restore_interrupts(state); + + dprintf("got page %p\n", page); + + if(page->cache_ref->cache->temporary && !trimming_cycle) { + // unless we're in the trimming cycle, dont write out pages + // that back anonymous stores + state = int_disable_interrupts(); + acquire_spinlock(&page_lock); + enqueue_page(&page_modified_queue, page); + page->state = PAGE_STATE_MODIFIED; + release_spinlock(&page_lock); + int_restore_interrupts(state); + vm_cache_release_ref(page->cache_ref); + continue; + } + + /* clear the modified flag on this page in all it's mappings */ + mutex_lock(&page->cache_ref->lock); + for(region = page->cache_ref->region_list; region; region = region->cache_next) { + if(page->offset > region->cache_offset + && page->offset < region->cache_offset + region->size) { + vm_translation_map *map = ®ion->aspace->translation_map; + map->ops->lock(map); + map->ops->clear_flags(map, page->offset - region->cache_offset + region->base, PAGE_MODIFIED); + map->ops->unlock(map); + } + } + mutex_unlock(&page->cache_ref->lock); + + /* write the page out to it's backing store */ + vecs->num = 1; + vecs->total_len = PAGE_SIZE; + vm_get_physical_page(page->ppn * PAGE_SIZE, (addr *)&vecs->vec[0].iov_base, PHYSICAL_PAGE_CAN_WAIT); + vecs->vec[0].iov_len = PAGE_SIZE; + + err = page->cache_ref->cache->store->ops->write(page->cache_ref->cache->store, page->offset, vecs); + + vm_put_physical_page((addr)vecs->vec[0].iov_base); + + state = int_disable_interrupts(); + acquire_spinlock(&page_lock); + if(page->ref_count > 0) { + page->state = PAGE_STATE_ACTIVE; + } else { + page->state = PAGE_STATE_INACTIVE; + } + enqueue_page(&page_active_queue, page); + release_spinlock(&page_lock); + int_restore_interrupts(state); + + vm_cache_release_ref(page->cache_ref); + } +} + +int vm_page_init(kernel_args *ka) +{ + unsigned int i; + + dprintf("vm_page_init: entry\n"); + + page_lock = 0; + + // initialize queues + page_free_queue.head = NULL; + page_free_queue.tail = NULL; + page_free_queue.count = 0; + page_clear_queue.head = NULL; + page_clear_queue.tail = NULL; + page_clear_queue.count = 0; + page_modified_queue.head = NULL; + page_modified_queue.tail = NULL; + page_modified_queue.count = 0; + page_active_queue.head = NULL; + page_active_queue.tail = NULL; + page_active_queue.count = 0; + + // calculate the size of memory by looking at the phys_mem_range array + { + unsigned int last_phys_page = 0; + + physical_page_offset = ka->phys_mem_range[0].start / PAGE_SIZE; + for(i=0; inum_phys_mem_ranges; i++) { + last_phys_page = (ka->phys_mem_range[i].start + ka->phys_mem_range[i].size) / PAGE_SIZE - 1; + } + dprintf("first phys page = 0x%lx, last 0x%x\n", physical_page_offset, last_phys_page); + num_pages = last_phys_page - physical_page_offset; + } + + // map in the new free page table + all_pages = (vm_page *)vm_alloc_from_ka_struct(ka, num_pages * sizeof(vm_page), LOCK_KERNEL|LOCK_RW); + + dprintf("vm_init: putting free_page_table @ %p, # ents %d (size 0x%x)\n", + all_pages, num_pages, (unsigned int)(num_pages * sizeof(vm_page))); + + // initialize the free page table + for(i=0; i < num_pages - 1; i++) { + all_pages[i].ppn = physical_page_offset + i; + all_pages[i].type = PAGE_TYPE_PHYSICAL; + all_pages[i].state = PAGE_STATE_FREE; + all_pages[i].ref_count = 0; + enqueue_page(&page_free_queue, &all_pages[i]); + } + + dprintf("initialized table\n"); + + // mark some of the page ranges inuse + for(i = 0; i < ka->num_phys_alloc_ranges; i++) { + vm_mark_page_range_inuse(ka->phys_alloc_range[i].start / PAGE_SIZE, + ka->phys_alloc_range[i].size / PAGE_SIZE); + } + + // set the global max_commit variable + vm_increase_max_commit(num_pages*PAGE_SIZE); + + dprintf("vm_page_init: exit\n"); + + return 0; +} + +int vm_page_init2(kernel_args *ka) +{ + void *null; + + null = all_pages; + vm_create_anonymous_region(vm_get_kernel_aspace_id(), "page_structures", &null, REGION_ADDR_EXACT_ADDRESS, + PAGE_ALIGN(num_pages * sizeof(vm_page)), REGION_WIRING_WIRED_ALREADY, LOCK_RW|LOCK_KERNEL); + + dbg_add_command(&dump_page_stats, "page_stats", "Dump statistics about page usage"); + dbg_add_command(&dump_free_page_table, "free_pages", "Dump list of free pages"); + + return 0; +} + +int vm_page_init_postthread(kernel_args *ka) +{ + thread_id tid; + + // create a kernel thread to clear out pages + tid = thread_create_kernel_thread("page scrubber", &page_scrubber, NULL); + thread_set_priority(tid, THREAD_LOWEST_PRIORITY); + thread_resume_thread(tid); + + modified_pages_available = create_sem(0, "modified_pages_avail_sem"); +#if 0 + // create a kernel thread to schedule modified pages to write + tid = thread_create_kernel_thread("pageout daemon", &pageout_daemon, THREAD_MIN_RT_PRIORITY + 1); + thread_resume_thread(tid); +#endif + return 0; +} + +static int page_scrubber(void *unused) +{ +#define SCRUB_SIZE 16 + int state; + vm_page *page[SCRUB_SIZE]; + int i; + int scrub_count; + + (void)(unused); + + dprintf("page_scrubber starting...\n"); + + for(;;) { + thread_snooze(100000); // 100ms + + if(page_free_queue.count > 0) { + state = int_disable_interrupts(); + acquire_spinlock(&page_lock); + + for(i=0; ippn * PAGE_SIZE); + } + + state = int_disable_interrupts(); + acquire_spinlock(&page_lock); + + for(i=0; istate = PAGE_STATE_CLEAR; + enqueue_page(&page_clear_queue, page[i]); + } + + release_spinlock(&page_lock); + int_restore_interrupts(state); + } + } + + return 0; +} + +static void clear_page(addr pa) +{ + addr va; + +// dprintf("clear_page: clearing page 0x%x\n", pa); + + vm_get_physical_page(pa, &va, PHYSICAL_PAGE_CAN_WAIT); + + memset((void *)va, 0, PAGE_SIZE); + + vm_put_physical_page(va); +} + +int vm_mark_page_inuse(addr page) +{ + return vm_mark_page_range_inuse(page, 1); +} + +int vm_mark_page_range_inuse(addr start_page, addr len) +{ + vm_page *page; + addr i; + int state; + + // XXX remove + dprintf("vm_mark_page_range_inuse: start 0x%lx, len 0x%lx\n", start_page, len); + + if(physical_page_offset > start_page) { + dprintf("vm_mark_page_range_inuse: start page %ld is before free list\n", start_page); + return ERR_INVALID_ARGS; + } + start_page -= physical_page_offset; + if(start_page + len >= num_pages) { + dprintf("vm_mark_page_range_inuse: range would extend past free list\n"); + return ERR_INVALID_ARGS; + } + + state = int_disable_interrupts(); + acquire_spinlock(&page_lock); + + for(i = 0; i < len; i++) { + page = &all_pages[start_page + i]; + switch(page->state) { + case PAGE_STATE_FREE: + case PAGE_STATE_CLEAR: + vm_page_set_state_nolock(page, PAGE_STATE_UNUSED); + break; + case PAGE_STATE_WIRED: + break; + case PAGE_STATE_ACTIVE: + case PAGE_STATE_INACTIVE: + case PAGE_STATE_BUSY: + case PAGE_STATE_MODIFIED: + case PAGE_STATE_UNUSED: + default: + // uh + dprintf("vm_mark_page_range_inuse: page 0x%lx in non-free state %d!\n", start_page + i, page->state); + } + } + + release_spinlock(&page_lock); + int_restore_interrupts(state); + + return i; +} + +vm_page *vm_page_allocate_specific_page(addr page_num, int page_state) +{ + vm_page *p; + int old_page_state = PAGE_STATE_BUSY; + int state; + + state = int_disable_interrupts(); + acquire_spinlock(&page_lock); + + p = vm_lookup_page(page_num); + if(p == NULL) + goto out; + + switch(p->state) { + case PAGE_STATE_FREE: + remove_page_from_queue(&page_free_queue, p); + break; + case PAGE_STATE_CLEAR: + remove_page_from_queue(&page_clear_queue, p); + break; + case PAGE_STATE_UNUSED: + break; + default: + // we can't allocate this page + p = NULL; + } + if(p == NULL) + goto out; + + old_page_state = p->state; + p->state = PAGE_STATE_BUSY; + + if(old_page_state != PAGE_STATE_UNUSED) + enqueue_page(&page_active_queue, p); + +out: + release_spinlock(&page_lock); + int_restore_interrupts(state); + + if(p != NULL && page_state == PAGE_STATE_CLEAR && + (old_page_state == PAGE_STATE_FREE || old_page_state == PAGE_STATE_UNUSED)) { + + clear_page(p->ppn * PAGE_SIZE); + } + + return p; +} + +vm_page *vm_page_allocate_page(int page_state) +{ + vm_page *p; + page_queue *q; + page_queue *q_other; + int state; + int old_page_state; + + switch(page_state) { + case PAGE_STATE_FREE: + q = &page_free_queue; + q_other = &page_clear_queue; + break; + case PAGE_STATE_CLEAR: + q = &page_clear_queue; + q_other = &page_free_queue; + break; + default: + return NULL; // invalid + } + + state = int_disable_interrupts(); + acquire_spinlock(&page_lock); + + p = dequeue_page(q); + if(p == NULL) { + // the clear queue was empty, grab one from the free queue and zero it out + p = dequeue_page(q_other); + if(p == NULL) { + // XXX hmm + panic("vm_allocate_page: out of memory!\n"); + } + } + + old_page_state = p->state; + p->state = PAGE_STATE_BUSY; + + enqueue_page(&page_active_queue, p); + + release_spinlock(&page_lock); + int_restore_interrupts(state); + + if(page_state == PAGE_STATE_CLEAR && old_page_state == PAGE_STATE_FREE) { + clear_page(p->ppn * PAGE_SIZE); + } + + return p; +} + +vm_page *vm_page_allocate_page_run(int page_state, addr len) +{ + unsigned int start; + unsigned int i; + vm_page *first_page = NULL; + int state; + + start = 0; + + state = int_disable_interrupts(); + acquire_spinlock(&page_lock); + + for(;;) { + bool foundit = true; + if(start + len >= num_pages) { + break; + } + for(i = 0; i < len; i++) { + if(all_pages[start + i].state != PAGE_STATE_FREE && + all_pages[start + i].state != PAGE_STATE_CLEAR) { + foundit = false; + i++; + break; + } + } + if(foundit) { + // pull the pages out of the appropriate queues + for(i = 0; i < len; i++) + vm_page_set_state_nolock(&all_pages[start + i], PAGE_STATE_BUSY); + first_page = &all_pages[start]; + break; + } else { + start += i; + if(start >= num_pages) { + // no more pages to look through + break; + } + } + } + release_spinlock(&page_lock); + int_restore_interrupts(state); + + return first_page; +} + +vm_page *vm_lookup_page(addr page_num) +{ + if(page_num < physical_page_offset) + return NULL; + page_num -= physical_page_offset; + if(page_num > num_pages) + return NULL; + + return &all_pages[page_num]; +} + +static int vm_page_set_state_nolock(vm_page *page, int page_state) +{ + page_queue *from_q = NULL; + page_queue *to_q = NULL; + + switch(page->state) { + case PAGE_STATE_BUSY: + case PAGE_STATE_ACTIVE: + case PAGE_STATE_INACTIVE: + case PAGE_STATE_WIRED: + case PAGE_STATE_UNUSED: + from_q = &page_active_queue; + break; + case PAGE_STATE_MODIFIED: + from_q = &page_modified_queue; + break; + case PAGE_STATE_FREE: + from_q = &page_free_queue; + break; + case PAGE_STATE_CLEAR: + from_q = &page_clear_queue; + break; + default: + panic("vm_page_set_state: vm_page %p in invalid state %d\n", page, page->state); + } + + switch(page_state) { + case PAGE_STATE_BUSY: + case PAGE_STATE_ACTIVE: + case PAGE_STATE_INACTIVE: + case PAGE_STATE_WIRED: + case PAGE_STATE_UNUSED: + to_q = &page_active_queue; + break; + case PAGE_STATE_MODIFIED: + to_q = &page_modified_queue; + break; + case PAGE_STATE_FREE: + to_q = &page_free_queue; + break; + case PAGE_STATE_CLEAR: + to_q = &page_clear_queue; + break; + default: + panic("vm_page_set_state: invalid target state %d\n", page_state); + } + move_page_to_queue(from_q, to_q, page); + page->state = page_state; + + return 0; +} + +int vm_page_set_state(vm_page *page, int page_state) +{ + int err; + int state = int_disable_interrupts(); + acquire_spinlock(&page_lock); + + err = vm_page_set_state_nolock(page, page_state); + + release_spinlock(&page_lock); + int_restore_interrupts(state); + + return err; +} + +addr vm_page_num_pages() +{ + return num_pages; +} + +addr vm_page_num_free_pages() +{ + return page_free_queue.count + page_clear_queue.count; +} + +void dump_free_page_table(int argc, char **argv) +{ + dprintf("not finished\n"); +} + +void dump_page_stats(int argc, char **argv) +{ + unsigned int page_types[8]; + addr i; + + memset(page_types, 0, sizeof(page_types)); + + for(i=0; i %d\n", free_start + free_page_table_base, i-1 + free_page_table_base); + free_start = END_OF_LIST; + } + inuse_start = i; + } else { + if(free_start != END_OF_LIST) { + i++; + continue; + } + if(inuse_start != PAGE_INUSE) { + dprintf("inuse from %d -> %d\n", inuse_start + free_page_table_base, i-1 + free_page_table_base); + inuse_start = PAGE_INUSE; + } + free_start = i; + } + i++; + } + if(inuse_start != PAGE_INUSE) { + dprintf("inuse from %d -> %d\n", inuse_start + free_page_table_base, i-1 + free_page_table_base); + } + if(free_start != END_OF_LIST) { + dprintf("free from %d -> %d\n", free_start + free_page_table_base, i-1 + free_page_table_base); + } +/* + for(i=0; i%d ", i, free_page_table[i]); + } +*/ +} +#endif +static addr vm_alloc_vspace_from_ka_struct(kernel_args *ka, unsigned int size) +{ + addr spot = 0; + unsigned int i; + int last_valloc_entry = 0; + + size = PAGE_ALIGN(size); + // find a slot in the virtual allocation addr range + for(i=1; inum_virt_alloc_ranges; i++) { + last_valloc_entry = i; + // check to see if the space between this one and the last is big enough + if(ka->virt_alloc_range[i].start - + (ka->virt_alloc_range[i-1].start + ka->virt_alloc_range[i-1].size) >= size) { + + spot = ka->virt_alloc_range[i-1].start + ka->virt_alloc_range[i-1].size; + ka->virt_alloc_range[i-1].size += size; + goto out; + } + } + if(spot == 0) { + // we hadn't found one between allocation ranges. this is ok. + // see if there's a gap after the last one + if(ka->virt_alloc_range[last_valloc_entry].start + ka->virt_alloc_range[last_valloc_entry].size + size <= + KERNEL_BASE + (KERNEL_SIZE - 1)) { + spot = ka->virt_alloc_range[last_valloc_entry].start + ka->virt_alloc_range[last_valloc_entry].size; + ka->virt_alloc_range[last_valloc_entry].size += size; + goto out; + } + // see if there's a gap before the first one + if(ka->virt_alloc_range[0].start > KERNEL_BASE) { + if(ka->virt_alloc_range[0].start - KERNEL_BASE >= size) { + ka->virt_alloc_range[0].start -= size; + spot = ka->virt_alloc_range[0].start; + goto out; + } + } + } + +out: + return spot; +} + +// XXX horrible brute-force method of determining if the page can be allocated +static bool is_page_in_phys_range(kernel_args *ka, addr paddr) +{ + unsigned int i; + + for(i=0; inum_phys_mem_ranges; i++) { + if(paddr >= ka->phys_mem_range[i].start && + paddr < ka->phys_mem_range[i].start + ka->phys_mem_range[i].size) { + return true; + } + } + return false; +} + +static addr vm_alloc_ppage_from_kernel_struct(kernel_args *ka) +{ + unsigned int i; + + for(i=0; inum_phys_alloc_ranges; i++) { + addr next_page; + + next_page = ka->phys_alloc_range[i].start + ka->phys_alloc_range[i].size; + // see if the page after the next allocated paddr run can be allocated + if(i + 1 < ka->num_phys_alloc_ranges && ka->phys_alloc_range[i+1].size != 0) { + // see if the next page will collide with the next allocated range + if(next_page >= ka->phys_alloc_range[i+1].start) + continue; + } + // see if the next physical page fits in the memory block + if(is_page_in_phys_range(ka, next_page)) { + // we got one! + ka->phys_alloc_range[i].size += PAGE_SIZE; + return ((ka->phys_alloc_range[i].start + ka->phys_alloc_range[i].size - PAGE_SIZE) / PAGE_SIZE); + } + } + + return 0; // could not allocate a block +} + +addr vm_alloc_from_ka_struct(kernel_args *ka, unsigned int size, int lock) +{ + addr vspot; + addr pspot; + unsigned int i; +// int curr_phys_alloc_range = 0; + + // find the vaddr to allocate at + vspot = vm_alloc_vspace_from_ka_struct(ka, size); +// dprintf("alloc_from_ka_struct: vaddr 0x%x\n", vspot); + + // map the pages + for(i=0; i +#include +#include +#include +#include +#include + +static void anonymous_destroy(struct vm_store *store) +{ + if(store) { + kfree(store); + } +} + +/* anonymous_commit + * As this store provides anonymous memory that is simply discarded + * when finished with, we don't bother recording the changes + * here, so we just return 0. + */ +static off_t anonymous_commit(struct vm_store *store, off_t size) +{ + return 0; +} + +static int anonymous_has_page(struct vm_store *store, off_t offset) +{ + return 0; +} + +static ssize_t anonymous_read(struct vm_store *store, off_t offset, iovecs *vecs) +{ + panic("anonymous_store: read called. Invalid!\n"); + return ERR_UNIMPLEMENTED; +} + +static ssize_t anonymous_write(struct vm_store *store, off_t offset, iovecs *vecs) +{ + // no place to write, this will cause the page daemon to skip this store + return 0; +} + +/* +static int anonymous_fault(struct vm_store *backing_store, struct vm_address_space *aspace, off_t offset) +{ + // unused +} +*/ + +static vm_store_ops anonymous_ops = { + &anonymous_destroy, + &anonymous_commit, + &anonymous_has_page, + &anonymous_read, + &anonymous_write, + NULL, // fault() is unused + NULL, + NULL +}; + +/* vm_store_create_anonymous + * Create a new vm_store that uses anonymous noswap memory + */ +vm_store *vm_store_create_anonymous_noswap() +{ + vm_store *store; + + store = kmalloc(sizeof(vm_store)); + if(store == NULL) + return NULL; + +dprintf("vm_store_create_anonymous (%p)\n", store); + + store->ops = &anonymous_ops; + store->cache = NULL; + store->data = NULL; + store->committed_size = 0; + + return store; +} + diff --git a/src/kernel/core/vm/vm_store_device.c b/src/kernel/core/vm/vm_store_device.c new file mode 100755 index 0000000000..94f66efc36 --- /dev/null +++ b/src/kernel/core/vm/vm_store_device.c @@ -0,0 +1,115 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include + +struct device_store_data { + addr base_addr; +}; + +static void device_destroy(struct vm_store *store) +{ + if(store) { + kfree(store); + } +} + +static off_t device_commit(struct vm_store *store, off_t size) +{ + store->committed_size = size; + return size; +} + +static int device_has_page(struct vm_store *store, off_t offset) +{ + // this should never be called + return 0; +} + +static ssize_t device_read(struct vm_store *store, off_t offset, iovecs *vecs) +{ + panic("device_store: read called. Invalid!\n"); + return ERR_UNIMPLEMENTED; +} + +static ssize_t device_write(struct vm_store *store, off_t offset, iovecs *vecs) +{ + // no place to write, this will cause the page daemon to skip this store + return 0; +} + +// this fault handler should take over the page fault routine and map the page in +// +// setup: the cache that this store is part of has a ref being held and will be +// released after this handler is done +static int device_fault(struct vm_store *store, struct vm_address_space *aspace, off_t offset) +{ + struct device_store_data *d = (struct device_store_data *)store->data; + vm_cache_ref *cache_ref = store->cache->ref; + vm_region *region; + +// dprintf("device_fault: offset 0x%x 0x%x + base_addr 0x%x\n", offset, d->base_addr); + + // figure out which page needs to be mapped where + mutex_lock(&cache_ref->lock); + (*aspace->translation_map.ops->lock)(&aspace->translation_map); + + // cycle through all of the regions that map this cache and map the page in + for(region = cache_ref->region_list; region != NULL; region = region->cache_next) { + // make sure this page in the cache that was faulted on is covered in this region + if(offset >= region->cache_offset && (offset - region->cache_offset) < region->size) { +// dprintf("device_fault: mapping paddr 0x%x to vaddr 0x%x\n", +// (addr)(d->base_addr + offset), +// (addr)(region->base + (offset - region->cache_offset))); + (*aspace->translation_map.ops->map)(&aspace->translation_map, + region->base + (offset - region->cache_offset), + d->base_addr + offset, region->lock); + } + } + + (*aspace->translation_map.ops->unlock)(&aspace->translation_map); + mutex_unlock(&cache_ref->lock); + +// dprintf("device_fault: done\n"); + + return 0; +} + +static vm_store_ops device_ops = { + &device_destroy, + &device_commit, + &device_has_page, + &device_read, + &device_write, + &device_fault, + NULL, + NULL +}; + +vm_store *vm_store_create_device(addr base_addr) +{ + vm_store *store; + struct device_store_data *d; + + store = kmalloc(sizeof(vm_store) + sizeof(struct device_store_data)); + if(store == NULL) + return NULL; + + store->ops = &device_ops; + store->cache = NULL; + store->data = (void *)((addr)store + sizeof(vm_store)); + store->committed_size = 0; + + d = (struct device_store_data *)store->data; + d->base_addr = base_addr; + + return store; +} + diff --git a/src/kernel/core/vm/vm_store_null.c b/src/kernel/core/vm/vm_store_null.c new file mode 100755 index 0000000000..61009bfe38 --- /dev/null +++ b/src/kernel/core/vm/vm_store_null.c @@ -0,0 +1,75 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include +#include + +static void null_destroy(struct vm_store *store) +{ + if(store) { + kfree(store); + } +} + +static off_t null_commit(struct vm_store *store, off_t size) +{ + store->committed_size = size; + return size; +} + +static int null_has_page(struct vm_store *store, off_t offset) +{ + return 1; // we always have the page, man +} + +static ssize_t null_read(struct vm_store *store, off_t offset, iovecs *vecs) +{ + return -1; +} + +static ssize_t null_write(struct vm_store *store, off_t offset, iovecs *vecs) +{ + return -1; +} + +static int null_fault(struct vm_store *store, struct vm_address_space *aspace, off_t offset) +{ + /* we can't fault on this region, that's pretty much the point of the null store object */ + return ERR_VM_PF_FATAL; +} + +static vm_store_ops null_ops = { + &null_destroy, + &null_commit, + &null_has_page, + &null_read, + &null_write, + &null_fault, + NULL, + NULL +}; + +vm_store *vm_store_create_null(void) +{ + vm_store *store; + + store = kmalloc(sizeof(vm_store)); + if(store == NULL) { + return NULL; + } + + store->ops = &null_ops; + store->cache = NULL; + store->data = NULL; + store->committed_size = 0; + + return store; +} + diff --git a/src/kernel/core/vm/vm_store_vnode.c b/src/kernel/core/vm/vm_store_vnode.c new file mode 100755 index 0000000000..1d7df01f23 --- /dev/null +++ b/src/kernel/core/vm/vm_store_vnode.c @@ -0,0 +1,101 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include +#include + +#define STORE_DATA(x) ((struct vnode_store_data *)(x->data)) + +struct vnode_store_data { + void *vn; +}; + +static void vnode_destroy(struct vm_store *store) +{ + if(store) { + kfree(store); + } +} + +/* vnode_commit + * We're being asked to commit some memory, so record the + * fact here. + */ +static off_t vnode_commit(struct vm_store *store, off_t size) +{ + store->committed_size = size; + return size; +} + +static int vnode_has_page(struct vm_store *store, off_t offset) +{ + return 1; // we always have the page, man +} + +static ssize_t vnode_read(struct vm_store *store, off_t offset, iovecs *vecs) +{ + return vfs_readpage(STORE_DATA(store)->vn, vecs, offset); +} + +static ssize_t vnode_write(struct vm_store *store, off_t offset, iovecs *vecs) +{ + return vfs_writepage(STORE_DATA(store)->vn, vecs, offset); +} + +/* unused +static int vnode_fault(struct vm_store *store, struct vm_address_space *aspace, off_t offset) +{ + return 0; +} +*/ + +static void vnode_acquire_ref(struct vm_store *store) +{ + vfs_vnode_acquire_ref(STORE_DATA(store)->vn); +} + +static void vnode_release_ref(struct vm_store *store) +{ + vfs_vnode_release_ref(STORE_DATA(store)->vn); +} + +static vm_store_ops vnode_ops = { + &vnode_destroy, + &vnode_commit, + &vnode_has_page, + &vnode_read, + &vnode_write, + NULL, + &vnode_acquire_ref, + &vnode_release_ref +}; + +vm_store *vm_store_create_vnode(void *vnode) +{ + vm_store *store; + struct vnode_store_data *d; + + store = kmalloc(sizeof(vm_store) + sizeof(struct vnode_store_data)); + if(store == NULL) { + vfs_put_vnode_ptr(vnode); + return NULL; + } + + store->ops = &vnode_ops; + store->cache = NULL; + store->data = (void *)((addr)store + sizeof(vm_store)); + store->committed_size = 0; + + d = (struct vnode_store_data *)store->data; + d->vn = vnode; + + return store; +} + diff --git a/src/kernel/core/vm/vm_tests.c b/src/kernel/core/vm/vm_tests.c new file mode 100755 index 0000000000..1d1b7f03bf --- /dev/null +++ b/src/kernel/core/vm/vm_tests.c @@ -0,0 +1,356 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include + +#include +#include +#include + +void vm_test() +{ +// region_id region, region2, region3; +// addr region_addr; +// int i; + + dprintf("vm_test: entry\n"); +#if 1 + dprintf("vm_test 1: creating anonymous region and writing to it\n"); + { + region_id region; + addr region_addr; + + region = vm_create_anonymous_region(vm_get_kernel_aspace_id(), "test_region", (void **)®ion_addr, + REGION_ADDR_ANY_ADDRESS, PAGE_SIZE * 16, REGION_WIRING_LAZY, LOCK_RW|LOCK_KERNEL); + if(region < 0) + panic("vm_test 1: failed to create test region\n"); + dprintf("region = 0x%x, addr = 0x%lx\n", region, region_addr); + + memset((void *)region_addr, 0, PAGE_SIZE * 16); + + dprintf("memsetted the region\n"); + if(vm_delete_region(vm_get_kernel_aspace_id(), region) < 0) + panic("vm_test 1: error deleting test region\n"); + dprintf("deleted the region\n"); + } +#endif +#if 1 + dprintf("vm_test 2: creating physical region and writing and reading from it\n"); + { + region_id region; + vm_region_info info; + char *ptr; + int i; + + region = vm_map_physical_memory(vm_get_kernel_aspace_id(), "test_physical_region", (void **)&ptr, + REGION_ADDR_ANY_ADDRESS, PAGE_SIZE * 16, LOCK_RW|LOCK_KERNEL, 0xb8000); + if(region < 0) + panic("vm_test 2: failed to create test region\n"); + + vm_get_region_info(region, &info); + dprintf("region = 0x%x, addr = %p, region->base = 0x%lx\n", region, ptr, info.base); + if((addr)ptr != info.base) + panic("vm_test 2: info returned about region does not match pointer returned\n"); + + for(i=0; i<64; i++) { + ptr[i] = 'a'; + } + if(vm_delete_region(vm_get_kernel_aspace_id(), region) < 0) + panic("vm_test 2: error deleting test region\n"); + dprintf("deleted the region\n"); + } +#endif +#if 1 + dprintf("vm_test 3: testing some functionality of vm_get_page_mapping(), vm_get/put_physical_page()\n"); + { + addr va, pa; + addr va2; + + vm_get_page_mapping(vm_get_kernel_aspace_id(), 0x80000000, &pa); + vm_get_physical_page(pa, &va, PHYSICAL_PAGE_CAN_WAIT); + dprintf("pa 0x%lx va 0x%lx\n", pa, va); + dprintf("%d\n", memcmp((void *)0x80000000, (void *)va, PAGE_SIZE)); + + vm_get_page_mapping(vm_get_kernel_aspace_id(), 0x80001000, &pa); + vm_get_physical_page(pa, &va2, PHYSICAL_PAGE_CAN_WAIT); + dprintf("pa 0x%lx va 0x%lx\n", pa, va2); + dprintf("%d\n", memcmp((void *)0x80001000, (void *)va2, PAGE_SIZE)); + + vm_put_physical_page(va); + vm_put_physical_page(va2); + + vm_get_page_mapping(vm_get_kernel_aspace_id(), 0x80000000, &pa); + vm_get_physical_page(pa, &va, PHYSICAL_PAGE_CAN_WAIT); + dprintf("pa 0x%lx va 0x%lx\n", pa, va); + dprintf("%d\n", memcmp((void *)0x80000000, (void *)va, PAGE_SIZE)); + + vm_put_physical_page(va); + } +#endif +#if 1 + dprintf("vm_test 4: cloning vidmem and testing if it compares\n"); + { + region_id region, region2; + vm_region_info info; + void *ptr; + int rc; + + region = vm_find_region_by_name(vm_get_kernel_aspace_id(), "vid_mem"); + if(region < 0) + panic("vm_test 4: error finding region 'vid_mem'\n"); + dprintf("vid_mem region = 0x%x\n", region); + + region2 = vm_clone_region(vm_get_kernel_aspace_id(), "vid_mem2", + &ptr, REGION_ADDR_ANY_ADDRESS, region, REGION_NO_PRIVATE_MAP, LOCK_RW|LOCK_KERNEL); + if(region2 < 0) + panic("vm_test 4: error cloning region 'vid_mem'\n"); + dprintf("region2 = 0x%x, ptr = %p\n", region2, ptr); + + vm_get_region_info(region, &info); + rc = memcmp(ptr, (void *)info.base, info.size); + if(rc != 0) + panic("vm_test 4: regions are not identical\n"); + else + dprintf("vm_test 4: comparison ok\n"); + if(vm_delete_region(vm_get_kernel_aspace_id(), region2) < 0) + panic("vm_test 4: error deleting cloned region\n"); + } +#endif +#if 1 + dprintf("vm_test 5: cloning vidmem in RO and testing if it compares\n"); + { + region_id region, region2; + vm_region_info info; + void *ptr; + int rc; + + region = vm_find_region_by_name(vm_get_kernel_aspace_id(), "vid_mem"); + if(region < 0) + panic("vm_test 5: error finding region 'vid_mem'\n"); + dprintf("vid_mem region = 0x%x\n", region); + + region2 = vm_clone_region(vm_get_kernel_aspace_id(), "vid_mem3", + &ptr, REGION_ADDR_ANY_ADDRESS, region, REGION_NO_PRIVATE_MAP, LOCK_RO|LOCK_KERNEL); + if(region2 < 0) + panic("vm_test 5: error cloning region 'vid_mem'\n"); + dprintf("region2 = 0x%x, ptr = %p\n", region2, ptr); + + vm_get_region_info(region, &info); + rc = memcmp(ptr, (void *)info.base, info.size); + if(rc != 0) + panic("vm_test 5: regions are not identical\n"); + else + dprintf("vm_test 5: comparison ok\n"); + + if(vm_delete_region(vm_get_kernel_aspace_id(), region2) < 0) + panic("vm_test 5: error deleting cloned region\n"); + } +#endif +#if 1 + dprintf("vm_test 6: creating anonymous region, cloning it, and testing if it compares\n"); + { + region_id region, region2; + void *region_addr; + void *ptr; + int rc; + + region = vm_create_anonymous_region(vm_get_kernel_aspace_id(), "test_region", ®ion_addr, + REGION_ADDR_ANY_ADDRESS, PAGE_SIZE * 16, REGION_WIRING_LAZY, LOCK_RW|LOCK_KERNEL); + if(region < 0) + panic("vm_test 6: error creating test region\n"); + dprintf("region = 0x%x, addr = %p\n", region, region_addr); + + memset(region_addr, 99, PAGE_SIZE * 16); + + dprintf("memsetted the region\n"); + + region2 = vm_clone_region(vm_get_kernel_aspace_id(), "test_region2", + &ptr, REGION_ADDR_ANY_ADDRESS, region, REGION_NO_PRIVATE_MAP, LOCK_RW|LOCK_KERNEL); + if(region2 < 0) + panic("vm_test 6: error cloning test region\n"); + dprintf("region2 = 0x%x, ptr = %p\n", region2, ptr); + + rc = memcmp(region_addr, ptr, PAGE_SIZE * 16); + if(rc != 0) + panic("vm_test 6: regions are not identical\n"); + else + dprintf("vm_test 6: comparison ok\n"); + + if(vm_delete_region(vm_get_kernel_aspace_id(), region) < 0) + panic("vm_test 6: error deleting test region\n"); + + if(vm_delete_region(vm_get_kernel_aspace_id(), region2) < 0) + panic("vm_test 6: error deleting cloned region\n"); + } +#endif +#if 1 + dprintf("vm_test 7: mmaping a known file a few times and verifying they see the same data\n"); + { + void *ptr, *ptr2; + region_id rid, rid2; +// char *blah; + int fd; + + fd = sys_open("/boot/kernel", STREAM_TYPE_FILE, 0); + + rid = vm_map_file(vm_get_kernel_aspace_id(), "mmap_test", &ptr, REGION_ADDR_ANY_ADDRESS, + PAGE_SIZE, LOCK_RW|LOCK_KERNEL, REGION_NO_PRIVATE_MAP, "/boot/kernel", 0); + + rid2 = vm_map_file(vm_get_kernel_aspace_id(), "mmap_test2", &ptr2, REGION_ADDR_ANY_ADDRESS, + PAGE_SIZE, LOCK_RW|LOCK_KERNEL, REGION_NO_PRIVATE_MAP, "/boot/kernel", 0); + + dprintf("diff %d\n", memcmp(ptr, ptr2, PAGE_SIZE)); + + dprintf("removing regions\n"); + + vm_delete_region(vm_get_kernel_aspace_id(), rid); + vm_delete_region(vm_get_kernel_aspace_id(), rid2); + + dprintf("regions deleted\n"); + + sys_close(fd); + + dprintf("vm_test 7: passed\n"); + } +#endif +#if 1 + dprintf("vm_test 8: creating anonymous region, cloning it with private mapping\n"); + { + region_id region, region2; + void *region_addr; + void *ptr; + int rc; + + dprintf("vm_test 8: creating test region...\n"); + + region = vm_create_anonymous_region(vm_get_kernel_aspace_id(), "test_region", ®ion_addr, + REGION_ADDR_ANY_ADDRESS, PAGE_SIZE * 16, REGION_WIRING_LAZY, LOCK_RW|LOCK_KERNEL); + if(region < 0) + panic("vm_test 8: error creating test region\n"); + dprintf("region = 0x%x, addr = %p\n", region, region_addr); + + dprintf("vm_test 8: memsetting the first 2 pages\n"); + + memset(region_addr, 99, PAGE_SIZE * 2); + + dprintf("vm_test 8: cloning test region with PRIVATE_MAP\n"); + + region2 = vm_clone_region(vm_get_kernel_aspace_id(), "test_region2", + &ptr, REGION_ADDR_ANY_ADDRESS, region, REGION_PRIVATE_MAP, LOCK_RW|LOCK_KERNEL); + if(region2 < 0) + panic("vm_test 8: error cloning test region\n"); + dprintf("region2 = 0x%x, ptr = %p\n", region2, ptr); + + dprintf("vm_test 8: comparing first 2 pages, shoudld be identical\n"); + + rc = memcmp(region_addr, ptr, PAGE_SIZE * 2); + if(rc != 0) + panic("vm_test 8: regions are not identical\n"); + else + dprintf("vm_test 8: comparison ok\n"); + + dprintf("vm_test 8: changing one page in the clone and comparing, should now differ\n"); + + memset(ptr, 1, 1); + + rc = memcmp(region_addr, ptr, PAGE_SIZE); + if(rc != 0) + dprintf("vm_test 8: regions are not identical, good\n"); + else + panic("vm_test 8: comparison shows not private mapping\n"); + + dprintf("vm_test 8: comparing untouched pages in source and clone, should be identical\n"); + + rc = memcmp((char *)region_addr + 2*PAGE_SIZE, (char *)ptr + 2*PAGE_SIZE, PAGE_SIZE * 1); + if(rc != 0) + panic("vm_test 8: regions are not identical\n"); + else + dprintf("vm_test 8: comparison ok\n"); + + dprintf("vm_test 8: modifying source page and comparing, should be the same\n"); + + memset((char *)region_addr + 3*PAGE_SIZE, 2, 4); + + rc = memcmp((char *)region_addr + 3*PAGE_SIZE, (char *)ptr + 3*PAGE_SIZE, PAGE_SIZE * 1); + if(rc != 0) + panic("vm_test 8: regions are not identical\n"); + else + dprintf("vm_test 8: comparison ok\n"); + + + dprintf("vm_test 8: modifying new page in clone, should not effect source, which is also untouched\n"); + + memset((char *)ptr + 4*PAGE_SIZE, 2, 4); + + rc = memcmp((char *)region_addr + 4*PAGE_SIZE, (char *)ptr + 4*PAGE_SIZE, PAGE_SIZE * 1); + if(rc != 0) + dprintf("vm_test 8: regions are not identical, good\n"); + else + panic("vm_test 8: comparison shows not private mapping\n"); + + if(vm_delete_region(vm_get_kernel_aspace_id(), region) < 0) + panic("vm_test 8: error deleting test region\n"); + + if(vm_delete_region(vm_get_kernel_aspace_id(), region2) < 0) + panic("vm_test 8: error deleting cloned region\n"); + } +#endif +#if 1 + dprintf("vm_test 9: mmaping a known file a few times, one with private mappings\n"); + { + void *ptr, *ptr2; + region_id rid, rid2; + int err; + + dprintf("vm_test 9: mapping /boot/kernel twice\n"); + + rid = vm_map_file(vm_get_kernel_aspace_id(), "mmap_test", &ptr, REGION_ADDR_ANY_ADDRESS, + PAGE_SIZE*4, LOCK_RW|LOCK_KERNEL, REGION_NO_PRIVATE_MAP, "/boot/kernel", 0); + + rid2 = vm_map_file(vm_get_kernel_aspace_id(), "mmap_test2", &ptr2, REGION_ADDR_ANY_ADDRESS, + PAGE_SIZE*4, LOCK_RW|LOCK_KERNEL, REGION_PRIVATE_MAP, "/boot/kernel", 0); + + err = memcmp(ptr, ptr2, PAGE_SIZE); + if(err) + panic("vm_test 9: two mappings are different\n"); + + dprintf("vm_test 9: modifying private mapping in section that has been referenced, should be different\n"); + + memset(ptr2, 0xaa, 4); + + err = memcmp(ptr, ptr2, PAGE_SIZE); + if(!err) + panic("vm_test 9: two mappings still identical\n"); + + dprintf("vm_test 9: modifying private mapping in section that hasn't been touched, should be different\n"); + + memset((char *)ptr2 + PAGE_SIZE, 0xaa, 4); + + err = memcmp((char *)ptr + PAGE_SIZE, (char *)ptr2 + PAGE_SIZE, PAGE_SIZE); + if(!err) + panic("vm_test 9: two mappings still identical\n"); + + dprintf("vm_test 9: modifying non-private mapping in section that hasn't been touched\n"); + + memset((char *)ptr + PAGE_SIZE*2, 0xaa, 4); + + err = memcmp((char *)ptr + PAGE_SIZE*2, (char *)ptr2 + PAGE_SIZE*2, PAGE_SIZE); + if(err) + panic("vm_test 9: two mappings are different\n"); + + dprintf("vm_test 9: removing regions\n"); + + vm_delete_region(vm_get_kernel_aspace_id(), rid); + vm_delete_region(vm_get_kernel_aspace_id(), rid2); + + dprintf("vm_test 9: regions deleted\n"); + + dprintf("vm_test 9: passed\n"); + } +#endif + dprintf("vm_test: done\n"); +} diff --git a/src/kernel/drivers/Jamfile b/src/kernel/drivers/Jamfile new file mode 100644 index 0000000000..f76d2d5165 --- /dev/null +++ b/src/kernel/drivers/Jamfile @@ -0,0 +1,18 @@ +SubDir OBOS_TOP sources os kits kernel drivers ; + +KernelStaticLibrary libdrivers : + <$(SOURCE_GRIST)>dev.c + <$(SOURCE_GRIST)>devs.c + <$(SOURCE_GRIST)>common/null.c + <$(SOURCE_GRIST)>common/zero.c + <$(SOURCE_GRIST)>arch/$(OBOS_ARCH)/console/console.c + <$(SOURCE_GRIST)>arch/$(OBOS_ARCH)/keyboard/keyboard.c + <$(SOURCE_GRIST)>arch/$(OBOS_ARCH)/ps2mouse/ps2mouse.c + + <$(SOURCE_GRIST)>fb_console/fb_console.c + : + -fno-pic -Wno-unused + ; + +#SubInclude OBOS_TOP sources os kits kernel drivers arch ; +SubInclude OBOS_TOP sources os kits kernel drivers common ; diff --git a/src/kernel/drivers/arch/Jamfile b/src/kernel/drivers/arch/Jamfile new file mode 100644 index 0000000000..1e930a8f6f --- /dev/null +++ b/src/kernel/drivers/arch/Jamfile @@ -0,0 +1,3 @@ +SubDir OBOS_TOP sources os kits kernel drivers arch ; + +SubInclude OBOS_TOP sources os kits kernel drivers arch $(OBOS_ARCH) ; diff --git a/src/kernel/drivers/arch/x86/Jamfile b/src/kernel/drivers/arch/x86/Jamfile new file mode 100644 index 0000000000..f89f19b00e --- /dev/null +++ b/src/kernel/drivers/arch/x86/Jamfile @@ -0,0 +1,5 @@ +SubDir OBOS_TOP sources os kits kernel drivers arch x86 ; + +SubInclude OBOS_TOP sources os kits kernel drivers arch x86 console ; +SubInclude OBOS_TOP sources os kits kernel drivers arch x86 keyboard ; +SubInclude OBOS_TOP sources os kits kernel drivers arch x86 ps2mouse ; diff --git a/src/kernel/drivers/arch/x86/console/Jamfile b/src/kernel/drivers/arch/x86/console/Jamfile new file mode 100644 index 0000000000..5f67f09985 --- /dev/null +++ b/src/kernel/drivers/arch/x86/console/Jamfile @@ -0,0 +1,3 @@ +SubDir OBOS_TOP sources os kits kernel drivers arch i386 console ; + +KernelObjects console.c : -fnopic ; diff --git a/src/kernel/drivers/arch/x86/console/console.c b/src/kernel/drivers/arch/x86/console/console.c new file mode 100755 index 0000000000..2c7fd12df4 --- /dev/null +++ b/src/kernel/drivers/arch/x86/console/console.c @@ -0,0 +1,304 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +static unsigned int origin = 0; + +#define SCREEN_START 0xb8000 +#define SCREEN_END 0xc0000 +#define LINES 25 +#define COLUMNS 80 +#define NPAR 16 +#define TAB_SIZE 8 +#define TAB_MASK 7 + +#define TEXT_INDEX 0x3d4 +#define TEXT_DATA 0x3d5 + +#define TEXT_CURSOR_LO 0x0f +#define TEXT_CURSOR_HI 0x0e + +#define scr_end (origin+LINES*COLUMNS*2) + +static unsigned int pos = 0; +static unsigned int x = 0; +static unsigned int y = 0; +static unsigned int bottom=LINES; +static unsigned int lines=LINES; +static unsigned int columns=COLUMNS; +static unsigned char attr=0x07; + +static mutex console_lock; +static int keyboard_fd = -1; + +static void update_cursor(unsigned int x, unsigned int y) +{ + short int pos = y*columns + x; + + out8(TEXT_CURSOR_LO, TEXT_INDEX); + out8((char)pos, TEXT_DATA); + out8(TEXT_CURSOR_HI, TEXT_INDEX); + out8((char)(pos >> 8), TEXT_DATA); +} + +static void gotoxy(unsigned int new_x,unsigned int new_y) +{ + if (new_x>=columns || new_y>=lines) + return; + x = new_x; + y = new_y; + pos = origin+((y*columns+x)<<1); +} + +static void scrup(void) +{ + unsigned long i; + + // move the screen up one + memcpy((void *)origin, (void *)origin+2*COLUMNS, 2*(LINES-1)*COLUMNS); + + // set the new position to the beginning of the last line + pos = origin + (LINES-1)*COLUMNS*2; + + // clear the bottom line + for(i = pos; i < scr_end; i += 2) { + *(unsigned short *)i = 0x0720; + } +} + +static void lf(void) +{ + if (y+1 0) { + pos -= 2; + x--; + *(unsigned short *)pos = 0x0720; + } +} + +static int saved_x=0; +static int saved_y=0; + +static void save_cur(void) +{ + saved_x=x; + saved_y=y; +} + +static void restore_cur(void) +{ + x=saved_x; + y=saved_y; + pos=origin+((y*columns+x)<<1); +} + +static char console_putch(const char c) +{ + if(++x>=COLUMNS) { + cr(); + lf(); + } + + *(char *)pos = c; + *(char *)(pos+1) = attr; + + pos += 2; + + return c; +} + +static void tab(void) +{ + x = (x + TAB_SIZE) & ~TAB_MASK; + if (x>=COLUMNS) { + x -= COLUMNS; + lf(); + } + pos=origin+((y*columns+x)<<1); +} + +static int console_open(const char *name, uint32 flags, void **cookie) +{ + return 0; +} + +static int console_freecookie(void * cookie) +{ + return 0; +} + +static int console_seek(void * cookie, off_t pos, int st) +{ +// dprintf("console_seek: entry\n"); + + return EPERM; +} + +static int console_close(void * cookie) +{ +// dprintf("console_close: entry\n"); + + return 0; +} + +static ssize_t console_read(void * cookie, off_t pos, void *buf, size_t *len) +{ + /* XXX - optimistic!! */ + *len = sys_read(keyboard_fd, buf, 0, *len); + return 0; +} + +static ssize_t _console_write(const void *buf, size_t len) +{ + size_t i; + const char *c; + + for(i=0; i 0) + err = 0; // we're okay + else + err = ERR_IO_ERROR; + restore_cur(); + mutex_unlock(&console_lock); + break; + } + default: + err = ERR_INVALID_ARGS; + } + + return err; +} + +device_hooks console_hooks = { + &console_open, + &console_close, + &console_freecookie, + &console_ioctl, + &console_read, + &console_write, + NULL, + NULL, +// NULL, +// NULL +}; + +int console_dev_init(kernel_args *ka) +{ + if(!ka->fb.enabled) { + dprintf("con_init: mapping vid mem\n"); + vm_map_physical_memory(vm_get_kernel_aspace_id(), "vid_mem", (void *)&origin, REGION_ADDR_ANY_ADDRESS, + SCREEN_END - SCREEN_START, LOCK_RW|LOCK_KERNEL, SCREEN_START); + dprintf("con_init: mapped vid mem to virtual address 0x%x\n", origin); + + pos = origin; + + gotoxy(0, ka->cons_line); + update_cursor(x, y); + + mutex_init(&console_lock, "console_lock"); + keyboard_fd = sys_open("/dev/keyboard", STREAM_TYPE_DEVICE, 0); + if(keyboard_fd < 0) + panic("console_dev_init: error opening /dev/keyboard\n"); + + // create device node + devfs_publish_device("console", NULL, &console_hooks); + } + + return 0; +} + diff --git a/src/kernel/drivers/arch/x86/ide/Jamfile b/src/kernel/drivers/arch/x86/ide/Jamfile new file mode 100644 index 0000000000..abfa4c4ce5 --- /dev/null +++ b/src/kernel/drivers/arch/x86/ide/Jamfile @@ -0,0 +1,3 @@ +SubDir OBOS_TOP sources os kits kernel drivers arch x86 ide ; + +KernelStaticLibrary libide : ide.c ide_raw.c ; diff --git a/src/kernel/drivers/arch/x86/ide/ide.c b/src/kernel/drivers/arch/x86/ide/ide.c new file mode 100755 index 0000000000..f8f7295e88 --- /dev/null +++ b/src/kernel/drivers/arch/x86/ide/ide.c @@ -0,0 +1,390 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Modified Sep 2001 by Rob Judd +** Distributed under the terms of the NewOS License. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include + +#include "ide_private.h" +#include "ide_raw.h" + +ide_device devices[MAX_DEVICES]; +sem_id ide_sem; + +#define IDE_0_INTERRUPT 14 +#define IDE_1_INTERRUPT 15 +#define MAX_PARTITIONS 8 + +typedef struct +{ + ide_device* dev; // Pointer to entry in 'devices' table + + // Specs for whole disk or partition + uint32 block_start; // Number of first block + uint32 block_count; // Number of blocks used + uint16 block_size; // Bytes per block +} ide_ident; + +//-------------------------------------------------------------------------------- +static int ide_open(const char *name, uint32 flags, void **cookie) +{ + ide_ident* ident = (ide_ident*)kmalloc(sizeof(ide_ident)); + /* We hold our 'ident' structure as cookie, as it contains all we need */ + *cookie = ident; + + return NO_ERROR; +} + +//-------------------------------------------------------------------------------- +static int ide_close(void * _cookie) +{ + return NO_ERROR; +} + +//-------------------------------------------------------------------------------- +static int ide_freecookie(void *cookie) +{ + kfree(cookie); + return NO_ERROR; +} + +//-------------------------------------------------------------------------------- +static int ide_seek(void * cookie, off_t pos, seek_type st) +{ + return ERR_UNIMPLEMENTED; +} + +//-------------------------------------------------------------------------------- +static int ide_get_geometry(ide_device* device, void *buf, size_t len) +{ + drive_geometry* drive_geometry = buf; + + if (len < sizeof(drive_geometry)) + return ERR_VFS_INSUFFICIENT_BUF; + + drive_geometry->blocks = device->end_block - device->start_block; + drive_geometry->heads = device->hardware_device.heads; + drive_geometry->cylinders = device->hardware_device.cyls; + drive_geometry->sectors = device->hardware_device.sectors; + drive_geometry->removable = false; + drive_geometry->bytes_per_sector = device->bytes_per_sector; + drive_geometry->read_only = false; + strcpy(drive_geometry->model, device->hardware_device.model); + strcpy(drive_geometry->serial, device->hardware_device.serial); + strcpy(drive_geometry->firmware, device->hardware_device.firmware); + + return NO_ERROR; +} + + +//-------------------------------------------------------------------------------- +static int ide_ioctl(void * _cookie, uint32 op, void *buf, size_t len) +{ + ide_ident* cookie = (ide_ident*)_cookie; + int err = 0; + + acquire_sem(ide_sem); + + switch(op) { + case DISK_GET_GEOMETRY: + err = ide_get_geometry(cookie->dev,buf,len); + break; + + case DISK_USE_DMA: + case DISK_USE_BUS_MASTERING: + err = ERR_UNIMPLEMENTED; + break; + + case DISK_USE_PIO: + err = NO_ERROR; + break; + + case DISK_GET_ACCOUSTIC_LEVEL: + if (len != sizeof(int8)) { + err = ERR_INVALID_ARGS; + } else { + err = ide_get_accoustic(cookie->dev, (int8*)buf); + } + break; + + case DISK_SET_ACCOUSTIC_LEVEL: + if (len != sizeof(int8)) { + err = ERR_INVALID_ARGS; + } else { + err = ide_set_accoustic(cookie->dev,*(int8*)buf); + } + break; + + default: + err = ERR_INVALID_ARGS; + } + + release_sem(ide_sem); + + return err; +} + +//-------------------------------------------------------------------------------- +static ssize_t ide_read(void * _cookie, off_t pos, void *buf, size_t *len) +{ + ide_ident* cookie = (ide_ident*)_cookie; + uint32 sectors; + uint32 currentSector; + uint32 sectorsToRead; + uint32 block; + + if (cookie == NULL) { + return ERR_INVALID_ARGS; + } + + // Make sure noone else is doing IDE + acquire_sem(ide_sem); + + // Calculate start block and number of blocks to read + block = pos / cookie->block_size; + block += cookie->block_start; + sectors = *len / cookie->block_size; + + // correct len to be the actual # of bytes to read + *len -= *len % cookie->block_size; + + // If it goes beyond the disk/partition, exit + if (block + sectors > cookie->block_start + cookie->block_count) { + release_sem(ide_sem); + *len = 0; + /* XXX - should be returning an error */ + return 0; + } + + // Start reading the sectors + currentSector = 0; + while(currentSector < sectors) { + // Read max. of 255 sectors at a time + sectorsToRead = (sectors - currentSector) > 255 ? 255 : sectors; + + // If the read fails, exit with I/O error + if (ide_read_block(cookie->dev, buf, block, sectorsToRead) != 0) { + release_sem(ide_sem); + return ERR_IO_ERROR; + } + + // Move to next block to read + block += sectorsToRead * cookie->block_size; + currentSector += sectorsToRead; + } + + // Give up + release_sem(ide_sem); + + return 0; +} + +//-------------------------------------------------------------------------------- +static ssize_t ide_write(void * _cookie, off_t pos, const void *buf, size_t *len) +{ + int block; + ide_ident* cookie = _cookie; + uint32 sectors; + uint32 currentSector; + uint32 sectorsToWrite; + + dprintf("ide_write: entry buf %p, pos 0x%Lx, *len %ld\n", buf, pos, *len); + if(cookie == NULL) { + return ERR_INVALID_ARGS; + } + + // Make sure no other I/O is done + acquire_sem(ide_sem); + + // Get the start pos and block count to write + block = pos / cookie->block_size + cookie->block_start; + sectors = *len / cookie->block_size; + + // If we're writing more than the disk/partition size + if (block + sectors > cookie->block_start + cookie->block_count) { + // exit without writing + release_sem(ide_sem); + return 0; + } + + // Loop over sectors to write + currentSector = 0; + while(currentSector < sectors) { + // Write a max of 255 sectors at a time + sectorsToWrite = (sectors - currentSector) > 255 ? 255 : sectors; + + // Write them + if (ide_write_block(cookie->dev, buf, block, sectorsToWrite) != 0) { + // dprintf("ide_write: ide_block returned %d\n", rc); + *len = currentSector * cookie->block_size; + release_sem(ide_sem); + return ERR_IO_ERROR; + } + + block += sectorsToWrite * cookie->block_size; + currentSector += sectorsToWrite; + } + + release_sem(ide_sem); + + return 0; +} + +//-------------------------------------------------------------------------------- +static int ide_canpage(void * ident) +{ + return false; +} + +//-------------------------------------------------------------------------------- +static ssize_t ide_readpage(void * ident, iovecs *vecs, off_t pos) +{ + return ERR_UNIMPLEMENTED; +} + +//-------------------------------------------------------------------------------- +static ssize_t ide_writepage(void * ident, iovecs *vecs, off_t pos) +{ + return ERR_UNIMPLEMENTED; +} + +//-------------------------------------------------------------------------------- +device_hooks ide_hooks = { + ide_open, + ide_close, + ide_freecookie, + ide_ioctl, + ide_read, + ide_write, + NULL, + NULL, +// NULL, +// NULL +}; + +//-------------------------------------------------------------------------------- +static int ide_interrupt_handler(void* data) +{ + dprintf("in ide interrupt handler\n"); + return INT_RESCHEDULE; +} + +//-------------------------------------------------------------------------------- +static ide_ident* ide_create_device_ident(ide_device* dev, int16 partition) +{ + ide_ident* ident = kmalloc(sizeof(ide_ident)); + if (ident != NULL) { + ident->dev = dev; + ident->block_size = dev->bytes_per_sector; + + if (partition >= 0 && partition < MAX_PARTITIONS) { + ident->block_start = dev->partitions[partition].starting_block; + ident->block_count = dev->partitions[partition].sector_count; + } + else + { + ident->block_start = 0; + ident->block_count = dev->sector_count; + } + } + + return ident; +} + +//-------------------------------------------------------------------------------- +static bool ide_attach_device(int bus, int device) +{ + ide_device* ide = &devices[(bus*2) + device]; + ide_ident* ident = NULL; + char devpath[256]; + int part; + + ide->bus = bus; + ide->device = device; + + if (ide_identify_device(bus, device)) { + ide->magic = IDE_MAGIC_COOKIE; + ide->magic2 = IDE_MAGIC_COOKIE2; + + if (ide_get_partitions(ide)) { + for (part=0; part < NUM_PARTITIONS*2; part++) { + if (ide->partitions[part].partition_type != 0 && + (ident=ide_create_device_ident(ide, part)) != NULL) { + sprintf(devpath, "disk/ide/ata/%d/%d/%d", bus, device, part); + devfs_publish_device(devpath, ident, &ide_hooks); + } + } + + dprintf("ide_attach_device(bus=%d,dev=%d) rc=true\n", bus, device); + + return true; + } + } + + dprintf("ide_attach_device(bus=%d,dev=%d) rc=false\n", bus, device); + + return false; +} + +//-------------------------------------------------------------------------------- +static bool ide_attach_buses(unsigned int bus) +{ +// char devpath[256]; + int found = 0; + int dev; + + for(dev=0; dev < 2; dev++) + if (ide_attach_device(bus, dev)) + found++; + + return(found > 0 ? true : false); +} + +//-------------------------------------------------------------------------------- +// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING +//-------------------------------------------------------------------------------- +// Don't try and attach more then one bus to the driver, as ide_raw_init +// overwrites globals and you end up writing blocks which were meant +// for bus #1 to bus #2 :( +// +// !!!!!! So, only use the one or the other, _never_ both !!!!!! +//-------------------------------------------------------------------------------- +int ide_bus_init(kernel_args *ka) +{ + // Create our top-level semaphore + ide_sem = create_sem(1, "ide_sem"); + if (ide_sem < 0) { + // We failed, so tell caller + return ide_sem; + } + + // attach ide bus #1 + int_set_io_interrupt_handler(0x20 + IDE_0_INTERRUPT, &ide_interrupt_handler, NULL); + ide_raw_init(0x1f0, 0x3f0); + ide_attach_buses(0); + + // attach ide bus #2 +// int_set_io_interrupt_handler(0x20 + IDE_1_INTERRUPT, &ide_interrupt_handler, NULL); +// ide_raw_init(0x170, 0x370); +// ide_attach_buses(1); + + return 0; +} diff --git a/src/kernel/drivers/arch/x86/ide/ide_raw.c b/src/kernel/drivers/arch/x86/ide/ide_raw.c new file mode 100755 index 0000000000..ac98646a7c --- /dev/null +++ b/src/kernel/drivers/arch/x86/ide/ide_raw.c @@ -0,0 +1,718 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Heavily modified by Rob Judd with +** acknowledgements to Hale Landis +** who wrote the reference implementation. +** Distributed under the terms of the NewOS License. +*/ + +#include "ide_private.h" +#include +#include +#include +#include "ide_raw.h" +#include "partition.h" +#include +#include +#include +#include +#include + +// ATA register bits + +// command block +#define CB_DATA 0 // data reg in/out pio_base_addr1+0 +#define CB_ERR 1 // error reg in pio_base_addr1+1 +#define CB_FR 1 // feature reg out pio_base_addr1+1 +#define CB_SC 2 // sector count reg in/out pio_base_addr1+2 +#define CB_SN 3 // sector number reg in/out pio_base_addr1+3 + // or block address 0-7 +#define CB_CL 4 // cylinder low reg in/out pio_base_addr1+4 + // or block address 8-15 +#define CB_CH 5 // cylinder high reg in/out pio_base_addr1+5 + // or block address 16-23 +#define CB_DH 6 // drive/head reg in/out pio_base_addr1+6 +#define CB_STAT 7 // primary status reg in pio_base_addr1+7 +#define CB_CMD 7 // command reg out pio_base_addr1+7 + +// control block +#define CB_ASTAT 8 // alternate status reg in pio_base_addr2+6 +#define CB_DC 8 // device control reg out pio_base_addr2+6 +#define CB_DA 9 // device address reg in pio_base_addr2+7 + +// error register +#define CB_ER_NDAM 0x01 // ATA address mark not found +#define CB_ER_NTK0 0x02 // ATA track 0 not found +#define CB_ER_ABRT 0x04 // ATA command aborted +#define CB_ER_MCR 0x08 // ATA media change request +#define CB_ER_IDNF 0x10 // ATA id not found +#define CB_ER_MC 0x20 // ATA media change +#define CB_ER_UNC 0x40 // ATA uncorrected error +#define CB_ER_BBK 0x80 // ATA bad block +#define CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC + +// drive/head register bits 7-4 +#define CB_DH_LBA 0x40 // LBA bit mask +#define CB_DH_DEV0 0xa0 // select device 0 +#define CB_DH_DEV1 0xb0 // select device 1 + +#define DRIVE_SUPPORT_LBA 0x20 // test mask for LBA support + +// status register bits +#define CB_STAT_ERR 0x01 // error (ATA) +#define CB_STAT_CHK 0x01 // check (ATAPI) +#define CB_STAT_IDX 0x02 // index +#define CB_STAT_CORR 0x04 // corrected +#define CB_STAT_DRQ 0x08 // data request +#define CB_STAT_SKC 0x10 // seek complete +#define CB_STAT_SERV 0x10 // service +#define CB_STAT_DF 0x20 // device fault +#define CB_STAT_WFT 0x20 // write fault (old name) +#define CB_STAT_RDY 0x40 // ready +#define CB_STAT_BSY 0x80 // busy + +// device control register bits +#define CB_DC_NIEN 0x02 // disable interrupts +#define CB_DC_SRST 0x04 // soft reset +#define CB_DC_HD15 0x08 // bit should always be set to one + + +// ATAPI commands + +#define CB_ER_P_ILI 0x01 // ATAPI illegal length indication +#define CB_ER_P_EOM 0x02 // ATAPI end of media +#define CB_ER_P_ABRT 0x04 // ATAPI command abort +#define CB_ER_P_MCR 0x08 // ATAPI media change request +#define CB_ER_P_SNSKEY 0xf0 // ATAPI sense key mask + +// ATAPI interrupt reason bits in the sector count register +#define CB_SC_P_CD 0x01 // ATAPI C/D +#define CB_SC_P_IO 0x02 // ATAPI I/O +#define CB_SC_P_REL 0x04 // ATAPI release +#define CB_SC_P_TAG 0xf8 // ATAPI tag (mask) + +//************************************************************** + +// The ATA command set + +// Mandatory commands +#define CMD_EXECUTE_DRIVE_DIAGNOSTIC 0x90 +#define CMD_FORMAT_TRACK 0x50 +#define CMD_INITIALIZE_DRIVE_PARAMETERS 0x91 +#define CMD_READ_LONG 0x22 // One sector inc. ECC, with retry +#define CMD_READ_LONG_ONCE 0x23 // One sector inc. ECC, sans retry +#define CMD_READ_SECTORS 0x20 +#define CMD_READ_SECTORS_ONCE 0x21 +#define CMD_READ_VERIFY_SECTORS 0x40 +#define CMD_READ_VERIFY_SECTORS_ONCE 0x41 +#define CMD_RECALIBRATE 0x10 // Actually 0x10 to 0x1F +#define CMD_SEEK 0x70 // Actually 0x70 to 0x7F +#define CMD_WRITE_LONG 0x32 +#define CMD_WRITE_LONG_ONCE 0x33 +#define CMD_WRITE_SECTORS 0x30 +#define CMD_WRITE_SECTORS_ONCE 0x31 + +// Error codes for CMD_EXECUTE_DRIVE_DIAGNOSTICS +#define DIAG_NO_ERROR 0x01 +#define DIAG_FORMATTER 0x02 +#define DIAG_DATA_BUFFER 0x03 +#define DIAG_ECC_CIRCUITRY 0x04 +#define DIAG_MICROPROCESSOR 0x05 +#define DIAG_SLAVE_DRIVE_MASK 0x80 + +// Accoustic Management commands +#define CMD_SET_ACCOUSTIC_LEVEL 0x2A +#define CMD_GET_ACCOUSTIC_LEVEL 0xAB + +// Command codes for CMD_FORMAT_TRACK +#define FMT_GOOD_SECTOR 0x00 +#define FMT_SUSPEND_REALLOC 0x20 +#define FMT_REALLOC_SECTOR 0x40 +#define FMT_MARK_SECTOR_DEFECTIVE 0x80 + +// Optional commands +#define CMD_ACK_MEDIA_CHANGE 0xDB +#define CMD_BOOT_POSTBOOT 0xDC +#define CMD_BOOT_PREBOOT 0xDD +#define CMD_CFA_ERASE_SECTORS 0xC0 +#define CMD_CFA_REQUEST_EXT_ERR_CODE 0x03 +#define CMD_CFA_TRANSLATE_SECTOR 0x87 +#define CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD +#define CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38 +#define CMD_CHECK_POWER_MODE 0x98 +#define CMD_DEVICE_RESET 0x08 +#define CMD_DOOR_LOCK 0xDE +#define CMD_DOOR_UNLOCK 0xDF +#define CMD_FLUSH_CACHE 0xE7 // CMD_REST +#define CMD_IDENTIFY_DEVICE 0xEC +#define CMD_IDENTIFY_DEVICE_PACKET 0xA1 +#define CMD_IDLE 0x97 +#define CMD_IDLE_IMMEDIATE 0x95 +#define CMD_NOP 0x00 +#define CMD_PACKET 0xA0 +#define CMD_READ_BUFFER 0xE4 +#define CMD_READ_DMA 0xC8 +#define CMD_READ_DMA_QUEUED 0xC7 +#define CMD_READ_MULTIPLE 0xC4 +#define CMD_RESTORE_DRIVE_STATE 0xEA +#define CMD_SET_FEATURES 0xEF +#define CMD_SET_MULTIPLE_MODE 0xC6 +#define CMD_SLEEP 0x99 +#define CMD_STANDBY 0x96 +#define CMD_STANDBY_IMMEDIATE 0x94 +#define CMD_WRITE_BUFFER 0xE8 +#define CMD_WRITE_DMA 0xCA +#define CMD_WRITE_DMA_ONCE 0xCB +#define CMD_WRITE_DMA_QUEUED 0xCC +#define CMD_WRITE_MULTIPLE 0xC5 +#define CMD_WRITE_SAME 0xE9 +#define CMD_WRITE_VERIFY 0x3C + +// Connor Peripherals' variations +#define CONNOR_CHECK_POWER_MODE 0xE5 +#define CONNOR_IDLE 0xE3 +#define CONNOR_IDLE_IMMEDIATE 0xE1 +#define CONNOR_SLEEP 0xE6 +#define CONNOR_STANDBY 0xE2 +#define CONNOR_STANDBY_IMMEDIATE 0xE0 + +//************************************************************** + + +// Waste some time by reading the alternate status a few times. +// This gives the drive time to set BUSY in the status register on +// really fast systems. If we don't do this, a slow drive on a fast +// system may not set BUSY fast enough and we would think it had +// completed the command when it really had not even started yet. +#define DELAY400NS { pio_inbyte(CB_ASTAT); pio_inbyte(CB_ASTAT); \ + pio_inbyte(CB_ASTAT); pio_inbyte(CB_ASTAT); } + +// Standard ide base addresses. For pc-card (pcmcia) drives, use +// unused contiguous address block { 100H < (base1=base2) < 3F0H } +unsigned int pio_base0_addr1 = 0x1f0; // Command block, ide bus 0 +unsigned int pio_base0_addr2 = 0x3f0; // Control block, ide bus 0 +unsigned int pio_base1_addr1 = 0x170; // Command block, ide bus 1 +unsigned int pio_base1_addr2 = 0x370; // Control block, ide bus 1 + +unsigned int pio_memory_seg = 0; +unsigned int pio_reg_addrs[10]; +unsigned char pio_last_read[10]; +unsigned char pio_last_write[10]; + + +static uint8 pio_inbyte(uint16 port) +{ + return in8(pio_reg_addrs[port]); +} + +static uint16 pio_inword(uint16 port) +{ + return in16(pio_reg_addrs[port]); +} + +static void pio_outbyte(uint16 port, uint8 data) +{ + out8(data, pio_reg_addrs[port]); +} + +static void pio_rep_inword(uint16 port, uint16 *addr, unsigned long count) +{ + __asm__ __volatile__ + ( + "rep ; insw" : "=D" (addr), "=c" (count) : "d" (pio_reg_addrs[port]), + "0" (addr), "1" (count) + ); +} + +static void pio_rep_outword(uint16 port, uint16 *addr, unsigned long count) +{ + __asm__ __volatile__ + ( + "rep ; outsw" : "=S" (addr), "=c" (count) : "d" (pio_reg_addrs[port]), + "0" (addr), "1" (count) + ); +} + +static void ide_reg_poll() +{ + while(1) + { + if ((pio_inbyte(CB_ASTAT) & CB_STAT_BSY) == 0) // If not busy + break; + } +} + +static bool ide_wait_busy() +{ + int i; + + for(i=0; i<10000; i++) + { + if ((pio_inbyte(CB_ASTAT) & CB_STAT_BSY) == 0) + return true; + } + return false; +} + +static int ide_select_device(int bus, int device) +{ + uint8 status; + int i; + ide_device ide = devices[(bus*2) + device]; + + // Test for a known, valid device + if(ide.device_type == (NO_DEVICE | UNKNOWN_DEVICE)) + return NO_ERR; + // See if we can get its attention + if(ide_wait_busy() == false) + return ERR_TIMEOUT; + // Select required device + pio_outbyte(CB_DH, device ? CB_DH_DEV1 : CB_DH_DEV0); + DELAY400NS; + for(i=0; i<10000; i++) + { + // Read the device status + status = pio_inbyte(CB_STAT); + if (ide.device_type == ATA_DEVICE) + { + if ((status & (CB_STAT_BSY | CB_STAT_RDY | CB_STAT_SKC)) + == (CB_STAT_RDY | CB_STAT_SKC)) + return NO_ERR; + } + else + { + if ((status & CB_STAT_BSY) == 0) + return NO_ERR; + } + } + return ERR_TIMEOUT; +} + +static void ide_delay(int bus, int device) +{ + ide_device ide = devices[(bus*2) + device]; + + if(ide.device_type == ATAPI_DEVICE) + thread_snooze(1000000); + + return; +} + +static int reg_pio_data_in(int bus, int dev, int cmd, int fr, int sc, + unsigned int cyl, int head, int sect, uint8 *output, + unsigned int numSect, unsigned int multiCnt) +{ + unsigned char devHead; + unsigned char devCtrl; + unsigned char cylLow; + unsigned char cylHigh; + unsigned char status; + uint16 *buffer = (uint16*)output; + +// dprintf("reg_pio_data_in: bus %d dev %d cmd %d fr %d sc %d cyl %d head %d sect %d numSect %d multiCnt %d\n", +// bus, dev, cmd, fr, sc, cyl, head, sect, numSect, multiCnt); + + devCtrl = CB_DC_HD15 | CB_DC_NIEN; + devHead = dev ? CB_DH_DEV1 : CB_DH_DEV0; + devHead = devHead | (head & 0x4f); + cylLow = cyl & 0x00ff; + cylHigh = (cyl & 0xff00) >> 8; + // these commands transfer only 1 sector + if(cmd == (CMD_IDENTIFY_DEVICE | CMD_IDENTIFY_DEVICE_PACKET | CMD_READ_BUFFER)) + numSect = 1; + // multiCnt = 1 unless CMD_READ_MULTIPLE true + if(cmd != CMD_READ_MULTIPLE || !multiCnt) + multiCnt = 1; + // select the drive + if(ide_select_device(bus, dev) == ERR_TIMEOUT) + return ERR_TIMEOUT; + // set up the registers + pio_outbyte(CB_DC, devCtrl); + pio_outbyte(CB_FR, fr); + pio_outbyte(CB_SC, sc); + pio_outbyte(CB_SN, sect); + pio_outbyte(CB_CL, cylLow); + pio_outbyte(CB_CH, cylHigh); + pio_outbyte(CB_DH, devHead); + // Start the command. The drive should immediately set BUSY status. + pio_outbyte(CB_CMD, cmd); + DELAY400NS; + while(1) + { + ide_delay(bus, dev); + // ensure drive isn't still busy + ide_reg_poll(); + // check status once per read + status = pio_inbyte(CB_STAT); + if((numSect < 1) && (status & CB_STAT_DRQ)) + return ERR_BUFFER_NOT_EMPTY; + if (numSect < 1) + break; + if((status & (CB_STAT_BSY | CB_STAT_DRQ)) == CB_STAT_DRQ) + { + unsigned int wordCnt = multiCnt > numSect ? numSect : multiCnt; + wordCnt = wordCnt * 256; + pio_rep_inword(CB_DATA, buffer, wordCnt); + DELAY400NS; + numSect = numSect - multiCnt; + buffer += wordCnt; + } + // catch all possible fault conditions + if(status & CB_STAT_BSY) + return ERR_DISK_BUSY; + if(status & CB_STAT_DF) + return ERR_DEVICE_FAULT; + if(status & CB_STAT_ERR) + return ERR_HARDWARE_ERROR; + if((status & CB_STAT_DRQ) == 0) + return ERR_DRQ_NOT_SET; + } + return NO_ERR; +} + +static int reg_pio_data_out( int bus, int dev, int cmd, int fr, int sc, + unsigned int cyl, int head, int sect, const uint8 *output, + unsigned int numSect, unsigned int multiCnt ) +{ + unsigned char devHead; + unsigned char devCtrl; + unsigned char cylLow; + unsigned char cylHigh; + unsigned char status; + uint16 *buffer = (uint16*)output; + + devCtrl = CB_DC_HD15 | CB_DC_NIEN; + devHead = dev ? CB_DH_DEV1 : CB_DH_DEV0; + devHead = devHead | (head & 0x4f); + cylLow = cyl & 0x00ff; + cylHigh = (cyl & 0xff00) >> 8; + if (cmd == CMD_WRITE_BUFFER) + numSect = 1; + // only Write Multiple and CFA Write Multiple W/O Erase uses multCnt + if ((cmd != CMD_WRITE_MULTIPLE) && (cmd != CMD_CFA_WRITE_MULTIPLE_WO_ERASE)) + multiCnt = 1; + // select the drive + if (ide_select_device(bus, dev) != NO_ERR) + return ERR_TIMEOUT; + // set up the registers + pio_outbyte(CB_DC, devCtrl); + pio_outbyte(CB_FR, fr); + pio_outbyte(CB_SC, sc); + pio_outbyte(CB_SN, sect); + pio_outbyte(CB_CL, cylLow); + pio_outbyte(CB_CH, cylHigh); + pio_outbyte(CB_DH, devHead); + // Start the command. The drive should immediately set BUSY status. + pio_outbyte(CB_CMD, cmd); + DELAY400NS; + if (ide_wait_busy() == false) + return ERR_TIMEOUT; + status = pio_inbyte(CB_STAT); + while (1) + { + if ((status & (CB_STAT_BSY | CB_STAT_DRQ)) == CB_STAT_DRQ) + { + unsigned int wordCnt = multiCnt > numSect ? numSect : multiCnt; + wordCnt = wordCnt * 256; + pio_rep_outword(CB_DATA, buffer, wordCnt); + DELAY400NS; + numSect = numSect - multiCnt; + buffer += wordCnt; + } + // check all possible fault conditions + if(status & CB_STAT_BSY) + return ERR_DISK_BUSY; + if(status & CB_STAT_DF) + return ERR_DEVICE_FAULT; + if(status & CB_STAT_ERR) + return ERR_HARDWARE_ERROR; + if ((status & CB_STAT_DRQ) == 0) + return ERR_DRQ_NOT_SET; + ide_delay(bus, dev); + // ensure drive isn't still busy + ide_reg_poll(); + if(numSect < 1 && status & (CB_STAT_BSY | CB_STAT_DF | CB_STAT_ERR)) + { + dprintf("status = 0x%x\n", status); + return ERR_BUFFER_NOT_EMPTY; + } + } + return NO_ERR; +} + +static void ide_btochs(uint32 block, ide_device *dev, int *cylinder, int *head, int *sect) +{ + *sect = (block % dev->hardware_device.sectors) + 1; + block /= dev->hardware_device.sectors; + *head = (block % dev->hardware_device.heads) | (dev->device ? 1 : 0); + block /= dev->hardware_device.heads; + *cylinder = block & 0xFFFF; +// dprintf("ide_btochs: block %d -> cyl %d head %d sect %d\n", block, *cylinder, *head, *sect); +} + +static void ide_btolba(uint32 block, ide_device *dev, int *cylinder, int *head, int *sect) +{ + *sect = block & 0xFF; + *cylinder = (block >> 8) & 0xFFFF; + *head = ((block >> 24) & 0xF) | (dev->device ? 1: 0) | CB_DH_LBA; +// dprintf("ide_btolba: block %d -> cyl %d head %d sect %d\n", block, *cylinder, *head, *sect); +} + +int ide_read_block(ide_device *device, char *data, uint32 block, uint8 numSectors) +{ + int cyl, head, sect; + + if(device->lba_supported) + ide_btolba(block, device, &cyl, &head, §); + else + ide_btochs(block, device, &cyl, &head, §); + + return reg_pio_data_in(device->bus, device->device, CMD_READ_SECTORS, + 0, numSectors, cyl, head, sect, data, numSectors, 2); +} + +int ide_write_block(ide_device *device, const char *data, uint32 block, uint8 numSectors) +{ + int cyl, head, sect; + + if(device->lba_supported) + ide_btolba(block, device, &cyl, &head, §); + else + ide_btochs(block, device, &cyl, &head, §); + + return reg_pio_data_out(device->bus, device->device, CMD_WRITE_SECTORS, + 0, numSectors, cyl, head, sect, data, numSectors, 2); +} + +void ide_string_conv (char *str, int len) +{ + unsigned int i; + int j; + + for (i=0; i=0 && str[j]==' '; j--) + str[j] = 0; +} + +// ide_reset() - execute a software reset +bool ide_reset (int bus, int device) +{ + unsigned char devCtrl = CB_DC_HD15 | CB_DC_NIEN; + + // Set and then reset the soft reset bit in the Device + // Control register. This causes device 0 be selected + pio_outbyte(CB_DC, devCtrl | CB_DC_SRST); + DELAY400NS; + pio_outbyte(CB_DC, devCtrl); + DELAY400NS; + + return (ide_wait_busy() ? true : false); +} + +bool ide_identify_device(int bus, int device) +{ + ide_device* ide = &devices[(bus*2) + device]; + uint8* buffer; + int rc; + + // Store specs for device + ide->bus = bus; + ide->device = device; + + // Do an IDENTIFY DEVICE command + buffer = (uint8*)&ide->hardware_device; + rc = reg_pio_data_in(bus, device, CMD_IDENTIFY_DEVICE, + 1, 0, 0, 0, 0, buffer, 1, 0); + + if (rc == NO_ERR) { + // If command was ok, lets assume ATA device + ide->device_type = ATA_DEVICE; + + // Convert the model string to ASCIIZ + ide_string_conv(ide->hardware_device.model, 40); + + // Get copy over interesting data + ide->sector_count = ide->hardware_device.cyls * ide->hardware_device.heads + * ide->hardware_device.sectors; + ide->bytes_per_sector = 512; + ide->lba_supported = ide->hardware_device.capabilities & DRIVE_SUPPORT_LBA; + ide->start_block = 0; + ide->end_block = ide->sector_count + ide->start_block; + + // Give some debugging output to show what was found + dprintf ("ide: disk at bus %d, device %d %s\n", bus, device, ide->hardware_device.model); + dprintf ("ide/%d/%d: %dMB; %d cyl, %d head, %d sec, %d bytes/sec (LBA=%d)\n", + bus, device, ide->sector_count * ide->bytes_per_sector / (1024*1024), + ide->hardware_device.cyls, ide->hardware_device.heads, + ide->hardware_device.sectors, ide->bytes_per_sector, ide->lba_supported ); + } else { + // Something went wrong, let's forget about this device + ide->device_type = NO_DEVICE; + } + + return (rc == NO_ERROR) ? true : false; +} + +// Set the pio base addresses +void ide_raw_init(int base1, int base2) +{ + unsigned int pio_base_addr1 = base1; + unsigned int pio_base_addr2 = base2; + + pio_reg_addrs[CB_DATA] = pio_base_addr1 + 0; // 0 + pio_reg_addrs[CB_FR ] = pio_base_addr1 + 1; // 1 + pio_reg_addrs[CB_SC ] = pio_base_addr1 + 2; // 2 + pio_reg_addrs[CB_SN ] = pio_base_addr1 + 3; // 3 + pio_reg_addrs[CB_CL ] = pio_base_addr1 + 4; // 4 + pio_reg_addrs[CB_CH ] = pio_base_addr1 + 5; // 5 + pio_reg_addrs[CB_DH ] = pio_base_addr1 + 6; // 6 + pio_reg_addrs[CB_CMD ] = pio_base_addr1 + 7; // 7 + pio_reg_addrs[CB_DC ] = pio_base_addr2 + 6; // 8 + pio_reg_addrs[CB_DA ] = pio_base_addr2 + 7; // 9 +} + +static char getHexChar(uint8 value) +{ + if(value < 10) + return value + '0'; + return 'A' + (value - 10); +} + +static void dumpHexLine(uint8 *buffer, int numberPerLine) +{ + uint8 *copy = buffer; + int i; + + for(i=0; i> 4)); + uint8 value2 = getHexChar(((*copy) & 0xF)); + dprintf("%c%c ", value1, value2); + copy++; + } + copy = buffer; + for(i=0; i= ' ' && *copy <= 'Z') + dprintf("%c", *copy); + else + dprintf("."); + copy++; + } + dprintf("\n"); +} + +static void dumpHexBuffer(uint8 *buffer, int size) +{ + int numberPerLine = 8; + int numberOfLines = size / numberPerLine; + int i; + + for(i=0; ipartitions, 0, sizeof(tPartition) * 2 * NUM_PARTITIONS); + if(ide_get_partition_info(device, device->partitions, 0) == false) + return false; + + dprintf("Primary Partition Table\n"); + for (i = 0; i < NUM_PARTITIONS; i++) + { + dprintf(" %d: flags:%x type:%x start:%d:%d:%d end:%d:%d:%d stblk:%d count:%d\n", + i, + device->partitions[i].boot_flags, + device->partitions[i].partition_type, + device->partitions[i].starting_head, + device->partitions[i].starting_sector, + device->partitions[i].starting_cylinder, + device->partitions[i].ending_head, + device->partitions[i].ending_sector, + device->partitions[i].ending_cylinder, + device->partitions[i].starting_block, + device->partitions[i].sector_count); + } + if(device->partitions[1].partition_type == PTDosExtended) + { + int extOffset = device->partitions[1].starting_block; + if(ide_get_partition_info(device, &device->partitions[4], extOffset) == false) + return false; + dprintf("Extended Partition Table\n"); + for (i=4; i<4+NUM_PARTITIONS; i++) + { + device->partitions[i].starting_block += extOffset; + dprintf(" %d: flags:%x type:%x start:%d:%d:%d end:%d:%d:%d stblk:%d count:%d\n", + i, + device->partitions[i].boot_flags, + device->partitions[i].partition_type, + device->partitions[i].starting_head, + device->partitions[i].starting_sector, + device->partitions[i].starting_cylinder, + device->partitions[i].ending_head, + device->partitions[i].ending_sector, + device->partitions[i].ending_cylinder, + device->partitions[i].starting_block, + device->partitions[i].sector_count); + } + } + return true; +} + + +// These two functions are called from ide_ioctl in ide.c. They are far from +// tested, and mostly just a C conversion of a DEBUG script presented on +// http://www.satwerk.de/ufd552.htm +// This should be tweaked some more before actual release! + +int ide_get_accoustic(ide_device *device, int8* level_ptr) +{ + return ERR_UNIMPLEMENTED; +} + +int ide_set_accoustic(ide_device *device, int8 level) +{ + pio_outbyte(CB_DH, (device->device == 1) ? CB_DH_DEV1 : CB_DH_DEV0); + pio_outbyte(CB_CMD, CMD_SET_ACCOUSTIC_LEVEL); + pio_outbyte(CB_SC, level); + pio_outbyte(CB_STAT, 0xEF); + + return NO_ERROR; +} diff --git a/src/kernel/drivers/arch/x86/keyboard/Jamfile b/src/kernel/drivers/arch/x86/keyboard/Jamfile new file mode 100644 index 0000000000..362e871942 --- /dev/null +++ b/src/kernel/drivers/arch/x86/keyboard/Jamfile @@ -0,0 +1,3 @@ +SubDir OBOS_TOP sources os kits kernel drivers arch x86 keyboard ; + +KernelObjects keyboard.c : -fno-pic ; diff --git a/src/kernel/drivers/arch/x86/keyboard/keyboard.c b/src/kernel/drivers/arch/x86/keyboard/keyboard.c new file mode 100755 index 0000000000..cabf5b4384 --- /dev/null +++ b/src/kernel/drivers/arch/x86/keyboard/keyboard.c @@ -0,0 +1,317 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +#define LSHIFT 42 +#define RSHIFT 54 +#define SCRLOCK 70 +#define NUMLOCK 69 +#define CAPS 58 +#define SYSREQ 55 +#define F11 87 +#define F12 88 + +#define LED_SCROLL 1 +#define LED_NUM 2 +#define LED_CAPS 4 + +static bool shift; +static int leds; +static sem_id keyboard_sem; +static mutex keyboard_read_mutex; +static char keyboard_buf[1024]; +static unsigned int head, tail; + +// stolen from nujeffos +const char unshifted_keymap[128] = { + 0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 8, '\t', + 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', 0, 'a', 's', + 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 0, '\\', 'z', 'x', 'c', 'v', + 'b', 'n', 'm', ',', '.', '/', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + '\\', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +const char shifted_keymap[128] = { + 0, 27, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', 8, '\t', + 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', 0, 'A', 'S', + 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', 0, '\\', 'Z', 'X', 'C', 'V', + 'B', 'N', 'M', '<', '>', '?', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +const char caps_keymap[128] = { + 0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 8, '\t', + 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '[', ']', '\n', 0, 'A', 'S', + 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', '\'', '`', 0, '\\', 'Z', 'X', 'C', 'V', + 'B', 'N', 'M', '<', '>', '?', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + '\\', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static void wait_for_output(void) +{ + while(in8(0x64) & 0x2) + ; +} + +static void set_leds(void) +{ + wait_for_output(); + out8(0xed, 0x60); + wait_for_output(); + out8(leds, 0x60); +} + +static ssize_t _keyboard_read(void *_buf, size_t len) +{ + unsigned int saved_tail; + char *buf = _buf; + size_t copied_bytes = 0; + size_t copy_len; + int rc; + + if(len > sizeof(keyboard_buf) - 1) + len = sizeof(keyboard_buf) - 1; + +retry: + // block here until data is ready + rc = acquire_sem_etc(keyboard_sem, 1, B_CAN_INTERRUPT, 0); + if(rc == ERR_SEM_INTERRUPTED) { + return 0; + } + + // critical section + mutex_lock(&keyboard_read_mutex); + + saved_tail = tail; + if(head == saved_tail) { + mutex_unlock(&keyboard_read_mutex); + goto retry; + } else { + // copy out of the buffer + if(head < saved_tail) + copy_len = min(len, saved_tail - head); + else + copy_len = min(len, sizeof(keyboard_buf) - head); + memcpy(buf, &keyboard_buf[head], copy_len); + copied_bytes = copy_len; + head = (head + copy_len) % sizeof(keyboard_buf); + if(head == 0 && saved_tail > 0 && copied_bytes < len) { + // we wrapped around and have more bytes to read + // copy the first part of the buffer + copy_len = min(saved_tail, len - copied_bytes); + memcpy(&buf[len], &keyboard_buf[0], copy_len); + copied_bytes += copy_len; + head = copy_len; + } + } + if(head != saved_tail) { + // we did not empty the keyboard queue + release_sem_etc(keyboard_sem, 1, B_DO_NOT_RESCHEDULE); + } + + mutex_unlock(&keyboard_read_mutex); + + return copied_bytes; +} + +static void insert_in_buf(char c) +{ + unsigned int temp_tail = tail; + + // see if the next char will collide with the head + temp_tail++; + temp_tail %= sizeof(keyboard_buf); + if(temp_tail == head) { + // buffer overflow, ditch this char + return; + } + keyboard_buf[tail] = c; + tail = temp_tail; + release_sem_etc(keyboard_sem, 1, B_DO_NOT_RESCHEDULE); +} + +static int handle_keyboard_interrupt(void* data) +{ + unsigned char key; + int retval = INT_NO_RESCHEDULE; + + key = in8(0x60); +// dprintf("handle_keyboard_interrupt: key = 0x%x\n", key); + + if(key & 0x80) { + // keyup + if(key == LSHIFT + 0x80 || key == RSHIFT + 0x80) + shift = false; + } else { + switch(key) { + case LSHIFT: + case RSHIFT: + shift = true; + break; + case CAPS: + if(leds & LED_CAPS) + leds &= ~LED_CAPS; + else + leds |= LED_CAPS; + set_leds(); + break; + case SCRLOCK: + if(leds & LED_SCROLL) { + leds &= ~LED_SCROLL; + dbg_set_serial_debug(false); + } else { + leds |= LED_SCROLL; + dbg_set_serial_debug(true); + } + set_leds(); + break; + case NUMLOCK: + if(leds & LED_NUM) + leds &= ~LED_NUM; + else + leds |= LED_NUM; + set_leds(); + break; + case SYSREQ: + panic("Keyboard Requested Halt\n"); + break; + case F11: + dbg_set_serial_debug(dbg_get_serial_debug()?false:true); + break; + case F12: + reboot(); + break; + default: { + char ascii; + + if(shift) + ascii = shifted_keymap[key]; + else + if (leds & LED_CAPS) + ascii = caps_keymap[key]; + else + ascii = unshifted_keymap[key]; + +// dprintf("ascii = 0x%x, '%c'\n", ascii, ascii); + if(ascii != 0) { + insert_in_buf(ascii); + retval = INT_RESCHEDULE; + } else { +// dprintf("keyboard: unknown scan-code 0x%x\n",key); + } + } + } + } + return retval; +} + +static int keyboard_open(const char *name, uint32 flags, void * *cookie) +{ + *cookie = NULL; + return 0; +} + +static int keyboard_close(void * cookie) +{ + return 0; +} + +static int keyboard_freecookie(void * cookie) +{ + return 0; +} + +static int keyboard_seek(void * cookie, off_t pos, int st) +{ + return EPERM; +} + +static ssize_t keyboard_read(void * cookie, off_t pos, void *buf, size_t *len) +{ + int rv; + if (*len < 0) + return 0; + + rv = _keyboard_read(buf, *len); + if (rv < 0) + return rv; + *len = rv; + return 0; +} + +static ssize_t keyboard_write(void * cookie, off_t pos, const void *buf, size_t *len) +{ + return ERR_VFS_READONLY_FS; +} + +static int keyboard_ioctl(void * cookie, uint32 op, void *buf, size_t len) +{ + return EINVAL; +} + +device_hooks keyboard_hooks = { + &keyboard_open, + &keyboard_close, + &keyboard_freecookie, + &keyboard_ioctl, + &keyboard_read, + &keyboard_write, + NULL, + NULL, +// NULL, +// NULL +}; + +static int setup_keyboard(void) +{ + keyboard_sem = create_sem(0, "keyboard_sem"); + if(keyboard_sem < 0) + panic("could not create keyboard sem!\n"); + + if(mutex_init(&keyboard_read_mutex, "keyboard_read_mutex") < 0) + panic("could not create keyboard read mutex!\n"); + + shift = 0; + leds = 0; + // have the scroll lock reflect the state of serial debugging + if(dbg_get_serial_debug()) + leds |= LED_SCROLL; + set_leds(); + + head = tail = 0; + + return 0; +} + +int keyboard_dev_init(kernel_args *ka) +{ + setup_keyboard(); + int_set_io_interrupt_handler(0x21,&handle_keyboard_interrupt, NULL); + + devfs_publish_device("keyboard", NULL, &keyboard_hooks); + + return 0; +} diff --git a/src/kernel/drivers/arch/x86/ps2mouse/Jamfile b/src/kernel/drivers/arch/x86/ps2mouse/Jamfile new file mode 100644 index 0000000000..5c12ce346f --- /dev/null +++ b/src/kernel/drivers/arch/x86/ps2mouse/Jamfile @@ -0,0 +1,3 @@ +SubDir OBOS_TOP sources os kits kernel drivers arch x86 ps2mouse ; + +KernelObjects ps2mouse.c : -D_PS2MOUSE_ ; diff --git a/src/kernel/drivers/arch/x86/ps2mouse/ps2mouse.c b/src/kernel/drivers/arch/x86/ps2mouse/ps2mouse.c new file mode 100755 index 0000000000..54984c28f1 --- /dev/null +++ b/src/kernel/drivers/arch/x86/ps2mouse/ps2mouse.c @@ -0,0 +1,340 @@ +/* + * ps2mouse.c: + * PS/2 mouse device driver for NewOS and OpenBeOS. + * Author: Elad Lahav (elad@eldarshany.com) + * Created: 21.12.2001 + * Modified: 11.1.2002 + */ + +/* + * A PS/2 mouse is connected to the IBM 8042 controller, and gets its + * name from the IBM PS/2 personal computer, which was the first to + * use this device. All resources are shared between the keyboard, and + * the mouse, referred to as the "Auxiliary Device". + * I/O: + * ~~~ + * The controller has 3 I/O registers: + * 1. Status (input), mapped to port 64h + * 2. Control (output), mapped to port 64h + * 3. Data (input/output), mapped to port 60h + * Data: + * ~~~~ + * Since a mouse is an input only device, data can only be read, and + * not written. A packet read from the mouse data port is composed of + * three bytes: + * byte 0: status byte, where + * - bit 0: Y overflow (1 = true) + * - bit 1: X overflow (1 = true) + * - bit 2: MSB of Y offset + * - bit 3: MSB of X offset + * - bit 4: Syncronization bit (always 1) + * - bit 5: Middle button (1 = down) + * - bit 6: Right button (1 = down) + * - bit 7: Left button (1 = down) + * byte 1: X position change, since last probed (-127 to +127) + * byte 2: Y position change, since last probed (-127 to +127) + * Interrupts: + * ~~~~~~~~~~ + * The PS/2 mouse device is connected to interrupt 12, which means that + * it uses the second interrupt controller (handles INT8 to INT15). In + * order for this interrupt to be enabled, both the 5th interrupt of + * the second controller AND the 3rd interrupt of the first controller + * (cascade mode) should be unmasked. + * The controller uses 3 consecutive interrupts to inform the computer + * that it has new data. On the first the data register holds the status + * byte, on the second the X offset, and on the 3rd the Y offset. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define _PS2MOUSE_ +#include + +///////////////////////////////////////////////////////////////////////// +// interrupt + +/* + * handle_mouse_interrupt: + * Interrupt handler for the mouse device. Called whenever the I/O + * controller generates an interrupt for the PS/2 mouse. Reads mouse + * information from the data port, and stores it, so it can be accessed + * by read() operations. The full data is obtained using 3 consecutive + * calls to the handler, each holds a different byte on the data port. + * Parameters: + * void*, ignored + * Return value: + * int, ??? + */ +static int handle_mouse_interrupt(void* data) +{ + char c; + static int next_input = 0; + + // read port + c = in8(PS2_PORT_DATA); + + // put port contents in the appropriate data member, according to + // current cycle + switch(next_input) { + // status byte + case 0: + md_int.status = c; + break; + + // x-axis change + case 1: + md_int.delta_x += c; + break; + + // y-axis change + case 2: + md_int.delta_y += c; + + // check if someone is waiting to read data + if(in_read) { + // copy data to read structure, and release waiting process + memcpy(&md_read, &md_int, sizeof(mouse_data)); + memset(&md_int, 0, sizeof(mouse_data)); + in_read = false; + release_sem_etc(mouse_sem, 1, B_DO_NOT_RESCHEDULE); + } // if + break; + } // switch + + next_input = (next_input + 1) % 3; + return INT_NO_RESCHEDULE; +} // handle_mouse_interrupt + +///////////////////////////////////////////////////////////////////////// +// file operations + +/* + * mouse_open: + */ +static int mouse_open(const char *name, uint32 flags, void **cookie) +{ + *cookie = NULL; + return 0; +} // mouse_open + +/* + * mouse_close: + */ +static int mouse_close(void * cookie) +{ + return 0; +} // mouse_close + +/* + * mouse_freecookie: + */ +static int mouse_freecookie(void * cookie) +{ + return 0; +} // mouse_freecookie + +/* + * mouse_seek: + */ +static int mouse_seek(void * cookie, off_t pos, int st) +{ + return EPERM; +} // mouse_seek + +/* + * mouse_read: + * Gets a mouse data packet. + * Parameters: + * void *, ignored + * void*, pointer to a buffer that accepts the data + * off_t, ignored + * ssize_t, buffer size, must be at least the size of the data packet + */ +static ssize_t mouse_read(void * cookie, off_t pos, void* buf, size_t *len) +{ + // inform interrupt handler that data is being waited for + in_read = true; + + // wait until there is data to read + if(acquire_sem_etc(mouse_sem, 1, B_CAN_INTERRUPT, 0) == + ERR_SEM_INTERRUPTED) { + return 0; + } // if + + // verify user's buffer is of the right size + if(*len < PACKET_SIZE) { + *len = 0; + /* XXX - should return an error here */ + return 0; + } + + // copy data to user's buffer + ((char*)buf)[0] = md_read.status; + ((char*)buf)[1] = md_read.delta_x; + ((char*)buf)[2] = md_read.delta_y; + + *len = PACKET_SIZE; + return 0; +} // mouse_read + +/* + * mouse_write: + */ +static ssize_t mouse_write(void * cookie, off_t pos, const void *buf, size_t *len) +{ + *len = 0; + return ERR_VFS_READONLY_FS; +} // mouse_write + +/* + * mouse_ioctl: + */ +static int mouse_ioctl(void * cookie, uint32 op, void *buf, size_t len) +{ + return ERR_INVALID_ARGS; +} // mouse_ioctl + +/* + * function structure used for file-op registration + */ +device_hooks ps2_mouse_hooks = { + &mouse_open, + &mouse_close, + &mouse_freecookie, + &mouse_ioctl, + &mouse_read, + &mouse_write, + NULL, + NULL, +// NULL, +// NULL +}; // ps2_mouse_hooks + +///////////////////////////////////////////////////////////////////////// +// initialization + +/* + * wait_write_ctrl: + * Wait until the control port is ready to be written. This requires that + * the "Input buffer full" and "Output buffer full" bits will both be set + * to 0. + */ +static void wait_write_ctrl() +{ + while(in8(PS2_PORT_CTRL) & 0x3); +} // wait_for_ctrl_output + +/* + * wait_write_data: + * Wait until the data port is ready to be written. This requires that + * the "Input buffer full" bit will be set to 0. + */ +static void wait_write_data() +{ + while(in8(PS2_PORT_CTRL) & 0x2); +} // wait_write_data + +/* + * wait_read_data: + * Wait until the data port can be read from. This requires that the + * "Output buffer full" bit will be set to 1. + */ +static void wait_read_data() +{ + while((in8(PS2_PORT_CTRL) & 0x1) == 0); +} // wait_read_data + +/* + * write_command_byte: + * Writes a command byte to the data port of the PS/2 controller. + * Parameters: + * unsigned char, byte to write + */ +static void write_command_byte(unsigned char b) +{ + wait_write_ctrl(); + out8(PS2_CTRL_WRITE_CMD, PS2_PORT_CTRL); + wait_write_data(); + out8(b, PS2_PORT_DATA); +} // write_command_byte + +/* + * write_aux_byte: + * Writes a byte to the mouse device. Uses the control port to indicate + * that the byte is sent to the auxiliary device (mouse), instead of the + * keyboard. + * Parameters: + * unsigned char, byte to write + */ +static void write_aux_byte(unsigned char b) +{ + wait_write_ctrl(); + out8(PS2_CTRL_WRITE_AUX, PS2_PORT_CTRL); + wait_write_data(); + out8(b, PS2_PORT_DATA); +} // write_aux_byte + +/* + * read_data_byte: + * Reads a single byte from the data port. + * Return value: + * unsigned char, byte read + */ +static unsigned char read_data_byte() +{ + wait_read_data(); + return in8(PS2_PORT_DATA); +} // read_data_byte + +/* + * mouse_dev_init: + * Called by the kernel to setup the device. Initializes the driver. + * Parameters: + * kernel_args*, ignored + * Return value: + * int, 0 if successful, negative error value otherwise + */ +int mouse_dev_init(kernel_args *ka) +{ + dprintf("Initializing PS/2 mouse\n"); + + // init device driver + memset(&md_int, 0, sizeof(mouse_data)); + + // register interrupt handler + int_set_io_interrupt_handler(INT_BASE + INT_PS2_MOUSE, + &handle_mouse_interrupt, NULL); + + // must enable the cascade interrupt + arch_int_enable_io_interrupt(INT_BASE + INT_CASCADE); + + // enable auxilary device, IRQs and PS/2 mouse + write_command_byte(PS2_CMD_DEV_INIT); + write_aux_byte(PS2_CMD_ENABLE_MOUSE); + + // controller should send ACK if mouse was detected + if(read_data_byte() != PS2_RES_ACK) { + dprintf("No PS/2 mouse found\n"); + return -1; + } // if + + dprintf("A PS/2 mouse has been successfully detected\n"); + + // create the mouse semaphore, used for synchronization between + // the interrupt handler and the read() operation + mouse_sem = create_sem(0, "ps2_mouse_sem"); + if(mouse_sem < 0) + panic("failed to create PS/2 mouse semaphore!\n"); + + // register device file-system like operations + devfs_publish_device("ps2mouse", NULL, &ps2_mouse_hooks); + + return 0; +} // mouse_dev_init diff --git a/src/kernel/drivers/beos.c b/src/kernel/drivers/beos.c new file mode 100755 index 0000000000..1ad4735233 --- /dev/null +++ b/src/kernel/drivers/beos.c @@ -0,0 +1,516 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef 0 //ARCH_x86 + +// contains a bunch of beos defines +#include "beos_p.h" + +// private funcs +static uint8 read8(int port); +static void write8(int port, uint8 data); +static uint16 read16(int port); +static void write16(int port, uint16 data); +static uint32 read32(int port); +static void write32(int port, uint32 data); +static void unhandled_isa_call(void); + +/* +static int translation_open(void * ident, void * *cookie); +static int translation_close(void * cookie); +static int translation_freecookie(void * cookie); +static int translation_seek(void * cookie, off_t pos, seek_type st); +static int translation_ioctl(void * cookie, int op, void *buf, size_t len); +static ssize_t translation_read(void * cookie, void *buf, off_t pos, ssize_t len); +static ssize_t translation_write(void * cookie, const void *buf, off_t pos, ssize_t len); +static int translation_canpage(void * ident); +static ssize_t translation_readpage(void * ident, iovecs *vecs, off_t pos); +static ssize_t translation_writepage(void * ident, iovecs *vecs, off_t pos); +*/ + +static int newos2beos_err(int err); +static int beos2newos_err(int err); + +isa_module_info isa = { + { /* binfo */ + { "isa", 0, NULL }, /* minfo */ + (void *)unhandled_isa_call + }, + read8, + write8, + read16, + write16, + read32, + write32, + (void *)unhandled_isa_call, + (void *)unhandled_isa_call, + (void *)unhandled_isa_call, + (void *)unhandled_isa_call, + (void *)unhandled_isa_call, + (void *)unhandled_isa_call +}; + +//struct module { +// const char *name; +// void *data; +//} modules[] = { +// { B_ISA_MODULE_NAME, &isa }, +// { NULL, NULL } +//}; + +int beos_layer_init(void) +{ + return 0; +} + +int _beos_atomic_add(volatile int *val, int incr) +{ + return atomic_add(val, incr); +} + +int _beos_atomic_and(volatile int *val, int incr) +{ + return atomic_and(val, incr); +} + +int _beos_atomic_or(volatile int *val, int incr) +{ + return atomic_or(val, incr); +} + +int _beos_acquire_sem(sem_id id) +{ + return newos2beos_err(sem_acquire(id, 1)); +} + +int _beos_acquire_sem_etc(sem_id id, uint32 count, uint32 flags, bigtime_t timeout) +{ + int nuflags = 0; + bigtime_t nutimeout = timeout; + + if(flags & B_CAN_INTERRUPT) + nuflags |= SEM_FLAG_INTERRUPTABLE; + if(flags & B_DO_NOT_RESCHEDULE) + nuflags |= SEM_FLAG_NO_RESCHED; + if(flags & B_RELATIVE_TIMEOUT) + nuflags |= SEM_FLAG_TIMEOUT; + if(flags & B_ABSOLUTE_TIMEOUT) { + nuflags |= SEM_FLAG_TIMEOUT; + nutimeout = timeout - system_time(); + if(nutimeout < 0) + nutimeout = 0; + } + return newos2beos_err(sem_acquire_etc(id, count, nuflags, nutimeout, NULL)); +} + +sem_id _beos_create_sem(uint32 count, const char *name) +{ + return newos2beos_err(sem_create(count, name)); +} + +int _beos_delete_sem(sem_id id) +{ + return newos2beos_err(sem_delete(id)); +} + +int _beos_get_sem_count(sem_id id, int32 *count) +{ + panic("_beos_get_sem_count: not supported\n"); + return 0; +} + +int _beos_release_sem(sem_id id) +{ + return newos2beos_err(sem_release(id, 1)); +} + +int _beos_release_sem_etc(sem_id id, int32 count, uint32 flags) +{ + int nuflags = 0; + + if(flags & B_DO_NOT_RESCHEDULE) + nuflags = SEM_FLAG_NO_RESCHED; + + return newos2beos_err(sem_release_etc(id, count, nuflags)); +} + +int _beos_strcmp(const char *cs, const char *ct) +{ + return strcmp(cs, ct); +} + +void _beos_spin(bigtime_t microseconds) +{ + bigtime_t time = system_time(); + + while((system_time() - time) < microseconds) + ; +} + +/* +int _beos_get_module(const char *path, module_info **vec) +{ + struct module *m; + + dprintf("get_module: called on '%s'\n", path); + for(m = modules; m->name; m++) { + if(!strcmp(path, m->name)) { + *vec = m->data; + return NO_ERROR; + } + } + return ERR_GENERAL; +} + +int _beos_put_module(const char *path) +{ + dprintf("put_module: called on '%s'\n", path); + return NO_ERROR; +} +*/ + +static uint8 read8(int port) +{ + return in8(port); +} + +static void write8(int port, uint8 data) +{ +// dprintf("w8 0x%x, 0x%x\n", port, data); + out8(data, port); +} + +static uint16 read16(int port) +{ + return in16(port); +} + +static void write16(int port, uint16 data) +{ +// dprintf("w16 0x%x, 0x%x\n", port, data); + out16(data, port); +} + +static uint32 read32(int port) +{ + return in32(port); +} + +static void write32(int port, uint32 data) +{ +// dprintf("w32 0x%x, 0x%x\n", port, data); + out32(data, port); +} + +static void unhandled_isa_call(void) +{ + panic("call into unhandled isa function\n"); +} + +static int beos2newos_err(int err) +{ + if(err >= 0) + return err; + + switch(err) { + case B_NO_MEMORY: return ERR_NO_MEMORY; + case B_IO_ERROR: return ERR_IO_ERROR; + case B_PERMISSION_DENIED: return ERR_PERMISSION_DENIED; + case B_NAME_NOT_FOUND: return ERR_NOT_FOUND; + case B_TIMED_OUT: return ERR_SEM_TIMED_OUT; + case B_INTERRUPTED: return ERR_SEM_INTERRUPTED; + case B_NOT_ALLOWED: return ERR_NOT_ALLOWED; + case B_ERROR: return ERR_GENERAL; + case B_BAD_SEM_ID: return ERR_INVALID_HANDLE; + case B_NO_MORE_SEMS: return ERR_SEM_OUT_OF_SLOTS; + case B_BAD_THREAD_ID: return ERR_INVALID_HANDLE; + case B_NO_MORE_THREADS: return ERR_NO_MORE_HANDLES; + case B_BAD_TEAM_ID: return ERR_INVALID_HANDLE; + case B_NO_MORE_TEAMS: return ERR_NO_MORE_HANDLES; + case B_BAD_PORT_ID: return ERR_INVALID_HANDLE; + case B_NO_MORE_PORTS: return ERR_NO_MORE_HANDLES; + case B_BAD_IMAGE_ID: return ERR_INVALID_HANDLE; + case B_NOT_AN_EXECUTABLE: return ERR_INVALID_BINARY; + default: return ERR_GENERAL; + } +} + +static int newos2beos_err(int err) +{ + if(err >= 0) + return err; + + switch(err) { + case ERR_NO_MEMORY: return B_NO_MEMORY; + case ERR_IO_ERROR: return B_IO_ERROR; + case ERR_TIMED_OUT: return B_TIMED_OUT; + case ERR_NOT_ALLOWED: return B_NOT_ALLOWED; + case ERR_PERMISSION_DENIED: return B_PERMISSION_DENIED; + case ERR_INVALID_BINARY: return B_NOT_AN_EXECUTABLE; + + case ERR_SEM_DELETED: return B_CANCELED; + case ERR_SEM_TIMED_OUT: return B_TIMED_OUT; + case ERR_SEM_OUT_OF_SLOTS: return B_NO_MORE_SEMS; + case ERR_SEM_INTERRUPTED: return B_INTERRUPTED; + default: return B_ERROR; + } +} + +/* +static int translation_open(void * ident, void * *_cookie) +{ + struct beos_device_node *node = (struct beos_device_node *)ident; + struct beos_device_cookie *cookie; + void *beos_cookie; + int err; + + err = node->beos_hooks->open(node->name, 0, &beos_cookie); + if(err < 0) + return beos2newos_err(err); + + cookie = kmalloc(sizeof(struct beos_device_cookie)); + if(!cookie) + return ERR_NO_MEMORY; + + cookie->node = node; + cookie->beos_cookie = beos_cookie; + cookie->pos = 0; + + *_cookie = cookie; + + return NO_ERROR; +} + +static int translation_close(void * _cookie) +{ + struct beos_device_cookie *cookie = _cookie; + int err; + + err = cookie->node->beos_hooks->close(cookie->beos_cookie); + if(err < 0) + return beos2newos_err(err); + + return NO_ERROR; +} + +static int translation_freecookie(void * _cookie) +{ + struct beos_device_cookie *cookie = _cookie; + int err; + + err = cookie->node->beos_hooks->free(cookie->beos_cookie); + if(err < 0) + return beos2newos_err(err); + + kfree(cookie); + + return NO_ERROR; +} + +static int translation_seek(void * _cookie, off_t pos, seek_type st) +{ + struct beos_device_cookie *cookie = _cookie; + int err = NO_ERROR; + off_t nupos; + + switch(st) { + case SEEK_SET: + if(pos < 0) + pos = 0; + cookie->pos = pos; + break; + case SEEK_CUR: + nupos = cookie->pos + pos; + if(nupos < 0) + nupos = 0; + cookie->pos = nupos; + break; + case SEEK_END: + default: + err = ERR_INVALID_ARGS; + } + return err; +} + +static int translation_ioctl(void * _cookie, int op, void *buf, size_t len) +{ + struct beos_device_cookie *cookie = _cookie; + int err; + + err = cookie->node->beos_hooks->control(cookie->beos_cookie, op, buf, len); + if(err < 0) + return beos2newos_err(err); + return NO_ERROR; +} + +static ssize_t translation_read(void * _cookie, void *buf, off_t pos, ssize_t _len) +{ + struct beos_device_cookie *cookie = _cookie; + int err; + bool update_cookie = false; + size_t len; + + if(pos < 0) { + update_cookie = true; + pos = cookie->pos; + } + + if(_len < 0) + len = 0; + else + len = _len; + + err = cookie->node->beos_hooks->read(cookie->beos_cookie, pos, buf, &len); + if(err < 0) + return beos2newos_err(err); + + if(update_cookie) { + cookie->pos += len; + } + return len; +} + +static ssize_t translation_write(void * _cookie, const void *buf, off_t pos, ssize_t _len) +{ + struct beos_device_cookie *cookie = _cookie; + int err; + bool update_cookie = false; + size_t len; + + if(pos < 0) { + update_cookie = true; + pos = cookie->pos; + } + + if(_len < 0) + len = 0; + else + len = _len; + + err = cookie->node->beos_hooks->write(cookie->beos_cookie, pos, buf, &len); + if(err < 0) + return beos2newos_err(err); + + if(update_cookie) { + cookie->pos += len; + } + return len; +} + +static int translation_canpage(void * ident) +{ + return 0; +} + +static ssize_t translation_readpage(void * ident, iovecs *vecs, off_t pos) +{ + return ERR_NOT_ALLOWED; +} + +static ssize_t translation_writepage(void * ident, iovecs *vecs, off_t pos) +{ + return ERR_NOT_ALLOWED; +} +*/ +/* +image_id beos_load_beos_driver(const char *name) +{ + image_id id; + char path[SYS_MAX_PATH_LEN]; + char **names; + int i; + + int (*init_hardware)(void); + int (*init_driver)(void); + char **(*publish_devices)(void); + beos_device_hooks *(*find_device)(const char *name); + int *api_version; + + sprintf(path, "/boot/addons/beosdev/%s", name); + + id = elf_load_kspace(path, "_beos_"); + if(id < 0) + return id; + + api_version = (int *)elf_lookup_symbol(id, "api_version"); + if(!api_version || *api_version != B_CUR_DRIVER_API_VERSION) + return ERR_INVALID_BINARY; + +// dprintf("calling init_hardware\n"); + + init_hardware = (void *)elf_lookup_symbol(id, "init_hardware"); + if(!init_hardware) + return ERR_INVALID_BINARY; + init_hardware(); + +// dprintf("done calling init_hardware\n"); + +// dprintf("calling init_driver\n"); + + init_driver = (void *)elf_lookup_symbol(id, "init_driver"); + if(!init_driver) + return ERR_INVALID_BINARY; + init_driver(); + +// dprintf("done calling init_driver\n"); + +// dprintf("calling publish_devices\n"); + + publish_devices = (void *)elf_lookup_symbol(id, "publish_devices"); + if(!publish_devices) + return ERR_INVALID_BINARY; + names = publish_devices(); + +// dprintf("done calling publish_devices\n"); + + find_device = (void *)elf_lookup_symbol(id, "find_device"); + if(!publish_devices) + return ERR_INVALID_BINARY; + + for(i=0; names[i]; i++) { + struct beos_device_node *node; + +// dprintf("publishing name '%s'\n", names[i]); + + node = kmalloc(sizeof(struct beos_device_node)); + + node->name = names[i]; + node->beos_hooks = find_device(names[i]); + + devfs_publish_device(names[i], node, &translation_hooks); + + node->next = nodes; + nodes = node; + } + + return id; +} +*/ +#else + +int beos_layer_init(void) +{ + return 0; +} + +image_id beos_load_beos_driver(const char *name) +{ + return ERR_GENERAL; +} + +#endif + diff --git a/src/kernel/drivers/dev.c b/src/kernel/drivers/dev.c new file mode 100755 index 0000000000..11c96e5894 --- /dev/null +++ b/src/kernel/drivers/dev.c @@ -0,0 +1,100 @@ +/* Contains code to load dev module and bootstrap it */ + +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +const char *device_paths[] = { + "/boot/addons/drivers/dev/misc", + "/boot/addons/drivers/dev/net", + NULL +}; + +int dev_init(kernel_args *ka) +{ + int fd; + const char **ptr; + + dprintf("dev_init: entry\n"); + + for (ptr = device_paths; (*ptr); ptr++) { +dprintf("DEV: looking at directory %s\n", *ptr); + fd = sys_open(*ptr, STREAM_TYPE_DIR, 0); + if(fd >= 0) { + ssize_t len; + char buf[SYS_MAX_NAME_LEN]; + + while((len = sys_read(fd, buf, 0, sizeof(buf))) > 0) { + dprintf("loading '%s' dev module\n", buf); + dev_load_dev_module(buf, *ptr); + } + sys_close(fd); + } + } + + return 0; +} + +image_id dev_load_dev_module(const char *name, const char *dirpath) +{ + image_id id; + status_t (*init_hardware)(void); + const char **(*publish_devices)(void); + device_hooks *(*find_device)(const char *); + void (*bootstrap)(); + char path[SYS_MAX_PATH_LEN]; + const char **devfs_paths; + device_hooks *hooks; + + sprintf(path, "%s/%s", dirpath, name); + + id = elf_load_kspace(path, ""); + if(id < 0) + return id; + + init_hardware = (void*)elf_lookup_symbol(id, "init_hardware"); + if (init_hardware) { +// dprintf("DEV: found init_hardware in %s\n", name); + if (init_hardware() != 0) { + dprintf("DEV: %s: init_hardware failed :(\n", name); + elf_unload_kspace(path); + return ENXIO; + } +// dprintf("DEV: Well alright - %s init'd OK!\n", name); + publish_devices = (void*)elf_lookup_symbol(id, "publish_devices"); +// dprintf("DEV: %s: found publish_devices\n", name); + devfs_paths = publish_devices(); +// dprintf("DEV: %s: publish_devices = %p\n", name, (char*)devfs_paths); + for (; *devfs_paths; devfs_paths++) { + dprintf("DEV: %s: wants to be known as %s\n", name, *devfs_paths); + } + find_device = (void*)elf_lookup_symbol(id, "find_device"); + if (!find_device) { + elf_unload_kspace(path); + return EFTYPE; + } + /* Should really cycle through these... */ + devfs_paths = publish_devices(); + for (; *devfs_paths; devfs_paths++) { + hooks = find_device(*devfs_paths); + if (hooks) + devfs_publish_device(*devfs_paths, NULL, hooks); + } + } else + return EFTYPE; + + return id; +} diff --git a/src/kernel/drivers/devs.c b/src/kernel/drivers/devs.c new file mode 100755 index 0000000000..02cfbab673 --- /dev/null +++ b/src/kernel/drivers/devs.c @@ -0,0 +1,52 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include + +#include + +#ifdef ARCH_x86 +#include +#include +#include +#include +#include +#endif +#ifdef ARCH_sh4 +#include +#include +#include +#include +#endif +#include +#include +#include + +int devs_init(kernel_args *ka) +{ + + null_dev_init(ka); + zero_dev_init(ka); +#ifdef ARCH_x86 +// ide_bus_init(ka); + keyboard_dev_init(ka); +// mouse_dev_init(ka); + console_dev_init(ka); +// rtl8139_dev_init(ka); +// netblock_dev_init(ka); +#endif + +#ifdef ARCH_sh4 + maple_bus_init(ka); + keyboard_dev_init(ka); +// console_dev_init(ka); + rtl8139_dev_init(ka); +#endif + fb_console_dev_init(ka); + + return 0; +} diff --git a/src/kernel/drivers/fb_console/Jamfile b/src/kernel/drivers/fb_console/Jamfile new file mode 100644 index 0000000000..f0b47b4c69 --- /dev/null +++ b/src/kernel/drivers/fb_console/Jamfile @@ -0,0 +1,4 @@ +SubDir OBOS_TOP sources os kits kernel drivers fb_console ; + +KernelStaticLibrary fb_console : fb_console.c ; + diff --git a/src/kernel/drivers/fb_console/fb_console.c b/src/kernel/drivers/fb_console/fb_console.c new file mode 100755 index 0000000000..30d7f889a8 --- /dev/null +++ b/src/kernel/drivers/fb_console/fb_console.c @@ -0,0 +1,477 @@ +/* +** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "font.h" + +int fb_console_dev_init(kernel_args *ka); + +#if 0 +// this version makes the sh4 compiler throw up +#define WRAP(x, limit) ((x) % (limit)) +#define INC_WITH_WRAP(x, limit) WRAP((x) + 1, (limit)) +#else +#define WRAP(x, limit) (((x) >= (limit)) ? ((x) - (limit)) : (x)) +#define INC_WITH_WRAP(x, limit) WRAP((x) + 1, (limit)) +#endif + +enum { + CONSOLE_OP_WRITEXY = 2376 +}; + +#define TAB_SIZE 8 +#define TAB_MASK 7 + +struct console_desc { + // describe the framebuffer + addr fb; + addr fb_size; + int fb_x; + int fb_y; + int fb_pixel_bytes; + + // describe the setup we have + int rows; + int columns; + + // describe the current state + int x; + int y; + int color; + int bcolor; + int saved_x; + int saved_y; + + // text buffers + char *buf; + int first_line; + int num_lines; + char **lines; + uint8 *dirty_lines; + void *render_buf; + + // renderer function + void (*render_line)(char *line, int line_num); + + mutex lock; + int keyboard_fd; +}; + +static struct console_desc console; + +static void render_line16(char *line, int line_num) +{ + int x; + int y; + int i; + uint16 *fb_spot = (uint16 *)(console.fb + line_num * CHAR_HEIGHT * console.fb_x * 2); + + for(y = 0; y < CHAR_HEIGHT; y++) { + uint16 *render_spot = console.render_buf; + for(x = 0; x < console.columns; x++) { + if(line[x]) { + uint8 bits = FONT[CHAR_HEIGHT * line[x] + y]; + for(i = 0; i < CHAR_WIDTH; i++) { + if(bits & 1) *render_spot = console.color; + else *render_spot = console.bcolor; + bits >>= 1; + render_spot++; + } + } else { + // null character, ignore the rest of the line + memset(render_spot, 0, (console.columns - x) * CHAR_WIDTH * 2); + break; + } + } + memcpy(fb_spot, console.render_buf, console.fb_x * 2); + fb_spot += console.fb_x; + } +} + +static void render_line32(char *line, int line_num) +{ + int x; + int y; + int i; + uint32 *fb_spot = (uint32 *)(console.fb + line_num * CHAR_HEIGHT * console.fb_x * 4); + + for(y = 0; y < CHAR_HEIGHT; y++) { + uint32 *render_spot = console.render_buf; + for(x = 0; x < console.columns; x++) { + if(line[x]) { + uint8 bits = FONT[CHAR_HEIGHT * line[x] + y]; + for(i = 0; i < CHAR_WIDTH; i++) { + if(bits & 1) *render_spot = console.color; + else *render_spot = console.bcolor; + bits >>= 1; + render_spot++; + } + } else { + // null character, ignore the rest of the line + memset(render_spot, 0, (console.columns - x) * CHAR_WIDTH * 4); + break; + } + + } + memcpy(fb_spot, console.render_buf, console.fb_x * 4); + fb_spot += console.fb_x; + } +} + +// scans through the lines, seeing if any needs to be repainted +static void repaint() +{ + int i; + int line_num; + + line_num = console.first_line; + for(i = 0; i < console.rows; i++) { +// dprintf("line_num = %d\n", line_num); + if(console.dirty_lines[line_num]) { +// dprintf("repaint(): rendering line %d %d\n", line_num, i); + console.render_line(console.lines[line_num], i); + console.dirty_lines[line_num] = 0; + } + line_num = INC_WITH_WRAP(line_num, console.num_lines); + } +} + +static void scrup(void) +{ + int i; + int line_num; + int last_line; + + // move the pointer to the top line down one + console.first_line = INC_WITH_WRAP(console.first_line, console.num_lines); + +// dprintf("scrup: first_line now %d\n", console.first_line); + + line_num = console.first_line; + for(i=0; i 0) { + console.x--; + console.lines[target_line][console.x] = ' '; + console.dirty_lines[target_line] = 1; + } +} + +static void save_cur(void) +{ + console.saved_x = console.x; + console.saved_y = console.y; +} + +static void restore_cur(void) +{ + console.x = console.saved_x; + console.y = console.saved_y; +} + +static char console_putch(const char c) +{ + int target_line; + + if(console.x+1 >= console.columns) { + cr(); + lf(); + } + + target_line = WRAP(console.first_line + console.y, console.num_lines); +// dprintf("target_line = %d\n", target_line); + console.lines[target_line][console.x++] = c; + console.lines[target_line][console.x] = 0; + console.dirty_lines[target_line] = 1; + + return c; +} + +static void tab(void) +{ + console.x = (console.x + TAB_SIZE) & ~TAB_MASK; + if (console.x >= console.columns) { + console.x -= console.columns; + lf(); + } +} + +static int console_open(const char *name, uint32 flags, void **cookie) +{ + return 0; +} + +static int console_freecookie(void * cookie) +{ + return 0; +} + +static int console_seek(void * cookie, off_t pos, int st) +{ +// dprintf("console_seek: entry\n"); + + return EPERM; +} + +static int console_close(void * cookie) +{ +// dprintf("console_close: entry\n"); + + return 0; +} + +static ssize_t console_read(void * cookie, off_t pos, void *buf, + size_t *len) +{ + return sys_read(console.keyboard_fd, buf, 0, *len); +} + +static ssize_t _console_write(const void *buf, size_t *len) +{ + size_t i; + const char *c; + + for(i=0; i < *len; i++) { + c = &((const char *)buf)[i]; + switch(*c) { + case '\n': + cr(); + lf(); + break; + case '\r': + cr(); + break; + case 0x8: // backspace + del(); + break; + case '\t': // tab + tab(); + break; + case '\0': + break; + default: + console_putch(*c); + } + } + return 0; +} + +static ssize_t console_write(void * cookie, off_t pos, + const void *buf, size_t *len) +{ + ssize_t err; + +// dprintf("console_write: entry, len = %d\n", len); + + mutex_lock(&console.lock); + + err = _console_write(buf, len); +// update_cursor(x, y); + repaint(); + + mutex_unlock(&console.lock); + + return err; +} + +static int console_ioctl(void * cookie, uint32 op, void *buf, size_t len) +{ + int err; + size_t wlen; + + switch(op) { + case CONSOLE_OP_WRITEXY: { + int x,y; + mutex_lock(&console.lock); + + x = ((int *)buf)[0]; + y = ((int *)buf)[1]; + + save_cur(); +// gotoxy(x, y); + wlen = len - 2 * sizeof(int); + if(_console_write(((char *)buf) + 2*sizeof(int), &wlen) == 0) + err = 0; // we're okay + else + err = ERR_IO_ERROR; + restore_cur(); + mutex_unlock(&console.lock); + break; + } + default: + err = ERR_INVALID_ARGS; + } + + return err; +} + +device_hooks fb_console_hooks = { + &console_open, + &console_close, + &console_freecookie, + &console_ioctl, + &console_read, + &console_write, + NULL, + NULL, +// NULL, +// NULL +}; + +int fb_console_dev_init(kernel_args *ka) +{ + if(ka->fb.enabled) { + int i; + + dprintf("fb_console_dev_init: framebuffer found at 0x%lx, x %d, y %d, bit depth %d\n", + ka->fb.mapping.start, ka->fb.x_size, ka->fb.y_size, ka->fb.bit_depth); + + memset(&console, 0, sizeof(console)); + + if(ka->fb.already_mapped) { + console.fb = ka->fb.mapping.start; + } else { + vm_map_physical_memory(vm_get_kernel_aspace_id(), "vesa_fb", (void *)&console.fb, REGION_ADDR_ANY_ADDRESS, + ka->fb.mapping.size, LOCK_RW|LOCK_KERNEL, ka->fb.mapping.start); + } + + console.fb_x = ka->fb.x_size; + console.fb_y = ka->fb.y_size; + console.fb_pixel_bytes = ka->fb.bit_depth / 8; + console.fb_size = ka->fb.mapping.size; + + switch(console.fb_pixel_bytes) { + case 2: + console.render_line = &render_line16; + console.color = 0xffff; + console.bcolor = 0; + break; + case 4: + console.render_line = &render_line32; + console.color = 0x00ffffff; + console.bcolor = 0; + break; + case 1: + default: + return 0; + } + + dprintf("framebuffer mapped at 0x%lx\n", console.fb); + + // figure out the number of rows/columns we have + console.rows = console.fb_y / CHAR_HEIGHT; + console.columns = console.fb_x / CHAR_WIDTH; + dprintf("%d rows %d columns\n", console.rows, console.columns); + + console.x = 0; + console.y = 0; + console.saved_x = 0; + console.saved_y = 0; + + dprintf("console %p\n", &console); + + // allocate some memory for this + console.render_buf = kmalloc(console.fb_x * console.fb_pixel_bytes); + memset((void *)console.render_buf, 0, console.fb_x * console.fb_pixel_bytes); + console.buf = kmalloc(console.rows * (console.columns+1)); + memset(console.buf, 0, console.rows * (console.columns+1)); + console.lines = kmalloc(console.rows * sizeof(char *)); + console.dirty_lines = kmalloc(console.rows); + // set up the line pointers + for(i=0; ifb.y_size; i++) { + uint16 row[ka->fb.x_size]; + for(j=0; jfb.x_size; j++) { + uint8 byte = j+i+k; + row[j] = byte; + } + memcpy(console.fb + i*ka->fb.x_size*2, row, sizeof(row)); + } + } +} +#endif + } + + return 0; +} + diff --git a/src/kernel/glue/Jamfile b/src/kernel/glue/Jamfile new file mode 100755 index 0000000000..ca6ac2d969 --- /dev/null +++ b/src/kernel/glue/Jamfile @@ -0,0 +1,4 @@ +SubDir OBOS_TOP sources os kits kernel glue ; + +KernelObjects lib0.c crt0.c ; + diff --git a/src/kernel/glue/crt0.c b/src/kernel/glue/crt0.c new file mode 100755 index 0000000000..1edf5b6694 --- /dev/null +++ b/src/kernel/glue/crt0.c @@ -0,0 +1,56 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#include +#include +#include + +extern int __stdio_init(void); +extern int __stdio_deinit(void); + +extern void sys_exit(int retcode); + +extern void (*__ctor_list)(void); +extern void (*__ctor_end)(void); + +extern int main(int argc,char **argv); + +int _start(struct uspace_prog_args_t *); +void _call_ctors(void); + +static char empty[1]; +char *__progname = empty; + +int _start(struct uspace_prog_args_t *uspa) +{ + int retcode; + register char *ap; + _call_ctors(); + +// __stdio_init(); + + if ((ap = uspa->argv[0])) { + if ((__progname = strrchr(ap, '/')) == NULL) + __progname = ap; + else + ++__progname; + } + + retcode = main(uspa->argc, uspa->argv); + +// __stdio_deinit(); + sys_exit(retcode); + return 0; +} + +void _call_ctors(void) +{ + void (**f)(void); + + for(f = &__ctor_list; f < &__ctor_end; f++) { + (**f)(); + } +} + diff --git a/src/kernel/glue/lib0.c b/src/kernel/glue/lib0.c new file mode 100755 index 0000000000..a7100548a5 --- /dev/null +++ b/src/kernel/glue/lib0.c @@ -0,0 +1,56 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Copyright 2002, Manuel J. Petit. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + +#include +#include + +extern void sys_exit(int retcode); + +extern void (*__ctor_list)(void); +extern void (*__ctor_end)(void); + +int _start(unsigned image_id, struct uspace_prog_args_t *); +static void _call_ctors(void); + +int +_start(unsigned imid, struct uspace_prog_args_t *uspa) +{ +// int i; +// int retcode; + void *ibc; + void *iac; + + ibc= uspa->rld_export->dl_sym(imid, "INIT_BEFORE_CTORS", 0); + iac= uspa->rld_export->dl_sym(imid, "INIT_AFTER_CTORS", 0); + + if(ibc) { + ((libinit_f*)(ibc))(imid, uspa); + } + _call_ctors(); + if(iac) { + ((libinit_f*)(iac))(imid, uspa); + } + + return 0; +} + +static +void _call_ctors(void) +{ + void (**f)(void); + + for(f = &__ctor_list; f < &__ctor_end; f++) { + (**f)(); + } +} + +int __gxx_personality_v0(void); + +// XXX hack to make gcc 3.x happy until we get libstdc++ working +int __gxx_personality_v0(void) +{ + return 0; +} diff --git a/src/kernel/ldscripts/sh4/library.ld b/src/kernel/ldscripts/sh4/library.ld new file mode 100644 index 0000000000..98553d8a0b --- /dev/null +++ b/src/kernel/ldscripts/sh4/library.ld @@ -0,0 +1,73 @@ +OUTPUT_FORMAT("elf32-shl", "elf32-shl", "elf32-shl") +OUTPUT_ARCH(sh) + +ENTRY(_start) +SEARCH_DIR("libgcc"); +SECTIONS +{ + . = 0x00200000 + SIZEOF_HEADERS; + + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0x9090 + .plt : { *(.plt) } + + /* text/read-only data */ + .text : { *(.text .gnu.linkonce.t.*) } + + .rodata : { *(.rodata) } + + /* writable data */ + . = ALIGN(0x1000) + (. & (0x1000 - 1)); + __data_start = .; + PROVIDE(_data_start = .); + .data : { *(.data .gnu.linkonce.d.*) } + + __ctor_list = .; + PROVIDE (_ctor_list = .); + .ctors : { *(.ctors) } + __ctor_end = .; + PROVIDE (_ctor_end = .); + + __dtor_list = .; + PROVIDE (_dtor_list = .); + .dtors : { *(.dtors) } + __dtor_end = .; + PROVIDE (_dtor_end = .); + + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + + + /* unintialized data (in same segment as writable data) */ + PROVIDE (__bss_start = .); + .bss : { *(.bss) } + + . = ALIGN(0x1000); + PROVIDE (_end = .); + + /* Strip unnecessary stuff */ + /DISCARD/ : { *(.comment .note .eh_frame .dtors) } +} diff --git a/src/kernel/ldscripts/x86/app.ld b/src/kernel/ldscripts/x86/app.ld new file mode 100644 index 0000000000..607f8cc7c6 --- /dev/null +++ b/src/kernel/ldscripts/x86/app.ld @@ -0,0 +1,73 @@ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) + +ENTRY(_start) +SEARCH_DIR("libgcc"); +SECTIONS +{ + . = 0x00200000 + SIZEOF_HEADERS; + + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0x9090 + .plt : { *(.plt) } + + /* text/read-only data */ + .text : { *(.text .gnu.linkonce.t.*) } + + .rodata : { *(.rodata) } + + /* writable data */ + . = ALIGN(0x1000) + (. & (0x1000 - 1)); + __data_start = .; + PROVIDE(_data_start = .); + .data : { *(.data .gnu.linkonce.d.*) } + + __ctor_list = .; + PROVIDE (_ctor_list = .); + .ctors : { *(.ctors) } + __ctor_end = .; + PROVIDE (_ctor_end = .); + + __dtor_list = .; + PROVIDE (_dtor_list = .); + .dtors : { *(.dtors) } + __dtor_end = .; + PROVIDE (_dtor_end = .); + + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + + + /* unintialized data (in same segment as writable data) */ + PROVIDE (__bss_start = .); + .bss : { *(.bss) } + + . = ALIGN(0x1000); + PROVIDE (_end = .); + + /* Strip unnecessary stuff */ + /DISCARD/ : { *(.comment .note .eh_frame .dtors) } +} diff --git a/src/kernel/ldscripts/x86/library.ld b/src/kernel/ldscripts/x86/library.ld new file mode 100644 index 0000000000..607f8cc7c6 --- /dev/null +++ b/src/kernel/ldscripts/x86/library.ld @@ -0,0 +1,73 @@ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) + +ENTRY(_start) +SEARCH_DIR("libgcc"); +SECTIONS +{ + . = 0x00200000 + SIZEOF_HEADERS; + + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0x9090 + .plt : { *(.plt) } + + /* text/read-only data */ + .text : { *(.text .gnu.linkonce.t.*) } + + .rodata : { *(.rodata) } + + /* writable data */ + . = ALIGN(0x1000) + (. & (0x1000 - 1)); + __data_start = .; + PROVIDE(_data_start = .); + .data : { *(.data .gnu.linkonce.d.*) } + + __ctor_list = .; + PROVIDE (_ctor_list = .); + .ctors : { *(.ctors) } + __ctor_end = .; + PROVIDE (_ctor_end = .); + + __dtor_list = .; + PROVIDE (_dtor_list = .); + .dtors : { *(.dtors) } + __dtor_end = .; + PROVIDE (_dtor_end = .); + + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + + + /* unintialized data (in same segment as writable data) */ + PROVIDE (__bss_start = .); + .bss : { *(.bss) } + + . = ALIGN(0x1000); + PROVIDE (_end = .); + + /* Strip unnecessary stuff */ + /DISCARD/ : { *(.comment .note .eh_frame .dtors) } +} diff --git a/src/kernel/libroot/Jamfile b/src/kernel/libroot/Jamfile new file mode 100755 index 0000000000..f60d8d666d --- /dev/null +++ b/src/kernel/libroot/Jamfile @@ -0,0 +1,3 @@ +SubDir OBOS_TOP sources os kits kernel libroot ; + +KernelObjects libroot.c : -fPIC -DPIC ; diff --git a/src/kernel/libroot/libroot.c b/src/kernel/libroot/libroot.c new file mode 100755 index 0000000000..23918953e0 --- /dev/null +++ b/src/kernel/libroot/libroot.c @@ -0,0 +1,237 @@ +#include +#include +#include +#include +#include + +// Names don't match, but basic function does. Little work needed on addr_spec. +area_id create_area(const char *name, void **start_addr, uint32 addr_spec, size_t size, uint32 lock, uint32 protection) + { return sys_vm_create_anonymous_region(name,start_addr,addr_spec,size,lock,protection); } + +// Not 100% sure about the REGION_PRIVATE_MAP +area_id clone_area(const char *name, void **dest_addr, uint32 addr_spec, uint32 protection, area_id source) + { return sys_vm_clone_region(name,dest_addr, addr_spec,source, REGION_PRIVATE_MAP,protection); } + +// TO DO - add a syscall interface +area_id find_area(const char *name) + { return sys_find_region_by_name(name);} + +// TO DO +area_id area_for(void *addr); + +// This is ok. +status_t delete_area(area_id id) + { return sys_vm_delete_region(id);} + +// TO DO +status_t resize_area(area_id id, size_t new_size); +// TO DO +status_t set_area_protection(area_id id, uint32 new_protection); + +// TO DO - convert region_info in VM land to area_info... +status_t _get_area_info(area_id id, area_info *ainfo, size_t size) + { + if (size < sizeof(ainfo)) + return B_ERROR; + else + return sys_vm_get_region_info(id, (void *)ainfo); + } + +// TO DO +status_t _get_next_area_info(team_id team, int32 *cookie, area_info *ainfo, size_t size); + + +// OK +port_id create_port(int32 capacity, const char *name) + { return sys_port_create(capacity,name); } + +// OK +port_id find_port(const char *name) + { return sys_port_find(name); } + +// OK +status_t write_port(port_id port, int32 code, const void *buf, size_t buf_size) + { return sys_port_write(port, code, buf, buf_size); } + +// OK +status_t read_port(port_id port, int32 *code, void *buf, size_t buf_size) + { return sys_port_read(port,code,buf,buf_size); } + +// Alter flags (?) +status_t write_port_etc(port_id port, int32 code, const void *buf, size_t buf_size, uint32 flags, bigtime_t timeout) + { return sys_port_write_etc(port,code,buf,buf_size,flags,timeout); } + +// Alter flags (?) +status_t read_port_etc(port_id port, int32 *code, void *buf, size_t buf_size, uint32 flags, bigtime_t timeout) + { return sys_port_read_etc(port,code,buf,buf_size,flags,timeout); } + +// OK +ssize_t port_buffer_size(port_id port) { return sys_port_buffer_size(port); } + +// Change the flags? +ssize_t port_buffer_size_etc(port_id port, uint32 flags, bigtime_t timeout) { return sys_port_buffer_size_etc(port,flags,timeout); } + +// OK +ssize_t port_count(port_id port) +{ return sys_port_count(port); } + +// OK +int set_port_owner(port_id port, team_id team) +{ return sys_port_set_owner(port, team); } + +// OK +status_t close_port(port_id port) { return sys_port_close(port); } + +// OK +status_t delete_port(port_id port) { return sys_port_delete(port); } + +// OK - this works and is necessary for bin compatability. +status_t _get_next_port_info(team_id team, int32 *cookie, port_info *info, size_t size) +{ return sys_port_get_next_port_info(team,cookie,info); } + +// OK +//status_t get_next_port_info (team_id team, int32 *cookie, port_info *info ) +//{ return sys_port_get_next_port_info(team, cookie, info); } + +// OK +//status_t get_port_info(port_id port, port_info *info ) +//{ return sys_port_get_info(port,info); } + +// OK - this works and is necessary for bin compatability. +status_t _get_port_info(port_id port, port_info *info, size_t size) { return sys_port_get_info(port,info); } + +// OK +sem_id create_sem(int32 count, const char *name) +{ return kern_create_sem(count,name); } + +// OK +status_t delete_sem(sem_id sem) +{ return kern_delete_sem(sem); } + +// OK +status_t acquire_sem(sem_id sem) +{ return kern_acquire_sem(sem); } + +// Have to modify flags ??? +int acquire_sem_etc(sem_id sem, int32 count, int32 flags, bigtime_t timeout) +{ return kern_acquire_sem_etc(sem, count, flags, timeout); } + +// OK +status_t release_sem(sem_id sem) +{ return kern_release_sem(sem); } + +// Have to modify flags ??? +status_t release_sem_etc(sem_id sem, int32 count, int32 flags) +{ return kern_release_sem_etc(sem, count, flags); } + +// OK +status_t get_sem_count(sem_id sem, int32 *count) +{ return sys_sem_get_count(sem,count); } + +// OK +status_t set_sem_owner(sem_id sem, team_id team) +{ return sys_set_sem_owner(sem, team); } + +// OK +status_t _get_sem_info(sem_id sem, sem_info *info, size_t size) +{ return kern_get_sem_info(sem,info, size); } + +// OK +int _get_next_sem_info(proc_id team, uint32 *cookie, sem_info *info, size_t size) +{ return kern_get_next_sem_info(team,cookie,info, size); } + +// TO DO +bigtime_t set_alarm(bigtime_t when, uint32 flags); + +// case SYSCALL_GET_CURRENT_THREAD_ID: *call_ret = thread_get_current_thread_id(); break; +// case SYSCALL_THREAD_CREATE_THREAD: *call_ret = user_thread_create_user_thread((char *)arg0, thread_get_current_thread()->proc->id, (addr)arg1, (void *)arg2); break; +// case SYSCALL_PROC_CREATE_PROC: *call_ret = user_proc_create_proc((const char *)arg0, (const char *)arg1, (char **)arg2, (int )arg3, (int)arg4); break; +// case SYSCALL_GET_CURRENT_PROC_ID: *call_ret = proc_get_current_proc_id(); break; +// case SYSCALL_PROC_WAIT_ON_PROC: *call_ret = user_proc_wait_on_proc((proc_id)arg0, (int *)arg1); break; + +// OK +status_t kill_thread(thread_id thread) + { return kern_kill_thread(thread); } + +// OK +status_t resume_thread(thread_id thread) + { return kern_resume_thread(thread); } + +// OK +status_t suspend_thread(thread_id thread) + { return kern_suspend_thread(thread); } + +// TO DO +status_t rename_thread(thread_id thread, const char *new_name); +// TO DO +status_t set_thread_priority (thread_id thread, int32 new_priority); + +// TO DO +void exit_thread(status_t status) + { /* return sys_exit_thread(thread); */ } + +// OK +status_t wait_for_thread (thread_id thread, status_t *thread_return_value) + { return sys_thread_wait_on_thread(thread,thread_return_value); } + +// TO DO +status_t on_exit_thread(void (*callback)(void *), void *data); +// TO DO +status_t _get_thread_info(thread_id thread, thread_info *info, size_t size); +// TO DO +status_t _get_next_thread_info(team_id tmid, int32 *cookie, thread_info *info, size_t size); +// TO DO +status_t _get_team_usage_info(team_id tmid, int32 who, team_usage_info *ti, size_t size); +// TO DO +thread_id find_thread(const char *name); + +#define get_thread_info(thread, info) _get_thread_info((thread), (info), sizeof(*(info))) +#define get_next_thread_info(tmid, cookie, info) _get_next_thread_info((tmid), (cookie), (info), sizeof(*(info))) +#define get_team_usage_info(tmid, who, info) _get_team_usage_info((tmid), (who), (info), sizeof(*(info))) + +// TO DO +status_t send_data(thread_id thread, int32 code, const void *buf, size_t buffer_size); +// TO DO +status_t receive_data(thread_id *sender, void *buf, size_t buffer_size); +// TO DO +bool has_data(thread_id thread); +// TO DO +status_t snooze(bigtime_t microseconds); +// TO DO +status_t snooze_until(bigtime_t time, int timebase); + +// OK +status_t kill_team(team_id team) + { return sys_proc_kill_proc(team); } + +// TO DO +status_t _get_team_info(team_id team, team_info *info, size_t size); +// TO DO +status_t _get_next_team_info(int32 *cookie, team_info *info, size_t size); +//#define get_team_info(team, info) _get_team_info((team), (info), sizeof(*(info))) +//#define get_next_team_info(cookie, info) _get_next_team_info((cookie), (info), sizeof(*(info))) + +// TO DO +status_t get_cpuid(cpuid_info* info, uint32 eax_register, uint32 cpu_num); +// TO DO +status_t _get_system_info (system_info *returned_info, size_t size); +#define get_system_info(info) _get_system_info((info), sizeof(*(info))) + +int32 is_computer_on(void) {return 1;} +double is_computer_on_fire(void) {return 0;} + +uint32 real_time_clock (void); +// TO DO +void set_real_time_clock (int32 secs_since_jan1_1970); +// TO DO +bigtime_t real_time_clock_usecs (void); +// TO DO +status_t set_timezone(char *str); +// TO DO + +// OK +bigtime_t system_time (void) /* time since booting in microseconds */ + { return sys_system_time(); } + +void debugger (const char *message); +const int disable_debugger(int state); diff --git a/src/kernel/libroot/libroot.h b/src/kernel/libroot/libroot.h new file mode 100755 index 0000000000..75b0d26cfa --- /dev/null +++ b/src/kernel/libroot/libroot.h @@ -0,0 +1,77 @@ +#include +#ifndef _LIBROOT_H +#define _LIBROOT_H + +#ifdef __cplusplus + "C" { +#endif + +area_id create_area(const char *name, void **start_addr, uint32 addr_spec, size_t size, uint32 lock, uint32 protection); +area_id clone_area(const char *name, void **dest_addr, uint32 addr_spec, uint32 protection, area_id source); +area_id find_area(const char *name); +area_id area_for(void *addr); +status_t delete_area(area_id id); +status_t resize_area(area_id id, size_t new_size); +status_t set_area_protection(area_id id, uint32 new_protection); + +status_t _get_area_info(area_id id, area_info *ainfo, size_t size); +status_t _get_next_area_info(team_id team, int32 *cookie, area_info *ainfo, size_t size); + + +port_id create_port(int32 capacity, const char *name); +port_id find_port(const char *name); +status_t write_port(port_id port, int32 code, const void *buf, size_t buf_size); +status_t read_port(port_id port, int32 *code, void *buf, size_t buf_size); +status_t write_port_etc(port_id port, int32 code, const void *buf, size_t buf_size, uint32 flags, bigtime_t timeout); +status_t read_port_etc(port_id port, int32 *code, void *buf, size_t buf_size, uint32 flags, bigtime_t timeout); +ssize_t port_buffer_size(port_id port); +ssize_t port_buffer_size_etc(port_id port, uint32 flags, bigtime_t timeout); +ssize_t port_count(port_id port); +status_t set_port_owner(port_id port, team_id team); +status_t close_port(port_id port); +status_t delete_port(port_id port); +status_t _get_port_info(port_id port, port_info *info, size_t size); +status_t _get_next_port_info(team_id team, int32 *cookie, port_info *info, size_t size); + +bigtime_t set_alarm(bigtime_t when, uint32 flags); + +status_t rename_thread(thread_id thread, const char *new_name); +status_t set_thread_priority (thread_id thread, int32 new_priority); +void exit_thread(status_t status); +status_t wait_for_thread (thread_id thread, status_t *thread_return_value); +status_t on_exit_thread(void (*callback)(void *), void *data); +status_t _get_thread_info(thread_id thread, thread_info *info, size_t size); +status_t _get_next_thread_info(team_id tmid, int32 *cookie, thread_info *info, size_t size); +status_t _get_team_usage_info(team_id tmid, int32 who, team_usage_info *ti, size_t size); +thread_id find_thread(const char *name); + + +status_t send_data(thread_id thread, int32 code, const void *buf, size_t buffer_size); +status_t receive_data(thread_id *sender, void *buf, size_t buffer_size); +bool has_data(thread_id thread); +status_t snooze(bigtime_t microseconds); +status_t snooze_until(bigtime_t time, int timebase); +status_t kill_team(team_id team); /* see also: send_signal() */ +status_t _get_team_info(team_id team, team_info *info, size_t size); +status_t _get_next_team_info(int32 *cookie, team_info *info, size_t size); + +status_t get_cpuid(cpuid_info* info, uint32 eax_register, uint32 cpu_num); +status_t _get_system_info (system_info *returned_info, size_t size); + +int32 is_computer_on(void); +double is_computer_on_fire(void); + +uint32 real_time_clock (void); +void set_real_time_clock (int32 secs_since_jan1_1970); +bigtime_t real_time_clock_usecs (void); +status_t set_timezone(char *str); + +bigtime_t system_time (void); /* time since booting in microseconds */ +void debugger (const char *message); +const int disable_debugger(int state); + +#ifdef __cplusplus +} +#endif + +#endif /* ifdef _LIBROOT_H */ diff --git a/src/kernel/libroot/libroot_types.h b/src/kernel/libroot/libroot_types.h new file mode 100755 index 0000000000..f7ae4e4330 --- /dev/null +++ b/src/kernel/libroot/libroot_types.h @@ -0,0 +1,227 @@ +#ifndef _LIBROOT_TYPES_H +#define _LIBROOT_TYPES_H + +#ifdef __cplusplus + "C" { +#endif +#include +#include +#include + +#define B_NO_LOCK 0 +#define B_LAZY_LOCK 1 +#define B_FULL_LOCK 2 +#define B_CONTIGUOUS 3 +#define B_LOMEM 4 + +#define B_ANY_ADDRESS 0 +#define B_EXACT_ADDRESS 1 +#define B_BASE_ADDRESS 2 +#define B_CLONE_ADDRESS 3 +#define B_ANY_KERNEL_ADDRESS 4 + +#define B_READ_AREA 1 +#define B_WRITE_AREA 2 + +enum { + B_ONE_SHOT_ABSOLUTE_ALARM = 1, /* alarm is one-shot and time is specified absolutely */ + B_ONE_SHOT_RELATIVE_ALARM = 2, /* alarm is one-shot and time is specified relatively */ + B_PERIODIC_ALARM = 3 /* alarm is periodic and time is the period */ +}; + +#define B_LOW_PRIORITY 5 +#define B_NORMAL_PRIORITY 10 +#define B_DISPLAY_PRIORITY 15 +#define B_URGENT_DISPLAY_PRIORITY 20 +#define B_REAL_TIME_DISPLAY_PRIORITY 100 +#define B_URGENT_PRIORITY 110 +#define B_REAL_TIME_PRIORITY 120 + + thread_id spawn_thread ( + thread_func function_name, + const char *thread_name, + int32 priority, + void *arg +); + +#define B_SYSTEM_TIMEBASE (0) +#define B_SYSTEM_TEAM 2 + +typedef struct { + team_id team; + int32 image_count; + int32 thread_count; + int32 area_count; + thread_id debugger_nub_thread; + port_id debugger_nub_port; + + int32 argc; /* number of args on the command line */ + char args[64]; /* abbreviated command line args */ + uid_t uid; + gid_t gid; +} team_info; + +#if __INTEL__ +#define B_MAX_CPU_COUNT 8 +#endif + +#if __POWERPC__ +#define B_MAX_CPU_COUNT 8 +#endif + +typedef enum cpu_types { + B_CPU_PPC_601 = 1, + B_CPU_PPC_603 = 2, + B_CPU_PPC_603e = 3, + B_CPU_PPC_604 = 4, + B_CPU_PPC_604e = 5, + B_CPU_PPC_750 = 6, + B_CPU_PPC_686 = 13, + B_CPU_X86, + B_CPU_ALPHA, + B_CPU_MIPS, + B_CPU_HPPA, + B_CPU_M68K, + B_CPU_ARM, + B_CPU_SH, + B_CPU_SPARC, +// Since these have specific values, AFAIK, they will stay, even unsupported + B_CPU_INTEL_X86 = 0x1000, + B_CPU_INTEL_PENTIUM = 0x1051, + B_CPU_INTEL_PENTIUM75, + B_CPU_INTEL_PENTIUM_486_OVERDRIVE, + B_CPU_INTEL_PENTIUM_MMX, + B_CPU_INTEL_PENTIUM_MMX_MODEL_4 = B_CPU_INTEL_PENTIUM_MMX, + B_CPU_INTEL_PENTIUM_MMX_MODEL_8 = 0x1058, + B_CPU_INTEL_PENTIUM75_486_OVERDRIVE, + B_CPU_INTEL_PENTIUM_PRO = 0x1061, + B_CPU_INTEL_PENTIUM_II = 0x1063, + B_CPU_INTEL_PENTIUM_II_MODEL_3 = 0x1063, + B_CPU_INTEL_PENTIUM_II_MODEL_5 = 0x1065, + B_CPU_INTEL_CELERON = 0x1066, + B_CPU_INTEL_PENTIUM_III = 0x1067, + B_CPU_INTEL_PENTIUM_III_MODEL_8 = 0x1068, + + B_CPU_AMD_X86 = 0x1100, + B_CPU_AMD_K5_MODEL0 = 0x1150, + B_CPU_AMD_K5_MODEL1, + B_CPU_AMD_K5_MODEL2, + B_CPU_AMD_K5_MODEL3, + + B_CPU_AMD_K6_MODEL6 = 0x1156, + B_CPU_AMD_K6_MODEL7 = 0x1157, + + B_CPU_AMD_K6_MODEL8 = 0x1158, + B_CPU_AMD_K6_2 = 0x1158, + + B_CPU_AMD_K6_MODEL9 = 0x1159, + B_CPU_AMD_K6_III = 0x1159, + + B_CPU_AMD_ATHLON_MODEL1 = 0x1161, + + B_CPU_CYRIX_X86 = 0x1200, + B_CPU_CYRIX_GXm = 0x1254, + B_CPU_CYRIX_6x86MX = 0x1260, + + B_CPU_IDT_X86 = 0x1300, + B_CPU_IDT_WINCHIP_C6 = 0x1354, + B_CPU_IDT_WINCHIP_2 = 0x1358, + + B_CPU_RISE_X86 = 0x1400, + B_CPU_RISE_mP6 = 0x1450 + +} cpu_type; + +#define B_CPU_X86_VENDOR_MASK 0x1F00 + +typedef enum platform_types { + B_BEBOX_PLATFORM = 0, + B_MAC_PLATFORM, + B_AT_CLONE_PLATFORM +} platform_type; + +typedef struct { + bigtime_t active_time; /* # usec doing useful work since boot */ +} cpu_info; + + +typedef int32 machine_id[2]; /* unique machine ID */ + +typedef struct { + machine_id id; /* unique machine ID */ + bigtime_t boot_time; /* time of boot (# usec since 1/1/70) */ + + int32 cpu_count; /* # of cpus */ + enum cpu_types cpu_type; /* type of cpu */ + int32 cpu_revision; /* revision # of cpu */ + cpu_info cpu_infos[B_MAX_CPU_COUNT]; /* info about individual cpus */ + int64 cpu_clock_speed; /* processor clock speed (Hz) */ + int64 bus_clock_speed; /* bus clock speed (Hz) */ + enum platform_types platform_type; /* type of machine we're on */ + + int32 max_pages; /* total # physical pages */ + int32 used_pages; /* # physical pages in use */ + int32 page_faults; /* # of page faults */ + int32 max_sems; /* maximum # semaphores */ + int32 used_sems; /* # semaphores in use */ + int32 max_ports; /* maximum # ports */ + int32 used_ports; /* # ports in use */ + int32 max_threads; /* maximum # threads */ + int32 used_threads; /* # threads in use */ + int32 max_teams; /* maximum # teams */ + int32 used_teams; /* # teams in use */ + + char kernel_name [SYS_MAX_NAME_LEN]; /* name of kernel */ + char kernel_build_date[B_OS_NAME_LENGTH]; /* date kernel built */ + char kernel_build_time[B_OS_NAME_LENGTH]; /* time kernel built */ + int64 kernel_version; /* version of this kernel */ + + bigtime_t _busy_wait_time; /* reserved for Be */ + int32 pad[4]; /* just in case... */ +} system_info; + +#ifdef __INTEL__ +typedef union { + struct { + uint32 max_eax; + char vendorid[12]; + } eax_0; + + struct { + uint32 stepping : 4; + uint32 model : 4; + uint32 family : 4; + uint32 type : 2; + uint32 reserved_0 : 18; + + uint32 reserved_1; + uint32 features; + uint32 reserved_2; + } eax_1; + +struct { + uint8 call_num; + uint8 cache_descriptors[15]; + } eax_2; + + struct { + uint32 reserved[2]; + uint32 serial_number_high; + uint32 serial_number_low; + } eax_3; + + char as_chars[16]; + + struct { + uint32 eax; + uint32 ebx; + uint32 edx; + uint32 ecx; + } regs; +} cpuid_info; +#endif +#ifdef __cplusplus +} +#endif + +#endif /* ifdef _LIBROOT_TYPES_ */ diff --git a/src/kits/app/Application.cpp b/src/kits/app/Application.cpp new file mode 100644 index 0000000000..d0f383fda6 --- /dev/null +++ b/src/kits/app/Application.cpp @@ -0,0 +1,364 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: Application.cpp +// Author: Erik Jaesler (erik@cgsoftware.com) +// Description: BApplication class is the center of the application +// universe. The global be_app and be_app_messenger +// variables are defined here as well. +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- +BApplication* be_app = NULL; +BMessenger be_app_messenger; + +BResources* BApplication::_app_resources = NULL; +BLocker BApplication::_app_resources_lock("_app_resources_lock"); + + +//------------------------------------------------------------------------------ +BApplication::BApplication(const char* signature) +{ +} +//------------------------------------------------------------------------------ +BApplication::BApplication(const char* signature, status_t* error) +{ +} +//------------------------------------------------------------------------------ +BApplication::~BApplication() +{ +} +//------------------------------------------------------------------------------ +BApplication::BApplication(BMessage* data) +{ +} +//------------------------------------------------------------------------------ +BArchivable* BApplication::Instantiate(BMessage* data) +{ + if (!validate_instantiation(data, "BApplication")) + { + return NULL; + } + + return new BApplication(data); +} +//------------------------------------------------------------------------------ +status_t BApplication::Archive(BMessage* data, bool deep) const +{ +} +//------------------------------------------------------------------------------ +status_t BApplication::InitCheck() const +{ + return fInitError; +} +//------------------------------------------------------------------------------ +thread_id BApplication::Run() +{ +} +//------------------------------------------------------------------------------ +void BApplication::Quit() +{ +} +//------------------------------------------------------------------------------ +bool BApplication::QuitRequested() +{ +} +//------------------------------------------------------------------------------ +void BApplication::Pulse() +{ +} +//------------------------------------------------------------------------------ +void BApplication::ReadyToRun() +{ +} +//------------------------------------------------------------------------------ +void BApplication::MessageReceived(BMessage* msg) +{ +} +//------------------------------------------------------------------------------ +void BApplication::ArgvReceived(int32 argc, char** argv) +{ +} +//------------------------------------------------------------------------------ +void BApplication::AppActivated(bool active) +{ +} +//------------------------------------------------------------------------------ +void BApplication::RefsReceived(BMessage* a_message) +{ +} +//------------------------------------------------------------------------------ +void BApplication::AboutRequested() +{ +} +//------------------------------------------------------------------------------ +BHandler* BApplication::ResolveSpecifier(BMessage* msg, int32 index, + BMessage* specifier, int32 form, + const char* property) +{ +} +//------------------------------------------------------------------------------ +void BApplication::ShowCursor() +{ + // TODO: talk to app_server +} +//------------------------------------------------------------------------------ +void BApplication::HideCursor() +{ + // TODO: talk to app_server +} +//------------------------------------------------------------------------------ +void BApplication::ObscureCursor() +{ + // TODO: talk to app_server +} +//------------------------------------------------------------------------------ +bool BApplication::IsCursorHidden() const +{ + // TODO: talk to app_server +} +//------------------------------------------------------------------------------ +void BApplication::SetCursor(const void* cursor) +{ + // BeBook sez: If you want to call SetCursor() without forcing an immediate + // sync of the Application Server, you have to use a BCursor. + // By deductive reasoning, this function forces a sync. =) + BCursor Cursor(cursor); + SetCursor(&Cursor, true); +} +//------------------------------------------------------------------------------ +void BApplication::SetCursor(const BCursor* cursor, bool sync) +{ + // TODO: talk to app_server +} +//------------------------------------------------------------------------------ +int32 BApplication::CountWindows() const +{ + // BeBook sez: The windows list includes all windows explicitely created by + // the app ... but excludes private windows create by Be + // classes. + // I'm taking this to include private menu windows, thus the incl_menus + // param is false. + return count_windows(false); +} +//------------------------------------------------------------------------------ +BWindow* BApplication::WindowAt(int32 index) const +{ + // BeBook sez: The windows list includes all windows explicitely created by + // the app ... but excludes private windows create by Be + // classes. + // I'm taking this to include private menu windows, thus the incl_menus + // param is false. + return window_at(index, false); +} +//------------------------------------------------------------------------------ +int32 BApplication::CountLoopers() const +{ + // Tough nut to crack; not documented *anywhere*. Dug down into BLooper and + // found its private sLooperCount var +} +//------------------------------------------------------------------------------ +BLooper* BApplication::LooperAt(int32 index) const +{ +} +//------------------------------------------------------------------------------ +bool BApplication::IsLaunching() const +{ + return !fReadyToRunCalled; +} +//------------------------------------------------------------------------------ +status_t BApplication::GetAppInfo(app_info* info) const +{ + return be_roster->GetRunningAppInfo(be_app->Team(), info); +} +//------------------------------------------------------------------------------ +BResources* BApplication::AppResources() +{ +} +//------------------------------------------------------------------------------ +void BApplication::DispatchMessage(BMessage* an_event, BHandler* handler) +{ +} +//------------------------------------------------------------------------------ +void BApplication::SetPulseRate(bigtime_t rate) +{ + fPulseRate = rate; +} +//------------------------------------------------------------------------------ +status_t BApplication::GetSupportedSuites(BMessage* data) +{ +} +//------------------------------------------------------------------------------ +status_t BApplication::Perform(perform_code d, void* arg) +{ +} +//------------------------------------------------------------------------------ +BApplication::BApplication(uint32 signature) +{ +} +//------------------------------------------------------------------------------ +BApplication::BApplication(const BApplication& rhs) +{ +} +//------------------------------------------------------------------------------ +BApplication& BApplication::operator=(const BApplication& rhs) +{ +} +//------------------------------------------------------------------------------ +void BApplication::_ReservedApplication1() +{ +} +//------------------------------------------------------------------------------ +void BApplication::_ReservedApplication2() +{ +} +//------------------------------------------------------------------------------ +void BApplication::_ReservedApplication3() +{ +} +//------------------------------------------------------------------------------ +void BApplication::_ReservedApplication4() +{ +} +//------------------------------------------------------------------------------ +void BApplication::_ReservedApplication5() +{ +} +//------------------------------------------------------------------------------ +void BApplication::_ReservedApplication6() +{ +} +//------------------------------------------------------------------------------ +void BApplication::_ReservedApplication7() +{ +} +//------------------------------------------------------------------------------ +void BApplication::_ReservedApplication8() +{ +} +//------------------------------------------------------------------------------ +bool BApplication::ScriptReceived(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property) +{ +} +//------------------------------------------------------------------------------ +void BApplication::run_task() +{ +} +//------------------------------------------------------------------------------ +void BApplication::InitData(const char* signature, status_t* error) +{ +} +//------------------------------------------------------------------------------ +void BApplication::BeginRectTracking(BRect r, bool trackWhole) +{ +} +//------------------------------------------------------------------------------ +void BApplication::EndRectTracking() +{ +} +//------------------------------------------------------------------------------ +void BApplication::get_scs() +{ +} +//------------------------------------------------------------------------------ +void BApplication::setup_server_heaps() +{ +} +//------------------------------------------------------------------------------ +void* BApplication::rw_offs_to_ptr(uint32 offset) +{ +} +//------------------------------------------------------------------------------ +void* BApplication::ro_offs_to_ptr(uint32 offset) +{ +} +//------------------------------------------------------------------------------ +void* BApplication::global_ro_offs_to_ptr(uint32 offset) +{ +} +//------------------------------------------------------------------------------ +void BApplication::connect_to_app_server() +{ +} +//------------------------------------------------------------------------------ +void BApplication::send_drag(BMessage* msg, int32 vs_token, BPoint offset, BRect drag_rect, BHandler* reply_to) +{ +} +//------------------------------------------------------------------------------ +void BApplication::send_drag(BMessage* msg, int32 vs_token, BPoint offset, int32 bitmap_token, drawing_mode dragMode, BHandler* reply_to) +{ +} +//------------------------------------------------------------------------------ +void BApplication::write_drag(_BSession_* session, BMessage* a_message) +{ +} +//------------------------------------------------------------------------------ +bool BApplication::quit_all_windows(bool force) +{ +} +//------------------------------------------------------------------------------ +bool BApplication::window_quit_loop(bool, bool) +{ +} +//------------------------------------------------------------------------------ +void BApplication::do_argv(BMessage* msg) +{ +} +//------------------------------------------------------------------------------ +uint32 BApplication::InitialWorkspace() +{ +} +//------------------------------------------------------------------------------ +int32 BApplication::count_windows(bool incl_menus) const +{ +} +//------------------------------------------------------------------------------ +BWindow* BApplication::window_at(uint32 index, bool incl_menus) const +{ +} +//------------------------------------------------------------------------------ +status_t BApplication::get_window_list(BList* list, bool incl_menus) const +{ +} +//------------------------------------------------------------------------------ +int32 BApplication::async_quit_entry(void* data) +{ +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/kits/app/Cursor.cpp b/src/kits/app/Cursor.cpp new file mode 100644 index 0000000000..072cbe6afb --- /dev/null +++ b/src/kits/app/Cursor.cpp @@ -0,0 +1,103 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: Cursor.cpp +// Author: Frans van Nispen (xlr8@tref.nl) +// Description: BCursor describes a view-wide or application-wide cursor. +//------------------------------------------------------------------------------ +/** + @note: As BeOS only supports 16x16 monochrome cursors, and I would like + to see a nice shadowes one, we will need to extend this one. + */ + +// Standard Includes ----------------------------------------------------------- +#include + +// System Includes ------------------------------------------------------------- +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + + +//------------------------------------------------------------------------------ +BCursor::BCursor(const void *cursorData) +{ +// uint8 data[68]; +// memcpy(&data, cursorData, 68); +} +//------------------------------------------------------------------------------ +// undefined on BeOS +BCursor::BCursor(BMessage *data) +{ +} +//------------------------------------------------------------------------------ +BCursor::~BCursor() +{ +} +//------------------------------------------------------------------------------ +// not implemented on BeOS +status_t BCursor::Archive(BMessage *into, bool deep = true) const +{ + return B_OK; +} +//------------------------------------------------------------------------------ +// not implemented on BeOS +BArchivable *BCursor::Instantiate(BMessage *data) +{ + return NULL; +} +//------------------------------------------------------------------------------ +status_t BCursor::Perform(perform_code d, void *arg) +{ + printf("perform %d\n", (int)d); + return B_OK; +} +//------------------------------------------------------------------------------ +void BCursor::_ReservedCursor1() +{ +} +//------------------------------------------------------------------------------ +void BCursor::_ReservedCursor2() +{ +} +//------------------------------------------------------------------------------ +void BCursor::_ReservedCursor3() +{ +} +//------------------------------------------------------------------------------ +void BCursor::_ReservedCursor4() +{ +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/kits/app/Handler.cpp b/src/kits/app/Handler.cpp new file mode 100644 index 0000000000..72c012e99e --- /dev/null +++ b/src/kits/app/Handler.cpp @@ -0,0 +1,971 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: Handler.cpp +// Author: Erik Jaesler (erik@cgsoftware.com) +// Description: BHandler defines the message-handling protocol. +// MessageReceived() is its lynchpin. +//------------------------------------------------------------------------------ +/** + @note Some musings on the member variable 'fToken'. In searching a dump + of libbe.so, I found a struct/class called 'TokenSpace', which has + various member functions like 'new_token'. More intriguing is a + dump of Dano's version of libbe.so: there is BPrivate::BTokenSpace, + which also has functions like 'NewToken'. There's more: one + version of BTokenSpace::NewToken takes a pointer to another new + class, BPrivate::BDirectMessageTarget. Only a constructor, + destructor and vtable are listed for it, so I'm guessing it's an + abstract base class (or not very useful ;). My guess is that + BDirectMessageTarget facilitates sending messages straight to an + associated BHandler. Maybe from app_server? Probably not, since + you'd have to do IPC anyway. But maybe within the same team, or + even between teams? It might save unnecessary trips to and from + app_server for messages which otherwise are entirely client-side. + + Back to tokens. There are also these functions in R5: + _safe_get_server_token_(const BLooper*, int32*) + BWindow::find_token_and_handler(BMessage*, int32*, BHandler**) + BWindow::get_server_token + + and Dano adds a few more provocative sounding functions: + get_handler_token(short, void*) (listed 3 times, actually) + new_handler_token(short, void*) + remove_handler_token(short, void*) + + Taken all together, I think there's a sound argument to be made that + each BHandler has an int32 token associated with it in app_server. + + Furthermore, there is, in R5, a function set_token_type(long, short) + which leads me to think that although BHandler's have server tokens + associated with them, the tokening facility is, in fact, generic. + These functions would seem to support that theory: + BBitmap::get_server_token + BPicture::set_token + + An important question is whether tokens are generated on the client + side and registered with the server or generated on the server and + given back to the client. The exported functions of TokenSpace in + libbe's dump are: + ~TokenSpace + TokenSpace + adjust_free(long, long) + dump() + find_free_entry(long*, long*) + full_search_adjust() + get_token(void**) + get_token(short*, void**) + new_token(long, short, void*) + new_token_array(long) + remove_token(long) + set_token_type(long, short) + + TokenSpace functions are also exported from app_server: + ~TokenSpace + TokenSpace + adjust_free(long, long) + cleanup_dead(long) + delete_atom(SAtom*) + dump_tokens() + find_free_entry(long*, long*) + full_search_adjust() + get_token(long, void**) + get_token(long, short*, void**) + get_token_by_type(int*, short, long, void**) + grab_atom(long, SAtom**) + iterate_tokens(long, short, + unsigned long(*)(long, long, short, void*, void*), + void*) + new_token(long, short, void*) + new_token_array(long) + remove_token(long) + set_token_type(long, short) + + While there are common functions in both locations, the fact that + app_server exports TokenSpace functions which libbe.so does not + leads me to believe that libbe.so and app_server each have their own + versions of TokenSpace. While it's possible that the libbe version + simply acts as a proxy for the app_server version, it seems not + only inefficient but unnecessary as well: client-side objects + exists in a different "namespace" than server-side objects, so over- + lap between the two token sets shouldn't be an issue. + + Obviously, I can't be entirely sure this is how R5 does it, but it + seems like a reasonable design to follow for our purposes. + */ +/** + @note Thought on "pseudo-atomic" operations in Lock(), LockWithTimeout(), + and Unlock(). Seems like avoiding the possibility of a looper + change during these functions would be the way to go, and having a + semaphore that protects SetLooper() would do the job very nicely. + Maybe that's too heavy-weight a solution, though. + */ + +// Standard Includes ----------------------------------------------------------- +#include +#include +#include +#include +#include + +// System Includes ------------------------------------------------------------- +#include +#include +#include +#include +#include +#include +#include + +// Project Includes ------------------------------------------------------------ +#include "TokenSpace.h" + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +using std::map; +using std::vector; +using BPrivate::gDefaultTokens; + +const char* gArchiveNameField = "_name"; +static property_info gHandlerPropInfo[] = +{ + { + // name + "Suites", + // commands + {B_GET_PROPERTY}, + // specifiers + {B_DIRECT_SPECIFIER}, + // usage + NULL, + // extra data + 0, + // types + { }, + // ctypes (compound_type) + { + // ctypes[0] + { + // pairs[0] + { + { + // name + "suites", + // type + B_STRING_TYPE + } + } + }, + // ctypes[1] + { + // pairs[1] + { + { + // name + "messages", + // type + B_PROPERTY_INFO_TYPE + } + } + } + }, + // reserved + {} + }, + { + "Messenger", + {B_GET_PROPERTY}, + {B_DIRECT_SPECIFIER}, + NULL, 0, + { B_MESSENGER_TYPE }, + {}, + {} + }, + { + "InternalName", + {B_GET_PROPERTY}, + {B_DIRECT_SPECIFIER}, + NULL, 0, + { B_STRING_TYPE }, + {}, + {} + }, + {} +}; + +bool FilterDeleter(void* filter); + +typedef map > THandlerObserverMap; +typedef map > TMessengerObserverMap; +//------------------------------------------------------------------------------ +// TODO: Change to BPrivate::BObserverList if possible +class _ObserverList +{ + public: + _ObserverList(void); + ~_ObserverList(void); + status_t SendNotices(unsigned long, BMessage const *); + status_t StartObserving(BHandler *, unsigned long); + status_t StartObserving(const BMessenger&, unsigned long); + status_t StopObserving(BHandler *, unsigned long); + status_t StopObserving(const BMessenger&, unsigned long); + bool IsEmpty(); + + private: + THandlerObserverMap fHandlerMap; + TMessengerObserverMap fMessengerMap; +}; +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +BHandler::BHandler(const char* name) + : BArchivable(), fName(NULL) +{ + InitData(name); +} +//------------------------------------------------------------------------------ +BHandler::~BHandler() +{ + if (fName) + { + free(fName); + } + + gDefaultTokens.RemoveToken(fToken); +} +//------------------------------------------------------------------------------ +BHandler::BHandler(BMessage* data) + : BArchivable(data), fName(NULL) +{ + const char* name = NULL; + + if (data) + { + data->FindString(gArchiveNameField, &name); + } + + InitData(name); +} +//------------------------------------------------------------------------------ +BArchivable* BHandler::Instantiate(BMessage* data) +{ + if (!validate_instantiation(data, "BHandler")) + { + return NULL; + } + + return new BHandler(data); +} +//------------------------------------------------------------------------------ +status_t BHandler::Archive(BMessage* data, bool deep) const +{ + status_t err = BArchivable::Archive(data, deep); + if (!err) + { + err = data->AddString(gArchiveNameField, fName); + } + + return err; +} +//------------------------------------------------------------------------------ +void BHandler::MessageReceived(BMessage* message) +{ + switch (message->what) + { + case B_GET_PROPERTY: + { + BMessage Specifier; + int32 form; + const char* prop; + int32 cur; + status_t err; + + err = message->GetCurrentSpecifier(&cur, &Specifier, &form, &prop); + if (!err) + { + BMessage Reply(B_REPLY); + if (strcmp(prop, "Suites") == 0) + { + if (GetSupportedSuites(&Reply) == B_OK && + Reply.AddInt32("error", B_OK) == B_OK) + { + message->SendReply(&Reply); + } + } + else if (strcmp(prop, "Messenger") == 0) + { + if (Reply.AddMessenger("result", this) == B_OK && + Reply.AddInt32("error", B_OK) == B_OK) + + { + message->SendReply(&Reply); + } + } + else if (strcmp(prop, "InternalName") == 0) + { + if (Reply.AddString("result", Name()) == B_OK && + Reply.AddInt32("error", B_OK) == B_OK) + + { + message->SendReply(&Reply); + } + } + else + { + // Should never be here + debugger("We are *not* supposed to be here"); + } + } + break; + } + + default: + if (fNextHandler) + { + fNextHandler->MessageReceived(message); + } + else + { + message->SendReply(B_MESSAGE_NOT_UNDERSTOOD); + } + break; + } +} +//------------------------------------------------------------------------------ +BLooper* BHandler::Looper() const +{ + return fLooper; +} +//------------------------------------------------------------------------------ +void BHandler::SetName(const char* name) +{ + if (fName) + { + free(fName); + fName = NULL; + } + + if (name) + { + fName = strdup(name); + } +} +//------------------------------------------------------------------------------ +const char* BHandler::Name() const +{ + return fName; +} +//------------------------------------------------------------------------------ +void BHandler::SetNextHandler(BHandler* handler) +{ + // NOTE: This is called by BLooper::RemoveHandler() with NULL as the param, + // so we need to handle that possiblity. + if (!handler) + { + fNextHandler = NULL; + return; + } + + if (!fLooper) + { + debugger("handler must belong to looper before setting NextHandler"); + fNextHandler = NULL; + return; + } + + if (fLooper != handler->Looper()) + { + debugger("The handler and its NextHandler must have the same looper"); + return; + } + + if (!fLooper->IsLocked()) + { + //debugger("Owning Looper must be locked before calling SetNextHandler"); + // NOTE: Original implementation allows setting the next handler here + // anyway. The documentation *clearly* says otherwise. Can we get away + // with being more strict? + + // return; + } + + // NOTE: I'm sure some sort of threading protection should happen here, + // hopefully the spec-mandated BLooper lock is sufficient. + // TODO: implement correctly + fNextHandler = handler; +} +//------------------------------------------------------------------------------ +BHandler* BHandler::NextHandler() const +{ + return fNextHandler; +} +//------------------------------------------------------------------------------ +void BHandler::AddFilter(BMessageFilter* filter) +{ + // NOTE: Although the documentation states that the handler must belong to + // a looper and the looper must be locked in order to use this method, + // testing shows that this is not the case in the original implementation. + // We may want to investigate enforcing these rules; it would be interesting + // to see how many apps out there have violated the dictates of the docs. + // For now, though, we'll play nicely. +#if 0 + if (!fLooper) + { + // TODO: error handling + return false; + } + + if (!fLooper->IsLocked()) + { + // TODO: error handling + return false; + } +#endif + + if (!fFilters) + { + fFilters = new BList; + } + + fFilters->AddItem(filter); +} +//------------------------------------------------------------------------------ +bool BHandler::RemoveFilter(BMessageFilter* filter) +{ + // NOTE: Although the documentation states that the handler must belong to + // a looper and the looper must be locked in order to use this method, + // testing shows that this is not the case in the original implementation. + // We may want to investigate enforcing these rules; it would be interesting + // to see how many apps out there have violated the dictates of the docs. + // For now, though, we'll play nicely. +#if 0 + if (!fLooper) + { + // TODO: error handling + return false; + } + + if (!fLooper->IsLocked()) + { + // TODO: error handling + return false; + } +#endif + + if (fFilters) + { + if (fFilters->RemoveItem((void*)filter)) + { + filter->SetLooper(NULL); + return true; + } + } + + return false; +} +//------------------------------------------------------------------------------ +void BHandler::SetFilterList(BList* filters) +{ +/** + @note Although the documentation states that the handler must belong to + a looper and the looper must be locked in order to use this method, + testing shows that this is not the case in the original implementation. + */ +#if 0 + if (!fLooper) + { + // TODO: error handling + return; + } +#endif + + if (fLooper && !fLooper->IsLocked()) + { + debugger("Owning Looper must be locked before calling SetFilterList"); + return; + } + +/** + @note I would like to use BObjectList internally, but this function is + spec'd such that fFilters would get deleted and then assigned + 'filters', which would obviously mess this up. Wondering if + anyone ever assigns a list of filters and then checks against + FilterList() to see if they are the same. + */ + // TODO: Explore issues with using BObjectList + if (fFilters) + { + fFilters->DoForEach(FilterDeleter); + delete fFilters; + } + + fFilters = filters; + if (fFilters) + { + for (int32 i = 0; i < fFilters->CountItems(); ++i) + { + BMessageFilter* Filter = + static_cast(fFilters->ItemAt(i)); + if (Filter) + { + Filter->SetLooper(fLooper); + } + } + } +} +//------------------------------------------------------------------------------ +BList* BHandler::FilterList() +{ + return fFilters; +} +//------------------------------------------------------------------------------ +bool BHandler::LockLooper() +{ +/** + @note BeBook says that this function "retrieves the handler's looper and + unlocks it in a pseudo-atomic operation, thus avoiding a race + condition." How "pseudo-atomic" would look completely escapes me, + so we'll go with the dumb version for now. Maybe I should use a + benaphore? + + BeBook mentions handling the case where the handler's looper + changes during this call. I've attempted a "pseudo-atomic" + operation to check that. + */ + BLooper* Looper = fLooper; + if (Looper) + { + bool result = Looper->Lock(); + + // Are we still assigned to the same looper? + if (fLooper == Looper) + { + return result; + } + else if (result) + { + // Our looper is different, and the lock was successful on the old + // one; undo the lock + Looper->Unlock(); + } + } + + return false; +} +//------------------------------------------------------------------------------ +status_t BHandler::LockLooperWithTimeout(bigtime_t timeout) +{ +/** + @note BeBook says that this function "retrieves the handler's looper and + unlocks it in a pseudo-atomic operation, thus avoiding a race + condition." How "pseudo-atomic" would look completely escapes me, + so we'll go with the dumb version for now. Maybe I should use a + benaphore? + + BeBook mentions handling the case where the handler's looper + changes during this call. I've attempted a "pseudo-atomic" + operation to check for that. + */ + BLooper* Looper = fLooper; + if (Looper) + { + status_t result = Looper->LockWithTimeout(timeout); + + // Are we still assigned to the same looper? + if (fLooper == Looper) + { + return result; + } + else + { + // Our looper changed during the lock attempt + if (result == B_OK) + { + // The lock was successful on the old looper; undo the lock + Looper->Unlock(); + } + + return B_MISMATCHED_VALUES; + } + } + + return B_BAD_VALUE; +} +//------------------------------------------------------------------------------ +void BHandler::UnlockLooper() +{ +/** + @note BeBook says that this function "retrieves the handler's looper and + unlocks it in a pseudo-atomic operation, thus avoiding a race + condition." How "pseudo-atomic" would look completely escapes me, + so we'll go with the dumb version for now. Maybe I should use a + benaphore? + + The solution I used for Lock() and LockWithTimeout() seems out of + place here; if our looper does change while attempting to unlock it, + re-Lock()ing the original looper just doesn't seem right. + */ + // TODO: implement correctly + if (fLooper) + { + fLooper->Unlock(); + } +} +//------------------------------------------------------------------------------ +BHandler* BHandler::ResolveSpecifier(BMessage* msg, int32 index, + BMessage* specifier, int32 form, + const char* property) +{ + // Straight from the BeBook + BPropertyInfo PropertyInfo(gHandlerPropInfo); + if (PropertyInfo.FindMatch(msg, index, specifier, form, property) >= 0) + { + return this; + } + + BMessage Reply(B_MESSAGE_NOT_UNDERSTOOD); + Reply.AddInt32("error", B_BAD_SCRIPT_SYNTAX); + Reply.AddString("message", "Didn't understand the specifier(s)"); + msg->SendReply(&Reply); + + return NULL; +} +//------------------------------------------------------------------------------ +status_t BHandler::GetSupportedSuites(BMessage* data) +{ +/** + @note This is the output from the original implementation (calling + PrintToStream() on both data and the contained BPropertyInfo): + +BMessage: what = (0x0, or 0) + entry suites, type='CSTR', c=1, size=21, data[0]: "suite/vnd.Be-handler" + entry messages, type='SCTD', c=1, size= 0, + property commands types specifiers +-------------------------------------------------------------------------------- + Suites PGET 1 + (RTSC,suites) + (DTCS,messages) + + Messenger PGET GNSM 1 + InternalName PGET RTSC 1 + + With a good deal of trial and error, I determined that the + parenthetical clauses are entries in the 'ctypes' field of + property_info. 'ctypes' is an array of 'compound_type', which + contains an array of 'field_pair's. I haven't the foggiest what + either 'compound_type' or 'field_pair' is for, being as the + scripting docs are so bloody horrible. The corresponding + property_info array is declared in the globals section. + */ + status_t err; + if (!data) + { + err = B_BAD_VALUE; + } + + if (!err) + { + err = data->AddString("Suites", "suite/vnd.Be-handler"); + if (!err) + { + BPropertyInfo PropertyInfo(gHandlerPropInfo); + err = data->AddFlat("message", &PropertyInfo); + } + } + + return err; +} +//------------------------------------------------------------------------------ +status_t BHandler::StartWatching(BMessenger Messenger, uint32 what) +{ + fObserverList ? fObserverList : fObserverList = new _ObserverList; + return fObserverList->StartObserving(Messenger, what); +} +//------------------------------------------------------------------------------ +status_t BHandler::StartWatchingAll(BMessenger Messenger) +{ + fObserverList ? fObserverList : fObserverList = new _ObserverList; + return fObserverList->StartObserving(Messenger, B_OBSERVER_OBSERVE_ALL); +} +//------------------------------------------------------------------------------ +status_t BHandler::StopWatching(BMessenger Messenger, uint32 what) +{ + fObserverList ? fObserverList : fObserverList = new _ObserverList; + return fObserverList->StopObserving(Messenger, what); +} +//------------------------------------------------------------------------------ +status_t BHandler::StopWatchingAll(BMessenger Messenger) +{ + fObserverList ? fObserverList : fObserverList = new _ObserverList; + return fObserverList->StopObserving(Messenger, B_OBSERVER_OBSERVE_ALL); +} +//------------------------------------------------------------------------------ +status_t BHandler::StartWatching(BHandler* Handler, uint32 what) +{ + fObserverList ? fObserverList : fObserverList = new _ObserverList; + return fObserverList->StartObserving(Handler, what); +} +//------------------------------------------------------------------------------ +status_t BHandler::StartWatchingAll(BHandler* Handler) +{ + fObserverList ? fObserverList : fObserverList = new _ObserverList; + return fObserverList->StartObserving(Handler, B_OBSERVER_OBSERVE_ALL); +} +//------------------------------------------------------------------------------ +status_t BHandler::StopWatching(BHandler* Handler, uint32 what) +{ + fObserverList ? fObserverList : fObserverList = new _ObserverList; + return fObserverList->StopObserving(Handler, what); +} +//------------------------------------------------------------------------------ +status_t BHandler::StopWatchingAll(BHandler* Handler) +{ + fObserverList ? fObserverList : fObserverList = new _ObserverList; + return fObserverList->StopObserving(Handler, B_OBSERVER_OBSERVE_ALL); +} +//------------------------------------------------------------------------------ +status_t BHandler::Perform(perform_code d, void* arg) +{ + return BArchivable::Perform(d, arg); +} +//------------------------------------------------------------------------------ +void BHandler::SendNotices(uint32 what, const BMessage* msg) +{ + fObserverList ? fObserverList : fObserverList = new _ObserverList; + fObserverList->SendNotices(what, msg); +} +//------------------------------------------------------------------------------ +bool BHandler::IsWatched() const +{ + return fObserverList && !fObserverList->IsEmpty(); +} +//------------------------------------------------------------------------------ +void BHandler::_ReservedHandler2() +{ + // Unused + ; +} +//------------------------------------------------------------------------------ +void BHandler::_ReservedHandler3() +{ + // Unused + ; +} +//------------------------------------------------------------------------------ +void BHandler::_ReservedHandler4() +{ + // Unused + ; +} +//------------------------------------------------------------------------------ +void BHandler::InitData(const char* name) +{ + SetName(name); + + fLooper = NULL; + fNextHandler = NULL; + fFilters = NULL; + fObserverList = NULL; + + fToken = gDefaultTokens.NewToken(B_HANDLER_TOKEN, this); +} +//------------------------------------------------------------------------------ +BHandler::BHandler(const BHandler& ) +{ + // No copy construction allowed. + ; +} +//------------------------------------------------------------------------------ +BHandler& BHandler::operator=(const BHandler& ) +{ + // No assignments allowed. + return *this; +} +//------------------------------------------------------------------------------ +void BHandler::SetLooper(BLooper* loop) +{ + fLooper = loop; +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// #pragma mark - +// #pragma mark _ObserverList +// #pramga mark - +//------------------------------------------------------------------------------ +_ObserverList::_ObserverList(void) +{ +} +//------------------------------------------------------------------------------ +_ObserverList::~_ObserverList(void) +{ +} +//------------------------------------------------------------------------------ +status_t _ObserverList::SendNotices(unsigned long what, BMessage const* Message) +{ + // Having to new a temporary is really irritating ... + BMessage* CopyMsg = NULL; + if (Message) + { + CopyMsg = new BMessage(*Message); + CopyMsg->what = B_OBSERVER_NOTICE_CHANGE; + CopyMsg->AddInt32(B_OBSERVE_ORIGINAL_WHAT, Message->what); + } + else + { + CopyMsg = new BMessage(B_OBSERVER_NOTICE_CHANGE); + } + + CopyMsg->AddInt32(B_OBSERVE_WHAT_CHANGE, what); + + vector& Handlers = fHandlerMap[what]; + for (uint32 i = 0; i < Handlers.size(); ++i) + { + BMessenger msgr(Handlers[i]); + msgr.SendMessage(CopyMsg); + } + + vector& Messengers = fMessengerMap[what]; + for (uint32 i = 0; i < Messengers.size(); ++i) + { + Messengers[i].SendMessage(CopyMsg); + } + + // Gotta make sure to clean up the annoying temporary ... + delete CopyMsg; + + return B_OK; +} +//------------------------------------------------------------------------------ +status_t _ObserverList::StartObserving(BHandler* Handler, unsigned long what) +{ + if (!Handler) + { + return B_BAD_HANDLER; + } + + vector& Handlers = fHandlerMap[what]; + vector::iterator iter; + iter = find(Handlers.begin(), Handlers.end(), Handler); + if (iter != Handlers.end()) + { + // TODO: verify + return B_OK; + } + + Handlers.push_back(Handler); + return B_OK; +} +//------------------------------------------------------------------------------ +status_t _ObserverList::StartObserving(const BMessenger& Messenger, + unsigned long what) +{ + vector& Messengers = fMessengerMap[what]; + vector::iterator iter; + iter = find(Messengers.begin(), Messengers.end(), Messenger); + if (iter != Messengers.end()) + { + // TODO: verify + return B_OK; + } + + Messengers.push_back(Messenger); + return B_OK; +} +//------------------------------------------------------------------------------ +status_t _ObserverList::StopObserving(BHandler* Handler, unsigned long what) +{ + if (Handler) + { + vector& Handlers = fHandlerMap[what]; + vector::iterator iter; + iter = find(Handlers.begin(), Handlers.end(), Handler); + if (iter != Handlers.end()) + { + Handlers.erase(iter); + if (Handlers.empty()) + { + fHandlerMap.erase(what); + } + return B_OK; + } + } + + return B_BAD_HANDLER; +} +//------------------------------------------------------------------------------ +status_t _ObserverList::StopObserving(const BMessenger& Messenger, + unsigned long what) +{ + // ???: What if you call StartWatching(MyMsngr, aWhat) and then call + // StopWatchingAll(MyMsnger)? Will MyMsnger be removed from the aWhat + // watcher list? For now, we'll assume that they're discreet lists + // which do no cross checking; i.e., MyMsnger would *not* be removed in + // this scenario. + vector& Messengers = fMessengerMap[what]; + vector::iterator iter; + iter = find(Messengers.begin(), Messengers.end(), Messenger); + if (iter != Messengers.end()) + { + Messengers.erase(iter); + if (Messengers.empty()) + { + fMessengerMap.erase(what); + } + return B_OK; + } + + return B_BAD_HANDLER; +} +//------------------------------------------------------------------------------ +bool _ObserverList::IsEmpty() +{ + return fHandlerMap.empty() && fMessengerMap.empty(); +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +bool FilterDeleter(void* filter) +{ + BMessageFilter* Filter = static_cast(filter); + if (Filter) + { + delete Filter; + Filter = NULL; + } + + return false; +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/kits/app/Invoker.cpp b/src/kits/app/Invoker.cpp new file mode 100644 index 0000000000..e01ce91bbb --- /dev/null +++ b/src/kits/app/Invoker.cpp @@ -0,0 +1,244 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: Invoker.cpp +// Author: Frans van Nispen (xlr8@tref.nl) +// Description: BMessageFilter class creates objects that filter +// in-coming BMessages. +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- +#include + +// System Includes ------------------------------------------------------------- +#include +#include +#include +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +BInvoker::BInvoker() + : fMessage(NULL), + fMessenger(be_app), + fReplyTo(NULL), + fTimeout(B_INFINITE_TIMEOUT) +{ +} +//------------------------------------------------------------------------------ +BInvoker::BInvoker(BMessage* message, const BHandler* handler, + const BLooper* looper) + : fMessage(message), + fMessenger(BMessenger(handler, looper)), + fReplyTo(NULL), + fTimeout(B_INFINITE_TIMEOUT) +{ +} +//------------------------------------------------------------------------------ +BInvoker::BInvoker(BMessage* message, BMessenger target) + : fMessage(message), + fMessenger(BMessenger(target)), + fReplyTo(NULL), + fTimeout(B_INFINITE_TIMEOUT) +{ +} +//------------------------------------------------------------------------------ +BInvoker::~BInvoker() +{ + delete fMessage; +} +//------------------------------------------------------------------------------ +status_t BInvoker::SetMessage(BMessage* message) +{ + delete fMessage; + fMessage = message; + return B_OK; +} +//------------------------------------------------------------------------------ +BMessage* BInvoker::Message() const +{ + return fMessage; +} +//------------------------------------------------------------------------------ +uint32 BInvoker::Command() const +{ + if (fMessage) + { + return fMessage->what; + } + else + { + return (uint32)NULL; + } +} +//------------------------------------------------------------------------------ +status_t BInvoker::SetTarget(const BHandler* handler, const BLooper* looper) +{ + fMessenger = BMessenger(handler, looper); + return fMessenger.IsValid(); +} +//------------------------------------------------------------------------------ +status_t BInvoker::SetTarget(BMessenger messenger) +{ + fMessenger = messenger; + return fMessenger.IsValid(); +} +//------------------------------------------------------------------------------ +bool BInvoker::IsTargetLocal() const +{ + return fMessenger.IsTargetLocal(); +} +//------------------------------------------------------------------------------ +BHandler* BInvoker::Target(BLooper** looper) const +{ + return fMessenger.Target(looper); +} +//------------------------------------------------------------------------------ +BMessenger BInvoker::Messenger() const +{ + return fMessenger; +} +//------------------------------------------------------------------------------ +status_t BInvoker::SetHandlerForReply(BHandler* handler) +{ + fReplyTo = handler; + return B_OK; +} +//------------------------------------------------------------------------------ +BHandler* BInvoker::HandlerForReply() const +{ + return fReplyTo; +} +//------------------------------------------------------------------------------ +status_t BInvoker::Invoke(BMessage* msg) +{ + return InvokeNotify( msg ); +} +//------------------------------------------------------------------------------ +status_t BInvoker::InvokeNotify(BMessage* msg, uint32 kind) +{ + fNotifyKind = kind; + + BMessage clone(kind); + status_t err = B_BAD_VALUE; + + if (!msg && fNotifyKind == B_CONTROL_INVOKED) + { + msg = fMessage; + } + + if (!msg) + { + if (!Target()->IsWatched()) + return err; + } + else + { + clone = *msg; + } + + clone.AddInt64("when", system_time()); + clone.AddPointer("source", this); + + if (msg) + { + err = fMessenger.SendMessage( &clone, fReplyTo, fTimeout); + } + + // Also send invocation to any observers of this handler. + Target()->SendNotices(kind, &clone); + return err; +} +//------------------------------------------------------------------------------ +status_t BInvoker::SetTimeout(bigtime_t timeout) +{ + fTimeout = timeout; + return B_OK; +} +//------------------------------------------------------------------------------ +bigtime_t BInvoker::Timeout() const +{ + return fTimeout; +} +//------------------------------------------------------------------------------ +uint32 BInvoker::InvokeKind(bool* notify) +{ + if (fNotifyKind == B_CONTROL_INVOKED) + { + *notify = false; + } + else + { + *notify = true; + } + + return fNotifyKind; +} +//------------------------------------------------------------------------------ +void BInvoker::BeginInvokeNotify(uint32 kind) +{ + fNotifyKind = kind; +} +//------------------------------------------------------------------------------ +void BInvoker::EndInvokeNotify() +{ + fNotifyKind = B_CONTROL_INVOKED; +} +//------------------------------------------------------------------------------ +void BInvoker::_ReservedInvoker1() +{ +} +//------------------------------------------------------------------------------ +void BInvoker::_ReservedInvoker2() +{ +} +//------------------------------------------------------------------------------ +void BInvoker::_ReservedInvoker3() +{ +} +//------------------------------------------------------------------------------ +BInvoker::BInvoker(const BInvoker &) +{ + // No copy construction allowed! +} +//------------------------------------------------------------------------------ +BInvoker& BInvoker::operator=(const BInvoker&) +{ + // No assignment allowed! + return *this; +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/kits/app/Jamfile b/src/kits/app/Jamfile new file mode 100644 index 0000000000..f97427ac11 --- /dev/null +++ b/src/kits/app/Jamfile @@ -0,0 +1,3 @@ +SubDir OBOS_TOP sources os kits app ; + + diff --git a/src/kits/app/Looper.cpp b/src/kits/app/Looper.cpp new file mode 100644 index 0000000000..aedef0083d --- /dev/null +++ b/src/kits/app/Looper.cpp @@ -0,0 +1,1428 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: Looper.cpp +// Author(s): Erik Jaesler (erik@cgsoftware.com) +// DarkWyrm (bpmagic@columbus.rr.com) +// Description: BLooper class spawns a thread that runs a message loop. +//------------------------------------------------------------------------------ + +/** + @note Although I'm implementing "by the book" for now, I would like to + refactor sLooperList and all of the functions that operate on it + into their own class in the BPrivate namespace. + + Also considering adding the thread priority when archiving. + + + */ + +// debugging +//#define DBG(x) x +#define DBG(x) +#define OUT printf + +// Standard Includes ----------------------------------------------------------- +#include + +// System Includes ------------------------------------------------------------- +#include +#include +#include +#include +#include +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "TokenSpace.h" + +// Local Defines --------------------------------------------------------------- +#define FILTER_LIST_BLOCK_SIZE 5 +#define DATA_BLOCK_SIZE 5 + +// Globals --------------------------------------------------------------------- +using BPrivate::gDefaultTokens; + +typedef bool (*find_loop_pred)(_loop_data_* data, void* data); +_loop_data_* find_loop_data(_loop_data_* begin, _loop_data_* end, + find_loop_pred, void* data); +bool looper_by_port_pred(_loop_data_* looper, void* data); +bool looper_by_tid_pred(_loop_data_* looper, void* data); +bool looper_by_name_pred(_loop_data_* looper, void* data); +bool looper_pred(_loop_data_* looper, void* data); +bool empty_slot_pred(_loop_data_* looper, void* data); +bool copy_list_pred(_loop_data_* looper, void* data); + +port_id _get_looper_port_(const BLooper* looper); +bool _use_preferred_target_(BMessage* msg) { return msg->fPreferred; } +int32 _get_message_target_(BMessage* msg) { return msg->fTarget; } + +uint32 BLooper::sLooperID = B_ERROR; +uint32 BLooper::sLooperListSize = 0; +uint32 BLooper::sLooperCount = 0; +_loop_data_* BLooper::sLooperList = NULL; +BLocker BLooper::sLooperListLock; +team_id BLooper::sTeamID = B_ERROR; + +static property_info gLooperPropInfo[] = +{ +}; + +struct _loop_data_ +{ + BLooper* looper; + thread_id thread; +}; + +//------------------------------------------------------------------------------ +BLooper::BLooper(const char* name, int32 priority, int32 port_capacity) + : BHandler(name), fMsgPort(-1) +{ + InitData(name, priority, port_capacity); +} +//------------------------------------------------------------------------------ +BLooper::~BLooper() +{ + kill_thread(fTaskID); + delete fQueue; + delete_sem(fLockSem); + delete_port(fMsgPort); + + UnlockFully(); + + // Clean up our filters + SetCommonFilterList(NULL); + + BAutolock ListLock(sLooperListLock); + RemoveHandler(this); + RemoveLooper(this); +} +//------------------------------------------------------------------------------ +BLooper::BLooper(BMessage* data) + : BHandler(data) +{ + int32 portCap; + if (data->FindInt32("_port_cap", &portCap) != B_OK) + { + portCap = B_LOOPER_PORT_DEFAULT_CAPACITY; + } + + InitData(Name(), B_NORMAL_PRIORITY, portCap); +} +//------------------------------------------------------------------------------ +BArchivable* BLooper::Instantiate(BMessage* data) +{ + if (validate_instantiation(data, "BLooper")) + { + return new BLooper(data); + } + + return NULL; +} +//------------------------------------------------------------------------------ +status_t BLooper::Archive(BMessage* data, bool deep) const +{ + status_t err = BHandler::Archive(data, deep); + if (!err) + { + port_info info; + err = get_port_info(fMsgPort, &info); + if (!err) + { + err = data->AddInt32("_port_cap", info.capacity); + } + } + + return err; +} +//------------------------------------------------------------------------------ +status_t BLooper::PostMessage(uint32 command) +{ + BMessage Message(command); + return _PostMessage(&Message, this, NULL); +} +//------------------------------------------------------------------------------ +status_t BLooper::PostMessage(BMessage* message) +{ + return _PostMessage(message, this, NULL); +} +//------------------------------------------------------------------------------ +status_t BLooper::PostMessage(uint32 command, BHandler* handler, + BHandler* reply_to) +{ + BMessage Message(command); + return _PostMessage(&Message, handler, reply_to); +} +//------------------------------------------------------------------------------ +status_t BLooper::PostMessage(BMessage* message, BHandler* handler, + BHandler* reply_to) +{ + return _PostMessage(message, handler, reply_to); +} +//------------------------------------------------------------------------------ +void BLooper::DispatchMessage(BMessage* message, BHandler* handler) +{ +DBG(OUT("BLooper::DispatchMessage(%.4s)\n", (char*)&message->what)); +/** + @note Initially, DispatchMessage() was locking the looper, calling the + filtering API, determining whether to use fPreferred or not, and + deleting the message. A look at the BeBook, however, reveals that + all this function does is handle its own B_QUIT_REQUESTED messages + and pass everything else to handler->MessageReceived(). Clearly the + rest must be happening in task_looper(). This makes a lot of sense + because otherwise every derived class would have to figure out when + to use fPreferred, handle the locking and filtering and delete the + message. Even if the BeBook didn't say as much, it would make total + sense to hoist that functionality out of here and into task_looper(). + */ + switch (message->what) + { + case _QUIT_: + { + // Can't call Quit() to do this, because of the slight chance + // another thread with have us locked between now and then. + fTerminating = true; + delete this; + break; + } + + case B_QUIT_REQUESTED: + { + if (handler == this) + { + do_quit_requested(message); + break; + } + else + { + // fall through + } + } + + default: + { + handler->MessageReceived(message); + break; + } + } +DBG(OUT("BLooper::DispatchMessage() done\n")); +} +//------------------------------------------------------------------------------ +void BLooper::MessageReceived(BMessage* msg) +{ + // TODO: verify + // The BeBook says this "simply calls the inherited function. ...the BLooper + // implementation does nothing of importance." Which is not the same as + // saying it does nothing. Investigate. + BHandler::MessageReceived(msg); +} +//------------------------------------------------------------------------------ +BMessage* BLooper::CurrentMessage() const +{ + return fLastMessage; +} +//------------------------------------------------------------------------------ +BMessage* BLooper::DetachCurrentMessage() +{ + Lock(); + BMessage* msg = fLastMessage; + fLastMessage = NULL; + fQueue->RemoveMessage(msg); + Unlock(); + return msg; +} +//------------------------------------------------------------------------------ +BMessageQueue* BLooper::MessageQueue() const +{ + return fQueue; +} +//------------------------------------------------------------------------------ +bool BLooper::IsMessageWaiting() const +{ + if (!IsLocked()) + { + // TODO: test + debugger(""); + } + + if (!fQueue->IsEmpty()) + { + return true; + } + + int32 count; + do + { + count = port_buffer_size_etc(fMsgPort, B_TIMEOUT, 0); + } while (count == B_WOULD_BLOCK); + + return count > 0; +} +//------------------------------------------------------------------------------ +void BLooper::AddHandler(BHandler* handler) +{ + AssertLocked(); + + if (handler->Looper() == NULL) + { + fHandlers.AddItem(handler); + handler->SetLooper(this); + handler->SetNextHandler(this); + BList* Filters = handler->FilterList(); + if (Filters) + { + for (int32 i = 0; i < Filters->CountItems(); ++i) + { + ((BMessageFilter*)Filters->ItemAt(i))->SetLooper(this); + } + } + } +} +//------------------------------------------------------------------------------ +bool BLooper::RemoveHandler(BHandler* handler) +{ + AssertLocked(); + + // TODO: test + // Need to ensure this algo reflects what actually happens + if (handler->Looper() == this && fHandlers.RemoveItem(handler)) + { + if (handler == fPreferred) + { + fPreferred = NULL; + } + + handler->SetNextHandler(NULL); + handler->SetLooper(NULL); + return true; + } + + return false; +} +//------------------------------------------------------------------------------ +int32 BLooper::CountHandlers() const +{ + AssertLocked(); + + return fHandlers.CountItems(); +} +//------------------------------------------------------------------------------ +BHandler* BLooper::HandlerAt(int32 index) const +{ + AssertLocked(); + + return (BHandler*)fHandlers.ItemAt(index); +} +//------------------------------------------------------------------------------ +int32 BLooper::IndexOf(BHandler* handler) const +{ + AssertLocked(); + + // TODO: test + // ensure the B_ERROR gets returned if the handler isn't in the list + return fHandlers.IndexOf(handler); +} +//------------------------------------------------------------------------------ +BHandler* BLooper::PreferredHandler() const +{ + return fPreferred; +} +//------------------------------------------------------------------------------ +void BLooper::SetPreferredHandler(BHandler* handler) +{ + if (handler && handler->Looper() == this && IndexOf(handler) >= 0) + { + fPreferred = handler; + } + else + { + fPreferred = NULL; + } +} +//------------------------------------------------------------------------------ +thread_id BLooper::Run() +{ + AssertLocked(); + + if (fRunCalled) + { + // Not allowed to call Run() more than once + // TODO: test + // find out what message is actually here + debugger(""); + } + + fTaskID = spawn_thread(_task0_, Name(), fInitPriority, this); + + if (fTaskID == B_NO_MORE_THREADS || fTaskID == B_NO_MEMORY) + { + return fTaskID; + } + + if (fMsgPort == B_NO_MORE_PORTS || fMsgPort == B_BAD_VALUE) + { + return fMsgPort; + } + + fRunCalled = true; + Unlock(); + status_t err = resume_thread(fTaskID); + if (err) + { + return err; + } + + return fTaskID; +} +//------------------------------------------------------------------------------ +void BLooper::Quit() +{ +DBG(OUT("BLooper::Quit()\n")); + if (!IsLocked()) + { + const char* name = Name(); + if (!name) + { + name = "no-name"; + } + printf("ERROR - you must Lock a looper before calling Quit(), " + "team=%d, looper=%s", Team(), name); + } +DBG(OUT(" is locked\n")); + + if (!fRunCalled || find_thread(NULL) == fTaskID) + { +DBG(OUT(" Run() has not been called yet or we are the looper thread\n")); + fTerminating = true; + delete this; + } + else + { +DBG(OUT(" Run() has already been called and we are not the looper thread\n")); + // As with sem in _Lock(), we need to cache this here in case the looper + // disappears before we get to the wait_for_thread() below + thread_id tid = Thread(); + + // bonefish: We need to unlock here. Otherwise the looper thread can't + // dispatch the _QUIT_ message we're going to post. + do { + Unlock(); + } while (IsLocked()); + + // As per the BeBook, if we've been called by a thread other than + // our own, the rest of the message queue has to get processed. So + // we put this in the queue, and when it shows up, we'll call Quit() + // from our own thread. + // A little testing with BMessageFilter shows _QUIT_ is being used here. + // I got suspicious when my test QuitRequested() wasn't getting called + // when Quit() was invoked from another thread. Makes a nice proof that + // this is how it's handled, too. + status_t err; +DBG(OUT(" PostMessage(_QUIT_)...\n")); +// err = PostMessage(_QUIT_); + +BMessage message(_QUIT_); +message.AddInt32("testfield", 42); +err = PostMessage(&message); +DBG(OUT(" ... done: %lx\n", err)); + + // There's a possibility that PostMessage() will return B_WILL_BLOCK + // because the port is full, so we'll wait a bit and re-post until + // we won't block. + while (err == B_WOULD_BLOCK) + { + // TODO: test this value; it may be too short + snooze(10000); + err = PostMessage(_QUIT_); + } + + // Also as per the BeBook, we have to wait until the looper is done + // processing any remaining messages. + int32 temp; + do + { +DBG(OUT(" wait_for_thread()...\n")); + err = wait_for_thread(tid, &temp); + } while (err == B_INTERRUPTED); + } +DBG(OUT("BLooper::Quit() done\n")); +} +//------------------------------------------------------------------------------ +bool BLooper::QuitRequested() +{ + return true; +} +//------------------------------------------------------------------------------ +bool BLooper::Lock() +{ + // Defer to global _Lock(); see notes there + return _Lock(this, -1, B_INFINITE_TIMEOUT) == B_OK; +} +//------------------------------------------------------------------------------ +void BLooper::Unlock() +{ +DBG(OUT("BLooper::Unlock()\n")); + // Make sure we're locked to begin with + AssertLocked(); + + // Decrement fOwnerCount + --fOwnerCount; +DBG(OUT(" fOwnerCount now: %ld\n", fOwnerCount)); + // Check to see if the owner still wants a lock + if (fOwnerCount == 0) + { + // Set fOwner to invalid thread_id (< 0) + fOwner = -1; + + // Decrement requested lock count (using fAtomicCount for this) + int32 atomicCount = atomic_add(&fAtomicCount, -1); +DBG(OUT(" fAtomicCount now: %ld\n", fAtomicCount)); + + // Check if anyone is waiting for a lock +// bonefish: Currently _Lock() always acquires the semaphore. +// if (atomicCount > 0) + { + // release the lock + release_sem(fLockSem); + } + } +DBG(OUT("BLooper::Unlock() done\n")); +} +//------------------------------------------------------------------------------ +bool BLooper::IsLocked() const +{ + // We have to lock the list for the call to IsLooperValid(). Has the side + // effect of not letting the looper get deleted while we're here. + BAutolock ListLock(sLooperListLock); + + if (!ListLock.IsLocked()) + { + // If we can't lock the list, our semaphore is probably toast + return false; + } + + if (!IsLooperValid(this)) + { + // The looper is gone, so of course it's not locked + return false; + } + + // Got this from Jeremy's BLocker implementation + return find_thread(NULL) == fOwner; +} +//------------------------------------------------------------------------------ +status_t BLooper::LockWithTimeout(bigtime_t timeout) +{ + return _Lock(this, -1, B_INFINITE_TIMEOUT); +} +//------------------------------------------------------------------------------ +thread_id BLooper::Thread() const +{ + return fTaskID; +} +//------------------------------------------------------------------------------ +team_id BLooper::Team() const +{ + return sTeamID; +} +//------------------------------------------------------------------------------ +BLooper* BLooper::LooperForThread(thread_id tid) +{ + BAutolock ListLock(sLooperListLock); + if (ListLock.IsLocked()) + { + _loop_data_* result = find_loop_data(sLooperList, + sLooperList + sLooperCount, + looper_by_tid_pred, (void*)tid); + if (result) + { + return result->looper; + } + } + + return NULL; +} +//------------------------------------------------------------------------------ +thread_id BLooper::LockingThread() const +{ + return fOwner; +} +//------------------------------------------------------------------------------ +int32 BLooper::CountLocks() const +{ + return fOwnerCount; +} +//------------------------------------------------------------------------------ +int32 BLooper::CountLockRequests() const +{ + return fAtomicCount; +} +//------------------------------------------------------------------------------ +sem_id BLooper::Sem() const +{ + return fLockSem; +} +//------------------------------------------------------------------------------ +BHandler* BLooper::ResolveSpecifier(BMessage* msg, int32 index, + BMessage* specifier, int32 form, + const char* property) +{ + // Straight from the BeBook + BPropertyInfo PropertyInfo(gLooperPropInfo); + if (PropertyInfo.FindMatch(msg, index, specifier, form, property) >= 0) + { + return this; + } + + BMessage Reply(B_MESSAGE_NOT_UNDERSTOOD); + Reply.AddInt32("error", B_BAD_SCRIPT_SYNTAX); + Reply.AddString("message", "Didn't understand the specifier(s)"); + msg->SendReply(&Reply); + + return NULL; +} +//------------------------------------------------------------------------------ +status_t BLooper::GetSupportedSuites(BMessage* data) +{ + // TODO: implement +} +//------------------------------------------------------------------------------ +void BLooper::AddCommonFilter(BMessageFilter* filter) +{ + AssertLocked(); + if (!fCommonFilters) + { + fCommonFilters = new BList(FILTER_LIST_BLOCK_SIZE); + } + filter->SetLooper(this); + fCommonFilters->AddItem(filter); +} +//------------------------------------------------------------------------------ +bool BLooper::RemoveCommonFilter(BMessageFilter* filter) +{ + AssertLocked(); + bool result = fCommonFilters->RemoveItem(filter); + if (result) + { + filter->SetLooper(NULL); + } + + return result; +} +//------------------------------------------------------------------------------ +void BLooper::SetCommonFilterList(BList* filters) +{ + AssertLocked(); + if (fCommonFilters) + { + for (int32 i = 0; i < fCommonFilters->CountItems(); ++i) + { + delete fCommonFilters->ItemAt(i); + } + fCommonFilters->MakeEmpty(); + } + + // Per the BeBook, we take ownership of the list + fCommonFilters = filters; + if (fCommonFilters) + { + for (int32 i = 0; i < fCommonFilters->CountItems(); ++i) + { + ((BMessageFilter*)fCommonFilters->ItemAt(i))->SetLooper(this); + } + } +} +//------------------------------------------------------------------------------ +BList* BLooper::CommonFilterList() const +{ + return fCommonFilters; +} +//------------------------------------------------------------------------------ +status_t BLooper::Perform(perform_code d, void* arg) +{ + // This is sort of what we're doing for this function everywhere + return B_ERROR; +} +//------------------------------------------------------------------------------ +BMessage* BLooper::MessageFromPort(bigtime_t timeout) +{ + return ReadMessageFromPort(timeout); +} +//------------------------------------------------------------------------------ +void BLooper::_ReservedLooper1() +{ +} +//------------------------------------------------------------------------------ +void BLooper::_ReservedLooper2() +{ +} +//------------------------------------------------------------------------------ +void BLooper::_ReservedLooper3() +{ +} +//------------------------------------------------------------------------------ +void BLooper::_ReservedLooper4() +{ +} +//------------------------------------------------------------------------------ +void BLooper::_ReservedLooper5() +{ +} +//------------------------------------------------------------------------------ +void BLooper::_ReservedLooper6() +{ +} +//------------------------------------------------------------------------------ +BLooper::BLooper(const BLooper&) +{ + // Copy construction not allowed +} +//------------------------------------------------------------------------------ +BLooper& BLooper::operator=(const BLooper& ) +{ + // Looper copying not allowed +} +//------------------------------------------------------------------------------ +BLooper::BLooper(int32 priority, port_id port, const char* name) +{ + // This must be a legacy constructor + fMsgPort = port; + InitData(name, priority, B_LOOPER_PORT_DEFAULT_CAPACITY); +} +//------------------------------------------------------------------------------ +status_t BLooper::_PostMessage(BMessage* msg, BHandler* handler, + BHandler* reply_to) +{ + BAutolock ListLock(sLooperListLock); + if (!ListLock.IsLocked()) + { + return B_BAD_VALUE; + } + + if (!IsLooperValid(this)) + { + return B_BAD_VALUE; + } + + // Does handler belong to this looper? + if (handler && handler->Looper() != this) + { + return B_MISMATCHED_VALUES; + } + + status_t err = B_OK; + + BMessenger Messenger(handler, this, &err); + + if (!err) + { + err = Messenger.SendMessage(msg, reply_to); + } + + return err; +} +//------------------------------------------------------------------------------ +status_t BLooper::_Lock(BLooper* loop, port_id port, bigtime_t timeout) +{ +DBG(OUT("BLooper::_Lock(%p, %lx)\n", loop, port)); +/** + @note The assumption I'm under here is that since we can get the port of + the BLooper directly from the BLooper itself, the port parameter is + for identifying BLoopers by port_id when a pointer to the BLooper in + question is not available. So this function has two modes: + o When loop != NULL, use it directly + o When loop == NULL and port is valid, use the port_id to get + the looper + I scoured the docs to find out what constitutes a valid port_id to + no avail. Since create_port uses the standard error values in its + returned port_id, I'll assume that anything less than zero is a safe + bet as an *invalid* port_id. I'm guessing that, like thread and + semaphore ids, anything >= zero is valid. So, the short version of + this reads: if you don't want to find by port_id, make port = -1. + + Another assumption I'm making is that Lock() and LockWithTimeout() + are covers for this function. If it turns out that we don't really + need this function, I may refactor this code into LockWithTimeout() + and have Lock() call it instead. This function could then be + removed. + */ + + // Check params (loop, port) + if (!loop && port < 0) + { +DBG(OUT("BLooper::_Lock() done 1\n")); + return B_BAD_VALUE; + } + + // forward declared so I can use BAutolock on sLooperListLock + thread_id curThread; + sem_id sem; + +/** + @note We lock the looper list at the start of the lock operation to + prevent the looper getting removed from the list while we're + doing list operations. Also ensures that the looper doesn't + get deleted here (since ~BLooper() has to lock the list as + well to remove itself). + */ + { + BAutolock ListLock(sLooperListLock); + if (!ListLock.IsLocked()) + { + // If we can't lock, the semaphore is probably + // gone, which leaves us in no-man's land +DBG(OUT("BLooper::_Lock() done 2\n")); + return B_BAD_VALUE; + } + + // Look up looper by port_id, if necessary + if (!loop) + { + loop = LooperForPort(port); + if (!loop) + { +DBG(OUT("BLooper::_Lock() done 3\n")); + return B_BAD_VALUE; + } + } + else + { + // Check looper validity + if (!IsLooperValid(loop)) + { +DBG(OUT("BLooper::_Lock() done 4\n")); + return B_BAD_VALUE; + } + } + + // Check for nested lock attempt + curThread = find_thread(NULL); + if (curThread == loop->fOwner) + { + // Bump fOwnerCount + ++loop->fOwnerCount; +DBG(OUT("BLooper::_Lock() done 5: fOwnerCount: %ld\n", loop->fOwnerCount)); + return B_OK; + } + + // Cache the semaphore + sem = loop->fLockSem; + + // Validate the semaphore + if (sem < 0) + { +DBG(OUT("BLooper::_Lock() done 6\n")); + return B_BAD_VALUE; + } + + // Bump the requested lock count (using fAtomicCount for this) + atomic_add(&loop->fAtomicCount, 1); + + // sLooperListLock automatically released here + } + +/** + @note We have to operate with the looper list unlocked during semaphore + acquisition so that the rest of the application doesn't have to + wait for this lock to happen. This is why we cached fLockSem + earlier -- with the list unlocked, the looper might get deleted + right out from under us. This is also why we use a raw semaphore + instead of the easier-to-deal-with BLocker; you can't cache a + BLocker. + */ + // acquire the lock + status_t err; + do + { + err = acquire_sem_etc(sem, 1, B_RELATIVE_TIMEOUT, timeout); + } while (err == B_INTERRUPTED); + + if (!err) + { + // Assign current thread to fOwner + loop->fOwner = curThread; + // Reset fOwnerCount to 1 + loop->fOwnerCount = 1; + } + +DBG(OUT("BLooper::_Lock() done: %lx\n", err)); + return err; +} +//------------------------------------------------------------------------------ +status_t BLooper::_LockComplete(BLooper* loop, int32 old, thread_id this_tid, + sem_id sem, bigtime_t timeout) +{ + // What is this for? Hope I'm not missing something conceptually here ... +} +//------------------------------------------------------------------------------ +void BLooper::InitData() +{ + fOwner = B_ERROR; + fRunCalled = false; + fQueue = new BMessageQueue(); + fCommonFilters = NULL; + fPreferred = NULL; + fTaskID = B_ERROR; + fTerminating = false; + + if (sTeamID == -1) + { + thread_info info; + get_thread_info(fTaskID,&info); + sTeamID = info.team; + } + + BAutolock ListLock(sLooperListLock); + AddLooper(this); + Lock(); + AddHandler(this); +} +//------------------------------------------------------------------------------ +void BLooper::InitData(const char* name, int32 priority, int32 port_capacity) +{ + fLockSem = create_sem(1, name); + + if (fMsgPort <= 0) + { + fMsgPort = create_port(port_capacity, name ? name : "LooperPort"); + } + + InitData(); +} +//------------------------------------------------------------------------------ +void BLooper::AddMessage(BMessage* msg) +{ + // TODO: implement + // Why is this here? +} +//------------------------------------------------------------------------------ +void BLooper::_AddMessagePriv(BMessage* msg) +{ + // TODO: implement + // No, really; why the hell is this here?? +} +//------------------------------------------------------------------------------ +status_t BLooper::_task0_(void* arg) +{ +DBG(OUT("LOOPER: _task0_()\n")); + BLooper* obj = (BLooper*)arg; + +DBG(OUT("LOOPER: locking looper...\n")); + if (obj->Lock()) + { +DBG(OUT("LOOPER: looper locked\n")); + obj->task_looper(); + obj->fTerminating = true; + delete obj; + } + + return B_OK; +} +//------------------------------------------------------------------------------ +void* BLooper::ReadRawFromPort(int32* msgcode, bigtime_t tout) +{ +DBG(OUT("BLooper::ReadRawFromPort()\n")); + int8* msgbuffer = NULL; + ssize_t buffersize; + ssize_t bytesread; + + if (tout == B_INFINITE_TIMEOUT) + { + buffersize = port_buffer_size(fMsgPort); +DBG(OUT("BLooper::ReadRawFromPort(): buffersize: %ld\n", buffersize)); + } + else + { + buffersize = port_buffer_size_etc(fMsgPort, 0, tout); + if (buffersize == B_TIMED_OUT || buffersize == B_BAD_PORT_ID || + buffersize == B_WOULD_BLOCK) + { +DBG(OUT("BLooper::ReadRawFromPort() done 1\n")); + return NULL; + } + } + + if (buffersize > 0) + msgbuffer = new int8[buffersize]; + + if (tout == B_INFINITE_TIMEOUT) + { +DBG(OUT("read_port()...\n")); + bytesread = read_port(fMsgPort, msgcode, msgbuffer, buffersize); +DBG(OUT("read_port() done: %ld\n", bytesread)); +DBG(OUT("BLooper::ReadRawFromPort() read: %.4s\n", (char*)msgcode)); + } + else + { + bytesread = read_port_etc(fMsgPort, msgcode, msgbuffer, buffersize, + B_TIMEOUT, tout); + } + +DBG(OUT("BLooper::ReadRawFromPort() done: %p\n", msgbuffer)); + return msgbuffer; +} +//------------------------------------------------------------------------------ +BMessage* BLooper::ReadMessageFromPort(bigtime_t tout) +{ +DBG(OUT("BLooper::ReadMessageFromPort()\n")); + int32 msgcode; + BMessage* bmsg; + + void* msgbuffer = ReadRawFromPort(&msgcode, tout); + + bmsg = ConvertToMessage(msgbuffer, msgcode); + + if (msgbuffer) + { + delete[] msgbuffer; + } + +DBG(OUT("BLooper::ReadMessageFromPort() done: %p\n", bmsg)); + return bmsg; +} +//------------------------------------------------------------------------------ +BMessage* BLooper::ConvertToMessage(void* raw, int32 code) +{ +DBG(OUT("BLooper::ConvertToMessage()\n")); + BMessage* bmsg = new BMessage(code); + + if (raw != NULL) + { + if (bmsg->Unflatten((const char*)raw) != B_OK) { +DBG(OUT("BLooper::ConvertToMessage(): unflattening message failed\n")); + delete bmsg; + bmsg = NULL; + } + } + +DBG(OUT("BLooper::ConvertToMessage(): %p\n", bmsg)); + return bmsg; +} +//------------------------------------------------------------------------------ +void BLooper::task_looper() +{ +DBG(OUT("BLooper::task_looper()\n")); + // Check that looper is locked (should be) + AssertLocked(); + // Unlock the looper + Unlock(); + + // loop: As long as we are not terminating. + while (!fTerminating) + { +DBG(OUT("LOOPER: outer loop\n")); + // Read from message port (how do we determine what the timeout is?) +DBG(OUT("LOOPER: MessageFromPort()...\n")); + BMessage* msg = MessageFromPort(); +DBG(OUT("LOOPER: ...done\n")); + + // Did we get a message? + if (msg) + { +DBG(OUT("LOOPER: got message\n")); + // Add to queue + fQueue->AddMessage(msg); + } +else +DBG(OUT("LOOPER: got no message\n")); + + // Get message count from port + int32 msgCount = port_count(fMsgPort); + for (int32 i = 0; i < msgCount; ++i) + { + // Read 'count' messages from port (so we will not block) + // We use zero as our timeout since we know there is stuff there + msg = MessageFromPort(0); + // Add messages to queue + fQueue->AddMessage(msg); + } + + // loop: As long as there are messages in the queue and the port is + // empty... and we are not terminating, of course. + bool dispatchNextMessage = true; + while (!fTerminating && dispatchNextMessage) { +DBG(OUT("LOOPER: inner loop\n")); + // Lock the looper + Lock(); + + // Get next message from queue (assign to fLastMessage) + fLastMessage = fQueue->NextMessage(); + if (!fLastMessage) { + // No more messages: Unlock the looper and terminate the + // dispatch loop. + dispatchNextMessage = false; + Unlock(); + } else { +DBG(OUT("LOOPER: fLastMessage: 0x%lx: %.4s\n", fLastMessage->what, +(char*)&fLastMessage->what)); +DBG(fLastMessage->PrintToStream()); + // Get the target handler + // Use BMessage friend functions to determine if we are using the + // preferred handler, or if a target has been specified + BHandler* handler; + if (_use_preferred_target_(fLastMessage)) + { +DBG(OUT("LOOPER: use preferred target\n")); + handler = fPreferred; + } + else + { +DBG(OUT("LOOPER: don't use preferred target\n")); + /** + @note Here is where all the token stuff starts to + make sense. How, exactly, do we determine + what the target BHandler is? If we look at + BMessage, we see an int32 field, fTarget. + Amazingly, we happen to have a global mapping + of BHandler pointers to int32s! + */ +DBG(OUT("LOOPER: use: %ld\n", _get_message_target_(fLastMessage))); + gDefaultTokens.GetToken(_get_message_target_(fLastMessage), + B_HANDLER_TOKEN, + (void**)&handler); +DBG(OUT("LOOPER: handler: %p, this: %p\n", handler, this)); + } + + if (!handler) + { +DBG(OUT("LOOPER: no target handler, use this\n")); + handler = this; + } + + // Is this a scripting message? (BMessage::HasSpecifiers()) + if (fLastMessage->HasSpecifiers()) + { + int32 index = 0; + // Make sure the current specifier is kosher + if (fLastMessage->GetCurrentSpecifier(&index) == B_OK) + { + handler = resolve_specifier(handler, fLastMessage); + } + } +else +DBG(OUT("LOOPER: no scripting message\n")); + + if (handler) + { + // Do filtering + handler = top_level_filter(fLastMessage, handler); +DBG(OUT("LOOPER: top_level_filter(): %p\n", handler)); + if (handler && handler->Looper() == this) + { + DispatchMessage(fLastMessage, handler); + } + } + + // Unlock the looper + Unlock(); + + // Delete the current message (fLastMessage) + delete fLastMessage; + fLastMessage = NULL; + + // Are any messages on the port? + if (port_count(fMsgPort) > 0) + { + // Do outer loop + dispatchNextMessage = false; + } + } + } + } +DBG(OUT("BLooper::task_looper() done\n")); +} +//------------------------------------------------------------------------------ +void BLooper::do_quit_requested(BMessage* msg) +{ +/** + @note I couldn't figure out why do_quit_requested() was necessary; why not + just call Quit()? Then, while writing the PostMessage() code, I + realized that the sender of the B_QUIT_REQUESTED message just might + be waiting for a reply. A quick test, and yes, we get a reply + which consists of: + what: B_REPLY + "result" (bool) return of QuitRequested() + "thread" (int32) the looper's thread id + + While Quit() could use fLastMessage, it makes more sense that + do_quit_requested() would handle it since it gets passed the + message. + */ + + bool isQuitting = QuitRequested(); + + if (msg->IsSourceWaiting()) + { + BMessage ReplyMsg(B_REPLY); + ReplyMsg.AddBool("result", isQuitting); + ReplyMsg.AddInt32("thread", fTaskID); + msg->SendReply(&ReplyMsg); + } + + if (isQuitting) + { + Quit(); + } +} +//------------------------------------------------------------------------------ +bool BLooper::AssertLocked() const +{ + if (!IsLocked()) + { + debugger("looper must be locked before proceeding\n"); + return false; + } + + return true; +} +//------------------------------------------------------------------------------ +BHandler* BLooper::top_level_filter(BMessage* msg, BHandler* t) +{ + // TODO: implement + // return the supplied handler for now + return t; +} +//------------------------------------------------------------------------------ +BHandler* BLooper::handler_only_filter(BMessage* msg, BHandler* t) +{ + // TODO: implement +} +//------------------------------------------------------------------------------ +BHandler* BLooper::apply_filters(BList* list, BMessage* msg, BHandler* target) +{ + // TODO: implement +} +//------------------------------------------------------------------------------ +void BLooper::check_lock() +{ + // TODO: implement +} +//------------------------------------------------------------------------------ +BHandler* BLooper::resolve_specifier(BHandler* target, BMessage* msg) +{ + // TODO: implement +} +//------------------------------------------------------------------------------ +void BLooper::UnlockFully() +{ + // TODO: implement +} +//------------------------------------------------------------------------------ +void BLooper::AddLooper(BLooper* loop) +{ + if (sLooperListLock.IsLocked()) + { +#if defined(CHECK_ADD_LOOPER) + // First see if it's already been added + if (!IsLooperValid(loop)) +#endif + { + _loop_data_* result = find_loop_data(sLooperList, + sLooperList + sLooperCount, + empty_slot_pred, NULL); + + uint32& looperCount = sLooperCount; // hokey debugging aids + uint32& looperListSize = sLooperListSize; + if (!result) + { + // No empty slots; time to expand + if (looperCount == looperListSize) + { + // Allocate the expanded list + _loop_data_* temp = + new _loop_data_[looperListSize + DATA_BLOCK_SIZE]; + if (!temp) + { + // Not good + debugger("unable to allocate looper list"); + return; + } + + // Transfer the existing data + memcpy(temp, sLooperList, + sizeof (_loop_data_*) * looperListSize); + delete[] sLooperList; + sLooperList = temp; + looperListSize += DATA_BLOCK_SIZE; + } + + // Whether we expanded or not, the "new" one will be at the end +DBG(OUT("BLooper::AddLooper(): looper added at %ld\n", looperCount)); + result = &sLooperList[looperCount]; + } + + result->looper = loop; + result->thread = loop->fTaskID; + ++looperCount; + } + } +} +//------------------------------------------------------------------------------ +bool BLooper::IsLooperValid(const BLooper* l) +{ + if (sLooperListLock.IsLocked()) + { + return find_loop_data(sLooperList, sLooperList + sLooperCount, + looper_pred, (void*)l); + } + + return false; +} +//------------------------------------------------------------------------------ +void BLooper::RemoveLooper(BLooper* l) +{ + if (sLooperListLock.IsLocked()) + { + _loop_data_* result = find_loop_data(sLooperList, + sLooperList + sLooperCount, + looper_pred, l); + if (result) + { + result->looper = NULL; + --sLooperCount; + } + + // Nothing left? Clean up; the app is probably exiting anyway + if (sLooperCount == 0) + { + delete[] sLooperList; + sLooperList = NULL; + sLooperListSize = 0; + } + } +} +//------------------------------------------------------------------------------ +void BLooper::GetLooperList(BList* list) +{ + BAutolock ListLock(sLooperListLock); + if (ListLock.IsLocked()) + { + find_loop_data(sLooperList, sLooperList + sLooperCount, + copy_list_pred, (void*)list); + } +} +//------------------------------------------------------------------------------ +BLooper* BLooper::LooperForName(const char* name) +{ + if (sLooperListLock.IsLocked()) + { + _loop_data_* result = find_loop_data(sLooperList, + sLooperList + sLooperCount, + looper_by_name_pred, (void*)name); + if (result) + { + return result->looper; + } + } + + return NULL; +} +//------------------------------------------------------------------------------ +BLooper* BLooper::LooperForPort(port_id port) +{ + if (sLooperListLock.IsLocked()) + { + _loop_data_* result = find_loop_data(sLooperList, + sLooperList + sLooperCount, + looper_by_port_pred, (void*)port); + if (result) + { + return result->looper; + } + } + + return NULL; +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +_loop_data_* find_loop_data(_loop_data_* begin, _loop_data_* end, + find_loop_pred predicate, void* data) +{ + while (begin && begin != end) + { + if (begin->looper) + { + if (predicate(begin, data)) + { + return begin; + } + } + ++begin; + } + + return NULL; +} +//------------------------------------------------------------------------------ +bool looper_by_port_pred(_loop_data_* looper, void *data) +{ + return _get_looper_port_(looper->looper) == (port_id)data; +} +//------------------------------------------------------------------------------ +bool looper_by_tid_pred(_loop_data_* looper, void *data) +{ + return looper->thread == (thread_id)data; +} +//------------------------------------------------------------------------------ +bool looper_by_name_pred(_loop_data_* looper, void *data) +{ + return strcmp(looper->looper->Name(), (const char*)data) == 0; +} +//------------------------------------------------------------------------------ +bool looper_pred(_loop_data_* looper, void *data) +{ + return looper->looper == (BLooper*)data; +} +//------------------------------------------------------------------------------ +bool empty_slot_pred(_loop_data_* looper, void*) +{ + return looper->looper == NULL; +} +//------------------------------------------------------------------------------ +bool copy_list_pred(_loop_data_ *looper, void* data) +{ + BList* List = (BList*)data; + if (List && looper->looper) + { + List->AddItem(looper->looper); + } + + // Ride this train to the end + return false; +} +//------------------------------------------------------------------------------ +port_id _get_looper_port_(const BLooper* looper) +{ + return looper->fMsgPort; +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/kits/app/MessageFilter.cpp b/src/kits/app/MessageFilter.cpp new file mode 100644 index 0000000000..6bac156770 --- /dev/null +++ b/src/kits/app/MessageFilter.cpp @@ -0,0 +1,165 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: MessageFilter.cpp +// Author: Erik Jaesler (erik@cgsoftware.com) +// Description: BMessageFilter class creates objects that filter +// in-coming BMessages. +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +BMessageFilter::BMessageFilter(uint32 inWhat, filter_hook func) + : fFiltersAny(false), + what(inWhat), + fDelivery(B_ANY_DELIVERY), + fSource(B_ANY_SOURCE), + fLooper(NULL), + fFilterFunction(func) +{ +} +//------------------------------------------------------------------------------ +BMessageFilter::BMessageFilter(message_delivery delivery, message_source source, + filter_hook func) + : fFiltersAny(true), + what(0), + fDelivery(delivery), + fSource(source), + fLooper(NULL), + fFilterFunction(func) +{ +} +//------------------------------------------------------------------------------ +BMessageFilter::BMessageFilter(message_delivery delivery, message_source source, + uint32 inWhat, filter_hook func) + : fFiltersAny(false), + what(inWhat), + fDelivery(delivery), + fSource(source), + fLooper(NULL), + fFilterFunction(func) +{ +} +//------------------------------------------------------------------------------ +BMessageFilter::BMessageFilter(const BMessageFilter& filter) +{ + *this = filter; +} +//------------------------------------------------------------------------------ +BMessageFilter::BMessageFilter(const BMessageFilter* filter) +{ + *this = *filter; +} +//------------------------------------------------------------------------------ +BMessageFilter::~BMessageFilter() +{ + ; +} +//------------------------------------------------------------------------------ +BMessageFilter& BMessageFilter::operator=(const BMessageFilter& from) +{ + fFiltersAny = from.FiltersAnyCommand(); + what = from.Command(); + fDelivery = from.MessageDelivery(); + fSource = from.MessageSource(); + fFilterFunction = from.FilterFunction(); + + SetLooper(from.Looper()); + + return *this; +} +//------------------------------------------------------------------------------ +filter_result BMessageFilter::Filter(BMessage* message, BHandler** target) +{ + if (fFilterFunction) + { + return fFilterFunction(message, target, this); + } + + return B_DISPATCH_MESSAGE; +} +//------------------------------------------------------------------------------ +message_delivery BMessageFilter::MessageDelivery() const +{ + return fDelivery; +} +//------------------------------------------------------------------------------ +message_source BMessageFilter::MessageSource() const +{ + return fSource; +} +//------------------------------------------------------------------------------ +uint32 BMessageFilter::Command() const +{ + return what; +} +//------------------------------------------------------------------------------ +bool BMessageFilter::FiltersAnyCommand() const +{ + return fFiltersAny; +} +//------------------------------------------------------------------------------ +BLooper* BMessageFilter::Looper() const +{ + return fLooper; +} +//------------------------------------------------------------------------------ +void BMessageFilter::_ReservedMessageFilter1() +{ + ; +} +//------------------------------------------------------------------------------ +void BMessageFilter::_ReservedMessageFilter2() +{ + ; +} +//------------------------------------------------------------------------------ +void BMessageFilter::SetLooper(BLooper* owner) +{ + // TODO: implement locking? + fLooper = owner; +} +//------------------------------------------------------------------------------ +filter_hook BMessageFilter::FilterFunction() const +{ + return fFilterFunction; +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/kits/app/MessageQueue.cpp b/src/kits/app/MessageQueue.cpp new file mode 100644 index 0000000000..19642eadbc --- /dev/null +++ b/src/kits/app/MessageQueue.cpp @@ -0,0 +1,434 @@ +// +// $Id: MessageQueue.cpp,v 1.1 2002/07/09 12:24:49 ejakowatz Exp $ +// +// This file contains the implementation of the BMessageQueue class +// for the OpenBeOS project. +// + + +#include "MessageQueue.h" +#include "Autolock.h" +#include "Message.h" + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS { +#endif + + +/* + * Method: BMessageQueue::BMessageQueue() + * Descr: This method is the only constructor for a BMessageQueue. Once the + * constructor completes, the BMessageQueue is created with no BMessages + * in it. + * + */ +BMessageQueue::BMessageQueue() : + fTheQueue(NULL), fQueueTail(NULL), fMessageCount(0) +{ +} + + +/* + * Method: BMessageQueue::~BMessageQueue() + * Descr: This is the desctructor for the BMessageQueue. It iterates over + * any messages left on the queue and deletes them. + * + * The implementation is careful not to release the lock when the + * BMessageQueue is deconstructed. If the lock is released, it is + * possible another thread will start an AddMessage() operation before + * the BLocker is deleted. The safe thing to do is not to unlock the + * BLocker from the destructor once it is acquired. That way, any thread + * waiting to do a AddMessage() will fail to acquire the lock since the + * BLocker will be deleted before they can acquire it. + * + */ +BMessageQueue::~BMessageQueue() +{ + if (fLocker.Lock()) { + BMessage *theMessage = fTheQueue; + while (theMessage != NULL) { + BMessage *messageToDelete = theMessage; + theMessage = theMessage->link; + delete messageToDelete; + } + } +} + + +/* + * Method: BMessageQueue::AddMessage() + * Descr: This method adds a BMessage to the queue. It makes a couple of + * assumptions: + * - The BMessage was allocated on the heap with new. Since the + * destructor delete's BMessages left on the queue, this must be + * true. The same assumption is made with Be's implementation. + * - The BMessage is not already on this or any other BMessageQueue. + * If it is, the queue it is already on will be corrupted. Be's + * implementation makes this assumption also and does corrupt + * BMessageQueues where this is violated. + * + */ +void +BMessageQueue::AddMessage(BMessage *message) +{ + if (message == NULL) { + return; + } + + // The Be implementation does not seem to check that the lock acquisition + // was successful. This will specifically cause problems when the + // message queue is deleted. On delete, any thread waiting for the lock + // will be notified that the lock failed. Be's implementation, because + // they do not check proceeds with the operation, potentially corrupting + // memory. This implementation is different, but I can't imagine that + // Be's implementation is worth emulating. + // + BAutolock theAutoLocker(fLocker); + + if (theAutoLocker.IsLocked()) { + + // The message passed in will be the last message on the queue so its + // link member should be set to null. + message->link = NULL; + + // We now have one more BMessage on the queue. + fMessageCount++; + + // If there are no BMessages on the queue. + if (fQueueTail == NULL) { + // Then this message is both the start and the end of the queue. + fTheQueue = message; + fQueueTail = message; + } else { + // If there are already messages on the queue, then the put this + // BMessage at the end. The last BMessage prior to this AddMessage() + // is fQueueTail. The BMessage at fQueueTail needs to point to the + // new last message, the one being added. + fQueueTail->link = message; + + // Now update the fQueueTail to point to this new last message. + fQueueTail = message; + } + } +} + + +/* + * Method: BMessageQueue::RemoveMessage() + * Descr: This method searches the queue for a particular BMessage. If + * it is found, it is removed from the queue. + * + */ +void +BMessageQueue::RemoveMessage(BMessage *message) +{ + if (message == NULL) { + return; + } + + BAutolock theAutoLocker(fLocker); + + // The Be implementation does not seem to check that the lock acquisition + // was successful. This will specifically cause problems when the + // message queue is deleted. On delete, any thread waiting for the lock + // will be notified that the lock failed. Be's implementation, because + // they do not check proceeds with the operation, potentially corrupting + // memory. This implementation is different, but I can't imagine that + // Be's implementation is worth emulating. + // + if (theAutoLocker.IsLocked()) { + + // If the message to be removed is at the front of the queue. + if (fTheQueue == message) { + // We need to special case the handling of removing the first element. + // First, the new front element will be the next one. + fTheQueue = fTheQueue->link; + + // Must decrement the count of elements since the front one is being + // removed. + fMessageCount--; + + // If the new front element is NULL, then that means that the queue + // is now empty. That means that fQueueTail must be set to NULL. + if (fTheQueue == NULL) { + fQueueTail = NULL; + } + + // We have found the message and removed it in this case. We can + // bail out now. The autolocker will take care of releasing the + // lock for us. + return; + } + + // The message to remove is not the first one, so we need to scan the + // queue. Get a message iterator and set it to the first element. + BMessage *messageIter = fTheQueue; + + // While we are not at the end of the list. + while (messageIter != NULL) { + // If the next message after this (ie second, then third etc) is + // the one we are looking for. + if (messageIter->link == message) { + // At this point, this is what we have: + // messageIter - the BMessage in the queue just before the + // match + // messageIter->link - the BMessage which matches message + // message - the same as messageIter->link + // message->link - the element after the match + // + // The next step is to link the BMessage just before the match + // to the one just after the match. This removes the match from + // the queue. + messageIter->link = message->link; + + // One less element on the queue. + fMessageCount--; + + // If there is no BMessage after the match is the + if (message->link == NULL) { + // That means that we just removed the last element from the + // queue. The new last element then must be messageIter. + fQueueTail = messageIter; + } + + // We can return now because we have a match and removed it. + return; + } + + // No match yet, go to the next element in the list. + messageIter = messageIter->link; + } + } +} + + +/* + * Method: BMessageQueue::CountMessages() + * Descr: This method just returns the number of BMessages on the queue. + */ +int32 +BMessageQueue::CountMessages(void) const +{ + return fMessageCount; +} + + +/* + * Method: BMessageQueue::IsEmpty() + * Descr: This method just returns true if there are no BMessages on the queue. + */ +bool +BMessageQueue::IsEmpty(void) const +{ + return (fMessageCount == 0); +} + + +/* + * Method: BMessageQueue::FindMessage() + * Descr: This method searches the queue for the index'th BMessage. The first + * BMessage is at index 0, the second at index 1 etc. The BMessage + * is returned if it is found. If no BMessage exists at that index + * (ie the queue is not that long or the index is invalid) NULL is + * returned. + * + * This method does not lock the BMessageQueue so there is risk that + * the queue could change in the course of the search. Be's + * implementation must do the same, unless they do some funky casting. + * The method is declared const which means it cannot modify the data + * members. Because it cannot modify the data members, it cannot + * acquire a lock. So unless they are casting away the const-ness + * of the this pointer, this member in Be's implementation does no + * locking either. + */ +BMessage * +BMessageQueue::FindMessage(int32 index) const +{ + // If the index is negative or larger than the number of messages on the + // queue. + if ((index < 0) || (index >= fMessageCount)) { + // No match is possible, bail out now. + return NULL; + } + + // Get a message iterator and initialize it to the start of the queue. + BMessage *messageIter = fTheQueue; + + // While this is not the end of the queue. + while (messageIter != NULL) { + // If the index reaches zero, then we have found a match. + if (index == 0) { + // Because this is a match, break out of the while loop so we can + // return the message pointed to messageIter. + break; + } + + // No match yet, decrement the index. We will have a match once index + // reaches zero. + index--; + // Increment the messageIter to the next BMessage on the queue. + messageIter = messageIter->link; + } + + // If no match was found, messageIter will be NULL since that is the only + // way out of the loop. If a match was found, the messageIter will point + // to that match. + return messageIter; +} + + +/* + * Method: BMessageQueue::FindMessage() + * Descr: This method searches the queue for the index'th BMessage that has a + * particular what code. The first BMessage with that what value is at + * index 0, the second at index 1 etc. The BMessage is returned if it + * is found. If no matching BMessage exists at that index NULL is + * returned. + * + * This method does not lock the BMessageQueue so there is risk that + * the queue could change in the course of the search. Be's + * implementation must do the same, unless they do some funky casting. + * The method is declared const which means it cannot modify the data + * members. Because it cannot modify the data members, it cannot + * acquire a lock. So unless they are casting away the const-ness + * of the this pointer, this member in Be's implementation does no + * locking either. + */ +BMessage * +BMessageQueue::FindMessage(uint32 what, + int32 index) const +{ + // If the index is negative or larger than the number of messages on the + // queue. + if ((index < 0) || (index >= fMessageCount)) { + // No match is possible, bail out now. + return NULL; + } + + // Get a message iterator and initialize it to the start of the queue. + BMessage *messageIter = fTheQueue; + + // While this is not the end of the queue. + while (messageIter != NULL) { + // If the messageIter points to a BMessage with the what code we are + // looking for. + if (messageIter->what == what) { + // If the index reaches zero, then we have found a match. + if (index == 0) { + // Because this is a match, break out of the while loop so we can + // return the message pointed to messageIter. + break; + } + // No match yet, decrement the index. We will have a match once index + // reaches zero. + index--; + } + // Increment the messageIter to the next BMessage on the queue. + messageIter = messageIter->link; + } + + // If no match was found, messageIter will be NULL since that is the only + // way out of the loop. If a match was found, the messageIter will point + // to that match. + return messageIter; +} + + +/* + * Method: BMessageQueue::Lock() + * Descr: This member just locks the BMessageQueue so no other thread can acquire + * the lock nor make changes to the queue through members like + * AddMessage(), RemoveMessage(), NextMessage() or ~BMessageQueue(). + */ +bool +BMessageQueue::Lock(void) +{ + return fLocker.Lock(); +} + + +/* + * Method: BMessageQueue::Unlock() + * Descr: This member releases the lock which was acquired by Lock(). + */ +void +BMessageQueue::Unlock(void) +{ + fLocker.Unlock(); +} + + +/* + * Method: BMessageQueue::IsLocked() + * Descr: This member returns whether or not the queue is locked + */ +bool +BMessageQueue::IsLocked(void) +{ + return fLocker.IsLocked(); +} + + +/* + * Method: BMessageQueue::NextMessage() + * Descr: This member removes the first BMessage on the queue and returns + * it to the caller. If the queue is empty, NULL is returned. + */ +BMessage * +BMessageQueue::NextMessage(void) +{ + // By default, we will assume that no BMessage is on the queue. + BMessage *result = NULL; + BAutolock theAutoLocker(fLocker); + + // The Be implementation does not seem to check that the lock acquisition + // was successful. This will specifically cause problems when the + // message queue is deleted. On delete, any thread waiting for the lock + // will be notified that the lock failed. Be's implementation, because + // they do not check proceeds with the operation, potentially corrupting + // memory. This implementation is different, but I can't imagine that + // Be's implementation is worth emulating. + // + if (theAutoLocker.IsLocked()) { + // Store the first BMessage in the queue in result. + result = fTheQueue; + + // If the queue is not empty. + if (fTheQueue != NULL) { + // Decrement the message count since we are removing an element. + fMessageCount--; + // The new front of the list is moved forward thereby removing the + // first element from the queue. + fTheQueue = fTheQueue->link; + // If the queue is empty after removing the front element. + if (fTheQueue == NULL) { + // We need to set the tail of the queue to NULL since the queue + // is now empty. + fQueueTail = NULL; + } + } + } + return result; +} + + +void +BMessageQueue::_ReservedMessageQueue1(void) +{ +} + + +void +BMessageQueue::_ReservedMessageQueue2(void) +{ +} + + +void +BMessageQueue::_ReservedMessageQueue3(void) +{ +} + +#ifdef USE_OPENBEOS_NAMESPACE +} +#endif \ No newline at end of file diff --git a/src/kits/app/Messenger.cpp b/src/kits/app/Messenger.cpp new file mode 100644 index 0000000000..6a277e3a74 --- /dev/null +++ b/src/kits/app/Messenger.cpp @@ -0,0 +1,624 @@ + //------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: Messenger.h +// Author: Ingo Weinhold (bonefish@users.sf.net) +// Description: BMessenger delivers messages to local or remote targets. +//------------------------------------------------------------------------------ + +// debugging +//#define DBG(x) x +#define DBG(x) +#define OUT printf + +// Standard Includes ----------------------------------------------------------- +#include +#include + +// System Includes ------------------------------------------------------------- +#include +#include +#include +#include +#include +#include + +// Project Includes ------------------------------------------------------------ +#include "TokenSpace.h" + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +using BPrivate::gDefaultTokens; + +enum { + NOT_IMPLEMENTED = B_ERROR, +}; + +// _get_object_token_ +/*! Return the token of a BHandler. + + \param handler The BHandler. + \return the token. + + \todo Think about a better place for this function. +*/ +inline +int32 +_get_object_token_(const BHandler* handler) +{ + return handler->fToken; +} + +// _set_message_target_ +/*! \brief Sets the target of a message. + + \param message The message. + \param token The target handler token. + \param preferred Indicates whether to use the looper's preferred handler. +*/ +inline +void +_set_message_target_(BMessage *message, int32 token, bool preferred) +{ + message->fTarget = token; + message->fPreferred = preferred; +} + +// _set_message_reply_ +/*! \brief Sets a message's reply target. + + \param message The message. + \param messenger The reply messenger. +*/ +inline +void +_set_message_reply_(BMessage *message, BMessenger messenger) +{ + message->fReplyTo.port = messenger.fPort; + message->fReplyTo.target = messenger.fHandlerToken; + message->fReplyTo.team = messenger.fTeam; + message->fReplyTo.preferred = messenger.fPreferredTarget; +} + +// constructor +/*! \brief Creates an unitialized BMessenger. +*/ +BMessenger::BMessenger() + : fPort(-1), + fHandlerToken(-1), + fTeam(-1), + fPreferredTarget(false) +{ +} + +// constructor +/*! \brief Creates a BMessenger and initializes it to target the already + running application identified by its signature and/or team ID. + + When only a signature is given, and multiple instances of the application + are running it is undeterminate which one is chosen as the target. In case + only a team ID is passed, the target application is identified uniquely. + If both are supplied, the application identified by the team ID must have + a matching signature, otherwise the initilization fails. + + \param signature The target application's signature. May be \c NULL. + \param team The target application's team ID. May be < 0. + \param result An optional pointer to a pre-allocated status_t into which + the result of the initialization is written. +*/ +BMessenger::BMessenger(const char *signature, team_id team, status_t *result) + : fPort(-1), + fHandlerToken(-1), + fTeam(-1), + fPreferredTarget(false) +{ + InitData(signature, team, result); +} + +// constructor +/*! \brief Creates a BMessenger and initializes it to target the local + BHandler and/or BLooper. + + When a \c NULL handler is supplied, the preferred handler in the given + looper is targeted. If no looper is supplied the looper the given handler + belongs to is used -- that means in particular, that the handler must + already belong to a looper. If both are supplied the handler must actually + belong to looper. + + \param handler The target handler. May be \c NULL. + \param looper The target looper. May be \c NULL. + \param result An optional pointer to a pre-allocated status_t into which + the result of the initialization is written. +*/ +BMessenger::BMessenger(const BHandler *handler, const BLooper *looper, + status_t *result) + : fPort(-1), + fHandlerToken(-1), + fTeam(-1), + fPreferredTarget(false) +{ + status_t error = (handler || looper ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + if (handler) { + // BHandler is given, check/retrieve the looper. + if (looper) { + if (handler->Looper() != looper) + error = B_MISMATCHED_VALUES; + } else { + looper = handler->Looper(); + if (looper == NULL) + error = B_MISMATCHED_VALUES; + } + // set port, token,... + if (error == B_OK) { + fPort = looper->fMsgPort; + fHandlerToken = _get_object_token_(handler); + fPreferredTarget = false; + } + } else { // handler == NULL (=> looper != NULL) + fPort = looper->fMsgPort; + fHandlerToken = false; + fPreferredTarget = true; + } + // get and set the team ID + if (error == B_OK) { + thread_info info; + error = get_thread_info(find_thread(NULL), &info); + if (error == B_OK) + fTeam = info.team; + } + } + if (result) + *result = error; +} + +// copy constructor +/*! \brief Creates a BMessenger and initializes it to have the same target + as the supplied messemger. + + \param from The messenger to be copied. +*/ +BMessenger::BMessenger(const BMessenger &from) + : fPort(from.fPort), + fHandlerToken(from.fHandlerToken), + fTeam(from.fTeam), + fPreferredTarget(from.fPreferredTarget) +{ +} + +// destructor +/*! \brief Frees all resources associated with this object. +*/ +BMessenger::~BMessenger() +{ +} + + +// Target + +// IsTargetLocal +/*! \brief Returns whether or not the messenger's target lives within the team + of the caller. + + \return \c true, if the object is properly initialized and its target + lives within the caller's team, \c false otherwise. +*/ +bool +BMessenger::IsTargetLocal() const +{ + thread_info info; + return (get_thread_info(find_thread(NULL), &info) == B_OK + && fTeam == info.team); +} + +// Target +/*! \brief Returns the handler and looper targeted by the messenger, if the + target is local. + + The handler is returned directly, the looper by reference. If both are + \c NULL, the object is either not properly initialized, the target + objects have been deleted or the target is remote. If only the returned + handler is \c NULL, either the looper's preferred handler is targeted or + the handler has been deleted. + + \param looper A pointer to a pre-allocated BLooper pointer into which + the pointer to the targeted looper is written. + \return The BHandler targeted by the messenger. +*/ +BHandler * +BMessenger::Target(BLooper **looper) const +{ + BHandler *handler = NULL; + if (IsTargetLocal()) { + if (!fPreferredTarget) { + gDefaultTokens.GetToken(fHandlerToken, B_HANDLER_TOKEN, + (void**)&handler); + } + if (looper) { + if (BLooper::sLooperListLock.Lock()) { + *looper = BLooper::LooperForPort(fPort); + BLooper::sLooperListLock.Unlock(); + } else + *looper = NULL; + } + } else if (looper) + *looper = NULL; + return handler; +} + +// LockTarget +/*! \brief Locks the BLooper targeted by the messenger, if the target is local. + + This method is a shorthand for retrieving the targeted looper via + Target() and calling BLooper::Lock() on the looper afterwards. + + \see BLooper::Lock() for details. + + \return \c true, if the looper could be locked sucessfully, \c false, if + the messenger is not properly initialized, the target is remote, + or the targeted looper is invalid. +*/ +bool +BMessenger::LockTarget() const +{ + BLooper *looper = NULL; + Target(&looper); + return (looper && looper->Lock()); +} + +// LockTargetWithTimeout +/*! \brief Locks the BLooper targeted by the messenger, if the target is local. + + This method is a shorthand for retrieving the targeted looper via + Target() and calling BLooper::LockWithTimeout() on the looper afterwards. + + \see BLooper::LockWithTimeout() for details. + + \return + - \c B_OK, if the looper could be locked sucessfully, + - \c B_BAD_VALUE, if the messenger is not properly initialized, + the target is remote, or the targeted looper is invalid, + - other error codes returned by BLooper::LockWithTimeout(). +*/ +status_t +BMessenger::LockTargetWithTimeout(bigtime_t timeout) const +{ + BLooper *looper = NULL; + Target(&looper); + status_t error = (looper ? B_OK : B_BAD_VALUE); + if (error == B_OK) + error = looper->LockWithTimeout(timeout); + return error; +} + + +// Message sending + +// SendMessage +/*! \brief Delivers a BMessage synchronously to the messenger's target. + + The method does not wait for a reply. It is sent asynchronously. + + \param command The what field of the message to deliver. + \param replyTo The handler to which a reply to the message shall be sent. + May be \c NULL. + \return + - \c B_OK: Everything went fine. + - \c B_BAD_PORT_ID: The messenger is not properly initialized or its + target doesn't exist anymore. +*/ +status_t +BMessenger::SendMessage(uint32 command, BHandler *replyTo) const +{ + BMessage message(command); + return SendMessage(&message, replyTo); +} + +// SendMessage +/*! \brief Delivers a BMessage synchronously to the messenger's target. + + A copy of the supplied message is sent and the caller retains ownership + of \a message. + + The method does not wait for a reply. It is sent asynchronously. + + \param message The message to be sent. + \param replyTo The handler to which a reply to the message shall be sent. + May be \c NULL. + \param timeout A timeout for the delivery of the message. + \return + - \c B_OK: Everything went fine. + - \c B_BAD_PORT_ID: The messenger is not properly initialized or its + target doesn't exist anymore. + - \c B_WOULD_BLOCK: A delivery timeout of 0 was supplied and the target + port was full when trying to deliver the message. + - \c B_TIMED_OUT: The timeout expired while trying to deliver the + message. +*/ +status_t +BMessenger::SendMessage(BMessage *message, BHandler *replyTo, + bigtime_t timeout) const +{ +DBG(OUT("BMessenger::SendMessage2(%.4s)\n", (char*)&message->what)); + // TODO: Verify the reply behavior. + status_t error = (message ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + BMessenger replyMessenger(replyTo); + bool wantsReply = replyTo; + error = message->_send_(fPort, fHandlerToken, fPreferredTarget, + timeout, wantsReply, replyMessenger); + } +DBG(OUT("BMessenger::SendMessage2() done: %lx\n", error)); + return error; +} + +// SendMessage +/*! \brief Delivers a BMessage synchronously to the messenger's target. + + A copy of the supplied message is sent and the caller retains ownership + of \a message. + + The method does not wait for a reply. It is sent asynchronously. + + \param message The message to be sent. + \param replyTo A messenger specifying the target for a reply to \a message. + \param timeout A timeout for the delivery of the message. + \return + - \c B_OK: Everything went fine. + - \c B_BAD_PORT_ID: The messenger is not properly initialized or its + target doesn't exist anymore. + - \c B_WOULD_BLOCK: A delivery timeout of 0 was supplied and the target + port was full when trying to deliver the message. + - \c B_TIMED_OUT: The timeout expired while trying to deliver the + message. +*/ +status_t +BMessenger::SendMessage(BMessage *message, BMessenger replyTo, + bigtime_t timeout) const +{ + // TODO: Verify the reply behavior. + status_t error = (message ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + error = message->_send_(fPort, fHandlerToken, fPreferredTarget, + timeout, true, replyTo); + } + return error; +} + +// SendMessage +/*! \brief Delivers a BMessage synchronously to the messenger's target and + waits for a reply. + + The method does wait for a reply. The reply message is copied into + \a reply. If the target doesn't send a reply, the \c what field of + \a reply is set to \c B_NO_REPLY. + + \param command The what field of the message to deliver. + \param reply A pointer to a pre-allocated BMessage into which the reply + message will be copied. + \return + - \c B_OK: Everything went fine. + - \c B_BAD_PORT_ID: The messenger is not properly initialized or its + target doesn't exist anymore. + - \c B_NO_MORE_PORTS: All reply ports are in use. +*/ +status_t +BMessenger::SendMessage(uint32 command, BMessage *reply) const +{ + BMessage message(command); + return SendMessage(&message, reply); +} + +// SendMessage +/*! \brief Delivers a BMessage synchronously to the messenger's target and + waits for a reply. + + A copy of the supplied message is sent and the caller retains ownership + of \a message. + + The method does wait for a reply. The reply message is copied into + \a reply. If the target doesn't send a reply or if a reply timeout occurs, + the \c what field of \a reply is set to \c B_NO_REPLY. + + \param message The message to be sent. + \param reply A pointer to a pre-allocated BMessage into which the reply + message will be copied. + \param deliveryTimeout A timeout for the delivery of the message. + \param replyTimeout A timeout for waiting for the reply. + \return + - \c B_OK: Everything went fine. + - \c B_BAD_PORT_ID: The messenger is not properly initialized or its + target doesn't exist anymore. + - \c B_WOULD_BLOCK: A delivery timeout of 0 was supplied and the target + port was full when trying to deliver the message. + - \c B_TIMED_OUT: The timeout expired while trying to deliver the + message. + - \c B_NO_MORE_PORTS: All reply ports are in use. +*/ +status_t +BMessenger::SendMessage(BMessage *message, BMessage *reply, + bigtime_t deliveryTimeout, bigtime_t replyTimeout) const +{ + status_t error = (message ? B_OK : B_BAD_VALUE); + if (error) { + error = message->send_message(fPort, fTeam, fHandlerToken, + fPreferredTarget, reply, deliveryTimeout, + replyTimeout); + } + return error; +} + + +// Operators and misc + +// = +/*! \brief Makes this BMessenger a copy of the supplied one. + + \param from the messenger to be copied. + \return A reference to this object. +*/ +BMessenger & +BMessenger::operator=(const BMessenger &from) +{ + if (this != &from) { + fPort = from.fPort; + fHandlerToken = from.fHandlerToken; + fTeam = from.fTeam; + fPreferredTarget = from.fPreferredTarget; + } +} + +// == +/*! \brief Returns whether this and the supplied messenger have the same + target. + + \param other The other messenger. + \return \c true, if the messengers have the same target or if both aren't + properly initialzed, \c false otherwise. +*/ +bool +BMessenger::operator==(const BMessenger &other) const +{ + return (fPort == other.fPort + && fHandlerToken == other.fHandlerToken + && fTeam == other.fTeam + && fPreferredTarget == other.fPreferredTarget); +} + +// IsValid +/*! \brief Returns whether the messenger's target looper does still exist. + + It is not checked whether the target handler is also still existing. + + \return \c true, if the messenger's target looper does still exist, + \c false otherwise. +*/ +bool +BMessenger::IsValid() const +{ + port_info info; + return (fPort >= 0 && get_port_info(fPort, &info) == B_OK); +} + +// Team +/*! \brief Returns the ID of the team the messenger's target lives in. + + \return The team of the messenger's target. +*/ +team_id +BMessenger::Team() const +{ + return fTeam; +} + + +//----- Private or reserved ----------------------------------------- + +// constructor +/*! \brief Creates a BMessenger and initializes it to team, target looper port + and handler token. + + If \a preferred is \c true, \a token is ignored. + + \param team The target's team. + \param port The target looper port. + \param token The target handler token. + \param preferred \c true to rather use the looper's preferred handler + instead of the one specified by \a token. +*/ +BMessenger::BMessenger(team_id team, port_id port, int32 token, bool preferred) + : fPort(-1), + fHandlerToken(-1), + fTeam(-1), + fPreferredTarget(false) +{ + fTeam = team; + fPort = port; + fHandlerToken = token; + fPreferredTarget = preferred; +} + +// InitData +/*! \brief Initializes the BMessenger object's data given the signature and/or + team ID of a target. + + When only a signature is given, and multiple instances of the application + are running it is undeterminate which one is chosen as the target. In case + only a team ID is passed, the target application is identified uniquely. + If both are supplied, the application identified by the team ID must have + a matching signature, otherwise the initilization fails. + + \param signature The target application's signature. May be \c NULL. + \param team The target application's team ID. May be < 0. + \param result An optional pointer to a pre-allocated status_t into which + the result of the initialization is written. + + \todo Implement! +*/ +void +BMessenger::InitData(const char *signature, team_id team, status_t *result) +{ + if (result) + *result = NOT_IMPLEMENTED; +} + +// < +/*! \brief Returns whether the first one of two BMessengers is less than the + second one. + + This method defines an order on BMessengers based on their member + variables \c fPort, \c fHandlerToken, \c fTeam and \c fPreferredTarget. +s + \param a The first messenger. + \param b The second messenger. + \return \c true, if \a a is less than \a b, \c false otherwise. +*/ +bool +operator<(const BMessenger &a, const BMessenger &b) +{ + return (a.fPort < b.fPort + || (a.fPort == b.fPort + && a.fHandlerToken < b.fHandlerToken + || (a.fHandlerToken == b.fHandlerToken + && a.fTeam < b.fTeam + || (a.fTeam == b.fTeam + && a.fPreferredTarget == false + && b.fPreferredTarget == true)))); +} + +// != +/*! \brief Returns whether two BMessengers have not the same target. + + \param a The first messenger. + \param b The second messenger. + \return \c false, if \a a and \a b have the same targets or are both not + properly initialized, \c true otherwise. +*/ +bool +operator!=(const BMessenger &a, const BMessenger &b) +{ + return !(a == b); +} + diff --git a/src/kits/app/PortLink.cpp b/src/kits/app/PortLink.cpp new file mode 100644 index 0000000000..8fba724569 --- /dev/null +++ b/src/kits/app/PortLink.cpp @@ -0,0 +1,438 @@ +/* + PortLink.cpp: + A helper class for port-based messaging + +------------------------------------------------------------------------ +How it works: + The class utilizes a fixed-size array of PortLinkData object pointers. When +data is attached, a new PortLinkData object is allocated and a copy of the +passed data is created inside it. When the time comes for the message to be sent, +the data is pieced together into a flattened array and written to the port. +------------------------------------------------------------------------ +Data members: + +*attachments[] - fixed-size array of pointers used to hold the attached data +opcode - message value which is sent along with any data +target - port to which the message is sent when Flush() is called +replyport - port used with synchronous messaging - FlushWithReply() +bufferlength - total bytes taken up by attachments +num_attachments - internal variable which is used to track which "slot" + will be the next one to receive an attachment object +*/ + +#include "PortLink.h" +#include +#include +#include + +//#define PLDEBUG + +// Internal data storage class for holding attached data whilst it is waiting +// to be Flattened() and then Flushed(). There is no need for this to be called outside +// the PortLink class. +class PortLinkData +{ +public: + PortLinkData(void); + ~PortLinkData(void); + bool Set(void *data, size_t size); + char *buffer; + size_t buffersize; +}; + +PortLink::PortLink(port_id port) +{ + // For this class to be useful (and to prevent a lot of init problems) + // we require a port in the constructor + target=port; + + // We start out without any data attached to the port message + num_attachments=0; + opcode=0; + bufferlength=0; + replyport=create_port(30,"PortLink reply port"); +} + +PortLink::~PortLink(void) +{ + // If, for some odd reason, this is deleted with something attached, + // free the memory used by the attachments. We do not flush the queue + // because the port may no longer be valid in cases such as the app + // is in the process of quitting + MakeEmpty(); +} + +void PortLink::SetOpCode(int32 code) +{ + // Sets the message code. This does not change once the message is sent. + // Another call to SetOpCode() is required for such things. + opcode=code; +} + +void PortLink::SetPort(port_id port) +{ + // Sets the target port. While not necessary in most uses, this exists + // mostly to prevent flexibility problems + target=port; +} + +port_id PortLink::GetPort(void) +{ + // Simply returns the port at which the object is pointed. + return target; +} + +void PortLink::Flush(bigtime_t timeout=B_INFINITE_TIMEOUT) +{ + // Fires a message off to the target, complete with attachments. NOTE: + // the recipient must delete all attachments, being the PortLink object assumes + // no responsiblity for the attachments once the message is sent. + int8 *msgbuffer; + int32 size; + + if(num_attachments>0) + { + FlattenData(&msgbuffer,&size); + + // Dump message to port, reset attachments, and clean up + if(timeout!=B_INFINITE_TIMEOUT) + write_port_etc(target,opcode,msgbuffer,size,B_TIMEOUT, timeout); + else + write_port(target,opcode,msgbuffer,size); + MakeEmpty(); + } + else + { + if(timeout!=B_INFINITE_TIMEOUT) + write_port_etc(target,opcode,NULL,0,B_TIMEOUT, timeout); + else + write_port(target,opcode,NULL,0); + } +} + +int8* PortLink::FlushWithReply(int32 *code, status_t *status, ssize_t *buffersize, bigtime_t timeout=B_INFINITE_TIMEOUT) +{ + // Fires a message to the target and then waits for a reply. The target will + // receive a message with the first item being the port_id to reply to. + // NOTE: like Flush(), any attached data must be deleted. + + // Effectively, an Attach() call inlined for changes + + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + { + *status=B_ERROR; + return NULL; + } + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&replyport,sizeof(port_id))) + { + bufferlength+=sizeof(port_id); + } + else + { + delete pld; + *status=B_ERROR; + return NULL; + } + + // Flatten() inlined to make some necessary changes + int8 *buffer=new int8[bufferlength]; + int8 *bufferindex=buffer; + size_t size=0; + + // attach our port_id first + memcpy(bufferindex, pld->buffer, pld->buffersize); + bufferindex += pld->buffersize; + size+=pld->buffersize; + + // attach everything else + for(int i=0;ibuffer, pld->buffersize); + bufferindex += pld->buffersize; + size+=pld->buffersize; + } + + // Flush the thing....FOOSH! :P + write_port(target,opcode,buffer,size); + MakeEmpty(); + delete buffer; + + // Now we wait for the reply + if(timeout==B_INFINITE_TIMEOUT) + { + *buffersize=port_buffer_size(replyport); + if(*buffersize>0) + buffer=(int8*)new int8[*buffersize]; + read_port(replyport,code, buffer, *buffersize); + } + else + { + *buffersize=port_buffer_size_etc(replyport,0,timeout); + if(*buffersize==B_TIMED_OUT) + { + *status=*buffersize; + return NULL; + } + if(*buffersize>0) + buffer=(int8*)new int8[*buffersize]; + read_port(replyport,code, buffer, *buffersize); + } + + // We got this far, so we apparently have some data + *status=B_OK; + return buffer; +} + +void PortLink::Attach(void *data, size_t size) +{ + // This is the member called to attach data to a message. Attachments are + // treated to be in 'Append' mode, tacking on each attached piece of data + // to the end of the list. + + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + if(size==0) + return; + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +// These functions were added for a major convenience in passing common types +// Eventually, I'd like to templatize these, but for now, this'll do + +void PortLink::Attach(int32 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int32); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(int16 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int16); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(int8 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int8); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(float data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(float); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(bool data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(bool); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(BRect data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(BRect); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(BPoint data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(BPoint); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::FlattenData(int8 **buffer,int32 *size) +{ + // This function is where all the magic happens, but it is strictly internal. + // It iterates through each PortLinkData object and copies it to the main buffer + // which ends up, ultimately, being written to the PortLink's target port. + + // skip if there aree no attachments + if(bufferlength<1) + return; + + *buffer=new int8[bufferlength]; + int8 *bufferindex=*buffer; + PortLinkData *pld; + *size=0; + + for(int i=0;ibuffer, pld->buffersize); + bufferindex += pld->buffersize; + *size+=pld->buffersize; + } +} + +void PortLink::MakeEmpty(void) +{ + // Nukes all the attachments currently held by the PortLink class + if(num_attachments!=0) + { + for(int i=0; i0) + free(buffer); +} + +bool PortLinkData::Set(void *data, size_t size) +{ + // Function copies the passed to the internal buffers for storage + if(size>0 && buffersize==0 && data!=NULL) + { + buffer=(char *)malloc(size); + if(buffer==NULL) + return false; + memcpy(buffer, data, size); + buffersize=size; + return true; + } + return false; +} diff --git a/src/kits/app/TokenSpace.cpp b/src/kits/app/TokenSpace.cpp new file mode 100644 index 0000000000..394669d0f5 --- /dev/null +++ b/src/kits/app/TokenSpace.cpp @@ -0,0 +1,126 @@ +//------------------------------------------------------------------------------ +// TokenSpace.cpp +// +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- +#include +#include + +// System Includes ------------------------------------------------------------- +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "TokenSpace.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +namespace BPrivate { + +BTokenSpace gDefaultTokens; + + +//------------------------------------------------------------------------------ +BTokenSpace::BTokenSpace() +{ +} +//------------------------------------------------------------------------------ +BTokenSpace::~BTokenSpace() +{ +} +//------------------------------------------------------------------------------ +int32 BTokenSpace::NewToken(int16 type, void* object, + new_token_callback callback) +{ + BAutolock Lock(fLocker); + TTokenInfo ti = { type, object }; + int32 token; + if (fTokenBin.empty()) + { + token = fTokenCount; + ++fTokenCount; + } + else + { + token = fTokenBin.top(); + fTokenBin.pop(); + } + + fTokenMap[token] = ti; + + if (callback) + { + callback(type, object); + } + + return token; +} +//------------------------------------------------------------------------------ +bool BTokenSpace::RemoveToken(int32 token, remove_token_callback callback) +{ + BAutolock Lock(fLocker); + TTokenMap::iterator iter = fTokenMap.find(token); + if (iter == fTokenMap.end()) + { + return false; + } + + if (callback) + { + callback(iter->second.type, iter->second.object); + } + + fTokenMap.erase(iter); + fTokenBin.push(token); + + return true; +} +//------------------------------------------------------------------------------ +bool BTokenSpace::CheckToken(int32 token, int16 type) const +{ + BAutolock Locker(const_cast(fLocker)); + TTokenMap::const_iterator iter = fTokenMap.find(token); + if (iter != fTokenMap.end() && iter->second.type == type) + { + return true; + } + + return false; +} +//------------------------------------------------------------------------------ +status_t BTokenSpace::GetToken(int32 token, int16 type, void** object, + get_token_callback callback) const +{ + BAutolock Locker(const_cast(fLocker)); + TTokenMap::const_iterator iter = fTokenMap.find(token); + if (iter == fTokenMap.end()) + { + *object = NULL; + return B_ERROR; + } + + if (callback && !callback(iter->second.type, iter->second.object)) + { + *object = NULL; + return B_ERROR; + } + + *object = iter->second.object; + + return B_OK; +} +//------------------------------------------------------------------------------ + +} // namespace BPrivate + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/kits/app/app.src b/src/kits/app/app.src new file mode 100644 index 0000000000..834d772fe0 --- /dev/null +++ b/src/kits/app/app.src @@ -0,0 +1,10 @@ +APP_KIT_SOURCE = + Cursor.cpp + Handler.cpp + Invoker.cpp + Looper.cpp + MessageFilter.cpp + MessageQueue.cpp + Messenger.cpp + TokenSpace.cpp +; diff --git a/src/kits/interface/Alert.cpp b/src/kits/interface/Alert.cpp new file mode 100644 index 0000000000..83f86db777 --- /dev/null +++ b/src/kits/interface/Alert.cpp @@ -0,0 +1,824 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: Alert.cpp +// Author: Erik Jaesler (erik@cgsoftware.com) +// Description: BAlert displays a modal alert window. +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- +#include + +// System Includes ------------------------------------------------------------- +#include +#include +#include +#include + +#include +#include +#include +// TODO: Fix +// This is hacked in because something in Accelerant.h or SupportDefs.h is lame! +typedef unsigned int uint; +#include +#include +#include + +#include +#include +#include +#include + +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- +#define DEFAULT_RECT BRect(100, 100, 100, 100) +#define max(LHS, RHS) ((LHS) > (RHS) ? (LHS) : (RHS)) + +// Globals --------------------------------------------------------------------- +const unsigned int kAlertButtonMsg = 'ALTB'; +const int kSemTimeOut = 50000; + +const int kButtonBottomOffset = 9; +const int kDefButtonBottomOffset = 6; +const int kButtonRightOffset = 6; +const int kButtonSpaceOffset = 6; +const int kButtonOffsetSpaceOffset = 26; +const int kButtonLeftOffset = 62; +const int kButtonUsualWidth = 75; + +const int kWindowIconOffset = 27; +const int kWindowMinWidth = 310; +const int kWindowMinOffset = 12; +const int kWindowOffsetMinWidth = 335; + +const int kIconStripeWidth = 30; + +const int kTextLeftOffset = 10; +const int kTextIconOffset = kWindowIconOffset + kIconStripeWidth - 2; +const int kTextTopOffset = 6; +const int kTextRightOffset = 10; +const int kTextBottomOffset = 45; + +//------------------------------------------------------------------------------ +class TAlertView : public BView +{ + public: + TAlertView(BRect frame); + TAlertView(BMessage* archive); + ~TAlertView(); + + static TAlertView* Instantiate(BMessage* archive); + status_t Archive(BMessage* archive, bool deep = true); + + virtual void Draw(BRect updateRect); + + // These functions (or something analogous) are missing from libbe.so's + // dump. I can only assume that the bitmap is a public var in the + // original implementation -- or BAlert is a friend of TAlertView. + // Neither one is necessary, since I can just add these. + void SetBitmap(BBitmap* Icon) { fIconBitmap = Icon; } + BBitmap* Bitmap() { return fIconBitmap; } + + private: + BBitmap* fIconBitmap; +}; +//------------------------------------------------------------------------------ +// I'm making a guess based on the name and TextEntryAlert's implementation that +// this is a BMessageFilter. I'm not sure, but I think I actually prefer how +// TextEntryAlert does it, but there are clearly no message filtering functions +// on BAlert so here we go. +class _BAlertFilter_ : public BMessageFilter +{ + public: + _BAlertFilter_(BAlert* Alert); + ~_BAlertFilter_(); + + virtual filter_result Filter(BMessage* msg, BHandler** target); + + private: + BAlert* fAlert; +}; +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +BAlert::BAlert(const char *title, const char *text, const char *button1, + const char *button2, const char *button3, button_width width, + alert_type type) + : BWindow(DEFAULT_RECT, title, B_MODAL_WINDOW, + B_NOT_CLOSABLE | B_NOT_RESIZABLE) +{ + InitObject(text, button1, button2, button3, width, B_EVEN_SPACING, type); +} +//------------------------------------------------------------------------------ +BAlert::BAlert(const char *title, const char *text, const char *button1, + const char *button2, const char *button3, button_width width, + button_spacing spacing, alert_type type) + : BWindow(DEFAULT_RECT, title, B_MODAL_WINDOW, + B_NOT_CLOSABLE | B_NOT_RESIZABLE) +{ + InitObject(text, button1, button2, button3, width, spacing, type); +} +//------------------------------------------------------------------------------ +BAlert::~BAlert() +{ + // Probably not necessary, but it makes me feel better. + if (fAlertSem >= B_OK) + { + delete_sem(fAlertSem); + } +} +//------------------------------------------------------------------------------ +BAlert::BAlert(BMessage* data) + : BWindow(data) +{ + BAutolock Autolock(this); + if (Autolock.IsLocked()) + { + fInvoker = NULL; + fAlertSem = -1; + fAlertVal = -1; + + fTextView = (BTextView*)FindView("_tv_"); + + fButtons[0] = (BButton*)FindView("_b0_"); + fButtons[1] = (BButton*)FindView("_b1_"); + fButtons[2] = (BButton*)FindView("_b2_"); + + if (fButtons[2]) + SetDefaultButton(fButtons[2]); + else if (fButtons[1]) + SetDefaultButton(fButtons[1]); + else if (fButtons[0]) + SetDefaultButton(fButtons[0]); + + TAlertView* Master = (TAlertView*)FindView("_master_"); + if (Master) + { + Master->SetBitmap(InitIcon()); + } + + // Get keys + char key; + for (int32 i = 0; i < 3; ++i) + { + if (data->FindInt8("_but_key", i, (int8*)&key) == B_OK) + fKeys[i] = key; + } + + int32 temp; + // Get alert type + if (data->FindInt32("_atype", &temp) == B_OK) + fMsgType = (alert_type)temp; + + // Get button width + if (data->FindInt32("_but_width", &temp) == B_OK) + fButtonWidth = (button_width)temp; + + AddCommonFilter(new _BAlertFilter_(this)); + } +} +//------------------------------------------------------------------------------ +BArchivable* BAlert::Instantiate(BMessage* data) +{ + if (!validate_instantiation(data, "BAlert")) + { + return NULL; + } + + return new BAlert(data); +} +//------------------------------------------------------------------------------ +status_t BAlert::Archive(BMessage* data, bool deep) const +{ + BWindow::Archive(data, deep); + + // Stow the text + data->AddString("_text", fTextView->Text()); + + // Stow the alert type + data->AddInt32("_atype", fMsgType); + + // Stow the button width + data->AddInt32("_but_width", fButtonWidth); + + // Stow the shortcut keys + if (fKeys[0] || fKeys[1] || fKeys[2]) + { + // If we have any to save, we must save something for everyone so it + // doesn't get confusing on the unarchive. + data->AddInt8("_but_key", fKeys[0]); + data->AddInt8("_but_key", fKeys[1]); + data->AddInt8("_but_key", fKeys[2]); + } + + return B_OK; +} +//------------------------------------------------------------------------------ +void BAlert::SetShortcut(int32 index, char key) +{ + if (index >= 0 && index < 3) + fKeys[index] = key; +} +//------------------------------------------------------------------------------ +char BAlert::Shortcut(int32 index) const +{ + if (index >= 0 && index < 3) + return fKeys[index]; + + return 0; +} +//------------------------------------------------------------------------------ +int32 BAlert::Go() +{ + // TODO: Add sound? + fAlertSem = create_sem(0, "AlertSem"); + if (fAlertSem < B_OK) + { + Quit(); + return -1; + } + + // Get the originating window, if it exists + BWindow* Window = + dynamic_cast(BLooper::LooperForThread(find_thread(NULL))); + + Show(); + + // Heavily modified from TextEntryAlert code; the original didn't let the + // blocked window ever draw. + if (Window) + { + status_t err; + for (;;) + { + do + { + err = acquire_sem_etc(fAlertSem, 1, B_RELATIVE_TIMEOUT, + kSemTimeOut); + // We've (probably) had our time slice taken away from us + } while (err == B_INTERRUPTED); + if (err == B_BAD_SEM_ID) + { + // Semaphore was finally nuked in MessageReceived + break; + } + Window->UpdateIfNeeded(); + } + } + else + { + // No window to update, so just hang out until we're done. + while (acquire_sem(fAlertSem) == B_INTERRUPTED) + { + ; + } + } + + // Have to cache the value since we delete on Quit() + int32 value = fAlertVal; + if (Lock()) + { + Quit(); + } + + return value; +} +//------------------------------------------------------------------------------ +status_t BAlert::Go(BInvoker* invoker) +{ + // TODO: Add sound? + // It would be cool if we triggered a system sound depending on the type of + // alert. + fInvoker = invoker; + Show(); + return B_OK; +} +//------------------------------------------------------------------------------ +void BAlert::MessageReceived(BMessage* msg) +{ + if (msg->what == kAlertButtonMsg) + { + int32 which; + if (msg->FindInt32("which", &which) == B_OK) + { + if (fAlertSem < B_OK) + { + // Semaphore hasn't been created; we're running asynchronous + if (fInvoker) + { + BMessage* out = fInvoker->Message(); + if (out && (out->AddInt32("which", which) == B_OK || + out->ReplaceInt32("which", which) == B_OK)) + { + fInvoker->Invoke(); + } + } + } + else + { + // Created semaphore means were running synchronously + fAlertVal = which; + + // TextAlertVar does release_sem() below, and then sets the + // member var. That doesn't make much sense to me, since we + // want to be able to clean up at some point. Better to just + // nuke the semaphore now; we don't need it any more and this + // lets synchronous Go() continue just as well. + delete_sem(fAlertSem); + fAlertSem = -1; + } + } + } +} +//------------------------------------------------------------------------------ +void BAlert::FrameResized(float new_width, float new_height) +{ + // Nothing in documentation; will have to test + // TODO: Implement? + BWindow::FrameResized(new_width, new_height); +} +//------------------------------------------------------------------------------ +BButton* BAlert::ButtonAt(int32 index) const +{ + BButton* Button = NULL; + if (index >= 0 && index < 3) + Button = fButtons[index]; + + return Button; +} +//------------------------------------------------------------------------------ +BTextView* BAlert::TextView() const +{ + return fTextView; +} +//------------------------------------------------------------------------------ +BHandler* BAlert::ResolveSpecifier(BMessage* msg, int32 index, + BMessage* specifier, int32 form, + const char* property) +{ + // Nothing in documentation; will have to test + // TODO: Implement? + return BWindow::ResolveSpecifier(msg, index, specifier, form, property); +} +//------------------------------------------------------------------------------ +status_t BAlert::GetSupportedSuites(BMessage* data) +{ + // Nothing in documentation; will have to test + // TODO: Implement? + return BWindow::GetSupportedSuites(data); +} +//------------------------------------------------------------------------------ +void BAlert::DispatchMessage(BMessage* msg, BHandler* handler) +{ + // Nothing in documentation; will have to test + // TODO: Implement? + BWindow::DispatchMessage(msg, handler); +} +//------------------------------------------------------------------------------ +void BAlert::Quit() +{ + // Nothing in documentation; will have to test + // TODO: Implement? + BWindow::Quit(); +} +//------------------------------------------------------------------------------ +bool BAlert::QuitRequested() +{ + // Nothing in documentation; will have to test + // TODO: Implement? + return BWindow::QuitRequested(); +} +//------------------------------------------------------------------------------ +BPoint BAlert::AlertPosition(float width, float height) +{ + BPoint result(100, 100); + + BWindow* Window = + dynamic_cast(BLooper::LooperForThread(find_thread(NULL))); + + BScreen Screen(Window); + if (!Screen.IsValid()) + { + // ... then we're in deep trouble + // But what to say about it? + // debugger(???); + } + + BRect screenRect = Screen.Frame(); + + // Horizontally, we're smack in the middle + result.x = (screenRect.Width() / 2.0) - (width / 2.0); + + // This is probably sooo wrong, but it looks right on 1024 x 768 + result.y = (screenRect.Height() / 4.0) - ceil(height / 3.0); + + return result; +} +//------------------------------------------------------------------------------ +status_t BAlert::Perform(perform_code d, void* arg) +{ + return BWindow::Perform(d, arg); +} +//------------------------------------------------------------------------------ +void BAlert::_ReservedAlert1() +{ + ; +} +//------------------------------------------------------------------------------ +void BAlert::_ReservedAlert2() +{ + ; +} +//------------------------------------------------------------------------------ +void BAlert::_ReservedAlert3() +{ + ; +} +//------------------------------------------------------------------------------ +void BAlert::InitObject(const char* text, const char* button0, + const char* button1, const char* button2, + button_width width, button_spacing spacing, + alert_type type) +{ + BAutolock Autolock(this); + if (Autolock.IsLocked()) + { + fInvoker = NULL; + fAlertSem = -1; + fAlertVal = -1; + fButtons[0] = fButtons[1] = fButtons[2] = NULL; + fTextView = NULL; + fKeys[0] = fKeys[1] = fKeys[2] = 0; + fMsgType = type; + fButtonWidth = width; + + // Set up the "_master_" view + TAlertView* MasterView = new TAlertView(Bounds()); + MasterView->SetBitmap(InitIcon()); + AddChild(MasterView); + + // Set up the buttons + int buttonCount = 0; + + // Have to have at least one button + if (button0 == NULL) + { + debugger("BAlert's must have at least one button."); + button0 = ""; + } + + BMessage ProtoMsg(kAlertButtonMsg); + ProtoMsg.AddInt32("which", 0); + fButtons[0] = new BButton(BRect(0, 0, 0, 0), "_b0_", button0, + new BMessage(ProtoMsg), + B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + ++buttonCount; + + if (button1) + { + ProtoMsg.ReplaceInt32("which", 1); + fButtons[buttonCount] = new BButton(BRect(0, 0, 0, 0), "_b1_", button1, + new BMessage(ProtoMsg), + B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + ++buttonCount; + } + + if (button2) + { + ProtoMsg.ReplaceInt32("which", 2); + fButtons[buttonCount] = new BButton(BRect(0, 0, 0, 0), "_b2_", button2, + new BMessage(ProtoMsg), + B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + ++buttonCount; + } + + SetDefaultButton(fButtons[buttonCount - 1]); + + float buttonWidth = 0; + float buttonHeight = 0; + for (int i = 0; i < buttonCount; ++i) + { + float temp; + fButtons[i]->GetPreferredSize(&temp, &buttonHeight); + buttonWidth = max(buttonWidth, temp); + } + + // Add first, because the buttons will ResizeToPreferred() + // in AttachedToWindow() + for (int i = 0; i < buttonCount; ++i) + { + MasterView->AddChild(fButtons[i]); + } + + for (int i = buttonCount - 1; i >= 0; --i) + { + switch (fButtonWidth) + { + case B_WIDTH_FROM_WIDEST: + fButtons[i]->ResizeTo(buttonWidth, buttonHeight); + break; + + case B_WIDTH_FROM_LABEL: + fButtons[i]->ResizeToPreferred(); + break; + + default: // B_WIDTH_AS_USUAL + fButtons[i]->GetPreferredSize(&buttonWidth, &buttonHeight); + buttonWidth = max(buttonWidth, kButtonUsualWidth); + fButtons[i]->ResizeTo(buttonWidth, buttonHeight); + break; + } + + float buttonX; + float buttonY; + float temp; + + fButtons[i]->GetPreferredSize(&temp, &buttonHeight); + buttonY = Bounds().bottom - buttonHeight; + + if (i == buttonCount - 1) // the right-most button + { + buttonX = Bounds().right - fButtons[i]->Frame().Width() - + kButtonRightOffset; + buttonY -= kDefButtonBottomOffset; + } + else + { + buttonX = fButtons[i + 1]->Frame().left - + fButtons[i]->Frame().Width() - + kButtonSpaceOffset; + + if (i == 0) + { + if (spacing == B_OFFSET_SPACING) + { + buttonX -= kButtonOffsetSpaceOffset; + } + else if (buttonCount == 3) + { + buttonX -= 3; + } + } + buttonY -= kButtonBottomOffset; + } + + fButtons[i]->MoveTo(buttonX, buttonY); + } + + + // Resize the window, if necessary + float totalWidth = kButtonRightOffset; + totalWidth += fButtons[buttonCount - 1]->Frame().right - + fButtons[0]->Frame().left; + if (MasterView->Bitmap()) + { + totalWidth += kIconStripeWidth + kWindowIconOffset; + } + else + { + totalWidth += kWindowMinOffset; + } + + if (spacing == B_OFFSET_SPACING) + { + totalWidth = max(kWindowOffsetMinWidth, totalWidth); + } + else + { + totalWidth += 5; + totalWidth = max(kWindowMinWidth, totalWidth); + } + ResizeTo(totalWidth, Bounds().Height()); + + // Set up the text view + BRect TextViewRect(kTextLeftOffset, kTextTopOffset, + Bounds().right - kTextRightOffset, + Bounds().bottom - kTextBottomOffset); + if (MasterView->Bitmap()) + { + TextViewRect.left = kTextIconOffset; + } + + fTextView = new BTextView(TextViewRect, "_tv_", + TextViewRect, + B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW); + fTextView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + fTextView->SetText(text, strlen(text)); + fTextView->MakeEditable(false); + fTextView->MakeSelectable(false); + fTextView->SetWordWrap(true); + + // Now resize the window vertically so that all the text is visible + float textHeight = fTextView->TextHeight(0, fTextView->CountLines()); + TextViewRect.OffsetTo(0, 0); + textHeight -= TextViewRect.Height(); + ResizeBy(0, textHeight); + fTextView->ResizeBy(0, textHeight); + TextViewRect.bottom += textHeight; + fTextView->SetTextRect(TextViewRect); + + MasterView->AddChild(fTextView); + + AddCommonFilter(new _BAlertFilter_(this)); + + MoveTo(AlertPosition(Frame().Width(), Frame().Height())); + } +} +//------------------------------------------------------------------------------ +BBitmap* BAlert::InitIcon() +{ + // After a bit of a search, I found the icons in app_server. =P + BBitmap* Icon = NULL; + BPath Path; + if (find_directory(B_BEOS_SERVERS_DIRECTORY, &Path) == B_OK) + { + Path.Append("app_server"); + BFile File; + if (File.SetTo(Path.Path(), B_READ_ONLY) == B_OK) + { + BResources Resources; + if (Resources.SetTo(&File) == B_OK) + { + // Which icon are we trying to load? + const char* iconName = ""; // Don't want any seg faults + switch (fMsgType) + { + case B_INFO_ALERT: + iconName = "info"; + break; + + case B_IDEA_ALERT: + iconName = "idea"; + break; + + case B_WARNING_ALERT: + iconName = "warn"; + break; + + case B_STOP_ALERT: + iconName = "stop"; + break; + + default: + // Alert type is either invalid or B_EMPTY_ALERT; + // either way, we're not going to load an icon + return Icon; + } + + // Load the raw icon data + size_t size; + const void* rawIcon = + Resources.LoadResource('ICON', iconName, &size); + + if (rawIcon) + { + // Now build the bitmap + Icon = new BBitmap(BRect(0, 0, 31, 31), B_CMAP8); + Icon->SetBits(rawIcon, size, 0, B_CMAP8); + } + } + } + } + + if (!Icon) + { + // If there's no icon, it's an empty alert indeed. + fMsgType = B_EMPTY_ALERT; + } + + return Icon; +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// #pragma mark - +// #pragma mark TAlertView +// #pragma mark - +//------------------------------------------------------------------------------ +TAlertView::TAlertView(BRect frame) + : BView(frame, "TAlertView", B_FOLLOW_ALL_SIDES, B_WILL_DRAW), + fIconBitmap(NULL) +{ + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); +} +//------------------------------------------------------------------------------ +TAlertView::TAlertView(BMessage* archive) + : BView(archive), + fIconBitmap(NULL) +{ +} +//------------------------------------------------------------------------------ +TAlertView::~TAlertView() +{ + if (fIconBitmap) + { + delete fIconBitmap; + } +} +//------------------------------------------------------------------------------ +TAlertView* TAlertView::Instantiate(BMessage* archive) +{ + if (!validate_instantiation(archive, "TAlertView")) + { + return NULL; + } + + return new TAlertView(archive); +} +//------------------------------------------------------------------------------ +status_t TAlertView::Archive(BMessage* archive, bool deep) +{ + return BView::Archive(archive, deep); +} +//------------------------------------------------------------------------------ +void TAlertView::Draw(BRect updateRect) +{ + // Here's the fun stuff + if (fIconBitmap) + { + BRect StripeRect = Bounds(); + StripeRect.right = kIconStripeWidth; + SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT)); + FillRect(StripeRect); + + SetDrawingMode(B_OP_OVER); + DrawBitmapAsync(fIconBitmap, BPoint(18, 6)); + SetDrawingMode(B_OP_COPY); + } +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// #pragma mark - +// #pragma mark _BAlertFilter_ +// #pragma mark - +//------------------------------------------------------------------------------ +_BAlertFilter_::_BAlertFilter_(BAlert* Alert) + : BMessageFilter(B_KEY_DOWN), + fAlert(Alert) +{ +} +//------------------------------------------------------------------------------ +_BAlertFilter_::~_BAlertFilter_() +{ + ; +} +//------------------------------------------------------------------------------ +filter_result _BAlertFilter_::Filter(BMessage* msg, BHandler** target) +{ + if (msg->what == B_KEY_DOWN) + { + char byte; + if (msg->FindInt8("byte", (int8*)&byte) == B_OK) + { + for (int i = 0; i < 3; ++i) + { + if (byte == fAlert->Shortcut(i) && fAlert->ButtonAt(i)) + { + char space = ' '; + fAlert->ButtonAt(i)->KeyDown(&space, 1); + + return B_SKIP_MESSAGE; + } + } + } + } + + return B_DISPATCH_MESSAGE; +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/kits/interface/Box.cpp b/src/kits/interface/Box.cpp new file mode 100644 index 0000000000..5fe1625de0 --- /dev/null +++ b/src/kits/interface/Box.cpp @@ -0,0 +1,363 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: Box.cpp +// Author: Marc Flerackers (mflerackers@androme.be) +// Description: BBox objects group views together and draw a border +// around them. +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- +#include + +// System Includes ------------------------------------------------------------- +#include +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +BBox::BBox(BRect frame, const char *name, uint32 resizingMode, uint32 flags, + border_style border) + : BView(frame, name, resizingMode, flags), + fLabel(NULL), + fStyle(border), + fLabelView(NULL) +{ + fBounds = Bounds(); + + SetFont(be_bold_font); + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); +} +//------------------------------------------------------------------------------ +BBox::~BBox() +{ + if (fLabel) + delete fLabel; +} +//------------------------------------------------------------------------------ +BBox::BBox(BMessage *archive) + : BView(archive) +{ + fBounds = Bounds(); + fLabelView = NULL; + + const char *string; + + if (archive->FindString("_label", &string) != B_OK) + fLabel = NULL; + else + SetLabel(string); + + int32 anInt32; + + if (archive->FindInt32("_style", &anInt32) != B_OK) + fStyle = B_FANCY_BORDER; + else + fStyle = (border_style)anInt32; +} +//------------------------------------------------------------------------------ +BArchivable *BBox::Instantiate(BMessage *archive) +{ + if ( validate_instantiation ( archive, "BBox" ) ) + return new BBox ( archive ); + else + return NULL; +} +//------------------------------------------------------------------------------ +status_t BBox::Archive(BMessage *archive, bool deep) const +{ + status_t err = BView::Archive(archive, deep); + + if (err != B_OK) + return err; + + if (fLabel) + err = archive->AddString("_label",fLabel); + + if (err != B_OK) + return err; + + if (fStyle != B_FANCY_BORDER) + err = archive->AddInt32("_style", fStyle); + + return err; +} +//------------------------------------------------------------------------------ +void BBox::SetBorder(border_style border) +{ + fStyle = border; + + Invalidate(); +} +//------------------------------------------------------------------------------ +border_style BBox::Border() const +{ + return fStyle; +} +//------------------------------------------------------------------------------ +void BBox::SetLabel(const char *string) +{ + if (fLabel) + delete fLabel; + + fLabel = strdup(string); + + // Update fBounds + fBounds = Bounds(); + + if (fLabel) + { + font_height fh; + GetFontHeight(&fh); + + fBounds.top = (float)ceil((fh.ascent + fh.descent) / 2.0f); + } + + Invalidate(); +} +//------------------------------------------------------------------------------ +status_t BBox::SetLabel(BView *viewLabel) +{ + if (viewLabel) + { + if (fLabelView) + RemoveChild(fLabelView); + + fLabelView = viewLabel; + AddChild(fLabelView); + + if(fLabel) + { + delete fLabel; + fLabel = NULL; + } + } + + // Update fBounds + fBounds = Bounds(); + + if (fLabelView) + fBounds.top = (float)ceil(fLabelView->Frame().Height() / 2.0f); + + Invalidate(); + + return B_OK; +} +//------------------------------------------------------------------------------ +const char *BBox::Label() const +{ + return fLabel; +} +//------------------------------------------------------------------------------ +BView *BBox::LabelView() const +{ + return fLabelView; +} +//------------------------------------------------------------------------------ +void BBox::Draw(BRect updateRect) +{ + switch (fStyle) + { + case B_FANCY_BORDER: + DrawFancy(); + break; + + case B_PLAIN_BORDER: + DrawPlain(); + break; + + default: + break; + } + + if (fLabel) + { + font_height fh; + GetFontHeight(&fh); + + SetHighColor(ViewColor()); + + FillRect(BRect(6.0f, 1.0f, 12.0f + StringWidth(fLabel), + (float)ceil(fh.ascent + fh.descent))/*, B_SOLID_LOW*/); + + SetHighColor(0, 0, 0); + DrawString(fLabel, BPoint(10.0f, (float)ceil(fh.ascent - fh.descent) + 1.0f )); + } +} +//------------------------------------------------------------------------------ +void BBox::AttachedToWindow() +{ + if (Parent()) + { + SetViewColor(Parent()->ViewColor()); + SetLowColor(Parent()->ViewColor()); + } +} +//------------------------------------------------------------------------------ +void BBox::DetachedFromWindow() +{ + BView::DetachedFromWindow(); +} +//------------------------------------------------------------------------------ +void BBox::AllAttached() +{ + BView::AllAttached(); +} +//------------------------------------------------------------------------------ +void BBox::AllDetached() +{ + BView::AllDetached(); +} +//------------------------------------------------------------------------------ +void BBox::FrameResized(float width, float height) +{ + fBounds.right = Bounds().right; + fBounds.bottom = Bounds().bottom; +} +//------------------------------------------------------------------------------ +void BBox::MessageReceived(BMessage *message) +{ + BView::MessageReceived(message); +} +//------------------------------------------------------------------------------ +void BBox::MouseDown(BPoint point) +{ + BView::MouseDown(point); +} +//------------------------------------------------------------------------------ +void BBox::MouseUp(BPoint point) +{ + BView::MouseUp(point); +} +//------------------------------------------------------------------------------ +void BBox::WindowActivated(bool active) +{ + BView::WindowActivated(active); +} +//------------------------------------------------------------------------------ +void BBox::MouseMoved(BPoint point, uint32 transit, const BMessage *message) +{ + BView::MouseMoved(point, transit, message); +} +//------------------------------------------------------------------------------ +void BBox::FrameMoved(BPoint newLocation) +{ + BView::FrameMoved(newLocation); +} +//------------------------------------------------------------------------------ +BHandler *BBox::ResolveSpecifier(BMessage *message, int32 index, + BMessage *specifier, int32 what, + const char *property) +{ + return BView::ResolveSpecifier(message, index, specifier, what, property); +} +//------------------------------------------------------------------------------ +void BBox::ResizeToPreferred() +{ + BView::ResizeToPreferred(); +} +//------------------------------------------------------------------------------ +void BBox::GetPreferredSize(float *width, float *height) +{ + BRect rect(0,0,99,99); + + if (Parent()) + { + rect = Parent()->Bounds(); + rect.InsetBy(10,10); + } + + *width = rect.Width(); + *height = rect.Height(); +} +//------------------------------------------------------------------------------ +void BBox::MakeFocus(bool focused) +{ + BView::MakeFocus(focused); +} +//------------------------------------------------------------------------------ +status_t BBox::GetSupportedSuites(BMessage *message) +{ + return BView::GetSupportedSuites(message); +} +//------------------------------------------------------------------------------ +status_t BBox::Perform(perform_code d, void *arg) +{ + return B_ERROR; +} +//------------------------------------------------------------------------------ +void BBox::_ReservedBox1() {} +void BBox::_ReservedBox2() {} +//------------------------------------------------------------------------------ +BBox &BBox::operator=(const BBox &) +{ + return *this; +} +//------------------------------------------------------------------------------ +void BBox::InitObject(BMessage *data) +{ +} +//------------------------------------------------------------------------------ +void BBox::DrawPlain() +{ + BRect rect = fBounds; + + rect.top--; + SetHighColor(tint_color(ViewColor(), B_LIGHTEN_MAX_TINT)); + StrokeLine(BPoint(rect.left, rect.bottom), BPoint(rect.left, rect.top)); + StrokeLine(BPoint(rect.left+1.0f, rect.top), BPoint(rect.right, rect.top)); + SetHighColor(tint_color(ViewColor(), B_DARKEN_3_TINT)); + StrokeLine(BPoint(rect.left+1.0f, rect.bottom), BPoint(rect.right, rect.bottom)); + StrokeLine(BPoint(rect.right, rect.bottom), BPoint(rect.right, rect.top+1.0f)); +} +//------------------------------------------------------------------------------ +void BBox::DrawFancy() +{ + BRect rect = fBounds; + + SetHighColor(tint_color(ViewColor(), B_LIGHTEN_MAX_TINT)); + rect.left++; + rect.top++; + StrokeRect(rect); + SetHighColor(tint_color(ViewColor(), B_DARKEN_3_TINT)); + rect.OffsetBy(-1,-1); + StrokeRect(rect); +} +//------------------------------------------------------------------------------ +void BBox::ClearAnyLabel() +{ +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ diff --git a/src/kits/interface/Button.cpp b/src/kits/interface/Button.cpp new file mode 100644 index 0000000000..6ce2cfa420 --- /dev/null +++ b/src/kits/interface/Button.cpp @@ -0,0 +1,521 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: Button.cpp +// Author: Marc Flerackers (mflerackers@androme.be) +// Description: BButton displays and controls a button in a window. +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +BButton::BButton(BRect frame, const char *name, const char *label, BMessage *message, + uint32 resizingMode, uint32 flags) + : BControl(frame, name, label, message, resizingMode, flags), + fDrawAsDefault(false) +{ + if (Bounds().Height() < 24.0f) + ResizeTo(Bounds().Width(), 24.0f); +} +//------------------------------------------------------------------------------ +BButton::~BButton() +{ +} +//------------------------------------------------------------------------------ +BButton::BButton(BMessage *archive) + : BControl (archive) +{ + if ( archive->FindBool ( "_default", &fDrawAsDefault ) != B_OK ) + fDrawAsDefault = false; +} +//------------------------------------------------------------------------------ +BArchivable *BButton::Instantiate ( BMessage *archive ) +{ + if ( validate_instantiation(archive, "BButton")) + return new BButton(archive); + else + return NULL; +} +//------------------------------------------------------------------------------ +status_t BButton::Archive(BMessage* archive, bool deep) const +{ + status_t err = BControl::Archive(archive, deep); + + if (err != B_OK) + return err; + + if (fDrawAsDefault) + err = archive->AddBool("_default", fDrawAsDefault); + + return err; +} +//------------------------------------------------------------------------------ +void BButton::Draw(BRect updateRect) +{ + BRect rect = Bounds(); + + rgb_color no_tint = ui_color(B_PANEL_BACKGROUND_COLOR), + lighten1 = tint_color(no_tint, B_LIGHTEN_1_TINT), + lighten2 = tint_color(no_tint, B_LIGHTEN_2_TINT), + lightenmax = tint_color(no_tint, B_LIGHTEN_MAX_TINT), + darken2 = tint_color(no_tint, B_DARKEN_2_TINT), + darken4 = tint_color(no_tint, B_DARKEN_4_TINT), + darkenmax = tint_color(no_tint, B_DARKEN_MAX_TINT); + + if (!IsDefault()) + { + SetHighColor(no_tint); + StrokeRect(rect); + rect.InsetBy(1,1); + } + + if (IsEnabled()) + { + if (Value()) + { + BeginLineArray(8); + + // Dark border + AddLine(BPoint(rect.left, rect.bottom-1.0f), + BPoint(rect.left, rect.top+1.0f), darken4); + AddLine(BPoint(rect.left+1.0f, rect.top), + BPoint(rect.right-1.0f, rect.top), darken4); + AddLine(BPoint(rect.left+1.0f, rect.bottom), + BPoint(rect.right-1.0f, rect.bottom), darken4); + AddLine(BPoint(rect.right, rect.bottom-1.0f), + BPoint(rect.right, rect.top+1.0f), darken4); + + rect.InsetBy(1,1); + + // First bevel + AddLine(BPoint(rect.left, rect.top), + BPoint(rect.left, rect.bottom), darkenmax); + AddLine(BPoint(rect.left+1.0f, rect.top), + BPoint(rect.right, rect.top), darkenmax); + AddLine(BPoint(rect.left+1.0f, rect.bottom), + BPoint(rect.right, rect.bottom), darken4); + AddLine(BPoint(rect.right, rect.bottom-1.0f), + BPoint(rect.right, rect.top+1.0f), darken4); + + EndLineArray(); + + rect.InsetBy(1,1); + + // Filling + SetHighColor(darkenmax); + FillRect(rect); + + // Label + BFont font; + GetFont(&font); + + float x = Bounds().Width() / 2 - StringWidth(Label()) / 2.0f; + float y = Bounds().Height() / 2.0f + (float)ceil(font.Size() / 2.0f); + + SetHighColor(lightenmax); + SetLowColor(darkenmax); + DrawString(Label(), BPoint(x, y)); + } + else + { + BeginLineArray(14); + + // Dark border + AddLine(BPoint(rect.left, rect.bottom-1.0f), + BPoint(rect.left, rect.top+1.0f), darken4); + AddLine(BPoint(rect.left+1.0f, rect.top), + BPoint(rect.right-1.0f, rect.top), darken4); + AddLine(BPoint(rect.left+1.0f, rect.bottom), + BPoint(rect.right-1.0f, rect.bottom), darken4); + AddLine(BPoint(rect.right, rect.bottom-1.0f), + BPoint(rect.right, rect.top+1.0f), darken4); + + rect.InsetBy(1,1); + + // First bevel + AddLine(BPoint(rect.left, rect.top), + BPoint(rect.left, rect.bottom), lighten1); + AddLine(BPoint(rect.left+1.0f, rect.top), + BPoint(rect.right, rect.top), lighten1); + AddLine(BPoint(rect.left+1.0f, rect.bottom), + BPoint(rect.right, rect.bottom), darken2); + AddLine(BPoint(rect.right, rect.bottom-1.0f), + BPoint(rect.right, rect.top+1.0f), darken2); + + rect.InsetBy(1,1); + + // Second bevel + AddLine(BPoint(rect.left, rect.top), + BPoint(rect.left, rect.bottom), lightenmax); + AddLine(BPoint(rect.left+1.0f, rect.top), + BPoint(rect.right, rect.top), lightenmax); + AddLine(BPoint(rect.left+1.0f, rect.bottom), + BPoint(rect.right, rect.bottom), no_tint); + AddLine(BPoint(rect.right, rect.bottom-1.0f), + BPoint(rect.right, rect.top+1.0f), no_tint); + + rect.InsetBy(1,1); + + // Third bevel + AddLine(BPoint(rect.left, rect.top), + BPoint(rect.left, rect.bottom), lightenmax); + AddLine(BPoint(rect.left+1.0f, rect.top), + BPoint(rect.right, rect.top), lightenmax); + + EndLineArray(); + + rect.left +=1; + rect.top += 1; + + // Filling + SetHighColor(lighten2); + FillRect(rect); + + // Label + BFont font; + GetFont(&font); + + float x = Bounds().Width() / 2 - StringWidth(Label()) / 2.0f; + float y = Bounds().Height() / 2.0f + (float)ceil(font.Size() / 2.0f); + + SetHighColor(darkenmax); + DrawString(Label(), BPoint(x, y)); + + // Focus + if (IsFocus()) + { + font_height fh; + font.GetHeight(&fh); + + y += 2.0f; + SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR)); + StrokeLine(BPoint(x, y), BPoint(x + StringWidth(Label()), y)); + } + } + } + else + { + BeginLineArray(14); + + // Dark border + AddLine(BPoint(rect.left, rect.bottom-1.0f), + BPoint(rect.left, rect.top+1.0f), darken2); + AddLine(BPoint(rect.left+1.0f, rect.top), + BPoint(rect.right-1.0f, rect.top), darken2); + AddLine(BPoint(rect.left+1.0f, rect.bottom), + BPoint(rect.right-1.0f, rect.bottom), darken2); + AddLine(BPoint(rect.right, rect.bottom-1.0f), + BPoint(rect.right, rect.top+1.0f), darken2); + + rect.InsetBy(1,1); + + // First bevel + AddLine(BPoint(rect.left, rect.top), + BPoint(rect.left, rect.bottom), lighten1); + AddLine(BPoint(rect.left+1.0f, rect.top), + BPoint(rect.right, rect.top), lighten1); + AddLine(BPoint(rect.left+1.0f, rect.bottom), + BPoint(rect.right, rect.bottom), no_tint); + AddLine(BPoint(rect.right, rect.bottom-1.0f), + BPoint(rect.right, rect.top+1.0f), no_tint); + + rect.InsetBy(1,1); + + // Second bevel + AddLine(BPoint(rect.left, rect.top), + BPoint(rect.left, rect.bottom), lightenmax); + AddLine(BPoint(rect.left+1.0f, rect.top), + BPoint(rect.right, rect.top), lightenmax); + AddLine(BPoint(rect.left+1.0f, rect.bottom), + BPoint(rect.right, rect.bottom), no_tint); + AddLine(BPoint(rect.right, rect.bottom-1.0f), + BPoint(rect.right, rect.top+1.0f), no_tint); + + rect.InsetBy(1,1); + + // Third bevel + AddLine(BPoint(rect.left, rect.top), + BPoint(rect.left, rect.bottom), lightenmax); + AddLine(BPoint(rect.left+1.0f, rect.top), + BPoint(rect.right, rect.top), lightenmax); + + EndLineArray(); + + rect.left +=1; + rect.top += 1; + + // Filling + SetHighColor(lighten2); + FillRect(rect); + + // Label + BFont font; + GetFont(&font); + + float x = Bounds().Width() / 2 - StringWidth(Label()) / 2.0f; + float y = Bounds().Height() / 2.0f + (float)ceil(font.Size() / 2.0f); + + SetHighColor(tint_color(no_tint, B_DISABLED_LABEL_TINT)); + DrawString(Label(), BPoint(x, y)); + } +} +//------------------------------------------------------------------------------ +void BButton::MouseDown(BPoint point) +{ + if (!IsEnabled()) + { + BControl::MouseDown(point); + return; + } + + SetMouseEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY | B_SUSPEND_VIEW_FOCUS); + + SetValue(B_CONTROL_ON); + SetTracking(true); +} +//------------------------------------------------------------------------------ +void BButton::AttachedToWindow() +{ + BControl::AttachedToWindow(); + + if (IsDefault()) + Window()->SetDefaultButton((BButton*)this); +} +//------------------------------------------------------------------------------ +void BButton::KeyDown ( const char *bytes, int32 numBytes ) +{ + if (numBytes == 1) + { + switch (bytes[0]) + { + case B_ENTER: + case B_SPACE: + SetValue(B_CONTROL_ON); + snooze(50000); + SetValue(B_CONTROL_OFF); + Invoke(); + break; + + default: + BControl::KeyDown(bytes, numBytes); + } + } + else + BControl::KeyDown(bytes, numBytes); +} +//------------------------------------------------------------------------------ +void BButton::MakeDefault(bool flag) +{ + if (flag == IsDefault()) + return; + + fDrawAsDefault = flag; + + if (Window()) + { + BButton *button = (BButton*)(Window()->DefaultButton()); + + if (fDrawAsDefault) + { + if(button) + button->MakeDefault(false); + + Window()->SetDefaultButton((BButton*)this); + } + else + { + if (button == this) + Window()->SetDefaultButton(NULL); + } + } + + Invalidate(); +} +//------------------------------------------------------------------------------ +void BButton::SetLabel(const char *string) +{ + BControl::SetLabel(string); +} +//------------------------------------------------------------------------------ +bool BButton::IsDefault() const +{ + return fDrawAsDefault; +} +//------------------------------------------------------------------------------ +void BButton::MessageReceived(BMessage *message) +{ + BControl::MessageReceived(message); +} +//------------------------------------------------------------------------------ +void BButton::WindowActivated(bool active) +{ + BControl::WindowActivated(active); +} +//------------------------------------------------------------------------------ +void BButton::MouseMoved(BPoint point, uint32 transit, const BMessage *message) +{ + if (IsEnabled() && IsTracking()) + { + if (transit == B_EXITED_VIEW) + SetValue(B_CONTROL_OFF); + else if (transit == B_ENTERED_VIEW) + SetValue(B_CONTROL_ON); + } + else + BControl::MouseMoved(point, transit, message); +} +//------------------------------------------------------------------------------ +void BButton::MouseUp(BPoint point) +{ + if (IsEnabled() && IsTracking()) + { + if (Bounds().Contains(point)) + { + if ( Value() == B_CONTROL_ON) + { + SetValue(B_CONTROL_OFF); + BControl::Invoke(); + } + } + + SetTracking(false); + } +} +//------------------------------------------------------------------------------ +void BButton::DetachedFromWindow() +{ + BControl::DetachedFromWindow(); +} +//------------------------------------------------------------------------------ +void BButton::SetValue(int32 value) +{ + BControl::SetValue(value); +} +//------------------------------------------------------------------------------ +void BButton::GetPreferredSize (float *width, float *height) +{ + font_height fh; + + GetFontHeight(&fh); + + *height = (float)ceil(fh.ascent + fh.descent + fh.leading) + 12.0f; + *width = 20.0f + (float)ceil(StringWidth(Label())); + + if (*width < 75.0f) + *width = 75.0f; +} +//------------------------------------------------------------------------------ +void BButton::ResizeToPreferred() +{ + float width, height; + GetPreferredSize(&width, &height); + ResizeTo(width,height); +} +//------------------------------------------------------------------------------ +status_t BButton::Invoke(BMessage *message) +{ + return BControl::Invoke(message); +} +//------------------------------------------------------------------------------ +void BButton::FrameMoved(BPoint newLocation) +{ + BControl::FrameMoved(newLocation); +} +//------------------------------------------------------------------------------ +void BButton::FrameResized(float width, float height) +{ + BControl::FrameResized(width, height); +} +//------------------------------------------------------------------------------ +void BButton::MakeFocus(bool focused) +{ + BControl::MakeFocus(focused); +} +//------------------------------------------------------------------------------ +void BButton::AllAttached() +{ + BControl::AllAttached(); +} +//------------------------------------------------------------------------------ +void BButton::AllDetached() +{ + BControl::AllDetached(); +} +//------------------------------------------------------------------------------ +BHandler *BButton::ResolveSpecifier(BMessage *message, int32 index, + BMessage *specifier, int32 what, + const char *property) +{ + return BControl::ResolveSpecifier(message, index, specifier, what, property); +} +//------------------------------------------------------------------------------ +status_t BButton::GetSupportedSuites(BMessage *message) +{ + return BControl::GetSupportedSuites(message); +} +//------------------------------------------------------------------------------ +status_t BButton::Perform(perform_code d, void *arg) +{ + return B_ERROR; +} + +//------------------------------------------------------------------------------ +void BButton::_ReservedButton1() {} +void BButton::_ReservedButton2() {} +void BButton::_ReservedButton3() {} +//------------------------------------------------------------------------------ +BButton &BButton::operator=(const BButton &) +{ + return *this; +} +//------------------------------------------------------------------------------ +BRect BButton::DrawDefault(BRect bounds, bool enabled) +{ + // TODO: + return BRect(); +} +//------------------------------------------------------------------------------ +status_t Execute() +{ + // TODO: + return B_ERROR; +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ diff --git a/src/kits/interface/CheckBox.cpp b/src/kits/interface/CheckBox.cpp new file mode 100644 index 0000000000..e3fd33a25d --- /dev/null +++ b/src/kits/interface/CheckBox.cpp @@ -0,0 +1,389 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: CheckBox.cpp +// Author: Marc Flerackers (mflerackers@androme.be) +// Description: BCheckBox displays an on/off control. +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +BCheckBox::BCheckBox(BRect frame, const char *name, const char *label, + BMessage *message, uint32 resizingMode, uint32 flags) + : BControl(frame, name, label, message, resizingMode, flags) +{ + fOutlined = false; + + if (Bounds().Height() < 18.0f) + ResizeTo(Bounds().Width(), 18.0f); +} +//------------------------------------------------------------------------------ +BCheckBox::~BCheckBox() +{ + +} +//------------------------------------------------------------------------------ +BCheckBox::BCheckBox(BMessage *archive) + : BControl(archive) +{ + fOutlined = false; +} +//------------------------------------------------------------------------------ +BArchivable *BCheckBox::Instantiate(BMessage *archive) +{ + if (validate_instantiation(archive, "BCheckBox")) + return new BCheckBox(archive); + else + return NULL; +} +//------------------------------------------------------------------------------ +status_t BCheckBox::Archive(BMessage *archive, bool deep) const +{ + return BControl::Archive(archive,deep); +} +//------------------------------------------------------------------------------ +void BCheckBox::Draw(BRect updateRect) +{ + rgb_color no_tint = ui_color(B_PANEL_BACKGROUND_COLOR), + lighten1 = tint_color(no_tint, B_LIGHTEN_1_TINT), + lightenmax = tint_color(no_tint, B_LIGHTEN_MAX_TINT), + darken1 = tint_color(no_tint, B_DARKEN_1_TINT), + darken2 = tint_color(no_tint, B_DARKEN_2_TINT), + darken3 = tint_color(no_tint, B_DARKEN_3_TINT), + darken4 = tint_color(no_tint, B_DARKEN_4_TINT), + darkenmax = tint_color(no_tint, B_DARKEN_MAX_TINT); + + BRect rect(1.0, 3.0, 13.0, 15.0); + + if (IsEnabled()) + { + // Filling + SetHighColor(lightenmax); + FillRect(rect); + + // Box + if (fOutlined) + { + SetHighColor(darken3); + StrokeRect(rect); + + rect.InsetBy(1,1); + + BeginLineArray(6); + + AddLine(BPoint(rect.left, rect.bottom), + BPoint(rect.left, rect.top), darken2); + AddLine(BPoint(rect.left, rect.top), + BPoint(rect.right, rect.top), darken2); + AddLine(BPoint(rect.left, rect.bottom), + BPoint(rect.right, rect.bottom), darken4); + AddLine(BPoint(rect.right, rect.bottom), + BPoint(rect.right, rect.top), darken4); + + EndLineArray(); + } + else + { + BeginLineArray(6); + + AddLine(BPoint(rect.left, rect.bottom), + BPoint(rect.left, rect.top), darken1); + AddLine(BPoint(rect.left, rect.top), + BPoint(rect.right, rect.top), darken1); + rect.InsetBy(1,1); + AddLine(BPoint(rect.left, rect.bottom), + BPoint(rect.left, rect.top), darken4); + AddLine(BPoint(rect.left, rect.top), + BPoint(rect.right, rect.top), darken4); + AddLine(BPoint(rect.left + 1.0f, rect.bottom), + BPoint(rect.right, rect.bottom), no_tint); + AddLine(BPoint(rect.right, rect.bottom), + BPoint(rect.right, rect.top + 1.0f), no_tint); + + EndLineArray(); + } + + // Checkmark + if (Value() == B_CONTROL_ON) + { + rect.InsetBy(2,2); + + SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR)); + SetPenSize(2); + StrokeLine(BPoint(rect.left, rect.top), + BPoint(rect.right, rect.bottom)); + StrokeLine(BPoint(rect.left, rect.bottom), + BPoint(rect.right, rect.top)); + SetPenSize(1); + } + + // Label + BFont font; + GetFont(&font); + font_height fh; + font.GetHeight(&fh); + + SetHighColor(darkenmax); + DrawString(Label(), BPoint(20.0f, 8.0f + (float)ceil(fh.ascent / 2.0f))); + + // Focus + if (IsFocus()) + { + float h = 8.0f + (float)ceil(fh.ascent / 2.0f) + 2.0f; + + SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR)); + StrokeLine(BPoint(20.0f, h), BPoint(20.0f + StringWidth(Label()), h)); + } + } + else + { + // Filling + SetHighColor(lighten1); + FillRect(rect); + + // Box + BeginLineArray(6); + + AddLine(BPoint(rect.left, rect.bottom), + BPoint(rect.left, rect.top), no_tint); + AddLine(BPoint(rect.left, rect.top), + BPoint(rect.right, rect.top), no_tint); + rect.InsetBy(1,1); + AddLine(BPoint(rect.left, rect.bottom), + BPoint(rect.left, rect.top), darken2); + AddLine(BPoint(rect.left, rect.top), + BPoint(rect.right, rect.top), darken2); + AddLine(BPoint(rect.left + 1.0f, rect.bottom), + BPoint(rect.right, rect.bottom), darken1); + AddLine(BPoint(rect.right, rect.bottom), + BPoint(rect.right, rect.top + 1.0f), darken1); + + EndLineArray(); + + // Checkmark + if (Value() == B_CONTROL_ON) + { + rect.InsetBy(2, 2); + + SetHighColor(tint_color(ui_color(B_KEYBOARD_NAVIGATION_COLOR), + B_DISABLED_MARK_TINT)); + SetPenSize(2); + StrokeLine(BPoint(rect.left, rect.top), + BPoint(rect.right, rect.bottom)); + StrokeLine(BPoint(rect.left, rect.bottom), + BPoint(rect.right, rect.top)); + SetPenSize(1); + } + + // Label + BFont font; + GetFont(&font); + font_height fh; + font.GetHeight(&fh); + + SetHighColor(tint_color(no_tint, B_DISABLED_LABEL_TINT)); + DrawString(Label(), BPoint(20.0f, 8.0f + (float)ceil(fh.ascent / 2.0f))); + } +} +//------------------------------------------------------------------------------ +void BCheckBox::AttachedToWindow() +{ + BControl::AttachedToWindow(); +} +//------------------------------------------------------------------------------ +void BCheckBox::MouseDown(BPoint point) +{ + if (!IsEnabled()) + { + BControl::MouseDown(point); + return; + } + + SetMouseEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY | + B_SUSPEND_VIEW_FOCUS); + + fOutlined = true; + SetTracking(true); + Invalidate(); +} +//------------------------------------------------------------------------------ +void BCheckBox::MessageReceived(BMessage *message) +{ + BControl::MessageReceived(message); +} +//------------------------------------------------------------------------------ +void BCheckBox::WindowActivated(bool active) +{ + BControl::WindowActivated(active); +} +//------------------------------------------------------------------------------ +void BCheckBox::KeyDown(const char *bytes, int32 numBytes) +{ +// if (*((int*)bytes) == VK_RETURN || *((int*)bytes) == VK_SPACE) +// SetValue(Value() ? 0 : 1); +// else +// { +// SetValue(0); + BControl::KeyDown(bytes, numBytes); +// } +} +//------------------------------------------------------------------------------ +void BCheckBox::MouseUp(BPoint point) +{ + if (IsEnabled() && IsTracking()) + { + fOutlined = false; + + if (Bounds().Contains(point)) + { + if (Value() == B_CONTROL_OFF) + SetValue(B_CONTROL_ON); + else + SetValue(B_CONTROL_OFF); + + BControl::Invoke(); + } + SetTracking(false); + } + else + { + BControl::MouseUp(point); + return; + } +} +//------------------------------------------------------------------------------ +void BCheckBox::MouseMoved(BPoint point, uint32 transit, const BMessage *message) +{ + if (IsEnabled() && IsTracking()) + { + if (transit == B_EXITED_VIEW) + fOutlined = false; + else if (transit == B_ENTERED_VIEW) + fOutlined = true; + + Invalidate(); + } + else + BControl::MouseMoved(point, transit, message); +} +//------------------------------------------------------------------------------ +void BCheckBox::DetachedFromWindow() +{ + BControl::DetachedFromWindow(); +} +//------------------------------------------------------------------------------ +void BCheckBox::SetValue(int32 value) +{ + BControl::SetValue(value); +} +//------------------------------------------------------------------------------ +void BCheckBox::GetPreferredSize(float *width, float *height) +{ + font_height fh; + GetFontHeight(&fh); + + *height = (float)ceil(fh.ascent + fh.descent + fh.leading) + 6.0f; + *width = 22.0f + (float)ceil(StringWidth(Label())); +} +//------------------------------------------------------------------------------ +void BCheckBox::ResizeToPreferred() +{ + float widht, height; + GetPreferredSize(&widht, &height); + BView::ResizeTo(widht,height); +} +//------------------------------------------------------------------------------ +status_t BCheckBox::Invoke(BMessage *message) +{ + return BControl::Invoke(message); +} +//------------------------------------------------------------------------------ +void BCheckBox::FrameMoved(BPoint newLocation) +{ + BControl::FrameMoved(newLocation); +} +//------------------------------------------------------------------------------ +void BCheckBox::FrameResized(float width, float height) +{ + BControl::FrameResized(width, height); +} +//------------------------------------------------------------------------------ +BHandler *BCheckBox::ResolveSpecifier(BMessage *message, int32 index, + BMessage *specifier, int32 what, + const char *property) +{ + return BControl::ResolveSpecifier(message, index, specifier, what, property); +} +//------------------------------------------------------------------------------ +status_t BCheckBox::GetSupportedSuites(BMessage *message) +{ + return BControl::GetSupportedSuites(message); +} +//------------------------------------------------------------------------------ +void BCheckBox::MakeFocus(bool focused) +{ + BControl::MakeFocus(focused); +} +//------------------------------------------------------------------------------ +void BCheckBox::AllAttached() +{ + BControl::AllAttached(); +} +//------------------------------------------------------------------------------ +void BCheckBox::AllDetached() +{ + BControl::AllDetached(); +} +//------------------------------------------------------------------------------ +status_t BCheckBox::Perform(perform_code d, void *arg) +{ + return B_ERROR; +} +//------------------------------------------------------------------------------ +void BCheckBox::_ReservedCheckBox1() {} +void BCheckBox::_ReservedCheckBox2() {} +void BCheckBox::_ReservedCheckBox3() {} +//------------------------------------------------------------------------------ +BCheckBox &BCheckBox::operator=(const BCheckBox &) +{ + return *this; +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ diff --git a/src/kits/interface/Control.cpp b/src/kits/interface/Control.cpp new file mode 100644 index 0000000000..d49d0a58db --- /dev/null +++ b/src/kits/interface/Control.cpp @@ -0,0 +1,539 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: Control.cpp +// Author: Marc Flerackers (mflerackers@androme.be) +// Description: BControl is the base class for user-event handling objects. +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- +#include + +// System Includes ------------------------------------------------------------- +#include +#include +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- +static property_info prop_list[] = +{ + { + "Enabled", + { B_GET_PROPERTY, 0 }, + { B_DIRECT_SPECIFIER, 0 }, + "Returns whether or not the BControl is currently enabled.", 0, + { B_BOOL_TYPE, 0 } + }, + { + "Enabled", + { B_SET_PROPERTY, 0 }, + { B_DIRECT_SPECIFIER, 0 }, + "Enables or disables the BControl.", 0, + { B_BOOL_TYPE, 0 } + }, + { + "Label", + { B_GET_PROPERTY, 0 }, + { B_DIRECT_SPECIFIER, 0 }, + "Returns the BControl's label.", 0, + { B_STRING_TYPE, 0 } + }, + { + "Label", + { B_SET_PROPERTY, 0 }, + { B_DIRECT_SPECIFIER, 0 }, + "Sets the label of the BControl.", 0, + { B_STRING_TYPE, 0 } + }, + { + "Value", + { B_GET_PROPERTY, 0 }, + { B_DIRECT_SPECIFIER, 0 }, + "Returns the BControl's value.", 0, + { B_INT32_TYPE, 0 } + }, + { + "Value", + { B_SET_PROPERTY, 0 }, + { B_DIRECT_SPECIFIER, 0 }, + "Sets the value of the BControl.", 0, + { B_INT32_TYPE, 0 }, + }, + { 0 } +}; + +//------------------------------------------------------------------------------ +BControl::BControl(BRect frame, const char *name, const char *label, BMessage *message, + uint32 resizingMode, uint32 flags) + : BView(frame, name, resizingMode, flags), + BInvoker(message, NULL), + fValue(B_CONTROL_OFF), + fEnabled(true), + fFocusChanging(false), + fTracking(false), + fWantsNav(true) +{ + fLabel = strdup(label); +} +//------------------------------------------------------------------------------ +BControl::~BControl () +{ + if ( fLabel ) + delete fLabel; +} +//------------------------------------------------------------------------------ +BControl::BControl(BMessage *archive) : BView(archive) +{ + const char *label; + + if (archive->FindInt32("_val", &fValue) != B_OK) + fValue = B_CONTROL_OFF; + + if (archive->FindString("_label", &label) != B_OK) + fLabel = NULL; + else + SetLabel(label); + + if ( archive->FindBool("_disable", &fEnabled) != B_OK) + fEnabled = true; + else + fEnabled = !fEnabled; + + fFocusChanging = false; + fTracking = false; + fWantsNav = true; + + BMessage message; + + if (archive->FindMessage("_msg", &message) == B_OK) + SetMessage(new BMessage(message)); +} +//------------------------------------------------------------------------------ +BArchivable *BControl::Instantiate(BMessage *archive) +{ + if (validate_instantiation(archive, "BControl")) + return new BControl(archive); + else + return NULL; +} +//------------------------------------------------------------------------------ +status_t BControl::Archive(BMessage *archive, bool deep) const +{ + status_t err = BView::Archive(archive, deep); + + if (err != B_OK) + return err; + + if (Message()) + err = archive->AddMessage("_msg", Message ()); + + if (err != B_OK) + return err; + + if (fLabel) + err = archive->AddString("_label", fLabel); + + if (err != B_OK ) + return err; + + if (fValue != B_CONTROL_OFF) + err = archive->AddInt32("_val", fValue); + + if (err != B_OK) + return err; + + if (!fEnabled) + err = archive->AddBool("_disable", true); + + return err; +} +//------------------------------------------------------------------------------ +void BControl::WindowActivated(bool active) +{ + // TODO: redraw if focus + BView::WindowActivated(active); +} +//------------------------------------------------------------------------------ +void BControl::AttachedToWindow() +{ + if (Parent()) + SetViewColor(Parent()->ViewColor()); + + if ( Target() == NULL) + BInvoker::SetTarget(BMessenger(Window(), NULL)); + + BView::AttachedToWindow(); +} +//------------------------------------------------------------------------------ +void BControl::MessageReceived(BMessage *message) +{ + switch (message->what) + { + case B_CONTROL_INVOKED: + Invoke(); + break; + + case B_GET_PROPERTY: + case B_SET_PROPERTY: + { + BPropertyInfo propInfo(prop_list); + BMessage specifier; + const char *property; + + if (message->GetCurrentSpecifier(NULL, &specifier) != B_OK || + specifier.FindString("property", &property) != B_OK) + return; + + switch (propInfo.FindMatch(message, 0, &specifier, specifier.what, property)) + { + case B_ERROR: + { + BView::MessageReceived(message); + break; + } + case 0: + { + BMessage reply; + reply.AddBool("result", fEnabled); + reply.AddBool("error", B_OK); + message->SendReply(&reply); + break; + } + case 1: + { + bool enabled; + message->FindBool("data", &enabled); + SetEnabled(enabled); + break; + } + case 2: + { + BMessage reply; + reply.AddString("result", fLabel); + reply.AddBool("error", B_OK); + message->SendReply(&reply); + break; + } + case 3: + { + const char *label; + message->FindString("data", &label); + SetLabel(label); + break; + } + case 4: + { + BMessage reply; + reply.AddInt32("result", fValue); + reply.AddBool("error", B_OK); + message->SendReply(&reply); + break; + } + case 5: + { + int32 value; + message->FindInt32("data", &value); + SetValue(value); + break; + } + } + + break; + } + default: + { + BView::MessageReceived(message); + break; + } + } +} +//------------------------------------------------------------------------------ +void BControl::MakeFocus(bool focused) +{ + BView::MakeFocus(focused); + + fFocusChanging = true; + Draw(Bounds()); + Flush(); + fFocusChanging = false; +} +//------------------------------------------------------------------------------ +void BControl::KeyDown(const char *bytes, int32 numBytes) +{ + BMessage* message = Window()->CurrentMessage(); + + if (numBytes == 1) + { + switch (bytes[0]) + { + case B_UP_ARROW: + message->ReplaceInt64("when", (int64)system_time()); + message->ReplaceInt32("key", 38); + message->ReplaceInt32("raw_char", B_TAB); + message->ReplaceInt32("modifiers", B_SCROLL_LOCK | B_SHIFT_KEY); + message->ReplaceInt8("byte", B_TAB); + message->ReplaceString("bytes", ""); + Looper()->PostMessage(message); + break; + + case B_DOWN_ARROW: + message->ReplaceInt64("when", (int64)system_time()); + message->ReplaceInt32("key", 38); + message->ReplaceInt32("raw_char", B_TAB); + message->ReplaceInt8("byte", B_TAB); + message->ReplaceString("bytes", ""); + Looper()->PostMessage(message); + break; + + case B_ENTER: + case B_SPACE: + if (Value()) + SetValue(B_CONTROL_OFF); + else + SetValue(B_CONTROL_ON); + + BInvoker::Invoke(); + break; + + default: + BView::KeyDown(bytes, numBytes); + } + } + else + BView::KeyDown(bytes, numBytes); +} +//------------------------------------------------------------------------------ +void BControl::MouseDown(BPoint point) +{ + BView::MouseDown(point); +} +//------------------------------------------------------------------------------ +void BControl::MouseUp(BPoint point) +{ + BView::MouseUp(point); +} +//------------------------------------------------------------------------------ +void BControl::MouseMoved(BPoint point, uint32 transit, const BMessage *message) +{ + BView::MouseMoved(point, transit, message); +} +//------------------------------------------------------------------------------ +void BControl::DetachedFromWindow() +{ + BView::DetachedFromWindow(); +} +//------------------------------------------------------------------------------ +void BControl::SetLabel(const char *string) +{ + if (fLabel) + delete fLabel; + + fLabel = strdup(string); + + Invalidate(); +} +//------------------------------------------------------------------------------ +const char *BControl::Label() const +{ + return fLabel; +} +//------------------------------------------------------------------------------ +void BControl::SetValue(int32 value) +{ + if (fValue == value) + return; + + fValue = value; + + Invalidate(); +} +//------------------------------------------------------------------------------ +int32 BControl::Value() const +{ + return fValue; +} +//------------------------------------------------------------------------------ +void BControl::SetEnabled(bool enabled) +{ + if (fEnabled == enabled) + return; + + fEnabled = enabled; + + if (fEnabled) + BView::SetFlags(Flags() | B_NAVIGABLE); + else + BView::SetFlags(Flags() & ~B_NAVIGABLE); + + Invalidate(); +} +//------------------------------------------------------------------------------ +bool BControl::IsEnabled() const +{ + return fEnabled; +} +//------------------------------------------------------------------------------ +void BControl::GetPreferredSize(float *width, float *height) +{ + *width = 1.0f; + *height = 1.0f; +} +//------------------------------------------------------------------------------ +void BControl::ResizeToPreferred() +{ + BView::ResizeToPreferred(); +} +//------------------------------------------------------------------------------ +status_t BControl::Invoke(BMessage *message) +{ + if (message) + { + BMessage copy(*message); + copy.AddInt64("when", (int64)system_time()); + copy.AddPointer("source", this); + return BInvoker::Invoke(©); + } + else if ( Message () ) + { + BMessage copy (*Message()); + copy.AddInt64 ("when", (int64)system_time()); + copy.AddPointer ("source", this); + return BInvoker::Invoke(©); + } + + return B_BAD_VALUE; +} +//------------------------------------------------------------------------------ +BHandler *BControl::ResolveSpecifier(BMessage *message, int32 index, + BMessage *specifier, int32 what, + const char *property) +{ + BPropertyInfo propInfo(prop_list); + BHandler *target = NULL; + + switch (propInfo.FindMatch(message, 0, specifier, what, property)) + { + case B_ERROR: + break; + + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + target = this; + break; + } + + if (!target) + target = BView::ResolveSpecifier(message, index, specifier, what, + property); + + return target; +} +//------------------------------------------------------------------------------ +status_t BControl::GetSupportedSuites(BMessage *message) +{ + status_t err; + + if (message == NULL) + return B_BAD_VALUE; + + err = message->AddString("suites", "suite/vnd.Be-control"); + + if (err != B_OK) + return err; + + BPropertyInfo prop_info(prop_list); + err = message->AddFlat("messages", &prop_info); + + if (err != B_OK) + return err; + + return BView::GetSupportedSuites(message); +} +//------------------------------------------------------------------------------ +void BControl::AllAttached() +{ + BView::AllAttached(); +} +//------------------------------------------------------------------------------ +void BControl::AllDetached() +{ + BView::AllDetached(); +} +//------------------------------------------------------------------------------ +status_t BControl::Perform(perform_code d, void *arg) +{ + return B_ERROR; +} +//------------------------------------------------------------------------------ +bool BControl::IsFocusChanging() const +{ + return fFocusChanging; +} +//------------------------------------------------------------------------------ +bool BControl::IsTracking() const +{ + return fTracking; +} +//------------------------------------------------------------------------------ +void BControl::SetTracking(bool state) +{ + fTracking = state; +} +//------------------------------------------------------------------------------ +void BControl::SetValueNoUpdate(int32 value) +{ + fValue = value; +} + +//------------------------------------------------------------------------------ +void BControl::_ReservedControl1() {} +void BControl::_ReservedControl2() {} +void BControl::_ReservedControl3() {} +void BControl::_ReservedControl4() {} +//------------------------------------------------------------------------------ +BControl &BControl::operator=(const BControl &) +{ + return *this; +} +//------------------------------------------------------------------------------ +void BControl::InitData(BMessage *data) +{ + +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ diff --git a/src/kits/interface/Input.cpp b/src/kits/interface/Input.cpp new file mode 100644 index 0000000000..ddd856e573 --- /dev/null +++ b/src/kits/interface/Input.cpp @@ -0,0 +1,155 @@ +/*********************************************************************** + * AUTHOR: nobody + * FILE: Input.cpp + * DATE: Sun Dec 16 15:57:43 2001 + * DESCR: + ***********************************************************************/ +#include "Input.h" + +/* + * Method: BInputDevice::~BInputDevice() + * Descr: + */ +BInputDevice::~BInputDevice() +{ +} + + +/* + * Method: BInputDevice::Name() + * Descr: + */ +const char * +BInputDevice::Name() const +{ + return NULL; +} + + +/* + * Method: BInputDevice::Type() + * Descr: + */ +input_device_type +BInputDevice::Type() const +{ + input_device_type dummy; + + return dummy; +} + + +/* + * Method: BInputDevice::IsRunning() + * Descr: + */ +bool +BInputDevice::IsRunning() const +{ + bool dummy; + + return dummy; +} + + +/* + * Method: BInputDevice::Start() + * Descr: + */ +status_t +BInputDevice::Start() +{ + status_t dummy; + + return dummy; +} + + +/* + * Method: BInputDevice::Stop() + * Descr: + */ +status_t +BInputDevice::Stop() +{ + status_t dummy; + + return dummy; +} + + +/* + * Method: BInputDevice::Control() + * Descr: + */ +status_t +BInputDevice::Control(uint32 code, + BMessage *message) +{ + status_t dummy; + + return dummy; +} + + +/* + * Method: BInputDevice::Start() + * Descr: + */ +status_t +BInputDevice::Start(input_device_type type) +{ + status_t dummy; + + return dummy; +} + + +/* + * Method: BInputDevice::Stop() + * Descr: + */ +status_t +BInputDevice::Stop(input_device_type type) +{ + status_t dummy; + + return dummy; +} + + +/* + * Method: BInputDevice::Control() + * Descr: + */ +status_t +BInputDevice::Control(input_device_type type, + uint32 code, + BMessage *message) +{ + status_t dummy; + + return dummy; +} + + +/* + * Method: BInputDevice::BInputDevice() + * Descr: + */ +BInputDevice::BInputDevice() +{ +} + + +/* + * Method: BInputDevice::set_name_and_type() + * Descr: + */ +void +BInputDevice::set_name_and_type(const char *name, + input_device_type type) +{ +} + + diff --git a/src/kits/interface/Jamfile b/src/kits/interface/Jamfile new file mode 100644 index 0000000000..779e5d3194 --- /dev/null +++ b/src/kits/interface/Jamfile @@ -0,0 +1,3 @@ +SubDir OBOS_TOP sources os kits interface ; + +#SubInclude OBOS_TOP sources os kits interface prefs ; diff --git a/src/kits/interface/ListItem.cpp b/src/kits/interface/ListItem.cpp new file mode 100644 index 0000000000..68eb801f2d --- /dev/null +++ b/src/kits/interface/ListItem.cpp @@ -0,0 +1,183 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// File: ListItem.h +// +// Description: BListView represents a one-dimensional list view. +// +// Copyright 2001, Ulrich Wimboeck +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include "MyListItem.h" + +/*----------------------------------------------------------------*/ +/*----- BListItem class ------------------------------------------*/ + +/** + * The constructors create a new BListItem object. The level and + * expanded arguments are only used if the item is added to a + * BOutlineListView object; see BOutlineListView::AddItem() for + * more information. The destructor is empty. + * + * @param outlineLevel Level of the + */ + +BListItem::BListItem(uint32 outlineLevel /* = 0 */, bool expanded /* = true */) + : fWidth(0), fHeight(0), fLevel(outlineLevel), fSelected(false), fEnabled(true), + fExpanded(expanded), fHasSubItems(false), fVisible(true) +{ +} + +BListItem::BListItem(BMessage* data) + : BArchivable(data), // first call the constructor of the base class + fWidth(0), fHeight(0), fLevel(0), fSelected(false), fEnabled(true), + fExpanded(true), fHasSubItems(false), fVisible(true) +{ + // get the data from the message + + if (data->FindBool("_sel", &fSelected) != B_OK) + fSelected = false ; + + if (data->FindBool("_disable", !fEnabled) != B_OK) + fEnabled = true ; + + if (data->FindBool("_li_expanded", fExpanded) != B_OK) + fExpanded = true ; + + if (data->FindInt32("_li_outline_level", fLevel) != B_OK) + fLevel = 0 ; +} + +BListItem::~BListItem() +{ + fWidth = 0 ; + fHeight = 0 ; + fLevel = 0 ; + fSelected = false ; + fEnabled = false ; +} + +status_t +BListItem::Archive(BMessage* data, bool deep /* = true */) const +{ + status_t tReturn = BArchivable::Archive(data, deep) ; + + if (tReturn != B_OK) + return tReturn ; + + tReturn = data->AddString("class", "BListItem") ; + + if (tReturn != B_OK) + return tReturn ; + + if (fSelected == true) + { + tReturn = data->AddBool("_sel", fSelected) ; + + if (tReturn != B_OK) + return tReturn ; + } + + if (fEnabled == false) + { + tReturn = data->AddBool("_disable", !fEnabled) ; + + if (tReturn != B_OK) + return tReturn ; + } + + if (!fExpanded) { + tReturn = data->AddInt32("_li_outline_level", fExpanded) ; + } + + return tReturn ; +} + +float +BListItem::Height() const +{ + return fHeight ; +} + +float +BListItem::Width() const +{ + return fWidth ; +} + +//inline +bool +BListItem::IsSelected() const +{ + return fSelected ; +} + +//inline +void +BListItem::Select() +{ + fSelected = true ; +} + +//inline +void +BListItem::Deselect() +{ + fSelected = false ; +} + +//inline +void +BListItem::SetEnabled(bool on) +{ + fEnabled = on ; +} + +//inline +bool +BListItem::IsEnabled() const +{ + return fEnabled ; +} + +//inline void +void BListItem::SetHeight(float height) +{ + fHeight = height ; +} + +//inline +void +BListItem::SetWidth(float width) +{ + fWidth = width ; +} + +void +BListItem::Update(BView* owner, const BFont* font) +{ + // Set the width of the item to the width of the owner + BRect rect(owner->Frame()) ; + SetWidth(rect.right - rect.left) ; + + // Set the height of the item to the height of the font + font_height height ; + font->GetHeight(&height) ; + SetHeight(height.leading + height.ascent + height.descent); +} + +status_t +BListItem::Perform(perform_code d, void* arg) +{ + status_t tReturn = B_OK ; + return tReturn ; +} + +inline uint32 +BListItem::OutlineLevel() const +{ + return fLevel ; +} diff --git a/src/kits/interface/ListView.cpp b/src/kits/interface/ListView.cpp new file mode 100644 index 0000000000..8e2b92172d --- /dev/null +++ b/src/kits/interface/ListView.cpp @@ -0,0 +1,1742 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// File: ListView.cpp +// +// Description: BListView represents a one-dimensional list view. +// +// Copyright 2001, Ulrich Wimboeck +// +//////////////////////////////////////////////////////////////////////////////// + +#include "ListView.h" +#include +#include +#include +#include +#include + + + +struct track_data +{ +} ; + +/** + * Initializes the new BListView. The frame, name, resizingMode, and flags + * arguments are identical to those declared for the BView class and are + * passed unchanged to the BView constructor. + * + * The list type can be either: + * B_SINGLE_SELECTION_LIST + * The user can select only one item in the list at a time. This is the + * default setting. + * B_MULTIPLE_SELECTION_LIST + * The user can select any number of items by holding down an Option + * key (for discontinuous selections) or a Shift key (for contiguous + * selections). + */ +BListView::BListView(BRect frame, const char *name, + list_view_type type /* = B_SINGLE_SELECTION_LIST */, + uint32 resizeMask /* = B_FOLLOW_LEFT | B_FOLLOW_TOP */, + uint32 flags /* = B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE */) + : BView(frame, name, resizeMask, flags) +{ + InitObject(type) ; +} + + +BListView::BListView(BMessage* data) + : BView(data) +{ + // if the pointer is null the object should be initialized anyway + if (data == NULL) { + InitObject(B_SINGLE_SELECTION_LIST) ; + return ; + } + + { + if (data->FindInt32("_lv_type", fListType) != B_OK) + fList = B_SINGLE_SELECTION_LIST ; + + // first check if a selection message is included in the messgage + // if there is one allocate memory for it and get it. + type_code code ; + + if (data->GetInfo("_2nd_msg", &code) == B_OK ) + { + if (code == B_MESSAGE_TYPE) + { + fSelectMessage = new BMessage() ; + data->FindMessage("_msg", fSelectMessage) ; + BInvoker::SetMessage(fSelectMessage) ; + + // set the fSelectMessage back to NULL + fSelectMessage = NULL ; + } + } + + // check if there is an invokation message stored + // in the archiv and set it + if (data->GetInfo("_msg", &code) == B_OK ) + { + if (code == B_MESSAGE_TYPE) + { + fSelectMessage = new BMessage() ; + data->FindMessage("_msg", fSelectMessage) ; + } + else { + fSelectMessage = NULL ; + } + } + + int32 count ; + + // add the item archivied in the message if it was a deep copy + if (data->GetInfo("_l_items", &code, &count) == B_OK) + { + if (code == B_MESSAGE_TYPE) + { + BMessage msg ; + BArchivable* unarchived ; + BListItem* item ; + + for (int32 i = 0 ; i < count ; ++i) + { + data->FindMessage("_l_items", i, &msg) ; + unarchived = instantiate_object(data) ; + item = dynamic_cast(unarchived) ; + + if (item != NULL) { + AddItem(item) ; + } + } + } + } + } +} + +/** + * Frees the selection and invocation messages, if any, and any memory + * allocated to hold the list of items, but not the items themselves. + */ +BListView::~BListView() +{ + // Remove all pointers from the list + fList.MakeEmpty() ; + + // delete the select message if there is one + // the invocation message is deleted by the destructor of BInvoker + if (fSelectMessage != NULL) + { + delete fSelectMessage ; + fSelectMessage = NULL ; + } + + if (fTrack != NULL) + { + delete fTrack ; + fTrack = NULL ; + } +} + +/** + * Returns a new BListView object, allocated by new and created + * with the version of the constructor that takes a BMessage + * archive. However, if the archive message doesn't contain + * data for a BListView object, this function returns NULL. + * + * @param data Pointer to a BMessge object containing the data + * of an archieved BListView object. + */ +BArchivable* +BListView::Instantiate(BMessage* data) +{ + if (validate_instantiation(data, "BListView")) + return new BListView(data) ; + + return NULL ; +} + +status_t +BListView::Archive(BMessage* data, bool deep /* = true */) const +{ + if (!data) + return B_ERROR ; + + BView::Archive(data, deep) ; + + data->AddString("class", "BListView") ; + data->AddInt32("_lv_type", fListType) ; + + if (fSelectMessage) { + data->AddMessage("_msg", fSelectMessage) ; + } + + if (BInvoker::Message()) { + data->AddMessage("_2nd_msg", BInvoker::Message()) ; + } + + if (deep) + { + BMessage* msg ; + + for (int i = 0 ; i < fList.CountItems() ; ++i) + { + msg = new BMessage() ; + ItemAt(i)->Archive(msg, deep) ; + data->AddMessage("_l_items", msg) ; + } + } + + return B_OK ; +} + +/** + * Calls upon every item in the updateRect area of the view to draw itself. + * Draw() is called for you whenever the list view is to be updated or + * redisplayed; you don't need to call it yourself. You also don't need to + * reimplement it; to change the way items are drawn, define a new version + * of DrawItem() in a class derived from BListItem. + */ +void +BListView::Draw(BRect updateRect) +{ + SetHighColor(0, 0 ,0) ; + + if (!fList.IsEmpty()) + { + // Find the first and the last item which has to be updated + float tmp = 0 ; + int32 firstIndex = 0 ; + + for ( ; firstIndex < fList.CountItems() ; ++firstIndex) + { + float help = (ItemAt(firstIndex))->Height() ; + tmp += help ; + if (tmp >= updateRect.top) + break ; + } + + int32 lastIndex = firstIndex ; + + for (; lastIndex < fList.CountItems() ; ++lastIndex) + { + //Draw the item + BRect rect(Bounds()); + rect.top = tmp - ItemAt(lastIndex)->Height() ; + rect.bottom = tmp ; + rect.right = 2000 ; + +// BRegion region ; + // region.Include(rect) ; + +// ConstrainClippingRegion(®ion) ; + ItemAt(lastIndex)->DrawItem(this, rect);//, true) ; + + if (tmp >= updateRect.bottom) + break ; + + tmp += ItemAt(lastIndex)->Height() ; + } + } +} + +void +BListView::MessageReceived(BMessage *msg) +{ + switch (msg->what) + { + // scripting stuff + case B_GET_SUPPORTED_SUITES: + { + BMessage reply(B_REPLY) ; + reply.AddString("suites", "suite/vnd.Be-list-view") ; + msg->SendReply(&reply) ; + break ; + } + case B_COUNT_PROPERTIES: + { + BMessage reply(B_REPLY) ; + reply.AddInt32("result", fList.CountItems()) ; + msg->SendReply(&reply) ; + break ; + } + case B_EXECUTE_PROPERTY: + break ; + case B_GET_PROPERTY: + break ; + case B_SET_PROPERTY: + break ; + case B_MOUSE_WHEEL_CHANGED: + break ; + } + + BView::MessageReceived(msg) ; +} + +/** + * Responds to B_MOUSE_DOWN messages by selecting items, invoking them + * (if the mouse-down event is the second of a double-click), and + * autoscrolling the list (when the user drags with a mouse button down). + * This function also calls InitiateDrag() to give derived classes the + * opportunity to drag items. You can implement that function; you shouldn't + * override (or call) this one. + */ + // The docu says shift key and option key like Windows but it does not. +void +BListView::MouseDown(BPoint where) +{ + int32 index = IndexOf(where) ; + + if (index >= 0) + { + bool extend = false ; + + if ((fListType == B_MULTIPLE_SELECTION_LIST) && (modifiers() & B_SHIFT_KEY)) + extend = true ; + + if (!ItemAt(index)->IsSelected()) + Select(index, extend) ; + else { + ItemAt(index)->Deselect() ; + InvalidateItem(index) ; + } + } + + MakeFocus() ; +} + +/** + * Permits the user to operate the list using the following keys: + * + * Up Arrow and Down Arrow + * Select the items that are immediately before and immediately after + * the currently selected item. + * + * Page Up and Page Down + * Select the items that are one viewful above and below the currently + * selected item—or the first and last items if there's no item a viewful away. + * + * Home and End + * Select the first and last items in the list. + * + * Enter and the space bar + * Invoke the current selection. + * + * This function also incorporates the inherited BView version so that the + * Tab key can navigate to another view. KeyDown() is called to report + * B_KEY_DOWN messages when the BListView is the focus view of the active + * window; you shouldn't call it yourself. + */ +void +BListView::KeyDown(const char *bytes, int32 numBytes) +{ + switch (*bytes) + { + // pressing the home key the first item in the list is selected + // and made visible + case B_HOME: + { + if (CountItems() > 0) + { + Select(0) ; + ScrollToSelection() ; + } + break; + } + // if the end key is pressed the last entry is selected and + // made visible + case B_END: + { + if (CountItems() > 0) + { + Select(CountItems() - 1) ; + ScrollToSelection() ; + } + break ; + } + // select the item above the first selected one + case B_UP_ARROW: + if (fFirstSelected > 0) + { + Select(fFirstSelected - 1) ; + ScrollToSelection() ; + } + break ; + // select the item below the last one + case B_DOWN_ARROW: + if ((fFirstSelected >= 0) && (fLastSelected < (fList.CountItems() - 1))) + { + Select(fLastSelected + 1) ; + ScrollToSelection() ; + } + break ; + case B_PAGE_UP: + { + BRect bounds(Bounds()) ; + BPoint top(bounds.left, bounds.top) ; + int32 index = IndexOf(top) ; + + if (index >= 0) + { + BRect frame(ItemFrame(index)) ; + + if ((frame.bottom - (bounds.bottom - bounds.top)) >= 0) + ScrollTo(bounds.left, frame.bottom - (bounds.bottom - bounds.top)) ; + else + ScrollTo(bounds.left, 0) ; + } + + break ; + } + case B_PAGE_DOWN: + { + BRect bounds(Bounds()) ; + BPoint bottom(bounds.left, bounds.bottom) ; + int32 index = IndexOf(bottom) ; + + if (index >= 0) + { + BRect frame(ItemFrame(index)) ; + float height ; + GetPreferredSize(NULL, &height) ; + + if ((bounds.bottom - bounds.top + frame.top) <= height) + { + ScrollTo(bounds.left, frame.top) ; + } + else { + ScrollTo(bounds.left, height - (bounds.bottom - bounds.top)) ; + } + } + + break; + } + // both, the space bar and the return key invoke the current selection + case B_SPACE: + case B_RETURN: + { + if (fFirstSelected >= 0) + { + Invoke() ; + } + break ; + } + } + BView::KeyDown(bytes, numBytes) ; +} + +/** + * Overrides the BView version of MakeFocus() to draw an indication that + * the BListView has become the focus for keyboard events when the + * focused flag is true, and to remove that indication when the flag is false. + */ +void +BListView::MakeFocus(bool state /* = true */) +{ + if (state != IsFocus()) + { + BView::MakeFocus(state) ; + } + + // if the list view is target of a scroll view + // the border of the scroll view needs to be set to the + // correct state + if (fScrollView != NULL) + { + fScrollView->SetBorderHighlighted(state) ; + } +} + +/** + * Updates the on-screen display in response to a notification that + * the BListView's frame rectangle has been resized. In particular, + * this function looks for a vertical scroll bar that's a sibling of + * the BListView. It adjusts this scroll bar to reflect the way the + * list view was resized, under the assumption that it must have the + * BListView as its target. + */ +void +BListView::FrameResized(float newWidth, float newHeight) +{ + // set the range of the scroll bars of the scroll view + FixupScrollBar() ; +} + +void +BListView::TargetedByScrollView(BScrollView *scroller) +{ +// if (fScrollView != NULL) + { + // delete fScrollView ; + } + + fScrollView = scroller ; +} + +void +BListView::ScrollTo(BPoint where) +{ + BView::ScrollTo(where) ; +} + +/** + * Adds an item to the BListView at the end of the list. If necessary, + * additional memory is allocated to accommodate the new item. + * Adding an item never removes an item already in the list. + * If the supplied pointer is NULL the function returns false. Otherwise, + * it returns true. + */ +bool +BListView::AddItem(BListItem *item) +{ + // check if the supplied pointer is NULL + bool bReturn = (item != NULL) ; + + if (bReturn) + { + if (bReturn = fList.AddItem(static_cast(item))) + { + // If the view is already attached to a view the item needs to be updated + if (Parent() != NULL) + { + BFont font ; + GetFont(&font) ; + item->Update(this, &font) ; + } + } + + // The new item needs to be drawn if visible + InvalidateItem(fList.CountItems() - 1) ; + } + + return bReturn ; +} + +/** + * Adds an item to the BListView at index. If necessary, additional memory is + * allocated to accommodate the new item. + * Adding an item never removes an item already in the list. If the item is + * added at an index that's already occupied, items currently in the list are + * bumped down one slot to make room. + * If index is out of range (greater than the current item count, or less than zero), this function fails and returns false. Otherwise, it returns + * true +*/ +bool +BListView::AddItem(BListItem *item, int32 atIndex) +{ + bool bReturn(item != NULL) ; + + // If successful invalidate all items starting at atIndex + if (bReturn) + { + if (bReturn = fList.AddItem(static_cast(item), atIndex)) + { + if (Parent() != NULL) + { + BFont font ; + GetFont(&font) ; + item->Update(this, &font) ; + } + } + + // The new item needs to drawn if visible + InvalidateFrom(atIndex) ; + } + + return bReturn ; +} + +/** + * Adds the contents of another list to this BListView. The items from + * the BList are appended to the end of the list. + * If the supplied pointer or one of the pointers within the list is NULL, + * the function fails and returns false. If successful, it returns true. + * The BListView doesn't check to be sure that all the items it adds from the + * list are pointers to BListItem objects. It assumes that they are; if the + * assumption is false, the program will crash. + */ +bool +BListView::AddList(BList* newItems) +{ + bool bReturn(newItems != NULL) ; + + if (bReturn) + { + for (int32 index = 0 ; index < newItems->CountItems() ; ++index) + { + if (newItems->ItemAt(index) == NULL) + { + bReturn = false ; + break ; + } + } + + if (bReturn) + { + int32 index = CountItems() ; + fList.AddList(newItems) ; + InvalidateFrom(index) ; + + if (Parent() != NULL) + { + BFont font ; + GetFont(&font) ; + + for (int32 index = CountItems() - fList.CountItems() ; + index < CountItems() ; ++index) + { + ItemAt(index)->Update(this, &font) ; + } + } + } + } + + return bReturn ; +} + +/** + * Adds the contents of another list to this BListView. The items from the + * BList are inserted at index. + * If the supplied pointer or one of the pointers within the list is NULL or + * the index is out of range, the function, fails and returns false. + * If successful, it returns true. + * The BListView doesn't check to be sure that all the items it adds from + * the list are pointers to BListItem objects. It assumes that they are; if the + * assumption is false, the program will crash. + */ +bool +BListView::AddList(BList *newItems, int32 atIndex) +{ + bool bReturn(newItems != NULL) ; + + if (bReturn) + { + for (int32 index = 0 ; index < newItems->CountItems() ; ++index) + { + if (newItems->ItemAt(index) == NULL) + { + bReturn = false ; + break ; + } + } + + if (bReturn) + { + fList.AddList(newItems, atIndex) ; + InvalidateFrom(atIndex) ; + + if (Parent() != NULL) + { + BFont font ; + GetFont(&font) ; + + for (int32 index = CountItems() - fList.CountItems() ; + index < CountItems() ; ++index) + { + ItemAt(index)->Update(this, &font) ; + } + } + } + } + + return bReturn ; +} + +/** + * Removes a single item from the BListView. If passed an index, + * it removes the item at that index and returns it. If there's no + * item at the index, it returns NULL. If passed an item, this + * function looks for that particular item in the list, removes it, + * and returns true. If it can't find the item, it returns false. + * If the item is in the list more than once, this function removes + * only its first occurrence. + */ +bool +BListView::RemoveItem(BListItem* item) +{ + bool bReturn = false ; + // Remember the position of the item + int32 index = IndexOf(item) ; + bReturn = fList.RemoveItem(static_cast(item)) ; + + // update all items with a higher index than the removed item + if (bReturn) + { + for ( ; index < fList.CountItems() ; ++index) + { + InvalidateItem(index) ; + } + } + + return bReturn ; +} + +BListItem* +BListView::RemoveItem(int32 index) +{ + BListItem* item = static_cast(fList.RemoveItem(index)) ; + + // update all items with a higher index than the removed item + if (item != NULL) + { + for ( ; index < fList.CountItems() ; ++index) + { + InvalidateItem(index) ; + } + } + + return item ; +} + +bool +BListView::RemoveItems(int32 index, int32 count) +{ + bool bReturn = fList.RemoveItems(index, count) ; + + // update all items with a higher index than the last removed item + if (bReturn) + { + for ( ; index < fList.CountItems() ; ++index) + { + InvalidateItem(index) ; + } + } + + return bReturn ; +} + + +/** + * These functions set, and return information about, the message that + * a BListView sends whenever a new item is selected. They're exact + * counterparts to the functions described above under SetInvocationMessage(), + * except that the selection message is sent whenever an item in the list + * is selected, rather than when invoked. It's more common to take action + * (to initiate a message) when invoking an item than when selecting one. + */ +void +BListView::SetSelectionMessage(BMessage *message) +{ + if (fSelectMessage != NULL) + { + delete fSelectMessage ; + } + + fSelectMessage = message ; +} + +BMessage* +BListView::SelectionMessage() const +{ + return fSelectMessage ; +} + +uint32 +BListView::SelectionCommand() const +{ + if (fSelectMessage) + return fSelectMessage->what ; + else + return 0 ; +} + +void +BListView::SetInvocationMessage(BMessage *message) +{ + BInvoker::SetMessage(message) ; +} + +/** + * These functions set and return information about the BMessage + * that the BListView sends when currently selected items are invoked. + * SetInvocationMessage() assigns message to the BListView, freeing + * any message previously assigned. The message becomes the responsibility + * of the BListView object and will be freed only when it's replaced by + * another message or the BListView is freed; you shouldn't free it + * yourself. + * Passing a NULL pointer to this function deletes the current message + * without replacing it. + * When sending the message, the Invoke() function makes a copy of it + * and adds two pieces of relevant information—"when" the message is + * sent and the "source" BListView. These names should not be used for + * any data that you add to the invocation message. + * InvocationMessage() returns a pointer to the BMessage and + * InvocationCommand() returns its what data member. The message + * belongs to the BListView; it can be altered by adding or removing + * data, but it shouldn't be deleted. To get rid of the current message, + * pass a NULL pointer to SetInvocationMessage(). + */ +BMessage* +BListView::InvocationMessage() const +{ + return BInvoker::Message() ; +} + + +uint32 +BListView::InvocationCommand() const +{ + return BInvoker::Command() ; +} + +/** + * These functions set and return the list type—whether or not + * it permits multiple selections. The list_view_type must be either + * B_SINGLE_SELECTION_LIST or B_MULTIPLE_SELECTION_LIST. The type + * is first set when the BListView is constructed. + */ +void +BListView::SetListType(list_view_type type) +{ + if (type != fListType) + { + // When the type is changed from B_MULTIPLE_SELECTION_LIST to + // B_SINGLE_SELECTION_LIST all selected items will be deselcted. + if (fListType == B_MULTIPLE_SELECTION_LIST) + { + for (int32 item = fFirstSelected ; item <= fLastSelected ; ++item) + { + if (ItemAt(item)->IsSelected()) + { + ItemAt(item)->Deselect() ; + InvalidateItem(item) ; + } + } + } + + fListType = type ; + } +} + +list_view_type +BListView::ListType() const +{ + return fListType ; +} + +/** + * This function returns the BListItem at index in the list, or NULL if the + * list is empty. + * The function does not alter the contents of the list—they don't remove the returned + * item. + */ +BListItem* +BListView::ItemAt(int32 index) const +{ + return static_cast(fList.ItemAt(index)) ; +} + +/** + * Returns the index where a particular item whose display rectangle + * includes a particular point—is located in the list. + * To determine whether an item lies at the specified point, only + * the y-coordinate value of the point is considered. + * If the item isn't in the list or the y-coordinate of the point + * doesn't intersect with the data rectangle of the BListView, the return + * value will be a negative number. + */ +int32 +BListView::IndexOf(BPoint point) const +{ + float tmp = 0 ; + + for (int32 index = 0 ; index < fList.CountItems() ; ++index) + { + tmp += ItemAt(index)->Height() ; + + if (point.y < tmp) + { + return index ; + } + } + + return -1 ; +} + +/** + * Returns the index where a particular item is located in the list. + * If the item is in the list more than once, the index returned will + * be the position of its first occurrence. + * If the item isn't in the list of the BListView, the return value + * will be a negative number. + */ +int32 +BListView::IndexOf(BListItem *item) const +{ + return fList.IndexOf(static_cast(item)) ; +} + + +/** + * This function returns the very first in the list, or NULL if the list is empty. + * The function does not alter the contents of the list—they don't remove the returned + * item. + */ +BListItem* +BListView::FirstItem() const +{ + return static_cast(fList.FirstItem()) ; +} + +/** + * This function returns the very last in the list, or NULL if the list is empty. + * The function does not alter the contents of the list—they don't remove the returned + * item. + */ + +BListItem* +BListView::LastItem() const +{ + return static_cast(fList.FirstItem()) ; +} + +/** + * Returns true if item is in the list, and false if not. + */ +bool +BListView::HasItem(BListItem *item) const +{ + return fList.HasItem(static_cast(item)) ; +} + +/** + * Returns the number of BListItems currently in the list. + */ +int32 +BListView::CountItems() const +{ + return fList.CountItems() ; +} + +/** + * MakeEmpty() empties the BListView of all its items, without freeing + * the BListItem objects. + */ +void +BListView::MakeEmpty() +{ + // Remove all items from the list + fList.MakeEmpty() ; + fFirstSelected = -1 ; + + // update the list view + Invalidate() ; +} + +/** + * IsEmpty() returns true if the list is empty (if it contains no items), + * and false otherwise. + */ +bool +BListView::IsEmpty() const +{ + return fList.IsEmpty() ; +} + +/** + * Calls the func function once for each item in the BListView. + * BListItems are visited in order, beginning with the first one in + * the list (index 0) and ending with the last. + * If a call to func returns true, the iteration is stopped, even + * if some items have not yet been visited. + */ +void +BListView::DoForEach(bool (*func)(BListItem *)) +{ + fList.DoForEach(reinterpret_cast(func)) ; +} + +/** + * Calls the func function once for each item in the BListView. + * BListItems are visited in order, beginning with the first one in + * the list (index 0) and ending with the last. + * If a call to func returns true, the iteration is stopped, even + * if some items have not yet been visited. + */ +void +BListView::DoForEach(bool (*func)(BListItem *, void *), void* parameter) +{ + fList.DoForEach(reinterpret_cast(func), parameter) ; +} + +/** + * Returns a pointer to the BListView's list of BListItems. You can index + * directly into the list of items if you're certain that the index is in range: + * BListItem *item = Items()[index] ; + * + * Although the practice is discouraged, you can also step through the list + * of items by incrementing the list pointer that Items() returns. Be aware + * that the list isn't null-terminated—you have to detect the end of the + * list by some other means. The simplest method is to count items: + * + * BListItem **ptr = myListView->Items() ; + * + * for ( long i = myListView->CountItems(); i > 0; i-- ) + * { + *   . . . + *  *ptr++ ; + * } + * + * You should never use the items pointer to alter the contents of the list. + */ +const BListItem** +BListView::Items() const +{ + return reinterpret_cast(fList.Items()) ; +} + +/** + * Invalidates the item at index so that an update message will + * be sent forcing the BListView to redraw it. + */ +void +BListView::InvalidateItem(int32 index) +{ + if (index <= fList.CountItems()) + { + // Invalidate the rectangle of the list item + Invalidate(Bounds() | ItemFrame(index)) ; + } +} + +void +BListView::ScrollToSelection() +{ + if (fFirstSelected != -1) + { + float tmp = 0 ; + int32 index = 0 ; + + for ( ; index < fFirstSelected ; ++index) + { + tmp += ItemAt(index)->Height() ; + } + + BRect rect (Bounds()) ; + + if (tmp < rect.top) + { + ScrollTo(0, tmp) ; + } + else if ((tmp + ItemAt(index)->Height()) > rect.bottom) + { + ScrollTo(0, tmp + ItemAt(index)->Height() - (rect.bottom - rect.top)) ; + } + } +} + +/** + * Selects the item at the index + * if extend is false all former selections will be removed + * if extend is true the + */ +void +BListView::Select(int32 index, bool extend /* = false */) +{ + // The index must be in range + if (index < fList.CountItems() && (index >= 0)) + { + // Deselect all selected items + if ((fFirstSelected != -1) && (!extend)) + { + for (int32 item = fFirstSelected ; item <= fLastSelected ; ++item) + { + if ((ItemAt(item)->IsSelected()) && (item != index)) + { + ItemAt(item)->Deselect() ; + InvalidateItem(item) ; + } + } + + // No item is selected any more + fFirstSelected = -1 ; + } + + if (fFirstSelected == -1) + { + fFirstSelected = index ; + fLastSelected = index ; + } + else if (index < fFirstSelected) + fFirstSelected = index ; + else if (index > fLastSelected) + fLastSelected = index ; + + if (!ItemAt(index)->IsSelected()) + { + ItemAt(index)->Select() ; + InvalidateItem(index) ; + } + + SelectionChanged() ; + } +} + +void +BListView::Select(int32 from, int32 to, bool extend /* = false */) +{ + if ((from <= to) && (to < fList.CountItems())) + { + // Deselect all current selected items + if (!extend) + { + } + + for (int32 index = from ; index <= to ; ++index) + { + ItemAt(index)->Select() ; + } + } +} + +/** + * Returns true if the item at index is currently selected, and false if it's not. + * It also returns false if the index is not in the range an therefoe does not + * exist. + */ +bool +BListView::IsItemSelected(int32 index) const +{ + if ((fFirstSelected >= 0) && (index >= fFirstSelected) && (index <= fLastSelected)) + return ItemAt(index)->IsSelected() ; + + return false ; +} + +/** + * Returns the index of a currently selected item in the list, or + * a negative number if no item is selected. + * The domain of the index passed as an argument is the current set + * of selected items; the first selected item is at index 0, the second + * at index 1, and so on, even if the selection is not contiguous. The + * domain of the returned index is the set of all items in the list. + * + * To get all currently selected items, increment the passed index until + * the function returns a negative number. + */ +int32 +BListView::CurrentSelection(int32 index /* = 0 */) const +{ + if ((index >= 0) && (fFirstSelected >= 0)) + { + for (int32 count = (fFirstSelected > index ? fFirstSelected : index) ; + count <= fLastSelected ; ++count) + { + if (ItemAt(count)->IsSelected()) + { + --index ; + + if (index == 0) + { + return count ; + } + } + } + } + + return -1 ; +} + +/** + * Augments the BInvoker version of Invoke() to add three pieces of information + * to each message the BListView sends: + * + * "when" - B_INT64_TYPE + * When the message is sent, as measured by the number of microseconds + * since 12:00:00 AM 1970. + * + * "source" - B_POINTER_TYPE + * A pointer to the BListView object. + * + * "index" - B_INT32_TYPE + * An array containing the index of every selected item. + * + * This function is called to send both the selection message and the + * invocation message. It can also be called from application code. The default + * target of the message (established by AttachedToWindow()) is the BWindow + * where the BListView is located. + * What it means to "invoke" selected items depends entirely on the + * invocation BMessage and the receiver's response to it. This function does + * nothing but send the message. + */ + + // check if it is done in the right way +status_t +BListView::Invoke(BMessage* msg /* = NULL */) +{ + return BInvoker::Invoke(msg) ; +} + +/** + * This function deselects all the items. + */ +void +BListView::DeselectAll() +{ + if (fFirstSelected != -1) + { + for (int32 index = fFirstSelected ; index <= fLastSelected ; ++index) + { + if (!ItemAt(index)->IsSelected()) + { + ItemAt(index)->Deselect() ; + InvalidateItem(index) ; + } + } + } +} + +/** + * This function deselects all the items except those from index start through + * index finish. + */ +void +BListView::DeselectExcept(int32 except_from, int32 except_to) +{ + // if no item is selected -> nothing to do + if ((fFirstSelected != -1) && (except_from <= except_to)) + { + for (int32 index = fFirstSelected ; index < except_from ; ++index) + { + if (!ItemAt(index)->IsSelected()) + { + ItemAt(index)->Deselect() ; + InvalidateItem(index) ; + } + } + for (int32 index = except_to + 1 ; index <= fLastSelected ; ++index) + { + if (!ItemAt(index)->IsSelected()) + { + ItemAt(index)->Deselect() ; + InvalidateItem(index) ; + } + } + + SelectionChanged() ; + } +} + +/** + * These functions deselect the item at index. + */ +void +BListView::Deselect(int32 index) +{ + if (fFirstSelected != -1) + { + if ((index < fLastSelected) && (index >= fFirstSelected)) + { + if (!ItemAt(index)->IsSelected()) + { + ItemAt(index)->Deselect() ; + InvalidateItem(index) ; + SelectionChanged() ; + } + } + } +} + +// Implemented by derived class +void +BListView::SelectionChanged() +{ +} + +void +BListView::SortItems(int (*cmp)(const void *, const void *)) +{ + fList.SortItems(cmp) ; + Invalidate() ; +} + + +/* These functions bottleneck through DoMiscellaneous() */ +bool +BListView::SwapItems(int32 a, int32 b) +{ + bool success = true ; + + if ((a >= 0) && (a < fList.CountItems()) && (b >= 0) && (b < fList.CountItems())) + { + // just swap if a is not b + if (a != b) + { + // ToDo chack if it is done correct + BListItem* item = RemoveItem(a) ; + AddItem(item, b - 1) ; + item = RemoveItem(b) ; + AddItem(item, a) ; + } + } + else { + success = false ; + } + + return success ; +} + +/** + * MoveItem() moves the item located at the index from to the index + * specified by the to argument. + * This function returns true if the requested operation is + * completed successfully, or false if the operation failed (for example, + * if a specified index is out of range). + */ + + // Is redraw neccessary???? +bool +BListView::MoveItem(int32 from, int32 to) +{ + bool success = true ; + + if ((to >= 0) && (to < fList.CountItems())) + { + // no move required if from would be to + if (from != to) + { + BListItem* item = RemoveItem(from) ; + + if (item != NULL) + AddItem(item, to - 1) ; + else + success = false ; + } + } + else { + success = false ; + } + + return success ; +} + +bool +BListView::ReplaceItem(int32 index, BListItem* item) +{ + bool success = true ; + + // otherwise the "new" item would be deleted + if (ItemAt(index) != item) + { + BListItem* old = RemoveItem(index) ; + + if (old != NULL) + { + AddItem(item, index) ; + delete old ; + } + // In this case the index is not in the range + else { + success = false ; + } + } + + return success ; +} + +/** + * Sets up the BListView and makes the BWindow to which it has become + * attached the target for the messages it sends when items are selected + * or invoked—provided another target hasn't already been set. In addition, + * this function calls Update() for each item in the list to give it a + * chance to adjust its layout. The BListView's vertical scroll bar is + * also adjusted. + * This function is called for you when the BListView becomes part of a + * window's view hierarchy. + */ +void +BListView::AttachedToWindow() +{ + // If no target is set the window to which the ListView is attached will + // become the target + if (BInvoker::Target() == NULL) + { + BInvoker::SetTarget(BView::Window()) ; + } + + // call the update function of all items in the list + for (int32 index = 0 ; index < fList.CountItems() ; ++index) + { + BFont font ; + BView::GetFont(&font) ; + ItemAt(index)->Update(this, &font) ; + + if (fWidth < ItemAt(index)->Width()) + fWidth = ItemAt(index)->Width() ; + } + + // Adjust the ScrollBars. + FixupScrollBar() ; +} + +void +BListView::FrameMoved(BPoint new_position) +{ +} + +/** + * Returns the frame rectangle of the BListItem at index. The rectangle is stated + * in the coordinate system of the BListView and defines the area where the item + * is drawn. Items can differ in height, (but all have the same width ??). + */ +BRect +BListView::ItemFrame(int32 index) +{ + BRect rect ; + + if ((index < fList.CountItems()) && (index >= 0)) + { + rect.left = 0 ; + + for (int32 item = 0 ; item < index ; ++item) + { + rect.top += ItemAt(item)->Height() ; + } + + rect.bottom = rect.top + ItemAt(index)->Height() ; + rect.right = Bounds().right ; + } + + return rect ; +} + +BHandler* +BListView::ResolveSpecifier(BMessage *msg, int32 index, + BMessage *specifier, int32 form, + const char *property) +{ + return NULL ; +} + +status_t +BListView::GetSupportedSuites(BMessage *data) +{ + return B_OK ; +} + +status_t +BListView::Perform(perform_code d, void *arg) +{ + return B_OK ; +} + +void +BListView::WindowActivated(bool state) +{ +} + +void +BListView::MouseUp(BPoint pt) +{ + int32 index = IndexOf(pt) ; + + if ((index > 0) && (fListType == B_MULTIPLE_SELECTION_LIST) && ((modifiers() & B_SHIFT_KEY))) + { + if (!ItemAt(index)->IsSelected()) + Deselect(index) ; + } +} + +void +BListView::MouseMoved(BPoint pt, uint32 code, const BMessage *msg) +{ +} + +void +BListView::DetachedFromWindow() +{ +} + +/** + * Implemented by derived classes to permit users to drag items. + * This function is called from the BListView's MouseDown() function; + * it should initiate the drag-and-drop operation and return true, + * or refuse to do so and return false. By default, it always + * returns false. + * The point that's passed to InitiateDrag() is the same as the + * point passed to MouseDown(); it's where the cursor was located + * when the user pressed the mouse button. The index of the item + * under the cursor (the item that would be dragged) is passed as the + * second argument, and the wasSelected flag indicates whether or + * not the item was selected before the mouse button went down. + * + * A BListView allows users to autoscroll the list by holding the + * mouse button down and dragging outside its frame rectangle. If a + * derived class implements InitiateDrag() to drag an item each time + * the user moves the mouse with a button down, it will hide this + * autoscrolling behavior. Therefore, derived classes typically + * permit users to drag items only if they're already selected (if + * wasSelected is true). In other words, it takes two mouse-down events + * to drag an item—one to select it and one to begin dragging it. + */ +bool +BListView::InitiateDrag(BPoint pt, int32 itemIndex, bool initialySelected) +{ + return false ; +} + +void +BListView::ResizeToPreferred() +{ +} + +void +BListView::GetPreferredSize(float* width, float* height) +{ + if (height != NULL) + { + *height = 0 ; + + for (int32 index = 0 ; index < CountItems() ; ++index) + { + *height += ItemAt(index)->Height() ; + } + } + + if (width != NULL) + *width = 0 ; +} + +void +BListView::AllAttached() +{ +} + +void +BListView::AllDetached() +{ +} + +//--------------------------------------------------------------------------- +// protected! + +bool +BListView::DoMiscellaneous(MiscCode code, MiscData* data) +{ + switch(code) + { + case B_NO_OP: + break; + + case B_REPLACE_OP: + data->replace.index ; + data->replace.item ; + break ; + + case B_MOVE_OP: + data->move.from ; + data->move.to ; + break ; + + case B_SWAP_OP: + data->swap.a ; + data->swap.b ; + break ; + } + + return true ; +} + +/*----- Private or reserved -----------------------------------------*/ + +void +BListView::InitObject(list_view_type type) +{ + fList.MakeEmpty() ; + fListType = type ; + fFirstSelected = -1 ; +/* +int32 fLastSelected; +int32 fAnchorIndex; +*/ + fWidth = 0 ; + fSelectMessage = NULL ; + fScrollView = NULL ; + fTrack = NULL ; +} + +/** + * Updates the scroll bars if the list view is targetted by a scroll view + */ +void +BListView::FixupScrollBar() +{ + // set the range of the scroll bars of the scroll view + if (fScrollView != NULL) + { + BScrollBar* bar ; + float height ; + float width ; + BRect bounds(Bounds()) ; + + GetPreferredSize(&width, &height) ; + height -= (bounds.bottom - bounds.top) ; + width -= (bounds.right - bounds.left) ; + + if (height < 0) + height = 0 ; + + if (width < 0) + width = 0 ; + + if ((bar = fScrollView->ScrollBar(B_HORIZONTAL)) != NULL) + { + bar->SetRange(0, width) ; + bar->SetSteps(ItemAt(0)->Height(), bounds.bottom - bounds.top) ; + } + + if ((bar = fScrollView->ScrollBar(B_VERTICAL)) != NULL) + { + bar->SetRange(0, height) ; + bar->SetSteps(ItemAt(0)->Height(), bounds.bottom - bounds.top) ; + } + } +} + +void +BListView::InvalidateFrom(int32 index) +{ + if ((index >= 0) && (index < CountItems())) + { + BRect frame(ItemFrame(index)) ; + + for (++index ; index < fList.CountItems() ; ++index) + frame.bottom += ItemAt(index)->Height() ; + + // build the rect which needs an update + BRect bounds(Bounds()) ; + frame = frame & bounds ; + frame = frame | bounds ; + Invalidate(frame) ; + } +} + +inline status_t +BListView::PostMsg(BMessage* msg) +{ + return BInvoker::Invoke(msg) ; +} + +void +BListView::FontChanged() +{ + // all items need to be updated + for (int32 i = 0 ; i < fList.CountItems() ; ++i) + { + ItemAt(i)->Update(this, NULL) ; + } +} + +int32 +BListView::RangeCheck(int32 index) +{ + return 0 ; +} + +bool +BListView::_Select(int32 index, bool extend) +{ + return true ; +} + +bool +BListView::_Select(int32 from, int32 to, bool extend) +{ + return true ; +} + +bool +BListView::_Deselect(int32 index) +{ + return true ; +} + +void +BListView::Deselect(int32 from, int32 to) +{ + for ( ; (from <= to) && (from < fList.CountItems()) ; ++from) + { + ItemAt(from)->Deselect() ; + } +} + +bool +BListView::_DeselectAll(int32 except_from, int32 except_to) +{ + for (int32 i = 0 ; i < CountItems() ; ++i) + { + if (i == except_from) + { + i = except_to ; + if (i >= CountItems()) + break ; + } + + ItemAt(i)->Deselect() ; + } + + return true ; +} + +void +BListView::PerformDelayedSelect() +{ +} + +bool +BListView::TryInitiateDrag(BPoint where) +{ + return true ; +} + +int32 +BListView::CalcFirstSelected(int32 after) +{ + return 0 ; +} + +int32 +BListView::CalcLastSelected(int32 before) +{ + return 0 ; +} + +void +BListView::DrawItem(BListItem* item, BRect itemRect, + bool complete /* = false */) +{ +} + +bool +BListView::DoSwapItems(int32 a, int32 b) +{ + return true ; +} + +bool +BListView::DoMoveItem(int32 from, int32 to) +{ + return true ; +} + +bool +BListView::DoReplaceItem(int32 index, BListItem* item) +{ + return true ; +} + +void +BListView::RescanSelection(int32 from, int32 to) +{ +} + +void +BListView::DoMouseUp(BPoint where) +{ +} + +void +BListView::DoMouseMoved(BPoint where) +{ +} diff --git a/src/kits/interface/Point.cpp b/src/kits/interface/Point.cpp new file mode 100644 index 0000000000..8ddd38f1c7 --- /dev/null +++ b/src/kits/interface/Point.cpp @@ -0,0 +1,101 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: Point.cpp +// Author: Frans van Nispen +// Description: BPoint represents a single x,y coordinate. +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- +#include +#include + +// System Includes ------------------------------------------------------------- +#include +#include +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + + +//------------------------------------------------------------------------------ +void BPoint::ConstrainTo(BRect r) +{ + x = max_c(min_c(x, r.right), r.left); + y = max_c(min_c(y, r.bottom), r.top); +} +//------------------------------------------------------------------------------ +void BPoint::PrintToStream() const +{ + printf("BPoint(x:%.0f, y:%.0f)\n", x, y); +} +//------------------------------------------------------------------------------ +BPoint BPoint::operator+(const BPoint& p) const +{ + return BPoint(x + p.x, y + p.y); +} +//------------------------------------------------------------------------------ +BPoint BPoint::operator-(const BPoint& p) const +{ + return BPoint(x - p.x, y - p.y); +} +//------------------------------------------------------------------------------ +BPoint& BPoint::operator+=(const BPoint& p) +{ + x += p.x; + y += p.y; + + return *this; +} +//------------------------------------------------------------------------------ +BPoint& BPoint::operator-=(const BPoint& p) +{ + x -= p.x; + y -= p.y; + + return *this; +} +//------------------------------------------------------------------------------ +bool BPoint::operator!=(const BPoint& p) const +{ + return x != p.x || y != p.y; +} +//------------------------------------------------------------------------------ +bool BPoint::operator==(const BPoint& p) const +{ + return x == p.x && y == p.y; +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/kits/interface/PrintJob.cpp b/src/kits/interface/PrintJob.cpp new file mode 100644 index 0000000000..bf5775e32e --- /dev/null +++ b/src/kits/interface/PrintJob.cpp @@ -0,0 +1,265 @@ +/* + +BPrintJob code. + +Main functionality is the creation of the spool file. The print_server +will take it from there. + +Copyright (c) 2001 OpenBeOS. Written by I.R. Adema. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#include "PrintJob.h" + +// ----------------------------------------------------------------------------- +BPrintJob::BPrintJob(const char *job_name) + : + print_job_name(NULL), + page_number(0), + spoolFile(NULL), + pr_error(B_OK), + setup_msg(NULL), + default_setup_msg(NULL), + m_curPageHeader(NULL) +{ + print_job_name = new char[strlen(job_name)+1]; + ::strcpy(print_job_name, job_name); +} + +// ----------------------------------------------------------------------------- +BPrintJob::~BPrintJob() +{ + delete print_job_name; +} + +// ----------------------------------------------------------------------------- +void +BPrintJob::BeginJob() +{ +} + +// ----------------------------------------------------------------------------- +void +BPrintJob::CommitJob() +{ +} + +// ----------------------------------------------------------------------------- +status_t +BPrintJob::ConfigJob() +{ + return B_OK; +} + +// ----------------------------------------------------------------------------- +void +BPrintJob::CancelJob() +{ +} + +// ----------------------------------------------------------------------------- +status_t +BPrintJob::ConfigPage() +{ + return B_OK; +} + +// ----------------------------------------------------------------------------- +void +BPrintJob::SpoolPage() +{ +} + +// ----------------------------------------------------------------------------- +bool +BPrintJob::CanContinue() +{ + // Check if our local error storage is still B_OK + return pr_error == B_OK && !stop_the_show; +} + + +// ----------------------------------------------------------------------------- +void +BPrintJob::DrawView(BView *a_view, + BRect a_rect, + BPoint where) +{ +} + + +// ----------------------------------------------------------------------------- +BMessage * +BPrintJob::Settings() +{ + return NULL; +} + +// ----------------------------------------------------------------------------- +void +BPrintJob::SetSettings(BMessage *a_msg) +{ +} + +// ----------------------------------------------------------------------------- +bool +BPrintJob::IsSettingsMessageValid(BMessage *a_msg) const +{ + return true; +} + +// ----------------------------------------------------------------------------- +BRect +BPrintJob::PaperRect() +{ + return paper_size; +} + +// ----------------------------------------------------------------------------- +BRect +BPrintJob::PrintableRect() +{ + return usable_size; +} + +// ----------------------------------------------------------------------------- +void +BPrintJob::GetResolution(int32 *xdpi, + int32 *ydpi) +{ + *xdpi = v_xres; + *ydpi = v_yres; +} + +// ----------------------------------------------------------------------------- +int32 +BPrintJob::FirstPage() +{ + return first_page; +} + +// ----------------------------------------------------------------------------- +int32 +BPrintJob::LastPage() +{ + return last_page; +} + +// ----------------------------------------------------------------------------- +int32 +BPrintJob::PrinterType(void *) const +{ + return B_COLOR_PRINTER; +} + +#if 0 +#pragma mark ----- PRIVATE ----- +#endif + +// ----------------------------------------------------------------------------- +void +BPrintJob::RecurseView(BView *v, + BPoint origin, + BPicture *p, + BRect r) +{ +} + +// ----------------------------------------------------------------------------- +void +BPrintJob::MangleName(char *filename) +{ +} + +// ----------------------------------------------------------------------------- +void +BPrintJob::HandlePageSetup(BMessage *setup) +{ +} + +// ----------------------------------------------------------------------------- +bool +BPrintJob::HandlePrintSetup(BMessage *setup) +{ + return true; +} + +// ----------------------------------------------------------------------------- +void +BPrintJob::NewPage() +{ +} + +// ----------------------------------------------------------------------------- +void +BPrintJob::EndLastPage() +{ +} + +// ----------------------------------------------------------------------------- +void +BPrintJob::AddSetupSpec() +{ +} + +// ----------------------------------------------------------------------------- +void +BPrintJob::AddPicture(BPicture *picture, + BRect *rect, + BPoint where) +{ +} + +// ----------------------------------------------------------------------------- +char * +BPrintJob::GetCurrentPrinterName() const +{ + return NULL; +} + +// ----------------------------------------------------------------------------- +void +BPrintJob::LoadDefaultSettings() +{ +} + + + +// ----------------------------------------------------------------------------- +void +BPrintJob::_ReservedPrintJob1() +{ +} + +void +BPrintJob::_ReservedPrintJob2() +{ +} + +void +BPrintJob::_ReservedPrintJob3() +{ +} + +void +BPrintJob::_ReservedPrintJob4() +{ +} diff --git a/src/kits/interface/RadioButton.cpp b/src/kits/interface/RadioButton.cpp new file mode 100644 index 0000000000..aef86aea97 --- /dev/null +++ b/src/kits/interface/RadioButton.cpp @@ -0,0 +1,404 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: RadioButton.cpp +// Author: Marc Flerackers (mflerackers@androme.be) +// Description: BRadioButton represents a single on/off button. All +// sibling BRadioButton objects comprise a single +// "multiple choice" control. +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +BRadioButton::BRadioButton(BRect frame, const char *name, const char *label, + BMessage *message, uint32 resizMask, uint32 flags) + : BControl(frame, name, label, message, resizMask, flags), + fOutlined(false) +{ + if (Bounds().Height() < 18.0f) + ResizeTo(Bounds().Width(), 18.0f); +} +//------------------------------------------------------------------------------ +BRadioButton::BRadioButton(BMessage *archive) + : BControl(archive), + fOutlined(false) +{ +} +//------------------------------------------------------------------------------ +BRadioButton::~BRadioButton() +{ +} +//------------------------------------------------------------------------------ +BArchivable *BRadioButton::Instantiate(BMessage *archive) +{ + if (validate_instantiation(archive, "BRadioButton")) + return new BRadioButton(archive); + else + return NULL; +} +//------------------------------------------------------------------------------ +status_t BRadioButton::Archive(BMessage *archive, bool deep) const +{ + return BControl::Archive(archive, deep); +} +//------------------------------------------------------------------------------ +void BRadioButton::Draw(BRect updateRect) +{ + // Placeholder until sBitmaps is filled in + rgb_color no_tint = ui_color(B_PANEL_BACKGROUND_COLOR), + lighten1 = tint_color(no_tint, B_LIGHTEN_1_TINT), + lightenmax = tint_color(no_tint, B_LIGHTEN_MAX_TINT), + darken1 = tint_color(no_tint, B_DARKEN_1_TINT), + darken2 = tint_color(no_tint, B_DARKEN_2_TINT), + darken3 = tint_color(no_tint, B_DARKEN_3_TINT), + darken4 = tint_color(no_tint, B_DARKEN_4_TINT), + darkenmax = tint_color(no_tint, B_DARKEN_MAX_TINT); + + BRect rect(1.0, 3.0, 13.0, 15.0); + + if (IsEnabled()) + { + // Dot + if (Value() == B_CONTROL_ON) + { + rgb_color kb_color = ui_color(B_KEYBOARD_NAVIGATION_COLOR); + + SetHighColor(tint_color(kb_color, B_DARKEN_3_TINT)); + FillEllipse(rect); + SetHighColor(kb_color); + FillEllipse(BRect(rect.left + 3, rect.top + 3, rect.right - 4, rect.bottom - 4)); + SetHighColor(tint_color(kb_color, B_DARKEN_3_TINT)); + StrokeLine(BPoint(rect.right - 5, rect.bottom - 4), + BPoint(rect.right - 4, rect.bottom - 5)); + SetHighColor(tint_color(kb_color, B_LIGHTEN_MAX_TINT)); + StrokeLine(BPoint(rect.left + 4, rect.top + 5), + BPoint(rect.left + 5, rect.top + 4)); + + } + else + { + SetHighColor(lightenmax); + FillEllipse(rect); + } + + // Outer circle + if (fOutlined) + { + SetHighColor(darken3); + StrokeEllipse(rect); + } + else + { + SetHighColor(darken1); + StrokeArc(rect, 45.0f, 180.0f); + SetHighColor(lightenmax); + StrokeArc(rect, 45.0f, -180.0f); + } + + rect.InsetBy(1, 1); + + // Inner circle + SetHighColor(darken3); + StrokeArc(rect, 45.0f, 180.0f); + StrokeLine(BPoint(rect.left + 1, rect.top + 1), + BPoint(rect.left + 1, rect.top + 1)); + SetHighColor(no_tint); + StrokeArc(rect, 45.0f, -180.0f); + StrokeLine(BPoint(rect.left + 1, rect.bottom - 1), + BPoint(rect.left + 1, rect.bottom - 1)); + StrokeLine(BPoint(rect.right - 1, rect.bottom - 1), + BPoint(rect.right - 1, rect.bottom - 1)); + StrokeLine(BPoint(rect.right - 1, rect.top + 1), + BPoint(rect.right - 1, rect.top + 1)); + + // Label + BFont font; + GetFont(&font); + font_height fh; + font.GetHeight(&fh); + + SetHighColor(darkenmax); + DrawString(Label(), BPoint(20.0f, 8.0f + (float)ceil(fh.ascent / 2.0f))); + + // Focus + if (IsFocus()) + { + float h = 8.0f + (float)ceil(fh.ascent / 2.0f) + 2.0f; + + SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR)); + StrokeLine(BPoint(20.0f, h), BPoint(20.0f + StringWidth(Label()), h)); + } + } + else + { + // Dot + if (Value() == B_CONTROL_ON) + { + rgb_color kb_color = ui_color(B_KEYBOARD_NAVIGATION_COLOR); + + SetHighColor(tint_color(kb_color, B_LIGHTEN_2_TINT)); + FillEllipse(rect); + SetHighColor(tint_color(kb_color, B_LIGHTEN_MAX_TINT)); + StrokeLine(BPoint(rect.left + 4, rect.top + 5), + BPoint(rect.left + 5, rect.top + 4)); + SetHighColor(tint_color(kb_color, B_DARKEN_3_TINT)); + StrokeArc(BRect(rect.left + 2, rect.top + 2, rect.right - 2, rect.bottom - 2), + 45.0f, -180.0f); + } + else + { + SetHighColor(lighten1); + FillEllipse(rect); + } + + // Outer circle + SetHighColor(no_tint); + StrokeArc(rect, 45.0f, 180.0f); + SetHighColor(lighten1); + StrokeArc(rect, 45.0f, -180.0f); + + rect.InsetBy(1, 1); + + // Inner circle + SetHighColor(darken2); + StrokeArc(rect, 45.0f, 180.0f); + StrokeLine(BPoint(rect.left + 1, rect.top + 1), + BPoint(rect.left + 1, rect.top + 1)); + SetHighColor(no_tint); + StrokeArc(rect, 45.0f, -180.0f); + StrokeLine(BPoint(rect.left + 1, rect.bottom - 1), + BPoint(rect.left + 1, rect.bottom - 1)); + StrokeLine(BPoint(rect.right - 1, rect.bottom - 1), + BPoint(rect.right - 1, rect.bottom - 1)); + StrokeLine(BPoint(rect.right - 1, rect.top + 1), + BPoint(rect.right - 1, rect.top + 1)); + + // Label + BFont font; + GetFont(&font); + font_height fh; + font.GetHeight(&fh); + + SetHighColor(tint_color(no_tint, B_DISABLED_LABEL_TINT)); + DrawString(Label(), BPoint(20.0f, 8.0f + (float)ceil(fh.ascent / 2.0f))); + } +} +//------------------------------------------------------------------------------ +void BRadioButton::MouseDown(BPoint point) +{ + if (!IsEnabled()) + { + BControl::MouseDown(point); + return; + } + + SetMouseEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY | + B_SUSPEND_VIEW_FOCUS); + + SetTracking(true); + fOutlined = true; + Invalidate(); +} +//------------------------------------------------------------------------------ +void BRadioButton::AttachedToWindow() +{ + BControl::AttachedToWindow(); +} +//------------------------------------------------------------------------------ +void BRadioButton::KeyDown(const char *bytes, int32 numBytes) +{ + BControl::KeyDown(bytes, numBytes); +} +//------------------------------------------------------------------------------ +void BRadioButton::SetValue(int32 value) +{ + if (BControl::Value() == value) + return; + + if (!IsTracking()) + { + BView *sibling; + + for (sibling = PreviousSibling(); sibling != NULL; + sibling = sibling->PreviousSibling()) + { + BRadioButton* radio = dynamic_cast(sibling); + + if (radio != NULL) + radio->BControl::SetValue(B_CONTROL_OFF); + } + + for (sibling = NextSibling(); sibling != NULL; + sibling = sibling->NextSibling()) + { + BRadioButton* radio = dynamic_cast(sibling); + + if (radio != NULL) + radio->BControl::SetValue(B_CONTROL_OFF); + } + } + + BControl::SetValue(B_CONTROL_ON); +} +//------------------------------------------------------------------------------ +void BRadioButton::GetPreferredSize(float *width, float *height) +{ + font_height fh; + GetFontHeight(&fh); + + *height = (float)ceil(fh.ascent + fh.descent + fh.leading) + 6.0f; + *width = 22.0f + (float)ceil(StringWidth(Label())); +} +//------------------------------------------------------------------------------ +void BRadioButton::ResizeToPreferred() +{ + float width, height; + GetPreferredSize(&width, &height); + BControl::ResizeTo(width, height); +} +//------------------------------------------------------------------------------ +status_t BRadioButton::Invoke(BMessage *message) +{ + return BControl::Invoke(message); +} +//------------------------------------------------------------------------------ +void BRadioButton::MessageReceived(BMessage *message) +{ + BControl::MessageReceived(message); +} +//------------------------------------------------------------------------------ +void BRadioButton::WindowActivated(bool active) +{ + BControl::WindowActivated(active); +} +//------------------------------------------------------------------------------ +void BRadioButton::MouseUp(BPoint point) +{ + if (IsEnabled() && IsTracking()) + { + fOutlined = false; + SetTracking(false); + + if (Bounds().Contains(point)) + { + SetValue(B_CONTROL_ON); + Invoke(); + } + } + else + { + BControl::MouseUp(point); + return; + } + + Invalidate(); +} +//------------------------------------------------------------------------------ +void BRadioButton::MouseMoved(BPoint point, uint32 transit, const BMessage *message) +{ + if (IsEnabled() && IsTracking()) + { + if (transit == B_EXITED_VIEW) + fOutlined = false; + else if (transit == B_ENTERED_VIEW) + fOutlined = true; + + Invalidate(); + } + else + BView::MouseMoved(point, transit, message); +} +//------------------------------------------------------------------------------ +void BRadioButton::DetachedFromWindow() +{ + BControl::DetachedFromWindow(); +} +//------------------------------------------------------------------------------ +void BRadioButton::FrameMoved(BPoint newLocation) +{ + BControl::FrameMoved(newLocation); +} +//------------------------------------------------------------------------------ +void BRadioButton::FrameResized(float width, float height) +{ + BControl::FrameResized(width, height); +} +//------------------------------------------------------------------------------ +BHandler *BRadioButton::ResolveSpecifier(BMessage *message, int32 index, + BMessage *specifier, int32 what, + const char *property) +{ + return ResolveSpecifier(message, index, specifier, what, property); +} +//------------------------------------------------------------------------------ +void BRadioButton::MakeFocus(bool focused) +{ + BControl::MakeFocus(); +} +//------------------------------------------------------------------------------ +void BRadioButton::AllAttached() +{ + BControl::AllAttached(); +} +//------------------------------------------------------------------------------ +void BRadioButton::AllDetached() +{ + BControl::AllDetached(); +} +//------------------------------------------------------------------------------ +status_t BRadioButton::GetSupportedSuites(BMessage *message) +{ + return GetSupportedSuites(message); +} +//------------------------------------------------------------------------------ +status_t BRadioButton::Perform(perform_code d, void *arg) +{ + return B_ERROR; +} +//------------------------------------------------------------------------------ +void BRadioButton::_ReservedRadioButton1() {} +void BRadioButton::_ReservedRadioButton2() {} +//------------------------------------------------------------------------------ +BRadioButton &BRadioButton::operator=(const BRadioButton &) +{ + return *this; +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ diff --git a/src/kits/interface/Rect.cpp b/src/kits/interface/Rect.cpp new file mode 100644 index 0000000000..c94ad74b31 --- /dev/null +++ b/src/kits/interface/Rect.cpp @@ -0,0 +1,245 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: Rect.cpp +// Author: Frans van Nispen (xlr8@tref.nl) +// Description: BRect represents a rectangular area. +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- +#include + +// System Includes ------------------------------------------------------------- +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +bool TestLineIntersect(const BRect& r, float x1, float y1, float x2, float y2, + bool vertical = true); + +//------------------------------------------------------------------------------ +void BRect::InsetBy(BPoint p) +{ + left += p.x; + right -= p.x; + top += p.y; + bottom -= p.y; +} +//------------------------------------------------------------------------------ +void BRect::InsetBy(float dx, float dy) +{ + left += dx; + right -= dx; + top += dy; + bottom -= dy; +} +//------------------------------------------------------------------------------ +BRect& BRect::InsetBySelf(BPoint p) +{ + this->InsetBy(p); + return *this; +} +//------------------------------------------------------------------------------ +BRect& BRect::InsetBySelf(float dx, float dy) +{ + this->InsetBy(dx, dy); + return *this; +} +//------------------------------------------------------------------------------ +BRect BRect::InsetByCopy(BPoint p) +{ + BRect copy(*this); + copy.InsetBy(p); + return copy; +} +//------------------------------------------------------------------------------ +BRect BRect::InsetByCopy(float dx, float dy) +{ + BRect copy(*this); + copy.InsetBy(dx, dy); + return copy; +} +//------------------------------------------------------------------------------ +void BRect::OffsetBy(BPoint p) +{ + left += p.x; + right += p.x; + top += p.y; + bottom += p.y; +} +//------------------------------------------------------------------------------ +void BRect::OffsetBy(float dx, float dy) +{ + left += dx; + right += dx; + top += dy; + bottom += dy; +} +//------------------------------------------------------------------------------ +BRect& BRect::OffsetBySelf(BPoint p) +{ + this->OffsetBy(p); + return *this; +} +//------------------------------------------------------------------------------ +BRect& BRect::OffsetBySelf(float dx, float dy) +{ + this->OffsetBy(dx, dy); + return *this; +} +//------------------------------------------------------------------------------ +BRect BRect::OffsetByCopy(BPoint p) +{ + BRect copy(*this); + copy.OffsetBy(p); + return copy; +} +//------------------------------------------------------------------------------ +BRect BRect::OffsetByCopy(float dx, float dy) +{ + BRect copy(*this); + copy.OffsetBy(dx, dy); + return copy; +} +//------------------------------------------------------------------------------ +void BRect::OffsetTo(BPoint p) +{ + right = (right - left) + p.x; + left = p.x; + bottom = (bottom - top) + p.y; + top = p.y; +} +//------------------------------------------------------------------------------ +void BRect::OffsetTo(float x, float y) +{ + right = (right - left) + x; + left = x; + bottom = (bottom - top) + y; + top=y; +} +//------------------------------------------------------------------------------ +BRect& BRect::OffsetToSelf(BPoint p) +{ + this->OffsetTo(p); + return *this; +} +//------------------------------------------------------------------------------ +BRect& BRect::OffsetToSelf(float dx, float dy) +{ + this->OffsetTo(dx, dy); + return *this; +} +//------------------------------------------------------------------------------ +BRect BRect::OffsetToCopy(BPoint p) +{ + BRect copy(*this); + copy.OffsetTo(p); + return copy; +} +//------------------------------------------------------------------------------ +BRect BRect::OffsetToCopy(float dx, float dy) +{ + BRect copy(*this); + copy.OffsetTo(dx, dy); + return copy; +} +//------------------------------------------------------------------------------ +void BRect::PrintToStream() const +{ + printf("(l:%.1f t:%.1f r:%.1f b:%.1f)\n", left, top, right, bottom); +} +//------------------------------------------------------------------------------ +bool BRect::operator==(BRect r) const +{ + return left == r.left && right == r.right && + top == r.top && bottom == r.bottom; +} +//------------------------------------------------------------------------------ +bool BRect::operator!=(BRect r) const +{ + return !(*this == r); +} +//------------------------------------------------------------------------------ +BRect BRect::operator&(BRect r) const +{ + return BRect(max_c(left, r.left), max_c(top, r.top), + min_c(right, r.right), min_c(bottom, r.bottom)); +} +//------------------------------------------------------------------------------ +BRect BRect::operator|(BRect r) const +{ + return BRect(min_c(left, r.left), min_c(top, r.top), + max_c(right, r.right), max_c(bottom, r.bottom)); +} +//------------------------------------------------------------------------------ +bool BRect::Intersects(BRect r) const +{ + return TestLineIntersect(*this, r.left, r.top, r.left, r.bottom) || + TestLineIntersect(*this, r.left, r.top, r.right, r.top, false) || + TestLineIntersect(*this, r.right, r.top, r.right, r.bottom) || + TestLineIntersect(*this, r.left, r.bottom, r.right, r.bottom, false); +} +//------------------------------------------------------------------------------ +bool BRect::Contains(BPoint p) const +{ + return p.x >= left && p.x <= right && p.y >= top && p.y <= bottom; +} +//------------------------------------------------------------------------------ +bool BRect::Contains(BRect r) const +{ + return r.left >= left && r.right <= right && + r.top >= top && r.bottom <= bottom; +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +bool TestLineIntersect(const BRect& r, float x1, float y1, float x2, float y2, + bool vertical) +{ + if (vertical) + { + return (x1 >= r.left && x1 <= r.right) && + ((y1 >= r.top && y1 <= r.bottom) || + (y2 >= r.top && y2 <= r.bottom)); + } + else + { + return (y1 >= r.top && y1 <= r.bottom) && + ((x1 >= r.left && x1 <= r.right) || + (x2 >= r.left && x2 <= r.right)); + } +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/kits/interface/StatusBar.cpp b/src/kits/interface/StatusBar.cpp new file mode 100644 index 0000000000..6e4e709e5a --- /dev/null +++ b/src/kits/interface/StatusBar.cpp @@ -0,0 +1,559 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: StatusBar.cpp +// Author: Marc Flerackers (mflerackers@androme.be) +// Description: BStatusBar displays a "percentage-of-completion" gauge. +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- +#include + +// System Includes ------------------------------------------------------------- +#include +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +BStatusBar::BStatusBar(BRect frame, const char *name, const char *label, + const char *trailingLabel) + : BView ( frame, name, 0, B_WILL_DRAW ), + fText(NULL), + fTrailingText(NULL), + fMax(100.0f), + fCurrent(0.0f), + fBarHeight(-1.0f), + fTrailingWidth(-1.0f), + fEraseText(-1.0f), + fEraseTrailingText(-1.0f), + fCustomBarHeight(false) + +{ + fLabel = strdup(label); + fTrailingLabel = strdup(trailingLabel); + + fBarColor.red = 50; + fBarColor.green = 150; + fBarColor.blue = 255; + fBarColor.alpha = 255; +} +//------------------------------------------------------------------------------ +BStatusBar::BStatusBar(BMessage *archive) + : BView(archive), + fTrailingWidth(-1.0f), + fEraseText(-1.0f), + fEraseTrailingText(-1.0f), + fCustomBarHeight(false) +{ + if (archive->FindFloat("_high", &fBarHeight) != B_OK) + fBarHeight = -1.0f; + + const void *ptr; + + if (archive->FindData("_bcolor", B_INT32_TYPE, &ptr, NULL ) != B_OK) + { + fBarColor.red = 50; + fBarColor.green = 150; + fBarColor.blue = 255; + fBarColor.alpha = 255; + } + else + memcpy(&fBarColor, ptr, sizeof(rgb_color)); + + if (archive->FindFloat("_val", &fCurrent) != B_OK) + fCurrent = 0.0f; + + if (archive->FindFloat("_max", &fMax) != B_OK) + fMax = 100.0f; + + const char *string; + + if (archive->FindString("_text", &string) != B_OK) + fText = NULL; + else + fText = strdup(string); + + if (archive->FindString("_ttext", &string) != B_OK) + fTrailingText = NULL; + else + fTrailingText = strdup(string); + + if (archive->FindString("_label", &string) != B_OK) + fLabel = NULL; + else + fLabel = strdup(string); + + if ( archive->FindString("_tlabel", &string) != B_OK) + fTrailingLabel = NULL; + else + fTrailingLabel = strdup(string); +} +//------------------------------------------------------------------------------ +BStatusBar::~BStatusBar() +{ + if (fLabel) + delete fLabel; + + if (fTrailingLabel) + delete fTrailingLabel; + + if (fText) + delete fText; + + if (fTrailingText) + delete fTrailingText; +} +//------------------------------------------------------------------------------ +BArchivable *BStatusBar::Instantiate(BMessage *archive) +{ + if (validate_instantiation(archive, "BStatusBar")) + return new BStatusBar(archive); + + return NULL; +} +//------------------------------------------------------------------------------ +status_t BStatusBar::Archive(BMessage *archive, bool deep) const +{ + status_t err = BView::Archive(archive, deep); + + if (err != B_OK) + return err; + + if (fBarHeight != 16.0f) + err = archive->AddFloat("_high", fBarHeight); + + if (err != B_OK) + return err; + + // TODO: Should we compare the color with (50, 150, 255) ? + err = archive->AddData("_bcolor", B_INT32_TYPE, &fBarColor, sizeof( int32 )); + + if (err != B_OK) + return err; + + if (fCurrent != 0.0f) + err = archive->AddFloat("_val", fCurrent); + + if (err != B_OK) + return err; + + if (fMax != 100.0f ) + err = archive->AddFloat("_max", fMax); + + if (err != B_OK) + return err; + + if (fText ) + err = archive->AddString("_text", fText); + + if (err != B_OK) + return err; + + if (fTrailingText) + err = archive->AddString("_ttext", fTrailingText); + + if (err != B_OK) + return err; + + if (fLabel) + err = archive->AddString("_label", fLabel); + + if (err != B_OK) + return err; + + if (fTrailingLabel) + err = archive->AddString ("_tlabel", fTrailingLabel); + + return err; +} +//------------------------------------------------------------------------------ +void BStatusBar::AttachedToWindow() +{ + float width, height; + GetPreferredSize(&width, &height); + ResizeTo(Frame().Width(), height); + + if (Parent()) + SetViewColor(Parent ()->ViewColor()); +} +//------------------------------------------------------------------------------ +void BStatusBar::MessageReceived(BMessage *message) +{ + switch(message->what) + { + case B_UPDATE_STATUS_BAR: + { + float delta; + const char *text = NULL, *trailing_text = NULL; + + message->FindFloat("delta", &delta); + message->FindString("text", &text); + message->FindString("trailing_text", &trailing_text); + + Update(delta, text, trailing_text); + + break; + } + case B_RESET_STATUS_BAR: + { + const char *label = NULL, *trailing_label = NULL; + + message->FindString("label", &label); + message->FindString("trailing_label", &trailing_label); + + Reset(label, trailing_label); + + break; + } + default: + BView::MessageReceived ( message ); + } +} +//------------------------------------------------------------------------------ +void BStatusBar::Draw(BRect updateRect) +{ + float width = Frame().Width(); + + if (fLabel) + { + font_height fh; + + GetFontHeight(&fh); + + SetHighColor(0, 0, 0); + DrawString(fLabel, BPoint(0.0f, (float)ceil(fh.ascent) + 1.0f)); + } + + BRect rect(0.0f, 14.0f, width, 14.0f + fBarHeight); + + // First bevel + SetHighColor(tint_color(ui_color ( B_PANEL_BACKGROUND_COLOR ), B_DARKEN_1_TINT)); + StrokeLine(BPoint(rect.left, rect.bottom), BPoint(rect.left, rect.top)); + StrokeLine(BPoint(rect.right, rect.top)); + + SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_LIGHTEN_2_TINT)); + StrokeLine(BPoint(rect.left + 1.0f, rect.bottom), BPoint(rect.right, rect.bottom)); + StrokeLine(BPoint(rect.right, rect.top + 1.0f)); + + rect.InsetBy(1.0f, 1.0f); + + // Second bevel + SetHighColor(tint_color(ui_color ( B_PANEL_BACKGROUND_COLOR ), B_DARKEN_4_TINT)); + StrokeLine(BPoint(rect.left, rect.bottom), BPoint(rect.left, rect.top)); + StrokeLine(BPoint(rect.right, rect.top)); + + SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + StrokeLine(BPoint(rect.left + 1.0f, rect.bottom), BPoint(rect.right, rect.bottom)); + StrokeLine(BPoint(rect.right, rect.top + 1.0f)); + + rect.InsetBy(1.0f, 1.0f); + + // Filling + SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_LIGHTEN_MAX_TINT)); + FillRect(rect); + + if (fCurrent != 0.0f) + { + rect.right = rect.left + (float)ceil(fCurrent * (width - 4) / fMax), + + // Bevel + SetHighColor(tint_color(fBarColor, B_LIGHTEN_2_TINT)); + StrokeLine(BPoint(rect.left, rect.bottom), BPoint(rect.left, rect.top)); + StrokeLine(BPoint(rect.right, rect.top)); + + SetHighColor(tint_color(fBarColor, B_DARKEN_2_TINT)); + StrokeLine(BPoint(rect.left, rect.bottom), BPoint(rect.right, rect.bottom)); + StrokeLine(BPoint(rect.right, rect.top)); + + rect.InsetBy(1.0f, 1.0f); + + // Filling + SetHighColor(fBarColor); + FillRect(rect); + } +} +//------------------------------------------------------------------------------ +void BStatusBar::SetBarColor(rgb_color color) +{ + memcpy(&fBarColor, &color, sizeof(rgb_color)); + + Invalidate(); +} +//------------------------------------------------------------------------------ +void BStatusBar::SetBarHeight(float height) +{ + BRect frame = Frame(); + + fBarHeight = height; + fCustomBarHeight = true; + ResizeTo(frame.Width(), fBarHeight + 16); +} +//------------------------------------------------------------------------------ +void BStatusBar::SetText ( const char *string ) +{ + if (fText) + delete fText; + + fText = strdup(string); + + Invalidate(); +} +//------------------------------------------------------------------------------ +void BStatusBar::SetTrailingText(const char *string) +{ + if (fTrailingText) + delete fTrailingText; + + fTrailingText = strdup(string); + + Invalidate(); +} +//------------------------------------------------------------------------------ +void BStatusBar::SetMaxValue(float max) +{ + fMax = max; + + Invalidate(); +} +//------------------------------------------------------------------------------ +void BStatusBar::Update(float delta, const char *text, const char *trailingText) +{ + fCurrent += delta; + + if (fText) + delete fText; + + fText = strdup(text); + + if (fTrailingText) + delete fTrailingText; + + fTrailingText = strdup(trailingText); + + Invalidate(); +} +//------------------------------------------------------------------------------ +void BStatusBar::Reset(const char *label, const char *trailingLabel) +{ + if (fLabel) + delete fLabel; + + fLabel = strdup(label); + + if (fTrailingLabel) + delete fTrailingLabel; + + fTrailingLabel = strdup(trailingLabel); + + fCurrent = 0.0f; + + Invalidate(); +} +float BStatusBar::CurrentValue() const +{ + return fCurrent; +} +//------------------------------------------------------------------------------ +float BStatusBar::MaxValue() const +{ + return fMax; +} +//------------------------------------------------------------------------------ +rgb_color BStatusBar::BarColor() const +{ + return fBarColor; +} +//------------------------------------------------------------------------------ +float BStatusBar::BarHeight() const +{ + if (!fCustomBarHeight && fBarHeight == -1.0f) + { + font_height fh; + GetFontHeight(&fh); + ((BStatusBar*)this)->fBarHeight = fh.ascent + fh.descent + 6.0f; + } + + return fBarHeight; +} +//------------------------------------------------------------------------------ +const char *BStatusBar::Text() const +{ + return fText; +} +//------------------------------------------------------------------------------ +const char *BStatusBar::TrailingText() const +{ + return fTrailingText; +} +//------------------------------------------------------------------------------ +const char *BStatusBar::Label() const +{ + return fLabel; +} +//------------------------------------------------------------------------------ +const char *BStatusBar::TrailingLabel() const +{ + return fTrailingLabel; +} +//------------------------------------------------------------------------------ +void BStatusBar::MouseDown(BPoint point) +{ + BView::MouseDown(point); +} +//------------------------------------------------------------------------------ +void BStatusBar::MouseUp(BPoint point) +{ + BView::MouseUp(point); +} +//------------------------------------------------------------------------------ +void BStatusBar::WindowActivated(bool state) +{ + BView::WindowActivated(state); +} +//------------------------------------------------------------------------------ +void BStatusBar::MouseMoved(BPoint point, uint32 transit, + const BMessage *message) +{ + BView::MouseMoved(point, transit, message); +} +//------------------------------------------------------------------------------ +void BStatusBar::DetachedFromWindow() +{ + BView::DetachedFromWindow(); +} +//------------------------------------------------------------------------------ +void BStatusBar::FrameMoved(BPoint new_position) +{ + BView::FrameMoved(new_position); +} +//------------------------------------------------------------------------------ +void BStatusBar::FrameResized(float new_width, float new_height) +{ + BView::FrameResized(new_width, new_height); +} +//------------------------------------------------------------------------------ +BHandler *BStatusBar::ResolveSpecifier(BMessage *message, int32 index, + BMessage *specifier, + int32 what, const char *property) +{ + return BView::ResolveSpecifier(message, index, specifier, what, property); +} +//------------------------------------------------------------------------------ +void BStatusBar::ResizeToPreferred() +{ + BView::ResizeToPreferred(); +} +//------------------------------------------------------------------------------ +void BStatusBar::GetPreferredSize(float *width, float *height) +{ + font_height fh; + GetFontHeight(&fh); + + *width = 0.0f; + if (Label() && TrailingLabel()) + *width += 3.0f; + if (Label()) + *width += (float)ceil(StringWidth(Label())) + 2.0f; + if (TrailingLabel()) + *width += (float)ceil(StringWidth(TrailingLabel())) + 2.0f; + if (Text()) + *width += 3.0f; + if (TrailingText()) + *width += 3.0f; + *height = fh.ascent + fh.descent + 5.0f + BarHeight(); +} +//------------------------------------------------------------------------------ +void BStatusBar::MakeFocus(bool state) +{ + BView::MakeFocus(state); +} +//------------------------------------------------------------------------------ +void BStatusBar::AllAttached() +{ + BView::AllAttached(); +} +//------------------------------------------------------------------------------ +void BStatusBar::AllDetached() +{ + BView::AllDetached(); +} +//------------------------------------------------------------------------------ +status_t BStatusBar::GetSupportedSuites(BMessage *data) +{ + return BView::GetSupportedSuites(data); +} +//------------------------------------------------------------------------------ +status_t BStatusBar::Perform(perform_code d, void *arg) +{ + return B_ERROR; +} +//------------------------------------------------------------------------------ +void BStatusBar::_ReservedStatusBar1() {} +void BStatusBar::_ReservedStatusBar2() {} +void BStatusBar::_ReservedStatusBar3() {} +void BStatusBar::_ReservedStatusBar4() {} + +//------------------------------------------------------------------------------ +BStatusBar &BStatusBar::operator=(const BStatusBar &) +{ + return *this; +} +//------------------------------------------------------------------------------ +void BStatusBar::InitObject(const char *l, const char *aux_l) +{ + // TODO: +} +//------------------------------------------------------------------------------ +void BStatusBar::SetTextData(char **pp, const char *str) +{ + // TODO: +} +//------------------------------------------------------------------------------ +void BStatusBar::FillBar(BRect r) +{ + // TODO: +} +//------------------------------------------------------------------------------ +void BStatusBar::Resize() +{ + // TODO: +} +//------------------------------------------------------------------------------ +void BStatusBar::_Draw(BRect updateRect, bool bar_only) +{ + // TODO: +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ diff --git a/src/kits/interface/StringItem.cpp b/src/kits/interface/StringItem.cpp new file mode 100644 index 0000000000..f2d8168748 --- /dev/null +++ b/src/kits/interface/StringItem.cpp @@ -0,0 +1,148 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// File: StringItem.cpp +// +// Description: BListView represents a one-dimensional list view. +// +// Copyright 2001, Ulrich Wimboeck +// +//////////////////////////////////////////////////////////////////////////////// + +#include "StringItem.h" +#include +#include +#include + +#ifdef USE_OPENBEOS_NAMESPACE +using namespace OpenBeOS +#endif + +/*----------------------------------------------------------------*/ +/*----- BStringItem class ----------------------------------------*/ + + +BStringItem::BStringItem(const char* text, uint32 outlineLevel /* = 0 */, + bool expanded /* = true */) + : BListItem(outlineLevel, expanded), fBaselineOffset(0), + fText(new char[strlen(text) + 1]) +{ + // copy the text !!!!! + strcpy(fText, text) ; +} + +BStringItem::~BStringItem() +{ + if (fText != NULL) { + delete fText ; + fText = NULL ; + } +} + +BStringItem::BStringItem(BMessage* data) + : BListItem(data) //First call the contructor of the base class +{ + char* text ; + if (data->FindString("_label", const_cast(&text)) == B_OK) + { + fText = new char[strlen(text) + 1] ; + strcpy(fText, text) ; + } + +} + +BArchivable* +BStringItem::Instantiate(BMessage* data) +{ + if (validate_instantiation(data, "BStringItem")) + return new MyStringItem(data) ; + + return NULL ; +} + +status_t +BStringItem::Archive(BMessage* data, bool deep /* = true */) const +{ + status_t tReturn (BListItem::Archive(data, deep)) ; + + if (tReturn != B_OK) + return tReturn ; + + if (data->AddString("class", "BStringItem") != B_OK) + return tReturn ; + + return tReturn = data->AddString("_label", fText) ; +} + +// The colors need to be set correct +void +BStringItem::DrawItem(BView* owner, BRect frame, bool complete /* = false */) +{ + if (IsSelected() || complete) + { + if (IsSelected()) + { + owner->SetHighColor( + tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_HIGHLIGHT_BACKGROUND_TINT)) ; + owner->SetLowColor(owner->HighColor()) ; + } + else { + owner->SetHighColor(owner->ViewColor()) ; + owner->SetLowColor(owner->ViewColor()) ; + } + + owner->FillRect(frame) ; + } + + BFont font ; + owner->GetFont(&font) ; + + // Get the height of the font to place the pen to + // the right position + font_height height ; + font.GetHeight(&height) ; + + owner->MovePenTo(frame.left + 4, frame.bottom - height.descent) ; + owner->SetHighColor(IsEnabled() ? ui_color(B_MENU_ITEM_TEXT_COLOR) + : tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_DISABLED_LABEL_TINT)) ; + + owner->DrawString(fText) ; +} + +void +BStringItem::SetText(const char* text) +{ + if (fText != NULL) + delete fText ; + + if (text != NULL) + { + fText = new char[strlen(text) + 1] ; + strcpy(fText, text) ; // copy text + } + else { + fText = NULL ; + } +} + +inline const char* +BStringItem::Text() const +{ + return fText ; +} + +void +BStringItem::Update(BView* owner, const BFont* font) +{ + BListItem::Update(owner, font) ; + + // Set the width to the width of the string + SetWidth(font->StringWidth(fText)) ; +} + +status_t +BStringItem::Perform(perform_code d, void* arg) +{ + status_t retval = B_OK ; + return retval ; +} + diff --git a/src/kits/interface/StringView.cpp b/src/kits/interface/StringView.cpp new file mode 100644 index 0000000000..eba8b85c52 --- /dev/null +++ b/src/kits/interface/StringView.cpp @@ -0,0 +1,277 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: StringView.cpp +// Author: Frans van Nispen (xlr8@tref.nl) +// Description: BStringView draw a non-editable text string +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- +#include +#include + +// System Includes ------------------------------------------------------------- +#include +#include +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + + +//------------------------------------------------------------------------------ +BStringView::BStringView(BRect frame, const char* name, const char* text, + uint32 resizeMask, uint32 flags) + : BView(frame, name, resizeMask, flags) +{ + fText = strdup(text); + fAlign = B_ALIGN_LEFT; +} +//------------------------------------------------------------------------------ +BStringView::BStringView(BMessage* data) + : BView(data) +{ + const char* text; + + if (data->FindInt32("_aligne",(int32&)fAlign) != B_OK) + { + fAlign = B_ALIGN_LEFT; + } + + if (data->FindString("_text",&text) != B_OK) + { + text = NULL; + } + + SetText(text); +} +//------------------------------------------------------------------------------ +BArchivable* BStringView::Instantiate(BMessage* data) +{ + if (!validate_instantiation(data,"BStringView")) + { + return NULL; + } + + return new BStringView(data); +} +//------------------------------------------------------------------------------ +status_t BStringView::Archive(BMessage* data, bool deep) const +{ + BView::Archive(data, deep); + + if (fText) + { + data->AddString("_text",fText); + } + + data->AddInt32("_align", fAlign); + + return B_OK; +} +//------------------------------------------------------------------------------ +BStringView::~BStringView() +{ + if (fText) + { + delete[] fText; + } +} +//------------------------------------------------------------------------------ +void BStringView::SetText(const char* text) +{ + if (fText) + { + delete[] fText; + } + fText = strdup(text); + Invalidate(); +} +//------------------------------------------------------------------------------ +const char* BStringView::Text() const +{ + return fText; +} +//------------------------------------------------------------------------------ +void BStringView::SetAlignment(alignment flag) +{ + fAlign = flag; + Invalidate(); +} +//------------------------------------------------------------------------------ +alignment BStringView::Alignment() const +{ + return fAlign; +} +//------------------------------------------------------------------------------ +void BStringView::AttachedToWindow() +{ + if (Parent()) + { + SetViewColor(Parent()->ViewColor()); + } +} +//------------------------------------------------------------------------------ +void BStringView::Draw(BRect bounds) +{ + SetLowColor(ViewColor()); + BFont font; + GetFont(&font); + font_height fh; + font.GetHeight(&fh); + + float y = Bounds().bottom - ceil(fh.descent); + float x; + switch (fAlign) + { + case B_ALIGN_RIGHT: + x = Bounds().Width() - font.StringWidth(fText) - 2.0f; + break; + + case B_ALIGN_CENTER: + x = (Bounds().Width() - font.StringWidth(fText))/2.0f; + break; + + default: + x = 2.0f; + break; + } + + DrawString( fText, BPoint(x,y) ); +} +//------------------------------------------------------------------------------ +void BStringView::ResizeToPreferred() +{ + float w, h; + GetPreferredSize(&w, &h); + BView::ResizeTo(w, h); +} +//------------------------------------------------------------------------------ +void BStringView::GetPreferredSize(float* width, float* height) +{ + BFont font; + GetFont(&font); + font_height fh; + font.GetHeight(&fh); + + *height = ceil(fh.ascent + fh.descent + fh.leading) + 2.0f; + *width = 4.0f + ceil(font.StringWidth(fText)); +} +//------------------------------------------------------------------------------ +void BStringView::MessageReceived(BMessage* msg) +{ + BView::MessageReceived(msg); +} +//------------------------------------------------------------------------------ +void BStringView::MouseDown(BPoint pt) +{ + BView::MouseDown(pt); +} +//------------------------------------------------------------------------------ +void BStringView::MouseUp(BPoint pt) +{ + BView::MouseUp(pt); +} +//------------------------------------------------------------------------------ +void BStringView::MouseMoved(BPoint pt, uint32 code, const BMessage* msg) +{ + BView::MouseMoved(pt, code, msg); +} +//------------------------------------------------------------------------------ +void BStringView::DetachedFromWindow() +{ + BView::DetachedFromWindow(); +} +//------------------------------------------------------------------------------ +void BStringView::FrameMoved(BPoint newPosition) +{ + BView::FrameMoved(newPosition); +} +//------------------------------------------------------------------------------ +void BStringView::FrameResized(float newWidth, float newHeight) +{ + BView::FrameResized(newWidth, newHeight); +} +//------------------------------------------------------------------------------ +BHandler* BStringView::ResolveSpecifier(BMessage* msg, int32 index, + BMessage* specifier, int32 form, + const char* property) +{ + return NULL; +} +//------------------------------------------------------------------------------ +void BStringView::MakeFocus(bool state = true) +{ + BView::MakeFocus(state); +} +//------------------------------------------------------------------------------ +void BStringView::AllAttached() +{ + BView::AllAttached(); +} +//------------------------------------------------------------------------------ +void BStringView::AllDetached() +{ + BView::AllDetached(); +} +//------------------------------------------------------------------------------ +status_t BStringView::GetSupportedSuites(BMessage* data) +{ + return B_OK; +} +//------------------------------------------------------------------------------ +status_t BStringView::Perform(perform_code d, void* arg) +{ + return B_ERROR; +} +//------------------------------------------------------------------------------ +void BStringView::_ReservedStringView1() +{ +} +//------------------------------------------------------------------------------ +void BStringView::_ReservedStringView2() +{ +} +//------------------------------------------------------------------------------ +void BStringView::_ReservedStringView3() +{ +} +//------------------------------------------------------------------------------ +BStringView& BStringView::operator=(const BStringView&) +{ + // Assignment not allowed + return *this; +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/kits/interface/TextControl.cpp b/src/kits/interface/TextControl.cpp new file mode 100644 index 0000000000..c0147c0aba --- /dev/null +++ b/src/kits/interface/TextControl.cpp @@ -0,0 +1,442 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: TextControl.cpp +// Author: Frans van Nispen (xlr8@tref.nl) +// Description: BTextControl displays text that can act like a control. +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- +#include + +// System Includes ------------------------------------------------------------- +#include +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "TextInput.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +BTextControl::BTextControl(BRect frame, const char* name, const char* label, + const char* text, BMessage* message, uint32 mask, + uint32 flags) + : BControl(frame, name, label, message, mask, flags) +{ + if (label) + { + fDivider = frame.Width() / 2.0f; + } + else + { + // no label + fDivider = 0.0f; + } + + fModificationMessage = NULL; + + frame = Bounds(); + if (fDivider) + { + frame.left = fDivider + 5.0f; + } + + BRect rect(frame); + rect.OffsetTo(0,0); + + frame.OffsetBy(-2,1); + + rect.InsetBy(2,2); + fText = new _BTextInput_(this, frame, "text", rect); + fText->SetText(text); + AddChild(fText); +} +//------------------------------------------------------------------------------ +BTextControl::~BTextControl() +{ + if (fText) + { + fText->RemoveSelf(); + delete fText; + } +} +//------------------------------------------------------------------------------ +BTextControl::BTextControl(BMessage* data) + : BControl(data) +{ + if (data->FindInt32("_a_label", (int32*)&fLabelAlign) != B_OK) + { + fLabelAlign = B_ALIGN_LEFT; + } + + alignment textAlign; + if (data->FindInt32("_a_text", (int32*)&textAlign) != B_OK) + { + fText->SetAlignment(B_ALIGN_LEFT); + } + else + { + fText->SetAlignment(textAlign); + } + + if (data->FindFloat("_divide", &fDivider) != B_OK) + { + if (Label()) + fDivider = Frame().Width()/2.0f; + else + fDivider = 0.0f; + } + + if (data->FindMessage("_mod_msg", fModificationMessage) != B_OK) + { + fModificationMessage = NULL; // Is this really necessary? + } + + // TODO: Recover additional info as per final implementation of Archive() +} +//------------------------------------------------------------------------------ +BArchivable* BTextControl::Instantiate(BMessage* data) +{ + if (!validate_instantiation(data,"BTextControl")) + { + return NULL; + } + + return new BTextControl(data); +} +//------------------------------------------------------------------------------ +status_t BTextControl::Archive(BMessage* data, bool deep = true) const +{ + // TODO: compare against original version and finish + status_t err = BView::Archive(data, deep); + + if (!err) + err = data->AddInt32("_a_label", fLabelAlign); + if (!err) + err = data->AddInt32("_a_text", fText->Alignment()); + if (!err) + err = data->AddFloat("_divide", fDivider); + if (!err && fModificationMessage) + err = data->AddMessage("_mod_msg", fModificationMessage); + + return err; +} +//------------------------------------------------------------------------------ +void BTextControl::SetText(const char* text) +{ + fText->SetText(text); +} +//------------------------------------------------------------------------------ +const char* BTextControl::Text() const +{ + return fText->Text(); +} +//------------------------------------------------------------------------------ +void BTextControl::SetValue(int32 value) +{ +} +//------------------------------------------------------------------------------ +status_t BTextControl::Invoke(BMessage* msg = NULL) +{ + return BControl::Invoke(msg); +} +//------------------------------------------------------------------------------ +BTextView* BTextControl::TextView() const +{ + return (BTextView*)fText; +} +//------------------------------------------------------------------------------ +void BTextControl::SetModificationMessage(BMessage* message) +{ + fModificationMessage = message; +} +//------------------------------------------------------------------------------ +BMessage* BTextControl::ModificationMessage() const +{ + return fModificationMessage; +} +//------------------------------------------------------------------------------ +void BTextControl::SetAlignment(alignment label, alignment text) +{ + fLabelAlign = label; + fText->SetAlignment(text); +} +//------------------------------------------------------------------------------ +void BTextControl::GetAlignment(alignment* label, alignment* text) const +{ + *label = fLabelAlign; + *text = fText->Alignment(); +} +//------------------------------------------------------------------------------ +void BTextControl::SetDivider(float dividing_line) +{ + fDivider = dividing_line; +// here I need some code to resize and invalidate the textView + + BRect frame = fText->Frame(); + if (fDivider) + { + frame.left = fDivider + 5.0f; + } + else + { + frame.left = 0.0f; + } + + if (!frame.IsValid()) + { + frame.left = frame.right - 6.0f; + } + + fText->ResizeTo( frame.Width(), frame.Height()); +// fText->FrameResized( frame.Width(), frame.Height()); + fText->MoveTo( frame.left, frame.top); + fText->Invalidate(); + + Invalidate(); +} +//------------------------------------------------------------------------------ +float BTextControl::Divider() const +{ + return fDivider; +} +//------------------------------------------------------------------------------ +void BTextControl::Draw(BRect rect) +{ + SetLowColor(ViewColor()); + BFont font; + GetFont(&font); + font_height fh; + font.GetHeight(&fh); + + if (Label()) + { + float y = ceil(fh.ascent + fh.descent + fh.leading) + 2.0f; + float x; + switch (fLabelAlign) + { + case B_ALIGN_RIGHT: + x = fDivider - font.StringWidth(Label()) - 3.0f; + break; + + case B_ALIGN_CENTER: + x = fDivider - font.StringWidth(Label())/2.0f; + break; + + default: + x = 3.0f; + break; + } + + SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), + IsEnabled() ? B_DARKEN_MAX_TINT : B_DISABLED_LABEL_TINT)); + DrawString(Label(), BPoint(x, y)); + } + + rect = fText->Frame(); + + rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR); + + rect.InsetBy(-1,-1); + SetHighColor(tint_color(base, IsEnabled() ? + B_DARKEN_1_TINT : B_DARKEN_2_TINT)); + StrokeLine(BPoint(rect.left,rect.bottom), BPoint(rect.left, rect.top)); + StrokeLine(BPoint(rect.left+1.0f,rect.top), BPoint(rect.right, rect.top)); + SetHighColor(tint_color(base, IsEnabled() ? + B_LIGHTEN_MAX_TINT : B_LIGHTEN_2_TINT)); + StrokeLine(BPoint(rect.left+1.0f,rect.bottom), + BPoint(rect.right, rect.bottom)); + StrokeLine(BPoint(rect.right,rect.bottom), + BPoint(rect.right, rect.top+1.0f)); +} +//------------------------------------------------------------------------------ +void BTextControl::MouseDown(BPoint where) +{ + if (IsEnabled()) + { + MakeFocus(true); + } +} +void BTextControl::AttachedToWindow() +{ + BControl::AttachedToWindow(); + if (Parent()) + { + SetViewColor(Parent()->ViewColor()); + } + + float w; + float h; + GetPreferredSize(&w, &h); + ResizeTo(Bounds().Width(), h); + fText->ResizeTo(fText->Bounds().Width(), h); +} +void BTextControl::MakeFocus(bool state = true) +{ + if (IsEnabled()) + { + fText->MakeFocus(state); + Invalidate(); + } +} +//------------------------------------------------------------------------------ +void BTextControl::SetEnabled(bool state) +{ + fText->SetEnabled(state); + BControl::SetEnabled(state); +} +//------------------------------------------------------------------------------ +void BTextControl::GetPreferredSize(float* width, float* height) +{ + BFont font; + GetFont(&font); + font_height fh; + font.GetHeight(&fh); + + *height = ceil(fh.ascent + fh.descent + fh.leading) + 7.0f; + + // TODO: this one I need to find out + *width = 4.0f + ceil(font.StringWidth(Label()))*2.0f; +} +//------------------------------------------------------------------------------ +void BTextControl::ResizeToPreferred() +{ + float w; + float h; + GetPreferredSize(&w, &h); + BView::ResizeTo(w,h); +} +//------------------------------------------------------------------------------ +void BTextControl::SetFlags(uint32 flags) +{ + BView::SetFlags(flags); +} +//------------------------------------------------------------------------------ +void BTextControl::MessageReceived(BMessage* msg) +{ + switch(msg->what) + { + case B_CONTROL_MODIFIED: + if (fModificationMessage) + { + BControl::Invoke(fModificationMessage); + } + break; + + default: + BControl::MessageReceived(msg); + break; + } +} +//------------------------------------------------------------------------------ +BHandler* BTextControl::ResolveSpecifier(BMessage* msg, int32 index, + BMessage* specifier, int32 form, + const char* property) +{ + return NULL; +} +//------------------------------------------------------------------------------ +status_t BTextControl::GetSupportedSuites(BMessage* data) +{ + return B_OK; +} +//------------------------------------------------------------------------------ +void BTextControl::MouseUp(BPoint pt) +{ + BControl::MouseUp(pt); +} +//------------------------------------------------------------------------------ +void BTextControl::MouseMoved(BPoint pt, uint32 code, const BMessage* msg) +{ + BControl::MouseMoved(pt, code, msg); +} +//------------------------------------------------------------------------------ +void BTextControl::DetachedFromWindow() +{ + BControl::DetachedFromWindow(); +} +//------------------------------------------------------------------------------ +void BTextControl::AllAttached() +{ + BControl::AllAttached(); +} +//------------------------------------------------------------------------------ +void BTextControl::AllDetached() +{ + BControl::AllDetached(); +} +//------------------------------------------------------------------------------ +void BTextControl::FrameMoved(BPoint newPosition) +{ + BControl::FrameMoved(newPosition); +} +//------------------------------------------------------------------------------ +void BTextControl::FrameResized(float newWidth, float newHeight) +{ + BControl::FrameResized(newWidth, newHeight); +} +//------------------------------------------------------------------------------ +void BTextControl::WindowActivated(bool active) +{ + BControl::WindowActivated(active); +} +//------------------------------------------------------------------------------ +status_t BTextControl::Perform(perform_code d, void* arg) +{ + return BControl::Perform(d, arg); +} +//------------------------------------------------------------------------------ +void BTextControl::_ReservedTextControl1() +{ +} +//------------------------------------------------------------------------------ +void BTextControl::_ReservedTextControl2() +{ +} +//------------------------------------------------------------------------------ +void BTextControl::_ReservedTextControl3() +{ +} +//------------------------------------------------------------------------------ +void BTextControl::_ReservedTextControl4() +{ +} +//------------------------------------------------------------------------------ +BTextControl& BTextControl::operator=(const BTextControl&) +{ + // Assignment not allowed + return *this; +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/kits/interface/TextInput.cpp b/src/kits/interface/TextInput.cpp new file mode 100644 index 0000000000..4eabacaa59 --- /dev/null +++ b/src/kits/interface/TextInput.cpp @@ -0,0 +1,242 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: TextInput.cpp +// Author: Frans van Nispen (xlr8@tref.nl) +// Description: The BTextView derivative owned by an instance of +// BTextControl. +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- +#include + +// System Includes ------------------------------------------------------------- +#include +#include +#include +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "TextInput.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + + +//------------------------------------------------------------------------------ +_BTextInput_::_BTextInput_(BTextControl* parent, BRect frame, const char* name, + BRect rect, uint32 mask, uint32 flags) + : BTextView(frame, name, rect, mask, flags), + fEnabled(true), + fChanged(false), + fParent(parent) +{ + SetMaxBytes(255); + SetWordWrap(false); +} +//------------------------------------------------------------------------------ +_BTextInput_::~_BTextInput_() +{ +} +//------------------------------------------------------------------------------ +void _BTextInput_::SetEnabled(bool state) +{ + fEnabled = state; + if (fEnabled) + { + BView::SetFlags(Flags() | B_NAVIGABLE); + } + else + { + BView::SetFlags(Flags() & (0xffffffff - B_NAVIGABLE)); + } + + Invalidate(); +} +//------------------------------------------------------------------------------ +void _BTextInput_::AttachedToWindow() +{ + BFont font; + GetFont(&font); + float h = font.Size() + 6.0f; + ResizeTo(Bounds().Width(), h); + + fViewColor = BTextView::ViewColor(); +} +//------------------------------------------------------------------------------ +rgb_color _BTextInput_::ViewColor() +{ + return fViewColor; +} +//------------------------------------------------------------------------------ +void _BTextInput_::SetViewColor(rgb_color color) +{ + fViewColor = color; +} +//------------------------------------------------------------------------------ +void _BTextInput_::MakeFocus(bool state) +{ + BTextView::MakeFocus(state); + if (state) + { + BTextView::SetViewColor(255, 255, 255, 255); + fChanged = false; + SelectAll(); + } + else + { + BTextView::SetViewColor(fViewColor); + } + + Invalidate(); +} +//------------------------------------------------------------------------------ +bool _BTextInput_::CanEndLine(int32 end) +{ + return false; +} +//------------------------------------------------------------------------------ +void _BTextInput_::KeyDown(const char* bytes, int32 numBytes) +{ + bool send = false; + + BMessage* msg = Window()->CurrentMessage(); + if (numBytes == 1) + { + switch (bytes[0]) + { + case B_UP_ARROW: + msg->ReplaceInt64("when", (int64)system_time()); + msg->ReplaceInt32("key", 38); + msg->ReplaceInt32("raw_char", B_TAB); + msg->ReplaceInt32("modifiers", B_SCROLL_LOCK | B_SHIFT_KEY); + msg->ReplaceInt8("byte", B_TAB); + msg->ReplaceString("bytes", ""); + fParent->BView::MakeFocus(true); + Looper()->PostMessage(msg); + send = true; + break; + + case B_ENTER: + { + SelectAll(); + send = true; + fChanged = true; + break; + } + + case B_DOWN_ARROW: + msg->ReplaceInt64("when", (int64)system_time()); + msg->ReplaceInt32("key", 38); + msg->ReplaceInt32("raw_char", B_TAB); + msg->ReplaceInt8("byte", B_TAB); + msg->ReplaceString("bytes", ""); + Looper()->PostMessage(msg); + send = true; + break; + + case B_TAB: + // This will make sure that it will skip to the next object + BView::KeyDown(bytes, numBytes); + send = true; + break; + + default: + BTextView::KeyDown(bytes, numBytes); + } + } + else + { + BTextView::KeyDown(bytes, numBytes); + } + + if (send) + { + if (fChanged) + { + Window()->PostMessage(new BMessage(B_CONTROL_INVOKED), fParent); + } + } + else + { + Window()->PostMessage(new BMessage(B_CONTROL_MODIFIED), fParent); + } + + fChanged = true; +} +//------------------------------------------------------------------------------ +void _BTextInput_::MouseDown(BPoint where) +{ + if (fEnabled) + { + BTextView::MouseDown(where); + } +} +//------------------------------------------------------------------------------ +void _BTextInput_::Draw(BRect rect) +{ + + BTextView::Draw(rect); + + rect = Bounds(); + + rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR); + SetHighColor(tint_color(base, fEnabled ? + B_DARKEN_4_TINT : B_LIGHTEN_2_TINT)); + StrokeLine(BPoint(rect.left,rect.bottom), BPoint(rect.left, rect.top)); + StrokeLine(BPoint(rect.left+1.0f,rect.top), BPoint(rect.right, rect.top)); + SetHighColor(tint_color(base, B_NO_TINT)); + StrokeLine(BPoint(rect.left+1.0f,rect.bottom), + BPoint(rect.right, rect.bottom)); + StrokeLine(BPoint(rect.right,rect.bottom), + BPoint(rect.right, rect.top+1.0f)); + + if (IsFocus()) + { + SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR)); + StrokeRect(rect); + } + + if (!fEnabled) + { + rect.InsetBy(1,1); + SetDrawingMode(B_OP_ALPHA); + rgb_color color = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), + B_LIGHTEN_1_TINT); + color.alpha = 140; + SetHighColor(color); + FillRect(rect); + SetDrawingMode(B_OP_COPY); + } +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/kits/interface/interface.src b/src/kits/interface/interface.src new file mode 100644 index 0000000000..402f678356 --- /dev/null +++ b/src/kits/interface/interface.src @@ -0,0 +1,14 @@ +INTERFACE_KIT_SOURCE = + Alert.cpp + Box.cpp + Button.cpp + CheckBox.cpp + Control.cpp + Point.cpp + RadioButton.cpp + Rect.cpp + StatusBar.cpp + StringView.cpp + TextControl.cpp + TextInput.cpp +; diff --git a/src/kits/media/!missing_symbols.cpp b/src/kits/media/!missing_symbols.cpp new file mode 100644 index 0000000000..18f44d4e07 --- /dev/null +++ b/src/kits/media/!missing_symbols.cpp @@ -0,0 +1,134 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: !missing_symbols.cpp + * DESCR: Some undocumented symboles that libmedia.so exports. + * All return codes are guessed!!! (void most times means it's still wrong) + ***********************************************************************/ +#include +#include "debug.h" + +/* + +used by libgame.so +BPrivate::BTrackReader::CountFrames(void) +BPrivate::BTrackReader::Format(void) const +BPrivate::BTrackReader::FrameSize(void) +BPrivate::BTrackReader::ReadFrames(void *, long) +BPrivate::BTrackReader::SeekToFrame(long long *) +BPrivate::BTrackReader::Track(void) +BPrivate::BTrackReader::~BTrackReader(void) +BPrivate::BTrackReader::BTrackReader(BMediaTrack *, media_raw_audio_format const &) +BPrivate::BTrackReader::BTrackReader(BFile *, media_raw_audio_format const &) +BPrivate::dec_load_hook(void *, long) +BPrivate::extractor_load_hook(void *, long) +rtm_create_pool_etc +rtm_get_pool + +used by libmidi.so +BSubscriber::IsInStream(void) const +BSubscriber::BSubscriber(char const *) +00036a94 B BSubscriber type_info node +BDACStream::SamplingRate(float *) const +BDACStream::SetSamplingRate(float) +BDACStream::BDACStream(void) +00036a88 B BDACStream type_info node + +used by BeIDE +BSubscriber::EnterStream(_sub_info *, bool, void *, bool (*)(void *, char *, unsigned long, void *), long (*)(void *, long), bool) +BSubscriber::ExitStream(bool) +BSubscriber::ProcessLoop(void) +BSubscriber::Subscribe(BAbstractBufferStream *) +BSubscriber::Unsubscribe(void) +BSubscriber::~BSubscriber(void) +BSubscriber::_ReservedSubscriber1(void) +BSubscriber::_ReservedSubscriber2(void) +BSubscriber::_ReservedSubscriber3(void) +BSubscriber::BSubscriber(char const *) +001132c0 W BSubscriber type_info function +00180484 B BSubscriber type_info node +BDACStream::SetSamplingRate(float) +BDACStream::~BDACStream(void) +BDACStream::BDACStream(void) +00180478 B BDACStream type_info node + +used by 3dmiX +BDACStream::SetSamplingRate(float) +BDACStream::BDACStream(void) +000706c4 B BDACStream type_info node +BSubscriber::BSubscriber(char const *) +000706d0 B BSubscriber type_info node +*/ + +struct _sub_info +{ + uint32 dummy; +}; + +namespace BPrivate +{ + +int32 media_debug; /* is this a function, or a bool, or an int32 ??? */ + +//BPrivate::BTrackReader move to TrackReader.h & TrackReader.cpp + +/* + +Already in MediaFormats.cpp + +void dec_load_hook(void *, long); +void extractor_load_hook(void *, long); + +void dec_load_hook(void *, long) +{ +} + +void extractor_load_hook(void *, long) +{ +} +*/ + +}; + +class _BMediaRosterP +{ + void AddCleanupFunction(void (*)(void *), void *); + void RemoveCleanupFunction(void (*)(void *), void *); +}; + +void _BMediaRosterP::AddCleanupFunction(void (*)(void *), void *) +{ + UNIMPLEMENTED(); +} + +void _BMediaRosterP::RemoveCleanupFunction(void (*)(void *), void *) +{ + UNIMPLEMENTED(); +} + +extern "C" { + +int MIDIisInitializingWorkaroundForDoom; +/* + +these two moved to RealtimeAlloc.cpp + +void rtm_create_pool_etc(void); +int32 rtm_get_pool(int32,int32 **P); + +void rtm_create_pool_etc(void) +{ + UNIMPLEMENTED(); +} + +int32 rtm_get_pool(int32,int32 **p) +{ + UNIMPLEMENTED(); + *p = (int32*)0x1199; + return B_OK; +} + +*/ + + +} + diff --git a/src/kits/media/Buffer.cpp b/src/kits/media/Buffer.cpp new file mode 100644 index 0000000000..196e4d7f85 --- /dev/null +++ b/src/kits/media/Buffer.cpp @@ -0,0 +1,284 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: Buffer.cpp + * DESCR: + ***********************************************************************/ +#include +#include +#include +#include "SharedBufferList.h" +#include "debug.h" +#include "../server/headers/ServerInterface.h" + +static team_id CurrentTeam(); +team_id CurrentTeam() +{ + thread_info info; + get_thread_info(find_thread(NULL),&info); + return info.team; +} + +/************************************************************* + * public struct buffer_clone_info + *************************************************************/ + +buffer_clone_info::buffer_clone_info() +{ + CALLED(); + buffer = 0; + area = 0; + offset = 0; + size = 0; + flags = 0; +} + + +buffer_clone_info::~buffer_clone_info() +{ + CALLED(); +} + +/************************************************************* + * public BBuffer + *************************************************************/ + +void * +BBuffer::Data() +{ + CALLED(); + return fData; +} + + +size_t +BBuffer::SizeAvailable() +{ + CALLED(); + return fSize; +} + + +size_t +BBuffer::SizeUsed() +{ + CALLED(); + return fMediaHeader.size_used; +} + + +void +BBuffer::SetSizeUsed(size_t size_used) +{ + CALLED(); + fMediaHeader.size_used = min_c(size_used,fSize); +} + + +uint32 +BBuffer::Flags() +{ + CALLED(); + return fFlags; +} + + +void +BBuffer::Recycle() +{ + CALLED(); + if (fBufferList == NULL) + return; + fBufferList->RecycleBuffer(this); +} + + +buffer_clone_info +BBuffer::CloneInfo() const +{ + CALLED(); + buffer_clone_info info; + + info.buffer = fBufferID; + info.area = fArea; + info.offset = fOffset; + info.size = fSize; + info.flags = fFlags; + + return info; +} + + +media_buffer_id +BBuffer::ID() +{ + CALLED(); + return fBufferID; +} + + +media_type +BBuffer::Type() +{ + CALLED(); + return fMediaHeader.type; +} + + +media_header * +BBuffer::Header() +{ + CALLED(); + return &fMediaHeader; +} + + +media_audio_header * +BBuffer::AudioHeader() +{ + CALLED(); + return &fMediaHeader.u.raw_audio; +} + + +media_video_header * +BBuffer::VideoHeader() +{ + CALLED(); + return &fMediaHeader.u.raw_video; +} + + +size_t +BBuffer::Size() +{ + CALLED(); + return SizeAvailable(); +} + +/************************************************************* + * private BBuffer + *************************************************************/ + +/* explicit */ +BBuffer::BBuffer(const buffer_clone_info & info) : + fBufferList(0), // must be 0 if not correct initialized + fData(0), // must be 0 if not correct initialized + fSize(0), // should be 0 if not correct initialized + fBufferID(0) // must be 0 if not registered +{ + CALLED(); + + // special case for BSmallBuffer + if (info.area == 0 && info.buffer == 0) + return; + + // ask media_server to get the area_id of the shared buffer list + area_id id; + BMessage request(MEDIA_SERVER_GET_SHARED_BUFFER_AREA); + BMessage reply; + + if (MediaKitPrivate::QueryServer(&request, &reply) != B_OK) + return; + + id = reply.FindInt32("area"); + + fBufferList = _shared_buffer_list::Clone(id); + if (fBufferList == NULL) + return; + + + BMessage response; + BMessage create(MEDIA_SERVER_REGISTER_BUFFER); + create.AddInt32("team",CurrentTeam()); + create.AddInt32("area",info.area); + create.AddInt32("offset",info.offset); + create.AddInt32("size",info.size); + create.AddInt32("flags",info.flags); + create.AddInt32("buffer",info.buffer); + + // ask media_server to register this buffer, + // either identified by "buffer" or by area information. + // media_server either has a copy of the area identified + // by "buffer", or creates a new area. + // the information and the area is cached by the media_server + // until the last buffer has been unregistered + // the area_id of the cached area is passed back to us, and we clone it. + + if (MediaKitPrivate::QueryServer(&create, &response) != B_OK) + return; + + // the response from media server contains enough information + // to clone the memory for this buffer + fBufferID = response.FindInt32("buffer"); + fSize = response.FindInt32("size"); + fFlags = response.FindInt32("flags"); + fOffset = response.FindInt32("offset"); + id = response.FindInt32("area"); + + fArea = clone_area("a cloned BBuffer", &fData, B_ANY_ADDRESS,B_READ_AREA | B_WRITE_AREA,id); + if (fArea <= B_OK) { + TRACE("buffer cloning failed\n"); + fData = 0; + return; + } + + fData = (char *)fData + fOffset; + fMediaHeader.size_used = 0; +} + + +BBuffer::~BBuffer() +{ + CALLED(); + // unmap the BufferList + if (fBufferList != NULL) { + fBufferList->Unmap(); + } + // unmap the Data + if (fData != NULL) { + BMessage unregister(MEDIA_SERVER_UNREGISTER_BUFFER); + BMessage response; + unregister.AddInt32("team",(int32)CurrentTeam()); + unregister.AddInt32("buffer",fBufferID); + + // ask media_server to unregister the buffer + // when the last clone of this buffer is gone, + // media_server will also remove it's cached area + + MediaKitPrivate::QueryServer(&unregister, &response); + + delete_area(fArea); + } +} + + +void +BBuffer::SetHeader(const media_header *header) +{ + CALLED(); + fMediaHeader = *header; + fMediaHeader.buffer = fBufferID; +} + + +/************************************************************* + * public BSmallBuffer + *************************************************************/ + +static const buffer_clone_info info; +BSmallBuffer::BSmallBuffer() + : BBuffer(info) +{ + UNIMPLEMENTED(); + debugger("BSmallBuffer::BSmallBuffer called\n"); +} + + +size_t +BSmallBuffer::SmallBufferSizeLimit() +{ + CALLED(); + return 64; +} + + diff --git a/src/kits/media/BufferConsumer.cpp b/src/kits/media/BufferConsumer.cpp new file mode 100644 index 0000000000..2d303d0a52 --- /dev/null +++ b/src/kits/media/BufferConsumer.cpp @@ -0,0 +1,560 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: BufferConsumer.cpp + * DESCR: + ***********************************************************************/ +#include +#include +#include +#include +#include +#include "debug.h" +#include "../server/headers/ServerInterface.h" +#include "BufferIdCache.h" + +/************************************************************* + * protected BBufferConsumer + *************************************************************/ + +/* virtual */ +BBufferConsumer::~BBufferConsumer() +{ + CALLED(); + delete fBufferCache; + if (fDeleteBufferGroup) + delete fDeleteBufferGroup; +} + + +/************************************************************* + * public BBufferConsumer + *************************************************************/ + +media_type +BBufferConsumer::ConsumerType() +{ + CALLED(); + return fConsumerType; +} + + +/* static */ status_t +BBufferConsumer::RegionToClipData(const BRegion *region, + int32 *format, + int32 *ioSize, + void *data) +{ + CALLED(); + + status_t rv; + int count; + + count = *ioSize / sizeof(int16); + rv = BBufferProducer::clip_region_to_shorts(region, (int16 *)data, count, &count); + *ioSize = count * sizeof(int16); + *format = BBufferProducer::B_CLIP_SHORT_RUNS; + + return rv; +} + +/************************************************************* + * protected BBufferConsumer + *************************************************************/ + +/* explicit */ +BBufferConsumer::BBufferConsumer(media_type consumer_type) : + BMediaNode("called by BBufferConsumer"), + fConsumerType(consumer_type), + fBufferCache(new _buffer_id_cache), + fDeleteBufferGroup(0) +{ + CALLED(); + + AddNodeKind(B_BUFFER_CONSUMER); +} + + +/* static */ void +BBufferConsumer::NotifyLateProducer(const media_source &what_source, + bigtime_t how_much, + bigtime_t performance_time) +{ + CALLED(); + if (what_source == media_source::null) + return; + + xfer_producer_late_notice_received data; + data.source = what_source; + data.how_much = how_much; + data.performance_time = performance_time; + + write_port(what_source.port, PRODUCER_LATE_NOTICE_RECEIVED, &data, sizeof(data)); +} + + +status_t +BBufferConsumer::SetVideoClippingFor(const media_source &output, + const media_destination &destination, + const int16 *shorts, + int32 short_count, + const media_video_display_info &display, + void *user_data, + int32 *change_tag, + void *_reserved_) +{ + CALLED(); + if (output == media_source::null) + return B_MEDIA_BAD_SOURCE; + if (destination == media_destination::null) + return B_MEDIA_BAD_DESTINATION; + if (short_count > int(B_MEDIA_MESSAGE_SIZE - sizeof(xfer_producer_video_clipping_changed)) / 2) + debugger("BBufferConsumer::SetVideoClippingFor short_count too large (8000 limit)\n"); + + xfer_producer_video_clipping_changed *data; + size_t size; + status_t rv; + + size = sizeof(xfer_producer_video_clipping_changed) + short_count * 2; + data = (xfer_producer_video_clipping_changed *) malloc(size); + data->source = output; + data->destination = destination; + data->display = display; + data->user_data = user_data; + data->change_tag = NewChangeTag(); + data->short_count = short_count; + memcpy(data->shorts, shorts, short_count * 2); + if (change_tag != NULL) + *change_tag = data->change_tag; + + rv = write_port(output.port, PRODUCER_VIDEO_CLIPPING_CHANGED, data, size); + free(data); + return rv; +} + + +status_t +BBufferConsumer::SetOutputEnabled(const media_source &source, + const media_destination &destination, + bool enabled, + void *user_data, + int32 *change_tag, + void *_reserved_) +{ + CALLED(); + if (destination == media_destination::null) + return B_MEDIA_BAD_DESTINATION; + if (source == media_source::null) + return B_MEDIA_BAD_SOURCE; + + xfer_producer_enable_output data; + + data.source = source; + data.destination = destination; + data.enabled = enabled; + data.user_data = user_data; + data.change_tag = NewChangeTag(); + if (change_tag != NULL) + *change_tag = data.change_tag; + + return write_port(source.port, PRODUCER_ENABLE_OUTPUT, &data, sizeof(data)); +} + + +status_t +BBufferConsumer::RequestFormatChange(const media_source &source, + const media_destination &destination, + const media_format &to_format, + void *user_data, + int32 *change_tag, + void *_reserved_) +{ + CALLED(); + if (destination == media_destination::null) + return B_MEDIA_BAD_DESTINATION; + if (source == media_source::null) + return B_MEDIA_BAD_SOURCE; + + xfer_producer_format_change_requested data; + + data.source = source; + data.destination = destination; + data.format = to_format; + data.user_data = user_data; + data.change_tag = NewChangeTag(); + if (change_tag != NULL) + *change_tag = data.change_tag; + + return write_port(source.port, PRODUCER_FORMAT_CHANGE_REQUESTED, &data, sizeof(data)); +} + + +status_t +BBufferConsumer::RequestAdditionalBuffer(const media_source &source, + BBuffer *prev_buffer, + void *_reserved) +{ + CALLED(); + if (source == media_source::null) + return B_MEDIA_BAD_SOURCE; + + xfer_producer_additional_buffer_requested data; + + data.source = source; + data.prev_buffer = prev_buffer->ID(); + data.prev_time = 0; + data.has_seek_tag = false; + //data.prev_tag = + + return write_port(source.port, PRODUCER_ADDITIONAL_BUFFER_REQUESTED, &data, sizeof(data)); +} + + +status_t +BBufferConsumer::RequestAdditionalBuffer(const media_source &source, + bigtime_t start_time, + void *_reserved) +{ + CALLED(); + if (source == media_source::null) + return B_MEDIA_BAD_SOURCE; + + xfer_producer_additional_buffer_requested data; + + data.source = source; + data.prev_buffer = 0; + data.prev_time = start_time; + data.has_seek_tag = false; + //data.prev_tag = + + return write_port(source.port, PRODUCER_ADDITIONAL_BUFFER_REQUESTED, &data, sizeof(data)); +} + + +status_t +BBufferConsumer::SetOutputBuffersFor(const media_source &source, + const media_destination &destination, + BBufferGroup *group, + void *user_data, + int32 *change_tag, + bool will_reclaim, + void *_reserved_) +{ + CALLED(); + + if (source == media_source::null) + return B_MEDIA_BAD_SOURCE; + if (destination == media_destination::null) + return B_MEDIA_BAD_DESTINATION; + + xfer_producer_set_buffer_group *data; + BBuffer **buffers; + int32 buffer_count; + size_t size; + status_t rv; + + if (group == 0) { + buffer_count = 0; + } else { + if (B_OK != group->CountBuffers(&buffer_count)) + return B_ERROR; + } + + if (buffer_count != 0) { + buffers = new BBuffer * [buffer_count]; + if (B_OK != group->GetBufferList(buffer_count,buffers)) { + delete buffers; + return B_ERROR; + } + } else { + buffers = NULL; + } + + size = sizeof(xfer_producer_set_buffer_group) + buffer_count * sizeof(media_buffer_id); + data = (xfer_producer_set_buffer_group *) malloc(size); + data->source = source; + data->destination = destination; + data->user_data = user_data; + data->change_tag = NewChangeTag(); + data->buffer_count = buffer_count; + for (int32 i = 0; i < buffer_count; i++) + data->buffers[i] = buffers[i]->ID(); + if (change_tag != NULL) + *change_tag = data->change_tag; + + rv = write_port(source.port, PRODUCER_SET_BUFFER_GROUP, data, size); + free(data); + delete [] buffers; + + if (rv == B_OK) { + if (fDeleteBufferGroup) + delete fDeleteBufferGroup; + fDeleteBufferGroup = will_reclaim ? group : NULL; + } + return rv; +} + + +status_t +BBufferConsumer::SendLatencyChange(const media_source &source, + const media_destination &destination, + bigtime_t my_new_latency, + uint32 flags) +{ + CALLED(); + if (destination == media_destination::null) + return B_MEDIA_BAD_DESTINATION; + if (source == media_source::null) + return B_MEDIA_BAD_SOURCE; + + xfer_producer_latency_changed data; + + data.source = source; + data.destination = destination; + data.latency = my_new_latency; + data.flags = flags; + + return write_port(source.port, PRODUCER_LATENCY_CHANGED, &data, sizeof(data)); +} + +/************************************************************* + * protected BBufferConsumer + *************************************************************/ + +/* virtual */ status_t +BBufferConsumer::HandleMessage(int32 message, + const void *rawdata, + size_t size) +{ + CALLED(); + switch (message) { + case CONSUMER_ACCEPT_FORMAT: + { + const xfer_consumer_accept_format *data = (const xfer_consumer_accept_format *)rawdata; + xfer_consumer_accept_format_reply reply; + reply.format = data->format; + reply.result = AcceptFormat(data->dest, &reply.format); + write_port(data->reply_port, 0, &reply, sizeof(reply)); + return B_OK; + } + + case CONSUMER_GET_NEXT_INPUT: + { + const xfer_consumer_get_next_input *data = (const xfer_consumer_get_next_input *)rawdata; + xfer_consumer_get_next_input_reply reply; + reply.cookie = data->cookie; + reply.result = GetNextInput(&reply.cookie, &reply.input); + write_port(data->reply_port, 0, &reply, sizeof(reply)); + return B_OK; + } + + case CONSUMER_DISPOSE_INPUT_COOKIE: + { + const xfer_consumer_dispose_input_cookie *data = (const xfer_consumer_dispose_input_cookie *)rawdata; + DisposeInputCookie(data->cookie); + return B_OK; + } + + case CONSUMER_BUFFER_RECEIVED: + { + const xfer_consumer_buffer_received *data = (const xfer_consumer_buffer_received *)rawdata; + BBuffer *buffer; + buffer = fBufferCache->GetBuffer(data->buffer); + buffer->SetHeader(&data->header); + BufferReceived(buffer); + return B_OK; + } + + case CONSUMER_PRODUCER_DATA_STATUS: + { + const xfer_consumer_producer_data_status *data = (const xfer_consumer_producer_data_status *)rawdata; + ProducerDataStatus(data->for_whom, data->status, data->at_performance_time); + return B_OK; + } + + case CONSUMER_GET_LATENCY_FOR: + { + const xfer_consumer_get_latency_for *data = (const xfer_consumer_get_latency_for *)rawdata; + xfer_consumer_get_latency_for_reply reply; + reply.result = GetLatencyFor(data->for_whom, &reply.latency, &reply.timesource); + write_port(data->reply_port, 0, &reply, sizeof(reply)); + return B_OK; + } + + case CONSUMER_CONNECTED: + { + const xfer_consumer_connected *data = (const xfer_consumer_connected *)rawdata; + xfer_consumer_connected_reply reply; + reply.result = Connected(data->producer, data->where, data->with_format, &reply.input); + write_port(data->reply_port, 0, &reply, sizeof(reply)); + return B_OK; + } + + case CONSUMER_DISCONNECTED: + { + const xfer_consumer_disconnected *data = (const xfer_consumer_disconnected *)rawdata; + Disconnected(data->producer, data->where); + return B_OK; + } + + case CONSUMER_FORMAT_CHANGED: + { + const xfer_consumer_format_changed *data = (const xfer_consumer_format_changed *)rawdata; + xfer_consumer_format_changed_reply reply; + reply.result = FormatChanged(data->producer, data->consumer, data->change_tag, data->format); + write_port(data->reply_port, 0, &reply, sizeof(reply)); + + // XXX is this RequestCompleted() correct? + xfer_node_request_completed completed; + completed.info.what = media_request_info::B_FORMAT_CHANGED; + completed.info.change_tag = data->change_tag; + completed.info.status = reply.result; + //completed.info.cookie + completed.info.user_data = 0; + completed.info.source = data->producer; + completed.info.destination = data->consumer; + completed.info.format = data->format; + write_port(data->consumer.port, NODE_REQUEST_COMPLETED, &completed, sizeof(completed)); + return B_OK; + } + + case CONSUMER_SEEK_TAG_REQUESTED: + { + const xfer_consumer_seek_tag_requested *data = (const xfer_consumer_seek_tag_requested *)rawdata; + xfer_consumer_seek_tag_requested_reply reply; + reply.result = SeekTagRequested(data->destination, data->target_time, data->flags, &reply.seek_tag, &reply.tagged_time, &reply.flags); + write_port(data->reply_port, 0, &reply, sizeof(reply)); + return B_OK; + } + + }; + return B_ERROR; +} + +status_t +BBufferConsumer::SeekTagRequested(const media_destination &destination, + bigtime_t in_target_time, + uint32 in_flags, + media_seek_tag *out_seek_tag, + bigtime_t *out_tagged_time, + uint32 *out_flags) +{ + CALLED(); + // may be implemented by derived classes + return B_ERROR; +} + +/************************************************************* + * private BBufferConsumer + *************************************************************/ + +/* +not implemented: +BBufferConsumer::BBufferConsumer() +BBufferConsumer::BBufferConsumer(const BBufferConsumer &clone) +BBufferConsumer & BBufferConsumer::operator=(const BBufferConsumer &clone) +*/ + +/* deprecated function for R4 */ +/* static */ status_t +BBufferConsumer::SetVideoClippingFor(const media_source &output, + const int16 *shorts, + int32 short_count, + const media_video_display_info &display, + int32 *change_tag) +{ + CALLED(); + if (output == media_source::null) + return B_MEDIA_BAD_SOURCE; + if (short_count > int(B_MEDIA_MESSAGE_SIZE - sizeof(xfer_producer_video_clipping_changed)) / 2) + debugger("BBufferConsumer::SetVideoClippingFor short_count too large (8000 limit)\n"); + + xfer_producer_video_clipping_changed *data; + size_t size; + status_t rv; + + size = sizeof(xfer_producer_video_clipping_changed) + short_count * 2; + data = (xfer_producer_video_clipping_changed *) malloc(size); + data->source = output; + data->destination = media_destination::null; + data->display = display; + data->user_data = 0; + data->change_tag = NewChangeTag(); + data->short_count = short_count; + memcpy(data->shorts, shorts, short_count * 2); + if (change_tag != NULL) + *change_tag = data->change_tag; + + rv = write_port(output.port, PRODUCER_VIDEO_CLIPPING_CHANGED, data, size); + free(data); + return rv; +} + + +/* deprecated function for R4 */ +/* static */ status_t +BBufferConsumer::RequestFormatChange(const media_source &source, + const media_destination &destination, + media_format *in_to_format, + int32 *change_tag) +{ + CALLED(); + if (destination == media_destination::null) + return B_MEDIA_BAD_DESTINATION; + if (source == media_source::null) + return B_MEDIA_BAD_SOURCE; + + xfer_producer_format_change_requested data; + + data.source = source; + data.destination = destination; + data.format = *in_to_format; + data.user_data = 0; + data.change_tag = NewChangeTag(); + if (change_tag != NULL) + *change_tag = data.change_tag; + + return write_port(source.port, PRODUCER_FORMAT_CHANGE_REQUESTED, &data, sizeof(data)); +} + + +/* deprecated function for R4 */ +/* static */ status_t +BBufferConsumer::SetOutputEnabled(const media_source &source, + bool enabled, + int32 *change_tag) +{ + CALLED(); + if (source == media_source::null) + return B_MEDIA_BAD_SOURCE; + + xfer_producer_enable_output data; + + data.source = source; + data.destination = media_destination::null; + data.enabled = enabled; + data.user_data = 0; + data.change_tag = NewChangeTag(); + if (change_tag != NULL) + *change_tag = data.change_tag; + + return write_port(source.port, PRODUCER_ENABLE_OUTPUT, &data, sizeof(data)); +} + + +status_t BBufferConsumer::_Reserved_BufferConsumer_0(void *) { return B_ERROR; } +status_t BBufferConsumer::_Reserved_BufferConsumer_1(void *) { return B_ERROR; } +status_t BBufferConsumer::_Reserved_BufferConsumer_2(void *) { return B_ERROR; } +status_t BBufferConsumer::_Reserved_BufferConsumer_3(void *) { return B_ERROR; } +status_t BBufferConsumer::_Reserved_BufferConsumer_4(void *) { return B_ERROR; } +status_t BBufferConsumer::_Reserved_BufferConsumer_5(void *) { return B_ERROR; } +status_t BBufferConsumer::_Reserved_BufferConsumer_6(void *) { return B_ERROR; } +status_t BBufferConsumer::_Reserved_BufferConsumer_7(void *) { return B_ERROR; } +status_t BBufferConsumer::_Reserved_BufferConsumer_8(void *) { return B_ERROR; } +status_t BBufferConsumer::_Reserved_BufferConsumer_9(void *) { return B_ERROR; } +status_t BBufferConsumer::_Reserved_BufferConsumer_10(void *) { return B_ERROR; } +status_t BBufferConsumer::_Reserved_BufferConsumer_11(void *) { return B_ERROR; } +status_t BBufferConsumer::_Reserved_BufferConsumer_12(void *) { return B_ERROR; } +status_t BBufferConsumer::_Reserved_BufferConsumer_13(void *) { return B_ERROR; } +status_t BBufferConsumer::_Reserved_BufferConsumer_14(void *) { return B_ERROR; } +status_t BBufferConsumer::_Reserved_BufferConsumer_15(void *) { return B_ERROR; } + diff --git a/src/kits/media/BufferGroup.cpp b/src/kits/media/BufferGroup.cpp new file mode 100644 index 0000000000..45e5748cec --- /dev/null +++ b/src/kits/media/BufferGroup.cpp @@ -0,0 +1,406 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: BufferGroup.cpp + * DESCR: + ***********************************************************************/ +#include +#include +#include +#include "debug.h" +#include "SharedBufferList.h" +#include "../server/headers/ServerInterface.h" + +/************************************************************* + * private BBufferGroup + *************************************************************/ + +status_t +BBufferGroup::InitBufferGroup() +{ + area_id id; + + // some defaults + fBufferList = 0; + fReclaimSem = B_ERROR; + fInitError = B_ERROR; + fRequestError = B_ERROR; + fBufferCount = 0; + + // create the reclaim semaphore + fReclaimSem = create_sem(0,"buffer reclaim sem"); + if (fReclaimSem < B_OK) { + fInitError = (status_t)fReclaimSem; + return fInitError; + } + + // ask media_server to get the area_id of the shared buffer list + BMessage request(MEDIA_SERVER_GET_SHARED_BUFFER_AREA); + BMessage reply; + + fInitError = MediaKitPrivate::QueryServer(&request, &reply); + if (fInitError != B_OK) + return fInitError; + + id = reply.FindInt32("area"); + + fBufferList = _shared_buffer_list::Clone(id); + if (fBufferList == NULL) + fInitError = B_ERROR; + + return fInitError; +} + + +/************************************************************* + * public BBufferGroup + *************************************************************/ + +BBufferGroup::BBufferGroup(size_t size, + int32 count, + uint32 placement, + uint32 lock) +{ + CALLED(); + if (InitBufferGroup() != B_OK) + return; + + // This one is easy. We need to create "count" BBuffers, + // each one "size" bytes large. They all go into one + // area, with "placement" and "lock" attributes. + // The BBuffers created will clone the area, and + // then we delete our area. This way BBuffers are + // independent from the BBufferGroup + + void *start_addr; + area_id buffer_area; + size_t area_size; + buffer_clone_info bci; + BBuffer *buffer; + + // don't allow all placement parameter values + if (placement != B_ANY_ADDRESS && placement != B_ANY_KERNEL_ADDRESS) { + TRACE("placement != B_ANY_ADDRESS && placement != B_ANY_KERNEL_ADDRESS (0x%08lx)\n",placement); + placement = B_ANY_ADDRESS; + } + + // first we roundup for a better placement in memory + size = (size + 63) & ~63; + + // now we create the area + area_size = ((size * count) + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1); + + buffer_area = create_area("some buffers area", &start_addr,placement,area_size,lock,B_READ_AREA | B_WRITE_AREA); + if (buffer_area < B_OK) { + TRACE("failed to allocate %ld bytes area\n",area_size); + fInitError = (status_t)buffer_area; + return; + } + + fBufferCount = count; + + for (int32 i = 0; i < count; i++) { + bci.area = buffer_area; + bci.offset = i * size; + bci.size = size; + buffer = new BBuffer(bci); + if (0 == buffer->Data()) { + // BBuffer::Data() will return 0 if an error occured + TRACE("error while creating buffer\n"); + delete buffer; + fInitError = B_ERROR; + break; + } + if (B_OK != fBufferList->AddBuffer(fReclaimSem,buffer)) { + TRACE("error when adding buffer\n"); + delete buffer; + fInitError = B_ERROR; + break; + } + } + + delete_area(buffer_area); +} + +/* explicit */ +BBufferGroup::BBufferGroup() +{ + CALLED(); + if (InitBufferGroup() != B_OK) + return; + + // this one simply creates an empty BBufferGroup +} + + +BBufferGroup::BBufferGroup(int32 count, + const media_buffer_id *buffers) +{ + CALLED(); + if (InitBufferGroup() != B_OK) + return; + + // XXX we need to make sure that a media_buffer_id is only added once to each group + + // this one creates "BBuffer"s from "media_buffer_id"s passed + // by the application. + + fBufferCount = count; + + buffer_clone_info bci; + BBuffer *buffer; + for (int32 i = 0; i < count; i++) { + bci.buffer = buffers[i]; + buffer = new BBuffer(bci); + if (0 == buffer->Data()) { + // BBuffer::Data() will return 0 if an error occured + TRACE("error while creating buffer\n"); + delete buffer; + fInitError = B_ERROR; + break; + } + if (B_OK != fBufferList->AddBuffer(fReclaimSem,buffer)) { + TRACE("error when adding buffer\n"); + delete buffer; + fInitError = B_ERROR; + break; + } + } +} + + +BBufferGroup::~BBufferGroup() +{ + CALLED(); + if (fBufferList) + fBufferList->Terminate(fReclaimSem); + if (fReclaimSem >= B_OK) + delete_sem(fReclaimSem); +} + + +status_t +BBufferGroup::InitCheck() +{ + CALLED(); + return fInitError; +} + + +status_t +BBufferGroup::AddBuffer(const buffer_clone_info &info, + BBuffer **out_buffer) +{ + CALLED(); + if (fInitError != B_OK) + return B_NO_INIT; + + // XXX we need to make sure that a media_buffer_id is only added once to each group + + BBuffer *buffer; + buffer = new BBuffer(info); + if (0 == buffer->Data()) { + // BBuffer::Data() will return 0 if an error occured + TRACE("error while creating buffer\n"); + delete buffer; + return B_ERROR; + } + if (B_OK != fBufferList->AddBuffer(fReclaimSem,buffer)) { + TRACE("error when adding buffer\n"); + delete buffer; + fInitError = B_ERROR; + return B_ERROR; + } + atomic_add(&fBufferCount,1); + + if (out_buffer != 0) + *out_buffer = buffer; + + return B_OK; +} + + +BBuffer * +BBufferGroup::RequestBuffer(size_t size, + bigtime_t timeout) +{ + CALLED(); + if (fInitError != B_OK) + return NULL; + + if (size <= 0) + return NULL; + + BBuffer *buffer; + status_t status; + + buffer = NULL; + status = fBufferList->RequestBuffer(fReclaimSem, fBufferCount, size, 0, &buffer, timeout); + fRequestError = status; + + return (status == B_OK) ? buffer : NULL; +} + + +status_t +BBufferGroup::RequestBuffer(BBuffer *buffer, + bigtime_t timeout) +{ + CALLED(); + if (fInitError != B_OK) + return B_NO_INIT; + + if (buffer == NULL) + return B_BAD_VALUE; + + status_t status; + status = fBufferList->RequestBuffer(fReclaimSem, fBufferCount, 0, 0, &buffer, timeout); + fRequestError = status; + + return status; +} + + +status_t +BBufferGroup::RequestError() +{ + CALLED(); + if (fInitError != B_OK) + return B_NO_INIT; + + return fRequestError; +} + + +status_t +BBufferGroup::CountBuffers(int32 *out_count) +{ + CALLED(); + if (fInitError != B_OK) + return B_NO_INIT; + + *out_count = fBufferCount; + return B_OK; +} + + +status_t +BBufferGroup::GetBufferList(int32 buf_count, + BBuffer **out_buffers) +{ + CALLED(); + if (fInitError != B_OK) + return B_NO_INIT; + + if (buf_count <= 0 || buf_count > fBufferCount) + return B_BAD_VALUE; + + return fBufferList->GetBufferList(fReclaimSem,buf_count,out_buffers); +} + + +status_t +BBufferGroup::WaitForBuffers() +{ + CALLED(); + if (fInitError != B_OK) + return B_NO_INIT; + + // XXX this function is not really useful anyway, and will + // XXX not work exactly as documented, but it is close enough + + if (fBufferCount < 0) + return B_BAD_VALUE; + if (fBufferCount == 0) + return B_OK; + + // we need to wait until at least one buffer belonging to this group is reclaimed. + // this has happened when can aquire "fReclaimSem" + + status_t status; + while (B_INTERRUPTED == (status = acquire_sem(fReclaimSem))) + ; + + if (status != B_OK) // some error happened + return status; + + // we need to release the "fReclaimSem" now, else we would block requesting of new buffers + + return release_sem(fReclaimSem); +} + + +status_t +BBufferGroup::ReclaimAllBuffers() +{ + CALLED(); + if (fInitError != B_OK) + return B_NO_INIT; + + // because additional BBuffers might get added to this group betweeen acquire and release + int32 count = fBufferCount; + + if (count < 0) + return B_BAD_VALUE; + if (count == 0) + return B_OK; + + // we need to wait until all BBuffers belonging to this group are reclaimed. + // this has happened when the "fReclaimSem" can be aquired "fBufferCount" times + + status_t status; + while (B_INTERRUPTED == (status = acquire_sem_etc(fReclaimSem, count, 0, 0))) + ; + + if (status != B_OK) // some error happened + return status; + + // we need to release the "fReclaimSem" now, else we would block requesting of new buffers + + return release_sem_etc(fReclaimSem, count, 0); +} + +/************************************************************* + * private BBufferGroup + *************************************************************/ + +/* not implemented */ +/* +BBufferGroup::BBufferGroup(const BBufferGroup &) +BBufferGroup & BBufferGroup::operator=(const BBufferGroup &) +*/ + +status_t +BBufferGroup::AddBuffersTo(BMessage * message, const char * name, bool needLock) +{ + CALLED(); + if (fInitError != B_OK) + return B_NO_INIT; + + // BeOS R4 legacy API. Implemented as a wrapper around GetBufferList + // "needLock" is ignored, GetBufferList will do locking + + if (message == NULL) + return B_BAD_VALUE; + + if (name == NULL || strlen(name) == 0) + return B_BAD_VALUE; + + BBuffer ** buffers; + status_t status; + int32 count; + + count = fBufferCount; + buffers = new BBuffer * [count]; + + if (B_OK != (status = GetBufferList(count,buffers))) + goto end; + + for (int32 i = 0; i < count; i++) + if (B_OK != (status = message->AddInt32(name,int32(buffers[i]->ID())))) + goto end; + +end: + delete [] buffers; + return status; +} + diff --git a/src/kits/media/BufferIdCache.cpp b/src/kits/media/BufferIdCache.cpp new file mode 100644 index 0000000000..de5ed9a786 --- /dev/null +++ b/src/kits/media/BufferIdCache.cpp @@ -0,0 +1,84 @@ +/*********************************************************************** + * Copyright (c) 2002 Marcus Overhagen. All Rights Reserved. + * This file may be used under the terms of the OpenBeOS License. + * + * A cache for BBuffers to be received by + * BBufferConsumer::BufferReceived() + ***********************************************************************/ + +#include +#include "BufferIdCache.h" +#include "debug.h" + +_buffer_id_cache::_buffer_id_cache() : + in_use(0), + used(0), + stat_missed(0), + stat_hit(0) +{ + for (int i = 0; i < MAX_CACHED_BUFFER; i++) { + info[i].buffer = 0; + info[i].id = 0; + info[i].last_used = 0; + } +} + +_buffer_id_cache::~_buffer_id_cache() +{ + for (int i = 0; i < MAX_CACHED_BUFFER; i++) + if (info[i].buffer) + delete info[i].buffer; + TRACE("### _buffer_id_cache finished, %ld in_use, %ld used, %ld hit, %ld missed\n",in_use,used,stat_hit,stat_missed); +} + +BBuffer * +_buffer_id_cache::GetBuffer(media_buffer_id id) +{ + if (id == 0) + debugger("_buffer_id_cache::GetBuffer called with 0 id\n"); + + used++; + + // try to find in cache + for (int i = 0; i < MAX_CACHED_BUFFER; i++) { + if (info[i].id == id) { + stat_hit++; + info[i].last_used = used; + return info[i].buffer; + } + } + + stat_missed++; + + // remove last recently used + if (in_use == MAX_CACHED_BUFFER) { + int32 min_last_used = used; + int index = 0; + for (int i = 0; i < MAX_CACHED_BUFFER; i++) { + if (info[i].last_used < min_last_used) { + min_last_used = info[i].last_used; + index = i; + } + } + delete info[index].buffer; + info[index].buffer = NULL; + in_use--; + } + + BBuffer *buffer; + buffer_clone_info ci; + ci.buffer = id; + buffer = new BBuffer(ci); + + // insert into cache + for (int i = 0; i < MAX_CACHED_BUFFER; i++) { + if (info[i].buffer == NULL) { + info[i].buffer = buffer; + info[i].id = id; + info[i].last_used = used; + in_use++; + break; + } + } + return buffer; +} diff --git a/src/kits/media/BufferIdCache.h b/src/kits/media/BufferIdCache.h new file mode 100644 index 0000000000..e6ff1a7d1b --- /dev/null +++ b/src/kits/media/BufferIdCache.h @@ -0,0 +1,34 @@ +/*********************************************************************** + * Copyright (c) 2002 Marcus Overhagen. All Rights Reserved. + * This file may be used under the terms of the OpenBeOS License. + * + * A cache for BBuffers to be received by + * BBufferConsumer::BufferReceived() + ***********************************************************************/ +#ifndef _BUFFER_ID_CACHE_H_ +#define _BUFFER_ID_CACHE_H_ + +class _buffer_id_cache +{ +public: + _buffer_id_cache(); + ~_buffer_id_cache(); + + BBuffer *GetBuffer(media_buffer_id id); + +private: + enum { MAX_CACHED_BUFFER = 17 }; + struct _buffer_id_info + { + BBuffer *buffer; + media_buffer_id id; + int32 last_used; + }; + _buffer_id_info info[MAX_CACHED_BUFFER]; + int32 in_use; + int32 used; + int32 stat_missed; + int32 stat_hit; +}; + +#endif diff --git a/src/kits/media/BufferProducer.cpp b/src/kits/media/BufferProducer.cpp new file mode 100644 index 0000000000..d7f88b0180 --- /dev/null +++ b/src/kits/media/BufferProducer.cpp @@ -0,0 +1,571 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: BufferProducer.cpp + * DESCR: + ***********************************************************************/ +#include +#include +#include +#include "PortPool.h" +#include "debug.h" +#include "../server/headers/ServerInterface.h" + +/************************************************************* + * protected BBufferProducer + *************************************************************/ + +BBufferProducer::~BBufferProducer() +{ + CALLED(); +} + +/************************************************************* + * public BBufferProducer + *************************************************************/ + +/* static */ status_t +BBufferProducer::ClipDataToRegion(int32 format, + int32 size, + const void *data, + BRegion *region) +{ + CALLED(); + + if (format != B_CLIP_SHORT_RUNS) + return B_MEDIA_BAD_CLIP_FORMAT; + + return clip_shorts_to_region((const int16 *)data, size / sizeof(int16), region); +} + +media_type +BBufferProducer::ProducerType() +{ + CALLED(); + return fProducerType; +} + +/************************************************************* + * protected BBufferProducer + *************************************************************/ + +/* explicit */ +BBufferProducer::BBufferProducer(media_type producer_type) : + BMediaNode("called by BBufferProducer"), + fProducerType(producer_type), + fInitialLatency(0), + fInitialFlags(0) +{ + CALLED(); + + AddNodeKind(B_BUFFER_PRODUCER); +} + + +status_t +BBufferProducer::VideoClippingChanged(const media_source &for_source, + int16 num_shorts, + int16 *clip_data, + const media_video_display_info &display, + int32 *_deprecated_) +{ + CALLED(); + // may be implemented by derived classes + return B_ERROR; +} + + +status_t +BBufferProducer::GetLatency(bigtime_t *out_lantency) +{ + UNIMPLEMENTED(); + + // XXX The default implementation of GetLatency() finds the maximum + // latency of your currently-available outputs by iterating over + // them, and returns that value in outLatency + + return B_ERROR; +} + + +status_t +BBufferProducer::SetPlayRate(int32 numer, + int32 denom) +{ + CALLED(); + // may be implemented by derived classes + return B_ERROR; +} + + +status_t +BBufferProducer::HandleMessage(int32 message, + const void *rawdata, + size_t size) +{ + CALLED(); + switch (message) { + + case PRODUCER_FORMAT_SUGGESTION_REQUESTED: + { + const xfer_producer_format_suggestion_requested *data = (const xfer_producer_format_suggestion_requested *)rawdata; + xfer_producer_format_suggestion_requested_reply reply; + reply.result = FormatSuggestionRequested(data->type, data->quality, &reply.format); + write_port(data->reply_port, 0, &reply, sizeof(reply)); + return B_OK; + } + + case PRODUCER_FORMAT_PROPOSAL: + { + const xfer_producer_format_proposal *data = (const xfer_producer_format_proposal *)rawdata; + xfer_producer_format_proposal_reply reply; + reply.result = FormatProposal(data->output, (media_format *)&data->format); + write_port(data->reply_port, 0, &reply, sizeof(reply)); + return B_OK; + } + + case PRODUCER_PREPARE_TO_CONNECT: + { + const xfer_producer_prepare_to_connect *data = (const xfer_producer_prepare_to_connect *)rawdata; + xfer_producer_prepare_to_connect_reply reply; + reply.format = data->format; + reply.name[0] = 0; + reply.result = PrepareToConnect(data->source, data->destination, &reply.format, &reply.out_source, reply.name); + write_port(data->reply_port, 0, &reply, sizeof(reply)); + return B_OK; + } + + case PRODUCER_CONNECT: + { + const xfer_producer_connect *data = (const xfer_producer_connect *)rawdata; + xfer_producer_connect_reply reply; + memcpy(reply.name, data->name, B_MEDIA_NAME_LENGTH); + Connect(data->error, data->source, data->destination, data->format, reply.name); + write_port(data->reply_port, 0, &reply, sizeof(reply)); + return B_OK; + } + + case PRODUCER_DISCONNECT: + { + const xfer_producer_disconnect *data = (const xfer_producer_disconnect *)rawdata; + Disconnect(data->source, data->destination); + return B_OK; + } + + case PRODUCER_GET_INITIAL_LATENCY: + { + const xfer_producer_get_initial_latency *data = (const xfer_producer_get_initial_latency *)rawdata; + xfer_producer_get_initial_latency_reply reply; + reply.initial_latency = fInitialLatency; + reply.flags = fInitialFlags; + write_port(data->reply_port, 0, &reply, sizeof(reply)); + return B_OK; + } + + case PRODUCER_SET_PLAY_RATE: + { + const xfer_producer_set_play_rate *data = (const xfer_producer_set_play_rate *)rawdata; + xfer_producer_set_play_rate_reply reply; + reply.result = SetPlayRate(data->numer, data->denom); + write_port(data->reply_port, 0, &reply, sizeof(reply)); + return B_OK; + } + + case PRODUCER_GET_LATENCY: + { + const xfer_producer_get_latency *data = (const xfer_producer_get_latency *)rawdata; + xfer_producer_get_latency_reply reply; + reply.result = GetLatency(&reply.latency); + write_port(data->reply_port, 0, &reply, sizeof(reply)); + return B_OK; + } + + case PRODUCER_GET_NEXT_OUTPUT: + { + const xfer_producer_get_next_output *data = (const xfer_producer_get_next_output *)rawdata; + xfer_producer_get_next_output_reply reply; + reply.cookie = data->cookie; + reply.result = GetNextOutput(&reply.cookie, &reply.output); + write_port(data->reply_port, 0, &reply, sizeof(reply)); + return B_OK; + } + + case PRODUCER_DISPOSE_OUTPUT_COOKIE: + { + const xfer_producer_dispose_output_cookie *data = (const xfer_producer_dispose_output_cookie *)rawdata; + DisposeOutputCookie(data->cookie); + return B_OK; + } + + case PRODUCER_SET_BUFFER_GROUP: + { + const xfer_producer_set_buffer_group *data = (const xfer_producer_set_buffer_group *)rawdata; + xfer_node_request_completed reply; + BBufferGroup *group; + status_t rv; + group = data->buffer_count != 0 ? new BBufferGroup(data->buffer_count, data->buffers) : NULL; + rv = SetBufferGroup(data->source, group); + if (data->destination == media_destination::null) + return B_OK; + reply.info.what = media_request_info::B_SET_OUTPUT_BUFFERS_FOR; + reply.info.change_tag = data->change_tag; + reply.info.status = rv; + reply.info.cookie = (int32)group; + reply.info.user_data = data->user_data; + reply.info.source = data->source; + reply.info.destination = data->destination; + write_port(data->destination.port, NODE_REQUEST_COMPLETED, &reply, sizeof(reply)); + return B_OK; + } + + case PRODUCER_FORMAT_CHANGE_REQUESTED: + { + const xfer_producer_format_change_requested *data = (const xfer_producer_format_change_requested *)rawdata; + xfer_node_request_completed reply; + status_t rv; + reply.info.format = data->format; + rv = FormatChangeRequested(data->source, data->destination, &reply.info.format, NULL); + if (data->destination == media_destination::null) + return B_OK; + reply.info.what = media_request_info::B_REQUEST_FORMAT_CHANGE; + reply.info.change_tag = data->change_tag; + reply.info.status = rv; + //reply.info.cookie + reply.info.user_data = data->user_data; + reply.info.source = data->source; + reply.info.destination = data->destination; + write_port(data->destination.port, NODE_REQUEST_COMPLETED, &reply, sizeof(reply)); + return B_OK; + } + + + case PRODUCER_VIDEO_CLIPPING_CHANGED: + { + const xfer_producer_video_clipping_changed *data = (const xfer_producer_video_clipping_changed *)rawdata; + xfer_node_request_completed reply; + status_t rv; + rv = VideoClippingChanged(data->source, data->short_count, (int16 *)data->shorts, data->display, NULL); + if (data->destination == media_destination::null) + return B_OK; + reply.info.what = media_request_info::B_SET_VIDEO_CLIPPING_FOR; + reply.info.change_tag = data->change_tag; + reply.info.status = rv; + //reply.info.cookie + reply.info.user_data = data->user_data; + reply.info.source = data->source; + reply.info.destination = data->destination; + reply.info.format.type = B_MEDIA_RAW_VIDEO; + reply.info.format.u.raw_video.display = data->display; + write_port(data->destination.port, NODE_REQUEST_COMPLETED, &reply, sizeof(reply)); + return B_OK; + } + + case PRODUCER_ADDITIONAL_BUFFER_REQUESTED: + { + const xfer_producer_additional_buffer_requested *data = (const xfer_producer_additional_buffer_requested *)rawdata; + AdditionalBufferRequested(data->source, data->prev_buffer, data->prev_time, data->has_seek_tag ? &data->prev_tag : NULL); + return B_OK; + } + + case PRODUCER_LATENCY_CHANGED: + { + const xfer_producer_latency_changed *data = (const xfer_producer_latency_changed *)rawdata; + LatencyChanged(data->source, data->destination, data->latency, data->flags); + return B_OK; + } + + case PRODUCER_LATE_NOTICE_RECEIVED: + { + const xfer_producer_late_notice_received *data = (const xfer_producer_late_notice_received *)rawdata; + LateNoticeReceived(data->source, data->how_much, data->performance_time); + return B_OK; + } + + case PRODUCER_ENABLE_OUTPUT: + { + const xfer_producer_enable_output *data = (const xfer_producer_enable_output *)rawdata; + xfer_node_request_completed reply; + EnableOutput(data->source, data->enabled, NULL); + if (data->destination == media_destination::null) + return B_OK; + reply.info.what = media_request_info::B_SET_OUTPUT_ENABLED; + reply.info.change_tag = data->change_tag; + reply.info.status = B_OK; + //reply.info.cookie + reply.info.user_data = data->user_data; + reply.info.source = data->source; + reply.info.destination = data->destination; + //reply.info.format + write_port(data->destination.port, NODE_REQUEST_COMPLETED, &reply, sizeof(reply)); + return B_OK; + } + + }; + return B_ERROR; +} + + +void +BBufferProducer::AdditionalBufferRequested(const media_source &source, + media_buffer_id prev_buffer, + bigtime_t prev_time, + const media_seek_tag *prev_tag) +{ + CALLED(); + // may be implemented by derived classes +} + + +void +BBufferProducer::LatencyChanged(const media_source &source, + const media_destination &destination, + bigtime_t new_latency, + uint32 flags) +{ + CALLED(); + // may be implemented by derived classes +} + + +status_t +BBufferProducer::SendBuffer(BBuffer *buffer, + const media_destination &destination) +{ + CALLED(); + if (destination == media_destination::null) + return B_MEDIA_BAD_DESTINATION; + if (buffer == NULL) + return B_BAD_VALUE; + + xfer_consumer_buffer_received data; + data.buffer = buffer->ID(); + data.header = *(buffer->Header()); + data.header.buffer = data.buffer; + data.header.destination = destination.id; + + return write_port(destination.port, CONSUMER_BUFFER_RECEIVED, &data, sizeof(data)); +} + + +status_t +BBufferProducer::SendDataStatus(int32 status, + const media_destination &destination, + bigtime_t at_time) +{ + CALLED(); + if (destination == media_destination::null) + return B_MEDIA_BAD_DESTINATION; + + xfer_consumer_producer_data_status data; + data.for_whom = destination; + data.status = status; + data.at_performance_time = at_time; + + return write_port(destination.port, CONSUMER_PRODUCER_DATA_STATUS, &data, sizeof(data)); +} + + +status_t +BBufferProducer::ProposeFormatChange(media_format *format, + const media_destination &for_destination) +{ + CALLED(); + if (for_destination == media_destination::null) + return B_MEDIA_BAD_DESTINATION; + + status_t rv; + int32 code; + xfer_consumer_accept_format data; + xfer_consumer_accept_format_reply reply; + + data.dest = for_destination; + data.format = *format; + data.reply_port = _PortPool->GetPort(); + + rv = write_port(for_destination.port, CONSUMER_ACCEPT_FORMAT, &data, sizeof(data)); + if (rv != B_OK) { + _PortPool->PutPort(data.reply_port); + return rv; + } + + rv = read_port(data.reply_port, &code, &reply, sizeof(reply)); + _PortPool->PutPort(data.reply_port); + if (rv < B_OK) + return rv; + + *format = reply.format; + + return reply.result; +} + + +status_t +BBufferProducer::ChangeFormat(const media_source &for_source, + const media_destination &for_destination, + media_format *format) +{ + CALLED(); + if (for_source == media_source::null) + return B_MEDIA_BAD_SOURCE; + if (for_destination == media_destination::null) + return B_MEDIA_BAD_DESTINATION; + + status_t rv; + int32 code; + xfer_consumer_format_changed data; + xfer_consumer_format_changed_reply reply; + + data.producer = for_source; + data.consumer = for_destination; + data.format = *format; + data.reply_port = _PortPool->GetPort(); + + rv = write_port(for_destination.port, CONSUMER_FORMAT_CHANGED, &data, sizeof(data)); + if (rv != B_OK) { + _PortPool->PutPort(data.reply_port); + return rv; + } + + rv = read_port(data.reply_port, &code, &reply, sizeof(reply)); + _PortPool->PutPort(data.reply_port); + if (rv < B_OK) + return rv; + + return reply.result; +} + + +status_t +BBufferProducer::FindLatencyFor(const media_destination &for_destination, + bigtime_t *out_latency, + media_node_id *out_timesource) +{ + CALLED(); + if (for_destination == media_destination::null) + return B_MEDIA_BAD_DESTINATION; + + status_t rv; + int32 code; + xfer_consumer_get_latency_for data; + xfer_consumer_get_latency_for_reply reply; + + data.for_whom = for_destination; + data.reply_port = _PortPool->GetPort(); + + rv = write_port(for_destination.port, CONSUMER_GET_LATENCY_FOR, &data, sizeof(data)); + if (rv != B_OK) { + _PortPool->PutPort(data.reply_port); + return rv; + } + + rv = read_port(data.reply_port, &code, &reply, sizeof(reply)); + _PortPool->PutPort(data.reply_port); + if (rv < B_OK) + return rv; + + *out_latency = reply.latency; + *out_timesource = reply.timesource; + + return reply.result; +} + + +status_t +BBufferProducer::FindSeekTag(const media_destination &for_destination, + bigtime_t in_target_time, + media_seek_tag *out_tag, + bigtime_t *out_tagged_time, + uint32 *out_flags, + uint32 in_flags) +{ + CALLED(); + if (for_destination == media_destination::null) + return B_MEDIA_BAD_DESTINATION; + + status_t rv; + int32 code; + xfer_consumer_seek_tag_requested data; + xfer_consumer_seek_tag_requested_reply reply; + + data.destination = for_destination; + data.target_time = in_target_time; + data.flags = in_flags; + data.reply_port = _PortPool->GetPort(); + + rv = write_port(for_destination.port, CONSUMER_SEEK_TAG_REQUESTED, &data, sizeof(data)); + if (rv != B_OK) { + _PortPool->PutPort(data.reply_port); + return rv; + } + + rv = read_port(data.reply_port, &code, &reply, sizeof(reply)); + _PortPool->PutPort(data.reply_port); + if (rv < B_OK) + return rv; + + *out_tag = reply.seek_tag; + *out_tagged_time = reply.tagged_time; + *out_flags = reply.flags; + + return reply.result; +} + + +void +BBufferProducer::SetInitialLatency(bigtime_t inInitialLatency, + uint32 flags) +{ + fInitialLatency = inInitialLatency; + fInitialFlags = flags; +} + +/************************************************************* + * private BBufferProducer + *************************************************************/ + +/* +private unimplemented +BBufferProducer::BBufferProducer() +BBufferProducer::BBufferProducer(const BBufferProducer &clone) +BBufferProducer & BBufferProducer::operator=(const BBufferProducer &clone) +*/ + +status_t BBufferProducer::_Reserved_BufferProducer_0(void *) { return B_ERROR; } +status_t BBufferProducer::_Reserved_BufferProducer_1(void *) { return B_ERROR; } +status_t BBufferProducer::_Reserved_BufferProducer_2(void *) { return B_ERROR; } +status_t BBufferProducer::_Reserved_BufferProducer_3(void *) { return B_ERROR; } +status_t BBufferProducer::_Reserved_BufferProducer_4(void *) { return B_ERROR; } +status_t BBufferProducer::_Reserved_BufferProducer_5(void *) { return B_ERROR; } +status_t BBufferProducer::_Reserved_BufferProducer_6(void *) { return B_ERROR; } +status_t BBufferProducer::_Reserved_BufferProducer_7(void *) { return B_ERROR; } +status_t BBufferProducer::_Reserved_BufferProducer_8(void *) { return B_ERROR; } +status_t BBufferProducer::_Reserved_BufferProducer_9(void *) { return B_ERROR; } +status_t BBufferProducer::_Reserved_BufferProducer_10(void *) { return B_ERROR; } +status_t BBufferProducer::_Reserved_BufferProducer_11(void *) { return B_ERROR; } +status_t BBufferProducer::_Reserved_BufferProducer_12(void *) { return B_ERROR; } +status_t BBufferProducer::_Reserved_BufferProducer_13(void *) { return B_ERROR; } +status_t BBufferProducer::_Reserved_BufferProducer_14(void *) { return B_ERROR; } +status_t BBufferProducer::_Reserved_BufferProducer_15(void *) { return B_ERROR; } + + +status_t +BBufferProducer::clip_shorts_to_region(const int16 *data, + int count, + BRegion *output) +{ + UNIMPLEMENTED(); + + return B_ERROR; +} + + +status_t +BBufferProducer::clip_region_to_shorts(const BRegion *input, + int16 *data, + int max_count, + int *out_count) +{ + UNIMPLEMENTED(); + + return B_ERROR; +} + diff --git a/src/kits/media/ChannelMixer.cpp b/src/kits/media/ChannelMixer.cpp new file mode 100644 index 0000000000..ca381cc311 --- /dev/null +++ b/src/kits/media/ChannelMixer.cpp @@ -0,0 +1,160 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: ChannelMixer.cpp + * DESCR: Converts mono into stereo, stereo into mono + * (multiple channel support should be added in the future) + ***********************************************************************/ + +#include +#include +#include + +#include "ChannelMixer.h" + +namespace MediaKitPrivate { + +status_t +ChannelMixer::mix(void *dest, int dest_chan_count, + const void *source, int source_chan_count, + int framecount, uint32 format) +{ + if (dest_chan_count == 1 && source_chan_count == 2) + return mix_2_to_1(dest, source, framecount, format); + else if (dest_chan_count == 2 && source_chan_count == 1) + return mix_1_to_2(dest, source, framecount, format); + else { + fprintf(stderr,"ChannelMixer::mix() dest_chan_count = %d, source_chan_count = %d not supported\n", + dest_chan_count, + source_chan_count); + return B_ERROR; + } +} + +status_t +ChannelMixer::mix_2_to_1(void *dest, const void *source, int framecount, uint32 format) +{ + switch (format) { + case media_raw_audio_format::B_AUDIO_FLOAT: + { + register float *d = (float *)dest; + register float *s = (float *)source; + while (framecount--) { + *(d++) = (s[0] + s[1]) / 2.0f; + s += 2; + } + return B_OK; + } + case media_raw_audio_format::B_AUDIO_INT: + { + register int32 *d = (int32 *)dest; + register int32 *s = (int32 *)source; + while (framecount--) { + *(d++) = (s[0] >> 1) + (s[1] >> 1); + s += 2; + } + return B_OK; + } + case media_raw_audio_format::B_AUDIO_SHORT: + { + register int16 *d = (int16 *)dest; + register int16 *s = (int16 *)source; + while (framecount--) { + register int32 temp = s[0] + s[1]; + *(d++) = int16(temp >> 1); + s += 2; + } + return B_OK; + } + case media_raw_audio_format::B_AUDIO_CHAR: + { + register int8 *d = (int8 *)dest; + register int8 *s = (int8 *)source; + while (framecount--) { + register int32 temp = s[0] + s[1]; + *(d++) = int8(temp >> 1); + s += 2; + } + return B_OK; + } + case media_raw_audio_format::B_AUDIO_UCHAR: + { + register uint8 *d = (uint8 *)dest; + register uint8 *s = (uint8 *)source; + while (framecount--) { + register int32 temp = (int32(s[0]) - 128) + (int32(s[1]) - 128); + *(d++) = int8((temp >> 1) + 128); + s += 2; + } + return B_OK; + } + default: + { + fprintf(stderr,"ChannelMixer::mix_2_to_1() unsupported sample format %d\n",(int)format); + return B_ERROR; + } + } +} + +status_t +ChannelMixer::mix_1_to_2(void *dest, const void *source, int framecount, uint32 format) +{ + switch (format) { + case media_raw_audio_format::B_AUDIO_FLOAT: + { + register float *d = (float *)dest; + register float *s = (float *)source; + while (framecount--) { + *(d++) = *s; + *(d++) = *(s++); + } + return B_OK; + } + case media_raw_audio_format::B_AUDIO_INT: + { + register int32 *d = (int32 *)dest; + register int32 *s = (int32 *)source; + while (framecount--) { + *(d++) = *s; + *(d++) = *(s++); + } + return B_OK; + } + case media_raw_audio_format::B_AUDIO_SHORT: + { + register int16 *d = (int16 *)dest; + register int16 *s = (int16 *)source; + while (framecount--) { + *(d++) = *s; + *(d++) = *(s++); + } + return B_OK; + } + case media_raw_audio_format::B_AUDIO_CHAR: + { + register int8 *d = (int8 *)dest; + register int8 *s = (int8 *)source; + while (framecount--) { + *(d++) = *s; + *(d++) = *(s++); + } + return B_OK; + } + case media_raw_audio_format::B_AUDIO_UCHAR: + { + register uint8 *d = (uint8 *)dest; + register uint8 *s = (uint8 *)source; + while (framecount--) { + *(d++) = *s; + *(d++) = *(s++); + } + return B_OK; + } + default: + { + fprintf(stderr,"ChannelMixer::mix_1_to_2() unsupported sample format %d\n",(int)format); + return B_ERROR; + } + } +} + +} //namespace MediaKitPrivate diff --git a/src/kits/media/Controllable.cpp b/src/kits/media/Controllable.cpp new file mode 100644 index 0000000000..07676f0952 --- /dev/null +++ b/src/kits/media/Controllable.cpp @@ -0,0 +1,164 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: Controllable.cpp + * DESCR: + ***********************************************************************/ +#include +#include "debug.h" + +/************************************************************* + * protected BControllable + *************************************************************/ + +BControllable::~BControllable() +{ + UNIMPLEMENTED(); +} + +/************************************************************* + * public BControllable + *************************************************************/ + +BParameterWeb * +BControllable::Web() +{ + UNIMPLEMENTED(); + return NULL; +} + + +bool +BControllable::LockParameterWeb() +{ + UNIMPLEMENTED(); + bool dummy; + + return dummy; +} + +/************************************************************* + * protected BControllable + *************************************************************/ + +void +BControllable::UnlockParameterWeb() +{ + UNIMPLEMENTED(); +} + + +BControllable::BControllable() + : BMediaNode("XXX fixme") +{ + UNIMPLEMENTED(); + + AddNodeKind(B_CONTROLLABLE); +} + + +status_t +BControllable::SetParameterWeb(BParameterWeb *web) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BControllable::HandleMessage(int32 message, + const void *data, + size_t size) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BControllable::BroadcastChangedParameter(int32 id) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BControllable::BroadcastNewParameterValue(bigtime_t when, + int32 id, + void *newValue, + size_t valueSize) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BControllable::StartControlPanel(BMessenger *out_messenger) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BControllable::ApplyParameterData(const void *value, + size_t size) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BControllable::MakeParameterData(const int32 *controls, + int32 count, + void *buf, + size_t *ioSize) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + +/************************************************************* + * private BControllable + *************************************************************/ + +/* +private unimplemented +BControllable::BControllable(const BControllable &clone) +BControllable & BControllable::operator=(const BControllable &clone) +*/ + +status_t BControllable::_Reserved_Controllable_0(void *) { return B_ERROR; } +status_t BControllable::_Reserved_Controllable_1(void *) { return B_ERROR; } +status_t BControllable::_Reserved_Controllable_2(void *) { return B_ERROR; } +status_t BControllable::_Reserved_Controllable_3(void *) { return B_ERROR; } +status_t BControllable::_Reserved_Controllable_4(void *) { return B_ERROR; } +status_t BControllable::_Reserved_Controllable_5(void *) { return B_ERROR; } +status_t BControllable::_Reserved_Controllable_6(void *) { return B_ERROR; } +status_t BControllable::_Reserved_Controllable_7(void *) { return B_ERROR; } +status_t BControllable::_Reserved_Controllable_8(void *) { return B_ERROR; } +status_t BControllable::_Reserved_Controllable_9(void *) { return B_ERROR; } +status_t BControllable::_Reserved_Controllable_10(void *) { return B_ERROR; } +status_t BControllable::_Reserved_Controllable_11(void *) { return B_ERROR; } +status_t BControllable::_Reserved_Controllable_12(void *) { return B_ERROR; } +status_t BControllable::_Reserved_Controllable_13(void *) { return B_ERROR; } +status_t BControllable::_Reserved_Controllable_14(void *) { return B_ERROR; } +status_t BControllable::_Reserved_Controllable_15(void *) { return B_ERROR; } + + diff --git a/src/kits/media/DormantNodeManager.cpp b/src/kits/media/DormantNodeManager.cpp new file mode 100644 index 0000000000..03d189d8fd --- /dev/null +++ b/src/kits/media/DormantNodeManager.cpp @@ -0,0 +1,5 @@ + +#include "DormantNodeManager.h" + +static DormantNodeManager manager; +DormantNodeManager *_DormantNodeManager = &manager; \ No newline at end of file diff --git a/src/kits/media/DormantNodeManager.h b/src/kits/media/DormantNodeManager.h new file mode 100644 index 0000000000..61f7f09a3c --- /dev/null +++ b/src/kits/media/DormantNodeManager.h @@ -0,0 +1,8 @@ + +class DormantNodeManager + InstantiateDormantNode(const dormant_node_info & in_info, bool global, + media_node * out_node) + + + +extern DormantNodeManager *_DormantNodeManager; \ No newline at end of file diff --git a/src/kits/media/FileInterface.cpp b/src/kits/media/FileInterface.cpp new file mode 100644 index 0000000000..606ac4b814 --- /dev/null +++ b/src/kits/media/FileInterface.cpp @@ -0,0 +1,73 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: FileInterface.cpp + * DESCR: + ***********************************************************************/ +#include +#include "debug.h" + +/************************************************************* + * protected BFileInterface + *************************************************************/ + +BFileInterface::~BFileInterface() +{ + UNIMPLEMENTED(); +} + +/************************************************************* + * public BFileInterface + *************************************************************/ + +/* nothing */ + +/************************************************************* + * protected BFileInterface + *************************************************************/ + +BFileInterface::BFileInterface() + : BMediaNode("XXX fixme") +{ + UNIMPLEMENTED(); + + AddNodeKind(B_FILE_INTERFACE); +} + + +status_t +BFileInterface::HandleMessage(int32 message, + const void *data, + size_t size) +{ + UNIMPLEMENTED(); + + return B_OK; +} + +/************************************************************* + * private BFileInterface + *************************************************************/ + +/* +private unimplemented +BFileInterface::BFileInterface(const BFileInterface &clone) +FileInterface & BFileInterface::operator=(const BFileInterface &clone) +*/ + +status_t BFileInterface::_Reserved_FileInterface_0(void *) { return B_ERROR; } +status_t BFileInterface::_Reserved_FileInterface_1(void *) { return B_ERROR; } +status_t BFileInterface::_Reserved_FileInterface_2(void *) { return B_ERROR; } +status_t BFileInterface::_Reserved_FileInterface_3(void *) { return B_ERROR; } +status_t BFileInterface::_Reserved_FileInterface_4(void *) { return B_ERROR; } +status_t BFileInterface::_Reserved_FileInterface_5(void *) { return B_ERROR; } +status_t BFileInterface::_Reserved_FileInterface_6(void *) { return B_ERROR; } +status_t BFileInterface::_Reserved_FileInterface_7(void *) { return B_ERROR; } +status_t BFileInterface::_Reserved_FileInterface_8(void *) { return B_ERROR; } +status_t BFileInterface::_Reserved_FileInterface_9(void *) { return B_ERROR; } +status_t BFileInterface::_Reserved_FileInterface_10(void *) { return B_ERROR; } +status_t BFileInterface::_Reserved_FileInterface_11(void *) { return B_ERROR; } +status_t BFileInterface::_Reserved_FileInterface_12(void *) { return B_ERROR; } +status_t BFileInterface::_Reserved_FileInterface_13(void *) { return B_ERROR; } +status_t BFileInterface::_Reserved_FileInterface_14(void *) { return B_ERROR; } +status_t BFileInterface::_Reserved_FileInterface_15(void *) { return B_ERROR; } + diff --git a/src/kits/media/MediaAddOn.cpp b/src/kits/media/MediaAddOn.cpp new file mode 100644 index 0000000000..7995187790 --- /dev/null +++ b/src/kits/media/MediaAddOn.cpp @@ -0,0 +1,619 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: MediaAddOn.cpp + * DESCR: + ***********************************************************************/ +#include +#include +#include +#include "debug.h" +#include "PortPool.h" +#include "../server/headers/ServerInterface.h" + +/* + * some little helper function + */ + +static inline char *newstrdup(const char *str); +char *newstrdup(const char *str) +{ + if (str == NULL) + return NULL; + int len = strlen(str) + 1; + char *p = new char[len]; + memcpy(p,str,len); + return p; +} + +#define FLATTEN_MAGIC 'CODE' +#define FLATTEN_TYPECODE 'DFIT' + +/************************************************************* + * public dormant_node_info + *************************************************************/ + +// final & verified +dormant_node_info::dormant_node_info() + : addon(-1), + flavor_id(-1) +{ + CALLED(); + name[0] = '\0'; +} + +// final +dormant_node_info::~dormant_node_info() +{ + CALLED(); +} + +/************************************************************* + * private flavor_info + *************************************************************/ + +/* DO NOT IMPLEMENT */ +/* +flavor_info &flavor_info::operator=(const flavor_info &other) +*/ + +/************************************************************* + * public dormant_flavor_info + *************************************************************/ + +// final & verified +dormant_flavor_info::dormant_flavor_info() +{ + CALLED(); + name = 0; + info = 0; + kinds = 0; + flavor_flags = 0; + internal_id = 0; + possible_count = 0; + in_format_count = 0; + in_format_flags = 0; + in_formats = 0; + out_format_count = 0; + out_format_flags = 0; + out_formats = 0; +} + + +/* virtual */ +dormant_flavor_info::~dormant_flavor_info() +{ + CALLED(); + delete [] name; + delete [] info; + delete [] in_formats; + delete [] out_formats; +} + + +dormant_flavor_info::dormant_flavor_info(const dormant_flavor_info &clone) +{ + *this = clone; +} + + +dormant_flavor_info & +dormant_flavor_info::operator=(const dormant_flavor_info &clone) +{ + CALLED(); + //*this = static_cast(clone); + *this = (const flavor_info)clone; + node_info = clone.node_info; + return *this; +} + + +dormant_flavor_info & +dormant_flavor_info::operator=(const flavor_info &clone) +{ + CALLED(); + delete [] name; + delete [] info; + delete [] in_formats; + delete [] out_formats; + + name = newstrdup(clone.name); + info = newstrdup(clone.info); + + kinds = clone.kinds; + flavor_flags = clone.flavor_flags; + internal_id = clone.internal_id; + possible_count = clone.possible_count; + + in_format_count = clone.in_format_count; + in_format_flags = clone.in_format_flags; + out_format_count = clone.out_format_count; + out_format_flags = clone.out_format_flags; + + if (in_format_count > 0) { + media_format *temp; + temp = new media_format[in_format_count]; + for (int i = 0; i < in_format_count; i++) + temp[i] = clone.in_formats[i]; + in_formats = temp; + } else { + in_formats = 0; + } + + if (out_format_count > 0) { + media_format *temp; + temp = new media_format[out_format_count]; + for (int i = 0; i < out_format_count; i++) + temp[i] = clone.out_formats[i]; + out_formats = temp; + } else { + out_formats = 0; + } + + dormant_node_info temp; + node_info = temp; + + return *this; +} + + +void +dormant_flavor_info::set_name(const char *in_name) +{ + CALLED(); + delete [] name; + name = newstrdup(in_name); +} + + +void +dormant_flavor_info::set_info(const char *in_info) +{ + CALLED(); + delete [] info; + info = newstrdup(in_info); +} + + +void +dormant_flavor_info::add_in_format(const media_format &in_format) +{ + CALLED(); + media_format *temp; + temp = new media_format[in_format_count + 1]; + for (int i = 0; i < in_format_count; i++) + temp[i] = in_formats[i]; + temp[in_format_count] = in_format; + delete [] in_formats; + in_format_count += 1; + in_formats = temp; +} + + +void +dormant_flavor_info::add_out_format(const media_format &out_format) +{ + CALLED(); + media_format *temp; + temp = new media_format[out_format_count + 1]; + for (int i = 0; i < out_format_count; i++) + temp[i] = out_formats[i]; + temp[out_format_count] = out_format; + delete [] out_formats; + out_format_count += 1; + out_formats = temp; +} + + +/* virtual */ bool +dormant_flavor_info::IsFixedSize() const +{ + CALLED(); + return false; +} + + +/* virtual */ type_code +dormant_flavor_info::TypeCode() const +{ + CALLED(); + return FLATTEN_TYPECODE; +} + + +/* virtual */ ssize_t +dormant_flavor_info::FlattenedSize() const +{ + ssize_t size = 0; + // magic + size += sizeof(int32); + // size + size += sizeof(int32); + // struct flavor_info + size += sizeof(int32) + strlen(name); + size += sizeof(int32) + strlen(info); + size += sizeof(kinds); + size += sizeof(flavor_flags); + size += sizeof(internal_id); + size += sizeof(possible_count); + size += sizeof(in_format_count); + size += sizeof(in_format_flags); + size += in_format_count * sizeof(media_format); + size += sizeof(out_format_count); + size += sizeof(out_format_flags); + size += out_format_count * sizeof(media_format); + // struct dormant_node_info node_info + size += sizeof(node_info); + + return size; +} + + +/* virtual */ status_t +dormant_flavor_info::Flatten(void *buffer, + ssize_t size) const +{ + CALLED(); + if (size < FlattenedSize()) + return B_ERROR; + + char *buf = (char *)buffer; + int32 namelen = name ? (int32)strlen(name) : -1; + int32 infolen = info ? (int32)strlen(info) : -1; + + // magic + *(int32*)buf = FLATTEN_MAGIC; buf += sizeof(int32); + + // size + *(int32*)buf = FlattenedSize(); buf += sizeof(int32); + + // struct flavor_info + *(int32*)buf = namelen; buf += sizeof(int32); + if (namelen > 0) { + memcpy(buf,name,namelen); + buf += namelen; + } + *(int32*)buf = infolen; buf += sizeof(int32); + if (infolen > 0) { + memcpy(buf,info,infolen); + buf += infolen; + } + + *(uint64*)buf = kinds; buf += sizeof(uint64); + *(uint32*)buf = flavor_flags; buf += sizeof(uint32); + *(int32*)buf = internal_id; buf += sizeof(int32); + *(int32*)buf = possible_count; buf += sizeof(int32); + *(int32*)buf = in_format_count; buf += sizeof(int32); + *(uint32*)buf = in_format_flags; buf += sizeof(uint32); + + // XXX FIXME! we should not!!! make flat copies of media_format + memcpy(buf,in_formats,in_format_count * sizeof(media_format)); buf += in_format_count * sizeof(media_format); + + *(int32*)buf = out_format_count; buf += sizeof(int32); + *(uint32*)buf = out_format_flags; buf += sizeof(uint32); + + // XXX FIXME! we should not!!! make flat copies of media_format + memcpy(buf,out_formats,out_format_count * sizeof(media_format)); buf += out_format_count * sizeof(media_format); + + *(dormant_node_info*)buf = node_info; buf += sizeof(dormant_node_info); + + return B_OK; +} + + +/* virtual */ status_t +dormant_flavor_info::Unflatten(type_code c, + const void *buffer, + ssize_t size) +{ + CALLED(); + if (c != FLATTEN_TYPECODE) + return B_ERROR; + if (size < 8) + return B_ERROR; + + const char *buf = (const char *)buffer; + int32 namelen; + int32 infolen; + + // magic + if (*(int32*)buf != FLATTEN_MAGIC) + return B_ERROR; + buf += sizeof(int32); + + // size + if (*(int32*)buf > size) + return B_ERROR; + buf += sizeof(int32); + + + delete [] name; + delete [] info; + delete [] in_formats; + delete [] out_formats; + name = 0; + info = 0; + in_formats = 0; + out_formats = 0; + + + // struct flavor_info + namelen = *(int32*)buf; buf += sizeof(int32); + if (namelen >= 0) { // if namelen is -1, we leave name = 0 + name = new char [namelen + 1]; + memcpy(name,buf,namelen); + name[namelen] = 0; + buf += namelen; + } + + infolen = *(int32*)buf; buf += sizeof(int32); + if (infolen >= 0) { // if infolen is -1, we leave info = 0 + info = new char [infolen + 1]; + memcpy(info,buf,infolen); + info[infolen] = 0; + buf += infolen; + } + + kinds = *(uint64*)buf; buf += sizeof(uint64); + flavor_flags = *(uint32*)buf; buf += sizeof(uint32); + internal_id = *(int32*)buf; buf += sizeof(int32); + possible_count = *(int32*)buf; buf += sizeof(int32); + in_format_count = *(int32*)buf; buf += sizeof(int32); + in_format_flags = *(uint32*)buf; buf += sizeof(uint32); + + // XXX FIXME! we should not!!! make flat copies of media_format + if (in_format_count > 0) { + in_formats = new media_format[in_format_count]; + memcpy((media_format *)in_formats,buf,in_format_count * sizeof(media_format)); + buf += in_format_count * sizeof(media_format); + } + + out_format_count = *(int32*)buf; buf += sizeof(int32); + out_format_flags = *(uint32*)buf; buf += sizeof(uint32); + + // XXX FIXME! we should not!!! make flat copies of media_format + if (out_format_count > 0) { + out_formats = new media_format[out_format_count]; + memcpy((media_format *)out_formats,buf,out_format_count * sizeof(media_format)); + buf += out_format_count * sizeof(media_format); + } + + node_info = *(dormant_node_info*)buf; buf += sizeof(dormant_node_info); + + return B_OK; +} + +/************************************************************* + * public BMediaAddOn + *************************************************************/ + +/* explicit */ +BMediaAddOn::BMediaAddOn(image_id image) : + _fImage(image), + _fAddon(0) +{ + CALLED(); + xfer_server_register_mediaaddon msg; + xfer_server_register_mediaaddon_reply reply; + port_id port; + status_t rv; + int32 code; + port = find_port("media_server port"); + if (port <= B_OK) + return; + msg.reply_port = _PortPool->GetPort(); + rv = write_port(port, SERVER_REGISTER_MEDIAADDON, &msg, sizeof(msg)); + if (rv != B_OK) { + _PortPool->PutPort(msg.reply_port); + return; + } + rv = read_port(msg.reply_port, &code, &reply, sizeof(reply)); + _PortPool->PutPort(msg.reply_port); + if (rv < B_OK) + return; + _fAddon = reply.addonid; +} + + +/* virtual */ +BMediaAddOn::~BMediaAddOn() +{ + CALLED(); + if (_fAddon != 0) { + xfer_server_unregister_mediaaddon msg; + port_id port; + port = find_port("media_server port"); + if (port <= B_OK) + return; + msg.addonid = _fAddon; + write_port(port, SERVER_UNREGISTER_MEDIAADDON, &msg, sizeof(msg)); + } +} + + +/* virtual */ status_t +BMediaAddOn::InitCheck(const char **out_failure_text) +{ + CALLED(); + // only to be implemented by derived classes + *out_failure_text = "no error"; + return B_OK; +} + + +/* virtual */ int32 +BMediaAddOn::CountFlavors() +{ + CALLED(); + // only to be implemented by derived classes + return 0; +} + + +/* virtual */ status_t +BMediaAddOn::GetFlavorAt(int32 n, + const flavor_info **out_info) +{ + CALLED(); + // only to be implemented by derived classes + return B_ERROR; +} + + +/* virtual */ BMediaNode * +BMediaAddOn::InstantiateNodeFor(const flavor_info *info, + BMessage *config, + status_t *out_error) +{ + CALLED(); + // only to be implemented by derived classes + return NULL; +} + + +/* virtual */ status_t +BMediaAddOn::GetConfigurationFor(BMediaNode *your_node, + BMessage *into_message) +{ + CALLED(); + // only to be implemented by derived classes + return B_ERROR; +} + + +/* virtual */ bool +BMediaAddOn::WantsAutoStart() +{ + CALLED(); + // only to be implemented by derived classes + return false; +} + + +/* virtual */ status_t +BMediaAddOn::AutoStart(int in_count, + BMediaNode **out_node, + int32 *out_internal_id, + bool *out_has_more) +{ + CALLED(); + // only to be implemented by derived classes + return B_ERROR; +} + + +/* virtual */ status_t +BMediaAddOn::SniffRef(const entry_ref &file, + BMimeType *io_mime_type, + float *out_quality, + int32 *out_internal_id) +{ + CALLED(); + // only to be implemented by BFileInterface derived classes + return B_ERROR; +} + + +/* virtual */ status_t +BMediaAddOn::SniffType(const BMimeType &type, + float *out_quality, + int32 *out_internal_id) +{ + CALLED(); + // only to be implemented by BFileInterface derived classes + return B_ERROR; +} + + +/* virtual */ status_t +BMediaAddOn::GetFileFormatList(int32 flavor_id, + media_file_format *out_writable_formats, + int32 in_write_items, + int32 *out_write_items, + media_file_format *out_readable_formats, + int32 in_read_items, + int32 *out_read_items, + void *_reserved) +{ + CALLED(); + // only to be implemented by BFileInterface derived classes + return B_ERROR; +} + + +/* virtual */ status_t +BMediaAddOn::SniffTypeKind(const BMimeType &type, + uint64 in_kinds, + float *out_quality, + int32 *out_internal_id, + void *_reserved) +{ + CALLED(); + // only to be implemented by BFileInterface derived classes + return B_ERROR; +} + + +image_id +BMediaAddOn::ImageID() +{ + return _fImage; +} + + +media_addon_id +BMediaAddOn::AddonID() +{ + return _fAddon; +} + +/************************************************************* + * protected BMediaAddOn + *************************************************************/ + +status_t +BMediaAddOn::NotifyFlavorChange() +{ + if (_fAddon == 0) + return B_ERROR; + + port_id port; + port = find_port("media_addon_server port"); + if (port <= B_OK) + return B_ERROR; + + xfer_addonserver_rescan_mediaaddon_flavors msg; + msg.addonid = _fAddon; + return write_port(port, ADDONSERVER_RESCAN_MEDIAADDON_FLAVORS, &msg, sizeof(msg)); +} + +/************************************************************* + * private BMediaAddOn + *************************************************************/ + +/* +unimplemented: +BMediaAddOn::BMediaAddOn() +BMediaAddOn::BMediaAddOn(const BMediaAddOn &clone) +BMediaAddOn & BMediaAddOn::operator=(const BMediaAddOn &clone) +*/ + + +/************************************************************* + * private BMediaAddOn + *************************************************************/ + +extern "C" { + // declared here to remove them from the class header file + status_t _Reserved_MediaAddOn_0__11BMediaAddOnPv(void *, void *); /* now used for BMediaAddOn::GetFileFormatList */ + status_t _Reserved_MediaAddOn_1__11BMediaAddOnPv(void *, void *); /* now used for BMediaAddOn::SniffTypeKind */ + status_t _Reserved_MediaAddOn_0__11BMediaAddOnPv(void *, void *) { return B_ERROR; } + status_t _Reserved_MediaAddOn_1__11BMediaAddOnPv(void *, void *) { return B_ERROR; } +}; + +status_t BMediaAddOn::_Reserved_MediaAddOn_2(void *) { return B_ERROR; } +status_t BMediaAddOn::_Reserved_MediaAddOn_3(void *) { return B_ERROR; } +status_t BMediaAddOn::_Reserved_MediaAddOn_4(void *) { return B_ERROR; } +status_t BMediaAddOn::_Reserved_MediaAddOn_5(void *) { return B_ERROR; } +status_t BMediaAddOn::_Reserved_MediaAddOn_6(void *) { return B_ERROR; } +status_t BMediaAddOn::_Reserved_MediaAddOn_7(void *) { return B_ERROR; } + diff --git a/src/kits/media/MediaDecoder.cpp b/src/kits/media/MediaDecoder.cpp new file mode 100644 index 0000000000..6ea344e97e --- /dev/null +++ b/src/kits/media/MediaDecoder.cpp @@ -0,0 +1,189 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: MediaDecoder.cpp + * DESCR: + ***********************************************************************/ +#include +#include "debug.h" + +/************************************************************* + * public BMediaDecoder + *************************************************************/ + +BMediaDecoder::BMediaDecoder() +{ + UNIMPLEMENTED(); +} + +BMediaDecoder::BMediaDecoder(const media_format *in_format, + const void *info, + size_t info_size) +{ + UNIMPLEMENTED(); +} + +BMediaDecoder::BMediaDecoder(const media_codec_info *mci) +{ + UNIMPLEMENTED(); +} + +/* virtual */ +BMediaDecoder::~BMediaDecoder() +{ + UNIMPLEMENTED(); +} + + +status_t +BMediaDecoder::InitCheck() const +{ + UNIMPLEMENTED(); + + return B_OK; +} + + +status_t +BMediaDecoder::SetTo(const media_format *in_format, + const void *info, + size_t info_size) +{ + UNIMPLEMENTED(); + return B_OK; +} + +status_t +BMediaDecoder::SetTo(const media_codec_info *mci) +{ + UNIMPLEMENTED(); + return B_OK; +} + +status_t +BMediaDecoder::SetInputFormat(const media_format *in_format, + const void *in_info, + size_t in_size) +{ + UNIMPLEMENTED(); + return B_OK; +} + +status_t +BMediaDecoder::SetOutputFormat(media_format *output_format) +{ + UNIMPLEMENTED(); + return B_OK; +} + +// Set output format to closest acceptable format, returns the +// format used. +status_t +BMediaDecoder::Decode(void *out_buffer, + int64 *out_frameCount, + media_header *out_mh, + media_decode_info *info) +{ + UNIMPLEMENTED(); + return B_OK; +} + +status_t +BMediaDecoder::GetDecoderInfo(media_codec_info *out_info) const +{ + UNIMPLEMENTED(); + return B_OK; +} + + +/************************************************************* + * protected BMediaDecoder + *************************************************************/ + + +/************************************************************* + * private BMediaDecoder + *************************************************************/ + +/* +// unimplemented +BMediaDecoder::BMediaDecoder(const BMediaDecoder &); +BMediaDecoder::BMediaDecoder & operator=(const BMediaDecoder &); +*/ + +/* static */ status_t +BMediaDecoder::next_chunk(void *classptr, void **chunkData, size_t *chunkLen, media_header *mh) +{ + UNIMPLEMENTED(); + return B_OK; +} + +void +BMediaDecoder::ReleaseDecoder() +{ + UNIMPLEMENTED(); +} + + +status_t BMediaDecoder::_Reserved_BMediaDecoder_0(int32 arg, ...) { return B_ERROR; } +status_t BMediaDecoder::_Reserved_BMediaDecoder_1(int32 arg, ...) { return B_ERROR; } +status_t BMediaDecoder::_Reserved_BMediaDecoder_2(int32 arg, ...) { return B_ERROR; } +status_t BMediaDecoder::_Reserved_BMediaDecoder_3(int32 arg, ...) { return B_ERROR; } +status_t BMediaDecoder::_Reserved_BMediaDecoder_4(int32 arg, ...) { return B_ERROR; } +status_t BMediaDecoder::_Reserved_BMediaDecoder_5(int32 arg, ...) { return B_ERROR; } +status_t BMediaDecoder::_Reserved_BMediaDecoder_6(int32 arg, ...) { return B_ERROR; } +status_t BMediaDecoder::_Reserved_BMediaDecoder_7(int32 arg, ...) { return B_ERROR; } +status_t BMediaDecoder::_Reserved_BMediaDecoder_8(int32 arg, ...) { return B_ERROR; } +status_t BMediaDecoder::_Reserved_BMediaDecoder_9(int32 arg, ...) { return B_ERROR; } +status_t BMediaDecoder::_Reserved_BMediaDecoder_10(int32 arg, ...) { return B_ERROR; } +status_t BMediaDecoder::_Reserved_BMediaDecoder_11(int32 arg, ...) { return B_ERROR; } +status_t BMediaDecoder::_Reserved_BMediaDecoder_12(int32 arg, ...) { return B_ERROR; } +status_t BMediaDecoder::_Reserved_BMediaDecoder_13(int32 arg, ...) { return B_ERROR; } +status_t BMediaDecoder::_Reserved_BMediaDecoder_14(int32 arg, ...) { return B_ERROR; } +status_t BMediaDecoder::_Reserved_BMediaDecoder_15(int32 arg, ...) { return B_ERROR; } + +/************************************************************* + * public BMediaBufferDecoder + *************************************************************/ + +BMediaBufferDecoder::BMediaBufferDecoder() +{ + UNIMPLEMENTED(); +} + +BMediaBufferDecoder::BMediaBufferDecoder(const media_format *in_format, + const void *info, + size_t info_size) +{ + UNIMPLEMENTED(); +} + +BMediaBufferDecoder::BMediaBufferDecoder(const media_codec_info *mci) +{ + UNIMPLEMENTED(); +} + +status_t +BMediaBufferDecoder::DecodeBuffer(const void *input_buffer, + size_t input_size, + void *out_buffer, + int64 *out_frameCount, + media_header *out_mh, + media_decode_info *info) +{ + UNIMPLEMENTED(); + return B_OK; +} + +/************************************************************* + * protected BMediaBufferDecoder + *************************************************************/ + +/* virtual */ +status_t BMediaBufferDecoder::GetNextChunk(const void **chunkData, + size_t *chunkLen, + media_header *mh) +{ + UNIMPLEMENTED(); + return B_OK; +} + diff --git a/src/kits/media/MediaDefs.cpp b/src/kits/media/MediaDefs.cpp new file mode 100644 index 0000000000..e7bbc22d3c --- /dev/null +++ b/src/kits/media/MediaDefs.cpp @@ -0,0 +1,484 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: MediaDefs.cpp + * DESCR: + ***********************************************************************/ +#include +#include +#include +#include "debug.h" + +/************************************************************* + * media_destination + *************************************************************/ + +// final +media_destination::media_destination(port_id port, + int32 id) + : port(port), + id(id) +{ + CALLED(); +} + +// final +media_destination::media_destination(const media_destination &clone) + : port(clone.port), + id(clone.id) +{ + CALLED(); +} + +// final +media_destination & +media_destination::operator=(const media_destination &clone) +{ + CALLED(); + port = clone.port; + id = clone.id; + return *this; +} + +// final & verfied +media_destination::media_destination() + : port(-1), + id(-1) +{ + CALLED(); +} + +// final +media_destination::~media_destination() +{ + CALLED(); +} + +// final & verfied +media_destination media_destination::null(-1,-1); + +/************************************************************* + * media_source + *************************************************************/ + +// final +media_source::media_source(port_id port, + int32 id) + : port(port), + id(id) +{ + CALLED(); +} + +// final +media_source::media_source(const media_source &clone) + : port(clone.port), + id(clone.id) +{ + CALLED(); +} + +// final +media_source & +media_source::operator=(const media_source &clone) +{ + CALLED(); + port = clone.port; + id = clone.id; + return *this; +} + +// final & verfied +media_source::media_source() + : port(-1), + id(-1) +{ + CALLED(); +} + +// final +media_source::~media_source() +{ + CALLED(); +} + +// final & verfied +media_source media_source::null(-1,-1); + +/************************************************************* + * + *************************************************************/ + +// final +bool operator==(const media_destination & a, const media_destination & b) +{ + CALLED(); + return (a.port == b.port) && (a.id == b.id); +} + +// final +bool operator!=(const media_destination & a, const media_destination & b) +{ + CALLED(); + return (a.port != b.port) || (a.id != b.id); +} + +bool operator<(const media_destination & a, const media_destination & b) +{ + UNIMPLEMENTED(); + return false; +} + +// final +bool operator==(const media_source & a, const media_source & b) +{ + CALLED(); + return (a.port == b.port) && (a.id == b.id); +} + +// final +bool operator!=(const media_source & a, const media_source & b) +{ + CALLED(); + return (a.port != b.port) || (a.id != b.id); +} + +bool operator<(const media_source & a, const media_source & b) +{ + UNIMPLEMENTED(); + return false; +} + +// final +bool operator==(const media_node & a, const media_node & b) +{ + CALLED(); + return (a.node == b.node) && (a.port == b.port) && (a.kind == b.kind); +} + +// final +bool operator!=(const media_node & a, const media_node & b) +{ + CALLED(); + return (a.node != b.node) || (a.port != b.port) || (a.kind != b.kind); +} + +bool operator<(const media_node & a, const media_node & b) +{ + UNIMPLEMENTED(); + return false; +} + + +/************************************************************* + * + *************************************************************/ + +media_multi_audio_format media_raw_audio_format::wildcard; + +media_multi_audio_format media_multi_audio_format::wildcard; + +media_encoded_audio_format media_encoded_audio_format::wildcard = {0}; + +media_video_display_info media_video_display_info::wildcard = {(color_space)0}; + +media_raw_video_format media_raw_video_format::wildcard = {0}; + +media_encoded_video_format media_encoded_video_format::wildcard = {0}; + +media_multistream_format media_multistream_format::wildcard = {0}; + +/************************************************************* + * media_format + *************************************************************/ + +bool +media_format::Matches(const media_format *otherFormat) const +{ + UNIMPLEMENTED(); + bool dummy; + + return dummy; +} + + +void +media_format::SpecializeTo(const media_format *otherFormat) +{ + UNIMPLEMENTED(); +} + + +status_t +media_format::SetMetaData(const void *data, + size_t size) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +const void * +media_format::MetaData() const +{ + UNIMPLEMENTED(); + return NULL; +} + + +int32 +media_format::MetaDataSize() const +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + +// final +media_format::media_format() +{ + CALLED(); + memset(this,0x00,sizeof(*this)); + //meta_data, meta_data_size, meta_data_area, use_area, + //team, and thisPtr are currently only used by decoders + //when communicating with the file reader; they're not + //currently for public use. + + //If any field is 0, it's treated as a wildcard +} + + +// final +media_format::media_format(const media_format &other) +{ + CALLED(); + *this = other; +} + +// final +media_format::~media_format() +{ + CALLED(); +} + + +// final +media_format & +media_format::operator=(const media_format &clone) +{ + CALLED(); + memset(this,0x00,sizeof(*this)); + + type = clone.type; + user_data_type = clone.user_data_type; + + memcpy(user_data,clone.user_data,sizeof(media_format::user_data)); + + require_flags = clone.require_flags; + deny_flags = clone.deny_flags; + + memcpy(u._reserved_,clone.u._reserved_,sizeof(media_format::u._reserved_)); + return *this; +} + +/************************************************************* + * + *************************************************************/ + + +bool operator==(const media_raw_audio_format & a, const media_raw_audio_format & b) +{ + UNIMPLEMENTED(); + return false; +} + +bool operator==(const media_multi_audio_info & a, const media_multi_audio_info & b) +{ + UNIMPLEMENTED(); + return false; +} + +bool operator==(const media_multi_audio_format & a, const media_multi_audio_format & b) +{ + UNIMPLEMENTED(); + return false; +} + +bool operator==(const media_encoded_audio_format & a, const media_encoded_audio_format & b) +{ + UNIMPLEMENTED(); + return false; +} + +bool operator==(const media_video_display_info & a, const media_video_display_info & b) +{ + UNIMPLEMENTED(); + return false; +} + +bool operator==(const media_raw_video_format & a, const media_raw_video_format & b) +{ + UNIMPLEMENTED(); + return false; +} + +bool operator==(const media_encoded_video_format & a, const media_encoded_video_format & b) +{ + UNIMPLEMENTED(); + return false; +} + +bool operator==(const media_multistream_format::vid_info & a, const media_multistream_format::vid_info & b) +{ + UNIMPLEMENTED(); + return false; +} + +bool operator==(const media_multistream_format::avi_info & a, const media_multistream_format::avi_info & b) +{ + UNIMPLEMENTED(); + return false; +} + +bool operator==(const media_multistream_format & a, const media_multistream_format & b) +{ + UNIMPLEMENTED(); + return false; +} + +bool operator==(const media_format & a, const media_format & b) +{ + UNIMPLEMENTED(); + return false; +} + +/************************************************************* + * + *************************************************************/ + +/* return true if a and b are compatible (accounting for wildcards) */ +bool format_is_compatible(const media_format & a, const media_format & b) /* a is the format you want to feed to something accepting b */ +{ + UNIMPLEMENTED(); + return false; +} + +bool string_for_format(const media_format & f, char * buf, size_t size) +{ + UNIMPLEMENTED(); + return false; +} + +/************************************************************* + * + *************************************************************/ + +bool operator==(const media_file_format_id & a, const media_file_format_id & b) +{ + UNIMPLEMENTED(); + return false; +} + +bool operator<(const media_file_format_id & a, const media_file_format_id & b) +{ + UNIMPLEMENTED(); + return false; +} + +/************************************************************* + * + *************************************************************/ + +// +// Use this function iterate through available file format writers +// +status_t get_next_file_format(int32 *cookie, media_file_format *mfi) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +/************************************************************* + * + *************************************************************/ + +// final & verified +const char * B_MEDIA_SERVER_SIGNATURE = "application/x-vnd.Be.media-server"; + +/************************************************************* + * + *************************************************************/ + +struct dormant_node_info +{ +}; + +struct buffer_clone_info +{ +}; + +/************************************************************* + * + *************************************************************/ + + +// If you for some reason need to get rid of the media_server (and friends) +// use these functions, rather than sending messages yourself. +// The callback will be called for various stages of the process, with 100 meaning completely done +// The callback should always return TRUE for the time being. +status_t shutdown_media_server(bigtime_t timeout = B_INFINITE_TIMEOUT, bool (*progress)(int stage, const char * message, void * cookie) = NULL, void * cookie = NULL) +{ + UNIMPLEMENTED(); + return B_OK; +} + +status_t launch_media_server(uint32 flags = 0) +{ + UNIMPLEMENTED(); + return B_OK; +} + +// Given an image_id, prepare that image_id for realtime media +// If the kind of media indicated by "flags" is not enabled for real-time, +// B_MEDIA_REALTIME_DISABLED is returned. +// If there are not enough system resources to enable real-time performance, +// B_MEDIA_REALTIME_UNAVAILABLE is returned. +status_t media_realtime_init_image(image_id image, uint32 flags) +{ + UNIMPLEMENTED(); + return B_OK; +} + +// Given a thread ID, and an optional indication of what the thread is +// doing in "flags", prepare the thread for real-time media performance. +// Currently, this means locking the thread stack, up to size_used bytes, +// or all of it if 0 is passed. Typically, you will not be using all +// 256 kB of the stack, so you should pass some smaller value you determine +// from profiling the thread; typically in the 32-64kB range. +// Return values are the same as for media_prepare_realtime_image(). +status_t media_realtime_init_thread(thread_id thread, size_t stack_used, uint32 flags) +{ + UNIMPLEMENTED(); + return B_OK; +} + +/************************************************************* + * media_encode_info + *************************************************************/ + + +media_encode_info::media_encode_info() +{ + UNIMPLEMENTED(); +} + + +media_decode_info::media_decode_info() +{ + UNIMPLEMENTED(); +} + + diff --git a/src/kits/media/MediaEncoder.cpp b/src/kits/media/MediaEncoder.cpp new file mode 100644 index 0000000000..7c1891a605 --- /dev/null +++ b/src/kits/media/MediaEncoder.cpp @@ -0,0 +1,211 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: MediaEncoder.cpp + * DESCR: + ***********************************************************************/ +#include +#include "debug.h" + + +/************************************************************* + * public BMediaEncoder + *************************************************************/ + +BMediaEncoder::BMediaEncoder() +{ + UNIMPLEMENTED(); +} + + +BMediaEncoder::BMediaEncoder(const media_format *output_format) +{ + UNIMPLEMENTED(); +} + + +BMediaEncoder::BMediaEncoder(const media_codec_info *mci) +{ + UNIMPLEMENTED(); +} + + +/* virtual */ +BMediaEncoder::~BMediaEncoder() +{ + UNIMPLEMENTED(); +} + + +status_t +BMediaEncoder::InitCheck() const +{ + UNIMPLEMENTED(); + + return B_OK; +} + +status_t +BMediaEncoder::SetTo(const media_format *output_format) +{ + UNIMPLEMENTED(); + return B_OK; +} + +status_t +BMediaEncoder::SetTo(const media_codec_info *mci) +{ + UNIMPLEMENTED(); + return B_OK; +} + + +status_t +BMediaEncoder::SetFormat(media_format *input_format, + media_format *output_format, + media_file_format *mfi) +{ + UNIMPLEMENTED(); + return B_OK; +} + +status_t +BMediaEncoder::Encode(const void *buffer, + int64 frame_count, + media_encode_info *info) +{ + UNIMPLEMENTED(); + return B_OK; +} + + +status_t +BMediaEncoder::GetEncodeParameters(encode_parameters *parameters) const +{ + UNIMPLEMENTED(); + return B_OK; +} + + +status_t +BMediaEncoder::SetEncodeParameters(encode_parameters *parameters) +{ + UNIMPLEMENTED(); + return B_OK; +} + + +/************************************************************* + * protected BMediaEncoder + *************************************************************/ + +/* virtual */ status_t +BMediaEncoder::AddTrackInfo(uint32 code, const char *data, size_t size) +{ + UNIMPLEMENTED(); + return B_OK; +} + + +/************************************************************* + * private BMediaEncoder + *************************************************************/ + +/* +// unimplemented +BMediaEncoder::BMediaEncoder(const BMediaEncoder &); +BMediaEncoder::BMediaEncoder & operator=(const BMediaEncoder &); +*/ + +/* static */ status_t +BMediaEncoder::write_chunk(void *classptr, + const void *chunk_data, + size_t chunk_len, + media_encode_info *info) +{ + UNIMPLEMENTED(); + return B_OK; +} + + +void +BMediaEncoder::Init() +{ + UNIMPLEMENTED(); +} + + +void +BMediaEncoder::ReleaseEncoder() +{ + UNIMPLEMENTED(); +} + +status_t BMediaEncoder::_Reserved_BMediaEncoder_0(int32 arg, ...) { return B_ERROR; } +status_t BMediaEncoder::_Reserved_BMediaEncoder_1(int32 arg, ...) { return B_ERROR; } +status_t BMediaEncoder::_Reserved_BMediaEncoder_2(int32 arg, ...) { return B_ERROR; } +status_t BMediaEncoder::_Reserved_BMediaEncoder_3(int32 arg, ...) { return B_ERROR; } +status_t BMediaEncoder::_Reserved_BMediaEncoder_4(int32 arg, ...) { return B_ERROR; } +status_t BMediaEncoder::_Reserved_BMediaEncoder_5(int32 arg, ...) { return B_ERROR; } +status_t BMediaEncoder::_Reserved_BMediaEncoder_6(int32 arg, ...) { return B_ERROR; } +status_t BMediaEncoder::_Reserved_BMediaEncoder_7(int32 arg, ...) { return B_ERROR; } +status_t BMediaEncoder::_Reserved_BMediaEncoder_8(int32 arg, ...) { return B_ERROR; } +status_t BMediaEncoder::_Reserved_BMediaEncoder_9(int32 arg, ...) { return B_ERROR; } +status_t BMediaEncoder::_Reserved_BMediaEncoder_10(int32 arg, ...) { return B_ERROR; } +status_t BMediaEncoder::_Reserved_BMediaEncoder_11(int32 arg, ...) { return B_ERROR; } +status_t BMediaEncoder::_Reserved_BMediaEncoder_12(int32 arg, ...) { return B_ERROR; } +status_t BMediaEncoder::_Reserved_BMediaEncoder_13(int32 arg, ...) { return B_ERROR; } +status_t BMediaEncoder::_Reserved_BMediaEncoder_14(int32 arg, ...) { return B_ERROR; } +status_t BMediaEncoder::_Reserved_BMediaEncoder_15(int32 arg, ...) { return B_ERROR; } + +/************************************************************* + * public BMediaBufferEncoder + *************************************************************/ + +BMediaBufferEncoder::BMediaBufferEncoder() +{ + UNIMPLEMENTED(); +} + + +BMediaBufferEncoder::BMediaBufferEncoder(const media_format *output_format) +{ + UNIMPLEMENTED(); +} + + +BMediaBufferEncoder::BMediaBufferEncoder(const media_codec_info *mci) +{ + UNIMPLEMENTED(); +} + + +status_t +BMediaBufferEncoder::EncodeToBuffer(void *output_buffer, + size_t *output_size, + const void *input_buffer, + int64 frame_count, + media_encode_info *info) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +/************************************************************* + * public BMediaBufferEncoder + *************************************************************/ + +status_t +BMediaBufferEncoder::WriteChunk(const void *chunk_data, + size_t chunk_len, + media_encode_info *info) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + diff --git a/src/kits/media/MediaEventLooper.cpp b/src/kits/media/MediaEventLooper.cpp new file mode 100644 index 0000000000..c74978e7a6 --- /dev/null +++ b/src/kits/media/MediaEventLooper.cpp @@ -0,0 +1,529 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: MediaEventLooper.cpp + * DESCR: + ***********************************************************************/ +#include +#include +#include +#include "debug.h" + +// XXX The bebook says that the latency is always calculated in realtime +// XXX This is not currently done in this code + +/************************************************************* + * protected BMediaEventLooper + *************************************************************/ + +/* virtual */ +BMediaEventLooper::~BMediaEventLooper() +{ + CALLED(); + // don't call Quit(); here +} + +/* explicit */ +BMediaEventLooper::BMediaEventLooper(uint32 apiVersion) : + BMediaNode("called by BMediaEventLooper"), + fControlThread(-1), + fCurrentPriority(B_URGENT_PRIORITY), + fSetPriority(B_URGENT_PRIORITY), + fRunState(B_UNREGISTERED), + fEventLatency(0), + fSchedulingLatency(0), + fBufferDuration(0), + fOfflineTime(0), + fApiVersion(apiVersion) +{ + CALLED(); + fEventQueue.SetCleanupHook(BMediaEventLooper::_CleanUpEntry,this); + fRealTimeQueue.SetCleanupHook(BMediaEventLooper::_CleanUpEntry,this); +} + +/* virtual */ void +BMediaEventLooper::NodeRegistered() +{ + CALLED(); + // don't call Run(); here, must be done by the derived class (yes, that's stupid) +} + + +/* virtual */ void +BMediaEventLooper::Start(bigtime_t performance_time) +{ + CALLED(); + // This hook function is called when a node is started + // by a call to the BMediaRoster. The specified + // performanceTime, the time at which the node + // should start running, may be in the future. + fEventQueue.AddEvent(media_timed_event(performance_time, BTimedEventQueue::B_START)); +} + + +/* virtual */ void +BMediaEventLooper::Stop(bigtime_t performance_time, + bool immediate) +{ + CALLED(); + // This hook function is called when a node is stopped + // by a call to the BMediaRoster. The specified performanceTime, + // the time at which the node should stop, may be in the future. + // If immediate is true, your node should ignore the performanceTime + // value and synchronously stop performance. When Stop() returns, + // you're promising not to write into any BBuffers you may have + // received from your downstream consumers, and you promise not + // to send any more buffers until Start() is called again. + + if (immediate) { + // always be sure to add to the front of the queue so we can make sure it is + // handled before any buffers are sent! + performance_time = fEventQueue.FirstEventTime(); + performance_time = (performance_time == B_INFINITE_TIMEOUT) ? 0 : performance_time - 1; + } + fEventQueue.AddEvent(media_timed_event(performance_time, BTimedEventQueue::B_STOP)); +} + + +/* virtual */ void +BMediaEventLooper::Seek(bigtime_t media_time, + bigtime_t performance_time) +{ + CALLED(); + // This hook function is called when a node is asked to seek to + // the specified mediaTime by a call to the BMediaRoster. + // The specified performanceTime, the time at which the node + // should begin the seek operation, may be in the future. + fEventQueue.AddEvent(media_timed_event(performance_time, BTimedEventQueue::B_SEEK, NULL, + BTimedEventQueue::B_NO_CLEANUP, 0, media_time, NULL)); +} + + +/* virtual */ void +BMediaEventLooper::TimeWarp(bigtime_t at_real_time, + bigtime_t to_performance_time) +{ + CALLED(); + // This hook function is called when the time source to which the + // node is slaved is repositioned (via a seek operation) such that + // there will be a sudden jump in the performance time progression + // as seen by the node. The to_performance_time argument indicates + // the new performance time; the change should occur at the real + // time specified by the at_real_time argument. + + // place in the realtime queue + fRealTimeQueue.AddEvent(media_timed_event(at_real_time, BTimedEventQueue::B_WARP, + NULL, BTimedEventQueue::B_NO_CLEANUP, 0, to_performance_time, NULL)); + + // BeBook: Your implementation of TimeWarp() should call through to BMediaNode::TimeWarp() + // BeBook: as well as all other inherited forms of TimeWarp() + // XXX should we do this here? + BMediaNode::TimeWarp(at_real_time, to_performance_time); +} + + +/* virtual */ status_t +BMediaEventLooper::AddTimer(bigtime_t at_performance_time, + int32 cookie) +{ + CALLED(); + // XXX what do we need to do here? + return BMediaNode::AddTimer(at_performance_time,cookie); +} + + +/* virtual */ void +BMediaEventLooper::SetRunMode(run_mode mode) +{ + CALLED(); + // The SetRunMode() hook function is called when someone requests that your node's run mode be changed. + + // bump or reduce priority when switching from/to offline run mode + int32 priority; + priority = (mode == B_OFFLINE) ? min_c(B_NORMAL_PRIORITY, fSetPriority) : fSetPriority; + if (priority != fCurrentPriority) { + fCurrentPriority = priority; + if(fControlThread > 0) { + set_thread_priority(fControlThread, fCurrentPriority); + fSchedulingLatency = estimate_max_scheduling_latency(fControlThread); + } + } + + BMediaNode::SetRunMode(mode); +} + + +/* virtual */ void +BMediaEventLooper::CleanUpEvent(const media_timed_event *event) +{ + CALLED(); + // Implement this function to clean up after custom events you've created + // and added to your queue. It's called when a custom event is removed from + // the queue, to let you handle any special tidying-up that the event might require. +} + + +/* virtual */ bigtime_t +BMediaEventLooper::OfflineTime() +{ + CALLED(); + return fOfflineTime; +} + + +/* virtual */ void +BMediaEventLooper::ControlLoop() +{ + CALLED(); + + bool is_realtime; + status_t err; + bigtime_t latency; + bigtime_t waituntil; + for (;;) { + // while there are no events or it is not time for the earliest event, + // process messages using WaitForMessages. Whenever this funtion times out, + // we need to handle the next event + for (;;) { + if (RunState() == B_QUITTING) + return; + // BMediaEventLooper compensates your performance time by adding the event latency + // (see SetEventLatency()) and the scheduling latency (or, for real-time events, + // only the scheduling latency). + // latency = fOut.downstream_latency + fOut.processing_latency + fSchedulingLatency; + // XXX well, fix this later + latency = fEventLatency + fSchedulingLatency; + + if (fEventQueue.HasEvents() && (TimeSource()->Now() - latency) >= fEventQueue.FirstEventTime()) { + is_realtime = false; + break; + } + if (fRealTimeQueue.HasEvents() && (TimeSource()->RealTimeFor(TimeSource()->Now(),fSchedulingLatency)) >= fRealTimeQueue.FirstEventTime()) { + is_realtime = true; + break; + } + waituntil = B_INFINITE_TIMEOUT; + if (fEventQueue.HasEvents()) { + waituntil = TimeSource()->RealTimeFor(fEventQueue.FirstEventTime(), latency); + is_realtime = false; + } + if (fRealTimeQueue.HasEvents()) { + bigtime_t temp; + temp = TimeSource()->RealTimeFor(TimeSource()->PerformanceTimeFor(fRealTimeQueue.FirstEventTime()), fSchedulingLatency); + if (temp < waituntil) { + waituntil = temp; + is_realtime = true; + } + } + err = WaitForMessage(waituntil); + if (err == B_TIMED_OUT) + break; + } + + /// we have timed out - so handle the next event + media_timed_event event; + if (is_realtime) + err = fRealTimeQueue.RemoveFirstEvent(&event); + else + err = fEventQueue.RemoveFirstEvent(&event); + + if (err == B_OK) { + bigtime_t lateness; + if (is_realtime) + lateness = TimeSource()->RealTime() - event.event_time; + else + lateness = TimeSource()->Now() - event.event_time; + DispatchEvent(&event,lateness,is_realtime); + } + } +} + + +thread_id +BMediaEventLooper::ControlThread() +{ + CALLED(); + return fControlThread; +} + +/************************************************************* + * protected BMediaEventLooper + *************************************************************/ + + +BTimedEventQueue * +BMediaEventLooper::EventQueue() +{ + CALLED(); + return &fEventQueue; +} + + +BTimedEventQueue * +BMediaEventLooper::RealTimeQueue() +{ + CALLED(); + return &fRealTimeQueue; +} + + +int32 +BMediaEventLooper::Priority() const +{ + CALLED(); + return fCurrentPriority; +} + + +int32 +BMediaEventLooper::RunState() const +{ + CALLED(); + return fRunState; +} + + +bigtime_t +BMediaEventLooper::EventLatency() const +{ + CALLED(); + return fEventLatency; +} + + +bigtime_t +BMediaEventLooper::BufferDuration() const +{ + CALLED(); + return fBufferDuration; +} + + +bigtime_t +BMediaEventLooper::SchedulingLatency() const +{ + CALLED(); + return fSchedulingLatency; +} + + +status_t +BMediaEventLooper::SetPriority(int32 priority) +{ + CALLED(); + + // clamp to a valid value + if (priority < 1) + priority = 1; + + if (priority > 120) + priority = 120; + + fSetPriority = priority; + fCurrentPriority = (RunMode() == B_OFFLINE) ? min_c(B_NORMAL_PRIORITY, fSetPriority) : fSetPriority; + + if(fControlThread > 0) { + set_thread_priority(fControlThread, fCurrentPriority); + fSchedulingLatency = estimate_max_scheduling_latency(fControlThread); + } + + return B_OK; +} + + +void +BMediaEventLooper::SetRunState(run_state state) +{ + CALLED(); + + // don't allow run state changes while quitting, + // also needed for correct terminating of the ControlLoop() + if (fRunState == B_QUITTING && state != B_TERMINATED) + return; + + fRunState = state; +} + + +void +BMediaEventLooper::SetEventLatency(bigtime_t latency) +{ + CALLED(); + // clamp to a valid value + if (latency < 0) + latency = 0; + + fEventLatency = latency; +} + + +void +BMediaEventLooper::SetBufferDuration(bigtime_t duration) +{ + CALLED(); + fBufferDuration = duration; +} + + +void +BMediaEventLooper::SetOfflineTime(bigtime_t offTime) +{ + CALLED(); + fOfflineTime = offTime; +} + + +void +BMediaEventLooper::Run() +{ + CALLED(); + + if (fControlThread != -1) + return; // thread already running + + char threadName[32]; + sprintf(threadName, "%.20s control", Name()); + fControlThread = spawn_thread(_ControlThreadStart, threadName, fCurrentPriority, this); + resume_thread(fControlThread); + + // get latency information + fSchedulingLatency = estimate_max_scheduling_latency(fControlThread); +} + + +void +BMediaEventLooper::Quit() +{ + CALLED(); + status_t err; + + if (fRunState == B_TERMINATED) + return; + + SetRunState(B_QUITTING); + + close_port(ControlPort()); + if (fControlThread != -1) + wait_for_thread(fControlThread, &err); + fControlThread = -1; + + SetRunState(B_TERMINATED); +} + + +void +BMediaEventLooper::DispatchEvent(const media_timed_event *event, + bigtime_t lateness, + bool realTimeEvent) +{ + CALLED(); + + HandleEvent(event,lateness,realTimeEvent); + + switch (event->type) { + case BTimedEventQueue::B_START: + SetRunState(B_STARTED); + break; + + case BTimedEventQueue::B_STOP: + SetRunState(B_STOPPED); + break; + + case BTimedEventQueue::B_SEEK: + /* nothing */ + break; + + case BTimedEventQueue::B_WARP: + /* nothing */ + break; + + default: + break; + } + +} + +/************************************************************* + * private BMediaEventLooper + *************************************************************/ + + +/* static */ int32 +BMediaEventLooper::_ControlThreadStart(void *arg) +{ + CALLED(); + ((BMediaEventLooper *)arg)->SetRunState(B_STOPPED); + ((BMediaEventLooper *)arg)->ControlLoop(); + ((BMediaEventLooper *)arg)->SetRunState(B_QUITTING); + return 0; +} + + +/* static */ void +BMediaEventLooper::_CleanUpEntry(const media_timed_event *event, + void *context) +{ + CALLED(); + ((BMediaEventLooper *)context)->_DispatchCleanUp(event); +} + + +void +BMediaEventLooper::_DispatchCleanUp(const media_timed_event *event) +{ + CALLED(); + + // this function to clean up after custom events you've created + if (event->cleanup >= BTimedEventQueue::B_USER_CLEANUP) + CleanUpEvent(event); +} + +/* +// unimplemented +BMediaEventLooper::BMediaEventLooper(const BMediaEventLooper &) +BMediaEventLooper &BMediaEventLooper::operator=(const BMediaEventLooper &) +*/ + +/************************************************************* + * protected BMediaEventLooper + *************************************************************/ + + +status_t +BMediaEventLooper::DeleteHook(BMediaNode *node) +{ + CALLED(); + // this is the DeleteHook that gets called by the media server + // before the media node is deleted + Quit(); + return BMediaNode::DeleteHook(node); +} + +/************************************************************* + * private BMediaEventLooper + *************************************************************/ + +status_t BMediaEventLooper::_Reserved_BMediaEventLooper_0(int32 arg,...) { return B_ERROR; } +status_t BMediaEventLooper::_Reserved_BMediaEventLooper_1(int32 arg,...) { return B_ERROR; } +status_t BMediaEventLooper::_Reserved_BMediaEventLooper_2(int32 arg,...) { return B_ERROR; } +status_t BMediaEventLooper::_Reserved_BMediaEventLooper_3(int32 arg,...) { return B_ERROR; } +status_t BMediaEventLooper::_Reserved_BMediaEventLooper_4(int32 arg,...) { return B_ERROR; } +status_t BMediaEventLooper::_Reserved_BMediaEventLooper_5(int32 arg,...) { return B_ERROR; } +status_t BMediaEventLooper::_Reserved_BMediaEventLooper_6(int32 arg,...) { return B_ERROR; } +status_t BMediaEventLooper::_Reserved_BMediaEventLooper_7(int32 arg,...) { return B_ERROR; } +status_t BMediaEventLooper::_Reserved_BMediaEventLooper_8(int32 arg,...) { return B_ERROR; } +status_t BMediaEventLooper::_Reserved_BMediaEventLooper_9(int32 arg,...) { return B_ERROR; } +status_t BMediaEventLooper::_Reserved_BMediaEventLooper_10(int32 arg,...) { return B_ERROR; } +status_t BMediaEventLooper::_Reserved_BMediaEventLooper_11(int32 arg,...) { return B_ERROR; } +status_t BMediaEventLooper::_Reserved_BMediaEventLooper_12(int32 arg,...) { return B_ERROR; } +status_t BMediaEventLooper::_Reserved_BMediaEventLooper_13(int32 arg,...) { return B_ERROR; } +status_t BMediaEventLooper::_Reserved_BMediaEventLooper_14(int32 arg,...) { return B_ERROR; } +status_t BMediaEventLooper::_Reserved_BMediaEventLooper_15(int32 arg,...) { return B_ERROR; } +status_t BMediaEventLooper::_Reserved_BMediaEventLooper_16(int32 arg,...) { return B_ERROR; } +status_t BMediaEventLooper::_Reserved_BMediaEventLooper_17(int32 arg,...) { return B_ERROR; } +status_t BMediaEventLooper::_Reserved_BMediaEventLooper_18(int32 arg,...) { return B_ERROR; } +status_t BMediaEventLooper::_Reserved_BMediaEventLooper_19(int32 arg,...) { return B_ERROR; } +status_t BMediaEventLooper::_Reserved_BMediaEventLooper_20(int32 arg,...) { return B_ERROR; } +status_t BMediaEventLooper::_Reserved_BMediaEventLooper_21(int32 arg,...) { return B_ERROR; } +status_t BMediaEventLooper::_Reserved_BMediaEventLooper_22(int32 arg,...) { return B_ERROR; } +status_t BMediaEventLooper::_Reserved_BMediaEventLooper_23(int32 arg,...) { return B_ERROR; } + diff --git a/src/kits/media/MediaFile.cpp b/src/kits/media/MediaFile.cpp new file mode 100644 index 0000000000..68115e4e02 --- /dev/null +++ b/src/kits/media/MediaFile.cpp @@ -0,0 +1,293 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: MediaFile.cpp + * DESCR: + ***********************************************************************/ +#include +#include +#include "debug.h" + + +/************************************************************* + * public BMediaFile + *************************************************************/ + +BMediaFile::BMediaFile(const entry_ref *ref) +{ + UNIMPLEMENTED(); +} + +BMediaFile::BMediaFile(BDataIO * source) +{ + UNIMPLEMENTED(); +} + +BMediaFile::BMediaFile(const entry_ref * ref, + int32 flags) +{ + UNIMPLEMENTED(); +} + +BMediaFile::BMediaFile(BDataIO * source, + int32 flags) +{ + UNIMPLEMENTED(); +} + +BMediaFile::BMediaFile(const entry_ref *ref, + const media_file_format * mfi, + int32 flags) +{ + UNIMPLEMENTED(); +} + +BMediaFile::BMediaFile(BDataIO *destination, + const media_file_format * mfi, + int32 flags) +{ + UNIMPLEMENTED(); +} + + +BMediaFile::BMediaFile(const media_file_format * mfi, + int32 flags) +{ + UNIMPLEMENTED(); +} + +/* virtual */ +BMediaFile::~BMediaFile() +{ + UNIMPLEMENTED(); +} + +status_t +BMediaFile::InitCheck() const +{ + UNIMPLEMENTED(); + + return B_OK; +} + +// Get info about the underlying file format. +status_t +BMediaFile::GetFileFormatInfo(media_file_format *mfi) const +{ + UNIMPLEMENTED(); + return B_OK; +} + +const char * +BMediaFile::Copyright(void) const +{ + UNIMPLEMENTED(); + return ""; +} + +int32 +BMediaFile::CountTracks() const +{ + UNIMPLEMENTED(); + return 1; +} + + +// Can be called multiple times with the same index. You must call +// ReleaseTrack() when you're done with a track. +BMediaTrack * +BMediaFile::TrackAt(int32 index) +{ + UNIMPLEMENTED(); + return new BMediaTrack(0, 0); +} + + +// Release the resource used by a given BMediaTrack object, to reduce +// the memory usage of your application. The specific 'track' object +// can no longer be used, but you can create another one by calling +// TrackAt() with the same track index. +status_t +BMediaFile::ReleaseTrack(BMediaTrack *track) +{ + UNIMPLEMENTED(); + return B_OK; +} + +status_t +BMediaFile::ReleaseAllTracks(void) +{ + UNIMPLEMENTED(); + return B_OK; +} + +// Create and add a track to the media file +BMediaTrack * +BMediaFile::CreateTrack(media_format *mf, + const media_codec_info *mci) +{ + UNIMPLEMENTED(); + return 0; +} + +// Create and add a raw track to the media file (it has no encoder) +BMediaTrack * +BMediaFile::CreateTrack(media_format *mf) +{ + UNIMPLEMENTED(); + return 0; +} + + +// Lets you set the copyright info for the entire file +status_t +BMediaFile::AddCopyright(const char *data) +{ + UNIMPLEMENTED(); + return B_OK; +} + + +// Call this to add user-defined chunks to a file (if they're supported) +status_t +BMediaFile::AddChunk(int32 type, const void *data, size_t size) +{ + UNIMPLEMENTED(); + return B_OK; +} + + +// After you have added all the tracks you want, call this +status_t +BMediaFile::CommitHeader(void) +{ + UNIMPLEMENTED(); + return B_OK; +} + + +// After you have written all the data to the track objects, call this +status_t +BMediaFile::CloseFile(void) +{ + UNIMPLEMENTED(); + return B_OK; +} + + +// This is for controlling file format parameters +BParameterWeb * +BMediaFile::Web() +{ + UNIMPLEMENTED(); + return 0; +} + +status_t +BMediaFile::GetParameterValue(int32 id, void *valu, size_t *size) +{ + UNIMPLEMENTED(); + return B_OK; +} + +status_t +BMediaFile::SetParameterValue(int32 id, const void *valu, size_t size) +{ + UNIMPLEMENTED(); + return B_OK; +} + + +BView * +BMediaFile::GetParameterView() +{ + UNIMPLEMENTED(); + return 0; +} + +/* virtual */ status_t +BMediaFile::Perform(int32 selector, void * data) +{ + UNIMPLEMENTED(); + return B_OK; +} + + +/************************************************************* + * private BMediaFile + *************************************************************/ + +void +BMediaFile::Init() +{ + UNIMPLEMENTED(); +} + +void +BMediaFile::InitReader(BDataIO *source, int32 flags /* = 0 */) +{ + UNIMPLEMENTED(); +} + +void +BMediaFile::InitWriter(BDataIO *source, const media_file_format * mfi, int32 flags) +{ + UNIMPLEMENTED(); +} + + +/* +//unimplemented +BMediaFile::BMediaFile(); +BMediaFile::BMediaFile(const BMediaFile&); +BMediaFile::BMediaFile& operator=(const BMediaFile&); +*/ + +status_t BMediaFile::_Reserved_BMediaFile_0(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_1(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_2(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_3(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_4(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_5(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_6(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_7(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_8(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_9(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_10(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_11(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_12(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_13(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_14(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_15(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_16(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_17(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_18(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_19(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_20(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_21(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_22(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_23(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_24(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_25(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_26(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_27(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_28(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_29(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_30(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_31(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_32(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_33(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_34(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_35(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_36(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_37(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_38(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_39(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_40(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_41(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_42(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_43(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_44(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_45(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_46(int32 arg, ...) { return B_ERROR; } +status_t BMediaFile::_Reserved_BMediaFile_47(int32 arg, ...) { return B_ERROR; } + diff --git a/src/kits/media/MediaFiles.cpp b/src/kits/media/MediaFiles.cpp new file mode 100644 index 0000000000..9260640c53 --- /dev/null +++ b/src/kits/media/MediaFiles.cpp @@ -0,0 +1,119 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: MediaFiles.cpp + * DESCR: + ***********************************************************************/ +#include +#include "debug.h" + +/************************************************************* + * public BMediaFiles + *************************************************************/ + +const char BMediaFiles::B_SOUNDS[] = "XXX fixme"; /* for "types" */ + +BMediaFiles::BMediaFiles() +{ + UNIMPLEMENTED(); +} + + +/* virtual */ +BMediaFiles::~BMediaFiles() +{ + UNIMPLEMENTED(); +} + + +/* virtual */ status_t +BMediaFiles::RewindTypes() +{ + UNIMPLEMENTED(); + + return B_OK; +} + + +/* virtual */ status_t +BMediaFiles::GetNextType(BString *out_type) +{ + UNIMPLEMENTED(); + + return B_ERROR; +} + + +/* virtual */ status_t +BMediaFiles::RewindRefs(const char *type) +{ + UNIMPLEMENTED(); + + return B_OK; +} + + +/* virtual */ status_t +BMediaFiles::GetNextRef(BString *out_type, + entry_ref *out_ref) +{ + UNIMPLEMENTED(); + + return B_ERROR; +} + + +/* virtual */ status_t +BMediaFiles::GetRefFor(const char *type, + const char *item, + entry_ref *out_ref) +{ + UNIMPLEMENTED(); + + return B_ERROR; +} + + +/* virtual */ status_t +BMediaFiles::SetRefFor(const char *type, + const char *item, + const entry_ref &ref) +{ + UNIMPLEMENTED(); + + return B_OK; +} + + +/* virtual */ status_t +BMediaFiles::RemoveRefFor(const char *type, + const char *item, + const entry_ref &ref) +{ + UNIMPLEMENTED(); + + return B_OK; +} + + +/* virtual */ status_t +BMediaFiles::RemoveItem(const char *type, + const char *item) +{ + UNIMPLEMENTED(); + + return B_OK; +} + +/************************************************************* + * private BMediaFiles + *************************************************************/ + +status_t BMediaFiles::_Reserved_MediaFiles_0(void *,...) { return B_ERROR; } +status_t BMediaFiles::_Reserved_MediaFiles_1(void *,...) { return B_ERROR; } +status_t BMediaFiles::_Reserved_MediaFiles_2(void *,...) { return B_ERROR; } +status_t BMediaFiles::_Reserved_MediaFiles_3(void *,...) { return B_ERROR; } +status_t BMediaFiles::_Reserved_MediaFiles_4(void *,...) { return B_ERROR; } +status_t BMediaFiles::_Reserved_MediaFiles_5(void *,...) { return B_ERROR; } +status_t BMediaFiles::_Reserved_MediaFiles_6(void *,...) { return B_ERROR; } +status_t BMediaFiles::_Reserved_MediaFiles_7(void *,...) { return B_ERROR; } + diff --git a/src/kits/media/MediaFormats.cpp b/src/kits/media/MediaFormats.cpp new file mode 100644 index 0000000000..c29272829c --- /dev/null +++ b/src/kits/media/MediaFormats.cpp @@ -0,0 +1,341 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: MediaFormats.cpp + * DESCR: + ***********************************************************************/ +#include +#include "debug.h" + + +/************************************************************* + * + *************************************************************/ + +status_t get_next_encoder(int32 *cookie, + const media_file_format *mfi, // this comes from get_next_file_format() + const media_format *input_format, // this is the type of data given to the encoder + media_format *output_format, // this is the type of data encoder will output + media_codec_info *ei) // information about the encoder +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t get_next_encoder(int32 *cookie, + const media_file_format *mfi, + const media_format *input_format, + const media_format *output_format, + media_codec_info *ei, + media_format *accepted_input_format, + media_format *accepted_output_format) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t get_next_encoder(int32 *cookie, media_codec_info *ei) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +bool does_file_accept_format(const media_file_format *mfi, + media_format *format, uint32 flags) +{ + UNIMPLEMENTED(); + return false; +} + +/************************************************************* + * _media_format_description + *************************************************************/ + +_media_format_description::_media_format_description() +{ + UNIMPLEMENTED(); +} + +_media_format_description::~_media_format_description() +{ + UNIMPLEMENTED(); +} + +_media_format_description::_media_format_description(const _media_format_description & other) +{ + UNIMPLEMENTED(); +} + +_media_format_description & +_media_format_description::operator=(const _media_format_description & other) +{ + UNIMPLEMENTED(); + return *this; +} + +/************************************************************* + * + *************************************************************/ + + +namespace BPrivate { + +class addon_list +{ +}; + + +void dec_load_hook(void *arg, image_id imgid) +{ + UNIMPLEMENTED(); +}; + +void extractor_load_hook(void *arg, image_id imgid) +{ + UNIMPLEMENTED(); +}; + +class Extractor +{ +}; + +} + +/************************************************************* + * public BMediaFormats + *************************************************************/ + +BMediaFormats::BMediaFormats() +{ + UNIMPLEMENTED(); +} + +/* virtual */ +BMediaFormats::~BMediaFormats() +{ + UNIMPLEMENTED(); +} + +status_t +BMediaFormats::InitCheck() +{ + UNIMPLEMENTED(); + + return B_OK; +} + +status_t +BMediaFormats::MakeFormatFor(const media_format_description * descs, + int32 desc_count, + media_format * io_format, + uint32 flags, + void * _reserved) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaFormats::GetFormatFor(const media_format_description & desc, + media_format * out_format) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +/* static */ status_t +BMediaFormats::GetBeOSFormatFor(uint32 fourcc, + media_format * out_format, + media_type type) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +/* static */ status_t +BMediaFormats::GetAVIFormatFor(uint32 fourcc, + media_format * out_format, + media_type type) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +/* static */ status_t +BMediaFormats::GetQuicktimeFormatFor(uint32 vendor, + uint32 fourcc, + media_format * out_format, + media_type type) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaFormats::GetCodeFor(const media_format & format, + media_format_family family, + media_format_description * out_description) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaFormats::RewindFormats() +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaFormats::GetNextFormat(media_format * out_format, + media_format_description * out_description) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + +// You need to lock/unlock (only) when using RewindFormats()/GetNextFormat() +bool +BMediaFormats::Lock() +{ + UNIMPLEMENTED(); + return true; +} + +void +BMediaFormats::Unlock() +{ + UNIMPLEMENTED(); +} + +/* --- begin deprecated API --- */ +status_t +BMediaFormats::MakeFormatFor(const media_format_description & desc, + const media_format & in_format, + media_format * out_format) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + +/************************************************************* + * private BMediaFormats + *************************************************************/ + +void +BMediaFormats::clear_formats() +{ + UNIMPLEMENTED(); +} + +/* static */ void +BMediaFormats::ex_clear_formats_imp() +{ + UNIMPLEMENTED(); +} + +/* static */ void +BMediaFormats::clear_formats_imp() +{ + UNIMPLEMENTED(); +} + +status_t +BMediaFormats::get_formats() +{ + UNIMPLEMENTED(); + return B_ERROR; +} + +/* static */ status_t +BMediaFormats::get_formats_imp() +{ + UNIMPLEMENTED(); + return B_ERROR; +} + +/* static */ BMessenger & +BMediaFormats::get_server() +{ + UNIMPLEMENTED(); + static BMessenger dummy; + return dummy; +} + +/* static */ status_t +BMediaFormats::bind_addon( + const char * addon, + const media_format * formats, + int32 count) +{ + UNIMPLEMENTED(); + return B_OK; +} + +/* static */ bool +BMediaFormats::is_bound( + const char * addon, + const media_format * formats, + int32 count) +{ + UNIMPLEMENTED(); + return false; +} + + +/* static */ status_t +BMediaFormats::find_addons( + const media_format * format, + BPrivate::addon_list & addons) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + +/************************************************************* + * static BMediaFormats variables + *************************************************************/ + +int32 BMediaFormats::s_cleared; +BMessenger BMediaFormats::s_server; +BList BMediaFormats::s_formats; +BLocker BMediaFormats::s_lock; + +/************************************************************* + * + *************************************************************/ + +bool operator==(const media_format_description & a, const media_format_description & b) +{ + UNIMPLEMENTED(); + return false; +} + +bool operator<(const media_format_description & a, const media_format_description & b) +{ + UNIMPLEMENTED(); + return false; +} + +bool operator==(const GUID & a, const GUID & b) +{ + UNIMPLEMENTED(); + return false; +} + +bool operator<(const GUID & a, const GUID & b) +{ + UNIMPLEMENTED(); + return false; +} + diff --git a/src/kits/media/MediaNode.cpp b/src/kits/media/MediaNode.cpp new file mode 100644 index 0000000000..7dc7498a29 --- /dev/null +++ b/src/kits/media/MediaNode.cpp @@ -0,0 +1,716 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: MediaNode.cpp + * DESCR: + ***********************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include "SystemTimeSource.h" +#include "debug.h" +#include "../server/headers/ServerInterface.h" + +// don't rename this one, it's used and exported for binary compatibility +int32 BMediaNode::_m_changeTag = 0; + +/************************************************************* + * media_node + *************************************************************/ + +// final & verified +media_node::media_node() + : node(-1), + port(-1), + kind(0) +{ + CALLED(); +} + +// final & verified +media_node::~media_node() +{ + CALLED(); +} + +/************************************************************* + * static media_node variables + *************************************************************/ + +// final & verified +media_node media_node::null; + +/************************************************************* + * media_input + *************************************************************/ + +// final +media_input::media_input() +{ + CALLED(); + name[0] = '\0'; +} + +// final +media_input::~media_input() +{ + CALLED(); +} + +/************************************************************* + * media_output + *************************************************************/ + +// final +media_output::media_output() +{ + CALLED(); + name[0] = '\0'; +} + +// final +media_output::~media_output() +{ + CALLED(); +} + +/************************************************************* + * live_node_info + *************************************************************/ + +// final & verified +live_node_info::live_node_info() + : hint_point(0.0f,0.0f) +{ + CALLED(); + name[0] = '\0'; +} + +// final & verified +live_node_info::~live_node_info() +{ + CALLED(); +} + +/************************************************************* + * protected BMediaNode + *************************************************************/ + +/* virtual */ +BMediaNode::~BMediaNode() +{ + CALLED(); + + // BeBook: UnregisterNode() unregisters a node from the Media Server. It's called automatically + // BeBook: by the BMediaNode destructor, but it might be convenient to call it sometime before + // BeBook: you delete your node instance, depending on your implementation and circumstances. + (BMediaRoster::Roster())->UnregisterNode(this); + + if (fControlPort != -1) + delete_port(fControlPort); + if (fTimeSource) + fTimeSource->Release(); +} + +/************************************************************* + * public BMediaNode + *************************************************************/ + +BMediaNode * +BMediaNode::Acquire() +{ + CALLED(); + atomic_add(&fRefCount,1); + return this; +} + + +BMediaNode * +BMediaNode::Release() +{ + CALLED(); + if (atomic_add(&fRefCount,-1) == 1) { + if (DeleteHook(this) != B_OK) { + TRACE("BMediaNode::Release(): DeleteHook failed\n"); + return Acquire(); + } + return NULL; + } + return this; +} + + +const char * +BMediaNode::Name() const +{ + CALLED(); + return fName; +} + + +media_node_id +BMediaNode::ID() const +{ + CALLED(); + return fNodeID; +} + + +uint64 +BMediaNode::Kinds() const +{ + CALLED(); + return fKinds; +} + + +media_node +BMediaNode::Node() const +{ + CALLED(); + media_node temp; + temp.node = ID(); + temp.port = ControlPort(); + temp.kind = Kinds(); + return temp; +} + + +BMediaNode::run_mode +BMediaNode::RunMode() const +{ + CALLED(); + return fRunMode; +} + + +BTimeSource * +BMediaNode::TimeSource() const +{ + CALLED(); + return fTimeSource; +} + + +/* virtual */ port_id +BMediaNode::ControlPort() const +{ + CALLED(); + return fControlPort; +} + + +/************************************************************* + * protected BMediaNode + *************************************************************/ + +status_t +BMediaNode::ReportError(node_error what, + const BMessage *info) +{ + UNIMPLEMENTED(); + // XXX Transmits the error code specified by whichError to anyone + // XXX that's receiving notifications from this node (see + // XXX BMediaRoster::StartWatching() and BMediaRoster::StopWatching() on). + return B_OK; +} + + +status_t +BMediaNode::NodeStopped(bigtime_t whenPerformance) +{ + UNIMPLEMENTED(); + // called by derived classes when they have + // finished handling a stop request. + + // XXX notify anyone who is listening for stop notifications! + + // XXX If your node is a BBufferProducer, downstream consumers + // XXX will be notified that your node stopped (automatically, no less) + // XXX through the BBufferConsumer::ProducerDataStatus(B_PRODUCER_STOPPED) call. + + return B_OK; +} + + +void +BMediaNode::TimerExpired(bigtime_t notifyPoint, + int32 cookie, + status_t error) +{ + UNIMPLEMENTED(); + // Used with AddTimer + // This will, in turn, cause the BMediaRoster::SyncToNode() call + // that instigated the timer to return to the caller. + // Probably only important to classes derived from BTimeSource. +} + + +// terrible hack to call the other constructor +// BMediaNode::BMediaNode(const char *name, media_node_id id, uint32 kinds) +extern "C" void __10BMediaNodePCclUl(BMediaNode *self, const char *name, media_node_id id, uint32 kinds); + +/* explicit */ +BMediaNode::BMediaNode(const char *name) +{ + CALLED(); + __10BMediaNodePCclUl(this,name,0,0); +} + + +status_t +BMediaNode::WaitForMessage(bigtime_t waitUntil, + uint32 flags, + void *_reserved_) +{ + CALLED(); + // This function waits until either real time specified by + // waitUntil or a message is received on the control port. + // The flags are currently unused and should be 0. + + char data[B_MEDIA_MESSAGE_SIZE]; // about 16 KByte stack used + int32 message; + ssize_t size; + + size = read_port_etc(fControlPort, &message, data, sizeof(data), B_ABSOLUTE_TIMEOUT, waitUntil); + if (size <= 0) { + if (size != B_TIMED_OUT) + TRACE("read_port_etc error 0x%08lx\n",size); + return size; // returns the error code + } + + if (B_OK == HandleMessage(message, data, size)) + return B_OK; + + HandleBadMessage(message, data, size); + + return B_ERROR; +} + + +/* virtual */ void +BMediaNode::Start(bigtime_t performance_time) +{ + CALLED(); + // This hook function is called when a node is started + // by a call to the BMediaRoster. The specified + // performanceTime, the time at which the node + // should start running, may be in the future. + // It may be overriden by derived classes. + // The BMediaEventLooper class handles this event! + // The BMediaNode class does nothing here. +} + + +/* virtual */ void +BMediaNode::Stop(bigtime_t performance_time, + bool immediate) +{ + CALLED(); + // This hook function is called when a node is stopped + // by a call to the BMediaRoster. The specified + // performanceTime, the time at which the node + // should stop running, may be in the future. + // It may be overriden by derived classes. + // The BMediaEventLooper class handles this event! + // The BMediaNode class does nothing here. +} + + +/* virtual */ void +BMediaNode::Seek(bigtime_t media_time, + bigtime_t performance_time) +{ + CALLED(); + // This hook function is called when a node is asked + // to seek to the specified mediaTime by a call to + // the BMediaRoster. The specified performanceTime, + // the time at which the node should begin the seek + // operation, may be in the future. + // It may be overriden by derived classes. + // The BMediaEventLooper class handles this event! + // The BMediaNode class does nothing here. +} + + +/* virtual */ void +BMediaNode::SetRunMode(run_mode mode) +{ + CALLED(); + + // this is a hook function, and + // may be overriden by derived classes. + + // the functionality here is only to + // support those people that don't + // use the roster to set the run mode + fRunMode = mode; +} + + +/* virtual */ void +BMediaNode::TimeWarp(bigtime_t at_real_time, + bigtime_t to_performance_time) +{ + CALLED(); + // May be overriden by derived classes. +} + + +/* virtual */ void +BMediaNode::Preroll() +{ + CALLED(); + // May be overriden by derived classes. +} + + +/* virtual */ void +BMediaNode::SetTimeSource(BTimeSource *time_source) +{ + CALLED(); + + // this is a hook function, and + // may be overriden by derived classes. + + // the functionality here is only to + // support those people that don't + // use the roster to set a time source + if (time_source == fTimeSource) + return; + if (time_source == NULL) + return; + if (fTimeSource) + fTimeSource->Release(); + fTimeSource = dynamic_cast(time_source->Acquire()); + fTimeSourceID = fTimeSource->ID(); +} + +/************************************************************* + * public BMediaNode + *************************************************************/ + +/* virtual */ status_t +BMediaNode::HandleMessage(int32 message, + const void *rawdata, + size_t size) +{ + CALLED(); + switch (message) { + case NODE_START: + { + const xfer_node_start *data = (const xfer_node_start *)rawdata; + Start(data->performance_time); + return B_OK; + } + + case NODE_STOP: + { + const xfer_node_stop *data = (const xfer_node_stop *)rawdata; + Stop(data->performance_time, data->immediate); + return B_OK; + } + + case NODE_SEEK: + { + const xfer_node_seek *data = (const xfer_node_seek *)rawdata; + Seek(data->media_time, data->performance_time); + return B_OK; + } + + case NODE_SET_RUN_MODE: + { + const xfer_node_set_run_mode *data = (const xfer_node_set_run_mode *)rawdata; + fRunMode = data->mode; + SetRunMode(fRunMode); + return B_OK; + } + + case NODE_TIME_WARP: + { + const xfer_node_time_warp *data = (const xfer_node_time_warp *)rawdata; + TimeWarp(data->at_real_time,data->to_performance_time); + return B_OK; + } + + case NODE_PREROLL: + { + Preroll(); + return B_OK; + } + + case NODE_REGISTERED: + { + const xfer_node_registered *data = (const xfer_node_registered *)rawdata; + fNodeID = data->node_id; + NodeRegistered(); + return B_OK; + } + + case NODE_SET_TIMESOURCE: + { + const xfer_node_set_timesource *data = (const xfer_node_set_timesource *)rawdata; + bool first = (fTimeSourceID == 0); + if (fTimeSource) + fTimeSource->Release(); + fTimeSourceID = data->timesource_id; + fTimeSource = 0; // XXX create timesource object here + fTimeSource = new _SysTimeSource; + if (!first) + SetTimeSource(fTimeSource); + return B_OK; + } + + case NODE_REQUEST_COMPLETED: + { + const xfer_node_request_completed *data = (const xfer_node_request_completed *)rawdata; + RequestCompleted(data->info); + return B_OK; + } + + }; + return B_ERROR; +} + + +void +BMediaNode::HandleBadMessage(int32 code, + const void *buffer, + size_t size) +{ + CALLED(); +} + + +void +BMediaNode::AddNodeKind(uint64 kind) +{ + CALLED(); + + fKinds |= kind; +} + + +void * +BMediaNode::operator new(size_t size) +{ + CALLED(); + return ::operator new(size); +} + +void * +BMediaNode::operator new(size_t size, + const nothrow_t &) throw() +{ + CALLED(); + return ::operator new(size,nothrow); +} + +void +BMediaNode::operator delete(void *ptr) +{ + CALLED(); + ::operator delete(ptr); +} + +void +BMediaNode::operator delete(void * ptr, + const nothrow_t &) throw() +{ + CALLED(); + ::operator delete(ptr,nothrow); +} + +/************************************************************* + * protected BMediaNode + *************************************************************/ + +/* virtual */ status_t +BMediaNode::RequestCompleted(const media_request_info &info) +{ + CALLED(); + // This function is called whenever a request issued by the node is completed. + // May be overriden by derived classes. + // info.change_tag can be used to match up requests against + // the accompaning calles from + // BBufferConsumer::RequestFormatChange() + // BBufferConsumer::SetOutputBuffersFor() + // BBufferConsumer::SetOutputEnabled() + // BBufferConsumer::SetVideoClippingFor() + return B_OK; +} + +/************************************************************* + * private BMediaNode + *************************************************************/ + +int32 +BMediaNode::IncrementChangeTag() +{ + CALLED(); + // Only present in BeOS R4 + // Obsoleted in BeOS R4.5 and later + // "updates the change tag, so that downstream consumers know that the node is in a new state." + // not supported, only for binary compatibility + return 0; +} + + +int32 +BMediaNode::ChangeTag() +{ + UNIMPLEMENTED(); + // Only present in BeOS R4 + // Obsoleted in BeOS R4.5 and later + // "returns the node's current change tag value." + // not supported, only for binary compatibility + return 0; +} + + +int32 +BMediaNode::MintChangeTag() +{ + UNIMPLEMENTED(); + // Only present in BeOS R4 + // Obsoleted in BeOS R4.5 and later + // "mints a new, reserved, change tag." + // "Call ApplyChangeTag() to apply it to the node" + // not supported, only for binary compatibility + return 0; +} + + +status_t +BMediaNode::ApplyChangeTag(int32 previously_reserved) +{ + UNIMPLEMENTED(); + // Only present in BeOS R4 + // Obsoleted in BeOS R4.5 and later + // "this returns B_OK if the new change tag is" + // "successfully applied, or B_MEDIA_STALE_CHANGE_TAG if the new change" + // "count you tried to apply is already obsolete." + // not supported, only for binary compatibility + return B_OK; +} + +/************************************************************* + * protected BMediaNode + *************************************************************/ + +/* virtual */ status_t +BMediaNode::DeleteHook(BMediaNode *node) +{ + CALLED(); + delete this; // delete "this" or "node" ??? + return B_OK; +} + + +/* virtual */ void +BMediaNode::NodeRegistered() +{ + CALLED(); + // The Media Server calls this hook function after the node has been registered. + // May be overriden by derived classes. +} + +/************************************************************* + * public BMediaNode + *************************************************************/ + +/* virtual */ status_t +BMediaNode::GetNodeAttributes(media_node_attribute *outAttributes, + size_t inMaxCount) +{ + UNIMPLEMENTED(); + + return B_ERROR; +} + + +/* virtual */ status_t +BMediaNode::AddTimer(bigtime_t at_performance_time, + int32 cookie) +{ + UNIMPLEMENTED(); + + return B_ERROR; +} + + +status_t BMediaNode::_Reserved_MediaNode_0(void *) { return B_ERROR; } +status_t BMediaNode::_Reserved_MediaNode_1(void *) { return B_ERROR; } +status_t BMediaNode::_Reserved_MediaNode_2(void *) { return B_ERROR; } +status_t BMediaNode::_Reserved_MediaNode_3(void *) { return B_ERROR; } +status_t BMediaNode::_Reserved_MediaNode_4(void *) { return B_ERROR; } +status_t BMediaNode::_Reserved_MediaNode_5(void *) { return B_ERROR; } +status_t BMediaNode::_Reserved_MediaNode_6(void *) { return B_ERROR; } +status_t BMediaNode::_Reserved_MediaNode_7(void *) { return B_ERROR; } +status_t BMediaNode::_Reserved_MediaNode_8(void *) { return B_ERROR; } +status_t BMediaNode::_Reserved_MediaNode_9(void *) { return B_ERROR; } +status_t BMediaNode::_Reserved_MediaNode_10(void *) { return B_ERROR; } +status_t BMediaNode::_Reserved_MediaNode_11(void *) { return B_ERROR; } +status_t BMediaNode::_Reserved_MediaNode_12(void *) { return B_ERROR; } +status_t BMediaNode::_Reserved_MediaNode_13(void *) { return B_ERROR; } +status_t BMediaNode::_Reserved_MediaNode_14(void *) { return B_ERROR; } +status_t BMediaNode::_Reserved_MediaNode_15(void *) { return B_ERROR; } + +/* +private unimplemented +BMediaNode::BMediaNode() +BMediaNode::BMediaNode(const BMediaNode &clone) +BMediaNode &BMediaNode::operator=(const BMediaNode &clone) +*/ + +BMediaNode::BMediaNode(const char *name, + media_node_id id, + uint32 kinds) : + fNodeID(id), + fTimeSource(0), + fRefCount(1), + fRunMode(B_INCREASE_LATENCY), + fKinds(kinds), + fTimeSourceID(0), + fControlPort(-1) +{ + CALLED(); + + // initialize node name + fName[0] = 0; + if (name) { + strncpy(fName,name,B_MEDIA_NAME_LENGTH - 1); + fName[B_MEDIA_NAME_LENGTH - 1] = 0; + } + TRACE("Media node name is: %s\n",fName); + + // create control port + fControlPort = create_port(64,fName); +} + + +/************************************************************* + * protected BMediaNode + *************************************************************/ + +/* static */ int32 +BMediaNode::NewChangeTag() +{ + CALLED(); + // change tags have been used in BeOS R4 to match up + // format change requests between producer and consumer, + // This has changed starting with R4.5 + // now "change tags" are used with + // BMediaNode::RequestCompleted() + // and + // BBufferConsumer::RequestFormatChange() + // BBufferConsumer::SetOutputBuffersFor() + // BBufferConsumer::SetOutputEnabled() + // BBufferConsumer::SetVideoClippingFor() + return atomic_add(&BMediaNode::_m_changeTag,1); +} + + diff --git a/src/kits/media/MediaRoster.cpp b/src/kits/media/MediaRoster.cpp new file mode 100644 index 0000000000..09ba5b0ac4 --- /dev/null +++ b/src/kits/media/MediaRoster.cpp @@ -0,0 +1,1500 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: MediaRoster.cpp + * DESCR: + ***********************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#undef DEBUG +#define DEBUG 3 +#include "debug.h" +#include "PortPool.h" +#include "../server/headers/ServerInterface.h" + +static BMessenger *ServerMessenger = 0; +static team_id team; + +// the BMediaRoster destructor is private, +// but _DefaultDeleter is a friend class of +// the BMediaRoster an thus can delete it +class _DefaultDeleter +{ +public: + void Delete() { delete BMediaRoster::_sDefault; } +}; + + +namespace MediaKitPrivate +{ + +class RosterSingleton +{ +public: + RosterSingleton() + { + thread_info info; + get_thread_info(find_thread(NULL), &info); + team = info.team; + ServerMessenger = new BMessenger(NEW_MEDIA_SERVER_SIGNATURE); + } + ~RosterSingleton() + { + _DefaultDeleter deleter; + deleter.Delete(); // deletes BMediaRoster::_sDefault + delete ServerMessenger; + } +}; + +RosterSingleton singleton; + + +status_t GetNode(node_type type, media_node * out_node, int32 * out_input_id = NULL, BString * out_input_name = NULL); +status_t SetNode(node_type type, const media_node *node, const dormant_node_info *info = NULL, const media_input *input = NULL); + +status_t QueryServer(BMessage *query, BMessage *reply) +{ + status_t status; + status = ServerMessenger->SendMessage(query,reply); + if (status != B_OK || reply->what != B_OK) { + TRACE("QueryServer failed! status = 0x%08lx\n",status); + TRACE("Query:\n"); + query->PrintToStream(); + TRACE("Reply:\n"); + reply->PrintToStream(); + } + return status; +} + +status_t GetNode(node_type type, media_node * out_node, int32 * out_input_id, BString * out_input_name) +{ + if (out_node == NULL) + return B_BAD_VALUE; + + xfer_server_get_node msg; + xfer_server_get_node_reply reply; + port_id port; + status_t rv; + int32 code; + + port = find_port("media_server port"); + if (port <= B_OK) + return B_ERROR; + + msg.type = type; + msg.reply_port = _PortPool->GetPort(); + rv = write_port(port, SERVER_GET_NODE, &msg, sizeof(msg)); + if (rv != B_OK) { + _PortPool->PutPort(msg.reply_port); + return rv; + } + rv = read_port(msg.reply_port, &code, &reply, sizeof(reply)); + _PortPool->PutPort(msg.reply_port); + if (rv < B_OK) + return rv; + *out_node = reply.node; + if (out_input_id) + *out_input_id = reply.input_id; + if (out_input_name) + *out_input_name = reply.input_name; + return reply.result; +} + +status_t SetNode(node_type type, const media_node *node, const dormant_node_info *info, const media_input *input) +{ + xfer_server_set_node msg; + xfer_server_set_node_reply reply; + port_id port; + status_t rv; + int32 code; + + port = find_port("media_server port"); + if (port <= B_OK) + return B_ERROR; + + msg.type = type; + msg.use_node = node ? true : false; + if (node) + msg.node = *node; + msg.use_dni = info ? true : false; + if (info) + msg.dni = *info; + msg.use_input = input ? true : false; + if (input) + msg.input = *input; + msg.reply_port = _PortPool->GetPort(); + rv = write_port(port, SERVER_SET_NODE, &msg, sizeof(msg)); + if (rv != B_OK) { + _PortPool->PutPort(msg.reply_port); + return rv; + } + rv = read_port(msg.reply_port, &code, &reply, sizeof(reply)); + _PortPool->PutPort(msg.reply_port); + + return (rv < B_OK) ? rv : reply.result; +} + +}; + +/************************************************************* + * public BMediaRoster + *************************************************************/ + +status_t +BMediaRoster::GetVideoInput(media_node * out_node) +{ + CALLED(); + return MediaKitPrivate::GetNode(VIDEO_INPUT, out_node); +} + + +status_t +BMediaRoster::GetAudioInput(media_node * out_node) +{ + CALLED(); + return MediaKitPrivate::GetNode(AUDIO_INPUT, out_node); +} + + +status_t +BMediaRoster::GetVideoOutput(media_node * out_node) +{ + CALLED(); + return MediaKitPrivate::GetNode(VIDEO_OUTPUT, out_node); +} + + +status_t +BMediaRoster::GetAudioMixer(media_node * out_node) +{ + CALLED(); + return MediaKitPrivate::GetNode(AUDIO_MIXER, out_node); +} + + +status_t +BMediaRoster::GetAudioOutput(media_node * out_node) +{ + CALLED(); + return MediaKitPrivate::GetNode(AUDIO_OUTPUT, out_node); +} + + +status_t +BMediaRoster::GetAudioOutput(media_node * out_node, + int32 * out_input_id, + BString * out_input_name) +{ + CALLED(); + return MediaKitPrivate::GetNode(AUDIO_OUTPUT_EX, out_node, out_input_id, out_input_name); +} + + +status_t +BMediaRoster::GetTimeSource(media_node * out_node) +{ + CALLED(); + return MediaKitPrivate::GetNode(TIME_SOURCE, out_node); +} + + +status_t +BMediaRoster::SetVideoInput(const media_node & producer) +{ + CALLED(); + return MediaKitPrivate::SetNode(VIDEO_INPUT, &producer); +} + + +status_t +BMediaRoster::SetVideoInput(const dormant_node_info & producer) +{ + CALLED(); + return MediaKitPrivate::SetNode(VIDEO_INPUT, NULL, &producer); +} + + +status_t +BMediaRoster::SetAudioInput(const media_node & producer) +{ + CALLED(); + return MediaKitPrivate::SetNode(AUDIO_INPUT, &producer); +} + + +status_t +BMediaRoster::SetAudioInput(const dormant_node_info & producer) +{ + CALLED(); + return MediaKitPrivate::SetNode(AUDIO_INPUT, NULL, &producer); +} + + +status_t +BMediaRoster::SetVideoOutput(const media_node & consumer) +{ + CALLED(); + return MediaKitPrivate::SetNode(VIDEO_OUTPUT, &consumer); +} + + +status_t +BMediaRoster::SetVideoOutput(const dormant_node_info & consumer) +{ + CALLED(); + return MediaKitPrivate::SetNode(VIDEO_OUTPUT, NULL, &consumer); +} + + +status_t +BMediaRoster::SetAudioOutput(const media_node & consumer) +{ + CALLED(); + return MediaKitPrivate::SetNode(AUDIO_OUTPUT, &consumer); +} + + +status_t +BMediaRoster::SetAudioOutput(const media_input & input_to_output) +{ + CALLED(); + return MediaKitPrivate::SetNode(AUDIO_OUTPUT, NULL, NULL, &input_to_output); +} + + +status_t +BMediaRoster::SetAudioOutput(const dormant_node_info & consumer) +{ + CALLED(); + return MediaKitPrivate::SetNode(AUDIO_OUTPUT, NULL, &consumer); +} + + +status_t +BMediaRoster::GetNodeFor(media_node_id node, + media_node * clone) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::GetSystemTimeSource(media_node * clone) +{ + CALLED(); + return MediaKitPrivate::GetNode(SYSTEM_TIME_SOURCE, clone); +} + + +status_t +BMediaRoster::ReleaseNode(const media_node & node) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + + +BTimeSource * +BMediaRoster::MakeTimeSourceFor(const media_node & for_node) +{ + UNIMPLEMENTED(); + return 0; +} + + +status_t +BMediaRoster::Connect(const media_source & from, + const media_destination & to, + media_format * io_format, + media_output * out_output, + media_input * out_input) +{ + CALLED(); + if (io_format == NULL || out_output == NULL || out_input == NULL) + return B_BAD_VALUE; + if (from == media_source::null) + return B_MEDIA_BAD_SOURCE; + if (to == media_destination::null) + return B_MEDIA_BAD_DESTINATION; + + xfer_producer_format_proposal msg1; + xfer_producer_format_proposal_reply reply1; + xfer_consumer_accept_format msg2; + xfer_consumer_accept_format_reply reply2; + xfer_producer_prepare_to_connect msg3; + xfer_producer_prepare_to_connect_reply reply3; + xfer_consumer_connected msg4; + xfer_consumer_connected_reply reply4; + xfer_producer_connect msg5; + xfer_producer_connect_reply reply5; + status_t rv; + port_id port; + int32 code; + + port = _PortPool->GetPort(); + + // BBufferProducer::FormatProposal + msg1.output = from; + msg1.format = *io_format; + msg1.reply_port = port; + rv = write_port(from.port, PRODUCER_FORMAT_PROPOSAL, &msg1, sizeof(msg1)); + if (rv != B_OK) + goto failed; + rv = read_port(port, &code, &reply1, sizeof(reply1)); + if (rv < B_OK) + goto failed; + if (reply1.result != B_OK) { + rv = reply1.result; + goto failed; + } + + // BBufferConsumer::AcceptFormat + msg2.dest = to; + msg2.format = *io_format; + msg2.reply_port = port; + rv = write_port(to.port, CONSUMER_ACCEPT_FORMAT, &msg2, sizeof(msg2)); + if (rv != B_OK) + goto failed; + rv = read_port(port, &code, &reply2, sizeof(reply2)); + if (rv < B_OK) + goto failed; + if (reply2.result != B_OK) { + rv = reply2.result; + goto failed; + } + *io_format = reply2.format; + + // BBufferProducer::PrepareToConnect + msg3.source = from; + msg3.destination = to; + msg3.format = *io_format; + msg3.reply_port = port; + rv = write_port(from.port, PRODUCER_PREPARE_TO_CONNECT, &msg3, sizeof(msg3)); + if (rv != B_OK) + goto failed; + rv = read_port(port, &code, &reply3, sizeof(reply3)); + if (rv < B_OK) + goto failed; + if (reply3.result != B_OK) { + rv = reply3.result; + goto failed; + } + *io_format = reply3.format; + //reply3.out_source; + //reply3.name; + + // BBufferConsumer::Connected + msg4.producer = reply3.out_source; + msg4.where = to; + msg4.with_format = *io_format; + msg4.reply_port = port; + rv = write_port(to.port, CONSUMER_CONNECTED, &msg4, sizeof(msg4)); + if (rv != B_OK) + goto failed; + rv = read_port(port, &code, &reply4, sizeof(reply4)); + if (rv < B_OK) + goto failed; + if (reply4.result != B_OK) { + rv = reply4.result; + goto failed; + } + // reply4.input; + + // BBufferProducer::Connect + msg5.error = B_OK; + msg5.source = reply3.out_source; + msg5.destination = to; + msg5.format = *io_format; + msg5.name[0] = 0; + msg5.reply_port = port; + + rv = write_port(from.port, PRODUCER_CONNECT, &msg5, sizeof(msg5)); + if (rv != B_OK) + goto failed; + rv = read_port(port, &code, &reply5, sizeof(reply5)); + if (rv < B_OK) + goto failed; + +// out_output->node = + out_output->source = reply3.out_source; + out_output->destination = to;//reply4.input; + out_output->format = *io_format; + strcpy(out_output->name,reply5.name); + +// out_input->node + out_input->source = reply3.out_source; + out_input->destination = to;//reply4.input; + out_input->format = *io_format; + strcpy(out_input->name,reply3.name); + + _PortPool->PutPort(port); + return B_OK; + +failed: + _PortPool->PutPort(port); + return rv; +} + + +status_t +BMediaRoster::Connect(const media_source & from, + const media_destination & to, + media_format * io_format, + media_output * out_output, + media_input * out_input, + uint32 in_flags, + void * _reserved) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::Disconnect(media_node_id source_node, + const media_source & source, + media_node_id destination_node, + const media_destination & destination) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::StartNode(const media_node & node, + bigtime_t at_performance_time) +{ + CALLED(); + if (node.node == 0) + return B_MEDIA_BAD_NODE; + + xfer_node_start msg; + msg.performance_time = at_performance_time; + + return write_port(node.port, NODE_START, &msg, sizeof(msg)); +} + + +status_t +BMediaRoster::StopNode(const media_node & node, + bigtime_t at_performance_time, + bool immediate) +{ + CALLED(); + if (node.node == 0) + return B_MEDIA_BAD_NODE; + + xfer_node_stop msg; + msg.performance_time = at_performance_time; + msg.immediate = immediate; + + return write_port(node.port, NODE_STOP, &msg, sizeof(msg)); +} + + +status_t +BMediaRoster::SeekNode(const media_node & node, + bigtime_t to_media_time, + bigtime_t at_performance_time) +{ + CALLED(); + if (node.node == 0) + return B_MEDIA_BAD_NODE; + + xfer_node_seek msg; + msg.media_time = to_media_time; + msg.performance_time = at_performance_time; + + return write_port(node.port, NODE_SEEK, &msg, sizeof(msg)); +} + + +status_t +BMediaRoster::StartTimeSource(const media_node & node, + bigtime_t at_real_time) +{ + CALLED(); + if (node.node == 0) + return B_MEDIA_BAD_NODE; + if ((node.kind & B_TIME_SOURCE) == 0) + return B_MEDIA_BAD_NODE; + + BTimeSource::time_source_op_info msg; + msg.op = BTimeSource::B_TIMESOURCE_START; + msg.real_time = at_real_time; + + return write_port(node.port, TIMESOURCE_OP, &msg, sizeof(msg)); +} + + +status_t +BMediaRoster::StopTimeSource(const media_node & node, + bigtime_t at_real_time, + bool immediate) +{ + CALLED(); + if (node.node == 0) + return B_MEDIA_BAD_NODE; + if ((node.kind & B_TIME_SOURCE) == 0) + return B_MEDIA_BAD_NODE; + + BTimeSource::time_source_op_info msg; + msg.op = immediate ? BTimeSource::B_TIMESOURCE_STOP_IMMEDIATELY : BTimeSource::B_TIMESOURCE_STOP; + msg.real_time = at_real_time; + + return write_port(node.port, TIMESOURCE_OP, &msg, sizeof(msg)); +} + + +status_t +BMediaRoster::SeekTimeSource(const media_node & node, + bigtime_t to_performance_time, + bigtime_t at_real_time) +{ + CALLED(); + if (node.node == 0) + return B_MEDIA_BAD_NODE; + if ((node.kind & B_TIME_SOURCE) == 0) + return B_MEDIA_BAD_NODE; + + BTimeSource::time_source_op_info msg; + msg.op = BTimeSource::B_TIMESOURCE_SEEK; + msg.real_time = at_real_time; + msg.performance_time = to_performance_time; + + return write_port(node.port, TIMESOURCE_OP, &msg, sizeof(msg)); +} + + +status_t +BMediaRoster::SyncToNode(const media_node & node, + bigtime_t at_time, + bigtime_t timeout) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::SetRunModeNode(const media_node & node, + BMediaNode::run_mode mode) +{ + CALLED(); + if (node.node == 0) + return B_MEDIA_BAD_NODE; + + xfer_node_set_run_mode msg; + msg.mode = mode; + + return write_port(node.port, NODE_SET_RUN_MODE, &msg, sizeof(msg)); +} + + +status_t +BMediaRoster::PrerollNode(const media_node & node) +{ + CALLED(); + if (node.node == 0) + return B_MEDIA_BAD_NODE; + + char dummy; + return write_port(node.port, NODE_PREROLL, &dummy, sizeof(dummy)); +} + + +status_t +BMediaRoster::RollNode(const media_node & node, + bigtime_t startPerformance, + bigtime_t stopPerformance, + bigtime_t atMediaTime) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::SetProducerRunModeDelay(const media_node & node, + bigtime_t delay, + BMediaNode::run_mode mode) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::SetProducerRate(const media_node & producer, + int32 numer, + int32 denom) +{ + CALLED(); + if (producer.node == 0) + return B_MEDIA_BAD_NODE; + if ((producer.kind & B_BUFFER_PRODUCER) == 0) + return B_MEDIA_BAD_NODE; + + xfer_producer_set_play_rate msg; + xfer_producer_set_play_rate_reply reply; + status_t rv; + int32 code; + + msg.numer = numer; + msg.denom = denom; + msg.reply_port = _PortPool->GetPort(); + rv = write_port(producer.node, PRODUCER_SET_PLAY_RATE, &msg, sizeof(msg)); + if (rv != B_OK) { + _PortPool->PutPort(msg.reply_port); + return rv; + } + rv = read_port(msg.reply_port, &code, &reply, sizeof(reply)); + _PortPool->PutPort(msg.reply_port); + return (rv < B_OK) ? rv : reply.result; +} + + + +/* Nodes will have available inputs/outputs as long as they are capable */ +/* of accepting more connections. The node may create an additional */ +/* output or input as the currently available is taken into usage. */ +status_t +BMediaRoster::GetLiveNodeInfo(const media_node & node, + live_node_info * out_live_info) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::GetLiveNodes(live_node_info * out_live_nodes, + int32 * io_total_count, + const media_format * has_input, + const media_format * has_output, + const char * name, + uint64 node_kinds) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::GetFreeInputsFor(const media_node & node, + media_input * out_free_inputs, + int32 buf_num_inputs, + int32 * out_total_count, + media_type filter_type) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::GetConnectedInputsFor(const media_node & node, + media_input * out_active_inputs, + int32 buf_num_inputs, + int32 * out_total_count) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::GetAllInputsFor(const media_node & node, + media_input * out_inputs, + int32 buf_num_inputs, + int32 * out_total_count) +{ + CALLED(); + if (node.node == 0 || (node.kind & B_BUFFER_CONSUMER) == 0) + return B_MEDIA_BAD_NODE; + if (out_inputs == NULL || out_total_count == NULL) + return B_BAD_VALUE; + + status_t rv; + status_t rv2; + port_id port; + int32 code; + int32 cookie; + + port = _PortPool->GetPort(); + *out_total_count = 0; + cookie = 0; + for (int32 i = 0; i < buf_num_inputs; i++) { + xfer_consumer_get_next_input msg; + xfer_consumer_get_next_input_reply reply; + msg.cookie = cookie; + msg.reply_port = port; + rv = write_port(node.port, CONSUMER_GET_NEXT_INPUT, &msg, sizeof(msg)); + if (rv != B_OK) + break; + rv = read_port(msg.reply_port, &code, &reply, sizeof(reply)); + if (rv < B_OK || reply.result != B_OK) + break; + *out_total_count += 1; + out_inputs[i] = reply.input; + cookie = reply.cookie; + } + _PortPool->PutPort(port); + + xfer_consumer_dispose_input_cookie msg2; + msg2.cookie = cookie; + rv2 = write_port(node.port, CONSUMER_DISPOSE_INPUT_COOKIE, &msg2, sizeof(msg2)); + + return (rv < B_OK) ? rv : rv2; +} + + +status_t +BMediaRoster::GetFreeOutputsFor(const media_node & node, + media_output * out_free_outputs, + int32 buf_num_outputs, + int32 * out_total_count, + media_type filter_type) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::GetConnectedOutputsFor(const media_node & node, + media_output * out_active_outputs, + int32 buf_num_outputs, + int32 * out_total_count) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::GetAllOutputsFor(const media_node & node, + media_output * out_outputs, + int32 buf_num_outputs, + int32 * out_total_count) +{ + CALLED(); + if (node.node == 0 || (node.kind & B_BUFFER_PRODUCER) == 0) + return B_MEDIA_BAD_NODE; + if (out_outputs == NULL || out_total_count == NULL) + return B_BAD_VALUE; + + status_t rv; + status_t rv2; + port_id port; + int32 code; + int32 cookie; + + port = _PortPool->GetPort(); + *out_total_count = 0; + cookie = 0; + for (int32 i = 0; i < buf_num_outputs; i++) { + xfer_producer_get_next_output msg; + xfer_producer_get_next_output_reply reply; + msg.cookie = cookie; + msg.reply_port = port; + rv = write_port(node.port, PRODUCER_GET_NEXT_OUTPUT, &msg, sizeof(msg)); + if (rv != B_OK) + break; + rv = read_port(msg.reply_port, &code, &reply, sizeof(reply)); + if (rv < B_OK || reply.result != B_OK) + break; + *out_total_count += 1; + out_outputs[i] = reply.output; + cookie = reply.cookie; + } + _PortPool->PutPort(port); + + xfer_producer_dispose_output_cookie msg2; + msg2.cookie = cookie; + rv2 = write_port(node.port, PRODUCER_DISPOSE_OUTPUT_COOKIE, &msg2, sizeof(msg2)); + + return (rv < B_OK) ? rv : rv2; +} + + +status_t +BMediaRoster::StartWatching(const BMessenger & where) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::StartWatching(const BMessenger & where, + int32 notificationType) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::StartWatching(const BMessenger & where, + const media_node & node, + int32 notificationType) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::StopWatching(const BMessenger & where) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::StopWatching(const BMessenger & where, + int32 notificationType) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::StopWatching(const BMessenger & where, + const media_node & node, + int32 notificationType) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::RegisterNode(BMediaNode * node) +{ + CALLED(); + if (node == NULL) + return B_BAD_VALUE; + + xfer_node_registered msg; + msg.node_id = 1; + + return node->HandleMessage(NODE_REGISTERED,&msg,sizeof(msg)); +} + + +status_t +BMediaRoster::UnregisterNode(BMediaNode * node) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +// thread safe for multiple calls to Roster() +/* static */ BMediaRoster * +BMediaRoster::Roster(status_t* out_error) +{ + CALLED(); + static BLocker locker("BMediaRoster::Roster locker"); + locker.Lock(); + if (_sDefault == NULL) { + _sDefault = new BMediaRoster(); + if (out_error != NULL) + *out_error = B_OK; + } else { + if (out_error != NULL) + *out_error = B_OK; + } + locker.Unlock(); + return _sDefault; +} + + +// won't create it if there isn't one +// not thread safe if you call Roster() at the same time +/* static */ BMediaRoster * +BMediaRoster::CurrentRoster() +{ + CALLED(); + return _sDefault; +} + + +status_t +BMediaRoster::SetTimeSourceFor(media_node_id node, + media_node_id time_source) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::GetParameterWebFor(const media_node & node, + BParameterWeb ** out_web) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::StartControlPanel(const media_node & node, + BMessenger * out_messenger) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::GetDormantNodes(dormant_node_info * out_info, + int32 * io_count, + const media_format * has_input /* = NULL */, + const media_format * has_output /* = NULL */, + const char * name /* = NULL */, + uint64 require_kinds /* = NULL */, + uint64 deny_kinds /* = NULL */) +{ + CALLED(); + if (out_info == NULL) + return B_BAD_VALUE; + if (io_count == NULL) + return B_BAD_VALUE; + if (*io_count <= 0) + return B_BAD_VALUE; + + xfer_server_get_dormant_nodes msg; + port_id port; + status_t rv; + + port = find_port("media_server port"); + if (port <= B_OK) + return B_ERROR; + + msg.maxcount = *io_count; + msg.has_input = (bool) has_input; + if (has_input) + msg.inputformat = *has_input; // XXX we should not make a flat copy of media_format + msg.has_output = (bool) has_output; + if (has_output) + msg.outputformat = *has_output;; // XXX we should not make a flat copy of media_format + msg.has_name = (bool) name; + if (name) { + int len = min_c(strlen(name),sizeof(msg.name) - 1); + memcpy(msg.name,name,len); + msg.name[len] = 0; + } + msg.require_kinds = require_kinds; + msg.deny_kinds = deny_kinds; + msg.reply_port = _PortPool->GetPort(); + + rv = write_port(port, SERVER_GET_DORMANT_NODES, &msg, sizeof(msg)); + if (rv != B_OK) { + _PortPool->PutPort(msg.reply_port); + return rv; + } + + xfer_server_get_dormant_nodes_reply reply; + int32 code; + + rv = read_port(msg.reply_port, &code, &reply, sizeof(reply)); + if (rv < B_OK) { + _PortPool->PutPort(msg.reply_port); + return rv; + } + + *io_count = reply.count; + + if (*io_count > 0) { + rv = read_port(msg.reply_port, &code, out_info, *io_count * sizeof(dormant_node_info)); + if (rv < B_OK) + reply.result = rv; + } + _PortPool->PutPort(msg.reply_port); + + return reply.result; +} + + +status_t +BMediaRoster::InstantiateDormantNode(const dormant_node_info & in_info, + media_node * out_node, + uint32 flags /* currently B_FLAVOR_IS_GLOBAL or B_FLAVOR_IS_LOCAL */ ) +{ + CALLED(); + if ((flags & (B_FLAVOR_IS_GLOBAL | B_FLAVOR_IS_LOCAL)) == 0) { + printf("Error: BMediaRoster::InstantiateDormantNode called without flags\n"); + return B_BAD_VALUE; + } + if (out_node == 0) + return B_BAD_VALUE; + + // XXX we should not trust the values passed in by the user, + // XXX and ask the server to determine where to insta + + if ((in_info.flavor_flags & B_FLAVOR_IS_GLOBAL) == 0 && (flags & B_FLAVOR_IS_LOCAL)) { + return InstantiateDormantNode(in_info,out_node); + } + + if ((in_info.flavor_flags & B_FLAVOR_IS_GLOBAL) || (flags & B_FLAVOR_IS_GLOBAL)) { + // forward this request into the media_addon_server, + // which in turn will call InstantiateDormantNode() + // to create it there localy + xfer_addonserver_instantiate_dormant_node msg; + xfer_addonserver_instantiate_dormant_node_reply reply; + port_id port; + status_t rv; + int32 code; + port = find_port("media_addon_server port"); + if (port <= B_OK) + return B_ERROR; + msg.info = in_info; + msg.reply_port = _PortPool->GetPort(); + rv = write_port(port, ADDONSERVER_INSTANTIATE_DORMANT_NODE, &msg, sizeof(msg)); + if (rv != B_OK) { + _PortPool->PutPort(msg.reply_port); + return rv; + } + rv = read_port(msg.reply_port, &code, &reply, sizeof(reply)); + _PortPool->PutPort(msg.reply_port); + if (rv < B_OK) + return rv; + *out_node = reply.node; + return reply.result; + } + + printf("Error: BMediaRoster::InstantiateDormantNode in_info.flavor_flags = %#08lx, flags = %#08lx\n", in_info.flavor_flags, flags); + + return B_ERROR; +} + + +status_t +BMediaRoster::InstantiateDormantNode(const dormant_node_info & in_info, + media_node * out_node) +{ + UNIMPLEMENTED(); + in_info + + // to instantiate a dormant node in the current address space, we need to + // either load the add-on from file and create a new BMediaAddOn class, or + // reuse the cached BMediaAddOn from a previous call + // call BMediaAddOn::InstantiateNodeFor() + // and cache the BMediaAddOn after that for later reuse. + // BeOS R5 does not seem to delete it when the application quits + // if B_FLAVOR_IS_GLOBAL, we need to use the BMediaAddOn object that + // resides in the media_addon_server + + // RegisterNode() is called automatically for nodes instantiated from add-ons + + return B_ERROR; +} + + +status_t +BMediaRoster::GetDormantNodeFor(const media_node & node, + dormant_node_info * out_info) +{ + UNIMPLEMENTED(); + + return B_ERROR; +} + + +status_t +BMediaRoster::GetDormantFlavorInfoFor(const dormant_node_info & in_dormant, + dormant_flavor_info * out_flavor) +{ + CALLED(); + + xfer_server_get_dormant_flavor_info msg; + xfer_server_get_dormant_flavor_info_reply *reply; + port_id port; + status_t rv; + int32 code; + + port = find_port("media_server port"); + if (port <= B_OK) + return B_ERROR; + + reply = (xfer_server_get_dormant_flavor_info_reply *) malloc(16000); + if (reply == 0) + return B_ERROR; + + msg.addon = in_dormant.addon; + msg.flavor_id = in_dormant.flavor_id; + msg.reply_port = _PortPool->GetPort(); + rv = write_port(port, SERVER_GET_DORMANT_FLAVOR_INFO, &msg, sizeof(msg)); + if (rv != B_OK) { + free(reply); + _PortPool->PutPort(msg.reply_port); + return rv; + } + rv = read_port(msg.reply_port, &code, reply, 16000); + _PortPool->PutPort(msg.reply_port); + + if (rv < B_OK) { + free(reply); + return rv; + } + + if (reply->result == B_OK) + rv = out_flavor->Unflatten(reply->dfi_type, &reply->dfi, reply->dfi_size); + else + rv = reply->result; + + free(reply); + return rv; +} + + +status_t +BMediaRoster::GetLatencyFor(const media_node & producer, + bigtime_t * out_latency) +{ + UNIMPLEMENTED(); + *out_latency = 0; + return B_ERROR; +} + + +status_t +BMediaRoster::GetInitialLatencyFor(const media_node & producer, + bigtime_t * out_latency, + uint32 * out_flags) +{ + UNIMPLEMENTED(); + *out_latency = 0; + *out_flags = 0; + return B_ERROR; +} + + +status_t +BMediaRoster::GetStartLatencyFor(const media_node & time_source, + bigtime_t * out_latency) +{ + UNIMPLEMENTED(); + *out_latency = 0; + return B_ERROR; +} + + +status_t +BMediaRoster::GetFileFormatsFor(const media_node & file_interface, + media_file_format * out_formats, + int32 * io_num_infos) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::SetRefFor(const media_node & file_interface, + const entry_ref & file, + bool create_and_truncate, + bigtime_t * out_length) /* if create is false */ +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::GetRefFor(const media_node & node, + entry_ref * out_file, + BMimeType * mime_type) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::SniffRefFor(const media_node & file_interface, + const entry_ref & file, + BMimeType * mime_type, + float * out_capability) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +/* This is the generic "here's a file, now can someone please play it" interface */ +status_t +BMediaRoster::SniffRef(const entry_ref & file, + uint64 require_node_kinds, /* if you need an EntityInterface or BufferConsumer or something */ + dormant_node_info * out_node, + BMimeType * mime_type) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::GetDormantNodeForType(const BMimeType & type, + uint64 require_node_kinds, + dormant_node_info * out_node) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::GetReadFileFormatsFor(const dormant_node_info & in_node, + media_file_format * out_read_formats, + int32 in_read_count, + int32 * out_read_count) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::GetWriteFileFormatsFor(const dormant_node_info & in_node, + media_file_format * out_write_formats, + int32 in_write_count, + int32 * out_write_count) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::GetFormatFor(const media_output & output, + media_format * io_format, + uint32 flags) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::GetFormatFor(const media_input & input, + media_format * io_format, + uint32 flags) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::GetFormatFor(const media_node & node, + media_format * io_format, + float quality) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +ssize_t +BMediaRoster::GetNodeAttributesFor(const media_node & node, + media_node_attribute * outArray, + size_t inMaxCount) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +media_node_id +BMediaRoster::NodeIDFor(port_id source_or_destination_port) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::GetInstancesFor(media_addon_id addon, + int32 flavor, + media_node_id * out_id, + int32 * io_count) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + + +status_t +BMediaRoster::SetRealtimeFlags(uint32 in_enabled) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +status_t +BMediaRoster::GetRealtimeFlags(uint32 * out_enabled) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +ssize_t +BMediaRoster::AudioBufferSizeFor(int32 channel_count, + uint32 sample_format, + float frame_rate, + bus_type bus_kind) +{ + UNIMPLEMENTED(); + return 4096; +} + + +/* Use MediaFlags to inquire about specific features of the Media Kit. */ +/* Returns < 0 for "not present", positive size for output data size. */ +/* 0 means that the capability is present, but no data about it. */ +/* static */ ssize_t +BMediaRoster::MediaFlags(media_flags cap, + void * buf, + size_t maxSize) +{ + UNIMPLEMENTED(); + return 0; +} + + + +/* BLooper overrides */ +/* virtual */ void +BMediaRoster::MessageReceived(BMessage * message) +{ + UNIMPLEMENTED(); +} + +/* virtual */ bool +BMediaRoster::QuitRequested() +{ + UNIMPLEMENTED(); + return true; +} + +/* virtual */ BHandler * +BMediaRoster::ResolveSpecifier(BMessage *msg, + int32 index, + BMessage *specifier, + int32 form, + const char *property) +{ + UNIMPLEMENTED(); + return 0; +} + + +/* virtual */ status_t +BMediaRoster::GetSupportedSuites(BMessage *data) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +BMediaRoster::~BMediaRoster() +{ + CALLED(); + BMessage msg(MEDIA_SERVER_UNREGISTER_APP); + BMessage reply; + msg.AddInt32("team",team); + ServerMessenger->SendMessage(&msg,&reply); +} + + +/************************************************************* + * private BMediaRoster + *************************************************************/ + +// deprecated call +status_t +BMediaRoster::SetOutputBuffersFor(const media_source & output, + BBufferGroup * group, + bool will_reclaim ) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +/* FBC stuffing (Mmmh, Stuffing!) */ +status_t BMediaRoster::_Reserved_MediaRoster_0(void *) { return B_ERROR; } +status_t BMediaRoster::_Reserved_MediaRoster_1(void *) { return B_ERROR; } +status_t BMediaRoster::_Reserved_MediaRoster_2(void *) { return B_ERROR; } +status_t BMediaRoster::_Reserved_MediaRoster_3(void *) { return B_ERROR; } +status_t BMediaRoster::_Reserved_MediaRoster_4(void *) { return B_ERROR; } +status_t BMediaRoster::_Reserved_MediaRoster_5(void *) { return B_ERROR; } +status_t BMediaRoster::_Reserved_MediaRoster_6(void *) { return B_ERROR; } +status_t BMediaRoster::_Reserved_MediaRoster_7(void *) { return B_ERROR; } + + +BMediaRoster::BMediaRoster() : + BLooper("BMediaRoster looper",B_NORMAL_PRIORITY,B_LOOPER_PORT_DEFAULT_CAPACITY) +{ + CALLED(); + BMessage msg(MEDIA_SERVER_REGISTER_APP); + BMessage reply; + msg.AddInt32("team",team); + ServerMessenger->SendMessage(&msg,&reply); +} + +/* static */ status_t +BMediaRoster::ParseCommand(BMessage & reply) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + + +status_t +BMediaRoster::GetDefaultInfo(media_node_id for_default, + BMessage & out_config) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + + +status_t +BMediaRoster::SetRunningDefault(media_node_id for_default, + const media_node & node) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + + +/************************************************************* + * static BMediaRoster variables + *************************************************************/ + +bool BMediaRoster::_isMediaServer; +port_id BMediaRoster::_mReplyPort; +int32 BMediaRoster::_mReplyPortRes; +int32 BMediaRoster::_mReplyPortUnavailCount; +BMediaRoster * BMediaRoster::_sDefault = NULL; + diff --git a/src/kits/media/MediaTheme.cpp b/src/kits/media/MediaTheme.cpp new file mode 100644 index 0000000000..f5534c7c30 --- /dev/null +++ b/src/kits/media/MediaTheme.cpp @@ -0,0 +1,154 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: MediaTheme.cpp + * DESCR: + ***********************************************************************/ +#include +#include "debug.h" + +/************************************************************* + * public BMediaTheme + *************************************************************/ + +BMediaTheme::~BMediaTheme() +{ + UNIMPLEMENTED(); +} + + +const char * +BMediaTheme::Name() +{ + UNIMPLEMENTED(); + return ""; +} + + +const char * +BMediaTheme::Info() +{ + UNIMPLEMENTED(); + return ""; +} + + +int32 +BMediaTheme::ID() +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +bool +BMediaTheme::GetRef(entry_ref *out_ref) +{ + UNIMPLEMENTED(); + bool dummy; + + return dummy; +} + + +BView * +BMediaTheme::ViewFor(BParameterWeb *web, + const BRect *hintRect, + BMediaTheme *using_theme) +{ + UNIMPLEMENTED(); + return NULL; +} + + +status_t +BMediaTheme::SetPreferredTheme(BMediaTheme *default_theme) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +BMediaTheme * +BMediaTheme::PreferredTheme() +{ + UNIMPLEMENTED(); + return NULL; +} + + +BBitmap * +BMediaTheme::BackgroundBitmapFor(bg_kind bg) +{ + UNIMPLEMENTED(); + return NULL; +} + + +rgb_color +BMediaTheme::BackgroundColorFor(bg_kind bg) +{ + UNIMPLEMENTED(); + rgb_color dummy; + + return dummy; +} + + +rgb_color +BMediaTheme::ForegroundColorFor(fg_kind fg) +{ + UNIMPLEMENTED(); + rgb_color dummy; + + return dummy; +} + +/************************************************************* + * protected BMediaTheme + *************************************************************/ + +BMediaTheme::BMediaTheme(const char *name, + const char *info, + const entry_ref *add_on, + int32 theme_id) +{ + UNIMPLEMENTED(); +} + + +BControl * +BMediaTheme::MakeFallbackViewFor(BParameter *control) +{ + UNIMPLEMENTED(); + return NULL; +} + +/************************************************************* + * private BMediaTheme + *************************************************************/ + +/* +private unimplemented +BMediaTheme::BMediaTheme() +BMediaTheme::BMediaTheme(const BMediaTheme &clone) +BMediaTheme & BMediaTheme::operator=(const BMediaTheme &clone) +*/ + +status_t BMediaTheme::_Reserved_ControlTheme_0(void *) { return B_ERROR; } +status_t BMediaTheme::_Reserved_ControlTheme_1(void *) { return B_ERROR; } +status_t BMediaTheme::_Reserved_ControlTheme_2(void *) { return B_ERROR; } +status_t BMediaTheme::_Reserved_ControlTheme_3(void *) { return B_ERROR; } +status_t BMediaTheme::_Reserved_ControlTheme_4(void *) { return B_ERROR; } +status_t BMediaTheme::_Reserved_ControlTheme_5(void *) { return B_ERROR; } +status_t BMediaTheme::_Reserved_ControlTheme_6(void *) { return B_ERROR; } +status_t BMediaTheme::_Reserved_ControlTheme_7(void *) { return B_ERROR; } + +/************************************************************* + * static BMediaTheme variables + *************************************************************/ + +BMediaTheme * BMediaTheme::_mDefaultTheme; diff --git a/src/kits/media/MediaTrack.cpp b/src/kits/media/MediaTrack.cpp new file mode 100644 index 0000000000..6f7f90317e --- /dev/null +++ b/src/kits/media/MediaTrack.cpp @@ -0,0 +1,439 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: MediaTrack.cpp + * DESCR: + ***********************************************************************/ +#include +#include "debug.h" + +/************************************************************* + * protected BMediaTrack + *************************************************************/ + +BMediaTrack::~BMediaTrack() +{ + UNIMPLEMENTED(); +} + +/************************************************************* + * public BMediaTrack + *************************************************************/ + +status_t +BMediaTrack::InitCheck() const +{ + UNIMPLEMENTED(); + + return B_OK; +} + + +status_t +BMediaTrack::GetCodecInfo(media_codec_info *mci) const +{ + UNIMPLEMENTED(); + + return B_ERROR; +} + + +status_t +BMediaTrack::EncodedFormat(media_format *out_format) const +{ + UNIMPLEMENTED(); + + return B_OK; +} + + +status_t +BMediaTrack::DecodedFormat(media_format *inout_format) +{ + UNIMPLEMENTED(); + + return B_OK; +} + + +int64 +BMediaTrack::CountFrames() const +{ + UNIMPLEMENTED(); + + return 100000; +} + + +bigtime_t +BMediaTrack::Duration() const +{ + UNIMPLEMENTED(); + + return 1000000; +} + + +int64 +BMediaTrack::CurrentFrame() const +{ + UNIMPLEMENTED(); + + return 0; +} + + +bigtime_t +BMediaTrack::CurrentTime() const +{ + UNIMPLEMENTED(); + + return 0; +} + + +status_t +BMediaTrack::ReadFrames(void *out_buffer, + int64 *out_frameCount, + media_header *mh) +{ + UNIMPLEMENTED(); + + return B_OK; +} + + +status_t +BMediaTrack::ReadFrames(void *out_buffer, + int64 *out_frameCount, + media_header *mh, + media_decode_info *info) +{ + UNIMPLEMENTED(); + + return B_OK; +} + + +status_t +BMediaTrack::ReplaceFrames(const void *in_buffer, + int64 *io_frameCount, + const media_header *mh) +{ + UNIMPLEMENTED(); + + return B_OK; +} + + +status_t +BMediaTrack::SeekToTime(bigtime_t *inout_time, + int32 flags) +{ + UNIMPLEMENTED(); + + return B_OK; +} + + +status_t +BMediaTrack::SeekToFrame(int64 *inout_frame, + int32 flags) +{ + UNIMPLEMENTED(); + + return B_OK; +} + + +status_t +BMediaTrack::FindKeyFrameForTime(bigtime_t *inout_time, + int32 flags) const +{ + UNIMPLEMENTED(); + + return B_OK; +} + + +status_t +BMediaTrack::FindKeyFrameForFrame(int64 *inout_frame, + int32 flags) const +{ + UNIMPLEMENTED(); + + return B_OK; +} + + +status_t +BMediaTrack::ReadChunk(char **out_buffer, + int32 *out_size, + media_header *mh) +{ + UNIMPLEMENTED(); + + return B_OK; +} + + +status_t +BMediaTrack::AddCopyright(const char *data) +{ + UNIMPLEMENTED(); + + return B_OK; +} + + +status_t +BMediaTrack::AddTrackInfo(uint32 code, + const void *data, + size_t size, + uint32 flags) +{ + UNIMPLEMENTED(); + + return B_OK; +} + + +status_t +BMediaTrack::WriteFrames(const void *data, + int32 num_frames, + int32 flags) +{ + UNIMPLEMENTED(); + + return B_OK; +} + + +status_t +BMediaTrack::WriteFrames(const void *data, + int64 num_frames, + media_encode_info *info) +{ + UNIMPLEMENTED(); + + return B_OK; +} + + +status_t +BMediaTrack::WriteChunk(const void *data, + size_t size, + uint32 flags) +{ + UNIMPLEMENTED(); + + return B_OK; +} + + +status_t +BMediaTrack::WriteChunk(const void *data, + size_t size, + media_encode_info *info) +{ + UNIMPLEMENTED(); + + return B_OK; +} + + +status_t +BMediaTrack::Flush() +{ + UNIMPLEMENTED(); + + return B_OK; +} + + +BParameterWeb * +BMediaTrack::Web() +{ + UNIMPLEMENTED(); + return NULL; +} + + +status_t +BMediaTrack::GetParameterValue(int32 id, + void *valu, + size_t *size) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BMediaTrack::SetParameterValue(int32 id, + const void *valu, + size_t size) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +BView * +BMediaTrack::GetParameterView() +{ + UNIMPLEMENTED(); + return NULL; +} + + +status_t +BMediaTrack::GetQuality(float *quality) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BMediaTrack::SetQuality(float quality) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BMediaTrack::GetEncodeParameters(encode_parameters *parameters) const +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BMediaTrack::SetEncodeParameters(encode_parameters *parameters) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BMediaTrack::Perform(int32 selector, + void *data) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + +/************************************************************* + * private BMediaTrack + *************************************************************/ + +BMediaTrack::BMediaTrack(BPrivate::MediaExtractor *extractor, + int32 stream) +{ + UNIMPLEMENTED(); +} + + +BMediaTrack::BMediaTrack(BPrivate::MediaWriter *writer, + int32 stream_num, + media_format *in_format, + BPrivate::Encoder *encoder, + media_codec_info *mci) +{ + UNIMPLEMENTED(); +} + + +status_t +BMediaTrack::TrackInfo(media_format *out_format, + void **out_info, + int32 *out_infoSize) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + +/* +// unimplemented +BMediaTrack::BMediaTrack() +BMediaTrack::BMediaTrack(const BMediaTrack &) +BMediaTrack &BMediaTrack::operator=(const BMediaTrack &) +*/ + +BPrivate::Decoder * +BMediaTrack::find_decoder(BMediaTrack *track, + int32 *id) +{ + UNIMPLEMENTED(); + return NULL; +} + + +status_t BMediaTrack::_Reserved_BMediaTrack_0(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_1(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_2(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_3(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_4(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_5(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_6(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_7(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_8(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_9(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_10(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_11(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_12(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_13(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_14(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_15(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_16(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_17(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_18(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_19(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_20(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_21(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_22(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_23(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_24(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_25(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_26(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_27(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_28(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_29(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_30(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_31(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_32(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_33(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_34(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_35(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_36(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_37(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_38(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_39(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_40(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_41(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_42(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_43(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_44(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_45(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_46(int32 arg, ...) { return B_ERROR; } +status_t BMediaTrack::_Reserved_BMediaTrack_47(int32 arg, ...) { return B_ERROR; } + diff --git a/src/kits/media/OldAudioModule.cpp b/src/kits/media/OldAudioModule.cpp new file mode 100644 index 0000000000..b7dddb205c --- /dev/null +++ b/src/kits/media/OldAudioModule.cpp @@ -0,0 +1,462 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: OldAudioModule.cpp + * DESCR: + ***********************************************************************/ +#include +#include "debug.h" + +/************************************************************* + * public BAudioEvent + *************************************************************/ + +BAudioEvent::BAudioEvent(int32 frames, + bool stereo, + float *samples) +{ + UNIMPLEMENTED(); +} + + +BAudioEvent::~BAudioEvent() +{ + UNIMPLEMENTED(); +} + + +mk_time +BAudioEvent::Start() +{ + UNIMPLEMENTED(); + mk_time dummy; + + return dummy; +} + + +void +BAudioEvent::SetStart(mk_time) +{ + UNIMPLEMENTED(); +} + + +mk_time +BAudioEvent::Duration() +{ + UNIMPLEMENTED(); + mk_time dummy; + + return dummy; +} + + +int32 +BAudioEvent::Frames() +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +float * +BAudioEvent::Samples() +{ + UNIMPLEMENTED(); + return NULL; +} + + +int32 +BAudioEvent::ChannelCount() +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +float +BAudioEvent::Gain() +{ + UNIMPLEMENTED(); + float dummy; + + return dummy; +} + + +void +BAudioEvent::SetGain(float) +{ + UNIMPLEMENTED(); +} + + +int32 +BAudioEvent::Destination() +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +void +BAudioEvent::SetDestination(int32) +{ + UNIMPLEMENTED(); +} + + +bool +BAudioEvent::MixIn(float *dst, + int32 frames, + mk_time time) +{ + UNIMPLEMENTED(); + bool dummy; + + return dummy; +} + + +BMediaEvent * +BAudioEvent::Clone() +{ + UNIMPLEMENTED(); + return NULL; +} + + +bigtime_t +BAudioEvent::CaptureTime() +{ + UNIMPLEMENTED(); + bigtime_t dummy; + + return dummy; +} + + +void +BAudioEvent::SetCaptureTime(bigtime_t) +{ + UNIMPLEMENTED(); +} + + +/************************************************************* + * public BDACRenderer + *************************************************************/ + +BDACRenderer::BDACRenderer(const char *name) +{ + UNIMPLEMENTED(); +} + + +BDACRenderer::~BDACRenderer() +{ + UNIMPLEMENTED(); +} + + +mk_rate +BDACRenderer::Units() +{ + UNIMPLEMENTED(); + mk_rate dummy; + + return dummy; +} + + +mk_time +BDACRenderer::Latency() +{ + UNIMPLEMENTED(); + mk_time dummy; + + return dummy; +} + + +mk_time +BDACRenderer::Start() +{ + UNIMPLEMENTED(); + mk_time dummy; + + return dummy; +} + + +mk_time +BDACRenderer::Duration() +{ + UNIMPLEMENTED(); + mk_time dummy; + + return dummy; +} + + +BTimeBase * +BDACRenderer::TimeBase() +{ + UNIMPLEMENTED(); + return NULL; +} + + +void +BDACRenderer::Open() +{ + UNIMPLEMENTED(); +} + + +void +BDACRenderer::Close() +{ + UNIMPLEMENTED(); +} + + +void +BDACRenderer::Wakeup() +{ + UNIMPLEMENTED(); +} + + +void +BDACRenderer::TransportChanged(mk_time time, + mk_rate rate, + transport_status status) +{ + UNIMPLEMENTED(); +} + + +void +BDACRenderer::StreamChanged() +{ + UNIMPLEMENTED(); +} + + +BMediaChannel * +BDACRenderer::Channel() +{ + UNIMPLEMENTED(); + return NULL; +} + +/************************************************************* + * private BDACRenderer + *************************************************************/ + + +bool +BDACRenderer::_WriteDAC(void *arg, + char *buf, + uint32 bytes, + void *header) +{ + UNIMPLEMENTED(); + bool dummy; + + return dummy; +} + + +bool +BDACRenderer::WriteDAC(short *buf, + int32 frames, + audio_buffer_header *header) +{ + UNIMPLEMENTED(); + bool dummy; + + return dummy; +} + + +bool +BDACRenderer::MixActiveSegments(mk_time start) +{ + UNIMPLEMENTED(); + bool dummy; + + return dummy; +} + + +void +BDACRenderer::MixOutput(short *dst) +{ + UNIMPLEMENTED(); +} + + +/************************************************************* + * public BAudioFileStream + *************************************************************/ + +BAudioFileStream::BAudioFileStream(BMediaChannel *channel, + BFile *file, + mk_time start) +{ + UNIMPLEMENTED(); +} + + +BAudioFileStream::~BAudioFileStream() +{ + UNIMPLEMENTED(); +} + + +BMediaEvent * +BAudioFileStream::GetEvent(BMediaChannel *channel) +{ + UNIMPLEMENTED(); + return NULL; +} + + +BMediaEvent * +BAudioFileStream::PeekEvent(BMediaChannel *channel, + mk_time asap) +{ + UNIMPLEMENTED(); + return NULL; +} + + +status_t +BAudioFileStream::SeekToTime(BMediaChannel *channel, + mk_time time) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +void +BAudioFileStream::SetStart(mk_time start) +{ + UNIMPLEMENTED(); +} + + +bigtime_t +BAudioFileStream::CaptureTime() +{ + UNIMPLEMENTED(); + bigtime_t dummy; + + return dummy; +} + + +BMediaChannel * +BAudioFileStream::Channel() +{ + UNIMPLEMENTED(); + return NULL; +} + +/************************************************************* + * public BADCSource + *************************************************************/ + +BADCSource::BADCSource(BMediaChannel *channel, + mk_time start) +{ + UNIMPLEMENTED(); +} + + +BADCSource::~BADCSource() +{ + UNIMPLEMENTED(); +} + + +BMediaEvent * +BADCSource::GetEvent(BMediaChannel *channel) +{ + UNIMPLEMENTED(); + return NULL; +} + + +BMediaEvent * +BADCSource::PeekEvent(BMediaChannel *channel, + mk_time asap) +{ + UNIMPLEMENTED(); + return NULL; +} + + +status_t +BADCSource::SeekToTime(BMediaChannel *channel, + mk_time time) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +void +BADCSource::SetStart(mk_time start) +{ + UNIMPLEMENTED(); +} + + +BMediaChannel * +BADCSource::Channel() +{ + UNIMPLEMENTED(); + return NULL; +} + +/************************************************************* + * private BADCSource + *************************************************************/ + +bool +BADCSource::_ReadADC(void *arg, + char *buf, + uint32 bytes, + void *header) +{ + UNIMPLEMENTED(); + bool dummy; + + return dummy; +} + + +void +BADCSource::ReadADC(short *buf, + int32 frames, + audio_buffer_header *header) +{ + UNIMPLEMENTED(); +} + + diff --git a/src/kits/media/OldAudioModule.h b/src/kits/media/OldAudioModule.h new file mode 100644 index 0000000000..9ea2be7656 --- /dev/null +++ b/src/kits/media/OldAudioModule.h @@ -0,0 +1,142 @@ +/* ================ + + FILE: AudioModule.h + REVS: $Revision: 1.1 $ + NAME: marc + + Copyright (c) 1997 by Be Incorporated. All Rights Reserved. + +================ */ + +#ifndef _AUDIO_MODULE_H +#define _AUDIO_MODULE_H + +#include +#include +#include + +class BADCStream; +class BDACStream; +class BSubscriber; + +class BAudioEvent : public BMediaEvent { +public: + BAudioEvent(int32 frames, bool stereo, float* samples = NULL); + ~BAudioEvent(); + + virtual mk_time Start(); + virtual void SetStart(mk_time); + virtual mk_time Duration(); + virtual int32 Frames(); + virtual float* Samples(); + virtual int32 ChannelCount(); + virtual float Gain(); + virtual void SetGain(float); + virtual int32 Destination(); + virtual void SetDestination(int32); + virtual bool MixIn (float* dst, int32 frames, mk_time time); + virtual BMediaEvent* Clone(); + virtual bigtime_t CaptureTime(); + virtual void SetCaptureTime(bigtime_t); + +private: + mk_time fStart; + int32 fFrames; + float* fSamples; + float fGain; + int32 fDestination; + bigtime_t fCaptureTime; + bool fStereo; + bool fFreeHuey; +}; + + +class BDACRenderer : public BMediaRenderer { +public: + BDACRenderer(const char* name = NULL); + ~BDACRenderer(); + + mk_rate Units(); + mk_time Latency(); + mk_time Start(); + mk_time Duration(); + BTimeBase* TimeBase(); + void Open(); + void Close(); + void Wakeup(); + void TransportChanged(mk_time time, mk_rate rate, + transport_status status); + void StreamChanged(); + + virtual BMediaChannel* Channel(); + +private: + static bool _WriteDAC(void* arg, char* buf, uint32 bytes, void* header); + bool WriteDAC(short* buf, int32 frames, audio_buffer_header* header); + bool MixActiveSegments(mk_time start); + void MixOutput(short* dst); + + BMediaChannel* fChannel; + BDACStream* fDACStream; + BSubscriber* fSubscriber; + float* fBuffer; + int32 fBufferFrames; + BList fActiveSegments; + mk_time fLatency; + mk_time fNextTime; + bool fRunning; + BTimeBase fDACTimeBase; +}; + + +class BAudioFileStream : public BEventStream { +public: + BAudioFileStream(BMediaChannel* channel, BFile* file, + mk_time start = B_UNDEFINED_MK_TIME); + ~BAudioFileStream(); + + BMediaEvent* GetEvent(BMediaChannel* channel); + BMediaEvent* PeekEvent(BMediaChannel* channel, mk_time asap = 0); + status_t SeekToTime(BMediaChannel* channel, mk_time time); + void SetStart(mk_time start); + + virtual bigtime_t CaptureTime(); + virtual BMediaChannel* Channel(); + +private: + BMediaChannel* fChannel; + BFile* fFile; + mk_time fTime; + BAudioEvent* fCurrentEvent; + short* fBuffer; +}; + + +class BADCSource : public BEventStream { +public: + BADCSource(BMediaChannel* channel, mk_time start = 0); + ~BADCSource(); + + BMediaEvent* GetEvent(BMediaChannel* channel); + BMediaEvent* PeekEvent(BMediaChannel* channel, mk_time asap = 0); + status_t SeekToTime(BMediaChannel* channel, mk_time time); + void SetStart(mk_time start); + + virtual BMediaChannel* Channel(); + +private: + static bool _ReadADC(void* arg, char* buf, uint32 bytes, void* header); + void ReadADC(short* buf, int32 frames, audio_buffer_header* header); + + BMediaChannel* fChannel; + BFile* fFile; + mk_time fTime; + BAudioEvent* fCurrentEvent; + BAudioEvent* fNextEvent; + BLocker fEventLock; + BADCStream* fADCStream; + BSubscriber* fSubscriber; +}; + + +#endif diff --git a/src/kits/media/OldAudioStream.cpp b/src/kits/media/OldAudioStream.cpp new file mode 100644 index 0000000000..39a0391c72 --- /dev/null +++ b/src/kits/media/OldAudioStream.cpp @@ -0,0 +1,279 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: OldAudioStream.cpp + * DESCR: + ***********************************************************************/ +#include +#include "debug.h" + +/************************************************************* + * public BADCStream + *************************************************************/ + +BADCStream::BADCStream() +{ + UNIMPLEMENTED(); +} + + +BADCStream::~BADCStream() +{ + UNIMPLEMENTED(); +} + + +status_t +BADCStream::SetADCInput(int32 device) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BADCStream::ADCInput(int32 *device) const +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BADCStream::SetSamplingRate(float sRate) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BADCStream::SamplingRate(float *sRate) const +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BADCStream::BoostMic(bool boost) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +bool +BADCStream::IsMicBoosted() const +{ + UNIMPLEMENTED(); + bool dummy; + + return dummy; +} + + +status_t +BADCStream::SetStreamBuffers(size_t bufferSize, + int32 bufferCount) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + +/************************************************************* + * protected BADCStream + *************************************************************/ + + +BMessenger * +BADCStream::Server() const +{ + UNIMPLEMENTED(); + return NULL; +} + + +stream_id +BADCStream::StreamID() const +{ + UNIMPLEMENTED(); + stream_id dummy; + + return dummy; +} + +/************************************************************* + * private BADCStream + *************************************************************/ + + +void +BADCStream::_ReservedADCStream1() +{ + UNIMPLEMENTED(); +} + + +void +BADCStream::_ReservedADCStream2() +{ + UNIMPLEMENTED(); +} + + +void +BADCStream::_ReservedADCStream3() +{ + UNIMPLEMENTED(); +} + +/************************************************************* + * public BDACStream + *************************************************************/ + +BDACStream::BDACStream() +{ + UNIMPLEMENTED(); +} + + +BDACStream::~BDACStream() +{ + UNIMPLEMENTED(); +} + + +status_t +BDACStream::SetSamplingRate(float sRate) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BDACStream::SamplingRate(float *sRate) const +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BDACStream::SetVolume(int32 device, + float l_volume, + float r_volume) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BDACStream::GetVolume(int32 device, + float *l_volume, + float *r_volume, + bool *enabled) const +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BDACStream::EnableDevice(int32 device, + bool enable) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +bool +BDACStream::IsDeviceEnabled(int32 device) const +{ + UNIMPLEMENTED(); + bool dummy; + + return dummy; +} + + +status_t +BDACStream::SetStreamBuffers(size_t bufferSize, + int32 bufferCount) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + +/************************************************************* + * protected BDACStream + *************************************************************/ + +BMessenger * +BDACStream::Server() const +{ + UNIMPLEMENTED(); + return NULL; +} + + +stream_id +BDACStream::StreamID() const +{ + UNIMPLEMENTED(); + stream_id dummy; + + return dummy; +} + +/************************************************************* + * private BDACStream + *************************************************************/ + +void +BDACStream::_ReservedDACStream1() +{ + UNIMPLEMENTED(); +} + + +void +BDACStream::_ReservedDACStream2() +{ + UNIMPLEMENTED(); +} + + +void +BDACStream::_ReservedDACStream3() +{ + UNIMPLEMENTED(); +} + + diff --git a/src/kits/media/OldAudioStream.h b/src/kits/media/OldAudioStream.h new file mode 100644 index 0000000000..dfdda88da0 --- /dev/null +++ b/src/kits/media/OldAudioStream.h @@ -0,0 +1,94 @@ +/****************************************************************************** + + File: AudioStream.h + + Copyright 1995-97, Be Incorporated + +******************************************************************************/ +#ifndef _AUDIO_STREAM_H +#define _AUDIO_STREAM_H + +#include +#include + + +/* ================ + Class definition for BADCStream and BDACStream + ================ */ + +class BADCStream : public BAbstractBufferStream +{ +public: + + BADCStream(); + virtual ~BADCStream(); + + status_t SetADCInput(int32 device); + status_t ADCInput(int32* device) const; + + status_t SetSamplingRate(float sRate); + status_t SamplingRate(float* sRate) const; + + status_t BoostMic(bool boost); + bool IsMicBoosted() const; + + status_t SetStreamBuffers(size_t bufferSize, int32 bufferCount); + +protected: + + virtual BMessenger* Server() const; /* message pipe to server */ + virtual stream_id StreamID() const; /* stream identifier */ + +private: + +virtual void _ReservedADCStream1(); +virtual void _ReservedADCStream2(); +virtual void _ReservedADCStream3(); + + BMessenger* fServer; + stream_id fStreamID; + uint32 _reserved[4]; +}; + + +class BDACStream : public BAbstractBufferStream +{ +public: + + BDACStream(); + virtual ~BDACStream(); + + status_t SetSamplingRate(float sRate); + status_t SamplingRate(float* sRate) const; + + status_t SetVolume(int32 device, + float l_volume, + float r_volume); + + status_t GetVolume(int32 device, + float *l_volume, + float *r_volume, + bool *enabled) const; + + status_t EnableDevice(int32 device, bool enable); + bool IsDeviceEnabled(int32 device) const; + + status_t SetStreamBuffers(size_t bufferSize, int32 bufferCount); + +protected: + + virtual BMessenger* Server() const; /* message pipe to server */ + virtual stream_id StreamID() const; /* stream identifier */ + +private: + +virtual void _ReservedDACStream1(); +virtual void _ReservedDACStream2(); +virtual void _ReservedDACStream3(); + + BMessenger* fServer; + stream_id fStreamID; + uint32 _reserved[4]; +}; + +#endif // #ifdef _AUDIO_STREAM_H diff --git a/src/kits/media/OldBufferMsgs.h b/src/kits/media/OldBufferMsgs.h new file mode 100644 index 0000000000..12adf96a25 --- /dev/null +++ b/src/kits/media/OldBufferMsgs.h @@ -0,0 +1,130 @@ +/* ++++++++++ + + FILE: BufferMsgs.h + + Copyright (c) 1995-1997 by Be Incorporated. All Rights Reserved. + ++++++ */ +#ifndef _BUFFER_MSGS_H +#define _BUFFER_MSGS_H + +#include + +/**************************************************************** +This file defines the messages sent between a Subscriber and a +Server. Changes to the protocol should be noted here and appropriate +modifications made to Subscriber.cpp and any servers (currently +the audio_server is the only one). + +BufferMsgs defines a message-based interface, not a class +interface. A BufferMsgs receives messages from Subscribers via the +BMessenger class. + +Here are the messages that must be supported for the base Subscriber +class and the replies that a server will send. Specific Servers +may support other messages as well. + +==== +Acquire a stream-id for subsequent operations. +'resource' is a server-specific value that specifies the resource +to which the client wants access. + +Upon success, the server replies with 'stream_id' (used for +subsequent operations). + +GET_STREAM_ID int32("resource") +=> GET_STREAM_ID int32("stream_id") +=> ERROR_RETURN int32("error") + +==== +Acquire access to a stream for subsequent operations. +'stream_id' specifies the stream to which the client wants access. +'will_wait' determines if the client will receive an immediate reply +or if it will block until access is granted. 'sem' is a semaphore +used to indicate that the stream has released a buffer. + +Upon success, the server replies with 'subscriber_id' (used for +subsequent operations). + +SUBSCRIBE String("name") + int32("stream_id") + int32("sem") + Bool("will_wait") +=> SUBSCRIBE int32("subscriber_id") +=> ERROR_RETURN int32("error") + +==== +Relinquish access to the stream. + +UNSUBSCRIBE int32("subscriber_id") +=> UNSUBSCRIBE +=> ERROR_RETURN int32("error") + +==== +Join the stream at the specified position and start receiving buffers +of data. +ENTER_STREAM int32("subscriber_id") + int32("neighbor") + Bool("before") +=> ENTER_STREAM +=> ERROR_RETURN int32("error") + +==== +Issue a request to stop receiving buffers. More buffers may continue +to arrive, but you must keep acquiring_ and releasing_ them until you +get one for which is_last_buffer() is true. Then you can stop. + +EXIT_STREAM int32("subscriber_id") +=> EXIT_STREAM +=> ERROR_RETURN int32("error") + +==== +Get information about a particular buffer stream. + +GET_STREAM_PARAMS int32("stream_id") +=> GET_STREAM_PARAMS int32("buffer_size") + int32("buffer_count") + Bool("is_running") + int32("subscriber_count") +=> ERROR_RETURN int32("error") +==== +Set information about a particular buffer stream. + +SET_STREAM_PARAMS int32("stream_id") + int32("buffer_size") <> + int32("buffer_count") <> + Bool("is_running") <> +=> SET_STREAM_PARAMS int32("buffer_size") + int32("buffer_count") + Bool("is_running") + int32("subscriber_count") +=> ERROR_RETURN int32("error") + +==== +Return the subscriber id of the index'th subscriber sharing the +stream with the given subscriber. + +SUBSCRIBER_INFO int32("subscriber_id") +=> SUBSCRIBER_INFO String("subscriber_name") + int32("stream_id") // granted access to + int32("position") // position (if active) or -1 +=> ERROR_RETURN int32("error") + + +****************************************************************/ + +/* message values */ +enum { + DEBUG_SERVER = 99, + SUBSCRIBE, + UNSUBSCRIBE, + ENTER_STREAM, + EXIT_STREAM, + GET_STREAM_PARAMETERS, + SET_STREAM_PARAMETERS, + GET_STREAM_ID, + SUBSCRIBER_INFO, + ERROR_RETURN + }; + +#endif // #ifndef _BUFFER_MSGS_H diff --git a/src/kits/media/OldBufferStream.cpp b/src/kits/media/OldBufferStream.cpp new file mode 100644 index 0000000000..c985fc9d0b --- /dev/null +++ b/src/kits/media/OldBufferStream.cpp @@ -0,0 +1,680 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: OldBufferStream.cpp + * DESCR: + ***********************************************************************/ +#include +#include "debug.h" + +/************************************************************* + * public BAbstractBufferStream + *************************************************************/ + +status_t +BAbstractBufferStream::GetStreamParameters(size_t *bufferSize, + int32 *bufferCount, + bool *isRunning, + int32 *subscriberCount) const +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BAbstractBufferStream::SetStreamBuffers(size_t bufferSize, + int32 bufferCount) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BAbstractBufferStream::StartStreaming() +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BAbstractBufferStream::StopStreaming() +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + +/************************************************************* + * protected BAbstractBufferStream + *************************************************************/ + +void +BAbstractBufferStream::_ReservedAbstractBufferStream1() +{ + UNIMPLEMENTED(); +} + + +void +BAbstractBufferStream::_ReservedAbstractBufferStream2() +{ + UNIMPLEMENTED(); +} + + +void +BAbstractBufferStream::_ReservedAbstractBufferStream3() +{ + UNIMPLEMENTED(); +} + + +void +BAbstractBufferStream::_ReservedAbstractBufferStream4() +{ + UNIMPLEMENTED(); +} + + +stream_id +BAbstractBufferStream::StreamID() const +{ + UNIMPLEMENTED(); + stream_id dummy; + + return dummy; +} + + +status_t +BAbstractBufferStream::Subscribe(char *name, + subscriber_id *subID, + sem_id semID) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BAbstractBufferStream::Unsubscribe(subscriber_id subID) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BAbstractBufferStream::EnterStream(subscriber_id subID, + subscriber_id neighbor, + bool before) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BAbstractBufferStream::ExitStream(subscriber_id subID) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +BMessenger * +BAbstractBufferStream::Server() const +{ + UNIMPLEMENTED(); + return NULL; +} + + +status_t +BAbstractBufferStream::SendRPC(BMessage *msg, + BMessage *reply) const +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + +/************************************************************* + * public BBufferStream + *************************************************************/ + +BBufferStream::BBufferStream(size_t headerSize, + BBufferStreamManager *controller, + BSubscriber *headFeeder, + BSubscriber *tailFeeder) +{ + UNIMPLEMENTED(); +} + + +BBufferStream::~BBufferStream() +{ + UNIMPLEMENTED(); +} + + +void * +BBufferStream::operator new(size_t size) +{ + UNIMPLEMENTED(); + return NULL; +} + + +void +BBufferStream::operator delete(void *stream, + size_t size) +{ + UNIMPLEMENTED(); +} + + +size_t +BBufferStream::HeaderSize() const +{ + UNIMPLEMENTED(); + size_t dummy; + + return dummy; +} + + +status_t +BBufferStream::GetStreamParameters(size_t *bufferSize, + int32 *bufferCount, + bool *isRunning, + int32 *subscriberCount) const +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BBufferStream::SetStreamBuffers(size_t bufferSize, + int32 bufferCount) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BBufferStream::StartStreaming() +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BBufferStream::StopStreaming() +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +BBufferStreamManager * +BBufferStream::StreamManager() const +{ + UNIMPLEMENTED(); + return NULL; +} + + +int32 +BBufferStream::CountBuffers() const +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +status_t +BBufferStream::Subscribe(char *name, + subscriber_id *subID, + sem_id semID) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BBufferStream::Unsubscribe(subscriber_id subID) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BBufferStream::EnterStream(subscriber_id subID, + subscriber_id neighbor, + bool before) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BBufferStream::ExitStream(subscriber_id subID) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +bool +BBufferStream::IsSubscribed(subscriber_id subID) +{ + UNIMPLEMENTED(); + bool dummy; + + return dummy; +} + + +bool +BBufferStream::IsEntered(subscriber_id subID) +{ + UNIMPLEMENTED(); + bool dummy; + + return dummy; +} + + +status_t +BBufferStream::SubscriberInfo(subscriber_id subID, + char **name, + stream_id *streamID, + int32 *position) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BBufferStream::UnblockSubscriber(subscriber_id subID) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BBufferStream::AcquireBuffer(subscriber_id subID, + buffer_id *bufID, + bigtime_t timeout) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BBufferStream::ReleaseBuffer(subscriber_id subID) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +size_t +BBufferStream::BufferSize(buffer_id bufID) const +{ + UNIMPLEMENTED(); + size_t dummy; + + return dummy; +} + + +char * +BBufferStream::BufferData(buffer_id bufID) const +{ + UNIMPLEMENTED(); + return NULL; +} + + +bool +BBufferStream::IsFinalBuffer(buffer_id bufID) const +{ + UNIMPLEMENTED(); + bool dummy; + + return dummy; +} + + +int32 +BBufferStream::CountBuffersHeld(subscriber_id subID) +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +int32 +BBufferStream::CountSubscribers() const +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +int32 +BBufferStream::CountEnteredSubscribers() const +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +subscriber_id +BBufferStream::FirstSubscriber() const +{ + UNIMPLEMENTED(); + subscriber_id dummy; + + return dummy; +} + + +subscriber_id +BBufferStream::LastSubscriber() const +{ + UNIMPLEMENTED(); + subscriber_id dummy; + + return dummy; +} + + +subscriber_id +BBufferStream::NextSubscriber(subscriber_id subID) +{ + UNIMPLEMENTED(); + subscriber_id dummy; + + return dummy; +} + + +subscriber_id +BBufferStream::PrevSubscriber(subscriber_id subID) +{ + UNIMPLEMENTED(); + subscriber_id dummy; + + return dummy; +} + + +void +BBufferStream::PrintStream() +{ + UNIMPLEMENTED(); +} + + +void +BBufferStream::PrintBuffers() +{ + UNIMPLEMENTED(); +} + + +void +BBufferStream::PrintSubscribers() +{ + UNIMPLEMENTED(); +} + + +bool +BBufferStream::Lock() +{ + UNIMPLEMENTED(); + bool dummy; + + return dummy; +} + + +void +BBufferStream::Unlock() +{ + UNIMPLEMENTED(); +} + + +status_t +BBufferStream::AddBuffer(buffer_id bufID) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +buffer_id +BBufferStream::RemoveBuffer(bool force) +{ + UNIMPLEMENTED(); + buffer_id dummy; + + return dummy; +} + + +buffer_id +BBufferStream::CreateBuffer(size_t size, + bool isFinal) +{ + UNIMPLEMENTED(); + buffer_id dummy; + + return dummy; +} + + +void +BBufferStream::DestroyBuffer(buffer_id bufID) +{ + UNIMPLEMENTED(); +} + + +void +BBufferStream::RescindBuffers() +{ + UNIMPLEMENTED(); +} + +/************************************************************* + * private BBufferStream + *************************************************************/ + +void +BBufferStream::_ReservedBufferStream1() +{ + UNIMPLEMENTED(); +} + + +void +BBufferStream::_ReservedBufferStream2() +{ + UNIMPLEMENTED(); +} + + +void +BBufferStream::_ReservedBufferStream3() +{ + UNIMPLEMENTED(); +} + + +void +BBufferStream::_ReservedBufferStream4() +{ + UNIMPLEMENTED(); +} + + +void +BBufferStream::InitSubscribers() +{ + UNIMPLEMENTED(); +} + + +bool +BBufferStream::IsSubscribedSafe(subscriber_id subID) const +{ + UNIMPLEMENTED(); + bool dummy; + + return dummy; +} + + +bool +BBufferStream::IsEnteredSafe(subscriber_id subID) const +{ + UNIMPLEMENTED(); + bool dummy; + + return dummy; +} + + +void +BBufferStream::InitBuffers() +{ + UNIMPLEMENTED(); +} + + +status_t +BBufferStream::WakeSubscriber(subscriber_id subID) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +void +BBufferStream::InheritBuffers(subscriber_id subID) +{ + UNIMPLEMENTED(); +} + + +void +BBufferStream::BequeathBuffers(subscriber_id subID) +{ + UNIMPLEMENTED(); +} + + +status_t +BBufferStream::ReleaseBufferSafe(subscriber_id subID) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BBufferStream::ReleaseBufferTo(buffer_id bufID, + subscriber_id subID) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +void +BBufferStream::FreeAllBuffers() +{ + UNIMPLEMENTED(); +} + + +void +BBufferStream::FreeAllSubscribers() +{ + UNIMPLEMENTED(); +} + + diff --git a/src/kits/media/OldBufferStream.h b/src/kits/media/OldBufferStream.h new file mode 100644 index 0000000000..f5bf5f654a --- /dev/null +++ b/src/kits/media/OldBufferStream.h @@ -0,0 +1,310 @@ +/****************************************************************************** + + File: BufferStream.h + + Copyright 1995-97, Be Incorporated + +******************************************************************************/ +#ifndef _BUFFER_STREAM_H +#define _BUFFER_STREAM_H + +#include +#include +#include +#include +#include +#include + +/* ================ + Per-subscriber information. + ================ */ + +struct _sbuf_info; + +typedef struct _sub_info { + _sub_info *fNext; /* next subscriber in the stream*/ + _sub_info *fPrev; /* previous subscriber in the stream */ + _sbuf_info *fRel; /* next buf to be released */ + _sbuf_info *fAcq; /* next buf to be acquired */ + sem_id fSem; /* semaphore used for blocking */ + bigtime_t fTotalTime; /* accumulated time between acq/rel */ + int32 fHeld; /* # of buffers acq'd but not yet rel'd */ + sem_id fBlockedOn; /* the semaphore being waited on */ + /* or B_BAD_SEM_ID if not blocked */ +} *subscriber_id; + + +/* ================ + Per-buffer information + ================ */ + +typedef struct _sbuf_info { + _sbuf_info *fNext; /* next "newer" buffer in the chain */ + subscriber_id fAvailTo; /* next subscriber to acquire this buffer */ + subscriber_id fHeldBy; /* subscriber that's acquired this buffer */ + bigtime_t fAcqTime; /* time at which this buffer was acquired */ + area_id fAreaID; /* for system memory allocation calls */ + char *fAddress; + int32 fSize; /* usable portion can be smaller than ... */ + int32 fAreaSize; /* ... the size of the area. */ + bool fIsFinal; /* TRUE => stream is stopping */ +} *buffer_id; + + +/* ================ + Interface definition for BBufferStream class + ================ */ + +/* We've chosen B_MAX_SUBSCRIBER_COUNT and B_MAX_BUFFER_COUNT to be small + * enough so that a BBufferStream structure fits in one 4096 byte page. + */ +#define B_MAX_SUBSCRIBER_COUNT 52 +#define B_MAX_BUFFER_COUNT 32 + +class BBufferStream; +class BBufferStreamManager; + +typedef BBufferStream* stream_id; // for now + + +class BAbstractBufferStream +{ +public: + + virtual status_t GetStreamParameters(size_t *bufferSize, + int32 *bufferCount, + bool *isRunning, + int32 *subscriberCount) const; + + virtual status_t SetStreamBuffers(size_t bufferSize, + int32 bufferCount); + + virtual status_t StartStreaming(); + virtual status_t StopStreaming(); + +protected: + +virtual void _ReservedAbstractBufferStream1(); +virtual void _ReservedAbstractBufferStream2(); +virtual void _ReservedAbstractBufferStream3(); +virtual void _ReservedAbstractBufferStream4(); + + friend class BSubscriber; + friend class BBufferStreamManager; + + virtual stream_id StreamID() const; + /* stream identifier for direct access */ + + /* Create or delete a subscriber id for subsequent operations */ + virtual status_t Subscribe(char *name, + subscriber_id *subID, + sem_id semID); + virtual status_t Unsubscribe(subscriber_id subID); + +/* Enter into or quit the stream */ + virtual status_t EnterStream(subscriber_id subID, + subscriber_id neighbor, + bool before); + + virtual status_t ExitStream(subscriber_id subID); + + virtual BMessenger* Server() const; /* message pipe to server */ + status_t SendRPC(BMessage* msg, BMessage* reply = NULL) const; +}; + + +class BBufferStream : public BAbstractBufferStream +{ +public: + + BBufferStream(size_t headerSize, + BBufferStreamManager* controller, + BSubscriber* headFeeder, + BSubscriber* tailFeeder); + virtual ~BBufferStream(); + +/* BBufferStreams are allocated on shared memory pages */ + void *operator new(size_t size); + void operator delete(void *stream, size_t size); + +/* Return header size */ + size_t HeaderSize() const; + +/* These four functions are delegated to the stream controller */ + status_t GetStreamParameters(size_t *bufferSize, + int32 *bufferCount, + bool *isRunning, + int32 *subscriberCount) const; + + status_t SetStreamBuffers(size_t bufferSize, + int32 bufferCount); + + status_t StartStreaming(); + status_t StopStreaming(); + +/* Get the controller for delegation */ + BBufferStreamManager *StreamManager() const; + +/* number of buffers in stream */ + int32 CountBuffers() const; + +/* Create or delete a subscriber id for subsequent operations */ + status_t Subscribe(char *name, + subscriber_id *subID, + sem_id semID); + + status_t Unsubscribe(subscriber_id subID); + +/* Enter into or quit the stream */ + status_t EnterStream(subscriber_id subID, + subscriber_id neighbor, + bool before); + + status_t ExitStream(subscriber_id subID); + +/* queries about a subscriber */ + bool IsSubscribed(subscriber_id subID); + bool IsEntered(subscriber_id subID); + + status_t SubscriberInfo(subscriber_id subID, + char** name, + stream_id* streamID, + int32* position); + +/* Force an error return of a subscriber if it's blocked */ + status_t UnblockSubscriber(subscriber_id subID); + +/* Acquire and release a buffer */ + status_t AcquireBuffer(subscriber_id subID, + buffer_id *bufID, + bigtime_t timeout); + status_t ReleaseBuffer(subscriber_id subID); + +/* Get the attributes of a particular buffer */ + size_t BufferSize(buffer_id bufID) const; + char *BufferData(buffer_id bufID) const; + bool IsFinalBuffer(buffer_id bufID) const; + +/* Get attributes of a particular subscriber */ + int32 CountBuffersHeld(subscriber_id subID); + +/* Queries for the BBufferStream */ + int32 CountSubscribers() const; + int32 CountEnteredSubscribers() const; + + subscriber_id FirstSubscriber() const; + subscriber_id LastSubscriber() const; + subscriber_id NextSubscriber(subscriber_id subID); + subscriber_id PrevSubscriber(subscriber_id subID); + +/* debugging aids */ + void PrintStream(); + void PrintBuffers(); + void PrintSubscribers(); + +/* gaining exclusive access to the BBufferStream */ + bool Lock(); + void Unlock(); + +/* introduce a new buffer into the "newest" end of the chain */ + status_t AddBuffer(buffer_id bufID); + +/* remove a buffer from the "oldest" end of the chain */ + buffer_id RemoveBuffer(bool force); + +/* allocate a buffer from shared memory and create a bufID for it. */ + buffer_id CreateBuffer(size_t size, bool isFinal); + +/* deallocate a buffer and returns its bufID to the freelist */ + void DestroyBuffer(buffer_id bufID); + +/* remove and destroy any "newest" buffers from the head of the chain + * that have not yet been claimed by any subscribers. If there are + * no subscribers, this clears the entire chain. + */ + void RescindBuffers(); + +/* ================ + Private member functions that assume locking already has been done. + ================ */ + +private: + +virtual void _ReservedBufferStream1(); +virtual void _ReservedBufferStream2(); +virtual void _ReservedBufferStream3(); +virtual void _ReservedBufferStream4(); + +/* initialize the free list of subscribers */ + void InitSubscribers(); + +/* return TRUE if subID appears valid */ + bool IsSubscribedSafe(subscriber_id subID) const; + +/* return TRUE if subID is entered into the stream */ + bool IsEnteredSafe(subscriber_id subID) const; + +/* initialize the free list of buffer IDs */ + void InitBuffers(); + +/* Wake a blocked subscriber */ + status_t WakeSubscriber(subscriber_id subID); + +/* Give subID all the buffers it can get */ + void InheritBuffers(subscriber_id subID); + +/* Relinquish any buffers held by subID */ + void BequeathBuffers(subscriber_id subID); + +/* Fast version of ReleaseBuffer() */ + status_t ReleaseBufferSafe(subscriber_id subID); + +/* Release a buffer to a subscriber */ + status_t ReleaseBufferTo(buffer_id bufID, subscriber_id subID); + +/* deallocate all buffers */ + void FreeAllBuffers(); + +/* deallocate all subscribers */ + void FreeAllSubscribers(); + +/* ================ + Private data members + ================ */ + + BLocker fLock; + area_id fAreaID; /* area id for this BBufferStream */ + BBufferStreamManager *fStreamManager; + BSubscriber *fHeadFeeder; + BSubscriber *fTailFeeder; + size_t fHeaderSize; + + /* ================ + subscribers + ================ */ + + _sub_info *fFreeSubs; /* free list of subscribers */ + _sub_info *fFirstSub; /* first entered in itinierary */ + _sub_info *fLastSub; /* last entered in itinerary */ + + sem_id fFirstSem; /* semaphore used by fFirstSub */ + int32 fSubCount; + int32 fEnteredSubCount; + + _sub_info fSubscribers[B_MAX_SUBSCRIBER_COUNT]; + + /* ================ + buffers + ================ */ + + _sbuf_info *fFreeBuffers; + _sbuf_info *fOldestBuffer; /* first in line */ + _sbuf_info *fNewestBuffer; /* fNewest->fNext = NULL */ + int32 fCountBuffers; + + _sbuf_info fBuffers[B_MAX_BUFFER_COUNT]; + + uint32 _reserved[4]; +}; + +#endif // #ifdef _BUFFER_STREAM_H diff --git a/src/kits/media/OldBufferStreamManager.cpp b/src/kits/media/OldBufferStreamManager.cpp new file mode 100644 index 0000000000..398b8bb5e5 --- /dev/null +++ b/src/kits/media/OldBufferStreamManager.cpp @@ -0,0 +1,287 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: OldBufferStreamManager.cpp + * DESCR: + ***********************************************************************/ +#include +#include "debug.h" + +/************************************************************* + * public BBufferStreamManager + *************************************************************/ + +BBufferStreamManager::BBufferStreamManager(char *name) +{ + UNIMPLEMENTED(); +} + + +BBufferStreamManager::~BBufferStreamManager() +{ + UNIMPLEMENTED(); +} + + +char * +BBufferStreamManager::Name() const +{ + UNIMPLEMENTED(); + return NULL; +} + + +BBufferStream * +BBufferStreamManager::Stream() const +{ + UNIMPLEMENTED(); + return NULL; +} + + +int32 +BBufferStreamManager::BufferCount() const +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +void +BBufferStreamManager::SetBufferCount(int32 count) +{ + UNIMPLEMENTED(); +} + + +int32 +BBufferStreamManager::BufferSize() const +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +void +BBufferStreamManager::SetBufferSize(int32 bytes) +{ + UNIMPLEMENTED(); +} + + +bigtime_t +BBufferStreamManager::BufferDelay() const +{ + UNIMPLEMENTED(); + bigtime_t dummy; + + return dummy; +} + + +void +BBufferStreamManager::SetBufferDelay(bigtime_t usecs) +{ + UNIMPLEMENTED(); +} + + +bigtime_t +BBufferStreamManager::Timeout() const +{ + UNIMPLEMENTED(); + bigtime_t dummy; + + return dummy; +} + + +void +BBufferStreamManager::SetTimeout(bigtime_t usecs) +{ + UNIMPLEMENTED(); +} + + +stream_state +BBufferStreamManager::Start() +{ + UNIMPLEMENTED(); + stream_state dummy; + + return dummy; +} + + +stream_state +BBufferStreamManager::Stop() +{ + UNIMPLEMENTED(); + stream_state dummy; + + return dummy; +} + + +stream_state +BBufferStreamManager::Abort() +{ + UNIMPLEMENTED(); + stream_state dummy; + + return dummy; +} + + +stream_state +BBufferStreamManager::State() const +{ + UNIMPLEMENTED(); + stream_state dummy; + + return dummy; +} + + +port_id +BBufferStreamManager::NotificationPort() const +{ + UNIMPLEMENTED(); + port_id dummy; + + return dummy; +} + + +void +BBufferStreamManager::SetNotificationPort(port_id port) +{ + UNIMPLEMENTED(); +} + + +bool +BBufferStreamManager::Lock() +{ + UNIMPLEMENTED(); + bool dummy; + + return dummy; +} + + +void +BBufferStreamManager::Unlock() +{ + UNIMPLEMENTED(); +} + + +status_t +BBufferStreamManager::Subscribe(BBufferStream *stream) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BBufferStreamManager::Unsubscribe() +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +subscriber_id +BBufferStreamManager::ID() const +{ + UNIMPLEMENTED(); + subscriber_id dummy; + + return dummy; +} + +/************************************************************* + * protected BBufferStreamManager + *************************************************************/ + +void +BBufferStreamManager::StartProcessing() +{ + UNIMPLEMENTED(); +} + + +void +BBufferStreamManager::StopProcessing() +{ + UNIMPLEMENTED(); +} + + +status_t +BBufferStreamManager::_ProcessingThread(void *arg) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +void +BBufferStreamManager::ProcessingThread() +{ + UNIMPLEMENTED(); +} + + +void +BBufferStreamManager::SetState(stream_state newState) +{ + UNIMPLEMENTED(); +} + + +bigtime_t +BBufferStreamManager::SnoozeUntil(bigtime_t sys_time) +{ + UNIMPLEMENTED(); + bigtime_t dummy; + + return dummy; +} + +/************************************************************* + * private BBufferStreamManager + *************************************************************/ + +void +BBufferStreamManager::_ReservedBufferStreamManager1() +{ + UNIMPLEMENTED(); +} + + +void +BBufferStreamManager::_ReservedBufferStreamManager2() +{ + UNIMPLEMENTED(); +} + + +void +BBufferStreamManager::_ReservedBufferStreamManager3() +{ + UNIMPLEMENTED(); +} + + diff --git a/src/kits/media/OldBufferStreamManager.h b/src/kits/media/OldBufferStreamManager.h new file mode 100644 index 0000000000..2811d06d2e --- /dev/null +++ b/src/kits/media/OldBufferStreamManager.h @@ -0,0 +1,189 @@ +/****************************************************************************** + + File: BufferStreamManager.h + + Copyright 1995-97, Be Incorporated + +******************************************************************************/ +#ifndef _BUFFER_STREAM_MANAGER_H +#define _BUFFER_STREAM_MANAGER_H + +#include +#include +#include +#include +#include + + +/* ================ + Local Declarations + ================ */ + +#define B_DEFAULT_BSTREAM_COUNT 3 +#define B_DEFAULT_BSTREAM_SIZE B_PAGE_SIZE +#define B_DEFAULT_BSTREAM_DELAY 10000 +#define B_DEFAULT_BSTREAM_TIMEOUT 5000000 + + +enum stream_state { + B_IDLE = 100, /* stream is shut down */ + B_RUNNING, /* stream is running */ + B_STOPPING /* waiting for final buffer to return */ + }; + + +/* ================ + Class definition for BBufferStreamManager + ================ */ + + +class BBufferStreamManager { + +public: + + BBufferStreamManager(char* name); + virtual ~BBufferStreamManager(); + + + char *Name() const; + BBufferStream *Stream() const; + + int32 BufferCount() const; + void SetBufferCount(int32 count); + + int32 BufferSize() const; + void SetBufferSize(int32 bytes); + + /* Get or set the minimum delay between sending out successive buffers. + * Although the StreamManager automatically shuts down when there + * are no more subscribers, setting the minumum delay can prevent + * prevent runaway streams. A zero or negative value means no + * delay. + */ + bigtime_t BufferDelay() const; + void SetBufferDelay(bigtime_t usecs); + + /* If no Buffers return to the StreamManager within a period of time, the + * StreamManager will decide that one of the subscribers is broken and + * will go hunting for it. When it finds the offending subscriber, + * it will be removed from the chain with impunity. + * + * The default is B_DEFAULT_TIMEOUT. Setting the timeout to 0 or a + * negative number will disable this. + */ + bigtime_t Timeout() const; + void SetTimeout(bigtime_t usecs); + + /**************************************************************** + * Control the running of the stream. + * + */ + + /* Set the pending state to B_RUNNING and, if required, start up + * the processing thread. The processing thread will start + * emitting buffers to the stream. + */ + stream_state Start(); + + /* Set the pending state to B_STOPPING. The processing thread will + * stop emitting new buffers to the stream, and when all buffers + * are accounted for, will automatically set the desired state + * to B_IDLE. + */ + stream_state Stop(); + + /* Set the desired state to B_IDLE. The processing thread will + * stop immediately and all buffers will be "reclaimed" back + * to the StreamManager. + */ + stream_state Abort(); + + /* Return the current state of the stream (B_RUNNING, B_STOPPING, or B_IDLE). + */ + stream_state State() const; + + /* When NotificationPort is set, the receiver will get a message + * whenever the state of the StreamManager changes. The msg_id of the + * message will be the new state of the StreamManager. + */ + port_id NotificationPort() const; + void SetNotificationPort(port_id port); + + /* Lock the data structures associated with this StreamManager + */ + bool Lock(); + void Unlock(); + + /**************************************************************** + * Subscribe functions + */ + + status_t Subscribe(BBufferStream *stream); + status_t Unsubscribe(); + subscriber_id ID() const; + + +/* ================ + Protected member functions. + ================ */ + +protected: + + /**************************************************************** + * + * The processing thread. This thread waits to acquire a Buffer + * (or for the timeout to expire) and takes appropriate action. + */ + virtual void StartProcessing(); + virtual void StopProcessing(); + static status_t _ProcessingThread(void *arg); + virtual void ProcessingThread(); + + /* Set the state of the stream. If newState is the same as the + * current state, this is a no-op. Otherwise, this method will + * notify anyone listening on the notification port about the + * changed state and will send a StateChange buffer through the + * stream. + */ + virtual void SetState(stream_state newState); + + /* Snooze until the desired time arrives. Returns the + * current time upon returning. + */ + bigtime_t SnoozeUntil(bigtime_t sys_time); + +/* ================ + Private data. + ================ */ + +private: + +virtual void _ReservedBufferStreamManager1(); +virtual void _ReservedBufferStreamManager2(); +virtual void _ReservedBufferStreamManager3(); + + /**************************************************************** + * + * Private fields. + * + */ + + BBufferStream *fStream; /* a BBufferStream object */ + stream_state fState; /* running, stopping, etc. */ + sem_id fSem; + + int32 fBufferCount; /* desired # of buffers */ + int32 fBufferSize; /* desired size of each buffer */ + bigtime_t fBufferDelay; /* minimum time between sends */ + bigtime_t fTimeout; /* watchdog timer */ + + port_id fNotifyPort; /* when set, send change of state msgs */ + thread_id fProcessingThread; /* thread to dispatch buffers */ + subscriber_id fManagerID; /* StreamManager's subID in fStream */ + + BLocker fLock; + char* fName; + uint32 _reserved[4]; +}; + +#endif // #ifdef _BUFFER_STREAM_MANAGER_H diff --git a/src/kits/media/OldMediaDefs.h b/src/kits/media/OldMediaDefs.h new file mode 100644 index 0000000000..8551ee4f7f --- /dev/null +++ b/src/kits/media/OldMediaDefs.h @@ -0,0 +1,83 @@ +/****************************************************************************** + + File: MediaDefs.h + + Copyright 1995-97, Be Incorporated + +******************************************************************************/ +#ifndef _MEDIA_DEFS_H +#define _MEDIA_DEFS_H + +#include +#include + +/* Buffer header for audio server */ + +typedef struct audio_buffer_header { + int32 buffer_number; + int32 subscriber_count; + bigtime_t time; + int32 reserved_1; + int32 reserved_2; + int32 reserved_3; + int32 reserved_4; +} audio_buffer_header; + + +#define B_MEDIA_LEVEL B_REAL_TIME_PRIORITY + +#define B_NO_CHANGE (-1) + +/* ================ + Subscriber IDs and special values + ================ */ + +#define B_NO_SUBSCRIBER_ID ((subscriber_id)-1) +#define B_NO_SUBSCRIBER_NAME "not subscribed" + +#define B_SHARED_SUBSCRIBER_ID ((subscriber_id)-2) +#define B_SHARED_SUBSCRIBER_NAME "shared subscriber" + +/* ================ + Values for sound files and audio streams + ================ */ + +/* values for byte_ordering */ +enum { B_BIG_ENDIAN, B_LITTLE_ENDIAN }; + +/* values for sample_format */ +enum { + B_UNDEFINED_SAMPLES, + B_LINEAR_SAMPLES, + B_FLOAT_SAMPLES, + B_MULAW_SAMPLES + }; + +/* Audio device codes for BAudioSubscriber's + * Get/SetVolume() and EnableDevice() calls + */ +enum { + B_CD_THROUGH=0, + B_LINE_IN_THROUGH, + B_ADC_IN, + B_LOOPBACK, + B_DAC_OUT, + B_MASTER_OUT, + B_SPEAKER_OUT, + B_SOUND_DEVICE_END + }; + +/* ADC input codes */ +enum { + B_CD_IN, + B_LINE_IN, + B_MIC_IN + }; + + +enum { + B_DAC_STREAM = 2354, + B_ADC_STREAM + }; + +#endif // #ifndef _MEDIA_DEFS_H diff --git a/src/kits/media/OldMediaKit.h b/src/kits/media/OldMediaKit.h new file mode 100644 index 0000000000..bdf177ea19 --- /dev/null +++ b/src/kits/media/OldMediaKit.h @@ -0,0 +1,17 @@ +/***************************************************************/ +// +// File: mediaKit.h +// +// Copyright 1992-97, Be Incorporated. +// +/***************************************************************/ + + +#include +#include +#include +#include +#include +#include +#include + diff --git a/src/kits/media/OldMediaModule.cpp b/src/kits/media/OldMediaModule.cpp new file mode 100644 index 0000000000..6096512451 --- /dev/null +++ b/src/kits/media/OldMediaModule.cpp @@ -0,0 +1,692 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: OldMediaModule.cpp + * DESCR: + ***********************************************************************/ +#include +#include "debug.h" + +/************************************************************* + * public BMediaEvent + *************************************************************/ + +mk_time +BMediaEvent::Duration() +{ + UNIMPLEMENTED(); + mk_time dummy; + + return dummy; +} + + +bigtime_t +BMediaEvent::CaptureTime() +{ + UNIMPLEMENTED(); + bigtime_t dummy; + + return dummy; +} + +/************************************************************* + * public BEventStream + *************************************************************/ + +BEventStream::BEventStream() +{ + UNIMPLEMENTED(); +} + + +BEventStream::~BEventStream() +{ + UNIMPLEMENTED(); +} + + +mk_time +BEventStream::Start() +{ + UNIMPLEMENTED(); + mk_time dummy; + + return dummy; +} + + +void +BEventStream::SetStart(mk_time) +{ + UNIMPLEMENTED(); +} + + +mk_time +BEventStream::Duration() +{ + UNIMPLEMENTED(); + mk_time dummy; + + return dummy; +} + + +void +BEventStream::SetDuration(mk_time) +{ + UNIMPLEMENTED(); +} + + +status_t +BEventStream::SeekToTime(BMediaChannel *channel, + mk_time time) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + +/************************************************************* + * public BMediaRenderer + *************************************************************/ + + +BMediaRenderer::BMediaRenderer(const char *name, + int32 priority) +{ + UNIMPLEMENTED(); +} + + +BMediaRenderer::~BMediaRenderer() +{ + UNIMPLEMENTED(); +} + + +char * +BMediaRenderer::Name() +{ + UNIMPLEMENTED(); + return NULL; +} + + +mk_time +BMediaRenderer::Latency() +{ + UNIMPLEMENTED(); + mk_time dummy; + + return dummy; +} + + +BTransport * +BMediaRenderer::Transport() +{ + UNIMPLEMENTED(); + return NULL; +} + + +void +BMediaRenderer::SetTransport(BTransport *) +{ + UNIMPLEMENTED(); +} + + +mk_time +BMediaRenderer::Start() +{ + UNIMPLEMENTED(); + mk_time dummy; + + return dummy; +} + + +mk_time +BMediaRenderer::Duration() +{ + UNIMPLEMENTED(); + mk_time dummy; + + return dummy; +} + + +BTimeBase * +BMediaRenderer::TimeBase() +{ + UNIMPLEMENTED(); + return NULL; +} + + +void +BMediaRenderer::Open() +{ + UNIMPLEMENTED(); +} + + +void +BMediaRenderer::Close() +{ + UNIMPLEMENTED(); +} + + +void +BMediaRenderer::WakeUp() +{ + UNIMPLEMENTED(); +} + + +void +BMediaRenderer::TransportChanged(mk_time time, + mk_rate rate, + transport_status status) +{ + UNIMPLEMENTED(); +} + + +void +BMediaRenderer::StreamChanged() +{ + UNIMPLEMENTED(); +} + + +void +BMediaRenderer::OpenReceived() +{ + UNIMPLEMENTED(); +} + + +void +BMediaRenderer::CloseReceived() +{ + UNIMPLEMENTED(); +} + + +void +BMediaRenderer::WakeUpReceived() +{ + UNIMPLEMENTED(); +} + + +void +BMediaRenderer::TransportChangedReceived(mk_time time, + mk_rate rate, + transport_status status) +{ + UNIMPLEMENTED(); +} + + +void +BMediaRenderer::StreamChangedReceived() +{ + UNIMPLEMENTED(); +} + +/************************************************************* + * private BMediaRenderer + *************************************************************/ + + +int32 +BMediaRenderer::_LoopThread(void *arg) +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +void +BMediaRenderer::LoopThread() +{ + UNIMPLEMENTED(); +} + +/************************************************************* + * public BTransport + *************************************************************/ + + +BTransport::BTransport() +{ + UNIMPLEMENTED(); +} + + +BTransport::~BTransport() +{ + UNIMPLEMENTED(); +} + + +BTimeBase * +BTransport::TimeBase() +{ + UNIMPLEMENTED(); + return NULL; +} + + +void +BTransport::SetTimeBase(BTimeBase *) +{ + UNIMPLEMENTED(); +} + + +BList * +BTransport::Renderers() +{ + UNIMPLEMENTED(); + return NULL; +} + + +void +BTransport::AddRenderer(BMediaRenderer *) +{ + UNIMPLEMENTED(); +} + + +bool +BTransport::RemoveRenderer(BMediaRenderer *) +{ + UNIMPLEMENTED(); + bool dummy; + + return dummy; +} + + +transport_status +BTransport::Status() +{ + UNIMPLEMENTED(); + transport_status dummy; + + return dummy; +} + + +void +BTransport::SetStatus(transport_status) +{ + UNIMPLEMENTED(); +} + + +mk_time +BTransport::PerformanceTime() +{ + UNIMPLEMENTED(); + mk_time dummy; + + return dummy; +} + + +mk_rate +BTransport::PerformanceRate() +{ + UNIMPLEMENTED(); + mk_rate dummy; + + return dummy; +} + + +mk_time +BTransport::TimeOffset() +{ + UNIMPLEMENTED(); + mk_time dummy; + + return dummy; +} + + +void +BTransport::SetTimeOffset(mk_time) +{ + UNIMPLEMENTED(); +} + + +mk_time +BTransport::MaximumLatency() +{ + UNIMPLEMENTED(); + mk_time dummy; + + return dummy; +} + + +mk_time +BTransport::PerformanceStart() +{ + UNIMPLEMENTED(); + mk_time dummy; + + return dummy; +} + + +mk_time +BTransport::PerformanceEnd() +{ + UNIMPLEMENTED(); + mk_time dummy; + + return dummy; +} + + +void +BTransport::Open() +{ + UNIMPLEMENTED(); +} + + +void +BTransport::Close() +{ + UNIMPLEMENTED(); +} + + +void +BTransport::TransportChanged() +{ + UNIMPLEMENTED(); +} + + +void +BTransport::TimeSkipped() +{ + UNIMPLEMENTED(); +} + + +void +BTransport::RequestWakeUp(mk_time, + BMediaRenderer *) +{ + UNIMPLEMENTED(); +} + + +void +BTransport::SeekToTime(mk_time) +{ + UNIMPLEMENTED(); +} + + +BMediaChannel * +BTransport::GetChannel(int32 selector) +{ + UNIMPLEMENTED(); + return NULL; +} + +/************************************************************* + * public BTimeBase + *************************************************************/ + + +BTimeBase::BTimeBase(mk_rate rate) +{ + UNIMPLEMENTED(); +} + + +BTimeBase::~BTimeBase() +{ + UNIMPLEMENTED(); +} + + +BList * +BTimeBase::Transports() +{ + UNIMPLEMENTED(); + return NULL; +} + + +void +BTimeBase::AddTransport(BTransport *) +{ + UNIMPLEMENTED(); +} + + +bool +BTimeBase::RemoveTransport(BTransport *) +{ + UNIMPLEMENTED(); + bool dummy; + + return dummy; +} + + +void +BTimeBase::TimeSkipped() +{ + UNIMPLEMENTED(); +} + + +status_t +BTimeBase::CallAt(mk_time time, + mk_deferred_call function, + void *arg) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +mk_time +BTimeBase::Time() +{ + UNIMPLEMENTED(); + mk_time dummy; + + return dummy; +} + + +mk_rate +BTimeBase::Rate() +{ + UNIMPLEMENTED(); + mk_rate dummy; + + return dummy; +} + + +mk_time +BTimeBase::TimeAt(bigtime_t system_time) +{ + UNIMPLEMENTED(); + mk_time dummy; + + return dummy; +} + + +bigtime_t +BTimeBase::SystemTimeAt(mk_time time) +{ + UNIMPLEMENTED(); + bigtime_t dummy; + + return dummy; +} + + +void +BTimeBase::Sync(mk_time time, + bigtime_t system_time) +{ + UNIMPLEMENTED(); +} + + +bool +BTimeBase::IsAbsolute() +{ + UNIMPLEMENTED(); + bool dummy; + + return dummy; +} + +/************************************************************* + * private BTimeBase + *************************************************************/ + +int32 +BTimeBase::_SnoozeThread(void *arg) +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +void +BTimeBase::SnoozeThread() +{ + UNIMPLEMENTED(); +} + +/************************************************************* + * public BMediaChannel + *************************************************************/ + +BMediaChannel::BMediaChannel(mk_rate rate, + BMediaRenderer *renderer, + BEventStream *source) +{ + UNIMPLEMENTED(); +} + + +BMediaChannel::~BMediaChannel() +{ + UNIMPLEMENTED(); +} + + +BMediaRenderer * +BMediaChannel::Renderer() +{ + UNIMPLEMENTED(); + return NULL; +} + + +void +BMediaChannel::SetRenderer(BMediaRenderer *) +{ + UNIMPLEMENTED(); +} + + +BEventStream * +BMediaChannel::Source() +{ + UNIMPLEMENTED(); + return NULL; +} + + +void +BMediaChannel::SetSource(BEventStream *) +{ + UNIMPLEMENTED(); +} + + +mk_rate +BMediaChannel::Rate() +{ + UNIMPLEMENTED(); + mk_rate dummy; + + return dummy; +} + + +void +BMediaChannel::SetRate(mk_rate) +{ + UNIMPLEMENTED(); +} + + +bool +BMediaChannel::LockChannel() +{ + UNIMPLEMENTED(); + bool dummy; + + return dummy; +} + + +status_t +BMediaChannel::LockWithTimeout(bigtime_t) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +void +BMediaChannel::UnlockChannel() +{ + UNIMPLEMENTED(); +} + + +void +BMediaChannel::StreamChanged() +{ + UNIMPLEMENTED(); +} + + diff --git a/src/kits/media/OldMediaModule.h b/src/kits/media/OldMediaModule.h new file mode 100644 index 0000000000..df300b2e6e --- /dev/null +++ b/src/kits/media/OldMediaModule.h @@ -0,0 +1,218 @@ +/* ================ + + FILE: MediaModule.h + REVS: $Revision: 1.1 $ + NAME: marc + + Copyright (c) 1997 by Be Incorporated. All Rights Reserved. + +================ */ + +#ifndef _MEDIA_MODULE_H +#define _MEDIA_MODULE_H + +#include +#include + +typedef double mk_time; +typedef double mk_rate; +typedef void (*mk_deferred_call)(void*); + +#define B_UNDEFINED_MK_TIME ((mk_time) -1) + +enum transport_status { + B_TRANSPORT_RUNNING, + B_TRANSPORT_STOPPED, + B_TRANSPORT_PAUSED +}; + +enum channel_selector { + B_VIDEO_MAIN_CHANNEL, + B_VIDEO_MONITOR_CHANNEL, + B_AUDIO_FRONT_CHANNEL, + B_AUDIO_CENTER_CHANNEL, + B_AUDIO_REAR_CHANNEL, + B_AUDIO_SUB_CHANNEL, + B_AUDIO_MONITOR_CHANNEL, + B_MIDI_CHANNEL, + B_MISC_CHANNEL +}; + + +class BMediaRenderer; +class BTransport; +class BTimeBase; +class BMessage; +class BMediaChannel; + + +class BMediaEvent { +public: + virtual ~BMediaEvent() {}; + virtual mk_time Start() = 0; + virtual mk_time Duration(); + virtual bigtime_t CaptureTime(); +}; + + +class BEventStream { +public: + BEventStream(); + virtual ~BEventStream(); + + virtual mk_time Start(); + virtual void SetStart(mk_time); + virtual mk_time Duration(); + virtual void SetDuration(mk_time); + virtual BMediaEvent* GetEvent(BMediaChannel* channel) = 0; + virtual BMediaEvent* PeekEvent(BMediaChannel* channel, + mk_time asap = 0) = 0; + virtual status_t SeekToTime(BMediaChannel* channel, + mk_time time); + +private: + mk_time fStart; + mk_time fDuration; +}; + + +class BMediaRenderer { +public: + BMediaRenderer(const char* name = NULL, int32 priority = B_NORMAL_PRIORITY); + virtual ~BMediaRenderer(); + + virtual char* Name(); + virtual mk_time Latency(); + virtual BTransport* Transport(); + virtual void SetTransport(BTransport*); + virtual mk_time Start(); + virtual mk_time Duration(); + virtual BTimeBase* TimeBase(); + + virtual void Open(); + virtual void Close(); + virtual void WakeUp(); + virtual void TransportChanged(mk_time time, mk_rate rate, + transport_status status); + virtual void StreamChanged(); + + virtual void OpenReceived(); + virtual void CloseReceived(); + virtual void WakeUpReceived(); + virtual void TransportChangedReceived(mk_time time, mk_rate rate, + transport_status status); + virtual void StreamChangedReceived(); + +private: + static int32 _LoopThread(void* arg); + void LoopThread(); + + thread_id fLoopThread; + sem_id fLoopSem; + int32 fFlags; + mk_time fTCTime; + mk_rate fTCRate; + transport_status fTCStatus; + BLocker fLoopLock; + + char* fName; + BTransport* fTransport; +}; + + +class BTransport { +public: + BTransport(); + virtual ~BTransport(); + + virtual BTimeBase* TimeBase(); + virtual void SetTimeBase(BTimeBase*); + virtual BList* Renderers(); + virtual void AddRenderer(BMediaRenderer*); + virtual bool RemoveRenderer(BMediaRenderer*); + virtual transport_status Status(); + virtual void SetStatus(transport_status); + virtual mk_time PerformanceTime(); + virtual mk_rate PerformanceRate(); + virtual mk_time TimeOffset(); + virtual void SetTimeOffset(mk_time); + virtual mk_time MaximumLatency(); + virtual mk_time PerformanceStart(); + virtual mk_time PerformanceEnd(); + virtual void Open(); + virtual void Close(); + virtual void TransportChanged(); + virtual void TimeSkipped(); + virtual void RequestWakeUp(mk_time, BMediaRenderer*); + virtual void SeekToTime(mk_time); + virtual BMediaChannel* GetChannel(int32 selector); + +private: + BTimeBase* fTimeBase; + BList fRenderers; + BList fChannels; + BLocker fChannelListLock; + transport_status fStatus; + mk_time fTimeOffset; +}; + + +class BTimeBase { +public: + BTimeBase(mk_rate rate = 1.0); + virtual ~BTimeBase(); + + virtual BList* Transports(); + virtual void AddTransport(BTransport*); + virtual bool RemoveTransport(BTransport*); + virtual void TimeSkipped(); + virtual status_t CallAt(mk_time time, mk_deferred_call function, void* arg); + virtual mk_time Time(); + virtual mk_rate Rate(); + virtual mk_time TimeAt(bigtime_t system_time); + virtual bigtime_t SystemTimeAt(mk_time time); + virtual void Sync(mk_time time, bigtime_t system_time); + virtual bool IsAbsolute(); + +private: + static int32 _SnoozeThread(void* arg); + void SnoozeThread(); + + BList fTransports; + BList fDeferredCalls; + BLocker fLock; + mk_rate fRate; + mk_time fSyncT; + bigtime_t fSyncS; + mk_time fSnoozeUntil; + thread_id fSnoozeThread; +}; + + +class BMediaChannel { +public: + BMediaChannel(mk_rate rate, + BMediaRenderer* renderer = NULL, + BEventStream* source = NULL); + virtual ~BMediaChannel(); + + virtual BMediaRenderer* Renderer(); + virtual void SetRenderer(BMediaRenderer*); + virtual BEventStream* Source(); + virtual void SetSource(BEventStream*); + virtual mk_rate Rate(); + virtual void SetRate(mk_rate); + bool LockChannel(); + status_t LockWithTimeout(bigtime_t); + void UnlockChannel(); + virtual void StreamChanged(); + +private: + mk_rate fRate; + BMediaRenderer* fRenderer; + BEventStream* fSource; + BLocker fChannelLock; +}; + + +#endif diff --git a/src/kits/media/OldSoundFile.cpp b/src/kits/media/OldSoundFile.cpp new file mode 100644 index 0000000000..a806176d50 --- /dev/null +++ b/src/kits/media/OldSoundFile.cpp @@ -0,0 +1,367 @@ +//OldSoundFile.h is replaced by SoundFile.h +//OldSoundFile.cpp is replaced by SoundFile.cpp + +#if 0 + +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: OldSoundFile.cpp + * DESCR: + ***********************************************************************/ +#include +#include "debug.h" + +/************************************************************* + * public BSoundFile + *************************************************************/ + +BSoundFile::BSoundFile() +{ + UNIMPLEMENTED(); +} + + +BSoundFile::BSoundFile(const entry_ref *ref, + uint32 open_mode) +{ + UNIMPLEMENTED(); +} + + +BSoundFile::~BSoundFile() +{ + UNIMPLEMENTED(); +} + + +status_t +BSoundFile::InitCheck() const +{ + UNIMPLEMENTED(); + + return B_OK; +} + + +status_t +BSoundFile::SetTo(const entry_ref *ref, + uint32 open_mode) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +int32 +BSoundFile::FileFormat() const +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +int32 +BSoundFile::SamplingRate() const +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +int32 +BSoundFile::CountChannels() const +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +int32 +BSoundFile::SampleSize() const +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +int32 +BSoundFile::ByteOrder() const +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +int32 +BSoundFile::SampleFormat() const +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +int32 +BSoundFile::FrameSize() const +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +off_t +BSoundFile::CountFrames() const +{ + UNIMPLEMENTED(); + off_t dummy; + + return dummy; +} + + +bool +BSoundFile::IsCompressed() const +{ + UNIMPLEMENTED(); + bool dummy; + + return dummy; +} + + +int32 +BSoundFile::CompressionType() const +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +char * +BSoundFile::CompressionName() const +{ + UNIMPLEMENTED(); + return NULL; +} + + +int32 +BSoundFile::SetFileFormat(int32 format) +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +int32 +BSoundFile::SetSamplingRate(int32 fps) +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +int32 +BSoundFile::SetChannelCount(int32 spf) +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +int32 +BSoundFile::SetSampleSize(int32 bps) +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +int32 +BSoundFile::SetByteOrder(int32 bord) +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +int32 +BSoundFile::SetSampleFormat(int32 fmt) +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +int32 +BSoundFile::SetCompressionType(int32 type) +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +char * +BSoundFile::SetCompressionName(char *name) +{ + UNIMPLEMENTED(); + return NULL; +} + + +bool +BSoundFile::SetIsCompressed(bool tf) +{ + UNIMPLEMENTED(); + bool dummy; + + return dummy; +} + + +off_t +BSoundFile::SetDataLocation(off_t offset) +{ + UNIMPLEMENTED(); + off_t dummy; + + return dummy; +} + + +off_t +BSoundFile::SetFrameCount(off_t count) +{ + UNIMPLEMENTED(); + off_t dummy; + + return dummy; +} + + +size_t +BSoundFile::ReadFrames(char *buf, + size_t count) +{ + UNIMPLEMENTED(); + size_t dummy; + + return dummy; +} + + +size_t +BSoundFile::WriteFrames(char *buf, + size_t count) +{ + UNIMPLEMENTED(); + size_t dummy; + + return dummy; +} + + +off_t +BSoundFile::SeekToFrame(off_t n) +{ + UNIMPLEMENTED(); + off_t dummy; + + return dummy; +} + + +off_t +BSoundFile::FrameIndex() const +{ + UNIMPLEMENTED(); + off_t dummy; + + return dummy; +} + + +off_t +BSoundFile::FramesRemaining() const +{ + UNIMPLEMENTED(); + off_t dummy; + + return dummy; +} + +/************************************************************* + * private BSoundFile + *************************************************************/ + + +void +BSoundFile::_ReservedSoundFile1() +{ + UNIMPLEMENTED(); +} + + +void +BSoundFile::_ReservedSoundFile2() +{ + UNIMPLEMENTED(); +} + + +void +BSoundFile::_ReservedSoundFile3() +{ + UNIMPLEMENTED(); +} + + +void +BSoundFile::_init_raw_stats() +{ + UNIMPLEMENTED(); +} + + +status_t +BSoundFile::_ref_to_file(const entry_ref *ref) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +#endif \ No newline at end of file diff --git a/src/kits/media/OldSoundFile.h b/src/kits/media/OldSoundFile.h new file mode 100644 index 0000000000..4ac0d510f7 --- /dev/null +++ b/src/kits/media/OldSoundFile.h @@ -0,0 +1,98 @@ +/****************************************************************************** + + File: SoundFile.h + + Description: Interface for a format-insensitive sound file object. + + Copyright 1995-97, Be Incorporated + +******************************************************************************/ + + +#ifndef _SOUND_FILE_H +#define _SOUND_FILE_H + +#include +#include +#include + +enum // sound_format +{ B_UNKNOWN_FILE, + B_AIFF_FILE, + B_WAVE_FILE, + B_UNIX_FILE }; + +class BSoundFile { + +public: + BSoundFile(); + BSoundFile(const entry_ref *ref, + uint32 open_mode); + virtual ~BSoundFile(); + + status_t InitCheck() const; + + status_t SetTo(const entry_ref *ref, uint32 open_mode); + + int32 FileFormat() const; + int32 SamplingRate() const; + int32 CountChannels() const; + int32 SampleSize() const; + int32 ByteOrder() const; + int32 SampleFormat() const; + int32 FrameSize() const; + off_t CountFrames() const; + + bool IsCompressed() const; + int32 CompressionType() const; + char *CompressionName() const; + + virtual int32 SetFileFormat(int32 format); + virtual int32 SetSamplingRate(int32 fps); + virtual int32 SetChannelCount(int32 spf); + virtual int32 SetSampleSize(int32 bps); + virtual int32 SetByteOrder(int32 bord); + virtual int32 SetSampleFormat(int32 fmt); + virtual int32 SetCompressionType(int32 type); + virtual char *SetCompressionName(char *name); + virtual bool SetIsCompressed(bool tf); + virtual off_t SetDataLocation(off_t offset); + virtual off_t SetFrameCount(off_t count); + + size_t ReadFrames(char *buf, size_t count); + size_t WriteFrames(char *buf, size_t count); + virtual off_t SeekToFrame(off_t n); + off_t FrameIndex() const; + off_t FramesRemaining() const; + + BFile *fSoundFile; + +private: + +virtual void _ReservedSoundFile1(); +virtual void _ReservedSoundFile2(); +virtual void _ReservedSoundFile3(); + + int32 fFileFormat; + int32 fSamplingRate; + int32 fChannelCount; + int32 fSampleSize; + int32 fByteOrder; + int32 fSampleFormat; + + off_t fByteOffset; /* offset to first sample */ + + off_t fFrameCount; + off_t fFrameIndex; + + bool fIsCompressed; + int32 fCompressionType; + char *fCompressionName; + status_t fCStatus; + void _init_raw_stats(); + status_t _ref_to_file(const entry_ref *ref); + uint32 _reserved[4]; +}; + + +#endif // #ifndef _SOUND_FILE_H diff --git a/src/kits/media/OldSubscriber.cpp b/src/kits/media/OldSubscriber.cpp new file mode 100644 index 0000000000..88d62372a4 --- /dev/null +++ b/src/kits/media/OldSubscriber.cpp @@ -0,0 +1,169 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: OldSubscriber.cpp + * DESCR: + ***********************************************************************/ +#include +#include "debug.h" + +/************************************************************* + * public BSubscriber + *************************************************************/ + +BSubscriber::BSubscriber(const char *name) +{ + UNIMPLEMENTED(); +} + + +BSubscriber::~BSubscriber() +{ + UNIMPLEMENTED(); +} + + +status_t +BSubscriber::Subscribe(BAbstractBufferStream *stream) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BSubscriber::Unsubscribe() +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +subscriber_id +BSubscriber::ID() const +{ + UNIMPLEMENTED(); + subscriber_id dummy; + + return dummy; +} + + +const char * +BSubscriber::Name() const +{ + UNIMPLEMENTED(); + return NULL; +} + + +void +BSubscriber::SetTimeout(bigtime_t microseconds) +{ + UNIMPLEMENTED(); +} + + +bigtime_t +BSubscriber::Timeout() const +{ + UNIMPLEMENTED(); + bigtime_t dummy; + + return dummy; +} + + +status_t +BSubscriber::EnterStream(subscriber_id neighbor, + bool before, + void *userData, + enter_stream_hook entryFunction, + exit_stream_hook exitFunction, + bool background) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BSubscriber::ExitStream(bool synch) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +bool +BSubscriber::IsInStream() const +{ + UNIMPLEMENTED(); + bool dummy; + + return dummy; +} + +/************************************************************* + * protected BSubscriber + *************************************************************/ + +status_t +BSubscriber::_ProcessLoop(void *arg) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BSubscriber::ProcessLoop() +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +BAbstractBufferStream * +BSubscriber::Stream() const +{ + UNIMPLEMENTED(); + return NULL; +} + +/************************************************************* + * private BSubscriber + *************************************************************/ + +void +BSubscriber::_ReservedSubscriber1() +{ + UNIMPLEMENTED(); +} + + +void +BSubscriber::_ReservedSubscriber2() +{ + UNIMPLEMENTED(); +} + + +void +BSubscriber::_ReservedSubscriber3() +{ + UNIMPLEMENTED(); +} + + diff --git a/src/kits/media/OldSubscriber.h b/src/kits/media/OldSubscriber.h new file mode 100644 index 0000000000..4c8722e526 --- /dev/null +++ b/src/kits/media/OldSubscriber.h @@ -0,0 +1,100 @@ +/****************************************************************************** + + File: Subscriber.h + + Description: Support for communication with a buffer stream server + + Copyright 1995-97, Be Incorporated + +******************************************************************************/ + +#ifndef _SUBSCRIBER_H +#define _SUBSCRIBER_H + +#include +#include +#include + +/* ================ + declarations + ================ */ + +typedef bool (*enter_stream_hook)(void *userData, char *buffer, size_t count, + void *header); +typedef status_t (*exit_stream_hook)(void *userData, status_t error); + +/* ================ + Class definition for BSubscriber + ================ */ + +class BSubscriber +{ +public: + BSubscriber(const char *name = NULL); + virtual ~BSubscriber(); + +/* ================ + Gaining access to the Buffer Stream + ================ */ + + virtual status_t Subscribe(BAbstractBufferStream* stream); + virtual status_t Unsubscribe(); + + subscriber_id ID() const; + const char *Name() const; + + void SetTimeout(bigtime_t microseconds); + bigtime_t Timeout() const; + +/* ================ + Streaming functions. + ================ */ + + virtual status_t EnterStream(subscriber_id neighbor, + bool before, + void *userData, + enter_stream_hook entryFunction, + exit_stream_hook exitFunction, + bool background); + + virtual status_t ExitStream(bool synch=FALSE); + + bool IsInStream() const; + +/* ================ + Protected members (may be used by inherited classes) + ================ */ + +protected: + + static status_t _ProcessLoop(void *arg); + virtual status_t ProcessLoop(); + BAbstractBufferStream *Stream() const; + +/* ================ + Private members + ================ */ + +private: + +virtual void _ReservedSubscriber1(); +virtual void _ReservedSubscriber2(); +virtual void _ReservedSubscriber3(); + + char *fName; /* name given to constructor */ + subscriber_id fSubID; /* our subscriber_id */ + sem_id fSem; /* stream semaphore */ + BAbstractBufferStream *fStream; /* buffer stream */ + void *fUserData; /* arg to fStreamFn and fCompletionFn */ + enter_stream_hook fStreamFn; /* per-buffer user function */ + exit_stream_hook fCompletionFn; /* called after streaming stops */ + bool fCallStreamFn; /* true while we should call fStreamFn */ + bigtime_t fTimeout; /* time out while awaiting buffers */ + thread_id fBackThread; + sem_id fSynchLock; + + int32 fFileID; /* reserved for future use */ + uint32 _reserved[4]; +}; + +#endif // #ifdef _SUBSCRIBER_H diff --git a/src/kits/media/ParameterWeb.cpp b/src/kits/media/ParameterWeb.cpp new file mode 100644 index 0000000000..003f76e07e --- /dev/null +++ b/src/kits/media/ParameterWeb.cpp @@ -0,0 +1,3153 @@ +/*********************************************************************** + * AUTHOR: Zousar Shaker + * FILE: ParameterWeb.cpp + * DESCR: BParameterWeb, BParameterGroup, BParameter, BNullParameter, + * BContinuousParameter, BDiscreteParameter + ***********************************************************************/ +#include +#include +#include "debug.h" + +//--------BEGIN-ADDED-BY-ZS---------------------------------- + + //Comment keywords: + // FIXME: Something that should be fixed + // QUESTION: Something that needs clarification + // NOTICE: Explanation of what's going on + +typedef unsigned char byte; + +/* by Marcus Overhagen: Sorry Zousar, but I really want the program + * to be stopped when something is wrong! + */ +#if 1 /* always use these */ + +#define ASSERT_WRETURN_VALUE(CheckExpr,RetVal) \ + ASSERT(CheckExpr) + +#define ASSERT_RETURN(CheckExpr) \ + ASSERT(CheckExpr) + +#else /* and disable the other macros */ + +/************************************************************* + * Used to check assertions, and if the assertions fail, a + * value is returned. It is used only to check + * potentially erronious conditions INTERNAL to the code (ie: + * if I have forgotten to change a variable from NULL to some + * usable value) it is NOT used to check erronious input from + * the outside world (ie: if the user of a class passes NULL for + * some parameter). (ZS) + *************************************************************/ +#define ASSERT_WRETURN_VALUE(CheckExpr,RetVal)\ + if(!(CheckExpr))\ + {\ + return (RetVal);\ + } +/************************************************************* + * Used to check assertions, and if the assertions fail, the + * method returns (no return value). It is used only to check + * potentially erronious conditions INTERNAL to the code (ie: + * if I have forgotten to change a variable from NULL to some + * usable value) it is NOT used to check erronious input from + * the outside world (ie: if the user of a class passes NULL for + * some parameter). (ZS) + *************************************************************/ +#define ASSERT_RETURN(CheckExpr)\ + if(!(CheckExpr))\ + {\ + return;\ + } + +#endif /* end of disabled macros */ + +/* + The following is documentation on the flattened format + of structures/classes in this module: + + //--------BEGIN-CORE-BPARAMETER-STRUCT--------------------- + ?? (0x02040607): 4 bytes + BParameter Struct Size (in bytes): 4 bytes + ID: 4 bytes + Name String Length: 1 byte (??) + Name String: 'Name String Length' bytes + Kind String Length: 1 byte (??) + Kind String: 'Kind String Length' bytes + Unit String Length: 1 byte (??) + Unit String: 'Unit String Length' bytes + Inputs Count: 4 bytes + Inputs (pointers): ('Inputs Count')*4 bytes + Outputs Count: 4 bytes + Outputs (pointers): ('Outputs Count')*4 bytes + Media Type: 4 bytes + ChannelCount: 4 bytes + Flags: 4 bytes + //---------END-CORE-BPARAMETER-STRUCT----------------------- + //--------BEGIN-BCONTINUOUSPARAMETER-STRUCT--------- + Min: 4 bytes (as float) + Max: 4 bytes (as float) + Stepping: 4 bytes (as float) + Response: 4 bytes (as int or enum) + Factor: 4 bytes (as float) + Offset: 4 bytes (as float) + //--------END-BCONTINUOUSPARAMETER-STRUCT------------- + //--------BEGIN-BDISCRETEPARAMETER-STRUCT---------------- + NumItems: 4 bytes (as int) + //for each item BEGIN + Item Name String Length: 1 byte + Item Name String: 'Item Name String Length' bytes + Item Value: 4 bytes (as int) + //for each item END + //--------END-BDISCRETEPARAMETER-STRUCT------------------- + + //--------BEGIN-CORE-BPARAMETERGROUP-STRUCT----------- + ?? (0x03040507 OR 0x03040509 depending if the flags field is included or not???): 4 bytes + (possible) Flags: 4 bytes + Name String Length: 1 byte (??) + Name String: 'Name String Length' bytes + Param Count: 4 bytes + //for each Param BEGIN + Pointer: 4 bytes + Parameter Type: 4 bytes + Flattened Parameter Size: 4 bytes + Flattened Parameter: 'Flattened Parameter Size' bytes + //for each Param END + Subgroup Count: 4 bytes + //for each SubGroup BEGIN + Pointer: 4 bytes + MEDIA PARAMETER GROUP TYPE('BMCG' (opposite byte order in file)): 4 bytes + Flattened Group Size: 4 bytes + Flattened Group: 'Flattened Group Size' bytes + //for each SubGroup END + + //---------END-CORE-BPARAMETERGROUP-STRUCT-------------- + + //--------BEGIN-CORE-BPARAMETERWEB-STRUCT----------- + ?? 0x01030506: 4 bytes + ??: 4 bytes (is always 1) + Group Count: 4 bytes + Node (as media_node): 0x18 bytes (decimal 24 bytes) + //for each Group BEGIN + Flattened Group Size: 4 bytes + Flattened Group: 'Flattened Group Size' bytes + //for each Group END + //for each Group BEGIN + ??: 4 bytes (never get written to (holds uninitialized value)) + //for each Group END + //---------END-CORE-BPARAMETERWEB-STRUCT-------------- + +*/ + +//--------END-ADDED-BY-ZS------------------------------------- + + + +/************************************************************* + * + *************************************************************/ + +const char * const B_GENERIC = ""; +const char * const B_MASTER_GAIN = "Master"; +const char * const B_GAIN = "Gain"; +const char * const B_BALANCE = "Balance"; +const char * const B_FREQUENCY = "Frequency"; +const char * const B_LEVEL = "Level"; +const char * const B_SHUTTLE_SPEED = "Speed"; +const char * const B_CROSSFADE = "XFade"; +const char * const B_EQUALIZATION = "EQ"; +const char * const B_COMPRESSION = "Compression"; +const char * const B_QUALITY = "Quality"; +const char * const B_BITRATE = "Bitrate"; +const char * const B_GOP_SIZE = "GOPSize"; +const char * const B_MUTE = "Mute"; +const char * const B_ENABLE = "Enable"; +const char * const B_INPUT_MUX = "Input"; +const char * const B_OUTPUT_MUX = "Output"; +const char * const B_TUNER_CHANNEL = "Channel"; +const char * const B_TRACK = "Track"; +const char * const B_RECSTATE = "RecState"; +const char * const B_SHUTTLE_MODE = "Shuttle"; +const char * const B_RESOLUTION = "Resolution"; +const char * const B_COLOR_SPACE = "Colorspace"; +const char * const B_FRAME_RATE = "FrameRate"; +const char * const B_VIDEO_FORMAT = "VideoFormat"; +const char * const B_WEB_PHYSICAL_INPUT = "PhysInput"; +const char * const B_WEB_PHYSICAL_OUTPUT = "PhysOutput"; +const char * const B_WEB_ADC_CONVERTER = "ADC"; +const char * const B_WEB_DAC_CONVERTER = "DAC"; +const char * const B_WEB_LOGICAL_INPUT = "LogInput"; +const char * const B_WEB_LOGICAL_OUTPUT = "LogOutput"; +const char * const B_WEB_LOGICAL_BUS = "LogBus"; +const char * const B_WEB_BUFFER_INPUT = "DataInput"; +const char * const B_WEB_BUFFER_OUTPUT = "DataOutput"; +const char * const B_SIMPLE_TRANSPORT = "SimpleTransport"; + +/************************************************************* + * public BParameterWeb + *************************************************************/ + +BParameterWeb::BParameterWeb():mNode(media_node::null) +{ + mGroups = new BList(); + + mOldRefs = new BList(); + mNewRefs = new BList(); +} + + +BParameterWeb::~BParameterWeb() +{ + int i; + + if(mGroups != NULL) + { + for(i = 0;i < mGroups->CountItems(); i++) + { + BParameterGroup *CurrentGroup = static_cast(mGroups->ItemAt(i)); + + if(CurrentGroup != NULL) + { + delete CurrentGroup; + } + } + mGroups->MakeEmpty(); + delete mGroups; + mGroups = NULL; + } + + if(mOldRefs != NULL) + { + mOldRefs->MakeEmpty(); + delete mOldRefs; + } + + if(mNewRefs != NULL) + { + mNewRefs->MakeEmpty(); + delete mNewRefs; + } + +} + + +media_node +BParameterWeb::Node() +{ + return mNode; +} + + +BParameterGroup * +BParameterWeb::MakeGroup(const char *name) +{ + ASSERT_WRETURN_VALUE(mGroups != NULL,NULL); + + BParameterGroup *NewGroup = new BParameterGroup(this,name); + + mGroups->AddItem(NewGroup); + + return NewGroup; +} + + +int32 +BParameterWeb::CountGroups() +{ + ASSERT_WRETURN_VALUE(mGroups != NULL,0); + + return mGroups->CountItems(); +} + + +BParameterGroup * +BParameterWeb::GroupAt(int32 index) +{ + ASSERT_WRETURN_VALUE(mGroups != NULL,NULL); + + return static_cast(mGroups->ItemAt(index)); +} + + +int32 +BParameterWeb::CountParameters() +{ + //iterative traversal of the parameter web + //NOTE: This most definately should be tested and debugged. + + ASSERT_WRETURN_VALUE(mGroups != NULL,0); + + int32 RetVal = 0; + + int i; + int Limit = mGroups->CountItems(); + for(i = 0; i < Limit; i++) + { + BList *GroupStack = new BList(); + BList *IterStack = new BList(); + BParameterGroup *CurrentGroup = static_cast(mGroups->ItemAt(i)); + int *CurrentIter = new int(0); + + while(1) + { + if(CurrentGroup != NULL) + { + if((*CurrentIter) == 0) + //if this is the first time you're encountering this node, add the parameters within it. + { + RetVal += CurrentGroup->CountParameters(); + } + + if((*CurrentIter) < CurrentGroup->CountGroups()) + //if we've still got sub-groups within the current group to account for + { + IterStack->AddItem(CurrentIter); + GroupStack->AddItem(CurrentGroup); + + //update the current group + CurrentGroup = CurrentGroup->GroupAt(*CurrentIter); + //increment the current iter + (*CurrentIter)++; + + //create a new iter for the group you're descending into + CurrentIter = new int(0); + } + else if(GroupStack->CountItems()) + //we've taken care of all the subgroups of the current group, and there's still something on the stack, clean up, and pop it + { + //toss out the iter associated with this group + if(CurrentIter != NULL) + delete CurrentIter; + + CurrentGroup = static_cast(GroupStack->RemoveItem(GroupStack->CountItems()-1)); + CurrentIter = static_cast(IterStack->RemoveItem(IterStack->CountItems()-1)); + } + else + //we've taken care of all the subgroups of the current group, and there's nothing on the stack, we're done. + { + break; + } + + } + else if(GroupStack->CountItems()) + { + if(CurrentIter != NULL) + delete CurrentIter; + + CurrentGroup = static_cast(GroupStack->RemoveItem(GroupStack->CountItems()-1)); + CurrentIter = static_cast(IterStack->RemoveItem(IterStack->CountItems()-1)); + } + else + { + //NULL current group, and nothing on the stack, it's time to exit + break; + } + } + + if(CurrentIter != NULL) + delete CurrentIter; + + delete IterStack; + delete GroupStack; + } + + return RetVal; +} + + +BParameter * +BParameterWeb::ParameterAt(int32 index) +{ + //iterative traversal of the parameter web + //NOTE: This most definately should be tested and debugged. + + ASSERT_WRETURN_VALUE(mGroups != NULL,0); + + + int i; + int Limit = mGroups->CountItems(); + for(i = 0; i < Limit; i++) + { + BList *GroupStack = new BList(); + BList *IterStack = new BList(); + BParameterGroup *CurrentGroup = static_cast(mGroups->ItemAt(i)); + int *CurrentIter = new int(0); + + while(1) + { + if(CurrentGroup != NULL) + { + + if((*CurrentIter) == 0) + //if this is the first time you're encountering this node, add the parameters within it. + { + if(index < CurrentGroup->CountParameters()) + { + //delete the current iter (it is not on the stack) + if(CurrentIter != NULL) + delete CurrentIter; + + //delete items in the IterStack + for(int j = 0; j < IterStack->CountItems(); j++) + { + int *Temp = static_cast(IterStack->ItemAt(j)); + if(Temp != NULL) + delete CurrentIter; + } + IterStack->MakeEmpty(); + delete IterStack; + + GroupStack->MakeEmpty(); + delete GroupStack; + + return CurrentGroup->ParameterAt(index); + } + else + { + index -= CurrentGroup->CountParameters(); + } + } + + if((*CurrentIter) < CurrentGroup->CountGroups()) + //if we've still got sub-groups within the current group to account for + { + IterStack->AddItem(CurrentIter); + GroupStack->AddItem(CurrentGroup); + + //update the current group + CurrentGroup = CurrentGroup->GroupAt(*CurrentIter); + //increment the current iter + (*CurrentIter)++; + + //create a new iter for the group you're descending into + CurrentIter = new int(0); + } + else if(GroupStack->CountItems()) + //we've taken care of all the subgroups of the current group, and there's still something on the stack, clean up, and pop it + { + //toss out the iter associated with this group + if(CurrentIter != NULL) + delete CurrentIter; + + CurrentGroup = static_cast(GroupStack->RemoveItem(GroupStack->CountItems()-1)); + CurrentIter = static_cast(IterStack->RemoveItem(IterStack->CountItems()-1)); + } + else + //we've taken care of all the subgroups of the current group, and there's nothing on the stack, we're done. + { + break; + } + + } + else if(GroupStack->CountItems()) + { + if(CurrentIter != NULL) + delete CurrentIter; + + CurrentGroup = static_cast(GroupStack->RemoveItem(GroupStack->CountItems()-1)); + CurrentIter = static_cast(IterStack->RemoveItem(IterStack->CountItems()-1)); + } + else + { + //NULL current group, and nothing on the stack, it's time to exit + break; + } + } + + if(CurrentIter != NULL) + delete CurrentIter; + + delete IterStack; + delete GroupStack; + } + + return NULL; +} + + +bool +BParameterWeb::IsFixedSize() const +{ + return false; +} + + +type_code +BParameterWeb::TypeCode() const +{ + return B_MEDIA_PARAMETER_WEB_TYPE; +} + + +ssize_t +BParameterWeb::FlattenedSize() const +{ +/* + //--------BEGIN-CORE-BPARAMETERWEB-STRUCT----------- + ?? 0x01030506: 4 bytes + ??: 4 bytes (is always 1) + Group Count: 4 bytes + Node (as media_node): 0x18 bytes (decimal 24 bytes) + //for each Group BEGIN + Flattened Group Size: 4 bytes + Flattened Group: 'Flattened Group Size' bytes + //for each Group END + //for each Group BEGIN + ??: 4 bytes (never get written to (holds uninitialized value)) + //for each Group END + //---------END-CORE-BPARAMETERWEB-STRUCT-------------- +*/ + //36 guaranteed bytes, variable after that. + ssize_t RetVal = sizeof(int32) + 2*sizeof(int32) + sizeof(media_node); + + int i; + int limit; + + limit = mGroups->CountItems(); + for(i = 0; i < limit; i++) + { + BParameterGroup *CurrentGroup = static_cast(mGroups->ItemAt(i)); + if(CurrentGroup != NULL) + { + //overhead for each parameter flattened + RetVal += 8; //4 bytes for the flattened size, and 4 in the 'mystery parameter'... + RetVal += CurrentGroup->FlattenedSize(); + } + } + + return RetVal; +} + + +status_t +BParameterWeb::Flatten(void *buffer, + ssize_t size) const +{ + if(buffer == NULL) + return B_NO_INIT; + + //NOTICE: It is important that this value is the size returned by BParameterGroup::FlattenedSize, + // not by a descendent's override of this method. + ssize_t ActualFSize = BParameterWeb::FlattenedSize(); + + if(size < ActualFSize) + return B_NO_MEMORY; + + byte *CurrentPos = static_cast(buffer); + + //QUESTION: I have no idea where this magic number came from, and i'm not sure that it's + //being written in the correct byte order. + *(reinterpret_cast(CurrentPos)) = 0x01030506; + CurrentPos += sizeof(int32); + + //QUESTION: Another unknown constant. This one is different in style than the others though. + *(reinterpret_cast(CurrentPos)) = 1; + CurrentPos += sizeof(int32); + + + int i; + int NumItems; + void **Items; + + + ssize_t *TotalWrittenSubGroupsCount = reinterpret_cast(CurrentPos); + (*TotalWrittenSubGroupsCount) = 0; + CurrentPos += sizeof(ssize_t); + + if(mGroups != NULL) + { + NumItems = mGroups->CountItems(); + Items = static_cast(mGroups->Items()); + + for(i = 0; i < NumItems; i++) + { + BParameterGroup *CurrentSubGroup = static_cast(Items[i]); + if(CurrentSubGroup != NULL) + { + ssize_t FlattenedSubGroupSize = CurrentSubGroup->FlattenedSize(); + + //write the flattened size value + *(reinterpret_cast(CurrentPos)) = FlattenedSubGroupSize; + CurrentPos += sizeof(ssize_t); + + //write the flattened sub group + status_t SubGroupFlattenStatus = CurrentSubGroup->Flatten(CurrentPos,FlattenedSubGroupSize); + + if(SubGroupFlattenStatus != B_OK) + { + return SubGroupFlattenStatus; + } + + CurrentPos += FlattenedSubGroupSize; + + (*TotalWrittenSubGroupsCount)++; + } + } + } + + return B_OK; +} + + +bool +BParameterWeb::AllowsTypeCode(type_code code) const +{ + return (code == this->TypeCode()); +} + + +status_t +BParameterWeb::Unflatten(type_code c, + const void *buf, + ssize_t size) +{ + if(!this->AllowsTypeCode(c)) + return B_BAD_TYPE; + + if(buf == NULL) + return B_NO_INIT; + + //if the buffer is smaller than the size needed to read the + //signature field, the mystery field, the group count, and the Node, then there is a problem + if(size < static_cast(sizeof(int32) + sizeof(int32) + sizeof(ssize_t) + sizeof(media_node)) ) + { + return B_ERROR; + } + + const byte *CurrentPos = static_cast(buf); + + //QUESTION: I have no idea where this magic number came from, and i'm not sure that it's + //being read in the correct byte order. + if( *(reinterpret_cast(CurrentPos)) != 0x010300506) + { + return B_BAD_TYPE; + } + CurrentPos += sizeof(int32); + + //QUESTION: I have no idea where this magic number came from, and i'm not sure that it's + //being read in the correct byte order. THIS SURELY HAS SOME MEANING I'M NOT AWARE OF. + if( *(reinterpret_cast(CurrentPos)) != 1) + { + return B_ERROR; + } + CurrentPos += sizeof(int32); + + + //this variable is used to cap lengths/sizes read from the flattened buffer + //to maximum reasonable sizes to ensure that we don't run off the buffer. + int MaxByteLength; + int i; + + if(mGroups != NULL) + { + for(i = 0; i < mGroups->CountItems(); i++) + { + BParameterGroup *CurrentItem = static_cast(mGroups->ItemAt(i)); + if(CurrentItem != NULL) + { + delete CurrentItem; + } + } + mGroups->MakeEmpty(); + } + else + { + mGroups = new BList(); + } + + + + //read NumGroups + int NumItems = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(ssize_t); + + //MaxByteLength = size - ((offset into struct) + (minimum bytes REQUIRED AFTER name string)) + //In this case, the fields REQUIRED after the group list are: + //(none) + //TOTAL: 0 bytes + MaxByteLength = size - (((CurrentPos + sizeof(media_node)) - static_cast(buf)) + 0); + + ssize_t MinFlattenedItemSize = 8; + + //each item occupies a minimum of 8 bytes, so make sure that there is enough + //space remaining in the buffer for the specified NumItems (assuming each is minimum size) + NumItems = min_c(NumItems,MaxByteLength/MinFlattenedItemSize); + + + + //read Node + mNode = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(media_node); + + + status_t RetVal = B_OK; + + for(i = 0; i < NumItems; i++) + { + //read the flattened size of this item + ssize_t SubGroupSize = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(ssize_t); + + //MaxByteLength = size - ((current offset into struct) + (minimum bytes REQUIRED AFTER name string)) + //In this case, the fields REQUIRED after the group list are: + //NumGroups*(4 bytes) + //TOTAL: NumGroups*(4 bytes) bytes + MaxByteLength = size - ((CurrentPos - static_cast(buf)) + (NumItems*4)); + + //make sure that the SubGroupSize cannot overflow the buffer we are reading out of + SubGroupSize = min_c(SubGroupSize,MaxByteLength); + + + BParameterGroup *NewSubGroup = new BParameterGroup(this,"New_UnNamed_SubGroup"); + + RetVal = NewSubGroup->Unflatten(NewSubGroup->TypeCode(),CurrentPos,SubGroupSize); + + if(RetVal != B_OK) + { + delete NewSubGroup; + //don't return, because we should still fix references... + break; + } + + CurrentPos += SubGroupSize; + + //add the item to the list + mGroups->AddItem(NewSubGroup); + + } + + + //fix all references + if((mOldRefs != NULL) && (mNewRefs != NULL)) + { + int limit = this->CountParameters(); + for(i = 0; i < limit; i++) + { + BParameter *CurrentParam = this->ParameterAt(i); + if(CurrentParam != NULL) + { + CurrentParam->FixRefs(*mOldRefs,*mNewRefs); + } + } + + this->mOldRefs->MakeEmpty(); + this->mNewRefs->MakeEmpty(); + } + + + return RetVal; +} + +/************************************************************* + * private BParameterWeb + *************************************************************/ + +/* +unimplemented +BParameterWeb::BParameterWeb(const BParameterWeb &clone) +BParameterWeb &BParameterWeb::operator=(const BParameterWeb &clone) +*/ + +status_t BParameterWeb::_Reserved_ControlWeb_0(void *) { return B_ERROR; } +status_t BParameterWeb::_Reserved_ControlWeb_1(void *) { return B_ERROR; } +status_t BParameterWeb::_Reserved_ControlWeb_2(void *) { return B_ERROR; } +status_t BParameterWeb::_Reserved_ControlWeb_3(void *) { return B_ERROR; } +status_t BParameterWeb::_Reserved_ControlWeb_4(void *) { return B_ERROR; } +status_t BParameterWeb::_Reserved_ControlWeb_5(void *) { return B_ERROR; } +status_t BParameterWeb::_Reserved_ControlWeb_6(void *) { return B_ERROR; } +status_t BParameterWeb::_Reserved_ControlWeb_7(void *) { return B_ERROR; } + +void +BParameterWeb::AddRefFix(void *oldItem, + void *newItem) +{ + ASSERT_RETURN(mOldRefs != NULL); + ASSERT_RETURN(mNewRefs != NULL); + + mOldRefs->AddItem(oldItem); + mNewRefs->AddItem(newItem); +} + +/************************************************************* + * private BParameterGroup + *************************************************************/ + +BParameterGroup::BParameterGroup(BParameterWeb *web, + const char *name):mWeb(web) +{ + mControls = new BList(); + mGroups = new BList(); + + int NameLength = 0; + if(name != NULL) + { + NameLength = strlen(name); + } + mName = new char[NameLength + 1]; + memcpy(mName,name,NameLength); + mName[NameLength] = 0; + + mFlags = 0; +} + + +BParameterGroup::~BParameterGroup() +{ + int i; + + int NumItems; + void **Items; + + if(mControls != NULL) + { + NumItems = mControls->CountItems(); + Items = static_cast(mControls->Items()); + + for(i = 0; i < NumItems; i++) + { + if(Items[i] != NULL) + { + delete Items[i]; + Items[i] = NULL; + } + } + } + + if(mGroups != NULL) + { + NumItems = mGroups->CountItems(); + Items = static_cast(mControls->Items()); + + for(i = 0; i < NumItems; i++) + { + if(Items[i] != NULL) + { + delete Items[i]; + Items[i] = NULL; + } + } + } + + if(mName != NULL) + { + delete[] mName; + mName = NULL; + } + +} + +/************************************************************* + * public BParameterGroup + *************************************************************/ + +BParameterWeb * +BParameterGroup::Web() const +{ + return mWeb; +} + + +const char * +BParameterGroup::Name() const +{ + return mName; +} + + +void +BParameterGroup::SetFlags(uint32 flags) +{ + mFlags = flags; +} + + +uint32 +BParameterGroup::Flags() const +{ + return mFlags; +} + + +BNullParameter * +BParameterGroup::MakeNullParameter(int32 id, + media_type m_type, + const char *name, + const char *kind) +{ + ASSERT_WRETURN_VALUE(mControls != NULL,NULL); + + BNullParameter *NewParam = new BNullParameter(id,m_type,mWeb,name,kind); + + NewParam->mGroup = this; + + mControls->AddItem(NewParam); + + return NewParam; +} + + +BContinuousParameter * +BParameterGroup::MakeContinuousParameter(int32 id, + media_type m_type, + const char *name, + const char *kind, + const char *unit, + float minimum, + float maximum, + float stepping) +{ + ASSERT_WRETURN_VALUE(mControls != NULL,NULL); + + BContinuousParameter *NewParam = new BContinuousParameter(id,m_type,mWeb,name,kind,unit,minimum,maximum,stepping); + + NewParam->mGroup = this; + + mControls->AddItem(NewParam); + + return NewParam; +} + + +BDiscreteParameter * +BParameterGroup::MakeDiscreteParameter(int32 id, + media_type m_type, + const char *name, + const char *kind) +{ + ASSERT_WRETURN_VALUE(mControls != NULL,NULL); + + BDiscreteParameter *NewParam = new BDiscreteParameter(id,m_type,mWeb,name,kind); + + NewParam->mGroup = this; + + mControls->AddItem(NewParam); + + return NewParam; +} + + +BParameterGroup * +BParameterGroup::MakeGroup(const char *name) +{ + ASSERT_WRETURN_VALUE(mGroups != NULL,NULL); + + BParameterGroup *NewGroup = new BParameterGroup(mWeb,name); + + mGroups->AddItem(NewGroup); + + return NewGroup; +} + + +int32 +BParameterGroup::CountParameters() +{ + ASSERT_WRETURN_VALUE(mControls != NULL,0); + + return mControls->CountItems(); +} + + +BParameter * +BParameterGroup::ParameterAt(int32 index) +{ + ASSERT_WRETURN_VALUE(mControls != NULL,NULL); + + return static_cast(mControls->ItemAt(index)); +} + + +int32 +BParameterGroup::CountGroups() +{ + ASSERT_WRETURN_VALUE(mGroups != NULL,0); + + return mGroups->CountItems(); +} + + +BParameterGroup * +BParameterGroup::GroupAt(int32 index) +{ + ASSERT_WRETURN_VALUE(mGroups != NULL,NULL); + + return static_cast(mGroups->ItemAt(index)); +} + + +bool +BParameterGroup::IsFixedSize() const +{ + return false; +} + + +type_code +BParameterGroup::TypeCode() const +{ + return B_MEDIA_PARAMETER_GROUP_TYPE; +} + + +ssize_t +BParameterGroup::FlattenedSize() const +{ + ASSERT_WRETURN_VALUE(mControls != NULL,0); + ASSERT_WRETURN_VALUE(mGroups != NULL,0); + /* + //--------BEGIN-CORE-BPARAMETERGROUP-STRUCT----------- + ?? (0x03040507 OR 0x03040509 depending if the flags field is included or not???): 4 bytes + (possible) Flags: 4 bytes + Name String Length: 1 byte (??) + Name String: 'Name String Length' bytes + Param Count: 4 bytes + //for each Param BEGIN + Pointer: 4 bytes + Parameter Type: 4 bytes + Flattened Parameter Size: 4 bytes + Flattened Parameter: 'Flattened Parameter Size' bytes + //for each Param END + Subgroup Count: 4 bytes + //for each SubGroup BEGIN + Pointer: 4 bytes + MEDIA PARAMETER GROUP TYPE('BMCG' (opposite byte order in file)): 4 bytes + Flattened Group Size: 4 bytes + Flattened Group: 'Flattened Group Size' bytes + //for each SubGroup END + + //---------END-CORE-BPARAMETERGROUP-STRUCT-------------- + */ + //13 guaranteed bytes, variable after that. + ssize_t RetVal = 13; + + if(mFlags != 0) + { + RetVal += 4; + } + + if(mName != NULL) + { + RetVal += min_c(strlen(mName),255); + } + + int i; + int limit; + + limit = mControls->CountItems(); + for(i = 0; i < limit; i++) + { + BParameter *CurrentParameter = static_cast(mControls->ItemAt(i)); + if(CurrentParameter != NULL) + { + //overhead for each parameter flattened + RetVal += 16; + RetVal += CurrentParameter->FlattenedSize(); + } + } + + limit = mGroups->CountItems(); + for(i = 0; i < limit; i++) + { + BParameterGroup *CurrentGroup = static_cast(mGroups->ItemAt(i)); + if(CurrentGroup != NULL) + { + //overhead for each group flattened + RetVal += 16; + RetVal += CurrentGroup->FlattenedSize(); + } + } + + + return RetVal; +} + + +status_t +BParameterGroup::Flatten(void *buffer, + ssize_t size) const +{ + if(buffer == NULL) + return B_NO_INIT; + + //NOTICE: It is important that this value is the size returned by BParameterGroup::FlattenedSize, + // not by a descendent's override of this method. + ssize_t ActualFSize = BParameterGroup::FlattenedSize(); + + if(size < ActualFSize) + return B_NO_MEMORY; + + byte *CurrentPos = static_cast(buffer); + + //QUESTION: I have no idea where this magic number came from, and i'm not sure that it's + //being written in the correct byte order. + if(mFlags == 0) + { + *(reinterpret_cast(CurrentPos)) = 0x03040507; + CurrentPos += sizeof(int32); + } + else + { + *(reinterpret_cast(CurrentPos)) = 0x03040509; + CurrentPos += sizeof(int32); + + *(reinterpret_cast(CurrentPos)) = mFlags; + CurrentPos += sizeof(uint32); + } + + //flatten and write the name string + byte NameStringLength = 0; + if(mName != NULL) + { + NameStringLength = min_c(strlen(mName),255); + } + *(reinterpret_cast(CurrentPos)) = NameStringLength; + CurrentPos += sizeof(byte); + + memcpy(CurrentPos,mName,NameStringLength); + CurrentPos += NameStringLength; + + + int i; + int NumItems; + void **Items; + + ssize_t *TotalWrittenParamsCount = reinterpret_cast(CurrentPos); + (*TotalWrittenParamsCount) = 0; + CurrentPos += sizeof(ssize_t); + + if(mControls != NULL) + { + NumItems = mControls->CountItems(); + Items = static_cast(mControls->Items()); + + for(i = 0; i < NumItems; i++) + { + BParameter *CurrentParam = static_cast(Items[i]); + if(CurrentParam != NULL) + { + //write the pointer value + *(reinterpret_cast(CurrentPos)) = CurrentParam; + CurrentPos += sizeof(BParameter *); + + //write the type value + *(reinterpret_cast(CurrentPos)) = CurrentParam->Type(); + CurrentPos += sizeof(BParameter::media_parameter_type); + + ssize_t FlattenedParamSize = CurrentParam->FlattenedSize(); + + //write the flattened size value + *(reinterpret_cast(CurrentPos)) = FlattenedParamSize; + CurrentPos += sizeof(ssize_t); + + //write the flattened parameter + status_t ParamFlattenStatus = CurrentParam->Flatten(CurrentPos,FlattenedParamSize); + + if(ParamFlattenStatus != B_OK) + { + return ParamFlattenStatus; + } + + CurrentPos += FlattenedParamSize; + + (*TotalWrittenParamsCount)++; + } + } + } + + ssize_t *TotalWrittenSubGroupsCount = reinterpret_cast(CurrentPos); + (*TotalWrittenSubGroupsCount) = 0; + CurrentPos += sizeof(ssize_t); + + if(mGroups != NULL) + { + NumItems = mGroups->CountItems(); + Items = static_cast(mGroups->Items()); + + for(i = 0; i < NumItems; i++) + { + BParameterGroup *CurrentSubGroup = static_cast(Items[i]); + if(CurrentSubGroup != NULL) + { + //write the pointer value + *(reinterpret_cast(CurrentPos)) = CurrentSubGroup; + CurrentPos += sizeof(BParameterGroup *); + + //write the type code value + *(reinterpret_cast(CurrentPos)) = CurrentSubGroup->TypeCode(); + CurrentPos += sizeof(type_code); + + ssize_t FlattenedSubGroupSize = CurrentSubGroup->FlattenedSize(); + + //write the flattened size value + *(reinterpret_cast(CurrentPos)) = FlattenedSubGroupSize; + CurrentPos += sizeof(ssize_t); + + //write the flattened sub group + status_t SubGroupFlattenStatus = CurrentSubGroup->Flatten(CurrentPos,FlattenedSubGroupSize); + + if(SubGroupFlattenStatus != B_OK) + { + return SubGroupFlattenStatus; + } + + CurrentPos += FlattenedSubGroupSize; + + (*TotalWrittenSubGroupsCount)++; + } + } + } + + return B_OK; +} + + +bool +BParameterGroup::AllowsTypeCode(type_code code) const +{ + return (code == this->TypeCode()); +} + + +status_t +BParameterGroup::Unflatten(type_code c, + const void *buf, + ssize_t size) +{ + if(!this->AllowsTypeCode(c)) + return B_BAD_TYPE; + + if(buf == NULL) + return B_NO_INIT; + + //if the buffer is smaller than the size needed to read the + //signature field, then there is a problem + if(size < static_cast(sizeof(int32)) ) + { + return B_ERROR; + } + + const byte *CurrentPos = static_cast(buf); + + uint32 Flags = 0; + + //QUESTION: I have no idea where this magic number came from, and i'm not sure that it's + //being read in the correct byte order. + if( *(reinterpret_cast(CurrentPos)) == 0x03040507) + { + CurrentPos += sizeof(int32); + } + else if( *(reinterpret_cast(CurrentPos)) == 0x03040509) + { + CurrentPos += sizeof(int32); + + //check to make sure we've got room to read the flags field + if(size < static_cast(sizeof(int32) + sizeof(uint32))) + { + return B_ERROR; + } + + Flags = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(uint32); + } + else + { + return B_BAD_TYPE; + } + + this->mFlags = Flags; + + + + + //this variable is used to cap lengths/sizes read from the flattened buffer + //to maximum reasonable sizes to ensure that we don't run off the buffer. + int32 MaxByteLength; + + //read the name string + byte NameStringLength = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(byte); + + //MaxByteLength = size - ((current offset into struct) + (minimum bytes REQUIRED AFTER name string)) + //In this case, the fields REQUIRED after the name string are: + //Param Count (4 bytes) + //Subgroup Count (4 bytes) + //TOTAL: 8 bytes + MaxByteLength = size - ((CurrentPos - static_cast(buf)) + 8); + + NameStringLength = min_c(NameStringLength,MaxByteLength); + + if(mName != NULL) + { + delete[] mName; + mName = NULL; + } + mName = new char[NameStringLength + 1]; + memcpy(mName,CurrentPos,NameStringLength); + mName[NameStringLength] = 0; + CurrentPos += NameStringLength; + + + + + //Clear all existing parameters/subgroups + int i; + if(mControls != NULL) + { + for(i = 0; i < mControls->CountItems(); i++) + { + BParameter *CurrentItem = static_cast(mControls->ItemAt(i)); + if(CurrentItem != NULL) + { + delete CurrentItem; + } + } + mControls->MakeEmpty(); + } + else + { + mControls = new BList(); + } + + if(mGroups != NULL) + { + for(i = 0; i < mGroups->CountItems(); i++) + { + BParameterGroup *CurrentItem = static_cast(mGroups->ItemAt(i)); + if(CurrentItem != NULL) + { + delete CurrentItem; + } + } + mGroups->MakeEmpty(); + } + else + { + mGroups = new BList(); + } + + + + //read NumParameters + ssize_t NumItems = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(ssize_t); + + //MaxByteLength = size - ((current offset into struct) + (minimum bytes REQUIRED AFTER name string)) + //In this case, the fields REQUIRED after the name string are: + //Subgroup Count (4 bytes) + //TOTAL: 4 bytes + MaxByteLength = size - ((CurrentPos - static_cast(buf)) + 4); + + ssize_t MinFlattenedItemSize(12); + + //each item occupies a minimum of 12 bytes, so make sure that there is enough + //space remaining in the buffer for the specified NumItems (assuming each is minimum size) + NumItems = min_c(NumItems,MaxByteLength/MinFlattenedItemSize); + + + for(i = 0; i < NumItems; i++) + { + //read the old pointer value of this item + BParameter *OldPointerVal = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(BParameter *); + + //read the media_parameter_type of this item + BParameter::media_parameter_type ParamType = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(BParameter::media_parameter_type); + + //read the flattened size of this item + ssize_t ParamSize = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(ssize_t); + + //MaxByteLength = size - ((current offset into struct) + (minimum bytes REQUIRED AFTER name string)) + //In this case, the fields REQUIRED after the name string are: + //Subgroup Count (4 bytes) + //TOTAL: 4 bytes + MaxByteLength = size - ((CurrentPos - static_cast(buf)) + 4); + + //make sure that the ParamSize cannot overflow the buffer we are reading out of + ParamSize = min_c(ParamSize,MaxByteLength); + + BParameter *NewParam = this->MakeControl(ParamType); + + //need to be careful because ParamType could be invalid + if(NewParam == NULL) + { + return B_ERROR; + } + + status_t RetVal = NewParam->Unflatten(NewParam->TypeCode(),CurrentPos,ParamSize); + + if(RetVal != B_OK) + { + delete NewParam; + return RetVal; + } + + CurrentPos += ParamSize; + + //add the item to the list + mControls->AddItem(NewParam); + + //add it's old pointer value to the RefFix list kept by the owner web + if(mWeb != NULL) + { + mWeb->AddRefFix(OldPointerVal,NewParam); + } + } + + + + + + //read NumSubGroups + NumItems = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(ssize_t); + + //MaxByteLength = size - ((current offset into struct) + (minimum bytes REQUIRED AFTER name string)) + //In this case, the fields REQUIRED after the name string are: + //(none) + //TOTAL: 0 bytes + MaxByteLength = size - ((CurrentPos - static_cast(buf)) + 0); + + MinFlattenedItemSize = 12; + + //each item occupies a minimum of 12 bytes, so make sure that there is enough + //space remaining in the buffer for the specified NumItems (assuming each is minimum size) + NumItems = min_c(NumItems,MaxByteLength/MinFlattenedItemSize); + + + for(i = 0; i < NumItems; i++) + { + //read the old pointer value of this item + BParameter *OldPointerVal = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(BParameter *); + + //read the type_code of this item + type_code BufTypeCode = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(type_code); + + //read the flattened size of this item + ssize_t SubGroupSize = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(ssize_t); + + //MaxByteLength = size - ((current offset into struct) + (minimum bytes REQUIRED AFTER name string)) + //In this case, the fields REQUIRED after the name string are: + //(none) + //TOTAL: 0 bytes + MaxByteLength = size - ((CurrentPos - static_cast(buf)) + 0); + + //make sure that the SubGroupSize cannot overflow the buffer we are reading out of + SubGroupSize = min_c(SubGroupSize,MaxByteLength); + + + BParameterGroup *NewSubGroup = new BParameterGroup(mWeb,"New_UnNamed_SubGroup"); + + status_t RetVal = NewSubGroup->Unflatten(BufTypeCode,CurrentPos,SubGroupSize); + + if(RetVal != B_OK) + { + delete NewSubGroup; + return RetVal; + } + + CurrentPos += SubGroupSize; + + //add the item to the list + mGroups->AddItem(NewSubGroup); + + //add it's old pointer value to the RefFix list kept by the owner web + if(mWeb != NULL) + { + mWeb->AddRefFix(OldPointerVal,NewSubGroup); + } + } + + + + + + + + + + + return B_OK; +} + +/************************************************************* + * private BParameterGroup + *************************************************************/ + +/* +// unimplemented +BParameterGroup::BParameterGroup() +BParameterGroup::BParameterGroup(const BParameterGroup &clone) +BParameterGroup &BParameterGroup::operator=(const BParameterGroup &clone) +*/ + +status_t BParameterGroup::_Reserved_ControlGroup_0(void *) { return B_ERROR; } +status_t BParameterGroup::_Reserved_ControlGroup_1(void *) { return B_ERROR; } +status_t BParameterGroup::_Reserved_ControlGroup_2(void *) { return B_ERROR; } +status_t BParameterGroup::_Reserved_ControlGroup_3(void *) { return B_ERROR; } +status_t BParameterGroup::_Reserved_ControlGroup_4(void *) { return B_ERROR; } +status_t BParameterGroup::_Reserved_ControlGroup_5(void *) { return B_ERROR; } +status_t BParameterGroup::_Reserved_ControlGroup_6(void *) { return B_ERROR; } +status_t BParameterGroup::_Reserved_ControlGroup_7(void *) { return B_ERROR; } + + +BParameter * +BParameterGroup::MakeControl(int32 type) +{ + /*NOTE: + Creates a new parameter for addition within this with a type defined by the passed 'type' parameter, + BUT DOES NOT ADD THE CREATED PARAMETER TO THE INTERNAL LIST OF PARAMETERS + */ + switch(type) + { + case(BParameter::B_NULL_PARAMETER): + { + return new BNullParameter(-1,B_MEDIA_UNKNOWN_TYPE,mWeb,"New_UnNamed_NullParameter",B_GENERIC); + } + break; + case(BParameter::B_DISCRETE_PARAMETER): + { + return new BDiscreteParameter(-1,B_MEDIA_UNKNOWN_TYPE,mWeb,"New_UnNamed_DiscreteParameter",B_GENERIC); + } + break; + case(BParameter::B_CONTINUOUS_PARAMETER): + { + return new BContinuousParameter(-1,B_MEDIA_UNKNOWN_TYPE,mWeb,"New_UnNamed_ContinuousParameter",B_GENERIC,"",0,100,1); + } + break; + default: + { + return NULL; + } + break; + } + return NULL; +} + +/************************************************************* + * public BParameter + *************************************************************/ + +BParameter::media_parameter_type +BParameter::Type() const +{ + return mType; +} + + +BParameterWeb * +BParameter::Web() const +{ + return mWeb; +} + + +BParameterGroup * +BParameter::Group() const +{ + return mGroup; +} + + +const char * +BParameter::Name() const +{ + return mName; +} + + +const char * +BParameter::Kind() const +{ + return mKind; +} + + +const char * +BParameter::Unit() const +{ + return mUnit; +} + + +int32 +BParameter::ID() const +{ + return mID; +} + + +void +BParameter::SetFlags(uint32 flags) +{ + mFlags = flags; +} + + +uint32 +BParameter::Flags() const +{ + return mFlags; +} + + +status_t +BParameter::GetValue(void *buffer, + size_t *ioSize, + bigtime_t *when) +{ + UNIMPLEMENTED(); + /* + * XXX FIXME! call BControllable::GetControlValue() here. + */ + return B_BAD_VALUE; +} + + +status_t +BParameter::SetValue(const void *buffer, + size_t size, + bigtime_t when) +{ + UNIMPLEMENTED(); + /* + * XXX FIXME! call BControllable::SetControlValue() here. + */ + return B_BAD_VALUE; +} + + +int32 +BParameter::CountChannels() +{ + return mChannels; +} + + +void +BParameter::SetChannelCount(int32 channel_count) +{ + mChannels = channel_count; +} + + +media_type +BParameter::MediaType() +{ + return mMediaType; +} + + +void +BParameter::SetMediaType(media_type m_type) +{ + mMediaType = m_type; +} + + +int32 +BParameter::CountInputs() +{ + ASSERT_WRETURN_VALUE(mInputs != NULL,0); + + return mInputs->CountItems(); +} + + +BParameter * +BParameter::InputAt(int32 index) +{ + ASSERT_WRETURN_VALUE(mInputs != NULL,NULL); + + return static_cast(mInputs->ItemAt(index)); +} + + +void +BParameter::AddInput(BParameter *input) +{ + // BeBook has this method returning a status value, + // but it should be updated + if(input == NULL) + { + return; + } + + ASSERT_RETURN(mInputs != NULL); + + if(mInputs->HasItem(input)) + { + //if already in input list, don't duplicate. + return; + } + + mInputs->AddItem(input); + input->AddOutput(this); +} + + +int32 +BParameter::CountOutputs() +{ + ASSERT_WRETURN_VALUE(mOutputs != NULL,0); + + return mOutputs->CountItems(); +} + + +BParameter * +BParameter::OutputAt(int32 index) +{ + ASSERT_WRETURN_VALUE(mOutputs != NULL,NULL); + + return static_cast(mOutputs->ItemAt(index)); +} + + +void +BParameter::AddOutput(BParameter *output) +{ + // BeBook has this method returning a status value, + // but it should be updated + if(output == NULL) + { + return; + } + + ASSERT_RETURN(mOutputs != NULL); + + if(mOutputs->HasItem(output)) + { + //if already in output list, don't duplicate. + return; + } + + mOutputs->AddItem(output); + output->AddInput(this); +} + + +bool +BParameter::IsFixedSize() const +{ + return false; +} + + +type_code +BParameter::TypeCode() const +{ + return B_MEDIA_PARAMETER_TYPE; +} + + +ssize_t +BParameter::FlattenedSize() const +{ + /* + ?? (0x02040607): 4 bytes + BParameter Struct Size (in bytes): 4 bytes + ID: 4 bytes + Name String Length: 1 byte (??) + Name String: 'Name String Length' bytes + Kind String Length: 1 byte (??) + Kind String: 'Kind String Length' bytes + Unit String Length: 1 byte (??) + Unit String: 'Unit String Length' bytes + Inputs Count: 4 bytes + Inputs (pointers): ('Inputs Count')*4 bytes + Outputs Count: 4 bytes + Outputs (pointers): ('Outputs Count')*4 bytes + Media Type: 4 bytes + ChannelCount: 4 bytes + Flags: 4 bytes + */ + //35 bytes are guaranteed, after that, add the variable length parts. + ssize_t RetVal = 35; + + if(mName != NULL) RetVal += strlen(mName); + + if(mKind != NULL) RetVal += strlen(mKind); + + if(mUnit != NULL) RetVal += strlen(mUnit); + + if(mInputs != NULL) RetVal += mInputs->CountItems()*sizeof(BParameter *); + + if(mOutputs != NULL) RetVal += mOutputs->CountItems()*sizeof(BParameter *); + + return RetVal; +} + + +status_t +BParameter::Flatten(void *buffer, + ssize_t size) const +{ + if(buffer == NULL) + return B_NO_INIT; + + //NOTICE: It is important that this value is the size returned by BParameter::FlattenedSize, + // not by a descendent's override of this method. + ssize_t ActualFSize = BParameter::FlattenedSize(); + + if(size < ActualFSize) + return B_NO_MEMORY; + + byte *CurrentPos = static_cast(buffer); + + //QUESTION: I have no idea where this magic number came from, and i'm not sure that it's + //being written in the correct byte order. + *(reinterpret_cast(CurrentPos)) = 0x02040607; + CurrentPos += sizeof(int32); + + //flatten and write the struct size + *(reinterpret_cast(CurrentPos)) = ActualFSize; + CurrentPos += sizeof(ssize_t); + + //flatten and write the ID + *(reinterpret_cast(CurrentPos)) = mID; + CurrentPos += sizeof(int32); + + //flatten and write the name string + byte NameStringLength = 0; + if(mName != NULL) + { + NameStringLength = min_c(strlen(mName),255); + } + *(reinterpret_cast(CurrentPos)) = NameStringLength; + CurrentPos += sizeof(byte); + + memcpy(CurrentPos,mName,NameStringLength); + CurrentPos += NameStringLength; + + //flatten and write the kind string + byte KindStringLength = 0; + if(mKind != NULL) + { + KindStringLength = min_c(strlen(mKind),255); + } + *(reinterpret_cast(CurrentPos)) = KindStringLength; + CurrentPos += sizeof(byte); + + memcpy(CurrentPos,mKind,KindStringLength); + CurrentPos += KindStringLength; + + //flatten and write the unit string + byte UnitStringLength = 0; + if(mUnit != NULL) + { + UnitStringLength = min_c(strlen(mUnit),255); + } + *(reinterpret_cast(CurrentPos)) = UnitStringLength; + CurrentPos += sizeof(byte); + + memcpy(CurrentPos,mUnit,UnitStringLength); + CurrentPos += UnitStringLength; + + + //flatten and write the list of inputs + ssize_t NumInputs = 0; + if(mInputs != NULL) + { + NumInputs = mInputs->CountItems(); + } + *(reinterpret_cast(CurrentPos)) = NumInputs; + CurrentPos += sizeof(ssize_t); + + memcpy(CurrentPos,mInputs->Items(),sizeof(BParameter *)*NumInputs); + + + //flatten and write the list of outputs + ssize_t NumOutputs = 0; + if(mOutputs != NULL) + { + NumOutputs = mOutputs->CountItems(); + } + *(reinterpret_cast(CurrentPos)) = NumOutputs; + CurrentPos += sizeof(ssize_t); + + memcpy(CurrentPos,mOutputs->Items(),sizeof(BParameter *)*NumOutputs); + + + //flatten and write the media type + *(reinterpret_cast(CurrentPos)) = mMediaType; + CurrentPos += sizeof(media_type); + + //flatten and write the channel count + *(reinterpret_cast(CurrentPos)) = mChannels; + CurrentPos += sizeof(int32); + + //flatten and write the flags + *(reinterpret_cast(CurrentPos)) = mFlags; + CurrentPos += sizeof(uint32); + + + return B_OK; +} + + +bool +BParameter::AllowsTypeCode(type_code code) const +{ + return (code == this->TypeCode()); +} + + +status_t +BParameter::Unflatten(type_code c, + const void *buf, + ssize_t size) +{ + + if(!this->AllowsTypeCode(c)) + return B_BAD_TYPE; + + if(buf == NULL) + return B_NO_INIT; + + //if the buffer is smaller than the size needed to read the + //signature and struct size fields, then there is a problem + if(size < static_cast(sizeof(int32) + sizeof(ssize_t))) + { + return B_ERROR; + } + + const byte *CurrentPos = static_cast(buf); + + + //QUESTION: I have no idea where this magic number came from, and i'm not sure that it's + //being read in the correct byte order. + if( *(reinterpret_cast(CurrentPos)) != 0x02040607) + { + return B_BAD_TYPE; + } + CurrentPos += sizeof(int32); + + //read the struct size + ssize_t ParamStructSize = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(ssize_t); + + if(ParamStructSize > size) + { + //if the struct size is larger than the size of the buffer we were given, + //there's a problem + return B_MISMATCHED_VALUES; + } + + //if the struct doesn't meet the minimum size for + //a flattened BParameter, then return an error. + //MinFlattenedParamSize = + //ID (4 bytes) + //Name String Length (1 byte) + //Kind String Length (1 byte) + //Unit String Length (1 byte) + //Inputs Count (4 bytes) + //Outputs Count (4 bytes) + //Media Type (4 bytes) + //Channel Count (4 bytes) + //Flags (4 bytes) + //TOTAL: 27 bytes + const ssize_t MinFlattenedParamSize(27); + if(ParamStructSize < MinFlattenedParamSize) + { + return B_ERROR; + } + + //read the ID + this->mID = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(int32); + + //this variable is used to cap lengths/sizes read from the flattened buffer + //to maximum reasonable sizes to ensure that we don't run off the buffer. + int32 MaxByteLength; + + //read the name string + byte NameStringLength = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(byte); + + //MaxByteLength = ParamStructSize - ((current offset into struct) + (minimum bytes REQUIRED AFTER name string)) + //In this case, the fields REQUIRED after the name string are: + //Kind String Length (1 byte) + //Unit String Length (1 byte) + //Inputs Count (4 bytes) + //Outputs Count (4 bytes) + //Media Type (4 bytes) + //Channel Count (4 bytes) + //Flags (4 bytes) + //TOTAL: 22 bytes + MaxByteLength = ParamStructSize - ((CurrentPos - static_cast(buf)) + 22); + + NameStringLength = min_c(NameStringLength,MaxByteLength); + + if(mName != NULL) + { + delete[] mName; + mName = NULL; + } + mName = new char[NameStringLength + 1]; + memcpy(mName,CurrentPos,NameStringLength); + mName[NameStringLength] = 0; + CurrentPos += NameStringLength; + + //read the kind string + byte KindStringLength = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(byte); + + //MaxByteLength = ParamStructSize - ((current offset into struct) + (minimum bytes REQUIRED AFTER kind string)) + //In this case, the fields REQUIRED after the kind string are: + //Unit String Length (1 byte) + //Inputs Count (4 bytes) + //Outputs Count (4 bytes) + //Media Type (4 bytes) + //Channel Count (4 bytes) + //Flags (4 bytes) + //TOTAL: 21 bytes + MaxByteLength = ParamStructSize - ((CurrentPos - static_cast(buf)) + 21); + + KindStringLength = min_c(KindStringLength,MaxByteLength); + + if(mKind != NULL) + { + delete[] mKind; + mKind = NULL; + } + mKind = new char[KindStringLength + 1]; + memcpy(mKind,CurrentPos,KindStringLength); + mKind[KindStringLength] = 0; + CurrentPos += KindStringLength; + + //read the unit string + byte UnitStringLength = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(byte); + + //MaxByteLength = ParamStructSize - ((current offset into struct) + (minimum bytes REQUIRED AFTER unit string)) + //In this case, the fields REQUIRED after the unit string are: + //Inputs Count (4 bytes) + //Outputs Count (4 bytes) + //Media Type (4 bytes) + //Channel Count (4 bytes) + //Flags (4 bytes) + //TOTAL: 20 bytes + MaxByteLength = ParamStructSize - ((CurrentPos - static_cast(buf)) + 20); + + UnitStringLength = min_c(UnitStringLength,MaxByteLength); + + if(mUnit != NULL) + { + delete[] mUnit; + mUnit = NULL; + } + mUnit = new char[UnitStringLength + 1]; + memcpy(mUnit,CurrentPos,UnitStringLength); + mUnit[UnitStringLength] = 0; + CurrentPos += UnitStringLength; + + //Set this flag to false to indicate that the pointer values in this parameter, have + //not been swapped. + mSwapDetected = false; + + //read the list of inputs + int i,j; + + ssize_t NumInputs = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(ssize_t); + + + //MaxByteLength = ParamStructSize - ((current offset into struct) + (minimum bytes REQUIRED AFTER inputs list)) + //In this case, the fields REQUIRED after the inputs list are: + //Outputs Count (4 bytes) + //Media Type (4 bytes) + //Channel Count (4 bytes) + //Flags (4 bytes) + //TOTAL: 16 bytes + MaxByteLength = ParamStructSize - ((CurrentPos - static_cast(buf)) + 16); + + NumInputs = min_c(NumInputs,static_cast(MaxByteLength/sizeof(BParameter *))); + + + if(this->mInputs == NULL) + { + this->mInputs = new BList(); + } + else + { + //if this object has an existing list of (valid) inputs, go to each one, removing this object + //as an output for each of the objects in the input list, then clear the list + if(mSwapDetected) + { + ssize_t OldInputCount = mInputs->CountItems(); + for(i = 0; i < OldInputCount; i++) + { + BParameter *CurrentParam = static_cast(this->mInputs->ItemAt(i)); + if((CurrentParam != NULL) && (CurrentParam->mOutputs != NULL)) + { + //Remove ALL instances of this parameter from the other parameter's + //output list + j = 0; + ssize_t CurrentParamsOutputCount = CurrentParam->mOutputs->CountItems(); + while(j < CurrentParamsOutputCount) + { + if(CurrentParam->mOutputs->ItemAt(j) == this) + { + //remove this item, update the CurrentParamsOutputCount, + //and DON'T increment j + CurrentParam->mOutputs->RemoveItem(j); + CurrentParamsOutputCount--; + } + else + { + //move on to the next one + j++; + } + } + } + } + } + this->mInputs->MakeEmpty(); + } + + for(i = 0; i < NumInputs; i++) + { + this->AddInput(*(reinterpret_cast(CurrentPos))); + CurrentPos += sizeof(BParameter *); + } + + + //read the list of outputs + ssize_t NumOutputs = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(ssize_t); + + + //MaxByteLength = ParamStructSize - ((current offset into struct) + (minimum bytes REQUIRED AFTER outputs list)) + //In this case, the fields REQUIRED after the outputs list are: + //Media Type (4 bytes) + //Channel Count (4 bytes) + //Flags (4 bytes) + //TOTAL: 12 bytes + MaxByteLength = ParamStructSize - ((CurrentPos - static_cast(buf)) + 12); + + NumOutputs = min_c(NumOutputs,static_cast(MaxByteLength/sizeof(BParameter *))); + + + if(this->mOutputs == NULL) + { + this->mOutputs = new BList(); + } + else + { + //if this object has an existing list of (valid) outputs, go to each one, removing this object + //as an input for each of the objects in the output list, then clear the list + if(mSwapDetected) + { + ssize_t OldOutputCount = mOutputs->CountItems(); + for(i = 0; i < OldOutputCount; i++) + { + BParameter *CurrentParam = static_cast(this->mOutputs->ItemAt(i)); + if((CurrentParam != NULL) && (CurrentParam->mInputs != NULL)) + { + //Remove ALL instances of this parameter from the other parameter's + //input list + j = 0; + ssize_t CurrentParamsInputCount = CurrentParam->mInputs->CountItems(); + while(j < CurrentParamsInputCount) + { + if(CurrentParam->mInputs->ItemAt(j) == this) + { + //remove this item, update the CurrentParamsInputCount, + //and DON'T increment j + CurrentParam->mInputs->RemoveItem(j); + CurrentParamsInputCount--; + } + else + { + //move on to the next one + j++; + } + } + } + } + } + this->mOutputs->MakeEmpty(); + } + + for(i = 0; i < NumOutputs; i++) + { + this->AddOutput(*(reinterpret_cast(CurrentPos))); + CurrentPos += sizeof(BParameter *); + } + + //read the media type + this->mMediaType = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(media_type); + + //read the channel count + this->mChannels = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(int32); + + //read the flags + this->mFlags = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(uint32); + + return B_OK; +} + +/************************************************************* + * private BParameter + *************************************************************/ + + +status_t BParameter::_Reserved_Control_0(void *) { return B_ERROR; } +status_t BParameter::_Reserved_Control_1(void *) { return B_ERROR; } +status_t BParameter::_Reserved_Control_2(void *) { return B_ERROR; } +status_t BParameter::_Reserved_Control_3(void *) { return B_ERROR; } +status_t BParameter::_Reserved_Control_4(void *) { return B_ERROR; } +status_t BParameter::_Reserved_Control_5(void *) { return B_ERROR; } +status_t BParameter::_Reserved_Control_6(void *) { return B_ERROR; } +status_t BParameter::_Reserved_Control_7(void *) { return B_ERROR; } + + +BParameter::BParameter(int32 id, + media_type m_type, + media_parameter_type type, + BParameterWeb *web, + const char *name, + const char *kind, + const char *unit):mID(id),mType(type),mWeb(web), + mGroup(NULL),mSwapDetected(true),mMediaType(m_type),mChannels(1),mFlags(0) +{ + mGroup = NULL; + + //copy the name string + if(name == NULL) + { + mName = new char[1]; + mName[0] = 0; + } + else + { + ssize_t NewNameLength = strlen(name); + mName = new char[NewNameLength + 1]; + mName[NewNameLength] = 0; + } + //copy the kind string + if(kind == NULL) + { + mKind = new char[1]; + mKind[0] = 0; + } + else + { + ssize_t NewKindLength = strlen(kind); + mKind = new char[NewKindLength + 1]; + mKind[NewKindLength] = 0; + } + //copy the unit string + if(unit == NULL) + { + mUnit = new char[1]; + mUnit[0] = 0; + } + else + { + ssize_t NewUnitLength = strlen(unit); + mUnit = new char[NewUnitLength + 1]; + mUnit[NewUnitLength] = 0; + } + + //create an empty input list + mInputs = new BList(); + + //create an empty output list + mOutputs = new BList(); + +} + + +BParameter::~BParameter() +{ + //don't worry about the mWeb/mGroup properties, you don't need + //to remove yourself from a web/group since the only way in which + //a parameter is destroyed is when the owner web/group destroys it + + if(mName != NULL) + { + delete[] mName; + mName = NULL; + } + if(mKind != NULL) + { + delete[] mKind; + mKind = NULL; + } + if(mUnit != NULL) + { + delete[] mUnit; + mUnit = NULL; + } + + int i,j; + + //clean up the inputs list + if(this->mInputs != NULL) + { + //if this object has an existing list of (valid)inputs, go to each one, removing this object + //as an output for each of the objects in the input list, then destroy the list + if(mSwapDetected) + { + ssize_t OldInputCount = mInputs->CountItems(); + for(i = 0; i < OldInputCount; i++) + { + BParameter *CurrentParam = static_cast(this->mInputs->ItemAt(i)); + if((CurrentParam != NULL) && (CurrentParam->mOutputs != NULL)) + { + //Remove ALL instances of this parameter from the other parameter's + //output list + j = 0; + ssize_t CurrentParamsOutputCount = CurrentParam->mOutputs->CountItems(); + while(j < CurrentParamsOutputCount) + { + if(CurrentParam->mOutputs->ItemAt(j) == this) + { + //remove this item, update the CurrentParamsOutputCount, + //and DON'T increment j + CurrentParam->mOutputs->RemoveItem(j); + CurrentParamsOutputCount--; + } + else + { + //move on to the next one + j++; + } + } + } + } + } + this->mInputs->MakeEmpty(); + delete mInputs; + mInputs = NULL; + } + + //clean up the outputs list + if(this->mOutputs != NULL) + { + //if this object has an existing list of (valid) outputs, go to each one, removing this object + //as an input for each of the objects in the output list, then clear the list + if(mSwapDetected) + { + ssize_t OldOutputCount = mOutputs->CountItems(); + for(i = 0; i < OldOutputCount; i++) + { + BParameter *CurrentParam = static_cast(this->mOutputs->ItemAt(i)); + if((CurrentParam != NULL) && (CurrentParam->mInputs != NULL)) + { + //Remove ALL instances of this parameter from the other parameter's + //input list + j = 0; + ssize_t CurrentParamsInputCount = CurrentParam->mInputs->CountItems(); + while(j < CurrentParamsInputCount) + { + if(CurrentParam->mInputs->ItemAt(j) == this) + { + //remove this item, update the CurrentParamsInputCount, + //and DON'T increment j + CurrentParam->mInputs->RemoveItem(j); + CurrentParamsInputCount--; + } + else + { + //move on to the next one + j++; + } + } + } + } + } + this->mOutputs->MakeEmpty(); + delete mOutputs; + mOutputs = NULL; + } + +} + + +void +BParameter::FixRefs(BList &old, + BList &updated) +{ + //Replaces references to (ie: pointers) items in the old list, with the + //coresponding items in the updated list. + //References are replaced in the mInputs and mOutputs lists. + + if(!mSwapDetected) + { + ASSERT_RETURN(mInputs); + ASSERT_RETURN(mOutputs); + + int i; + void **Items = static_cast(mInputs->Items()); + int NumItems = mInputs->CountItems(); + + + for(i = 0; i < NumItems; i++) + { + void *CurrentItem = Items[i]; + + int32 Index = old.IndexOf(CurrentItem); + + if(Index >= 0) + { + Items[i] = updated.ItemAt(Index); + } + } + + Items = static_cast(mOutputs->Items()); + NumItems = mOutputs->CountItems(); + + for(i = 0; i < NumItems; i++) + { + void *CurrentItem = Items[i]; + + int32 Index = old.IndexOf(CurrentItem); + + if(Index >= 0) + { + Items[i] = updated.ItemAt(Index); + } + } + + mSwapDetected = true; + } + +} + +/************************************************************* + * public BContinuousParameter + *************************************************************/ + + +type_code +BContinuousParameter::ValueType() +{ + return B_FLOAT_TYPE; +} + + +float +BContinuousParameter::MinValue() +{ + return mMinimum; +} + + +float +BContinuousParameter::MaxValue() +{ + return mMaximum; +} + + +float +BContinuousParameter::ValueStep() +{ + return mStepping; +} + + +void +BContinuousParameter::SetResponse(int resp, + float factor, + float offset) +{ + mResponse = static_cast(resp); + mFactor = factor; + mOffset = offset; +} + + +void +BContinuousParameter::GetResponse(int *resp, + float *factor, + float *offset) +{ + if(resp != NULL) *resp = mResponse; + if(factor != NULL) *factor = mFactor; + if(offset != NULL) *offset = mOffset; +} + + +ssize_t +BContinuousParameter::FlattenedSize() const +{ + ssize_t RetVal = BParameter::FlattenedSize(); + + /* + Min: 4 bytes (as float) + Max: 4 bytes (as float) + Stepping: 4 bytes (as float) + Response: 4 bytes (as int or enum) + Factor: 4 bytes (as float) + Offset: 4 bytes (as float) + */ + + RetVal += 24; + + return RetVal; +} + + +status_t +BContinuousParameter::Flatten(void *buffer, + ssize_t size) const +{ + if(buffer == NULL) + return B_NO_INIT; + + ssize_t TotalBParameterFlatSize = BParameter::FlattenedSize(); + //see BContinuousParameter::FlattenedSize() for a description of this value + const ssize_t AdditionalBContParamFlatSize = 24; + + if(size < (TotalBParameterFlatSize + AdditionalBContParamFlatSize)) + { + return B_NO_MEMORY; + } + + status_t RetVal = BParameter::Flatten(buffer,size); + + if(RetVal != B_OK) + { + return RetVal; + } + + byte *CurrentPos = static_cast(buffer); + CurrentPos += TotalBParameterFlatSize; + + //write out the mMinimum property + *(reinterpret_cast(CurrentPos)) = mMinimum; + CurrentPos += sizeof(float); + //write out the mMaximum property + *(reinterpret_cast(CurrentPos)) = mMaximum; + CurrentPos += sizeof(float); + //write out the mStepping property + *(reinterpret_cast(CurrentPos)) = mStepping; + CurrentPos += sizeof(float); + //write out the mResponse property + *(reinterpret_cast(CurrentPos)) = mResponse; + CurrentPos += sizeof(response); + //write out the mFactor property + *(reinterpret_cast(CurrentPos)) = mFactor; + CurrentPos += sizeof(float); + //write out the mOffset property + *(reinterpret_cast(CurrentPos)) = mOffset; + CurrentPos += sizeof(float); + + + return B_OK; +} + + +status_t +BContinuousParameter::Unflatten(type_code c, + const void *buf, + ssize_t size) +{ + + /* + * NOTICE: This method tries to avoid corrupting an existing parameter + * by only reading values out of the buffer after it has verified + * that the size of the buffer is sufficient to read all needed + * fields. In this way, we avoid having to exit this method after + * the 'this' object has been modified by reading a part of the buffer. + */ + + if(!this->AllowsTypeCode(c)) + return B_BAD_TYPE; + + if(buf == NULL) + return B_NO_INIT; + + //if the buffer is smaller than the size needed to read the + //signature and struct size fields, then there is a problem + if(size < static_cast(sizeof(int32) + sizeof(ssize_t))) + { + return B_ERROR; + } + + const byte *CurrentPos = static_cast(buf); + + + //QUESTION: I have no idea where this magic number came from, and i'm not sure that it's + //being read in the correct byte order. + if( *(reinterpret_cast(CurrentPos)) != 0x02040607) + { + return B_BAD_TYPE; + } + CurrentPos += sizeof(int32); + + //read the struct size + ssize_t ParamStructSize = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(ssize_t); + + //see BContinuousParameter::FlattenedSize() for a description of this value + const ssize_t AdditionalBContParamFlatSize = 24; + + if((ParamStructSize + AdditionalBContParamFlatSize) > size) + { + //if the struct size is larger than the size of the buffer we were given, + //there's a problem + return B_ERROR; + } + + //read the base BParameter + status_t RetVal = BParameter::Unflatten(c,buf,size); + + if(RetVal != B_OK) + { + return RetVal; + } + + CurrentPos = static_cast(buf); + CurrentPos += ParamStructSize; + + + //read the mMinimum property + mMinimum = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(float); + //read the mMaximum property + mMaximum = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(float); + //read the mStepping property + mStepping = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(float); + //read the mResponse property + mResponse = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(response); + //read the mFactor property + mFactor = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(float); + //read the mOffset property + mOffset = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(float); + + + return B_OK; +} + +/************************************************************* + * private BContinuousParameter + *************************************************************/ + +status_t BContinuousParameter::_Reserved_ContinuousParameter_0(void *) { return B_ERROR; } +status_t BContinuousParameter::_Reserved_ContinuousParameter_1(void *) { return B_ERROR; } +status_t BContinuousParameter::_Reserved_ContinuousParameter_2(void *) { return B_ERROR; } +status_t BContinuousParameter::_Reserved_ContinuousParameter_3(void *) { return B_ERROR; } +status_t BContinuousParameter::_Reserved_ContinuousParameter_4(void *) { return B_ERROR; } +status_t BContinuousParameter::_Reserved_ContinuousParameter_5(void *) { return B_ERROR; } +status_t BContinuousParameter::_Reserved_ContinuousParameter_6(void *) { return B_ERROR; } +status_t BContinuousParameter::_Reserved_ContinuousParameter_7(void *) { return B_ERROR; } + + +BContinuousParameter::BContinuousParameter(int32 id, + media_type m_type, + BParameterWeb *web, + const char *name, + const char *kind, + const char *unit, + float minimum, + float maximum, + float stepping) + : BParameter(id,m_type,B_CONTINUOUS_PARAMETER,web,name,kind,unit),mMinimum(minimum),mMaximum(maximum),mStepping(stepping), + mResponse(B_LINEAR),mFactor(1.0),mOffset(0.0) +{ +} + + +BContinuousParameter::~BContinuousParameter() +{ +} + +/************************************************************* + * public BDiscreteParameter + *************************************************************/ + +type_code +BDiscreteParameter::ValueType() +{ + return B_INT32_TYPE; +} + + +int32 +BDiscreteParameter::CountItems() +{ + ASSERT_WRETURN_VALUE(mValues != NULL,0); + + return mValues->CountItems(); +} + + +const char * +BDiscreteParameter::ItemNameAt(int32 index) +{ + ASSERT_WRETURN_VALUE(mSelections != NULL,NULL); + + return reinterpret_cast(mSelections->ItemAt(index)); +} + + +int32 +BDiscreteParameter::ItemValueAt(int32 index) +{ + ASSERT_WRETURN_VALUE(mValues != NULL,0); + + //check for out of range + if((index < 0) || (index >= mValues->CountItems())) + { + return 0; + } + + int32 *Item = static_cast(mValues->ItemAt(index)); + if(Item == NULL) + { + return 0; + } + + return *Item; +} + + +status_t +BDiscreteParameter::AddItem(int32 value, + const char *name) +{ + ASSERT_WRETURN_VALUE(mValues != NULL,B_ERROR); + ASSERT_WRETURN_VALUE(mSelections != NULL,B_ERROR); + + int32 *NewVal = new int32(value); + char *NewSel = NULL; + if(name != NULL) + { + ssize_t NameLength = strlen(name); + NewSel = new char[NameLength + 1]; + memcpy(NewSel,name,NameLength); + NewSel[NameLength] = 0; + } + + //QUESTION: How do we watch for the B_NO_MEMORY case (Be Book refers to this)? + mValues->AddItem(NewVal); + mSelections->AddItem(NewSel); + + return B_OK; +} + + +status_t +BDiscreteParameter::MakeItemsFromInputs() +{ + ASSERT_WRETURN_VALUE(mValues != NULL,B_ERROR); + ASSERT_WRETURN_VALUE(mSelections != NULL,B_ERROR); + ASSERT_WRETURN_VALUE(mInputs != NULL,B_ERROR); + + int32 i; + ssize_t NumInputs = mInputs->CountItems(); + for(i = 0; i < NumInputs; i++) + { + BParameter *CurrentParam = static_cast(mInputs->ItemAt(i)); + this->AddItem(i,CurrentParam->Name()); + } + + return B_OK; +} + + +status_t +BDiscreteParameter::MakeItemsFromOutputs() +{ + ASSERT_WRETURN_VALUE(mValues != NULL,B_ERROR); + ASSERT_WRETURN_VALUE(mSelections != NULL,B_ERROR); + ASSERT_WRETURN_VALUE(mOutputs != NULL,B_ERROR); + + int32 i; + ssize_t NumOutputs = mOutputs->CountItems(); + for(i = 0; i < NumOutputs; i++) + { + BParameter *CurrentParam = static_cast(mOutputs->ItemAt(i)); + this->AddItem(i,CurrentParam->Name()); + } + + return B_OK; +} + + +void +BDiscreteParameter::MakeEmpty() +{ + ASSERT_RETURN(mValues != NULL); + ASSERT_RETURN(mSelections != NULL); + + int32 i; + ssize_t ListSize = mValues->CountItems(); + for(i = 0; i < ListSize; i++) + { + int32 *CurrentValue = static_cast(mValues->ItemAt(i)); + if(CurrentValue != NULL) + { + delete CurrentValue; + } + } + mValues->MakeEmpty(); + + ListSize = mSelections->CountItems(); + for(i = 0; i < ListSize; i++) + { + char *CurrentSelection = static_cast(mSelections->ItemAt(i)); + if(CurrentSelection != NULL) + { + delete[] CurrentSelection; + } + } + mSelections->MakeEmpty(); + +} + + +ssize_t +BDiscreteParameter::FlattenedSize() const +{ + ssize_t RetVal = BParameter::FlattenedSize(); + /* + //--------BEGIN-BDISCRETEPARAMETER-STRUCT---------------- + NumItems: 4 bytes (as int) + //for each item BEGIN + Item Name String Length: 1 byte + Item Name String: 'Item Name String Length' bytes + Item Value: 4 bytes (as int) + //for each item END + //--------END-BDISCRETEPARAMETER-STRUCT------------------- + */ + RetVal += sizeof(ssize_t); + + ssize_t NumItems = mValues->CountItems(); + int32 i; + for(i = 0; i < NumItems; i++) + { + char *CurrentSel = static_cast(mSelections->ItemAt(i)); + + if(CurrentSel != NULL) + { + RetVal += min_c(strlen(CurrentSel),255); + } + + //regardless of string size, there is a cost of 5 bytes for each item (string length + value) + RetVal += 5; + } + + return RetVal; +} + + +status_t +BDiscreteParameter::Flatten(void *buffer, + ssize_t size) const +{ + if(buffer == NULL) + return B_NO_INIT; + + ssize_t TotalBParameterFlatSize = BParameter::FlattenedSize(); + + //see BDiscreteParameter::FlattenedSize() for a description of this value + ssize_t AdditionalBDiscParamFlatSize = sizeof(ssize_t); + + ssize_t NumItems = mValues->CountItems(); + int32 i; + for(i = 0; i < NumItems; i++) + { + char *CurrentSel = static_cast(mSelections->ItemAt(i)); + + if(CurrentSel != NULL) + { + AdditionalBDiscParamFlatSize += min_c(strlen(CurrentSel),255); + } + + //regardless of string size, there is a cost of 5 bytes for each item (string length + value) + AdditionalBDiscParamFlatSize += 5; + } + + + if(size < (TotalBParameterFlatSize + AdditionalBDiscParamFlatSize)) + { + return B_NO_MEMORY; + } + + status_t RetVal = BParameter::Flatten(buffer,size); + + if(RetVal != B_OK) + { + return RetVal; + } + + byte *CurrentPos = static_cast(buffer); + CurrentPos += TotalBParameterFlatSize; + + //write out the number of value/name pairs + *(reinterpret_cast(CurrentPos)) = NumItems; + CurrentPos += sizeof(ssize_t); + + //write out all value/name pairs themselves + for(i = 0; i < NumItems; i++) + { + const char *CurrentSel = static_cast(mSelections->ItemAt(i)); + const int32 *CurrentVal = static_cast(mValues->ItemAt(i)); + + if(CurrentSel != NULL) + { + byte NameLength = min_c(strlen(CurrentSel),255); + + //write out the name length + *(reinterpret_cast(CurrentPos)) = NameLength; + CurrentPos += sizeof(byte); + + memcpy(CurrentPos,CurrentSel,NameLength); + CurrentPos += NameLength; + } + else + { + //write out a zero name length + *(reinterpret_cast(CurrentPos)) = 0; + CurrentPos += sizeof(byte); + } + + if(CurrentVal != NULL) + { + //write out the value + *(reinterpret_cast(CurrentPos)) = *CurrentVal; + CurrentPos += sizeof(int32); + } + else + { + //write out a zero value + *(reinterpret_cast(CurrentPos)) = 0; + CurrentPos += sizeof(int32); + } + } + + + return B_OK; +} + + +status_t +BDiscreteParameter::Unflatten(type_code c, + const void *buf, + ssize_t size) +{ + /* + * NOTICE: This method tries to avoid corrupting an existing parameter + * by only reading values out of the buffer after it has verified + * that the size of the buffer is sufficient to read all needed + * fields. In this way, we avoid having to exit this method after + * the 'this' object has been modified by reading a part of the buffer. + */ + + if(!this->AllowsTypeCode(c)) + return B_BAD_TYPE; + + if(buf == NULL) + return B_NO_INIT; + + //if the buffer is smaller than the size needed to read the + //signature and struct size fields, then there is a problem + if(size < static_cast(sizeof(int32) + sizeof(ssize_t))) + { + return B_ERROR; + } + + const byte *CurrentPos = static_cast(buf); + + + //QUESTION: I have no idea where this magic number came from, and i'm not sure that it's + //being read in the correct byte order. + if( *(reinterpret_cast(CurrentPos)) != 0x02040607) + { + return B_BAD_TYPE; + } + CurrentPos += sizeof(int32); + + //read the struct size + ssize_t ParamStructSize = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(ssize_t); + + //this is the minimum REQUIRED additional space for a BDiscreteParameter in a flattened buffer + const ssize_t AdditionalBDiscParamFlatSize = 1; + + if((ParamStructSize + AdditionalBDiscParamFlatSize) > size) + { + //if the struct size is larger than the size of the buffer we were given, + //there's a problem + return B_ERROR; + } + + //read the base BParameter + status_t RetVal = BParameter::Unflatten(c,buf,size); + + if(RetVal != B_OK) + { + return RetVal; + } + + CurrentPos = static_cast(buf); + CurrentPos += ParamStructSize; + + //read NumItems + ssize_t NumItems = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(ssize_t); + + ssize_t MaxByteLength = size - (CurrentPos - static_cast(buf)); + + const ssize_t MinFlattenedItemSize(5); + + //each item occupies a minimum of 5 bytes, so make sure that there is enough + //space remaining in the buffer for the specified NumItems (assuming each is minimum size) + NumItems = min_c(NumItems,MaxByteLength/MinFlattenedItemSize); + + //clear any existing name/value pairs + this->MakeEmpty(); + + int i; + for(i = 0; i < NumItems; i++) + { + //read the string length for the name associated with this item + byte NameStringLength = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(byte); + + //ensure that we don't read so much that we don't have enough buffer left for the minimum remainder + //of this item (4 byte int32 value), or for the minimum size of the remaining items (5bytes*(num remaining items)) + MaxByteLength = size - ((CurrentPos - static_cast(buf)) + (NumItems - (i+1))*MinFlattenedItemSize + sizeof(int32)); + + NameStringLength = min_c(NameStringLength,MaxByteLength); + + //read the name string + char *ItemName = new char[NameStringLength + 1]; + memcpy(ItemName,CurrentPos,NameStringLength); + ItemName[NameStringLength] = 0; + CurrentPos += NameStringLength; + + + //read the value of this item + int32 ItemValue = *(reinterpret_cast(CurrentPos)); + CurrentPos += sizeof(int32); + + //add the item and name to the list + this->AddItem(ItemValue,ItemName); + } + + + return B_OK; +} + +/************************************************************* + * private BDiscreteParameter + *************************************************************/ + +status_t BDiscreteParameter::_Reserved_DiscreteParameter_0(void *) { return B_ERROR; } +status_t BDiscreteParameter::_Reserved_DiscreteParameter_1(void *) { return B_ERROR; } +status_t BDiscreteParameter::_Reserved_DiscreteParameter_2(void *) { return B_ERROR; } +status_t BDiscreteParameter::_Reserved_DiscreteParameter_3(void *) { return B_ERROR; } +status_t BDiscreteParameter::_Reserved_DiscreteParameter_4(void *) { return B_ERROR; } +status_t BDiscreteParameter::_Reserved_DiscreteParameter_5(void *) { return B_ERROR; } +status_t BDiscreteParameter::_Reserved_DiscreteParameter_6(void *) { return B_ERROR; } +status_t BDiscreteParameter::_Reserved_DiscreteParameter_7(void *) { return B_ERROR; } + + +BDiscreteParameter::BDiscreteParameter(int32 id, + media_type m_type, + BParameterWeb *web, + const char *name, + const char *kind) +: BParameter(id,m_type,B_DISCRETE_PARAMETER,web,name,kind,"") +{ + this->mSelections = new BList(); + this->mValues = new BList(); +} + + +BDiscreteParameter::~BDiscreteParameter() +{ + this->MakeEmpty(); + + if(this->mSelections != NULL) + { + delete this->mSelections; + } + if(this->mValues != NULL) + { + delete this->mValues; + } +} + +/************************************************************* + * public BNullParameter + *************************************************************/ + +type_code +BNullParameter::ValueType() +{ + //NULL parameters have no value type + return 0; +} + + +ssize_t +BNullParameter::FlattenedSize() const +{ + return BParameter::FlattenedSize(); +} + + +status_t +BNullParameter::Flatten(void *buffer, + ssize_t size) const +{ + return BParameter::Flatten(buffer,size); +} + + +status_t +BNullParameter::Unflatten(type_code c, + const void *buf, + ssize_t size) +{ + return BParameter::Unflatten(c,buf,size); +} + +/************************************************************* + * private BNullParameter + *************************************************************/ + +status_t BNullParameter::_Reserved_NullParameter_0(void *) { return B_ERROR; } +status_t BNullParameter::_Reserved_NullParameter_1(void *) { return B_ERROR; } +status_t BNullParameter::_Reserved_NullParameter_2(void *) { return B_ERROR; } +status_t BNullParameter::_Reserved_NullParameter_3(void *) { return B_ERROR; } +status_t BNullParameter::_Reserved_NullParameter_4(void *) { return B_ERROR; } +status_t BNullParameter::_Reserved_NullParameter_5(void *) { return B_ERROR; } +status_t BNullParameter::_Reserved_NullParameter_6(void *) { return B_ERROR; } +status_t BNullParameter::_Reserved_NullParameter_7(void *) { return B_ERROR; } + + +BNullParameter::BNullParameter(int32 id, + media_type m_type, + BParameterWeb *web, + const char *name, + const char *kind) + : BParameter(id,m_type,B_NULL_PARAMETER,web,name,kind,"") +{ +} + + +BNullParameter::~BNullParameter() +{ +} + + diff --git a/src/kits/media/PlaySound.cpp b/src/kits/media/PlaySound.cpp new file mode 100644 index 0000000000..ce7ad1b27b --- /dev/null +++ b/src/kits/media/PlaySound.cpp @@ -0,0 +1,34 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: PlaySound.cpp + * DESCR: + ***********************************************************************/ + +#include +#include +#include + +#include +#include "debug.h" + +sound_handle play_sound(const entry_ref *soundRef, + bool mix, + bool queue, + bool background + ) +{ + UNIMPLEMENTED(); + return (sound_handle)1; +} + +status_t stop_sound(sound_handle handle) +{ + UNIMPLEMENTED(); + return B_OK; +} + +status_t wait_for_sound(sound_handle handle) +{ + UNIMPLEMENTED(); + return B_OK; +} diff --git a/src/kits/media/PortPool.cpp b/src/kits/media/PortPool.cpp new file mode 100644 index 0000000000..8b7a7be9f2 --- /dev/null +++ b/src/kits/media/PortPool.cpp @@ -0,0 +1,86 @@ +/*********************************************************************** + * Copyright (c) 2002 Marcus Overhagen. All Rights Reserved. + * This file may be used under the terms of the OpenBeOS License. + * + * A pool of kernel ports + ***********************************************************************/ +#include +#include +#include "PortPool.h" +#include "debug.h" + +PortPool _ThePortPool; +PortPool *_PortPool = &_ThePortPool; + +PortPool::PortPool() +{ + locker_atom = 0; + locker_sem = create_sem(0,"port pool lock"); + count = 0; + maxcount = 0; + pool = 0; +} + +PortPool::~PortPool() +{ + for (int i = 0; i < maxcount; i++) + delete_port(pool[i].port); + delete_sem(locker_sem); + if (pool) + free(pool); +} + +port_id +PortPool::GetPort() +{ + Lock(); + port_id port; + if (count == maxcount) { + maxcount += 3; + pool = (PortInfo *)realloc(pool,sizeof(PortInfo) * maxcount); + if (pool == NULL) + debugger("out of memory in PortPool::GetPort()\n"); + for (int i = count; i < maxcount; i++) { + pool[i].used = false; + pool[i].port = create_port(1,"some reply port"); + } + } + count++; + for (int i = 0; i < maxcount; i++) + if (pool[i].used == false) { + port = pool[i].port; + pool[i].used = true; + break; + } + Unlock(); + return port; +} + +void +PortPool::PutPort(port_id port) +{ + Lock(); + count--; + for (int i = 0; i < maxcount; i++) + if (pool[i].port == port) { + pool[i].used = false; + break; + } + Unlock(); +} + +void +PortPool::Lock() +{ + if (atomic_add(&locker_atom, 1) > 0) { + while (B_INTERRUPTED == acquire_sem(locker_sem)) + ; + } +} + +void +PortPool::Unlock() +{ + if (atomic_add(&locker_atom, -1) > 1) + release_sem(locker_sem); +} diff --git a/src/kits/media/RealtimeAlloc.cpp b/src/kits/media/RealtimeAlloc.cpp new file mode 100644 index 0000000000..f341918c68 --- /dev/null +++ b/src/kits/media/RealtimeAlloc.cpp @@ -0,0 +1,141 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: RealtimeAlloc.cpp + * DESCR: + ***********************************************************************/ + +#define NDEBUG + +#include +#include +#include +#include "debug.h" + + +struct rtm_pool +{ +}; + +extern "C" { + rtm_pool * _rtm_pool; +}; + +status_t rtm_create_pool(rtm_pool ** out_pool, size_t total_size, const char * name) +{ + BROKEN(); + *out_pool = (rtm_pool *) 0x55557777; + TRACE(" new pool = 0x%08x\n",(int)*out_pool); + /* If out_pool is NULL, the default pool will be created if it isn't already. */ + /* If the default pool is already created, it will return EALREADY. */ + return B_OK; +} + +status_t rtm_delete_pool(rtm_pool * pool) +{ + BROKEN(); + TRACE(" pool = 0x%08x\n",(int)pool); + return B_OK; +} + +void * rtm_alloc(rtm_pool * pool, size_t size) +{ + BROKEN(); + TRACE(" pool = 0x%08x\n",(int)pool); + /* If NULL is passed for pool, the default pool is used (if created). */ + void *p = malloc(size); + TRACE(" returning ptr = 0x%08x\n",(int)p); + return p; +} + +status_t rtm_free(void * data) +{ + BROKEN(); + TRACE(" ptr = 0x%08x\n",(int)data); + free(data); + return B_OK; +} + +status_t rtm_realloc(void ** data, size_t new_size) +{ + BROKEN(); + TRACE(" ptr = 0x%08x\n",(int)*data); + void * newptr = realloc(*data, new_size); + if (newptr) { + *data = newptr; + TRACE(" new ptr = 0x%08x\n",(int)*data); + return B_OK; + } else + return B_ERROR; +} + +status_t rtm_size_for(void * data) +{ + UNIMPLEMENTED(); + TRACE(" ptr = 0x%08x\n",(int)data); + return 0; +} + +status_t rtm_phys_size_for(void * data) +{ + UNIMPLEMENTED(); + TRACE(" ptr = 0x%08x\n",(int)data); + return 0; +} + +rtm_pool * rtm_default_pool() +{ + BROKEN(); + /* Return the default pool, or NULL if not yet initialized */ + TRACE(" returning pool = 0x%08x\n",0x22229999); + return (rtm_pool *) 0x22229999; +} + + +/****************************************************************************/ +/* undocumented symboles that libmedia.so exports */ +/* the following function declarations are guessed and are still wrong */ +/****************************************************************************/ + +extern "C" { + +status_t rtm_create_pool_etc(rtm_pool ** out_pool, size_t total_size, const char * name, int32 param4, int32 param5, ...); + +void rtm_get_pool(rtm_pool *pool,void *data,int32 param3,int32 param4, ...); + +} + +/* +param5 of rtm_create_pool_etc matches +param3 of rtm_get_pool +and might be a pointer into some structure + +param4 of rtm_create_pool_etc is 0 in the Doom game, +and might be a Flags field + +param4 of rtm_get_pool is 0x00000003 in the Doom game, +and might be a Flags field + +*/ + +status_t rtm_create_pool_etc(rtm_pool ** out_pool, size_t total_size, const char * name, int32 param4, int32 param5, ...) +{ + BROKEN(); + *out_pool = (rtm_pool *) 0x44448888; + TRACE(" new pool = 0x%08x\n",(int)*out_pool); + TRACE(" size = %d\n",(int)total_size); + TRACE(" name = %s\n",name); + TRACE(" param4 = 0x%08x\n",(int)param4); + TRACE(" param5 = 0x%08x\n",(int)param5); + return B_OK; +} + + +void rtm_get_pool(rtm_pool *pool,void *data,int32 param3, int32 param4, ...) +{ + UNIMPLEMENTED(); + TRACE(" pool = 0x%08x\n",(int)pool); + TRACE(" ptr = 0x%08x\n",(int)data); + TRACE(" param3 = 0x%08x\n",(int)param3); + TRACE(" param4 = 0x%08x\n",(int)param4); +} + diff --git a/src/kits/media/SampleConverter.cpp b/src/kits/media/SampleConverter.cpp new file mode 100644 index 0000000000..48cb3d5015 --- /dev/null +++ b/src/kits/media/SampleConverter.cpp @@ -0,0 +1,292 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: SampleConverter.cpp + * DESCR: Converts between different sample formats + ***********************************************************************/ + +#include +#include +#include + +#include "SampleConverter.h" + +extern "C" { +// used by BeOS R5 legacy.media_addon and mixer.media_addon +void convertBufferFloatToShort(float *out, short *in, int32 count); +void convertBufferFloatToShort(float *out, short *in, int32 count) +{ + MediaKitPrivate::SampleConverter::convert( + out, + media_raw_audio_format::B_AUDIO_FLOAT, + in, + media_raw_audio_format::B_AUDIO_SHORT, + count); +} +}; + +namespace MediaKitPrivate { + +status_t +SampleConverter::convert(void *dest, uint32 dest_format, + const void *source, uint32 source_format, int samplecount) +{ + switch (dest_format) { + case media_raw_audio_format::B_AUDIO_FLOAT: + switch (source_format) { + case media_raw_audio_format::B_AUDIO_FLOAT: + memcpy(dest,source,samplecount * sizeof(float)); + return B_OK; + case media_raw_audio_format::B_AUDIO_INT: + convert((float *)dest,(const int32 *)source,samplecount); + return B_OK; + case media_raw_audio_format::B_AUDIO_SHORT: + convert((float *)dest,(const int16 *)source,samplecount); + return B_OK; + case media_raw_audio_format::B_AUDIO_CHAR: + convert((float *)dest,(const int8 *)source,samplecount); + return B_OK; + case media_raw_audio_format::B_AUDIO_UCHAR: + convert((float *)dest,(const uint8 *)source,samplecount); + return B_OK; + default: + fprintf(stderr,"SampleConverter::convert() unsupported source sample format %d\n",(int)source_format); + return B_ERROR; + } + case media_raw_audio_format::B_AUDIO_INT: + switch (source_format) { + case media_raw_audio_format::B_AUDIO_FLOAT: + convert((int32 *)dest,(const float *)source,samplecount); + return B_OK; + case media_raw_audio_format::B_AUDIO_INT: + memcpy(dest,source,samplecount * sizeof(int32)); + return B_OK; + case media_raw_audio_format::B_AUDIO_SHORT: + convert((int32 *)dest,(const int16 *)source,samplecount); + return B_OK; + case media_raw_audio_format::B_AUDIO_CHAR: + convert((int32 *)dest,(const int8 *)source,samplecount); + return B_OK; + case media_raw_audio_format::B_AUDIO_UCHAR: + convert((int32 *)dest,(const uint8 *)source,samplecount); + return B_OK; + default: + fprintf(stderr,"SampleConverter::convert() unsupported source sample format %d\n",(int)source_format); + return B_ERROR; + } + case media_raw_audio_format::B_AUDIO_SHORT: + switch (source_format) { + case media_raw_audio_format::B_AUDIO_FLOAT: + convert((int16 *)dest,(const float *)source,samplecount); + return B_OK; + case media_raw_audio_format::B_AUDIO_INT: + convert((int16 *)dest,(const int32 *)source,samplecount); + return B_OK; + case media_raw_audio_format::B_AUDIO_SHORT: + memcpy(dest,source,samplecount * sizeof(int16)); + return B_OK; + case media_raw_audio_format::B_AUDIO_CHAR: + convert((int16 *)dest,(const int8 *)source,samplecount); + return B_OK; + case media_raw_audio_format::B_AUDIO_UCHAR: + convert((int16 *)dest,(const uint8 *)source,samplecount); + return B_OK; + default: + fprintf(stderr,"SampleConverter::convert() unsupported source sample format %d\n",(int)source_format); + return B_ERROR; + } + case media_raw_audio_format::B_AUDIO_CHAR: + switch (source_format) { + case media_raw_audio_format::B_AUDIO_FLOAT: + convert((int8 *)dest,(const float *)source,samplecount); + return B_OK; + case media_raw_audio_format::B_AUDIO_INT: + convert((int8 *)dest,(const int32 *)source,samplecount); + return B_OK; + case media_raw_audio_format::B_AUDIO_SHORT: + convert((int8 *)dest,(const int16 *)source,samplecount); + return B_OK; + case media_raw_audio_format::B_AUDIO_CHAR: + memcpy(dest,source,samplecount * sizeof(int8)); + return B_OK; + case media_raw_audio_format::B_AUDIO_UCHAR: + convert((int8 *)dest,(const uint8 *)source,samplecount); + return B_OK; + default: + fprintf(stderr,"SampleConverter::convert() unsupported source sample format %d\n",(int)source_format); + return B_ERROR; + } + case media_raw_audio_format::B_AUDIO_UCHAR: + switch (source_format) { + case media_raw_audio_format::B_AUDIO_FLOAT: + convert((uint8 *)dest,(const float *)source,samplecount); + return B_OK; + case media_raw_audio_format::B_AUDIO_INT: + convert((uint8 *)dest,(const int32 *)source,samplecount); + return B_OK; + case media_raw_audio_format::B_AUDIO_SHORT: + convert((uint8 *)dest,(const int16 *)source,samplecount); + return B_OK; + case media_raw_audio_format::B_AUDIO_CHAR: + convert((uint8 *)dest,(const int8 *)source,samplecount); + return B_OK; + case media_raw_audio_format::B_AUDIO_UCHAR: + memcpy(dest,source,samplecount * sizeof(uint8)); + return B_OK; + default: + fprintf(stderr,"SampleConverter::convert() unsupported source sample format %d\n",(int)source_format); + return B_ERROR; + } + default: + fprintf(stderr,"SampleConverter::convert() unsupported destination sample format %d\n",(int)source_format); + return B_ERROR; + } +} + +void SampleConverter::convert(uint8 *dest, const float *source, int samplecount) +{ + while (samplecount--) { + register int32 sample = int32(*(source++) * 127.0f); + if (sample > 127) + sample = 255; + else if (sample < -127) + sample = 1; + *dest++ = uint8(sample + 128); + } +} + +void SampleConverter::convert(uint8 *dest, const int32 *source, int samplecount) +{ + while (samplecount--) + *dest++ = uint8((*source++ / (256 * 256 * 256)) + 128); +} + +void SampleConverter::convert(uint8 *dest, const int16 *source, int samplecount) +{ + while (samplecount--) + *dest++ = uint8((int32(*source++) / 256) + 128); +} + +void SampleConverter::convert(uint8 *dest, const int8 *source, int samplecount) +{ + while (samplecount--) + *dest++ = uint8(int32(*source++) + 128); +} + +void SampleConverter::convert(int8 *dest, const float *source, int samplecount) +{ + while (samplecount--) { + register int32 sample = (int32) (*(source++) * 127.0f); + if (sample > 127) + *dest++ = 127; + else if (sample < -127) + *dest++ = -127; + else + *dest++ = int8(sample); + } +} + +void SampleConverter::convert(int8 *dest, const int32 *source, int samplecount) +{ + while (samplecount--) + *dest++ = int8(*source++ / (256 * 256 * 256)); +} + +void SampleConverter::convert(int8 *dest, const int16 *source, int samplecount) +{ + while (samplecount--) + *dest++ = int8(*source++ / 256); +} + +void SampleConverter::convert(int8 *dest, const uint8 *source, int samplecount) +{ + while (samplecount--) + *dest++ = int8(*source++ - 128); +} + +void SampleConverter::convert(int16 *dest, const float *source, int samplecount) +{ + while (samplecount--) { + register int32 sample = (int32) (*source++ * 32767.0f); + if (sample > 32767) + *dest++ = 32767; + else if (sample < -32767) + *dest++ = -32767; + else + *dest++ = int16(sample); + } +} + +void SampleConverter::convert(int16 *dest, const int32 *source, int samplecount) +{ + while (samplecount--) + *dest++ = int16(*source++ / (256 * 256)); +} + +void SampleConverter::convert(int16 *dest, const int8 *source, int samplecount) +{ + while (samplecount--) + *dest++ = int16(*source++) * 256; +} + +void SampleConverter::convert(int16 *dest, const uint8 *source, int samplecount) +{ + while (samplecount--) + *dest++ = (int16(*source++) - 128) * 256; +} + +void SampleConverter::convert(int32 *dest, const float *source, int samplecount) +{ + while (samplecount--) { + register double sample = double(*source++) * 2147483647.0; + if (sample > 2147483647.0) + *dest++ = 2147483647; + else if (sample < -2147483647.0) + *dest++ = -2147483647; + else + *dest++ = int32(sample); + } +} + +void SampleConverter::convert(int32 *dest, const int16 *source, int samplecount) +{ + while (samplecount--) + *dest++ = int32(*source++) * 256 * 256; +} + +void SampleConverter::convert(int32 *dest, const int8 *source, int samplecount) +{ + while (samplecount--) + *dest++ = int32(*source++) * 256 * 256 * 256; +} + +void SampleConverter::convert(int32 *dest, const uint8 *source, int samplecount) +{ + while (samplecount--) + *dest++ = (int32(*source++) - 128) * 256 * 256 * 256; +} + +void SampleConverter::convert(float *dest, const int32 *source, int samplecount) +{ + while (samplecount--) + *dest++ = float(*source++) / 2147483647.0f; +} + +void SampleConverter::convert(float *dest, const int16 *source, int samplecount) +{ + while (samplecount--) + *dest++ = float(*source++) / 32767.0f; +} + +void SampleConverter::convert(float *dest, const int8 *source, int samplecount) +{ + while (samplecount--) + *dest++ = float(*source++) / 127.0f; +} + +void SampleConverter::convert(float *dest, const uint8 *source, int samplecount) +{ + while (samplecount--) + *dest++ = (float(*source++) - 128.0f) / 127.0f; +} + +} //namespace MediaKitPrivate diff --git a/src/kits/media/SamplingrateConverter.cpp b/src/kits/media/SamplingrateConverter.cpp new file mode 100644 index 0000000000..17b36fec1e --- /dev/null +++ b/src/kits/media/SamplingrateConverter.cpp @@ -0,0 +1,389 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: SamplingrateConverter.cpp + * DESCR: Converts between different sampling rates + * This is really bad code, as there are much better algorithms + * than the simple duplicating or dropping of samples. + * Also, the implementation isn't very nice. + * Feel free to send me better versions to marcus@overhagen.de + ***********************************************************************/ + +#include +#include +#include + +#include "SamplingrateConverter.h" + + +namespace MediaKitPrivate { + +static void Upsample_stereo(const float *inbuffer, int inframecount, float *outbuffer, int outframecount); +static void Upsample_mono(const float *inbuffer, int inframecount, float *outbuffer, int outframecount); +static void Upsample_stereo(const int32 *inbuffer, int inframecount, int32 *outbuffer, int outframecount); +static void Upsample_mono(const int32 *inbuffer, int inframecount, int32 *outbuffer, int outframecount); +static void Upsample_stereo(const int16 *inbuffer, int inframecount, int16 *outbuffer, int outframecount); +static void Upsample_mono(const int16 *inbuffer, int inframecount, int16 *outbuffer, int outframecount); +static void Upsample_stereo(const int8 *inbuffer, int inframecount, int8 *outbuffer, int outframecount); +static void Upsample_mono(const int8 *inbuffer, int inframecount, int8 *outbuffer, int outframecount); +static void Upsample_stereo(const uint8 *inbuffer, int inframecount, uint8 *outbuffer, int outframecount); +static void Upsample_mono(const uint8 *inbuffer, int inframecount, uint8 *outbuffer, int outframecount); +static void Downsample_stereo(const float *inbuffer, int inframecount, float *outbuffer, int outframecount); +static void Downsample_mono(const float *inbuffer, int inframecount, float *outbuffer, int outframecount); +static void Downsample_stereo(const int32 *inbuffer, int inframecount, int32 *outbuffer, int outframecount); +static void Downsample_mono(const int32 *inbuffer, int inframecount, int32 *outbuffer, int outframecount); +static void Downsample_stereo(const int16 *inbuffer, int inframecount, int16 *outbuffer, int outframecount); +static void Downsample_mono(const int16 *inbuffer, int inframecount, int16 *outbuffer, int outframecount); +static void Downsample_stereo(const int8 *inbuffer, int inframecount, int8 *outbuffer, int outframecount); +static void Downsample_mono(const int8 *inbuffer, int inframecount, int8 *outbuffer, int outframecount); +static void Downsample_stereo(const uint8 *inbuffer, int inframecount, uint8 *outbuffer, int outframecount); +static void Downsample_mono(const uint8 *inbuffer, int inframecount, uint8 *outbuffer, int outframecount); + + +status_t +SamplingrateConverter::convert(void *dest, int destframecount, + const void *src, int srcframecount, + uint32 format, + int channel_count) +{ + if (channel_count != 1 && channel_count != 2) { + fprintf(stderr,"SamplingrateConverter::convert() unsupported channel count %d\n",channel_count); + return B_ERROR; + } + switch (format) { + case media_raw_audio_format::B_AUDIO_FLOAT: + if (destframecount > srcframecount) { + if (channel_count == 1) + Upsample_mono((const float *)src,srcframecount,(float *)dest,destframecount); + else + Upsample_stereo((const float *)src,srcframecount,(float *)dest,destframecount); + } else { + if (channel_count == 1) + Downsample_mono((const float *)src,srcframecount,(float *)dest,destframecount); + else + Downsample_stereo((const float *)src,srcframecount,(float *)dest,destframecount); + } + return B_OK; + case media_raw_audio_format::B_AUDIO_INT: + if (destframecount > srcframecount) { + if (channel_count == 1) + Upsample_mono((const int32 *)src,srcframecount,(int32 *)dest,destframecount); + else + Upsample_stereo((const int32 *)src,srcframecount,(int32 *)dest,destframecount); + } else { + if (channel_count == 1) + Downsample_mono((const int32 *)src,srcframecount,(int32 *)dest,destframecount); + else + Downsample_stereo((const int32 *)src,srcframecount,(int32 *)dest,destframecount); + } + return B_OK; + case media_raw_audio_format::B_AUDIO_SHORT: + if (destframecount > srcframecount) { + if (channel_count == 1) + Upsample_mono((const int16 *)src,srcframecount,(int16 *)dest,destframecount); + else + Upsample_stereo((const int16 *)src,srcframecount,(int16 *)dest,destframecount); + } else { + if (channel_count == 1) + Downsample_mono((const int16 *)src,srcframecount,(int16 *)dest,destframecount); + else + Downsample_stereo((const int16 *)src,srcframecount,(int16 *)dest,destframecount); + } + return B_OK; + case media_raw_audio_format::B_AUDIO_CHAR: + if (destframecount > srcframecount) { + if (channel_count == 1) + Upsample_mono((const int8 *)src,srcframecount,(int8 *)dest,destframecount); + else + Upsample_stereo((const int8 *)src,srcframecount,(int8 *)dest,destframecount); + } else { + if (channel_count == 1) + Downsample_mono((const int8 *)src,srcframecount,(int8 *)dest,destframecount); + else + Downsample_stereo((const int8 *)src,srcframecount,(int8 *)dest,destframecount); + } + return B_OK; + case media_raw_audio_format::B_AUDIO_UCHAR: + if (destframecount > srcframecount) { + if (channel_count == 1) + Upsample_mono((const uint8 *)src,srcframecount,(uint8 *)dest,destframecount); + else + Upsample_stereo((const uint8 *)src,srcframecount,(uint8 *)dest,destframecount); + } else { + if (channel_count == 1) + Downsample_mono((const uint8 *)src,srcframecount,(uint8 *)dest,destframecount); + else + Downsample_stereo((const uint8 *)src,srcframecount,(uint8 *)dest,destframecount); + } + return B_OK; + default: + fprintf(stderr,"SamplingrateConverter::convert() unsupported sample format %d\n",(int)format); + return B_ERROR; + } +} + +void Upsample_stereo(const float *inbuffer, int inframecount, float *outbuffer, int outframecount) +{ + float delta = float(inframecount) / float(outframecount); + float current = 0.0f; + + while (outframecount--) { + *outbuffer++ = inbuffer[0]; + *outbuffer++ = inbuffer[1]; + current += delta; + if (current > 1.0f) { + current -= 1.0f; + inbuffer += 2; + } + } +} + +void Upsample_mono(const float *inbuffer, int inframecount, float *outbuffer, int outframecount) +{ + float delta = float(inframecount) / float(outframecount); + float current = 0.0f; + + while (outframecount--) { + *outbuffer++ = inbuffer[0]; + current += delta; + if (current > 1.0f) { + current -= 1.0f; + inbuffer++; + } + } +} + +void Upsample_stereo(const int32 *inbuffer, int inframecount, int32 *outbuffer, int outframecount) +{ + float delta = float(inframecount) / float(outframecount); + float current = 0.0f; + + while (outframecount--) { + *outbuffer++ = inbuffer[0]; + *outbuffer++ = inbuffer[1]; + current += delta; + if (current > 1.0f) { + current -= 1.0f; + inbuffer += 2; + } + } +} + +void Upsample_mono(const int32 *inbuffer, int inframecount, int32 *outbuffer, int outframecount) +{ + float delta = float(inframecount) / float(outframecount); + float current = 0.0f; + + while (outframecount--) { + *outbuffer++ = inbuffer[0]; + current += delta; + if (current > 1.0f) { + current -= 1.0f; + inbuffer++; + } + } +} + +void Upsample_stereo(const int16 *inbuffer, int inframecount, int16 *outbuffer, int outframecount) +{ + float delta = float(inframecount) / float(outframecount); + float current = 0.0f; + + while (outframecount--) { + *outbuffer++ = inbuffer[0]; + *outbuffer++ = inbuffer[1]; + current += delta; + if (current > 1.0f) { + current -= 1.0f; + inbuffer += 2; + } + } +} + +void Upsample_mono(const int16 *inbuffer, int inframecount, int16 *outbuffer, int outframecount) +{ + float delta = float(inframecount) / float(outframecount); + float current = 0.0f; + + while (outframecount--) { + *outbuffer++ = inbuffer[0]; + current += delta; + if (current > 1.0f) { + current -= 1.0f; + inbuffer++; + } + } +} + +void Upsample_stereo(const int8 *inbuffer, int inframecount, int8 *outbuffer, int outframecount) +{ + float delta = float(inframecount) / float(outframecount); + float current = 0.0f; + + while (outframecount--) { + *outbuffer++ = inbuffer[0]; + *outbuffer++ = inbuffer[1]; + current += delta; + if (current > 1.0f) { + current -= 1.0f; + inbuffer += 2; + } + } +} + +void Upsample_mono(const int8 *inbuffer, int inframecount, int8 *outbuffer, int outframecount) +{ + float delta = float(inframecount) / float(outframecount); + float current = 0.0f; + + while (outframecount--) { + *outbuffer++ = inbuffer[0]; + current += delta; + if (current > 1.0f) { + current -= 1.0f; + inbuffer++; + } + } +} + +void Upsample_stereo(const uint8 *inbuffer, int inframecount, uint8 *outbuffer, int outframecount) +{ + float delta = float(inframecount) / float(outframecount); + float current = 0.0f; + + while (outframecount--) { + *outbuffer++ = inbuffer[0]; + *outbuffer++ = inbuffer[1]; + current += delta; + if (current > 1.0f) { + current -= 1.0f; + inbuffer += 2; + } + } +} + +void Upsample_mono(const uint8 *inbuffer, int inframecount, uint8 *outbuffer, int outframecount) +{ + float delta = float(inframecount) / float(outframecount); + float current = 0.0f; + + while (outframecount--) { + *outbuffer++ = inbuffer[0]; + current += delta; + if (current > 1.0f) { + current -= 1.0f; + inbuffer++; + } + } +} + +void Downsample_stereo(const float *inbuffer, int inframecount, float *outbuffer, int outframecount) +{ + double delta = double(inframecount) / double(outframecount); + double pos = 0.0; + while (outframecount--) { + int p = int(pos); + *outbuffer++ = inbuffer[p]; + *outbuffer++ = inbuffer[p+1]; + pos += delta; + } +} + +void Downsample_mono(const float *inbuffer, int inframecount, float *outbuffer, int outframecount) +{ + double delta = double(inframecount) / double(outframecount); + double pos = 0.0; + while (outframecount--) { + *outbuffer++ = inbuffer[int(pos)]; + pos += delta; + } +} + +void Downsample_stereo(const int32 *inbuffer, int inframecount, int32 *outbuffer, int outframecount) +{ + double delta = double(inframecount) / double(outframecount); + double pos = 0.0; + while (outframecount--) { + int p = int(pos); + *outbuffer++ = inbuffer[p]; + *outbuffer++ = inbuffer[p+1]; + pos += delta; + } +} + +void Downsample_mono(const int32 *inbuffer, int inframecount, int32 *outbuffer, int outframecount) +{ + double delta = double(inframecount) / double(outframecount); + double pos = 0.0; + while (outframecount--) { + *outbuffer++ = inbuffer[int(pos)]; + pos += delta; + } +} + +void Downsample_stereo(const int16 *inbuffer, int inframecount, int16 *outbuffer, int outframecount) +{ + double delta = double(inframecount) / double(outframecount); + double pos = 0.0; + while (outframecount--) { + int p = int(pos); + *outbuffer++ = inbuffer[p]; + *outbuffer++ = inbuffer[p+1]; + pos += delta; + } +} + +void Downsample_mono(const int16 *inbuffer, int inframecount, int16 *outbuffer, int outframecount) +{ + double delta = double(inframecount) / double(outframecount); + double pos = 0.0; + while (outframecount--) { + *outbuffer++ = inbuffer[int(pos)]; + pos += delta; + } +} + +void Downsample_stereo(const int8 *inbuffer, int inframecount, int8 *outbuffer, int outframecount) +{ + double delta = double(inframecount) / double(outframecount); + double pos = 0.0; + while (outframecount--) { + int p = int(pos); + *outbuffer++ = inbuffer[p]; + *outbuffer++ = inbuffer[p+1]; + pos += delta; + } +} + +void Downsample_mono(const int8 *inbuffer, int inframecount, int8 *outbuffer, int outframecount) +{ + double delta = double(inframecount) / double(outframecount); + double pos = 0.0; + while (outframecount--) { + *outbuffer++ = inbuffer[int(pos)]; + pos += delta; + } +} + +void Downsample_stereo(const uint8 *inbuffer, int inframecount, uint8 *outbuffer, int outframecount) +{ + double delta = double(inframecount) / double(outframecount); + double pos = 0.0; + while (outframecount--) { + int p = int(pos); + *outbuffer++ = inbuffer[p]; + *outbuffer++ = inbuffer[p+1]; + pos += delta; + } +} + +void Downsample_mono(const uint8 *inbuffer, int inframecount, uint8 *outbuffer, int outframecount) +{ + double delta = double(inframecount) / double(outframecount); + double pos = 0.0; + while (outframecount--) { + *outbuffer++ = inbuffer[int(pos)]; + pos += delta; + } +} + +} //namespace MediaKitPrivate diff --git a/src/kits/media/SharedBufferList.cpp b/src/kits/media/SharedBufferList.cpp new file mode 100644 index 0000000000..cd0f0077c5 --- /dev/null +++ b/src/kits/media/SharedBufferList.cpp @@ -0,0 +1,312 @@ +/*********************************************************************** + * Copyright (c) 2002 Marcus Overhagen. All Rights Reserved. + * This file may be used under the terms of the OpenBeOS License. + * + * Used for BBufferGroup and BBuffer management across teams + ***********************************************************************/ +#include +#include "SharedBufferList.h" +#include "debug.h" + + +status_t +_shared_buffer_list::Init() +{ + CALLED(); + locker_atom = 0; + locker_sem = create_sem(0,"shared buffer list lock"); + if (locker_sem < B_OK) + return (status_t) locker_sem; + + for (int i = 0; i < MAX_BUFFER; i++) { + info[i].id = -1; + info[i].buffer = 0; + info[i].reclaim_sem = 0; + info[i].reclaimed = false; + } + return B_OK; +} + +_shared_buffer_list * +_shared_buffer_list::Clone(area_id id) +{ + CALLED(); + // if id == -1, we are in the media_server team, + // and create the initial list, else we clone it + + _shared_buffer_list *adr; + status_t status; + + if (id == -1) { + size_t size = ((sizeof(_shared_buffer_list)) + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1); + status = create_area("shared buffer list",(void **)&adr,B_ANY_KERNEL_ADDRESS,size,B_LAZY_LOCK,B_READ_AREA | B_WRITE_AREA); + if (status >= B_OK) { + status = adr->Init(); + if (status != B_OK) + delete_area(area_for(adr)); + } + } else { + status = clone_area("shared buffer list clone",(void **)&adr,B_ANY_KERNEL_ADDRESS,B_READ_AREA | B_WRITE_AREA,id); + //TRACE("cloned area, id = 0x%08lx, ptr = 0x%08x\n",status,(int)adr); + } + + return (status < B_OK) ? NULL : adr; +} + +void +_shared_buffer_list::Unmap() +{ + // unmap the memory used by this struct + // XXX is this save? + area_id id; + id = area_for(this); + if (id >= B_OK) + delete_area(id); +} + +void +_shared_buffer_list::Terminate(sem_id group_reclaim_sem) +{ + CALLED(); + + // delete all BBuffers of this group, then unmap from memory + + if (Lock() != B_OK) { // better not try to access the list unlocked + // but at least try to unmap the memory + Unmap(); + return; + } + + for (int32 i = 0; i < buffercount; i++) { + if (info[i].reclaim_sem == group_reclaim_sem) { + // delete the associated buffer + delete info[i].buffer; + // decrement buffer count by one + buffercount--; + // fill the gap in the list with the last entry + if (buffercount > 0) { + info[i] = info[buffercount]; + i--; // make sure we check this entry again + } + } + } + + Unlock(); + + Unmap(); +} + +status_t +_shared_buffer_list::Lock() +{ + if (atomic_add(&locker_atom, 1) > 0) { + status_t status; + while (B_INTERRUPTED == (status = acquire_sem(locker_sem))) + ; + return status; // will only return != B_OK if the media_server crashed or quit + } + return B_OK; +} + +status_t +_shared_buffer_list::Unlock() +{ + if (atomic_add(&locker_atom, -1) > 1) + return release_sem(locker_sem); // will only return != B_OK if the media_server crashed or quit + return B_OK; +} + +status_t +_shared_buffer_list::AddBuffer(sem_id group_reclaim_sem, BBuffer *buffer) +{ + CALLED(); + + if (buffer == NULL) + return B_BAD_VALUE; + + if (Lock() != B_OK) + return B_ERROR; + + if (buffercount == MAX_BUFFER) { + Unlock(); + debugger("we are doomed"); + return B_ERROR; + } + + info[buffercount].id = buffer->ID(); + info[buffercount].buffer = buffer; + info[buffercount].reclaim_sem = group_reclaim_sem; + info[buffercount].reclaimed = true; + buffercount++; + + status_t status1 = release_sem_etc(group_reclaim_sem,1,B_DO_NOT_RESCHEDULE); + status_t status2 = Unlock(); + + return (status1 == B_OK && status2 == B_OK) ? B_OK : B_ERROR; +} + +status_t +_shared_buffer_list::RequestBuffer(sem_id group_reclaim_sem, int32 buffers_in_group, size_t size, media_buffer_id wantID, BBuffer **buffer, bigtime_t timeout) +{ + CALLED(); + // we always search for a buffer from the group indicated by group_reclaim_sem first + // if "size" != 0, we search for a buffer that is "size" bytes or larger + // if "wantID" != 0, we search for a buffer with this id + // if "*buffer" != NULL, we search for a buffer at this address + // if we found a buffer, we also need to mark it in all other groups as requested + // and also once need to acquire the reclaim_sem of the other groups + + status_t status; + uint32 acquire_flags; + int32 count; + + if (timeout <= 0) { + timeout = 0; + acquire_flags = B_RELATIVE_TIMEOUT; + } else if (timeout != B_INFINITE_TIMEOUT) { + timeout += system_time(); + acquire_flags = B_ABSOLUTE_TIMEOUT; + } else { + //timeout is B_INFINITE_TIMEOUT + acquire_flags = B_RELATIVE_TIMEOUT; + } + + // with each itaration we request one more buffer, since we need to skip the buffers that don't fit the request + count = 1; + + do { + while (B_INTERRUPTED == (status = acquire_sem_etc(group_reclaim_sem, count, acquire_flags, timeout))) + ; + if (status != B_OK) + return status; + + // try to exit savely if the lock fails + if (Lock() != B_OK) { + release_sem_etc(group_reclaim_sem, count, 0); + return B_ERROR; + } + + for (int32 i = 0; i < buffercount; i++) { + // we need a BBuffer from the group, and it must be marked as reclaimed + if (info[i].reclaim_sem == group_reclaim_sem && info[i].reclaimed) { + if ( + (size != 0 && size <= info[i].buffer->SizeAvailable()) || + (*buffer != 0 && info[i].buffer == *buffer) || + (wantID != 0 && info[i].id == wantID) + ) { + // we found a buffer + info[i].reclaimed = false; + *buffer = info[i].buffer; + // if we requested more than one buffer, release the rest + if (count > 1) + release_sem_etc(group_reclaim_sem, count - 1, B_DO_NOT_RESCHEDULE); + + // and mark all buffers with the same ID as requested in all other buffer groups + RequestBufferInOtherGroups(group_reclaim_sem, info[i].buffer->ID()); + + Unlock(); + return B_OK; + } + } + } + + release_sem_etc(group_reclaim_sem, count, B_DO_NOT_RESCHEDULE); + if (Unlock() != B_OK) + return B_ERROR; + + // prepare to request one more buffer next time + count++; + } while (count <= buffers_in_group); + + return B_ERROR; +} + +void +_shared_buffer_list::RequestBufferInOtherGroups(sem_id group_reclaim_sem, media_buffer_id id) +{ + for (int32 i = 0; i < buffercount; i++) { + // find buffers with same id, but belonging to other groups + if (info[i].id == id && info[i].reclaim_sem != group_reclaim_sem) { + + // and mark them as requested + // XXX this can deadlock if BBuffers with same media_buffer_id + // XXX exist in more than one BBufferGroup, and RequestBuffer() + // XXX is called on both groups (which should not be done). + status_t status; + while (B_INTERRUPTED == (status = acquire_sem(info[i].reclaim_sem))) + ; + // try to skip entries that belong to crashed teams + if (status != B_OK) + continue; + + if (info[i].reclaimed == false) { + TRACE("Error, BBuffer 0x%08x, id = 0x%08x not reclaimed while requesting\n",(int)info[i].buffer,(int)id); + continue; + } + + info[i].reclaimed = false; + } + } +} + +status_t +_shared_buffer_list::RecycleBuffer(BBuffer *buffer) +{ + CALLED(); + + int reclaimed_count; + + media_buffer_id id = buffer->ID(); + + if (Lock() != B_OK) + return B_ERROR; + + reclaimed_count = 0; + for (int32 i = 0; i < buffercount; i++) { + // find the buffer id, and reclaim it in all groups it belongs to + if (info[i].id == id) { + reclaimed_count++; + if (info[i].reclaimed) { + TRACE("Error, BBuffer 0x%08x, id = 0x%08x already reclaimed\n",(int)buffer,(int)id); + continue; + } + info[i].reclaimed = true; + release_sem_etc(info[i].reclaim_sem, 1, B_DO_NOT_RESCHEDULE); + } + } + if (Unlock() != B_OK) + return B_ERROR; + + if (reclaimed_count == 0) { + TRACE("Error, BBuffer 0x%08x, id = 0x%08x NOT reclaimed\n",(int)buffer,(int)id); + return B_ERROR; + } + + return B_OK; +} + +status_t +_shared_buffer_list::GetBufferList(sem_id group_reclaim_sem, int32 buf_count, BBuffer **out_buffers) +{ + CALLED(); + + int32 found; + + found = 0; + + if (Lock() != B_OK) + return B_ERROR; + + for (int32 i = 0; i < buffercount; i++) + if (info[i].reclaim_sem == group_reclaim_sem) { + out_buffers[found++] = info[i].buffer; + if (found == buf_count) + break; + } + + if (Unlock() != B_OK) + return B_ERROR; + + return (found == buf_count) ? B_OK : B_ERROR; +} + diff --git a/src/kits/media/Sound.cpp b/src/kits/media/Sound.cpp new file mode 100644 index 0000000000..50468d5786 --- /dev/null +++ b/src/kits/media/Sound.cpp @@ -0,0 +1,187 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: Sound.cpp + * DESCR: + ***********************************************************************/ + +#include +#include "debug.h" + +/************************************************************* + * public BSound + *************************************************************/ + +BSound::BSound( void * data, + size_t size, + const media_raw_audio_format & format, + bool free_when_done = false) +{ + UNIMPLEMENTED(); +} + +BSound::BSound( const entry_ref * sound_file, + bool load_into_memory = false) +{ + UNIMPLEMENTED(); +} + +status_t +BSound::InitCheck() +{ + UNIMPLEMENTED(); + + return B_OK; +} + +BSound * +BSound::AcquireRef() +{ + UNIMPLEMENTED(); + return 0; +} + +bool +BSound::ReleaseRef() +{ + UNIMPLEMENTED(); + return 0; +} + +int32 +BSound::RefCount() const +{ + UNIMPLEMENTED(); + return 0; +} // unreliable! + +/* virtual */ bigtime_t +BSound::Duration() const +{ + UNIMPLEMENTED(); + return 0; +} + +/* virtual */ const media_raw_audio_format & +BSound::Format() const +{ + UNIMPLEMENTED(); + return _m_format; +} + +/* virtual */ const void * +BSound::Data() const +{ + UNIMPLEMENTED(); + return 0; +} /* returns NULL for files */ + +/* virtual */ off_t +BSound::Size() const +{ + UNIMPLEMENTED(); + return 0; +} + +/* virtual */ bool +BSound::GetDataAt(off_t offset, + void * into_buffer, + size_t buffer_size, + size_t * out_used) +{ + UNIMPLEMENTED(); + return 0; +} + +/************************************************************* + * protected BSound + *************************************************************/ + +BSound::BSound(const media_raw_audio_format & format) +{ + UNIMPLEMENTED(); +} + +/* virtual */ status_t +BSound::Perform(int32 code,...) +{ + UNIMPLEMENTED(); + return 0; +} + +/************************************************************* + * private BSound + *************************************************************/ + +/* +BSound::BSound(const BSound &); // unimplemented +BSound & BSound::operator=(const BSound &); // unimplemented +*/ + +void +BSound::Reset() +{ + UNIMPLEMENTED(); +} + +/* virtual */ +BSound::~BSound() +{ + UNIMPLEMENTED(); +} + +void +BSound::free_data() +{ + UNIMPLEMENTED(); +} + +/* static */ status_t +BSound::load_entry(void * arg) +{ + UNIMPLEMENTED(); + return 0; +} + +void +BSound::loader_thread() +{ + UNIMPLEMENTED(); +} + +bool +BSound::check_stop() +{ + UNIMPLEMENTED(); + return 0; +} + +/************************************************************* + * public BSound + *************************************************************/ + +/* virtual */ status_t +BSound::BindTo(BSoundPlayer * player, + const media_raw_audio_format & format) +{ + UNIMPLEMENTED(); + return 0; +} + +/* virtual */ status_t +BSound::UnbindFrom(BSoundPlayer * player) +{ + UNIMPLEMENTED(); + return 0; +} + +/************************************************************* + * private BSound + *************************************************************/ + +status_t BSound::_Reserved_Sound_0(void *) { return B_ERROR; } +status_t BSound::_Reserved_Sound_1(void *) { return B_ERROR; } +status_t BSound::_Reserved_Sound_2(void *) { return B_ERROR; } +status_t BSound::_Reserved_Sound_3(void *) { return B_ERROR; } +status_t BSound::_Reserved_Sound_4(void *) { return B_ERROR; } +status_t BSound::_Reserved_Sound_5(void *) { return B_ERROR; } + diff --git a/src/kits/media/SoundFile.cpp b/src/kits/media/SoundFile.cpp new file mode 100644 index 0000000000..23f2dc4d74 --- /dev/null +++ b/src/kits/media/SoundFile.cpp @@ -0,0 +1,344 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: SoundFile.cpp + * DESCR: + ***********************************************************************/ +#include +#include "debug.h" + +/************************************************************* + * public BSoundFile + *************************************************************/ + +BSoundFile::BSoundFile() +{ + UNIMPLEMENTED(); +} + + +BSoundFile::BSoundFile(const entry_ref *ref, + uint32 open_mode) +{ + UNIMPLEMENTED(); +} + +/* virtual */ +BSoundFile::~BSoundFile() +{ + UNIMPLEMENTED(); +} + + +status_t +BSoundFile::InitCheck() const +{ + UNIMPLEMENTED(); + + return B_OK; +} + + +status_t +BSoundFile::SetTo(const entry_ref *ref, + uint32 open_mode) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +int32 +BSoundFile::FileFormat() const +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +int32 +BSoundFile::SamplingRate() const +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +int32 +BSoundFile::CountChannels() const +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +int32 +BSoundFile::SampleSize() const +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +int32 +BSoundFile::ByteOrder() const +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +int32 +BSoundFile::SampleFormat() const +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +int32 +BSoundFile::FrameSize() const +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +off_t +BSoundFile::CountFrames() const +{ + UNIMPLEMENTED(); + off_t dummy; + + return dummy; +} + + +bool +BSoundFile::IsCompressed() const +{ + UNIMPLEMENTED(); + bool dummy; + + return dummy; +} + + +int32 +BSoundFile::CompressionType() const +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +char * +BSoundFile::CompressionName() const +{ + UNIMPLEMENTED(); + return NULL; +} + + +/* virtual */ int32 +BSoundFile::SetFileFormat(int32 format) +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +/* virtual */ int32 +BSoundFile::SetSamplingRate(int32 fps) +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +/* virtual */ int32 +BSoundFile::SetChannelCount(int32 spf) +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +/* virtual */ int32 +BSoundFile::SetSampleSize(int32 bps) +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +/* virtual */ int32 +BSoundFile::SetByteOrder(int32 bord) +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +/* virtual */ int32 +BSoundFile::SetSampleFormat(int32 fmt) +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +/* virtual */ int32 +BSoundFile::SetCompressionType(int32 type) +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +/* virtual */ char * +BSoundFile::SetCompressionName(char *name) +{ + UNIMPLEMENTED(); + return NULL; +} + + +/* virtual */ bool +BSoundFile::SetIsCompressed(bool tf) +{ + UNIMPLEMENTED(); + bool dummy; + + return dummy; +} + + +/* virtual */ off_t +BSoundFile::SetDataLocation(off_t offset) +{ + UNIMPLEMENTED(); + off_t dummy; + + return dummy; +} + + +/* virtual */ off_t +BSoundFile::SetFrameCount(off_t count) +{ + UNIMPLEMENTED(); + off_t dummy; + + return dummy; +} + + +size_t +BSoundFile::ReadFrames(char *buf, + size_t count) +{ + UNIMPLEMENTED(); + size_t dummy; + + return dummy; +} + + +size_t +BSoundFile::WriteFrames(char *buf, + size_t count) +{ + UNIMPLEMENTED(); + size_t dummy; + + return dummy; +} + + +/* virtual */ off_t +BSoundFile::SeekToFrame(off_t n) +{ + UNIMPLEMENTED(); + off_t dummy; + + return dummy; +} + + +off_t +BSoundFile::FrameIndex() const +{ + UNIMPLEMENTED(); + off_t dummy; + + return dummy; +} + + +off_t +BSoundFile::FramesRemaining() const +{ + UNIMPLEMENTED(); + off_t dummy; + + return dummy; +} + +/************************************************************* + * private BSoundFile + *************************************************************/ + + +void BSoundFile::_ReservedSoundFile1() {} +void BSoundFile::_ReservedSoundFile2() {} +void BSoundFile::_ReservedSoundFile3() {} + +void +BSoundFile::_init_raw_stats() +{ + UNIMPLEMENTED(); +} + + +status_t +BSoundFile::_ref_to_file(const entry_ref *ref) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + diff --git a/src/kits/media/SoundPlayNode.cpp b/src/kits/media/SoundPlayNode.cpp new file mode 100644 index 0000000000..d0c19386de --- /dev/null +++ b/src/kits/media/SoundPlayNode.cpp @@ -0,0 +1,438 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: SoundPlayNode.cpp + * DESCR: This is the BBufferProducer, used internally by BSoundPlayer + * This belongs into a private namespace, but isn't for + * compatibility reasons. + ***********************************************************************/ + +//#include +#include +#include +#include +#include "SoundPlayNode.h" +#include "debug.h" +#include "ChannelMixer.h" +#include "SampleConverter.h" +#include "SamplingrateConverter.h" + +#include +#include +#include + +int driver; +sem_id sem; + +enum { + SOUND_GET_PARAMS = B_DEVICE_OP_CODES_END, + SOUND_SET_PARAMS, + SOUND_SET_PLAYBACK_COMPLETION_SEM, + SOUND_SET_CAPTURE_COMPLETION_SEM, + SOUND_RESERVED_1, /* unused */ + SOUND_RESERVED_2, /* unused */ + SOUND_DEBUG_ON, /* unused */ + SOUND_DEBUG_OFF, /* unused */ + SOUND_WRITE_BUFFER, + SOUND_READ_BUFFER, + SOUND_LOCK_FOR_DMA +}; + +typedef struct audio_buffer_header { + int32 buffer_number; + int32 subscriber_count; + bigtime_t time; + int32 reserved_1; + int32 reserved_2; + int32 reserved_3; + int32 reserved_4; +} audio_buffer_header; + +enum adc_source { + line = 0, cd, mic, loopback +}; + +enum sample_rate { + kHz_8_0 = 0, kHz_5_51, kHz_16_0, kHz_11_025, kHz_27_42, + kHz_18_9, kHz_32_0, kHz_22_05, kHz_37_8 = 9, + kHz_44_1 = 11, kHz_48_0, kHz_33_075, kHz_9_6, kHz_6_62 +}; + +enum sample_format {}; /* obsolete */ + +struct channel { + enum adc_source adc_source; + char adc_gain; + char mic_gain_enable; + char cd_mix_gain; + char cd_mix_mute; + char aux2_mix_gain; + char aux2_mix_mute; + char line_mix_gain; + char line_mix_mute; + char dac_attn; + char dac_mute; +}; + +typedef struct sound_setup { + struct channel left; + struct channel right; + enum sample_rate sample_rate; + enum sample_format playback_format; + enum sample_format capture_format; + char dither_enable; + char mic_attn; + char mic_enable; + char output_boost; + char highpass_enable; + char mono_gain; + char mono_mute; +} sound_setup; + +sound_setup setup = +{ + { line, 15, 0, 31,0,0,0,31,0,6 /* dac attenuation */,0 }, /* left channel*/ + { line, 15, 0, 31,0,0,0,31,0,6 /* dac attenuation */,0 }, /* right channel*/ + kHz_44_1, /* sample rate */ + (sample_format)0, /* ignore (always 16bit-linear) */ + (sample_format)0, /* ignore (always 16bit-linear) */ + 0, /* non-zero enables dither on 16 => 8 bit */ + 0, /* 0..64 mic input level */ + 0, /* non-zero enables mic input */ + 0, /* ignore (always on) */ + 0, /* ignore (always on) */ + 9, /* 0..64 mono speaker gain */ + 0 /* non-zero mutes speaker */ +}; + + +_SoundPlayNode::_SoundPlayNode(const char *name, const media_multi_audio_format *format, BSoundPlayer *player) : + BBufferProducer(B_MEDIA_RAW_AUDIO), + BMediaNode(name) +{ + TRACE("_SoundPlayNode\n"); + fFormat = *format; + fPlayer = player; + fThreadId = -1; + + fFramesPerBuffer = fFormat.buffer_size / (fFormat.channel_count * (fFormat.format & media_raw_audio_format::B_AUDIO_SIZE_MASK)); + + printf("Format Info:\n"); + printf(" frame_rate: %f\n",fFormat.frame_rate); + printf(" channel_count: %ld\n",fFormat.channel_count); + printf(" byte_order: %ld (",fFormat.byte_order); + switch (fFormat.byte_order) { + case B_MEDIA_BIG_ENDIAN: printf("B_MEDIA_BIG_ENDIAN)\n"); break; + case B_MEDIA_LITTLE_ENDIAN: printf("B_MEDIA_LITTLE_ENDIAN)\n"); break; + default: printf("unknown)\n"); break; + } + printf(" buffer_size: %ld\n",fFormat.buffer_size); + printf(" format: %ld (",fFormat.format); + switch (fFormat.format) { + case media_raw_audio_format::B_AUDIO_FLOAT: printf("B_AUDIO_FLOAT)\n"); break; + case media_raw_audio_format::B_AUDIO_SHORT: printf("B_AUDIO_SHORT)\n"); break; + case media_raw_audio_format::B_AUDIO_INT: printf("B_AUDIO_INT)\n"); break; + case media_raw_audio_format::B_AUDIO_CHAR: printf("B_AUDIO_CHAR)\n"); break; + case media_raw_audio_format::B_AUDIO_UCHAR: printf("B_AUDIO_UCHAR)\n"); break; + default: printf("unknown)\n"); break; + } + + driver = open("/dev/audio/old/awe64/1", O_RDWR); + if (driver <= 0) + debugger("couldn't open soundcard device driver\n"); + + sem = create_sem(0,"sem"); + ioctl(driver,SOUND_SET_PARAMS,&setup); + ioctl(driver,SOUND_SET_PLAYBACK_COMPLETION_SEM,&sem); +} + + +_SoundPlayNode::~_SoundPlayNode() +{ + TRACE("~_SoundPlayNode\n"); + Stop(); + close(driver); +} + + +media_multi_audio_format +_SoundPlayNode::Format() const +{ + return fFormat; +} + + +/* virtual */ status_t +_SoundPlayNode::FormatSuggestionRequested( + media_type type, + int32 quality, + media_format * format) +{ + return B_ERROR; +} + + +/* virtual */ status_t +_SoundPlayNode::FormatProposal( + const media_source & output, + media_format * format) +{ + return B_ERROR; +} + + +/* If the format isn't good, put a good format into *io_format and return error */ +/* If format has wildcard, specialize to what you can do (and change). */ +/* If you can change the format, return OK. */ +/* The request comes from your destination sychronously, so you cannot ask it */ +/* whether it likes it -- you should assume it will since it asked. */ +/* virtual */ status_t +_SoundPlayNode::FormatChangeRequested( + const media_source & source, + const media_destination & destination, + media_format * io_format, + int32 * _deprecated_) +{ + return B_ERROR; +} + + +/* virtual */ status_t +_SoundPlayNode::GetNextOutput( /* cookie starts as 0 */ + int32 * cookie, + media_output * out_output) +{ + return B_ERROR; +} + + +/* virtual */ status_t +_SoundPlayNode::DisposeOutputCookie( + int32 cookie) +{ + return B_ERROR; +} + + +/* In this function, you should either pass on the group to your upstream guy, */ +/* or delete your current group and hang on to this group. Deleting the previous */ +/* group (unless you passed it on with the reclaim flag set to false) is very */ +/* important, else you will 1) leak memory and 2) block someone who may want */ +/* to reclaim the buffers living in that group. */ +/* virtual */ status_t +_SoundPlayNode::SetBufferGroup( + const media_source & for_source, + BBufferGroup * group) +{ + return B_ERROR; +} + + +/* Format of clipping is (as int16-s): . */ +/* Repeat for each line where the clipping is different from the previous line. */ +/* If is negative, use the data from line - (there are 0 pairs after */ +/* a negative . Yes, we only support 32k*32k frame buffers for clipping. */ +/* Any non-0 field of 'display' means that that field changed, and if you don't support */ +/* that change, you should return an error and ignore the request. Note that the buffer */ +/* offset values do not have wildcards; 0 (or -1, or whatever) are real values and must */ +/* be adhered to. */ +/* virtual */ status_t +_SoundPlayNode::VideoClippingChanged( + const media_source & for_source, + int16 num_shorts, + int16 * clip_data, + const media_video_display_info & display, + int32 * _deprecated_) +{ + return B_ERROR; +} + + +/* Iterates over all outputs and maxes the latency found */ +/* virtual */ status_t +_SoundPlayNode::GetLatency( + bigtime_t * out_lantency) +{ + return B_ERROR; +} + + +/* virtual */ status_t +_SoundPlayNode::PrepareToConnect( + const media_source & what, + const media_destination & where, + media_format * format, + media_source * out_source, + char * out_name) +{ + return B_ERROR; +} + + +/* virtual */ void +_SoundPlayNode::Connect( + status_t error, + const media_source & source, + const media_destination & destination, + const media_format & format, + char * io_name) +{ +} + + +/* virtual */ void +_SoundPlayNode::Disconnect( + const media_source & what, + const media_destination & where) +{ +} + + +/* virtual */ void +_SoundPlayNode::LateNoticeReceived( + const media_source & what, + bigtime_t how_much, + bigtime_t performance_time) +{ +} + + +/* virtual */ void +_SoundPlayNode::EnableOutput( + const media_source & what, + bool enabled, + int32 * _deprecated_) +{ +} + + +/* Who instantiated you -- or NULL for app class */ +/* virtual */ BMediaAddOn* +_SoundPlayNode::AddOn(int32 * internal_id) const +{ + return NULL; +} + +void +_SoundPlayNode::Start() +{ + TRACE("_SoundPlayNode::Start\n"); + if (fThreadId != -1) + return; + + fStopThread = false; + fThreadId = spawn_thread(threadstart,"OpenBeOS play thread",105,this); + resume_thread(fThreadId); +} + +void +_SoundPlayNode::Stop() +{ + TRACE("_SoundPlayNode::Stop\n"); + if (fThreadId == -1) + return; + + fStopThread = true; + + status_t dummy; + wait_for_thread(fThreadId,&dummy); + fThreadId = -1; +} + + +int32 +_SoundPlayNode::threadstart(void *arg) +{ + ((_SoundPlayNode *)arg)->PlayThread(); + return 0; +} + + +void +_SoundPlayNode::PlayThread() +{ + /* + * without real media nodes, timesources, and other stuff, + * it's not easy to provide accurate audio playback + */ + double buffer_time = (1000000.0 * fFramesPerBuffer) / fFormat.frame_rate; + bool ChangeSampleformat = fFormat.format != media_raw_audio_format::B_AUDIO_SHORT; + bool ChangeSamplingrate = fFormat.frame_rate != 44100.0f; + bool ChangeChannelcount = fFormat.channel_count != 2; + int ResampledFramesPerBuffer = int(0.5f + (fFramesPerBuffer * (44100.0f / fFormat.frame_rate))); + void *temp1 = 0; + void *temp2 = 0; + void *temp3 = 0; + + if (ChangeSampleformat) + temp1 = new char [(fFormat.format & 0xf) * fFramesPerBuffer * fFormat.channel_count]; + if (ChangeSamplingrate) + temp2 = new char [sizeof(uint16) * ResampledFramesPerBuffer * fFormat.channel_count]; + if (ChangeChannelcount) + temp3 = new char [sizeof(uint16) * ResampledFramesPerBuffer * 2]; + + TRACE("_SoundPlayNode::PlayThread: ChangeSampleformat = %d, ChangeSamplingrate = %d, ChangeChannelcount = %d\n", + ChangeSampleformat,ChangeSamplingrate,ChangeChannelcount); + + double buf_nb; + bigtime_t start; + void *source; + + char *buf = new char [2 * 2 * ResampledFramesPerBuffer + sizeof(audio_buffer_header)]; + char *buffer = buf + sizeof(audio_buffer_header); + audio_buffer_header *header = (audio_buffer_header *)buf; + header->reserved_1 = 2 * 2 * ResampledFramesPerBuffer + sizeof(audio_buffer_header); + + start = system_time() + 50000; + buf_nb = 0; + while (!fStopThread) { + if (fPlayer->_m_has_data != 0) { + memset(fPlayer->_m_buf,0,fPlayer->_m_bufsize); + fPlayer->PlayBuffer(fPlayer->_m_buf,fPlayer->_m_bufsize,(const media_raw_audio_format)fFormat); + source = fPlayer->_m_buf; + if (ChangeSampleformat) { + MediaKitPrivate::SampleConverter::convert( + temp1, media_raw_audio_format::B_AUDIO_SHORT, + source, fFormat.format, + fFramesPerBuffer * fFormat.channel_count); + source = temp1; + } + if (ChangeSamplingrate) { + MediaKitPrivate::SamplingrateConverter::convert( + temp2, ResampledFramesPerBuffer, + source, fFramesPerBuffer, + media_raw_audio_format::B_AUDIO_SHORT, + fFormat.channel_count); + source = temp2; + } + if (ChangeChannelcount) { + MediaKitPrivate::ChannelMixer::mix( + temp3, 2, + source, fFormat.channel_count, + ResampledFramesPerBuffer, + media_raw_audio_format::B_AUDIO_SHORT); + source = temp3; + } +// if (fFormat.byte_order == B_MEDIA_LITTLE_ENDIAN) +// swap_data(B_INT16_TYPE,source,ResampledFramesPerBuffer * 2 * 2,B_SWAP_ALWAYS); + //at this place, we have a buffer with sound data + //of 2 channels, 16bit integer samples, at 44100 frames/sec + //pointer: source + //framecount: ResampledFramesPerBuffer + +// snooze_until(start + bigtime_t(buf_nb++ * buffer_time),B_SYSTEM_TIMEBASE); + buf_nb++; + memcpy(buffer,source,ResampledFramesPerBuffer * 2 * 2); + ioctl(driver,SOUND_WRITE_BUFFER,buf); + acquire_sem(sem); + + } else { + snooze_until(start + bigtime_t(buf_nb++ * buffer_time),B_SYSTEM_TIMEBASE); + } + } + TRACE("_SoundPlayNode::PlayThread: %.0f buffers processed\n",buf_nb); + delete [] temp1; + delete [] temp2; + delete [] temp3; + delete [] buf; +} + diff --git a/src/kits/media/SoundPlayNode.h b/src/kits/media/SoundPlayNode.h new file mode 100644 index 0000000000..e00996dbe2 --- /dev/null +++ b/src/kits/media/SoundPlayNode.h @@ -0,0 +1,91 @@ +#ifndef _SOUND_PLAY_NODE_ +#define _SOUND_PLAY_NODE_ + +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: SoundPlayNode.h + * DESCR: This is the BBufferProducer, used internally by BSoundPlayer + * This belongs into a private namespace, but isn't for + * compatibility reasons. + ***********************************************************************/ + +class _SoundPlayNode : public BBufferProducer +{ +public: + _SoundPlayNode(const char *name, const media_multi_audio_format *format, BSoundPlayer *player); + ~_SoundPlayNode(); + + media_multi_audio_format Format() const; + +private: + + virtual status_t FormatSuggestionRequested( + media_type type, + int32 quality, + media_format * format); + virtual status_t FormatProposal( + const media_source & output, + media_format * format); + virtual status_t FormatChangeRequested( + const media_source & source, + const media_destination & destination, + media_format * io_format, + int32 * _deprecated_); + virtual status_t GetNextOutput( /* cookie starts as 0 */ + int32 * cookie, + media_output * out_output); + virtual status_t DisposeOutputCookie( + int32 cookie); + virtual status_t SetBufferGroup( + const media_source & for_source, + BBufferGroup * group); + virtual status_t VideoClippingChanged( + const media_source & for_source, + int16 num_shorts, + int16 * clip_data, + const media_video_display_info & display, + int32 * _deprecated_); + virtual status_t GetLatency( + bigtime_t * out_lantency); + virtual status_t PrepareToConnect( + const media_source & what, + const media_destination & where, + media_format * format, + media_source * out_source, + char * out_name); + virtual void Connect( + status_t error, + const media_source & source, + const media_destination & destination, + const media_format & format, + char * io_name); + virtual void Disconnect( + const media_source & what, + const media_destination & where); + virtual void LateNoticeReceived( + const media_source & what, + bigtime_t how_much, + bigtime_t performance_time); + virtual void EnableOutput( + const media_source & what, + bool enabled, + int32 * _deprecated_); + + virtual BMediaAddOn* AddOn( + int32 * internal_id) const; + +public: + void Start(); + void Stop(); + +private: + int fFramesPerBuffer; + thread_id fThreadId; + volatile bool fStopThread; + static int32 threadstart(void *arg); + void PlayThread(); + media_multi_audio_format fFormat; + BSoundPlayer *fPlayer; +}; + +#endif diff --git a/src/kits/media/SoundPlayer.cpp b/src/kits/media/SoundPlayer.cpp new file mode 100644 index 0000000000..1ca318b3e4 --- /dev/null +++ b/src/kits/media/SoundPlayer.cpp @@ -0,0 +1,541 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: SoundPlayer.cpp + * DESCR: + ***********************************************************************/ +#include +#include +#include +#include + +#include "debug.h" +#include "SoundPlayNode.h" + +/* this is the normal volume DB range of 16 bit integer */ +const float minDB = -96; +const float maxDB = 0; + +/************************************************************* + * public sound_error + *************************************************************/ + +//final +sound_error::sound_error(const char *str) +{ + CALLED(); + m_str_const = str; +} + +//final +const char * +sound_error::what() const +{ + CALLED(); + return m_str_const; +} + +/************************************************************* + * public BSoundPlayer + *************************************************************/ + +BSoundPlayer::BSoundPlayer(const char * name, + void (*PlayBuffer)(void *, void * buffer, size_t size, const media_raw_audio_format & format), + void (*Notifier)(void *, sound_player_notification what, ...), + void * cookie) +{ + CALLED(); + + Init(NULL,&media_multi_audio_format::wildcard,name,NULL,PlayBuffer,Notifier,cookie); +} + +BSoundPlayer::BSoundPlayer(const media_raw_audio_format * format, + const char * name, + void (*PlayBuffer)(void *, void * buffer, size_t size, const media_raw_audio_format & format), + void (*Notifier)(void *, sound_player_notification what, ...), + void * cookie) +{ + CALLED(); + media_multi_audio_format fmt = media_multi_audio_format::wildcard; + memcpy(&fmt,format,sizeof(*format)); + Init(NULL,&fmt,name,NULL,PlayBuffer,Notifier,cookie); +} + +BSoundPlayer::BSoundPlayer(const media_node & toNode, + const media_multi_audio_format * format, + const char * name, + const media_input * input, + void (*PlayBuffer)(void *, void * buffer, size_t size, const media_raw_audio_format & format), + void (*Notifier)(void *, sound_player_notification what, ...), + void * cookie) +{ + CALLED(); + if (toNode.kind & B_BUFFER_CONSUMER == 0) + debugger("BSoundPlayer: toNode must have B_BUFFER_CONSUMER kind!\n"); + Init(&toNode,format,name,input,PlayBuffer,Notifier,cookie); +} + +/* virtual */ +BSoundPlayer::~BSoundPlayer() +{ + CALLED(); + if (_m_node) + _m_node->Release(); + delete _m_node; + delete [] _m_buf; +} + + +status_t +BSoundPlayer::InitCheck() +{ + CALLED(); + return _m_init_err; +} + + +media_raw_audio_format +BSoundPlayer::Format() const +{ + CALLED(); + + media_raw_audio_format temp = media_raw_audio_format::wildcard; + + if (_m_node) { + media_multi_audio_format fmt; + fmt = _m_node->Format(); + memcpy(&temp,&fmt,sizeof(temp)); + } + + return temp; +} + + +status_t +BSoundPlayer::Start() +{ + CALLED(); + + if (!_m_node) + return B_ERROR; + + _m_node->Start(); + return B_OK; +} + + +void +BSoundPlayer::Stop(bool block, + bool flush) +{ + CALLED(); + + if (!_m_node) + return; + + _m_node->Stop(); +} + +BSoundPlayer::BufferPlayerFunc +BSoundPlayer::BufferPlayer() const +{ + CALLED(); + return _PlayBuffer; +} + +void BSoundPlayer::SetBufferPlayer(void (*PlayBuffer)(void *, void * buffer, size_t size, const media_raw_audio_format & format)) +{ + CALLED(); + _m_lock.Lock(); + _PlayBuffer = PlayBuffer; + _m_lock.Unlock(); +} + +BSoundPlayer::EventNotifierFunc +BSoundPlayer::EventNotifier() const +{ + CALLED(); + return _Notifier; +} + +void BSoundPlayer::SetNotifier(void (*Notifier)(void *, sound_player_notification what, ...)) +{ + CALLED(); + _m_lock.Lock(); + _Notifier = Notifier; + _m_lock.Unlock(); +} + +void * +BSoundPlayer::Cookie() const +{ + CALLED(); + return _m_cookie; +} + +void +BSoundPlayer::SetCookie(void *cookie) +{ + CALLED(); + _m_lock.Lock(); + _m_cookie = cookie; + _m_lock.Unlock(); +} + +void BSoundPlayer::SetCallbacks(void (*PlayBuffer)(void *, void * buffer, size_t size, const media_raw_audio_format & format), + void (*Notifier)(void *, sound_player_notification what, ...), + void * cookie) +{ + CALLED(); + _m_lock.Lock(); + SetBufferPlayer(PlayBuffer); + SetNotifier(Notifier); + SetCookie(cookie); + _m_lock.Unlock(); +} + + +bigtime_t +BSoundPlayer::CurrentTime() +{ + CALLED(); + if (!_m_node) + return system_time(); +#if 0 /* we don't have a media roster, or real media nodes yet */ + return _m_node->TimeSource()->Now(); /* either this one is wrong */ +#endif + return system_time(); +} + + +bigtime_t +BSoundPlayer::PerformanceTime() +{ + CALLED(); + if (!_m_node) + return (bigtime_t) B_ERROR; +#if 0 /* we don't have a media roster, or real media nodes yet */ + return _m_node->TimeSource()->Now(); /* or this one is wrong */ +#endif + return system_time(); +} + + +status_t +BSoundPlayer::Preroll() +{ + UNIMPLEMENTED(); + + return B_OK; +} + + +BSoundPlayer::play_id +BSoundPlayer::StartPlaying(BSound *sound, + bigtime_t at_time) +{ + UNIMPLEMENTED(); + return 1; +} + + +BSoundPlayer::play_id +BSoundPlayer::StartPlaying(BSound *sound, + bigtime_t at_time, + float with_volume) +{ + UNIMPLEMENTED(); + return 1; +} + + +status_t +BSoundPlayer::SetSoundVolume(play_id sound, + float new_volume) +{ + UNIMPLEMENTED(); + + return B_OK; +} + + +bool +BSoundPlayer::IsPlaying(play_id id) +{ + UNIMPLEMENTED(); + + return true; +} + + +status_t +BSoundPlayer::StopPlaying(play_id id) +{ + UNIMPLEMENTED(); + + return B_OK; +} + + +status_t +BSoundPlayer::WaitForSound(play_id id) +{ + UNIMPLEMENTED(); + + return B_OK; +} + + +float +BSoundPlayer::Volume() +{ + CALLED(); + return _m_volume; +} + + +void +BSoundPlayer::SetVolume(float new_volume) +{ + CALLED(); + _m_lock.Lock(); + if (new_volume >= 0.0f) + _m_volume = new_volume; + _m_lock.Unlock(); +} + + +float +BSoundPlayer::VolumeDB(bool forcePoll) +{ + CALLED(); + return 20.0f * log10(_m_volume); +} + + +void +BSoundPlayer::SetVolumeDB(float volume_dB) +{ + CALLED(); + _m_lock.Lock(); + _m_volume = pow(10.0f,volume_dB / 20.0f); + _m_lock.Unlock(); +} + + +status_t +BSoundPlayer::GetVolumeInfo(media_node *out_node, + int32 *out_parameter, + float *out_min_dB, + float *out_max_dB) +{ + BROKEN(); + + *out_node = m_output.node; + *out_parameter = -1; /* is the parameter ID for the volume control */ + *out_min_dB = minDB; + *out_max_dB = maxDB; + + return B_OK; +} + + +bigtime_t +BSoundPlayer::Latency() +{ + BROKEN(); + return 50000; +} + + +/* virtual */ bool +BSoundPlayer::HasData() +{ + CALLED(); + + return _m_has_data != 0; +} + + +void +BSoundPlayer::SetHasData(bool has_data) +{ + CALLED(); + _m_lock.Lock(); + _m_has_data = has_data ? 1 : 0; + _m_lock.Unlock(); +} + + +/************************************************************* + * protected BSoundPlayer + *************************************************************/ + +//final +void +BSoundPlayer::SetInitError(status_t in_error) +{ + CALLED(); + _m_init_err = in_error; +} + + +/************************************************************* + * private BSoundPlayer + *************************************************************/ + +status_t BSoundPlayer::_Reserved_SoundPlayer_0(void *, ...) { return B_ERROR; } +status_t BSoundPlayer::_Reserved_SoundPlayer_1(void *, ...) { return B_ERROR; } +status_t BSoundPlayer::_Reserved_SoundPlayer_2(void *, ...) { return B_ERROR; } +status_t BSoundPlayer::_Reserved_SoundPlayer_3(void *, ...) { return B_ERROR; } +status_t BSoundPlayer::_Reserved_SoundPlayer_4(void *, ...) { return B_ERROR; } +status_t BSoundPlayer::_Reserved_SoundPlayer_5(void *, ...) { return B_ERROR; } +status_t BSoundPlayer::_Reserved_SoundPlayer_6(void *, ...) { return B_ERROR; } +status_t BSoundPlayer::_Reserved_SoundPlayer_7(void *, ...) { return B_ERROR; } + + +void +BSoundPlayer::NotifySoundDone(play_id sound, + bool got_to_play) +{ + UNIMPLEMENTED(); +} + + +void +BSoundPlayer::get_volume_slider() +{ + UNIMPLEMENTED(); +} + +void +BSoundPlayer::Init( + const media_node * node, + const media_multi_audio_format * format, + const char * name, + const media_input * input, + void (*PlayBuffer)(void *, void * buffer, size_t size, const media_raw_audio_format & format), + void (*Notifier)(void *, sound_player_notification what, ...), + void * cookie) +{ + BROKEN(); + _m_node = NULL; + _m_sounds = NULL; + _m_waiting = NULL; + _PlayBuffer = PlayBuffer; + _Notifier = Notifier; + //_m_lock; + _m_volume = 0.0f; + //m_input; + //m_output; + _m_mix_buffer = 0; + _m_mix_buffer_size = 0; + _m_cookie = cookie; + _m_buf = NULL; + _m_bufsize = 0; + _m_has_data = 0; + _m_init_err = B_ERROR; + _m_perfTime = 0; + _m_volumeSlider = NULL; + _m_gotVolume = 0; + + _m_node = 0; + +#if 0 /* we don't have a media roster, or real media nodes yet */ + status_t status; + BMediaRoster *roster; + media_node outnode; + roster = BMediaRoster::Roster(); + if (!roster) { + TRACE("BSoundPlayer::Init: Couldn't get BMediaRoster\n"); + return; + } + + //connect our producer node either to the + //system mixer or to the supplied out node + if (!node) { + status = roster->GetAudioMixer(&outnode); + if (status != B_OK) { + TRACE("BSoundPlayer::Init: Couldn't GetAudioMixer\n"); + SetInitError(status); + return; + } + node = &outnode; + } +#endif + + media_multi_audio_format fmt; + memcpy(&fmt,format,sizeof(fmt)); + + if (fmt.frame_rate == media_multi_audio_format::wildcard.frame_rate) + fmt.frame_rate = 44100.0f; + if (fmt.channel_count == media_multi_audio_format::wildcard.channel_count) + fmt.channel_count = 2; + if (fmt.format == media_multi_audio_format::wildcard.format) + fmt.format = media_raw_audio_format::B_AUDIO_FLOAT; + if (fmt.byte_order == media_multi_audio_format::wildcard.byte_order) + fmt.byte_order = B_MEDIA_HOST_ENDIAN; + if (fmt.buffer_size == media_multi_audio_format::wildcard.buffer_size) + fmt.buffer_size = 4096; + + if (fmt.channel_count != 1 && fmt.channel_count != 2) + debugger("BSoundPlayer: not a 1 or 2 channel audio format\n"); + if (fmt.frame_rate <= 0.0f) + debugger("BSoundPlayer: framerate must be > 0\n"); + + _m_bufsize = fmt.buffer_size; + _m_buf = new char[_m_bufsize]; + _m_node = new _SoundPlayNode(name,&fmt,this); + + +/* + m_input = ; + m_output = ; + + +tryFormat = fileAudioOutput.format; +   err = roster->Connect(fileAudioOutput.source, audioInput.destination, +               &tryFormat, &m_output, &m_input); + + + err = roster->GetStartLatencyFor(timeSourceNode, &startTime); +   startTime += b_timesource->PerformanceTimeFor(BTimeSource::RealTime() +               + 1000000 / 50); +    +   err = roster->StartNode(mediaFileNode, startTime); +   err = roster->StartNode(codecNode, startTime); +   err = roster->StartNode(videoNode, startTime); + +*/ + + SetInitError(B_OK); +} + +/* virtual */ void +BSoundPlayer::Notify(sound_player_notification what, + ...) +{ + CALLED(); + _m_lock.Lock(); + if (_Notifier) + (*_Notifier)(_m_cookie,what); + else { + } + _m_lock.Unlock(); +} + + +/* virtual */ void +BSoundPlayer::PlayBuffer(void *buffer, + size_t size, + const media_raw_audio_format &format) +{ +// CALLED(); + _m_lock.Lock(); + if (_PlayBuffer) + (*_PlayBuffer)(_m_cookie,buffer,size,format); + else { + } + _m_lock.Unlock(); +} + + diff --git a/src/kits/media/SystemTimeSource.cpp b/src/kits/media/SystemTimeSource.cpp new file mode 100644 index 0000000000..30a515e8b6 --- /dev/null +++ b/src/kits/media/SystemTimeSource.cpp @@ -0,0 +1,44 @@ +/*********************************************************************** + * Copyright (c) 2002 Marcus Overhagen. All Rights Reserved. + * This file may be used under the terms of the OpenBeOS License. + * + * The realtime BTimeSource + ***********************************************************************/ + +// XXX This works only as long a BTimeSource is only supporting realtime + +#include +#include "SystemTimeSource.h" + +_SysTimeSource::_SysTimeSource() : + BMediaNode("time source") +{ +} + +/* virtual */ status_t +_SysTimeSource::SnoozeUntil( + bigtime_t performance_time, + bigtime_t with_latency, + bool retry_signals) +{ + bigtime_t time = performance_time - with_latency; + status_t err; + do { + err = snooze_until(time,B_SYSTEM_TIMEBASE); + } while (err == B_INTERRUPTED && retry_signals); + return err; +} + +/* virtual */ status_t +_SysTimeSource::TimeSourceOp( + const time_source_op_info & op, + void * _reserved) +{ + return B_OK; +} + +/* virtual */ BMediaAddOn* +_SysTimeSource::AddOn(int32 * internal_id) const +{ + return NULL; +} diff --git a/src/kits/media/SystemTimeSource.h b/src/kits/media/SystemTimeSource.h new file mode 100644 index 0000000000..6585f4fe46 --- /dev/null +++ b/src/kits/media/SystemTimeSource.h @@ -0,0 +1,31 @@ +/*********************************************************************** + * Copyright (c) 2002 Marcus Overhagen. All Rights Reserved. + * This file may be used under the terms of the OpenBeOS License. + * + * The realtime BTimeSource + ***********************************************************************/ +#ifndef _SYSTEM_TIME_SOURCE_H_ +#define _SYSTEM_TIME_SOURCE_H_ + +#include + +class _SysTimeSource : public BTimeSource +{ +public: + _SysTimeSource(); + + virtual status_t SnoozeUntil( + bigtime_t performance_time, + bigtime_t with_latency = 0, + bool retry_signals = false); +protected: + virtual status_t TimeSourceOp( + const time_source_op_info & op, + void * _reserved); + +virtual BMediaAddOn* AddOn( + int32 * internal_id) const; + +}; + +#endif diff --git a/src/kits/media/TimeCode.cpp b/src/kits/media/TimeCode.cpp new file mode 100644 index 0000000000..7c6a779d16 --- /dev/null +++ b/src/kits/media/TimeCode.cpp @@ -0,0 +1,270 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: TimeCode.cpp + * DESCR: + ***********************************************************************/ +#include +#include "debug.h" + +status_t us_to_timecode(bigtime_t micros, int * hours, int * minutes, int * seconds, int * frames, const timecode_info * code = NULL) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + +status_t timecode_to_us(int hours, int minutes, int seconds, int frames, bigtime_t * micros, const timecode_info * code = NULL) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + +status_t frames_to_timecode(int32 l_frames, int * hours, int * minutes, int * seconds, int * frames, const timecode_info * code = NULL) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + +status_t timecode_to_frames(int hours, int minutes, int seconds, int frames, int32 * l_frames, const timecode_info * code = NULL) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + +status_t get_timecode_description(timecode_type type, timecode_info * out_timecode) +{ + UNIMPLEMENTED(); + return B_ERROR; +} + +status_t count_timecodes() +{ + UNIMPLEMENTED(); + return B_ERROR; +} + +/************************************************************* + * public BTimeCode + *************************************************************/ + + +BTimeCode::BTimeCode() +{ + UNIMPLEMENTED(); +} + + +BTimeCode::BTimeCode(bigtime_t us, + timecode_type type) +{ + UNIMPLEMENTED(); +} + + +BTimeCode::BTimeCode(const BTimeCode &clone) +{ + UNIMPLEMENTED(); +} + + +BTimeCode::BTimeCode(int hours, + int minutes, + int seconds, + int frames, + timecode_type type) +{ + UNIMPLEMENTED(); +} + + +BTimeCode::~BTimeCode() +{ + UNIMPLEMENTED(); +} + + +void +BTimeCode::SetData(int hours, + int minutes, + int seconds, + int frames) +{ + UNIMPLEMENTED(); +} + + +status_t +BTimeCode::SetType(timecode_type type) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +void +BTimeCode::SetMicroseconds(bigtime_t us) +{ + UNIMPLEMENTED(); +} + + +void +BTimeCode::SetLinearFrames(int32 linear_frames) +{ + UNIMPLEMENTED(); +} + + +BTimeCode & +BTimeCode::operator=(const BTimeCode &clone) +{ + UNIMPLEMENTED(); + return *this; +} + + +bool +BTimeCode::operator==(const BTimeCode &other) const +{ + UNIMPLEMENTED(); + bool dummy; + + return dummy; +} + + +bool +BTimeCode::operator<(const BTimeCode &other) const +{ + UNIMPLEMENTED(); + bool dummy; + + return dummy; +} + + +BTimeCode & +BTimeCode::operator+=(const BTimeCode &other) +{ + UNIMPLEMENTED(); + return *this; +} + + +BTimeCode & +BTimeCode::operator-=(const BTimeCode &other) +{ + UNIMPLEMENTED(); + return *this; +} + + +BTimeCode +BTimeCode::operator+(const BTimeCode &other) const +{ + UNIMPLEMENTED(); + BTimeCode tc(*this); + tc += other; + return tc; +} + + +BTimeCode +BTimeCode::operator-(const BTimeCode &other) const +{ + UNIMPLEMENTED(); + BTimeCode tc(*this); + tc -= other; + return tc; +} + + +int +BTimeCode::Hours() const +{ + UNIMPLEMENTED(); + int dummy; + + return dummy; +} + + +int +BTimeCode::Minutes() const +{ + UNIMPLEMENTED(); + int dummy; + + return dummy; +} + + +int +BTimeCode::Seconds() const +{ + UNIMPLEMENTED(); + int dummy; + + return dummy; +} + + +int +BTimeCode::Frames() const +{ + UNIMPLEMENTED(); + int dummy; + + return dummy; +} + + +timecode_type +BTimeCode::Type() const +{ + UNIMPLEMENTED(); + timecode_type dummy; + + return dummy; +} + + +void +BTimeCode::GetData(int *out_hours, + int *out_minutes, + int *out_seconds, + int *out_frames, + timecode_type *out_type) const +{ + UNIMPLEMENTED(); +} + + +bigtime_t +BTimeCode::Microseconds() const +{ + UNIMPLEMENTED(); + bigtime_t dummy; + + return dummy; +} + + +int32 +BTimeCode::LinearFrames() const +{ + UNIMPLEMENTED(); + int32 dummy; + + return dummy; +} + + +void +BTimeCode::GetString(char *str) const +{ + UNIMPLEMENTED(); +} + + diff --git a/src/kits/media/TimeSource.cpp b/src/kits/media/TimeSource.cpp new file mode 100644 index 0000000000..e096e25a48 --- /dev/null +++ b/src/kits/media/TimeSource.cpp @@ -0,0 +1,256 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: TimeSource.cpp + * DESCR: + ***********************************************************************/ +#include +#include "debug.h" +#include "../server/headers/ServerInterface.h" + +// XXX This BTimeSource only works for realtime, nothing else is implemented + +// XXX The bebook says that the latency is always calculated in realtime +// XXX This is not currently done in this code + +/************************************************************* + * protected BTimeSource + *************************************************************/ + +BTimeSource::~BTimeSource() +{ + CALLED(); +} + +/************************************************************* + * public BTimeSource + *************************************************************/ + +status_t +BTimeSource::SnoozeUntil(bigtime_t performance_time, + bigtime_t with_latency, + bool retry_signals) +{ + CALLED(); + + return B_ERROR; +} + + +bigtime_t +BTimeSource::Now() +{ + CALLED(); + return PerformanceTimeFor(RealTime()); +} + + +bigtime_t +BTimeSource::PerformanceTimeFor(bigtime_t real_time) +{ + CALLED(); + bigtime_t performanceTime; + float drift; + + while (GetTime(&performanceTime, &real_time, &drift) != B_OK) + snooze(1000); + + return (bigtime_t)(performanceTime + (RealTime() - real_time) * drift); +} + + +bigtime_t +BTimeSource::RealTimeFor(bigtime_t performance_time, + bigtime_t with_latency) +{ + CALLED(); + + return performance_time - with_latency; +} + + +bool +BTimeSource::IsRunning() +{ + CALLED(); + return !fStopped; +} + + +status_t +BTimeSource::GetTime(bigtime_t *performance_time, + bigtime_t *real_time, + float *drift) +{ + CALLED(); + *performance_time = *real_time; + *drift = 1.0f; + + return B_OK; +} + + +bigtime_t +BTimeSource::RealTime() +{ + CALLED(); + return system_time(); +} + + +status_t +BTimeSource::GetStartLatency(bigtime_t *out_latency) +{ + CALLED(); + *out_latency = 0; + return B_OK; +} + +/************************************************************* + * protected BTimeSource + *************************************************************/ + + +BTimeSource::BTimeSource() : + BMediaNode("called by BTimeSource"), + fStopped(false) +{ + CALLED(); + + AddNodeKind(B_TIME_SOURCE); +} + + +status_t +BTimeSource::HandleMessage(int32 message, + const void *rawdata, + size_t size) +{ + CALLED(); + switch (message) { + case TIMESOURCE_OP: + { + const time_source_op_info *data = (const time_source_op_info *)rawdata; + status_t result; + result = TimeSourceOp(*data, NULL); + return B_OK; + } + }; + return B_ERROR; +} + + +void +BTimeSource::PublishTime(bigtime_t performance_time, + bigtime_t real_time, + float drift) +{ + UNIMPLEMENTED(); +} + + +void +BTimeSource::BroadcastTimeWarp(bigtime_t at_real_time, + bigtime_t new_performance_time) +{ + UNIMPLEMENTED(); +} + + +void +BTimeSource::SendRunMode(run_mode mode) +{ + UNIMPLEMENTED(); +} + + +void +BTimeSource::SetRunMode(run_mode mode) +{ + CALLED(); + BMediaNode::SetRunMode(mode); +} +/************************************************************* + * private BTimeSource + *************************************************************/ + +/* +//unimplemented +BTimeSource::BTimeSource(const BTimeSource &clone) +BTimeSource &BTimeSource::operator=(const BTimeSource &clone) +*/ + +status_t BTimeSource::_Reserved_TimeSource_0(void *) { return B_ERROR; } +status_t BTimeSource::_Reserved_TimeSource_1(void *) { return B_ERROR; } +status_t BTimeSource::_Reserved_TimeSource_2(void *) { return B_ERROR; } +status_t BTimeSource::_Reserved_TimeSource_3(void *) { return B_ERROR; } +status_t BTimeSource::_Reserved_TimeSource_4(void *) { return B_ERROR; } +status_t BTimeSource::_Reserved_TimeSource_5(void *) { return B_ERROR; } + +/* explicit */ +BTimeSource::BTimeSource(media_node_id id) : + BMediaNode("called by BTimeSource", id, 0), + fStopped(false) +{ + CALLED(); + + AddNodeKind(B_TIME_SOURCE); +} + + +void +BTimeSource::FinishCreate() +{ + UNIMPLEMENTED(); +} + + +status_t +BTimeSource::RemoveMe(BMediaNode *node) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +status_t +BTimeSource::AddMe(BMediaNode *node) +{ + UNIMPLEMENTED(); + status_t dummy; + + return dummy; +} + + +void +BTimeSource::DirectStart(bigtime_t at) +{ + UNIMPLEMENTED(); +} + + +void +BTimeSource::DirectStop(bigtime_t at, + bool immediate) +{ + UNIMPLEMENTED(); +} + + +void +BTimeSource::DirectSeek(bigtime_t to, + bigtime_t at) +{ + UNIMPLEMENTED(); +} + + +void +BTimeSource::DirectSetRunMode(run_mode mode) +{ + UNIMPLEMENTED(); +} + + diff --git a/src/kits/media/TimedEventQueue.cpp b/src/kits/media/TimedEventQueue.cpp new file mode 100644 index 0000000000..2711f9dfea --- /dev/null +++ b/src/kits/media/TimedEventQueue.cpp @@ -0,0 +1,301 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: TimedEventQueue.cpp + * DESCR: used by BMediaEventLooper + ***********************************************************************/ + +#define NDEBUG +#include +#include +#include "TimedEventQueuePrivate.h" +#include "debug.h" + +/************************************************************* + * struct media_timed_event + *************************************************************/ + +media_timed_event::media_timed_event() +{ + CALLED(); + memset(this, 0, sizeof(*this)); +} + + +media_timed_event::media_timed_event(bigtime_t inTime, + int32 inType) +{ + CALLED(); + memset(this, 0, sizeof(*this)); + event_time = inTime; + type = inType; +} + + +media_timed_event::media_timed_event(bigtime_t inTime, + int32 inType, + void *inPointer, + uint32 inCleanup) +{ + CALLED(); + memset(this, 0, sizeof(*this)); + event_time = inTime; + type = inType; + pointer = inPointer; + cleanup = inCleanup; +} + + +media_timed_event::media_timed_event(bigtime_t inTime, + int32 inType, + void *inPointer, + uint32 inCleanup, + int32 inData, + int64 inBigdata, + char *inUserData, + size_t dataSize) +{ + CALLED(); + memset(this, 0, sizeof(*this)); + event_time = inTime; + type = inType; + pointer = inPointer; + cleanup = inCleanup; + data = inData; + bigdata = inBigdata; + memcpy(user_data,inUserData,min_c(sizeof(media_timed_event::user_data),dataSize)); +} + + +media_timed_event::media_timed_event(const media_timed_event &clone) +{ + CALLED(); + *this = clone; +} + + +void +media_timed_event::operator=(const media_timed_event &clone) +{ + CALLED(); + memcpy(this, &clone, sizeof(*this)); +} + + +media_timed_event::~media_timed_event() +{ + CALLED(); +} + +/************************************************************* + * global operators + *************************************************************/ + +bool operator==(const media_timed_event & a, const media_timed_event & b) +{ + CALLED(); + return (0 == memcmp(&a,&b,sizeof(media_timed_event))); +} + +bool operator!=(const media_timed_event & a, const media_timed_event & b) +{ + CALLED(); + return (0 != memcmp(&a,&b,sizeof(media_timed_event))); +} + +bool operator<(const media_timed_event & a, const media_timed_event & b) +{ + CALLED(); + return a.event_time < b.event_time; +} + +bool operator>(const media_timed_event & a, const media_timed_event &b) +{ + CALLED(); + return a.event_time > b.event_time; +} + + +/************************************************************* + * public BTimedEventQueue + *************************************************************/ + + +void * +BTimedEventQueue::operator new(size_t s) +{ + CALLED(); + return ::operator new(s); +} + + +void +BTimedEventQueue::operator delete(void *p, size_t s) +{ + CALLED(); + return ::operator delete(p); +} + + +BTimedEventQueue::BTimedEventQueue() : + fImp(new _event_queue_imp) +{ + CALLED(); +} + + +BTimedEventQueue::~BTimedEventQueue() +{ + CALLED(); + delete fImp; +} + + +status_t +BTimedEventQueue::AddEvent(const media_timed_event &event) +{ + CALLED(); + return fImp->AddEvent(event); +} + + +status_t +BTimedEventQueue::RemoveEvent(const media_timed_event *event) +{ + CALLED(); + return fImp->RemoveEvent(event); +} + + +status_t +BTimedEventQueue::RemoveFirstEvent(media_timed_event *outEvent) +{ + CALLED(); + return fImp->RemoveFirstEvent(outEvent); +} + + +bool +BTimedEventQueue::HasEvents() const +{ + CALLED(); + return fImp->HasEvents(); +} + + +int32 +BTimedEventQueue::EventCount() const +{ + CALLED(); + return fImp->EventCount(); +} + + +const media_timed_event * +BTimedEventQueue::FirstEvent() const +{ + CALLED(); + return fImp->FirstEvent(); +} + + +bigtime_t +BTimedEventQueue::FirstEventTime() const +{ + CALLED(); + return fImp->FirstEventTime(); +} + + +const media_timed_event * +BTimedEventQueue::LastEvent() const +{ + CALLED(); + return fImp->LastEvent(); +} + + +bigtime_t +BTimedEventQueue::LastEventTime() const +{ + CALLED(); + return fImp->LastEventTime(); +} + + +const media_timed_event * +BTimedEventQueue::FindFirstMatch(bigtime_t eventTime, + time_direction direction, + bool inclusive, + int32 eventType) +{ + CALLED(); + return fImp->FindFirstMatch(eventTime, direction, inclusive, eventType); +} + + +status_t +BTimedEventQueue::DoForEach(for_each_hook hook, + void *context, + bigtime_t eventTime, + time_direction direction, + bool inclusive, + int32 eventType) +{ + CALLED(); + return fImp->DoForEach(hook, context, eventTime, direction, inclusive, eventType); +} + + +void +BTimedEventQueue::SetCleanupHook(cleanup_hook hook, + void *context) +{ + CALLED(); + fImp->SetCleanupHook(hook, context); +} + + +status_t +BTimedEventQueue::FlushEvents(bigtime_t eventTime, + time_direction direction, + bool inclusive, + int32 eventType) +{ + CALLED(); + return fImp->FlushEvents(eventTime, direction, inclusive, eventType); +} + +/************************************************************* + * private BTimedEventQueue + *************************************************************/ + +/* +// unimplemented +BTimedEventQueue::BTimedEventQueue(const BTimedEventQueue &other) +BTimedEventQueue &BTimedEventQueue::operator=(const BTimedEventQueue &other) +*/ + +status_t BTimedEventQueue::_Reserved_BTimedEventQueue_0(void *, ...) { return B_ERROR; } +status_t BTimedEventQueue::_Reserved_BTimedEventQueue_1(void *, ...) { return B_ERROR; } +status_t BTimedEventQueue::_Reserved_BTimedEventQueue_2(void *, ...) { return B_ERROR; } +status_t BTimedEventQueue::_Reserved_BTimedEventQueue_3(void *, ...) { return B_ERROR; } +status_t BTimedEventQueue::_Reserved_BTimedEventQueue_4(void *, ...) { return B_ERROR; } +status_t BTimedEventQueue::_Reserved_BTimedEventQueue_5(void *, ...) { return B_ERROR; } +status_t BTimedEventQueue::_Reserved_BTimedEventQueue_6(void *, ...) { return B_ERROR; } +status_t BTimedEventQueue::_Reserved_BTimedEventQueue_7(void *, ...) { return B_ERROR; } +status_t BTimedEventQueue::_Reserved_BTimedEventQueue_8(void *, ...) { return B_ERROR; } +status_t BTimedEventQueue::_Reserved_BTimedEventQueue_9(void *, ...) { return B_ERROR; } +status_t BTimedEventQueue::_Reserved_BTimedEventQueue_10(void *, ...) { return B_ERROR; } +status_t BTimedEventQueue::_Reserved_BTimedEventQueue_11(void *, ...) { return B_ERROR; } +status_t BTimedEventQueue::_Reserved_BTimedEventQueue_12(void *, ...) { return B_ERROR; } +status_t BTimedEventQueue::_Reserved_BTimedEventQueue_13(void *, ...) { return B_ERROR; } +status_t BTimedEventQueue::_Reserved_BTimedEventQueue_14(void *, ...) { return B_ERROR; } +status_t BTimedEventQueue::_Reserved_BTimedEventQueue_15(void *, ...) { return B_ERROR; } +status_t BTimedEventQueue::_Reserved_BTimedEventQueue_16(void *, ...) { return B_ERROR; } +status_t BTimedEventQueue::_Reserved_BTimedEventQueue_17(void *, ...) { return B_ERROR; } +status_t BTimedEventQueue::_Reserved_BTimedEventQueue_18(void *, ...) { return B_ERROR; } +status_t BTimedEventQueue::_Reserved_BTimedEventQueue_19(void *, ...) { return B_ERROR; } +status_t BTimedEventQueue::_Reserved_BTimedEventQueue_20(void *, ...) { return B_ERROR; } +status_t BTimedEventQueue::_Reserved_BTimedEventQueue_21(void *, ...) { return B_ERROR; } +status_t BTimedEventQueue::_Reserved_BTimedEventQueue_22(void *, ...) { return B_ERROR; } +status_t BTimedEventQueue::_Reserved_BTimedEventQueue_23(void *, ...) { return B_ERROR; } diff --git a/src/kits/media/TimedEventQueuePrivate.cpp b/src/kits/media/TimedEventQueuePrivate.cpp new file mode 100644 index 0000000000..5419c4f684 --- /dev/null +++ b/src/kits/media/TimedEventQueuePrivate.cpp @@ -0,0 +1,595 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: TimedEventQueuePrivate.cpp + * DESCR: implements _event_queue_imp used by BTimedEventQueue, + * not thread save! + ***********************************************************************/ + +#undef DEBUG +#define DEBUG 1 +#include +#include +#include +#include //defines B_DELETE +#include "TimedEventQueuePrivate.h" +#include "Debug.h" +#include "debug.h" + +_event_queue_imp::_event_queue_imp() : + fLock("BTimedEventQueue locker"), + fEventCount(0), + fFirstEntry(NULL), + fLastEntry(NULL), + fCleanupHookContext(NULL), + fCleanupHook(0) +{ +} + + +_event_queue_imp::~_event_queue_imp() +{ + event_queue_entry *entry; + entry = fFirstEntry; + while (entry) { + event_queue_entry *deleteme; + deleteme = entry; + entry = entry->next; + delete deleteme; + } +} + + +status_t +_event_queue_imp::AddEvent(const media_timed_event &event) +{ + BAutolock lock(fLock); + + if (event.type <= 0) { + return B_BAD_VALUE; + } + + //create a new queue + if (fFirstEntry == NULL) { + ASSERT(fEventCount == 0); + ASSERT(fLastEntry == NULL); + fFirstEntry = fLastEntry = new event_queue_entry; + memcpy(&fFirstEntry->event,&event,sizeof(media_timed_event)); + fFirstEntry->prev = NULL; + fFirstEntry->next = NULL; + fEventCount++; + return B_OK; + } + + //insert at queue begin + if (fFirstEntry->event.event_time >= event.event_time) { + event_queue_entry *newentry = new event_queue_entry; + memcpy(&newentry->event,&event,sizeof(media_timed_event)); + newentry->prev = NULL; + newentry->next = fFirstEntry; + fFirstEntry->prev = newentry; + fFirstEntry = newentry; + fEventCount++; + return B_OK; + } + + //insert at queue end + if (fLastEntry->event.event_time <= event.event_time) { + event_queue_entry *newentry = new event_queue_entry; + memcpy(&newentry->event,&event,sizeof(media_timed_event)); + newentry->prev = fLastEntry; + newentry->next = NULL; + fLastEntry->next = newentry; + fLastEntry = newentry; + fEventCount++; + return B_OK; + } + + //insert into the queue + for (event_queue_entry *entry = fLastEntry; entry; entry = entry->prev) { + if (entry->event.event_time <= event.event_time) { + //insert after entry + event_queue_entry *newentry = new event_queue_entry; + memcpy(&newentry->event,&event,sizeof(media_timed_event)); + newentry->prev = entry; + newentry->next = entry->next; + (entry->next)->prev = newentry; + entry->next = newentry; + fEventCount++; + return B_OK; + } + } + + debugger("_event_queue_imp::AddEvent failed, should not be here\n"); + return B_OK; +} + + +status_t +_event_queue_imp::RemoveEvent(const media_timed_event *event) +{ + BAutolock lock(fLock); + + for (event_queue_entry *entry = fFirstEntry; entry; entry = entry->next) { + if (entry->event == *event) { + // No cleanup here + RemoveEntry(entry); + return B_OK; + } + } + + return B_ERROR; +} + + +status_t +_event_queue_imp::RemoveFirstEvent(media_timed_event * outEvent) +{ + BAutolock lock(fLock); + + if (fFirstEntry == 0) + return B_ERROR; + + if (outEvent != 0) + *outEvent = fFirstEntry->event; + else + CleanupEvent(&fFirstEntry->event); + + RemoveEntry(fFirstEntry); + + return B_OK; +} + + +bool +_event_queue_imp::HasEvents() const +{ + return fEventCount != 0; +} + + +int32 +_event_queue_imp::EventCount() const +{ + #if DEBUG > 1 + Dump(); + #endif + return fEventCount; +} + + +const media_timed_event * +_event_queue_imp::FirstEvent() const +{ + return fFirstEntry ? &fFirstEntry->event : NULL; +} + + +bigtime_t +_event_queue_imp::FirstEventTime() const +{ + return fFirstEntry ? fFirstEntry->event.event_time : B_INFINITE_TIMEOUT; +} + + +const media_timed_event * +_event_queue_imp::LastEvent() const +{ + return fLastEntry ? &fLastEntry->event : NULL; +} + + +bigtime_t +_event_queue_imp::LastEventTime() const +{ + return fLastEntry ? fLastEntry->event.event_time : B_INFINITE_TIMEOUT; +} + + +const media_timed_event * +_event_queue_imp::FindFirstMatch(bigtime_t eventTime, + BTimedEventQueue::time_direction direction, + bool inclusive, + int32 eventType) +{ + event_queue_entry *end; + event_queue_entry *entry; + + BAutolock lock(fLock); + + switch (direction) { + case BTimedEventQueue::B_ALWAYS: + for (entry = fFirstEntry; entry; entry = entry->next) { + if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) + return &entry->event; + } + return NULL; + + case BTimedEventQueue::B_BEFORE_TIME: + end = GetEnd_BeforeTime(eventTime, inclusive); + if (end == NULL) + return NULL; + end = end->next; + for (entry = fFirstEntry; entry != end; entry = entry->next) { + if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) { + return &entry->event; + } + } + return NULL; + + case BTimedEventQueue::B_AT_TIME: + { + bool found_time = false; + for (entry = fFirstEntry; entry; entry = entry->next) { + if (eventTime == entry->event.event_time) { + found_time = true; + if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) + return &entry->event; + } else if (found_time) + return NULL; + } + return NULL; + } + + case BTimedEventQueue::B_AFTER_TIME: + for (entry = GetStart_AfterTime(eventTime, inclusive); entry; entry = entry->next) { + if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) { + return &entry->event; + } + } + return NULL; + } + + return NULL; +} + + +status_t +_event_queue_imp::DoForEach(BTimedEventQueue::for_each_hook hook, + void *context, + bigtime_t eventTime, + BTimedEventQueue::time_direction direction, + bool inclusive, + int32 eventType) +{ + event_queue_entry *end; + event_queue_entry *entry; + event_queue_entry *remove; + BTimedEventQueue::queue_action action; + + BAutolock lock(fLock); + + switch (direction) { + case BTimedEventQueue::B_ALWAYS: + for (entry = fFirstEntry; entry; ) { + if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) { + action = (*hook)(&entry->event, context); + switch (action) { + case BTimedEventQueue::B_DONE: + return B_OK; + case BTimedEventQueue::B_REMOVE_EVENT: + CleanupEvent(&entry->event); + remove = entry; + entry = entry->next; + RemoveEntry(remove); + break; + case BTimedEventQueue::B_NO_ACTION: + case BTimedEventQueue::B_RESORT_QUEUE: + default: + entry = entry->next; + break; + } + } else { + entry = entry->next; + } + } + return B_OK; + + case BTimedEventQueue::B_BEFORE_TIME: + end = GetEnd_BeforeTime(eventTime, inclusive); + if (end == NULL) + return B_OK; + end = end->next; + for (entry = fFirstEntry; entry != end; ) { + if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) { + action = (*hook)(&entry->event, context); + switch (action) { + case BTimedEventQueue::B_DONE: + return B_OK; + case BTimedEventQueue::B_REMOVE_EVENT: + CleanupEvent(&entry->event); + remove = entry; + entry = entry->next; + RemoveEntry(remove); + break; + case BTimedEventQueue::B_NO_ACTION: + case BTimedEventQueue::B_RESORT_QUEUE: + default: + entry = entry->next; + break; + } + } else { + entry = entry->next; + } + } + return B_OK; + + case BTimedEventQueue::B_AT_TIME: + { + bool found_time = false; + for (entry = fFirstEntry; entry; ) { + if (eventTime == entry->event.event_time) { + found_time = true; + if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) { + action = (*hook)(&entry->event, context); + switch (action) { + case BTimedEventQueue::B_DONE: + return B_OK; + case BTimedEventQueue::B_REMOVE_EVENT: + CleanupEvent(&entry->event); + remove = entry; + entry = entry->next; + RemoveEntry(remove); + break; + case BTimedEventQueue::B_NO_ACTION: + case BTimedEventQueue::B_RESORT_QUEUE: + default: + entry = entry->next; + break; + } + } else { + entry = entry->next; + } + } else if (found_time) { + break; + } else { + entry = entry->next; + } + } + return B_OK; + } + + case BTimedEventQueue::B_AFTER_TIME: + for (entry = GetStart_AfterTime(eventTime, inclusive); entry; ) { + if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) { + action = (*hook)(&entry->event, context); + switch (action) { + case BTimedEventQueue::B_DONE: + return B_OK; + case BTimedEventQueue::B_REMOVE_EVENT: + CleanupEvent(&entry->event); + remove = entry; + entry = entry->next; + RemoveEntry(remove); + break; + case BTimedEventQueue::B_NO_ACTION: + case BTimedEventQueue::B_RESORT_QUEUE: + default: + entry = entry->next; + break; + } + } else { + entry = entry->next; + } + } + return B_OK; + } + + return B_ERROR; +} + + +status_t +_event_queue_imp::FlushEvents(bigtime_t eventTime, + BTimedEventQueue::time_direction direction, + bool inclusive, + int32 eventType) +{ + event_queue_entry *end; + event_queue_entry *entry; + event_queue_entry *remove; + + BAutolock lock(fLock); + + switch (direction) { + case BTimedEventQueue::B_ALWAYS: + for (entry = fFirstEntry; entry; ) { + if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) { + CleanupEvent(&entry->event); + remove = entry; + entry = entry->next; + RemoveEntry(remove); + } else { + entry = entry->next; + } + } + return B_OK; + + case BTimedEventQueue::B_BEFORE_TIME: + end = GetEnd_BeforeTime(eventTime, inclusive); + if (end == NULL) + return B_OK; + end = end->next; + for (entry = fFirstEntry; entry != end; ) { + if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) { + CleanupEvent(&entry->event); + remove = entry; + entry = entry->next; + RemoveEntry(remove); + } else { + entry = entry->next; + } + } + return B_OK; + + case BTimedEventQueue::B_AT_TIME: + { + bool found_time = false; + for (entry = fFirstEntry; entry; ) { + if (eventTime == entry->event.event_time) { + found_time = true; + if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) { + CleanupEvent(&entry->event); + remove = entry; + entry = entry->next; + RemoveEntry(remove); + } else { + entry = entry->next; + } + } else if (found_time) { + break; + } else { + entry = entry->next; + } + } + return B_OK; + } + + case BTimedEventQueue::B_AFTER_TIME: + for (entry = GetStart_AfterTime(eventTime, inclusive); entry; ) { + if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) { + CleanupEvent(&entry->event); + remove = entry; + entry = entry->next; + RemoveEntry(remove); + } else { + entry = entry->next; + } + } + return B_OK; + } + + return B_ERROR; +} + + +void +_event_queue_imp::SetCleanupHook(BTimedEventQueue::cleanup_hook hook, void *context) +{ + BAutolock lock(fLock); + fCleanupHookContext = context; + fCleanupHook = hook; +} + + +void +_event_queue_imp::RemoveEntry(event_queue_entry *entry) +{ + //remove the entry from double-linked list + //and delete it + if (entry->prev != NULL) + (entry->prev)->next = entry->next; + if (entry->next != NULL) + (entry->next)->prev = entry->prev; + if (entry == fFirstEntry) { + fFirstEntry = entry->next; + if (fFirstEntry != NULL) + fFirstEntry->prev = NULL; + } + if (entry == fLastEntry) { + fLastEntry = entry->prev; + if (fLastEntry != NULL) + fLastEntry->next = NULL; + } + delete entry; + fEventCount--; + ASSERT(fEventCount >= 0); + ASSERT(fEventCount != 0 || ((fFirstEntry == NULL) && (fLastEntry == NULL))); +} + + +void +_event_queue_imp::CleanupEvent(media_timed_event *event) +{ + //perform the cleanup action required + //when deleting an event from the queue + + //BeBook says: + // Each event has a cleanup flag associated with it that indicates + // what sort of special action needs to be performed when the event is + // removed from the queue. If this value is B_NO_CLEANUP, nothing is done. + // If it's B_RECYCLE, and the event is a B_HANDLE_BUFFER event, BTimedEventQueue + // will automatically recycle the buffer associated with the event. + // If the cleanup flag is B_DELETE or is B_USER_CLEANUP or greater, + // the cleanup hook function will be called. + //and: + // cleanup hook function specified by hook to be called for events + // as they're removed from the queue. The hook will be called only + // for events with cleanup_flag values of B_DELETE or B_USER_CLEANUP or greater. + //and: + // These values define how BTimedEventQueue should handle removing + // events from the queue. If the flag is B_USER_CLEANUP or greater, + // the cleanup hook function is called when the event is removed. + //Problems: + // B_DELETE is a keyboard code! (seems to have existed in early + // sample code as a cleanup flag) + // + // exiting cleanup flags are: + // B_NO_CLEANUP = 0, + // B_RECYCLE_BUFFER, // recycle buffers handled by BTimedEventQueue + // B_EXPIRE_TIMER, // call TimerExpired() on the event->data + // B_USER_CLEANUP = 0x4000 // others go to the cleanup func + // + + if (event->cleanup == BTimedEventQueue::B_NO_CLEANUP) { + // do nothing + } else if (event->type == BTimedEventQueue::B_HANDLE_BUFFER && event->cleanup == BTimedEventQueue::B_RECYCLE_BUFFER) { + ((BBuffer *)event->pointer)->Recycle(); + } else if (event->cleanup == BTimedEventQueue::B_EXPIRE_TIMER) { + // call TimerExpired() on the event->data + debugger("BTimedEventQueue cleanup: calling TimerExpired() should be implemented here\n"); + } else if (event->cleanup == B_DELETE || event->cleanup >= BTimedEventQueue::B_USER_CLEANUP) { + if (fCleanupHook) + (*fCleanupHook)(event,fCleanupHookContext); + } else { + TRACE("BTimedEventQueue cleanup unhandled! type = %ld, cleanup = %ld\n", event->type, event->cleanup); + } +} + + +_event_queue_imp::event_queue_entry * +_event_queue_imp::GetEnd_BeforeTime(bigtime_t eventTime, bool inclusive) +{ + event_queue_entry *entry; + + entry = fLastEntry; + while (entry) { + if ((entry->event.event_time > eventTime) || (!inclusive && entry->event.event_time == eventTime)) + entry = entry->prev; + else + break; + } + return entry; +} + + +_event_queue_imp::event_queue_entry * +_event_queue_imp::GetStart_AfterTime(bigtime_t eventTime, bool inclusive) +{ + event_queue_entry *entry; + + entry = fFirstEntry; + while (entry) { + if ((entry->event.event_time < eventTime) || (!inclusive && entry->event.event_time == eventTime)) + entry = entry->next; + else + break; + } + return entry; +} + + +#if DEBUG > 1 +void +_event_queue_imp::Dump() const +{ + TRACE("fEventCount = 0x%x\n",(int)fEventCount); + TRACE("fFirstEntry = 0x%x\n",(int)fFirstEntry); + TRACE("fLastEntry = 0x%x\n",(int)fLastEntry); + for (event_queue_entry *entry = fFirstEntry; entry; entry = entry->next) { + TRACE("entry = 0x%x\n",(int)entry); + TRACE(" entry.prev = 0x%x\n",(int)entry->prev); + TRACE(" entry.next = 0x%x\n",(int)entry->next); + TRACE(" entry.event.event_time = 0x%x\n",(int)entry->event.event_time); + } +} +#endif diff --git a/src/kits/media/TimedEventQueuePrivate.h b/src/kits/media/TimedEventQueuePrivate.h new file mode 100644 index 0000000000..add3084e5c --- /dev/null +++ b/src/kits/media/TimedEventQueuePrivate.h @@ -0,0 +1,78 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: TimedEventQueuePrivate.cpp + * DESCR: implements _event_queue_imp used by BTimedEventQueue, + * not thread save! + ***********************************************************************/ + +#ifndef _TIMED_EVENT_QUEUE_PRIVATE_H +#define _TIMED_EVENT_QUEUE_PRIVATE_H + +#include +#include + +struct _event_queue_imp +{ + _event_queue_imp(); + ~_event_queue_imp(); + + status_t AddEvent(const media_timed_event &event); + status_t RemoveEvent(const media_timed_event *event); + status_t RemoveFirstEvent(media_timed_event * outEvent); + + bool HasEvents() const; + int32 EventCount() const; + + const media_timed_event * FirstEvent() const; + bigtime_t FirstEventTime() const; + const media_timed_event * LastEvent() const; + bigtime_t LastEventTime() const; + + const media_timed_event * FindFirstMatch( + bigtime_t eventTime, + BTimedEventQueue::time_direction direction, + bool inclusive, + int32 eventType); + + status_t DoForEach( + BTimedEventQueue::for_each_hook hook, + void *context, + bigtime_t eventTime, + BTimedEventQueue::time_direction direction, + bool inclusive, + int32 eventType); + + void SetCleanupHook(BTimedEventQueue::cleanup_hook hook, void *context); + status_t FlushEvents( + bigtime_t eventTime, + BTimedEventQueue::time_direction direction, + bool inclusive, + int32 eventType); + +#if DEBUG > 1 + void Dump() const; +#endif + +private: + struct event_queue_entry + { + struct event_queue_entry *prev; + struct event_queue_entry *next; + media_timed_event event; + }; + + void RemoveEntry(event_queue_entry *entry); + void CleanupEvent(media_timed_event *event); + + event_queue_entry *GetEnd_BeforeTime(bigtime_t eventTime, bool inclusive); + event_queue_entry *GetStart_AfterTime(bigtime_t eventTime, bool inclusive); + + BLocker fLock; + int32 fEventCount; + event_queue_entry *fFirstEntry; + event_queue_entry *fLastEntry; + void * fCleanupHookContext; + BTimedEventQueue::cleanup_hook fCleanupHook; +}; + +#endif //_TIMED_EVENT_QUEUE_PRIVATE_H diff --git a/src/kits/media/TrackReader.cpp b/src/kits/media/TrackReader.cpp new file mode 100644 index 0000000000..4bdf7d1b8c --- /dev/null +++ b/src/kits/media/TrackReader.cpp @@ -0,0 +1,224 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: TrackReader.cpp + * DESCR: The undocumented BTrackReader class, + * used by BSound and the GameSound classes + ***********************************************************************/ + +#include +#include +#include +#include +#include "TrackReader.h" +#include "debug.h" + +namespace BPrivate +{ + +BTrackReader::BTrackReader(BMediaTrack *track, media_raw_audio_format const &format) : + fFrameSize(0), + fBuffer(0), + fBufferOffset(0), + fBufferUsedSize(0), + fMediaFile(0), + fMediaTrack(0), + fFormat(format) +{ + CALLED(); + if (track == NULL) + return; + if (track->InitCheck() != B_OK) + return; + + SetToTrack(track); + + // if the track was not set abort now + if (fMediaTrack == 0) + return; + + fBuffer = new uint8[fFormat.buffer_size]; + fFrameSize = fFormat.channel_count * (fFormat.format & media_raw_audio_format::B_AUDIO_SIZE_MASK); + + TRACE("BTrackReader::BTrackReader successful\n"); +} + +BTrackReader::BTrackReader(BFile *file, media_raw_audio_format const &format) : + fFrameSize(0), + fBuffer(0), + fBufferOffset(0), + fBufferUsedSize(0), + fMediaFile(0), + fMediaTrack(0), + fFormat(format) +{ + CALLED(); + if (file == NULL) + return; + if (file->InitCheck() != B_OK) + return; + + fMediaFile = new BMediaFile(file); + if (fMediaFile->InitCheck() != B_OK) + return; + + int count = fMediaFile->CountTracks(); + if (count == 0) { + TRACE("no tracks in file\n"); + return; + } + + // find the first audio track + BMediaTrack *track; + BMediaTrack *audiotrack = 0; + for (int tr = 0; tr < count; tr++) { + track = fMediaFile->TrackAt(tr); + if (track == 0 || track->InitCheck() != B_OK) + continue; + media_format fmt; + if (track->EncodedFormat(&fmt) != B_OK) + continue; + if (fmt.type == B_MEDIA_RAW_AUDIO) { + audiotrack = track; + break; + } + fMediaFile->ReleaseTrack(track); + } + if (audiotrack == 0) { + TRACE("no audio track in file\n"); + return; + } + + SetToTrack(audiotrack); + + // if the track was not set, release it + if (fMediaTrack == 0) { + fMediaFile->ReleaseTrack(audiotrack); + return; + } + + fBuffer = new uint8[fFormat.buffer_size]; + fFrameSize = fFormat.channel_count * (fFormat.format & media_raw_audio_format::B_AUDIO_SIZE_MASK); + + TRACE("BTrackReader::BTrackReader successful\n"); +} + +void +BTrackReader::SetToTrack(BMediaTrack *track) +{ + media_format fmt; + memset(&fmt,0,sizeof(fmt)); //wildcard + memcpy(&fmt.u.raw_audio,&fFormat,sizeof(fFormat)); + fmt.type = B_MEDIA_RAW_AUDIO; + + //try to find a output format + if (B_OK == track->DecodedFormat(&fmt)) { + memcpy(&fFormat,&fmt.u.raw_audio,sizeof(fFormat)); + fMediaTrack = track; + return; + } + + //try again + fmt.u.raw_audio.buffer_size = 0; + if (B_OK == track->DecodedFormat(&fmt)) { + memcpy(&fFormat,&fmt.u.raw_audio,sizeof(fFormat)); + fMediaTrack = track; + return; + } + + //we have failed + TRACE("BTrackReader::SetToTrack failed\n"); +} + +BTrackReader::~BTrackReader() +{ + CALLED(); + if (fMediaFile && fMediaTrack) + fMediaFile->ReleaseTrack(fMediaTrack); + delete fMediaFile; + delete [] fBuffer; +} + +status_t +BTrackReader::InitCheck() +{ + CALLED(); + return fMediaTrack ? fMediaTrack->InitCheck() : B_ERROR; +} + +int64 +BTrackReader::CountFrames(void) +{ + CALLED(); + return fMediaTrack ? fMediaTrack->CountFrames() : 0; +} + +const media_raw_audio_format & +BTrackReader::Format(void) const +{ + CALLED(); + return fFormat; +} + +int32 +BTrackReader::FrameSize(void) +{ + CALLED(); + return fFrameSize; +} + +status_t +BTrackReader::ReadFrames(void *in_buffer, int32 frame_count) +{ + CALLED(); + + uint8 *buffer = (uint8 *)in_buffer; + int32 bytes_to_read = frame_count * fFrameSize; + + status_t last_status = B_OK; + while (bytes_to_read > 0) { + int32 bytes_to_copy = min_c(fBufferUsedSize,bytes_to_read); + if (bytes_to_copy > 0) { + memcpy(buffer,fBuffer + fBufferOffset,bytes_to_copy); + buffer += bytes_to_copy; + bytes_to_read -= bytes_to_copy; + fBufferOffset += bytes_to_copy; + fBufferUsedSize -= bytes_to_copy; + } + if (last_status != B_OK) + break; + if (fBufferUsedSize == 0) { + int64 outFrameCount; + last_status = fMediaTrack->ReadFrames(fBuffer,&outFrameCount); + fBufferOffset = 0; + fBufferUsedSize = outFrameCount * fFrameSize; + } + } + if (bytes_to_read > 0) { + memset(buffer,0,bytes_to_read); + return B_LAST_BUFFER_ERROR; + } else { + return B_OK; + } +} + +status_t +BTrackReader::SeekToFrame(int64 *in_out_frame) +{ + CALLED(); + status_t s = fMediaTrack->SeekToFrame(in_out_frame, B_MEDIA_SEEK_CLOSEST_BACKWARD); + if (s != B_OK) + return s; + fBufferUsedSize = 0; + fBufferOffset = 0; + return B_OK; +} + +BMediaTrack * +BTrackReader::Track(void) +{ + CALLED(); + return fMediaTrack; +} + +}; //namespace BPrivate + diff --git a/src/kits/media/TrackReader.h b/src/kits/media/TrackReader.h new file mode 100644 index 0000000000..caad68bf27 --- /dev/null +++ b/src/kits/media/TrackReader.h @@ -0,0 +1,45 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: TrackReader.h + * DESCR: The undocumented BTrackReader class, + * used by BSound and the GameSound classes + ***********************************************************************/ + +#if !defined(_TRACK_READER_H_) +#define _TRACK_READER_H_ + +namespace BPrivate +{ + +class BTrackReader +{ +public: + BTrackReader(BMediaTrack *, media_raw_audio_format const &); + BTrackReader(BFile *, media_raw_audio_format const &); + ~BTrackReader(); + + status_t InitCheck(); + int64 CountFrames(void); + int32 FrameSize(void); + status_t ReadFrames(void *in_buffer, int32 frame_count); + status_t SeekToFrame(int64 *in_out_frame); + + BMediaTrack * Track(void); + const media_raw_audio_format & Format(void) const; + +private: + void SetToTrack(BMediaTrack *track); + +private: + int32 fFrameSize; + uint8 * fBuffer; + int32 fBufferOffset; + int32 fBufferUsedSize; + BMediaFile *fMediaFile; + BMediaTrack *fMediaTrack; + media_raw_audio_format fFormat; +}; + +}; //namespace BPrivate + +#endif diff --git a/src/kits/media/VolumeControl.cpp b/src/kits/media/VolumeControl.cpp new file mode 100644 index 0000000000..baadde46bf --- /dev/null +++ b/src/kits/media/VolumeControl.cpp @@ -0,0 +1,58 @@ +/*********************************************************************** + * AUTHOR: Marcus Overhagen + * FILE: VolumeControl.cpp + * DESCR: transitional private volume control functions + ***********************************************************************/ + +#include +#include +#include "debug.h" +#include "VolumeControl.h" +#include "../server/headers/ServerInterface.h" + +namespace MediaKitPrivate { + +status_t GetMasterVolume(float *left, float *right) +{ + CALLED(); + BMessenger m(NEW_MEDIA_SERVER_SIGNATURE); + BMessage msg(MEDIA_SERVER_GET_VOLUME); + BMessage reply; + status_t s; + + if (!m.IsValid()) + return B_ERROR; + + s = m.SendMessage(&msg,&reply); + if (s != B_OK) + return s; + + reply.FindFloat("left",left); + reply.FindFloat("right",right); + + return (status_t)reply.what; +} + +status_t SetMasterVolume(float left, float right) +{ + CALLED(); + BMessenger m(NEW_MEDIA_SERVER_SIGNATURE); + BMessage msg(MEDIA_SERVER_SET_VOLUME); + BMessage reply; + status_t s; + + if (!m.IsValid()) + return B_ERROR; + + msg.AddFloat("left",left); + msg.AddFloat("right",right); + + s = m.SendMessage(&msg,&reply); + if (s != B_OK) + return s; + + return (status_t)reply.what; +} + +} //namespace MediaKitPrivate + diff --git a/src/kits/midi/Midi.cpp b/src/kits/midi/Midi.cpp new file mode 100644 index 0000000000..992bbd818f --- /dev/null +++ b/src/kits/midi/Midi.cpp @@ -0,0 +1,334 @@ +//----------------------------------------------------------------------------- +// +#include +#include +#include +#include "MidiEvent.h" + +#define MSG_CODE_PROCESS_EVENT 1 +#define MSG_CODE_TERMINATE_THREAD 0 + +//----------------------------------------------------------------------------- +// Initialization Stuff +BMidi::BMidi() { + _con_list = new BList(); + _is_running = false; + _is_inflowing = false; + _inflow_port = create_port(1,"Inflow Port"); + _inflow_thread_id = spawn_thread(_InflowThread, + "BMidi Inflow Thread", B_REAL_TIME_PRIORITY, (void *)this); + status_t ret = resume_thread(_inflow_thread_id); +} + +BMidi::~BMidi() { + status_t exit_value; + write_port(_inflow_port,MSG_CODE_TERMINATE_THREAD,NULL,0); + wait_for_thread(_inflow_thread_id,&exit_value); + delete_port(_inflow_port); + delete _con_list; +} + +//----------------------------------------------------------------------------- +// Stubs for midi event hooks. +void BMidi::NoteOff(uchar chan, uchar note, uchar vel, uint32 time) { +} +void BMidi::NoteOn(uchar chan, uchar note, uchar vel, uint32 time) { +} +void BMidi::KeyPressure(uchar chan, uchar note, uchar pres, uint32 time) { +} +void BMidi::ControlChange(uchar chan, uchar ctrl_num, uchar ctrl_val, + uint32 time) { +} +void BMidi::ProgramChange(uchar chan, uchar prog_num, uint32 time) { +} +void BMidi::ChannelPressure(uchar chan, uchar pres, uint32 time) { +} +void BMidi::PitchBend(uchar chan, uchar lsb, uchar msb, uint32 time) { +} +void BMidi::SystemExclusive(void * data, size_t data_len, uint32 time) { +} +void BMidi::SystemCommon(uchar stat_byte, uchar data1, uchar data2, + uint32 time) { +} +void BMidi::SystemRealTime(uchar stat_byte, uint32 time) { +} +void BMidi::TempoChange(int32 bpm, uint32 time) { +} +void BMidi::AllNotesOff(bool just_chan, uint32 time) { +} + +//----------------------------------------------------------------------------- +// Public API Functions +status_t BMidi::Start() { + _keep_running = true; + _run_thread_id = spawn_thread(_RunThread, + "BMidi Run Thread", B_REAL_TIME_PRIORITY, (void *)this); + status_t ret = resume_thread(_run_thread_id); + if(ret != B_OK) { + return ret; + } + _is_running = true; + return B_OK; +} + +void BMidi::Stop() { + _keep_running = false; + status_t exit_value; + status_t ret; + ret = wait_for_thread(_run_thread_id,&exit_value); + _is_running = false; +} + +bool BMidi::IsRunning() const { + thread_info info; + get_thread_info(_run_thread_id,&info); + if(find_thread("BMidi Run Thread") == _run_thread_id) { + return true; + } + return false; +} + +void BMidi::Connect(BMidi * to_object) { + _con_list->AddItem((void *)to_object); +} + +void BMidi::Disconnect(BMidi * from_object) { + _con_list->RemoveItem((void *)from_object); +} + +bool BMidi::IsConnected(BMidi * to_object) const { + return _con_list->HasItem((void *)to_object); +} + +BList * BMidi::Connections() const { + return _con_list; +} + +void BMidi::SnoozeUntil(uint32 time) const { + snooze_until((uint64)time*1000,B_SYSTEM_TIMEBASE); +} + +bool BMidi::KeepRunning() { + return _keep_running; +} + +void BMidi::Run() { + while(KeepRunning()) { + snooze(50000); + } +} + +//----------------------------------------------------------------------------- +// Spray Functions +void BMidi::_SprayEvent(BMidiEvent * e) const { + int32 num_connections = _con_list->CountItems(); + BMidi * m; + cerr << "SprayEvent time = " << e->time << " cur_time " << B_NOW << endl; + for(int32 i = 0; i < num_connections; i++) { + m = (BMidi *)_con_list->ItemAt(i); + write_port(m->_inflow_port,MSG_CODE_PROCESS_EVENT,e,sizeof(*e)); + } +} + +void BMidi::SprayNoteOff(uchar chan, uchar note, uchar vel, + uint32 time) const { + BMidiEvent e; + e.time = time; + e.opcode = BMidiEvent::OP_NOTE_OFF; + e.data.note_off.channel = chan; + e.data.note_off.note = note; + e.data.note_off.velocity = vel; + _SprayEvent(&e); +} + +void BMidi::SprayNoteOn(uchar chan, uchar note, uchar vel, + uint32 time) const { + BMidiEvent e; + e.time = time; + e.opcode = BMidiEvent::OP_NOTE_ON; + e.data.note_on.channel = chan; + e.data.note_on.note = note; + e.data.note_on.velocity = vel; + _SprayEvent(&e); +} + +void BMidi::SprayKeyPressure(uchar chan, uchar note, uchar pres, + uint32 time) const { + BMidiEvent e; + e.time = time; + e.opcode = BMidiEvent::OP_NOTE_OFF; + e.data.key_pressure.channel = chan; + e.data.key_pressure.note = note; + e.data.key_pressure.pressure = pres; + _SprayEvent(&e); +} + +void BMidi::SprayControlChange(uchar chan, uchar ctrl_num, uchar ctrl_val, + uint32 time) const { + BMidiEvent e; + e.time = time; + e.opcode = BMidiEvent::OP_CONTROL_CHANGE; + e.data.control_change.channel = chan; + e.data.control_change.number = ctrl_num; + e.data.control_change.value = ctrl_val; + _SprayEvent(&e); +} + +void BMidi::SprayProgramChange(uchar chan, uchar prog_num, + uint32 time) const { + BMidiEvent e; + e.time = time; + e.opcode = BMidiEvent::OP_PROGRAM_CHANGE; + e.data.program_change.channel = chan; + e.data.program_change.number = prog_num; + _SprayEvent(&e); +} + +void BMidi::SprayChannelPressure(uchar chan, uchar pres, + uint32 time) const { + BMidiEvent e; + e.time = time; + e.opcode = BMidiEvent::OP_CHANNEL_PRESSURE; + e.data.channel_pressure.channel = chan; + e.data.channel_pressure.pressure = pres; + _SprayEvent(&e); +} + +void BMidi::SprayPitchBend(uchar chan, uchar lsb, uchar msb, + uint32 time) const { + BMidiEvent e; + e.time = time; + e.opcode = BMidiEvent::OP_PITCH_BEND; + e.data.pitch_bend.channel = chan; + e.data.pitch_bend.lsb = lsb; + e.data.pitch_bend.msb = msb; + _SprayEvent(&e); +} + +void BMidi::SpraySystemExclusive(void * data, size_t data_len, + uint32 time) const { + // Should this data be duplicated!!?? + BMidiEvent e; + e.time = time; + e.opcode = BMidiEvent::OP_SYSTEM_EXCLUSIVE; + e.data.system_exclusive.data = (uint8 *)data; + e.data.system_exclusive.length = data_len; + _SprayEvent(&e); +} + +void BMidi::SpraySystemCommon(uchar stat_byte, uchar data1, uchar data2, + uint32 time) const { + BMidiEvent e; + e.time = time; + e.opcode = BMidiEvent::OP_SYSTEM_COMMON; + e.data.system_common.status = stat_byte; + e.data.system_common.data1 = data1; + e.data.system_common.data2 = data2; + _SprayEvent(&e); +} + +void BMidi::SpraySystemRealTime(uchar stat_byte, uint32 time) const { + BMidiEvent e; + e.time = time; + e.opcode = BMidiEvent::OP_SYSTEM_REAL_TIME; + e.data.system_real_time.status = stat_byte; + _SprayEvent(&e); +} + +void BMidi::SprayTempoChange(int32 bpm, uint32 time) const { + BMidiEvent e; + e.time = time; + e.opcode = BMidiEvent::OP_TEMPO_CHANGE; + e.data.tempo_change.beats_per_minute = bpm; + _SprayEvent(&e); +} + +//----------------------------------------------------------------------------- +// The Inflow Thread +void BMidi::_Inflow() { + BMidiEvent e; + int32 code; + size_t len; + while(true) { + len = read_port(_inflow_port,&code,&e,sizeof(e)); + if (len < 0) continue; // ignore errors + if(code == MSG_CODE_TERMINATE_THREAD) return; + if (len != sizeof(e)) continue; // ignore data in wrong size + // Otherwise we process an event. + switch(e.opcode) { + case BMidiEvent::OP_NONE: + case BMidiEvent::OP_TRACK_END: + case BMidiEvent::OP_ALL_NOTES_OFF: + break; + case BMidiEvent::OP_NOTE_OFF: + NoteOff(e.data.note_off.channel, + e.data.note_off.note, + e.data.note_off.velocity, + e.time); + break; + case BMidiEvent::OP_NOTE_ON: + NoteOff(e.data.note_on.channel, + e.data.note_on.note, + e.data.note_on.velocity, + e.time); + break; + case BMidiEvent::OP_KEY_PRESSURE: + KeyPressure(e.data.key_pressure.channel, + e.data.key_pressure.note, + e.data.key_pressure.pressure, + e.time); + break; + case BMidiEvent::OP_CONTROL_CHANGE: + ControlChange(e.data.control_change.channel, + e.data.control_change.number, + e.data.control_change.value, + e.time); + break; + case BMidiEvent::OP_PROGRAM_CHANGE: + ProgramChange(e.data.program_change.channel, + e.data.program_change.number, + e.time); + break; + case BMidiEvent::OP_CHANNEL_PRESSURE: + ChannelPressure(e.data.channel_pressure.channel, + e.data.channel_pressure.pressure, + e.time); + break; + case BMidiEvent::OP_PITCH_BEND: + PitchBend(e.data.pitch_bend.channel, + e.data.pitch_bend.lsb, + e.data.pitch_bend.msb, + e.time); + break; + case BMidiEvent::OP_SYSTEM_EXCLUSIVE: + SystemExclusive(e.data.system_exclusive.data, + e.data.system_exclusive.length, + e.time); + break; + case BMidiEvent::OP_SYSTEM_COMMON: + SystemCommon(e.data.system_common.status, + e.data.system_common.data1, + e.data.system_common.data2, + e.time); + break; + case BMidiEvent::OP_SYSTEM_REAL_TIME: + SystemRealTime(e.data.system_real_time.status, e.time); + break; + case BMidiEvent::OP_TEMPO_CHANGE: + TempoChange(e.data.tempo_change.beats_per_minute, e.time); + break; + default: + break; + } + } +} + +int32 BMidi::_RunThread(void * data) { + ((BMidi *)data)->Run(); + return 0; +} + +int32 BMidi::_InflowThread(void * data) { + ((BMidi *)data)->_Inflow(); + return 0; +} diff --git a/src/kits/midi/MidiEvent.cpp b/src/kits/midi/MidiEvent.cpp new file mode 100644 index 0000000000..f35d5a9fab --- /dev/null +++ b/src/kits/midi/MidiEvent.cpp @@ -0,0 +1,10 @@ +//----------------------------------------------------------------------------- +// +#include "MidiEvent.h" + +BMidiEvent::BMidiEvent() { + opcode = OP_NONE; +} + +BMidiEvent::~BMidiEvent() { +} diff --git a/src/kits/midi/MidiEvent.h b/src/kits/midi/MidiEvent.h new file mode 100644 index 0000000000..f7ef6152d2 --- /dev/null +++ b/src/kits/midi/MidiEvent.h @@ -0,0 +1,88 @@ +//----------------------------------------------------------------------------- +// +#ifndef _MIDI_EVENT_H_ +#define _MIDI_EVENT_H_ + +#include + +class BMidiEvent { +public: + BMidiEvent(); + ~BMidiEvent(); + + enum Opcode { + OP_NONE, + OP_NOTE_OFF, + OP_NOTE_ON, + OP_KEY_PRESSURE, + OP_CONTROL_CHANGE, + OP_PROGRAM_CHANGE, + OP_CHANNEL_PRESSURE, + OP_PITCH_BEND, + OP_SYSTEM_EXCLUSIVE, + OP_SYSTEM_COMMON, + OP_SYSTEM_REAL_TIME, + OP_TEMPO_CHANGE, + OP_ALL_NOTES_OFF, + OP_TRACK_END, + OP_NUM + }; + + uint32 time; + Opcode opcode; + union Data { + struct NoteOffData { + uint8 channel; + uint8 note; + uint8 velocity; + } note_off; + struct NoteOnData { + uint8 channel; + uint8 note; + uint8 velocity; + } note_on; + struct KeyPressureData { + uint8 channel; + uint8 note; + uint8 pressure; + } key_pressure; + struct ControlChangeData { + uint8 channel; + uint8 number; + uint8 value; + } control_change; + struct ProgramChangeData { + uint8 channel; + uint8 number; + } program_change; + struct ChannelPressureData { + uint8 channel; + uint8 pressure; + } channel_pressure; + struct PitchBendData { + uint8 channel; + uint8 lsb; + uint8 msb; + } pitch_bend; + struct SystemExclusiveData { + uint8 * data; + int32 length; + } system_exclusive; + struct SystemCommonData { + uint8 status; + uint8 data1; + uint8 data2; + } system_common; + struct SystemRealTimeData { + uint8 status; + } system_real_time; + struct TempoChangeData { + uint32 beats_per_minute; + } tempo_change; + struct AllNotesOffData { + bool just_channel; + } all_notes_off; + } data; +}; + +#endif _MIDI_EVENT_H_ \ No newline at end of file diff --git a/src/kits/midi/MidiStore.cpp b/src/kits/midi/MidiStore.cpp new file mode 100644 index 0000000000..5a6e19e72d --- /dev/null +++ b/src/kits/midi/MidiStore.cpp @@ -0,0 +1,606 @@ +//----------------------------------------------------------------------------- +// +#include +#include +#include +#include +#include +#include +#include "MidiEvent.h" + +#define PACK_4_U8_TO_U32(_d1, _d2) \ + _d2 = (uint32)_d1[0] << 24 | (uint32)_d1[1] << 16 | \ + (uint32)_d1[2] << 8 | (uint32)_d1[3]; +#define PACK_2_U8_TO_U16(_d1, _d2) \ + _d2 = (uint16)_d1[0] << 8 | (uint16)_d1[1]; + +//----------------------------------------------------------------------------- +// Public Access Routines +BMidiStore::BMidiStore() { + _evt_list = new BList(); + _tempo = 60; + _cur_evt = 0; +} + +BMidiStore::~BMidiStore() { + int32 num_items = _evt_list->CountItems(); + for(int i = num_items - 1; i >= 0; i--) { + delete (BMidiEvent *)_evt_list->RemoveItem(i); + } + _evt_list->MakeEmpty(); + delete _evt_list; +} + +void BMidiStore::NoteOff(uchar chan, uchar note, uchar vel, uint32 time) { + BMidiEvent * e = new BMidiEvent; + e->opcode = BMidiEvent::OP_NOTE_OFF; + e->time = B_NOW; + e->data.note_off.channel = chan; + e->data.note_off.note = note; + e->data.note_off.velocity = vel; + _evt_list->AddItem(e); +} + +void BMidiStore::NoteOn(uchar chan, uchar note, uchar vel, uint32 time) { + BMidiEvent * e = new BMidiEvent; + e->opcode = BMidiEvent::OP_NOTE_ON; + e->time = B_NOW; + e->data.note_on.channel = chan; + e->data.note_on.note = note; + e->data.note_on.velocity = vel; + _evt_list->AddItem(e); +} + +void BMidiStore::KeyPressure(uchar chan, uchar note, uchar pres, + uint32 time) { + BMidiEvent * e = new BMidiEvent; + e->opcode = BMidiEvent::OP_KEY_PRESSURE; + e->time = B_NOW; + e->data.key_pressure.channel = chan; + e->data.key_pressure.note = note; + e->data.key_pressure.pressure = pres; + _evt_list->AddItem(e); +} + +void BMidiStore::ControlChange(uchar chan, uchar ctrl_num, uchar ctrl_val, + uint32 time) { + BMidiEvent * e = new BMidiEvent; + e->opcode = BMidiEvent::OP_CONTROL_CHANGE; + e->time = B_NOW; + e->data.control_change.channel = chan; + e->data.control_change.number = ctrl_num; + e->data.control_change.value = ctrl_val; + _evt_list->AddItem(e); +} + +void BMidiStore::ProgramChange(uchar chan, uchar prog_num, uint32 time) { + BMidiEvent * e = new BMidiEvent; + e->opcode = BMidiEvent::OP_PROGRAM_CHANGE; + e->time = B_NOW; + e->data.program_change.channel = chan; + e->data.program_change.number = prog_num; + _evt_list->AddItem(e); +} + +void BMidiStore::ChannelPressure(uchar chan, uchar pres, uint32 time) { + BMidiEvent * e = new BMidiEvent; + e->opcode = BMidiEvent::OP_CHANNEL_PRESSURE; + e->time = B_NOW; + e->data.channel_pressure.channel = chan; + e->data.channel_pressure.pressure = pres; + _evt_list->AddItem(e); +} + +void BMidiStore::PitchBend(uchar chan, uchar lsb, uchar msb, uint32 time) { + BMidiEvent * e = new BMidiEvent; + e->opcode = BMidiEvent::OP_PITCH_BEND; + e->time = B_NOW; + e->data.pitch_bend.channel = chan; + e->data.pitch_bend.lsb = lsb; + e->data.pitch_bend.msb = msb; + _evt_list->AddItem(e); +} + +void BMidiStore::SystemExclusive(void * data, size_t data_len, uint32 time) { + BMidiEvent * e = new BMidiEvent; + e->opcode = BMidiEvent::OP_SYSTEM_EXCLUSIVE; + e->time = B_NOW; + e->data.system_exclusive.data = (uint8 *)data; + e->data.system_exclusive.length = data_len; + _evt_list->AddItem(e); +} + +void BMidiStore::SystemCommon(uchar stat_byte, uchar data1, uchar data2, + uint32 time) { + BMidiEvent * e = new BMidiEvent; + e->opcode = BMidiEvent::OP_SYSTEM_COMMON; + e->time = B_NOW; + e->data.system_common.status = stat_byte; + e->data.system_common.data1 = data1; + e->data.system_common.data2 = data2; + _evt_list->AddItem(e); +} + +void BMidiStore::SystemRealTime(uchar stat_byte, uint32 time) { + BMidiEvent * e = new BMidiEvent; + e->opcode = BMidiEvent::OP_SYSTEM_REAL_TIME; + e->time = B_NOW; + e->data.system_real_time.status = stat_byte; + _evt_list->AddItem(e); +} + +void BMidiStore::TempoChange(int32 bpm, uint32 time) { + BMidiEvent * e = new BMidiEvent; + e->opcode = BMidiEvent::OP_TEMPO_CHANGE; + e->time = B_NOW; + e->data.tempo_change.beats_per_minute = bpm; + _evt_list->AddItem(e); +} + +void BMidiStore::AllNotesOff(bool just_chan, uint32 time) { + BMidiEvent * e = new BMidiEvent; + e->opcode = BMidiEvent::OP_ALL_NOTES_OFF; + e->time = B_NOW; + e->data.all_notes_off.just_channel = just_chan; + _evt_list->AddItem(e); +} + +status_t BMidiStore::Import(const entry_ref * ref) { + BEntry file_entry(ref,true); + BPath file_path; + file_entry.GetPath(&file_path); + ifstream inf(file_path.Path(), ios::in | ios::binary); + if(!inf) { + return B_ERROR; + } + inf.seekg(0,ios::end); + uint32 file_len = inf.tellg(); + if(file_len < 16) { + return B_BAD_MIDI_DATA; + } + inf.seekg(ios::beg); + uint8 * data = new uint8[file_len]; + if(data == NULL) { + return B_ERROR; + } + inf.read(data,file_len); + inf.close(); + uint8 * d = data; + if(strncmp((const char *)d,"MThd",4) != 0) { + return B_BAD_MIDI_DATA; + } + d += 4; + uint32 hdr_len; + PACK_4_U8_TO_U32(d,hdr_len); + if(hdr_len != 6) { + return B_BAD_MIDI_DATA; + } + d += 4; + uint32 format; + uint32 tracks; + uint32 division; + PACK_2_U8_TO_U16(d,format); + d += 2; + PACK_2_U8_TO_U16(d,tracks); + d += 2; + PACK_2_U8_TO_U16(d,division); + if(!(division & 0x8000)) { + _ticks_per_beat = division; + } + d += 2; + try { + switch(format) { + case 0: + _DecodeFormat0Tracks(d,tracks,file_len-(data-d)); + break; + case 1: + _DecodeFormat1Tracks(d,tracks,file_len-(data-d)); + break; + case 2: + _DecodeFormat2Tracks(d,tracks,file_len-(data-d)); + break; + default: + return B_BAD_MIDI_DATA; + } + } catch(status_t err) { + return err; + } + return B_OK; +} + +status_t BMidiStore::Export(const entry_ref * ref, int32 format) { + ofstream ouf(ref->name, ios::out | ios::binary); + if(!ouf) { + return B_ERROR; + } + ouf.write("MHdr",4); + + ouf.close(); + return B_OK; +} + +void BMidiStore::SortEvents(bool force) { + _evt_list->SortItems(_CompareEvents); +} + +uint32 BMidiStore::CountEvents() const { + return _evt_list->CountItems(); +} + +uint32 BMidiStore::CurrentEvent() const { + return _cur_evt; +} + +void BMidiStore::SetCurrentEvent(uint32 event_num) { + _cur_evt = event_num; +} + +uint32 BMidiStore::DeltaOfEvent(uint32 event_num) const { + BMidiEvent * e = (BMidiEvent *)_evt_list->ItemAt(event_num); + return e->time - _start_time; +} + +uint32 BMidiStore::EventAtDelta(uint32 time) const { + uint32 event_num = 0; + + return event_num; +} + +uint32 BMidiStore::BeginTime() const { + return _start_time; +} + +void BMidiStore::SetTempo(int32 bpm) { + _tempo = bpm; +} + +int32 BMidiStore::Tempo() const { + return _tempo; +} + +void BMidiStore::Run() { + _start_time = B_NOW; + uint32 last_tick = 0; + uint32 last_time = _start_time; + while(KeepRunning()) { + BMidiEvent * e = (BMidiEvent *)_evt_list->ItemAt(_cur_evt); + if(e == NULL) { + return; + } + uint32 tick = e->time; + uint32 tick_delta = tick - last_tick; + uint32 beat_len = (60000 / _tempo); + uint32 delta_time = (beat_len * tick_delta) / _ticks_per_beat; + uint32 time = last_time + delta_time; + last_time = time; + last_tick = tick; + BMidiEvent::Data & d = e->data; + cerr << "event 0x" << hex << e->opcode << " time = " << time << endl; + switch(e->opcode) { + case BMidiEvent::OP_NOTE_OFF: + SprayNoteOff(d.note_off.channel, + d.note_off.note, d.note_off.velocity,time); + break; + case BMidiEvent::OP_NOTE_ON: + SprayNoteOn(d.note_on.channel, + d.note_on.note,d.note_on.velocity,time); + break; + case BMidiEvent::OP_KEY_PRESSURE: + SprayKeyPressure(d.key_pressure.channel, + d.key_pressure.note,d.key_pressure.pressure,time); + break; + case BMidiEvent::OP_CONTROL_CHANGE: + SprayControlChange(d.control_change.channel, + d.control_change.number,d.control_change.value,time); + break; + case BMidiEvent::OP_PROGRAM_CHANGE: + SprayProgramChange(d.program_change.channel, + d.program_change.number,time); + break; + case BMidiEvent::OP_CHANNEL_PRESSURE: + SprayChannelPressure(d.channel_pressure.channel, + d.channel_pressure.pressure,time); + break; + case BMidiEvent::OP_PITCH_BEND: + SprayPitchBend(d.pitch_bend.channel, + d.pitch_bend.lsb,d.pitch_bend.msb,time); + break; + case BMidiEvent::OP_SYSTEM_EXCLUSIVE: + SpraySystemExclusive(d.system_exclusive.data, + d.system_exclusive.length,time); + break; + case BMidiEvent::OP_SYSTEM_COMMON: + SpraySystemCommon(d.system_common.status, + d.system_common.data1,d.system_common.data2,time); + break; + case BMidiEvent::OP_SYSTEM_REAL_TIME: + SpraySystemRealTime(d.system_real_time.status,time); + break; + case BMidiEvent::OP_TEMPO_CHANGE: + SprayTempoChange(d.tempo_change.beats_per_minute,time); + _tempo = d.tempo_change.beats_per_minute; + break; + case BMidiEvent::OP_ALL_NOTES_OFF: + break; + default: + break; + } + _cur_evt++; + } +} + +//----------------------------------------------------------------------------- +// Decode and Encode Routines +uint8* BMidiStore::_DecodeTrack(uint8* d) { + if(strncmp((const char *)d,"MTrk",4) != 0) { + throw B_BAD_MIDI_DATA; + } +// cerr << "Track " << (track+1) << " offset = " << (unsigned long)(d-data) << "\n"; + d += 4; + uint32 trk_len; + PACK_4_U8_TO_U32(d,trk_len); + d += 4; + uint32 ticks = 0; + uint8* track_last_byte = d + trk_len; + uint8* next_chunk = track_last_byte; + BMidiEvent* event = NULL; + uint8 status = 0; + try { + while(d < track_last_byte) { + uint32 evt_dticks = _ReadVarLength(&d, track_last_byte); + ticks += evt_dticks; + event = new BMidiEvent(); + if ((d[0] & 0x80) != 0) { // running status + status = d[0]; d ++; + } + _ReadEvent(status, &d, track_last_byte, event); + event->time = ticks; // TODO: convert ticks to milliseconds + if(event->opcode == BMidiEvent::OP_TRACK_END) { + delete event; event = NULL; + break; + } + if (event->opcode != BMidiEvent::OP_NONE) { + _evt_list->AddItem(event); + } else { // skip unknown event + delete event; event = NULL; + } + } + } catch(status_t e) { + delete event; + throw e; + } + return next_chunk; +} + + +void BMidiStore::_DecodeFormat0Tracks(uint8 * data, uint16 tracks, + uint32 len) { + _DecodeTrack(data); +} + +void BMidiStore::_DecodeFormat1Tracks(uint8 * data, uint16 tracks, + uint32 len) { + if(tracks == 0) { + throw B_BAD_MIDI_DATA; + } + // simply merge all tracks into one and sort the events afterwards + uint8 * next_track = data; + for (int track = 0; track < tracks; track ++) { + next_track = _DecodeTrack(next_track); + } + SortEvents(); +} + +void BMidiStore::_DecodeFormat2Tracks(uint8 * data, uint16 tracks, + uint32 len) { + return; +} + +void BMidiStore::_EncodeFormat0Tracks(uint8 *) { +} + +void BMidiStore::_EncodeFormat1Tracks(uint8 *) { +} + +void BMidiStore::_EncodeFormat2Tracks(uint8 *) { +} + +void BMidiStore::_ReadEvent(uint8 status, uint8 ** data, uint8 * max_d, BMidiEvent * event) { +#define CHECK_DATA(_d) if((_d) > max_d) throw B_BAD_MIDI_DATA; +#define INC_DATA(_d) CHECK_DATA(_d); d = _d; + uint8 * d = *data; + if(d == NULL) { + throw B_BAD_MIDI_DATA; + } +// cerr << "ReadEvent 0x" << hex << (int)status << "\n"; + if(status == 0xff) { + uint32 len; + if(d[0] == 0x0) { + INC_DATA(d+1); + if(d[0] == 0x00) { + // Sequence number! + INC_DATA(d+1); + } else if(d[0] == 0x02) { + // Sequence number! + INC_DATA(d+3); + } else { + throw B_BAD_MIDI_DATA; + } + } else if(d[0] > 0x00 && d[0] < 0x0a) { + INC_DATA(d+1); + len = _ReadVarLength(&d,max_d); + INC_DATA(d+len); + } else if(d[0] == 0x2f) { + INC_DATA(d+1); + if(d[0] == 0x00) { + INC_DATA(d+1); + event->opcode = BMidiEvent::OP_TRACK_END; + } else { + throw B_BAD_MIDI_DATA; + } + } else if(d[0] == 0x51) { + INC_DATA(d+1); + if(d[0] == 0x03) { + event->opcode = BMidiEvent::OP_TEMPO_CHANGE; + INC_DATA(d+1); + CHECK_DATA(d+2); + uint32 mspb = (uint32)d[0] << 16 | + (uint32)d[1] << 8 | (uint32)d[2]; + uint32 bpm = 60000000 / mspb; + event->data.tempo_change.beats_per_minute = bpm; + INC_DATA(d+3); + } else { + throw B_BAD_MIDI_DATA; + } + } else if(d[0] == 0x54) { + INC_DATA(d+1); + if(d[0] == 0x05) { + INC_DATA(d+1); + // SMPTE start time. + // hour = d[0]; + // minute = d[1]; + // second = d[2]; + // frame = d[3]; + // fraction = d[4]; + INC_DATA(d+5); + } else { + throw B_BAD_MIDI_DATA; + } + } else if(d[0] == 0x58) { + INC_DATA(d+1); + if(d[0] == 0x04) { + INC_DATA(d+1); + // Time signature. + // numerator = d[0]; + // denominator = d[1]; + // midi clocks = d[2]; + // 32nd notes in a quarter = d[3]; + INC_DATA(d+4); + } else { + throw B_BAD_MIDI_DATA; + } + } else if(d[0] == 0x59) { + INC_DATA(d+1); + if(d[0] == 0x02) { + INC_DATA(d+1); + // Key signature. + // sf = d[0]; + // minor = d[1]; + INC_DATA(d+2); + } else { + throw B_BAD_MIDI_DATA; + } + } else if(d[0] == 0x7f) { + INC_DATA(d+1); + uint32 len = _ReadVarLength(&d,max_d); + INC_DATA(d+len); + } else if(d[0] == 0x20) { + INC_DATA(d+1); + if(d[0] == 0x01) { + INC_DATA(d+2); + } else { + throw B_BAD_MIDI_DATA; + } + } else if(d[0] == 0x21) { + INC_DATA(d+1); + if(d[0] == 0x01) { + INC_DATA(d+2); + } + } else { + throw B_BAD_MIDI_DATA; + } + } else if(status == 0xf0) { + // Manufacturer ID = d[0]; + while(d[0] != 0xf7) { + // Read data eliding the msb. + INC_DATA(d+1); + } + } else if((status & 0xf0) == 0x80) { + event->opcode = BMidiEvent::OP_NOTE_OFF; + event->data.note_off.channel = status & 0x0f; + event->data.note_off.note = d[0]; + INC_DATA(d+1); + event->data.note_off.velocity = d[0]; + INC_DATA(d+1); + } else if((status & 0xf0) == 0x90) { + event->opcode = BMidiEvent::OP_NOTE_ON; + event->data.note_on.channel = status & 0x0f; + event->data.note_on.note = d[0]; + INC_DATA(d+1); + event->data.note_on.velocity = d[0]; + INC_DATA(d+1); + } else if((status & 0xf0) == 0xa0) { + event->opcode = BMidiEvent::OP_KEY_PRESSURE; + event->data.key_pressure.channel = status & 0x0f; + event->data.key_pressure.note = d[0]; + INC_DATA(d+1); + event->data.key_pressure.pressure = d[0]; + INC_DATA(d+1); + } else if((status & 0xf0) == 0xb0) { + event->opcode = BMidiEvent::OP_CONTROL_CHANGE; + event->data.control_change.channel = status & 0x0f; + event->data.control_change.number = d[0]; + INC_DATA(d+1); + event->data.control_change.value = d[0]; + INC_DATA(d+1); + } else if((status & 0xf0) == 0xc0) { + event->opcode = BMidiEvent::OP_PROGRAM_CHANGE; + event->data.program_change.channel = status & 0x0f; + event->data.program_change.number = d[0]; + INC_DATA(d+1); + } else if((status & 0xf0) == 0xd0) { + event->opcode = BMidiEvent::OP_CHANNEL_PRESSURE; + event->data.channel_pressure.channel = status & 0x0f; + event->data.channel_pressure.pressure = d[0]; + INC_DATA(d+1); + } else if((status & 0xf0) == 0xe0) { + event->opcode = BMidiEvent::OP_PITCH_BEND; + event->data.pitch_bend.channel = d[0] & 0x0f; + event->data.pitch_bend.lsb = d[0]; + INC_DATA(d+1); + event->data.pitch_bend.msb = d[0]; + INC_DATA(d+1); + } else { + cerr << "Unsupported Code:0x" << hex << (int)status << endl; + throw B_BAD_MIDI_DATA; + } + *data = d; +#undef INC_DATA +#undef CHECK_DATA +} + +void BMidiStore::_WriteEvent(BMidiEvent * e) { +} + +uint32 BMidiStore::_ReadVarLength(uint8 ** data, uint8 * max_d) { + uint32 val; + uint8 bytes = 1; + uint8 byte = 0; + uint8 * d = *data; + val = *d; + d++; + if(val & 0x80) { + val &= 0x7f; + do { + if(d > max_d) { + throw B_BAD_MIDI_DATA; + } + byte = *d; + val = (val << 7) + byte & 0x7f; + bytes++; + d++; + } while(byte & 0x80); + } + *data = d; + return val; +} + + +void BMidiStore::_WriteVarLength(uint32 length) { +} + +int BMidiStore::_CompareEvents(const void * e1, const void *e2) { + BMidiEvent * evt1 = (BMidiEvent *)e1; + BMidiEvent * evt2 = (BMidiEvent *)e2; + return evt1->time - evt2->time; +} diff --git a/src/kits/midi/MidiText.cpp b/src/kits/midi/MidiText.cpp new file mode 100644 index 0000000000..503487b0d7 --- /dev/null +++ b/src/kits/midi/MidiText.cpp @@ -0,0 +1,117 @@ +//----------------------------------------------------------------------------- +// +#include +#include +#include "MidiEvent.h" + +BMidiText::BMidiText() { + _start_time = 0x0; +} + +BMidiText::~BMidiText() { +} + +void BMidiText::NoteOff(uchar chan, uchar note, uchar vel, uint32 time) { + SnoozeUntil(time); + _PrintTime(); + cout << ":NOTE OFF;channel = " << (int)chan + << ",note = " << (int)note << ",velocity = " << (int)vel << endl; +} + +void BMidiText::NoteOn(uchar chan, uchar note, uchar vel, uint32 time) { + SnoozeUntil(time); + _PrintTime(); + cout << ":NOTE ON;channel = " << (int)chan + << ",note = " << (int)note << ",velocity = " << (int)vel << endl; +} + +void BMidiText::KeyPressure(uchar chan, uchar note, uchar pres, uint32 time) { + SnoozeUntil(time); + _PrintTime(); + cout << ":KEY PRESSURE;channel = " << (int)chan + << ",note = " << (int)note << ",pressure = " << (int)pres << endl; +} + +void BMidiText::ControlChange(uchar chan, uchar ctrl_num, + uchar ctrl_val, uint32 time) { + SnoozeUntil(time); + _PrintTime(); + cout << ":CONTROL CHANGE;channel = " << (int)chan + << ",control = " << (int)ctrl_num + << ",value = "<< (int)ctrl_val << endl; +} + +void BMidiText::ProgramChange(uchar chan, uchar prog_num, uint32 time) { + SnoozeUntil(time); + _PrintTime(); + cout << ":PROGRAM CHANGE;channel = " << (int)chan + << ",program = " << (int)prog_num << endl; +} + +void BMidiText::ChannelPressure(uchar chan, uchar pres, uint32 time) { + SnoozeUntil(time); + _PrintTime(); + cout << ":CHANNEL PRESSURE;channel = " << (int)chan + << ",pressure = " << (int)pres << endl; +} + +void BMidiText::PitchBend(uchar chan, uchar lsb, uchar msb, uint32 time) { + SnoozeUntil(time); + _PrintTime(); + cout << ":PITCH BEND;channel = " << (int)chan << hex + << ",lsb = " << (int)lsb << ",msb = " << (int)msb << endl; +} + +void BMidiText::SystemExclusive(void * data, size_t data_len, uint32 time) { + SnoozeUntil(time); + _PrintTime(); + cout << ":SYSTEM EXCLUSIVE;"; + for(size_t i = 0; i < data_len; i++) { + cout << hex << (int)((char *)data)[i]; + } + cout << endl; +} + +void BMidiText::SystemCommon(uchar stat_byte, uchar data1, + uchar data2, uint32 time) { + SnoozeUntil(time); + _PrintTime(); + cout << ":SYSTEM COMMON;status = " << hex << (int)stat_byte + << ",data1 = " << (int)data1 << ",data2 = " << (int)data2 << endl; +} + +void BMidiText::SystemRealTime(uchar stat_byte, uint32 time) { + SnoozeUntil(time); + _PrintTime(); + cout << ":SYSTEM REAL TIME;status = " << hex << (int)stat << endl; +} + +void BMidiText::TempoChange(int32 bpm, uint32 time) { + SnoozeUntil(time); + _PrintTime(); + cout << ":TEMPO CHANGE;" << "beatsperminute = " << bpm << endl; +} + +void BMidiText::AllNotesOff(bool just_chan, uint32 time) { + SnoozeUntil(time); + _PrintTime(); + cout << ":ALL NOTES OFF;" << endl; +} + +void BMidiText::ResetTimer(bool start) { + if(start) { + _start_time = (uint32)(system_time() / 1000); + } else { + _start_time = 0; + } +} + +//----------------------------------------------------------------------------- +// +void BMidiText::_PrintTime() { + uint32 cur_time = B_NOW; + if(_start_time == 0) { + _start_time = cur_time; + } + cout << (cur_time - _start_time); +} diff --git a/src/kits/screensaver/ScreenSaver.cpp b/src/kits/screensaver/ScreenSaver.cpp new file mode 100644 index 0000000000..ddca14df12 --- /dev/null +++ b/src/kits/screensaver/ScreenSaver.cpp @@ -0,0 +1,157 @@ +#include "ScreenSaver.h" + +BScreenSaver::BScreenSaver(BMessage *archive, + image_id) +{ + ticksize = 50000; + looponcount = 0; + loopoffcount = 0; +} + + +BScreenSaver::~BScreenSaver() +{ +} + + +status_t +BScreenSaver::InitCheck() +{ + return B_OK; // This method is meant to be overridden +} + + +status_t +BScreenSaver::StartSaver(BView *view, + bool preview) +{ + return B_OK; // This method is meant to be overridden +} + +void +BScreenSaver::StopSaver() +{ + return; // This method is meant to be overridden +} + +void +BScreenSaver::Draw(BView *view, + int32 frame) +{ + return; // This method is meant to be overridden +} + +void +BScreenSaver::DirectConnected(direct_buffer_info *info) +{ + return; // This method is meant to be overridden +} + +void +BScreenSaver::DirectDraw(int32 frame) +{ + return; // This method is meant to be overridden +} + +void +BScreenSaver::StartConfig(BView *configView) +{ + return; // This method is meant to be overridden +} + +void +BScreenSaver::StopConfig() +{ + return; // This method is meant to be overridden +} + +void +BScreenSaver::SupplyInfo(BMessage *info) const +{ + return; // This method is meant to be overridden +} + +void +BScreenSaver::ModulesChanged(const BMessage *info) +{ + return; // This method is meant to be overridden +} + +status_t +BScreenSaver::SaveState(BMessage *into) const +{ + return -1; +} + +void +BScreenSaver::SetTickSize(bigtime_t ts) +{ + ticksize = ts; +} + +bigtime_t +BScreenSaver::TickSize() const +{ + return ticksize; +} + +void +BScreenSaver::SetLoop(int32 on_count, + int32 off_count) +{ + looponcount = on_count; + loopoffcount = off_count; +} + +int32 +BScreenSaver::LoopOnCount() const +{ + return looponcount; +} + +int32 +BScreenSaver::LoopOffCount() const +{ + return loopoffcount; +} + +void +BScreenSaver::_ReservedScreenSaver1() +{ +} + +void +BScreenSaver::_ReservedScreenSaver2() +{ +} + +void +BScreenSaver::_ReservedScreenSaver3() +{ +} + +void +BScreenSaver::_ReservedScreenSaver4() +{ +} + +void +BScreenSaver::_ReservedScreenSaver5() +{ +} + +void +BScreenSaver::_ReservedScreenSaver6() +{ +} + +void +BScreenSaver::_ReservedScreenSaver7() +{ +} + +void +BScreenSaver::_ReservedScreenSaver8() +{ +} + diff --git a/src/kits/storage/Directory.cpp b/src/kits/storage/Directory.cpp new file mode 100644 index 0000000000..64c81ef277 --- /dev/null +++ b/src/kits/storage/Directory.cpp @@ -0,0 +1,978 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file Directory.cpp + BDirectory implementation. +*/ + +#include +#include + +#include +#include +#include +#include +#include +#include "storage_support.h" +#include "kernel_interface.h" + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS { +#endif + +// constructor +//! Creates an uninitialized BDirectory object. +BDirectory::BDirectory() + : BNode(), + BEntryList(), + fDirFd(StorageKit::NullFd) +{ +} + +// copy constructor +//! Creates a copy of the supplied BDirectory. +/*! \param dir the BDirectory object to be copied +*/ +BDirectory::BDirectory(const BDirectory &dir) + : BNode(), + BEntryList(), + fDirFd(StorageKit::NullFd) +{ + *this = dir; +} + +// constructor +/*! \brief Creates a BDirectory and initializes it to the directory referred + to by the supplied entry_ref. + \param ref the entry_ref referring to the directory +*/ +BDirectory::BDirectory(const entry_ref *ref) + : BNode(), + BEntryList(), + fDirFd(StorageKit::NullFd) +{ + SetTo(ref); +} + +// constructor +/*! \brief Creates a BDirectory and initializes it to the directory referred + to by the supplied node_ref. + \param nref the node_ref referring to the directory +*/ +BDirectory::BDirectory(const node_ref *nref) + : BNode(), + BEntryList(), + fDirFd(StorageKit::NullFd) +{ + SetTo(nref); +} + +// constructor +/*! \brief Creates a BDirectory and initializes it to the directory referred + to by the supplied BEntry. + \param entry the BEntry referring to the directory +*/ +BDirectory::BDirectory(const BEntry *entry) + : BNode(), + BEntryList(), + fDirFd(StorageKit::NullFd) +{ + SetTo(entry); +} + +// constructor +/*! \brief Creates a BDirectory and initializes it to the directory referred + to by the supplied path name. + \param path the directory's path name +*/ +BDirectory::BDirectory(const char *path) + : BNode(), + BEntryList(), + fDirFd(StorageKit::NullFd) +{ + SetTo(path); +} + +// constructor +/*! \brief Creates a BDirectory and initializes it to the directory referred + to by the supplied path name relative to the specified BDirectory. + \param dir the BDirectory, relative to which the directory's path name is + given + \param path the directory's path name relative to \a dir +*/ +BDirectory::BDirectory(const BDirectory *dir, const char *path) + : BNode(), + BEntryList(), + fDirFd(StorageKit::NullFd) +{ + SetTo(dir, path); +} + +// destructor +//! Frees all allocated resources. +/*! If the BDirectory is properly initialized, the directory's file descriptor + is closed. +*/ +BDirectory::~BDirectory() +{ + // Also called by the BNode destructor, but we rather try to avoid + // problems with calling virtual functions in the base class destructor. + // Depending on the compiler implementation an object may be degraded to + // an object of the base class after the destructor of the derived class + // has been executed. + close_fd(); +} + +// SetTo +/*! \brief Re-initializes the BDirectory to the directory referred to by the + supplied entry_ref. + \param ref the entry_ref referring to the directory + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a ref. + - \c B_ENTRY_NOT_FOUND: Directory not found. + - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. + - \c B_NO_MEMORY: Insufficient memory for operation. + - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. + - \c B_BUSY: A node was busy. + - \c B_FILE_ERROR: A general file error. + - \c B_NO_MORE_FDS: The application has run out of file descriptors. + \todo Currently implemented using StorageKit::entry_ref_to_path(). + Reimplement! +*/ +status_t +BDirectory::SetTo(const entry_ref *ref) +{ + Unset(); + char path[B_PATH_NAME_LENGTH + 1]; + status_t error = (ref ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + error = StorageKit::entry_ref_to_path(ref, path, + B_PATH_NAME_LENGTH + 1); + } + if (error == B_OK) + error = SetTo(path); + set_status(error); + return error; +} + +// SetTo +/*! \brief Re-initializes the BDirectory to the directory referred to by the + supplied node_ref. + \param nref the node_ref referring to the directory + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a nref. + - \c B_ENTRY_NOT_FOUND: Directory not found. + - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. + - \c B_NO_MEMORY: Insufficient memory for operation. + - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. + - \c B_BUSY: A node was busy. + - \c B_FILE_ERROR: A general file error. + - \c B_NO_MORE_FDS: The application has run out of file descriptors. +*/ +status_t +BDirectory::SetTo(const node_ref *nref) +{ + Unset(); + status_t error = (nref ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + entry_ref ref(nref->device, nref->node, "."); + error = SetTo(&ref); + } + set_status(error); + return error; +} + +// SetTo +/*! \brief Re-initializes the BDirectory to the directory referred to by the + supplied BEntry. + \param entry the BEntry referring to the directory + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a entry. + - \c B_ENTRY_NOT_FOUND: Directory not found. + - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. + - \c B_NO_MEMORY: Insufficient memory for operation. + - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. + - \c B_BUSY: A node was busy. + - \c B_FILE_ERROR: A general file error. + - \c B_NO_MORE_FDS: The application has run out of file descriptors. + \todo Implemented using SetTo(entry_ref*). Check, if necessary to + reimplement! +*/ +status_t +BDirectory::SetTo(const BEntry *entry) +{ + Unset(); + entry_ref ref; + status_t error = (entry ? B_OK : B_BAD_VALUE); + if (error == B_OK && entry->InitCheck() != B_OK) + error = B_BAD_VALUE; + if (error == B_OK) + error = entry->GetRef(&ref); + if (error == B_OK) + error = SetTo(&ref); + set_status(error); + return error; +} + +// SetTo +/*! \brief Re-initializes the BDirectory to the directory referred to by the + supplied path name. + \param path the directory's path name + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a path. + - \c B_ENTRY_NOT_FOUND: Directory not found. + - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. + - \c B_NO_MEMORY: Insufficient memory for operation. + - \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long. + - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. + - \c B_BUSY: A node was busy. + - \c B_FILE_ERROR: A general file error. + - \c B_NO_MORE_FDS: The application has run out of file descriptors. + - \c B_NOT_A_DIRECTORY: \a path includes a non-directory. +*/ +status_t +BDirectory::SetTo(const char *path) +{ + Unset(); + status_t result = (path ? B_OK : B_BAD_VALUE); + StorageKit::FileDescriptor newDirFd = StorageKit::NullFd; + if (result == B_OK) + result = StorageKit::open_dir(path, newDirFd); + if (result == B_OK) { + // We have to take care that BNode doesn't stick to a symbolic link. + // open_dir() does always traverse those. Therefore we open the FD for + // BNode (without the O_NOTRAVERSE flag). + StorageKit::FileDescriptor fd = StorageKit::NullFd; + result = StorageKit::open(path, O_RDWR, fd); + if (result == B_OK) { + result = set_fd(fd); + if (result != B_OK) + StorageKit::close(fd); + } + if (result == B_OK) + fDirFd = newDirFd; + else + StorageKit::close_dir(newDirFd); + } + // finally set the BNode status + set_status(result); + return result; +} + +// SetTo +/*! \brief Re-initializes the BDirectory to the directory referred to by the + supplied path name relative to the specified BDirectory. + \param dir the BDirectory, relative to which the directory's path name is + given + \param path the directory's path name relative to \a dir + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a dir or \a path, or \a path is absolute. + - \c B_ENTRY_NOT_FOUND: Directory not found. + - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. + - \c B_NO_MEMORY: Insufficient memory for operation. + - \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long. + - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. + - \c B_BUSY: A node was busy. + - \c B_FILE_ERROR: A general file error. + - \c B_NO_MORE_FDS: The application has run out of file descriptors. + - \c B_NOT_A_DIRECTORY: \a path includes a non-directory. + \todo Implemented using SetTo(BEntry*). Check, if necessary to reimplement! +*/ +status_t +BDirectory::SetTo(const BDirectory *dir, const char *path) +{ + Unset(); + status_t error = (dir && path ? B_OK : B_BAD_VALUE); + if (error == B_OK && StorageKit::is_absolute_path(path)) + error = B_BAD_VALUE; + BEntry entry; + if (error == B_OK) + error = entry.SetTo(dir, path); + if (error == B_OK) + error = SetTo(&entry); + set_status(error); + return error; +} + +// GetEntry +//! Returns a BEntry referring to the directory represented by this object. +/*! If the initialization of \a entry fails, it is Unset(). + \param entry a pointer to the entry that shall be set to refer to the + directory + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a entry. + - \c B_ENTRY_NOT_FOUND: Directory not found. + - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. + - \c B_NO_MEMORY: Insufficient memory for operation. + - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. + - \c B_BUSY: A node was busy. + - \c B_FILE_ERROR: A general file error. + - \c B_NO_MORE_FDS: The application has run out of file descriptors. + \todo Implemented using StorageKit::dir_to_self_entry_ref(). Check, if + there is a better alternative. +*/ +status_t +BDirectory::GetEntry(BEntry *entry) const +{ + status_t error = (entry ? B_OK : B_BAD_VALUE); + if (entry) + entry->Unset(); + if (error == B_OK && InitCheck() != B_OK) + error = B_NO_INIT; + entry_ref ref; + if (error == B_OK) + error = StorageKit::dir_to_self_entry_ref(fDirFd, &ref); + if (error == B_OK) + error = entry->SetTo(&ref); + return error; +} + +// IsRootDirectory +/*! \brief Returns whether the directory represented by this BDirectory is a + root directory of a volume. + \return + - \c true, if the BDirectory is properly initialized and represents a + root directory of some volume, + - \c false, otherwise. +*/ +bool +BDirectory::IsRootDirectory() const +{ + // compare the directory's node ID with the ID of the root node of the FS + bool result = false; + node_ref ref; + fs_info info; + if (GetNodeRef(&ref) == B_OK && fs_stat_dev(ref.device, &info) == 0) + result = (ref.node == info.root); + return result; +} + +// FindEntry +/*! \brief Finds an entry referred to by a path relative to the directory + represented by this BDirectory. + \a path may be absolute. If the BDirectory is not properly initialized, + the entry is search relative to the current directory. + If the entry couldn't be found, \a entry is Unset(). + \param path the entry's path name. May be relative to this directory or + absolute. + \param entry a pointer to a BEntry to be initialized with the found entry + \param traverse specifies whether to follow it, if the found entry + is a symbolic link. + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a path or \a entry. + - \c B_ENTRY_NOT_FOUND: Entry not found. + - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. + - \c B_NO_MEMORY: Insufficient memory for operation. + - \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long. + - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. + - \c B_BUSY: A node was busy. + - \c B_FILE_ERROR: A general file error. + - \c B_NO_MORE_FDS: The application has run out of file descriptors. + - \c B_NOT_A_DIRECTORY: \a path includes a non-directory. + \note The functionality of this method differs from the one of + BEntry::SetTo(BDirectory *, const char *, bool) in that the + latter doesn't require the entry to be existent, whereas this + function does. +*/ +status_t +BDirectory::FindEntry(const char *path, BEntry *entry, bool traverse) const +{ + status_t error = (path && entry ? B_OK : B_BAD_VALUE); + if (entry) + entry->Unset(); + if (error == B_OK) { + // init a potentially abstract entry + if (InitCheck() == B_OK) + error = entry->SetTo(this, path, traverse); + else + error = entry->SetTo(path, traverse); + // fail, if entry is abstract + if (error == B_OK && !entry->Exists()) { + error = B_ENTRY_NOT_FOUND; + entry->Unset(); + } + } + return error; +} + +// Contains +/*! \brief Returns whether this directory or any of its subdirectories + at any level contain the entry referred to by the supplied path name. + Only entries that match the node flavor specified by \a nodeFlags are + considered. + If the BDirectory is not properly initialized, the method returns \c true, + if the entry exists and its kind does match. A non-absolute path is + considered relative to the current directory. + \param path the entry's path name. May be relative to this directory or + absolute. + \param nodeFlags Any of the following: + - \c B_FILE_NODE: The entry must be a file. + - \c B_DIRECTORY_NODE: The entry must be a directory. + - \c B_SYMLINK_NODE: The entry must be a symbolic link. + - \c B_ANY_NODE: The entry may be of any kind. + \return + - \c true, if the entry exists, its kind does match \nodeFlags and the + BDirectory is either not properly initialized or it does contain the + entry at any level, + - \c false, otherwise +*/ +bool +BDirectory::Contains(const char *path, int32 nodeFlags) const +{ + bool result = true; + if (path) { + BEntry entry; + if (InitCheck() == B_OK && !StorageKit::is_absolute_path(path)) + entry.SetTo(this, path); + else + entry.SetTo(path); + result = Contains(&entry, nodeFlags); + } else { + // R5 behavior + result = (InitCheck() == B_OK); + } + return result; +} + +// Contains +/*! \brief Returns whether this directory or any of its subdirectories + at any level contain the entry referred to by the supplied BEntry. + Only entries that match the node flavor specified by \a nodeFlags are + considered. + \param entry a BEntry referring to the entry + \param nodeFlags Any of the following: + - \c B_FILE_NODE: The entry must be a file. + - \c B_DIRECTORY_NODE: The entry must be a directory. + - \c B_SYMLINK_NODE: The entry must be a symbolic link. + - \c B_ANY_NODE: The entry may be of any kind. + \return + - \c true, if the BDirectory is properly initialized and the entry of the + matching kind could be found, + - \c false, otherwise +*/ +bool +BDirectory::Contains(const BEntry *entry, int32 nodeFlags) const +{ + bool result = (entry); + // check, if the entry exists at all + if (result) + result = entry->Exists(); + // test the node kind + if (result) { + switch (nodeFlags) { + case B_FILE_NODE: + result = entry->IsFile(); + break; + case B_DIRECTORY_NODE: + result = entry->IsDirectory(); + break; + case B_SYMLINK_NODE: + result = entry->IsSymLink(); + break; + case B_ANY_NODE: + break; + default: + result = false; + break; + } + } + // If the directory is initialized, get the canonical paths of the dir and + // the entry and check, if the latter is a prefix of the first one. + if (result && InitCheck() == B_OK) { + char dirPath[B_PATH_NAME_LENGTH + 1]; + char entryPath[B_PATH_NAME_LENGTH + 1]; + result = (StorageKit::dir_to_path(fDirFd, dirPath, + B_PATH_NAME_LENGTH + 1) == B_OK); + entry_ref ref; + if (result) + result = (entry->GetRef(&ref) == B_OK); + if (result) { + result = (StorageKit::entry_ref_to_path(&ref, entryPath, + B_PATH_NAME_LENGTH + 1) + == B_OK); + } + if (result) + result = !strncmp(dirPath, entryPath, strlen(dirPath)); + } + return result; +} + +// GetStatFor +/*! \brief Returns the stat structure of the entry referred to by the supplied + path name. + \param path the entry's path name. May be relative to this directory or + absolute, or \c NULL to get the directories stat info. + \param st a pointer to the stat structure to be filled in by this function + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a st. + - \c B_ENTRY_NOT_FOUND: Entry not found. + - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. + - \c B_NO_MEMORY: Insufficient memory for operation. + - \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long. + - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. + - \c B_BUSY: A node was busy. + - \c B_FILE_ERROR: A general file error. + - \c B_NO_MORE_FDS: The application has run out of file descriptors. + - \c B_NOT_A_DIRECTORY: \a path includes a non-directory. +*/ +status_t +BDirectory::GetStatFor(const char *path, struct stat *st) const +{ + status_t error = (st ? B_OK : B_BAD_VALUE); + if (error == B_OK && InitCheck() != B_OK) + error = B_NO_INIT; + if (error == B_OK) { + if (path) { + if (strlen(path) == 0) + error = B_ENTRY_NOT_FOUND; + else { + BEntry entry(this, path); + error = entry.InitCheck(); + if (error == B_OK) + error = entry.GetStat(st); + } + } else + error = GetStat(st); + } + return error; +} + +// GetNextEntry +//! Returns the BDirectory's next entry as a BEntry. +/*! Unlike GetNextDirents() this method ignores the entries "." and "..". + \param entry a pointer to a BEntry to be initialized to the found entry + \param traverse specifies whether to follow it, if the found entry + is a symbolic link. + \note The iterator used by this method is the same one used by + GetNextRef(), GetNextDirents(), Rewind() and CountEntries(). + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a entry. + - \c B_ENTRY_NOT_FOUND: No more entries found. + - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. + - \c B_NO_MEMORY: Insufficient memory for operation. + - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. + - \c B_BUSY: A node was busy. + - \c B_FILE_ERROR: A general file error. + - \c B_NO_MORE_FDS: The application has run out of file descriptors. +*/ +status_t +BDirectory::GetNextEntry(BEntry *entry, bool traverse) +{ + status_t error = (entry ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + entry_ref ref; + error = GetNextRef(&ref); + if (error == B_OK) + error = entry->SetTo(&ref, traverse); + } + return error; +} + +// GetNextRef +//! Returns the BDirectory's next entry as an entry_ref. +/*! Unlike GetNextDirents() this method ignores the entries "." and "..". + \param ref a pointer to an entry_ref to be filled in with the data of the + found entry + \param traverse specifies whether to follow it, if the found entry + is a symbolic link. + \note The iterator used be this method is the same one used by + GetNextEntry(), GetNextDirents(), Rewind() and CountEntries(). + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a ref. + - \c B_ENTRY_NOT_FOUND: No more entries found. + - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. + - \c B_NO_MEMORY: Insufficient memory for operation. + - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. + - \c B_BUSY: A node was busy. + - \c B_FILE_ERROR: A general file error. + - \c B_NO_MORE_FDS: The application has run out of file descriptors. +*/ +status_t +BDirectory::GetNextRef(entry_ref *ref) +{ + status_t error = (ref ? B_OK : B_BAD_VALUE); + if (error == B_OK && InitCheck() != B_OK) + error = B_FILE_ERROR; + if (error == B_OK) { + StorageKit::LongDirEntry entry; + bool next = true; + while (error == B_OK && next) { + if (StorageKit::read_dir(fDirFd, &entry, sizeof(entry), 1) != 1) + error = B_ENTRY_NOT_FOUND; + if (error == B_OK) { + next = (!strcmp(entry.d_name, ".") + || !strcmp(entry.d_name, "..")); + } + } + if (error == B_OK) + *ref = entry_ref(entry.d_pdev, entry.d_pino, entry.d_name); + } + return error; +} + +// GetNextDirents +//! Returns the BDirectory's next entries as dirent structures. +/*! Unlike GetNextEntry() and GetNextRef(), this method returns also + the entries "." and "..". + \param buf a pointer to a buffer to be filled with dirent structures of + the found entries + \param count the maximal number of entries to be returned. + \note The iterator used by this method is the same one used by + GetNextEntry(), GetNextRef(), Rewind() and CountEntries(). + \return + - The number of dirent structures stored in the buffer, 0 when there are + no more entries to be returned. + - \c B_BAD_VALUE: \c NULL \a buf. + - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. + - \c B_NO_MEMORY: Insufficient memory for operation. + - \c B_NAME_TOO_LONG: The entry's name is too long for the buffer. + - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. + - \c B_BUSY: A node was busy. + - \c B_FILE_ERROR: A general file error. + - \c B_NO_MORE_FDS: The application has run out of file descriptors. +*/ +int32 +BDirectory::GetNextDirents(dirent *buf, size_t bufSize, int32 count) +{ + int32 result = (buf ? B_OK : B_BAD_VALUE); + if (result == B_OK && InitCheck() != B_OK) + result = B_FILE_ERROR; + if (result == B_OK) + result = StorageKit::read_dir(fDirFd, buf, bufSize, count); + return result; +} + +// Rewind +//! Rewinds the directory iterator. +/*! \return + - \c B_OK: Everything went fine. + - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. + - \c B_NO_MEMORY: Insufficient memory for operation. + - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. + - \c B_BUSY: A node was busy. + - \c B_FILE_ERROR: A general file error. + - \c B_NO_MORE_FDS: The application has run out of file descriptors. + \see GetNextEntry(), GetNextRef(), GetNextDirents(), CountEntries() +*/ +status_t +BDirectory::Rewind() +{ + status_t error = B_OK; + if (error == B_OK && InitCheck() != B_OK) + error = B_FILE_ERROR; + if (error == B_OK) + error = StorageKit::rewind_dir(fDirFd); + return error; +} + +// CountEntries +//! Returns the number of entries in this directory. +/*! CountEntries() uses the directory iterator also used by GetNextEntry(), + GetNextRef() and GetNextDirents(). It does a Rewind(), iterates through + the entries and Rewind()s again. The entries "." and ".." are not counted. + \return + - the number of entries in the directory (not counting "." and ".."). + - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. + - \c B_NO_MEMORY: Insufficient memory for operation. + - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. + - \c B_BUSY: A node was busy. + - \c B_FILE_ERROR: A general file error. + - \c B_NO_MORE_FDS: The application has run out of file descriptors. + \see GetNextEntry(), GetNextRef(), GetNextDirents(), Rewind() +*/ +int32 +BDirectory::CountEntries() +{ + status_t error = Rewind(); + int32 count = 0; + if (error == B_OK) { + StorageKit::LongDirEntry entry; + while (error == B_OK) { + if (StorageKit::read_dir(fDirFd, &entry, sizeof(entry), 1) != 1) + error = B_ENTRY_NOT_FOUND; + if (error == B_OK + && strcmp(entry.d_name, ".") && strcmp(entry.d_name, "..")) { + count++; + } + } + if (error == B_ENTRY_NOT_FOUND) + error = B_OK; + } + Rewind(); + return (error == B_OK ? count : error); +} + +// CreateDirectory +//! Creates a new directory. +/*! If an entry with the supplied name does already exist, the method fails. + \param path the new directory's path name. May be relative to this + directory or absolute. + \param dir a pointer to a BDirectory to be initialized to the newly + created directory. May be \c NULL. + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a path. + - \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry. + - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. + - \c B_NO_MEMORY: Insufficient memory for operation. + - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. + - \c B_BUSY: A node was busy. + - \c B_FILE_ERROR: A general file error. + - \c B_FILE_EXISTS: An entry with that name does already exist. + - \c B_NO_MORE_FDS: The application has run out of file descriptors. +*/ +status_t +BDirectory::CreateDirectory(const char *path, BDirectory *dir) +{ + status_t error = (path ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + // get the actual (absolute) path using BEntry's help + BEntry entry; + if (InitCheck() == B_OK && !StorageKit::is_absolute_path(path)) + entry.SetTo(this, path); + else + entry.SetTo(path); + error = entry.InitCheck(); + BPath realPath; + if (error == B_OK) + error = entry.GetPath(&realPath); + if (error == B_OK) + error = StorageKit::create_dir(realPath.Path()); + if (error == B_OK && dir) + error = dir->SetTo(realPath.Path()); + } + return error; +} + +// CreateFile +//! Creates a new file. +/*! If a file with the supplied name does already exist, the method fails, + unless it is passed \c false to \a failIfExists -- in that case the file + is truncated to zero size. The new BFile will operate in \c B_READ_WRITE + mode. + \param path the new file's path name. May be relative to this + directory or absolute. + \param file a pointer to a BFile to be initialized to the newly + created file. May be \c NULL. + \param failIfExists \c true, if the method should fail when the file + already exists, \c false otherwise + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a path. + - \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry. + - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. + - \c B_NO_MEMORY: Insufficient memory for operation. + - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. + - \c B_BUSY: A node was busy. + - \c B_FILE_ERROR: A general file error. + - \c B_FILE_EXISTS: A file with that name does already exist and + \c true has been passed for \a failIfExists. + - \c B_IS_A_DIRECTORY: A directory with the supplied name does already + exist. + - \c B_NO_MORE_FDS: The application has run out of file descriptors. +*/ +status_t +BDirectory::CreateFile(const char *path, BFile *file, bool failIfExists) +{ + status_t error (path ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + // Let BFile do the dirty job. + uint32 openMode = B_READ_WRITE | B_CREATE_FILE + | (failIfExists ? B_FAIL_IF_EXISTS : 0); + BFile tmpFile; + BFile *realFile = (file ? file : &tmpFile); + if (InitCheck() == B_OK && !StorageKit::is_absolute_path(path)) + error = realFile->SetTo(this, path, openMode); + else + error = realFile->SetTo(path, openMode); + if (error != B_OK) + realFile->Unset(); + } + return error; +} + +// CreateSymLink +//! Creates a new symbolic link. +/*! If an entry with the supplied name does already exist, the method fails. + \param path the new symbolic link's path name. May be relative to this + directory or absolute. + \param linkToPath the path the symbolic link shall point to. + \param dir a pointer to a BSymLink to be initialized to the newly + created symbolic link. May be \c NULL. + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a path or \a linkToPath. + - \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry. + - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. + - \c B_NO_MEMORY: Insufficient memory for operation. + - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. + - \c B_BUSY: A node was busy. + - \c B_FILE_ERROR: A general file error. + - \c B_FILE_EXISTS: An entry with that name does already exist. + - \c B_NO_MORE_FDS: The application has run out of file descriptors. +*/ +status_t +BDirectory::CreateSymLink(const char *path, const char *linkToPath, + BSymLink *link) +{ + status_t error = (path && linkToPath ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + // get the actual (absolute) path using BEntry's help + BEntry entry; + if (InitCheck() == B_OK && !StorageKit::is_absolute_path(path)) + entry.SetTo(this, path); + else + entry.SetTo(path); + error = entry.InitCheck(); + BPath realPath; + if (error == B_OK) + error = entry.GetPath(&realPath); + if (error == B_OK) + error = StorageKit::create_link(realPath.Path(), linkToPath); + if (error == B_OK && link) + error = link->SetTo(realPath.Path()); + } + return error; +} + +// = +//! Assigns another BDirectory to this BDirectory. +/*! If the other BDirectory is uninitialized, this one will be too. Otherwise + it will refer to the same directory, unless an error occurs. + \param dir the original BDirectory + \return a reference to this BDirectory +*/ +BDirectory & +BDirectory::operator=(const BDirectory &dir) +{ + if (&dir != this) { // no need to assign us to ourselves + Unset(); + if (dir.InitCheck() == B_OK) { + *((BNode*)this) = dir; + if (InitCheck() == B_OK) { + // duplicate the file descriptor + status_t status = StorageKit::dup_dir(dir.fDirFd, fDirFd); + if (status != B_OK) + Unset(); + set_status(status); + } + } + } + return *this; +} + + +// FBC +void BDirectory::_ReservedDirectory1() {} +void BDirectory::_ReservedDirectory2() {} +void BDirectory::_ReservedDirectory3() {} +void BDirectory::_ReservedDirectory4() {} +void BDirectory::_ReservedDirectory5() {} +void BDirectory::_ReservedDirectory6() {} + +// close_fd +//! Closes the BDirectory's file descriptor. +void +BDirectory::close_fd() +{ + if (fDirFd != StorageKit::NullFd) { + StorageKit::close_dir(fDirFd); + fDirFd = StorageKit::NullFd; + } + BNode::close_fd(); +} + +//! Returns the BDirectory's file descriptor. +/*! To be used instead of accessing the BDirectory's private \c fDirFd member + directly. + \return the file descriptor, or -1, if not properly initialized. +*/ +StorageKit::FileDescriptor +BDirectory::get_fd() const +{ + return fDirFd; +} + + +// C functions + +// create_directory +//! Creates all missing directories along a given path. +/*! \param path the directory path name. + \param mode a permission specification, which shall be used for the + newly created directories. + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a path. + - \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry. + - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. + - \c B_NO_MEMORY: Insufficient memory for operation. + - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. + - \c B_BUSY: A node was busy. + - \c B_FILE_ERROR: A general file error. + - \c B_NOT_A_DIRECTORY: An entry other than a directory with that name does + already exist. + - \c B_NO_MORE_FDS: The application has run out of file descriptors. + \todo Check for efficency. +*/ +status_t +create_directory(const char *path, mode_t mode) +{ + // That's the strategy: We start with the first component of the supplied + // path, create a BPath object from it and successively add the following + // components. Each time we get a new path, we check, if the entry it + // refers to exists and is a directory. If it doesn't exist, then we try + // to create it. This goes on, until we're done with the input path or + // an error occurs. + status_t error = (path ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + BPath dirPath; + char *component; + int32 nextComponent; + do { + // get the next path component + error = StorageKit::parse_first_path_component(path, component, + nextComponent); + if (error == B_OK) { + // append it to the BPath + if (dirPath.InitCheck() == B_NO_INIT) // first component + error = dirPath.SetTo(component); + else + error = dirPath.Append(component); + delete[] component; + path += nextComponent; + // create a BEntry from the BPath + BEntry entry; + if (error == B_OK) + error = entry.SetTo(dirPath.Path(), true); + // check, if it exists + if (error == B_OK) { + if (entry.Exists()) { + // yep, it exists + if (!entry.IsDirectory()) // but is no directory + error = B_NOT_A_DIRECTORY; + } else // it doesn't exists -- create it + error = StorageKit::create_dir(dirPath.Path(), mode); + } + } + } while (error == B_OK && nextComponent != 0); + } + return error; +} + + +#ifdef USE_OPENBEOS_NAMESPACE +}; // namespace OpenBeOS +#endif diff --git a/src/kits/storage/Entry.cpp b/src/kits/storage/Entry.cpp new file mode 100644 index 0000000000..21645a55d9 --- /dev/null +++ b/src/kits/storage/Entry.cpp @@ -0,0 +1,1136 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file Entry.cpp + BEntry and entry_ref implementations. +*/ + +#include + +#include +#include + +#include +#include +#include +#include "kernel_interface.h" +#include "storage_support.h" + +#ifdef USE_OPENBEOS_NAMESPACE +using namespace OpenBeOS; +#endif + +// SYMLINK_MAX is needed by B_SYMLINK_MAX +// I don't know, why it isn't defined. +#ifndef SYMLINK_MAX +#define SYMLINK_MAX (16) +#endif + +//---------------------------------------------------------------------------- +// struct entry_ref +//---------------------------------------------------------------------------- + +/*! \struct entry_ref + \brief A filesystem entry represented as a name in a concrete directory. + + entry_refs may refer to pre-existing (concrete) files, as well as non-existing + (abstract) files. However, the parent directory of the file \b must exist. + + The result of this dichotomy is a blending of the persistence gained by referring + to entries with a reference to their internal filesystem node and the flexibility gained + by referring to entries by name. + + For example, if the directory in which the entry resides (or a + directory further up in the hierarchy) is moved or renamed, the entry_ref will + still refer to the correct file (whereas a pathname to the previous location of the + file would now be invalid). + + On the other hand, say that the entry_ref refers to a concrete file. If the file + itself is renamed, the entry_ref now refers to an abstract file with the old name + (the upside in this case is that abstract entries may be represented by entry_refs + without preallocating an internal filesystem node for them). +*/ + + +//! Creates an unitialized entry_ref. +entry_ref::entry_ref() + : device(-1), + directory(-1), + name(NULL) +{ +} + +/*! \brief Creates an entry_ref initialized to the given file name in the given + directory on the given device. + + \p name may refer to either a pre-existing file in the given + directory, or a non-existent file. No explicit checking is done to verify validity of the given arguments, but + later use of the entry_ref will fail if \p dev is not a valid device or \p dir + is a not a directory on \p dev. + + \param dev the device on which the entry's parent directory resides + \param dir the directory in which the entry resides + \param name the leaf name of the entry, which is not required to exist +*/ +entry_ref::entry_ref(dev_t dev, ino_t dir, const char *name) + : device(dev), directory(dir), name(NULL) +{ + set_name(name); +} + +/*! \brief Creates a copy of the given entry_ref. + + \param ref a reference to an entry_ref to copy +*/ +entry_ref::entry_ref(const entry_ref &ref) + : device(ref.device), + directory(ref.directory), + name(NULL) +{ + set_name(ref.name); +} + +//! Destroys the object and frees the storage allocated for the leaf name, if necessary. +entry_ref::~entry_ref() +{ + if (name != NULL) + delete [] name; +} + +/*! \brief Set the entry_ref's leaf name, freeing the storage allocated for any previous + name and then making a copy of the new name. + + \param name pointer to a null-terminated string containing the new name for + the entry. May be \c NULL. +*/ +status_t entry_ref::set_name(const char *name) +{ + if (this->name != NULL) { + delete [] this->name; + } + + if (name == NULL) { + this->name = NULL; + } else { + this->name = new(nothrow) char[strlen(name)+1]; + if (this->name == NULL) + return B_NO_MEMORY; + strcpy(this->name, name); + } + + return B_OK; +} + +/*! \brief Compares the entry_ref with another entry_ref, returning true if they are equal. + \return + - \c true - The entry_refs are equal + - \c false - The entry_refs are not equal +*/ +bool +entry_ref::operator==(const entry_ref &ref) const +{ + return (device == ref.device + && directory == ref.directory + && (name == ref.name + || name != NULL && ref.name != NULL + && strcmp(name, ref.name) == 0)); +} + +/*! \brief Compares the entry_ref with another entry_ref, returning true if they are not equal. + \return + - \c true - The entry_refs are not equal + - \c false - The entry_refs are equal +*/ +bool +entry_ref::operator!=(const entry_ref &ref) const +{ + return !(*this == ref); +} + +/*! \brief Makes the entry_ref a copy of the entry_ref specified by \a ref. + \param ref the entry_ref to copy + \return + - A reference to the copy +*/ +entry_ref& +entry_ref::operator=(const entry_ref &ref) +{ + if (this == &ref) + return *this; + + device = ref.device; + directory = ref.directory; + set_name(ref.name); + return *this; +} + +/*! + \var dev_t entry_ref::device + \brief The device id of the storage device on which the entry resides + +*/ + +/*! + \var ino_t entry_ref::directory + \brief The inode number of the directory in which the entry resides +*/ + +/*! + \var char *entry_ref::name + \brief The leaf name of the entry +*/ + + +//---------------------------------------------------------------------------- +// BEntry +//---------------------------------------------------------------------------- + +/*! + \class BEntry + \brief A location in the filesystem + + The BEntry class defines objects that represent "locations" in the file system + hierarchy. Each location (or entry) is given as a name within a directory. For + example, when you create a BEntry thus: + + \code + BEntry entry("/boot/home/fido"); + \endcode + + ...you're telling the BEntry object to represent the location of the file + called fido within the directory \c "/boot/home". + + \author Ingo Weinhold + \author Tyler Dauwalder + \author Simon Cusack + + \version 0.0.0 +*/ + +//! Creates an uninitialized BEntry object. +/*! Should be followed by a call to one of the SetTo functions, + or an assignment: + - SetTo(const BDirectory*, const char*, bool) + - SetTo(const entry_ref*, bool) + - SetTo(const char*, bool) + - operator=(const BEntry&) +*/ +BEntry::BEntry() + : fDirFd(StorageKit::NullFd), + fName(NULL), + fCStatus(B_NO_INIT) +{ +} + +//! Creates a BEntry initialized to the given directory and path combination. +/*! If traverse is true and \c dir/path refers to a symlink, the BEntry will + refer to the linked file; if false, the BEntry will refer to the symlink itself. + + \param dir directory in which \a path resides + \param path relative path reckoned off of \a dir + \param traverse whether or not to traverse symlinks + \see SetTo(const BDirectory*, const char *, bool) + +*/ +BEntry::BEntry(const BDirectory *dir, const char *path, bool traverse) + : fDirFd(StorageKit::NullFd), + fName(NULL), + fCStatus(B_NO_INIT) +{ + SetTo(dir, path, traverse); +} + +//! Creates a BEntry for the file referred to by the given entry_ref. +/*! If traverse is true and \a ref refers to a symlink, the BEntry + will refer to the linked file; if false, the BEntry will refer + to the symlink itself. + + \param ref the entry_ref referring to the given file + \param traverse whether or not symlinks are to be traversed + \see SetTo(const entry_ref*, bool) +*/ + +BEntry::BEntry(const entry_ref *ref, bool traverse) + : fDirFd(StorageKit::NullFd), + fName(NULL), + fCStatus(B_NO_INIT) +{ + SetTo(ref, traverse); +} + +//! Creates a BEntry initialized to the given path. +/*! If \a path is relative, it will + be reckoned off the current working directory. If \a path refers to a symlink and + traverse is true, the BEntry will refer to the linked file. If traverse is false, + the BEntry will refer to the symlink itself. + + \param path the file of interest + \param traverse whether or not symlinks are to be traversed + \see SetTo(const char*, bool) + +*/ +BEntry::BEntry(const char *path, bool traverse) + : fDirFd(StorageKit::NullFd), + fName(NULL), + fCStatus(B_NO_INIT) +{ + SetTo(path, traverse); +} + +//! Creates a copy of the given BEntry. +/*! \param entry the entry to be copied + \see operator=(const BEntry&) +*/ +BEntry::BEntry(const BEntry &entry) + : fDirFd(StorageKit::NullFd), + fName(NULL), + fCStatus(B_NO_INIT) +{ + *this = entry; +} + +//! Frees all of the BEntry's allocated resources. +/*! \see Unset() +*/ +BEntry::~BEntry() +{ + Unset(); +} + +//! Returns the result of the most recent construction or SetTo() call. +/*! \return + - \c B_OK Success + - \c B_NO_INIT The object has been Unset() or is uninitialized + - some error code +*/ +status_t +BEntry::InitCheck() const +{ + return fCStatus; +} + +//! Returns true if the Entry exists in the filesytem, false otherwise. +/*! \return + - \c true - The entry exists + - \c false - The entry does not exist +*/ +bool +BEntry::Exists() const +{ + if (fCStatus != B_OK) + return false; + + // Attempt to find the entry in our current directory + StorageKit::LongDirEntry entry; + return StorageKit::find_dir(fDirFd, fName, &entry, sizeof(entry)) == B_OK; +} + +/*! \brief Fills in a stat structure for the entry. The information is copied into + the \c stat structure pointed to by \a result. + + \b NOTE: The BStatable object does not cache the stat structure; every time you + call GetStat(), fresh stat information is retrieved. + + \param result pointer to a pre-allocated structure into which the stat information will be copied + \return + - \c B_OK - Success + - "error code" - Failure +*/ +status_t +BEntry::GetStat(struct stat *result) const +{ + if (fCStatus != B_OK) + return B_NO_INIT; + + entry_ref ref; + status_t status = GetRef(&ref); + if (status != B_OK) + return status; + + return StorageKit::get_stat(ref, result); +} + +/*! \brief Reinitializes the BEntry to the path or directory path combination, + resolving symlinks if traverse is true + + \return + - \c B_OK - Success + - "error code" - Failure + + \todo Reimplement! Concatenating dir and leaf to an absolute path prevents + the user from accessing entries with longer absolute path. + R5 handles this without problems. +*/ +status_t +BEntry::SetTo(const BDirectory *dir, const char *path, bool traverse) +{ + Unset(); + if (dir == NULL) + return (fCStatus = B_BAD_VALUE); + + fCStatus = B_OK; + if (StorageKit::is_absolute_path(path)) { + SetTo(path, traverse); + } else { + if (dir->InitCheck() != B_OK) + fCStatus = B_BAD_VALUE; + // get the dir's path + char rootPath[B_PATH_NAME_LENGTH + 1]; + if (fCStatus == B_OK) { + fCStatus = StorageKit::dir_to_path(dir->get_fd(), rootPath, + B_PATH_NAME_LENGTH + 1); + } + // Concatenate our two path strings together + if (fCStatus == B_OK && path) { + // The concatenated strings must fit into our buffer. + if (strlen(rootPath) + strlen(path) + 2 > B_PATH_NAME_LENGTH + 1) + fCStatus = B_NAME_TOO_LONG; + else { + strcat(rootPath, "/"); + strcat(rootPath, path); + } + } + // set the resulting path + if (fCStatus == B_OK) + SetTo(rootPath, traverse); + } + return fCStatus; +} + +/*! \brief Reinitializes the BEntry to the entry_ref, resolving symlinks if + traverse is true + + \return + - \c B_OK - Success + - "error code" - Failure + + \todo Implemented using entry_ref_to_path(). Reimplement! +*/ +status_t +BEntry::SetTo(const entry_ref *ref, bool traverse) +{ + Unset(); + if (ref == NULL) { + return (fCStatus = B_BAD_VALUE); + } + + char path[B_PATH_NAME_LENGTH + 1]; + + fCStatus = StorageKit::entry_ref_to_path(ref, path, + B_PATH_NAME_LENGTH + 1); + return (fCStatus == B_OK) ? SetTo(path, traverse) : fCStatus ; +} + +/*! \brief Reinitializes the BEntry object to the path, resolving symlinks if + traverse is true + + \return + - \c B_OK - Success + - "error code" - Failure + +*/ +status_t +BEntry::SetTo(const char *path, bool traverse) +{ + Unset(); + // check the argument + fCStatus = (path ? B_OK : B_BAD_VALUE); + if (fCStatus == B_OK) + fCStatus = StorageKit::check_path_name(path); + if (fCStatus == B_OK) { + // Get the path and leaf portions of the given path + char *pathStr, *leafStr; + pathStr = leafStr = NULL; + fCStatus = StorageKit::split_path(path, pathStr, leafStr); + if (fCStatus == B_OK) { + // Open the directory + StorageKit::FileDescriptor dirFd; + fCStatus = StorageKit::open_dir(pathStr, dirFd); + if (fCStatus == B_OK) { + fCStatus = set(dirFd, leafStr, traverse); + if (fCStatus != B_OK) + StorageKit::close_dir(dirFd); + } + } + delete [] pathStr; + delete [] leafStr; + } + return fCStatus; +} + +/*! \brief Reinitializes the BEntry to an uninitialized BEntry object */ +void +BEntry::Unset() +{ + // Close the directory + if (fDirFd != StorageKit::NullFd) { + StorageKit::close_dir(fDirFd); + } + + // Free our leaf name + if (fName != NULL) { + delete [] fName; + } + + fDirFd = StorageKit::NullFd; + fName = NULL; + fCStatus = B_NO_INIT; +} + +/*! \brief Gets an entry_ref structure for the BEntry. + + \param ref pointer to a preallocated entry_ref into which the result is copied + \return + - \c B_OK - Success + - "error code" - Failure + + */ +status_t +BEntry::GetRef(entry_ref *ref) const +{ + if (fCStatus != B_OK) + return B_NO_INIT; + + if (ref == NULL) + return B_BAD_VALUE; + + struct stat st; + status_t error = StorageKit::get_stat(fDirFd, &st); + if (error == B_OK) { + ref->device = st.st_dev; + ref->directory = st.st_ino; + error = ref->set_name(fName); + } + return error; +} + +/*! \brief Gets the path for the BEntry. + + \param path pointer to a pre-allocated BPath object into which the result is stored + \return + - \c B_OK - Success + - "error code" - Failure + +*/ +status_t +BEntry::GetPath(BPath *path) const +{ + if (fCStatus != B_OK) + return B_NO_INIT; + + if (path == NULL) + return B_BAD_VALUE; + + entry_ref ref; + status_t status; + + status = GetRef(&ref); + if (status != B_OK) + return status; + + return path->SetTo(&ref); +} + +/*! \brief Gets the parent of the BEntry as another BEntry. + + If the function fails, the argument is Unset(). Destructive calls to GetParent() are + allowed, i.e.: + + \code + BEntry entry("/boot/home/fido"); + status_t err; + char name[B_FILE_NAME_LENGTH]; + + // Spit out the path components backwards, one at a time. + do { + entry.GetName(name); + printf("> %s\n", name); + } while ((err=entry.GetParent(&entry)) == B_OK); + + // Complain for reasons other than reaching the top. + if (err != B_ENTRY_NOT_FOUND) + printf(">> Error: %s\n", strerror(err)); + \endcode + + will output: + + \code + > fido + > home + > boot + > . + \endcode + + \param entry pointer to a pre-allocated BEntry object into which the result is stored + \return + - \c B_OK - Success + - \c B_ENTRY_NOT_FOUND - Attempted to get the parent of the root directory \c "/" + - "error code" - Failure + +*/ +status_t BEntry::GetParent(BEntry *entry) const +{ + if (fCStatus != B_OK) + return B_NO_INIT; + + if (entry == NULL) + return B_BAD_VALUE; + + // Convert ourselves to a entry_ref and change the + // leaf name to "." + + entry_ref ref; + status_t status; + + status = GetRef(&ref); + if (status == B_OK) { + + // Verify we aren't an entry representing "/" + status = StorageKit::entry_ref_is_root_dir(ref) ? B_ENTRY_NOT_FOUND + : B_OK ; + if (status == B_OK) { + + status = ref.set_name("."); + if (status == B_OK) { + + entry->SetTo(&ref); + return entry->InitCheck(); + + } + } + } + + // If we get this far, an error occured, so we Unset() the + // argument as dictated by the BeBook + entry->Unset(); + return status; +} + +/*! \brief Gets the parent of the BEntry as a BDirectory. + + If the function fails, the argument is Unset(). + + \param dir pointer to a pre-allocated BDirectory object into which the result is stored + \return + - \c B_OK - Success + - \c B_ENTRY_NOT_FOUND - Attempted to get the parent of the root directory \c "/" + - "error code" - Failure + +*/ +status_t +BEntry::GetParent(BDirectory *dir) const +{ + if (fCStatus != B_OK) + return B_NO_INIT; + + if (dir == NULL) + return B_BAD_VALUE; + + entry_ref ref; + status_t status; + + status = GetRef(&ref); + if (status == B_OK) { + + // Verify we aren't an entry representing "/" + status = StorageKit::entry_ref_is_root_dir(ref) ? B_ENTRY_NOT_FOUND : B_OK ; + if (status == B_OK) { + + // Now point the entry_ref to the parent directory (instead of ourselves) + status = ref.set_name("."); + if (status == B_OK) { + dir->SetTo(&ref); + return dir->InitCheck(); + } + } + } + + // If we get this far, an error occured, so we Unset() the + // argument as dictated by the BeBook + dir->Unset(); + return status; +} + +/*! \brief Gets the name of the entry's leaf. + + \c buffer must be pre-allocated and of sufficient + length to hold the entire string. A length of \c B_FILE_NAME_LENGTH+1 is recommended. + + \param buffer pointer to a pre-allocated string into which the result is copied + \return + - \c B_OK - Success + - "error code" - Failure + +*/ +status_t +BEntry::GetName(char *buffer) const +{ + status_t result = B_ERROR; + + if (fCStatus != B_OK) { + result = B_NO_INIT; + } else if (buffer == NULL) { + result = B_BAD_VALUE; + } else { + strcpy(buffer, fName); + result = B_OK; + } + + return result; +} + +/*! \brief Renames the BEntry to path, replacing an existing entry if clobber is true. + + NOTE: The BEntry must refer to an existing file. If it is abstract, this method will fail. + + \param path Pointer to a string containing the new name for the entry. May + be absolute or relative. If relative, the entry is renamed within its + current directory. + \param clobber If \c false and a file with the name given by \c path already exists, + the method will fail. If \c true and such a file exists, it will + be overwritten. + \return + - \c B_OK - Success + - \c B_ENTRY_EXISTS - The new location is already taken and \c clobber was \c false + - \c B_ENTRY_NOT_FOUND - Attempted to rename an abstract entry + - "error code" - Failure + +*/ +status_t +BEntry::Rename(const char *path, bool clobber) +{ + if (path == NULL) + return B_BAD_VALUE; + if (fCStatus != B_OK) + return B_NO_INIT; + + status_t status = B_OK; + // Convert the given path to an absolute path, if it isn't already. + char fullPath[B_PATH_NAME_LENGTH + 1]; + if (!StorageKit::is_absolute_path(path)) { + // Convert our directory to an absolute pathname + status = StorageKit::dir_to_path(fDirFd, fullPath, + B_PATH_NAME_LENGTH + 1); + if (status == B_OK) { + // Concatenate our pathname to it + strcat(fullPath, "/"); + strcat(fullPath, path); + path = fullPath; + } + } + // Check, whether the file does already exist, if clobber is false. + if (status == B_OK && !clobber) { + // We're not supposed to kill an already-existing file, + // so we'll try to figure out if it exists by stat()ing it. + StorageKit::Stat s; + status = StorageKit::get_stat(path, &s); + if (status == B_OK) + status = B_FILE_EXISTS; + else if (status == B_ENTRY_NOT_FOUND) + status = B_OK; + } + // Turn ourselves into a pathname, rename ourselves + if (status == B_OK) { + BPath oldPath; + status = GetPath(&oldPath); + if (status == B_OK) { + status = StorageKit::rename(oldPath.Path(), path); + if (status == B_OK) + status = SetTo(path, false); + } + } + return status; +} + +/*! \brief Moves the BEntry to directory or directory+path combination, replacing an existing entry if clobber is true. + + NOTE: The BEntry must refer to an existing file. If it is abstract, this method will fail. + + \param dir Pointer to a pre-allocated BDirectory into which the entry should be moved. + \param path Optional new leaf name for the entry. May be a simple leaf or a relative path; + either way, \c path is reckoned off of \c dir. If \c NULL, the entry retains + its previous leaf name. + \param clobber If \c false and an entry already exists at the specified destination, + the method will fail. If \c true and such an entry exists, it will + be overwritten. + \return + - \c B_OK - Success + - \c B_ENTRY_EXISTS - The new location is already taken and \c clobber was \c false + - \c B_ENTRY_NOT_FOUND - Attempted to move an abstract entry + - "error code" - Failure + + +*/ +status_t +BEntry::MoveTo(BDirectory *dir, const char *path = NULL, bool clobber) +{ + if (fCStatus != B_OK) + return B_NO_INIT; + else if (dir == NULL) + return B_BAD_VALUE; + else if (dir->InitCheck() != B_OK) + return B_BAD_VALUE; + + // NULL path simply means move without renaming + if (path == NULL) + path = fName; + + status_t status = B_OK; + // Determine the absolute path of the target entry. + if (!StorageKit::is_absolute_path(path)) { + // Convert our directory to an absolute pathname + char fullPath[B_PATH_NAME_LENGTH + 1]; + status = StorageKit::dir_to_path(dir->get_fd(), fullPath, + B_PATH_NAME_LENGTH + 1); + // Concatenate our pathname to it + if (status == B_OK) { + strcat(fullPath, "/"); + strcat(fullPath, path); + path = fullPath; + } + } + // Now let rename do the dirty work + if (status == B_OK) + status = Rename(path, clobber); + return status; +} + +/*! \brief Removes the entry from the file system. + + NOTE: If any file descriptors are open on the file when Remove() is called, + the chunk of data they refer to will continue to exist until all such file + descriptors are closed. The BEntry object, however, becomes abstract and + no longer refers to any actual data in the filesystem. + + \return + - B_OK - Success + - "error code" - Failure + +*/ +status_t +BEntry::Remove() +{ + if (fCStatus != B_OK) + return B_NO_INIT; + + BPath path; + status_t status; + + status = GetPath(&path); + if (status != B_OK) + return status; + + return StorageKit::remove(path.Path()); +} + + +/*! \brief Returns true if the BEntry and \c item refer to the same entry or + if they are both uninitialized. + + \return + - true - Both BEntry objects refer to the same entry or they are both uninitialzed + - false - The BEntry objects refer to different entries + + */ +bool +BEntry::operator==(const BEntry &item) const +{ + // First check statuses + if (this->InitCheck() != B_OK && item.InitCheck() != B_OK) { + return true; + } else if (this->InitCheck() == B_OK && item.InitCheck() == B_OK) { + + // Directories don't compare well directly, so we'll + // compare entry_refs instead + entry_ref ref1, ref2; + if (this->GetRef(&ref1) != B_OK) + return false; + if (item.GetRef(&ref2) != B_OK) + return false; + return (ref1 == ref2); + + } else { + return false; + } + +} + +/*! \brief Returns false if the BEntry and \c item refer to the same entry or + if they are both uninitialized. + + \return + - true - The BEntry objects refer to different entries + - false - Both BEntry objects refer to the same entry or they are both uninitialzed + + */ +bool +BEntry::operator!=(const BEntry &item) const +{ + return !(*this == item); +} + +/*! \brief Reinitializes the BEntry to be a copy of the argument + + \return + - A reference to the copy + +*/ +BEntry& +BEntry::operator=(const BEntry &item) +{ + if (this == &item) + return *this; + + Unset(); + if (item.fCStatus == B_OK) { + fCStatus = StorageKit::dup_dir(item.fDirFd, fDirFd); + if (fCStatus == B_OK) { + fCStatus = set_name(item.fName); + } + } + + return *this; +} + +/*! Reserved for future use. */ +void BEntry::_PennyEntry1(){} +/*! Reserved for future use. */ +void BEntry::_PennyEntry2(){} +/*! Reserved for future use. */ +void BEntry::_PennyEntry3(){} +/*! Reserved for future use. */ +void BEntry::_PennyEntry4(){} +/*! Reserved for future use. */ +void BEntry::_PennyEntry5(){} +/*! Reserved for future use. */ +void BEntry::_PennyEntry6(){} + +/*! \brief Updates the BEntry with the data from the stat structure according to the mask. +*/ +status_t +BEntry::set_stat(struct stat &st, uint32 what) +{ + if (fCStatus != B_OK) + return B_FILE_ERROR; + + BPath path; + status_t status; + + status = GetPath(&path); + if (status != B_OK) + return status; + + return StorageKit::set_stat(path.Path(), st, what); +} + +/*! Sets the Entry to point to the entry named by \c leaf in the given directory. If \c traverse + is \c true and the given entry is a symlink, the object is recursively set to point to the + entry pointed to by the symlink. + + \c leaf must be a leaf-name only (i.e. it must contain no '/' characters), + otherwise this function will return \c B_BAD_VALUE. If \c B_OK is returned, + the caller is no longer responsible for closing the directory file descriptor + with a call to StorageKit::close_dir. + + \param dirFd File descriptor of the directory in which the entry resides + \param leaf Pointer to a string containing the entry's leaf name + \param traverse If \c true and the given entry is a symlink, the object is recursively + set to point to the entry linked to by the symlink. + \return + - B_OK - Success + - "error code" - Failure + +*/ +status_t +BEntry::set(StorageKit::FileDescriptor dirFd, const char *leaf, bool traverse) +{ + // Verify that path is valid + status_t error = StorageKit::check_entry_name(leaf); + if (error != B_OK) + return error; + // Check whether the entry is abstract or concrete. + // We try traversing concrete entries only. + StorageKit::LongDirEntry dirEntry; + bool isConcrete = (StorageKit::find_dir(dirFd, leaf, &dirEntry, + sizeof(dirEntry)) == B_OK); + if (traverse && isConcrete) { + // Though the link traversing strategy is iterative, we introduce + // some recursion, since we are using BSymLink, which may be + // (currently is) implemented using BEntry. Nevertheless this is + // harmless, because BSymLink does, of course, not want to traverse + // the link. + + // convert the dir FD into a BPath + entry_ref ref; + error = StorageKit::dir_to_self_entry_ref(dirFd, &ref); + char dirPathname[B_PATH_NAME_LENGTH + 1]; + if (error == B_OK) { + error = StorageKit::entry_ref_to_path(&ref, dirPathname, + sizeof(dirPathname)); + } + BPath dirPath(dirPathname); + if (error == B_OK) + error = dirPath.InitCheck(); + BPath linkPath; + if (error == B_OK) + linkPath.SetTo(dirPath.Path(), leaf); + if (error == B_OK) { + // Here comes the link traversing loop: A BSymLink is created + // from the dir and the leaf name, the link target is determined, + // the target's dir and leaf name are got and so on. + bool isLink = true; + int32 linkLimit = B_MAX_SYMLINKS; + while (error == B_OK && isLink && linkLimit > 0) { + linkLimit--; + // that's OK with any node, even if it's not a symlink + BSymLink link(linkPath.Path()); + error = link.InitCheck(); + if (error == B_OK) { + isLink = link.IsSymLink(); + if (isLink) { + // get the path to the link target + ssize_t linkSize = link.MakeLinkedPath(dirPath.Path(), + &linkPath); + if (linkSize < 0) + error = linkSize; + // get the link target's dir path + if (error == B_OK) + error = linkPath.GetParent(&dirPath); + } + } + } + // set the new values + if (error == B_OK) { + if (isLink) + error = B_LINK_LIMIT; + else { + StorageKit::FileDescriptor newDirFd = StorageKit::NullFd; + error = StorageKit::open_dir(dirPath.Path(), newDirFd); + if (error == B_OK) { + // If we are successful, we are responsible for the + // supplied FD. Thus we close it. + StorageKit::close_dir(dirFd); + dirFd = StorageKit::NullFd; + fDirFd = newDirFd; + // handle "/", which has a "" Leaf() + if (linkPath == "/") + set_name("."); + else + set_name(linkPath.Leaf()); + } + } + } + } // getting the dir path for the FD + } else { + // don't traverse: either the flag is not set or the entry is abstract + fDirFd = dirFd; + set_name(leaf); + } + return error; +} + +/*! \brief Handles string allocation, deallocation, and copying for the entry's leaf name. + + \return + - B_OK - Success + - "error code" - Failure +*/ +status_t +BEntry::set_name(const char *name) +{ + if (name == NULL) + return B_BAD_VALUE; + + if (fName != NULL) { + delete [] fName; + } + + fName = new(nothrow) char[strlen(name)+1]; + if (fName == NULL) + return B_NO_MEMORY; + + strcpy(fName, name); + + return B_OK; +} + + +/*! Debugging function, dumps the given entry to stdout. This function is not part of + the R5 implementation, and thus calls to it will mean you can't link with the + R5 Storage Kit. + + \param name Pointer to a string to be printed along with the dump for identification + purposes. + + */ +void +BEntry::Dump(const char *name) +{ + if (name != NULL) { + printf("------------------------------------------------------------\n"); + printf("%s\n", name); + printf("------------------------------------------------------------\n"); + } + + printf("fCStatus == %ld\n", fCStatus); + + StorageKit::LongDirEntry entry; + if (fDirFd != -1 + && StorageKit::find_dir(fDirFd, ".", &entry, sizeof(entry)) == B_OK) { + printf("dir.device == %ld\n", entry.d_pdev); + printf("dir.inode == %lld\n", entry.d_pino); + } else { + printf("dir == NullFd\n"); + } + + printf("leaf == '%s'\n", fName); + printf("\n"); + +} + +// get_ref_for_path +/*! \brief Returns an entry_ref for a given path. + \param path The path name referring to the entry + \param ref The entry_ref structure to be filled in + \return + - \c B_OK - Everything went fine. + - \c B_BAD_VALUE - \c NULL \a path or \a ref. + - \c B_ENTRY_NOT_FOUND - A (non-leaf) path component does not exist. + - \c B_NO_MEMORY - Insufficient memory for successful completion. +*/ +status_t +get_ref_for_path(const char *path, entry_ref *ref) +{ + status_t error = (path && ref ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + BEntry entry(path); + error = entry.InitCheck(); + if (error == B_OK) + error = entry.GetRef(ref); + } + return error; +} + +// < +/*! \brief Returns whether an entry is less than another. + The components are compared in order \c device, \c directory, \c name. + A \c NULL \c name is less than any non-null name. + + \return + - true - a < b + - false - a >= b +*/ +bool +operator<(const entry_ref & a, const entry_ref & b) +{ + return (a.device < b.device + || (a.device == b.device + && (a.directory < b.directory + || (a.directory == b.directory + && (a.name == NULL && b.name != NULL + || (a.name != NULL && b.name != NULL + && strcmp(a.name, b.name) < 0)))))); +} + diff --git a/src/kits/storage/EntryList.cpp b/src/kits/storage/EntryList.cpp new file mode 100644 index 0000000000..7555e71ccb --- /dev/null +++ b/src/kits/storage/EntryList.cpp @@ -0,0 +1,107 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file EntryList.cpp + BEntryList implementation. +*/ + +#include + +// constructor +//! Creates a BEntryList. +/*! Does nothing at this time. +*/ +BEntryList::BEntryList() +{ +} + +// destructor +//! Frees all resources associated with this BEntryList. +/*! Does nothing at this time. +*/ +BEntryList::~BEntryList() +{ +} + +// GetNextEntry +/*! \fn status_t BEntryList::GetNextEntry(BEntry *entry, bool traverse) + \brief Returns the BEntryList's next entry as a BEntry. + Places the next entry in the list in \a entry, traversing symlinks if + \a traverse is \c true. + \param entry a pointer to a BEntry to be initialized with the found entry + \param traverse specifies whether to follow it, if the found entry + is a symbolic link. + \note The iterator used by this method is the same one used by + GetNextRef(), GetNextDirents(), Rewind() and CountEntries(). + \return + - \c B_OK if successful, + - \c B_ENTRY_NOT_FOUND when at the end of the list, + - another error code (depending on the implementation of the derived class) + if an error occured. +*/ + +// GetNextRef +/*! \fn status_t BEntryList::GetNextRef(entry_ref *ref) + \brief Returns the BEntryList's next entry as an entry_ref. + Places an entry_ref to the next entry in the list into \a ref. + \param ref a pointer to an entry_ref to be filled in with the data of the + found entry + \note The iterator used by this method is the same one used by + GetNextEntry(), GetNextDirents(), Rewind() and CountEntries(). + \return + - \c B_OK if successful, + - \c B_ENTRY_NOT_FOUND when at the end of the list, + - another error code (depending on the implementation of the derived class) + if an error occured. +*/ + +// GetNextDirents +/*! \fn int32 BEntryList::GetNextDirents(struct dirent *buf, size_t length, int32 count) + \brief Returns the BEntryList's next entries as dirent structures. + Reads a number of entries into the array of dirent structures pointed to by + \a buf. Reads as many but no more than \a count entries, as many entries as + remain, or as many entries as will fit into the array at \a buf with given + length \a length (in bytes), whichever is smallest. + \param buf a pointer to a buffer to be filled with dirent structures of + the found entries + \param length the maximal number of entries to be read. + \note The iterator used by this method is the same one used by + GetNextEntry(), GetNextRef(), Rewind() and CountEntries(). + \return + - The number of dirent structures stored in the buffer, 0 when there are + no more entries to be read. + - an error code (depending on the implementation of the derived class) + if an error occured. +*/ + +// Rewind +/*! \fn status_t BEntryList::Rewind() + \brief Rewinds the list pointer to the beginning of the list. + \return + - \c B_OK if successful, + - an error code (depending on the implementation of the derived class) + if an error occured. +*/ + +// CountEntries +/*! \fn int32 BEntryList::CountEntries() + \brief Returns the number of entries in the list + \return + - the number of entries in the list, + - an error code (depending on the implementation of the derived class) + if an error occured. +*/ + + +/*! Currently unused */ +void BEntryList::_ReservedEntryList1() {} +void BEntryList::_ReservedEntryList2() {} +void BEntryList::_ReservedEntryList3() {} +void BEntryList::_ReservedEntryList4() {} +void BEntryList::_ReservedEntryList5() {} +void BEntryList::_ReservedEntryList6() {} +void BEntryList::_ReservedEntryList7() {} +void BEntryList::_ReservedEntryList8() {} + diff --git a/src/kits/storage/File.cpp b/src/kits/storage/File.cpp new file mode 100644 index 0000000000..3895bc8ba2 --- /dev/null +++ b/src/kits/storage/File.cpp @@ -0,0 +1,525 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file File.cpp + BFile implementation. +*/ + +#include + +#include +#include +#include "kernel_interface.h" + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS { +#endif + +// constructor +//! Creates an uninitialized BFile. +BFile::BFile() + : BNode(), + BPositionIO(), + fMode(0) +{ +} + +// copy constructor +//! Creates a copy of the supplied BFile. +/*! If \a file is uninitialized, the newly constructed BFile will be, too. + \param file the BFile object to be copied +*/ +BFile::BFile(const BFile &file) + : BNode(), + BPositionIO(), + fMode(0) +{ + *this = file; +} + +// constructor +/*! \brief Creates a BFile and initializes it to the file referred to by + the supplied entry_ref and according to the specified open mode. + \param ref the entry_ref referring to the file + \param openMode the mode in which the file should be opened + \see SetTo() for values for \a openMode +*/ +BFile::BFile(const entry_ref *ref, uint32 openMode) + : BNode(), + BPositionIO(), + fMode(0) +{ + SetTo(ref, openMode); +} + +// constructor +/*! \brief Creates a BFile and initializes it to the file referred to by + the supplied BEntry and according to the specified open mode. + \param entry the BEntry referring to the file + \param openMode the mode in which the file should be opened + \see SetTo() for values for \a openMode +*/ +BFile::BFile(const BEntry *entry, uint32 openMode) + : BNode(), + BPositionIO(), + fMode(0) +{ + SetTo(entry, openMode); +} + +// constructor +/*! \brief Creates a BFile and initializes it to the file referred to by + the supplied path name and according to the specified open mode. + \param path the file's path name + \param openMode the mode in which the file should be opened + \see SetTo() for values for \a openMode +*/ +BFile::BFile(const char *path, uint32 openMode) + : BNode(), + BPositionIO(), + fMode(0) +{ + SetTo(path, openMode); +} + +// constructor +/*! \brief Creates a BFile and initializes it to the file referred to by + the supplied path name relative to the specified BDirectory and + according to the specified open mode. + \param dir the BDirectory, relative to which the file's path name is + given + \param path the file's path name relative to \a dir + \param openMode the mode in which the file should be opened + \see SetTo() for values for \a openMode +*/ +BFile::BFile(BDirectory *dir, const char *path, uint32 openMode) + : BNode(), + BPositionIO(), + fMode(0) +{ + SetTo(dir, path, openMode); +} + +// destructor +//! Frees all allocated resources. +/*! If the file is properly initialized, the file's file descriptor is closed. +*/ +BFile::~BFile() +{ + // Also called by the BNode destructor, but we rather try to avoid + // problems with calling virtual functions in the base class destructor. + // Depending on the compiler implementation an object may be degraded to + // an object of the base class after the destructor of the derived class + // has been executed. + close_fd(); +} + +// SetTo +/*! \brief Re-initializes the BFile to the file referred to by the + supplied entry_ref and according to the specified open mode. + \param ref the entry_ref referring to the file + \param openMode the mode in which the file should be opened + \a openMode must be a bitwise or of exactly one of the flags + - \c B_READ_ONLY: The file is opened read only. + - \c B_WRITE_ONLY: The file is opened write only. + - \c B_READ_WRITE: The file is opened for random read/write access. + and any number of the flags + - \c B_CREATE_FILE: A new file will be created, if it does not already + exist. + - \c B_FAIL_IF_EXISTS: If the file does already exist and B_CREATE_FILE is + set, SetTo() fails. + - \c B_ERASE_FILE: An already existing file is truncated to zero size. + - \c B_OPEN_AT_END: Seek() to the end of the file after opening. + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a ref or bad \a openMode. + - \c B_ENTRY_NOT_FOUND: File not found or failed to create file. + - \c B_FILE_EXISTS: File exists and \c B_FAIL_IF_EXISTS was passed. + - \c B_PERMISSION_DENIED: File permissions didn't allow operation. + - \c B_NO_MEMORY: Insufficient memory for operation. + - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. + - \c B_BUSY: A node was busy. + - \c B_FILE_ERROR: A general file error. + - \c B_NO_MORE_FDS: The application has run out of file descriptors. + \todo Currently implemented using StorageKit::entry_ref_to_path(). + Reimplement! +*/ +status_t +BFile::SetTo(const entry_ref *ref, uint32 openMode) +{ + Unset(); + char path[B_PATH_NAME_LENGTH + 1]; + status_t error = (ref ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + error = StorageKit::entry_ref_to_path(ref, path, + B_PATH_NAME_LENGTH + 1); + } + if (error == B_OK) + error = SetTo(path, openMode); + set_status(error); + return error; +} + +// SetTo +/*! \brief Re-initializes the BFile to the file referred to by the + supplied BEntry and according to the specified open mode. + \param entry the BEntry referring to the file + \param openMode the mode in which the file should be opened + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a entry or bad \a openMode. + - \c B_ENTRY_NOT_FOUND: File not found or failed to create file. + - \c B_FILE_EXISTS: File exists and \c B_FAIL_IF_EXISTS was passed. + - \c B_PERMISSION_DENIED: File permissions didn't allow operation. + - \c B_NO_MEMORY: Insufficient memory for operation. + - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. + - \c B_BUSY: A node was busy. + - \c B_FILE_ERROR: A general file error. + - \c B_NO_MORE_FDS: The application has run out of file descriptors. + \todo Implemented using SetTo(entry_ref*, uint32). Check, if necessary + to reimplement! +*/ +status_t +BFile::SetTo(const BEntry *entry, uint32 openMode) +{ + Unset(); + entry_ref ref; + status_t error = (entry ? B_OK : B_BAD_VALUE); + if (error == B_OK) + error = entry->GetRef(&ref); + if (error == B_OK) + error = SetTo(&ref, openMode); + set_status(error); + return error; +} + +// SetTo +/*! \brief Re-initializes the BFile to the file referred to by the + supplied path name and according to the specified open mode. + \param path the file's path name + \param openMode the mode in which the file should be opened + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a path or bad \a openMode. + - \c B_ENTRY_NOT_FOUND: File not found or failed to create file. + - \c B_FILE_EXISTS: File exists and \c B_FAIL_IF_EXISTS was passed. + - \c B_PERMISSION_DENIED: File permissions didn't allow operation. + - \c B_NO_MEMORY: Insufficient memory for operation. + - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. + - \c B_BUSY: A node was busy. + - \c B_FILE_ERROR: A general file error. + - \c B_NO_MORE_FDS: The application has run out of file descriptors. +*/ +status_t +BFile::SetTo(const char *path, uint32 openMode) +{ + Unset(); + status_t result = B_OK; + StorageKit::FileDescriptor newFd = StorageKit::NullFd; + if (path) { + // analyze openMode + // Well, it's a bit schizophrenic to convert the B_* style openMode + // to POSIX style openFlags, but to use O_RWMASK to filter openMode. + StorageKit::OpenFlags openFlags; + switch (openMode & O_RWMASK) { + case B_READ_ONLY: + openFlags = O_RDONLY; + break; + case B_WRITE_ONLY: + openFlags = O_WRONLY; + break; + case B_READ_WRITE: + openFlags = O_RDWR; + break; + default: + result = B_BAD_VALUE; + break; + } + if (result == B_OK) { + if (openMode & B_ERASE_FILE) + openFlags |= O_TRUNC; + if (openMode & B_OPEN_AT_END) + openFlags |= O_APPEND; + if (openMode & B_CREATE_FILE) { + openFlags |= O_CREAT; + if (openMode & B_FAIL_IF_EXISTS) + openFlags |= O_EXCL; + result = StorageKit::open(path, openFlags, S_IREAD | S_IWRITE, + newFd); + } else + result = StorageKit::open(path, openFlags, newFd); + if (result == B_OK) + fMode = openFlags; + } + } else + result = B_BAD_VALUE; + // set the new file descriptor + if (result == B_OK) { + result = set_fd(newFd); + if (result != B_OK) + StorageKit::close(newFd); + } + // finally set the BNode status + set_status(result); + return result; +} + +// SetTo +/*! \brief Re-initializes the BFile to the file referred to by the + supplied path name relative to the specified BDirectory and + according to the specified open mode. + \param dir the BDirectory, relative to which the file's path name is + given + \param path the file's path name relative to \a dir + \param openMode the mode in which the file should be opened + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a dir or \a path or bad \a openMode. + - \c B_ENTRY_NOT_FOUND: File not found or failed to create file. + - \c B_FILE_EXISTS: File exists and \c B_FAIL_IF_EXISTS was passed. + - \c B_PERMISSION_DENIED: File permissions didn't allow operation. + - \c B_NO_MEMORY: Insufficient memory for operation. + - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. + - \c B_BUSY: A node was busy. + - \c B_FILE_ERROR: A general file error. + - \c B_NO_MORE_FDS: The application has run out of file descriptors. + \todo Implemented using SetTo(BEntry*, uint32). Check, if necessary + to reimplement! +*/ +status_t +BFile::SetTo(const BDirectory *dir, const char *path, uint32 openMode) +{ + Unset(); + status_t error = (dir && path ? B_OK : B_BAD_VALUE); + BEntry entry; + if (error == B_OK) + error = entry.SetTo(dir, path); + if (error == B_OK) + error = SetTo(&entry, openMode); + set_status(error); + return error; +} + +// IsReadable +//! Returns whether the file is readable. +/*! \return + - \c true, if the BFile has been initialized properly and the file has + been been opened for reading, + - \c false, otherwise. +*/ +bool +BFile::IsReadable() const +{ + return (InitCheck() == B_OK + && ((fMode & O_RWMASK) == O_RDONLY + || (fMode & O_RWMASK) == O_RDWR)); +} + +// IsWritable +//! Returns whether the file is writable. +/*! \return + - \c true, if the BFile has been initialized properly and the file has + been opened for writing, + - \c false, otherwise. +*/ +bool +BFile::IsWritable() const +{ + return (InitCheck() == B_OK + && ((fMode & O_RWMASK) == O_WRONLY + || (fMode & O_RWMASK) == O_RDWR)); +} + +// Read +//! Reads a number of bytes from the file into a buffer. +/*! \param buffer the buffer the data from the file shall be written to + \param size the number of bytes that shall be read + \return the number of bytes actually read or an error code +*/ +ssize_t +BFile::Read(void *buffer, size_t size) +{ + ssize_t result = InitCheck(); + if (result == B_OK) + result = StorageKit::read(get_fd(), buffer, size); + return result; +} + +// ReadAt +/*! \brief Reads a number of bytes from a certain position within the file + into a buffer. + \param location the position (in bytes) within the file from which the + data shall be read + \param buffer the buffer the data from the file shall be written to + \param size the number of bytes that shall be read + \return the number of bytes actually read or an error code +*/ +ssize_t +BFile::ReadAt(off_t location, void *buffer, size_t size) +{ + ssize_t result = InitCheck(); + if (result == B_OK) + result = StorageKit::read(get_fd(), buffer, location, size); + return result; +} + +// Write +//! Writes a number of bytes from a buffer into the file. +/*! \param buffer the buffer containing the data to be written to the file + \param size the number of bytes that shall be written + \return the number of bytes actually written or an error code +*/ +ssize_t +BFile::Write(const void *buffer, size_t size) +{ + ssize_t result = InitCheck(); + if (result == B_OK) + result = StorageKit::write(get_fd(), buffer, size); + return result; +} + +// WriteAt +/*! \brief Writes a number of bytes from a buffer at a certain position + into the file. + \param location the position (in bytes) within the file at which the data + shall be written + \param buffer the buffer containing the data to be written to the file + \param size the number of bytes that shall be written + \return the number of bytes actually written or an error code +*/ +ssize_t +BFile::WriteAt(off_t location, const void *buffer, size_t size) +{ + ssize_t result = InitCheck(); + if (result == B_OK) + result = StorageKit::write(get_fd(), buffer, location, size); + return result; +} + +// Seek +//! Seeks to another read/write position within the file. +/*! It is allowed to seek past the end of the file. A subsequent call to + Write() will pad the file with undefined data. Seeking before the + beginning of the file will fail and the behavior of subsequent Read() + or Write() invocations will be undefined. + \param offset new read/write position, depending on \a seekMode relative + to the beginning or the end of the file or the current position + \param seekMode: + - \c SEEK_SET: move relative to the beginning of the file + - \c SEEK_CUR: move relative to the current position + - \c SEEK_END: move relative to the end of the file + \return + - the new read/write position relative to the beginning of the file + - \c B_ERROR when trying to seek before the beginning of the file + - \c B_FILE_ERROR, if the file is not properly initialized +*/ +off_t +BFile::Seek(off_t offset, uint32 seekMode) +{ + off_t result = (InitCheck() == B_OK ? B_OK : B_FILE_ERROR); + if (result == B_OK) + result = StorageKit::seek(get_fd(), offset, seekMode); + return result; +} + +// Position +//! Returns the current read/write position within the file. +/*! \return + - the current read/write position relative to the beginning of the file + - \c B_ERROR, after a Seek() before the beginning of the file + - \c B_FILE_ERROR, if the file has not been initialized +*/ +off_t +BFile::Position() const +{ + off_t result = (InitCheck() == B_OK ? B_OK : B_FILE_ERROR); + if (result == B_OK) + result = StorageKit::get_position(get_fd()); + return result; +} + +// SetSize +//! Sets the size of the file. +/*! If the file is shorter than \a size bytes it will be padded with + unspecified data to the requested size. If it is larger, it will be + truncated. + Note: There's no problem with setting the size of a BFile opened in + \c B_READ_ONLY mode, unless the file resides on a read only volume. + \param size the new file size + \return + - \c B_OK, if everything went fine + - \c B_NOT_ALLOWED, if trying to set the size of a file on a read only + volume + - \c B_DEVICE_FULL, if there's not enough space left on the volume +*/ +status_t +BFile::SetSize(off_t size) +{ + status_t result = InitCheck(); + if (result == B_OK && size < 0) + result = B_BAD_VALUE; + struct stat statData; + if (result == B_OK) { + statData.st_size = size; + result = set_stat(statData, WSTAT_SIZE); + } + return result; +} + +// = +//! Assigns another BFile to this BFile. +/*! If the other BFile is uninitialized, this one will be too. Otherwise it + will refer to the same file using the same mode, unless an error occurs. + \param file the original BFile + \return a reference to this BFile +*/ +BFile & +BFile::operator=(const BFile &file) +{ + if (&file != this) { // no need to assign us to ourselves + Unset(); + if (file.InitCheck() == B_OK) { + // duplicate the file descriptor + StorageKit::FileDescriptor fd = -1; + status_t status = StorageKit::dup(file.get_fd(), fd); + // set it + if (status == B_OK) { + status = set_fd(fd); + if (status == B_OK) + fMode = file.fMode; + else + StorageKit::close(fd); + } + set_status(status); + } + } + return *this; +} + + +// FBC +void BFile::_ReservedFile1() {} +void BFile::_ReservedFile2() {} +void BFile::_ReservedFile3() {} +void BFile::_ReservedFile4() {} +void BFile::_ReservedFile5() {} +void BFile::_ReservedFile6() {} + + +// get_fd +/*! Returns the file descriptor. + To be used instead of accessing the BNode's private \c fFd member directly. + \return the file descriptor, or -1, if not properly initialized. +*/ +StorageKit::FileDescriptor +BFile::get_fd() const +{ + return fFd; +} + + +#ifdef USE_OPENBEOS_NAMESPACE +}; // namespace OpenBeOS +#endif + diff --git a/src/kits/storage/FindDirectory.cpp b/src/kits/storage/FindDirectory.cpp new file mode 100644 index 0000000000..61c7171fbe --- /dev/null +++ b/src/kits/storage/FindDirectory.cpp @@ -0,0 +1,308 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file FindDirectory.cpp + find_directory() implementations. +*/ + +#include + +#include + +#include +#include +#include +#include +#include + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS { +#endif + +enum { + NOT_IMPLEMENTED = B_ERROR, +}; + +// find_directory +/*! \brief Internal find_directory() helper function, that does the real work. + \param which the directory_which constant specifying the directory + \param path a BPath object to be initialized to the directory's path + \param createIt \c true, if the directory shall be created, if it doesn't + already exist, \c false otherwise. + \param device the volume on which the directory is located + \return \c B_OK if everything went fine, an error code otherwise. +*/ +static +status_t +find_directory(directory_which which, BPath &path, bool createIt, dev_t device) +{ + status_t error = B_BAD_VALUE; + switch (which) { + // volume relative dirs + case B_DESKTOP_DIRECTORY: + { + if (device < 0) + device = dev_for_path("/boot"); + fs_info info; + if (fs_stat_dev(device, &info) == 0) { + if (!strcmp(info.fsh_name, "bfs")) { + entry_ref ref(device, info.root, "home"); + BPath homePath(&ref); + error = homePath.InitCheck(); + if (error == B_OK) + path.SetTo(homePath.Path(), "Desktop"); + } else + error = B_ENTRY_NOT_FOUND; + } else + error = errno; + break; + } + case B_TRASH_DIRECTORY: + { + if (device < 0) + device = dev_for_path("/boot"); + fs_info info; + if (fs_stat_dev(device, &info) == 0) { + if (!strcmp(info.fsh_name, "bfs")) { + entry_ref ref(device, info.root, "home"); + BPath homePath(&ref); + error = homePath.InitCheck(); + if (error == B_OK) + path.SetTo(homePath.Path(), "Desktop/Trash"); + } else if (!strcmp(info.fsh_name, "dos")) { + entry_ref ref(device, info.root, "RECYCLED"); + BPath recycledPath(&ref); + error = recycledPath.InitCheck(); + if (error == B_OK) + path.SetTo(recycledPath.Path(), "_BEOS_"); + } else + error = B_ENTRY_NOT_FOUND; + } else + error = errno; + break; + } + // BeOS directories. These are mostly accessed read-only. + case B_BEOS_DIRECTORY: + error = path.SetTo("/boot/beos"); + break; + case B_BEOS_SYSTEM_DIRECTORY: + error = path.SetTo("/boot/beos/system"); + break; + case B_BEOS_ADDONS_DIRECTORY: + error = path.SetTo("/boot/beos/system/add-ons"); + break; + case B_BEOS_BOOT_DIRECTORY: + error = path.SetTo("/boot/beos/system/boot"); + break; + case B_BEOS_FONTS_DIRECTORY: + error = path.SetTo("/boot/beos/etc/fonts"); + break; + case B_BEOS_LIB_DIRECTORY: + error = path.SetTo("/boot/beos/system/lib"); + break; + case B_BEOS_SERVERS_DIRECTORY: + error = path.SetTo("/boot/beos/system/servers"); + break; + case B_BEOS_APPS_DIRECTORY: + error = path.SetTo("/boot/beos/apps"); + break; + case B_BEOS_BIN_DIRECTORY: + error = path.SetTo("/boot/beos/bin"); + break; + case B_BEOS_ETC_DIRECTORY: + error = path.SetTo("/boot/beos/etc"); + break; + case B_BEOS_DOCUMENTATION_DIRECTORY: + error = path.SetTo("/boot/beos/documentation"); + break; + case B_BEOS_PREFERENCES_DIRECTORY: + error = path.SetTo("/boot/beos/preferences"); + break; + case B_BEOS_TRANSLATORS_DIRECTORY: + error = path.SetTo("/boot/beos/system/add-ons/Translators"); + break; + case B_BEOS_MEDIA_NODES_DIRECTORY: + error = path.SetTo("/boot/beos/system/add-ons/media"); + break; + case B_BEOS_SOUNDS_DIRECTORY: + error = path.SetTo("/boot/beos/etc/sounds"); + break; + // Common directories, shared among all users. + case B_COMMON_DIRECTORY: + error = path.SetTo("/boot/home"); + break; + case B_COMMON_SYSTEM_DIRECTORY: + error = path.SetTo("/boot/home/config"); + break; + case B_COMMON_ADDONS_DIRECTORY: + error = path.SetTo("/boot/home/config/add-ons"); + break; + case B_COMMON_BOOT_DIRECTORY: + error = path.SetTo("/boot/home/config/boot"); + break; + case B_COMMON_FONTS_DIRECTORY: + error = path.SetTo("/boot/home/config/fonts"); + break; + case B_COMMON_LIB_DIRECTORY: + error = path.SetTo("/boot/home/config/lib"); + break; + case B_COMMON_SERVERS_DIRECTORY: + error = path.SetTo("/boot/home/config/servers"); + break; + case B_COMMON_BIN_DIRECTORY: + error = path.SetTo("/boot/home/config/bin"); + break; + case B_COMMON_ETC_DIRECTORY: + error = path.SetTo("/boot/home/config/etc"); + break; + case B_COMMON_DOCUMENTATION_DIRECTORY: + error = path.SetTo("/boot/home/config/documentation"); + break; + case B_COMMON_SETTINGS_DIRECTORY: + error = path.SetTo("/boot/home/config/settings"); + break; + case B_COMMON_DEVELOP_DIRECTORY: + error = path.SetTo("/boot/develop"); + break; + case B_COMMON_LOG_DIRECTORY: + error = path.SetTo("/boot/var/log"); + break; + case B_COMMON_SPOOL_DIRECTORY: + error = path.SetTo("/boot/var/spool"); + break; + case B_COMMON_TEMP_DIRECTORY: + error = path.SetTo("/boot/var/tmp"); + break; + case B_COMMON_VAR_DIRECTORY: + error = path.SetTo("/boot/var"); + break; + case B_COMMON_TRANSLATORS_DIRECTORY: + error = path.SetTo("/boot/home/config/add-ons/Translators"); + break; + case B_COMMON_MEDIA_NODES_DIRECTORY: + error = path.SetTo("/boot/home/config/add-ons/media"); + break; + case B_COMMON_SOUNDS_DIRECTORY: + error = path.SetTo("/boot/home/config/sounds"); + break; + // User directories. These are interpreted in the context + // of the user making the find_directory call. + case B_USER_DIRECTORY: + error = path.SetTo("/boot/home"); + break; + case B_USER_CONFIG_DIRECTORY: + error = path.SetTo("/boot/home/config"); + break; + case B_USER_ADDONS_DIRECTORY: + error = path.SetTo("/boot/home/config/add-ons"); + break; + case B_USER_BOOT_DIRECTORY: + error = path.SetTo("/boot/home/config/boot"); + break; + case B_USER_FONTS_DIRECTORY: + error = path.SetTo("/boot/home/config/fonts"); + break; + case B_USER_LIB_DIRECTORY: + error = path.SetTo("/boot/home/config/lib"); + break; + case B_USER_SETTINGS_DIRECTORY: + error = path.SetTo("/boot/home/config/settings"); + break; + case B_USER_DESKBAR_DIRECTORY: + error = path.SetTo("/boot/home/config/be"); + break; + case B_USER_PRINTERS_DIRECTORY: + error = path.SetTo("/boot/home/config/settings/printers"); + break; + case B_USER_TRANSLATORS_DIRECTORY: + error = path.SetTo("/boot/home/config/add-ons/Translators"); + break; + case B_USER_MEDIA_NODES_DIRECTORY: + error = path.SetTo("/boot/home/config/add-ons/media"); + break; + case B_USER_SOUNDS_DIRECTORY: + error = path.SetTo("/boot/home/config/sounds"); + break; + // Global directories. + case B_APPS_DIRECTORY: + error = path.SetTo("/boot/apps"); + break; + case B_PREFERENCES_DIRECTORY: + error = path.SetTo("/boot/preferences"); + break; + case B_UTILITIES_DIRECTORY: + error = path.SetTo("/boot/utilities"); + break; + } + // create the directory, if desired + if (error == B_OK && createIt) + create_directory(path.Path(), S_IRWXU | S_IRWXG | S_IRWXO); + return error; +} + + +// find_directory +//! Returns a path of a directory specified by a directory_which constant. +/*! If the supplied volume ID is + \param which the directory_which constant specifying the directory + \param volume the volume on which the directory is located + \param createIt \c true, if the directory shall be created, if it doesn't + already exist, \c false otherwise. + \param pathString a pointer to a buffer into which the directory path + shall be written. + \param length the size of the buffer + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a pathString. + - \c E2BIG: Buffer is too small for path. + - another error code +*/ +status_t +find_directory(directory_which which, dev_t volume, bool createIt, + char *pathString, int32 length) +{ + status_t error = (pathString ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + BPath path; + error = find_directory(which, path, createIt, volume); + if (error == B_OK && (int32)strlen(path.Path()) >= length) + error = E2BIG; + if (error == B_OK) + strcpy(pathString, path.Path()); + } + return error; +} + +// find_directory +//! Returns a path of a directory specified by a directory_which constant. +/*! \param which the directory_which constant specifying the directory + \param path a BPath object to be initialized to the directory's path + \param createIt \c true, if the directory shall be created, if it doesn't + already exist, \c false otherwise. + \param volume the volume on which the directory is located + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a path. + - another error code +*/ +status_t +find_directory(directory_which which, BPath *path, bool createIt, + BVolume *volume) +{ + status_t error = (path ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + dev_t device = -1; + if (volume && volume->InitCheck() == B_OK) + device = volume->Device(); + error = find_directory(which, *path, createIt, device); + } + return error; +} + + +#ifdef USE_OPENBEOS_NAMESPACE +}; // namespace OpenBeOS +#endif + diff --git a/src/kits/storage/Jamfile b/src/kits/storage/Jamfile new file mode 100644 index 0000000000..b588a5d0c2 --- /dev/null +++ b/src/kits/storage/Jamfile @@ -0,0 +1,52 @@ +# This is $(TOP)/source/lib/Jamfile + +SubDir TOP source lib ; + +SharedFromSources $(TOP)/source/lib/libstorage.so : + ByteOrder.cpp + DataIO.cpp + Directory.cpp + Entry.cpp + EntryList.cpp + File.cpp + FindDirectory.cpp + Flattenable.cpp + List.cpp + Locker.cpp + MallocIO.cpp + Mime.cpp + MimeType.cpp + Node.cpp + #NodeInfo.cpp + OffsetFile.cpp + Path.cpp + Query.cpp + QueryPredicate.cpp + ResourcesContainer.cpp + ResourceFile.cpp + ResourceItem.cpp + Resources.cpp + ResourceStrings.cpp + Statable.cpp + SymLink.cpp + Volume.cpp + kernel_interface.POSIX.cpp + storage_support.cpp ; +LinkSharedLibs $(TOP)/source/lib/libstorage.so : + $(TOP)/source/lib/libbeadapter.so +; +LinkSharedOSLibs $(TOP)/source/lib/libstorage.so : + /boot/develop/lib/x86/libbe.so +; + + +# Here come the rules for our adapter library. + +HDRS = ; + +SharedFromSources $(TOP)/source/lib/libbeadapter.so : + LibBeAdapter.cpp +; +LinkSharedOSLibs $(TOP)/source/lib/libbeadapter.so : + /boot/develop/lib/x86/libbe.so +; diff --git a/src/kits/storage/LibBeAdapter.cpp b/src/kits/storage/LibBeAdapter.cpp new file mode 100644 index 0000000000..c6b1346a85 --- /dev/null +++ b/src/kits/storage/LibBeAdapter.cpp @@ -0,0 +1,44 @@ +// LibBeAdapter.cpp + +#include +#include +#include +#include + +status_t +entry_ref_to_path_adapter(dev_t device, ino_t directory, const char *name, + char *buffer, size_t size) +{ + status_t error = (name && buffer ? B_OK : B_BAD_VALUE); + BEntry entry; + if (error == B_OK) { + entry_ref ref(device, directory, name); + error = entry.SetTo(&ref); + } + BPath path; + if (error == B_OK) + error = entry.GetPath(&path); + if (error == B_OK) { + if (size >= strlen(path.Path()) + 1) + strcpy(buffer, path.Path()); + else + error = B_BAD_VALUE; + } + return error; +} + +// swap_data_adapter +status_t +swap_data_adapter(type_code type, void *data, size_t length, + swap_action action) +{ + return swap_data(type, data, length, action); +} + +// is_type_swapped_adapter +bool +is_type_swapped_adapter(type_code type) +{ + return is_type_swapped(type); +} + diff --git a/src/kits/storage/Mime.cpp b/src/kits/storage/Mime.cpp new file mode 100644 index 0000000000..92ce9e495a --- /dev/null +++ b/src/kits/storage/Mime.cpp @@ -0,0 +1,78 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file Mime.cpp + Mime type C functions implementation. +*/ + +#include + +enum { + NOT_IMPLEMENTED = B_ERROR, +}; + +// update_mime_info +/*! \brief Updates the MIME information for one or more files. + If \a path points to a file, the MIME information for this file are + updated only. If it points to a directory and \a recursive is non-null, + the information for all the files in the given directory tree are updated. + If path is \c NULL all files are considered; \a recursive is ignored in + this case. + \param path The path to a file or directory, or \c NULL. + \param recursive Non-null to trigger recursive behavior. + \param synchronous If non-null update_mime_info() waits until the + operation is finished, otherwise it returns immediately and the + update is done asynchronously. + \param force If non-null, also the information for files are updated that + have already been updated. + \return + - \c B_OK: Everything went fine. + - An error code otherwise. +*/ +int +update_mime_info(const char *path, int recursive, int synchronous, int force) +{ + return NOT_IMPLEMENTED; +} + +// create_app_meta_mime +/*! Creates a MIME database entry for one or more applications. + \a path should either point to an application file or should be \c NULL. + In the first case a MIME database entry for that application is created, + in the second case entries for all applications are created. + \param path The path to an application file, or \c NULL. + \param recursive Currently unused. + \param synchronous If non-null create_app_meta_mime() waits until the + operation is finished, otherwise it returns immediately and the + operation is done asynchronously. + \param force If non-null, entries are created even if they do already + exist. + \return + - \c B_OK: Everything went fine. + - An error code otherwise. +*/ +status_t +create_app_meta_mime(const char *path, int recursive, int synchronous, + int force) +{ + return NOT_IMPLEMENTED; +} + +// get_device_icon +/*! Retrieves an icon associated with a given device. + \param dev The path to the device. + \param icon A pointer to a buffer the icon data shall be written to. + \param size The size of the icon. Currently the sizes 16 (small) and + 32 (large) are supported. + \return + - \c B_OK: Everything went fine. + - An error code otherwise. +*/ +status_t +get_device_icon(const char *dev, void *icon, int32 size) +{ + return NOT_IMPLEMENTED; +} + diff --git a/src/kits/storage/MimeType.cpp b/src/kits/storage/MimeType.cpp new file mode 100644 index 0000000000..d9361b7393 --- /dev/null +++ b/src/kits/storage/MimeType.cpp @@ -0,0 +1,1002 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file MimeType.cpp + BMimeType implementation. +*/ +#include + +enum { + NOT_IMPLEMENTED = B_ERROR, +}; + + +const char *B_PEF_APP_MIME_TYPE = "application/x-be-executable"; +const char *B_PE_APP_MIME_TYPE = "application/x-vnd.be-peexecutable"; +const char *B_ELF_APP_MIME_TYPE = "application/x-vnd.be-elfexecutable"; +const char *B_RESOURCE_MIME_TYPE = "application/x-be-resource"; +const char *B_FILE_MIME_TYPE = "application/octet-stream"; +// Might be defined platform depended, but ELF will certainly be the common +// format for all platforms anyway. +const char *B_APP_MIME_TYPE = B_ELF_APP_MIME_TYPE; + +// constructor +/*! \brief Creates an uninitialized BMimeType object. +*/ +BMimeType::BMimeType() +{ +} + +// constructor +/*! \brief Creates a BMimeType object and initializes it to the supplied + MIME type. + The supplied string must specify a valid MIME type or supertype. + \see SetTo() for further information. + \param mimeType The MIME string. +*/ +BMimeType::BMimeType(const char *mimeType) +{ +} + +// destructor +/*! \brief Frees all resources associated with this object. +*/ +BMimeType::~BMimeType() +{ +} + +// SetTo +/*! \brief Initializes this object to the supplied MIME type. + The supplied string must specify a valid MIME type or supertype. + Valid MIME types are given by the following grammar: + MIMEType ::= Supertype "/" [ Subtype ] + Supertype ::= "application" | "audio" | "image" | "message" + | "multipart" | "text" | "video" + Subtype ::= MIMEChar MIMEChar* + MIMEChar ::= any character except white spaces, CTLs and '/', '<', '>', + '@',, ',', ';', ':', '"', '(', ')', '[', ']', '?', '=', '\' + (Note: RFC1341 also forbits '.', but it is allowed here.) + + Currently the supertype is not restricted to one of the seven types given, + but can be an arbitrary string (obeying the same rule as the subtype). + Nevertheless it is a very bad idea to use another supertype. + The supplied MIME string is copied; the caller retains the ownership. + \param mimeType The MIME string. + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL or invalid \a mimeString. + - \c B_NO_MEMORY: Insufficient memory to copy the MIME string. +*/ +status_t +BMimeType::SetTo(const char *mimeType) +{ + return NOT_IMPLEMENTED; +} + +// Unset +/*! \brief Returns the object to an uninitialized state. +*/ +void +BMimeType::Unset() +{ +} + +// InitCheck +/*! Returns the result of the most recent constructor or SetTo() call. + \return + - \c B_OK: The object is properly initialized. + - A specific error code otherwise. +*/ +status_t +BMimeType::InitCheck() const +{ + return NOT_IMPLEMENTED; +} + +// Type +/*! \brief Returns the MIME string represented by this object. + \return The MIME string, if the object is properly initialized, \c NULL + otherwise. +*/ +const char * +BMimeType::Type() const +{ + return NULL; // not implemented +} + +// IsValid +/*! \brief Returns whether the object represents a valid MIME type. + \see SetTo() for further information. + \return \c true, if the object is properly initialized, \c false + otherwise. +*/ +bool +BMimeType::IsValid() const +{ + return false; // not implemented +} + +// IsSupertypeOnly +/*! \brief Returns whether this objects represents a supertype. + \return \c true, if the object is properly initialized and represents a + supertype, \c false otherwise. +*/ +bool +BMimeType::IsSupertypeOnly() const +{ + return false; // not implemented +} + +// IsInstalled +//! Returns whether or not this type is currently installed in the MIME database +/*! To add the MIME type to the database, call \c Install(). + To remove the MIME type from the database, call \c Delete(). + + \return + - \c true: The MIME type is currently installed in the database + - \c false: The MIME type is not currently installed in the database +*/ +bool +BMimeType::IsInstalled() const +{ + return false; // not implemented +} + +// GetSupertype +/*! \brief Returns the supertype of the MIME type represented by this object. + The supplied object is initialized to this object's supertype. If this + BMimeType is not properly initialized, the supplied object will be Unset(). + \param superType A pointer to the BMimeType object that shall be + initialized to this object's supertype. + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a superType or this object is not initialized. +*/ +status_t +BMimeType::GetSupertype(BMimeType *superType) const +{ + return NOT_IMPLEMENTED; +} + +// == +/*! \brief Returns whether this and the supplied MIME type are equal. + Two BMimeType objects are said to be equal, if they represent the same + MIME string, ignoring case, or if both are not initialized. + \param type The BMimeType to be compared with. + \return \c true, if the objects are equal, \c false otherwise. +*/ +bool +BMimeType::operator==(const BMimeType &type) const +{ + return false; // not implemented +} + +// == +/*! \brief Returns whether this and the supplied MIME type are equal. + A BMimeType objects equals a MIME string, if its MIME string equals the + latter one, ignoring case, or if it is uninitialized and the MIME string + is \c NULL. + \param type The MIME string to be compared with. + \return \c true, if the MIME types are equal, \c false otherwise. +*/ +bool +BMimeType::operator==(const char *type) const +{ + return false; // not implemented +} + +// Contains +/*! \brief Returns whether this MIME type is a supertype of or equals the + supplied one. + \param type The MIME type. + \return \c true, if this MIME type is a supertype of or equals the + supplied one, \c false otherwise. +*/ +bool +BMimeType::Contains(const BMimeType *type) const +{ + return false; // not implemented +} + +// Install +//! Adds the MIME type to the MIME database +/*! To check if the MIME type is already installed, call \c IsInstalled(). + To remove the MIME type from the database, call \c Delete(). + + \note The R5 implementation returns random values if the type is already + installed, so be sure to check \c IsInstalled() first. + + \return + - \c B_OK: Success + - "error code": Failure +*/ +status_t +BMimeType::Install() +{ + return NOT_IMPLEMENTED; +} + +// Delete +//! Removes the MIME type from the MIME database +/*! To check if the MIME type is already installed, call \c IsInstalled(). + To add the MIME type to the database, call \c Install(). + + \note Calling \c BMimeType::Delete() does not uninitialize or otherwise + deallocate the \c BMimeType object; it simply removes the type from the + database. + + \return + - \c B_OK: Success + - "error code": Failure +*/ +status_t +BMimeType::Delete() +{ + return NOT_IMPLEMENTED; +} + +// GetIcon +//! Fetches the large or mini icon associated with the MIME type +/*! The icon is copied into the \c BBitmap pointed to by \c icon. The bitmap must + be the proper size: \c 32x32 for the large icon, \c 16x16 for the mini icon. + Additionally, the bitmap must be in the \c B_CMAP8 color space (8-bit color). + + \param icon Pointer to a pre-allocated \c BBitmap of proper size and colorspace into + which the icon is copied. + \param icon_size Value that specifies which icon to return. Currently \c B_LARGE_ICON + and \c B_MINI_ICON are supported. + \return + - \c B_OK: Success + - \c B_ENTRY_NOT_FOUND: No icon of the given size exists for the given type + - "error code": Failure + +*/ +status_t +BMimeType::GetIcon(BBitmap *icon, icon_size) const +{ + return NOT_IMPLEMENTED; +} + +// GetPreferredApp +//! Fetches the signature of the MIME type's preferred application from the MIME database +/*! The preferred app is the application that's used to access a file when, for example, the user + double-clicks the file in a Tracker window. Unless the file identifies in its attributes a + "custom" preferred app, Tracker will ask the file type database for the preferred app + that's associated with the file's type. + + The string pointed to by \c signature must be long enough to + hold the preferred applications signature; a length of \c B_MIME_TYPE_LENGTH+1 is + recommended. + + \param signature Pointer to a pre-allocated string into which the signature of the preferred app is copied. If + the function fails, the contents of the string are undefined. + \param verb \c app_verb value that specifies the type of access for which you are requesting the preferred app. + Currently, the only supported app verb is \c B_OPEN. + \return + - \c B_OK: Success + - \c B_ENTRY_NOT_FOUND: No preferred app exists for the given type and app_verb + - "error code": Failure +*/ +status_t +BMimeType::GetPreferredApp(char *signature, app_verb verb) const +{ + return NOT_IMPLEMENTED; +} + +// GetAttrInfo +/*! \brief Fetches from the MIME database a BMessage describing the attributes + typically associated with files of the given MIME type + + The attribute information is returned in a pre-allocated BMessage pointed to by + the \c info parameter (note that the any prior contents of the message + will be destroyed). If the method succeeds, the format of the BMessage + pointed to by \c info will be the following: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        field nametypeelement[0..n]
        "attr:name" \c B_STRING_TYPE The name of each attribute
        "attr:public_name" \c B_STRING_TYPE The human-readable name of each attribute
        "attr:type" \c B_INT32_TYPE The type code for each attribute
        "attr:viewable" \c B_BOOL_TYPE For each attribute: \c true if the attribute is public, \c false if it's private
        "attr:editable" \c B_BOOL_TYPE For each attribute: \c true if the attribute should be user editable, \c false if not
        + + The \c BMessage::what value is set to decimal \c 233, but is otherwise meaningless. + + \param info Pointer to a pre-allocated BMessage into which information about + the MIME type's associated file attributes is stored. + \return + - \c B_OK: Success + - "error code": Failure +*/ +status_t +BMimeType::GetAttrInfo(BMessage *info) const +{ + return NOT_IMPLEMENTED; +} + +// GetFileExtensions +//! Fetches the MIME type's associated filename extensions from the MIME database +/*! The MIME database associates a list of filename extensions (a character string + following the rightmost dot, \c ".", character in the filename) with each type. + These extensions can then be used to help determine the type of any untyped files + that may be encountered. + + The list of extensions is returned in a pre-allocated BMessage pointed to by + the \c extensions parameter (note that the any prior contents of the message + will be destroyed). If the method succeeds, the format of the BMessage + pointed to by \c extensions will be the following: + - The message's \c "extensions" field will contain an indexed array of strings, + one for each extension. The extensions are given without the preceding \c "." + character by convention. + - The message's \c "type" field will be a string containing the MIME type whose + associated file extensions you are fetching. + - The \c what member of the BMessage will be set to \c 234, but is otherwise + irrelevant. + + Note that any other fields present in the BMessage passed to the most recent + \c SetFileExtensions() call will also be returned. + + \param extensions Pointer to a pre-allocated BMessage into which the + MIME type's associated file extensions will be stored. + \return + - \c B_OK: Success + - "error code": Failure +*/ +status_t +BMimeType::GetFileExtensions(BMessage *extensions) const +{ + return NOT_IMPLEMENTED; +} + +// GetShortDescription +//! Fetches the MIME type's short description from the MIME database +/*! The string pointed to by \c description must be long enough to + hold the short description; a length of \c B_MIME_TYPE_LENGTH+1 is + recommended. + + \param description Pointer to a pre-allocated string into which the long description is copied. If + the function fails, the contents of the string are undefined. + \return + - \c B_OK: Success + - \c B_ENTRY_NOT_FOUND: No short description exists for the given type + - "error code": Failure +*/ +status_t +BMimeType::GetShortDescription(char *description) const +{ + return NOT_IMPLEMENTED; +} + +// GetLongDescription +//! Fetches the MIME type's long description from the MIME database +/*! The string pointed to by \c description must be long enough to + hold the long description; a length of \c B_MIME_TYPE_LENGTH+1 is + recommended. + + \param description Pointer to a pre-allocated string into which the long description is copied. If + the function fails, the contents of the string are undefined. + \return + - \c B_OK: Success + - \c B_ENTRY_NOT_FOUND: No long description exists for the given type + - "error code": Failure +*/ +status_t +BMimeType::GetLongDescription(char *description) const +{ + return NOT_IMPLEMENTED; +} + +// GetSupportingApps +status_t +BMimeType::GetSupportingApps(BMessage *signatures) const +{ + return NOT_IMPLEMENTED; +} + +// SetIcon +//! Sets the large or mini icon for the MIME type +/*! The icon is copied from the \c BBitmap pointed to by \c icon. The bitmap must + be the proper size: \c 32x32 for the large icon, \c 16x16 for the mini icon. + Additionally, the bitmap must be in the \c B_CMAP8 color space (8-bit color). + + If you want to erase the current icon, pass \c NULL as the \c icon argument. + + \param icon Pointer to a pre-allocated \c BBitmap of proper size and colorspace + containing the new icon, or \c NULL to clear the current icon. + \param icon_size Value that specifies which icon to update. Currently \c B_LARGE_ICON + and \c B_MINI_ICON are supported. + \return + - \c B_OK: Success + - "error code": Failure + +*/ +status_t +BMimeType::SetIcon(const BBitmap *icon, icon_size) +{ + return NOT_IMPLEMENTED; +} + +// SetPreferredApp +//! Sets the preferred application for the MIME type +/*! The preferred app is the application that's used to access a file when, for example, the user + double-clicks the file in a Tracker window. Unless the file identifies in its attributes a + "custom" preferred app, Tracker will ask the file type database for the preferred app + that's associated with the file's type. + + The string pointed to by \c signature must be of + length less than or equal to \c B_MIME_TYPE_LENGTH characters. + + \note If the MIME type is not installed, it will first be installed, and then + the preferred app will be set. + + \param signature Pointer to a pre-allocated string containing the signature of the new preferred app. + \param verb \c app_verb value that specifies the type of access for which you are setting the preferred app. + Currently, the only supported app verb is \c B_OPEN. + \return + - \c B_OK: Success + - "error code": Failure +*/ +status_t +BMimeType::SetPreferredApp(const char *signature, app_verb verb) +{ + return NOT_IMPLEMENTED; +} + +// SetAttrInfo +/*! \brief Sets the description of the attributes typically associated with files + of the given MIME type + + The attribute information is technically arbitrary, but the expected + format of the BMessage pointed to by the \c info parameter is as follows: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        field nametypeelement[0..n]
        "attr:name" \c B_STRING_TYPE The name of each attribute
        "attr:public_name" \c B_STRING_TYPE The human-readable name of each attribute
        "attr:type" \c B_INT32_TYPE The type code for each attribute
        "attr:viewable" \c B_BOOL_TYPE For each attribute: \c true if the attribute is public, \c false if it's private
        "attr:editable" \c B_BOOL_TYPE For each attribute: \c true if the attribute should be user editable, \c false if not
        + + The \c BMessage::what value is ignored. + + \param info Pointer to a pre-allocated and properly formatted BMessage containing + information about the file attributes typically associated with the + MIME type. + \return + - \c B_OK: Success + - "error code": Failure +*/ +status_t +BMimeType::SetAttrInfo(const BMessage *info) +{ + return NOT_IMPLEMENTED; +} + +// SetFileExtensions +//! Sets the list of filename extensions associated with the MIME type +/*! The MIME database associates a list of filename extensions (a character string + following the rightmost dot, \c ".", character in the filename) with each type. + These extensions can then be used to help determine the type of any untyped files + that may be encountered. + + The list of extensions is given in a pre-allocated BMessage pointed to by + the \c extensions parameter. The format of the message should be as follows: + - The message's \c "extensions" field should contain an indexed array of strings, + one for each extension. The extensions are to be given without the preceding \c "." + character (i.e. \c "html" or \c "mp3", not \c ".html" or \c ".mp3" ). + - The \c what member of the BMessage is ignored. + + Note that any other fields present in the \c BMessage will currently be retained + and returned by calls to \c GetFileExtensions(); however, this may change in the + future, so it is recommended that you not rely on this behaviour, and that no other + fields be present. Also, note that no checking is performed to verify the \c BMessage is + properly formatted; it's up to you to do things right. + + Finally, bear in mind that \c SetFileExtensions() clobbers the existing set of + extensions. If you want to augment a type's extensions, you should retrieve the + existing set, add the new ones, and then call \c SetFileExtensions(). + + \param extensions Pointer to a pre-allocated, properly formatted BMessage containing + the new list of file extensions to associate with this MIME type. + \return + - \c B_OK: Success + - "error code": Failure +*/ +status_t +BMimeType::SetFileExtensions(const BMessage *extensions) +{ + return NOT_IMPLEMENTED; +} + +// SetShortDescription +//! Sets the short description field for the MIME type +/*! The string pointed to by \c description must be of + length less than or equal to \c B_MIME_TYPE_LENGTH characters. + + \note If the MIME type is not installed, it will first be installed, and then + the short description will be set. + + \param description Pointer to a pre-allocated string containing the new short description + \return + - \c B_OK: Success + - "error code": Failure +*/ +status_t +BMimeType::SetShortDescription(const char *description) +{ + return NOT_IMPLEMENTED; +} + +// SetLongDescription +//! Sets the long description field for the MIME type +/*! The string pointed to by \c description must be of + length less than or equal to \c B_MIME_TYPE_LENGTH characters. + + \note If the MIME type is not installed, it will first be installed, and then + the long description will be set. + + \param description Pointer to a pre-allocated string containing the new long description + \return + - \c B_OK: Success + - "error code": Failure +*/ +status_t +BMimeType::SetLongDescription(const char *description) +{ + return NOT_IMPLEMENTED; +} + +// GetInstalledSupertypes +status_t +BMimeType::GetInstalledSupertypes(BMessage *super_types) +{ + return NOT_IMPLEMENTED; +} + +// GetInstalledTypes +status_t +BMimeType::GetInstalledTypes(BMessage *types) +{ + return NOT_IMPLEMENTED; +} + +// GetInstalledTypes +status_t +BMimeType::GetInstalledTypes(const char *super_type, BMessage *subtypes) +{ + return NOT_IMPLEMENTED; +} + +// GetWildcardApps +status_t +BMimeType::GetWildcardApps(BMessage *wild_ones) +{ + return NOT_IMPLEMENTED; +} + +// IsValid +/*! \brief Returns whether the given string represents a valid MIME type. + \see SetTo() for further information. + \return \c true, if the given string represents a valid MIME type. +*/ +bool +BMimeType::IsValid(const char *string) +{ + return false; // not implemented +} + +// GetAppHint +//! Fetches an \c entry_ref that serves as a hint as to where the MIME type's preferred application might live +/*! The app hint is a path that identifies the executable that should be used when launching an application + that has this signature. For example, when Tracker needs to launch an app of type \c "application/YourAppHere", + it asks the database for the application hint. This hint is converted to an \c entry_ref before it is passed + to the caller. Of course, the path may not point to an application, or it might point to an application + with the wrong signature (and so on); that's why this is merely a hint. + + The \c entry_ref pointed to by \c ref must be pre-allocated. + + \param ref Pointer to a pre-allocated \c entry_ref into which the location of the app hint is copied. If + the function fails, the contents of the \c entry_ref are undefined. + \return + - \c B_OK: Success + - \c B_ENTRY_NOT_FOUND: No app hint exists for the given type + - "error code": Failure +*/ +status_t +BMimeType::GetAppHint(entry_ref *ref) const +{ + return NOT_IMPLEMENTED; +} + +// SetAppHint +//! Sets the app hint field for the MIME type +/*! The app hint is a path that identifies the executable that should be used when launching an application + that has this signature. For example, when Tracker needs to launch an app of type \c "application/YourAppHere", + it asks the database for the application hint. This hint is converted to an \c entry_ref before it is passed + to the caller. Of course, the path may not point to an application, or it might point to an application + with the wrong signature (and so on); that's why this is merely a hint. + + The \c entry_ref pointed to by \c ref must be pre-allocated. It must be a valid \c entry_ref (i.e. + entry_ref(-1, -1, "some_file") will trigger an error), but it need not point to an existing file, nor need + it actually point to an application. That's not to say that it shouldn't; such an \c entry_ref would + render the app hint useless. + + \param ref Pointer to a pre-allocated \c entry_ref containting the location of the new app hint + \return + - \c B_OK: Success + - "error code": Failure +*/ +status_t +BMimeType::SetAppHint(const entry_ref *ref) +{ + return NOT_IMPLEMENTED; +} + +// GetIconForType +/*! \brief Fetches the large or mini icon used by an application of this type for files of the + given type. + + This can be confusing, so here's how this function is intended to be used: + - The actual \c BMimeType object should be set to the MIME signature of an + application for whom you want to look up custom icons for custom MIME types. + - The \c type parameter specifies the file type whose custom icon you are fetching. + + The type of the \c BMimeType object is not required to actually be a subtype of + \c "application/"; that is the intended use however, and calling \c GetIconForType() + on a non-application type will likely return \c B_ENTRY_NOT_FOUND. + + The icon is copied into the \c BBitmap pointed to by \c icon. The bitmap must + be the proper size: \c 32x32 for the large icon, \c 16x16 for the mini icon. + Additionally, the bitmap must be in the \c B_CMAP8 color space (8-bit color). + + \param type Pointer to a pre-allocated string containing the MIME type whose + custom icon you wish to fetch. + \param icon Pointer to a pre-allocated \c BBitmap of proper size and colorspace into + which the icon is copied. + \param icon_size Value that specifies which icon to return. Currently \c B_LARGE_ICON + and \c B_MINI_ICON are supported. + \return + - \c B_OK: Success + - \c B_ENTRY_NOT_FOUND: No icon of the given size exists for the given type + - "error code": Failure + +*/ +status_t +BMimeType::GetIconForType(const char *type, BBitmap *icon, icon_size which) const +{ + return NOT_IMPLEMENTED; +} + +// SetIconForType +/*! \brief Sets the large or mini icon used by an application of this type for + files of the given type. + + This can be confusing, so here's how this function is intended to be used: + - The actual \c BMimeType object should be set to the MIME signature of an + application to whom you want to assign custom icons for custom MIME types. + - The \c type parameter specifies the file type whose custom icon you are + setting. + + The type of the \c BMimeType object is not required to actually be a subtype of + \c "application/"; that is the intended use however, and application-specific + icons are not expected to be present for non-application types. + + The icon is copied from the \c BBitmap pointed to by \c icon. The bitmap must + be the proper size: \c 32x32 for the large icon, \c 16x16 for the mini icon. + Additionally, the bitmap must be in the \c B_CMAP8 color space (8-bit color). + + If you want to erase the current icon, pass \c NULL as the \c icon argument. + + \param type Pointer to a pre-allocated string containing the MIME type whose + custom icon you wish to set. + \param icon Pointer to a pre-allocated \c BBitmap of proper size and colorspace + containing the new icon, or \c NULL to clear the current icon. + \param icon_size Value that specifies which icon to update. Currently \c B_LARGE_ICON + and \c B_MINI_ICON are supported. + \return + - \c B_OK: Success + - "error code": Failure + +*/ +status_t +BMimeType::SetIconForType(const char *type, const BBitmap *icon, icon_size which) +{ + return NOT_IMPLEMENTED; +} + +// GetSnifferRule +/*! \brief Retrieves the MIME type's sniffer rule. + \param result Pointer to a pre-allocated BString into which the value is + copied. + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a result or uninitialized BMimeType + - \c B_ENTRY_NOT_FOUND: The MIME type is not installed. +*/ +status_t +BMimeType::GetSnifferRule(BString *result) const +{ + return NOT_IMPLEMENTED; +} + +// SetSnifferRule +/*! \brief Sets the MIME type's sniffer rule. + + If the supplied \a rule is \c NULL, the MIME type's sniffer rule is + unset. + + SetSnifferRule() does also return \c B_OK, if the type is not installed, + but the call will have no effect in this case. + + \param rule The rule string, may be \c NULL. + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: Uninitialized BMimeType. + - \c B_BAD_MIME_SNIFFER_RULE: The supplied sniffer rule is invalid. + + \see CheckSnifferRule(). +*/ +status_t +BMimeType::SetSnifferRule(const char *rule) +{ + return NOT_IMPLEMENTED; +} + +// CheckSnifferRule +/*! \brief Checks whether a MIME sniffer rule is valid or not. + + A MIME sniffer rule is valid, if it is well-formed with respect to the + following grammar and fulfills some further conditions listed thereafter: + + Rule ::= LWS Priority LWS ExprList LWS + ExprList ::= Expression (LWS Expression)* + Expression ::= "(" LWS (PatternList | RPatternList) LWS ")" + | Range LWS "(" LWS PatternList LWS ")" + RPatternList ::= RPattern (LWS "|" LWS RPattern)* + PatternList ::= Pattern (LWS "|" LWS Pattern)* + RPattern ::= Range LWS Pattern + Pattern ::= PString [ LWS "&" LWS Mask ] + Range ::= "[" LWS SDecimal [LWS ":" LWS SDecimal] LWS "]" + + Priority ::= Float + Mask ::= PString + PString ::= HexString | QuotedString | Octal [UnquotedString] + EscapedChar [UnquotedString] + HexString ::= "0x" HexPair HexPair* + HexPair ::= HexChar HexChar + QuotedString ::= '"' QChar QChar* '"' | "'" QChar QChar* "'" + Octal ::= "\" OctChar [OctChar [OctChar]] + SDecimal ::= ["+" | "-"] Decimal + Decimal ::= DecChar DecChar* + Float ::= Fixed [("E" | "e") Decimal] + Fixed ::= SDecimal ["." [Decimal]] | [SDecimal] "." Decimal + UnquotedString ::= UChar UChar* + LWS ::= LWSChar* + + LWSChar ::= LF | " " | TAB + OctChar ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" + DecChar ::= OctChar | "8" | "9" + HexChar ::= DecChar | "a" | "b" | "c" | "d" | "e" | "A" | "B" | "C" + | "D" | "E" + Char :: + QChar ::= | EscapedChar + EscapedChar ::= "\" Char + UChar ::= + + Conditions: + (checked) + - If a mask is specified for a pattern, this mask must have the same + length as the pattern string. + (not checked) + - 0 <= Priority <= 1 + - 0 <= Range begin <= Range end + - Rules of the form "() | () | ..." are invalid. + + Examples: + - 1.0 ('ABCD') + The file must start with the string "ABCD". The priority of the rule + is 1.0 (maximal). + - 0.8 [0:3] ('ABCD' | 'abcd') + The file must contain the string "ABCD" or "abcd" starting somewhere in + the first four bytes. The rule priority is 0.8. + - 0.5 ([0:3] 'ABCD' | [0:3] 'abcd' | [13] 'EFGH') + The file must contain the string "ABCD" or "abcd" starting somewhere in + the first four bytes or the string "EFGH" at position 13. The rule + priority is 0.5. + - 0.8 [0:3] ('ABCD' & 0xff00ffff | 'abcd' & 0xffff00ff) + The file must contain the string "A.CD" or "ab.d" (whereas "." is an + arbitrary character) starting somewhere in the first four bytes. The + rule priority is 0.8. + + Real examples: + - 0.20 ([0]"//" | [0]"/\*" | [0:32]"#include" | [0:32]"#ifndef" + | [0:32]"#ifdef") + text/x-source-code + - 0.70 ("8BPS \000\000\000\000" & 0xffffffff0000ffffffff ) + image/x-photoshop + + \param rule The rule string. + \param parseError A pointer to a pre-allocated BString into which a + description of the parse error is written (if any), may be \c NULL. + \return + - \c B_OK: The supplied sniffer rule is valid. + - \c B_BAD_VALUE: \c NULL \a rule. + - \c B_BAD_MIME_SNIFFER_RULE: The supplied sniffer rule is not valid. A + description of the error is written to \a parseError, if supplied. +*/ +status_t +BMimeType::CheckSnifferRule(const char *rule, BString *parseError) +{ + return NOT_IMPLEMENTED; +} + +// GuessMimeType +/*! \brief Guesses a MIME type for the entry referred to by the given + entry_ref. + This version of GuessMimeType() combines the features of the other + versions: First the data of the given file are checked (sniffed). Only + if the result of this operation is inconclusive, i.e. + "application/octet-stream", the filename is examined for extensions. + + \param ref Pointer to the entry_ref referring to the entry. + \param result Pointer to a pre-allocated BMimeType which is set to the + resulting MIME type. + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a ref or \a result. + - \c B_NAME_NOT_FOUND: \a ref refers to an abstract entry. +*/ +status_t +BMimeType::GuessMimeType(const entry_ref *file, BMimeType *result) +{ + return NOT_IMPLEMENTED; +} + +// GuessMimeType +/*! \brief Guesses a MIME type for the supplied chunk of data. + \param buffer Pointer to the data buffer. + \param length Size of the buffer in bytes. + \param result Pointer to a pre-allocated BMimeType which is set to the + resulting MIME type. + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a buffer or \a result. +*/ +status_t +BMimeType::GuessMimeType(const void *buffer, int32 length, BMimeType *result) +{ + return NOT_IMPLEMENTED; +} + +// GuessMimeType +/*! \brief Guesses a MIME type for the given filename. + Only the filename itself is taken into consideration (in particular its + name extension), not the entry it refers to. I.e. an entry with that name + doesn't need to exist at all. + + \param filename The filename. + \param result Pointer to a pre-allocated BMimeType which is set to the + resulting MIME type. + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a ref or \a result. +*/ +status_t +BMimeType::GuessMimeType(const char *filename, BMimeType *result) +{ + return NOT_IMPLEMENTED; +} + +// StartWatching +/*! \brief Starts monitoring the MIME database for a given target. + Until StopWatching() is called for the target, an update message is sent + to it, whenever the MIME database changes. + \param target A BMessenger identifying the target for the update messages. + \return + - \c B_OK: Everything went fine. + - An error code otherwise. +*/ +status_t +BMimeType::StartWatching(BMessenger target) +{ + return NOT_IMPLEMENTED; +} + +// StopWatching +/*! \brief Stops monitoring the MIME database for a given target (previously + started via StartWatching()). + \param target A BMessenger identifying the target for the update messages. + \return + - \c B_OK: Everything went fine. + - An error code otherwise. +*/ +status_t +BMimeType::StopWatching(BMessenger target) +{ + return NOT_IMPLEMENTED; +} + +// SetType +/*! \brief Initializes this object to the supplied MIME type. + \deprecated This method has the same semantics as SetTo(). + Use SetTo() instead. +*/ +status_t +BMimeType::SetType(const char *mimeType) +{ + return NOT_IMPLEMENTED; +} + + +void BMimeType::_ReservedMimeType1() {} +void BMimeType::_ReservedMimeType2() {} +void BMimeType::_ReservedMimeType3() {} + +// = +/*! \brief Unimplemented assignment operator. +*/ +BMimeType & +BMimeType::operator=(const BMimeType &) +{ + return *this; // not implemented +} + +// copy constructor +/*! \brief Unimplemented copy constructor. +*/ +BMimeType::BMimeType(const BMimeType &) +{ +} + diff --git a/src/kits/storage/Node.cpp b/src/kits/storage/Node.cpp new file mode 100644 index 0000000000..c1207aa965 --- /dev/null +++ b/src/kits/storage/Node.cpp @@ -0,0 +1,744 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//---------------------------------------------------------------------- +/*! + \file Node.cpp + BNode implementation. +*/ + +#include // for struct attr_info +#include +#include + +#include +#include + +#include "kernel_interface.h" +#include "storage_support.h" + +//---------------------------------------------------------------------- +// node_ref +//---------------------------------------------------------------------- + +// constructor +/*! \brief Creates an uninitialized node_ref object. +*/ +node_ref::node_ref() + : device(-1), + node(-1) +{ +} + +// copy constructor +/*! \brief Creates a copy of the given node_ref object. + \param ref the node_ref to be copied +*/ +node_ref::node_ref(const node_ref &ref) + : device(-1), + node(-1) +{ + *this = ref; +} + +// == +/*! \brief Tests whether this node_ref and the supplied one are equal. + \param ref the node_ref to be compared with + \return \c true, if the objects are equal, \c false otherwise +*/ +bool +node_ref::operator==(const node_ref &ref) const +{ + return (device == ref.device && node == ref.node); +} + +// != +/*! \brief Tests whether this node_ref and the supplied one are not equal. + \param ref the node_ref to be compared with + \return \c false, if the objects are equal, \c true otherwise +*/ +bool +node_ref::operator!=(const node_ref &ref) const +{ + return !(*this == ref); +} + +// = +/*! \brief Makes this node ref a copy of the supplied one. + \param ref the node_ref to be copied + \return a reference to this object +*/ +node_ref& +node_ref::operator=(const node_ref &ref) +{ + device = ref.device; + node = ref.node; + return *this; +} + +//---------------------------------------------------------------------- +// BNode +//---------------------------------------------------------------------- + +/*! \brief Creates an uninitialized BNode object +*/ +BNode::BNode() + : fFd(StorageKit::NullFd), + fAttrFd(StorageKit::NullFd), + fCStatus(B_NO_INIT) +{ +} + +/*! \brief Creates a BNode object and initializes it to the specified + entry_ref. + \param ref the entry_ref referring to the entry +*/ +BNode::BNode(const entry_ref *ref) + : fFd(StorageKit::NullFd), + fAttrFd(StorageKit::NullFd), + fCStatus(B_NO_INIT) +{ + SetTo(ref); +} + +/*! \brief Creates a BNode object and initializes it to the specified + filesystem entry. + \param entry the BEntry representing the entry +*/ +BNode::BNode(const BEntry *entry) + : fFd(StorageKit::NullFd), + fAttrFd(StorageKit::NullFd), + fCStatus(B_NO_INIT) +{ + SetTo(entry); +} + +/*! \brief Creates a BNode object and initializes it to the entry referred + to by the specified path. + \param path the path referring to the entry +*/ +BNode::BNode(const char *path) + : fFd(StorageKit::NullFd), + fAttrFd(StorageKit::NullFd), + fCStatus(B_NO_INIT) +{ + SetTo(path); +} + +/*! \brief Creates a BNode object and initializes it to the entry referred + to by the specified path rooted in the specified directory. + \param dir the BDirectory, relative to which the entry's path name is + given + \param path the entry's path name relative to \a dir +*/ +BNode::BNode(const BDirectory *dir, const char *path) + : fFd(StorageKit::NullFd), + fAttrFd(StorageKit::NullFd), + fCStatus(B_NO_INIT) +{ + SetTo(dir, path); +} + +/*! \brief Creates a copy of the given BNode. + \param node the BNode to be copied +*/ +BNode::BNode(const BNode &node) + : fFd(StorageKit::NullFd), + fAttrFd(StorageKit::NullFd), + fCStatus(B_NO_INIT) +{ + *this = node; +} + +/*! \brief Frees all resources associated with this BNode. +*/ +BNode::~BNode() +{ + Unset(); +} + +/*! \brief Checks whether the object has been properly initialized or not. + \return + - \c B_OK, if the object has been properly initialized, + - an error code, otherwise. +*/ +status_t +BNode::InitCheck() const +{ + return fCStatus; +} + +/*! \brief Fills in the given stat structure with \code stat() \endcode + information for this object. + \param st a pointer to a stat structure to be filled in + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a st. + - another error code, e.g., if the object wasn't properly initialized +*/ +status_t +BNode::GetStat(struct stat *st) const +{ + return (fCStatus != B_OK) ? fCStatus : StorageKit::get_stat(fFd, st) ; +} + +/*! \brief Reinitializes the object to the specified entry_ref. + \param ref the entry_ref referring to the entry + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a ref. + - \c B_ENTRY_NOT_FOUND: The entry could not be found. + - \c B_BUSY: The entry is locked. + \todo Currently implemented using StorageKit::entry_ref_to_path(). + Reimplement! +*/ +status_t +BNode::SetTo(const entry_ref *ref) +{ + Unset(); + char path[B_PATH_NAME_LENGTH + 1]; + status_t error = (ref ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + error = StorageKit::entry_ref_to_path(ref, path, + B_PATH_NAME_LENGTH + 1); + } + if (error == B_OK) + error = SetTo(path); + fCStatus = error; + return error; +} + +/*! \brief Reinitializes the object to the specified filesystem entry. + \param entry the BEntry representing the entry + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a entry. + - \c B_ENTRY_NOT_FOUND: The entry could not be found. + - \c B_BUSY: The entry is locked. + \todo Implemented using SetTo(entry_ref*). Check, if necessary to + reimplement! +*/ +status_t +BNode::SetTo(const BEntry *entry) +{ + Unset(); + entry_ref ref; + status_t error = (entry ? B_OK : B_BAD_VALUE); + if (error == B_OK && entry->InitCheck() != B_OK) + error = B_BAD_VALUE; + if (error == B_OK) + error = entry->GetRef(&ref); + if (error == B_OK) + error = SetTo(&ref); + fCStatus = error; + return error; +} + +/*! \brief Reinitializes the object to the entry referred to by the specified + path. + \param path the path referring to the entry + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a path. + - \c B_ENTRY_NOT_FOUND: The entry could not be found. + - \c B_BUSY: The entry is locked. +*/ +status_t +BNode::SetTo(const char *path) +{ + Unset(); + if (path != NULL) + fCStatus = StorageKit::open(path, O_RDWR | O_NOTRAVERSE, fFd); + return fCStatus; +} + +/*! \brief Reinitializes the object to the entry referred to by the specified + path rooted in the specified directory. + \param dir the BDirectory, relative to which the entry's path name is + given + \param path the entry's path name relative to \a dir + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a dir or \a path. + - \c B_ENTRY_NOT_FOUND: The entry could not be found. + - \c B_BUSY: The entry is locked. + \todo Implemented using SetTo(BEntry*). Check, if necessary to reimplement! +*/ +status_t +BNode::SetTo(const BDirectory *dir, const char *path) +{ + Unset(); + status_t error = (dir && path ? B_OK : B_BAD_VALUE); + if (error == B_OK && StorageKit::is_absolute_path(path)) + error = B_BAD_VALUE; + BEntry entry; + if (error == B_OK) + error = entry.SetTo(dir, path); + if (error == B_OK) + error = SetTo(&entry); + fCStatus = error; + return error; +} + +/*! \brief Returns the object to an uninitialized state. +*/ +void +BNode::Unset() +{ + close_fd(); + fCStatus = B_NO_INIT; +} + +/*! \brief Attains an exclusive lock on the data referred to by this node, so + that it may not be modified by any other objects or methods. + \return + - \c B_OK: Everything went fine. + - \c B_FILE_ERROR: The object is not initialized. + - \c B_BUSY: The node is already locked. + \todo Currently unimplemented; requires new kernel. +*/ +status_t +BNode::Lock() +{ + if (fCStatus != B_OK) + return fCStatus; + + // This will have to wait for the new kenel + return B_FILE_ERROR; + + // We'll need to keep lock around if the kernel function + // doesn't just work on file descriptors +// StorageKit::FileLock lock; +// return StorageKit::lock(fFd, StorageKit::READ_WRITE, &lock); +} + +/*! \brief Unlocks the node. + \return + - \c B_OK: Everything went fine. + - \c B_FILE_ERROR: The object is not initialized. + - \c B_BAD_VALUE: The node is not locked. + \todo Currently unimplemented; requires new kernel. +*/ +status_t +BNode::Unlock() +{ + if (fCStatus != B_OK) + return fCStatus; + // This will have to wait for the new kenel + return B_FILE_ERROR; +} + +/*! \brief Immediately performs any pending disk actions on the node. + \return + - \c B_OK: Everything went fine. + - an error code, if something went wrong. +*/ +status_t +BNode::Sync() +{ + return (fCStatus != B_OK) ? B_FILE_ERROR : StorageKit::sync(fFd) ; +} + +/*! \brief Writes data from a buffer to an attribute. + Write the \a len bytes of data from \a buffer to + the attribute specified by \a name after erasing any data + that existed previously. The type specified by \a type \em is + remembered, and may be queried with GetAttrInfo(). The value of + \a offset is currently ignored. + \param attr the name of the attribute + \param type the type of the attribute + \param offset the index at which to write the data (currently ignored) + \param buffer the buffer containing the data to be written + \param len the number of bytes to be written + \return + - the number of bytes actually written + - \c B_BAD_VALUE: \c NULL \a attr or \a buffer + - \c B_FILE_ERROR: The object is not initialized or the node it refers to + is read only. + - \c B_NOT_ALLOWED: The node resides on a read only volume. + - \c B_DEVICE_FULL: Insufficient disk space. + - \c B_NO_MEMORY: Insufficient memory to complete the operation. +*/ +ssize_t +BNode::WriteAttr(const char *attr, type_code type, off_t offset, + const void *buffer, size_t len) +{ + if (fCStatus != B_OK) + return B_FILE_ERROR; + else { + ssize_t result = StorageKit::write_attr(fFd, attr, type, offset, + buffer, len); + return result; + } +} + +/*! \brief Reads data from an attribute into a buffer. + Reads the data of the attribute given by \a name into + the buffer specified by \a buffer with length specified + by \a len. \a type and \a offset are currently ignored. + \param attr the name of the attribute + \param type the type of the attribute (currently ignored) + \param offset the index from which to read the data (currently ignored) + \param buffer the buffer for the data to be read + \param len the number of bytes to be read + \return + - the number of bytes actually read + - \c B_BAD_VALUE: \c NULL \a attr or \a buffer + - \c B_FILE_ERROR: The object is not initialized. + - \c B_ENTRY_NOT_FOUND: The node has no attribute \a attr. +*/ +ssize_t +BNode::ReadAttr(const char *attr, type_code type, off_t offset, + void *buffer, size_t len) const +{ + if (fCStatus != B_OK) + return B_FILE_ERROR; + else { + ssize_t result = StorageKit::read_attr(fFd, attr, type, offset, buffer, + len); + return result; + } +} + +/*! \brief Deletes the attribute given by \a name. + \param name the name of the attribute + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a name + - \c B_FILE_ERROR: The object is not initialized or the node it refers to + is read only. + - \c B_ENTRY_NOT_FOUND: The node has no attribute \a name. + - \c B_NOT_ALLOWED: The node resides on a read only volume. +*/ +status_t +BNode::RemoveAttr(const char *name) +{ + return (fCStatus != B_OK) ? B_FILE_ERROR + : StorageKit::remove_attr(fFd, name); +} + +/*! \brief Moves the attribute given by \a oldname to \a newname. + If \a newname already exists, the current data is clobbered. + \param oldname the name of the attribute to be renamed + \param newname the new name for the attribute + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a oldname or \a newname + - \c B_FILE_ERROR: The object is not initialized or the node it refers to + is read only. + - \c B_ENTRY_NOT_FOUND: The node has no attribute \a oldname. + - \c B_NOT_ALLOWED: The node resides on a read only volume. +*/ +status_t +BNode::RenameAttr(const char *oldname, const char *newname) +{ + if (fCStatus != B_OK) + return B_FILE_ERROR; + return StorageKit::rename_attr(fFd, oldname, newname); +} + + +/*! \brief Fills in the pre-allocated attr_info struct pointed to by \a info + with useful information about the attribute specified by \a name. + \param name the name of the attribute + \param info the attr_info structure to be filled in + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a name + - \c B_FILE_ERROR: The object is not initialized. + - \c B_ENTRY_NOT_FOUND: The node has no attribute \a name. +*/ +status_t +BNode::GetAttrInfo(const char *name, struct attr_info *info) const +{ + return (fCStatus != B_OK) ? B_FILE_ERROR + : StorageKit::stat_attr(fFd, name, info); +} + +/*! \brief Returns the next attribute in the node's list of attributes. + Every BNode maintains a pointer to its list of attributes. + GetNextAttrName() retrieves the name of the attribute that the pointer is + currently pointing to, and then bumps the pointer to the next attribute. + The name is copied into the buffer, which should be at least + B_ATTR_NAME_LENGTH characters long. The copied name is NULL-terminated. + When you've asked for every name in the list, GetNextAttrName() + returns \c B_ENTRY_NOT_FOUND. + \param buffer the buffer the name of the next attribute shall be stored in + (must be at least \c B_ATTR_NAME_LENGTH bytes long) + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a buffer. + - \c B_FILE_ERROR: The object is not initialized. + - \c B_ENTRY_NOT_FOUND: There are no more attributes, the last attribute + name has already been returned. + */ +status_t +BNode::GetNextAttrName(char *buffer) +{ + // We're allowed to assume buffer is at least + // B_BUFFER_NAME_LENGTH chars long, but NULLs + // are not acceptable. + if (buffer == NULL) + return B_BAD_VALUE; // /new R5 crashed when passed NULL + if (InitAttrDir() != B_OK) + return B_FILE_ERROR; + + StorageKit::LongDirEntry entry; + status_t error = StorageKit::read_attr_dir(fAttrFd, entry); + if (error == B_OK) { + strncpy(buffer, entry.d_name, B_ATTR_NAME_LENGTH); + return B_OK; + } + return error; +} + +/*! \brief Resets the object's attribute pointer to the first attribute in the + list. + \return + - \c B_OK: Everything went fine. + - \c B_FILE_ERROR: Some error occured. +*/ +status_t +BNode::RewindAttrs() +{ + if (InitAttrDir() != B_OK) + return B_FILE_ERROR; + StorageKit::rewind_attr_dir(fAttrFd); + return B_OK; +} + +/*! Writes the specified string to the specified attribute, clobbering any + previous data. + \param name the name of the attribute + \param data the BString to be written to the attribute + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a name or \a data + - \c B_FILE_ERROR: The object is not initialized or the node it refers to + is read only. + - \c B_NOT_ALLOWED: The node resides on a read only volume. + - \c B_DEVICE_FULL: Insufficient disk space. + - \c B_NO_MEMORY: Insufficient memory to complete the operation. +*/ +status_t +BNode::WriteAttrString(const char *name, const BString *data) +{ + status_t error = (!name || !data) ? B_BAD_VALUE : B_OK; + if (error == B_OK) { + int32 len = data->Length(); + ssize_t sizeWritten = WriteAttr(name, B_STRING_TYPE, 0, data->String(), + len); + if (sizeWritten != len) + error = sizeWritten; + } + return error; +} + +/*! \brief Reads the data of the specified attribute into the pre-allocated + \a result. + \param name the name of the attribute + \param result the BString to be set to the value of the attribute + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a name or \a result + - \c B_FILE_ERROR: The object is not initialized. + - \c B_ENTRY_NOT_FOUND: The node has no attribute \a attr. +*/ +status_t +BNode::ReadAttrString(const char *name, BString *result) const +{ + if (!name || !result) + return B_BAD_VALUE; + + attr_info info; + status_t error; + + error = GetAttrInfo(name, &info); + if (error != B_OK) + return error; + // Lock the string's buffer so we can meddle with it + char *data = result->LockBuffer(info.size+1); + if (!data) + return B_NO_MEMORY; + // Read the attribute + ssize_t bytes = ReadAttr(name, B_STRING_TYPE, 0, data, info.size); + // Check for failure + if (bytes < 0) { + error = bytes; + bytes = 0; // In this instance, we simply clear the string + } else + error = B_OK; + // Null terminate the new string just to be sure (since it *is* + // possible to read and write non-NULL-terminated strings) + data[bytes] = 0; + result->UnlockBuffer(bytes+1); + return error; +} + +/*! \brief Reinitializes the object as a copy of the \a node. + \param node the BNode to be copied + \return a reference to this BNode object. +*/ +BNode& +BNode::operator=(const BNode &node) +{ + // No need to do any assignment if already equal + if (*this == node) + return *this; + // Close down out current state + Unset(); + // We have to manually dup the node, because R5::BNode::Dup() + // is not declared to be const (which IMO is retarded). + fFd = StorageKit::dup(node.fFd); + fCStatus = (fFd == StorageKit::NullFd) ? B_NO_INIT : B_OK ; + return *this; +} + +/*! Tests whether this and the supplied BNode object are equal. + Two BNode objects are said to be equal if they're set to the same node, + or if they're both \c B_NO_INIT. + \param node the BNode to be compared with + \return \c true, if the BNode objects are equal, \c false otherwise +*/ +bool +BNode::operator==(const BNode &node) const +{ + if (fCStatus == B_NO_INIT && node.InitCheck() == B_NO_INIT) + return true; + if (fCStatus == B_OK && node.InitCheck() == B_OK) { + // Check if they're identical + StorageKit::Stat s1, s2; + if (GetStat(&s1) != B_OK) + return false; + if (node.GetStat(&s2) != B_OK) + return false; + return (s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino); + } + return false; +} + +/*! Tests whether this and the supplied BNode object are not equal. + Two BNode objects are said to be equal if they're set to the same node, + or if they're both \c B_NO_INIT. + \param node the BNode to be compared with + \return \c false, if the BNode objects are equal, \c true otherwise +*/ +bool +BNode::operator!=(const BNode &node) const +{ + return !(*this == node); +} + +/*! \brief Returns a POSIX file descriptor to the node this object refers to. + Remember to call close() on the file descriptor when you're through with + it. + \return a valid file descriptor, or -1, if something went wrong. +*/ +int +BNode::Dup() +{ + return StorageKit::dup(fFd); +} + + +/*! (currently unused) */ +void BNode::_ReservedNode1() { } +void BNode::_ReservedNode2() { } +void BNode::_ReservedNode3() { } +void BNode::_ReservedNode4() { } +void BNode::_ReservedNode5() { } +void BNode::_ReservedNode6() { } + +/*! \brief Sets the node's file descriptor. + Used by each implementation (i.e. BNode, BFile, BDirectory, etc.) to set + the node's file descriptor. This allows each subclass to use the various + file-type specific system calls for opening file descriptors. + \param fd the file descriptor this BNode should be set to (may be -1) + \return \c B_OK, if everything went fine, an error code otherwise. + \note This method calls close_fd() to close previously opened FDs. Thus + derived classes should take care to first call set_fd() and set + class specific resources freed in their close_fd() version + thereafter. +*/ +status_t +BNode::set_fd(StorageKit::FileDescriptor fd) +{ + if (fFd != -1) + close_fd(); + fFd = fd; + return B_OK; +} + +/*! \brief Closes the node's file descriptor(s). + To be implemented by subclasses to close the file descriptor using the + proper system call for the given file-type. This implementation calls + StorageKit::close(fFd) and also StorageKit::close_attr_dir(fAttrDir) + if necessary. +*/ +void +BNode::close_fd() +{ + if (fAttrFd != StorageKit::NullFd) + { + StorageKit::close_attr_dir(fAttrFd); + fAttrFd = StorageKit::NullFd; + } + if (fFd != StorageKit::NullFd) { + close(fFd); + fFd = StorageKit::NullFd; + } +} + +// set_status +/*! \brief Sets the BNode's status. + To be used by derived classes instead of accessing the BNode's private + \c fCStatus member directly. + \param newStatus the new value for the status variable. +*/ +void +BNode::set_status(status_t newStatus) +{ + fCStatus = newStatus; +} + +/*! \brief Modifies a certain setting for this node based on \a what and the + corresponding value in \a st. + Inherited from and called by BStatable. + \param st a stat structure containing the value to be set + \param what specifies what setting to be modified + \return \c B_OK if everything went fine, an error code otherwise. +*/ +status_t +BNode::set_stat(struct stat &st, uint32 what) +{ + if (fCStatus != B_OK) + return B_FILE_ERROR; + return StorageKit::set_stat(fFd, st, what); +} + +/*! \brief Verifies that the BNode has been properly initialized, and then + (if necessary) opens the attribute directory on the node's file + descriptor, storing it in fAttrDir. + \return \c B_OK if everything went fine, an error code otherwise. +*/ +status_t +BNode::InitAttrDir() +{ + if (fCStatus == B_OK && fAttrFd == StorageKit::NullFd) + return StorageKit::open_attr_dir(fFd, fAttrFd); + return fCStatus; +} + +/*! \var BNode::fFd + File descriptor for the given node. +*/ + +/*! \var BNode::fAttrFd + This appears to be passed to the attribute directory functions + like a StorageKit::Dir would be, but it's actually a file descriptor. + Best I can figure, the R5 syscall for reading attributes must've + just taken a file descriptor. Depending on what our kernel ends up + providing, this may or may not be replaced with an Dir* +*/ + +/*! \var BNode::fCStatus + The object's initialization status. +*/ diff --git a/src/kits/storage/Node.notes b/src/kits/storage/Node.notes new file mode 100644 index 0000000000..dd3305e774 --- /dev/null +++ b/src/kits/storage/Node.notes @@ -0,0 +1,11 @@ +Notes concerning the OpenBeOS implementation of BNode: +1. GetNextAttrName returns B_BAD_VALUE when passed a NULL pointer instead of crashing +2. R5::BNode returns B_BAD_ADDRESS when RewindAttrs() fails (not B_FILE_ERROR as claimed in the BeBook). We currently follow suit. +3. RenameAttr() actually works, whereas the R5 version doesn't (apparently because BFS doesn't implement it directly...). +4. Write/ReadAttrString() functions need to be documented (they aren't in the R5 BeBook). +5. ReadAttrString() adds an extra NULL char to the end of the string it reads as a precaution before handing it back to the BString result, since it's possible to read a non-NULL-terminated string of characters from an attribute. +6. Write/ReadAttrString() can't be tested until we have an OpenBeOS implementation of BString. +7. Dup() should be declared const, but it isn't by R5, so our implementation follows suit. +8. Locking is not supported by the Posix implemention of OpenBeOS BNode, due to fcntl(fd, F_SETLK, ...) not being implemented in R5. + + diff --git a/src/kits/storage/NodeInfo.cpp b/src/kits/storage/NodeInfo.cpp new file mode 100644 index 0000000000..d5ffea1203 --- /dev/null +++ b/src/kits/storage/NodeInfo.cpp @@ -0,0 +1,294 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file NodeInfo.cpp + BNodeInfo implementation. +*/ + +#include + +#include + +#include +#include + +#include + +#define NI_BEOS "BEOS" +// I've added a BEOS hash-define incase we wish to change to OBOS +#define NI_TYPE NI_BEOS ":TYPE" +#define NI_PREF NI_BEOS ":PREF_APP" +#define NI_HINT NI_BEOS ":PPATH" +#define NI_ICON "STD_ICON" +#define NI_M_ICON NI_BEOS ":M:" NI_ICON +#define NI_L_ICON NI_BEOS ":L:" NI_ICON +#define NI_ICON_SIZE(k) ((k == B_LARGE_ICON) ? NI_L_ICON : NI_M_ICON ) + + +BNodeInfo::BNodeInfo(BNode *node) +{ + fCStatus = SetTo(node); +} + +BNodeInfo::~BNodeInfo() +{ +} + +status_t +BNodeInfo::SetTo(BNode *node) +{ + fCStatus = B_BAD_VALUE; + if(node != NULL) { + fCStatus = node->InitCheck(); + fNode = node; + } + return fCStatus; +} + +status_t +BNodeInfo::InitCheck() const +{ + return fCStatus; +} + +status_t +BNodeInfo::GetType(char *type) const +{ + if(type == NULL) return; + if(fCStatus == B_OK) { + attr_info attrInfo; + status_t error; + + error = fNode->GetAttrInfo(NI_TYPE, &attrInfo); + if(error == B_OK) { + error = fNode->ReadAttr(NI_TYPE, attrInfo.type, 0, type, + attrInfo.size); + } + // Future Idea: Add a bit to identify based on extention etc + // see CVS verion 1.6 for big chuck of the code. + + return (error > B_OK ? B_OK : error); + } else + return B_NO_INIT; +} + +status_t +BNodeInfo::SetType(const char *type) +{ + if( fCStatus == B_OK ) { + status_t error; + error = fNode->WriteAttr(NI_TYPE, B_STRING_TYPE, 0, type, sizeof(type)); + return ( error > B_OK ? B_OK : error ); + } else + return B_NO_INIT; +} + + +status_t +BNodeInfo::GetIcon(BBitmap *icon, icon_size k = B_LARGE_ICON) const +{ + if(fCStatus == B_OK) { + attr_info attrInfo; + int error; + + error = fNode->GetAttrInfo(NI_ICON_SIZE(k), &attrInfo); + if(error == B_OK) { + + error = fNode->ReadAttr(NI_ICON_SIZE(k), attrInfo.type, 0, icon, + attrInfo.size); + } + + return (error > B_OK ? B_OK : error); + } else + return B_NO_INIT; +} + +status_t +BNodeInfo::SetIcon(const BBitmap *icon, icon_size k = B_LARGE_ICON) +{ + if( fCStatus == B_OK ) { + return fNode->WriteAttr(NI_ICON_SIZE(k), B_COLOR_8_BIT_TYPE, + 0, icon, sizeof(icon)); + } else + return B_NO_INIT; +} + +status_t +BNodeInfo::GetPreferredApp(char *signature, + app_verb verb = B_OPEN) const +{ + if(fCStatus == B_OK) { + attr_info attrInfo; + int error; + + error = fNode->GetAttrInfo(NI_PREF, &attrInfo); + if(error == B_OK) { + + error = fNode->ReadAttr(NI_PREF, attrInfo.type, 0, + signature, attrInfo.size); + if(error < B_OK) { + char *mimetpye = new(nothrow) char[B_MIME_TYPE_LENGTH]; + if (mimetype) { + if( GetMineType(mimetype) >= B_OK ) { + BMimeType mime(mimetype); + error = mine.GetPreferredApp(signature, verb); + } + + delete minetype; + } else + error = B_NO_MEMORY; + } + } + + return (error > B_OK ? B_OK : error); + } else + return B_NO_INIT; +} + +status_t +BNodeInfo::SetPreferredApp(const char *signature, + app_verb verb = B_OPEN) +{ + + if(size_of(signature) > B_MIME_TYPE_LENGTH) + return B_BAD_VALUE; + + if( fCStatus == B_OK ) { + return fNode->WriteAttr(NI_PREF, B_STRING_TYPE, + 0, signature, sizeof(signature)); + } else + return B_NO_INIT; +} + +status_t +BNodeInfo::GetAppHint(entry_ref *ref) const +{ + if(fCStatus == B_OK) { + attr_info attrInfo; + status_t error; + + error = fNode->GetAttrInfo(NI_HINT, &attrInfo); + if(error == B_OK) { + + error = fNode->ReadAttr(NI_HINT, attrInfo.type, 0, + ref, attrInfo.size); + if(error < B_OK) { + char *mimetype = new(nothrow) char[B_MIME_TYPE_LENGTH]; + if (mimetype) { + if( GetMineType(mimetype) >= B_OK ) { + BMimeType mime(mimetype); + error = mime.GetAppHint(ref); + } + + delete minetype; + } else + error = B_NO_MEMORY; + } + } + + return (error > B_OK ? B_OK : error); + } else + return B_NO_INIT; +} + +status_t +BNodeInfo::SetAppHint(const entry_ref *ref) +{ + if( fCStatus == B_OK ) { + return fNode->WriteAttr(NI_HINT, B_REF_TYPE, + 0, ref, sizeof(ref)); + } else + return B_NO_INIT; +} + +status_t +BNodeInfo::GetTrackerIcon(BBitmap *icon, + icon_size k = B_LARGE_ICON) const +{ + status_t getIconReturn = GetIcon(icon, k); + entry_ref ref; + char mimetype[B_MIME_TYPE_LENGTH]; + + // Ask the attr + if(getIconReturn == B_OK) + return OK; + + // Ask the File Type db based on app sig + if( GetAppHint(&ref) == B_OK ) { + BFile appFile(ref); + if(appFile.InitCheck() == B_OK) { + BAppFileInfo appFileInfo( appFile ); + if( appFileInfo.GetIcon( icon, k ) == B_OK) { + return B_OK; + } + } + } + + // Ask FTdb based on mime type + + if( GetMimeType(&mimetype) ) { + if( BMimeType.GetIconForType(mimetype, icon, k) == B_OK) + return B_OK; + + // asks the File Type database for the preferred app based on the node's + // file type, and then asks that app for the icon it uses to display this + // node's file type. + BMimeType mime(mimetype); + if( mime.GetAppHint(&ref) == B_OK ) { + BFile appFile(ref); + if(appFile.InitCheck() == B_OK) { + BAppFileInfo appFileInfo( appFile ); + if( appFileInfo.GetIcon( icon, k ) == B_OK) { + return B_OK; + } + } + } + + } + + // Quit + return getIconReturn; +} + + +status_t +BNodeInfo::GetTrackerIcon(const entry_ref *ref, + BBitmap *icon, + icon_size k = B_LARGE_ICON) +{ + BNode node(ref); + if( node.InitCheck() == B_OK ) { + BNodeInfo nodeInfo(node); + if( nodeInfo.InitCheck() == B_OK ) { + return nodeInfo.GetTrackerIcon(icon, k); + } + } + return B_NO_INIT; +} + +void +BNodeInfo::_ReservedNodeInfo1() +{ +} + +void +BNodeInfo::_ReservedNodeInfo2() +{ +} + +void +BNodeInfo::_ReservedNodeInfo3() +{ +} + +BNodeInfo & +BNodeInfo::operator=(const BNodeInfo &nodeInfo) +{ + return *this; +} + +BNodeInfo::BNodeInfo(const BNodeInfo &) +{ +} diff --git a/src/kits/storage/OffsetFile.cpp b/src/kits/storage/OffsetFile.cpp new file mode 100644 index 0000000000..ba669664a7 --- /dev/null +++ b/src/kits/storage/OffsetFile.cpp @@ -0,0 +1,171 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file OffsetFile.cpp + OffsetFile implementation. +*/ + +#include + +#include "OffsetFile.h" + +namespace StorageKit { + +// constructor +OffsetFile::OffsetFile() + : fFile(), + fOffset(0), + fCurrentPosition(0) +{ +} + +// constructor +OffsetFile::OffsetFile(BFile *file, off_t offset) + : fFile(NULL), + fOffset(0), + fCurrentPosition(0) +{ + SetTo(file, offset); +} + +// destructor +OffsetFile::~OffsetFile() +{ +} + +// SetTo +status_t +OffsetFile::SetTo(BFile *file, off_t offset) +{ + Unset(); + fFile = file; + fOffset = offset; + return fFile->InitCheck(); +} + +// Unset +void +OffsetFile::Unset() +{ + fFile = NULL; + fOffset = 0; + fCurrentPosition = 0; +} + +// InitCheck +status_t +OffsetFile::InitCheck() const +{ + return (fFile ? fFile->InitCheck() : B_NO_INIT); +} + +// File +BFile * +OffsetFile::File() const +{ + return fFile; +} + +// ReadAt +ssize_t +OffsetFile::ReadAt(off_t pos, void *buffer, size_t size) +{ + status_t error = InitCheck(); + ssize_t result = 0; + if (error == B_OK) + result = fFile->ReadAt(pos + fOffset, buffer, size); + return (error == B_OK ? result : error); +} + +// WriteAt +ssize_t +OffsetFile::WriteAt(off_t pos, const void *buffer, size_t size) +{ + status_t error = InitCheck(); + ssize_t result = 0; + if (error == B_OK) + result = fFile->WriteAt(pos + fOffset, buffer, size); + return (error == B_OK ? result : error); +} + +// Seek +off_t +OffsetFile::Seek(off_t position, uint32 seekMode) +{ + off_t result = B_BAD_VALUE; + status_t error = InitCheck(); + if (error == B_OK) { + switch (seekMode) { + case SEEK_SET: + if (position >= 0) + result = fCurrentPosition = position; + break; + case SEEK_END: + { + off_t size; + error = GetSize(&size); + if (error == B_OK) { + if (size + position >= 0) + result = fCurrentPosition = size + position; + } + break; + } + case SEEK_CUR: + if (fCurrentPosition + position >= 0) + result = fCurrentPosition += position; + break; + default: + break; + } + } + return (error == B_OK ? result : error); +} + +// Position +off_t +OffsetFile::Position() const +{ + return fCurrentPosition; +} + +// SetSize +status_t +OffsetFile::SetSize(off_t size) +{ + status_t error = (size >= 0 ? B_OK : B_BAD_VALUE ); + if (error == B_OK) + error = InitCheck(); + if (error == B_OK) + error = fFile->SetSize(size + fOffset); + return error; +} + +// GetSize +status_t +OffsetFile::GetSize(off_t *size) +{ + status_t error = (size ? B_OK : B_BAD_VALUE ); + if (error == B_OK) + error = InitCheck(); + if (error == B_OK) + error = fFile->GetSize(size); + if (error == B_OK) { + *size -= fOffset; + if (*size < 0) + *size = 0; + } + return error; +} + +// Offset +off_t +OffsetFile::Offset() const +{ + return fOffset; +} + + +}; // namespace StorageKit + diff --git a/src/kits/storage/Path.cpp b/src/kits/storage/Path.cpp new file mode 100644 index 0000000000..16e12daf41 --- /dev/null +++ b/src/kits/storage/Path.cpp @@ -0,0 +1,716 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file Path.cpp + BPath implementation. +*/ + +#include + +#include +#include +#include +#include +#include +#include "kernel_interface.h" +#include "storage_support.h" + +#ifdef USE_OPENBEOS_NAMESPACE +using namespace OpenBeOS; +#endif + +//! Creates an uninitialized BPath object. +BPath::BPath() + : fName(NULL), + fCStatus(B_NO_INIT) +{ +} + +//! Creates a copy of the given BPath object. +/*! \param path the object to be copied +*/ +BPath::BPath(const BPath &path) + : fName(NULL), + fCStatus(B_NO_INIT) +{ + *this = path; +} + +/*! \brief Creates a BPath object and initializes it to the filesystem entry + specified by the given entry_ref struct. + \param ref the entry_ref +*/ +BPath::BPath(const entry_ref *ref) + : fName(NULL), + fCStatus(B_NO_INIT) +{ + SetTo(ref); +} + +/*! Creates a BPath object and initializes it to the filesystem entry + specified by the given BEntry object. + \param entry the BEntry object +*/ +BPath::BPath(const BEntry *entry) + : fName(NULL), + fCStatus(B_NO_INIT) +{ + SetTo(entry); +} + +/*! \brief Creates a BPath object and initializes it to the specified path or + path and filename combination. + \param dir The base component of the pathname. May be absolute or relative. + If relative, it is reckoned off the current working directory. + \param leaf The (optional) leaf component of the pathname. Must be + relative. The value of leaf is concatenated to the end of \a dir + (a "/" will be added as a separator, if necessary). + \param normalize boolean flag used to force normalization; normalization + may occur even if false (see \ref MustNormalize). +*/ +BPath::BPath(const char *dir, const char *leaf, bool normalize) + : fName(NULL), + fCStatus(B_NO_INIT) +{ + SetTo(dir, leaf, normalize); +} + +/*! \brief Creates a BPath object and initializes it to the specified directory + and filename combination. + \param dir Refers to the directory that provides the base component of the + pathname. + \param leaf The (optional) leaf component of the pathname. Must be + relative. The value of leaf is concatenated to the end of \a dir + (a "/" will be added as a separator, if necessary). + \param normalize boolean flag used to force normalization; normalization + may occur even if false (see \ref MustNormalize). +*/ +BPath::BPath(const BDirectory *dir, const char *leaf, bool normalize) + : fName(NULL), + fCStatus(B_NO_INIT) +{ + SetTo(dir, leaf, normalize); +} + +//! Destroys the BPath object and frees any of its associated resources. +BPath::~BPath() +{ + Unset(); +} + +//! Returns the status of the most recent construction or SetTo() call. +/*! \return \c B_OK, if the BPath object is properly initialized, an error + code otherwise. +*/ +status_t +BPath::InitCheck() const +{ + return fCStatus; +} + +/*! \brief Reinitializes the object to the filesystem entry specified by the + given entry_ref struct. + \param ref the entry_ref + \return + - \c B_OK: The initialization was successful. + - \c B_BAD_VALUE: \c NULL \a ref. + - \c B_NAME_TOO_LONG: The pathname is longer than \c B_PATH_NAME_LENGTH. + - other error codes. +*/ +status_t +BPath::SetTo(const entry_ref *ref) +{ + Unset(); + status_t error = (ref ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + char path[B_PATH_NAME_LENGTH + 1]; + error = StorageKit::entry_ref_to_path(ref, path, sizeof(path)); + if (error == B_OK) + error = set_path(path); // the path is already normalized + } + fCStatus = error; + return error; +} + +/*! \brief Reinitializes the object to the specified filesystem entry. + \param entry the BEntry + \return + - \c B_OK: The initialization was successful. + - \c B_BAD_VALUE: \c NULL \a entry. + - \c B_NAME_TOO_LONG: The pathname is longer than \c B_PATH_NAME_LENGTH. + - other error codes. +*/ +status_t +BPath::SetTo(const BEntry *entry) +{ + Unset(); + status_t error = (entry ? B_OK : B_BAD_VALUE); + entry_ref ref; + if (error == B_OK) + error = entry->GetRef(&ref); + if (error == B_OK) + error = SetTo(&ref); + fCStatus = error; + return error; +} + +/*! \brief Reinitializes the object to the specified path or path and file + name combination. + \param path the path name + \param leaf the leaf name (may be \c NULL) + \param normalize boolean flag used to force normalization; normalization + may occur even if false (see \ref MustNormalize). + \return + - \c B_OK: The initialization was successful. + - \c B_BAD_VALUE: \c NULL \a path or absolute \a leaf. + - \c B_NAME_TOO_LONG: The pathname is longer than \c B_PATH_NAME_LENGTH. + - other error codes. + \note \code path.SetTo(path.Path(), "new leaf") \endcode is safe. +*/ +status_t +BPath::SetTo(const char *path, const char *leaf, bool normalize) +{ + status_t error = (path ? B_OK : B_BAD_VALUE); + if (error == B_OK && leaf && StorageKit::is_absolute_path(leaf)) + error = B_BAD_VALUE; + char newPath[B_PATH_NAME_LENGTH + 1]; + if (error == B_OK) { + // we always normalize relative paths + normalize |= !StorageKit::is_absolute_path(path); + // build a new path from path and leaf + // copy path first + uint32 pathLen = strlen(path); + if (pathLen >= sizeof(newPath)) + error = B_NAME_TOO_LONG; + if (error == B_OK) + strcpy(newPath, path); + // append leaf, if supplied + if (error == B_OK && leaf) { + bool needsSeparator = (pathLen > 0 && path[pathLen - 1] != '/'); + uint32 wholeLen = pathLen + (needsSeparator ? 1 : 0) + + strlen(leaf); + if (wholeLen >= sizeof(newPath)) + error = B_NAME_TOO_LONG; + if (error == B_OK) { + if (needsSeparator) { + newPath[pathLen] = '/'; + pathLen++; + } + strcpy(newPath + pathLen, leaf); + } + } + // check, if necessary to normalize + if (error == B_OK && !normalize) { + try { + normalize = normalize || MustNormalize(newPath); + } catch (BPath::EBadInput) { + error = B_BAD_VALUE; + } + } + // normalize the path, if necessary, otherwise just set it + if (error == B_OK) { + if (normalize) { + char normalizedPath[B_PATH_NAME_LENGTH + 1]; + error = StorageKit::get_canonical_path(newPath, normalizedPath, + sizeof(normalizedPath)); + if (error == B_OK) + error = set_path(normalizedPath); + } else + error = set_path(newPath); + } + } + // cleanup, if something went wrong + if (error != B_OK) + Unset(); + fCStatus = error; + return error; +} + +/*! \brief Reinitializes the object to the specified directory and relative + path combination. + \param dir Refers to the directory that provides the base component of the + pathname. + \param path the relative path name (may be \c NULL) + \param normalize boolean flag used to force normalization; normalization + may occur even if false (see \ref MustNormalize). + \return + - \c B_OK: The initialization was successful. + - \c B_BAD_VALUE: \c NULL \a dir or absolute \a path. + - \c B_NAME_TOO_LONG: The pathname is longer than \c B_PATH_NAME_LENGTH. + - other error codes. +*/ +status_t +BPath::SetTo(const BDirectory *dir, const char *path, bool normalize) +{ + status_t error = (dir && dir->InitCheck() == B_OK ? B_OK : B_BAD_VALUE); + // get the path of the BDirectory + BEntry entry; + if (error == B_OK) + error = dir->GetEntry(&entry); + BPath dirPath; + if (error == B_OK) + error = dirPath.SetTo(&entry); + // let the other version do the work + if (error == B_OK) + error = SetTo(dirPath.Path(), path, normalize); + if (error != B_OK) + Unset(); + fCStatus = error; + return error; +} + +/*! \brief Returns the object to an uninitialized state. The object frees any + resources it allocated and marks itself as uninitialized. +*/ +void +BPath::Unset() +{ + set_path(NULL); + fCStatus = B_NO_INIT; +} + +/*! \brief Appends the given (relative) path to the end of the current path. + This call fails if the path is absolute or the object to which you're + appending is uninitialized. + \param path relative pathname to append to current path (may be \c NULL). + \param normalize boolean flag used to force normalization; normalization + may occur even if false (see \ref MustNormalize). + \return + - \c B_OK: The initialization was successful. + - \c B_BAD_VALUE: The object is not properly initialized. + - \c B_NAME_TOO_LONG: The pathname is longer than \c B_PATH_NAME_LENGTH. + - other error codes. +*/ +status_t +BPath::Append(const char *path, bool normalize) +{ + status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE); + if (error == B_OK) + error = SetTo(Path(), path, normalize); + if (error != B_OK) + Unset(); + fCStatus = error; + return error; +} + +//! Returns the object's complete path name. +/*! \return + - the object's path name, or + - \c NULL, if it is not properly initialized. +*/ +const char * +BPath::Path() const +{ + return fName; +} + +//! Returns the leaf portion of the object's path name. +/*! The leaf portion is defined as the string after the last \c '/'. For + the root path (\c "/") it is the empty string (\c ""). + \return + - the leaf portion of the object's path name, or + - \c NULL, if it is not properly initialized. +*/ +const char * +BPath::Leaf() const +{ + const char *result = NULL; + if (InitCheck() == B_OK) { + result = fName + strlen(fName); + // There should be no need for the second condition, since we deal + // with absolute paths only and those contain at least one '/'. + // However, it doesn't harm. + while (*result != '/' && result > fName) + result--; + result++; + } + return result; +} + +/*! \brief Calls the argument's SetTo() method with the name of the + object's parent directory. + No normalization is done. + \param path the BPath object to be initialized to the parent directory's + path name. + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a path. + - \c B_ENTRY_NOT_FOUND: The object represents \c "/". + - other error code returned by SetTo(). +*/ +status_t +BPath::GetParent(BPath *path) const +{ + status_t error = (path ? B_OK : B_BAD_VALUE); + if (error == B_OK) + error = InitCheck(); + if (error == B_OK) { + int32 len = strlen(fName); + if (len == 1) // handle "/" + error = B_ENTRY_NOT_FOUND; + else { + char parentPath[B_PATH_NAME_LENGTH + 1]; + len--; + while (fName[len] != '/' && len > 0) + len--; + if (len == 0) // parent dir is "/" + len++; + memcpy(parentPath, fName, len); + parentPath[len] = 0; + error = path->SetTo(parentPath); + } + } + return error; +} + +//! Performs a simple (string-wise) comparison of paths. +/*! No normalization takes place! Uninitialized BPath objects are considered + to be equal. + \param item the BPath object to be compared with + \return \c true, if the path names are equal, \c false otherwise. +*/ +bool +BPath::operator==(const BPath &item) const +{ + return (*this == item.Path()); +} + +//! Performs a simple (string-wise) comparison of paths. +/*! No normalization takes place! + \param path the path name to be compared with + \return \c true, if the path names are equal, \c false otherwise. +*/ +bool +BPath::operator==(const char *path) const +{ + return (InitCheck() != B_OK && path == NULL + || fName && path && strcmp(fName, path) == 0); +} + +//! Performs a simple (string-wise) comparison of paths. +/*! No normalization takes place! Uninitialized BPath objects are considered + to be equal. + \param item the BPath object to be compared with + \return \c true, if the path names are not equal, \c false otherwise. +*/ +bool +BPath::operator!=(const BPath &item) const +{ + return !(*this == item); +} + +//! Performs a simple (string-wise) comparison of paths. +/*! No normalization takes place! + \param path the path name to be compared with + \return \c true, if the path names are not equal, \c false otherwise. +*/ +bool +BPath::operator!=(const char *path) const +{ + return !(*this == path); +} + +//! Initializes the object to be a copy of the argument. +/*! \param item the BPath object to be copied + \return \c *this +*/ +BPath& +BPath::operator=(const BPath &item) +{ + if (this != &item) + *this = item.Path(); + return *this; +} + +//! Initializes the object to be a copy of the argument. +/*! Has the same effect as \code SetTo(path) \endcode. + \param path the path name to be assigned to this object + \return \c *this +*/ +BPath& +BPath::operator=(const char *path) +{ + if (path == NULL) + Unset(); + else + SetTo(path); + return *this; +} + + +// BFlattenable functionality + +// that's the layout of a flattened entry_ref +struct flattened_entry_ref { + dev_t device; + ino_t directory; + char name[1]; +}; + +// base size of a flattened entry ref +static const size_t flattened_entry_ref_size + = sizeof(dev_t) + sizeof(ino_t); + + +//! Returns \c false. +/*! Implements BFlattenable. + \return \c false +*/ +bool +BPath::IsFixedSize() const +{ + return false; +} + +//! Returns \c B_REF_TYPE. +/*! Implements BFlattenable. + \return \c B_REF_TYPE +*/ +type_code +BPath::TypeCode() const +{ + return B_REF_TYPE; +} + +/*! \brief Returns the size of the flattened entry_ref structure that + represents the pathname. + Implements BFlattenable. + \return the size needed for flattening. +*/ +ssize_t +BPath::FlattenedSize() const +{ + ssize_t size = flattened_entry_ref_size; + BEntry entry; + entry_ref ref; + if (InitCheck() == B_OK + && entry.SetTo(Path()) == B_OK + && entry.GetRef(&ref) == B_OK) { + size += strlen(ref.name) + 1; + } + return size; +} + +/*! \brief Converts the object's pathname to an entry_ref and writes it into + buffer. + Implements BFlattenable. + \param buffer the buffer the data shall be stored in + \param size the size of \a buffer + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL buffer or the buffer is of insufficient size. + - other error codes. + \todo Reimplement for performance reasons: Don't call FlattenedSize(). +*/ +status_t +BPath::Flatten(void *buffer, ssize_t size) const +{ + status_t error = (buffer ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + ssize_t flattenedSize = FlattenedSize(); + if (flattenedSize < 0) + error = flattenedSize; + if (error == B_OK && size < flattenedSize) + error = B_BAD_VALUE; + if (error == B_OK) { + // convert the path to an entry_ref + BEntry entry; + entry_ref ref; + if (InitCheck() == B_OK && entry.SetTo(Path()) == B_OK) + entry.GetRef(&ref); + // store the entry_ref in the buffer + flattened_entry_ref &fref = *(flattened_entry_ref*)buffer; + fref.device = ref.device; + fref.directory = ref.directory; + if (ref.name) + strcpy(fref.name, ref.name); + } + } + return error; +} + +//! Returns \c true if code is \c B_REF_TYPE, and false otherwise. +/*! Implements BFlattenable. + \param code the type code in question + \return \c true if code is \c B_REF_TYPE, and false otherwise. +*/ +bool +BPath::AllowsTypeCode(type_code code) const +{ + return (code == B_REF_TYPE); +} + +/*! \brief Initializes the BPath with the flattened entry_ref data that's + found in the supplied buffer. + The type code must be \c B_REF_TYPE. + Implements BFlattenable. + \param code the type code of the flattened data + \param buf a pointer to the flattened data + \param size the number of bytes contained in \a buf + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL buffer or the buffer doesn't contain an + entry_ref. + - other error codes. +*/ +status_t +BPath::Unflatten(type_code code, const void *buf, ssize_t size) +{ + Unset(); + status_t error = B_OK; + // check params + if (!(code == B_REF_TYPE && buf + && size >= (ssize_t)flattened_entry_ref_size)) { + error = B_BAD_VALUE; + } + if (error == B_OK) { + if (size == (ssize_t)flattened_entry_ref_size) { + // already Unset(); + } else { + // reconstruct the entry_ref from the buffer + const flattened_entry_ref &fref = *(const flattened_entry_ref*)buf; + BString name(fref.name, size - flattened_entry_ref_size); + entry_ref ref(fref.device, fref.directory, name.String()); + error = SetTo(&ref); + } + } + if (error != B_OK) + fCStatus = error; + return error; +} + +void BPath::_WarPath1() {} +void BPath::_WarPath2() {} +void BPath::_WarPath3() {} + +/*! \brief Sets the supplied path. + The path is copied. If \c NULL, the object's path is set to NULL as well. + The object's old path is deleted. + \param path the path to be set + \return + - \c B_OK: Everything went fine. + - \c B_NO_MEMORY: Insufficient memory. +*/ +status_t +BPath::set_path(const char *path) +{ + status_t error = B_OK; + const char *oldPath = fName; + // set the new path + if (path) { + fName = new(nothrow) char[strlen(path) + 1]; + if (fName) + strcpy(fName, path); + else + error = B_NO_MEMORY; + } else + fName = NULL; + // delete the old one + delete[] oldPath; + return error; +} + + + +/*! \brief Checks a path to see if normalization is required. + + The following items require normalization: + - Relative pathnames (after concatenation; e.g. "boot/ltj") + - The presence of "." or ".." ("/boot/ltj/../ltj/./gwar") + - Redundant slashes ("/boot//ltj") + - A trailing slash ("/boot/ltj/") + + \return + - \c true: \a path requires normalization + - \c false: \a path does not require normalization + + \exception BPath::EBadInput : \a path is \c NULL or an empty string. + + */ +bool +BPath::MustNormalize(const char *path) +{ + // Check for useless input + if (path == NULL || path[0] == 0) + throw BPath::EBadInput(); + + int len = strlen(path); + + /* Look for anything in the string that forces us to normalize: + + No leading / + + any occurence of /./ or /../ or //, or a trailing /. or /.. + + a trailing / + */; + if (path[0] != '/') + return true; // not "/*" + else if (len == 1) + return false; // "/" + else if (len > 1 && path[len-1] == '/') + return true; // "*/" + else { + enum ParseState { + NoMatch, + InitialSlash, + OneDot, + TwoDots + } state = NoMatch; + + for (int i = 0; path[i] != 0; i++) { + switch (state) { + case NoMatch: + if (path[i] == '/') + state = InitialSlash; + break; + + case InitialSlash: + if (path[i] == '/') + return true; // "*//*" + else if (path[i] == '.') + state = OneDot; + else + state = NoMatch; + break; + + case OneDot: + if (path[i] == '/') + return true; // "*/./*" + else if (path[i] == '.') + state = TwoDots; + else + state = NoMatch; + break; + + case TwoDots: + if (path[i] == '/') + return true; // "*/../*" + else + state = NoMatch; + break; + } + } + // If we hit the end of the string while in either + // of these two states, there was a trailing /. or /.. + if (state == OneDot || state == TwoDots) + return true; + else + return false; + } + +} + +/*! \class BPath::EBadInput + \brief Internal exception class thrown by BPath::MustNormalize() when given + invalid input. +*/ + +/*! + \var char *BPath::fName + \brief Pointer to the object's path name string. +*/ + +/*! + \var status_t BPath::fCStatus + \brief The object's initialization status. +*/ diff --git a/src/kits/storage/Query.cpp b/src/kits/storage/Query.cpp new file mode 100644 index 0000000000..17dadb445d --- /dev/null +++ b/src/kits/storage/Query.cpp @@ -0,0 +1,772 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file Query.cpp + BQuery implementation. +*/ +#include + +#include +#include +#include +#include + +#include +#include + +#include "kernel_interface.h" +#include "QueryPredicate.h" + +using namespace StorageKit; + +enum { + NOT_IMPLEMENTED = B_ERROR, +}; + + +// =========================================================================== +// Hack to get a BMessenger's port and token. + +class _TRoster_ { +public: + static inline void get_messenger_port_token(const BMessenger &messenger, + port_id &port, int32 &token) + { + port = messenger.fPort; + token = messenger.fHandlerToken; + } +}; +// =========================================================================== + + +// BQuery + +// constructor +/*! \brief Creates an uninitialized BQuery. +*/ +BQuery::BQuery() + : BEntryList(), + fStack(NULL), + fPredicate(NULL), + fDevice(B_ERROR), + fLive(false), + fPort(B_ERROR), + fToken(0), + fQueryFd(NullFd) +{ +} + +// destructor +/*! \brief Frees all resources associated with the object. +*/ +BQuery::~BQuery() +{ + Clear(); +} + +// Clear +/*! \brief Resets the object to a uninitialized state. + \return \c B_OK +*/ +status_t +BQuery::Clear() +{ + // close the currently open query + status_t error = B_OK; + if (fQueryFd != NullFd) { + error = close_query(fQueryFd); + fQueryFd = NullFd; + } + // delete the predicate stack and the predicate + delete fStack; + fStack = NULL; + delete[] fPredicate; + fPredicate = NULL; + // reset the other parameters + fDevice = B_ERROR; + fLive = false; + fPort = B_ERROR; + fToken = 0; + return error; +} + +// PushAttr +/*! \brief Pushes an attribute name onto the BQuery's predicate stack. + \param attrName the attribute name + \return + - \c B_OK: Everything went fine. + - \c B_NO_MEMORY: Not enough memory. + - \c B_NOT_ALLOWED: PushAttribute() was called after Fetch(). + \note In BeOS R5 this method returns \c void. That is checking the return + value will render your code source and binary incompatible! + Calling PushXYZ() after a Fetch() does change the predicate on R5, + but it doesn't affect the active query and the newly created + predicate can not even be used for the next query, since in order + to be able to reuse the BQuery object for another query, Clear() has + to be called and Clear() also deletes the predicate. +*/ +status_t +BQuery::PushAttr(const char *attrName) +{ + return _PushNode(new(nothrow) AttributeNode(attrName), true); +} + +// PushOp +/*! \brief Pushes an operator onto the BQuery's predicate stack. + \param op the code representing the operator + \return + - \c B_OK: Everything went fine. + - \c B_NO_MEMORY: Not enough memory. + - \c B_NOT_ALLOWED: PushOp() was called after Fetch(). + \note In BeOS R5 this method returns \c void. That is checking the return + value will render your code source and binary incompatible! + Calling PushXYZ() after a Fetch() does change the predicate on R5, + but it doesn't affect the active query and the newly created + predicate can not even be used for the next query, since in order + to be able to reuse the BQuery object for another query, Clear() has + to be called and Clear() also deletes the predicate. +*/ +status_t +BQuery::PushOp(query_op op) +{ + status_t error = B_OK; + switch (op) { + case B_EQ: + case B_GT: + case B_GE: + case B_LT: + case B_LE: + case B_NE: + case B_CONTAINS: + case B_BEGINS_WITH: + case B_ENDS_WITH: + case B_AND: + case B_OR: + error = _PushNode(new(nothrow) BinaryOpNode(op), true); + break; + case B_NOT: + error = _PushNode(new(nothrow) UnaryOpNode(op), true); + break; + default: + error = _PushNode(new(nothrow) SpecialOpNode(op), true); + break; + } + return error; +} + +// PushUInt32 +/*! \brief Pushes a uint32 value onto the BQuery's predicate stack. + \param value the value + \return + - \c B_OK: Everything went fine. + - \c B_NO_MEMORY: Not enough memory. + - \c B_NOT_ALLOWED: PushUInt32() was called after Fetch(). + \note In BeOS R5 this method returns \c void. That is checking the return + value will render your code source and binary incompatible! + Calling PushXYZ() after a Fetch() does change the predicate on R5, + but it doesn't affect the active query and the newly created + predicate can not even be used for the next query, since in order + to be able to reuse the BQuery object for another query, Clear() has + to be called and Clear() also deletes the predicate. +*/ +status_t +BQuery::PushUInt32(uint32 value) +{ + return _PushNode(new(nothrow) UInt32ValueNode(value), true); +} + +// PushInt32 +/*! \brief Pushes an int32 value onto the BQuery's predicate stack. + \param value the value + \return + - \c B_OK: Everything went fine. + - \c B_NO_MEMORY: Not enough memory. + - \c B_NOT_ALLOWED: PushInt32() was called after Fetch(). + \note In BeOS R5 this method returns \c void. That is checking the return + value will render your code source and binary incompatible! + Calling PushXYZ() after a Fetch() does change the predicate on R5, + but it doesn't affect the active query and the newly created + predicate can not even be used for the next query, since in order + to be able to reuse the BQuery object for another query, Clear() has + to be called and Clear() also deletes the predicate. +*/ +status_t +BQuery::PushInt32(int32 value) +{ + return _PushNode(new(nothrow) Int32ValueNode(value), true); +} + +// PushUInt64 +/*! \brief Pushes a uint64 value onto the BQuery's predicate stack. + \param value the value + \return + - \c B_OK: Everything went fine. + - \c B_NO_MEMORY: Not enough memory. + - \c B_NOT_ALLOWED: PushUInt64() was called after Fetch(). + \note In BeOS R5 this method returns \c void. That is checking the return + value will render your code source and binary incompatible! + Calling PushXYZ() after a Fetch() does change the predicate on R5, + but it doesn't affect the active query and the newly created + predicate can not even be used for the next query, since in order + to be able to reuse the BQuery object for another query, Clear() has + to be called and Clear() also deletes the predicate. +*/ +status_t +BQuery::PushUInt64(uint64 value) +{ + return _PushNode(new(nothrow) UInt64ValueNode(value), true); +} + +// PushInt64 +/*! \brief Pushes an int64 value onto the BQuery's predicate stack. + \param value the value + \return + - \c B_OK: Everything went fine. + - \c B_NO_MEMORY: Not enough memory. + - \c B_NOT_ALLOWED: PushInt64() was called after Fetch(). + \note In BeOS R5 this method returns \c void. That is checking the return + value will render your code source and binary incompatible! + Calling PushXYZ() after a Fetch() does change the predicate on R5, + but it doesn't affect the active query and the newly created + predicate can not even be used for the next query, since in order + to be able to reuse the BQuery object for another query, Clear() has + to be called and Clear() also deletes the predicate. +*/ +status_t +BQuery::PushInt64(int64 value) +{ + return _PushNode(new(nothrow) Int64ValueNode(value), true); +} + +// PushFloat +/*! \brief Pushes a float value onto the BQuery's predicate stack. + \param value the value + \return + - \c B_OK: Everything went fine. + - \c B_NO_MEMORY: Not enough memory. + - \c B_NOT_ALLOWED: PushFloat() was called after Fetch(). + \note In BeOS R5 this method returns \c void. That is checking the return + value will render your code source and binary incompatible! + Calling PushXYZ() after a Fetch() does change the predicate on R5, + but it doesn't affect the active query and the newly created + predicate can not even be used for the next query, since in order + to be able to reuse the BQuery object for another query, Clear() has + to be called and Clear() also deletes the predicate. +*/ +status_t +BQuery::PushFloat(float value) +{ + return _PushNode(new(nothrow) FloatValueNode(value), true); +} + +// PushDouble +/*! \brief Pushes a double value onto the BQuery's predicate stack. + \param value the value + \return + - \c B_OK: Everything went fine. + - \c B_NO_MEMORY: Not enough memory. + - \c B_NOT_ALLOWED: PushDouble() was called after Fetch(). + \note In BeOS R5 this method returns \c void. That is checking the return + value will render your code source and binary incompatible! + Calling PushXYZ() after a Fetch() does change the predicate on R5, + but it doesn't affect the active query and the newly created + predicate can not even be used for the next query, since in order + to be able to reuse the BQuery object for another query, Clear() has + to be called and Clear() also deletes the predicate. +*/ +status_t +BQuery::PushDouble(double value) +{ + return _PushNode(new(nothrow) DoubleValueNode(value), true); +} + +// PushString +/*! \brief Pushes a string value onto the BQuery's predicate stack. + \param value the value + \param caseInsensitive \c true, if the case of the string should be + ignored, \c false otherwise + \return + - \c B_OK: Everything went fine. + - \c B_NO_MEMORY: Not enough memory. + - \c B_NOT_ALLOWED: PushString() was called after Fetch(). + \note In BeOS R5 this method returns \c void. That is checking the return + value will render your code source and binary incompatible! + Calling PushXYZ() after a Fetch() does change the predicate on R5, + but it doesn't affect the active query and the newly created + predicate can not even be used for the next query, since in order + to be able to reuse the BQuery object for another query, Clear() has + to be called and Clear() also deletes the predicate. +*/ +status_t +BQuery::PushString(const char *value, bool caseInsensitive) +{ + return _PushNode(new(nothrow) StringNode(value, caseInsensitive), true); +} + +// PushDate +/*! \brief Pushes a date value onto the BQuery's predicate stack. + The supplied date can be any string understood by the POSIX function + parsedate(). + \param date the date string + \return + - \c B_OK: Everything went fine. + - \c B_ERROR: Error parsing the string. + - \c B_NOT_ALLOWED: PushDate() was called after Fetch(). + \note Calling PushXYZ() after a Fetch() does change the predicate on R5, + but it doesn't affect the active query and the newly created + predicate can not even be used for the next query, since in order + to be able to reuse the BQuery object for another query, Clear() has + to be called and Clear() also deletes the predicate. +*/ +status_t +BQuery::PushDate(const char *date) +{ + status_t error = (date ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + time_t t; + time(&t); + t = parsedate(date, t); + if (t < 0) { +// error = t; + error = B_BAD_VALUE; + } + } + if (error == B_OK) + error = _PushNode(new(nothrow) DateNode(date), true); + return error; +} + +// SetVolume +/*! \brief Sets the BQuery's volume. + A query is restricted to one volume. This method sets this volume. It + fails, if called after Fetch(). To reuse a BQuery object it has to be + reset via Clear(). + \param volume the volume + \return + - \c B_OK: Everything went fine. + - \c B_NOT_ALLOWED: SetVolume() was called after Fetch(). +*/ +status_t +BQuery::SetVolume(const BVolume *volume) +{ + status_t error = (volume ? B_OK : B_BAD_VALUE); + if (error == B_OK && _HasFetched()) + error = B_NOT_ALLOWED; + if (error == B_OK) { + if (volume->InitCheck() == B_OK) + fDevice = volume->Device(); + else + fDevice = B_ERROR; + } + return error; +} + +// SetPredicate +/*! \brief Sets the BQuery's predicate. + A predicate can be set either using this method or constructing one on + the predicate stack. The two methods can not be mixed. The letter one + has precedence over this one. + The method fails, if called after Fetch(). To reuse a BQuery object it has + to be reset via Clear(). + \param predicate the predicate string + \return + - \c B_OK: Everything went fine. + - \c B_NOT_ALLOWED: SetPredicate() was called after Fetch(). + - \c B_NO_MEMORY: Insufficient memory to store the predicate. +*/ +status_t +BQuery::SetPredicate(const char *expression) +{ + status_t error = (expression ? B_OK : B_BAD_VALUE); + if (error == B_OK && _HasFetched()) + error = B_NOT_ALLOWED; + if (error == B_OK) + error = _SetPredicate(expression); + return error; +} + +// SetTarget +/*! \brief Sets the BQuery's target and makes the query live. + The query update messages are sent to the specified target. They might + roll in immediately after calling Fetch(). + This methods fails, if called after Fetch(). To reuse a BQuery object it + has to be reset via Clear(). + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \a messenger was not properly initialized. + - \c B_NOT_ALLOWED: SetTarget() was called after Fetch(). +*/ +status_t +BQuery::SetTarget(BMessenger messenger) +{ + status_t error = (messenger.IsValid() ? B_OK : B_BAD_VALUE); + if (error == B_OK && _HasFetched()) + error = B_NOT_ALLOWED; + if (error == B_OK) { + _TRoster_::get_messenger_port_token(messenger, fPort, fToken); + fLive = true; + } + return error; +} + +// IsLive +/*! \brief Returns whether the query associated with this object is live. + \return \c true, if the query is live, \c false otherwise +*/ +bool +BQuery::IsLive() const +{ + return fLive; +} + +// GetPredicate +/*! \brief Returns the BQuery's predicate. + Regardless of whether the predicate has been constructed using the + predicate stack or set via SetPredicate(), this method returns a + string representation. + \param buffer a pointer to a buffer into which the predicate shall be + written + \param length the size of the provided buffer + \return + - \c B_OK: Everything went fine. + - \c B_NO_INIT: The predicate isn't set. + - \c B_BAD_VALUE: \a buffer is \c NULL or too short. + \note This method causes the predicate stack to be evaluated and cleared. + You can't interleave Push*() and GetPredicate() calls. +*/ +status_t +BQuery::GetPredicate(char *buffer, size_t length) +{ + status_t error = (buffer ? B_OK : B_BAD_VALUE); + if (error == B_OK) +// error = _EvaluateStack(); + _EvaluateStack(); + if (error == B_OK && !fPredicate) + error = B_NO_INIT; + if (error == B_OK && length <= strlen(fPredicate)) + error = B_BAD_VALUE; + if (error == B_OK) + strcpy(buffer, fPredicate); + return error; +} + +// GetPredicate +/*! \brief Returns the BQuery's predicate. + Regardless of whether the predicate has been constructed using the + predicate stack or set via SetPredicate(), this method returns a + string representation. + \param predicate a pointer to a BString which shall be set to the + predicate string + \return + - \c B_OK: Everything went fine. + - \c B_NO_INIT: The predicate isn't set. + - \c B_BAD_VALUE: \c NULL \a predicate. + \note This method causes the predicate stack to be evaluated and cleared. + You can't interleave Push*() and GetPredicate() calls. +*/ +status_t +BQuery::GetPredicate(BString *predicate) +{ + status_t error = (predicate ? B_OK : B_BAD_VALUE); + if (error == B_OK) +// error = _EvaluateStack(); + _EvaluateStack(); + if (error == B_OK && !fPredicate) + error = B_NO_INIT; + if (error == B_OK) + predicate->SetTo(fPredicate); + return error; +} + +// PredicateLength +/*! \brief Returns the length of the BQuery's predicate string. + Regardless of whether the predicate has been constructed using the + predicate stack or set via SetPredicate(), this method returns the length + of its string representation (counting the terminating null). + \return + - the length of the predicate string (counting the terminating null) or + - 0, if an error occured + \note This method causes the predicate stack to be evaluated and cleared. + You can't interleave Push*() and PredicateLength() calls. +*/ +size_t +BQuery::PredicateLength() +{ + status_t error = _EvaluateStack(); + if (error == B_OK && !fPredicate) + error = B_NO_INIT; + size_t size = 0; + if (error == B_OK) + size = strlen(fPredicate) + 1; + return size; +} + +// TargetDevice +/*! \brief Returns the device ID identifying the BQuery's volume. + \return the device ID of the BQuery's volume or \c B_NO_INIT, if the + volume isn't set. + +*/ +dev_t +BQuery::TargetDevice() const +{ + return fDevice; +} + +// Fetch +/*! \brief Tells the BQuery to start fetching entries satisfying the predicate. + After Fetch() has been called GetNextEntry(), GetNextRef() and + GetNextDirents() can be used to retrieve the enties. Live query updates + may be sent immediately after this method has been called. + Fetch() fails, if it has already been called. To reuse a BQuery object it + has to be reset via Clear(). + \return + - \c B_OK: Everything went fine. + - \c B_NO_INIT: The predicate or the volume aren't set. + - \c B_BAD_VALUE: The predicate is invalid. + - \c B_NOT_ALLOWED: Fetch() has already been called. +*/ +status_t +BQuery::Fetch() +{ + status_t error = (_HasFetched() ? B_NOT_ALLOWED : B_OK); + if (error == B_OK) +// error = _EvaluateStack(); + _EvaluateStack(); + if (error == B_OK && (!fPredicate || fDevice < 0)) + error = B_NO_INIT; + if (error == B_OK) { + if (fLive) { + error = open_live_query(fDevice, fPredicate, B_LIVE_QUERY, fPort, + fToken, fQueryFd); + } else + error = open_query(fDevice, fPredicate, 0, fQueryFd); + } + return error; +} + + +// BEntryList interface + +// GetNextEntry +/*! \brief Returns the BQuery's next entry as a BEntry. + Places the next entry in the list in \a entry, traversing symlinks if + \a traverse is \c true. + \param entry a pointer to a BEntry to be initialized with the found entry + \param traverse specifies whether to follow it, if the found entry + is a symbolic link. + \note The iterator used by this method is the same one used by + GetNextRef() and GetNextDirents(). + \return + - \c B_OK if successful, + - \c B_ENTRY_NOT_FOUND when at the end of the list, + - \c B_BAD_VALUE: The queries predicate includes unindexed attributes. + - \c B_FILE_ERROR: Fetch() has not been called before. +*/ +status_t +BQuery::GetNextEntry(BEntry *entry, bool traverse) +{ + status_t error = (entry ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + entry_ref ref; + error = GetNextRef(&ref); + if (error == B_OK) + error = entry->SetTo(&ref, traverse); + } + return error; +} + +// GetNextRef +/*! \brief Returns the BQuery's next entry as an entry_ref. + Places an entry_ref to the next entry in the list into \a ref. + \param ref a pointer to an entry_ref to be filled in with the data of the + found entry + \note The iterator used by this method is the same one used by + GetNextEntry() and GetNextDirents(). + \return + - \c B_OK if successful, + - \c B_ENTRY_NOT_FOUND when at the end of the list, + - \c B_BAD_VALUE: The queries predicate includes unindexed attributes. + - \c B_FILE_ERROR: Fetch() has not been called before. +*/ +status_t +BQuery::GetNextRef(entry_ref *ref) +{ + status_t error = (ref ? B_OK : B_BAD_VALUE); + if (error == B_OK && !_HasFetched()) + error = B_FILE_ERROR; + if (error == B_OK) { + StorageKit::LongDirEntry entry; + if (StorageKit::read_query(fQueryFd, &entry, sizeof(entry), 1) != 1) + error = B_ENTRY_NOT_FOUND; + if (error == B_OK) + *ref = entry_ref(entry.d_pdev, entry.d_pino, entry.d_name); + } + return error; +} + +// GetNextDirents +/*! \brief Returns the BQuery's next entries as dirent structures. + Reads a number of entries into the array of dirent structures pointed to by + \a buf. Reads as many but no more than \a count entries, as many entries as + remain, or as many entries as will fit into the array at \a buf with given + length \a length (in bytes), whichever is smallest. + \param buf a pointer to a buffer to be filled with dirent structures of + the found entries + \param length the maximal number of entries to be read. + \note The iterator used by this method is the same one used by + GetNextEntry() and GetNextRef(). + \return + - The number of dirent structures stored in the buffer, 0 when there are + no more entries to be read. + - \c B_BAD_VALUE: The queries predicate includes unindexed attributes. + - \c B_FILE_ERROR: Fetch() has not been called before. +*/ +int32 +BQuery::GetNextDirents(struct dirent *buf, size_t length, int32 count) +{ + int32 result = (buf ? B_OK : B_BAD_VALUE); + if (result == B_OK && !_HasFetched()) + result = B_FILE_ERROR; + if (result == B_OK) + result = read_query(fQueryFd, buf, length, count); + return result; +} + +// Rewind +/*! \brief Unimplemented method of the BEntryList interface. + \return \c B_ERROR. +*/ +status_t +BQuery::Rewind() +{ + return B_ERROR; +} + +// CountEntries +/*! \brief Unimplemented method of the BEntryList interface. + \return 0. +*/ +int32 +BQuery::CountEntries() +{ + return B_ERROR; +} + +// _HasFetched +/*! Returns whether Fetch() has already been called on this object. + \return \c true, if Fetch() has successfully been invoked, \c false + otherwise. +*/ +bool +BQuery::_HasFetched() const +{ + return (fQueryFd != NullFd); +} + +// _PushNode +/*! \brief Pushs a node onto the predicate stack. + If the stack has not been allocate until this time, this method does + allocate it. + If the supplied node is \c NULL, it is assumed that there was not enough + memory to allocate the node and thus \c B_NO_MEMORY is returned. + In case the method fails, the caller retains the ownership of the supplied + node and thus is responsible for deleting it, if \a deleteOnError is + \c false. If it is \c true, the node is deleted, if an error occurs. + \param node the node to be pushed + \param deleteOnError + \return + - \c B_OK: Everything went fine. + - \c B_NO_MEMORY: \c NULL \a node or insuffient memory to allocate the + predicate stack or push the node. + - \c B_NOT_ALLOWED: _PushNode() was called after Fetch(). +*/ +status_t +BQuery::_PushNode(QueryNode *node, bool deleteOnError) +{ + status_t error = (node ? B_OK : B_NO_MEMORY); + if (error == B_OK && _HasFetched()) + error = B_NOT_ALLOWED; + // allocate the stack, if necessary + if (error == B_OK && !fStack) { + fStack = new(nothrow) QueryStack; + if (!fStack) + error = B_NO_MEMORY; + } + if (error == B_OK) + error = fStack->PushNode(node); + if (error != B_OK && deleteOnError) + delete node; + return error; +} + +// _SetPredicate +/*! \brief Helper method to set the BQuery's predicate. + It is not checked whether Fetch() has already been invoked. + \param predicate the predicate string + \return + - \c B_OK: Everything went fine. + - \c B_NO_MEMORY: Insufficient memory to store the predicate. +*/ +status_t +BQuery::_SetPredicate(const char *expression) +{ + status_t error = B_OK; + // unset the old predicate + delete[] fPredicate; + fPredicate = NULL; + // set the new one + if (expression) { + fPredicate = new(nothrow) char[strlen(expression) + 1]; + if (fPredicate) + strcpy(fPredicate, expression); + else + error = B_NO_MEMORY; + } + return error; +} + +// _EvaluateStack +/*! Evaluates the query's predicate stack. + The method does nothing (and returns \c B_OK), if the stack is \c NULL. + If the stack is non-null and Fetch() has already been called, the method + fails. + \return + - \c B_OK: Everything went fine. + - \c B_NO_MEMORY: Insufficient memory. + - \c B_NOT_ALLOWED: _EvaluateStack() was called after Fetch(). + - another error code +*/ +status_t +BQuery::_EvaluateStack() +{ + status_t error = B_OK; + if (fStack) { + _SetPredicate(NULL); + if (_HasFetched()) + error = B_NOT_ALLOWED; + // convert the stack to a tree and evaluate it + QueryNode *node = NULL; + if (error == B_OK) + error = fStack->ConvertToTree(node); + BString predicate; + if (error == B_OK) + error = node->GetString(predicate); + if (error == B_OK) + error = _SetPredicate(predicate.String()); + delete fStack; + fStack = NULL; + } + return error; +} + + +// FBC +void BQuery::_ReservedQuery1() {} +void BQuery::_ReservedQuery2() {} +void BQuery::_ReservedQuery3() {} +void BQuery::_ReservedQuery4() {} +void BQuery::_ReservedQuery5() {} +void BQuery::_ReservedQuery6() {} diff --git a/src/kits/storage/QueryPredicate.cpp b/src/kits/storage/QueryPredicate.cpp new file mode 100644 index 0000000000..fc3cec4d94 --- /dev/null +++ b/src/kits/storage/QueryPredicate.cpp @@ -0,0 +1,485 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file QueryPredicate.cpp + BQuery predicate helper classes implementation. +*/ +#include "QueryPredicate.h" + +#include + +namespace StorageKit { + +// QueryNode + +// constructor +QueryNode::QueryNode() +{ +} + +// destructor +QueryNode::~QueryNode() +{ +} + + +// LeafNode + +// constructor +LeafNode::LeafNode() + : QueryNode() +{ +} + +// destructor +LeafNode::~LeafNode() +{ +} + +// Arity +uint32 +LeafNode::Arity() const +{ + return 0; +} + +// SetChildAt +status_t +LeafNode::SetChildAt(QueryNode *child, int32 index) +{ + return B_BAD_VALUE; +} + +// ChildAt +QueryNode * +LeafNode::ChildAt(int32 index) +{ + return NULL; +} + + +// UnaryNode + +// constructor +UnaryNode::UnaryNode() + : QueryNode(), + fChild(NULL) +{ +} + +// destructor +UnaryNode::~UnaryNode() +{ + delete fChild; +} + +// Arity +uint32 +UnaryNode::Arity() const +{ + return 1; +} + +// SetChildAt +status_t +UnaryNode::SetChildAt(QueryNode *child, int32 index) +{ + status_t error = B_OK; + if (index == 0) { + delete fChild; + fChild = child; + } else + error = B_BAD_VALUE; + return error; +} + +// ChildAt +QueryNode * +UnaryNode::ChildAt(int32 index) +{ + QueryNode *result = NULL; + if (index == 0) + result = fChild; + return result; +} + + +// BinaryNode + +// constructor +BinaryNode::BinaryNode() + : QueryNode(), + fChild1(NULL), + fChild2(NULL) +{ +} + +// destructor +BinaryNode::~BinaryNode() +{ + delete fChild1; + delete fChild2; +} + +// Arity +uint32 +BinaryNode::Arity() const +{ + return 2; +} + +// SetChildAt +status_t +BinaryNode::SetChildAt(QueryNode *child, int32 index) +{ + status_t error = B_OK; + if (index == 0) { + delete fChild1; + fChild1 = child; + } else if (index == 1) { + delete fChild2; + fChild2 = child; + } else + error = B_BAD_VALUE; + return error; +} + +// ChildAt +QueryNode * +BinaryNode::ChildAt(int32 index) +{ + QueryNode *result = NULL; + if (index == 0) + result = fChild1; + else if (index == 1) + result = fChild2; + return result; +} + + +// AttributeNode + +// constructor +AttributeNode::AttributeNode(const char *attribute) + : LeafNode(), + fAttribute(attribute) +{ +} + +// GetString +status_t +AttributeNode::GetString(BString &predicate) +{ + predicate.SetTo(fAttribute); + return B_OK; +} + + +// StringNode + +// constructor +StringNode::StringNode(const char *value, bool caseInsensitive) + : LeafNode(), + fValue() +{ + if (value) { + if (caseInsensitive) { + int32 len = strlen(value); + for (int32 i = 0; i < len; i++) { + char c = value[i]; + if (isalpha(c)) { + int lower = tolower(c); + int upper = toupper(c); + if (lower < 0 || upper < 0) + fValue << c; + else + fValue << "[" << (char)lower << (char)upper << "]"; + } else + fValue << c; + } + } else + fValue = value; + } +} + +// GetString +status_t +StringNode::GetString(BString &predicate) +{ + BString escaped(fValue); + escaped.CharacterEscape("\"\\'", '\\'); + predicate.SetTo(""); + predicate << "\"" << escaped << "\""; + return B_OK; +} + + +// DateNode + +// constructor +DateNode::DateNode(const char *value) + : LeafNode(), + fValue(value) +{ +} + +// GetString +status_t +DateNode::GetString(BString &predicate) +{ + BString escaped(fValue); + escaped.CharacterEscape("%\"\\'", '\\'); + predicate.SetTo(""); + predicate << "%" << escaped << "%"; + return B_OK; +} + + +// ValueNode + +// GetString +// +// float specialization +template<> +status_t +ValueNode::GetString(BString &predicate) +{ + char buffer[32]; + sprintf(buffer, "0x%08lx", *(int32*)&fValue); + predicate.SetTo(buffer); + return B_OK; +} + +// GetString +// +// double specialization +template<> +status_t +ValueNode::GetString(BString &predicate) +{ + char buffer[32]; + sprintf(buffer, "0x%016Lx", *(int64*)&fValue); + predicate.SetTo(buffer); + return B_OK; +} + + +// SpecialOpNode + +// constructor +SpecialOpNode::SpecialOpNode(query_op op) + : LeafNode(), + fOp(op) +{ +} + +// GetString +status_t +SpecialOpNode::GetString(BString &predicate) +{ + return B_BAD_VALUE; +} + + +// UnaryOpNode + +// constructor +UnaryOpNode::UnaryOpNode(query_op op) + : UnaryNode(), + fOp(op) +{ +} + +// GetString +status_t +UnaryOpNode::GetString(BString &predicate) +{ + status_t error = (fChild ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + if (fOp == B_NOT) { + BString childString; + error = fChild->GetString(childString); + predicate.SetTo("(!"); + predicate << childString << ")"; + } else + error = B_BAD_VALUE; + } + return error; +} + + +// BinaryOpNode + +// constructor +BinaryOpNode::BinaryOpNode(query_op op) + : BinaryNode(), + fOp(op) +{ +} + +// GetString +status_t +BinaryOpNode::GetString(BString &predicate) +{ + status_t error = (fChild1 && fChild2 ? B_OK : B_BAD_VALUE); + BString childString1; + BString childString2; + if (error == B_OK) + error = fChild1->GetString(childString1); + if (error == B_OK) + error = fChild2->GetString(childString2); + predicate.SetTo(""); + if (error == B_OK) { + switch (fOp) { + case B_EQ: + predicate << "(" << childString1 << "==" + << childString2 << ")"; + break; + case B_GT: + predicate << "(" << childString1 << ">" + << childString2 << ")"; + break; + case B_GE: + predicate << "(" << childString1 << ">=" + << childString2 << ")"; + break; + case B_LT: + predicate << "(" << childString1 << "<" + << childString2 << ")"; + break; + case B_LE: + predicate << "(" << childString1 << "<=" + << childString2 << ")"; + break; + case B_NE: + predicate << "(" << childString1 << "!=" + << childString2 << ")"; + break; + case B_CONTAINS: + if (StringNode *strNode = dynamic_cast(fChild2)) { + BString value; + value << "*" << strNode->Value() << "*"; + error = StringNode(value.String()).GetString(childString2); + } + if (error == B_OK) { + predicate << "(" << childString1 << "==" + << childString2 << ")"; + } + break; + case B_BEGINS_WITH: + if (StringNode *strNode = dynamic_cast(fChild2)) { + BString value; + value << strNode->Value() << "*"; + error = StringNode(value.String()).GetString(childString2); + } + if (error == B_OK) { + predicate << "(" << childString1 << "==" + << childString2 << ")"; + } + break; + case B_ENDS_WITH: + if (StringNode *strNode = dynamic_cast(fChild2)) { + BString value; + value << "*" << strNode->Value(); + error = StringNode(value.String()).GetString(childString2); + } + if (error == B_OK) { + predicate << "(" << childString1 << "==" + << childString2 << ")"; + } + break; + case B_AND: + predicate << "(" << childString1 << "&&" + << childString2 << ")"; + break; + case B_OR: + predicate << "(" << childString1 << "||" + << childString2 << ")"; + break; + default: + error = B_BAD_VALUE; + break; + } + } + return error; +} + + +// QueryStack + +// constructor +QueryStack::QueryStack() + : fNodes() +{ +} + +// destructor +QueryStack::~QueryStack() +{ + for (int32 i = 0; QueryNode *node = (QueryNode*)fNodes.ItemAt(i); i++) + delete node; +} + +// PushNode +status_t +QueryStack::PushNode(QueryNode *node) +{ + status_t error = (node ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + if (!fNodes.AddItem(node)) + error = B_NO_MEMORY; + } + return error; +} + +// PopNode +QueryNode * +QueryStack::PopNode() +{ + return (QueryNode*)fNodes.RemoveItem(fNodes.CountItems() - 1); +} + +// ConvertToTree +status_t +QueryStack::ConvertToTree(QueryNode *&rootNode) +{ + status_t error = _GetSubTree(rootNode); + if (error == B_OK && !fNodes.IsEmpty()) { + error = B_BAD_VALUE; + delete rootNode; + rootNode = NULL; + } + return error; +} + +// _GetSubTree +status_t +QueryStack::_GetSubTree(QueryNode *&rootNode) +{ + QueryNode *node = PopNode(); + status_t error = (node ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + uint32 arity = node->Arity(); + for (int32 i = (int32)arity - 1; error == B_OK && i >= 0; i--) { + QueryNode *child = NULL; + error = _GetSubTree(child); + if (error == B_OK) { + error = node->SetChildAt(child, i); + if (error != B_OK) + delete child; + } + } + } + // clean up, if something went wrong + if (error != B_OK && node) { + delete node; + node = NULL; + } + rootNode = node; + return error; +} + + +}; // namespace StorageKit diff --git a/src/kits/storage/ResourceFile.cpp b/src/kits/storage/ResourceFile.cpp new file mode 100644 index 0000000000..1a051cedfd --- /dev/null +++ b/src/kits/storage/ResourceFile.cpp @@ -0,0 +1,1236 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file ResourceFile.cpp + ResourceFile implementation. +*/ + +#include "ResourceFile.h" + +#include +#include +#include + +#include "Elf.h" +#include "Exception.h" +#include "Pef.h" +#include "ResourceItem.h" +#include "ResourcesContainer.h" +#include "ResourcesDefs.h" +//#include "Warnings.h" + +namespace StorageKit { + +// ELF defs +static const uint32 kMaxELFHeaderSize = sizeof(Elf32_Ehdr) + 32; +static const char kELFFileMagic[4] = { 0x7f, 'E', 'L', 'F' }; + +// sanity bounds +static const uint32 kMaxResourceCount = 10000; +static const uint32 kELFMaxResourceAlignment = 1024 * 1024 * 10; // 10 MB + +// recognized file types (indices into kFileTypeNames) +enum { + FILE_TYPE_UNKNOWN = 0, + FILE_TYPE_X86_RESOURCE = 1, + FILE_TYPE_PPC_RESOURCE = 2, + FILE_TYPE_ELF = 3, + FILE_TYPE_PEF = 4, + FILE_TYPE_EMPTY = 5, +}; + +const char *kFileTypeNames[] = { + "unknown", + "x86 resource file", + "PPC resource file", + "ELF object file", + "PEF object file", + "empty file", +}; + + +// helper functions/classes + +// read_exactly +static +void +read_exactly(BPositionIO &file, off_t position, void *buffer, size_t size, + const char *errorMessage = NULL) +{ + ssize_t read = file.ReadAt(position, buffer, size); + if (read < 0) + throw Exception(read, errorMessage); + else if ((size_t)read != size) { + if (errorMessage) { + throw Exception("%s Read too few bytes (%ld/%lu).", errorMessage, + read, size); + } else + throw Exception("Read too few bytes (%ld/%lu).", read, size); + } +} + +// write_exactly +static +void +write_exactly(BPositionIO &file, off_t position, const void *buffer, + size_t size, const char *errorMessage = NULL) +{ + ssize_t written = file.WriteAt(position, buffer, size); + if (written < 0) + throw Exception(written, errorMessage); + else if ((size_t)written != size) { + if (errorMessage) { + throw Exception("%s Wrote too few bytes (%ld/%lu).", errorMessage, + written, size); + } else + throw Exception("Wrote too few bytes (%ld/%lu).", written, size); + } +} + +// align_value +template +static inline +TV +align_value(const TV &value, const TA &alignment) +{ + return ((value + alignment - 1) / alignment) * alignment; +} + +// calculate_checksum +static +uint32 +calculate_checksum(const void *data, uint32 size) +{ + uint32 checkSum = 0; + const uint8 *csData = (const uint8*)data; + const uint8 *dataEnd = csData + size; + const uint8 *current = csData; + for (; current < dataEnd; current += 4) { + uint32 word = 0; + int32 bytes = min(4L, dataEnd - current); + for (int32 i = 0; i < bytes; i++) + word = (word << 8) + current[i]; + checkSum += word; + } + return checkSum; +} + +// skip_bytes +static inline +const void* +skip_bytes(const void *buffer, int32 offset) +{ + return (const char*)buffer + offset; +} + +// skip_bytes +static inline +void* +skip_bytes(void *buffer, int32 offset) +{ + return (char*)buffer + offset; +} + +// fill_pattern +static +void +fill_pattern(uint32 byteOffset, void *_buffer, uint32 count) +{ + uint32 *buffer = (uint32*)_buffer; + for (uint32 i = 0; i < count; i++) + buffer[i] = kUnusedResourceDataPattern[(byteOffset / 4 + i) % 3]; +} + +// fill_pattern +static +void +fill_pattern(const void *dataBegin, void *buffer, uint32 count) +{ + fill_pattern((char*)buffer - (const char*)dataBegin, buffer, count); +} + +// fill_pattern +static +void +fill_pattern(const void *dataBegin, void *buffer, const void *bufferEnd) +{ + fill_pattern(dataBegin, buffer, + ((const char*)bufferEnd - (char*)buffer) / 4); +} + +// check_pattern +static +bool +check_pattern(uint32 byteOffset, void *_buffer, uint32 count, + bool hostEndianess) +{ + bool result = true; + uint32 *buffer = (uint32*)_buffer; + for (uint32 i = 0; result && i < count; i++) { + uint32 value = buffer[i]; + if (!hostEndianess) + value = B_SWAP_INT32(value); + result + = (value == kUnusedResourceDataPattern[(byteOffset / 4 + i) % 3]); + } + return result; +} + +// MemArea +struct MemArea { + MemArea(const void *data, uint32 size) : data(data), size(size) {} + + inline bool check(const void *_current, uint32 skip = 0) const + { + const char *start = (const char*)data; + const char *current = (const char*)_current; + return (start <= current && start + size >= current + skip); + } + + const void* data; + uint32 size; +}; + +// AutoDeleter +template +struct AutoDeleter { + AutoDeleter(C *object, bool array = false) : object(object), array(array) + { + } + + ~AutoDeleter() + { + if (array) + delete[] object; + else + delete object; + } + + C* object; + bool array; +}; + +// resource_parse_info +struct resource_parse_info { + off_t file_size; + int32 resource_count; + ResourcesContainer *container; + char *info_table; + uint32 info_table_offset; + uint32 info_table_size; +}; + + +// constructor +ResourceFile::ResourceFile() + : fFile(), + fFileType(FILE_TYPE_UNKNOWN), + fHostEndianess(true), + fEmptyResources(true) +{ +} + +// destructor +ResourceFile::~ResourceFile() +{ + Unset(); +} + +// SetTo +status_t +ResourceFile::SetTo(BFile *file, bool clobber) +{ + status_t error = (file ? B_OK : B_BAD_VALUE); + Unset(); + if (error == B_OK) { + try { + _InitFile(*file, clobber); + } catch (Exception exception) { + Unset(); + if (exception.Error() != B_OK) + error = exception.Error(); + else + error = B_ERROR; + } + } + return error; +} + +// Unset +void +ResourceFile::Unset() +{ + // file + fFile.Unset(); + fFileType = FILE_TYPE_UNKNOWN; + fHostEndianess = true; + fEmptyResources = true; +} + +// InitCheck +status_t +ResourceFile::InitCheck() const +{ + return fFile.InitCheck(); +} + +// InitContainer +status_t +ResourceFile::InitContainer(ResourcesContainer &container) +{ + container.MakeEmpty(); + status_t error = InitCheck(); + if (error == B_OK && !fEmptyResources) { + resource_parse_info parseInfo; + parseInfo.file_size = 0; + parseInfo.resource_count = 0; + parseInfo.container = &container; + parseInfo.info_table = NULL; + parseInfo.info_table_offset = 0; + parseInfo.info_table_size = 0; + try { + // get the file size + error = fFile.GetSize(&parseInfo.file_size); + if (error != B_OK) + throw Exception(error, "Failed to get the file size."); + _ReadHeader(parseInfo); + _ReadIndex(parseInfo); + _ReadInfoTable(parseInfo); + container.SetModified(false); + } catch (Exception exception) { + if (exception.Error() != B_OK) + error = exception.Error(); + else + error = B_ERROR; + } + delete[] parseInfo.info_table; + } + return error; +} + +// ReadResource +status_t +ResourceFile::ReadResource(ResourceItem &resource, bool force) +{ + status_t error = InitCheck(); + size_t size = resource.DataSize(); + if (error == B_OK && (force || !resource.IsLoaded())) { + if (error == B_OK) + error = resource.SetSize(size); + void *data = NULL; + if (error == B_OK) { + data = resource.Data(); + ssize_t bytesRead = fFile.ReadAt(resource.Offset(), data, size); + if (bytesRead < 0) + error = bytesRead; + else if ((size_t)bytesRead != size) + error = B_IO_ERROR; + } + if (error == B_OK) { + // convert the data, if necessary + if (!fHostEndianess) + swap_data(resource.Type(), data, size, B_SWAP_ALWAYS); + resource.SetLoaded(true); + resource.SetModified(false); + } + } + return error; +} + +// ReadResources +status_t +ResourceFile::ReadResources(ResourcesContainer &container, bool force) +{ + status_t error = InitCheck(); + int32 count = container.CountResources(); + for (int32 i = 0; error == B_OK && i < count; i++) { + if (ResourceItem *resource = container.ResourceAt(i)) + error = ReadResource(*resource, force); + else + error = B_ERROR; + } + return error; +} + +// WriteResources +status_t +ResourceFile::WriteResources(ResourcesContainer &container) +{ + status_t error = InitCheck(); + if (error == B_OK && !fFile.File()->IsWritable()) + error = B_NOT_ALLOWED; + if (error == B_OK && fFileType == FILE_TYPE_EMPTY) + error = _MakeEmptyResourceFile(); + if (error == B_OK) + error = _WriteResources(container); + if (error == B_OK) + fEmptyResources = false; + return error; +} + + +// _InitFile +void +ResourceFile::_InitFile(BFile &file, bool clobber) +{ + status_t error = B_OK; + fFile.Unset(); + // get the file size first + off_t fileSize = 0; + error = file.GetSize(&fileSize); + if (error != B_OK) + throw Exception(error, "Failed to get the file size."); + // read the first four bytes, and check, if they identify a resource file + char magic[4]; + if (fileSize >= 4) + read_exactly(file, 0, magic, 4, "Failed to read magic number."); + else if (fileSize > 0 && !clobber) + throw Exception(B_IO_ERROR, "File is not a resource file."); + if (fileSize == 0) { + // empty file + fHostEndianess = true; + fFileType = FILE_TYPE_EMPTY; + fFile.SetTo(&file, 0); + fEmptyResources = true; + } else if (!memcmp(magic, kX86ResourceFileMagic, 4)) { + // x86 resource file + fHostEndianess = B_HOST_IS_LENDIAN; + fFileType = FILE_TYPE_X86_RESOURCE; + fFile.SetTo(&file, kX86ResourcesOffset); + fEmptyResources = false; + } else if (!memcmp(magic, kPEFFileMagic1, 4)) { + PEFContainerHeader pefHeader; + read_exactly(file, 0, &pefHeader, kPEFContainerHeaderSize, + "Failed to read PEF container header."); + if (!memcmp(pefHeader.tag2, kPPCResourceFileMagic, 4)) { + // PPC resource file + fHostEndianess = B_HOST_IS_BENDIAN; + fFileType = FILE_TYPE_PPC_RESOURCE; + fFile.SetTo(&file, kPPCResourcesOffset); + fEmptyResources = false; + } else if (!memcmp(pefHeader.tag2, kPEFFileMagic2, 4)) { + // PEF file + fFileType = FILE_TYPE_PEF; + _InitPEFFile(file, pefHeader); + } else + throw Exception(B_IO_ERROR, "File is not a resource file."); + } else if (!memcmp(magic, kELFFileMagic, 4)) { + // ELF file + fFileType = FILE_TYPE_ELF; + _InitELFFile(file); + } else if (!memcmp(magic, kX86ResourceFileMagic, 2)) { + // x86 resource file with screwed magic? +// Warnings::AddCurrentWarning("File magic is 0x%08lx. Should be 0x%08lx " +// "for x86 resource file. Try anyway.", +// ntohl(*(uint32*)magic), +// ntohl(*(uint32*)kX86ResourceFileMagic)); + fHostEndianess = B_HOST_IS_LENDIAN; + fFileType = FILE_TYPE_X86_RESOURCE; + fFile.SetTo(&file, kX86ResourcesOffset); + fEmptyResources = true; + } else { + if (clobber) { + // make it an x86 resource file + fHostEndianess = true; + fFileType = FILE_TYPE_EMPTY; + fFile.SetTo(&file, 0); + } else + throw Exception(B_IO_ERROR, "File is not a resource file."); + } + error = fFile.InitCheck(); + if (error != B_OK) + throw Exception(error, "Failed to initialize resource file."); + // clobber, if desired + if (clobber) { + // just write an empty resources container + ResourcesContainer container; + WriteResources(container); + } +} + +// _InitELFFile +void +ResourceFile::_InitELFFile(BFile &file) +{ + status_t error = B_OK; + // get the file size + off_t fileSize = 0; + error = file.GetSize(&fileSize); + if (error != B_OK) + throw Exception(error, "Failed to get the file size."); + // read ELF header + Elf32_Ehdr fileHeader; + read_exactly(file, 0, &fileHeader, sizeof(Elf32_Ehdr), + "Failed to read ELF header."); + // check data encoding (endianess) + switch (fileHeader.e_ident[EI_DATA]) { + case ELFDATA2LSB: + fHostEndianess = B_HOST_IS_LENDIAN; + break; + case ELFDATA2MSB: + fHostEndianess = B_HOST_IS_BENDIAN; + break; + default: + case ELFDATANONE: + throw Exception(B_IO_ERROR, "Unsupported ELF data encoding."); + break; + } + // get the header values + uint32 headerSize = _GetUInt16(fileHeader.e_ehsize); + uint32 programHeaderTableOffset = _GetUInt32(fileHeader.e_phoff); + uint32 programHeaderSize = _GetUInt16(fileHeader.e_phentsize); + uint32 programHeaderCount = _GetUInt16(fileHeader.e_phnum); + uint32 sectionHeaderTableOffset = _GetUInt32(fileHeader.e_shoff); + uint32 sectionHeaderSize = _GetUInt16(fileHeader.e_shentsize); + uint32 sectionHeaderCount = _GetUInt16(fileHeader.e_shnum); + bool hasProgramHeaderTable = (programHeaderTableOffset != 0); + bool hasSectionHeaderTable = (sectionHeaderTableOffset != 0); + // check the sanity of the header values + // ELF header size + if (headerSize < sizeof(Elf32_Ehdr) || headerSize > kMaxELFHeaderSize) { + throw Exception(B_IO_ERROR, + "Invalid ELF header: invalid ELF header size: %lu.", + headerSize); + } + uint32 resourceOffset = headerSize; + uint32 resourceAlignment = 0; + // program header table offset and entry count/size + uint32 programHeaderTableSize = 0; + if (hasProgramHeaderTable) { + if (programHeaderTableOffset < headerSize + || programHeaderTableOffset > fileSize) { + throw Exception(B_IO_ERROR, "Invalid ELF header: invalid program " + "header table offset: %lu.", + programHeaderTableOffset); + } + programHeaderTableSize = programHeaderSize * programHeaderCount; + if (programHeaderSize < sizeof(Elf32_Phdr) + || programHeaderTableOffset + programHeaderTableSize > fileSize) { + throw Exception(B_IO_ERROR, "Invalid ELF header: program header " + "table exceeds file: %lu.", + programHeaderTableOffset + programHeaderTableSize); + } + resourceOffset = max(resourceOffset, programHeaderTableOffset + + programHeaderTableSize); + // iterate through the program headers + for (int32 i = 0; i < (int32)programHeaderCount; i++) { + uint32 shOffset = programHeaderTableOffset + i * programHeaderSize; + Elf32_Phdr programHeader; + read_exactly(file, shOffset, &programHeader, sizeof(Elf32_Shdr), + "Failed to read ELF program header."); + // get the header values + uint32 type = _GetUInt32(programHeader.p_type); + uint32 offset = _GetUInt32(programHeader.p_offset); + uint32 size = _GetUInt32(programHeader.p_filesz); + uint32 alignment = _GetUInt32(programHeader.p_align); + // check the values + // PT_NULL marks the header unused, + if (type != PT_NULL) { + if (/*offset < headerSize ||*/ offset > fileSize) { + throw Exception(B_IO_ERROR, "Invalid ELF program header: " + "invalid program offset: %lu.", offset); + } + uint32 segmentEnd = offset + size; + if (segmentEnd > fileSize) { + throw Exception(B_IO_ERROR, "Invalid ELF section header: " + "segment exceeds file: %lu.", segmentEnd); + } + resourceOffset = max(resourceOffset, segmentEnd); + resourceAlignment = max(resourceAlignment, alignment); + } + } + } + // section header table offset and entry count/size + uint32 sectionHeaderTableSize = 0; + if (hasSectionHeaderTable) { + if (sectionHeaderTableOffset < headerSize + || sectionHeaderTableOffset > fileSize) { + throw Exception(B_IO_ERROR, "Invalid ELF header: invalid section " + "header table offset: %lu.", + sectionHeaderTableOffset); + } + sectionHeaderTableSize = sectionHeaderSize * sectionHeaderCount; + if (sectionHeaderSize < sizeof(Elf32_Shdr) + || sectionHeaderTableOffset + sectionHeaderTableSize > fileSize) { + throw Exception(B_IO_ERROR, "Invalid ELF header: section header " + "table exceeds file: %lu.", + sectionHeaderTableOffset + sectionHeaderTableSize); + } + resourceOffset = max(resourceOffset, sectionHeaderTableOffset + + sectionHeaderTableSize); + // iterate through the section headers + for (int32 i = 0; i < (int32)sectionHeaderCount; i++) { + uint32 shOffset = sectionHeaderTableOffset + i * sectionHeaderSize; + Elf32_Shdr sectionHeader; + read_exactly(file, shOffset, §ionHeader, sizeof(Elf32_Shdr), + "Failed to read ELF section header."); + // get the header values + uint32 type = _GetUInt32(sectionHeader.sh_type); + uint32 offset = _GetUInt32(sectionHeader.sh_offset); + uint32 size = _GetUInt32(sectionHeader.sh_size); + // check the values + // SHT_NULL marks the header unused, + // SHT_NOBITS sections take no space in the file + if (type != SHT_NULL && type != SHT_NOBITS) { + if (offset < headerSize || offset > fileSize) { + throw Exception(B_IO_ERROR, "Invalid ELF section header: " + "invalid section offset: %lu.", offset); + } + uint32 sectionEnd = offset + size; + if (sectionEnd > fileSize) { + throw Exception(B_IO_ERROR, "Invalid ELF section header: " + "section exceeds file: %lu.", sectionEnd); + } + resourceOffset = max(resourceOffset, sectionEnd); + } + } + } + // align the offset + if (resourceAlignment < kELFMinResourceAlignment) + resourceAlignment = kELFMinResourceAlignment; + if (resourceAlignment > kELFMaxResourceAlignment) { + throw Exception(B_IO_ERROR, "The ELF object file requires an invalid " + "alignment: %lu.", resourceAlignment); + } + resourceOffset = align_value(resourceOffset, resourceAlignment); + if (resourceOffset >= fileSize) { +// throw Exception("The ELF object file does not contain resources."); + fEmptyResources = true; + } else + fEmptyResources = false; + // fine, init the offset file + fFile.SetTo(&file, resourceOffset); +} + +// _InitPEFFile +void +ResourceFile::_InitPEFFile(BFile &file, const PEFContainerHeader &pefHeader) +{ + status_t error = B_OK; + // get the file size + off_t fileSize = 0; + error = file.GetSize(&fileSize); + if (error != B_OK) + throw Exception(error, "Failed to get the file size."); + // check architecture -- we support PPC only + if (memcmp(pefHeader.architecture, kPEFArchitecturePPC, 4)) + throw Exception(B_IO_ERROR, "PEF file architecture is not PPC."); + fHostEndianess = B_HOST_IS_BENDIAN; + // get the section count + uint16 sectionCount = _GetUInt16(pefHeader.sectionCount); + // iterate through the PEF sections headers + uint32 sectionHeaderTableOffset = kPEFContainerHeaderSize; + uint32 sectionHeaderTableEnd + = sectionHeaderTableOffset + sectionCount * kPEFSectionHeaderSize; + uint32 resourceOffset = sectionHeaderTableEnd; + for (int32 i = 0; i < (int32)sectionCount; i++) { + uint32 shOffset = sectionHeaderTableOffset + i * kPEFSectionHeaderSize; + PEFSectionHeader sectionHeader; + read_exactly(file, shOffset, §ionHeader, kPEFSectionHeaderSize, + "Failed to read PEF section header."); + // get the header values + uint32 offset = _GetUInt32(sectionHeader.containerOffset); + uint32 size = _GetUInt32(sectionHeader.packedSize); + // check the values + if (offset < sectionHeaderTableEnd || offset > fileSize) { + throw Exception(B_IO_ERROR, "Invalid PEF section header: invalid " + "section offset: %lu.", offset); + } + uint32 sectionEnd = offset + size; + if (sectionEnd > fileSize) { + throw Exception(B_IO_ERROR, "Invalid PEF section header: section " + "exceeds file: %lu.", sectionEnd); + } + resourceOffset = max(resourceOffset, sectionEnd); + } + if (resourceOffset >= fileSize) { +// throw Exception("The PEF object file does not contain resources."); + fEmptyResources = true; + } else + fEmptyResources = false; + // init the offset file + fFile.SetTo(&file, resourceOffset); +} + +// _ReadHeader +void +ResourceFile::_ReadHeader(resource_parse_info &parseInfo) +{ + // read the header + resources_header header; + read_exactly(fFile, 0, &header, kResourcesHeaderSize, + "Failed to read the header."); + // check the header + // magic + uint32 magic = _GetUInt32(header.rh_resources_magic); + if (magic == kResourcesHeaderMagic) { + // everything is fine + } else if (B_SWAP_INT32(magic) == kResourcesHeaderMagic) { +// const char *endianessStr[2] = { "little", "big" }; +// int32 endianess +// = (fHostEndianess == ((bool)B_HOST_IS_LENDIAN ? 0 : 1)); +// Warnings::AddCurrentWarning("Endianess seems to be %s, although %s " +// "was expected.", +// endianessStr[1 - endianess], +// endianessStr[endianess]); + fHostEndianess = !fHostEndianess; + } else + throw Exception(B_IO_ERROR, "Invalid resources header magic."); + // resource count + uint32 resourceCount = _GetUInt32(header.rh_resource_count); + if (resourceCount > kMaxResourceCount) + throw Exception(B_IO_ERROR, "Bad number of resources."); + // index section offset + uint32 indexSectionOffset = _GetUInt32(header.rh_index_section_offset); + if (indexSectionOffset != kResourceIndexSectionOffset) { + throw Exception(B_IO_ERROR, "Unexpected resource index section " + "offset. Is: %lu, should be: %lu.", indexSectionOffset, + kResourceIndexSectionOffset); + } + // admin section size + uint32 indexSectionSize = kResourceIndexSectionHeaderSize + + kResourceIndexEntrySize * resourceCount; + indexSectionSize = align_value(indexSectionSize, + kResourceIndexSectionAlignment); + uint32 adminSectionSize = _GetUInt32(header.rh_admin_section_size); + if (adminSectionSize != indexSectionOffset + indexSectionSize) { + throw Exception(B_IO_ERROR, "Unexpected resource admin section size. " + "Is: %lu, should be: %lu.", adminSectionSize, + indexSectionOffset + indexSectionSize); + } + // set the resource count + parseInfo.resource_count = resourceCount; +} + +// _ReadIndex +void +ResourceFile::_ReadIndex(resource_parse_info &parseInfo) +{ + int32 &resourceCount = parseInfo.resource_count; + off_t &fileSize = parseInfo.file_size; + // read the header + resource_index_section_header header; + read_exactly(fFile, kResourceIndexSectionOffset, &header, + kResourceIndexSectionHeaderSize, + "Failed to read the resource index section header."); + // check the header + // index section offset + uint32 indexSectionOffset = _GetUInt32(header.rish_index_section_offset); + if (indexSectionOffset != kResourceIndexSectionOffset) { + throw Exception(B_IO_ERROR, "Unexpected resource index section " + "offset. Is: %lu, should be: %lu.", indexSectionOffset, + kResourceIndexSectionOffset); + } + // index section size + uint32 expectedIndexSectionSize = kResourceIndexSectionHeaderSize + + kResourceIndexEntrySize * resourceCount; + expectedIndexSectionSize = align_value(expectedIndexSectionSize, + kResourceIndexSectionAlignment); + uint32 indexSectionSize = _GetUInt32(header.rish_index_section_size); + if (indexSectionSize != expectedIndexSectionSize) { + throw Exception(B_IO_ERROR, "Unexpected resource index section size. " + "Is: %lu, should be: %lu.", indexSectionSize, + expectedIndexSectionSize); + } + // unknown section offset + uint32 unknownSectionOffset + = _GetUInt32(header.rish_unknown_section_offset); + if (unknownSectionOffset != indexSectionOffset + indexSectionSize) { + throw Exception(B_IO_ERROR, "Unexpected resource index section size. " + "Is: %lu, should be: %lu.", unknownSectionOffset, + indexSectionOffset + indexSectionSize); + } + // unknown section size + uint32 unknownSectionSize = _GetUInt32(header.rish_unknown_section_size); + if (unknownSectionSize != kUnknownResourceSectionSize) { + throw Exception(B_IO_ERROR, "Unexpected resource index section " + "offset. Is: %lu, should be: %lu.", + unknownSectionOffset, kUnknownResourceSectionSize); + } + // info table offset and size + uint32 infoTableOffset = _GetUInt32(header.rish_info_table_offset); + uint32 infoTableSize = _GetUInt32(header.rish_info_table_size); + if (infoTableOffset + infoTableSize > fileSize) + throw Exception(B_IO_ERROR, "Invalid info table location."); + parseInfo.info_table_offset = infoTableOffset; + parseInfo.info_table_size = infoTableSize; + // read the index entries + uint32 indexTableOffset = indexSectionOffset + + kResourceIndexSectionHeaderSize; + int32 maxResourceCount = (unknownSectionOffset - indexTableOffset) + / kResourceIndexEntrySize; + int32 actualResourceCount = 0; + bool tableEndReached = false; + for (int32 i = 0; !tableEndReached && i < maxResourceCount; i++) { + // read one entry + tableEndReached = !_ReadIndexEntry(parseInfo, i, indexTableOffset, + (i >= resourceCount)); + if (!tableEndReached) + actualResourceCount++; + } + // check resource count + if (actualResourceCount != resourceCount) { + if (actualResourceCount > resourceCount) { +// Warnings::AddCurrentWarning("Resource index table contains " +// "%ld entries, although it should be " +// "%ld only.", actualResourceCount, +// resourceCount); + } + resourceCount = actualResourceCount; + } +} + +// _ReadIndexEntry +bool +ResourceFile::_ReadIndexEntry(resource_parse_info &parseInfo, int32 index, + uint32 tableOffset, bool peekAhead) +{ + off_t &fileSize = parseInfo.file_size; + // + bool result = true; + resource_index_entry entry; + // read one entry + off_t entryOffset = tableOffset + index * kResourceIndexEntrySize; + read_exactly(fFile, entryOffset, &entry, kResourceIndexEntrySize, + "Failed to read a resource index entry."); + // check, if the end is reached early + if (result && check_pattern(entryOffset, &entry, + kResourceIndexEntrySize / 4, fHostEndianess)) { + if (!peekAhead) { +// Warnings::AddCurrentWarning("Unexpected end of resource index " +// "table at index: %ld (/%ld).", +// index + 1, resourceCount); + } + result = false; + } + uint32 offset = _GetUInt32(entry.rie_offset); + uint32 size = _GetUInt32(entry.rie_size); + // check the location + if (result && offset + size > fileSize) { + if (peekAhead) { +// Warnings::AddCurrentWarning("Invalid data after resource index " +// "table."); + } else { + throw Exception(B_IO_ERROR, "Invalid resource index entry: index: " + "%ld, offset: %lu (%lx), size: %lu (%lx).", + index + 1, offset, offset, size, size); + } + result = false; + } + // add the entry + if (result) { + ResourceItem *item = new(nothrow) ResourceItem; + if (!item) + throw Exception(B_NO_MEMORY); + item->SetLocation(offset, size); + if (!parseInfo.container->AddResource(item, index, false)) { + delete item; + throw Exception(B_NO_MEMORY); + } + } + return result; +} + +// _ReadInfoTable +void +ResourceFile::_ReadInfoTable(resource_parse_info &parseInfo) +{ + int32 &resourceCount = parseInfo.resource_count; + // read the info table + // alloc memory for the table + char *tableData = new(nothrow) char[parseInfo.info_table_size]; + if (!tableData) + throw Exception(B_NO_MEMORY); + int32 dataSize = parseInfo.info_table_size; + parseInfo.info_table = tableData; // freed by the info owner + read_exactly(fFile, parseInfo.info_table_offset, tableData, dataSize, + "Failed to read resource info table."); + // + bool *readIndices = new(nothrow) bool[resourceCount + 1]; + // + 1 => always > 0 + if (!readIndices) + throw Exception(B_NO_MEMORY); + AutoDeleter readIndicesDeleter(readIndices, true); + for (int32 i = 0; i < resourceCount; i++) + readIndices[i] = false; + MemArea area(tableData, dataSize); + const void *data = tableData; + // check the table end/check sum + if (_ReadInfoTableEnd(data, dataSize)) + dataSize -= kResourceInfoTableEndSize; + // read the infos + int32 resourceIndex = 1; + uint32 minRemainderSize + = kMinResourceInfoBlockSize + kResourceInfoSeparatorSize; + while (area.check(data, minRemainderSize)) { + // read a resource block + if (!area.check(data, kMinResourceInfoBlockSize)) { + throw Exception(B_IO_ERROR, "Unexpected end of resource info " + "table at index %ld.", resourceIndex); + } + const resource_info_block *infoBlock + = (const resource_info_block*)data; + type_code type = _GetUInt32(infoBlock->rib_type); + // read the infos of this block + const resource_info *info = infoBlock->rib_info; + while (info) { + data = _ReadResourceInfo(parseInfo, area, info, type, readIndices); + // prepare for next iteration, if there is another info + if (!area.check(data, kResourceInfoSeparatorSize)) { + throw Exception(B_IO_ERROR, "Unexpected end of resource info " + "table after index %ld.", resourceIndex); + } + const resource_info_separator *separator + = (const resource_info_separator*)data; + if (_GetUInt32(separator->ris_value1) == 0xffffffff + && _GetUInt32(separator->ris_value2) == 0xffffffff) { + // info block ends + info = NULL; + data = skip_bytes(data, kResourceInfoSeparatorSize); + } else { + // another info follows + info = (const resource_info*)data; + } + resourceIndex++; + } + // end of the info block + } + // handle special case: empty resource info table + if (resourceIndex == 1) { + if (!area.check(data, kResourceInfoSeparatorSize)) { + throw Exception(B_IO_ERROR, "Unexpected end of resource info " + "table."); + } + const resource_info_separator *tableTerminator + = (const resource_info_separator*)data; + if (_GetUInt32(tableTerminator->ris_value1) != 0xffffffff + || _GetUInt32(tableTerminator->ris_value2) != 0xffffffff) { + throw Exception(B_IO_ERROR, "The resource info table ought to be " + "empty, but is not properly terminated."); + } + data = skip_bytes(data, kResourceInfoSeparatorSize); + } + // Check, if the correct number of bytes are remaining. + uint32 bytesLeft = (const char*)tableData + dataSize - (const char*)data; + if (bytesLeft != 0) { + throw Exception(B_IO_ERROR, "Error at the end of the resource info " + "table: %lu bytes are remaining.", bytesLeft); + } + // check, if all items have been initialized + for (int32 i = resourceCount - 1; i >= 0; i--) { + if (!readIndices[i]) { +// Warnings::AddCurrentWarning("Resource item at index %ld " +// "has no info. Item removed.", i + 1); + if (ResourceItem *item = parseInfo.container->RemoveResource(i)) + delete item; + resourceCount--; + } + } +} + +// _ReadInfoTableEnd +bool +ResourceFile::_ReadInfoTableEnd(const void *data, int32 dataSize) +{ + bool hasTableEnd = true; + if ((uint32)dataSize < kResourceInfoSeparatorSize) + throw Exception(B_IO_ERROR, "Info table is too short."); + if ((uint32)dataSize < kResourceInfoTableEndSize) + hasTableEnd = false; + if (hasTableEnd) { + const resource_info_table_end *tableEnd + = (const resource_info_table_end*) + skip_bytes(data, dataSize - kResourceInfoTableEndSize); + if (_GetInt32(tableEnd->rite_terminator) != 0) + hasTableEnd = false; + if (hasTableEnd) { + dataSize -= kResourceInfoTableEndSize; + // checksum + uint32 checkSum = calculate_checksum(data, dataSize); + uint32 fileCheckSum = _GetUInt32(tableEnd->rite_check_sum); + if (checkSum != fileCheckSum) { + throw Exception(B_IO_ERROR, "Invalid resource info table check" + " sum: In file: %lx, calculated: %lx.", + fileCheckSum, checkSum); + } + } + } +// if (!hasTableEnd) +// Warnings::AddCurrentWarning("resource info table has no check sum."); + return hasTableEnd; +} + +// _ReadResourceInfo +const void* +ResourceFile::_ReadResourceInfo(resource_parse_info &parseInfo, + const MemArea &area, const resource_info *info, + type_code type, bool *readIndices) +{ + int32 &resourceCount = parseInfo.resource_count; + // + int32 id = _GetInt32(info->ri_id); + int32 index = _GetInt32(info->ri_index); + uint16 nameSize = _GetUInt16(info->ri_name_size); + const char *name = info->ri_name; + // check the values + bool ignore = false; + // index + if (index < 1 || index > resourceCount) { +// Warnings::AddCurrentWarning("Invalid index field in resource " +// "info table: %lu.", index); + ignore = true; + } + if (!ignore) { + if (readIndices[index - 1]) { + throw Exception(B_IO_ERROR, "Multiple resource infos with the " + "same index field: %ld.", index); + } + readIndices[index - 1] = true; + } + // name size + if (!area.check(name, nameSize)) { + throw Exception(B_IO_ERROR, "Invalid name size (%d) for index %ld in " + "resource info table.", (int)nameSize, index); + } + // check, if name is null terminated + if (name[nameSize - 1] != 0) { +// Warnings::AddCurrentWarning("Name for index %ld in " +// "resource info table is not null " +// "terminated.", index); + } + // set the values + if (!ignore) { + BString resourceName(name, nameSize); + if (ResourceItem *item = parseInfo.container->ResourceAt(index - 1)) + item->SetIdentity(type, id, resourceName.String()); + else { + throw Exception(B_IO_ERROR, "Unexpected error: No resource item " + "at index %ld.", index); + } + } + return skip_bytes(name, nameSize); +} + +// _WriteResources +status_t +ResourceFile::_WriteResources(ResourcesContainer &container) +{ + status_t error = B_OK; + int32 resourceCount = container.CountResources(); + char *buffer = NULL; + try { + // calculate sizes and offsets + // header + uint32 size = kResourcesHeaderSize; + size_t bufferSize = size; + // index section + uint32 indexSectionOffset = size; + uint32 indexSectionSize = kResourceIndexSectionHeaderSize + + resourceCount * kResourceIndexEntrySize; + indexSectionSize = align_value(indexSectionSize, + kResourceIndexSectionAlignment); + size += indexSectionSize; + bufferSize = max(bufferSize, indexSectionSize); + // unknown section + uint32 unknownSectionOffset = size; + uint32 unknownSectionSize = kUnknownResourceSectionSize; + size += unknownSectionSize; + bufferSize = max(bufferSize, unknownSectionSize); + // data + uint32 dataOffset = size; + uint32 dataSize = 0; + for (int32 i = 0; i < resourceCount; i++) { + ResourceItem *item = container.ResourceAt(i); + if (!item->IsLoaded()) + throw Exception(B_IO_ERROR, "Resource is not loaded."); + dataSize += item->DataSize(); + bufferSize = max(bufferSize, item->DataSize()); + } + size += dataSize; + // info table + uint32 infoTableOffset = size; + uint32 infoTableSize = 0; + type_code type = 0; + for (int32 i = 0; i < resourceCount; i++) { + ResourceItem *item = container.ResourceAt(i); + if (i == 0 || type != item->Type()) { + if (i != 0) + infoTableSize += kResourceInfoSeparatorSize; + type = item->Type(); + infoTableSize += kMinResourceInfoBlockSize; + } else + infoTableSize += kMinResourceInfoSize; + if (const char *name = item->Name()) + infoTableSize += strlen(name) + 1; + } + infoTableSize += kResourceInfoSeparatorSize + + kResourceInfoTableEndSize; + size += infoTableSize; + bufferSize = max(bufferSize, infoTableSize); + + // write... + // set the file size + fFile.SetSize(size); + buffer = new(nothrow) char[bufferSize]; + if (!buffer) + throw Exception(B_NO_MEMORY); + void *data = buffer; + // header + resources_header *resourcesHeader = (resources_header*)data; + resourcesHeader->rh_resources_magic = kResourcesHeaderMagic; + resourcesHeader->rh_resource_count = resourceCount; + resourcesHeader->rh_index_section_offset = indexSectionOffset; + resourcesHeader->rh_admin_section_size = indexSectionOffset + + indexSectionSize; + for (int32 i = 0; i < 13; i++) + resourcesHeader->rh_pad[i] = 0; + write_exactly(fFile, 0, buffer, kResourcesHeaderSize, + "Failed to write resources header."); + // index section + data = buffer; + // header + resource_index_section_header *indexHeader + = (resource_index_section_header*)data; + indexHeader->rish_index_section_offset = indexSectionOffset; + indexHeader->rish_index_section_size = indexSectionSize; + indexHeader->rish_unknown_section_offset = unknownSectionOffset; + indexHeader->rish_unknown_section_size = unknownSectionSize; + indexHeader->rish_info_table_offset = infoTableOffset; + indexHeader->rish_info_table_size = infoTableSize; + fill_pattern(buffer - indexSectionOffset, + &indexHeader->rish_unused_data1, 1); + fill_pattern(buffer - indexSectionOffset, + indexHeader->rish_unused_data2, 25); + fill_pattern(buffer - indexSectionOffset, + &indexHeader->rish_unused_data3, 1); + // index table + data = skip_bytes(data, kResourceIndexSectionHeaderSize); + resource_index_entry *entry = (resource_index_entry*)data; + uint32 entryOffset = dataOffset; + for (int32 i = 0; i < resourceCount; i++, entry++) { + ResourceItem *item = container.ResourceAt(i); + uint32 entrySize = item->DataSize(); + entry->rie_offset = entryOffset; + entry->rie_size = entrySize; + entry->rie_pad = 0; + entryOffset += entrySize; + } + fill_pattern(buffer - indexSectionOffset, entry, + buffer + indexSectionSize); + write_exactly(fFile, indexSectionOffset, buffer, indexSectionSize, + "Failed to write index section."); + // unknown section + fill_pattern(unknownSectionOffset, buffer, unknownSectionSize / 4); + write_exactly(fFile, unknownSectionOffset, buffer, unknownSectionSize, + "Failed to write unknown section."); + // data + uint32 itemOffset = dataOffset; + for (int32 i = 0; i < resourceCount; i++) { + data = buffer; + ResourceItem *item = container.ResourceAt(i); + const void *itemData = item->Data(); + uint32 itemSize = item->DataSize(); + if (!itemData && itemSize > 0) + throw Exception(error, "Invalid resource item data."); + if (itemData) { + // swap data, if necessary + if (!fHostEndianess) { + memcpy(data, itemData, itemSize); + swap_data(item->Type(), data, itemSize, B_SWAP_ALWAYS); + itemData = data; + } + write_exactly(fFile, itemOffset, itemData, itemSize, + "Failed to write resource item data."); + } + item->SetOffset(itemOffset); + itemOffset += itemSize; + } + // info table + data = buffer; + type = 0; + for (int32 i = 0; i < resourceCount; i++) { + ResourceItem *item = container.ResourceAt(i); + resource_info *info = NULL; + if (i == 0 || type != item->Type()) { + if (i != 0) { + resource_info_separator *separator + = (resource_info_separator*)data; + separator->ris_value1 = 0xffffffff; + separator->ris_value2 = 0xffffffff; + data = skip_bytes(data, kResourceInfoSeparatorSize); + } + type = item->Type(); + resource_info_block *infoBlock = (resource_info_block*)data; + infoBlock->rib_type = type; + info = infoBlock->rib_info; + } else + info = (resource_info*)data; + // info + info->ri_id = item->ID(); + info->ri_index = i + 1; + info->ri_name_size = 0; + data = info->ri_name; + if (const char *name = item->Name()) { + uint32 nameLen = strlen(name); + memcpy(info->ri_name, name, nameLen + 1); + data = skip_bytes(data, nameLen + 1); + info->ri_name_size = nameLen + 1; + } + } + // separator + resource_info_separator *separator = (resource_info_separator*)data; + separator->ris_value1 = 0xffffffff; + separator->ris_value2 = 0xffffffff; + // table end + data = skip_bytes(data, kResourceInfoSeparatorSize); + resource_info_table_end *tableEnd = (resource_info_table_end*)data; + tableEnd->rite_check_sum = calculate_checksum(buffer, + infoTableSize - kResourceInfoTableEndSize); + tableEnd->rite_terminator = 0; + write_exactly(fFile, infoTableOffset, buffer, infoTableSize, + "Failed to write info table."); + } catch (Exception exception) { + if (exception.Error() != B_OK) + error = exception.Error(); + else + error = B_ERROR; + } + delete[] buffer; + return error; +} + +// _MakeEmptyResourceFile +status_t +ResourceFile::_MakeEmptyResourceFile() +{ + status_t error = fFile.InitCheck(); + if (error == B_OK && !fFile.File()->IsWritable()) + error = B_NOT_ALLOWED; + if (error == B_OK) { + try { + BFile *file = fFile.File(); + // make it an x86 resource file + error = file->SetSize(4); + if (error != B_OK) + throw Exception(error, "Failed to set file size."); + write_exactly(*file, 0, kX86ResourceFileMagic, 4, + "Failed to write magic number."); + fHostEndianess = B_HOST_IS_LENDIAN; + fFileType = FILE_TYPE_X86_RESOURCE; + fFile.SetTo(file, kX86ResourcesOffset); + fEmptyResources = true; + } catch (Exception exception) { + if (exception.Error() != B_OK) + error = exception.Error(); + else + error = B_ERROR; + } + } + return error; +} + + +}; // namespace StorageKit + diff --git a/src/kits/storage/ResourceItem.cpp b/src/kits/storage/ResourceItem.cpp new file mode 100644 index 0000000000..ecaaf2fa42 --- /dev/null +++ b/src/kits/storage/ResourceItem.cpp @@ -0,0 +1,191 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file ResourcesItem.cpp + ResourceItem implementation. +*/ + +#include "ResourceItem.h" + +#include +#include + +#include + +namespace StorageKit { + +// constructor +ResourceItem::ResourceItem() + : BMallocIO(), + fOffset(0), + fInitialSize(0), + fType(0), + fID(0), + fName(), + fIsLoaded(false), + fIsModified(false) +{ + SetBlockSize(1); +} + +// destructor +ResourceItem::~ResourceItem() +{ +} + +// WriteAt +ssize_t +ResourceItem::WriteAt(off_t pos, const void *buffer, size_t size) +{ + ssize_t result = BMallocIO::WriteAt(pos, buffer, size); + if (result >= 0) + SetModified(true); + return result; +} + +// SetSize +status_t +ResourceItem::SetSize(off_t size) +{ + status_t error = BMallocIO::SetSize(size); + if (error == B_OK) + SetModified(true); + return error; +} + +// SetLocation +void +ResourceItem::SetLocation(int32 offset, size_t initialSize) +{ + SetOffset(offset); + fInitialSize = initialSize; +} + +// SetIdentity +void +ResourceItem::SetIdentity(type_code type, int32 id, const char *name) +{ + fType = type; + fID = id; + fName = name; +} + +// SetOffset +void +ResourceItem::SetOffset(int32 offset) +{ + fOffset = offset; +} + +// Offset +int32 +ResourceItem::Offset() const +{ + return fOffset; +} + +// InitialSize +size_t +ResourceItem::InitialSize() const +{ + return fInitialSize; +} + +// DataSize +size_t +ResourceItem::DataSize() const +{ + if (IsModified()) + return BufferLength(); + return fInitialSize; +} + +// SetType +void +ResourceItem::SetType(type_code type) +{ + fType = type; +} + +// Type +type_code +ResourceItem::Type() const +{ + return fType; +} + +// SetID +void +ResourceItem::SetID(int32 id) +{ + fID = id; +} + +// ID +int32 +ResourceItem::ID() const +{ + return fID; +} + +// SetName +void +ResourceItem::SetName(const char *name) +{ + fName = name; +} + +// Name +const char * +ResourceItem::Name() const +{ + if (fName.Length() > 0) + return fName.String(); + return NULL; +} + +// Data +void * +ResourceItem::Data() const +{ + // Since MallocIO may have a NULL buffer, if the data size is 0, + // we return a pointer to ourselves in this case. This ensures, that + // the resource item still can be uniquely identified by its data pointer. + if (DataSize() == 0) + return const_cast(this); + return const_cast(Buffer()); +} + +// SetLoaded +void +ResourceItem::SetLoaded(bool loaded) +{ + fIsLoaded = loaded; +} + +// IsLoaded +bool +ResourceItem::IsLoaded() const +{ + return (BufferLength() > 0 || fIsLoaded); +} + +// SetModified +void +ResourceItem::SetModified(bool modified) +{ + fIsModified = modified; +} + +// IsModified +bool +ResourceItem::IsModified() const +{ + return fIsModified; +} + + +}; // namespace StorageKit + diff --git a/src/kits/storage/ResourceStrings.cpp b/src/kits/storage/ResourceStrings.cpp new file mode 100644 index 0000000000..c94f91aadc --- /dev/null +++ b/src/kits/storage/ResourceStrings.cpp @@ -0,0 +1,402 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file ResourceStrings.cpp + BResourceStrings implementation. +*/ + +#include + +#include +#include + +#include +#include +#include +#include + +#include "kernel_interface.h" + +// constructor +/*! \brief Creates an object initialized to the application's string resources. +*/ +BResourceStrings::BResourceStrings() + : _string_lock(), + _init_error(), + fFileRef(), + fResources(NULL), + fHashTable(NULL), + fHashTableSize(0), + fStringCount(0) +{ + SetStringFile(NULL); +} + +// constructor +/*! \brief Creates an object initialized to the string resources of the + file referred to by the supplied entry_ref. + \param ref the entry_ref referring to the resource file +*/ +BResourceStrings::BResourceStrings(const entry_ref &ref) + : _string_lock(), + _init_error(), + fFileRef(), + fResources(NULL), + fHashTable(NULL), + fHashTableSize(0), + fStringCount(0) +{ + SetStringFile(&ref); +} + +// destructor +/*! \brief Frees all resources associated with the BResourceStrings object. +*/ +BResourceStrings::~BResourceStrings() +{ + _string_lock.Lock(); + _Cleanup(); +} + +// InitCheck +/*! \brief Returns the status of the last initialization via contructor or + SetStringFile(). + \return \c B_OK, if the object is properly initialized, an error code + otherwise. +*/ +status_t +BResourceStrings::InitCheck() +{ + return _init_error; +} + +// NewString +/*! \brief Finds and returns a copy of the string identified by the supplied + ID. + The caller is responsible for deleting the returned BString object. + \param id the ID of the requested string + \return + - A string object containing the requested string, + - \c NULL, if the object is not properly initialized or there is no string + with ID \a id. +*/ +BString * +BResourceStrings::NewString(int32 id) +{ +// _string_lock.Lock(); + BString *result = NULL; + if (const char *str = FindString(id)) + result = new(nothrow) BString(str); +// _string_lock.Unlock(); + return result; +} + +// FindString +/*! \brief Finds and returns the string identified by the supplied ID. + The caller must not free the returned string. It belongs to the + BResourceStrings object and is valid until the object is destroyed or set + to another file. + \param id the ID of the requested string + \return + - The requested string, + - \c NULL, if the object is not properly initialized or there is no string + with ID \a id. +*/ +const char * +BResourceStrings::FindString(int32 id) +{ + _string_lock.Lock(); + const char *result = NULL; + if (InitCheck() == B_OK) { + if (_string_id_hash *entry = _FindString(id)) + result = entry->data; + } + _string_lock.Unlock(); + return result; +} + +// SetStringFile +/*! \brief Re-initialized the BResourceStrings object to the file referred to + by the supplied entry_ref. + If the supplied entry_ref is \c NULL, the object is initialized to the + application file. + \param ref the entry_ref referring to the resource file +*/ +status_t +BResourceStrings::SetStringFile(const entry_ref *ref) +{ + _string_lock.Lock(); + // cleanup + _Cleanup(); + // get the ref (if NULL, take the application) + status_t error = B_OK; + entry_ref fileRef; + if (ref) { + fileRef = *ref; + fFileRef = *ref; + } else { + char appPath[B_PATH_NAME_LENGTH + 1]; + error = StorageKit::get_app_path(appPath); + if (error == B_OK) + error = get_ref_for_path(appPath, &fileRef); + } + // get the BResources + if (error == B_OK) { + BFile file(&fileRef, B_READ_ONLY); + error = file.InitCheck(); + if (error == B_OK) { + fResources = new(nothrow) BResources; + if (fResources) + error = fResources->SetTo(&file); + else + error = B_NO_MEMORY; + } + } + // read the strings + if (error == B_OK) { + // count them first + fStringCount = 0; + int32 id; + const char *name; + size_t length; + while (fResources->GetResourceInfo(RESOURCE_TYPE, fStringCount, &id, + &name, &length)) { + fStringCount++; + } + // allocate a hash table with a nice size + // I don't have a heuristic at hand, so let's simply take the count. + error = _Rehash(fStringCount); + // load the resources + for (int32 i = 0; error == B_OK && i < fStringCount; i++) { + if (!fResources->GetResourceInfo(RESOURCE_TYPE, i, &id, &name, + &length)) { + error = B_ERROR; + } + if (error == B_OK) { + const void *data + = fResources->LoadResource(RESOURCE_TYPE, id, &length); + if (data) { + _string_id_hash *entry = NULL; + if (length == 0) + entry = _AddString(NULL, id, false); + else + entry = _AddString((char*)data, id, false); + if (!entry) + error = B_ERROR; + } else + error = B_ERROR; + } + } + } + // if something went wrong, cleanup the mess + if (error != B_OK) + _Cleanup(); + _init_error = error; + _string_lock.Unlock(); + return error; +} + +// GetStringFile +/*! \brief Returns an entry_ref referring to the resource file, the object is + currently initialized to. + \param outRef a pointer to an entry_ref variable to be initialized to the + requested entry_ref + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a outRef. + - other error codes +*/ +status_t +BResourceStrings::GetStringFile(entry_ref *outRef) +{ + status_t error = (outRef ? B_OK : B_BAD_VALUE); + if (error == B_OK) + error = InitCheck(); + if (error == B_OK) { + if (fFileRef == entry_ref()) + error = B_ENTRY_NOT_FOUND; + else + *outRef = fFileRef; + } + return error; +} + + +// _Cleanup +/*! \brief Frees all resources associated with this object and sets all + member variables to harmless values. +*/ +void +BResourceStrings::_Cleanup() +{ +// _string_lock.Lock(); + _MakeEmpty(); + delete[] fHashTable; + fHashTable = NULL; + delete fResources; + fResources = NULL; + fFileRef = entry_ref(); + fHashTableSize = 0; + fStringCount = 0; + _init_error = B_OK; +// _string_lock.Unlock(); +} + +// _MakeEmpty +/*! \brief Empties the id->string hash table. +*/ +void +BResourceStrings::_MakeEmpty() +{ + if (fHashTable) { + for (int32 i = 0; i < fHashTableSize; i++) { + while (_string_id_hash *entry = fHashTable[i]) { + fHashTable[i] = entry->next; + delete entry; + } + } + fStringCount = 0; + } +} + +// _Rehash +/*! \brief Resizes the id->string hash table to the supplied size. + \param newSize the new hash table size + \return + - \c B_OK: Everything went fine. + - \c B_NO_MEMORY: Insuffient memory. +*/ +status_t +BResourceStrings::_Rehash(int32 newSize) +{ + status_t error = B_OK; + if (newSize > 0 && newSize != fHashTableSize) { + // alloc a new table and fill it with NULL + _string_id_hash **newHashTable + = new(nothrow) _string_id_hash*[newSize]; + if (newHashTable) { + memset(newHashTable, 0, sizeof(_string_id_hash*) * newSize); + // move the entries to the new table + if (fHashTable && fHashTableSize > 0 && fStringCount > 0) { + for (int32 i = 0; i < fHashTableSize; i++) { + while (_string_id_hash *entry = fHashTable[i]) { + fHashTable[i] = entry->next; + int32 newPos = entry->id % newSize; + entry->next = newHashTable[newPos]; + newHashTable[newPos] = entry; + } + } + } + // set the new table + delete[] fHashTable; + fHashTable = newHashTable; + fHashTableSize = newSize; + } else + error = B_NO_MEMORY; + } + return error; +} + +// _AddString +/*! \brief Adds an entry to the id->string hash table. + If there is already a string with the given ID, it will be replaced. + \param str the string + \param id the id of the string + \param wasMalloced if \c true, the object will be responsible for + free()ing the supplied string + \return the hash table entry or \c NULL, if something went wrong +*/ +BResourceStrings::_string_id_hash * +BResourceStrings::_AddString(char *str, int32 id, bool wasMalloced) +{ + _string_id_hash *entry = NULL; + if (fHashTable && fHashTableSize > 0) + entry = new(nothrow) _string_id_hash; + if (entry) { + entry->assign_string(str, false); + entry->id = id; + entry->data_alloced = wasMalloced; + int32 pos = id % fHashTableSize; + entry->next = fHashTable[pos]; + fHashTable[pos] = entry; + } + return entry; +} + +// _FindString +/*! \brief Returns the hash table entry for a given ID. + \param id the ID + \return the hash table entry or \c NULL, if there is no entry with this ID +*/ +BResourceStrings::_string_id_hash * +BResourceStrings::_FindString(int32 id) +{ + _string_id_hash *entry = NULL; + if (fHashTable && fHashTableSize > 0) { + int32 pos = id % fHashTableSize; + entry = fHashTable[pos]; + while (entry != NULL && entry->id != id) + entry = entry->next; + } + return entry; +} + + +// FBC +void BResourceStrings::_ReservedResourceStrings0() {} +void BResourceStrings::_ReservedResourceStrings1() {} +void BResourceStrings::_ReservedResourceStrings2() {} +void BResourceStrings::_ReservedResourceStrings3() {} +void BResourceStrings::_ReservedResourceStrings4() {} +void BResourceStrings::_ReservedResourceStrings5() {} + + +// _string_id_hash + +// constructor +/*! \brief Creates an uninitialized hash table entry. +*/ +BResourceStrings::_string_id_hash::_string_id_hash() + : next(NULL), + id(0), + data(NULL), + data_alloced(false) +{ +} + +// destructor +/*! \brief Frees all resources associated with this object. + Only if \c data_alloced is \c true, the string will be free()d. +*/ +BResourceStrings::_string_id_hash::~_string_id_hash() +{ + if (data_alloced) + free(data); +} + +// assign_string +/*! \brief Sets the string of the hash table entry. + \param str the string + \param makeCopy If \c true, the supplied string is copied and the copy + will be freed on destruction. If \c false, the entry points to the + supplied string. It will not be freed() on destruction. +*/ +void +BResourceStrings::_string_id_hash::assign_string(const char *str, + bool makeCopy) +{ + if (data_alloced) + free(data); + data = NULL; + data_alloced = false; + if (str) { + if (makeCopy) { + data = strdup(str); + data_alloced = true; + } else + data = const_cast(str); + } +} + diff --git a/src/kits/storage/Resources.cpp b/src/kits/storage/Resources.cpp new file mode 100644 index 0000000000..62a94fafaa --- /dev/null +++ b/src/kits/storage/Resources.cpp @@ -0,0 +1,848 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file Resources.cpp + BResources implementation. + + BResources delegates most of the work to ResourcesContainer and + ResourceFile. The first one manages a collections of ResourceItem's, + the actual resources, whereas the latter provides the file I/O + functionality. + An InitCheck() method is not needed, since a BResources object will + never be invalid. It always serves as a resources container, even if + it is not associated with a file. It is always possible to WriteTo() + the resources BResources contains to a file (a valid one of course). +*/ +#include + +#include +#include + +#include "ResourceFile.h" +#include "ResourceItem.h" +#include "ResourcesContainer.h" + +using namespace StorageKit; + +enum { + NOT_IMPLEMENTED = B_ERROR, +}; + +// constructor +/*! \brief Creates an unitialized BResources object. +*/ +BResources::BResources() + : fFile(), + fContainer(NULL), + fResourceFile(NULL), + fReadOnly(false) +{ + fContainer = new(nothrow) ResourcesContainer; +} + +// constructor +/*! \brief Creates a BResources object that represents the resources of the + supplied file. + If the \a clobber argument is \c true, the data of the file are erased + and it is turned into an empty resource file. Otherwise \a file + must refer either to a resource file or to an executable (ELF or PEF + binary). If the file has been opened \c B_READ_ONLY, only read access + to its resources is possible. + The BResources object makes a copy of \a file, that is the caller remains + owner of the BFile object. + \param file the file + \param clobber if \c true, the \a file is truncated to size 0 +*/ +BResources::BResources(const BFile *file, bool clobber) + : fFile(), + fContainer(NULL), + fResourceFile(NULL), + fReadOnly(false) +{ + fContainer = new(nothrow) ResourcesContainer; + SetTo(file, clobber); +} + +// destructor +/*! \brief Frees all resources associated with this object + Calls Sync() before doing so to make sure that the changes are written + back to the file. +*/ +BResources::~BResources() +{ + Unset(); + delete fContainer; +} + +// SetTo +/*! \brief Re-initialized the BResources object to represent the resources of + the supplied file. + What happens, if \a clobber is \c true, depends on the type of the file. + If the file is capable of containing resources, that is, is a resource + file or an executable (ELF or PEF), its resources are removed. Otherwise + the file's data are erased and it is turned into an empty resource file. + If \a clobber is \c false, \a file must refer to a file that is capable + of containing resources. + If the file has been opened \c B_READ_ONLY, only read access + to its resources is possible. + The BResources object makes a copy of \a file, that is the caller remains + owner of the BFile object. + \param file the file + \param clobber if \c true, the \a file is truncated to size 0 + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL or uninitialized \a file. + - \c B_ERROR: Failed to initialize the object (for whatever reason). +*/ +status_t +BResources::SetTo(const BFile *file, bool clobber) +{ + Unset(); + status_t error = B_OK; + if (file) { + error = file->InitCheck(); + if (error == B_OK) { + fFile = *file; + error = fFile.InitCheck(); + } + if (error == B_OK) { + fReadOnly = !fFile.IsWritable(); + fResourceFile = new(nothrow) ResourceFile; + if (fResourceFile) + error = fResourceFile->SetTo(&fFile, clobber); + else + error = B_NO_MEMORY; + } + if (error == B_OK) { + if (fContainer) + error = fResourceFile->InitContainer(*fContainer); + else + error = B_NO_MEMORY; + } + } + if (error != B_OK) { + delete fResourceFile; + fResourceFile = NULL; + if (fContainer) + fContainer->MakeEmpty(); + } + return error; +} + +// Unset +/*! \brief Returns the BResources object to an uninitialized state. + If the object represented resources that had been modified, the data are + written back to the file. + \note This method extends the BeOS R5 API. +*/ +void +BResources::Unset() +{ + if (fContainer && fContainer->IsModified()) + Sync(); + delete fResourceFile; + fResourceFile = NULL; + fFile.Unset(); + if (fContainer) + fContainer->MakeEmpty(); + else + fContainer = new(nothrow) ResourcesContainer; + fReadOnly = false; +} + +// InitCheck +/*! Returns the current initialization status. + Unlike other Storage Kit classes a BResources object is always properly + initialized, unless it couldn't allocate memory for some important + internal structures. Thus even after a call to SetTo() that reported an + error, InitCheck() is likely to return \c B_OK. + \return + - \c B_OK, if the objects is properly initialized, + - \c B_NO_MEMORY otherwise. + \note This method extends the BeOS R5 API. +*/ +status_t +BResources::InitCheck() const +{ + return (fContainer ? B_OK : B_NO_MEMORY); +} + +// File +/*! \brief Returns a reference to the BResources' BFile object. + \return a reference to the object's BFile. +*/ +const BFile & +BResources::File() const +{ + return fFile; +} + +// LoadResource +/*! \brief Loads a resource identified by type and ID into memory. + A resource is loaded into memory only once. A second call with the same + parameters will result in the same pointer. The BResources object is the + owner of the allocated memory and the pointer to it will be valid until + the object is destroyed or the resource is removed or modified. + \param type the type of the resource to be loaded + \param id the ID of the resource to be loaded + \param outSize a pointer to a variable into which the size of the resource + shall be written + \return A pointer to the resource data, if everything went fine, or + \c NULL, if the file does not have a resource that matchs the + parameters or an error occured. +*/ +const void * +BResources::LoadResource(type_code type, int32 id, size_t *outSize) +{ + // find the resource + status_t error = InitCheck(); + ResourceItem *resource = NULL; + if (error == B_OK) { + resource = fContainer->ResourceAt(fContainer->IndexOf(type, id)); + if (!resource) + error = B_ENTRY_NOT_FOUND; + } + // load it, if necessary + if (error == B_OK && !resource->IsLoaded() && fResourceFile) + error = fResourceFile->ReadResource(*resource); + // return the result + const void *result = NULL; + if (error == B_OK) { + result = resource->Data(); + if (outSize) + *outSize = resource->DataSize(); + } + return result; +} + +// LoadResource +/*! \brief Loads a resource identified by type and name into memory. + A resource is loaded into memory only once. A second call with the same + parameters will result in the same pointer. The BResources object is the + owner of the allocated memory and the pointer to it will be valid until + the object is destroyed or the resource is removed or modified. + \param type the type of the resource to be loaded + \param name the name of the resource to be loaded + \param outSize a pointer to a variable into which the size of the resource + shall be written + \return A pointer to the resource data, if everything went fine, or + \c NULL, if the file does not have a resource that matches the + parameters or an error occured. + \note Since a type and name pair may not identify a resource uniquely, + this method always returns the first resource that matches the + parameters, that is the one with the least index. +*/ +const void * +BResources::LoadResource(type_code type, const char *name, size_t *outSize) +{ + // find the resource + status_t error = InitCheck(); + ResourceItem *resource = NULL; + if (error == B_OK) { + resource = fContainer->ResourceAt(fContainer->IndexOf(type, name)); + if (!resource) + error = B_ENTRY_NOT_FOUND; + } + // load it, if necessary + if (error == B_OK && !resource->IsLoaded() && fResourceFile) + error = fResourceFile->ReadResource(*resource); + // return the result + const void *result = NULL; + if (error == B_OK) { + result = resource->Data(); + if (outSize) + *outSize = resource->DataSize(); + } + return result; +} + +// PreloadResourceType +/*! \brief Loads all resources of a certain type into memory. + For performance reasons it might be useful to do that. If \a type is + 0, all resources are loaded. + \param type of the resources to be loaded + \return + - \c B_OK: Everything went fine. + - \c B_BAD_FILE: The resource map is empty??? + - The negative of the number of errors occured. +*/ +status_t +BResources::PreloadResourceType(type_code type) +{ + status_t error = InitCheck(); + if (error == B_OK && fResourceFile) { + if (type == 0) + error = fResourceFile->ReadResources(*fContainer); + else { + int32 count = fContainer->CountResources(); + int32 errorCount = 0; + for (int32 i = 0; i < count; i++) { + ResourceItem *resource = fContainer->ResourceAt(i); + if (resource->Type() == type) { + if (fResourceFile->ReadResource(*resource) != B_OK) + errorCount++; + } + } + error = -errorCount; + } + } + return error; +} + +// Sync +/*! \brief Writes all changes to the resources to the file. + Since AddResource() and RemoveResource() may change the resources only in + memory, this method can be used to make sure, that all changes are + actually written to the file. + The BResources object's destructor calls Sync() before cleaning up. + \return + - \c B_OK: Everything went fine. + - \c B_BAD_FILE: The resource map is empty??? + - \c B_NOT_ALLOWED: The file is opened read only. + - \c B_FILE_ERROR: A file error occured. + - \c B_IO_ERROR: An error occured while writing the resources. + \note When a resource is written to the file, its data are converted + to the endianess of the file, and when reading a resource, the + data are converted to the host's endianess. This does of course + only work for known types, i.e. those that swap_data() is able to + cope with. +*/ +status_t +BResources::Sync() +{ + status_t error = InitCheck(); + if (error == B_OK) + error = fFile.InitCheck(); + if (error == B_OK) { + if (fReadOnly) + error = B_NOT_ALLOWED; + else if (!fResourceFile) + error = B_FILE_ERROR; + } + if (error == B_OK) + error = fResourceFile->ReadResources(*fContainer); + if (error == B_OK) + error = fResourceFile->WriteResources(*fContainer); + return error; +} + +// MergeFrom +/*! \brief Adds the resources of the supplied file to this file's resources. + \param fromFile the file whose resources shall be copied + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a fromFile. + - \c B_BAD_FILE: The resource map is empty??? + - \c B_FILE_ERROR: A file error occured. + - \c B_IO_ERROR: An error occured while writing the resources. +*/ +status_t +BResources::MergeFrom(BFile *fromFile) +{ + status_t error = (fromFile ? B_OK : B_BAD_VALUE); + if (error == B_OK) + error = InitCheck(); + if (error == B_OK) { + ResourceFile resourceFile; + error = resourceFile.SetTo(fromFile); + ResourcesContainer container; + if (error == B_OK) + error = resourceFile.InitContainer(container); + if (error == B_OK) + error = resourceFile.ReadResources(container); + if (error == B_OK) + fContainer->AssimilateResources(container); + } + return error; +} + +// WriteTo +/*! \brief Writes the resources to a new file. + The resources formerly contained in the target file (if any) are erased. + When the method returns, the BResources object refers to the new file. + \param file the file the resources shall be written to. + \return + - \c B_OK: Everything went fine. + - a specific error code. + \note If the resources have been modified, but not Sync()ed, the old file + remains unmodified. +*/ +status_t +BResources::WriteTo(BFile *file) +{ + status_t error = (file ? B_OK : B_BAD_VALUE); + if (error == B_OK) + error = InitCheck(); + // make sure, that all resources are loaded + if (error == B_OK && fResourceFile) { + error = fResourceFile->ReadResources(*fContainer); + fResourceFile->Unset(); + } + // set the new file, but keep the old container + if (error == B_OK) { + ResourcesContainer *container = fContainer; + fContainer = new(nothrow) ResourcesContainer; + if (fContainer) { + error = SetTo(file, false); + delete fContainer; + } else + error = B_NO_MEMORY; + fContainer = container; + } + // write the resources + if (error == B_OK && fResourceFile) + error = fResourceFile->WriteResources(*fContainer); + return error; +} + +// AddResource +/*! \brief Adds a new resource to the file. + If a resource with the same type and ID does already exist, it is + replaced. The caller keeps the ownership of the supplied chunk of memory + containing the resource data. + Supplying an empty name (\c "") is equivalent to supplying a \c NULL name. + \param type the type of the resource + \param id the ID of the resource + \param data the resource data + \param length the size of the data in bytes + \param name the name of the resource (may be \c NULL) + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL \a data + - \c B_NOT_ALLOWED: The file is opened read only. + - \c B_FILE_ERROR: A file error occured. + - \c B_NO_MEMORY: Not enough memory for that operation. +*/ +status_t +BResources::AddResource(type_code type, int32 id, const void *data, + size_t length, const char *name) +{ + status_t error = (data ? B_OK : B_BAD_VALUE); + if (error == B_OK) + error = InitCheck(); + if (error == B_OK) + error = (fReadOnly ? B_NOT_ALLOWED : B_OK); + if (error == B_OK) { + ResourceItem *item = new(nothrow) ResourceItem; + if (!item) + error = B_NO_MEMORY; + if (error == B_OK) { + item->SetIdentity(type, id, name); + ssize_t written = item->WriteAt(0, data, length); + if (written < 0) + error = written; + else if (written != (ssize_t)length) + error = B_ERROR; + } + if (error == B_OK) { + if (!fContainer->AddResource(item)) + error = B_NO_MEMORY; + } + if (error != B_OK) + delete item; + } + return error; +} + +// HasResource +/*! \brief Returns whether the file contains a resource with a certain + type and ID. + \param type the resource type + \param id the ID of the resource + \return \c true, if the file contains a matching resource, \false otherwise +*/ +bool +BResources::HasResource(type_code type, int32 id) +{ + return (InitCheck() == B_OK && fContainer->IndexOf(type, id) >= 0); +} + +// HasResource +/*! \brief Returns whether the file contains a resource with a certain + type and name. + \param type the resource type + \param name the name of the resource + \return \c true, if the file contains a matching resource, \false otherwise +*/ +bool +BResources::HasResource(type_code type, const char *name) +{ + return (InitCheck() == B_OK && fContainer->IndexOf(type, name) >= 0); +} + +// GetResourceInfo +/*! \brief Returns information about a resource identified by an index. + \param byIndex the index of the resource in the file + \param typeFound a pointer to a variable the type of the found resource + shall be written into + \param idFound a pointer to a variable the ID of the found resource + shall be written into + \param nameFound a pointer to a variable the name pointer of the found + resource shall be written into + \param lengthFound a pointer to a variable the data size of the found + resource shall be written into + \return \c true, if a matching resource could be found, false otherwise +*/ +bool +BResources::GetResourceInfo(int32 byIndex, type_code *typeFound, + int32 *idFound, const char **nameFound, + size_t *lengthFound) +{ + ResourceItem *item = NULL; + if (InitCheck() == B_OK) + item = fContainer->ResourceAt(byIndex); + if (item) { + if (typeFound) + *typeFound = item->Type(); + if (idFound) + *idFound = item->ID(); + if (nameFound) + *nameFound = item->Name(); + if (lengthFound) + *lengthFound = item->DataSize(); + } + return item; +} + +// GetResourceInfo +/*! \brief Returns information about a resource identified by a type and an + index. + \param byType the resource type + \param andIndex the index into a array of resources of type \a byType + \param idFound a pointer to a variable the ID of the found resource + shall be written into + \param nameFound a pointer to a variable the name pointer of the found + resource shall be written into + \param lengthFound a pointer to a variable the data size of the found + resource shall be written into + \return \c true, if a matching resource could be found, false otherwise +*/ +bool +BResources::GetResourceInfo(type_code byType, int32 andIndex, int32 *idFound, + const char **nameFound, size_t *lengthFound) +{ + ResourceItem *item = NULL; + if (InitCheck() == B_OK) { + item = fContainer->ResourceAt(fContainer->IndexOfType(byType, + andIndex)); + } + if (item) { + if (idFound) + *idFound = item->ID(); + if (nameFound) + *nameFound = item->Name(); + if (lengthFound) + *lengthFound = item->DataSize(); + } + return item; +} + +// GetResourceInfo +/*! \brief Returns information about a resource identified by a type and an ID. + \param byType the resource type + \param andID the resource ID + \param nameFound a pointer to a variable the name pointer of the found + resource shall be written into + \param lengthFound a pointer to a variable the data size of the found + resource shall be written into + \return \c true, if a matching resource could be found, false otherwise +*/ +bool +BResources::GetResourceInfo(type_code byType, int32 andID, + const char **nameFound, size_t *lengthFound) +{ + ResourceItem *item = NULL; + if (InitCheck() == B_OK) + item = fContainer->ResourceAt(fContainer->IndexOf(byType, andID)); + if (item) { + if (nameFound) + *nameFound = item->Name(); + if (lengthFound) + *lengthFound = item->DataSize(); + } + return item; +} + +// GetResourceInfo +/*! \brief Returns information about a resource identified by a type and a + name. + \param byType the resource type + \param andName the resource name + \param idFound a pointer to a variable the ID of the found resource + shall be written into + \param lengthFound a pointer to a variable the data size of the found + resource shall be written into + \return \c true, if a matching resource could be found, false otherwise +*/ +bool +BResources::GetResourceInfo(type_code byType, const char *andName, + int32 *idFound, size_t *lengthFound) +{ + ResourceItem *item = NULL; + if (InitCheck() == B_OK) + item = fContainer->ResourceAt(fContainer->IndexOf(byType, andName)); + if (item) { + if (idFound) + *idFound = item->ID(); + if (lengthFound) + *lengthFound = item->DataSize(); + } + return item; +} + +// GetResourceInfo +/*! \brief Returns information about a resource identified by a data pointer. + \param byPointer the pointer to the resource data (formely returned by + LoadResource()) + \param typeFound a pointer to a variable the type of the found resource + shall be written into + \param idFound a pointer to a variable the ID of the found resource + shall be written into + \param lengthFound a pointer to a variable the data size of the found + resource shall be written into + \param nameFound a pointer to a variable the name pointer of the found + resource shall be written into + \return \c true, if a matching resource could be found, false otherwise +*/ +bool +BResources::GetResourceInfo(const void *byPointer, type_code *typeFound, + int32 *idFound, size_t *lengthFound, + const char **nameFound) +{ + ResourceItem *item = NULL; + if (InitCheck() == B_OK) + item = fContainer->ResourceAt(fContainer->IndexOf(byPointer)); + if (item) { + if (typeFound) + *typeFound = item->Type(); + if (idFound) + *idFound = item->ID(); + if (nameFound) + *nameFound = item->Name(); + if (lengthFound) + *lengthFound = item->DataSize(); + } + return item; +} + +// RemoveResource +/*! \brief Removes a resource identified by its data pointer. + \param resource the pointer to the resource data (formely returned by + LoadResource()) + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \c NULL or invalid (not pointing to any resource data of + this file) \a resource. + - \c B_NOT_ALLOWED: The file is opened read only. + - \c B_FILE_ERROR: A file error occured. + - \c B_ERROR: An error occured while removing the resource. +*/ +status_t +BResources::RemoveResource(const void *resource) +{ + status_t error = (resource ? B_OK : B_BAD_VALUE); + if (error == B_OK) + error = InitCheck(); + if (error == B_OK) + error = (fReadOnly ? B_NOT_ALLOWED : B_OK); + if (error == B_OK) { + ResourceItem *item + = fContainer->RemoveResource(fContainer->IndexOf(resource)); + if (item) + delete item; + else + error = B_BAD_VALUE; + } + return error; +} + +// RemoveResource +/*! \brief Removes a resource identified by type and ID. + \param type the type of the resource + \param id the ID of the resource + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: No such resource. + - \c B_NOT_ALLOWED: The file is opened read only. + - \c B_FILE_ERROR: A file error occured. + - \c B_ERROR: An error occured while removing the resource. +*/ +status_t +BResources::RemoveResource(type_code type, int32 id) +{ + status_t error = InitCheck(); + if (error == B_OK) + error = (fReadOnly ? B_NOT_ALLOWED : B_OK); + if (error == B_OK) { + ResourceItem *item + = fContainer->RemoveResource(fContainer->IndexOf(type, id)); + if (item) + delete item; + else + error = B_BAD_VALUE; + } + return error; +} + + +// deprecated + +// WriteResource +/*! \brief Writes data into an existing resource. + If writing the data would exceed the bounds of the resource, it is + enlarged respectively. If \a offset is past the end of the resource, + padding with unspecified data is inserted. + \param type the type of the resource + \param id the ID of the resource + \param data the data to be written + \param offset the byte offset relative to the beginning of the resource at + which the data shall be written + \param length the size of the data to be written + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \a type and \a id do not identify an existing resource or + \c NULL \a data. + - \c B_NO_MEMORY: Not enough memory for this operation. + - other error codes. + \deprecated Always use AddResource(). +*/ +status_t +BResources::WriteResource(type_code type, int32 id, const void *data, + off_t offset, size_t length) +{ + status_t error = (data && offset >= 0 ? B_OK : B_BAD_VALUE); + if (error == B_OK) + error = InitCheck(); + if (error == B_OK) + error = (fReadOnly ? B_NOT_ALLOWED : B_OK); + ResourceItem *item = NULL; + if (error == B_OK) { + item = fContainer->ResourceAt(fContainer->IndexOf(type, id)); + if (!item) + error = B_BAD_VALUE; + } + if (error == B_OK && fResourceFile) + error = fResourceFile->ReadResource(*item); + if (error == B_OK) { + if (item) { + ssize_t written = item->WriteAt(offset, data, length); + if (written < 0) + error = written; + else if (written != (ssize_t)length) + error = B_ERROR; + } + } + return error; +} + +// ReadResource +/*! \brief Reads data from an existing resource. + If more data than existing are requested, this method does not fail. It + will then read only the existing data. As a consequence an offset past + the end of the resource will not cause the method to fail, but no data + will be read at all. + \param type the type of the resource + \param id the ID of the resource + \param data a pointer to a buffer into which the data shall be read + \param offset the byte offset relative to the beginning of the resource + from which the data shall be read + \param length the size of the data to be read + \return + - \c B_OK: Everything went fine. + - \c B_BAD_VALUE: \a type and \a id do not identify an existing resource or + \c NULL \a data. + - \c B_NO_MEMORY: Not enough memory for this operation. + - other error codes. + \deprecated Use LoadResource() only. +*/ +status_t +BResources::ReadResource(type_code type, int32 id, void *data, off_t offset, + size_t length) +{ + status_t error = (data && offset >= 0 ? B_OK : B_BAD_VALUE); + if (error == B_OK) + error = InitCheck(); + ResourceItem *item = NULL; + if (error == B_OK) { + item = fContainer->ResourceAt(fContainer->IndexOf(type, id)); + if (!item) + error = B_BAD_VALUE; + } + if (error == B_OK && fResourceFile) + error = fResourceFile->ReadResource(*item); + if (error == B_OK) { + if (item) { + ssize_t read = item->ReadAt(offset, data, length); + if (read < 0) + error = read; + } else + error = B_BAD_VALUE; + } + return error; +} + +// FindResource +/*! \brief Finds a resource by type and ID and returns a copy of its data. + The caller is responsible for free()ing the returned memory. + \param type the type of the resource + \param id the ID of the resource + \param lengthFound a pointer to a variable into which the size of the + resource data shall be written + \return + - a pointer to the resource data, if everything went fine, + - \c NULL, if an error occured. + \deprecated Use LoadResource(). +*/ +void * +BResources::FindResource(type_code type, int32 id, size_t *lengthFound) +{ + void *result = NULL; + size_t size = 0; + if (const void *data = LoadResource(type, id, &size)) { + if ((result = malloc(size))) + memcpy(result, data, size); + } + if (lengthFound) + *lengthFound = size; + return result; +} + +// FindResource +/*! \brief Finds a resource by type and name and returns a copy of its data. + The caller is responsible for free()ing the returned memory. + \param type the type of the resource + \param name the name of the resource + \param lengthFound a pointer to a variable into which the size of the + resource data shall be written + \return + - a pointer to the resource data, if everything went fine, + - \c NULL, if an error occured. + \deprecated Use LoadResource(). +*/ +void * +BResources::FindResource(type_code type, const char *name, size_t *lengthFound) +{ + void *result = NULL; + size_t size = 0; + if (const void *data = LoadResource(type, name, &size)) { + if ((result = malloc(size))) + memcpy(result, data, size); + } + if (lengthFound) + *lengthFound = size; + return result; +} + + +// FBC +void BResources::_ReservedResources1() {} +void BResources::_ReservedResources2() {} +void BResources::_ReservedResources3() {} +void BResources::_ReservedResources4() {} +void BResources::_ReservedResources5() {} +void BResources::_ReservedResources6() {} +void BResources::_ReservedResources7() {} +void BResources::_ReservedResources8() {} + diff --git a/src/kits/storage/ResourcesContainer.cpp b/src/kits/storage/ResourcesContainer.cpp new file mode 100644 index 0000000000..a18aa64bf7 --- /dev/null +++ b/src/kits/storage/ResourcesContainer.cpp @@ -0,0 +1,211 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file ResourcesContainer.cpp + ResourcesContainer implementation. +*/ + +#include + +#include "ResourcesContainer.h" + +#include "ResourceItem.h" + +namespace StorageKit { + +// constructor +ResourcesContainer::ResourcesContainer() + : fResources(), + fIsModified(false) +{ +} + +// destructor +ResourcesContainer::~ResourcesContainer() +{ + MakeEmpty(); +} + +// AddResource +// +// Returns false, if item is NULL or memory is insufficient, true otherwise. +bool +ResourcesContainer::AddResource(ResourceItem *item, int32 index, + bool replace) +{ + bool result = false; + if (item) { + // replace an item with the same type and id + if (replace) + delete RemoveResource(IndexOf(item->Type(), item->ID())); + int32 count = CountResources(); + if (index < 0 || index > count) + index = count; + result = fResources.AddItem(item, count); + SetModified(true); + } + return result; +} + +// RemoveResource +ResourceItem* +ResourcesContainer::RemoveResource(int32 index) +{ + ResourceItem* item = (ResourceItem*)fResources.RemoveItem(index); + if (item) + SetModified(true); + return item; +} + +// RemoveResource +bool +ResourcesContainer::RemoveResource(ResourceItem *item) +{ + return RemoveResource(IndexOf(item)); +} + +// MakeEmpty +void +ResourcesContainer::MakeEmpty() +{ + for (int32 i = 0; ResourceItem *item = ResourceAt(i); i++) + delete item; + fResources.MakeEmpty(); + SetModified(false); +} + +// AssimilateResources +void +ResourcesContainer::AssimilateResources(ResourcesContainer &container) +{ + // Resistance is futile! ;-) + int32 newCount = container.CountResources(); + for (int32 i = 0; i < newCount; i++) { + ResourceItem *item = container.ResourceAt(i); + if (item->IsLoaded()) + AddResource(item); + else { + // That should not happen. + // Delete the item to have a consistent behavior. + delete item; + } + } + container.fResources.MakeEmpty(); + container.SetModified(true); + SetModified(true); +} + +// IndexOf +int32 +ResourcesContainer::IndexOf(ResourceItem *item) const +{ + return fResources.IndexOf(item); +} + +// IndexOf +int32 +ResourcesContainer::IndexOf(const void *data) const +{ + int32 index = -1; + if (data) { + int32 count = CountResources(); + for (int32 i = 0; index == -1 && i < count; i++) { + if (ResourceAt(i)->Data() == data) + index = i; + } + } + return index; +} + +// IndexOf +int32 +ResourcesContainer::IndexOf(type_code type, int32 id) const +{ + int32 index = -1; + int32 count = CountResources(); + for (int32 i = 0; index == -1 && i < count; i++) { + ResourceItem *item = ResourceAt(i); + if (item->Type() == type && item->ID() == id) + index = i; + } + return index; +} + +// IndexOf +int32 +ResourcesContainer::IndexOf(type_code type, const char *name) const +{ + int32 index = -1; + int32 count = CountResources(); + for (int32 i = 0; index == -1 && i < count; i++) { + ResourceItem *item = ResourceAt(i); + const char *itemName = item->Name(); + if (item->Type() == type && (name == NULL && itemName == NULL + || name != NULL && itemName != NULL + && !strcmp(name, itemName))) { + index = i; + } + } + return index; +} + +// IndexOfType +int32 +ResourcesContainer::IndexOfType(type_code type, int32 typeIndex) const +{ + int32 index = -1; + int32 count = CountResources(); + for (int32 i = 0; index == -1 && i < count; i++) { + ResourceItem *item = ResourceAt(i); + if (item->Type() == type) { + if (typeIndex == 0) + index = i; + typeIndex--; + } + } + return index; +} + +// ResourceAt +ResourceItem* +ResourcesContainer::ResourceAt(int32 index) const +{ + return (ResourceItem*)fResources.ItemAt(index); +} + +// CountResources +int32 +ResourcesContainer::CountResources() const +{ + return fResources.CountItems(); +} + +// SetModified +void +ResourcesContainer::SetModified(bool modified) +{ + fIsModified = modified; + // If unmodified, set the resource item's modified flag as well. + if (!modified) { + int32 count = CountResources(); + for (int32 i = 0; i < count; i++) + ResourceAt(i)->SetModified(false); + } +} + +// IsModified +bool +ResourcesContainer::IsModified() const +{ + bool isModified = fIsModified; + int32 count = CountResources(); + for (int32 i = 0; !isModified && i < count; i++) + isModified |= ResourceAt(i)->IsModified(); + return isModified; +} + + +}; // namespace StorageKit + diff --git a/src/kits/storage/Statable.cpp b/src/kits/storage/Statable.cpp new file mode 100644 index 0000000000..42a76d5bb7 --- /dev/null +++ b/src/kits/storage/Statable.cpp @@ -0,0 +1,324 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file Statable.cpp + BStatable implementation. +*/ + +#include +#include +#include + +#include + +#include "fsproto.h" +#include "kernel_interface.h" + +/*! \fn status_t GetStat(struct stat *st) const + \brief Returns the stat stucture for the node. + \param st the stat structure to be filled in. + \return + - \c B_OK: Worked fine + - \c B_NO_MEMORY: Could not allocate the memory for the call. + - \c B_BAD_VALUE: The current node does not exist. + - \c B_NOT_ALLOWED: Read only node or volume. +*/ + +/*! \brief Returns if the current node is a file. + \return \c true, if the BNode is properly initialized and is a file, + \c false otherwise. +*/ +bool +BStatable::IsFile() const +{ + struct stat statData; + if ( GetStat(&statData) == B_OK ) + return S_ISREG(statData.st_mode); + else + return false; +} + +/*! \brief Returns if the current node is a directory. + \return \c true, if the BNode is properly initialized and is a file, + \c false otherwise. +*/ +bool +BStatable::IsDirectory() const +{ + struct stat statData; + if ( GetStat(&statData) == B_OK ) + return S_ISDIR(statData.st_mode); + else + return false; +} + +/*! \brief Returns if the current node is a symbolic link. + \return \c true, if the BNode is properly initialized and is a symlink, + \c false otherwise. +*/ +bool +BStatable::IsSymLink() const +{ + struct stat statData; + if ( GetStat(&statData) == B_OK ) + return S_ISLNK(statData.st_mode); + else + return false; +} + +/*! \brief Returns a node_ref for the current node. + \param ref the node_ref structure to be filled in + \see GetStat() for return codes +*/ +status_t +BStatable::GetNodeRef(node_ref *ref) const +{ + status_t error = (ref ? B_OK : B_BAD_VALUE); + struct stat statData; + if (error == B_OK) + error = GetStat(&statData); + if (error == B_OK) { + ref->device = statData.st_dev; + ref->node = statData.st_ino; + } + return error; +} + +/*! \brief Returns the owner of the node. + \param owner a pointer to a uid_t variable to be set to the result + \see GetStat() for return codes +*/ +status_t +BStatable::GetOwner(uid_t *owner) const +{ + status_t error = (owner ? B_OK : B_BAD_VALUE); + struct stat statData; + if (error == B_OK) + error = GetStat(&statData); + if (error == B_OK) + *owner = statData.st_uid; + return error; +} + +/*! \brief Sets the owner of the node. + \param owner the new owner + \see GetStat() for return codes +*/ +status_t +BStatable::SetOwner(uid_t owner) +{ + status_t error; + struct stat statData; + error = GetStat(&statData); + if (error == B_OK) { + statData.st_uid = owner; + error = set_stat(statData, WSTAT_UID); + } + return error; +} + +/*! \brief Returns the group owner of the node. + \param group a pointer to a gid_t variable to be set to the result + \see GetStat() for return codes +*/ +status_t +BStatable::GetGroup(gid_t *group) const +{ + status_t error = (group ? B_OK : B_BAD_VALUE); + struct stat statData; + if (error == B_OK) + error = GetStat(&statData); + if (error == B_OK) + *group = statData.st_gid; + return error; +} + +/*! \brief Sets the group owner of the node. + \param group the new group + \see GetStat() for return codes +*/ +status_t +BStatable::SetGroup(gid_t group) +{ + status_t error; + struct stat statData; + error = GetStat(&statData); + if (error == B_OK) { + statData.st_gid = group; + error = set_stat(statData, WSTAT_GID); + } + return error; +} + +/*! \brief Returns the permissions of the node. + \param perms a pointer to a mode_t variable to be set to the result + \see GetStat() for return codes +*/ +status_t +BStatable::GetPermissions(mode_t *perms) const +{ + status_t error = (perms ? B_OK : B_BAD_VALUE); + struct stat statData; + if (error == B_OK) + error = GetStat(&statData); + if (error == B_OK) + *perms = (statData.st_mode & S_IUMSK); + return error; +} + +/*! \brief Sets the permissions of the node. + \param perms the new permissions + \see GetStat() for return codes +*/ +status_t +BStatable::SetPermissions(mode_t perms) +{ + status_t error; + struct stat statData; + error = GetStat(&statData); + if (error == B_OK) { + statData.st_mode = (statData.st_mode & ~S_IUMSK) | (perms & S_IUMSK); + error = set_stat(statData, WSTAT_MODE); + } + return error; +} + +/*! \brief Get the size of the node's data (not counting attributes). + \param size a pointer to a variable to be set to the result + \see GetStat() for return codes +*/ +status_t +BStatable::GetSize(off_t *size) const +{ + status_t error = (size ? B_OK : B_BAD_VALUE); + struct stat statData; + if (error == B_OK) + error = GetStat(&statData); + if (error == B_OK) + *size = statData.st_size; + return error; +} + +/*! \brief Returns the last time the node was modified. + \param mtime a pointer to a variable to be set to the result + \see GetStat() for return codes +*/ +status_t +BStatable::GetModificationTime(time_t *mtime) const +{ + status_t error = (mtime ? B_OK : B_BAD_VALUE); + struct stat statData; + if (error == B_OK) + error = GetStat(&statData); + if (error == B_OK) + *mtime = statData.st_mtime; + return error; +} + +/*! \brief Sets the last time the node was modified. + \param mtime the new modification time + \see GetStat() for return codes +*/ +status_t +BStatable::SetModificationTime(time_t mtime) +{ + status_t error; + struct stat statData; + error = GetStat(&statData); + if (error == B_OK) { + statData.st_mtime = mtime; + error = set_stat(statData, WSTAT_MTIME); + } + return error; +} + +/*! \brief Returns the time the node was created. + \param ctime a pointer to a variable to be set to the result + \see GetStat() for return codes +*/ +status_t +BStatable::GetCreationTime(time_t *ctime) const +{ + status_t error = (ctime ? B_OK : B_BAD_VALUE); + struct stat statData; + if (error == B_OK) + error = GetStat(&statData); + if (error == B_OK) + *ctime = statData.st_crtime; + return error; +} + +/*! \brief Sets the time the node was created. + \param ctime the new creation time + \see GetStat() for return codes +*/ +status_t +BStatable::SetCreationTime(time_t ctime) +{ + status_t error; + struct stat statData; + error = GetStat(&statData); + if (error == B_OK) { + statData.st_crtime = ctime; + error = set_stat(statData, WSTAT_CRTIME); + } + return error; +} + +/*! \brief Returns the time the node was accessed. + Not used. + \see GetModificationTime() + \see GetStat() for return codes +*/ +status_t +BStatable::GetAccessTime(time_t *atime) const +{ + status_t error = (atime ? B_OK : B_BAD_VALUE); + struct stat statData; + if (error == B_OK) + error = GetStat(&statData); + if (error == B_OK) + *atime = statData.st_atime; + return error; +} + +/*! \brief Sets the time the node was accessed. + Not used. + \see GetModificationTime() + \see GetStat() for return codes +*/ +status_t +BStatable::SetAccessTime(time_t atime) +{ + status_t error; + struct stat statData; + error = GetStat(&statData); + if (error == B_OK) { + statData.st_atime = atime; + error = set_stat(statData, WSTAT_ATIME); + } + return error; +} + +/*! \brief Returns the volume the node lives on. + \param vol a pointer to a variable to be set to the result + \see BVolume + \see GetStat() for return codes +*/ +status_t +BStatable::GetVolume(BVolume *vol) const +{ + status_t error = (vol ? B_OK : B_BAD_VALUE); + struct stat statData; + if (error == B_OK) + error = GetStat(&statData); + if (error == B_OK) + error = vol->SetTo(statData.st_dev); + return error; +} + +void BStatable::_OhSoStatable1() {} +void BStatable::_OhSoStatable2() {} +void BStatable::_OhSoStatable3() {} diff --git a/src/kits/storage/SymLink.cpp b/src/kits/storage/SymLink.cpp new file mode 100644 index 0000000000..a64ddf3cf1 --- /dev/null +++ b/src/kits/storage/SymLink.cpp @@ -0,0 +1,325 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- +/*! + \file SymLink.cpp + BSymLink implementation. +*/ + +#include + +#include +#include +#include +#include +#include + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS { +#endif + +// constructor +//! Creates an uninitialized BSymLink object. +BSymLink::BSymLink() + : BNode() + // WORKAROUND + , fSecretEntry(new(nothrow) BEntry) +{ +} + +// copy constructor +//! Creates a copy of the supplied BSymLink. +/*! \param link the BSymLink object to be copied +*/ +BSymLink::BSymLink(const BSymLink &link) + : BNode() + // WORKAROUND + , fSecretEntry(new(nothrow) BEntry) +{ + *this = link; +} + +// constructor +/*! \brief Creates a BSymLink and initializes it to the symbolic link referred + to by the supplied entry_ref. + \param ref the entry_ref referring to the symbolic link +*/ +BSymLink::BSymLink(const entry_ref *ref) + : BNode() + // WORKAROUND + , fSecretEntry(new(nothrow) BEntry) +{ + SetTo(ref); +} + +// constructor +/*! \brief Creates a BSymLink and initializes it to the symbolic link referred + to by the supplied BEntry. + \param entry the BEntry referring to the symbolic link +*/ +BSymLink::BSymLink(const BEntry *entry) + : BNode() + // WORKAROUND + , fSecretEntry(new(nothrow) BEntry) +{ + SetTo(entry); +} + +// constructor +/*! \brief Creates a BSymLink and initializes it to the symbolic link referred + to by the supplied path name. + \param path the symbolic link's path name +*/ +BSymLink::BSymLink(const char *path) + : BNode() + // WORKAROUND + , fSecretEntry(new(nothrow) BEntry) +{ + SetTo(path); +} + +// constructor +/*! \brief Creates a BSymLink and initializes it to the symbolic link referred + to by the supplied path name relative to the specified BDirectory. + \param dir the BDirectory, relative to which the symbolic link's path name + is given + \param path the symbolic link's path name relative to \a dir +*/ +BSymLink::BSymLink(const BDirectory *dir, const char *path) + : BNode() + // WORKAROUND + , fSecretEntry(new(nothrow) BEntry) +{ + SetTo(dir, path); +} + +// destructor +//! Frees all allocated resources. +/*! If the BSymLink is properly initialized, the symbolic link's file + descriptor is closed. +*/ +BSymLink::~BSymLink() +{ + // WORKAROUND + delete fSecretEntry; +} + +// WORKAROUND +status_t +BSymLink::SetTo(const entry_ref *ref) +{ + status_t error = BNode::SetTo(ref); + if (fSecretEntry) { + fSecretEntry->Unset(); + if (error == B_OK) + fSecretEntry->SetTo(ref); + } else + error = B_NO_MEMORY; + return error; +} + +// WORKAROUND +status_t +BSymLink::SetTo(const BEntry *entry) +{ + status_t error = BNode::SetTo(entry); + if (fSecretEntry) { + fSecretEntry->Unset(); + if (error == B_OK) + *fSecretEntry = *entry; + } else + error = B_NO_MEMORY; + return error; +} + +// WORKAROUND +status_t +BSymLink::SetTo(const char *path) +{ + status_t error = BNode::SetTo(path); + if (fSecretEntry) { + fSecretEntry->Unset(); + if (error == B_OK) + fSecretEntry->SetTo(path); + } else + error = B_NO_MEMORY; + return error; +} + +// WORKAROUND +status_t +BSymLink::SetTo(const BDirectory *dir, const char *path) +{ + status_t error = BNode::SetTo(dir, path); + if (fSecretEntry) { + fSecretEntry->Unset(); + if (error == B_OK) + fSecretEntry->SetTo(dir, path); + } else + error = B_NO_MEMORY; + return error; +} + +// WORKAROUND +void +BSymLink::Unset() +{ + BNode::Unset(); + if (fSecretEntry) + fSecretEntry->Unset(); +} + + +// ReadLink +//! Reads the contents of the symbolic link into a buffer. +/*! \param buf the buffer + \param size the size of the buffer + \return + - the number of bytes written into the buffer + - \c B_BAD_VALUE: \c NULL \a buf or the object doesn't refer to a symbolic + link. + - \c B_FILE_ERROR: The object is not initialized. + - some other error code +*/ +ssize_t +BSymLink::ReadLink(char *buf, size_t size) +{ +/* + status_t error = (buf ? B_OK : B_BAD_VALUE); + if (error == B_OK && InitCheck() != B_OK) + error = B_FILE_ERROR; + if (error == B_OK) + error = StorageKit::read_link(get_fd(), buf, size); + return error; +*/ +// WORKAROUND + status_t error = (buf ? B_OK : B_BAD_VALUE); + if (error == B_OK && (InitCheck() != B_OK + || !fSecretEntry + || fSecretEntry->InitCheck() != B_OK)) { + error = B_FILE_ERROR; + } + entry_ref ref; + if (error == B_OK) + error = fSecretEntry->GetRef(&ref); + char path[B_PATH_NAME_LENGTH + 1]; + if (error == B_OK) + error = StorageKit::entry_ref_to_path(&ref, path, sizeof(path)); + if (error == B_OK) + error = StorageKit::read_link(path, buf, size); + return error; +} + +// MakeLinkedPath +/*! \brief Combines a directory path and the contents of this symbolic link to + an absolute path. + \param dirPath the path name of the directory + \param path the BPath object to be set to the resulting path name + \return + - \c the length of the resulting path name, + - \c B_BAD_VALUE: \c NULL \a dirPath or \a path or the object doesn't + refer to a symbolic link. + - \c B_FILE_ERROR: The object is not initialized. + - \c B_NAME_TOO_LONG: The resulting path name is too long. + - some other error code +*/ +ssize_t +BSymLink::MakeLinkedPath(const char *dirPath, BPath *path) +{ + // R5 seems to convert the dirPath to a BDirectory, which causes links to + // be resolved, i.e. a "/tmp" dirPath expands to "/boot/var/tmp". + // That does also mean, that the dirPath must exists! + ssize_t result = (dirPath && path ? B_OK : B_BAD_VALUE); + if (result == B_OK) { + BDirectory dir(dirPath); + result = dir.InitCheck(); + if (result == B_OK) + result = MakeLinkedPath(&dir, path); + } + return result; +} + +// MakeLinkedPath +/*! \brief Combines a directory path and the contents of this symbolic link to + an absolute path. + \param dir the BDirectory referring to the directory + \param path the BPath object to be set to the resulting path name + \return + - \c the length of the resulting path name, + - \c B_BAD_VALUE: \c NULL \a dir or \a path or the object doesn't + refer to a symbolic link. + - \c B_FILE_ERROR: The object is not initialized. + - \c B_NAME_TOO_LONG: The resulting path name is too long. + - some other error code +*/ +ssize_t +BSymLink::MakeLinkedPath(const BDirectory *dir, BPath *path) +{ + ssize_t result = (dir && path ? 0 : B_BAD_VALUE); + char contents[B_PATH_NAME_LENGTH + 1]; + if (result == 0) + result = ReadLink(contents, sizeof(contents)); + if (result >= 0) { + if (StorageKit::is_absolute_path(contents)) + result = path->SetTo(contents); + else + result = path->SetTo(dir, contents); + if (result == B_OK) + result = strlen(path->Path()); + } + return result; +} + +// IsAbsolute +//! Returns whether this BSymLink refers to an absolute link. +/*! /return + - \c true, if the object is properly initialized and the symbolic link it + refers to is an absolute link, + - \c false, otherwise. +*/ +bool +BSymLink::IsAbsolute() +{ + char contents[B_PATH_NAME_LENGTH + 1]; + bool result = (ReadLink(contents, sizeof(contents)) >= 0); + if (result) + result = StorageKit::is_absolute_path(contents); + return result; +} + +// WORKAROUND +BSymLink & +BSymLink::operator=(const BSymLink &link) +{ + if (&link != this) { // no need to assign us to ourselves + Unset(); + static_cast(*this) = link; + if (fSecretEntry && link.fSecretEntry) + *fSecretEntry = *link.fSecretEntry; + } + return *this; +} + + +void BSymLink::_ReservedSymLink1() {} +void BSymLink::_ReservedSymLink2() {} +void BSymLink::_ReservedSymLink3() {} +void BSymLink::_ReservedSymLink4() {} +void BSymLink::_ReservedSymLink5() {} +void BSymLink::_ReservedSymLink6() {} + +//! Returns the BSymLink's file descriptor. +/*! To be used instead of accessing the BNode's private \c fFd member directly. + \return the file descriptor, or -1, if not properly initialized. +*/ +StorageKit::FileDescriptor +BSymLink::get_fd() const +{ + return fFd; +} + + +#ifdef USE_OPENBEOS_NAMESPACE +}; // namespace OpenBeOS +#endif diff --git a/src/kits/storage/Volume.cpp b/src/kits/storage/Volume.cpp new file mode 100644 index 0000000000..aeebadaa6b --- /dev/null +++ b/src/kits/storage/Volume.cpp @@ -0,0 +1,585 @@ +// ---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// File Name: Directory.cpp +// +// Description: BVolume class +// ---------------------------------------------------------------------- + +#include +//#include "Volume.h" + +#include +#include +#include +#include + + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS { +#endif + +// ---------------------------------------------------------------------- +// BVolume (public) +// ---------------------------------------------------------------------- +// Default constructor: does nothing and sets InitCheck() to B_NO_INIT. + +BVolume::BVolume(void) +{ + Unset(); +} + + +// ---------------------------------------------------------------------- +// BVolume (public) +// ---------------------------------------------------------------------- +// Device constructor: sets the BVolume to point to the volume +// represented by the argument. See the SetTo() function for +// status codes. + +BVolume::BVolume( + dev_t dev) +{ + SetTo(dev); +} + + +// ---------------------------------------------------------------------- +// BVolume (public) +// ---------------------------------------------------------------------- +// Copy constructor: sets the object to point to the same device as +// does the argument. + +BVolume::BVolume( + const BVolume& vol) +{ + fDev = vol.Device(); + fCStatus = vol.InitCheck(); +} + + +// ---------------------------------------------------------------------- +// ~BVolume (public, virtual) +// ---------------------------------------------------------------------- +// Destructor: Destroys the BVolume object. + +BVolume::~BVolume(void) +{ +} + + +// ---------------------------------------------------------------------- +// InitCheck (public) +// ---------------------------------------------------------------------- +// Returns the status of the last initialization (from either the +// constructor or SetTo()). + +status_t +BVolume::InitCheck(void) const +{ + return fCStatus; +} + + +// ---------------------------------------------------------------------- +// SetTo (public) +// ---------------------------------------------------------------------- +// Initializes the BVolume object to represent the volume (device) +// identified by the argument. + +status_t +BVolume::SetTo( + dev_t dev) +{ + fDev = dev; + + // Call the kernel function that gets device information + // in order to determine the device status: + fs_info fsInfo; + int err = fs_stat_dev(dev, &fsInfo); + + if (err != 0) { + fCStatus = errno; + } + else { + fCStatus = B_OK; + } + + return fCStatus; +} + + +// ---------------------------------------------------------------------- +// Unset (public) +// ---------------------------------------------------------------------- +// Uninitializes the BVolume. + +void +BVolume::Unset(void) +{ + fDev = 0L; + fCStatus = B_NO_INIT; +} + + +// ---------------------------------------------------------------------- +// Device (public) +// ---------------------------------------------------------------------- +// Returns the object's dev_t number. + +dev_t +BVolume::Device(void) const +{ + return fDev; +} + + +// ---------------------------------------------------------------------- +// GetRootDirectory (public) +// ---------------------------------------------------------------------- +// Initializes dir (which must be allocated) to refer to the volume's +// "root directory." The root directory stands at the "root" of the +// volume's file hierarchy. +// +// NOTE: This isn't necessarily the root of the entire file +// hierarchy, but only the root of the volume hierarchy. +// +// This function does not change fDev nor fCStatus. + +status_t +BVolume::GetRootDirectory( + BDirectory* dir) const +{ + status_t currentStatus = fCStatus; + + if ((dir != NULL) && (currentStatus == B_OK)){ + + // Obtain the device information for the current device + // and initialize the passed-in BDirectory object with + // the device and root node values. + + fs_info fsInfo; + int err = fs_stat_dev(fDev, &fsInfo); + + if (err != 0) { + currentStatus = errno; + } + else { + node_ref nodeRef; + + nodeRef.device = fsInfo.dev; + // NOTE: This should be the same as fDev. + nodeRef.node = fsInfo.root; + + currentStatus = dir->SetTo(&nodeRef); + } + + } + + return currentStatus; +} + + +// ---------------------------------------------------------------------- +// Capacity (public) +// ---------------------------------------------------------------------- +// Returns the volume's total storage capacity (in bytes). + +off_t +BVolume::Capacity(void) const +{ + off_t totalBytes = 0; + + if (fCStatus == B_OK){ + + // Obtain the device information for the current device + // and calculate the total storage capacity. + + fs_info fsInfo; + int err = fs_stat_dev(fDev, &fsInfo); + + if (err == 0) { + totalBytes = fsInfo.block_size * fsInfo.total_blocks; + } + + } + + return totalBytes; +} + + +// ---------------------------------------------------------------------- +// FreeBytes (public) +// ---------------------------------------------------------------------- +// Returns the amount of storage that's currently unused on the +// volume (in bytes). + +off_t +BVolume::FreeBytes(void) const +{ + off_t remainingBytes = 0L; + + if (fCStatus == B_OK){ + + // Obtain the device information for the current device + // and calculate the free storage available. + + fs_info fsInfo; + int err = fs_stat_dev(fDev, &fsInfo); + + if (err == 0) { + remainingBytes = fsInfo.block_size * fsInfo.free_blocks; + } + + } + + return remainingBytes; +} + + +// ---------------------------------------------------------------------- +// GetName (public) +// ---------------------------------------------------------------------- +// Copies the name of the volume into the supplied buffer. + +status_t +BVolume::GetName( + char* name) const +{ + status_t currentStatus = fCStatus; + + if ((name != NULL) && (currentStatus == B_OK)) { + + // Obtain the device information for the current device + // and copies the device name into the buffer. + + fs_info fsInfo; + int err = fs_stat_dev(fDev, &fsInfo); + + if (err != 0) { + currentStatus = errno; + } + else { + strcpy(name, fsInfo.volume_name); + currentStatus = B_OK; + } + + } + + return currentStatus; +} + + +// ---------------------------------------------------------------------- +// SetName (public) +// ---------------------------------------------------------------------- +// Sets the name of the volume to the supplied string. +// Setting the name is typically (and most politely) the user's +// responsibility (a task that's performed, most easily, through the +// Tracker). If you really want to set the name of the volume +// programmatically, you do so by renaming the volume's root directory. + +status_t +BVolume::SetName( + const char* name) +{ + status_t currentStatus = B_ERROR; + + // *** Call a kernel or, more indirectly, a POSIX function + // that sets a volume name *** + + return currentStatus; +} + + +// ---------------------------------------------------------------------- +// GetIcon (public) +// ---------------------------------------------------------------------- +// Returns the volume's icon in icon. which specifies the icon to +// retrieve, either B_MINI_ICON (16x16) or B_LARGE_ICON (32x32). + +status_t +BVolume::GetIcon( + BBitmap* icon, + icon_size which) const +{ + status_t currentStatus = fCStatus; + + if ((icon != NULL) && (currentStatus == B_OK) + && ((which == B_MINI_ICON) || (which == B_LARGE_ICON))) { + char deviceName[B_DEV_NAME_LENGTH]; + + currentStatus = GetName(deviceName); + + if (currentStatus == B_OK) + { + currentStatus = get_device_icon(deviceName, icon, which); + } + } + + return (currentStatus); +} + + +// ---------------------------------------------------------------------- +// IsRemovable (public) +// ---------------------------------------------------------------------- +// Tests the volume and returns whether or not it is removable. + +bool +BVolume::IsRemovable(void) const +{ + bool volumeIsRemovable = false; + + // Obtain the device information for the current device + // and determines whether or not the device is removable. + + fs_info fsInfo; + int err = fs_stat_dev(fDev, &fsInfo); + + if (err == 0) { + volumeIsRemovable = (fsInfo.flags & B_FS_IS_REMOVABLE); + } + + return (volumeIsRemovable); +} + + +// ---------------------------------------------------------------------- +// IsReadOnly (public) +// ---------------------------------------------------------------------- +// Tests the volume and returns whether or not it is read-only. + +bool +BVolume::IsReadOnly(void) const +{ + bool volumeIsReadOnly = false; + + // Obtain the device information for the current device + // and determines whether or not the device is read-only. + + fs_info fsInfo; + int err = fs_stat_dev(fDev, &fsInfo); + + if (err == 0) { + volumeIsReadOnly = (fsInfo.flags & B_FS_IS_READONLY); + } + + return (volumeIsReadOnly); +} + + +// ---------------------------------------------------------------------- +// IsPersistent (public) +// ---------------------------------------------------------------------- +// Tests the volume and returns whether or not it is persistent. + +bool +BVolume::IsPersistent(void) const +{ + bool volumeIsPersistent = false; + + // Obtain the device information for the current device + // and determines whether or not the storage medium + // is persistent. + + fs_info fsInfo; + int err = fs_stat_dev(fDev, &fsInfo); + + if (err == 0) { + volumeIsPersistent = (fsInfo.flags & B_FS_IS_PERSISTENT); + } + + return (volumeIsPersistent); +} + + +// ---------------------------------------------------------------------- +// IsShared (public) +// ---------------------------------------------------------------------- +// Tests the volume and returns whether or not it is shared. + +bool +BVolume::IsShared(void) const +{ + bool volumeIsShared = false; + + // Obtain the device information for the current device + // and determines whether or not the volume is shared + // over a network. + + fs_info fsInfo; + int err = fs_stat_dev(fDev, &fsInfo); + + if (err == 0) { + volumeIsShared = (fsInfo.flags & B_FS_IS_SHARED); + } + + return (volumeIsShared); +} + + +// ---------------------------------------------------------------------- +// KnowsMime (public) +// ---------------------------------------------------------------------- +// Tests the volume and returns whether or not it uses MIME types. + +bool +BVolume::KnowsMime(void) const +{ + bool volumeKnowsMime = false; + + // Obtain the device information for the current device + // and determines whether or not the volume supports + // MIME types. + + fs_info fsInfo; + int err = fs_stat_dev(fDev, &fsInfo); + + if (err == 0) { + volumeKnowsMime = (fsInfo.flags & B_FS_HAS_MIME); + } + + return (volumeKnowsMime); +} + + +// ---------------------------------------------------------------------- +// KnowsAttr (public) +// ---------------------------------------------------------------------- +// Tests the volume and returns whether or not its files +// accept attributes. + +bool +BVolume::KnowsAttr(void) const +{ + bool volumeKnowsAttr = false; + + // Obtain the device information for the current device + // and determines whether or not the files on the + // volume accept attributes. + + fs_info fsInfo; + int err = fs_stat_dev(fDev, &fsInfo); + + if (err == 0) { + volumeKnowsAttr = (fsInfo.flags & B_FS_HAS_ATTR); + } + + return (volumeKnowsAttr); +} + + +// ---------------------------------------------------------------------- +// KnowsQuery (public) +// ---------------------------------------------------------------------- +// Tests the volume and returns whether or not it can respond +// to queries. + +bool +BVolume::KnowsQuery(void) const +{ + bool volumeKnowsQuery = false; + + // Obtain the device information for the current device + // and determines whether or not the volume can + // respond to queries. + + fs_info fsInfo; + int err = fs_stat_dev(fDev, &fsInfo); + + if (err == 0) { + volumeKnowsQuery = (fsInfo.flags & B_FS_HAS_QUERY); + } + + return (volumeKnowsQuery); +} + + +// ---------------------------------------------------------------------- +// operator == (public) +// ---------------------------------------------------------------------- +// Two BVolume objects are said to be equal if they refer to the +// same volume, or if they're both uninitialized. +// Returns whether or not the volumes are equal. + +bool +BVolume::operator==( + const BVolume& vol) const +{ + // First determine whether both objects are uninitialized, + // since comparing the fDev members of uninitialized BVolume + // instances will return an invalid result. + + bool areEqual = ((this->fCStatus == B_NO_INIT) + && (vol.InitCheck() == B_NO_INIT)); + + if (!areEqual) { + // The BVolume instance are initialized, test the + // fDev member values: + areEqual = (this->fDev == vol.Device()); + } + + return (areEqual); +} + + +// ---------------------------------------------------------------------- +// operator != (public) +// ---------------------------------------------------------------------- +// Two BVolume objects are said to be equal if they refer to the +// same volume, or if they're both uninitialized. +// Returns whether or not the volumes are not equal. + +bool +BVolume::operator!=( + const BVolume& vol) const +{ + bool areNotEqual = !(*this == vol); + + return (areNotEqual); +} + + +// ---------------------------------------------------------------------- +// operator = (public) +// ---------------------------------------------------------------------- +// In the expression: +// +// BVolume a = b; +// +// BVolume a is initialized to refer to the same volume as b. +// To gauge the success of the assignment, you should call InitCheck() +// immediately afterwards. +// +// Assigning a BVolume to itself is safe. +// Assigning from an uninitialized BVolume is "successful": +// The assigned-to BVolume will also be uninitialized (B_NO_INIT). + +BVolume& +BVolume::operator=( + const BVolume& vol) +{ + this->fDev = vol.Device(); + this->fCStatus = vol.InitCheck(); + + return (*this); +} + + +// FBC +void BVolume::_TurnUpTheVolume1() {} +void BVolume::_TurnUpTheVolume2() {} +void BVolume::_TurnUpTheVolume3() {} +void BVolume::_TurnUpTheVolume4() {} +void BVolume::_TurnUpTheVolume5() {} +void BVolume::_TurnUpTheVolume6() {} +void BVolume::_TurnUpTheVolume7() {} +void BVolume::_TurnUpTheVolume8() {} + + +#ifdef USE_OPENBEOS_NAMESPACE +} +#endif + diff --git a/src/kits/storage/kernel_interface.POSIX.cpp b/src/kits/storage/kernel_interface.POSIX.cpp new file mode 100644 index 0000000000..dd8bb4b650 --- /dev/null +++ b/src/kits/storage/kernel_interface.POSIX.cpp @@ -0,0 +1,1139 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//---------------------------------------------------------------------- +/*! + \file kernel_interface.POSIX.cpp + Initial implementation of our kernel interface with + calls to the POSIX api. This will later be replaced with a version + that makes syscalls into the actual kernel +*/ + +#include "kernel_interface.h" +#include "storage_support.h" + +#include "LibBeAdapter.h" + +#include +#include +#include // errno +#include +#include // BeOS's C-based attribute functions +#include // BeOS's C-based query functions +#include // entry_ref +#include // used by get_app_path() +#include // for utime() and struct utimbuf +#include + +// This is just for cout while developing; shouldn't need it +// when all is said and done. +#include + +// For convenience: +struct LongDIR : DIR { char _buffer[B_FILE_NAME_LENGTH]; }; + + +//------------------------------------------------------------------------------ +// File Functions +//------------------------------------------------------------------------------ + +status_t +StorageKit::open( const char *path, OpenFlags flags, FileDescriptor &result ) +{ + if (path == NULL) { + result = -1; + return B_BAD_VALUE; + } + + // This version of the function may not be called with the O_CREAT flag + if (flags & O_CREAT) + return B_BAD_VALUE; + + // Open file and return the proper error code + result = ::open(path, flags); + return (result == -1) ? errno : B_OK ; +} + +/*! Same as the other version of open() except the file is created with the + permissions given by creationFlags if it doesn't exist. */ +status_t +StorageKit::open( const char *path, OpenFlags flags, + CreationFlags creationFlags, FileDescriptor &result ) +{ + if (path == NULL) { + result = -1; + return B_BAD_VALUE; + } + + // Open/Create the file and return the proper error code + result = ::open(path, flags | O_CREAT, creationFlags); + return (result == -1) ? errno : B_OK ; +} + +status_t +StorageKit::close(StorageKit::FileDescriptor file) +{ + return (::close(file) == -1) ? errno : B_OK ; +} + +/*! \param fd the file descriptor + \param buf the buffer to be read into + \param len the number of bytes to be read + \return the number of bytes actually read or an error code +*/ +ssize_t +StorageKit::read(StorageKit::FileDescriptor fd, void *buf, size_t len) +{ + ssize_t result = (buf == NULL ? B_BAD_VALUE : B_OK); + if (result == B_OK) { + result = ::read(fd, buf, len); + if (result == -1) + result = errno; + } + return result; +} + +/*! \param fd the file descriptor + \param buf the buffer to be read into + \param pos file position from which to be read + \param len the number of bytes to be read + \return the number of bytes actually read or an error code +*/ +ssize_t +StorageKit::read(StorageKit::FileDescriptor fd, void *buf, off_t pos, + size_t len) +{ + ssize_t result = (buf == NULL || pos < 0 ? B_BAD_VALUE : B_OK); + if (result == B_OK) { + result = ::read_pos(fd, pos, buf, len); + if (result == -1) + result = errno; + } + return result; +} + +/*! \param fd the file descriptor + \param buf the buffer containing the data to be written + \param len the number of bytes to be written + \return the number of bytes actually written or an error code +*/ +ssize_t +StorageKit::write(StorageKit::FileDescriptor fd, const void *buf, size_t len) +{ + ssize_t result = (buf == NULL ? B_BAD_VALUE : B_OK); + if (result == B_OK) { + result = ::write(fd, buf, len); + if (result == -1) + result = errno; + } + return result; +} + +/*! \param fd the file descriptor + \param buf the buffer containing the data to be written + \param pos file position to which to be written + \param len the number of bytes to be written + \return the number of bytes actually written or an error code +*/ +ssize_t +StorageKit::write(StorageKit::FileDescriptor fd, const void *buf, off_t pos, + size_t len) +{ + ssize_t result = (buf == NULL || pos < 0 ? B_BAD_VALUE : B_OK); + if (result == B_OK) { + result = ::write_pos(fd, pos, buf, len); + if (result == -1) + result = errno; + } + return result; +} + +/*! \param fd the file descriptor + \param pos the relative new position of the read/write pointer in bytes + \param mode \c SEEK_SET/\c SEEK_END/\c SEEK_CUR to indicate that \a pos + is relative to the file's beginning/end/current read/write pointer + \return the new position of the read/write pointer relative to the + beginning of the file, or an error code +*/ +off_t +StorageKit::seek(StorageKit::FileDescriptor fd, off_t pos, + StorageKit::SeekMode mode) +{ + off_t result = ::lseek(fd, pos, mode); + if (result == -1) + result = errno; + return result; +} + +/*! \param fd the file descriptor + \return the position of the read/write pointer relative to the + beginning of the file, or an error code +*/ +off_t +StorageKit::get_position(StorageKit::FileDescriptor fd) +{ + off_t result = ::lseek(fd, 0, SEEK_CUR); + if (result == -1) + result = errno; + return result; +} + +StorageKit::FileDescriptor +StorageKit::dup(StorageKit::FileDescriptor file) +{ + return ::dup(file); +} + +/*! If the supplied file descriptor is -1, the copy will be -1 as well and + B_OK is returned. + \param file the file descriptor to be duplicated + \param result the variable the resulting file descriptor will be stored in + \return B_OK, if everything went fine, or an error code. +*/ +status_t +StorageKit::dup( FileDescriptor file, FileDescriptor& result ) +{ + status_t error = B_OK; + if (file == -1) + result = -1; + else { + result = dup(file); + if (result == -1) + error = errno; + } + return error; +} + +status_t +StorageKit::sync( FileDescriptor file ) +{ + return (fsync(file) == -1) ? errno : B_OK ; +} + +//! /todo Get rid of DumpLock() at some point (it's only for debugging) +void DumpLock(StorageKit::FileLock &lock) +{ + cout << endl; + cout << "type == "; + switch (lock.l_type) { + case F_RDLCK: + cout << "F_RDLCK"; + break; + + case F_WRLCK: + cout << "F_WRLCK"; + break; + + case F_UNLCK: + cout << "F_UNLCK"; + break; + + default: + cout << lock.l_type; + break; + } + cout << endl; + + cout << "whence == " << lock.l_whence << endl; + cout << "start == " << lock.l_start << endl; + cout << "len == " << lock.l_len << endl; + cout << "pid == " << lock.l_pid << endl; + cout << endl; +} + +// As best I can tell, fcntl(fd, F_SETLK, lock) and fcntl(fd, F_GETLK, lock) +// are unimplemented in BeOS R5. Thus locking we'll have to wait for the new +// kernel. I believe this function would work if fcntl() worked correctly. +status_t +StorageKit::lock(FileDescriptor file, OpenFlags mode, FileLock *lock) +{ + return B_FILE_ERROR; +/* + if (lock == NULL) + return B_BAD_VALUE; + +// DumpLock(*lock); + short lock_type; + switch (mode) { + case READ: + lock_type = F_RDLCK; + break; + + case WRITE: + case READ_WRITE: + default: + lock_type = F_WRLCK; + break; + } + +// lock->l_type = F_UNLCK; + lock->l_type = lock_type; + lock->l_whence = SEEK_SET; + lock->l_start = 0; // Beginning of file... + lock->l_len = 0; // ...to end of file + lock->l_pid = 0; // Don't really care :-) + +// DumpLock(*lock); + ::fcntl(file, F_GETLK, lock); +// DumpLock(*lock); + if (lock->l_type != F_UNLCK) { + return errno; + } + +// lock->l_type = F_RDLCK; + lock->l_type = lock_type; +// DumpLock(*lock); + + errno = 0; + + return (::fcntl(file, F_SETLK, lock) == 0) ? B_OK : errno; +*/ +} + +// As best I can tell, fcntl(fd, F_SETLK, lock) and fcntl(fd, F_GETLK, lock) +// are unimplemented in BeOS R5. Thus locking will have to wait for the new +// kernel. I believe this function would work if fcntl() worked correctly. +status_t +StorageKit::unlock(FileDescriptor file, FileLock *lock) +{ + return B_FILE_ERROR; + +/* + if (lock == NULL) + return B_BAD_VALUE; + + lock->l_type = F_UNLCK; + + return (::fcntl(file, F_SETLK, lock) == 0) ? B_OK : errno ; +*/ +} + +status_t +StorageKit::get_stat(const char *path, Stat *s) +{ + if (path == NULL || s == NULL) + return B_BAD_VALUE; + + return (::lstat(path, s) == -1) ? errno : B_OK ; +} + +status_t +StorageKit::get_stat(FileDescriptor file, Stat *s) +{ + if (s == NULL) + return B_BAD_VALUE; + + return (::fstat(file, s) == -1) ? errno : B_OK ; +} + +status_t +StorageKit::get_stat(entry_ref &ref, Stat *result) +{ + char path[B_PATH_NAME_LENGTH + 1]; + status_t status; + + status = StorageKit::entry_ref_to_path(&ref, path, B_PATH_NAME_LENGTH + 1); + return (status != B_OK) ? status : StorageKit::get_stat(path, result); +} + +status_t +StorageKit::set_stat(FileDescriptor file, Stat &s, StatMember what) +{ + int result; + + switch (what) { + case WSTAT_MODE: + // For some stupid reason, BeOS R5 has no fchmod function, just + // chmod(char *filename, ...), so for the moment we're screwed. +// result = fchmod(file, s.st_mode); +// break; + return B_BAD_VALUE; + + case WSTAT_UID: + result = ::fchown(file, s.st_uid, 0xFFFFFFFF); + break; + + case WSTAT_GID: + { + // Should work, but doesn't. uid is set to 0xffffffff. +// result = ::fchown(file, 0xFFFFFFFF, s.st_gid); + Stat st; + result = fstat(file, &st); + if (result == 0) + result = ::fchown(file, st.st_uid, s.st_gid); + break; + } + + case WSTAT_SIZE: + // For enlarging files the truncate() behavior seems to be not + // precisely defined, but with a bit of luck it might come pretty + // close to what we need. + result = ::ftruncate(file, s.st_size); + break; + + // These would all require a call to utime(char *filename, ...), but + // we have no filename, only a file descriptor, so they'll have to + // wait until our new kernel shows up (or we decide to try calling + // into the R5 kernel ;-) + case WSTAT_ATIME: + case WSTAT_MTIME: + case WSTAT_CRTIME: + return B_BAD_VALUE; + + default: + return B_BAD_VALUE; + } + + return (result == -1) ? errno : B_OK ; +} + +status_t +StorageKit::set_stat(const char *file, Stat &s, StatMember what) +{ + int result; + + //! \todo Test/verify set_stat() functionality + switch (what) { + case WSTAT_MODE: + result = ::chmod(file, s.st_mode); + break; + + case WSTAT_UID: + { + // Doesn't work: chown seems to traverse links. +// result = ::chown(file, s.st_uid, 0xFFFFFFFF); + int fd = ::open(file, O_RDWR | O_NOTRAVERSE); + if (fd != -1) { + status_t error = set_stat(fd, s, what); + ::close(fd); + return error; + } else + result = -1; + break; + } + case WSTAT_GID: + { + // Doesn't work: chown seems to traverse links. +// result = ::chown(file, 0xFFFFFFFF, s.st_gid); + int fd = ::open(file, O_RDWR | O_NOTRAVERSE); + if (fd != -1) { + status_t error = set_stat(fd, s, what); + ::close(fd); + return error; + } else + result = -1; + break; + } + + case WSTAT_SIZE: + // For enlarging files the truncate() behavior seems to be not + // precisely defined, but with a bit of luck it might come pretty + // close to what we need. + result = ::truncate(file, s.st_size); + break; + + case WSTAT_ATIME: + case WSTAT_MTIME: + { + // Grab the previous mod and access times so we only overwrite + // the specified time and not both + Stat *oldStat; + result = ::stat(file, oldStat); + if (result < 0) + break; + + utimbuf buffer; + buffer.actime = (what == WSTAT_ATIME) ? s.st_atime : oldStat->st_atime; + buffer.modtime = (what == WSTAT_MTIME) ? s.st_mtime : oldStat->st_mtime; + result = ::utime(file, &buffer); + } + + //! \todo Implement set_stat(..., WSTAT_CRTIME) + case WSTAT_CRTIME: + return B_BAD_VALUE; + + default: + return B_BAD_VALUE; + } + + return (result == -1) ? errno : B_OK ; +} + + + +//------------------------------------------------------------------------------ +// Attribute Functions +//------------------------------------------------------------------------------ + +ssize_t +StorageKit::read_attr ( StorageKit::FileDescriptor file, const char *attribute, + uint32 type, off_t pos, void *buf, size_t count ) +{ + if (attribute == NULL || buf == NULL) + return B_BAD_VALUE; + + ssize_t result = fs_read_attr ( file, attribute, type, pos, buf, count ); + return (result == -1 ? errno : result); +} + +ssize_t +StorageKit::write_attr ( StorageKit::FileDescriptor file, + const char *attribute, uint32 type, off_t pos, + const void *buf, size_t count ) +{ + if (attribute == NULL || buf == NULL) + return B_BAD_VALUE; + + ssize_t result = fs_write_attr ( file, attribute, type, pos, buf, count ); + return (result == -1 ? errno : result); +} + +status_t +StorageKit::rename_attr(FileDescriptor file, const char *oldName, + const char *newName) +{ + status_t error = (oldName && newName ? B_OK : B_BAD_VALUE); + // Figure out how much data there is + attr_info info; + if (error == B_OK) { + error = stat_attr(file, oldName, &info); + if (error != B_OK) + error = B_BAD_VALUE; // This is what R5::BNode returns... + } + // Alloc a buffer + char *data = NULL; + if (error == B_OK) { + // alloc at least one byte + data = new(nothrow) char[max(info.size, 1LL)]; + if (data == NULL) + error = B_NO_MEMORY; + } + // Read in the data + if (error == B_OK) { + ssize_t size = read_attr(file, oldName, info.type, 0, data, info.size); + if (size != info.size) { + if (size < 0) + error = size; + else + error = B_ERROR; + } + } + // Write it to the new attribute + if (error == B_OK) { + ssize_t size = 0; + if (info.size > 0) + size = write_attr(file, newName, info.type, 0, data, info.size); + if (size != info.size) { + if (size < 0) + error = size; + else + error = B_ERROR; + } + } + // free the buffer + if (data) + delete[] data; + // Remove the old attribute + if (error == B_OK) + error = remove_attr(file, oldName); + return error; +} + +status_t +StorageKit::remove_attr ( StorageKit::FileDescriptor file, const char *attr ) +{ + if (attr == NULL) + return B_BAD_VALUE; + + // fs_remove_attr is supposed to set errno properly upon failure, + // but currently does not appear to. It isn't set consistent + // with what is returned by R5::BNode::RemoveAttr(), and it isn't + // set consistent with what the BeBook's claims it is set to either. + return fs_remove_attr ( file, attr ) == -1 ? errno : B_OK ; +} + +status_t +StorageKit::stat_attr( FileDescriptor file, const char *name, AttrInfo *ai ) +{ + if (name == NULL || ai == NULL) + return B_BAD_VALUE; + + return (fs_stat_attr( file, name, ai ) == -1) ? errno : B_OK ; +} + + +//------------------------------------------------------------------------------ +// Attribute Directory Functions +//------------------------------------------------------------------------------ + +status_t +StorageKit::open_attr_dir( FileDescriptor file, FileDescriptor &result ) +{ + result = NullFd; + if (DIR *dir = ::fs_fopen_attr_dir(file)) { + result = dir->fd; + free(dir); + } + return (result < 0) ? errno : B_OK ; +} + +status_t +StorageKit::rewind_attr_dir( FileDescriptor dir ) +{ + if (dir < 0) + return B_BAD_VALUE; + else { + // init a DIR structure + LongDIR dirDir; + dirDir.fd = dir; + ::fs_rewind_attr_dir(&dirDir); + return B_OK; + } +} + +// buffer must be large enough!!! +status_t +StorageKit::read_attr_dir( FileDescriptor dir, StorageKit::DirEntry& buffer ) +{ + // init a DIR structure + LongDIR dirDir; + dirDir.fd = dir; + // check parameters + status_t error = B_OK; + // read one entry and copy it into the buffer + if (dirent *entry = ::fs_read_attr_dir(&dirDir)) { + // Don't trust entry->d_reclen. + // Unlike stated in BeBook::BEntryList, the value is not the length + // of the whole structure, but only of the name. Some FSs count + // the terminating '\0', others don't. + // So we calculate the size ourselves (including the '\0'): + size_t entryLen = entry->d_name + strlen(entry->d_name) + 1 + - (char*)entry; + memcpy(&buffer, entry, entryLen); + } else + error = B_ENTRY_NOT_FOUND; + return error; +} + +status_t +StorageKit::close_attr_dir ( FileDescriptor dir ) +{ + if (dir == StorageKit::NullFd) + return B_BAD_VALUE; + + // init a DIR structure + if (LongDIR* dirDir = (LongDIR*)malloc(sizeof(LongDIR))) { + dirDir->fd = dir; + return (fs_close_attr_dir(dirDir) == -1) ? errno : B_OK ; + } + return B_NO_MEMORY; +} + + +//------------------------------------------------------------------------------ +// Directory Functions +//------------------------------------------------------------------------------ + +status_t +StorageKit::open_dir( const char *path, FileDescriptor &result ) +{ + result = NullFd; + if (DIR *dir = ::opendir(path)) { + result = dir->fd; + free(dir); + } + return (result < 0) ? errno : B_OK ; +} + +/*! The parent directory must already exist. + \param path the directory's path name + \param mode the file permissions + \return B_OK, if everything went fine, an error code otherwise +*/ +status_t +StorageKit::create_dir( const char *path, mode_t mode ) +{ + status_t error = (path ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + if (mkdir(path, mode) == -1) + error = errno; + } + return error; +} + +/*! The parent directory must already exist. + \param path the directory's path name + \param result set to a file descriptor for the new directory + \param mode the file permissions + \return B_OK, if everything went fine, an error code otherwise +*/ +status_t +StorageKit::create_dir( const char *path, FileDescriptor &result, + mode_t mode ) +{ + status_t error = create_dir(path, mode); + if (error == B_OK) + error = open_dir(path, result); + return error; +} + +/*! \param dir the directory + \param buffer the dirent structure to be filled + \param length the size of the dirent structure + \param count the maximal number of entries to be read + \return + - the number of entries stored in the supplied buffer, + - \c 0, if at the end of the entry list, + - \c B_BAD_VALUE, if \a buffer is NULL, or the supplied buffer is too small +*/ +int32 +StorageKit::read_dir( FileDescriptor dir, DirEntry *buffer, size_t length, + int32 count ) +{ + // init a DIR structure + LongDIR dirDir; + dirDir.fd = dir; + // check parameters + int32 result = (buffer == NULL ? B_BAD_VALUE : 0); + if (result == 0 && count > 0) { + // read one entry and copy it into the buffer + if (dirent *entry = readdir(&dirDir)) { + // Don't trust entry->d_reclen. + // Unlike stated in BeBook::BEntryList, the value is not the length + // of the whole structure, but only of the name. Some FSs count + // the terminating '\0', others don't. + // So we calculate the size ourselves (including the '\0'): + size_t entryLen = entry->d_name + strlen(entry->d_name) + 1 + - (char*)entry; + if (length >= entryLen) { + memcpy(buffer, entry, entryLen); + result = 1; + } else // buffer too small + result = B_BAD_VALUE; + } + } + return result; +} + +status_t +StorageKit::rewind_dir( FileDescriptor dir ) +{ + if (dir < 0) + return B_BAD_VALUE; + else { + // init a DIR structure + LongDIR dirDir; + dirDir.fd = dir; + ::rewinddir(&dirDir); + return B_OK; + } +} + +status_t +StorageKit::find_dir( FileDescriptor dir, const char *name, + DirEntry *result, size_t length ) +{ + if (dir < 0 || name == NULL || result == NULL) + return B_BAD_VALUE; + + status_t status; + + status = StorageKit::rewind_dir(dir); + if (status == B_OK) { + while ( StorageKit::read_dir(dir, result, length, 1) == 1) + { + if (strcmp(result->d_name, name) == 0) + return B_OK; + } + status = B_ENTRY_NOT_FOUND; + } + + return status; +} + +status_t +StorageKit::find_dir( FileDescriptor dir, const char *name, entry_ref *result ) +{ + status_t status = (result ? B_OK : B_BAD_VALUE); + LongDirEntry entry; + if (status == B_OK) + status = StorageKit::find_dir(dir, name, &entry, sizeof(entry)); + if (status == B_OK) { + result->device = entry.d_pdev; + result->directory = entry.d_pino; + status = result->set_name(entry.d_name); + } + return status; +} + +status_t +StorageKit::dup_dir( FileDescriptor dir, FileDescriptor &result ) +{ + return StorageKit::dup(dir, result); +} + +status_t +StorageKit::close_dir( FileDescriptor dir ) +{ + // init a DIR structure + if (LongDIR* dirDir = (LongDIR*)malloc(sizeof(LongDIR))) { + dirDir->fd = dir; + return (::closedir(dirDir) == -1) ? errno : B_OK; + } + return B_NO_MEMORY; +} + +//------------------------------------------------------------------------------ +// SymLink functions +//------------------------------------------------------------------------------ + +/*! The parent directory must already exist. + \param path the link's path name + \param linkToPath the path name the link shall point to + \return B_OK, if everything went fine, an error code otherwise +*/ +status_t +StorageKit::create_link( const char *path, const char *linkToPath ) +{ + status_t error = (path && linkToPath ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + if (symlink(linkToPath, path) == -1) + error = errno; + } + return error; +} + +/*! The parent directory must already exist. + \param path the link's path name + \param linkToPath the path name the link shall point to + \param result set to a file descriptor for the new symbolic link + \return B_OK, if everything went fine, an error code otherwise +*/ +status_t +StorageKit::create_link( const char *path, const char *linkToPath, + FileDescriptor &result) +{ + status_t error = create_link(path, linkToPath); + if (error == B_OK) + error = open(path, O_RDWR, result); + return error; +} + +ssize_t +StorageKit::read_link( const char *path, char *result, size_t size ) +{ + if (result == NULL) + return B_BAD_VALUE; + // Don't null terminate, when the buffer is too small. That would make + // things more difficult. BTW: readlink() returns the actual length of + // the link contents and so do we. + int len = ::readlink(path, result, size); + if (len == -1) { + if (size > 0) + result[0] = 0; // Null terminate + return errno; + } else { + if (len < (int)size) + result[len] = 0; // Null terminate + return len; + } +} + +ssize_t +StorageKit::read_link( FileDescriptor fd, char *result, size_t size ) +{ + ssize_t error = (result ? B_OK : B_BAD_VALUE); + // no way to implement it :-( + if (error == B_OK) + error = B_ERROR; + return error; +} + + +//------------------------------------------------------------------------------ +// Query Functions +//------------------------------------------------------------------------------ + +status_t +StorageKit::open_query( dev_t device, const char *query, uint32 flags, + FileDescriptor &result ) +{ + if (flags & B_LIVE_QUERY) + return B_BAD_VALUE; + result = NullFd; + if (DIR *dir = fs_open_query(device, query, flags)) { + result = dir->fd; + free(dir); + } + return (result < 0) ? errno : B_OK ; +} + +status_t +StorageKit::open_live_query( dev_t device, const char *query, uint32 flags, + port_id port, int32 token, + FileDescriptor &result ) +{ + if (!(flags & B_LIVE_QUERY)) + return B_BAD_VALUE; + result = NullFd; + if (DIR *dir = fs_open_live_query(device, query, flags, port, token)) { + result = dir->fd; + free(dir); + } + return (result < 0) ? errno : B_OK ; +} + +/*! \param query the query + \param buffer the dirent structure to be filled + \param length the size of the dirent structure + \param count the maximal number of entries to be read + \return + - the number of entries stored in the supplied buffer, + - \c 0, if at the end of the entry list, + - \c B_BAD_VALUE, if \a buffer is NULL, or the supplied buffer is too small +*/ +int32 +StorageKit::read_query( FileDescriptor query, DirEntry *buffer, size_t length, + int32 count ) +{ + // init a DIR structure + LongDIR queryDir; + queryDir.fd = query; + // check parameters + int32 result = (buffer == NULL ? B_BAD_VALUE : 0); + if (result == 0 && count > 0) { + // read one entry and copy it into the buffer + if (dirent *entry = fs_read_query(&queryDir)) { + // Don't trust entry->d_reclen. + // Unlike stated in BeBook::BEntryList, the value is not the length + // of the whole structure, but only of the name. Some FSs count + // the terminating '\0', others don't. + // So we calculate the size ourselves (including the '\0'): + size_t entryLen = entry->d_name + strlen(entry->d_name) + 1 + - (char*)entry; + if (length >= entryLen) { + memcpy(buffer, entry, entryLen); + result = 1; + } else // buffer too small + result = B_BAD_VALUE; + } + } + return result; +} + +status_t +StorageKit::close_query( FileDescriptor query ) +{ + // init a DIR structure + if (LongDIR* queryDir = (LongDIR*)malloc(sizeof(LongDIR))) { + queryDir->fd = query; + return (fs_close_query(queryDir) == -1) ? errno : B_OK; + } + return B_NO_MEMORY; +} + + +//------------------------------------------------------------------------------ +// Miscellaneous Functions +//------------------------------------------------------------------------------ + +status_t +StorageKit::entry_ref_to_path( const struct entry_ref *ref, char *result, + size_t size ) +{ + if (ref == NULL) { + return B_BAD_VALUE; + } else { + return entry_ref_to_path(ref->device, ref->directory, ref->name, + result, size); + } +} + +status_t +StorageKit::entry_ref_to_path( dev_t device, ino_t directory, const char *name, + char *result, size_t size ) +{ + return entry_ref_to_path_adapter(device, directory, name, result, size); +} + +status_t +StorageKit::dir_to_self_entry_ref( FileDescriptor dir, entry_ref *result ) +{ + if (dir == StorageKit::NullFd || result == NULL) + return B_BAD_VALUE; + return find_dir(dir, ".", result); +} + +status_t +StorageKit::dir_to_path( FileDescriptor dir, char *result, size_t size ) +{ + if (dir < 0 || result == NULL) + return B_BAD_VALUE; + + entry_ref entry; + status_t status; + + status = dir_to_self_entry_ref(dir, &entry); + if (status != B_OK) + return status; + + return entry_ref_to_path(&entry, result, size); +} + +/*! \param path the path name. + \param result a pointer to a buffer the resulting path name shall be + written into. + \param size the size of the buffer + \return \c B_OK if everything went fine, an error code otherwise +*/ +status_t +StorageKit::get_canonical_path(const char *path, char *result, size_t size) +{ + status_t error = (path && result ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + char *dirPath = NULL; + char *leafName = NULL; + error = split_path(path, dirPath, leafName); + if (error == B_OK) { + // handle special leaf names ("." and "..") + if (strcmp(leafName, ".") == 0 || strcmp(leafName, "..") == 0) + error = get_canonical_dir_path(path, result, size); + else { + // get the canonical dir path and append the leaf name + error = get_canonical_dir_path(dirPath, result, size); + if (error == B_OK) { + size_t dirPathLen = strlen(result); + // "/" doesn't need a '/' to be appended + bool separatorNeeded = (result[dirPathLen - 1] != '/'); + size_t neededSize = dirPathLen + (separatorNeeded ? 1 : 0) + + strlen(leafName) + 1; + if (neededSize <= size) { + if (separatorNeeded) + strcat(result + dirPathLen, "/"); + strcat(result + dirPathLen, leafName); + } else + error = B_BAD_VALUE; + } + } + delete[] dirPath; + delete[] leafName; + } + } + return error; +} + +/*! The caller is responsible for deleting the returned path name. + \param path the path name. + \param result in this variable the resulting path name is returned + \return \c B_OK if everything went fine, an error code otherwise +*/ +status_t +StorageKit::get_canonical_path(const char *path, char *&result) +{ + status_t error = (path ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + result = new(nothrow) char[B_PATH_NAME_LENGTH + 1]; + if (!result) + error = B_NO_MEMORY; + if (error == B_OK) { + error = get_canonical_path(path, result, B_PATH_NAME_LENGTH + 1); + if (error != B_OK) { + delete[] result; + result = NULL; + } + } + } + return error; +} + +/*! \param path the path name. + \param result a pointer to a buffer the resulting path name shall be + written into. + \param size the size of the buffer + \return \c B_OK if everything went fine, an error code otherwise +*/ +status_t +StorageKit::get_canonical_dir_path(const char *path, char *result, size_t size) +{ + status_t error = (path && result ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + FileDescriptor dir; + error = open_dir(path, dir); + if (error == B_OK) { + error = dir_to_path(dir, result, size); + close_dir(dir); + } + } + return error; +} + +/*! The caller is responsible for deleting the returned path name. + \param path the path name. + \param result in this variable the resulting path name is returned + \return \c B_OK if everything went fine, an error code otherwise +*/ +status_t +StorageKit::get_canonical_dir_path(const char *path, char *&result) +{ + status_t error = (path ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + result = new(nothrow) char[B_PATH_NAME_LENGTH + 1]; + if (!result) + error = B_NO_MEMORY; + if (error == B_OK) { + error = get_canonical_dir_path(path, result, + B_PATH_NAME_LENGTH + 1); + if (error != B_OK) { + delete[] result; + result = NULL; + } + } + } + return error; +} + +status_t +StorageKit::get_app_path(char *buffer) +{ + status_t error = (buffer ? B_OK : B_BAD_VALUE); + image_info info; + int32 cookie = 0; + bool found = false; + while (!found && get_next_image_info(0, &cookie, &info) == B_OK) { + if (info.type == B_APP_IMAGE) { + strncpy(buffer, info.name, B_PATH_NAME_LENGTH); + buffer[B_PATH_NAME_LENGTH] = 0; + found = true; + } + } + if (error == B_OK && !found) + error = B_ENTRY_NOT_FOUND; + return error; +} + +bool +StorageKit::entry_ref_is_root_dir( entry_ref &ref ) +{ + return ref.directory == 1 && ref.device == 1 && ref.name[0] == '.' + && ref.name[1] == 0; +} + +status_t +StorageKit::rename(const char *oldPath, const char *newPath) +{ + if (oldPath == NULL || newPath == NULL) + return B_BAD_VALUE; + + return (::rename(oldPath, newPath) == -1) ? errno : B_OK ; +} + +/*! Removes path from the filesystem. */ +status_t +StorageKit::remove(const char *path) +{ + if (path == NULL) + return B_BAD_VALUE; + + return (::remove(path) == -1) ? errno : B_OK ; +} + diff --git a/src/kits/storage/storage_support.cpp b/src/kits/storage/storage_support.cpp new file mode 100644 index 0000000000..3631d79948 --- /dev/null +++ b/src/kits/storage/storage_support.cpp @@ -0,0 +1,318 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//---------------------------------------------------------------------- +/*! + \file storage_support.cpp + Implementations of miscellaneous internal Storage Kit support functions. +*/ + +#include +#include + +#include +#include +#include "storage_support.h" + +namespace StorageKit { + +/*! \param path the path + \return \c true, if \a path is not \c NULL and absolute, \c false otherwise +*/ +bool +is_absolute_path(const char *path) +{ + return (path && path[0] == '/'); +} + +// parse_path +static +void +parse_path(const char *fullPath, int &leafStart, int &leafEnd, int &pathEnd) +{ + if (fullPath == NULL) + return; + + enum PathParserState { PPS_START, PPS_LEAF } state = PPS_START; + + int len = strlen(fullPath); + + leafStart = -1; + leafEnd = -1; + pathEnd = -2; + + bool loop = true; + for (int pos = len-1; ; pos--) { + if (pos < 0) + break; + + switch (state) { + case PPS_START: + // Skip all trailing '/' chars, then move on to + // reading the leaf name + if (fullPath[pos] != '/') { + leafEnd = pos; + state = PPS_LEAF; + } + break; + + case PPS_LEAF: + // Read leaf name chars until we hit a '/' char + if (fullPath[pos] == '/') { + leafStart = pos+1; + pathEnd = pos-1; + loop = false; + } + break; + } + + if (!loop) + break; + } +} + +/*! The caller is responsible for deleting the returned directory path name + and the leaf name. + \param fullPath the path name to be split + \param path a variable the directory path name pointer shall + be written into, may be NULL + \param leaf a variable the leaf name pointer shall be + written into, may be NULL +*/ +status_t +split_path(const char *fullPath, char *&path, char *&leaf) +{ + return split_path(fullPath, &path, &leaf); +} + +/*! The caller is responsible for deleting the returned directory path name + and the leaf name. + \param fullPath the path name to be split + \param path a pointer to a variable the directory path name pointer shall + be written into, may be NULL + \param leaf a pointer to a variable the leaf name pointer shall be + written into, may be NULL +*/ +status_t +split_path(const char *fullPath, char **path, char **leaf) +{ + if (path) + *path = NULL; + if (leaf) + *leaf = NULL; + + if (fullPath == NULL) + return B_BAD_VALUE; + + int leafStart, leafEnd, pathEnd, len; + parse_path(fullPath, leafStart, leafEnd, pathEnd); + + try { + // Tidy up/handle special cases + if (leafEnd == -1) { + + // Handle special cases + if (fullPath[0] == '/') { + // Handle "/" + if (path) { + *path = new char[2]; + (*path)[0] = '/'; + (*path)[1] = 0; + } + if (leaf) { + *leaf = new char[2]; + (*leaf)[0] = '.'; + (*leaf)[1] = 0; + } + return B_OK; + } else if (fullPath[0] == 0) { + // Handle "", which we'll treat as "./" + if (path) { + *path = new char[1]; + (*path)[0] = 0; + } + if (leaf) { + *leaf = new char[2]; + (*leaf)[0] = '.'; + (*leaf)[1] = 0; + } + return B_OK; + } + + } else if (leafStart == -1) { + // fullPath is just an entry name, no parent directories specified + leafStart = 0; + } else if (pathEnd == -1) { + // The path is '/' (since pathEnd would be -2 if we had + // run out of characters before hitting a '/') + pathEnd = 0; + } + + // Alloc new strings and copy the path and leaf over + if (path) { + if (pathEnd == -2) { + // empty path + *path = new char[2]; + (*path)[0] = '.'; + (*path)[1] = 0; + } else { + // non-empty path + len = pathEnd + 1; + *path = new char[len+1]; + memcpy(*path, fullPath, len); + (*path)[len] = 0; + } + } + if (leaf) { + len = leafEnd - leafStart + 1; + *leaf = new char[len+1]; + memcpy(*leaf, fullPath + leafStart, len); + (*leaf)[len] = 0; + } + } catch (bad_alloc exception) { + if (path) + delete[] *path; + if (leaf) + delete[] *leaf; + return B_NO_MEMORY; + } + return B_OK; +} + +/*! The length of the first component is returned as well as the index at + which the next one starts. These values are only valid, if the function + returns \c B_OK. + \param path the path to be parsed + \param length the variable the length of the first component is written + into + \param nextComponent the variable the index of the next component is + written into. \c 0 is returned, if there is no next component. + \return \c B_OK, if \a path is not \c NULL, \c B_BAD_VALUE otherwise +*/ +status_t +parse_first_path_component(const char *path, int32& length, + int32& nextComponent) +{ + status_t error = (path ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + int32 i = 0; + // find first '/' or end of name + for (; path[i] != '/' && path[i] != '\0'; i++); + // handle special case "/..." (absolute path) + if (i == 0 && path[i] != '\0') + i = 1; + length = i; + // find last '/' or end of name + for (; path[i] == '/' && path[i] != '\0'; i++); + if (path[i] == '\0') // this covers "" as well + nextComponent = 0; + else + nextComponent = i; + } + return error; +} + +/*! A string containing the first component is returned and the index, at + which the next one starts. These values are only valid, if the function + returns \c B_OK. + \param path the path to be parsed + \param component the variable the pointer to the newly allocated string + containing the first path component is written into. The caller + is responsible for delete[]'ing the string. + \param nextComponent the variable the index of the next component is + written into. \c 0 is returned, if there is no next component. + \return \c B_OK, if \a path is not \c NULL, \c B_BAD_VALUE otherwise +*/ +status_t +parse_first_path_component(const char *path, char *&component, + int32& nextComponent) +{ + int32 length; + status_t error = parse_first_path_component(path, length, nextComponent); + if (error == B_OK) { + component = new(nothrow) char[length + 1]; + if (component) { + strncpy(component, path, length); + component[length] = '\0'; + } else + error = B_NO_MEMORY; + } + return error; +} + +/*! An entry name is considered valid, if its length doesn't exceed + \c B_FILE_NAME_LENGTH (including the terminating null) and it doesn't + contain any \c "/". + \param entry the entry name + \return + - \c B_OK, if \a entry is valid, + - \c B_BAD_VALUE, if \a entry is \c NULL or contains a "/", + - \c B_NAME_TOO_LONG, if \a entry is too long + \note \c "" is considered a valid entry name. + \note According to a couple of tests the deal is the following: + The length of an entry name must not exceed \c B_FILE_NAME_LENGTH + including the terminating null character, whereas the null character + is not included in the \c B_PATH_NAME_LENGTH characters for a path + name. + Therefore the sufficient buffer sizes for entry/path names are + \c B_FILE_NAME_LENGTH and \c B_PATH_NAME_LENGTH + 1 respectively. + However, I recommend to use "+ 1" in both cases. +*/ +status_t +check_entry_name(const char *entry) +{ + status_t error = (entry ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + if (strlen(entry) >= B_FILE_NAME_LENGTH) + error = B_NAME_TOO_LONG; + } + if (error == B_OK) { + for (int32 i = 0; error == B_OK && entry[i] != '\0'; i++) { + if (entry[i] == '/') + error = B_BAD_VALUE; + } + } + return error; +} + +/*! An path name is considered valid, if its length doesn't exceed + \c B_PATH_NAME_LENGTH (NOT including the terminating null) and each of + its components is a valid entry name. + \param entry the entry name + \return + - \c B_OK, if \a path is valid, + - \c B_BAD_VALUE, if \a path is \c NULL, + - \c B_NAME_TOO_LONG, if \a path, or any of its components is too long + \note \c "" is considered a valid path name. + \note According to a couple of tests the deal is the following: + The length of an entry name must not exceed \c B_FILE_NAME_LENGTH + including the terminating null character, whereas the null character + is not included in the \c B_PATH_NAME_LENGTH characters for a path + name. + Therefore the sufficient buffer sizes for entry/path names are + \c B_FILE_NAME_LENGTH and \c B_PATH_NAME_LENGTH + 1 respectively. + However, I recommend to use "+ 1" in both cases. +*/ +status_t +check_path_name(const char *path) +{ + status_t error = (path ? B_OK : B_BAD_VALUE); + // check the path components + const char *remainder = path; + int32 length, nextComponent; + do { + error = parse_first_path_component(remainder, length, nextComponent); + if (error == B_OK) { + if (length >= B_FILE_NAME_LENGTH) + error = B_NAME_TOO_LONG; + remainder += nextComponent; + } + } while (error == B_OK && nextComponent != 0); + // check the length of the path + if (error == B_OK && strlen(path) > B_PATH_NAME_LENGTH) + error = B_NAME_TOO_LONG; + return error; +} + + +} // namespace StorageKit diff --git a/src/kits/support/Archivable.cpp b/src/kits/support/Archivable.cpp new file mode 100644 index 0000000000..4b108cde9e --- /dev/null +++ b/src/kits/support/Archivable.cpp @@ -0,0 +1,571 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, OpenBeOS +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: Archivable.cpp +// Author: Erik Jaesler (erik@cgsoftware.com) +// Description: BArchivable mix-in class defines the archiving +// protocol. Also some global archiving functions. +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- +#include +#include +#include +#include +#include +#include +#include + +// System Includes ------------------------------------------------------------- +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + + +using std::string; +using std::vector; + +const char* B_CLASS_FIELD = "class"; +const char* B_ADD_ON_FIELD = "add_on"; +const int32 FUNC_NAME_LEN = 1024; + +// TODO: consider moving these +// to a separate module, and making them more full-featured (e.g., taking +// NS::ClassName::Function(Param p) instead of just NS::ClassName) +static void Demangle(const char *name, BString &out); +static void Mangle(const char *name, BString &out); +static instantiation_func FindFuncInImage(BString& funcName, image_id id, + status_t& err); +static bool CheckSig(const char* sig, image_info& info); + +/* +// TODO: Where do these get triggered from? +Log entries graciously coughed up by the Be implementation: + Nov 28 01:40:45 instantiate_object failed: NULL BMessage argument + Nov 28 01:40:45 instantiate_object failed: Failed to find an entrydefining the class name (Name not found). + Nov 28 01:40:45 instantiate_object failed: No signature specified in archive, looking for class "TInvalidClassName". + Nov 28 01:40:45 instantiate_object failed: Error finding app with signature "application/x-vnd.InvalidSignature" (Application could not be found) + Nov 28 01:40:45 instantiate_object failed: Application could not be found (8000200b) + Nov 28 01:40:45 instantiate_object failed: Failed to find exported Instantiate static function for class TInvalidClassName. + Nov 28 01:40:45 instantiate_object failed: Invalid argument (80000005) + Nov 28 01:40:45 instantiate_object failed: No signature specified in archive, looking for class "TRemoteTestObject". + Nov 28 01:40:45 instantiate_object - couldn't get mime sig for /boot/home/src/projects/OpenBeOS/app_kit/test/lib/support/BArchivable/./BArchivableSystemTester + Nov 28 01:40:45 instantiate_object failed: Error finding app with signature "application/x-vnd.InvalidSignature" (Application could not be found) + Nov 28 01:40:45 instantiate_object failed: Application could not be found (8000200b) + Nov 28 01:40:45 instantiate_object failed: Error finding app with signature "application/x-vnd.InvalidSignature" (Application could not be found) + Nov 28 01:40:45 instantiate_object failed: Application could not be found (8000200b) + Nov 28 01:40:45 instantiate_object failed: Error finding app with signature "application/x-vnd.InvalidSignature" (Application could not be found) + Nov 28 01:40:45 instantiate_object failed: Application could not be found (8000200b) +*/ + +//------------------------------------------------------------------------------ +BArchivable::BArchivable() +{ + ; +} +//------------------------------------------------------------------------------ +BArchivable::BArchivable(BMessage* from) +{ + ; +} +//------------------------------------------------------------------------------ +BArchivable::~BArchivable() +{ + ; +} +//------------------------------------------------------------------------------ +status_t BArchivable::Archive(BMessage* into, bool deep) const +{ + if (!into) + { + // TODO: logging/other error reporting? + return B_BAD_VALUE; + } + + BString name; + Demangle(typeid(*this).name(), name); + + return into->AddString(B_CLASS_FIELD, name); +} +//------------------------------------------------------------------------------ +BArchivable* BArchivable::Instantiate(BMessage* from) +{ + debugger("Can't create a plain BArchivable object"); + return NULL; +} +//------------------------------------------------------------------------------ +status_t BArchivable::Perform(perform_code d, void* arg) +{ + // TODO: Check against original + return B_ERROR; +} +//------------------------------------------------------------------------------ +void BArchivable::_ReservedArchivable1() +{ + ; +} +//------------------------------------------------------------------------------ +void BArchivable::_ReservedArchivable2() +{ + ; +} +//------------------------------------------------------------------------------ +void BArchivable::_ReservedArchivable3() +{ + ; +} +//------------------------------------------------------------------------------ +void BuildFuncName(const char* className, BString& funcName) +{ + funcName = ""; + + // This is what we're after: + // Instantiate__Q28OpenBeOS11BArchivableP8BMessage + Mangle(className, funcName); + funcName.Prepend("Instantiate__"); + funcName.Append("P8BMessage"); +} +//------------------------------------------------------------------------------ +BArchivable* instantiate_object(BMessage* archive, image_id* id) +{ + errno = B_OK; + + // Check our params + if (id) + { + *id = B_BAD_VALUE; + } + + if (!archive) + { + // TODO: extended error handling + errno = B_BAD_VALUE; + syslog(LOG_ERR, "instantiate_object failed: NULL BMessage argument"); + return NULL; + } + + // Get class name from archive + const char* name = NULL; + status_t err = archive->FindString(B_CLASS_FIELD, &name); + if (err) + { + // TODO: extended error handling + syslog(LOG_ERR, "instantiate_object failed: Failed to find an entry " + "defining the class name (%s).", strerror(err)); + return NULL; + } + + // Get sig from archive + const char* sig = NULL; + bool hasSig = (archive->FindString(B_ADD_ON_FIELD, &sig) == B_OK); + + instantiation_func iFunc = find_instantiation_func(name, sig); + + // if find_instantiation_func() can't locate Class::Instantiate() + // and a signature was specified + if (!iFunc && hasSig) + { + // use BRoster::FindApp() to locate an app or add-on with the symbol + BRoster Roster; + entry_ref ref; + err = Roster.FindApp(sig, &ref); + + BEntry entry; + + // if an entry_ref is obtained + if (!err) + { + err = entry.SetTo(&ref); + } + + if (err) + { + syslog(LOG_ERR, "instantiate_object failed: Error finding app " + "with signature \"%s\" (%s)", sig, strerror(err)); + } + + if (!err) + { + BPath path; + err = entry.GetPath(&path); + if (!err) + { + // load the app/add-on + image_id theImage = load_add_on(path.Path()); + if (theImage < 0) + { + // TODO: extended error handling + return NULL; + } + + // Save the image_id + if (id) + { + *id = theImage; + } + + BString funcName; + BuildFuncName(name, funcName); + iFunc = FindFuncInImage(funcName, theImage, err); + if (!iFunc) + { + syslog(LOG_ERR, "instantiate_object failed: Failed to find exported " + "Instantiate static function for class %s.", name); + } + } + } + } + else if (!iFunc) + { + syslog(LOG_ERR, "instantiate_object failed: No signature specified " + "in archive, looking for class \"%s\".", name); + errno = B_BAD_VALUE; + } + + if (err) + { + // TODO: extended error handling + syslog(LOG_ERR, "instantiate_object failed: %s (%x)", + strerror(err), err); + errno = err; + return NULL; + } + + // if Class::Instantiate(BMessage*) was found + if (iFunc) + { + // use to create and return an object instance + return iFunc(archive); + } + + return NULL; +} +//------------------------------------------------------------------------------ +BArchivable* instantiate_object(BMessage* from) +{ + return instantiate_object(from, NULL); +} +//------------------------------------------------------------------------------ +bool validate_instantiation(BMessage* from, const char* class_name) +{ + errno = B_OK; + + // Make sure our params are kosher -- original skimped here =P + if (!from) + { + // Not standard; Be implementation has a segment + // violation on this error mode + errno = B_BAD_VALUE; + + return false; + } + + status_t err = B_OK; + const char* data; + for (int32 index = 0; err == B_OK; ++index) + { + err = from->FindString(B_CLASS_FIELD, index, &data); + if (!err && strcmp(data, class_name) == 0) + { + return true; + } + } + + errno = B_MISMATCHED_VALUES; + syslog(LOG_ERR, "validate_instantiation failed on class %s.", class_name); + + return false; +} +//------------------------------------------------------------------------------ +instantiation_func find_instantiation_func(const char* class_name, + const char* sig) +{ + errno = B_OK; + if (!class_name) + { + errno = B_BAD_VALUE; + return NULL; + } + + BRoster Roster; + instantiation_func theFunc = NULL; + BString funcName; + + BuildFuncName(class_name, funcName); + + thread_id tid = find_thread(NULL); + thread_info ti; + status_t err = get_thread_info(tid, &ti); + if (!err) + { + // for each image_id in team_id + image_info info; + int32 cookie = 0; + while (!theFunc && (get_next_image_info(ti.team, &cookie, &info) == B_OK)) + { + theFunc = FindFuncInImage(funcName, info.id, err); + } + + if (theFunc && !CheckSig(sig, info)) + { + // TODO: extended error handling + theFunc = NULL; + } + } + + return theFunc; +} +//------------------------------------------------------------------------------ +instantiation_func find_instantiation_func(const char* class_name) +{ + return find_instantiation_func(class_name, NULL); +} +//------------------------------------------------------------------------------ +instantiation_func find_instantiation_func(BMessage* archive_data) +{ + errno = B_OK; + + if (!archive_data) + { + // TODO: extended error handling + errno = B_BAD_VALUE; + return NULL; + } + + const char* name = NULL; + const char* sig = NULL; + status_t err; + + err = archive_data->FindString(B_CLASS_FIELD, &name); + if (err) + { + // TODO: extended error handling + return NULL; + } + + err = archive_data->FindString(B_ADD_ON_FIELD, &sig); + + return find_instantiation_func(name, sig); +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +int GetNumber(const char*& name) +{ + int val = atoi(name); + while (isdigit(*name)) + { + ++name; + } + + return val; +} +//------------------------------------------------------------------------------ +void Demangle(const char* name, BString& out) +{ +// TODO: add support for template classes +// _find__t12basic_string3ZcZt18string_char_traits1ZcZt24__default_alloc_template2b0i0PCccUlUl + + out = ""; + + // Are we in a namespace? + if (*name == 'Q') + { + // Yessir, we are; how many deep are we? + int nsCount = 0; + ++name; + if (*name == '_') // more than 10 deep + { + ++name; + if (!isdigit(*name)) + ; // TODO: error handling + + nsCount = GetNumber(name); + if (*name == '_') // more than 10 deep + ++name; + else + ; // this should be an error condition + } + else + { + nsCount = *name - '0'; + ++name; + } + + int nameLen = 0; + for (int i = 0; i < nsCount - 1; ++i) + { + if (!isdigit(*name)) + ; // TODO: error handling + + nameLen = GetNumber(name); + out.Append(name, nameLen); + out += "::"; + name += nameLen; + } + } + + out.Append(name, GetNumber(name)); +} +//------------------------------------------------------------------------------ +void Mangle(const char* name, BString& out) +{ +// TODO: add support for template classes +// _find__t12basic_string3ZcZt18string_char_traits1ZcZt24__default_alloc_template2b0i0PCccUlUl + + // Chop this: + // testthree::testfour::Testthree::Testfour + // up into little bite-sized pieces + int count = 0; + string origName(name); + vector spacenames; + + string::size_type pos = 0; + string::size_type oldpos = 0; + while (pos != string::npos) + { + pos = origName.find_first_of("::", oldpos); + spacenames.push_back(string(origName, oldpos, pos - oldpos)); + pos = origName.find_first_not_of("::", pos); + oldpos = pos; + ++count; + } + + // Now mangle it into this: + // Q49testthree8testfour9Testthree8Testfour + out = ""; + if (count > 1) + { + out += 'Q'; + if (count > 10) + out += '_'; + out << count; + if (count > 10) + out += '_'; + } + + for (unsigned int i = 0; i < spacenames.size(); ++i) + { + out << (int)spacenames[i].length(); + out += spacenames[i].c_str(); + } +} +//------------------------------------------------------------------------------ +instantiation_func FindFuncInImage(BString& funcName, image_id id, + status_t& err) +{ + err = B_OK; + instantiation_func theFunc = NULL; + + // Don't need to do it this way ... +#if 0 + char foundFuncName[FUNC_NAME_LEN]; + int32 symbolType; + int32 funcNameLen; + + // for each B_SYMBOL_TYPE_TEXT in image_id + for (int32 i = 0; !err; ++i) + { + funcNameLen = FUNC_NAME_LEN; + err = get_nth_image_symbol(id, i, foundFuncName, &funcNameLen, + &symbolType, (void**)&theFunc); + + if (!err && symbolType == B_SYMBOL_TYPE_TEXT) + { + // try to match Class::Instantiate(BMessage*) signature + if (funcName.ICompare(foundFuncName, funcNameLen) == 0) + break; + else + theFunc = NULL; + } + } +#endif + + err = get_image_symbol(id, funcName.String(), B_SYMBOL_TYPE_TEXT, + (void**)&theFunc); + + if (err) + { + // TODO: error handling + theFunc = NULL; + } + + return theFunc; +} +//------------------------------------------------------------------------------ +bool CheckSig(const char* sig, image_info& info) +{ + if (!sig) + { + // If it wasn't specified, anything "matches" + return true; + } + + status_t err = B_OK; + + // Get image signature + BFile ImageFile(info.name, B_READ_ONLY); + err = ImageFile.InitCheck(); + if (err) + { + // TODO: extended error handling + return false; + } + + char imageSig[B_MIME_TYPE_LENGTH]; + BAppFileInfo AFI(&ImageFile); + err = AFI.GetSignature(imageSig); + if (err) + { + // TODO: extended error handling + syslog(LOG_ERR, "instantiate_object - couldn't get mime sig for %s", + info.name); + return false; + } + + return strcmp(sig, imageSig) == 0; +} +//------------------------------------------------------------------------------ + + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/kits/support/ByteOrder.cpp b/src/kits/support/ByteOrder.cpp new file mode 100644 index 0000000000..a1987c5606 --- /dev/null +++ b/src/kits/support/ByteOrder.cpp @@ -0,0 +1,22 @@ +// Quick and dirty implementation of the byte order functions. +// Just here to be able to compile and test BFile. +// To be replaced by the OpenBeOS version to be provided by the IK Team. + +#include + +#include "LibBeAdapter.h" + +// swap_data +status_t +swap_data(type_code type, void *data, size_t length, swap_action action) +{ + return swap_data_adapter(type, data, length, action); +} + +// is_type_swapped +bool +is_type_swapped(type_code type) +{ + return is_type_swapped_adapter(type); +} + diff --git a/src/kits/support/DataIO.cpp b/src/kits/support/DataIO.cpp new file mode 100644 index 0000000000..fefe9760ac --- /dev/null +++ b/src/kits/support/DataIO.cpp @@ -0,0 +1,10 @@ +/****************************************************************************** +/ +/ File: DataIO.cpp +/ +/ Description: BMallocIO and BMemoryIO objects represent a buffer of +/ dynamically allocated memory. +/ +/ Author: Steve Vallee +/ +******************************************************************************/ diff --git a/src/kits/support/Flattenable.cpp b/src/kits/support/Flattenable.cpp new file mode 100644 index 0000000000..c320325163 --- /dev/null +++ b/src/kits/support/Flattenable.cpp @@ -0,0 +1,33 @@ +// Quick and dirty implementation of the BFlattenable class. +// Just here to be able to compile and test BPath. +// To be replaced by the OpenBeOS version to be provided by the IK Team. + +#include + +#include + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS { +#endif + +// AllowsTypeCode +bool +BFlattenable::AllowsTypeCode(type_code code) const +{ + return (TypeCode() == code); +} + +// destructor +BFlattenable::~BFlattenable() +{ +} + + +void BFlattenable::_ReservedFlattenable1() {} +void BFlattenable::_ReservedFlattenable2() {} +void BFlattenable::_ReservedFlattenable3() {} + + +#ifdef USE_OPENBEOS_NAMESPACE +} +#endif diff --git a/src/kits/support/Jamfile b/src/kits/support/Jamfile new file mode 100644 index 0000000000..43dbc6acba --- /dev/null +++ b/src/kits/support/Jamfile @@ -0,0 +1 @@ +SubDir OBOS_TOP sources os kits support ; diff --git a/src/kits/support/List.cpp b/src/kits/support/List.cpp new file mode 100644 index 0000000000..7290e00739 --- /dev/null +++ b/src/kits/support/List.cpp @@ -0,0 +1,305 @@ +// List.cpp +// Just here to be able to compile and test BResources. +// To be replaced by the OpenBeOS version to be provided by the IK Team. + +#include "List.h" + +#include +#include +#include + +// constructor +BList::BList(int32 count) + : fObjectList(NULL), + fPhysicalSize(0), + fItemCount(0), + fBlockSize(count) +{ + if (fBlockSize <= 0) + fBlockSize = 1; + Resize(fItemCount); +} + +// copy constructor +BList::BList(const BList& anotherList) + : fObjectList(NULL), + fPhysicalSize(0), + fItemCount(0), + fBlockSize(anotherList.fBlockSize) +{ + *this = anotherList; +} + +// destructor +BList::~BList() +{ + free(fObjectList); +} + +// helper function +static inline +void +move_items(void** items, int32 offset, int32 count) +{ + if (count > 0 && offset != 0) + memmove(items + offset, items, count * sizeof(void*)); +} + +// AddItem +bool +BList::AddItem(void *item, int32 index) +{ + bool result = (index >= 0 && index <= fItemCount + && Resize(fItemCount + 1)); + if (result) { + move_items(fObjectList + index, 1, fItemCount - index - 1); + fObjectList[index] = item; + } + return result; +} + +// AddItem +bool +BList::AddItem(void *item) +{ + bool result = true; + if ((int32)fPhysicalSize > fItemCount) { + fObjectList[fItemCount] = item; + fItemCount++; + } else { + if ((result = Resize(fItemCount + 1))) + fObjectList[fItemCount - 1] = item; + } + return result; +} + +// AddList +bool +BList::AddList(BList *list, int32 index) +{ + bool result = (list && index >= 0 && index <= fItemCount); + if (result && list->fItemCount > 0) { + int32 count = list->fItemCount; + result = Resize(fItemCount + count); + if (result) { + move_items(fObjectList + index, count, fItemCount - index - count); + memcpy(fObjectList + index, list->fObjectList, + list->fItemCount * sizeof(void *)); + } + } + return result; +} + +// AddList +bool +BList::AddList(BList *list) +{ + bool result = (list); + if (result && list->fItemCount > 0) { + int32 index = fItemCount; + int32 count = list->fItemCount; + result = Resize(fItemCount + count); + if (result) { + memcpy(fObjectList + index, list->fObjectList, + list->fItemCount * sizeof(void *)); + } + } + return result; +} + +// CountItems +int32 +BList::CountItems() const +{ + return fItemCount; +} + +// DoForEach +void +BList::DoForEach(bool (*func)(void *)) +{ + if (func) { + for (int32 i = 0; i < fItemCount; i++) + (*func)(fObjectList[i]); + } +} + +// DoForEach +void +BList::DoForEach(bool (*func)(void *, void *), void *arg2) +{ + if (func) { + for (int32 i = 0; i < fItemCount; i++) + (*func)(fObjectList[i], arg2); + } +} + +// FirstItem +void * +BList::FirstItem() const +{ + void *item = NULL; + if (fItemCount > 0) + item = fObjectList[0]; + return item; +} + +// HasItem +bool +BList::HasItem(void *item) const +{ + return (IndexOf(item) >= 0); +} + +// IndexOf +int32 +BList::IndexOf(void *item) const +{ + for (int32 i = 0; i < fItemCount; i++) { + if (fObjectList[i] == item) + return i; + } + return -1; +} + +// IsEmpty +bool +BList::IsEmpty() const +{ + return (fItemCount == 0); +} + +// ItemAt +void * +BList::ItemAt(int32 index) const +{ + void *item = NULL; + if (index >= 0 && index < fItemCount) + item = fObjectList[index]; + return item; +} + +// Items +void * +BList::Items() const +{ + return fObjectList; +} + +// LastItem +void * +BList::LastItem() const +{ + void *item = NULL; + if (fItemCount > 0) + item = fObjectList[fItemCount - 1]; + return item; +} + +// MakeEmpty +void +BList::MakeEmpty() +{ + Resize(0); +} + +// RemoveItem +bool +BList::RemoveItem(void *item) +{ + int32 index = IndexOf(item); + bool result = (index >= 0); + if (result) + RemoveItem(index); + return result; +} + +// RemoveItem +void * +BList::RemoveItem(int32 index) +{ + void *item = NULL; + if (index >= 0 && index < fItemCount) { + item = fObjectList[index]; + move_items(fObjectList + index + 1, -1, fItemCount - index - 1); + Resize(fItemCount - 1); + } + return item; +} + +// RemoveItems +bool +BList::RemoveItems(int32 index, int32 count) +{ + bool result = (index >= 0 && index <= fItemCount); + if (result) { + if (index + count > fItemCount) + count = fItemCount - index; + if (count > 0) { + move_items(fObjectList + index + count, -count, + fItemCount - index - count); + Resize(fItemCount - count); + } else + result = false; + } + return result; +} + +// SortItems +void +BList::SortItems(int (*compareFunc)(const void *, const void *)) +{ + if (compareFunc) + qsort(fObjectList, fItemCount, sizeof(void *), compareFunc); +} + +// = +BList& +BList::operator =(const BList &list) +{ + fBlockSize = list.fBlockSize; + Resize(list.fItemCount); + memcpy(fObjectList, list.fObjectList, fItemCount * sizeof(void*)); + return *this; +} + +// reserved +void +BList::_ReservedList1() +{ +} + +// reserved +void +BList::_ReservedList2() +{ +} + +// Resize +// +// Resizes fObjectList to be large enough to contain count items. +// fItemCount is adjusted accordingly. +bool +BList::Resize(int32 count) +{ + bool result = true; + // calculate the new physical size + int32 newSize = count; + if (newSize <= 0) + newSize = 1; + newSize = ((newSize - 1) / fBlockSize + 1) * fBlockSize; + // resize if necessary + if ((size_t)newSize != fPhysicalSize) { + void** newObjectList + = (void**)realloc(fObjectList, newSize * sizeof(void*)); + if (newObjectList) { + fObjectList = newObjectList; + fPhysicalSize = newSize; + } else + result = false; + } + if (result) + fItemCount = count; + return result; +} + diff --git a/src/kits/support/Locker.cpp b/src/kits/support/Locker.cpp new file mode 100644 index 0000000000..c3180ee095 --- /dev/null +++ b/src/kits/support/Locker.cpp @@ -0,0 +1,297 @@ +// +// $Id: Locker.cpp,v 1.1 2002/07/09 12:24:49 ejakowatz Exp $ +// +// This file contains the OpenBeOS implementation of BLocker. +// + + +#include "Locker.h" +#include +#include + + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS { +#endif + + +// +// Data Member Documentation: +// +// The "fBenaphoreCount" member is set to 1 if the BLocker style is +// semaphore. If the style is benaphore, it is initialized to 0 and +// is incremented atomically when it is acquired, decremented when it +// is released. By setting the benaphore count to 1 when the style is +// semaphore, the benaphore effectively becomes a semaphore. I was able +// to determine this is what Be's implementation does by testing the +// result of the CountLockRequests() member. +// +// The "fSemaphoreID" member holds the sem_id returned from create_sem() +// when the BLocker is constructed. It is used to acquire and release +// the lock regardless of the lock style (semaphore or benaphore). +// +// The "fLockOwner" member holds the thread_id of the thread which +// currently holds the lock. If no thread holds the lock, it is set to +// B_ERROR. +// +// The "fRecursiveCount" member holds a count of the number of times the +// thread holding the lock has acquired the lock without a matching unlock. +// It is basically the number of times the thread must call Unlock() before +// the lock can be acquired by a different thread. +// + + +// +// Constructors: +// +// All constructors just pass their arguments to InitLocker(). Note that +// the default for "name" is "some BLocker" and "benaphore_style" is true. +// + +BLocker::BLocker() +{ + InitLocker("some BLocker", true); +} + + +BLocker::BLocker(const char *name) +{ + InitLocker(name, true); +} + + +BLocker::BLocker(bool benaphore_style) +{ + InitLocker("some BLocker", benaphore_style); +} + + +BLocker::BLocker(const char *name, + bool benaphore_style) +{ + InitLocker(name, benaphore_style); +} + + +// +// This constructor is not documented. The final argument is ignored for +// now. In Be's headers, its called "for_IPC". DO NOT USE THIS +// CONSTRUCTOR! +// +BLocker::BLocker(const char *name, + bool benaphore_style, + bool) +{ + InitLocker(name, benaphore_style); +} + + +// +// The destructor just deletes the semaphore. By deleting the semaphore, +// any threads waiting to acquire the BLocker will be unblocked. +// +BLocker::~BLocker() +{ + delete_sem(fSemaphoreID); +} + + +bool +BLocker::Lock(void) +{ + status_t result; + + return (AcquireLock(B_INFINITE_TIMEOUT, &result)); +} + + +status_t +BLocker::LockWithTimeout(bigtime_t timeout) +{ + status_t result; + + AcquireLock(timeout, &result); + return result; +} + + + +void +BLocker::Unlock(void) +{ + // If the thread currently holds the lockdecrement + if (IsLocked()) { + + // Decrement the number of outstanding locks this thread holds + // on this BLocker. + fRecursiveCount--; + + // If the recursive count is now at 0, that means the BLocker has + // been released by the thread. + if (fRecursiveCount == 0) { + + // The BLocker is no longer owned by any thread. + fLockOwner = B_ERROR; + + // Decrement the benaphore count and store the undecremented + // value in oldBenaphoreCount. + int32 oldBenaphoreCount = atomic_add(&fBenaphoreCount, -1); + + // If the oldBenaphoreCount is greater than 1, then there is + // at lease one thread waiting for the lock in the case of a + // benaphore. + if (oldBenaphoreCount > 1) { + + // Since there are threads waiting for the lock, it must + // be released. Note, the old benaphore count will always be + // greater than 1 for a semaphore so the release is always done. + release_sem(fSemaphoreID); + } + } + } +} + + +thread_id +BLocker::LockingThread(void) const +{ + return fLockOwner; +} + + +bool +BLocker::IsLocked(void) const +{ + // This member returns true if the calling thread holds the lock. + // The easiest way to determine this is to compare the result of + // find_thread() to the fLockOwner. + return (find_thread(NULL) == fLockOwner); +} + + +int32 +BLocker::CountLocks(void) const +{ + return fRecursiveCount; +} + + +int32 +BLocker::CountLockRequests(void) const +{ + return fBenaphoreCount; +} + + +sem_id +BLocker::Sem(void) const +{ + return fSemaphoreID; +} + + +void +BLocker::InitLocker(const char *name, + bool benaphore) +{ + if (benaphore) { + // Because this is a benaphore, initialize the benaphore count and + // create the semaphore. Because this is a benaphore, the semaphore + // count starts at 0 (ie acquired). + fBenaphoreCount = 0; + fSemaphoreID = create_sem(0, name); + } else { + // Because this is a semaphore, initialize the benaphore count to -1 + // and create the semaphore. Because this is semaphore style, the + // semaphore count starts at 1 so that one thread can acquire it and + // the next thread to acquire it will block. + fBenaphoreCount = 1; + fSemaphoreID = create_sem(1, name); + } + + // The lock is currently not acquired so there is no owner. + fLockOwner = B_ERROR; + + // The lock is currently not acquired so the recursive count is zero. + fRecursiveCount = 0; +} + + +bool +BLocker::AcquireLock(bigtime_t timeout, + status_t *error) +{ + // By default, return no error. + *error = B_NO_ERROR; + + // Only try to acquire the lock if the thread doesn't already own it. + if (!IsLocked()) { + + // Increment the benaphore count and test to see if it was already greater + // than 0. If it is greater than 0, then some thread already has the + // benaphore or the style is a semaphore. Either way, we need to acquire + // the semaphore in this case. + int32 oldBenaphoreCount = atomic_add(&fBenaphoreCount, 1); + if (oldBenaphoreCount > 0) { + + *error = acquire_sem_etc(fSemaphoreID, 1, B_RELATIVE_TIMEOUT, + timeout); + // Note, if the lock here does time out, the benaphore count + // is not decremented. By doing this, the benaphore count will + // never go back to zero. This means that the locking essentially + // changes to semaphore style if this was a benaphore. + // + // Doing the decrement of the benaphore count when the acquisition + // fails is a risky thing to do. If you decrement the counter at + // the same time the thread which holds the benaphore does an + // Unlock(), there is serious risk of a race condition. + // + // If the Unlock() sees a positive count and releases the semaphore + // and then the timed out thread decrements the count to 0, there + // is no one to take the semaphore. The next two threads will be + // able to acquire the benaphore at the same time! The first will + // increment the counter and acquire the lock. The second will + // acquire the semaphore and therefore the lock. Not good. + // + // This has been discussed on the becodetalk mailing list and + // Trey from Be had this to say: + // + // I looked at the LockWithTimeout() code, and it does not have + // _this_ (ie the race condition) problem. It circumvents it by + // NOT doing the atomic_add(&count, -1) if the semaphore + // acquisition fails. This means that if a + // BLocker::LockWithTimeout() times out, all other Lock*() attempts + // turn into guaranteed semaphore grabs, _with_ the overhead of a + // (now) useless atomic_add(). + // + // Given Trey's comments, it looks like Be took the same approach + // I did. The output of CountLockRequests() of Be's implementation + // confirms Trey's comments also. + // + // Finally some thoughts for the future with this code: + // - If 2^31 timeouts occur on a 32-bit machine (ie today), + // the benaphore count will wrap to a negative number. This + // would have unknown consequences on the ability of the BLocker + // to continue to function. + // + } + } + + // If the lock has successfully been acquired. + if (*error == B_NO_ERROR) { + + // Set the lock owner to this thread and increment the recursive count + // by one. The recursive count is incremented because one more Unlock() + // is now required to release the lock (ie, 0 => 1, 1 => 2 etc). + fLockOwner = find_thread(NULL); + fRecursiveCount++; + } + + // Return true if the lock has been acquired. + return (*error == B_NO_ERROR); +} + + +#ifdef USE_OPENBEOS_NAMESPACE +} +#endif diff --git a/src/kits/support/MallocIO.cpp b/src/kits/support/MallocIO.cpp new file mode 100644 index 0000000000..1dbf29ffea --- /dev/null +++ b/src/kits/support/MallocIO.cpp @@ -0,0 +1,176 @@ +// MallocIO.cpp +// Just here to be able to compile and test BResources. +// To be replaced by the OpenBeOS version to be provided by the IK Team. + +#include +#include +#include +#include + +#include "MallocIO.h" + +// constructor +BMallocIO::BMallocIO() + : fBlockSize(256), + fMallocSize(0), + fLength(0), + fData(NULL), + fPosition(0) +{ +} + +// destructor +BMallocIO::~BMallocIO() +{ + if (fData) + free(fData); +} + +// ReadAt +ssize_t +BMallocIO::ReadAt(off_t pos, void *buffer, size_t size) +{ + status_t error = (pos >= 0 && buffer ? B_OK : B_BAD_VALUE); + ssize_t sizeRead = 0; + if (error == B_OK && pos < fLength) { + sizeRead = min((off_t)size, fLength - pos); + memcpy(buffer, fData + pos, sizeRead); + } + return (error != B_OK ? error : sizeRead); +} + +// WriteAt +ssize_t +BMallocIO::WriteAt(off_t pos, const void *buffer, size_t size) +{ + status_t error = (pos >= 0 && buffer ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + size_t newSize = max(pos + size, (off_t)fLength); + error = _Resize(newSize); + } + if (error == B_OK) + memcpy(fData + pos, buffer, size); + return (error != B_OK ? error : size); +} + +// Seek +off_t +BMallocIO::Seek(off_t position, uint32 seekMode) +{ + off_t result = B_BAD_VALUE; + switch (seekMode) { + case SEEK_SET: + if (position >= 0) + result = fPosition = position; + break; + case SEEK_END: + { + if (fLength + position >= 0) + result = fPosition = fLength + position; + break; + } + case SEEK_CUR: + if (fPosition + position >= 0) + result = fPosition += position; + break; + default: + break; + } + return result; +} + +// Position +off_t +BMallocIO::Position() const +{ + return fPosition; +} + +// SetSize +status_t +BMallocIO::SetSize(off_t size) +{ + status_t error = (size >= 0 ? B_OK : B_BAD_VALUE ); + if (error == B_OK) + error = _Resize(size); + return error; +} + +// SetBlockSize +void +BMallocIO::SetBlockSize(size_t blockSize) +{ + if (blockSize == 0) + blockSize = 1; + if (blockSize != fBlockSize) { + fBlockSize = blockSize; + _Resize(fLength); + } +} + +// Buffer +const void * +BMallocIO::Buffer() const +{ + return fData; +} + +// BufferLength +size_t +BMallocIO::BufferLength() const +{ + return fLength; +} + +// _Resize +status_t +BMallocIO::_Resize(off_t size) +{ + status_t error = (size >= 0 ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + if (size == 0) { + // size == 0, free the memory + free(fData); + fData = NULL; + } else { + // size != 0, see, if necessary to resize + size_t newSize = (size + fBlockSize - 1) / fBlockSize * fBlockSize; + if (newSize != fMallocSize) { + // we need to resize + if (char *newData = (char*)realloc(fData, newSize)) { + // set the new area to 0 + if (fMallocSize < newSize) { + memset(newData + fMallocSize, 0, + newSize - fMallocSize); + } + fData = newData; + fMallocSize = newSize; + } else // couldn't alloc the memory + error = B_NO_MEMORY; + } + } + } + if (error == B_OK) + fLength = size; + return error; +} + + +// FBC +void BMallocIO::_ReservedMallocIO1() {} +void BMallocIO::_ReservedMallocIO2() {} + +// copy constructor +BMallocIO::BMallocIO(const BMallocIO &) +{ + // copying not allowed... +} + +// assignment operator +BMallocIO & +BMallocIO::operator=(const BMallocIO &) +{ + // copying not allowed... + return *this; +} + diff --git a/src/kits/support/StopWatch.cpp b/src/kits/support/StopWatch.cpp new file mode 100644 index 0000000000..6d0a53bbb8 --- /dev/null +++ b/src/kits/support/StopWatch.cpp @@ -0,0 +1,74 @@ +// 100% done +#include "support/StopWatch.h" +#include +#include + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS { +#endif + +BStopWatch::BStopWatch(const char *name, bool silent){ + fSilent = silent; + fName = name; + Reset(); +} + +BStopWatch::~BStopWatch(){ + if (!fSilent){ + printf("StopWatch \"%s\": %d usecs.", fName, (int)ElapsedTime() ); + + if (fLap){ + for (int i=1; i<=fLap; i++){ + if (!((i-1)%4)) printf("\n "); + printf("[%d: %d#%d] ", i, (int)(fLaps[i]-fStart), (int)(fLaps[i] - fLaps[i-1]) ); + } + printf("\n"); + } + } +} + +void BStopWatch::Suspend(){ + if (!fSuspendTime) + fSuspendTime = system_time(); +} + +void BStopWatch::Resume(){ + if (fSuspendTime) + fStart = system_time() - fSuspendTime - fStart; +} + +bigtime_t BStopWatch::Lap(){ + if (!fSuspendTime){ + if (fLap<9) fLap++; + fLaps[fLap] = system_time(); + return (system_time()-fStart); + }else + return 0; +} + +bigtime_t BStopWatch::ElapsedTime() const{ + if (fSuspendTime) + return (fSuspendTime-fStart); + else + return (system_time()-fStart); +} + +void BStopWatch::Reset(){ + fStart = system_time(); // store current time + fSuspendTime = 0; + fLap = 0; // clear laps + for (int i=0; i<10; i++) + fLaps[i] = fStart; +} + +const char *BStopWatch::Name() const{ + return fName; +} + +// just for future binary compatibility +void BStopWatch::_ReservedStopWatch1() {} +void BStopWatch::_ReservedStopWatch2() {} + +#ifdef USE_OPENBEOS_NAMESPACE +} // namespace OpenBeOS +#endif diff --git a/src/kits/support/String.cpp b/src/kits/support/String.cpp new file mode 100644 index 0000000000..3c7e68ede4 --- /dev/null +++ b/src/kits/support/String.cpp @@ -0,0 +1,9 @@ +/****************************************************************************** +/ +/ File: String.cpp +/ +/ Description: Implementation of the BString class +/ +/ Author: Steve Vallee +/ +******************************************************************************/ diff --git a/src/kits/support/support.src b/src/kits/support/support.src new file mode 100644 index 0000000000..5c265fd055 --- /dev/null +++ b/src/kits/support/support.src @@ -0,0 +1,7 @@ +SUPPORT_KIT_SOURCE = + Archivable.cpp + DataIO.cpp + Locker.cpp + StopWatch.cpp + String.cpp +; diff --git a/src/kits/translation/BitmapStream.cpp b/src/kits/translation/BitmapStream.cpp new file mode 100644 index 0000000000..520df7e174 --- /dev/null +++ b/src/kits/translation/BitmapStream.cpp @@ -0,0 +1,486 @@ +/*****************************************************************************/ +// File: BitmapStream.cpp +// Class: BBitmapStream +// Reimplimented by: Travis Smith, Michael Wilber, Translation Kit Team +// Reimplimentation: 2002-04 +// +// Description: BPositionIO based object to read/write bitmap format to/from +// a BBitmap object. +// +// The BTranslationUtils class uses this object and makes it +// easy for users to load bitmaps. +// +// Copyright (c) 2002 OpenBeOS Project +// +// Original Version: Copyright 1998, Be Incorporated, All Rights Reserved. +// Copyright 1995-1997, Jon Watte +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ + +#include +#include +#include +#include + + +// --------------------------------------------------------------- +// Constructor +// +// Initializes this object to either use the BBitmap passed to +// it as the object to read/write to or to create a BBitmap +// when data is written to this object. +// +// Preconditions: +// +// Parameters: bitmap, the bitmap used to read from/write to, +// if it is NULL, a bitmap is created when +// this object is written to +// +// Postconditions: +// +// Returns: +// --------------------------------------------------------------- +BBitmapStream::BBitmapStream(BBitmap *bitmap) +{ + fBitmap = bitmap; + fDetached = false; + fPosition = 0; + fSize = 0; + fpBigEndianHeader = NULL; + + // Extract header information if bitmap is available + if (fBitmap) { + fHeader.magic = B_TRANSLATOR_BITMAP; + fHeader.bounds = fBitmap->Bounds(); + fHeader.rowBytes = fBitmap->BytesPerRow(); + fHeader.colors = fBitmap->ColorSpace(); + fHeader.dataSize = (uint32) + (fHeader.bounds.Height() + 1) * fHeader.rowBytes; + fSize = sizeof(TranslatorBitmap) + fHeader.dataSize; + + SetBigEndianHeader(); + } +} + +// --------------------------------------------------------------- +// Destructor +// +// Destroys memory used by this object, but does not destroy the +// bitmap used by this object if it has been detached. This is so +// the user can use that bitmap after this object is destroyed. +// +// Preconditions: +// +// Parameters: +// +// Postconditions: +// +// Returns: +// --------------------------------------------------------------- +BBitmapStream::~BBitmapStream() +{ + if (fBitmap && !fDetached) + delete fBitmap; + + if (fpBigEndianHeader) + delete fpBigEndianHeader; +} + +// --------------------------------------------------------------- +// ReadAt +// +// Reads data from the stream at a specific position and for a +// specific amount. The first sizeof(TranslatorBitmap) bytes +// are the bitmap header. The header is always written out +// and read in as Big Endian byte order. +// +// Preconditions: +// +// Parameters: pos, the position in the stream to read from +// buffer, where the data will be read into +// size, the amount of data to read +// +// Postconditions: +// +// Returns: B_ERROR if there is no bitmap stored by the stream +// or if pos is a bad value, +// B_BAD_VALUE if buffer is NULL +// or the amount read if the result >= 0 +// --------------------------------------------------------------- +status_t +BBitmapStream::ReadAt(off_t pos, void *buffer, size_t size) +{ + if (!buffer) + return B_BAD_VALUE; + if (!fBitmap) + return B_ERROR; + if (!size) + return B_NO_ERROR; + if (pos >= fSize) + return B_ERROR; + + long toRead; + void *source; + + if (fPosition < sizeof(TranslatorBitmap)) { + toRead = sizeof(TranslatorBitmap) - pos; + source = ((char *)fpBigEndianHeader) + pos; + } else { + toRead = fSize - pos; + source = ((char *)fBitmap->Bits()) + fPosition - + sizeof(TranslatorBitmap); + } + if (toRead > size) + toRead = size; + + memcpy(buffer, source, toRead); + return toRead; +} + +// --------------------------------------------------------------- +// WriteAt +// +// Writes data to the bitmap from data, starting at position pos +// of size, size. The first sizeof(TranslatorBitmap) bytes +// of data must be the TranslatorBitmap header in the Big +// Endian byte order, otherwise, the data will fail to be +// successfully written. +// +// Preconditions: +// +// Parameters: pos, the position in the stream to write to +// data, the data to write to the stream +// size, the size of the data to write to the stream +// +// Postconditions: +// +// Returns: B_BAD_VALUE if size is bad or data is NULL, +// B_MISMATCHED_VALUES if the bitmap header is bad, +// or the amount written if the result is >= 0 +// --------------------------------------------------------------- +status_t +BBitmapStream::WriteAt(off_t pos, const void *data, size_t size) +{ + if (!data) + return B_BAD_VALUE; + if (!size) + return B_NO_ERROR; + + ssize_t written = 0; + while (size > 0) { + long toWrite; + void *dest; + // We depend on writing the header separately in detecting + // changes to it + if (pos < sizeof(TranslatorBitmap)) { + toWrite = sizeof(TranslatorBitmap) - pos; + dest = ((char *)&fHeader) + pos; + } else { + toWrite = fHeader.dataSize - pos + sizeof(TranslatorBitmap); + dest = ((char *)fBitmap->Bits()) + pos - sizeof(TranslatorBitmap); + } + if (toWrite > size) + toWrite = size; + if (!toWrite && size) + // i.e. we've been told to write too much + return B_BAD_VALUE; + + memcpy(dest, data, toWrite); + pos += toWrite; + written += toWrite; + data = ((char *)data) + toWrite; + size -= toWrite; + if (pos > fSize) + fSize = pos; + // If we change the header, the rest needs to be reset + if (pos == sizeof(TranslatorBitmap)) { + // Setup both host and Big Endian byte order bitmap headers + ConvertBEndianToHost(&fHeader); + SetBigEndianHeader(); + + if (fBitmap && ((fBitmap->Bounds() != fHeader.bounds) || + (fBitmap->ColorSpace() != fHeader.colors) || + (fBitmap->BytesPerRow() != fHeader.rowBytes))) { + if (!fDetached) + // if someone detached, we don't delete + delete fBitmap; + fBitmap = NULL; + } + if (!fBitmap) { + if ((fHeader.bounds.left > 0.0) || (fHeader.bounds.top > 0.0)) + DEBUGGER("non-origin bounds!"); + fBitmap = new BBitmap(fHeader.bounds, fHeader.colors); + if (fBitmap->BytesPerRow() != fHeader.rowBytes) + return B_MISMATCHED_VALUES; + } + if (fBitmap) + fSize = sizeof(TranslatorBitmap) + fBitmap->BitsLength(); + } + } + return written; +} + +// --------------------------------------------------------------- +// Seeks +// +// Changes the current stream position. +// +// Preconditions: +// +// Parameters: position, the position offset +// whence, decides how the position offset is used +// SEEK_CUR, position is added to current +// stream position +// SEEK_END, position is added to the end +// stream position +// SEEK_SET, the stream position is set to +// position +// +// Postconditions: +// +// Returns: B_BAD_VALUE if the position is bad +// or the new position value if the result >= 0 +// --------------------------------------------------------------- +off_t +BBitmapStream::Seek(off_t position, uint32 whence) +{ + // When whence == SEEK_SET, it just falls through to + // fPosition = position + if (whence == SEEK_CUR) + position += fPosition; + if (whence == SEEK_END) + position += fSize; + + if (position < 0) + return B_BAD_VALUE; + if (position > fSize) + return B_BAD_VALUE; + + fPosition = position; + return fPosition; +} + +// --------------------------------------------------------------- +// Position +// +// Returns the current stream position +// +// Preconditions: +// +// Parameters: +// +// Postconditions: +// +// Returns: returns the curren stream position +// --------------------------------------------------------------- +off_t +BBitmapStream::Position() const +{ + return fPosition; +} + + +// --------------------------------------------------------------- +// Size +// +// Returns the curren stream size +// +// Preconditions: +// +// Parameters: +// +// Postconditions: +// +// Returns: returns the current stream size +// --------------------------------------------------------------- +off_t +BBitmapStream::Size() const +{ + return fSize; +} + +// --------------------------------------------------------------- +// SetSize +// +// Sets the size of the data, but I'm not sure if this function +// has any real purpose. +// +// Preconditions: +// +// Parameters: size, the size to set the stream size to. +// +// Postconditions: +// +// Returns: B_BAD_VALUE, if size is a bad value +// B_NO_ERROR, if size is a valid value +// --------------------------------------------------------------- +status_t +BBitmapStream::SetSize(off_t size) +{ + if (size < 0) + return B_BAD_VALUE; + if (fBitmap && (size > fHeader.dataSize + sizeof(TranslatorBitmap))) + return B_BAD_VALUE; + // Problem: + // What if someone calls SetSize() before writing the header, + // so we don't know what bitmap to create? + // Solution: + // We assume people will write the header before any data, + // so SetSize() is really not going to do anything. + if (fBitmap) + // if we checked that the size was OK + fSize = size; + + return B_NO_ERROR; +} + +// --------------------------------------------------------------- +// DetachBitmap +// +// Returns the internal bitmap through outBitmap so the user +// can do whatever they want to it. It means that when the +// BBitmapStream is deleted, the bitmap is not deleted. After +// the bitmap has been detached, it is still used by the stream, +// but it is never deleted by the stream. +// +// Preconditions: +// +// Parameters: outBitmap, where the bitmap is detached to +// +// Postconditions: +// +// Returns: B_BAD_VALUE, if outBitmap is NULL or the internal +// bitmap is NULL +// B_ERROR, if the bitmap has already been detached +// B_NO_ERROR, if the bitmap was successfully detached +// --------------------------------------------------------------- +status_t +BBitmapStream::DetachBitmap(BBitmap **outBitmap) +{ + if (!outBitmap || !fBitmap) + return B_BAD_VALUE; + if (fDetached) + return B_ERROR; + + fDetached = true; + *outBitmap = fBitmap; + + return B_NO_ERROR; +} + +// --------------------------------------------------------------- +// ConvertBEndianToHost +// +// This static function converts a TranslatorBitmap from Big +// Endian byte order to the host byte order. +// +// Preconditions: Data pointed to by pheader must be in +// Big Endian byte order +// +// Parameters: pheader, the TranslatorBitmap structure to convert +// +// Postconditions: +// +// Returns: B_OK, if the byte swap succeeded +// B_BAD_VALUE, if pheader is NULL, +// or the byte swap failed +// --------------------------------------------------------------- +status_t +BBitmapStream::ConvertBEndianToHost(TranslatorBitmap *pheader) +{ + if (!pheader) + return B_BAD_VALUE; + + return swap_data(B_UINT32_TYPE, pheader, sizeof(TranslatorBitmap), + B_SWAP_BENDIAN_TO_HOST); +} + +// --------------------------------------------------------------- +// SetBigEndianHeader +// +// Assigns fpBigEndianHeader to the Big Endian byte order version +// of fHeader, the bitmap header information. fpBigEndianHeader is +// used by ReadAt() to send out the bitmap header in the Big +// Endian byte order. +// +// Preconditions: fHeader must be in the host byte order for +// this function to work properly +// +// Parameters: +// +// Postconditions: +// +// Returns: B_OK, if the byte swap succeeded +// B_BAD_VALUE, if the byte swap failed +// --------------------------------------------------------------- +status_t +BBitmapStream::SetBigEndianHeader() +{ + if (!fpBigEndianHeader) + fpBigEndianHeader = new TranslatorBitmap; + + fpBigEndianHeader->magic = fHeader.magic; + fpBigEndianHeader->bounds = fHeader.bounds; + fpBigEndianHeader->rowBytes = fHeader.rowBytes; + fpBigEndianHeader->colors = fHeader.colors; + fpBigEndianHeader->dataSize = fHeader.dataSize; + + return swap_data(B_UINT32_TYPE, fpBigEndianHeader, + sizeof(TranslatorBitmap), B_SWAP_HOST_TO_BENDIAN); +} + +// --------------------------------------------------------------- +// _ReservedBitmapStream1() +// +// It doesn't do anything :). Its here only for past/future +// binary compatibility. +// +// Preconditions: +// +// Parameters: +// +// Postconditions: +// +// Returns: +// --------------------------------------------------------------- +void +BBitmapStream::_ReservedBitmapStream1() +{ +} + +// --------------------------------------------------------------- +// _ReservedBitmapStream2() +// +// It doesn't do anything :). Its only here for past/future +// binary compatibility. +// +// Preconditions: +// +// Parameters: +// +// Postconditions: +// +// Returns: +// --------------------------------------------------------------- +void +BBitmapStream::_ReservedBitmapStream2() +{ +} + diff --git a/src/kits/translation/Jamfile b/src/kits/translation/Jamfile new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/kits/translation/R4xTranslator.cpp b/src/kits/translation/R4xTranslator.cpp new file mode 100644 index 0000000000..b71975450b --- /dev/null +++ b/src/kits/translation/R4xTranslator.cpp @@ -0,0 +1,320 @@ +/*****************************************************************************/ +// File: R4xTranslator.cpp +// Class: BR4xTranslator +// Author: Michael Wilber, Translation Kit Team +// Originally Created: 2002-06-11 +// +// Description: This class is a BTranslator based object for +// BeOS R4.0 and R4.5 type translators, aka, the translators +// that don't use the make_nth_translator() mechanism. +// +// This class is used by the OpenBeOS BTranslatorRoster +// so that R4x translators, post R4.5 translators and private +// BTranslator objects could be accessed in the same way. +// +// +// Copyright (c) 2002 OpenBeOS Project +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ + +#include + +// --------------------------------------------------------------- +// Constructor +// +// Initializes class data. +// +// Preconditions: +// +// Parameters: kpData, data and function pointers that do all of +// the useful work for this class +// +// Postconditions: If kpData is freed before the BR4xTranslator, +// the BR4xTranslator will fail to work and +// could the computer to crash. kpData may point +// to a translator add-on image, this image +// should not be unloaded before the +// BR4xTranslator is freed. +// +// +// Returns: +// --------------------------------------------------------------- +BR4xTranslator::BR4xTranslator(const translator_data *kpData) : BTranslator() +{ + fpData = new translator_data; + + fpData->translatorName = kpData->translatorName; + fpData->translatorInfo = kpData->translatorInfo; + fpData->translatorVersion = kpData->translatorVersion; + fpData->inputFormats = kpData->inputFormats; + fpData->outputFormats = kpData->outputFormats; + + fpData->Identify = kpData->Identify; + fpData->Translate = kpData->Translate; + fpData->MakeConfig = kpData->MakeConfig; + fpData->GetConfigMessage = kpData->GetConfigMessage; +} + +// --------------------------------------------------------------- +// Destructor +// +// Frees memory used by this object. Note that none of the members +// of the struct have delete used on them, this is because most +// are const pointers and the one that isn't is a regular int32. +// +// Preconditions: +// +// Parameters: +// +// Postconditions: +// +// Returns: +// --------------------------------------------------------------- +BR4xTranslator::~BR4xTranslator() +{ + delete fpData; +} + +// --------------------------------------------------------------- +// TranslatorName +// +// Returns a short name for the translator that this object stores +// +// Preconditions: +// +// Parameters: +// +// Postconditions: +// +// Returns: +// --------------------------------------------------------------- +const char *BR4xTranslator::TranslatorName() const +{ + return fpData->translatorName; +} + +// --------------------------------------------------------------- +// TranslatorInfo +// +// Returns a verbose name/description for the translator that this +// object stores +// +// Preconditions: +// +// Parameters: +// +// Postconditions: +// +// Returns: +// --------------------------------------------------------------- +const char *BR4xTranslator::TranslatorInfo() const +{ + return fpData->translatorInfo; +} + +// --------------------------------------------------------------- +// TranslatorVersion +// +// Returns the version number for this translator +// +// Preconditions: +// +// Parameters: +// +// Postconditions: +// +// Returns: +// --------------------------------------------------------------- +int32 BR4xTranslator::TranslatorVersion() const +{ + return fpData->translatorVersion; +} + +// --------------------------------------------------------------- +// InputFormats +// +// Returns the list of supported input formats and the count +// of supported input formats +// +// Preconditions: +// +// Parameters: out_count, the number of input formats is stored +// here after the function completes +// +// Postconditions: +// +// Returns: the list of supported input formats +// --------------------------------------------------------------- +const translation_format *BR4xTranslator::InputFormats(int32 *out_count) const +{ + int32 i; + for (i = 0; fpData->inputFormats[i].type; i++); + + *out_count = i; + return fpData->inputFormats; +} + +// --------------------------------------------------------------- +// OutputFormats +// +// Returns the list of supported output formats +// +// Preconditions: +// +// Parameters: out_count, the number of output formats is stored +// here after the function completes +// +// Postconditions: +// +// Returns: the list of supported output formats +// --------------------------------------------------------------- +const translation_format *BR4xTranslator::OutputFormats(int32 *out_count) const +{ + int32 i; + for (i = 0; fpData->outputFormats[i].type; i++); + + *out_count = i; + return fpData->outputFormats; +} + +// --------------------------------------------------------------- +// Identify +// +// If the translator understands how to convert the data contained +// in inSource to media type outType, it fills outInfo with +// details about the input format and return B_OK. If it doesn't +// know how to translate the data, it returns B_NO_TRANSLATOR. +// +// The actual work for this function is done by the translator +// add-on at the other end of the Identify function pointer. +// So, there's no telling the actual behavior of this function +// it depends on the translator add-on. +// +// Preconditions: +// +// Parameters: inSource, the data that wants to be converted +// inFormat, (can be null) hint about the data in +// inSource +// ioExtension, (can be null) contains additional +// information for the translator +// add-on +// outInfo, information about the capabilities +// of this translator +// outType, the output type +// +// +// Postconditions: +// +// Returns: B_OK if this translator can handle the data, +// B_NO_TRANSLATOR if it can't +// --------------------------------------------------------------- +status_t BR4xTranslator::Identify(BPositionIO *inSource, + const translation_format *inFormat, BMessage *ioExtension, + translator_info *outInfo, uint32 outType) +{ + return fpData->Identify(inSource, inFormat, ioExtension, outInfo, outType); +} + +// --------------------------------------------------------------- +// Translate +// +// The translator translates data from inSource to format outType, +// writing the output to outDestination. +// +// The actual work for this function is done by the translator +// add-on at the other end of the Translate function pointer. +// So, there's no telling the actual behavior of this function +// it depends on the translator add-on. +// +// Preconditions: +// +// Parameters: inSource, data to be translated +// inInfo, hint about the data in inSource +// ioExtension, contains configuration information +// outType, the format to translate the data to +// outDestination, where the source is translated to +// +// Postconditions: +// +// Returns: B_OK, if it converted the data +// B_NO_TRANSLATOR, if it couldn't +// some other value, if it feels like it +// --------------------------------------------------------------- +status_t BR4xTranslator::Translate(BPositionIO *inSource, + const translator_info *inInfo, BMessage *ioExtension, uint32 outType, + BPositionIO *outDestination) +{ + return fpData->Translate(inSource, inInfo, ioExtension, outType, + outDestination); +} + +// --------------------------------------------------------------- +// MakeConfigurationView +// +// This creates a BView object that allows the user to configure +// the options for the translator. Not all translators support +// this feature, and for those that don't, this function +// returns B_NO_TRANSLATOR. +// +// Preconditions: +// +// Parameters: ioExtension, the settings for the translator +// outView, the view created by the translator +// outExtent, the bounds of the view +// +// Postconditions: +// +// Returns: B_NO_TRANSLATOR, if this function is not support +// anything else, whatever the translator feels like +// returning +// --------------------------------------------------------------- +status_t BR4xTranslator::MakeConfigurationView(BMessage *ioExtension, + BView **outView, BRect *outExtent) +{ + if (fpData->MakeConfig) + return fpData->MakeConfig(ioExtension, outView, outExtent); + else + return B_ERROR; +} + +// --------------------------------------------------------------- +// GetConfigurationMessage +// +// This function stores the current configuration for the +// translator into ioExtension. Not all translators +// support this function. +// +// Preconditions: +// +// Parameters: ioExtension, where the configuration is stored +// +// Postconditions: +// +// Returns: B_NO_TRANSLATOR, if function is not support +// something else, if it is +// --------------------------------------------------------------- +status_t BR4xTranslator::GetConfigurationMessage(BMessage *ioExtension) +{ + if (fpData->GetConfigMessage) + return fpData->GetConfigMessage(ioExtension); + else + return B_ERROR; +} + diff --git a/src/kits/translation/TranslationUtils.cpp b/src/kits/translation/TranslationUtils.cpp new file mode 100644 index 0000000000..92b93c9346 --- /dev/null +++ b/src/kits/translation/TranslationUtils.cpp @@ -0,0 +1,964 @@ +/*****************************************************************************/ +// File: TranslationUtils.h +// Class: BTranslationUtils +// Reimplimented by: Michael Wilber, Translation Kit Team +// Reimplimentation: 2002-04 +// +// Description: Utility functions for the Translation Kit +// +// +// Copyright (c) 2002 OpenBeOS Project +// +// Original Version: Copyright 1998, Be Incorporated, All Rights Reserved. +// Copyright 1995-1997, Jon Watte +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// --------------------------------------------------------------- +// Constructor +// +// Does nothing! :) This class has no data members. +// +// Preconditions: +// +// Parameters: +// +// Postconditions: +// +// Returns: +// --------------------------------------------------------------- +BTranslationUtils::BTranslationUtils() +{ +} + +// --------------------------------------------------------------- +// Desstructor +// +// Does nothing! :) This class has no data members. +// +// Preconditions: +// +// Parameters: +// +// Postconditions: +// +// Returns: +// --------------------------------------------------------------- +BTranslationUtils::~BTranslationUtils() +{ +} + +// --------------------------------------------------------------- +// Constructor +// +// Does nothing! :) This class has no data members. +// +// Preconditions: +// +// Parameters: kUtils, not used +// +// Postconditions: +// +// Returns: +// --------------------------------------------------------------- +BTranslationUtils::BTranslationUtils(const BTranslationUtils &kUtils) +{ +} + +// --------------------------------------------------------------- +// operator= +// +// Does nothing! :) This class has no data members. +// +// Preconditions: +// +// Parameters: kUtils, not used +// +// Postconditions: +// +// Returns: reference to the object +// --------------------------------------------------------------- +BTranslationUtils & +BTranslationUtils::operator=(const BTranslationUtils &kUtils) +{ + return *this; +} + +// --------------------------------------------------------------- +// GetBitmap +// +// Returns a BBitmap object for the bitmap file or resource +// kName. The user has to delete this object. It first tries +// to open kName as a file, then as a resource. +// +// Preconditions: +// +// Parameters: kName, the name of the bitmap file or resource to +// be returned +// roster, BTranslatorRoster used to do the translation +// +// Postconditions: +// +// Returns: NULL, if the file could not be opened and the +// resource couldn't be found or couldn't be +// translated to a BBitmap +// BBitmap * to the bitmap reference by kName +// --------------------------------------------------------------- +BBitmap * +BTranslationUtils::GetBitmap(const char *kName, BTranslatorRoster *roster) +{ + BBitmap *pBitmap = GetBitmapFile(kName, roster); + // Try loading a bitmap from the file named name + + // Try loading the bitmap as an application resource + if (pBitmap == NULL) + pBitmap = GetBitmap(B_TRANSLATOR_BITMAP, kName, roster); + + return pBitmap; +} + +// --------------------------------------------------------------- +// GetBitmap +// +// Returns a BBitmap object for the bitmap resource identified by +// the type type with the resource id, id. +// The user has to delete this object. +// +// Preconditions: +// +// Parameters: type, the type of resource to be loaded +// id, the id for the resource to be loaded +// roster, BTranslatorRoster used to do the translation +// +// Postconditions: +// +// Returns: NULL, if the resource couldn't be loaded or couldn't +// be translated to a BBitmap +// BBitmap * to the bitmap identified by type and id +// --------------------------------------------------------------- +BBitmap * +BTranslationUtils::GetBitmap(uint32 type, int32 id, BTranslatorRoster *roster) +{ + BResources *pResources = BApplication::AppResources(); + // Remember: pResources must not be freed because + // it belongs to the application + if (pResources == NULL || pResources->HasResource(type, id) == false) + return NULL; + + // Load the bitmap resource from the application file + // pRawData should be NULL if the resource is an + // unknown type or not available + size_t bitmapSize = 0; + const void *kpRawData = pResources->LoadResource(type, id, &bitmapSize); + if (kpRawData == NULL || bitmapSize == 0) + return NULL; + + BMemoryIO memio(kpRawData, bitmapSize); + // Put the pointer to the raw image data into a BMemoryIO object + // so that it can be used with BTranslatorRoster->Translate() in + // the TranslateToBitmap() function + + return TranslateToBitmap(&memio, roster); + // Translate the data in memio using the BTranslatorRoster roster +} + +// --------------------------------------------------------------- +// GetBitmap +// +// Returns a BBitmap object for the bitmap resource identified by +// the type type with the resource name, kName. +// The user has to delete this object. Note that a resource type +// and name does not uniquely identify a resource in a file. +// +// Preconditions: +// +// Parameters: type, the type of resource to be loaded +// kName, the name of the resource to be loaded +// roster, BTranslatorRoster used to do the translation +// +// Postconditions: +// +// Returns: NULL, if the resource couldn't be loaded or couldn't +// be translated to a BBitmap +// BBitmap * to the bitmap identified by type and kName +// --------------------------------------------------------------- +BBitmap * +BTranslationUtils::GetBitmap(uint32 type, const char *kName, + BTranslatorRoster *roster) +{ + BResources *pResources = BApplication::AppResources(); + // Remember: pResources must not be freed because + // it belongs to the application + if (pResources == NULL || pResources->HasResource(type, kName) == false) + return NULL; + + // Load the bitmap resource from the application file + size_t bitmapSize = 0; + const void *kpRawData = pResources->LoadResource(type, kName, &bitmapSize); + if (kpRawData == NULL || bitmapSize == 0) + return NULL; + + BMemoryIO memio(kpRawData, bitmapSize); + // Put the pointer to the raw image data into a BMemoryIO object so + // that it can be used with BTranslatorRoster->Translate() + + return TranslateToBitmap(&memio, roster); + // Translate the data in memio using the BTranslatorRoster roster +} + +// --------------------------------------------------------------- +// GetBitmapFile +// +// Returns a BBitmap object for the bitmap file named kName. +// The user has to delete this object. +// +// Preconditions: +// +// Parameters: kName, the name of the bitmap file +// roster, BTranslatorRoster used to do the translation +// +// Postconditions: +// +// Returns: NULL, if the file couldn't be opened or couldn't +// be translated to a BBitmap +// BBitmap * to the bitmap file named kName +// --------------------------------------------------------------- +BBitmap * +BTranslationUtils::GetBitmapFile(const char *kName, BTranslatorRoster *roster) +{ + BFile bitmapFile(kName, B_READ_ONLY); + if (bitmapFile.InitCheck() != B_OK) + return NULL; + + return TranslateToBitmap(&bitmapFile, roster); + // Translate the data in memio using the BTranslatorRoster roster +} + +// --------------------------------------------------------------- +// GetBitmap +// +// Returns a BBitmap object for the bitmap file with the entry_ref +// kRef. The user has to delete this object. +// +// Preconditions: +// +// Parameters: kRef, the entry_ref for the bitmap file +// roster, BTranslatorRoster used to do the translation +// +// Postconditions: +// +// Returns: NULL, if the file couldn't be opened or couldn't +// be translated to a BBitmap +// BBitmap * to the bitmap file referenced by kRef +// --------------------------------------------------------------- +BBitmap * +BTranslationUtils::GetBitmap(const entry_ref *kRef, BTranslatorRoster *roster) +{ + BFile bitmapFile(kRef, B_READ_ONLY); + if (bitmapFile.InitCheck() != B_OK) + return NULL; + + return TranslateToBitmap(&bitmapFile, roster); + // Translate the data in bitmapFile using the BTranslatorRoster roster +} + +// --------------------------------------------------------------- +// GetBitmap +// +// Returns a BBitmap object from the BPositionIO *stream. The +// user must delete the returned object +// +// Preconditions: +// +// Parameters: stream, the stream with bitmap data in it +// roster, BTranslatorRoster used to do the translation +// +// Postconditions: +// +// Returns: NULL, if the stream couldn't be translated to a BBitmap +// BBitmap * to the bitmap file named kName +// --------------------------------------------------------------- +BBitmap * +BTranslationUtils::GetBitmap(BPositionIO *stream, BTranslatorRoster *roster) +{ + return TranslateToBitmap(stream, roster); + // Translate the data in memio using the BTranslatorRoster roster +} + +// --------------------------------------------------------------- +// GetStyledText +// +// This function translates the styled text in fromStream and +// inserts it at the end of the text in intoView, using the +// BTranslatorRoster *roster to do the translation. The structs +// that make it possible to work with the translated data are +// defined in +// /boot/develop/headers/be/translation/TranslatorFormats.h +// +// Preconditions: +// +// Parameters: fromStream, the stream with the styled text +// intoView, the view where the test will be inserted +// roster, BTranslatorRoster used to do the translation +// +// Postconditions: +// +// Returns: B_BAD_VALUE, if fromStream or intoView is NULL +// B_ERROR, if any other error occurred +// B_NO_ERROR, if successful +// --------------------------------------------------------------- +status_t +BTranslationUtils::GetStyledText(BPositionIO *fromStream, BTextView *intoView, + BTranslatorRoster *roster) +{ + if (fromStream == NULL || intoView == NULL) + return B_BAD_VALUE; + + // Use default Translator if none is specified + if (roster == NULL) { + roster = BTranslatorRoster::Default(); + if (roster == NULL) + return B_ERROR; + } + + // Translate the file from whatever format it is in the file + // to the B_STYLED_TEXT_FORMAT, placing the translated data into mallio + BMallocIO mallio; + if (roster->Translate(fromStream, NULL, NULL, &mallio, + B_STYLED_TEXT_FORMAT) < B_OK) + return B_ERROR; + + // make sure there is enough data to fill the stream header + const size_t kStreamHeaderSize = sizeof(TranslatorStyledTextStreamHeader); + if (mallio.BufferLength() < kStreamHeaderSize) + return B_ERROR; + + // copy the stream header from the mallio buffer + TranslatorStyledTextStreamHeader stm_header = + *((TranslatorStyledTextStreamHeader *) mallio.Buffer()); + + // convert the stm_header.header struct to the host format + const size_t kRecordHeaderSize = sizeof(TranslatorStyledTextRecordHeader); + if (swap_data(B_UINT32_TYPE, &stm_header.header, kRecordHeaderSize, + B_SWAP_BENDIAN_TO_HOST) != B_OK) + return B_ERROR; + if (swap_data(B_INT32_TYPE, &stm_header.version, sizeof(int32), + B_SWAP_BENDIAN_TO_HOST) != B_OK) + return B_ERROR; + if (stm_header.header.magic != 'STXT') + return B_ERROR; + + // copy the text header from the mallio buffer + uint32 offset = stm_header.header.header_size + + stm_header.header.data_size; + const size_t kTextHeaderSize = sizeof(TranslatorStyledTextTextHeader); + if (mallio.BufferLength() < offset + kTextHeaderSize) + return B_ERROR; + + TranslatorStyledTextTextHeader txt_header = + *((TranslatorStyledTextTextHeader *) ((char *) mallio.Buffer() + + offset)); + + // convert the stm_header.header struct to the host format + if (swap_data(B_UINT32_TYPE, &txt_header.header, kRecordHeaderSize, + B_SWAP_BENDIAN_TO_HOST) != B_OK) + return B_ERROR; + if (swap_data(B_INT32_TYPE, &txt_header.charset, sizeof(int32), + B_SWAP_BENDIAN_TO_HOST) != B_OK) + return B_ERROR; + if (txt_header.header.magic != 'TEXT') + return B_ERROR; + if (txt_header.charset != B_UNICODE_UTF8) + return B_ERROR; + + offset += txt_header.header.header_size; + if (mallio.BufferLength() < offset + txt_header.header.data_size) + return B_ERROR; + + const char *pTextData = ((const char *) mallio.Buffer()) + offset; + // point text pointer at the actual character data + + if (mallio.BufferLength() > offset + txt_header.header.data_size) { + // If the stream contains information beyond the text data + // (which means that this data is probably styled text data) + + offset += txt_header.header.data_size; + const size_t kStyleHeaderSize = + sizeof(TranslatorStyledTextStyleHeader); + if (mallio.BufferLength() < offset + kStyleHeaderSize) + return B_ERROR; + + TranslatorStyledTextStyleHeader stl_header = + *((TranslatorStyledTextStyleHeader *) + ((char *) mallio.Buffer() + offset)); + if (swap_data(B_UINT32_TYPE, &stl_header.header, kRecordHeaderSize, + B_SWAP_BENDIAN_TO_HOST) != B_OK) + return B_ERROR; + if (swap_data(B_UINT32_TYPE, &stl_header.apply_offset, sizeof(uint32), + B_SWAP_BENDIAN_TO_HOST) != B_OK) + return B_ERROR; + if (swap_data(B_UINT32_TYPE, &stl_header.apply_length, sizeof(uint32), + B_SWAP_BENDIAN_TO_HOST) != B_OK) + return B_ERROR; + if (stl_header.header.magic != 'STYL') + return B_ERROR; + + offset += stl_header.header.header_size; + if (mallio.BufferLength() < offset + stl_header.header.data_size) + return B_ERROR; + + // set pRawData to the flattened run array data + const void *kpRawData = (const void *) ((char *) mallio.Buffer() + + offset); + text_run_array *pRunArray = BTextView::UnflattenRunArray(kpRawData); + + if (pRunArray) { + intoView->Insert(intoView->TextLength(), pTextData, + txt_header.header.data_size, pRunArray); + free(pRunArray); + pRunArray = NULL; + } else + return B_ERROR; + } else + intoView->Insert(intoView->TextLength(), pTextData, + txt_header.header.data_size); + + return B_NO_ERROR; +} + +// --------------------------------------------------------------- +// PutStyledText +// +// This function takes styled text data from fromView and writes it to +// intoStream. The plain text data and styled text data are combined +// when they are written to intoStream. This is different than how +// a save operation in StyledEdit works. With StyledEdit, it writes +// plain text data to the file, but puts the styled text data in +// the "styles" attribute. In other words, this function writes +// styled text data to files in a manner that isn't human readable. +// +// So, if you want to write styled text +// data to a file, and you want it to behave the way StyledEdit does, +// you want to use the BTranslationUtils::WriteStyledEditFile() function. +// +// Preconditions: +// +// Parameters: fromView, the view with the styled text in it +// intoStream, the stream where the styled text is put +// roster, not used +// +// Postconditions: +// +// Returns: B_BAD_VALUE, if fromView or intoStream is NULL +// B_ERROR, if anything else went wrong +// B_NO_ERROR, if successful +// --------------------------------------------------------------- +status_t +BTranslationUtils::PutStyledText(BTextView *fromView, BPositionIO *intoStream, + BTranslatorRoster *roster) +{ + if (fromView == NULL || intoStream == NULL) + return B_BAD_VALUE; + + int32 textLength = fromView->TextLength(); + if (textLength < 0) + return B_ERROR; + + const char *pTextData = fromView->Text(); + // its OK if the result of fromView->Text() is NULL + + int32 runArrayLength = 0; + text_run_array *pRunArray = fromView->RunArray(0, textLength, + &runArrayLength); + if (pRunArray == NULL) + return B_ERROR; + + int32 flatRunArrayLength = 0; + void *pflatRunArray = + BTextView::FlattenRunArray(pRunArray, &flatRunArrayLength); + if (pflatRunArray == NULL) { + free(pRunArray); + pRunArray = NULL; + + return B_ERROR; + } + + // Rather than use a goto, I put a whole bunch of code that + // could error out inside of a loop, and break out of the loop + // if there is an error. If there is no error, loop is set + // to false. This is so that I don't have to put free() + // calls everywhere there could be an error. + + // This block of code is where I do all of the writting of the + // data to the stream. I've gathered all of the data that I + // need at this point. + bool loop = true; + while (loop) { + const size_t kStreamHeaderSize = + sizeof(TranslatorStyledTextStreamHeader); + TranslatorStyledTextStreamHeader stm_header; + stm_header.header.magic = 'STXT'; + stm_header.header.header_size = kStreamHeaderSize; + stm_header.header.data_size = 0; + stm_header.version = 100; + + // convert the stm_header.header struct to the host format + const size_t kRecordHeaderSize = + sizeof(TranslatorStyledTextRecordHeader); + if (swap_data(B_UINT32_TYPE, &stm_header.header, kRecordHeaderSize, + B_SWAP_HOST_TO_BENDIAN) != B_OK) + break; + if (swap_data(B_INT32_TYPE, &stm_header.version, sizeof(int32), + B_SWAP_HOST_TO_BENDIAN) != B_OK) + break; + + const size_t kTextHeaderSize = sizeof(TranslatorStyledTextTextHeader); + TranslatorStyledTextTextHeader txt_header; + txt_header.header.magic = 'TEXT'; + txt_header.header.header_size = kTextHeaderSize; + txt_header.header.data_size = textLength; + txt_header.charset = B_UNICODE_UTF8; + + // convert the stm_header.header struct to the host format + if (swap_data(B_UINT32_TYPE, &txt_header.header, kRecordHeaderSize, + B_SWAP_HOST_TO_BENDIAN) != B_OK) + break; + if (swap_data(B_INT32_TYPE, &txt_header.charset, sizeof(int32), + B_SWAP_HOST_TO_BENDIAN) != B_OK) + break; + + const size_t kStyleHeaderSize = + sizeof(TranslatorStyledTextStyleHeader); + TranslatorStyledTextStyleHeader stl_header; + stl_header.header.magic = 'STYL'; + stl_header.header.header_size = kStyleHeaderSize; + stl_header.header.data_size = flatRunArrayLength; + stl_header.apply_offset = 0; + stl_header.apply_length = textLength; + + // convert the stl_header.header struct to the host format + if (swap_data(B_UINT32_TYPE, &stl_header.header, kRecordHeaderSize, + B_SWAP_HOST_TO_BENDIAN) != B_OK) + break; + if (swap_data(B_UINT32_TYPE, &stl_header.apply_offset, sizeof(uint32), + B_SWAP_HOST_TO_BENDIAN) != B_OK) + break; + if (swap_data(B_UINT32_TYPE, &stl_header.apply_length, sizeof(uint32), + B_SWAP_HOST_TO_BENDIAN) != B_OK) + break; + + // Here, you can see the structure of the styled text data by + // observing the order that the various structs and data are + // written to the stream + ssize_t amountWritten = 0; + amountWritten = intoStream->Write(&stm_header, kStreamHeaderSize); + if ((size_t) amountWritten != kStreamHeaderSize) + break; + amountWritten = intoStream->Write(&txt_header, kTextHeaderSize); + if ((size_t) amountWritten != kTextHeaderSize) + break; + amountWritten = intoStream->Write(pTextData, textLength); + if (amountWritten != textLength) + break; + amountWritten = intoStream->Write(&stl_header, kStyleHeaderSize); + if ((size_t) amountWritten != kStyleHeaderSize) + break; + amountWritten = intoStream->Write(pflatRunArray, flatRunArrayLength); + if (amountWritten != flatRunArrayLength) + break; + + loop = false; + // gracefully break out of the loop + } // end of while(loop) + + free(pflatRunArray); + pflatRunArray = NULL; + free(pRunArray); + pRunArray = NULL; + + if (loop) + return B_ERROR; + else + return B_NO_ERROR; +} + +// --------------------------------------------------------------- +// WriteStyledEditFile +// +// This function writes the styled text data from fromView +// and stores it in the file intoFile. +// +// This function is similar to PutStyledText() except that it +// only writes styled text data to files and it puts the +// plain text data in the file and stores the styled data as +// the attribute "styles". +// +// You can use PutStyledText() to write styled text data +// to files, but it writes the data in a format that isn't +// human readable. +// +// It is important to note that this function doesn't +// write files in exactly the same manner that you get +// when you do a File->Save operation in StyledEdit. +// This function doesn't write all of the attributes +// that StyledEdit does, even though it easily could. +// +// Preconditions: +// +// Parameters: fromView, the view with the styled text +// intoFile, the file where the styled text +// is written to +// +// Postconditions: +// +// Returns: B_BAD_VALUE, if either parameter is NULL +// B_ERROR, if anything else went wrong +// B_OK, if successful +// --------------------------------------------------------------- +status_t +BTranslationUtils::WriteStyledEditFile(BTextView *fromView, BFile *intoFile) +{ + if (fromView == NULL || intoFile == NULL) + return B_BAD_VALUE; + + int32 textLength = fromView->TextLength(); + if (textLength < 0) + return B_ERROR; + + const char *kpTextData = fromView->Text(); + if (kpTextData == NULL && textLength != 0) + return B_ERROR; + + // Write plain text data to file + ssize_t amtWritten = intoFile->Write(kpTextData, textLength); + if (amtWritten != textLength) + return B_ERROR; + + // Write attributes + // BEOS:TYPE + // (this is so that the BeOS will recognize this file as a text file) + amtWritten = intoFile->WriteAttr("BEOS:TYPE", 'MIMS', 0, "text/plain", 11); + if ((size_t) amtWritten != 11) + return B_ERROR; + + text_run_array *pRunArray = fromView->RunArray(0, fromView->TextLength()); + if (pRunArray == NULL) + return B_ERROR; + + int32 runArraySize = 0; + void *pflatRunArray = BTextView::FlattenRunArray(pRunArray, &runArraySize); + if (pflatRunArray == NULL) { + free(pRunArray); + pRunArray = NULL; + return B_ERROR; + } + if (runArraySize < 0) { + free(pflatRunArray); + pflatRunArray = NULL; + free(pRunArray); + pRunArray = NULL; + return B_ERROR; + } + + // This is how the styled text data is stored in the file + // (the trick is that it isn't actually stored in the file, its stored + // as an attribute in the file's node) + amtWritten = intoFile->WriteAttr("styles", B_RAW_TYPE, 0, pflatRunArray, + runArraySize); + free(pflatRunArray); + pflatRunArray = NULL; + free(pRunArray); + pRunArray = NULL; + if (amtWritten == runArraySize) + return B_OK; + else + return B_ERROR; +} + +// --------------------------------------------------------------- +// GetDefaultSettings +// +// Each translator can have default settings, set by the +// "translations" control panel. You can read these settings to +// pass on to a translator using one of these functions. +// +// Preconditions: +// +// Parameters: forTranslator, the translator the settings are for +// roster, the roster used to get the settings +// +// Postconditions: +// +// Returns: NULL, if anything went wrong +// BMessage * of configuration data for forTranslator +// --------------------------------------------------------------- +BMessage * +BTranslationUtils::GetDefaultSettings(translator_id forTranslator, + BTranslatorRoster *roster) +{ + // Use default Translator if none is specified + if (roster == NULL) { + roster = BTranslatorRoster::Default(); + if (roster == NULL) + return NULL; + } + + BMessage *pMessage = new BMessage(); + if (pMessage == NULL) + return NULL; + + status_t result = roster->GetConfigurationMessage(forTranslator, pMessage); + switch (result) { + case B_OK: + break; + + case B_NO_TRANSLATOR: + // Be's version seems to just pass an empty + // BMessage for this case, well, in some cases anyway + break; + + case B_NOT_INITIALIZED: + delete pMessage; + pMessage = NULL; + break; + + case B_BAD_VALUE: + delete pMessage; + pMessage = NULL; + break; + + default: + break; + } + + return pMessage; +} + +// --------------------------------------------------------------- +// GetDefaultSettings +// +// Attempts to find the translator settings for +// the translator named kTranslatorName with a version of +// translatorVersion. +// +// Preconditions: +// +// Parameters: kTranslatorName, the name of the translator +// the settings are for +// translatorVersion, the version of the translator +// to retrieve +// +// Postconditions: +// +// Returns: NULL, if anything went wrong +// BMessage * of configuration data for kTranslatorName +// --------------------------------------------------------------- +BMessage * +BTranslationUtils::GetDefaultSettings(const char *kTranslatorName, + int32 translatorVersion) +{ + BTranslatorRoster *roster = BTranslatorRoster::Default(); + translator_id *translators = NULL; + int32 numTranslators = 0; + if (roster == NULL + || roster->GetAllTranslators(&translators, &numTranslators) != B_OK) + return NULL; + + // Cycle through all of the default translators + // looking for a translator that matches the name and version + // that I was given + BMessage *pMessage = NULL; + const char *currentTranName = NULL, *currentTranInfo = NULL; + int32 currentTranVersion = 0; + for (int i = 0; i < numTranslators; i++) { + + if (roster->GetTranslatorInfo(translators[i], ¤tTranName, + ¤tTranInfo, ¤tTranVersion) == B_OK) { + + if (currentTranVersion == translatorVersion + && strcmp(currentTranName, kTranslatorName) == 0) { + pMessage = GetDefaultSettings(translators[i], roster); + break; + } + } + } + + delete[] translators; + return pMessage; +} + +// --------------------------------------------------------------- +// AddTranslationItems +// +// Envious of that "Save As" menu in ShowImage? Well, you can have your own! +// AddTranslationItems will add menu items for all translations from the +// basic format you specify (B_TRANSLATOR_BITMAP, B_TRANSLATOR_TEXT etc). +// The translator ID and format constant chosen will be added to the message +// that is sent to you when the menu item is selected. +// +// The following code is a modified version of code +// written by Jon Watte from +// http://www.b500.com/bepage/TranslationKit2.html +// +// Preconditions: +// +// Parameters: intoMenu, the menu where the entries are created +// fromType, the type of translators to put on +// intoMenu +// kModel, the BMessage model for creating the menu +// if NULL, B_TRANSLATION_MENU is used +// kTranslationIdName, the name used for +// translator_id in the menuitem, +// if NULL, be:translator is used +// kTranslatorTypeName, the name used for +// output format id in the menuitem +// roster, BTranslatorRoster used to find translators +// if NULL, the default translators are used +// +// +// Postconditions: +// +// Returns: B_BAD_VALUE, if intoMenu is NULL +// B_OK, if successful +// error value if not successful +// --------------------------------------------------------------- +status_t +BTranslationUtils::AddTranslationItems(BMenu *intoMenu, uint32 fromType, + const BMessage *kModel, const char *kTranslatorIdName, + const char *kTranslatorTypeName, BTranslatorRoster *roster) +{ + if (!intoMenu) + return B_BAD_VALUE; + + if (!roster) + roster = BTranslatorRoster::Default(); + + if (!kTranslatorIdName) + kTranslatorIdName = "be:translator"; + + if (!kTranslatorTypeName) + kTranslatorTypeName = "be:type"; + + translator_id * ids = NULL; + int32 count = 0; + status_t err = roster->GetAllTranslators(&ids, &count); + if (err < B_OK) + return err; + + for (int tix = 0; tix < count; tix++) { + const translation_format *formats = NULL; + int32 numFormats = 0; + bool ok = false; + err = roster->GetInputFormats(ids[tix], &formats, &numFormats); + if (err == B_OK) { + for (int iix = 0; iix < numFormats; iix++) { + if (formats[iix].type == fromType) { + ok = true; + break; + } + } + } + if (!ok) + continue; + + err = roster->GetOutputFormats(ids[tix], &formats, &numFormats); + if (err == B_OK) { + for (int oix = 0; oix < numFormats; oix++) { + if (formats[oix].type != fromType) { + BMessage *itemmsg; + if (kModel) + itemmsg = new BMessage(*kModel); + else + itemmsg = new BMessage(B_TRANSLATION_MENU); + itemmsg->AddInt32(kTranslatorIdName, ids[tix]); + itemmsg->AddInt32(kTranslatorTypeName, formats[oix].type); + intoMenu->AddItem( + new BMenuItem(formats[oix].name, itemmsg)); + } + } + } + } + + delete[] ids; + return B_OK; +} + +// --------------------------------------------------------------- +// TranslateToBitmap +// +// Translates the image data from pio to the type type using the +// supplied BTranslatorRoster. If BTranslatorRoster is not supplied +// the default BTranslatorRoster is used. This function is used +// indirectly by the GetBitmap functions +// +// Preconditions: +// +// Parameters: pio, the stream to get the bitmap from +// type, the type of data in the stream +// roster, BTranslatorRoster used to do the +// translation, if NULL the default +// translators are used +// +// Postconditions: +// +// Returns: NULL, if anything went wrong +// BBitmap * for the bitmap data from pio if successful +// --------------------------------------------------------------- +BBitmap * +BTranslationUtils::TranslateToBitmap(BPositionIO *pio, + BTranslatorRoster *roster) +{ + if (pio == NULL) + return NULL; + + // Use default Translator if none is specified + if (roster == NULL) { + roster = BTranslatorRoster::Default(); + if (roster == NULL) + return NULL; + } + + // Translate the file from whatever format it is in the file + // to the type format so that it can be stored in a BBitmap + BBitmapStream bitmapStream; + if (roster->Translate(pio, NULL, NULL, &bitmapStream, + B_TRANSLATOR_BITMAP) < B_OK) + return NULL; + + // Detach the BBitmap from the BBitmapStream so the user + // of this function can do what they please with it. + BBitmap *pBitmap = NULL; + if (bitmapStream.DetachBitmap(&pBitmap) == B_NO_ERROR) + return pBitmap; + else + return NULL; +} + diff --git a/src/kits/translation/Translator.cpp b/src/kits/translation/Translator.cpp new file mode 100644 index 0000000000..610628ba94 --- /dev/null +++ b/src/kits/translation/Translator.cpp @@ -0,0 +1,356 @@ +/*****************************************************************************/ +// File: Translator.cpp +// Class: BTranslator +// Reimplimented by: Michael Wilber, Translation Kit Team +// Reimplimentation: 2002-06-15 +// +// Description: This file contains the BTranslator class, the base class for +// all translators that don't use the BeOS R4/R4.5 add-on method. +// +// +// Copyright (c) 2002 OpenBeOS Project +// +// Original Version: Copyright 1998, Be Incorporated, All Rights Reserved. +// Copyright 1995-1997, Jon Watte +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ + +#include + +// Set refcount to 1 +// --------------------------------------------------------------- +// Constructor +// +// Sets refcount to 1 and creates a semaphore for locking the +// object. +// +// Preconditions: +// +// Parameters: +// +// Postconditions: +// +// Returns: +// --------------------------------------------------------------- +BTranslator::BTranslator() +{ + fRefCount = 1; + fSem = create_sem(1, "BTranslator Lock"); +} + +// --------------------------------------------------------------- +// Destructor +// +// Deletes the semaphore and resets it. +// +// Preconditions: +// +// Parameters: +// +// Postconditions: +// +// Returns: +// --------------------------------------------------------------- +BTranslator::~BTranslator() +{ + delete_sem(fSem); + fSem = 0; +} + +// --------------------------------------------------------------- +// Acquire +// +// Increments the refcount and returns a pointer to this object. +// +// Preconditions: +// +// Parameters: +// +// Postconditions: +// +// Returns: NULL, if failed to acquire the sempaphore +// pointer to this object if successful +// --------------------------------------------------------------- +BTranslator *BTranslator::Acquire() +{ + if (fSem > 0 && acquire_sem(fSem) == B_OK) { + fRefCount++; + release_sem(fSem); + return this; + } else + return NULL; +} + +// --------------------------------------------------------------- +// Release +// +// Decrements the refcount and returns a pointer to this object. +// When the refcount hits zero, the object is destroyed. This is +// so multiple objects can own the BTranslator and it won't get +// deleted until all of them are done with it. +// +// Preconditions: +// +// Parameters: +// +// Postconditions: +// +// Returns: NULL, if failed to acquire the sempaphore or the +// object was just deleted +// pointer to this object if successful +// --------------------------------------------------------------- +BTranslator *BTranslator::Release() +{ + if (fSem > 0 && acquire_sem(fSem) == B_OK) { + fRefCount--; + if (fRefCount > 0) { + release_sem(fSem); + return this; + } else { + delete this; + return NULL; + } + } else + return NULL; +} + +// --------------------------------------------------------------- +// ReferenceCount +// +// This function returns the current +// refcount. Notice that it is not thread safe. +// This function is only meant for fun/debugging. +// +// Preconditions: +// +// Parameters: +// +// Postconditions: +// +// Returns: the current refcount +// --------------------------------------------------------------- +int32 BTranslator::ReferenceCount() +{ + return fRefCount; +} + +// --------------------------------------------------------------- +// MakeConfigurationView +// +// This virtual function is for creating a configuration view +// for the translator so the user can change its settings. This +// base class version does nothing. Not all BTranslator derived +// object are required to support this function. +// +// Preconditions: +// +// Parameters: ioExtension, configuration data for the translator +// outView, where the created view is stored +// outText, the bounds of the view are stored here +// +// Postconditions: +// +// Returns: B_ERROR +// --------------------------------------------------------------- +status_t BTranslator::MakeConfigurationView(BMessage *ioExtension, + BView **outView, BRect *outExtent) +{ + return B_ERROR; +} + +// --------------------------------------------------------------- +// GetConfigurationMessage +// +// Puts the current configuration for the translator into +// ioExtension. Not all translators are required to support +// this function +// +// Preconditions: +// +// Parameters: ioExtension, where the configuration data is stored +// +// Postconditions: +// +// Returns: B_ERROR +// --------------------------------------------------------------- +status_t BTranslator::GetConfigurationMessage(BMessage *ioExtension) +{ + return B_ERROR; +} + +// --------------------------------------------------------------- +// _Reserved_Translator_0 +// +// It does nothing! :) Its only here for past/future binary +// compatiblity. +// +// Preconditions: +// +// Parameters: n, not used +// p, not used +// +// Postconditions: +// +// Returns: B_ERROR +// --------------------------------------------------------------- +status_t BTranslator::_Reserved_Translator_0(int32 n, void *p) +{ + return B_ERROR; +} + +// --------------------------------------------------------------- +// _Reserved_Translator_1 +// +// It does nothing! :) Its only here for past/future binary +// compatiblity. +// +// Preconditions: +// +// Parameters: n, not used +// p, not used +// +// Postconditions: +// +// Returns: B_ERROR +// --------------------------------------------------------------- +status_t BTranslator::_Reserved_Translator_1(int32 n, void *p) +{ + return B_ERROR; +} + +// --------------------------------------------------------------- +// _Reserved_Translator_2 +// +// It does nothing! :) Its only here for past/future binary +// compatiblity. +// +// Preconditions: +// +// Parameters: n, not used +// p, not used +// +// Postconditions: +// +// Returns: B_ERROR +// --------------------------------------------------------------- +status_t BTranslator::_Reserved_Translator_2(int32 n, void *p) +{ + return B_ERROR; +} + +// --------------------------------------------------------------- +// _Reserved_Translator_3 +// +// It does nothing! :) Its only here for past/future binary +// compatiblity. +// +// Preconditions: +// +// Parameters: n, not used +// p, not used +// +// Postconditions: +// +// Returns: B_ERROR +// --------------------------------------------------------------- +status_t BTranslator::_Reserved_Translator_3(int32 n, void *p) +{ + return B_ERROR; +} + +// --------------------------------------------------------------- +// _Reserved_Translator_4 +// +// It does nothing! :) Its only here for past/future binary +// compatiblity. +// +// Preconditions: +// +// Parameters: n, not used +// p, not used +// +// Postconditions: +// +// Returns: B_ERROR +// --------------------------------------------------------------- +status_t BTranslator::_Reserved_Translator_4(int32 n, void *p) +{ + return B_ERROR; +} + +// --------------------------------------------------------------- +// _Reserved_Translator_5 +// +// It does nothing! :) Its only here for past/future binary +// compatiblity. +// +// Preconditions: +// +// Parameters: n, not used +// p, not used +// +// Postconditions: +// +// Returns: B_ERROR +// --------------------------------------------------------------- +status_t BTranslator::_Reserved_Translator_5(int32 n, void *p) +{ + return B_ERROR; +} + +// --------------------------------------------------------------- +// _Reserved_Translator_6 +// +// It does nothing! :) Its only here for past/future binary +// compatiblity. +// +// Preconditions: +// +// Parameters: n, not used +// p, not used +// +// Postconditions: +// +// Returns: B_ERROR +// --------------------------------------------------------------- +status_t BTranslator::_Reserved_Translator_6(int32 n, void *p) +{ + return B_ERROR; +} + +// --------------------------------------------------------------- +// _Reserved_Translator_7 +// +// It does nothing! :) Its only here for past/future binary +// compatiblity. +// +// Preconditions: +// +// Parameters: n, not used +// p, not used +// +// Postconditions: +// +// Returns: B_ERROR +// --------------------------------------------------------------- +status_t BTranslator::_Reserved_Translator_7(int32 n, void *p) +{ + return B_ERROR; +} diff --git a/src/kits/translation/TranslatorRoster.cpp b/src/kits/translation/TranslatorRoster.cpp new file mode 100644 index 0000000000..c0a4613cad --- /dev/null +++ b/src/kits/translation/TranslatorRoster.cpp @@ -0,0 +1,1686 @@ +/*****************************************************************************/ +// File: TranslatorRoster.cpp +// Class: BTranslatorRoster +// Reimplimented by: Michael Wilber, Translation Kit Team +// Reimplimentation: 2002-06-11 +// +// Description: This class is the guts of the translation kit, it makes the +// whole thing happen. It bridges the applications using this +// object with the translators that the apps need to access. +// +// +// Copyright (c) 2002 OpenBeOS Project +// +// Original Version: Copyright 1998, Be Incorporated, All Rights Reserved. +// Copyright 1995-1997, Jon Watte +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ + +#include + +// Initialize static member variable +BTranslatorRoster *BTranslatorRoster::fspDefaultTranslators = NULL; + +// Extensions used in the extension BMessage, defined in TranslatorFormats.h +char B_TRANSLATOR_EXT_HEADER_ONLY[] = "/headerOnly"; +char B_TRANSLATOR_EXT_DATA_ONLY[] = "/dataOnly"; +char B_TRANSLATOR_EXT_COMMENT[] = "/comment"; +char B_TRANSLATOR_EXT_TIME[] = "/time"; +char B_TRANSLATOR_EXT_FRAME[] = "/frame"; +char B_TRANSLATOR_EXT_BITMAP_RECT[] = "bits/Rect"; +char B_TRANSLATOR_EXT_BITMAP_COLOR_SPACE[] = "bits/space"; +char B_TRANSLATOR_EXT_BITMAP_PALETTE[] = "bits/palette"; +char B_TRANSLATOR_EXT_SOUND_CHANNEL[] = "nois/channel"; +char B_TRANSLATOR_EXT_SOUND_MONO[] = "nois/mono"; +char B_TRANSLATOR_EXT_SOUND_MARKER[] = "nois/marker"; +char B_TRANSLATOR_EXT_SOUND_LOOP[] = "nois/loop"; + +// --------------------------------------------------------------- +// Constructor +// +// Private, unimplimented constructor that no one should use. +// I don't think there would be much of a need for this function. +// +// Preconditions: +// +// Parameters: tr, not used +// +// Postconditions: +// +// Returns: +// --------------------------------------------------------------- +BTranslatorRoster::BTranslatorRoster(const BTranslatorRoster &tr) + : BArchivable() +{ + Initialize(); +} + +// --------------------------------------------------------------- +// operator= +// +// Private, unimplimented function that no one should use. +// I don't know that there is a need for this function anyway. +// +// Preconditions: +// +// Parameters: tr, not used +// +// Postconditions: +// +// Returns: refernce to this object +// --------------------------------------------------------------- +BTranslatorRoster & +BTranslatorRoster::operator=(const BTranslatorRoster &tr) +{ + return *this; +} + +// --------------------------------------------------------------- +// Constructor +// +// Initilizes the BTranslatorRoster to the empty state, it loads +// no translators. +// +// Preconditions: +// +// Parameters: +// +// Postconditions: +// +// Returns: +// --------------------------------------------------------------- +BTranslatorRoster::BTranslatorRoster() : BArchivable() +{ + Initialize(); +} + +// --------------------------------------------------------------- +// Constructor +// +// This constructor initilizes the BTranslatorRoster, then +// loads all of the translators specified in the +// "be:translator_path" field of the supplied BMessage. +// +// Preconditions: +// +// Parameters: model, the BMessage where the translator paths are +// found. +// +// Postconditions: +// +// Returns: +// --------------------------------------------------------------- +BTranslatorRoster::BTranslatorRoster(BMessage *model) : BArchivable() +{ + Initialize(); + + if (model) { + BString bstr; + for (int32 i = 0; + model->FindString("be:translator_path", i, &bstr) == B_OK; i++) { + AddTranslators(bstr.String()); + bstr = ""; + } + } +} + +// --------------------------------------------------------------- +// Initialize() +// +// This function initializes this object to the empty state. It +// is used by all constructors. +// +// Preconditions: Object must be in initial uninitialized state +// +// Parameters: +// +// Postconditions: +// +// Returns: +// --------------------------------------------------------------- +void BTranslatorRoster::Initialize() +{ + fpTranslators = NULL; + fSem = create_sem(1, "BTranslatorRoster Lock"); +} + +// --------------------------------------------------------------- +// Destructor +// +// Unloads any translators that were loaded and frees all memory +// allocated by the BTranslatorRoster, except for the static +// member data. +// +// Preconditions: +// +// Parameters: +// +// Postconditions: +// +// Returns: +// --------------------------------------------------------------- +BTranslatorRoster::~BTranslatorRoster() +{ + if (fSem > 0 && acquire_sem(fSem) == B_NO_ERROR) { + + // FIRST PASS: release BTranslator objects + translator_node *pTranNode = fpTranslators; + while (pTranNode) { + translator_node *pRelTranNode = pTranNode; + pTranNode = pTranNode->next; + pRelTranNode->translator->Release(); + } + + // SECOND PASS: unload images and delete nodes + // (I can't delete a BTranslator if I've deleted + // the code for it) + pTranNode = fpTranslators; + while (pTranNode) { + translator_node *pDelTranNode = pTranNode; + pTranNode = pTranNode->next; + + // only try to unload actual images + if (pDelTranNode->image >= 0) + unload_add_on(pDelTranNode->image); + // I may end up trying to unload the same image + // more than once, but I don't think + // that should be a problem + delete[] pDelTranNode->path; + delete pDelTranNode; + } + + fpTranslators = NULL; + } + + delete_sem(fSem); +} + +// --------------------------------------------------------------- +// Archive +// +// Archives the BTranslatorRoster by recording its loaded add-ons +// in the BMessage into. The deep variable appeared to have no +// impact in Be's version of this function, so I went the same +// route. +// +// Preconditions: +// +// Parameters: into, the BMessage that this object is written to +// deep, if true, more data is written, if false, +// less data is written +// +// Postconditions: +// +// Returns: B_OK, if everything went well +// B_BAD_VALUE, if into is NULL +// B_NOT_INITIALIZED, if the constructor couldn't create +// a semaphore +// other errors that BMessage::AddString() and +// BArchivable::Archive() return +// --------------------------------------------------------------- +status_t +BTranslatorRoster::Archive(BMessage *into, bool deep) const +{ + if (!into) + return B_BAD_VALUE; + + status_t result = B_NOT_INITIALIZED; + + if (fSem > 0 && acquire_sem(fSem) == B_OK) { + result = BArchivable::Archive(into, deep); + if (result == B_OK) { + result = into->AddString("class", "BTranslatorRoster"); + + translator_node *pTranNode = NULL; + for (pTranNode = fpTranslators; result == B_OK && pTranNode; + pTranNode = pTranNode->next) { + if (pTranNode->path[0]) + result = into->AddString("be:translator_path", + pTranNode->path); + } + } + release_sem(fSem); + } + + return result; +} + +// --------------------------------------------------------------- +// Instantiate +// +// This static member function returns a new BTranslatorRosters +// object, allocated by new and created with the version of the +// constructor that takes a BMessage archive. However if the +// archive doesn't contain data for a BTranslatorRoster object, +// Instantiate() returns NULL. +// +// Preconditions: +// +// Parameters: from, the BMessage to create the new object from +// +// Postconditions: +// +// Returns: returns NULL if the BMessage was no good +// returns a BArchivable * to a BTranslatorRoster +// --------------------------------------------------------------- +BArchivable * +BTranslatorRoster::Instantiate(BMessage *from) +{ + if (!from || !validate_instantiation(from, "BTranslatorRoster")) + return NULL; + else + return new BTranslatorRoster(from); +} + +// --------------------------------------------------------------- +// Version +// +// Sets outCurVersion to the Translation Kit protocol version +// number and outMinVersion to the minimum protocol version number +// supported. Returns a string containing verbose version +// information. Currently, inAppVersion must be +// B_TRANSLATION_CURRENT_VERSION, but as far as I can tell, its +// completely ignored. +// +// Preconditions: +// +// Parameters: outCurVersion, the current version is stored here +// outMinVersion, the minimum supported version is +// stored here +// inAppVersion, is ignored as far as I know +// +// Postconditions: +// +// Returns: string of verbose translation kit version +// information or an empty string if either of the +// out variables is NULL. +// --------------------------------------------------------------- +const char * +BTranslatorRoster::Version(int32 *outCurVersion, int32 *outMinVersion, + int32 inAppVersion) +{ + if (!outCurVersion || !outMinVersion) + return ""; + + static char vString[50]; + static char vDate[] = __DATE__; + if (!vString[0]) { + sprintf(vString, "Translation Kit v%d.%d.%d %s\n", + B_TRANSLATION_CURRENT_VERSION/100, + (B_TRANSLATION_CURRENT_VERSION/10)%10, + B_TRANSLATION_CURRENT_VERSION%10, + vDate); + } + *outCurVersion = B_TRANSLATION_CURRENT_VERSION; + *outMinVersion = B_TRANSLATION_MIN_VERSION; + return vString; +} + +// --------------------------------------------------------------- +// Default +// +// This static member function returns a pointer to the default +// BTranslatorRoster that has the default translators stored in +// it. The paths for the default translators are loaded from +// the TRANSLATORS environment variable. If it does not exist, +// the paths used are /boot/home/config/add-ons/Translators, +// /boot/home/config/add-ons/Datatypes, and +// /system/add-ons/Translators. The BTranslatorRoster returned +// by this function is global to the application and should +// not be deleted. +// +// This code probably isn't thread safe (yet). +// +// Preconditions: +// +// Parameters: +// +// Postconditions: +// +// Returns: pointer to the default BTranslatorRoster +// --------------------------------------------------------------- +BTranslatorRoster * +BTranslatorRoster::Default() +{ + // If the default translators have not been loaded, + // create a new BTranslatorRoster for them, and load them. + if (!fspDefaultTranslators) { + fspDefaultTranslators = new BTranslatorRoster(); + fspDefaultTranslators->AddTranslators(NULL); + } + + return fspDefaultTranslators; +} + +// --------------------------------------------------------------- +// AddTranslators +// +// This function takes a string of colon delimited paths, +// (folders or specific files) and adds the translators from +// those paths to this BTranslatorRoster. +// +// If load_path is NULL, it parses the environment variable +// TRANSLATORS. If that does not exist, it uses the paths: +// /boot/home/config/add-ons/Translators, +// /boot/home/config/add-ons/Datatypes and +// /system/add-ons/Translators. +// +// Preconditions: +// +// Parameters: load_path, colon delimited list of paths +// to load translators from +// +// Postconditions: +// +// Returns: B_OK on success, +// B_BAD_VALUE if there was something wrong with +// load_path +// other errors for problems with loading add-ons +// --------------------------------------------------------------- +status_t +BTranslatorRoster::AddTranslators(const char *load_path) +{ + if (fSem <= 0) + return fSem; + + status_t loadErr = B_ERROR; + int32 nLoaded = 0; + + if (acquire_sem(fSem) == B_OK) { + if (load_path == NULL) + load_path = getenv("TRANSLATORS"); + if (load_path == NULL) + load_path = kgDefaultTranslatorPath; + + char pathbuf[PATH_MAX]; + const char *ptr = load_path; + const char *end = ptr; + struct stat stbuf; + while (*ptr != 0) { + // find segments specified by colons + end = strchr(ptr, ':'); + if (end == NULL) + end = ptr + strlen(ptr); + if (end-ptr > PATH_MAX - 1) + loadErr = B_BAD_VALUE; + else { + // copy this segment of the path into a path, and load it + memcpy(pathbuf, ptr, end - ptr); + pathbuf[end - ptr] = 0; + + if (!stat(pathbuf, &stbuf)) { + // files are loaded as translators + if (S_ISREG(stbuf.st_mode)) { + status_t err = LoadTranslator(pathbuf); + if (err != B_OK) + loadErr = err; + else + nLoaded++; + } else + // directories are scanned + LoadDir(pathbuf, loadErr, nLoaded); + } + } + ptr = end + 1; + if (*end == 0) + break; + } // while (*ptr != 0) + + release_sem(fSem); + + } // if (acquire_sem(fSem) == B_OK) + + // if anything loaded, it's not too bad + if (nLoaded) + loadErr = B_OK; + + return loadErr; +} + +// --------------------------------------------------------------- +// AddTranslator +// +// Adds a BTranslator based object to the BTranslatorRoster. +// When you add a BTranslator roster, it is Acquire()'d by +// BTranslatorRoster; it is Release()'d when the +// BTranslatorRoster is deleted. +// +// Preconditions: +// +// Parameters: translator, the translator to be added to the +// BTranslatorRoster +// +// Postconditions: +// +// Returns: B_BAD_VALUE, if translator is NULL, +// B_NOT_INITIALIZED, if the constructor couldn't +// create a semaphore +// B_OK if all went well +// --------------------------------------------------------------- +status_t +BTranslatorRoster::AddTranslator(BTranslator *translator) +{ + if (!translator) + return B_BAD_VALUE; + + status_t result = B_NOT_INITIALIZED; + + if (fSem > 0 && acquire_sem(fSem) == B_NO_ERROR) { + // Determine if translator is already in the list + translator_node *pNode = fpTranslators; + while (pNode) { + // If translator is in the list, don't add it + if (!strcmp(pNode->translator->TranslatorName(), + translator->TranslatorName())) { + result = B_OK; + break; + } + pNode = pNode->next; + } + + // if translator is NOT in the list, add it + if (!pNode) + result = AddTranslatorToList(translator); + + release_sem(fSem); + } + + return result; +} + +// --------------------------------------------------------------- +// Identify +// +// This function determines which translator is best suited +// to convert the data from inSource. +// +// Preconditions: +// +// Parameters: inSource, the data to be translated, +// ioExtension, the configuration data for the +// translator +// outInfo, the information about the chosen +// translator is put here +// inHintType, a hint about the type of data +// that is in inSource, can be +// zero if type is not known +// inHintMIME, a hint about the MIME type of +// data that is in inSource, +// can be NULL +// inWantType, the desired output type for +// inSource, if zero, any type +// is ok. +// +// Postconditions: +// +// Returns: B_OK, identification of inSource was successful, +// B_NO_TRANSLATOR, no appropriate translator found +// B_NOT_INITIALIZED, the constructor failed to +// create a semaphore +// B_BAD_VALUE, inSource or outInfo is NULL +// other values, error using inSource +// --------------------------------------------------------------- +status_t +BTranslatorRoster::Identify(BPositionIO *inSource, + BMessage *ioExtension, translator_info *outInfo, + uint32 inHintType, const char *inHintMIME, + uint32 inWantType) +{ + if (!inSource || !outInfo) + return B_BAD_VALUE; + + status_t result = B_NOT_INITIALIZED; + bool bFoundMatch = false; + + if (fSem > 0 && acquire_sem(fSem) == B_OK) { + + translator_node *pTranNode = fpTranslators; + float bestWeight = 0.0; + for (; pTranNode; pTranNode = pTranNode->next) { + + const translation_format *format = NULL; + translator_info tmpInfo; + float weight = 0.0; + bool addmatch = false; + // eliminates need for a goto + + result = inSource->Seek(0, SEEK_SET); + if (result == B_OK) { + + int32 inputFormatsCount = 0; + const translation_format *inputFormats = + pTranNode->translator->InputFormats(&inputFormatsCount); + + if (CheckFormats(inputFormats, inputFormatsCount, inHintType, + inHintMIME, &format)) { + + // after checking the formats for hints, we still need to make + // sure the translator recognizes the data and can output the + // desired format, so we call its' Identify() function. + if (format && !pTranNode->translator->Identify(inSource, + format, ioExtension, &tmpInfo, inWantType)) + addmatch = true; + + } else if (!pTranNode->translator->Identify(inSource, NULL, + ioExtension, &tmpInfo, inWantType)) + addmatch = true; + + if (addmatch) { + weight = tmpInfo.quality * tmpInfo.capability; + + // Since many kinds of data can look like text, + // don't choose the text format if it has been identified + // as belonging to a different group. + if (bFoundMatch && outInfo->group == B_TRANSLATOR_TEXT && + tmpInfo.group != B_TRANSLATOR_TEXT) + bestWeight = 0.0; + else if (bFoundMatch && tmpInfo.group == B_TRANSLATOR_TEXT && + outInfo->group != B_TRANSLATOR_TEXT) + weight = 0.0; + + if (weight > bestWeight) { + bFoundMatch = true; + bestWeight = weight; + + tmpInfo.translator = pTranNode->id; + outInfo->type = tmpInfo.type; + outInfo->translator = tmpInfo.translator; + outInfo->group = tmpInfo.group; + outInfo->quality = tmpInfo.quality; + outInfo->capability = tmpInfo.capability; + strcpy(outInfo->name, tmpInfo.name); + strcpy(outInfo->MIME, tmpInfo.MIME); + } + } + } // if (result == B_OK) + } // for (; pTranNode; pTranNode = pTranNode->next) + + if (bFoundMatch) + result = B_NO_ERROR; + else if (result == B_OK) + result = B_NO_TRANSLATOR; + + release_sem(fSem); + } // if (acquire_sem(fSem) == B_OK) + + return result; +} + +// --------------------------------------------------------------- +// compare_data +// +// This function is not a member of BTranslatorRoster, but it is +// used by the GetTranslators() member function as the function +// passed to qsort to sort the translators from best to worst. +// +// Preconditions: +// +// Parameters: a, pointer to translator_info structure to be +// compared to b +// b, pointer to translator_info structure to be +// compared to a +// +// Postconditions: +// +// Returns: < 0 if a is less desirable than b, +// 0 if a as good as b, +// > 0 if a is more desirable than b +// --------------------------------------------------------------- +static int +compare_data(const void *a, const void *b) +{ + register translator_info *ai = (translator_info *)a; + register translator_info *bi = (translator_info *)b; + return (int) (- ai->quality * ai->capability + + bi->quality * bi->capability); +} + +// --------------------------------------------------------------- +// GetTranslators +// +// Finds all translators capable of handling the data in inSource +// and puts them into the outInfo array (which you must delete +// yourself when you are done with it). Specifying a value for +// inHintType, inHintMIME and/or inWantType causes only the +// translators that satisfy them to be included in the outInfo. +// +// Preconditions: +// +// Parameters: inSource, the data that wants to be translated +// ioExtension, configuration data for the translator +// outInfo, the array of acceptable translators is +// stored here if the function succeeds +// outNumInfo, number of entries in outInfo +// inHintType, hint for the type of data in +// inSource, can be zero if the +// type is not known +// inHintMIME, hint MIME type of the data +// in inSource, can be NULL if +// the MIME type is not known +// inWantType, the desired output type for +// the data in inSource, can be zero +// for any type. +// +// Postconditions: +// +// Returns: B_OK, successfully indentified the data in inSource +// B_NO_TRANSLATOR, no translator could handle inSource +// B_NOT_INITIALIZED, the constructore failed to create +// a semaphore +// B_BAD_VALUE, inSource, outInfo, or outNumInfo is NULL +// other errors, problems using inSource +// --------------------------------------------------------------- +status_t +BTranslatorRoster::GetTranslators(BPositionIO *inSource, + BMessage *ioExtension, translator_info **outInfo, + int32 *outNumInfo, uint32 inHintType, + const char *inHintMIME, uint32 inWantType) +{ + if (!inSource || !outInfo || !outNumInfo) + return B_BAD_VALUE; + + status_t result = B_NOT_INITIALIZED; + + *outInfo = NULL; + *outNumInfo = 0; + + if (fSem > 0 && acquire_sem(fSem) == B_OK) { + + int32 physCnt = 10; + *outInfo = new translator_info[physCnt]; + *outNumInfo = 0; + + translator_node *pTranNode = fpTranslators; + for (; pTranNode; pTranNode = pTranNode->next) { + + const translation_format *format = NULL; + translator_info tmpInfo; + bool addmatch = false; + // avoid the need for a goto + + result = inSource->Seek(0, SEEK_SET); + if (result < B_OK) { + // break out of the loop if error reading from source + delete *outInfo; + *outInfo = NULL; + break; + } else { + int32 inputFormatsCount = 0; + const translation_format *inputFormats = + pTranNode->translator->InputFormats(&inputFormatsCount); + + if (CheckFormats(inputFormats, inputFormatsCount, inHintType, + inHintMIME, &format)) { + if (format && !pTranNode->translator->Identify(inSource, + format, ioExtension, &tmpInfo, inWantType)) + addmatch = true; + + } else if (!pTranNode->translator->Identify(inSource, NULL, + ioExtension, &tmpInfo, inWantType)) + addmatch = true; + + if (addmatch) { + // dynamically resize output list + // + if (physCnt <= *outNumInfo) { + physCnt += 10; + translator_info *nOut = new translator_info[physCnt]; + for (int ix = 0; ix < *outNumInfo; ix++) + nOut[ix] = (*outInfo)[ix]; + + delete[] *outInfo; + *outInfo = nOut; + } + + // XOR to discourage taking advantage of undocumented + // features + tmpInfo.translator = pTranNode->id; + (*outInfo)[(*outNumInfo)++] = tmpInfo; + } + } + } // for (; pTranNode; pTranNode = pTranNode->next) + + // if exited loop WITHOUT errors + if (!pTranNode) { + + if (*outNumInfo > 1) + qsort(*outInfo, *outNumInfo, sizeof(**outInfo), compare_data); + + if (*outNumInfo > 0) + result = B_NO_ERROR; + else + result = B_NO_TRANSLATOR; + } + + release_sem(fSem); + + } // if (acquire_sem(fSem) == B_OK) + + return result; +} + +// --------------------------------------------------------------- +// GetAllTranslators +// +// Returns a list of all of the translators stored by this object. +// You must delete the list, outList, yourself when you are done +// with it. +// +// Preconditions: +// +// Parameters: outList, where the list is stored, +// (you must delete the list yourself) +// outCount, where the count of the items in +// the list is stored +// +// Postconditions: +// +// Returns: B_BAD_VALUE, if outList or outCount is NULL +// B_NOT_INITIALIZED, if the constructor couldn't +// create a semaphore +// B_NO_ERROR, if successful +// --------------------------------------------------------------- +status_t +BTranslatorRoster::GetAllTranslators( + translator_id **outList, int32 *outCount) +{ + if (!outList || !outCount) + return B_BAD_VALUE; + + status_t result = B_NOT_INITIALIZED; + + *outList = NULL; + *outCount = 0; + + if (fSem > 0 && acquire_sem(fSem) == B_OK) { + // count handlers + translator_node *pTranNode = NULL; + for (pTranNode = fpTranslators; pTranNode; pTranNode = pTranNode->next) + (*outCount)++; + *outList = new translator_id[*outCount]; + *outCount = 0; + for (pTranNode = fpTranslators; pTranNode; pTranNode = pTranNode->next) + (*outList)[(*outCount)++] = pTranNode->id; + + result = B_NO_ERROR; + release_sem(fSem); + } + + return result; +} + +// --------------------------------------------------------------- +// GetTranslatorInfo +// +// Returns information about the translator with translator_id +// forTranslator. outName is the short name of the translator, +// outInfo is the verbose name / description of the translator, +// and outVersion is the integer representation of the translator +// version. +// +// Preconditions: +// +// Parameters: forTranslator, identifies which translator +// you want info for +// outName, the translator name is put here +// outInfo, the translator info is put here +// outVersion, the translation version is put here +// +// Postconditions: +// +// Returns: B_NO_ERROR, if successful, +// B_BAD_VALUE, if any parameter is NULL +// B_NOT_INITIALIZED, if the constructor couldn't +// create a semaphore +// B_NO_TRANSLATOR, if forTranslator is not a valid +// translator id +// --------------------------------------------------------------- +status_t +BTranslatorRoster::GetTranslatorInfo( + translator_id forTranslator, const char **outName, + const char **outInfo, int32 *outVersion) +{ + if (!outName || !outInfo || !outVersion) + return B_BAD_VALUE; + + status_t result = B_NOT_INITIALIZED; + + if (fSem > 0 && acquire_sem(fSem) == B_OK) { + // find the translator we've requested + translator_node *pTranNode = FindTranslatorNode(forTranslator); + if (!pTranNode) + result = B_NO_TRANSLATOR; + else { + *outName = pTranNode->translator->TranslatorName(); + *outInfo = pTranNode->translator->TranslatorInfo(); + *outVersion = pTranNode->translator->TranslatorVersion(); + + result = B_NO_ERROR; + } + release_sem(fSem); + } + + return result; +} + +// --------------------------------------------------------------- +// GetInputFormats +// +// Returns all of the input formats for the translator +// forTranslator. Not all translators publish the input formats +// that they accept. +// +// Preconditions: +// +// Parameters: forTranslator, identifies which translator +// you want info for +// outFormats, array of input formats +// outNumFormats, number of items in outFormats +// +// Postconditions: +// +// Returns: B_NO_ERROR, if successful +// B_BAD_VALUE, if either pointer is NULL +// B_NOT_INITIALIZED, if the constructor couldn't +// create a semaphore +// B_NO_TRANSLATOR, if forTranslator is a bad id +// --------------------------------------------------------------- +status_t +BTranslatorRoster::GetInputFormats(translator_id forTranslator, + const translation_format **outFormats, int32 *outNumFormats) +{ + if (!outFormats || !outNumFormats) + return B_BAD_VALUE; + + status_t result = B_NOT_INITIALIZED; + + *outFormats = NULL; + *outNumFormats = 0; + + if (fSem > 0 && acquire_sem(fSem) == B_OK) { + // find the translator we've requested + translator_node *pTranNode = FindTranslatorNode(forTranslator); + if (!pTranNode) + result = B_NO_TRANSLATOR; + else { + *outFormats = pTranNode->translator->InputFormats(outNumFormats); + result = B_NO_ERROR; + } + release_sem(fSem); + } + + return result; +} + +// --------------------------------------------------------------- +// GetOutputFormats +// +// Returns all of the output formats for the translator +// forTranslator. Not all translators publish the output formats +// that they accept. +// +// Preconditions: +// +// Parameters: forTranslator, identifies which translator +// you want info for +// outFormats, array of output formats +// outNumFormats, number of items in outFormats +// +// Postconditions: +// +// Returns: B_NO_ERROR, if successful +// B_BAD_VALUE, if either pointer is NULL +// B_NOT_INITIALIZED, if the constructor couldn't +// create a semaphore +// B_NO_TRANSLATOR, if forTranslator is a bad id +// --------------------------------------------------------------- +status_t +BTranslatorRoster::GetOutputFormats(translator_id forTranslator, + const translation_format **outFormats, int32 *outNumFormats) +{ + if (!outFormats || !outNumFormats) + return B_BAD_VALUE; + + status_t result = B_NOT_INITIALIZED; + + *outFormats = NULL; + *outNumFormats = 0; + + if (fSem > 0 && acquire_sem(fSem) == B_OK) { + // find the translator we've requested + translator_node *pTranNode = FindTranslatorNode(forTranslator); + if (!pTranNode) + result = B_NO_TRANSLATOR; + else { + *outFormats = pTranNode->translator->OutputFormats(outNumFormats); + result = B_NO_ERROR; + } + release_sem(fSem); + } + + return result; +} + +// --------------------------------------------------------------- +// Translate +// +// This function is the whole point of the Translation Kit. +// This is for translating the data in inSource to outDestination +// using the format inWantOutType. +// +// Preconditions: +// +// Parameters: inSource, the data that wants to be translated +// ioExtension, configuration data for the translator +// inInfo, identifies the translator to use, can be +// NULL, calls Identify() if NULL +// inHintType, hint for the type of data in +// inSource, can be zero if the +// type is not known +// inHintMIME, hint MIME type of the data +// in inSource, can be NULL if +// the MIME type is not known +// inWantOutType, the desired output type for +// the data in inSource. +// outDestination, where inSource is translated to +// +// Postconditions: +// +// Returns: B_OK, translation successful, +// B_NO_TRANSLATOR, no appropriate translator found +// B_NOT_INITIALIZED, the constructor failed to +// create a semaphore +// B_BAD_VALUE, inSource or outDestination is NULL +// other values, error using inSource +// --------------------------------------------------------------- +status_t +BTranslatorRoster::Translate(BPositionIO *inSource, + const translator_info *inInfo, BMessage *ioExtension, + BPositionIO *outDestination, uint32 inWantOutType, + uint32 inHintType, const char *inHintMIME) +{ + if (!inSource || !outDestination) + return B_BAD_VALUE; + + if (fSem <= 0) + return B_NOT_INITIALIZED; + + status_t result = B_OK; + translator_info stat_info; + + if (!inInfo) { + // go look for a suitable translator + inInfo = &stat_info; + + result = Identify(inSource, ioExtension, &stat_info, + inHintType, inHintMIME, inWantOutType); + // Identify is a locked function, so it cannot be + // called from code that is already locked + } + + if (result >= B_OK && acquire_sem(fSem) == B_OK) { + translator_node *pTranNode = FindTranslatorNode(inInfo->translator); + if (!pTranNode) { + result = B_NO_TRANSLATOR; + } + else { + result = inSource->Seek(0, SEEK_SET); + if (result == B_OK) + result = pTranNode->translator->Translate(inSource, inInfo, + ioExtension, inWantOutType, outDestination); + } + release_sem(fSem); + } + + return result; +} + +// --------------------------------------------------------------- +// Translate +// +// This function is the whole point of the Translation Kit. +// This is for translating the data in inSource to outDestination +// using the format inWantOutType. +// +// Preconditions: +// +// Parameters: inSource, the data that wants to be translated +// ioExtension, configuration data for the translator +// inTranslator, the translator to use for the +// translation +// inWantOutType, the desired output type for +// the data in inSource. +// outDestination, where inSource is translated to +// +// Postconditions: +// +// Returns: B_OK, translation successful, +// B_NO_TRANSLATOR, inTranslator is an invalid id +// B_NOT_INITIALIZED, the constructor failed to +// create a semaphore +// B_BAD_VALUE, inSource or outDestination is NULL +// other values, error using inSource +// --------------------------------------------------------------- +status_t +BTranslatorRoster::Translate(translator_id inTranslator, + BPositionIO *inSource, BMessage *ioExtension, + BPositionIO *outDestination, uint32 inWantOutType) +{ + if (!inSource || !outDestination) + return B_BAD_VALUE; + + status_t result = B_NOT_INITIALIZED; + + if (fSem > 0 && acquire_sem(fSem) == B_OK) { + translator_node *pTranNode = FindTranslatorNode(inTranslator); + if (!pTranNode) + result = B_NO_TRANSLATOR; + else { + result = inSource->Seek(0, SEEK_SET); + if (result == B_OK) { + translator_info traninfo; + result = pTranNode->translator->Identify(inSource, NULL, + ioExtension, &traninfo, inWantOutType); + if (result == B_OK) { + result = inSource->Seek(0, SEEK_SET); + if (result == B_OK) { + result = pTranNode->translator->Translate(inSource, + &traninfo, ioExtension, inWantOutType, + outDestination); + } + } + } + } + release_sem(fSem); + } + + return result; +} + +// --------------------------------------------------------------- +// MakeConfigurationView +// +// Returns outView, a BView for configuring the translator +// forTranslator. Not all translators support this. +// +// Preconditions: +// +// Parameters: forTranslator, the translator the view is for +// ioExtension, the configuration data for +// the translator +// outView, the view for configuring the +// translator +// outExtent, the bounds for the view, the view +// can be resized +// +// Postconditions: +// +// Returns: B_OK, success, +// B_NO_TRANSLATOR, inTranslator is an invalid id +// B_NOT_INITIALIZED, the constructor failed to +// create a semaphore +// B_BAD_VALUE, inSource or outDestination is NULL +// other values, error using inSource +// --------------------------------------------------------------- +status_t +BTranslatorRoster::MakeConfigurationView( + translator_id forTranslator, BMessage *ioExtension, + BView **outView, BRect *outExtent) +{ + if (!outView || !outExtent) + return B_BAD_VALUE; + + status_t result = B_NOT_INITIALIZED; + + if (fSem > 0 && acquire_sem(fSem) == B_OK) { + translator_node *pTranNode = FindTranslatorNode(forTranslator); + if (!pTranNode) + result = B_NO_TRANSLATOR; + else + result = pTranNode->translator->MakeConfigurationView(ioExtension, + outView, outExtent); + + release_sem(fSem); + } + + return result; +} + +// --------------------------------------------------------------- +// GetConfigurationMessage +// +// Gets the configuration setttings for the translator +// forTranslator and puts the settings into ioExtension. +// +// Preconditions: +// +// Parameters: forTranslator, the translator the info +// is for +// ioExtension, the configuration data for +// the translator is stored here +// +// Postconditions: +// +// Returns: B_OK, success, +// B_NO_TRANSLATOR, inTranslator is an invalid id +// B_NOT_INITIALIZED, the constructor failed to +// create a semaphore +// B_BAD_VALUE, inSource or outDestination is NULL +// other values, error using inSource +// --------------------------------------------------------------- +status_t +BTranslatorRoster::GetConfigurationMessage( + translator_id forTranslator, BMessage *ioExtension) +{ + if (!ioExtension) + return B_BAD_VALUE; + + status_t result = B_NOT_INITIALIZED; + + if (fSem > 0 && acquire_sem(fSem) == B_OK) { + translator_node *pTranNode = FindTranslatorNode(forTranslator); + if (!pTranNode) + result = B_NO_TRANSLATOR; + else + result = + pTranNode->translator->GetConfigurationMessage(ioExtension); + + release_sem(fSem); + } + + return result; +} + +// --------------------------------------------------------------- +// GetRefFor +// +// Gets the entry_ref for the given translator. +// +// Preconditions: +// +// Parameters: forTranslator, the translator the info +// is for +// entry_ref, where the entry ref is stored +// +// Postconditions: +// +// Returns: B_OK, success, +// B_NO_TRANSLATOR, translator is an invalid id +// B_NOT_INITIALIZED, the constructor failed to +// create a semaphore +// B_BAD_VALUE, inSource or outDestination is NULL +// other values, error using inSource +// --------------------------------------------------------------- +status_t +BTranslatorRoster::GetRefFor(translator_id translator, + entry_ref *out_ref) +{ + if (!out_ref) + return B_BAD_VALUE; + + status_t result = B_NOT_INITIALIZED; + + if (fSem > 0 && acquire_sem(fSem) == B_OK) { + translator_node *pTranNode = FindTranslatorNode(translator); + if (!pTranNode) + result = B_NO_TRANSLATOR; + else { + if (pTranNode->path[0] == '\0') + result = B_ERROR; + else + result = get_ref_for_path(pTranNode->path, out_ref); + } + release_sem(fSem); + } + + return result; +} + + +// --------------------------------------------------------------- +// FindTranslatorNode +// +// Finds the translator_node that holds the translator with +// the translator_id id. +// +// Preconditions: +// +// Parameters: id, the translator you want a translator_node for +// +// Postconditions: +// +// Returns: NULL if id is not a valid translator_id, +// pointer to the translator_node that holds the +// translator id +// --------------------------------------------------------------- +translator_node * +BTranslatorRoster::FindTranslatorNode(translator_id id) +{ + translator_node *pTranNode = NULL; + for (pTranNode = fpTranslators; pTranNode; pTranNode = pTranNode->next) + if (pTranNode->id == id) + break; + + return pTranNode; +} + +// --------------------------------------------------------------- +// LoadTranslator +// +// Loads the translator from path into memory and adds it to +// the BTranslatorRoster. +// +// Preconditions: This should only be called inside of locked +// code. +// +// Parameters: path, the path for the translator to be loaded +// +// Postconditions: +// +// Returns: B_BAD_VALUE, if path is NULL, +// B_NO_ERROR, if all is well, +// other values if error loading add ons +// --------------------------------------------------------------- +status_t +BTranslatorRoster::LoadTranslator(const char *path) +{ + if (!path) + return B_BAD_VALUE; + + // check that this ref is not already loaded + const char *name = strrchr(path, '/'); + if (name) + name++; + else + name = path; + for (translator_node *i = fpTranslators; i; i=i->next) + if (!strcmp(name, i->translator->TranslatorName())) + return B_NO_ERROR; + // we use name for determining whether it's loaded + // that is not entirely foolproof, but making SURE will be + // a very slow process that I don't much care for. + + image_id image = load_add_on(path); + // Load the data and code for the Translator into memory + if (image < 0) + return image; + + // Function pointer used to create post R4.5 style translators + BTranslator *(*pMakeNthTranslator)(int32 n,image_id you,uint32 flags,...); + + status_t err = get_image_symbol(image, "make_nth_translator", + B_SYMBOL_TYPE_TEXT, (void **)&pMakeNthTranslator); + if (!err) { + // If the translator add-on supports the post R4.5 + // translator creation mechanism + + BTranslator *ptran = NULL; + // WARNING: This code assumes that the ref count on the + // BTranslators from MakeNth... begin at 1!!! + // I NEED TO WRITE CODE TO TEST WHAT THE REF COUNT FOR + // THESE BTRANSLATORS START AS!!!! + for (int32 n = 0; (ptran = pMakeNthTranslator(n, image, 0)); n++) + AddTranslatorToList(ptran, path, image, false); + + return B_NO_ERROR; + + } else { + // If the translator add-on is in the R4.0 / R4.5 format + translator_data trandata; + + // find all the symbols + err = get_image_symbol(image, "translatorName", B_SYMBOL_TYPE_DATA, + (void **)&trandata.translatorName); + if (!err && get_image_symbol(image, "translatorInfo", + B_SYMBOL_TYPE_DATA, (void **)&trandata.translatorInfo)) + trandata.translatorInfo = NULL; + long * vptr = NULL; + if (!err) + err = get_image_symbol(image, "translatorVersion", + B_SYMBOL_TYPE_DATA, (void **)&vptr); + if (!err && (vptr != NULL)) + trandata.translatorVersion = *vptr; + if (!err && get_image_symbol(image, "inputFormats", + B_SYMBOL_TYPE_DATA, (void **)&trandata.inputFormats)) + trandata.inputFormats = NULL; + if (!err && get_image_symbol(image, "outputFormats", + B_SYMBOL_TYPE_DATA, (void **)&trandata.outputFormats)) + trandata.outputFormats = NULL; + if (!err) + err = get_image_symbol(image, "Identify", B_SYMBOL_TYPE_TEXT, + (void **)&trandata.Identify); + if (!err) + err = get_image_symbol(image, "Translate", + B_SYMBOL_TYPE_TEXT, (void **)&trandata.Translate); + if (!err && get_image_symbol(image, "MakeConfig", + B_SYMBOL_TYPE_TEXT, (void **)&trandata.MakeConfig)) + trandata.MakeConfig = NULL; + if (!err && get_image_symbol(image, "GetConfigMessage", + B_SYMBOL_TYPE_TEXT, (void **)&trandata.GetConfigMessage)) + trandata.GetConfigMessage = NULL; + + // if add-on is not in the correct format, return with error + if (err) + return err; + + // add this translator to the list + BR4xTranslator *pR4xTran = new BR4xTranslator(&trandata); + AddTranslatorToList(pR4xTran, path, image, false); + // do not call Acquire() on ptran because I want it to be + // deleted the first time Release() is called on it. + + return B_NO_ERROR; + } +} + +// --------------------------------------------------------------- +// LoadDir +// +// Loads all of the translators in the directory path +// +// Preconditions: should only be called inside locked code +// +// Parameters: path, the directory of translators to load +// loadErr, the return code +// nLoaded, number of translators loaded +// +// Postconditions: +// +// Returns: B_FILE_NOT_FOUND, if the path is NULL or invalid +// other errors if LoadTranslator failed +// --------------------------------------------------------------- +void +BTranslatorRoster::LoadDir(const char *path, int32 &loadErr, int32 &nLoaded) +{ + if (!path) { + loadErr = B_FILE_NOT_FOUND; + return; + } + + loadErr = B_OK; + DIR *dir = opendir(path); + if (!dir) { + loadErr = B_FILE_NOT_FOUND; + return; + } + struct dirent *dent; + struct stat stbuf; + char cwd[PATH_MAX] = ""; + while (NULL != (dent = readdir(dir))) { + strcpy(cwd, path); + strcat(cwd, "/"); + strcat(cwd, dent->d_name); + status_t err = stat(cwd, &stbuf); + + if (!err && S_ISREG(stbuf.st_mode) && + strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) { + + err = LoadTranslator(cwd); + if (err == B_OK) + nLoaded++; + else + loadErr = err; + } + } + closedir(dir); +} + +// --------------------------------------------------------------- +// CheckFormats +// +// Function used to determine if hintType and hintMIME can be +// used to find the desired translation_format. +// +// Preconditions: Should only be called from inside locked code +// +// Parameters: inputFormats, the formats check against the hints +// inputFormatsCount, number of items in inputFormats +// hintType, the type this function is looking for +// hintMIME, the MIME type this function is looking +// for +// outFormat, NULL if no suitable translation_format +// from inputFormats was found, not NULL +// if a translation_format matching the +// hints was found +// +// +// Postconditions: +// +// Returns: true, if a determination could be made +// false, if indentification must be done +// --------------------------------------------------------------- +bool +BTranslatorRoster::CheckFormats(const translation_format *inputFormats, + int32 inputFormatsCount, uint32 hintType, const char *hintMIME, + const translation_format **outFormat) +{ + if (!inputFormats || inputFormatsCount <= 0 || !outFormat) + return false; + + *outFormat = NULL; + + // return false if we can't use hints for this module + if (!hintType && !hintMIME) + return false; + + // check for the length of the MIME string, since it may be just a prefix + // so we use strncmp(). + int mlen = 0; + if (hintMIME) + mlen = strlen(hintMIME); + + // scan for suitable format + const translation_format *fmt = inputFormats; + for (int32 i = 0; i < inputFormatsCount && fmt->type; i++, fmt++) { + if ((fmt->type == hintType) || + (hintMIME && mlen && !strncmp(fmt->MIME, hintMIME, mlen))) { + *outFormat = fmt; + return true; + } + } + // the module did export formats, but none matched. + // we return true (uses formats) but set outFormat to NULL + return true; +} + +// --------------------------------------------------------------- +// AddTranslatorToList +// +// Adds a BTranslator based object to the list of translators +// stored by the BTranslatorRoster. +// +// Preconditions: Should only be called inside locked code +// +// Parameters: translator, the translator to add to this object +// +// Postconditions: +// +// Returns: B_BAD_VALUE, if translator is NULL +// B_OK, if not +// --------------------------------------------------------------- +status_t +BTranslatorRoster::AddTranslatorToList(BTranslator *translator) +{ + return AddTranslatorToList(translator, "", -1, true); + // add translator to list with no add-on image to unload, + // and call Acquire() on it +} + +// --------------------------------------------------------------- +// AddTranslatorToList +// +// Adds a BTranslator based object to the list of translators +// stored by the BTranslatorRoster. +// +// Preconditions: Should only be called inside locked code +// +// Parameters: translator, the translator to add to this object +// path, the path the translator was loaded from +// image, the image the translator was loaded from +// acquire, if true Acquire() is called on the +// translator +// +// Postconditions: +// +// Returns: B_BAD_VALUE, if translator is NULL +// B_OK, if not +// --------------------------------------------------------------- +status_t +BTranslatorRoster::AddTranslatorToList(BTranslator *translator, + const char *path, image_id image, bool acquire) +{ + if (!translator || !path) + return B_BAD_VALUE; + + translator_node *pTranNode = new translator_node; + + if (acquire) + pTranNode->translator = translator->Acquire(); + else + pTranNode->translator = translator; + + if (fpTranslators) + pTranNode->id = fpTranslators->id + 1; + else + pTranNode->id = 1; + + pTranNode->path = new char[strlen(path) + 1]; + strcpy(pTranNode->path, path); + pTranNode->image = image; + pTranNode->next = fpTranslators; + fpTranslators = pTranNode; + + return B_OK; +} + +// --------------------------------------------------------------- +// ReservedTranslatorRoster1 +// +// It does nothing! :) Its here only for past/future binary +// compatibility. +// +// Preconditions: +// +// Parameters: +// +// Postconditions: +// +// Returns: +// --------------------------------------------------------------- +void +BTranslatorRoster::ReservedTranslatorRoster1() +{ +} + +// --------------------------------------------------------------- +// ReservedTranslatorRoster2 +// +// It does nothing! :) Its here only for past/future binary +// compatibility. +// +// Preconditions: +// +// Parameters: +// +// Postconditions: +// +// Returns: +// --------------------------------------------------------------- +void +BTranslatorRoster::ReservedTranslatorRoster2() +{ +} + +// --------------------------------------------------------------- +// ReservedTranslatorRoster3 +// +// It does nothing! :) Its here only for past/future binary +// compatibility. +// +// Preconditions: +// +// Parameters: +// +// Postconditions: +// +// Returns: +// --------------------------------------------------------------- +void +BTranslatorRoster::ReservedTranslatorRoster3() +{ +} + +// --------------------------------------------------------------- +// ReservedTranslatorRoster4 +// +// It does nothing! :) Its here only for past/future binary +// compatibility. +// +// Preconditions: +// +// Parameters: +// +// Postconditions: +// +// Returns: +// --------------------------------------------------------------- +void +BTranslatorRoster::ReservedTranslatorRoster4() +{ +} + +// --------------------------------------------------------------- +// ReservedTranslatorRoster5 +// +// It does nothing! :) Its here only for past/future binary +// compatibility. +// +// Preconditions: +// +// Parameters: +// +// Postconditions: +// +// Returns: +// --------------------------------------------------------------- +void +BTranslatorRoster::ReservedTranslatorRoster5() +{ +} + +// --------------------------------------------------------------- +// ReservedTranslatorRoster6 +// +// It does nothing! :) Its here only for past/future binary +// compatibility. +// +// Preconditions: +// +// Parameters: +// +// Postconditions: +// +// Returns: +// --------------------------------------------------------------- +void +BTranslatorRoster::ReservedTranslatorRoster6() +{ +} + diff --git a/src/prefs/Jamfile b/src/prefs/Jamfile new file mode 100644 index 0000000000..860dd93d40 --- /dev/null +++ b/src/prefs/Jamfile @@ -0,0 +1,3 @@ +SubInclude OBOS_TOP sources os kits interface prefs menu ; +SubInclude OBOS_TOP sources os kits interface prefs screen ; +SubInclude OBOS_TOP sources os kits interface prefs workspaces ; diff --git a/src/prefs/appearance/APRMain.cpp b/src/prefs/appearance/APRMain.cpp new file mode 100644 index 0000000000..5672ce51c2 --- /dev/null +++ b/src/prefs/appearance/APRMain.cpp @@ -0,0 +1,23 @@ +#include "APRMain.h" +#include + +APRApplication::APRApplication() + :BApplication("application/x-vnd.obos-Appearance") +{ + BRect rect; + + // This is just the size and location of the window when Show() is called + rect.Set(100,100,580,220); + aprwin=new APRWindow(rect); + aprwin->Show(); +} + +int main(int, char**) +{ + APRApplication myApplication; + + // This function doesn't return until the application quits + myApplication.Run(); + + return(0); +} diff --git a/src/prefs/appearance/APRMain.h b/src/prefs/appearance/APRMain.h new file mode 100644 index 0000000000..31d41eb2b2 --- /dev/null +++ b/src/prefs/appearance/APRMain.h @@ -0,0 +1,14 @@ +#ifndef APR_WORLD_H +#define APR_WORLD_H + +#include +#include "APRWindow.h" + +class APRApplication : public BApplication +{ +public: + APRApplication(); + APRWindow *aprwin; +}; + +#endif diff --git a/src/prefs/appearance/APRView.cpp b/src/prefs/appearance/APRView.cpp new file mode 100644 index 0000000000..18b7879e21 --- /dev/null +++ b/src/prefs/appearance/APRView.cpp @@ -0,0 +1,414 @@ +/* + APRView.cpp: The Appearance app's bulky boy + + Handles all the grunt work. Color settings are stored in a BMessage to + allow for easy transition to and from disk. The messy details are in the + hard-coded strings to translate the enumerated color_which defines to + strings and such, but even those should be easy to maintain. +*/ +#include +#include "APRView.h" +#include "PortLink.h" +#include +#include +#include + +#define SETTINGS_DIR "/boot/home/config/settings/app_server/" + +#define APPLY_SETTINGS 'aply' +#define REVERT_SETTINGS 'rvrt' +#define DEFAULT_SETTINGS 'dflt' +#define TRY_SETTINGS 'trys' + +#define ATTRIBUTE_CHOSEN 'atch' +#define UPDATE_COLOR 'upcl' + +void SetRGBColor(rgb_color *col,uint8 r, uint8 g, uint8 b, uint8 a=255); +void PrintRGBColor(rgb_color col); + +APRView::APRView(BRect frame, const char *name, int32 resize, int32 flags) + :BView(frame,name,resize,flags) +{ + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + + // Set up list of color attributes + attrlist=new BListView(BRect(10,10,110,110),"AttributeList"); + + scrollview=new BScrollView("ScrollView",attrlist, B_FOLLOW_LEFT | + B_FOLLOW_TOP, 0, false, true); + AddChild(scrollview); + scrollview->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + + attrlist->SetSelectionMessage(new BMessage(ATTRIBUTE_CHOSEN)); + + attrlist->AddItem(new BStringItem("Window Background")); + attrlist->AddItem(new BStringItem("Menu Background")); + attrlist->AddItem(new BStringItem("Selected Menu Background")); + attrlist->AddItem(new BStringItem("Menu Text")); + attrlist->AddItem(new BStringItem("Selected Menu Text")); + attrlist->AddItem(new BStringItem("Window Tab")); + attrlist->AddItem(new BStringItem("Keyboard Navigation")); + attrlist->AddItem(new BStringItem("Desktop Color")); + + picker=new BColorControl(BPoint(scrollview->Frame().right+20,scrollview->Frame().top),B_CELLS_32x8,5.0,"Picker", + new BMessage(UPDATE_COLOR)); + AddChild(picker); + + BRect cvrect=picker->Frame(); + cvrect.OffsetBy(picker->Bounds().Width()+10,0); + cvrect.right=Bounds().right-10; + + colorview=new BView(cvrect,"ColorView",B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW); + colorview->SetViewColor(picker->ValueAsColor()); + AddChild(colorview); + + cvrect.Set(0,0,50,25); + cvrect.OffsetBy(picker->Frame().left, + picker->Frame().bottom+20); + + defaults=new BButton(cvrect,"DefaultsButton","Defaults", + new BMessage(DEFAULT_SETTINGS),B_FOLLOW_LEFT |B_FOLLOW_TOP, + B_WILL_DRAW | B_NAVIGABLE); + AddChild(defaults); + + cvrect.OffsetBy(70,0); + revert=new BButton(cvrect,"RevertButton","Revert", + new BMessage(REVERT_SETTINGS),B_FOLLOW_LEFT |B_FOLLOW_TOP, + B_WILL_DRAW | B_NAVIGABLE); + AddChild(revert); + // Eventually we might want to have this disabled at the start and + // enabled when the user makes changes and such. Then again, maybe we won't. +// revert->SetEnabled(false); + + cvrect.OffsetBy(70,0); + try_settings=new BButton(cvrect,"TryButton","Try", + new BMessage(TRY_SETTINGS),B_FOLLOW_LEFT |B_FOLLOW_TOP, + B_WILL_DRAW | B_NAVIGABLE); + AddChild(try_settings); + + // Eventually we might want to have this disabled at the start and + // enabled when the user makes changes and such. Then again, maybe we won't. +// try_settings->SetEnabled(false); + + cvrect.OffsetBy(70,0); + apply=new BButton(cvrect,"ApplyButton","Apply", + new BMessage(APPLY_SETTINGS),B_FOLLOW_LEFT |B_FOLLOW_TOP, + B_WILL_DRAW | B_NAVIGABLE); + AddChild(apply); + + attribute=B_PANEL_BACKGROUND_COLOR; + attrstring="PANEL_BACKGROUND"; + LoadSettings(); + picker->SetValue(GetColorFromMessage(&settings,attrstring.String())); + +} + +APRView::~APRView(void) +{ +} + +void APRView::AttachedToWindow(void) +{ + picker->SetTarget(this); + attrlist->SetTarget(this); + apply->SetTarget(this); + defaults->SetTarget(this); + try_settings->SetTarget(this); + revert->SetTarget(this); + attrlist->Select(0); +} + +void APRView::MessageReceived(BMessage *msg) +{ + switch(msg->what) + { + case UPDATE_COLOR: + { + rgb_color col=picker->ValueAsColor(); + + colorview->SetViewColor(col); + colorview->Invalidate(); + + // Update current attribute here + settings.ReplaceData(attrstring.String(),(type_code)'RGBC', + &col,sizeof(rgb_color)); + break; + } + case ATTRIBUTE_CHOSEN: + { + attribute=SelectionToAttribute(attrlist->CurrentSelection()); + attrstring=SelectionToString(attrlist->CurrentSelection()); + + rgb_color col=GetColorFromMessage(&settings,attrstring.String(),0); + picker->SetValue(col); + colorview->SetViewColor(col); + colorview->Invalidate(); + break; + } + case APPLY_SETTINGS: + { + SaveSettings(); + NotifyServer(); + break; + } + case TRY_SETTINGS: + { + // Tell server to apply settings here without saving them. + // Theoretically, the user can set this temporarily and keep it + // until the next boot. + NotifyServer(); + break; + } + case REVERT_SETTINGS: + { + LoadSettings(); + rgb_color col=GetColorFromMessage(&settings,attrstring.String(),0); + picker->SetValue(col); + colorview->SetViewColor(col); + colorview->Invalidate(); + break; + } + case DEFAULT_SETTINGS: + { + SetDefaults(); + rgb_color col=GetColorFromMessage(&settings,attrstring.String(),0); + picker->SetValue(col); + colorview->SetViewColor(col); + colorview->Invalidate(); + break; + } + default: + BView::MessageReceived(msg); + break; + } +} + +color_which APRView::SelectionToAttribute(int32 index) +{ + switch(index) + { + case 0: + return B_PANEL_BACKGROUND_COLOR; + break; // not necessary, but do it anyway. ;) + case 1: + return B_MENU_BACKGROUND_COLOR; + break; // not necessary, but do it anyway. ;) + case 2: + return B_MENU_SELECTION_BACKGROUND_COLOR; + break; // not necessary, but do it anyway. ;) + case 3: + return B_MENU_ITEM_TEXT_COLOR; + break; // not necessary, but do it anyway. ;) + case 4: + return B_MENU_SELECTED_ITEM_TEXT_COLOR; + break; // not necessary, but do it anyway. ;) + case 5: + return B_WINDOW_TAB_COLOR; + break; // not necessary, but do it anyway. ;) + case 6: + return B_KEYBOARD_NAVIGATION_COLOR; + break; // not necessary, but do it anyway. ;) + default: + return B_DESKTOP_COLOR; + break; // not necessary, but do it anyway. ;) + } + +} + +void APRView::SaveSettings(void) +{ + BString path(SETTINGS_DIR); + path+="SystemColors"; + printf("%s\n",path.String()); + BFile file(path.String(),B_READ_WRITE|B_CREATE_FILE|B_ERASE_FILE); + + settings.Flatten(&file); +} + +void APRView::LoadSettings(void) +{ + settings.MakeEmpty(); + + BDirectory dir,newdir; + if(dir.SetTo(SETTINGS_DIR)==B_ENTRY_NOT_FOUND) + create_directory(SETTINGS_DIR,0777); + + BString path(SETTINGS_DIR); + path+="SystemColors"; + BFile file(path.String(),B_READ_ONLY); + + if(file.InitCheck()==B_OK) + { + if(settings.Unflatten(&file)==B_OK) + { + // Get the color for the current attribute here + return; + } + printf("Error unflattening settings file %s\n",path.String()); + } + + // If we get this far, we have encountered an error, so reset the settings + // to the defaults + SetDefaults(); +} + +void APRView::SetDefaults(void) +{ + settings.MakeEmpty(); + rgb_color col={216,216,216,255}; + settings.AddData("PANEL_BACKGROUND",(type_code)'RGBC',&col,sizeof(rgb_color)); + + SetRGBColor(&col,219,219,219,0); + settings.AddData("MENU_BACKGROUND",(type_code)'RGBC',&col,sizeof(rgb_color)); + + SetRGBColor(&col,115,120,184); + settings.AddData("MENU_SELECTION_BACKGROUND",(type_code)'RGBC',&col,sizeof(rgb_color)); + + SetRGBColor(&col,0,0,0); + settings.AddData("MENU_ITEM_TEXT",(type_code)'RGBC',&col,sizeof(rgb_color)); + + SetRGBColor(&col,255,255,255); + settings.AddData("MENU_SELECTED_ITEM_TEXT",(type_code)'RGBC',&col,sizeof(rgb_color)); + + SetRGBColor(&col,255,203,0); + settings.AddData("WINDOW_TAB",(type_code)'RGBC',&col,sizeof(rgb_color)); + + SetRGBColor(&col,0,0,229); + settings.AddData("KEYBOARD_NAVIGATION",(type_code)'RGBC',&col,sizeof(rgb_color)); + + SetRGBColor(&col,51,102,160); + settings.AddData("DESKTOP",(type_code)'RGBC',&col,sizeof(rgb_color)); +} + +void APRView::NotifyServer(void) +{ + // Send a message to the app_server with the settings which we have. + // While it might be worthwhile to someday have a separate protocol for + // updating just one color, for now, we just need something to get things + // done. Extract all the colors from the settings BMessage, attach them + // to a PortLink message and fire it off to the server. + + // Name taken from ServerProtocol.h + port_id serverport=find_port("OBappserver"); + + if(serverport==B_NAME_NOT_FOUND) + return; + + PortLink *pl=new PortLink(serverport); + + // 'suic'==SET_UI_COLORS message from ServerProtocol.h + pl->SetOpCode('suic'); + + rgb_color col; + col=GetColorFromMessage(&settings,"PANEL_BACKGROUND"); + pl->Attach(&col,sizeof(rgb_color)); + col=GetColorFromMessage(&settings,"MENU_BACKGROUND"); + pl->Attach(&col,sizeof(rgb_color)); + col=GetColorFromMessage(&settings,"MENU_SELECTION_BACKGROUND"); + pl->Attach(&col,sizeof(rgb_color)); + col=GetColorFromMessage(&settings,"MENU_ITEM_TEXT"); + pl->Attach(&col,sizeof(rgb_color)); + col=GetColorFromMessage(&settings,"MENU_SELECTED_ITEM_TEXT"); + pl->Attach(&col,sizeof(rgb_color)); + col=GetColorFromMessage(&settings,"WINDOW_TAB"); + pl->Attach(&col,sizeof(rgb_color)); + col=GetColorFromMessage(&settings,"KEYBOARD_NAVIGATION"); + pl->Attach(&col,sizeof(rgb_color)); + col=GetColorFromMessage(&settings,"DESKTOP_COLOR"); + pl->Attach(&col,sizeof(rgb_color)); + + pl->Flush(); + delete pl; +} + +rgb_color APRView::GetColorFromMessage(BMessage *msg, const char *name, int32 index=0) +{ + // Simple function to do the dirty work of getting an rgb_color from + // a message + rgb_color *col,rcolor={0,0,0,0}; + uint8 *ptr; + ssize_t size; + + if(msg->FindData(name,(type_code)'RGBC',index,(const void**)&ptr,&size)==B_OK) + { + col=(rgb_color*)ptr; + rcolor=*col; + } + return rcolor; +} + +const char *APRView::AttributeToString(color_which attr) +{ + switch(attr) + { + case B_PANEL_BACKGROUND_COLOR: + return "PANEL_BACKGROUND"; + break; + case B_MENU_BACKGROUND_COLOR: + return "MENU_BACKGROUND"; + break; + case B_MENU_SELECTION_BACKGROUND_COLOR: + return "MENU_SELECTION_BACKGROUND"; + break; + case B_MENU_ITEM_TEXT_COLOR: + return "MENU_ITEM_TEXT"; + break; + case B_MENU_SELECTED_ITEM_TEXT_COLOR: + return "MENU_SELECTED_ITEM_TEXT"; + break; + case B_WINDOW_TAB_COLOR: + return "WINDOW_TAB"; + break; + case B_KEYBOARD_NAVIGATION_COLOR: + return "KEYBOARD_NAVIGATION"; + break; + default: + return "DESKTOP_COLOR"; + break; + } +} + +const char *APRView::SelectionToString(int32 index) +{ + switch(index) + { + case 0: + return "PANEL_BACKGROUND"; + break; + case 1: + return "MENU_BACKGROUND"; + break; + case 2: + return "MENU_SELECTION_BACKGROUND"; + break; + case 3: + return "MENU_ITEM_TEXT"; + break; + case 4: + return "MENU_SELECTED_ITEM_TEXT"; + break; + case 5: + return "WINDOW_TAB"; + break; + case 6: + return "KEYBOARD_NAVIGATION"; + break; + default: + return "DESKTOP_COLOR"; + break; + } +} + +void SetRGBColor(rgb_color *col,uint8 r, uint8 g, uint8 b, uint8 a=255) +{ + col->red=r; + col->green=g; + col->blue=b; + col->alpha=a; +} + +void PrintRGBColor(rgb_color col) +{ + printf("RGB Color (%d,%d,%d,%d)\n",col.red,col.green,col.blue,col.alpha); +} + diff --git a/src/prefs/appearance/APRView.h b/src/prefs/appearance/APRView.h new file mode 100644 index 0000000000..da12ade6bf --- /dev/null +++ b/src/prefs/appearance/APRView.h @@ -0,0 +1,40 @@ +#ifndef APR_VIEW_H_ +#define APR_VIEW_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class APRView : public BView +{ +public: + APRView(BRect frame, const char *name, int32 resize, int32 flags); + ~APRView(void); + void AttachedToWindow(void); + void MessageReceived(BMessage *msg); + color_which SelectionToAttribute(int32 index); + const char *AttributeToString(color_which attr); + const char *SelectionToString(int32 index); + void SaveSettings(void); + void LoadSettings(void); + void SetDefaults(void); + void NotifyServer(void); + rgb_color GetColorFromMessage(BMessage *msg, const char *name, int32 index=0); + + BColorControl *picker; + BButton *apply,*revert,*defaults,*try_settings; + BListView *attrlist; + BView *colorview; + color_which attribute; + BMessage settings; + BString attrstring; + BScrollView *scrollview; +}; + +#endif diff --git a/src/prefs/appearance/APRWindow.cpp b/src/prefs/appearance/APRWindow.cpp new file mode 100644 index 0000000000..7a7da4c47a --- /dev/null +++ b/src/prefs/appearance/APRWindow.cpp @@ -0,0 +1,15 @@ +#include "APRWindow.h" +#include "APRView.h" + +APRWindow::APRWindow(BRect frame) + : BWindow(frame, "Appearance", B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE ) +{ + APRView *v=new APRView(Bounds(),"AppearanceView",B_FOLLOW_ALL, B_WILL_DRAW); + AddChild(v); +} + +bool APRWindow::QuitRequested() +{ + be_app->PostMessage(B_QUIT_REQUESTED); + return(true); +} diff --git a/src/prefs/appearance/APRWindow.h b/src/prefs/appearance/APRWindow.h new file mode 100644 index 0000000000..19a469509f --- /dev/null +++ b/src/prefs/appearance/APRWindow.h @@ -0,0 +1,15 @@ +#ifndef APR_WINDOW_H +#define APR_WINDOW_H + +#include +#include +#include + +class APRWindow : public BWindow +{ +public: + APRWindow(BRect frame); + virtual bool QuitRequested(); +}; + +#endif diff --git a/src/prefs/appearance/PortLink.cpp b/src/prefs/appearance/PortLink.cpp new file mode 100644 index 0000000000..8fba724569 --- /dev/null +++ b/src/prefs/appearance/PortLink.cpp @@ -0,0 +1,438 @@ +/* + PortLink.cpp: + A helper class for port-based messaging + +------------------------------------------------------------------------ +How it works: + The class utilizes a fixed-size array of PortLinkData object pointers. When +data is attached, a new PortLinkData object is allocated and a copy of the +passed data is created inside it. When the time comes for the message to be sent, +the data is pieced together into a flattened array and written to the port. +------------------------------------------------------------------------ +Data members: + +*attachments[] - fixed-size array of pointers used to hold the attached data +opcode - message value which is sent along with any data +target - port to which the message is sent when Flush() is called +replyport - port used with synchronous messaging - FlushWithReply() +bufferlength - total bytes taken up by attachments +num_attachments - internal variable which is used to track which "slot" + will be the next one to receive an attachment object +*/ + +#include "PortLink.h" +#include +#include +#include + +//#define PLDEBUG + +// Internal data storage class for holding attached data whilst it is waiting +// to be Flattened() and then Flushed(). There is no need for this to be called outside +// the PortLink class. +class PortLinkData +{ +public: + PortLinkData(void); + ~PortLinkData(void); + bool Set(void *data, size_t size); + char *buffer; + size_t buffersize; +}; + +PortLink::PortLink(port_id port) +{ + // For this class to be useful (and to prevent a lot of init problems) + // we require a port in the constructor + target=port; + + // We start out without any data attached to the port message + num_attachments=0; + opcode=0; + bufferlength=0; + replyport=create_port(30,"PortLink reply port"); +} + +PortLink::~PortLink(void) +{ + // If, for some odd reason, this is deleted with something attached, + // free the memory used by the attachments. We do not flush the queue + // because the port may no longer be valid in cases such as the app + // is in the process of quitting + MakeEmpty(); +} + +void PortLink::SetOpCode(int32 code) +{ + // Sets the message code. This does not change once the message is sent. + // Another call to SetOpCode() is required for such things. + opcode=code; +} + +void PortLink::SetPort(port_id port) +{ + // Sets the target port. While not necessary in most uses, this exists + // mostly to prevent flexibility problems + target=port; +} + +port_id PortLink::GetPort(void) +{ + // Simply returns the port at which the object is pointed. + return target; +} + +void PortLink::Flush(bigtime_t timeout=B_INFINITE_TIMEOUT) +{ + // Fires a message off to the target, complete with attachments. NOTE: + // the recipient must delete all attachments, being the PortLink object assumes + // no responsiblity for the attachments once the message is sent. + int8 *msgbuffer; + int32 size; + + if(num_attachments>0) + { + FlattenData(&msgbuffer,&size); + + // Dump message to port, reset attachments, and clean up + if(timeout!=B_INFINITE_TIMEOUT) + write_port_etc(target,opcode,msgbuffer,size,B_TIMEOUT, timeout); + else + write_port(target,opcode,msgbuffer,size); + MakeEmpty(); + } + else + { + if(timeout!=B_INFINITE_TIMEOUT) + write_port_etc(target,opcode,NULL,0,B_TIMEOUT, timeout); + else + write_port(target,opcode,NULL,0); + } +} + +int8* PortLink::FlushWithReply(int32 *code, status_t *status, ssize_t *buffersize, bigtime_t timeout=B_INFINITE_TIMEOUT) +{ + // Fires a message to the target and then waits for a reply. The target will + // receive a message with the first item being the port_id to reply to. + // NOTE: like Flush(), any attached data must be deleted. + + // Effectively, an Attach() call inlined for changes + + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + { + *status=B_ERROR; + return NULL; + } + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&replyport,sizeof(port_id))) + { + bufferlength+=sizeof(port_id); + } + else + { + delete pld; + *status=B_ERROR; + return NULL; + } + + // Flatten() inlined to make some necessary changes + int8 *buffer=new int8[bufferlength]; + int8 *bufferindex=buffer; + size_t size=0; + + // attach our port_id first + memcpy(bufferindex, pld->buffer, pld->buffersize); + bufferindex += pld->buffersize; + size+=pld->buffersize; + + // attach everything else + for(int i=0;ibuffer, pld->buffersize); + bufferindex += pld->buffersize; + size+=pld->buffersize; + } + + // Flush the thing....FOOSH! :P + write_port(target,opcode,buffer,size); + MakeEmpty(); + delete buffer; + + // Now we wait for the reply + if(timeout==B_INFINITE_TIMEOUT) + { + *buffersize=port_buffer_size(replyport); + if(*buffersize>0) + buffer=(int8*)new int8[*buffersize]; + read_port(replyport,code, buffer, *buffersize); + } + else + { + *buffersize=port_buffer_size_etc(replyport,0,timeout); + if(*buffersize==B_TIMED_OUT) + { + *status=*buffersize; + return NULL; + } + if(*buffersize>0) + buffer=(int8*)new int8[*buffersize]; + read_port(replyport,code, buffer, *buffersize); + } + + // We got this far, so we apparently have some data + *status=B_OK; + return buffer; +} + +void PortLink::Attach(void *data, size_t size) +{ + // This is the member called to attach data to a message. Attachments are + // treated to be in 'Append' mode, tacking on each attached piece of data + // to the end of the list. + + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + if(size==0) + return; + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +// These functions were added for a major convenience in passing common types +// Eventually, I'd like to templatize these, but for now, this'll do + +void PortLink::Attach(int32 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int32); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(int16 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int16); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(int8 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int8); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(float data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(float); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(bool data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(bool); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(BRect data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(BRect); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(BPoint data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(BPoint); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::FlattenData(int8 **buffer,int32 *size) +{ + // This function is where all the magic happens, but it is strictly internal. + // It iterates through each PortLinkData object and copies it to the main buffer + // which ends up, ultimately, being written to the PortLink's target port. + + // skip if there aree no attachments + if(bufferlength<1) + return; + + *buffer=new int8[bufferlength]; + int8 *bufferindex=*buffer; + PortLinkData *pld; + *size=0; + + for(int i=0;ibuffer, pld->buffersize); + bufferindex += pld->buffersize; + *size+=pld->buffersize; + } +} + +void PortLink::MakeEmpty(void) +{ + // Nukes all the attachments currently held by the PortLink class + if(num_attachments!=0) + { + for(int i=0; i0) + free(buffer); +} + +bool PortLinkData::Set(void *data, size_t size) +{ + // Function copies the passed to the internal buffers for storage + if(size>0 && buffersize==0 && data!=NULL) + { + buffer=(char *)malloc(size); + if(buffer==NULL) + return false; + memcpy(buffer, data, size); + buffersize=size; + return true; + } + return false; +} diff --git a/src/prefs/appearance/PortLink.h b/src/prefs/appearance/PortLink.h new file mode 100644 index 0000000000..9f5432daab --- /dev/null +++ b/src/prefs/appearance/PortLink.h @@ -0,0 +1,43 @@ +#ifndef _PORTLINK_H_ +#define _PORTLINK_H_ + +#include +#include +#include +#include + +#ifndef _PORTLINK_BUFFERSIZE +#define _PORTLINK_MAX_ATTACHMENTS 50 +#endif + +class PortLinkData; + +class PortLink +{ +public: + PortLink(port_id port); + ~PortLink(void); + void SetOpCode(int32 code); + void SetPort(port_id port); + port_id GetPort(void); + void Flush(bigtime_t timeout=B_INFINITE_TIMEOUT); + int8* FlushWithReply(int32 *code, status_t *status, ssize_t *buffersize, + bigtime_t timeout=B_INFINITE_TIMEOUT); + void Attach(void *data, size_t size); + void Attach(int32 data); + void Attach(int16 data); + void Attach(int8 data); + void Attach(float data); + void Attach(bool data); + void Attach(BRect data); + void Attach(BPoint data); + void MakeEmpty(void); +protected: + void FlattenData(int8 **buffer,int32 *size); + port_id target, replyport; + int32 opcode, bufferlength; + int num_attachments; + PortLinkData *attachments[_PORTLINK_MAX_ATTACHMENTS]; +}; + +#endif \ No newline at end of file diff --git a/src/prefs/datatranslations/DataTranslations.cpp b/src/prefs/datatranslations/DataTranslations.cpp new file mode 100644 index 0000000000..f76602f3d7 --- /dev/null +++ b/src/prefs/datatranslations/DataTranslations.cpp @@ -0,0 +1,196 @@ +/* + * DataTranslations.cpp + * DataTranslations mccall@digitalparadise.co.uk + * + */ + +#include +#include + +#include "DataTranslations.h" +#include "DataTranslationsWindow.h" +#include "DataTranslationsSettings.h" +#include "DataTranslationsMessages.h" + +const char DataTranslationsApplication::kDataTranslationsApplicationSig[] = "application/x-vnd.OpenBeOS-prefs-translations"; + +int main(int, char**) +{ + DataTranslationsApplication myApplication; + + myApplication.Run(); + + return(0); +} + +DataTranslationsApplication::DataTranslationsApplication() + :BApplication(kDataTranslationsApplicationSig) +{ + + DataTranslationsWindow *window; + + fSettings = new DataTranslationsSettings(); + + window = new DataTranslationsWindow(); + +} + + +/* Unused. +void +DataTranslationsApplication::MessageReceived(BMessage *message) +{ + switch(message->what) { + case ERROR_DETECTED: + { + BAlert *errorAlert = new BAlert("Error", "Unknown Error occured","OK",NULL,NULL,B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_WARNING_ALERT); + errorAlert->Go(); + be_app->PostMessage(B_QUIT_REQUESTED); + } + break; + default: + BApplication::MessageReceived(message); + break; + } +} +*/ +void +DataTranslationsApplication::SetWindowCorner(BPoint corner) +{ + fSettings->SetWindowCorner(corner); +} + +void +DataTranslationsApplication::AboutRequested(void) +{ + (new BAlert("", "... written by Oliver Siebenmarck", "Cool!"))->Go(); + return; +} + +DataTranslationsApplication::~DataTranslationsApplication() +{ + delete fSettings; +} + +void DataTranslationsApplication::Install_Done() +{ + (new BAlert("", "You have to quit and restart running applications\nfor the installed Translators to be available in them.", "OK"))->Go(); + // aWindow->Install_Done = true; + return; +} + +void DataTranslationsApplication::RefsReceived(BMessage *message) +{ + + uint32 type; + int32 count; + entry_ref ref; + BPath path; + BString newfile; + + char e_name[B_FILE_NAME_LENGTH]; + char mbuf[256]; + + + message->GetInfo("refs", &type, &count); + if ( type != B_REF_TYPE ) return; + + + if ( message->FindRef("refs", &ref) == B_OK ) + { + BEntry entry(&ref, true); + entry.GetName(e_name); + + if ( entry.IsFile() && entry.GetPath(&path)==B_OK) + { + BNode node (&entry); + BNodeInfo info (&node); + info.GetType (mbuf); + string.SetTo(mbuf); + + if (string.FindFirst("application/x-vnd.Be-elfexecutable") != B_ERROR ) + { + BDirectory dirt("/boot/home/config/add-ons/Translators/"); + newfile.SetTo("/boot/home/config/add-ons/Translators/"); + newfile << e_name; // Newfile with full path. + + // Find out wether we need to copy it + string.SetTo(""); + string << "The item '" << e_name << "' is now copied into the right place.\nWhat do you want to do with the original?"; + BAlert *keep = new BAlert("keep", string.String() , "Remove", "Keep"); + keep->SetShortcut(1, B_ESCAPE); + if (keep->Go() == 0) + moveit = true; + + if (moveit) // Just a quick move + { + if (dirt.Contains(newfile.String())) + { + string.SetTo(""); + string << "An item named '" << e_name <<"' already is in the \nTranslators folder"; + BAlert *myAlert = new BAlert("title", string.String() , "Overwrite", "Stop"); + myAlert->SetShortcut(1, B_ESCAPE); + + if (myAlert->Go() != 0) + return; + // File exists, we are still here. Kill it. + BEntry dele; + dirt.FindEntry(e_name, &dele); + dele.Remove(); + } + entry.MoveTo(&dirt); // Move it. + Install_Done(); // Installation done + return; + } + + if (dirt.Contains(newfile.String())) + { + // File exists, What are we supposed to do now (Overwrite/_Stopp_?) + string.SetTo(""); + string << "An item named '" << e_name <<"' already is in the \nTranslators folder"; + BAlert *myAlert = new BAlert("title", string.String() , "Overwrite", "Stop"); + myAlert->SetShortcut(1, B_ESCAPE); + + if (myAlert->Go() != 0) + return; + } + + string.SetTo(path.Path()); // Fullpath+Filename + + BString + command = "copyattr -d -r "; + command << string.String() << " " << newfile.String(); // Prepare Copy + + system(command.String()); // Execute copy command + + string.SetTo(""); + string << "Filename: " << e_name << "\nPath: " << path.Path() ; + + // The new Translator has been installed by now. + // And done we are + Install_Done(); + return; + } + else + { + // Not a Translator + no_trans(e_name); + } + } + else + { + // Not even a file... + no_trans(e_name); + } + } +} + +void DataTranslationsApplication::no_trans(char item_name[B_FILE_NAME_LENGTH]) +{ + BString text; + text.SetTo("The item '"); + text << item_name << "' does not appear to be a Translator and will not be installed"; + (new BAlert("", text.String(), "Stop"))->Go(); + return; +} + diff --git a/src/prefs/datatranslations/DataTranslations.h b/src/prefs/datatranslations/DataTranslations.h new file mode 100644 index 0000000000..f981449208 --- /dev/null +++ b/src/prefs/datatranslations/DataTranslations.h @@ -0,0 +1,41 @@ +#ifndef DATA_TRANSLATIONS_H +#define DATA_TRANSLATIONS_H + +#include +#include +#include + +#include + +#include "DataTranslationsWindow.h" +#include "DataTranslationsView.h" +#include "DataTranslationsSettings.h" + +class DataTranslationsApplication : public BApplication +{ +public: + DataTranslationsApplication(); + virtual ~DataTranslationsApplication(); + + // void MessageReceived(BMessage *message); + virtual void RefsReceived(BMessage *message); + BPoint WindowCorner() const {return fSettings->WindowCorner(); } + void SetWindowCorner(BPoint corner); + + void AboutRequested(void); + +private: + void Install_Done(); + + static const char kDataTranslationsApplicationSig[]; + + DataTranslationsSettings *fSettings; + + // Tell User our installation is done + void no_trans(char item_name[B_FILE_NAME_LENGTH]); + // Tell User he didn´t drop a translator + bool overwrite, moveit; + BString string; +}; + +#endif \ No newline at end of file diff --git a/src/prefs/datatranslations/DataTranslations.rsrc b/src/prefs/datatranslations/DataTranslations.rsrc new file mode 100644 index 0000000000..770404f2dc Binary files /dev/null and b/src/prefs/datatranslations/DataTranslations.rsrc differ diff --git a/src/prefs/datatranslations/DataTranslationsMessages.h b/src/prefs/datatranslations/DataTranslationsMessages.h new file mode 100644 index 0000000000..bf277326b6 --- /dev/null +++ b/src/prefs/datatranslations/DataTranslationsMessages.h @@ -0,0 +1,15 @@ +/* + + DataTranslationsMessages.h + +*/ + +#ifndef DATA_TRANSLATIONS_MESSAGES_H +#define DATA_TRANSLATIONS_MESSAGES_H + +#define BUTTON_MSG 'PRES' + +const uint32 SEL_CHANGE = 'SEch'; +const uint32 ERROR_DETECTED = 'ERor'; + +#endif \ No newline at end of file diff --git a/src/prefs/datatranslations/DataTranslationsSettings.cpp b/src/prefs/datatranslations/DataTranslationsSettings.cpp new file mode 100644 index 0000000000..59a35afc2d --- /dev/null +++ b/src/prefs/datatranslations/DataTranslationsSettings.cpp @@ -0,0 +1,68 @@ +/* + * DataTranslationsSettings.cpp + * DataTranslations Oliver Siebenmarck + * + */ + +#include +#include +#include +#include +#include +#include + +#include "DataTranslationsSettings.h" +#include "DataTranslationsMessages.h" + +const char DataTranslationsSettings::kDataTranslationsSettingsFile[] = "Translation Settings"; + +DataTranslationsSettings::DataTranslationsSettings() +{ + BPath path; + + if (find_directory(B_USER_SETTINGS_DIRECTORY,&path) == B_OK) { + path.Append(kDataTranslationsSettingsFile); + BFile file(path.Path(), B_READ_ONLY); + if (file.InitCheck() == B_OK) { + // Now read in the data + file.Seek(-8,SEEK_END); // Skip over the first 497 bytes to just the window + // position. + if (file.Read(&fCorner, sizeof(BPoint)) != sizeof(BPoint)) { + fCorner.x=50; + fCorner.y=50; + }; + } + else { + fCorner.x=50; + fCorner.y=50; + } + } + else + be_app->PostMessage(ERROR_DETECTED); + + fCorner.PrintToStream(); +} + +DataTranslationsSettings::~DataTranslationsSettings() +{ + BPath path; + + if (find_directory(B_USER_SETTINGS_DIRECTORY,&path) < B_OK) + return; + + path.Append(kDataTranslationsSettingsFile); + + BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE); + if (file.InitCheck() == B_OK) { + file.Seek(-8,SEEK_END); // Skip over the first 497 bytes to just the window + // position. + fCorner.PrintToStream(); + file.Write(&fCorner, sizeof(BPoint)); + } +} + +void +DataTranslationsSettings::SetWindowCorner(BPoint corner) +{ + fCorner=corner; +} \ No newline at end of file diff --git a/src/prefs/datatranslations/DataTranslationsSettings.h b/src/prefs/datatranslations/DataTranslationsSettings.h new file mode 100644 index 0000000000..7ae5353547 --- /dev/null +++ b/src/prefs/datatranslations/DataTranslationsSettings.h @@ -0,0 +1,17 @@ +#ifndef DATA_TRANSLATIONS_SETTINGS_H_ +#define DATA_TRANSLATIONS_SETTINGS_H_ + +class DataTranslationsSettings{ +public : + DataTranslationsSettings(); + ~DataTranslationsSettings(); + + BPoint WindowCorner() const { return fCorner; } + void SetWindowCorner(BPoint corner); + +private: + static const char kDataTranslationsSettingsFile[]; + BPoint fCorner; +}; + +#endif \ No newline at end of file diff --git a/src/prefs/datatranslations/DataTranslationsView.cpp b/src/prefs/datatranslations/DataTranslationsView.cpp new file mode 100644 index 0000000000..1f09ea45d6 --- /dev/null +++ b/src/prefs/datatranslations/DataTranslationsView.cpp @@ -0,0 +1,65 @@ +/* + + DataTranslationsView.cpp + +*/ + +#ifndef _APPLICATION_H +#include +#endif + +#include "DataTranslationsView.h" + + +DataTranslationsView::DataTranslationsView(BRect rect, const char *name, list_view_type type = B_SINGLE_SELECTION_LIST) : + BListView(rect, name, B_SINGLE_SELECTION_LIST) +{ + + messagerunner = NULL; + SetViewColor(217,217,217); +} + +void DataTranslationsView::MessageReceived(BMessage *message) +{ + + uint32 type; + int32 count; + + switch (message->what) { + case B_SIMPLE_DATA: + message->GetInfo("refs", &type, &count); + if ( count>0 && type == B_REF_TYPE ) + { + message->what = B_REFS_RECEIVED; + be_app->PostMessage(message); + Invalidate(); + } + break; + default: + BView::MessageReceived(message); + break; + } +} + +void DataTranslationsView::MouseMoved(BPoint point, uint32 transit, const BMessage *msg) +{ + if ((transit == B_ENTERED_VIEW) && (msg != NULL)) + { + BRect x( 0, 0, 110, 278); + SetHighColor(220,0,0); + SetPenSize(4); + StrokeRect(x); + SetHighColor(0,0,0); + } + if ((transit == B_EXITED_VIEW) && (msg != NULL)) + { + Invalidate(); + } + return; +} + + +DataTranslationsView::~DataTranslationsView() +{ + if (messagerunner != NULL) delete messagerunner; +} \ No newline at end of file diff --git a/src/prefs/datatranslations/DataTranslationsView.h b/src/prefs/datatranslations/DataTranslationsView.h new file mode 100644 index 0000000000..ee152d410f --- /dev/null +++ b/src/prefs/datatranslations/DataTranslationsView.h @@ -0,0 +1,31 @@ +/* + * + * DataTranslationsView.h + * + * by Oliver Siebenmarck +*/ + +#ifndef DATA_TRANSLATIONS_VIEW_H +#define DATA_TRANSLATIONS_VIEW_H + +#include +#include +#include + + +class DataTranslationsView : public BListView { + public: + DataTranslationsView(BRect rect, + const char *name, list_view_type type = B_SINGLE_SELECTION_LIST ); + + ~DataTranslationsView(); + void MessageReceived(BMessage *message); + virtual void MouseMoved(BPoint point, uint32 transit, const BMessage *msg); + + private: + + + BMessageRunner *messagerunner; +}; + +#endif diff --git a/src/prefs/datatranslations/DataTranslationsWindow.cpp b/src/prefs/datatranslations/DataTranslationsWindow.cpp new file mode 100644 index 0000000000..e5f95137de --- /dev/null +++ b/src/prefs/datatranslations/DataTranslationsWindow.cpp @@ -0,0 +1,279 @@ +/* + * DataTranslationsWindow.cpp + * + */ + +#include +#include +#include + + +#include "DataTranslationsMessages.h" +#include "DataTranslationsWindow.h" +#include "DataTranslations.h" + +#define DATA_TRANSLATIONS_WINDOW_RIGHT 400 +#define DATA_TRANSLATIONS_WINDOW_BOTTOM 300 + +DataTranslationsWindow::DataTranslationsWindow() + : BWindow(BRect(0,0,DATA_TRANSLATIONS_WINDOW_RIGHT,DATA_TRANSLATIONS_WINDOW_BOTTOM), "DataTranslations", B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE ) +{ + BScreen screen; + + MoveTo(dynamic_cast(be_app)->WindowCorner()); + + // Code to make sure that the window doesn't get drawn off screen... + if (!(screen.Frame().right >= Frame().right && screen.Frame().bottom >= Frame().bottom)) + MoveTo((screen.Frame().right-Bounds().right)*.5,(screen.Frame().bottom-Bounds().bottom)*.5); + // above does not work correctly....have to work on it. + + BuildView(); + Show(); + +} + + +// Reads the installed translators and adds them to our BListView +int DataTranslationsWindow::WriteTrans() +{ + BTranslatorRoster *roster = BTranslatorRoster::Default(); + + int32 num_translators, i; + translator_id *translators; + const char *tname, *tinfo; + + int32 tversion; + + // Get all Translators on the system. Gives us the number of translators + // installed in num_translators and a reference to the first one + + roster->GetAllTranslators(&translators, &num_translators); + + for (i=0;iGetTranslatorInfo(translators[i], &tname,&tinfo, &tversion); + liste->AddItem(new BStringItem(tname)); + } + + delete [] translators; // Garbage collection + + return 0; +} + +// Finds a specific translator by it´s id +void DataTranslationsWindow::Trans_by_ID(int32 id) +{ + BTranslatorRoster *roster = BTranslatorRoster::Default(); + + int32 num_translators; + translator_id *translators; + bool has_view; + + has_view = true; + roster->GetAllTranslators(&translators, &num_translators); + + // Getting the first three Infos: Name, Info & Version + roster->GetTranslatorInfo(translators[id], &translator_name,&translator_info, &translator_version); + roster->Archive(&archiv, true); + + rBox->RemoveChild(Konf); + if (roster->MakeConfigurationView( translators[id], new BMessage() , &Konf, new BRect( 0, 0, 200, 233)) != B_OK ) + {// be_app->PostMessage(B_QUIT_REQUESTED); // Something went wrong -> Quit + rBox->RemoveChild(Konf); + has_view = false; + } + + // Konf->SetViewColor(ui_color(B_BACKGROUND_COLOR)); + if (has_view) + { + Konf->ResizeTo(230, 233); + Konf->SetFlags(B_WILL_DRAW | B_NAVIGABLE); + rBox->AddChild(Konf); + } + + UpdateIfNeeded(); + + delete [] translators; // Garbage collection +} + +void DataTranslationsWindow::BuildView() +{ + newIcon = false; + Install_Done = false; + + BRect r( 300, 250, 380, 270 ); // Pos: Info-Button + BRect all( 0, 0, 400, 300); // Fenster-Groesse + BRect cv( 150, 13, 387, 245); // ConfigView & hosting Box + BRect mau( 146, 8, 390, 290); // Grenz-Box around ConfView + BRect DTN_pos( 195 , 245, 298 , 265); // Pos: Dateiname + BRect ic ( 156 , 245, 188 , 277); // Pos: TrackerIcon + + Konf = new BView(cv, "KONF", B_NOT_RESIZABLE, B_WILL_DRAW ); + // Konf->SetViewColor(ui_color(B_BACKGROUND_COLOR)); + + rBox = new BBox(cv, "Right_Side"); + gBox = new BBox(mau, "Grau"); + + Icon = new BView(ic, "Ikon", B_NOT_RESIZABLE, B_WILL_DRAW | B_PULSE_NEEDED); + + Icon->SetDrawingMode(B_OP_OVER); + // Icon->SetViewColor(ui_color(B_BACKGROUND_COLOR)); + Icon->SetHighColor(217,217,217); + Icon_bit = new BBitmap(BRect(0, 0, 31, 31), B_CMAP8, true, false); + + dButton = new BButton(r, "STD", "Info. . .", new BMessage(BUTTON_MSG)); + + fBox = new BBox(all, "All_Window"); + fBox->SetBorder(B_NO_BORDER); + + r.Set( 10, 10, 120, 288); // List View + + liste = new DataTranslationsView(r, "Transen", B_SINGLE_SELECTION_LIST); + liste->SetSelectionMessage(new BMessage(SEL_CHANGE)); + + DTN = new BStringView(DTN_pos, "DataName", "Test", B_NOT_RESIZABLE); + // DTN->SetViewColor(ui_color(B_BACKGROUND_COLOR)); + + // Here we add the names of all installed translators + WriteTrans(); + + // Setting up the Box around my LView + r.Set( 8, 8, 123, 288); // Box around the List + lBox = new BBox(r, "List-Box"); + lBox->SetBorder(B_NO_BORDER); + lBox->SetViewColor(255,255,255); + + // Put list into a BScrollView, to get that nice srcollbar + tListe = new BScrollView("scroll_trans", liste, B_FOLLOW_LEFT | B_FOLLOW_TOP, 0, false, true, B_FANCY_BORDER); + + + rBox->SetBorder(B_NO_BORDER); + rBox->AddChild(Konf); + rBox->SetFlags(B_NAVIGABLE_JUMP); + + // Attach Views to my Window + AddChild(dButton); + AddChild(tListe); + AddChild(rBox); + + AddChild(fBox); + AddChild(Icon); + AddChild(DTN); + AddChild(lBox); + AddChild(gBox); + + // Set the focus + liste->MakeFocus(); + + // Select the first Translator in list + liste->Select(0, false); + showInfo = true; + +} + +bool DataTranslationsWindow::QuitRequested() +{ + + dynamic_cast(be_app)->SetWindowCorner(BPoint(Frame().left,Frame().top)); + + be_app->PostMessage(B_QUIT_REQUESTED); + + return(true); +} + +void +DataTranslationsWindow::MessageReceived(BMessage *message) +{ + int32 selected; + + switch(message->what) { + case BUTTON_MSG: + selected=liste->CurrentSelection(0); + + // Should we show translator info? + if (!showInfo) + { + // No => Show standard box + (new BAlert("yo!", "Translation Settings\n\nUse this control panel to set values that various\ntranslators use when no other settings are specified\nin the application.", "OK"))->Go(); + break; + } + // Yes => Show Translator info. + Trans_by_ID(selected); + archiv.FindString("be:translator_path", selected, &pfad); + tex << "Name :" << translator_name << "\nVersion: " << (int32)translator_version << "\nInfo: " << translator_info << "\nPath: " << pfad << "\n"; + (new BAlert("yo!", tex.String(), "OK"))->Go(); + tex.SetTo(""); + DrawIcon(); + break; + + case SEL_CHANGE: + // Now we have to update Filename and Icon + // First we find the selected Translator + selected=liste->CurrentSelection(0); + + // If none selected, clear the old one + if (selected < 0) + { + Icon->FillRect(BRect(0, 0, 31, 31)); + DTN->SetText(""); + showInfo = false; + rBox->RemoveChild(Konf); + break; + } + + newIcon = true; + showInfo = true; + Trans_by_ID(selected); + // Now we find the path, and update filename + archiv.FindString("be:translator_path", selected, &pfad); + tex.SetTo(pfad); + tex.Remove(0,tex.FindLast("/")+1); + DTN->SetText(tex.String()); + DrawIcon(); + break; + + + default: + BWindow::MessageReceived(message); + break; + } + +} + +void DataTranslationsWindow::DrawIcon() +{ + if (newIcon) + { + entry.SetTo(pfad); + node.SetTo(&entry); + info.SetTo(&node); + Icon->FillRect(BRect(0, 0, 31, 31)); + newIcon = false; + } + if (info.GetTrackerIcon(Icon_bit) != B_OK) QuitRequested(); + Icon->DrawBitmap(Icon_bit); + + if (Install_Done) + { + liste->RemoveItems(0, liste->CountItems()); + WriteTrans(); + liste->Select(0, false); + Install_Done = false; + } + +} + +void DataTranslationsWindow::WindowActivated(bool state) +{ + if (showInfo) DrawIcon(); +} + +void DataTranslationsWindow::FrameMoved(BPoint origin) +{ + if (showInfo) DrawIcon(); +} + +DataTranslationsWindow::~DataTranslationsWindow() +{ + +} \ No newline at end of file diff --git a/src/prefs/datatranslations/DataTranslationsWindow.h b/src/prefs/datatranslations/DataTranslationsWindow.h new file mode 100644 index 0000000000..4617d157d9 --- /dev/null +++ b/src/prefs/datatranslations/DataTranslationsWindow.h @@ -0,0 +1,77 @@ +#ifndef DATATRANSLATIONS_WINDOW_H +#define DATATRANSLATIONS_WINDOW_H + +#ifndef _WINDOW_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "DataTranslationsSettings.h" +#include "DataTranslationsView.h" + +class DataTranslationsWindow : public BWindow +{ +public: + DataTranslationsWindow(); + ~DataTranslationsWindow(); + +virtual bool QuitRequested(); +virtual void MessageReceived(BMessage* message); +virtual void WindowActivated(bool state); +virtual void FrameMoved(BPoint origin); + // void WindowActivated(bool state); + // void FrameMoved(BPoint origin); + void DrawIcon(); + bool Install_Done; // True if an install just finished, but no List-Update done yet. + + +private: + const char *translator_name, *translator_info; + int32 translator_version; + const char* pfad; + BString tex; + bool showInfo; + bool newIcon; + + + BButton* dButton; // Default-Button + BBox* fBox; // Full-Window Box + BScrollView* tListe; // To get that fancy scrollbar + BBox* lBox; // Box around list + BBox* rBox; // Box hosting Config View + BBox* gBox; // Box around Config View, funny border + + DataTranslationsView* liste; // Improved list of Translators + + BStringView* DTN; // Display the DataTranslatorName + BMessage archiv; // My Message + BView* Icon; // The Icon and Config - Views + BBitmap* Icon_bit; + BView* Konf; + + BEntry entry; + BNode node; + BNodeInfo info; + + void Trans_by_ID(int32 id); + int WriteTrans(); + void BuildView(); + +}; + +#endif // DATATRANSLATIONS_WINDOW_H diff --git a/src/prefs/drivesetup/MainWindow.cpp b/src/prefs/drivesetup/MainWindow.cpp new file mode 100644 index 0000000000..c79341b26f --- /dev/null +++ b/src/prefs/drivesetup/MainWindow.cpp @@ -0,0 +1,208 @@ +/*! \file MainWindow.cpp + * \brief Code for the MainWindow class. + * + * Displays the main window, the essence of the app. + * +*/ + +#ifndef MAIN_WINDOW_H + + #include "MainWindow.h" + +#endif + +/** + * Constructor. + * @param frame The size to make the window. + */ +MainWindow::MainWindow(BRect frame, PosSettings *Settings) + :BWindow(frame, "DriveSetup", B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS | B_NOT_ZOOMABLE){ + + BRect bRect; + BMenu *menu; + BMenu *tmpMenu; + BMenuItem *emptyItem; + + fSettings = Settings; + + bRect = Bounds(); + bRect.bottom = 18.0; + + rootMenu = new BMenuBar(bRect, "root menu"); + //Setup Mount menu + menu = new BMenu("Mount"); + menu->AddItem(new BMenuItem("Mount All Partitions", new BMessage(MOUNT_MOUNT_ALL_MSG), 'M')); + menu->AddSeparatorItem(); + rootMenu->AddItem(menu); + + //Setup Unmount menu + menu = new BMenu("Unmount"); + emptyItem = new BMenuItem("", NULL); + emptyItem->SetEnabled(false); + menu->AddItem(emptyItem); + rootMenu->AddItem(menu); + + //Setup Setup menu + menu = new BMenu("Setup"); + menu->AddItem(new BMenuItem("Format", new BMessage(SETUP_FORMAT_MSG), 'F')); + tmpMenu = new BMenu("Partition"); + tmpMenu->AddItem(new BMenuItem("apple...", new BMessage(SETUP_PARTITION_APPLE_MSG))); + tmpMenu->AddItem(new BMenuItem("intel...", new BMessage(SETUP_PARTITION_INTEL_MSG))); + menu->AddItem(tmpMenu); + tmpMenu = new BMenu("Initialize"); + //add menu for formats + menu->AddItem(tmpMenu); + + rootMenu->AddItem(menu); + + //Setup Options menu + menu = new BMenu("Options"); + menu->AddItem(new BMenuItem("Eject", new BMessage(OPTIONS_EJECT_MSG), 'E')); + menu->AddItem(new BMenuItem("Surface Test", new BMessage(OPTIONS_SURFACE_TEST_MSG), 'T')); + rootMenu->AddItem(menu); + + //Setup Rescan menu + menu = new BMenu("Rescan"); + menu->AddItem(new BMenuItem("IDE", new BMessage(RESCAN_IDE_MSG))); + menu->AddItem(new BMenuItem("SCSI", new BMessage(RESCAN_SCSI_MSG))); + rootMenu->AddItem(menu); + + AddChild(rootMenu); + +} + +/** + * Handles messages. + * @param message The message recieved by the window. + */ +void MainWindow::MessageReceived(BMessage *message){ + + switch(message->what){ + + case MOUNT_MOUNT_ALL_MSG: + + printf("MOUNT_MOUNT_ALL_MSG\n"); + break; + + case MOUNT_MOUNT_SELECTED_MSG: + + printf("MOUNT_MOUNT_SELECTED_MSG\n"); + break; + + case UNMOUNT_UNMOUNT_SELECTED_MSG: + + printf("UNMOUNT_UNMOUNT_SELECTED_MSG\n"); + break; + + case SETUP_FORMAT_MSG: + + printf("SETUP_FORMAT_MSG\n"); + break; + + case SETUP_PARTITION_APPLE_MSG: + + printf("SETUP_PARTITION_APPLE_MSG\n"); + break; + + case SETUP_PARTITION_INTEL_MSG: + + printf("SETUP_PARTITION_INTEL_MSG\n"); + break; + + case SETUP_INITIALIZE_MSG: + + printf("SETUP_INITIALIZE_MSG\n"); + break; + + case OPTIONS_EJECT_MSG: + + printf("OPTIONS_EJECT_MSG\n"); + break; + + case OPTIONS_SURFACE_TEST_MSG: + + printf("OPTIONS_SURFACE_TEST_MSG\n"); + break; + + case RESCAN_IDE_MSG: + + printf("RESCAN_IDE_MSG\n"); + break; + + case RESCAN_SCSI_MSG: + + printf("RESCAN_SCSI_MSG\n"); + break; + + default: + + BWindow::MessageReceived(message); + + }//switch + +} + +/** + * Quits and Saves. + * Sets the swap size and turns the virtual memory on by writing to the + * /boot/home/config/settings/kernel/drivers/virtual_memory file. + */ +bool MainWindow::QuitRequested(){ + + be_app->PostMessage(B_QUIT_REQUESTED); + return(true); + +} + +void MainWindow::FrameMoved(BPoint origin) +{//MainWindow::FrameMoved + fSettings->SetWindowPosition(Frame()); +}//MainWindow::FrameMoved + +void MainWindow::AddDeviceInfo(dev_info d){ + + BMenuItem *tmp; + int cnt; + + printf("Got %s\n", d.device); + + cnt = 0; + while(cnt < d.numParts){ + + if(d.parts[cnt].mounted){ + + //Check to see if we have to get rid of the item + if(strcmp(rootMenu->SubmenuAt(1)->ItemAt(0)->Label(), "") == 0){ + + rootMenu->SubmenuAt(1)->RemoveItem((int32) 0); + + }//if + //add to Unmount menu + tmp = new BMenuItem(d.parts[cnt].mount_pt, new BMessage(UNMOUNT_UNMOUNT_SELECTED_MSG)); + if(strcmp(d.parts[cnt].mount_pt, "/boot") == 0){ + + tmp->SetEnabled(false); + + }//if + rootMenu->SubmenuAt(1)->AddItem(tmp); + + }//if + + //add to Mount menu + //This label comes from the type mapping + tmp = new BMenuItem(d.parts[cnt].fs, new BMessage(MOUNT_MOUNT_SELECTED_MSG)); + if(d.parts[cnt].mounted){ + + tmp->SetEnabled(false); + + }//if + rootMenu->SubmenuAt(0)->AddItem(tmp); + + cnt++; + + }//while + + //send to view + +}//SetDeviceInfo + diff --git a/src/prefs/drivesetup/MainWindow.h b/src/prefs/drivesetup/MainWindow.h new file mode 100644 index 0000000000..89ea07df28 --- /dev/null +++ b/src/prefs/drivesetup/MainWindow.h @@ -0,0 +1,85 @@ +/*! \file MainWindow.h + \brief Header for the MainWindow class. + +*/ + +#ifndef MAIN_WINDOW_H + + #define MAIN_WINDOW_H + + #define MOUNT_MOUNT_ALL_MSG 'mall' + #define MOUNT_MOUNT_SELECTED_MSG 'msel' + #define UNMOUNT_UNMOUNT_SELECTED_MSG 'usel' + #define SETUP_FORMAT_MSG 'sfor' + #define SETUP_PARTITION_APPLE_MSG 'spaa' + #define SETUP_PARTITION_INTEL_MSG 'spai' + #define SETUP_INITIALIZE_MSG 'sini' + #define OPTIONS_EJECT_MSG 'oeje' + #define OPTIONS_SURFACE_TEST_MSG 'osut' + #define RESCAN_IDE_MSG 'ride' + #define RESCAN_SCSI_MSG 'rscs' + + #ifndef _APPLICATION_H + + #include + + #endif + #ifndef _WINDOW_H + + #include + + #endif + #ifndef _MENU_BAR_H + + #include + + #endif + #ifndef _MENU_ITEM_H + + #include + + #endif + #ifndef _RECT_H + + #include + + #endif + #ifndef _STDIO_H + + #include + + #endif + #ifndef POS_SETTINGS_H + + #include "PosSettings.h" + + #endif + #ifndef STRUCTS_H + + #include "structs.h" + + #endif + + /** + * The main window of the app. + * + * Sets up and displays everything you need for the app. + */ + class MainWindow : public BWindow{ + + private: + + PosSettings *fSettings; + BMenuBar *rootMenu; + + public: + + MainWindow(BRect frame, PosSettings *fSettings); + virtual bool QuitRequested(); + virtual void MessageReceived(BMessage *message); + virtual void FrameMoved(BPoint origin); + void AddDeviceInfo(dev_info d); + + }; + +#endif diff --git a/src/prefs/drivesetup/PosSettings.cpp b/src/prefs/drivesetup/PosSettings.cpp new file mode 100644 index 0000000000..e05187168d --- /dev/null +++ b/src/prefs/drivesetup/PosSettings.cpp @@ -0,0 +1,94 @@ +#ifndef POS_SETTINGS_H +#include "PosSettings.h" +#endif +#ifndef _APPLICATION_H +#include +#endif +#ifndef _FILE_H +#include +#endif +#ifndef _PATH_H +#include +#endif +#ifndef _FINDDIRECTORY_H +#include +#endif + +#include + +const char PosSettings::kVMSettingsFile[] = "DriveSetup_prefs"; + +PosSettings::PosSettings() +{//VMSettings::VMSettings + + BPath path; + if (find_directory(B_USER_SETTINGS_DIRECTORY,&path) == B_OK) + { + path.Append(kVMSettingsFile); + BFile file(path.Path(), B_READ_ONLY); + if (file.InitCheck() != B_OK) + be_app->PostMessage(B_QUIT_REQUESTED); + // Now read in the data + if (file.Read(&fcorner, sizeof(BPoint)) != sizeof(BPoint)) + be_app->PostMessage(B_QUIT_REQUESTED); + if (file.Read(&brCorner, sizeof(BPoint)) != sizeof(BPoint)) + be_app->PostMessage(B_QUIT_REQUESTED); + } + printf("VM settings file read.\n"); + printf("=========================\n"); + printf("fcorner read in as "); + fcorner.PrintToStream(); + printf("brCorner read in as "); + brCorner.PrintToStream(); + + fWindowFrame.left=fcorner.x; + fWindowFrame.top=fcorner.y; + fWindowFrame.right=brCorner.x; + fWindowFrame.bottom=brCorner.y; + + //Check to see if the co-ords of the window are in the range of the Screen + BScreen screen; + if (screen.Frame().right >= fWindowFrame.right + && screen.Frame().bottom >= fWindowFrame.bottom) + return; + // If they are not, lets just stick the window in the middle + // of the screen. + + //I don't want to deal with this now - MSM + + /*fWindowFrame = screen.Frame(); + fWindowFrame.left = (fWindowFrame.right-269)/2; + fWindowFrame.right = fWindowFrame.left + 269; + fWindowFrame.top = (fWindowFrame.bottom-172)/2; + fWindowFrame.bottom = fWindowFrame.top + 172; +*/ +}//VMSettings::VMSettings + +PosSettings::~PosSettings() +{//VMSettings::~VMSettings +//printf("enter\n"); + BPath path; + if (find_directory(B_USER_SETTINGS_DIRECTORY,&path) < B_OK) + return; +//printf("find_directory\n"); + path.Append(kVMSettingsFile); +//printf("path.Append\n"); + BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE); +//printf("create file\n"); + if (file.InitCheck() == B_OK) + { + //printf("in if statement\n"); + file.Write(&fcorner, sizeof(BPoint)); + file.Write(&brCorner, sizeof(BPoint)); + } +//printf("exit\n"); +}//MouseSettings::~MouseSettings + +void PosSettings::SetWindowPosition(BRect f) +{//VMSettings::SetWindowFrame + fcorner.x=f.left; + fcorner.y=f.top; + brCorner.x=f.right; + brCorner.y=f.bottom; +brCorner.PrintToStream(); +}//VMSettings::SetWindowFrame \ No newline at end of file diff --git a/src/prefs/drivesetup/PosSettings.h b/src/prefs/drivesetup/PosSettings.h new file mode 100644 index 0000000000..da4c74c40a --- /dev/null +++ b/src/prefs/drivesetup/PosSettings.h @@ -0,0 +1,21 @@ +#ifndef POS_SETTINGS_H_ +#define POS_SETTINGS_H_ + +#include +#include + +class PosSettings{ +public : + PosSettings(); + virtual ~PosSettings(); + BRect WindowPosition() const { return fWindowFrame; } + void SetWindowPosition(BRect); + +private: + static const char kVMSettingsFile[]; + BRect fWindowFrame; + BPoint fcorner; + BPoint brCorner; +}; + +#endif \ No newline at end of file diff --git a/src/prefs/drivesetup/Resource.rsrc b/src/prefs/drivesetup/Resource.rsrc new file mode 100644 index 0000000000..0d4c16f1db Binary files /dev/null and b/src/prefs/drivesetup/Resource.rsrc differ diff --git a/src/prefs/drivesetup/main.cpp b/src/prefs/drivesetup/main.cpp new file mode 100644 index 0000000000..d015172c43 --- /dev/null +++ b/src/prefs/drivesetup/main.cpp @@ -0,0 +1,117 @@ +/*! \file main.cpp + * \brief Code for the main class. + * + * This file contains the code for the main class. This class sets up all + * of the initial conditions for the app. + * +*/ + +#ifndef MAIN_WINDOW_H + + #include "MainWindow.h" + +#endif +#ifndef MAIN_H + + #include "main.h" + +#endif + +/** + * Main method. + * + * Starts the whole thing. + */ +int main(int, char**){ + + /** + * An instance of the application. + */ + DriveSetup dsApp; + + dsApp.Run(); + + return(0); + +} + +/* + * Constructor. + * + * Provides a contstructor for the application. + */ +DriveSetup::DriveSetup() + :BApplication("application/x-vnd.MSM-DriveSetupPrefPanel"){ + + fSettings = new PosSettings(); + + /* + * The main interface window. + */ + MainWindow *Main; + dev_info devs; + partition_info partitions[4]; + + Main = new MainWindow(fSettings->WindowPosition(), fSettings); + + //This section is to set up defaults that I can use for testing. + //set up floppy drive + partitions[0].type = 11; + partitions[0].fs = "dos"; + partitions[0].name = ""; + partitions[0].mount_pt = ""; + partitions[0].size = 1.4; + partitions[0].mounted = FALSE; + devs.device = "/dev/disk/floppy"; + devs.map = 1; + devs.numParts = 1; + devs.parts = partitions; + Main->AddDeviceInfo(devs); + + partitions[0].type = 11; + partitions[0].fs = "dos"; + partitions[0].name = "winxp"; + partitions[0].mount_pt = "/winxp"; + partitions[0].size = 5600.0; + partitions[0].mounted = TRUE; + partitions[1].type = 12; + partitions[1].fs = "dos"; + partitions[1].name = "windata"; + partitions[1].mount_pt = "/windata"; + partitions[1].size = 3600.0; + partitions[1].mounted = TRUE; + partitions[2].type = 235; + partitions[2].fs = "Be File System"; + partitions[2].name = "BeOS"; + partitions[2].mount_pt = "/boot"; + partitions[2].size = 4900.0; + partitions[2].mounted = TRUE; + devs.device = "/dev/disk/ide/ata/0/master/0"; + devs.map = 1; + devs.numParts = 3; + devs.parts = partitions; + Main->AddDeviceInfo(devs); + + partitions[0].type = 11; + partitions[0].fs = "iso9660"; + partitions[0].name = ""; + partitions[0].mount_pt = "/OUTLAWSTAR_D1"; + partitions[0].size = 2200.0; + partitions[0].mounted = TRUE; + devs.device = "/dev/disk/ide/atapi/1/master/0"; + devs.map = 2; + devs.numParts = 1; + devs.parts = partitions; + Main->AddDeviceInfo(devs); + + //End set up of defaults + + Main->Show(); + +} + +DriveSetup::~DriveSetup() +{ + delete fSettings; +} + diff --git a/src/prefs/drivesetup/main.h b/src/prefs/drivesetup/main.h new file mode 100644 index 0000000000..1a98930790 --- /dev/null +++ b/src/prefs/drivesetup/main.h @@ -0,0 +1,53 @@ +/*! \file main.h + \brief Header file for the main class. + +*/ + +#ifndef MAIN_H + + #define MAIN_H + + #ifndef _APPLICATION_H + + #include + + #endif + + #ifndef _STDIO_H + + #include + + #endif + #ifndef POS_SETTINGS_H + + #include "PosSettings.h" + + #endif + #ifndef STRUCTS_H + + #include "structs.h" + + #endif + + + /** + * Main class. + * + * Gets everything going. + */ + class DriveSetup : public BApplication{ + + public: + + /** + * Constructor. + */ + DriveSetup(); + virtual ~DriveSetup(); + + private: + PosSettings *fSettings; + + }; + +#endif \ No newline at end of file diff --git a/src/prefs/drivesetup/structs.h b/src/prefs/drivesetup/structs.h new file mode 100644 index 0000000000..b6cd316764 --- /dev/null +++ b/src/prefs/drivesetup/structs.h @@ -0,0 +1,32 @@ +/*! \file structs.h + \brief Holds the structs used. + +*/ + +#ifndef STRUCTS_H + + #define STRUCTS_H + + struct partition_info{ + + int32 type; /* partition type */ + /* Maybe get this from the type mapping? */ + char *fs; /* file system */ + char *name; /* volume name */ + char *mount_pt; /* mounted at */ + double size; /* size (in MB) */ + bool mounted; /* TRUE if mounted, FALSE if not */ + + }; + + struct dev_info{ + + char *device; /* the path to the device */ + int map; /* 0 for none, 1 for intel, 2 for apple */ + int numParts; /* number of partitions */ + partition_info parts[4]; /* information on the partitions on the device */ + + }; + +#endif + diff --git a/src/prefs/dun/DUN.cpp b/src/prefs/dun/DUN.cpp new file mode 100644 index 0000000000..b834be04a8 --- /dev/null +++ b/src/prefs/dun/DUN.cpp @@ -0,0 +1,71 @@ +/* + +DUN by Sikosis (beos@gravity24hr.com) + +(C) 2002 OpenBeOS under MIT license + +*/ + +#include "app/Application.h" +#include +#include "interface/Window.h" +#include "interface/View.h" +#include + +#include "DUN.h" +#include "ModemWindow.h" +#include "DUNWindow.h" +#include "DUNView.h" +// ------------------------------------------------------------------------------- // + + +// Application Signature and Title +const char *APP_SIGNATURE = "application/x-vnd.OBOS.Dial-UpNetworking"; + +// Default Window Size +float FormTopDefault = 100; +float FormLeftDefault = 100; +float FormWidthDefault = 312; +float FormHeightDefault = 250; + +float FormTopState1 = 100; +float FormLeftState1 = 100; +float FormWidthState1 = 312; +float FormHeightState1 = 282; + +float FormTopState2 = 100; +float FormLeftState2 = 100; +float FormWidthState2 = 312; +float FormHeightState2 = 282; + +BRect windowRect(FormTopDefault,FormLeftDefault,FormLeftDefault+FormWidthDefault,FormTopDefault+FormHeightDefault); + +const uint32 MENU_CON_NEW = 'MCNu'; + +// DUN -- constructor for DUN Class +DUN::DUN() : BApplication (APP_SIGNATURE) { + new DUNWindow(windowRect); + +} +// ------------------------------------------------------------------------------- // + +// DUN::MessageReceived -- handles incoming messages +void DUN::MessageReceived (BMessage *message) { + switch(message->what) { + case MENU_CON_NEW: + (new BAlert("","New Connection Window","Coming Soon"))->Go(); + break; + default: + BApplication::MessageReceived(message); // pass it along ... + break; + } +} +// ------------------------------------------------------------------------------- // + +// DUN Main +int main(void) { + DUN theApp; + theApp.Run(); + return 0; +} +// end diff --git a/src/prefs/dun/DUN.h b/src/prefs/dun/DUN.h new file mode 100644 index 0000000000..c0960db94d --- /dev/null +++ b/src/prefs/dun/DUN.h @@ -0,0 +1,21 @@ +/* + +DUN Header by Sikosis (beos@gravity24hr.com) + +(C) 2002 OpenBeOS under MIT license + +*/ + +#ifndef __DUN_H__ +#define __DUN_H__ + +extern const char *APP_SIGNATURE; + +class DUN : public BApplication { +public: + DUN(); + virtual void MessageReceived(BMessage *message); +private: +}; + +#endif diff --git a/src/prefs/dun/DUN.rsrc b/src/prefs/dun/DUN.rsrc new file mode 100644 index 0000000000..cc0bebf9e3 Binary files /dev/null and b/src/prefs/dun/DUN.rsrc differ diff --git a/src/prefs/dun/DUNView.cpp b/src/prefs/dun/DUNView.cpp new file mode 100644 index 0000000000..8a9d5e0362 --- /dev/null +++ b/src/prefs/dun/DUNView.cpp @@ -0,0 +1,30 @@ +/* + +DUNView by Sikosis (beos@gravity24hr.com) + +(C) 2002 OpenBeOS under MIT license + +*/ + +#include "app/Application.h" +#include "interface/Window.h" +#include "interface/View.h" +#include + +#include "DUN.h" +#include "ModemWindow.h" +#include "DUNWindow.h" +#include "DUNView.h" + +// DUNView -- the view so we can put objects like text boxes on it +DUNView::DUNView (BRect frame) : BView (frame, "DUNView", B_FOLLOW_ALL_SIDES, B_WILL_DRAW ) { + // Set the Background Color + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); +} + +ModemView::ModemView (BRect frame) : BView (frame, "ModemView", B_FOLLOW_ALL_SIDES, B_WILL_DRAW ) +{ + // Set the Background Color + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); +} +// end diff --git a/src/prefs/dun/DUNView.h b/src/prefs/dun/DUNView.h new file mode 100644 index 0000000000..7a7ae06a46 --- /dev/null +++ b/src/prefs/dun/DUNView.h @@ -0,0 +1,22 @@ +/* + +DUNView by Sikosis (beos@gravity24hr.com) + +(C) 2002 OpenBeOS under MIT license + +*/ + +#ifndef __DUNVIEW_H__ +#define __DUNVIEW_H__ + +class DUNView : public BView { +public: + DUNView(BRect frame); +}; + +class ModemView : public BView { +public: + ModemView(BRect frame); +}; + +#endif diff --git a/src/prefs/dun/DUNWindow.cpp b/src/prefs/dun/DUNWindow.cpp new file mode 100644 index 0000000000..fbcebd076a --- /dev/null +++ b/src/prefs/dun/DUNWindow.cpp @@ -0,0 +1,271 @@ +/* + +DUNWindow by Sikosis (beos@gravity24hr.com) + +(C) 2002 OpenBeOS under MIT license + +*/ + +#include "app/Application.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "DUN.h" +#include "DUNWindow.h" +#include "ModemWindow.h" +#include "DUNView.h" + +// Constants +const uint32 BTN_MODEM = 'Modm'; +const uint32 BTN_DISCONNECT = 'Disc'; +const uint32 BTN_CONNECT = 'Conn'; +const uint32 CHK_CALLWAITING = 'Ckcw'; +const uint32 CHK_DIALOUTPREFIX = 'Ckdp'; + +const uint32 MENU_CLICKTOADD = 'MC2A'; +const uint32 MENU_CON_NEW = 'MCNu'; +const uint32 MENU_CON_DELETE_CURRENT = 'MCDl'; + +const uint32 MENU_LOC_HOME = 'MLHm'; +const uint32 MENU_LOC_WORK = 'MLWk'; +const uint32 MENU_LOC_NEW = 'MLNu'; +const uint32 MENU_LOC_DELETE_CURRENT = 'MLDl'; + +float ModemFormTopDefault = 150; +float ModemFormLeftDefault = 150; +float ModemFormWidthDefault = 281; +float ModemFormHeightDefault = 324; +BRect windowRectModem(ModemFormTopDefault,ModemFormLeftDefault,ModemFormLeftDefault+ModemFormWidthDefault,ModemFormTopDefault+ModemFormHeightDefault); + +// DUNWindow -- constructor for DUNWindow Class +DUNWindow::DUNWindow(BRect frame) : BWindow (frame, "OBOS Dial-up Networking", B_TITLED_WINDOW, B_NOT_RESIZABLE , 0) { + InitWindow(); + Show(); + +} +// ------------------------------------------------------------------------------- // + +// DUNWindow::InitWindow -- Initialization Commands here +void DUNWindow::InitWindow(void) { + BRect r; + r = Bounds(); + + // Buttons + float ButtonTop = 217; + float ButtonWidth = 24; + BRect btn1(10,ButtonTop,83,ButtonTop+ButtonWidth); + modembutton = new BButton(btn1,"Modem","Modem...", new BMessage(BTN_MODEM), B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE); + BRect btn2(143,ButtonTop,218,ButtonTop+ButtonWidth); + disconnectbutton = new BButton(btn2,"Disconnect","Disconnect", new BMessage(BTN_DISCONNECT), B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE); + BRect btn3(230,ButtonTop,302,ButtonTop+ButtonWidth); + connectbutton = new BButton(btn3,"Connect","Connect", new BMessage(BTN_CONNECT), B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE); + + // Check Boxes -- Only when form in state 2 + //BRect chk1(68,110,220,110); + //disablecallwaiting = new BCheckBox(chk1,"Disable call waiting","Disable call waiting:", new BMessage(CHK_CALLWAITING), B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE); + //BRect chk2(68,137,220,110); + //dialoutprefix = new BCheckBox(chk2,"Dial out prefix","Dial out prefix:", new BMessage(CHK_DIALOUTPREFIX), B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE); + + // Connection MenuField + BRect mfld1(15,8,180,28); + BMenuItem *menuconnew; + BMenuItem *menucondelete; + + conmenufield = new BMenu("Click to add"); + conmenufield->AddSeparatorItem(); + conmenufield->AddItem(menuconnew = new BMenuItem("New...", new BMessage(MENU_CON_NEW))); + menuconnew->SetTarget(be_app); + conmenufield->AddItem(menucondelete = new BMenuItem("Delete Current", new BMessage(MENU_CON_DELETE_CURRENT))); + menucondelete->SetEnabled(false); + menucondelete->SetTarget(be_app); + connectionmenufield = new BMenuField(mfld1,"connection_menu","Connect to:",conmenufield,B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE); + connectionmenufield->SetDivider(77); + connectionmenufield->SetFont(be_bold_font); + connectionmenufield->SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + + // Location MenuField + BRect mfld2(mfld1.left,75,250,125); + BMenuItem *menulochome; + BMenuItem *menulocwork; + BMenuItem *menulocnew; + BMenuItem *menulocdelete; + + locmenufield = new BMenu("Home "); + locmenufield->AddItem(menulochome = new BMenuItem("Home", new BMessage(MENU_LOC_HOME))); + menulochome->SetTarget(be_app); + menulochome->SetMarked(true); + + locmenufield->AddItem(menulocwork = new BMenuItem("Work", new BMessage(MENU_LOC_WORK))); + menulocwork->SetTarget(be_app); + locmenufield->AddSeparatorItem(); + + locmenufield->AddItem(menulocnew = new BMenuItem("New...", new BMessage(MENU_LOC_NEW))); + menulocnew->SetTarget(be_app); + + locmenufield->AddItem(menulocdelete = new BMenuItem("Delete Current", new BMessage(MENU_LOC_DELETE_CURRENT))); + menulocdelete->SetTarget(be_app); + + locationmenufield = new BMenuField(mfld2,"location_menu","From location:",locmenufield,B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE); + locationmenufield->SetDivider(88); + locationmenufield->SetFont(be_bold_font); + locationmenufield->SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + + // Displays - on the main window + BRect CPLocation(40,43,300,10); + tvConnectionProfile = new BTextView(r, "Connection Profile", CPLocation, B_FOLLOW_ALL, B_WILL_DRAW); + tvConnectionProfile->SetText(""); + tvConnectionProfile->MakeSelectable(false); + tvConnectionProfile->MakeEditable(false); + + // Displays - Call waiting may be enabled. + BRect CWLocation(40,113,300,10); + tvCallWaiting = new BTextView(r, "Call waiting", CWLocation, B_FOLLOW_ALL, B_WILL_DRAW); + tvCallWaiting->SetText("Call waiting may be enabled."); + tvCallWaiting->MakeSelectable(false); + tvCallWaiting->MakeEditable(false); + + // Displays - No Connection + BRect NCLocation(21,168,300,10); + tvConnection = new BTextView(r, "No Connection", NCLocation, B_FOLLOW_ALL, B_WILL_DRAW); + tvConnection->SetText("No Connection"); + tvConnection->MakeSelectable(false); + tvConnection->MakeEditable(false); + + // Display - Time Online ie. 00:00:00 + BRect TOLocation(249,168,300,10); + tvTimeOnline = new BTextView(r, "Time Online", TOLocation, B_FOLLOW_ALL, B_WILL_DRAW); + tvTimeOnline->SetText("00:00:00"); + tvTimeOnline->MakeSelectable(false); + tvTimeOnline->MakeEditable(false); + + // Display - TextView of Local IP address + BRect TextLIPLocation(21,186,300,10); + tvLIP = new BTextView(r, "Local IP address", TextLIPLocation, B_FOLLOW_ALL, B_WILL_DRAW); + tvLIP->SetText("Local IP address:"); + tvLIP->MakeSelectable(false); + tvLIP->MakeEditable(false); + + // Display - Local IP address + BRect LIPLocation (264,186,300,10); + tvLocalIPAddress = new BTextView(r, "None", LIPLocation, B_FOLLOW_ALL, B_WILL_DRAW); + tvLocalIPAddress->SetText("None"); + tvLocalIPAddress->MakeSelectable(false); + tvLocalIPAddress->MakeEditable(false); + + // Outline List View - Fake ones really as we're only using them as an indicator. + BListItem *conitem; + BListItem *consubitem; + BRect lst1(20,44,100,80); + BListItem *locitem; + BListItem *locsubitem; + BRect lst2(20,114,100,170); + + connectionlistitem = new BOutlineListView(lst1, "connection_list", B_MULTIPLE_SELECTION_LIST); + connectionlistitem->AddItem(conitem = new BStringItem("")); + connectionlistitem->AddUnder(consubitem = new BStringItem("\0"), conitem); + connectionlistitem->Collapse(conitem); + + /* BFont myfont; + connectionlistitem->GetFont(&myfont); + myfont.SetShear(5.0); + myfont.SetSpacing(B_CHAR_SPACING); + connectionlistitem->SetFont(&myfont);*/ + + //connectionlistitem->Update(aDUNview,); + + locationlistitem = new BOutlineListView(lst2, "location_list", B_SINGLE_SELECTION_LIST); + locationlistitem->AddItem(locitem = new BStringItem("")); + locationlistitem->AddUnder(locsubitem = new BStringItem(""), locitem); + locationlistitem->Collapse(locitem); + + // Frames + BRect tf(10,18,302,67); + topframe = new BBox(tf,"Connect to:",B_FOLLOW_ALL | B_WILL_DRAW | B_NAVIGABLE_JUMP, B_FANCY_BORDER); + BRect mf(10,86,302,139); + middleframe = new BBox(mf,"From Location:",B_FOLLOW_ALL | B_WILL_DRAW | B_NAVIGABLE_JUMP, B_FANCY_BORDER); + BRect bf(10,149,302,208); + bottomframe = new BBox(bf,"Connection",B_FOLLOW_ALL | B_WILL_DRAW | B_NAVIGABLE_JUMP, B_FANCY_BORDER); + + // Set Labels for Frames + //middleframe->SetLabel("From Location:"); + bottomframe->SetLabel("Connection"); + + // Add our Objects to the Window + AddChild(modembutton); + AddChild(disconnectbutton); + AddChild(connectbutton); +// AddChild(disablecallwaiting); +// AddChild(dialoutprefix); + AddChild(connectionlistitem); + AddChild(topframe); + AddChild(connectionmenufield); + AddChild(locationlistitem); + AddChild(middleframe); + AddChild(locationmenufield); + AddChild(bottomframe); + AddChild(tvConnectionProfile); + AddChild(tvCallWaiting); + AddChild(tvConnection); + AddChild(tvTimeOnline); + AddChild(tvLIP); + AddChild(tvLocalIPAddress); + + // Make Connection Menu the Focus -- otherwise it looks funny + connectionmenufield->MakeFocus(true); + + // Disable Buttons that need to be + disconnectbutton->SetEnabled(false); + connectbutton->SetEnabled(false); + + // Set Default Button + connectbutton->MakeDefault(true); + + // Add the Drawing View + AddChild(aDUNview = new DUNView(r)); +} +// ------------------------------------------------------------------------------- // + +//void DUNView::MouseDown(BPoint bp) { + //BString *tmp; +// (new BAlert("","Clicked","Okay"))->Go(); +//} + +// DUNWindow::~DUNWindow -- destructor +DUNWindow::~DUNWindow() { + exit(0); +} +// ------------------------------------------------------------------------------- // + +// DUNWindow::QuitRequested -- Post a message to the app to quit +bool DUNWindow::QuitRequested() { + be_app->PostMessage(B_QUIT_REQUESTED); + return true; +} +// ------------------------------------------------------------------------------- // + +// DUNWindow::MessageReceived -- receives messages +void DUNWindow::MessageReceived (BMessage *message) { + switch(message->what) { + case BTN_MODEM: + new ModemWindow(windowRectModem); + break; + default: + BWindow::MessageReceived(message); + break; + } +} +// end diff --git a/src/prefs/dun/DUNWindow.h b/src/prefs/dun/DUNWindow.h new file mode 100644 index 0000000000..e472ddc045 --- /dev/null +++ b/src/prefs/dun/DUNWindow.h @@ -0,0 +1,53 @@ +/* + +DUNWindow Header by Sikosis (beos@gravity24hr.com) + +(C) 2002 OpenBeOS under MIT license + +*/ + +#ifndef __DUNWINDOW_H__ +#define __DUNWINDOW_H__ + +class DUNView; + +class DUNWindow : public BWindow { +public: + DUNWindow(BRect frame); + ~DUNWindow(); + virtual bool QuitRequested(); + virtual void MessageReceived(BMessage *message); +private: + void InitWindow(void); + DUNView* aDUNview; + + //BMenuBar *menubar; + BBox *topframe; + BBox *middleframe; + BBox *bottomframe; + + BButton *modembutton; + BButton *disconnectbutton; + BButton *connectbutton; + + BCheckBox *disablecallwaiting; + BCheckBox *dialoutprefix; + + BOutlineListView *connectionlistitem; + BOutlineListView *locationlistitem; + + BMenuField *connectionmenufield; + BMenuField *locationmenufield; + BMenu *conmenufield; + BMenu *locmenufield; + + BTextView *tvConnectionProfile; + BTextView *tvCallWaiting; + BTextView *tvConnection; + BTextView *tvTimeOnline; + BTextView *tvLIP; + BTextView *tvLocalIPAddress; + +}; + +#endif diff --git a/src/prefs/dun/ModemWindow.cpp b/src/prefs/dun/ModemWindow.cpp new file mode 100644 index 0000000000..ab835ac227 --- /dev/null +++ b/src/prefs/dun/ModemWindow.cpp @@ -0,0 +1,185 @@ +/* + +ModemWindow by Sikosis (beos@gravity24hr.com) + +(C) 2002 OpenBeOS under MIT license + +*/ + +#include "app/Application.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "DUN.h" +//#include "DUNWindow.h" +#include "ModemWindow.h" +#include "DUNView.h" + +// Constants +const uint32 BTN_MODEM_WINDOW_CANCEL = 'BMWC'; +const uint32 BTN_MODEM_WINDOW_CUSTOM = 'BMWU'; +const uint32 BTN_MODEM_WINDOW_DONE = 'BMWD'; +const uint32 MENU = 'Menu'; +const uint32 CHK_MAKE_CONNECTION = 'CKMC'; +const uint32 CHK_SHOW_TERMINAL = 'CKST'; +const uint32 CHK_LOG_ALL = 'CKLA'; + +// ModemWindow -- constructor for ModemWindow Class +ModemWindow::ModemWindow(BRect frame) : BWindow (frame, "", B_MODAL_WINDOW, B_NOT_RESIZABLE , 0) +{ + InitWindow(); + Show(); +} +// ------------------------------------------------------------------------------- // + +// ModemWindow::InitWindow -- Initialization Commands here +void ModemWindow::InitWindow(void) +{ + BRect r; + r = Bounds(); + + // Buttons + BRect btn1(10,r.bottom - 34,83,r.bottom - 16); + BRect btn2(108,r.bottom - 34,184,r.bottom - 16); + BRect btn3(196,r.bottom - 34,271,r.bottom - 16); + btnModemWindowCustom = new BButton(btn1,"Custom"," Custom ... ", new BMessage(BTN_MODEM_WINDOW_CUSTOM), B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE); + btnModemWindowCancel = new BButton(btn2,"Cancel"," Cancel ", new BMessage(BTN_MODEM_WINDOW_CANCEL), B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE); + btnModemWindowDone = new BButton(btn3,"Done"," Done ", new BMessage(BTN_MODEM_WINDOW_DONE), B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE); + + // YourModemIs MenuField + BRect mfld1(15,20,350,30); + BMenuItem *menu[100]; + YourModemIsMenu = new BMenu(" "); + YourModemIsMenu->AddSeparatorItem(); + YourModemIsMenu->AddItem(menu[1] = new BMenuItem("New...", new BMessage(MENU))); + menu[1]->SetTarget(be_app); + YourModemIsMenuField = new BMenuField(mfld1,"yourmodem_menufield","Your modem is:",YourModemIsMenu,B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE); + YourModemIsMenuField->SetDivider(76); + YourModemIsMenuField->SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + + // ConnectVia MenuField + BRect mfld2(28,45,350,55); + BMenuItem *menu2[100]; + ConnectViaMenu = new BMenu("serial 1 "); + //ConnectViaMenu->AddSeparatorItem(); + ConnectViaMenu->AddItem(menu2[1] = new BMenuItem("serial 2 ", new BMessage(MENU))); + menu2[1]->SetTarget(be_app); + ConnectViaMenuField = new BMenuField(mfld2,"connectvia_menufield","Connect via:",ConnectViaMenu,B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE); + ConnectViaMenuField->SetDivider(63); + ConnectViaMenuField->SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + + // Speed MenuField + BRect mfld3(54,70,350,80); + BMenuItem *menu3[100]; + SpeedMenu = new BMenu("9600 "); + SpeedMenu->AddItem(menu3[1] = new BMenuItem("19200 ", new BMessage(MENU))); + menu3[1]->SetTarget(be_app); + SpeedMenuField = new BMenuField(mfld3,"speed_menufield","Speed:",SpeedMenu,B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE); + SpeedMenuField->SetDivider(37); + SpeedMenuField->SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + + // TextView - Redial + BRect RedialLocation (15,112,350,132); + tvRedial = new BTextView(r, "Redial", RedialLocation, B_FOLLOW_ALL, B_WILL_DRAW); + tvRedial->SetText("Redial"); + tvRedial->MakeSelectable(false); + tvRedial->MakeEditable(false); + + // TextView - TimesBusySignal + BRect TimesBusySignalLocation (82,112,400,132); + tvTimesBusySignal = new BTextView(r, "TimesBusySignal", TimesBusySignalLocation, B_FOLLOW_ALL, B_WILL_DRAW); + tvTimesBusySignal->SetText("time(s) on busy signal"); + tvTimesBusySignal->MakeSelectable(false); + tvTimesBusySignal->MakeEditable(false); + + // TextView - ReadLogPath + BRect ReadLogPathLocation (32,238,350,258); + tvReadLogPath = new BTextView(r, "ReadLogPath", ReadLogPathLocation, B_FOLLOW_ALL, B_WILL_DRAW); + tvReadLogPath->SetText("Read log file path: /boot/var/log/ppp-read.log"); + tvReadLogPath->MakeSelectable(false); + tvReadLogPath->MakeEditable(false); + + // TextView - WriteLogPath + BRect WriteLogPathLocation (32,256,350,276); + tvWriteLogPath = new BTextView(r, "WriteLogPath", WriteLogPathLocation, B_FOLLOW_ALL, B_WILL_DRAW); + tvWriteLogPath->SetText("Write log file path: /boot/var/log/ppp-write.log"); + tvWriteLogPath->MakeSelectable(false); + tvWriteLogPath->MakeEditable(false); + + // CheckBox - chkMakeConnection + BRect chkMakeConnectionLocation (15,159,300,179); + chkMakeConnection = new BCheckBox(chkMakeConnectionLocation, "chkMakeConnection", "Make connection when necessary", new BMessage(CHK_MAKE_CONNECTION), B_FOLLOW_LEFT | B_FOLLOW_TOP , B_WILL_DRAW | B_NAVIGABLE); + chkMakeConnection->SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + + // CheckBox - chkShowTerminal + BRect chkShowTerminalLocation (15,196,300,216); + chkShowTerminal = new BCheckBox(chkShowTerminalLocation, "chkShowTerminal", "Show terminal when connecting", new BMessage(CHK_SHOW_TERMINAL), B_FOLLOW_LEFT | B_FOLLOW_TOP , B_WILL_DRAW | B_NAVIGABLE); + chkShowTerminal->SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + + // CheckBox - chkLogAll + BRect chkLogAllLocation (15,215,300,235); + chkLogAll = new BCheckBox(chkLogAllLocation, "chkLogAll", "Log all bytes sent/received", new BMessage(CHK_LOG_ALL), B_FOLLOW_LEFT | B_FOLLOW_TOP , B_WILL_DRAW | B_NAVIGABLE); + chkLogAll->SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + + // Add Objects to View + AddChild(YourModemIsMenuField); + AddChild(ConnectViaMenuField); + AddChild(SpeedMenuField); + AddChild(btnModemWindowCancel); + AddChild(btnModemWindowCustom); + AddChild(btnModemWindowDone); + AddChild(chkMakeConnection); + AddChild(chkShowTerminal); + AddChild(chkLogAll); + AddChild(tvRedial); + AddChild(tvTimesBusySignal); + AddChild(tvReadLogPath); + AddChild(tvWriteLogPath); + + btnModemWindowDone->MakeDefault(true); + + // Add the Drawing View + AddChild(aModemview = new ModemView(r)); +} +// ------------------------------------------------------------------------------- // + +// ModemWindow::~ModemWindow -- destructor +ModemWindow::~ModemWindow() +{ + exit(0); +} +// ------------------------------------------------------------------------------- // + +// ModemWindow::MessageReceived -- receives messages +void ModemWindow::MessageReceived (BMessage *message) +{ + switch(message->what) + { + case BTN_MODEM_WINDOW_DONE: + Quit(); // debugging purposes + break; + case BTN_MODEM_WINDOW_CANCEL: + Hide(); // must find a better way to close this window and not the entire application + break; + default: + BWindow::MessageReceived(message); + break; + } +} +// end diff --git a/src/prefs/dun/ModemWindow.h b/src/prefs/dun/ModemWindow.h new file mode 100644 index 0000000000..da297630b9 --- /dev/null +++ b/src/prefs/dun/ModemWindow.h @@ -0,0 +1,45 @@ +/* + +ModemWindow Header by Sikosis (beos@gravity24hr.com) + +(C) 2002 OpenBeOS under MIT license + +*/ + +#ifndef __MODEMWINDOW_H__ +#define __MODEMWINDOW_H__ + +class ModemView; + +class ModemWindow : public BWindow +{ +public: + ModemWindow(BRect frame); + ~ModemWindow(); + virtual void MessageReceived(BMessage *message); +private: + void InitWindow(void); + ModemView* aModemview; + + BButton *btnModemWindowCustom; + BButton *btnModemWindowCancel; + BButton *btnModemWindowDone; + + BMenu *YourModemIsMenu; + BMenuField *YourModemIsMenuField; + BMenu *ConnectViaMenu; + BMenuField *ConnectViaMenuField; + BMenu *SpeedMenu; + BMenuField *SpeedMenuField; + + BTextView *tvRedial; + BTextView *tvTimesBusySignal; + BTextView *tvReadLogPath; + BTextView *tvWriteLogPath; + + BCheckBox *chkMakeConnection; + BCheckBox *chkShowTerminal; + BCheckBox *chkLogAll; +}; + +#endif diff --git a/src/prefs/fonts/.doxygen-conf b/src/prefs/fonts/.doxygen-conf new file mode 100644 index 0000000000..857103cc88 --- /dev/null +++ b/src/prefs/fonts/.doxygen-conf @@ -0,0 +1,691 @@ +# Doxyfile 1.2.1 + +# This file describes the settings to be used by doxygen for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = "Fonts Preferences App" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 1 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = ../docs/api/ + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Dutch, French, Italian, Czech, Swedish, German, Finnish, Japanese, +# Spanish, Russian, Croatian, Polish, and Portuguese. + +OUTPUT_LANGUAGE = English + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these class will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = YES + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. It is allowed to use relative paths in the argument list. + +STRIP_FROM_PATH = + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a class diagram (in Html and LaTeX) for classes with base or +# super classes. Setting the tag to NO turns the diagrams off. + +CLASS_DIAGRAMS = YES + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the CASE_SENSE_NAMES tag is set to NO (the default) then Doxygen +# will only generate file names in lower case letters. If set to +# YES upper case letters are also allowed. This is useful if you have +# classes or files whose names only differ in case and if your file system +# supports case sensitive file names. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the JAVADOC_AUTOBRIEF tag is set to YES (the default) then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the Javadoc-style will +# behave just like the Qt-style comments. + +JAVADOC_AUTOBRIEF = YES + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# reimplements. + +INHERIT_DOCS = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# The ENABLE_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. + +WARN_FORMAT = "$file:$line: $text" + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = . + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +FILE_PATTERNS = *.cpp *.h + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. + +EXCLUDE_PATTERNS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. + +INPUT_FILTER = + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimised for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using a WORD or other. +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assigments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. Warning: This feature +# is still experimental and very incomplete. + +GENERATE_XML = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_PREDEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +#--------------------------------------------------------------------------- +# Configuration::addtions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tagfiles. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the ENABLE_PREPROCESSING, INCLUDE_GRAPH, and HAVE_DOT tags are set to +# YES then doxygen will generate a graph for each documented file showing +# the direct and indirect include dependencies of the file with other +# documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, INCLUDED_BY_GRAPH, and HAVE_DOT tags are set to +# YES then doxygen will generate a graph for each documented header file showing +# the documented files that directly or indirectly include this file + +INCLUDED_BY_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found on the path. + +DOT_PATH = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO + +# The CGI_NAME tag should be the name of the CGI script that +# starts the search engine (doxysearch) with the correct parameters. +# A script with this name will be generated by doxygen. + +CGI_NAME = search.cgi + +# The CGI_URL tag should be the absolute URL to the directory where the +# cgi binaries are located. See the documentation of your http daemon for +# details. + +CGI_URL = + +# The DOC_URL tag should be the absolute URL to the directory where the +# documentation is located. If left blank the absolute path to the +# documentation, with file:// prepended to it, will be used. + +DOC_URL = + +# The DOC_ABSPATH tag should be the absolute path to the directory where the +# documentation is located. If left blank the directory on the local machine +# will be used. + +DOC_ABSPATH = + +# The BIN_ABSPATH tag must point to the directory where the doxysearch binary +# is installed. + +BIN_ABSPATH = /usr/local/bin/ + +# The EXT_DOC_PATHS tag can be used to specify one or more paths to +# documentation generated for other projects. This allows doxysearch to search +# the documentation for these projects as well. + +EXT_DOC_PATHS = diff --git a/src/prefs/fonts/ButtonView.cpp b/src/prefs/fonts/ButtonView.cpp new file mode 100644 index 0000000000..e06138c0bd --- /dev/null +++ b/src/prefs/fonts/ButtonView.cpp @@ -0,0 +1,76 @@ +/*! \file ButtonView.cpp + * \brief Code for the ButtonView. + */ + +#ifndef BUTTON_VIEW_H + + #include "ButtonView.h" + +#endif + +/** + * Constructor + * @param rect The size of the view. + */ +ButtonView::ButtonView(BRect rect) + : BView(rect, "ButtonView", B_FOLLOW_ALL, B_WILL_DRAW) +{ + + float x; + float y; + BRect viewSize = Bounds(); + BButton *rescanButton; + BButton *defaultsButton; + + x = viewSize.Width() / 37; + y = viewSize.Height() / 6; + + SetViewColor(216,216,216,0); + + rescanButton = new BButton(*(new BRect(x, y, (9.0 * x), (4.0 * y))), + "rescanButton", + "Rescan", + new BMessage(RESCAN_FONTS_MSG), + B_FOLLOW_LEFT, + B_WILL_DRAW + ); + defaultsButton = new BButton(*(new BRect((11.0 * x), y, (19.0 * x), (4.0 * y))), + "defaultsButton", + "Defaults", + new BMessage(RESET_FONTS_MSG), + B_FOLLOW_LEFT, + B_WILL_DRAW + ); + revertButton = new BButton(*(new BRect((20.0 * x), y, (28.0 * x), (4.0 * y))), + "revertButton", + "Revert", + new BMessage(REVERT_MSG), + B_FOLLOW_LEFT, + B_WILL_DRAW + ); + + revertButton->SetEnabled(false); + + AddChild(rescanButton); + AddChild(defaultsButton); + AddChild(revertButton); + +} + +/** + * Returns the state of the revert button. + */ +bool ButtonView::RevertState(){ + + return revertButton->IsEnabled(); + +}//RevertState + +/** + * Sets the state of the revert button. + */ +void ButtonView::SetRevertState(bool b){ + + revertButton->SetEnabled(b); + +}//SetRevertState \ No newline at end of file diff --git a/src/prefs/fonts/ButtonView.h b/src/prefs/fonts/ButtonView.h new file mode 100644 index 0000000000..0fdb39089e --- /dev/null +++ b/src/prefs/fonts/ButtonView.h @@ -0,0 +1,53 @@ +/*! \file ButtonView.h + * \brief Header file for the ButtonView class. + */ + +#ifndef BUTTON_VIEW_H + + #define BUTTON_VIEW_H + + /*! + * Message sent when the rescan button is sent. + */ + #define RESCAN_FONTS_MSG 'rscn' + + /*! + * Message sent when the reset button is sent. + */ + #define RESET_FONTS_MSG 'rset' + + /*! + * Message sent when the revert button is sent. + */ + #define REVERT_MSG 'rvrt' + + #ifndef _VIEW_H + + #include + + #endif + + #ifndef _BUTTON_H + + #include + + #endif + + class ButtonView : public BView{ + + public: + + ButtonView(BRect frame); + bool RevertState(); + void SetRevertState(bool b); + + private: + + /** + * The revert button. + */ + BButton *revertButton; + + }; + +#endif diff --git a/src/prefs/fonts/CacheView.cpp b/src/prefs/fonts/CacheView.cpp new file mode 100644 index 0000000000..327da20953 --- /dev/null +++ b/src/prefs/fonts/CacheView.cpp @@ -0,0 +1,163 @@ +/*! \file CacheView.cpp + * \brief The file that contains code for the CacheView. + */ +#ifndef CACHE_VIEW_H + + #include "CacheView.h" + +#endif + +/** + * Constructor + * @param rect The size of the view. + * @param minVal The minimum value of the cache sliders. + * @param maxVal The maximum value of the cache sliders. + * @param printCurrVal The starting value of the print slider. + * @param screenCurrVal The starting value of the screen slider. + */ +CacheView::CacheView(BRect rect, int minVal, int maxVal, int32 printCurrVal, int32 screenCurrVal) + : BView(rect, "CacheView", B_FOLLOW_ALL, B_WILL_DRAW) +{ + + float x; + float y; + BRect viewSize = Bounds(); + char sliderMinLabel[10]; + char sliderMaxLabel[10]; + char msg[100]; + + origPrintVal = printCurrVal; + origScreenVal = screenCurrVal; + SetViewColor(216, 216, 216, 0); + + rgb_color fillColor; + fillColor.red = 0; + fillColor.blue = 152; + fillColor.green = 102; + + viewSize.InsetBy(15, 10); + + sprintf(msg, "Screen font cache size : %d kB", screenCurrVal); + + screenFCS = new BSlider(*(new BRect(viewSize.left, viewSize.top, viewSize.right, viewSize.top + 25.0)), + "screenFontCache", + msg, + new BMessage(SCREEN_FCS_UPDATE_MSG), + minVal, + maxVal, + B_TRIANGLE_THUMB + ); + screenFCS->SetModificationMessage(new BMessage(SCREEN_FCS_MODIFICATION_MSG)); + + sprintf(sliderMinLabel, "%d kB", minVal); + sprintf(sliderMaxLabel, "%d kB", maxVal); + screenFCS->SetLimitLabels(sliderMinLabel, sliderMaxLabel); + screenFCS->UseFillColor(TRUE, &fillColor); + screenFCS->SetValue(screenCurrVal); + + viewSize.top = viewSize.top + 65.0; + + sprintf(msg, "Printing font cache size : %d kB", printCurrVal); + + printFCS = new BSlider(*(new BRect(viewSize.left, viewSize.top, viewSize.right, viewSize.top + 25.0)), + "printFontCache", + msg, + new BMessage(PRINT_FCS_UPDATE_MSG), + minVal, + maxVal, + B_TRIANGLE_THUMB + ); + printFCS->SetModificationMessage(new BMessage(PRINT_FCS_MODIFICATION_MSG)); + + printFCS->SetLimitLabels(sliderMinLabel, sliderMaxLabel); + printFCS->UseFillColor(TRUE, &fillColor); + printFCS->SetValue(printCurrVal); + + viewSize.top = viewSize.top + 70.0; + + BButton *saveCache = new BButton(*(new BRect(viewSize.left, viewSize.top, 100.0, 20.0)), + "saveCache", + "Save Cache", + NULL, + B_FOLLOW_LEFT, + B_WILL_DRAW + ); + + AddChild(screenFCS); + AddChild(printFCS); + AddChild(saveCache); + +} + +/** + * Updates the label on the print slider. + * @param txt The text to update the slider to. + */ +void CacheView::updatePrintFCS(const char* txt){ + + printFCS->SetLabel(txt); + +}//updatePrintFCS + +/** + * Updates the label on the screen slider. + * @param txt The text to update the slider to. + */ +void CacheView::updateScreenFCS(const char* txt){ + + screenFCS->SetLabel(txt); + +}//updatePrintFCS + +/** + * Gets the current value of the print slider. + */ +int CacheView::getPrintFCSValue(){ + + return int(printFCS->Value()); + +}//getPrintValue + +/** + * Gets the current value of the screen slider. + */ +int CacheView::getScreenFCSValue(){ + + return int(screenFCS->Value()); + +}//getPrintValue + +/** + * Sets the sliders to their original values. + */ +void CacheView::revertToOriginal(){ + + char msg[100]; + + screenFCS->SetValue(origScreenVal); + sprintf(msg, "Screen font cache size : %d kB", getScreenFCSValue()); + updateScreenFCS(msg); + + printFCS->SetValue(origPrintVal); + sprintf(msg, "Printing font cache size : %d kB", getPrintFCSValue()); + updatePrintFCS(msg); + +}//revertToOriginal + +/** + * Sets the sliders to their default values. + */ +void CacheView::resetToDefaults(){ + + char msg[100]; + + screenFCS->SetValue((int32) 256); + sprintf(msg, "Screen font cache size : %d kB", getScreenFCSValue()); + updateScreenFCS(msg); + + printFCS->SetValue((int32) 256); + sprintf(msg, "Printing font cache size : %d kB", getPrintFCSValue()); + updatePrintFCS(msg); + +}//revertToOriginal + diff --git a/src/prefs/fonts/CacheView.h b/src/prefs/fonts/CacheView.h new file mode 100644 index 0000000000..e067713ccd --- /dev/null +++ b/src/prefs/fonts/CacheView.h @@ -0,0 +1,92 @@ +/*! \file CacheView.h + * \brief Header file for the CacheView class. + */ + +#ifndef CACHE_VIEW_H + + #define CACHE_VIEW_H + + /*! + * Message sent when the print slider is updated. + */ + #define PRINT_FCS_UPDATE_MSG 'pfum' + + /*! + * Message sent when the screen slider is updated. + */ + #define SCREEN_FCS_UPDATE_MSG 'sfum' + + /*! + * Message sent when the print slider is modified. + */ + #define PRINT_FCS_MODIFICATION_MSG 'pfmm' + + /*! + * Message sent when the screen slider is modified. + */ + #define SCREEN_FCS_MODIFICATION_MSG 'sfmm' + + #ifndef _VIEW_H + + #include + + #endif + + #ifndef _BOX_H + + #include + + #endif + #ifndef _SLIDER_H + + #include + + #endif + #ifndef _STDIO_H + + #include + + #endif + #ifndef _BUTTON_H + + #include + + #endif + + class CacheView : public BView{ + + public: + + CacheView(BRect frame, int minVal, int maxVal, int32 printCurrVal, int32 screenCurrVal); + void updatePrintFCS(const char* txt); + void updateScreenFCS(const char* txt); + int getPrintFCSValue(); + int getScreenFCSValue(); + void revertToOriginal(); + void resetToDefaults(); + + private: + + /** + * The screen cache slider. + */ + BSlider *screenFCS; + + /** + * The print cache slider. + */ + BSlider *printFCS; + + /** + * The original print slider value. + */ + int32 origPrintVal; + + /** + * The original screen slider value. + */ + int32 origScreenVal; + + }; + +#endif diff --git a/src/prefs/fonts/FontSelectionView.cpp b/src/prefs/fonts/FontSelectionView.cpp new file mode 100644 index 0000000000..312910f279 --- /dev/null +++ b/src/prefs/fonts/FontSelectionView.cpp @@ -0,0 +1,490 @@ +/*! \file FontSelectionView.cpp + \brief Header for the FontSelectionView class. + +*/ + +#ifndef FONT_SELECTION_VIEW_H + + #include "FontSelectionView.h" + +#endif + +/** + * Constructor + * @param rect The size of the view. + * @param name The name of the view. + * @param type The type of the view: plain, italic, etc. + */ +FontSelectionView::FontSelectionView(BRect rect, const char *name, int type) + : BView(rect, name, B_FOLLOW_ALL, B_WILL_DRAW) +{ + + BBox *testTextBox; + float x; + float y; + BRect viewSize = Bounds(); + BMenuField *fontListField; + BMenuField *sizeListField; + + x = viewSize.Width() / 37; + y = viewSize.Height() / 8; + + minSizeIndex = 9; + maxSizeIndex = 12; + + switch(type){ + + case PLAIN_FONT_SELECTION_VIEW: + + sprintf(typeLabel, "Plain font"); + origFont = be_plain_font; + workingFont = be_plain_font; + setSizeChangedMessage = PLAIN_SIZE_CHANGED_MSG; + setFontChangedMessage = PLAIN_FONT_CHANGED_MSG; + setStyleChangedMessage = PLAIN_STYLE_CHANGED_MSG; + + defaultFont = new BFont(); + defaultFont->SetFamilyAndStyle("Swis721 BT", "Roman"); + defaultFont->SetSize(10.0); + + break; + + case BOLD_FONT_SELECTION_VIEW: + + sprintf(typeLabel, "Bold font"); + origFont = be_bold_font; + workingFont = be_bold_font; + setSizeChangedMessage = BOLD_SIZE_CHANGED_MSG; + setFontChangedMessage = BOLD_FONT_CHANGED_MSG; + setStyleChangedMessage = BOLD_STYLE_CHANGED_MSG; + + defaultFont = new BFont(); + defaultFont->SetFamilyAndStyle("Swis721 BT", "Bold"); + defaultFont->SetSize(12.0); + + break; + + case FIXED_FONT_SELECTION_VIEW: + + sprintf(typeLabel, "Fixed font"); + origFont = be_fixed_font; + workingFont = be_fixed_font; + setSizeChangedMessage = FIXED_SIZE_CHANGED_MSG; + setFontChangedMessage = FIXED_FONT_CHANGED_MSG; + setStyleChangedMessage = FIXED_STYLE_CHANGED_MSG; + + defaultFont = new BFont(); + defaultFont->SetFamilyAndStyle("Courier10 BT", "Roman"); + defaultFont->SetSize(12.0); + + break; + + }//switch + + sizeList = new BPopUpMenu("sizeList", true, true, B_ITEMS_IN_COLUMN); + fontList = new BPopUpMenu("fontList", true, true, B_ITEMS_IN_COLUMN); + fontListField = new BMenuField(*(new BRect(x, y, (25 * x), (3 * y))), "fontField", typeLabel, fontList); + fontListField->SetDivider(7 * x); + sizeListField = new BMenuField(*(new BRect((27 * x), y, (36 * x), (3 * y))), "fontField", "Size", sizeList); + sizeListField->SetDivider(31 * x); + testText = new BStringView(*(new BRect((8 * x), (5 * y), (35 * x), (8 * y))), "testText", "The quick brown fox jumped over the lazy dog.", B_FOLLOW_ALL, B_WILL_DRAW); + testText->SetFont(&workingFont); + testTextBox = new BBox(*(new BRect((8 * x), (5 * y), (36 * x), (8 * y))), "TestTextBox", B_FOLLOW_ALL, B_WILL_DRAW, B_FANCY_BORDER); + + fontList->SetLabelFromMarked(true); + + buildMenus(); + + SetViewColor(216, 216, 216, 0); + + AddChild(testTextBox); + AddChild(testText); + AddChild(sizeListField); + AddChild(fontListField); + +} + +/** + * Emptys the menu so it can be rebuilt. + * @param m The menu to empty. + */ +void FontSelectionView::emptyMenu(BPopUpMenu *m){ + + int32 cnt; + int32 numItemsInMenu = m->CountItems(); + + for(cnt = 0;cnt < numItemsInMenu;cnt++){ + + BMenu *tmp; + BMenuItem *tmpI; + int32 cnt2; + int32 numItemsInSubmenu; + + tmpI = m->RemoveItem((int32) 0); + tmp = tmpI->Submenu(); + + if(tmp != NULL){ + + numItemsInSubmenu = tmp->CountItems(); + for(cnt2 = 0;cnt2 < numItemsInSubmenu;cnt2++){ + + BMenuItem *tmpItem; + + tmpItem = tmp->RemoveItem((int32) 0); + delete tmpItem; + + }//for + + }//if + + delete tmpI; + + }//for + +}//emptyMenu + +/** + * Emptys both the font and the size menus. + */ +void FontSelectionView::emptyMenus(){ + + //empty font menu + emptyMenu(fontList); + + //empty size menu + emptyMenu(sizeList); + +}//emptyMenus + +/** + * Builds the font and size menus. + */ +void FontSelectionView::buildMenus(){ + + int32 numFamilies; + int counter; + + numFamilies = count_font_families(); + for ( int32 i = 0; i < numFamilies; i++ ) { + + font_family family; + uint32 flags; + + if ( get_font_family(i, &family, &flags) == B_OK ) { + + BMenu *tmpStyleMenu; + int32 numStyles; + bool markFamily; + + markFamily = false; + + tmpStyleMenu = new BMenu(family); + tmpStyleMenu->SetRadioMode(true); + numStyles = count_font_styles(family); + for ( int32 j = 0; j < numStyles; j++ ) { + + font_style style; + if ( get_font_style(family, j, &style, &flags) == B_OK ) { + + BMenuItem *tmpItem; + char workingStyle[64]; + char workingFamily[64]; + + workingFont.GetFamilyAndStyle(&workingFamily, &workingStyle); + tmpItem = new BMenuItem(style, new BMessage(setStyleChangedMessage)); + if((strcmp(style, workingStyle) == 0) && (strcmp(family, workingFamily) == 0)){ + + markFamily = true; + tmpItem->SetMarked(true); + + }//if + + tmpStyleMenu->AddItem(tmpItem); + + }//if + + }//for + + fontList->AddItem(new BMenuItem((tmpStyleMenu), new BMessage(setFontChangedMessage))); + + if(markFamily){ + + tmpStyleMenu->Superitem()->SetMarked(true); + + }//if + + }//if + + }//for + + //build size menu + for(counter = minSizeIndex;counter < (maxSizeIndex + 1);counter++){ + + char buf[1]; + BMenuItem *tmp; + + sprintf(buf, "%d", counter); + sizeList->AddItem(tmp = new BMenuItem(buf, new BMessage(setSizeChangedMessage))); + if(counter == (int) workingFont.Size()){ + + tmp->SetMarked(true); + + }//if + + }//for + +}//buildMenus + +/** + * Writes the test text in the given font. + * @param fnt The font to write the test text in. + */ +void FontSelectionView::SetTestTextFont(BFont *fnt){ + + testText->SetFont(fnt, B_FONT_ALL); + testText->Invalidate(); + +}//SetTextTextFont + +/** + * Gets the current font. + */ +BFont FontSelectionView::GetTestTextFont(){ + + BFont rtrnFont; + + testText->GetFont(&rtrnFont); + + return rtrnFont; + +}//SetTextTextFont + +/** + * Gets the selected size. + */ +float FontSelectionView::GetSelectedSize(){ + + return minSizeIndex + sizeList->IndexOf(sizeList->FindMarked()); + +}//GetSelectedSize + +/** + * Gets the selected font_family. + * @param family The selected font_family. + */ +void FontSelectionView::GetSelectedFont(font_family *family){ + + int numFamilies = count_font_families(); + for ( int32 i = 0; i < numFamilies; i++ ) { + + font_family fam; + uint32 flags; + + if ( get_font_family(i, &fam, &flags) == B_OK ) { + + if(strcmp(fam, fontList->FindMarked()->Label()) == 0){ + + get_font_family(i, family, &flags); + + }//if + + }//if + + }//for + +}//GetSelectedFont + +/** + * Gets the selected style. + * @param style The selected style. + */ +void FontSelectionView::GetSelectedStyle(font_style *style){ + + int numFamilies = count_font_families(); + font_family curr; + + GetSelectedFont(&curr); + + for ( int32 i = 0; i < numFamilies; i++ ) { + + font_family fam; + uint32 flags; + + if ( get_font_family(i, &fam, &flags) == B_OK ) { + + if(strcmp(fam, curr) == 0){ + + int32 numStyles = count_font_styles(fam); + for ( int32 j = 0; j < numStyles; j++ ) { + + font_style sty; + if ( get_font_style(fam, j, &sty, &flags) == B_OK ) { + + if(strcmp(sty, fontList->FindMarked()->Submenu()->FindMarked()->Label()) == 0){ + + get_font_style(fam, j, style, &flags); + + }//if + + }//if + + }//for + + }//if + + }//if + + }//for + +}//GetSelectedStyle + +/** + * If a style is selected, this function is called to update the font menu, + * in case the selected style is from a non selected font. It also marks the + * selected style, and unmarks all other styles. + */ +void FontSelectionView::UpdateFontSelectionFromStyle(){ + + int i = 0; + + for(i = 0;i < fontList->CountItems();i++){ + + int j = 0; + + for(j = 0;j < fontList->ItemAt(i)->Submenu()->CountItems();j++){ + + if(fontList->ItemAt(i)->Submenu()->ItemAt(j)->IsMarked()){ + + if(!strcmp(fontList->ItemAt(i)->Label(), fontList->FindMarked()->Label()) == 0){ + + fontList->FindMarked()->Submenu()->FindMarked()->SetMarked(false); + fontList->ItemAt(i)->SetMarked(true); + + }//if + + }//if + + }//for + + }//for + +}//UpdateFontSelection + +/** + * Updates the font menu based on the user selection. + */ +void FontSelectionView::UpdateFontSelection(){ + + int i = 0; + + for(i = 0;i < fontList->CountItems();i++){ + + int j = 0; + + for(j = 0;j < fontList->ItemAt(i)->Submenu()->CountItems();j++){ + + if(fontList->ItemAt(i)->Submenu()->ItemAt(j)->IsMarked()){ + + if(strcmp(fontList->ItemAt(i)->Label(), fontList->FindMarked()->Label()) > 0){ + + fontList->ItemAt(i)->Submenu()->FindMarked()->SetMarked(false); + fontList->FindMarked()->Submenu()->ItemAt(0)->SetMarked(true); + + }//if + + }//if + + }//for + + }//for + +}//UpdateFontSelection + +/** + * Updates the font and size menus based on the given font. + * @param fnt The font to set the menus to. + * \note This methd needs rewriting BADLY - it's horribly written + */ +void FontSelectionView::UpdateFontSelection(BFont *fnt){ + + int i = 0; + char style[64]; + char family[64]; + + fnt->GetFamilyAndStyle(&family, &style); + + for(i = 0;i < fontList->CountItems();i++){ + + int j = 0; + + if(strcmp(fontList->ItemAt(i)->Label(), family) == 0){ + + fontList->ItemAt(i)->SetMarked(true); + + }//if + + for(j = 0;j < fontList->ItemAt(i)->Submenu()->CountItems();j++){ + + if(fontList->ItemAt(i)->Submenu()->ItemAt(j)->IsMarked()){ + + fontList->ItemAt(i)->Submenu()->ItemAt(j)->SetMarked(false); + + }//if + if(strcmp(fontList->ItemAt(i)->Label(), family) == 0){ + + if(strcmp(fontList->ItemAt(i)->Submenu()->ItemAt(j)->Label(), style) == 0){ + + fontList->ItemAt(i)->Submenu()->ItemAt(j)->SetMarked(true); + + }//if + + }//if + + }//for + + }//for + + //Update size menu + for(i = 0;i < sizeList->CountItems();i++){ + + char size[1]; + + sprintf(size, "%d", (int)fnt->Size()); + if(strcmp(sizeList->ItemAt(i)->Label(), size) == 0){ + + sizeList->ItemAt(i)->SetMarked(true); + + }//if + + }//for + +}//UpdateFontSelection + +/** + * Resets the test text to the default font. + */ +void FontSelectionView::resetToDefaults(){ + + //Update menus + UpdateFontSelection(defaultFont); + + //Update test text + SetTestTextFont(defaultFont); + +}//resetToDefaults + +/** + * Resets the test text to the original font. + */ +void FontSelectionView::revertToOriginal(){ + + //Update menus + UpdateFontSelection(&origFont); + + //Update test text + SetTestTextFont(&origFont); + +}//resetToDefaults + + + diff --git a/src/prefs/fonts/FontSelectionView.h b/src/prefs/fonts/FontSelectionView.h new file mode 100644 index 0000000000..f4f3028fd1 --- /dev/null +++ b/src/prefs/fonts/FontSelectionView.h @@ -0,0 +1,188 @@ +/*! \file FontSelectionView.h + \brief Header for the FontSelectionView class. + +*/ + +#ifndef FONT_SELECTION_VIEW_H + + #define FONT_SELECTION_VIEW_H + + /*! + * Constant to define that the view is a plain view. + */ + #define PLAIN_FONT_SELECTION_VIEW 1 + /*! + * Constant to define that the view is a bold view. + */ + #define BOLD_FONT_SELECTION_VIEW 2 + /*! + * Constant to define that the view is a fixed view. + */ + #define FIXED_FONT_SELECTION_VIEW 3 + + /*! + * The plain size menu was changed. + */ + #define PLAIN_SIZE_CHANGED_MSG 'plsz' + /*! + * The bold size menu was changed. + */ + #define BOLD_SIZE_CHANGED_MSG 'blsz' + /*! + * The fixed size menu was changed. + */ + #define FIXED_SIZE_CHANGED_MSG 'fxsz' + + /*! + * The plain font menu was changed. + */ + #define PLAIN_FONT_CHANGED_MSG 'plfn' + /*! + * The bold font menu was changed. + */ + #define BOLD_FONT_CHANGED_MSG 'blfn' + /*! + * The fixed font menu was changed. + */ + #define FIXED_FONT_CHANGED_MSG 'fxfn' + + /*! + * The plain style menu was changed. + */ + #define PLAIN_STYLE_CHANGED_MSG 'plst' + /*! + * The bold style menu was changed. + */ + #define BOLD_STYLE_CHANGED_MSG 'blst' + /*! + * The fixed style menu was changed. + */ + #define FIXED_STYLE_CHANGED_MSG 'fxst' + + #ifndef _VIEW_H + + #include + + #endif + + #ifndef _BOX_H + + #include + + #endif + + #ifndef _STRING_VIEW_H + + #include + + #endif + + #ifndef _POP_UP_MENU_H + + #include + + #endif + + #ifndef _MENU_FIELD_H + + #include + + #endif + + #ifndef _MENU_ITEM_H + + #include + + #endif + #ifndef _STDIO_H + + #include + + #endif + + class FontSelectionView : public BView{ + + public: + + FontSelectionView(BRect rect, const char *name, int type); + void SetTestTextFont(BFont *fnt); + BFont GetTestTextFont(); + float GetSelectedSize(); + void GetSelectedFont(font_family *family); + void GetSelectedStyle(font_style *style); + void UpdateFontSelectionFromStyle(); + void UpdateFontSelection(); + void buildMenus(); + void emptyMenus(); + void resetToDefaults(); + void revertToOriginal(); + + private: + + /** + * The test text display view. + */ + BStringView *testText; + + /** + * The font menu. + */ + BPopUpMenu *fontList; + + /** + * The size menu. + */ + BPopUpMenu *sizeList; + + /** + * The minimum font size allowed. + */ + int minSizeIndex; + + /** + * The maximum font size allowed. + */ + int maxSizeIndex; + + /** + * The message sent when the size menu is changed. + */ + uint32 setSizeChangedMessage; + + /** + * The message sent when the font menu is changed. + */ + uint32 setFontChangedMessage; + + /** + * The message sent when the style menu is changed. + */ + uint32 setStyleChangedMessage; + + /** + * The label that shows what type the view is. + */ + char typeLabel[30]; + + /** + * The original font, set when the view is instantiated. + */ + BFont origFont; + + /** + * The current font. + */ + BFont workingFont; + + /** + * The default font. + */ + BFont *defaultFont; + + void emptyMenu(BPopUpMenu *m); + void UpdateFontSelection(BFont *fnt); + + + }; + +#endif diff --git a/src/prefs/fonts/FontView.cpp b/src/prefs/fonts/FontView.cpp new file mode 100644 index 0000000000..4db7a8707c --- /dev/null +++ b/src/prefs/fonts/FontView.cpp @@ -0,0 +1,86 @@ +/*! \file FontView.cpp + \brief Header for the FontView class. + +*/ + +#ifndef FONT_VIEW_H + + #include "FontView.h" + +#endif + +/** + * Constructor. + * @param rect The size of the view. + */ +FontView::FontView(BRect rect) + : BView(rect, "FontView", B_FOLLOW_ALL, B_WILL_DRAW) +{ + + float x; + float y; + BRect viewSize = Bounds(); + + SetViewColor(216, 216, 216, 0); + + x = viewSize.Width() / 39; + y = viewSize.Height() / 25; + + plainSelectionView = new FontSelectionView(*(new BRect(x, y, (38.0 * x), (8.0 * y))), "Plain", PLAIN_FONT_SELECTION_VIEW); + boldSelectionView = new FontSelectionView(*(new BRect(x, (9.0 * y), (38.0 * x), (16.0 * y))), "Bold", BOLD_FONT_SELECTION_VIEW); + fixedSelectionView = new FontSelectionView(*(new BRect(x, (17.0 * y), (38.0 * x), (24.0 * y))), "Fixed", FIXED_FONT_SELECTION_VIEW); + + AddChild(plainSelectionView); + AddChild(boldSelectionView); + AddChild(fixedSelectionView); + +} + +/** + * Calls each FontSelectionView's buildMenus() function to build the + * font and size menus. + */ +void FontView::buildMenus(){ + + plainSelectionView->buildMenus(); + boldSelectionView->buildMenus(); + fixedSelectionView->buildMenus(); + +}//buildMenus + +/** + * Calls each FontSelectionView's emptyMenus() function to clear the + * font and size menus. + */ +void FontView::emptyMenus(){ + + plainSelectionView->emptyMenus(); + boldSelectionView->emptyMenus(); + fixedSelectionView->emptyMenus(); + +}//buildMenus + +/** + * Calls each FontSelectionView's resetToDefaults() function to reset + * the font and size menus to the default font. + */ +void FontView::resetToDefaults(){ + + plainSelectionView->resetToDefaults(); + boldSelectionView->resetToDefaults(); + fixedSelectionView->resetToDefaults(); + +}//resetToDefaults + +/** + * Calls each FontSelectionView's revertToOriginal() function to reset + * the font and size menus to the original font. + */ +void FontView::revertToOriginal(){ + + plainSelectionView->revertToOriginal(); + boldSelectionView->revertToOriginal(); + fixedSelectionView->revertToOriginal(); + +}//resetToDefaults + diff --git a/src/prefs/fonts/FontView.h b/src/prefs/fonts/FontView.h new file mode 100644 index 0000000000..3d34606fb1 --- /dev/null +++ b/src/prefs/fonts/FontView.h @@ -0,0 +1,43 @@ +/*! \file FontView.h + \brief Header for the FontView class. + +*/ + +#ifndef FONT_VIEW_H + + #define FONT_VIEW_H + + #ifndef _VIEW_H + + #include + + #endif + + #ifndef FONT_SELECTION_VIEW_H + + #include "FontSelectionView.h" + + #endif + + #ifndef _BOX_H + + #include + + #endif + + class FontView : public BView{ + + public: + + FontView(BRect frame); + FontSelectionView *plainSelectionView; + FontSelectionView *boldSelectionView; + FontSelectionView *fixedSelectionView; + void buildMenus(); + void emptyMenus(); + void resetToDefaults(); + void revertToOriginal(); + + }; + +#endif diff --git a/src/prefs/fonts/MainWindow.cpp b/src/prefs/fonts/MainWindow.cpp new file mode 100644 index 0000000000..a1177a059e --- /dev/null +++ b/src/prefs/fonts/MainWindow.cpp @@ -0,0 +1,237 @@ +/*! \file MainWindow.cpp + * \brief Code for the main window. + * + * Displays the main window. + * +*/ + +#ifndef MAIN_WINDOW_H + + #include "MainWindow.h" + +#endif + +/** + * Constructor. + * @param frame The size to make the window. + */ +MainWindow::MainWindow(BRect frame) + : BWindow(frame, "Fonts", B_TITLED_WINDOW, B_NOT_RESIZABLE | B_ASYNCHRONOUS_CONTROLS | B_NOT_ZOOMABLE ){ + + BRect r; + BTabView *tabView; + BTab *tab; + BBox *topLevelView; + double buttonViewHeight = 38.0; + + r = Bounds(); + r.InsetBy(0, 10); + r.bottom -= buttonViewHeight; + + tabView = new BTabView(r, "tab_view", B_WIDTH_FROM_WIDEST); + tabView->SetViewColor(216,216,216,0); + + r = tabView->Bounds(); + r.InsetBy(5,5); + r.bottom -= tabView->TabHeight(); + tab = new BTab(); + tabView->AddTab(fontPanel = new FontView(r), tab); + tab->SetLabel("Fonts"); + tab = new BTab(); + tabView->AddTab(cachePanel = new CacheView(r, 64, 4096, (int32) 256, (int32) 256), tab); + tab->SetLabel("Cache"); + + r = Bounds(); + r.top = r.bottom - buttonViewHeight; + + buttonView = new ButtonView(r); + + topLevelView = new BBox(Bounds(), "TopLevelView", B_FOLLOW_ALL, B_WILL_DRAW, B_NO_BORDER); + + AddChild(buttonView); + AddChild(tabView); + AddChild(topLevelView); + +} + +/** + * Runs when the user quits the application. + */ +bool MainWindow::QuitRequested() +{ + be_app->PostMessage(B_QUIT_REQUESTED); + return(true); +} + +/** + * Handles messages sent to the class. + * @param message The message to be handled. + */ +void MainWindow::MessageReceived(BMessage *message){ + + char msg[100]; + + switch(message->what){ + + case PLAIN_SIZE_CHANGED_MSG: + + updateSize(fontPanel->plainSelectionView); + buttonView->SetRevertState(true); + break; + + case BOLD_SIZE_CHANGED_MSG: + + updateSize(fontPanel->boldSelectionView); + buttonView->SetRevertState(true); + break; + + case FIXED_SIZE_CHANGED_MSG: + + updateSize(fontPanel->fixedSelectionView); + buttonView->SetRevertState(true); + break; + + case PLAIN_FONT_CHANGED_MSG: + + updateFont(fontPanel->plainSelectionView); + buttonView->SetRevertState(true); + break; + + case BOLD_FONT_CHANGED_MSG: + + updateFont(fontPanel->boldSelectionView); + buttonView->SetRevertState(true); + break; + + case FIXED_FONT_CHANGED_MSG: + + updateFont(fontPanel->fixedSelectionView); + buttonView->SetRevertState(true); + break; + + case PLAIN_STYLE_CHANGED_MSG: + + updateStyle(fontPanel->plainSelectionView); + buttonView->SetRevertState(true); + break; + + case BOLD_STYLE_CHANGED_MSG: + + updateStyle(fontPanel->boldSelectionView); + buttonView->SetRevertState(true); + break; + + case FIXED_STYLE_CHANGED_MSG: + + updateStyle(fontPanel->fixedSelectionView); + buttonView->SetRevertState(true); + break; + + case RESCAN_FONTS_MSG: + + update_font_families(false); + fontPanel->emptyMenus(); + fontPanel->buildMenus(); + updateFont(fontPanel->plainSelectionView); + updateFont(fontPanel->boldSelectionView); + updateFont(fontPanel->fixedSelectionView); + break; + + case RESET_FONTS_MSG: + + fontPanel->resetToDefaults(); + cachePanel->resetToDefaults(); + buttonView->SetRevertState(true); + break; + + case REVERT_MSG: + + fontPanel->revertToOriginal(); + cachePanel->revertToOriginal(); + buttonView->SetRevertState(false); + break; + + case PRINT_FCS_UPDATE_MSG: + + printf("print update message\n"); + //buttonView->SetRevertState(true); + break; + + case PRINT_FCS_MODIFICATION_MSG: + + sprintf(msg, "Printing font cache size : %d kB", cachePanel->getPrintFCSValue()); + cachePanel->updatePrintFCS(msg); + buttonView->SetRevertState(true); + break; + + case SCREEN_FCS_UPDATE_MSG: + + printf("screen update message\n"); + //buttonView->SetRevertState(true); + buttonView->SetRevertState(true); + break; + + case SCREEN_FCS_MODIFICATION_MSG: + + sprintf(msg, "Screen font cache size : %d kB", cachePanel->getScreenFCSValue()); + cachePanel->updateScreenFCS(msg); + buttonView->SetRevertState(true); + break; + + default: + + BWindow::MessageReceived(message); + + } + +} + +/** + * Sets the size of the test text when a new size is picked. + * @param theView The FontSelectionView that is affected. + */ +void MainWindow::updateSize(FontSelectionView *theView){ + + BFont workingFont; + + workingFont = theView->GetTestTextFont(); + workingFont.SetSize(theView->GetSelectedSize()); + theView->SetTestTextFont(&workingFont); + +}//updateSize + +/** + * Updates the test text to the selected font. + * @param theView The FontSelectionView that is affected. + */ +void MainWindow::updateFont(FontSelectionView *theView){ + + BFont workingFont; + font_family updateTo; + + theView->UpdateFontSelection(); + workingFont = theView->GetTestTextFont(); + theView->GetSelectedFont(&updateTo); + workingFont.SetFamilyAndStyle(updateTo, NULL); + theView->SetTestTextFont(&workingFont); + +}//updateFont + +/** + * Updates the test text to the selected style. + * @param theView The FontSelectionView that is affected. + */ +void MainWindow::updateStyle(FontSelectionView *theView){ + + BFont workingFont; + font_style updateTo; + font_family update; + + theView->UpdateFontSelectionFromStyle(); + workingFont = theView->GetTestTextFont(); + theView->GetSelectedStyle(&updateTo); + theView->GetSelectedFont(&update); + workingFont.SetFamilyAndStyle(update, updateTo); + theView->SetTestTextFont(&workingFont); + +}//updateStyle diff --git a/src/prefs/fonts/MainWindow.h b/src/prefs/fonts/MainWindow.h new file mode 100644 index 0000000000..ce327a0e7b --- /dev/null +++ b/src/prefs/fonts/MainWindow.h @@ -0,0 +1,82 @@ +/*! \file MainWindow.h + \brief Header for the MainWindow class. + +*/ + +#ifndef MAIN_WINDOW_H + + #define MAIN_WINDOW_H + + #ifndef _APPLICATION_H + + #include + + #endif + #ifndef _WINDOW_H + + #include + + #endif + #ifndef _TAB_VIEW_H + + #include + + #endif + + #ifndef FONT_VIEW_H + + #include "FontView.h" + + #endif + + #ifndef CACHE_VIEW_H + + #include "CacheView.h" + + #endif + + #ifndef BUTTON_VIEW_H + + #include "ButtonView.h" + + #endif + + #ifndef _BOX_H + + #include + + #endif + + class MainWindow : public BWindow{ + + public: + + MainWindow(BRect frame); + virtual bool QuitRequested(); + virtual void MessageReceived(BMessage *message); + + private: + + /** + * The panel that shows the font selection views. + */ + FontView *fontPanel; + + /** + * The panel that holds the default, revert and rescan buttons. + */ + ButtonView *buttonView; + + /** + * The panel that holds the sliders for adjusting the cache sizes. + */ + CacheView *cachePanel; + + void updateSize(FontSelectionView *theView); + void updateFont(FontSelectionView *theView); + void updateStyle(FontSelectionView *theView); + + }; + +#endif + diff --git a/src/prefs/fonts/Resource.rsrc b/src/prefs/fonts/Resource.rsrc new file mode 100644 index 0000000000..ef0d2a6b7e Binary files /dev/null and b/src/prefs/fonts/Resource.rsrc differ diff --git a/src/prefs/fonts/main.cpp b/src/prefs/fonts/main.cpp new file mode 100644 index 0000000000..57cbc0d57f --- /dev/null +++ b/src/prefs/fonts/main.cpp @@ -0,0 +1,59 @@ +/*! \file main.cpp + \brief Code for the main class. + +*/ + +#ifndef MAIN_WINDOW_H + + #include "MainWindow.h" + +#endif +#ifndef MAIN_H + + #include "main.h" + +#endif + +/** + * Main method. + * + * Starts the whole thing. + */ +int main(int, char**){ + + /** + * An instance of the application. + */ + Font_pref fontApp; + + fontApp.Run(); + + return(0); + +} + +/* + * Constructor. + * + * Provides a contstructor for the application. + */ +Font_pref::Font_pref() + :BApplication("application/x-vnd.MSM-FontPrefPanel"){ + + /* + * The main interface window. + */ + MainWindow *Main; + + /* + * Sets the size for the main window. + */ + BRect MainWindowRect; + + MainWindowRect.Set(100, 80, 450, 350); + Main = new MainWindow(MainWindowRect); + + Main->Show(); + +} + diff --git a/src/prefs/fonts/main.h b/src/prefs/fonts/main.h new file mode 100644 index 0000000000..7a2ca4d22d --- /dev/null +++ b/src/prefs/fonts/main.h @@ -0,0 +1,32 @@ +/*! \file main.h + \brief Header file for the main class. + +*/ + +#ifndef MAIN_H + + #define MAIN_H + + #ifndef _APPLICATION_H + + #include + + #endif + + /** + * Main class. + * + * Gets everything going. + */ + class Font_pref : public BApplication{ + + public: + + /** + * Constructor. + */ + Font_pref(); + + }; + +#endif \ No newline at end of file diff --git a/src/prefs/keyboard/Jamfile b/src/prefs/keyboard/Jamfile new file mode 100644 index 0000000000..4841522d77 --- /dev/null +++ b/src/prefs/keyboard/Jamfile @@ -0,0 +1,7 @@ +SubDir OBOS_TOP sources os kits input prefs keyboard ; + +Preference Keyboard : Keyboard.cpp KeyboardSettings.cpp KeyboardView.cpp KeyboardWindow.cpp ; + +LinkSharedOSLibs Keyboard : translation be root ; + +AddResources Keyboard : Keyboard.rsrc ; diff --git a/src/prefs/keyboard/Keyboard.cpp b/src/prefs/keyboard/Keyboard.cpp new file mode 100644 index 0000000000..e3f7289e37 --- /dev/null +++ b/src/prefs/keyboard/Keyboard.cpp @@ -0,0 +1,82 @@ +/* + * Keyboard.cpp + * Keyboard mccall@digitalparadise.co.uk + * + */ + +#include +#include + +#include "Keyboard.h" +#include "KeyboardWindow.h" +#include "KeyboardSettings.h" +#include "KeyboardMessages.h" + +const char KeyboardApplication::kKeyboardApplicationSig[] = "application/x-vnd.OpenBeOS-KYBD"; + +int main(int, char**) +{ + KeyboardApplication myApplication; + + myApplication.Run(); + + return(0); +} + +KeyboardApplication::KeyboardApplication() + :BApplication(kKeyboardApplicationSig) +{ + + KeyboardWindow *window; + + fSettings = new KeyboardSettings(); + + window = new KeyboardWindow(); + +} + +void +KeyboardApplication::MessageReceived(BMessage *message) +{ + switch(message->what) { + case ERROR_DETECTED: + { + BAlert *errorAlert = new BAlert("Error", "Something has gone wrong!","OK",NULL,NULL,B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_WARNING_ALERT); + errorAlert->Go(); + be_app->PostMessage(B_QUIT_REQUESTED); + } + break; + default: + BApplication::MessageReceived(message); + break; + } +} + +void +KeyboardApplication::SetWindowCorner(BPoint corner) +{ + fSettings->SetWindowCorner(corner); +} + +void +KeyboardApplication::SetKeyboardRepeatRate(int32 rate) +{ + fSettings->SetKeyboardRepeatRate(rate); +} + +void +KeyboardApplication::SetKeyboardRepeatDelay(int32 rate) +{ + fSettings->SetKeyboardRepeatDelay(rate); +} + +void +KeyboardApplication::AboutRequested(void) +{ + (new BAlert("about", "...by Andrew Edward McCall", "Dig Deal"))->Go(); +} + +KeyboardApplication::~KeyboardApplication() +{ + delete fSettings; +} \ No newline at end of file diff --git a/src/prefs/keyboard/Keyboard.h b/src/prefs/keyboard/Keyboard.h new file mode 100644 index 0000000000..ff207b3ca4 --- /dev/null +++ b/src/prefs/keyboard/Keyboard.h @@ -0,0 +1,33 @@ +#ifndef KEYBOARD_H +#define KEYBOARD_H + +#include + +#include "KeyboardWindow.h" +#include "KeyboardSettings.h" + +class KeyboardApplication : public BApplication +{ +public: + KeyboardApplication(); + virtual ~KeyboardApplication(); + + void MessageReceived(BMessage *message); + BPoint WindowCorner() const {return fSettings->WindowCorner(); } + void SetWindowCorner(BPoint corner); + int32 KeyboardRepeatRate() const {return fSettings->KeyboardRepeatRate(); } + void SetKeyboardRepeatRate(int32 rate); + int32 KeyboardRepeatDelay() const {return fSettings->KeyboardRepeatDelay(); } + void SetKeyboardRepeatDelay(int32 rate); + + void AboutRequested(void); + +private: + + static const char kKeyboardApplicationSig[]; + + KeyboardSettings *fSettings; + +}; + +#endif \ No newline at end of file diff --git a/src/prefs/keyboard/Keyboard.rsrc b/src/prefs/keyboard/Keyboard.rsrc new file mode 100644 index 0000000000..76af3844b2 Binary files /dev/null and b/src/prefs/keyboard/Keyboard.rsrc differ diff --git a/src/prefs/keyboard/KeyboardMessages.h b/src/prefs/keyboard/KeyboardMessages.h new file mode 100644 index 0000000000..6c28bdf525 --- /dev/null +++ b/src/prefs/keyboard/KeyboardMessages.h @@ -0,0 +1,17 @@ +/* + + KeyboardMessages.h + +*/ + +#ifndef KEYBOARD_MESSAGES_H +#define KEYBOARD_MESSAGES_H + +const uint32 BUTTON_DEFAULTS = 'BTde'; +const uint32 BUTTON_REVERT = 'BTre'; +const uint32 SLIDER_REPEAT_RATE = 'SLrr'; +const uint32 SLIDER_DELAY_RATE = 'SLdr'; + +const uint32 ERROR_DETECTED = 'ERor'; + +#endif //KEYBOARD_MESSAGES_H \ No newline at end of file diff --git a/src/prefs/keyboard/KeyboardSettings.cpp b/src/prefs/keyboard/KeyboardSettings.cpp new file mode 100644 index 0000000000..4cc7e6bcda --- /dev/null +++ b/src/prefs/keyboard/KeyboardSettings.cpp @@ -0,0 +1,83 @@ +/* + * KeyboardSettings.cpp + * Keyboard mccall@digitalparadise.co.uk + * + */ + +#include +#include +#include +#include +#include +#include + +#include "KeyboardSettings.h" +#include "KeyboardMessages.h" + +const char KeyboardSettings::kKeyboardSettingsFile[] = "Keyboard_settings"; + +KeyboardSettings::KeyboardSettings() +{ + BPath path; + + if (find_directory(B_USER_SETTINGS_DIRECTORY,&path) == B_OK) { + path.Append(kKeyboardSettingsFile); + BFile file(path.Path(), B_READ_ONLY); + if (file.InitCheck() == B_OK) { + // Now read in the data + if (file.Read(&fSettings, sizeof(kb_settings)) != sizeof(kb_settings)) { + fSettings.key_repeat_delay=200; + fSettings.key_repeat_rate=250000; + } + + if (file.Read(&fCorner, sizeof(BPoint)) != sizeof(BPoint)) { + fCorner.x=50; + fCorner.y=50; + }; + } + else { + fCorner.x=50; + fCorner.y=50; + fSettings.key_repeat_delay=200; + fSettings.key_repeat_rate=250000; + } + } + else + be_app->PostMessage(ERROR_DETECTED); +} + +KeyboardSettings::~KeyboardSettings() +{ + BPath path; + + if (find_directory(B_USER_SETTINGS_DIRECTORY,&path) < B_OK) + return; + + path.Append(kKeyboardSettingsFile); + + BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE); + if (file.InitCheck() == B_OK) { + file.Write(&fSettings, sizeof(kb_settings)); + file.Write(&fCorner, sizeof(BPoint)); + } + + +} + +void +KeyboardSettings::SetWindowCorner(BPoint corner) +{ + fCorner=corner; +} + +void +KeyboardSettings::SetKeyboardRepeatRate(int32 rate) +{ + fSettings.key_repeat_rate=rate; +} + +void +KeyboardSettings::SetKeyboardRepeatDelay(int32 rate) +{ + fSettings.key_repeat_delay=rate; +} \ No newline at end of file diff --git a/src/prefs/keyboard/KeyboardSettings.h b/src/prefs/keyboard/KeyboardSettings.h new file mode 100644 index 0000000000..579d638f1f --- /dev/null +++ b/src/prefs/keyboard/KeyboardSettings.h @@ -0,0 +1,29 @@ +#ifndef KEYBOARD_SETTINGS_H_ +#define KEYBOARD_SETTINGS_H_ + +#include + +typedef struct { + bigtime_t key_repeat_delay; + int32 key_repeat_rate; +} kb_settings; + +class KeyboardSettings{ +public : + KeyboardSettings(); + ~KeyboardSettings(); + + BPoint WindowCorner() const { return fCorner; } + void SetWindowCorner(BPoint corner); + int32 KeyboardRepeatRate() const { return fSettings.key_repeat_rate; } + void SetKeyboardRepeatRate(int32 rate); + int32 KeyboardRepeatDelay() const { return fSettings.key_repeat_delay; } + void SetKeyboardRepeatDelay(int32 rate); + +private: + static const char kKeyboardSettingsFile[]; + BPoint fCorner; + kb_settings fSettings; +}; + +#endif \ No newline at end of file diff --git a/src/prefs/keyboard/KeyboardView.cpp b/src/prefs/keyboard/KeyboardView.cpp new file mode 100644 index 0000000000..4cd215ce74 --- /dev/null +++ b/src/prefs/keyboard/KeyboardView.cpp @@ -0,0 +1,86 @@ +/* + + KeyboardView.cpp + +*/ +#include +#include +#include +#include +#include +#include + +#include "KeyboardView.h" +#include "KeyboardMessages.h" + + +KeyboardView::KeyboardView(BRect rect) + : BBox(rect, "keyboard_view", + B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP, + B_PLAIN_BORDER) +{ + BRect frame; + BButton *button; + BSlider *slider; + BTextControl *textcontrol; + + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + + fIconBitmap = BTranslationUtils::GetBitmap("key_bmap"); + fClockBitmap = BTranslationUtils::GetBitmap("clock_bmap"); + + //Add the "Default" button.. + frame.Set(10,187,85,207); + button = new BButton(frame,"keyboard_defaults","Defaults", new BMessage(BUTTON_DEFAULTS)); + AddChild(button); + + // Add the "Revert" button... + frame.Set(92,187,167,207); + button = new BButton(frame,"keyboard_revert","Revert", new BMessage(BUTTON_REVERT)); + button->SetEnabled(false); + AddChild(button); + + // Create the box for the sliders... + frame=Bounds(); + frame.left=frame.left+11; + frame.top=frame.top+12; + frame.right=frame.right-11; + frame.bottom=frame.bottom-44; + fBox = new BBox(frame,"keyboard_box",B_FOLLOW_LEFT,B_WILL_DRAW,B_FANCY_BORDER); + + // Create the "Key repeat rate" slider... + frame.Set(10,10,172,50); + slider = new BSlider(frame,"key_repeat_rate","Key repeat rate", new BMessage(SLIDER_REPEAT_RATE),20,300,B_BLOCK_THUMB,B_FOLLOW_LEFT,B_WILL_DRAW); + slider->SetHashMarks(B_HASH_MARKS_BOTTOM); + slider->SetHashMarkCount(5); + slider->SetLimitLabels("Slow","Fast"); + fBox->AddChild(slider); + + // Create the "Delay until key repeat" slider... + frame.Set(10,65,172,115); + slider = new BSlider(frame,"delay_until_key_repeat","Delay until key repeat", new BMessage(SLIDER_DELAY_RATE),250000,1000000,B_BLOCK_THUMB,B_FOLLOW_LEFT,B_WILL_DRAW); + slider->SetHashMarks(B_HASH_MARKS_BOTTOM); + slider->SetHashMarkCount(4); + slider->SetLimitLabels("Short","Long"); + fBox->AddChild(slider); + + // Create the "Typing test area" text box... + frame=Bounds(); + frame.left=frame.left+10; + frame.top=135; + frame.right=frame.right-34; + frame.bottom=frame.bottom-11; + textcontrol = new BTextControl(frame,"typing_test_area",NULL,"Typing test area", new BMessage('TTEA'),B_FOLLOW_LEFT,B_WILL_DRAW); + textcontrol->SetAlignment(B_ALIGN_LEFT,B_ALIGN_CENTER); + fBox->AddChild(textcontrol); + + AddChild(fBox); + +} + +void KeyboardView::Draw(BRect updateFrame) +{ + inherited::Draw(updateFrame); + fBox->DrawBitmap(fIconBitmap,BPoint(178,26)); + fBox->DrawBitmap(fClockBitmap,BPoint(178,83)); +} \ No newline at end of file diff --git a/src/prefs/keyboard/KeyboardView.h b/src/prefs/keyboard/KeyboardView.h new file mode 100644 index 0000000000..87df385d3b --- /dev/null +++ b/src/prefs/keyboard/KeyboardView.h @@ -0,0 +1,32 @@ +/* + + KeyboardView.h + +*/ + +#ifndef KEYBOARD_VIEW_H +#define KEYBOARD_VIEW_H + + +#include +#include +#include +#include +#include + +class KeyboardView : public BBox +{ +public: + typedef BBox inherited; + + KeyboardView(BRect frame); + virtual void Draw(BRect frame); + +private: + BBitmap *fIconBitmap; + BBitmap *fClockBitmap; + BBox *fBox; + +}; + +#endif diff --git a/src/prefs/keyboard/KeyboardWindow.cpp b/src/prefs/keyboard/KeyboardWindow.cpp new file mode 100644 index 0000000000..389a738bbf --- /dev/null +++ b/src/prefs/keyboard/KeyboardWindow.cpp @@ -0,0 +1,155 @@ +/* + * KeyboardWindow.cpp + * Keyboard mccall@digitalparadise.co.uk + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "KeyboardMessages.h" +#include "KeyboardWindow.h" +#include "KeyboardView.h" +#include "Keyboard.h" + +#define KEYBOARD_WINDOW_RIGHT 229 +#define KEYBOARD_WINDOW_BOTTTOM 221 + +KeyboardWindow::KeyboardWindow() + : BWindow(BRect(0,0,KEYBOARD_WINDOW_RIGHT,KEYBOARD_WINDOW_BOTTTOM), "Keyboard", B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE ) +{ + BScreen screen; + BSlider *slider=NULL; + + MoveTo(dynamic_cast(be_app)->WindowCorner()); + + // Code to make sure that the window doesn't get drawn off screen... + if (!(screen.Frame().right >= Frame().right && screen.Frame().bottom >= Frame().bottom)) + MoveTo((screen.Frame().right-Bounds().right)*.5,(screen.Frame().bottom-Bounds().bottom)*.5); + + BuildView(); + AddChild(fView); + + slider = (BSlider *)FindView("key_repeat_rate"); + if (slider !=NULL) slider->SetValue(dynamic_cast(be_app)->KeyboardRepeatRate()); + printf("On start repeat rate: %ld\n", dynamic_cast(be_app)->KeyboardRepeatRate()); + + slider = (BSlider *)FindView("delay_until_key_repeat"); + if (slider !=NULL) slider->SetValue(dynamic_cast(be_app)->KeyboardRepeatDelay()); + printf("On start repeat delay: %ld\n", dynamic_cast(be_app)->KeyboardRepeatDelay()); + + Show(); + +} + +void +KeyboardWindow::BuildView() +{ + fView = new KeyboardView(Bounds()); +} + +bool +KeyboardWindow::QuitRequested() +{ + BSlider *slider=NULL; + + dynamic_cast(be_app)->SetWindowCorner(BPoint(Frame().left,Frame().top)); + + slider = (BSlider *)FindView("key_repeat_rate"); + if (slider !=NULL) dynamic_cast(be_app)->SetKeyboardRepeatRate(slider->Value()); + printf("On quit repeat rate: %ld\n", dynamic_cast(be_app)->KeyboardRepeatRate()); + + slider = (BSlider *)FindView("delay_until_key_repeat"); + if (slider !=NULL) dynamic_cast(be_app)->SetKeyboardRepeatDelay(slider->Value()); + printf("On quit repeat delay: %ld\n", dynamic_cast(be_app)->KeyboardRepeatDelay()); + + be_app->PostMessage(B_QUIT_REQUESTED); + + return(true); +} + +void +KeyboardWindow::MessageReceived(BMessage *message) +{ + BSlider *slider=NULL; + BButton *button=NULL; + + switch(message->what) { + case BUTTON_DEFAULTS:{ + if (set_key_repeat_rate(200)!=B_OK) + be_app->PostMessage(ERROR_DETECTED); + slider = (BSlider *)FindView("key_repeat_rate"); + if (slider !=NULL) slider->SetValue(200); + + if (set_key_repeat_delay(250000)!=B_OK) + be_app->PostMessage(ERROR_DETECTED); + slider = (BSlider *)FindView("delay_until_key_repeat"); + if (slider !=NULL) slider->SetValue(250000); + + button = (BButton *)FindView("keyboard_revert"); + if (button !=NULL) button->SetEnabled(true); + } + break; + case BUTTON_REVERT:{ + if (set_key_repeat_rate(dynamic_cast(be_app)->KeyboardRepeatRate())!=B_OK) + be_app->PostMessage(ERROR_DETECTED); + slider = (BSlider *)FindView("key_repeat_rate"); + if (slider !=NULL) slider->SetValue(dynamic_cast(be_app)->KeyboardRepeatRate()); + + if (set_key_repeat_delay(dynamic_cast(be_app)->KeyboardRepeatDelay())!=B_OK) + be_app->PostMessage(ERROR_DETECTED); + slider = (BSlider *)FindView("delay_until_key_repeat"); + if (slider !=NULL) slider->SetValue(dynamic_cast(be_app)->KeyboardRepeatDelay()); + + button = (BButton *)FindView("keyboard_revert"); + if (button !=NULL) button->SetEnabled(false); + } + break; + case SLIDER_REPEAT_RATE:{ + if (set_key_repeat_rate(message->FindInt32("be:value"))!=B_OK) + be_app->PostMessage(ERROR_DETECTED); + + button = (BButton *)FindView("keyboard_revert"); + if (button !=NULL) button->SetEnabled(true); + } + break; + case SLIDER_DELAY_RATE:{ + bigtime_t rate; + rate=message->FindInt32("be:value"); + // We need to look at the value from the slider and make it "jump" + // to the next notch along. Setting the min and max values of the + // slider to 1 and 4 doesn't work like the real Keyboard app. + if (rate < 375000) + rate = 250000; + if ((rate >= 375000)&&(rate < 625000)) + rate = 500000; + if ((rate >= 625000)&&(rate < 875000)) + rate = 750000; + if (rate >= 875000) + rate = 1000000; + + if (set_key_repeat_delay(rate)!=B_OK) + be_app->PostMessage(ERROR_DETECTED); + slider = (BSlider *)FindView("delay_until_key_repeat"); + if (slider !=NULL) slider->SetValue(rate); + + button = (BButton *)FindView("keyboard_revert"); + if (button !=NULL) button->SetEnabled(true); + } + break; + default: + BWindow::MessageReceived(message); + break; + } + +} + +KeyboardWindow::~KeyboardWindow() +{ + +} \ No newline at end of file diff --git a/src/prefs/keyboard/KeyboardWindow.h b/src/prefs/keyboard/KeyboardWindow.h new file mode 100644 index 0000000000..e19cb945d4 --- /dev/null +++ b/src/prefs/keyboard/KeyboardWindow.h @@ -0,0 +1,24 @@ +#ifndef KEYBOARD_WINDOW_H +#define KEYBOARD_WINDOW_H + +#include + +#include "KeyboardSettings.h" +#include "KeyboardView.h" + +class KeyboardWindow : public BWindow +{ +public: + KeyboardWindow(); + ~KeyboardWindow(); + + bool QuitRequested(); + void MessageReceived(BMessage *message); + void BuildView(); + +private: + KeyboardView *fView; + +}; + +#endif diff --git a/src/prefs/keymap/KeymapApplication.cpp b/src/prefs/keymap/KeymapApplication.cpp new file mode 100644 index 0000000000..b13f4ff770 --- /dev/null +++ b/src/prefs/keymap/KeymapApplication.cpp @@ -0,0 +1,182 @@ +#include +#include +#include +#include +#if DEBUG + #include + #include +#endif //DEBUG +#include "KeymapWindow.h" +#include "KeymapApplication.h" +#include + + +KeymapApplication::KeymapApplication() + : BApplication( APP_SIGNATURE ) +{ + // create the window + BRect frame = WINDOW_DIMENSIONS; + frame.OffsetTo( WINDOW_LEFT_TOP_POSITION ); + fWindow = new KeymapWindow( frame ); + fWindow->Show(); +} + +void KeymapApplication::MessageReceived( BMessage * message ) +{ + BApplication::MessageReceived( message ); +} + + +/* + * Returns a BList containing BEntry objects + * representing the systems' keymap files + */ +BList* KeymapApplication::SystemMaps() +{ + // TODO: find a constant containing this path and use that instead + return EntryList( "/boot/beos/etc/Keymap" ); +} + +BList* KeymapApplication::UserMaps() +{ + // TODO: find a constant containing this path and use that instead + return EntryList( "/boot/home/config/settings/Keymap" ); +} + +BList* KeymapApplication::EntryList( char *directoryPath ) +{ + BList *entryList; + BDirectory *directory; + BEntry *currentEntry; + + + entryList = new BList(); + directory = new BDirectory(); + + if( directory->SetTo( directoryPath ) == B_OK ) + // put each files' name in the list + while( true ) { + currentEntry = new BEntry(); + if( directory->GetNextEntry( currentEntry, true ) != B_OK ) { + delete currentEntry; + break; + } + entryList->AddItem( currentEntry ); + #if DEBUG + char name[B_FILE_NAME_LENGTH]; + currentEntry->GetName( name ); + cout << "Found: " << name << endl; + #endif //DEBUG + } + else { + // something went wrong; no system keymaps today + // TODO: catch error codes and act appropriately + + } + delete directory; + + return entryList; +} + +BEntry* KeymapApplication::CurrentMap() +{ + BEntry *entry; + + // TODO: find a constant containing this path and use that instead + entry = new BEntry( "/boot/home/config/settings/Key_map" ); + return entry; +} + +bool KeymapApplication::UseKeymap( BEntry *keymap ) +{ // Copies keymap to ~/config/settings/key_map + BFile *inFile; + BFile *outFile; + + // Open input file + if( !keymap->Exists() ) + return false; + inFile = new BFile( keymap, B_READ_ONLY ); + if( !inFile->IsReadable() ) { + delete inFile; + return false; + } + + // Is keymap a valid keymap file? + if( !IsValidKeymap( inFile ) ) { + delete inFile; + return false; + } + + // Open output file + // TODO: find a nice constant for the path and use that instead + outFile = new BFile( "/boot/home/config/settings/Key_map", B_WRITE_ONLY|B_ERASE_FILE|B_CREATE_FILE ); + if( !outFile->IsWritable() ) { + delete inFile; + delete outFile; + return false; + } + + // Copy file + if( Copy( inFile, outFile ) != B_OK ) { + delete inFile; + delete outFile; + return false; + } + delete inFile; + delete outFile; + + // Tell Input Server there is a new keymap + if( NotifyInputServer() != B_OK ) + return false; + + return true; +} + +bool KeymapApplication::IsValidKeymap( BFile *inFile ) +{ + // TODO: implement this thing + + return true; +} + +int KeymapApplication::Copy( BFile *original, BFile *copy ) +{ + char *buffer[ COPY_BUFFER_SIZE ]; + int offset = 0; + int errorCode = B_NO_ERROR; + ssize_t nrBytesRead; + ssize_t nrBytesWritten; + + while( true ) { + nrBytesRead = original->ReadAt( offset, buffer, COPY_BUFFER_SIZE ); + if( nrBytesRead == 0 ) + { + errorCode = B_OK; + break; + } + nrBytesWritten = copy->WriteAt( offset, buffer, nrBytesRead ); + if( nrBytesWritten != nrBytesRead ) + { + errorCode = B_ERROR; + break; + } + if( nrBytesRead < COPY_BUFFER_SIZE ) + { + errorCode = B_OK; + break; + } + offset += nrBytesRead; + } + + return errorCode; +} + +int KeymapApplication::NotifyInputServer() +{ + // This took me days to find out. Go figure. + // Be didn't need to restart the thing - they prolly used + // a proprietary interface to notify it. Coordinate with + // the input_server guys. + system("kill -KILL input_server"); + return B_NO_ERROR; +} diff --git a/src/prefs/keymap/KeymapApplication.h b/src/prefs/keymap/KeymapApplication.h new file mode 100644 index 0000000000..c41f41069e --- /dev/null +++ b/src/prefs/keymap/KeymapApplication.h @@ -0,0 +1,32 @@ +#ifndef OBOS_KEYMAP_APPLICATION_H +#define OBOS_KEYMAP_APPLICATION_H + +#include +#include + +#define APP_SIGNATURE "application/x-vnd.OpenBeOS-Keymap" +#define COPY_BUFFER_SIZE 1 * 1024 + + +class KeymapWindow; + +class KeymapApplication : public BApplication { +public: + KeymapApplication(); + void MessageReceived(BMessage *message); + BList* SystemMaps(); + BList* UserMaps(); + BEntry* CurrentMap(); + bool UseKeymap( BEntry *keymap ); + +protected: + KeymapWindow *fWindow; + + BList* EntryList( char *directoryPath ); + bool IsValidKeymap( BFile *inFile ); + int Copy( BFile *original, BFile *copy ); + int NotifyInputServer(); + +}; + +#endif // OBOS_KEYMAP_APPLICATION_H \ No newline at end of file diff --git a/src/prefs/keymap/KeymapListItem.cpp b/src/prefs/keymap/KeymapListItem.cpp new file mode 100644 index 0000000000..496b0b1fb4 --- /dev/null +++ b/src/prefs/keymap/KeymapListItem.cpp @@ -0,0 +1,28 @@ +/* + * A BStringItem modified such that it holds + * the BEntry object it corresponds with + */ + +#include "KeymapListItem.h" + + +KeymapListItem::KeymapListItem( BEntry *keymap ) + : BStringItem( "" ) +{ + char name[B_FILE_NAME_LENGTH]; + + fKeymap = keymap; + keymap->GetName( name ); + + SetText( name ); +} + +KeymapListItem::~KeymapListItem() +{ + delete fKeymap; +} + +BEntry* KeymapListItem::KeymapEntry() +{ + return fKeymap; +} diff --git a/src/prefs/keymap/KeymapListItem.h b/src/prefs/keymap/KeymapListItem.h new file mode 100644 index 0000000000..9763415b1e --- /dev/null +++ b/src/prefs/keymap/KeymapListItem.h @@ -0,0 +1,24 @@ +/* + * A BStringItem modified such that it holds + * the BEntry object it corresponds with + */ + +#ifndef OBOS_KEYMAP_LIST_ITEM_H +#define OBOS_KEYMAP_LIST_ITEM_H + +#include +#include + + +class KeymapListItem : public BStringItem { +public: + KeymapListItem( BEntry *keymap ); + ~KeymapListItem(); + BEntry *KeymapEntry(); + +protected: + BEntry *fKeymap; + +}; + +#endif //OBOS_KEYMAP_LIST_ITEM_H \ No newline at end of file diff --git a/src/prefs/keymap/KeymapWindow.cpp b/src/prefs/keymap/KeymapWindow.cpp new file mode 100644 index 0000000000..6ae2f29f5b --- /dev/null +++ b/src/prefs/keymap/KeymapWindow.cpp @@ -0,0 +1,355 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef DEBUG + #include +#endif //DEBUG +#include "KeymapWindow.h" +#include "KeymapListItem.h" +#include "KeymapApplication.h" +#include "messages.h" + +#include + +KeymapWindow::KeymapWindow( BRect frame ) + : BWindow( frame, WINDOW_TITLE, B_TITLED_WINDOW, + B_NOT_ZOOMABLE|B_NOT_RESIZABLE|B_ASYNCHRONOUS_CONTROLS ) +{ + rgb_color tempColor; + BRect bounds = Bounds(); + BMenuBar *menubar; + + fApplication = (KeymapApplication*) be_app; + fSelectedMap = fApplication->CurrentMap(); + + // Add the menu bar + menubar = AddMenuBar(); + + // The view to hold all but the menu bar + bounds.top = menubar->Bounds().bottom + 1; + fPlaceholderView = new BView( bounds, "placeholderView", + B_FOLLOW_NONE, 0 ); + tempColor = ui_color( B_MENU_BACKGROUND_COLOR ); + fPlaceholderView->SetViewColor( tempColor ); + AddChild( fPlaceholderView ); + + // Create the Maps box and contents + AddMaps(); + + // The 'Use' button + bounds.Set( 527,200, 600,220 ); + fUseButton = new BButton( bounds, "useButton", "Use", + new BMessage( USE_KEYMAP )); + fPlaceholderView->AddChild( fUseButton ); + + // The 'Revert' button + bounds.Set( 442,200, 515,220 ); + fRevertButton = new BButton( bounds, "revertButton", "Revert", + new BMessage( REVERT )); + fPlaceholderView->AddChild( fRevertButton ); + +} + +BMenuBar * KeymapWindow::AddMenuBar() +{ + BRect bounds; + BMenu *menu; + BMenuItem *currentItem; + BMenuBar *menubar; + + bounds = Bounds(); + menubar = new BMenuBar( bounds, "menubar" ); + AddChild( menubar ); + + // Create the File menu + menu = new BMenu( "File" ); + menu->AddItem( new BMenuItem( "Open" B_UTF8_ELLIPSIS, + new BMessage( MENU_FILE_OPEN ), 'O' ) ); + menu->AddSeparatorItem(); + currentItem = new BMenuItem( "Save", + new BMessage( MENU_FILE_SAVE ), 'S' ); + currentItem->SetEnabled( false ); + menu->AddItem( currentItem ); + menu->AddItem( new BMenuItem( "Save As" B_UTF8_ELLIPSIS, + new BMessage( MENU_FILE_SAVE_AS ))); + menu->AddSeparatorItem(); + menu->AddItem( new BMenuItem( "Quit", + new BMessage( B_QUIT_REQUESTED ), 'Q' )); + menubar->AddItem( menu ); + + // Create the Edit menu + menu = new BMenu( "Edit" ); + currentItem = new BMenuItem( "Undo", + new BMessage( MENU_EDIT_UNDO ), 'Z' ); + currentItem->SetEnabled( false ); + menu->AddItem( currentItem ); + menu->AddSeparatorItem(); + menu->AddItem( new BMenuItem( "Cut", + new BMessage( MENU_EDIT_CUT ), 'X' )); + menu->AddItem( new BMenuItem( "Copy", + new BMessage( MENU_EDIT_COPY ), 'C' )); + menu->AddItem( new BMenuItem( "Paste", + new BMessage( MENU_EDIT_PASTE ), 'V' )); + menu->AddItem( new BMenuItem( "Clear", + new BMessage( MENU_EDIT_CLEAR ))); + menu->AddSeparatorItem(); + menu->AddItem( new BMenuItem( "Select All", + new BMessage( MENU_EDIT_SELECT_ALL ), 'A' )); + menubar->AddItem( menu ); + + // Create the Font menu + menu = new BMenu( "Font" ); + + menubar->AddItem( menu ); + + return menubar; +} + +void KeymapWindow::AddMaps() +{ + BBox *mapsBox; + BRect bounds; + BList *entryList; + BList *listItems; + KeymapListItem *currentKeymapItem; + + // The Maps box + bounds = BRect( 9,11, 140, 227 ); + mapsBox = new BBox( bounds ); + mapsBox->SetLabel( "Maps" ); + fPlaceholderView->AddChild( mapsBox ); +/* + // Set drawing mode to B_OP_COPY + mapsBox->SetDrawingMode( B_OP_COPY ); + + // Set mapsBox->LowColor to background color + rgb_color tempColor; + tempColor = ui_color( B_MENU_BACKGROUND_COLOR ); + mapsBox->SetLowColor( tempColor ); + + // Set mapsBox->HighColor to black + tempColor.red = 0; + tempColor.green = 0; + tempColor.blue = 0; + tempColor.alpha = 0; + mapsBox->SetHighColor( tempColor ); + + // Set font to something nice + BFont *font = new BFont(); + font->SetFace( B_REGULAR_FACE ); +// font->SetFamilyAndStyle(); + font->SetRotation( 0.0 ); + font->SetShear( 90.0 ); + font->SetSize( 12.0 ); + font->SetSpacing( B_BITMAP_SPACING ); + mapsBox->SetFont( font ); +*/ + // The System list + bounds = BRect( 209,20, 370,135 ); +/* + BView *textSystem = new BView( bounds, NULL, B_NOT_RESIZABLE, 0 ); + rgb_color tempColor; + tempColor = ui_color( B_MENU_BACKGROUND_COLOR ); +*/ +/* + tempColor.red = 0; + tempColor.green = 0; + tempColor.blue = 0; + tempColor.alpha = 0; +*/ +// textSystem->SetViewColor( tempColor ); +// textSystem->SetLowColor( tempColor ); +/* + tempColor.red = 0; + tempColor.green = 0; + tempColor.blue = 0; + tempColor.alpha = 0; + textSystem->SetHighColor( tempColor ); + + tempColor.red = 0; + tempColor.green = 0; + tempColor.blue = 0; + tempColor.alpha = 0; + textSystem->SetLowColor( tempColor ); + + textSystem->DrawString( "System", BPoint( 0, 14 ) ); + fPlaceholderView->AddChild( textSystem ); +*/ + bounds = BRect( 13,36, 103,106 ); + entryList = fApplication->SystemMaps(); + fSystemListView = new BListView( bounds, "systemList" ); + listItems = ListItemsFromEntryList( entryList ); + fSystemListView->AddList( listItems ); + mapsBox->AddChild( new BScrollView( "systemScrollList", fSystemListView, + B_FOLLOW_LEFT | B_FOLLOW_TOP, 0, false, true )); + fSystemListView->SetSelectionMessage( new BMessage( SYSTEM_MAP_SELECTED )); + delete listItems; + delete entryList; + + // The User list + mapsBox->DrawString( "User", BPoint( 13, 113 )); + bounds = BRect( 13,129, 103,199 ); + entryList = fApplication->UserMaps(); + fUserListView = new BListView( bounds, "userList" ); + // '(Current)' + currentKeymapItem = ItemFromEntry( fApplication->CurrentMap() ); + if( currentKeymapItem != NULL ) + fUserListView->AddItem( currentKeymapItem ); + // Saved keymaps + listItems = ListItemsFromEntryList( entryList ); + fUserListView->AddList( listItems ); + mapsBox->AddChild( new BScrollView( "systemScrollList", fUserListView, + B_FOLLOW_LEFT | B_FOLLOW_TOP, 0, false, true )); + fUserListView->SetSelectionMessage( new BMessage( USER_MAP_SELECTED )); + delete listItems; + delete entryList; +} + +BList* KeymapWindow::ListItemsFromEntryList( BList * entryList) +{ + BEntry *currentEntry; + BList *listItems; + int nrItems; + #ifdef DEBUG + char name[B_FILE_NAME_LENGTH]; + #endif //DEBUG + + listItems = new BList(); + nrItems = entryList->CountItems(); + for( int index=0; indexItemAt( index ); + listItems->AddItem( new KeymapListItem( currentEntry )); + + #ifdef DEBUG + currentEntry->GetName( name ); + cout << "New list item: " << name << endl; + #endif //DEBUG + } + + return listItems; +} + +KeymapListItem* KeymapWindow::ItemFromEntry( BEntry *entry ) +{ + KeymapListItem *item; + + if( entry->Exists() ) { + item = new KeymapListItem( entry ); + item->SetText( "(Current)" ); + } + else + item = NULL; + + return item; +} + +bool KeymapWindow::QuitRequested() +{ + be_app->PostMessage( B_QUIT_REQUESTED ); + return true; +} + +void KeymapWindow::MessageReceived( BMessage* message ) +{ + switch( message->what ) { + case MENU_FILE_OPEN: + break; + case MENU_FILE_SAVE: + break; + case MENU_FILE_SAVE_AS: + break; + case MENU_EDIT_UNDO: + break; + case MENU_EDIT_CUT: + break; + case MENU_EDIT_COPY: + break; + case MENU_EDIT_PASTE: + break; + case MENU_EDIT_CLEAR: + break; + case MENU_EDIT_SELECT_ALL: + break; + case SYSTEM_MAP_SELECTED: + HandleSystemMapSelected( message ); + break; + case USER_MAP_SELECTED: + HandleUserMapSelected( message ); + break; + case USE_KEYMAP: + UseKeymap(); + break; + case REVERT: // do nothing, just like the original + break; + + default: + BWindow::MessageReceived( message ); + break; + } +} + +void KeymapWindow::HandleSystemMapSelected( BMessage *selectionMessage ) +{ + #if DEBUG + cout << "System map selected" << endl; + #endif //DEBUG + HandleMapSelected( selectionMessage, fSystemListView, fUserListView ); +} + +void KeymapWindow::HandleUserMapSelected( BMessage *selectionMessage ) +{ + #if DEBUG + cout << "User map selected" << endl; + #endif //DEBUG + HandleMapSelected( selectionMessage, fUserListView, fSystemListView ); +} + +void KeymapWindow::HandleMapSelected( BMessage *selectionMessage, + BListView * selectedView, BListView * otherView ) +{ + int32 index; + KeymapListItem *keymapListItem; + + // Anything selected? + index = selectedView->CurrentSelection( 0 ); + if( index < 0 ) { + #if DEBUG + cout << "index<0; HandleMapSelected ends here." << endl; + + #endif //DEBUG + return; + } + + // Store selected map in fSelectedMap + keymapListItem = (KeymapListItem*)selectedView->ItemAt( index ); + if( keymapListItem == NULL ) + return; + fSelectedMap = keymapListItem->KeymapEntry(); + #if DEBUG + char name[B_FILE_NAME_LENGTH]; + fSelectedMap->GetName( name ); + cout << "fSelectedMap has been set to " << name << endl; + #endif //DEBUG + + // Deselect item in other BListView + otherView->DeselectAll(); +} + +void KeymapWindow::UseKeymap() +{ + if( fSelectedMap != NULL ) + fApplication->UseKeymap( fSelectedMap ); + else { + // There is no keymap selected! + BAlert *alert; + alert = new BAlert( "w>noKeymap", "No keymap has been selected", "Bummer", + NULL, NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT ); + alert->Go(); + } +} diff --git a/src/prefs/keymap/KeymapWindow.h b/src/prefs/keymap/KeymapWindow.h new file mode 100644 index 0000000000..b0774a502b --- /dev/null +++ b/src/prefs/keymap/KeymapWindow.h @@ -0,0 +1,50 @@ +#ifndef OBOS_KEYMAP_WINDOW_H +#define OBOS_KEYMAP_WINDOW_H + + +#include +#include +#include + + +#if !DEBUG + #define WINDOW_TITLE "Keymap" +#else + #define WINDOW_TITLE "OBOS Keymap" +#endif //DEBUG +#define WINDOW_LEFT_TOP_POSITION BPoint( 80, 25 ) +#define WINDOW_DIMENSIONS BRect( 0,0, 612,256 ) + +class KeymapListItem; +class KeymapApplication; + +class KeymapWindow : public BWindow { +public: + KeymapWindow( BRect frame ); + bool QuitRequested(); + void MessageReceived( BMessage* message ); + +protected: + KeymapApplication *fApplication; + BView *fPlaceholderView; + BListView *fSystemListView; + BListView *fUserListView; + // the map that's currently highlighted + BEntry *fSelectedMap; + BButton *fUseButton; + BButton *fRevertButton; + const char *title; + + BMenuBar *AddMenuBar(); + void AddMaps(); + BList *ListItemsFromEntryList( BList * entryList); + KeymapListItem* ItemFromEntry( BEntry *entry ); + void HandleSystemMapSelected( BMessage* ); + void HandleUserMapSelected( BMessage* ); + void HandleMapSelected( BMessage *selectionMessage, + BListView * selectedView, BListView * otherView ); + void UseKeymap(); + +}; + +#endif // OBOS_KEYMAP_WINDOW_H diff --git a/src/prefs/keymap/main.cpp b/src/prefs/keymap/main.cpp new file mode 100644 index 0000000000..a2f5414eb3 --- /dev/null +++ b/src/prefs/keymap/main.cpp @@ -0,0 +1,17 @@ +/* + * Part of the Open BeOS project + * (C) 2002 Be United + * Creation: Sandor Vroemisse + */ + +#include +#include "KeymapApplication.h" + + +int main () +{ + new KeymapApplication; + be_app->Run(); + delete be_app; + return 0; +} diff --git a/src/prefs/media/MediaPrefsApp.cpp b/src/prefs/media/MediaPrefsApp.cpp new file mode 100644 index 0000000000..7b65fd2887 --- /dev/null +++ b/src/prefs/media/MediaPrefsApp.cpp @@ -0,0 +1,22 @@ +#include "MediaPrefsApp.h" + + +MediaPrefsApp::MediaPrefsApp() + : BApplication( "application/x-vnd.OBeOS.Media" ) +{ + BRect r; + + r.Set( 100, 100, 200, 300 ); + window = new MediaPrefsWindow( r ); + window->Show(); +} + + +int +main( int argc, char **argv ) +{ + MediaPrefsApp app; + + app.Run(); + return 0; +} diff --git a/src/prefs/media/MediaPrefsApp.h b/src/prefs/media/MediaPrefsApp.h new file mode 100644 index 0000000000..756433ab4d --- /dev/null +++ b/src/prefs/media/MediaPrefsApp.h @@ -0,0 +1,12 @@ +#include + +#include "MediaPrefsWindow.h" + +class MediaPrefsApp : public BApplication { + + public: + MediaPrefsApp(); + + private: + MediaPrefsWindow *window; +}; diff --git a/src/prefs/media/MediaPrefsSlider.cpp b/src/prefs/media/MediaPrefsSlider.cpp new file mode 100644 index 0000000000..9218689d93 --- /dev/null +++ b/src/prefs/media/MediaPrefsSlider.cpp @@ -0,0 +1,9 @@ +#include "MediaPrefsSlider.h" +#include "VolumeControl.h" + + +MediaPrefsSlider::MediaPrefsSlider( BRect r, const char *name, const char *label, BMessage *model, + int32 channels, uint32 resize, uint32 flags ) + : BChannelSlider( r, name, label, model, B_VERTICAL, channels, resize, flags ) +{ +} diff --git a/src/prefs/media/MediaPrefsSlider.h b/src/prefs/media/MediaPrefsSlider.h new file mode 100644 index 0000000000..6ddcd8fec6 --- /dev/null +++ b/src/prefs/media/MediaPrefsSlider.h @@ -0,0 +1,10 @@ +#include + +#define vI2F (float)(9.999 / 100) + +class MediaPrefsSlider : public BChannelSlider { + + public: + MediaPrefsSlider( BRect r, const char *name, const char *label, BMessage *model, + int32 channels, uint32 resize, uint32 flags ); +}; diff --git a/src/prefs/media/MediaPrefsView.cpp b/src/prefs/media/MediaPrefsView.cpp new file mode 100644 index 0000000000..1b81e3e3e9 --- /dev/null +++ b/src/prefs/media/MediaPrefsView.cpp @@ -0,0 +1,7 @@ +#include "MediaPrefsView.h" + + +MediaPrefsView::MediaPrefsView( BRect r, char *name ) + : BView( r, name, B_FOLLOW_ALL_SIDES, B_WILL_DRAW ) +{ +} diff --git a/src/prefs/media/MediaPrefsView.h b/src/prefs/media/MediaPrefsView.h new file mode 100644 index 0000000000..54dbfc0e9c --- /dev/null +++ b/src/prefs/media/MediaPrefsView.h @@ -0,0 +1,8 @@ +#include + +class MediaPrefsView : public BView { + + public: + MediaPrefsView( BRect r, char *name ); + +}; diff --git a/src/prefs/media/MediaPrefsWindow.cpp b/src/prefs/media/MediaPrefsWindow.cpp new file mode 100644 index 0000000000..3a746618b9 --- /dev/null +++ b/src/prefs/media/MediaPrefsWindow.cpp @@ -0,0 +1,65 @@ +#include "MediaPrefsApp.h" +#include "VolumeControl.h" + + +MediaPrefsWindow::MediaPrefsWindow( BRect wRect ) + : BWindow( wRect, "Media", B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS ) +{ + float fLeft, fRight; + int32 iLeft, iRight; + + wRect.OffsetTo( B_ORIGIN ); + view = new MediaPrefsView( wRect, "MainView" ); + view->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) ); + + this->AddChild( view ); + + slider = new MediaPrefsSlider( wRect, "MasterVol", "Master", + new BMessage( 'mVol' ), 2, + B_FOLLOW_LEFT|B_FOLLOW_TOP, B_WILL_DRAW ); + slider->SetLimits( 0, 100 ); + slider->SetLimitLabels( "0", "100" ); + + view->AddChild( slider ); + + // use private API + if ( MediaKitPrivate::GetMasterVolume( &fLeft, &fRight ) == B_OK ) { + // left,right range is 0..9.999 + iLeft = (int32)( fLeft / vI2F ); + iRight = (int32)( fRight / vI2F ); + } else { + iLeft = 0; + iRight = 0; + } + + slider->SetValueFor( 0, iLeft ); + slider->SetValueFor( 1, iRight ); +} + + +bool MediaPrefsWindow::QuitRequested() +{ + be_app->PostMessage( B_QUIT_REQUESTED ); + return true; +} + + +void MediaPrefsWindow::MessageReceived( BMessage *msg ) +{ + switch ( msg->what ) { + case 'mVol': + { + int32 iLeft = slider->ValueFor( 0 ); + int32 iRight = slider->ValueFor( 1 ); + + float fLeft = float( iLeft ) * vI2F; + float fRight = float( iRight ) * vI2F; + + MediaKitPrivate::SetMasterVolume( fLeft, fRight ); + } + break; + + default: + BWindow::MessageReceived( msg ); + } +} diff --git a/src/prefs/media/MediaPrefsWindow.h b/src/prefs/media/MediaPrefsWindow.h new file mode 100644 index 0000000000..d6d6af255a --- /dev/null +++ b/src/prefs/media/MediaPrefsWindow.h @@ -0,0 +1,17 @@ +#include + +#include "MediaPrefsView.h" +#include "MediaPrefsSlider.h" + + +class MediaPrefsWindow : public BWindow { + + public: + MediaPrefsWindow( BRect wRect ); + virtual bool QuitRequested(); + virtual void MessageReceived( BMessage *msg ); + + private: + MediaPrefsView *view; + MediaPrefsSlider *slider; +}; diff --git a/src/prefs/menu/BitmapMenuItem.cpp b/src/prefs/menu/BitmapMenuItem.cpp new file mode 100644 index 0000000000..c5bf8e356d --- /dev/null +++ b/src/prefs/menu/BitmapMenuItem.cpp @@ -0,0 +1,60 @@ +// System Headers +#ifndef _NODE_INFO_H +#include +#endif + +// Project Headers +#include "BitmapMenuItem.h" + + +// BitmapMenuItem class definition +BitmapMenuItem::BitmapMenuItem(const char* name, BMessage* message, + BBitmap* bmp, char shortcut, uint32 modifiers) + : BMenuItem(name, message, shortcut, modifiers) +{ + fBmp = bmp; + fName.SetTo(name); + + fCheckBmp = BTranslationUtils::GetBitmap(B_RAW_TYPE, "CHECK"); +} + +void BitmapMenuItem::Draw(void) +{ + BRect dr; + + BMenu* menu = Menu(); + + // if we don't have a menu, get out... + if (!menu) return; + + BRect itemFrame = Frame(); + + if (IsSelected()) { + menu->SetHighColor(160, 160, 160); + menu->SetLowColor(160, 160, 160); + menu->FillRect(itemFrame); + } else { + menu->SetHighColor(219, 219, 219); + menu->SetLowColor(219, 219, 219); + } + menu->SetHighColor(0, 0, 0); + + if (IsMarked()) { + menu->MovePenTo(itemFrame.left + 2, itemFrame.bottom - 4); + BRect checkFrame(0, 0, 12, 12); + dr.Set(itemFrame.left, itemFrame.top + 2, itemFrame.left + 12, itemFrame.top + 14); + menu->SetDrawingMode(B_OP_OVER); + menu->DrawBitmap(fCheckBmp, checkFrame, dr); + menu->SetDrawingMode(B_OP_COPY); + } + + menu->MovePenTo(itemFrame.left + 38, itemFrame.bottom - 5); + menu->DrawString(fName.String()); + + BRect bitmapFrame = fBmp->Bounds(); + dr.Set(itemFrame.left + 14, itemFrame.top + 2, itemFrame.left + 14 + bitmapFrame.right, itemFrame.top + 17); + menu->SetDrawingMode(B_OP_OVER); + menu->DrawBitmap(fBmp, bitmapFrame, dr); + menu->SetDrawingMode(B_OP_COPY); + +} diff --git a/src/prefs/menu/BitmapMenuItem.h b/src/prefs/menu/BitmapMenuItem.h new file mode 100644 index 0000000000..2364160114 --- /dev/null +++ b/src/prefs/menu/BitmapMenuItem.h @@ -0,0 +1,27 @@ +#ifndef _MBitmapMenuItem_h +#define _MBitmapMenuItem_h + +// System Headers +#include +#include +#ifndef _TRANSLATION_UTILS_H +#include +#endif +#include + + +// MBitmapMenuItem class declaration +class BitmapMenuItem : public BMenuItem +{ +public: + BitmapMenuItem(const char* name, BMessage* message, BBitmap* bmp, + char shortcut = 0, uint32 modifiers = 0); +virtual void Draw(void); + +private: + BBitmap *fBmp; + BString fName; + BBitmap *fCheckBmp; +}; + +#endif // _MBitmapMenuItem_h \ No newline at end of file diff --git a/src/prefs/menu/ColorPicker.cpp b/src/prefs/menu/ColorPicker.cpp new file mode 100644 index 0000000000..9b9669caca --- /dev/null +++ b/src/prefs/menu/ColorPicker.cpp @@ -0,0 +1,20 @@ + + #include "MenuApp.h" + + ColorPicker::ColorPicker() + :BColorControl(BPoint(10,10), B_CELLS_32x8, + 9, "COLOR", new BMessage(MENU_COLOR), true) + { + menu_info info; + get_menu_info(&info); + SetValue(info.background_color); + } + + ColorPicker::~ColorPicker() + {} + + void + ColorPicker::MessageReceived(BMessage *msg){ + switch(msg->what) { + } + } \ No newline at end of file diff --git a/src/prefs/menu/ColorWindow.cpp b/src/prefs/menu/ColorWindow.cpp new file mode 100644 index 0000000000..251f6e5e3a --- /dev/null +++ b/src/prefs/menu/ColorWindow.cpp @@ -0,0 +1,69 @@ + + #include "MenuApp.h" + + ColorWindow::ColorWindow() + : BWindow(BRect(150,150,350,200), "Menu Color Schene", B_TITLED_WINDOW, B_NOT_ZOOMABLE | B_NOT_RESIZABLE) + { + // Set and collect the variables for revert + get_menu_info(&info); + get_menu_info(&revert_info); + + BView *colView = new BView(BRect(0,0,1000,100), "menuView", + B_FOLLOW_ALL_SIDES, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE); + + colorPicker = new ColorPicker(); + colView->SetViewColor(219,219,219,255); + colView->AddChild(colorPicker); + AddChild(colView); + + ResizeTo(383,130); + + // Create the buttons and add them to the view + DefaultButton = new BButton(BRect(10,100,85,110), "Default", "Default", + new BMessage(MENU_COLOR_DEFAULT), B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE); + RevertButton = new BButton(BRect(95,100,175,20), "REVERT", "Revert", + new BMessage(MENU_REVERT), B_FOLLOW_LEFT | B_FOLLOW_BOTTOM, B_WILL_DRAW | B_NAVIGABLE); + + colView->AddChild(DefaultButton); + colView->AddChild(RevertButton); + } + + ColorWindow::~ColorWindow() + {} + + void + ColorWindow::MessageReceived(BMessage *msg) + { + switch(msg->what) { + + case MENU_REVERT: + colorPicker->SetValue(revert_info.background_color); + info.background_color = colorPicker->ValueAsColor(); + set_menu_info(&info); + be_app->PostMessage(UPDATE_WINDOW); + break; + + case MENU_COLOR_DEFAULT: + // change to system color for system wide + // compatability + rgb_color color; + color.red = 219; + color.blue = 219; + color.green = 219; + color.alpha = 255; + colorPicker->SetValue(color); + + case MENU_COLOR:{ + get_menu_info(&info); + info.background_color = colorPicker->ValueAsColor(); + set_menu_info(&info); + be_app->PostMessage(UPDATE_WINDOW); + break;} + + default: + be_app->PostMessage(UPDATE_WINDOW); + BMessage(msg); + break; + } + } + \ No newline at end of file diff --git a/src/prefs/menu/FontMenu.cpp b/src/prefs/menu/FontMenu.cpp new file mode 100644 index 0000000000..6d82b092c7 --- /dev/null +++ b/src/prefs/menu/FontMenu.cpp @@ -0,0 +1,122 @@ + + #include "MenuApp.h" + #include + + FontMenu::FontMenu() + : BMenu("Font", B_ITEMS_IN_COLUMN) + { + get_menu_info(&info); + SetRadioMode(true); + GetFonts(); + } + + FontMenu::~FontMenu() + { /*nothing to clean up*/} + + void + FontMenu::GetFonts() + { + int32 numFamilies = count_font_families(); + for ( int32 i = 0; i < numFamilies; i++ ) { + font_family *family = (font_family*)malloc(sizeof(font_family)); + uint32 flags; + if ( get_font_family(i, family, &flags) == B_OK ) { + fontStyleMenu = new BMenu(*family, B_ITEMS_IN_COLUMN); + fontStyleMenu->SetRadioMode(true); + int32 numStyles = count_font_styles(*family); + for ( int32 j = 0; j < numStyles; j++ ) { + font_style *style = (font_style*)malloc(sizeof(font_style)); + if ( get_font_style(*family, j, style, &flags) == B_OK ) { + BMessage *msg = new BMessage(MENU_FONT_STYLE); + msg->AddPointer("family", family); + msg->AddPointer("style", style); + fontStyleItem = new BMenuItem(*style, msg, 0, 0); + fontStyleMenu->AddItem(fontStyleItem); + } + } + BMessage *msg = new BMessage(MENU_FONT_FAMILY); + msg->AddPointer("family", family); + font_style *style = (font_style*)malloc(sizeof(font_style)); + // if font family selected, we need to change style to + // first style + if ( get_font_style(*family, 0, style, &flags) == B_OK ) + msg->AddPointer("style", style); + fontFamily = new BMenuItem(fontStyleMenu, msg); + AddItem(fontFamily); + } + } + } + + void + FontMenu::Update() + { + // it may be better to pull all menu prefs + // related stuff out of the FontMenu class + // so it can be easily reused in other apps + get_menu_info(&info); + + // font menu + BFont font; + font.SetFamilyAndStyle(info.f_family, info.f_style); + font.SetSize(info.font_size); + SetFont(&font); + SetViewColor(info.background_color); + InvalidateLayout(); + + // font style menus + for (int i = 0; i < CountItems(); i++) { + ItemAt(i)->Submenu()->SetFont(&font); + } + + ClearAllMarkedItems(); + PlaceCheckMarkOnFont(info.f_family, info.f_style); + } + + status_t + FontMenu::PlaceCheckMarkOnFont(font_family family, font_style style) + { + BMenuItem *fontFamilyItem; + BMenuItem *fontStyleItem; + BMenu *styleMenu; + + fontFamilyItem = FindItem(family); + + if ((fontFamilyItem != NULL) && (family != NULL)) + { + fontFamilyItem->SetMarked(true); + styleMenu = fontFamilyItem->Submenu(); + + if ((styleMenu != NULL) && (style != NULL)) + { + fontStyleItem = styleMenu->FindItem(style); + + if (fontStyleItem != NULL) + { + fontStyleItem->SetMarked(true); + } + + } + else + return B_ERROR; + } + else + return B_ERROR; + + + return B_OK; + } + + void + FontMenu::ClearAllMarkedItems() + { + // we need to clear all menuitems and submenuitems + for (int i = 0; i < CountItems(); i++) { + ItemAt(i)->SetMarked(false); + + BMenu *submenu = ItemAt(i)->Submenu(); + for (int j = 0; j < submenu->CountItems(); j++) { + submenu->ItemAt(j)->SetMarked(false); + } + } + + } \ No newline at end of file diff --git a/src/prefs/menu/FontSizeMenu.cpp b/src/prefs/menu/FontSizeMenu.cpp new file mode 100644 index 0000000000..caf5e90d00 --- /dev/null +++ b/src/prefs/menu/FontSizeMenu.cpp @@ -0,0 +1,69 @@ + + #include "MenuApp.h" + + FontSizeMenu::FontSizeMenu() + :BMenu("Font Size", B_ITEMS_IN_COLUMN) + { + get_menu_info(&info); + + BMessage *msg = new BMessage(MENU_FONT_SIZE); + msg->AddFloat("size", 9); + fontSizeNine = new BMenuItem("9", msg, 0, 0); + AddItem(fontSizeNine); + if(info.font_size == 9){fontSizeNine->SetMarked(true);} + + msg = new BMessage(MENU_FONT_SIZE); + msg->AddFloat("size", 10); + fontSizeTen = new BMenuItem("10", msg, 0, 0); + AddItem(fontSizeTen); + if(info.font_size == 10){fontSizeTen->SetMarked(true);} + + msg = new BMessage(MENU_FONT_SIZE); + msg->AddFloat("size", 11); + fontSizeEleven = new BMenuItem("11", msg, 0, 0); + AddItem(fontSizeEleven); + if(info.font_size == 11){fontSizeEleven->SetMarked(true);} + + msg = new BMessage(MENU_FONT_SIZE); + msg->AddFloat("size", 12); + fontSizeTwelve = new BMenuItem("12", msg, 0, 0); + AddItem(fontSizeTwelve); + if(info.font_size == 12){fontSizeTwelve->SetMarked(true);} + + msg = new BMessage(MENU_FONT_SIZE); + msg->AddFloat("size", 14); + fontSizeFourteen = new BMenuItem("14", msg, 0, 0); + AddItem(fontSizeFourteen); + if(info.font_size == 14){fontSizeFourteen->SetMarked(true);} + + msg = new BMessage(MENU_FONT_SIZE); + msg->AddFloat("size", 18); + fontSizeEighteen = new BMenuItem("18", msg, 0, 0); + AddItem(fontSizeEighteen); + if(info.font_size == 18){fontSizeEighteen->SetMarked(true);} + + SetTargetForItems(Window()); + SetRadioMode(true); + } + + FontSizeMenu::~FontSizeMenu() + { } + + void + FontSizeMenu::Update() + { + get_menu_info(&info); + BFont font; + + Supermenu()->Window()->Lock(); + font.SetFamilyAndStyle(info.f_family, info.f_style); + font.SetSize(info.font_size); + SetFont(&font); + SetViewColor(info.background_color); + Supermenu()->Window()->Unlock(); + set_menu_info(&info); + + InvalidateLayout(); + Invalidate(); + SetEnabled(true); + } \ No newline at end of file diff --git a/src/prefs/menu/Jamfile b/src/prefs/menu/Jamfile new file mode 100644 index 0000000000..7274c539f0 --- /dev/null +++ b/src/prefs/menu/Jamfile @@ -0,0 +1,7 @@ +SubDir OBOS_TOP sources os kits interface prefs menu ; + +Preference Menu : BitmapMenuItem.cpp ColorPicker.cpp ColorWindow.cpp FontMenu.cpp FontSizeMenu.cpp MenuApp.cpp MenuBar.cpp MenuWindow.cpp ; + +LinkSharedOSLibs Menu : translation be root ; + +AddResources Menu : Menu.rsrc ; diff --git a/src/prefs/menu/Menu.rsrc b/src/prefs/menu/Menu.rsrc new file mode 100644 index 0000000000..0192e861fb Binary files /dev/null and b/src/prefs/menu/Menu.rsrc differ diff --git a/src/prefs/menu/MenuApp.cpp b/src/prefs/menu/MenuApp.cpp new file mode 100644 index 0000000000..75c54dd545 --- /dev/null +++ b/src/prefs/menu/MenuApp.cpp @@ -0,0 +1,55 @@ + + #include "MenuApp.h" + + MenuApp::MenuApp() + : BApplication("application/x-vnd.Be-GGUI") + { + get_menu_info(&info); + + menuWindow = new MenuWindow(); + Update(); + menuWindow->Show(); + } + + MenuApp::~MenuApp() + {/*nothing to clean up*/} + + bool + MenuApp::QuitRequested() + { + return true; + } + + void + MenuApp::Update() + { + menuWindow->Update(); + } + + int main() + { + new MenuApp(); + be_app -> Run(); + delete be_app; + } + + void + MenuApp::MessageReceived(BMessage *msg){ + switch(msg->what) { + + //others + case UPDATE_WINDOW: + case CLICK_OPEN_MSG: + case ALLWAYS_TRIGGERS_MSG: + case CTL_MARKED_MSG: + case ALT_MARKED_MSG: + case COLOR_SCHEME_MSG: + case MENU_COLOR: + menuWindow->PostMessage(msg); + break; + + default: + BMessage(msg); + break; + } + } \ No newline at end of file diff --git a/src/prefs/menu/MenuApp.h b/src/prefs/menu/MenuApp.h new file mode 100644 index 0000000000..ac8437b68b --- /dev/null +++ b/src/prefs/menu/MenuApp.h @@ -0,0 +1,142 @@ + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #include "BitmapMenuItem.h" + + #ifndef MENU_H + #define MENU_H + + #include "msg.h" + + class FontSizeMenu : public BMenu { + public: + FontSizeMenu(); + virtual ~FontSizeMenu(); + virtual void Update(); + + menu_info info; + BMenuItem *fontSizeNine; + BMenuItem *fontSizeTen; + BMenuItem *fontSizeEleven; + BMenuItem *fontSizeTwelve; + BMenuItem *fontSizeFourteen; + BMenuItem *fontSizeEighteen; + }; + + class FontMenu : public BMenu { + public: + FontMenu(); + virtual ~FontMenu(); + virtual void GetFonts(); + virtual void Update(); + virtual status_t PlaceCheckMarkOnFont(font_family family, font_style style); + virtual void ClearAllMarkedItems(); + + menu_info info; + BMenuItem *fontFamily; + BMenu *fontStyleMenu; + BMenuItem *fontStyleItem; + }; + + class MenuBar : public BMenuBar { + public: + MenuBar(); + virtual ~MenuBar(); + void set_menu(); + void build_menu(); + virtual void Update(); + virtual void FrameResized(float width, float height); + + BRect menu_rect; + BRect rect; + menu_info info; + + //bitmaps + BBitmap *fCtlBmp; + BBitmap *fAltBmp; + BBitmap *fSep0Bmp; + BBitmap *fSep1Bmp; + BBitmap *fSep2Bmp; + + //seperator submenu + BMenu *separatorStyleMenu; + BMenuItem *separatorStyleZero; + BMenuItem *separatorStyleOne; + BMenuItem *separatorStyleTwo; + + //others + FontMenu *fontMenu; + FontSizeMenu *fontSizeMenu; + BMenuItem *clickToOpenItem; + BMenuItem *alwaysShowTriggersItem; + BMenuItem *colorSchemeItem; + BMenuItem *separatorStyleItem; + BMenuItem *ctlAsShortcutItem; + BMenuItem *altAsShortcutItem; + }; + + class ColorPicker : public BColorControl { + public: + ColorPicker(); + virtual ~ColorPicker(); + virtual void MessageReceived(BMessage *msg); + }; + + class ColorWindow : public BWindow { + public: + ColorWindow(); + virtual ~ColorWindow(); + virtual void MessageReceived(BMessage *msg); + + ColorPicker *colorPicker; + BButton *DefaultButton; + BButton *RevertButton; + menu_info revert_info; + menu_info info; + }; + + class MenuWindow : public BWindow { + public: + MenuWindow(); + virtual ~MenuWindow(); + virtual void MessageReceived(BMessage *msg); + virtual bool QuitRequested(); + virtual void Update(); + void Defaults(); + + bool revert; + ColorWindow *colorWindow; + BMenuItem *toggleItem; + menu_info info; + menu_info revert_info; + BRect rect; + BMenu *menu; + MenuBar *menuBar; + BBox *menuView; + BButton *revertButton; + BButton *defaultButton; + }; + + class MenuApp : public BApplication { + public: + MenuApp(); + virtual ~MenuApp(); + virtual void Update(); + virtual void MessageReceived(BMessage *msg); + virtual bool QuitRequested(); + + //main + MenuWindow *menuWindow; + BRect rect; + menu_info info; + BMenu *menu; + }; + + #endif \ No newline at end of file diff --git a/src/prefs/menu/MenuBar.cpp b/src/prefs/menu/MenuBar.cpp new file mode 100644 index 0000000000..b35676ed6b --- /dev/null +++ b/src/prefs/menu/MenuBar.cpp @@ -0,0 +1,141 @@ + #include "MenuApp.h" + #include + #include + #include + #include + + MenuBar::MenuBar() + :BMenuBar(BRect(40,10,10,10), "menu", B_FOLLOW_TOP|B_FRAME_EVENTS, B_ITEMS_IN_COLUMN, true) + { + fCtlBmp = BTranslationUtils::GetBitmap(B_RAW_TYPE, "CTL"); + fAltBmp = BTranslationUtils::GetBitmap(B_RAW_TYPE, "ALT"); + fSep0Bmp = BTranslationUtils::GetBitmap(B_RAW_TYPE, "SEP0"); + fSep1Bmp = BTranslationUtils::GetBitmap(B_RAW_TYPE, "SEP1"); + fSep2Bmp = BTranslationUtils::GetBitmap(B_RAW_TYPE, "SEP2"); + + + get_menu_info(&info); + build_menu(); + set_menu(); + } + + MenuBar::~MenuBar() + { /*nothing to clean up*/} + + void + MenuBar::build_menu() + { + // font and font size menus + fontMenu = new FontMenu(); + fontSizeMenu = new FontSizeMenu(); + + // create the menu items + clickToOpenItem = new BMenuItem("Click To Open", new BMessage(CLICK_OPEN_MSG), 0, 0); + alwaysShowTriggersItem = new BMenuItem("Always Show Triggers", new BMessage(ALLWAYS_TRIGGERS_MSG), 0, 0); + separatorStyleItem = new BMenuItem("Separator Style", new BMessage(DEFAULT_MSG), 0, 0); + ctlAsShortcutItem = new BitmapMenuItem("as Shortcut Key", new BMessage(CTL_MARKED_MSG), fCtlBmp); + altAsShortcutItem = new BitmapMenuItem("as Shortcut Key", new BMessage(ALT_MARKED_MSG), fAltBmp); + + // color menu + colorSchemeItem = new BMenuItem("Color Scheme...", new BMessage(COLOR_SCHEME_MSG), 0, 0); + + // create the separator menu + separatorStyleMenu = new BMenu("Separator Style", B_ITEMS_IN_COLUMN); + separatorStyleMenu->SetRadioMode(true); + BMessage *msg = new BMessage(MENU_SEP_TYPE); + msg->AddInt32("sep", 0); + separatorStyleZero = new BitmapMenuItem(" ", msg, fSep0Bmp); + msg = new BMessage(MENU_SEP_TYPE); + msg->AddInt32("sep", 1); + separatorStyleOne = new BitmapMenuItem("", msg, fSep1Bmp); + msg = new BMessage(MENU_SEP_TYPE); + msg->AddInt32("sep", 2); + separatorStyleTwo = new BitmapMenuItem("", msg, fSep2Bmp); + if (info.separator == 0) + separatorStyleZero->SetMarked(true); + if (info.separator == 1) + separatorStyleOne->SetMarked(true); + if (info.separator == 2) + separatorStyleTwo->SetMarked(true); + separatorStyleMenu->AddItem(separatorStyleZero); + separatorStyleMenu->AddItem(separatorStyleOne); + separatorStyleMenu->AddItem(separatorStyleTwo); + separatorStyleMenu->SetTargetForItems(Window()); + + // Add items to menubar + AddItem(fontMenu, 0); + AddItem(fontSizeMenu, 1); + AddSeparatorItem(); + AddItem(clickToOpenItem); + AddItem(alwaysShowTriggersItem); + AddSeparatorItem(); + AddItem(colorSchemeItem); + AddItem(separatorStyleMenu); + AddSeparatorItem(); + AddItem(ctlAsShortcutItem); + AddItem(altAsShortcutItem); + SetTargetForItems(Window()); + } + + void + MenuBar::set_menu() + { + key_map *keys; + char *chars; + bool altAsShortcut; + + // get up-to-date menu info + get_menu_info(&info); + + alwaysShowTriggersItem->SetMarked(info.triggers_always_shown); + + clickToOpenItem->SetMarked(info.click_to_open); + alwaysShowTriggersItem->SetEnabled(!info.click_to_open); + + get_key_map(&keys, &chars); + + altAsShortcut = (keys->left_command_key == 0x5d) && (keys->right_command_key == 0x5f); + altAsShortcutItem->SetMarked(altAsShortcut); + ctlAsShortcutItem->SetMarked(!altAsShortcut); + + free(chars); + free(keys); + } + + void + MenuBar::Update() + { + // get up-to-date menu info + get_menu_info(&info); + + // update submenus + fontMenu->Update(); + fontSizeMenu->Update(); + + // this needs to be updated in case the Defaults + // were requested. + if (info.separator == 0) + separatorStyleZero->SetMarked(true); + else if (info.separator == 1) + separatorStyleOne->SetMarked(true); + else if (info.separator == 2) + separatorStyleTwo->SetMarked(true); + + set_menu(); + + BFont font; + Window()->Lock(); + font.SetFamilyAndStyle(info.f_family, info.f_style); + font.SetSize(info.font_size); + SetFont(&font); + SetViewColor(info.background_color); + Window()->Unlock(); + + // force the menu to redraw + InvalidateLayout(); + } + + void MenuBar::FrameResized(float width, float height) + { + Window()->PostMessage(UPDATE_WINDOW); + } \ No newline at end of file diff --git a/src/prefs/menu/MenuWindow.cpp b/src/prefs/menu/MenuWindow.cpp new file mode 100644 index 0000000000..90a7f8feca --- /dev/null +++ b/src/prefs/menu/MenuWindow.cpp @@ -0,0 +1,202 @@ + #include "MenuApp.h" + #include + #include + + int ans; + + MenuWindow::MenuWindow() + : BWindow(rect, "Menu", B_TITLED_WINDOW, B_NOT_ZOOMABLE | B_NOT_RESIZABLE) + { + get_menu_info(&revert_info); + get_menu_info(&info); + + revert = false; + + MoveTo((rect.left += 100),(rect.top += 100)); + BRect r = Bounds(); + r.left -= 1; + r.top -= 1; + menuView = new BBox(r, "menuView", + B_FOLLOW_ALL, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE); + menuView->SetViewColor(219,219,219,255); + menuBar = new MenuBar(); + menuView->AddChild(menuBar); + AddChild(menuView); + menuView->ResizeTo((Frame().right),(Frame().bottom)); + defaultButton = new BButton(BRect(10,0,85,20), "Default", "Defaults", + new BMessage(MENU_DEFAULT), B_FOLLOW_LEFT | B_FOLLOW_BOTTOM, B_WILL_DRAW | B_NAVIGABLE); + revertButton = new BButton(BRect(95,0,175,20), "Revert", "Revert", + new BMessage(MENU_REVERT), B_FOLLOW_LEFT | B_FOLLOW_BOTTOM, B_WILL_DRAW | B_NAVIGABLE); + revertButton->SetEnabled(false); + + menuView->AddChild(defaultButton); + menuView->AddChild(revertButton); + + Update(); + + } + + MenuWindow::~MenuWindow() + {/*nothing to delete;*/} + + void + MenuWindow::MessageReceived(BMessage *msg) + { + switch(msg->what) { + + case MENU_REVERT: + set_menu_info(&revert_info); + revert = false; + Update(); + break; + + case MENU_DEFAULT: + Defaults(); + break; + + case UPDATE_WINDOW: + Update(); + break; + + case MENU_FONT_FAMILY: + case MENU_FONT_STYLE: + { + font_family *family; + msg->FindPointer("family", (void**)&family); + font_style *style; + msg->FindPointer("style", (void**)&style); + info.f_family = *family; + info.f_style = *style; + set_menu_info(&info); + Update(); + break; + } + + case MENU_FONT_SIZE: + revert = true; + float f; + msg->FindFloat("size", &f); + info.font_size = f; + set_menu_info(&info); + Update(); + break; + + case MENU_SEP_TYPE: + revert = true; + int32 i; + msg->FindInt32("sep", &i); + info.separator = i; + set_menu_info(&info); + Update(); + break; + + case CLICK_OPEN_MSG: + revert = true; + if (info.click_to_open != true) + info.click_to_open = true; + else + info.click_to_open = false; + set_menu_info(&info); + menuBar->set_menu(); + Update(); + break; + + case ALLWAYS_TRIGGERS_MSG: + revert = true; + if (info.triggers_always_shown != true) + info.triggers_always_shown = true; + else + info.triggers_always_shown = false; + set_menu_info(&info); + menuBar->set_menu(); + Update(); + break; + + case CTL_MARKED_MSG: + revert = true; + menuBar->ctlAsShortcutItem->SetMarked(true); + menuBar->altAsShortcutItem->SetMarked(false); + // This might not be the same for all keyboards + set_modifier_key(B_LEFT_COMMAND_KEY, 0x5c); + set_modifier_key(B_RIGHT_COMMAND_KEY, 0x60); + set_modifier_key(B_LEFT_CONTROL_KEY, 0x5d); + set_modifier_key(B_RIGHT_OPTION_KEY, 0x5f); + + be_roster->Broadcast(new BMessage(B_MODIFIERS_CHANGED)); + Update(); + break; + + case ALT_MARKED_MSG: + revert = true; + menuBar->altAsShortcutItem->SetMarked(true); + menuBar->ctlAsShortcutItem->SetMarked(false); + // This might not be the same for all keyboards + set_modifier_key(B_LEFT_COMMAND_KEY, 0x5d); + set_modifier_key(B_RIGHT_COMMAND_KEY, 0x5f); + set_modifier_key(B_LEFT_CONTROL_KEY, 0x5c); + set_modifier_key(B_RIGHT_OPTION_KEY, 0x60); + + be_roster->Broadcast(new BMessage(B_MODIFIERS_CHANGED)); + Update(); + break; + + case COLOR_SCHEME_MSG: + colorWindow = new ColorWindow(); + colorWindow->Show(); + break; + + case MENU_COLOR: + set_menu_info(&info); + (new BAlert("test","we made it","cool"))->Go(); + break; + + default: + BMessage(msg); + break; + } + } + + bool + MenuWindow::QuitRequested() + { + be_app->PostMessage(B_QUIT_REQUESTED); + return true; + } + + void + MenuWindow::Update() + { + revertButton->SetEnabled(revert); + + // alert the rest of the application to update + menuBar->Update(); + + // resize the window according to the size of menuBar + ResizeTo((menuBar->Frame().right + 35), (menuBar->Frame().bottom + 45)); + } + + void + MenuWindow::Defaults() + { + // to set the default color. this should be changed + // to the system color for system wide compatability. + rgb_color color; + color.red = 219; + color.blue = 219; + color.green = 219; + color.alpha = 255; + + // the default settings. possibly a call to the app_server + // would provide and execute this information, as it does + // for get_menu_info and set_menu_info (or is this information + // coming from libbe.so? or else where?). + info.font_size = 12; + //info.f_family = "test"; + //info.f_style = "test"; + info.background_color = color; + info.separator = 0; + info.click_to_open = true; + info.triggers_always_shown = false; + set_menu_info(&info); + Update(); + } \ No newline at end of file diff --git a/src/prefs/menu/msg.h b/src/prefs/menu/msg.h new file mode 100644 index 0000000000..a4ba496527 --- /dev/null +++ b/src/prefs/menu/msg.h @@ -0,0 +1,27 @@ + + const uint32 MENU_BAR_ARCHIVE = 'mbar'; + +//default + const uint32 DEFAULT_MSG = 'dmsg'; + const uint32 MENU_DEFAULT = 'mede'; + const uint32 MENU_REVERT = 'mere'; + +//others + const uint32 UPDATE_WINDOW = 'uwin'; + const uint32 ALLWAYS_TRIGGERS_MSG = 'alti'; + const uint32 COLOR_SCHEME_MSG = 'cosc'; + const uint32 CTL_MARKED_MSG = 'ctms'; + const uint32 ALT_MARKED_MSG = 'alms'; + +//color + const uint32 MENU_COLOR = 'meco'; + const uint32 CLICK_OPEN_MSG = 'clop'; + const uint32 MENU_COLOR_DEFAULT = 'mcod'; + +//font + const uint32 MENU_FONT_FAMILY = 'mffm'; + const uint32 MENU_FONT_STYLE = 'mfst'; + const uint32 MENU_FONT_SIZE = 'mfsz'; + +//seperator + const uint32 MENU_SEP_TYPE = 'mstp'; \ No newline at end of file diff --git a/src/prefs/mouse/Jamfile b/src/prefs/mouse/Jamfile new file mode 100644 index 0000000000..39e5dfcba6 --- /dev/null +++ b/src/prefs/mouse/Jamfile @@ -0,0 +1,7 @@ +SubDir OBOS_TOP sources os kits input prefs mouse ; + +Preference Mouse : Mouse.cpp MouseSettings.cpp MouseView.cpp MouseWindow.cpp ; + +LinkSharedOSLibs Mouse : translation be root ; + +AddResources Mouse : Mouse.rsrc ; diff --git a/src/prefs/mouse/Mouse.cpp b/src/prefs/mouse/Mouse.cpp new file mode 100644 index 0000000000..1b6b48df8b --- /dev/null +++ b/src/prefs/mouse/Mouse.cpp @@ -0,0 +1,88 @@ +/* + * Mouse.cpp + * Mouse mccall@digitalparadise.co.uk + * + */ + +#include +#include + +#include "Mouse.h" +#include "MouseWindow.h" +#include "MouseSettings.h" +#include "MouseMessages.h" + +const char MouseApplication::kMouseApplicationSig[] = "application/x-vnd.OpenBeOS-MOUS"; + +int main(int, char**) +{ + MouseApplication myApplication; + + myApplication.Run(); + + return(0); +} + +MouseApplication::MouseApplication() + :BApplication(kMouseApplicationSig) +{ + + MouseWindow *window; + + fSettings = new MouseSettings(); + + window = new MouseWindow(); + +} + +void +MouseApplication::MessageReceived(BMessage *message) +{ + switch(message->what) { + case ERROR_DETECTED: + { + BAlert *errorAlert = new BAlert("Error", "Something has gone wrong!","OK",NULL,NULL,B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_WARNING_ALERT); + errorAlert->Go(); + be_app->PostMessage(B_QUIT_REQUESTED); + } + break; + default: + BApplication::MessageReceived(message); + break; + } +} + +void +MouseApplication::SetWindowCorner(BPoint corner) +{ + fSettings->SetWindowCorner(corner); +} + +void +MouseApplication::SetMouseType(mouse_type type) +{ + fSettings->SetMouseType(type); +} + +void +MouseApplication::SetClickSpeed(bigtime_t click_speed) +{ + fSettings->SetClickSpeed(click_speed); +} + +void +MouseApplication::SetMouseSpeed(int32 speed) +{ + fSettings->SetMouseSpeed(speed); +} + +void +MouseApplication::AboutRequested(void) +{ + (new BAlert("about", "...by Andrew Edward McCall", "Dig Deal"))->Go(); +} + +MouseApplication::~MouseApplication() +{ + delete fSettings; +} \ No newline at end of file diff --git a/src/prefs/mouse/Mouse.h b/src/prefs/mouse/Mouse.h new file mode 100644 index 0000000000..32eeaa96c9 --- /dev/null +++ b/src/prefs/mouse/Mouse.h @@ -0,0 +1,35 @@ +#ifndef MOUSE_H +#define MOUSE_H + +#include + +#include "MouseWindow.h" +#include "MouseSettings.h" + +class MouseApplication : public BApplication +{ +public: + MouseApplication(); + virtual ~MouseApplication(); + + void MessageReceived(BMessage *message); + BPoint WindowCorner() const {return fSettings->WindowCorner(); } + void SetWindowCorner(BPoint corner); + int32 MouseType() const {return fSettings->MouseType(); } + void SetMouseType(mouse_type type); + bigtime_t ClickSpeed() const {return fSettings->ClickSpeed(); } + void SetClickSpeed(bigtime_t click_speed); + int32 MouseSpeed() const {return fSettings->MouseSpeed(); } + void SetMouseSpeed(int32 speed); + + void AboutRequested(void); + +private: + + static const char kMouseApplicationSig[]; + + MouseSettings *fSettings; + +}; + +#endif \ No newline at end of file diff --git a/src/prefs/mouse/Mouse.rsrc b/src/prefs/mouse/Mouse.rsrc new file mode 100644 index 0000000000..e611c5f494 Binary files /dev/null and b/src/prefs/mouse/Mouse.rsrc differ diff --git a/src/prefs/mouse/MouseMessages.h b/src/prefs/mouse/MouseMessages.h new file mode 100644 index 0000000000..ffa9090306 --- /dev/null +++ b/src/prefs/mouse/MouseMessages.h @@ -0,0 +1,22 @@ +/* + + MouseMessages.h + +*/ + +#ifndef MOUSE_MESSAGES_H +#define MOUSE_MESSAGES_H + +const uint32 BUTTON_DEFAULTS = 'BTde'; +const uint32 BUTTON_REVERT = 'BTre'; + +const uint32 POPUP_MOUSE_TYPE = 'PUmt'; + +const uint32 DOUBLE_CLICK_TEST_AREA = 'TCte'; + +const uint32 SLIDER_DOUBLE_CLICK_SPEED = 'SLdc'; +const uint32 SLIDER_MOUSE_SPEED = 'SLms'; + +const uint32 ERROR_DETECTED = 'ERor'; + +#endif \ No newline at end of file diff --git a/src/prefs/mouse/MouseSettings.cpp b/src/prefs/mouse/MouseSettings.cpp new file mode 100644 index 0000000000..59145e8b8a --- /dev/null +++ b/src/prefs/mouse/MouseSettings.cpp @@ -0,0 +1,101 @@ +/* + * MouseSettings.cpp + * Mouse mccall@digitalparadise.co.uk + * + */ + +#include +#include +#include +#include +#include +#include + +#include "MouseSettings.h" +#include "MouseMessages.h" + +const char MouseSettings::kMouseSettingsFile[] = "Mouse_settings"; + +MouseSettings::MouseSettings() +{ + BPath path; + + if (find_directory(B_USER_SETTINGS_DIRECTORY,&path) == B_OK) { + path.Append(kMouseSettingsFile); + BFile file(path.Path(), B_READ_ONLY); + if (file.InitCheck() == B_OK) { + // Now read in the data + if (file.Read(&fSettings, sizeof(mouse_settings)) != sizeof(mouse_settings)) { + if (get_mouse_type((int32*)&fSettings.type) != B_OK) + be_app->PostMessage(ERROR_DETECTED); + if (get_mouse_map(&fSettings.map) != B_OK) + be_app->PostMessage(ERROR_DETECTED); + if (get_mouse_speed((int32 *)&fSettings.accel.speed) != B_OK) + be_app->PostMessage(ERROR_DETECTED); + if (get_click_speed(&fSettings.click_speed) != B_OK) + be_app->PostMessage(ERROR_DETECTED); + } + + if (file.Read(&fCorner, sizeof(BPoint)) != sizeof(BPoint)) { + fCorner.x=50; + fCorner.y=50; + } + } + else { + if (get_mouse_type((int32*)&fSettings.type) != B_OK) + be_app->PostMessage(ERROR_DETECTED); + if (get_mouse_map(&fSettings.map) != B_OK) + be_app->PostMessage(ERROR_DETECTED); + + if (get_click_speed(&fSettings.click_speed) != B_OK) + be_app->PostMessage(ERROR_DETECTED); + fCorner.x=50; + fCorner.y=50; + } + } + else + be_app->PostMessage(ERROR_DETECTED); + + printf("Size is : %ld\n",sizeof(mouse_settings)+sizeof(BPoint)); + +} + +MouseSettings::~MouseSettings() +{ + BPath path; + + if (find_directory(B_USER_SETTINGS_DIRECTORY,&path) < B_OK) + return; + + path.Append(kMouseSettingsFile); + + BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE); + if (file.InitCheck() == B_OK) { + file.Write(&fSettings, sizeof(mouse_settings)); + file.Write(&fCorner, sizeof(BPoint)); + } +} + +void +MouseSettings::SetWindowCorner(BPoint corner) +{ + fCorner=corner; +} + +void +MouseSettings::SetMouseType(mouse_type type) +{ + fSettings.type=type; +} + +void +MouseSettings::SetClickSpeed(bigtime_t click_speed) +{ + fSettings.click_speed=-(click_speed-1000000); +} + +void +MouseSettings::SetMouseSpeed(int32 accel) +{ + fSettings.accel.speed=accel; +} \ No newline at end of file diff --git a/src/prefs/mouse/MouseSettings.h b/src/prefs/mouse/MouseSettings.h new file mode 100644 index 0000000000..5f082ada39 --- /dev/null +++ b/src/prefs/mouse/MouseSettings.h @@ -0,0 +1,47 @@ +#ifndef MOUSE_SETTINGS_H_ +#define MOUSE_SETTINGS_H_ + +#include +#include + +typedef enum { + MOUSE_1_BUTTON = 1, + MOUSE_2_BUTTON, + MOUSE_3_BUTTON +} mouse_type; + + +typedef struct { + bool enabled; // Acceleration on / off + int32 accel_factor; // accel factor: 256 = step by 1, 128 = step by 1/2 + int32 speed; // speed accelerator (1=1X, 2 = 2x)... +} mouse_accel; + +typedef struct { + mouse_type type; + mouse_map map; + mouse_accel accel; + bigtime_t click_speed; +} mouse_settings; + +class MouseSettings{ +public : + MouseSettings(); + ~MouseSettings(); + + BPoint WindowCorner() const { return fCorner; } + void SetWindowCorner(BPoint corner); + mouse_type MouseType() const { return fSettings.type; } + void SetMouseType(mouse_type type); + bigtime_t ClickSpeed() const { return -(fSettings.click_speed-1000000); } // -1000000 to correct the Sliders 0-100000 scale + void SetClickSpeed(bigtime_t click_speed); + int32 MouseSpeed() const { return fSettings.accel.speed; } + void SetMouseSpeed(int32 speed); + +private: + static const char kMouseSettingsFile[]; + BPoint fCorner; + mouse_settings fSettings; +}; + +#endif \ No newline at end of file diff --git a/src/prefs/mouse/MouseView.cpp b/src/prefs/mouse/MouseView.cpp new file mode 100644 index 0000000000..5c0f34daae --- /dev/null +++ b/src/prefs/mouse/MouseView.cpp @@ -0,0 +1,137 @@ +/* + + MouseView.cpp + +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MouseView.h" +#include "MouseMessages.h" + + +MouseView::MouseView(BRect rect) + : BBox(rect, "mouse_view", + B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP, + B_PLAIN_BORDER) +{ + BRect frame; + BButton *button; + BTextControl *textcontrol; + BSlider *slider; + BPopUpMenu *popupmenu; + BMenuField *menufield; + + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + + fDoubleClickBitmap = BTranslationUtils::GetBitmap("double_click_bmap"); + fSpeedBitmap = BTranslationUtils::GetBitmap("speed_bmap"); + fAccelerationBitmap = BTranslationUtils::GetBitmap("acceleration_bmap"); + + // Add the "Default" button.. + frame.Set(10,259,85,279); + button = new BButton(frame,"mouse_defaults","Defaults", new BMessage(BUTTON_DEFAULTS)); + AddChild(button); + + // Add the "Revert" button... + frame.Set(92,259,167,279); + button = new BButton(frame,"mouse_revert","Revert", new BMessage(BUTTON_REVERT)); + button->SetEnabled(false); + AddChild(button); + + // Create the main box for the controls... + frame=Bounds(); + frame.left=frame.left+11; + frame.top=frame.top+11; + frame.right=frame.right-11; + frame.bottom=frame.bottom-44; + fBox = new BBox(frame,"mouse_box",B_FOLLOW_LEFT,B_WILL_DRAW,B_FANCY_BORDER); + + // Add the "Mouse Type" pop up menu + popupmenu = new BPopUpMenu("Mouse Type Menu"); + popupmenu->AddItem(new BMenuItem("1-Button",new BMessage(POPUP_MOUSE_TYPE))); + popupmenu->AddItem(new BMenuItem("2-Button",new BMessage(POPUP_MOUSE_TYPE))); + popupmenu->AddItem(new BMenuItem("3-Button",new BMessage(POPUP_MOUSE_TYPE))); + + frame.Set(18,10,208,20); + menufield = new BMenuField(frame, "mouse_type", "Mouse Type", popupmenu); + menufield->SetDivider(menufield->Divider() - 30); + fBox->AddChild(menufield); + + // Add the "Mouse Type" pop up menu + popupmenu = new BPopUpMenu("Focus Follows Mouse Menu"); + popupmenu->AddItem(new BMenuItem("Disabled",new BMessage(BUTTON_REVERT))); + popupmenu->AddItem(new BMenuItem("Enabled",new BMessage(BUTTON_REVERT))); + popupmenu->AddItem(new BMenuItem("Warping",new BMessage(BUTTON_REVERT))); + popupmenu->AddItem(new BMenuItem("Instant-Warping",new BMessage(BUTTON_REVERT))); + + frame.Set(168,207,440,200); + menufield = new BMenuField(frame, "Focus follows mouse", "Focus follows mouse:", popupmenu); + menufield->SetDivider(menufield->Divider() - 30); + fBox->AddChild(menufield); + + // Create the "Double-click speed slider... + frame.Set(168,10,328,50); + slider = new BSlider(frame,"double_click_speed","Double-click speed", new BMessage(SLIDER_DOUBLE_CLICK_SPEED),0,1000000,B_BLOCK_THUMB,B_FOLLOW_LEFT,B_WILL_DRAW); + slider->SetHashMarks(B_HASH_MARKS_BOTTOM); + slider->SetHashMarkCount(5); + slider->SetLimitLabels("Slow","Fast"); + fBox->AddChild(slider); + + // Create the "Mouse Speed" slider... + frame.Set(168,75,328,125); + slider = new BSlider(frame,"mouse_speed","Mouse Speed", new BMessage(SLIDER_MOUSE_SPEED),8192,524287,B_BLOCK_THUMB,B_FOLLOW_LEFT,B_WILL_DRAW); + slider->SetHashMarks(B_HASH_MARKS_BOTTOM); + slider->SetHashMarkCount(7); + slider->SetLimitLabels("Slow","Fast"); + fBox->AddChild(slider); + + // Create the "Mouse Acceleration" slider... + frame.Set(168,140,328,190); + slider = new BSlider(frame,"mouse_acceleration","Mouse Acceleration", new BMessage(SLIDER_MOUSE_SPEED),250000,1000000,B_BLOCK_THUMB,B_FOLLOW_LEFT,B_WILL_DRAW); + slider->SetHashMarks(B_HASH_MARKS_BOTTOM); + slider->SetHashMarkCount(5); + slider->SetLimitLabels("Slow","Fast"); + fBox->AddChild(slider); + + // Create the "Double-click test area" text box... + frame=fBox->Bounds(); + frame.left=frame.left+10; + frame.right=frame.right-230; + frame.top=frame.bottom-30; + textcontrol = new BTextControl(frame,"double_click_test_area",NULL,"Double-click test area", new BMessage(DOUBLE_CLICK_TEST_AREA),B_FOLLOW_LEFT,B_WILL_DRAW); + textcontrol->SetAlignment(B_ALIGN_LEFT,B_ALIGN_CENTER); + fBox->AddChild(textcontrol); + + AddChild(fBox); + +} + +void MouseView::Draw(BRect updateFrame) +{ + inherited::Draw(updateFrame); + fBox->SetHighColor(120,120,120); + fBox->SetLowColor(255,255,255); + // Line above the test area + fBox->StrokeLine(BPoint(10,199),BPoint(150,199),B_SOLID_HIGH); + fBox->StrokeLine(BPoint(11,200),BPoint(150,200),B_SOLID_LOW); + // Line above focus follows mouse + fBox->StrokeLine(BPoint(170,199),BPoint(362,199),B_SOLID_HIGH); + fBox->StrokeLine(BPoint(171,200),BPoint(362,200),B_SOLID_LOW); + // Line in the middle + fBox->StrokeLine(BPoint(160,10),BPoint(160,230),B_SOLID_HIGH); + fBox->StrokeLine(BPoint(161,11),BPoint(161,230),B_SOLID_LOW); + //Draw the icons + fBox->DrawBitmap(fDoubleClickBitmap,BPoint(341,20)); + fBox->DrawBitmap(fSpeedBitmap,BPoint(331,90)); + fBox->DrawBitmap(fAccelerationBitmap,BPoint(331,155)); + +} \ No newline at end of file diff --git a/src/prefs/mouse/MouseView.h b/src/prefs/mouse/MouseView.h new file mode 100644 index 0000000000..5da3d008b6 --- /dev/null +++ b/src/prefs/mouse/MouseView.h @@ -0,0 +1,29 @@ +/* + + MouseView.h + +*/ + +#ifndef MOUSE_VIEW_H +#define MOUSE_VIEW_H + +#include +#include + +class MouseView : public BBox +{ +public: + typedef BBox inherited; + + MouseView(BRect frame); + virtual void Draw(BRect frame); + +private: + BBox *fBox; + + BBitmap *fDoubleClickBitmap; + BBitmap *fSpeedBitmap; + BBitmap *fAccelerationBitmap; +}; + +#endif diff --git a/src/prefs/mouse/MouseWindow.cpp b/src/prefs/mouse/MouseWindow.cpp new file mode 100644 index 0000000000..9719749177 --- /dev/null +++ b/src/prefs/mouse/MouseWindow.cpp @@ -0,0 +1,126 @@ +/* + * MouseWindow.cpp + * Mouse mccall@digitalparadise.co.uk + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MouseMessages.h" +#include "MouseWindow.h" +#include "MouseView.h" +#include "Mouse.h" + +#define MOUSE_WINDOW_RIGHT 397 +#define MOUSE_WINDOW_BOTTTOM 293 + +MouseWindow::MouseWindow() + : BWindow(BRect(0,0,MOUSE_WINDOW_RIGHT,MOUSE_WINDOW_BOTTTOM), "Mouse", B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE ) +{ + BScreen screen; + BSlider *slider=NULL; + BMenuField *menufield=NULL; + + MoveTo(dynamic_cast(be_app)->WindowCorner()); + + // Code to make sure that the window doesn't get drawn off screen... + if (!(screen.Frame().right >= Frame().right && screen.Frame().bottom >= Frame().bottom)) + MoveTo((screen.Frame().right-Bounds().right)*.5,(screen.Frame().bottom-Bounds().bottom)*.5); + + BuildView(); + AddChild(fView); + + + menufield = (BMenuField *)FindView("mouse_type"); + if (menufield !=NULL) + menufield->Menu()->ItemAt((dynamic_cast(be_app)->MouseType())-1)->SetMarked(true); + + slider = (BSlider *)FindView("double_click_speed"); + if (slider !=NULL) slider->SetValue((dynamic_cast(be_app)->ClickSpeed())); + + slider = (BSlider *)FindView("mouse_speed"); + if (slider !=NULL) slider->SetValue((dynamic_cast(be_app)->MouseSpeed())); + Show(); + +} + +void +MouseWindow::BuildView() +{ + fView = new MouseView(Bounds()); +} + +bool +MouseWindow::QuitRequested() +{ + + BSlider *slider=NULL; + BMenuField *menufield=NULL; + + dynamic_cast(be_app)->SetWindowCorner(BPoint(Frame().left,Frame().top)); + + slider = (BSlider *)FindView("double_click_speed"); + if (slider !=NULL) + dynamic_cast(be_app)->SetClickSpeed(slider->Value()); + + + + menufield = (BMenuField *)FindView("mouse_type"); + if (menufield !=NULL) { + BMenu *menu; + menu = menufield->Menu(); + dynamic_cast(be_app)->SetMouseType((mouse_type)(menu->IndexOf(menu->FindMarked())+1)); + } + + be_app->PostMessage(B_QUIT_REQUESTED); + return(true); +} + +void +MouseWindow::MessageReceived(BMessage *message) +{ + BSlider *slider=NULL; + BButton *button=NULL; + BMenuField *menufield=NULL; + + switch(message->what) { + case BUTTON_DEFAULTS: { + if (set_click_speed(500000)!=B_OK) + be_app->PostMessage(ERROR_DETECTED); + slider = (BSlider *)FindView("double_click_speed"); + if (slider !=NULL) slider->SetValue(500000); + + button = (BButton *)FindView("mouse_revert"); + if (button !=NULL) button->SetEnabled(true); + } + break; + case POPUP_MOUSE_TYPE: { + beep(); + menufield = (BMenuField *)FindView("mouse_type"); + if (menufield !=NULL) { + BMenu *menu; + menu = menufield->Menu(); + if (set_mouse_type(menu->IndexOf(menu->FindMarked())+1) !=B_OK) + be_app->PostMessage(ERROR_DETECTED); + } + } + break; + default: + BWindow::MessageReceived(message); + break; + } + +} + +MouseWindow::~MouseWindow() +{ + +} \ No newline at end of file diff --git a/src/prefs/mouse/MouseWindow.h b/src/prefs/mouse/MouseWindow.h new file mode 100644 index 0000000000..228726a16e --- /dev/null +++ b/src/prefs/mouse/MouseWindow.h @@ -0,0 +1,24 @@ +#ifndef MOUSE_WINDOW_H +#define MOUSE_WINDOW_H + +#include + +#include "MouseSettings.h" +#include "MouseView.h" + +class MouseWindow : public BWindow +{ +public: + MouseWindow(); + ~MouseWindow(); + + bool QuitRequested(); + void MessageReceived(BMessage *message); + void BuildView(); + +private: + MouseView *fView; + +}; + +#endif diff --git a/src/prefs/print/AddPrinterDialog.h b/src/prefs/print/AddPrinterDialog.h new file mode 100644 index 0000000000..b9549ca7f8 --- /dev/null +++ b/src/prefs/print/AddPrinterDialog.h @@ -0,0 +1,19 @@ +#ifndef ADDPRINTERDIALOG_H +#define ADDPRINTERDIALOG_H + +class AddPrinterDialog; + +#include + +class AddPrinterDialog : public BWindow +{ + typedef BWindow Inherited; +public: + static status_t Start(); + +private: + AddPrinterDialog(); + void BuildGUI(); +}; + +#endif diff --git a/src/prefs/print/Globals.cpp b/src/prefs/print/Globals.cpp new file mode 100644 index 0000000000..3b947ad926 --- /dev/null +++ b/src/prefs/print/Globals.cpp @@ -0,0 +1,15 @@ +#include "Globals.h" +#include "pr_server.h" + +#include + +status_t GetPrinterServerMessenger(BMessenger& msgr) +{ + // If print server is not yet running, start it + if (!be_roster->IsRunning(PSRV_SIGNATURE_TYPE)) + be_roster->Launch(PSRV_SIGNATURE_TYPE); + + msgr = BMessenger(PSRV_SIGNATURE_TYPE); + + return msgr.IsValid() ? B_OK : B_ERROR; +} diff --git a/src/prefs/print/Globals.h b/src/prefs/print/Globals.h new file mode 100644 index 0000000000..9bf4beda6d --- /dev/null +++ b/src/prefs/print/Globals.h @@ -0,0 +1,8 @@ +#ifndef GLOBALS_H +#define GLOBALS_H + +#include + +status_t GetPrinterServerMessenger(BMessenger& msgr); + +#endif diff --git a/src/prefs/print/Messages.h b/src/prefs/print/Messages.h new file mode 100644 index 0000000000..f8219c9ebe --- /dev/null +++ b/src/prefs/print/Messages.h @@ -0,0 +1,32 @@ +/* + * Printers Preference Application. + * Copyright (C) 2001 OpenBeOS. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef MESSAGES_H +#define MESSAGES_H + +#include + +const uint32 MSG_ADD_PRINTER = 'AddP'; +const uint32 MSG_REMOVE_PRINTER = 'RemP'; +const uint32 MSG_MKDEF_PRINTER = 'MDfP'; +const uint32 MSG_PRINTER_SELECTED = 'PSel'; +const uint32 MSG_CANCEL_JOB = 'CncJ'; +const uint32 MSG_RESTART_JOB = 'RstJ'; + +#endif diff --git a/src/prefs/print/PrinterListView.cpp b/src/prefs/print/PrinterListView.cpp new file mode 100644 index 0000000000..1c58156bc6 --- /dev/null +++ b/src/prefs/print/PrinterListView.cpp @@ -0,0 +1,211 @@ +/* + * Printers Preference Application. + * Copyright (C) 2001 OpenBeOS. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "PrinterListView.h" +#include "pr_server.h" + +#include "Messages.h" +#include "Globals.h" + +#include +#include +#include +#include +#include + +PrinterListView::PrinterListView(BRect frame) + : Inherited(frame, "printers_list", B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL) +{ + // TODO: Fixup situation in which PrintServer is not running + BMessenger msgr; + if (GetPrinterServerMessenger(msgr) == B_OK) + { + BMessage count(B_COUNT_PROPERTIES); + count.AddSpecifier("Printers"); + + BMessage reply; + msgr.SendMessage(&count, &reply); + + int32 countPrinters; + if (reply.FindInt32("result", &countPrinters) == B_OK) + { + for (int32 printerIdx=0; printerIdx < countPrinters; printerIdx++) + { + BMessage getPrinter(B_GET_PROPERTY); + getPrinter.AddSpecifier("Printer", printerIdx); + msgr.SendMessage(&getPrinter, &reply); + + reply.PrintToStream(); + + BMessenger thePrinter; + if (reply.FindMessenger("result", &thePrinter) == B_OK) + AddItem(new PrinterItem(thePrinter), CountItems()); + } + } + } +} + +void PrinterListView::AttachedToWindow() +{ + Inherited::AttachedToWindow(); + + SetSelectionMessage(new BMessage(MSG_PRINTER_SELECTED)); + SetInvocationMessage(new BMessage(MSG_MKDEF_PRINTER)); + SetTarget(Window()); +} + +BBitmap* PrinterItem::sIcon = NULL; +BBitmap* PrinterItem::sSelectedIcon = NULL; + +PrinterItem::PrinterItem(const BMessenger& thePrinter) + : BListItem(0, false), + fMessenger(thePrinter) +{ + if (sIcon == NULL) + { + sIcon = new BBitmap(BRect(0,0,B_LARGE_ICON-1,B_LARGE_ICON-1), B_CMAP8); + BMimeType type(PSRV_PRINTER_FILETYPE); + type.GetIcon(sIcon, B_LARGE_ICON); + } + + if (sSelectedIcon == NULL) + { + sSelectedIcon = new BBitmap(BRect(0,0,B_LARGE_ICON-1,B_LARGE_ICON-1), B_CMAP8); + BMimeType type(PRNT_SIGNATURE_TYPE); + type.GetIcon(sSelectedIcon, B_LARGE_ICON); + } + + // Get Name of printer + GetStringProperty("Name", fName); + GetStringProperty("Comments", fComments); + GetStringProperty("TransportAddon", fTransport); + GetStringProperty("PrinterAddon", fDriverName); +} + +void PrinterItem::GetStringProperty(const char* propName, BString& outString) +{ + BMessage script(B_GET_PROPERTY); + BMessage reply; + script.AddSpecifier(propName); + fMessenger.SendMessage(&script,&reply); + reply.FindString("result", &outString); +} + +void PrinterItem::Update(BView *owner, const BFont *font) +{ + BListItem::Update(owner,font); + + font_height height; + font->GetHeight(&height); + + SetHeight( (height.ascent+height.descent+height.leading) * 3.0 +4 ); +} + +void PrinterItem::Remove(BListView* view) +{ + BMessenger msgr; + + if (GetPrinterServerMessenger(msgr) == B_OK) + { + BMessage script(B_DELETE_PROPERTY); + BMessage reply; + + script.AddSpecifier("Printer", view->IndexOf(this)); + + if (msgr.SendMessage(&script,&reply) == B_OK) + view->RemoveItem(this); + } +} + +void PrinterItem::DrawItem(BView *owner, BRect /*bounds*/, bool complete) +{ + BListView* list = dynamic_cast(owner); + if (list) + { + font_height height; + BFont font; + owner->GetFont(&font); + font.GetHeight(&height); + float fntheight = height.ascent+height.descent+height.leading; + + BRect bounds = list->ItemFrame(list->IndexOf(this)); + + rgb_color color = owner->ViewColor(); + if ( IsSelected() ) + color = tint_color(color, B_HIGHLIGHT_BACKGROUND_TINT); + + rgb_color oldviewcolor = owner->ViewColor(); + rgb_color oldlowcolor = owner->LowColor(); + rgb_color oldcolor = owner->HighColor(); + owner->SetViewColor( color ); + owner->SetHighColor( color ); + owner->SetLowColor( color ); + owner->FillRect(bounds); + owner->SetLowColor( oldlowcolor ); + owner->SetHighColor( oldcolor ); + + BPoint iconPt = bounds.LeftTop() + BPoint(2,2); + BPoint namePt = iconPt + BPoint(B_LARGE_ICON+8, fntheight); + BPoint driverPt = iconPt + BPoint(B_LARGE_ICON+8, fntheight*2); + BPoint commentPt = iconPt + BPoint(B_LARGE_ICON+8, fntheight*3); + + float width = owner->StringWidth("No jobs pending."); + BPoint pendingPt(bounds.right - width -8, namePt.y); + BPoint transportPt(bounds.right - width -8, driverPt.y); + + drawing_mode mode = owner->DrawingMode(); + owner->SetDrawingMode(B_OP_OVER); + owner->DrawBitmap(IsActivePrinter() ? sSelectedIcon : sIcon, iconPt); + + // left of item + owner->DrawString(fName.String(), fName.Length(), namePt); + owner->DrawString(fDriverName.String(), fDriverName.Length(), driverPt); + owner->DrawString(fComments.String(), fComments.Length(), commentPt); + + // right of item + owner->DrawString("No jobs pending.", 16, pendingPt); + owner->DrawString(fTransport.String(), fTransport.Length(), transportPt); + + owner->SetDrawingMode(mode); + + owner->SetViewColor(oldviewcolor); + } +} + +bool PrinterItem::IsActivePrinter() +{ + bool rc = false; + BMessenger msgr; + + if (::GetPrinterServerMessenger(msgr) == B_OK) + { + BMessage reply, getNameOfActivePrinter(B_GET_PROPERTY); + getNameOfActivePrinter.AddSpecifier("ActivePrinter"); + + BString activePrinterName; + if (msgr.SendMessage(&getNameOfActivePrinter, &reply) == B_OK && + reply.FindString("result", &activePrinterName) == B_OK) { + // Compare name of active printer with name of 'this' printer item + rc = (fName == activePrinterName); + } + } + + return rc; +} + diff --git a/src/prefs/print/PrinterListView.h b/src/prefs/print/PrinterListView.h new file mode 100644 index 0000000000..fe4dee96fb --- /dev/null +++ b/src/prefs/print/PrinterListView.h @@ -0,0 +1,63 @@ +/* + * Printers Preference Application. + * Copyright (C) 2001 OpenBeOS. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PRINTERSLISTVIEW_H +#define PRINTERSLISTVIEW_H + +class PrinterListView; + +#include +#include +#include + +class PrinterListView : public BListView +{ + typedef BListView Inherited; +public: + PrinterListView(BRect frame); + void AttachedToWindow(); +}; + +class BBitmap; +class PrinterItem : public BListItem +{ +public: + PrinterItem(const BMessenger& thePrinter); + + void DrawItem(BView *owner, BRect bounds, bool complete); + void Update(BView *owner, const BFont *font); + + void Remove(BListView* view); + bool IsActivePrinter(); + + const char* Name() const + { return fName.String(); } +private: + void GetStringProperty(const char* propName, BString& outString); + + BMessenger fMessenger; + BString fComments; + BString fTransport; + BString fDriverName; + BString fName; + static BBitmap* sIcon; + static BBitmap* sSelectedIcon; +}; + +#endif diff --git a/src/prefs/print/Printers.FileTypes.rsrc b/src/prefs/print/Printers.FileTypes.rsrc new file mode 100644 index 0000000000..c36a0c8c6d Binary files /dev/null and b/src/prefs/print/Printers.FileTypes.rsrc differ diff --git a/src/prefs/print/Printers.cpp b/src/prefs/print/Printers.cpp new file mode 100644 index 0000000000..b54f2100d4 --- /dev/null +++ b/src/prefs/print/Printers.cpp @@ -0,0 +1,44 @@ +/* + * Printers Preference Application. + * Copyright (C) 2001 OpenBeOS. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Printers.h" + +#ifndef PRINTERSWINDOW_H + #include "PrintersWindow.h" +#endif + +int main() +{ + new PrintersApp; + be_app->Run(); + delete be_app; + + return 0; +} + +PrintersApp::PrintersApp() + : Inherited(PRINTERS_SIGNATURE) +{ +} + +void PrintersApp::ReadyToRun() +{ + PrintersWindow* win = new PrintersWindow(BRect(78.0, 71.0, 561.0, 409.0)); + win->Show(); +} diff --git a/src/prefs/print/Printers.h b/src/prefs/print/Printers.h new file mode 100644 index 0000000000..52efab781a --- /dev/null +++ b/src/prefs/print/Printers.h @@ -0,0 +1,37 @@ +/* + * Printers Preference Application. + * Copyright (C) 2001 OpenBeOS. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PRINTERS_H +#define PRINTERS_H + +class PrintersApp; + +#include + +#define PRINTERS_SIGNATURE "application/x-vnd.Be-PRNT2" + +class PrintersApp : public BApplication +{ + typedef BApplication Inherited; +public: + PrintersApp(); + void ReadyToRun(); +}; + +#endif diff --git a/src/prefs/print/PrintersWindow.cpp b/src/prefs/print/PrintersWindow.cpp new file mode 100644 index 0000000000..82b4d76d5d --- /dev/null +++ b/src/prefs/print/PrintersWindow.cpp @@ -0,0 +1,260 @@ +/* + * Printers Preference Application. + * Copyright (C) 2001 OpenBeOS. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "PrintersWindow.h" + +#include "AddPrinterDialog.h" +#include "PrinterListView.h" +#include "pr_server.h" +#include "Globals.h" +#include "Messages.h" + +// BeOS API +#include +#include +#include +#include +#include + +PrintersWindow::PrintersWindow(BRect frame) + : Inherited(BRect(78.0, 71.0, 561.0, 409.0), "Printers", B_TITLED_WINDOW, B_NOT_H_RESIZABLE) +{ + BuildGUI(); +} + +bool PrintersWindow::QuitRequested() +{ + bool result = Inherited::QuitRequested(); + if (result) { + be_app->PostMessage(B_QUIT_REQUESTED); + } + + return result; +} + +void PrintersWindow::MessageReceived(BMessage* msg) +{ + switch(msg->what) + { + case MSG_PRINTER_SELECTED: + { + int32 prIndex = fPrinterListView->CurrentSelection(); + if (prIndex >= 0) + { + BMessenger msgr; + if (::GetPrinterServerMessenger(msgr) == B_OK) + { + BMessage script(B_GET_PROPERTY); + BMessage reply; + BString name; + + script.AddSpecifier("Name"); + script.AddSpecifier("Printer", fPrinterListView->CurrentSelection()); + msgr.SendMessage(&script,&reply); + if (reply.FindString("result", &name) == B_OK) + { + fJobsBox->SetLabel((BString("Print Jobs for ") << name).String()); + fMakeDefault->SetEnabled(true); + fRemove->SetEnabled(true); + } + } + } + else + { + fJobsBox->SetLabel("Print Jobs: No printer selected"); + fMakeDefault->SetEnabled(false); + fRemove->SetEnabled(false); + } + } + break; + + case MSG_ADD_PRINTER: + //if (AddPrinterDialog::Start() == B_OK) + break; + + case MSG_REMOVE_PRINTER: + { + // Get selection + int32 idx = fPrinterListView->CurrentSelection(); + + // If a printer is selected + if (idx >= 0) + { + PrinterItem* item = (PrinterItem*)fPrinterListView->ItemAt(idx); + if (item != NULL) + item->Remove(fPrinterListView); + } + } + break; + + case MSG_MKDEF_PRINTER: + { + int32 prIndex = fPrinterListView->CurrentSelection(); + if (prIndex >= 0) + { + PrinterItem* printer = dynamic_cast(fPrinterListView->ItemAt(prIndex)); + BMessenger msgr; + if (printer != NULL && ::GetPrinterServerMessenger(msgr) == B_OK) + { + BMessage setActivePrinter(B_SET_PROPERTY); + setActivePrinter.AddSpecifier("ActivePrinter"); + setActivePrinter.AddString("data", printer->Name()); + msgr.SendMessage(&setActivePrinter); + + fPrinterListView->Invalidate(); + } + } + } + break; + + + case MSG_CANCEL_JOB: + break; + + case MSG_RESTART_JOB: + break; + + + default: + Inherited::MessageReceived(msg); + } +} + +void PrintersWindow::BuildGUI() +{ + const float boxInset = 10.0; + BRect r(Bounds()); + +// ------------------------ First of all, create a nice grey backdrop + BBox * backdrop = new BBox(Bounds(), "backdrop", B_FOLLOW_ALL_SIDES, + B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP, + B_PLAIN_BORDER); + AddChild(backdrop); + +// ------------------------ Next, build the printers overview box + BBox* printersBox = new BBox(BRect(boxInset, boxInset, r.Width()-boxInset, (r.Height()/2) - (boxInset/2)), + "printersBox", B_FOLLOW_ALL); + printersBox->SetFont(be_bold_font); + printersBox->SetLabel("Printers:"); + backdrop->AddChild(printersBox); + + // Width of largest button + float maxWidth = 0; + + // Add Button + BButton* addButton = new BButton(BRect(5,5,5,5), "add", "Add...", new BMessage(MSG_ADD_PRINTER), B_FOLLOW_RIGHT); + printersBox->AddChild(addButton); + addButton->ResizeToPreferred(); + + maxWidth = addButton->Bounds().Width(); + + // Remove button + fRemove = new BButton(BRect(5,30,5,30), "remove", "Remove", new BMessage(MSG_REMOVE_PRINTER), B_FOLLOW_RIGHT); + printersBox->AddChild(fRemove); + fRemove->ResizeToPreferred(); + + if (fRemove->Bounds().Width() > maxWidth) + maxWidth = fRemove->Bounds().Width(); + + // Make Default button + fMakeDefault = new BButton(BRect(5,60,5,60), "default", "Make Default", new BMessage(MSG_MKDEF_PRINTER), B_FOLLOW_RIGHT); + printersBox->AddChild(fMakeDefault); + fMakeDefault->ResizeToPreferred(); + + if (fMakeDefault->Bounds().Width() > maxWidth) + maxWidth = fMakeDefault->Bounds().Width(); + + // Resize all buttons to maximum width and align them to the right + float xPos = printersBox->Bounds().Width()-boxInset-maxWidth; + addButton->MoveTo(xPos, boxInset +5); + addButton->ResizeTo(maxWidth, addButton->Bounds().Height()); + + fRemove->MoveTo(xPos, boxInset + addButton->Bounds().Height() + boxInset +5); + fRemove->ResizeTo(maxWidth, fRemove->Bounds().Height()); + + fMakeDefault->MoveTo(xPos, boxInset + addButton->Bounds().Height() + + boxInset + fRemove->Bounds().Height() + + boxInset +5); + fMakeDefault->ResizeTo(maxWidth, fMakeDefault->Bounds().Height()); + + // Disable all selection-based buttons + fRemove->SetEnabled(false); + fMakeDefault->SetEnabled(false); + + // Create listview with scroller + BRect listBounds(boxInset, boxInset+5, fMakeDefault->Frame().left - boxInset - B_V_SCROLL_BAR_WIDTH, + printersBox->Bounds().Height()-boxInset); + fPrinterListView = new PrinterListView(listBounds); + BScrollView* pscroller = new BScrollView("printer_scroller", fPrinterListView, + B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS, false, true, B_FANCY_BORDER); + printersBox->AddChild(pscroller); + +// ------------------------ Lastly, build the jobs overview box + fJobsBox = new BBox(BRect(boxInset, (r.Height()/2)+(boxInset/2), Bounds().Width()-10, Bounds().Height() - boxInset), + "jobsBox", B_FOLLOW_LEFT_RIGHT+B_FOLLOW_BOTTOM); + fJobsBox->SetFont(be_bold_font); + fJobsBox->SetLabel("Print Jobs: No printer selected"); + backdrop->AddChild(fJobsBox); + + // Cancel Job Button + BButton* cancelButton = new BButton(BRect(5,5,5,5), "cancel", "Cancel Job", new BMessage(MSG_CANCEL_JOB), B_FOLLOW_RIGHT+B_FOLLOW_TOP); + fJobsBox->AddChild(cancelButton); + cancelButton->ResizeToPreferred(); + + maxWidth = cancelButton->Bounds().Width(); + + // Restart Job button + BButton* restartButton = new BButton(BRect(5,30,5,30), "restart", "Restart Job", new BMessage(MSG_RESTART_JOB), B_FOLLOW_RIGHT+B_FOLLOW_TOP); + fJobsBox->AddChild(restartButton); + restartButton->ResizeToPreferred(); + + if (restartButton->Bounds().Width() > maxWidth) + maxWidth = restartButton->Bounds().Width(); + + // Resize all buttons to maximum width and align them to the right + xPos = fJobsBox->Bounds().Width()-boxInset-maxWidth; + cancelButton->MoveTo(xPos, boxInset +5); + cancelButton->ResizeTo(maxWidth, cancelButton->Bounds().Height()); + + restartButton->MoveTo(xPos, boxInset + cancelButton->Bounds().Height() + boxInset +5); + restartButton->ResizeTo(maxWidth, restartButton->Bounds().Height()); + + // Disable all selection-based buttons + cancelButton->SetEnabled(false); + restartButton->SetEnabled(false); + + // Create listview with scroller + listBounds = BRect(boxInset, boxInset+5, cancelButton->Frame().left - boxInset - B_V_SCROLL_BAR_WIDTH, + fJobsBox->Bounds().Height()-boxInset); + fJobListView = new BListView(listBounds, "jobs_list", B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL); + BScrollView* jscroller = new BScrollView("jobs_scroller", fJobListView, + B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS, false, true, B_FANCY_BORDER); + fJobsBox->AddChild(jscroller); + + // Determine min width + float width; + width = (jscroller->Bounds().Width() < pscroller->Bounds().Width()) ? + jscroller->Bounds().Width() : pscroller->Bounds().Width(); + + // Resize boxes to the same size + jscroller->ResizeTo(width, jscroller->Bounds().Height()); + pscroller->ResizeTo(width, pscroller->Bounds().Height()); + + SetSizeLimits(Bounds().Width(), Bounds().Width(), Bounds().Height(), 20000); +} diff --git a/src/prefs/print/PrintersWindow.h b/src/prefs/print/PrintersWindow.h new file mode 100644 index 0000000000..001ad300de --- /dev/null +++ b/src/prefs/print/PrintersWindow.h @@ -0,0 +1,46 @@ +/* + * Printers Preference Application. + * Copyright (C) 2001 OpenBeOS. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PRINTERSWINDOW_H +#define PRINTERSWINDOW_H + +class PrintersWindow; + +#include + +class PrintersWindow : public BWindow +{ + typedef BWindow Inherited; +public: + PrintersWindow(BRect frame); + + void MessageReceived(BMessage* msg); + bool QuitRequested(); +private: + void BuildGUI(); + + BListView* fPrinterListView; + BButton* fMakeDefault; + BButton* fRemove; + + BListView* fJobListView; + BBox* fJobsBox; +}; + +#endif diff --git a/src/prefs/screen/AlertView.cpp b/src/prefs/screen/AlertView.cpp new file mode 100644 index 0000000000..20024fa1ff --- /dev/null +++ b/src/prefs/screen/AlertView.cpp @@ -0,0 +1,53 @@ +#include +#include +#include + +#include "AlertView.h" +#include "Bitmaps.h" + +AlertView::AlertView(BRect frame, char *name) + : BView(frame, name, B_FOLLOW_ALL, B_WILL_DRAW) +{ + Count = 10; + + fBitmap = new BBitmap(BRect(0, 0, 31, 31), B_COLOR_8_BIT); + fBitmap->SetBits(BitmapBits, 32 * 32, 0, B_COLOR_8_BIT); +} + +void AlertView::AttachedToWindow() +{ + rgb_color greyColor = {216, 216, 216, 255}; + SetViewColor(greyColor); +} + +void AlertView::Draw(BRect updateRect) +{ + rgb_color darkColor = {184, 184, 184, 255}; + rgb_color blackColor = {0, 0, 0, 255}; + + SetHighColor(darkColor); + + FillRect(BRect(0.0, 0.0, 30.0, 100.0)); + + SetDrawingMode(B_OP_ALPHA); + + DrawBitmap(fBitmap, BPoint(18.0, 6.0)); + + SetDrawingMode(B_OP_OVER); + + SetHighColor(blackColor); + + SetFont(be_bold_font); + + MovePenTo(60.0, 20.0); + + DrawString("Do you wish to keep these settings?"); + + MovePenTo(60.0, 37.0); + + fString.Truncate(0); + + fString << "Settings will revert in " << Count << " seconds."; + + DrawString(fString.String()); +} diff --git a/src/prefs/screen/AlertView.h b/src/prefs/screen/AlertView.h new file mode 100644 index 0000000000..46cf67b4c4 --- /dev/null +++ b/src/prefs/screen/AlertView.h @@ -0,0 +1,21 @@ +#ifndef ALERTVIEW_H +#define ALERTVIEW_H + +#include +#include + +class AlertView : public BView +{ + +public: + AlertView(BRect frame, char *name); + virtual void AttachedToWindow(); + virtual void Draw(BRect updateRect); + int32 Count; + +private: + BBitmap *fBitmap; + BString fString; +}; + +#endif \ No newline at end of file diff --git a/src/prefs/screen/AlertWindow.cpp b/src/prefs/screen/AlertWindow.cpp new file mode 100644 index 0000000000..67c868b12a --- /dev/null +++ b/src/prefs/screen/AlertWindow.cpp @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include "AlertWindow.h" +#include "AlertView.h" +#include "Constants.h" + +AlertWindow::AlertWindow(BRect frame) + : BWindow(frame, "Revert", B_MODAL_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL, B_NOT_RESIZABLE | B_NOT_ZOOMABLE, B_ALL_WORKSPACES) +{ + frame = Bounds(); + + fAlertView = new AlertView(frame, "ScreenView"); + + AddChild(fAlertView); + + BRect ButtonRect; + + ButtonRect.Set(215.0, 59.0, 400.0, 190.0); + + fKeepButton = new BButton(ButtonRect, "KeepButton", "Keep", + new BMessage(BUTTON_KEEP_MSG)); + + fKeepButton->AttachedToWindow(); + fKeepButton->ResizeToPreferred(); + + fAlertView->AddChild(fKeepButton); + + ButtonRect.Set(130.0, 59.0, 400.0, 190.0); + + fRevertButton = new BButton(ButtonRect, "RevertButton", "Revert", + new BMessage(BUTTON_REVERT_MSG)); + + fRevertButton->AttachedToWindow(); + fRevertButton->ResizeToPreferred(); + + fAlertView->AddChild(fRevertButton); + + BMessenger Messenger(this); + + fRunner = new BMessageRunner(Messenger, new BMessage(DIM_COUNT_MSG), 1000000, 10); + + Show(); +} + +bool AlertWindow::QuitRequested() +{ + delete fRunner; + + Quit(); + + return(true); +} + +void AlertWindow::MessageReceived(BMessage *message) +{ + switch (message->what) + { + case BUTTON_KEEP_MSG: + { + be_app->PostMessage(MAKE_INITIAL_MSG); + + PostMessage(B_QUIT_REQUESTED); + + break; + } + + case BUTTON_REVERT_MSG: + { + be_app->PostMessage(SET_INITIAL_MODE_MSG); + + PostMessage(B_QUIT_REQUESTED); + + break; + } + + case DIM_COUNT_MSG: + { + fAlertView->Count = fAlertView->Count - 1; + + fAlertView->Invalidate(BRect(180.0, 20.0, 260.0, 50.0)); + + if (fAlertView->Count == 0) + PostMessage(BUTTON_REVERT_MSG); + + break; + } + + default: + BWindow::MessageReceived(message); + + break; + } +} diff --git a/src/prefs/screen/AlertWindow.h b/src/prefs/screen/AlertWindow.h new file mode 100644 index 0000000000..572748a4a6 --- /dev/null +++ b/src/prefs/screen/AlertWindow.h @@ -0,0 +1,21 @@ +#ifndef ALERTWINDOW_H +#define ALERTWINDOW_H + +#include "AlertView.h" + +class AlertWindow : public BWindow +{ + +public: + AlertWindow(BRect frame); + virtual bool QuitRequested(); + virtual void MessageReceived(BMessage *message); + +private: + AlertView *fAlertView; + BMessageRunner *fRunner; + BButton *fRevertButton; + BButton *fKeepButton; +}; + +#endif \ No newline at end of file diff --git a/src/prefs/screen/Bitmaps.h b/src/prefs/screen/Bitmaps.h new file mode 100644 index 0000000000..70667cc7fb --- /dev/null +++ b/src/prefs/screen/Bitmaps.h @@ -0,0 +1,75 @@ +#ifndef BITMAPS_H +#define BITMAPS_H + +#include + +class Bitmap; + +const unsigned char BitmapBits [] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xfa,0xfa,0xfa,0x00,0x00,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0x00, + 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, + 0xfa,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, + 0xfa,0xfa,0xfa,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x3f,0x3f,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, + 0xfa,0xfa,0x3f,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf9,0xf9,0x3f,0x3f,0xfa,0xfa,0xfa,0xfa,0xfa, + 0xfa,0x3f,0x5d,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf9,0xf9,0xf9,0xf9,0x3f,0x3f,0xfa,0xfa,0xfa, + 0x3f,0x5d,0x5d,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0x3f,0x3f,0x3f, + 0x5d,0x5d,0x5d,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0x5d, + 0x5d,0x5d,0x5d,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0x5d, + 0x5d,0x5d,0x5d,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0x5d, + 0x5d,0x5d,0x5d,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0x5d, + 0x5d,0x5d,0x5d,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0x5d, + 0x5d,0x5d,0x5d,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0x5d, + 0x5d,0x5d,0x5d,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0x5d, + 0x5d,0x5d,0x5d,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0x5d, + 0x5d,0x5d,0x5d,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0x5d, + 0x5d,0x5d,0x5d,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0x5d, + 0x5d,0x5d,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xa5,0x00,0x00,0xf9,0xf9,0xf9,0xf9,0x5d, + 0x5d,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xa5,0xa5,0xa5,0xa5,0x00,0x00,0xf9,0xf9,0x5d, + 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xa5,0xa5,0xa5,0xa5,0x00,0x00,0x00, + 0xa5,0xa5,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf9,0xf9,0x00,0x00,0xa5,0xa5,0xa5,0xa5,0xa5, + 0xa5,0x00,0x5d,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf9,0xf9,0xf9,0xf9,0x00,0x00,0xa5,0xa5,0xa5, + 0x00,0x5d,0x5d,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0x00,0x00,0x00, + 0x5d,0x5d,0x5d,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0x5d, + 0x5d,0x5d,0x5d,0x00,0x0e,0x0e,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0x5d, + 0x5d,0x5d,0x5d,0x00,0x0e,0x0e,0x0e,0x0e,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0x5d, + 0x5d,0x5d,0x5d,0x00,0x0e,0x0e,0x0e,0x0e,0x0e,0x0e,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0x5d, + 0x5d,0x5d,0x00,0x0e,0x0e,0x0e,0x0e,0x0e,0x0e,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0xf9,0xf9,0xf9,0xf9,0x5d, + 0x5d,0x00,0x0e,0x0e,0x0e,0x0e,0x0e,0x0e,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0xf9,0xf9,0x5d, + 0x00,0x0e,0x0e,0x0e,0x0e,0x0e,0x0e,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00, + 0x0e,0x0e,0x0e,0x0e,0x0e,0x0e,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff +}; + +#endif \ No newline at end of file diff --git a/src/prefs/screen/Constants.h b/src/prefs/screen/Constants.h new file mode 100644 index 0000000000..bdb0bf5c4f --- /dev/null +++ b/src/prefs/screen/Constants.h @@ -0,0 +1,25 @@ +#ifndef CONSTANTS_H +#define CONSTANTS_H + +#define WORKSPACE_CHECK_MSG 'wchk' +#define BUTTON_DEFAULTS_MSG 'bdef' +#define BUTTON_REVERT_MSG 'brev' +#define BUTTON_APPLY_MSG 'bapl' +#define BUTTON_DONE_MSG 'bdon' +#define BUTTON_CANCEL_MSG 'bcnc' +#define BUTTON_KEEP_MSG 'bkep' +#define POP_WORKSPACE_CHANGED_MSG 'pwsc' +#define POP_RESOLUTION_MSG 'pres' +#define POP_COLORS_MSG 'pclr' +#define POP_REFRESH_MSG 'prfr' +#define POP_OTHER_REFRESH_MSG 'porf' +#define UPDATE_DESKTOP_COLOR_MSG 'udsc' +#define UPDATE_DESKTOP_MSG 'udsk' +#define SLIDER_MODIFICATION_MSG 'sldm' +#define SLIDER_INVOKE_MSG 'sldi' +#define SET_INITIAL_MODE_MSG 'sinm' +#define SET_CUSTOM_REFRESH_MSG 'scrf' +#define DIM_COUNT_MSG 'scrf' +#define MAKE_INITIAL_MSG 'mkin' + +#endif \ No newline at end of file diff --git a/src/prefs/screen/Jamfile b/src/prefs/screen/Jamfile new file mode 100644 index 0000000000..8e46788238 --- /dev/null +++ b/src/prefs/screen/Jamfile @@ -0,0 +1,7 @@ +SubDir OBOS_TOP sources os kits interface prefs screen ; + +Preference Screen : AlertView.cpp AlertWindow.cpp RefreshSlider.cpp RefreshView.cpp RefreshWindow.cpp Screen.cpp ScreenDrawView.cpp ScreenSettings.cpp ScreenView.cpp ScreenWindow.cpp ; + +LinkSharedOSLibs Screen : be root ; + +AddResources Screen : Screen.rsrc ; diff --git a/src/prefs/screen/RefreshSlider.cpp b/src/prefs/screen/RefreshSlider.cpp new file mode 100644 index 0000000000..23c014daca --- /dev/null +++ b/src/prefs/screen/RefreshSlider.cpp @@ -0,0 +1,105 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include "RefreshSlider.h" +#include "Constants.h" + +RefreshSlider::RefreshSlider(BRect frame) + : BSlider(frame, "Screen", "Refresh Rate:", new BMessage(SLIDER_INVOKE_MSG), 450, 845) +{ + fStatus = (char*)malloc(64); +} + +RefreshSlider::~RefreshSlider() +{ + if (fStatus) + free(fStatus); +} + +void RefreshSlider::DrawFocusMark() +{ + if (IsFocus()) + { + rgb_color blueColor = {0, 0, 229, 255}; + + BRect Rect; + + BView *View; + + Rect = ThumbFrame(); + + View = OffscreenView(); + + Rect.InsetBy(2.0, 2.0); + Rect.right = Rect.right - 1; + Rect.bottom = Rect.bottom - 1; + + View->SetHighColor(blueColor); + View->StrokeRect(Rect); + } +} + +void RefreshSlider::KeyDown(const char *bytes, int32 numBytes) +{ + switch ( *bytes ) + { + case B_LEFT_ARROW: + { + SetValue(Value() - 1); + + Invoke(); + + break; + } + + case B_RIGHT_ARROW: + { + SetValue(Value() + 1); + + Invoke(); + + break; + } + + default: + break; + } +} + +char* RefreshSlider::UpdateText() const +{ + if (fStatus && Window()->Lock()) + { + BString String; + + String << Value(); + + int32 Len = String.Length()+1; + strcpy(fStatus, String.LockBuffer(Len)); + + char Last = fStatus[2]; + + String.UnlockBuffer(Len); + + String.Truncate(2); + + String << "." << Last << " Hz"; + + strcpy(fStatus, String.LockBuffer(Len)); + + String.UnlockBuffer(Len); + + return(fStatus); + } + else + { + return NULL; + } +} + diff --git a/src/prefs/screen/RefreshSlider.h b/src/prefs/screen/RefreshSlider.h new file mode 100644 index 0000000000..209019a068 --- /dev/null +++ b/src/prefs/screen/RefreshSlider.h @@ -0,0 +1,20 @@ +#ifndef REFRESHSLIDER_H +#define REFRESHSLIDER_H + +#include + +class RefreshSlider : public BSlider +{ + +public: + RefreshSlider(BRect frame); + ~RefreshSlider(); + virtual void DrawFocusMark(); + virtual char* UpdateText() const; + virtual void KeyDown(const char *bytes, int32 numBytes); + +private: + char* fStatus; +}; + +#endif \ No newline at end of file diff --git a/src/prefs/screen/RefreshView.cpp b/src/prefs/screen/RefreshView.cpp new file mode 100644 index 0000000000..24647d0018 --- /dev/null +++ b/src/prefs/screen/RefreshView.cpp @@ -0,0 +1,36 @@ +#include + +#include "RefreshView.h" + +RefreshView::RefreshView(BRect rect, char *name) + : BView(rect, name, B_FOLLOW_ALL, B_WILL_DRAW) +{ + +} + +void RefreshView::AttachedToWindow() +{ + rgb_color greyColor = {216, 216, 216, 255}; + SetViewColor(greyColor); +} + +void RefreshView::Draw(BRect updateRect) +{ + rgb_color whiteColor = {255, 255, 255, 255}; + rgb_color darkColor = {128, 128, 128, 255}; + rgb_color blackColor = {0, 0, 0, 255}; + + SetHighColor(whiteColor); + + StrokeLine(BPoint(Bounds().left, Bounds().top), BPoint(Bounds().right, Bounds().top)); + StrokeLine(BPoint(Bounds().left, Bounds().top), BPoint(Bounds().left, Bounds().bottom)); + + SetHighColor(darkColor); + + StrokeLine(BPoint(Bounds().left, Bounds().bottom), BPoint(Bounds().right, Bounds().bottom)); + StrokeLine(BPoint(Bounds().right, Bounds().bottom), BPoint(Bounds().right, Bounds().top)); + + SetHighColor(blackColor); + + DrawString("Type or use the left and right arrow keys.", BPoint(10.0, 23.0)); +} diff --git a/src/prefs/screen/RefreshView.h b/src/prefs/screen/RefreshView.h new file mode 100644 index 0000000000..b0c6da939e --- /dev/null +++ b/src/prefs/screen/RefreshView.h @@ -0,0 +1,15 @@ +#ifndef REFRESHVIEW_H +#define REFRESHVIEW_H + +#include + +class RefreshView : public BView +{ + +public: + RefreshView(BRect frame, char *name); + virtual void AttachedToWindow(); + virtual void Draw(BRect updateRect); +}; + +#endif \ No newline at end of file diff --git a/src/prefs/screen/RefreshWindow.cpp b/src/prefs/screen/RefreshWindow.cpp new file mode 100644 index 0000000000..77ca1284a3 --- /dev/null +++ b/src/prefs/screen/RefreshWindow.cpp @@ -0,0 +1,121 @@ +#include +#include +#include +#include + +#include + +#include "RefreshWindow.h" +#include "RefreshView.h" +#include "RefreshSlider.h" +#include "Constants.h" + +RefreshWindow::RefreshWindow(BRect frame, int32 value) + : BWindow(frame, "Refresh Rate", B_MODAL_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE, B_ALL_WORKSPACES) +{ + int32 Value = value * 10; + + frame = Bounds(); + + fRefreshView = new RefreshView(frame, "RefreshView"); + + AddChild(fRefreshView); + + BRect SliderRect; + + SliderRect.Set(10.0, 35.0, 299.0, 60.0); + + fRefreshSlider = new RefreshSlider(SliderRect); + + fRefreshSlider->SetHashMarks(B_HASH_MARKS_BOTTOM); + fRefreshSlider->SetHashMarkCount(10); + fRefreshSlider->SetLimitLabels("45.0", "84.5"); + fRefreshSlider->SetKeyIncrementValue(1); + fRefreshSlider->SetValue(Value); + fRefreshSlider->SetSnoozeAmount(1); + fRefreshSlider->SetModificationMessage(new BMessage(SLIDER_MODIFICATION_MSG)); + + fRefreshView->AddChild(fRefreshSlider); + + BRect ButtonRect; + + ButtonRect.Set(219.0, 97.0, 230.0, 120.0); + + fDoneButton = new BButton(ButtonRect, "DoneButton", "Done", + new BMessage(BUTTON_DONE_MSG)); + + fDoneButton->ResizeToPreferred(); + fDoneButton->MakeDefault(true); + + fRefreshView->AddChild(fDoneButton); + + ButtonRect.Set(130.0, 97.0, 200.0, 120.0); + + fCancelButton = new BButton(ButtonRect, "CancelButton", "Cancel", + new BMessage(BUTTON_CANCEL_MSG)); + + fCancelButton->ResizeToPreferred(); + + fRefreshView->AddChild(fCancelButton); + + Show(); + + PostMessage(SLIDER_INVOKE_MSG); +} + +bool RefreshWindow::QuitRequested() +{ + return(true); +} + +void RefreshWindow::WindowActivated(bool active) +{ + if (active == true) + fRefreshSlider->MakeFocus(true); + else + fRefreshSlider->MakeFocus(false); +} + +void RefreshWindow::MessageReceived(BMessage* message) +{ + switch(message->what) + { + case BUTTON_DONE_MSG: + { + BMessenger Messenger("application/x-vnd.RR-SCRN"); + + BMessage Message(SET_CUSTOM_REFRESH_MSG); + + float Value; + + Value = (float)fRefreshSlider->Value() / 10; + + Message.AddFloat("refresh", Value); + + Messenger.SendMessage(&Message); + + PostMessage(B_QUIT_REQUESTED); + + break; + } + + case BUTTON_CANCEL_MSG: + { + PostMessage(B_QUIT_REQUESTED); + + break; + } + + case SLIDER_INVOKE_MSG: + { + fRefreshSlider->MakeFocus(true); + + break; + } + + default: + BWindow::MessageReceived(message); + + break; + } +} \ No newline at end of file diff --git a/src/prefs/screen/RefreshWindow.h b/src/prefs/screen/RefreshWindow.h new file mode 100644 index 0000000000..77fda39bf5 --- /dev/null +++ b/src/prefs/screen/RefreshWindow.h @@ -0,0 +1,25 @@ +#ifndef REFRESHWINDOW_H +#define REFRESHWINDOW_H + +#include + +#include "RefreshView.h" +#include "RefreshSlider.h" + +class RefreshWindow : public BWindow +{ + +public: + RefreshWindow(BRect frame, int32 value); + virtual bool QuitRequested(); + virtual void MessageReceived(BMessage *message); + virtual void WindowActivated(bool active); + +private: + RefreshView *fRefreshView; + RefreshSlider *fRefreshSlider; + BButton *fDoneButton; + BButton *fCancelButton; +}; + +#endif \ No newline at end of file diff --git a/src/prefs/screen/Screen.cpp b/src/prefs/screen/Screen.cpp new file mode 100644 index 0000000000..abe53bb8bf --- /dev/null +++ b/src/prefs/screen/Screen.cpp @@ -0,0 +1,80 @@ +// Screen V0.9 build 1 by Rafael Romo for the OpenBeOS Preferences team. +// web.tiscalinet.it/rockman +// rockman@tiscalinet.it + +#include +#include + +#include +#include + +#include "ScreenApplication.h" +#include "ScreenWindow.h" +#include "ScreenSettings.h" +#include "Constants.h" + +ScreenApplication::ScreenApplication() + : BApplication("application/x-vnd.RR-SCRN") +{ + fScreenWindow = new ScreenWindow(new ScreenSettings()); +} + +void ScreenApplication::AboutRequested() +{ + BAlert *AboutAlert = new BAlert("About", "Screen by Rafael Romo\nThe OBOS place to configure your monitor", + "Ok", NULL, NULL, + B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_INFO_ALERT); + AboutAlert->SetShortcut(0, B_OK); + AboutAlert->Go(); +} + +void ScreenApplication::MessageReceived(BMessage* message) +{ + switch(message->what) + { + case SET_INITIAL_MODE_MSG: + { + fScreenWindow->PostMessage(new BMessage(SET_INITIAL_MODE_MSG)); + + break; + } + + case SET_CUSTOM_REFRESH_MSG: + { + BMessage *Message; + + Message = new BMessage(SET_CUSTOM_REFRESH_MSG); + + float Value; + + message->FindFloat("refresh", &Value); + + Message->AddFloat("refresh", Value); + + fScreenWindow->PostMessage(Message); + + break; + } + + case MAKE_INITIAL_MSG: + { + fScreenWindow->PostMessage(new BMessage(MAKE_INITIAL_MSG)); + + break; + } + + default: + BApplication::MessageReceived(message); + + break; + } +} + +int main() +{ + ScreenApplication MyApplication; + + MyApplication.Run(); + + return(0); +} \ No newline at end of file diff --git a/src/prefs/screen/Screen.rsrc b/src/prefs/screen/Screen.rsrc new file mode 100644 index 0000000000..b9aabe9eab Binary files /dev/null and b/src/prefs/screen/Screen.rsrc differ diff --git a/src/prefs/screen/ScreenApplication.h b/src/prefs/screen/ScreenApplication.h new file mode 100644 index 0000000000..c057b1ef77 --- /dev/null +++ b/src/prefs/screen/ScreenApplication.h @@ -0,0 +1,19 @@ +#ifndef SCREENAPPLICATION_H +#define SCREENAPPLICATION_H + +#include "ScreenWindow.h" + +class ScreenApplication : public BApplication +{ + +public: + ScreenApplication(); + virtual void MessageReceived(BMessage *message); + virtual void AboutRequested(); + +private: + ScreenWindow *fScreenWindow; + bool NeedWindow; +}; + +#endif \ No newline at end of file diff --git a/src/prefs/screen/ScreenDrawView.cpp b/src/prefs/screen/ScreenDrawView.cpp new file mode 100644 index 0000000000..babc3a0df6 --- /dev/null +++ b/src/prefs/screen/ScreenDrawView.cpp @@ -0,0 +1,243 @@ +#include +#include +#include +#include +#include + +#include + +#include "ScreenDrawView.h" +#include "Constants.h" + +ScreenDrawView::ScreenDrawView(BRect rect, char *name) + : BView(rect, name, B_FOLLOW_ALL, B_WILL_DRAW) +{ + fScreen = new BScreen(B_MAIN_SCREEN_ID); + + desktopColor = fScreen->DesktopColor(current_workspace()); + + display_mode Mode; + + fScreen->GetMode(&Mode); + + fResolution = Mode.virtual_width; +} + +void ScreenDrawView::AttachedToWindow() +{ + rgb_color greyColor = {216, 216, 216, 255}; + SetViewColor(greyColor); +} + +void ScreenDrawView::MouseDown(BPoint point) +{ + be_roster->Launch("application/x-vnd.Be-BACK"); +} + +void ScreenDrawView::Draw(BRect updateRect) +{ + if (fResolution == 1600) + { + rgb_color darkColor = {160, 160, 160, 255}; + rgb_color blackColor = {0, 0, 0, 255}; + rgb_color redColor = {228, 0, 0, 255}; + + SetHighColor(darkColor); + + FillRoundRect(Bounds(), 3.0, 3.0); + + SetHighColor(blackColor); + + StrokeRoundRect(Bounds(), 3.0, 3.0); + + SetHighColor(desktopColor); + + FillRoundRect(BRect(4.0, 4.0, 98.0, 73.0), 2.0, 2.0); + + SetHighColor(blackColor); + + StrokeRoundRect(BRect(4.0, 4.0, 98.0, 73.0), 2.0, 2.0); + + SetHighColor(redColor); + + StrokeLine(BPoint(4.0, 75.0), BPoint(5.0, 75.0)); + } + else if(fResolution == 1280) + { + rgb_color darkColor = {160, 160, 160, 255}; + rgb_color blackColor = {0, 0, 0, 255}; + rgb_color redColor = {228, 0, 0, 255}; + + SetHighColor(darkColor); + + FillRoundRect(BRect(10.0, 6.0, 92.0, 72.0), 3.0, 3.0); + + SetHighColor(blackColor); + + StrokeRoundRect(BRect(10.0, 6.0, 92.0, 72.0), 3.0, 3.0); + + SetHighColor(desktopColor); + + FillRoundRect(BRect(14.0, 10.0, 88.0, 68.0), 2.0, 2.0); + + SetHighColor(blackColor); + + StrokeRoundRect(BRect(14.0, 10.0, 88.0, 68.0), 2.0, 2.0); + + SetHighColor(redColor); + + StrokeLine(BPoint(15.0, 70.0), BPoint(16.0, 70.0)); + } + else if(fResolution == 1152) + { + rgb_color darkColor = {160, 160, 160, 255}; + rgb_color blackColor = {0, 0, 0, 255}; + rgb_color redColor = {228, 0, 0, 255}; + + SetHighColor(darkColor); + + FillRoundRect(BRect(15.0, 9.0, 89.0, 68.0), 3.0, 3.0); + + SetHighColor(blackColor); + + StrokeRoundRect(BRect(15.0, 9.0, 89.0, 68.0), 3.0, 3.0); + + SetHighColor(desktopColor); + + FillRoundRect(BRect(19.0, 13.0, 85.0, 64.0), 2.0, 2.0); + + SetHighColor(blackColor); + + StrokeRoundRect(BRect(19.0, 13.0, 85.0, 64.0), 2.0, 2.0); + + SetHighColor(redColor); + + StrokeLine(BPoint(19.0, 66.0), BPoint(20.0, 66.0)); + } + else if(fResolution == 1024) + { + rgb_color darkColor = {160, 160, 160, 255}; + rgb_color blackColor = {0, 0, 0, 255}; + rgb_color redColor = {228, 0, 0, 255}; + + SetHighColor(darkColor); + + FillRoundRect(BRect(18.0, 14.0, 84.0, 64.0), 3.0, 3.0); + + SetHighColor(blackColor); + + StrokeRoundRect(BRect(18.0, 14.0, 84.0, 64.0), 3.0, 3.0); + + SetHighColor(desktopColor); + + FillRoundRect(BRect(22.0, 18.0, 80.0, 60.0), 2.0, 2.0); + + SetHighColor(blackColor); + + StrokeRoundRect(BRect(22.0, 18.0, 80.0, 60.0), 2.0, 2.0); + + SetHighColor(redColor); + + StrokeLine(BPoint(22.0, 62.0), BPoint(23.0, 62.0)); + } + else if(fResolution == 800) + { + rgb_color darkColor = {160, 160, 160, 255}; + rgb_color blackColor = {0, 0, 0, 255}; + rgb_color redColor = {228, 0, 0, 255}; + + SetHighColor(darkColor); + + FillRoundRect(BRect(25.0, 19.0, 77.0, 58.0), 3.0, 3.0); + + SetHighColor(blackColor); + + StrokeRoundRect(BRect(25.0, 19.0, 77.0, 58.0), 3.0, 3.0); + + SetHighColor(desktopColor); + + FillRoundRect(BRect(29.0, 23.0, 73.0, 54.0), 2.0, 2.0); + + SetHighColor(blackColor); + + StrokeRoundRect(BRect(29.0, 23.0, 73.0, 54.0), 2.0, 2.0); + + SetHighColor(redColor); + + StrokeLine(BPoint(29.0, 56.0), BPoint(30.0, 56.0)); + } + else if(fResolution == 640) + { + rgb_color darkColor = {160, 160, 160, 255}; + rgb_color blackColor = {0, 0, 0, 255}; + rgb_color redColor = {228, 0, 0, 255}; + + SetHighColor(darkColor); + + FillRoundRect(BRect(31.0, 23.0, 73.0, 55.0), 3.0, 3.0); + + SetHighColor(blackColor); + + StrokeRoundRect(BRect(31.0, 23.0, 73.0, 55.0), 3.0, 3.0); + + SetHighColor(desktopColor); + + FillRoundRect(BRect(35.0, 27.0, 69.0, 51.0), 2.0, 2.0); + + SetHighColor(blackColor); + + StrokeRoundRect(BRect(35.0, 27.0, 69.0, 51.0), 2.0, 2.0); + + SetHighColor(redColor); + + StrokeLine(BPoint(35.0, 53.0), BPoint(36.0, 53.0)); + } +} + +void ScreenDrawView::MessageReceived(BMessage* message) +{ + switch(message->what) + { + case UPDATE_DESKTOP_MSG: + { + const char *Resolution; + int32 NextfResolution; + + message->FindString("resolution", &Resolution); + + if (strcmp(Resolution, "640 x 480") == 0) + NextfResolution = 640; + else if (strcmp(Resolution, "800 x 600") == 0) + NextfResolution = 800; + else if (strcmp(Resolution, "1024 x 768") == 0) + NextfResolution = 1024; + else if (strcmp(Resolution, "1152 x 864") == 0) + NextfResolution = 1152; + else if (strcmp(Resolution, "1280 x 1024") == 0) + NextfResolution = 1280; + else if (strcmp(Resolution, "1600 x 1200") == 0) + NextfResolution = 1600; + else + NextfResolution = 640; + + if (fResolution != NextfResolution) + { + fResolution = NextfResolution; + + Invalidate(); + } + } + + case UPDATE_DESKTOP_COLOR_MSG: + { + desktopColor = fScreen->DesktopColor(current_workspace()); + + Invalidate(); + } + + default: + BView::MessageReceived(message); + + break; + } +} diff --git a/src/prefs/screen/ScreenDrawView.h b/src/prefs/screen/ScreenDrawView.h new file mode 100644 index 0000000000..951b7586e7 --- /dev/null +++ b/src/prefs/screen/ScreenDrawView.h @@ -0,0 +1,22 @@ +#ifndef SCREENDRAWVIEW_H +#define SCREENDRAWVIEW_H + +#include + +class ScreenDrawView : public BView +{ + +public: + ScreenDrawView(BRect frame, char *name); + virtual void AttachedToWindow(); + virtual void Draw(BRect updateRect); + virtual void MessageReceived(BMessage *message); + virtual void MouseDown(BPoint point); + +private: + BScreen *fScreen; + rgb_color desktopColor; + int32 fResolution; +}; + +#endif \ No newline at end of file diff --git a/src/prefs/screen/ScreenSettings.cpp b/src/prefs/screen/ScreenSettings.cpp new file mode 100644 index 0000000000..dbfd972de6 --- /dev/null +++ b/src/prefs/screen/ScreenSettings.cpp @@ -0,0 +1,49 @@ +#include +#include + +#include "ScreenSettings.h" + +const char ScreenSettings::fScreenSettingsFile[] = "RRScreen_Data"; + +ScreenSettings::ScreenSettings() +{ + BPath path; + if (find_directory(B_USER_SETTINGS_DIRECTORY,&path) == B_OK) + { + path.Append(fScreenSettingsFile); + + BFile file(path.Path(), B_READ_ONLY); + if (file.InitCheck() == B_OK && file.Read(&fWindowFrame, sizeof(BRect)) == sizeof(BRect)) + { + BScreen Screen; + if (Screen.Frame().right >= fWindowFrame.right + && Screen.Frame().bottom >= fWindowFrame.bottom) + return; + } + } + + BScreen Screen; + fWindowFrame = Screen.Frame(); + fWindowFrame.left = (Screen.Frame().right / 2) - 178; + fWindowFrame.top = (Screen.Frame().right / 2) - 101; + fWindowFrame.right = fWindowFrame.left + 356; + fWindowFrame.bottom = fWindowFrame.top + 202; +} + +ScreenSettings::~ScreenSettings() +{ + BPath path; + if (find_directory(B_USER_SETTINGS_DIRECTORY,&path) < B_OK) + return; + + path.Append(fScreenSettingsFile); + + BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE); + if (file.InitCheck() == B_OK) + file.Write(&fWindowFrame, sizeof(BRect)); +} + +void ScreenSettings::SetWindowFrame(BRect frame) +{ + fWindowFrame = frame; +} diff --git a/src/prefs/screen/ScreenSettings.h b/src/prefs/screen/ScreenSettings.h new file mode 100644 index 0000000000..f5929f79bb --- /dev/null +++ b/src/prefs/screen/ScreenSettings.h @@ -0,0 +1,21 @@ +#ifndef SCREENSETTINGS_H +#define SCREENSETTINGS_H + +#include + +class ScreenSettings +{ + +public: + ScreenSettings(); + virtual ~ScreenSettings(); + + BRect WindowFrame() const { return fWindowFrame; }; + void SetWindowFrame(BRect); + +private: + static const char fScreenSettingsFile[]; + BRect fWindowFrame; +}; + +#endif \ No newline at end of file diff --git a/src/prefs/screen/ScreenView.cpp b/src/prefs/screen/ScreenView.cpp new file mode 100644 index 0000000000..c150b8a829 --- /dev/null +++ b/src/prefs/screen/ScreenView.cpp @@ -0,0 +1,33 @@ +#include + +#include "ScreenView.h" + +ScreenView::ScreenView(BRect rect, char *name) + : BView(rect, name, B_FOLLOW_ALL, B_WILL_DRAW) +{ +} + +void ScreenView::AttachedToWindow() +{ + rgb_color greyColor = {216, 216, 216, 255}; + SetViewColor(greyColor); +} + +void ScreenView::Draw(BRect updateRect) +{ + rgb_color whiteColor = {255, 255, 255, 255}; + rgb_color darkColor = {128, 128, 128, 255}; + rgb_color blackColor = {0, 0, 0, 255}; + + SetHighColor(whiteColor); + + StrokeLine(BPoint(Bounds().left, Bounds().top), BPoint(Bounds().right, Bounds().top)); + StrokeLine(BPoint(Bounds().left, Bounds().top), BPoint(Bounds().left, Bounds().bottom)); + + SetHighColor(darkColor); + + StrokeLine(BPoint(Bounds().left, Bounds().bottom), BPoint(Bounds().right, Bounds().bottom)); + StrokeLine(BPoint(Bounds().right, Bounds().bottom), BPoint(Bounds().right, Bounds().top)); + + SetHighColor(blackColor); +} \ No newline at end of file diff --git a/src/prefs/screen/ScreenView.h b/src/prefs/screen/ScreenView.h new file mode 100644 index 0000000000..da2386d63c --- /dev/null +++ b/src/prefs/screen/ScreenView.h @@ -0,0 +1,15 @@ +#ifndef SCREENVIEW_H +#define SCREENVIEW_H + +#include + +class ScreenView : public BView +{ + +public: + ScreenView(BRect frame, char *name); + virtual void AttachedToWindow(); + virtual void Draw(BRect updateRect); +}; + +#endif \ No newline at end of file diff --git a/src/prefs/screen/ScreenWindow.cpp b/src/prefs/screen/ScreenWindow.cpp new file mode 100644 index 0000000000..deb416c5e2 --- /dev/null +++ b/src/prefs/screen/ScreenWindow.cpp @@ -0,0 +1,1216 @@ +// Note: +// The program has been tested with a 17" Monitor only. +// Do not distribute this program at this state. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "ScreenWindow.h" +#include "ScreenDrawView.h" +#include "ScreenView.h" +#include "AlertWindow.h" +#include "Constants.h" + +ScreenWindow::ScreenWindow(ScreenSettings *Settings) + : BWindow(Settings->WindowFrame(), "Screen", B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE, B_ALL_WORKSPACES) +{ + BRect frame = Bounds(); + + fScreenView = new ScreenView(frame, "ScreenView"); + + AddChild(fScreenView); + + fSettings = Settings; + + BRect ScreenBoxRect; + BRect ScreenDrawViewRect; + BRect ControlsBoxRect; + BRect WorkspaceMenuRect; + BRect WorkspaceCountMenuRect; + BRect ControlMenuRect; + BRect ButtonRect; + + ScreenBoxRect.Set(11.0, 18.0, 153.0, 155.0); + + fScreenBox = new BBox(ScreenBoxRect); + fScreenBox->SetBorder(B_FANCY_BORDER); + + ScreenDrawViewRect.Set(20.0, 16.0, 122.0, 93.0); + + fScreenDrawView = new ScreenDrawView(ScreenDrawViewRect, "ScreenDrawView"); + + int32 Count; + + BString String; + + String << count_workspaces(); + + fWorkspaceCountMenu = new BPopUpMenu(String.String(), true, true); + for (Count = 1; Count <= 32; Count++) + { + String.Truncate(0); + String << Count; + fWorkspaceCountMenu->AddItem(new BMenuItem(String.String(), new BMessage(POP_WORKSPACE_CHANGED_MSG))); + } + + String.Truncate(0); + String << count_workspaces(); + + BMenuItem *Marked = fWorkspaceCountMenu->FindItem(String.String()); + Marked->SetMarked(true); + + WorkspaceCountMenuRect.Set(7.0, 107.0, 135.0, 127.0); + + fWorkspaceCountField = new BMenuField(WorkspaceCountMenuRect, "WorkspaceCountMenu", "Workspace count:", fWorkspaceCountMenu, true); + + fWorkspaceCountField->SetDivider(91.0); + + fScreenBox->AddChild(fScreenDrawView); + + fScreenBox->AddChild(fWorkspaceCountField); + + fScreenView->AddChild(fScreenBox); + + fWorkspaceMenu = new BPopUpMenu("Current Workspace", true, true); + fAllWorkspacesItem = new BMenuItem("All Workspaces", new BMessage(WORKSPACE_CHECK_MSG)); + fWorkspaceMenu->AddItem(fAllWorkspacesItem); + fCurrentWorkspaceItem = new BMenuItem("Current Workspace", new BMessage(WORKSPACE_CHECK_MSG)); + fCurrentWorkspaceItem->SetMarked(true); + fWorkspaceMenu->AddItem(fCurrentWorkspaceItem); + + WorkspaceMenuRect.Set(0.0, 0.0, 132.0, 18.0); + + fWorkspaceField = new BMenuField(WorkspaceMenuRect, "WorkspaceMenu", NULL, fWorkspaceMenu, true); + + ControlsBoxRect.Set(164.0, 7.0, 345.0, 155.0); + + fControlsBox = new BBox(ControlsBoxRect); + fControlsBox->SetBorder(B_FANCY_BORDER); + fControlsBox->SetLabel(fWorkspaceField); + + ButtonRect.Set(88.0, 114.0, 200.0, 150.0); + + fApplyButton = new BButton(ButtonRect, "ApplyButton", "Apply", + new BMessage(BUTTON_APPLY_MSG)); + + fApplyButton->AttachedToWindow(); + fApplyButton->ResizeToPreferred(); + fApplyButton->SetEnabled(false); + + fControlsBox->AddChild(fApplyButton); + + fResolutionMenu = new BPopUpMenu("640 x 480", true, true); + fResolutionMenu->AddItem(new BMenuItem("640 x 480", new BMessage(POP_RESOLUTION_MSG))); + fResolutionMenu->AddItem(new BMenuItem("800 x 600", new BMessage(POP_RESOLUTION_MSG))); + fResolutionMenu->AddItem(new BMenuItem("1024 x 768", new BMessage(POP_RESOLUTION_MSG))); + fResolutionMenu->AddItem(new BMenuItem("1152 x 864", new BMessage(POP_RESOLUTION_MSG))); + fResolutionMenu->AddItem(new BMenuItem("1280 x 1024", new BMessage(POP_RESOLUTION_MSG))); + fResolutionMenu->AddItem(new BMenuItem("1600 x 1200", new BMessage(POP_RESOLUTION_MSG))); + + ControlMenuRect.Set(33.0, 30.0, 171.0, 48.0); + + fResolutionField = new BMenuField(ControlMenuRect, "ResolutionMenu", "Resolution:", fResolutionMenu, true); + + Marked = fResolutionMenu->FindItem("640 x 480"); + Marked->SetMarked(true); + + fResolutionField->SetDivider(55.0); + + fControlsBox->AddChild(fResolutionField); + + fColorsMenu = new BPopUpMenu("8 Bits/Pixel", true, true); + fColorsMenu->AddItem(new BMenuItem("8 Bits/Pixel", new BMessage(POP_COLORS_MSG))); + fColorsMenu->AddItem(new BMenuItem("15 Bits/Pixel", new BMessage(POP_COLORS_MSG))); + fColorsMenu->AddItem(new BMenuItem("16 Bits/Pixel", new BMessage(POP_COLORS_MSG))); + fColorsMenu->AddItem(new BMenuItem("32 Bits/Pixel", new BMessage(POP_COLORS_MSG))); + + ControlMenuRect.Set(50.0, 58.0, 171.0, 76.0); + + fColorsField = new BMenuField(ControlMenuRect, "ColorsMenu", "Colors:", fColorsMenu, true); + + Marked = fColorsMenu->FindItem("8 Bits/Pixel"); + Marked->SetMarked(true); + + fColorsField->SetDivider(38.0); + + fControlsBox->AddChild(fColorsField); + + + fRefreshMenu = new BPopUpMenu("60 Hz", true, true); + fRefreshMenu->AddItem(new BMenuItem("56 Hz", new BMessage(POP_REFRESH_MSG))); + fRefreshMenu->AddItem(new BMenuItem("60 Hz", new BMessage(POP_REFRESH_MSG))); + fRefreshMenu->AddItem(new BMenuItem("70 Hz", new BMessage(POP_REFRESH_MSG))); + fRefreshMenu->AddItem(new BMenuItem("72 Hz", new BMessage(POP_REFRESH_MSG))); + fRefreshMenu->AddItem(new BMenuItem("75 Hz", new BMessage(POP_REFRESH_MSG))); + fRefreshMenu->AddItem(new BMenuItem("Other...", new BMessage(POP_OTHER_REFRESH_MSG))); + + ControlMenuRect.Set(19.0, 86.0, 171.0, 104.0); + + fRefreshField = new BMenuField(ControlMenuRect, "RefreshMenu", "Refresh Rate:", fRefreshMenu, true); + + Marked = fRefreshMenu->FindItem("60 Hz"); + Marked->SetMarked(true); + + fRefreshField->SetDivider(69.0); + + fControlsBox->AddChild(fRefreshField); + + fScreenView->AddChild(fControlsBox); + + ButtonRect.Set(10.0, 167, 100.0, 200.0); + + fDefaultsButton = new BButton(ButtonRect, "DefaultsButton", "Defaults", + new BMessage(BUTTON_DEFAULTS_MSG)); + + fDefaultsButton->AttachedToWindow(); + fDefaultsButton->ResizeToPreferred(); + + fScreenView->AddChild(fDefaultsButton); + + ButtonRect.Set(95.0, 167, 160.0, 200.0); + + fRevertButton = new BButton(ButtonRect, "RevertButton", "Revert", + new BMessage(BUTTON_REVERT_MSG)); + + fRevertButton->AttachedToWindow(); + fRevertButton->ResizeToPreferred(); + fRevertButton->SetEnabled(false); + + fScreenView->AddChild(fRevertButton); + + BScreen *Screen = new BScreen(B_MAIN_SCREEN_ID); + + display_mode mode; + + Screen->GetMode(&mode); + + fInitialMode = mode; + + String.Truncate(0); + + String << (int32)mode.virtual_width << " x " << (int32)mode.virtual_height; + + Marked = fResolutionMenu->FindItem(String.String()); + Marked->SetMarked(true); + + fInitialResolution = Marked; + + if (mode.space == B_CMAP8) + { + Marked = fColorsMenu->FindItem("8 Bits/Pixel"); + Marked->SetMarked(true); + } + if (mode.space == B_RGB15) + { + Marked = fColorsMenu->FindItem("15 Bits/Pixel"); + Marked->SetMarked(true); + } + if (mode.space == B_RGB16) + { + Marked = fColorsMenu->FindItem("16 Bits/Pixel"); + Marked->SetMarked(true); + } + if (mode.space == B_RGB32) + { + Marked = fColorsMenu->FindItem("32 Bits/Pixel"); + Marked->SetMarked(true); + } + + fInitialColors = Marked; + + String.Truncate(0); + + int32 total_size = mode.timing.h_total * mode.timing.v_total; + + fInitialRefreshN = (mode.timing.pixel_clock * 1000) / total_size; + + fCustomRefresh = fInitialRefreshN; + + String << (int32)fInitialRefreshN << " Hz"; + + Marked = fRefreshMenu->FindItem(String.String()); + if (Marked != NULL) + { + Marked->SetMarked(true); + + fInitialRefresh = Marked; + } + else + { + BMenuItem *Other = fRefreshMenu->FindItem("Other..."); + + String.Truncate(0); + + float total_sizef = mode.timing.h_total * mode.timing.v_total; + + String << ((int32)mode.timing.pixel_clock * 1000) / total_sizef; + + String.Truncate(4); + + String << " Hz/Other..."; + + Other->SetLabel(String.String()); + Other->SetMarked(true); + + String.Truncate(7); + + fRefreshMenu->Superitem()->SetLabel(String.String()); + + fInitialRefresh = Other; + } + + Show(); +} + +ScreenWindow::~ScreenWindow() +{ + delete fSettings; +} + +bool ScreenWindow::QuitRequested() +{ + be_app->PostMessage(B_QUIT_REQUESTED); + + return(true); +} + +void ScreenWindow::FrameMoved(BPoint position) +{ + fSettings->SetWindowFrame(Frame()); +} + +void ScreenWindow::ScreenChanged(BRect frame, color_space mode) +{ + if (frame.right <= Frame().right + && frame.bottom <= Frame().bottom) + MoveTo(((frame.right / 2) - 178), ((frame.right / 2) - 101)); +} + +void ScreenWindow::WorkspaceActivated(int32 ws, bool state) +{ + PostMessage(new BMessage(UPDATE_DESKTOP_COLOR_MSG), fScreenDrawView); +} + +void ScreenWindow::CheckApplyEnabled() +{ + int equals = 0; + + if (fResolutionMenu->FindMarked() == fInitialResolution) + { + equals = equals + 1; + } + else + { + equals = equals - 1; + } + + if (fColorsMenu->FindMarked() == fInitialColors) + { + equals = equals + 1; + } + else + { + equals = equals - 1; + } + + if (fRefreshMenu->FindMarked() == fInitialRefresh) + { + equals = equals + 1; + } + else + { + equals = equals - 1; + } + + if(equals != 3) + { + fApplyButton->SetEnabled(true); + fRevertButton->SetEnabled(true); + } + else + { + fApplyButton->SetEnabled(false); + fRevertButton->SetEnabled(false); + } +} + +void ScreenWindow::MessageReceived(BMessage* message) +{ + switch(message->what) + { + case WORKSPACE_CHECK_MSG: + { + fApplyButton->SetEnabled(true); + + break; + } + + case POP_WORKSPACE_CHANGED_MSG: + { + BMenuItem *Item = fWorkspaceCountMenu->FindMarked(); + + set_workspace_count(fWorkspaceCountMenu->IndexOf(Item) + 1); + + break; + } + + case POP_RESOLUTION_MSG: + { + CheckApplyEnabled(); + + BMessage *Message = new BMessage(UPDATE_DESKTOP_MSG); + + const char *Resolution; + + Resolution = fResolutionMenu->FindMarked()->Label(); + + Message->AddString("resolution", Resolution); + + PostMessage(Message, fScreenDrawView); + + if (fResolutionMenu->FindMarked() == fInitialResolution) + + break; + } + + case POP_COLORS_MSG: + { + CheckApplyEnabled(); + + break; + } + + case POP_REFRESH_MSG: + { + CheckApplyEnabled(); + + break; + } + + case POP_OTHER_REFRESH_MSG: + { + CheckApplyEnabled(); + + int32 Value; + + Value = (int32)fCustomRefresh; + + fRefreshWindow = new RefreshWindow(BRect((Frame().left + 201.0), (Frame().top + 34.0), (Frame().left + 509.0), (Frame().top + 169.0)), Value); + + BMenuItem *Other = fRefreshMenu->FindItem(POP_OTHER_REFRESH_MSG); + + BString String; + + String << Other->Label(); + + String.Truncate(7); + + fRefreshMenu->Superitem()->SetLabel(String.String()); + + break; + } + + case BUTTON_DEFAULTS_MSG: + { + fResolutionMenu->FindItem("640 x 480")->SetMarked(true); + fColorsMenu->FindItem("8 Bits/Pixel")->SetMarked(true); + fRefreshMenu->FindItem("60 Hz")->SetMarked(true); + + CheckApplyEnabled(); + + break; + } + + case BUTTON_REVERT_MSG: + { + fInitialResolution->SetMarked(true); + fInitialColors->SetMarked(true); + fInitialRefresh->SetMarked(true); + + CheckApplyEnabled(); + + BMenuItem *Other = fRefreshMenu->FindItem(POP_OTHER_REFRESH_MSG); + + if (fInitialRefresh == Other) + { + BString String; + + String << fInitialRefreshN; + + String.Truncate(4); + + String << " Hz/Other..."; + + fRefreshMenu->FindItem(POP_OTHER_REFRESH_MSG)->SetLabel(String.String()); + + String.Truncate(7); + + fRefreshMenu->Superitem()->SetLabel(String.String()); + } + + break; + } + + case BUTTON_APPLY_MSG: + { + BScreen *Screen; + + Screen = new BScreen(B_MAIN_SCREEN_ID); + + display_mode *modelist; + display_mode *mode = NULL; + + uint32 count; + + Screen->GetModeList(&modelist, &count); + + uint32 loop = 0; + + count = count - 1; + + if (fResolutionMenu->FindMarked() == fResolutionMenu->FindItem("640 x 480")) + { + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem("56 Hz")) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 0) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * 56 / 1000; + } + + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem("60 Hz")) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 2) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * 60 / 1000; + } + + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem("70 Hz")) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 3) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * 70 / 1000; + } + + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem("72 Hz")) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 3) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * 72 / 1000; + } + + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem("75 Hz")) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 4) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * 75 / 1000; + } + + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem(POP_OTHER_REFRESH_MSG)) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 3) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * fCustomRefresh / 1000; + } + } + else if (fResolutionMenu->FindMarked() == fResolutionMenu->FindItem("800 x 600")) + { + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem("56 Hz")) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 6) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * 56 / 1000; + } + + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem("60 Hz")) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 8) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * 60 / 1000; + } + + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem("70 Hz")) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 9) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * 70 / 1000; + } + + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem("72 Hz")) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 9) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * 72 / 1000; + } + + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem("75 Hz")) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 10) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * 75 / 1000; + } + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem(POP_OTHER_REFRESH_MSG)) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 8) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * fCustomRefresh / 1000; + } + } + else if (fResolutionMenu->FindMarked() == fResolutionMenu->FindItem("1024 x 768")) + { + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem("56 Hz")) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 11) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * 56 / 1000; + } + + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem("60 Hz")) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 13) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * 60 / 1000; + } + + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem("70 Hz")) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 14) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * 70 / 1000; + } + + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem("72 Hz")) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 14) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * 72 / 1000; + } + + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem("75 Hz")) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 15) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * 75 / 1000; + } + + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem(POP_OTHER_REFRESH_MSG)) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 13) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * fCustomRefresh / 1000; + } + } + else if (fResolutionMenu->FindMarked() == fResolutionMenu->FindItem("1152 x 864")) + { + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem("56 Hz")) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 16) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * 56 / 1000; + } + + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem("60 Hz")) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 16) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * 60 / 1000; + } + + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem("70 Hz")) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 17) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * 70 / 1000; + } + + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem("72 Hz")) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 17) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * 72 / 1000; + } + + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem("75 Hz")) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 17) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * 75 / 1000; + } + + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem(POP_OTHER_REFRESH_MSG)) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 16) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * fCustomRefresh / 1000; + } + } + else if (fResolutionMenu->FindMarked() == fResolutionMenu->FindItem("1280 x 1024")) + { + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem("56 Hz")) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 18) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * 56 / 1000; + } + + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem("60 Hz")) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 20) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * 60 / 1000; + } + + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem("70 Hz")) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 20) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * 70 / 1000; + } + + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem("72 Hz")) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 20) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * 72 / 1000; + } + + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem("75 Hz")) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 20) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * 75 / 1000; + } + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem(POP_OTHER_REFRESH_MSG)) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 19) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * fCustomRefresh / 1000; + } + } + else if (fResolutionMenu->FindMarked() == fResolutionMenu->FindItem("1600 x 1200")) + { + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem("56 Hz")) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 21) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * 56 / 1000; + } + + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem("60 Hz")) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 23) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * 60 / 1000; + } + + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem("70 Hz")) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 24) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * 70 / 1000; + } + + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem("72 Hz")) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 24) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * 72 / 1000; + } + + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem("75 Hz")) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 25) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * 75 / 1000; + } + + if (fRefreshMenu->FindMarked() == fRefreshMenu->FindItem(POP_OTHER_REFRESH_MSG)) + { + for (loop = 0; loop <= count; loop++) + { + if (mode != NULL) + break; + + if (loop == 22) + mode = modelist; + + modelist++; + } + + mode->timing.pixel_clock = (mode->timing.h_total * mode->timing.v_total) * fCustomRefresh / 1000; + } + } + + if (fColorsMenu->FindMarked() == fColorsMenu->FindItem("8 Bits/Pixel")) + { + mode->space = B_CMAP8; + } + else if (fColorsMenu->FindMarked() == fColorsMenu->FindItem("15 Bits/Pixel")) + { + mode->space = B_RGB15; + } + else if (fColorsMenu->FindMarked() == fColorsMenu->FindItem("16 Bits/Pixel")) + { + mode->space = B_RGB16; + } + else if (fColorsMenu->FindMarked() == fColorsMenu->FindItem("32 Bits/Pixel")) + { + mode->space = B_RGB32; + } + + mode->h_display_start = 0; + mode->v_display_start = 0; + + if (fWorkspaceMenu->FindMarked() == fWorkspaceMenu->FindItem("All Workspaces")) + { + int32 button; + + BAlert *WorkspacesAlert = new BAlert("WorkspacesAlert", "Change all workspaces? +This action cannot be reverted", "Okay", "Cancel", NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); + button = WorkspacesAlert->Go(); + + if (button == 1) + break; + + int32 count, old; + + old = current_workspace(); + + for (count = 0; count < count_workspaces(); count ++) + { + activate_workspace(count); + Screen->SetMode(mode); + } + + activate_workspace(old); + } + else + Screen->SetMode(mode); + + BRect Rect; + + Rect.Set(100.0, 100.0, 400.0, 193.0); + + Rect.left = (Screen->Frame().right / 2) - 150; + Rect.top = (Screen->Frame().bottom / 2) - 42; + Rect.right = Rect.left + 300.0; + Rect.bottom = Rect.top + 93.0; + + new AlertWindow(Rect); + + break; + } + + case SET_INITIAL_MODE_MSG: + { + BMenuItem *Other = fRefreshMenu->FindItem(POP_OTHER_REFRESH_MSG); + + if (fInitialRefresh == Other) + { + Other->SetMarked(true); + + BString String; + + String << fInitialRefreshN; + + String.Truncate(4); + + String << " Hz/Other..."; + + fRefreshMenu->FindItem(POP_OTHER_REFRESH_MSG)->SetLabel(String.String()); + + String.Truncate(7); + + fRefreshMenu->Superitem()->SetLabel(String.String()); + } + BScreen *Screen; + + Screen = new BScreen(B_MAIN_SCREEN_ID); + + Screen->SetMode(&fInitialMode); + + break; + } + + case SET_CUSTOM_REFRESH_MSG: + { + message->FindFloat("refresh", &fCustomRefresh); + + BMenuItem *Other = fRefreshMenu->FindItem(POP_OTHER_REFRESH_MSG); + + Other->SetMarked(true); + + BString String; + + String << fCustomRefresh; + + String.Truncate(4); + + String << " Hz/Other..."; + + fRefreshMenu->FindItem(POP_OTHER_REFRESH_MSG)->SetLabel(String.String()); + + String.Truncate(7); + + fRefreshMenu->Superitem()->SetLabel(String.String()); + + if (fCustomRefresh != fInitialRefreshN) + { + fApplyButton->SetEnabled(true); + fRevertButton->SetEnabled(true); + } + + break; + } + + case MAKE_INITIAL_MSG: + { + BScreen *Screen; + + display_mode mode; + + Screen = new BScreen(B_MAIN_SCREEN_ID); + + Screen->GetMode(&mode); + + fInitialRefreshN = fCustomRefresh; + fInitialResolution = fResolutionMenu->FindMarked(); + fInitialColors = fColorsMenu->FindMarked(); + fInitialRefresh = fRefreshMenu->FindMarked(); + fInitialMode = mode; + + break; + } + + default: + BWindow::MessageReceived(message); + + break; + } +} diff --git a/src/prefs/screen/ScreenWindow.h b/src/prefs/screen/ScreenWindow.h new file mode 100644 index 0000000000..aaa8bed609 --- /dev/null +++ b/src/prefs/screen/ScreenWindow.h @@ -0,0 +1,58 @@ +#ifndef SCREENWINDOW_H +#define SCREENWINDOW_H + +#include +#include +#include +#include +#include + +#include "ScreenView.h" +#include "ScreenDrawView.h" +#include "RefreshWindow.h" +#include "ScreenSettings.h" + +class ScreenWindow : public BWindow +{ + +public: + ScreenWindow(ScreenSettings *Settings); + virtual ~ScreenWindow(); + virtual bool QuitRequested(); + virtual void MessageReceived(BMessage *message); + virtual void WorkspaceActivated(int32 ws, bool state); + virtual void FrameMoved(BPoint position); + virtual void ScreenChanged(BRect frame, color_space mode); + +private: + void CheckApplyEnabled(); + ScreenSettings *fSettings; + ScreenView *fScreenView; + ScreenDrawView *fScreenDrawView; + RefreshWindow *fRefreshWindow; + BPopUpMenu *fWorkspaceMenu; + BMenuField *fWorkspaceField; + BPopUpMenu *fWorkspaceCountMenu; + BMenuField *fWorkspaceCountField; + BPopUpMenu *fResolutionMenu; + BMenuField *fResolutionField; + BPopUpMenu *fColorsMenu; + BMenuField *fColorsField; + BPopUpMenu *fRefreshMenu; + BMenuField *fRefreshField; + BMenuItem *fCurrentWorkspaceItem; + BMenuItem *fAllWorkspacesItem; + BButton *fDefaultsButton; + BButton *fApplyButton; + BButton *fRevertButton; + BBox *fScreenBox; + BBox *fControlsBox; + BMenuItem *fInitialResolution; + BMenuItem *fInitialColors; + BMenuItem *fInitialRefresh; + display_mode fInitialMode; + float fCustomRefresh; + float fInitialRefreshN; +}; + +#endif \ No newline at end of file diff --git a/src/prefs/screensaver/Constants.cpp b/src/prefs/screensaver/Constants.cpp new file mode 100644 index 0000000000..d05b6ec804 --- /dev/null +++ b/src/prefs/screensaver/Constants.cpp @@ -0,0 +1,44 @@ +#ifndef __CONSTANTS__ +#define __CONSTANTS__ + +static const char *times[]={"30 seconds", "1 minute", "1 minute 30 seconds", + "2 minutes", "2 minutes 30 seconds", "3 minutes", + "4 minutes", "5 minutes", "6 minutes", + "7 minutes", "8 minutes", "9 minutes", + "10 minutes", "15 minutes", "20 minutes", + "25 minutes", "30 minutes", "40 minutes", + "50 minutes", "1 hour", "1 hour 30 minutes", + "2 hours", "2 hours 30 minutes", "3 hours", + "4 hours", "5 hours"}; +static const int timeInSeconds[]={ 30, 60, 90, + 120, 150, 180, + 240, 300, 360, + 420, 480, 540, + 600, 900, 1200, + 1500, 1800, 2400, + 3000, 3600, 5400, + 7200, 9000, 10800, + 14400, 18000}; + +int secondsToSlider(int); + +const int TAB1_CHG='TAB1'; +const int TAB2_CHG='TAB2'; +const int PWBUTTON='PWBT'; +const int DONE_CLICKED='DONE'; +const int CANCEL_CLICKED='CNCL'; +const int BUTTON_CHANGED='BTNC'; +const int SHOW='SHOW'; +const int POPULATE='POPU'; +const int UTILIZE='UTIL'; +const int SAVER_SEL='SSEL'; + +rgb_color black = {0,0,0,0}; +rgb_color darkGrey = {150,150,150,0}; +rgb_color grey = {200,200,200,0}; +rgb_color lightBlue = {200,200,255,0}; +rgb_color lightGreen = {255,200,200,0}; +rgb_color red = {255,100,100,0}; + + +#endif diff --git a/src/prefs/screensaver/Constants.h b/src/prefs/screensaver/Constants.h new file mode 100644 index 0000000000..9035e7fd0b --- /dev/null +++ b/src/prefs/screensaver/Constants.h @@ -0,0 +1,44 @@ +#ifndef __CONSTANTS__ +#define __CONSTANTS__ + +static const char *times[]={"30 seconds", "1 minute", "1 minute 30 seconds", + "2 minutes", "2 minutes 30 seconds", "3 minutes", + "4 minutes", "5 minutes", "6 minutes", + "7 minutes", "8 minutes", "9 minutes", + "10 minutes", "15 minutes", "20 minutes", + "25 minutes", "30 minutes", "40 minutes", + "50 minutes", "1 hour", "1 hour 30 minutes", + "2 hours", "2 hours 30 minutes", "3 hours", + "4 hours", "5 hours"}; +static const int timeInSeconds[]={ 30, 60, 90, + 120, 150, 180, + 240, 300, 360, + 420, 480, 540, + 600, 900, 1200, + 1500, 1800, 2400, + 3000, 3600, 5400, + 7200, 9000, 10800, + 14400, 18000}; + +int secondsToSlider(int); + +const int TAB1_CHG ='TAB1'; +const int TAB2_CHG ='TAB2'; +const int PWBUTTON ='PWBT'; +const int DONE_CLICKED ='DONE'; +const int CANCEL_CLICKED ='CNCL'; +const int BUTTON_CHANGED ='BTNC'; +const int SHOW ='SHOW'; +const int POPULATE ='POPU'; +const int UTILIZE ='UTIL'; +const int SAVER_SEL ='SSEL'; + +const rgb_color black = {0,0,0,0}; +const rgb_color darkGrey = {150,150,150,0}; +const rgb_color grey = {200,200,200,0}; +const rgb_color lightBlue = {200,200,255,0}; +const rgb_color lightGreen = {255,200,200,0}; +const rgb_color red = {255,100,100,0}; + + +#endif diff --git a/src/prefs/screensaver/MouseAreaView.cpp b/src/prefs/screensaver/MouseAreaView.cpp new file mode 100644 index 0000000000..fe7d4f4776 --- /dev/null +++ b/src/prefs/screensaver/MouseAreaView.cpp @@ -0,0 +1,132 @@ +#include "MouseAreaView.h" +#include "Constants.h" +#include +#include +#include +#include + +inline BPoint scaleDirect(float x, float y,BRect area) +{ + return BPoint(area.Width()*x+area.left,area.Height()*y+area.top); +} + +inline BRect scaleDirect (float x1,float x2,float y1,float y2,BRect area) +{ + return BRect(area.Width()*x1+area.left,area.Height()*y1+area.top, area.Width()*x2+area.left,area.Height()*y2+area.top); +} + +float positionalX[]= {0,.1,.25,.3,.7,.75,.9,1.0}; +float positionalY[]= {0,.1,.7,.8,.9,1.0}; + +inline BPoint scale(int x, int y,BRect area) { return scaleDirect(positionalX[x],positionalY[y],area); } +inline BRect scale(int x1, int x2, int y1, int y2,BRect area) { return scaleDirect(positionalX[x1],positionalX[x2],positionalY[y1],positionalY[y2],area); } + +int secondsToSlider(int val) +{ + int t; + for (t=0;t + +enum arrowDirection {UPLEFT,UPRIGHT,DOWNLEFT,DOWNRIGHT,NONE}; + +class MouseAreaView : public BView +{ + public: + MouseAreaView(BRect frame, const char *name) : BView (frame,name,B_FOLLOW_NONE,B_WILL_DRAW) + { SetViewColor(216,216,216); + currentDirection=NONE;} + + virtual void Draw(BRect update); + virtual void MouseUp(BPoint point); + void DrawArrow(void); + inline int getDirection(void) {return ((int)currentDirection);} + void setDirection(int direction) {currentDirection=(arrowDirection)direction;Draw(BRect (0,0,100,100));} + private: + BRect screenArea; + arrowDirection currentDirection; +}; diff --git a/src/prefs/screensaver/OBOSScreenSaverPreferences.cpp b/src/prefs/screensaver/OBOSScreenSaverPreferences.cpp new file mode 100644 index 0000000000..64aa2bd267 --- /dev/null +++ b/src/prefs/screensaver/OBOSScreenSaverPreferences.cpp @@ -0,0 +1,36 @@ +#include + +#include "OBOSScreenSaverPreferences.h" +#include "ScreenSaver.h" + +const char *APP_SIG = "application/x-vnd.SSPreferences"; + +OBOSScreenSaverPreferences::OBOSScreenSaverPreferences(void) : BApplication(APP_SIG) +{ + m_MainForm = new ScreenSaver(); + m_MainForm->Show(); +} + +OBOSScreenSaverPreferences::~OBOSScreenSaverPreferences(void) +{ +} + +void OBOSScreenSaverPreferences::MessageReceived(BMessage *message) +{ + switch(message->what) + { + case B_READY_TO_RUN: + break; + default: + { + BApplication::MessageReceived(message); + } + } +} + +int main(void) +{ + OBOSScreenSaverPreferences app; + app.Run(); + return 0; +} diff --git a/src/prefs/screensaver/OBOSScreenSaverPreferences.h b/src/prefs/screensaver/OBOSScreenSaverPreferences.h new file mode 100644 index 0000000000..4a522fdac5 --- /dev/null +++ b/src/prefs/screensaver/OBOSScreenSaverPreferences.h @@ -0,0 +1,16 @@ +#ifndef _OBOSScreenSaverPreferences_H +#define _OBOSScreenSaverPreferences_H + +extern const char *APP_SIG; + +class OBOSScreenSaverPreferences: public BApplication { + BWindow *m_MainForm; +public: + OBOSScreenSaverPreferences(void); + virtual ~OBOSScreenSaverPreferences(void); + + virtual void MessageReceived(BMessage *); + +}; + +#endif // _OBOSScreenSaverPreferences_H diff --git a/src/prefs/screensaver/PreviewView.cpp b/src/prefs/screensaver/PreviewView.cpp new file mode 100644 index 0000000000..dcfc425704 --- /dev/null +++ b/src/prefs/screensaver/PreviewView.cpp @@ -0,0 +1,155 @@ +#include "PreviewView.h" +#include "Constants.h" +#include +#include +#include +#include +#include +#include + +inline BPoint scaleDirect(float x, float y,BRect area) +{ + return BPoint(area.Width()*x+area.left,area.Height()*y+area.top); +} + +inline BRect scaleDirect (float x1,float x2,float y1,float y2,BRect area) +{ + return BRect(area.Width()*x1+area.left,area.Height()*y1+area.top, area.Width()*x2+area.left,area.Height()*y2+area.top); +} + +//float positionalX[]= {0,.1,.25,.3,.7,.75,.9,1.0}; +//float positionalY[]= {0,.1,.7,.8,.9,1.0}; + +//inline BPoint scale(int x, int y,BRect area) { return scaleDirect(positionalX[x],positionalY[y],area); } +//inline BRect scale(int x1, int x2, int y1, int y2,BRect area) { return scaleDirect(positionalX[x1],positionalX[x2],positionalY[y1],positionalY[y2],area); } + +float sampleX[]= {0,.025,.25,.6,.625,.7,.725,.75,.975,1.0}; +float sampleY[]= {0,.05,.8,.9,.933,.966,1.0}; +inline BPoint scale2(int x, int y,BRect area) { return scaleDirect(sampleX[x],sampleY[y],area); } +inline BRect scale2(int x1, int x2, int y1, int y2,BRect area) { return scaleDirect(sampleX[x1],sampleX[x2],sampleY[y1],sampleY[y2],area); } + +PreviewView::PreviewView(BRect frame, const char *name) +: BView (frame,name,B_FOLLOW_NONE,B_WILL_DRAW), + addonImage (0), + saver (0), + settingsBoxPtr (0) +{ + SetViewColor(216,216,216); + AddChild(previewArea=new BView (scale2(1,8,1,2,Bounds()),"sampleScreen",B_FOLLOW_NONE,0)); + previewArea->SetViewColor(lightBlue); +} + +void PreviewView::Draw(BRect update) +{ + SetViewColor(216,216,216); + SetHighColor(grey); + FillRoundRect(scale2(0,9,0,3,Bounds()),4,4); + SetHighColor(black); + StrokeRoundRect(scale2(0,9,0,3,Bounds()),4,4); + FillRoundRect(scale2(1,8,1,2,Bounds()),4,4); + SetHighColor(grey); + FillRoundRect(scale2(2,7,3,6,Bounds()),4,4); + SetHighColor(black); + StrokeLine(scale2(2,3,Bounds()),scale2(2,6,Bounds())); + StrokeLine(scale2(2,6,Bounds()),scale2(7,6,Bounds())); + StrokeLine(scale2(7,6,Bounds()),scale2(7,3,Bounds())); + SetHighColor(lightGreen); + FillRect(scale2(3,4,4,5,Bounds())); + SetHighColor(darkGrey); + FillRect(scale2(5,6,4,5,Bounds())); +} + +void removeChildren(BView* view) +{ + int children = view->CountChildren(); + std::cout << "Removing " << children << " child(ren) from view\n"; + BView* child = view->ChildAt(0); + while( child != NULL ) + { + removeChildren( child ); + view->RemoveChild(child); + delete child; + child = view->ChildAt(0); + } +} + +void PreviewView::LoadNewAddon(const char* addOnFilename) +{ + status_t lastOpStatus; + + BScreenSaver *(*instantiate)(BMessage *, image_id ); + if (saver != 0) + { + // tell module the show's over + saver->StopSaver(); + saver->StopConfig(); + // get rid of the settings elements + removeChildren( settingsBoxPtr ); + settingsBoxPtr->Draw(settingsBoxPtr->Bounds()); + // get rid of the module + delete saver; + saver = 0; + + // clean up preview area + previewArea->ClearViewOverlay(); + previewArea->ClearViewBitmap(); + } + if (addonImage != 0) + { + unload_add_on(addonImage); + addonImage = 0; + } + + std::cout << "Loading add-on: " << addOnFilename << '\n'; + addonImage = load_add_on(addOnFilename); + if (addonImage < 0 ) + { + std::cout << "Unable to open the add-on\n" + "load_add_on returned " << std::hex << addonImage << std::dec << "!\n"; + return; + } + std::cout << "Add-on loaded properly! image = " << addonImage << '\n'; + + lastOpStatus = get_image_symbol(addonImage, "instantiate_screen_saver", B_SYMBOL_TYPE_TEXT,(void **) &instantiate); + if (lastOpStatus != B_OK) + { + // add-on does not have proper function exported! + std::cout << "Add-on does not export instantiation function, " + "get_image_symbol() returned " << lastOpStatus << '\n'; + return; + } + + std::cout << "Add-on supports correct functionality!\n"; + saver = instantiate(new BMessage, addonImage); + std::cout << "instantiate() called correctly!\n"; + + std::cout << "setting up screen saver for preview\n"; + lastOpStatus = saver->InitCheck(); + if ( lastOpStatus != B_OK ) + { + std::cout << "InitCheck() said no go, returned " << lastOpStatus << '\n'; + return; + } + + std::cout << "InitCheck() returned B_OK, calling StartSaver()\n"; + lastOpStatus = saver->StartSaver(previewArea, true); + if ( lastOpStatus != B_OK ) + { + std::cout << "StartSaver() said no go, returned " << lastOpStatus << '\n'; + return; + } + + std::cout << "StartSaver() returned B_OK, calling StartConfig()\n"; + if ( settingsBoxPtr == 0 ) + { + std::cout << "Settings box not instantiated yet!\n"; + } + else + { + saver->StartConfig( settingsBoxPtr ); + } + + std::cout << "StartConfig() called, drawing first frame for now.\n"; + saver->Draw(previewArea, 0); + +} \ No newline at end of file diff --git a/src/prefs/screensaver/PreviewView.h b/src/prefs/screensaver/PreviewView.h new file mode 100644 index 0000000000..acf557cb95 --- /dev/null +++ b/src/prefs/screensaver/PreviewView.h @@ -0,0 +1,21 @@ +#include +#include + +class BScreenSaver; + +class PreviewView : public BView +{ +public: + PreviewView(BRect frame, const char *name); + void Draw(BRect update); + void LoadNewAddon(const char* addOnFilename); + + void SetSettingsBoxPtr( BBox* settingsBox ) + { settingsBoxPtr = settingsBox; } + +private: + BView *previewArea; + BBox *settingsBoxPtr; + image_id addonImage; + BScreenSaver* saver; +}; diff --git a/src/prefs/screensaver/ScreenSaver.cpp b/src/prefs/screensaver/ScreenSaver.cpp new file mode 100644 index 0000000000..d5f356905d --- /dev/null +++ b/src/prefs/screensaver/ScreenSaver.cpp @@ -0,0 +1,416 @@ +#include "ScreenSaver.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "MouseAreaView.h" +#include "PreviewView.h" + +void drawPositionalMonitor(BView *view,BRect areaToDrawIn,int state); +BView *drawSampleMonitor(BView *view, BRect area); + int columns[4]={15,175,195,430}; + int rows[6]={10,150,155,255,270,290}; + +struct SSListItem +{ + BString fileName; + BString displayName; +}; + +void ScreenSaver::MessageReceived(BMessage *msg) +{ + switch(msg->what) + { + case TAB1_CHG: + updateStatus(); + BWindow::MessageReceived(msg); + break; + case TAB2_CHG: + updateStatus(); + BWindow::MessageReceived(msg); + break; + case PWBUTTON: + { + updateStatus(); + pwMessenger->SendMessage(SHOW); + BWindow::MessageReceived(msg); + } + break; + case B_QUIT_REQUESTED: + be_app->PostMessage(B_QUIT_REQUESTED); + BWindow::MessageReceived(msg); + break; + case SAVER_SEL: + updateStatus(); + SelectedAddonFileName = reinterpret_cast(AddonList->ItemAt(ListView1->CurrentSelection()))->fileName; + previewDisplay->LoadNewAddon(SelectedAddonFileName.String()); + BWindow::MessageReceived(msg); + break; + default: + BWindow::MessageReceived(msg); + break; + } +} + +void ScreenSaver::loadSettings(BMessage *msg) +{ + BRect frame; + if (B_OK == msg->FindRect("windowframe",&frame)) { + MoveTo(frame.left,frame.top); + ResizeTo(frame.right-frame.left,frame.bottom-frame.top); + } + + int32 value; + msg->FindInt32("windowtab",&value); + tabView->Select(value); + msg->FindInt32("timeflags",&value); + EnableCheckbox->SetValue(value); + msg->FindInt32("timefade",&value); + value=secondsToSlider(value); + if (value>=0) RunSlider->SetValue(value); + msg->FindInt32("timestandby",&value); + value=secondsToSlider(value); + if (value>=0) TurnOffSlider->SetValue(value); + + msg->FindInt32("cornernow",&value); + fadeNow->setDirection(value); + msg->FindInt32("cornernever",&value); + fadeNever->setDirection(value); + + bool enable; + msg->FindBool("lockenable",&enable); + PasswordCheckbox->SetValue(enable); + msg->FindInt32("lockdelay",&value); + value=secondsToSlider(value); + if (value>=0) PasswordSlider->SetValue(value); + + BString name; + msg->FindString("modulename",&name); + const BStringItem **ptr = (const BStringItem **)(ListView1->Items()); + long count=ListView1->CountItems(); + for ( long i = 0; i < count; i++ ) + { + if (name==((*ptr)->Text())) + ListView1->Select(count=i); // Clever bit here - intentional assignment. + else + *ptr++; + } + msg->what=UTILIZE; + pwMessenger->SendMessage(msg); + // Pass to the module for its parameters... +} + +void ScreenSaver::saveSettings(void) +{ + BMessage msg; + msg.AddRect("windowframe",Frame()); + msg.AddInt32("windowtab",tabView->Selection()); + msg.AddInt32("timeflags",EnableCheckbox->Value()); + msg.AddInt32("timefade", timeInSeconds[RunSlider->Value()]); + msg.AddInt32("timestandby", timeInSeconds[TurnOffSlider->Value()]); + msg.AddInt32("timesuspend", timeInSeconds[TurnOffSlider->Value()]); + msg.AddInt32("timeoff", timeInSeconds[TurnOffSlider->Value()]); + msg.AddInt32("cornernow", fadeNow->getDirection()); + msg.AddInt32("cornernever", fadeNever->getDirection()); + msg.AddBool("lockenable",PasswordCheckbox->Value()); + msg.AddInt32("lockdelay", timeInSeconds[PasswordSlider->Value()]); + int selection=ListView1->CurrentSelection(0); + if (selection>=0) + msg.AddString("modulename", ((BStringItem *)(ListView1->ItemAt(selection)))->Text()); + msg.what=POPULATE; + BMessage newMsg; + pwMessenger->SendMessage(&msg,&newMsg); + // Pass this message to the loaded screen saver so that it can add its own preferences + /* > B_MESSAGE_TYPE "modulesettings_SuperString" + > | What=B_OK + > | B_BOOL_TYPE "fade" 1 + > B_STRING_TYPE "modulename" "Lissart" + */ + BPath path; + find_directory(B_USER_SETTINGS_DIRECTORY,&path); + path.Append("OBOS_Screen_Saver",true); + BFile file(path.Path(),B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); + newMsg.Flatten(&file); +} + +bool ScreenSaver::QuitRequested() +{ + updateStatus(); + be_app->PostMessage(B_QUIT_REQUESTED); + return(true); +} + +void ScreenSaver::updateStatus(void) +{ + DisableUpdates(); + PasswordCheckbox->SetEnabled(EnableCheckbox->Value()); + TurnOffScreenCheckBox->SetEnabled(EnableCheckbox->Value()); + RunSlider->SetEnabled(EnableCheckbox->Value()); + TurnOffSlider->SetEnabled(EnableCheckbox->Value() && TurnOffScreenCheckBox->Value()); + TurnOffSlider->SetEnabled(false); + TurnOffScreenCheckBox->SetEnabled(false); + PasswordSlider->SetEnabled(EnableCheckbox->Value() && PasswordCheckbox->Value()); + PasswordButton->SetEnabled(EnableCheckbox->Value() && PasswordCheckbox->Value()); + RunSlider->SetLabel(times[RunSlider->Value()]); + TurnOffSlider->SetLabel(times[TurnOffSlider->Value()]); + PasswordSlider->SetLabel(times[PasswordSlider->Value()]); + EnableUpdates(); + saveSettings(); +}; + +void ScreenSaver::SetupForm(void) +{ + BRect r; + BView *background; + BTab *tab; + r = Bounds(); + + background=new BView(r,"background",B_FOLLOW_NONE,0); + background->SetViewColor(216,216,216,0); + AddChild(background); + + r.InsetBy(0,3); + tabView = new BTabView(r, "tab_view"); + tabView->SetViewColor(216,216,216,0); + r = tabView->Bounds(); + r.InsetBy(0,4); + r.bottom -= tabView->TabHeight(); + + tab = new BTab(); + tabView->AddTab(tab2=new BView(r,"Fade",B_FOLLOW_NONE,0), tab); + tab->SetLabel("Fade"); + + tab = new BTab(); + tabView->AddTab(tab1=new BView(r,"Modules",B_FOLLOW_NONE,0), tab); + tab->SetLabel("Modules"); + background->AddChild(tabView); + setupTab2(); + setupTab1(); + pwWin=new pwWindow; + pwMessenger=new BMessenger (NULL,pwWin); + + //chng 5/31/02 adg + // replace this: + //pwWin->Show(); + //pwWin->Hide(); + // with this: + pwWin->Run(); + //end chng + + // Time to load the settings into a message and implement them... + BPath path; + find_directory(B_USER_SETTINGS_DIRECTORY,&path); + path.Append("OBOS_Screen_Saver",true); + BFile file(path.Path(),B_READ_ONLY); + BMessage msg; + msg.Unflatten(&file); + loadSettings (&msg); + updateStatus(); +} + +void commonLookAndFeel(BView *widget,bool isSlider,bool isControl) + { + {rgb_color clr = {216,216,216,255}; widget->SetViewColor(clr);} + if (isSlider) + { + BSlider *slid=dynamic_cast(widget); + {rgb_color clr = {160,160,160,0}; slid->SetBarColor(clr);} + slid->SetHashMarks(B_HASH_MARKS_NONE); + slid->SetHashMarkCount(0); + slid->SetStyle(B_TRIANGLE_THUMB); + slid->SetLimitLabels("",""); + slid->SetLimitLabels(NULL,NULL); + slid->SetLabel("0 minutes"); + slid->SetValue(0); + slid->SetEnabled(true); + } + {rgb_color clr = {0,0,0,0}; widget->SetHighColor(clr);} + widget->SetFlags(B_WILL_DRAW|B_NAVIGABLE); + widget->SetResizingMode(B_FOLLOW_NONE); + widget->SetFontSize(10); + widget->SetFont(be_plain_font); + if (isControl) + { + BControl *wid=dynamic_cast(widget); + wid->SetEnabled(true); + } + } + +//******* +void addScreenSaversToList (directory_which dir, BList *list) +{ + BPath path; + find_directory(dir,&path); + path.Append("Screen Savers",true); + + const char* pathName = path.Path(); + + BDirectory ssDir(pathName); + BEntry thisSS; + char thisName[B_FILE_NAME_LENGTH]; + + while (B_OK==ssDir.GetNextEntry(&thisSS,true)) + { + thisSS.GetName(thisName); + SSListItem* tempListItem = new SSListItem; + tempListItem->fileName = pathName; + tempListItem->fileName += "/"; + tempListItem->fileName += thisName; + tempListItem->displayName = thisName; + + list->AddItem(tempListItem); + } +} + +// sorting function for SSListItems +int compareSSListItems(const void* left, const void* right) +{ + SSListItem* leftItem = *(SSListItem **)left; + SSListItem* rightItem = *(SSListItem **)right; + + return leftItem->displayName.Compare(rightItem->displayName); +} + +void displayScreenSaversList(BList* list, BListView* view) +{ + list->SortItems(compareSSListItems); + + int numItems = list->CountItems(); + for( int i = 0; i < numItems; ++i ) + { + SSListItem* item = (SSListItem*)(list->ItemAt(i)); + view->AddItem( new BStringItem(item->displayName.String()) ); + } +} + +void ScreenSaver::setupTab1(void) +{ + {rgb_color clr = {216,216,216,255}; tab1->SetViewColor(clr);} + tab1->AddChild( ModuleSettingsBox = new BBox(BRect(columns[2],rows[0],columns[3],rows[5]),"ModuleSettingsBox")); + commonLookAndFeel(ModuleSettingsBox,false,false); + ModuleSettingsBox->SetLabel("Module settings"); + ModuleSettingsBox->SetBorder(B_FANCY_BORDER); + + ListView1 = new BListView(BRect(columns[0],rows[2],columns[1],rows[3]),"ListView1",B_SINGLE_SELECTION_LIST); + tab1->AddChild(new BScrollView("scroll_list",ListView1,B_FOLLOW_NONE,0,false,true)); + commonLookAndFeel(ModuleSettingsBox,false,false); + {rgb_color clr = {255,255,255,0}; ListView1->SetViewColor(clr);} + ListView1->SetListType(B_SINGLE_SELECTION_LIST); + + // selection message for screensaver list + ListView1->SetSelectionMessage( new BMessage( SAVER_SEL ) ); + + tab1->AddChild( TestButton = new BButton(BRect(columns[0],rows[4],94,rows[5]),"TestButton","Test", new BMessage (TAB1_CHG))); + commonLookAndFeel(TestButton,false,true); + TestButton->SetLabel("Test"); + + tab1->AddChild( AddButton = new BButton(BRect(97,rows[4],columns[1],rows[5]),"AddButton","Add...", new BMessage (TAB1_CHG))); + commonLookAndFeel(AddButton,false,true); + AddButton->SetLabel("Add..."); + + tab1->AddChild(previewDisplay = new PreviewView(BRect(columns[0],rows[0],columns[1],rows[1]),"preview")); + // ----------------------------------------------------------------------------------------- + // Populate the listview with the screensavers that exist. + + previewDisplay->SetSettingsBoxPtr( ModuleSettingsBox ); + + AddonList = new BList; + + addScreenSaversToList( B_BEOS_ADDONS_DIRECTORY, AddonList ); + addScreenSaversToList( B_USER_ADDONS_DIRECTORY, AddonList ); + + displayScreenSaversList( AddonList, ListView1 ); +} //end setupTab1() + + +void ScreenSaver::setupTab2(void) +{ + font_height stdFontHt; + be_plain_font->GetHeight(&stdFontHt); + int stringHeight=(int)(stdFontHt.ascent+stdFontHt.descent),sliderHeight=30; + int topEdge; + {rgb_color clr = {216,216,216,255}; tab2->SetViewColor(clr);} + tab2->AddChild( EnableScreenSaverBox = new BBox(BRect(11,13,437,280),"EnableScreenSaverBox")); + commonLookAndFeel(EnableScreenSaverBox,false,false); + + EnableCheckbox = new BCheckBox(BRect(0,0,90,stringHeight),"EnableCheckBox","Enable Screen Saver", new BMessage (TAB2_CHG)); + EnableScreenSaverBox->SetLabel(EnableCheckbox); + EnableScreenSaverBox->SetBorder(B_FANCY_BORDER); + + // Run Module + topEdge=26; + EnableScreenSaverBox->AddChild( StringView1 = new BStringView(BRect(21,topEdge,101,topEdge+stringHeight),"StringView1","Run module")); + commonLookAndFeel(StringView1,false,false); + StringView1->SetText("Run module"); + StringView1->SetAlignment(B_ALIGN_LEFT); + + EnableScreenSaverBox->AddChild( RunSlider = new BSlider(BRect(132,topEdge,415,topEdge+sliderHeight),"RunSlider","minutes", new BMessage(TAB2_CHG), 0, 25)); + RunSlider->SetModificationMessage(new BMessage(TAB2_CHG)); + commonLookAndFeel(RunSlider,true,true); + float w,h; + RunSlider->GetPreferredSize(&w,&h); + sliderHeight=(int)h; + + // Turn Off + topEdge+=sliderHeight; + EnableScreenSaverBox->AddChild( TurnOffScreenCheckBox = new BCheckBox(BRect(9,topEdge,107,topEdge+stringHeight),"TurnOffScreenCheckBox","Turn off screen", new BMessage (TAB2_CHG))); + commonLookAndFeel(TurnOffScreenCheckBox,false,true); + TurnOffScreenCheckBox->SetLabel("Turn off screen"); + TurnOffScreenCheckBox->SetResizingMode(B_FOLLOW_NONE); + + EnableScreenSaverBox->AddChild( TurnOffSlider = new BSlider(BRect(132,topEdge,415,topEdge+sliderHeight),"TurnOffSlider","", new BMessage(TAB2_CHG), 0, 25)); + TurnOffSlider->SetModificationMessage(new BMessage(TAB2_CHG)); + commonLookAndFeel(TurnOffSlider,true,true); + + // Password + topEdge+=sliderHeight; + EnableScreenSaverBox->AddChild( PasswordCheckbox = new BCheckBox(BRect(9,topEdge,108,topEdge+stringHeight),"PasswordCheckbox","Password lock", new BMessage (TAB2_CHG))); + commonLookAndFeel(PasswordCheckbox,false,true); + PasswordCheckbox->SetLabel("Password lock"); + + EnableScreenSaverBox->AddChild( PasswordSlider = new BSlider(BRect(132,topEdge,415,topEdge+sliderHeight),"PasswordSlider","", new BMessage(TAB2_CHG), 0, 25)); + PasswordSlider->SetModificationMessage(new BMessage(TAB2_CHG)); + commonLookAndFeel(PasswordSlider,true,true); + + topEdge+=sliderHeight; + EnableScreenSaverBox->AddChild( PasswordButton = new BButton(BRect(331,topEdge,405,topEdge+25),"PasswordButton","Password...", new BMessage (PWBUTTON))); + commonLookAndFeel(PasswordButton,false,true); + PasswordButton->SetLabel("Password..."); + + // Bottom + + EnableScreenSaverBox->AddChild(fadeNow=new MouseAreaView(BRect(20,205,80,260),"fadeNow")); + EnableScreenSaverBox->AddChild(fadeNever=new MouseAreaView(BRect(220,205,280,260),"fadeNever")); + + EnableScreenSaverBox->AddChild( FadeNowString = new BStringView(BRect(85,210,188,222),"FadeNowString","Fade now when")); + commonLookAndFeel(FadeNowString,false,false); + FadeNowString->SetText("Fade now when"); + FadeNowString->SetAlignment(B_ALIGN_LEFT); + + EnableScreenSaverBox->AddChild( FadeNowString2 = new BStringView(BRect(85,225,188,237),"FadeNowString2","mouse is here")); + commonLookAndFeel(FadeNowString2,false,false); + FadeNowString2->SetText("mouse is here"); + FadeNowString2->SetAlignment(B_ALIGN_LEFT); + + EnableScreenSaverBox->AddChild( DontFadeString = new BStringView(BRect(285,210,382,222),"DontFadeString","Don't fade when")); + commonLookAndFeel(DontFadeString,false,false); + DontFadeString->SetText("Don't fade when"); + DontFadeString->SetAlignment(B_ALIGN_LEFT); + + EnableScreenSaverBox->AddChild( DontFadeString2 = new BStringView(BRect(285,225,382,237),"DontFadeString2","mouse is here")); + commonLookAndFeel(DontFadeString2,false,false); + DontFadeString2->SetText("mouse is here"); + DontFadeString2->SetAlignment(B_ALIGN_LEFT); +} + diff --git a/src/prefs/screensaver/ScreenSaver.h b/src/prefs/screensaver/ScreenSaver.h new file mode 100644 index 0000000000..13de83d901 --- /dev/null +++ b/src/prefs/screensaver/ScreenSaver.h @@ -0,0 +1,68 @@ +#ifndef _ScreenSaver_H +#define _ScreenSaver_H +#include +#include "Constants.h" +#include "pwWindow.h" + +class MouseAreaView; +class PreviewView; + +class ScreenSaver: public BWindow { +public: + ScreenSaver(void) : BWindow(BRect(50,50,500,385),"OBOS Screen Saver Preferences",B_TITLED_WINDOW,B_ASYNCHRONOUS_CONTROLS | B_NOT_ZOOMABLE | B_NOT_RESIZABLE) + { + pwWin=NULL; + sampleView=NULL; + SetupForm(); + } + virtual void MessageReceived(BMessage *message); + virtual bool QuitRequested(void); + virtual ~ScreenSaver(void) {}; + +private: + void SetupForm(void); + void setupTab1(void); + void setupTab2(void); + void updateStatus(void); + void loadSettings(BMessage *msg); + void saveSettings(void); + + int fadeState,noFadeState; + BView *sampleView; + + BView *tab1,*tab2; + BTabView *tabView; + BBox *ModuleSettingsBox; + + PreviewView *previewDisplay; + BListView *ListView1; + BList *AddonList; + BString SelectedAddonFileName; + image_id currentAddon; + + BButton *TestButton; + BButton *AddButton; + BBox *EnableScreenSaverBox; + BSlider *PasswordSlider; + BSlider *TurnOffSlider; + BSlider *RunSlider; + BStringView *StringView1; + BCheckBox *EnableCheckbox; + BCheckBox *PasswordCheckbox; + BCheckBox *TurnOffScreenCheckBox; + BStringView *TurnOffMinutes; + BStringView *RunMinutes; + BStringView *PasswordMinutes; + BButton *PasswordButton; + BStringView *FadeNowString; + BStringView *FadeNowString2; + BStringView *DontFadeString; + BStringView *DontFadeString2; + BPicture samplePicture; + MouseAreaView *fadeNow,*fadeNever; + pwWindow *pwWin; + BMessenger *pwMessenger; + +}; + +#endif // _ScreenSaver_H diff --git a/src/prefs/screensaver/pwWindow.cpp b/src/prefs/screensaver/pwWindow.cpp new file mode 100644 index 0000000000..a40cb99c0a --- /dev/null +++ b/src/prefs/screensaver/pwWindow.cpp @@ -0,0 +1,100 @@ +#include "pwWindow.h" +#include +#include "RadioButton.h" +#include "Alert.h" + +void pwWindow::setup(void) +{ + BView *owner=new BView(Bounds(),"ownerView",B_FOLLOW_NONE,B_WILL_DRAW); + owner->SetViewColor(216,216,216); + AddChild(owner); + useNetwork=new BRadioButton(BRect(15,10,160,20),"useNetwork","Use Network password",new BMessage(BUTTON_CHANGED),B_FOLLOW_NONE); + useNetwork->SetValue(1); + owner->AddChild(useNetwork); + useCustom=new BRadioButton(BRect(30,50,130,60),"useCustom","Use custom password",new BMessage(BUTTON_CHANGED),B_FOLLOW_NONE); + + customBox=new BBox(BRect(10,30,270,105),"custBeBox",B_FOLLOW_NONE); + customBox->SetLabel(useCustom); + password=new BTextControl(BRect(10,20,250,35),"pwdCntrl","Password:",NULL,B_FOLLOW_NONE); + confirm=new BTextControl(BRect(10,45,250,60),"confirmCntrl","Confirm password:",NULL,B_FOLLOW_NONE); + password->SetAlignment(B_ALIGN_RIGHT,B_ALIGN_LEFT); + password->SetDivider(90); + password->TextView()->HideTyping(true); + confirm->SetAlignment(B_ALIGN_RIGHT,B_ALIGN_LEFT); + confirm->SetDivider(90); + confirm->TextView()->HideTyping(true); + customBox->AddChild(password); + customBox->AddChild(confirm); + owner->AddChild(customBox); + + done=new BButton(BRect(200,120,275,130),"done","Done",new BMessage (DONE_CLICKED),B_FOLLOW_NONE); + cancel=new BButton(BRect(115,120,190,130),"cancel","Cancel",new BMessage (CANCEL_CLICKED),B_FOLLOW_NONE); + owner->AddChild(done); + owner->AddChild(cancel); + done->MakeDefault(true); + update(); +} + +void pwWindow::update(void) +{ + useNetPassword=(useCustom->Value()>0); + confirm->SetEnabled(useNetPassword); + password->SetEnabled(useNetPassword); +} + +void pwWindow::MessageReceived(BMessage *message) +{ + switch(message->what) + { + case DONE_CLICKED: + if (useCustom->Value()) + if (strcmp(password->Text(),confirm->Text())) + { + BAlert *alert=new BAlert("noMatch","Passwords don't match. Try again.","OK"); + alert->Go(); + } + else + { + thePassword=password->Text(); + Hide(); + } + else + { + password->SetText(""); + confirm->SetText(""); + Hide(); + } + break; + case CANCEL_CLICKED: + password->SetText(""); + confirm->SetText(""); + Hide(); + break; + case BUTTON_CHANGED: + update(); + break; + case SHOW: + Show(); + break; + case POPULATE: + message->ReplaceString("lockpassword", ((useNetPassword)?"":thePassword)); + message->ReplaceString("lockmethod", (useNetPassword?"network":"custom")); + message->SendReply(message); + break; + case UTILIZE: + { + BString temp; + message->FindString("lockmethod",&temp); + useNetPassword=(temp=="custom"); + if (!useNetPassword) + { + message->FindString("lockpassword",&temp); + thePassword=temp; + } + break; + } + default: + BWindow::MessageReceived(message); + break; + } +} diff --git a/src/prefs/screensaver/pwWindow.h b/src/prefs/screensaver/pwWindow.h new file mode 100644 index 0000000000..41236dc2b2 --- /dev/null +++ b/src/prefs/screensaver/pwWindow.h @@ -0,0 +1,26 @@ +#include "Window.h" +#include "CheckBox.h" +#include "String.h" +#include "Box.h" +#include "TextControl.h" +#include "Button.h" +#include "Constants.h" + +class pwWindow : public BWindow +{ + public: + pwWindow (void) : BWindow(BRect(100,100,380,250),"",B_MODAL_WINDOW_LOOK,B_MODAL_APP_WINDOW_FEEL,B_NOT_RESIZABLE) {setup();} + void setup(void); + void update(void); + virtual void MessageReceived(BMessage *message); + + private: + BRadioButton *useNetwork,*useCustom; + BBox *customBox; + BTextControl *password,*confirm; + BButton *cancel,*done; + BString thePassword; + bool useNetPassword; + +}; + diff --git a/src/prefs/translation/Common.h b/src/prefs/translation/Common.h new file mode 100644 index 0000000000..b35e8c741e --- /dev/null +++ b/src/prefs/translation/Common.h @@ -0,0 +1,6 @@ +#ifndef COMMON_H +#define COMMON_H + +#define DRAG_TO_TRACKER 'drat' + +#endif \ No newline at end of file diff --git a/src/prefs/translation/DataTranslations.FileTypes.rsrc b/src/prefs/translation/DataTranslations.FileTypes.rsrc new file mode 100644 index 0000000000..404d932ff6 Binary files /dev/null and b/src/prefs/translation/DataTranslations.FileTypes.rsrc differ diff --git a/src/prefs/translation/LView.cpp b/src/prefs/translation/LView.cpp new file mode 100644 index 0000000000..2963324ab8 --- /dev/null +++ b/src/prefs/translation/LView.cpp @@ -0,0 +1,42 @@ +#include "LView.h" +#include "Common.h" + +#ifndef _APPLICATION_H +#include +#endif + +LView::LView(BRect rect, const char *name, list_view_type type = B_SINGLE_SELECTION_LIST) : + BListView(rect, name, B_SINGLE_SELECTION_LIST) { + + message_from_tracker = NULL; + messagerunner = NULL; + SetViewColor(217,217,217); +} + + + +void LView::MessageReceived(BMessage *message) { + + uint32 type; + int32 count; + + switch (message->what) { + case B_SIMPLE_DATA: + message->GetInfo("refs", &type, &count); + if ( count>0 && type == B_REF_TYPE ) + { + message->what = B_REFS_RECEIVED; + be_app->PostMessage(message); + } + break; + default: + BView::MessageReceived(message); + break; + } +} + + +LView::~LView() +{ + if (messagerunner != NULL) delete messagerunner; +} \ No newline at end of file diff --git a/src/prefs/translation/LView.h b/src/prefs/translation/LView.h new file mode 100644 index 0000000000..c4f9694384 --- /dev/null +++ b/src/prefs/translation/LView.h @@ -0,0 +1,26 @@ +#ifndef LVIEW_H +#define LVIEW_H + +#include +#include +#include + +#include "Common.h" + +class LView : public BListView { + public: + LView(BRect rect, + const char *name, list_view_type type = B_SINGLE_SELECTION_LIST ); + + ~LView(); + void MessageReceived(BMessage *message); + + + private: + + const BMessage *message_from_tracker; + + BMessageRunner *messagerunner; +}; + +#endif diff --git a/src/prefs/translation/datatrans.cpp b/src/prefs/translation/datatrans.cpp new file mode 100644 index 0000000000..d60d430331 --- /dev/null +++ b/src/prefs/translation/datatrans.cpp @@ -0,0 +1,159 @@ +/** + * DataTranslations2 + * + * This is to become the OBOS-replacement for the original BeOS + * DataTranslations Preferences App. This App is not doing a lot, + * basically it just shows all installed Translators, and helps you + * installing new ones. (Drag em on the ListBox; Drop; done) + * + */ + +#include + +#include + + +#ifndef _APPLICATION_H +#include +#endif + +#ifndef DATATRANS_H +#include "datatrans.h" +#endif + +#ifndef TRANS_WIN_H +#include "transwin.h" +#endif + +int main(int, char**) +{ + DATApp myApplication; + + myApplication.Run(); + + return(0); +} + +DATApp::DATApp():BApplication("application/x-vnd.Be-prefs-translations2") +{ + DATWindow *aWindow; + BRect aRect; + + // set up a rectangle and instantiate a new window + aRect.Set(40, 40, 440, 340); + aWindow = new DATWindow(aRect); + + + // make window visible + aWindow->Show(); + +} + +void DATApp :: RefsReceived(BMessage *message) +{ + + uint32 type; + int32 count; + entry_ref ref; + BPath path; + BString newfile; + + char e_name[B_FILE_NAME_LENGTH]; + char mbuf[256]; + + + message->GetInfo("refs", &type, &count); + if ( type != B_REF_TYPE ) return; + + + if ( message->FindRef("refs", &ref) == B_OK ) + { + BEntry entry(&ref, true); + if ( entry.IsFile() && entry.GetPath(&path)==B_OK) + { + entry.GetName(e_name); + BNode node (&entry); + BNodeInfo info (&node); + info.GetType (mbuf); + string.SetTo(mbuf); + + if (string.FindFirst("application/x-vnd.Be-elfexecutable") != B_ERROR ) + { + BDirectory dirt("/boot/home/config/add-ons/Translators/"); + newfile.SetTo("/boot/home/config/add-ons/Translators/"); + newfile << e_name; // Newfile with full path. + + // Find out wether we need to copy it + string.SetTo(""); + string << "The item '" << e_name << "' is now copied into the right place.\nWhat do you want to do with the original?"; + BAlert *keep = new BAlert("keep", string.String() , "Remove", "Keep"); + keep->SetShortcut(1, B_ESCAPE); + + if (keep->Go() == 0) // Just a quick move + { + if (dirt.Contains(newfile.String())) + { + string.SetTo(""); + string << "An item named '" << e_name <<"' already is in the \nTranslators folder"; + BAlert *myAlert = new BAlert("title", string.String() , "Overwrite", "Stop"); + myAlert->SetShortcut(1, B_ESCAPE); + + if (myAlert->Go() != 0) + return; + // File exists, we are still here. Kill it. + BEntry dele; + dirt.FindEntry(e_name, &dele); + dele.Remove(); + } + entry.MoveTo(&dirt); + (new BAlert("", "You have to quit and restart running applications\nfor the installed Translators to be available in them.", "OK"))->Go(); + return; + } + + if (dirt.Contains(newfile.String())) + { + // File exists, What are we supposed to do now (Overwrite/_Stopp_?) + string.SetTo(""); + string << "An item named '" << e_name <<"' already is in the \nTranslators folder"; + BAlert *myAlert = new BAlert("title", string.String() , "Overwrite", "Stop"); + myAlert->SetShortcut(1, B_ESCAPE); + + if (myAlert->Go() != 0) + return; + } + + string.SetTo(path.Path()); // Fullpath+Filename + + BString + command = "copyattr -d -r "; + command << string.String() << " " << newfile.String(); // Prepare Copy + + system(command.String()); // Execute copy command + + string.SetTo(""); + string << "Filename: " << e_name << "\nPath: " << path.Path() ; + + // The new Translator has been installed by now. + (new BAlert("", "You have to quit and restart running applications\nfor the installed Translators to be available in them.", "OK"))->Go(); + // And done we are + return; + } + else + { + // Not a Translator + entry.GetName(e_name); + string.SetTo(""); + string << "The item '" << e_name << "' does not appear to be a Translator and will not be installed"; + (new BAlert("", string.String(), "Stop"))->Go(); + } + } + else + { + // Not even a file... + entry.GetName(e_name); + string.SetTo(""); + string << "The item '" << e_name << "' does not appear to be a Translator and will not be installed"; + (new BAlert("", string.String(), "Stop"))->Go(); + } + } +} diff --git a/src/prefs/translation/datatrans.h b/src/prefs/translation/datatrans.h new file mode 100644 index 0000000000..d8f40f2fa5 --- /dev/null +++ b/src/prefs/translation/datatrans.h @@ -0,0 +1,35 @@ +/* + + datatrans.h + +*/ + +#ifndef DATATRANS_H //DATATRANS_H + +#define DATATRANS_H + +#ifndef _APPLICATION_H +#include +#endif + +#ifndef LVIEW_H +#include "LView.h" +#endif + +#include + +class DATApp : public BApplication +{ +public: + DATApp(); + + virtual void RefsReceived(BMessage *message); + + +private: + + BString string; + +}; + +#endif //DATATRANS_H \ No newline at end of file diff --git a/src/prefs/translation/transwin.cpp b/src/prefs/translation/transwin.cpp new file mode 100644 index 0000000000..0956f3b000 --- /dev/null +++ b/src/prefs/translation/transwin.cpp @@ -0,0 +1,244 @@ +/* + + transwin.cpp + +*/ + +#ifndef _APPLICATION_H +#include +#endif +#ifndef TRANS_WIN_H +#include "transwin.h" +#endif + +#include + + + +DATWindow::DATWindow(BRect frame) + : BWindow(frame, "Data Translations2", B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE ) +{ + newIcon = false; + + BRect r( 300, 250, 380, 270 ); // Pos: Info-Button + BRect all( 0, 0, 400, 300); // Fenster-Groesse + BRect cv( 150, 13, 387, 245); // ConfigView & hosting Box + BRect mau( 146, 8, 390, 290); // Grenz-Box around ConfView + BRect DTN_pos( 195 , 245, 298 , 265); // Pos: Dateiname + BRect ic ( 156 , 245, 188 , 277); // Pos: TrackerIcon + + Konf = new BView(cv, "KONF", B_NOT_RESIZABLE, B_WILL_DRAW ); + // Konf->SetViewColor(217,217,217); + + rBox = new BBox(cv, "Right_Side"); + gBox = new BBox(mau, "Grau"); + + Icon = new BView(ic, "Ikon", B_NOT_RESIZABLE, B_WILL_DRAW | B_PULSE_NEEDED); + + Icon->SetDrawingMode(B_OP_OVER); + Icon->SetViewColor(217,217,217); + Icon->SetHighColor(217,217,217); + Icon_bit = new BBitmap(BRect(0, 0, 31, 31), B_CMAP8, true, false); + + dButton = new BButton(r, "STD", "Info. . .", new BMessage(BUTTON_MSG)); + + fBox = new BBox(all, "All_Window", B_FOLLOW_ALL_SIDES, + B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP, + B_PLAIN_BORDER); + + r.Set( 10, 10, 120, 288); // List View + + liste = new LView(r, "Transen", B_SINGLE_SELECTION_LIST); + liste->SetSelectionMessage(new BMessage(SEL_CHANGE)); + + DTN = new BStringView(DTN_pos, "DataName", "Test", B_NOT_RESIZABLE); + DTN->SetViewColor(217,217,217); + + // Here we add the names of all installed translators + WriteTrans(); + + // Setting up the Box around my LView + r.Set( 8, 8, 123, 288); // Box around the List + lBox = new BBox(r, "List-Box"); + lBox->SetBorder(B_NO_BORDER); + lBox->SetViewColor(255,255,255); + + // Put list into a BScrollView, to get that nice srcollbar + tListe = new BScrollView("scroll_trans", liste, B_FOLLOW_LEFT | B_FOLLOW_TOP, 0, false, true, B_FANCY_BORDER); + + + rBox->SetBorder(B_NO_BORDER); + rBox->AddChild(Konf); + rBox->SetFlags(B_NAVIGABLE_JUMP); + + // Attach Views to my Window + AddChild(dButton); + AddChild(tListe); + AddChild(rBox); + + AddChild(fBox); + AddChild(Icon); + AddChild(DTN); + AddChild(lBox); + AddChild(gBox); + + // Set the focus + liste->MakeFocus(); + + // Select the first Translator in list + liste->Select(0, false); + showInfo = true; + +} + + +bool DATWindow::QuitRequested() +{ + be_app->PostMessage(B_QUIT_REQUESTED); + return(true); +} + +// Reads the installed translators and adds them to our BListView +int DATWindow::WriteTrans() +{ + BTranslatorRoster *roster = BTranslatorRoster::Default(); + + int32 num_translators, i; + translator_id *translators; + const char *tname, *tinfo; + + int32 tversion; + + // Get all Translators on the system. Gives us the number of translators + // installed in num_translators and a reference to the first one, so + // we can use translators like any normal array + + roster->GetAllTranslators(&translators, &num_translators); + + for (i=0;iGetTranslatorInfo(translators[i], &tname,&tinfo, &tversion); + liste->AddItem(new BStringItem(tname)); + } + + delete [] translators; // clean up our droppings + + return 0; +} + + +// Finds a specific translator by it´s id +void DATWindow::Trans_by_ID(int32 id) +{ + BTranslatorRoster *roster = BTranslatorRoster::Default(); + + int32 num_translators; + translator_id *translators; + // const char *translator_name, *translator_info; + + + roster->GetAllTranslators(&translators, &num_translators); + + // Getting the first three Infos: Name, Info & Version + roster->GetTranslatorInfo(translators[id], &translator_name,&translator_info, &translator_version); + roster->Archive(&archiv, true); + + rBox->RemoveChild(Konf); + if (roster->MakeConfigurationView( translators[id], new BMessage() , &Konf, new BRect( 0, 0, 200, 233)) != B_OK ) + { + BString text; + text << "The translator '" << translator_name << "' has no settings"; + Konf = new BStringView(BRect(0, 0, 200, 233), "no_settings", text.String()); + }; + + // ( 171, 11, 391, 284) + Konf->SetViewColor(217,217,217); + Konf->ResizeTo(230, 233); + Konf->SetFlags(B_WILL_DRAW | B_NAVIGABLE); + rBox->AddChild(Konf); + + UpdateIfNeeded(); // Fixes that one Icon problem + + delete [] translators; // clean up our droppings +} + +void DATWindow::DrawIcon() +{ + if (newIcon) + { + entry.SetTo(pfad); + node.SetTo(&entry); + info.SetTo(&node); + Icon->FillRect(BRect(0, 0, 31, 31)); + newIcon = false; + } + if (info.GetTrackerIcon(Icon_bit) != B_OK) QuitRequested(); + Icon->DrawBitmap(Icon_bit); +} + +void DATWindow::WindowActivated(bool state) +{ + if (showInfo) DrawIcon(); +} + +void DATWindow::FrameMoved(BPoint origin) +{ + if (showInfo) DrawIcon(); +} + +void DATWindow::MessageReceived(BMessage* message) +{ + int32 selected; + + switch(message->what) + { + case BUTTON_MSG: + selected=liste->CurrentSelection(0); + + // Should we show translator info? + if (!showInfo) + { + // No => Show standard box + (new BAlert("yo!", "Translation Settings\n\nUse this control panel to set values that various\ntranslators use when no other settings are specified\nin the application.", "OK"))->Go(); + break; + } + // Yes => Show Translator info. + Trans_by_ID(selected); + archiv.FindString("be:translator_path", selected, &pfad); + tex.SetTo(""); + tex << "Name: " << translator_name << "\nVersion: " << (int32)translator_version << "\nInfo: " << translator_info << "\nPath: " << pfad << "\n"; + (new BAlert("yo!", tex.String(), "OK"))->Go(); + tex.SetTo(""); + DrawIcon(); + break; + + case SEL_CHANGE: + // Now we have to update Filename and Icon + // First we find the selected Translator + selected=liste->CurrentSelection(0); + + // If none selected, clear the old one + if (selected < 0) + { + Icon->FillRect(BRect(0, 0, 31, 31)); + DTN->SetText(""); + showInfo = false; + rBox->RemoveChild(Konf); + break; + } + + newIcon = true; + showInfo = true; + Trans_by_ID(selected); + // Now we find the path, and update filename + archiv.FindString("be:translator_path", selected, &pfad); + tex.SetTo(pfad); + tex.Remove(0,tex.FindLast("/")+1); + DTN->SetText(tex.String()); + DrawIcon(); + break; + + default: + BWindow::MessageReceived(message); + } +} diff --git a/src/prefs/translation/transwin.h b/src/prefs/translation/transwin.h new file mode 100644 index 0000000000..b431873c50 --- /dev/null +++ b/src/prefs/translation/transwin.h @@ -0,0 +1,87 @@ +/* + + transwin.h + +*/ + +#ifndef TRANS_WIN_H +#define TRANS_WIN_H + +#ifndef _WINDOW_H +#include +#endif + +#ifndef LVIEW_H +#include "LView.h" +#endif + +#define BUTTON_MSG 'PRES' +const uint32 SEL_CHANGE = 'SEch'; + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +class DATWindow : public BWindow +{ +public: + DATWindow(BRect frame); +virtual bool QuitRequested(); +virtual void MessageReceived(BMessage* message); +virtual void WindowActivated(bool state); +virtual void FrameMoved(BPoint origin); + + void DrawIcon(); + +private: + const char *translator_name, *translator_info; + int32 translator_version; + const char* pfad; + BString tex; + bool showInfo; + bool newIcon; + + BButton* dButton; // Default-Button + BBox* fBox; // Full-Window Box + BScrollView* tListe; // To get that fancy scrollbar + BBox* lBox; // Box around list + BBox* rBox; // Box hosting Config View + BBox* gBox; // Box around Config View, funny border + + // BListView* list; // My lovely List of Translators no longer needed + + LView* liste; // Improved list of Translators + + BStringView* DTN; // Display the DataTranslatorName + BMessage archiv; // My Message + BView* Icon; // The Icon and Config - Views + BBitmap* Icon_bit; + BView* Konf; + + + BEntry entry; + BNode node; + BNodeInfo info; + + void GetDrop(BMessage *message); + void Trans_by_ID(int32 id); + int WriteTrans(); + +}; + +#endif //TRANS_WIN_H \ No newline at end of file diff --git a/src/prefs/virtualmemory/.doxygen-conf b/src/prefs/virtualmemory/.doxygen-conf new file mode 100644 index 0000000000..7e19f07950 --- /dev/null +++ b/src/prefs/virtualmemory/.doxygen-conf @@ -0,0 +1,691 @@ +# Doxyfile 1.2.1 + +# This file describes the settings to be used by doxygen for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = "Virtual Memory Preferences App" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 1 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Dutch, French, Italian, Czech, Swedish, German, Finnish, Japanese, +# Spanish, Russian, Croatian, Polish, and Portuguese. + +OUTPUT_LANGUAGE = English + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these class will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. It is allowed to use relative paths in the argument list. + +STRIP_FROM_PATH = + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a class diagram (in Html and LaTeX) for classes with base or +# super classes. Setting the tag to NO turns the diagrams off. + +CLASS_DIAGRAMS = YES + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the CASE_SENSE_NAMES tag is set to NO (the default) then Doxygen +# will only generate file names in lower case letters. If set to +# YES upper case letters are also allowed. This is useful if you have +# classes or files whose names only differ in case and if your file system +# supports case sensitive file names. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the JAVADOC_AUTOBRIEF tag is set to YES (the default) then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the Javadoc-style will +# behave just like the Qt-style comments. + +JAVADOC_AUTOBRIEF = YES + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# reimplements. + +INHERIT_DOCS = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# The ENABLE_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. + +WARN_FORMAT = "$file:$line: $text" + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = . + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +FILE_PATTERNS = *.cpp *.h + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. + +EXCLUDE_PATTERNS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. + +INPUT_FILTER = + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = docs + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimised for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using a WORD or other. +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assigments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. Warning: This feature +# is still experimental and very incomplete. + +GENERATE_XML = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_PREDEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +#--------------------------------------------------------------------------- +# Configuration::addtions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tagfiles. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the ENABLE_PREPROCESSING, INCLUDE_GRAPH, and HAVE_DOT tags are set to +# YES then doxygen will generate a graph for each documented file showing +# the direct and indirect include dependencies of the file with other +# documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, INCLUDED_BY_GRAPH, and HAVE_DOT tags are set to +# YES then doxygen will generate a graph for each documented header file showing +# the documented files that directly or indirectly include this file + +INCLUDED_BY_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found on the path. + +DOT_PATH = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO + +# The CGI_NAME tag should be the name of the CGI script that +# starts the search engine (doxysearch) with the correct parameters. +# A script with this name will be generated by doxygen. + +CGI_NAME = search.cgi + +# The CGI_URL tag should be the absolute URL to the directory where the +# cgi binaries are located. See the documentation of your http daemon for +# details. + +CGI_URL = + +# The DOC_URL tag should be the absolute URL to the directory where the +# documentation is located. If left blank the absolute path to the +# documentation, with file:// prepended to it, will be used. + +DOC_URL = + +# The DOC_ABSPATH tag should be the absolute path to the directory where the +# documentation is located. If left blank the directory on the local machine +# will be used. + +DOC_ABSPATH = + +# The BIN_ABSPATH tag must point to the directory where the doxysearch binary +# is installed. + +BIN_ABSPATH = /usr/local/bin/ + +# The EXT_DOC_PATHS tag can be used to specify one or more paths to +# documentation generated for other projects. This allows doxysearch to search +# the documentation for these projects as well. + +EXT_DOC_PATHS = diff --git a/src/prefs/virtualmemory/MainWindow.cpp b/src/prefs/virtualmemory/MainWindow.cpp new file mode 100644 index 0000000000..2fcc9d28dc --- /dev/null +++ b/src/prefs/virtualmemory/MainWindow.cpp @@ -0,0 +1,263 @@ +/*! \file MainWindow.cpp + * \brief Code for the MainWindow class. + * + * Displays the main window, the essence of the app. + * +*/ + +#include "MainWindow.h" + +/** + * Constructor. + * @param frame The size to make the window. + * @param physMem The amount of physical memory in the machine. + * @param currSwp The current swap file size. + * @param minVal The minimum value of the swap file. + * @param maxSwapVal The maximum value of the swap file. + */ +MainWindow::MainWindow(BRect frame, int physMemVal, int currSwapVal, int minVal, int maxSwapVal, VMSettings *Settings) + :BWindow(frame, "Virtual Memory", B_TITLED_WINDOW, B_NOT_RESIZABLE | B_ASYNCHRONOUS_CONTROLS | B_NOT_ZOOMABLE){ + + BStringView *physMem; + BStringView *currSwap; + BButton *defaultButton; + BBox *topLevelView; + BBox *boxView; + + fSettings = Settings; + + /** + * Sets the fill color for the "used" portion of the slider. + */ + rgb_color fillColor; + fillColor.red = 0; + fillColor.blue = 152; + fillColor.green = 102; + + /** + * This var sets the size of the visible box around the string views and + * the slider. + */ + BRect boxRect=Bounds(); + boxRect.left=boxRect.left+10; + boxRect.top=boxRect.top+10; + boxRect.bottom=boxRect.bottom-45; + boxRect.right=boxRect.right-10; + char labels[50]; + char sliderMinLabel[10]; + char sliderMaxLabel[10]; + + origMemSize = currSwapVal; + minSwapVal = minVal; + + /** + * Set up the "Physical Memory" label. + */ + sprintf(labels, "Physical Memory: %d MB", physMemVal); + physMem = new BStringView(*(new BRect(10, 10, 210, 20)), "PhysicalMemory", labels, B_FOLLOW_ALL, B_WILL_DRAW); + + /** + * Set up the "Current Swap File Size" label. + */ + sprintf(labels, "Current Swap File Size: %d MB", currSwapVal); + currSwap = new BStringView(*(new BRect(10, 25, 210, 35)), "CurrentSwapSize", labels, B_FOLLOW_ALL, B_WILL_DRAW); + + /** + * Set up the "Requested Swap File Size" label. + */ + sprintf(labels, "Requested Swap File Size: %d MB", currSwapVal); + reqSwap = new BStringView(*(new BRect(10, 40, 210, 50)), "RequestedSwapSize", labels, B_FOLLOW_ALL, B_WILL_DRAW); + + /** + * Set up the slider. + */ + sprintf(sliderMinLabel, "%d MB", minSwapVal); + sprintf(sliderMaxLabel, "%d MB", maxSwapVal); + reqSizeSlider = new BSlider(*(new BRect(10, 51, 240, 75)), "ReqSwapSizeSlider", "", new BMessage(MEMORY_SLIDER_MSG), minSwapVal, maxSwapVal, B_TRIANGLE_THUMB, B_FOLLOW_LEFT, B_WILL_DRAW); + reqSizeSlider->SetLimitLabels(sliderMinLabel, sliderMaxLabel); + reqSizeSlider->UseFillColor(TRUE, &fillColor); + reqSizeSlider->SetModificationMessage(new BMessage(SLIDER_UPDATE_MSG)); + + reqSizeSlider->SetValue(currSwapVal); + + /** + * Initializes the restart notice view. + */ + restart = new BStringView(*(new BRect(40, 100, 210, 110)), "RestartMessage", "", B_FOLLOW_ALL, B_WILL_DRAW); + + /** + * This view holds the three labels and the slider. + */ + boxView = new BBox(boxRect, "BoxView", B_FOLLOW_ALL, B_WILL_DRAW, B_FANCY_BORDER); + boxView->AddChild(reqSizeSlider); + boxView->AddChild(physMem); + boxView->AddChild(currSwap); + boxView->AddChild(reqSwap); + boxView->AddChild(restart); + + defaultButton = new BButton(*(new BRect(10, 138, 85, 158)), "DefaultButton", "Default", new BMessage(DEFAULT_BUTTON_MSG), B_FOLLOW_ALL, B_WILL_DRAW); + revertButton = new BButton(*(new BRect(95, 138, 170, 158)), "RevertButton", "Revert", new BMessage(REVERT_BUTTON_MSG), B_FOLLOW_ALL, B_WILL_DRAW); + revertButton->SetEnabled(false); + + topLevelView = new BBox(Bounds(), "TopLevelView", B_FOLLOW_ALL, B_WILL_DRAW, B_NO_BORDER); + topLevelView->AddChild(boxView); + topLevelView->AddChild(defaultButton); + topLevelView->AddChild(revertButton); + + AddChild(topLevelView); + +} + +/** + * Displays the "Changes will take effect on restart" message. + * @param setTo If true, displays the message If false, un-displays it. + */ +void MainWindow::toggleChangedMessage(bool setTo){ + + char msg[100]; + if(setTo){ + + revertButton->SetEnabled(true); + sprintf(msg, "Changes will take effect on restart."); + restart->SetText(msg); + + }//if + else{ + + restart->SetText(""); + + }//else + +}//toggleChangedMessage + +/** + * Handles messages. + * @param message The message recieved by the window. + */ +void MainWindow::MessageReceived(BMessage *message){ + + char msg[100]; + + switch(message->what){ + + int currVal; + + /** + * Updates the requested swap file size during a drag. + */ + case SLIDER_UPDATE_MSG: + + currVal = int(reqSizeSlider->Value()); + sprintf(msg, "Requested Swap File Size: %d MB", currVal); + reqSwap->SetText(msg); + + if(currVal != origMemSize){ + + toggleChangedMessage(true); + + }//if + else{ + + revertButton->SetEnabled(false); + toggleChangedMessage(false); + + }//else + + break; + + /** + * Case where the slider was moved. + * Resets the "Requested Swap File Size" label to the new value. + */ + case MEMORY_SLIDER_MSG: + + currVal = int(reqSizeSlider->Value()); + sprintf(msg, "Requested Swap File Size: %d MB", currVal); + reqSwap->SetText(msg); + + if(currVal != origMemSize){ + + toggleChangedMessage(true); + + }//if + else{ + + revertButton->SetEnabled(false); + toggleChangedMessage(false); + + }//else + + break; + + /** + * Case where the default button was pressed. + * Eventually will set the swap file size to the optimum size, + * as decided by this app (as soon as I can figure out how to + * do that). + */ + case DEFAULT_BUTTON_MSG: + + reqSizeSlider->SetValue(minSwapVal); + sprintf(msg, "Requested Swap File Size: %d MB", minSwapVal); + reqSwap->SetText(msg); + if(minSwapVal != origMemSize){ + + toggleChangedMessage(true); + + }//if + else{ + + revertButton->SetEnabled(false); + toggleChangedMessage(false); + + }//else + break; + + /** + * Case where the revert button was pressed. + * Returns things to the way they were when the app was started, + * which is not necessarily the default size. + */ + case REVERT_BUTTON_MSG: + + revertButton->SetEnabled(false); + sprintf(msg, "Requested Swap File Size: %d MB", origMemSize); + reqSwap->SetText(msg); + reqSizeSlider->SetValue(origMemSize); + toggleChangedMessage(false); + break; + + /** + * Unhandled messages get passed to BWindow. + */ + default: + + BWindow::MessageReceived(message); + + } + +} + +/** + * Quits and Saves. + * Sets the swap size and turns the virtual memory on by writing to the + * /boot/home/config/settings/kernel/drivers/virtual_memory file. + */ +bool MainWindow::QuitRequested(){ + + FILE *settingsFile = + fopen("/boot/home/config/settings/kernel/drivers/virtual_memory", "w"); + fprintf(settingsFile, "vm on\n"); + fprintf(settingsFile, "swap_size %d\n", (int(reqSizeSlider->Value()) * 1048576)); + fclose(settingsFile); + + be_app->PostMessage(B_QUIT_REQUESTED); + return(true); + +} + +void MainWindow::FrameMoved(BPoint origin) +{//MainWindow::FrameMoved + fSettings->SetWindowPosition(Frame()); +}//MainWindow::FrameMoved + diff --git a/src/prefs/virtualmemory/MainWindow.h b/src/prefs/virtualmemory/MainWindow.h new file mode 100644 index 0000000000..5ceb13622b --- /dev/null +++ b/src/prefs/virtualmemory/MainWindow.h @@ -0,0 +1,127 @@ +/*! \file MainWindow.h + \brief Header for the MainWindow class. + +*/ + +#ifndef MAIN_WINDOW_H + + + #define MAIN_WINDOW_H + + /*! + * Default button message. + */ + #define DEFAULT_BUTTON_MSG 'dflt' + + /*! + * Revert button message. + */ + #define REVERT_BUTTON_MSG 'rvrt' + + /*! + * Slider message. + */ + #define MEMORY_SLIDER_MSG 'sldr' + + /*! + * Slider dragging message. + */ + #define SLIDER_UPDATE_MSG 'sldu' + + #ifndef _APPLICATION_H + + #include + + #endif + #ifndef _WINDOW_H + + #include + + #endif + #ifndef _STRING_VIEW_H + + #include + + #endif + #ifndef _BOX_H + + #include + + #endif + #ifndef _SLIDER_H + + #include + + #endif + #ifndef _BUTTON_H + + #include + + #endif + #ifndef _STDIO_H + + #include + + #endif + #ifndef VM_SETTINGS_H + + #include "VMSettings.h" + + #endif + + /** + * The main window of the app. + * + * Sets up and displays everything you need for the app. + */ + class MainWindow : public BWindow{ + + private: + + /** + * Saves the size of the swap file when the app is started + * so that it can be restored later if need be. + */ + int origMemSize; + + /** + * Saves the minimum virtual memory value; + */ + int minSwapVal; + + /** + * The BStringView that shows the requested swap file + * size. + */ + BStringView *reqSwap; + + /** + * The slider that lets you adjust the size of the swap file. + */ + BSlider *reqSizeSlider; + + /** + * The button that returns the swap file to the original + * size. + */ + BButton *revertButton; + + /** + * The BStringView that informs you that you need to + * restart. + */ + BStringView *restart; + + VMSettings *fSettings; + + public: + + MainWindow(BRect frame, int physMem, int currSwp, int sliderMin, int sliderMax, VMSettings *fSettings); + virtual bool QuitRequested(); + virtual void MessageReceived(BMessage *message); + virtual void FrameMoved(BPoint origin); + virtual void toggleChangedMessage(bool setTo); + + }; + +#endif diff --git a/src/prefs/virtualmemory/Resource.rsrc b/src/prefs/virtualmemory/Resource.rsrc new file mode 100644 index 0000000000..7c2e55cc91 Binary files /dev/null and b/src/prefs/virtualmemory/Resource.rsrc differ diff --git a/src/prefs/virtualmemory/VMSettings.cpp b/src/prefs/virtualmemory/VMSettings.cpp new file mode 100644 index 0000000000..010de5b0a0 --- /dev/null +++ b/src/prefs/virtualmemory/VMSettings.cpp @@ -0,0 +1,79 @@ +#ifndef VM_SETTINGS_H +#include "VMSettings.h" +#endif +#ifndef _APPLICATION_H +#include +#endif +#ifndef _FILE_H +#include +#endif +#ifndef _PATH_H +#include +#endif +#ifndef _FINDDIRECTORY_H +#include +#endif + +#include + +const char VMSettings::kVMSettingsFile[] = "VM_data"; + +VMSettings::VMSettings() +{//VMSettings::VMSettings + + BPath path; + if (find_directory(B_USER_SETTINGS_DIRECTORY,&path) == B_OK) + { + path.Append(kVMSettingsFile); + BFile file(path.Path(), B_READ_ONLY); + if (file.InitCheck() != B_OK) + be_app->PostMessage(B_QUIT_REQUESTED); + // Now read in the data + if (file.Read(&fcorner, sizeof(BPoint)) != sizeof(BPoint)) + be_app->PostMessage(B_QUIT_REQUESTED); + } + printf("VM settings file read.\n"); + printf("=========================\n"); + printf("fcorner read in as "); + fcorner.PrintToStream(); + + fWindowFrame.left=fcorner.x; + fWindowFrame.top=fcorner.y; + fWindowFrame.right=fWindowFrame.left+269; + fWindowFrame.bottom=fWindowFrame.top+172; + + //Check to see if the co-ords of the window are in the range of the Screen + BScreen screen; + if (screen.Frame().right >= fWindowFrame.right + && screen.Frame().bottom >= fWindowFrame.bottom) + return; + // If they are not, lets just stick the window in the middle + // of the screen. + fWindowFrame = screen.Frame(); + fWindowFrame.left = (fWindowFrame.right-269)/2; + fWindowFrame.right = fWindowFrame.left + 269; + fWindowFrame.top = (fWindowFrame.bottom-172)/2; + fWindowFrame.bottom = fWindowFrame.top + 172; + +}//VMSettings::VMSettings + +VMSettings::~VMSettings() +{//VMSettings::~VMSettings + BPath path; + if (find_directory(B_USER_SETTINGS_DIRECTORY,&path) < B_OK) + return; + + path.Append(kVMSettingsFile); + + BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE); + if (file.InitCheck() == B_OK) + { + file.Write(&fcorner, sizeof(BPoint)); + } +}//MouseSettings::~MouseSettings + +void VMSettings::SetWindowPosition(BRect f) +{//VMSettings::SetWindowFrame + fcorner.x=f.left; + fcorner.y=f.top; +}//VMSettings::SetWindowFrame \ No newline at end of file diff --git a/src/prefs/virtualmemory/VMSettings.h b/src/prefs/virtualmemory/VMSettings.h new file mode 100644 index 0000000000..91f12def77 --- /dev/null +++ b/src/prefs/virtualmemory/VMSettings.h @@ -0,0 +1,20 @@ +#ifndef VM_SETTINGS_H_ +#define VM_SETTINGS_H_ + +#include +#include + +class VMSettings{ +public : + VMSettings(); + virtual ~VMSettings(); + BRect WindowPosition() const { return fWindowFrame; } + void SetWindowPosition(BRect); + +private: + static const char kVMSettingsFile[]; + BRect fWindowFrame; + BPoint fcorner; +}; + +#endif \ No newline at end of file diff --git a/src/prefs/virtualmemory/main.cpp b/src/prefs/virtualmemory/main.cpp new file mode 100644 index 0000000000..8112e2f282 --- /dev/null +++ b/src/prefs/virtualmemory/main.cpp @@ -0,0 +1,144 @@ +/*! \file main.cpp + * \brief Code for the main class. + * + * This file contains the code for the main class. This class sets up all + * of the initial conditions for the app. + * +*/ + +#include "MainWindow.h" +#include "main.h" + +/** + * Main method. + * + * Starts the whole thing. + */ +int main(int, char**){ + + /** + * An instance of the application. + */ + VM_pref vmApp; + + vmApp.Run(); + + return(0); + +} + +/* + * Constructor. + * + * Provides a contstructor for the application. + */ +VM_pref::VM_pref() + :BApplication("application/x-vnd.MSM-VirtualMemoryPrefPanel"){ + + FILE *settingsFile = + fopen("/boot/home/config/settings/kernel/drivers/virtual_memory", "r"); + FILE *ptr; + char dummy[80]; + BVolume bootVol; + BVolumeRoster *vol_rost = new BVolumeRoster(); + fSettings = new VMSettings(); + + /* + * The main interface window. + */ + MainWindow *Main; + + /* + * The amount of physical memory in the machine. + */ + int physMem; + + /* + * The current size of the swap file. + */ + int currSwap; + + /* + * The set size of the swap file. + */ + int setSwap; + + /* + * The minimum size the swap file can be. + */ + int minSwap; + + /* + * The maximum size the swap file can be. + */ + int maxSwap; + + /* + * System info + */ + system_info info; + + /* + * Swap file + */ + const char *swap_file; + + bool changeMsg = false; + + swap_file = "/boot/var/swap"; + BEntry swap(swap_file); + off_t swapsize; + swap.GetSize(&swapsize); + currSwap = swapsize / 1048576; + + get_system_info(&info); + physMem = (info.max_pages * 4096) / 1048576; + + minSwap = physMem + (int)(physMem / 3.0); + + if(settingsFile != NULL){ + + fscanf(settingsFile, "%s %s\n", dummy, dummy); + fscanf(settingsFile, "%s %d\n", dummy, &setSwap); + setSwap = setSwap / 1048576; + + }//if + else{ + + setSwap = minSwap; + + }//else + fclose(settingsFile); + + vol_rost->GetBootVolume(&bootVol); + /* maxSwap is defined by the amount of free space on your boot + * volume, plus the current swap file size, minus an arbitrary + * amount of space, just so you don't fill up your drive completly. + */ + maxSwap = (bootVol.FreeBytes() / 1048576) + currSwap - 16; + + if(currSwap != setSwap){ + + currSwap = setSwap; + changeMsg = true; + + }//if + + Main = new MainWindow(fSettings->WindowPosition(), physMem, currSwap, minSwap, maxSwap, fSettings); + + if(changeMsg){ + + Main->toggleChangedMessage(true); + + }//if + + Main->Show(); + +} + + +VM_pref::~VM_pref() +{//VM_pref::~VM_pref + delete fSettings; +}//VM_pref::~VM_pref + diff --git a/src/prefs/virtualmemory/main.h b/src/prefs/virtualmemory/main.h new file mode 100644 index 0000000000..3b51adcee0 --- /dev/null +++ b/src/prefs/virtualmemory/main.h @@ -0,0 +1,71 @@ +/*! \file main.h + \brief Header file for the main class. + +*/ + +#ifndef MAIN_H + + #define MAIN_H + + #ifndef _APPLICATION_H + + #include + + #endif + + #ifndef _VOLUME_H + + #include + + #endif + #ifndef _VOLUME_ROSTER_H + + #include + + #endif + #ifndef _STDIO_H + + #include + + #endif + #ifndef VM_SETTINGS_H + + #include "VMSettings.h" + + #endif + #ifndef _OS_H + + #include + + #endif + #ifndef _ENTRY_H + + #include + + #endif + + /** + * Main class. + * + * Gets everything going. + */ + class VM_pref : public BApplication{ + + public: + + /** + * Constructor. + */ + VM_pref(); + + /** + * Destructor. + */ + virtual ~VM_pref(); + + private: + VMSettings *fSettings; + + }; + +#endif \ No newline at end of file diff --git a/src/prefs/workspaces/Jamfile b/src/prefs/workspaces/Jamfile new file mode 100644 index 0000000000..764de9ccc9 --- /dev/null +++ b/src/prefs/workspaces/Jamfile @@ -0,0 +1,7 @@ +SubDir OBOS_TOP sources os kits interface prefs workspaces ; + +Preference Workspaces : Workspaces.cpp ; + +LinkSharedOSLibs Workspaces : be root ; + +AddResources Workspaces : Workspaces.rsrc ; diff --git a/src/prefs/workspaces/Workspaces.cpp b/src/prefs/workspaces/Workspaces.cpp new file mode 100644 index 0000000000..625105fd9f --- /dev/null +++ b/src/prefs/workspaces/Workspaces.cpp @@ -0,0 +1,274 @@ +/* + * Workspaces.cpp + * Open BeOS version alpha 1 by François Revol revol@free.fr + * + * Workspaces window trick found by Minox on BeShare + * (using B_ALL_WORKSPACES as flags in BWindow) + * Found out that using 0xffffffff as Flags was causing the windo not to close on Alt-W + * hey Workspaces get Flags of Window 0 + * gives 0x00008080 which makes it. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +class WorkspacesPreferences { + public: + WorkspacesPreferences(); + virtual ~WorkspacesPreferences(); + + BRect WindowFrame() const { return fWindowFrame; } + BRect ScreenFrame() const { return fScreenFrame; } + void UpdateScreenFrame(); + void SetWindowFrame(BRect); + + private: + static const char kWorkspacesSettingFile[]; + BRect fWindowFrame, fScreenFrame; +}; + +class WorkspacesWindow : public BWindow { + public: + WorkspacesWindow(WorkspacesPreferences *fPreferences); + virtual ~WorkspacesWindow(); + + virtual void ScreenChanged(BRect frame,color_space mode); + virtual void FrameMoved(BPoint origin); + virtual void FrameResized(float width, float height); + virtual void Zoom(BPoint origin, float width, float height); + virtual void MessageReceived(BMessage *msg); + virtual bool QuitRequested(void); + + private: + WorkspacesPreferences *fPreferences; +}; + +class WorkspacesApp : public BApplication { + public: + WorkspacesApp(); + virtual ~WorkspacesApp(); + + virtual void AboutRequested(void); + virtual void ArgvReceived(int32 argc, char **argv); + virtual void ReadyToRun(void); + virtual bool WorkspacesApp::QuitRequested(void); + + private: + static const char kWorkspacesAppSig[]; +}; + +const char WorkspacesApp::kWorkspacesAppSig[] = "application/x-vnd.Be-WORK"; +const char WorkspacesPreferences::kWorkspacesSettingFile[] = "Workspace_data"; + + +WorkspacesPreferences::WorkspacesPreferences() +{ + UpdateScreenFrame(); + + BPath path; + if (find_directory(B_USER_SETTINGS_DIRECTORY,&path) == B_OK) { + path.Append(kWorkspacesSettingFile); + + BFile file(path.Path(), B_READ_ONLY); + if (file.InitCheck() == B_OK && file.Read(&fWindowFrame, sizeof(BRect)) == sizeof(BRect)) { + BScreen screen; + if (screen.Frame().right >= fWindowFrame.right + && screen.Frame().bottom >= fWindowFrame.bottom) + return; + } + } + + fWindowFrame = fScreenFrame; + fWindowFrame.OffsetBy(-10, -10); + fWindowFrame.left = fWindowFrame.right - 160; + fWindowFrame.top = fWindowFrame.bottom - 120; +} + + +WorkspacesPreferences::~WorkspacesPreferences() +{ + BPath path; + if (find_directory(B_USER_SETTINGS_DIRECTORY,&path) < B_OK) + return; + + path.Append(kWorkspacesSettingFile); + + BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE); + if (file.InitCheck() == B_OK) + file.Write(&fWindowFrame, sizeof(BRect)); +} + + +void +WorkspacesPreferences::UpdateScreenFrame() +{ + BScreen screen; + fScreenFrame = screen.Frame(); +} + + +void +WorkspacesPreferences::SetWindowFrame(BRect f) +{ + fWindowFrame = f; + + UpdateScreenFrame(); +} + + +// #pragma mark - + + +// here is the trick :) +#define B_WORKSPACES_WINDOW 0x00008000 + +WorkspacesWindow::WorkspacesWindow(WorkspacesPreferences *preferences) + : BWindow(preferences->WindowFrame(), "Workspaces", B_TITLED_WINDOW_LOOK, + B_NORMAL_WINDOW_FEEL, B_WORKSPACES_WINDOW | B_AVOID_FRONT, B_ALL_WORKSPACES) +{ + fPreferences = preferences; +} + + +WorkspacesWindow::~WorkspacesWindow() +{ + delete fPreferences; +} + + +void +WorkspacesWindow::ScreenChanged(BRect frame,color_space mode) +{ + BRect rect = fPreferences->WindowFrame(); + BRect old = fPreferences->ScreenFrame(); + + // adjust horizontal position + if (frame.right < rect.left || frame.right > rect.right && rect.left > old.right/2) + MoveTo(frame.right - (old.right - rect.left),rect.top); + + // adjust vertical position + if (frame.bottom < rect.top || frame.bottom > rect.bottom && rect.top > old.bottom/2) + MoveTo(Frame().left,frame.bottom - (old.bottom - rect.top)); +} + + +void +WorkspacesWindow::FrameMoved(BPoint origin) +{ + fPreferences->SetWindowFrame(Frame()); +} + + +void +WorkspacesWindow::FrameResized(float width, float height) +{ + fPreferences->SetWindowFrame(Frame()); +} + + +void +WorkspacesWindow::Zoom(BPoint origin, float width, float height) +{ + BScreen screen; + origin = screen.Frame().RightBottom(); + origin.x -= 10 + fPreferences->WindowFrame().Width(); + origin.y -= 10 + fPreferences->WindowFrame().Height(); + + MoveTo(origin); +} + + +void +WorkspacesWindow::MessageReceived(BMessage *msg) +{ + if (msg->what == 'DATA') { // Drop from Tracker + entry_ref ref; + for (int i = 0; (msg->FindRef("refs", i, &ref) == B_OK); i++) + be_roster->Launch(&ref); + } else + BWindow::MessageReceived(msg); +} + + +bool +WorkspacesWindow::QuitRequested(void) +{ + be_app->PostMessage(B_QUIT_REQUESTED); + return true; +} + + +// #pragma mark - + + +WorkspacesApp::WorkspacesApp() : BApplication(kWorkspacesAppSig) +{ +} + + +WorkspacesApp::~WorkspacesApp() +{ +} + + +void +WorkspacesApp::AboutRequested(void) +{ + // blocking !! + // the original does the same by the way =) + (new BAlert("about", "OpenBeOS Workspaces\n\tby François Revol, Axel Dörfler.\n\noriginal Be version by Robert Polic", "Big Deal"))->Go(); +} + + +void +WorkspacesApp::ArgvReceived(int32 argc, char **argv) +{ + // we are told to switch to a specific workspace + if (argc > 1) { + // get it from the command line... + activate_workspace(atoi(argv[1])); + // if the app is running, don't quit + // but if it isn't, cancel the complete run, so it doesn't + // open any window + if (IsLaunching()) + Quit(); + } +} + + +void +WorkspacesApp::ReadyToRun(void) +{ + (new WorkspacesWindow(new WorkspacesPreferences()))->Show(); +} + + +bool +WorkspacesApp::QuitRequested(void) +{ + return true; +} + + +// #pragma mark - + + +int +main(int argc, char **argv) +{ + new WorkspacesApp(); + be_app->Run(); + delete be_app; + return 0; +} + diff --git a/src/prefs/workspaces/Workspaces.rsrc b/src/prefs/workspaces/Workspaces.rsrc new file mode 100644 index 0000000000..1cddf50a25 Binary files /dev/null and b/src/prefs/workspaces/Workspaces.rsrc differ diff --git a/src/servers/app/proto1/AppServer.cpp b/src/servers/app/proto1/AppServer.cpp new file mode 100644 index 0000000000..0ae116c257 --- /dev/null +++ b/src/servers/app/proto1/AppServer.cpp @@ -0,0 +1,84 @@ +#include "scheduler.h" +#include +#include +#include "AppServer.h" +#include "Desktop.h" + +AppServer::AppServer(void) : BApplication("application/x-vnd.obe-OBAppServer") +{ + printf("AppServer()\n"); +} + +AppServer::~AppServer(void) +{ + printf("~AppServer()\n"); + +// kill_thread(PicassoID); +// kill_thread(InputID); + shutdown_desktop(); +} + +void AppServer::Initialize(void) +{ + printf("AppServer::Initialize()\n"); + mouseport=create_port(30,"OBpcreate"); + messageport=create_port(20,"OBpcreate"); + + // Set up the Desktop + init_desktop(3); +/* + // Start up the housekeeping threads + PicassoID = spawn_thread(Draw, "picasso", B_DISPLAY_PRIORITY, this); + if (PicassoID >= 0) + resume_thread(PicassoID); + + InputID = spawn_thread(Draw, "poller", B_DISPLAY_PRIORITY, this); + if (InputID >= 0) + resume_thread(InputID); + + MainLoop(); +*/ +} + +void AppServer::MainLoop(void) +{ + printf("AppServer::MainLoop()\n"); + // Main loop. Monitors the message queue and dispatches as appropriate + int32 msgcode; + uint8 *msgbuffer=new uint8[65536]; + + for(;;) + { + if (read_port(messageport,&msgcode,msgbuffer,65536)!=0) + { + printf("Message sent to OB App server: %ld\n",msgcode); + if(msgcode==B_QUIT_REQUESTED) + break; + } + } + delete msgbuffer; +} + +int32 AppServer::Picasso(void *data) +{ + return 1; +} + +int32 AppServer::Poller(void *data) +{ + return 1; +} + +void AppServer::DispatchMessage(BMessage *msg) +{ + printf("AppServer::DispatchMessage():"); msg->PrintToStream(); +} + +int main( int argc, char** argv ) +{ + AppServer *obas = new AppServer(); + obas->Initialize(); + obas->Run(); + return( 0 ); +} + diff --git a/src/servers/app/proto1/AppServer.h b/src/servers/app/proto1/AppServer.h new file mode 100644 index 0000000000..fdae9fa280 --- /dev/null +++ b/src/servers/app/proto1/AppServer.h @@ -0,0 +1,28 @@ +#ifndef _OPENBEOS_APP_SERVER_H_ +#define _OPENBEOS_APP_SERVER_H_ + +#include +#include +#include "Globals.h" + +class BMessage; +class Desktop; + +class AppServer : public BApplication +{ +public: + AppServer(void); + ~AppServer(void); + void Initialize(void); + void MainLoop(void); + port_id messageport,mouseport; + static int32 Picasso(void *data); + static int32 Poller(void *data); +// void Run(void); + +private: + void DispatchMessage(BMessage *pcReq); + thread_id DrawID, InputID; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto1/Desktop.cpp b/src/servers/app/proto1/Desktop.cpp new file mode 100644 index 0000000000..88a4c477b9 --- /dev/null +++ b/src/servers/app/proto1/Desktop.cpp @@ -0,0 +1,227 @@ + +/* + Screen.cpp: + Function implementations of screen functions in InterfaceDefs.h +*/ +#include +#include +#include +#include +#include +#include "DisplayDriver.h" +#include "DirectDriver.h" +#include "Desktop.h" + +class ServerWindow; +class ServerBitmap; +class ServerLayer; +class Workspace; + +//--------------------GLOBALS------------------------- +int32 workspace_count, active_workspace; +BList desktop; +Workspace *pactive_workspace; +color_map system_palette; +DisplayDriver *gfxdriver; +//---------------------------------------------------- + + +//-------------------INTERNAL CLASS DEFS-------------- +class Workspace +{ +public: + Workspace(void); + Workspace(BPath imagepath); + ~Workspace(); + + BList layerlist; + BList focuslist; + rgb_color bgcolor; + screen_info screendata, + olddata; +}; + +DisplayDriver *get_gfxdriver(void) +{ + return gfxdriver; +} + +Workspace::Workspace(void) +{ + workspace_count++; + + // default values + layerlist.MakeEmpty(); + focuslist.MakeEmpty(); + bgcolor.red=51; + bgcolor.green=102; + bgcolor.blue=160; + screendata.mode=B_CMAP8; + screendata.spaces=B_8_BIT_640x480; + screendata.refresh_rate=60.0; + screendata.min_refresh_rate=60.0; + screendata.max_refresh_rate=60.0; + screendata.h_position=(uchar)50; + screendata.v_position=(uchar)50; + screendata.h_size=(uchar)50; + screendata.v_size=(uchar)50; + olddata=screendata; +} + +Workspace::~Workspace(void) +{ + workspace_count--; +} +//--------------------------------------------------- + + +//-----------------GLOBAL FUNCTION DEFS--------------- + +void init_desktop(int8 workspaces) +{ + printf("init_desktop()\n"); +/* + Create the screen bitmap + Get framebuffer area info + Call setup_screenmode + Create top layer for workspace + Set cursor + Turn mouse on in display driver +*/ + workspace_count=workspaces; + if(workspace_count==0) + workspace_count++; + + // Instantiate and initialize display driver + gfxdriver=new DirectDriver(); + gfxdriver->Initialize(); + if(gfxdriver->IsInitialized()) + printf("Driver initialized\n"); + else + printf("Driver NOT initialized\n"); + + // Create the workspaces we're supposed to have + for(int8 i=0; iSetScreen(pactive_workspace->screendata.spaces); +} + +void shutdown_desktop(void) +{ + printf("Shutdown desktop()\n"); + int32 i,count=desktop.CountItems(); + for(i=0;iworkspace_count || workspace<0) + return; + + Workspace *proposed=(Workspace *)desktop.ItemAt(workspace); + + if(proposed==NULL) + return; + + if(pactive_workspace->screendata.spaces != proposed->screendata.spaces) + { + gfxdriver->SetScreen(proposed->screendata.spaces); + } + + // What else needs to go here? --DW + +} + +const color_map *system_colors(void) +{ + return (const color_map *)&system_palette; +} + +status_t set_screen_space(int32 index, uint32 res, bool stick = true) +{ + printf("set_screen_space(%ld,%lu, %s)\n",index,res,(stick==true)?"true":"false"); + return B_ERROR; +} + +status_t get_scroll_bar_info(scroll_bar_info *info) +{ + return B_ERROR; +} + +status_t set_scroll_bar_info(scroll_bar_info *info) +{ + printf("set_scroll_bar_info()\n"); + return B_ERROR; +} + +bigtime_t idle_time() +{ + return 0; +} + +void run_select_printer_panel() +{ +} + +void run_add_printer_panel() +{ +} + +void run_be_about() +{ +} + +void set_focus_follows_mouse(bool follow) +{ + printf("set_focus_follows_mouse(%s)\n",(follow==true)?"true":"false"); +} + +bool focus_follows_mouse() +{ + return false; +} diff --git a/src/servers/app/proto1/Desktop.h b/src/servers/app/proto1/Desktop.h new file mode 100644 index 0000000000..5b850d0f2d --- /dev/null +++ b/src/servers/app/proto1/Desktop.h @@ -0,0 +1,33 @@ +#ifndef _OBDESKTOP_H_ +#define _OBDESKTOP_H_ + +#include +#include +class DisplayDriver; + +typedef enum +{ PLACE_MANUAL=0, + PLACE_SCALE=1, + PLACE_TILE=2 +} wallpaper_placement; + +void init_desktop(int8 workspaces); +void shutdown_desktop(void); +DisplayDriver *get_gfxdriver(void); + +typedef struct +{ + color_space mode; + BRect frame; + uint32 spaces; + float min_refresh_rate; + float max_refresh_rate; + float refresh_rate; + uchar h_position; + uchar v_position; + uchar h_size; + uchar v_size; +} screen_info; + + +#endif \ No newline at end of file diff --git a/src/servers/app/proto1/DirectDriver.cpp b/src/servers/app/proto1/DirectDriver.cpp new file mode 100644 index 0000000000..69c49e1bd8 --- /dev/null +++ b/src/servers/app/proto1/DirectDriver.cpp @@ -0,0 +1,117 @@ +#include +#include "DirectDriver.h" + +OBAppServerScreen::OBAppServerScreen(status_t *error) + : BWindowScreen("DirectDriver",B_32_BIT_800x600,error,true) +{ + redraw=true; +} + +OBAppServerScreen::~OBAppServerScreen(void) +{ +} + +void OBAppServerScreen::MessageReceived(BMessage *msg) +{ + msg->PrintToStream(); + switch(msg->what) + { + case B_KEY_DOWN: + Disconnect(); + QuitRequested(); + break; + default: + BWindowScreen::MessageReceived(msg); + break; + } +} + +bool OBAppServerScreen::QuitRequested(void) +{ + be_app->PostMessage(B_QUIT_REQUESTED); + return true; +} + +int32 OBAppServerScreen::Draw(void *data) +{ + OBAppServerScreen *screen=(OBAppServerScreen *)data; + for(;;) + { + if(screen->connected && screen->redraw) + { + // Draw a sample background + screen->Clear(128,128,128); + screen->SimWin(BRect(100,100,250,250)); + screen->redraw=false; + } + } + return 1; +} + +void OBAppServerScreen::ScreenConnected(bool ok) +{ + if(ok==true) + connected=true; + else + connected=false; +} + +void OBAppServerScreen::Clear(uint8 red,uint8 green,uint8 blue) +{ + if(!connected) return; +} + +void OBAppServerScreen::SimWin(BRect rect) +{ + if(!connected) return; +} + +DirectDriver::DirectDriver(void) +{ + printf("DirectDriver()\n"); + old_space=B_32_BIT_800x600; +} + +DirectDriver::~DirectDriver(void) +{ + printf("~DirectDriver()\n"); + winscreen->Quit(); +} + +void DirectDriver::Initialize(void) +{ + printf("DirectDriver::Initialize()\n"); + status_t stat; + winscreen=new OBAppServerScreen(&stat); + if(stat==B_OK) + { + is_initialized=true; + winscreen->Show(); + } + else + delete winscreen; + + if(winscreen->connected==false) + return; + ginfo=winscreen->CardInfo(); + for(int8 i=0;i<48;i++) + ghooks[i]=winscreen->CardHookAt(i); +} + +void DirectDriver::SafeMode(void) +{ + printf("DirectDriver::SafeMode()\n"); + Reset(); +} + +void DirectDriver::Reset(void) +{ + printf("DirectDriver::Reset()\n"); + if(is_initialized) + winscreen->Clear(51,102,160); +} + +void DirectDriver::SetScreen(uint32 space) +{ + printf("DirectDriver::SetScreen(%lu)\n",space); +} \ No newline at end of file diff --git a/src/servers/app/proto1/DirectDriver.h b/src/servers/app/proto1/DirectDriver.h new file mode 100644 index 0000000000..21920d049d --- /dev/null +++ b/src/servers/app/proto1/DirectDriver.h @@ -0,0 +1,44 @@ +#ifndef _DIRECTDRIVER_H_ +#define _DIRECTDRIVER_H_ + +#include +#include +#include +#include +#include "DisplayDriver.h" + +class OBAppServerScreen : public BWindowScreen +{ +public: + OBAppServerScreen(status_t *error); + ~OBAppServerScreen(void); + virtual void MessageReceived(BMessage *msg); + virtual bool QuitRequested(void); + static int32 Draw(void *data); + virtual void ScreenConnected(bool connected); + + // Graphics stuff implemented here for the moment + void Clear(uint8 red,uint8 green,uint8 blue); + void SimWin(BRect rect); + + int32 DrawID; + bool redraw,connected; +}; + +class DirectDriver : public DisplayDriver +{ +public: + DirectDriver(void); + virtual ~DirectDriver(void); + + virtual void Initialize(void); // Sets the driver + virtual void SafeMode(void); // Easy-access functions for common tasks + virtual void Reset(void); + virtual void SetScreen(uint32 space); + OBAppServerScreen *winscreen; +protected: + // Original screen info + uint32 old_space; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto1/DisplayDriver.cpp b/src/servers/app/proto1/DisplayDriver.cpp new file mode 100644 index 0000000000..43dc9647b6 --- /dev/null +++ b/src/servers/app/proto1/DisplayDriver.cpp @@ -0,0 +1,34 @@ +#include "DisplayDriver.h" + +DisplayDriver::DisplayDriver(void) +{ + is_initialized=false; + cursor_visible=false; +} + +DisplayDriver::~DisplayDriver(void) +{ +} + +void DisplayDriver::Initialize(void) +{ // Loading loop to find proper driver + +} + +bool DisplayDriver::IsInitialized(void) +{ // Let dev know whether things worked out ok + return is_initialized; +} + +void DisplayDriver::SafeMode(void) +{ // Set video mode to 640x480x256 mode +} + +void DisplayDriver::Reset(void) +{ // Reloads and restarts driver. Defaults to a safe mode + +} + +void DisplayDriver::SetScreen(uint32 space) +{ +} \ No newline at end of file diff --git a/src/servers/app/proto1/DisplayDriver.h b/src/servers/app/proto1/DisplayDriver.h new file mode 100644 index 0000000000..cafa3fd708 --- /dev/null +++ b/src/servers/app/proto1/DisplayDriver.h @@ -0,0 +1,56 @@ +#ifndef _GFX_DRIVER_H_ +#define _GFX_DRIVER_H_ + +#include +#include "Desktop.h" + +typedef struct +{ + uchar *xormask, *andmask; + int32 width, height; + int32 hotx, hoty; + +} cursor_data; + +#ifndef HOOK_DEFINE_CURSOR + +#define HOOK_DEFINE_CURSOR 0 +#define HOOK_MOVE_CURSOR 1 +#define HOOK_SHOW_CURSOR 2 +#define HOOK_DRAW_LINE_8BIT 3 +#define HOOK_DRAW_LINE_16BIT 12 +#define HOOK_DRAW_LINE_32BIT 4 +#define HOOK_DRAW_RECT_8BIT 5 +#define HOOK_DRAW_RECT_16BIT 13 +#define HOOK_DRAW_RECT_32BIT 6 +#define HOOK_BLIT 7 +#define HOOK_DRAW_ARRAY_8BIT 8 +#define HOOK_DRAW_ARRAY_16BIT 14 // Not implemented in current R5 drivers +#define HOOK_DRAW_ARRAY_32BIT 9 +#define HOOK_SYNC 10 +#define HOOK_INVERT_RECT 11 + +#endif + +class DisplayDriver +{ +public: + DisplayDriver(void); + virtual ~DisplayDriver(void); + + virtual void Initialize(void); // Sets the driver + virtual void SafeMode(void); // Easy-access functions for common tasks + virtual void Reset(void); + virtual void SetScreen(uint32 space); + + virtual bool IsInitialized(void); + graphics_card_hook ghooks[48]; + graphics_card_info *ginfo; + cursor_data current_cursor; + bool cursor_visible; + +protected: + bool is_initialized; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto1/Globals.h b/src/servers/app/proto1/Globals.h new file mode 100644 index 0000000000..2753cad1aa --- /dev/null +++ b/src/servers/app/proto1/Globals.h @@ -0,0 +1,7 @@ +#ifndef _SERVER_GLOBALS_H_ +#define _SERVER_GLOBALS_H_ + +#include +BList *gBitmaplist, *gLayerlist; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto1/GraphicsHooks.cc b/src/servers/app/proto1/GraphicsHooks.cc new file mode 100644 index 0000000000..2bd8e1c67e --- /dev/null +++ b/src/servers/app/proto1/GraphicsHooks.cc @@ -0,0 +1,181 @@ +#include +#include +#include "GraphicsHooks.h" +//#include "AppServer.h" // for the framebuffer pointer + +// Structs necessary for our hook functions +#include + +int32 define_cursor(uchar *xormask, uchar *andmask, int32 width, + int32 height, int32 hotx, int32 hoty) +{ + return 0; +} + +int32 move_cursor(int32 screenx, int32 screeny) +{ + return 0; +} + +int32 show_cursor(bool flag) +{ + return 0; +} + +int32 draw_line_with_8_bit_depth(int32 startx, int32 endx, + int32 starty, int32 endy, uint8 colorindex, bool cliptorect, + int16 clipleft, int16 cliptop, int16 clipright, int16 clipbottom) +{ + if(cliptorect) + { // Do clipping before we start if we're told to + BRect rect(clipleft,cliptop,clipright,clipbottom); + BPoint start(startx,starty),end(endx,endy); + start.ConstrainTo(rect); + end.ConstrainTo(rect); + } + + return B_OK; +} + +int32 draw_line_with_32_bit_depth(int32 startx, int32 endx, + int32 starty, int32 endy, uint32 color, bool cliptorect, + int16 clipleft, int16 cliptop, int16 clipright, int16 clipbottom) +{ + if(cliptorect) + { // Do clipping before we start if we're told to + BRect rect(clipleft,cliptop,clipright,clipbottom); + BPoint start(startx,starty),end(endx,endy); + start.ConstrainTo(rect); + end.ConstrainTo(rect); + } + + return 0; +} + +int32 draw_rect_with_8_bit_depth(int32 left, int32 top, int32 right, + int32 bottom, uint8 colorindex) +{ + return 0; +} + +int32 draw_rect_with_32_bit_depth(int32 left, int32 top, int32 right, + int32 bottom, uint32 color) +{ + return 0; +} + +int32 blit(int32 sourcex, int32 sourcey, int32 destinationx, + int32 destinationy, int32 width, int32 height) +{ + return 0; +} + +int32 draw_array_with_8_bit_depth(indexed_color_line *array, int32 numitems, + bool cliptorect, int16 clipleft, int16 cliptop, + int16 clipright, int16 clipbottom) +{ + return 0; +} + +int32 draw_array_with_32_bit_depth(rgb_color_line *array, int32 numitems, + bool cliptorect, int16 clipleft, int16 cliptop, + int16 clipright, int16 clipbottom) +{ + return 0; +} + +int32 sync(void) +{ + return 0; +} + +int32 invert_rect(int32 left, int32 top, int32 right, int32 bottom) +{ + return 0; +} + +int32 draw_line_with_16_bit_depth(int32 startx, int32 endx, + int32 starty, int32 endy, uint16 color, bool cliptorect, + int16 clipleft, int16 cliptop, int16 clipright, int16 clipbottom) +{ + return 0; +} + +int32 draw_rect_with_16_bit_depth(int32 left, int32 top, int32 right, + int32 bottom, uint16 color) +{ + return 0; +} + +// hook functions not officially-defined, but which should exist +int32 draw_array_with_16_bit_depth(high_color_line *array, int32 numitems, + bool cliptorect, int16 clipleft, int16 cliptop, + int16 clipright, int16 clipbottom) +{ + return 0; +} + +int32 draw_frect_with_8_bit_depth(int32 left, int32 top, int32 right, + int32 bottom, uint8 colorindex) +{ + return 0; +} + +int32 draw_frect_with_16_bit_depth(int32 left, int32 top, int32 right, + int32 bottom, uint16 color) +{ + return 0; +} + +int32 draw_frect_with_32_bit_depth(int32 left, int32 top, int32 right, + int32 bottom, uint32 color) +{ + return 0; +} + +/* +rgb_color GetPixel_32(BPoint pt) +{ +// pt.x = floor(pt.x / zoom); +// pt.y = floor(pt.y / zoom); + rgb_color color; + + uint32 pos_bits=uint32 ( (p_active_layer->bitmap->BytesPerRow()*pt.y) + (pt.x*4) ); + uint8 *s_bits=(uint8*) p_active_layer->bitmap->Bits() + pos_bits; + + color.blue=*s_bits; + s_bits++; + color.green=*s_bits; + s_bits++; + color.red=*s_bits; + s_bits++; + color.alpha=*s_bits; + return color; +} + +void SetPixel_32(BPoint where, rgb_color color) +{ + // Make some quick-access pointers + BBitmap *work_bmp; + work_bmp=p_active_layer->bitmap; + + uint8 *bmpdata=(uint8 *)work_bmp->Bits(); + + // Check bounds + where.ConstrainTo(work_bmp->Bounds()); + + // Calculate offset & jump + uint32 bitoffset; + bitoffset= uint32 ((where.x*4)+(work_bmp->BytesPerRow()*where.y)); //only counts there - it is similar on all lines + bmpdata += bitoffset; + + // Assign color data + *bmpdata=color.blue; + bmpdata++; + *bmpdata=color.green; + bmpdata++; + *bmpdata=color.red; + bmpdata++; + *bmpdata=color.alpha; +} +*/ \ No newline at end of file diff --git a/src/servers/app/proto1/GraphicsHooks.h b/src/servers/app/proto1/GraphicsHooks.h new file mode 100644 index 0000000000..8b9c5b2f05 --- /dev/null +++ b/src/servers/app/proto1/GraphicsHooks.h @@ -0,0 +1,60 @@ +// Structs necessary for our hook functions +#include + +typedef struct +{ int16 x1,y1,x2,y2; + uint8 color; +} indexed_color_line; + +typedef struct +{ int16 x1,y1,x2,y2; + rgb_color color; +} rgb_color_line; + +int32 define_cursor(uchar *xormask, uchar *andmask, int32 width, + int32 height, int32 hotx, int32 hoty); +int32 move_cursor(int32 screenx, int32 screeny); +int32 show_cursor(bool flag); +int32 draw_line_with_8_bit_depth(int32 startx, int32 endx, + int32 starty, int32 endy, uint8 colorindex, bool cliptorect, + int16 clipleft, int16 cliptop, int16 clipright, int16 clipbottom); +int32 draw_line_with_32_bit_depth(int32 startx, int32 endx, + int32 starty, int32 endy, uint32 color, bool cliptorect, + int16 clipleft, int16 cliptop, int16 clipright, int16 clipbottom); +int32 draw_rect_with_8_bit_depth(int32 left, int32 top, int32 right, + int32 bottom, uint8 colorindex); +int32 draw_rect_with_32_bit_depth(int32 left, int32 top, int32 right, + int32 bottom, uint32 color); +int32 blit(int32 sourcex, int32 sourcey, int32 destinationx, + int32 destinationy, int32 width, int32 height); +int32 draw_array_with_8_bit_depth(indexed_color_line *array, int32 numitems, + bool cliptorect, int16 clipleft, int16 cliptop, + int16 clipright, int16 clipbottom); +int32 draw_array_with_32_bit_depth(rgb_color_line *array, int32 numitems, + bool cliptorect, int16 clipleft, int16 cliptop, + int16 clipright, int16 clipbottom); +int32 sync(void); +int32 invert_rect(int32 left, int32 top, int32 right, int32 bottom); +int32 draw_line_with_16_bit_depth(int32 startx, int32 endx, + int32 starty, int32 endy, uint16 color, bool cliptorect, + int16 clipleft, int16 cliptop, int16 clipright, int16 clipbottom); +int32 draw_rect_with_16_bit_depth(int32 left, int32 top, int32 right, + int32 bottom, uint16 color); + + +// Not officially-defined hook functions which should be here +typedef struct +{ int16 x1,y1,x2,y2; + uint16 color; +} high_color_line; + +int32 draw_array_with_16_bit_depth(high_color_line *array, int32 numitems, + bool cliptorect, int16 clipleft, int16 cliptop, + int16 clipright, int16 clipbottom); + +int32 draw_frect_with_8_bit_depth(int32 left, int32 top, int32 right, + int32 bottom, uint8 colorindex); +int32 draw_frect_with_16_bit_depth(int32 left, int32 top, int32 right, + int32 bottom, uint16 color); +int32 draw_frect_with_32_bit_depth(int32 left, int32 top, int32 right, + int32 bottom, uint32 color); diff --git a/src/servers/app/proto1/Layer.cpp b/src/servers/app/proto1/Layer.cpp new file mode 100644 index 0000000000..4130a02e2e --- /dev/null +++ b/src/servers/app/proto1/Layer.cpp @@ -0,0 +1,74 @@ +#include "Layer.h" + +Layer::Layer(ServerWindow *Win, const char *Name, BRect &Frame, int32 Flags) +{ +} + +Layer::Layer(ServerBitmap *Bitmap) +{ +} + +Layer::~Layer(void) +{ +} + +void Layer::Initialize(void) +{ +} + +void Layer::Show(void) +{ +} + +void Layer::Hide(void) +{ +} + +bool Layer::IsVisible(void) +{ + return false; +} + +void Layer::Update(bool ForceUpdate) +{ +} + +bool Layer::IsBackground(void) +{ + return false; +} + +void Layer::SetFrame(const BRect &Rect) +{ +} + +BRect Layer::Frame(void) +{ + return BRect(0,0,0,0); +} + +BRect Layer::Bounds(void) +{ + return BRect(0,0,0,0); +} + +void Layer::Invalidate(const BRect &Rect) +{ +} + +void Layer::AddRegion(BRegion *Region) +{ +} + +void Layer::RemoveRegions(void) +{ +} + +void Layer::UpdateRegions(bool ForceUpdate=true, bool Root=true) +{ +} + +void Layer::Draw(const BRect &Rect) +{ +} + diff --git a/src/servers/app/proto1/Layer.h b/src/servers/app/proto1/Layer.h new file mode 100644 index 0000000000..603d5642a3 --- /dev/null +++ b/src/servers/app/proto1/Layer.h @@ -0,0 +1,60 @@ +#ifndef _LAYER_H_ +#define _LAYER_H_ + +#include +#include +#include + +class ServerBitmap; +class ServerWindow; + +class Layer +{ +public: + Layer(ServerWindow *Win, const char *Name, BRect &Frame, int32 Flags); + Layer(ServerBitmap *Bitmap); + virtual ~Layer(void); + + void Initialize(void); + void Show(void); + void Hide(void); + bool IsVisible(void); + void Update(bool ForceUpdate); + + bool IsBackground(void); + + virtual void SetFrame(const BRect &Rect); + BRect Frame(void); + BRect Bounds(void); + + void Invalidate(const BRect &Rect); + void AddRegion(BRegion *Region); + void RemoveRegions(void); + void UpdateRegions(bool ForceUpdate=true, bool Root=true); + + // Render functions: + virtual void Draw(const BRect &Rect); + + const char *name; + int32 handle; + ServerWindow *window; // Window associated with this. NULL for background layer + ServerBitmap *bitmap; // Blasted to screen on redraw. We render to this + + BRect frame; + + BRegion *visible, // Everything currently visible + *full, // The complete region + *update; // Area to be updated at next redraw + + int32 flags; // Various flags for behavior + + // Render state: + BPoint penpos; + rgb_color high, low, erase; + + int32 drawingmode; +}; + + Layer *FindLayer(int32 Handle); + +#endif diff --git a/src/servers/app/proto1/ServerBitmap.cpp b/src/servers/app/proto1/ServerBitmap.cpp new file mode 100644 index 0000000000..9c8748f802 --- /dev/null +++ b/src/servers/app/proto1/ServerBitmap.cpp @@ -0,0 +1,134 @@ +#include "ServerBitmap.h" +#include "Desktop.h" + +ServerBitmap::ServerBitmap(BRect rect,color_space cspace,int32 BytesPerLine=0) +{ + width=rect.IntegerWidth()+1; + height=rect.IntegerHeight()+1; + colorspace=cspace; + is_vram=false; + + // Big convoluted mess just to handle every color space and dword align + // the buffer + switch(cspace) + { + // Buffer is dword-aligned, so nothing need be done + // aside from allocate the memory + case B_RGB32: + case B_RGBA32: + case B_RGB32_BIG: + case B_RGBA32_BIG: + case B_UVL32: + case B_UVLA32: + case B_LAB32: + case B_LABA32: + case B_HSI32: + case B_HSIA32: + case B_HSV32: + case B_HSVA32: + case B_HLS32: + case B_HLSA32: + case B_CMY32: + case B_CMYA32: + case B_CMYK32: + + // 24-bit=32bit with extra 8 bits ignored + case B_RGB24_BIG: + case B_RGB24: + case B_LAB24: + case B_UVL24: + case B_HSI24: + case B_HSV24: + case B_HLS24: + case B_CMY24: + { + if(BytesPerLine<(width*4)) + bytesperline=width*4; + else + bytesperline=BytesPerLine; + break; + } + // Calculate size and dword-align + + // 1-bit + case B_GRAY1: + { + int32 numbytes=width>>3; + if((width % 8) != 0) + numbytes++; + if(BytesPerLine +#include +#include "DisplayDriver.h" + +class ServerBitmap +{ +public: + ServerBitmap(BRect rect,color_space cspace,int32 BytesPerLine=0); + ~ServerBitmap(void); + + int32 width,height; + int32 bytesperline; + color_space colorspace; + uint8 *buffer; + DisplayDriver *driver; + bool is_vram; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto1/ServerWindow.cpp b/src/servers/app/proto1/ServerWindow.cpp new file mode 100644 index 0000000000..25573409cf --- /dev/null +++ b/src/servers/app/proto1/ServerWindow.cpp @@ -0,0 +1,114 @@ +#include +#include "ServerWindow.h" + +ServerWindow::ServerWindow(const char *Title, uint32 Flags, uint32 Desktop, + const BRect &Rect, ServerApp *App, port_id SendPort) +{ +} + +ServerWindow::ServerWindow(ServerApp *App, ServerBitmap *Bitmap) +{ +} + +ServerWindow::~ServerWindow(void) +{ +} + +void ServerWindow::PostMessage(BMessage *msg) +{ +} + +void ServerWindow::ReplaceDecorator(void) +{ +} + +void ServerWindow::Quit(void) +{ +} + +const char *ServerWindow::GetTitle(void) +{ + return NULL; +} + +ServerApp *ServerWindow::GetApp(void) +{ + return NULL; +} + +BMessenger *ServerWindow::GetAppTarget(void) +{ + return NULL; +} + +void ServerWindow::Show(void) +{ +} + +void ServerWindow::Hide(void) +{ +} + +void ServerWindow::SetFocus(void) +{ +} + +bool ServerWindow::HasFocus(void) +{ + return false; +} + +void ServerWindow::DesktopActivated(int32 NewDesktop, const BPoint Resolution, color_space CSpace) +{ +} + +void ServerWindow::WindowActivated(bool Active) +{ +} + +void ServerWindow::ScreenModeChanged(const BPoint Resolustion, color_space CSpace) +{ +} + +void ServerWindow::SetFrame(const BRect &Frame) +{ +} + +BRect ServerWindow::Frame(void) +{ + return BRect(0,0,0,0); +} + +thread_id ServerWindow::Run(void) +{ + return -1; +} + +status_t ServerWindow::Lock(void) +{ + return B_ERROR; +} + +status_t ServerWindow::Unlock(void) +{ + return B_ERROR; +} + +bool ServerWindow::IsLocked(void) +{ + return false; +} + +bool ServerWindow::DispatchMessage(BMessage *msg) +{ + return false; +} + +bool ServerWindow::DispatchMessage(const void *msg, int nCode) +{ + return false; +} + +void ServerWindow::Loop(void) +{ +} diff --git a/src/servers/app/proto1/ServerWindow.h b/src/servers/app/proto1/ServerWindow.h new file mode 100644 index 0000000000..4c97ab93bb --- /dev/null +++ b/src/servers/app/proto1/ServerWindow.h @@ -0,0 +1,70 @@ +#ifndef _SERVERWIN_H_ +#define _SERVERWIN_H_ + +#include +#include +#include +#include + +class BString; +class BMessenger; +class BRect; +class BPoint; +class ServerApp; +class ServerBitmap; +class WindowDecorator; + +class ServerWindow +{ +public: +ServerWindow(const char *Title, uint32 Flags, uint32 Desktop, + const BRect &Rect, ServerApp *App, port_id SendPort); +ServerWindow(ServerApp *App, ServerBitmap *Bitmap); +virtual ~ServerWindow(void); + +void PostMessage(BMessage *msg); +void ReplaceDecorator(void); +virtual void Quit(void); +const char *GetTitle(void); +ServerApp *GetApp(void); +BMessenger *GetAppTarget(void); +void Show(void); +void Hide(void); +void SetFocus(void); +bool HasFocus(void); + +void DesktopActivated(int32 NewDesktop, const BPoint Resolution, color_space CSpace); +void WindowActivated(bool Active); +void ScreenModeChanged(const BPoint Resolustion, color_space CSpace); + +void SetFrame(const BRect &Frame); +BRect Frame(void); + +thread_id Run(void); +status_t Lock(void); +status_t Unlock(void); +bool IsLocked(void); + +bool DispatchMessage(BMessage *msg); +bool DispatchMessage(const void *msg, int nCode); + +void Loop(void); + +const char *title; +int32 flags; +int32 desktop; + +ServerBitmap *userbitmap; +ServerApp *app; + +WindowDecorator *decorator; +bigtime_t lasthit; // Time of last mouse click + +thread_id thread; +port_id rcvport; // Messages from application +port_id sendport; // Messages to application +BLocker mutex; +BMessenger *apptarget; +}; + +#endif diff --git a/src/servers/app/proto2/AppServer.cpp b/src/servers/app/proto2/AppServer.cpp new file mode 100644 index 0000000000..544512d659 --- /dev/null +++ b/src/servers/app/proto2/AppServer.cpp @@ -0,0 +1,177 @@ +#include +#include +#include "ServerProtocol.h" + +#include "AppServer.h" +#include "ServerApp.h" +#include "PortLink.h" + +AppServer::AppServer(void) : BApplication("application/x-vnd.obe-OBAppServer") +{ + printf("AppServer()\n"); + + mouseport=create_port(30,"OBpcreate"); +// messageport=create_port(20,"OBpcreate"); + messageport=create_port(20,SERVER_PORT_NAME); + printf("Server message port: %ld\n",messageport); + applist=new BList(0); + quitting_server=false; +} + +AppServer::~AppServer(void) +{ + printf("~AppServer()\n"); + + ServerApp *temp; + for(int32 i=0;iCountItems();i++) + { + temp=(ServerApp *)applist->ItemAt(i); + if(temp!=NULL) + delete temp; + } + delete applist; +} + +thread_id AppServer::Run(void) +{ + printf("AppServer::Run()\n"); + + MainLoop(); + return 0; +} + +void AppServer::MainLoop(void) +{ + printf("AppServer::MainLoop()\n"); + + // Main loop. Monitors the message queue and dispatches as appropriate + int32 msgcode; + int8 *msgbuffer=NULL; + ssize_t buffersize,bytesread; + + for(;;) + { + buffersize=port_buffer_size(messageport); + if(buffersize>0) + msgbuffer=new int8[buffersize]; + bytesread=read_port(messageport,&msgcode,msgbuffer,buffersize); + + if (bytesread != B_BAD_PORT_ID && bytesread != B_TIMED_OUT && bytesread != B_WOULD_BLOCK) + { + switch(msgcode) + { + case CREATE_APP: + case DELETE_APP: + case B_QUIT_REQUESTED: + DispatchMessage(msgcode,msgbuffer); + break; + default: + printf("Server received unexpected code %ld\n",msgcode); + break; + } + + } + + if(buffersize>0) + delete msgbuffer; + if(msgcode==DELETE_APP) + { + if(quitting_server==true && applist->CountItems()==0) + break; + } + } + +} + + +void AppServer::DispatchMessage(int32 code, int8 *buffer) +{ + int8 *index=buffer; + switch(code) + { + case CREATE_APP: + { + printf("AppServer: Create App\n"); + + // Attached data: + // 1) port_id - receiver port of a regular app + // 2) char * - signature of the regular app + + // Find the necessary data + port_id app_port=*((port_id*)index); + index+=sizeof(port_id); + + char *app_signature=(char *)index; + + // Create the ServerApp subthread for this app + ServerApp *newapp=new ServerApp(app_port,app_signature); + applist->AddItem(newapp); + newapp->Run(); + break; + } + case DELETE_APP: + { + // Delete a ServerApp. Received only from the respective ServerApp + printf("AppServer: Delete App\n"); + + // Attached Data: + // 1) thread_id - thread ID of the ServerApp to be deleted + + int32 i, appnum=applist->CountItems(); + ServerApp *srvapp; + thread_id srvapp_id=*((thread_id*)buffer); + + // Run through the list of apps and nuke the proper one + for(i=0;iItemAt(i); + if(srvapp!=NULL && srvapp->monitor_thread==srvapp_id) + { + srvapp=(ServerApp *)applist->RemoveItem(i); + delete srvapp; + } + } + break; + } + case B_QUIT_REQUESTED: + { + printf("Shutdown sequence initiated.\n"); + // Attached Data: + // none + + // We've been asked to quit, so (for now) broadcast to all + // test apps to quit + PortLink *applink=new PortLink(0); + ServerApp *srvapp; + int32 i,appnum=applist->CountItems(); + + applink->SetOpCode(QUIT_APP); + for(i=0;iItemAt(i); + if(srvapp!=NULL) + { + applink->SetPort(srvapp->receiver); + applink->Flush(); + } + } + + delete applink; + // So when we delete the last ServerApp, we can exit the server + quitting_server=true; + break; + } + default: + printf("Unexpected message %ld (%lx) in AppServer::DispatchMessage()\n",code,code); + break; + } +} + +int main( int argc, char** argv ) +{ + AppServer *obas = new AppServer(); + obas->Run(); + delete obas; + return( 0 ); +} + diff --git a/src/servers/app/proto2/AppServer.h b/src/servers/app/proto2/AppServer.h new file mode 100644 index 0000000000..0c781a735d --- /dev/null +++ b/src/servers/app/proto2/AppServer.h @@ -0,0 +1,27 @@ +#ifndef _OPENBEOS_APP_SERVER_H_ +#define _OPENBEOS_APP_SERVER_H_ + +#include +#include +#include + +class BMessage; +class ServerApp; + +class AppServer : public BApplication +{ +public: + AppServer(void); + ~AppServer(void); + thread_id Run(void); + void MainLoop(void); + port_id messageport,mouseport; + +private: + void DispatchMessage(int32 code, int8 *buffer); + thread_id DrawID, InputID; + bool quitting_server; + BList *applist; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto2/PortLink.cpp b/src/servers/app/proto2/PortLink.cpp new file mode 100644 index 0000000000..8fba724569 --- /dev/null +++ b/src/servers/app/proto2/PortLink.cpp @@ -0,0 +1,438 @@ +/* + PortLink.cpp: + A helper class for port-based messaging + +------------------------------------------------------------------------ +How it works: + The class utilizes a fixed-size array of PortLinkData object pointers. When +data is attached, a new PortLinkData object is allocated and a copy of the +passed data is created inside it. When the time comes for the message to be sent, +the data is pieced together into a flattened array and written to the port. +------------------------------------------------------------------------ +Data members: + +*attachments[] - fixed-size array of pointers used to hold the attached data +opcode - message value which is sent along with any data +target - port to which the message is sent when Flush() is called +replyport - port used with synchronous messaging - FlushWithReply() +bufferlength - total bytes taken up by attachments +num_attachments - internal variable which is used to track which "slot" + will be the next one to receive an attachment object +*/ + +#include "PortLink.h" +#include +#include +#include + +//#define PLDEBUG + +// Internal data storage class for holding attached data whilst it is waiting +// to be Flattened() and then Flushed(). There is no need for this to be called outside +// the PortLink class. +class PortLinkData +{ +public: + PortLinkData(void); + ~PortLinkData(void); + bool Set(void *data, size_t size); + char *buffer; + size_t buffersize; +}; + +PortLink::PortLink(port_id port) +{ + // For this class to be useful (and to prevent a lot of init problems) + // we require a port in the constructor + target=port; + + // We start out without any data attached to the port message + num_attachments=0; + opcode=0; + bufferlength=0; + replyport=create_port(30,"PortLink reply port"); +} + +PortLink::~PortLink(void) +{ + // If, for some odd reason, this is deleted with something attached, + // free the memory used by the attachments. We do not flush the queue + // because the port may no longer be valid in cases such as the app + // is in the process of quitting + MakeEmpty(); +} + +void PortLink::SetOpCode(int32 code) +{ + // Sets the message code. This does not change once the message is sent. + // Another call to SetOpCode() is required for such things. + opcode=code; +} + +void PortLink::SetPort(port_id port) +{ + // Sets the target port. While not necessary in most uses, this exists + // mostly to prevent flexibility problems + target=port; +} + +port_id PortLink::GetPort(void) +{ + // Simply returns the port at which the object is pointed. + return target; +} + +void PortLink::Flush(bigtime_t timeout=B_INFINITE_TIMEOUT) +{ + // Fires a message off to the target, complete with attachments. NOTE: + // the recipient must delete all attachments, being the PortLink object assumes + // no responsiblity for the attachments once the message is sent. + int8 *msgbuffer; + int32 size; + + if(num_attachments>0) + { + FlattenData(&msgbuffer,&size); + + // Dump message to port, reset attachments, and clean up + if(timeout!=B_INFINITE_TIMEOUT) + write_port_etc(target,opcode,msgbuffer,size,B_TIMEOUT, timeout); + else + write_port(target,opcode,msgbuffer,size); + MakeEmpty(); + } + else + { + if(timeout!=B_INFINITE_TIMEOUT) + write_port_etc(target,opcode,NULL,0,B_TIMEOUT, timeout); + else + write_port(target,opcode,NULL,0); + } +} + +int8* PortLink::FlushWithReply(int32 *code, status_t *status, ssize_t *buffersize, bigtime_t timeout=B_INFINITE_TIMEOUT) +{ + // Fires a message to the target and then waits for a reply. The target will + // receive a message with the first item being the port_id to reply to. + // NOTE: like Flush(), any attached data must be deleted. + + // Effectively, an Attach() call inlined for changes + + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + { + *status=B_ERROR; + return NULL; + } + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&replyport,sizeof(port_id))) + { + bufferlength+=sizeof(port_id); + } + else + { + delete pld; + *status=B_ERROR; + return NULL; + } + + // Flatten() inlined to make some necessary changes + int8 *buffer=new int8[bufferlength]; + int8 *bufferindex=buffer; + size_t size=0; + + // attach our port_id first + memcpy(bufferindex, pld->buffer, pld->buffersize); + bufferindex += pld->buffersize; + size+=pld->buffersize; + + // attach everything else + for(int i=0;ibuffer, pld->buffersize); + bufferindex += pld->buffersize; + size+=pld->buffersize; + } + + // Flush the thing....FOOSH! :P + write_port(target,opcode,buffer,size); + MakeEmpty(); + delete buffer; + + // Now we wait for the reply + if(timeout==B_INFINITE_TIMEOUT) + { + *buffersize=port_buffer_size(replyport); + if(*buffersize>0) + buffer=(int8*)new int8[*buffersize]; + read_port(replyport,code, buffer, *buffersize); + } + else + { + *buffersize=port_buffer_size_etc(replyport,0,timeout); + if(*buffersize==B_TIMED_OUT) + { + *status=*buffersize; + return NULL; + } + if(*buffersize>0) + buffer=(int8*)new int8[*buffersize]; + read_port(replyport,code, buffer, *buffersize); + } + + // We got this far, so we apparently have some data + *status=B_OK; + return buffer; +} + +void PortLink::Attach(void *data, size_t size) +{ + // This is the member called to attach data to a message. Attachments are + // treated to be in 'Append' mode, tacking on each attached piece of data + // to the end of the list. + + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + if(size==0) + return; + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +// These functions were added for a major convenience in passing common types +// Eventually, I'd like to templatize these, but for now, this'll do + +void PortLink::Attach(int32 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int32); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(int16 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int16); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(int8 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int8); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(float data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(float); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(bool data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(bool); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(BRect data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(BRect); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(BPoint data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(BPoint); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::FlattenData(int8 **buffer,int32 *size) +{ + // This function is where all the magic happens, but it is strictly internal. + // It iterates through each PortLinkData object and copies it to the main buffer + // which ends up, ultimately, being written to the PortLink's target port. + + // skip if there aree no attachments + if(bufferlength<1) + return; + + *buffer=new int8[bufferlength]; + int8 *bufferindex=*buffer; + PortLinkData *pld; + *size=0; + + for(int i=0;ibuffer, pld->buffersize); + bufferindex += pld->buffersize; + *size+=pld->buffersize; + } +} + +void PortLink::MakeEmpty(void) +{ + // Nukes all the attachments currently held by the PortLink class + if(num_attachments!=0) + { + for(int i=0; i0) + free(buffer); +} + +bool PortLinkData::Set(void *data, size_t size) +{ + // Function copies the passed to the internal buffers for storage + if(size>0 && buffersize==0 && data!=NULL) + { + buffer=(char *)malloc(size); + if(buffer==NULL) + return false; + memcpy(buffer, data, size); + buffersize=size; + return true; + } + return false; +} diff --git a/src/servers/app/proto2/PortLink.h b/src/servers/app/proto2/PortLink.h new file mode 100644 index 0000000000..9f5432daab --- /dev/null +++ b/src/servers/app/proto2/PortLink.h @@ -0,0 +1,43 @@ +#ifndef _PORTLINK_H_ +#define _PORTLINK_H_ + +#include +#include +#include +#include + +#ifndef _PORTLINK_BUFFERSIZE +#define _PORTLINK_MAX_ATTACHMENTS 50 +#endif + +class PortLinkData; + +class PortLink +{ +public: + PortLink(port_id port); + ~PortLink(void); + void SetOpCode(int32 code); + void SetPort(port_id port); + port_id GetPort(void); + void Flush(bigtime_t timeout=B_INFINITE_TIMEOUT); + int8* FlushWithReply(int32 *code, status_t *status, ssize_t *buffersize, + bigtime_t timeout=B_INFINITE_TIMEOUT); + void Attach(void *data, size_t size); + void Attach(int32 data); + void Attach(int16 data); + void Attach(int8 data); + void Attach(float data); + void Attach(bool data); + void Attach(BRect data); + void Attach(BPoint data); + void MakeEmpty(void); +protected: + void FlattenData(int8 **buffer,int32 *size); + port_id target, replyport; + int32 opcode, bufferlength; + int num_attachments; + PortLinkData *attachments[_PORTLINK_MAX_ATTACHMENTS]; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto2/README b/src/servers/app/proto2/README new file mode 100644 index 0000000000..b9aaf0d60e --- /dev/null +++ b/src/servers/app/proto2/README @@ -0,0 +1,31 @@ +Prototype 2: Messaging + +This is the second proof-of-concept prototype for the OpenBeOS app_server. This demonstrates the use of the PortLink class to send messages quickly and how the server manages processes under normal circumstances (ie, not killing a team). Listed at the end of this file is the sequence of events for a particular task, utilizing only 3 types of components: the Server class, ServerApp application-monitoring nodes, and the application itself. All 3 have been built for R5. Although not formally documented, the code is relatively clean and mostly commented. + +Files Included + +OBAppServer: the actual server +OBApp: a skeleton of what's supposed to be an app. Implemented only for testing purposes but some concepts may eventually make their way into the real OBOS BApplication class +OBHey: Quick-and-dirty app which sends a message code (in decimal) to a specified port. For the sake of reference, B_QUIT_REQUESTED=1599165009. + +Application launch: +1) App constructor +2) App->server CREATE_APP +3) Server spawns ServerApp +4) ServerApp->App SET_PORT +5) App reinitializes serverlink to SET_PORT port + +Application quit (from app side): +1) ->App B_QUIT_REQUESTED +2) App -> ServerApp B_QUIT_REQUESTED and quits +3) ServerApp -> Server DELETE_APP and quits +4) Server removes ServerApp from list and deletes object + +App Server quit: +1) Right now: Server->all ServerApps (QUIT_APP) + Eventually: Server->Registrar(BROADCAST_QUIT) +1a) Right now: ServerApps->Apps(B_QUIT_REQUESTED) +2) Server sets internal flag quitting_server to true +3) When server receives DELETE_APP, checks to see if any ServerApps are left. +4) If no ServerApps are left after deleting the sender of the delete_app message, server checks to see if quitting_server is set to true +5) Server exits \ No newline at end of file diff --git a/src/servers/app/proto2/ServerApp.cpp b/src/servers/app/proto2/ServerApp.cpp new file mode 100644 index 0000000000..e549cf4801 --- /dev/null +++ b/src/servers/app/proto2/ServerApp.cpp @@ -0,0 +1,139 @@ +#include +#include "ServerApp.h" +#include "ServerProtocol.h" +#include "PortLink.h" +#include +#include + +ServerApp::ServerApp(port_id msgport, char *signature) +{ + printf("New ServerApp %s for app at port %ld\n",signature,msgport); + + // need to copy the signature because the message buffer + // owns the copy which we are passed as a parameter. + if(signature) + { + app_sig=new char[strlen(signature)]; + sprintf(app_sig,signature); + } + else + { + app_sig=new char[strlen("Application")]; + sprintf(app_sig,"Application"); + } + + // sender is the monitored app's event port + sender=msgport; + applink=new PortLink(sender); + + // receiver is the port to which the app sends messages for the server + receiver=create_port(30,app_sig); + printf("ServerApp port for app %s is at %ld\n",app_sig,receiver); + if(receiver==B_NO_MORE_PORTS) + { + // uh-oh. We have a serious problem. Tell the app to quit + applink->SetOpCode(B_QUIT_REQUESTED); + applink->Flush(); + } + else + { + // Everything checks out, so tell the application + // where to send future messages + applink->SetOpCode(SET_SERVER_PORT); + applink->Attach(&receiver,sizeof(port_id)); + applink->Flush(); + } +} + +ServerApp::~ServerApp(void) +{ + printf("%s::~ServerApp()\n",app_sig); + delete app_sig; + delete applink; +} + +bool ServerApp::Run(void) +{ + monitor_thread=spawn_thread(MonitorApp,app_sig,B_NORMAL_PRIORITY,this); + if(monitor_thread==B_NO_MORE_THREADS || monitor_thread==B_NO_MEMORY) + return false; + resume_thread(monitor_thread); + return true; +} + +int32 ServerApp::MonitorApp(void *data) +{ + ServerApp *app=(ServerApp *)data; + app->Loop(); + exit_thread(0); + return 0; +} + +void ServerApp::Loop(void) +{ + printf("%s::MainLoop()\n",app_sig); + + int32 msgcode; + int8 *msgbuffer=NULL; + ssize_t buffersize,bytesread; + + for(;;) + { + buffersize=port_buffer_size(receiver); + + if(buffersize>0) + { + // buffers are PortLink messages. Allocate necessary buffer and + // we'll cast it as a BMessage. + msgbuffer=new int8[buffersize]; + bytesread=read_port(receiver,&msgcode,msgbuffer,buffersize); + } + else + bytesread=read_port(receiver,&msgcode,NULL,0); + + if (bytesread != B_BAD_PORT_ID && bytesread != B_TIMED_OUT && bytesread != B_WOULD_BLOCK) + { + switch(msgcode) + { + case B_QUIT_REQUESTED: + { + // We receive this message when the app we monitor quits + port_id serverport=find_port(SERVER_PORT_NAME); + if(serverport==B_NAME_NOT_FOUND) + { + printf("PANIC: ServerApp %s could not find the app_server port!\n",app_sig); + break; + } + printf("ServerApp %s quitting\n",app_sig); + applink->SetPort(serverport); + applink->SetOpCode(DELETE_APP); + applink->Attach(&monitor_thread,sizeof(thread_id)); + applink->Flush(); + break; + } + case QUIT_APP: + { + printf("ServerApp asking %s to quit\n",app_sig); + applink->SetOpCode(B_QUIT_REQUESTED); + applink->Flush(); + break; + } + default: + printf("Server received unexpected code %ld\n",msgcode); + break; + } + + } + + if(buffersize>0) + delete msgbuffer; + + if(msgcode==B_QUIT_REQUESTED) + break; + } +} + +void ServerApp::DispatchMessage(BMessage *msg) +{ +} + diff --git a/src/servers/app/proto2/ServerApp.h b/src/servers/app/proto2/ServerApp.h new file mode 100644 index 0000000000..cf450ccc9c --- /dev/null +++ b/src/servers/app/proto2/ServerApp.h @@ -0,0 +1,25 @@ +#ifndef _SRVAPP_H_ +#define _SRVAPP_H_ + +#include +class BMessage; +class PortLink; + +class ServerApp +{ +public: + ServerApp(port_id msgport, char *signature); + ~ServerApp(void); + + bool Run(void); + static int32 MonitorApp(void *data); + void Loop(void); + void DispatchMessage(BMessage *msg); + + port_id sender,receiver; + char *app_sig; + thread_id monitor_thread; + PortLink *applink; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto2/ServerProtocol.h b/src/servers/app/proto2/ServerProtocol.h new file mode 100644 index 0000000000..9cc7d7cf40 --- /dev/null +++ b/src/servers/app/proto2/ServerProtocol.h @@ -0,0 +1,12 @@ +#ifndef _APPSERVER_PROTOCOL_ +#define _APPSERVER_PROTOCOL_ + +#define CREATE_APP 'drca' +#define DELETE_APP 'drda' + +#define SET_SERVER_PORT 'srsp' +#define QUIT_APP 'srqa' + +#define SERVER_PORT_NAME "OBappserver" + +#endif \ No newline at end of file diff --git a/src/servers/app/proto2/obhey/obhey.c b/src/servers/app/proto2/obhey/obhey.c new file mode 100644 index 0000000000..8e6bfbd617 --- /dev/null +++ b/src/servers/app/proto2/obhey/obhey.c @@ -0,0 +1,25 @@ +#include +#include +#include +#include +/* + Sends a message to the OpenBeOS app_server's message port +*/ + +int main(int argc, char **argv) +{ + int32 msgcode; + + if(argc>2) + { + port_id serverport=atoi(argv[1]); + msgcode=atoi(argv[2]); + + write_port(serverport,msgcode,NULL,0); + printf("Sent %ld to port %ld\n",msgcode,serverport); + return 1; + } + + printf("obhey port \n"); + return 0; +} \ No newline at end of file diff --git a/src/servers/app/proto2/obtestapp/OBApp.cpp b/src/servers/app/proto2/obtestapp/OBApp.cpp new file mode 100644 index 0000000000..7d22133a26 --- /dev/null +++ b/src/servers/app/proto2/obtestapp/OBApp.cpp @@ -0,0 +1,180 @@ +/* + OBApp.cpp: App faker for OpenBeOS app_server prototype #2 +*/ + +#include +#include +#include +#include +#include +#include +#include "ServerProtocol.h" +#include "PortLink.h" + +class TestApp +{ +public: + TestApp(void); + virtual ~TestApp(void); + + void MainLoop(void); // Replaces BLooper message looping + + // Hmm... What's this do? ;^) + virtual void DispatchMessage(BMessage *msg, BHandler *handler); + virtual void MessageReceived(BMessage *msg); + bool Run(void); + + port_id messageport, serverport; + char *signature; + bool initialized; + PortLink *serverlink; +}; + + +TestApp::TestApp(void) +{ + printf("TestApp::TestApp()\n"); + initialized=true; + + // Receives messages from server and others + messageport=create_port(50,"msgport"); + if(messageport==B_BAD_VALUE || messageport==B_NO_MORE_PORTS) + { printf("TestApp: Couldn't create message port\n"); + initialized=false; + } + + // Find the port for the app_server + serverport=find_port("OBappserver"); + if(serverport==B_NAME_NOT_FOUND) + { printf("TestApp: Couldn't find server port\n"); + initialized=false; + + serverlink=new PortLink(create_port(50,"OBAppServer")); + } + else + { + serverlink=new PortLink(serverport); + } + +// signature=new char[255]; + signature=new char[strlen("application/x-vnd.wgp-OBTestApp")]; + sprintf(signature,"application/x-vnd.wgp-OBTestApp"); +} + +TestApp::~TestApp(void) +{ + printf("%s::~TestApp()\n",signature); + delete signature; + + if(initialized==true) + delete serverlink; +} + +void TestApp::MainLoop(void) +{ + printf("TestApp::MainLoop()\n"); + + // Notify server of app's existence +/* BMessage *createmsg=new BMessage(CREATE_APP); + createmsg->AddString("signature",signature); +// createmsg->AddInt32("PID",PID); + createmsg->AddInt32("messageport",messageport); + + printf("port id: %ld\n",messageport); + printf("signature: %s\n",signature); + + write_port(serverport,CREATE_APP,createmsg,sizeof(*createmsg)); +*/ + serverlink->SetOpCode(CREATE_APP); + serverlink->Attach(&messageport,sizeof(port_id)); +// serverlink.Attach(PID); + serverlink->Attach(signature,strlen(signature)); + serverlink->Flush(); + + int32 msgcode; + uint8 *msgbuffer=NULL; + ssize_t buffersize,bytesread; + + for(;;) + { + buffersize=port_buffer_size(messageport); + + if(buffersize>0) + { + // buffers are flattened messages. Allocate necessary buffer and + // we'll cast it as a BMessage. + msgbuffer=new uint8[buffersize]; + bytesread=read_port(messageport,&msgcode,msgbuffer,buffersize); + } + else + bytesread=read_port(messageport,&msgcode,NULL,0); + + if (bytesread != B_BAD_PORT_ID && bytesread != B_TIMED_OUT && bytesread != B_WOULD_BLOCK) + { + switch(msgcode) + { + case B_QUIT_REQUESTED: + { + // Attached data: + // None + printf("%s: Quit requested\n",signature); + serverlink->SetOpCode(msgcode); + serverlink->Flush(); + break; + } + case SET_SERVER_PORT: + { + // Attached data: + // port_id - id of the port of the corresponding ServerApp + if(buffersize<1) + { + printf("%s: Set Server Port has no attached data\n",signature); + break; + } + printf("%s: Set Server Port to %ld\n",signature,*((port_id *)msgbuffer)); + serverport=*((port_id *)msgbuffer); + serverlink->SetPort(serverport); + break; + } + default: + printf("OBTestApp received unexpected code %ld\n",msgcode); + break; + } + + if(msgcode==B_QUIT_REQUESTED) + { + printf("Quitting %s\n",signature); + break; + } + } + + if(buffersize>0) + delete msgbuffer; + } +} + +void TestApp::DispatchMessage(BMessage *msg, BHandler *handler) +{ + printf("TestApp::DispatchMessage()\n"); +} + +void TestApp::MessageReceived(BMessage *msg) +{ + printf("TestApp::MessageReceived()\n"); +} + +bool TestApp::Run(void) +{ + printf("TestApp::Run()\n"); +// if(!initialized) +// return false; + + MainLoop(); + return true; +} + +int main(void) +{ + TestApp app; + app.Run(); +} \ No newline at end of file diff --git a/src/servers/app/proto2/obtestapp/PortLink.cpp b/src/servers/app/proto2/obtestapp/PortLink.cpp new file mode 100644 index 0000000000..8fba724569 --- /dev/null +++ b/src/servers/app/proto2/obtestapp/PortLink.cpp @@ -0,0 +1,438 @@ +/* + PortLink.cpp: + A helper class for port-based messaging + +------------------------------------------------------------------------ +How it works: + The class utilizes a fixed-size array of PortLinkData object pointers. When +data is attached, a new PortLinkData object is allocated and a copy of the +passed data is created inside it. When the time comes for the message to be sent, +the data is pieced together into a flattened array and written to the port. +------------------------------------------------------------------------ +Data members: + +*attachments[] - fixed-size array of pointers used to hold the attached data +opcode - message value which is sent along with any data +target - port to which the message is sent when Flush() is called +replyport - port used with synchronous messaging - FlushWithReply() +bufferlength - total bytes taken up by attachments +num_attachments - internal variable which is used to track which "slot" + will be the next one to receive an attachment object +*/ + +#include "PortLink.h" +#include +#include +#include + +//#define PLDEBUG + +// Internal data storage class for holding attached data whilst it is waiting +// to be Flattened() and then Flushed(). There is no need for this to be called outside +// the PortLink class. +class PortLinkData +{ +public: + PortLinkData(void); + ~PortLinkData(void); + bool Set(void *data, size_t size); + char *buffer; + size_t buffersize; +}; + +PortLink::PortLink(port_id port) +{ + // For this class to be useful (and to prevent a lot of init problems) + // we require a port in the constructor + target=port; + + // We start out without any data attached to the port message + num_attachments=0; + opcode=0; + bufferlength=0; + replyport=create_port(30,"PortLink reply port"); +} + +PortLink::~PortLink(void) +{ + // If, for some odd reason, this is deleted with something attached, + // free the memory used by the attachments. We do not flush the queue + // because the port may no longer be valid in cases such as the app + // is in the process of quitting + MakeEmpty(); +} + +void PortLink::SetOpCode(int32 code) +{ + // Sets the message code. This does not change once the message is sent. + // Another call to SetOpCode() is required for such things. + opcode=code; +} + +void PortLink::SetPort(port_id port) +{ + // Sets the target port. While not necessary in most uses, this exists + // mostly to prevent flexibility problems + target=port; +} + +port_id PortLink::GetPort(void) +{ + // Simply returns the port at which the object is pointed. + return target; +} + +void PortLink::Flush(bigtime_t timeout=B_INFINITE_TIMEOUT) +{ + // Fires a message off to the target, complete with attachments. NOTE: + // the recipient must delete all attachments, being the PortLink object assumes + // no responsiblity for the attachments once the message is sent. + int8 *msgbuffer; + int32 size; + + if(num_attachments>0) + { + FlattenData(&msgbuffer,&size); + + // Dump message to port, reset attachments, and clean up + if(timeout!=B_INFINITE_TIMEOUT) + write_port_etc(target,opcode,msgbuffer,size,B_TIMEOUT, timeout); + else + write_port(target,opcode,msgbuffer,size); + MakeEmpty(); + } + else + { + if(timeout!=B_INFINITE_TIMEOUT) + write_port_etc(target,opcode,NULL,0,B_TIMEOUT, timeout); + else + write_port(target,opcode,NULL,0); + } +} + +int8* PortLink::FlushWithReply(int32 *code, status_t *status, ssize_t *buffersize, bigtime_t timeout=B_INFINITE_TIMEOUT) +{ + // Fires a message to the target and then waits for a reply. The target will + // receive a message with the first item being the port_id to reply to. + // NOTE: like Flush(), any attached data must be deleted. + + // Effectively, an Attach() call inlined for changes + + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + { + *status=B_ERROR; + return NULL; + } + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&replyport,sizeof(port_id))) + { + bufferlength+=sizeof(port_id); + } + else + { + delete pld; + *status=B_ERROR; + return NULL; + } + + // Flatten() inlined to make some necessary changes + int8 *buffer=new int8[bufferlength]; + int8 *bufferindex=buffer; + size_t size=0; + + // attach our port_id first + memcpy(bufferindex, pld->buffer, pld->buffersize); + bufferindex += pld->buffersize; + size+=pld->buffersize; + + // attach everything else + for(int i=0;ibuffer, pld->buffersize); + bufferindex += pld->buffersize; + size+=pld->buffersize; + } + + // Flush the thing....FOOSH! :P + write_port(target,opcode,buffer,size); + MakeEmpty(); + delete buffer; + + // Now we wait for the reply + if(timeout==B_INFINITE_TIMEOUT) + { + *buffersize=port_buffer_size(replyport); + if(*buffersize>0) + buffer=(int8*)new int8[*buffersize]; + read_port(replyport,code, buffer, *buffersize); + } + else + { + *buffersize=port_buffer_size_etc(replyport,0,timeout); + if(*buffersize==B_TIMED_OUT) + { + *status=*buffersize; + return NULL; + } + if(*buffersize>0) + buffer=(int8*)new int8[*buffersize]; + read_port(replyport,code, buffer, *buffersize); + } + + // We got this far, so we apparently have some data + *status=B_OK; + return buffer; +} + +void PortLink::Attach(void *data, size_t size) +{ + // This is the member called to attach data to a message. Attachments are + // treated to be in 'Append' mode, tacking on each attached piece of data + // to the end of the list. + + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + if(size==0) + return; + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +// These functions were added for a major convenience in passing common types +// Eventually, I'd like to templatize these, but for now, this'll do + +void PortLink::Attach(int32 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int32); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(int16 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int16); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(int8 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int8); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(float data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(float); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(bool data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(bool); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(BRect data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(BRect); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(BPoint data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(BPoint); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::FlattenData(int8 **buffer,int32 *size) +{ + // This function is where all the magic happens, but it is strictly internal. + // It iterates through each PortLinkData object and copies it to the main buffer + // which ends up, ultimately, being written to the PortLink's target port. + + // skip if there aree no attachments + if(bufferlength<1) + return; + + *buffer=new int8[bufferlength]; + int8 *bufferindex=*buffer; + PortLinkData *pld; + *size=0; + + for(int i=0;ibuffer, pld->buffersize); + bufferindex += pld->buffersize; + *size+=pld->buffersize; + } +} + +void PortLink::MakeEmpty(void) +{ + // Nukes all the attachments currently held by the PortLink class + if(num_attachments!=0) + { + for(int i=0; i0) + free(buffer); +} + +bool PortLinkData::Set(void *data, size_t size) +{ + // Function copies the passed to the internal buffers for storage + if(size>0 && buffersize==0 && data!=NULL) + { + buffer=(char *)malloc(size); + if(buffer==NULL) + return false; + memcpy(buffer, data, size); + buffersize=size; + return true; + } + return false; +} diff --git a/src/servers/app/proto2/obtestapp/PortLink.h b/src/servers/app/proto2/obtestapp/PortLink.h new file mode 100644 index 0000000000..9f5432daab --- /dev/null +++ b/src/servers/app/proto2/obtestapp/PortLink.h @@ -0,0 +1,43 @@ +#ifndef _PORTLINK_H_ +#define _PORTLINK_H_ + +#include +#include +#include +#include + +#ifndef _PORTLINK_BUFFERSIZE +#define _PORTLINK_MAX_ATTACHMENTS 50 +#endif + +class PortLinkData; + +class PortLink +{ +public: + PortLink(port_id port); + ~PortLink(void); + void SetOpCode(int32 code); + void SetPort(port_id port); + port_id GetPort(void); + void Flush(bigtime_t timeout=B_INFINITE_TIMEOUT); + int8* FlushWithReply(int32 *code, status_t *status, ssize_t *buffersize, + bigtime_t timeout=B_INFINITE_TIMEOUT); + void Attach(void *data, size_t size); + void Attach(int32 data); + void Attach(int16 data); + void Attach(int8 data); + void Attach(float data); + void Attach(bool data); + void Attach(BRect data); + void Attach(BPoint data); + void MakeEmpty(void); +protected: + void FlattenData(int8 **buffer,int32 *size); + port_id target, replyport; + int32 opcode, bufferlength; + int num_attachments; + PortLinkData *attachments[_PORTLINK_MAX_ATTACHMENTS]; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto2/obtestapp/ServerProtocol.h b/src/servers/app/proto2/obtestapp/ServerProtocol.h new file mode 100644 index 0000000000..9cc7d7cf40 --- /dev/null +++ b/src/servers/app/proto2/obtestapp/ServerProtocol.h @@ -0,0 +1,12 @@ +#ifndef _APPSERVER_PROTOCOL_ +#define _APPSERVER_PROTOCOL_ + +#define CREATE_APP 'drca' +#define DELETE_APP 'drda' + +#define SET_SERVER_PORT 'srsp' +#define QUIT_APP 'srqa' + +#define SERVER_PORT_NAME "OBappserver" + +#endif \ No newline at end of file diff --git a/src/servers/app/proto3/AppServer.cpp b/src/servers/app/proto3/AppServer.cpp new file mode 100644 index 0000000000..8d1805eaa7 --- /dev/null +++ b/src/servers/app/proto3/AppServer.cpp @@ -0,0 +1,295 @@ +#include +#include +#include "scheduler.h" +#include +#include "AppServer.h" +#include "ServerApp.h" +#include "Desktop.h" +#include "ServerProtocol.h" +#include "PortLink.h" +#include "DisplayDriver.h" + +AppServer::AppServer(void) : BApplication("application/x-vnd.obe-OBAppServer") +{ +// printf("AppServer()\n"); + + mouseport=create_port(30,SERVER_INPUT_PORT); + messageport=create_port(20,SERVER_PORT_NAME); +// printf("Server message port: %ld\n",messageport); +// printf("Server input port: %ld\n",mouseport); + applist=new BList(0); + quitting_server=false; + exit_poller=false; + + // Set up the Desktop + init_desktop(3); + + // Spawn our input-polling thread + poller_id = spawn_thread(PollerThread, "Poller", B_NORMAL_PRIORITY, this); + if (poller_id >= 0) + resume_thread(poller_id); + driver=get_gfxdriver(); +} + +AppServer::~AppServer(void) +{ + shutdown_desktop(); + + ServerApp *temp; + for(int32 i=0;iCountItems();i++) + { + temp=(ServerApp *)applist->ItemAt(i); + if(temp!=NULL) + delete temp; + } + delete applist; +} + +thread_id AppServer::Run(void) +{ + //printf("AppServer::Run()\n"); + + MainLoop(); + return 0; +} + +void AppServer::MainLoop(void) +{ + // Main loop (duh). Monitors the message queue and dispatches as appropriate. + // Input messages are handled by the poller, however. + + //printf("AppServer::MainLoop()\n"); + + int32 msgcode; + int8 *msgbuffer=NULL; + ssize_t buffersize,bytesread; + + for(;;) + { + buffersize=port_buffer_size(messageport); + if(buffersize>0) + msgbuffer=new int8[buffersize]; + bytesread=read_port(messageport,&msgcode,msgbuffer,buffersize); + + if (bytesread != B_BAD_PORT_ID && bytesread != B_TIMED_OUT && bytesread != B_WOULD_BLOCK) + { + switch(msgcode) + { + case CREATE_APP: + case DELETE_APP: + case B_QUIT_REQUESTED: + DispatchMessage(msgcode,msgbuffer); + break; + default: + //printf("Server received unexpected code %ld\n",msgcode); + break; + } + + } + + if(buffersize>0) + delete msgbuffer; + if(msgcode==DELETE_APP || msgcode==B_QUIT_REQUESTED) + { + if(quitting_server==true && applist->CountItems()==0) + break; + } + } + // Make sure our polling thread has exited + if(find_thread("Poller")!=B_NAME_NOT_FOUND) + kill_thread(poller_id); + +} + + +void AppServer::DispatchMessage(int32 code, int8 *buffer) +{ + int8 *index=buffer; + switch(code) + { + case CREATE_APP: + { + // Create the ServerApp to node monitor a new BApplication + + //printf("AppServer: Create App\n"); + + // Attached data: + // 1) port_id - receiver port of a regular app + // 2) char * - signature of the regular app + + // Find the necessary data + port_id app_port=*((port_id*)index); + index+=sizeof(port_id); + + char *app_signature=(char *)index; + + // Create the ServerApp subthread for this app + ServerApp *newapp=new ServerApp(app_port,app_signature); + applist->AddItem(newapp); + newapp->Run(); + break; + } + case DELETE_APP: + { + // Delete a ServerApp. Received only from the respective ServerApp when a + // BApplication asks it to quit. + + //printf("AppServer: Delete App\n"); + + // Attached Data: + // 1) thread_id - thread ID of the ServerApp to be deleted + + int32 i, appnum=applist->CountItems(); + ServerApp *srvapp; + thread_id srvapp_id=*((thread_id*)buffer); + + // Run through the list of apps and nuke the proper one + for(i=0;iItemAt(i); + if(srvapp!=NULL && srvapp->monitor_thread==srvapp_id) + { + srvapp=(ServerApp *)applist->RemoveItem(i); + delete srvapp; + } + } + break; + } + case B_QUIT_REQUESTED: + { + //printf("Shutdown sequence initiated.\n"); + + // Attached Data: + // none + + // We've been asked to quit, so (for now) broadcast to all + // test apps to quit. This situation will occur only when the server + // is compiled as a regular Be application. + PortLink *applink=new PortLink(0); + ServerApp *srvapp; + int32 i,appnum=applist->CountItems(); + + applink->SetOpCode(QUIT_APP); + for(i=0;iItemAt(i); + if(srvapp!=NULL) + { + applink->SetPort(srvapp->receiver); + applink->Flush(); + } + } + + delete applink; + // So when we delete the last ServerApp, we can exit the server + quitting_server=true; + exit_poller=true; + break; + } + default: + //printf("Unexpected message %ld (%lx) in AppServer::DispatchMessage()\n",code,code); + break; + } +} + +void AppServer::Poller(void) +{ + // This thread handles nothing but input messages for mouse and keyboard + int32 msgcode; + int8 *msgbuffer=NULL,*index; + ssize_t buffersize,bytesread; + + for(;;) + { + buffersize=port_buffer_size(mouseport); + if(buffersize>0) + msgbuffer=new int8[buffersize]; + bytesread=read_port(mouseport,&msgcode,msgbuffer,buffersize); + + if (bytesread != B_BAD_PORT_ID && bytesread != B_TIMED_OUT && bytesread != B_WOULD_BLOCK) + { + switch(msgcode) + { + case B_MOUSE_DOWN: + { + //printf("AppServer: Mouse Down\n"); + + // Attached data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - modifier keys down during click + // 5) int32 - buttons down + // 6) int32 - number of clicks + break; + } + case B_MOUSE_MOVED: + { + // Attached data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - buttons down + + index=msgbuffer; + + // Throw away the time sent - for now + index += sizeof(int64); + + float tempx=0,tempy=0; + tempx=*((float*)index); + index+=sizeof(float); + tempy=*((float*)index); + index+=sizeof(float); + + driver->MoveCursorTo((int)tempx,(int)tempy); + break; + } + case B_MOUSE_UP: + { + //printf("AppServer: Mouse Up\n"); + + // Attached data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - buttons down + + break; + } + default: + //printf("Server::Poller received unexpected code %ld\n",msgcode); + break; + } + + } + + if(buffersize>0) + delete msgbuffer; + + if(exit_poller) + break; + } +} + +int32 AppServer::PollerThread(void *data) +{ + //printf("Starting Poller thread...\n"); + AppServer *server=(AppServer *)data; + + server->Poller(); // This won't return until it's told to + + //printf("Exiting Poller thread...\n"); + exit_thread(B_OK); + return B_OK; +} + +int main( int argc, char** argv ) +{ + AppServer *obas = new AppServer(); + obas->Run(); + delete obas; + return 0; +} + + \ No newline at end of file diff --git a/src/servers/app/proto3/AppServer.h b/src/servers/app/proto3/AppServer.h new file mode 100644 index 0000000000..4214ecdfc8 --- /dev/null +++ b/src/servers/app/proto3/AppServer.h @@ -0,0 +1,33 @@ +#ifndef _OPENBEOS_APP_SERVER_H_ +#define _OPENBEOS_APP_SERVER_H_ + +#include +#include +#include + +class BMessage; +class ServerApp; +class DisplayDriver; + +class AppServer : public BApplication +{ +public: + AppServer(void); + ~AppServer(void); + thread_id Run(void); + void MainLoop(void); + port_id messageport,mouseport; + void Poller(void); + +private: + void DispatchMessage(int32 code, int8 *buffer); + static int32 PollerThread(void *data); + + bool quitting_server; + BList *applist; + thread_id poller_id; + bool exit_poller; + DisplayDriver *driver; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto3/DebugTools.cpp b/src/servers/app/proto3/DebugTools.cpp new file mode 100644 index 0000000000..6e728d02c4 --- /dev/null +++ b/src/servers/app/proto3/DebugTools.cpp @@ -0,0 +1,44 @@ +#include +#include +#include "DebugTools.h" + +void PrintStatusToStream(status_t value) +{ + // Function which simply translates a returned status code into a string + // and dumps it to stdout + BString outstr; + switch(value) + { + case B_OK: + outstr="B_OK "; + break; + case B_NAME_NOT_FOUND: + outstr="B_NAME_NOT_FOUND "; + break; + case B_BAD_VALUE: + outstr="B_BAD_VALUE "; + break; + case B_ERROR: + outstr="B_ERROR "; + break; + case B_TIMED_OUT: + outstr="B_TIMED_OUT "; + break; + case B_NO_MORE_PORTS: + outstr="B_NO_MORE_PORTS "; + break; + case B_WOULD_BLOCK: + outstr="B_WOULD_BLOCK "; + break; + case B_BAD_PORT_ID: + outstr="B_BAD_PORT_ID "; + break; + case B_BAD_TEAM_ID: + outstr="B_BAD_TEAM_ID "; + break; + default: + outstr="undefined status value in debugtools::PrintStatusToStream() "; + break; + } + cout << "Status: " << outstr.String(); +} diff --git a/src/servers/app/proto3/DebugTools.h b/src/servers/app/proto3/DebugTools.h new file mode 100644 index 0000000000..8d3b01740b --- /dev/null +++ b/src/servers/app/proto3/DebugTools.h @@ -0,0 +1,8 @@ +#ifndef _DEBUGTOOLS_H_ +#define _DEBUGTOOLS_H_ + +#include + +void PrintStatusToStream(status_t value); + +#endif \ No newline at end of file diff --git a/src/servers/app/proto3/Desktop.cpp b/src/servers/app/proto3/Desktop.cpp new file mode 100644 index 0000000000..8111068006 --- /dev/null +++ b/src/servers/app/proto3/Desktop.cpp @@ -0,0 +1,227 @@ +/* + Desktop.cpp: + Code necessary to handle the Desktop, defined as the collection of workspaces. +*/ +#include +#include +#include +#include +#include +#include "DisplayDriver.h" +#include "ViewDriver.h" +#include "Desktop.h" + +class ServerWindow; +class ServerBitmap; +class ServerLayer; +class Workspace; + +//--------------------GLOBALS------------------------- +int32 workspace_count, active_workspace; +BList desktop; +Workspace *pactive_workspace; +color_map system_palette; +ViewDriver *gfxdriver; +//---------------------------------------------------- + + +//-------------------INTERNAL CLASS DEFS-------------- +class Workspace +{ +public: + Workspace(void); + Workspace(BPath imagepath); + ~Workspace(); + + BList layerlist; + BList focuslist; + rgb_color bgcolor; + screen_info screendata, + olddata; +}; + +DisplayDriver *get_gfxdriver(void) +{ + return gfxdriver; +} + +Workspace::Workspace(void) +{ + workspace_count++; + + // default values + layerlist.MakeEmpty(); + focuslist.MakeEmpty(); + bgcolor.red=51; + bgcolor.green=102; + bgcolor.blue=160; + screendata.mode=B_CMAP8; + screendata.spaces=B_8_BIT_640x480; + screendata.refresh_rate=60.0; + screendata.min_refresh_rate=60.0; + screendata.max_refresh_rate=60.0; + screendata.h_position=(uchar)50; + screendata.v_position=(uchar)50; + screendata.h_size=(uchar)50; + screendata.v_size=(uchar)50; + olddata=screendata; +} + +Workspace::~Workspace(void) +{ + workspace_count--; +} +//--------------------------------------------------- + + +//-----------------GLOBAL FUNCTION DEFS--------------- + +void init_desktop(int8 workspaces) +{ + workspace_count=workspaces; + if(workspace_count==0) + workspace_count++; + + // Instantiate and initialize display driver + gfxdriver=new ViewDriver(); + gfxdriver->Initialize(); + if(gfxdriver->IsInitialized()) + printf("Driver initialized\n"); + else + printf("Driver NOT initialized\n"); + + // Create the workspaces we're supposed to have + for(int8 i=0; iSetScreen(pactive_workspace->screendata.spaces); + + // Clear the screen + gfxdriver->Clear(80,85,152); + + // Draw a couple primitives just so we can see something + rgb_color color; + color.red=255; + color.green=0; + color.blue=0; + color.alpha=255; + gfxdriver->FillRect(BRect(10,10,50,50),color); + color.green=255; + gfxdriver->FillEllipse(BRect(50,10,100,50),color); +} + +void shutdown_desktop(void) +{ + int32 i,count=desktop.CountItems(); + for(i=0;iShutdown(); + delete gfxdriver; +} + +int32 count_workspaces(void) +{ + return workspace_count; +} + +void set_workspace_count(int32 count) +{ + //printf("set_workspace_count(%ld)\n",count); + if(count<0) + return; + + if(countworkspace_count || workspace<0) + return; + + Workspace *proposed=(Workspace *)desktop.ItemAt(workspace); + + if(proposed==NULL) + return; + + if(pactive_workspace->screendata.spaces != proposed->screendata.spaces) + { + gfxdriver->SetScreen(proposed->screendata.spaces); + } + +} + +const color_map *system_colors(void) +{ + return (const color_map *)&system_palette; +} + +status_t set_screen_space(int32 index, uint32 res, bool stick = true) +{ + //printf("set_screen_space(%ld,%lu, %s)\n",index,res,(stick==true)?"true":"false"); + return B_ERROR; +} + +status_t get_scroll_bar_info(scroll_bar_info *info) +{ + return B_ERROR; +} + +status_t set_scroll_bar_info(scroll_bar_info *info) +{ + //printf("set_scroll_bar_info()\n"); + return B_ERROR; +} + +bigtime_t idle_time() +{ + return 0; +} + +void run_select_printer_panel() +{ +} + +void run_add_printer_panel() +{ +} + +void run_be_about() +{ +} + +void set_focus_follows_mouse(bool follow) +{ + //printf("set_focus_follows_mouse(%s)\n",(follow==true)?"true":"false"); +} + +bool focus_follows_mouse() +{ + return false; +} diff --git a/src/servers/app/proto3/Desktop.h b/src/servers/app/proto3/Desktop.h new file mode 100644 index 0000000000..89cf4d2bff --- /dev/null +++ b/src/servers/app/proto3/Desktop.h @@ -0,0 +1,27 @@ +#ifndef _OBDESKTOP_H_ +#define _OBDESKTOP_H_ + +#include +#include +class DisplayDriver; + +void init_desktop(int8 workspaces); +void shutdown_desktop(void); +DisplayDriver *get_gfxdriver(void); + +typedef struct +{ + color_space mode; + BRect frame; + uint32 spaces; + float min_refresh_rate; + float max_refresh_rate; + float refresh_rate; + uchar h_position; + uchar v_position; + uchar h_size; + uchar v_size; +} screen_info; + + +#endif \ No newline at end of file diff --git a/src/servers/app/proto3/DirectDriver.cpp b/src/servers/app/proto3/DirectDriver.cpp new file mode 100644 index 0000000000..b451ae9b2e --- /dev/null +++ b/src/servers/app/proto3/DirectDriver.cpp @@ -0,0 +1,251 @@ +#include +#include "DirectDriver.h" +#include + +#ifndef ABS + #define ABS(a) (a<0)?a*-1:a +#endif + +OBAppServerScreen::OBAppServerScreen(status_t *error) + : BDirectWindow(BRect(100,60,740,540),"OBOS App Server, P3",B_TITLED_WINDOW, + B_NOT_RESIZABLE | B_NOT_ZOOMABLE) +{ + redraw=true; +} + +OBAppServerScreen::~OBAppServerScreen(void) +{ +} + +void OBAppServerScreen::MessageReceived(BMessage *msg) +{ + msg->PrintToStream(); + switch(msg->what) + { + case B_KEY_DOWN: +// Disconnect(); + QuitRequested(); + break; + default: + BDirectWindow::MessageReceived(msg); + break; + } +} + +bool OBAppServerScreen::QuitRequested(void) +{ + redraw=false; + be_app->PostMessage(B_QUIT_REQUESTED); + return true; +} + +int32 OBAppServerScreen::Draw(void *data) +{ + OBAppServerScreen *screen=(OBAppServerScreen *)data; + for(;;) + { + if(screen->connected && screen->redraw) + { + // Draw a sample background + screen->redraw=false; + } + } + return 1; +} + +void OBAppServerScreen::DirectConnected(direct_buffer_info *dbinfo) +{ +/* if(ok==true) + { + connected=true; + gcinfo=CardInfo(); + for(int8 i=0;i<48;i++) + gchooks[i]=CardHookAt(i); + } + else + connected=false; +*/ +} + +DirectDriver::DirectDriver(void) +{ +// printf("DirectDriver()\n"); +// old_space=B_32_BIT_800x600; +} + +DirectDriver::~DirectDriver(void) +{ + printf("~DirectDriver()\n"); + winscreen->Lock(); + winscreen->Close(); +} + +void DirectDriver::Initialize(void) +{ +/* printf("DirectDriver::Initialize()\n"); + status_t stat; + winscreen=new OBAppServerScreen(&stat); + if(stat==B_OK) + winscreen->Show(); + else + delete winscreen; +*/ +} + +void DirectDriver::SafeMode(void) +{ +/* printf("DirectDriver::SafeMode()\n"); +// SetScreen(B_8_BIT_640x480); + SetScreen(B_32_BIT_800x600); + Reset(); +*/ +} + +void DirectDriver::Reset(void) +{ +/* printf("DirectDriver::Reset()\n"); + if(winscreen->connected==true) + Clear(51,102,160); +*/ +} + +void DirectDriver::SetScreen(uint32 space) +{ +// printf("DirectDriver::SetScreen(%lu)\n",space); +// winscreen->SetSpace(space); +} + +void DirectDriver::Clear(uint8 red, uint8 green, uint8 blue) +{ +/* // This simply clears the entire screen, utilizing a string and + // memcpy to speed things up in a minor way + printf("DirectDriver::Clear(%d,%d,%d)\n",red,green,blue); + + if(winscreen->connected==false) + return; + + int i,imax, + length=winscreen->gcinfo->bytes_per_row; + int8 fillstring[length]; + + + switch(winscreen->gcinfo->bits_per_pixel) + { + case 32: + { + int32 color,*index32; + + // order is going to be BGRA or ARGB + if(winscreen->gcinfo->rgba_order[0]=='B') + { + // Create the number to quickly create the string + + // BBGG RRAA in RAM => 0xRRAA BBGG + color= (int32(red) << 24) + 0xFF0000L + (int32(blue) << 8) + green; + } + else + { + // Create the number to quickly create the string + + // AARR GGBB in RAM + color= 0xFF000000L + (int32(red) << 16) + (int32(green) << 8) + blue; + } + + // fill the string with the appropriate values + index32=(int32 *)fillstring; + imax=winscreen->gcinfo->width; + + for(i=0;igcinfo->rgba_order[0]=='B') + { + // Little-endian + // G[2:0],B[4:0] R[4:0],G[5:3] + + // Ick. Gotta love all that shifting and masking. :( + color= (int16((green & 7)) << 13) + + (int16((blue & 31)) << 8) + + (int16((red & 31)) << 4) + + (int16(green & 56)); + } + else + { + // Big-endian + // R[4:0],G[5:3] G[2:0],B[4:0] + color= (int16(red & 31) << 11) + + (int16(green & 56) << 8) + + (int16(green & 3) << 5) + + (blue & 31); + } + break; + } + case 15: + { + + // RGBA_15: + // G[2:0],B[4:0] A[0],R[4:0],G[4:3] + + // RGBA_15_BIG: + // A[0],R[4:0],G[4:3] G[2:0],B[4:0] + break; + } +*/ +/* case 8: + { + // This is both the easiest and hardest: + // We fill using memset(), but we have to find the closest match to the + // color we've been given. Yuck. + + // Find the closest match by comparing the differences in values for each + // color. This function was not intended to be called rapidly, so speed is + // not much of an issue at this point. + int8 closest=0; + int16 closest_delta=765, delta; // (255 * 3) + + // Get the current palette + rgb_color *list=winscreen->ColorList(); + for(i=0;i<256;i++) + { + delta=ABS(list->red-red)+ABS(list->green-green)+ABS(list->blue-blue); + if(deltagcinfo->frame_buffer,closest, + winscreen->gcinfo->bytes_per_row * winscreen->gcinfo->height); + + // Nothing left to do! + return; + break; + } + default: + { + printf("Unsupported bit depth %d in DirectDriver::Clear(r,g,b)!!\n",winscreen->gcinfo->bits_per_pixel); + return; + } + } + imax=winscreen->gcinfo->height; + + // a pointer to increment for the screen copy. Faster than doing a multiply + // each iteration + int8 *pbuffer=(int8*)winscreen->gcinfo->frame_buffer; + for(i=0;i +#include +#include +#include +#include "DisplayDriver.h" + +class OBAppServerScreen : public BDirectWindow +{ +public: + OBAppServerScreen(status_t *error); + ~OBAppServerScreen(void); + virtual void MessageReceived(BMessage *msg); + virtual bool QuitRequested(void); + static int32 Draw(void *data); + virtual void DirectConnected(direct_buffer_info *dbinfo); + + int32 DrawID; + bool redraw,connected; + graphics_card_info *gcinfo; + graphics_card_hook *gchooks; +}; + +class DirectDriver : public DisplayDriver +{ +public: + DirectDriver(void); + virtual ~DirectDriver(void); + + virtual void Initialize(void); // Sets the driver + virtual void SafeMode(void); // Easy-access functions for common tasks + virtual void Reset(void); + virtual void SetScreen(uint32 space); + virtual void Clear(uint8 red,uint8 green,uint8 blue); +// virtual void SetPixel(int x, int y, rgb_color color); +// virtual void StrokeEllipse(BRect rect, rgb_color color); + OBAppServerScreen *winscreen; + +protected: + // Original screen info + uint32 old_space; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto3/DisplayDriver.cpp b/src/servers/app/proto3/DisplayDriver.cpp new file mode 100644 index 0000000000..671d64ef97 --- /dev/null +++ b/src/servers/app/proto3/DisplayDriver.cpp @@ -0,0 +1,183 @@ +/* + DisplayDriver.cpp + Modular class to allow the server to not care what the ultimate output is + for graphics calls. +*/ +#include "DisplayDriver.h" +#include "ServerCursor.h" + +DisplayDriver::DisplayDriver(void) +{ + is_initialized=false; + cursor_visible=false; + show_on_move=false; + locker=new BLocker(); +} + +DisplayDriver::~DisplayDriver(void) +{ + delete locker; +} + +void DisplayDriver::Initialize(void) +{ // Loading loop to find proper driver or other setup for the driver +} + +void DisplayDriver::Shutdown(void) +{ // For use by subclasses +} + +bool DisplayDriver::IsInitialized(void) +{ // Let us know whether things worked out ok + return is_initialized; +} + +void DisplayDriver::SafeMode(void) +{ // Set video mode to 640x480x256 mode +} + +void DisplayDriver::Reset(void) +{ // Intended to reload and restart driver. Defaults to a safe mode +} + +void DisplayDriver::SetScreen(uint32 space) +{ // Set the screen to a particular mode +} + +int32 DisplayDriver::GetHeight(void) +{ // Gets the height of the current mode + return ginfo->height; +} + +int32 DisplayDriver::GetWidth(void) +{ // Gets the width of the current mode + return ginfo->width; +} + +int DisplayDriver::GetDepth(void) +{ // Gets the color depth of the current mode + return ginfo->bytes_per_row; +} + +void DisplayDriver::Clear(uint8 red,uint8 green,uint8 blue) +{ +} + +void DisplayDriver::StrokeRect(BRect rect, rgb_color color) +{ +} + +void DisplayDriver::FillRect(BRect rect, rgb_color color) +{ +} + +void DisplayDriver::StrokeEllipse(BRect rect, rgb_color color) +{ +} + +void DisplayDriver::FillEllipse(BRect rect,rgb_color color) +{ +} + +void DisplayDriver::SetPixel(int x, int y, rgb_color color) +{ // Internal function utilized by other functions to draw to the buffer + // Will eventually be an inline function +} + +void DisplayDriver::SetCursor(ServerCursor *cursor) +{ +} + +void DisplayDriver::SetCursor(int32 value) +{ // This is used just to provide an easy way of setting one of the default cursors + // Then again, I may just get rid of this thing. +} + +void DisplayDriver::ShowCursor(void) +{ +} + +void DisplayDriver::HideCursor(void) +{ +} + +void DisplayDriver::ObscureCursor(void) +{ // Hides cursor until mouse is moved +} + +bool DisplayDriver::IsCursorHidden(void) +{ + return false; +} + +void DisplayDriver::MoveCursorTo(int x, int y) +{ +} + +void DisplayDriver::Blit(BPoint dest, ServerBitmap *sourcebmp, ServerBitmap *destbmp) +{ // Screen-to-screen bitmap copying +} + +void DisplayDriver::DrawBitmap(ServerBitmap *bitmap) +{ +} + +void DisplayDriver::DrawChar(char c, int x, int y) +{ +} + +void DisplayDriver::DrawString(char *string, int length, int x, int y) +{ +} + +void DisplayDriver::StrokeArc(int centerx, int centery, int xradius, int yradius) +{ +} + +void DisplayDriver::FillArc(int centerx, int centery, int xradius, int yradius) +{ +} + +void DisplayDriver::StrokePolygon(int *x, int *y, int numpoints, bool is_closed) +{ +} + +void DisplayDriver::FillPolygon(int *x, int *y, int numpoints, bool is_closed) +{ +} + +void DisplayDriver::StrokeRegion(ServerRegion *region) +{ +} + +void DisplayDriver::FillRegion(ServerRegion *region) +{ +} + +void DisplayDriver::StrokeRoundRect(ServerRect *rect) +{ +} + +void DisplayDriver::FillRoundRect(ServerRect *rect) +{ +} + +void DisplayDriver::StrokeShape(ServerShape *shape) +{ +} + +void DisplayDriver::FillShape(ServerShape *shape) +{ +} + +void DisplayDriver::StrokeTriangle(int *x, int *y) +{ +} + +void DisplayDriver::FillTriangle(int *x, int *y) +{ +} + +void DisplayDriver::MoveTo(int x, int y) +{ // Moves the graphics pen to this position +} diff --git a/src/servers/app/proto3/DisplayDriver.h b/src/servers/app/proto3/DisplayDriver.h new file mode 100644 index 0000000000..1d1c0b9a11 --- /dev/null +++ b/src/servers/app/proto3/DisplayDriver.h @@ -0,0 +1,111 @@ +#ifndef _GFX_DRIVER_H_ +#define _GFX_DRIVER_H_ + +#include +#include +#include +#include "Desktop.h" + +class ServerBitmap; +class ServerRegion; +class ServerShape; +class ServerRect; +class ServerCursor; + +#ifndef ROUND + #define ROUND(a) ( (a-long(a))>=.5)?(long(a)+1):(long(a)) +#endif + +typedef struct +{ + uchar *xormask, *andmask; + int32 width, height; + int32 hotx, hoty; + +} cursor_data; + +#ifndef HOOK_DEFINE_CURSOR + +#define HOOK_DEFINE_CURSOR 0 +#define HOOK_MOVE_CURSOR 1 +#define HOOK_SHOW_CURSOR 2 +#define HOOK_DRAW_LINE_8BIT 3 +#define HOOK_DRAW_LINE_16BIT 12 +#define HOOK_DRAW_LINE_32BIT 4 +#define HOOK_DRAW_RECT_8BIT 5 +#define HOOK_DRAW_RECT_16BIT 13 +#define HOOK_DRAW_RECT_32BIT 6 +#define HOOK_BLIT 7 +#define HOOK_DRAW_ARRAY_8BIT 8 +#define HOOK_DRAW_ARRAY_16BIT 14 // Not implemented in current R5 drivers +#define HOOK_DRAW_ARRAY_32BIT 9 +#define HOOK_SYNC 10 +#define HOOK_INVERT_RECT 11 + +#endif + +class ServerCursor; + +class DisplayDriver +{ +public: + DisplayDriver(void); + virtual ~DisplayDriver(void); + + virtual void Initialize(void); // Sets the driver + virtual void Shutdown(void); // You never know when you'll need this + + virtual void SafeMode(void); // Easy-access functions for common tasks + virtual void Reset(void); + virtual void Clear(uint8 red,uint8 green,uint8 blue); + + // Settings functions + virtual void SetScreen(uint32 space); + virtual int32 GetHeight(void); + virtual int32 GetWidth(void); + virtual int GetDepth(void); + + // Drawing functions + virtual void SetPixel(int x, int y, rgb_color color); + virtual void DrawBitmap(ServerBitmap *bitmap); + virtual void DrawChar(char c, int x, int y); + virtual void DrawString(char *string, int length, int x, int y); + virtual void StrokeRect(BRect rect,rgb_color color); + virtual void FillRect(BRect rect, rgb_color color); + virtual void StrokeEllipse(BRect rect,rgb_color color); + virtual void FillEllipse(BRect rect,rgb_color color); + virtual void StrokeArc(int centerx, int centery, int xradius, int yradius); + virtual void FillArc(int centerx, int centery, int xradius, int yradius); + virtual void StrokePolygon(int *x, int *y, int numpoints, bool is_closed); + virtual void FillPolygon(int *x, int *y, int numpoints, bool is_closed); + virtual void StrokeRegion(ServerRegion *region); + virtual void FillRegion(ServerRegion *region); + virtual void StrokeRoundRect(ServerRect *rect); + virtual void FillRoundRect(ServerRect *rect); + virtual void StrokeShape(ServerShape *shape); + virtual void FillShape(ServerShape *shape); + virtual void StrokeTriangle(int *x, int *y); + virtual void FillTriangle(int *x, int *y); + virtual void MoveTo(int x, int y); + virtual void Blit(BPoint dest, ServerBitmap *src, ServerBitmap *dest); + + virtual void SetCursor(int32 value); + virtual void SetCursor(ServerCursor *cursor); + virtual void ShowCursor(void); + virtual void MoveCursorTo(int x, int y); + virtual void HideCursor(void); + virtual void ObscureCursor(void); + virtual bool IsCursorHidden(void); + + + virtual bool IsInitialized(void); + graphics_card_hook ghooks[48]; + graphics_card_info *ginfo; + +protected: + bool is_initialized, cursor_visible, show_on_move; + ServerCursor *current_cursor; + BLocker *locker; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto3/Globals.h b/src/servers/app/proto3/Globals.h new file mode 100644 index 0000000000..2753cad1aa --- /dev/null +++ b/src/servers/app/proto3/Globals.h @@ -0,0 +1,7 @@ +#ifndef _SERVER_GLOBALS_H_ +#define _SERVER_GLOBALS_H_ + +#include +BList *gBitmaplist, *gLayerlist; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto3/Layer.cpp b/src/servers/app/proto3/Layer.cpp new file mode 100644 index 0000000000..4130a02e2e --- /dev/null +++ b/src/servers/app/proto3/Layer.cpp @@ -0,0 +1,74 @@ +#include "Layer.h" + +Layer::Layer(ServerWindow *Win, const char *Name, BRect &Frame, int32 Flags) +{ +} + +Layer::Layer(ServerBitmap *Bitmap) +{ +} + +Layer::~Layer(void) +{ +} + +void Layer::Initialize(void) +{ +} + +void Layer::Show(void) +{ +} + +void Layer::Hide(void) +{ +} + +bool Layer::IsVisible(void) +{ + return false; +} + +void Layer::Update(bool ForceUpdate) +{ +} + +bool Layer::IsBackground(void) +{ + return false; +} + +void Layer::SetFrame(const BRect &Rect) +{ +} + +BRect Layer::Frame(void) +{ + return BRect(0,0,0,0); +} + +BRect Layer::Bounds(void) +{ + return BRect(0,0,0,0); +} + +void Layer::Invalidate(const BRect &Rect) +{ +} + +void Layer::AddRegion(BRegion *Region) +{ +} + +void Layer::RemoveRegions(void) +{ +} + +void Layer::UpdateRegions(bool ForceUpdate=true, bool Root=true) +{ +} + +void Layer::Draw(const BRect &Rect) +{ +} + diff --git a/src/servers/app/proto3/Layer.h b/src/servers/app/proto3/Layer.h new file mode 100644 index 0000000000..603d5642a3 --- /dev/null +++ b/src/servers/app/proto3/Layer.h @@ -0,0 +1,60 @@ +#ifndef _LAYER_H_ +#define _LAYER_H_ + +#include +#include +#include + +class ServerBitmap; +class ServerWindow; + +class Layer +{ +public: + Layer(ServerWindow *Win, const char *Name, BRect &Frame, int32 Flags); + Layer(ServerBitmap *Bitmap); + virtual ~Layer(void); + + void Initialize(void); + void Show(void); + void Hide(void); + bool IsVisible(void); + void Update(bool ForceUpdate); + + bool IsBackground(void); + + virtual void SetFrame(const BRect &Rect); + BRect Frame(void); + BRect Bounds(void); + + void Invalidate(const BRect &Rect); + void AddRegion(BRegion *Region); + void RemoveRegions(void); + void UpdateRegions(bool ForceUpdate=true, bool Root=true); + + // Render functions: + virtual void Draw(const BRect &Rect); + + const char *name; + int32 handle; + ServerWindow *window; // Window associated with this. NULL for background layer + ServerBitmap *bitmap; // Blasted to screen on redraw. We render to this + + BRect frame; + + BRegion *visible, // Everything currently visible + *full, // The complete region + *update; // Area to be updated at next redraw + + int32 flags; // Various flags for behavior + + // Render state: + BPoint penpos; + rgb_color high, low, erase; + + int32 drawingmode; +}; + + Layer *FindLayer(int32 Handle); + +#endif diff --git a/src/servers/app/proto3/PortLink.cpp b/src/servers/app/proto3/PortLink.cpp new file mode 100644 index 0000000000..8fba724569 --- /dev/null +++ b/src/servers/app/proto3/PortLink.cpp @@ -0,0 +1,438 @@ +/* + PortLink.cpp: + A helper class for port-based messaging + +------------------------------------------------------------------------ +How it works: + The class utilizes a fixed-size array of PortLinkData object pointers. When +data is attached, a new PortLinkData object is allocated and a copy of the +passed data is created inside it. When the time comes for the message to be sent, +the data is pieced together into a flattened array and written to the port. +------------------------------------------------------------------------ +Data members: + +*attachments[] - fixed-size array of pointers used to hold the attached data +opcode - message value which is sent along with any data +target - port to which the message is sent when Flush() is called +replyport - port used with synchronous messaging - FlushWithReply() +bufferlength - total bytes taken up by attachments +num_attachments - internal variable which is used to track which "slot" + will be the next one to receive an attachment object +*/ + +#include "PortLink.h" +#include +#include +#include + +//#define PLDEBUG + +// Internal data storage class for holding attached data whilst it is waiting +// to be Flattened() and then Flushed(). There is no need for this to be called outside +// the PortLink class. +class PortLinkData +{ +public: + PortLinkData(void); + ~PortLinkData(void); + bool Set(void *data, size_t size); + char *buffer; + size_t buffersize; +}; + +PortLink::PortLink(port_id port) +{ + // For this class to be useful (and to prevent a lot of init problems) + // we require a port in the constructor + target=port; + + // We start out without any data attached to the port message + num_attachments=0; + opcode=0; + bufferlength=0; + replyport=create_port(30,"PortLink reply port"); +} + +PortLink::~PortLink(void) +{ + // If, for some odd reason, this is deleted with something attached, + // free the memory used by the attachments. We do not flush the queue + // because the port may no longer be valid in cases such as the app + // is in the process of quitting + MakeEmpty(); +} + +void PortLink::SetOpCode(int32 code) +{ + // Sets the message code. This does not change once the message is sent. + // Another call to SetOpCode() is required for such things. + opcode=code; +} + +void PortLink::SetPort(port_id port) +{ + // Sets the target port. While not necessary in most uses, this exists + // mostly to prevent flexibility problems + target=port; +} + +port_id PortLink::GetPort(void) +{ + // Simply returns the port at which the object is pointed. + return target; +} + +void PortLink::Flush(bigtime_t timeout=B_INFINITE_TIMEOUT) +{ + // Fires a message off to the target, complete with attachments. NOTE: + // the recipient must delete all attachments, being the PortLink object assumes + // no responsiblity for the attachments once the message is sent. + int8 *msgbuffer; + int32 size; + + if(num_attachments>0) + { + FlattenData(&msgbuffer,&size); + + // Dump message to port, reset attachments, and clean up + if(timeout!=B_INFINITE_TIMEOUT) + write_port_etc(target,opcode,msgbuffer,size,B_TIMEOUT, timeout); + else + write_port(target,opcode,msgbuffer,size); + MakeEmpty(); + } + else + { + if(timeout!=B_INFINITE_TIMEOUT) + write_port_etc(target,opcode,NULL,0,B_TIMEOUT, timeout); + else + write_port(target,opcode,NULL,0); + } +} + +int8* PortLink::FlushWithReply(int32 *code, status_t *status, ssize_t *buffersize, bigtime_t timeout=B_INFINITE_TIMEOUT) +{ + // Fires a message to the target and then waits for a reply. The target will + // receive a message with the first item being the port_id to reply to. + // NOTE: like Flush(), any attached data must be deleted. + + // Effectively, an Attach() call inlined for changes + + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + { + *status=B_ERROR; + return NULL; + } + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&replyport,sizeof(port_id))) + { + bufferlength+=sizeof(port_id); + } + else + { + delete pld; + *status=B_ERROR; + return NULL; + } + + // Flatten() inlined to make some necessary changes + int8 *buffer=new int8[bufferlength]; + int8 *bufferindex=buffer; + size_t size=0; + + // attach our port_id first + memcpy(bufferindex, pld->buffer, pld->buffersize); + bufferindex += pld->buffersize; + size+=pld->buffersize; + + // attach everything else + for(int i=0;ibuffer, pld->buffersize); + bufferindex += pld->buffersize; + size+=pld->buffersize; + } + + // Flush the thing....FOOSH! :P + write_port(target,opcode,buffer,size); + MakeEmpty(); + delete buffer; + + // Now we wait for the reply + if(timeout==B_INFINITE_TIMEOUT) + { + *buffersize=port_buffer_size(replyport); + if(*buffersize>0) + buffer=(int8*)new int8[*buffersize]; + read_port(replyport,code, buffer, *buffersize); + } + else + { + *buffersize=port_buffer_size_etc(replyport,0,timeout); + if(*buffersize==B_TIMED_OUT) + { + *status=*buffersize; + return NULL; + } + if(*buffersize>0) + buffer=(int8*)new int8[*buffersize]; + read_port(replyport,code, buffer, *buffersize); + } + + // We got this far, so we apparently have some data + *status=B_OK; + return buffer; +} + +void PortLink::Attach(void *data, size_t size) +{ + // This is the member called to attach data to a message. Attachments are + // treated to be in 'Append' mode, tacking on each attached piece of data + // to the end of the list. + + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + if(size==0) + return; + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +// These functions were added for a major convenience in passing common types +// Eventually, I'd like to templatize these, but for now, this'll do + +void PortLink::Attach(int32 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int32); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(int16 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int16); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(int8 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int8); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(float data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(float); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(bool data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(bool); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(BRect data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(BRect); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(BPoint data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(BPoint); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::FlattenData(int8 **buffer,int32 *size) +{ + // This function is where all the magic happens, but it is strictly internal. + // It iterates through each PortLinkData object and copies it to the main buffer + // which ends up, ultimately, being written to the PortLink's target port. + + // skip if there aree no attachments + if(bufferlength<1) + return; + + *buffer=new int8[bufferlength]; + int8 *bufferindex=*buffer; + PortLinkData *pld; + *size=0; + + for(int i=0;ibuffer, pld->buffersize); + bufferindex += pld->buffersize; + *size+=pld->buffersize; + } +} + +void PortLink::MakeEmpty(void) +{ + // Nukes all the attachments currently held by the PortLink class + if(num_attachments!=0) + { + for(int i=0; i0) + free(buffer); +} + +bool PortLinkData::Set(void *data, size_t size) +{ + // Function copies the passed to the internal buffers for storage + if(size>0 && buffersize==0 && data!=NULL) + { + buffer=(char *)malloc(size); + if(buffer==NULL) + return false; + memcpy(buffer, data, size); + buffersize=size; + return true; + } + return false; +} diff --git a/src/servers/app/proto3/PortLink.h b/src/servers/app/proto3/PortLink.h new file mode 100644 index 0000000000..9f5432daab --- /dev/null +++ b/src/servers/app/proto3/PortLink.h @@ -0,0 +1,43 @@ +#ifndef _PORTLINK_H_ +#define _PORTLINK_H_ + +#include +#include +#include +#include + +#ifndef _PORTLINK_BUFFERSIZE +#define _PORTLINK_MAX_ATTACHMENTS 50 +#endif + +class PortLinkData; + +class PortLink +{ +public: + PortLink(port_id port); + ~PortLink(void); + void SetOpCode(int32 code); + void SetPort(port_id port); + port_id GetPort(void); + void Flush(bigtime_t timeout=B_INFINITE_TIMEOUT); + int8* FlushWithReply(int32 *code, status_t *status, ssize_t *buffersize, + bigtime_t timeout=B_INFINITE_TIMEOUT); + void Attach(void *data, size_t size); + void Attach(int32 data); + void Attach(int16 data); + void Attach(int8 data); + void Attach(float data); + void Attach(bool data); + void Attach(BRect data); + void Attach(BPoint data); + void MakeEmpty(void); +protected: + void FlattenData(int8 **buffer,int32 *size); + port_id target, replyport; + int32 opcode, bufferlength; + int num_attachments; + PortLinkData *attachments[_PORTLINK_MAX_ATTACHMENTS]; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto3/README b/src/servers/app/proto3/README new file mode 100644 index 0000000000..95e9d670c7 --- /dev/null +++ b/src/servers/app/proto3/README @@ -0,0 +1,9 @@ +OpenBeOS App Server Test Prototype #3 + +This is an example of both a work in progress and a lot of research at the same time. Many of the concepts used in this prototype will be used in the real server. It doesn't do much, but the fact that it exists and does what it does is the result of a *lot* of work. + +This prototype does everything the second one did PLUS has much of the foundation for graphics in place. Graphics updates are slow and there is a lot of flicker, but this is expected - the driver-access module used also emulates the Input Server and utilizes BeOS' app_server to provide all the drawing. + +The code is reasonably (IMHO) well-commented and should be easy to understand at first glance. Also included are some extra files which I didn't feel like throwing out or are in place for future development. ;D Enjoy. + +--DarkWyrm \ No newline at end of file diff --git a/src/servers/app/proto3/ServerApp.cpp b/src/servers/app/proto3/ServerApp.cpp new file mode 100644 index 0000000000..279ec17bc3 --- /dev/null +++ b/src/servers/app/proto3/ServerApp.cpp @@ -0,0 +1,155 @@ +/* + ServerApp.cpp + Class which works with a BApplication. Handles all messages coming + from and going to its application. +*/ + +#include +#include "ServerApp.h" +#include "ServerProtocol.h" +#include "PortLink.h" +#include +#include + +ServerApp::ServerApp(port_id msgport, char *signature) +{ + //printf("New ServerApp %s for app at port %ld\n",signature,msgport); + + // need to copy the signature because the message buffer + // owns the copy which we are passed as a parameter. + if(signature) + { + app_sig=new char[strlen(signature)]; + sprintf(app_sig,signature); + } + else + { + app_sig=new char[strlen("Application")]; + sprintf(app_sig,"Application"); + } + + // sender is the monitored app's event port + sender=msgport; + applink=new PortLink(sender); + + // receiver is the port to which the app sends messages for the server + receiver=create_port(30,app_sig); + //printf("ServerApp port for app %s is at %ld\n",app_sig,receiver); + if(receiver==B_NO_MORE_PORTS) + { + // uh-oh. We have a serious problem. Tell the app to quit + applink->SetOpCode(B_QUIT_REQUESTED); + applink->Flush(); + } + else + { + // Everything checks out, so tell the application + // where to send future messages + applink->SetOpCode(SET_SERVER_PORT); + applink->Attach(&receiver,sizeof(port_id)); + applink->Flush(); + } +} + +ServerApp::~ServerApp(void) +{ + //printf("%s::~ServerApp()\n",app_sig); + delete app_sig; + delete applink; +} + +bool ServerApp::Run(void) +{ + // Unlike a BApplication, a ServerApp is *supposed* to return immediately + // when its Run function is called. + monitor_thread=spawn_thread(MonitorApp,app_sig,B_NORMAL_PRIORITY,this); + if(monitor_thread==B_NO_MORE_THREADS || monitor_thread==B_NO_MEMORY) + return false; + resume_thread(monitor_thread); + return true; +} + +int32 ServerApp::MonitorApp(void *data) +{ + ServerApp *app=(ServerApp *)data; + app->Loop(); + exit_thread(0); + return 0; +} + +void ServerApp::Loop(void) +{ + // Message-dispatching loop for the ServerApp + + //printf("%s::MainLoop()\n",app_sig); + + int32 msgcode; + int8 *msgbuffer=NULL; + ssize_t buffersize,bytesread; + + for(;;) + { + buffersize=port_buffer_size(receiver); + + if(buffersize>0) + { + // buffers are PortLink messages. Allocate necessary buffer and + // we'll cast it as a BMessage. + msgbuffer=new int8[buffersize]; + bytesread=read_port(receiver,&msgcode,msgbuffer,buffersize); + } + else + bytesread=read_port(receiver,&msgcode,NULL,0); + + if (bytesread != B_BAD_PORT_ID && bytesread != B_TIMED_OUT && bytesread != B_WOULD_BLOCK) + { + switch(msgcode) + { + case B_QUIT_REQUESTED: + { + // Our BApplication sent us this message when it quit. + // We need to ask the app_server to delete our monitor + port_id serverport=find_port(SERVER_PORT_NAME); + if(serverport==B_NAME_NOT_FOUND) + { + //printf("PANIC: ServerApp %s could not find the app_server port!\n",app_sig); + break; + } + //printf("ServerApp %s quitting\n",app_sig); + applink->SetPort(serverport); + applink->SetOpCode(DELETE_APP); + applink->Attach(&monitor_thread,sizeof(thread_id)); + applink->Flush(); + break; + } + case QUIT_APP: + { + // This message is received from the app_server thread + // because the server was asked to quit. Thus, we + // ask all apps to quit. This is NOT the same as system + // shutdown + + //printf("ServerApp asking %s to quit\n",app_sig); + applink->SetOpCode(B_QUIT_REQUESTED); + applink->Flush(); + break; + } + default: + //printf("Server received unexpected code %ld\n",msgcode); + break; + } + + } + + if(buffersize>0) + delete msgbuffer; + + if(msgcode==B_QUIT_REQUESTED) + break; + } +} + +void ServerApp::DispatchMessage(BMessage *msg) +{ +} + diff --git a/src/servers/app/proto3/ServerApp.h b/src/servers/app/proto3/ServerApp.h new file mode 100644 index 0000000000..cf450ccc9c --- /dev/null +++ b/src/servers/app/proto3/ServerApp.h @@ -0,0 +1,25 @@ +#ifndef _SRVAPP_H_ +#define _SRVAPP_H_ + +#include +class BMessage; +class PortLink; + +class ServerApp +{ +public: + ServerApp(port_id msgport, char *signature); + ~ServerApp(void); + + bool Run(void); + static int32 MonitorApp(void *data); + void Loop(void); + void DispatchMessage(BMessage *msg); + + port_id sender,receiver; + char *app_sig; + thread_id monitor_thread; + PortLink *applink; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto3/ServerBitmap.cpp b/src/servers/app/proto3/ServerBitmap.cpp new file mode 100644 index 0000000000..61cc689556 --- /dev/null +++ b/src/servers/app/proto3/ServerBitmap.cpp @@ -0,0 +1,214 @@ +/* + ServerBitmap.cpp + Bitmap class which is intended to provide an easy way to package all the + data associated with a picture. It's very low-level, so there's still + plenty to do when coding with 'em. Also, they're used to access draw on the + frame buffer in a relatively easy way. +*/ + +// These three includes for ServerBitmap(const char *path_to_image_file) only +#include +#include +#include + +#include +#include "ServerBitmap.h" +#include "Desktop.h" + +ServerBitmap::ServerBitmap(BRect rect,color_space space,int32 BytesPerLine=0) +{ + width=rect.IntegerWidth()+1; + height=rect.IntegerHeight()+1; + cspace=space; + is_vram=false; + + HandleSpace(space, BytesPerLine); + buffer=new uint8[bytesperline*height]; + driver=get_gfxdriver(); +} + +ServerBitmap::ServerBitmap(int32 w,int32 h,color_space space,int32 BytesPerLine=0) +{ + width=w; + height=h; + cspace=space; + is_vram=false; + + HandleSpace(space, BytesPerLine); + buffer=new uint8[bytesperline*height]; + driver=get_gfxdriver(); +} + +ServerBitmap::ServerBitmap(void) +{ + is_vram=true; + UpdateSettings(); +} + +// This particular version is not intended for use except for testing purposes. +// It loads a BBitmap and copies it to the ServerBitmap. Probably will disappear +// when the *real* server is written +ServerBitmap::ServerBitmap(const char *path) +{ + BBitmap *bmp=BTranslationUtils::GetBitmap(path); + assert(bmp!=NULL); + + if(bmp==NULL) + { + width=0; + height=0; + cspace=B_NO_COLOR_SPACE; + bytesperline=0; + } + else + { + width=bmp->Bounds().IntegerWidth(); + height=bmp->Bounds().IntegerHeight(); + cspace=bmp->ColorSpace(); + bytesperline=bmp->BytesPerRow(); + buffer=new uint8[bmp->BitsLength()]; + memcpy(buffer,(void *)bmp->Bits(),bmp->BitsLength()); + } +} + +ServerBitmap::~ServerBitmap(void) +{ + if(!is_vram) + delete buffer; +} + +void ServerBitmap::UpdateSettings(void) +{ + // This is only used when the object is pointing to the frame buffer + driver=get_gfxdriver(); + bpp=driver->GetDepth(); + width=driver->GetWidth(); + height=driver->GetHeight(); +} + +void ServerBitmap::HandleSpace(color_space space, int32 BytesPerLine) +{ + // Function written to handle color space setup which is required + // by the two "normal" constructors + + // Big convoluted mess just to handle every color space and dword align + // the buffer + switch(space) + { + // Buffer is dword-aligned, so nothing need be done + // aside from allocate the memory + case B_RGB32: + case B_RGBA32: + case B_RGB32_BIG: + case B_RGBA32_BIG: + case B_UVL32: + case B_UVLA32: + case B_LAB32: + case B_LABA32: + case B_HSI32: + case B_HSIA32: + case B_HSV32: + case B_HSVA32: + case B_HLS32: + case B_HLSA32: + case B_CMY32: + case B_CMYA32: + case B_CMYK32: + + // 24-bit = 32-bit with extra 8 bits ignored + case B_RGB24_BIG: + case B_RGB24: + case B_LAB24: + case B_UVL24: + case B_HSI24: + case B_HSV24: + case B_HLS24: + case B_CMY24: + { + if(BytesPerLine<(width*4)) + bytesperline=width*4; + else + bytesperline=BytesPerLine; + bpp=32; + break; + } + // Calculate size and dword-align + + // 1-bit + case B_GRAY1: + { + int32 numbytes=width>>3; + if((width % 8) != 0) + numbytes++; + if(BytesPerLine +#include +#include "DisplayDriver.h" + +class ServerBitmap +{ +public: + ServerBitmap(BRect rect,color_space space,int32 BytesPerLine=0); + ServerBitmap(int32 w,int32 h,color_space space,int32 BytesPerLine=0); + ServerBitmap(void); + ServerBitmap(const char *path); + ~ServerBitmap(void); + void UpdateSettings(void); + + int32 width,height; + int32 bytesperline; + color_space cspace; + int bpp; + uint8 *buffer; + +protected: + void HandleSpace(color_space space, int32 BytesPerLine); + DisplayDriver *driver; + bool is_vram; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto3/ServerCursor.cpp b/src/servers/app/proto3/ServerCursor.cpp new file mode 100644 index 0000000000..29fad12f0c --- /dev/null +++ b/src/servers/app/proto3/ServerCursor.cpp @@ -0,0 +1,76 @@ +/* + ServerCursor.cpp + This is the server-side class used to handle cursors. Note that it + will handle the R5 cursors, but it will also handle taking a bitmap. + + This is new code, and there may be changes to the API before it settles + in. +*/ + +#include "ServerCursor.h" +#include "ServerBitmap.h" + +ServerCursor::ServerCursor(ServerBitmap *bmp) +{ + is_initialized=false; + position.Set(0,0); + SetCursor(bmp); +} + +ServerCursor::ServerCursor(int8 *data, color_space space) +{ + // For handling the idiot R5 API data format + + is_initialized=false; + position.Set(0,0); + SetCursor(data,space); +} + +ServerCursor::~ServerCursor(void) +{ + if(is_initialized) + { + delete bitmap; + delete mask; + } +} + +void ServerCursor::SetCursor(int8 *data, color_space space) +{ + // 68-byte array used in R5 for holding cursors. + // This API has serious problems and should be deprecated(but supported) + // in a future release, perhaps right after the first one + if(is_initialized) + { + delete bitmap; + delete mask; + } + cspace=space; + + bitmap=new ServerBitmap(16,16,B_GRAY1); + mask=new ServerBitmap(16,16,B_GRAY1); + width=16; + height=16; + bounds.Set(0,0,15,15); +} + +void ServerCursor::SetCursor(ServerBitmap *bmp) +{ + if(is_initialized) + { + delete bitmap; + delete mask; + } + cspace=bmp->cspace; + + bitmap=new ServerBitmap(16,16,B_GRAY1); + mask=new ServerBitmap(16,16,B_GRAY1); + width=bmp->width; + height=bmp->height; + bounds.Set(0,0,bmp->width-1,bmp->height-1); +} + +void ServerCursor::MoveTo(int32 x, int32 y) +{ + position.Set(x,y); +} diff --git a/src/servers/app/proto3/ServerCursor.h b/src/servers/app/proto3/ServerCursor.h new file mode 100644 index 0000000000..17c23f661c --- /dev/null +++ b/src/servers/app/proto3/ServerCursor.h @@ -0,0 +1,29 @@ +#ifndef _SERVER_SPRITE_H +#define _SERVER_SPRITE_H + +#include +#include + +class ServerBitmap; + +class ServerCursor +{ +public: + ServerCursor(ServerBitmap *bmp); + ServerCursor(int8 *data,color_space space); + ~ServerCursor(void); + void MoveTo(int32 x, int32 y); + void SetCursor(int8 *data, color_space space); + void SetCursor(ServerBitmap *bmp); + + ServerBitmap *bitmap, + *mask; + + color_space cspace; + BRect bounds; + int width,height; + BPoint position; + bool is_initialized; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto3/ServerProtocol.h b/src/servers/app/proto3/ServerProtocol.h new file mode 100644 index 0000000000..e41135f1b6 --- /dev/null +++ b/src/servers/app/proto3/ServerProtocol.h @@ -0,0 +1,13 @@ +#ifndef _APPSERVER_PROTOCOL_ +#define _APPSERVER_PROTOCOL_ + +#define CREATE_APP 'drca' +#define DELETE_APP 'drda' + +#define SET_SERVER_PORT 'srsp' +#define QUIT_APP 'srqa' + +#define SERVER_PORT_NAME "OBappserver" +#define SERVER_INPUT_PORT "OBinputport" + +#endif \ No newline at end of file diff --git a/src/servers/app/proto3/ServerRect.h b/src/servers/app/proto3/ServerRect.h new file mode 100644 index 0000000000..2632cf3b46 --- /dev/null +++ b/src/servers/app/proto3/ServerRect.h @@ -0,0 +1,35 @@ +#ifndef _SERVER_RECT_H_ +#define _SERVER_RECT_H_ + +class ServerRect +{ +public: + ServerRect(int32 l, int32 t, int32 r, int32 b) + { left=l; top=t; right=r; bottom=b; } + ServerRect(void) + { left=top=0; right=bottom=0; } + ServerRect(const ServerRect &rect); + ServerRect Bounds(void) const + { return( ServerRect( 0, 0, right - left, bottom - top ) );} + + virtual ~ServerRect(void); + bool Intersect(const ServerRect &rect ) const + { return( !( rect.right < left || rect.left > right || rect.bottom < top || rect.top > bottom ) ); } + + + int32 left,top,right,bottom; +}; + +ServerRect::ServerRect( const ServerRect& rect ) +{ + left = rect.left; + top = rect.top; + right = rect.right; + bottom = rect.bottom; +} + +ServerRect::~ServerRect(void) +{ +} + +#endif \ No newline at end of file diff --git a/src/servers/app/proto3/ServerRegion.h b/src/servers/app/proto3/ServerRegion.h new file mode 100644 index 0000000000..d0da8cc79a --- /dev/null +++ b/src/servers/app/proto3/ServerRegion.h @@ -0,0 +1,21 @@ +#ifndef _SERVER_REGION_H_ +#define _SERVER_REGION_H_ + +#include "ServerRect.h" + +class ServerRegion +{ +public: + ServerRegion(void); + ServerRegion(const ServerRect rect); + ServerRegion(const ServerRegion ®); + virtual ~ServerRegion(void); + bool Intersects(ServerRect rect); + void Set(ServerRect rect); + void Include(ServerRect rect); + void Exclude(ServerRect rect); + void IntersectWith(ServerRect rect); + void MakeEmpty(void); + void Optimize(void); +}; +#endif \ No newline at end of file diff --git a/src/servers/app/proto3/ServerSprite.cpp b/src/servers/app/proto3/ServerSprite.cpp new file mode 100644 index 0000000000..915e487dd3 --- /dev/null +++ b/src/servers/app/proto3/ServerSprite.cpp @@ -0,0 +1,29 @@ +#include "ServerCursor.h" +#include "ServerBitmap.h" + +ServerCursor::ServerCursor(ServerBitmap *bmp) +{ +} + +ServerCursor::~ServerCursor(void) +{ +} + +ServerCursor::SetCursor(int8 *data) +{ + // 68-byte array used in R5 for holding cursors. + // This API has serious problems and should be deprecated(but supported) + // in a future release, perhaps the first one(?) +} + +void ServerCursor::SaveClientData(void) +{ +} + +void ServerCursor::MoveTo(int32 x, int32 y) +{ +} + +void ServerCursor::SetClient(ServerBitmap *bmp) +{ +} \ No newline at end of file diff --git a/src/servers/app/proto3/ServerWindow.cpp b/src/servers/app/proto3/ServerWindow.cpp new file mode 100644 index 0000000000..25573409cf --- /dev/null +++ b/src/servers/app/proto3/ServerWindow.cpp @@ -0,0 +1,114 @@ +#include +#include "ServerWindow.h" + +ServerWindow::ServerWindow(const char *Title, uint32 Flags, uint32 Desktop, + const BRect &Rect, ServerApp *App, port_id SendPort) +{ +} + +ServerWindow::ServerWindow(ServerApp *App, ServerBitmap *Bitmap) +{ +} + +ServerWindow::~ServerWindow(void) +{ +} + +void ServerWindow::PostMessage(BMessage *msg) +{ +} + +void ServerWindow::ReplaceDecorator(void) +{ +} + +void ServerWindow::Quit(void) +{ +} + +const char *ServerWindow::GetTitle(void) +{ + return NULL; +} + +ServerApp *ServerWindow::GetApp(void) +{ + return NULL; +} + +BMessenger *ServerWindow::GetAppTarget(void) +{ + return NULL; +} + +void ServerWindow::Show(void) +{ +} + +void ServerWindow::Hide(void) +{ +} + +void ServerWindow::SetFocus(void) +{ +} + +bool ServerWindow::HasFocus(void) +{ + return false; +} + +void ServerWindow::DesktopActivated(int32 NewDesktop, const BPoint Resolution, color_space CSpace) +{ +} + +void ServerWindow::WindowActivated(bool Active) +{ +} + +void ServerWindow::ScreenModeChanged(const BPoint Resolustion, color_space CSpace) +{ +} + +void ServerWindow::SetFrame(const BRect &Frame) +{ +} + +BRect ServerWindow::Frame(void) +{ + return BRect(0,0,0,0); +} + +thread_id ServerWindow::Run(void) +{ + return -1; +} + +status_t ServerWindow::Lock(void) +{ + return B_ERROR; +} + +status_t ServerWindow::Unlock(void) +{ + return B_ERROR; +} + +bool ServerWindow::IsLocked(void) +{ + return false; +} + +bool ServerWindow::DispatchMessage(BMessage *msg) +{ + return false; +} + +bool ServerWindow::DispatchMessage(const void *msg, int nCode) +{ + return false; +} + +void ServerWindow::Loop(void) +{ +} diff --git a/src/servers/app/proto3/ServerWindow.h b/src/servers/app/proto3/ServerWindow.h new file mode 100644 index 0000000000..4c97ab93bb --- /dev/null +++ b/src/servers/app/proto3/ServerWindow.h @@ -0,0 +1,70 @@ +#ifndef _SERVERWIN_H_ +#define _SERVERWIN_H_ + +#include +#include +#include +#include + +class BString; +class BMessenger; +class BRect; +class BPoint; +class ServerApp; +class ServerBitmap; +class WindowDecorator; + +class ServerWindow +{ +public: +ServerWindow(const char *Title, uint32 Flags, uint32 Desktop, + const BRect &Rect, ServerApp *App, port_id SendPort); +ServerWindow(ServerApp *App, ServerBitmap *Bitmap); +virtual ~ServerWindow(void); + +void PostMessage(BMessage *msg); +void ReplaceDecorator(void); +virtual void Quit(void); +const char *GetTitle(void); +ServerApp *GetApp(void); +BMessenger *GetAppTarget(void); +void Show(void); +void Hide(void); +void SetFocus(void); +bool HasFocus(void); + +void DesktopActivated(int32 NewDesktop, const BPoint Resolution, color_space CSpace); +void WindowActivated(bool Active); +void ScreenModeChanged(const BPoint Resolustion, color_space CSpace); + +void SetFrame(const BRect &Frame); +BRect Frame(void); + +thread_id Run(void); +status_t Lock(void); +status_t Unlock(void); +bool IsLocked(void); + +bool DispatchMessage(BMessage *msg); +bool DispatchMessage(const void *msg, int nCode); + +void Loop(void); + +const char *title; +int32 flags; +int32 desktop; + +ServerBitmap *userbitmap; +ServerApp *app; + +WindowDecorator *decorator; +bigtime_t lasthit; // Time of last mouse click + +thread_id thread; +port_id rcvport; // Messages from application +port_id sendport; // Messages to application +BLocker mutex; +BMessenger *apptarget; +}; + +#endif diff --git a/src/servers/app/proto3/SystemPalette.cpp b/src/servers/app/proto3/SystemPalette.cpp new file mode 100644 index 0000000000..3a388ed6b4 --- /dev/null +++ b/src/servers/app/proto3/SystemPalette.cpp @@ -0,0 +1,327 @@ +/* + SystemPalette.cpp + One global function to generate the palette which is the default BeOS + System palette and the variable to go with it +*/ + +#include "SystemPalette.h" + +rgb_color SystemPalette[256]; + +void GenerateSystemPalette(rgb_color *palette) +{ + int i,j,index=0; + int indexvals1[]={ 255,229,204,179,154,129,105,80,55,30 }, + indexvals2[]={ 255,203,152,102,51,0 }; + rgb_color *currentcol; + + // Grays 0,0,0 -> 248,248,248 by 8's + for(i=0; i<=248; i+=8,index++) + { + currentcol=&(palette[index]); + currentcol->red=i; + currentcol->green=i; + currentcol->blue=i; + currentcol->alpha=255; + } + + // Blues, following indexvals1 + for(i=0; i<10; i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=0; + currentcol->green=0; + currentcol->blue=indexvals1[i]; + currentcol->alpha=255; + } + + // Reds, following indexvals1 - 1 + for(i=0; i<10; i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=indexvals1[i] - 1; + currentcol->green=0; + currentcol->blue=0; + currentcol->alpha=255; + } + + // Greens, following indexvals1 - 1 + for(i=0; i<10; i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=0; + currentcol->green=indexvals1[i] - 1; + currentcol->blue=0; + currentcol->alpha=255; + } + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=152; + currentcol->blue=51; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=255; + currentcol->blue=255; + index++; + + for(j=1;j<5;j++) + { + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=indexvals2[j]; + currentcol->green=255; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + } + + for(i=0;i<4;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=255; + currentcol->green=152; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=102; + currentcol->blue=51; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=102; + currentcol->blue=0; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=102; + currentcol->blue=255; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=102; + currentcol->blue=203; + index++; + + // Mostly array runs from here on out + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=203; + currentcol->green=203; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=152; + currentcol->green=255; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=102; + currentcol->green=255; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=51; + currentcol->green=255; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=255; + currentcol->green=102; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=102; + currentcol->blue=152; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=102; + currentcol->blue=102; + index++; + + // knocks out 4 assignment loops at once :) + for(j=1;j<5;j++) + { + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=indexvals2[j]; + currentcol->green=152; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + } + + currentcol+=sizeof(rgb_color); + currentcol->red=230; + currentcol->green=134; + currentcol->blue=0; + index++; + + for(i=1;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=255; + currentcol->green=51; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=102; + currentcol->blue=51; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=102; + currentcol->blue=0; + index++; + + for(j=1;j<5;j++) + { + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=indexvals2[j]; + currentcol->green=102; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + } + + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=255; + currentcol->green=0; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=175; + currentcol->blue=19; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=51; + currentcol->blue=255; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=51; + currentcol->blue=203; + index++; + + for(j=1;j<5;j++) + { + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=indexvals2[j]; + currentcol->green=51; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + } + + for(i=3;i>=0;i--,index++) + { + currentcol=&(palette[index]); + currentcol->red=255; + currentcol->green=203; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + for(i=2;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=0; + currentcol->green=51; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + for(i=0;i<5;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=203; + currentcol->green=0; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=227; + currentcol->blue=70; + index++; + + for(j=2;j<6;j++) + { + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=indexvals2[j]; + currentcol->green=0; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + } + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=203; + currentcol->blue=51; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=203; + currentcol->blue=0; + index++; + + for(i=5;i<=0;i--,index++) + { + currentcol=&(palette[index]); + currentcol->red=255; + currentcol->green=255; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + +} diff --git a/src/servers/app/proto3/SystemPalette.h b/src/servers/app/proto3/SystemPalette.h new file mode 100644 index 0000000000..0fb99d0fed --- /dev/null +++ b/src/servers/app/proto3/SystemPalette.h @@ -0,0 +1,9 @@ +#ifndef _SYSTEM_PALETTE_H_ +#define _SYSTEM_PALETTE_H_ + +#include + +void GenerateSystemPalette(rgb_color *palette); +extern rgb_color SystemPalette[]; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto3/ViewDriver.cpp b/src/servers/app/proto3/ViewDriver.cpp new file mode 100644 index 0000000000..5f2a189691 --- /dev/null +++ b/src/servers/app/proto3/ViewDriver.cpp @@ -0,0 +1,555 @@ +/* + ViewDriver: + First, slowest, and easiest driver class in the app_server which is designed + to utilize the BeOS graphics functions to cut out a lot of junk in getting the + drawing infrastructure in this server. + + The concept is to have VDView::Draw() draw a bitmap, which is a "frame buffer" + of sorts, utilize a second view to write to it. This cuts out + the most problems with having a crapload of code to get just right without + having to write a bunch of unit tests + + Components: 3 classes, VDView, VDWindow, and ViewDriver + + ViewDriver - a wrapper class which mostly posts messages to the VDWindow + VDWindow - does most of the work. + VDView - doesn't do all that much except display the rendered bitmap +*/ + +#include +#include +#include +#include +#include "PortLink.h" +#include "ServerProtocol.h" +#include "ServerBitmap.h" +#include "ViewDriver.h" +#include "ServerCursor.h" +#include "DebugTools.h" + +// Message defines for internal use only +#define VDWIN_CLEAR 'vwcl' +#define VDWIN_SAFEMODE 'vwsm' +#define VDWIN_RESET 'vwrs' +#define VDWIN_SETSCREEN 'vwss' +#define VDWIN_FILLRECT 'vwfr' +#define VDWIN_STROKERECT 'vwsr' +#define VDWIN_FILLELLIPSE 'vwfe' +#define VDWIN_STROKEELLIPSE 'vwse' +#define VDWIN_SHOWCURSOR 'vscr' +#define VDWIN_HIDECURSOR 'vhcr' +#define VDWIN_MOVECURSOR 'vmcr' + +static uint8 pickcursor[] = {16,1,2,1, +0,0,64,0,160,0,88,0,36,0,34,0,17,0,8,128, +4,88,2,60,1,120,0,240,1,248,1,220,0,140,0,0, +0,0,64,0,224,0,120,0,60,0,62,0,31,0,15,128, +7,216,3,252,1,248,0,240,1,248,1,220,0,140,0,0 +}; +static uint8 crosscursor[] = {16,1,5,5, +14,0,4,0,4,0,4,0,128,32,241,224,128,32,4,0, +4,0,4,0,14,0,0,0,0,0,0,0,0,0,0,0, +14,0,4,0,4,0,4,0,128,32,245,224,128,32,4,0, +4,0,4,0,14,0,0,0,0,0,0,0,0,0,0,0 +}; + +VDView::VDView(BRect bounds) + : BView(bounds,"viewdriver_view",B_FOLLOW_ALL, B_WILL_DRAW) +{ + viewbmp=new BBitmap(bounds,B_RGB32,true); + drawview=new BView(viewbmp->Bounds(),"drawview",B_FOLLOW_ALL, B_WILL_DRAW); + + // This link for sending mouse messages to the OBAppServer. + // This is only to take the place of the Input Server. I suppose I could write + // an addon filter to be more like the Input Server, but then I wouldn't be working + // on this thing! :P + serverlink=new PortLink(find_port(SERVER_INPUT_PORT)); +// printf("VDView: app_server input port: %ld\n",serverlink->GetPort()); + + hide_cursor=0; + + // Create a cursor which isn't just a box + cursor=new BBitmap(BRect(0,0,20,20),B_RGBA32,true); + BView *v=new BView(cursor->Bounds(),"v", B_FOLLOW_NONE, B_WILL_DRAW); + cursor->Lock(); + cursor->AddChild(v); + v->SetHighColor(255,255,255,0); + v->FillRect(cursor->Bounds()); + v->SetHighColor(255,0,0,255); + v->FillTriangle(cursor->Bounds().LeftTop(),cursor->Bounds().RightTop(),cursor->Bounds().LeftBottom()); + cursor->RemoveChild(v); + cursor->Unlock(); + + cursorframe=cursor->Bounds(); + oldcursorframe=cursor->Bounds(); +} + +VDView::~VDView(void) +{ + delete viewbmp; + delete serverlink; + delete cursor; +} + +void VDView::AttachedToWindow(void) +{ +// printf("VDView::AttachedToWindow()\n"); +} + +void VDView::Draw(BRect rect) +{ + DrawBitmapAsync(viewbmp,oldcursorframe,oldcursorframe); + DrawBitmapAsync(viewbmp,rect,rect); + SetDrawingMode(B_OP_ALPHA); + DrawBitmapAsync(cursor,cursor->Bounds(),cursorframe); + SetDrawingMode(B_OP_COPY); + Sync(); + +// oldcursorframe.PrintToStream(); +// cursorframe.PrintToStream(); +// printf("\n"); +} + +void VDView::MouseDown(BPoint pt) +{ +// printf("VDView::MouseDown()\n"); +// serverlink->SetOpCode(B_MOUSE_DOWN); +// serverlink->Flush(); +} + +void VDView::MouseMoved(BPoint pt, uint32 transit, const BMessage *msg) +{ + // This emulates an Input Server by sending the same kind of messages to the + // server's port. Being we're using a regular window, it would make little sense + // to do anything else. + + // Attach data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - buttons down + BPoint p; + uint32 buttons; + int64 time=(int64)real_time_clock(); + + serverlink->SetOpCode(B_MOUSE_MOVED); + serverlink->Attach(&time,sizeof(int64)); + serverlink->Attach(&pt.x,sizeof(float)); + serverlink->Attach(&pt.y,sizeof(float)); + GetMouse(&p,&buttons); + serverlink->Attach(&buttons,sizeof(int32)); + serverlink->Flush(); +} + +void VDView::MouseUp(BPoint pt) +{ +// printf("VDView::MouseUp()\n"); +// serverlink->SetOpCode(B_MOUSE_UP); +// serverlink->Flush(); +} + +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- + +VDWindow::VDWindow(void) + : BWindow(BRect(100,60,740,540),"OBOS App Server, P3",B_TITLED_WINDOW, + B_NOT_ZOOMABLE | B_NOT_RESIZABLE) +{ + view=new VDView(Bounds()); + AddChild(view); + pick=new BCursor(pickcursor); + cross=new BCursor(crosscursor); +} + +VDWindow::~VDWindow(void) +{ + delete pick; + delete cross; +} + +void VDWindow::MessageReceived(BMessage *msg) +{ + switch(msg->what) + { + case VDWIN_CLEAR: + { +// printf("ViewDriver: Clear\n"); + int8 red=0,green=0,blue=0; + msg->FindInt8("red",&red); + msg->FindInt8("green",&green); + msg->FindInt8("blue",&blue); + Clear(red,green,blue); + break; + } + case VDWIN_SETSCREEN: + { + // debug printing done in SetScreen() + int32 space=0; + msg->FindInt32("screenmode",&space); + SetScreen(space); + break; + } + case VDWIN_RESET: + { +// printf("ViewDriver: Reset\n"); + Reset(); + break; + } + case VDWIN_SAFEMODE: + { +// printf("ViewDriver: Safemode\n"); + SafeMode(); + break; + } + case VDWIN_FILLRECT: + { +// printf("ViewDriver: FillRect\n"); + BRect rect(0,0,0,0); + rgb_color color; + + msg->FindRect("rect",&rect); + msg->FindInt8("red",(int8 *)&color.red); + msg->FindInt8("green",(int8 *)&color.green); + msg->FindInt8("blue",(int8 *)&color.blue); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->SetHighColor(color); + view->drawview->FillRect(rect); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + break; + } + case VDWIN_STROKERECT: + { +// printf("ViewDriver: StrokeRect\n"); + BRect rect(0,0,0,0); + rgb_color color; + + msg->FindRect("rect",&rect); + msg->FindInt8("red",(int8 *)&color.red); + msg->FindInt8("green",(int8 *)&color.green); + msg->FindInt8("blue",(int8 *)&color.blue); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->SetHighColor(color); + view->drawview->StrokeRect(rect); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + break; + } + case VDWIN_FILLELLIPSE: + { +// printf("ViewDriver: FillEllipse\n"); + BRect rect(0,0,0,0); + rgb_color color; + + msg->FindRect("rect",&rect); + msg->FindInt8("red",(int8 *)&color.red); + msg->FindInt8("green",(int8 *)&color.green); + msg->FindInt8("blue",(int8 *)&color.blue); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->SetHighColor(color); + view->drawview->FillEllipse(rect); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + break; + } + case VDWIN_STROKEELLIPSE: + { +// printf("ViewDriver: StrokeEllipse\n"); + BRect rect(0,0,0,0); + rgb_color color; + + msg->FindRect("rect",&rect); + msg->FindInt8("red",(int8 *)&color.red); + msg->FindInt8("green",(int8 *)&color.green); + msg->FindInt8("blue",(int8 *)&color.blue); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->SetHighColor(color); + view->drawview->StrokeEllipse(rect); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + break; + } + case VDWIN_SHOWCURSOR: + { + if(view->hide_cursor>0) + view->hide_cursor--; + break; + } + case VDWIN_HIDECURSOR: + { + view->hide_cursor++; + break; + } + case VDWIN_MOVECURSOR: + { + view->oldcursorframe=view->cursorframe; + + int16 x,y; + msg->FindInt16("x",&x); + msg->FindInt16("y",&y); + view->cursorframe.OffsetTo(x,y); + view->Invalidate(view->oldcursorframe); + break; + } + default: + BWindow::MessageReceived(msg); + break; + } +} + +void VDWindow::SafeMode(void) +{ + SetScreen(B_32_BIT_640x480); +} + +void VDWindow::Reset(void) +{ + SafeMode(); + Clear(255,255,255); +} + +void VDWindow::SetScreen(uint32 space) +{ + switch(space) + { + case B_32_BIT_640x480: + case B_16_BIT_640x480: + case B_8_BIT_640x480: + { + ResizeTo(640.0,480.0); +//printf("SetScreen(): 640x480\n"); + break; + } + case B_32_BIT_800x600: + case B_16_BIT_800x600: + case B_8_BIT_800x600: + { + ResizeTo(800.0,600.0); +//printf("SetScreen(): 800x600\n"); + break; + } + case B_32_BIT_1024x768: + case B_16_BIT_1024x768: + case B_8_BIT_1024x768: + { + ResizeTo(1024.0,768.0); +//printf("SetScreen(): 1024x768\n"); + break; + } + default: + break; + } +} + +void VDWindow::Clear(uint8 red,uint8 green,uint8 blue) +{ +//printf("Clear: (%d,%d,%d)\n",red,green,blue); + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->SetHighColor(red,green,blue); + view->drawview->FillRect(view->drawview->Bounds()); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + view->Invalidate(); +} + +bool VDWindow::QuitRequested(void) +{ + port_id serverport=find_port(SERVER_PORT_NAME); + if(serverport!=B_NAME_NOT_FOUND) + { + write_port(serverport,B_QUIT_REQUESTED,NULL,0); + } + return true; +} + +void VDWindow::WindowActivated(bool active) +{ + // This is just to hide the regular system cursor so we can see our own + if(active) + be_app->HideCursor(); + else + be_app->ShowCursor(); +} + +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- + +/* + Posting messages to the rendering window helps run right around a whole + migraine's worth of multithreaded code +*/ + +ViewDriver::ViewDriver(void) +{ + screenwin=new VDWindow(); + hide_cursor=0; +} + +ViewDriver::~ViewDriver(void) +{ + if(is_initialized) + { + screenwin->Lock(); + screenwin->Quit(); + } +} + +void ViewDriver::Initialize(void) +{ + locker->Lock(); + screenwin->Show(); + is_initialized=true; + locker->Unlock(); +} + +void ViewDriver::Shutdown(void) +{ + locker->Lock(); + screenwin->Lock(); + screenwin->Close(); + is_initialized=false; + locker->Unlock(); +} + +void ViewDriver::SafeMode(void) +{ + locker->Lock(); + screenwin->PostMessage(VDWIN_SAFEMODE); + locker->Unlock(); +} + +void ViewDriver::Reset(void) +{ + locker->Lock(); + screenwin->PostMessage(VDWIN_RESET); + locker->Unlock(); +} + +void ViewDriver::SetScreen(uint32 space) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_SETSCREEN); + msg->AddInt32("screenmode",space); + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::Clear(uint8 red, uint8 green, uint8 blue) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_CLEAR); + msg->AddInt8("red",red); + msg->AddInt8("green",green); + msg->AddInt8("blue",blue); + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::StrokeRect(BRect rect,rgb_color color) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_STROKERECT); + msg->AddRect("rect",rect); + msg->AddInt8("red",color.red); + msg->AddInt8("green",color.green); + msg->AddInt8("blue",color.blue); + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::FillRect(BRect rect, rgb_color color) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_FILLRECT); + msg->AddRect("rect",rect); + msg->AddInt8("red",color.red); + msg->AddInt8("green",color.green); + msg->AddInt8("blue",color.blue); + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::StrokeEllipse(BRect rect,rgb_color color) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_STROKEELLIPSE); + msg->AddRect("rect",rect); + msg->AddInt8("red",color.red); + msg->AddInt8("green",color.green); + msg->AddInt8("blue",color.blue); + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::FillEllipse(BRect rect,rgb_color color) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_FILLELLIPSE); + msg->AddRect("rect",rect); + msg->AddInt8("red",color.red); + msg->AddInt8("green",color.green); + msg->AddInt8("blue",color.blue); + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::Blit(BPoint dest, ServerBitmap *sourcebmp, ServerBitmap *destbmp) +{ +} + +void ViewDriver::SetCursor(int32 value) +{ +} + +void ViewDriver::SetCursor(ServerCursor *cursor) +{ +} + +void ViewDriver::ShowCursor(void) +{ + locker->Lock(); + if(hide_cursor>0) + { + hide_cursor--; + screenwin->PostMessage(VDWIN_SHOWCURSOR); + } + locker->Unlock(); +} + +void ViewDriver::HideCursor(void) +{ + locker->Lock(); + hide_cursor++; + screenwin->PostMessage(VDWIN_HIDECURSOR); + locker->Unlock(); +} + +bool ViewDriver::IsCursorHidden(void) +{ + locker->Lock(); + bool value=(hide_cursor>0)?true:false; + locker->Unlock(); + + return value; +} + +void ViewDriver::MoveCursorTo(int x, int y) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_MOVECURSOR); + msg->AddInt16("x",x); + msg->AddInt16("y",y); + screenwin->PostMessage(msg); + locker->Unlock(); +} diff --git a/src/servers/app/proto3/ViewDriver.h b/src/servers/app/proto3/ViewDriver.h new file mode 100644 index 0000000000..38d4dd6ded --- /dev/null +++ b/src/servers/app/proto3/ViewDriver.h @@ -0,0 +1,89 @@ +#ifndef _VIEWDRIVER_H_ +#define _VIEWDRIVER_H_ + +#include +#include +#include +#include +#include +#include +#include "DisplayDriver.h" + +class BBitmap; +class PortLink; +class VDWindow; +class ServerCursor; + +class VDView : public BView +{ +public: + VDView(BRect bounds); + ~VDView(void); + void AttachedToWindow(void); + void Draw(BRect rect); + void MouseDown(BPoint pt); + void MouseMoved(BPoint pt, uint32 transit, const BMessage *msg); + void MouseUp(BPoint pt); + + BBitmap *viewbmp; + BView *drawview; + PortLink *serverlink; + +protected: + friend VDWindow; + + int hide_cursor; + BBitmap *cursor; + + BRect cursorframe, oldcursorframe; +}; + +class VDWindow : public BWindow +{ +public: + VDWindow(void); + ~VDWindow(void); + void MessageReceived(BMessage *msg); + bool QuitRequested(void); + void WindowActivated(bool active); + + void SafeMode(void); + void Reset(void); + void SetScreen(uint32 space); + void Clear(uint8 red,uint8 green,uint8 blue); + + VDView *view; + BCursor *pick, *cross; +}; + +class ViewDriver : public DisplayDriver +{ +public: + ViewDriver(void); + virtual ~ViewDriver(void); + + virtual void Initialize(void); + virtual void Shutdown(void); + virtual void SafeMode(void); + virtual void Reset(void); + virtual void SetScreen(uint32 space); + virtual void Clear(uint8 red,uint8 green,uint8 blue); + + virtual void StrokeRect(BRect rect,rgb_color color); + virtual void FillRect(BRect rect, rgb_color color); + virtual void StrokeEllipse(BRect rect,rgb_color color); + virtual void FillEllipse(BRect rect,rgb_color color); + virtual void Blit(BPoint dest, ServerBitmap *sourcebmp, ServerBitmap *destbmp); + + virtual void SetCursor(int32 value); + virtual void SetCursor(ServerCursor *cursor); + virtual void ShowCursor(void); + virtual void HideCursor(void); + virtual bool IsCursorHidden(void); + virtual void MoveCursorTo(int x, int y); + VDWindow *screenwin; +protected: + int hide_cursor; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto4/AppServer.cpp b/src/servers/app/proto4/AppServer.cpp new file mode 100644 index 0000000000..f26e53ff69 --- /dev/null +++ b/src/servers/app/proto4/AppServer.cpp @@ -0,0 +1,323 @@ +#include +#include +#include "scheduler.h" +#include +#include +#include "AppServer.h" +#include "ServerApp.h" +#include "Desktop.h" +#include "ServerProtocol.h" +#include "PortLink.h" +#include "DisplayDriver.h" +#include "DebugTools.h" + +AppServer::AppServer(void) : BApplication("application/x-vnd.obe-OBAppServer") +{ +// printf("AppServer()\n"); + + mouseport=create_port(30,SERVER_INPUT_PORT); + messageport=create_port(20,SERVER_PORT_NAME); +// printf("Server message port: %ld\n",messageport); +// printf("Server input port: %ld\n",mouseport); + applist=new BList(0); + quitting_server=false; + exit_poller=false; + + // Set up the Desktop + init_desktop(3); + + // Spawn our input-polling thread + poller_id = spawn_thread(PollerThread, "Poller", B_NORMAL_PRIORITY, this); + if (poller_id >= 0) + resume_thread(poller_id); + driver=get_gfxdriver(); + + active_app=-1; + p_active_app=NULL; + + // This is necessary to mediate access between the Poller and app_server threads + active_lock=new BLocker; +} + +AppServer::~AppServer(void) +{ + shutdown_desktop(); + + ServerApp *temp; + for(int32 i=0;iCountItems();i++) + { + temp=(ServerApp *)applist->ItemAt(i); + if(temp!=NULL) + delete temp; + } + delete applist; + delete active_lock; +} + +thread_id AppServer::Run(void) +{ + //printf("AppServer::Run()\n"); + + MainLoop(); + return 0; +} + +void AppServer::MainLoop(void) +{ + // Main loop (duh). Monitors the message queue and dispatches as appropriate. + // Input messages are handled by the poller, however. + + //printf("AppServer::MainLoop()\n"); + + int32 msgcode; + int8 *msgbuffer=NULL; + ssize_t buffersize,bytesread; + + for(;;) + { + buffersize=port_buffer_size(messageport); + if(buffersize>0) + msgbuffer=new int8[buffersize]; + bytesread=read_port(messageport,&msgcode,msgbuffer,buffersize); + + if (bytesread != B_BAD_PORT_ID && bytesread != B_TIMED_OUT && bytesread != B_WOULD_BLOCK) + { + switch(msgcode) + { + case CREATE_APP: + case DELETE_APP: + case B_QUIT_REQUESTED: + DispatchMessage(msgcode,msgbuffer); + break; + default: + //printf("Server received unexpected code %ld\n",msgcode); + break; + } + + } + + if(buffersize>0) + delete msgbuffer; + if(msgcode==DELETE_APP || msgcode==B_QUIT_REQUESTED) + { + if(quitting_server==true && applist->CountItems()==0) + break; + } + } + // Make sure our polling thread has exited + if(find_thread("Poller")!=B_NAME_NOT_FOUND) + kill_thread(poller_id); + +} + + +void AppServer::DispatchMessage(int32 code, int8 *buffer) +{ + int8 *index=buffer; + switch(code) + { + case CREATE_APP: + { + // Create the ServerApp to node monitor a new BApplication + + //printf("AppServer: Create App\n"); + + // Attached data: + // 1) port_id - receiver port of a regular app + // 2) char * - signature of the regular app + + // Find the necessary data + port_id app_port=*((port_id*)index); + index+=sizeof(port_id); + + char *app_signature=(char *)index; + + // Create the ServerApp subthread for this app + ServerApp *newapp=new ServerApp(app_port,app_signature); + applist->AddItem(newapp); + + active_lock->Lock(); + p_active_app=newapp; + active_app=applist->CountItems()-1; + active_lock->Unlock(); + + newapp->Run(); + + break; + } + case DELETE_APP: + { + // Delete a ServerApp. Received only from the respective ServerApp when a + // BApplication asks it to quit. + + //printf("AppServer: Delete App\n"); + + // Attached Data: + // 1) thread_id - thread ID of the ServerApp to be deleted + + int32 i, appnum=applist->CountItems(); + ServerApp *srvapp; + thread_id srvapp_id=*((thread_id*)buffer); + + // Run through the list of apps and nuke the proper one + for(i=0;iItemAt(i); + if(srvapp!=NULL && srvapp->monitor_thread==srvapp_id) + { + srvapp=(ServerApp *)applist->RemoveItem(i); + delete srvapp; + active_lock->Lock(); + + if(applist->CountItems()==0) + { + // active==-1 signifies that no other apps are running - NOT good + active_app=-1; + } + else + { + // we actually still have apps running, so make a new one active + if(active_app>0) + active_app--; + else + active_app=0; + } + p_active_app=(active_app>-1)?(ServerApp*)applist->ItemAt(active_app):NULL; + active_lock->Unlock(); + break; // jump out of the loop + } + } + break; + } + case B_QUIT_REQUESTED: + { + //printf("Shutdown sequence initiated.\n"); + + // Attached Data: + // none + + // We've been asked to quit, so (for now) broadcast to all + // test apps to quit. This situation will occur only when the server + // is compiled as a regular Be application. + PortLink *applink=new PortLink(0); + ServerApp *srvapp; + int32 i,appnum=applist->CountItems(); + + applink->SetOpCode(QUIT_APP); + for(i=0;iItemAt(i); + if(srvapp!=NULL) + { + applink->SetPort(srvapp->receiver); + applink->Flush(); + } + } + + delete applink; + // So when we delete the last ServerApp, we can exit the server + quitting_server=true; + exit_poller=true; + break; + } + default: + //printf("Unexpected message %ld (%lx) in AppServer::DispatchMessage()\n",code,code); + break; + } +} + +void AppServer::Poller(void) +{ + // This thread handles nothing but input messages for mouse and keyboard + int32 msgcode; + int8 *msgbuffer=NULL,*index; + ssize_t buffersize,bytesread; + + for(;;) + { + buffersize=port_buffer_size(mouseport); + if(buffersize>0) + msgbuffer=new int8[buffersize]; + bytesread=read_port(mouseport,&msgcode,msgbuffer,buffersize); + + if (bytesread != B_BAD_PORT_ID && bytesread != B_TIMED_OUT && bytesread != B_WOULD_BLOCK) + { + switch(msgcode) + { + // We don't need to do anything with these two, so just pass them + // onto the active application. Eventually, we will pass them onto + // the window which is currently under the cursor. + case B_MOUSE_DOWN: + case B_MOUSE_UP: + { + active_lock->Lock(); + if(active_app>-1) + write_port(p_active_app->receiver, msgcode,msgbuffer,buffersize); + active_lock->Unlock(); + break; + } + + // Process the cursor and then pass it on + case B_MOUSE_MOVED: + { + // Attached data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - buttons down + + index=msgbuffer; + + // Time sent is not necessary for cursor processing. + index += sizeof(int64); + + float tempx=0,tempy=0; + tempx=*((float*)index); + index+=sizeof(float); + tempy=*((float*)index); + index+=sizeof(float); + + driver->MoveCursorTo(tempx,tempy); + + active_lock->Lock(); + if(active_app>-1) + write_port(p_active_app->receiver, msgcode,msgbuffer,buffersize); + active_lock->Unlock(); + break; + } + default: + //printf("Server::Poller received unexpected code %ld\n",msgcode); + break; + } + + } + + if(buffersize>0) + delete msgbuffer; + + if(exit_poller) + break; + } +} + +int32 AppServer::PollerThread(void *data) +{ + //printf("Starting Poller thread...\n"); + AppServer *server=(AppServer *)data; + + server->Poller(); // This won't return until it's told to + + //printf("Exiting Poller thread...\n"); + exit_thread(B_OK); + return B_OK; +} + +int main( int argc, char** argv ) +{ + AppServer *obas = new AppServer(); + obas->Run(); + delete obas; + return 0; +} + + \ No newline at end of file diff --git a/src/servers/app/proto4/AppServer.h b/src/servers/app/proto4/AppServer.h new file mode 100644 index 0000000000..f24ec39a7c --- /dev/null +++ b/src/servers/app/proto4/AppServer.h @@ -0,0 +1,37 @@ +#ifndef _OPENBEOS_APP_SERVER_H_ +#define _OPENBEOS_APP_SERVER_H_ + +#include +#include +#include +#include + +class BMessage; +class ServerApp; +class DisplayDriver; + +class AppServer : public BApplication +{ +public: + AppServer(void); + ~AppServer(void); + thread_id Run(void); + void MainLoop(void); + port_id messageport,mouseport; + void Poller(void); + +private: + void DispatchMessage(int32 code, int8 *buffer); + static int32 PollerThread(void *data); + + bool quitting_server; + BList *applist; + int32 active_app; + ServerApp *p_active_app; + thread_id poller_id; + BLocker *active_lock; + bool exit_poller; + DisplayDriver *driver; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto4/BUGS b/src/servers/app/proto4/BUGS new file mode 100644 index 0000000000..69d18cbea0 --- /dev/null +++ b/src/servers/app/proto4/BUGS @@ -0,0 +1 @@ +Cursor display is just a little bit funky (try moving cursor by 1 pixel) \ No newline at end of file diff --git a/src/servers/app/proto4/CHANGES b/src/servers/app/proto4/CHANGES new file mode 100644 index 0000000000..5cbff3e3e8 --- /dev/null +++ b/src/servers/app/proto4/CHANGES @@ -0,0 +1,19 @@ +Prototype 4 + +Serious DisplayDriver API changes +Support of cursordata-based SetCursor calls by test app (ServerCursor translates them to 32-bit bitmaps) +TestApp has been modified to test the graphics access module +Implemented many, many BView graphics calls and appropriate protocols +BShape, BRegion, and BPolygon graphics calls not implemented. +BFont-based calls, save DrawString and SetFontSize, are unimplemented. +Partial foundation laid for BBitmap support + +Prototype 3 + +Added GUI and hardcoded cursor + + +Prototype 2 + +Adding and removing test applications +Quitting server causes all test apps to quit also \ No newline at end of file diff --git a/src/servers/app/proto4/DebugTools.cpp b/src/servers/app/proto4/DebugTools.cpp new file mode 100644 index 0000000000..25f852f970 --- /dev/null +++ b/src/servers/app/proto4/DebugTools.cpp @@ -0,0 +1,205 @@ +#include +#include +#include "DebugTools.h" + +void PrintStatusToStream(status_t value) +{ + // Function which simply translates a returned status code into a string + // and dumps it to stdout + BString outstr; + switch(value) + { + case B_OK: + outstr="B_OK "; + break; + case B_NAME_NOT_FOUND: + outstr="B_NAME_NOT_FOUND "; + break; + case B_BAD_VALUE: + outstr="B_BAD_VALUE "; + break; + case B_ERROR: + outstr="B_ERROR "; + break; + case B_TIMED_OUT: + outstr="B_TIMED_OUT "; + break; + case B_NO_MORE_PORTS: + outstr="B_NO_MORE_PORTS "; + break; + case B_WOULD_BLOCK: + outstr="B_WOULD_BLOCK "; + break; + case B_BAD_PORT_ID: + outstr="B_BAD_PORT_ID "; + break; + case B_BAD_TEAM_ID: + outstr="B_BAD_TEAM_ID "; + break; + default: + outstr="undefined status value in debugtools::PrintStatusToStream() "; + break; + } + cout << "Status: " << outstr.String() << endl << flush; + +} + +void PrintColorSpaceToStream(color_space value) +{ + // Dump a color space to cout + BString outstr; + switch(value) + { + case B_RGB32: + outstr="B_RGB32 "; + break; + case B_RGBA32: + outstr="B_RGBA32 "; + break; + case B_RGB32_BIG: + outstr="B_RGB32_BIG "; + break; + case B_RGBA32_BIG: + outstr=" "; + break; + case B_UVL32: + outstr="B_UVL32 "; + break; + case B_UVLA32: + outstr="B_UVLA32 "; + break; + case B_LAB32: + outstr="B_LAB32 "; + break; + case B_LABA32: + outstr="B_LABA32 "; + break; + case B_HSI32: + outstr="B_HSI32 "; + break; + case B_HSIA32: + outstr="B_HSIA32 "; + break; + case B_HSV32: + outstr="B_HSV32 "; + break; + case B_HSVA32: + outstr="B_HSVA32 "; + break; + case B_HLS32: + outstr="B_HLS32 "; + break; + case B_HLSA32: + outstr="B_HLSA32 "; + break; + case B_CMY32: + outstr="B_CMY32"; + break; + case B_CMYA32: + outstr="B_CMYA32 "; + break; + case B_CMYK32: + outstr="B_CMYK32 "; + break; + case B_RGB24_BIG: + outstr="B_RGB24_BIG "; + break; + case B_RGB24: + outstr="B_RGB24 "; + break; + case B_LAB24: + outstr="B_LAB24 "; + break; + case B_UVL24: + outstr="B_UVL24 "; + break; + case B_HSI24: + outstr="B_HSI24 "; + break; + case B_HSV24: + outstr="B_HSV24 "; + break; + case B_HLS24: + outstr="B_HLS24 "; + break; + case B_CMY24: + outstr="B_CMY24 "; + break; + case B_GRAY1: + outstr="B_GRAY1 "; + break; + case B_CMAP8: + outstr="B_CMAP8 "; + break; + case B_GRAY8: + outstr="B_GRAY8 "; + break; + case B_YUV411: + outstr="B_YUV411 "; + break; + case B_YUV420: + outstr="B_YUV420 "; + break; + case B_YCbCr422: + outstr="B_YCbCr422 "; + break; + case B_YCbCr411: + outstr="B_YCbCr411 "; + break; + case B_YCbCr420: + outstr="B_YCbCr420 "; + break; + case B_YUV422: + outstr="B_YUV422 "; + break; + case B_YUV9: + outstr="B_YUV9 "; + break; + case B_YUV12: + outstr="B_YUV12 "; + break; + case B_RGB15: + outstr="B_RGB15 "; + break; + case B_RGBA15: + outstr="B_RGBA15 "; + break; + case B_RGB16: + outstr="B_RGB16 "; + break; + case B_RGB16_BIG: + outstr="B_RGB16_BIG "; + break; + case B_RGB15_BIG: + outstr="B_RGB15_BIG "; + break; + case B_RGBA15_BIG: + outstr="B_RGBA15_BIG "; + break; + case B_YCbCr444: + outstr="B_YCbCr444 "; + break; + case B_YUV444: + outstr="B_YUV444 "; + break; + case B_NO_COLOR_SPACE: + outstr="B_NO_COLOR_SPACE "; + break; + default: + outstr="Undefined color space "; + break; + } + cout << "Color Space: " << outstr.String() << flush; +} + +void TranslateMessageCodeToStream(int32 code) +{ + // Used to translate BMessage message codes back to a character + // format + + cout << "'" + << (char)((code & 0xFF000000) >> 24) + << (char)((code & 0x00FF0000) >> 16) + << (char)((code & 0x0000FF00) >> 8) + << (char)((code & 0x000000FF)) << "' "; +} \ No newline at end of file diff --git a/src/servers/app/proto4/DebugTools.h b/src/servers/app/proto4/DebugTools.h new file mode 100644 index 0000000000..e629820577 --- /dev/null +++ b/src/servers/app/proto4/DebugTools.h @@ -0,0 +1,11 @@ +#ifndef _DEBUGTOOLS_H_ +#define _DEBUGTOOLS_H_ + +#include +#include + +void PrintStatusToStream(status_t value); +void PrintColorSpaceToStream(color_space value); +void TranslateMessageCodeToStream(int32 code); + +#endif \ No newline at end of file diff --git a/src/servers/app/proto4/Desktop.cpp b/src/servers/app/proto4/Desktop.cpp new file mode 100644 index 0000000000..125de6c6f4 --- /dev/null +++ b/src/servers/app/proto4/Desktop.cpp @@ -0,0 +1,338 @@ +/* + Desktop.cpp: + Code necessary to handle the Desktop, defined as the collection of workspaces. +*/ + +//#define DEBUG_WORKSPACES + +#include +#include +#include +#include +#include "DisplayDriver.h" +#include "ViewDriver.h" +#include "Desktop.h" + +class ServerWindow; +class ServerBitmap; +class Workspace; + +// Quick hack to make setting rgb_colors much easier to live with +void set_rgb_color(rgb_color *col,uint8 red, uint8 green, uint8 blue, uint8 alpha=255) +{ + col->red=red; + col->green=green; + col->blue=blue; + col->alpha=alpha; +} + +//--------------------GLOBALS------------------------- +int32 workspace_count, active_workspace; +BList *desktop; +Workspace *pactive_workspace; +color_map system_palette; +ViewDriver *gfxdriver; +//---------------------------------------------------- + + +//-------------------INTERNAL CLASS DEFS-------------- +class Workspace +{ +public: + Workspace(void); + Workspace(BPath imagepath); + ~Workspace(); + + BList layerlist; + BList focuslist; + rgb_color bgcolor; + screen_info screendata, + olddata; +}; + +DisplayDriver *get_gfxdriver(void) +{ + return gfxdriver; +} + +Workspace::Workspace(void) +{ + workspace_count++; + + // default values + layerlist.MakeEmpty(); + focuslist.MakeEmpty(); + bgcolor.red=51; + bgcolor.green=102; + bgcolor.blue=160; + screendata.mode=B_CMAP8; + screendata.spaces=B_8_BIT_640x480; + screendata.refresh_rate=60.0; + screendata.min_refresh_rate=60.0; + screendata.max_refresh_rate=60.0; + screendata.h_position=(uchar)50; + screendata.v_position=(uchar)50; + screendata.h_size=(uchar)50; + screendata.v_size=(uchar)50; + olddata=screendata; +} + +Workspace::~Workspace(void) +{ + workspace_count--; +} +//--------------------------------------------------- + + +//-----------------GLOBAL FUNCTION DEFS--------------- + +void init_desktop(int8 workspaces) +{ +#ifdef DEBUG_WORKSPACES +printf("init_desktop(%d)\n",workspaces); +#endif + workspace_count=workspaces; + if(workspace_count==0) + workspace_count++; + + // Instantiate and initialize display driver + gfxdriver=new ViewDriver(); + gfxdriver->Initialize(); + +#ifdef DEBUG_WORKSPACES +printf("Driver %s\n", (gfxdriver->IsInitialized()==true)?"initialized":"NOT initialized"); +#endif + + desktop=new BList(0); + + // Create the workspaces we're supposed to have + for(int8 i=0; iAddItem(new Workspace()); + } + + // Load workspace preferences here + + // We're going to punch in some hardcoded settings for testing purposes. + // There are 3 workspaces hardcoded in for now, but we'll only use the + // second one. + Workspace *wksp=(Workspace*)desktop->ItemAt(1); + if(wksp!=NULL) // in case I forgot something + { + set_rgb_color(&(wksp->bgcolor),0,200,236); + screen_info *tempsd=&(wksp->screendata); + tempsd->mode=B_CMAP8; + tempsd->spaces=B_8_BIT_800x600; + tempsd->frame.Set(0,0,799,599); + } + else + printf("DW goofed on the workspace index :P\n"); + + + // Activate workspace 0 + pactive_workspace=(Workspace *)desktop->ItemAt(0); + gfxdriver->SetScreen(pactive_workspace->screendata.spaces); + + // Clear the screen + set_rgb_color(&(pactive_workspace->bgcolor),80,85,152); + gfxdriver->Clear(pactive_workspace->bgcolor); + +#ifdef DEBUG_WORKSPACES +printf("Desktop initialized\n"); +#endif +} + +void shutdown_desktop(void) +{ + int32 i,count=desktop->CountItems(); + for(i=0;iItemAt(i)!=NULL) + delete desktop->ItemAt(i); + } + desktop->MakeEmpty(); + delete desktop; + gfxdriver->Shutdown(); + delete gfxdriver; +} + + +int32 CountWorkspaces(void) +{ +#ifdef DEBUG_WORKSPACES +printf("CountWorkspaces() returned %ld\n",workspace_count); +#endif + return workspace_count; +} + +void SetWorkspaceCount(int32 count) +{ + if(count<0) + { +#ifdef DEBUG_WORKSPACES +printf("SetWorkspaceCount(value<0) - DOH!\n"); +#endif + return; + } + if(count==workspace_count) + return; + + // Activate last workspace in new set if we're using one to be nuked + if(countItemAt(i)!=NULL) + { + delete (Workspace*)desktop->ItemAt(i); + desktop->RemoveItem(i); + } + } + } + else + { + // count > workspace_count here + + // Once we have default workspace preferences which can be set by the + // user, we'll end up having to initialize newly-added workspaces to that + // data. In the mean time, the defaults in the constructor will do. :) + for(int32 i=count;iAddItem(new Workspace()); + } + } + + // don't forget to update our global! + workspace_count=desktop->CountItems(); + +#ifdef DEBUG_WORKSPACES +printf("SetWorkspaceCount(%ld)\n",workspace_count); +#endif + +} + +int32 CurrentWorkspace(void) +{ +#ifdef DEBUG_WORKSPACES +printf("CurrentWorkspace() returned %ld\n",active_workspace); +#endif + return active_workspace; +} + +void ActivateWorkspace(int32 workspace) +{ + // In order to change workspaces, we'll need to make all the necessary + // changes to the screen to fit the new one, such as resolution, + // background color, color depth, refresh rate, etc. + + if(workspace>workspace_count || workspace<0) + return; + + Workspace *proposed=(Workspace *)desktop->ItemAt(workspace); + + if(proposed==NULL) + return; + + // Here's where we update all the screen stuff + if(pactive_workspace->screendata.spaces != proposed->screendata.spaces) + { + gfxdriver->SetScreen(proposed->screendata.spaces); + gfxdriver->Clear(proposed->bgcolor); + } + // more if != then change code goes here. Currently, a lot of the code which + // uses this stuff is not implemented, so it's kind of moot. However, when we + // use the real graphics HW, it'll become important. + + // actually set our active workspace data to reflect the change in workspaces + pactive_workspace=proposed; + active_workspace=workspace; +#ifdef DEBUG_WORKSPACES +printf("ActivateWorkspace(%ld)\n",active_workspace); +#endif +} + +const color_map *SystemColors(void) +{ + return (const color_map *)&system_palette; +} + +status_t SetScreenSpace(int32 index, uint32 res, bool stick = true) +{ +#ifdef DEBUG_WORKSPACES +printf("SetScreenSpace(%ld,%lu, %s)\n",index,res,(stick==true)?"true":"false"); +#endif + + if(index>workspace_count-1) + { + printf("SetScreenSpace was passed invalid workspace value %ld\n",index); + return B_ERROR; + } + if(res>0x800000) // the last "normal" screen mode defined in GraphicsDefs.h + { + printf("SetScreenSpace was passed invalid screen value %lu\n",res); + return B_ERROR; + } + + // When we actually use app_server preferences, we'll save the screen mode to + // the preferences so that we use this mode next boot. For now, we treat stick==false + if(stick==true) + { + // save the screen data here + } + if(index==active_workspace) + { + gfxdriver->SetScreen(res); + gfxdriver->Clear(pactive_workspace->bgcolor); + } + else + { + // just set the workspace's data here. right now, do nothing. + } + return B_OK; +} + +status_t GetScrollBarInfo(scroll_bar_info *info) +{ + return B_ERROR; +} + +status_t SetScrollBarInfo(scroll_bar_info *info) +{ + //printf("set_scroll_bar_info()\n"); + return B_ERROR; +} + +bigtime_t IdleTime() +{ + return 0; +} + +void RunSelectPrinterPanel() +{ // Not sure what to do with this guy just yet +} + +void RunAddPrinterPanel() +{ // Not sure what to do with this guy just yet +} + +void RunBeAbout() +{ // the BeOS About Window belongs to Tracker.... +} + +void SetFocusFollowsMouse(bool follow) +{ + //printf("set_focus_follows_mouse(%s)\n",(follow==true)?"true":"false"); +} + +bool FocusFollowsMouse() +{ + return false; +} + +// Another "just in case DW screws up again" section +#ifdef DEBUG_WORKSPACES +#undef DEBUG_WORKSPACES +#endif \ No newline at end of file diff --git a/src/servers/app/proto4/Desktop.h b/src/servers/app/proto4/Desktop.h new file mode 100644 index 0000000000..a4830a8c21 --- /dev/null +++ b/src/servers/app/proto4/Desktop.h @@ -0,0 +1,37 @@ +#ifndef _OBDESKTOP_H_ +#define _OBDESKTOP_H_ + + +#include +#include +#include +class DisplayDriver; + +void init_desktop(int8 workspaces); +void shutdown_desktop(void); +DisplayDriver *get_gfxdriver(void); + +// Workspace access functions +int32 CountWorkspaces(void); +void SetWorkspaceCount(int32 count); +int32 CurrentWorkspace(void); +void ActivateWorkspace(int32 workspace); +const color_map *SystemColors(void); +status_t SetScreenSpace(int32 index, uint32 res, bool stick = true); + +typedef struct +{ + color_space mode; + BRect frame; + uint32 spaces; + float min_refresh_rate; + float max_refresh_rate; + float refresh_rate; + uchar h_position; + uchar v_position; + uchar h_size; + uchar v_size; +} screen_info; + + +#endif \ No newline at end of file diff --git a/src/servers/app/proto4/DirectDriver.cpp b/src/servers/app/proto4/DirectDriver.cpp new file mode 100644 index 0000000000..b451ae9b2e --- /dev/null +++ b/src/servers/app/proto4/DirectDriver.cpp @@ -0,0 +1,251 @@ +#include +#include "DirectDriver.h" +#include + +#ifndef ABS + #define ABS(a) (a<0)?a*-1:a +#endif + +OBAppServerScreen::OBAppServerScreen(status_t *error) + : BDirectWindow(BRect(100,60,740,540),"OBOS App Server, P3",B_TITLED_WINDOW, + B_NOT_RESIZABLE | B_NOT_ZOOMABLE) +{ + redraw=true; +} + +OBAppServerScreen::~OBAppServerScreen(void) +{ +} + +void OBAppServerScreen::MessageReceived(BMessage *msg) +{ + msg->PrintToStream(); + switch(msg->what) + { + case B_KEY_DOWN: +// Disconnect(); + QuitRequested(); + break; + default: + BDirectWindow::MessageReceived(msg); + break; + } +} + +bool OBAppServerScreen::QuitRequested(void) +{ + redraw=false; + be_app->PostMessage(B_QUIT_REQUESTED); + return true; +} + +int32 OBAppServerScreen::Draw(void *data) +{ + OBAppServerScreen *screen=(OBAppServerScreen *)data; + for(;;) + { + if(screen->connected && screen->redraw) + { + // Draw a sample background + screen->redraw=false; + } + } + return 1; +} + +void OBAppServerScreen::DirectConnected(direct_buffer_info *dbinfo) +{ +/* if(ok==true) + { + connected=true; + gcinfo=CardInfo(); + for(int8 i=0;i<48;i++) + gchooks[i]=CardHookAt(i); + } + else + connected=false; +*/ +} + +DirectDriver::DirectDriver(void) +{ +// printf("DirectDriver()\n"); +// old_space=B_32_BIT_800x600; +} + +DirectDriver::~DirectDriver(void) +{ + printf("~DirectDriver()\n"); + winscreen->Lock(); + winscreen->Close(); +} + +void DirectDriver::Initialize(void) +{ +/* printf("DirectDriver::Initialize()\n"); + status_t stat; + winscreen=new OBAppServerScreen(&stat); + if(stat==B_OK) + winscreen->Show(); + else + delete winscreen; +*/ +} + +void DirectDriver::SafeMode(void) +{ +/* printf("DirectDriver::SafeMode()\n"); +// SetScreen(B_8_BIT_640x480); + SetScreen(B_32_BIT_800x600); + Reset(); +*/ +} + +void DirectDriver::Reset(void) +{ +/* printf("DirectDriver::Reset()\n"); + if(winscreen->connected==true) + Clear(51,102,160); +*/ +} + +void DirectDriver::SetScreen(uint32 space) +{ +// printf("DirectDriver::SetScreen(%lu)\n",space); +// winscreen->SetSpace(space); +} + +void DirectDriver::Clear(uint8 red, uint8 green, uint8 blue) +{ +/* // This simply clears the entire screen, utilizing a string and + // memcpy to speed things up in a minor way + printf("DirectDriver::Clear(%d,%d,%d)\n",red,green,blue); + + if(winscreen->connected==false) + return; + + int i,imax, + length=winscreen->gcinfo->bytes_per_row; + int8 fillstring[length]; + + + switch(winscreen->gcinfo->bits_per_pixel) + { + case 32: + { + int32 color,*index32; + + // order is going to be BGRA or ARGB + if(winscreen->gcinfo->rgba_order[0]=='B') + { + // Create the number to quickly create the string + + // BBGG RRAA in RAM => 0xRRAA BBGG + color= (int32(red) << 24) + 0xFF0000L + (int32(blue) << 8) + green; + } + else + { + // Create the number to quickly create the string + + // AARR GGBB in RAM + color= 0xFF000000L + (int32(red) << 16) + (int32(green) << 8) + blue; + } + + // fill the string with the appropriate values + index32=(int32 *)fillstring; + imax=winscreen->gcinfo->width; + + for(i=0;igcinfo->rgba_order[0]=='B') + { + // Little-endian + // G[2:0],B[4:0] R[4:0],G[5:3] + + // Ick. Gotta love all that shifting and masking. :( + color= (int16((green & 7)) << 13) + + (int16((blue & 31)) << 8) + + (int16((red & 31)) << 4) + + (int16(green & 56)); + } + else + { + // Big-endian + // R[4:0],G[5:3] G[2:0],B[4:0] + color= (int16(red & 31) << 11) + + (int16(green & 56) << 8) + + (int16(green & 3) << 5) + + (blue & 31); + } + break; + } + case 15: + { + + // RGBA_15: + // G[2:0],B[4:0] A[0],R[4:0],G[4:3] + + // RGBA_15_BIG: + // A[0],R[4:0],G[4:3] G[2:0],B[4:0] + break; + } +*/ +/* case 8: + { + // This is both the easiest and hardest: + // We fill using memset(), but we have to find the closest match to the + // color we've been given. Yuck. + + // Find the closest match by comparing the differences in values for each + // color. This function was not intended to be called rapidly, so speed is + // not much of an issue at this point. + int8 closest=0; + int16 closest_delta=765, delta; // (255 * 3) + + // Get the current palette + rgb_color *list=winscreen->ColorList(); + for(i=0;i<256;i++) + { + delta=ABS(list->red-red)+ABS(list->green-green)+ABS(list->blue-blue); + if(deltagcinfo->frame_buffer,closest, + winscreen->gcinfo->bytes_per_row * winscreen->gcinfo->height); + + // Nothing left to do! + return; + break; + } + default: + { + printf("Unsupported bit depth %d in DirectDriver::Clear(r,g,b)!!\n",winscreen->gcinfo->bits_per_pixel); + return; + } + } + imax=winscreen->gcinfo->height; + + // a pointer to increment for the screen copy. Faster than doing a multiply + // each iteration + int8 *pbuffer=(int8*)winscreen->gcinfo->frame_buffer; + for(i=0;i +#include +#include +#include +#include "DisplayDriver.h" + +class OBAppServerScreen : public BDirectWindow +{ +public: + OBAppServerScreen(status_t *error); + ~OBAppServerScreen(void); + virtual void MessageReceived(BMessage *msg); + virtual bool QuitRequested(void); + static int32 Draw(void *data); + virtual void DirectConnected(direct_buffer_info *dbinfo); + + int32 DrawID; + bool redraw,connected; + graphics_card_info *gcinfo; + graphics_card_hook *gchooks; +}; + +class DirectDriver : public DisplayDriver +{ +public: + DirectDriver(void); + virtual ~DirectDriver(void); + + virtual void Initialize(void); // Sets the driver + virtual void SafeMode(void); // Easy-access functions for common tasks + virtual void Reset(void); + virtual void SetScreen(uint32 space); + virtual void Clear(uint8 red,uint8 green,uint8 blue); +// virtual void SetPixel(int x, int y, rgb_color color); +// virtual void StrokeEllipse(BRect rect, rgb_color color); + OBAppServerScreen *winscreen; + +protected: + // Original screen info + uint32 old_space; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto4/DisplayDriver.cpp b/src/servers/app/proto4/DisplayDriver.cpp new file mode 100644 index 0000000000..75e8f9bd60 --- /dev/null +++ b/src/servers/app/proto4/DisplayDriver.cpp @@ -0,0 +1,230 @@ +/* + DisplayDriver.cpp + Modular class to allow the server to not care what the ultimate output is + for graphics calls. +*/ +#include "DisplayDriver.h" +#include "ServerCursor.h" + +DisplayDriver::DisplayDriver(void) +{ + is_initialized=false; + cursor_visible=false; + show_on_move=false; + locker=new BLocker(); + + penpos.Set(0,0); + pensize=0.0; + + // initialize to BView defaults + highcol.red=0; + highcol.green=0; + highcol.blue=0; + highcol.alpha=0; + lowcol.red=255; + lowcol.green=255; + lowcol.blue=255; + lowcol.alpha=255; +} + +DisplayDriver::~DisplayDriver(void) +{ + delete locker; +} + +void DisplayDriver::Initialize(void) +{ // Loading loop to find proper driver or other setup for the driver +} + +bool DisplayDriver::IsInitialized(void) +{ // Let us know whether things worked out ok + return is_initialized; +} + +void DisplayDriver::Shutdown(void) +{ // For use by subclasses +} + +void DisplayDriver::SafeMode(void) +{ // Set video mode to 640x480x256 mode +} + +void DisplayDriver::Reset(void) +{ // Intended to reload and restart driver. Defaults to a safe mode +} + +void DisplayDriver::Clear(uint8 red,uint8 green,uint8 blue) +{ +} + +void DisplayDriver::Clear(rgb_color col) +{ +} + +void DisplayDriver::SetScreen(uint32 space) +{ // Set the screen to a particular mode +} + +int32 DisplayDriver::GetHeight(void) +{ // Gets the height of the current mode + return ginfo->height; +} + +int32 DisplayDriver::GetWidth(void) +{ // Gets the width of the current mode + return ginfo->width; +} + +int DisplayDriver::GetDepth(void) +{ // Gets the color depth of the current mode + return ginfo->bytes_per_row; +} + +void DisplayDriver::Blit(BPoint dest, ServerBitmap *sourcebmp, ServerBitmap *destbmp) +{ // Screen-to-screen bitmap copying +} + +void DisplayDriver::DrawBitmap(ServerBitmap *bitmap) +{ +} + +void DisplayDriver::DrawChar(char c, BPoint point) +{ +} + +void DisplayDriver::DrawString(char *string, int length, BPoint point) +{ +} + +void DisplayDriver::FillArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern) +{ +} + +void DisplayDriver::FillBezier(BPoint *points, uint8 *pattern) +{ +} + +void DisplayDriver::FillEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern) +{ +} + +void DisplayDriver::FillPolygon(int *x, int *y, int numpoints, bool is_closed) +{ +} + +void DisplayDriver::FillRect(BRect rect, uint8 *pattern) +{ +} + +void DisplayDriver::FillRegion(BRegion *region) +{ +} + +void DisplayDriver::FillRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern) +{ +} + +void DisplayDriver::FillShape(BShape *shape) +{ +} + +void DisplayDriver::FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern) +{ +} + +void DisplayDriver::HideCursor(void) +{ +} + +bool DisplayDriver::IsCursorHidden(void) +{ + return false; +} + +void DisplayDriver::ObscureCursor(void) +{ // Hides cursor until mouse is moved +} + +void DisplayDriver::MoveCursorTo(float x, float y) +{ +} + +void DisplayDriver::MovePenTo(BPoint pt) +{ // Moves the graphics pen to this position +} + +BPoint DisplayDriver::PenPosition(void) +{ + return penpos; +} + +float DisplayDriver::PenSize(void) +{ + return pensize; +} + +void DisplayDriver::SetCursor(ServerCursor *cursor) +{ +} + +void DisplayDriver::SetCursor(int32 value) +{ // This is used just to provide an easy way of setting one of the default cursors + // Then again, I may just get rid of this thing. +} + +void DisplayDriver::SetHighColor(uint8 r,uint8 g,uint8 b,uint8 a=255) +{ +} + +void DisplayDriver::SetLowColor(uint8 r,uint8 g,uint8 b,uint8 a=255) +{ +} + +void DisplayDriver::SetPenSize(float size) +{ +} + +void DisplayDriver::SetPixel(int x, int y, uint8 *pattern) +{ // Internal function utilized by other functions to draw to the buffer + // Will eventually be an inline function +} + +void DisplayDriver::ShowCursor(void) +{ +} + +void DisplayDriver::StrokeArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern) +{ +} + +void DisplayDriver::StrokeBezier(BPoint *points, uint8 *pattern) +{ +} + +void DisplayDriver::StrokeEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern) +{ +} + +void DisplayDriver::StrokeLine(BPoint point, uint8 *pattern) +{ +} + +void DisplayDriver::StrokePolygon(int *x, int *y, int numpoints, bool is_closed) +{ +} + +void DisplayDriver::StrokeRect(BRect rect, uint8 *pattern) +{ +} + +void DisplayDriver::StrokeRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern) +{ +} + +void DisplayDriver::StrokeShape(BShape *shape) +{ +} + +void DisplayDriver::StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern) +{ +} diff --git a/src/servers/app/proto4/DisplayDriver.h b/src/servers/app/proto4/DisplayDriver.h new file mode 100644 index 0000000000..3552e0a0d9 --- /dev/null +++ b/src/servers/app/proto4/DisplayDriver.h @@ -0,0 +1,124 @@ +#ifndef _GFX_DRIVER_H_ +#define _GFX_DRIVER_H_ + +#include +#include +#include +#include "Desktop.h" + +class ServerBitmap; +class ServerCursor; + +#ifndef ROUND + #define ROUND(a) ( (a-long(a))>=.5)?(long(a)+1):(long(a)) +#endif + +typedef struct +{ + uchar *xormask, *andmask; + int32 width, height; + int32 hotx, hoty; + +} cursor_data; + +#ifndef HOOK_DEFINE_CURSOR + +#define HOOK_DEFINE_CURSOR 0 +#define HOOK_MOVE_CURSOR 1 +#define HOOK_SHOW_CURSOR 2 +#define HOOK_DRAW_LINE_8BIT 3 +#define HOOK_DRAW_LINE_16BIT 12 +#define HOOK_DRAW_LINE_32BIT 4 +#define HOOK_DRAW_RECT_8BIT 5 +#define HOOK_DRAW_RECT_16BIT 13 +#define HOOK_DRAW_RECT_32BIT 6 +#define HOOK_BLIT 7 +#define HOOK_DRAW_ARRAY_8BIT 8 +#define HOOK_DRAW_ARRAY_16BIT 14 // Not implemented in current R5 drivers +#define HOOK_DRAW_ARRAY_32BIT 9 +#define HOOK_SYNC 10 +#define HOOK_INVERT_RECT 11 + +#endif + +class ServerCursor; + +class DisplayDriver +{ +public: + DisplayDriver(void); + virtual ~DisplayDriver(void); + + virtual void Initialize(void); // Sets the driver + virtual bool IsInitialized(void); + virtual void Shutdown(void); // You never know when you'll need this + + virtual void SafeMode(void); // Easy-access functions for common tasks + virtual void Reset(void); + virtual void Clear(uint8 red,uint8 green,uint8 blue); + virtual void Clear(rgb_color col); + + // Settings functions + virtual void SetScreen(uint32 space); + virtual int32 GetHeight(void); + virtual int32 GetWidth(void); + virtual int GetDepth(void); + + // Drawing functions + virtual void Blit(BPoint dest, ServerBitmap *src, ServerBitmap *dest); + virtual void DrawBitmap(ServerBitmap *bitmap); + virtual void DrawChar(char c, BPoint point); + virtual void DrawString(char *string, int length, BPoint point); + + virtual void FillArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern); + virtual void FillBezier(BPoint *points, uint8 *pattern); + virtual void FillEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern); + virtual void FillPolygon(int *x, int *y, int numpoints, bool is_closed); + virtual void FillRect(BRect rect, uint8 *pattern); + virtual void FillRegion(BRegion *region); + virtual void FillRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern); + virtual void FillShape(BShape *shape); + virtual void FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern); + +// virtual void GetBlendingMode(source_alpha *srcmode, alpha_function *funcmode); +// virtual drawing_mode GetDrawingMode(void); + virtual void HideCursor(void); + virtual bool IsCursorHidden(void); + virtual void MoveCursorTo(float x, float y); + virtual void MovePenTo(BPoint pt); + virtual void ObscureCursor(void); + virtual BPoint PenPosition(void); + virtual float PenSize(void); +// virtual void SetBlendingMode(source_alpha srcmode, alpha_function funcmode); + virtual void SetCursor(int32 value); + virtual void SetCursor(ServerCursor *cursor); +// virtual void SetDrawingMode(drawing_mode mode); + virtual void ShowCursor(void); + virtual void SetHighColor(uint8 r,uint8 g,uint8 b,uint8 a=255); + virtual void SetLowColor(uint8 r,uint8 g,uint8 b,uint8 a=255); + virtual void SetPenSize(float size); + virtual void SetPixel(int x, int y, uint8 *pattern); + + virtual void StrokeArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern); + virtual void StrokeBezier(BPoint *points, uint8 *pattern); + virtual void StrokeEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern); + virtual void StrokeLine(BPoint point, uint8 *pattern); + virtual void StrokePolygon(int *x, int *y, int numpoints, bool is_closed); + virtual void StrokeRect(BRect rect,uint8 *pattern); + virtual void StrokeRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern); + virtual void StrokeShape(BShape *shape); + virtual void StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern); + + graphics_card_hook ghooks[48]; + graphics_card_info *ginfo; + +protected: + bool is_initialized, cursor_visible, show_on_move; + ServerCursor *current_cursor; + BLocker *locker; + rgb_color highcol, lowcol; + BPoint penpos; + float pensize; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto4/Globals.h b/src/servers/app/proto4/Globals.h new file mode 100644 index 0000000000..2753cad1aa --- /dev/null +++ b/src/servers/app/proto4/Globals.h @@ -0,0 +1,7 @@ +#ifndef _SERVER_GLOBALS_H_ +#define _SERVER_GLOBALS_H_ + +#include +BList *gBitmaplist, *gLayerlist; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto4/Layer.cpp b/src/servers/app/proto4/Layer.cpp new file mode 100644 index 0000000000..4be5bbfae2 --- /dev/null +++ b/src/servers/app/proto4/Layer.cpp @@ -0,0 +1,281 @@ +/* + Layer.cpp: + +*/ +#include +#include +#include "ServerWindow.h" +#include "Layer.h" + +Layer::Layer(ServerWindow *Win, const char *Name, Layer *Parent, + BRect &Frame, int32 Flags) +{ + Initialize(); + flags=Flags; + frame=Frame; + if(Name!=NULL) + { + name=new char[strlen(Name)]; + cout << "Layer::Layer name=" << strcpy((char *)name, Name) << endl; + } + else + name=NULL; + if(Parent!=NULL) + Parent->AddChild(this); +} + +Layer::~Layer(void) +{ +} + +void Layer::Initialize(void) +{ + visible=NULL; + full=NULL; + update=NULL; + high.red=255; high.green=255; high.blue=255; high.alpha=255; + low.red=255; low.green=255; low.blue=255; low.alpha=255; + erase.red=255; erase.green=255; erase.blue=255; erase.alpha=255; + drawingmode=B_OP_COPY; + parent=NULL; + uppersibling=NULL; + lowersibling=NULL; + topchild=NULL; + bottomchild=NULL; + hidecount=0; +} + +void Layer::AddChild(Layer *child, bool topmost=true) +{ + // If we don't have any children, simply add the thing. + if (bottomchild==NULL && topchild==NULL) + { + bottomchild=child; + topchild=child; + child->lowersibling=NULL; + child->uppersibling=NULL; + } + else + { + if (topmost) + { + // "Move" the top child if there is one already and add to the + // top of the tree + if (topchild!=NULL) + topchild->uppersibling = child; + + topchild=child; + child->uppersibling= NULL; + child->lowersibling = topchild; + } + else + { + // Add layer to bottom of tree unless there are no other + // children + Layer *lay=bottomchild; + if (lay!=NULL) + { + child->uppersibling=lay; + child->lowersibling=lay->lowersibling; + lay->lowersibling=child; + + if(child->lowersibling!=NULL) + child->lowersibling->uppersibling=child; + else + bottomchild=child; + } + else + { + topchild=child; + topchild->uppersibling=child; + child->lowersibling=topchild; + child->uppersibling=NULL; + } + } + } + child->parent = this; + child->SetAddedData(hidecount); +} + +void Layer::RemoveChild(Layer *child) +{ + if(child->parent!=this) + { + cout << "DEBUG: attempt to remove a non-child layer\n" << endl; + return; + } + + if (child==bottomchild) + bottomchild=child->uppersibling; + + if (child==bottomchild) + bottomchild=child->uppersibling; + + if (child->lowersibling!=NULL) + child->lowersibling->uppersibling=child->uppersibling; + + if (child->uppersibling!=NULL) + child->uppersibling->lowersibling=child->lowersibling; + + child->parent=NULL; + child->lowersibling=NULL; + child->uppersibling=NULL; +} + +void Layer::RemoveSelf(void) +{ + if (parent!=NULL) + parent->RemoveChild(this); +} + +void Layer::SetAddedData(uint8 count) +{ + hidecount+=count; + Layer *lay; + for (lay=topchild; lay!=NULL; lay=lay->lowersibling) + lay->SetAddedData(count); +} + +void Layer::Show(void) +{ + hidecount--; + if(hidecount==0) + SetDirty(true); +} + +void Layer::Hide(void) +{ + if(parent==NULL) + { + cout << "DEBUG: attempt to hide an orphan layer" << endl; + return; + } + if(hidecount==0) + { + // Invalidate any sibling layers when this gets hidden so that + // we see what's left. This is a slower way to do things, but it + // works + Layer *sibling; + for (sibling=parent->bottomchild; sibling!=NULL; sibling=sibling->uppersibling) + { + if (sibling->frame.Intersects(frame)) + { + sibling->MarkModified(frame & sibling->frame); + } + } + + // Hide all child layers + Layer *child; + for (child=topchild; child!=NULL; child=child->lowersibling) + { + child->Hide(); + } + } + hidecount++; +} + +bool Layer::IsVisible(void) +{ + return (hidecount==0)?true:false; +} + +void Layer::Update(bool ForceUpdate) +{ +} + +void Layer::SetFrame(const BRect &Rect) +{ +} + +BRect Layer::Frame(void) +{ + return frame; +} + +BRect Layer::Bounds(void) +{ + BRect r=frame; + r.OffsetTo(0,0); + return r; +} + +void Layer::Invalidate(const BRect &rect) +{ + if (hidecount==0) + { + if (update==NULL) + update=new BRegion(rect); + else + update->Include(rect); + } +} + +// Invalidates the entire layer, possibly including the child layers +void Layer::Invalidate(bool recursive) +{ + if (hidecount==0) + { + delete update; + update = new BRegion(frame); + + if (recursive) + { + for (Layer *lay=bottomchild; lay!=NULL; lay=lay->uppersibling) + lay->Invalidate(true); + } + } +} + +// This invalidates the layer and all its child layers +void Layer::SetDirty(bool flag) +{ + isdirty=flag; + + Layer *lay; + for (lay=bottomchild; lay!=NULL; lay=lay->uppersibling ) + { + lay->SetDirty(flag); + } +} + +void Layer::AddRegion(BRegion *Region) +{ +} + +void Layer::RemoveRegions(void) +{ +/* delete visible; + delete full; + delete update; + + visible=NULL; + full=NULL; + update=NULL; + + Layer *lay; + for (lay=topchild; lay!=NULL; lay=lay->lowersibling ) + lay->DeleteRegions(); +*/ +} + +void Layer::UpdateRegions(bool ForceUpdate=true, bool Root=true) +{ +} + +void Layer::MarkModified(BRect rect) +{ + if (frame.Intersects(rect)) + { + BRect r=rect & frame; + isdirty=true; + + Layer* lay; + for (lay=bottomchild; lay!=NULL; lay=lay->uppersibling ) + lay->MarkModified(r); + } +} + +// virtual function to be defined by child classes +void Layer::Draw(const BRect &Rect) +{ +} diff --git a/src/servers/app/proto4/Layer.h b/src/servers/app/proto4/Layer.h new file mode 100644 index 0000000000..edcbd26eeb --- /dev/null +++ b/src/servers/app/proto4/Layer.h @@ -0,0 +1,68 @@ +#ifndef _LAYER_H_ +#define _LAYER_H_ + +#include +#include +#include + +class ServerWindow; + +class Layer +{ +public: + Layer(ServerWindow *Win, const char *Name, Layer *Parent, BRect &Frame, int32 Flags); + virtual ~Layer(void); + + void Initialize(void); + void Show(void); + void Hide(void); + bool IsVisible(void); + void Update(bool ForceUpdate); + + void AddChild(Layer *child, bool topmost=true); + void RemoveChild(Layer *child); + void RemoveSelf(void); + void SetAddedData(uint8 count); + + virtual void SetFrame(const BRect &Rect); + BRect Frame(void); + BRect Bounds(void); + + void Invalidate(const BRect &rect); + void Invalidate(bool recursive); + void AddRegion(BRegion *Region); + void RemoveRegions(void); + void UpdateRegions(bool ForceUpdate=true, bool Root=true); + void SetDirty(bool flag); + void MarkModified(BRect rect); + + // Render functions: + virtual void Draw(const BRect &Rect); + + const char *name; + int32 handle; + ServerWindow *window; // Window associated with this. NULL for background layer + + BRect frame; + + BRegion *visible, // Everything currently visible + *full, // The complete region + *update; // Area to be updated at next redraw + + int32 flags; // Various flags for behavior + uint8 hidecount; // tracks the number of hide calls + bool isdirty; // has regions which are invalid + + // The whole set of layers is actually a tree + Layer *topchild, *bottomchild; + Layer *uppersibling, *lowersibling; + Layer *parent; + + // Render state: + BPoint penpos; + rgb_color high, low, erase; + + int32 drawingmode; +}; + +#endif diff --git a/src/servers/app/proto4/PortLink.cpp b/src/servers/app/proto4/PortLink.cpp new file mode 100644 index 0000000000..8fba724569 --- /dev/null +++ b/src/servers/app/proto4/PortLink.cpp @@ -0,0 +1,438 @@ +/* + PortLink.cpp: + A helper class for port-based messaging + +------------------------------------------------------------------------ +How it works: + The class utilizes a fixed-size array of PortLinkData object pointers. When +data is attached, a new PortLinkData object is allocated and a copy of the +passed data is created inside it. When the time comes for the message to be sent, +the data is pieced together into a flattened array and written to the port. +------------------------------------------------------------------------ +Data members: + +*attachments[] - fixed-size array of pointers used to hold the attached data +opcode - message value which is sent along with any data +target - port to which the message is sent when Flush() is called +replyport - port used with synchronous messaging - FlushWithReply() +bufferlength - total bytes taken up by attachments +num_attachments - internal variable which is used to track which "slot" + will be the next one to receive an attachment object +*/ + +#include "PortLink.h" +#include +#include +#include + +//#define PLDEBUG + +// Internal data storage class for holding attached data whilst it is waiting +// to be Flattened() and then Flushed(). There is no need for this to be called outside +// the PortLink class. +class PortLinkData +{ +public: + PortLinkData(void); + ~PortLinkData(void); + bool Set(void *data, size_t size); + char *buffer; + size_t buffersize; +}; + +PortLink::PortLink(port_id port) +{ + // For this class to be useful (and to prevent a lot of init problems) + // we require a port in the constructor + target=port; + + // We start out without any data attached to the port message + num_attachments=0; + opcode=0; + bufferlength=0; + replyport=create_port(30,"PortLink reply port"); +} + +PortLink::~PortLink(void) +{ + // If, for some odd reason, this is deleted with something attached, + // free the memory used by the attachments. We do not flush the queue + // because the port may no longer be valid in cases such as the app + // is in the process of quitting + MakeEmpty(); +} + +void PortLink::SetOpCode(int32 code) +{ + // Sets the message code. This does not change once the message is sent. + // Another call to SetOpCode() is required for such things. + opcode=code; +} + +void PortLink::SetPort(port_id port) +{ + // Sets the target port. While not necessary in most uses, this exists + // mostly to prevent flexibility problems + target=port; +} + +port_id PortLink::GetPort(void) +{ + // Simply returns the port at which the object is pointed. + return target; +} + +void PortLink::Flush(bigtime_t timeout=B_INFINITE_TIMEOUT) +{ + // Fires a message off to the target, complete with attachments. NOTE: + // the recipient must delete all attachments, being the PortLink object assumes + // no responsiblity for the attachments once the message is sent. + int8 *msgbuffer; + int32 size; + + if(num_attachments>0) + { + FlattenData(&msgbuffer,&size); + + // Dump message to port, reset attachments, and clean up + if(timeout!=B_INFINITE_TIMEOUT) + write_port_etc(target,opcode,msgbuffer,size,B_TIMEOUT, timeout); + else + write_port(target,opcode,msgbuffer,size); + MakeEmpty(); + } + else + { + if(timeout!=B_INFINITE_TIMEOUT) + write_port_etc(target,opcode,NULL,0,B_TIMEOUT, timeout); + else + write_port(target,opcode,NULL,0); + } +} + +int8* PortLink::FlushWithReply(int32 *code, status_t *status, ssize_t *buffersize, bigtime_t timeout=B_INFINITE_TIMEOUT) +{ + // Fires a message to the target and then waits for a reply. The target will + // receive a message with the first item being the port_id to reply to. + // NOTE: like Flush(), any attached data must be deleted. + + // Effectively, an Attach() call inlined for changes + + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + { + *status=B_ERROR; + return NULL; + } + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&replyport,sizeof(port_id))) + { + bufferlength+=sizeof(port_id); + } + else + { + delete pld; + *status=B_ERROR; + return NULL; + } + + // Flatten() inlined to make some necessary changes + int8 *buffer=new int8[bufferlength]; + int8 *bufferindex=buffer; + size_t size=0; + + // attach our port_id first + memcpy(bufferindex, pld->buffer, pld->buffersize); + bufferindex += pld->buffersize; + size+=pld->buffersize; + + // attach everything else + for(int i=0;ibuffer, pld->buffersize); + bufferindex += pld->buffersize; + size+=pld->buffersize; + } + + // Flush the thing....FOOSH! :P + write_port(target,opcode,buffer,size); + MakeEmpty(); + delete buffer; + + // Now we wait for the reply + if(timeout==B_INFINITE_TIMEOUT) + { + *buffersize=port_buffer_size(replyport); + if(*buffersize>0) + buffer=(int8*)new int8[*buffersize]; + read_port(replyport,code, buffer, *buffersize); + } + else + { + *buffersize=port_buffer_size_etc(replyport,0,timeout); + if(*buffersize==B_TIMED_OUT) + { + *status=*buffersize; + return NULL; + } + if(*buffersize>0) + buffer=(int8*)new int8[*buffersize]; + read_port(replyport,code, buffer, *buffersize); + } + + // We got this far, so we apparently have some data + *status=B_OK; + return buffer; +} + +void PortLink::Attach(void *data, size_t size) +{ + // This is the member called to attach data to a message. Attachments are + // treated to be in 'Append' mode, tacking on each attached piece of data + // to the end of the list. + + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + if(size==0) + return; + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +// These functions were added for a major convenience in passing common types +// Eventually, I'd like to templatize these, but for now, this'll do + +void PortLink::Attach(int32 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int32); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(int16 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int16); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(int8 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int8); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(float data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(float); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(bool data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(bool); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(BRect data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(BRect); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(BPoint data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(BPoint); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::FlattenData(int8 **buffer,int32 *size) +{ + // This function is where all the magic happens, but it is strictly internal. + // It iterates through each PortLinkData object and copies it to the main buffer + // which ends up, ultimately, being written to the PortLink's target port. + + // skip if there aree no attachments + if(bufferlength<1) + return; + + *buffer=new int8[bufferlength]; + int8 *bufferindex=*buffer; + PortLinkData *pld; + *size=0; + + for(int i=0;ibuffer, pld->buffersize); + bufferindex += pld->buffersize; + *size+=pld->buffersize; + } +} + +void PortLink::MakeEmpty(void) +{ + // Nukes all the attachments currently held by the PortLink class + if(num_attachments!=0) + { + for(int i=0; i0) + free(buffer); +} + +bool PortLinkData::Set(void *data, size_t size) +{ + // Function copies the passed to the internal buffers for storage + if(size>0 && buffersize==0 && data!=NULL) + { + buffer=(char *)malloc(size); + if(buffer==NULL) + return false; + memcpy(buffer, data, size); + buffersize=size; + return true; + } + return false; +} diff --git a/src/servers/app/proto4/PortLink.h b/src/servers/app/proto4/PortLink.h new file mode 100644 index 0000000000..9f5432daab --- /dev/null +++ b/src/servers/app/proto4/PortLink.h @@ -0,0 +1,43 @@ +#ifndef _PORTLINK_H_ +#define _PORTLINK_H_ + +#include +#include +#include +#include + +#ifndef _PORTLINK_BUFFERSIZE +#define _PORTLINK_MAX_ATTACHMENTS 50 +#endif + +class PortLinkData; + +class PortLink +{ +public: + PortLink(port_id port); + ~PortLink(void); + void SetOpCode(int32 code); + void SetPort(port_id port); + port_id GetPort(void); + void Flush(bigtime_t timeout=B_INFINITE_TIMEOUT); + int8* FlushWithReply(int32 *code, status_t *status, ssize_t *buffersize, + bigtime_t timeout=B_INFINITE_TIMEOUT); + void Attach(void *data, size_t size); + void Attach(int32 data); + void Attach(int16 data); + void Attach(int8 data); + void Attach(float data); + void Attach(bool data); + void Attach(BRect data); + void Attach(BPoint data); + void MakeEmpty(void); +protected: + void FlattenData(int8 **buffer,int32 *size); + port_id target, replyport; + int32 opcode, bufferlength; + int num_attachments; + PortLinkData *attachments[_PORTLINK_MAX_ATTACHMENTS]; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto4/README b/src/servers/app/proto4/README new file mode 100644 index 0000000000..0a1e3bb834 --- /dev/null +++ b/src/servers/app/proto4/README @@ -0,0 +1,9 @@ +OpenBeOS App Server Test Prototype #4 + +This prototype is an extension of the third one, where the TestApp has become a test bed for graphics functions. The graphics-access object used, ViewDriver, has most of the useful BView calls implemented and tested. Such was necessary to proceed to the next steps. The functions not implemented were not done either because it was way too much work or simply not possible to do with the current test application. They will have to wait until BView is done. In any event, not bad for 2 weeks' work. + +This is an example of both a work in progress and a lot of research at the same time. Many of the concepts used in this prototype will be used in the real server. It doesn't do much, but the fact that it exists and does what it does is the result of a *lot* of work. + +The code is reasonably (IMHO) well-commented and should be easy to understand at first glance. Also included are some extra files which I didn't feel like throwing out or are in place for future development. ;D Enjoy. + +--DarkWyrm \ No newline at end of file diff --git a/src/servers/app/proto4/ServerApp.cpp b/src/servers/app/proto4/ServerApp.cpp new file mode 100644 index 0000000000..87e9537b7c --- /dev/null +++ b/src/servers/app/proto4/ServerApp.cpp @@ -0,0 +1,759 @@ +/* + ServerApp.cpp + Class which works with a BApplication. Handles all messages coming + from and going to its application. +*/ +//#define DEBUG_SERVERAPP_MSGS +//#define DEBUG_SERVERAPP_CURSORS + +#include +#include +#include +#include "Desktop.h" +#include "DisplayDriver.h" +#include "ServerApp.h" +#include "ServerWindow.h" +#include "ServerBitmap.h" +#include "ServerProtocol.h" +#include "ServerCursor.h" +#include "PortLink.h" +#include +#include +#include +#include "DebugTools.h" + +ServerApp::ServerApp(port_id msgport, char *signature) +{ + // need to copy the signature because the message buffer + // owns the copy which we are passed as a parameter. + if(signature) + { + app_sig=new char[strlen(signature)]; + sprintf(app_sig,signature); + } + else + { + app_sig=new char[strlen("Application")]; + sprintf(app_sig,"Application"); + } + + // sender is the monitored app's event port + sender=msgport; + applink=new PortLink(sender); + + // receiver is the port to which the app sends messages for the server + receiver=create_port(30,app_sig); + //printf("ServerApp port for app %s is at %ld\n",app_sig,receiver); + if(receiver==B_NO_MORE_PORTS) + { + // uh-oh. We have a serious problem. Tell the app to quit + applink->SetOpCode(B_QUIT_REQUESTED); + applink->Flush(); + } + else + { + // Everything checks out, so tell the application + // where to send future messages + applink->SetOpCode(SET_SERVER_PORT); + applink->Attach(&receiver,sizeof(port_id)); + applink->Flush(); + } + winlist=new BList(0); + bmplist=new BList(0); + driver=get_gfxdriver(); + isactive=false; + cursor=new ServerCursor(); + + // This exists for testing the graphics access module and will disappear + // when layers are implemented + high.red=255; + high.green=255; + high.blue=255; + high.alpha=255; + low.red=0; + low.green=0; + low.blue=0; + low.alpha=255; +} + +ServerApp::~ServerApp(void) +{ + int32 i; + ServerWindow *tempwin; + for(i=0;iCountItems();i++) + { + tempwin=(ServerWindow*)winlist->ItemAt(i); + delete tempwin; + } + winlist->MakeEmpty(); + delete winlist; + + ServerBitmap *tempbmp; + for(i=0;iCountItems();i++) + { + tempbmp=(ServerBitmap*)bmplist->ItemAt(i); + delete tempbmp; + } + bmplist->MakeEmpty(); + delete bmplist; + + delete app_sig; + delete applink; + delete cursor; +} + +bool ServerApp::Run(void) +{ + // Unlike a BApplication, a ServerApp is *supposed* to return immediately + // when its Run function is called. + monitor_thread=spawn_thread(MonitorApp,app_sig,B_NORMAL_PRIORITY,this); + if(monitor_thread==B_NO_MORE_THREADS || monitor_thread==B_NO_MEMORY) + return false; + resume_thread(monitor_thread); + return true; +} + +int32 ServerApp::MonitorApp(void *data) +{ + ServerApp *app=(ServerApp *)data; + app->Loop(); + exit_thread(0); + return 0; +} + +void ServerApp::Loop(void) +{ + // Message-dispatching loop for the ServerApp + int32 msgcode; + int8 *msgbuffer=NULL; + ssize_t buffersize,bytesread; + + for(;;) + { + buffersize=port_buffer_size(receiver); + + if(buffersize>0) + { + // buffers are PortLink messages. Allocate necessary buffer and + // we'll cast it as a BMessage. + msgbuffer=new int8[buffersize]; + bytesread=read_port(receiver,&msgcode,msgbuffer,buffersize); + } + else + bytesread=read_port(receiver,&msgcode,NULL,0); + if (bytesread != B_BAD_PORT_ID && bytesread != B_TIMED_OUT && bytesread != B_WOULD_BLOCK) + { + switch(msgcode) + { +// -------------- Messages received from the Application ------------------ + case B_QUIT_REQUESTED: + { + // Our BApplication sent us this message when it quit. + // We need to ask the app_server to delete our monitor + port_id serverport=find_port(SERVER_PORT_NAME); + if(serverport==B_NAME_NOT_FOUND) + { + printf("PANIC: ServerApp %s could not find the app_server port!\n",app_sig); + break; + } + + applink->SetPort(serverport); + applink->SetOpCode(DELETE_APP); + applink->Attach(&monitor_thread,sizeof(thread_id)); + applink->Flush(); + break; + } + case CREATE_WINDOW: + case DELETE_WINDOW: + case SHOW_CURSOR: + case HIDE_CURSOR: + case OBSCURE_CURSOR: + case SET_CURSOR_BCURSOR: + case SET_CURSOR_DATA: + case SET_CURSOR_BBITMAP: + case GFX_MOVEPENBY: + case GFX_MOVEPENTO: + case GFX_SETPENSIZE: + case GFX_COUNT_WORKSPACES: + case GFX_SET_WORKSPACE_COUNT: + case GFX_CURRENT_WORKSPACE: + case GFX_ACTIVATE_WORKSPACE: + case GFX_SYSTEM_COLORS: + case GFX_SET_SCREEN_MODE: + case GFX_GET_SCROLLBAR_INFO: + case GFX_SET_SCROLLBAR_INFO: + case GFX_IDLE_TIME: + case GFX_SELECT_PRINTER_PANEL: + case GFX_ADD_PRINTER_PANEL: + case GFX_RUN_BE_ABOUT: + case GFX_SET_FOCUS_FOLLOWS_MOUSE: + case GFX_FOCUS_FOLLOWS_MOUSE: + + // Graphics messages + case GFX_SET_HIGH_COLOR: + case GFX_SET_LOW_COLOR: + case GFX_DRAW_STRING: + case GFX_SET_FONT_SIZE: + case GFX_STROKE_ARC: + case GFX_STROKE_BEZIER: + case GFX_STROKE_ELLIPSE: + case GFX_STROKE_LINE: + case GFX_STROKE_POLYGON: + case GFX_STROKE_RECT: + case GFX_STROKE_ROUNDRECT: + case GFX_STROKE_SHAPE: + case GFX_STROKE_TRIANGLE: + case GFX_FILL_ARC: + case GFX_FILL_BEZIER: + case GFX_FILL_ELLIPSE: + case GFX_FILL_POLYGON: + case GFX_FILL_RECT: + case GFX_FILL_REGION: + case GFX_FILL_ROUNDRECT: + case GFX_FILL_SHAPE: + case GFX_FILL_TRIANGLE: + DispatchMessage(msgcode, msgbuffer); + break; + +// -------------- Messages received from the Server ------------------------ + // Mouse messages simply get passed onto the active app for now + case B_MOUSE_UP: + case B_MOUSE_DOWN: + case B_MOUSE_MOVED: + { + // everything is formatted as it should be, so just call + // write_port. Eventually, this will be replaced by a + // BMessage + write_port(sender, msgcode, msgbuffer, buffersize); + break; + } + case QUIT_APP: + { + // This message is received from the app_server thread + // because the server was asked to quit. Thus, we + // ask all apps to quit. This is NOT the same as system + // shutdown and will happen only in testing + + //printf("ServerApp asking %s to quit\n",app_sig); + applink->SetOpCode(B_QUIT_REQUESTED); + applink->Flush(); + break; + } + default: + { +#ifdef DEBUG_SERVERAPP_MSGS +cout << "ServerApp received unrecognized code: "; +TranslateMessageCodeToStream(msgcode); +cout << endl << flush; +#endif + break; + } + } + + } + + if(buffersize>0) + delete msgbuffer; + + if(msgcode==B_QUIT_REQUESTED) + break; + } +} + +void ServerApp::DispatchMessage(int32 code, int8 *buffer) +{ +#ifdef DEBUG_SERVERAPP_MSGS +cout << "ServerApp Message: "; +TranslateMessageCodeToStream(code); +cout << endl << flush; +#endif + +int8 *index=buffer; + switch(code) + { + case CREATE_WINDOW: + { + // Attached data + // + break; + } + case DELETE_WINDOW: + { + // Attached data + break; + } + case GFX_SET_SCREEN_MODE: + { + // Attached data + // 1) int32 workspace # + // 2) uint32 screen mode + // 3) bool make default + int32 workspace=*((int32*)index); index+=sizeof(int32); + uint32 mode=*((uint32*)index); index+=sizeof(uint32); + + SetScreenSpace(workspace,mode,*((bool*)index)); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp: SetScreenMode(%ld,%lu,%s)\n",workspace, + mode,(*((bool*)index)==true)?"true":"false"); +#endif + break; + } + case GFX_ACTIVATE_WORKSPACE: + { + // Attached data + // 1) int32 workspace index + ActivateWorkspace(*((int32*)index)); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp: ActivateWorkspace(%ld)\n",*((int32*)index)); +#endif + break; + } + case SHOW_CURSOR: + { + driver->ShowCursor(); + break; + } + case HIDE_CURSOR: + { + driver->HideCursor(); + break; + } + case OBSCURE_CURSOR: + { + driver->ObscureCursor(); + break; + } + case SET_CURSOR_DATA: + { + // Attached data: 68 bytes of cursor data + + // Get the data, update the app's cursor, and update the + // app's cursor if active. + int8 cdata[68]; + memcpy(cdata, buffer, 68); + cursor->SetCursor(cdata); + driver->SetCursor(cursor); +#ifdef DEBUG_SERVERAPP_CURSOR +printf("ServerApp: SetCursor(%d,%d,%d,%d)\n",r,g,b,a); +#endif + break; + } + case SET_CURSOR_BCURSOR: + // Not yet implemented + break; + + case SET_CURSOR_BBITMAP: + // Not yet implemented + break; + + // Graphics messages + case GFX_SET_HIGH_COLOR: + { + // Attached data: + // 1) uint8 red + // 2) uint8 green + // 3) uint8 blue + // 4) uint8 alpha + + uint8 r,g,b,a; + r=*((uint8*)index); index+=sizeof(uint8); + g=*((uint8*)index); index+=sizeof(uint8); + b=*((uint8*)index); index+=sizeof(uint8); + a=*((uint8*)index); + +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp: SetHighColor(%d,%d,%d,%d)\n",r,g,b,a); +#endif + driver->SetHighColor(r,g,b,a); + break; + } + case GFX_SET_LOW_COLOR: + { + // Attached data: + // 1) uint8 red + // 2) uint8 green + // 3) uint8 blue + // 4) uint8 alpha + + uint8 r,g,b,a; + r=*((uint8*)index); index+=sizeof(uint8); + g=*((uint8*)index); index+=sizeof(uint8); + b=*((uint8*)index); index+=sizeof(uint8); + a=*((uint8*)index); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp: SetHighColor(%d,%d,%d,%d)\n",r,g,b,a); +#endif + driver->SetLowColor(r,g,b,a); + break; + } + case GFX_MOVEPENBY: + { + // Attached data: + // 1) BPoint pt + + // Default functionality is MoveTo, so get the current position + // from the driver and compensate + BPoint *ptindex,passed_pt; + + ptindex=(BPoint*)index; + passed_pt=driver->PenPosition(); + passed_pt+=*ptindex; +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp MovePenBy: (%f,%f)\n",ptindex->x,ptindex->y); +printf("Pen moved to (%f,%f)\n",passed_pt.x,passed_pt.y); +#endif + driver->MovePenTo(passed_pt); + break; + } + case GFX_MOVEPENTO: + { + // Attached data: + // 1) BPoint pt + BPoint *pt; + pt=(BPoint*)index; +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp MovePenTo: (%f,%f)\n",pt->x,pt->y); +#endif + driver->MovePenTo(*pt); + break; + } + case GFX_SETPENSIZE: + { + // Attached data: + // 1) float pen size +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp SetPenSize(%f)\n",*((float*)index)); +#endif + driver->SetPenSize(*((float*)index)); + break; + } + case GFX_DRAW_STRING: + { + // Attached data: + // 1) uint16 string length + // 2) char * string + // 3) BPoint point + + uint16 length=*((uint16*)index); index+=sizeof(uint16); + char *string=new char[length]; + strcpy(string, (const char *)index); index+=length; + BPoint point=*((BPoint*)index); + +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp DrawString(%s, %d, BPoint(%f,%f))\n",string,length,point.x,point.y); +#endif + driver->DrawString(string, length, point); + delete string; + break; + } + case GFX_SET_FONT_SIZE: + break; + case GFX_STROKE_ARC: + { + // Attached data: + // 1) float center x + // 2) float center y + // 3) float x radius + // 4) float y radius + // 5) float starting angle + // 6) float span (arc length in degrees) + // 7) uint8[8] pattern + float cx,cy,rx,ry,angle,span; + + cx=*((float*)index); index+=sizeof(float); + cy=*((float*)index); index+=sizeof(float); + rx=*((float*)index); index+=sizeof(float); + ry=*((float*)index); index+=sizeof(float); + angle=*((float*)index); index+=sizeof(float); + span=*((float*)index); index+=sizeof(float); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp StrokeArc: "); +printf("Center: %f,%f\n",cx,cy); +printf("Radii: %f,%f\n",rx,ry); +printf("Angle, Span: %f,%f\n",angle, span); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->StrokeArc(cx,cy,rx,ry,angle,span,(uint8*)index); + break; + } + case GFX_STROKE_BEZIER: + { + // Attached data: + // 1) BPoint #1 + // 2) BPoint #2 + // 3) BPoint #3 + // 4) BPoint #4 + // 5) uint8[8] pattern + +#ifdef DEBUG_SERVERAPP_MSGS +BPoint *pt=(BPoint*)index; +printf("ServerApp StrokeBezier:\n"); +printf("Point 1: "); pt[0].PrintToStream(); +printf("Point 2: "); pt[1].PrintToStream(); +printf("Point 3: "); pt[2].PrintToStream(); +printf("Point 4: "); pt[3].PrintToStream(); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->StrokeBezier((BPoint*)index,(uint8*)(index+(sizeof(BPoint)*4))); + break; + } + case GFX_STROKE_ELLIPSE: + { + // Attached data: + // 1) float center x + // 2) float center y + // 3) float x radius + // 4) float y radius + // 5) uint8[8] pattern + float cx,cy,rx,ry; + + cx=*((float*)index); index+=sizeof(float); + cy=*((float*)index); index+=sizeof(float); + rx=*((float*)index); index+=sizeof(float); + ry=*((float*)index); index+=sizeof(float); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp StrokeEllipse: "); +printf("Center: %f,%f\n",cx,cy); +printf("Radii: %f,%f\n",rx,ry); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->StrokeEllipse(cx,cy,rx,ry,(uint8*)index); + break; + } + case GFX_STROKE_LINE: + { + // Attached data: + // 1) BPoint endpoint + // 2) uint8[8] pattern + BPoint *pt; + pt=(BPoint*)index; index+=sizeof(BPoint); + +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp StrokeLineTo: (%f,%f)\n",pt->x,pt->y); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->StrokeLine(*pt,(uint8*)index); + break; + } + case GFX_STROKE_POLYGON: + break; + case GFX_STROKE_RECT: + { + // Attached data: + // 1) BRect rect + // 2) uint8[8] pattern + BRect rect; + rect=*((BRect*)index); index+=sizeof(BRect); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp StrokeRect: "); rect.PrintToStream(); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->StrokeRect(rect, (uint8*)index); + break; + } + case GFX_STROKE_ROUNDRECT: + { + // Attached data: + // 1) BRect rect + // 2) float x_radius + // 3) float y_radius + // 4) uint8[8] pattern + BRect rect; + float x,y; + + rect=*((BRect*)index); index+=sizeof(BRect); + x=*((float*)index); index+=sizeof(float); + y=*((float*)index); index+=sizeof(float); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp StrokeRoundRect: "); rect.PrintToStream(); +printf("Radii: %f,%f\n",x,y); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->StrokeRoundRect(rect, x,y,(uint8*)index); + break; + } + case GFX_STROKE_SHAPE: + break; + case GFX_STROKE_TRIANGLE: + { + // Attached data + // 1) BPoint #1 + // 2) BPoint #2 + // 3) BPoint #3 + // 4) BRect invalid rect + // 5) uint8[8] pattern + BPoint pt1,pt2,pt3; + BRect rect; + pt1=*((BPoint*)index); index+=sizeof(BPoint); + pt2=*((BPoint*)index); index+=sizeof(BPoint); + pt3=*((BPoint*)index); index+=sizeof(BPoint); + rect=*((BRect*)index); index+=sizeof(BRect); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp StrokeTriangle: "); +printf("Point 1: "); pt1.PrintToStream(); +printf("Point 2: "); pt2.PrintToStream(); +printf("Point 3: "); pt3.PrintToStream(); +printf("Rectangle: "); rect.PrintToStream(); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->StrokeTriangle(pt1,pt2,pt3,rect,(uint8*)index); + break; + } + case GFX_FILL_ARC: + { + // Attached data: + // 1) float center x + // 2) float center y + // 3) float x radius + // 4) float y radius + // 5) float starting angle + // 6) float span (arc length in degrees) + // 7) uint8[8] pattern + float cx,cy,rx,ry,angle,span; + + cx=*((float*)index); index+=sizeof(float); + cy=*((float*)index); index+=sizeof(float); + rx=*((float*)index); index+=sizeof(float); + ry=*((float*)index); index+=sizeof(float); + angle=*((float*)index); index+=sizeof(float); + span=*((float*)index); index+=sizeof(float); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp FillArc: "); +printf("Center: %f,%f\n",cx,cy); +printf("Radii: %f,%f\n",rx,ry); +printf("Angle, Span: %f,%f\n",angle, span); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->FillArc(cx,cy,rx,ry,angle,span,(uint8*)index); + break; + } + case GFX_FILL_BEZIER: + { + // Attached data: + // 1) BPoint #1 + // 2) BPoint #2 + // 3) BPoint #3 + // 4) BPoint #4 + // 5) uint8[8] pattern + +#ifdef DEBUG_SERVERAPP_MSGS +BPoint *pt=(BPoint*)index; +printf("ServerApp FillBezier:\n"); +printf("Point 1: "); pt[0].PrintToStream(); +printf("Point 2: "); pt[1].PrintToStream(); +printf("Point 3: "); pt[2].PrintToStream(); +printf("Point 4: "); pt[3].PrintToStream(); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->FillBezier((BPoint*)index,(uint8*)(index+(sizeof(BPoint)*4))); + break; + } + case GFX_FILL_ELLIPSE: + { + // Attached data: + // 1) float center x + // 2) float center y + // 3) float x radius + // 4) float y radius + // 5) uint8[8] pattern + float cx,cy,rx,ry; + + cx=*((float*)index); index+=sizeof(float); + cy=*((float*)index); index+=sizeof(float); + rx=*((float*)index); index+=sizeof(float); + ry=*((float*)index); index+=sizeof(float); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp FillEllipse: "); +printf("Center: %f,%f\n",cx,cy); +printf("Radii: %f,%f\n",rx,ry); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->FillEllipse(cx,cy,rx,ry,(uint8*)index); + break; + } + case GFX_FILL_POLYGON: + break; + case GFX_FILL_RECT: + { + // Attached data: + // 1) BRect rect + // 2) uint8[8] pattern + BRect rect; + rect=*((BRect*)index); index+=sizeof(BRect); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp FillRect: "); rect.PrintToStream(); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->FillRect(rect, (uint8*)index); + break; + } + case GFX_FILL_REGION: + break; + case GFX_FILL_ROUNDRECT: + { + // Attached data: + // 1) BRect rect + // 2) float x_radius + // 3) float y_radius + // 4) uint8[8] pattern + BRect rect; + float x,y; + + rect=*((BRect*)index); index+=sizeof(BRect); + x=*((float*)index); index+=sizeof(float); + y=*((float*)index); index+=sizeof(float); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp FillRoundRect: "); rect.PrintToStream(); +printf("Radii: %f,%f\n",x,y); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->FillRoundRect(rect, x,y,(uint8*)index); + break; + } + case GFX_FILL_SHAPE: + break; + case GFX_FILL_TRIANGLE: + { + // Attached data + // 1) BPoint #1 + // 2) BPoint #2 + // 3) BPoint #3 + // 4) BRect invalid rect + // 5) uint8[8] pattern + BPoint pt1,pt2,pt3; + BRect rect; + pt1=*((BPoint*)index); index+=sizeof(BPoint); + pt2=*((BPoint*)index); index+=sizeof(BPoint); + pt3=*((BPoint*)index); index+=sizeof(BPoint); + rect=*((BRect*)index); index+=sizeof(BRect); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp FillTriangle: "); +printf("Point 1: "); pt1.PrintToStream(); +printf("Point 2: "); pt2.PrintToStream(); +printf("Point 3: "); pt3.PrintToStream(); +printf("Rectangle: "); rect.PrintToStream(); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->FillTriangle(pt1,pt2,pt3,rect,(uint8*)index); + break; + } + default: + { +#ifdef DEBUG_SERVERAPP_MSGS +cout << "DispatchMessage::Unrecognized code: "; +TranslateMessageCodeToStream(code); +cout << endl << flush; +#endif + break; + } + } +} + +// Prevent any preprocessor problems in case I screw something up +#ifdef DEBUG_SERVERAPP_MSGS +#undef DEBUG_SERVERAPP_MSGS +#endif + +#ifdef DEBUG_SERVERAPP_CURSORS +#undef DEBUG_SERVERAPP_CURSORS +#endif diff --git a/src/servers/app/proto4/ServerApp.h b/src/servers/app/proto4/ServerApp.h new file mode 100644 index 0000000000..3265d9d050 --- /dev/null +++ b/src/servers/app/proto4/ServerApp.h @@ -0,0 +1,35 @@ +#ifndef _SRVAPP_H_ +#define _SRVAPP_H_ + +#include +class BMessage; +class PortLink; +class BList; +class ServerCursor; +class DisplayDriver; + +class ServerApp +{ +public: + ServerApp(port_id msgport, char *signature); + ~ServerApp(void); + + bool Run(void); + static int32 MonitorApp(void *data); + void Loop(void); + void DispatchMessage(int32 code, int8 *buffer); + bool IsActive(void) { return isactive; } + void Activate(bool value) { isactive=value; } + + port_id sender,receiver; + char *app_sig; + thread_id monitor_thread; + PortLink *applink; + BList *winlist, *bmplist; + ServerCursor *cursor; + DisplayDriver *driver; + bool isactive; + rgb_color high, low; // just for testing until layers are implemented +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto4/ServerBitmap.cpp b/src/servers/app/proto4/ServerBitmap.cpp new file mode 100644 index 0000000000..b210a31c96 --- /dev/null +++ b/src/servers/app/proto4/ServerBitmap.cpp @@ -0,0 +1,252 @@ +/* + ServerBitmap.cpp + Bitmap class which is intended to provide an easy way to package all the + data associated with a picture. It's very low-level, so there's still + plenty to do when coding with 'em. Also, they're used to access draw on the + frame buffer in a relatively easy way, although it is currently unclear + whether this functionality will even be necessary. +*/ + +// These three includes for ServerBitmap(const char *path_to_image_file) only +#include +#include +#include + +#include +#include "ServerBitmap.h" +#include "Desktop.h" + +ServerBitmap::ServerBitmap(BRect rect,color_space space,int32 BytesPerLine=0) +{ + width=rect.IntegerWidth()+1; + height=rect.IntegerHeight()+1; + cspace=space; + is_vram=false; + is_area=false; + areaid=B_ERROR; + + HandleSpace(space, BytesPerLine); + buffer=new uint8[bytesperline*height]; + driver=get_gfxdriver(); +} + +ServerBitmap::ServerBitmap(int32 w,int32 h,color_space space,int32 BytesPerLine=0) +{ + width=w; + height=h; + cspace=space; + is_vram=false; + is_area=false; + areaid=B_ERROR; + + HandleSpace(space, BytesPerLine); + buffer=new uint8[bytesperline*height]; + driver=get_gfxdriver(); +} + +ServerBitmap::ServerBitmap(int32 w,int32 h,color_space space, area_id areaID, int32 BytesPerLine=0) +{ + // This version is used for holding BBitmaps as one of the undocumented BBitmap + // constructors allows - it creates an area on the server's side. + width=w; + height=h; + cspace=space; + is_vram=false; + is_area=true; + + HandleSpace(space, BytesPerLine); + area_info ainfo; + areaid=areaID; + get_area_info(areaid, &ainfo); + buffer=(uint8*)ainfo.address; + driver=get_gfxdriver(); +} + +ServerBitmap::ServerBitmap(void) +{ + // This version is obviously intended for use as an easy-access class for the + // frame buffer. AtheOS does it and it's small, so why not? Worst case, this + // can disappear if not necessary. + is_vram=true; + is_area=false; + areaid=B_ERROR; + UpdateSettings(); +} + +// This particular version is not intended for use except for testing purposes. +// It loads a BBitmap and copies it to the ServerBitmap. Probably will disappear +// when the *real* server is written +ServerBitmap::ServerBitmap(const char *path) +{ + BBitmap *bmp=BTranslationUtils::GetBitmap(path); + assert(bmp!=NULL); + + if(bmp==NULL) + { + width=0; + height=0; + cspace=B_NO_COLOR_SPACE; + bytesperline=0; + } + else + { + width=bmp->Bounds().IntegerWidth(); + height=bmp->Bounds().IntegerHeight(); + cspace=bmp->ColorSpace(); + bytesperline=bmp->BytesPerRow(); + buffer=new uint8[bmp->BitsLength()]; + memcpy(buffer,(void *)bmp->Bits(),bmp->BitsLength()); + } +} + +ServerBitmap::~ServerBitmap(void) +{ + if(!is_vram) + delete buffer; +} + +void ServerBitmap::UpdateSettings(void) +{ + // This is only used when the object is pointing to the frame buffer + driver=get_gfxdriver(); + bpp=driver->GetDepth(); + width=driver->GetWidth(); + height=driver->GetHeight(); +} + +void ServerBitmap::SetBuffer(void *buffer) +{ + buffer=(uint8 *)buffer; +} + +uint8 *ServerBitmap::Buffer(void) +{ + return buffer; +} + +void ServerBitmap::HandleSpace(color_space space, int32 BytesPerLine) +{ + // Function written to handle color space setup which is required + // by the two "normal" constructors + + // Big convoluted mess just to handle every color space and dword align + // the buffer + switch(space) + { + // Buffer is dword-aligned, so nothing need be done + // aside from allocate the memory + case B_RGB32: + case B_RGBA32: + case B_RGB32_BIG: + case B_RGBA32_BIG: + case B_UVL32: + case B_UVLA32: + case B_LAB32: + case B_LABA32: + case B_HSI32: + case B_HSIA32: + case B_HSV32: + case B_HSVA32: + case B_HLS32: + case B_HLSA32: + case B_CMY32: + case B_CMYA32: + case B_CMYK32: + + // 24-bit = 32-bit with extra 8 bits ignored + case B_RGB24_BIG: + case B_RGB24: + case B_LAB24: + case B_UVL24: + case B_HSI24: + case B_HSV24: + case B_HLS24: + case B_CMY24: + { + if(BytesPerLine<(width*4)) + bytesperline=width*4; + else + bytesperline=BytesPerLine; + bpp=32; + break; + } + // Calculate size and dword-align + + // 1-bit + case B_GRAY1: + { + int32 numbytes=width>>3; + if((width % 8) != 0) + numbytes++; + if(BytesPerLine +#include +#include +#include "DisplayDriver.h" + +class ServerBitmap +{ +public: + ServerBitmap(BRect rect,color_space space,int32 BytesPerLine=0); + ServerBitmap(int32 w,int32 h,color_space space,int32 BytesPerLine=0); + ServerBitmap(int32 w,int32 h,color_space space, area_id areaID, int32 BytesPerLine=0); + ServerBitmap(void); + ServerBitmap(const char *path); + ~ServerBitmap(void); + void UpdateSettings(void); + void SetBuffer(void *buffer); + uint8 *Buffer(void); + void SetArea(area_id ID); + area_id Area(void); + + int32 width,height; + int32 bytesperline; + color_space cspace; + int bpp; + +protected: + void HandleSpace(color_space space, int32 BytesPerLine); + DisplayDriver *driver; + bool is_vram,is_area; + area_id areaid; + uint8 *buffer; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto4/ServerCursor.cpp b/src/servers/app/proto4/ServerCursor.cpp new file mode 100644 index 0000000000..7ff11d1ac0 --- /dev/null +++ b/src/servers/app/proto4/ServerCursor.cpp @@ -0,0 +1,124 @@ +/* + ServerCursor.cpp + This is the server-side class used to handle cursors. Note that it + will handle the R5 cursor API, but it will also handle taking a bitmap. + + ServerCursors are 32-bit. Eventually, we will be mapping colors to fit + when the set is called. + + This is new code, and there may be changes to the API before it settles + in. +*/ + +#include "ServerCursor.h" +#include "ServerBitmap.h" +#include +#include + +long pow2(int power) +{ + if(power==0) + return 1; + return long(2 << (power-1)); +} + +ServerCursor::ServerCursor(void) +{ + // For when an application is started. This will probably disappear once I + // get the stuff for default cursors established + is_initialized=false; + position.Set(0,0); +} + +ServerCursor::ServerCursor(ServerBitmap *bmp, ServerBitmap *cmask=NULL) +{ + // The OpenBeOS R1 API uses Bitmaps to create cursors - more flexibility that way. + is_initialized=false; + position.Set(0,0); + SetCursor(bmp); +} + +ServerCursor::ServerCursor(int8 *data) +{ + // For handling the idiot R5 API data format + is_initialized=false; + position.Set(0,0); + SetCursor(data); +} + +ServerCursor::~ServerCursor(void) +{ + if(is_initialized) + delete bitmap; +} + +void ServerCursor::SetCursor(int8 *data) +{ + // 68-byte array used in R5 for holding cursors. + // This API has serious problems and should be deprecated(but supported) + // in a future release, perhaps right after the first one + + if(is_initialized) + { + delete bitmap; + } + cspace=B_RGBA32; + + bitmap=new ServerBitmap(16,16,B_RGBA32); + width=16; + height=16; + bounds.Set(0,0,15,15); + + // Now that we have all the setup, we're going to map (for now) the cursor + // to RGBA32. Eventually, there will be support for 16 and 8-bit depths + uint32 black=0xFF000000, + white=0xFFFFFFFF, + *bmppos; + uint16 *cursorpos, *maskpos,cursorflip, maskflip, + cursorval, maskval; + uint8 i,j; + + cursorpos=(uint16*)(data+4); + maskpos=(uint16*)(data+36); + + // for each row in the cursor data + for(j=0;j<16;j++) + { + bmppos=(uint32*)(bitmap->Buffer()+ (j*bitmap->bytesperline) ); + + // On intel, our bytes end up swapped, so we must swap them back + cursorflip=(cursorpos[j] & 0xFF) << 8; + cursorflip |= (cursorpos[j] & 0xFF00) >> 8; + maskflip=(maskpos[j] & 0xFF) << 8; + maskflip |= (maskpos[j] & 0xFF00) >> 8; + + // for each column in each row of cursor data + for(i=0;i<16;i++) + { + // Get the values and dump them to the bitmap + cursorval=cursorflip & pow2(15-i); + maskval=maskflip & pow2(15-i); + bmppos[i]=((cursorval!=0)?black:white) & ((maskval>0)?0xFFFFFFFF:0x00FFFFFF); + } + } +} + +// Currently unimplemented +void ServerCursor::SetCursor(ServerBitmap *bmp, ServerBitmap *cmask=NULL) +{ +/* if(is_initialized) + delete bitmap; + cspace=bmp->cspace; + + bitmap=new ServerBitmap(bmp->width,bmp->height,cspace); + + width=bmp->width; + height=bmp->height; + bounds.Set(0,0,bmp->width-1,bmp->height-1); +*/ +} + +void ServerCursor::MoveTo(int32 x, int32 y) +{ + position.Set(x,y); +} diff --git a/src/servers/app/proto4/ServerCursor.h b/src/servers/app/proto4/ServerCursor.h new file mode 100644 index 0000000000..c7e7b13972 --- /dev/null +++ b/src/servers/app/proto4/ServerCursor.h @@ -0,0 +1,29 @@ +#ifndef _SERVER_SPRITE_H +#define _SERVER_SPRITE_H + +#include +#include + +class ServerBitmap; + +class ServerCursor +{ +public: + ServerCursor(ServerBitmap *bmp,ServerBitmap *cmask=NULL); + ServerCursor(int8 *data); + ServerCursor(void); + ~ServerCursor(void); + void MoveTo(int32 x, int32 y); + void SetCursor(int8 *data); + void SetCursor(ServerBitmap *bmp, ServerBitmap *cmask=NULL); + + ServerBitmap *bitmap; + + color_space cspace; + BRect bounds; + int width,height; + BPoint position,hotspot; + bool is_initialized; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto4/ServerProtocol.h b/src/servers/app/proto4/ServerProtocol.h new file mode 100644 index 0000000000..ab23ca2d10 --- /dev/null +++ b/src/servers/app/proto4/ServerProtocol.h @@ -0,0 +1,69 @@ +#ifndef _APPSERVER_PROTOCOL_ +#define _APPSERVER_PROTOCOL_ + +#define CREATE_APP 'drca' +#define DELETE_APP 'drda' +#define QUIT_APP 'srqa' + +#define SET_SERVER_PORT 'srsp' + +#define CREATE_WINDOW 'drcw' +#define DELETE_WINDOW 'drdw' +#define QUIT_WINDOW 'srqw' + +#define SERVER_PORT_NAME "OBappserver" +#define SERVER_INPUT_PORT "OBinputport" + +#define SET_CURSOR_DATA 'sscd' +#define SET_CURSOR_BCURSOR 'sscb' +#define SET_CURSOR_BBITMAP 'sscB' +#define SHOW_CURSOR 'srsc' +#define HIDE_CURSOR 'srhc' +#define OBSCURE_CURSOR 'sroc' + +#define GFX_COUNT_WORKSPACES 'gcws' +#define GFX_SET_WORKSPACE_COUNT 'ggwc' +#define GFX_CURRENT_WORKSPACE 'ggcw' +#define GFX_ACTIVATE_WORKSPACE 'gaws' +#define GFX_SYSTEM_COLORS 'gsyc' +#define GFX_SET_SCREEN_MODE 'gssm' +#define GFX_GET_SCROLLBAR_INFO 'ggsi' +#define GFX_SET_SCROLLBAR_INFO 'gssi' +#define GFX_IDLE_TIME 'gidt' +#define GFX_SELECT_PRINTER_PANEL 'gspp' +#define GFX_ADD_PRINTER_PANEL 'gapp' +#define GFX_RUN_BE_ABOUT 'grba' +#define GFX_SET_FOCUS_FOLLOWS_MOUSE 'gsfm' +#define GFX_FOCUS_FOLLOWS_MOUSE 'gffm' + +#define GFX_SET_HIGH_COLOR 'gshc' +#define GFX_SET_LOW_COLOR 'gslc' + +#define GFX_STROKE_ARC 'gsar' +#define GFX_STROKE_BEZIER 'gsbz' +#define GFX_STROKE_ELLIPSE 'gsel' +#define GFX_STROKE_LINE 'gsln' +#define GFX_STROKE_POLYGON 'gspy' +#define GFX_STROKE_RECT 'gsrc' +#define GFX_STROKE_ROUNDRECT 'gsrr' +#define GFX_STROKE_SHAPE 'gssh' +#define GFX_STROKE_TRIANGLE 'gstr' + +#define GFX_FILL_ARC 'gfar' +#define GFX_FILL_BEZIER 'gfbz' +#define GFX_FILL_ELLIPSE 'gfel' +#define GFX_FILL_POLYGON 'gfpy' +#define GFX_FILL_RECT 'gfrc' +#define GFX_FILL_REGION 'gfrg' +#define GFX_FILL_ROUNDRECT 'gfrr' +#define GFX_FILL_SHAPE 'gfsh' +#define GFX_FILL_TRIANGLE 'gftr' + +#define GFX_MOVEPENBY 'gmpb' +#define GFX_MOVEPENTO 'gmpt' +#define GFX_SETPENSIZE 'gsps' + +#define GFX_DRAW_STRING 'gdst' +#define GFX_SET_FONT 'gsft' +#define GFX_SET_FONT_SIZE 'gsfs' +#endif \ No newline at end of file diff --git a/src/servers/app/proto4/ServerSprite.cpp b/src/servers/app/proto4/ServerSprite.cpp new file mode 100644 index 0000000000..915e487dd3 --- /dev/null +++ b/src/servers/app/proto4/ServerSprite.cpp @@ -0,0 +1,29 @@ +#include "ServerCursor.h" +#include "ServerBitmap.h" + +ServerCursor::ServerCursor(ServerBitmap *bmp) +{ +} + +ServerCursor::~ServerCursor(void) +{ +} + +ServerCursor::SetCursor(int8 *data) +{ + // 68-byte array used in R5 for holding cursors. + // This API has serious problems and should be deprecated(but supported) + // in a future release, perhaps the first one(?) +} + +void ServerCursor::SaveClientData(void) +{ +} + +void ServerCursor::MoveTo(int32 x, int32 y) +{ +} + +void ServerCursor::SetClient(ServerBitmap *bmp) +{ +} \ No newline at end of file diff --git a/src/servers/app/proto4/ServerWindow.cpp b/src/servers/app/proto4/ServerWindow.cpp new file mode 100644 index 0000000000..f8921ed8a2 --- /dev/null +++ b/src/servers/app/proto4/ServerWindow.cpp @@ -0,0 +1,210 @@ +#include +#include +#include +#include +#include "PortLink.h" +#include "ServerWindow.h" +#include "ServerApp.h" +#include "ServerProtocol.h" + +ServerWindow::ServerWindow(const char *Title, uint32 Flags, uint32 Desktop, + const BRect &Rect, ServerApp *App, port_id SendPort) +{ + cout << "ServerWindow " << Title << endl; + + if(Title) + { + title=new char[strlen(Title)]; + sprintf((char *)title,Title); + } + else + { + title=new char[strlen("Window")]; + sprintf((char *)title,"Window"); + } + + // sender is the monitored app's event port + sender=SendPort; + winlink=new PortLink(sender); + + if(App!=NULL) + applink=new PortLink(App->receiver); + else + applink=NULL; + + // receiver is the port to which the app sends messages for the server + receiver=create_port(30,title); + + cout << "ServerWin port for window " << title << "is at " << (int32)receiver << endl; + if(receiver==B_NO_MORE_PORTS) + { + // uh-oh. We have a serious problem. Tell the app to quit + if(applink!=NULL) + { + applink->SetOpCode(B_QUIT_REQUESTED); + applink->Flush(); + } + } + else + { + // Everything checks out, so tell the application + // where to send future messages + winlink->SetOpCode(SET_SERVER_PORT); + winlink->Attach(&receiver,sizeof(port_id)); + winlink->Flush(); + } + active=false; + frame.Set(0,0,0,0); + hidecount=0; + + // Spawn our message monitoring thread + thread=spawn_thread(MonitorWin,title,B_NORMAL_PRIORITY,this); + if(thread!=B_NO_MORE_THREADS && thread!=B_NO_MEMORY) + resume_thread(thread); + +} + +ServerWindow::~ServerWindow(void) +{ + if(applink!=NULL) + delete applink; + delete title; + delete winlink; +} + +void ServerWindow::PostMessage(BMessage *msg) +{ +} + +void ServerWindow::ReplaceDecorator(void) +{ +} + +void ServerWindow::Quit(void) +{ +} + +const char *ServerWindow::GetTitle(void) +{ + return title; +} + +ServerApp *ServerWindow::GetApp(void) +{ + return app; +} + +void ServerWindow::Show(void) +{ +} + +void ServerWindow::Hide(void) +{ +} + +bool ServerWindow::IsHidden(void) +{ + return (hidecount==0)?true:false; +} + +void ServerWindow::SetFocus(bool value) +{ + active=value; +} + +bool ServerWindow::HasFocus(void) +{ + return active; +} + +void ServerWindow::DesktopActivated(int32 NewDesktop, const BPoint Resolution, color_space CSpace) +{ +} + +void ServerWindow::WindowActivated(bool Active) +{ +} + +void ServerWindow::ScreenModeChanged(const BPoint Resolustion, color_space CSpace) +{ +} + +void ServerWindow::SetFrame(const BRect &rect) +{ + frame=rect; +} + +BRect ServerWindow::Frame(void) +{ + return frame; +} + +status_t ServerWindow::Lock(void) +{ + return locker.Lock(); +} + +void ServerWindow::Unlock(void) +{ + locker.Unlock(); +} + +bool ServerWindow::IsLocked(void) +{ + return locker.IsLocked(); +} + +void ServerWindow::DispatchMessage(const void *msg, int nCode) +{ +} + +void ServerWindow::Loop(void) +{ + // Message-dispatching loop for the ServerWindow + + cout << "Main message loop for " << title << endl; + + int32 msgcode; + int8 *msgbuffer=NULL; + ssize_t buffersize,bytesread; + + for(;;) + { + buffersize=port_buffer_size(receiver); + + if(buffersize>0) + { + // buffers are PortLink messages. Allocate necessary buffer and + // we'll cast it as a BMessage. + msgbuffer=new int8[buffersize]; + bytesread=read_port(receiver,&msgcode,msgbuffer,buffersize); + } + else + bytesread=read_port(receiver,&msgcode,NULL,0); + + if (bytesread != B_BAD_PORT_ID && bytesread != B_TIMED_OUT && bytesread != B_WOULD_BLOCK) + { + switch(msgcode) + { + default: + cout << "ServerWin received unexpected code " << (int32)msgcode << endl; + break; + } + + } + + if(buffersize>0) + delete msgbuffer; + + if(msgcode==B_QUIT_REQUESTED) + break; + } +} + +int32 ServerWindow::MonitorWin(void *data) +{ + ServerWindow *win=(ServerWindow *)data; + win->Loop(); + exit_thread(0); + return 0; +} diff --git a/src/servers/app/proto4/ServerWindow.h b/src/servers/app/proto4/ServerWindow.h new file mode 100644 index 0000000000..4230b9be91 --- /dev/null +++ b/src/servers/app/proto4/ServerWindow.h @@ -0,0 +1,69 @@ +#ifndef _SERVERWIN_H_ +#define _SERVERWIN_H_ + +#include +#include +#include +#include +#include + +class BString; +class BMessenger; +class BPoint; +class ServerApp; +class WindowDecorator; +class PortLink; + +class ServerWindow +{ +public: + ServerWindow(const char *Title, uint32 Flags, uint32 Desktop, + const BRect &Rect, ServerApp *App, port_id SendPort); + ~ServerWindow(void); + + void PostMessage(BMessage *msg); + void ReplaceDecorator(void); + void Quit(void); + const char *GetTitle(void); + ServerApp *GetApp(void); + void Show(void); + void Hide(void); + bool IsHidden(void); + void SetFocus(bool value); + bool HasFocus(void); + + void DesktopActivated(int32 NewDesktop, const BPoint Resolution, color_space CSpace); + void WindowActivated(bool Active); + void ScreenModeChanged(const BPoint Resolution, color_space CSpace); + + void SetFrame(const BRect &rect); + BRect Frame(void); + + status_t Lock(void); + void Unlock(void); + bool IsLocked(void); + + void DispatchMessage(const void *msg, int nCode); + static int32 MonitorWin(void *data); + void Loop(void); + + const char *title; + int32 flags; + int32 desktop; + bool active; + + ServerApp *app; + + WindowDecorator *decorator; + bigtime_t lasthit; // Time of last mouse click + + thread_id thread; + port_id receiver; // Messages from window + port_id sender; // Messages to window + PortLink *winlink,*applink; + BLocker locker; + BRect frame; + uint8 hidecount; +}; + +#endif diff --git a/src/servers/app/proto4/SystemPalette.cpp b/src/servers/app/proto4/SystemPalette.cpp new file mode 100644 index 0000000000..3a388ed6b4 --- /dev/null +++ b/src/servers/app/proto4/SystemPalette.cpp @@ -0,0 +1,327 @@ +/* + SystemPalette.cpp + One global function to generate the palette which is the default BeOS + System palette and the variable to go with it +*/ + +#include "SystemPalette.h" + +rgb_color SystemPalette[256]; + +void GenerateSystemPalette(rgb_color *palette) +{ + int i,j,index=0; + int indexvals1[]={ 255,229,204,179,154,129,105,80,55,30 }, + indexvals2[]={ 255,203,152,102,51,0 }; + rgb_color *currentcol; + + // Grays 0,0,0 -> 248,248,248 by 8's + for(i=0; i<=248; i+=8,index++) + { + currentcol=&(palette[index]); + currentcol->red=i; + currentcol->green=i; + currentcol->blue=i; + currentcol->alpha=255; + } + + // Blues, following indexvals1 + for(i=0; i<10; i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=0; + currentcol->green=0; + currentcol->blue=indexvals1[i]; + currentcol->alpha=255; + } + + // Reds, following indexvals1 - 1 + for(i=0; i<10; i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=indexvals1[i] - 1; + currentcol->green=0; + currentcol->blue=0; + currentcol->alpha=255; + } + + // Greens, following indexvals1 - 1 + for(i=0; i<10; i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=0; + currentcol->green=indexvals1[i] - 1; + currentcol->blue=0; + currentcol->alpha=255; + } + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=152; + currentcol->blue=51; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=255; + currentcol->blue=255; + index++; + + for(j=1;j<5;j++) + { + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=indexvals2[j]; + currentcol->green=255; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + } + + for(i=0;i<4;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=255; + currentcol->green=152; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=102; + currentcol->blue=51; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=102; + currentcol->blue=0; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=102; + currentcol->blue=255; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=102; + currentcol->blue=203; + index++; + + // Mostly array runs from here on out + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=203; + currentcol->green=203; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=152; + currentcol->green=255; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=102; + currentcol->green=255; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=51; + currentcol->green=255; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=255; + currentcol->green=102; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=102; + currentcol->blue=152; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=102; + currentcol->blue=102; + index++; + + // knocks out 4 assignment loops at once :) + for(j=1;j<5;j++) + { + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=indexvals2[j]; + currentcol->green=152; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + } + + currentcol+=sizeof(rgb_color); + currentcol->red=230; + currentcol->green=134; + currentcol->blue=0; + index++; + + for(i=1;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=255; + currentcol->green=51; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=102; + currentcol->blue=51; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=102; + currentcol->blue=0; + index++; + + for(j=1;j<5;j++) + { + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=indexvals2[j]; + currentcol->green=102; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + } + + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=255; + currentcol->green=0; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=175; + currentcol->blue=19; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=51; + currentcol->blue=255; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=51; + currentcol->blue=203; + index++; + + for(j=1;j<5;j++) + { + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=indexvals2[j]; + currentcol->green=51; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + } + + for(i=3;i>=0;i--,index++) + { + currentcol=&(palette[index]); + currentcol->red=255; + currentcol->green=203; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + for(i=2;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=0; + currentcol->green=51; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + for(i=0;i<5;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=203; + currentcol->green=0; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=227; + currentcol->blue=70; + index++; + + for(j=2;j<6;j++) + { + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=indexvals2[j]; + currentcol->green=0; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + } + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=203; + currentcol->blue=51; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=203; + currentcol->blue=0; + index++; + + for(i=5;i<=0;i--,index++) + { + currentcol=&(palette[index]); + currentcol->red=255; + currentcol->green=255; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + +} diff --git a/src/servers/app/proto4/SystemPalette.h b/src/servers/app/proto4/SystemPalette.h new file mode 100644 index 0000000000..0fb99d0fed --- /dev/null +++ b/src/servers/app/proto4/SystemPalette.h @@ -0,0 +1,9 @@ +#ifndef _SYSTEM_PALETTE_H_ +#define _SYSTEM_PALETTE_H_ + +#include + +void GenerateSystemPalette(rgb_color *palette); +extern rgb_color SystemPalette[]; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto4/ViewDriver.cpp b/src/servers/app/proto4/ViewDriver.cpp new file mode 100644 index 0000000000..3ee50066ac --- /dev/null +++ b/src/servers/app/proto4/ViewDriver.cpp @@ -0,0 +1,1385 @@ +/* + ViewDriver: + First, slowest, and easiest driver class in the app_server which is designed + to utilize the BeOS graphics functions to cut out a lot of junk in getting the + drawing infrastructure in this server. + + The concept is to have VDView::Draw() draw a bitmap, which is a "frame buffer" + of sorts, utilize a second view to write to it. This cuts out + the most problems with having a crapload of code to get just right without + having to write a bunch of unit tests + + Components: 3 classes, VDView, VDWindow, and ViewDriver + + ViewDriver - a wrapper class which mostly posts messages to the VDWindow + VDWindow - does most of the work. + VDView - doesn't do all that much except display the rendered bitmap +*/ + +//#define DEBUG_DRIVER_MODULE + +#include +#include +#include +#include +#include +#include "PortLink.h" +#include "ServerProtocol.h" +#include "ServerBitmap.h" +#include "ViewDriver.h" +#include "ServerCursor.h" +#include "DebugTools.h" + +// Message defines for internal use only +enum +{ +VDWIN_CLEAR=100, +VDWIN_SAFEMODE, +VDWIN_RESET, +VDWIN_SETSCREEN, + +VDWIN_FILLARC, +VDWIN_STROKEARC, +VDWIN_FILLRECT, +VDWIN_STROKERECT, +VDWIN_FILLROUNDRECT, +VDWIN_STROKEROUNDRECT, +VDWIN_FILLELLIPSE, +VDWIN_STROKEELLIPSE, +VDWIN_FILLBEZIER, +VDWIN_STROKEBEZIER, +VDWIN_FILLTRIANGLE, +VDWIN_STROKETRIANGLE, +VDWIN_STROKELINE, +VDWIN_DRAWSTRING, + +VDWIN_SETPENSIZE, +VDWIN_MOVEPENTO, +VDWIN_SHOWCURSOR, +VDWIN_HIDECURSOR, +VDWIN_OBSCURECURSOR, +VDWIN_MOVECURSOR, +VDWIN_SETCURSOR, +VDWIN_SETHIGHCOLOR, +VDWIN_SETLOWCOLOR +}; + +VDView::VDView(BRect bounds) + : BView(bounds,"viewdriver_view",B_FOLLOW_ALL, B_WILL_DRAW) +{ + viewbmp=new BBitmap(bounds,B_RGB32,true); + drawview=new BView(viewbmp->Bounds(),"drawview",B_FOLLOW_ALL, B_WILL_DRAW); + + // This link for sending mouse messages to the OBAppServer. + // This is only to take the place of the Input Server. I suppose I could write + // an addon filter to be more like the Input Server, but then I wouldn't be working + // on this thing! :P + serverlink=new PortLink(find_port(SERVER_INPUT_PORT)); + +#ifdef DEBUG_DRIVER_MODULE + printf("VDView: app_server input port: %ld\n",serverlink->GetPort()); +#endif + + hide_cursor=0; + obscure_cursor=false; + + // Create a cursor which isn't just a box + cursor=new BBitmap(BRect(0,0,20,20),B_RGBA32,true); + BView *v=new BView(cursor->Bounds(),"v", B_FOLLOW_NONE, B_WILL_DRAW); + + cursor->Lock(); + cursor->AddChild(v); + + v->SetHighColor(255,255,255,0); + v->FillRect(cursor->Bounds()); + v->SetHighColor(255,0,0,255); + v->FillTriangle(cursor->Bounds().LeftTop(),cursor->Bounds().RightTop(),cursor->Bounds().LeftBottom()); + + cursor->RemoveChild(v); + cursor->Unlock(); + + cursorframe=cursor->Bounds(); + oldcursorframe=cursor->Bounds(); +} + +VDView::~VDView(void) +{ + delete viewbmp; + delete serverlink; + delete cursor; +} + +void VDView::AttachedToWindow(void) +{ +// printf("VDView::AttachedToWindow()\n"); +} + +void VDView::Draw(BRect rect) +{ + DrawBitmapAsync(viewbmp,oldcursorframe,oldcursorframe); + DrawBitmapAsync(viewbmp,rect,rect); + + if(hide_cursor==0 && obscure_cursor==false) + { + SetDrawingMode(B_OP_ALPHA); + DrawBitmapAsync(cursor,cursor->Bounds(),cursorframe); + SetDrawingMode(B_OP_COPY); + } + Sync(); +} + +// These functions emulate the Input Server by sending the *exact* same kind of messages +// to the server's port. Being we're using a regular window, it would make little sense +// to do anything else. + +void VDView::MouseDown(BPoint pt) +{ + // Attach data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - modifier keys down + // 5) int32 - buttons down + // 6) int32 - clicks + + BPoint p; + + uint32 buttons, + mod=modifiers(), + clicks=1; // can't get the # of clicks without a *lot* of extra work :( + + int64 time=(int64)real_time_clock(); + + GetMouse(&p,&buttons); + + serverlink->SetOpCode(B_MOUSE_DOWN); + serverlink->Attach(&time, sizeof(int64)); + serverlink->Attach(&pt.x,sizeof(float)); + serverlink->Attach(&pt.y,sizeof(float)); + serverlink->Attach(&mod, sizeof(uint32)); + serverlink->Attach(&buttons, sizeof(uint32)); + serverlink->Attach(&clicks, sizeof(uint32)); + serverlink->Flush(); +} + +void VDView::MouseMoved(BPoint pt, uint32 transit, const BMessage *msg) +{ + // Attach data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - buttons down + BPoint p; + uint32 buttons; + int64 time=(int64)real_time_clock(); + + serverlink->SetOpCode(B_MOUSE_MOVED); + serverlink->Attach(&time,sizeof(int64)); + serverlink->Attach(&pt.x,sizeof(float)); + serverlink->Attach(&pt.y,sizeof(float)); + GetMouse(&p,&buttons); + serverlink->Attach(&buttons,sizeof(int32)); + serverlink->Flush(); +} + +void VDView::MouseUp(BPoint pt) +{ + // Attach data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - modifier keys down + BPoint p; + + uint32 buttons, + mod=modifiers(); + + int64 time=(int64)real_time_clock(); + + GetMouse(&p,&buttons); + + serverlink->SetOpCode(B_MOUSE_UP); + serverlink->Attach(&time, sizeof(int64)); + serverlink->Attach(&pt.x,sizeof(float)); + serverlink->Attach(&pt.y,sizeof(float)); + serverlink->Attach(&mod, sizeof(uint32)); + serverlink->Flush(); +} + +void VDView::SetMode(int16 width, int16 height, uint8 bpp) +{ + // This function resets the emulated video buffer + color_space s; + + switch(bpp) + { + case 16: + s=B_RGBA15; + break; + case 8: + s=B_CMAP8; + break; + default: + s=B_RGBA32; + break; + } + delete viewbmp; + viewbmp=new BBitmap(BRect(0,0,width-1,height-1),s,true); + drawview->ResizeTo(width-1,height-1); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver::SetMode(%d x %d x %d)\n",width,height,bpp); +#endif +} + +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- + +VDWindow::VDWindow(void) + : BWindow(BRect(100,60,740,540),"OBOS App Server, P4",B_TITLED_WINDOW, + B_NOT_ZOOMABLE | B_NOT_RESIZABLE) +{ + view=new VDView(Bounds()); + AddChild(view); +} + +VDWindow::~VDWindow(void) +{ +} + +void VDWindow::MessageReceived(BMessage *msg) +{ + switch(msg->what) + { + case VDWIN_CLEAR: + { + int8 red=0,green=0,blue=0; + msg->FindInt8("red",&red); + msg->FindInt8("green",&green); + msg->FindInt8("blue",&blue); + Clear(red,green,blue); + break; + } + case VDWIN_SETSCREEN: + { + // debug printing done in SetScreen() + int32 space=0; + msg->FindInt32("screenmode",&space); + SetScreen(space); + break; + } + case VDWIN_RESET: + { + Reset(); + break; + } + case VDWIN_SAFEMODE: + { + SafeMode(); + break; + } + case VDWIN_DRAWSTRING: + { + char *string; + BPoint point; + uint16 length; + msg->FindString("string",(const char **)&string); + msg->FindInt16("length",(int16*)&length); + msg->FindPoint("point",&point); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->SetDrawingMode(B_OP_ALPHA); + view->drawview->DrawString(string,length,point); + view->drawview->SetDrawingMode(B_OP_COPY); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + + // Until I can figure out a better way, if I even bother... + view->Invalidate(); + } + case VDWIN_FILLARC: + { + float cx,cy,rx,ry,angle,span; + int64 temp64; + + msg->FindFloat("cx",&cx); + msg->FindFloat("cy",&cy); + msg->FindFloat("rx",&rx); + msg->FindFloat("ry",&ry); + msg->FindFloat("angle",&angle); + msg->FindFloat("span",&span); + msg->FindInt64("pattern",&temp64); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->FillArc(BPoint(cx,cy),rx,ry,angle,span,*((pattern *)&temp64)); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + view->Invalidate(BRect(cx-rx,cy-ry,cx+rx,cy+ry)); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver::FillArc: "); +printf("Center: %f,%f\n",cx,cy); +printf("Radii: %f,%f\n",rx,ry); +printf("Angle, Span: %f,%f\n",angle, span); +printf("pattern: {%llx}\n",temp64); +#endif + break; + } + case VDWIN_STROKEARC: + { + float cx,cy,rx,ry,angle,span; + int64 temp64; + + msg->FindFloat("cx",&cx); + msg->FindFloat("cy",&cy); + msg->FindFloat("rx",&rx); + msg->FindFloat("ry",&ry); + msg->FindFloat("angle",&angle); + msg->FindFloat("span",&span); + msg->FindInt64("pattern",&temp64); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->StrokeArc(BPoint(cx,cy),rx,ry,angle,span,*((pattern *)&temp64)); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + view->Invalidate(BRect(cx-rx,cy-ry,cx+rx,cy+ry)); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: StrokeArc: "); +printf("Center: %f,%f\n",cx,cy); +printf("Radii: %f,%f\n",rx,ry); +printf("Angle, Span: %f,%f\n",angle, span); +printf("pattern: {%llx}\n",temp64); +#endif + break; + } + case VDWIN_FILLBEZIER: + { + BPoint points[4]; + int64 temp64; + msg->FindPoint("p1",points); + msg->FindPoint("p2",&(points[1])); + msg->FindPoint("p3",&(points[2])); + msg->FindPoint("p4",&(points[3])); + msg->FindInt64("pattern",&temp64); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->FillBezier(points,*((pattern *)&temp64)); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + + // Invalidate the whole view until I can figure out how to calculate + // a rect which encompasses the line + view->Invalidate(); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: FillBezier:\n"); +printf("Point 1: "); points[0].PrintToStream(); +printf("Point 2: "); points[1].PrintToStream(); +printf("Point 3: "); points[2].PrintToStream(); +printf("Point 4: "); points[3].PrintToStream(); +printf("pattern: {%llx}\n",temp64); +#endif + break; + } + case VDWIN_STROKEBEZIER: + { + BPoint points[4]; + int64 temp64; + msg->FindPoint("p1",points); + msg->FindPoint("p2",&(points[1])); + msg->FindPoint("p3",&(points[2])); + msg->FindPoint("p4",&(points[3])); + msg->FindInt64("pattern",&temp64); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->StrokeBezier(points,*((pattern *)&temp64)); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + + // Invalidate the whole view until I can figure out how to calculate + // a rect which encompasses the line + view->Invalidate(); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: StrokeBezier:\n"); +printf("Point 1: "); points[0].PrintToStream(); +printf("Point 2: "); points[1].PrintToStream(); +printf("Point 3: "); points[2].PrintToStream(); +printf("Point 4: "); points[3].PrintToStream(); +printf("pattern: {%llx}\n",temp64); +#endif + break; + } + case VDWIN_FILLRECT: + { + BRect rect(0,0,0,0); + int64 temp64; + + msg->FindRect("rect",&rect); + msg->FindInt64("pattern",&temp64); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->FillRect(rect,*((pattern *)&temp64)); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + view->Invalidate(rect); +#ifdef DEBUG_DRIVER_MODULE +printf("FillRect: "); rect.PrintToStream(); +printf("pattern: {%llxd}\n",temp64); +#endif + break; + } + case VDWIN_STROKERECT: + { + BRect rect(0,0,0,0); + int64 temp64; + + msg->FindRect("rect",&rect); + msg->FindInt64("pattern",&temp64); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->StrokeRect(rect,*((pattern *)&temp64)); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + view->Invalidate(rect); +#ifdef DEBUG_DRIVER_MODULE +printf("StrokeRect: "); rect.PrintToStream(); +printf("pattern: {%llx}\n",temp64); +#endif + break; + } + case VDWIN_FILLELLIPSE: + { + float cx,cy,rx,ry; + int64 temp64; + + msg->FindFloat("cx",&cx); + msg->FindFloat("cy",&cy); + msg->FindFloat("rx",&rx); + msg->FindFloat("ry",&ry); + msg->FindInt64("pattern",&temp64); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->FillEllipse(BPoint(cx,cy),rx,ry,*((pattern *)&temp64)); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + view->Invalidate(BRect(cx-rx,cy-ry,cx+rx,cy+ry)); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: FillEllipse: "); +printf("Center: %f,%f\n",cx,cy); +printf("Radii: %f,%f\n",rx,ry); +printf("pattern: {%llx}\n",temp64); +#endif + break; + } + case VDWIN_STROKEELLIPSE: + { + float cx,cy,rx,ry; + int64 temp64; + + msg->FindFloat("cx",&cx); + msg->FindFloat("cy",&cy); + msg->FindFloat("rx",&rx); + msg->FindFloat("ry",&ry); + msg->FindInt64("pattern",&temp64); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->StrokeEllipse(BPoint(cx,cy),rx,ry,*((pattern *)&temp64)); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + view->Invalidate(BRect(cx-rx,cy-ry,cx+rx,cy+ry)); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: StrokeEllipse: "); +printf("Center: %f,%f\n",cx,cy); +printf("Radii: %f,%f\n",rx,ry); +printf("pattern: {%llx}\n",temp64); +#endif + break; + } + case VDWIN_FILLROUNDRECT: + { + BRect rect(0,0,0,0); + int64 temp64; + float x,y; + + msg->FindRect("rect",&rect); + msg->FindFloat("x",&x); + msg->FindFloat("y",&y); + msg->FindInt64("pattern",&temp64); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->FillRoundRect(rect,x,y,*((pattern *)&temp64)); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + view->Invalidate(rect); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: FillRoundRect: "); rect.PrintToStream(); +printf("Radii: %f,%f\n",x,y); +printf("pattern: {%llx}\n",temp64); +#endif + break; + } + case VDWIN_STROKEROUNDRECT: + { + BRect rect(0,0,0,0); + int64 temp64; + float x,y; + + msg->FindRect("rect",&rect); + msg->FindFloat("x",&x); + msg->FindFloat("y",&y); + msg->FindInt64("pattern",&temp64); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->StrokeRoundRect(rect,x,y,*((pattern *)&temp64)); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + view->Invalidate(rect); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: StrokeRoundRect: "); rect.PrintToStream(); +printf("Radii: %f,%f\n",x,y); +printf("pattern: {%llx}\n",temp64); +#endif + break; + } + case VDWIN_FILLTRIANGLE: + { + BPoint pt1,pt2,pt3; + BRect invalid; + int64 temp64; + msg->FindPoint("first",&pt1); + msg->FindPoint("second",&pt2); + msg->FindPoint("third",&pt3); + msg->FindRect("rect",&invalid); + msg->FindInt64("pattern",&temp64); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->FillTriangle(pt1,pt2,pt3,*((pattern *)&temp64)); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + + view->Invalidate(invalid); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: FillTriangle:\n"); +printf("Point 1: "); pt1.PrintToStream(); +printf("Point 2: "); pt2.PrintToStream(); +printf("Point 3: "); pt3.PrintToStream(); +printf("Rect: "); invalid.PrintToStream(); +printf("pattern: {%llx}\n",temp64); +#endif + break; + } + case VDWIN_STROKETRIANGLE: + { + BPoint pt1,pt2,pt3; + BRect invalid; + int64 temp64; + msg->FindPoint("first",&pt1); + msg->FindPoint("second",&pt2); + msg->FindPoint("third",&pt3); + msg->FindRect("rect",&invalid); + msg->FindInt64("pattern",&temp64); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->StrokeTriangle(pt1,pt2,pt3,*((pattern *)&temp64)); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + + view->Invalidate(invalid); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: StrokeTriangle:\n"); +printf("Point 1: "); pt1.PrintToStream(); +printf("Point 2: "); pt2.PrintToStream(); +printf("Point 3: "); pt3.PrintToStream(); +printf("Rect: "); invalid.PrintToStream(); +printf("pattern: {%llx}\n",temp64); +#endif + break; + } + case VDWIN_STROKELINE: + { + BPoint pt(0,0),pt2(0,0); + int64 temp64; + + msg->FindPoint("from",&pt); + msg->FindPoint("to",&pt2); + msg->FindInt64("pattern",&temp64); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->StrokeLine(pt,pt2,*((pattern *)&temp64)); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + + // Because BRect requires (pt1,pt2) where pt1=LeftTop(), + // we have to jump through some hoops + + BRect invalid(MIN(pt2.x,pt.x), MIN(pt2.y,pt.y), + MAX(pt2.x,pt.x), MAX(pt2.y,pt.y) ); + invalid.InsetBy((view->drawview->PenSize()/2)*-1,(view->drawview->PenSize()/2)*-1); + view->Invalidate(invalid); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: StrokeLine(%f,%f)\n",pt.x,pt.y); +printf("pattern: {%llx}\n",temp64); +#endif + break; + } + case VDWIN_SHOWCURSOR: + { + if(view->hide_cursor>0) + { + view->hide_cursor--; +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: ShowCursor() - still hidden\n"); +#endif + } + if(view->hide_cursor==0) + { +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: ShowCursor() - cursor shown\n"); +#endif + view->Invalidate(view->cursorframe); + } + break; + } + case VDWIN_HIDECURSOR: + { + view->hide_cursor++; +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: HideCursor()\n"); +#endif + if(view->hide_cursor==1) + { +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: HideCursor() - cursor was hidden\n"); +#endif + view->Invalidate(view->cursorframe); + } + break; + } + case VDWIN_OBSCURECURSOR: + { +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: ObscureCursor()\n"); +#endif + view->obscure_cursor=true; + view->Invalidate(view->cursorframe); + break; + } + case VDWIN_MOVECURSOR: + { + float x,y; + msg->FindFloat("x",&x); + msg->FindFloat("y",&y); + + // this was changed because an extra message was + // sent even though the mouse was never moved + if(view->cursorframe.left!=x || view->cursorframe.top!=y) + { + if(view->obscure_cursor) + view->obscure_cursor=false; + + view->oldcursorframe=view->cursorframe; + view->cursorframe.OffsetTo(x,y); + } + + if(view->hide_cursor==0) + view->Invalidate(view->oldcursorframe); + break; + } + case VDWIN_SETCURSOR: + { +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: SetCursor()\n"); +#endif + ServerCursor *cdata; + msg->FindPointer("SCursor",(void**)&cdata); + + if(cdata!=NULL) + { + BBitmap *bmp=new BBitmap(BRect(0,0,cdata->width-1,cdata->height-1), + cdata->cspace); + + // Copy the server bitmap in the cursor to a BBitmap + uint8 *sbmppos=(uint8*)cdata->bitmap->Buffer(), + *bbmppos=(uint8*)bmp->Bits(); + + int32 bytes=cdata->bitmap->bytesperline, + bbytes=bmp->BytesPerRow(); + + for(int i=0;iheight;i++) + memcpy(bbmppos+(i*bbytes), sbmppos+(i*bytes), bytes); + + // Replace the bitmap + delete view->cursor; + view->cursor=bmp; + view->Invalidate(view->cursorframe); + break; + } + break; + } + case VDWIN_SETHIGHCOLOR: + { + uint8 r=0,g=0,b=0,a=0; + msg->FindInt8("red",(int8*)&r); + msg->FindInt8("green",(int8*)&g); + msg->FindInt8("blue",(int8*)&b); + msg->FindInt8("alpha",(int8*)&a); + view->drawview->SetHighColor(r,g,b,a); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: SetHighColor(%d,%d,%d,%d)\n",r,g,b,a); +#endif + break; + } + case VDWIN_SETLOWCOLOR: + { + uint8 r=0,g=0,b=0,a=0; + msg->FindInt8("red",(int8*)&r); + msg->FindInt8("green",(int8*)&g); + msg->FindInt8("blue",(int8*)&b); + msg->FindInt8("alpha",(int8*)&a); + view->drawview->SetLowColor(r,g,b,a); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: SetLowColor(%d,%d,%d,%d)\n",r,g,b,a); +#endif + break; + } + case VDWIN_SETPENSIZE: + { + float pensize; + msg->FindFloat("size",&pensize); + view->drawview->SetPenSize(pensize); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: SetPenSize(%f)\n",pensize); +#endif + break; + } + case VDWIN_MOVEPENTO: + { + BPoint pt; + msg->FindPoint("point",&pt); + view->drawview->MovePenTo(pt); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: MovePenTo(%f,%f)\n",pt.x,pt.y); +#endif + break; + } + default: + BWindow::MessageReceived(msg); + break; + } +} + +void VDWindow::SafeMode(void) +{ + SetScreen(B_8_BIT_640x480); +} + +void VDWindow::Reset(void) +{ + SafeMode(); + Clear(255,255,255); +} + +void VDWindow::SetScreen(uint32 space) +{ + int16 w=640,h=480; + uint8 bpp=0; + switch(space) + { + case B_32_BIT_800x600: + case B_16_BIT_800x600: + case B_8_BIT_800x600: + { + w=800; h=600; + break; + } + case B_32_BIT_1024x768: + case B_16_BIT_1024x768: + case B_8_BIT_1024x768: + { + w=1024; h=768; + break; + } + default: + break; + } + ResizeTo(w-1,h-1); + + switch(space) + { + case B_32_BIT_640x480: + case B_32_BIT_800x600: + case B_32_BIT_1024x768: + bpp=32; + break; + case B_16_BIT_640x480: + case B_16_BIT_800x600: + case B_16_BIT_1024x768: + bpp=16; + break; + case B_8_BIT_640x480: + case B_8_BIT_800x600: + case B_8_BIT_1024x768: + bpp=8; + break; + default: + break; + } + view->SetMode(w,h,bpp); +} + +void VDWindow::Clear(uint8 red,uint8 green,uint8 blue) +{ +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: Clear(%d,%d,%d)\n",red,green,blue); +#endif + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->SetHighColor(red,green,blue); + view->drawview->FillRect(view->drawview->Bounds()); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + view->Invalidate(); +} + +bool VDWindow::QuitRequested(void) +{ + port_id serverport=find_port(SERVER_PORT_NAME); + if(serverport!=B_NAME_NOT_FOUND) + { + write_port(serverport,B_QUIT_REQUESTED,NULL,0); + } + return true; +} + +void VDWindow::WindowActivated(bool active) +{ + // This is just to hide the regular system cursor so we can see our own + if(active) + be_app->HideCursor(); + else + be_app->ShowCursor(); +} + +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- + +/* + Posting messages to the rendering window helps run right around a whole + migraine's worth of multithreaded code +*/ + +ViewDriver::ViewDriver(void) +{ + screenwin=new VDWindow(); + hide_cursor=0; +} + +ViewDriver::~ViewDriver(void) +{ + if(is_initialized) + { + screenwin->Lock(); + screenwin->Quit(); + } +} + +void ViewDriver::Initialize(void) +{ + locker->Lock(); + screenwin->Show(); + is_initialized=true; + SetPenSize(1.0); + MovePenTo(BPoint(0,0)); + locker->Unlock(); +} + +void ViewDriver::Shutdown(void) +{ + locker->Lock(); + screenwin->Lock(); + screenwin->Close(); + is_initialized=false; + locker->Unlock(); +} + +bool ViewDriver::IsInitialized(void) +{ + return is_initialized; +} + +void ViewDriver::SafeMode(void) +{ + locker->Lock(); + screenwin->PostMessage(VDWIN_SAFEMODE); + locker->Unlock(); +} + +void ViewDriver::Reset(void) +{ + locker->Lock(); + screenwin->PostMessage(VDWIN_RESET); + locker->Unlock(); +} + +void ViewDriver::SetScreen(uint32 space) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_SETSCREEN); + msg->AddInt32("screenmode",space); + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::Clear(uint8 red, uint8 green, uint8 blue) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_CLEAR); + msg->AddInt8("red",red); + msg->AddInt8("green",green); + msg->AddInt8("blue",blue); + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::Clear(rgb_color col) +{ + Clear(col.red,col.green,col.blue); +} + +int32 ViewDriver::GetHeight(void) +{ // Gets the height of the current mode + return 0; +} + +int32 ViewDriver::GetWidth(void) +{ // Gets the width of the current mode + return 0; +} + +int ViewDriver::GetDepth(void) +{ // Gets the color depth of the current mode + return 0; +} + +void ViewDriver::Blit(BPoint dest, ServerBitmap *sourcebmp, ServerBitmap *destbmp) +{ +} + +void ViewDriver::DrawBitmap(ServerBitmap *bitmap) +{ +} + +void ViewDriver::DrawChar(char c, BPoint point) +{ + char string[2]; + string[0]=c; + string[1]='\0'; + DrawString(string,2,point); +} + +void ViewDriver::DrawString(char *string, int length, BPoint point) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_DRAWSTRING); + msg->AddString("string",string); + msg->AddInt16("length",length); + msg->AddPoint("point",point); + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::FillArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_FILLARC); + msg->AddFloat("cx",centerx); + msg->AddFloat("cy",centery); + msg->AddFloat("rx",xradius); + msg->AddFloat("ry",yradius); + msg->AddFloat("angle",angle); + msg->AddFloat("span",span); + + // Have to actually copy the pattern data because a sort of race condition + // Using an int64 to make for an easy copy. + int64 pat=*((int64*)pattern); + msg->AddInt64("pattern",pat); + + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::FillBezier(BPoint *points, uint8 *pattern) +{ + locker->Lock(); + int64 pat=*((int64*)pattern); + + BMessage *msg=new BMessage(VDWIN_FILLBEZIER); + msg->AddPoint("p1",points[0]); + msg->AddPoint("p2",points[1]); + msg->AddPoint("p3",points[2]); + msg->AddPoint("p4",points[3]); + msg->AddInt64("pattern",pat); + + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::FillEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_FILLELLIPSE); + msg->AddFloat("cx",centerx); + msg->AddFloat("cy",centery); + msg->AddFloat("rx",x_radius); + msg->AddFloat("ry",y_radius); + + // Have to actually copy the pattern data because a sort of race condition + // Using an int64 to make for an easy copy. + int64 pat=*((int64*)pattern); + msg->AddInt64("pattern",pat); + + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::FillPolygon(int *x, int *y, int numpoints, bool is_closed) +{ +} + +void ViewDriver::FillRect(BRect rect, uint8 *pattern) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_FILLRECT); + msg->AddRect("rect",rect); + + // Have to actually copy the pattern data because a sort of race condition + // Using an int64 to make for an easy copy. + int64 pat=*((int64*)pattern); + msg->AddInt64("pattern",pat); + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::FillRegion(BRegion *region) +{ +} + +void ViewDriver::FillRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_FILLROUNDRECT); + msg->AddRect("rect",rect); + msg->AddFloat("x",xradius); + msg->AddFloat("y",yradius); + + // Have to actually copy the pattern data because a sort of race condition + // Using an int64 to make for an easy copy. + int64 pat=*((int64*)pattern); + msg->AddInt64("pattern",pat); + + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::FillShape(BShape *shape) +{ +} + +void ViewDriver::FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_FILLTRIANGLE); + msg->AddPoint("first",first); + msg->AddPoint("second",second); + msg->AddPoint("third",third); + msg->AddRect("rect",rect); + + // Have to actually copy the pattern data because a sort of race condition + // Using an int64 to make for an easy copy. + int64 pat=*((int64*)pattern); + msg->AddInt64("pattern",pat); + + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::HideCursor(void) +{ + locker->Lock(); + hide_cursor++; + screenwin->PostMessage(VDWIN_HIDECURSOR); + locker->Unlock(); +} + +bool ViewDriver::IsCursorHidden(void) +{ + locker->Lock(); + bool value=(hide_cursor>0)?true:false; + locker->Unlock(); + return value; +} + +void ViewDriver::ObscureCursor(void) +{ // Hides cursor until mouse is moved + locker->Lock(); + screenwin->PostMessage(VDWIN_OBSCURECURSOR); + locker->Unlock(); +} + +void ViewDriver::MoveCursorTo(float x, float y) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_MOVECURSOR); + msg->AddFloat("x",x); + msg->AddFloat("y",y); + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::MovePenTo(BPoint pt) +{ // Moves the graphics pen to this position + + locker->Lock(); + penpos=pt; + + BMessage *msg=new BMessage(VDWIN_MOVEPENTO); + msg->AddPoint("point",penpos); + screenwin->PostMessage(msg); + locker->Unlock(); +} + +BPoint ViewDriver::PenPosition(void) +{ + return penpos; +} + +float ViewDriver::PenSize(void) +{ + return pensize; +} + +void ViewDriver::SetCursor(int32 value) +{ +} + +void ViewDriver::SetCursor(ServerCursor *cursor) +{ + // We are given a ServerCursor. Fire it off to the view driver's window for translation + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_SETCURSOR); + msg->AddPointer("SCursor",cursor); + screenwin->PostMessage(msg); // Much faster than copying data. :) + locker->Unlock(); +} + +void ViewDriver::SetPenSize(float size) +{ + locker->Lock(); + pensize=size; + + BMessage *msg=new BMessage(VDWIN_SETPENSIZE); + msg->AddFloat("size",pensize); + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::SetHighColor(uint8 r,uint8 g,uint8 b,uint8 a=255) +{ + locker->Lock(); + highcol.red=r; + highcol.green=g; + highcol.blue=b; + highcol.alpha=a; + + BMessage *msg=new BMessage(VDWIN_SETHIGHCOLOR); + msg->AddInt8("red",r); + msg->AddInt8("green",g); + msg->AddInt8("blue",b); + msg->AddInt8("alpha",a); + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::SetLowColor(uint8 r,uint8 g,uint8 b,uint8 a=255) +{ + locker->Lock(); + lowcol.red=r; + lowcol.green=g; + lowcol.blue=b; + lowcol.alpha=a; + + BMessage *msg=new BMessage(VDWIN_SETLOWCOLOR); + msg->AddInt8("red",r); + msg->AddInt8("green",g); + msg->AddInt8("blue",b); + msg->AddInt8("alpha",a); + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::SetPixel(int x, int y, uint8 *pattern) +{ // Internal function utilized by other functions to draw to the buffer + // Will eventually be an inline function +} + +void ViewDriver::ShowCursor(void) +{ + locker->Lock(); + if(hide_cursor>0) + { + hide_cursor--; + screenwin->PostMessage(VDWIN_SHOWCURSOR); + } + locker->Unlock(); +} + +void ViewDriver::StrokeArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_STROKEARC); + msg->AddFloat("cx",centerx); + msg->AddFloat("cy",centery); + msg->AddFloat("rx",xradius); + msg->AddFloat("ry",yradius); + msg->AddFloat("angle",angle); + msg->AddFloat("span",span); + + // Have to actually copy the pattern data because a sort of race condition + // Using an int64 to make for an easy copy. + int64 pat=*((int64*)pattern); + msg->AddInt64("pattern",pat); + + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::StrokeBezier(BPoint *points, uint8 *pattern) +{ + locker->Lock(); + int64 pat=*((int64*)pattern); + + BMessage *msg=new BMessage(VDWIN_STROKEBEZIER); + msg->AddPoint("p1",points[0]); + msg->AddPoint("p2",points[1]); + msg->AddPoint("p3",points[2]); + msg->AddPoint("p4",points[3]); + msg->AddInt64("pattern",pat); + + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::StrokeEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_STROKEELLIPSE); + msg->AddFloat("cx",centerx); + msg->AddFloat("cy",centery); + msg->AddFloat("rx",x_radius); + msg->AddFloat("ry",y_radius); + + // Have to actually copy the pattern data because a sort of race condition + // Using an int64 to make for an easy copy. + int64 pat=*((int64*)pattern); + msg->AddInt64("pattern",pat); + + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::StrokeLine(BPoint point, uint8 *pattern) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_STROKELINE); + msg->AddPoint("from",penpos); + msg->AddPoint("to",point); + + // Have to actually copy the pattern data because a sort of race condition + // Using an int64 to make for an easy copy. + int64 pat=*((int64*)pattern); + msg->AddInt64("pattern",pat); + + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::StrokePolygon(int *x, int *y, int numpoints, bool is_closed) +{ +} + +void ViewDriver::StrokeRect(BRect rect,uint8 *pattern) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_STROKERECT); + msg->AddRect("rect",rect); + + // Have to actually copy the pattern data because a sort of race condition + // Using an int64 to make for an easy copy. + int64 pat=*((int64*)pattern); + msg->AddInt64("pattern",pat); + + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::StrokeRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_STROKEROUNDRECT); + msg->AddRect("rect",rect); + msg->AddFloat("x",xradius); + msg->AddFloat("y",yradius); + + // Have to actually copy the pattern data because a sort of race condition + // Using an int64 to make for an easy copy. + int64 pat=*((int64*)pattern); + msg->AddInt64("pattern",pat); + + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::StrokeShape(BShape *shape) +{ +} + +void ViewDriver::StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_STROKETRIANGLE); + msg->AddPoint("first",first); + msg->AddPoint("second",second); + msg->AddPoint("third",third); + msg->AddRect("rect",rect); + + // Have to actually copy the pattern data because a sort of race condition + // Using an int64 to make for an easy copy. + int64 pat=*((int64*)pattern); + msg->AddInt64("pattern",pat); + + screenwin->PostMessage(msg); + locker->Unlock(); +} + +#ifdef DEBUG_DRIVER_MODULE +#undef DEBUG_DRIVER_MODULE +#endif \ No newline at end of file diff --git a/src/servers/app/proto4/ViewDriver.h b/src/servers/app/proto4/ViewDriver.h new file mode 100644 index 0000000000..24358b2dac --- /dev/null +++ b/src/servers/app/proto4/ViewDriver.h @@ -0,0 +1,127 @@ +#ifndef _VIEWDRIVER_H_ +#define _VIEWDRIVER_H_ + +#include +#include +#include +#include +#include // for pattern struct +#include +#include +#include "DisplayDriver.h" + +class BBitmap; +class PortLink; +class VDWindow; +class ServerCursor; + +class VDView : public BView +{ +public: + VDView(BRect bounds); + ~VDView(void); + void AttachedToWindow(void); + void Draw(BRect rect); + void MouseDown(BPoint pt); + void MouseMoved(BPoint pt, uint32 transit, const BMessage *msg); + void MouseUp(BPoint pt); + void SetMode(int16 width, int16 height, uint8 bpp); + + BBitmap *viewbmp; + BView *drawview; + PortLink *serverlink; + +protected: + friend VDWindow; + + int hide_cursor; + BBitmap *cursor; + + BRect cursorframe, oldcursorframe; + bool obscure_cursor; +}; + +class VDWindow : public BWindow +{ +public: + VDWindow(void); + ~VDWindow(void); + void MessageReceived(BMessage *msg); + bool QuitRequested(void); + void WindowActivated(bool active); + + void SafeMode(void); + void Reset(void); + void SetScreen(uint32 space); + void Clear(uint8 red,uint8 green,uint8 blue); + + VDView *view; +}; + +class ViewDriver : public DisplayDriver +{ +public: + ViewDriver(void); + virtual ~ViewDriver(void); + + virtual void Initialize(void); // Sets the driver + virtual bool IsInitialized(void); + virtual void Shutdown(void); // You never know when you'll need this + + virtual void SafeMode(void); // Easy-access functions for common tasks + virtual void Reset(void); + virtual void Clear(uint8 red,uint8 green,uint8 blue); + virtual void Clear(rgb_color col); + + // Settings functions + virtual void SetScreen(uint32 space); + virtual int32 GetHeight(void); + virtual int32 GetWidth(void); + virtual int GetDepth(void); + + // Drawing functions + virtual void Blit(BPoint dest, ServerBitmap *src, ServerBitmap *dest); + virtual void DrawBitmap(ServerBitmap *bitmap); + virtual void DrawChar(char c, BPoint point); + virtual void DrawString(char *string, int length, BPoint point); + + virtual void FillArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern); + virtual void FillBezier(BPoint *points, uint8 *pattern); + virtual void FillEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern); + virtual void FillPolygon(int *x, int *y, int numpoints, bool is_closed); + virtual void FillRect(BRect rect, uint8 *pattern); + virtual void FillRegion(BRegion *region); + virtual void FillRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern); + virtual void FillShape(BShape *shape); + virtual void FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern); + + virtual void HideCursor(void); + virtual bool IsCursorHidden(void); + virtual void MoveCursorTo(float x, float y); + virtual void MovePenTo(BPoint pt); + virtual void ObscureCursor(void); + virtual BPoint PenPosition(void); + virtual float PenSize(void); + virtual void SetCursor(int32 value); + virtual void SetCursor(ServerCursor *cursor); + virtual void SetHighColor(uint8 r,uint8 g,uint8 b,uint8 a=255); + virtual void SetLowColor(uint8 r,uint8 g,uint8 b,uint8 a=255); + virtual void SetPenSize(float size); + virtual void SetPixel(int x, int y, uint8 *pattern); + virtual void ShowCursor(void); + + virtual void StrokeArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern); + virtual void StrokeBezier(BPoint *points, uint8 *pattern); + virtual void StrokeEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern); + virtual void StrokeLine(BPoint point, uint8 *pattern); + virtual void StrokePolygon(int *x, int *y, int numpoints, bool is_closed); + virtual void StrokeRect(BRect rect,uint8 *pattern); + virtual void StrokeRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern); + virtual void StrokeShape(BShape *shape); + virtual void StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern); + VDWindow *screenwin; +protected: + int hide_cursor; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto4/main.cpp b/src/servers/app/proto4/main.cpp new file mode 100644 index 0000000000..a237ea2468 --- /dev/null +++ b/src/servers/app/proto4/main.cpp @@ -0,0 +1,16 @@ +// main.cpp + + +const char app_sig[] = "application/x-vnd.myApp"; + +#include + +int main() +{ + if(is_computer_on()) + { + // TODO: start up the application! + } + + return 0; +} diff --git a/src/servers/app/proto4/obhey/obhey.c b/src/servers/app/proto4/obhey/obhey.c new file mode 100644 index 0000000000..8e6bfbd617 --- /dev/null +++ b/src/servers/app/proto4/obhey/obhey.c @@ -0,0 +1,25 @@ +#include +#include +#include +#include +/* + Sends a message to the OpenBeOS app_server's message port +*/ + +int main(int argc, char **argv) +{ + int32 msgcode; + + if(argc>2) + { + port_id serverport=atoi(argv[1]); + msgcode=atoi(argv[2]); + + write_port(serverport,msgcode,NULL,0); + printf("Sent %ld to port %ld\n",msgcode,serverport); + return 1; + } + + printf("obhey port \n"); + return 0; +} \ No newline at end of file diff --git a/src/servers/app/proto4/obtestapp/OBApp.cpp b/src/servers/app/proto4/obtestapp/OBApp.cpp new file mode 100644 index 0000000000..099b97b91d --- /dev/null +++ b/src/servers/app/proto4/obtestapp/OBApp.cpp @@ -0,0 +1,639 @@ +/* + OBApp.cpp: App faker for OpenBeOS app_server prototype #4 + + This one happens to be a graphics tester. + + ReadyToRun is set to spawn a thread to post all the messages. Posting from a + separate thread will be necessary once packetized graphics messaging is done. + + Because graphics message packetizing is not done, the code in each function to + test the graphics will obviously change even though the data format which the + server will ultimately receive will stay the same. +*/ + +#include +#include // for the pattern struct and screen mode defs +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ServerProtocol.h" +#include "PortLink.h" +#include "OBApp.h" + +TestApp::TestApp(void) +{ + initialized=true; + + // Receives messages from server and others + messageport=create_port(50,"msgport"); + if(messageport==B_BAD_VALUE || messageport==B_NO_MORE_PORTS) + { printf("TestApp: Couldn't create message port\n"); + initialized=false; + } + + // Find the port for the app_server + serverport=find_port("OBappserver"); + if(serverport==B_NAME_NOT_FOUND) + { printf("TestApp: Couldn't find server port\n"); + initialized=false; + + serverlink=new PortLink(create_port(50,"OBAppServer")); + } + else + { + serverlink=new PortLink(serverport); + } + +// signature=new char[255]; + signature=new char[strlen("application/x-vnd.wgp-OBTestApp")]; + sprintf(signature,"application/x-vnd.wgp-OBTestApp"); + +} + +TestApp::~TestApp(void) +{ +// printf("%s::~TestApp()\n",signature); + delete signature; + + if(initialized==true) + delete serverlink; +} + +void TestApp::MainLoop(void) +{ + printf("TestApp::MainLoop()\n"); + + // Notify server of app's existence + serverlink->SetOpCode(CREATE_APP); + serverlink->Attach(&messageport,sizeof(port_id)); +// serverlink.Attach(PID); + serverlink->Attach(signature,strlen(signature)); + serverlink->Flush(); + + int32 msgcode; + uint8 *msgbuffer=NULL; + ssize_t buffersize,bytesread; + + for(;;) + { + buffersize=port_buffer_size(messageport); + + if(buffersize>0) + { + // buffers are flattened messages. Allocate necessary buffer and + // we'll cast it as a BMessage. + msgbuffer=new uint8[buffersize]; + bytesread=read_port(messageport,&msgcode,msgbuffer,buffersize); + } + else + bytesread=read_port(messageport,&msgcode,NULL,0); + + if (bytesread != B_BAD_PORT_ID && bytesread != B_TIMED_OUT && bytesread != B_WOULD_BLOCK) + { + switch(msgcode) + { + case B_QUIT_REQUESTED: + { + // Attached data: + // None + printf("%s: Quit requested\n",signature); + serverlink->SetOpCode(msgcode); + serverlink->Flush(); + break; + } + case SET_SERVER_PORT: + { + // This message is received when the server has created + // the ServerApp object to monitor our application. It is + // sending us the port to which we send future messages + + // Attached data: + // port_id - id of the port of the corresponding ServerApp + if(buffersize<1) + { + printf("%s: Set Server Port has no attached data\n",signature); + break; + } + printf("%s: Set Server Port to %ld\n",signature,*((port_id *)msgbuffer)); + serverport=*((port_id *)msgbuffer); + serverlink->SetPort(serverport); + ReadyToRun(); + break; + } + case B_MOUSE_MOVED: + case B_MOUSE_DOWN: + case B_MOUSE_UP: + DispatchMessage(msgcode, (int8*)msgbuffer); + break; + default: + printf("OBTestApp received unexpected code %ld\n",msgcode); + break; + } + + if(msgcode==B_QUIT_REQUESTED) + { + printf("Quitting %s\n",signature); + break; + } + } + + if(buffersize>0) + delete msgbuffer; + } +} + +void TestApp::DispatchMessage(BMessage *msg, BHandler *handler) +{ +// printf("TestApp::DispatchMessage()\n"); +} + +// For test application purposes only - will be replaced later +void TestApp::DispatchMessage(int32 code, int8 *buffer) +{ + switch(code) + { + case B_MOUSE_DOWN: + case B_MOUSE_UP: + case B_MOUSE_MOVED: + break; + default: + printf("TestApp %s received unknown code %ld\n",signature,code); + break; + } +} + +void TestApp::MessageReceived(BMessage *msg) +{ +// printf("TestApp::MessageReceived()\n"); +} + +void TestApp::ShowCursor(void) +{ + serverlink->SetOpCode(SHOW_CURSOR); + serverlink->Flush(); +} + +void TestApp::HideCursor(void) +{ + serverlink->SetOpCode(HIDE_CURSOR); + serverlink->Flush(); +} + +void TestApp::ObscureCursor(void) +{ + serverlink->SetOpCode(OBSCURE_CURSOR); + serverlink->Flush(); +} + +bool TestApp::IsCursorHidden(void) +{ + return false; +} + +void TestApp::SetCursor(const void *cursor) +{ +printf("TestApp::SetCursor()\n"); + // attach & send the 68-byte chunk + serverlink->SetOpCode(SET_CURSOR_DATA); + serverlink->Attach((void*)cursor, 68); + serverlink->Flush(); +} + +void TestApp::SetCursor(const BCursor *cursor, bool sync=true) +{ + // attach & send the BCursor + serverlink->SetOpCode(SET_CURSOR_BCURSOR); + serverlink->Attach((BCursor*)cursor, sizeof(BCursor)); + serverlink->Flush(); +} + +void TestApp::SetCursor(BBitmap *bmp) +{ + // This will be enabled once the BBitmap functionality is better nailed down + +/* // attach & send the TestBitmap's area_id + serverlink->SetOpCode(SET_CURSOR_BCURSOR); + serverlink->Attach(bmp, sizeof(BCursor)); + serverlink->Flush(); +*/ +} + +void TestApp::ReadyToRun(void) +{ + thread_id tid=spawn_thread(TestGraphics,"testthread",B_NORMAL_PRIORITY,this); + if(tid!=B_NO_MEMORY && tid!=B_NO_MORE_THREADS) + resume_thread(tid); +} + +int32 TestApp::TestGraphics(void *data) +{ + printf("TestGraphics Spawned\n"); + TestApp *app=(TestApp*)data; + + app->TestScreenStates(); + app->TestArcs(); + app->TestBeziers(); + app->TestEllipses(); + app->TestLines(); +// app->TestPolygon(); + app->TestRects(); +// app->TestRegions(); +// app->TestShape(); + app->TestTriangle(); + app->TestCursors(); + app->TestFonts(); + printf("TestGraphics Exited\n"); + exit_thread(0); + return 0; +} + +void TestApp::SetHighColor(uint8 r, uint8 g, uint8 b) +{ + // Server always expects an alpha value + uint8 a=255; + serverlink->SetOpCode(GFX_SET_HIGH_COLOR); + serverlink->Attach(&r,sizeof(uint8)); + serverlink->Attach(&g,sizeof(uint8)); + serverlink->Attach(&b,sizeof(uint8)); + serverlink->Attach(&a,sizeof(uint8)); + serverlink->Flush(); +} + +void TestApp::SetLowColor(uint8 r, uint8 g, uint8 b) +{ + // Server always expects an alpha value + uint8 a=255; + serverlink->SetOpCode(GFX_SET_LOW_COLOR); + serverlink->Attach(&r,sizeof(uint8)); + serverlink->Attach(&g,sizeof(uint8)); + serverlink->Attach(&b,sizeof(uint8)); + serverlink->Attach(&a,sizeof(uint8)); + serverlink->Flush(); +} + +void TestApp::TestScreenStates(void) +{ + // This function is here to test all the graphics state code, such as + // resolution, desktop switching, etc. + + // Protocol defined here will be used by the screen-related global functions + + int32 workspace=0; + uint32 mode=B_32_BIT_640x480; + bool sticky=false; + + // set_screen_space() + serverlink->SetOpCode(GFX_SET_SCREEN_MODE); + serverlink->Attach(&workspace,sizeof(int32)); + serverlink->Attach(&mode,sizeof(int32)); + serverlink->Attach(&sticky,sizeof(bool)); + serverlink->Flush(); + + // This code works, I just don't want to mess with it when I'm + // working on the other tests. +/* + // activate_workspace() + workspace=1; + serverlink->SetOpCode(GFX_ACTIVATE_WORKSPACE); + serverlink->Attach(&workspace,sizeof(int32)); + serverlink->Flush(); +*/ +} + +void TestApp::TestArcs(void) +{ + float centerx=275, centery=95, + radx=70, rady=45, + angle=40, + span=210; + + // Fill Arc + SetHighColor(0,0,255); + serverlink->SetOpCode(GFX_FILL_ARC); + serverlink->Attach(¢erx,sizeof(float)); + serverlink->Attach(¢ery,sizeof(float)); + serverlink->Attach(&radx,sizeof(float)); + serverlink->Attach(&rady,sizeof(float)); + serverlink->Attach(&angle,sizeof(float)); + serverlink->Attach(&span,sizeof(float)); + serverlink->Attach((pattern *)&B_SOLID_HIGH, sizeof(pattern)); + serverlink->Flush(); + + // Stroke Arc + for(int i=0; i<45; i+=5) + { + centerx=280+i; + centery=100+i; + radx=75+i; + rady=50+i; + angle=45+i; + span=215+i; + SetHighColor(128+(i*2),128+(i*2),128+(i*2)); + serverlink->SetOpCode(GFX_STROKE_ARC); + serverlink->Attach(¢erx,sizeof(float)); + serverlink->Attach(¢ery,sizeof(float)); + serverlink->Attach(&radx,sizeof(float)); + serverlink->Attach(&rady,sizeof(float)); + serverlink->Attach(&angle,sizeof(float)); + serverlink->Attach(&span,sizeof(float)); + serverlink->Attach((pattern *)&B_SOLID_HIGH, sizeof(pattern)); + serverlink->Flush(); + } +} + +void TestApp::TestBeziers(void) +{ + BPoint p1(500,300), + p2(350,450), + p3(350,300), + p4(500,450); + + // Stroke Bezier + SetHighColor(0,255,0); + serverlink->SetOpCode(GFX_STROKE_BEZIER); + serverlink->Attach(&p1,sizeof(BPoint)); + serverlink->Attach(&p2,sizeof(BPoint)); + serverlink->Attach(&p3,sizeof(BPoint)); + serverlink->Attach(&p4,sizeof(BPoint)); + serverlink->Attach((pattern *)&B_SOLID_HIGH, sizeof(pattern)); + serverlink->Flush(); + + // Fill Bezier + p1.Set(250,250); + p2.Set(300,300); + p3.Set(300,250); + p4.Set(300,250); + SetHighColor(255,0,0); + serverlink->SetOpCode(GFX_FILL_BEZIER); + serverlink->Attach(&p1,sizeof(BPoint)); + serverlink->Attach(&p2,sizeof(BPoint)); + serverlink->Attach(&p3,sizeof(BPoint)); + serverlink->Attach(&p4,sizeof(BPoint)); + serverlink->Attach((pattern *)&B_SOLID_HIGH, sizeof(pattern)); + serverlink->Flush(); + +} + +void TestApp::TestEllipses(void) +{ + float centerx=200, centery=200, + radx=10, rady=5; + + // Fill Ellipse + SetHighColor(0,0,0); + serverlink->SetOpCode(GFX_FILL_ELLIPSE); + serverlink->Attach(¢erx,sizeof(float)); + serverlink->Attach(¢ery,sizeof(float)); + serverlink->Attach(&radx,sizeof(float)); + serverlink->Attach(&rady,sizeof(float)); + serverlink->Attach((pattern *)&B_SOLID_HIGH, sizeof(pattern)); + serverlink->Flush(); + + // Stroke Ellipse + for(int i=5; i<255; i+=10) + { + SetHighColor(i,i,i); + radx=10+i; + rady=5+i; + serverlink->SetOpCode(GFX_STROKE_ELLIPSE); + serverlink->Attach(¢erx,sizeof(float)); + serverlink->Attach(¢ery,sizeof(float)); + serverlink->Attach(&radx,sizeof(float)); + serverlink->Attach(&rady,sizeof(float)); + serverlink->Attach((pattern *)&B_SOLID_HIGH, sizeof(pattern)); + serverlink->Flush(); + } +} + +void TestApp::TestFonts(void) +{ + + // Can't test SetFont() -- we don't have an active BApplication. :( + + // Draw String + BString string("OpenBeOS: The Future is Drawing Near..."); + uint16 length=string.Length(); + + // this will be set to a negative value in the case of not being passed + // a BPoint + BPoint pt(10,175); + + SetHighColor(0,0,0); + serverlink->SetOpCode(GFX_DRAW_STRING); + + // String passing protocol for PortLink/AppServer combination: + // uint16 length of string precedes each string + serverlink->Attach(&length,sizeof(uint16)); + serverlink->Attach((char *)string.String(),string.Length()); + serverlink->Attach(&pt,sizeof(BPoint)); + + // for now, passing escapements is disabled, so none are attached + serverlink->Flush(); +} + +void TestApp::TestLines(void) +{ + // Protocol for the usual line method (BPoint,BPoint) will simply + // result in a MovePenTo call followed by a StrokeLine(BPoint) call + + BPoint pt(100,100); + float x=50,y=50,size=1; + + // MovePenTo() + serverlink->SetOpCode(GFX_MOVEPENTO); + serverlink->Attach(&pt,sizeof(BPoint)); + serverlink->Flush(); + + // StrokeLine(BPoint) + pt.Set(10,10); + SetHighColor(255,0,255); + serverlink->SetOpCode(GFX_STROKE_LINE); + serverlink->Attach(&pt,sizeof(BPoint)); + serverlink->Attach((pattern *)&B_SOLID_HIGH, sizeof(pattern)); + serverlink->Flush(); + + // MovePenBy() + pt.Set(100,0); + serverlink->SetOpCode(GFX_MOVEPENBY); + serverlink->Attach(&x,sizeof(float)); + serverlink->Attach(&y,sizeof(float)); + serverlink->Flush(); + + // Eventually, this will become a LineArray test... + for(int i=0;i<256;i++) + { + // SetPenSize() + size=i/10; + serverlink->SetOpCode(GFX_SETPENSIZE); + serverlink->Attach(&size,sizeof(float)); + serverlink->Flush(); + + // StrokeLine(BPoint) + pt.Set(10,10+i); + SetHighColor(255,i,255); + serverlink->SetOpCode(GFX_STROKE_LINE); + serverlink->Attach(&pt,sizeof(BPoint)); + serverlink->Attach((pattern *)&B_SOLID_HIGH, sizeof(pattern)); + serverlink->Flush(); + } + // SetPenSize() + size=1; + serverlink->SetOpCode(GFX_SETPENSIZE); + serverlink->Attach(&size,sizeof(float)); + serverlink->Flush(); +} + +void TestApp::TestPolygon(void) +{ + // This one's going to REALLY be a pain. Can't be flattened like a BShape. + // Can't access any of its data like BRegion. I guess it'll have to wait until + // I've implemented the BView class. I'm starting to get a headache.... +} + +void TestApp::TestRects(void) +{ + BRect rect(10,270,75,335); + float xrad=10,yrad=30; + + SetHighColor(255,0,0); + + // Stroke Rect + serverlink->SetOpCode(GFX_STROKE_RECT); + serverlink->Attach(&rect,sizeof(BRect)); + serverlink->Attach((pattern *)&B_SOLID_HIGH, sizeof(pattern)); + serverlink->Flush(); + + // Fill Rect + rect.OffsetBy(100,10); + serverlink->SetOpCode(GFX_FILL_RECT); + serverlink->Attach(&rect,sizeof(BRect)); + serverlink->Attach((pattern *)&B_SOLID_LOW, sizeof(pattern)); + serverlink->Flush(); + + // Stroke Round Rect + rect.OffsetBy(100,10); + + SetHighColor(0,255,0); + serverlink->SetOpCode(GFX_STROKE_ROUNDRECT); + serverlink->Attach(&rect,sizeof(BRect)); + serverlink->Attach(&xrad,sizeof(float)); + serverlink->Attach(&yrad,sizeof(float)); + serverlink->Attach((pattern *)&B_SOLID_HIGH, sizeof(pattern)); + serverlink->Flush(); + + // Fill Round Rect + rect.OffsetBy(100,10); + SetHighColor(0,255,255); + serverlink->SetOpCode(GFX_FILL_ROUNDRECT); + serverlink->Attach(&rect,sizeof(BRect)); + serverlink->Attach(&xrad,sizeof(float)); + serverlink->Attach(&yrad,sizeof(float)); + serverlink->Attach((pattern *)&B_SOLID_HIGH, sizeof(pattern)); + serverlink->Flush(); + +} + +void TestApp::TestRegions(void) +{ +/* +Because of the varying size of BRegions, this will be a bit sticky. Size does +not change with added rectangles because the internally, it uses a BList. We +also must contend with the fact that they very well may not fit into the +port's buffer, which could have very nasty results. + +Possible Solutions: +1) Flatten it like a PortLink flattens data and pass the flattened region to + the server via an area. We' can simply clone it and pass the second + area_id to the server. +2) Attach it to a BMessage and fire it off. +3) Create an API which operates something like BeginRectArray() +*/ + +} + +void TestApp::TestShape(void) +{ + // BShapes are derived from BArchivable, so we'll flatten it, and fire it to + // the server via a BMessage. Thus, this will need to be done later... +} + +void TestApp::TestTriangle(void) +{ + // In either form of the function, we have to calculate the invaliated + // rect which contains the triangle unless the caller gives us one. Thus, + // the functions will always send a BRect to the server. + + BRect invalid; + + BPoint pt1(600,100), pt2(500,200), pt3(550,450); + + invalid.Set( MIN( MIN(pt1.x,pt2.x), pt3.x), + MIN( MIN(pt1.y,pt2.y), pt3.y), + MAX( MAX(pt1.x,pt2.x), pt3.x), + MAX( MAX(pt1.y,pt2.y), pt3.y) ); + + // Fill Triangle + SetHighColor(228,228,50); + serverlink->SetOpCode(GFX_FILL_TRIANGLE); + serverlink->Attach(&pt1,sizeof(BPoint)); + serverlink->Attach(&pt2,sizeof(BPoint)); + serverlink->Attach(&pt3,sizeof(BPoint)); + serverlink->Attach(&invalid,sizeof(BRect)); + serverlink->Attach((pattern *)&B_SOLID_HIGH, sizeof(pattern)); + serverlink->Flush(); + + + pt1.Set(50,50); + pt2.Set(200,475); + pt3.Set(400,400); + invalid.Set( MIN( MIN(pt1.x,pt2.x), pt3.x), + MIN( MIN(pt1.y,pt2.y), pt3.y), + MAX( MAX(pt1.x,pt2.x), pt3.x), + MAX( MAX(pt1.y,pt2.y), pt3.y) ); + // Stroke Triangle + SetHighColor(0,128,128); + serverlink->SetOpCode(GFX_STROKE_TRIANGLE); + serverlink->Attach(&pt1,sizeof(BPoint)); + serverlink->Attach(&pt2,sizeof(BPoint)); + serverlink->Attach(&pt3,sizeof(BPoint)); + serverlink->Attach(&invalid,sizeof(BRect)); + serverlink->Attach((pattern *)&B_SOLID_HIGH, sizeof(pattern)); + serverlink->Flush(); +} + +void TestApp::TestCursors(void) +{ +uint8 cross[] = {16,1,5,5, +14,0,4,0,4,0,4,0,128,32,241,224,128,32,4,0, +4,0,4,0,14,0,0,0,0,0,0,0,0,0,0,0, +14,0,4,0,4,0,4,0,128,32,245,224,128,32,4,0, +4,0,4,0,14,0,0,0,0,0,0,0,0,0,0,0 +}; + + SetCursor(cross); + HideCursor(); + ShowCursor(); + ObscureCursor(); +} + +bool TestApp::Run(void) +{ +// printf("TestApp::Run()\n"); + if(!initialized) + return false; + + MainLoop(); + return true; +} + +int main(void) +{ + TestApp app; + app.Run(); +} \ No newline at end of file diff --git a/src/servers/app/proto4/obtestapp/OBApp.h b/src/servers/app/proto4/obtestapp/OBApp.h new file mode 100644 index 0000000000..a1394c6a62 --- /dev/null +++ b/src/servers/app/proto4/obtestapp/OBApp.h @@ -0,0 +1,57 @@ +#ifndef _OBOS_APPLICATION_H_ +#define _OBOS_APPLICATION_H_ + +#include +#include + +class PortLink; + +class TestApp +{ +public: + TestApp(void); + virtual ~TestApp(void); + + // Replaces BLooper message looping + void MainLoop(void); + + // Hmm... What do these do? ;^) + void DispatchMessage(int32 code, int8 *buffer); + virtual void DispatchMessage(BMessage *msg, BHandler *handler); + virtual void MessageReceived(BMessage *msg); + virtual void ReadyToRun(void); + bool Run(void); + void ShowCursor(void); + void HideCursor(void); + void ObscureCursor(void); + bool IsCursorHidden(void); + void SetCursor(const void *cursor); + void SetCursor(const BCursor *cursor, bool sync=true); + void SetCursor(BBitmap *bmp); + + port_id messageport, serverport; + char *signature; + bool initialized; + PortLink *serverlink; + + static int32 TestGraphics(void *data); + + // Testing functions: + void SetLowColor(uint8 r, uint8 g, uint8 b); + void SetHighColor(uint8 r, uint8 g, uint8 b); + + void TestScreenStates(void); + void TestArcs(void); + void TestBeziers(void); + void TestEllipses(void); + void TestFonts(void); + void TestLines(void); + void TestPolygon(void); + void TestRects(void); + void TestRegions(void); + void TestShape(void); + void TestTriangle(void); + void TestCursors(void); +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto4/obtestapp/PortLink.cpp b/src/servers/app/proto4/obtestapp/PortLink.cpp new file mode 100644 index 0000000000..8fba724569 --- /dev/null +++ b/src/servers/app/proto4/obtestapp/PortLink.cpp @@ -0,0 +1,438 @@ +/* + PortLink.cpp: + A helper class for port-based messaging + +------------------------------------------------------------------------ +How it works: + The class utilizes a fixed-size array of PortLinkData object pointers. When +data is attached, a new PortLinkData object is allocated and a copy of the +passed data is created inside it. When the time comes for the message to be sent, +the data is pieced together into a flattened array and written to the port. +------------------------------------------------------------------------ +Data members: + +*attachments[] - fixed-size array of pointers used to hold the attached data +opcode - message value which is sent along with any data +target - port to which the message is sent when Flush() is called +replyport - port used with synchronous messaging - FlushWithReply() +bufferlength - total bytes taken up by attachments +num_attachments - internal variable which is used to track which "slot" + will be the next one to receive an attachment object +*/ + +#include "PortLink.h" +#include +#include +#include + +//#define PLDEBUG + +// Internal data storage class for holding attached data whilst it is waiting +// to be Flattened() and then Flushed(). There is no need for this to be called outside +// the PortLink class. +class PortLinkData +{ +public: + PortLinkData(void); + ~PortLinkData(void); + bool Set(void *data, size_t size); + char *buffer; + size_t buffersize; +}; + +PortLink::PortLink(port_id port) +{ + // For this class to be useful (and to prevent a lot of init problems) + // we require a port in the constructor + target=port; + + // We start out without any data attached to the port message + num_attachments=0; + opcode=0; + bufferlength=0; + replyport=create_port(30,"PortLink reply port"); +} + +PortLink::~PortLink(void) +{ + // If, for some odd reason, this is deleted with something attached, + // free the memory used by the attachments. We do not flush the queue + // because the port may no longer be valid in cases such as the app + // is in the process of quitting + MakeEmpty(); +} + +void PortLink::SetOpCode(int32 code) +{ + // Sets the message code. This does not change once the message is sent. + // Another call to SetOpCode() is required for such things. + opcode=code; +} + +void PortLink::SetPort(port_id port) +{ + // Sets the target port. While not necessary in most uses, this exists + // mostly to prevent flexibility problems + target=port; +} + +port_id PortLink::GetPort(void) +{ + // Simply returns the port at which the object is pointed. + return target; +} + +void PortLink::Flush(bigtime_t timeout=B_INFINITE_TIMEOUT) +{ + // Fires a message off to the target, complete with attachments. NOTE: + // the recipient must delete all attachments, being the PortLink object assumes + // no responsiblity for the attachments once the message is sent. + int8 *msgbuffer; + int32 size; + + if(num_attachments>0) + { + FlattenData(&msgbuffer,&size); + + // Dump message to port, reset attachments, and clean up + if(timeout!=B_INFINITE_TIMEOUT) + write_port_etc(target,opcode,msgbuffer,size,B_TIMEOUT, timeout); + else + write_port(target,opcode,msgbuffer,size); + MakeEmpty(); + } + else + { + if(timeout!=B_INFINITE_TIMEOUT) + write_port_etc(target,opcode,NULL,0,B_TIMEOUT, timeout); + else + write_port(target,opcode,NULL,0); + } +} + +int8* PortLink::FlushWithReply(int32 *code, status_t *status, ssize_t *buffersize, bigtime_t timeout=B_INFINITE_TIMEOUT) +{ + // Fires a message to the target and then waits for a reply. The target will + // receive a message with the first item being the port_id to reply to. + // NOTE: like Flush(), any attached data must be deleted. + + // Effectively, an Attach() call inlined for changes + + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + { + *status=B_ERROR; + return NULL; + } + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&replyport,sizeof(port_id))) + { + bufferlength+=sizeof(port_id); + } + else + { + delete pld; + *status=B_ERROR; + return NULL; + } + + // Flatten() inlined to make some necessary changes + int8 *buffer=new int8[bufferlength]; + int8 *bufferindex=buffer; + size_t size=0; + + // attach our port_id first + memcpy(bufferindex, pld->buffer, pld->buffersize); + bufferindex += pld->buffersize; + size+=pld->buffersize; + + // attach everything else + for(int i=0;ibuffer, pld->buffersize); + bufferindex += pld->buffersize; + size+=pld->buffersize; + } + + // Flush the thing....FOOSH! :P + write_port(target,opcode,buffer,size); + MakeEmpty(); + delete buffer; + + // Now we wait for the reply + if(timeout==B_INFINITE_TIMEOUT) + { + *buffersize=port_buffer_size(replyport); + if(*buffersize>0) + buffer=(int8*)new int8[*buffersize]; + read_port(replyport,code, buffer, *buffersize); + } + else + { + *buffersize=port_buffer_size_etc(replyport,0,timeout); + if(*buffersize==B_TIMED_OUT) + { + *status=*buffersize; + return NULL; + } + if(*buffersize>0) + buffer=(int8*)new int8[*buffersize]; + read_port(replyport,code, buffer, *buffersize); + } + + // We got this far, so we apparently have some data + *status=B_OK; + return buffer; +} + +void PortLink::Attach(void *data, size_t size) +{ + // This is the member called to attach data to a message. Attachments are + // treated to be in 'Append' mode, tacking on each attached piece of data + // to the end of the list. + + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + if(size==0) + return; + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +// These functions were added for a major convenience in passing common types +// Eventually, I'd like to templatize these, but for now, this'll do + +void PortLink::Attach(int32 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int32); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(int16 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int16); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(int8 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int8); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(float data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(float); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(bool data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(bool); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(BRect data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(BRect); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(BPoint data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(BPoint); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::FlattenData(int8 **buffer,int32 *size) +{ + // This function is where all the magic happens, but it is strictly internal. + // It iterates through each PortLinkData object and copies it to the main buffer + // which ends up, ultimately, being written to the PortLink's target port. + + // skip if there aree no attachments + if(bufferlength<1) + return; + + *buffer=new int8[bufferlength]; + int8 *bufferindex=*buffer; + PortLinkData *pld; + *size=0; + + for(int i=0;ibuffer, pld->buffersize); + bufferindex += pld->buffersize; + *size+=pld->buffersize; + } +} + +void PortLink::MakeEmpty(void) +{ + // Nukes all the attachments currently held by the PortLink class + if(num_attachments!=0) + { + for(int i=0; i0) + free(buffer); +} + +bool PortLinkData::Set(void *data, size_t size) +{ + // Function copies the passed to the internal buffers for storage + if(size>0 && buffersize==0 && data!=NULL) + { + buffer=(char *)malloc(size); + if(buffer==NULL) + return false; + memcpy(buffer, data, size); + buffersize=size; + return true; + } + return false; +} diff --git a/src/servers/app/proto4/obtestapp/PortLink.h b/src/servers/app/proto4/obtestapp/PortLink.h new file mode 100644 index 0000000000..9f5432daab --- /dev/null +++ b/src/servers/app/proto4/obtestapp/PortLink.h @@ -0,0 +1,43 @@ +#ifndef _PORTLINK_H_ +#define _PORTLINK_H_ + +#include +#include +#include +#include + +#ifndef _PORTLINK_BUFFERSIZE +#define _PORTLINK_MAX_ATTACHMENTS 50 +#endif + +class PortLinkData; + +class PortLink +{ +public: + PortLink(port_id port); + ~PortLink(void); + void SetOpCode(int32 code); + void SetPort(port_id port); + port_id GetPort(void); + void Flush(bigtime_t timeout=B_INFINITE_TIMEOUT); + int8* FlushWithReply(int32 *code, status_t *status, ssize_t *buffersize, + bigtime_t timeout=B_INFINITE_TIMEOUT); + void Attach(void *data, size_t size); + void Attach(int32 data); + void Attach(int16 data); + void Attach(int8 data); + void Attach(float data); + void Attach(bool data); + void Attach(BRect data); + void Attach(BPoint data); + void MakeEmpty(void); +protected: + void FlattenData(int8 **buffer,int32 *size); + port_id target, replyport; + int32 opcode, bufferlength; + int num_attachments; + PortLinkData *attachments[_PORTLINK_MAX_ATTACHMENTS]; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto4/obtestapp/ServerProtocol.h b/src/servers/app/proto4/obtestapp/ServerProtocol.h new file mode 100644 index 0000000000..ab23ca2d10 --- /dev/null +++ b/src/servers/app/proto4/obtestapp/ServerProtocol.h @@ -0,0 +1,69 @@ +#ifndef _APPSERVER_PROTOCOL_ +#define _APPSERVER_PROTOCOL_ + +#define CREATE_APP 'drca' +#define DELETE_APP 'drda' +#define QUIT_APP 'srqa' + +#define SET_SERVER_PORT 'srsp' + +#define CREATE_WINDOW 'drcw' +#define DELETE_WINDOW 'drdw' +#define QUIT_WINDOW 'srqw' + +#define SERVER_PORT_NAME "OBappserver" +#define SERVER_INPUT_PORT "OBinputport" + +#define SET_CURSOR_DATA 'sscd' +#define SET_CURSOR_BCURSOR 'sscb' +#define SET_CURSOR_BBITMAP 'sscB' +#define SHOW_CURSOR 'srsc' +#define HIDE_CURSOR 'srhc' +#define OBSCURE_CURSOR 'sroc' + +#define GFX_COUNT_WORKSPACES 'gcws' +#define GFX_SET_WORKSPACE_COUNT 'ggwc' +#define GFX_CURRENT_WORKSPACE 'ggcw' +#define GFX_ACTIVATE_WORKSPACE 'gaws' +#define GFX_SYSTEM_COLORS 'gsyc' +#define GFX_SET_SCREEN_MODE 'gssm' +#define GFX_GET_SCROLLBAR_INFO 'ggsi' +#define GFX_SET_SCROLLBAR_INFO 'gssi' +#define GFX_IDLE_TIME 'gidt' +#define GFX_SELECT_PRINTER_PANEL 'gspp' +#define GFX_ADD_PRINTER_PANEL 'gapp' +#define GFX_RUN_BE_ABOUT 'grba' +#define GFX_SET_FOCUS_FOLLOWS_MOUSE 'gsfm' +#define GFX_FOCUS_FOLLOWS_MOUSE 'gffm' + +#define GFX_SET_HIGH_COLOR 'gshc' +#define GFX_SET_LOW_COLOR 'gslc' + +#define GFX_STROKE_ARC 'gsar' +#define GFX_STROKE_BEZIER 'gsbz' +#define GFX_STROKE_ELLIPSE 'gsel' +#define GFX_STROKE_LINE 'gsln' +#define GFX_STROKE_POLYGON 'gspy' +#define GFX_STROKE_RECT 'gsrc' +#define GFX_STROKE_ROUNDRECT 'gsrr' +#define GFX_STROKE_SHAPE 'gssh' +#define GFX_STROKE_TRIANGLE 'gstr' + +#define GFX_FILL_ARC 'gfar' +#define GFX_FILL_BEZIER 'gfbz' +#define GFX_FILL_ELLIPSE 'gfel' +#define GFX_FILL_POLYGON 'gfpy' +#define GFX_FILL_RECT 'gfrc' +#define GFX_FILL_REGION 'gfrg' +#define GFX_FILL_ROUNDRECT 'gfrr' +#define GFX_FILL_SHAPE 'gfsh' +#define GFX_FILL_TRIANGLE 'gftr' + +#define GFX_MOVEPENBY 'gmpb' +#define GFX_MOVEPENTO 'gmpt' +#define GFX_SETPENSIZE 'gsps' + +#define GFX_DRAW_STRING 'gdst' +#define GFX_SET_FONT 'gsft' +#define GFX_SET_FONT_SIZE 'gsfs' +#endif \ No newline at end of file diff --git a/src/servers/app/proto4/obtestapp/TestBitmap.cpp b/src/servers/app/proto4/obtestapp/TestBitmap.cpp new file mode 100644 index 0000000000..7da40d92fa --- /dev/null +++ b/src/servers/app/proto4/obtestapp/TestBitmap.cpp @@ -0,0 +1,193 @@ +/* + TestBitmap.h + BBitmap faker used to test app_server prototypes +*/ + +#include +#include "TestBitmap.h" + +TestBitmap::TestBitmap(BRect bounds,color_space depth,bool accepts_views = false, + bool need_contiguous = false) +{ +} + +TestBitmap::TestBitmap(BRect bounds,uint32 flags,color_space depth, + int32 bytesPerRow=B_ANY_BYTES_PER_ROW,screen_id screenID=B_MAIN_SCREEN_ID) +{ +} + +TestBitmap::TestBitmap(const TestBitmap *source,bool accepts_views = false, + bool need_contiguous = false) +{ +} + +TestBitmap::~TestBitmap(void) +{ +} + +status_t TestBitmap::InitCheck() +{ + return B_ERROR; +} + +bool TestBitmap::IsValid() +{ + return false; +} + +area_id TestBitmap::Area() +{ + return B_ERROR; +} + +void * TestBitmap::Bits() +{ + return NULL; +} + +int32 TestBitmap::BitsLength() +{ + return 0; +} + +int32 TestBitmap::BytesPerRow() +{ + return 0; +} + +color_space TestBitmap::ColorSpace() +{ + return B_NO_COLOR_SPACE; +} + +BRect TestBitmap::Bounds() +{ + return BRect(0,0,0,0); +} + +void TestBitmap::HandleSpace(color_space space, int32 BytesPerLine) +{ + // Function written to handle color space setup which is required + // by the two "normal" constructors + + // Big convoluted mess just to handle every color space and dword align + // the buffer + switch(space) + { + // Buffer is dword-aligned, so nothing need be done + // aside from allocate the memory + case B_RGB32: + case B_RGBA32: + case B_RGB32_BIG: + case B_RGBA32_BIG: + case B_UVL32: + case B_UVLA32: + case B_LAB32: + case B_LABA32: + case B_HSI32: + case B_HSIA32: + case B_HSV32: + case B_HSVA32: + case B_HLS32: + case B_HLSA32: + case B_CMY32: + case B_CMYA32: + case B_CMYK32: + + // 24-bit = 32-bit with extra 8 bits ignored + case B_RGB24_BIG: + case B_RGB24: + case B_LAB24: + case B_UVL24: + case B_HSI24: + case B_HSV24: + case B_HLS24: + case B_CMY24: + { + if(BytesPerLine<(width*4)) + bytesperline=width*4; + else + bytesperline=BytesPerLine; + bpp=32; + break; + } + // Calculate size and dword-align + + // 1-bit + case B_GRAY1: + { + int32 numbytes=width>>3; + if((width % 8) != 0) + numbytes++; + if(BytesPerLine +#include + +enum { + B_BITMAP_CLEAR_TO_WHITE = 0x00000001, + B_BITMAP_ACCEPTS_VIEWS = 0x00000002, + B_BITMAP_IS_AREA = 0x00000004, + B_BITMAP_IS_LOCKED = 0x00000008 | B_BITMAP_IS_AREA, + B_BITMAP_IS_CONTIGUOUS = 0x00000010 | B_BITMAP_IS_LOCKED, + B_BITMAP_IS_OFFSCREEN = 0x00000020, + B_BITMAP_WILL_OVERLAY = 0x00000040 | B_BITMAP_IS_OFFSCREEN, + B_BITMAP_RESERVE_OVERLAY_CHANNEL = 0x00000080 +}; + +#ifndef B_ANY_BYTES_PER_ROW +#define B_ANY_BYTES_PER_ROW -1 +#endif + +class TestBitmap +{ +public: + TestBitmap(BRect bounds,color_space depth,bool accepts_views = false, + bool need_contiguous = false); + TestBitmap(BRect bounds,uint32 flags,color_space depth, + int32 bytesPerRow=B_ANY_BYTES_PER_ROW,screen_id screenID=B_MAIN_SCREEN_ID); + TestBitmap(const TestBitmap *source,bool accepts_views = false, + bool need_contiguous = false); + ~TestBitmap(void); + + status_t InitCheck(); + bool IsValid(); + +// status_t LockBits(uint32 *state=NULL); +// void UnlockBits(); + + area_id Area(); + void *Bits(); + int32 BitsLength(); + int32 BytesPerRow(); + color_space ColorSpace(); + BRect Bounds(); + + void SetBits(const void *data,int32 length,int32 offset,color_space cs); +/* virtual void AddChild(BView *view); + virtual bool RemoveChild(BView *view); + int32 CountChildren(); + BView *ChildAt(int32 index); + BView *FindView(const char *view_name); + BView *FindView(BPoint point); + bool Lock(); + void Unlock(); + bool IsLocked(); +*/ +protected: + void HandleSpace(color_space space, int32 BytesPerLine); + uint8 *buffer; + + int32 width,height; + int32 bytesperline; + color_space cspace; + int bpp; + area_id area; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto5/AppServer.cpp b/src/servers/app/proto5/AppServer.cpp new file mode 100644 index 0000000000..dba1639534 --- /dev/null +++ b/src/servers/app/proto5/AppServer.cpp @@ -0,0 +1,552 @@ +/* + AppServer.cpp + File for the main app_server thread. This particular thread monitors for + application start and quit messages. It also starts the housekeeping threads + and initializes most of the server's globals. +*/ +#include +#include +#include "scheduler.h" +#include +#include +#include +#include +#include "AppServer.h" +#include "Layer.h" +#include "ServerApp.h" +#include "ServerWindow.h" +#include "Desktop.h" +#include "ServerProtocol.h" +#include "PortLink.h" +#include "DisplayDriver.h" +#include "DebugTools.h" +#include "BeDecorator.h" +//#include "YMakDecorator.h" + +//#define DEBUG_APPSERVER_THREAD + +// This bad boy holds only the top layer for each workspace +//BList *layerlist; + +// Used for mediating access to the layer lists +//BLocker *layerlock; + +// Used for access via instantiate_decorator +AppServer *app_server; + +AppServer::AppServer(void) : BApplication("application/x-vnd.obe-OBAppServer") +{ +#ifdef DEBUG_APPSERVER_THREAD + printf("AppServer()\n"); +#endif + + mouseport=create_port(30,SERVER_INPUT_PORT); + messageport=create_port(20,SERVER_PORT_NAME); +#ifdef DEBUG_APPSERVER_THREAD +printf("Server message port: %ld\n",messageport); +printf("Server input port: %ld\n",mouseport); +#endif + applist=new BList(0); + quitting_server=false; + exit_poller=false; + + // Set up the Desktop + init_desktop(3); + + // This is necessary to mediate access between the Poller and app_server threads + active_lock=new BLocker; + + // This locker is for app_server and Picasso to vy for control of the ServerApp list + applist_lock=new BLocker; + + // This locker is to mediate access to the make_decorator pointer + decor_lock=new BLocker; + + // Get the driver first - Poller thread utilizes the thing + driver=get_gfxdriver(); + + // Spawn our input-polling thread + poller_id = spawn_thread(PollerThread, "Poller", B_NORMAL_PRIORITY, this); + if (poller_id >= 0) + resume_thread(poller_id); + + // Spawn our thread-monitoring thread + picasso_id = spawn_thread(PicassoThread,"Picasso", B_NORMAL_PRIORITY, this); + if (picasso_id >= 0) + resume_thread(picasso_id); + + active_app=-1; + p_active_app=NULL; + +// layerlock=new BLocker; +// layerlist=new BList(1); +} + +AppServer::~AppServer(void) +{ + shutdown_desktop(); + + ServerApp *tempapp; +// Layer *templayer; + int32 i; + applist_lock->Lock(); + for(i=0;iCountItems();i++) + { + tempapp=(ServerApp *)applist->ItemAt(i); + if(tempapp!=NULL) + delete tempapp; + } + delete applist; + applist_lock->Unlock(); + +/* layerlock->Lock(); + for(i=0;iCountItems();i++) + { + templayer=(Layer *)layerlist->ItemAt(i); + + if(templayer!=NULL) + { + templayer->PruneTree(); + delete templayer; + } + } + delete layerlist; + layerlock->Unlock(); + + delete layerlock; +*/ delete active_lock; + delete applist_lock; + + // If these threads are still running, kill them - after this, if exit_poller + // is deleted, who knows what will happen... These things will just return an + // error and fail if the threads have already exited. + kill_thread(poller_id); + kill_thread(picasso_id); + + delete decor_lock; + + make_decorator=NULL; +} + +thread_id AppServer::Run(void) +{ +#ifdef DEBUG_APPSERVER_THREAD +printf("AppServer::Run()\n"); +#endif + + MainLoop(); + return 0; +} + +void AppServer::MainLoop(void) +{ + // Main loop (duh). Monitors the message queue and dispatches as appropriate. + // Input messages are handled by the poller, however. + +#ifdef DEBUG_APPSERVER_THREAD +printf("AppServer::MainLoop()\n"); +#endif + + int32 msgcode; + int8 *msgbuffer=NULL; + ssize_t buffersize,bytesread; + + for(;;) + { + buffersize=port_buffer_size(messageport); + if(buffersize>0) + msgbuffer=new int8[buffersize]; + bytesread=read_port(messageport,&msgcode,msgbuffer,buffersize); + + if (bytesread != B_BAD_PORT_ID && bytesread != B_TIMED_OUT && bytesread != B_WOULD_BLOCK) + { + switch(msgcode) + { + case CREATE_APP: + case DELETE_APP: + case B_QUIT_REQUESTED: + DispatchMessage(msgcode,msgbuffer); + break; + default: + { +#ifdef DEBUG_APPSERVER_THREAD +printf("Server received unexpected code %ld\n",msgcode); +#endif + break; + } + } + + } + + if(buffersize>0) + delete msgbuffer; + if(msgcode==DELETE_APP || msgcode==B_QUIT_REQUESTED) + { + if(quitting_server==true && applist->CountItems()==0) + break; + } + } + // Make sure our polling thread has exited + if(find_thread("Poller")!=B_NAME_NOT_FOUND) + kill_thread(poller_id); + +} + + +void AppServer::DispatchMessage(int32 code, int8 *buffer) +{ + int8 *index=buffer; + switch(code) + { + case CREATE_APP: + { + // Create the ServerApp to node monitor a new BApplication + +#ifdef DEBUG_APPSERVER_THREAD +printf("AppServer: Create App\n"); +#endif + + // Attached data: + // 1) port_id - port to reply to + // 2) port_id - receiver port of a regular app + // 3) char * - signature of the regular app + + // Find the necessary data + port_id reply_port=*((port_id*)index); index+=sizeof(port_id); + port_id app_port=*((port_id*)index); index+=sizeof(port_id); + + char *app_signature=(char *)index; + + // Create the ServerApp subthread for this app + applist_lock->Lock(); + ServerApp *newapp=new ServerApp(app_port,app_signature); + applist->AddItem(newapp); + applist_lock->Unlock(); + + active_lock->Lock(); + p_active_app=newapp; + active_app=applist->CountItems()-1; + + PortLink *replylink=new PortLink(reply_port); + replylink->SetOpCode(SET_SERVER_PORT); + replylink->Attach((int32)newapp->receiver); + replylink->Flush(); + + delete replylink; + + active_lock->Unlock(); + + newapp->Run(); + + break; + } + case DELETE_APP: + { + // Delete a ServerApp. Received only from the respective ServerApp when a + // BApplication asks it to quit. + +#ifdef DEBUG_APPSERVER_THREAD +printf("AppServer: Delete App\n"); +#endif + + // Attached Data: + // 1) thread_id - thread ID of the ServerApp to be deleted + + int32 i, appnum=applist->CountItems(); + ServerApp *srvapp; + thread_id srvapp_id=*((thread_id*)buffer); + + // Run through the list of apps and nuke the proper one + for(i=0;iItemAt(i); + + if(srvapp!=NULL && srvapp->monitor_thread==srvapp_id) + { + applist_lock->Lock(); + srvapp=(ServerApp *)applist->RemoveItem(i); + if(srvapp) + { + delete srvapp; + srvapp=NULL; + } + applist_lock->Unlock(); + active_lock->Lock(); + + if(applist->CountItems()==0) + { + // active==-1 signifies that no other apps are running - NOT good + active_app=-1; + } + else + { + // we actually still have apps running, so make a new one active + if(active_app>0) + active_app--; + else + active_app=0; + } + p_active_app=(active_app>-1)?(ServerApp*)applist->ItemAt(active_app):NULL; + active_lock->Unlock(); + break; // jump out of our for() loop + } + + } + break; + } + case B_QUIT_REQUESTED: + { +#ifdef DEBUG_APPSERVER_THREAD +printf("Shutdown sequence initiated.\n"); +#endif + + // Attached Data: + // none + + // We've been asked to quit, so (for now) broadcast to all + // test apps to quit. This situation will occur only when the server + // is compiled as a regular Be application. + PortLink *applink=new PortLink(0); + ServerApp *srvapp; + + applist_lock->Lock(); + int32 i,appnum=applist->CountItems(); + + applink->SetOpCode(QUIT_APP); + for(i=0;iItemAt(i); + if(srvapp!=NULL) + { + applink->SetPort(srvapp->receiver); + applink->Flush(); + } + } + applist_lock->Unlock(); + + delete applink; + // So when we delete the last ServerApp, we can exit the server + quitting_server=true; + exit_poller=true; + break; + } + default: + //printf("Unexpected message %ld (%lx) in AppServer::DispatchMessage()\n",code,code); + break; + } +} + +bool AppServer::LoadDecorator(BString path) +{ + // Loads a window decorator based on the supplied path and forces a decorator update. + // If it cannot load the specified decorator, it will retain the current one and + // return false. + + create_decorator *pcreatefunc=NULL; + get_decorator_version *pversionfunc=NULL; + status_t stat; + image_id addon; + + addon=load_add_on(path.String()); + + stat=get_image_symbol(addon, "get_decorator_version", B_SYMBOL_TYPE_TEXT, (void**)&pversionfunc); + if(stat!=B_OK) + { + printf("ERROR: Could not get version for Decorator %s\n", path.String()); + unload_add_on(addon); + return false; + } + + // As of now, we do nothing with decorator versions, but the possibility exists + // that the API will change even though I cannot forsee any reason to do so. If + // we *did* do anything with decorator versions, the assignment to a global would + // go here. + + stat=get_image_symbol(addon, "get_decorator_version", B_SYMBOL_TYPE_TEXT, (void**)&pversionfunc); + if(stat!=B_OK) + { + printf("ERROR: Could not get version for Decorator %s\n", path.String()); + unload_add_on(addon); + return false; + } + decor_lock->Lock(); + make_decorator=pcreatefunc; + decorator_id=addon; + decor_lock->Unlock(); + return true; +} + +void AppServer::LoadDefaultDecorator(void) +{ + // This function is called on server startup to provide a fallback decorator in + // case the decorator specified in the config file cannot be loaded. It just + // wouldn't do to have windows with no borders. ;) It also unloads any loaded + // decorator addons. We can specify that we want the default. It is no less + // functional - just internal. + +} + +Decorator *instantiate_decorator(Layer *lay, uint32 dflags, window_look wlook) +{ + Decorator *decor=NULL; + + app_server->decor_lock->Lock(); + if(app_server->make_decorator!=NULL) + decor=app_server->make_decorator(lay, dflags, wlook); + else + decor=new BeDecorator(lay, dflags, wlook); +// decor=new YMakDecorator(lay, dflags, wlook); + + app_server->decor_lock->Unlock(); + return decor; +} + +void AppServer::Poller(void) +{ + // This thread handles nothing but input messages for mouse and keyboard + int32 msgcode; + int8 *msgbuffer=NULL,*index; + ssize_t buffersize,bytesread; + + for(;;) + { + buffersize=port_buffer_size(mouseport); + if(buffersize>0) + msgbuffer=new int8[buffersize]; + bytesread=read_port(mouseport,&msgcode,msgbuffer,buffersize); + + if (bytesread != B_BAD_PORT_ID && bytesread != B_TIMED_OUT && bytesread != B_WOULD_BLOCK) + { + switch(msgcode) + { + // We don't need to do anything with these two, so just pass them + // onto the active application. Eventually, we will pass them onto + // the window which is currently under the cursor. + case B_MOUSE_DOWN: + case B_MOUSE_UP: + { +/* + active_lock->Lock(); + if(active_app>-1 && p_active_app!=NULL) + write_port(p_active_app->receiver, msgcode,msgbuffer,buffersize); + active_lock->Unlock(); +*/ + ServerWindow::HandleMouseEvent(msgcode,msgbuffer); + break; + } + + // Process the cursor and then pass it on + case B_MOUSE_MOVED: + { + // Attached data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - buttons down + + index=msgbuffer; + + // Time sent is not necessary for cursor processing. + index += sizeof(int64); + + float tempx=0,tempy=0; + tempx=*((float*)index); + index+=sizeof(float); + tempy=*((float*)index); + index+=sizeof(float); + + driver->MoveCursorTo(tempx,tempy); + +/* active_lock->Lock(); + if(active_app>-1 && p_active_app!=NULL) + write_port(p_active_app->receiver, msgcode,msgbuffer,buffersize); + active_lock->Unlock(); +*/ + ServerWindow::HandleMouseEvent(msgcode,msgbuffer); + break; + } + default: + //printf("Server::Poller received unexpected code %ld\n",msgcode); + break; + } + + } + + if(buffersize>0) + delete msgbuffer; + + if(exit_poller) + break; + } +} + +int32 AppServer::PollerThread(void *data) +{ +#ifdef DEBUG_APPSERVER_THREAD +printf("Starting Poller thread...\n"); +#endif + AppServer *server=(AppServer *)data; + + // This won't return until it's told to + server->Poller(); + +#ifdef DEBUG_APPSERVER_THREAD +printf("Exiting Poller thread...\n"); +#endif + exit_thread(B_OK); + return B_OK; +} + +void AppServer::Picasso(void) +{ + int32 i; + ServerApp *app; + for(;;) + { + applist_lock->Lock(); + for(i=0;iCountItems(); i++) + { + app=(ServerApp*)applist->ItemAt(i); + ASSERT(app!=NULL); + app->PingTarget(); + } + applist_lock->Unlock(); + + // if poller thread has to exit, so do we - I just was too lazy + // to rename the variable name. ;) + if(exit_poller) + break; + + // we do this every other second so as not to suck *too* many CPU cycles + snooze(2000000); + } +} + +int32 AppServer::PicassoThread(void *data) +{ +#ifdef DEBUG_APPSERVER_THREAD +printf("Starting Picasso thread...\n"); +#endif + AppServer *server=(AppServer *)data; + + // This won't return until it's told to + server->Picasso(); + +#ifdef DEBUG_APPSERVER_THREAD +printf("Exiting Picasso thread...\n"); +#endif + exit_thread(B_OK); + return B_OK; +} + +int main( int argc, char** argv ) +{ + // There can be only one.... + if(find_port(SERVER_PORT_NAME)!=B_NAME_NOT_FOUND) + return -1; + + app_server = new AppServer(); + app_server->Run(); + delete app_server; + return 0; +} diff --git a/src/servers/app/proto5/AppServer.h b/src/servers/app/proto5/AppServer.h new file mode 100644 index 0000000000..d7e352428d --- /dev/null +++ b/src/servers/app/proto5/AppServer.h @@ -0,0 +1,50 @@ +#ifndef _OPENBEOS_APP_SERVER_H_ +#define _OPENBEOS_APP_SERVER_H_ + +#include +#include +#include +#include +#include // for window_look +#include "Decorator.h" + +class Layer; +class BMessage; +class ServerApp; +class DisplayDriver; + +class AppServer : public BApplication +{ +public: + AppServer(void); + ~AppServer(void); + thread_id Run(void); + void MainLoop(void); + port_id messageport,mouseport; + void Poller(void); + void Picasso(void); + +private: + friend Decorator *instantiate_decorator(Layer *lay, uint32 dflags, window_look wlook); + + void DispatchMessage(int32 code, int8 *buffer); + static int32 PollerThread(void *data); + static int32 PicassoThread(void *data); + bool LoadDecorator(BString path); + void LoadDefaultDecorator(void); + + image_id decorator_id; + create_decorator *make_decorator; // global function pointer + bool quitting_server; + BList *applist; + int32 active_app; + ServerApp *p_active_app; + thread_id poller_id, picasso_id; + + BLocker *active_lock, *applist_lock, *decor_lock; + bool exit_poller; + DisplayDriver *driver; +}; + +Decorator *instantiate_decorator(Layer *lay, uint32 dflags, window_look wlook); +#endif \ No newline at end of file diff --git a/src/servers/app/proto5/BUGS b/src/servers/app/proto5/BUGS new file mode 100644 index 0000000000..71d92ac9b4 --- /dev/null +++ b/src/servers/app/proto5/BUGS @@ -0,0 +1,3 @@ +Get a General OS Error followed by a segfault only when an application is started and the server is running under the debugger. + +Cursor display is just a little bit funky (try moving cursor by 1 pixel) when using the ViewDriver diff --git a/src/servers/app/proto5/BeDecorator.cpp b/src/servers/app/proto5/BeDecorator.cpp new file mode 100644 index 0000000000..8cfaacc226 --- /dev/null +++ b/src/servers/app/proto5/BeDecorator.cpp @@ -0,0 +1,359 @@ +#include "Layer.h" +#include "DisplayDriver.h" +#include +#include "BeDecorator.h" + +#define DEBUG_DECOR + +#ifdef DEBUG_DECOR +#include +#endif + +BeDecorator::BeDecorator(Layer *lay, uint32 dflags, window_look wlook) + : Decorator(lay, dflags, wlook) +{ +#ifdef DEBUG_DECOR +printf("BeDecorator()\n"); +#endif + zoomstate=false; + closestate=false; + taboffset=0; + + blue.red=100; + blue.green=100; + blue.blue=255; + + blue2.red=150; + blue2.green=150; + blue2.blue=255; + + black.red=0; + black.green=0; + black.blue=0; + + gray.red=224; + gray.green=224; + gray.blue=224; + + white.red=224; + white.green=224; + white.blue=224; + + yellow.red=255; + yellow.green=203; + yellow.blue=0; + + ltyellow.red=255; + ltyellow.green=236; + ltyellow.blue=33; + + mdyellow.red=255; + mdyellow.green=203; + mdyellow.blue=0; + + dkyellow.red=234; + dkyellow.green=181; + dkyellow.blue=0; + + Resize(lay->frame); +} + +BeDecorator::~BeDecorator(void) +{ +#ifdef DEBUG_DECOR +printf("~BeDecorator()\n"); +#endif +} + +click_type BeDecorator::Clicked(BPoint pt, uint32 buttons) +{ + // the case order is important - we go from smallest to largest + if(closerect.Contains(pt)) + { + +#ifdef DEBUG_DECOR +printf("BeDecorator():Clicked() - Close\n"); +#endif + + return CLICK_CLOSE; + } + + if(zoomrect.Contains(pt)) + { + +#ifdef DEBUG_DECOR +printf("BeDecorator():Clicked() - Zoom\n"); +#endif + + return CLICK_ZOOM; + } + + if(resizerect.Contains(pt)) + { + +#ifdef DEBUG_DECOR +printf("BeDecorator():Clicked() - Resize thumb\n"); +#endif + + return CLICK_RESIZE_RB; + } + + // Clicking in the tab? + if(tabrect.Contains(pt)) + { + // Here's part of our window management stuff + if(buttons==B_PRIMARY_MOUSE_BUTTON && !focused) + return CLICK_MOVETOFRONT; + if(buttons==B_SECONDARY_MOUSE_BUTTON) + return CLICK_MOVETOBACK; + return CLICK_TAB; + } + + // We got this far, so user is clicking on the border? + BRect borderrect(frame); + borderrect.top+=19; + BRect clientrect(borderrect.InsetByCopy(2,2)); + if(borderrect.Contains(pt) && !clientrect.Contains(pt)) + { +#ifdef DEBUG_DECOR +printf("BeDecorator():Clicked() - Drag\n"); +#endif + return CLICK_DRAG; + } + + // Guess user didn't click anything +#ifdef DEBUG_DECOR +printf("BeDecorator():Clicked()\n"); +#endif + return CLICK_NONE; +} + +void BeDecorator::Resize(BRect rect) +{ +#ifdef DEBUG_DECOR +printf("BeDecorator()::Resize()"); rect.PrintToStream(); +#endif + frame=rect; + closerect=frame; + tabrect=frame; + resizerect=frame; + borderrect=frame; + + closerect.left+=2; + closerect.top+=2; + closerect.right=closerect.left+10; + closerect.bottom=closerect.top+10; + + borderrect.top+=19; + + resizerect.top=resizerect.bottom-18; + resizerect.left=resizerect.right-18; + + tabrect.bottom=tabrect.top+18; + tabrect.right=tabrect.left+tabrect.Width()/2; + + zoomrect=tabrect; + zoomrect.top+=2; + zoomrect.right-=2; + zoomrect.bottom-=2; + zoomrect.left=zoomrect.right-10; + zoomrect.bottom=zoomrect.top+10; +} + +void BeDecorator::MoveBy(BPoint pt) +{ + frame.OffsetBy(pt); + closerect.OffsetBy(pt); + tabrect.OffsetBy(pt); + resizerect.OffsetBy(pt); + borderrect.OffsetBy(pt); + zoomrect.OffsetBy(pt); +} + +BRect BeDecorator::GetBorderSize(void) +{ + return bsize; +} + +BPoint BeDecorator::GetMinimumSize(void) +{ + return minsize; +} + +void BeDecorator::SetFlags(uint32 dflags) +{ + flags=dflags; +} + +void BeDecorator::UpdateFont(void) +{ +} + +void BeDecorator::UpdateTitle(const char *string) +{ +} + +void BeDecorator::SetFocus(bool bfocused) +{ + focused=bfocused; +} + +void BeDecorator::SetCloseButton(bool down) +{ + closestate=down; +} + +void BeDecorator::SetZoomButton(bool down) +{ + zoomstate=down; +} + +void BeDecorator::Draw(BRect update) +{ +#ifdef DEBUG_DECOR +printf("BeDecorator()::Draw():"); update.PrintToStream(); +#endif + // We need to draw a few things: the tab, the resize thumb, the borders, + // and the buttons + + DrawTab(); + + // Draw the top view's client area - just a hack :) + driver->FillRect(borderrect,blue); + + DrawFrame(); + +} + +void BeDecorator::DrawZoom(BRect r) +{ + BPoint pt1(r.left+2,r.bottom-2); + BPoint pt2(r.left+(r.Width()/2),r.top+2); + BPoint pt3(r.right-2,r.bottom-2); + if(zoomstate) + { + driver->FillRect(r,ltyellow); + driver->FillRect(r,(uint8*)&B_SOLID_LOW); + driver->FillTriangle(pt1,pt2,pt3,r,(uint8*)&B_SOLID_HIGH); + driver->StrokeLine(pt1,pt2,white); + driver->StrokeRect(r,black); + } + else + { + driver->FillRect(r,ltyellow); + driver->FillRect(r,(uint8*)&B_SOLID_HIGH); + driver->FillTriangle(pt1,pt2,pt3,r,(uint8*)&B_SOLID_LOW); + driver->StrokeLine(pt1,pt2,white); + driver->StrokeRect(r,black); + } +} + +void BeDecorator::DrawClose(BRect r) +{ + float w=r.Width()/2, h=r.Height()/2; + + if(closestate) + { + BPoint pt1(r.LeftTop()); + BPoint pt2(r.left+w,r.top); + BPoint pt3(r.left,r.top+h); + driver->FillTriangle(pt1,pt2,pt3,r,(uint8*)&B_SOLID_HIGH); + + pt1.Set(r.right-w,r.bottom); + pt2.Set(r.right,r.bottom-h); + pt3.Set(r.right,r.bottom); + driver->FillTriangle(pt1,pt2,pt3,r,(uint8*)&B_SOLID_LOW); + + driver->StrokeRect(r,black); + } + else + { + driver->FillRect(r,mdyellow); + + BPoint pt1(r.LeftTop()); + BPoint pt2(r.left+w,r.top); + BPoint pt3(r.left,r.top+h); + driver->FillTriangle(pt1,pt2,pt3,r,(uint8*)&B_SOLID_LOW); + + pt1.Set(r.right-w,r.bottom); + pt2.Set(r.right,r.bottom-h); + pt3.Set(r.right,r.bottom); + driver->FillTriangle(pt1,pt2,pt3,r,(uint8*)&B_SOLID_HIGH); + + driver->StrokeRect(r,black); + } +} + +void BeDecorator::Draw(void) +{ + // Easy way to draw everything - no worries about drawing only certain + // things + + DrawTab(); + + // Draw the top view's client area - just a hack :) + driver->FillRect(borderrect,blue); + + DrawFrame(); +} + +void BeDecorator::DrawTab(void) +{ + if(focused) + driver->FillRect(tabrect,yellow); + else + driver->FillRect(tabrect,gray); + driver->StrokeRect(tabrect,black); +} + +void BeDecorator::DrawFrame(void) +{ + driver->StrokeRect(borderrect,black); + + // Draw the resize thumb if we're supposed to + if(!(flags & B_NOT_RESIZABLE)) + { + driver->FillRect(resizerect,gray); + driver->StrokeRect(resizerect,black); + } + + // Draw the buttons if we're supposed to + if(!(flags & B_NOT_CLOSABLE)) + DrawClose(closerect); + if(!(flags & B_NOT_ZOOMABLE)) + DrawZoom(zoomrect); +} + +void BeDecorator::SetLook(window_look wlook) +{ + look=wlook; +} + +void BeDecorator::CalculateBorders(void) +{ + switch(look) + { + case B_NO_BORDER_WINDOW_LOOK: + { + bsize.Set(0,0,0,0); + break; + } + case B_TITLED_WINDOW_LOOK: + case B_DOCUMENT_WINDOW_LOOK: + case B_BORDERED_WINDOW_LOOK: + { + bsize.top=18; + break; + } + case B_MODAL_WINDOW_LOOK: + case B_FLOATING_WINDOW_LOOK: + { + bsize.top=15; + break; + } + default: + { + break; + } + } +} diff --git a/src/servers/app/proto5/BeDecorator.h b/src/servers/app/proto5/BeDecorator.h new file mode 100644 index 0000000000..70ac8fe528 --- /dev/null +++ b/src/servers/app/proto5/BeDecorator.h @@ -0,0 +1,40 @@ +#ifndef _BEOS_DECORATOR_H_ +#define _BEOS_DECORATOR_H_ + +#include "Decorator.h" + +class BeDecorator: public Decorator +{ +public: + BeDecorator(Layer *lay, uint32 dflags, window_look wlook); + ~BeDecorator(void); + + click_type Clicked(BPoint pt, uint32 buttons); + void Resize(BRect rect); + void MoveBy(BPoint pt); + BRect GetBorderSize(void); + BPoint GetMinimumSize(void); + void SetTitle(const char *newtitle); + void SetFlags(uint32 flags); + void SetLook(window_look wlook); + void UpdateFont(void); + void UpdateTitle(const char *string); + void SetFocus(bool focused); + void SetCloseButton(bool down); + void SetZoomButton(bool down); + void Draw(void); + void Draw(BRect update); + void DrawZoom(BRect r); + void DrawClose(BRect r); + void DrawTab(void); + void DrawFrame(void); + void CalculateBorders(void); + + uint32 taboffset; + rgb_color blue,blue2,black,gray,white,yellow; + rgb_color ltyellow,mdyellow, dkyellow; + BRect zoomrect,closerect,tabrect,frame, + resizerect,borderrect; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto5/DebugTools.cpp b/src/servers/app/proto5/DebugTools.cpp new file mode 100644 index 0000000000..0a0c6aed1d --- /dev/null +++ b/src/servers/app/proto5/DebugTools.cpp @@ -0,0 +1,219 @@ +#include +#include +#include +#include "DebugTools.h" + +void PrintStatusToStream(status_t value) +{ + // Function which simply translates a returned status code into a string + // and dumps it to stdout + BString outstr; + switch(value) + { + case B_OK: + outstr="B_OK "; + break; + case B_NAME_NOT_FOUND: + outstr="B_NAME_NOT_FOUND "; + break; + case B_BAD_VALUE: + outstr="B_BAD_VALUE "; + break; + case B_ERROR: + outstr="B_ERROR "; + break; + case B_TIMED_OUT: + outstr="B_TIMED_OUT "; + break; + case B_NO_MORE_PORTS: + outstr="B_NO_MORE_PORTS "; + break; + case B_WOULD_BLOCK: + outstr="B_WOULD_BLOCK "; + break; + case B_BAD_PORT_ID: + outstr="B_BAD_PORT_ID "; + break; + case B_BAD_TEAM_ID: + outstr="B_BAD_TEAM_ID "; + break; + default: + outstr="undefined status value in debugtools::PrintStatusToStream() "; + break; + } + cout << "Status: " << outstr.String() << endl << flush; + +} + +void PrintColorSpaceToStream(color_space value) +{ + // Dump a color space to cout + BString outstr; + switch(value) + { + case B_RGB32: + outstr="B_RGB32 "; + break; + case B_RGBA32: + outstr="B_RGBA32 "; + break; + case B_RGB32_BIG: + outstr="B_RGB32_BIG "; + break; + case B_RGBA32_BIG: + outstr=" "; + break; + case B_UVL32: + outstr="B_UVL32 "; + break; + case B_UVLA32: + outstr="B_UVLA32 "; + break; + case B_LAB32: + outstr="B_LAB32 "; + break; + case B_LABA32: + outstr="B_LABA32 "; + break; + case B_HSI32: + outstr="B_HSI32 "; + break; + case B_HSIA32: + outstr="B_HSIA32 "; + break; + case B_HSV32: + outstr="B_HSV32 "; + break; + case B_HSVA32: + outstr="B_HSVA32 "; + break; + case B_HLS32: + outstr="B_HLS32 "; + break; + case B_HLSA32: + outstr="B_HLSA32 "; + break; + case B_CMY32: + outstr="B_CMY32"; + break; + case B_CMYA32: + outstr="B_CMYA32 "; + break; + case B_CMYK32: + outstr="B_CMYK32 "; + break; + case B_RGB24_BIG: + outstr="B_RGB24_BIG "; + break; + case B_RGB24: + outstr="B_RGB24 "; + break; + case B_LAB24: + outstr="B_LAB24 "; + break; + case B_UVL24: + outstr="B_UVL24 "; + break; + case B_HSI24: + outstr="B_HSI24 "; + break; + case B_HSV24: + outstr="B_HSV24 "; + break; + case B_HLS24: + outstr="B_HLS24 "; + break; + case B_CMY24: + outstr="B_CMY24 "; + break; + case B_GRAY1: + outstr="B_GRAY1 "; + break; + case B_CMAP8: + outstr="B_CMAP8 "; + break; + case B_GRAY8: + outstr="B_GRAY8 "; + break; + case B_YUV411: + outstr="B_YUV411 "; + break; + case B_YUV420: + outstr="B_YUV420 "; + break; + case B_YCbCr422: + outstr="B_YCbCr422 "; + break; + case B_YCbCr411: + outstr="B_YCbCr411 "; + break; + case B_YCbCr420: + outstr="B_YCbCr420 "; + break; + case B_YUV422: + outstr="B_YUV422 "; + break; + case B_YUV9: + outstr="B_YUV9 "; + break; + case B_YUV12: + outstr="B_YUV12 "; + break; + case B_RGB15: + outstr="B_RGB15 "; + break; + case B_RGBA15: + outstr="B_RGBA15 "; + break; + case B_RGB16: + outstr="B_RGB16 "; + break; + case B_RGB16_BIG: + outstr="B_RGB16_BIG "; + break; + case B_RGB15_BIG: + outstr="B_RGB15_BIG "; + break; + case B_RGBA15_BIG: + outstr="B_RGBA15_BIG "; + break; + case B_YCbCr444: + outstr="B_YCbCr444 "; + break; + case B_YUV444: + outstr="B_YUV444 "; + break; + case B_NO_COLOR_SPACE: + outstr="B_NO_COLOR_SPACE "; + break; + default: + outstr="Undefined color space "; + break; + } + cout << "Color Space: " << outstr.String() << flush; +} + +void TranslateMessageCodeToStream(int32 code) +{ + // Used to translate BMessage message codes back to a character + // format + + cout << "'" + << (char)((code & 0xFF000000) >> 24) + << (char)((code & 0x00FF0000) >> 16) + << (char)((code & 0x0000FF00) >> 8) + << (char)((code & 0x000000FF)) << "' "; +} + +void PrintMessageCode(int32 code) +{ + // Used to translate BMessage message codes back to a character + // format + + printf("Message code %c%c%c%c\n", + (char)((code & 0xFF000000) >> 24), + (char)((code & 0x00FF0000) >> 16), + (char)((code & 0x0000FF00) >> 8), + (char)((code & 0x000000FF)) ); +} + diff --git a/src/servers/app/proto5/DebugTools.h b/src/servers/app/proto5/DebugTools.h new file mode 100644 index 0000000000..2f45b1ac6c --- /dev/null +++ b/src/servers/app/proto5/DebugTools.h @@ -0,0 +1,12 @@ +#ifndef _DEBUGTOOLS_H_ +#define _DEBUGTOOLS_H_ + +#include +#include + +void PrintStatusToStream(status_t value); +void PrintColorSpaceToStream(color_space value); +void TranslateMessageCodeToStream(int32 code); +void PrintMessageCode(int32 code); + +#endif \ No newline at end of file diff --git a/src/servers/app/proto5/Decorator.cpp b/src/servers/app/proto5/Decorator.cpp new file mode 100644 index 0000000000..44349208ee --- /dev/null +++ b/src/servers/app/proto5/Decorator.cpp @@ -0,0 +1,133 @@ +#include "Decorator.h" + +Decorator::Decorator(Layer *lay, uint32 windowflags, window_look wlook) +{ + layer=lay; + flags=windowflags; + minsize.Set(0,0); + bsize.Set(1,1,1,1); + look=wlook; + focused=true; + driver=get_gfxdriver(); +} + +Decorator::~Decorator(void) +{ +} + +Layer* Decorator::GetLayer(void) +{ + return layer; +} + +click_type Decorator::Clicked(BPoint pt, uint32 buttons) +{ + return CLICK_NONE; +} + +void Decorator::Resize(BRect rect) +{ +} + +void Decorator::MoveBy(BPoint pt) +{ +} + +BRect Decorator::GetBorderSize(void) +{ + return BRect(0,0,0,0); +} + +BPoint Decorator::GetMinimumSize(void) +{ + return BPoint(0,0); +} + +void Decorator::SetFlags(uint32 flags) +{ +} + +uint32 Decorator::Flags(void) +{ + return flags; +} + +void Decorator::SetLook(window_look wlook) +{ +} + +uint32 Decorator::Look(void) +{ + return look; +} + +void Decorator::UpdateTitle(const char *string) +{ +} + +void Decorator::UpdateFont(void) +{ +} + +void Decorator::SetFocus(bool focused) +{ +} + +void Decorator::SetCloseButton(bool down) +{ +} + +void Decorator::SetZoomButton(bool down) +{ +} + +void Decorator::SetMinimizeButton(bool down) +{ +} + +bool Decorator::GetCloseButton(void) const +{ + return closestate; +} + +bool Decorator::GetZoomButton(void) const +{ + return zoomstate; +} + +bool Decorator::GetMinimizeButton(void) const +{ + return minstate; +} + +void Decorator::Draw(BRect update) +{ +} + +void Decorator::Draw(void) +{ +} + +void Decorator::DrawTab(void) +{ +} + +void Decorator::DrawFrame(void) +{ +} + +void Decorator::DrawZoom(BRect r) +{ +} + +void Decorator::DrawClose(BRect r) +{ +} + +void Decorator::DrawMinimize(BRect r) +{ +} + +void Decorator::CalculateBorders(void) +{ +} diff --git a/src/servers/app/proto5/Decorator.h b/src/servers/app/proto5/Decorator.h new file mode 100644 index 0000000000..78ed26058d --- /dev/null +++ b/src/servers/app/proto5/Decorator.h @@ -0,0 +1,69 @@ +#ifndef _DECORATOR_H_ +#define _DECORATOR_H_ + +#include +#include +#include +#include "Desktop.h" + +class Layer; +class DisplayDriver; + +typedef enum { CLICK_NONE=0, CLICK_ZOOM, CLICK_CLOSE, CLICK_MINIMIZE, + CLICK_TAB, CLICK_DRAG, CLICK_MOVETOBACK, CLICK_MOVETOFRONT, + + CLICK_RESIZE, CLICK_RESIZE_L, CLICK_RESIZE_T, + CLICK_RESIZE_R, CLICK_RESIZE_B, CLICK_RESIZE_LT, CLICK_RESIZE_RT, + CLICK_RESIZE_LB, CLICK_RESIZE_RB } click_type; + +class Decorator +{ +public: + Decorator(Layer *lay, uint32 windowflags, window_look wlook); + virtual ~Decorator(void); + + Layer* GetLayer(void); + + virtual click_type Clicked(BPoint pt, uint32 buttons); + virtual void Resize(BRect rect); + virtual void MoveBy(BPoint pt); + virtual BRect GetBorderSize(void); + virtual BPoint GetMinimumSize(void); + virtual void SetFlags(uint32 flags); + virtual uint32 Flags(void); + virtual void SetLook(window_look wlook); + virtual uint32 Look(void); + virtual void UpdateTitle(const char *string); + virtual void UpdateFont(void); + virtual void SetFocus(bool focused); + virtual void SetCloseButton(bool down); + virtual void SetZoomButton(bool down); + virtual void SetMinimizeButton(bool down); + bool GetCloseButton(void) const; + bool GetZoomButton(void) const; + bool GetMinimizeButton(void) const; + virtual void Draw(BRect update); + virtual void Draw(void); + virtual void DrawTab(void); + virtual void DrawFrame(void); + virtual void DrawZoom(BRect r); + virtual void DrawClose(BRect r); + virtual void DrawMinimize(BRect r); +protected: + virtual void CalculateBorders(void); + Layer *layer; + uint32 flags; + BPoint minsize; + BRect bsize; + uint32 look; + bool focused; + bool zoomstate, closestate, minstate; + DisplayDriver *driver; +}; + +// C exports to hide the class-related stuff from the rest of the +// server. Written for each decorator, but don't amount to much. +typedef uint16 get_decorator_version(void); +typedef Decorator *create_decorator(Layer *lay, uint32 dflags, window_look wlook); + +#endif diff --git a/src/servers/app/proto5/Desktop.cpp b/src/servers/app/proto5/Desktop.cpp new file mode 100644 index 0000000000..148880ae80 --- /dev/null +++ b/src/servers/app/proto5/Desktop.cpp @@ -0,0 +1,403 @@ +/* + Desktop.cpp: + Code necessary to handle the Desktop, defined as the collection of workspaces. +*/ + +#define DEBUG_WORKSPACES + +#include +#include +#include +#include +#include +#include "ServerWindow.h" +#include "ServerCursor.h" +#include "Layer.h" +#include "DisplayDriver.h" +#include "ViewDriver.h" +#include "SecondDriver.h" +#include "Desktop.h" +#include "WindowBorder.h" + +class ServerWindow; +class ServerBitmap; +class Workspace; + +// Quick hack to make setting rgb_colors much easier to live with +void set_rgb_color(rgb_color *col,uint8 red, uint8 green, uint8 blue, uint8 alpha=255) +{ + col->red=red; + col->green=green; + col->blue=blue; + col->alpha=alpha; +} + +//--------------------GLOBALS------------------------- +uint32 workspace_count, active_workspace; +BList *desktop; +ServerCursor *startup_cursor; +Workspace *pactive_workspace; +color_map system_palette; +DisplayDriver *gfxdriver; +int32 token_count=-1; +BLocker *workspacelock; +BLocker *layerlock; +UpdateNode *upnode; +//---------------------------------------------------- + + +//-------------------INTERNAL CLASS DEFS-------------- +class Workspace +{ +public: + Workspace(void); + Workspace(BPath imagepath); + ~Workspace(); + void SetBGColor(rgb_color col); + rgb_color BGColor(void); + thread_id tid; + + RootLayer *toplayer; + BList focuslist; + rgb_color bgcolor; + screen_info screendata, + olddata; +}; + +DisplayDriver *get_gfxdriver(void) +{ + return gfxdriver; +} + +Workspace::Workspace(void) +{ + workspace_count++; + + // default values + focuslist.MakeEmpty(); + bgcolor.red=51; + bgcolor.green=102; + bgcolor.blue=160; + screendata.mode=B_CMAP8; + screendata.spaces=B_8_BIT_640x480; + screendata.refresh_rate=60.0; + screendata.min_refresh_rate=60.0; + screendata.max_refresh_rate=60.0; + screendata.h_position=(uchar)50; + screendata.v_position=(uchar)50; + screendata.h_size=(uchar)50; + screendata.v_size=(uchar)50; + olddata=screendata; + + // We need one top layer for each workspace times the number of monitors - ick. + // Currently, we only have 1 monitor. *Whew* + char wspace_name[128]; + sprintf(wspace_name,"workspace %ld root",workspace_count); + toplayer=new RootLayer(BRect(0,0,639,439),wspace_name); +} + +Workspace::~Workspace(void) + { + workspace_count--; + toplayer->PruneTree(); +} + +void Workspace::SetBGColor(rgb_color col) +{ + bgcolor=col; + toplayer->SetColor(col); +#ifdef DEBUG_WORKSPACES +printf("Workspace::SetBGColor(%d,%d,%d,%d)\n",bgcolor.red,bgcolor.green, + bgcolor.blue,bgcolor.alpha); +#endif +} + +rgb_color Workspace::BGColor(void) +{ + return bgcolor; +} +//--------------------------------------------------- + + +//-----------------GLOBAL FUNCTION DEFS--------------- + +void init_desktop(int8 workspaces) +{ +#ifdef DEBUG_WORKSPACES +printf("init_desktop(%d)\n",workspaces); +#endif + workspace_count=workspaces; + if(workspace_count==0) + workspace_count++; + + // Instantiate and initialize display driver + gfxdriver=new ViewDriver(); +// gfxdriver=new SecondDriver(); + gfxdriver->Initialize(); + + workspacelock=new BLocker(); + layerlock=new BLocker(); + +#ifdef DEBUG_WORKSPACES +printf("Driver %s\n", (gfxdriver->IsInitialized()==true)?"initialized":"NOT initialized"); +#endif + + desktop=new BList(0); + + // Create the workspaces we're supposed to have + for(int8 i=0; iAddItem(new Workspace()); + } + + // Load workspace preferences here + + // We're going to punch in some hardcoded settings for testing purposes. + // There are 3 workspaces hardcoded in for now, but we'll only use the + // second one. + Workspace *wksp=(Workspace*)desktop->ItemAt(1); + if(wksp!=NULL) // in case I forgot something + { + rgb_color bcol; + set_rgb_color(&bcol,0,200,236); + +// set_rgb_color(&(wksp->bgcolor),0,200,236); + wksp->SetBGColor(bcol); + screen_info *tempsd=&(wksp->screendata); + tempsd->mode=B_CMAP8; + tempsd->spaces=B_8_BIT_800x600; + tempsd->frame.Set(0,0,799,599); + } + else + printf("DW goofed on the workspace index :P\n"); + + // Activate workspace 0 + pactive_workspace=(Workspace *)desktop->ItemAt(0); + gfxdriver->SetScreen(pactive_workspace->screendata.spaces); + + // Clear the screen + set_rgb_color(&(pactive_workspace->toplayer->bgcolor),80,85,152); + gfxdriver->Clear(pactive_workspace->toplayer->bgcolor); + startup_cursor=new ServerCursor(default_cursor); + gfxdriver->SetCursor(startup_cursor); + + pactive_workspace->toplayer->SetVisible(true); +#ifdef DEBUG_WORKSPACES +printf("Desktop initialized\n"); +#endif +} + +void shutdown_desktop(void) +{ + int32 i,count=desktop->CountItems(); + Workspace *w; + for(i=0;iItemAt(i); + if(w!=NULL) + delete w; + } + desktop->MakeEmpty(); + delete desktop; + gfxdriver->Shutdown(); + delete gfxdriver; + delete workspacelock; + delete layerlock; + delete startup_cursor; +} + + +int32 CountWorkspaces(void) +{ +#ifdef DEBUG_WORKSPACES +printf("CountWorkspaces() returned %ld\n",workspace_count); +#endif + return workspace_count; +} + +void SetWorkspaceCount(uint32 count) +{ + if(count<0) + { +#ifdef DEBUG_WORKSPACES +printf("SetWorkspaceCount(value<0) - DOH!\n"); +#endif + return; + } + if(count==workspace_count) + return; + + // Activate last workspace in new set if we're using one to be nuked + if(countItemAt(i)!=NULL) + { + delete (Workspace*)desktop->ItemAt(i); + desktop->RemoveItem(i); + } + } + } + else + { + // count > workspace_count here + + // Once we have default workspace preferences which can be set by the + // user, we'll end up having to initialize newly-added workspaces to that + // data. In the mean time, the defaults in the constructor will do. :) + for(uint32 i=count;iAddItem(new Workspace()); + } + } + + // don't forget to update our global! + workspace_count=desktop->CountItems(); + +#ifdef DEBUG_WORKSPACES +printf("SetWorkspaceCount(%ld)\n",workspace_count); +#endif + +} + +int32 CurrentWorkspace(void) +{ +#ifdef DEBUG_WORKSPACES +printf("CurrentWorkspace() returned %ld\n",active_workspace); +#endif + return active_workspace; +} + +void ActivateWorkspace(uint32 workspace) +{ + // In order to change workspaces, we'll need to make all the necessary + // changes to the screen to fit the new one, such as resolution, + // background color, color depth, refresh rate, etc. + + if(workspace>workspace_count || workspace<0) + return; + + Workspace *proposed=(Workspace *)desktop->ItemAt(workspace); + + if(proposed==NULL) + return; + + // Here's where we update all the screen stuff +// if(pactive_workspace->screendata.spaces != proposed->screendata.spaces) +// { + gfxdriver->SetScreen(proposed->screendata.spaces); + gfxdriver->Clear(proposed->bgcolor); + pactive_workspace->toplayer->SetVisible(false); + proposed->toplayer->SetVisible(true); +// } + // more if != then change code goes here. Currently, a lot of the code which + // uses this stuff is not implemented, so it's kind of moot. However, when we + // use the real graphics HW, it'll become important. + + // actually set our active workspace data to reflect the change in workspaces + pactive_workspace=proposed; + active_workspace=workspace; +#ifdef DEBUG_WORKSPACES +printf("ActivateWorkspace(%ld)\n",active_workspace); +#endif +} + +const color_map *SystemColors(void) +{ + return (const color_map *)&system_palette; +} + +status_t SetScreenSpace(uint32 index, uint32 res, bool stick = true) +{ +#ifdef DEBUG_WORKSPACES +printf("SetScreenSpace(%ld,%lu, %s)\n",index,res,(stick==true)?"true":"false"); +#endif + + if(index>workspace_count-1) + { + printf("SetScreenSpace was passed invalid workspace value %ld\n",index); + return B_ERROR; + } + if(res>0x800000) // the last "normal" screen mode defined in GraphicsDefs.h + { + printf("SetScreenSpace was passed invalid screen value %lu\n",res); + return B_ERROR; + } + + // When we actually use app_server preferences, we'll save the screen mode to + // the preferences so that we use this mode next boot. For now, we treat stick==false + if(stick==true) + { + // save the screen data here + } + if(index==active_workspace) + { + gfxdriver->SetScreen(res); + gfxdriver->Clear(pactive_workspace->bgcolor); + } + else + { + // just set the workspace's data here. right now, do nothing. + } + return B_OK; +} + +int32 GetViewToken(void) +{ + // Used to generate view and layer tokens + return ++token_count; +} + +void AddWindowToDesktop(ServerWindow *win,uint32 workspace) +{ + // Adds the top layer of each window to the root layer in the specified workspace. + // Note that in calling AddChild, a redraw is invoked + if(!win || workspace>workspace_count-1) + return; + + workspacelock->Lock(); + Workspace *w=(Workspace *)desktop->ItemAt(workspace); + if(w) + { + // a check for the B_CURRENT_WORKSPACE or B_ALL_WORKSPACES specifiers will + // go here later + + w->toplayer->AddChild(win->winborder); + } + workspacelock->Unlock(); +} + +void RemoveWindowFromDesktop(ServerWindow *win) +{ + // A little more time-consuming than AddWindow + if(!win) + return; + + workspacelock->Lock(); + + // a check for the B_CURRENT_WORKSPACE or B_ALL_WORKSPACES specifiers will + // go here later + + // If the window belongs on only 1 workspace, calling RemoveSelf is the most + // elegant solution. + win->winborder->RemoveSelf(); + workspacelock->Unlock(); +} + +Layer *GetRootLayer(void) +{ + layerlock->Lock(); + Layer *lay=(workspace_count>0)?pactive_workspace->toplayer:NULL; + layerlock->Unlock(); + + return lay; +} + +// Another "just in case DW screws up again" section +#ifdef DEBUG_WORKSPACES +#undef DEBUG_WORKSPACES +#endif \ No newline at end of file diff --git a/src/servers/app/proto5/Desktop.h b/src/servers/app/proto5/Desktop.h new file mode 100644 index 0000000000..54b5e1bf3f --- /dev/null +++ b/src/servers/app/proto5/Desktop.h @@ -0,0 +1,46 @@ +#ifndef _OBDESKTOP_H_ +#define _OBDESKTOP_H_ + + +#include +#include +#include + +class DisplayDriver; +class ServerWindow; +class Layer; + +void init_desktop(int8 workspaces); +void shutdown_desktop(void); +DisplayDriver *get_gfxdriver(void); + +// Workspace access functions +int32 CountWorkspaces(void); +void SetWorkspaceCount(uint32 count); + +int32 CurrentWorkspace(void); +void ActivateWorkspace(uint32 workspace); + +const color_map *SystemColors(void); +status_t SetScreenSpace(uint32 index, uint32 res, bool stick=true); + +void AddWindowToDesktop(ServerWindow *win,uint32 workspace); +void RemoveWindowFromDesktop(ServerWindow *win); +Layer *GetRootLayer(void); +int32 GetViewToken(void); + +typedef struct +{ + color_space mode; + BRect frame; + uint32 spaces; + float min_refresh_rate; + float max_refresh_rate; + float refresh_rate; + uchar h_position; + uchar v_position; + uchar h_size; + uchar v_size; +} screen_info; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto5/DisplayDriver.cpp b/src/servers/app/proto5/DisplayDriver.cpp new file mode 100644 index 0000000000..a947061984 --- /dev/null +++ b/src/servers/app/proto5/DisplayDriver.cpp @@ -0,0 +1,242 @@ +/* + DisplayDriver.cpp + Modular class to allow the server to not care what the ultimate output is + for graphics calls. +*/ +#include "DisplayDriver.h" +#include "ServerCursor.h" + +DisplayDriver::DisplayDriver(void) +{ + is_initialized=false; + cursor_visible=false; + show_on_move=false; + locker=new BLocker(); + + penpos.Set(0,0); + pensize=0.0; + + // initialize to BView defaults + highcol.red=0; + highcol.green=0; + highcol.blue=0; + highcol.alpha=0; + lowcol.red=255; + lowcol.green=255; + lowcol.blue=255; + lowcol.alpha=255; +} + +DisplayDriver::~DisplayDriver(void) +{ + delete locker; +} + +void DisplayDriver::Initialize(void) +{ // Loading loop to find proper driver or other setup for the driver +} + +bool DisplayDriver::IsInitialized(void) +{ // Let us know whether things worked out ok + return is_initialized; +} + +void DisplayDriver::Shutdown(void) +{ // For use by subclasses +} + +void DisplayDriver::SafeMode(void) +{ // Set video mode to 640x480x256 mode +} + +void DisplayDriver::Reset(void) +{ // Intended to reload and restart driver. Defaults to a safe mode +} + +void DisplayDriver::Clear(uint8 red,uint8 green,uint8 blue) +{ +} + +void DisplayDriver::Clear(rgb_color col) +{ +} + +void DisplayDriver::SetScreen(uint32 space) +{ // Set the screen to a particular mode +} + +int32 DisplayDriver::GetHeight(void) +{ // Gets the height of the current mode + return ginfo->height; +} + +int32 DisplayDriver::GetWidth(void) +{ // Gets the width of the current mode + return ginfo->width; +} + +int DisplayDriver::GetDepth(void) +{ // Gets the color depth of the current mode + return ginfo->bytes_per_row; +} + +void DisplayDriver::Blit(BRect src, BRect dest) +{ // Screen-to-screen bitmap copying +} + +void DisplayDriver::DrawBitmap(ServerBitmap *bitmap) +{ +} + +void DisplayDriver::DrawChar(char c, BPoint point) +{ +} + +void DisplayDriver::DrawString(char *string, int length, BPoint point) +{ +} + +void DisplayDriver::FillArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern) +{ +} + +void DisplayDriver::FillBezier(BPoint *points, uint8 *pattern) +{ +} + +void DisplayDriver::FillEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern) +{ +} + +void DisplayDriver::FillPolygon(int *x, int *y, int numpoints, bool is_closed) +{ +} + +void DisplayDriver::FillRect(BRect rect, uint8 *pattern) +{ +} + +void DisplayDriver::FillRect(BRect rect, rgb_color col) +{ +} + +void DisplayDriver::FillRegion(BRegion *region) +{ +} + +void DisplayDriver::FillRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern) +{ +} + +void DisplayDriver::FillShape(BShape *shape) +{ +} + +void DisplayDriver::FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern) +{ +} + +void DisplayDriver::HideCursor(void) +{ +} + +bool DisplayDriver::IsCursorHidden(void) +{ + return false; +} + +void DisplayDriver::ObscureCursor(void) +{ // Hides cursor until mouse is moved +} + +void DisplayDriver::MoveCursorTo(float x, float y) +{ +} + +void DisplayDriver::MovePenTo(BPoint pt) +{ // Moves the graphics pen to this position +} + +BPoint DisplayDriver::PenPosition(void) +{ + return penpos; +} + +float DisplayDriver::PenSize(void) +{ + return pensize; +} + +void DisplayDriver::SetCursor(ServerCursor *cursor) +{ +} + +void DisplayDriver::SetCursor(int32 value) +{ // This is used just to provide an easy way of setting one of the default cursors + // Then again, I may just get rid of this thing. +} + +void DisplayDriver::SetHighColor(uint8 r,uint8 g,uint8 b,uint8 a=255) +{ +} + +void DisplayDriver::SetLowColor(uint8 r,uint8 g,uint8 b,uint8 a=255) +{ +} + +void DisplayDriver::SetPenSize(float size) +{ +} + +void DisplayDriver::SetPixel(int x, int y, uint8 *pattern) +{ // Internal function utilized by other functions to draw to the buffer + // Will eventually be an inline function +} + +void DisplayDriver::ShowCursor(void) +{ +} + +void DisplayDriver::StrokeArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern) +{ +} + +void DisplayDriver::StrokeBezier(BPoint *points, uint8 *pattern) +{ +} + +void DisplayDriver::StrokeEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern) +{ +} + +void DisplayDriver::StrokeLine(BPoint point, uint8 *pattern) +{ +} + +void DisplayDriver::StrokeLine(BPoint pt1, BPoint pt2, rgb_color col) +{ +} + +void DisplayDriver::StrokePolygon(int *x, int *y, int numpoints, bool is_closed) +{ +} + +void DisplayDriver::StrokeRect(BRect rect, uint8 *pattern) +{ +} + +void DisplayDriver::StrokeRect(BRect rect, rgb_color col) +{ +} + +void DisplayDriver::StrokeRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern) +{ +} + +void DisplayDriver::StrokeShape(BShape *shape) +{ +} + +void DisplayDriver::StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern) +{ +} diff --git a/src/servers/app/proto5/DisplayDriver.h b/src/servers/app/proto5/DisplayDriver.h new file mode 100644 index 0000000000..77a6e707b9 --- /dev/null +++ b/src/servers/app/proto5/DisplayDriver.h @@ -0,0 +1,127 @@ +#ifndef _GFX_DRIVER_H_ +#define _GFX_DRIVER_H_ + +#include +#include +#include +#include "Desktop.h" + +class ServerBitmap; +class ServerCursor; + +#ifndef ROUND + #define ROUND(a) ( (a-long(a))>=.5)?(long(a)+1):(long(a)) +#endif + +typedef struct +{ + uchar *xormask, *andmask; + int32 width, height; + int32 hotx, hoty; + +} cursor_data; + +#ifndef HOOK_DEFINE_CURSOR + +#define HOOK_DEFINE_CURSOR 0 +#define HOOK_MOVE_CURSOR 1 +#define HOOK_SHOW_CURSOR 2 +#define HOOK_DRAW_LINE_8BIT 3 +#define HOOK_DRAW_LINE_16BIT 12 +#define HOOK_DRAW_LINE_32BIT 4 +#define HOOK_DRAW_RECT_8BIT 5 +#define HOOK_DRAW_RECT_16BIT 13 +#define HOOK_DRAW_RECT_32BIT 6 +#define HOOK_BLIT 7 +#define HOOK_DRAW_ARRAY_8BIT 8 +#define HOOK_DRAW_ARRAY_16BIT 14 // Not implemented in current R5 drivers +#define HOOK_DRAW_ARRAY_32BIT 9 +#define HOOK_SYNC 10 +#define HOOK_INVERT_RECT 11 + +#endif + +class ServerCursor; + +class DisplayDriver +{ +public: + DisplayDriver(void); + virtual ~DisplayDriver(void); + + virtual void Initialize(void); // Sets the driver + virtual bool IsInitialized(void); + virtual void Shutdown(void); // You never know when you'll need this + + virtual void SafeMode(void); // Easy-access functions for common tasks + virtual void Reset(void); + virtual void Clear(uint8 red,uint8 green,uint8 blue); + virtual void Clear(rgb_color col); + + // Settings functions + virtual void SetScreen(uint32 space); + virtual int32 GetHeight(void); + virtual int32 GetWidth(void); + virtual int GetDepth(void); + + // Drawing functions + virtual void Blit(BRect src, BRect dest); + virtual void DrawBitmap(ServerBitmap *bitmap); + virtual void DrawChar(char c, BPoint point); + virtual void DrawString(char *string, int length, BPoint point); + + virtual void FillArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern); + virtual void FillBezier(BPoint *points, uint8 *pattern); + virtual void FillEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern); + virtual void FillPolygon(int *x, int *y, int numpoints, bool is_closed); + virtual void FillRect(BRect rect, uint8 *pattern); + virtual void FillRect(BRect rect, rgb_color col); + virtual void FillRegion(BRegion *region); + virtual void FillRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern); + virtual void FillShape(BShape *shape); + virtual void FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern); + +// virtual void GetBlendingMode(source_alpha *srcmode, alpha_function *funcmode); +// virtual drawing_mode GetDrawingMode(void); + virtual void HideCursor(void); + virtual bool IsCursorHidden(void); + virtual void MoveCursorTo(float x, float y); + virtual void MovePenTo(BPoint pt); + virtual void ObscureCursor(void); + virtual BPoint PenPosition(void); + virtual float PenSize(void); +// virtual void SetBlendingMode(source_alpha srcmode, alpha_function funcmode); + virtual void SetCursor(int32 value); + virtual void SetCursor(ServerCursor *cursor); +// virtual void SetDrawingMode(drawing_mode mode); + virtual void ShowCursor(void); + virtual void SetHighColor(uint8 r,uint8 g,uint8 b,uint8 a=255); + virtual void SetLowColor(uint8 r,uint8 g,uint8 b,uint8 a=255); + virtual void SetPenSize(float size); + virtual void SetPixel(int x, int y, uint8 *pattern); + + virtual void StrokeArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern); + virtual void StrokeBezier(BPoint *points, uint8 *pattern); + virtual void StrokeEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern); + virtual void StrokeLine(BPoint point, uint8 *pattern); + virtual void StrokeLine(BPoint pt1, BPoint pt2, rgb_color col); + virtual void StrokePolygon(int *x, int *y, int numpoints, bool is_closed); + virtual void StrokeRect(BRect rect,uint8 *pattern); + virtual void StrokeRect(BRect rect, rgb_color col); + virtual void StrokeRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern); + virtual void StrokeShape(BShape *shape); + virtual void StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern); + + graphics_card_hook ghooks[48]; + graphics_card_info *ginfo; + +protected: + bool is_initialized, cursor_visible, show_on_move; + ServerCursor *current_cursor; + BLocker *locker; + rgb_color highcol, lowcol; + BPoint penpos; + float pensize; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto5/Globals.h b/src/servers/app/proto5/Globals.h new file mode 100644 index 0000000000..2753cad1aa --- /dev/null +++ b/src/servers/app/proto5/Globals.h @@ -0,0 +1,7 @@ +#ifndef _SERVER_GLOBALS_H_ +#define _SERVER_GLOBALS_H_ + +#include +BList *gBitmaplist, *gLayerlist; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto5/Layer.cpp b/src/servers/app/proto5/Layer.cpp new file mode 100644 index 0000000000..530966ddb4 --- /dev/null +++ b/src/servers/app/proto5/Layer.cpp @@ -0,0 +1,735 @@ +/* + Layer.cpp + Class used for rendering to the frame buffer. One layer per view on screen and + also for window decorators +*/ +#include "Layer.h" +#include "ServerWindow.h" +#include "Desktop.h" +#include "PortLink.h" +#include "DisplayDriver.h" +#include +#include +#include +#include +#include + +#define DEBUG_LAYERS + +Layer::Layer(BRect rect, const char *layername, ServerWindow *srvwin, + int32 viewflags, int32 token) +{ + if(rect.IsValid()) + // frame is in parent layer's coordinates + frame=rect; + else + { +#ifdef DEBUG_LAYERS +printf("Invalid BRect: "); rect.PrintToStream(); +#endif + frame.Set(0,0,1,1); + } + + name=new BString(layername); + + // Layer does not start out as a part of the tree + parent=NULL; + uppersibling=NULL; + lowersibling=NULL; + topchild=NULL; + bottomchild=NULL; + + visible=new BRegion(Bounds()); + invalid=NULL; + + serverwin=srvwin; + + view_token=token; + + flags=viewflags; + + hidecount=0; + is_dirty=false; + is_updating=false; + + // Because this is not part of the tree, level is negative (thus, irrelevant) + level=0; +#ifdef DEBUG_LAYERS + PrintToStream(); +#endif +} + +Layer::Layer(BRect rect, const char *layername) +{ + // This constructor is used for the top layer in each workspace + if(rect.IsValid()) + frame=rect; + else + frame.Set(0,0,1,1); + + name=new BString(layername); + + // Layer is the root for the workspace + parent=NULL; + uppersibling=NULL; + lowersibling=NULL; + topchild=NULL; + bottomchild=NULL; + + visible=new BRegion(Bounds()); + invalid=NULL; + + serverwin=NULL; + flags=0; + hidecount=0; + is_dirty=false; + + level=0; + + view_token=-1; +#ifdef DEBUG_LAYERS + PrintToStream(); +#endif +} + +Layer::~Layer(void) +{ +#ifdef DEBUG_LAYERS + cout << "Layer Destructor for " << name->String() << endl << flush; +#endif + if(visible!=NULL) + delete visible; + if(invalid!=NULL) + delete invalid; + delete name; +} + +void Layer::AddChild(Layer *layer) +{ + // Adds a layer to the top of the layer's children +#ifdef DEBUG_LAYERS +printf("AddChild %s\n",layer->name->String()); +#endif + + if(layer->parent!=NULL) + { + printf("ERROR: AddChild(): View already has a parent\n"); + return; + } + layer->parent=this; + if(layer->visible && layer->hidecount==0 && visible) + { + // Technically, we could safely take the address of ConvertToParent(BRegion) + // but we don't just to avoid a compiler nag + + BRegion *reg=new BRegion(layer->ConvertToParent(layer->visible)); + visible->Exclude(reg); + delete reg; + } + + if(topchild!=NULL) + { + layer->lowersibling=topchild; + topchild->uppersibling=layer; + if(layer->frame.Intersects(layer->lowersibling->frame)) + { + if(layer->lowersibling->visible && layer->lowersibling->hidecount==0) + { + BRegion *reg=new BRegion(ConvertToParent(layer->visible)); + BRegion *reg2=new BRegion(layer->lowersibling->ConvertFromParent(reg)); + delete reg; + layer->lowersibling->visible->Exclude(reg2); + delete reg2; + } + } + } + else + bottomchild=layer; + topchild=layer; + layer->level=level+1; +} + +void Layer::RemoveChild(Layer *layer) +{ + // Remove a layer from the tree +#ifdef DEBUG_LAYERS + cout << "RemoveChild " << layer->name->String() << endl << flush; +#endif + + if(layer->parent==NULL) + { + cout << "ERROR: RemoveChild(): View doesn't have a parent\n" << flush; + return; + } + if(layer->parent!=this) + { + cout << "ERROR: RemoveChild(): View is not a child of this layer\n" << flush; + return; + } + + if(hidecount==0 && layer->visible && layer->parent->visible) + { + BRegion *reg=new BRegion(ConvertToParent(visible)); + layer->parent->visible->Include(reg); + delete reg; + } + + // Take care of parent + layer->parent=NULL; + if(topchild==layer) + topchild=layer->lowersibling; + if(bottomchild==layer) + bottomchild=layer->uppersibling; + + // Take care of siblings + if(layer->uppersibling!=NULL) + layer->uppersibling->lowersibling=layer->lowersibling; + if(layer->lowersibling!=NULL) + layer->lowersibling->lowersibling=layer->uppersibling; + layer->SetLevel(0); + layer->uppersibling=NULL; + layer->lowersibling=NULL; +} + +void Layer::RemoveSelf(void) +{ + // A Layer removes itself from the tree (duh) +#ifdef DEBUG_LAYERS + cout << "RemoveChild " << name->String() << endl; +#endif + if(parent==NULL) + { + cout << "ERROR: RemoveSelf(): View doesn't have a parent\n" << flush; + return; + } + parent->RemoveChild(this); +} + +Layer *Layer::GetChildAt(BPoint pt, bool recursive=false) +{ + // Find out which child gets hit if we click at a certain spot. Returns NULL + // if there are no visible children or if the click does not hit a child layer + // If recursive==true, then it will continue to call until it reaches a layer + // which has no children, i.e. a layer that is at the top of its 'branch' in + // the layer tree + + Layer *child; + if(recursive) + { + for(child=topchild; child!=NULL; child=child->lowersibling) + { + if(child->topchild!=NULL) + child->GetChildAt(pt,true); + + if(child->hidecount>0) + continue; + + if(child->frame.Contains(pt)) + return child; + } + } + else + { + for(child=topchild; child!=NULL; child=child->lowersibling) + { + if(child->hidecount>0) + continue; + + if(child->frame.Contains(pt)) + return child; + } + } + return NULL; +} + +BRect Layer::Bounds(void) +{ + return frame.OffsetToCopy(0,0); +} + +BRect Layer::Frame(void) +{ + return frame; +} + +void Layer::SetLevel(int32 value) +{ + // Sets hierarchy level of layer and all children +#ifdef DEBUG_LAYERS + printf("SetLevel %ld\n",value); +#endif + level=value; + + Layer *lay; + + lay=topchild; + + while(lay!=NULL) + { + if(lay->topchild!=NULL) + lay->topchild->SetLevel(value+1); + lay=lay->lowersibling; + } +} + +void Layer::PruneTree(void) +{ + // recursively deletes all children (and grandchildren, etc) of the passed layer + // This is mostly used for server shutdown or deleting a workspace +#ifdef DEBUG_LAYERS + printf("PruneTree() at level %ld\n", level); +#endif + Layer *lay,*nextlay; + + lay=topchild; + + while(lay!=NULL) + { + if(lay->topchild!=NULL) + lay->topchild->PruneTree(); + nextlay=lay->lowersibling; + delete lay; + lay=nextlay; + } + // Man, this thing is short. Elegant, ain't it? :P +} + +Layer *Layer::FindLayer(int32 token) +{ + // recursive search for a layer based on its view token + Layer *lay, *trylay; + + // Search child layers first + for(lay=topchild; lay!=NULL; lay=lay->lowersibling) + { + if(lay->view_token==token) + return lay; + } + + // Hmmm... not in this layer's children. Try lower descendants + for(lay=topchild; lay!=NULL; lay=lay->lowersibling) + { + trylay=lay->FindLayer(token); + if(trylay) + return trylay; + } + + // Well, we got this far in the function, so apparently there is no match to be found + return NULL; +} + +// Tested +void Layer::Invalidate(BRegion region) +{ + int32 i; + BRect r; + + // See if the region intersects with our current area + if(region.Intersects(Bounds()) && hidecount==0) + { + BRegion clippedreg(region); + clippedreg.IntersectWith(visible); + if(clippedreg.CountRects()>0) + { + is_dirty=true; + if(invalid) + invalid->Include(&clippedreg); + else + invalid=new BRegion(clippedreg); + } + } + + BRegion *reg; + for(Layer *lay=topchild;lay!=NULL; lay=lay->lowersibling) + { + if(lay->hidecount==0) + { + reg=new BRegion(lay->ConvertFromParent(®ion)); + + for(i=0;iCountRects();i++) + { + r=reg->RectAt(i); + if(frame.Intersects(r)) + lay->Invalidate(r); + } + + delete reg; + } + } +} + +// Tested +void Layer::Invalidate(BRect rect) +{ + // Make our own section dirty and pass it on to any children, if necessary.... + // YES, WE ARE SHARING DIRT! Mudpies anyone? :D + + if(Bounds().Intersects(rect)) + { + + // Clip the rectangle to the visible region of the layer + if(visible->Intersects(rect)) + { + BRegion reg(rect); + reg.IntersectWith(visible); + if(reg.CountRects()>0) + { + is_dirty=true; + if(invalid) + invalid->Include(®); + else + invalid=new BRegion(reg); + } + } + } + for(Layer *lay=topchild;lay!=NULL; lay=lay->lowersibling) + lay->Invalidate(lay->ConvertFromParent(rect)); +} + +void Layer::RequestDraw(void) +{ +/* if(visible==NULL || hidecount>0) + return; + + if(serverwin) + { + if(invalid==NULL) + invalid=new BRegion(*visible); + serverwin->RequestDraw(invalid->Frame()); + delete invalid; + invalid=NULL; + } + + is_dirty=false; + for(Layer *lay=topchild; lay!=NULL; lay=lay->lowersibling) + { + if(lay->IsDirty()) + lay->RequestDraw(); + } +*/ +} + +bool Layer::IsDirty(void) const +{ + return is_dirty; +} + +void Layer::ShowLayer(void) +{ + if(hidecount==0) + return; + + hidecount--; + if(hidecount==0) + { + BRegion *reg=new BRegion(ConvertToParent(visible)); + parent->visible->Exclude(reg); + delete reg; + is_dirty=true; + } + + Layer *child; + for(child=topchild; child!=NULL; child=child->lowersibling) + child->ShowLayer(); +} + +void Layer::HideLayer(void) +{ + if(hidecount==0) + { + BRegion *reg=new BRegion(ConvertToParent(visible)); + parent->visible->Include(reg); + delete reg; + parent->is_dirty=true; + is_dirty=true; + } + hidecount++; + + Layer *child; + for(child=topchild; child!=NULL; child=child->lowersibling) + child->HideLayer(); +} + +// Tested +uint32 Layer::CountChildren(void) +{ + uint32 i=0; + Layer *lay=topchild; + while(lay!=NULL) + { + lay=lay->lowersibling; + i++; + } + return i; +} + +void Layer::MoveBy(float x, float y) +{ + BRect oldframe(frame); + frame.OffsetBy(x,y); + + if(parent) + { + if(parent->invalid==NULL) + parent->invalid=new BRegion(oldframe); + else + parent->invalid->Include(oldframe); + } + +// for(Layer *lay=topchild; lay!=NULL; lay=lay->lowersibling) +// lay->MoveBy(x,y); + Invalidate(Bounds()); +} + +void Layer::PrintToStream(void) +{ + printf("-----------\nLayer %s\n",name->String()); + if(parent) + printf("Parent: %s (%p)\n",parent->name->String(), parent); + else + printf("Parent: NULL\n"); + if(uppersibling) + printf("Upper sibling: %s (%p)\n",uppersibling->name->String(), uppersibling); + else + printf("Upper sibling: NULL\n"); + if(lowersibling) + printf("Lower sibling: %s (%p)\n",lowersibling->name->String(), lowersibling); + else + printf("Lower sibling: NULL\n"); + if(topchild) + printf("Top child: %s (%p)\n",topchild->name->String(), topchild); + else + printf("Top child: NULL\n"); + if(bottomchild) + printf("Bottom child: %s (%p)\n",bottomchild->name->String(), bottomchild); + else + printf("Bottom child: NULL\n"); + printf("Frame: "); frame.PrintToStream(); + printf("Token: %ld\nLevel: %ld\n",view_token, level); + printf("Hide count: %u\n",hidecount); + if(invalid) + { + printf("Invalid Areas: "); invalid->PrintToStream(); + } + else + printf("Invalid Areas: NULL\n"); + if(visible) + { + printf("Visible Areas: "); visible->PrintToStream(); + } + else + printf("Visible Areas: NULL\n"); + printf("Is updating = %s\n",(is_updating)?"yes":"no"); +} + +// Tested +BRect Layer::ConvertToParent(BRect rect) +{ + return (rect.OffsetByCopy(frame.LeftTop())); +} + +// Tested +BPoint Layer::ConvertToParent(BPoint point) +{ + float x=point.x + frame.left, + y=point.y+frame.top; + return (BPoint(x,y)); +} + +// Tested +BRegion Layer::ConvertToParent(BRegion *reg) +{ + BRegion newreg; + for(int32 i=0; iCountRects();i++) + newreg.Include(ConvertToParent(reg->RectAt(i))); + return BRegion(newreg); +} + +// Tested +BRect Layer::ConvertFromParent(BRect rect) +{ + return (rect.OffsetByCopy(frame.left*-1,frame.top*-1)); +} + +// Tested +BPoint Layer::ConvertFromParent(BPoint point) +{ + return ( point-frame.LeftTop()); +} + +// Tested +BRegion Layer::ConvertFromParent(BRegion *reg) +{ + BRegion newreg; + for(int32 i=0; iCountRects();i++) + newreg.Include(ConvertFromParent(reg->RectAt(i))); + return BRegion(newreg); +} + +// Tested +BRegion Layer::ConvertToTop(BRegion *reg) +{ + BRegion newreg; + for(int32 i=0; iCountRects();i++) + newreg.Include(ConvertToTop(reg->RectAt(i))); + return BRegion(newreg); +} + +// Tested +BRect Layer::ConvertToTop(BRect rect) +{ + if (parent!=NULL) + return(parent->ConvertToTop(rect.OffsetByCopy(frame.LeftTop())) ); + else + return(rect); +} + +// Tested +BPoint Layer::ConvertToTop(BPoint point) +{ + if (parent!=NULL) + return(parent->ConvertToTop(point + frame.LeftTop()) ); + else + return(point); +} + +// Tested +BRegion Layer::ConvertFromTop(BRegion *reg) +{ + BRegion newreg; + for(int32 i=0; iCountRects();i++) + newreg.Include(ConvertFromTop(reg->RectAt(i))); + return BRegion(newreg); +} + +// Tested +BRect Layer::ConvertFromTop(BRect rect) +{ + if (parent!=NULL) + return(parent->ConvertFromTop(rect.OffsetByCopy(frame.LeftTop().x*-1, + frame.LeftTop().y*-1)) ); + else + return(rect); +} + +// Tested +BPoint Layer::ConvertFromTop(BPoint point) +{ + if (parent!=NULL) + return(parent->ConvertFromTop(point - frame.LeftTop()) ); + else + return(point); +} + +RootLayer::RootLayer(BRect rect, const char *layername, ServerWindow *srvwin, + int32 viewflags, int32 token) + : Layer(rect,layername,srvwin,viewflags,token) +{ + updater_id=-1; +} + +RootLayer::RootLayer(BRect rect, const char *layername) + : Layer(rect,layername) +{ + updater_id=-1; + driver=get_gfxdriver(); +} + +RootLayer::~RootLayer(void) +{ +} + +void RootLayer::SetVisible(bool is_visible) +{ + if(visible!=is_visible) + { + visible=is_visible; +/* if(visible) + { + updater_id=spawn_thread(UpdaterThread,name->String(),B_NORMAL_PRIORITY,this); + if(updater_id!=B_NO_MORE_THREADS && updater_id!=B_NO_MEMORY) + resume_thread(updater_id); + } +*/ + } +} + +bool RootLayer::IsVisible(void) const +{ + return visible; +} + +int32 RootLayer::UpdaterThread(void *data) +{ + // Updater thread which checks to see if its layer needs updating. If so, then + // call the recursive function RequestDraw. + + RootLayer *root=(RootLayer*)data; + + while(1) + { + if(!root->visible) + { + return 0; + exit_thread(1); + } + + if(root->IsDirty()) + { + layerlock->Lock(); + root->RequestDraw(); + layerlock->Unlock(); + } + } +} + +void RootLayer::RequestDraw(void) +{ + if(!invalid) + return; + + ASSERT(driver!=NULL); + +#ifdef DEBUG_LAYERS +printf("Root::RequestDraw: invalid rects: %ld\n",invalid->CountRects()); +#endif + + for(int32 i=0; invalid->CountRects();i++) + { + if(invalid->RectAt(i).IsValid()) + { +#ifdef DEBUG_LAYERS +printf("Root::RequestDraw:FillRect, color %u,%u,%u,%u\n",bgcolor.red,bgcolor.green, + bgcolor.blue,bgcolor.alpha); +#endif + driver->FillRect(invalid->RectAt(i),bgcolor); + } + else + break; + } + + delete invalid; + invalid=NULL; + is_dirty=false; + +/* for(Layer *lay=topchild; lay!=NULL; lay=lay->lowersibling) + { + if(lay->IsDirty()) + lay->RequestDraw(); + } +*/ +} + +void RootLayer::SetColor(rgb_color col) +{ + bgcolor=col; +#ifdef DEBUG_LAYERS +printf("Root::SetColor(%u,%u,%u,%u)\n",bgcolor.red,bgcolor.green, + bgcolor.blue,bgcolor.alpha); +#endif +} + +rgb_color RootLayer::GetColor(void) const +{ + return bgcolor; +} diff --git a/src/servers/app/proto5/Layer.h b/src/servers/app/proto5/Layer.h new file mode 100644 index 0000000000..1fbcbc1ce4 --- /dev/null +++ b/src/servers/app/proto5/Layer.h @@ -0,0 +1,108 @@ +#ifndef _LAYER_H_ +#define _LAYER_H_ + +#include +#include +#include +#include +#include +#include + +class ServerWindow; +class UpdateNode; +class DisplayDriver; + +class Layer +{ +public: + Layer(BRect rect, const char *layername, ServerWindow *srvwin, + int32 viewflags, int32 token); + Layer(BRect rect, const char *layername); + virtual ~Layer(void); + + void ShowLayer(void); + void HideLayer(void); + Layer *FindLayer(int32 token); + void MoveLayer(BPoint delta, bool include_children=true); + void AddChild(Layer *child); + void RemoveChild(Layer *child); + void RemoveSelf(void); + uint32 CountChildren(void); + Layer *GetChildAt(BPoint pt, bool recursive=false); + BRect Bounds(void); + BRect Frame(void); + + void MoveBy(float x, float y); + void ResizeBy(float x, float y); + + void RebuildRegions(bool include_children=true); + bool IsDirty(void) const; + void PrintToStream(void); + void PruneTree(void); + void SetLevel(int32 value); + void Invalidate(BRect rect); + void Invalidate(BRegion region); + virtual void RequestDraw(void); + + BRect ConvertToParent(BRect rect); + BPoint ConvertToParent(BPoint point); + BRegion ConvertToParent(BRegion *reg); + BRect ConvertFromParent(BRect rect); + BPoint ConvertFromParent(BPoint point); + BRegion ConvertFromParent(BRegion *reg); + BRegion ConvertToTop(BRegion *reg); + BRect ConvertToTop(BRect rect); + BPoint ConvertToTop(BPoint point); + BRegion ConvertFromTop(BRegion *reg); + BRect ConvertFromTop(BRect rect); + BPoint ConvertFromTop(BPoint point); + + BRect frame; + + Layer *parent, + *uppersibling, + *lowersibling, + *topchild, + *bottomchild; + + BRegion *visible, + *invalid; + + ServerWindow *serverwin; + + BString *name; + int32 view_token; // identifier for the corresponding view + int32 level; // how far layer is from root + int32 flags; // view flags + uint8 hidecount; + bool is_dirty; // true if we need to redraw + bool is_updating; +}; + +class RootLayer : public Layer +{ +public: + RootLayer(BRect rect, const char *layername, ServerWindow *srvwin, + int32 viewflags, int32 token); + RootLayer(BRect rect, const char *layername); + ~RootLayer(void); + virtual void RequestDraw(void); + void SetVisible(bool is_visible); + bool IsVisible(void) const; + + void SetColor(rgb_color col); + rgb_color GetColor(void) const; + + static int32 UpdaterThread(void *data); + rgb_color bgcolor; +private: + thread_id updater_id; + bool visible; + DisplayDriver *driver; +}; + +extern BLocker *layerlock; +extern BList *layerlist; +extern Layer *rootlayer; +extern UpdateNode *updatenode; +#endif \ No newline at end of file diff --git a/src/servers/app/proto5/PortLink.cpp b/src/servers/app/proto5/PortLink.cpp new file mode 100644 index 0000000000..8fba724569 --- /dev/null +++ b/src/servers/app/proto5/PortLink.cpp @@ -0,0 +1,438 @@ +/* + PortLink.cpp: + A helper class for port-based messaging + +------------------------------------------------------------------------ +How it works: + The class utilizes a fixed-size array of PortLinkData object pointers. When +data is attached, a new PortLinkData object is allocated and a copy of the +passed data is created inside it. When the time comes for the message to be sent, +the data is pieced together into a flattened array and written to the port. +------------------------------------------------------------------------ +Data members: + +*attachments[] - fixed-size array of pointers used to hold the attached data +opcode - message value which is sent along with any data +target - port to which the message is sent when Flush() is called +replyport - port used with synchronous messaging - FlushWithReply() +bufferlength - total bytes taken up by attachments +num_attachments - internal variable which is used to track which "slot" + will be the next one to receive an attachment object +*/ + +#include "PortLink.h" +#include +#include +#include + +//#define PLDEBUG + +// Internal data storage class for holding attached data whilst it is waiting +// to be Flattened() and then Flushed(). There is no need for this to be called outside +// the PortLink class. +class PortLinkData +{ +public: + PortLinkData(void); + ~PortLinkData(void); + bool Set(void *data, size_t size); + char *buffer; + size_t buffersize; +}; + +PortLink::PortLink(port_id port) +{ + // For this class to be useful (and to prevent a lot of init problems) + // we require a port in the constructor + target=port; + + // We start out without any data attached to the port message + num_attachments=0; + opcode=0; + bufferlength=0; + replyport=create_port(30,"PortLink reply port"); +} + +PortLink::~PortLink(void) +{ + // If, for some odd reason, this is deleted with something attached, + // free the memory used by the attachments. We do not flush the queue + // because the port may no longer be valid in cases such as the app + // is in the process of quitting + MakeEmpty(); +} + +void PortLink::SetOpCode(int32 code) +{ + // Sets the message code. This does not change once the message is sent. + // Another call to SetOpCode() is required for such things. + opcode=code; +} + +void PortLink::SetPort(port_id port) +{ + // Sets the target port. While not necessary in most uses, this exists + // mostly to prevent flexibility problems + target=port; +} + +port_id PortLink::GetPort(void) +{ + // Simply returns the port at which the object is pointed. + return target; +} + +void PortLink::Flush(bigtime_t timeout=B_INFINITE_TIMEOUT) +{ + // Fires a message off to the target, complete with attachments. NOTE: + // the recipient must delete all attachments, being the PortLink object assumes + // no responsiblity for the attachments once the message is sent. + int8 *msgbuffer; + int32 size; + + if(num_attachments>0) + { + FlattenData(&msgbuffer,&size); + + // Dump message to port, reset attachments, and clean up + if(timeout!=B_INFINITE_TIMEOUT) + write_port_etc(target,opcode,msgbuffer,size,B_TIMEOUT, timeout); + else + write_port(target,opcode,msgbuffer,size); + MakeEmpty(); + } + else + { + if(timeout!=B_INFINITE_TIMEOUT) + write_port_etc(target,opcode,NULL,0,B_TIMEOUT, timeout); + else + write_port(target,opcode,NULL,0); + } +} + +int8* PortLink::FlushWithReply(int32 *code, status_t *status, ssize_t *buffersize, bigtime_t timeout=B_INFINITE_TIMEOUT) +{ + // Fires a message to the target and then waits for a reply. The target will + // receive a message with the first item being the port_id to reply to. + // NOTE: like Flush(), any attached data must be deleted. + + // Effectively, an Attach() call inlined for changes + + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + { + *status=B_ERROR; + return NULL; + } + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&replyport,sizeof(port_id))) + { + bufferlength+=sizeof(port_id); + } + else + { + delete pld; + *status=B_ERROR; + return NULL; + } + + // Flatten() inlined to make some necessary changes + int8 *buffer=new int8[bufferlength]; + int8 *bufferindex=buffer; + size_t size=0; + + // attach our port_id first + memcpy(bufferindex, pld->buffer, pld->buffersize); + bufferindex += pld->buffersize; + size+=pld->buffersize; + + // attach everything else + for(int i=0;ibuffer, pld->buffersize); + bufferindex += pld->buffersize; + size+=pld->buffersize; + } + + // Flush the thing....FOOSH! :P + write_port(target,opcode,buffer,size); + MakeEmpty(); + delete buffer; + + // Now we wait for the reply + if(timeout==B_INFINITE_TIMEOUT) + { + *buffersize=port_buffer_size(replyport); + if(*buffersize>0) + buffer=(int8*)new int8[*buffersize]; + read_port(replyport,code, buffer, *buffersize); + } + else + { + *buffersize=port_buffer_size_etc(replyport,0,timeout); + if(*buffersize==B_TIMED_OUT) + { + *status=*buffersize; + return NULL; + } + if(*buffersize>0) + buffer=(int8*)new int8[*buffersize]; + read_port(replyport,code, buffer, *buffersize); + } + + // We got this far, so we apparently have some data + *status=B_OK; + return buffer; +} + +void PortLink::Attach(void *data, size_t size) +{ + // This is the member called to attach data to a message. Attachments are + // treated to be in 'Append' mode, tacking on each attached piece of data + // to the end of the list. + + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + if(size==0) + return; + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +// These functions were added for a major convenience in passing common types +// Eventually, I'd like to templatize these, but for now, this'll do + +void PortLink::Attach(int32 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int32); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(int16 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int16); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(int8 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int8); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(float data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(float); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(bool data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(bool); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(BRect data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(BRect); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(BPoint data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(BPoint); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::FlattenData(int8 **buffer,int32 *size) +{ + // This function is where all the magic happens, but it is strictly internal. + // It iterates through each PortLinkData object and copies it to the main buffer + // which ends up, ultimately, being written to the PortLink's target port. + + // skip if there aree no attachments + if(bufferlength<1) + return; + + *buffer=new int8[bufferlength]; + int8 *bufferindex=*buffer; + PortLinkData *pld; + *size=0; + + for(int i=0;ibuffer, pld->buffersize); + bufferindex += pld->buffersize; + *size+=pld->buffersize; + } +} + +void PortLink::MakeEmpty(void) +{ + // Nukes all the attachments currently held by the PortLink class + if(num_attachments!=0) + { + for(int i=0; i0) + free(buffer); +} + +bool PortLinkData::Set(void *data, size_t size) +{ + // Function copies the passed to the internal buffers for storage + if(size>0 && buffersize==0 && data!=NULL) + { + buffer=(char *)malloc(size); + if(buffer==NULL) + return false; + memcpy(buffer, data, size); + buffersize=size; + return true; + } + return false; +} diff --git a/src/servers/app/proto5/PortLink.h b/src/servers/app/proto5/PortLink.h new file mode 100644 index 0000000000..9f5432daab --- /dev/null +++ b/src/servers/app/proto5/PortLink.h @@ -0,0 +1,43 @@ +#ifndef _PORTLINK_H_ +#define _PORTLINK_H_ + +#include +#include +#include +#include + +#ifndef _PORTLINK_BUFFERSIZE +#define _PORTLINK_MAX_ATTACHMENTS 50 +#endif + +class PortLinkData; + +class PortLink +{ +public: + PortLink(port_id port); + ~PortLink(void); + void SetOpCode(int32 code); + void SetPort(port_id port); + port_id GetPort(void); + void Flush(bigtime_t timeout=B_INFINITE_TIMEOUT); + int8* FlushWithReply(int32 *code, status_t *status, ssize_t *buffersize, + bigtime_t timeout=B_INFINITE_TIMEOUT); + void Attach(void *data, size_t size); + void Attach(int32 data); + void Attach(int16 data); + void Attach(int8 data); + void Attach(float data); + void Attach(bool data); + void Attach(BRect data); + void Attach(BPoint data); + void MakeEmpty(void); +protected: + void FlattenData(int8 **buffer,int32 *size); + port_id target, replyport; + int32 opcode, bufferlength; + int num_attachments; + PortLinkData *attachments[_PORTLINK_MAX_ATTACHMENTS]; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto5/SecondDriver.cpp b/src/servers/app/proto5/SecondDriver.cpp new file mode 100644 index 0000000000..6a8523fb10 --- /dev/null +++ b/src/servers/app/proto5/SecondDriver.cpp @@ -0,0 +1,838 @@ +/******************************************************* +* SecondDriver +* +* Second driver is a Drvier abstraction layer for the +* OBOS app_server. It provides access to the Graphic +* HW via the low level api calls. This provides a +* way to run the app_server on real HW. +* This driver also makes it easy for you to run the +* OBOS app_server in parallel with the Be app_server +* when two or more video cards are installed in your +* computer. +* +* @author YNOP (ynop@beunited.org) +* @version beta1 (p5) +* +* History: +* - Added Ellipse (Stroke & Fill) +* Ran though test app to make sure worked +* Fixed HorizLine to used fill_span instead of fill_rect :P +* Updated the Cursor code to work again. +* Made new cursor (Be-hand like) +* - Added StrokeBezir +* Added HorizLine for speed +* - Added HW acceleration methods +* - Brez Line added +* - Created by YNOP +* +* Todo: +* Clean up src and add more comments :P +* Redo StrokeLine to use PenSize +* Redo StrokeLine to use pattern +* Mouse Cursor seems to be broken in proto5 ? +* Add in a way to read app_server_settings file so we can get the real settings +* Make display mode settings more flexable +* Look into FreeType for DrawString :P fun fun fun +* +* Todo methods: +* Blit() DrawBitmap() DrawString() FillArc() FillBezier() FillPolygon() +* FillRegion() FillRoundRect() FillShape() FillTriangle() +* StrokeArc() StrokeRoundRect() StrokeShpae() +* +*******************************************************/ +#include +#include + +#include + +#include "PortLink.h" +#include "ServerProtocol.h" +#include "ServerBitmap.h" +#include "ServerCursor.h" +#include "DebugTools.h" +#include "SecondDriver.h" +#include "SecondDriverHelper.h" + +/******************************************************* +* @description +*******************************************************/ +SecondDriver::SecondDriver(void):DisplayDriver(){ + SetupBezier(); + hide_cursor = false; + fd = -1; + image = -1; + + gah = NULL; + bits = NULL; + bpr = -1; + + scs = NULL; + mc = NULL; + sc = NULL; + + et = NULL; + re = NULL; + + s2sb = NULL; + fr = NULL; + ir = NULL; + s2stb = NULL; + fs = NULL; + +} + +/******************************************************* +* @description +*******************************************************/ +SecondDriver::~SecondDriver(void){ + if(is_initialized){ + } +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::Initialize(void){ + et = NULL; + bits = NULL; + + // Find a driver + fd = get_device(); + if(fd < 0){ + printf("No Device settings found.\n"); + fd = find_device(); + }else{ + printf("Device read from settings file\n"); + } + if(fd < 0){ + printf("No device find, trying fallback stub\n"); + fd = fallback_device(); + } + if(fd < 0){ + printf("Didn't find device :(\n"); + is_initialized = false; + } + /* load the accelerant */ + image = load_accelerant(fd, &gah); + if (image >= 0){ + // Set up the display to a valid resolution + if(get_and_set_mode(gah,&dm) == B_OK){ + // Here we are all good + if(dm.space == B_CMAP8){ + set_palette(gah); + } + get_frame_buffer(gah, &fbc); + bits = (uint32*)fbc.frame_buffer/*_dma*/; + bpr = fbc.bytes_per_row/4; // sould be by depth + + if(dm.flags & B_HARDWARE_CURSOR){ + // Lets check out tha hardwar cursoer stuff :P + printf("Mode supports Hardware cursors\n"); + scs = (set_cursor_shape)gah(B_SET_CURSOR_SHAPE,NULL); + mc = (move_cursor)gah(B_MOVE_CURSOR,NULL); + sc = (show_cursor)gah(B_SHOW_CURSOR,NULL); + } + + // Ok. now lets see if we can add some spiffy + // 2D acceleration to this :) + accelerant_engine_count aec = (accelerant_engine_count)gah(B_ACCELERANT_ENGINE_COUNT,NULL); + uint32 count = aec(); + if(count > 0){ + acquire_engine ae = (acquire_engine)gah(B_ACQUIRE_ENGINE,NULL); + re = (release_engine)gah(B_RELEASE_ENGINE,NULL); + if(ae(B_2D_ACCELERATION,1000,&st,&et) == B_OK){ + // Now lets see if we have some functions + printf("You should be verry happy. You have 2D hardware Acceleration\n"); + s2sb = (screen_to_screen_blit)gah(B_SCREEN_TO_SCREEN_BLIT,NULL); + fr = (fill_rectangle)gah(B_FILL_RECTANGLE,NULL); + ir = (invert_rectangle)gah(B_INVERT_RECTANGLE,NULL); + s2stb = (screen_to_screen_transparent_blit)gah(B_SCREEN_TO_SCREEN_TRANSPARENT_BLIT,NULL); + fs = (fill_span)gah(B_FILL_SPAN,NULL); + } + } + is_initialized = true; + }else{ + // failed to set mode + is_initialized = false; + } + }else{ + // image failed to load + is_initialized = false; + } + + if(is_initialized){ + printf("\n\tSecond Driver by YNOP (ynop@beunited.org)\n"); + printf("\tSecond Driver is copyrigth YNOP 2002\n"); + printf("\tHave fun, its all set up :)\n\n"); + } + + SetCursor((ServerCursor*)NULL); + ShowCursor(); + int32 h = GetHeight(); + int32 w = GetWidth(); + MoveCursorTo(w/2,h/2); + +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::Shutdown(void){ + printf("\tShuting down SecondDriver\n"); + if(et){ + if(re(et,&st) != B_OK){ + printf("Failed to release engine\n"); + } + } + + uninit_accelerant ua = (uninit_accelerant)gah(B_UNINIT_ACCELERANT,NULL); + if(ua){ ua();} + + unload_add_on(image); + + // clsoe the file now... + close(fd); + + + is_initialized=false; +} + +/******************************************************* +* @description +*******************************************************/ +bool SecondDriver::IsInitialized(void){ + return is_initialized; +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::SafeMode(void){ +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::Reset(void){ +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::SetScreen(uint32 space){ + // Clear(51,102,152); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::Clear(uint8 red, uint8 green, uint8 blue){ + rgb_color r; + r.red = red; + r.blue = blue; + r.green = green; + Clear(r); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::Clear(rgb_color col){ + highcol = col; + FillRect(BRect(0,0,GetHeight()-1,GetWidth()-1),NULL); +} + +/******************************************************* +* @description +*******************************************************/ +int32 SecondDriver::GetHeight(void){ + // Gets the height of the current mode + return dm.virtual_height; +} + +/******************************************************* +* @description +*******************************************************/ +int32 SecondDriver::GetWidth(void){ + // Gets the width of the current mode + return dm.virtual_width; +} + +/******************************************************* +* @description +*******************************************************/ +int SecondDriver::GetDepth(void){ + // Gets the color depth of the current mode + return 0; +} + +/******************************************************* +* @description +*******************************************************/ +#ifdef PROTO_4 + void SecondDriver::Blit(BPoint loc, ServerBitmap *src, ServerBitmap *dest) +#else + void SecondDriver::Blit(BRect src, BRect dest) +#endif +{ + printf("Calling Blit (not wirten yet)\n"); + if(s2sb){ + printf("Accelerated Blit\n"); + }else{ + + } +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::DrawBitmap(ServerBitmap *bitmap){ + printf("Calling DrawBitmap (not writen yet)\n"); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::DrawChar(char c, BPoint point){ + char string[2]; + string[0]=c; + string[1]='\0'; + DrawString(string,2,point); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::DrawString(char *string, int length, BPoint point){ + printf("DrawString is not writen yet\n"); + + // i would say that libtruetype would do some good herer +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern){ + printf("FillArc is not writen yet\n"); + StrokeArc(centerx,centery,xradius,yradius,angle,span,pattern); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillBezier(BPoint *points, uint8 *pattern){ + printf("FillBezier is not writen yet\n"); + StrokeBezier(points,pattern); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern){ + MidpointEllipse(centerx,centery,x_radius,y_radius,true,pattern); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillPolygon(int *x, int *y, int numpoints, bool is_closed){ + printf("FillPolygon is not writen yet\n"); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillRect(BRect rect, uint8 *pattern){ + if(fr){ + // usieng accelertated 2d file + union{ + uint8 bytes[4]; + uint32 word; + }c1; + + //printf("Accelerated Fill\n"); + fill_rect_params frp; + frp.left =(uint16) rect.left; + frp.top =(uint16) rect.top; + frp.right =(uint16) rect.right; + frp.bottom =(uint16) rect.bottom; + c1.bytes[0] = highcol.blue; + c1.bytes[1] = highcol.green; + c1.bytes[2] = highcol.red; + fr(et,c1.word,&frp,1); + }else{ + for(int32 i = 0;i < rect.Height()-1;i++){ + MovePenTo(BPoint(rect.left,rect.top+i)); + StrokeLine(BPoint(rect.right,rect.top+i),pattern); + //HorizLine(rect.left,rect.right,rect.top+i); // uses accel :P + } + } +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillRect(BRect rect, rgb_color col){ + rgb_color tmpc = highcol; + highcol = col; + FillRect(rect, NULL); + highcol = tmpc; +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillRegion(BRegion *region){ + printf("RillRegion is not writen yet\n"); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern){ + printf("FillRoundRect is not writen yet\n"); + StrokeRoundRect(rect,xradius,yradius,pattern); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillShape(BShape *shape){ + printf("FillShape is not writen yet\n"); + StrokeShape(shape); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern){ + printf("FillTriangle is not writen yet\n"); + StrokeTriangle(first,second,third,rect,pattern); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::HideCursor(void){ + if(sc){ + sc(false); + cursor_visible = false; + }else{ + printf("Shoftware Hide Cursor\n"); + } +} + +/******************************************************* +* @description +*******************************************************/ +bool SecondDriver::IsCursorHidden(void){ + return cursor_visible; +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::ObscureCursor(void){ + // Hides cursor until mouse is moved + HideCursor(); + show_on_move = true; +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::MoveCursorTo(float x, float y){ + if(show_on_move){ + ShowCursor(); + } + if(mc){ + mc((short unsigned int)x,(short unsigned int)y); + }else{ + printf("Software move Cursor\n"); + } +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::MovePenTo(BPoint pt){ + penpos = pt; +} + +/******************************************************* +* @description +*******************************************************/ +BPoint SecondDriver::PenPosition(void){ + return penpos; +} + +/******************************************************* +* @description +*******************************************************/ +float SecondDriver::PenSize(void){ + return pensize; +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::SetCursor(int32 value){ + printf("Setcursoer value?\n"); + // Uh what is this all about? +} + + + + +//0 - 1 = black +//0 - 0 = what +//1 - 0 = trans +//1 - 1 = invert + +// Pointy cursor +/*uint8 andMask[] = { + 63,255,15,255,131,255,128,127,192,31,192,31,224,63,224,63, + 224,31,240,15,243,7,255,131,255,193,255,224,255,240,255,248 +}; +uint8 xorMask[] = { + 192,0,176,0,76,0,67,128,32,96,32,32,16,64,16,64, + 16,32,11,16,12,136,0,68,0,34,0,17,0,9,0,7 +};*/ +// BeOS like cursor +uint8 andMask[] = { + 255,255,255,255,199,255,195,255,195,255,224,31,224,3,240,1, + 240,0,192,0,128,0,128,0,192,0,240,0,252,1,254,7 +}; +uint8 xorMask[] = { + 0,0,0,0,56,0,36,0,36,0,19,224,18,92,9,42, + 8,1,60,0,76,0,66,0,48,0,12,0,2,0,1,0 +}; + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::SetCursor(ServerCursor *cursor){ + printf("Setting cursor\n"); + current_cursor = cursor; +// uint8 *andMask; + // uint8 *xorMask; + if(scs){ +// scs(cursor->width,cursor->height,(short unsigned int)cursor->hotspot.x,(short unsigned int)cursor->hotspot.y,andMask,xorMask); + scs(16,16,3,3,andMask,xorMask); + }else{ + printf("Setting software cursor\n"); + } +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::SetPenSize(float size){ + pensize = size; +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::SetHighColor(uint8 r,uint8 g,uint8 b,uint8 a=255){ + highcol.red = r; + highcol.green = g; + highcol.blue = b; + highcol.alpha = a; +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::SetLowColor(uint8 r,uint8 g,uint8 b,uint8 a=255){ + lowcol.red = r; + lowcol.green = g; + lowcol.blue = b; + lowcol.alpha = a; +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::SetPixel(int x, int y, uint8 *pattern){ + union{ + uint8 bytes[4]; + uint32 word; + }c1; + + c1.bytes[0] = highcol.blue; + c1.bytes[1] = highcol.green; + c1.bytes[2] = highcol.red; + c1.bytes[3] = highcol.alpha; + + *(bits + x + y*bpr) = c1.word; +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::ShowCursor(void){ + printf("\tShow Cursor\n"); + show_on_move = false; + cursor_visible = true; + if(sc){ + sc(true); + }else{ + printf("Software show cursor\n"); + } +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::StrokeArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern){ + printf("StrokeArch is not writen yet\n"); +} + + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::StrokeBezier(BPoint *pts, uint8 *pattern){ + BPoint segment[SEGMENTS + 1]; + computeSegments(pts[0], pts[1],pts[2],pts[3], segment); + + MovePenTo(segment[0]); + + for(int32 s = 1 ; s <= SEGMENTS ; ++s ){ + if(segment[s].x != segment[s - 1].x || segment[s].y != segment[s - 1].y ) { + StrokeLine(segment[s],pattern); + } + } +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::StrokeEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern){ + MidpointEllipse(centerx,centery,x_radius,y_radius,false,pattern); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::StrokeLine(BPoint point, uint8 *pattern){ + if(penpos.y == point.y){ + HorizLine(penpos.x,point.x,point.y,pattern); + return; + } + + int oct = 0; + int xoff = (int32)penpos.x; + int yoff = (int32)penpos.y; + int32 x2 = (int32)point.x-xoff; + int32 y2 = (int32)point.y-yoff; + int32 x1 = 0; + int32 y1 = 0; +// if(y2==0){ if (x1>x2){int t=x1;x1=x2;x2=t;}HorizLine(x1+xoff,x2+xoff,y1+yoff); return;} + if(y2<0){ y2 = -y2; oct+=4; }//bit2=1 + if(x2<0){ x2 = -x2; oct+=2;}//bit1=1 + if(x2 x2){ int32 t=x1;x1=x2;x2=t; } + if(fr){ + union{ + uint8 bytes[4]; + uint32 word; + }c1; + + //printf("Accelerated HorizLine\n"); + uint16 list[3]; + list[0] = y; + list[1] = x1; + list[2] = x2; + c1.bytes[0] = highcol.blue; + c1.bytes[1] = highcol.green; + c1.bytes[2] = highcol.red; + fs(et,c1.word,list,1); + }else{ + //software hline + printf("\t!!HorizLine without HWaccel is a waist\n"); + for(int32 i = x1; i <= x2;i++){ + SetPixel(i,y,pattern); + } + } + +} + +//void EllipsePoints(float cx,float cy,int32 x, int32 y){ +// view->StrokeLine(BPoint(x+cent.x,y+cent.y),BPoint(x+cent.x,y+cent.y)); +// view->StrokeLine(BPoint(-x+cent.x,y+cent.y),BPoint(-x+cent.x,y+cent.y)); +// view->StrokeLine(BPoint(x+cent.x,-y+cent.y),BPoint(x+cent.x,-y+cent.y)); +// view->StrokeLine(BPoint(-x+cent.x,-y+cent.y),BPoint(-x+cent.x,-y+cent.y)); +#define EllipsePoints(cx,cy,x,y,pattern){ \ + SetPixel( x+cx, y+cx,pattern); \ + SetPixel(-x+cx, y+cx,pattern); \ + SetPixel( x+cx,-y+cx,pattern); \ + SetPixel(-x+cx,-y+cx,pattern); \ +} + + +//void EllipsePointsFill(BPoint cent,int32 x, int32 y,pattern){ +// view->StrokeLine(BPoint(-x+cent.x,y+cent.y),BPoint(x+cent.x,y+cent.y)); +// view->StrokeLine(BPoint(-x+cent.x,-y+cent.y),BPoint(x+cent.x,-y+cent.y)); + + #define EllipsePointsFill(cx,cy,x,y,pattern){ \ + HorizLine(-x+cx,x+cx, y+cy, pattern); \ + HorizLine(-x+cx,x+cx, -y+cy, pattern); \ +} + + +/******************************************************* +* +*******************************************************/ +void SecondDriver::MidpointEllipse(float centx,float centy,int32 xrad, int32 yrad,bool fill,uint8 *pattern){ + if(xrad < 0){ xrad = -xrad; } + if(yrad < 0){ yrad = -yrad; } + double d2; + int32 x = 0; + int32 y = yrad; + + int32 xradSqr = xrad*xrad; + int32 yradSqr = yrad*yrad; + + double dl = yradSqr - (xradSqr*yrad) + (0.25 *xradSqr); + + if(fill){ EllipsePointsFill(centx,centy,x,y,pattern); }else{ EllipsePoints(centx,centy,x,y,pattern); } + + // Test gradient if still in region 1 + while((xradSqr*(y-.5)) > (yradSqr*(x+1))){ + if(dl < 0){ // Select E + dl += yradSqr*(2*x + 3); + }else{ // Select SE + dl += yradSqr*(2*x + 3) + xradSqr*(-2*y + 2); + y--; + } + x++; + if(fill){ EllipsePointsFill(centx,centy,x,y,pattern); }else{ EllipsePoints(centx,centy,x,y,pattern); } + } + + d2 = (yradSqr*(x + .5)*(x + .5)) + (xradSqr*(y-1)*(y-1)) - xradSqr*yradSqr; + while(y > 0){ + if(d2 < 0){ // Select SE + d2 += yradSqr*(2*x + 2) + xradSqr*(-2*y + 3); + x++; + }else{ // Select E + d2 += xradSqr*(-2*y + 3); + } + y--; + if(fill){ EllipsePointsFill(centx,centy,x,y,pattern); }else{ EllipsePoints(centx,centy,x,y,pattern); } + } +} + + + +#ifdef DEBUG_DRIVER_MODULE +#undef DEBUG_DRIVER_MODULE +#endif \ No newline at end of file diff --git a/src/servers/app/proto5/SecondDriver.h b/src/servers/app/proto5/SecondDriver.h new file mode 100644 index 0000000000..e1b937b618 --- /dev/null +++ b/src/servers/app/proto5/SecondDriver.h @@ -0,0 +1,123 @@ +#ifndef _SECDRIVER_H_ +#define _SECDRIVER_H_ + +#include +#include +#include +#include +#include // for pattern struct +#include +#include +#include "DisplayDriver.h" + +#include +#include +#include + +class BBitmap; +class PortLink; +class VDWindow; +class ServerCursor; + + +class SecondDriver:public DisplayDriver{ +public: + SecondDriver(void); + virtual ~SecondDriver(void); + + virtual void Initialize(void); // Sets the driver + virtual bool IsInitialized(void); + virtual void Shutdown(void); // You never know when you'll need this + + virtual void SafeMode(void); // Easy-access functions for common tasks + virtual void Reset(void); + virtual void Clear(uint8 red,uint8 green,uint8 blue); + virtual void Clear(rgb_color col); + + // Settings functions + virtual void SetScreen(uint32 space); + virtual int32 GetHeight(void); + virtual int32 GetWidth(void); + virtual int GetDepth(void); + + // Drawing functions + #ifdef PROTO_4 + virtual void Blit(BPoint loc, ServerBitmap *src, ServerBitmap *dest); + #else + virtual void Blit(BRect src, BRect dest); + #endif + virtual void DrawBitmap(ServerBitmap *bitmap); + virtual void DrawChar(char c, BPoint point); + virtual void DrawString(char *string, int length, BPoint point); + + virtual void FillArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern); + virtual void FillBezier(BPoint *points, uint8 *pattern); + virtual void FillEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern); + virtual void FillPolygon(int *x, int *y, int numpoints, bool is_closed); + virtual void FillRect(BRect rect, uint8 *pattern); + virtual void FillRect(BRect rect, rgb_color col); + virtual void FillRegion(BRegion *region); + virtual void FillRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern); + virtual void FillShape(BShape *shape); + virtual void FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern); + + virtual void HideCursor(void); + virtual bool IsCursorHidden(void); + virtual void MoveCursorTo(float x, float y); + virtual void MovePenTo(BPoint pt); + virtual void ObscureCursor(void); + virtual BPoint PenPosition(void); + virtual float PenSize(void); + virtual void SetCursor(int32 value); + virtual void SetCursor(ServerCursor *cursor); + virtual void SetHighColor(uint8 r,uint8 g,uint8 b,uint8 a=255); + virtual void SetLowColor(uint8 r,uint8 g,uint8 b,uint8 a=255); + virtual void SetPenSize(float size); + virtual void SetPixel(int x, int y, uint8 *pattern); + virtual void ShowCursor(void); + + virtual void StrokeArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern); + virtual void StrokeBezier(BPoint *points, uint8 *pattern); + virtual void StrokeEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern); + virtual void StrokeLine(BPoint point, uint8 *pattern); + virtual void StrokeLine(BPoint pt1, BPoint pt2, rgb_color col); + virtual void StrokePolygon(int *x, int *y, int numpoints, bool is_closed); + virtual void StrokeRect(BRect rect,uint8 *pattern); + virtual void StrokeRect(BRect rect,rgb_color col); + virtual void StrokeRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern); + virtual void StrokeShape(BShape *shape); + virtual void StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern); +private: + void HorizLine(int32 x1,int32 x2,int32 y, uint8 *pattern); + void MidpointEllipse(float centerx, float centery,int32 xrad, int32 yrad,bool fill,uint8 *pattern); +protected: + int hide_cursor; + + int fd; + image_id image; + GetAccelerantHook gah; + display_mode dm; + + frame_buffer_config fbc; + + uint32 *bits; + int32 bpr; + + set_cursor_shape scs; + move_cursor mc; + show_cursor sc; + + sync_token st; + engine_token *et; + release_engine re; + + screen_to_screen_blit s2sb; + fill_rectangle fr; + invert_rectangle ir; + screen_to_screen_transparent_blit s2stb; + fill_span fs; + + +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto5/SecondDriverHelper.h b/src/servers/app/proto5/SecondDriverHelper.h new file mode 100644 index 0000000000..ff3ee288d7 --- /dev/null +++ b/src/servers/app/proto5/SecondDriverHelper.h @@ -0,0 +1,435 @@ +/******************************************************* +* SecondDriver +* +* Helper methods for SecondDriver. This is where we +* put all the code that inits the real HW and +* seaches for the acceleration methods an all that +* other stuff. +* +* @author YNOP (ynop@beunited.org) +*******************************************************/ +#ifndef _SECDRIVER_HELPER_H_ +#define _SECDRIVER_HELPER_H_ + +//#include +#include +#include + +#include +#include +#include // has ioctl ?:P +//#include +#include + +#define DEV_GRAPHICS "/dev/graphics/" +#define ACCELERANTS_DIR "/accelerants/" +#define DEV_STUB "stub" + +/******************************************************* +* @description Loads the driver from settings ... +*******************************************************/ +int get_device(){ +// 102b_0519_001300 102b_051a_001400 stub + return open(DEV_GRAPHICS"102b_051a_001400", B_READ_WRITE); +// return -1; +} + +/******************************************************* +* @description Loads the stub driver - never fun +*******************************************************/ +int fallback_device(){ + return open(DEV_GRAPHICS DEV_STUB, B_READ_WRITE); +} + +/******************************************************* +* @description Find the first device that it can open +* in the /dev/graphics dir and returns it. +*******************************************************/ +int find_device(){ + DIR *d; + struct dirent *e; + char name_buf[1024]; + int fd = -1; + //bool foundfirst = false; // hacky way of finding second video card in your box + + printf("Probeing %s for device...\n",DEV_GRAPHICS); + + /* open directory apath */ + d = opendir(DEV_GRAPHICS); + if(!d){ return B_ERROR; } + while((e = readdir(d)) != NULL){ + if (!strcmp(e->d_name, ".") || !strcmp(e->d_name, "..") || !strcmp(e->d_name, "stub")){ + continue; + } + strcpy(name_buf, DEV_GRAPHICS); +// strcat(name_buf, "/"); + strcat(name_buf, e->d_name); + fd = open(name_buf, B_READ_WRITE); + ///printf("Opening device %s\n",name_buf); + if(fd >= 0){ + //printf("Open wend ok\n"); + /*if(!foundfirst){ + foundfirst = true; + printf("\tbut we are not going to use it as app_server is\n"); + }else{ + // found it :) + */ printf("\tOpened device %s\n",name_buf); + closedir(d); + return fd; + //} + }else{ + //foundfirst = true; // this is a proper find as the app_server should let us open the dev + printf("\tCouldn't open device %s\n",name_buf); + } + } + closedir(d); + return B_ERROR; +} + +/******************************************************* +* @description Finds and loads the Accelerant for +* this device +*******************************************************/ +image_id load_accelerant(int fd, GetAccelerantHook *hook) { + status_t result; + image_id image = -1; + char + signature[1024], + path[PATH_MAX]; + struct stat st; + const static directory_which vols[] = { + B_USER_ADDONS_DIRECTORY, + B_COMMON_ADDONS_DIRECTORY, + B_BEOS_ADDONS_DIRECTORY + }; + + /* get signature from driver */ + result = ioctl(fd, B_GET_ACCELERANT_SIGNATURE, &signature, sizeof(signature)); + if (result != B_OK){ + printf("Failed to get accelerant signature from drived!\n"); + return result; + } + + printf("Searching for Accelerant named \"%s\"\n",signature); + + // note failure by default + for(int32 i=0; i < (int32)(sizeof (vols) / sizeof (vols[0])); i++) { + //printf("attempting to get path for %ld (%d)\n", i, vols[i]); + if(find_directory(vols[i], -1, false, path, PATH_MAX) != B_OK) { + printf("warning: find directory failed (continueing)\n"); + continue; + } + + strcat (path, ACCELERANTS_DIR); + strcat (path, signature); + printf("\tTrying %s\n",path); + + // don't try to load non-existant files + if (stat(path, &st) != 0) continue; + + // try and load it up.. + image = load_add_on(path); + if (image >= 0) { + printf("\tAccelerant loaded - trying to init\n"); + // get entrypoint from accelerant + result = get_image_symbol(image, B_ACCELERANT_ENTRY_POINT, +#if defined(__INTEL__) + B_SYMBOL_TYPE_ANY, +#else + B_SYMBOL_TYPE_TEXT, +#endif + (void **)hook); + if (result == B_OK) { + init_accelerant ia; + ia = (init_accelerant)(*hook)(B_INIT_ACCELERANT, NULL); + if(ia && ((result = ia(fd)) == B_OK)) { + // we have a winner! + //printf("Accelerant %s \n", path); + printf("\tAccelerant Init() was B_OK\n"); + break; + } else { + printf("\tAccelerant Init() failed: %ld\n", result); + } + } else { + printf("\tCouldn't find the entry point :-(\n"); + } + // unload the accelerant, as we must be able to init! + unload_add_on(image); + } + if (image < 0) printf("\tLoad Image failure. ID: %.8lx (%s)\n", image, strerror(image)); + // mark failure to load image + image = -1; + } + + //printf("Add-on image id: %ld\n", image); + return image; +} + +/******************************************************* +* @description +*******************************************************/ +static const char *spaceToString(uint32 cs) { + const char *s; + switch (cs) { +#define s2s(a) case a: s = #a ; break + s2s(B_RGB32); + s2s(B_RGBA32); + s2s(B_RGB32_BIG); + s2s(B_RGBA32_BIG); + s2s(B_RGB16); + s2s(B_RGB16_BIG); + s2s(B_RGB15); + s2s(B_RGBA15); + s2s(B_RGB15_BIG); + s2s(B_RGBA15_BIG); + s2s(B_CMAP8); + s2s(B_GRAY8); + s2s(B_GRAY1); + s2s(B_YCbCr422); + s2s(B_YCbCr420); + s2s(B_YUV422); + s2s(B_YUV411); + s2s(B_YUV9); + s2s(B_YUV12); + default: + s = "unknown"; break; +#undef s2s + } + return s; +} + +/******************************************************* +* @description +*******************************************************/ +void dump_mode(display_mode *dm) { + display_timing *t = &(dm->timing); + printf(" pixel_clock: %ldKHz\n", t->pixel_clock); + printf(" H: %4d %4d %4d %4d\n", t->h_display, t->h_sync_start, t->h_sync_end, t->h_total); + printf(" V: %4d %4d %4d %4d\n", t->v_display, t->v_sync_start, t->v_sync_end, t->v_total); + printf(" timing flags:"); + if (t->flags & B_BLANK_PEDESTAL) printf(" B_BLANK_PEDESTAL"); + if (t->flags & B_TIMING_INTERLACED) printf(" B_TIMING_INTERLACED"); + if (t->flags & B_POSITIVE_HSYNC) printf(" B_POSITIVE_HSYNC"); + if (t->flags & B_POSITIVE_VSYNC) printf(" B_POSITIVE_VSYNC"); + if (t->flags & B_SYNC_ON_GREEN) printf(" B_SYNC_ON_GREEN"); + if (!t->flags) printf(" (none)\n"); + else printf("\n"); + printf(" refresh rate: %4.2f\n", ((double)t->pixel_clock * 1000) / ((double)t->h_total * (double)t->v_total)); + printf(" color space: %s\n", spaceToString(dm->space)); + printf(" virtual size: %dx%d\n", dm->virtual_width, dm->virtual_height); + printf("dispaly start: %d,%d\n", dm->h_display_start, dm->v_display_start); + + printf(" mode flags:"); + if (dm->flags & B_SCROLL) printf(" B_SCROLL"); + if (dm->flags & B_8_BIT_DAC) printf(" B_8_BIT_DAC"); + if (dm->flags & B_HARDWARE_CURSOR) printf(" B_HARDWARE_CURSOR"); + if (dm->flags & B_PARALLEL_ACCESS) printf(" B_PARALLEL_ACCESS"); +// if (dm->flags & B_SUPPORTS_OVERLAYS) printf(" B_SUPPORTS_OVERLAYS"); + if (!dm->flags) printf(" (none)\n"); + else printf("\n"); +} + +/******************************************************* +* @description +*******************************************************/ +void simple_dump_mode(display_mode *dm){ + //printf("H: %4d\n", t->h_display); + //printf("V: %4d\n", t->v_display); + display_timing *t = &(dm->timing); + printf("Virtual size: %d x %d\n", dm->virtual_width, dm->virtual_height); + printf("Color space: %s\n", spaceToString(dm->space)); + printf("Refresh rate: %4.2f\n", ((double)t->pixel_clock * 1000) / ((double)t->h_total * (double)t->v_total)); +} + +/******************************************************* +* @description +*******************************************************/ +void mode_from_settings(display_mode *dm){ + // display_timing *t = &(dm->timing); + dm->space = B_RGB32; + dm->virtual_width = 800; + dm->virtual_height = 600; + dm->h_display_start = 0; + dm->v_display_start = 0; +} + +/******************************************************* +* @description +*******************************************************/ +status_t get_and_set_mode(GetAccelerantHook gah, display_mode *dm) { + printf("Setting up display mode\n"); + accelerant_mode_count gmc; + uint32 mode_count; + get_mode_list gml; + display_mode *mode_list, target, high, low; + propose_display_mode pdm; + status_t result = B_ERROR; + set_display_mode sdm; + + /* find the propose mode hook */ + pdm = (propose_display_mode)gah(B_PROPOSE_DISPLAY_MODE, NULL); + if (!pdm) { + printf("No B_PROPOSE_DISPLAY_MODE\n"); + goto exit0; + } + /* and the set mode hook */ + sdm = (set_display_mode)gah(B_SET_DISPLAY_MODE, NULL); + if (!sdm) { + printf("No B_SET_DISPLAY_MODE\n"); + goto exit0; + } + + /* how many modes does the driver support */ + gmc = (accelerant_mode_count)gah(B_ACCELERANT_MODE_COUNT, NULL); + if (!gmc) { + printf("No B_ACCELERANT_MODE_COUNT\n"); + goto exit0; + } + mode_count = gmc(); + printf("\tDriver supports %lu differnat video modes\n", mode_count); + if (mode_count == 0) goto exit0; + + /* get a list of graphics modes from the driver */ + gml = (get_mode_list)gah(B_GET_MODE_LIST, NULL); + if (!gml) { + printf("No B_GET_MODE_LIST\n"); + goto exit0; + } + mode_list = (display_mode *)calloc(sizeof(display_mode), mode_count); + if (!mode_list) { + printf("Couldn't calloc() for mode list\n"); + goto exit0; + } + if (gml(mode_list) != B_OK) { + printf("mode list retrieval failed\n"); + goto free_mode_list; + } + + /* take the first mode in the list */ + //printf("\tPropose Display Mode\n------------------------\n"); + //simple_dump_mode(&mode_list[69]); + //mode_from_settings(&mode_list[69]); + target = mode_list[69]; + high = mode_list[69]; + low = mode_list[69]; + /* make as tall a virtual height as possible */ + //target.virtual_height = high.virtual_height = 0xffff; + // virtual hight should only be used if a res larger than + // the screen can handle + /* propose the display mode */ + if (pdm(&target, &low, &high) == B_ERROR) { + printf("propose_display_mode failed\n"); + goto free_mode_list; + } + printf("------Target display mode------\n"); + simple_dump_mode(&target); + printf("-------------------------------\n"); + /* we got a display mode, now set it */ + if (sdm(&target) == B_ERROR) { + printf("set display mode failed\n"); + goto free_mode_list; + } + /* note the mode and success */ + *dm = target; + result = B_OK; + +free_mode_list: + free(mode_list); +exit0: + return result; +} + + +/******************************************************* +* @description +*******************************************************/ +void get_frame_buffer(GetAccelerantHook gah, frame_buffer_config *fbc) { + get_frame_buffer_config gfbc; + gfbc = (get_frame_buffer_config)gah(B_GET_FRAME_BUFFER_CONFIG, NULL); + gfbc(fbc); +} + +/******************************************************* +* @description +*******************************************************/ +sem_id get_sem(GetAccelerantHook gah) { + accelerant_retrace_semaphore ars; + ars = (accelerant_retrace_semaphore)gah(B_ACCELERANT_RETRACE_SEMAPHORE, NULL); + return ars(); +} + +/******************************************************* +* @description +*******************************************************/ +void set_palette(GetAccelerantHook gah) { + set_indexed_colors sic; + sic = (set_indexed_colors)gah(B_SET_INDEXED_COLORS, NULL); + if (sic) { + /* booring grey ramp for now */ + uint8 map[3 * 256]; + uint8 *p = map; + int i; + for (i = 0; i < 256; i++) { + *p++ = i; + *p++ = i; + *p++ = i; + } + sic(256, 0, map, 0); + } +} + +// This is a ll the stuff needed to stroke a Bezier Curve.. +// Note that we should probably wait and alloc this data latter +// on when we stroke our first Curve. That way if no curve ever +// gets render (unlikely i know) then this space would be saved. +#define SEGMENTS 32 +#define Fixed float +static Fixed weight1[SEGMENTS + 1]; +static Fixed weight2[SEGMENTS + 1]; +#define w1(s) weight1[s] +#define w2(s) weight2[s] +#define w3(s) weight2[SEGMENTS - s] +#define w4(s) weight1[SEGMENTS - s] +#define FixMul(a,b) (a)*(b) +#define FixRound(a) ((a-int32(a))>=.5)?(int32(a)+1):(int32(a)) +#define FixRatio(a,b) ((a)/float(b)) + +/******************************************************* +* @description Creats the two Bernstien Pollynomials +* We only need to creat two becase the 1 & 4 are +* mirrors and the 2 & 3 are mirros. +*******************************************************/ +void SetupBezier(){ + Fixed t, zero, one; + int s; + zero = FixRatio(0, 1); + one = FixRatio(1, 1); + + weight1[0] = one; + weight2[0] = zero; + for(s = 1 ;s < SEGMENTS ;++s){ + t = FixRatio(s, SEGMENTS); + weight1[s] = FixMul(one - t, FixMul(one - t, one - t)); + weight2[s] = 3 * FixMul(t, FixMul(t - one, t - one)); + } + weight1[SEGMENTS] = zero; + weight2[SEGMENTS] = zero; +} + +/******************************************************* +* @description Useing the weights of the 4 bernstein +* pollynomials calc the segment endpoints. This is +* the real worker method +*******************************************************/ +static void computeSegments(BPoint p1,BPoint p2, BPoint p3, BPoint p4, BPoint *segment){ + int s; + segment[0] = p1; + for(s = 1;s < SEGMENTS;++s){ + segment[s].y = FixRound(w1(s) * p1.y + w2(s) * p2.y + w3(s) * p3.y + w4(s) * p4.y); + segment[s].x = FixRound(w1(s) * p1.x + w2(s) * p2.x + w3(s) * p3.x + w4(s) * p4.x); + } + segment[SEGMENTS] = p4; +} + +#endif + diff --git a/src/servers/app/proto5/ServerApp.cpp b/src/servers/app/proto5/ServerApp.cpp new file mode 100644 index 0000000000..9cbc15c9e9 --- /dev/null +++ b/src/servers/app/proto5/ServerApp.cpp @@ -0,0 +1,883 @@ +/* + ServerApp.cpp + Class which works with a BApplication. Handles all messages coming + from and going to its application. +*/ +//#define DEBUG_SERVERAPP_MSGS +//#define DEBUG_SERVERAPP_CURSORS +//#define DEBUG_SERVERAPP_MISC + +#include +#include +#include +#include +#include "Desktop.h" +#include "DisplayDriver.h" +//#include "Layer.h" +#include "ServerApp.h" +#include "ServerWindow.h" +#include "ServerBitmap.h" +#include "ServerProtocol.h" +#include "ServerCursor.h" +#include "PortLink.h" +#include +#include +#include +#include "DebugTools.h" + + +ServerApp::ServerApp(port_id msgport, char *signature) +{ + // need to copy the signature because the message buffer + // owns the copy which we are passed as a parameter. + app_sig=(signature)?signature:"Application"; + + // sender is the monitored app's event port + sender=msgport; + applink=new PortLink(sender); + + port_info pinfo; + get_port_info(sender,&pinfo); + target_id=pinfo.team; + + // receiver is the port to which the app sends messages for the server + receiver=create_port(30,app_sig.String()); + +#ifdef DEBUG_SERVERAPP_MISC +printf("ServerApp port for app %s is at %ld\n",app_sig.String(),receiver); +#endif + + if(receiver==B_NO_MORE_PORTS) + { + // uh-oh. We have a serious problem. Tell the app to quit + applink->SetOpCode(B_QUIT_REQUESTED); + applink->Flush(); + } + + // No longer necessary. This message is sent from the app_server thread + // now because of changes in the application structure from previous + // prototypes. +/* else + { + // Everything checks out, so tell the application + // where to send future messages + applink->SetOpCode(SET_SERVER_PORT); + applink->Attach(&receiver,sizeof(port_id)); + applink->Flush(); + } +*/ + applink->SetPort(sender); + winlist=new BList(0); + bmplist=new BList(0); + driver=get_gfxdriver(); + isactive=false; + cursor=new ServerCursor(); + + // This exists for testing the graphics access module and will disappear + // when layers are implemented + high.red=255; + high.green=255; + high.blue=255; + high.alpha=255; + low.red=0; + low.green=0; + low.blue=0; + low.alpha=255; +} + +ServerApp::~ServerApp(void) +{ +#ifdef DEBUG_SERVERAPP_MISC +printf("%s: ~ServerApp\n",app_sig.String()); +#endif + int32 i; + ServerWindow *tempwin; + for(i=0;iCountItems();i++) + { + tempwin=(ServerWindow*)winlist->ItemAt(i); + if(tempwin) + delete tempwin; + } + winlist->MakeEmpty(); + delete winlist; + + ServerBitmap *tempbmp; + for(i=0;iCountItems();i++) + { + tempbmp=(ServerBitmap*)bmplist->ItemAt(i); + if(tempbmp) + delete tempbmp; + } + bmplist->MakeEmpty(); + delete bmplist; + + delete applink; + applink=NULL; + delete cursor; + + // Kill the monitor thread if it exists + thread_info info; + if(get_thread_info(monitor_thread,&info)==B_OK) + kill_thread(monitor_thread); +} + +bool ServerApp::Run(void) +{ +#ifdef DEBUG_SERVERAPP_MISC +printf("%s: Run()\n",app_sig.String()); +#endif + // Unlike a BApplication, a ServerApp is *supposed* to return immediately + // when its Run function is called. + monitor_thread=spawn_thread(MonitorApp,app_sig.String(),B_NORMAL_PRIORITY,this); + if(monitor_thread==B_NO_MORE_THREADS || monitor_thread==B_NO_MEMORY) + return false; + resume_thread(monitor_thread); + return true; +} + +bool ServerApp::PingTarget(void) +{ + // This function is called by the app_server thread to ensure that + // the target app still exists. We do this not by sending a message + // but by calling get_port_info. We don't want to send ping messages + // just because the app might simply be hung. If this is the case, it + // should be up to the user to kill it. If the app has been killed, its + // ports will be invalid. Thus, if get_port_info returns an error, we + // tell the app_server to delete the respective ServerApp. + + team_info tinfo; + if(get_team_info(target_id,&tinfo)==B_BAD_TEAM_ID) + { + port_id serverport=find_port(SERVER_PORT_NAME); + if(serverport==B_NAME_NOT_FOUND) + { + printf("PANIC: ServerApp %s could not find the app_server port in PingTarget()!\n",app_sig.String()); + return false; + } + applink->SetPort(serverport); + applink->SetOpCode(DELETE_APP); + applink->Attach(&monitor_thread,sizeof(thread_id)); + applink->Flush(); +#ifdef DEBUG_SERVERAPP_MISC +printf("%s: target application is dead. ServerApp is quitting\n",app_sig.String()); +#endif + return false; + } + return true; +} + +int32 ServerApp::MonitorApp(void *data) +{ + ServerApp *app=(ServerApp *)data; + app->Loop(); + exit_thread(0); + return 0; +} + +void ServerApp::Loop(void) +{ +#ifdef DEBUG_SERVERAPP_MISC +printf("%s: Loop()\n",app_sig.String()); +#endif + // Message-dispatching loop for the ServerApp + int32 msgcode; + int8 *msgbuffer=NULL; + ssize_t buffersize,bytesread; + + for(;;) + { + buffersize=port_buffer_size(receiver); + + if(buffersize>0) + { + // buffers are PortLink messages. Allocate necessary buffer and + // we'll cast it as a BMessage. + msgbuffer=new int8[buffersize]; + bytesread=read_port(receiver,&msgcode,msgbuffer,buffersize); + } + else + bytesread=read_port(receiver,&msgcode,NULL,0); + if (bytesread != B_BAD_PORT_ID && bytesread != B_TIMED_OUT && bytesread != B_WOULD_BLOCK) + { + switch(msgcode) + { +// -------------- Messages received from the Application ------------------ + case B_QUIT_REQUESTED: + { + // Our BApplication sent us this message when it quit. + // We need to ask the app_server to delete our monitor + port_id serverport=find_port(SERVER_PORT_NAME); + if(serverport==B_NAME_NOT_FOUND) + { + printf("PANIC: ServerApp %s could not find the app_server port!\n",app_sig.String()); + break; + } + applink->SetPort(serverport); + applink->SetOpCode(DELETE_APP); + applink->Attach(&monitor_thread,sizeof(thread_id)); + applink->Flush(); + break; + } +/* case CREATE_WINDOW: + + case LAYER_CREATE: + case LAYER_DELETE: + case SHOW_CURSOR: + case HIDE_CURSOR: + case OBSCURE_CURSOR: + case SET_CURSOR_BCURSOR: + case SET_CURSOR_DATA: + case SET_CURSOR_BBITMAP: + + case GFX_MOVEPENBY: + case GFX_MOVEPENTO: + case GFX_SETPENSIZE: + case GFX_COUNT_WORKSPACES: + case GFX_SET_WORKSPACE_COUNT: + case GFX_CURRENT_WORKSPACE: + case GFX_ACTIVATE_WORKSPACE: + case GFX_SYSTEM_COLORS: + case GFX_SET_SCREEN_MODE: + case GFX_GET_SCROLLBAR_INFO: + case GFX_SET_SCROLLBAR_INFO: + case GFX_IDLE_TIME: + case GFX_SELECT_PRINTER_PANEL: + case GFX_ADD_PRINTER_PANEL: + case GFX_RUN_BE_ABOUT: + case GFX_SET_FOCUS_FOLLOWS_MOUSE: + case GFX_FOCUS_FOLLOWS_MOUSE: + + // Graphics messages + case GFX_SET_HIGH_COLOR: + case GFX_SET_LOW_COLOR: + case GFX_DRAW_STRING: + case GFX_SET_FONT_SIZE: + case GFX_STROKE_ARC: + case GFX_STROKE_BEZIER: + case GFX_STROKE_ELLIPSE: + case GFX_STROKE_LINE: + case GFX_STROKE_POLYGON: + case GFX_STROKE_RECT: + case GFX_STROKE_ROUNDRECT: + case GFX_STROKE_SHAPE: + case GFX_STROKE_TRIANGLE: + case GFX_FILL_ARC: + case GFX_FILL_BEZIER: + case GFX_FILL_ELLIPSE: + case GFX_FILL_POLYGON: + case GFX_FILL_RECT: + case GFX_FILL_REGION: + case GFX_FILL_ROUNDRECT: + case GFX_FILL_SHAPE: + case GFX_FILL_TRIANGLE: + DispatchMessage(msgcode, msgbuffer); + break; +*/ +// -------------- Messages received from the Server ------------------------ + // Mouse messages simply get passed onto the active app for now + case B_MOUSE_UP: + case B_MOUSE_DOWN: + case B_MOUSE_MOVED: + { + // everything is formatted as it should be, so just call + // write_port. Eventually, this will be replaced by a + // BMessage + write_port(sender, msgcode, msgbuffer, buffersize); + break; + } + case QUIT_APP: + { + // This message is received from the app_server thread + // because the server was asked to quit. Thus, we + // ask all apps to quit. This is NOT the same as system + // shutdown and will happen only in testing + +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp asking %s to quit\n",app_sig); +#endif + applink->SetOpCode(B_QUIT_REQUESTED); + applink->Flush(); + break; + } + default: + { + +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp received unrecognized code: "); +PrintMessageCodeToStream(msgcode); +#endif + + DispatchMessage(msgcode, msgbuffer); + break; + } + } + + } + + if(buffersize>0) + delete msgbuffer; + + if(msgcode==B_QUIT_REQUESTED) + break; + } +} + +void ServerApp::DispatchMessage(int32 code, int8 *buffer) +{ +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp "); +PrintMessageCode(code); +#endif + +int8 *index=buffer; + switch(code) + { + case CREATE_WINDOW: + { + // Create the ServerWindow to node monitor a new OBWindow + + // Attached data: + // 1) port_id reply port + // 2) BRect window frame + // 3) uint32 window flags + // 4) port_id window's message port + // 5) uint32 workspace index + // 6) const char * title + + // Find the necessary data + port_id reply_port=*((port_id*)index); index+=sizeof(port_id); + + BRect rect=*((BRect*)index); index+=sizeof(BRect); + + uint32 winflags=*((uint32*)index); index+=sizeof(uint32); + + port_id win_port=*((port_id*)index); index+=sizeof(port_id); + + uint32 workspace=*((uint32*)index); index+=sizeof(uint32); + + // Create the ServerWindow object for this window + ServerWindow *newwin=new ServerWindow(rect,(const char *)index, + winflags,this,win_port,workspace); + winlist->AddItem(newwin); + + // Window looper is waiting for our reply. Send back the + // ServerWindow's message port + PortLink *replylink=new PortLink(reply_port); + replylink->SetOpCode(SET_SERVER_PORT); + replylink->Attach((int32)newwin->receiver); + replylink->Flush(); + + delete replylink; + +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp: Create Window()\n"); +printf("Frame: "); rect.PrintToStream(); +printf("Title: %s\n",(const char*)index); +printf("SenderPort: %ld\n",win_port); +printf("Flags: 0x%lx\n",winflags); +printf("Workspace: 0x%lx\n",workspace); +#endif + + break; + + } + case DELETE_WINDOW: + { + // Received from a ServerWindow when its window quits + + // Attached data: + // 1) thread_id ServerWindow ID + thread_id winid; + ServerWindow *w; + for(int32 i=0;iCountItems();i++) + { + w=(ServerWindow*)winlist->ItemAt(i); + if(w->thread==winid) + { + winlist->RemoveItem(w); + delete w; + break; + } + } +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp: Delete Window()\n"); +printf("Thread ID: %ld",winid); +#endif + break; + } + case GFX_SET_SCREEN_MODE: + { + // Attached data + // 1) int32 workspace # + // 2) uint32 screen mode + // 3) bool make default + int32 workspace=*((int32*)index); index+=sizeof(int32); + uint32 mode=*((uint32*)index); index+=sizeof(uint32); + + SetScreenSpace(workspace,mode,*((bool*)index)); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp: SetScreenMode(%ld,%lu,%s)\n",workspace, + mode,(*((bool*)index)==true)?"true":"false"); +#endif + break; + } + case GFX_ACTIVATE_WORKSPACE: + { + // Attached data + // 1) int32 workspace index + ActivateWorkspace(*((int32*)index)); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp: ActivateWorkspace(%ld)\n",*((int32*)index)); +#endif + break; + } + case SHOW_CURSOR: + { + driver->ShowCursor(); + break; + } + case HIDE_CURSOR: + { + driver->HideCursor(); + break; + } + case OBSCURE_CURSOR: + { + driver->ObscureCursor(); + break; + } + case SET_CURSOR_DATA: + { + // Attached data: 68 bytes of cursor data + + // Get the data, update the app's cursor, and update the + // app's cursor if active. + int8 cdata[68]; + memcpy(cdata, buffer, 68); + cursor->SetCursor(cdata); + driver->SetCursor(cursor); +#ifdef DEBUG_SERVERAPP_CURSOR +printf("ServerApp: SetCursor(%d,%d,%d,%d)\n",r,g,b,a); +#endif + break; + } + case SET_CURSOR_BCURSOR: + // Not yet implemented + break; + + case SET_CURSOR_BBITMAP: + // Not yet implemented + break; + + // Graphics messages + case GFX_SET_HIGH_COLOR: + { + // Attached data: + // 1) uint8 red + // 2) uint8 green + // 3) uint8 blue + // 4) uint8 alpha + + uint8 r,g,b,a; + r=*((uint8*)index); index+=sizeof(uint8); + g=*((uint8*)index); index+=sizeof(uint8); + b=*((uint8*)index); index+=sizeof(uint8); + a=*((uint8*)index); + +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp: SetHighColor(%d,%d,%d,%d)\n",r,g,b,a); +#endif + driver->SetHighColor(r,g,b,a); + break; + } + case GFX_SET_LOW_COLOR: + { + // Attached data: + // 1) uint8 red + // 2) uint8 green + // 3) uint8 blue + // 4) uint8 alpha + + uint8 r,g,b,a; + r=*((uint8*)index); index+=sizeof(uint8); + g=*((uint8*)index); index+=sizeof(uint8); + b=*((uint8*)index); index+=sizeof(uint8); + a=*((uint8*)index); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp: SetHighColor(%d,%d,%d,%d)\n",r,g,b,a); +#endif + driver->SetLowColor(r,g,b,a); + break; + } + case GFX_MOVEPENBY: + { + // Attached data: + // 1) BPoint pt + + // Default functionality is MoveTo, so get the current position + // from the driver and compensate + BPoint *ptindex,passed_pt; + + ptindex=(BPoint*)index; + passed_pt=driver->PenPosition(); + passed_pt+=*ptindex; +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp MovePenBy: (%f,%f)\n",ptindex->x,ptindex->y); +printf("Pen moved to (%f,%f)\n",passed_pt.x,passed_pt.y); +#endif + driver->MovePenTo(passed_pt); + break; + } + case GFX_MOVEPENTO: + { + // Attached data: + // 1) BPoint pt + BPoint *pt; + pt=(BPoint*)index; +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp MovePenTo: (%f,%f)\n",pt->x,pt->y); +#endif + driver->MovePenTo(*pt); + break; + } + case GFX_SETPENSIZE: + { + // Attached data: + // 1) float pen size +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp SetPenSize(%f)\n",*((float*)index)); +#endif + driver->SetPenSize(*((float*)index)); + break; + } + case GFX_DRAW_STRING: + { + // Attached data: + // 1) uint16 string length + // 2) char * string + // 3) BPoint point + + uint16 length=*((uint16*)index); index+=sizeof(uint16); +// char *string=new char[length]; +// strcpy(string, (const char *)index); index+=length; + BString string=(char *)index; index+=length; + BPoint point=*((BPoint*)index); + +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp DrawString(%s, %d, BPoint(%f,%f))\n",string.String(),length,point.x,point.y); +#endif + driver->DrawString((char*)string.String(), length, point); +// delete string; + break; + } + case GFX_SET_FONT_SIZE: + break; + case GFX_STROKE_ARC: + { + // Attached data: + // 1) float center x + // 2) float center y + // 3) float x radius + // 4) float y radius + // 5) float starting angle + // 6) float span (arc length in degrees) + // 7) uint8[8] pattern + float cx,cy,rx,ry,angle,span; + + cx=*((float*)index); index+=sizeof(float); + cy=*((float*)index); index+=sizeof(float); + rx=*((float*)index); index+=sizeof(float); + ry=*((float*)index); index+=sizeof(float); + angle=*((float*)index); index+=sizeof(float); + span=*((float*)index); index+=sizeof(float); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp StrokeArc: "); +printf("Center: %f,%f\n",cx,cy); +printf("Radii: %f,%f\n",rx,ry); +printf("Angle, Span: %f,%f\n",angle, span); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->StrokeArc(cx,cy,rx,ry,angle,span,(uint8*)index); + break; + } + case GFX_STROKE_BEZIER: + { + // Attached data: + // 1) BPoint #1 + // 2) BPoint #2 + // 3) BPoint #3 + // 4) BPoint #4 + // 5) uint8[8] pattern + +#ifdef DEBUG_SERVERAPP_MSGS +BPoint *pt=(BPoint*)index; +printf("ServerApp StrokeBezier:\n"); +printf("Point 1: "); pt[0].PrintToStream(); +printf("Point 2: "); pt[1].PrintToStream(); +printf("Point 3: "); pt[2].PrintToStream(); +printf("Point 4: "); pt[3].PrintToStream(); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->StrokeBezier((BPoint*)index,(uint8*)(index+(sizeof(BPoint)*4))); + break; + } + case GFX_STROKE_ELLIPSE: + { + // Attached data: + // 1) float center x + // 2) float center y + // 3) float x radius + // 4) float y radius + // 5) uint8[8] pattern + float cx,cy,rx,ry; + + cx=*((float*)index); index+=sizeof(float); + cy=*((float*)index); index+=sizeof(float); + rx=*((float*)index); index+=sizeof(float); + ry=*((float*)index); index+=sizeof(float); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp StrokeEllipse: "); +printf("Center: %f,%f\n",cx,cy); +printf("Radii: %f,%f\n",rx,ry); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->StrokeEllipse(cx,cy,rx,ry,(uint8*)index); + break; + } + case GFX_STROKE_LINE: + { + // Attached data: + // 1) BPoint endpoint + // 2) uint8[8] pattern + BPoint *pt; + pt=(BPoint*)index; index+=sizeof(BPoint); + +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp StrokeLineTo: (%f,%f)\n",pt->x,pt->y); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->StrokeLine(*pt,(uint8*)index); + break; + } + case GFX_STROKE_POLYGON: + break; + case GFX_STROKE_RECT: + { + // Attached data: + // 1) BRect rect + // 2) uint8[8] pattern + BRect rect; + rect=*((BRect*)index); index+=sizeof(BRect); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp StrokeRect: "); rect.PrintToStream(); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->StrokeRect(rect, (uint8*)index); + break; + } + case GFX_STROKE_ROUNDRECT: + { + // Attached data: + // 1) BRect rect + // 2) float x_radius + // 3) float y_radius + // 4) uint8[8] pattern + BRect rect; + float x,y; + + rect=*((BRect*)index); index+=sizeof(BRect); + x=*((float*)index); index+=sizeof(float); + y=*((float*)index); index+=sizeof(float); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp StrokeRoundRect: "); rect.PrintToStream(); +printf("Radii: %f,%f\n",x,y); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->StrokeRoundRect(rect, x,y,(uint8*)index); + break; + } + case GFX_STROKE_SHAPE: + break; + case GFX_STROKE_TRIANGLE: + { + // Attached data + // 1) BPoint #1 + // 2) BPoint #2 + // 3) BPoint #3 + // 4) BRect invalid rect + // 5) uint8[8] pattern + BPoint pt1,pt2,pt3; + BRect rect; + pt1=*((BPoint*)index); index+=sizeof(BPoint); + pt2=*((BPoint*)index); index+=sizeof(BPoint); + pt3=*((BPoint*)index); index+=sizeof(BPoint); + rect=*((BRect*)index); index+=sizeof(BRect); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp StrokeTriangle: "); +printf("Point 1: "); pt1.PrintToStream(); +printf("Point 2: "); pt2.PrintToStream(); +printf("Point 3: "); pt3.PrintToStream(); +printf("Rectangle: "); rect.PrintToStream(); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->StrokeTriangle(pt1,pt2,pt3,rect,(uint8*)index); + break; + } + case GFX_FILL_ARC: + { + // Attached data: + // 1) float center x + // 2) float center y + // 3) float x radius + // 4) float y radius + // 5) float starting angle + // 6) float span (arc length in degrees) + // 7) uint8[8] pattern + float cx,cy,rx,ry,angle,span; + + cx=*((float*)index); index+=sizeof(float); + cy=*((float*)index); index+=sizeof(float); + rx=*((float*)index); index+=sizeof(float); + ry=*((float*)index); index+=sizeof(float); + angle=*((float*)index); index+=sizeof(float); + span=*((float*)index); index+=sizeof(float); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp FillArc: "); +printf("Center: %f,%f\n",cx,cy); +printf("Radii: %f,%f\n",rx,ry); +printf("Angle, Span: %f,%f\n",angle, span); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->FillArc(cx,cy,rx,ry,angle,span,(uint8*)index); + break; + } + case GFX_FILL_BEZIER: + { + // Attached data: + // 1) BPoint #1 + // 2) BPoint #2 + // 3) BPoint #3 + // 4) BPoint #4 + // 5) uint8[8] pattern + +#ifdef DEBUG_SERVERAPP_MSGS +BPoint *pt=(BPoint*)index; +printf("ServerApp FillBezier:\n"); +printf("Point 1: "); pt[0].PrintToStream(); +printf("Point 2: "); pt[1].PrintToStream(); +printf("Point 3: "); pt[2].PrintToStream(); +printf("Point 4: "); pt[3].PrintToStream(); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->FillBezier((BPoint*)index,(uint8*)(index+(sizeof(BPoint)*4))); + break; + } + case GFX_FILL_ELLIPSE: + { + // Attached data: + // 1) float center x + // 2) float center y + // 3) float x radius + // 4) float y radius + // 5) uint8[8] pattern + float cx,cy,rx,ry; + + cx=*((float*)index); index+=sizeof(float); + cy=*((float*)index); index+=sizeof(float); + rx=*((float*)index); index+=sizeof(float); + ry=*((float*)index); index+=sizeof(float); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp FillEllipse: "); +printf("Center: %f,%f\n",cx,cy); +printf("Radii: %f,%f\n",rx,ry); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->FillEllipse(cx,cy,rx,ry,(uint8*)index); + break; + } + case GFX_FILL_POLYGON: + break; + case GFX_FILL_RECT: + { + // Attached data: + // 1) BRect rect + // 2) uint8[8] pattern + BRect rect; + rect=*((BRect*)index); index+=sizeof(BRect); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp FillRect: "); rect.PrintToStream(); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->FillRect(rect, (uint8*)index); + break; + } + case GFX_FILL_REGION: + break; + case GFX_FILL_ROUNDRECT: + { + // Attached data: + // 1) BRect rect + // 2) float x_radius + // 3) float y_radius + // 4) uint8[8] pattern + BRect rect; + float x,y; + + rect=*((BRect*)index); index+=sizeof(BRect); + x=*((float*)index); index+=sizeof(float); + y=*((float*)index); index+=sizeof(float); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp FillRoundRect: "); rect.PrintToStream(); +printf("Radii: %f,%f\n",x,y); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->FillRoundRect(rect, x,y,(uint8*)index); + break; + } + case GFX_FILL_SHAPE: + break; + case GFX_FILL_TRIANGLE: + { + // Attached data + // 1) BPoint #1 + // 2) BPoint #2 + // 3) BPoint #3 + // 4) BRect invalid rect + // 5) uint8[8] pattern + BPoint pt1,pt2,pt3; + BRect rect; + pt1=*((BPoint*)index); index+=sizeof(BPoint); + pt2=*((BPoint*)index); index+=sizeof(BPoint); + pt3=*((BPoint*)index); index+=sizeof(BPoint); + rect=*((BRect*)index); index+=sizeof(BRect); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp FillTriangle: "); +printf("Point 1: "); pt1.PrintToStream(); +printf("Point 2: "); pt2.PrintToStream(); +printf("Point 3: "); pt3.PrintToStream(); +printf("Rectangle: "); rect.PrintToStream(); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->FillTriangle(pt1,pt2,pt3,rect,(uint8*)index); + break; + } + default: + { +#ifdef DEBUG_SERVERAPP_MSGS +cout << "DispatchMessage::Unrecognized code: "; +TranslateMessageCodeToStream(code); +cout << endl << flush; +#endif + break; + } + } +} + +// Prevent any preprocessor problems in case I screw something up +#ifdef DEBUG_SERVERAPP_MSGS +#undef DEBUG_SERVERAPP_MSGS +#endif + +#ifdef DEBUG_SERVERAPP_CURSORS +#undef DEBUG_SERVERAPP_CURSORS +#endif diff --git a/src/servers/app/proto5/ServerApp.h b/src/servers/app/proto5/ServerApp.h new file mode 100644 index 0000000000..6a53822cbf --- /dev/null +++ b/src/servers/app/proto5/ServerApp.h @@ -0,0 +1,42 @@ +#ifndef _SRVAPP_H_ +#define _SRVAPP_H_ + +#include +#include +class BMessage; +class PortLink; +class BList; +class ServerCursor; +class DisplayDriver; + +class ServerApp +{ +public: + ServerApp(port_id msgport, char *signature); + ~ServerApp(void); + + bool Run(void); + static int32 MonitorApp(void *data); + void Loop(void); + bool IsActive(void) const { return isactive; } + void Activate(bool value) { isactive=value; } + bool PingTarget(void); + +// char *app_sig; + port_id sender,receiver; + BString app_sig; + thread_id monitor_thread; + PortLink *applink; + BList *winlist, *bmplist; + ServerCursor *cursor; + DisplayDriver *driver; + rgb_color high, low; // just for testing until layers are implemented + +protected: + void DispatchMessage(int32 code, int8 *buffer); + + bool isactive; + team_id target_id; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto5/ServerBitmap.cpp b/src/servers/app/proto5/ServerBitmap.cpp new file mode 100644 index 0000000000..ee01f297f3 --- /dev/null +++ b/src/servers/app/proto5/ServerBitmap.cpp @@ -0,0 +1,257 @@ +/* + ServerBitmap.cpp + Bitmap class which is intended to provide an easy way to package all the + data associated with a picture. It's very low-level, so there's still + plenty to do when coding with 'em. Also, they can be used to access draw on the + frame buffer in a relatively easy way, although it is currently unclear + whether this functionality will even be necessary. +*/ + +// These three includes for ServerBitmap(const char *path_to_image_file) only +#include +#include +#include + +#include +#include "ServerBitmap.h" +#include "Desktop.h" + +ServerBitmap::ServerBitmap(BRect rect,color_space space,int32 BytesPerLine=0) +{ + width=rect.IntegerWidth()+1; + height=rect.IntegerHeight()+1; + cspace=space; + is_vram=false; + is_area=false; + areaid=B_ERROR; + + HandleSpace(space, BytesPerLine); + buffer=new uint8[bytesperline*height]; + driver=get_gfxdriver(); +} + +ServerBitmap::ServerBitmap(int32 w,int32 h,color_space space,int32 BytesPerLine=0) +{ + width=w; + height=h; + cspace=space; + is_vram=false; + is_area=false; + areaid=B_ERROR; + + HandleSpace(space, BytesPerLine); + buffer=new uint8[bytesperline*height]; + driver=get_gfxdriver(); +} + +ServerBitmap::ServerBitmap(int32 w,int32 h,color_space space, area_id areaID, int32 BytesPerLine=0) +{ + // This version is used for holding BBitmaps as one of the undocumented BBitmap + // constructors allows - it creates an area on the server's side. + width=w; + height=h; + cspace=space; + is_vram=false; + is_area=true; + + HandleSpace(space, BytesPerLine); + area_info ainfo; + areaid=areaID; + get_area_info(areaid, &ainfo); + buffer=(uint8*)ainfo.address; + driver=get_gfxdriver(); +} + +ServerBitmap::ServerBitmap(void) +{ + // This version is obviously intended for use as an easy-access class for the + // frame buffer. AtheOS does it and it's small, so why not? Worst case, this + // can disappear if not necessary. + is_vram=true; + is_area=false; + areaid=B_ERROR; + UpdateSettings(); +} + +// This particular version is not intended for use except for testing purposes. +// It loads a BBitmap and copies it to the ServerBitmap. Probably will disappear +// when the *real* server is written +ServerBitmap::ServerBitmap(const char *path) +{ + BBitmap *bmp=BTranslationUtils::GetBitmap(path); + assert(bmp!=NULL); + + if(bmp==NULL) + { + width=0; + height=0; + cspace=B_NO_COLOR_SPACE; + bytesperline=0; + } + else + { + width=bmp->Bounds().IntegerWidth(); + height=bmp->Bounds().IntegerHeight(); + cspace=bmp->ColorSpace(); + bytesperline=bmp->BytesPerRow(); + buffer=new uint8[bmp->BitsLength()]; + memcpy(buffer,(void *)bmp->Bits(),bmp->BitsLength()); + } +} + +ServerBitmap::~ServerBitmap(void) +{ + if(!is_vram) + delete buffer; +} + +void ServerBitmap::UpdateSettings(void) +{ + // This is only used when the object is pointing to the frame buffer + driver=get_gfxdriver(); + bpp=driver->GetDepth(); + width=driver->GetWidth(); + height=driver->GetHeight(); +} + +void ServerBitmap::SetBuffer(void *buffer) +{ + buffer=(uint8 *)buffer; +} + +uint8 *ServerBitmap::Buffer(void) +{ + return buffer; +} + +uint32 ServerBitmap::BitsLength(void) +{ + return (uint32)(bytesperline*height); +} + +void ServerBitmap::HandleSpace(color_space space, int32 BytesPerLine) +{ + // Function written to handle color space setup which is required + // by the two "normal" constructors + + // Big convoluted mess just to handle every color space and dword align + // the buffer + switch(space) + { + // Buffer is dword-aligned, so nothing need be done + // aside from allocate the memory + case B_RGB32: + case B_RGBA32: + case B_RGB32_BIG: + case B_RGBA32_BIG: + case B_UVL32: + case B_UVLA32: + case B_LAB32: + case B_LABA32: + case B_HSI32: + case B_HSIA32: + case B_HSV32: + case B_HSVA32: + case B_HLS32: + case B_HLSA32: + case B_CMY32: + case B_CMYA32: + case B_CMYK32: + + // 24-bit = 32-bit with extra 8 bits ignored + case B_RGB24_BIG: + case B_RGB24: + case B_LAB24: + case B_UVL24: + case B_HSI24: + case B_HSV24: + case B_HLS24: + case B_CMY24: + { + if(BytesPerLine<(width*4)) + bytesperline=width*4; + else + bytesperline=BytesPerLine; + bpp=32; + break; + } + // Calculate size and dword-align + + // 1-bit + case B_GRAY1: + { + int32 numbytes=width>>3; + if((width % 8) != 0) + numbytes++; + if(BytesPerLine +#include +#include +#include "DisplayDriver.h" + +class ServerBitmap +{ +public: + ServerBitmap(BRect rect,color_space space,int32 BytesPerLine=0); + ServerBitmap(int32 w,int32 h,color_space space,int32 BytesPerLine=0); + ServerBitmap(int32 w,int32 h,color_space space, area_id areaID, int32 BytesPerLine=0); + ServerBitmap(void); + ServerBitmap(const char *path); + ~ServerBitmap(void); + void UpdateSettings(void); + void SetBuffer(void *buffer); + uint8 *Buffer(void); + void SetArea(area_id ID); + area_id Area(void); + uint32 BitsLength(void); + + int32 width,height; + int32 bytesperline; + color_space cspace; + int bpp; + +protected: + void HandleSpace(color_space space, int32 BytesPerLine); + DisplayDriver *driver; + bool is_vram,is_area; + area_id areaid; + uint8 *buffer; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto5/ServerCursor.cpp b/src/servers/app/proto5/ServerCursor.cpp new file mode 100644 index 0000000000..bb11e51760 --- /dev/null +++ b/src/servers/app/proto5/ServerCursor.cpp @@ -0,0 +1,136 @@ +/* + ServerCursor.cpp + This is the server-side class used to handle cursors. Note that it + will handle the R5 cursor API, but it will also handle taking a bitmap. + + ServerCursors are 32-bit. Eventually, we will be mapping colors to fit + when the set is called. + + This is new code, and there may be changes to the API before it settles + in. +*/ + +#include "ServerCursor.h" +#include "ServerBitmap.h" +#include +#include + +int8 default_cursor[]={ + 16,1,0,0, + + // data + 0xff, 0x80, 0x80, 0x80, 0x81, 0x00, 0x80, 0x80, 0x80, 0x40, 0x80, 0x80, 0x81, 0x00, 0xa2, 0x00, + 0xd4, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + // mask + 0xff, 0x80, 0xff, 0x80, 0xff, 0x00, 0xff, 0x80, 0xff, 0xc0, 0xff, 0x80, 0xff, 0x00, 0xfe, 0x00, + 0xdc, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +long pow2(int power) +{ + if(power==0) + return 1; + return long(2 << (power-1)); +} + +ServerCursor::ServerCursor(void) +{ + // For when an application is started. This will probably disappear once I + // get the stuff for default cursors established + is_initialized=false; + position.Set(0,0); +} + +ServerCursor::ServerCursor(ServerBitmap *bmp, ServerBitmap *cmask=NULL) +{ + // The OpenBeOS R1 API uses Bitmaps to create cursors - more flexibility that way. + is_initialized=false; + position.Set(0,0); + SetCursor(bmp); +} + +ServerCursor::ServerCursor(int8 *data) +{ + // For handling the idiot R5 API data format + is_initialized=false; + position.Set(0,0); + SetCursor(data); +} + +ServerCursor::~ServerCursor(void) +{ + if(is_initialized) + delete bitmap; +} + +void ServerCursor::SetCursor(int8 *data) +{ + // 68-byte array used in R5 for holding cursors. + // This API has serious problems and should be deprecated(but supported) + // in a future release, perhaps right after the first one + + if(is_initialized) + { + delete bitmap; + } + cspace=B_RGBA32; + + bitmap=new ServerBitmap(16,16,B_RGBA32); + width=16; + height=16; + bounds.Set(0,0,15,15); + + // Now that we have all the setup, we're going to map (for now) the cursor + // to RGBA32. Eventually, there will be support for 16 and 8-bit depths + uint32 black=0xFF000000, + white=0xFFFFFFFF, + *bmppos; + uint16 *cursorpos, *maskpos,cursorflip, maskflip, + cursorval, maskval; + uint8 i,j; + + cursorpos=(uint16*)(data+4); + maskpos=(uint16*)(data+36); + + // for each row in the cursor data + for(j=0;j<16;j++) + { + bmppos=(uint32*)(bitmap->Buffer()+ (j*bitmap->bytesperline) ); + + // On intel, our bytes end up swapped, so we must swap them back + cursorflip=(cursorpos[j] & 0xFF) << 8; + cursorflip |= (cursorpos[j] & 0xFF00) >> 8; + maskflip=(maskpos[j] & 0xFF) << 8; + maskflip |= (maskpos[j] & 0xFF00) >> 8; + + // for each column in each row of cursor data + for(i=0;i<16;i++) + { + // Get the values and dump them to the bitmap + cursorval=cursorflip & pow2(15-i); + maskval=maskflip & pow2(15-i); + bmppos[i]=((cursorval!=0)?black:white) & ((maskval>0)?0xFFFFFFFF:0x00FFFFFF); + } + } +} + +// Currently unimplemented +void ServerCursor::SetCursor(ServerBitmap *bmp, ServerBitmap *cmask=NULL) +{ +/* if(is_initialized) + delete bitmap; + cspace=bmp->cspace; + + bitmap=new ServerBitmap(bmp->width,bmp->height,cspace); + + width=bmp->width; + height=bmp->height; + bounds.Set(0,0,bmp->width-1,bmp->height-1); +*/ +} + +void ServerCursor::MoveTo(int32 x, int32 y) +{ + position.Set(x,y); +} diff --git a/src/servers/app/proto5/ServerCursor.h b/src/servers/app/proto5/ServerCursor.h new file mode 100644 index 0000000000..b75b822acb --- /dev/null +++ b/src/servers/app/proto5/ServerCursor.h @@ -0,0 +1,31 @@ +#ifndef _SERVER_SPRITE_H +#define _SERVER_SPRITE_H + +#include +#include + +class ServerBitmap; + +class ServerCursor +{ +public: + ServerCursor(ServerBitmap *bmp,ServerBitmap *cmask=NULL); + ServerCursor(int8 *data); + ServerCursor(void); + ~ServerCursor(void); + void MoveTo(int32 x, int32 y); + void SetCursor(int8 *data); + void SetCursor(ServerBitmap *bmp, ServerBitmap *cmask=NULL); + + ServerBitmap *bitmap; + + color_space cspace; + BRect bounds; + int width,height; + BPoint position,hotspot; + bool is_initialized; +}; + +extern int8 default_cursor[]; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto5/ServerProtocol.h b/src/servers/app/proto5/ServerProtocol.h new file mode 100644 index 0000000000..d2138e2c1b --- /dev/null +++ b/src/servers/app/proto5/ServerProtocol.h @@ -0,0 +1,95 @@ +#ifndef _APPSERVER_PROTOCOL_ +#define _APPSERVER_PROTOCOL_ + +#define CREATE_APP 'drca' +#define DELETE_APP 'drda' +#define QUIT_APP 'srqa' + +#define SET_SERVER_PORT 'srsp' + +#define CREATE_WINDOW 'drcw' +#define DELETE_WINDOW 'drdw' +#define SHOW_WINDOW 'drsw' +#define HIDE_WINDOW 'drhw' +#define QUIT_WINDOW 'srqw' + +#define SERVER_PORT_NAME "OBappserver" +#define SERVER_INPUT_PORT "OBinputport" + +#define SET_CURSOR_DATA 'sscd' +#define SET_CURSOR_BCURSOR 'sscb' +#define SET_CURSOR_BBITMAP 'sscB' +#define SHOW_CURSOR 'srsc' +#define HIDE_CURSOR 'srhc' +#define OBSCURE_CURSOR 'sroc' + +#define GFX_COUNT_WORKSPACES 'gcws' +#define GFX_SET_WORKSPACE_COUNT 'ggwc' +#define GFX_CURRENT_WORKSPACE 'ggcw' +#define GFX_ACTIVATE_WORKSPACE 'gaws' +#define GFX_GET_SYSTEM_COLORS 'gsyc' +#define GFX_SET_SYSTEM_COLORS 'gsyc' +#define GFX_SET_SCREEN_MODE 'gssm' +#define GFX_GET_SCROLLBAR_INFO 'ggsi' +#define GFX_SET_SCROLLBAR_INFO 'gssi' +#define GFX_IDLE_TIME 'gidt' +#define GFX_SELECT_PRINTER_PANEL 'gspp' +#define GFX_ADD_PRINTER_PANEL 'gapp' +#define GFX_RUN_BE_ABOUT 'grba' +#define GFX_SET_FOCUS_FOLLOWS_MOUSE 'gsfm' +#define GFX_FOCUS_FOLLOWS_MOUSE 'gffm' + +#define GFX_SET_HIGH_COLOR 'gshc' +#define GFX_SET_LOW_COLOR 'gslc' +#define GFX_SET_VIEW_COLOR 'gsvc' + +#define GFX_STROKE_ARC 'gsar' +#define GFX_STROKE_BEZIER 'gsbz' +#define GFX_STROKE_ELLIPSE 'gsel' +#define GFX_STROKE_LINE 'gsln' +#define GFX_STROKE_POLYGON 'gspy' +#define GFX_STROKE_RECT 'gsrc' +#define GFX_STROKE_ROUNDRECT 'gsrr' +#define GFX_STROKE_SHAPE 'gssh' +#define GFX_STROKE_TRIANGLE 'gstr' + +#define GFX_FILL_ARC 'gfar' +#define GFX_FILL_BEZIER 'gfbz' +#define GFX_FILL_ELLIPSE 'gfel' +#define GFX_FILL_POLYGON 'gfpy' +#define GFX_FILL_RECT 'gfrc' +#define GFX_FILL_REGION 'gfrg' +#define GFX_FILL_ROUNDRECT 'gfrr' +#define GFX_FILL_SHAPE 'gfsh' +#define GFX_FILL_TRIANGLE 'gftr' + +#define GFX_MOVEPENBY 'gmpb' +#define GFX_MOVEPENTO 'gmpt' +#define GFX_SETPENSIZE 'gsps' + +#define GFX_DRAW_STRING 'gdst' +#define GFX_SET_FONT 'gsft' +#define GFX_SET_FONT_SIZE 'gsfs' + +#define GFX_FLUSH 'gfsh' +#define GFX_SYNC 'gsyn' + +#define LAYER_CREATE 'lycr' +#define LAYER_DELETE 'lydl' +#define LAYER_ADD_CHILD 'lyac' +#define LAYER_REMOVE_CHILD 'lyrc' +#define LAYER_REMOVE_SELF 'lyrs' +#define LAYER_SHOW 'lysh' +#define LAYER_HIDE 'lyhd' +#define LAYER_MOVE 'lymv' +#define LAYER_RESIZE 'lyre' +#define LAYER_INVALIDATE 'lyin' +#define LAYER_DRAW 'lydr' + +#define BEGIN_RECT_TRACKING 'rtbg' +#define END_RECT_TRACKING 'rten' + +#define VIEW_GET_TOKEN 'vgtk' +#define VIEW_ADD 'vadd' +#define VIEW_REMOVE 'vrem' +#endif \ No newline at end of file diff --git a/src/servers/app/proto5/ServerSprite.cpp b/src/servers/app/proto5/ServerSprite.cpp new file mode 100644 index 0000000000..915e487dd3 --- /dev/null +++ b/src/servers/app/proto5/ServerSprite.cpp @@ -0,0 +1,29 @@ +#include "ServerCursor.h" +#include "ServerBitmap.h" + +ServerCursor::ServerCursor(ServerBitmap *bmp) +{ +} + +ServerCursor::~ServerCursor(void) +{ +} + +ServerCursor::SetCursor(int8 *data) +{ + // 68-byte array used in R5 for holding cursors. + // This API has serious problems and should be deprecated(but supported) + // in a future release, perhaps the first one(?) +} + +void ServerCursor::SaveClientData(void) +{ +} + +void ServerCursor::MoveTo(int32 x, int32 y) +{ +} + +void ServerCursor::SetClient(ServerBitmap *bmp) +{ +} \ No newline at end of file diff --git a/src/servers/app/proto5/ServerWindow.cpp b/src/servers/app/proto5/ServerWindow.cpp new file mode 100644 index 0000000000..25302fca52 --- /dev/null +++ b/src/servers/app/proto5/ServerWindow.cpp @@ -0,0 +1,462 @@ +/* + ServerWindow.cpp + Class which works with a BWindow. Handles all messages coming from and + going to its window plus all drawing calls. +*/ +#include +#include +#include +#include +#include +#include // for B_XXXXX_MOUSE_BUTTON defines +#include "AppServer.h" +#include "Layer.h" +#include "PortLink.h" +#include "ServerWindow.h" +#include "ServerApp.h" +#include "ServerProtocol.h" +#include "WindowBorder.h" +#include "DebugTools.h" + +//#define DEBUG_SERVERWIN + +// Used for providing identifiers for views +int32 view_counter=0; +bool movewin=false; + +ServerWindow::ServerWindow(BRect rect, const char *string, uint32 winflags, + ServerApp *winapp, port_id winport, uint32 index) +{ + title=new BString; + if(string) + title->SetTo(string); + else + title->SetTo("Window"); +#ifdef DEBUG_SERVERWIN +printf("ServerWindow() %s\n",title->String()); +#endif + + // This must happen before the WindowBorder object - it needs this object's frame + // to be valid + frame=rect; + + winborder=new WindowBorder(this, title->String()); + + // hard code this for now - window look also needs to be attached and sent to + // server by BWindow constructor + decorator=instantiate_decorator(winborder, winflags, B_TITLED_WINDOW_LOOK); + winborder->SetDecorator(decorator); + + + // sender is the monitored app's event port + sender=winport; + winlink=new PortLink(sender); + + if(winapp!=NULL) + applink=new PortLink(winapp->receiver); + else + applink=NULL; + + // receiver is the port to which the app sends messages for the server + receiver=create_port(30,title->String()); + + active=false; + hidecount=0; + + // Spawn our message monitoring thread + thread=spawn_thread(MonitorWin,title->String(),B_NORMAL_PRIORITY,this); + if(thread!=B_NO_MORE_THREADS && thread!=B_NO_MEMORY) + resume_thread(thread); + + workspace=index; + + AddWindowToDesktop(this,index); +} + +ServerWindow::~ServerWindow(void) +{ +#ifdef DEBUG_SERVERWIN +printf("%s::~ServerWindow()\n",title->String()); +#endif + RemoveWindowFromDesktop(this); + if(applink!=NULL) + delete applink; + delete title; + delete winlink; + delete decorator; + delete winborder; + kill_thread(thread); +} + +void ServerWindow::RequestDraw(BRect rect) +{ + winlink->SetOpCode(LAYER_DRAW); + winlink->Attach(&rect,sizeof(BRect)); + winlink->Flush(); +} + +void ServerWindow::ReplaceDecorator(void) +{ +#ifdef DEBUG_SERVERWIN +printf("%s::ReplaceDecorator()\n",title->String()); +#endif +} + +void ServerWindow::Quit(void) +{ +#ifdef DEBUG_SERVERWIN +printf("%s::Quit()\n",title->String()); +#endif +} + +const char *ServerWindow::GetTitle(void) +{ + return title->String(); +} + +ServerApp *ServerWindow::GetApp(void) +{ + return app; +} + +void ServerWindow::Show(void) +{ +#ifdef DEBUG_SERVERWIN +printf("%s::Show()\n",title->String()); +#endif + if(winborder) + { + winborder->ShowLayer(); + winborder->Draw(frame); + } +} + +void ServerWindow::Hide(void) +{ +#ifdef DEBUG_SERVERWIN +printf("%s::Hide()\n",title->String()); +#endif + if(winborder) + winborder->HideLayer(); +} + +bool ServerWindow::IsHidden(void) +{ + return (hidecount==0)?true:false; +} + +void ServerWindow::SetFocus(bool value) +{ +#ifdef DEBUG_SERVERWIN +printf("%s::SetFocus(%s)\n",title->String(),(value==true)?"true":"false"); +#endif + active=value; +} + +bool ServerWindow::HasFocus(void) +{ + return active; +} + +void ServerWindow::WorkspaceActivated(int32 NewWorkspace, const BPoint Resolution, color_space CSpace) +{ +} + +void ServerWindow::WindowActivated(bool Active) +{ +} + +void ServerWindow::ScreenModeChanged(const BPoint Resolustion, color_space CSpace) +{ +} + +void ServerWindow::SetFrame(const BRect &rect) +{ +#ifdef DEBUG_SERVERWIN +printf("%s::SetFrame()",title->String()); rect.PrintToStream(); +#endif + frame=rect; +} + +BRect ServerWindow::Frame(void) +{ + return frame; +} + +status_t ServerWindow::Lock(void) +{ +#ifdef DEBUG_SERVERWIN +printf("%s::Lock()\n",title->String()); +#endif + return locker.Lock(); +} + +void ServerWindow::Unlock(void) +{ +#ifdef DEBUG_SERVERWIN +printf("%s::Unlock()\n",title->String()); +#endif + locker.Unlock(); +} + +bool ServerWindow::IsLocked(void) +{ + return locker.IsLocked(); +} + +void ServerWindow::Loop(void) +{ + // Message-dispatching loop for the ServerWindow + +#ifdef DEBUG_SERVERWIN +printf("%s::Loop()\n",title->String()); +#endif + int32 msgcode; + int8 *msgbuffer=NULL; + ssize_t buffersize,bytesread; + + for(;;) + { + buffersize=port_buffer_size(receiver); + + if(buffersize>0) + { + msgbuffer=new int8[buffersize]; + bytesread=read_port(receiver,&msgcode,msgbuffer,buffersize); + } + else + bytesread=read_port(receiver,&msgcode,NULL,0); + + if (bytesread != B_BAD_PORT_ID && bytesread != B_TIMED_OUT && bytesread != B_WOULD_BLOCK) + { + switch(msgcode) + { + case LAYER_CREATE: + { + // Received when a view is attached to a window. This will require + // us to attach a layer in the tree in the same manner and invalidate + // the area in which the new layer resides assuming that it is + // visible + + // Attached Data: + // 1) (int32) id of the parent view + // 2) (int32) id of the child view + // 3) (BRect) frame in parent's coordinates + // 4) (int32) resize flags + // 5) (int32) view flags + // 6) (uint16) view's hide level + + break; + } + case LAYER_DELETE: + { + // Received when a view is detached from a window. This is definitely + // the less taxing operation - we call PruneTree() on the removed + // layer, detach the layer itself, delete it, and invalidate the + // area assuming that the view was visible when removed + + // Attached Data: + // 1) (int32) id of the removed view + break; + } + case SHOW_WINDOW: + { + Show(); + break; + } + case HIDE_WINDOW: + { + Hide(); + break; + } + case DELETE_WINDOW: + { + // Received from our window when it is told to quit, so tell our + // application to delete this object + applink->SetOpCode(DELETE_WINDOW); + applink->Attach((int32)thread); + applink->Flush(); + break; + } + case VIEW_GET_TOKEN: + { + // Request to get a view identifier - this is synchronous, so reply + // immediately + + // Attached data: + // 1) port_id reply port + port_id reply_port=*((port_id*)msgbuffer); + PortLink *link=new PortLink(reply_port); + link->Attach(view_counter++); + link->Flush(); + break; + } + default: + DispatchMessage(msgcode,msgbuffer); + break; + } + + } + + if(buffersize>0) + delete msgbuffer; + + if(msgcode==B_QUIT_REQUESTED) + break; + } +} + +void ServerWindow::DispatchMessage(int32 code, int8 *msgbuffer) +{ + switch(code) + { + default: + { +#ifdef DEBUG_SERVERWIN +printf("%s::ServerWindow(): Received unexpected code: ",title->String()); +PrintMessageCode(code); +#endif + break; + } + } +} + +int32 ServerWindow::MonitorWin(void *data) +{ + ServerWindow *win=(ServerWindow *)data; + win->Loop(); + exit_thread(0); + return 0; +} + +void ServerWindow::HandleMouseEvent(int32 code, int8 *buffer) +{ + ServerWindow *mousewin=NULL; + int8 *index=buffer; + + // Find the window which will receive our mouse event. + Layer *root=GetRootLayer(); + WindowBorder *winborder; + ASSERT(root!=NULL); + + // Dispatch the mouse event to the proper window + switch(code) + { + case B_MOUSE_DOWN: + { + // Attached data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - modifier keys down + // 5) int32 - buttons down + // 6) int32 - clicks + +// int64 time=*((int64*)index); + index+=sizeof(int64); + float x=*((float*)index); + index+=sizeof(float); + float y=*((float*)index); + index+=sizeof(float); +// int32 modifiers=*((int32*)index); + index+=sizeof(uint32); + uint32 buttons=*((uint32*)index); + index+=sizeof(uint32); +// int32 clicks=*((int32*)index); + BPoint pt(x,y); + + // If we have clicked on a window, + winborder=(WindowBorder*)root->GetChildAt(pt); + if(winborder) + { + mousewin=winborder->Window(); + ASSERT(mousewin!=NULL); + + winborder->MouseDown(pt,buttons); + +#ifdef DEBUG_SERVERWIN +printf("ServerWindow() %s: MouseDown(%.1f,%.1f)\n",mousewin->title->String(),x,y); +#endif + } + break; + } + case B_MOUSE_UP: + { + // Attached data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - modifier keys down + +// int64 time=*((int64*)index); + index+=sizeof(int64); + float x=*((float*)index); + index+=sizeof(float); + float y=*((float*)index); + index+=sizeof(float); +// int32 modifiers=*((int32*)index); + BPoint pt(x,y); + + is_moving_window=false; + winborder=(WindowBorder*)root->GetChildAt(pt); + if(winborder) + { + mousewin=winborder->Window(); + ASSERT(mousewin!=NULL); + + // Eventually, we will build in MouseUp messages with buttons specified + // For now, we just "assume" no mouse specification with a 0. + winborder->MouseUp(pt,0); + + // Do cool mouse stuff here + +#ifdef DEBUG_SERVERWIN +printf("ServerWindow() %s: MouseUp(%.1f,%.1f)\n",mousewin->title->String(),x,y); +#endif + } + break; + } + case B_MOUSE_MOVED: + { + // Attached data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - buttons down +// int64 time=*((int64*)index); + index+=sizeof(int64); + float x=*((float*)index); + index+=sizeof(float); + float y=*((float*)index); + index+=sizeof(float); + uint32 buttons=*((uint32*)index); + BPoint pt(x,y); + + winborder=(WindowBorder*)root->GetChildAt(pt); + if(activeborder) + winborder=activeborder; + if(winborder) + { + mousewin=winborder->Window(); + ASSERT(mousewin!=NULL); + + winborder->MouseMoved(pt,buttons); + + // Do cool mouse stuff here + +#ifdef DEBUG_SERVERWIN +printf("ServerWindow() %s: MouseMoved(%.1f,%.1f)\n",mousewin->title->String(),x,y); +#endif + } + break; + } + default: + { +#ifdef DEBUG_SERVERWIN +printf("HandleMouseEvent() received an unrecognized mouse event"); +PrintMessageCode(code); +#endif + break; + } + } +} diff --git a/src/servers/app/proto5/ServerWindow.h b/src/servers/app/proto5/ServerWindow.h new file mode 100644 index 0000000000..424256949b --- /dev/null +++ b/src/servers/app/proto5/ServerWindow.h @@ -0,0 +1,73 @@ +#ifndef _SERVERWIN_H_ +#define _SERVERWIN_H_ + +#include +#include +#include +#include +#include +#include + +class BString; +class BMessenger; +class BPoint; +class ServerApp; +class Decorator; +class PortLink; +class WindowBorder; + +class ServerWindow +{ +public: + ServerWindow(BRect rect, const char *string, uint32 winflags, + ServerApp *winapp, port_id winport, uint32 index); + ~ServerWindow(void); + + void ReplaceDecorator(void); + void Quit(void); + const char *GetTitle(void); + ServerApp *GetApp(void); + void Show(void); + void Hide(void); + bool IsHidden(void); + void SetFocus(bool value); + bool HasFocus(void); + void RequestDraw(BRect rect); + + void WorkspaceActivated(int32 NewDesktop, const BPoint Resolution, color_space CSpace); + void WindowActivated(bool Active); + void ScreenModeChanged(const BPoint Resolution, color_space CSpace); + + void SetFrame(const BRect &rect); + BRect Frame(void); + + status_t Lock(void); + void Unlock(void); + bool IsLocked(void); + + void DispatchMessage(int32 code, int8 *msgbuffer); + static int32 MonitorWin(void *data); + static void HandleMouseEvent(int32 code, int8 *buffer); + void Loop(void); + + BString *title; + int32 flags; + int32 workspace; + bool active; + + ServerApp *app; + + Decorator *decorator; + WindowBorder *winborder; + bigtime_t lasthit; // Time of last mouse click + + thread_id thread; + port_id receiver; // Messages from window + port_id sender; // Messages to window + PortLink *winlink,*applink; + BLocker locker; + BRect frame; + uint8 hidecount; +}; + +#endif diff --git a/src/servers/app/proto5/SystemPalette.cpp b/src/servers/app/proto5/SystemPalette.cpp new file mode 100644 index 0000000000..3a388ed6b4 --- /dev/null +++ b/src/servers/app/proto5/SystemPalette.cpp @@ -0,0 +1,327 @@ +/* + SystemPalette.cpp + One global function to generate the palette which is the default BeOS + System palette and the variable to go with it +*/ + +#include "SystemPalette.h" + +rgb_color SystemPalette[256]; + +void GenerateSystemPalette(rgb_color *palette) +{ + int i,j,index=0; + int indexvals1[]={ 255,229,204,179,154,129,105,80,55,30 }, + indexvals2[]={ 255,203,152,102,51,0 }; + rgb_color *currentcol; + + // Grays 0,0,0 -> 248,248,248 by 8's + for(i=0; i<=248; i+=8,index++) + { + currentcol=&(palette[index]); + currentcol->red=i; + currentcol->green=i; + currentcol->blue=i; + currentcol->alpha=255; + } + + // Blues, following indexvals1 + for(i=0; i<10; i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=0; + currentcol->green=0; + currentcol->blue=indexvals1[i]; + currentcol->alpha=255; + } + + // Reds, following indexvals1 - 1 + for(i=0; i<10; i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=indexvals1[i] - 1; + currentcol->green=0; + currentcol->blue=0; + currentcol->alpha=255; + } + + // Greens, following indexvals1 - 1 + for(i=0; i<10; i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=0; + currentcol->green=indexvals1[i] - 1; + currentcol->blue=0; + currentcol->alpha=255; + } + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=152; + currentcol->blue=51; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=255; + currentcol->blue=255; + index++; + + for(j=1;j<5;j++) + { + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=indexvals2[j]; + currentcol->green=255; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + } + + for(i=0;i<4;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=255; + currentcol->green=152; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=102; + currentcol->blue=51; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=102; + currentcol->blue=0; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=102; + currentcol->blue=255; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=102; + currentcol->blue=203; + index++; + + // Mostly array runs from here on out + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=203; + currentcol->green=203; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=152; + currentcol->green=255; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=102; + currentcol->green=255; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=51; + currentcol->green=255; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=255; + currentcol->green=102; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=102; + currentcol->blue=152; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=102; + currentcol->blue=102; + index++; + + // knocks out 4 assignment loops at once :) + for(j=1;j<5;j++) + { + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=indexvals2[j]; + currentcol->green=152; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + } + + currentcol+=sizeof(rgb_color); + currentcol->red=230; + currentcol->green=134; + currentcol->blue=0; + index++; + + for(i=1;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=255; + currentcol->green=51; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=102; + currentcol->blue=51; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=102; + currentcol->blue=0; + index++; + + for(j=1;j<5;j++) + { + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=indexvals2[j]; + currentcol->green=102; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + } + + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=255; + currentcol->green=0; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=175; + currentcol->blue=19; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=51; + currentcol->blue=255; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=51; + currentcol->blue=203; + index++; + + for(j=1;j<5;j++) + { + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=indexvals2[j]; + currentcol->green=51; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + } + + for(i=3;i>=0;i--,index++) + { + currentcol=&(palette[index]); + currentcol->red=255; + currentcol->green=203; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + for(i=2;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=0; + currentcol->green=51; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + for(i=0;i<5;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=203; + currentcol->green=0; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=227; + currentcol->blue=70; + index++; + + for(j=2;j<6;j++) + { + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=indexvals2[j]; + currentcol->green=0; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + } + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=203; + currentcol->blue=51; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=203; + currentcol->blue=0; + index++; + + for(i=5;i<=0;i--,index++) + { + currentcol=&(palette[index]); + currentcol->red=255; + currentcol->green=255; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + +} diff --git a/src/servers/app/proto5/SystemPalette.h b/src/servers/app/proto5/SystemPalette.h new file mode 100644 index 0000000000..0fb99d0fed --- /dev/null +++ b/src/servers/app/proto5/SystemPalette.h @@ -0,0 +1,9 @@ +#ifndef _SYSTEM_PALETTE_H_ +#define _SYSTEM_PALETTE_H_ + +#include + +void GenerateSystemPalette(rgb_color *palette); +extern rgb_color SystemPalette[]; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto5/TODO b/src/servers/app/proto5/TODO new file mode 100644 index 0000000000..30d5887c1c --- /dev/null +++ b/src/servers/app/proto5/TODO @@ -0,0 +1,3 @@ +Finish Layers code which is declared in header but unimplemented + +Add Layer::Frame() \ No newline at end of file diff --git a/src/servers/app/proto5/ViewDriver.cpp b/src/servers/app/proto5/ViewDriver.cpp new file mode 100644 index 0000000000..2979ee4b17 --- /dev/null +++ b/src/servers/app/proto5/ViewDriver.cpp @@ -0,0 +1,1558 @@ +/* + ViewDriver: + First, slowest, and easiest driver class in the app_server which is designed + to utilize the BeOS graphics functions to cut out a lot of junk in getting the + drawing infrastructure in this server. + + The concept is to have VDView::Draw() draw a bitmap, which is a "frame buffer" + of sorts, utilize a second view to write to it. This cuts out + the most problems with having a crapload of code to get just right without + having to write a bunch of unit tests + + Components: 3 classes, VDView, VDWindow, and ViewDriver + + ViewDriver - a wrapper class which mostly posts messages to the VDWindow + VDWindow - does most of the work. + VDView - doesn't do all that much except display the rendered bitmap +*/ + +//#define DEBUG_DRIVER_MODULE +//#define DEBUG_SERVER_EMU + +//#define DISABLE_SERVER_EMU + +#include +#include +#include +#include +#include +#include "PortLink.h" +#include "ServerProtocol.h" +#include "ServerBitmap.h" +#include "ViewDriver.h" +#include "ServerCursor.h" +#include "DebugTools.h" + +// Message defines for internal use only +enum +{ +VDWIN_CLEAR=100, +VDWIN_SAFEMODE, +VDWIN_RESET, +VDWIN_SETSCREEN, + +VDWIN_FILLARC, +VDWIN_STROKEARC, +VDWIN_FILLRECT, +VDWIN_STROKERECT, +VDWIN_FILLROUNDRECT, +VDWIN_STROKEROUNDRECT, +VDWIN_FILLELLIPSE, +VDWIN_STROKEELLIPSE, +VDWIN_FILLBEZIER, +VDWIN_STROKEBEZIER, +VDWIN_FILLTRIANGLE, +VDWIN_STROKETRIANGLE, +VDWIN_STROKELINE, +VDWIN_DRAWSTRING, + +VDWIN_SETPENSIZE, +VDWIN_MOVEPENTO, +VDWIN_SHOWCURSOR, +VDWIN_HIDECURSOR, +VDWIN_OBSCURECURSOR, +VDWIN_MOVECURSOR, +VDWIN_SETCURSOR, +VDWIN_SETHIGHCOLOR, +VDWIN_SETLOWCOLOR +}; + +VDView::VDView(BRect bounds) + : BView(bounds,"viewdriver_view",B_FOLLOW_ALL, B_WILL_DRAW) +{ + viewbmp=new BBitmap(bounds,B_RGB32,true); + drawview=new BView(viewbmp->Bounds(),"drawview",B_FOLLOW_ALL, B_WILL_DRAW); + + // This link for sending mouse messages to the OBAppServer. + // This is only to take the place of the Input Server. I suppose I could write + // an addon filter to be more like the Input Server, but then I wouldn't be working + // on this thing! :P + serverlink=new PortLink(find_port(SERVER_INPUT_PORT)); + +#ifdef DEBUG_DRIVER_MODULE + printf("VDView: app_server input port: %ld\n",serverlink->GetPort()); +#endif + + hide_cursor=0; + obscure_cursor=false; + + // Create a cursor which isn't just a box + cursor=new BBitmap(BRect(0,0,20,20),B_RGBA32,true); + BView *v=new BView(cursor->Bounds(),"v", B_FOLLOW_NONE, B_WILL_DRAW); + + cursor->Lock(); + cursor->AddChild(v); + + v->SetHighColor(255,255,255,0); + v->FillRect(cursor->Bounds()); + v->SetHighColor(255,0,0,255); + v->FillTriangle(cursor->Bounds().LeftTop(),cursor->Bounds().RightTop(),cursor->Bounds().LeftBottom()); + + cursor->RemoveChild(v); + cursor->Unlock(); + + cursorframe=cursor->Bounds(); + oldcursorframe=cursor->Bounds(); +} + +VDView::~VDView(void) +{ + delete viewbmp; + delete serverlink; + delete cursor; +} + +void VDView::AttachedToWindow(void) +{ +// printf("VDView::AttachedToWindow()\n"); +} + +void VDView::Draw(BRect rect) +{ + DrawBitmapAsync(viewbmp,oldcursorframe,oldcursorframe); + DrawBitmapAsync(viewbmp,rect,rect); + + if(hide_cursor==0 && obscure_cursor==false) + { + SetDrawingMode(B_OP_ALPHA); + DrawBitmapAsync(cursor,cursor->Bounds(),cursorframe); + SetDrawingMode(B_OP_COPY); + } + Sync(); +} + +// These functions emulate the Input Server by sending the *exact* same kind of messages +// to the server's port. Being we're using a regular window, it would make little sense +// to do anything else. + +void VDView::MouseDown(BPoint pt) +{ +#ifdef DEBUG_SERVER_EMU +printf("ViewDriver::MouseDown\t"); +#endif + // Attach data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - modifier keys down + // 5) int32 - buttons down + // 6) int32 - clicks +#ifndef DISABLE_SERVER_EMU + BPoint p; + + uint32 buttons, + mod=modifiers(), + clicks=1; // can't get the # of clicks without a *lot* of extra work :( + + int64 time=(int64)real_time_clock(); + + GetMouse(&p,&buttons); + + serverlink->SetOpCode(B_MOUSE_DOWN); + serverlink->Attach(&time, sizeof(int64)); + serverlink->Attach(&pt.x,sizeof(float)); + serverlink->Attach(&pt.y,sizeof(float)); + serverlink->Attach(&mod, sizeof(uint32)); + serverlink->Attach(&buttons, sizeof(uint32)); + serverlink->Attach(&clicks, sizeof(uint32)); + serverlink->Flush(); +#endif +} + +void VDView::MouseMoved(BPoint pt, uint32 transit, const BMessage *msg) +{ + // Attach data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - buttons down +#ifndef DISABLE_SERVER_EMU + BPoint p; + uint32 buttons; + int64 time=(int64)real_time_clock(); + + serverlink->SetOpCode(B_MOUSE_MOVED); + serverlink->Attach(&time,sizeof(int64)); + serverlink->Attach(&pt.x,sizeof(float)); + serverlink->Attach(&pt.y,sizeof(float)); + GetMouse(&p,&buttons); + serverlink->Attach(&buttons,sizeof(int32)); + serverlink->Flush(); +#endif +} + +void VDView::MouseUp(BPoint pt) +{ +#ifdef DEBUG_SERVER_EMU +printf("ViewDriver::MouseUp\t"); +#endif + // Attach data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - modifier keys down +#ifndef DISABLE_SERVER_EMU + BPoint p; + + uint32 buttons, + mod=modifiers(); + + int64 time=(int64)real_time_clock(); + + GetMouse(&p,&buttons); + + serverlink->SetOpCode(B_MOUSE_UP); + serverlink->Attach(&time, sizeof(int64)); + serverlink->Attach(&pt.x,sizeof(float)); + serverlink->Attach(&pt.y,sizeof(float)); + serverlink->Attach(&mod, sizeof(uint32)); + serverlink->Flush(); +#endif +} + +void VDView::SetMode(int16 width, int16 height, uint8 bpp) +{ + // This function resets the emulated video buffer + color_space s; + + switch(bpp) + { + case 16: + s=B_RGBA15; + break; + case 8: + s=B_CMAP8; + break; + default: + s=B_RGBA32; + break; + } + delete viewbmp; + viewbmp=new BBitmap(BRect(0,0,width-1,height-1),s,true); + drawview->ResizeTo(width-1,height-1); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver::SetMode(%d x %d x %d)\n",width,height,bpp); +#endif +} + +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- + +VDWindow::VDWindow(void) + : BWindow(BRect(100,60,740,540),"OBOS App Server, P5",B_TITLED_WINDOW, + B_NOT_ZOOMABLE | B_NOT_RESIZABLE) +{ + view=new VDView(Bounds()); + AddChild(view); +} + +VDWindow::~VDWindow(void) +{ +} + +void VDWindow::MessageReceived(BMessage *msg) +{ + switch(msg->what) + { + case VDWIN_CLEAR: + { + int8 red=0,green=0,blue=0; + msg->FindInt8("red",&red); + msg->FindInt8("green",&green); + msg->FindInt8("blue",&blue); + Clear(red,green,blue); + break; + } + case VDWIN_SETSCREEN: + { + // debug printing done in SetScreen() + int32 space=0; + msg->FindInt32("screenmode",&space); + SetScreen(space); + break; + } + case VDWIN_RESET: + { + Reset(); + break; + } + case VDWIN_SAFEMODE: + { + SafeMode(); + break; + } + case VDWIN_DRAWSTRING: + { + char *string; + BPoint point; + uint16 length; + msg->FindString("string",(const char **)&string); + msg->FindInt16("length",(int16*)&length); + msg->FindPoint("point",&point); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->SetDrawingMode(B_OP_ALPHA); + view->drawview->DrawString(string,length,point); + view->drawview->SetDrawingMode(B_OP_COPY); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver::DrawString: "); +printf("String: %s\n",string); +printf("Length: %d\n",length); +printf("Point: "); point.PrintToStream(); +#endif + // Until I can figure out a better way, if I even bother... + view->Invalidate(); + } + case VDWIN_FILLARC: + { + float cx,cy,rx,ry,angle,span; + int64 temp64; + + msg->FindFloat("cx",&cx); + msg->FindFloat("cy",&cy); + msg->FindFloat("rx",&rx); + msg->FindFloat("ry",&ry); + msg->FindFloat("angle",&angle); + msg->FindFloat("span",&span); + if(msg->FindInt64("pattern",&temp64)!=B_OK) + temp64=*((int64*)&B_SOLID_HIGH); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->FillArc(BPoint(cx,cy),rx,ry,angle,span,*((pattern *)&temp64)); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + view->Invalidate(BRect(cx-rx,cy-ry,cx+rx,cy+ry)); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver::FillArc: "); +printf("Center: %f,%f\n",cx,cy); +printf("Radii: %f,%f\n",rx,ry); +printf("Angle, Span: %f,%f\n",angle, span); +printf("pattern: {%llx}\n",temp64); +#endif + break; + } + case VDWIN_STROKEARC: + { + float cx,cy,rx,ry,angle,span; + int64 temp64; + + msg->FindFloat("cx",&cx); + msg->FindFloat("cy",&cy); + msg->FindFloat("rx",&rx); + msg->FindFloat("ry",&ry); + msg->FindFloat("angle",&angle); + msg->FindFloat("span",&span); + if(msg->FindInt64("pattern",&temp64)!=B_OK) + temp64=*((int64*)&B_SOLID_HIGH); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->StrokeArc(BPoint(cx,cy),rx,ry,angle,span,*((pattern *)&temp64)); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + view->Invalidate(BRect(cx-rx,cy-ry,cx+rx,cy+ry)); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: StrokeArc: "); +printf("Center: %f,%f\n",cx,cy); +printf("Radii: %f,%f\n",rx,ry); +printf("Angle, Span: %f,%f\n",angle, span); +printf("pattern: {%llx}\n",temp64); +#endif + break; + } + case VDWIN_FILLBEZIER: + { + BPoint points[4]; + int64 temp64; + msg->FindPoint("p1",points); + msg->FindPoint("p2",&(points[1])); + msg->FindPoint("p3",&(points[2])); + msg->FindPoint("p4",&(points[3])); + if(msg->FindInt64("pattern",&temp64)!=B_OK) + temp64=*((int64*)&B_SOLID_HIGH); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->FillBezier(points,*((pattern *)&temp64)); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + + // Invalidate the whole view until I can figure out how to calculate + // a rect which encompasses the line + view->Invalidate(); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: FillBezier:\n"); +printf("Point 1: "); points[0].PrintToStream(); +printf("Point 2: "); points[1].PrintToStream(); +printf("Point 3: "); points[2].PrintToStream(); +printf("Point 4: "); points[3].PrintToStream(); +printf("pattern: {%llx}\n",temp64); +#endif + break; + } + case VDWIN_STROKEBEZIER: + { + BPoint points[4]; + int64 temp64; + msg->FindPoint("p1",points); + msg->FindPoint("p2",&(points[1])); + msg->FindPoint("p3",&(points[2])); + msg->FindPoint("p4",&(points[3])); + if(msg->FindInt64("pattern",&temp64)!=B_OK) + temp64=*((int64*)&B_SOLID_HIGH); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->StrokeBezier(points,*((pattern *)&temp64)); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + + // Invalidate the whole view until I can figure out how to calculate + // a rect which encompasses the line + view->Invalidate(); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: StrokeBezier:\n"); +printf("Point 1: "); points[0].PrintToStream(); +printf("Point 2: "); points[1].PrintToStream(); +printf("Point 3: "); points[2].PrintToStream(); +printf("Point 4: "); points[3].PrintToStream(); +printf("pattern: {%llx}\n",temp64); +#endif + break; + } + case VDWIN_FILLRECT: + { + BRect rect(0,0,0,0); + int64 temp64; + + msg->FindRect("rect",&rect); + if(msg->FindInt64("pattern",&temp64)==B_NAME_NOT_FOUND) + { + // Pattern will not exist if we are using the internal + // API which specifies a color and a rectangle + rgb_color highcolor=view->drawview->HighColor(); + rgb_color rectcolor; + msg->FindInt8("red",(int8*)&(rectcolor.red)); + msg->FindInt8("green",(int8*)&(rectcolor.green)); + msg->FindInt8("blue",(int8*)&(rectcolor.blue)); + msg->FindInt8("alpha",(int8*)&(rectcolor.alpha)); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->SetHighColor(rectcolor); + view->drawview->FillRect(rect,B_SOLID_HIGH); + view->drawview->SetHighColor(highcolor); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + view->Invalidate(rect); +#ifdef DEBUG_DRIVER_MODULE +printf("FillRect: "); rect.PrintToStream(); +printf("color (%d,%d,%d,%d)\n",rectcolor.red,rectcolor.green,rectcolor.blue,rectcolor.alpha); +#endif + break; + } + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->FillRect(rect,*((pattern *)&temp64)); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + view->Invalidate(rect); +#ifdef DEBUG_DRIVER_MODULE +printf("FillRect: "); rect.PrintToStream(); +printf("pattern: {%llxd}\n",temp64); +#endif + break; + } + case VDWIN_STROKERECT: + { + BRect rect(0,0,0,0); + int64 temp64; + + msg->FindRect("rect",&rect); + + if(msg->FindInt64("pattern",&temp64)==B_NAME_NOT_FOUND) + { + // Pattern will not exist if we are using the internal + // API which specifies a color and a rectangle + rgb_color highcolor=view->drawview->HighColor(); + rgb_color rectcolor; + msg->FindInt8("red",(int8*)&(rectcolor.red)); + msg->FindInt8("green",(int8*)&(rectcolor.green)); + msg->FindInt8("blue",(int8*)&(rectcolor.blue)); + msg->FindInt8("alpha",(int8*)&(rectcolor.alpha)); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->SetHighColor(rectcolor); + view->drawview->StrokeRect(rect,B_SOLID_HIGH); + view->drawview->SetHighColor(highcolor); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + view->Invalidate(rect); +#ifdef DEBUG_DRIVER_MODULE +printf("StrokeRect: "); rect.PrintToStream(); +printf("color (%d,%d,%d,%d)\n",rectcolor.red,rectcolor.green,rectcolor.blue,rectcolor.alpha); +#endif + break; + } + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->StrokeRect(rect,*((pattern *)&temp64)); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + view->Invalidate(rect); +#ifdef DEBUG_DRIVER_MODULE +printf("StrokeRect: "); rect.PrintToStream(); +printf("pattern: {%llx}\n",temp64); +#endif + break; + } + case VDWIN_FILLELLIPSE: + { + float cx,cy,rx,ry; + int64 temp64; + + msg->FindFloat("cx",&cx); + msg->FindFloat("cy",&cy); + msg->FindFloat("rx",&rx); + msg->FindFloat("ry",&ry); + if(msg->FindInt64("pattern",&temp64)!=B_OK) + temp64=*((int64*)&B_SOLID_HIGH); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->FillEllipse(BPoint(cx,cy),rx,ry,*((pattern *)&temp64)); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + view->Invalidate(BRect(cx-rx,cy-ry,cx+rx,cy+ry)); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: FillEllipse: "); +printf("Center: %f,%f\n",cx,cy); +printf("Radii: %f,%f\n",rx,ry); +printf("pattern: {%llx}\n",temp64); +#endif + break; + } + case VDWIN_STROKEELLIPSE: + { + float cx,cy,rx,ry; + int64 temp64; + + msg->FindFloat("cx",&cx); + msg->FindFloat("cy",&cy); + msg->FindFloat("rx",&rx); + msg->FindFloat("ry",&ry); + if(msg->FindInt64("pattern",&temp64)!=B_OK) + temp64=*((int64*)&B_SOLID_HIGH); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->StrokeEllipse(BPoint(cx,cy),rx,ry,*((pattern *)&temp64)); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + view->Invalidate(BRect(cx-rx,cy-ry,cx+rx,cy+ry)); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: StrokeEllipse: "); +printf("Center: %f,%f\n",cx,cy); +printf("Radii: %f,%f\n",rx,ry); +printf("pattern: {%llx}\n",temp64); +#endif + break; + } + case VDWIN_FILLROUNDRECT: + { + BRect rect(0,0,0,0); + int64 temp64; + float x,y; + + msg->FindRect("rect",&rect); + msg->FindFloat("x",&x); + msg->FindFloat("y",&y); + if(msg->FindInt64("pattern",&temp64)!=B_OK) + temp64=*((int64*)&B_SOLID_HIGH); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->FillRoundRect(rect,x,y,*((pattern *)&temp64)); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + view->Invalidate(rect); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: FillRoundRect: "); rect.PrintToStream(); +printf("Radii: %f,%f\n",x,y); +printf("pattern: {%llx}\n",temp64); +#endif + break; + } + case VDWIN_STROKEROUNDRECT: + { + BRect rect(0,0,0,0); + int64 temp64; + float x,y; + + msg->FindRect("rect",&rect); + msg->FindFloat("x",&x); + msg->FindFloat("y",&y); + if(msg->FindInt64("pattern",&temp64)!=B_OK) + temp64=*((int64*)&B_SOLID_HIGH); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->StrokeRoundRect(rect,x,y,*((pattern *)&temp64)); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + view->Invalidate(rect); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: StrokeRoundRect: "); rect.PrintToStream(); +printf("Radii: %f,%f\n",x,y); +printf("pattern: {%llx}\n",temp64); +#endif + break; + } + case VDWIN_FILLTRIANGLE: + { + BPoint pt1,pt2,pt3; + BRect invalid; + int64 temp64; + msg->FindPoint("first",&pt1); + msg->FindPoint("second",&pt2); + msg->FindPoint("third",&pt3); + msg->FindRect("rect",&invalid); + if(msg->FindInt64("pattern",&temp64)!=B_OK) + temp64=*((int64*)&B_SOLID_HIGH); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->FillTriangle(pt1,pt2,pt3,*((pattern *)&temp64)); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + + view->Invalidate(invalid); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: FillTriangle:\n"); +printf("Point 1: "); pt1.PrintToStream(); +printf("Point 2: "); pt2.PrintToStream(); +printf("Point 3: "); pt3.PrintToStream(); +printf("Rect: "); invalid.PrintToStream(); +printf("pattern: {%llx}\n",temp64); +#endif + break; + } + case VDWIN_STROKETRIANGLE: + { + BPoint pt1,pt2,pt3; + BRect invalid; + int64 temp64; + msg->FindPoint("first",&pt1); + msg->FindPoint("second",&pt2); + msg->FindPoint("third",&pt3); + msg->FindRect("rect",&invalid); + if(msg->FindInt64("pattern",&temp64)!=B_OK) + temp64=*((int64*)&B_SOLID_HIGH); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->StrokeTriangle(pt1,pt2,pt3,*((pattern *)&temp64)); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + + view->Invalidate(invalid); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: StrokeTriangle:\n"); +printf("Point 1: "); pt1.PrintToStream(); +printf("Point 2: "); pt2.PrintToStream(); +printf("Point 3: "); pt3.PrintToStream(); +printf("Rect: "); invalid.PrintToStream(); +printf("pattern: {%llx}\n",temp64); +#endif + break; + } + case VDWIN_STROKELINE: + { + BPoint pt(0,0),pt2(0,0); + int64 temp64; + rgb_color tcol, oldcol; + + msg->FindPoint("from",&pt); + msg->FindPoint("to",&pt2); + if(msg->FindInt64("pattern",&temp64)!=B_OK) + temp64=*((int64*)&B_SOLID_HIGH); + + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + + if(msg->FindInt8("red",(int8*)&tcol.red)!=B_NAME_NOT_FOUND) + { + msg->FindInt8("green",(int8*)&tcol.green); + msg->FindInt8("blue",(int8*)&tcol.blue); + msg->FindInt8("alpha",(int8*)&tcol.alpha); + oldcol=view->drawview->HighColor(); + view->drawview->SetHighColor(tcol); + view->drawview->StrokeLine(pt,pt2,*((pattern *)&temp64)); + view->drawview->SetHighColor(oldcol); + } + else + view->drawview->StrokeLine(pt,pt2,*((pattern *)&temp64)); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + + // Because BRect requires (pt1,pt2) where pt1=LeftTop(), + // we have to jump through some hoops + + BRect invalid(MIN(pt2.x,pt.x), MIN(pt2.y,pt.y), + MAX(pt2.x,pt.x), MAX(pt2.y,pt.y) ); + invalid.InsetBy((view->drawview->PenSize()/2)*-1,(view->drawview->PenSize()/2)*-1); + view->Invalidate(invalid); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: StrokeLine(%f,%f)\n",pt.x,pt.y); +printf("pattern: {%llx}\n",temp64); +#endif + break; + } + case VDWIN_SHOWCURSOR: + { + if(view->hide_cursor>0) + { + view->hide_cursor--; +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: ShowCursor() - still hidden\n"); +#endif + } + if(view->hide_cursor==0) + { +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: ShowCursor() - cursor shown\n"); +#endif + view->Invalidate(view->cursorframe); + } + break; + } + case VDWIN_HIDECURSOR: + { + view->hide_cursor++; +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: HideCursor()\n"); +#endif + if(view->hide_cursor==1) + { +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: HideCursor() - cursor was hidden\n"); +#endif + view->Invalidate(view->cursorframe); + } + break; + } + case VDWIN_OBSCURECURSOR: + { +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: ObscureCursor()\n"); +#endif + view->obscure_cursor=true; + view->Invalidate(view->cursorframe); + break; + } + case VDWIN_MOVECURSOR: + { + float x,y; + msg->FindFloat("x",&x); + msg->FindFloat("y",&y); + + // this was changed because an extra message was + // sent even though the mouse was never moved + if(view->cursorframe.left!=x || view->cursorframe.top!=y) + { + if(view->obscure_cursor) + view->obscure_cursor=false; + + view->oldcursorframe=view->cursorframe; + view->cursorframe.OffsetTo(x,y); + } + + if(view->hide_cursor==0) + view->Invalidate(view->oldcursorframe); + break; + } + case VDWIN_SETCURSOR: + { +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: SetCursor()\n"); +#endif + ServerCursor *cdata; + msg->FindPointer("SCursor",(void**)&cdata); + + if(cdata!=NULL) + { + BBitmap *bmp=new BBitmap(BRect(0,0,cdata->width-1,cdata->height-1), + cdata->cspace); + + // Copy the server bitmap in the cursor to a BBitmap + uint8 *sbmppos=(uint8*)cdata->bitmap->Buffer(), + *bbmppos=(uint8*)bmp->Bits(); + + int32 bytes=cdata->bitmap->bytesperline, + bbytes=bmp->BytesPerRow(); + + for(int i=0;iheight;i++) + memcpy(bbmppos+(i*bbytes), sbmppos+(i*bytes), bytes); + + // Replace the bitmap + delete view->cursor; + view->cursor=bmp; + view->Invalidate(view->cursorframe); + break; + } + break; + } + case VDWIN_SETHIGHCOLOR: + { + uint8 r=0,g=0,b=0,a=0; + msg->FindInt8("red",(int8*)&r); + msg->FindInt8("green",(int8*)&g); + msg->FindInt8("blue",(int8*)&b); + msg->FindInt8("alpha",(int8*)&a); + view->drawview->SetHighColor(r,g,b,a); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: SetHighColor(%d,%d,%d,%d)\n",r,g,b,a); +#endif + break; + } + case VDWIN_SETLOWCOLOR: + { + uint8 r=0,g=0,b=0,a=0; + msg->FindInt8("red",(int8*)&r); + msg->FindInt8("green",(int8*)&g); + msg->FindInt8("blue",(int8*)&b); + msg->FindInt8("alpha",(int8*)&a); + view->drawview->SetLowColor(r,g,b,a); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: SetLowColor(%d,%d,%d,%d)\n",r,g,b,a); +#endif + break; + } + case VDWIN_SETPENSIZE: + { + float pensize; + msg->FindFloat("size",&pensize); + view->drawview->SetPenSize(pensize); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: SetPenSize(%f)\n",pensize); +#endif + break; + } + case VDWIN_MOVEPENTO: + { + BPoint pt; + msg->FindPoint("point",&pt); + view->drawview->MovePenTo(pt); +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: MovePenTo(%f,%f)\n",pt.x,pt.y); +#endif + break; + } + default: + BWindow::MessageReceived(msg); + break; + } +} + +void VDWindow::SafeMode(void) +{ + SetScreen(B_8_BIT_640x480); +} + +void VDWindow::Reset(void) +{ + SafeMode(); + Clear(255,255,255); +} + +void VDWindow::SetScreen(uint32 space) +{ + int16 w=640,h=480; + uint8 bpp=0; + switch(space) + { + case B_32_BIT_800x600: + case B_16_BIT_800x600: + case B_8_BIT_800x600: + { + w=800; h=600; + break; + } + case B_32_BIT_1024x768: + case B_16_BIT_1024x768: + case B_8_BIT_1024x768: + { + w=1024; h=768; + break; + } + default: + break; + } + ResizeTo(w-1,h-1); + + switch(space) + { + case B_32_BIT_640x480: + case B_32_BIT_800x600: + case B_32_BIT_1024x768: + bpp=32; + break; + case B_16_BIT_640x480: + case B_16_BIT_800x600: + case B_16_BIT_1024x768: + bpp=16; + break; + case B_8_BIT_640x480: + case B_8_BIT_800x600: + case B_8_BIT_1024x768: + bpp=8; + break; + default: + break; + } + view->SetMode(w,h,bpp); +} + +void VDWindow::Clear(uint8 red,uint8 green,uint8 blue) +{ +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: Clear(%d,%d,%d)\n",red,green,blue); +#endif + view->viewbmp->Lock(); + view->viewbmp->AddChild(view->drawview); + view->drawview->SetHighColor(red,green,blue); + view->drawview->FillRect(view->drawview->Bounds()); + view->viewbmp->RemoveChild(view->drawview); + view->viewbmp->Unlock(); + view->Invalidate(); +} + +bool VDWindow::QuitRequested(void) +{ + port_id serverport=find_port(SERVER_PORT_NAME); + if(serverport!=B_NAME_NOT_FOUND) + { + write_port(serverport,B_QUIT_REQUESTED,NULL,0); + } + return true; +} + +void VDWindow::WindowActivated(bool active) +{ + // This is just to hide the regular system cursor so we can see our own + if(active) + be_app->HideCursor(); + else + be_app->ShowCursor(); +} + +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- + +/* + Posting messages to the rendering window helps run right around a whole + migraine's worth of multithreaded code +*/ + +ViewDriver::ViewDriver(void) +{ + screenwin=new VDWindow(); + hide_cursor=0; +} + +ViewDriver::~ViewDriver(void) +{ + if(is_initialized) + { + screenwin->Lock(); + screenwin->Quit(); + } +} + +void ViewDriver::Initialize(void) +{ + locker->Lock(); + screenwin->Show(); + is_initialized=true; + SetPenSize(1.0); + MovePenTo(BPoint(0,0)); + locker->Unlock(); +} + +void ViewDriver::Shutdown(void) +{ + locker->Lock(); + is_initialized=false; + locker->Unlock(); +} + +bool ViewDriver::IsInitialized(void) +{ + return is_initialized; +} + +void ViewDriver::SafeMode(void) +{ + locker->Lock(); + screenwin->PostMessage(VDWIN_SAFEMODE); + locker->Unlock(); +} + +void ViewDriver::Reset(void) +{ + locker->Lock(); + screenwin->PostMessage(VDWIN_RESET); + locker->Unlock(); +} + +void ViewDriver::SetScreen(uint32 space) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_SETSCREEN); + msg->AddInt32("screenmode",space); + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::Clear(uint8 red, uint8 green, uint8 blue) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_CLEAR); + msg->AddInt8("red",red); + msg->AddInt8("green",green); + msg->AddInt8("blue",blue); + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::Clear(rgb_color col) +{ + Clear(col.red,col.green,col.blue); +} + +int32 ViewDriver::GetHeight(void) +{ // Gets the height of the current mode + return 0; +} + +int32 ViewDriver::GetWidth(void) +{ // Gets the width of the current mode + return 0; +} + +int ViewDriver::GetDepth(void) +{ // Gets the color depth of the current mode + return 0; +} + +void ViewDriver::Blit(BRect src, BRect dest) +{ +} + +void ViewDriver::DrawBitmap(ServerBitmap *bitmap) +{ +} + +void ViewDriver::DrawChar(char c, BPoint point) +{ + char string[2]; + string[0]=c; + string[1]='\0'; + DrawString(string,2,point); +} + +void ViewDriver::DrawString(char *string, int length, BPoint point) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_DRAWSTRING); + msg->AddString("string",string); + msg->AddInt16("length",length); + msg->AddPoint("point",point); + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::FillArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_FILLARC); + msg->AddFloat("cx",centerx); + msg->AddFloat("cy",centery); + msg->AddFloat("rx",xradius); + msg->AddFloat("ry",yradius); + msg->AddFloat("angle",angle); + msg->AddFloat("span",span); + + // Have to actually copy the pattern data because a sort of race condition + // Using an int64 to make for an easy copy. + if(pattern) + { + int64 pat=*((int64*)pattern); + msg->AddInt64("pattern",pat); + } + + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::FillBezier(BPoint *points, uint8 *pattern) +{ + locker->Lock(); + + BMessage *msg=new BMessage(VDWIN_FILLBEZIER); + msg->AddPoint("p1",points[0]); + msg->AddPoint("p2",points[1]); + msg->AddPoint("p3",points[2]); + msg->AddPoint("p4",points[3]); + if(pattern) + { + int64 pat=*((int64*)pattern); + msg->AddInt64("pattern",pat); + } + + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::FillEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_FILLELLIPSE); + msg->AddFloat("cx",centerx); + msg->AddFloat("cy",centery); + msg->AddFloat("rx",x_radius); + msg->AddFloat("ry",y_radius); + + // Have to actually copy the pattern data because a sort of race condition + // Using an int64 to make for an easy copy. + if(pattern) + { + int64 pat=*((int64*)pattern); + msg->AddInt64("pattern",pat); + } + + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::FillPolygon(int *x, int *y, int numpoints, bool is_closed) +{ +} + +void ViewDriver::FillRect(BRect rect, uint8 *pattern) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_FILLRECT); + msg->AddRect("rect",rect); + + // Have to actually copy the pattern data because a sort of race condition + // Using an int64 to make for an easy copy. + if(pattern) + { + int64 pat=*((int64*)pattern); + msg->AddInt64("pattern",pat); + } + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::FillRect(BRect rect, rgb_color col) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_FILLRECT); + msg->AddRect("rect",rect); + + msg->AddInt8("red",col.red); + msg->AddInt8("green",col.green); + msg->AddInt8("blue",col.blue); + msg->AddInt8("alpha",col.alpha); + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::FillRegion(BRegion *region) +{ +} + +void ViewDriver::FillRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_FILLROUNDRECT); + msg->AddRect("rect",rect); + msg->AddFloat("x",xradius); + msg->AddFloat("y",yradius); + + // Have to actually copy the pattern data because a sort of race condition + // Using an int64 to make for an easy copy. + if(pattern) + { + int64 pat=*((int64*)pattern); + msg->AddInt64("pattern",pat); + } + + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::FillShape(BShape *shape) +{ +} + +void ViewDriver::FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_FILLTRIANGLE); + msg->AddPoint("first",first); + msg->AddPoint("second",second); + msg->AddPoint("third",third); + msg->AddRect("rect",rect); + + // Have to actually copy the pattern data because a sort of race condition + // Using an int64 to make for an easy copy. + if(pattern) + { + int64 pat=*((int64*)pattern); + msg->AddInt64("pattern",pat); + } + + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::HideCursor(void) +{ + locker->Lock(); + hide_cursor++; + screenwin->PostMessage(VDWIN_HIDECURSOR); + locker->Unlock(); +} + +bool ViewDriver::IsCursorHidden(void) +{ + locker->Lock(); + bool value=(hide_cursor>0)?true:false; + locker->Unlock(); + return value; +} + +void ViewDriver::ObscureCursor(void) +{ // Hides cursor until mouse is moved + locker->Lock(); + screenwin->PostMessage(VDWIN_OBSCURECURSOR); + locker->Unlock(); +} + +void ViewDriver::MoveCursorTo(float x, float y) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_MOVECURSOR); + msg->AddFloat("x",x); + msg->AddFloat("y",y); + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::MovePenTo(BPoint pt) +{ // Moves the graphics pen to this position + + locker->Lock(); + penpos=pt; + + BMessage *msg=new BMessage(VDWIN_MOVEPENTO); + msg->AddPoint("point",penpos); + screenwin->PostMessage(msg); + locker->Unlock(); +} + +BPoint ViewDriver::PenPosition(void) +{ + return penpos; +} + +float ViewDriver::PenSize(void) +{ + return pensize; +} + +void ViewDriver::SetCursor(int32 value) +{ +} + +void ViewDriver::SetCursor(ServerCursor *cursor) +{ + // We are given a ServerCursor, but the data is really a ServerBitmap. + // Copy it and fire it off to the view driver's window for translation + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_SETCURSOR); + msg->AddPointer("SCursor",cursor); + screenwin->PostMessage(msg); // Much faster than copying data. :) + locker->Unlock(); +} + +void ViewDriver::SetPenSize(float size) +{ + locker->Lock(); + pensize=size; + + BMessage *msg=new BMessage(VDWIN_SETPENSIZE); + msg->AddFloat("size",pensize); + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::SetHighColor(uint8 r,uint8 g,uint8 b,uint8 a=255) +{ + locker->Lock(); + highcol.red=r; + highcol.green=g; + highcol.blue=b; + highcol.alpha=a; + + BMessage *msg=new BMessage(VDWIN_SETHIGHCOLOR); + msg->AddInt8("red",r); + msg->AddInt8("green",g); + msg->AddInt8("blue",b); + msg->AddInt8("alpha",a); + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::SetLowColor(uint8 r,uint8 g,uint8 b,uint8 a=255) +{ + locker->Lock(); + lowcol.red=r; + lowcol.green=g; + lowcol.blue=b; + lowcol.alpha=a; + + BMessage *msg=new BMessage(VDWIN_SETLOWCOLOR); + msg->AddInt8("red",r); + msg->AddInt8("green",g); + msg->AddInt8("blue",b); + msg->AddInt8("alpha",a); + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::SetPixel(int x, int y, uint8 *pattern) +{ // Internal function utilized by other functions to draw to the buffer + // Will eventually be an inline function +} + +void ViewDriver::ShowCursor(void) +{ + locker->Lock(); + if(hide_cursor>0) + { + hide_cursor--; + screenwin->PostMessage(VDWIN_SHOWCURSOR); + } + locker->Unlock(); +} + +void ViewDriver::StrokeArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_STROKEARC); + msg->AddFloat("cx",centerx); + msg->AddFloat("cy",centery); + msg->AddFloat("rx",xradius); + msg->AddFloat("ry",yradius); + msg->AddFloat("angle",angle); + msg->AddFloat("span",span); + + // Have to actually copy the pattern data because a sort of race condition + // Using an int64 to make for an easy copy. + if(pattern) + { + int64 pat=*((int64*)pattern); + msg->AddInt64("pattern",pat); + } + + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::StrokeBezier(BPoint *points, uint8 *pattern) +{ + locker->Lock(); + + BMessage *msg=new BMessage(VDWIN_STROKEBEZIER); + msg->AddPoint("p1",points[0]); + msg->AddPoint("p2",points[1]); + msg->AddPoint("p3",points[2]); + msg->AddPoint("p4",points[3]); + if(pattern) + { + int64 pat=*((int64*)pattern); + msg->AddInt64("pattern",pat); + } + + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::StrokeEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_STROKEELLIPSE); + msg->AddFloat("cx",centerx); + msg->AddFloat("cy",centery); + msg->AddFloat("rx",x_radius); + msg->AddFloat("ry",y_radius); + + // Have to actually copy the pattern data because a sort of race condition + // Using an int64 to make for an easy copy. + if(pattern) + { + int64 pat=*((int64*)pattern); + msg->AddInt64("pattern",pat); + } + + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::StrokeLine(BPoint point, uint8 *pattern) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_STROKELINE); + msg->AddPoint("from",penpos); + msg->AddPoint("to",point); + + // Have to actually copy the pattern data because a sort of race condition + // Using an int64 to make for an easy copy. + if(pattern) + { + int64 pat=*((int64*)pattern); + msg->AddInt64("pattern",pat); + } + + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::StrokeLine(BPoint pt1, BPoint pt2, rgb_color col) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_STROKELINE); + msg->AddPoint("from",pt1); + msg->AddPoint("to",pt2); + msg->AddInt8("red",col.red); + msg->AddInt8("green",col.green); + msg->AddInt8("blue",col.blue); + msg->AddInt8("alpha",col.alpha); + + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::StrokePolygon(int *x, int *y, int numpoints, bool is_closed) +{ +} + +void ViewDriver::StrokeRect(BRect rect,uint8 *pattern) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_STROKERECT); + msg->AddRect("rect",rect); + + // Have to actually copy the pattern data because a sort of race condition + // Using an int64 to make for an easy copy. + if(pattern) + { + int64 pat=*((int64*)pattern); + msg->AddInt64("pattern",pat); + } + + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::StrokeRect(BRect rect,rgb_color col) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_STROKERECT); + msg->AddRect("rect",rect); + + msg->AddInt8("red",col.red); + msg->AddInt8("green",col.green); + msg->AddInt8("blue",col.blue); + msg->AddInt8("alpha",col.alpha); + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::StrokeRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_STROKEROUNDRECT); + msg->AddRect("rect",rect); + msg->AddFloat("x",xradius); + msg->AddFloat("y",yradius); + + // Have to actually copy the pattern data because a sort of race condition + // Using an int64 to make for an easy copy. + if(pattern) + { + int64 pat=*((int64*)pattern); + msg->AddInt64("pattern",pat); + } + + screenwin->PostMessage(msg); + locker->Unlock(); +} + +void ViewDriver::StrokeShape(BShape *shape) +{ +} + +void ViewDriver::StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern) +{ + locker->Lock(); + BMessage *msg=new BMessage(VDWIN_STROKETRIANGLE); + msg->AddPoint("first",first); + msg->AddPoint("second",second); + msg->AddPoint("third",third); + msg->AddRect("rect",rect); + + // Have to actually copy the pattern data because a sort of race condition + // Using an int64 to make for an easy copy. + if(pattern) + { + int64 pat=*((int64*)pattern); + msg->AddInt64("pattern",pat); + } + + screenwin->PostMessage(msg); + locker->Unlock(); +} + +#ifdef DEBUG_DRIVER_MODULE +#undef DEBUG_DRIVER_MODULE +#endif \ No newline at end of file diff --git a/src/servers/app/proto5/ViewDriver.h b/src/servers/app/proto5/ViewDriver.h new file mode 100644 index 0000000000..8c675a8daf --- /dev/null +++ b/src/servers/app/proto5/ViewDriver.h @@ -0,0 +1,129 @@ +#ifndef _VIEWDRIVER_H_ +#define _VIEWDRIVER_H_ + +#include +#include +#include +#include +#include // for pattern struct +#include +#include +#include "DisplayDriver.h" + +class BBitmap; +class PortLink; +class VDWindow; +class ServerCursor; + +class VDView : public BView +{ +public: + VDView(BRect bounds); + ~VDView(void); + void AttachedToWindow(void); + void Draw(BRect rect); + void MouseDown(BPoint pt); + void MouseMoved(BPoint pt, uint32 transit, const BMessage *msg); + void MouseUp(BPoint pt); + void SetMode(int16 width, int16 height, uint8 bpp); + + BBitmap *viewbmp; + BView *drawview; + PortLink *serverlink; + +protected: + friend VDWindow; + + int hide_cursor; + BBitmap *cursor; + + BRect cursorframe, oldcursorframe; + bool obscure_cursor; +}; + +class VDWindow : public BWindow +{ +public: + VDWindow(void); + ~VDWindow(void); + void MessageReceived(BMessage *msg); + bool QuitRequested(void); + void WindowActivated(bool active); + + void SafeMode(void); + void Reset(void); + void SetScreen(uint32 space); + void Clear(uint8 red,uint8 green,uint8 blue); + VDView *view; +}; + +class ViewDriver : public DisplayDriver +{ +public: + ViewDriver(void); + virtual ~ViewDriver(void); + + virtual void Initialize(void); // Sets the driver + virtual bool IsInitialized(void); + virtual void Shutdown(void); // You never know when you'll need this + + virtual void SafeMode(void); // Easy-access functions for common tasks + virtual void Reset(void); + virtual void Clear(uint8 red,uint8 green,uint8 blue); + virtual void Clear(rgb_color col); + + // Settings functions + virtual void SetScreen(uint32 space); + virtual int32 GetHeight(void); + virtual int32 GetWidth(void); + virtual int GetDepth(void); + + // Drawing functions + virtual void Blit(BRect src, BRect dest); + virtual void DrawBitmap(ServerBitmap *bitmap); + virtual void DrawChar(char c, BPoint point); + virtual void DrawString(char *string, int length, BPoint point); + + virtual void FillArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern); + virtual void FillBezier(BPoint *points, uint8 *pattern); + virtual void FillEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern); + virtual void FillPolygon(int *x, int *y, int numpoints, bool is_closed); + virtual void FillRect(BRect rect, uint8 *pattern); + virtual void FillRect(BRect rect, rgb_color col); + virtual void FillRegion(BRegion *region); + virtual void FillRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern); + virtual void FillShape(BShape *shape); + virtual void FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern); + + virtual void HideCursor(void); + virtual bool IsCursorHidden(void); + virtual void MoveCursorTo(float x, float y); + virtual void MovePenTo(BPoint pt); + virtual void ObscureCursor(void); + virtual BPoint PenPosition(void); + virtual float PenSize(void); + virtual void SetCursor(int32 value); + virtual void SetCursor(ServerCursor *cursor); + virtual void SetHighColor(uint8 r,uint8 g,uint8 b,uint8 a=255); + virtual void SetLowColor(uint8 r,uint8 g,uint8 b,uint8 a=255); + virtual void SetPenSize(float size); + virtual void SetPixel(int x, int y, uint8 *pattern); + virtual void ShowCursor(void); + + virtual void StrokeArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern); + virtual void StrokeBezier(BPoint *points, uint8 *pattern); + virtual void StrokeEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern); + virtual void StrokeLine(BPoint point, uint8 *pattern); + virtual void StrokeLine(BPoint pt1, BPoint pt2, rgb_color col); + virtual void StrokePolygon(int *x, int *y, int numpoints, bool is_closed); + virtual void StrokeRect(BRect rect,uint8 *pattern); + virtual void StrokeRect(BRect rect,rgb_color col); + virtual void StrokeRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern); + virtual void StrokeShape(BShape *shape); + virtual void StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern); + VDWindow *screenwin; +protected: + int hide_cursor; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto5/WindowBorder.cpp b/src/servers/app/proto5/WindowBorder.cpp new file mode 100644 index 0000000000..c41014a5a7 --- /dev/null +++ b/src/servers/app/proto5/WindowBorder.cpp @@ -0,0 +1,253 @@ +#include +#include +#include +#include +#include "View.h" // for mouse button defines +#include "ServerWindow.h" +#include "WindowBorder.h" +#include "Decorator.h" +#include "Desktop.h" + +#define DEBUG_WINBORDER + +#ifdef DEBUG_WINBORDER +#include +#endif + +bool is_moving_window=false; +WindowBorder *activeborder=NULL; + +WindowBorder::WindowBorder(ServerWindow *win, const char *bordertitle) + : Layer(win->frame,win->title->String()) +{ +#ifdef DEBUG_WINBORDER +printf("WindowBorder()\n"); +#endif + mbuttons=0; + swin=win; + title=new BString(bordertitle); + hresizewin=false; + vresizewin=false; +} + +WindowBorder::~WindowBorder(void) +{ +#ifdef DEBUG_WINBORDER +printf("~WindowBorder()\n"); +#endif + delete title; +} + +void WindowBorder::MouseDown(BPoint pt, uint32 buttons) +{ + mbuttons=buttons; + click_type click=decor->Clicked(pt, mbuttons); + + switch(click) + { + case CLICK_MOVETOBACK: + { +#ifdef DEBUG_WINBORDER +printf("WindowBorder(): MoveToBack\n"); +#endif + swin->SetFocus(false); + + // Move the window to the back (the top of the tree) + Layer *top=GetRootLayer(); + ASSERT(top!=NULL); + layerlock->Lock(); + top->RemoveChild(this); + top->AddChild(this); + swin->SetFocus(false); + decor->SetFocus(false); + decor->Draw(); + layerlock->Unlock(); + break; + } + case CLICK_MOVETOFRONT: + { +#ifdef DEBUG_WINBORDER +printf("WindowBorder(): MoveToFront\n"); +#endif + swin->SetFocus(true); + + // Move the window to the front by making it the bottom + // child of the root layer + Layer *top=GetRootLayer(); + layerlock->Lock(); + top->RemoveChild(this); + uppersibling=top->bottomchild; + lowersibling=NULL; + top->bottomchild=this; + if(top->topchild==NULL) + top->topchild=this; + parent=top; + swin->SetFocus(true); + decor->SetFocus(true); + decor->Draw(); + layerlock->Unlock(); + is_moving_window=true; + activeborder=this; + break; + } + case CLICK_CLOSE: + { +#ifdef DEBUG_WINBORDER +printf("WindowBorder(): SetCloseButton\n"); +#endif + decor->SetCloseButton(true); + swin->SetFocus(true); + decor->SetFocus(true); + decor->Draw(); + activeborder=this; + break; + } + case CLICK_ZOOM: + { +#ifdef DEBUG_WINBORDER +printf("WindowBorder(): SetZoomButton\n"); +#endif + decor->SetZoomButton(true); + swin->SetFocus(true); + decor->SetFocus(true); + decor->Draw(); + activeborder=this; + break; + } + case CLICK_MINIMIZE: + { +#ifdef DEBUG_WINBORDER +printf("WindowBorder(): SetMinimizeButton\n"); +#endif + decor->SetMinimizeButton(true); + break; + } + case CLICK_TAB: + { +#ifdef DEBUG_WINBORDER +printf("WindowBorder(): Click Tab\n"); +#endif + if(buttons==B_PRIMARY_MOUSE_BUTTON) + { + is_moving_window=true; + activeborder=this; + } + break; + } + case CLICK_NONE: + { +#ifdef DEBUG_WINBORDER +printf("WindowBorder(): Click None\n"); +#endif + break; + } + default: + { +#ifdef DEBUG_WINBORDER +printf("WindowBorder()::MouseDown: Undefined click type\n"); +#endif + break; + } + } +} + +void WindowBorder::MouseMoved(BPoint pt, uint32 buttons) +{ + click_type click=decor->Clicked(pt, mbuttons); + if(click!=CLICK_CLOSE && decor->GetCloseButton()) + { + decor->SetCloseButton(false); + decor->Draw(); + } + + if(click!=CLICK_ZOOM && decor->GetZoomButton()) + { + decor->SetZoomButton(false); + decor->Draw(); + } + + if(is_moving_window==true) + { + float dx=pt.x-mousepos.x, + dy=pt.y-mousepos.y; + if(dx!=0 || dy!=0) + { + clientframe.OffsetBy(pt); + + swin->Lock(); + swin->frame.OffsetBy(dx,dy); + swin->Unlock(); + + layerlock->Lock(); + MoveBy(dx,dy); + parent->RequestDraw(); + layerlock->Unlock(); + decor->MoveBy(BPoint(dx, dy)); + decor->Draw(); + } + } + mousepos=pt; +} + +void WindowBorder::MouseUp(BPoint pt, uint32 buttons) +{ +// mbuttons&= ~buttons; + mbuttons=buttons; + activeborder=NULL; + is_moving_window=false; + + click_type click=decor->Clicked(pt, mbuttons); + + switch(click) + { + case CLICK_CLOSE: + { + decor->SetCloseButton(false); + decor->Draw(); + break; + } + case CLICK_ZOOM: + { + decor->SetZoomButton(false); + decor->Draw(); + break; + } + default: + { + break; + } + } +} + +void WindowBorder::Draw(BRect update_rect) +{ + // Just a hard-coded placeholder for now + if(decor->Look()==B_NO_BORDER_WINDOW_LOOK) + return; + +#ifdef DEBUG_WINBORDER +printf("WindowBorder()::Draw():"); update_rect.PrintToStream(); +#endif + + if(update && visible!=NULL) + is_updating=true; + + decor->Draw(update_rect); + + if(update && visible!=NULL) + is_updating=false; +} + +void WindowBorder::SetDecorator(Decorator *newdecor) +{ + // AtheOS kills the decorator here. However, the decor + // under OBOS doesn't belong to the border - it belongs to the + // ServerWindow, so the ServerWindow will handle all (de)allocation + // tasks. We just need to update the pointer. + decor=newdecor; +} + +ServerWindow *WindowBorder::Window(void) const +{ + return swin; +} diff --git a/src/servers/app/proto5/WindowBorder.h b/src/servers/app/proto5/WindowBorder.h new file mode 100644 index 0000000000..b8d5c14f07 --- /dev/null +++ b/src/servers/app/proto5/WindowBorder.h @@ -0,0 +1,37 @@ +#ifndef _WINBORDER_H_ +#define _WINBORDER_H_ + +#include +#include +#include "Layer.h" + +class ServerWindow; +class Decorator; + +class WindowBorder : public Layer +{ +public: + WindowBorder(ServerWindow *win, const char *bordertitle); + ~WindowBorder(void); + void MouseDown(BPoint pt, uint32 buttons); + void MouseMoved(BPoint pt, uint32 buttons); + void MouseUp(BPoint pt, uint32 buttons); + void Draw(BRect update); + void SystemColorsUpdated(void); + void SetDecorator(Decorator *newdecor); + ServerWindow *Window(void) const; + + ServerWindow *swin; + BString *title; + Decorator *decor; + int32 flags; + BRect frame, clientframe; + uint32 mbuttons; + BPoint mousepos; + bool update; + bool hresizewin,vresizewin; +}; + +extern bool is_moving_window; +extern WindowBorder *activeborder; +#endif \ No newline at end of file diff --git a/src/servers/app/proto5/YMakDecorator.cpp b/src/servers/app/proto5/YMakDecorator.cpp new file mode 100644 index 0000000000..a660e4a857 --- /dev/null +++ b/src/servers/app/proto5/YMakDecorator.cpp @@ -0,0 +1,656 @@ +/******************************************************* +* YMakDecorator +* +* Writen by YNOP. +* used BeOS Magnify and decor to try to figure out +* how it looks. +* Originaly writen on AtheOS as MakDadddy Decor. +* Hacked around several times, and then ported +* (by me again) to OBOS app_server Decorator API +* +* TODO +* Fix title issuse (We need a Font width to center by) +* Fix any issuse that came about via porting +* These may have to do with the fact that the origin is +* differnat for the two API's and also with the fact +* that we can test anything yet :P +* Border size should change with Font Height +* +* @author YNOP (ynop@beunited.org) +* @version 1 (p5) +*******************************************************/ + + +#include "Layer.h" +#include "DisplayDriver.h" +#include "YMakDecorator.h" + +//#define DEBUG_DECOR + +#ifdef DEBUG_DECOR +#include +#endif + +// Hardcoded sized .. TOP should be Font based... +#define TOP 22 +#define FRAME 6 + +/******************************************************* +* @description +*******************************************************/ +YMakDecorator::YMakDecorator(Layer *lay, uint32 dflags, window_look wlook):Decorator(lay, dflags, wlook){ + if(flags & B_NO_BORDER_WINDOW_LOOK){ + LeftBorder = 0; + TopBorder = 0; + RightBorder = 0; + BottomBorder = 0; + }else{ + TopBorder = TOP; + LeftBorder = FRAME; + RightBorder = FRAME; + BottomBorder = FRAME; + } + Resize(lay->frame); +} + +/******************************************************* +* @description +*******************************************************/ +YMakDecorator::~YMakDecorator(void){ +} + +/******************************************************* +* @description +*******************************************************/ +click_type YMakDecorator::Clicked(BPoint pt, uint32 buttons){ +#ifdef DEBUG_DECOR +printf("YMakDecorator():Clicked(%f,%f)\n",pt.x,pt.y); +printf("ZoomRect:");ZoomRect.PrintToStream(); +#endif + + if(CloseRect.Contains(pt)){ + return CLICK_CLOSE; + } + if(ZoomRect.Contains(pt)){ + return CLICK_ZOOM; + } + //return CLICK_RESIZE_RB; + //return CLICK_NONE; + return CLICK_DRAG; +} + +/******************************************************* +* @description +*******************************************************/ +void YMakDecorator::Resize(BRect rect){ + frame = rect; + + BRect But; + But.left = frame.left + 0; + But.right = frame.left + 12; + But.top = frame.top + 0; + But.bottom = frame.top + 12; + + CloseRect = But; + CloseRect.left += 4; + CloseRect.top += 4; + CloseRect.right += 4; + CloseRect.bottom += 4; + +} + +/******************************************************* +* @description +*******************************************************/ +BRect YMakDecorator::GetBorderSize(void){ + // I dont know what this does yet :P + return bsize; +} + +/******************************************************* +* @description +*******************************************************/ +BPoint YMakDecorator::GetMinimumSize(void){ + return minsize; +} + +/******************************************************* +* @description +*******************************************************/ +void YMakDecorator::SetFlags(uint32 dflags){ + flags=dflags; +} + +/******************************************************* +* @description +*******************************************************/ +void YMakDecorator::UpdateFont(void){ +} + +/******************************************************* +* @description +*******************************************************/ +void YMakDecorator::UpdateTitle(const char *string){ +} + +/******************************************************* +* @description +*******************************************************/ +void YMakDecorator::SetFocus(bool bfocused){ + focused=bfocused; +} + +/******************************************************* +* @description +*******************************************************/ +void YMakDecorator::SetCloseButton(bool down){ + closestate=down; +} + +/******************************************************* +* @description +*******************************************************/ +void YMakDecorator::SetZoomButton(bool down){ + zoomstate=down; +} + +/******************************************************* +* @description +*******************************************************/ +void YMakDecorator::Draw(BRect update){ + BRect b = frame; + BRect cOBounds = frame; + + rgb_color cB = {0, 0, 0, 255}; + rgb_color cW = {251,251,251,255}; + rgb_color cG = {154,154,154,255}; + rgb_color cD = {113,113,113,255}; + rgb_color cL = {203,203,203,255}; + + // Debug yellow backgound to make sure we cover everthign :) + // Take this out in real ver for speed :P + rgb_color yellow = {255,255,0}; + driver->FillRect(frame,yellow); + + // Stroke outside border + driver->SetHighColor(cB.red,cB.green,cB.blue,cB.alpha); + driver->StrokeRect(b,NULL); + + // Stroke inside border + b = cOBounds; + b.top += TOP - 1; + b.bottom -= FRAME-1; + b.left += FRAME - 1; + b.right -= FRAME-1; + driver->StrokeRect(b,NULL); + + if(focused){ + // Stroke outer boder (raized) + b = cOBounds; + b.left += 1; + b.right -= 1; + b.top += 1; + b.bottom -= 1; + driver->SetHighColor(cW.red,cW.green,cW.blue,cW.alpha); + driver->MovePenTo(BPoint(b.left,b.top));driver->StrokeLine(BPoint(b.right,b.top),NULL); + + driver->MovePenTo(BPoint(b.left,b.bottom));driver->StrokeLine(BPoint(b.left,b.top),NULL); + driver->SetHighColor(cG.red,cG.green,cG.blue,cG.alpha); + driver->MovePenTo(BPoint(b.right,b.top));driver->StrokeLine(BPoint(b.right,b.bottom),NULL); + driver->MovePenTo(BPoint(b.right,b.bottom));driver->StrokeLine(BPoint(b.left,b.bottom),NULL); + + // Stroke inter border (raized) + b = cOBounds; + b.top += TOP - 2; + b.bottom -= FRAME - 2; + b.left += FRAME - 2; + b.right -= FRAME - 2; + driver->SetHighColor(cG.red,cG.green,cG.blue,cG.alpha); + driver->MovePenTo(BPoint(b.left,b.top));driver->StrokeLine(BPoint(b.right,b.top),NULL); + driver->MovePenTo(BPoint(b.left,b.bottom));driver->StrokeLine(BPoint(b.left,b.top),NULL); + driver->SetHighColor(cW.red,cW.green,cW.blue,cW.alpha); + driver->MovePenTo(BPoint(b.right,b.top));driver->StrokeLine(BPoint(b.right,b.bottom),NULL); + driver->MovePenTo(BPoint(b.right,b.bottom));driver->StrokeLine(BPoint(b.left,b.bottom),NULL); + + driver->SetHighColor(cL.red,cL.green,cL.blue,cL.alpha); + // Fill top + b = cOBounds; + b.bottom = b.top + TOP - 3; + b.top += 2; + b.left += 2; + b.right -= 2; + driver->FillRect(b,NULL); + // Fill left + b = cOBounds; + b.left += 2; + b.right = cOBounds.left + FRAME - 3; + b.top = cOBounds.top + TOP - 2; + b.bottom -= 2; + driver->FillRect(b,NULL); + // Fill right + b = cOBounds; + b.left = b.right - FRAME + 3; + b.right -= 2; + b.top = b.top + TOP - 2; + b.bottom -= 2; + driver->FillRect(b,NULL); + // fill bottom + b = cOBounds; + b.top = b.bottom - FRAME + 3; + b.bottom -= 2; + b.left += FRAME - 2; + b.right -= FRAME - 2; + driver->FillRect(b,NULL); + + // Stroke the lines .. stoke them oohh ya .. storkem .. + // + b = cOBounds; + b.left += 20; + b.right -= 20; + b.top += 4; + b.bottom += 10; + + //if((Flags & WND_NO_DEPTH_BUT) == 0){ + // b.right -= 20; + //} + + + driver->SetHighColor(cW.red,cW.green,cW.blue,cW.alpha); + driver->MovePenTo(BPoint(b.left,b.top+0));driver->StrokeLine(BPoint(b.right-1,b.top+0),NULL); + driver->MovePenTo(BPoint(b.left,b.top+2));driver->StrokeLine(BPoint(b.right-1,b.top+2),NULL); + driver->MovePenTo(BPoint(b.left,b.top+4));driver->StrokeLine(BPoint(b.right-1,b.top+4),NULL); + driver->MovePenTo(BPoint(b.left,b.top+6));driver->StrokeLine(BPoint(b.right-1,b.top+6),NULL); + driver->MovePenTo(BPoint(b.left,b.top+8));driver->StrokeLine(BPoint(b.right-1,b.top+8),NULL); + driver->MovePenTo(BPoint(b.left,b.top+10));driver->StrokeLine(BPoint(b.right-1,b.top+10),NULL); + +#ifdef DEBUG_DECOR +printf("About to draw high lines\n"); +printf("do done\n"); +#endif + driver->SetHighColor(cD.red,cD.green,cD.blue,cD.alpha); + driver->MovePenTo(BPoint(b.left+1,b.top+1));driver->StrokeLine(BPoint(b.right,b.top+1),NULL); + driver->MovePenTo(BPoint(b.left+1,b.top+3));driver->StrokeLine(BPoint(b.right,b.top+3),NULL); + driver->MovePenTo(BPoint(b.left+1,b.top+5));driver->StrokeLine(BPoint(b.right,b.top+5),NULL); + driver->MovePenTo(BPoint(b.left+1,b.top+7));driver->StrokeLine(BPoint(b.right,b.top+7),NULL); + driver->MovePenTo(BPoint(b.left+1,b.top+9));driver->StrokeLine(BPoint(b.right,b.top+9),NULL); + driver->MovePenTo(BPoint(b.left+1,b.top+11));driver->StrokeLine(BPoint(b.right,b.top+11),NULL); + + }else{ + driver->SetHighColor(cL.red,cL.green,cL.blue,cL.alpha); + // Fill top + b = cOBounds; + b.bottom = b.top + TOP - 2; + b.top += 1; + b.left += 1; + b.right -= 1; + driver->FillRect(b,NULL); + // Fill left side + b = cOBounds; + b.left += 1; + b.right = b.left + FRAME - 2; + b.top = b.top + TOP - 1; + b.bottom -= 1; + driver->FillRect(b,NULL); + // fill right + b = cOBounds; + b.left = b.right - FRAME + 2; + b.right -= 1; + b.top = b.top + TOP - 1; + b.bottom -= 1; + driver->FillRect(b,NULL); + // fill bottom + b = cOBounds; + b.top = b.bottom - FRAME + 2; + b.bottom -= 1; + b.left += FRAME - 1; + b.right -= FRAME - 1; + driver->FillRect(b,NULL); + } + + +/* if((flags & WND_NO_TITLE) == 0){ + // Stroke The title Text + driver->SetFgColor(cL.red,cL.green,cL.blue,cL.alpha); + b.left = 30; + b.right = 100; + //Font *font = new Font(DEFAULT_FONT_WINDOW); + //b.right = font->GetStringWidth(Title.c_str()); + + int32 len = strlen(Title.c_str()); + b.right = b.left + len * 7; + + + b.top = 2; + b.bottom = TOP - 3; + V->FillRect(b); + if(HasFocus){ + V->SetFgColor(0,0,0,255); + }else{ + V->SetFgColor(cD); + } + V->SetBgColor(cL); + V->MovePenTo(34,TOP-7); + V->DrawString(Title.c_str(), -1 ); + } +*/ + + + if(!(flags & B_NOT_CLOSABLE)){ + DrawClose(CloseRect); + } + if(!(flags & B_NOT_ZOOMABLE)){ + DrawZoom(ZoomRect); + } + + +/* if(!(flags & B_NOT_RESIZABLE)) +*/ +} + +void YMakDecorator::Draw(void) +{ + BRect b = frame; + BRect cOBounds = frame; + + rgb_color cB = {0, 0, 0, 255}; + rgb_color cW = {251,251,251,255}; + rgb_color cG = {154,154,154,255}; + rgb_color cD = {113,113,113,255}; + rgb_color cL = {203,203,203,255}; + + // Debug yellow backgound to make sure we cover everthign :) + // Take this out in real ver for speed :P + rgb_color yellow = {255,255,0}; + driver->FillRect(frame,yellow); + + // Stroke outside border + driver->SetHighColor(cB.red,cB.green,cB.blue,cB.alpha); + driver->StrokeRect(b,NULL); + + // Stroke inside border + b = cOBounds; + b.top += TOP - 1; + b.bottom -= FRAME-1; + b.left += FRAME - 1; + b.right -= FRAME-1; + driver->StrokeRect(b,NULL); + + if(focused){ + // Stroke outer boder (raized) + b = cOBounds; + b.left += 1; + b.right -= 1; + b.top += 1; + b.bottom -= 1; + driver->SetHighColor(cW.red,cW.green,cW.blue,cW.alpha); + driver->MovePenTo(BPoint(b.left,b.top));driver->StrokeLine(BPoint(b.right,b.top),NULL); + + driver->MovePenTo(BPoint(b.left,b.bottom));driver->StrokeLine(BPoint(b.left,b.top),NULL); + driver->SetHighColor(cG.red,cG.green,cG.blue,cG.alpha); + driver->MovePenTo(BPoint(b.right,b.top));driver->StrokeLine(BPoint(b.right,b.bottom),NULL); + driver->MovePenTo(BPoint(b.right,b.bottom));driver->StrokeLine(BPoint(b.left,b.bottom),NULL); + + // Stroke inter border (raized) + b = cOBounds; + b.top += TOP - 2; + b.bottom -= FRAME - 2; + b.left += FRAME - 2; + b.right -= FRAME - 2; + driver->SetHighColor(cG.red,cG.green,cG.blue,cG.alpha); + driver->MovePenTo(BPoint(b.left,b.top));driver->StrokeLine(BPoint(b.right,b.top),NULL); + driver->MovePenTo(BPoint(b.left,b.bottom));driver->StrokeLine(BPoint(b.left,b.top),NULL); + driver->SetHighColor(cW.red,cW.green,cW.blue,cW.alpha); + driver->MovePenTo(BPoint(b.right,b.top));driver->StrokeLine(BPoint(b.right,b.bottom),NULL); + driver->MovePenTo(BPoint(b.right,b.bottom));driver->StrokeLine(BPoint(b.left,b.bottom),NULL); + + driver->SetHighColor(cL.red,cL.green,cL.blue,cL.alpha); + // Fill top + b = cOBounds; + b.bottom = b.top + TOP - 3; + b.top += 2; + b.left += 2; + b.right -= 2; + driver->FillRect(b,NULL); + // Fill left + b = cOBounds; + b.left += 2; + b.right = cOBounds.left + FRAME - 3; + b.top = cOBounds.top + TOP - 2; + b.bottom -= 2; + driver->FillRect(b,NULL); + // Fill right + b = cOBounds; + b.left = b.right - FRAME + 3; + b.right -= 2; + b.top = b.top + TOP - 2; + b.bottom -= 2; + driver->FillRect(b,NULL); + // fill bottom + b = cOBounds; + b.top = b.bottom - FRAME + 3; + b.bottom -= 2; + b.left += FRAME - 2; + b.right -= FRAME - 2; + driver->FillRect(b,NULL); + + // Stroke the lines .. stoke them oohh ya .. storkem .. + // + b = cOBounds; + b.left += 20; + b.right -= 20; + b.top += 4; + b.bottom += 10; + + //if((Flags & WND_NO_DEPTH_BUT) == 0){ + // b.right -= 20; + //} + + + driver->SetHighColor(cW.red,cW.green,cW.blue,cW.alpha); + driver->MovePenTo(BPoint(b.left,b.top+0));driver->StrokeLine(BPoint(b.right-1,b.top+0),NULL); + driver->MovePenTo(BPoint(b.left,b.top+2));driver->StrokeLine(BPoint(b.right-1,b.top+2),NULL); + driver->MovePenTo(BPoint(b.left,b.top+4));driver->StrokeLine(BPoint(b.right-1,b.top+4),NULL); + driver->MovePenTo(BPoint(b.left,b.top+6));driver->StrokeLine(BPoint(b.right-1,b.top+6),NULL); + driver->MovePenTo(BPoint(b.left,b.top+8));driver->StrokeLine(BPoint(b.right-1,b.top+8),NULL); + driver->MovePenTo(BPoint(b.left,b.top+10));driver->StrokeLine(BPoint(b.right-1,b.top+10),NULL); + +#ifdef DEBUG_DECOR +printf("About to draw high lines\n"); +printf("do done\n"); +#endif + driver->SetHighColor(cD.red,cD.green,cD.blue,cD.alpha); + driver->MovePenTo(BPoint(b.left+1,b.top+1));driver->StrokeLine(BPoint(b.right,b.top+1),NULL); + driver->MovePenTo(BPoint(b.left+1,b.top+3));driver->StrokeLine(BPoint(b.right,b.top+3),NULL); + driver->MovePenTo(BPoint(b.left+1,b.top+5));driver->StrokeLine(BPoint(b.right,b.top+5),NULL); + driver->MovePenTo(BPoint(b.left+1,b.top+7));driver->StrokeLine(BPoint(b.right,b.top+7),NULL); + driver->MovePenTo(BPoint(b.left+1,b.top+9));driver->StrokeLine(BPoint(b.right,b.top+9),NULL); + driver->MovePenTo(BPoint(b.left+1,b.top+11));driver->StrokeLine(BPoint(b.right,b.top+11),NULL); + + }else{ + driver->SetHighColor(cL.red,cL.green,cL.blue,cL.alpha); + // Fill top + b = cOBounds; + b.bottom = b.top + TOP - 2; + b.top += 1; + b.left += 1; + b.right -= 1; + driver->FillRect(b,NULL); + // Fill left side + b = cOBounds; + b.left += 1; + b.right = b.left + FRAME - 2; + b.top = b.top + TOP - 1; + b.bottom -= 1; + driver->FillRect(b,NULL); + // fill right + b = cOBounds; + b.left = b.right - FRAME + 2; + b.right -= 1; + b.top = b.top + TOP - 1; + b.bottom -= 1; + driver->FillRect(b,NULL); + // fill bottom + b = cOBounds; + b.top = b.bottom - FRAME + 2; + b.bottom -= 1; + b.left += FRAME - 1; + b.right -= FRAME - 1; + driver->FillRect(b,NULL); + } + + +/* if((flags & WND_NO_TITLE) == 0){ + // Stroke The title Text + driver->SetFgColor(cL.red,cL.green,cL.blue,cL.alpha); + b.left = 30; + b.right = 100; + //Font *font = new Font(DEFAULT_FONT_WINDOW); + //b.right = font->GetStringWidth(Title.c_str()); + + int32 len = strlen(Title.c_str()); + b.right = b.left + len * 7; + + + b.top = 2; + b.bottom = TOP - 3; + V->FillRect(b); + if(HasFocus){ + V->SetFgColor(0,0,0,255); + }else{ + V->SetFgColor(cD); + } + V->SetBgColor(cL); + V->MovePenTo(34,TOP-7); + V->DrawString(Title.c_str(), -1 ); + } +*/ + + + if(!(flags & B_NOT_CLOSABLE)){ + DrawClose(CloseRect); + } + if(!(flags & B_NOT_ZOOMABLE)){ + DrawZoom(ZoomRect); + } + +} + +/******************************************************* +* @description +*******************************************************/ +void YMakDecorator::DrawZoom(BRect r){ +// if(zoomstate) +} + +/******************************************************* +* @description +*******************************************************/ +void YMakDecorator::DrawClose(BRect r){ + BRect b = CloseRect; + + // if((Flags & WND_NO_CLOSE_BUT)){ return; } +// if(!HasFocus){ return; } + + + b.left += 1; + b.right -= 1; + b.top += 1; + b.bottom -= 1; + driver->SetHighColor(32,32,32,255); + /*V->DrawLine(Point(b.left,b.top),Point(b.right,b.top)); + V->DrawLine(Point(b.right,b.top),Point(b.right,b.bottom)); + V->DrawLine(Point(b.left,b.bottom),Point(b.left,b.top)); + V->DrawLine(Point(b.right,b.bottom),Point(b.left,b.bottom));*/ + driver->StrokeRect(b,NULL); + + + b = CloseRect; + + // top left higlith + driver->SetHighColor(136,136,136,255); + driver->MovePenTo(BPoint(b.left,b.top));driver->StrokeLine(BPoint(b.right-1,b.top),NULL); + driver->MovePenTo(BPoint(b.left,b.top+1));driver->StrokeLine(BPoint(b.left,b.bottom-1),NULL); + + // right bottom shadow + driver->SetHighColor(251,251,251,255); + driver->MovePenTo(BPoint(b.right,b.bottom));driver->StrokeLine(BPoint(b.left+1,b.bottom),NULL); + driver->MovePenTo(BPoint(b.right,b.bottom));driver->StrokeLine(BPoint(b.right,b.top+1),NULL); + + if(closestate){ + b = CloseRect; + b.left += 2; + b.right -= 2; + b.top += 2; + b.bottom -= 2; + + // Button down + driver->SetHighColor(200,200,200,255); + driver->FillRect(b,NULL); + }else{ + b = CloseRect; + b.left += 2; + b.right -= 2; + b.top += 2; + b.bottom -= 2; + + // top left + driver->SetHighColor(240,240,240,255); + driver->MovePenTo(BPoint(b.left,b.top));driver->StrokeLine(BPoint(b.right,b.top),NULL); + driver->MovePenTo(BPoint(b.left,b.top));driver->StrokeLine(BPoint(b.left,b.bottom),NULL); + + // bottom right + driver->SetHighColor(136,136,136,255); + driver->MovePenTo(BPoint(b.right,b.bottom));driver->StrokeLine(BPoint(b.left+1,b.bottom),NULL); + driver->MovePenTo(BPoint(b.right,b.bottom));driver->StrokeLine(BPoint(b.right,b.top+1),NULL); + + // fill insdie (Hacked - Mack is a gradiant in the button :P!!) + driver->SetHighColor(203,203,203,255); + b.left += 1; + b.right -= 1; + b.top += 1; + b.bottom -= 1; + driver->FillRect(b,NULL); + } +} + +/******************************************************* +* @description +*******************************************************/ +void YMakDecorator::SetLook(window_look wlook){ + look = wlook; +} + +/******************************************************* +* @description +*******************************************************/ +void YMakDecorator::CalculateBorders(void){ + switch(look) + { + case B_NO_BORDER_WINDOW_LOOK: + { +// bsize.Set(0,0,0,0); + break; + } + case B_TITLED_WINDOW_LOOK: + case B_DOCUMENT_WINDOW_LOOK: + case B_BORDERED_WINDOW_LOOK: + { +// bsize.top=18; + break; + } + case B_MODAL_WINDOW_LOOK: + case B_FLOATING_WINDOW_LOOK: + { +// bsize.top=15; + break; + } + default: + { + break; + } + } +} + + + + diff --git a/src/servers/app/proto5/YMakDecorator.h b/src/servers/app/proto5/YMakDecorator.h new file mode 100644 index 0000000000..e52e95e5a7 --- /dev/null +++ b/src/servers/app/proto5/YMakDecorator.h @@ -0,0 +1,49 @@ +#ifndef _YNOP_MAK_DECORATOR_H_ +#define _YNOP_MAK_DECORATOR_H_ + +#include "Decorator.h" + +class YMakDecorator: public Decorator{ +public: + YMakDecorator(Layer *lay, uint32 dflags, window_look wlook); + ~YMakDecorator(void); + + click_type Clicked(BPoint pt, uint32 buttons); + void Resize(BRect rect); + BRect GetBorderSize(void); + BPoint GetMinimumSize(void); + void SetTitle(const char *newtitle); + void SetFlags(uint32 flags); + void SetLook(window_look wlook); + void UpdateFont(void); + void UpdateTitle(const char *string); + void SetFocus(bool focused); + void SetCloseButton(bool down); + void SetZoomButton(bool down); + void Draw(BRect update); + void Draw(void); + void DrawZoom(BRect r); + void DrawClose(BRect r); + void CalculateBorders(void); +private: + BRect frame; + + bool zoomstate; + bool closestate; + + BRect CloseRect; + BRect ZoomRect; + + int LeftBorder; + int TopBorder; + int RightBorder; + int BottomBorder; +/* + bool HasFocus; + bool CloseState; + bool ZoomState; + bool DepthState; +*/ +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto5/main.cpp b/src/servers/app/proto5/main.cpp new file mode 100644 index 0000000000..a237ea2468 --- /dev/null +++ b/src/servers/app/proto5/main.cpp @@ -0,0 +1,16 @@ +// main.cpp + + +const char app_sig[] = "application/x-vnd.myApp"; + +#include + +int main() +{ + if(is_computer_on()) + { + // TODO: start up the application! + } + + return 0; +} diff --git a/src/servers/app/proto5/obhey/obhey.c b/src/servers/app/proto5/obhey/obhey.c new file mode 100644 index 0000000000..8e6bfbd617 --- /dev/null +++ b/src/servers/app/proto5/obhey/obhey.c @@ -0,0 +1,25 @@ +#include +#include +#include +#include +/* + Sends a message to the OpenBeOS app_server's message port +*/ + +int main(int argc, char **argv) +{ + int32 msgcode; + + if(argc>2) + { + port_id serverport=atoi(argv[1]); + msgcode=atoi(argv[2]); + + write_port(serverport,msgcode,NULL,0); + printf("Sent %ld to port %ld\n",msgcode,serverport); + return 1; + } + + printf("obhey port \n"); + return 0; +} \ No newline at end of file diff --git a/src/servers/app/proto5/router/router.cpp b/src/servers/app/proto5/router/router.cpp new file mode 100644 index 0000000000..baf1a7df68 --- /dev/null +++ b/src/servers/app/proto5/router/router.cpp @@ -0,0 +1,134 @@ +#include "router.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include "PortLink.h" +#include "ServerProtocol.h" +//#define SERVER_PORT_NAME "OBappserver" +//#define SERVER_INPUT_PORT "OBinputport" + + +/******************************************************* +* +*******************************************************/ +BInputServerFilter* instantiate_input_filter(){ + return (new RouterInputFilter()); +} + +/******************************************************* +* +*******************************************************/ +RouterInputFilter::RouterInputFilter():BInputServerFilter(){ + port_id pid = find_port(SERVER_INPUT_PORT); + serverlink = new PortLink(pid); + +} + +/******************************************************* +* +*******************************************************/ +RouterInputFilter::~RouterInputFilter(){ +} + +/******************************************************* +* Everthing went just find .. right? +*******************************************************/ +status_t RouterInputFilter::InitCheck(){ + return B_OK; +} + + + +/******************************************************* +* +*******************************************************/ +filter_result RouterInputFilter::Filter(BMessage *message, BList *outList){ + if(serverlink == NULL){ + return B_DISPATCH_MESSAGE; + } + port_id pid = find_port(SERVER_INPUT_PORT); + if(pid < 0){ + return B_DISPATCH_MESSAGE; + } + serverlink->SetPort(pid); + + switch(message->what){ + case B_MOUSE_MOVED:{ + BPoint p; + uint32 buttons = 0; + // get piont and button from msg + if(message->FindPoint("where",&p) != B_OK){ + + } + int64 time=(int64)real_time_clock(); + + serverlink->SetOpCode(B_MOUSE_MOVED); + serverlink->Attach(&time,sizeof(int64)); + serverlink->Attach(&p.x,sizeof(float)); + serverlink->Attach(&p.y,sizeof(float)); + serverlink->Attach(&buttons,sizeof(int32)); + + // prevent server crashes from hanging the Input Server + serverlink->Flush(1000000); + }break; + case B_MOUSE_UP:{ + BPoint p; + + uint32 mod=modifiers(); + // Eventually, we will also be sending a uint32 buttons. + + int64 time=(int64)real_time_clock(); + + message->FindPoint("where",&p); + + serverlink->SetOpCode(B_MOUSE_UP); + serverlink->Attach(&time, sizeof(int64)); + serverlink->Attach(&p.x,sizeof(float)); + serverlink->Attach(&p.y,sizeof(float)); + serverlink->Attach(&mod, sizeof(uint32)); + + // prevent server crashes from hanging the Input Server + serverlink->Flush(1000000); + }break; + case B_MOUSE_DOWN:{ + BPoint p; + + uint32 buttons, + mod=modifiers(); + int32 clicks; + message->FindInt32("clicks",&clicks); + message->FindPoint("where",&p); + message->FindInt32("buttons",(int32*)&buttons); + + int64 time=(int64)real_time_clock(); + + serverlink->SetOpCode(B_MOUSE_DOWN); + serverlink->Attach(&time, sizeof(int64)); + serverlink->Attach(&p.x,sizeof(float)); + serverlink->Attach(&p.y,sizeof(float)); + serverlink->Attach(&mod, sizeof(uint32)); + serverlink->Attach(&buttons, sizeof(uint32)); + serverlink->Attach(&clicks, sizeof(uint32)); + + // prevent server crashes from hanging the Input Server + serverlink->Flush(1000000); + }break; + + // Should be some Mouse Down and Up code here .. + // Along with some Key Down and up codes .. + default: + break; + } + + //delete serverlink; + + // Let all msg flow normally to the + // Be app_server + return B_DISPATCH_MESSAGE; +} diff --git a/src/servers/app/proto5/router/router.h b/src/servers/app/proto5/router/router.h new file mode 100644 index 0000000000..5cfa514e66 --- /dev/null +++ b/src/servers/app/proto5/router/router.h @@ -0,0 +1,23 @@ +#ifndef _ROUTER_H +#define _ROUTER_H + +#include +#include +#include +#include + +class PortLink; + +// export this for the input_server +extern "C" _EXPORT BInputServerFilter* instantiate_input_filter(); + +class RouterInputFilter : public BInputServerFilter { + public: + RouterInputFilter(); + virtual ~RouterInputFilter(); + virtual status_t InitCheck(); + virtual filter_result Filter(BMessage *message, BList *outList); +private: + PortLink *serverlink; +}; +#endif \ No newline at end of file diff --git a/src/servers/app/proto5/testobapp/BUGS b/src/servers/app/proto5/testobapp/BUGS new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/servers/app/proto5/testobapp/CHANGES b/src/servers/app/proto5/testobapp/CHANGES new file mode 100644 index 0000000000..97ae3aae99 --- /dev/null +++ b/src/servers/app/proto5/testobapp/CHANGES @@ -0,0 +1,6 @@ +OBApplication - Prototype 5 + +App properly falls through if construction failed +Added a server ping failsafe +Added REMOVEWINDOW code +Moved quit-all-windows code to Quit() to fix a crasher \ No newline at end of file diff --git a/src/servers/app/proto5/testobapp/DebugTools.cpp b/src/servers/app/proto5/testobapp/DebugTools.cpp new file mode 100644 index 0000000000..0a0c6aed1d --- /dev/null +++ b/src/servers/app/proto5/testobapp/DebugTools.cpp @@ -0,0 +1,219 @@ +#include +#include +#include +#include "DebugTools.h" + +void PrintStatusToStream(status_t value) +{ + // Function which simply translates a returned status code into a string + // and dumps it to stdout + BString outstr; + switch(value) + { + case B_OK: + outstr="B_OK "; + break; + case B_NAME_NOT_FOUND: + outstr="B_NAME_NOT_FOUND "; + break; + case B_BAD_VALUE: + outstr="B_BAD_VALUE "; + break; + case B_ERROR: + outstr="B_ERROR "; + break; + case B_TIMED_OUT: + outstr="B_TIMED_OUT "; + break; + case B_NO_MORE_PORTS: + outstr="B_NO_MORE_PORTS "; + break; + case B_WOULD_BLOCK: + outstr="B_WOULD_BLOCK "; + break; + case B_BAD_PORT_ID: + outstr="B_BAD_PORT_ID "; + break; + case B_BAD_TEAM_ID: + outstr="B_BAD_TEAM_ID "; + break; + default: + outstr="undefined status value in debugtools::PrintStatusToStream() "; + break; + } + cout << "Status: " << outstr.String() << endl << flush; + +} + +void PrintColorSpaceToStream(color_space value) +{ + // Dump a color space to cout + BString outstr; + switch(value) + { + case B_RGB32: + outstr="B_RGB32 "; + break; + case B_RGBA32: + outstr="B_RGBA32 "; + break; + case B_RGB32_BIG: + outstr="B_RGB32_BIG "; + break; + case B_RGBA32_BIG: + outstr=" "; + break; + case B_UVL32: + outstr="B_UVL32 "; + break; + case B_UVLA32: + outstr="B_UVLA32 "; + break; + case B_LAB32: + outstr="B_LAB32 "; + break; + case B_LABA32: + outstr="B_LABA32 "; + break; + case B_HSI32: + outstr="B_HSI32 "; + break; + case B_HSIA32: + outstr="B_HSIA32 "; + break; + case B_HSV32: + outstr="B_HSV32 "; + break; + case B_HSVA32: + outstr="B_HSVA32 "; + break; + case B_HLS32: + outstr="B_HLS32 "; + break; + case B_HLSA32: + outstr="B_HLSA32 "; + break; + case B_CMY32: + outstr="B_CMY32"; + break; + case B_CMYA32: + outstr="B_CMYA32 "; + break; + case B_CMYK32: + outstr="B_CMYK32 "; + break; + case B_RGB24_BIG: + outstr="B_RGB24_BIG "; + break; + case B_RGB24: + outstr="B_RGB24 "; + break; + case B_LAB24: + outstr="B_LAB24 "; + break; + case B_UVL24: + outstr="B_UVL24 "; + break; + case B_HSI24: + outstr="B_HSI24 "; + break; + case B_HSV24: + outstr="B_HSV24 "; + break; + case B_HLS24: + outstr="B_HLS24 "; + break; + case B_CMY24: + outstr="B_CMY24 "; + break; + case B_GRAY1: + outstr="B_GRAY1 "; + break; + case B_CMAP8: + outstr="B_CMAP8 "; + break; + case B_GRAY8: + outstr="B_GRAY8 "; + break; + case B_YUV411: + outstr="B_YUV411 "; + break; + case B_YUV420: + outstr="B_YUV420 "; + break; + case B_YCbCr422: + outstr="B_YCbCr422 "; + break; + case B_YCbCr411: + outstr="B_YCbCr411 "; + break; + case B_YCbCr420: + outstr="B_YCbCr420 "; + break; + case B_YUV422: + outstr="B_YUV422 "; + break; + case B_YUV9: + outstr="B_YUV9 "; + break; + case B_YUV12: + outstr="B_YUV12 "; + break; + case B_RGB15: + outstr="B_RGB15 "; + break; + case B_RGBA15: + outstr="B_RGBA15 "; + break; + case B_RGB16: + outstr="B_RGB16 "; + break; + case B_RGB16_BIG: + outstr="B_RGB16_BIG "; + break; + case B_RGB15_BIG: + outstr="B_RGB15_BIG "; + break; + case B_RGBA15_BIG: + outstr="B_RGBA15_BIG "; + break; + case B_YCbCr444: + outstr="B_YCbCr444 "; + break; + case B_YUV444: + outstr="B_YUV444 "; + break; + case B_NO_COLOR_SPACE: + outstr="B_NO_COLOR_SPACE "; + break; + default: + outstr="Undefined color space "; + break; + } + cout << "Color Space: " << outstr.String() << flush; +} + +void TranslateMessageCodeToStream(int32 code) +{ + // Used to translate BMessage message codes back to a character + // format + + cout << "'" + << (char)((code & 0xFF000000) >> 24) + << (char)((code & 0x00FF0000) >> 16) + << (char)((code & 0x0000FF00) >> 8) + << (char)((code & 0x000000FF)) << "' "; +} + +void PrintMessageCode(int32 code) +{ + // Used to translate BMessage message codes back to a character + // format + + printf("Message code %c%c%c%c\n", + (char)((code & 0xFF000000) >> 24), + (char)((code & 0x00FF0000) >> 16), + (char)((code & 0x0000FF00) >> 8), + (char)((code & 0x000000FF)) ); +} + diff --git a/src/servers/app/proto5/testobapp/DebugTools.h b/src/servers/app/proto5/testobapp/DebugTools.h new file mode 100644 index 0000000000..2f45b1ac6c --- /dev/null +++ b/src/servers/app/proto5/testobapp/DebugTools.h @@ -0,0 +1,12 @@ +#ifndef _DEBUGTOOLS_H_ +#define _DEBUGTOOLS_H_ + +#include +#include + +void PrintStatusToStream(status_t value); +void PrintColorSpaceToStream(color_space value); +void TranslateMessageCodeToStream(int32 code); +void PrintMessageCode(int32 code); + +#endif \ No newline at end of file diff --git a/src/servers/app/proto5/testobapp/OBApplication.cpp b/src/servers/app/proto5/testobapp/OBApplication.cpp new file mode 100644 index 0000000000..2fcd3265c0 --- /dev/null +++ b/src/servers/app/proto5/testobapp/OBApplication.cpp @@ -0,0 +1,402 @@ +/* + OBApplication.cpp: + Beginning framework for a *real* BApplication replacement for prototype #5 + +*/ + +#include +#include // for the pattern struct and screen mode defs +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ServerProtocol.h" +#include "PortLink.h" +#include "OBApplication.h" +#include "OBWindow.h" +#include "DebugTools.h" + +OBApplication *obe_app; + +#define DEBUG_OBAPP + +OBApplication::OBApplication(const char *sig) : BApplication(sig) +{ + if(sig) + signature=new BString(sig); + else + signature=new BString("application/x-vnd.obos-OBApplication"); + +#ifdef DEBUG_OBAPP +printf("OBApplication(%s)\n",signature->String()); +#endif + + // A BApplication is locked on start, but because this is not a "real" + // one, we do not actually lock it. + + initcheckval=B_OK; + + // Receives messages from server and others + messageport=create_port(50,"msgport"); + if(messageport==B_BAD_VALUE || messageport==B_NO_MORE_PORTS) + { + printf("OBApplication: Couldn't create message port\n"); + initcheckval=B_ERROR; + } + + // Find the port for the app_server + serverport=find_port("OBappserver"); + if(serverport==B_NAME_NOT_FOUND) + { + printf("OBApplication: Couldn't find server port\n"); + serverlink=NULL; + write_port(messageport,B_QUIT_REQUESTED,NULL,0); + initcheckval=B_ERROR; + } + else + { + serverlink=new PortLink(serverport); +#ifdef DEBUG_OBAPP +printf("OBApplication(%s): App Server Port %ld\n",signature->String(),serverport); +#endif + + // Notify server of app's existence + int32 replycode; + status_t replystat; + ssize_t replysize; + int8 *replybuffer; + + serverlink->SetOpCode(CREATE_APP); + serverlink->Attach(&messageport,sizeof(port_id)); +// serverlink.Attach(PID); + serverlink->Attach((char*)signature->String(),strlen(signature->String())); + + // Send and wait for ServerApp port. Necessary here (as opposed to start + // of message loop) in case any windows are created in application constructor + replybuffer=serverlink->FlushWithReply(&replycode,&replystat,&replysize); + serverport=*((port_id*)replybuffer); + serverlink->SetPort(serverport); + delete replybuffer; +#ifdef DEBUG_OBAPP +printf("OBApplication(%s): ServerApp Port %ld\n",signature->String(),serverport); +#endif + ReadyToRun(); + } + + obe_app=this; + windowlist=new BList(0); +} + +OBApplication::~OBApplication(void) +{ +#ifdef DEBUG_OBAPP +printf("%s::~OBApplication()\n",signature->String()); +#endif + delete signature; + + if(serverlink) + delete serverlink; + +// OBWindow *win; +// for(int32 i=0; iCountItems(); i++) +// { +// win=(OBWindow*)windowlist->RemoveItem(i); +// if(win) +// win->Quit(); +// } + + delete windowlist; +} + +status_t OBApplication::InitCheck(void) const +{ + // Called to make sure everything in the constructor turned out ok. If it didn't, + // the application falls through and the process ends. + return initcheckval; +} + +void OBApplication::MainLoop(void) +{ +#ifdef DEBUG_OBAPP +printf("%s::MainLoop()\n",signature->String()); +#endif + + int32 msgcode; + uint8 *msgbuffer=NULL; + ssize_t buffersize,bytesread; + + for(;;) + { + // Modified this slightly so that OBApplications will eventually time out + // if the server crashes. Saves on a lot of Ctrl-Alt-Del's. :) CPU time is + // saved by setting the timeout to 3 seconds - more than enough time. + if(find_thread("OBAppServer")==B_NAME_NOT_FOUND) + { + printf("%s lost connection with server. Quitting.\n",signature->String()); + break; + } + + buffersize=port_buffer_size_etc(messageport,B_TIMEOUT,300000); + if(buffersize==B_TIMED_OUT) + continue; + + if(buffersize>0) + { + // buffers are flattened messages. Allocate necessary buffer and + // we'll cast it as a BMessage. + msgbuffer=new uint8[buffersize]; + bytesread=read_port(messageport,&msgcode,msgbuffer,buffersize); + } + else + bytesread=read_port(messageport,&msgcode,NULL,0); + + if (bytesread != B_BAD_PORT_ID && bytesread != B_TIMED_OUT && bytesread != B_WOULD_BLOCK) + { + switch(msgcode) + { + case B_QUIT_REQUESTED: + { + // Attached data: + // None +// printf("%s: Quit requested\n",signature); + serverlink->SetOpCode(msgcode); + serverlink->Flush(); + break; + } +/* case SET_SERVER_PORT: + { + // This message is received when the server has created + // the ServerApp object to monitor our application. It is + // sending us the port to which we send future messages + + // Attached data: + // port_id - id of the port of the corresponding ServerApp + if(buffersize<1) + { + printf("%s: Set Server Port has no attached data\n",signature->String()); + break; + } +// printf("%s: Set Server Port to %ld\n",signature,*((port_id *)msgbuffer)); + serverport=*((port_id *)msgbuffer); + serverlink->SetPort(serverport); + ReadyToRun(); + break; + } +*/ + case ADDWINDOW: + { + // This message is received by a window's constructor so that it + // can be added to the window list + + // Attached Data: + // 1) OBWindow *window + + // I hope this is the right syntax... + windowlist->AddItem(msgbuffer); +#ifdef DEBUG_OBAPP +printf("%s: Add Window @ %p\n",signature->String(),msgbuffer); +#endif + break; + } + case REMOVEWINDOW: + { + // This message is received by a window's constructor so that it + // can be added to the window list + + // Attached Data: + // 1) OBWindow *window + + // I hope this is the right syntax... + windowlist->RemoveItem(msgbuffer); +#ifdef DEBUG_OBAPP +printf("%s: Remove Window @ %p\n",signature->String(),msgbuffer); +#endif + break; + } + case B_MOUSE_MOVED: + case B_MOUSE_DOWN: + case B_MOUSE_UP: + DispatchMessage(msgcode, (int8*)msgbuffer); + break; + + // Later on, this will default to passing the message to + // DispatchMessage(BMessage*, BHandler*) + default: + printf("OBApplication received unexpected code %ld - ",msgcode); + PrintMessageCode(msgcode); + break; + } + + if(msgcode==B_QUIT_REQUESTED) + { + printf("Quitting %s\n",signature->String()); + break; + } + } + + if(buffersize>0) + delete msgbuffer; + } +} + +void OBApplication::DispatchMessage(BMessage *msg, BHandler *handler) +{ +#ifdef DEBUG_OBAPP +printf("%s::DispatchMessage(BMessage*,BHandler*)\n",signature->String()); +#endif + BApplication::DispatchMessage(msg,handler); +} + +void OBApplication::DispatchMessage(int32 code, int8 *buffer) +{ + // This function will be necessary to handle server messages. + switch(code) + { + case B_MOUSE_DOWN: + case B_MOUSE_UP: + case B_MOUSE_MOVED: + break; + default: + printf("OBApplication %s received unknown code %ld\n",signature->String(),code); + break; + } +} + +void OBApplication::MessageReceived(BMessage *msg) +{ +#ifdef DEBUG_OBAPP +printf("%s::MessageReceived()\n",signature->String()); +#endif +} + +void OBApplication::ShowCursor(void) +{ +#ifdef DEBUG_OBAPP +printf("%s::ShowCursor()\n",signature->String()); +#endif + serverlink->SetOpCode(SHOW_CURSOR); + serverlink->Flush(); +} + +void OBApplication::HideCursor(void) +{ +#ifdef DEBUG_OBAPP +printf("%s::HideCursor()\n",signature->String()); +#endif + serverlink->SetOpCode(HIDE_CURSOR); + serverlink->Flush(); +} + +void OBApplication::ObscureCursor(void) +{ +#ifdef DEBUG_OBAPP +printf("%s::ObscureCursor()\n",signature->String()); +#endif + serverlink->SetOpCode(OBSCURE_CURSOR); + serverlink->Flush(); +} + +bool OBApplication::IsCursorHidden(void) const +{ + return false; +} + +void OBApplication::SetCursor(const void *cursor) +{ +#ifdef DEBUG_OBAPP +printf("%s::SetCursor()\n",signature->String()); +#endif + // attach & send the 68-byte chunk + serverlink->SetOpCode(SET_CURSOR_DATA); + serverlink->Attach((void*)cursor, 68); + serverlink->Flush(); +} + +thread_id OBApplication::Run(void) +{ +#ifdef DEBUG_OBAPP +printf("%s::Run()\n",signature->String()); +#endif + if(initcheckval==B_OK) + MainLoop(); + + return 0; +} + +status_t OBApplication::Archive(BMessage *data, bool deep = true) const +{ + return B_ERROR; +} + +void OBApplication::Quit(void) +{ +#ifdef DEBUG_OBAPP +printf("%s::Quit()\n",signature->String()); +#endif + OBWindow *win; + while(windowlist->CountItems()>0) + { + win=(OBWindow*)windowlist->RemoveItem(0L); + if(win) + win->Quit(); + } + + BApplication::Quit(); +} + +bool OBApplication::QuitRequested(void) +{ +#ifdef DEBUG_OBAPP +printf("%s::QuitRequested()\n",signature->String()); +#endif + return true; +} + +void OBApplication::Pulse(void) +{ +} + +void OBApplication::ArgvReceived(int32 argc, char **argv) +{ +} + +void OBApplication::AppActivated(bool active) +{ +} + +void OBApplication::RefsReceived(BMessage *a_message) +{ +} + +void OBApplication::AboutRequested(void) +{ +} + +BHandler *OBApplication::ResolveSpecifier(BMessage *msg,int32 index,BMessage *specifier, + int32 form,const char *property) +{ + return NULL; +} + +status_t OBApplication::GetSupportedSuites(BMessage *data) +{ + return B_ERROR; +} + +status_t OBApplication::Perform(perform_code d, void *arg) +{ + return B_ERROR; +} + +void OBApplication::ReadyToRun(void) +{ +#ifdef DEBUG_OBAPP +printf("%s::ReadyToRun()\n",signature->String()); +#endif +} diff --git a/src/servers/app/proto5/testobapp/OBApplication.h b/src/servers/app/proto5/testobapp/OBApplication.h new file mode 100644 index 0000000000..14478ddfba --- /dev/null +++ b/src/servers/app/proto5/testobapp/OBApplication.h @@ -0,0 +1,71 @@ +#ifndef _OBOS_APPLICATION_H_ +#define _OBOS_APPLICATION_H_ + +#include +#include + +class PortLink; +class BList; +class OBWindow; + +class OBApplication : private BApplication +{ +public: + +OBApplication(const char *signature); +OBApplication(const char *signature, status_t *error); +virtual ~OBApplication(void); + +OBApplication(BMessage *data); +static BArchivable *Instantiate(BMessage *data); +virtual status_t Archive(BMessage *data, bool deep = true) const; + +status_t InitCheck() const; + +virtual thread_id Run(void); +virtual void Quit(void); +virtual bool QuitRequested(void); +virtual void Pulse(void); +virtual void ReadyToRun(void); +virtual void MessageReceived(BMessage *msg); +virtual void ArgvReceived(int32 argc, char **argv); +virtual void AppActivated(bool active); +virtual void RefsReceived(BMessage *a_message); +virtual void AboutRequested(void); + +virtual BHandler *ResolveSpecifier(BMessage *msg,int32 index, +BMessage *specifier,int32 form,const char *property); + +void ShowCursor(void); +void HideCursor(void); +void ObscureCursor(void); +bool IsCursorHidden(void) const; +void SetCursor(const void *cursor); +void SetCursor(const BCursor *cursor, bool sync=true); +int32 CountWindows(void) const; +BWindow *WindowAt(int32 index) const; +int32 CountLoopers(void) const; +BLooper *LooperAt(int32 index) const; +bool IsLaunching(void) const; +status_t GetAppInfo(app_info *info) const; +static BResources *AppResources(void); +virtual void DispatchMessage(BMessage *an_event,BHandler *handler); +void SetPulseRate(bigtime_t rate); +virtual status_t GetSupportedSuites(BMessage *data); +virtual status_t Perform(perform_code d, void *arg); + +protected: +friend OBWindow; + +void MainLoop(void); +void DispatchMessage(int32 code, int8 *buffer); + +port_id messageport, serverport; +BString *signature; +PortLink *serverlink; +BList *windowlist; +status_t initcheckval; +}; + +extern OBApplication *obe_app; +#endif \ No newline at end of file diff --git a/src/servers/app/proto5/testobapp/OBTestApp.cpp b/src/servers/app/proto5/testobapp/OBTestApp.cpp new file mode 100644 index 0000000000..5b9899f105 --- /dev/null +++ b/src/servers/app/proto5/testobapp/OBTestApp.cpp @@ -0,0 +1,30 @@ +#include "OBApplication.h" +#include "OBWindow.h" +#include "OBView.h" + +class OBTestApp : public OBApplication +{ +public: + OBTestApp(void); + ~OBTestApp(void); +}; + +OBWindow *win; + +OBTestApp::OBTestApp(void) : OBApplication("application/OBTestApp") +{ + win=new OBWindow(BRect(100,100,200,200), "OBWindow1",B_BORDERED_WINDOW_LOOK, + B_NORMAL_WINDOW_FEEL,0); + win->Show(); +} + +OBTestApp::~OBTestApp(void) +{ +} + +int main(void) +{ + OBTestApp *app=new OBTestApp(); + app->Run(); + delete app; +} diff --git a/src/servers/app/proto5/testobapp/OBView.cpp b/src/servers/app/proto5/testobapp/OBView.cpp new file mode 100644 index 0000000000..1132f77db5 --- /dev/null +++ b/src/servers/app/proto5/testobapp/OBView.cpp @@ -0,0 +1,872 @@ +#include +#include +#include "PortLink.h" +#include "ServerProtocol.h" +#include "OBView.h" +#include "OBWindow.h" + +//#define DEBUG_VIEW + +#ifndef SET_RGB_COLOR + #define SET_RGB_COLOR(a,b,c,d,e) a.red=b; a.green=c; a.blue=d; a.alpha=e; +#endif + +OBView::OBView(BRect frame,const char *name,uint32 resizeMask,uint32 flags) + : BHandler(name) +{ + viewflags=flags; + resizeflags=resizeMask; + origin_h=0.0; + origin_v=0.0; + + owner=NULL; + parent=NULL; + uppersibling=NULL; + lowersibling=NULL; + topchild=NULL; + bottomchild=NULL; + hidelevel=0; + + // This will be changed when added to a BWindow as the top view + topview=false; + + SET_RGB_COLOR(highcol,0,0,0,255); + SET_RGB_COLOR(lowcol,255,255,255,255); + SET_RGB_COLOR(viewcol,255,255,255,255); + + // We need to align to the nearest pixel, rounded down + // There's probably a better way to do this, but it'll work for now... + vframe.left=(int32)frame.left; + vframe.top=(int32)frame.top; + vframe.right=(int32)frame.right; + vframe.bottom=(int32)frame.bottom; +} + +OBView::~OBView() +{ + // Be Book says it's an error to delete while attached to a window. + // We'll just prevent that problem... + if(owner) + { + // No, this isn't an error to utilize parent and not owner. We + // aren't actually attached to the window class itself. We're + // attached to a view which is a member of the window. + parent->RemoveChild(this); + } + + + OBView *v; + for(v=topchild; v!=NULL; v=v->lowersibling) + delete v; +} + +void OBView::AttachedToWindow() +{ + // Hook function +} + +void OBView::AllAttached() +{ + // Hook function +} + +void OBView::DetachedFromWindow() +{ + // Hook function +} + +void OBView::AllDetached() +{ + // Hook function +} + +void OBView::MessageReceived(BMessage *msg) +{ + // Adds scripting support to the BHandler version. This is + // only a skeleton implementation, so it has been skipped + BHandler::MessageReceived(msg); +} + +void OBView::AddChild(OBView *child, OBView *before = NULL) +{ + if(!child) + return; + if(child->parent || child->owner) + { + printf("%s::AddChild(): child already has a parent\n",Name()); + return; + } + if(child->parent==this) + { + printf("%s::AddChild(): child already belongs to view\n",Name()); + return; + } + + // Adds a layer to the top of the layer's children +#ifdef DEBUG_VIEW + printf("%s::AddChild(%s)\n", Name(), child->Name()); +#endif + + child->parent=this; + child->owner=owner; + + // View specified. Add new child above the specified view + if(before) + { + if(before->parent==this) + { + child->lowersibling=before; + child->uppersibling=before->uppersibling; + before->uppersibling->lowersibling=child; + before->uppersibling=child; + + // If we're attached to a window, notify all child views of + // their attachment + if(owner) + { + CallAttached(child); + child->AllAttached(); + } + + } + else + { + printf("%s::AddChild(): Can't add %s before %s - different parents\n", + Name(), child->Name(), before->Name()); + } + return; + } + + // If we haven't specified, child is added to bottom of list + if(bottomchild!=NULL) + { + child->uppersibling=bottomchild; + bottomchild->lowersibling=child; + } + bottomchild=child; + +} + +bool OBView::RemoveChild(OBView *child) +{ + if(!child) + return false; + + if(child->parent!=this) + { + printf("%s::RemoveChild(): %s not child of this view\n",Name(),child->Name()); + return false; + } + + // Adds a layer to the top of the layer's children +#ifdef DEBUG_VIEW + printf("%s::RemoveChild(%s)\n", Name(), child->Name()); +#endif + + if(owner) + { + CallDetached(child); + + // We only need to tell the server to prune the layer tree + // at the child's level + PortLink *link=new PortLink(owner->outport); + link->SetOpCode(LAYER_DELETE); + link->Attach(child->id); + link->Flush(); + delete link; + } + + // Note that we do the pointer reassignments last because the other + // function calls made in RemoveChild() depend on these pointers + if(topchild==child) + topchild=child->lowersibling; + if(bottomchild==child) + bottomchild=child->lowersibling; + + if(child->uppersibling!=NULL) + child->uppersibling->lowersibling=child->lowersibling; + if(child->lowersibling!=NULL) + child->lowersibling->uppersibling=child->uppersibling; + + child->parent=NULL; + child->owner=NULL; + child->lowersibling=NULL; + child->uppersibling=NULL; + return true; +} + +bool OBView::RemoveSelf() +{ + return false; +} + +int32 OBView::CountChildren() const +{ + OBView *v=topchild; + int32 children=0; + + while(v!=NULL) + { + v=v->lowersibling; + children++; + } + + return children; +} + +OBView *OBView::ChildAt(int32 index) const +{ + // We're using a tree, so traverse the tree + OBView *v=topchild; + + for(int32 i=0;ilowersibling; + } + + return v; +} + +OBView *OBView::NextSibling() const +{ + return lowersibling; +} + +OBView *OBView::PreviousSibling() const +{ + return uppersibling; +} + +OBWindow *OBView::Window() const +{ + return owner; +} + +void OBView::Draw(BRect updateRect) +{ +} + +void OBView::MouseDown(BPoint where) +{ + // Hook function +} + +void OBView::MouseUp(BPoint where) +{ + // Hook function +} + +void OBView::MouseMoved(BPoint where,uint32 code,const BMessage *a_message) +{ + // Hook function +} + +void OBView::WindowActivated(bool state) +{ + // Hook function +} + +void OBView::KeyDown(const char *bytes, int32 numBytes) +{ + // Hook function +} + +void OBView::KeyUp(const char *bytes, int32 numBytes) +{ + // Hook function +} + +void OBView::Pulse() +{ + // Hook function +} + +void OBView::FrameMoved(BPoint new_position) +{ + // Hook function +} + +void OBView::FrameResized(float new_width, float new_height) +{ + // Hook function +} + +void OBView::TargetedByScrollView(BScrollView *scroll_view) +{ + // Hook function +} + +void OBView::BeginRectTracking(BRect startRect,uint32 style = B_TRACK_WHOLE_RECT) +{ + if(!owner) + { + printf("BeginRectTracking(): view must be attached to a window\n"); + return; + } + owner->serverlink->SetOpCode(BEGIN_RECT_TRACKING); + owner->serverlink->Attach(&startRect, sizeof(BRect)); + owner->serverlink->Attach(&style, sizeof(uint32)); + owner->serverlink->Flush(); +} + +void OBView::EndRectTracking(void) +{ + if(!owner) + { + printf("EndRectTracking(): view must be attached to a window\n"); + return; + } + owner->serverlink->SetOpCode(END_RECT_TRACKING); + owner->serverlink->Flush(); +} + +void OBView::GetMouse(BPoint *location, uint32 *buttons, + bool checkMessageQueue=true) +{ +} + +OBView *OBView::FindView(const char *name) +{ + OBView *v; + v=FindViewInChildren(name); + + return v; +} + +OBView *OBView::Parent() const +{ + return parent; +} + +BRect OBView::Bounds() const +{ + BRect rframe=vframe; + rframe.OffsetTo(0,0); + return rframe; +} + +BRect OBView::Frame() const +{ + return vframe; +} + +void OBView::ConvertToScreen(BPoint* pt) const +{ +} + +BPoint OBView::ConvertToScreen(BPoint pt) const +{ + return BPoint(-1,-1); +} + +void OBView::ConvertFromScreen(BPoint* pt) const +{ +} + +BPoint OBView::ConvertFromScreen(BPoint pt) const +{ + return BPoint(-1,-1); +} + +void OBView::ConvertToScreen(BRect *r) const +{ +} + +BRect OBView::ConvertToScreen(BRect r) const +{ + return BRect(0,0,0,0); +} + +void OBView::ConvertFromScreen(BRect *r) const +{ +} + +BRect OBView::ConvertFromScreen(BRect r) const +{ + return BRect(0,0,0,0); +} + +void OBView::ConvertToParent(BPoint *pt) const +{ +} + +BPoint OBView::ConvertToParent(BPoint pt) const +{ + return BPoint(-1,-1); +} + +void OBView::ConvertFromParent(BPoint *pt) const +{ +} + +BPoint OBView::ConvertFromParent(BPoint pt) const +{ + return BPoint(-1,-1); +} + +void OBView::ConvertToParent(BRect *r) const +{ +} + +BRect OBView::ConvertToParent(BRect r) const +{ + return BRect(0,0,0,0); +} + +void OBView::ConvertFromParent(BRect *r) const +{ +} + +BRect OBView::ConvertFromParent(BRect r) const +{ + return BRect(0,0,0,0); +} + +BPoint OBView::LeftTop() const +{ + return BPoint(-1,-1); +} + +void OBView::GetClippingRegion(BRegion *region) const +{ +} + +void OBView::ConstrainClippingRegion(BRegion *region) +{ +} + +void OBView::SetDrawingMode(drawing_mode mode) +{ +} + +drawing_mode OBView::DrawingMode() const +{ + return B_OP_COPY; +} + +void OBView::SetBlendingMode(source_alpha srcAlpha, alpha_function alphaFunc) +{ +} + +void OBView::GetBlendingMode(source_alpha *srcAlpha, alpha_function *alphaFunc) const +{ +} + +void OBView::SetPenSize(float size) +{ +} + +float OBView::PenSize() const +{ + return 0.0; +} + +void OBView::SetViewColor(rgb_color c) +{ + SET_RGB_COLOR(viewcol,c.red,c.green,c.blue,c.alpha); + owner->drawmsglink->Attach((int32)GFX_SET_VIEW_COLOR); + owner->drawmsglink->Attach((int8)c.red); + owner->drawmsglink->Attach((int8)c.green); + owner->drawmsglink->Attach((int8)c.blue); + owner->drawmsglink->Attach((int8)c.alpha); +} + +void OBView::SetViewColor(uchar r, uchar g, uchar b, uchar a=255) +{ + SET_RGB_COLOR(viewcol,r,g,b,a); + owner->drawmsglink->Attach((int32)GFX_SET_VIEW_COLOR); + owner->drawmsglink->Attach((int8)r); + owner->drawmsglink->Attach((int8)g); + owner->drawmsglink->Attach((int8)b); + owner->drawmsglink->Attach((int8)a); +} + +rgb_color OBView::ViewColor() const +{ + return viewcol; +} + +void OBView::SetHighColor(rgb_color c) +{ + SET_RGB_COLOR(highcol,c.red,c.green,c.blue,c.alpha); + owner->drawmsglink->Attach((int32)GFX_SET_HIGH_COLOR); + owner->drawmsglink->Attach((int8)c.red); + owner->drawmsglink->Attach((int8)c.green); + owner->drawmsglink->Attach((int8)c.blue); + owner->drawmsglink->Attach((int8)c.alpha); +} + +void OBView::SetHighColor(uchar r, uchar g, uchar b, uchar a=255) +{ + SET_RGB_COLOR(highcol,r,g,b,a); + owner->drawmsglink->Attach((int32)GFX_SET_HIGH_COLOR); + owner->drawmsglink->Attach((int8)r); + owner->drawmsglink->Attach((int8)g); + owner->drawmsglink->Attach((int8)b); + owner->drawmsglink->Attach((int8)a); +} + +rgb_color OBView::HighColor() const +{ + return highcol; +} + +void OBView::SetLowColor(rgb_color c) +{ + SET_RGB_COLOR(lowcol,c.red,c.green,c.blue,c.alpha); + owner->drawmsglink->Attach((int32)GFX_SET_LOW_COLOR); + owner->drawmsglink->Attach((int8)c.red); + owner->drawmsglink->Attach((int8)c.green); + owner->drawmsglink->Attach((int8)c.blue); + owner->drawmsglink->Attach((int8)c.alpha); +} + +void OBView::SetLowColor(uchar r, uchar g, uchar b, uchar a=255) +{ + SET_RGB_COLOR(lowcol,r,g,b,a); + owner->drawmsglink->Attach((int32)GFX_SET_LOW_COLOR); + owner->drawmsglink->Attach((int8)r); + owner->drawmsglink->Attach((int8)g); + owner->drawmsglink->Attach((int8)b); + owner->drawmsglink->Attach((int8)a); +} + +rgb_color OBView::LowColor() const +{ + return lowcol; +} + +void OBView::Invalidate(BRect invalRect) +{ + if(!owner) + { + printf("Invalidate(): view must be attached to a window\n"); + return; + } + owner->drawmsglink->Attach(invalRect); +} + +void OBView::Invalidate(const BRegion *invalRegion) +{ + // undocumented function +} + +void OBView::Invalidate() +{ + if(!owner) + { + printf("Invalidate(): view must be attached to a window\n"); + return; + } + owner->drawmsglink->Attach(Bounds()); +} + +void OBView::SetFlags(uint32 flags) +{ +} + +uint32 OBView::Flags() const +{ + return viewflags; +} + +void OBView::SetResizingMode(uint32 mode) +{ +} + +uint32 OBView::ResizingMode() const +{ + return resizeflags; +} + +void OBView::MoveBy(float dh, float dv) +{ +} + +void OBView::MoveTo(BPoint where) +{ +} + +void OBView::MoveTo(float x, float y) +{ +} + +void OBView::ResizeBy(float dh, float dv) +{ +} + +void OBView::ResizeTo(float width, float height) +{ +} + +void OBView::MakeFocus(bool focusState = true) +{ +} + +bool OBView::IsFocus() const +{ + return has_focus; +} + +void OBView::Show() +{ + hidelevel--; + + for(OBView *v=topchild; v!=NULL; v=v->lowersibling ) + v->Show(); +} + +void OBView::Hide() +{ + hidelevel++; + + for(OBView *v=topchild; v!=NULL; v=v->lowersibling ) + v->Show(); +} + +bool OBView::IsHidden() const +{ + return (hidelevel>0)?true:false; +} + +bool OBView::IsHidden(const OBView* looking_from) const +{ + // undocumented function + return false; +} + +void OBView::Flush() const +{ + // When attachment count inclusion is implemented, it needs to go + // in this function + + owner->drawmsglink->SetOpCode(GFX_FLUSH); + owner->drawmsglink->Flush(); +} + +void OBView::Sync() const +{ + // When attachment count inclusion is implemented, it needs to go + // in this function + + int32 code; + status_t status; + ssize_t buffersize; + + owner->drawmsglink->SetOpCode(GFX_SYNC); + + // Reply received: + + // Code: SYNC + // Attached data: none + // Buffersize: 0 + owner->drawmsglink->FlushWithReply(&code,&status,&buffersize); +} + +void OBView::StrokeRect(BRect r, pattern p=B_SOLID_HIGH) +{ + if(!owner) + { + printf("StrokeRect(): view must be attached to a window\n"); + return; + } + + owner->drawmsglink->Attach((int32)GFX_STROKE_RECT); + owner->drawmsglink->Attach(r); + owner->drawmsglink->Attach(&p, sizeof(pattern)); +} + +void OBView::FillRect(BRect r, pattern p=B_SOLID_HIGH) +{ + if(!owner) + { + printf("FillRect(): view must be attached to a window\n"); + return; + } + + owner->drawmsglink->Attach((int32)GFX_FILL_RECT); + owner->drawmsglink->Attach(r); + owner->drawmsglink->Attach(&p, sizeof(pattern)); +} + +void OBView::MovePenTo(BPoint pt) +{ + if(!owner) + { + printf("MovePenTo(): view must be attached to a window\n"); + return; + } + owner->drawmsglink->Attach((int32)GFX_MOVEPENTO); + owner->drawmsglink->Attach(pt); +} + +void OBView::MovePenTo(float x, float y) +{ + if(!owner) + { + printf("MovePenTo(): view must be attached to a window\n"); + return; + } + owner->drawmsglink->Attach((int32)GFX_MOVEPENTO); + owner->drawmsglink->Attach(BPoint(x,y)); +} + +void OBView::MovePenBy(float x, float y) +{ + if(!owner) + { + printf("MovePenBy(): view must be attached to a window\n"); + return; + } + owner->drawmsglink->Attach((int32)GFX_MOVEPENBY); + owner->drawmsglink->Attach(x); + owner->drawmsglink->Attach(y); +} + +BPoint OBView::PenLocation() const +{ + return BPoint(0,0); +} + +void OBView::StrokeLine(BPoint toPt,pattern p=B_SOLID_HIGH) +{ + if(!owner) + { + printf("StrokeLine(): view must be attached to a window\n"); + return; + } + owner->drawmsglink->Attach((int32)GFX_STROKE_LINE); + owner->drawmsglink->Attach(toPt); + owner->drawmsglink->Attach((pattern *)&p, sizeof(pattern)); +} + +void OBView::StrokeLine(BPoint pt0,BPoint pt1,pattern p=B_SOLID_HIGH) +{ + if(!owner) + { + printf("StrokeLine(): view must be attached to a window\n"); + return; + } + owner->drawmsglink->Attach((int32)GFX_MOVEPENTO); + owner->drawmsglink->Attach(pt0); + + owner->drawmsglink->Attach((int32)GFX_STROKE_LINE); + owner->drawmsglink->Attach(pt1); + owner->drawmsglink->Attach((pattern *)&p, sizeof(pattern)); +} + +// Protected members + +int32 OBView::GetServerToken(void) +{ + // Function which asks the app_server for an ID value + // NOTE that it requires an owner + + if(!owner) + { + printf("GetServerToken(): view must be attached to a window\n"); + return -1; + } + + int32 code; + status_t status; + ssize_t buffersize; + int32 *buffer; + + owner->serverlink->SetOpCode(VIEW_GET_TOKEN); + + // Reply received: + + // Code: GET_VIEW_TOKEN + // Attached data: + // 1) int32 view ID + buffer=(int32*)owner->drawmsglink->FlushWithReply(&code,&status,&buffersize); + id=*buffer; + + // necessary because each reply allocates memory from the heap for + // the returned buffer + delete buffer; + + return id; +} + +void OBView::CallAttached(OBView *view) +{ + // Recursively calls AttachedToWindow() for all children of the view + AddedToWindow(); + AttachedToWindow(); + + for(OBView *v=topchild; v!=NULL; v=v->lowersibling) + { + if(v->topchild) + CallAttached(v->topchild); + } +} + +void OBView::CallDetached(OBView *view) +{ + // Recursively calls DetachedFromWindow() for all children of the view + DetachedFromWindow(); + + for(OBView *v=topchild; v!=NULL; v=v->lowersibling) + { + if(v->topchild) + CallDetached(v->topchild); + } +} + +void OBView::AddedToWindow(void) +{ + // Hook function called during AddChild to take care of setup in server + // of adding a bunch of views at once, not just one + + // Theoretically, shouldn't be needed, but this is here in case I do + // something really stupid. ;) + if(!owner) + return; + + // If we're finally attached to a window, then the child needs to become + // known to the server + + // Create View message. Layers are app_server's view counterparts + + // Attach Data: + // 1) (int32) id of the parent view + // 2) (int32) id of the child view + // 3) (BRect) frame in parent's coordinates + // 4) (int32) resize flags + // 5) (int32) view flags + // 6) (uint16) view's hide level + id=GetServerToken(); + + PortLink *link=new PortLink(owner->outport); + link->SetOpCode(LAYER_CREATE); + link->Attach(parent->id); + link->Attach(id); + link->Attach(vframe); + link->Attach((int32)resizeflags); + link->Attach((int32)viewflags); + link->Attach(&hidelevel,sizeof(uint16)); + link->Flush(); + delete link; +} + +OBView *OBView::FindViewInChildren(const char *name) +{ + // Looks in all children of a view and returns the first view + // with a matching name. + + // Process: + // 1) Search this view's children starting with topchild + // 2) If not found, cycle through them again, this second time + // recursively searching each child. + // 3) If the view is found in the first child search, assign the ** + // and return the *. + // 4) If the view is found in the second child search, break out of the + // search loop by assigning and returning the * + // 5) If we complete the loop, it means that the view was not found. + // We should, thus, return NULL + return NULL; +} diff --git a/src/servers/app/proto5/testobapp/OBView.h b/src/servers/app/proto5/testobapp/OBView.h new file mode 100644 index 0000000000..86a2448d8c --- /dev/null +++ b/src/servers/app/proto5/testobapp/OBView.h @@ -0,0 +1,168 @@ +#ifndef _OBVIEW_H_ +#define _OBVIEW_H_ + +#include +#include +#include +#include +#include +#include + +class BMessage; +class BString; +class BWindow; +class OBWindow; + +class OBView : public BHandler +{ +public: +OBView( BRect frame,const char *name,uint32 resizeMask,uint32 flags); +virtual ~OBView(); + +virtual void AttachedToWindow(); +virtual void AllAttached(); +virtual void DetachedFromWindow(); +virtual void AllDetached(); + +virtual void MessageReceived(BMessage *msg); + +void AddChild(OBView *child, OBView *before = NULL); +bool RemoveChild(OBView *child); +bool RemoveSelf(); +int32 CountChildren() const; +OBView *ChildAt(int32 index) const; +OBView *NextSibling() const; +OBView *PreviousSibling() const; + +OBWindow *Window() const; + +virtual void Draw(BRect updateRect); +virtual void MouseDown(BPoint where); +virtual void MouseUp(BPoint where); +virtual void MouseMoved( BPoint where,uint32 code,const BMessage *a_message); +virtual void WindowActivated(bool state); +virtual void KeyDown(const char *bytes, int32 numBytes); +virtual void KeyUp(const char *bytes, int32 numBytes); +virtual void Pulse(); +virtual void FrameMoved(BPoint new_position); +virtual void FrameResized(float new_width, float new_height); + +virtual void TargetedByScrollView(BScrollView *scroll_view); +void BeginRectTracking( BRect startRect,uint32 style = B_TRACK_WHOLE_RECT); +void EndRectTracking(); + +void GetMouse(BPoint *location,uint32 *buttons,bool checkMessageQueue=true); + +OBView *FindView(const char *name); +OBView *Parent() const; +BRect Bounds() const; +BRect Frame() const; +void ConvertToScreen(BPoint* pt) const; +BPoint ConvertToScreen(BPoint pt) const; +void ConvertFromScreen(BPoint* pt) const; +BPoint ConvertFromScreen(BPoint pt) const; +void ConvertToScreen(BRect *r) const; +BRect ConvertToScreen(BRect r) const; +void ConvertFromScreen(BRect *r) const; +BRect ConvertFromScreen(BRect r) const; +void ConvertToParent(BPoint *pt) const; +BPoint ConvertToParent(BPoint pt) const; +void ConvertFromParent(BPoint *pt) const; +BPoint ConvertFromParent(BPoint pt) const; +void ConvertToParent(BRect *r) const; +BRect ConvertToParent(BRect r) const; +void ConvertFromParent(BRect *r) const; +BRect ConvertFromParent(BRect r) const; +BPoint LeftTop() const; + +void GetClippingRegion(BRegion *region) const; +virtual void ConstrainClippingRegion(BRegion *region); + +virtual void SetDrawingMode(drawing_mode mode); +drawing_mode DrawingMode() const; + +void SetBlendingMode(source_alpha srcAlpha, alpha_function alphaFunc); +void GetBlendingMode(source_alpha *srcAlpha, alpha_function *alphaFunc) const; + +virtual void SetPenSize(float size); +float PenSize() const; + +virtual void SetViewColor(rgb_color c); +void SetViewColor(uchar r, uchar g, uchar b, uchar a = 255); +rgb_color ViewColor() const; + +virtual void SetHighColor(rgb_color a_color); +void SetHighColor(uchar r, uchar g, uchar b, uchar a = 255); +rgb_color HighColor() const; + +virtual void SetLowColor(rgb_color a_color); +void SetLowColor(uchar r, uchar g, uchar b, uchar a = 255); +rgb_color LowColor() const; + +void Invalidate(BRect invalRect); +void Invalidate(const BRegion *invalRegion); +void Invalidate(); + +virtual void SetFlags(uint32 flags); +uint32 Flags() const; +virtual void SetResizingMode(uint32 mode); +uint32 ResizingMode() const; +void MoveBy(float dh, float dv); +void MoveTo(BPoint where); +void MoveTo(float x, float y); +void ResizeBy(float dh, float dv); +void ResizeTo(float width, float height); +virtual void MakeFocus(bool focusState = true); +bool IsFocus() const; + +virtual void Show(); +virtual void Hide(); +bool IsHidden() const; +bool IsHidden(const OBView* looking_from) const; + +void Flush() const; +void Sync() const; + +void StrokeRect(BRect r, pattern p = B_SOLID_HIGH); +void FillRect(BRect r, pattern p = B_SOLID_HIGH); +void MovePenTo(BPoint pt); +void MovePenTo(float x, float y); +void MovePenBy(float x, float y); +BPoint PenLocation() const; +void StrokeLine( BPoint toPt,pattern p = B_SOLID_HIGH); +void StrokeLine( BPoint pt0,BPoint pt1,pattern p = B_SOLID_HIGH); + +protected: + friend OBWindow; + +int32 GetServerToken(void); +void CallAttached(OBView *view); +void CallDetached(OBView *view); +OBView *FindViewInChildren(const char *name); +void AddedToWindow(void); + +int32 id; +uint32 viewflags, resizeflags; +float origin_h; +float origin_v; +OBWindow* owner; + +OBView* parent; +OBView* uppersibling; +OBView* lowersibling; +OBView* topchild; +OBView* bottomchild; + +uint16 hidelevel; +bool topview; +bool has_focus; + +BRect vframe; +BRegion *clipregion; + +rgb_color highcol; +rgb_color lowcol; +rgb_color viewcol; +}; + +#endif diff --git a/src/servers/app/proto5/testobapp/OBWindow.cpp b/src/servers/app/proto5/testobapp/OBWindow.cpp new file mode 100644 index 0000000000..6d88d8e362 --- /dev/null +++ b/src/servers/app/proto5/testobapp/OBWindow.cpp @@ -0,0 +1,443 @@ +#include +#include +#include +#include "OBApplication.h" +#include "OBView.h" +#include "OBWindow.h" +#include "ServerProtocol.h" +#include "PortLink.h" + +#define DEBUG_OBWINDOW + +OBWindow::OBWindow(BRect frame,const char *title, window_type type, +uint32 flags,uint32 workspace = B_CURRENT_WORKSPACE) +{ +} + +OBWindow::OBWindow(BRect frame,const char *title, window_look look,window_feel feel, +uint32 flags,uint32 workspace = B_CURRENT_WORKSPACE) +{ +#ifdef DEBUG_OBWINDOW +printf("OBWindow(%s)\n",title); +#endif + Lock(); + + // Window starts hidden by default + hidelevel=1; + + wframe=frame; + wlook=look; + wfeel=feel; + wflags=flags; + wkspace=workspace; + + wtitle=new BString(title); + + // Receives messages from server and others + inport=create_port(50,"msgport"); + if(inport==B_BAD_VALUE || inport==B_NO_MORE_PORTS) + printf("OBWindow: Couldn't create message port\n"); + + // Notify app that we exist + OBWindow *win=this; + PortLink *link=new PortLink(obe_app->messageport); + link->SetOpCode(ADDWINDOW); + link->Attach(&win,sizeof(OBWindow*)); + link->Flush(); + delete link; + + // we set this flag because the window starts locked. When Show() is + // called it will unlock the looper and show the window + startlocked=true; + + // We create our serverlink utilizing our application's server port + // because the server's ServerApp will handle window creation + serverlink=new PortLink(obe_app->serverport); + + // make sure that the server port is valid. It will == B_NAME_NOT_FOUND if the + // OBApplication couldn't find the server + + if(obe_app->serverport!=B_NAME_NOT_FOUND) + { + // Notify server of window's existence + serverlink->SetOpCode(CREATE_WINDOW); + serverlink->Attach(wframe); + serverlink->Attach((int32)wflags); + serverlink->Attach(&inport,sizeof(port_id)); + serverlink->Attach((int32)wkspace); + serverlink->Attach((char*)wtitle->String(),wtitle->Length()); + + // Send and wait for ServerWindow port. Necessary here so we can respond to + // messages as soon as Show() is called. + + int32 replycode; + status_t replystat; + ssize_t replysize; + int8 *replybuffer; + + replybuffer=serverlink->FlushWithReply(&replycode,&replystat,&replysize); + outport=*((port_id*)replybuffer); + serverlink->SetPort(outport); + delete replybuffer; + +#ifdef DEBUG_OBWINDOW +printf("OBWindow(%s): ServerWindow Port %ld\n",wtitle->String(),outport); +#endif + + // Create and attach the top view + top_view=new OBView(wframe.OffsetToCopy(0,0),"top_view",B_FOLLOW_ALL, B_WILL_DRAW); + top_view->owner=this; + top_view->topview=true; + } + else + PostMessage(B_QUIT_REQUESTED); +} + +OBWindow::~OBWindow() +{ +#ifdef DEBUG_OBWINDOW +printf("~OBWindow(%s)\n",wtitle->String()); +#endif + // delete all children. How? OBView recursively deletes its children + delete top_view; + + delete wtitle; + delete serverlink; + delete drawmsglink; + +} + +void OBWindow::Quit() +{ +#ifdef DEBUG_OBWINDOW +printf("%s::Quit()\n",wtitle->String()); +#endif + // I hope this works. If it doesn't, we'll need to do a synchronous msg + OBWindow *win=this; + PortLink *link=new PortLink(obe_app->messageport); + link->SetOpCode(REMOVEWINDOW); + link->Attach(&win,sizeof(OBWindow *)); + link->Flush(); + delete link; + + // Server will need to be notified of window destruction + serverlink->SetOpCode(DELETE_WINDOW); + serverlink->Attach(&ID,sizeof(int32)); + serverlink->Flush(); + + // Quit our looper and delete our self :) + Quit(); +} + +void OBWindow::Close() +{ + Quit(); +} + +void OBWindow::AddChild(OBView *child, OBView *before = NULL) +{ +#ifdef DEBUG_OBWINDOW +printf("%s::AddChild()\n",wtitle->String()); +#endif + top_view->AddChild(child,before); +} + +bool OBWindow::RemoveChild(OBView *child) +{ +#ifdef DEBUG_OBWINDOW +printf("%s::RemoveChild()\n",wtitle->String()); +#endif + return top_view->RemoveChild(child); +} + +int32 OBWindow::CountChildren() const +{ + return top_view->CountChildren(); +} + +OBView *OBWindow::ChildAt(int32 index) const +{ + return top_view->ChildAt(index); +} + +void OBWindow::DispatchMessage(BMessage *message, BHandler *handler) +{ +} + +void OBWindow::MessageReceived(BMessage *message) +{ + // Not sure right now what needs to be handled. + switch(message->what) + { + default: + BLooper::MessageReceived(message); + } +} + +void OBWindow::FrameMoved(BPoint new_position) +{ +} + +void OBWindow::WorkspacesChanged(uint32 old_ws, uint32 new_ws) +{ +} + +void OBWindow::WorkspaceActivated(int32 ws, bool state) +{ +} + +void OBWindow::FrameResized(float new_width, float new_height) +{ +} + +void OBWindow::Minimize(bool minimize) +{ +} + +void OBWindow::Zoom(BPoint rec_position,float rec_width,float rec_height) +{ +} + +void OBWindow::Zoom() +{ +} + +void OBWindow::ScreenChanged(BRect screen_size, color_space depth) +{ +} + +bool OBWindow::NeedsUpdate() const +{ + return false; +} + +void OBWindow::UpdateIfNeeded() +{ +} + +OBView *OBWindow::FindView(const char *view_name) const +{ + return top_view->FindView(view_name); +} + +OBView *OBWindow::FindView(BPoint) const +{ + return NULL; +} + +OBView *OBWindow::CurrentFocus() const +{ + return focusedview; +} + +void OBWindow::Activate(bool=true) +{ +} + +void OBWindow::WindowActivated(bool state) +{ +} + +void OBWindow::ConvertToScreen(BPoint *pt) const +{ +} + +BPoint OBWindow::ConvertToScreen(BPoint pt) const +{ + return BPoint(-1,-1); +} + +void OBWindow::ConvertFromScreen(BPoint *pt) const +{ +} + +BPoint OBWindow::ConvertFromScreen(BPoint pt) const +{ + return BPoint(-1,-1); +} + +void OBWindow::ConvertToScreen(BRect *rect) const +{ +} + +BRect OBWindow::ConvertToScreen(BRect rect) const +{ + return BRect(0,0,0,0); +} + +void OBWindow::ConvertFromScreen(BRect *rect) const +{ +} + +BRect OBWindow::ConvertFromScreen(BRect rect) const +{ + return BRect(0,0,0,0); +} + +void OBWindow::MoveBy(float dx, float dy) +{ +} + +void OBWindow::MoveTo(BPoint) +{ +} + +void OBWindow::MoveTo(float x, float y) +{ +} + +void OBWindow::ResizeBy(float dx, float dy) +{ +} + +void OBWindow::ResizeTo(float width, float height) +{ +} + +void OBWindow::Show() +{ + if(startlocked) + { + startlocked=false; + Unlock(); + } + hidelevel--; + if(hidelevel==0) + { + serverlink->SetOpCode(SHOW_WINDOW); + serverlink->Flush(); + } +} + +void OBWindow::Hide() +{ + if(hidelevel==0) + { + serverlink->SetOpCode(HIDE_WINDOW); + serverlink->Flush(); + } + hidelevel++; +} + +bool OBWindow::IsHidden() const +{ + return false; +} + +bool OBWindow::IsMinimized() const +{ + return false; +} + +void OBWindow::Flush() const +{ + // When attachment count inclusion is implemented, it needs to go + // in this function + + drawmsglink->SetOpCode(GFX_FLUSH); + drawmsglink->Flush(); +} + +void OBWindow::Sync() const +{ + // When attachment count inclusion is implemented, it needs to go + // in this function + + int32 code; + status_t status; + ssize_t buffersize; + + drawmsglink->SetOpCode(GFX_SYNC); + + // Reply received: + + // Code: SYNC + // Attached data: none + // Buffersize: 0 + drawmsglink->FlushWithReply(&code,&status,&buffersize); +} + +status_t OBWindow::SendBehind(const OBWindow *window) +{ + return B_ERROR; +} + +void OBWindow::DisableUpdates() +{ +} + +void OBWindow::EnableUpdates() +{ +} + +void OBWindow::BeginViewTransaction() +{ +} + +void OBWindow::EndViewTransaction() +{ +} + +BRect OBWindow::Bounds() const +{ + return BRect(0,0,0,0); +} + +BRect OBWindow::Frame() const +{ + return BRect(0,0,0,0); +} + +const char *OBWindow::Title() const +{ + return NULL; +} + +void OBWindow::SetTitle(const char *title) +{ +} + +bool OBWindow::IsFront() const +{ + return false; +} + +bool OBWindow::IsActive() const +{ + return false; +} + +uint32 OBWindow::Workspaces() const +{ + return 0; +} + +void OBWindow::SetWorkspaces(uint32) +{ +} + +OBView *OBWindow::LastMouseMovedView() const +{ + return NULL; +} + +status_t OBWindow::AddToSubset(OBWindow *window) +{ + return B_ERROR; +} + +status_t OBWindow::RemoveFromSubset(OBWindow *window) +{ + return B_ERROR; +} + +bool OBWindow::QuitRequested() +{ + return false; +} + +thread_id OBWindow::Run() +{ + return 0; +} + diff --git a/src/servers/app/proto5/testobapp/OBWindow.h b/src/servers/app/proto5/testobapp/OBWindow.h new file mode 100644 index 0000000000..c3593cf874 --- /dev/null +++ b/src/servers/app/proto5/testobapp/OBWindow.h @@ -0,0 +1,140 @@ +#ifndef _OBWINDOW_H +#define _OBWINDOW_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class BButton; +class BMenuBar; +class BMenuItem; +class BMessage; +class BMessageRunner; +class BMessenger; +class OBView; +class PortLink; + +struct message; +struct _cmd_key_; +struct _view_attr_; + +#define ADDWINDOW '_adw' +#define REMOVEWINDOW '_rmw' + +class OBWindow : public BLooper +{ +public: +OBWindow(BRect frame,const char *title, window_type type, +uint32 flags,uint32 workspace = B_CURRENT_WORKSPACE); + +OBWindow(BRect frame,const char *title, window_look look,window_feel feel, +uint32 flags,uint32 workspace = B_CURRENT_WORKSPACE); + +virtual ~OBWindow(); + +virtual void Quit(); +void Close(); + +void AddChild(OBView *child, OBView *before = NULL); +bool RemoveChild(OBView *child); +int32 CountChildren() const; +OBView *ChildAt(int32 index) const; + +virtual void DispatchMessage(BMessage *message, BHandler *handler); +virtual void MessageReceived(BMessage *message); +virtual void FrameMoved(BPoint new_position); +virtual void WorkspacesChanged(uint32 old_ws, uint32 new_ws); +virtual void WorkspaceActivated(int32 ws, bool state); +virtual void FrameResized(float new_width, float new_height); +virtual void Minimize(bool minimize); +virtual void Zoom( BPoint rec_position, + float rec_width, + float rec_height); +void Zoom(); +virtual void ScreenChanged(BRect screen_size, color_space depth); +bool NeedsUpdate() const; +void UpdateIfNeeded(); +OBView *FindView(const char *view_name) const; +OBView *FindView(BPoint) const; +OBView *CurrentFocus() const; +void Activate(bool = true); +virtual void WindowActivated(bool state); +void ConvertToScreen(BPoint *pt) const; +BPoint ConvertToScreen(BPoint pt) const; +void ConvertFromScreen(BPoint *pt) const; +BPoint ConvertFromScreen(BPoint pt) const; +void ConvertToScreen(BRect *rect) const; +BRect ConvertToScreen(BRect rect) const; +void ConvertFromScreen(BRect *rect) const; +BRect ConvertFromScreen(BRect rect) const; +void MoveBy(float dx, float dy); +void MoveTo(BPoint); +void MoveTo(float x, float y); +void ResizeBy(float dx, float dy); +void ResizeTo(float width, float height); +virtual void Show(); +virtual void Hide(); +bool IsHidden() const; +bool IsMinimized() const; + +void Flush() const; +void Sync() const; + +status_t SendBehind(const OBWindow *window); + +void DisableUpdates(); +void EnableUpdates(); + +void BeginViewTransaction(); +void EndViewTransaction(); + +BRect Bounds() const; +BRect Frame() const; +const char *Title() const; +void SetTitle(const char *title); +bool IsFront() const; +bool IsActive() const; +uint32 Workspaces() const; +void SetWorkspaces(uint32); +OBView *LastMouseMovedView() const; + + +status_t AddToSubset(OBWindow *window); +status_t RemoveFromSubset(OBWindow *window); + +virtual bool QuitRequested(); +virtual thread_id Run(); + +protected: +friend OBView; + +BString *wtitle; +int32 ID; +int32 topview_ID; +uint8 hidelevel; +uint32 wflags; + +PortLink *drawmsglink, *serverlink; +port_id inport; +port_id outport; + +OBView *top_view; +OBView *focusedview; +OBView *fLastMouseMovedView; +BRect wframe; + +window_look wlook; +window_feel wfeel; + +bool startlocked; +bool in_update; +bool is_active; +int32 wkspace; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto5/testobapp/PortLink.cpp b/src/servers/app/proto5/testobapp/PortLink.cpp new file mode 100644 index 0000000000..8fba724569 --- /dev/null +++ b/src/servers/app/proto5/testobapp/PortLink.cpp @@ -0,0 +1,438 @@ +/* + PortLink.cpp: + A helper class for port-based messaging + +------------------------------------------------------------------------ +How it works: + The class utilizes a fixed-size array of PortLinkData object pointers. When +data is attached, a new PortLinkData object is allocated and a copy of the +passed data is created inside it. When the time comes for the message to be sent, +the data is pieced together into a flattened array and written to the port. +------------------------------------------------------------------------ +Data members: + +*attachments[] - fixed-size array of pointers used to hold the attached data +opcode - message value which is sent along with any data +target - port to which the message is sent when Flush() is called +replyport - port used with synchronous messaging - FlushWithReply() +bufferlength - total bytes taken up by attachments +num_attachments - internal variable which is used to track which "slot" + will be the next one to receive an attachment object +*/ + +#include "PortLink.h" +#include +#include +#include + +//#define PLDEBUG + +// Internal data storage class for holding attached data whilst it is waiting +// to be Flattened() and then Flushed(). There is no need for this to be called outside +// the PortLink class. +class PortLinkData +{ +public: + PortLinkData(void); + ~PortLinkData(void); + bool Set(void *data, size_t size); + char *buffer; + size_t buffersize; +}; + +PortLink::PortLink(port_id port) +{ + // For this class to be useful (and to prevent a lot of init problems) + // we require a port in the constructor + target=port; + + // We start out without any data attached to the port message + num_attachments=0; + opcode=0; + bufferlength=0; + replyport=create_port(30,"PortLink reply port"); +} + +PortLink::~PortLink(void) +{ + // If, for some odd reason, this is deleted with something attached, + // free the memory used by the attachments. We do not flush the queue + // because the port may no longer be valid in cases such as the app + // is in the process of quitting + MakeEmpty(); +} + +void PortLink::SetOpCode(int32 code) +{ + // Sets the message code. This does not change once the message is sent. + // Another call to SetOpCode() is required for such things. + opcode=code; +} + +void PortLink::SetPort(port_id port) +{ + // Sets the target port. While not necessary in most uses, this exists + // mostly to prevent flexibility problems + target=port; +} + +port_id PortLink::GetPort(void) +{ + // Simply returns the port at which the object is pointed. + return target; +} + +void PortLink::Flush(bigtime_t timeout=B_INFINITE_TIMEOUT) +{ + // Fires a message off to the target, complete with attachments. NOTE: + // the recipient must delete all attachments, being the PortLink object assumes + // no responsiblity for the attachments once the message is sent. + int8 *msgbuffer; + int32 size; + + if(num_attachments>0) + { + FlattenData(&msgbuffer,&size); + + // Dump message to port, reset attachments, and clean up + if(timeout!=B_INFINITE_TIMEOUT) + write_port_etc(target,opcode,msgbuffer,size,B_TIMEOUT, timeout); + else + write_port(target,opcode,msgbuffer,size); + MakeEmpty(); + } + else + { + if(timeout!=B_INFINITE_TIMEOUT) + write_port_etc(target,opcode,NULL,0,B_TIMEOUT, timeout); + else + write_port(target,opcode,NULL,0); + } +} + +int8* PortLink::FlushWithReply(int32 *code, status_t *status, ssize_t *buffersize, bigtime_t timeout=B_INFINITE_TIMEOUT) +{ + // Fires a message to the target and then waits for a reply. The target will + // receive a message with the first item being the port_id to reply to. + // NOTE: like Flush(), any attached data must be deleted. + + // Effectively, an Attach() call inlined for changes + + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + { + *status=B_ERROR; + return NULL; + } + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&replyport,sizeof(port_id))) + { + bufferlength+=sizeof(port_id); + } + else + { + delete pld; + *status=B_ERROR; + return NULL; + } + + // Flatten() inlined to make some necessary changes + int8 *buffer=new int8[bufferlength]; + int8 *bufferindex=buffer; + size_t size=0; + + // attach our port_id first + memcpy(bufferindex, pld->buffer, pld->buffersize); + bufferindex += pld->buffersize; + size+=pld->buffersize; + + // attach everything else + for(int i=0;ibuffer, pld->buffersize); + bufferindex += pld->buffersize; + size+=pld->buffersize; + } + + // Flush the thing....FOOSH! :P + write_port(target,opcode,buffer,size); + MakeEmpty(); + delete buffer; + + // Now we wait for the reply + if(timeout==B_INFINITE_TIMEOUT) + { + *buffersize=port_buffer_size(replyport); + if(*buffersize>0) + buffer=(int8*)new int8[*buffersize]; + read_port(replyport,code, buffer, *buffersize); + } + else + { + *buffersize=port_buffer_size_etc(replyport,0,timeout); + if(*buffersize==B_TIMED_OUT) + { + *status=*buffersize; + return NULL; + } + if(*buffersize>0) + buffer=(int8*)new int8[*buffersize]; + read_port(replyport,code, buffer, *buffersize); + } + + // We got this far, so we apparently have some data + *status=B_OK; + return buffer; +} + +void PortLink::Attach(void *data, size_t size) +{ + // This is the member called to attach data to a message. Attachments are + // treated to be in 'Append' mode, tacking on each attached piece of data + // to the end of the list. + + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + if(size==0) + return; + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +// These functions were added for a major convenience in passing common types +// Eventually, I'd like to templatize these, but for now, this'll do + +void PortLink::Attach(int32 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int32); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(int16 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int16); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(int8 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int8); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(float data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(float); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(bool data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(bool); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(BRect data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(BRect); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(BPoint data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(BPoint); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::FlattenData(int8 **buffer,int32 *size) +{ + // This function is where all the magic happens, but it is strictly internal. + // It iterates through each PortLinkData object and copies it to the main buffer + // which ends up, ultimately, being written to the PortLink's target port. + + // skip if there aree no attachments + if(bufferlength<1) + return; + + *buffer=new int8[bufferlength]; + int8 *bufferindex=*buffer; + PortLinkData *pld; + *size=0; + + for(int i=0;ibuffer, pld->buffersize); + bufferindex += pld->buffersize; + *size+=pld->buffersize; + } +} + +void PortLink::MakeEmpty(void) +{ + // Nukes all the attachments currently held by the PortLink class + if(num_attachments!=0) + { + for(int i=0; i0) + free(buffer); +} + +bool PortLinkData::Set(void *data, size_t size) +{ + // Function copies the passed to the internal buffers for storage + if(size>0 && buffersize==0 && data!=NULL) + { + buffer=(char *)malloc(size); + if(buffer==NULL) + return false; + memcpy(buffer, data, size); + buffersize=size; + return true; + } + return false; +} diff --git a/src/servers/app/proto5/testobapp/PortLink.h b/src/servers/app/proto5/testobapp/PortLink.h new file mode 100644 index 0000000000..9f5432daab --- /dev/null +++ b/src/servers/app/proto5/testobapp/PortLink.h @@ -0,0 +1,43 @@ +#ifndef _PORTLINK_H_ +#define _PORTLINK_H_ + +#include +#include +#include +#include + +#ifndef _PORTLINK_BUFFERSIZE +#define _PORTLINK_MAX_ATTACHMENTS 50 +#endif + +class PortLinkData; + +class PortLink +{ +public: + PortLink(port_id port); + ~PortLink(void); + void SetOpCode(int32 code); + void SetPort(port_id port); + port_id GetPort(void); + void Flush(bigtime_t timeout=B_INFINITE_TIMEOUT); + int8* FlushWithReply(int32 *code, status_t *status, ssize_t *buffersize, + bigtime_t timeout=B_INFINITE_TIMEOUT); + void Attach(void *data, size_t size); + void Attach(int32 data); + void Attach(int16 data); + void Attach(int8 data); + void Attach(float data); + void Attach(bool data); + void Attach(BRect data); + void Attach(BPoint data); + void MakeEmpty(void); +protected: + void FlattenData(int8 **buffer,int32 *size); + port_id target, replyport; + int32 opcode, bufferlength; + int num_attachments; + PortLinkData *attachments[_PORTLINK_MAX_ATTACHMENTS]; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto5/testobapp/ServerProtocol.h b/src/servers/app/proto5/testobapp/ServerProtocol.h new file mode 100644 index 0000000000..1c8c3f3fdf --- /dev/null +++ b/src/servers/app/proto5/testobapp/ServerProtocol.h @@ -0,0 +1,94 @@ +#ifndef _APPSERVER_PROTOCOL_ +#define _APPSERVER_PROTOCOL_ + +#define CREATE_APP 'drca' +#define DELETE_APP 'drda' +#define QUIT_APP 'srqa' + +#define SET_SERVER_PORT 'srsp' + +#define CREATE_WINDOW 'drcw' +#define DELETE_WINDOW 'drdw' +#define SHOW_WINDOW 'drsw' +#define HIDE_WINDOW 'drhw' +#define QUIT_WINDOW 'srqw' + +#define SERVER_PORT_NAME "OBappserver" +#define SERVER_INPUT_PORT "OBinputport" + +#define SET_CURSOR_DATA 'sscd' +#define SET_CURSOR_BCURSOR 'sscb' +#define SET_CURSOR_BBITMAP 'sscB' +#define SHOW_CURSOR 'srsc' +#define HIDE_CURSOR 'srhc' +#define OBSCURE_CURSOR 'sroc' + +#define GFX_COUNT_WORKSPACES 'gcws' +#define GFX_SET_WORKSPACE_COUNT 'ggwc' +#define GFX_CURRENT_WORKSPACE 'ggcw' +#define GFX_ACTIVATE_WORKSPACE 'gaws' +#define GFX_SYSTEM_COLORS 'gsyc' +#define GFX_SET_SCREEN_MODE 'gssm' +#define GFX_GET_SCROLLBAR_INFO 'ggsi' +#define GFX_SET_SCROLLBAR_INFO 'gssi' +#define GFX_IDLE_TIME 'gidt' +#define GFX_SELECT_PRINTER_PANEL 'gspp' +#define GFX_ADD_PRINTER_PANEL 'gapp' +#define GFX_RUN_BE_ABOUT 'grba' +#define GFX_SET_FOCUS_FOLLOWS_MOUSE 'gsfm' +#define GFX_FOCUS_FOLLOWS_MOUSE 'gffm' + +#define GFX_SET_HIGH_COLOR 'gshc' +#define GFX_SET_LOW_COLOR 'gslc' +#define GFX_SET_VIEW_COLOR 'gsvc' + +#define GFX_STROKE_ARC 'gsar' +#define GFX_STROKE_BEZIER 'gsbz' +#define GFX_STROKE_ELLIPSE 'gsel' +#define GFX_STROKE_LINE 'gsln' +#define GFX_STROKE_POLYGON 'gspy' +#define GFX_STROKE_RECT 'gsrc' +#define GFX_STROKE_ROUNDRECT 'gsrr' +#define GFX_STROKE_SHAPE 'gssh' +#define GFX_STROKE_TRIANGLE 'gstr' + +#define GFX_FILL_ARC 'gfar' +#define GFX_FILL_BEZIER 'gfbz' +#define GFX_FILL_ELLIPSE 'gfel' +#define GFX_FILL_POLYGON 'gfpy' +#define GFX_FILL_RECT 'gfrc' +#define GFX_FILL_REGION 'gfrg' +#define GFX_FILL_ROUNDRECT 'gfrr' +#define GFX_FILL_SHAPE 'gfsh' +#define GFX_FILL_TRIANGLE 'gftr' + +#define GFX_MOVEPENBY 'gmpb' +#define GFX_MOVEPENTO 'gmpt' +#define GFX_SETPENSIZE 'gsps' + +#define GFX_DRAW_STRING 'gdst' +#define GFX_SET_FONT 'gsft' +#define GFX_SET_FONT_SIZE 'gsfs' + +#define GFX_FLUSH 'gfsh' +#define GFX_SYNC 'gsyn' + +#define LAYER_CREATE 'lycr' +#define LAYER_DELETE 'lydl' +#define LAYER_ADD_CHILD 'lyac' +#define LAYER_REMOVE_CHILD 'lyrc' +#define LAYER_REMOVE_SELF 'lyrs' +#define LAYER_SHOW 'lysh' +#define LAYER_HIDE 'lyhd' +#define LAYER_MOVE 'lymv' +#define LAYER_RESIZE 'lyre' +#define LAYER_INVALIDATE 'lyin' +#define LAYER_DRAW 'lydr' + +#define BEGIN_RECT_TRACKING 'rtbg' +#define END_RECT_TRACKING 'rten' + +#define VIEW_GET_TOKEN 'vgtk' +#define VIEW_ADD 'vadd' +#define VIEW_REMOVE 'vrem' +#endif \ No newline at end of file diff --git a/src/servers/app/proto5/testobapp/TODO b/src/servers/app/proto5/testobapp/TODO new file mode 100644 index 0000000000..e7bb1f2efa --- /dev/null +++ b/src/servers/app/proto5/testobapp/TODO @@ -0,0 +1,3 @@ +Write server-side Add/Remove View code +Figure out a good screen update protocol +Flesh out OBWindow::MessageReceived() diff --git a/src/servers/app/proto6/AppServer.cpp b/src/servers/app/proto6/AppServer.cpp new file mode 100644 index 0000000000..233bdef0d7 --- /dev/null +++ b/src/servers/app/proto6/AppServer.cpp @@ -0,0 +1,584 @@ +/* + AppServer.cpp + File for the main app_server thread. This particular thread monitors for + application start and quit messages. It also starts the housekeeping threads + and initializes most of the server's globals. +*/ +#include +#include +#include "scheduler.h" +#include +#include +#include +#include +#include "AppServer.h" +#include "Layer.h" +#include "ServerApp.h" +#include "ServerWindow.h" +#include "Desktop.h" +#include "ServerProtocol.h" +#include "PortLink.h" +#include "DisplayDriver.h" +#include "DebugTools.h" +#include "BeDecorator.h" +#include "WinDecorator.h" +#include "YMakDecorator.h" + +//#define DEBUG_APPSERVER_THREAD + +// This bad boy holds only the top layer for each workspace +//BList *layerlist; + +// Used for mediating access to the layer lists +//BLocker *layerlock; + +// Used for access via instantiate_decorator +AppServer *app_server; + +AppServer::AppServer(void) : BApplication("application/x-vnd.obe-OBAppServer") +{ +#ifdef DEBUG_APPSERVER_THREAD + printf("AppServer()\n"); +#endif + + mouseport=create_port(30,SERVER_INPUT_PORT); + messageport=create_port(20,SERVER_PORT_NAME); +#ifdef DEBUG_APPSERVER_THREAD +printf("Server message port: %ld\n",messageport); +printf("Server input port: %ld\n",mouseport); +#endif + applist=new BList(0); + quitting_server=false; + exit_poller=false; + + // Set up the Desktop + init_desktop(3); + + // This is necessary to mediate access between the Poller and app_server threads + active_lock=new BLocker; + + // This locker is for app_server and Picasso to vy for control of the ServerApp list + applist_lock=new BLocker; + + // This locker is to mediate access to the make_decorator pointer + decor_lock=new BLocker; + + // Get the driver first - Poller thread utilizes the thing + driver=get_gfxdriver(); + + // Spawn our input-polling thread + poller_id = spawn_thread(PollerThread, "Poller", B_NORMAL_PRIORITY, this); + if (poller_id >= 0) + resume_thread(poller_id); + + // Spawn our thread-monitoring thread + picasso_id = spawn_thread(PicassoThread,"Picasso", B_NORMAL_PRIORITY, this); + if (picasso_id >= 0) + resume_thread(picasso_id); + + active_app=-1; + p_active_app=NULL; + + make_decorator=NULL; +// layerlock=new BLocker; +// layerlist=new BList(1); +} + +AppServer::~AppServer(void) +{ + shutdown_desktop(); + + ServerApp *tempapp; +// Layer *templayer; + int32 i; + applist_lock->Lock(); + for(i=0;iCountItems();i++) + { + tempapp=(ServerApp *)applist->ItemAt(i); + if(tempapp!=NULL) + delete tempapp; + } + delete applist; + applist_lock->Unlock(); + +/* layerlock->Lock(); + for(i=0;iCountItems();i++) + { + templayer=(Layer *)layerlist->ItemAt(i); + + if(templayer!=NULL) + { + templayer->PruneTree(); + delete templayer; + } + } + delete layerlist; + layerlock->Unlock(); + + delete layerlock; +*/ delete active_lock; + delete applist_lock; + + // If these threads are still running, kill them - after this, if exit_poller + // is deleted, who knows what will happen... These things will just return an + // error and fail if the threads have already exited. + kill_thread(poller_id); + kill_thread(picasso_id); + + delete decor_lock; + + make_decorator=NULL; +} + +thread_id AppServer::Run(void) +{ +#ifdef DEBUG_APPSERVER_THREAD +printf("AppServer::Run()\n"); +#endif + + MainLoop(); + return 0; +} + +void AppServer::MainLoop(void) +{ + // Main loop (duh). Monitors the message queue and dispatches as appropriate. + // Input messages are handled by the poller, however. + +#ifdef DEBUG_APPSERVER_THREAD +printf("AppServer::MainLoop()\n"); +#endif + + int32 msgcode; + int8 *msgbuffer=NULL; + ssize_t buffersize,bytesread; + + for(;;) + { + buffersize=port_buffer_size(messageport); + if(buffersize>0) + msgbuffer=new int8[buffersize]; + bytesread=read_port(messageport,&msgcode,msgbuffer,buffersize); + + if (bytesread != B_BAD_PORT_ID && bytesread != B_TIMED_OUT && bytesread != B_WOULD_BLOCK) + { + switch(msgcode) + { + case CREATE_APP: + case DELETE_APP: + case GET_SCREEN_MODE: + case B_QUIT_REQUESTED: + DispatchMessage(msgcode,msgbuffer); + break; + default: + { +#ifdef DEBUG_APPSERVER_THREAD +printf("Server received unexpected code %ld\n",msgcode); +#endif + break; + } + } + + } + + if(buffersize>0) + delete msgbuffer; + if(msgcode==DELETE_APP || msgcode==B_QUIT_REQUESTED) + { + if(quitting_server==true && applist->CountItems()==0) + break; + } + } + // Make sure our polling thread has exited + if(find_thread("Poller")!=B_NAME_NOT_FOUND) + kill_thread(poller_id); + +} + + +void AppServer::DispatchMessage(int32 code, int8 *buffer) +{ + int8 *index=buffer; + switch(code) + { + case CREATE_APP: + { + // Create the ServerApp to node monitor a new BApplication + +#ifdef DEBUG_APPSERVER_THREAD +printf("AppServer: Create App\n"); +#endif + + // Attached data: + // 1) port_id - port to reply to + // 2) port_id - receiver port of a regular app + // 3) char * - signature of the regular app + + // Find the necessary data + port_id reply_port=*((port_id*)index); index+=sizeof(port_id); + port_id app_port=*((port_id*)index); index+=sizeof(port_id); + + char *app_signature=(char *)index; + + // Create the ServerApp subthread for this app + applist_lock->Lock(); + ServerApp *newapp=new ServerApp(app_port,app_signature); + applist->AddItem(newapp); + applist_lock->Unlock(); + + active_lock->Lock(); + p_active_app=newapp; + active_app=applist->CountItems()-1; + + PortLink *replylink=new PortLink(reply_port); + replylink->SetOpCode(SET_SERVER_PORT); + replylink->Attach((int32)newapp->receiver); + replylink->Flush(); + + delete replylink; + + active_lock->Unlock(); + + newapp->Run(); + + break; + } + case DELETE_APP: + { + // Delete a ServerApp. Received only from the respective ServerApp when a + // BApplication asks it to quit. + +#ifdef DEBUG_APPSERVER_THREAD +printf("AppServer: Delete App\n"); +#endif + + // Attached Data: + // 1) thread_id - thread ID of the ServerApp to be deleted + + int32 i, appnum=applist->CountItems(); + ServerApp *srvapp; + thread_id srvapp_id=*((thread_id*)buffer); + + // Run through the list of apps and nuke the proper one + for(i=0;iItemAt(i); + + if(srvapp!=NULL && srvapp->monitor_thread==srvapp_id) + { + applist_lock->Lock(); + srvapp=(ServerApp *)applist->RemoveItem(i); + if(srvapp) + { + delete srvapp; + srvapp=NULL; + } + applist_lock->Unlock(); + active_lock->Lock(); + + if(applist->CountItems()==0) + { + // active==-1 signifies that no other apps are running - NOT good + active_app=-1; + } + else + { + // we actually still have apps running, so make a new one active + if(active_app>0) + active_app--; + else + active_app=0; + } + p_active_app=(active_app>-1)?(ServerApp*)applist->ItemAt(active_app):NULL; + active_lock->Unlock(); + break; // jump out of our for() loop + } + + } + break; + } + case GET_SCREEN_MODE: + { + // Synchronous message call to get the stats on the current screen mode + // in the app_server. Simply a hack in place for the Input Server until + // BScreens are done. + +#ifdef DEBUG_APPSERVER_THREAD +printf("AppServer: Get Screen Mode\n"); +#endif + // Attached Data: + // 1) port_id - port to reply to + + // Returned Data: + // 1) int32 width + // 2) int32 height + // 3) int depth + + PortLink *replylink=new PortLink(*((port_id*)index)); + replylink->SetOpCode(GET_SCREEN_MODE); + replylink->Attach(driver->GetWidth()); + replylink->Attach(driver->GetHeight()); + replylink->Attach((int16)driver->GetDepth()); + replylink->Flush(); + delete replylink; + break; + } + case B_QUIT_REQUESTED: + { +#ifdef DEBUG_APPSERVER_THREAD +printf("Shutdown sequence initiated.\n"); +#endif + + // Attached Data: + // none + + // We've been asked to quit, so (for now) broadcast to all + // test apps to quit. This situation will occur only when the server + // is compiled as a regular Be application. + PortLink *applink=new PortLink(0); + ServerApp *srvapp; + + applist_lock->Lock(); + int32 i,appnum=applist->CountItems(); + + applink->SetOpCode(QUIT_APP); + for(i=0;iItemAt(i); + if(srvapp!=NULL) + { + applink->SetPort(srvapp->receiver); + applink->Flush(); + } + } + applist_lock->Unlock(); + + delete applink; + // So when we delete the last ServerApp, we can exit the server + quitting_server=true; + exit_poller=true; + break; + } + default: + //printf("Unexpected message %ld (%lx) in AppServer::DispatchMessage()\n",code,code); + break; + } +} + +bool AppServer::LoadDecorator(BString path) +{ + // Loads a window decorator based on the supplied path and forces a decorator update. + // If it cannot load the specified decorator, it will retain the current one and + // return false. + + create_decorator *pcreatefunc=NULL; + get_decorator_version *pversionfunc=NULL; + status_t stat; + image_id addon; + + addon=load_add_on(path.String()); + + stat=get_image_symbol(addon, "get_decorator_version", B_SYMBOL_TYPE_TEXT, (void**)&pversionfunc); + if(stat!=B_OK) + { + printf("ERROR: Could not get version for Decorator %s\n", path.String()); + unload_add_on(addon); + return false; + } + + // As of now, we do nothing with decorator versions, but the possibility exists + // that the API will change even though I cannot forsee any reason to do so. If + // we *did* do anything with decorator versions, the assignment to a global would + // go here. + + stat=get_image_symbol(addon, "get_decorator_version", B_SYMBOL_TYPE_TEXT, (void**)&pversionfunc); + if(stat!=B_OK) + { + printf("ERROR: Could not get version for Decorator %s\n", path.String()); + unload_add_on(addon); + return false; + } + decor_lock->Lock(); + make_decorator=pcreatefunc; + decorator_id=addon; + decor_lock->Unlock(); + return true; +} + +void AppServer::LoadDefaultDecorator(void) +{ + // This function is called on server startup to provide a fallback decorator in + // case the decorator specified in the config file cannot be loaded. It just + // wouldn't do to have windows with no borders. ;) It also unloads any loaded + // decorator addons. We can specify that we want the default. It is no less + // functional - just internal. + +} + +Decorator *instantiate_decorator(Layer *lay, uint32 dflags, uint32 wlook) +{ + Decorator *decor=NULL; + + app_server->decor_lock->Lock(); + if(app_server->make_decorator!=NULL) + decor=app_server->make_decorator(lay, dflags, wlook); + else + { + decor=new BeDecorator(lay, dflags, wlook); +// decor=new WinDecorator(lay, dflags, wlook); +// decor=new YMakDecorator(lay, dflags, wlook); + } + + app_server->decor_lock->Unlock(); + return decor; +} + +void AppServer::Poller(void) +{ + // This thread handles nothing but input messages for mouse and keyboard + int32 msgcode; + int8 *msgbuffer=NULL,*index; + ssize_t buffersize,bytesread; + + for(;;) + { + buffersize=port_buffer_size(mouseport); + if(buffersize>0) + msgbuffer=new int8[buffersize]; + bytesread=read_port(mouseport,&msgcode,msgbuffer,buffersize); + + if (bytesread != B_BAD_PORT_ID && bytesread != B_TIMED_OUT && bytesread != B_WOULD_BLOCK) + { + switch(msgcode) + { + // We don't need to do anything with these two, so just pass them + // onto the active application. Eventually, we will pass them onto + // the window which is currently under the cursor. + case B_MOUSE_DOWN: + case B_MOUSE_UP: + { +/* + active_lock->Lock(); + if(active_app>-1 && p_active_app!=NULL) + write_port(p_active_app->receiver, msgcode,msgbuffer,buffersize); + active_lock->Unlock(); +*/ + ServerWindow::HandleMouseEvent(msgcode,msgbuffer); + break; + } + + // Process the cursor and then pass it on + case B_MOUSE_MOVED: + { + // Attached data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - buttons down + + index=msgbuffer; + + // Time sent is not necessary for cursor processing. + index += sizeof(int64); + + float tempx=0,tempy=0; + tempx=*((float*)index); + index+=sizeof(float); + tempy=*((float*)index); + index+=sizeof(float); + + driver->MoveCursorTo(tempx,tempy); + +/* active_lock->Lock(); + if(active_app>-1 && p_active_app!=NULL) + write_port(p_active_app->receiver, msgcode,msgbuffer,buffersize); + active_lock->Unlock(); +*/ + ServerWindow::HandleMouseEvent(msgcode,msgbuffer); + break; + } + default: + //printf("Server::Poller received unexpected code %ld\n",msgcode); + break; + } + + } + + if(buffersize>0) + delete msgbuffer; + + if(exit_poller) + break; + } +} + +int32 AppServer::PollerThread(void *data) +{ +#ifdef DEBUG_APPSERVER_THREAD +printf("Starting Poller thread...\n"); +#endif + AppServer *server=(AppServer *)data; + + // This won't return until it's told to + server->Poller(); + +#ifdef DEBUG_APPSERVER_THREAD +printf("Exiting Poller thread...\n"); +#endif + exit_thread(B_OK); + return B_OK; +} + +void AppServer::Picasso(void) +{ + int32 i; + ServerApp *app; + for(;;) + { + applist_lock->Lock(); + for(i=0;iCountItems(); i++) + { + app=(ServerApp*)applist->ItemAt(i); + ASSERT(app!=NULL); + app->PingTarget(); + } + applist_lock->Unlock(); + + // if poller thread has to exit, so do we - I just was too lazy + // to rename the variable name. ;) + if(exit_poller) + break; + + // we do this every other second so as not to suck *too* many CPU cycles + snooze(2000000); + } +} + +int32 AppServer::PicassoThread(void *data) +{ +#ifdef DEBUG_APPSERVER_THREAD +printf("Starting Picasso thread...\n"); +#endif + AppServer *server=(AppServer *)data; + + // This won't return until it's told to + server->Picasso(); + +#ifdef DEBUG_APPSERVER_THREAD +printf("Exiting Picasso thread...\n"); +#endif + exit_thread(B_OK); + return B_OK; +} + +int main( int argc, char** argv ) +{ + // There can be only one.... + if(find_port(SERVER_PORT_NAME)!=B_NAME_NOT_FOUND) + return -1; + + app_server = new AppServer(); + app_server->Run(); + delete app_server; + return 0; +} diff --git a/src/servers/app/proto6/AppServer.h b/src/servers/app/proto6/AppServer.h new file mode 100644 index 0000000000..9c2fbc5a62 --- /dev/null +++ b/src/servers/app/proto6/AppServer.h @@ -0,0 +1,50 @@ +#ifndef _OPENBEOS_APP_SERVER_H_ +#define _OPENBEOS_APP_SERVER_H_ + +#include +#include +#include +#include +//#include // for window_look +#include "Decorator.h" + +class Layer; +class BMessage; +class ServerApp; +class DisplayDriver; + +class AppServer : public BApplication +{ +public: + AppServer(void); + ~AppServer(void); + thread_id Run(void); + void MainLoop(void); + port_id messageport,mouseport; + void Poller(void); + void Picasso(void); + +private: + friend Decorator *instantiate_decorator(Layer *lay, uint32 dflags, uint32 wlook); + + void DispatchMessage(int32 code, int8 *buffer); + static int32 PollerThread(void *data); + static int32 PicassoThread(void *data); + bool LoadDecorator(BString path); + void LoadDefaultDecorator(void); + + image_id decorator_id; + create_decorator *make_decorator; // global function pointer + bool quitting_server; + BList *applist; + int32 active_app; + ServerApp *p_active_app; + thread_id poller_id, picasso_id; + + BLocker *active_lock, *applist_lock, *decor_lock; + bool exit_poller; + DisplayDriver *driver; +}; + +Decorator *instantiate_decorator(Layer *lay, uint32 dflags, uint32 wlook); +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/BeDecorator.cpp b/src/servers/app/proto6/BeDecorator.cpp new file mode 100644 index 0000000000..b5935bb81b --- /dev/null +++ b/src/servers/app/proto6/BeDecorator.cpp @@ -0,0 +1,530 @@ +#include "Layer.h" +#include "DisplayDriver.h" +#include +#include "BeDecorator.h" +#include "ColorUtils.h" + +//#define DEBUG_DECOR + +#ifdef DEBUG_DECOR +#include +#endif + +BeDecorator::BeDecorator(Layer *lay, uint32 dflags, uint32 wlook) + : Decorator(lay, dflags, wlook) +{ +#ifdef DEBUG_DECOR +printf("BeDecorator()\n"); +#endif + zoomstate=false; + closestate=false; + taboffset=0; + + // These hard-coded assignments will go bye-bye when the system colors + // API is implemented + + // commented these out because they are taken care of by the SetFocus() call + SetFocus(false); +// SetRGBColor(&tab_highcol,255,236,33); +// SetRGBColor(&tab_lowcol,234,181,0); + +// SetRGBColor(&button_highcol,255,255,0); +// SetRGBColor(&button_lowcol,255,203,0); + + SetRGBColor(&frame_highercol,216,216,216); + SetRGBColor(&frame_lowercol,110,110,110); + + SetRGBColor(&textcol,0,0,0); + + frame_highcol=MakeBlendColor(frame_lowercol,frame_highercol,0.75); + frame_midcol=MakeBlendColor(frame_lowercol,frame_highercol,0.5); + frame_lowcol=MakeBlendColor(frame_lowercol,frame_highercol,0.25); + + Resize(lay->frame); + + // We need to modify the visible rectangle because we have tabbed windows + if(lay->visible) + { + delete lay->visible; + lay->visible=GetFootprint(); + } + + // This flag is used to determine whether or not we're moving the tab + slidetab=false; +} + +BeDecorator::~BeDecorator(void) +{ +#ifdef DEBUG_DECOR +printf("~BeDecorator()\n"); +#endif +} + +click_type BeDecorator::Clicked(BPoint pt, uint32 buttons) +{ + // Clicked is a hit-testing function which is called by each + // decorator object's respective WindowBorder. When a click or + // mouse message is received, we must return to the WindowBorder + // what the click meant to us and the appropriate action for it + // to take. + + // the case order is important - we go from smallest to largest + // for efficiency's sake. + if(closerect.Contains(pt)) + { + +#ifdef DEBUG_DECOR +printf("BeDecorator():Clicked() - Close\n"); +#endif + + return CLICK_CLOSE; + } + + if(zoomrect.Contains(pt)) + { + +#ifdef DEBUG_DECOR +printf("BeDecorator():Clicked() - Zoom\n"); +#endif + + return CLICK_ZOOM; + } + + if(resizerect.Contains(pt) && dlook==WLOOK_DOCUMENT) + { + +#ifdef DEBUG_DECOR +printf("BeDecorator():Clicked() - Resize thumb\n"); +#endif + + return CLICK_RESIZE; + } + + // Clicking in the tab? + if(tabrect.Contains(pt)) + { + // Here's part of our window management stuff + if(buttons==B_PRIMARY_MOUSE_BUTTON && !focused) + return CLICK_MOVETOFRONT; + if(buttons==B_SECONDARY_MOUSE_BUTTON) + return CLICK_MOVETOBACK; + return CLICK_DRAG; + } + + // We got this far, so user is clicking on the border? + BRect brect(frame); + brect.top+=19; + BRect clientrect(brect.InsetByCopy(3,3)); + if(brect.Contains(pt) && !clientrect.Contains(pt)) + { +#ifdef DEBUG_DECOR +printf("BeDecorator():Clicked() - Drag\n"); +#endif + if(resizerect.Contains(pt)) + return CLICK_RESIZE; + + return CLICK_DRAG; + } + + // Guess user didn't click anything +#ifdef DEBUG_DECOR +printf("BeDecorator():Clicked()\n"); +#endif + return CLICK_NONE; +} + +void BeDecorator::Resize(BRect rect) +{ + // Here we determine the size of every rectangle that we use + // internally when we are given the size of the client rectangle. + + // Current version simply makes everything fit inside the rect + // instead of building around it. This will change. + +#ifdef DEBUG_DECOR +printf("BeDecorator()::Resize()"); rect.PrintToStream(); +#endif + frame=rect; + tabrect=frame; + resizerect=frame; + borderrect=frame; + closerect=frame; + + closerect.left+=(dlook==WLOOK_FLOATING)?2:4; + closerect.top+=(dlook==WLOOK_FLOATING)?6:4; + closerect.right=closerect.left+10; + closerect.bottom=closerect.top+10; + + borderrect.top+=19; + + resizerect.top=resizerect.bottom-18; + resizerect.left=resizerect.right-18; + + tabrect.bottom=tabrect.top+18; + if(layer->name) + { + float titlewidth=closerect.right + +driver->StringWidth(layer->name->String(), + layer->name->Length()) + +35; + tabrect.right=(titlewidthInclude(tabrect); + return reg; +} + +void BeDecorator::SetFlags(uint32 wflags) +{ + dflags=wflags; +} + +void BeDecorator::UpdateFont(void) +{ + // This will be updated once font capability is implemented +} + +void BeDecorator::UpdateTitle(const char *string) +{ + // Designed simply to redraw the title when it has changed on + // the client side. + if(string) + { + driver->SetDrawingMode(B_OP_OVER); + rgb_color tmpcol=driver->HighColor(); + driver->SetHighColor(textcol.red,textcol.green,textcol.blue); + driver->DrawString((char *)string,strlen(string), + BPoint(closerect.right+textoffset,closerect.bottom-1)); + driver->SetHighColor(tmpcol.red,tmpcol.green,tmpcol.blue); + driver->SetDrawingMode(B_OP_COPY); + } + +} + +void BeDecorator::SetFocus(bool bfocused) +{ + // SetFocus() performs necessary duties for color swapping and + // other things when a window is deactivated or activated. + + focused=bfocused; + + if(focused) + { + SetRGBColor(&tab_highcol,255,236,33); + SetRGBColor(&tab_lowcol,234,181,0); + + SetRGBColor(&button_highcol,255,255,0); + SetRGBColor(&button_lowcol,255,203,0); + } + else + { + SetRGBColor(&tab_highcol,235,235,235); + SetRGBColor(&tab_lowcol,160,160,160); + + SetRGBColor(&button_highcol,229,229,229); + SetRGBColor(&button_lowcol,153,153,153); + } + +} + +void BeDecorator::Draw(BRect update) +{ + // We need to draw a few things: the tab, the resize thumb, the borders, + // and the buttons + + if(tabrect.Intersects(update)) + DrawTab(); + + // Draw the top view's client area - just a hack :) + rgb_color blue={100,100,255,255}; + + if(borderrect.Intersects(update)) + driver->FillRect(borderrect,blue); + + DrawFrame(); +} + +void BeDecorator::Draw(void) +{ + // Easy way to draw everything - no worries about drawing only certain + // things + + DrawTab(); + + // Draw the top view's client area - just a hack :) + rgb_color blue={100,100,255,255}; + driver->FillRect(borderrect,blue); + + DrawFrame(); +} + +void BeDecorator::DrawZoom(BRect r) +{ + // If this has been implemented, then the decorator has a Zoom button + // which should be drawn based on the state of the member zoomstate + BRect zr=r; + zr.left+=zr.Width()/3; + zr.top+=zr.Height()/3; + + DrawBlendedRect(zr,zoomstate); + DrawBlendedRect(zr.OffsetToCopy(r.LeftTop()),zoomstate); +} + +void BeDecorator::DrawClose(BRect r) +{ + // Just like DrawZoom, but for a close button + DrawBlendedRect(r,closestate); +} + +void BeDecorator::DrawTab(void) +{ + // If a window has a tab, this will draw it and any buttons which are + // in it. + if(dlook==WLOOK_NO_BORDER) + return; + + rgb_color tmpcol; + float rstep,gstep,bstep; + + int steps=tabrect.IntegerHeight(); + rstep=float(tab_highcol.red-tab_lowcol.red)/steps; + gstep=float(tab_highcol.green-tab_lowcol.green)/steps; + bstep=float(tab_highcol.blue-tab_lowcol.blue)/steps; + + driver->StrokeRect(tabrect,frame_lowcol); + driver->BeginLineArray(steps+1); + for(float i=1;i<=steps; i++) + { + SetRGBColor(&tmpcol, uint8(tab_highcol.red-(i*rstep)), + uint8(tab_highcol.green-(i*gstep)), + uint8(tab_highcol.blue-(i*bstep))); + driver->AddLine(BPoint(tabrect.left+1,tabrect.top+i), + BPoint(tabrect.right-1,tabrect.top+i),tmpcol); + } + driver->EndLineArray(); + UpdateTitle(layer->name->String()); + + // Draw the buttons if we're supposed to + if(!(dflags & NOT_CLOSABLE)) + DrawClose(closerect); + if(!(dflags & NOT_ZOOMABLE)) + DrawZoom(zoomrect); +} + +void BeDecorator::DrawBlendedRect(BRect r, bool down) +{ + // This bad boy is used to draw a rectangle with a gradient. + // Note that it is not part of the Decorator API - it's specific + // to just the BeDecorator. Called by DrawZoom and DrawClose + + // Actually just draws a blended square + int32 w=r.IntegerWidth(), h=r.IntegerHeight(); + + rgb_color tmpcol,halfcol, startcol, endcol; + float rstep,gstep,bstep,i; + + int steps=(wStrokeLine(BPoint(r.left,r.top+i), + BPoint(r.left+i,r.top),tmpcol); + + SetRGBColor(&tmpcol, uint8(halfcol.red-(i*rstep)), + uint8(halfcol.green-(i*gstep)), + uint8(halfcol.blue-(i*bstep))); + driver->StrokeLine(BPoint(r.left+steps,r.top+i), + BPoint(r.left+i,r.top+steps),tmpcol); + + } + driver->StrokeRect(r,frame_lowcol); +} + +void BeDecorator::DrawFrame(void) +{ + // Duh, draws the window frame, I think. ;) + + if(dlook==WLOOK_NO_BORDER) + return; + + BRect r=borderrect; + + driver->BeginLineArray(12); + driver->AddLine(BPoint(r.left,r.top),BPoint(r.right-1,r.top), + frame_midcol); + driver->AddLine(BPoint(r.left,r.top),BPoint(r.left,r.bottom), + frame_lowcol); + driver->AddLine(BPoint(r.right,r.bottom),BPoint(r.right,r.top), + frame_lowercol); + driver->AddLine(BPoint(r.right,r.bottom),BPoint(r.left,r.bottom), + frame_lowercol); + + r.InsetBy(1,1); + driver->AddLine(BPoint(r.left,r.top),BPoint(r.right-1,r.top), + frame_highercol); + driver->AddLine(BPoint(r.left,r.top),BPoint(r.left,r.bottom), + frame_highercol); + driver->AddLine(BPoint(r.right,r.bottom),BPoint(r.right,r.top), + frame_midcol); + driver->AddLine(BPoint(r.right,r.bottom),BPoint(r.left,r.bottom), + frame_midcol); + + r.InsetBy(1,1); + driver->StrokeRect(r,frame_highcol); + + r.InsetBy(1,1); + driver->AddLine(BPoint(r.left,r.top),BPoint(r.right-1,r.top), + frame_lowercol); + driver->AddLine(BPoint(r.left,r.top),BPoint(r.left,r.bottom), + frame_lowercol); + driver->AddLine(BPoint(r.right,r.bottom),BPoint(r.right,r.top), + frame_highercol); + driver->AddLine(BPoint(r.right,r.bottom),BPoint(r.left,r.bottom), + frame_highercol); + driver->EndLineArray(); + + // Draw the resize thumb if we're supposed to + if(!(dflags & NOT_RESIZABLE)) + { + r=resizerect; + + int32 w=r.IntegerWidth(), h=r.IntegerHeight(); + + // This code is strictly for B_DOCUMENT_WINDOW looks + if(dlook==WLOOK_DOCUMENT) + { + rgb_color tmpcol,halfcol, startcol, endcol; + float rstep,gstep,bstep,i; + + int steps=(wStrokeLine(BPoint(r.left,r.top+i), + BPoint(r.left+i,r.top),tmpcol); + + SetRGBColor(&tmpcol, uint8(halfcol.red-(i*rstep)), + uint8(halfcol.green-(i*gstep)), + uint8(halfcol.blue-(i*bstep))); + driver->StrokeLine(BPoint(r.left+steps,r.top+i), + BPoint(r.left+i,r.top+steps),tmpcol); + } + driver->StrokeRect(r,frame_lowercol); + } + else + { + driver->StrokeLine(BPoint(r.right,r.top),BPoint(r.right-3,r.top), + frame_lowercol); + driver->StrokeLine(BPoint(r.left,r.bottom),BPoint(r.left,r.bottom-3), + frame_lowercol); + } + } +} + +void BeDecorator::SetLook(uint32 wlook) +{ + dlook=wlook; +} + +void BeDecorator::CalculateBorders(void) +{ + // Here we calculate the size of the border on each side - how much the + // decorator's visible area "sticks out" past the client rectangle. + switch(dlook) + { + case WLOOK_NO_BORDER: + { + bsize.Set(0,0,0,0); + break; + } + case WLOOK_TITLED: + case WLOOK_DOCUMENT: + case WLOOK_BORDERED: + { + bsize.top=18; + break; + } + case WLOOK_MODAL: + case WLOOK_FLOATING: + { + bsize.top=15; + break; + } + default: + { + break; + } + } +} diff --git a/src/servers/app/proto6/BeDecorator.h b/src/servers/app/proto6/BeDecorator.h new file mode 100644 index 0000000000..0c30e48911 --- /dev/null +++ b/src/servers/app/proto6/BeDecorator.h @@ -0,0 +1,46 @@ +#ifndef _BEOS_DECORATOR_H_ +#define _BEOS_DECORATOR_H_ + +#include "Decorator.h" + +class BeDecorator: public Decorator +{ +public: + BeDecorator(Layer *lay, uint32 dflags, uint32 wlook); + ~BeDecorator(void); + + click_type Clicked(BPoint pt, uint32 buttons); + void Resize(BRect rect); + void MoveBy(BPoint pt); + BPoint GetMinimumSize(void); + BRegion *GetFootprint(void); + void SetTitle(const char *newtitle); + void SetFlags(uint32 flags); + void SetLook(uint32 wlook); + void UpdateFont(void); + void UpdateTitle(const char *string); + void SetFocus(bool focused); + void Draw(void); + void Draw(BRect update); + void DrawZoom(BRect r); + void DrawClose(BRect r); + void DrawTab(void); + void DrawFrame(void); + void CalculateBorders(void); + + void DrawBlendedRect(BRect r, bool down); + uint32 taboffset; + + rgb_color tab_highcol, tab_lowcol; + rgb_color button_highcol, button_lowcol; + rgb_color frame_highcol, frame_midcol, frame_lowcol, frame_highercol, + frame_lowercol; + rgb_color textcol; + + bool slidetab; + BRect zoomrect,closerect,tabrect,frame, + resizerect,borderrect; + int textoffset; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/ColorUtils.cc b/src/servers/app/proto6/ColorUtils.cc new file mode 100644 index 0000000000..510476eca9 --- /dev/null +++ b/src/servers/app/proto6/ColorUtils.cc @@ -0,0 +1,101 @@ +#include "ColorUtils.h" +#include +#include + +//#define DEBUG_COLOR_UTILS + +void SetRGBColor(rgb_color *col,uint8 r, uint8 g, uint8 b, uint8 a=255) +{ + col->red=r; + col->green=g; + col->blue=b; + col->alpha=a; +} + +uint8 FindClosestColor(rgb_color *palette, rgb_color color) +{ + // We will be passed a 256-color palette and a 24-bit color + uint16 cindex=0,cdelta=765,delta=765; + rgb_color *c; + + for(uint16 i=0;i<256;i++) + { + c=&(palette[i]); + delta=abs(c->red-color.red)+abs(c->green-color.green)+ + abs(c->blue-color.blue); + + if(delta==0) + { + cindex=i; + break; + } + + if(delta1) + return newcol; + + delta=int16(col2.red)-int16(col.red); + mod=col.red + (position * delta); + newcol.red=uint8(mod); + if(mod>255 ) + newcol.red=255; + if(mod<0 ) + newcol.red=0; + + delta=int16(col2.green)-int16(col.green); + mod=col.green + (position * delta); + newcol.green=uint8(mod); + if(mod>255 ) + newcol.green=255; + if(mod<0 ) + newcol.green=0; + + delta=int16(col2.blue)-int16(col.blue); + mod=col.blue + (position * delta); + newcol.blue=uint8(mod); + if(mod>255 ) + newcol.blue=255; + if(mod<0 ) + newcol.blue=0; + + delta=int8(col2.alpha)-int8(col.alpha); + mod=col.alpha + (position * delta); + newcol.alpha=uint8(mod); + if(mod>255 ) + newcol.alpha=255; + if(mod<0 ) + newcol.alpha=0; +#ifdef DEBUG_COLOR_UTILS +printf("MakeBlendColor( {%u,%u,%u,%u}, {%u,%u,%u,%u}, %f) : {%u,%u,%u,%u}\n", + col.red,col.green,col.blue,col.alpha, + col2.red,col2.green,col2.blue,col2.alpha, + position, + newcol.red,newcol.green,newcol.blue,newcol.alpha); +#endif + return newcol; +} diff --git a/src/servers/app/proto6/ColorUtils.h b/src/servers/app/proto6/ColorUtils.h new file mode 100644 index 0000000000..c4002d2357 --- /dev/null +++ b/src/servers/app/proto6/ColorUtils.h @@ -0,0 +1,20 @@ +#ifndef COLORUTILS_H_ +#define COLORUTILS_H_ + +#include + +// Quick assignment for rgb_color structs +void SetRGBColor(rgb_color *col,uint8 r, uint8 g, uint8 b, uint8 a=255); + +// Given a color palette, returns the index of the closest match to +// the color passed to it. Alpha values are not considered +uint8 FindClosestColor(rgb_color *palette, rgb_color color); +uint16 FindClosestColor16(rgb_color color); + +// Function which could be used to calculate gradient colors. Position is +// a floating point number such that 0.0 <= position <= 1.0. Any number outside +// this range will cause the function to fail and return the color (0,0,0,0) +// Alpha components are included in the calculations. 0 yields color #1 +// and 1 yields color #2. +rgb_color MakeBlendColor(rgb_color col, rgb_color col2, float position); +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/DebugTools.cpp b/src/servers/app/proto6/DebugTools.cpp new file mode 100644 index 0000000000..f626e927be --- /dev/null +++ b/src/servers/app/proto6/DebugTools.cpp @@ -0,0 +1,222 @@ +#include +#include +#include "DebugTools.h" + +void PrintStatusToStream(status_t value) +{ + // Function which simply translates a returned status code into a string + // and dumps it to stdout + cout << "Status: " << TranslateStatusToString(value).String() << endl << flush; +} + +BString TranslateStatusToString(status_t value) +{ + BString outstr; + switch(value) + { + case B_OK: + outstr="B_OK "; + break; + case B_NAME_NOT_FOUND: + outstr="B_NAME_NOT_FOUND "; + break; + case B_BAD_VALUE: + outstr="B_BAD_VALUE "; + break; + case B_ERROR: + outstr="B_ERROR "; + break; + case B_TIMED_OUT: + outstr="B_TIMED_OUT "; + break; + case B_NO_MORE_PORTS: + outstr="B_NO_MORE_PORTS "; + break; + case B_WOULD_BLOCK: + outstr="B_WOULD_BLOCK "; + break; + case B_BAD_PORT_ID: + outstr="B_BAD_PORT_ID "; + break; + case B_BAD_TEAM_ID: + outstr="B_BAD_TEAM_ID "; + break; + default: + outstr="undefined status value in debugtools::PrintStatusToStream() "; + break; + } + return BString(outstr); +} + +void PrintColorSpaceToStream(color_space value) +{ + // Dump a color space to cout + BString outstr; + switch(value) + { + case B_RGB32: + outstr="B_RGB32 "; + break; + case B_RGBA32: + outstr="B_RGBA32 "; + break; + case B_RGB32_BIG: + outstr="B_RGB32_BIG "; + break; + case B_RGBA32_BIG: + outstr=" "; + break; + case B_UVL32: + outstr="B_UVL32 "; + break; + case B_UVLA32: + outstr="B_UVLA32 "; + break; + case B_LAB32: + outstr="B_LAB32 "; + break; + case B_LABA32: + outstr="B_LABA32 "; + break; + case B_HSI32: + outstr="B_HSI32 "; + break; + case B_HSIA32: + outstr="B_HSIA32 "; + break; + case B_HSV32: + outstr="B_HSV32 "; + break; + case B_HSVA32: + outstr="B_HSVA32 "; + break; + case B_HLS32: + outstr="B_HLS32 "; + break; + case B_HLSA32: + outstr="B_HLSA32 "; + break; + case B_CMY32: + outstr="B_CMY32"; + break; + case B_CMYA32: + outstr="B_CMYA32 "; + break; + case B_CMYK32: + outstr="B_CMYK32 "; + break; + case B_RGB24_BIG: + outstr="B_RGB24_BIG "; + break; + case B_RGB24: + outstr="B_RGB24 "; + break; + case B_LAB24: + outstr="B_LAB24 "; + break; + case B_UVL24: + outstr="B_UVL24 "; + break; + case B_HSI24: + outstr="B_HSI24 "; + break; + case B_HSV24: + outstr="B_HSV24 "; + break; + case B_HLS24: + outstr="B_HLS24 "; + break; + case B_CMY24: + outstr="B_CMY24 "; + break; + case B_GRAY1: + outstr="B_GRAY1 "; + break; + case B_CMAP8: + outstr="B_CMAP8 "; + break; + case B_GRAY8: + outstr="B_GRAY8 "; + break; + case B_YUV411: + outstr="B_YUV411 "; + break; + case B_YUV420: + outstr="B_YUV420 "; + break; + case B_YCbCr422: + outstr="B_YCbCr422 "; + break; + case B_YCbCr411: + outstr="B_YCbCr411 "; + break; + case B_YCbCr420: + outstr="B_YCbCr420 "; + break; + case B_YUV422: + outstr="B_YUV422 "; + break; + case B_YUV9: + outstr="B_YUV9 "; + break; + case B_YUV12: + outstr="B_YUV12 "; + break; + case B_RGB15: + outstr="B_RGB15 "; + break; + case B_RGBA15: + outstr="B_RGBA15 "; + break; + case B_RGB16: + outstr="B_RGB16 "; + break; + case B_RGB16_BIG: + outstr="B_RGB16_BIG "; + break; + case B_RGB15_BIG: + outstr="B_RGB15_BIG "; + break; + case B_RGBA15_BIG: + outstr="B_RGBA15_BIG "; + break; + case B_YCbCr444: + outstr="B_YCbCr444 "; + break; + case B_YUV444: + outstr="B_YUV444 "; + break; + case B_NO_COLOR_SPACE: + outstr="B_NO_COLOR_SPACE "; + break; + default: + outstr="Undefined color space "; + break; + } + cout << "Color Space: " << outstr.String() << flush; +} + +void TranslateMessageCodeToStream(int32 code) +{ + // Used to translate BMessage message codes back to a character + // format + + cout << "'" + << (char)((code & 0xFF000000) >> 24) + << (char)((code & 0x00FF0000) >> 16) + << (char)((code & 0x0000FF00) >> 8) + << (char)((code & 0x000000FF)) << "' "; +} + +void PrintMessageCode(int32 code) +{ + // Used to translate BMessage message codes back to a character + // format + + printf("Message code %c%c%c%c\n", + (char)((code & 0xFF000000) >> 24), + (char)((code & 0x00FF0000) >> 16), + (char)((code & 0x0000FF00) >> 8), + (char)((code & 0x000000FF)) ); +} + diff --git a/src/servers/app/proto6/DebugTools.h b/src/servers/app/proto6/DebugTools.h new file mode 100644 index 0000000000..55bf1b0635 --- /dev/null +++ b/src/servers/app/proto6/DebugTools.h @@ -0,0 +1,13 @@ +#ifndef _DEBUGTOOLS_H_ +#define _DEBUGTOOLS_H_ + +#include +#include +#include + +void PrintColorSpaceToStream(color_space value); +void TranslateMessageCodeToStream(int32 code); +void PrintMessageCode(int32 code); +BString TranslateStatusToString(status_t value); + +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/Decorator.cpp b/src/servers/app/proto6/Decorator.cpp new file mode 100644 index 0000000000..3117887ecd --- /dev/null +++ b/src/servers/app/proto6/Decorator.cpp @@ -0,0 +1,153 @@ +#include "Decorator.h" + +Decorator::Decorator(Layer *lay, uint32 windowflags, uint32 wlook) +{ + layer=lay; + dflags=windowflags; + minsize.Set(0,0); + bsize.Set(1,1,1,1); + dlook=wlook; + focused=false; + driver=get_gfxdriver(); +} + +Decorator::~Decorator(void) +{ +} + +Layer* Decorator::GetLayer(void) +{ + return layer; +} + +click_type Decorator::Clicked(BPoint pt, uint32 buttons) +{ + return CLICK_NONE; +} + +void Decorator::Resize(BRect rect) +{ +} + +void Decorator::MoveBy(BPoint pt) +{ +} + +BRect Decorator::GetBorderSize(void) +{ + return bsize; +} + +BPoint Decorator::GetMinimumSize(void) +{ + return BPoint(0,0); +} + +BRegion * Decorator::GetFootprint(void) +{ + return NULL; +} + +void Decorator::SetFlags(uint32 flags) +{ + dflags=flags; +} + +uint32 Decorator::Flags(void) +{ + return dflags; +} + +void Decorator::SetLook(uint32 wlook) +{ + dlook=(uint32)wlook; +} + +uint32 Decorator::Look(void) +{ + return dlook; +} + +void Decorator::SetFeel(uint32 wfeel) +{ + dfeel=(uint32)wfeel; +} + +uint32 Decorator::Feel(void) +{ + return dfeel; +} + +void Decorator::UpdateTitle(const char *string) +{ +} + +void Decorator::UpdateFont(void) +{ +} + +void Decorator::SetFocus(bool focused) +{ +} + +void Decorator::SetCloseButton(bool down) +{ + closestate=down; +} + +void Decorator::SetZoomButton(bool down) +{ + zoomstate=down; +} + +void Decorator::SetMinimizeButton(bool down) +{ + minstate=down; +} + +bool Decorator::GetCloseButton(void) const +{ + return closestate; +} + +bool Decorator::GetZoomButton(void) const +{ + return zoomstate; +} + +bool Decorator::GetMinimizeButton(void) const +{ + return minstate; +} + +void Decorator::Draw(BRect update) +{ +} + +void Decorator::Draw(void) +{ +} + +void Decorator::DrawTab(void) +{ +} + +void Decorator::DrawFrame(void) +{ +} + +void Decorator::DrawZoom(BRect r) +{ +} + +void Decorator::DrawClose(BRect r) +{ +} + +void Decorator::DrawMinimize(BRect r) +{ +} + +void Decorator::CalculateBorders(void) +{ +} diff --git a/src/servers/app/proto6/Decorator.h b/src/servers/app/proto6/Decorator.h new file mode 100644 index 0000000000..93e71b5928 --- /dev/null +++ b/src/servers/app/proto6/Decorator.h @@ -0,0 +1,107 @@ +#ifndef _DECORATOR_H_ +#define _DECORATOR_H_ + +#include +#include +//#include +#include "Desktop.h" + +class Layer; +class DisplayDriver; + +typedef enum { CLICK_NONE=0, CLICK_ZOOM, CLICK_CLOSE, CLICK_MINIMIZE, + CLICK_TAB, CLICK_DRAG, CLICK_MOVETOBACK, CLICK_MOVETOFRONT, + + CLICK_RESIZE, CLICK_RESIZE_L, CLICK_RESIZE_T, + CLICK_RESIZE_R, CLICK_RESIZE_B, CLICK_RESIZE_LT, CLICK_RESIZE_RT, + CLICK_RESIZE_LB, CLICK_RESIZE_RB } click_type; + +// Definitions which are used in place of including Window.h +// window_look and window_feel are enumerated types, so we convert them +// to uint32's in order to ensure a constant size when sending via PortLink +// instead of depending on magic numbers in the header file. + +#define WLOOK_NO_BORDER 0 +#define WLOOK_BORDERED 1 +#define WLOOK_TITLED 2 +#define WLOOK_DOCUMENT 3 +#define WLOOK_MODAL 4 +#define WLOOK_FLOATING 5 + +#define WFEEL_NORMAL 0 +#define WFEEL_MODAL_SUBSET 1 +#define WFEEL_MODAL_APP 2 +#define WFEEL_MODAL_WINDOW 3 +#define WFEEL_FLOATING_SUBSET 4 +#define WFEEL_FLOATING_APP 5 +#define WFEEL_FLOATING_WINDOW 6 + +#define NOT_MOVABLE 0x00000001 +#define NOT_CLOSABLE 0x00000020 +#define NOT_ZOOMABLE 0x00000040 +#define NOT_MINIMIZABLE 0x00004000 +#define NOT_RESIZABLE 0x00000002 +#define NOT_H_RESIZABLE 0x00000004 +#define NOT_V_RESIZABLE 0x00000008 +#define AVOID_FRONT 0x00000080 +#define AVOID_FOCUS 0x00002000 +#define WILL_ACCEPT_FIRST_CLICK 0x00000010 +#define OUTLINE_RESIZE 0x00001000 +#define NO_WORKSPACE_ACTIVATION 0x00000100 +#define NOT_ANCHORED_ON_ACTIVATE 0x00020000 +#define ASYNCHRONOUS_CONTROLS 0x00080000 +#define QUIT_ON_WINDOW_CLOSE 0x00100000 + +class Decorator +{ +public: + Decorator(Layer *lay, uint32 windowflags, uint32 wlook); + virtual ~Decorator(void); + + Layer* GetLayer(void); + + virtual click_type Clicked(BPoint pt, uint32 buttons); + virtual void Resize(BRect rect); + virtual void MoveBy(BPoint pt); + virtual BRect GetBorderSize(void); + virtual BPoint GetMinimumSize(void); + virtual BRegion *GetFootprint(void); + virtual void SetFlags(uint32 flags); + virtual uint32 Flags(void); + virtual void SetLook(uint32 wlook); + virtual uint32 Look(void); + virtual void SetFeel(uint32 wfeel); + virtual uint32 Feel(void); + virtual void UpdateTitle(const char *string); + virtual void UpdateFont(void); + virtual void SetFocus(bool focused); + virtual void SetCloseButton(bool down); + virtual void SetZoomButton(bool down); + virtual void SetMinimizeButton(bool down); + bool GetCloseButton(void) const; + bool GetZoomButton(void) const; + bool GetMinimizeButton(void) const; + virtual void Draw(BRect update); + virtual void Draw(void); + virtual void DrawTab(void); + virtual void DrawFrame(void); + virtual void DrawZoom(BRect r); + virtual void DrawClose(BRect r); + virtual void DrawMinimize(BRect r); +protected: + virtual void CalculateBorders(void); + Layer *layer; + BPoint minsize; + uint32 dlook, dfeel, dflags; + BRect bsize; + bool focused; + bool zoomstate, closestate, minstate; + DisplayDriver *driver; +}; + +// C exports to hide the class-related stuff from the rest of the +// server. Written for each decorator, but don't amount to much. +typedef uint16 get_decorator_version(void); +typedef Decorator *create_decorator(Layer *lay, uint32 dflags, uint32 wlook); + +#endif diff --git a/src/servers/app/proto6/Desktop.cpp b/src/servers/app/proto6/Desktop.cpp new file mode 100644 index 0000000000..c7ac1af3c3 --- /dev/null +++ b/src/servers/app/proto6/Desktop.cpp @@ -0,0 +1,413 @@ +/* + Desktop.cpp: + Code necessary to handle the Desktop, defined as the collection of workspaces. +*/ + +//#define DEBUG_WORKSPACES + +#include +#include +#include +#include +#include +#include "ColorUtils.h" +#include "SystemPalette.h" +#include "ServerWindow.h" +#include "ServerCursor.h" +#include "Layer.h" +#include "DisplayDriver.h" +#include "ViewDriver.h" +#include "SecondDriver.h" +#include "ScreenDriver.h" +#include "Desktop.h" +#include "WindowBorder.h" + +class ServerWindow; +class ServerBitmap; +class Workspace; + +//--------------------GLOBALS------------------------- +uint32 workspace_count, active_workspace; +BList *desktop; +ServerCursor *startup_cursor; +Workspace *pactive_workspace; +DisplayDriver *gfxdriver; +int32 token_count=-1; +BLocker *workspacelock; +BLocker *layerlock; +UpdateNode *upnode; +//---------------------------------------------------- + + +//-------------------INTERNAL CLASS DEFS-------------- +class Workspace +{ +public: + Workspace(void); + Workspace(BPath imagepath); + ~Workspace(); + void SetBGColor(rgb_color col); + rgb_color BGColor(void); + thread_id tid; + + RootLayer *toplayer; + BList focuslist; + rgb_color bgcolor; + screen_info screendata, + olddata; +}; + +DisplayDriver *get_gfxdriver(void) +{ + return gfxdriver; +} + +Workspace::Workspace(void) +{ + workspace_count++; + + // default values + focuslist.MakeEmpty(); + bgcolor.red=51; + bgcolor.green=102; + bgcolor.blue=160; + screendata.mode=B_CMAP8; + screendata.spaces=B_8_BIT_640x480; + screendata.refresh_rate=60.0; + screendata.min_refresh_rate=60.0; + screendata.max_refresh_rate=60.0; + screendata.h_position=(uchar)50; + screendata.v_position=(uchar)50; + screendata.h_size=(uchar)50; + screendata.v_size=(uchar)50; + olddata=screendata; + + // We need one top layer for each workspace times the number of monitors - ick. + // Currently, we only have 1 monitor. *Whew* + char wspace_name[128]; + sprintf(wspace_name,"workspace %ld root",workspace_count); + toplayer=new RootLayer(BRect(0,0,639,439),wspace_name); +} + +Workspace::~Workspace(void) + { + workspace_count--; + toplayer->PruneTree(); +} + +void Workspace::SetBGColor(rgb_color col) +{ + bgcolor=col; + toplayer->SetColor(col); +#ifdef DEBUG_WORKSPACES +printf("Workspace::SetBGColor(%d,%d,%d,%d)\n",bgcolor.red,bgcolor.green, + bgcolor.blue,bgcolor.alpha); +#endif +} + +rgb_color Workspace::BGColor(void) +{ + return bgcolor; +} +//--------------------------------------------------- + + +//-----------------GLOBAL FUNCTION DEFS--------------- + +void init_desktop(int8 workspaces) +{ +#ifdef DEBUG_WORKSPACES +printf("init_desktop(%d)\n",workspaces); +#endif + workspace_count=workspaces; + if(workspace_count==0) + workspace_count++; + + // Instantiate and initialize display driver + gfxdriver=new ViewDriver(); +// gfxdriver=new SecondDriver(); +// gfxdriver=new ScreenDriver(); + gfxdriver->Initialize(); + + workspacelock=new BLocker(); + layerlock=new BLocker(); + +#ifdef DEBUG_WORKSPACES +printf("Driver %s\n", (gfxdriver->IsInitialized()==true)?"initialized":"NOT initialized"); +#endif + + desktop=new BList(0); + + // Create the workspaces we're supposed to have + for(int8 i=0; iAddItem(new Workspace()); + + // Load workspace preferences here + + // We're going to punch in some hardcoded settings for testing purposes. + // There are 3 workspaces hardcoded in for now, but we'll only use the + // second one. + Workspace *wksp=(Workspace*)desktop->ItemAt(1); + if(wksp!=NULL) // in case I forgot something + { + rgb_color bcol; + SetRGBColor(&bcol,0,200,236); + +// SetRGBColor(&(wksp->bgcolor),0,200,236); + wksp->SetBGColor(bcol); + screen_info *tempsd=&(wksp->screendata); + tempsd->mode=B_CMAP8; + tempsd->spaces=B_8_BIT_800x600; + tempsd->frame.Set(0,0,799,599); + } + else + printf("DW goofed on the workspace index :P\n"); + + // Activate workspace 0 + pactive_workspace=(Workspace *)desktop->ItemAt(0); + pactive_workspace->screendata.spaces=B_32_BIT_640x480; + gfxdriver->SetScreen(pactive_workspace->screendata.spaces); + + // Clear the screen + SetRGBColor(&(pactive_workspace->toplayer->bgcolor),80,85,152); + gfxdriver->Clear(pactive_workspace->toplayer->bgcolor); + startup_cursor=new ServerCursor(default_cursor); + gfxdriver->SetCursor(startup_cursor); + gfxdriver->ShowCursor(); + + pactive_workspace->toplayer->SetVisible(true); +#ifdef DEBUG_WORKSPACES +printf("Desktop initialized\n"); +#endif +} + +void shutdown_desktop(void) +{ + int32 i,count=desktop->CountItems(); + Workspace *w; + for(i=0;iItemAt(i); + if(w!=NULL) + delete w; + } + desktop->MakeEmpty(); + delete desktop; + gfxdriver->Shutdown(); + delete gfxdriver; + delete workspacelock; + delete layerlock; + delete startup_cursor; +} + + +int32 CountWorkspaces(void) +{ +#ifdef DEBUG_WORKSPACES +printf("CountWorkspaces() returned %ld\n",workspace_count); +#endif + return workspace_count; +} + +void SetWorkspaceCount(uint32 count) +{ + if(count<0) + { +#ifdef DEBUG_WORKSPACES +printf("SetWorkspaceCount(value<0) - DOH!\n"); +#endif + return; + } + if(count==workspace_count) + return; + + // Activate last workspace in new set if we're using one to be nuked + if(countItemAt(i)!=NULL) + { + delete (Workspace*)desktop->ItemAt(i); + desktop->RemoveItem(i); + } + } + } + else + { + // count > workspace_count here + + // Once we have default workspace preferences which can be set by the + // user, we'll end up having to initialize newly-added workspaces to that + // data. In the mean time, the defaults in the constructor will do. :) + for(uint32 i=count;iAddItem(new Workspace()); + } + } + + // don't forget to update our global! + workspace_count=desktop->CountItems(); + +#ifdef DEBUG_WORKSPACES +printf("SetWorkspaceCount(%ld)\n",workspace_count); +#endif + +} + +int32 CurrentWorkspace(void) +{ +#ifdef DEBUG_WORKSPACES +printf("CurrentWorkspace() returned %ld\n",active_workspace); +#endif + return active_workspace; +} + +void ActivateWorkspace(uint32 workspace) +{ + // In order to change workspaces, we'll need to make all the necessary + // changes to the screen to fit the new one, such as resolution, + // background color, color depth, refresh rate, etc. + + if(workspace>workspace_count || workspace<0) + return; + + Workspace *proposed=(Workspace *)desktop->ItemAt(workspace); + + if(proposed==NULL) + return; + + // Here's where we update all the screen stuff +// if(pactive_workspace->screendata.spaces != proposed->screendata.spaces) +// { + gfxdriver->SetScreen(proposed->screendata.spaces); + gfxdriver->Clear(proposed->bgcolor); + pactive_workspace->toplayer->SetVisible(false); + proposed->toplayer->SetVisible(true); +// } + // more if != then change code goes here. Currently, a lot of the code which + // uses this stuff is not implemented, so it's kind of moot. However, when we + // use the real graphics HW, it'll become important. + + // actually set our active workspace data to reflect the change in workspaces + pactive_workspace=proposed; + active_workspace=workspace; +#ifdef DEBUG_WORKSPACES +printf("ActivateWorkspace(%ld)\n",active_workspace); +#endif +} + +const color_map *SystemColors(void) +{ + return (const color_map *)&system_palette; +} + +status_t SetScreenSpace(uint32 index, uint32 res, bool stick = true) +{ +#ifdef DEBUG_WORKSPACES +printf("SetScreenSpace(%ld,%lu, %s)\n",index,res,(stick==true)?"true":"false"); +#endif + + if(index>workspace_count-1) + { + printf("SetScreenSpace was passed invalid workspace value %ld\n",index); + return B_ERROR; + } + if(res>0x800000) // the last "normal" screen mode defined in GraphicsDefs.h + { + printf("SetScreenSpace was passed invalid screen value %lu\n",res); + return B_ERROR; + } + + // When we actually use app_server preferences, we'll save the screen mode to + // the preferences so that we use this mode next boot. For now, we treat stick==false + if(stick==true) + { + // save the screen data here + } + if(index==active_workspace) + { + gfxdriver->SetScreen(res); + gfxdriver->Clear(pactive_workspace->bgcolor); + } + else + { + // just set the workspace's data here. right now, do nothing. + } + return B_OK; +} + +int32 GetViewToken(void) +{ + // Used to generate view and layer tokens + return ++token_count; +} + +void AddWindowToDesktop(ServerWindow *win,uint32 workspace) +{ + // Adds the top layer of each window to the root layer in the specified workspace. + // Note that in calling AddChild, a redraw is invoked + if(!win || workspace>workspace_count-1) + return; + + workspacelock->Lock(); + Workspace *w=(Workspace *)desktop->ItemAt(workspace); + if(w) + { + // a check for the B_CURRENT_WORKSPACE or B_ALL_WORKSPACES specifiers will + // go here later + + w->toplayer->AddChild(win->winborder); + } + workspacelock->Unlock(); +} + +void RemoveWindowFromDesktop(ServerWindow *win) +{ + // A little more time-consuming than AddWindow + if(!win) + return; + + workspacelock->Lock(); + + // a check for the B_CURRENT_WORKSPACE or B_ALL_WORKSPACES specifiers will + // go here later + + // If the window belongs on only 1 workspace, calling RemoveSelf is the most + // elegant solution. + win->winborder->RemoveSelf(); + workspacelock->Unlock(); +} + +Layer *GetRootLayer(void) +{ + layerlock->Lock(); + Layer *lay=(workspace_count>0)?pactive_workspace->toplayer:NULL; + layerlock->Unlock(); + + return lay; +} + +ServerWindow *GetActiveWindow(int32 workspace) +{ + Layer *root=GetRootLayer(); + if(!root) + return NULL; + Layer *lay=root->topchild, *nextlay; + while(lay!=NULL) + { + if(lay->serverwin && lay->serverwin->HasFocus()) + return lay->serverwin; + nextlay=lay->lowersibling; + lay=nextlay; + } + return NULL; +} + +// Another "just in case DW screws up again" section +#ifdef DEBUG_WORKSPACES +#undef DEBUG_WORKSPACES +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/Desktop.h b/src/servers/app/proto6/Desktop.h new file mode 100644 index 0000000000..f5bb363c3d --- /dev/null +++ b/src/servers/app/proto6/Desktop.h @@ -0,0 +1,47 @@ +#ifndef _OBDESKTOP_H_ +#define _OBDESKTOP_H_ + + +#include +#include +#include + +class DisplayDriver; +class ServerWindow; +class Layer; + +void init_desktop(int8 workspaces); +void shutdown_desktop(void); +DisplayDriver *get_gfxdriver(void); + +// Workspace access functions +int32 CountWorkspaces(void); +void SetWorkspaceCount(uint32 count); + +int32 CurrentWorkspace(void); +void ActivateWorkspace(uint32 workspace); + +const color_map *SystemColors(void); +status_t SetScreenSpace(uint32 index, uint32 res, bool stick=true); + +void AddWindowToDesktop(ServerWindow *win,uint32 workspace); +void RemoveWindowFromDesktop(ServerWindow *win); +ServerWindow *GetActiveWindow(int32 workspace); +Layer *GetRootLayer(void); +int32 GetViewToken(void); + +typedef struct +{ + color_space mode; + BRect frame; + uint32 spaces; + float min_refresh_rate; + float max_refresh_rate; + float refresh_rate; + uchar h_position; + uchar v_position; + uchar h_size; + uchar v_size; +} screen_info; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/DisplayDriver.cpp b/src/servers/app/proto6/DisplayDriver.cpp new file mode 100644 index 0000000000..54c8cd5fcd --- /dev/null +++ b/src/servers/app/proto6/DisplayDriver.cpp @@ -0,0 +1,327 @@ +/* + DisplayDriver.cpp + Modular class to allow the server to not care what the ultimate output is + for graphics calls. +*/ +#include "DisplayDriver.h" +#include "ColorUtils.h" +#include "SystemPalette.h" +#include "ServerCursor.h" + +DisplayDriver::DisplayDriver(void) +{ + is_initialized=false; + cursor_visible=true; + show_on_move=false; + locker=new BLocker(); + + penpos.Set(0,0); + pensize=0.0; + + // initialize to BView defaults + highcol.red=0; + highcol.green=0; + highcol.blue=0; + highcol.alpha=0; + lowcol.red=255; + lowcol.green=255; + lowcol.blue=255; + lowcol.alpha=255; +} + +DisplayDriver::~DisplayDriver(void) +{ + delete locker; +} + +void DisplayDriver::Initialize(void) +{ // Loading loop to find proper driver or other setup for the driver +} + +bool DisplayDriver::IsInitialized(void) +{ // Let us know whether things worked out ok + return is_initialized; +} + +void DisplayDriver::Shutdown(void) +{ // For use by subclasses +} + +void DisplayDriver::SafeMode(void) +{ // Set video mode to 640x480x256 mode +} + +void DisplayDriver::Reset(void) +{ // Intended to reload and restart driver. Defaults to a safe mode +} + +void DisplayDriver::Clear(uint8 red,uint8 green,uint8 blue) +{ +} + +void DisplayDriver::Clear(rgb_color col) +{ +} + +void DisplayDriver::SetScreen(uint32 space) +{ // Set the screen to a particular mode +} + +int32 DisplayDriver::GetHeight(void) +{ // Gets the height of the current mode + return ginfo->height; +} + +int32 DisplayDriver::GetWidth(void) +{ // Gets the width of the current mode + return ginfo->width; +} + +int DisplayDriver::GetDepth(void) +{ // Gets the color depth of the current mode + return ginfo->bytes_per_row; +} + +void DisplayDriver::AddLine(BPoint pt1, BPoint pt2, rgb_color col) +{ +} + +void DisplayDriver::BeginLineArray(int32 count) +{ +} + +void DisplayDriver::Blit(BRect src, BRect dest) +{ // Screen-to-screen bitmap copying +} + +void DisplayDriver::DrawBitmap(ServerBitmap *bitmap, BRect source, BRect dest) +{ +} + +void DisplayDriver::DrawChar(char c, BPoint point) +{ +} + +void DisplayDriver::DrawLineArray(int32 count,BPoint *start, BPoint *end, rgb_color *color) +{ +} + +void DisplayDriver::DrawString(char *string, int length, BPoint point) +{ +} + +void DisplayDriver::EndLineArray(void) +{ +} + +void DisplayDriver::FillArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern) +{ +} + +void DisplayDriver::FillBezier(BPoint *points, uint8 *pattern) +{ +} + +void DisplayDriver::FillEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern) +{ +} + +void DisplayDriver::FillPolygon(int *x, int *y, int numpoints, bool is_closed) +{ +} + +void DisplayDriver::FillRect(BRect rect, uint8 *pattern) +{ +} + +void DisplayDriver::FillRect(BRect rect, rgb_color col) +{ +} + +void DisplayDriver::FillRegion(BRegion *region) +{ +} + +void DisplayDriver::FillRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern) +{ +} + +void DisplayDriver::FillShape(BShape *shape) +{ +} + +void DisplayDriver::FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern) +{ +} + +void DisplayDriver::FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, rgb_color col) +{ +} + +drawing_mode DisplayDriver::GetDrawingMode(void) +{ + return B_OP_COPY; +} + +void DisplayDriver::HideCursor(void) +{ +} + +rgb_color DisplayDriver::HighColor(void) +{ + locker->Lock(); + rgb_color col=highcol; + locker->Unlock(); + return col; +} + +bool DisplayDriver::IsCursorHidden(void) +{ + return false; +} + +rgb_color DisplayDriver::LowColor(void) +{ + locker->Lock(); + rgb_color col=lowcol; + locker->Unlock(); + return col; +} + +void DisplayDriver::ObscureCursor(void) +{ // Hides cursor until mouse is moved +} + +void DisplayDriver::MoveCursorTo(float x, float y) +{ +} + +void DisplayDriver::MovePenTo(BPoint pt) +{ // Moves the graphics pen to this position + penpos=pt; +} + +BPoint DisplayDriver::PenPosition(void) +{ + return penpos; +} + +float DisplayDriver::PenSize(void) +{ + return pensize; +} + +void DisplayDriver::SetCursor(ServerCursor *cursor) +{ +} + +void DisplayDriver::SetDrawingMode(drawing_mode mode) +{ +} + +void DisplayDriver::SetHighColor(uint8 r,uint8 g,uint8 b,uint8 a=255) +{ + SetRGBColor(&highcol,r,g,b,a); + high16=FindClosestColor16(highcol); + high8=FindClosestColor(system_palette,highcol); +} + +void DisplayDriver::SetHighColor(rgb_color col) +{ + highcol=col; + high16=FindClosestColor16(highcol); + high8=FindClosestColor(system_palette,highcol); +} + +void DisplayDriver::SetLowColor(uint8 r,uint8 g,uint8 b,uint8 a=255) +{ + SetRGBColor(&lowcol,r,g,b,a); + low16=FindClosestColor16(lowcol); + low8=FindClosestColor(system_palette,lowcol); +} + +void DisplayDriver::SetLowColor(rgb_color col) +{ + lowcol=col; + low16=FindClosestColor16(lowcol); + low8=FindClosestColor(system_palette,lowcol); +} + +void DisplayDriver::SetPenSize(float size) +{ + pensize=(size>0)?size:1; +} + +void DisplayDriver::SetPixel(int x, int y, uint8 *pattern) +{ // Internal function utilized by other functions to draw to the buffer + // Will eventually be an inline function +} + +void DisplayDriver::ShowCursor(void) +{ +} + +float DisplayDriver::StringWidth(const char *string, int32 length) +{ + return -1.0; +} + +void DisplayDriver::StrokeArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern) +{ +} + +void DisplayDriver::StrokeBezier(BPoint *points, uint8 *pattern) +{ +} + +void DisplayDriver::StrokeEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern) +{ +} + +void DisplayDriver::StrokeLine(BPoint point, uint8 *pattern) +{ +} + +void DisplayDriver::StrokeLine(BPoint pt1, BPoint pt2, rgb_color col) +{ +} + +void DisplayDriver::StrokePolygon(int *x, int *y, int numpoints, bool is_closed) +{ +} + +void DisplayDriver::StrokeRect(BRect rect, uint8 *pattern) +{ +} + +void DisplayDriver::StrokeRect(BRect rect, rgb_color col) +{ +} + +void DisplayDriver::StrokeRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern) +{ +} + +void DisplayDriver::StrokeShape(BShape *shape) +{ +} + +void DisplayDriver::StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern) +{ +} + +void DisplayDriver::StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, rgb_color col) +{ +} + +void DisplayDriver::Line32(BPoint pt, BPoint pt2, uint8 *pattern) +{ +} + +void DisplayDriver::Line16(BPoint pt, BPoint pt2, uint8 *pattern) +{ +} + +void DisplayDriver::Line8(BPoint pt, BPoint pt2, uint8 *pattern) +{ +} diff --git a/src/servers/app/proto6/DisplayDriver.h b/src/servers/app/proto6/DisplayDriver.h new file mode 100644 index 0000000000..b679d6e07a --- /dev/null +++ b/src/servers/app/proto6/DisplayDriver.h @@ -0,0 +1,156 @@ +#ifndef _GFX_DRIVER_H_ +#define _GFX_DRIVER_H_ + +#include +#include +#include +#include "Desktop.h" + +class ServerBitmap; +class ServerCursor; + +#ifndef ROUND + #define ROUND(a) ( (a-long(a))>=.5)?(long(a)+1):(long(a)) +#endif + +typedef struct +{ + uchar *xormask, *andmask; + int32 width, height; + int32 hotx, hoty; + +} cursor_data; + +#ifndef HOOK_DEFINE_CURSOR + +#define HOOK_DEFINE_CURSOR 0 +#define HOOK_MOVE_CURSOR 1 +#define HOOK_SHOW_CURSOR 2 +#define HOOK_DRAW_LINE_8BIT 3 +#define HOOK_DRAW_LINE_16BIT 12 +#define HOOK_DRAW_LINE_32BIT 4 +#define HOOK_DRAW_RECT_8BIT 5 +#define HOOK_DRAW_RECT_16BIT 13 +#define HOOK_DRAW_RECT_32BIT 6 +#define HOOK_BLIT 7 +#define HOOK_DRAW_ARRAY_8BIT 8 +#define HOOK_DRAW_ARRAY_16BIT 14 // Not implemented in current R5 drivers +#define HOOK_DRAW_ARRAY_32BIT 9 +#define HOOK_SYNC 10 +#define HOOK_INVERT_RECT 11 + +#endif + +class ServerCursor; + +#define DRAW_COPY 0 +#define DRAW_OVER 1 +#define DRAW_ERASE 2 +#define DRAW_INVERT 3 +#define DRAW_ADD 4 +#define DRAW_SUBTRACT 5 +#define DRAW_BLEND 6 +#define DRAW_MIN 7 +#define DRAW_MAX 8 +#define DRAW_SELECT 9 +#define DRAW_ALPHA 10 + + +class DisplayDriver +{ +public: + DisplayDriver(void); + virtual ~DisplayDriver(void); + + virtual void Initialize(void); // Sets the driver + virtual bool IsInitialized(void); + virtual void Shutdown(void); // You never know when you'll need this + + virtual void SafeMode(void); // Easy-access functions for common tasks + virtual void Reset(void); + virtual void Clear(uint8 red,uint8 green,uint8 blue); + virtual void Clear(rgb_color col); + + // Settings functions + virtual void SetScreen(uint32 space); + virtual int32 GetHeight(void); + virtual int32 GetWidth(void); + virtual int GetDepth(void); + + // Drawing functions + virtual void AddLine(BPoint pt1, BPoint pt2, rgb_color col); + virtual void BeginLineArray(int32 count); + virtual void Blit(BRect src, BRect dest); + virtual void DrawBitmap(ServerBitmap *bitmap, BRect source, BRect dest); + virtual void DrawChar(char c, BPoint point); + virtual void DrawLineArray(int32 count,BPoint *start, BPoint *end, rgb_color *color); + virtual void DrawString(char *string, int length, BPoint point); + virtual void EndLineArray(void); + + virtual void FillArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern); + virtual void FillBezier(BPoint *points, uint8 *pattern); + virtual void FillEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern); + virtual void FillPolygon(int *x, int *y, int numpoints, bool is_closed); + virtual void FillRect(BRect rect, uint8 *pattern); + virtual void FillRect(BRect rect, rgb_color col); + virtual void FillRegion(BRegion *region); + virtual void FillRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern); + virtual void FillShape(BShape *shape); + virtual void FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern); + virtual void FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, rgb_color col); + +// virtual void GetBlendingMode(source_alpha *srcmode, alpha_function *funcmode); + virtual drawing_mode GetDrawingMode(void); + virtual void HideCursor(void); + rgb_color HighColor(void); + virtual bool IsCursorHidden(void); + rgb_color LowColor(void); + virtual void MoveCursorTo(float x, float y); + virtual void MovePenTo(BPoint pt); + virtual void ObscureCursor(void); + virtual BPoint PenPosition(void); + virtual float PenSize(void); +// virtual void SetBlendingMode(source_alpha srcmode, alpha_function funcmode); + virtual void SetCursor(ServerCursor *cursor); + virtual void SetDrawingMode(drawing_mode mode); + virtual void ShowCursor(void); + virtual void SetHighColor(uint8 r,uint8 g,uint8 b,uint8 a=255); + virtual void SetHighColor(rgb_color col); + virtual void SetLowColor(uint8 r,uint8 g,uint8 b,uint8 a=255); + virtual void SetLowColor(rgb_color col); + virtual void SetPenSize(float size); + virtual void SetPixel(int x, int y, uint8 *pattern); + + virtual float StringWidth(const char *string, int32 length); + virtual void StrokeArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern); + virtual void StrokeBezier(BPoint *points, uint8 *pattern); + virtual void StrokeEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern); + virtual void StrokeLine(BPoint point, uint8 *pattern); + virtual void StrokeLine(BPoint pt1, BPoint pt2, rgb_color col); + virtual void StrokePolygon(int *x, int *y, int numpoints, bool is_closed); + virtual void StrokeRect(BRect rect,uint8 *pattern); + virtual void StrokeRect(BRect rect, rgb_color col); + virtual void StrokeRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern); + virtual void StrokeShape(BShape *shape); + virtual void StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern); + virtual void StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, rgb_color col); + + graphics_card_hook ghooks[48]; + graphics_card_info *ginfo; + +protected: + virtual void Line32(BPoint pt, BPoint pt2, uint8 *pattern); + virtual void Line16(BPoint pt, BPoint pt2, uint8 *pattern); + virtual void Line8(BPoint pt, BPoint pt2, uint8 *pattern); + + bool is_initialized, cursor_visible, show_on_move; + ServerCursor *current_cursor; + BLocker *locker; + rgb_color highcol, lowcol; + uint16 high16, low16; + uint8 high8, low8; + BPoint penpos; + float pensize; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/Globals.h b/src/servers/app/proto6/Globals.h new file mode 100644 index 0000000000..2753cad1aa --- /dev/null +++ b/src/servers/app/proto6/Globals.h @@ -0,0 +1,7 @@ +#ifndef _SERVER_GLOBALS_H_ +#define _SERVER_GLOBALS_H_ + +#include +BList *gBitmaplist, *gLayerlist; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/Layer.cpp b/src/servers/app/proto6/Layer.cpp new file mode 100644 index 0000000000..cdb556aefb --- /dev/null +++ b/src/servers/app/proto6/Layer.cpp @@ -0,0 +1,885 @@ +/* + Layer.cpp + Class used for rendering to the frame buffer. One layer per view on screen and + also for window decorators +*/ +#include "Layer.h" +#include "ServerWindow.h" +#include "Desktop.h" +#include "PortLink.h" +#include "DisplayDriver.h" +#include +#include +#include +#include +#include + +//#define DEBUG_LAYERS + +Layer::Layer(BRect rect, const char *layername, ServerWindow *srvwin, + int32 viewflags, int32 token) +{ + if(rect.IsValid()) + // frame is in parent layer's coordinates + frame=rect; + else + { +#ifdef DEBUG_LAYERS +printf("Invalid BRect: "); rect.PrintToStream(); +#endif + frame.Set(0,0,1,1); + } + + name=new BString(layername); + + // Layer does not start out as a part of the tree + parent=NULL; + uppersibling=NULL; + lowersibling=NULL; + topchild=NULL; + bottomchild=NULL; + + visible=new BRegion(Bounds()); + full=new BRegion(Bounds()); + invalid=NULL; + + serverwin=srvwin; + + view_token=token; + + flags=viewflags; + + hidecount=0; + is_dirty=false; + is_updating=false; + + // Because this is not part of the tree, level is negative (thus, irrelevant) + level=0; +#ifdef DEBUG_LAYERS + PrintToStream(); +#endif +} + +Layer::Layer(BRect rect, const char *layername) +{ + // This constructor is used for the top layer in each workspace + if(rect.IsValid()) + frame=rect; + else + frame.Set(0,0,1,1); + + name=new BString(layername); + + // Layer is the root for the workspace + parent=NULL; + uppersibling=NULL; + lowersibling=NULL; + topchild=NULL; + bottomchild=NULL; + + visible=new BRegion(Bounds()); + full=new BRegion(Bounds()); + invalid=NULL; + + serverwin=NULL; + flags=0; + hidecount=0; + is_dirty=false; + + level=0; + + view_token=-1; +#ifdef DEBUG_LAYERS + PrintToStream(); +#endif +} + +Layer::~Layer(void) +{ +#ifdef DEBUG_LAYERS +printf("Layer Destructor for %s\n",name->String()); +#endif + if(visible) + { + delete visible; + visible=NULL; + } + if(full) + { + delete full; + full=NULL; + } + if(invalid) + { + delete invalid; + invalid=NULL; + } + if(name) + { + delete name; + name=NULL; + } +} + +// Tested for adding children with 1 and 2 child cases, but not more +void Layer::AddChild(Layer *layer) +{ + // Adds a layer to the top of the layer's children +#ifdef DEBUG_LAYERS +printf("AddChild %s\n",layer->name->String()); +printf("Before AddChild: \n"); +PrintNode(); +if(parent) + parent->PrintNode(); +if(uppersibling) + uppersibling->PrintNode(); +if(lowersibling) + lowersibling->PrintNode(); +if(topchild) + topchild->PrintNode(); +if(bottomchild) + bottomchild->PrintNode(); +#endif + + + if(layer->parent!=NULL) + { + printf("ERROR: AddChild(): View already has a parent\n"); + return; + } + layer->parent=this; + if(layer->visible && layer->hidecount==0 && visible) + { + // Technically, we could safely take the address of ConvertToParent(BRegion) + // but we don't just to avoid a compiler nag + + BRegion *reg=new BRegion(layer->ConvertToParent(layer->visible)); + visible->Exclude(reg); + delete reg; + } + + if(topchild!=NULL) + { + layer->lowersibling=topchild; + topchild->uppersibling=layer; + if(layer->frame.Intersects(layer->lowersibling->frame)) + { + if(layer->lowersibling->visible && layer->lowersibling->hidecount==0) + { + BRegion *reg=new BRegion(ConvertToParent(layer->visible)); + BRegion *reg2=new BRegion(layer->lowersibling->ConvertFromParent(reg)); + delete reg; + layer->lowersibling->visible->Exclude(reg2); + delete reg2; + } + } + } + else + bottomchild=layer; + topchild=layer; + layer->level=level+1; + +#ifdef DEBUG_LAYERS +printf("After AddChild: \n"); +PrintNode(); +if(parent) + parent->PrintNode(); +if(uppersibling) + uppersibling->PrintNode(); +if(lowersibling) + lowersibling->PrintNode(); +if(topchild) + topchild->PrintNode(); +if(bottomchild) + bottomchild->PrintNode(); +#endif +} + +// Tested for cases with 1 and 2 children, but no more than that +void Layer::RemoveChild(Layer *layer) +{ + // Remove a layer from the tree +#ifdef DEBUG_LAYERS +printf("RemoveChild %s\n",layer->name->String()); +printf("Before RemoveChild: \n"); +PrintNode(); +if(parent) + parent->PrintNode(); +if(uppersibling) + uppersibling->PrintNode(); +if(lowersibling) + lowersibling->PrintNode(); +if(topchild) + topchild->PrintNode(); +if(bottomchild) + bottomchild->PrintNode(); +#endif + + if(layer->parent==NULL) + { + printf("ERROR: RemoveChild(): View doesn't have a parent\n"); + return; + } + if(layer->parent!=this) + { + printf("ERROR: RemoveChild(): View is not a child of this layer\n"); + return; + } + + if(hidecount==0 && layer->visible && layer->parent->visible) + { + BRegion *reg=new BRegion(ConvertToParent(visible)); + layer->parent->visible->Include(reg); + delete reg; + } + + // Take care of parent + layer->parent=NULL; + if(topchild==layer) + topchild=layer->lowersibling; + if(bottomchild==layer) + bottomchild=layer->uppersibling; + + // Take care of siblings + if(layer->uppersibling!=NULL) + layer->uppersibling->lowersibling=layer->lowersibling; + if(layer->lowersibling!=NULL) + layer->lowersibling->uppersibling=layer->uppersibling; + layer->SetLevel(0); + layer->uppersibling=NULL; + layer->lowersibling=NULL; + +#ifdef DEBUG_LAYERS +printf("After RemoveChild: \n"); +PrintNode(); +if(parent) + parent->PrintNode(); +if(uppersibling) + uppersibling->PrintNode(); +if(lowersibling) + lowersibling->PrintNode(); +if(topchild) + topchild->PrintNode(); +if(bottomchild) + bottomchild->PrintNode(); +#endif +} + +void Layer::RemoveSelf(void) +{ + // A Layer removes itself from the tree (duh) +#ifdef DEBUG_LAYERS + cout << "RemoveSelf " << name->String() << endl; +#endif + if(parent==NULL) + { + cout << "ERROR: RemoveSelf(): View doesn't have a parent\n" << flush; + return; + } + parent->RemoveChild(this); +} + +Layer *Layer::GetChildAt(BPoint pt, bool recursive=false) +{ + // Find out which child gets hit if we click at a certain spot. Returns NULL + // if there are no visible children or if the click does not hit a child layer + // If recursive==true, then it will continue to call until it reaches a layer + // which has no children, i.e. a layer that is at the top of its 'branch' in + // the layer tree + + Layer *child; + if(recursive) + { + for(child=bottomchild; child!=NULL; child=child->uppersibling) + { + if(child->bottomchild!=NULL) + child->GetChildAt(pt,true); + + if(child->hidecount>0) + continue; + + if(child->frame.Contains(pt)) + return child; + } + } + else + { + for(child=bottomchild; child!=NULL; child=child->uppersibling) + { + if(child->hidecount>0) + continue; +// if(child->visible && child->visible->Contains(ConvertFromTop(pt))) +// printf("child hit by mouse. News at 11\n"); + if(child->frame.Contains(pt)) + return child; + } + } + return NULL; +} + +BRect Layer::Bounds(void) +{ + return frame.OffsetToCopy(0,0); +} + +BRect Layer::Frame(void) +{ + return frame; +} + +void Layer::SetLevel(int32 value) +{ + // Sets hierarchy level of layer and all children +#ifdef DEBUG_LAYERS + printf("SetLevel %ld\n",value); +#endif + level=value; + + Layer *lay; + + lay=topchild; + + while(lay!=NULL) + { + if(lay->topchild!=NULL) + lay->topchild->SetLevel(value+1); + lay=lay->lowersibling; + } +} + +void Layer::PruneTree(void) +{ + // recursively deletes all children (and grandchildren, etc) of the passed layer + // This is mostly used for server shutdown or deleting a workspace +#ifdef DEBUG_LAYERS + printf("PruneTree() at level %ld\n", level); +#endif + Layer *lay,*nextlay; + + lay=topchild; + topchild=NULL; + + while(lay!=NULL) + { + if(lay->topchild!=NULL) + { +// lay->topchild->PruneTree(); + lay->PruneTree(); + } + nextlay=lay->lowersibling; + lay->lowersibling=NULL; + delete lay; + lay=nextlay; + } + // Man, this thing is short. Elegant, ain't it? :P +} + +Layer *Layer::FindLayer(int32 token) +{ + // recursive search for a layer based on its view token + Layer *lay, *trylay; + + // Search child layers first + for(lay=topchild; lay!=NULL; lay=lay->lowersibling) + { + if(lay->view_token==token) + return lay; + } + + // Hmmm... not in this layer's children. Try lower descendants + for(lay=topchild; lay!=NULL; lay=lay->lowersibling) + { + trylay=lay->FindLayer(token); + if(trylay) + return trylay; + } + + // Well, we got this far in the function, so apparently there is no match to be found + return NULL; +} + +// Tested +void Layer::Invalidate(BRegion region) +{ + int32 i; + BRect r; + + // See if the region intersects with our current area + if(region.Intersects(Bounds()) && hidecount==0) + { + BRegion clippedreg(region); + clippedreg.IntersectWith(visible); + if(clippedreg.CountRects()>0) + { + is_dirty=true; + if(invalid) + invalid->Include(&clippedreg); + else + invalid=new BRegion(clippedreg); + } + } + + BRegion *reg; + for(Layer *lay=topchild;lay!=NULL; lay=lay->lowersibling) + { + if(lay->hidecount==0) + { + reg=new BRegion(lay->ConvertFromParent(®ion)); + + for(i=0;iCountRects();i++) + { + r=reg->RectAt(i); + if(frame.Intersects(r)) + lay->Invalidate(r); + } + + delete reg; + } + } +} + +// Tested +void Layer::Invalidate(BRect rect) +{ + // Make our own section dirty and pass it on to any children, if necessary.... + // YES, WE ARE SHARING DIRT! Mudpies anyone? :D + + if(Frame().Intersects(rect)) + { + + // Clip the rectangle to the visible region of the layer + if(visible->Intersects(rect)) + { + BRegion reg(rect); + reg.IntersectWith(visible); + if(reg.CountRects()>0) + { + is_dirty=true; + if(invalid) + invalid->Include(®); + else + invalid=new BRegion(reg); + } + } + } + for(Layer *lay=topchild;lay!=NULL; lay=lay->lowersibling) + lay->Invalidate(lay->ConvertFromParent(rect)); +} + +void Layer::RequestDraw(void) +{ + if(visible==NULL || hidecount>0) + return; + + if(serverwin) + { + if(invalid==NULL) + invalid=new BRegion(*visible); + serverwin->RequestDraw(invalid->Frame()); + delete invalid; + invalid=NULL; + } + + is_dirty=false; + for(Layer *lay=topchild; lay!=NULL; lay=lay->lowersibling) + { + if(lay->IsDirty()) + lay->RequestDraw(); + } + +} + +bool Layer::IsDirty(void) const +{ +// return is_dirty; + return (!invalid)?true:false; +} + +void Layer::ShowLayer(void) +{ + if(hidecount==0) + return; + + hidecount--; + if(hidecount==0) + { + BRegion *reg=new BRegion(ConvertToParent(visible)); + parent->visible->Exclude(reg); + delete reg; + is_dirty=true; + } + + Layer *child; + for(child=topchild; child!=NULL; child=child->lowersibling) + child->ShowLayer(); +} + +void Layer::HideLayer(void) +{ + if(hidecount==0) + { + BRegion *reg=new BRegion(ConvertToParent(visible)); + parent->visible->Include(reg); + delete reg; + parent->is_dirty=true; + is_dirty=true; + } + hidecount++; + + Layer *child; + for(child=topchild; child!=NULL; child=child->lowersibling) + child->HideLayer(); +} + +// Tested +uint32 Layer::CountChildren(void) +{ + uint32 i=0; + Layer *lay=topchild; + while(lay!=NULL) + { + lay=lay->lowersibling; + i++; + } + return i; +} + +void Layer::MoveBy(float x, float y) +{ + BRect oldframe(frame); + frame.OffsetBy(x,y); + + if(parent) + { + if(parent->invalid==NULL) + parent->invalid=new BRegion(oldframe); + else + parent->invalid->Include(oldframe); + } + +// for(Layer *lay=topchild; lay!=NULL; lay=lay->lowersibling) +// lay->MoveBy(x,y); + Invalidate(Frame()); +} + +void Layer::ResizeBy(float x, float y) +{ + BRect oldframe=frame; + frame.right+=x; + frame.bottom+=y; + + if(parent) + parent->RebuildRegions(); + else + RebuildRegions(); + +// for(Layer *lay=topchild; lay!=NULL; lay=lay->lowersibling) +// lay->ResizeBy(x,y); + if(x<0 || y<0) + parent->Invalidate(oldframe); + Invalidate(Bounds()); +} + +void Layer::RebuildRegions(bool include_children=true) +{ + if(full) + full->Include(Bounds()); + else + full=new BRegion(Bounds()); + + if(visible) + visible->Include(Bounds()); + else + visible=new BRegion(Bounds()); + + // Remove child footprints from visible region here + + if(include_children) + { + for(Layer *lay=topchild; lay!=NULL; lay=lay->lowersibling) + { + if(lay->topchild) + lay->RebuildRegions(true); + } + } +} + +void Layer::PrintToStream(void) +{ + printf("-----------\nLayer %s\n",name->String()); + if(parent) + printf("Parent: %s (%p)\n",parent->name->String(), parent); + else + printf("Parent: NULL\n"); + if(uppersibling) + printf("Upper sibling: %s (%p)\n",uppersibling->name->String(), uppersibling); + else + printf("Upper sibling: NULL\n"); + if(lowersibling) + printf("Lower sibling: %s (%p)\n",lowersibling->name->String(), lowersibling); + else + printf("Lower sibling: NULL\n"); + if(topchild) + printf("Top child: %s (%p)\n",topchild->name->String(), topchild); + else + printf("Top child: NULL\n"); + if(bottomchild) + printf("Bottom child: %s (%p)\n",bottomchild->name->String(), bottomchild); + else + printf("Bottom child: NULL\n"); + printf("Frame: "); frame.PrintToStream(); + printf("Token: %ld\nLevel: %ld\n",view_token, level); + printf("Hide count: %u\n",hidecount); + if(invalid) + { + printf("Invalid Areas: "); invalid->PrintToStream(); + } + else + printf("Invalid Areas: NULL\n"); + if(visible) + { + printf("Visible Areas: "); visible->PrintToStream(); + } + else + printf("Visible Areas: NULL\n"); + printf("Is updating = %s\n",(is_updating)?"yes":"no"); +} + +void Layer::PrintNode(void) +{ + printf("-----------\nLayer %s\n",name->String()); + if(parent) + printf("Parent: %s (%p)\n",parent->name->String(), parent); + else + printf("Parent: NULL\n"); + if(uppersibling) + printf("Upper sibling: %s (%p)\n",uppersibling->name->String(), uppersibling); + else + printf("Upper sibling: NULL\n"); + if(lowersibling) + printf("Lower sibling: %s (%p)\n",lowersibling->name->String(), lowersibling); + else + printf("Lower sibling: NULL\n"); + if(topchild) + printf("Top child: %s (%p)\n",topchild->name->String(), topchild); + else + printf("Top child: NULL\n"); + if(bottomchild) + printf("Bottom child: %s (%p)\n",bottomchild->name->String(), bottomchild); + else + printf("Bottom child: NULL\n"); +} + +// Tested +BRect Layer::ConvertToParent(BRect rect) +{ + return (rect.OffsetByCopy(frame.LeftTop())); +} + +// Tested +BPoint Layer::ConvertToParent(BPoint point) +{ + float x=point.x + frame.left, + y=point.y+frame.top; + return (BPoint(x,y)); +} + +// Tested +BRegion Layer::ConvertToParent(BRegion *reg) +{ + BRegion newreg; + for(int32 i=0; iCountRects();i++) + newreg.Include(ConvertToParent(reg->RectAt(i))); + return BRegion(newreg); +} + +// Tested +BRect Layer::ConvertFromParent(BRect rect) +{ + return (rect.OffsetByCopy(frame.left*-1,frame.top*-1)); +} + +// Tested +BPoint Layer::ConvertFromParent(BPoint point) +{ + return ( point-frame.LeftTop()); +} + +// Tested +BRegion Layer::ConvertFromParent(BRegion *reg) +{ + BRegion newreg; + for(int32 i=0; iCountRects();i++) + newreg.Include(ConvertFromParent(reg->RectAt(i))); + return BRegion(newreg); +} + +// Tested +BRegion Layer::ConvertToTop(BRegion *reg) +{ + BRegion newreg; + for(int32 i=0; iCountRects();i++) + newreg.Include(ConvertToTop(reg->RectAt(i))); + return BRegion(newreg); +} + +// Tested +BRect Layer::ConvertToTop(BRect rect) +{ + if (parent!=NULL) + return(parent->ConvertToTop(rect.OffsetByCopy(frame.LeftTop())) ); + else + return(rect); +} + +// Tested +BPoint Layer::ConvertToTop(BPoint point) +{ + if (parent!=NULL) + return(parent->ConvertToTop(point + frame.LeftTop()) ); + else + return(point); +} + +// Tested +BRegion Layer::ConvertFromTop(BRegion *reg) +{ + BRegion newreg; + for(int32 i=0; iCountRects();i++) + newreg.Include(ConvertFromTop(reg->RectAt(i))); + return BRegion(newreg); +} + +// Tested +BRect Layer::ConvertFromTop(BRect rect) +{ + if (parent!=NULL) + return(parent->ConvertFromTop(rect.OffsetByCopy(frame.LeftTop().x*-1, + frame.LeftTop().y*-1)) ); + else + return(rect); +} + +// Tested +BPoint Layer::ConvertFromTop(BPoint point) +{ + if (parent!=NULL) + return(parent->ConvertFromTop(point - frame.LeftTop()) ); + else + return(point); +} + +RootLayer::RootLayer(BRect rect, const char *layername, ServerWindow *srvwin, + int32 viewflags, int32 token) + : Layer(rect,layername,srvwin,viewflags,token) +{ + updater_id=-1; +} + +RootLayer::RootLayer(BRect rect, const char *layername) + : Layer(rect,layername) +{ + updater_id=-1; + driver=get_gfxdriver(); +} + +RootLayer::~RootLayer(void) +{ +} + +void RootLayer::SetVisible(bool fVisible) +{ + if(is_visible!=fVisible) + { + is_visible=fVisible; +/* if(visible) + { + updater_id=spawn_thread(UpdaterThread,name->String(),B_NORMAL_PRIORITY,this); + if(updater_id!=B_NO_MORE_THREADS && updater_id!=B_NO_MEMORY) + resume_thread(updater_id); + } +*/ + } +} + +bool RootLayer::IsVisible(void) const +{ + return is_visible; +} + +int32 RootLayer::UpdaterThread(void *data) +{ + // Updater thread which checks to see if its layer needs updating. If so, then + // call the recursive function RequestDraw. + + RootLayer *root=(RootLayer*)data; + + while(1) + { + if(!root->is_visible) + { + return 0; + exit_thread(1); + } + + if(root->IsDirty()) + { + layerlock->Lock(); + root->RequestDraw(); + layerlock->Unlock(); + } + } +} + +void RootLayer::RequestDraw(void) +{ + if(!invalid) + return; + + ASSERT(driver!=NULL); + +#ifdef DEBUG_LAYERS +printf("Root::RequestDraw: invalid rects: %ld\n",invalid->CountRects()); +#endif + + // Redraw the base + for(int32 i=0; invalid->CountRects();i++) + { + if(invalid->RectAt(i).IsValid()) + { +#ifdef DEBUG_LAYERS +printf("Root::RequestDraw:FillRect, color %u,%u,%u,%u\n",bgcolor.red,bgcolor.green, + bgcolor.blue,bgcolor.alpha); +#endif + driver->FillRect(invalid->RectAt(i),bgcolor); + } + else + break; + } + + delete invalid; + invalid=NULL; + is_dirty=false; + + // force redraw of all dirty windows + for(Layer *lay=topchild; lay!=NULL; lay=lay->lowersibling) + { + if(lay->IsDirty()) + lay->RequestDraw(); + } + +} + +void RootLayer::SetColor(rgb_color col) +{ + bgcolor=col; +#ifdef DEBUG_LAYERS +printf("Root::SetColor(%u,%u,%u,%u)\n",bgcolor.red,bgcolor.green, + bgcolor.blue,bgcolor.alpha); +#endif +} + +rgb_color RootLayer::GetColor(void) const +{ + return bgcolor; +} diff --git a/src/servers/app/proto6/Layer.h b/src/servers/app/proto6/Layer.h new file mode 100644 index 0000000000..b11dabfd2b --- /dev/null +++ b/src/servers/app/proto6/Layer.h @@ -0,0 +1,108 @@ +#ifndef _LAYER_H_ +#define _LAYER_H_ + +#include +#include +#include +#include +#include +#include + +class ServerWindow; +class UpdateNode; +class DisplayDriver; + +class Layer +{ +public: + Layer(BRect rect, const char *layername, ServerWindow *srvwin, + int32 viewflags, int32 token); + Layer(BRect rect, const char *layername); + virtual ~Layer(void); + + void ShowLayer(void); + void HideLayer(void); + Layer *FindLayer(int32 token); + void MoveLayer(BPoint delta, bool include_children=true); + void AddChild(Layer *child); + void RemoveChild(Layer *child); + void RemoveSelf(void); + uint32 CountChildren(void); + Layer *GetChildAt(BPoint pt, bool recursive=false); + BRect Bounds(void); + BRect Frame(void); + + void MoveBy(float x, float y); + void ResizeBy(float x, float y); + + void RebuildRegions(bool include_children=true); + bool IsDirty(void) const; + void PrintToStream(void); + void PrintNode(void); + void PruneTree(void); + void SetLevel(int32 value); + void Invalidate(BRect rect); + void Invalidate(BRegion region); + virtual void RequestDraw(void); + + BRect ConvertToParent(BRect rect); + BPoint ConvertToParent(BPoint point); + BRegion ConvertToParent(BRegion *reg); + BRect ConvertFromParent(BRect rect); + BPoint ConvertFromParent(BPoint point); + BRegion ConvertFromParent(BRegion *reg); + BRegion ConvertToTop(BRegion *reg); + BRect ConvertToTop(BRect rect); + BPoint ConvertToTop(BPoint point); + BRegion ConvertFromTop(BRegion *reg); + BRect ConvertFromTop(BRect rect); + BPoint ConvertFromTop(BPoint point); + + BRect frame; + + Layer *parent, + *uppersibling, + *lowersibling, + *topchild, + *bottomchild; + + BRegion *visible, + *invalid; + + ServerWindow *serverwin; + + BString *name; + int32 view_token; // identifier for the corresponding view + int32 level; // how far layer is from root + int32 flags; // view flags + uint8 hidecount; + bool is_dirty; // true if we need to redraw + bool is_updating; +}; + +class RootLayer : public Layer +{ +public: + RootLayer(BRect rect, const char *layername, ServerWindow *srvwin, + int32 viewflags, int32 token); + RootLayer(BRect rect, const char *layername); + ~RootLayer(void); + virtual void RequestDraw(void); + void SetVisible(bool is_visible); + bool IsVisible(void) const; + + void SetColor(rgb_color col); + rgb_color GetColor(void) const; + + static int32 UpdaterThread(void *data); + rgb_color bgcolor; +private: + thread_id updater_id; + bool visible; + DisplayDriver *driver; +}; + +extern BLocker *layerlock; +extern BList *layerlist; +extern Layer *rootlayer; +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/PortLink.cpp b/src/servers/app/proto6/PortLink.cpp new file mode 100644 index 0000000000..8fba724569 --- /dev/null +++ b/src/servers/app/proto6/PortLink.cpp @@ -0,0 +1,438 @@ +/* + PortLink.cpp: + A helper class for port-based messaging + +------------------------------------------------------------------------ +How it works: + The class utilizes a fixed-size array of PortLinkData object pointers. When +data is attached, a new PortLinkData object is allocated and a copy of the +passed data is created inside it. When the time comes for the message to be sent, +the data is pieced together into a flattened array and written to the port. +------------------------------------------------------------------------ +Data members: + +*attachments[] - fixed-size array of pointers used to hold the attached data +opcode - message value which is sent along with any data +target - port to which the message is sent when Flush() is called +replyport - port used with synchronous messaging - FlushWithReply() +bufferlength - total bytes taken up by attachments +num_attachments - internal variable which is used to track which "slot" + will be the next one to receive an attachment object +*/ + +#include "PortLink.h" +#include +#include +#include + +//#define PLDEBUG + +// Internal data storage class for holding attached data whilst it is waiting +// to be Flattened() and then Flushed(). There is no need for this to be called outside +// the PortLink class. +class PortLinkData +{ +public: + PortLinkData(void); + ~PortLinkData(void); + bool Set(void *data, size_t size); + char *buffer; + size_t buffersize; +}; + +PortLink::PortLink(port_id port) +{ + // For this class to be useful (and to prevent a lot of init problems) + // we require a port in the constructor + target=port; + + // We start out without any data attached to the port message + num_attachments=0; + opcode=0; + bufferlength=0; + replyport=create_port(30,"PortLink reply port"); +} + +PortLink::~PortLink(void) +{ + // If, for some odd reason, this is deleted with something attached, + // free the memory used by the attachments. We do not flush the queue + // because the port may no longer be valid in cases such as the app + // is in the process of quitting + MakeEmpty(); +} + +void PortLink::SetOpCode(int32 code) +{ + // Sets the message code. This does not change once the message is sent. + // Another call to SetOpCode() is required for such things. + opcode=code; +} + +void PortLink::SetPort(port_id port) +{ + // Sets the target port. While not necessary in most uses, this exists + // mostly to prevent flexibility problems + target=port; +} + +port_id PortLink::GetPort(void) +{ + // Simply returns the port at which the object is pointed. + return target; +} + +void PortLink::Flush(bigtime_t timeout=B_INFINITE_TIMEOUT) +{ + // Fires a message off to the target, complete with attachments. NOTE: + // the recipient must delete all attachments, being the PortLink object assumes + // no responsiblity for the attachments once the message is sent. + int8 *msgbuffer; + int32 size; + + if(num_attachments>0) + { + FlattenData(&msgbuffer,&size); + + // Dump message to port, reset attachments, and clean up + if(timeout!=B_INFINITE_TIMEOUT) + write_port_etc(target,opcode,msgbuffer,size,B_TIMEOUT, timeout); + else + write_port(target,opcode,msgbuffer,size); + MakeEmpty(); + } + else + { + if(timeout!=B_INFINITE_TIMEOUT) + write_port_etc(target,opcode,NULL,0,B_TIMEOUT, timeout); + else + write_port(target,opcode,NULL,0); + } +} + +int8* PortLink::FlushWithReply(int32 *code, status_t *status, ssize_t *buffersize, bigtime_t timeout=B_INFINITE_TIMEOUT) +{ + // Fires a message to the target and then waits for a reply. The target will + // receive a message with the first item being the port_id to reply to. + // NOTE: like Flush(), any attached data must be deleted. + + // Effectively, an Attach() call inlined for changes + + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + { + *status=B_ERROR; + return NULL; + } + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&replyport,sizeof(port_id))) + { + bufferlength+=sizeof(port_id); + } + else + { + delete pld; + *status=B_ERROR; + return NULL; + } + + // Flatten() inlined to make some necessary changes + int8 *buffer=new int8[bufferlength]; + int8 *bufferindex=buffer; + size_t size=0; + + // attach our port_id first + memcpy(bufferindex, pld->buffer, pld->buffersize); + bufferindex += pld->buffersize; + size+=pld->buffersize; + + // attach everything else + for(int i=0;ibuffer, pld->buffersize); + bufferindex += pld->buffersize; + size+=pld->buffersize; + } + + // Flush the thing....FOOSH! :P + write_port(target,opcode,buffer,size); + MakeEmpty(); + delete buffer; + + // Now we wait for the reply + if(timeout==B_INFINITE_TIMEOUT) + { + *buffersize=port_buffer_size(replyport); + if(*buffersize>0) + buffer=(int8*)new int8[*buffersize]; + read_port(replyport,code, buffer, *buffersize); + } + else + { + *buffersize=port_buffer_size_etc(replyport,0,timeout); + if(*buffersize==B_TIMED_OUT) + { + *status=*buffersize; + return NULL; + } + if(*buffersize>0) + buffer=(int8*)new int8[*buffersize]; + read_port(replyport,code, buffer, *buffersize); + } + + // We got this far, so we apparently have some data + *status=B_OK; + return buffer; +} + +void PortLink::Attach(void *data, size_t size) +{ + // This is the member called to attach data to a message. Attachments are + // treated to be in 'Append' mode, tacking on each attached piece of data + // to the end of the list. + + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + if(size==0) + return; + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +// These functions were added for a major convenience in passing common types +// Eventually, I'd like to templatize these, but for now, this'll do + +void PortLink::Attach(int32 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int32); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(int16 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int16); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(int8 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int8); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(float data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(float); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(bool data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(bool); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(BRect data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(BRect); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(BPoint data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(BPoint); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::FlattenData(int8 **buffer,int32 *size) +{ + // This function is where all the magic happens, but it is strictly internal. + // It iterates through each PortLinkData object and copies it to the main buffer + // which ends up, ultimately, being written to the PortLink's target port. + + // skip if there aree no attachments + if(bufferlength<1) + return; + + *buffer=new int8[bufferlength]; + int8 *bufferindex=*buffer; + PortLinkData *pld; + *size=0; + + for(int i=0;ibuffer, pld->buffersize); + bufferindex += pld->buffersize; + *size+=pld->buffersize; + } +} + +void PortLink::MakeEmpty(void) +{ + // Nukes all the attachments currently held by the PortLink class + if(num_attachments!=0) + { + for(int i=0; i0) + free(buffer); +} + +bool PortLinkData::Set(void *data, size_t size) +{ + // Function copies the passed to the internal buffers for storage + if(size>0 && buffersize==0 && data!=NULL) + { + buffer=(char *)malloc(size); + if(buffer==NULL) + return false; + memcpy(buffer, data, size); + buffersize=size; + return true; + } + return false; +} diff --git a/src/servers/app/proto6/PortLink.h b/src/servers/app/proto6/PortLink.h new file mode 100644 index 0000000000..9f5432daab --- /dev/null +++ b/src/servers/app/proto6/PortLink.h @@ -0,0 +1,43 @@ +#ifndef _PORTLINK_H_ +#define _PORTLINK_H_ + +#include +#include +#include +#include + +#ifndef _PORTLINK_BUFFERSIZE +#define _PORTLINK_MAX_ATTACHMENTS 50 +#endif + +class PortLinkData; + +class PortLink +{ +public: + PortLink(port_id port); + ~PortLink(void); + void SetOpCode(int32 code); + void SetPort(port_id port); + port_id GetPort(void); + void Flush(bigtime_t timeout=B_INFINITE_TIMEOUT); + int8* FlushWithReply(int32 *code, status_t *status, ssize_t *buffersize, + bigtime_t timeout=B_INFINITE_TIMEOUT); + void Attach(void *data, size_t size); + void Attach(int32 data); + void Attach(int16 data); + void Attach(int8 data); + void Attach(float data); + void Attach(bool data); + void Attach(BRect data); + void Attach(BPoint data); + void MakeEmpty(void); +protected: + void FlattenData(int8 **buffer,int32 *size); + port_id target, replyport; + int32 opcode, bufferlength; + int num_attachments; + PortLinkData *attachments[_PORTLINK_MAX_ATTACHMENTS]; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/ScreenDriver.cpp b/src/servers/app/proto6/ScreenDriver.cpp new file mode 100644 index 0000000000..1928324e9a --- /dev/null +++ b/src/servers/app/proto6/ScreenDriver.cpp @@ -0,0 +1,915 @@ +/* + ScreenDriver.cpp + Replacement class for the ViewDriver which utilizes a BWindowScreen for ease + of testing without requiring a second video card for SecondDriver and also + without the limitations (mostly speed) of ViewDriver. + + Note that unlike ViewDriver, this graphics module does NOT emulate + the Input Server. The Router input server filter is required for use. + + The concept is pretty close to the retooled ViewDriver, where each module + call locks a couple BLockers and draws to the buffer. + + Components: + ScreenDriver: actual driver module + FrameBuffer: BWindowScreen derivative which provides the module access + to the video card + Internal functions for doing graphics on the buffer + + Done: + Basic module init and shutdown + Clear() - 8-bit and 32-bit + SetPixel32 + StrokeLine(pt,pt,rgb_color) + StrokeRect - both forms + FillRect - both forms, but not using fastest methods + ToDo: + 16-Bit mode functions + StrokeLine(pt,pattern) needs to utilize patterns + FillRect(rect,pattern) needs to utilize patterns + Implement a lot of functions +*/ +#include "ScreenDriver.h" +#include "ServerCursor.h" +#include "ServerProtocol.h" +#include "ServerBitmap.h" +#include "SystemPalette.h" +#include "ColorUtils.h" +#include "PortLink.h" +#include "DebugTools.h" +#include +#include +#include +#include + +#define DEBUG_DRIVER + +// Define this if you want to use the spacebar to launch the server prototype's +// test application +#define LAUNCH_TESTAPP + +#ifdef LAUNCH_TESTAPP +#include +#include +#endif + +// functions internal to the driver +void Clear_32Bit(void *buffer, int width, int height, rgb_color col); +void Clear_16Bit(void *buffer, int width, int height, uint16 col); +void Clear_8Bit(void *buffer, int width, int height, uint8 col); + +void HLine_32Bit(graphics_card_info i, uint16 x, uint16 y, uint16 length, rgb_color col); +void HLine_16Bit(graphics_card_info i, uint16 x, uint16 y, uint16 length, uint16 col); +void HLine_16Bit(graphics_card_info i, uint16 x, uint16 y, uint16 length, uint8 col); + +FrameBuffer::FrameBuffer(const char *title, uint32 space, status_t *st,bool debug) + : BWindowScreen(title,space,st,debug) +{ + is_connected=false; +} + +FrameBuffer::~FrameBuffer(void) +{ +} + +void FrameBuffer::ScreenConnected(bool connected) +{ + is_connected=connected; + if(connected) + { + // Cache the state just in case + graphics_card_info *info=CardInfo(); + gcinfo=*info; + } +} + +void FrameBuffer::MessageReceived(BMessage *msg) +{ + switch(msg->what) + { + case B_KEY_DOWN: + { + int32 key; + msg->FindInt32("key",&key); + if(key==0x47) // Enter key + { + port_id serverport=find_port(SERVER_PORT_NAME); + write_port(serverport,B_QUIT_REQUESTED,NULL,0); + break; + } + #ifdef LAUNCH_TESTAPP + if(key==0x5e) + { + printf("Launching test app\n"); + status_t value; + BEntry entry("/boot/home/Desktop/openbeos/proto6/OBApplication/OBApplication"); + entry_ref ref; + entry.GetRef(&ref); + value=be_roster->Launch(&ref); + + BString str=TranslateStatusToString(value); + printf("Launch return code: %s",str.String()); + printf("\n"); + } + #endif + } + default: + BWindowScreen::MessageReceived(msg); + } +} + +bool FrameBuffer::QuitRequested(void) +{ + port_id serverport=find_port(SERVER_PORT_NAME); + + if(serverport!=B_NAME_NOT_FOUND) + write_port(serverport,B_QUIT_REQUESTED,NULL,0); + + return true; +} + +ScreenDriver::ScreenDriver(void) +{ + status_t st; + fbuffer=new FrameBuffer("OBAppServer",B_8_BIT_640x480,&st,true); + + drawmode=DRAW_COPY; + // Create our cursor here + cursor=new ServerBitmap(BRect(0,0,16,16),B_CMAP8); +} + +ScreenDriver::~ScreenDriver(void) +{ + delete cursor; +} + +void ScreenDriver::Initialize(void) +{ + fbuffer->Show(); + + // draw on the module's default cursor here to make it look preety + + // wait 1 sec for the window to show... + snooze(500000); +} + +void ScreenDriver::Shutdown(void) +{ + fbuffer->Lock(); + fbuffer->Quit(); +} + +void ScreenDriver::Clear(uint8 red,uint8 green,uint8 blue) +{ + locker->Lock(); + rgb_color c; + SetRGBColor(&c,red,green,blue); + Clear(c); + locker->Unlock(); +} + +void ScreenDriver::Clear(rgb_color col) +{ + locker->Lock(); +#ifdef DEBUG_DRIVER +printf("ScreenDriver::Clear(%u,%u,%u)\n",col.red,col.green,col.blue); +#endif + if(fbuffer->IsConnected()) + { + switch(fbuffer->gcinfo.bits_per_pixel) + { + case 32: + case 24: + { +printf("Clear: 32/24-bit\n"); + Clear_32Bit(fbuffer->gcinfo.frame_buffer, + fbuffer->gcinfo.width,fbuffer->gcinfo.height,col); + break; + } + case 16: + case 15: + { +printf("Clear: 16/15-bit unimplemented\n"); + // Look up color here +// uint16 c; +// Clear_16Bit(gcinfo.frame_buffer,gcinfo.width,gcinfo.height,c); + break; + } + case 8: + { +printf("Clear: 8-bit\n"); + // Look up color here + uint8 c=FindClosestColor(fbuffer->ColorList(),col); + + Clear_8Bit(fbuffer->gcinfo.frame_buffer, + fbuffer->gcinfo.width,fbuffer->gcinfo.height, c); + break; + } + default: + { +#ifdef DEBUG_DRIVER +printf("Clear: unknown bit depth %u\n",fbuffer->gcinfo.bits_per_pixel); +#endif + break; + } + } + } + else + { +#ifdef DEBUG_DRIVER +printf("Clear: driver is disconnected\n"); +#endif + } + locker->Unlock(); +} + +void ScreenDriver::DrawBitmap(ServerBitmap *bitmap, BRect source, BRect dest) +{ + locker->Lock(); +#ifdef DEBUG_DRIVER +printf("ScreenDriver::DrawBitmap(*, (%f,%f,%f,%f),(%f,%f,%f,%f) )\n", + source.left,source.top,source.right,source.bottom, + dest.left,dest.top,dest.right,dest.bottom); +#endif + if(fbuffer->IsConnected()) + { + // Scale bitmap here if source!=dest + + switch(fbuffer->gcinfo.bits_per_pixel) + { + case 32: + case 24: + { + printf("DrawBitmap: 32/24-bit unimplemented\n"); + break; + } + case 16: + case 15: + { + printf("DrawBitmap: 16/15-bit unimplemented\n"); + break; + } + case 8: + { + printf("DrawBitmap: 8-bit unimplemented\n"); + break; + } + default: + { +#ifdef DEBUG_DRIVER +printf("Clear: unknown bit depth %u\n",fbuffer->gcinfo.bits_per_pixel); +#endif + break; + } + } + } + + locker->Unlock(); +} + +void ScreenDriver::FillRect(BRect rect, uint8 *pattern) +{ + locker->Lock(); + + FillRect(rect,highcol); + + locker->Unlock(); +} + +void ScreenDriver::FillRect(BRect rect, rgb_color col) +{ +#ifdef DEBUG_DRIVER +printf("ScreenDriver::FillRect( (%f,%f,%f,%f), {%u,%u,%u,%u}\n",rect.left,rect.top, + rect.right,rect.bottom,col.red,col.green,col.blue,col.alpha); +#endif + locker->Lock(); + if(fbuffer->IsConnected()) + { + // int32 width=rect.IntegerWidth(); + for(int32 i=(int32)rect.top;i<=rect.bottom;i++) + // HLine(fbuffer->gcinfo,(int32)rect.left,i,width,col); + StrokeLine(BPoint(rect.left,i),BPoint(rect.right,i),col); + } + locker->Unlock(); +} + +void ScreenDriver::FillRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern) +{ +#ifdef DEBUG_DRIVER +printf("ScreenDriver::FillRoundRect( (%f,%f,%f,%f), %llx) ---->Unimplemented<----\n",rect.left,rect.top, + rect.right,rect.bottom,*((uint64*)pattern)); +#endif + FillRect(rect,pattern); +} + +void ScreenDriver::FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern) +{ +#ifdef DEBUG_DRIVER +printf("ScreenDriver::FillTriangle(%llx): --->Currently Unimplemented<---\n",*((uint64*)pattern)); +printf("\tFirst: (%f,%f)\n\tSecond: (%f,%f)\n\tThird: (%f,%f)\n",first.x,first.y, + second.x,second.y,third.x,third.y); +rect.PrintToStream(); +#endif + locker->Lock(); + if(fbuffer->IsConnected()) + { + BPoint oldpos=penpos; + MovePenTo(first); StrokeLine(second,pattern); + MovePenTo(second); StrokeLine(third,pattern); + MovePenTo(third); StrokeLine(first,pattern); + penpos=oldpos; + } + locker->Unlock(); +} + +void ScreenDriver::FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, rgb_color col) +{ +#ifdef DEBUG_DRIVER +printf("ScreenDriver::FillTriangle({%u,%u,%u,%u}): --->Currently Unimplemented<---\n", + col.red,col.green,col.blue,col.alpha); +printf("\tFirst: (%f,%f)\n\tSecond: (%f,%f)\n\tThird: (%f,%f)\n",first.x,first.y, + second.x,second.y,third.x,third.y); +rect.PrintToStream(); +#endif + locker->Lock(); + if(fbuffer->IsConnected()) + { + StrokeLine(first,second,col); + StrokeLine(first,third,col); + StrokeLine(third,second,col); + } + locker->Unlock(); +} + +void ScreenDriver::SetHighColor(uint8 r,uint8 g,uint8 b,uint8 a=255) +{ + rgb_color col={r,g,b,a}; + SetHighColor(col); +} + +void ScreenDriver::SetHighColor(rgb_color col) +{ + highcol=col; + + switch(fbuffer->gcinfo.bits_per_pixel) + { + case 16: + case 15: + high16=FindClosestColor16(highcol); + break; + case 8: + high8=FindClosestColor(system_palette,highcol); + break; + default: + break; + } +} + +void ScreenDriver::SetLowColor(uint8 r,uint8 g,uint8 b,uint8 a=255) +{ + rgb_color col={r,g,b,a}; + SetLowColor(col); +} + +void ScreenDriver::SetLowColor(rgb_color col) +{ + lowcol=col; + + switch(fbuffer->gcinfo.bits_per_pixel) + { + case 16: + case 15: + low16=FindClosestColor16(highcol); + break; + case 8: + low8=FindClosestColor(system_palette,highcol); + break; + default: + break; + } +} + +void ScreenDriver::SetPixel(int x, int y, uint8 *pattern) +{ + switch(fbuffer->gcinfo.bits_per_pixel) + { + case 32: + case 24: + SetPixel32(x,y,highcol); + break; + case 16: + case 15: + SetPixel16(x,y,FindClosestColor16(highcol)); + break; + default: + printf("SetPixel8 Unimplemented\n"); +// SetPixel8(x,y,FindClosestColor(highcol)); + break; + } + +} + +void ScreenDriver::SetPixel32(int x, int y, rgb_color col) +{ + // Code courtesy of YNOP's SecondDriver + union + { + uint8 bytes[4]; + uint32 word; + }c1; + + c1.bytes[0]=col.blue; + c1.bytes[1]=col.green; + c1.bytes[2]=col.red; + c1.bytes[3]=col.alpha; + + uint32 *bits=(uint32*)fbuffer->gcinfo.frame_buffer; + *(bits + x + (y*fbuffer->gcinfo.width))=c1.word; +} + +void ScreenDriver::SetPixel16(int x, int y, uint16 col) +{ +#ifdef DEBUG_DRIVER +printf("SetPixel16 unimplemented\n"); +#endif +} + +void ScreenDriver::SetPixel8(int x, int y, uint8 col) +{ + // When the DisplayDriver API changes, we'll use the uint8 highcolor. Until then, + // we'll use *pattern + uint8 *bits=(uint8*)fbuffer->gcinfo.frame_buffer; + *(bits + x + (y*fbuffer->gcinfo.bytes_per_row))=col; +} + +void ScreenDriver::SetScreen(uint32 space) +{ +#ifdef DEBUG_DRIVER +printf("ScreenDriver::SetScreen(%lu}\n",space); +#endif + locker->Lock(); + if(fbuffer->IsConnected()) + { + fbuffer->SetSpace(space); + + // We have changed the frame buffer info, so update the cached info + graphics_card_info *info=fbuffer->CardInfo(); + fbuffer->gcinfo=*info; + } + locker->Unlock(); +} + +void ScreenDriver::StrokeLine(BPoint point, uint8 *pattern) +{ +#ifdef DEBUG_DRIVER +printf("ScreenDriver::StrokeLine( (%f,%f), %llx}\n",point.x,point.y,*((uint64*)pattern)); +#endif + locker->Lock(); + if(fbuffer->IsConnected()) + { + // Courtesy YNOP's SecondDriver with minor changes by DW + int oct=0; + int xoff=(int32)penpos.x; + int yoff=(int32)penpos.y; + int32 x2=(int32)point.x-xoff; + int32 y2=(int32)point.y-yoff; + int32 x1=0; + int32 y1=0; + if(y2<0){ y2=-y2; oct+=4; }//bit2=1 + if(x2<0){ x2=-x2; oct+=2;}//bit1=1 + if(x2Unlock(); +} + +void ScreenDriver::StrokeLine(BPoint start, BPoint end, rgb_color col) +{ +#ifdef DEBUG_DRIVER +printf("ScreenDriver::StrokeLine( (%f,%f),(%f,%f), {%u,%u,%u,%u}\n",start.x,start.y, + end.x,end.y,col.red,col.green,col.blue,col.alpha); +#endif + locker->Lock(); + if(fbuffer->IsConnected()) + { + // Courtesy YNOP's SecondDriver with minor changes by DW + rgb_color savecol=highcol; + SetHighColor(col.red,col.green,col.blue); + + int oct=0; + int xoff=(int32)start.x; + int yoff=(int32)start.y; + int32 x2=(int32)end.x-xoff; + int32 y2=(int32)end.y-yoff; + int32 x1=0; + int32 y1=0; + if(y2<0){ y2=-y2; oct+=4; }//bit2=1 + if(x2<0){ x2=-x2; oct+=2;}//bit1=1 + if(x2Unlock(); +} + +void ScreenDriver::StrokePolygon(int *x, int *y, int numpoints, bool is_closed) +{ +#ifdef DEBUG_DRIVER +printf("ScreenDriver::StrokePolygon( is_closed=%s)\n",(is_closed==true)?"true":"false"); +for(int debug=0;debugLock(); + if(fbuffer->IsConnected()) + { + for(int32 i=0; i<(numpoints-1); i++) + StrokeLine(BPoint(x[i],y[i]),BPoint(x[i+1],y[i+1]),highcol); + + if(is_closed) + StrokeLine(BPoint(x[numpoints-1],y[numpoints-1]),BPoint(x[0],y[0]),highcol); + } + locker->Unlock(); +} + +void ScreenDriver::StrokeRect(BRect rect,uint8 *pattern) +{ +#ifdef DEBUG_DRIVER +printf("ScreenDriver::StrokeRect( (%f,%f,%f,%f), %llx)\n",rect.left,rect.top, + rect.right,rect.bottom,*((uint64*)pattern)); +#endif + locker->Lock(); + if(fbuffer->IsConnected()) + { + BPoint oldpos=penpos; + + MovePenTo(rect.LeftTop()); StrokeLine(BPoint(rect.right,rect.top),pattern); + MovePenTo(BPoint(rect.right,rect.top)); StrokeLine(BPoint(rect.right,rect.bottom),pattern); + MovePenTo(BPoint(rect.right,rect.bottom)); StrokeLine(BPoint(rect.left,rect.bottom),pattern); + MovePenTo(BPoint(rect.left,rect.bottom)); StrokeLine(BPoint(rect.left,rect.top),pattern); + +// Line32(rect.LeftTop(),BPoint(rect.right,rect.top),pattern); +// Line32(BPoint(rect.right,rect.top),BPoint(rect.right,rect.bottom),pattern); +// Line32(BPoint(rect.right,rect.bottom),BPoint(rect.left,rect.bottom),pattern); +// Line32(BPoint(rect.left,rect.bottom),BPoint(rect.left,rect.top),pattern); + + penpos=oldpos; + } + locker->Unlock(); +} + +void ScreenDriver::StrokeRect(BRect rect,rgb_color col) +{ +#ifdef DEBUG_DRIVER +printf("ScreenDriver::StrokeRect( (%f,%f,%f,%f), {%u,%u,%u,%u}\n",rect.left,rect.top, + rect.right,rect.bottom,col.red,col.green,col.blue,col.alpha); +#endif + locker->Lock(); + if(fbuffer->IsConnected()) + { + StrokeLine(BPoint(rect.left,rect.top),BPoint(rect.right,rect.top),col); + StrokeLine(BPoint(rect.right,rect.top),BPoint(rect.right,rect.bottom),col); + StrokeLine(BPoint(rect.right,rect.bottom),BPoint(rect.left,rect.bottom),col); + StrokeLine(BPoint(rect.left,rect.bottom),BPoint(rect.left,rect.top),col); + } + locker->Unlock(); +} + +void ScreenDriver::StrokeRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern) +{ +#ifdef DEBUG_DRIVER +printf("ScreenDriver::StrokeRoundRect( (%f,%f,%f,%f), %llx) ---->Unimplemented<----\n",rect.left,rect.top, + rect.right,rect.bottom,*((uint64*)pattern)); +#endif + StrokeRect(rect,pattern); +} + +void ScreenDriver::StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern) +{ +#ifdef DEBUG_DRIVER +printf("ScreenDriver::StrokeTriangle(%llx):\n",*((uint64*)pattern)); +printf("\tFirst: (%f,%f)\n\tSecond: (%f,%f)\n\tThird: (%f,%f)\n",first.x,first.y, + second.x,second.y,third.x,third.y); +rect.PrintToStream(); +#endif + locker->Lock(); + if(fbuffer->IsConnected()) + { + BPoint oldpos=penpos; + MovePenTo(first); StrokeLine(second,pattern); + MovePenTo(second); StrokeLine(third,pattern); + MovePenTo(third); StrokeLine(first,pattern); + penpos=oldpos; + } + locker->Unlock(); +} + +void ScreenDriver::StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, rgb_color col) +{ +#ifdef DEBUG_DRIVER +printf("ScreenDriver::StrokeTriangle({%u,%u,%u,%u}):\n", + col.red,col.green,col.blue,col.alpha); +printf("\tFirst: (%f,%f)\n\tSecond: (%f,%f)\n\tThird: (%f,%f)\n",first.x,first.y, + second.x,second.y,third.x,third.y); +rect.PrintToStream(); +#endif + locker->Lock(); + if(fbuffer->IsConnected()) + { + StrokeLine(first,second,col); + StrokeLine(first,third,col); + StrokeLine(third,second,col); + } + locker->Unlock(); +} + +void ScreenDriver::Line32(BPoint pt, BPoint pt2, uint8 *pattern) +{ +#ifdef DEBUG_DRIVER +printf("ScreenDriver::Line32( (%f,%f),(%f,%f), 0x%llx\n",pt.x,pt.y, + pt2.x,pt2.y,*((int64*)pattern)); +#endif + // Courtesy YNOP's SecondDriver with minor changes by DW + int oct=0; + int xoff=(int32)pt.x; + int yoff=(int32)pt.y; + int32 x2=(int32)pt2.x-xoff; + int32 y2=(int32)pt2.y-yoff; + int32 x1=0; + int32 y1=0; + if(y2<0){ y2=-y2; oct+=4; }//bit2=1 + if(x2<0){ x2=-x2; oct+=2;}//bit1=1 + if(x232) + patindex=0; + } +} + +void ScreenDriver::SetPixelPattern(int x, int y, uint8 *pattern, uint8 patternindex) +{ + // This function is designed to add pattern support to this thing. Should be + // inlined later to add speed lost in the multiple function calls. +#ifdef DEBUG_DRIVER +printf("ScreenDriver::SetPixelPattern(%u,%u,%llx,%u)\n",x,y,*((int64*)pattern),patternindex); +#endif + if(patternindex>32) + return; + + if(fbuffer->IsConnected()) + { + uint64 *p64=(uint64*)pattern; + + // check for transparency in mask. If transparent, we can quit here + + bool transparent_bit= + ( *p64 & ~((uint64)2 << (32-patternindex)))?true:false; +printf("SetPixelPattern: pattern=0x%llx\n",*p64); +printf("SetPixelPattern: bit=0x%llx\n",((uint64)2 << (32-patternindex))); +printf("SetPixelPattern: bit mask=0x%llx\n",~((uint64)2 << (32-patternindex))); +printf("SetPixelPattern: bit value=%s\n",transparent_bit?"true":"false"); + + bool highcolor_bit= + ( *p64 & ~((uint64)2 << (64-patternindex)))?true:false; + + switch(fbuffer->gcinfo.bits_per_pixel) + { + case 32: + case 24: + { + + break; + } + case 16: + case 15: + { + break; + } + case 8: + { + break; + } + default: + { +#ifdef DEBUG_DRIVER +printf("SetPixelPattern: unknown bit depth %u\n",fbuffer->gcinfo.bits_per_pixel); +#endif + break; + } + } + } + else + { +#ifdef DEBUG_DRIVER +printf("SetPixelPattern: driver is disconnected\n"); +#endif + } +} + +void Clear_32Bit(void *buffer, int width, int height, rgb_color col) +{ +#ifdef DEBUG_DRIVER +printf("Clear_32Bit(*,%d,%d,(r=%u,g=%u,b=%u,a=%u)\n",width,height,col.red,col.green, + col.blue,col.alpha); +#endif + + uint32 c=0,*pcolor=(uint32*)buffer; + + // apparently width=bytes per row + uint32 bpr=width; + + // ARGB order + c|=col.alpha * 0x01000000; + c|=col.red * 0x010000; + c|=col.green * 0x0100; + c|=col.blue; + +#ifdef DEBUG_DRIVER +printf("Clear color value: 0x%lx\n",c); +#endif + for(int32 j=0;jbpr)?length-((x+length)-bpr):length; + + pcolor=(uint32*)i.frame_buffer; + pcolor+=(y*bpr)+(x*4); + for(int32 i=0;ibpr)?length-((x+length)-bpr):length; + + memset(pcolor,col,bytes); +} diff --git a/src/servers/app/proto6/ScreenDriver.h b/src/servers/app/proto6/ScreenDriver.h new file mode 100644 index 0000000000..714e1cc46e --- /dev/null +++ b/src/servers/app/proto6/ScreenDriver.h @@ -0,0 +1,114 @@ +#ifndef _SCREENDRIVER_H_ +#define _SCREENDRIVER_H_ + +#include +#include +#include +#include +#include +#include +#include +#include // for clipping_rect definition +#include +#include "DisplayDriver.h" + +class VDWindow; +class ServerCursor; +class ServerBitmap; + + +class FrameBuffer : public BWindowScreen +{ +public: + FrameBuffer(const char *title, uint32 space, status_t *st,bool debug); + ~FrameBuffer(void); + void ScreenConnected(bool connected); + void MessageReceived(BMessage *msg); + bool IsConnected(void) const { return is_connected; } + bool QuitRequested(void); + + graphics_card_info gcinfo; +protected: + bool is_connected; +}; + +class ScreenDriver : public DisplayDriver +{ +public: + ScreenDriver(void); + ~ScreenDriver(void); + + void Initialize(void); + void Shutdown(void); + + void Clear(uint8 red,uint8 green,uint8 blue); + void Clear(rgb_color col); + + // Settings functions + void SetScreen(uint32 space); +/* int32 GetHeight(void); + int32 GetWidth(void); + int GetDepth(void); + + // Drawing functions + void Blit(BRect src, BRect dest); +*/ void DrawBitmap(ServerBitmap *bitmap, BRect source, BRect dest); +/* void DrawChar(char c, BPoint point); + void DrawString(char *string, int length, BPoint point); + + void FillArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern); + void FillBezier(BPoint *points, uint8 *pattern); + void FillEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern); + void FillPolygon(int *x, int *y, int numpoints, bool is_closed); +*/ void FillRect(BRect rect, uint8 *pattern); + void FillRect(BRect rect, rgb_color col); +// void FillRegion(BRegion *region); + void FillRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern); +// void FillShape(BShape *shape); + + void FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern); + void FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, rgb_color col); +/* + void HideCursor(void); + bool IsCursorHidden(void); + void MoveCursorTo(float x, float y); + void ObscureCursor(void); + float PenSize(void); + void SetCursor(ServerCursor *cursor); +*/ + void SetHighColor(uint8 r,uint8 g,uint8 b,uint8 a=255); + void SetHighColor(rgb_color col); + void SetLowColor(uint8 r,uint8 g,uint8 b,uint8 a=255); + void SetLowColor(rgb_color col); + + void SetPixel(int x, int y, uint8 *pattern); + + void SetPixel32(int x, int y, rgb_color col); + void SetPixel16(int x, int y, uint16 col); + void SetPixel8(int x, int y, uint8 col); + void SetPixelPattern(int x, int y, uint8 *pattern, uint8 patternindex); + +// void ShowCursor(void); + +// void StrokeArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern); +// void StrokeBezier(BPoint *points, uint8 *pattern); +// void StrokeEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern); + void StrokeLine(BPoint point, uint8 *pattern); + void StrokeLine(BPoint pt1, BPoint pt2, rgb_color col); + void StrokePolygon(int *x, int *y, int numpoints, bool is_closed); + void StrokeRect(BRect rect,uint8 *pattern); + void StrokeRect(BRect rect,rgb_color col); + void StrokeRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern); +// void StrokeShape(BShape *shape); + void StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern); + void StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, rgb_color col); + +protected: + void Line32(BPoint pt, BPoint pt2, uint8 *pattern); + FrameBuffer *fbuffer; + int hide_cursor; + ServerBitmap *cursor; + int32 drawmode; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/SecondDriver.cpp b/src/servers/app/proto6/SecondDriver.cpp new file mode 100644 index 0000000000..6b232bb96f --- /dev/null +++ b/src/servers/app/proto6/SecondDriver.cpp @@ -0,0 +1,836 @@ +/******************************************************* +* SecondDriver +* +* Second driver is a Drvier abstraction layer for the +* OBOS app_server. It provides access to the Graphic +* HW via the low level api calls. This provides a +* way to run the app_server on real HW. +* This driver also makes it easy for you to run the +* OBOS app_server in parallel with the Be app_server +* when two or more video cards are installed in your +* computer. +* +* @author YNOP (ynop@beunited.org) +* @version beta1 (p5) +* +* History: +* - Added Ellipse (Stroke & Fill) +* Ran though test app to make sure worked +* Fixed HorizLine to used fill_span instead of fill_rect :P +* Updated the Cursor code to work again. +* Made new cursor (Be-hand like) +* - Added StrokeBezir +* Added HorizLine for speed +* - Added HW acceleration methods +* - Brez Line added +* - Created by YNOP +* +* Todo: +* Clean up src and add more comments :P +* Redo StrokeLine to use PenSize +* Redo StrokeLine to use pattern +* Mouse Cursor seems to be broken in proto5 ? +* Add in a way to read app_server_settings file so we can get the real settings +* Make display mode settings more flexable +* Look into FreeType for DrawString :P fun fun fun +* +* Todo methods: +* Blit() DrawBitmap() DrawString() FillArc() FillBezier() FillPolygon() +* FillRegion() FillRoundRect() FillShape() FillTriangle() +* StrokeArc() StrokeRoundRect() StrokeShpae() +* +*******************************************************/ +#include +#include + +#include + +#include "PortLink.h" +#include "ServerProtocol.h" +#include "ServerBitmap.h" +#include "ServerCursor.h" +#include "DebugTools.h" +#include "SecondDriver.h" +#include "SecondDriverHelper.h" + +/******************************************************* +* @description +*******************************************************/ +SecondDriver::SecondDriver(void):DisplayDriver(){ + SetupBezier(); + hide_cursor = false; + fd = -1; + image = -1; + + gah = NULL; + bits = NULL; + bpr = -1; + + scs = NULL; + mc = NULL; + sc = NULL; + + et = NULL; + re = NULL; + + s2sb = NULL; + fr = NULL; + ir = NULL; + s2stb = NULL; + fs = NULL; + +} + +/******************************************************* +* @description +*******************************************************/ +SecondDriver::~SecondDriver(void){ + if(is_initialized){ + } +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::Initialize(void){ + et = NULL; + bits = NULL; + + // Find a driver + fd = get_device(); + if(fd < 0){ + printf("No Device settings found.\n"); + fd = find_device(); + }else{ + printf("Device read from settings file\n"); + } + if(fd < 0){ + printf("No device find, trying fallback stub\n"); + fd = fallback_device(); + } + if(fd < 0){ + printf("Didn't find device :(\n"); + is_initialized = false; + } + /* load the accelerant */ + image = load_accelerant(fd, &gah); + if (image >= 0){ + // Set up the display to a valid resolution + if(get_and_set_mode(gah,&dm) == B_OK){ + // Here we are all good + if(dm.space == B_CMAP8){ + set_palette(gah); + } + get_frame_buffer(gah, &fbc); + bits = (uint32*)fbc.frame_buffer/*_dma*/; + bpr = fbc.bytes_per_row/4; // sould be by depth + + if(dm.flags & B_HARDWARE_CURSOR){ + // Lets check out tha hardwar cursoer stuff :P + printf("Mode supports Hardware cursors\n"); + scs = (set_cursor_shape)gah(B_SET_CURSOR_SHAPE,NULL); + mc = (move_cursor)gah(B_MOVE_CURSOR,NULL); + sc = (show_cursor)gah(B_SHOW_CURSOR,NULL); + } + + // Ok. now lets see if we can add some spiffy + // 2D acceleration to this :) + accelerant_engine_count aec = (accelerant_engine_count)gah(B_ACCELERANT_ENGINE_COUNT,NULL); + uint32 count = aec(); + if(count > 0){ + acquire_engine ae = (acquire_engine)gah(B_ACQUIRE_ENGINE,NULL); + re = (release_engine)gah(B_RELEASE_ENGINE,NULL); + if(ae(B_2D_ACCELERATION,1000,&st,&et) == B_OK){ + // Now lets see if we have some functions + printf("You should be verry happy. You have 2D hardware Acceleration\n"); + s2sb = (screen_to_screen_blit)gah(B_SCREEN_TO_SCREEN_BLIT,NULL); + fr = (fill_rectangle)gah(B_FILL_RECTANGLE,NULL); + ir = (invert_rectangle)gah(B_INVERT_RECTANGLE,NULL); + s2stb = (screen_to_screen_transparent_blit)gah(B_SCREEN_TO_SCREEN_TRANSPARENT_BLIT,NULL); + fs = (fill_span)gah(B_FILL_SPAN,NULL); + } + } + is_initialized = true; + }else{ + // failed to set mode + is_initialized = false; + } + }else{ + // image failed to load + is_initialized = false; + } + + if(is_initialized){ + printf("\n\tSecond Driver by YNOP (ynop@beunited.org)\n"); + printf("\tSecond Driver is copyrigth YNOP 2002\n"); + printf("\tHave fun, its all set up :)\n\n"); + } + + SetCursor((ServerCursor*)NULL); + ShowCursor(); + int32 h = GetHeight(); + int32 w = GetWidth(); + MoveCursorTo(w/2,h/2); + +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::Shutdown(void){ + printf("\tShuting down SecondDriver\n"); + if(et){ + if(re(et,&st) != B_OK){ + printf("Failed to release engine\n"); + } + } + + uninit_accelerant ua = (uninit_accelerant)gah(B_UNINIT_ACCELERANT,NULL); + if(ua){ ua();} + + unload_add_on(image); + + // clsoe the file now... + close(fd); + + + is_initialized=false; +} + +/******************************************************* +* @description +*******************************************************/ +bool SecondDriver::IsInitialized(void){ + return is_initialized; +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::SafeMode(void){ +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::Reset(void){ +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::SetScreen(uint32 space){ + // Clear(51,102,152); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::Clear(uint8 red, uint8 green, uint8 blue){ + rgb_color r; + r.red = red; + r.blue = blue; + r.green = green; + Clear(r); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::Clear(rgb_color col){ + highcol = col; + FillRect(BRect(0,0,GetHeight()-1,GetWidth()-1),NULL); +} + +/******************************************************* +* @description +*******************************************************/ +int32 SecondDriver::GetHeight(void){ + // Gets the height of the current mode + return dm.virtual_height; +} + +/******************************************************* +* @description +*******************************************************/ +int32 SecondDriver::GetWidth(void){ + // Gets the width of the current mode + return dm.virtual_width; +} + +/******************************************************* +* @description +*******************************************************/ +int SecondDriver::GetDepth(void){ + // Gets the color depth of the current mode + return 0; +} + +/******************************************************* +* @description +*******************************************************/ +#ifdef PROTO_4 + void SecondDriver::Blit(BPoint loc, ServerBitmap *src, ServerBitmap *dest) +#else + void SecondDriver::Blit(BRect src, BRect dest) +#endif +{ + printf("Calling Blit (not wirten yet)\n"); + if(s2sb){ + printf("Accelerated Blit\n"); + }else{ + + } +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::DrawBitmap(ServerBitmap *bitmap, BRect source, BRect dest){ + printf("Calling DrawBitmap (not writen yet)\n"); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::DrawChar(char c, BPoint point){ + char string[2]; + string[0]=c; + string[1]='\0'; + DrawString(string,2,point); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::DrawString(char *string, int length, BPoint point){ + printf("DrawString is not writen yet\n"); + + // i would say that libtruetype would do some good herer +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern){ + printf("FillArc is not writen yet\n"); + StrokeArc(centerx,centery,xradius,yradius,angle,span,pattern); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillBezier(BPoint *points, uint8 *pattern){ + printf("FillBezier is not writen yet\n"); + StrokeBezier(points,pattern); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern){ + MidpointEllipse(centerx,centery,x_radius,y_radius,true,pattern); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillPolygon(int *x, int *y, int numpoints, bool is_closed){ + printf("FillPolygon is not writen yet\n"); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillRect(BRect rect, uint8 *pattern){ + if(fr){ + // usieng accelertated 2d file + union{ + uint8 bytes[4]; + uint32 word; + }c1; + + //printf("Accelerated Fill\n"); + fill_rect_params frp; + frp.left =(uint16) rect.left; + frp.top =(uint16) rect.top; + frp.right =(uint16) rect.right; + frp.bottom =(uint16) rect.bottom; + c1.bytes[0] = highcol.blue; + c1.bytes[1] = highcol.green; + c1.bytes[2] = highcol.red; + fr(et,c1.word,&frp,1); + }else{ + for(int32 i = 0;i < rect.Height()-1;i++){ + MovePenTo(BPoint(rect.left,rect.top+i)); + StrokeLine(BPoint(rect.right,rect.top+i),pattern); + //HorizLine(rect.left,rect.right,rect.top+i); // uses accel :P + } + } +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillRect(BRect rect, rgb_color col){ + rgb_color tmpc = highcol; + highcol = col; + FillRect(rect, NULL); + highcol = tmpc; +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillRegion(BRegion *region){ + printf("RillRegion is not writen yet\n"); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern){ + printf("FillRoundRect is not writen yet\n"); + StrokeRoundRect(rect,xradius,yradius,pattern); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillShape(BShape *shape){ + printf("FillShape is not writen yet\n"); + StrokeShape(shape); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern){ + printf("FillTriangle is not writen yet\n"); + StrokeTriangle(first,second,third,rect,pattern); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, rgb_color color){ + printf("FillTriangle is not writen yet\n"); + StrokeTriangle(first,second,third,rect,color); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::HideCursor(void){ + if(sc){ + sc(false); + cursor_visible = false; + }else{ + printf("Shoftware Hide Cursor\n"); + } +} + +/******************************************************* +* @description +*******************************************************/ +bool SecondDriver::IsCursorHidden(void){ + return cursor_visible; +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::ObscureCursor(void){ + // Hides cursor until mouse is moved + HideCursor(); + show_on_move = true; +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::MoveCursorTo(float x, float y){ + if(show_on_move){ + ShowCursor(); + } + if(mc){ + mc((short unsigned int)x,(short unsigned int)y); + }else{ + printf("Software move Cursor\n"); + } +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::MovePenTo(BPoint pt){ + penpos = pt; +} + +/******************************************************* +* @description +*******************************************************/ +BPoint SecondDriver::PenPosition(void){ + return penpos; +} + +/******************************************************* +* @description +*******************************************************/ +float SecondDriver::PenSize(void){ + return pensize; +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::SetCursor(int32 value){ + printf("Setcursoer value?\n"); + // Uh what is this all about? +} + + + + +//0 - 1 = black +//0 - 0 = what +//1 - 0 = trans +//1 - 1 = invert + +// Pointy cursor +/*uint8 andMask[] = { + 63,255,15,255,131,255,128,127,192,31,192,31,224,63,224,63, + 224,31,240,15,243,7,255,131,255,193,255,224,255,240,255,248 +}; +uint8 xorMask[] = { + 192,0,176,0,76,0,67,128,32,96,32,32,16,64,16,64, + 16,32,11,16,12,136,0,68,0,34,0,17,0,9,0,7 +};*/ +// BeOS like cursor +uint8 andMask[] = { + 255,255,255,255,199,255,195,255,195,255,224,31,224,3,240,1, + 240,0,192,0,128,0,128,0,192,0,240,0,252,1,254,7 +}; +uint8 xorMask[] = { + 0,0,0,0,56,0,36,0,36,0,19,224,18,92,9,42, + 8,1,60,0,76,0,66,0,48,0,12,0,2,0,1,0 +}; + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::SetCursor(ServerCursor *cursor){ + printf("Setting cursor\n"); + current_cursor = cursor; +// uint8 *andMask; + // uint8 *xorMask; + if(scs){ +// scs(cursor->width,cursor->height,(short unsigned int)cursor->hotspot.x,(short unsigned int)cursor->hotspot.y,andMask,xorMask); + scs(16,16,3,3,andMask,xorMask); + }else{ + printf("Setting software cursor\n"); + } +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::SetPenSize(float size){ + pensize = size; +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::SetPixel(int x, int y, uint8 *pattern){ + union{ + uint8 bytes[4]; + uint32 word; + }c1; + + c1.bytes[0] = highcol.blue; + c1.bytes[1] = highcol.green; + c1.bytes[2] = highcol.red; + c1.bytes[3] = highcol.alpha; + + *(bits + x + y*bpr) = c1.word; +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::ShowCursor(void){ + printf("\tShow Cursor\n"); + show_on_move = false; + cursor_visible = true; + if(sc){ + sc(true); + }else{ + printf("Software show cursor\n"); + } +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::StrokeArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern){ + printf("StrokeArch is not writen yet\n"); +} + + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::StrokeBezier(BPoint *pts, uint8 *pattern){ + BPoint segment[SEGMENTS + 1]; + computeSegments(pts[0], pts[1],pts[2],pts[3], segment); + + MovePenTo(segment[0]); + + for(int32 s = 1 ; s <= SEGMENTS ; ++s ){ + if(segment[s].x != segment[s - 1].x || segment[s].y != segment[s - 1].y ) { + StrokeLine(segment[s],pattern); + } + } +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::StrokeEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern){ + MidpointEllipse(centerx,centery,x_radius,y_radius,false,pattern); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::StrokeLine(BPoint point, uint8 *pattern){ + if(penpos.y == point.y){ + HorizLine(penpos.x,point.x,point.y,pattern); + return; + } + + int oct = 0; + int xoff = (int32)penpos.x; + int yoff = (int32)penpos.y; + int32 x2 = (int32)point.x-xoff; + int32 y2 = (int32)point.y-yoff; + int32 x1 = 0; + int32 y1 = 0; +// if(y2==0){ if (x1>x2){int t=x1;x1=x2;x2=t;}HorizLine(x1+xoff,x2+xoff,y1+yoff); return;} + if(y2<0){ y2 = -y2; oct+=4; }//bit2=1 + if(x2<0){ x2 = -x2; oct+=2;}//bit1=1 + if(x2 x2){ int32 t=x1;x1=x2;x2=t; } + if(fr){ + union{ + uint8 bytes[4]; + uint32 word; + }c1; + + //printf("Accelerated HorizLine\n"); + uint16 list[3]; + list[0] = y; + list[1] = x1; + list[2] = x2; + c1.bytes[0] = highcol.blue; + c1.bytes[1] = highcol.green; + c1.bytes[2] = highcol.red; + fs(et,c1.word,list,1); + }else{ + //software hline + printf("\t!!HorizLine without HWaccel is a waist\n"); + for(int32 i = x1; i <= x2;i++){ + SetPixel(i,y,pattern); + } + } + +} + +//void EllipsePoints(float cx,float cy,int32 x, int32 y){ +// view->StrokeLine(BPoint(x+cent.x,y+cent.y),BPoint(x+cent.x,y+cent.y)); +// view->StrokeLine(BPoint(-x+cent.x,y+cent.y),BPoint(-x+cent.x,y+cent.y)); +// view->StrokeLine(BPoint(x+cent.x,-y+cent.y),BPoint(x+cent.x,-y+cent.y)); +// view->StrokeLine(BPoint(-x+cent.x,-y+cent.y),BPoint(-x+cent.x,-y+cent.y)); +#define EllipsePoints(cx,cy,x,y,pattern){ \ + SetPixel( x+cx, y+cx,pattern); \ + SetPixel(-x+cx, y+cx,pattern); \ + SetPixel( x+cx,-y+cx,pattern); \ + SetPixel(-x+cx,-y+cx,pattern); \ +} + + +//void EllipsePointsFill(BPoint cent,int32 x, int32 y,pattern){ +// view->StrokeLine(BPoint(-x+cent.x,y+cent.y),BPoint(x+cent.x,y+cent.y)); +// view->StrokeLine(BPoint(-x+cent.x,-y+cent.y),BPoint(x+cent.x,-y+cent.y)); + + #define EllipsePointsFill(cx,cy,x,y,pattern){ \ + HorizLine(-x+cx,x+cx, y+cy, pattern); \ + HorizLine(-x+cx,x+cx, -y+cy, pattern); \ +} + + +/******************************************************* +* +*******************************************************/ +void SecondDriver::MidpointEllipse(float centx,float centy,int32 xrad, int32 yrad,bool fill,uint8 *pattern){ + if(xrad < 0){ xrad = -xrad; } + if(yrad < 0){ yrad = -yrad; } + double d2; + int32 x = 0; + int32 y = yrad; + + int32 xradSqr = xrad*xrad; + int32 yradSqr = yrad*yrad; + + double dl = yradSqr - (xradSqr*yrad) + (0.25 *xradSqr); + + if(fill){ EllipsePointsFill(centx,centy,x,y,pattern); }else{ EllipsePoints(centx,centy,x,y,pattern); } + + // Test gradient if still in region 1 + while((xradSqr*(y-.5)) > (yradSqr*(x+1))){ + if(dl < 0){ // Select E + dl += yradSqr*(2*x + 3); + }else{ // Select SE + dl += yradSqr*(2*x + 3) + xradSqr*(-2*y + 2); + y--; + } + x++; + if(fill){ EllipsePointsFill(centx,centy,x,y,pattern); }else{ EllipsePoints(centx,centy,x,y,pattern); } + } + + d2 = (yradSqr*(x + .5)*(x + .5)) + (xradSqr*(y-1)*(y-1)) - xradSqr*yradSqr; + while(y > 0){ + if(d2 < 0){ // Select SE + d2 += yradSqr*(2*x + 2) + xradSqr*(-2*y + 3); + x++; + }else{ // Select E + d2 += xradSqr*(-2*y + 3); + } + y--; + if(fill){ EllipsePointsFill(centx,centy,x,y,pattern); }else{ EllipsePoints(centx,centy,x,y,pattern); } + } +} + + + +#ifdef DEBUG_DRIVER_MODULE +#undef DEBUG_DRIVER_MODULE +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/SecondDriver.h b/src/servers/app/proto6/SecondDriver.h new file mode 100644 index 0000000000..3dcbab2a1f --- /dev/null +++ b/src/servers/app/proto6/SecondDriver.h @@ -0,0 +1,123 @@ +#ifndef _SECDRIVER_H_ +#define _SECDRIVER_H_ + +#include +#include +#include +#include +#include // for pattern struct +#include +#include +#include "DisplayDriver.h" + +#include +#include +#include + +class BBitmap; +class PortLink; +class VDWindow; +class ServerCursor; + + +class SecondDriver:public DisplayDriver{ +public: + SecondDriver(void); + virtual ~SecondDriver(void); + + virtual void Initialize(void); // Sets the driver + virtual bool IsInitialized(void); + virtual void Shutdown(void); // You never know when you'll need this + + virtual void SafeMode(void); // Easy-access functions for common tasks + virtual void Reset(void); + virtual void Clear(uint8 red,uint8 green,uint8 blue); + virtual void Clear(rgb_color col); + + // Settings functions + virtual void SetScreen(uint32 space); + virtual int32 GetHeight(void); + virtual int32 GetWidth(void); + virtual int GetDepth(void); + + // Drawing functions + #ifdef PROTO_4 + virtual void Blit(BPoint loc, ServerBitmap *src, ServerBitmap *dest); + #else + virtual void Blit(BRect src, BRect dest); + #endif + virtual void DrawBitmap(ServerBitmap *bitmap, BRect source, BRect dest); + virtual void DrawChar(char c, BPoint point); + virtual void DrawString(char *string, int length, BPoint point); + + virtual void FillArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern); + virtual void FillBezier(BPoint *points, uint8 *pattern); + virtual void FillEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern); + virtual void FillPolygon(int *x, int *y, int numpoints, bool is_closed); + virtual void FillRect(BRect rect, uint8 *pattern); + virtual void FillRect(BRect rect, rgb_color col); + virtual void FillRegion(BRegion *region); + virtual void FillRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern); + virtual void FillShape(BShape *shape); + virtual void FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern); + virtual void FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, rgb_color color); + + virtual void HideCursor(void); + virtual bool IsCursorHidden(void); + virtual void MoveCursorTo(float x, float y); + virtual void MovePenTo(BPoint pt); + virtual void ObscureCursor(void); + virtual BPoint PenPosition(void); + virtual float PenSize(void); + virtual void SetCursor(int32 value); + virtual void SetCursor(ServerCursor *cursor); + virtual void SetPenSize(float size); + virtual void SetPixel(int x, int y, uint8 *pattern); + virtual void ShowCursor(void); + + virtual void StrokeArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern); + virtual void StrokeBezier(BPoint *points, uint8 *pattern); + virtual void StrokeEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern); + virtual void StrokeLine(BPoint point, uint8 *pattern); + virtual void StrokeLine(BPoint pt1, BPoint pt2, rgb_color col); + virtual void StrokePolygon(int *x, int *y, int numpoints, bool is_closed); + virtual void StrokeRect(BRect rect,uint8 *pattern); + virtual void StrokeRect(BRect rect,rgb_color col); + virtual void StrokeRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern); + virtual void StrokeShape(BShape *shape); + virtual void StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern); + virtual void StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, rgb_color color); +private: + void HorizLine(int32 x1,int32 x2,int32 y, uint8 *pattern); + void MidpointEllipse(float centerx, float centery,int32 xrad, int32 yrad,bool fill,uint8 *pattern); +protected: + int hide_cursor; + + int fd; + image_id image; + GetAccelerantHook gah; + display_mode dm; + + frame_buffer_config fbc; + + uint32 *bits; + int32 bpr; + + set_cursor_shape scs; + move_cursor mc; + show_cursor sc; + + sync_token st; + engine_token *et; + release_engine re; + + screen_to_screen_blit s2sb; + fill_rectangle fr; + invert_rectangle ir; + screen_to_screen_transparent_blit s2stb; + fill_span fs; + + +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/SecondDriverHelper.h b/src/servers/app/proto6/SecondDriverHelper.h new file mode 100644 index 0000000000..ff3ee288d7 --- /dev/null +++ b/src/servers/app/proto6/SecondDriverHelper.h @@ -0,0 +1,435 @@ +/******************************************************* +* SecondDriver +* +* Helper methods for SecondDriver. This is where we +* put all the code that inits the real HW and +* seaches for the acceleration methods an all that +* other stuff. +* +* @author YNOP (ynop@beunited.org) +*******************************************************/ +#ifndef _SECDRIVER_HELPER_H_ +#define _SECDRIVER_HELPER_H_ + +//#include +#include +#include + +#include +#include +#include // has ioctl ?:P +//#include +#include + +#define DEV_GRAPHICS "/dev/graphics/" +#define ACCELERANTS_DIR "/accelerants/" +#define DEV_STUB "stub" + +/******************************************************* +* @description Loads the driver from settings ... +*******************************************************/ +int get_device(){ +// 102b_0519_001300 102b_051a_001400 stub + return open(DEV_GRAPHICS"102b_051a_001400", B_READ_WRITE); +// return -1; +} + +/******************************************************* +* @description Loads the stub driver - never fun +*******************************************************/ +int fallback_device(){ + return open(DEV_GRAPHICS DEV_STUB, B_READ_WRITE); +} + +/******************************************************* +* @description Find the first device that it can open +* in the /dev/graphics dir and returns it. +*******************************************************/ +int find_device(){ + DIR *d; + struct dirent *e; + char name_buf[1024]; + int fd = -1; + //bool foundfirst = false; // hacky way of finding second video card in your box + + printf("Probeing %s for device...\n",DEV_GRAPHICS); + + /* open directory apath */ + d = opendir(DEV_GRAPHICS); + if(!d){ return B_ERROR; } + while((e = readdir(d)) != NULL){ + if (!strcmp(e->d_name, ".") || !strcmp(e->d_name, "..") || !strcmp(e->d_name, "stub")){ + continue; + } + strcpy(name_buf, DEV_GRAPHICS); +// strcat(name_buf, "/"); + strcat(name_buf, e->d_name); + fd = open(name_buf, B_READ_WRITE); + ///printf("Opening device %s\n",name_buf); + if(fd >= 0){ + //printf("Open wend ok\n"); + /*if(!foundfirst){ + foundfirst = true; + printf("\tbut we are not going to use it as app_server is\n"); + }else{ + // found it :) + */ printf("\tOpened device %s\n",name_buf); + closedir(d); + return fd; + //} + }else{ + //foundfirst = true; // this is a proper find as the app_server should let us open the dev + printf("\tCouldn't open device %s\n",name_buf); + } + } + closedir(d); + return B_ERROR; +} + +/******************************************************* +* @description Finds and loads the Accelerant for +* this device +*******************************************************/ +image_id load_accelerant(int fd, GetAccelerantHook *hook) { + status_t result; + image_id image = -1; + char + signature[1024], + path[PATH_MAX]; + struct stat st; + const static directory_which vols[] = { + B_USER_ADDONS_DIRECTORY, + B_COMMON_ADDONS_DIRECTORY, + B_BEOS_ADDONS_DIRECTORY + }; + + /* get signature from driver */ + result = ioctl(fd, B_GET_ACCELERANT_SIGNATURE, &signature, sizeof(signature)); + if (result != B_OK){ + printf("Failed to get accelerant signature from drived!\n"); + return result; + } + + printf("Searching for Accelerant named \"%s\"\n",signature); + + // note failure by default + for(int32 i=0; i < (int32)(sizeof (vols) / sizeof (vols[0])); i++) { + //printf("attempting to get path for %ld (%d)\n", i, vols[i]); + if(find_directory(vols[i], -1, false, path, PATH_MAX) != B_OK) { + printf("warning: find directory failed (continueing)\n"); + continue; + } + + strcat (path, ACCELERANTS_DIR); + strcat (path, signature); + printf("\tTrying %s\n",path); + + // don't try to load non-existant files + if (stat(path, &st) != 0) continue; + + // try and load it up.. + image = load_add_on(path); + if (image >= 0) { + printf("\tAccelerant loaded - trying to init\n"); + // get entrypoint from accelerant + result = get_image_symbol(image, B_ACCELERANT_ENTRY_POINT, +#if defined(__INTEL__) + B_SYMBOL_TYPE_ANY, +#else + B_SYMBOL_TYPE_TEXT, +#endif + (void **)hook); + if (result == B_OK) { + init_accelerant ia; + ia = (init_accelerant)(*hook)(B_INIT_ACCELERANT, NULL); + if(ia && ((result = ia(fd)) == B_OK)) { + // we have a winner! + //printf("Accelerant %s \n", path); + printf("\tAccelerant Init() was B_OK\n"); + break; + } else { + printf("\tAccelerant Init() failed: %ld\n", result); + } + } else { + printf("\tCouldn't find the entry point :-(\n"); + } + // unload the accelerant, as we must be able to init! + unload_add_on(image); + } + if (image < 0) printf("\tLoad Image failure. ID: %.8lx (%s)\n", image, strerror(image)); + // mark failure to load image + image = -1; + } + + //printf("Add-on image id: %ld\n", image); + return image; +} + +/******************************************************* +* @description +*******************************************************/ +static const char *spaceToString(uint32 cs) { + const char *s; + switch (cs) { +#define s2s(a) case a: s = #a ; break + s2s(B_RGB32); + s2s(B_RGBA32); + s2s(B_RGB32_BIG); + s2s(B_RGBA32_BIG); + s2s(B_RGB16); + s2s(B_RGB16_BIG); + s2s(B_RGB15); + s2s(B_RGBA15); + s2s(B_RGB15_BIG); + s2s(B_RGBA15_BIG); + s2s(B_CMAP8); + s2s(B_GRAY8); + s2s(B_GRAY1); + s2s(B_YCbCr422); + s2s(B_YCbCr420); + s2s(B_YUV422); + s2s(B_YUV411); + s2s(B_YUV9); + s2s(B_YUV12); + default: + s = "unknown"; break; +#undef s2s + } + return s; +} + +/******************************************************* +* @description +*******************************************************/ +void dump_mode(display_mode *dm) { + display_timing *t = &(dm->timing); + printf(" pixel_clock: %ldKHz\n", t->pixel_clock); + printf(" H: %4d %4d %4d %4d\n", t->h_display, t->h_sync_start, t->h_sync_end, t->h_total); + printf(" V: %4d %4d %4d %4d\n", t->v_display, t->v_sync_start, t->v_sync_end, t->v_total); + printf(" timing flags:"); + if (t->flags & B_BLANK_PEDESTAL) printf(" B_BLANK_PEDESTAL"); + if (t->flags & B_TIMING_INTERLACED) printf(" B_TIMING_INTERLACED"); + if (t->flags & B_POSITIVE_HSYNC) printf(" B_POSITIVE_HSYNC"); + if (t->flags & B_POSITIVE_VSYNC) printf(" B_POSITIVE_VSYNC"); + if (t->flags & B_SYNC_ON_GREEN) printf(" B_SYNC_ON_GREEN"); + if (!t->flags) printf(" (none)\n"); + else printf("\n"); + printf(" refresh rate: %4.2f\n", ((double)t->pixel_clock * 1000) / ((double)t->h_total * (double)t->v_total)); + printf(" color space: %s\n", spaceToString(dm->space)); + printf(" virtual size: %dx%d\n", dm->virtual_width, dm->virtual_height); + printf("dispaly start: %d,%d\n", dm->h_display_start, dm->v_display_start); + + printf(" mode flags:"); + if (dm->flags & B_SCROLL) printf(" B_SCROLL"); + if (dm->flags & B_8_BIT_DAC) printf(" B_8_BIT_DAC"); + if (dm->flags & B_HARDWARE_CURSOR) printf(" B_HARDWARE_CURSOR"); + if (dm->flags & B_PARALLEL_ACCESS) printf(" B_PARALLEL_ACCESS"); +// if (dm->flags & B_SUPPORTS_OVERLAYS) printf(" B_SUPPORTS_OVERLAYS"); + if (!dm->flags) printf(" (none)\n"); + else printf("\n"); +} + +/******************************************************* +* @description +*******************************************************/ +void simple_dump_mode(display_mode *dm){ + //printf("H: %4d\n", t->h_display); + //printf("V: %4d\n", t->v_display); + display_timing *t = &(dm->timing); + printf("Virtual size: %d x %d\n", dm->virtual_width, dm->virtual_height); + printf("Color space: %s\n", spaceToString(dm->space)); + printf("Refresh rate: %4.2f\n", ((double)t->pixel_clock * 1000) / ((double)t->h_total * (double)t->v_total)); +} + +/******************************************************* +* @description +*******************************************************/ +void mode_from_settings(display_mode *dm){ + // display_timing *t = &(dm->timing); + dm->space = B_RGB32; + dm->virtual_width = 800; + dm->virtual_height = 600; + dm->h_display_start = 0; + dm->v_display_start = 0; +} + +/******************************************************* +* @description +*******************************************************/ +status_t get_and_set_mode(GetAccelerantHook gah, display_mode *dm) { + printf("Setting up display mode\n"); + accelerant_mode_count gmc; + uint32 mode_count; + get_mode_list gml; + display_mode *mode_list, target, high, low; + propose_display_mode pdm; + status_t result = B_ERROR; + set_display_mode sdm; + + /* find the propose mode hook */ + pdm = (propose_display_mode)gah(B_PROPOSE_DISPLAY_MODE, NULL); + if (!pdm) { + printf("No B_PROPOSE_DISPLAY_MODE\n"); + goto exit0; + } + /* and the set mode hook */ + sdm = (set_display_mode)gah(B_SET_DISPLAY_MODE, NULL); + if (!sdm) { + printf("No B_SET_DISPLAY_MODE\n"); + goto exit0; + } + + /* how many modes does the driver support */ + gmc = (accelerant_mode_count)gah(B_ACCELERANT_MODE_COUNT, NULL); + if (!gmc) { + printf("No B_ACCELERANT_MODE_COUNT\n"); + goto exit0; + } + mode_count = gmc(); + printf("\tDriver supports %lu differnat video modes\n", mode_count); + if (mode_count == 0) goto exit0; + + /* get a list of graphics modes from the driver */ + gml = (get_mode_list)gah(B_GET_MODE_LIST, NULL); + if (!gml) { + printf("No B_GET_MODE_LIST\n"); + goto exit0; + } + mode_list = (display_mode *)calloc(sizeof(display_mode), mode_count); + if (!mode_list) { + printf("Couldn't calloc() for mode list\n"); + goto exit0; + } + if (gml(mode_list) != B_OK) { + printf("mode list retrieval failed\n"); + goto free_mode_list; + } + + /* take the first mode in the list */ + //printf("\tPropose Display Mode\n------------------------\n"); + //simple_dump_mode(&mode_list[69]); + //mode_from_settings(&mode_list[69]); + target = mode_list[69]; + high = mode_list[69]; + low = mode_list[69]; + /* make as tall a virtual height as possible */ + //target.virtual_height = high.virtual_height = 0xffff; + // virtual hight should only be used if a res larger than + // the screen can handle + /* propose the display mode */ + if (pdm(&target, &low, &high) == B_ERROR) { + printf("propose_display_mode failed\n"); + goto free_mode_list; + } + printf("------Target display mode------\n"); + simple_dump_mode(&target); + printf("-------------------------------\n"); + /* we got a display mode, now set it */ + if (sdm(&target) == B_ERROR) { + printf("set display mode failed\n"); + goto free_mode_list; + } + /* note the mode and success */ + *dm = target; + result = B_OK; + +free_mode_list: + free(mode_list); +exit0: + return result; +} + + +/******************************************************* +* @description +*******************************************************/ +void get_frame_buffer(GetAccelerantHook gah, frame_buffer_config *fbc) { + get_frame_buffer_config gfbc; + gfbc = (get_frame_buffer_config)gah(B_GET_FRAME_BUFFER_CONFIG, NULL); + gfbc(fbc); +} + +/******************************************************* +* @description +*******************************************************/ +sem_id get_sem(GetAccelerantHook gah) { + accelerant_retrace_semaphore ars; + ars = (accelerant_retrace_semaphore)gah(B_ACCELERANT_RETRACE_SEMAPHORE, NULL); + return ars(); +} + +/******************************************************* +* @description +*******************************************************/ +void set_palette(GetAccelerantHook gah) { + set_indexed_colors sic; + sic = (set_indexed_colors)gah(B_SET_INDEXED_COLORS, NULL); + if (sic) { + /* booring grey ramp for now */ + uint8 map[3 * 256]; + uint8 *p = map; + int i; + for (i = 0; i < 256; i++) { + *p++ = i; + *p++ = i; + *p++ = i; + } + sic(256, 0, map, 0); + } +} + +// This is a ll the stuff needed to stroke a Bezier Curve.. +// Note that we should probably wait and alloc this data latter +// on when we stroke our first Curve. That way if no curve ever +// gets render (unlikely i know) then this space would be saved. +#define SEGMENTS 32 +#define Fixed float +static Fixed weight1[SEGMENTS + 1]; +static Fixed weight2[SEGMENTS + 1]; +#define w1(s) weight1[s] +#define w2(s) weight2[s] +#define w3(s) weight2[SEGMENTS - s] +#define w4(s) weight1[SEGMENTS - s] +#define FixMul(a,b) (a)*(b) +#define FixRound(a) ((a-int32(a))>=.5)?(int32(a)+1):(int32(a)) +#define FixRatio(a,b) ((a)/float(b)) + +/******************************************************* +* @description Creats the two Bernstien Pollynomials +* We only need to creat two becase the 1 & 4 are +* mirrors and the 2 & 3 are mirros. +*******************************************************/ +void SetupBezier(){ + Fixed t, zero, one; + int s; + zero = FixRatio(0, 1); + one = FixRatio(1, 1); + + weight1[0] = one; + weight2[0] = zero; + for(s = 1 ;s < SEGMENTS ;++s){ + t = FixRatio(s, SEGMENTS); + weight1[s] = FixMul(one - t, FixMul(one - t, one - t)); + weight2[s] = 3 * FixMul(t, FixMul(t - one, t - one)); + } + weight1[SEGMENTS] = zero; + weight2[SEGMENTS] = zero; +} + +/******************************************************* +* @description Useing the weights of the 4 bernstein +* pollynomials calc the segment endpoints. This is +* the real worker method +*******************************************************/ +static void computeSegments(BPoint p1,BPoint p2, BPoint p3, BPoint p4, BPoint *segment){ + int s; + segment[0] = p1; + for(s = 1;s < SEGMENTS;++s){ + segment[s].y = FixRound(w1(s) * p1.y + w2(s) * p2.y + w3(s) * p3.y + w4(s) * p4.y); + segment[s].x = FixRound(w1(s) * p1.x + w2(s) * p2.x + w3(s) * p3.x + w4(s) * p4.x); + } + segment[SEGMENTS] = p4; +} + +#endif + diff --git a/src/servers/app/proto6/ServerApp.cpp b/src/servers/app/proto6/ServerApp.cpp new file mode 100644 index 0000000000..65516aae3c --- /dev/null +++ b/src/servers/app/proto6/ServerApp.cpp @@ -0,0 +1,831 @@ +/* + ServerApp.cpp + Class which works with a BApplication. Handles all messages coming + from and going to its application. +*/ +//#define DEBUG_SERVERAPP_MSGS +//#define DEBUG_SERVERAPP_CURSORS +//#define DEBUG_SERVERAPP_MISC + +#include +#include +#include +#include +#include "Desktop.h" +#include "DisplayDriver.h" +//#include "Layer.h" +#include "ServerApp.h" +#include "ServerWindow.h" +#include "ServerBitmap.h" +#include "ServerProtocol.h" +#include "ServerCursor.h" +#include "PortLink.h" +#include +#include +#include +#include "DebugTools.h" + + +ServerApp::ServerApp(port_id msgport, char *signature) +{ + // need to copy the signature because the message buffer + // owns the copy which we are passed as a parameter. + app_sig=(signature)?signature:"Application"; + + // sender is the monitored app's event port + sender=msgport; + applink=new PortLink(sender); + + port_info pinfo; + get_port_info(sender,&pinfo); + target_id=pinfo.team; + + // receiver is the port to which the app sends messages for the server + receiver=create_port(30,app_sig.String()); + +#ifdef DEBUG_SERVERAPP_MISC +printf("ServerApp port for app %s is at %ld\n",app_sig.String(),receiver); +#endif + + if(receiver==B_NO_MORE_PORTS) + { + // uh-oh. We have a serious problem. Tell the app to quit + applink->SetOpCode(B_QUIT_REQUESTED); + applink->Flush(); + } + + // No longer necessary. This message is sent from the app_server thread + // now because of changes in the application structure from previous + // prototypes. +/* else + { + // Everything checks out, so tell the application + // where to send future messages + applink->SetOpCode(SET_SERVER_PORT); + applink->Attach(&receiver,sizeof(port_id)); + applink->Flush(); + } +*/ + applink->SetPort(sender); + winlist=new BList(0); + bmplist=new BList(0); + driver=get_gfxdriver(); + isactive=false; + cursor=new ServerCursor(); + + // This exists for testing the graphics access module and will disappear + // when layers are implemented + high.red=255; + high.green=255; + high.blue=255; + high.alpha=255; + low.red=0; + low.green=0; + low.blue=0; + low.alpha=255; +} + +ServerApp::~ServerApp(void) +{ +#ifdef DEBUG_SERVERAPP_MISC +printf("%s: ~ServerApp\n",app_sig.String()); +#endif + int32 i; + ServerWindow *tempwin; + for(i=0;iCountItems();i++) + { + tempwin=(ServerWindow*)winlist->ItemAt(i); + if(tempwin) + delete tempwin; + } + winlist->MakeEmpty(); + delete winlist; + + ServerBitmap *tempbmp; + for(i=0;iCountItems();i++) + { + tempbmp=(ServerBitmap*)bmplist->ItemAt(i); + if(tempbmp) + delete tempbmp; + } + bmplist->MakeEmpty(); + delete bmplist; + + delete applink; + applink=NULL; + delete cursor; + + // Kill the monitor thread if it exists + thread_info info; + if(get_thread_info(monitor_thread,&info)==B_OK) + kill_thread(monitor_thread); +} + +bool ServerApp::Run(void) +{ +#ifdef DEBUG_SERVERAPP_MISC +printf("%s: Run()\n",app_sig.String()); +#endif + // Unlike a BApplication, a ServerApp is *supposed* to return immediately + // when its Run function is called. + monitor_thread=spawn_thread(MonitorApp,app_sig.String(),B_NORMAL_PRIORITY,this); + if(monitor_thread==B_NO_MORE_THREADS || monitor_thread==B_NO_MEMORY) + return false; + resume_thread(monitor_thread); + return true; +} + +bool ServerApp::PingTarget(void) +{ + // This function is called by the app_server thread to ensure that + // the target app still exists. We do this not by sending a message + // but by calling get_port_info. We don't want to send ping messages + // just because the app might simply be hung. If this is the case, it + // should be up to the user to kill it. If the app has been killed, its + // ports will be invalid. Thus, if get_port_info returns an error, we + // tell the app_server to delete the respective ServerApp. + + team_info tinfo; + if(get_team_info(target_id,&tinfo)==B_BAD_TEAM_ID) + { + port_id serverport=find_port(SERVER_PORT_NAME); + if(serverport==B_NAME_NOT_FOUND) + { + printf("PANIC: ServerApp %s could not find the app_server port in PingTarget()!\n",app_sig.String()); + return false; + } + applink->SetPort(serverport); + applink->SetOpCode(DELETE_APP); + applink->Attach(&monitor_thread,sizeof(thread_id)); + applink->Flush(); +#ifdef DEBUG_SERVERAPP_MISC +printf("%s: target application is dead. ServerApp is quitting\n",app_sig.String()); +#endif + return false; + } + return true; +} + +int32 ServerApp::MonitorApp(void *data) +{ + ServerApp *app=(ServerApp *)data; + app->Loop(); + exit_thread(0); + return 0; +} + +void ServerApp::Loop(void) +{ +#ifdef DEBUG_SERVERAPP_MISC +printf("%s: Loop()\n",app_sig.String()); +#endif + // Message-dispatching loop for the ServerApp + int32 msgcode; + int8 *msgbuffer=NULL; + ssize_t buffersize,bytesread; + + for(;;) + { + buffersize=port_buffer_size(receiver); + + if(buffersize>0) + { + // buffers are PortLink messages. Allocate necessary buffer and + // we'll cast it as a BMessage. + msgbuffer=new int8[buffersize]; + bytesread=read_port(receiver,&msgcode,msgbuffer,buffersize); + } + else + bytesread=read_port(receiver,&msgcode,NULL,0); + if (bytesread != B_BAD_PORT_ID && bytesread != B_TIMED_OUT && bytesread != B_WOULD_BLOCK) + { + switch(msgcode) + { +// -------------- Messages received from the Application ------------------ + case B_QUIT_REQUESTED: + { + // Our BApplication sent us this message when it quit. + // We need to ask the app_server to delete our monitor + port_id serverport=find_port(SERVER_PORT_NAME); + if(serverport==B_NAME_NOT_FOUND) + { + printf("PANIC: ServerApp %s could not find the app_server port!\n",app_sig.String()); + break; + } + applink->SetPort(serverport); + applink->SetOpCode(DELETE_APP); + applink->Attach(&monitor_thread,sizeof(thread_id)); + applink->Flush(); + break; + } + +// -------------- Messages received from the Server ------------------------ + // Mouse messages simply get passed onto the active app for now + case B_MOUSE_UP: + case B_MOUSE_DOWN: + case B_MOUSE_MOVED: + { + // everything is formatted as it should be, so just call + // write_port. Eventually, this will be replaced by a + // BMessage + write_port(sender, msgcode, msgbuffer, buffersize); + break; + } + case QUIT_APP: + { + // This message is received from the app_server thread + // because the server was asked to quit. Thus, we + // ask all apps to quit. This is NOT the same as system + // shutdown and will happen only in testing + +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp asking %s to quit\n",app_sig.String()); +#endif + applink->SetOpCode(B_QUIT_REQUESTED); + applink->Flush(); + break; + } + default: + { + +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp received unrecognized code: "); +PrintMessageCode(msgcode); +#endif + + DispatchMessage(msgcode, msgbuffer); + break; + } + } + + } + + if(buffersize>0) + delete msgbuffer; + + if(msgcode==B_QUIT_REQUESTED) + break; + } +} + +void ServerApp::DispatchMessage(int32 code, int8 *buffer) +{ +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp "); +PrintMessageCode(code); +#endif + +int8 *index=buffer; + switch(code) + { + case CREATE_WINDOW: + { + // Create the ServerWindow to node monitor a new OBWindow + + // Attached data: + // 1) port_id reply port + // 2) BRect window frame + // 3) uint32 window flags + // 4) port_id window's message port + // 5) uint32 workspace index + // 6) const char * title + + // Find the necessary data + port_id reply_port=*((port_id*)index); index+=sizeof(port_id); + BRect rect=*((BRect*)index); index+=sizeof(BRect); + + uint32 winlook=*((uint32*)index); index+=sizeof(uint32); + uint32 winfeel=*((uint32*)index); index+=sizeof(uint32); + uint32 winflags=*((uint32*)index); index+=sizeof(uint32); + + port_id win_port=*((port_id*)index); index+=sizeof(port_id); + uint32 workspace=*((uint32*)index); index+=sizeof(uint32); + + // Create the ServerWindow object for this window + ServerWindow *newwin=new ServerWindow(rect,(const char *)index, + winlook, winfeel, winflags,this,win_port,workspace); + winlist->AddItem(newwin); + + // Window looper is waiting for our reply. Send back the + // ServerWindow's message port + PortLink *replylink=new PortLink(reply_port); + replylink->SetOpCode(SET_SERVER_PORT); + replylink->Attach((int32)newwin->receiver); + replylink->Flush(); + + delete replylink; + +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp: Create Window()\n"); +printf("Frame: "); rect.PrintToStream(); +printf("Title: %s\n",(const char*)index); +printf("SenderPort: %ld\n",win_port); +printf("Look: 0x%lx\n",winlook); +printf("Feel: 0x%lx\n",winfeel); +printf("Flags: 0x%lx\n",winflags); +printf("Workspace: 0x%lx\n",workspace); +#endif + + break; + + } + case DELETE_WINDOW: + { + // Received from a ServerWindow when its window quits + + // Attached data: + // 1) thread_id ServerWindow ID + thread_id winid; + ServerWindow *w; + for(int32 i=0;iCountItems();i++) + { + w=(ServerWindow*)winlist->ItemAt(i); + if(w->thread==winid) + { + winlist->RemoveItem(w); + delete w; + break; + } + } +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp: Delete Window()\n"); +printf("Thread ID: %ld",winid); +#endif + break; + } + case GFX_SET_SCREEN_MODE: + { + // Attached data + // 1) int32 workspace # + // 2) uint32 screen mode + // 3) bool make default + int32 workspace=*((int32*)index); index+=sizeof(int32); + uint32 mode=*((uint32*)index); index+=sizeof(uint32); + + SetScreenSpace(workspace,mode,*((bool*)index)); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp: SetScreenMode(%ld,%lu,%s)\n",workspace, + mode,(*((bool*)index)==true)?"true":"false"); +#endif + break; + } + case GFX_ACTIVATE_WORKSPACE: + { + // Attached data + // 1) int32 workspace index + ActivateWorkspace(*((int32*)index)); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp: ActivateWorkspace(%ld)\n",*((int32*)index)); +#endif + break; + } + case SHOW_CURSOR: + { + driver->ShowCursor(); + break; + } + case HIDE_CURSOR: + { + driver->HideCursor(); + break; + } + case OBSCURE_CURSOR: + { + driver->ObscureCursor(); + break; + } + case SET_CURSOR_DATA: + { + // Attached data: 68 bytes of cursor data + + // Get the data, update the app's cursor, and update the + // app's cursor if active. + int8 cdata[68]; + memcpy(cdata, buffer, 68); + cursor->SetCursor(cdata); + driver->SetCursor(cursor); +#ifdef DEBUG_SERVERAPP_CURSOR +printf("ServerApp: SetCursor(%d,%d,%d,%d)\n",r,g,b,a); +#endif + break; + } + case SET_CURSOR_BCURSOR: + // Not yet implemented + break; + + case SET_CURSOR_BBITMAP: + // Not yet implemented + break; + + // Graphics messages + case GFX_SET_HIGH_COLOR: + { + // Attached data: + // 1) uint8 red + // 2) uint8 green + // 3) uint8 blue + // 4) uint8 alpha + + uint8 r,g,b,a; + r=*((uint8*)index); index+=sizeof(uint8); + g=*((uint8*)index); index+=sizeof(uint8); + b=*((uint8*)index); index+=sizeof(uint8); + a=*((uint8*)index); + +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp: SetHighColor(%d,%d,%d,%d)\n",r,g,b,a); +#endif + driver->SetHighColor(r,g,b,a); + break; + } + case GFX_SET_LOW_COLOR: + { + // Attached data: + // 1) uint8 red + // 2) uint8 green + // 3) uint8 blue + // 4) uint8 alpha + + uint8 r,g,b,a; + r=*((uint8*)index); index+=sizeof(uint8); + g=*((uint8*)index); index+=sizeof(uint8); + b=*((uint8*)index); index+=sizeof(uint8); + a=*((uint8*)index); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp: SetHighColor(%d,%d,%d,%d)\n",r,g,b,a); +#endif + driver->SetLowColor(r,g,b,a); + break; + } + case GFX_MOVEPENBY: + { + // Attached data: + // 1) BPoint pt + + // Default functionality is MoveTo, so get the current position + // from the driver and compensate + BPoint *ptindex,passed_pt; + + ptindex=(BPoint*)index; + passed_pt=driver->PenPosition(); + passed_pt+=*ptindex; +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp MovePenBy: (%f,%f)\n",ptindex->x,ptindex->y); +printf("Pen moved to (%f,%f)\n",passed_pt.x,passed_pt.y); +#endif + driver->MovePenTo(passed_pt); + break; + } + case GFX_MOVEPENTO: + { + // Attached data: + // 1) BPoint pt + BPoint *pt; + pt=(BPoint*)index; +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp MovePenTo: (%f,%f)\n",pt->x,pt->y); +#endif + driver->MovePenTo(*pt); + break; + } + case GFX_SETPENSIZE: + { + // Attached data: + // 1) float pen size +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp SetPenSize(%f)\n",*((float*)index)); +#endif + driver->SetPenSize(*((float*)index)); + break; + } + case GFX_DRAW_STRING: + { + // Attached data: + // 1) uint16 string length + // 2) char * string + // 3) BPoint point + + uint16 length=*((uint16*)index); index+=sizeof(uint16); +// char *string=new char[length]; +// strcpy(string, (const char *)index); index+=length; + BString string=(char *)index; index+=length; + BPoint point=*((BPoint*)index); + +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp DrawString(%s, %d, BPoint(%f,%f))\n",string.String(),length,point.x,point.y); +#endif + driver->DrawString((char*)string.String(), length, point); +// delete string; + break; + } + case GFX_SET_FONT_SIZE: + break; + case GFX_STROKE_ARC: + { + // Attached data: + // 1) float center x + // 2) float center y + // 3) float x radius + // 4) float y radius + // 5) float starting angle + // 6) float span (arc length in degrees) + // 7) uint8[8] pattern + float cx,cy,rx,ry,angle,span; + + cx=*((float*)index); index+=sizeof(float); + cy=*((float*)index); index+=sizeof(float); + rx=*((float*)index); index+=sizeof(float); + ry=*((float*)index); index+=sizeof(float); + angle=*((float*)index); index+=sizeof(float); + span=*((float*)index); index+=sizeof(float); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp StrokeArc: "); +printf("Center: %f,%f\n",cx,cy); +printf("Radii: %f,%f\n",rx,ry); +printf("Angle, Span: %f,%f\n",angle, span); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->StrokeArc(cx,cy,rx,ry,angle,span,(uint8*)index); + break; + } + case GFX_STROKE_BEZIER: + { + // Attached data: + // 1) BPoint #1 + // 2) BPoint #2 + // 3) BPoint #3 + // 4) BPoint #4 + // 5) uint8[8] pattern + +#ifdef DEBUG_SERVERAPP_MSGS +BPoint *pt=(BPoint*)index; +printf("ServerApp StrokeBezier:\n"); +printf("Point 1: "); pt[0].PrintToStream(); +printf("Point 2: "); pt[1].PrintToStream(); +printf("Point 3: "); pt[2].PrintToStream(); +printf("Point 4: "); pt[3].PrintToStream(); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->StrokeBezier((BPoint*)index,(uint8*)(index+(sizeof(BPoint)*4))); + break; + } + case GFX_STROKE_ELLIPSE: + { + // Attached data: + // 1) float center x + // 2) float center y + // 3) float x radius + // 4) float y radius + // 5) uint8[8] pattern + float cx,cy,rx,ry; + + cx=*((float*)index); index+=sizeof(float); + cy=*((float*)index); index+=sizeof(float); + rx=*((float*)index); index+=sizeof(float); + ry=*((float*)index); index+=sizeof(float); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp StrokeEllipse: "); +printf("Center: %f,%f\n",cx,cy); +printf("Radii: %f,%f\n",rx,ry); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->StrokeEllipse(cx,cy,rx,ry,(uint8*)index); + break; + } + case GFX_STROKE_LINE: + { + // Attached data: + // 1) BPoint endpoint + // 2) uint8[8] pattern + BPoint *pt; + pt=(BPoint*)index; index+=sizeof(BPoint); + +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp StrokeLineTo: (%f,%f)\n",pt->x,pt->y); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->StrokeLine(*pt,(uint8*)index); + break; + } + case GFX_STROKE_POLYGON: + break; + case GFX_STROKE_RECT: + { + // Attached data: + // 1) BRect rect + // 2) uint8[8] pattern + BRect rect; + rect=*((BRect*)index); index+=sizeof(BRect); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp StrokeRect: "); rect.PrintToStream(); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->StrokeRect(rect, (uint8*)index); + break; + } + case GFX_STROKE_ROUNDRECT: + { + // Attached data: + // 1) BRect rect + // 2) float x_radius + // 3) float y_radius + // 4) uint8[8] pattern + BRect rect; + float x,y; + + rect=*((BRect*)index); index+=sizeof(BRect); + x=*((float*)index); index+=sizeof(float); + y=*((float*)index); index+=sizeof(float); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp StrokeRoundRect: "); rect.PrintToStream(); +printf("Radii: %f,%f\n",x,y); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->StrokeRoundRect(rect, x,y,(uint8*)index); + break; + } + case GFX_STROKE_SHAPE: + break; + case GFX_STROKE_TRIANGLE: + { + // Attached data + // 1) BPoint #1 + // 2) BPoint #2 + // 3) BPoint #3 + // 4) BRect invalid rect + // 5) uint8[8] pattern + BPoint pt1,pt2,pt3; + BRect rect; + pt1=*((BPoint*)index); index+=sizeof(BPoint); + pt2=*((BPoint*)index); index+=sizeof(BPoint); + pt3=*((BPoint*)index); index+=sizeof(BPoint); + rect=*((BRect*)index); index+=sizeof(BRect); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp StrokeTriangle: "); +printf("Point 1: "); pt1.PrintToStream(); +printf("Point 2: "); pt2.PrintToStream(); +printf("Point 3: "); pt3.PrintToStream(); +printf("Rectangle: "); rect.PrintToStream(); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->StrokeTriangle(pt1,pt2,pt3,rect,(uint8*)index); + break; + } + case GFX_FILL_ARC: + { + // Attached data: + // 1) float center x + // 2) float center y + // 3) float x radius + // 4) float y radius + // 5) float starting angle + // 6) float span (arc length in degrees) + // 7) uint8[8] pattern + float cx,cy,rx,ry,angle,span; + + cx=*((float*)index); index+=sizeof(float); + cy=*((float*)index); index+=sizeof(float); + rx=*((float*)index); index+=sizeof(float); + ry=*((float*)index); index+=sizeof(float); + angle=*((float*)index); index+=sizeof(float); + span=*((float*)index); index+=sizeof(float); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp FillArc: "); +printf("Center: %f,%f\n",cx,cy); +printf("Radii: %f,%f\n",rx,ry); +printf("Angle, Span: %f,%f\n",angle, span); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->FillArc(cx,cy,rx,ry,angle,span,(uint8*)index); + break; + } + case GFX_FILL_BEZIER: + { + // Attached data: + // 1) BPoint #1 + // 2) BPoint #2 + // 3) BPoint #3 + // 4) BPoint #4 + // 5) uint8[8] pattern + +#ifdef DEBUG_SERVERAPP_MSGS +BPoint *pt=(BPoint*)index; +printf("ServerApp FillBezier:\n"); +printf("Point 1: "); pt[0].PrintToStream(); +printf("Point 2: "); pt[1].PrintToStream(); +printf("Point 3: "); pt[2].PrintToStream(); +printf("Point 4: "); pt[3].PrintToStream(); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->FillBezier((BPoint*)index,(uint8*)(index+(sizeof(BPoint)*4))); + break; + } + case GFX_FILL_ELLIPSE: + { + // Attached data: + // 1) float center x + // 2) float center y + // 3) float x radius + // 4) float y radius + // 5) uint8[8] pattern + float cx,cy,rx,ry; + + cx=*((float*)index); index+=sizeof(float); + cy=*((float*)index); index+=sizeof(float); + rx=*((float*)index); index+=sizeof(float); + ry=*((float*)index); index+=sizeof(float); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp FillEllipse: "); +printf("Center: %f,%f\n",cx,cy); +printf("Radii: %f,%f\n",rx,ry); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->FillEllipse(cx,cy,rx,ry,(uint8*)index); + break; + } + case GFX_FILL_POLYGON: + break; + case GFX_FILL_RECT: + { + // Attached data: + // 1) BRect rect + // 2) uint8[8] pattern + BRect rect; + rect=*((BRect*)index); index+=sizeof(BRect); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp FillRect: "); rect.PrintToStream(); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->FillRect(rect, (uint8*)index); + break; + } + case GFX_FILL_REGION: + break; + case GFX_FILL_ROUNDRECT: + { + // Attached data: + // 1) BRect rect + // 2) float x_radius + // 3) float y_radius + // 4) uint8[8] pattern + BRect rect; + float x,y; + + rect=*((BRect*)index); index+=sizeof(BRect); + x=*((float*)index); index+=sizeof(float); + y=*((float*)index); index+=sizeof(float); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp FillRoundRect: "); rect.PrintToStream(); +printf("Radii: %f,%f\n",x,y); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->FillRoundRect(rect, x,y,(uint8*)index); + break; + } + case GFX_FILL_SHAPE: + break; + case GFX_FILL_TRIANGLE: + { + // Attached data + // 1) BPoint #1 + // 2) BPoint #2 + // 3) BPoint #3 + // 4) BRect invalid rect + // 5) uint8[8] pattern + BPoint pt1,pt2,pt3; + BRect rect; + pt1=*((BPoint*)index); index+=sizeof(BPoint); + pt2=*((BPoint*)index); index+=sizeof(BPoint); + pt3=*((BPoint*)index); index+=sizeof(BPoint); + rect=*((BRect*)index); index+=sizeof(BRect); +#ifdef DEBUG_SERVERAPP_MSGS +printf("ServerApp FillTriangle: "); +printf("Point 1: "); pt1.PrintToStream(); +printf("Point 2: "); pt2.PrintToStream(); +printf("Point 3: "); pt3.PrintToStream(); +printf("Rectangle: "); rect.PrintToStream(); +printf("pattern: {%d,%d,%d,%d,%d,%d,%d,%d}\n",index[0],index[1],index[2],index[3],index[4],index[5],index[6],index[7]); +#endif + driver->FillTriangle(pt1,pt2,pt3,rect,(uint8*)index); + break; + } + default: + { +#ifdef DEBUG_SERVERAPP_MSGS +cout << "DispatchMessage::Unrecognized code: "; +TranslateMessageCodeToStream(code); +cout << endl << flush; +#endif + break; + } + } +} + +// Prevent any preprocessor problems in case I screw something up +#ifdef DEBUG_SERVERAPP_MSGS +#undef DEBUG_SERVERAPP_MSGS +#endif + +#ifdef DEBUG_SERVERAPP_CURSORS +#undef DEBUG_SERVERAPP_CURSORS +#endif diff --git a/src/servers/app/proto6/ServerApp.h b/src/servers/app/proto6/ServerApp.h new file mode 100644 index 0000000000..6a53822cbf --- /dev/null +++ b/src/servers/app/proto6/ServerApp.h @@ -0,0 +1,42 @@ +#ifndef _SRVAPP_H_ +#define _SRVAPP_H_ + +#include +#include +class BMessage; +class PortLink; +class BList; +class ServerCursor; +class DisplayDriver; + +class ServerApp +{ +public: + ServerApp(port_id msgport, char *signature); + ~ServerApp(void); + + bool Run(void); + static int32 MonitorApp(void *data); + void Loop(void); + bool IsActive(void) const { return isactive; } + void Activate(bool value) { isactive=value; } + bool PingTarget(void); + +// char *app_sig; + port_id sender,receiver; + BString app_sig; + thread_id monitor_thread; + PortLink *applink; + BList *winlist, *bmplist; + ServerCursor *cursor; + DisplayDriver *driver; + rgb_color high, low; // just for testing until layers are implemented + +protected: + void DispatchMessage(int32 code, int8 *buffer); + + bool isactive; + team_id target_id; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/ServerBitmap.cpp b/src/servers/app/proto6/ServerBitmap.cpp new file mode 100644 index 0000000000..ee01f297f3 --- /dev/null +++ b/src/servers/app/proto6/ServerBitmap.cpp @@ -0,0 +1,257 @@ +/* + ServerBitmap.cpp + Bitmap class which is intended to provide an easy way to package all the + data associated with a picture. It's very low-level, so there's still + plenty to do when coding with 'em. Also, they can be used to access draw on the + frame buffer in a relatively easy way, although it is currently unclear + whether this functionality will even be necessary. +*/ + +// These three includes for ServerBitmap(const char *path_to_image_file) only +#include +#include +#include + +#include +#include "ServerBitmap.h" +#include "Desktop.h" + +ServerBitmap::ServerBitmap(BRect rect,color_space space,int32 BytesPerLine=0) +{ + width=rect.IntegerWidth()+1; + height=rect.IntegerHeight()+1; + cspace=space; + is_vram=false; + is_area=false; + areaid=B_ERROR; + + HandleSpace(space, BytesPerLine); + buffer=new uint8[bytesperline*height]; + driver=get_gfxdriver(); +} + +ServerBitmap::ServerBitmap(int32 w,int32 h,color_space space,int32 BytesPerLine=0) +{ + width=w; + height=h; + cspace=space; + is_vram=false; + is_area=false; + areaid=B_ERROR; + + HandleSpace(space, BytesPerLine); + buffer=new uint8[bytesperline*height]; + driver=get_gfxdriver(); +} + +ServerBitmap::ServerBitmap(int32 w,int32 h,color_space space, area_id areaID, int32 BytesPerLine=0) +{ + // This version is used for holding BBitmaps as one of the undocumented BBitmap + // constructors allows - it creates an area on the server's side. + width=w; + height=h; + cspace=space; + is_vram=false; + is_area=true; + + HandleSpace(space, BytesPerLine); + area_info ainfo; + areaid=areaID; + get_area_info(areaid, &ainfo); + buffer=(uint8*)ainfo.address; + driver=get_gfxdriver(); +} + +ServerBitmap::ServerBitmap(void) +{ + // This version is obviously intended for use as an easy-access class for the + // frame buffer. AtheOS does it and it's small, so why not? Worst case, this + // can disappear if not necessary. + is_vram=true; + is_area=false; + areaid=B_ERROR; + UpdateSettings(); +} + +// This particular version is not intended for use except for testing purposes. +// It loads a BBitmap and copies it to the ServerBitmap. Probably will disappear +// when the *real* server is written +ServerBitmap::ServerBitmap(const char *path) +{ + BBitmap *bmp=BTranslationUtils::GetBitmap(path); + assert(bmp!=NULL); + + if(bmp==NULL) + { + width=0; + height=0; + cspace=B_NO_COLOR_SPACE; + bytesperline=0; + } + else + { + width=bmp->Bounds().IntegerWidth(); + height=bmp->Bounds().IntegerHeight(); + cspace=bmp->ColorSpace(); + bytesperline=bmp->BytesPerRow(); + buffer=new uint8[bmp->BitsLength()]; + memcpy(buffer,(void *)bmp->Bits(),bmp->BitsLength()); + } +} + +ServerBitmap::~ServerBitmap(void) +{ + if(!is_vram) + delete buffer; +} + +void ServerBitmap::UpdateSettings(void) +{ + // This is only used when the object is pointing to the frame buffer + driver=get_gfxdriver(); + bpp=driver->GetDepth(); + width=driver->GetWidth(); + height=driver->GetHeight(); +} + +void ServerBitmap::SetBuffer(void *buffer) +{ + buffer=(uint8 *)buffer; +} + +uint8 *ServerBitmap::Buffer(void) +{ + return buffer; +} + +uint32 ServerBitmap::BitsLength(void) +{ + return (uint32)(bytesperline*height); +} + +void ServerBitmap::HandleSpace(color_space space, int32 BytesPerLine) +{ + // Function written to handle color space setup which is required + // by the two "normal" constructors + + // Big convoluted mess just to handle every color space and dword align + // the buffer + switch(space) + { + // Buffer is dword-aligned, so nothing need be done + // aside from allocate the memory + case B_RGB32: + case B_RGBA32: + case B_RGB32_BIG: + case B_RGBA32_BIG: + case B_UVL32: + case B_UVLA32: + case B_LAB32: + case B_LABA32: + case B_HSI32: + case B_HSIA32: + case B_HSV32: + case B_HSVA32: + case B_HLS32: + case B_HLSA32: + case B_CMY32: + case B_CMYA32: + case B_CMYK32: + + // 24-bit = 32-bit with extra 8 bits ignored + case B_RGB24_BIG: + case B_RGB24: + case B_LAB24: + case B_UVL24: + case B_HSI24: + case B_HSV24: + case B_HLS24: + case B_CMY24: + { + if(BytesPerLine<(width*4)) + bytesperline=width*4; + else + bytesperline=BytesPerLine; + bpp=32; + break; + } + // Calculate size and dword-align + + // 1-bit + case B_GRAY1: + { + int32 numbytes=width>>3; + if((width % 8) != 0) + numbytes++; + if(BytesPerLine +#include +#include +#include "DisplayDriver.h" + +class ServerBitmap +{ +public: + ServerBitmap(BRect rect,color_space space,int32 BytesPerLine=0); + ServerBitmap(int32 w,int32 h,color_space space,int32 BytesPerLine=0); + ServerBitmap(int32 w,int32 h,color_space space, area_id areaID, int32 BytesPerLine=0); + ServerBitmap(void); + ServerBitmap(const char *path); + ~ServerBitmap(void); + void UpdateSettings(void); + void SetBuffer(void *buffer); + uint8 *Buffer(void); + void SetArea(area_id ID); + area_id Area(void); + uint32 BitsLength(void); + BRect Bounds() { return BRect(0,0,width-1,height-1); }; + int32 BytesPerRow(void) { return bytesperline; }; + + int32 width,height; + int32 bytesperline; + color_space cspace; + int bpp; + +protected: + void HandleSpace(color_space space, int32 BytesPerLine); + DisplayDriver *driver; + bool is_vram,is_area; + area_id areaid; + uint8 *buffer; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/ServerCursor.cpp b/src/servers/app/proto6/ServerCursor.cpp new file mode 100644 index 0000000000..bb11e51760 --- /dev/null +++ b/src/servers/app/proto6/ServerCursor.cpp @@ -0,0 +1,136 @@ +/* + ServerCursor.cpp + This is the server-side class used to handle cursors. Note that it + will handle the R5 cursor API, but it will also handle taking a bitmap. + + ServerCursors are 32-bit. Eventually, we will be mapping colors to fit + when the set is called. + + This is new code, and there may be changes to the API before it settles + in. +*/ + +#include "ServerCursor.h" +#include "ServerBitmap.h" +#include +#include + +int8 default_cursor[]={ + 16,1,0,0, + + // data + 0xff, 0x80, 0x80, 0x80, 0x81, 0x00, 0x80, 0x80, 0x80, 0x40, 0x80, 0x80, 0x81, 0x00, 0xa2, 0x00, + 0xd4, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + // mask + 0xff, 0x80, 0xff, 0x80, 0xff, 0x00, 0xff, 0x80, 0xff, 0xc0, 0xff, 0x80, 0xff, 0x00, 0xfe, 0x00, + 0xdc, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +long pow2(int power) +{ + if(power==0) + return 1; + return long(2 << (power-1)); +} + +ServerCursor::ServerCursor(void) +{ + // For when an application is started. This will probably disappear once I + // get the stuff for default cursors established + is_initialized=false; + position.Set(0,0); +} + +ServerCursor::ServerCursor(ServerBitmap *bmp, ServerBitmap *cmask=NULL) +{ + // The OpenBeOS R1 API uses Bitmaps to create cursors - more flexibility that way. + is_initialized=false; + position.Set(0,0); + SetCursor(bmp); +} + +ServerCursor::ServerCursor(int8 *data) +{ + // For handling the idiot R5 API data format + is_initialized=false; + position.Set(0,0); + SetCursor(data); +} + +ServerCursor::~ServerCursor(void) +{ + if(is_initialized) + delete bitmap; +} + +void ServerCursor::SetCursor(int8 *data) +{ + // 68-byte array used in R5 for holding cursors. + // This API has serious problems and should be deprecated(but supported) + // in a future release, perhaps right after the first one + + if(is_initialized) + { + delete bitmap; + } + cspace=B_RGBA32; + + bitmap=new ServerBitmap(16,16,B_RGBA32); + width=16; + height=16; + bounds.Set(0,0,15,15); + + // Now that we have all the setup, we're going to map (for now) the cursor + // to RGBA32. Eventually, there will be support for 16 and 8-bit depths + uint32 black=0xFF000000, + white=0xFFFFFFFF, + *bmppos; + uint16 *cursorpos, *maskpos,cursorflip, maskflip, + cursorval, maskval; + uint8 i,j; + + cursorpos=(uint16*)(data+4); + maskpos=(uint16*)(data+36); + + // for each row in the cursor data + for(j=0;j<16;j++) + { + bmppos=(uint32*)(bitmap->Buffer()+ (j*bitmap->bytesperline) ); + + // On intel, our bytes end up swapped, so we must swap them back + cursorflip=(cursorpos[j] & 0xFF) << 8; + cursorflip |= (cursorpos[j] & 0xFF00) >> 8; + maskflip=(maskpos[j] & 0xFF) << 8; + maskflip |= (maskpos[j] & 0xFF00) >> 8; + + // for each column in each row of cursor data + for(i=0;i<16;i++) + { + // Get the values and dump them to the bitmap + cursorval=cursorflip & pow2(15-i); + maskval=maskflip & pow2(15-i); + bmppos[i]=((cursorval!=0)?black:white) & ((maskval>0)?0xFFFFFFFF:0x00FFFFFF); + } + } +} + +// Currently unimplemented +void ServerCursor::SetCursor(ServerBitmap *bmp, ServerBitmap *cmask=NULL) +{ +/* if(is_initialized) + delete bitmap; + cspace=bmp->cspace; + + bitmap=new ServerBitmap(bmp->width,bmp->height,cspace); + + width=bmp->width; + height=bmp->height; + bounds.Set(0,0,bmp->width-1,bmp->height-1); +*/ +} + +void ServerCursor::MoveTo(int32 x, int32 y) +{ + position.Set(x,y); +} diff --git a/src/servers/app/proto6/ServerCursor.h b/src/servers/app/proto6/ServerCursor.h new file mode 100644 index 0000000000..b75b822acb --- /dev/null +++ b/src/servers/app/proto6/ServerCursor.h @@ -0,0 +1,31 @@ +#ifndef _SERVER_SPRITE_H +#define _SERVER_SPRITE_H + +#include +#include + +class ServerBitmap; + +class ServerCursor +{ +public: + ServerCursor(ServerBitmap *bmp,ServerBitmap *cmask=NULL); + ServerCursor(int8 *data); + ServerCursor(void); + ~ServerCursor(void); + void MoveTo(int32 x, int32 y); + void SetCursor(int8 *data); + void SetCursor(ServerBitmap *bmp, ServerBitmap *cmask=NULL); + + ServerBitmap *bitmap; + + color_space cspace; + BRect bounds; + int width,height; + BPoint position,hotspot; + bool is_initialized; +}; + +extern int8 default_cursor[]; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/ServerProtocol.h b/src/servers/app/proto6/ServerProtocol.h new file mode 100644 index 0000000000..2295e31e26 --- /dev/null +++ b/src/servers/app/proto6/ServerProtocol.h @@ -0,0 +1,105 @@ +#ifndef _APPSERVER_PROTOCOL_ +#define _APPSERVER_PROTOCOL_ + +#define CREATE_APP 'drca' +#define DELETE_APP 'drda' +#define QUIT_APP 'srqa' + +#define SET_SERVER_PORT 'srsp' + +#define CREATE_WINDOW 'drcw' +#define DELETE_WINDOW 'drdw' +#define SHOW_WINDOW 'drsw' +#define HIDE_WINDOW 'drhw' +#define QUIT_WINDOW 'srqw' + +#define SERVER_PORT_NAME "OBappserver" +#define SERVER_INPUT_PORT "OBinputport" + + +// This will be modified. Currently a kludge for the input server until +// BScreens are implemented by the IK Taeam +#define GET_SCREEN_MODE 'gsmd' + +#define SET_UI_COLORS 'suic' +#define GET_UI_COLOR 'guic' +#define SET_DECORATOR 'sdec' +#define GET_DECORATOR 'gdec' + +#define SET_CURSOR_DATA 'sscd' +#define SET_CURSOR_BCURSOR 'sscb' +#define SET_CURSOR_BBITMAP 'sscB' +#define SHOW_CURSOR 'srsc' +#define HIDE_CURSOR 'srhc' +#define OBSCURE_CURSOR 'sroc' + +#define GFX_COUNT_WORKSPACES 'gcws' +#define GFX_SET_WORKSPACE_COUNT 'ggwc' +#define GFX_CURRENT_WORKSPACE 'ggcw' +#define GFX_ACTIVATE_WORKSPACE 'gaws' +#define GFX_GET_SYSTEM_COLORS 'gsyc' +#define GFX_SET_SYSTEM_COLORS 'gsyc' +#define GFX_SET_SCREEN_MODE 'gssm' +#define GFX_GET_SCROLLBAR_INFO 'ggsi' +#define GFX_SET_SCROLLBAR_INFO 'gssi' +#define GFX_IDLE_TIME 'gidt' +#define GFX_SELECT_PRINTER_PANEL 'gspp' +#define GFX_ADD_PRINTER_PANEL 'gapp' +#define GFX_RUN_BE_ABOUT 'grba' +#define GFX_SET_FOCUS_FOLLOWS_MOUSE 'gsfm' +#define GFX_FOCUS_FOLLOWS_MOUSE 'gffm' + +#define GFX_SET_HIGH_COLOR 'gshc' +#define GFX_SET_LOW_COLOR 'gslc' +#define GFX_SET_VIEW_COLOR 'gsvc' + +#define GFX_STROKE_ARC 'gsar' +#define GFX_STROKE_BEZIER 'gsbz' +#define GFX_STROKE_ELLIPSE 'gsel' +#define GFX_STROKE_LINE 'gsln' +#define GFX_STROKE_POLYGON 'gspy' +#define GFX_STROKE_RECT 'gsrc' +#define GFX_STROKE_ROUNDRECT 'gsrr' +#define GFX_STROKE_SHAPE 'gssh' +#define GFX_STROKE_TRIANGLE 'gstr' + +#define GFX_FILL_ARC 'gfar' +#define GFX_FILL_BEZIER 'gfbz' +#define GFX_FILL_ELLIPSE 'gfel' +#define GFX_FILL_POLYGON 'gfpy' +#define GFX_FILL_RECT 'gfrc' +#define GFX_FILL_REGION 'gfrg' +#define GFX_FILL_ROUNDRECT 'gfrr' +#define GFX_FILL_SHAPE 'gfsh' +#define GFX_FILL_TRIANGLE 'gftr' + +#define GFX_MOVEPENBY 'gmpb' +#define GFX_MOVEPENTO 'gmpt' +#define GFX_SETPENSIZE 'gsps' + +#define GFX_DRAW_STRING 'gdst' +#define GFX_SET_FONT 'gsft' +#define GFX_SET_FONT_SIZE 'gsfs' + +#define GFX_FLUSH 'gfsh' +#define GFX_SYNC 'gsyn' + +#define LAYER_CREATE 'lycr' +#define LAYER_DELETE 'lydl' +#define LAYER_ADD_CHILD 'lyac' +#define LAYER_REMOVE_CHILD 'lyrc' +#define LAYER_REMOVE_SELF 'lyrs' +#define LAYER_SHOW 'lysh' +#define LAYER_HIDE 'lyhd' +#define LAYER_MOVE 'lymv' +#define LAYER_RESIZE 'lyre' +#define LAYER_INVALIDATE 'lyin' +#define LAYER_DRAW 'lydr' + +#define BEGIN_RECT_TRACKING 'rtbg' +#define END_RECT_TRACKING 'rten' + +#define VIEW_GET_TOKEN 'vgtk' +#define VIEW_ADD 'vadd' +#define VIEW_REMOVE 'vrem' +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/ServerWindow.cpp b/src/servers/app/proto6/ServerWindow.cpp new file mode 100644 index 0000000000..bd88d427da --- /dev/null +++ b/src/servers/app/proto6/ServerWindow.cpp @@ -0,0 +1,507 @@ +/* + ServerWindow.cpp + Class which works with a BWindow. Handles all messages coming from and + going to its window plus all drawing calls. +*/ +#include +#include +#include +#include +#include +#include // for B_XXXXX_MOUSE_BUTTON defines +#include "AppServer.h" +#include "Layer.h" +#include "PortLink.h" +#include "ServerWindow.h" +#include "ServerApp.h" +#include "ServerProtocol.h" +#include "WindowBorder.h" +#include "DebugTools.h" + +//#define DEBUG_SERVERWIN + +// Used for providing identifiers for views +int32 view_counter=0; + +// Used in window focus management +ServerWindow *active_serverwindow=NULL; + +ServerWindow::ServerWindow(BRect rect, const char *string, uint32 wlook, + uint32 wfeel, uint32 wflags, ServerApp *winapp, port_id winport, uint32 index) +{ + title=new BString; + if(string) + title->SetTo(string); + else + title->SetTo("Window"); +#ifdef DEBUG_SERVERWIN +printf("ServerWindow() %s\n",title->String()); +#endif + + // This must happen before the WindowBorder object - it needs this object's frame + // to be valid + frame=rect; + + // set these early also - the decorator will also need them + winflags=wflags; + winlook=wlook; + winfeel=wfeel; + + + winborder=new WindowBorder(this, title->String()); + + // hard code this for now - window look also needs to be attached and sent to + // server by BWindow constructor + decorator=instantiate_decorator(winborder, winflags, wlook); +#ifdef DEBUG_SERVERWIN +if(decorator==NULL) + printf("ServerWindow() %s: NULL decorator returned\n",title->String()); +#endif + winborder->SetDecorator(decorator); +#ifdef DEBUG_SERVERWIN +printf("ServerWindow() %s: decorator set\n",title->String()); +#endif + + // sender is the monitored app's event port + sender=winport; + winlink=new PortLink(sender); + + if(winapp!=NULL) + applink=new PortLink(winapp->receiver); + else + applink=NULL; +#ifdef DEBUG_SERVERWIN +printf("ServerWindow() %s: PortLink established\n",title->String()); +#endif + + // receiver is the port to which the app sends messages for the server + receiver=create_port(30,title->String()); + + active=false; + hidecount=0; + + // Spawn our message monitoring thread + thread=spawn_thread(MonitorWin,title->String(),B_NORMAL_PRIORITY,this); + if(thread!=B_NO_MORE_THREADS && thread!=B_NO_MEMORY) + resume_thread(thread); +#ifdef DEBUG_SERVERWIN +printf("ServerWindow() %s: MonitorThread spawned\n",title->String()); +#endif + + workspace=index; + + AddWindowToDesktop(this,index); +#ifdef DEBUG_SERVERWIN +printf("ServerWindow() %s: Added to Desktop\n",title->String()); +#endif +} + +ServerWindow::~ServerWindow(void) +{ +#ifdef DEBUG_SERVERWIN +printf("%s::~ServerWindow()\n",title->String()); +#endif + RemoveWindowFromDesktop(this); + if(applink) + { + delete applink; + applink=NULL; + + delete title; + delete winlink; + delete decorator; + delete winborder; + } + kill_thread(thread); +} + +void ServerWindow::RequestDraw(BRect rect) +{ + winlink->SetOpCode(LAYER_DRAW); + winlink->Attach(&rect,sizeof(BRect)); + winlink->Flush(); +} + +void ServerWindow::ReplaceDecorator(void) +{ +#ifdef DEBUG_SERVERWIN +printf("%s::ReplaceDecorator()\n",title->String()); +#endif +} + +void ServerWindow::Quit(void) +{ +#ifdef DEBUG_SERVERWIN +printf("%s::Quit()\n",title->String()); +#endif +} + +const char *ServerWindow::GetTitle(void) +{ + return title->String(); +} + +ServerApp *ServerWindow::GetApp(void) +{ + return app; +} + +void ServerWindow::Show(void) +{ +#ifdef DEBUG_SERVERWIN +printf("%s::Show()\n",title->String()); +#endif + if(winborder) + { + winborder->ShowLayer(); + ActivateWindow(this); +// winborder->Draw(frame); + } +} + +void ServerWindow::Hide(void) +{ +#ifdef DEBUG_SERVERWIN +printf("%s::Hide()\n",title->String()); +#endif + if(winborder) + winborder->HideLayer(); +} + +bool ServerWindow::IsHidden(void) +{ + return (hidecount==0)?true:false; +} + +void ServerWindow::SetFocus(bool value) +{ +#ifdef DEBUG_SERVERWIN +printf("%s::SetFocus(%s)\n",title->String(),(value==true)?"true":"false"); +#endif + if(active!=value) + { + active=value; + decorator->SetFocus(value); + decorator->Draw(); + } +} + +bool ServerWindow::HasFocus(void) +{ + return active; +} + +void ServerWindow::WorkspaceActivated(int32 NewWorkspace, const BPoint Resolution, color_space CSpace) +{ +} + +void ServerWindow::WindowActivated(bool Active) +{ +} + +void ServerWindow::ScreenModeChanged(const BPoint Resolustion, color_space CSpace) +{ +} + +void ServerWindow::SetFrame(const BRect &rect) +{ +#ifdef DEBUG_SERVERWIN +printf("%s::SetFrame()",title->String()); rect.PrintToStream(); +#endif + frame=rect; +} + +BRect ServerWindow::Frame(void) +{ + return frame; +} + +status_t ServerWindow::Lock(void) +{ +#ifdef DEBUG_SERVERWIN +printf("%s::Lock()\n",title->String()); +#endif + return locker.Lock(); +} + +void ServerWindow::Unlock(void) +{ +#ifdef DEBUG_SERVERWIN +printf("%s::Unlock()\n",title->String()); +#endif + locker.Unlock(); +} + +bool ServerWindow::IsLocked(void) +{ + return locker.IsLocked(); +} + +void ServerWindow::Loop(void) +{ + // Message-dispatching loop for the ServerWindow + +#ifdef DEBUG_SERVERWIN +printf("%s::Loop()\n",title->String()); +#endif + int32 msgcode; + int8 *msgbuffer=NULL; + ssize_t buffersize,bytesread; + + for(;;) + { + buffersize=port_buffer_size(receiver); + + if(buffersize>0) + { + msgbuffer=new int8[buffersize]; + bytesread=read_port(receiver,&msgcode,msgbuffer,buffersize); + } + else + bytesread=read_port(receiver,&msgcode,NULL,0); + + if (bytesread != B_BAD_PORT_ID && bytesread != B_TIMED_OUT && bytesread != B_WOULD_BLOCK) + { + switch(msgcode) + { + case LAYER_CREATE: + { + // Received when a view is attached to a window. This will require + // us to attach a layer in the tree in the same manner and invalidate + // the area in which the new layer resides assuming that it is + // visible + + // Attached Data: + // 1) (int32) id of the parent view + // 2) (int32) id of the child view + // 3) (BRect) frame in parent's coordinates + // 4) (int32) resize flags + // 5) (int32) view flags + // 6) (uint16) view's hide level + + break; + } + case LAYER_DELETE: + { + // Received when a view is detached from a window. This is definitely + // the less taxing operation - we call PruneTree() on the removed + // layer, detach the layer itself, delete it, and invalidate the + // area assuming that the view was visible when removed + + // Attached Data: + // 1) (int32) id of the removed view + break; + } + case SHOW_WINDOW: + { + Show(); + break; + } + case HIDE_WINDOW: + { + Hide(); + break; + } + case DELETE_WINDOW: + { + // Received from our window when it is told to quit, so tell our + // application to delete this object + applink->SetOpCode(DELETE_WINDOW); + applink->Attach((int32)thread); + applink->Flush(); + break; + } + case VIEW_GET_TOKEN: + { + // Request to get a view identifier - this is synchronous, so reply + // immediately + + // Attached data: + // 1) port_id reply port + port_id reply_port=*((port_id*)msgbuffer); + PortLink *link=new PortLink(reply_port); + link->Attach(view_counter++); + link->Flush(); + break; + } + default: + DispatchMessage(msgcode,msgbuffer); + break; + } + + } + + if(buffersize>0) + delete msgbuffer; + + if(msgcode==B_QUIT_REQUESTED) + break; + } +} + +void ServerWindow::DispatchMessage(int32 code, int8 *msgbuffer) +{ + switch(code) + { + default: + { +#ifdef DEBUG_SERVERWIN +printf("%s::ServerWindow(): Received unexpected code: ",title->String()); +PrintMessageCode(code); +#endif + break; + } + } +} + +int32 ServerWindow::MonitorWin(void *data) +{ + ServerWindow *win=(ServerWindow *)data; + win->Loop(); + exit_thread(0); + return 0; +} + +void ServerWindow::HandleMouseEvent(int32 code, int8 *buffer) +{ + ServerWindow *mousewin=NULL; + int8 *index=buffer; + + // Find the window which will receive our mouse event. + Layer *root=GetRootLayer(); + WindowBorder *winborder; + ASSERT(root!=NULL); + + // Dispatch the mouse event to the proper window + switch(code) + { + case B_MOUSE_DOWN: + { + // Attached data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - modifier keys down + // 5) int32 - buttons down + // 6) int32 - clicks + +// int64 time=*((int64*)index); + index+=sizeof(int64); + float x=*((float*)index); + index+=sizeof(float); + float y=*((float*)index); + index+=sizeof(float); +// int32 modifiers=*((int32*)index); + index+=sizeof(uint32); + uint32 buttons=*((uint32*)index); + index+=sizeof(uint32); +// int32 clicks=*((int32*)index); + BPoint pt(x,y); + + // If we have clicked on a window, + winborder=(WindowBorder*)root->GetChildAt(pt); + if(winborder) + { + mousewin=winborder->Window(); + ASSERT(mousewin!=NULL); + winborder->MouseDown(pt,buttons); + +#ifdef DEBUG_SERVERWIN +printf("ServerWindow() %s: MouseDown(%.1f,%.1f)\n",mousewin->title->String(),x,y); +#endif + } + break; + } + case B_MOUSE_UP: + { + // Attached data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - modifier keys down + +// int64 time=*((int64*)index); + index+=sizeof(int64); + float x=*((float*)index); + index+=sizeof(float); + float y=*((float*)index); + index+=sizeof(float); +// int32 modifiers=*((int32*)index); + BPoint pt(x,y); + + is_moving_window=false; + winborder=(WindowBorder*)root->GetChildAt(pt); + if(winborder) + { + mousewin=winborder->Window(); + ASSERT(mousewin!=NULL); + + // Eventually, we will build in MouseUp messages with buttons specified + // For now, we just "assume" no mouse specification with a 0. + winborder->MouseUp(pt,0); + + // Do cool mouse stuff here + +#ifdef DEBUG_SERVERWIN +printf("ServerWindow() %s: MouseUp(%.1f,%.1f)\n",mousewin->title->String(),x,y); +#endif + } + break; + } + case B_MOUSE_MOVED: + { + // Attached data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - buttons down +// int64 time=*((int64*)index); + index+=sizeof(int64); + float x=*((float*)index); + index+=sizeof(float); + float y=*((float*)index); + index+=sizeof(float); + uint32 buttons=*((uint32*)index); + BPoint pt(x,y); + + if(!is_moving_window) + { + winborder=(WindowBorder*)root->GetChildAt(pt); + if(winborder) + { + mousewin=winborder->Window(); + ASSERT(mousewin!=NULL); + + winborder->MouseMoved(pt,buttons); + } + } + else + { + mousewin=active_serverwindow; + ASSERT(mousewin!=NULL); + + mousewin->winborder->MouseMoved(pt,buttons); + } + break; + } + default: + { +#ifdef DEBUG_SERVERWIN +printf("HandleMouseEvent() received an unrecognized mouse event"); +PrintMessageCode(code); +#endif + break; + } + } +} + +void ActivateWindow(ServerWindow *win) +{ + if(active_serverwindow==win) + return; + if(active_serverwindow) + active_serverwindow->SetFocus(false); + active_serverwindow=win; + if(win) + win->SetFocus(true); +} diff --git a/src/servers/app/proto6/ServerWindow.h b/src/servers/app/proto6/ServerWindow.h new file mode 100644 index 0000000000..9266979aea --- /dev/null +++ b/src/servers/app/proto6/ServerWindow.h @@ -0,0 +1,76 @@ +#ifndef _SERVERWIN_H_ +#define _SERVERWIN_H_ + +#include +#include +#include +#include +#include +#include + +class BString; +class BMessenger; +class BPoint; +class ServerApp; +class Decorator; +class PortLink; +class WindowBorder; + +class ServerWindow +{ +public: + ServerWindow(BRect rect, const char *string, uint32 wlook, uint32 wfeel, + uint32 wflags, ServerApp *winapp, port_id winport, uint32 index); + ~ServerWindow(void); + + void ReplaceDecorator(void); + void Quit(void); + const char *GetTitle(void); + ServerApp *GetApp(void); + void Show(void); + void Hide(void); + bool IsHidden(void); + void SetFocus(bool value); + bool HasFocus(void); + void RequestDraw(BRect rect); + + void WorkspaceActivated(int32 NewDesktop, const BPoint Resolution, color_space CSpace); + void WindowActivated(bool Active); + void ScreenModeChanged(const BPoint Resolution, color_space CSpace); + + void SetFrame(const BRect &rect); + BRect Frame(void); + + status_t Lock(void); + void Unlock(void); + bool IsLocked(void); + + void DispatchMessage(int32 code, int8 *msgbuffer); + static int32 MonitorWin(void *data); + static void HandleMouseEvent(int32 code, int8 *buffer); + void Loop(void); + + BString *title; + int32 winlook, winfeel, winflags; + int32 workspace; + bool active; + + ServerApp *app; + + Decorator *decorator; + WindowBorder *winborder; + bigtime_t lasthit; // Time of last mouse click + + thread_id thread; + port_id receiver; // Messages from window + port_id sender; // Messages to window + PortLink *winlink,*applink; + BLocker locker; + BRect frame; + uint8 hidecount; +}; + +void ActivateWindow(ServerWindow *win); + + +#endif diff --git a/src/servers/app/proto6/SystemPalette.cpp b/src/servers/app/proto6/SystemPalette.cpp new file mode 100644 index 0000000000..dc3fdcd40f --- /dev/null +++ b/src/servers/app/proto6/SystemPalette.cpp @@ -0,0 +1,327 @@ +/* + SystemPalette.cpp + One global function to generate the palette which is the default BeOS + System palette and the variable to go with it +*/ + +#include "SystemPalette.h" + +rgb_color system_palette[256]; + +void GenerateSystemPalette(rgb_color *palette) +{ + int i,j,index=0; + int indexvals1[]={ 255,229,204,179,154,129,105,80,55,30 }, + indexvals2[]={ 255,203,152,102,51,0 }; + rgb_color *currentcol; + + // Grays 0,0,0 -> 248,248,248 by 8's + for(i=0; i<=248; i+=8,index++) + { + currentcol=&(palette[index]); + currentcol->red=i; + currentcol->green=i; + currentcol->blue=i; + currentcol->alpha=255; + } + + // Blues, following indexvals1 + for(i=0; i<10; i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=0; + currentcol->green=0; + currentcol->blue=indexvals1[i]; + currentcol->alpha=255; + } + + // Reds, following indexvals1 - 1 + for(i=0; i<10; i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=indexvals1[i] - 1; + currentcol->green=0; + currentcol->blue=0; + currentcol->alpha=255; + } + + // Greens, following indexvals1 - 1 + for(i=0; i<10; i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=0; + currentcol->green=indexvals1[i] - 1; + currentcol->blue=0; + currentcol->alpha=255; + } + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=152; + currentcol->blue=51; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=255; + currentcol->blue=255; + index++; + + for(j=1;j<5;j++) + { + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=indexvals2[j]; + currentcol->green=255; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + } + + for(i=0;i<4;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=255; + currentcol->green=152; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=102; + currentcol->blue=51; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=102; + currentcol->blue=0; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=102; + currentcol->blue=255; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=102; + currentcol->blue=203; + index++; + + // Mostly array runs from here on out + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=203; + currentcol->green=203; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=152; + currentcol->green=255; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=102; + currentcol->green=255; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=51; + currentcol->green=255; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=255; + currentcol->green=102; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=102; + currentcol->blue=152; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=102; + currentcol->blue=102; + index++; + + // knocks out 4 assignment loops at once :) + for(j=1;j<5;j++) + { + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=indexvals2[j]; + currentcol->green=152; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + } + + currentcol+=sizeof(rgb_color); + currentcol->red=230; + currentcol->green=134; + currentcol->blue=0; + index++; + + for(i=1;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=255; + currentcol->green=51; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=102; + currentcol->blue=51; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=102; + currentcol->blue=0; + index++; + + for(j=1;j<5;j++) + { + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=indexvals2[j]; + currentcol->green=102; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + } + + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=255; + currentcol->green=0; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=175; + currentcol->blue=19; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=51; + currentcol->blue=255; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=51; + currentcol->blue=203; + index++; + + for(j=1;j<5;j++) + { + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=indexvals2[j]; + currentcol->green=51; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + } + + for(i=3;i>=0;i--,index++) + { + currentcol=&(palette[index]); + currentcol->red=255; + currentcol->green=203; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + for(i=2;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=0; + currentcol->green=51; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + for(i=0;i<5;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=203; + currentcol->green=0; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=227; + currentcol->blue=70; + index++; + + for(j=2;j<6;j++) + { + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=indexvals2[j]; + currentcol->green=0; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + } + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=203; + currentcol->blue=51; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=203; + currentcol->blue=0; + index++; + + for(i=5;i<=0;i--,index++) + { + currentcol=&(palette[index]); + currentcol->red=255; + currentcol->green=255; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + +} diff --git a/src/servers/app/proto6/SystemPalette.h b/src/servers/app/proto6/SystemPalette.h new file mode 100644 index 0000000000..1bc1d7188a --- /dev/null +++ b/src/servers/app/proto6/SystemPalette.h @@ -0,0 +1,9 @@ +#ifndef _SYSTEM_PALETTE_H_ +#define _SYSTEM_PALETTE_H_ + +#include + +void GenerateSystemPalette(rgb_color *palette); +extern rgb_color system_palette[]; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/ViewDriver.cpp b/src/servers/app/proto6/ViewDriver.cpp new file mode 100644 index 0000000000..3f8f090d52 --- /dev/null +++ b/src/servers/app/proto6/ViewDriver.cpp @@ -0,0 +1,1084 @@ +/* + ViewDriver: + First, slowest, and easiest driver class in the app_server which is designed + to utilize the BeOS graphics functions to cut out a lot of junk in getting the + drawing infrastructure in this server. + + The concept is to have VDView::Draw() draw a bitmap, which is a "frame buffer" + of sorts, utilize a second view to write to it. This cuts out + the most problems with having a crapload of code to get just right without + having to write a bunch of unit tests + + Components: 3 classes, VDView, VDWindow, and ViewDriver + + ViewDriver - a wrapper class which mostly posts messages to the VDWindow + VDWindow - does most of the work. + VDView - doesn't do all that much except display the rendered bitmap +*/ + +#define DEBUG_DRIVER_MODULE +//#define DEBUG_SERVER_EMU + +//#define DISABLE_SERVER_EMU + +#include +#include +#include +#include +#include +#include +#include +#include "PortLink.h" +#include "ServerProtocol.h" +#include "ServerBitmap.h" +#include "ViewDriver.h" +#include "ServerCursor.h" +#include "DebugTools.h" + +enum +{ +VDWIN_CLEAR=100, + +VDWIN_SHOWCURSOR, +VDWIN_HIDECURSOR, +VDWIN_OBSCURECURSOR, +VDWIN_MOVECURSOR, +VDWIN_SETCURSOR, +}; + +ViewDriver *viewdriver_global; + +VDView::VDView(BRect bounds) + : BView(bounds,"viewdriver_view",B_FOLLOW_ALL, B_WILL_DRAW) +{ + viewbmp=new BBitmap(bounds,B_RGB32,true); + + // This link for sending mouse messages to the OBAppServer. + // This is only to take the place of the Input Server. I suppose I could write + // an addon filter to be more like the Input Server, but then I wouldn't be working + // on this thing! :P + serverlink=new PortLink(find_port(SERVER_INPUT_PORT)); + +#ifdef DEBUG_DRIVER_MODULE + printf("VDView: app_server input port: %ld\n",serverlink->GetPort()); +#endif + + // Create a cursor which isn't just a box + cursor=new BBitmap(BRect(0,0,20,20),B_RGBA32,true); + BView *v=new BView(cursor->Bounds(),"v", B_FOLLOW_NONE, B_WILL_DRAW); + hide_cursor=0; + + cursor->Lock(); + cursor->AddChild(v); + + v->SetHighColor(255,255,255,0); + v->FillRect(cursor->Bounds()); + v->SetHighColor(255,0,0,255); + v->FillTriangle(cursor->Bounds().LeftTop(),cursor->Bounds().RightTop(),cursor->Bounds().LeftBottom()); + + cursor->RemoveChild(v); + cursor->Unlock(); + + cursorframe=cursor->Bounds(); + oldcursorframe=cursor->Bounds(); +} + +VDView::~VDView(void) +{ + delete serverlink; + delete viewbmp; + delete cursor; +} + +void VDView::AttachedToWindow(void) +{ +} + +void VDView::Draw(BRect rect) +{ + if(viewbmp) + { + DrawBitmapAsync(viewbmp,oldcursorframe,oldcursorframe); + DrawBitmapAsync(viewbmp,rect,rect); + + if(hide_cursor==0 && obscure_cursor==false) + { + SetDrawingMode(B_OP_ALPHA); + DrawBitmapAsync(cursor,cursor->Bounds(),cursorframe); + SetDrawingMode(B_OP_COPY); + } + Sync(); + } +} + +// These functions emulate the Input Server by sending the *exact* same kind of messages +// to the server's port. Being we're using a regular window, it would make little sense +// to do anything else. + +void VDView::MouseDown(BPoint pt) +{ +#ifdef DEBUG_SERVER_EMU +printf("ViewDriver::MouseDown\t"); +#endif + // Attach data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - modifier keys down + // 5) int32 - buttons down + // 6) int32 - clicks +#ifndef DISABLE_SERVER_EMU + BPoint p; + + uint32 buttons, + mod=modifiers(), + clicks=1; // can't get the # of clicks without a *lot* of extra work :( + + int64 time=(int64)real_time_clock(); + + GetMouse(&p,&buttons); + + serverlink->SetOpCode(B_MOUSE_DOWN); + serverlink->Attach(&time, sizeof(int64)); + serverlink->Attach(&pt.x,sizeof(float)); + serverlink->Attach(&pt.y,sizeof(float)); + serverlink->Attach(&mod, sizeof(uint32)); + serverlink->Attach(&buttons, sizeof(uint32)); + serverlink->Attach(&clicks, sizeof(uint32)); + serverlink->Flush(); +#endif +} + +void VDView::MouseMoved(BPoint pt, uint32 transit, const BMessage *msg) +{ + // Attach data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - buttons down +#ifndef DISABLE_SERVER_EMU + BPoint p; + uint32 buttons; + int64 time=(int64)real_time_clock(); + + serverlink->SetOpCode(B_MOUSE_MOVED); + serverlink->Attach(&time,sizeof(int64)); + serverlink->Attach(&pt.x,sizeof(float)); + serverlink->Attach(&pt.y,sizeof(float)); + GetMouse(&p,&buttons); + serverlink->Attach(&buttons,sizeof(int32)); + serverlink->Flush(); +#endif +} + +void VDView::MouseUp(BPoint pt) +{ +#ifdef DEBUG_SERVER_EMU +printf("ViewDriver::MouseUp\t"); +#endif + // Attach data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - modifier keys down +#ifndef DISABLE_SERVER_EMU + BPoint p; + + uint32 buttons, + mod=modifiers(); + + int64 time=(int64)real_time_clock(); + + GetMouse(&p,&buttons); + + serverlink->SetOpCode(B_MOUSE_UP); + serverlink->Attach(&time, sizeof(int64)); + serverlink->Attach(&pt.x,sizeof(float)); + serverlink->Attach(&pt.y,sizeof(float)); + serverlink->Attach(&mod, sizeof(uint32)); + serverlink->Flush(); +#endif +} + +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- + +VDWindow::VDWindow(void) + : BWindow(BRect(100,60,740,540),"OBOS App Server, P6",B_TITLED_WINDOW, + B_NOT_ZOOMABLE | B_NOT_RESIZABLE) +{ + view=new VDView(Bounds()); + AddChild(view); +} + +VDWindow::~VDWindow(void) +{ +} + +void VDWindow::MessageReceived(BMessage *msg) +{ + switch(msg->what) + { + case VDWIN_SHOWCURSOR: + { + if(view->hide_cursor>0) + { + view->hide_cursor--; +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: ShowCursor() - still hidden\n"); +#endif + } + if(view->hide_cursor==0) + { +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: ShowCursor() - cursor shown\n"); +#endif + view->Invalidate(view->cursorframe); + } + break; + } + case VDWIN_HIDECURSOR: + { + view->hide_cursor++; +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: HideCursor()\n"); +#endif + if(view->hide_cursor==1) + { +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: HideCursor() - cursor was hidden\n"); +#endif + view->Invalidate(view->cursorframe); + } + break; + } + case VDWIN_OBSCURECURSOR: + { +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: ObscureCursor()\n"); +#endif + view->obscure_cursor=true; + view->Invalidate(view->cursorframe); + break; + } + case VDWIN_MOVECURSOR: + { + float x,y; + msg->FindFloat("x",&x); + msg->FindFloat("y",&y); + + // this was changed because an extra message was + // sent even though the mouse was never moved + if(view->cursorframe.left!=x || view->cursorframe.top!=y) + { + if(view->obscure_cursor) + view->obscure_cursor=false; + + view->oldcursorframe=view->cursorframe; + view->cursorframe.OffsetTo(x,y); + } + + if(view->hide_cursor==0) + view->Invalidate(view->oldcursorframe); + break; + } + case VDWIN_SETCURSOR: + { +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: SetCursor()\n"); +#endif + ServerCursor *cdata; + msg->FindPointer("SCursor",(void**)&cdata); + + if(cdata!=NULL) + { + BBitmap *bmp=new BBitmap(BRect(0,0,cdata->width-1,cdata->height-1), + cdata->cspace); + + // Copy the server bitmap in the cursor to a BBitmap + uint8 *sbmppos=(uint8*)cdata->bitmap->Buffer(), + *bbmppos=(uint8*)bmp->Bits(); + + int32 bytes=cdata->bitmap->bytesperline, + bbytes=bmp->BytesPerRow(); + + for(int i=0;iheight;i++) + memcpy(bbmppos+(i*bbytes), sbmppos+(i*bytes), bytes); + + // Replace the bitmap + delete view->cursor; + view->cursor=bmp; + view->Invalidate(view->cursorframe); + break; + } + break; + } + default: + BWindow::MessageReceived(msg); + break; + } +} + +bool VDWindow::QuitRequested(void) +{ + port_id serverport=find_port(SERVER_PORT_NAME); + + if(serverport!=B_NAME_NOT_FOUND) + write_port(serverport,B_QUIT_REQUESTED,NULL,0); + + return true; +} + +void VDWindow::WindowActivated(bool active) +{ + // This is just to hide the regular system cursor so we can see our own + if(active) + be_app->HideCursor(); + else + be_app->ShowCursor(); +} + +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- + +ViewDriver::ViewDriver(void) +{ + viewdriver_global=this; + screenwin=new VDWindow(); + framebuffer=screenwin->view->viewbmp; + serverlink=screenwin->view->serverlink; + hide_cursor=0; +} + +ViewDriver::~ViewDriver(void) +{ + if(is_initialized) + { + screenwin->Lock(); + screenwin->Quit(); + } +} + +void ViewDriver::Initialize(void) +{ + drawview=new BView(framebuffer->Bounds(),"drawview",B_FOLLOW_ALL, B_WILL_DRAW); + framebuffer->AddChild(drawview); + + hide_cursor=0; + obscure_cursor=false; + + SetPenSize(1.0); + MovePenTo(BPoint(0,0)); + is_initialized=true; + + // We can afford to call the above functions without locking + // because the window is locked until Show() is first called + screenwin->Show(); +} + +void ViewDriver::Shutdown(void) +{ + locker->Lock(); + is_initialized=false; + locker->Unlock(); +} + +bool ViewDriver::IsInitialized(void) +{ + return is_initialized; +} + +void ViewDriver::SafeMode(void) +{ + SetScreen(B_8_BIT_640x480); +} + +void ViewDriver::Reset(void) +{ + SafeMode(); + Clear(255,255,255); +} + +void ViewDriver::SetScreen(uint32 space) +{ + screenwin->Lock(); + int16 w=640,h=480; + color_space s; + + switch(space) + { + case B_32_BIT_800x600: + case B_16_BIT_800x600: + case B_8_BIT_800x600: + { + w=800; h=600; + break; + } + case B_32_BIT_1024x768: + case B_16_BIT_1024x768: + case B_8_BIT_1024x768: + { + w=1024; h=768; + break; + } + default: + break; + } + screenwin->ResizeTo(w-1,h-1); + + switch(space) + { + case B_32_BIT_640x480: + case B_32_BIT_800x600: + case B_32_BIT_1024x768: + s=B_RGBA32; + break; + case B_16_BIT_640x480: + case B_16_BIT_800x600: + case B_16_BIT_1024x768: + s=B_RGBA15; + break; + case B_8_BIT_640x480: + case B_8_BIT_800x600: + case B_8_BIT_1024x768: + s=B_CMAP8; + break; + default: + break; + } + + + delete framebuffer; + + screenwin->view->viewbmp=new BBitmap(BRect(0,0,w-1,h-1),s,true); + framebuffer=screenwin->view->viewbmp; + drawview=new BView(framebuffer->Bounds(),"drawview",B_FOLLOW_ALL, B_WILL_DRAW); + framebuffer->AddChild(drawview); + + screenwin->Unlock(); +} + +void ViewDriver::Clear(uint8 red, uint8 green, uint8 blue) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->SetHighColor(red,green,blue); + drawview->FillRect(drawview->Bounds()); + drawview->Sync(); + screenwin->view->Invalidate(); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::Clear(rgb_color col) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->SetHighColor(col); + drawview->FillRect(drawview->Bounds()); + drawview->Sync(); + screenwin->view->Invalidate(); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +int32 ViewDriver::GetHeight(void) +{ + screenwin->Lock(); + int32 h=bufferheight; + screenwin->Unlock(); + + return h; +} + +int32 ViewDriver::GetWidth(void) +{ + screenwin->Lock(); + int32 w=bufferwidth; + screenwin->Unlock(); + + return w; +} + +int ViewDriver::GetDepth(void) +{ + screenwin->Lock(); + int d=bufferdepth; + screenwin->Unlock(); + + return d; +} + +void ViewDriver::AddLine(BPoint pt1, BPoint pt2, rgb_color col) +{ + drawview->AddLine(pt1,pt2,col); + laregion.Include(BRect(pt1,pt2)); +} + +void ViewDriver::BeginLineArray(int32 count) +{ + // NOTE: the unlocking is done in EndLineArray()! + screenwin->Lock(); + framebuffer->Lock(); + laregion.MakeEmpty(); + drawview->BeginLineArray(count); +} + +void ViewDriver::Blit(BRect src, BRect dest) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->CopyBits(src,dest); + drawview->Sync(); + screenwin->view->Invalidate(dest); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::DrawBitmap(ServerBitmap *bitmap) +{ +} + +void ViewDriver::DrawLineArray(int32 count,BPoint *start, BPoint *end, rgb_color *color) +{ + screenwin->Lock(); + framebuffer->Lock(); + + BRegion invalid; + drawview->BeginLineArray(count+1); + for(int32 i=0;iAddLine(start[i],end[i],color[i]); + invalid.Include(BRect(start[i],end[i])); + } + drawview->EndLineArray(); + drawview->Sync(); + screenwin->view->Invalidate(invalid.Frame()); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::DrawChar(char c, BPoint point) +{ + char string[2]; + string[0]=c; + string[1]='\0'; + DrawString(string,2,point); +} + +void ViewDriver::DrawString(char *string, int length, BPoint point) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->DrawString(string,length,point); + font_height fheight; + drawview->GetFontHeight(&fheight); + BRect invalid(point,BPoint(point.x+drawview->StringWidth(string,length), + fheight.ascent+5)); + drawview->Sync(); + screenwin->view->Invalidate(invalid); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::EndLineArray(void) +{ + // NOTE: the locking is done in BeginLineArray()! + drawview->EndLineArray(); + drawview->Sync(); + screenwin->view->Invalidate(laregion.Frame()); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::FillArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pat) +{ + screenwin->Lock(); + framebuffer->Lock(); + if(pat!=NULL) + drawview->FillArc(BPoint(centerx,centery),xradius,yradius,angle,span,*((pattern*)pat)); + else + drawview->FillArc(BPoint(centerx,centery),xradius,yradius,angle,span); + drawview->Sync(); + screenwin->view->Invalidate(BRect(centerx-xradius,centery-yradius, + centerx+xradius,centery+yradius)); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::FillBezier(BPoint *points, uint8 *pat) +{ + screenwin->Lock(); + framebuffer->Lock(); + if(pat!=NULL) + drawview->FillBezier(points,*((pattern*)pat)); + else + drawview->FillBezier(points); + drawview->Sync(); + + // Invalidate the whole view until I get around to adding in the invalid rect calc code + screenwin->view->Invalidate(); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::FillEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pat) +{ + screenwin->Lock(); + framebuffer->Lock(); + if(pat!=NULL) + drawview->FillEllipse(BPoint(centerx,centery),x_radius,y_radius,*((pattern*)pat)); + else + drawview->FillEllipse(BPoint(centerx,centery),x_radius,y_radius); + drawview->Sync(); + screenwin->view->Invalidate(BRect(centerx-x_radius,centery-y_radius, + centerx+x_radius,centery+y_radius)); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::FillPolygon(int *x, int *y, int numpoints, bool is_closed) +{ +} + +void ViewDriver::FillRect(BRect rect, uint8 *pat) +{ + screenwin->Lock(); + framebuffer->Lock(); + if(pat!=NULL) + drawview->FillRect(rect,*((pattern*)pat)); + else + drawview->FillRect(rect); + drawview->Sync(); + screenwin->view->Invalidate(rect); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::FillRect(BRect rect, rgb_color col) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->SetHighColor(col); + drawview->FillRect(rect); + drawview->SetHighColor(highcolor); + drawview->Sync(); + screenwin->view->Invalidate(rect); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::FillRegion(BRegion *region) +{ +} + +void ViewDriver::FillRoundRect(BRect rect,float xradius, float yradius, uint8 *pat) +{ + screenwin->Lock(); + framebuffer->Lock(); + if(pat!=NULL) + drawview->FillRoundRect(rect,xradius,yradius,*((pattern*)pat)); + else + drawview->FillRoundRect(rect,xradius,yradius); + drawview->Sync(); + screenwin->view->Invalidate(rect); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::FillShape(BShape *shape) +{ +} + +void ViewDriver::FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pat) +{ + screenwin->Lock(); + framebuffer->Lock(); + if(pat!=NULL) + drawview->FillTriangle(first,second,third,rect,*((pattern*)pat)); + else + drawview->FillTriangle(first,second,third,rect); + drawview->Sync(); + screenwin->view->Invalidate(rect); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, rgb_color col) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->SetHighColor(col); + drawview->FillTriangle(first,second,third,rect); + drawview->SetHighColor(highcolor); + drawview->Sync(); + screenwin->view->Invalidate(rect); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::HideCursor(void) +{ + screenwin->Lock(); + locker->Lock(); + + hide_cursor++; + screenwin->PostMessage(VDWIN_HIDECURSOR); + + locker->Unlock(); + screenwin->Unlock(); + +} + +bool ViewDriver::IsCursorHidden(void) +{ + screenwin->Lock(); + bool value=(hide_cursor>0)?true:false; + screenwin->Unlock(); + return value; +} + +void ViewDriver::ObscureCursor(void) +{ + screenwin->Lock(); + screenwin->PostMessage(VDWIN_OBSCURECURSOR); + screenwin->Unlock(); +} + +void ViewDriver::MoveCursorTo(float x, float y) +{ + screenwin->Lock(); + BMessage *msg=new BMessage(VDWIN_MOVECURSOR); + msg->AddFloat("x",x); + msg->AddFloat("y",y); + screenwin->PostMessage(msg); + screenwin->Unlock(); +} + +void ViewDriver::MovePenTo(BPoint pt) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->MovePenTo(pt); + penpos=pt; + framebuffer->Unlock(); + screenwin->Unlock(); +} + +BPoint ViewDriver::PenPosition(void) +{ + return penpos; +} + +float ViewDriver::PenSize(void) +{ + return pensize; +} + +void ViewDriver::SetCursor(ServerCursor *cursor) +{ + if(cursor!=NULL) + { + screenwin->Lock(); + BBitmap *bmp=new BBitmap(BRect(0,0,cursor->width-1,cursor->height-1), + cursor->cspace); + + // Copy the server bitmap in the cursor to a BBitmap + uint8 *sbmppos=(uint8*)cursor->bitmap->Buffer(), + *bbmppos=(uint8*)bmp->Bits(); + + int32 bytes=cursor->bitmap->bytesperline, + bbytes=bmp->BytesPerRow(); + + for(int i=0;iheight;i++) + memcpy(bbmppos+(i*bbytes), sbmppos+(i*bytes), bytes); + + // Replace the bitmap + delete screenwin->view->cursor; + screenwin->view->cursor=bmp; + screenwin->view->Invalidate(screenwin->view->cursorframe); + screenwin->Unlock(); + } +} + +void ViewDriver::SetPenSize(float size) +{ + screenwin->Lock(); + framebuffer->Lock(); + pensize=size; + drawview->SetPenSize(size); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::SetHighColor(uint8 r,uint8 g,uint8 b,uint8 a=255) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->SetHighColor(r,g,b,a); + highcolor.red=r; + highcolor.green=g; + highcolor.blue=b; + highcolor.alpha=a; + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::SetHighColor(rgb_color col) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->SetHighColor(col); + highcolor=col; + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::SetLowColor(uint8 r,uint8 g,uint8 b,uint8 a=255) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->SetLowColor(r,g,b,a); + lowcolor.red=r; + lowcolor.green=g; + lowcolor.blue=b; + lowcolor.alpha=a; + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::SetLowColor(rgb_color col) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->SetLowColor(col); + lowcolor=col; + framebuffer->Unlock(); + screenwin->Unlock(); +} + +drawing_mode ViewDriver::GetDrawingMode(void) +{ + drawing_mode dm; + + screenwin->Lock(); + framebuffer->Lock(); + dm=drawview->DrawingMode(); + framebuffer->Unlock(); + screenwin->Unlock(); + return dm; +} + +void ViewDriver::SetDrawingMode(drawing_mode dmode) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->SetDrawingMode(dmode); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::SetPixel(int x, int y, uint8 *pattern) +{ +} + +void ViewDriver::ShowCursor(void) +{ + screenwin->Lock(); + if(hide_cursor>0) + { + hide_cursor--; + screenwin->PostMessage(VDWIN_SHOWCURSOR); + } + screenwin->Unlock(); +} + +float ViewDriver::StringWidth(const char *string, int32 length) +{ + return drawview->StringWidth(string,length); +} + +void ViewDriver::StrokeArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pat) +{ + screenwin->Lock(); + framebuffer->Lock(); + if(pat!=NULL) + drawview->StrokeArc(BPoint(centerx,centery),xradius,yradius,angle,span,*((pattern*)pat)); + else + drawview->StrokeArc(BPoint(centerx,centery),xradius,yradius,angle,span); + drawview->Sync(); + screenwin->view->Invalidate(BRect(centerx-xradius,centery-yradius, + centerx+xradius,centery+yradius)); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::StrokeBezier(BPoint *points, uint8 *pat) +{ + screenwin->Lock(); + framebuffer->Lock(); + if(pat!=NULL) + drawview->StrokeBezier(points,*((pattern*)pat)); + else + drawview->StrokeBezier(points); + drawview->Sync(); + + // Invalidate the whole view until I get around to adding in the invalid rect calc code + screenwin->view->Invalidate(); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::StrokeEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pat) +{ + screenwin->Lock(); + framebuffer->Lock(); + if(pat!=NULL) + drawview->StrokeEllipse(BPoint(centerx,centery),x_radius,y_radius,*((pattern*)pat)); + else + drawview->StrokeEllipse(BPoint(centerx,centery),x_radius,y_radius); + drawview->Sync(); + screenwin->view->Invalidate(BRect(centerx-x_radius,centery-y_radius, + centerx+x_radius,centery+y_radius)); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::StrokeLine(BPoint point, uint8 *pat) +{ + screenwin->Lock(); + framebuffer->Lock(); + if(pat!=NULL) + drawview->StrokeLine(point,*((pattern*)pat)); + else + drawview->StrokeLine(point); + drawview->Sync(); + screenwin->view->Invalidate(BRect(penpos,point)); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::StrokeLine(BPoint pt1, BPoint pt2, rgb_color col) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->SetHighColor(col); + drawview->StrokeLine(pt1,pt2); + drawview->SetHighColor(highcolor); + drawview->Sync(); + screenwin->view->Invalidate(BRect(pt1,pt2)); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::StrokePolygon(int *x, int *y, int numpoints, bool is_closed) +{ + screenwin->Lock(); + framebuffer->Lock(); + + BRegion invalid; + + drawview->BeginLineArray(numpoints+2); + BPoint start,end; + for(int i=1;iAddLine(start,end,highcolor); + invalid.Include(BRect(start,end)); + } + + if(is_closed) + { + start.Set(x[numpoints-1],y[numpoints-1]); + end.Set(x[0],y[0]); + drawview->AddLine(start,end,highcolor); + invalid.Include(BRect(start,end)); + } + drawview->EndLineArray(); + + drawview->Sync(); + screenwin->view->Invalidate(invalid.Frame()); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::StrokeRect(BRect rect, uint8 *pat) +{ + screenwin->Lock(); + framebuffer->Lock(); + if(pat!=NULL) + drawview->StrokeRect(rect,*((pattern*)pat)); + else + drawview->StrokeRect(rect); + drawview->Sync(); + screenwin->view->Invalidate(rect); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::StrokeRect(BRect rect, rgb_color col) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->SetHighColor(col); + drawview->StrokeRect(rect); + drawview->SetHighColor(highcolor); + drawview->Sync(); + screenwin->view->Invalidate(rect); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::StrokeRoundRect(BRect rect,float xradius, float yradius, uint8 *pat) +{ + screenwin->Lock(); + framebuffer->Lock(); + if(pat!=NULL) + drawview->StrokeRoundRect(rect,xradius,yradius,*((pattern*)pat)); + else + drawview->StrokeRoundRect(rect,xradius,yradius); + drawview->Sync(); + screenwin->view->Invalidate(rect); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::StrokeShape(BShape *shape) +{ +} + +void ViewDriver::StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pat) +{ + screenwin->Lock(); + framebuffer->Lock(); + if(pat!=NULL) + drawview->StrokeTriangle(first,second,third,rect,*((pattern*)pat)); + else + drawview->StrokeTriangle(first,second,third,rect); + drawview->Sync(); + screenwin->view->Invalidate(rect); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, rgb_color col) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->SetHighColor(col); + drawview->StrokeTriangle(first,second,third,rect); + drawview->SetHighColor(highcolor); + drawview->Sync(); + screenwin->view->Invalidate(rect); + framebuffer->Unlock(); + screenwin->Unlock(); +} diff --git a/src/servers/app/proto6/ViewDriver.h b/src/servers/app/proto6/ViewDriver.h new file mode 100644 index 0000000000..3514baa6c4 --- /dev/null +++ b/src/servers/app/proto6/ViewDriver.h @@ -0,0 +1,140 @@ +#ifndef _VIEWDRIVER_H_ +#define _VIEWDRIVER_H_ + +#include +#include +#include +#include +#include // for pattern struct +#include +#include +#include "DisplayDriver.h" + +class BBitmap; +class PortLink; +class VDWindow; +class ServerCursor; + +class VDView : public BView +{ +public: + VDView(BRect bounds); + ~VDView(void); + void AttachedToWindow(void); + void Draw(BRect rect); + void MouseDown(BPoint pt); + void MouseMoved(BPoint pt, uint32 transit, const BMessage *msg); + void MouseUp(BPoint pt); + + BBitmap *viewbmp; + PortLink *serverlink; + + int hide_cursor; + BBitmap *cursor; + + BRect cursorframe, oldcursorframe; + bool obscure_cursor; +}; + +class VDWindow : public BWindow +{ +public: + VDWindow(void); + ~VDWindow(void); + void MessageReceived(BMessage *msg); + bool QuitRequested(void); + void WindowActivated(bool active); + + VDView *view; +}; + +class ViewDriver : public DisplayDriver +{ +public: + ViewDriver(void); + ~ViewDriver(void); + + void Initialize(void); // Sets the driver + bool IsInitialized(void); + void Shutdown(void); // You never know when you'll need this + + void SafeMode(void); // Easy-access functions for common tasks + void Reset(void); + void Clear(uint8 red,uint8 green,uint8 blue); + void Clear(rgb_color col); + + // Settings functions + void SetScreen(uint32 space); + int32 GetHeight(void); + int32 GetWidth(void); + int GetDepth(void); + + // Drawing functions + void AddLine(BPoint pt1, BPoint pt2, rgb_color col); + void BeginLineArray(int32 count); + void Blit(BRect src, BRect dest); + void DrawBitmap(ServerBitmap *bitmap); + void DrawLineArray(int32 count,BPoint *start, BPoint *end, rgb_color *color); + void DrawChar(char c, BPoint point); + void DrawString(char *string, int length, BPoint point); + void EndLineArray(void); + + void FillArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern); + void FillBezier(BPoint *points, uint8 *pattern); + void FillEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern); + void FillPolygon(int *x, int *y, int numpoints, bool is_closed); + void FillRect(BRect rect, uint8 *pattern); + void FillRect(BRect rect, rgb_color col); + void FillRegion(BRegion *region); + void FillRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern); + void FillShape(BShape *shape); + void FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern); + void FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, rgb_color col); + + void HideCursor(void); + bool IsCursorHidden(void); + void MoveCursorTo(float x, float y); + void MovePenTo(BPoint pt); + void ObscureCursor(void); + BPoint PenPosition(void); + float PenSize(void); + void SetCursor(ServerCursor *cursor); + drawing_mode GetDrawingMode(void); + void SetDrawingMode(drawing_mode mode); + void SetHighColor(uint8 r,uint8 g,uint8 b,uint8 a=255); + void SetHighColor(rgb_color col); + void SetLowColor(uint8 r,uint8 g,uint8 b,uint8 a=255); + void SetLowColor(rgb_color col); + void SetPenSize(float size); + void SetPixel(int x, int y, uint8 *pattern); + void ShowCursor(void); + + float StringWidth(const char *string, int32 length); + void StrokeArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern); + void StrokeBezier(BPoint *points, uint8 *pattern); + void StrokeEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern); + void StrokeLine(BPoint point, uint8 *pattern); + void StrokeLine(BPoint pt1, BPoint pt2, rgb_color col); + void StrokePolygon(int *x, int *y, int numpoints, bool is_closed); + void StrokeRect(BRect rect,uint8 *pattern); + void StrokeRect(BRect rect,rgb_color col); + void StrokeRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern); + void StrokeShape(BShape *shape); + void StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern); + void StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, rgb_color col); + VDWindow *screenwin; +protected: + int hide_cursor; + bool obscure_cursor; + BBitmap *framebuffer; + BView *drawview; + + PortLink *serverlink; + // Region used to track of invalid areas for the Begin/EndLineArray functions + BRegion laregion; + rgb_color highcolor,lowcolor; + int32 bufferheight, bufferwidth; + int bufferdepth; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/WinDecorator.cpp b/src/servers/app/proto6/WinDecorator.cpp new file mode 100644 index 0000000000..c2a2f8632e --- /dev/null +++ b/src/servers/app/proto6/WinDecorator.cpp @@ -0,0 +1,441 @@ +#include "Layer.h" +#include "DisplayDriver.h" +#include +#include "WinDecorator.h" +#include "ColorUtils.h" + +//#define DEBUG_DECOR + +#ifdef DEBUG_DECOR +#include +#endif + +WinDecorator::WinDecorator(Layer *lay, uint32 dflags, uint32 wlook) + : Decorator(lay, dflags, wlook) +{ +#ifdef DEBUG_DECOR +printf("WinDecorator()\n"); +#endif + zoomstate=false; + closestate=false; + minstate=false; + taboffset=0; + + // These hard-coded assignments will go bye-bye when the system colors + // API is implemented + + SetRGBColor(&tab_highcol,100,100,255); + SetRGBColor(&tab_lowcol,40,0,255); + + SetRGBColor(&button_highercol,255,255,255); + SetRGBColor(&button_lowercol,0,0,0); + + button_highcol=MakeBlendColor(button_lowercol,button_highercol,0.85); + button_midcol=MakeBlendColor(button_lowercol,button_highercol,0.75); + button_lowcol=MakeBlendColor(button_lowercol,button_highercol,0.5); + + SetRGBColor(&frame_highercol,216,216,216); + SetRGBColor(&frame_lowercol,110,110,110); + + SetRGBColor(&textcol,0,0,0); + + frame_highcol=MakeBlendColor(frame_lowercol,frame_highercol,0.75); + frame_midcol=MakeBlendColor(frame_lowercol,frame_highercol,0.5); + frame_lowcol=MakeBlendColor(frame_lowercol,frame_highercol,0.25); + + Resize(lay->frame); + + textoffset=5; +} + +WinDecorator::~WinDecorator(void) +{ +#ifdef DEBUG_DECOR +printf("~WinDecorator()\n"); +#endif +} + +click_type WinDecorator::Clicked(BPoint pt, uint32 buttons) +{ + // Clicked is a hit-testing function which is called by each + // decorator object's respective WindowBorder. When a click or + // mouse message is received, we must return to the WindowBorder + // what the click meant to us and the appropriate action for it + // to take. + + // the case order is important - we go from smallest to largest + // for efficiency's sake. + if(closerect.Contains(pt)) + { + +#ifdef DEBUG_DECOR +printf("WinDecorator():Clicked() - Close\n"); +#endif + + return CLICK_CLOSE; + } + + if(zoomrect.Contains(pt)) + { + +#ifdef DEBUG_DECOR +printf("WinDecorator():Clicked() - Zoom\n"); +#endif + + return CLICK_ZOOM; + } + + if(minrect.Contains(pt)) + { + +#ifdef DEBUG_DECOR +printf("WinDecorator():Clicked() - Minimize\n"); +#endif + + return CLICK_MINIMIZE; + } + + // Clicking in the tab? + if(tabrect.Contains(pt)) + { + // Here's part of our window management stuff + if(buttons==B_PRIMARY_MOUSE_BUTTON && !focused) + return CLICK_MOVETOFRONT; + if(buttons==B_SECONDARY_MOUSE_BUTTON) + return CLICK_MOVETOBACK; + return CLICK_DRAG; + } + + // We got this far, so user is clicking on the border? + BRect brect(frame); + brect.top+=19; + BRect clientrect(brect.InsetByCopy(3,3)); + if(brect.Contains(pt) && !clientrect.Contains(pt)) + { +#ifdef DEBUG_DECOR +printf("WinDecorator():Clicked() - Resize\n"); +#endif + if(brect.Contains(pt)) + return CLICK_RESIZE; + } + + // Guess user didn't click anything +#ifdef DEBUG_DECOR +printf("WinDecorator():Clicked()\n"); +#endif + return CLICK_NONE; +} + +void WinDecorator::Resize(BRect rect) +{ + // Here we determine the size of every rectangle that we use + // internally when we are given the size of the client rectangle. + + // Current version simply makes everything fit inside the rect + // instead of building around it. This will change. + +#ifdef DEBUG_DECOR +printf("WinDecorator()::Resize()"); rect.PrintToStream(); +#endif + frame=rect; + tabrect=frame; + borderrect=frame; + + borderrect.top+=19; + + tabrect.bottom=tabrect.top+18; + + zoomrect=tabrect; + zoomrect.top+=4; + zoomrect.right-=4; + zoomrect.bottom-=4; + zoomrect.left=zoomrect.right-10; + zoomrect.bottom=zoomrect.top+10; + + closerect=zoomrect; + zoomrect.OffsetBy(0-zoomrect.Width()-4,0); + + minrect=zoomrect; + minrect.OffsetBy(0-zoomrect.Width()-2,0); + +} + +void WinDecorator::MoveBy(BPoint pt) +{ + // Move all internal rectangles the appropriate amount + frame.OffsetBy(pt); + closerect.OffsetBy(pt); + tabrect.OffsetBy(pt); + borderrect.OffsetBy(pt); + zoomrect.OffsetBy(pt); + minrect.OffsetBy(pt); +} + +BPoint WinDecorator::GetMinimumSize(void) +{ + // This is currently unused, but minsize is the minimum size the + // window may take. + return minsize; +} + +void WinDecorator::SetFlags(uint32 wflags) +{ + dflags=wflags; +} + +void WinDecorator::UpdateFont(void) +{ + // This will be updated once font capability is implemented +} + +void WinDecorator::UpdateTitle(const char *string) +{ + // Designed simply to redraw the title when it has changed on + // the client side. + if(string) + { + driver->SetDrawingMode(B_OP_OVER); + rgb_color tmpcol=driver->HighColor(); + driver->SetHighColor(textcol.red,textcol.green,textcol.blue); + driver->DrawString((char *)string,strlen(string), + BPoint(frame.left+textoffset,closerect.bottom-1)); + driver->SetHighColor(tmpcol.red,tmpcol.green,tmpcol.blue); + driver->SetDrawingMode(B_OP_COPY); + } + +} + +void WinDecorator::SetFocus(bool bfocused) +{ + // SetFocus() performs necessary duties for color swapping and + // other things when a window is deactivated or activated. + + focused=bfocused; + + if(focused) + { + SetRGBColor(&tab_highcol,100,100,255); + SetRGBColor(&tab_lowcol,40,0,255); + } + else + { + SetRGBColor(&tab_highcol,220,220,220); + SetRGBColor(&tab_lowcol,128,128,128); + } +} + +void WinDecorator::Draw(BRect update) +{ + // We need to draw a few things: the tab, the resize thumb, the borders, + // and the buttons + + if(tabrect.Intersects(update)) + DrawTab(); + + // Draw the top view's client area - just a hack :) + rgb_color blue={100,100,255,255}; + + if(borderrect.Intersects(update)) + driver->FillRect(borderrect,blue); + + DrawFrame(); +} + +void WinDecorator::Draw(void) +{ + // Easy way to draw everything - no worries about drawing only certain + // things + + DrawTab(); + + // Draw the top view's client area - just a hack :) + rgb_color blue={100,100,255,255}; + driver->FillRect(borderrect,blue); + + DrawFrame(); +} + +void WinDecorator::DrawZoom(BRect r) +{ + // If this has been implemented, then the decorator has a Zoom button + // which should be drawn based on the state of the member zoomstate + DrawBlendedRect(r,zoomstate); + + // Draw the Zoom box + driver->StrokeRect(r.InsetByCopy(2,2),textcol); +} + +void WinDecorator::DrawClose(BRect r) +{ + // Just like DrawZoom, but for a close button + DrawBlendedRect(r,closestate); + + // Draw the X + driver->StrokeLine(BPoint(closerect.left+2,closerect.top+2),BPoint(closerect.right-2, + closerect.bottom-2),textcol); + driver->StrokeLine(BPoint(closerect.right-2,closerect.top+2),BPoint(closerect.left+2, + closerect.bottom-2),textcol); +} + +void WinDecorator::DrawMinimize(BRect r) +{ + // Just like DrawZoom, but for a Minimize button + DrawBlendedRect(r,minstate); + + driver->StrokeLine(BPoint(minrect.left+2,minrect.bottom-2),BPoint(minrect.right-2, + minrect.bottom-2),textcol); +} + +void WinDecorator::DrawTab(void) +{ + // If a window has a tab, this will draw it and any buttons which are + // in it. + if(dlook==WLOOK_NO_BORDER) + return; + + rgb_color tmpcol; + float rstep,gstep,bstep; + + int steps=tabrect.IntegerWidth(); + rstep=float(tab_highcol.red-tab_lowcol.red)/steps; + gstep=float(tab_highcol.green-tab_lowcol.green)/steps; + bstep=float(tab_highcol.blue-tab_lowcol.blue)/steps; + + driver->StrokeRect(tabrect,frame_lowcol); + + driver->BeginLineArray(steps); + for(float i=1;iAddLine(BPoint(tabrect.left+i,tabrect.top+1), + BPoint(tabrect.left+i,tabrect.bottom-1),tmpcol); + } + driver->EndLineArray(); + UpdateTitle(layer->name->String()); + + // Draw the buttons if we're supposed to + if(!(dflags & NOT_CLOSABLE)) + DrawClose(closerect); + if(!(dflags & NOT_ZOOMABLE)) + DrawZoom(zoomrect); + if(!(dflags & NOT_MINIMIZABLE)) + DrawMinimize(minrect); +} + +void WinDecorator::DrawBlendedRect(BRect r, bool down) +{ + // This bad boy is used to draw a rectangle with a gradient. + // Note that it is not part of the Decorator API - it's specific + // to just the WinDecorator. Called by DrawZoom and DrawClose + BRect zr=r; + rgb_color startcol,endcol; + rgb_color start2col,end2col; + + if(down) + { + startcol=button_lowercol; + start2col=button_lowcol; + endcol=button_highercol; + end2col=button_highcol; + } + else + { + startcol=button_highercol; + start2col=button_highcol; + end2col=button_lowcol; + endcol=button_lowercol; + } + driver->BeginLineArray(8); + driver->AddLine(BPoint(zr.left,zr.top),BPoint(zr.right-1,zr.top),startcol); + driver->AddLine(BPoint(zr.left,zr.top),BPoint(zr.left,zr.bottom-1),startcol); + driver->AddLine(BPoint(zr.right,zr.top),BPoint(zr.right,zr.bottom),endcol); + driver->AddLine(BPoint(zr.left,zr.bottom),BPoint(zr.right,zr.bottom),endcol); + + zr.InsetBy(1,1); + driver->AddLine(BPoint(zr.left,zr.top),BPoint(zr.right-1,zr.top),start2col); + driver->AddLine(BPoint(zr.left,zr.top),BPoint(zr.left,zr.bottom-1),start2col); + driver->AddLine(BPoint(zr.right,zr.top),BPoint(zr.right,zr.bottom),end2col); + driver->AddLine(BPoint(zr.left,zr.bottom),BPoint(zr.right,zr.bottom),end2col); + driver->EndLineArray(); + zr.InsetBy(1,1); + driver->FillRect(zr,button_midcol); +} + +void WinDecorator::DrawFrame(void) +{ + // Duh, draws the window frame, I think. ;) + + if(dlook==WLOOK_NO_BORDER) + return; + + BRect r=borderrect; + + driver->BeginLineArray(12); + driver->AddLine(BPoint(r.left,r.top),BPoint(r.right-1,r.top), + frame_midcol); + driver->AddLine(BPoint(r.left,r.top),BPoint(r.left,r.bottom), + frame_lowcol); + driver->AddLine(BPoint(r.right,r.bottom),BPoint(r.right,r.top), + frame_lowercol); + driver->AddLine(BPoint(r.right,r.bottom),BPoint(r.left,r.bottom), + frame_lowercol); + + r.InsetBy(1,1); + driver->AddLine(BPoint(r.left,r.top),BPoint(r.right-1,r.top), + frame_highercol); + driver->AddLine(BPoint(r.left,r.top),BPoint(r.left,r.bottom), + frame_highercol); + driver->AddLine(BPoint(r.right,r.bottom),BPoint(r.right,r.top), + frame_midcol); + driver->AddLine(BPoint(r.right,r.bottom),BPoint(r.left,r.bottom), + frame_midcol); + + r.InsetBy(1,1); + driver->StrokeRect(r,frame_highcol); + + r.InsetBy(1,1); + driver->AddLine(BPoint(r.left,r.top),BPoint(r.right-1,r.top), + frame_lowercol); + driver->AddLine(BPoint(r.left,r.top),BPoint(r.left,r.bottom), + frame_lowercol); + driver->AddLine(BPoint(r.right,r.bottom),BPoint(r.right,r.top), + frame_highercol); + driver->AddLine(BPoint(r.right,r.bottom),BPoint(r.left,r.bottom), + frame_highercol); + driver->EndLineArray(); +} + +void WinDecorator::SetLook(uint32 wlook) +{ + dlook=wlook; +} + +void WinDecorator::CalculateBorders(void) +{ + // Here we calculate the size of the border on each side - how much the + // decorator's visible area "sticks out" past the client rectangle. + switch(dlook) + { + case WLOOK_NO_BORDER: + { + bsize.Set(0,0,0,0); + break; + } + case WLOOK_TITLED: + case WLOOK_DOCUMENT: + case WLOOK_BORDERED: + case WLOOK_MODAL: + case WLOOK_FLOATING: + { + bsize.top=18; + break; + } + default: + { + break; + } + } +} diff --git a/src/servers/app/proto6/WinDecorator.h b/src/servers/app/proto6/WinDecorator.h new file mode 100644 index 0000000000..1173035349 --- /dev/null +++ b/src/servers/app/proto6/WinDecorator.h @@ -0,0 +1,45 @@ +#ifndef _WIN_DECORATOR_H_ +#define _WIN_DECORATOR_H_ + +#include "Decorator.h" + +class WinDecorator: public Decorator +{ +public: + WinDecorator(Layer *lay, uint32 dflags, uint32 wlook); + ~WinDecorator(void); + + click_type Clicked(BPoint pt, uint32 buttons); + void Resize(BRect rect); + void MoveBy(BPoint pt); + BPoint GetMinimumSize(void); + void SetTitle(const char *newtitle); + void SetFlags(uint32 flags); + void SetLook(uint32 wlook); + void UpdateFont(void); + void UpdateTitle(const char *string); + void SetFocus(bool focused); + void Draw(void); + void Draw(BRect update); + void DrawZoom(BRect r); + void DrawClose(BRect r); + void DrawMinimize(BRect r); + void DrawTab(void); + void DrawFrame(void); + void CalculateBorders(void); + + void DrawBlendedRect(BRect r, bool down); + uint32 taboffset; + + rgb_color tab_highcol, tab_lowcol; + rgb_color button_highercol, button_lowercol; + rgb_color button_highcol, button_midcol, button_lowcol; + rgb_color frame_highcol, frame_midcol, frame_lowcol, frame_highercol, + frame_lowercol; + rgb_color textcol; + + BRect zoomrect,closerect,minrect,tabrect,frame,borderrect; + int textoffset; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/WindowBorder.cpp b/src/servers/app/proto6/WindowBorder.cpp new file mode 100644 index 0000000000..7499656837 --- /dev/null +++ b/src/servers/app/proto6/WindowBorder.cpp @@ -0,0 +1,370 @@ +#include +#include +#include +#include +#include "View.h" // for mouse button defines +#include "ServerWindow.h" +#include "WindowBorder.h" +#include "Decorator.h" +#include "Desktop.h" + +#define DEBUG_WINBORDER + +#ifdef DEBUG_WINBORDER +#include +#endif + +bool is_moving_window=false; +bool is_resizing_window=false; +extern ServerWindow *active_serverwindow; + +WindowBorder::WindowBorder(ServerWindow *win, const char *bordertitle) + : Layer((win==NULL)?BRect(0,0,1,1):win->frame, + (win==NULL)?NULL:win->title->String()) +{ +#ifdef DEBUG_WINBORDER +printf("WindowBorder()\n"); +#endif + mbuttons=0; + swin=win; + mousepos.Set(0,0); + update=false; + + title=new BString(bordertitle); + hresizewin=false; + vresizewin=false; + +} + +WindowBorder::~WindowBorder(void) +{ +#ifdef DEBUG_WINBORDER +printf("~WindowBorder()\n"); +#endif + delete title; +} + +void WindowBorder::MouseDown(BPoint pt, uint32 buttons) +{ + mbuttons=buttons; + click_type click=decor->Clicked(pt, mbuttons); + mousepos=pt; + + switch(click) + { + case CLICK_MOVETOBACK: + { + MoveToBack(); + break; + } + case CLICK_MOVETOFRONT: + { + MoveToFront(); + break; + } + case CLICK_CLOSE: + { +#ifdef DEBUG_WINBORDER +printf("WindowBorder(): SetCloseButton\n"); +#endif + decor->SetCloseButton(true); + decor->Draw(); + break; + } + case CLICK_ZOOM: + { +#ifdef DEBUG_WINBORDER +printf("WindowBorder(): SetZoomButton\n"); +#endif + decor->SetZoomButton(true); + decor->Draw(); + break; + } + case CLICK_MINIMIZE: + { +#ifdef DEBUG_WINBORDER +printf("WindowBorder(): SetMinimizeButton\n"); +#endif + decor->SetMinimizeButton(true); + decor->Draw(); + break; + } + case CLICK_DRAG: + { +#ifdef DEBUG_WINBORDER +printf("WindowBorder(): Click Tab\n"); +#endif + if(buttons==B_PRIMARY_MOUSE_BUTTON) + { + is_moving_window=true; + } + if(buttons==B_SECONDARY_MOUSE_BUTTON) + MoveToBack(); + break; + } + case CLICK_RESIZE: + { +#ifdef DEBUG_WINBORDER +printf("WindowBorder(): Click Resize\n"); +#endif + if(buttons==B_PRIMARY_MOUSE_BUTTON) + { + is_resizing_window=true; + } + break; + } + case CLICK_NONE: + { +#ifdef DEBUG_WINBORDER +printf("WindowBorder(): Click None\n"); +#endif + break; + } + default: + { +#ifdef DEBUG_WINBORDER +printf("WindowBorder()::MouseDown: Undefined click type\n"); +#endif + break; + } + } + if(click!=CLICK_NONE) + ActivateWindow(swin); +} + +void WindowBorder::MouseMoved(BPoint pt, uint32 buttons) +{ + click_type click=decor->Clicked(pt, mbuttons); + if(click!=CLICK_CLOSE && decor->GetCloseButton()) + { + decor->SetCloseButton(false); + decor->Draw(); + } + + if(click!=CLICK_ZOOM && decor->GetZoomButton()) + { + decor->SetZoomButton(false); + decor->Draw(); + } + + if(click!=CLICK_MINIMIZE && decor->GetMinimizeButton()) + { + decor->SetMinimizeButton(false); + decor->Draw(); + } + + if(is_moving_window==true) + { + float dx=pt.x-mousepos.x, + dy=pt.y-mousepos.y; + if(dx!=0 || dy!=0) + { + BRect oldmoveframe=swin->frame; + clientframe.OffsetBy(pt); + + swin->Lock(); + swin->frame.OffsetBy(dx,dy); + swin->Unlock(); + + layerlock->Lock(); +// InvalidateLowerSiblings(oldmoveframe); + parent->Invalidate(oldmoveframe); + MoveBy(dx,dy); + parent->RequestDraw(); + decor->MoveBy(BPoint(dx, dy)); + decor->Draw(); + layerlock->Unlock(); + } + } + if(is_resizing_window==true) + { + float dx=pt.x-mousepos.x, + dy=pt.y-mousepos.y; + if(dx!=0 || dy!=0) + { + clientframe.right+=dx; + clientframe.bottom+=dy; + + swin->Lock(); + swin->frame.right+=dx; + swin->frame.bottom+=dy; + swin->Unlock(); + + layerlock->Lock(); + ResizeBy(dx,dy); + parent->RequestDraw(); + layerlock->Unlock(); + decor->Resize(swin->frame); + decor->Draw(); + } + } + mousepos=pt; +} + +void WindowBorder::MouseUp(BPoint pt, uint32 buttons) +{ +// mbuttons&= ~buttons; + mbuttons=buttons; + is_moving_window=false; + is_resizing_window=false; + + click_type click=decor->Clicked(pt, mbuttons); + + switch(click) + { + case CLICK_CLOSE: + { + decor->SetCloseButton(false); + decor->Draw(); + + // call close window stuff here + + break; + } + case CLICK_ZOOM: + { + decor->SetZoomButton(false); + decor->Draw(); + + // call zoom stuff here + + break; + } + case CLICK_MINIMIZE: + { + decor->SetMinimizeButton(false); + decor->Draw(); + + // call minimize stuff here + + } + default: + { + break; + } + } +} + +void WindowBorder::Draw(BRect update_rect) +{ +#ifdef DEBUG_WINBORDER +printf("WindowBorder()::Draw():"); update_rect.PrintToStream(); +#endif + + if(update && visible!=NULL) + is_updating=true; + + decor->Draw(update_rect); + + if(update && visible!=NULL) + is_updating=false; +} + +void WindowBorder::SetDecorator(Decorator *newdecor) +{ + // AtheOS kills the decorator here. However, the decor + // under OBOS doesn't belong to the border - it belongs to the + // ServerWindow, so the ServerWindow will handle all (de)allocation + // tasks. We just need to update the pointer. +#ifdef DEBUG_WINBORDER +printf("WindowBorder::SetDecorator(%p)\n",newdecor); +#endif + if(newdecor) + { + decor=newdecor; +// if(visible) +// delete visible; +// visible=decor->GetFootprint(); + } +} + +ServerWindow *WindowBorder::Window(void) const +{ + return swin; +} +void WindowBorder::RequestDraw(void) +{ + if(invalid) + { +// for(int32 i=0; iCountRects();i++) +// decor->Draw(ConvertToTop(invalid->RectAt(i))); + decor->Draw(); + delete invalid; + invalid=NULL; + is_dirty=false; + } + +} + +void WindowBorder::InvalidateLowerSiblings(BRect r) +{ + // this is used to update the other windows when a window border + // is moved or resized. + Layer *lay; + BRect toprect=ConvertToTop(r); + + for(lay=uppersibling;lay!=NULL;lay=lay->uppersibling) + { + lay->Invalidate(toprect); + lay->RequestDraw(); + } +} + +void WindowBorder::MoveToBack(void) +{ +#ifdef DEBUG_WINBORDER +printf("WindowBorder(): MoveToBack\n"); +#endif + Layer *temp=NULL; + if(uppersibling) + temp=uppersibling; + + // Move the window to the back (the top of the tree) + Layer *top=GetRootLayer(); + ASSERT(top!=NULL); + layerlock->Lock(); + top->RemoveChild(this); + top->AddChild(this); + level=1; + swin->SetFocus(false); + decor->SetFocus(false); + decor->Draw(); + + if(temp) + ActivateWindow(uppersibling->serverwin); + layerlock->Unlock(); +} + +void WindowBorder::MoveToFront(void) +{ +#ifdef DEBUG_WINBORDER +printf("MoveToFront: \n"); +#endif + // Move the window to the front by making it the bottom + // child of the root layer + Layer *top=GetRootLayer(); + layerlock->Lock(); + + top->RemoveChild(this); + + // Make this the bottom child of the parent layer. Can't use + // AddChild(), so we'll manipulate the pointers directly. Remember, + // we need to change pointers for 4 layers - the parent, the + // uppersibling (if any), the lowersibling, and the layer in question + + // temporary placeholder while we exchange the data + Layer *templayer; + + // tweak parent + templayer=top->bottomchild; + top->bottomchild=this; + + // Tweak this layer + parent=top; + uppersibling=templayer; + uppersibling->lowersibling=this; + lowersibling=NULL; + + layerlock->Unlock(); + is_moving_window=true; +} diff --git a/src/servers/app/proto6/WindowBorder.h b/src/servers/app/proto6/WindowBorder.h new file mode 100644 index 0000000000..8463e822a8 --- /dev/null +++ b/src/servers/app/proto6/WindowBorder.h @@ -0,0 +1,39 @@ +#ifndef _WINBORDER_H_ +#define _WINBORDER_H_ + +#include +#include +#include "Layer.h" + +class ServerWindow; +class Decorator; + +class WindowBorder : public Layer +{ +public: + WindowBorder(ServerWindow *win, const char *bordertitle); + ~WindowBorder(void); + void MouseDown(BPoint pt, uint32 buttons); + void MouseMoved(BPoint pt, uint32 buttons); + void MouseUp(BPoint pt, uint32 buttons); + void Draw(BRect update); + void SystemColorsUpdated(void); + void SetDecorator(Decorator *newdecor); + ServerWindow *Window(void) const; + void RequestDraw(void); + void MoveToBack(void); + void MoveToFront(void); + + ServerWindow *swin; + BString *title; + Decorator *decor; + int32 flags; + BRect frame, clientframe; + uint32 mbuttons; + BPoint mousepos; + bool update; + bool hresizewin,vresizewin; +}; + +extern bool is_moving_window, is_resizing_window; +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/YMakDecorator.cpp b/src/servers/app/proto6/YMakDecorator.cpp new file mode 100644 index 0000000000..18324ec899 --- /dev/null +++ b/src/servers/app/proto6/YMakDecorator.cpp @@ -0,0 +1,660 @@ +/******************************************************* +* YMakDecorator +* +* Writen by YNOP. +* used BeOS Magnify and decor to try to figure out +* how it looks. +* Originaly writen on AtheOS as MakDadddy Decor. +* Hacked around several times, and then ported +* (by me again) to OBOS app_server Decorator API +* +* TODO +* Fix title issuse (We need a Font width to center by) +* Fix any issuse that came about via porting +* These may have to do with the fact that the origin is +* differnat for the two API's and also with the fact +* that we can test anything yet :P +* Border size should change with Font Height +* +* @author YNOP (ynop@beunited.org) +* @version 1 (p5) +*******************************************************/ + + +#include "Layer.h" +#include "DisplayDriver.h" +#include "YMakDecorator.h" + +//#define DEBUG_DECOR + +#ifdef DEBUG_DECOR +#include +#endif + +// Hardcoded sized .. TOP should be Font based... +#define TOP 22 +#define FRAME 6 + +/******************************************************* +* @description +*******************************************************/ +YMakDecorator::YMakDecorator(Layer *lay, uint32 flags, uint32 wlook) + :Decorator(lay, flags, wlook) +{ + if(dflags & WLOOK_NO_BORDER){ + LeftBorder = 0; + TopBorder = 0; + RightBorder = 0; + BottomBorder = 0; + }else{ + TopBorder = TOP; + LeftBorder = FRAME; + RightBorder = FRAME; + BottomBorder = FRAME; + } + Resize(lay->frame); +} + +/******************************************************* +* @description +*******************************************************/ +YMakDecorator::~YMakDecorator(void){ +} + +/******************************************************* +* @description +*******************************************************/ +click_type YMakDecorator::Clicked(BPoint pt, uint32 buttons){ +#ifdef DEBUG_DECOR +printf("YMakDecorator():Clicked(%f,%f)\n",pt.x,pt.y); +printf("ZoomRect:");ZoomRect.PrintToStream(); +#endif + + if(CloseRect.Contains(pt)){ + return CLICK_CLOSE; + } + if(ZoomRect.Contains(pt)){ + return CLICK_ZOOM; + } + + //return CLICK_RESIZE_RB; + //return CLICK_NONE; + return CLICK_DRAG; +} + +/******************************************************* +* @description +*******************************************************/ +void YMakDecorator::Resize(BRect rect){ + frame = rect; + + BRect But; + But.left = frame.left + 0; + But.right = frame.left + 12; + But.top = frame.top + 0; + But.bottom = frame.top + 12; + + CloseRect = But; + CloseRect.left += 4; + CloseRect.top += 4; + CloseRect.right += 4; + CloseRect.bottom += 4; + +} + +/******************************************************* +* @description +*******************************************************/ +BPoint YMakDecorator::GetMinimumSize(void){ + return minsize; +} + +/******************************************************* +* @description +*******************************************************/ +void YMakDecorator::SetFlags(uint32 flags){ + dflags=flags; +} + +/******************************************************* +* @description +*******************************************************/ +void YMakDecorator::UpdateFont(void){ +} + +/******************************************************* +* @description +*******************************************************/ +void YMakDecorator::UpdateTitle(const char *string){ +} + +/******************************************************* +* @description +*******************************************************/ +void YMakDecorator::SetFocus(bool bfocused){ + focused=bfocused; +} + +/******************************************************* +* @description +*******************************************************/ +void YMakDecorator::Draw(BRect update){ + BRect b = frame; + BRect cOBounds = frame; + + rgb_color cB = {0, 0, 0, 255}; + rgb_color cW = {251,251,251,255}; + rgb_color cG = {154,154,154,255}; + rgb_color cD = {113,113,113,255}; + rgb_color cL = {203,203,203,255}; + + // Debug yellow backgound to make sure we cover everthign :) + // Take this out in real ver for speed :P + rgb_color yellow = {255,255,0}; + driver->FillRect(frame,yellow); + + // Stroke outside border + driver->SetHighColor(cB.red,cB.green,cB.blue,cB.alpha); + driver->StrokeRect(b,NULL); + + // Stroke inside border + b = cOBounds; + b.top += TOP - 1; + b.bottom -= FRAME-1; + b.left += FRAME - 1; + b.right -= FRAME-1; + driver->StrokeRect(b,NULL); + + if(focused){ + // Stroke outer boder (raized) + b = cOBounds; + b.left += 1; + b.right -= 1; + b.top += 1; + b.bottom -= 1; + driver->SetHighColor(cW.red,cW.green,cW.blue,cW.alpha); + driver->MovePenTo(BPoint(b.left,b.top));driver->StrokeLine(BPoint(b.right,b.top),NULL); + + driver->MovePenTo(BPoint(b.left,b.bottom));driver->StrokeLine(BPoint(b.left,b.top),NULL); + driver->SetHighColor(cG.red,cG.green,cG.blue,cG.alpha); + driver->MovePenTo(BPoint(b.right,b.top));driver->StrokeLine(BPoint(b.right,b.bottom),NULL); + driver->MovePenTo(BPoint(b.right,b.bottom));driver->StrokeLine(BPoint(b.left,b.bottom),NULL); + + // Stroke inter border (raized) + b = cOBounds; + b.top += TOP - 2; + b.bottom -= FRAME - 2; + b.left += FRAME - 2; + b.right -= FRAME - 2; + driver->SetHighColor(cG.red,cG.green,cG.blue,cG.alpha); + driver->MovePenTo(BPoint(b.left,b.top));driver->StrokeLine(BPoint(b.right,b.top),NULL); + driver->MovePenTo(BPoint(b.left,b.bottom));driver->StrokeLine(BPoint(b.left,b.top),NULL); + driver->SetHighColor(cW.red,cW.green,cW.blue,cW.alpha); + driver->MovePenTo(BPoint(b.right,b.top));driver->StrokeLine(BPoint(b.right,b.bottom),NULL); + driver->MovePenTo(BPoint(b.right,b.bottom));driver->StrokeLine(BPoint(b.left,b.bottom),NULL); + + driver->SetHighColor(cL.red,cL.green,cL.blue,cL.alpha); + // Fill top + b = cOBounds; + b.bottom = b.top + TOP - 3; + b.top += 2; + b.left += 2; + b.right -= 2; + driver->FillRect(b,NULL); + // Fill left + b = cOBounds; + b.left += 2; + b.right = cOBounds.left + FRAME - 3; + b.top = cOBounds.top + TOP - 2; + b.bottom -= 2; + driver->FillRect(b,NULL); + // Fill right + b = cOBounds; + b.left = b.right - FRAME + 3; + b.right -= 2; + b.top = b.top + TOP - 2; + b.bottom -= 2; + driver->FillRect(b,NULL); + // fill bottom + b = cOBounds; + b.top = b.bottom - FRAME + 3; + b.bottom -= 2; + b.left += FRAME - 2; + b.right -= FRAME - 2; + driver->FillRect(b,NULL); + + // Stroke the lines .. stoke them oohh ya .. storkem .. + // + b = cOBounds; + b.left += 20; + b.right -= 20; + b.top += 4; + b.bottom += 10; + + //if((Flags & WND_NO_DEPTH_BUT) == 0){ + // b.right -= 20; + //} + +/* + driver->SetHighColor(cW.red,cW.green,cW.blue,cW.alpha); + driver->MovePenTo(BPoint(b.left,b.top+0));driver->StrokeLine(BPoint(b.right-1,b.top+0),NULL); + driver->MovePenTo(BPoint(b.left,b.top+2));driver->StrokeLine(BPoint(b.right-1,b.top+2),NULL); + driver->MovePenTo(BPoint(b.left,b.top+4));driver->StrokeLine(BPoint(b.right-1,b.top+4),NULL); + driver->MovePenTo(BPoint(b.left,b.top+6));driver->StrokeLine(BPoint(b.right-1,b.top+6),NULL); + driver->MovePenTo(BPoint(b.left,b.top+8));driver->StrokeLine(BPoint(b.right-1,b.top+8),NULL); + driver->MovePenTo(BPoint(b.left,b.top+10));driver->StrokeLine(BPoint(b.right-1,b.top+10),NULL); +*/ + // tightened the loop to reflect the changes in the DisplayDriver API + for(int j=0;j<12;j+=2) + driver->StrokeLine(BPoint(b.left,b.top+j),BPoint(b.right-1,b.top+j),cW); + +#ifdef DEBUG_DECOR +printf("About to draw high lines\n"); +printf("do done\n"); +#endif +/* + driver->SetHighColor(cD.red,cD.green,cD.blue,cD.alpha); + driver->MovePenTo(BPoint(b.left+1,b.top+1));driver->StrokeLine(BPoint(b.right,b.top+1),NULL); + driver->MovePenTo(BPoint(b.left+1,b.top+3));driver->StrokeLine(BPoint(b.right,b.top+3),NULL); + driver->MovePenTo(BPoint(b.left+1,b.top+5));driver->StrokeLine(BPoint(b.right,b.top+5),NULL); + driver->MovePenTo(BPoint(b.left+1,b.top+7));driver->StrokeLine(BPoint(b.right,b.top+7),NULL); + driver->MovePenTo(BPoint(b.left+1,b.top+9));driver->StrokeLine(BPoint(b.right,b.top+9),NULL); + driver->MovePenTo(BPoint(b.left+1,b.top+11));driver->StrokeLine(BPoint(b.right,b.top+11),NULL); +*/ + // tightened the loop to reflect the changes in the DisplayDriver API + for(int j=1;j<13;j+=2) + driver->StrokeLine(BPoint(b.left+1,b.top+j),BPoint(b.right,b.top+j),cD); + + }else{ + driver->SetHighColor(cL.red,cL.green,cL.blue,cL.alpha); + // Fill top + b = cOBounds; + b.bottom = b.top + TOP - 2; + b.top += 1; + b.left += 1; + b.right -= 1; + driver->FillRect(b,NULL); + // Fill left side + b = cOBounds; + b.left += 1; + b.right = b.left + FRAME - 2; + b.top = b.top + TOP - 1; + b.bottom -= 1; + driver->FillRect(b,NULL); + // fill right + b = cOBounds; + b.left = b.right - FRAME + 2; + b.right -= 1; + b.top = b.top + TOP - 1; + b.bottom -= 1; + driver->FillRect(b,NULL); + // fill bottom + b = cOBounds; + b.top = b.bottom - FRAME + 2; + b.bottom -= 1; + b.left += FRAME - 1; + b.right -= FRAME - 1; + driver->FillRect(b,NULL); + } + + +/* if((dflags & WND_NO_TITLE) == 0){ + // Stroke The title Text + driver->SetFgColor(cL.red,cL.green,cL.blue,cL.alpha); + b.left = 30; + b.right = 100; + //Font *font = new Font(DEFAULT_FONT_WINDOW); + //b.right = font->GetStringWidth(Title.c_str()); + + int32 len = strlen(Title.c_str()); + b.right = b.left + len * 7; + + + b.top = 2; + b.bottom = TOP - 3; + V->FillRect(b); + if(HasFocus){ + V->SetFgColor(0,0,0,255); + }else{ + V->SetFgColor(cD); + } + V->SetBgColor(cL); + V->MovePenTo(34,TOP-7); + V->DrawString(Title.c_str(), -1 ); + } +*/ + + + if(!(dflags & NOT_CLOSABLE)){ + DrawClose(CloseRect); + } + if(!(dflags & NOT_ZOOMABLE)){ + DrawZoom(ZoomRect); + } + + +/* if(!(dflags & NOT_RESIZABLE)) +*/ +} + +void YMakDecorator::Draw(void) +{ + BRect b = frame; + BRect cOBounds = frame; + + rgb_color cB = {0, 0, 0, 255}; + rgb_color cW = {251,251,251,255}; + rgb_color cG = {154,154,154,255}; + rgb_color cD = {113,113,113,255}; + rgb_color cL = {203,203,203,255}; + + // Debug yellow backgound to make sure we cover everthign :) + // Take this out in real ver for speed :P + rgb_color yellow = {255,255,0}; + driver->FillRect(frame,yellow); + + // Stroke outside border + driver->SetHighColor(cB.red,cB.green,cB.blue,cB.alpha); + driver->StrokeRect(b,NULL); + + // Stroke inside border + b = cOBounds; + b.top += TOP - 1; + b.bottom -= FRAME-1; + b.left += FRAME - 1; + b.right -= FRAME-1; + driver->StrokeRect(b,NULL); + + if(focused){ + // Stroke outer boder (raized) + b = cOBounds; + b.left += 1; + b.right -= 1; + b.top += 1; + b.bottom -= 1; + driver->SetHighColor(cW.red,cW.green,cW.blue,cW.alpha); + driver->MovePenTo(BPoint(b.left,b.top));driver->StrokeLine(BPoint(b.right,b.top),NULL); + + driver->MovePenTo(BPoint(b.left,b.bottom));driver->StrokeLine(BPoint(b.left,b.top),NULL); + driver->SetHighColor(cG.red,cG.green,cG.blue,cG.alpha); + driver->MovePenTo(BPoint(b.right,b.top));driver->StrokeLine(BPoint(b.right,b.bottom),NULL); + driver->MovePenTo(BPoint(b.right,b.bottom));driver->StrokeLine(BPoint(b.left,b.bottom),NULL); + + // Stroke inter border (raized) + b = cOBounds; + b.top += TOP - 2; + b.bottom -= FRAME - 2; + b.left += FRAME - 2; + b.right -= FRAME - 2; + driver->SetHighColor(cG.red,cG.green,cG.blue,cG.alpha); + driver->MovePenTo(BPoint(b.left,b.top));driver->StrokeLine(BPoint(b.right,b.top),NULL); + driver->MovePenTo(BPoint(b.left,b.bottom));driver->StrokeLine(BPoint(b.left,b.top),NULL); + driver->SetHighColor(cW.red,cW.green,cW.blue,cW.alpha); + driver->MovePenTo(BPoint(b.right,b.top));driver->StrokeLine(BPoint(b.right,b.bottom),NULL); + driver->MovePenTo(BPoint(b.right,b.bottom));driver->StrokeLine(BPoint(b.left,b.bottom),NULL); + + driver->SetHighColor(cL.red,cL.green,cL.blue,cL.alpha); + // Fill top + b = cOBounds; + b.bottom = b.top + TOP - 3; + b.top += 2; + b.left += 2; + b.right -= 2; + driver->FillRect(b,NULL); + // Fill left + b = cOBounds; + b.left += 2; + b.right = cOBounds.left + FRAME - 3; + b.top = cOBounds.top + TOP - 2; + b.bottom -= 2; + driver->FillRect(b,NULL); + // Fill right + b = cOBounds; + b.left = b.right - FRAME + 3; + b.right -= 2; + b.top = b.top + TOP - 2; + b.bottom -= 2; + driver->FillRect(b,NULL); + // fill bottom + b = cOBounds; + b.top = b.bottom - FRAME + 3; + b.bottom -= 2; + b.left += FRAME - 2; + b.right -= FRAME - 2; + driver->FillRect(b,NULL); + + // Stroke the lines .. stoke them oohh ya .. storkem .. + // + b = cOBounds; + b.left += 20; + b.right -= 20; + b.top += 4; + b.bottom += 10; + + //if((Flags & WND_NO_DEPTH_BUT) == 0){ + // b.right -= 20; + //} + +/* + driver->SetHighColor(cW.red,cW.green,cW.blue,cW.alpha); + + driver->MovePenTo(BPoint(b.left,b.top+0));driver->StrokeLine(BPoint(b.right-1,b.top+0),NULL); + driver->MovePenTo(BPoint(b.left,b.top+2));driver->StrokeLine(BPoint(b.right-1,b.top+2),NULL); + driver->MovePenTo(BPoint(b.left,b.top+4));driver->StrokeLine(BPoint(b.right-1,b.top+4),NULL); + driver->MovePenTo(BPoint(b.left,b.top+6));driver->StrokeLine(BPoint(b.right-1,b.top+6),NULL); + driver->MovePenTo(BPoint(b.left,b.top+8));driver->StrokeLine(BPoint(b.right-1,b.top+8),NULL); + driver->MovePenTo(BPoint(b.left,b.top+10));driver->StrokeLine(BPoint(b.right-1,b.top+10),NULL); +*/ + // tightened the loop to reflect the changes in the DisplayDriver API + for(int j=0;j<12;j+=2) + driver->StrokeLine(BPoint(b.left,b.top+j),BPoint(b.right-1,b.top+j),cW); + +#ifdef DEBUG_DECOR +printf("About to draw high lines\n"); +printf("do done\n"); +#endif +/* + driver->SetHighColor(cD.red,cD.green,cD.blue,cD.alpha); + + driver->MovePenTo(BPoint(b.left+1,b.top+1));driver->StrokeLine(BPoint(b.right,b.top+1),NULL); + driver->MovePenTo(BPoint(b.left+1,b.top+3));driver->StrokeLine(BPoint(b.right,b.top+3),NULL); + driver->MovePenTo(BPoint(b.left+1,b.top+5));driver->StrokeLine(BPoint(b.right,b.top+5),NULL); + driver->MovePenTo(BPoint(b.left+1,b.top+7));driver->StrokeLine(BPoint(b.right,b.top+7),NULL); + driver->MovePenTo(BPoint(b.left+1,b.top+9));driver->StrokeLine(BPoint(b.right,b.top+9),NULL); + driver->MovePenTo(BPoint(b.left+1,b.top+11));driver->StrokeLine(BPoint(b.right,b.top+11),NULL); +*/ + // tightened the loop to reflect the changes in the DisplayDriver API + for(int j=1;j<13;j+=2) + driver->StrokeLine(BPoint(b.left+1,b.top+j),BPoint(b.right,b.top+j),cD); + + }else{ + driver->SetHighColor(cL.red,cL.green,cL.blue,cL.alpha); + // Fill top + b = cOBounds; + b.bottom = b.top + TOP - 2; + b.top += 1; + b.left += 1; + b.right -= 1; + driver->FillRect(b,NULL); + // Fill left side + b = cOBounds; + b.left += 1; + b.right = b.left + FRAME - 2; + b.top = b.top + TOP - 1; + b.bottom -= 1; + driver->FillRect(b,NULL); + // fill right + b = cOBounds; + b.left = b.right - FRAME + 2; + b.right -= 1; + b.top = b.top + TOP - 1; + b.bottom -= 1; + driver->FillRect(b,NULL); + // fill bottom + b = cOBounds; + b.top = b.bottom - FRAME + 2; + b.bottom -= 1; + b.left += FRAME - 1; + b.right -= FRAME - 1; + driver->FillRect(b,NULL); + } + + +/* if((dflags & WND_NO_TITLE) == 0){ + // Stroke The title Text + driver->SetFgColor(cL.red,cL.green,cL.blue,cL.alpha); + b.left = 30; + b.right = 100; + //Font *font = new Font(DEFAULT_FONT_WINDOW); + //b.right = font->GetStringWidth(Title.c_str()); + + int32 len = strlen(Title.c_str()); + b.right = b.left + len * 7; + + + b.top = 2; + b.bottom = TOP - 3; + V->FillRect(b); + if(HasFocus){ + V->SetFgColor(0,0,0,255); + }else{ + V->SetFgColor(cD); + } + V->SetBgColor(cL); + V->MovePenTo(34,TOP-7); + V->DrawString(Title.c_str(), -1 ); + } +*/ + + + if(!(dflags & NOT_CLOSABLE)){ + DrawClose(CloseRect); + } + if(!(dflags & NOT_ZOOMABLE)){ + DrawZoom(ZoomRect); + } + +} + +/******************************************************* +* @description +*******************************************************/ +void YMakDecorator::DrawZoom(BRect r){ +// if(zoomstate) +} + +/******************************************************* +* @description +*******************************************************/ +void YMakDecorator::DrawClose(BRect r){ + BRect b = CloseRect; + + // if((dflags & WND_NO_CLOSE_BUT)){ return; } +// if(!HasFocus){ return; } + + + b.left += 1; + b.right -= 1; + b.top += 1; + b.bottom -= 1; + driver->SetHighColor(32,32,32,255); + /*V->DrawLine(Point(b.left,b.top),Point(b.right,b.top)); + V->DrawLine(Point(b.right,b.top),Point(b.right,b.bottom)); + V->DrawLine(Point(b.left,b.bottom),Point(b.left,b.top)); + V->DrawLine(Point(b.right,b.bottom),Point(b.left,b.bottom));*/ + driver->StrokeRect(b,NULL); + + + b = CloseRect; + + // top left higlith + driver->SetHighColor(136,136,136,255); + driver->MovePenTo(BPoint(b.left,b.top));driver->StrokeLine(BPoint(b.right-1,b.top),NULL); + driver->MovePenTo(BPoint(b.left,b.top+1));driver->StrokeLine(BPoint(b.left,b.bottom-1),NULL); + + // right bottom shadow + driver->SetHighColor(251,251,251,255); + driver->MovePenTo(BPoint(b.right,b.bottom));driver->StrokeLine(BPoint(b.left+1,b.bottom),NULL); + driver->MovePenTo(BPoint(b.right,b.bottom));driver->StrokeLine(BPoint(b.right,b.top+1),NULL); + + if(closestate){ + b = CloseRect; + b.left += 2; + b.right -= 2; + b.top += 2; + b.bottom -= 2; + + // Button down + driver->SetHighColor(200,200,200,255); + driver->FillRect(b,NULL); + }else{ + b = CloseRect; + b.left += 2; + b.right -= 2; + b.top += 2; + b.bottom -= 2; + + // top left + driver->SetHighColor(240,240,240,255); + driver->MovePenTo(BPoint(b.left,b.top));driver->StrokeLine(BPoint(b.right,b.top),NULL); + driver->MovePenTo(BPoint(b.left,b.top));driver->StrokeLine(BPoint(b.left,b.bottom),NULL); + + // bottom right + driver->SetHighColor(136,136,136,255); + driver->MovePenTo(BPoint(b.right,b.bottom));driver->StrokeLine(BPoint(b.left+1,b.bottom),NULL); + driver->MovePenTo(BPoint(b.right,b.bottom));driver->StrokeLine(BPoint(b.right,b.top+1),NULL); + + // fill insdie (Hacked - Mack is a gradiant in the button :P!!) + driver->SetHighColor(203,203,203,255); + b.left += 1; + b.right -= 1; + b.top += 1; + b.bottom -= 1; + driver->FillRect(b,NULL); + } +} + +/******************************************************* +* @description +*******************************************************/ +void YMakDecorator::SetLook(uint32 wlook){ + dlook = wlook; +} + +/******************************************************* +* @description +*******************************************************/ +void YMakDecorator::CalculateBorders(void){ + switch(dlook) + { + case WLOOK_NO_BORDER: + { +// bsize.Set(0,0,0,0); + break; + } + case WLOOK_TITLED: + case WLOOK_DOCUMENT: + case WLOOK_BORDERED: + { +// bsize.top=18; + break; + } + case WLOOK_MODAL: + case WLOOK_FLOATING: + { +// bsize.top=15; + break; + } + default: + { + break; + } + } +} + +void YMakDecorator::MoveBy(BPoint pt) +{ + frame.OffsetBy(pt); + CloseRect.OffsetBy(pt); + ZoomRect.OffsetBy(pt); +} \ No newline at end of file diff --git a/src/servers/app/proto6/YMakDecorator.h b/src/servers/app/proto6/YMakDecorator.h new file mode 100644 index 0000000000..0de389f28f --- /dev/null +++ b/src/servers/app/proto6/YMakDecorator.h @@ -0,0 +1,47 @@ +#ifndef _YNOP_MAK_DECORATOR_H_ +#define _YNOP_MAK_DECORATOR_H_ + +#include "Decorator.h" + +class YMakDecorator: public Decorator{ +public: + YMakDecorator(Layer *lay, uint32 dflags, uint32 wlook); + ~YMakDecorator(void); + + click_type Clicked(BPoint pt, uint32 buttons); + void Resize(BRect rect); + BPoint GetMinimumSize(void); + void SetTitle(const char *newtitle); + void SetFlags(uint32 flags); + void SetLook(uint32 wlook); + void UpdateFont(void); + void UpdateTitle(const char *string); + void SetFocus(bool focused); + void Draw(BRect update); + void Draw(void); + void DrawZoom(BRect r); + void DrawClose(BRect r); + void CalculateBorders(void); + void MoveBy(BPoint pt); +private: + BRect frame; + + bool zoomstate; + bool closestate; + + BRect CloseRect; + BRect ZoomRect; + + int LeftBorder; + int TopBorder; + int RightBorder; + int BottomBorder; +/* + bool HasFocus; + bool CloseState; + bool ZoomState; + bool DepthState; +*/ +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/driverharness/AppServer.cpp b/src/servers/app/proto6/driverharness/AppServer.cpp new file mode 100644 index 0000000000..9ee4e49423 --- /dev/null +++ b/src/servers/app/proto6/driverharness/AppServer.cpp @@ -0,0 +1,456 @@ +/* + AppServer.cpp + File for the main app_server thread. This particular thread monitors for + application start and quit messages. It also starts the housekeeping threads + and initializes most of the server's globals. +*/ +#include +#include +#include "scheduler.h" +#include +#include +#include +#include +#include +#include "AppServer.h" +#include "Desktop.h" +#include "ServerProtocol.h" +#include "ServerCursor.h" +#include "PortLink.h" +#include "DisplayDriver.h" +#include "DebugTools.h" +#include "ViewDriver.h" +#include "DirectDriver.h" +#include "ScreenDriver.h" + +//#define DEBUG_APPSERVER_THREAD + +AppServer::AppServer(void) : BApplication("application/x-vnd.obe-OBAppServer") +{ +#ifdef DEBUG_APPSERVER_THREAD + printf("AppServer()\n"); +#endif + + mouseport=create_port(30,SERVER_INPUT_PORT); + messageport=create_port(20,SERVER_PORT_NAME); +#ifdef DEBUG_APPSERVER_THREAD +printf("Server message port: %ld\n",messageport); +printf("Server input port: %ld\n",mouseport); +#endif + applist=new BList(0); + quitting_server=false; + exit_poller=false; + +// driver=new ViewDriver; +// driver=new DirectDriver; + driver=new ScreenDriver; + driver->Initialize(); + + // Spawn our input-polling thread + poller_id = spawn_thread(PollerThread, "Poller", B_NORMAL_PRIORITY, this); + if (poller_id >= 0) + resume_thread(poller_id); +} + +AppServer::~AppServer(void) +{ + // If these threads are still running, kill them - after this, if exit_poller + // is deleted, who knows what will happen... These things will just return an + // error and fail if the threads have already exited. + kill_thread(poller_id); + + driver->Shutdown(); + delete driver; + +} + +void AppServer::RunTests(void) +{ + driver->SetScreen(B_32_BIT_800x600); + driver->Clear(80,85,152); + +// TestScreenStates(); + TestArcs(); + TestBeziers(); + TestEllipses(); + TestLines(); + TestPolygon(); + TestRects(); + TestRegions(); + TestShape(); + TestTriangle(); + + TestCursors(); + TestFonts(); + +} + +thread_id AppServer::Run(void) +{ +#ifdef DEBUG_APPSERVER_THREAD +printf("AppServer::Run()\n"); +#endif + RunTests(); + MainLoop(); + return 0; +} + +void AppServer::MainLoop(void) +{ + // Main loop (duh). Monitors the message queue and dispatches as appropriate. + // Input messages are handled by the poller, however. + +#ifdef DEBUG_APPSERVER_THREAD +printf("AppServer::MainLoop()\n"); +#endif + + int32 msgcode; + int8 *msgbuffer=NULL; + ssize_t buffersize,bytesread; + + for(;;) + { + buffersize=port_buffer_size(messageport); + if(buffersize>0) + msgbuffer=new int8[buffersize]; + bytesread=read_port(messageport,&msgcode,msgbuffer,buffersize); + + if (bytesread != B_BAD_PORT_ID && bytesread != B_TIMED_OUT && bytesread != B_WOULD_BLOCK) + { + switch(msgcode) + { + case CREATE_APP: + case DELETE_APP: + case B_QUIT_REQUESTED: + DispatchMessage(msgcode,msgbuffer); + break; + default: + { +#ifdef DEBUG_APPSERVER_THREAD +printf("Server received unexpected code %ld\n",msgcode); +#endif + break; + } + } + + } + + if(buffersize>0) + delete msgbuffer; + if(msgcode==DELETE_APP || msgcode==B_QUIT_REQUESTED) + { + if(quitting_server==true && applist->CountItems()==0) + break; + } + } + // Make sure our polling thread has exited + if(find_thread("Poller")!=B_NAME_NOT_FOUND) + kill_thread(poller_id); + +} + + +void AppServer::DispatchMessage(int32 code, int8 *buffer) +{ + switch(code) + { + case B_QUIT_REQUESTED: + { + quitting_server=true; + exit_poller=true; + break; + } + default: + break; + } +} + +void AppServer::Poller(void) +{ + // This thread handles nothing but input messages for mouse and keyboard + int32 msgcode; + int8 *msgbuffer=NULL,*index; + ssize_t buffersize,bytesread; + + for(;;) + { + buffersize=port_buffer_size(mouseport); + if(buffersize>0) + msgbuffer=new int8[buffersize]; + bytesread=read_port(mouseport,&msgcode,msgbuffer,buffersize); + + if (bytesread != B_BAD_PORT_ID && bytesread != B_TIMED_OUT && bytesread != B_WOULD_BLOCK) + { + switch(msgcode) + { + // Process the cursor and then pass it on + case B_MOUSE_MOVED: + { + // Attached data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - buttons down + + index=msgbuffer; + + // Time sent is not necessary for cursor processing. + index += sizeof(int64); + + float tempx=0,tempy=0; + tempx=*((float*)index); + index+=sizeof(float); + tempy=*((float*)index); + index+=sizeof(float); + + driver->MoveCursorTo(tempx,tempy); + + break; + } + default: + //printf("Server::Poller received unexpected code %ld\n",msgcode); + break; + } + + } + + if(buffersize>0) + delete msgbuffer; + + if(exit_poller) + break; + } +} + +int32 AppServer::PollerThread(void *data) +{ +#ifdef DEBUG_APPSERVER_THREAD +printf("Starting Poller thread...\n"); +#endif + AppServer *server=(AppServer *)data; + + // This won't return until it's told to + server->Poller(); + +#ifdef DEBUG_APPSERVER_THREAD +printf("Exiting Poller thread...\n"); +#endif + exit_thread(B_OK); + return B_OK; +} + +void AppServer::TestScreenStates(void) +{ + driver->SetScreen(B_8_BIT_640x480); + snooze(3000000); + driver->SetScreen(B_8_BIT_800x600); +} + +void AppServer::TestArcs(void) +{ + driver->SetHighColor(0,0,255); + driver->FillArc(275,95,70,45,40,210,(uint8 *)&B_SOLID_HIGH); + + for(int i=0; i<45; i+=5) + { + driver->SetHighColor(128+(i*2),128+(i*2),128+(i*2)); + driver->StrokeArc(280+i,100+i,75+i,50+i,45+i,215+i,(uint8 *)&B_SOLID_HIGH); + } +} + +void AppServer::TestBeziers(void) +{ + BPoint pts[4]; + + pts[0].Set(500,300), + pts[1].Set(350,450), + pts[2].Set(350,300), + pts[3].Set(500,450); + + driver->SetHighColor(0,255,0); + driver->StrokeBezier(pts, (uint8 *)&B_SOLID_HIGH); + + // Fill Bezier + pts[0].Set(250,250), + pts[1].Set(300,300), + pts[2].Set(300,250), + pts[3].Set(300,250); + + driver->SetHighColor(255,0,0); + driver->FillBezier(pts, (uint8 *)&B_SOLID_HIGH); + +} + +void AppServer::TestEllipses(void) +{ + driver->SetHighColor(0,0,0); + driver->FillEllipse(200,200, 10, 5,(uint8*)&B_SOLID_HIGH); + + for(int i=5; i<255; i+=10) + { + driver->SetHighColor(i,i,i); + driver->StrokeEllipse(200,200, 10+i, 5+i,(uint8*)&B_SOLID_HIGH); + } + +} + +void AppServer::TestFonts(void) +{ + // Draw String + BString string("OpenBeOS: The Future is Drawing Near..."); + uint16 length=string.Length(); + + driver->SetHighColor(0,0,0); + driver->DrawString((char*)string.String(),length,BPoint(10,200)); +} + +void AppServer::TestLines(void) +{ + int32 i; + rgb_color col; + col.red=255; + col.green=0; + col.blue=0; + + driver->MovePenTo(BPoint(10,150)); + driver->SetHighColor(255,0,0); + + for(i=0;i<100;i++) + { + col.green=100+i; + col.blue=100+i; + driver->StrokeLine(BPoint(10,10),BPoint(10+i,100),col); + } + + for(i=0;i<100;i++) + driver->StrokeLine(BPoint(10+i,200),(uint8*)&B_SOLID_HIGH); + +// BPoint start[100],end[100]; +// rgb_color colarray[100]; + +/* for(i=0;i<100;i++) + { + start[i].Set(10,10); + end[i].Set(110,10+i); + colarray[i].red=100+i; + colarray[i].green=100+i; + colarray[i].blue=255; + } + driver->DrawLineArray(100,start,end,colarray); +*/ + driver->BeginLineArray(100); + for(i=0;i<100;i++) + { + col.red=100+i; + col.green=100+i; + col.blue=255; + driver->AddLine(BPoint(10,10),BPoint(110,10+i),col); + } + driver->EndLineArray(); +} + +void AppServer::TestPolygon(void) +{ + int x[]={10,20,30,40,50,40,30,20,10}; + int y[]={20,10,20,30,40,50,40,30,25}; + driver->StrokePolygon(x,y,9,false); +} + +void AppServer::TestRects(void) +{ + BRect rect(10,270,75,335); + + rgb_color col; + col.red=255; + col.green=255; + col.blue=0; + + driver->SetHighColor(255,0,0); + driver->StrokeRect(rect,(uint8*)&B_SOLID_HIGH); + + rect.InsetBy(1,1); + driver->SetHighColor(0,0,0); + driver->FillRect(rect,(uint8*)&B_SOLID_HIGH); + + rect.InsetBy(1,1); + driver->StrokeRect(rect,col); + + rect.InsetBy(1,1); + col.red=0; + driver->FillRect(rect,col); + + rect.OffsetBy(100,10); + driver->SetHighColor(0,255,0); + driver->StrokeRoundRect(rect,10,30,(uint8*)&B_SOLID_HIGH); + + rect.OffsetBy(100,10); + driver->SetHighColor(0,255,255); + driver->FillRoundRect(rect,10,30,(uint8*)&B_SOLID_HIGH); +} + +void AppServer::TestRegions(void) +{ +} + +void AppServer::TestShape(void) +{ +} + +void AppServer::TestTriangle(void) +{ + BRect invalid; + BPoint pt[3]; + pt[0].Set(600,100); + pt[1].Set(500,200); + pt[2].Set(550,450); + + invalid.Set( MIN( MIN(pt[0].x,pt[1].x), pt[2].x), + MIN( MIN(pt[0].y,pt[1].y), pt[2].y), + MAX( MAX(pt[0].x,pt[1].x), pt[2].x), + MAX( MAX(pt[0].y,pt[1].y), pt[2].y) ); + + driver->SetHighColor(228,228,50); + driver->FillTriangle(pt[0],pt[1],pt[2],invalid,(uint8*)&B_SOLID_HIGH); + + + pt[0].Set(50,50); + pt[1].Set(200,475); + pt[2].Set(400,400); + invalid.Set( MIN( MIN(pt[0].x,pt[1].x), pt[2].x), + MIN( MIN(pt[0].y,pt[1].y), pt[2].y), + MAX( MAX(pt[0].x,pt[1].x), pt[2].x), + MAX( MAX(pt[0].y,pt[1].y), pt[2].y) ); + // Stroke Triangle + driver->SetHighColor(0,128,128); + driver->StrokeTriangle(pt[0],pt[1],pt[2],invalid,(uint8*)&B_SOLID_HIGH); +} + +void AppServer::TestCursors(void) +{ + int8 cross[] = { 16,1,5,5, + 14,0,4,0,4,0,4,0,128,32,241,224,128,32,4,0, + 4,0,4,0,14,0,0,0,0,0,0,0,0,0,0,0, + 14,0,4,0,4,0,4,0,128,32,245,224,128,32,4,0, + 4,0,4,0,14,0,0,0,0,0,0,0,0,0,0,0 }; + + ServerCursor *crosscursor=new ServerCursor(cross); + driver->SetCursor(crosscursor); + + driver->HideCursor(); + driver->ShowCursor(); + driver->ObscureCursor(); + + delete crosscursor; +} + +int main( int argc, char** argv ) +{ + // There can be only one.... + if(find_port(SERVER_PORT_NAME)!=B_NAME_NOT_FOUND) + return -1; + + AppServer *app_server = new AppServer(); + app_server->Run(); + delete app_server; + return 0; +} diff --git a/src/servers/app/proto6/driverharness/AppServer.h b/src/servers/app/proto6/driverharness/AppServer.h new file mode 100644 index 0000000000..1a943b3946 --- /dev/null +++ b/src/servers/app/proto6/driverharness/AppServer.h @@ -0,0 +1,50 @@ +#ifndef _OPENBEOS_APP_SERVER_H_ +#define _OPENBEOS_APP_SERVER_H_ + +#include +#include +#include +#include +#include // for window_look + +class BMessage; +class DisplayDriver; + +class AppServer : public BApplication +{ +public: + AppServer(void); + ~AppServer(void); + thread_id Run(void); + void MainLoop(void); + port_id messageport,mouseport; + void Poller(void); + + void TestScreenStates(void); + void TestArcs(void); + void TestBeziers(void); + void TestEllipses(void); + void TestFonts(void); + void TestLines(void); + void TestPolygon(void); + void TestRects(void); + void TestRegions(void); + void TestShape(void); + void TestTriangle(void); + void TestCursors(void); + +private: + void RunTests(void); + void DispatchMessage(int32 code, int8 *buffer); + static int32 PollerThread(void *data); + bool quitting_server; + BList *applist; + int32 active_app; + thread_id poller_id; + + BLocker *active_lock, *applist_lock, *decor_lock; + bool exit_poller; + DisplayDriver *driver; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/driverharness/ColorUtils.cc b/src/servers/app/proto6/driverharness/ColorUtils.cc new file mode 100644 index 0000000000..fa413f3a13 --- /dev/null +++ b/src/servers/app/proto6/driverharness/ColorUtils.cc @@ -0,0 +1,46 @@ +#include "ColorUtils.h" +#include "SystemPalette.h" +#include +#include + +void SetRGBColor(rgb_color *col,uint8 r, uint8 g, uint8 b, uint8 a=255) +{ + col->red=r; + col->green=g; + col->blue=b; + col->alpha=a; +} + +uint8 FindClosestColor(rgb_color *palette, rgb_color color) +{ + // We will be passed a 256-color palette and a 24-bit color + uint16 cindex=0,cdelta=765,delta=765; + rgb_color *c; + + for(uint16 i=0;i<256;i++) + { + c=&(palette[i]); + delta=abs(c->red-color.red)+abs(c->green-color.green)+ + abs(c->blue-color.blue); + + if(delta==0) + { + cindex=i; + break; + } + + if(delta + +// Quick assignment for rgb_color structs +void SetRGBColor(rgb_color *col,uint8 r, uint8 g, uint8 b, uint8 a=255); + +// Given a color palette, returns the index of the closest match to +// the color passed to it. Alpha values are not considered +uint8 FindClosestColor(rgb_color *palette, rgb_color color); +uint16 FindClosestColor16(rgb_color color); +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/driverharness/DHApp.cpp b/src/servers/app/proto6/driverharness/DHApp.cpp new file mode 100644 index 0000000000..12092528bf --- /dev/null +++ b/src/servers/app/proto6/driverharness/DHApp.cpp @@ -0,0 +1,23 @@ +#include "DHApp.h" +#include "DisplayDriver.h" +#include "ViewDriver.h" + +DHApp::DHApp(void) : BApplication("application/x-vnd.obos-DDriverHarness") +{ + driver=new ViewDriver; + driver->Initialize(); +} + +DHApp::~DHApp(void) +{ + driver->Shutdown(); + delete driver; +} + +int main(void) +{ + DHApp *app=new DHApp; + app->Run(); + delete app; + return 0; +} \ No newline at end of file diff --git a/src/servers/app/proto6/driverharness/DHApp.h b/src/servers/app/proto6/driverharness/DHApp.h new file mode 100644 index 0000000000..589180b5dd --- /dev/null +++ b/src/servers/app/proto6/driverharness/DHApp.h @@ -0,0 +1,16 @@ +#ifndef _DHAPP_H_ +#define _DHAPP_H_ + +#include + +class DisplayDriver; + +class DHApp : public BApplication +{ +public: + DHApp(void); + ~DHApp(void); + DisplayDriver *driver; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/driverharness/DHServerBitmap.cpp b/src/servers/app/proto6/driverharness/DHServerBitmap.cpp new file mode 100644 index 0000000000..2622bd6a41 --- /dev/null +++ b/src/servers/app/proto6/driverharness/DHServerBitmap.cpp @@ -0,0 +1,269 @@ +/* + ServerBitmap.cpp + Bitmap class which is intended to provide an easy way to package all the + data associated with a picture. It's very low-level, so there's still + plenty to do when coding with 'em. Also, they can be used to access draw on the + frame buffer in a relatively easy way, although it is currently unclear + whether this functionality will even be necessary. +*/ + +// These three includes for ServerBitmap(const char *path_to_image_file) only +#include +#include +#include + +#include +#include "ServerBitmap.h" +#include "Desktop.h" + +//#define DEBUG_BITMAP + +#ifdef DEBUG_BITMAP +#include +#endif + +ServerBitmap::ServerBitmap(BRect rect,color_space space,int32 BytesPerLine=0) +{ + width=rect.IntegerWidth()+1; + height=rect.IntegerHeight()+1; + cspace=space; + is_vram=false; + is_area=false; + areaid=B_ERROR; + + HandleSpace(space, BytesPerLine); + buffer=new uint8[bytesperline*height]; +// driver=get_gfxdriver(); +} + +ServerBitmap::ServerBitmap(int32 w,int32 h,color_space space,int32 BytesPerLine=0) +{ + width=w; + height=h; + cspace=space; + is_vram=false; + is_area=false; + areaid=B_ERROR; + + HandleSpace(space, BytesPerLine); + buffer=new uint8[bytesperline*height]; +// driver=get_gfxdriver(); +} + +ServerBitmap::ServerBitmap(int32 w,int32 h,color_space space, area_id areaID, int32 BytesPerLine=0) +{ + // This version is used for holding BBitmaps as one of the undocumented BBitmap + // constructors allows - it creates an area on the server's side. + width=w; + height=h; + cspace=space; + is_vram=false; + is_area=true; + + HandleSpace(space, BytesPerLine); + area_info ainfo; + areaid=areaID; + get_area_info(areaid, &ainfo); + buffer=(uint8*)ainfo.address; +// driver=get_gfxdriver(); +} + +ServerBitmap::ServerBitmap(void) +{ + // This version is obviously intended for use as an easy-access class for the + // frame buffer. AtheOS does it and it's small, so why not? Worst case, this + // can disappear if not necessary. + is_vram=true; + is_area=false; + areaid=B_ERROR; + UpdateSettings(); +} + +// This particular version is not intended for use except for testing purposes. +// It loads a BBitmap and copies it to the ServerBitmap. Probably will disappear +// when the *real* server is written +ServerBitmap::ServerBitmap(const char *path) +{ + BBitmap *bmp=BTranslationUtils::GetBitmap(path); + assert(bmp!=NULL); + + if(bmp==NULL) + { + width=0; + height=0; + cspace=B_NO_COLOR_SPACE; + bytesperline=0; + } + else + { + width=bmp->Bounds().IntegerWidth(); + height=bmp->Bounds().IntegerHeight(); + cspace=bmp->ColorSpace(); + bytesperline=bmp->BytesPerRow(); + buffer=new uint8[bmp->BitsLength()]; + memcpy(buffer,(void *)bmp->Bits(),bmp->BitsLength()); + } +} + +ServerBitmap::~ServerBitmap(void) +{ + if(!is_vram) + delete buffer; +} + +void ServerBitmap::UpdateSettings(void) +{ + // This is only used when the object is pointing to the frame buffer +// driver=get_gfxdriver(); + bpp=driver->GetDepth(); + width=driver->GetWidth(); + height=driver->GetHeight(); +} + +void ServerBitmap::SetBuffer(void *buffer) +{ + buffer=(uint8 *)buffer; +} + +uint8 *ServerBitmap::Buffer(void) +{ + return buffer; +} + +uint32 ServerBitmap::BitsLength(void) +{ + return (uint32)(bytesperline*height); +} + +void ServerBitmap::HandleSpace(color_space space, int32 BytesPerLine) +{ + // Function written to handle color space setup which is required + // by the two "normal" constructors + + // Big convoluted mess just to handle every color space and dword align + // the buffer + switch(space) + { + // Buffer is dword-aligned, so nothing need be done + // aside from allocate the memory + case B_RGB32: + case B_RGBA32: + case B_RGB32_BIG: + case B_RGBA32_BIG: + case B_UVL32: + case B_UVLA32: + case B_LAB32: + case B_LABA32: + case B_HSI32: + case B_HSIA32: + case B_HSV32: + case B_HSVA32: + case B_HLS32: + case B_HLSA32: + case B_CMY32: + case B_CMYA32: + case B_CMYK32: + + // 24-bit = 32-bit with extra 8 bits ignored + case B_RGB24_BIG: + case B_RGB24: + case B_LAB24: + case B_UVL24: + case B_HSI24: + case B_HSV24: + case B_HLS24: + case B_CMY24: + { + if(BytesPerLine<(width*4)) + bytesperline=width*4; + else + bytesperline=BytesPerLine; + bpp=32; + break; + } + // Calculate size and dword-align + + // 1-bit + case B_GRAY1: + { + int32 numbytes=width>>3; + if((width % 8) != 0) + numbytes++; + if(BytesPerLine +#include +#include "DebugTools.h" + +void PrintStatusToStream(status_t value) +{ + // Function which simply translates a returned status code into a string + // and dumps it to stdout + cout << "Status: " << TranslateStatusToString(value).String() << endl << flush; +} + +BString TranslateStatusToString(status_t value) +{ + BString outstr; + switch(value) + { + case B_OK: + outstr="B_OK "; + break; + case B_NAME_NOT_FOUND: + outstr="B_NAME_NOT_FOUND "; + break; + case B_BAD_VALUE: + outstr="B_BAD_VALUE "; + break; + case B_ERROR: + outstr="B_ERROR "; + break; + case B_TIMED_OUT: + outstr="B_TIMED_OUT "; + break; + case B_NO_MORE_PORTS: + outstr="B_NO_MORE_PORTS "; + break; + case B_WOULD_BLOCK: + outstr="B_WOULD_BLOCK "; + break; + case B_BAD_PORT_ID: + outstr="B_BAD_PORT_ID "; + break; + case B_BAD_TEAM_ID: + outstr="B_BAD_TEAM_ID "; + break; + default: + outstr="undefined status value in debugtools::PrintStatusToStream() "; + break; + } + return BString(outstr); +} + +void PrintColorSpaceToStream(color_space value) +{ + // Dump a color space to cout + BString outstr; + switch(value) + { + case B_RGB32: + outstr="B_RGB32 "; + break; + case B_RGBA32: + outstr="B_RGBA32 "; + break; + case B_RGB32_BIG: + outstr="B_RGB32_BIG "; + break; + case B_RGBA32_BIG: + outstr=" "; + break; + case B_UVL32: + outstr="B_UVL32 "; + break; + case B_UVLA32: + outstr="B_UVLA32 "; + break; + case B_LAB32: + outstr="B_LAB32 "; + break; + case B_LABA32: + outstr="B_LABA32 "; + break; + case B_HSI32: + outstr="B_HSI32 "; + break; + case B_HSIA32: + outstr="B_HSIA32 "; + break; + case B_HSV32: + outstr="B_HSV32 "; + break; + case B_HSVA32: + outstr="B_HSVA32 "; + break; + case B_HLS32: + outstr="B_HLS32 "; + break; + case B_HLSA32: + outstr="B_HLSA32 "; + break; + case B_CMY32: + outstr="B_CMY32"; + break; + case B_CMYA32: + outstr="B_CMYA32 "; + break; + case B_CMYK32: + outstr="B_CMYK32 "; + break; + case B_RGB24_BIG: + outstr="B_RGB24_BIG "; + break; + case B_RGB24: + outstr="B_RGB24 "; + break; + case B_LAB24: + outstr="B_LAB24 "; + break; + case B_UVL24: + outstr="B_UVL24 "; + break; + case B_HSI24: + outstr="B_HSI24 "; + break; + case B_HSV24: + outstr="B_HSV24 "; + break; + case B_HLS24: + outstr="B_HLS24 "; + break; + case B_CMY24: + outstr="B_CMY24 "; + break; + case B_GRAY1: + outstr="B_GRAY1 "; + break; + case B_CMAP8: + outstr="B_CMAP8 "; + break; + case B_GRAY8: + outstr="B_GRAY8 "; + break; + case B_YUV411: + outstr="B_YUV411 "; + break; + case B_YUV420: + outstr="B_YUV420 "; + break; + case B_YCbCr422: + outstr="B_YCbCr422 "; + break; + case B_YCbCr411: + outstr="B_YCbCr411 "; + break; + case B_YCbCr420: + outstr="B_YCbCr420 "; + break; + case B_YUV422: + outstr="B_YUV422 "; + break; + case B_YUV9: + outstr="B_YUV9 "; + break; + case B_YUV12: + outstr="B_YUV12 "; + break; + case B_RGB15: + outstr="B_RGB15 "; + break; + case B_RGBA15: + outstr="B_RGBA15 "; + break; + case B_RGB16: + outstr="B_RGB16 "; + break; + case B_RGB16_BIG: + outstr="B_RGB16_BIG "; + break; + case B_RGB15_BIG: + outstr="B_RGB15_BIG "; + break; + case B_RGBA15_BIG: + outstr="B_RGBA15_BIG "; + break; + case B_YCbCr444: + outstr="B_YCbCr444 "; + break; + case B_YUV444: + outstr="B_YUV444 "; + break; + case B_NO_COLOR_SPACE: + outstr="B_NO_COLOR_SPACE "; + break; + default: + outstr="Undefined color space "; + break; + } + cout << "Color Space: " << outstr.String() << flush; +} + +void TranslateMessageCodeToStream(int32 code) +{ + // Used to translate BMessage message codes back to a character + // format + + cout << "'" + << (char)((code & 0xFF000000) >> 24) + << (char)((code & 0x00FF0000) >> 16) + << (char)((code & 0x0000FF00) >> 8) + << (char)((code & 0x000000FF)) << "' "; +} + +void PrintMessageCode(int32 code) +{ + // Used to translate BMessage message codes back to a character + // format + + printf("Message code %c%c%c%c\n", + (char)((code & 0xFF000000) >> 24), + (char)((code & 0x00FF0000) >> 16), + (char)((code & 0x0000FF00) >> 8), + (char)((code & 0x000000FF)) ); +} + diff --git a/src/servers/app/proto6/driverharness/DebugTools.h b/src/servers/app/proto6/driverharness/DebugTools.h new file mode 100644 index 0000000000..55bf1b0635 --- /dev/null +++ b/src/servers/app/proto6/driverharness/DebugTools.h @@ -0,0 +1,13 @@ +#ifndef _DEBUGTOOLS_H_ +#define _DEBUGTOOLS_H_ + +#include +#include +#include + +void PrintColorSpaceToStream(color_space value); +void TranslateMessageCodeToStream(int32 code); +void PrintMessageCode(int32 code); +BString TranslateStatusToString(status_t value); + +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/driverharness/Desktop.h b/src/servers/app/proto6/driverharness/Desktop.h new file mode 100644 index 0000000000..54b5e1bf3f --- /dev/null +++ b/src/servers/app/proto6/driverharness/Desktop.h @@ -0,0 +1,46 @@ +#ifndef _OBDESKTOP_H_ +#define _OBDESKTOP_H_ + + +#include +#include +#include + +class DisplayDriver; +class ServerWindow; +class Layer; + +void init_desktop(int8 workspaces); +void shutdown_desktop(void); +DisplayDriver *get_gfxdriver(void); + +// Workspace access functions +int32 CountWorkspaces(void); +void SetWorkspaceCount(uint32 count); + +int32 CurrentWorkspace(void); +void ActivateWorkspace(uint32 workspace); + +const color_map *SystemColors(void); +status_t SetScreenSpace(uint32 index, uint32 res, bool stick=true); + +void AddWindowToDesktop(ServerWindow *win,uint32 workspace); +void RemoveWindowFromDesktop(ServerWindow *win); +Layer *GetRootLayer(void); +int32 GetViewToken(void); + +typedef struct +{ + color_space mode; + BRect frame; + uint32 spaces; + float min_refresh_rate; + float max_refresh_rate; + float refresh_rate; + uchar h_position; + uchar v_position; + uchar h_size; + uchar v_size; +} screen_info; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/driverharness/DirectDriver.cpp b/src/servers/app/proto6/driverharness/DirectDriver.cpp new file mode 100644 index 0000000000..4f72f12422 --- /dev/null +++ b/src/servers/app/proto6/driverharness/DirectDriver.cpp @@ -0,0 +1,322 @@ +/* + DriverDriver: + Replacement class for the ViewDriver which utilizes a BDirectWindow for ease + of testing without requiring a second video card for SecondDriver and also + without the limitations (mostly speed) of ViewDriver. + + Note that unlike ViewDriver, this windowed graphics module does NOT emulate + the Input Server. The Router input server filter is required for use. + + The concept is a combination of both SecondDriver and ViewDriver: utilize + PortLink messaging (for better speed than BMessages) and draw directly to the + frame buffer. + + Components: 2 classes, DDriverWin and DirectDriver + + DirectDriver - a wrapper class which enqueues draw requests + DDirectWin - does most of the work. +*/ + +#define DEBUG_DRIVER_MODULE +#include +#include +#include +#include +#include "PortLink.h" +#include "ServerProtocol.h" +#include "DirectDriver.h" +#include "ServerBitmap.h" + +// Message defines for internal use only +enum +{ +DDWIN_SHUTDOWN=100, +DDWIN_CLEAR, +DDWIN_SAFEMODE, +DDWIN_RESET, +DDWIN_SETSCREEN, + +DDWIN_FILLARC, +DDWIN_STROKEARC, +DDWIN_FILLRECT, +DDWIN_STROKERECT, +DDWIN_FILLROUNDRECT, +DDWIN_STROKEROUNDRECT, +DDWIN_FILLELLIPSE, +DDWIN_STROKEELLIPSE, +DDWIN_FILLBEZIER, +DDWIN_STROKEBEZIER, +DDWIN_FILLTRIANGLE, +DDWIN_STROKETRIANGLE, +DDWIN_STROKELINE, +DDWIN_DRAWSTRING, + +DDWIN_SETPENSIZE, +DDWIN_MOVEPENTO, +DDWIN_SHOWCURSOR, +DDWIN_HIDECURSOR, +DDWIN_OBSCURECURSOR, +DDWIN_MOVECURSOR, +DDWIN_SETCURSOR, +DDWIN_SETHIGHCOLOR, +DDWIN_SETLOWCOLOR +}; + +DDriverWin::DDriverWin(BRect frame) + : BDirectWindow(frame,"OBOS App Server, P6",B_TITLED_WINDOW, + B_NOT_ZOOMABLE | B_NOT_RESIZABLE) +{ + msgport=create_port(100,"DDWinPort"); + fConnected=false; + fConnectionDisabled=false; + locker=new BLocker(); + fClipList=NULL; + fNumClipRects=0; + + AddChild(new BView(Bounds(),"BView",B_FOLLOW_ALL,0)); + if(ChildAt(0)) + ChildAt(0)->SetViewColor(B_TRANSPARENT_32_BIT); + + if (!SupportsWindowMode()) + SetFullScreen(true); + framebuffer=NULL; + + fDirty=true; + fDrawThreadID=spawn_thread(DrawingThread, "drawing_thread",B_NORMAL_PRIORITY, (void *) this); + resume_thread(fDrawThreadID); + Show(); +} + +DDriverWin::~DDriverWin(void) +{ + int32 result; + + // In case the update thread is waiting for a message (very likely), + // give it a message to unblock it + fConnectionDisabled=true; + write_port(msgport,DDWIN_SHUTDOWN,NULL,0); + Hide(); + Sync(); + wait_for_thread(fDrawThreadID, &result); + free(fClipList); + if(framebuffer) + delete framebuffer; + delete locker; +} + +void DDriverWin::DirectConnected(direct_buffer_info *info) +{ + if (!fConnected && fConnectionDisabled) + return; + + locker->Lock(); + + switch(info->buffer_state & B_DIRECT_MODE_MASK) + { + case B_DIRECT_START: + { + fConnected=true; + // fall through on purpose + } + case B_DIRECT_MODIFY: + { + // Get clipping information + if (fClipList) + { + free(fClipList); + fClipList=NULL; + } + fNumClipRects=info->clip_list_count; + fClipList=(clipping_rect *) + malloc(fNumClipRects*sizeof(clipping_rect)); + if (fClipList) + { + memcpy(fClipList, info->clip_list, + fNumClipRects*sizeof(clipping_rect)); + fBits=(uint8 *) info->bits; + fRowBytes=info->bytes_per_row; + fFormat=info->pixel_format; + fBounds=info->window_bounds; + fDirty=true; + } + framebuffer=new ServerBitmap(Bounds(),info->pixel_format); + break; + } + case B_DIRECT_STOP: + { + fConnected=false; + delete framebuffer; + framebuffer=NULL; + break; + } + } + locker->Unlock(); +} + +int32 DDriverWin::DrawingThread(void *data) +{ + DDriverWin *w=(DDriverWin *)data; +// port_id dport=w->msgport; + + while (!w->fConnectionDisabled) + { + w->locker->Lock(); + if (w->fConnected) + { + if ( w->framebuffer && (w->fFormat==B_RGB32 || w->fFormat==B_RGBA32) && w->fDirty) +// if ( w->fFormat==B_CMAP8 && w->fDirty) + { + int32 y; + int32 width, height; + int32 adder,bmpadder; + uint8 *p_fbuffer, *p_bitmap; + clipping_rect *clip; + int32 i; + + adder=w->fRowBytes; + bmpadder=w->framebuffer->bytesperline; + + for (i=0; ifNumClipRects; i++) + { + clip=&(w->fClipList[i]); + width=((clip->right-clip->left)+1)*4; + height=(clip->bottom-clip->top)+1; + p_fbuffer=w->fBits+(clip->top*w->fRowBytes)+(clip->left*4); + p_bitmap=w->framebuffer->Buffer()+(clip->top*w->framebuffer->bytesperline)+(clip->left*4); + y=0; + while (y < height) + { +printf("Copy %ld bytes from %p to %p\n",width,p_bitmap, p_fbuffer); + memcpy(p_fbuffer, p_bitmap, width); + p_fbuffer+=adder; + p_bitmap+=bmpadder; + y++; + } + } + } + w->fDirty=false; + } + w->locker->Unlock(); + + // Use BWindow or BView APIs here if you want + + // process messages from port here by calling member function DispatchMessage + + snooze(16000); + } + return B_OK; +} + +bool DDriverWin::QuitRequested(void) +{ + port_id serverport=find_port(SERVER_PORT_NAME); + if(serverport!=B_NAME_NOT_FOUND) + { + write_port(serverport,B_QUIT_REQUESTED,NULL,0); + } + return true; +} + +void DDriverWin::WindowActivated(bool active) +{ + // This is just to hide the regular system cursor so we can see our own + if(active) + be_app->HideCursor(); + else + be_app->ShowCursor(); +} + +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- + +void DDriverWin::SafeMode(void) +{ +} + +void DDriverWin::Reset(void) +{ +} + +void DDriverWin::SetScreen(uint32 space) +{ +} + +void DDriverWin::Clear(clipping_rect *rect,uint8 red,uint8 green,uint8 blue) +{ + int32 width=((rect->right-rect->left)+1)*4; + int32 height=(rect->bottom-rect->top)+1; + uint8 *p=fBits+(rect->top*fRowBytes)+(rect->left*4); + int32 y=0; + + // Loop to clear each row + while (y < height) + { + // loop to clear 1 row belongs here + memset(p, 0x00, width); + + y++; + p+=fRowBytes; + } +} + +DirectDriver::DirectDriver(void) +{ + driverwin=new DDriverWin(BRect(100,60,740,540)); + hide_cursor=0; + drawlink=new PortLink(driverwin->msgport); +} + +DirectDriver::~DirectDriver(void) +{ + if(is_initialized) + { + driverwin->Lock(); + driverwin->Quit(); + } + delete drawlink; +} + +void DirectDriver::Initialize(void) +{ + locker->Lock(); + is_initialized=true; +// SetPenSize(1.0); +// MovePenTo(BPoint(0,0)); + locker->Unlock(); +} + +bool DirectDriver::IsInitialized(void) +{ + return is_initialized; +} + +void DirectDriver::Shutdown(void) +{ + locker->Lock(); + is_initialized=false; + locker->Unlock(); +} + +void DirectDriver::SafeMode(void) +{ +} + +void DirectDriver::Reset(void) +{ +} + +void DirectDriver::Clear(uint8 red,uint8 green,uint8 blue) +{ +} + +void DirectDriver::Clear(rgb_color col) +{ +} + diff --git a/src/servers/app/proto6/driverharness/DirectDriver.h b/src/servers/app/proto6/driverharness/DirectDriver.h new file mode 100644 index 0000000000..f0f1073df6 --- /dev/null +++ b/src/servers/app/proto6/driverharness/DirectDriver.h @@ -0,0 +1,117 @@ +#ifndef _DIRECTDRIVER_H_ +#define _DIRECTDRIVER_H_ + +#include +#include +#include +#include +#include +#include +#include // for clipping_rect definition +#include "DisplayDriver.h" + +class BBitmap; +class PortLink; +class VDWindow; +class ServerCursor; +class PortLink; +class ServerBitmap; + +class DDriverWin : public BDirectWindow +{ +public: + DDriverWin(BRect frame); + ~DDriverWin(void); + bool QuitRequested(void); + void WindowActivated(bool active); + void DirectConnected(direct_buffer_info *info); + static int32 DrawingThread(void *data); + port_id msgport; + + void SafeMode(void); + void Reset(void); + void SetScreen(uint32 space); + void Clear(clipping_rect *rect, uint8 red,uint8 green,uint8 blue); + ServerBitmap *framebuffer; +protected: + BLocker *locker; + bool fConnected, fConnectionDisabled, fDirty; + clipping_rect *fClipList,fBounds; + thread_id fDrawThreadID; + color_space fFormat; + uint8 *fBits; + int32 fNumClipRects, fRowBytes; +}; + +class DirectDriver : public DisplayDriver +{ +public: + DirectDriver(void); + virtual ~DirectDriver(void); + + virtual void Initialize(void); + virtual bool IsInitialized(void); + virtual void Shutdown(void); + + virtual void SafeMode(void); + virtual void Reset(void); + virtual void Clear(uint8 red,uint8 green,uint8 blue); + virtual void Clear(rgb_color col); + +/* // Settings functions + virtual void SetScreen(uint32 space); + virtual int32 GetHeight(void); + virtual int32 GetWidth(void); + virtual int GetDepth(void); + + // Drawing functions + virtual void Blit(BRect src, BRect dest); + virtual void DrawBitmap(ServerBitmap *bitmap); + virtual void DrawChar(char c, BPoint point); + virtual void DrawString(char *string, int length, BPoint point); + + virtual void FillArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern); + virtual void FillBezier(BPoint *points, uint8 *pattern); + virtual void FillEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern); + virtual void FillPolygon(int *x, int *y, int numpoints, bool is_closed); + virtual void FillRect(BRect rect, uint8 *pattern); + virtual void FillRect(BRect rect, rgb_color col); + virtual void FillRegion(BRegion *region); + virtual void FillRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern); + virtual void FillShape(BShape *shape); + virtual void FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern); + + virtual void HideCursor(void); + virtual bool IsCursorHidden(void); + virtual void MoveCursorTo(float x, float y); + virtual void MovePenTo(BPoint pt); + virtual void ObscureCursor(void); + virtual BPoint PenPosition(void); + virtual float PenSize(void); + virtual void SetCursor(int32 value); + virtual void SetCursor(ServerCursor *cursor); + virtual void SetHighColor(uint8 r,uint8 g,uint8 b,uint8 a=255); + virtual void SetLowColor(uint8 r,uint8 g,uint8 b,uint8 a=255); + virtual void SetPenSize(float size); + virtual void SetPixel(int x, int y, uint8 *pattern); + virtual void ShowCursor(void); + + virtual void StrokeArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern); + virtual void StrokeBezier(BPoint *points, uint8 *pattern); + virtual void StrokeEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern); + virtual void StrokeLine(BPoint point, uint8 *pattern); + virtual void StrokeLine(BPoint pt1, BPoint pt2, rgb_color col); + virtual void StrokePolygon(int *x, int *y, int numpoints, bool is_closed); + virtual void StrokeRect(BRect rect,uint8 *pattern); + virtual void StrokeRect(BRect rect,rgb_color col); + virtual void StrokeRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern); + virtual void StrokeShape(BShape *shape); + virtual void StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern); +*/ +protected: + DDriverWin *driverwin; + int hide_cursor; + PortLink *drawlink; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/driverharness/DisplayDriver.cpp b/src/servers/app/proto6/driverharness/DisplayDriver.cpp new file mode 100644 index 0000000000..54c8cd5fcd --- /dev/null +++ b/src/servers/app/proto6/driverharness/DisplayDriver.cpp @@ -0,0 +1,327 @@ +/* + DisplayDriver.cpp + Modular class to allow the server to not care what the ultimate output is + for graphics calls. +*/ +#include "DisplayDriver.h" +#include "ColorUtils.h" +#include "SystemPalette.h" +#include "ServerCursor.h" + +DisplayDriver::DisplayDriver(void) +{ + is_initialized=false; + cursor_visible=true; + show_on_move=false; + locker=new BLocker(); + + penpos.Set(0,0); + pensize=0.0; + + // initialize to BView defaults + highcol.red=0; + highcol.green=0; + highcol.blue=0; + highcol.alpha=0; + lowcol.red=255; + lowcol.green=255; + lowcol.blue=255; + lowcol.alpha=255; +} + +DisplayDriver::~DisplayDriver(void) +{ + delete locker; +} + +void DisplayDriver::Initialize(void) +{ // Loading loop to find proper driver or other setup for the driver +} + +bool DisplayDriver::IsInitialized(void) +{ // Let us know whether things worked out ok + return is_initialized; +} + +void DisplayDriver::Shutdown(void) +{ // For use by subclasses +} + +void DisplayDriver::SafeMode(void) +{ // Set video mode to 640x480x256 mode +} + +void DisplayDriver::Reset(void) +{ // Intended to reload and restart driver. Defaults to a safe mode +} + +void DisplayDriver::Clear(uint8 red,uint8 green,uint8 blue) +{ +} + +void DisplayDriver::Clear(rgb_color col) +{ +} + +void DisplayDriver::SetScreen(uint32 space) +{ // Set the screen to a particular mode +} + +int32 DisplayDriver::GetHeight(void) +{ // Gets the height of the current mode + return ginfo->height; +} + +int32 DisplayDriver::GetWidth(void) +{ // Gets the width of the current mode + return ginfo->width; +} + +int DisplayDriver::GetDepth(void) +{ // Gets the color depth of the current mode + return ginfo->bytes_per_row; +} + +void DisplayDriver::AddLine(BPoint pt1, BPoint pt2, rgb_color col) +{ +} + +void DisplayDriver::BeginLineArray(int32 count) +{ +} + +void DisplayDriver::Blit(BRect src, BRect dest) +{ // Screen-to-screen bitmap copying +} + +void DisplayDriver::DrawBitmap(ServerBitmap *bitmap, BRect source, BRect dest) +{ +} + +void DisplayDriver::DrawChar(char c, BPoint point) +{ +} + +void DisplayDriver::DrawLineArray(int32 count,BPoint *start, BPoint *end, rgb_color *color) +{ +} + +void DisplayDriver::DrawString(char *string, int length, BPoint point) +{ +} + +void DisplayDriver::EndLineArray(void) +{ +} + +void DisplayDriver::FillArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern) +{ +} + +void DisplayDriver::FillBezier(BPoint *points, uint8 *pattern) +{ +} + +void DisplayDriver::FillEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern) +{ +} + +void DisplayDriver::FillPolygon(int *x, int *y, int numpoints, bool is_closed) +{ +} + +void DisplayDriver::FillRect(BRect rect, uint8 *pattern) +{ +} + +void DisplayDriver::FillRect(BRect rect, rgb_color col) +{ +} + +void DisplayDriver::FillRegion(BRegion *region) +{ +} + +void DisplayDriver::FillRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern) +{ +} + +void DisplayDriver::FillShape(BShape *shape) +{ +} + +void DisplayDriver::FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern) +{ +} + +void DisplayDriver::FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, rgb_color col) +{ +} + +drawing_mode DisplayDriver::GetDrawingMode(void) +{ + return B_OP_COPY; +} + +void DisplayDriver::HideCursor(void) +{ +} + +rgb_color DisplayDriver::HighColor(void) +{ + locker->Lock(); + rgb_color col=highcol; + locker->Unlock(); + return col; +} + +bool DisplayDriver::IsCursorHidden(void) +{ + return false; +} + +rgb_color DisplayDriver::LowColor(void) +{ + locker->Lock(); + rgb_color col=lowcol; + locker->Unlock(); + return col; +} + +void DisplayDriver::ObscureCursor(void) +{ // Hides cursor until mouse is moved +} + +void DisplayDriver::MoveCursorTo(float x, float y) +{ +} + +void DisplayDriver::MovePenTo(BPoint pt) +{ // Moves the graphics pen to this position + penpos=pt; +} + +BPoint DisplayDriver::PenPosition(void) +{ + return penpos; +} + +float DisplayDriver::PenSize(void) +{ + return pensize; +} + +void DisplayDriver::SetCursor(ServerCursor *cursor) +{ +} + +void DisplayDriver::SetDrawingMode(drawing_mode mode) +{ +} + +void DisplayDriver::SetHighColor(uint8 r,uint8 g,uint8 b,uint8 a=255) +{ + SetRGBColor(&highcol,r,g,b,a); + high16=FindClosestColor16(highcol); + high8=FindClosestColor(system_palette,highcol); +} + +void DisplayDriver::SetHighColor(rgb_color col) +{ + highcol=col; + high16=FindClosestColor16(highcol); + high8=FindClosestColor(system_palette,highcol); +} + +void DisplayDriver::SetLowColor(uint8 r,uint8 g,uint8 b,uint8 a=255) +{ + SetRGBColor(&lowcol,r,g,b,a); + low16=FindClosestColor16(lowcol); + low8=FindClosestColor(system_palette,lowcol); +} + +void DisplayDriver::SetLowColor(rgb_color col) +{ + lowcol=col; + low16=FindClosestColor16(lowcol); + low8=FindClosestColor(system_palette,lowcol); +} + +void DisplayDriver::SetPenSize(float size) +{ + pensize=(size>0)?size:1; +} + +void DisplayDriver::SetPixel(int x, int y, uint8 *pattern) +{ // Internal function utilized by other functions to draw to the buffer + // Will eventually be an inline function +} + +void DisplayDriver::ShowCursor(void) +{ +} + +float DisplayDriver::StringWidth(const char *string, int32 length) +{ + return -1.0; +} + +void DisplayDriver::StrokeArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern) +{ +} + +void DisplayDriver::StrokeBezier(BPoint *points, uint8 *pattern) +{ +} + +void DisplayDriver::StrokeEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern) +{ +} + +void DisplayDriver::StrokeLine(BPoint point, uint8 *pattern) +{ +} + +void DisplayDriver::StrokeLine(BPoint pt1, BPoint pt2, rgb_color col) +{ +} + +void DisplayDriver::StrokePolygon(int *x, int *y, int numpoints, bool is_closed) +{ +} + +void DisplayDriver::StrokeRect(BRect rect, uint8 *pattern) +{ +} + +void DisplayDriver::StrokeRect(BRect rect, rgb_color col) +{ +} + +void DisplayDriver::StrokeRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern) +{ +} + +void DisplayDriver::StrokeShape(BShape *shape) +{ +} + +void DisplayDriver::StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern) +{ +} + +void DisplayDriver::StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, rgb_color col) +{ +} + +void DisplayDriver::Line32(BPoint pt, BPoint pt2, uint8 *pattern) +{ +} + +void DisplayDriver::Line16(BPoint pt, BPoint pt2, uint8 *pattern) +{ +} + +void DisplayDriver::Line8(BPoint pt, BPoint pt2, uint8 *pattern) +{ +} diff --git a/src/servers/app/proto6/driverharness/DisplayDriver.h b/src/servers/app/proto6/driverharness/DisplayDriver.h new file mode 100644 index 0000000000..b679d6e07a --- /dev/null +++ b/src/servers/app/proto6/driverharness/DisplayDriver.h @@ -0,0 +1,156 @@ +#ifndef _GFX_DRIVER_H_ +#define _GFX_DRIVER_H_ + +#include +#include +#include +#include "Desktop.h" + +class ServerBitmap; +class ServerCursor; + +#ifndef ROUND + #define ROUND(a) ( (a-long(a))>=.5)?(long(a)+1):(long(a)) +#endif + +typedef struct +{ + uchar *xormask, *andmask; + int32 width, height; + int32 hotx, hoty; + +} cursor_data; + +#ifndef HOOK_DEFINE_CURSOR + +#define HOOK_DEFINE_CURSOR 0 +#define HOOK_MOVE_CURSOR 1 +#define HOOK_SHOW_CURSOR 2 +#define HOOK_DRAW_LINE_8BIT 3 +#define HOOK_DRAW_LINE_16BIT 12 +#define HOOK_DRAW_LINE_32BIT 4 +#define HOOK_DRAW_RECT_8BIT 5 +#define HOOK_DRAW_RECT_16BIT 13 +#define HOOK_DRAW_RECT_32BIT 6 +#define HOOK_BLIT 7 +#define HOOK_DRAW_ARRAY_8BIT 8 +#define HOOK_DRAW_ARRAY_16BIT 14 // Not implemented in current R5 drivers +#define HOOK_DRAW_ARRAY_32BIT 9 +#define HOOK_SYNC 10 +#define HOOK_INVERT_RECT 11 + +#endif + +class ServerCursor; + +#define DRAW_COPY 0 +#define DRAW_OVER 1 +#define DRAW_ERASE 2 +#define DRAW_INVERT 3 +#define DRAW_ADD 4 +#define DRAW_SUBTRACT 5 +#define DRAW_BLEND 6 +#define DRAW_MIN 7 +#define DRAW_MAX 8 +#define DRAW_SELECT 9 +#define DRAW_ALPHA 10 + + +class DisplayDriver +{ +public: + DisplayDriver(void); + virtual ~DisplayDriver(void); + + virtual void Initialize(void); // Sets the driver + virtual bool IsInitialized(void); + virtual void Shutdown(void); // You never know when you'll need this + + virtual void SafeMode(void); // Easy-access functions for common tasks + virtual void Reset(void); + virtual void Clear(uint8 red,uint8 green,uint8 blue); + virtual void Clear(rgb_color col); + + // Settings functions + virtual void SetScreen(uint32 space); + virtual int32 GetHeight(void); + virtual int32 GetWidth(void); + virtual int GetDepth(void); + + // Drawing functions + virtual void AddLine(BPoint pt1, BPoint pt2, rgb_color col); + virtual void BeginLineArray(int32 count); + virtual void Blit(BRect src, BRect dest); + virtual void DrawBitmap(ServerBitmap *bitmap, BRect source, BRect dest); + virtual void DrawChar(char c, BPoint point); + virtual void DrawLineArray(int32 count,BPoint *start, BPoint *end, rgb_color *color); + virtual void DrawString(char *string, int length, BPoint point); + virtual void EndLineArray(void); + + virtual void FillArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern); + virtual void FillBezier(BPoint *points, uint8 *pattern); + virtual void FillEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern); + virtual void FillPolygon(int *x, int *y, int numpoints, bool is_closed); + virtual void FillRect(BRect rect, uint8 *pattern); + virtual void FillRect(BRect rect, rgb_color col); + virtual void FillRegion(BRegion *region); + virtual void FillRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern); + virtual void FillShape(BShape *shape); + virtual void FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern); + virtual void FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, rgb_color col); + +// virtual void GetBlendingMode(source_alpha *srcmode, alpha_function *funcmode); + virtual drawing_mode GetDrawingMode(void); + virtual void HideCursor(void); + rgb_color HighColor(void); + virtual bool IsCursorHidden(void); + rgb_color LowColor(void); + virtual void MoveCursorTo(float x, float y); + virtual void MovePenTo(BPoint pt); + virtual void ObscureCursor(void); + virtual BPoint PenPosition(void); + virtual float PenSize(void); +// virtual void SetBlendingMode(source_alpha srcmode, alpha_function funcmode); + virtual void SetCursor(ServerCursor *cursor); + virtual void SetDrawingMode(drawing_mode mode); + virtual void ShowCursor(void); + virtual void SetHighColor(uint8 r,uint8 g,uint8 b,uint8 a=255); + virtual void SetHighColor(rgb_color col); + virtual void SetLowColor(uint8 r,uint8 g,uint8 b,uint8 a=255); + virtual void SetLowColor(rgb_color col); + virtual void SetPenSize(float size); + virtual void SetPixel(int x, int y, uint8 *pattern); + + virtual float StringWidth(const char *string, int32 length); + virtual void StrokeArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern); + virtual void StrokeBezier(BPoint *points, uint8 *pattern); + virtual void StrokeEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern); + virtual void StrokeLine(BPoint point, uint8 *pattern); + virtual void StrokeLine(BPoint pt1, BPoint pt2, rgb_color col); + virtual void StrokePolygon(int *x, int *y, int numpoints, bool is_closed); + virtual void StrokeRect(BRect rect,uint8 *pattern); + virtual void StrokeRect(BRect rect, rgb_color col); + virtual void StrokeRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern); + virtual void StrokeShape(BShape *shape); + virtual void StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern); + virtual void StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, rgb_color col); + + graphics_card_hook ghooks[48]; + graphics_card_info *ginfo; + +protected: + virtual void Line32(BPoint pt, BPoint pt2, uint8 *pattern); + virtual void Line16(BPoint pt, BPoint pt2, uint8 *pattern); + virtual void Line8(BPoint pt, BPoint pt2, uint8 *pattern); + + bool is_initialized, cursor_visible, show_on_move; + ServerCursor *current_cursor; + BLocker *locker; + rgb_color highcol, lowcol; + uint16 high16, low16; + uint8 high8, low8; + BPoint penpos; + float pensize; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/driverharness/PortLink.cpp b/src/servers/app/proto6/driverharness/PortLink.cpp new file mode 100644 index 0000000000..8fba724569 --- /dev/null +++ b/src/servers/app/proto6/driverharness/PortLink.cpp @@ -0,0 +1,438 @@ +/* + PortLink.cpp: + A helper class for port-based messaging + +------------------------------------------------------------------------ +How it works: + The class utilizes a fixed-size array of PortLinkData object pointers. When +data is attached, a new PortLinkData object is allocated and a copy of the +passed data is created inside it. When the time comes for the message to be sent, +the data is pieced together into a flattened array and written to the port. +------------------------------------------------------------------------ +Data members: + +*attachments[] - fixed-size array of pointers used to hold the attached data +opcode - message value which is sent along with any data +target - port to which the message is sent when Flush() is called +replyport - port used with synchronous messaging - FlushWithReply() +bufferlength - total bytes taken up by attachments +num_attachments - internal variable which is used to track which "slot" + will be the next one to receive an attachment object +*/ + +#include "PortLink.h" +#include +#include +#include + +//#define PLDEBUG + +// Internal data storage class for holding attached data whilst it is waiting +// to be Flattened() and then Flushed(). There is no need for this to be called outside +// the PortLink class. +class PortLinkData +{ +public: + PortLinkData(void); + ~PortLinkData(void); + bool Set(void *data, size_t size); + char *buffer; + size_t buffersize; +}; + +PortLink::PortLink(port_id port) +{ + // For this class to be useful (and to prevent a lot of init problems) + // we require a port in the constructor + target=port; + + // We start out without any data attached to the port message + num_attachments=0; + opcode=0; + bufferlength=0; + replyport=create_port(30,"PortLink reply port"); +} + +PortLink::~PortLink(void) +{ + // If, for some odd reason, this is deleted with something attached, + // free the memory used by the attachments. We do not flush the queue + // because the port may no longer be valid in cases such as the app + // is in the process of quitting + MakeEmpty(); +} + +void PortLink::SetOpCode(int32 code) +{ + // Sets the message code. This does not change once the message is sent. + // Another call to SetOpCode() is required for such things. + opcode=code; +} + +void PortLink::SetPort(port_id port) +{ + // Sets the target port. While not necessary in most uses, this exists + // mostly to prevent flexibility problems + target=port; +} + +port_id PortLink::GetPort(void) +{ + // Simply returns the port at which the object is pointed. + return target; +} + +void PortLink::Flush(bigtime_t timeout=B_INFINITE_TIMEOUT) +{ + // Fires a message off to the target, complete with attachments. NOTE: + // the recipient must delete all attachments, being the PortLink object assumes + // no responsiblity for the attachments once the message is sent. + int8 *msgbuffer; + int32 size; + + if(num_attachments>0) + { + FlattenData(&msgbuffer,&size); + + // Dump message to port, reset attachments, and clean up + if(timeout!=B_INFINITE_TIMEOUT) + write_port_etc(target,opcode,msgbuffer,size,B_TIMEOUT, timeout); + else + write_port(target,opcode,msgbuffer,size); + MakeEmpty(); + } + else + { + if(timeout!=B_INFINITE_TIMEOUT) + write_port_etc(target,opcode,NULL,0,B_TIMEOUT, timeout); + else + write_port(target,opcode,NULL,0); + } +} + +int8* PortLink::FlushWithReply(int32 *code, status_t *status, ssize_t *buffersize, bigtime_t timeout=B_INFINITE_TIMEOUT) +{ + // Fires a message to the target and then waits for a reply. The target will + // receive a message with the first item being the port_id to reply to. + // NOTE: like Flush(), any attached data must be deleted. + + // Effectively, an Attach() call inlined for changes + + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + { + *status=B_ERROR; + return NULL; + } + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&replyport,sizeof(port_id))) + { + bufferlength+=sizeof(port_id); + } + else + { + delete pld; + *status=B_ERROR; + return NULL; + } + + // Flatten() inlined to make some necessary changes + int8 *buffer=new int8[bufferlength]; + int8 *bufferindex=buffer; + size_t size=0; + + // attach our port_id first + memcpy(bufferindex, pld->buffer, pld->buffersize); + bufferindex += pld->buffersize; + size+=pld->buffersize; + + // attach everything else + for(int i=0;ibuffer, pld->buffersize); + bufferindex += pld->buffersize; + size+=pld->buffersize; + } + + // Flush the thing....FOOSH! :P + write_port(target,opcode,buffer,size); + MakeEmpty(); + delete buffer; + + // Now we wait for the reply + if(timeout==B_INFINITE_TIMEOUT) + { + *buffersize=port_buffer_size(replyport); + if(*buffersize>0) + buffer=(int8*)new int8[*buffersize]; + read_port(replyport,code, buffer, *buffersize); + } + else + { + *buffersize=port_buffer_size_etc(replyport,0,timeout); + if(*buffersize==B_TIMED_OUT) + { + *status=*buffersize; + return NULL; + } + if(*buffersize>0) + buffer=(int8*)new int8[*buffersize]; + read_port(replyport,code, buffer, *buffersize); + } + + // We got this far, so we apparently have some data + *status=B_OK; + return buffer; +} + +void PortLink::Attach(void *data, size_t size) +{ + // This is the member called to attach data to a message. Attachments are + // treated to be in 'Append' mode, tacking on each attached piece of data + // to the end of the list. + + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + if(size==0) + return; + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +// These functions were added for a major convenience in passing common types +// Eventually, I'd like to templatize these, but for now, this'll do + +void PortLink::Attach(int32 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int32); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(int16 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int16); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(int8 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int8); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(float data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(float); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(bool data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(bool); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(BRect data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(BRect); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(BPoint data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(BPoint); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::FlattenData(int8 **buffer,int32 *size) +{ + // This function is where all the magic happens, but it is strictly internal. + // It iterates through each PortLinkData object and copies it to the main buffer + // which ends up, ultimately, being written to the PortLink's target port. + + // skip if there aree no attachments + if(bufferlength<1) + return; + + *buffer=new int8[bufferlength]; + int8 *bufferindex=*buffer; + PortLinkData *pld; + *size=0; + + for(int i=0;ibuffer, pld->buffersize); + bufferindex += pld->buffersize; + *size+=pld->buffersize; + } +} + +void PortLink::MakeEmpty(void) +{ + // Nukes all the attachments currently held by the PortLink class + if(num_attachments!=0) + { + for(int i=0; i0) + free(buffer); +} + +bool PortLinkData::Set(void *data, size_t size) +{ + // Function copies the passed to the internal buffers for storage + if(size>0 && buffersize==0 && data!=NULL) + { + buffer=(char *)malloc(size); + if(buffer==NULL) + return false; + memcpy(buffer, data, size); + buffersize=size; + return true; + } + return false; +} diff --git a/src/servers/app/proto6/driverharness/PortLink.h b/src/servers/app/proto6/driverharness/PortLink.h new file mode 100644 index 0000000000..9f5432daab --- /dev/null +++ b/src/servers/app/proto6/driverharness/PortLink.h @@ -0,0 +1,43 @@ +#ifndef _PORTLINK_H_ +#define _PORTLINK_H_ + +#include +#include +#include +#include + +#ifndef _PORTLINK_BUFFERSIZE +#define _PORTLINK_MAX_ATTACHMENTS 50 +#endif + +class PortLinkData; + +class PortLink +{ +public: + PortLink(port_id port); + ~PortLink(void); + void SetOpCode(int32 code); + void SetPort(port_id port); + port_id GetPort(void); + void Flush(bigtime_t timeout=B_INFINITE_TIMEOUT); + int8* FlushWithReply(int32 *code, status_t *status, ssize_t *buffersize, + bigtime_t timeout=B_INFINITE_TIMEOUT); + void Attach(void *data, size_t size); + void Attach(int32 data); + void Attach(int16 data); + void Attach(int8 data); + void Attach(float data); + void Attach(bool data); + void Attach(BRect data); + void Attach(BPoint data); + void MakeEmpty(void); +protected: + void FlattenData(int8 **buffer,int32 *size); + port_id target, replyport; + int32 opcode, bufferlength; + int num_attachments; + PortLinkData *attachments[_PORTLINK_MAX_ATTACHMENTS]; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/driverharness/ScreenDriver.cpp b/src/servers/app/proto6/driverharness/ScreenDriver.cpp new file mode 100644 index 0000000000..1928324e9a --- /dev/null +++ b/src/servers/app/proto6/driverharness/ScreenDriver.cpp @@ -0,0 +1,915 @@ +/* + ScreenDriver.cpp + Replacement class for the ViewDriver which utilizes a BWindowScreen for ease + of testing without requiring a second video card for SecondDriver and also + without the limitations (mostly speed) of ViewDriver. + + Note that unlike ViewDriver, this graphics module does NOT emulate + the Input Server. The Router input server filter is required for use. + + The concept is pretty close to the retooled ViewDriver, where each module + call locks a couple BLockers and draws to the buffer. + + Components: + ScreenDriver: actual driver module + FrameBuffer: BWindowScreen derivative which provides the module access + to the video card + Internal functions for doing graphics on the buffer + + Done: + Basic module init and shutdown + Clear() - 8-bit and 32-bit + SetPixel32 + StrokeLine(pt,pt,rgb_color) + StrokeRect - both forms + FillRect - both forms, but not using fastest methods + ToDo: + 16-Bit mode functions + StrokeLine(pt,pattern) needs to utilize patterns + FillRect(rect,pattern) needs to utilize patterns + Implement a lot of functions +*/ +#include "ScreenDriver.h" +#include "ServerCursor.h" +#include "ServerProtocol.h" +#include "ServerBitmap.h" +#include "SystemPalette.h" +#include "ColorUtils.h" +#include "PortLink.h" +#include "DebugTools.h" +#include +#include +#include +#include + +#define DEBUG_DRIVER + +// Define this if you want to use the spacebar to launch the server prototype's +// test application +#define LAUNCH_TESTAPP + +#ifdef LAUNCH_TESTAPP +#include +#include +#endif + +// functions internal to the driver +void Clear_32Bit(void *buffer, int width, int height, rgb_color col); +void Clear_16Bit(void *buffer, int width, int height, uint16 col); +void Clear_8Bit(void *buffer, int width, int height, uint8 col); + +void HLine_32Bit(graphics_card_info i, uint16 x, uint16 y, uint16 length, rgb_color col); +void HLine_16Bit(graphics_card_info i, uint16 x, uint16 y, uint16 length, uint16 col); +void HLine_16Bit(graphics_card_info i, uint16 x, uint16 y, uint16 length, uint8 col); + +FrameBuffer::FrameBuffer(const char *title, uint32 space, status_t *st,bool debug) + : BWindowScreen(title,space,st,debug) +{ + is_connected=false; +} + +FrameBuffer::~FrameBuffer(void) +{ +} + +void FrameBuffer::ScreenConnected(bool connected) +{ + is_connected=connected; + if(connected) + { + // Cache the state just in case + graphics_card_info *info=CardInfo(); + gcinfo=*info; + } +} + +void FrameBuffer::MessageReceived(BMessage *msg) +{ + switch(msg->what) + { + case B_KEY_DOWN: + { + int32 key; + msg->FindInt32("key",&key); + if(key==0x47) // Enter key + { + port_id serverport=find_port(SERVER_PORT_NAME); + write_port(serverport,B_QUIT_REQUESTED,NULL,0); + break; + } + #ifdef LAUNCH_TESTAPP + if(key==0x5e) + { + printf("Launching test app\n"); + status_t value; + BEntry entry("/boot/home/Desktop/openbeos/proto6/OBApplication/OBApplication"); + entry_ref ref; + entry.GetRef(&ref); + value=be_roster->Launch(&ref); + + BString str=TranslateStatusToString(value); + printf("Launch return code: %s",str.String()); + printf("\n"); + } + #endif + } + default: + BWindowScreen::MessageReceived(msg); + } +} + +bool FrameBuffer::QuitRequested(void) +{ + port_id serverport=find_port(SERVER_PORT_NAME); + + if(serverport!=B_NAME_NOT_FOUND) + write_port(serverport,B_QUIT_REQUESTED,NULL,0); + + return true; +} + +ScreenDriver::ScreenDriver(void) +{ + status_t st; + fbuffer=new FrameBuffer("OBAppServer",B_8_BIT_640x480,&st,true); + + drawmode=DRAW_COPY; + // Create our cursor here + cursor=new ServerBitmap(BRect(0,0,16,16),B_CMAP8); +} + +ScreenDriver::~ScreenDriver(void) +{ + delete cursor; +} + +void ScreenDriver::Initialize(void) +{ + fbuffer->Show(); + + // draw on the module's default cursor here to make it look preety + + // wait 1 sec for the window to show... + snooze(500000); +} + +void ScreenDriver::Shutdown(void) +{ + fbuffer->Lock(); + fbuffer->Quit(); +} + +void ScreenDriver::Clear(uint8 red,uint8 green,uint8 blue) +{ + locker->Lock(); + rgb_color c; + SetRGBColor(&c,red,green,blue); + Clear(c); + locker->Unlock(); +} + +void ScreenDriver::Clear(rgb_color col) +{ + locker->Lock(); +#ifdef DEBUG_DRIVER +printf("ScreenDriver::Clear(%u,%u,%u)\n",col.red,col.green,col.blue); +#endif + if(fbuffer->IsConnected()) + { + switch(fbuffer->gcinfo.bits_per_pixel) + { + case 32: + case 24: + { +printf("Clear: 32/24-bit\n"); + Clear_32Bit(fbuffer->gcinfo.frame_buffer, + fbuffer->gcinfo.width,fbuffer->gcinfo.height,col); + break; + } + case 16: + case 15: + { +printf("Clear: 16/15-bit unimplemented\n"); + // Look up color here +// uint16 c; +// Clear_16Bit(gcinfo.frame_buffer,gcinfo.width,gcinfo.height,c); + break; + } + case 8: + { +printf("Clear: 8-bit\n"); + // Look up color here + uint8 c=FindClosestColor(fbuffer->ColorList(),col); + + Clear_8Bit(fbuffer->gcinfo.frame_buffer, + fbuffer->gcinfo.width,fbuffer->gcinfo.height, c); + break; + } + default: + { +#ifdef DEBUG_DRIVER +printf("Clear: unknown bit depth %u\n",fbuffer->gcinfo.bits_per_pixel); +#endif + break; + } + } + } + else + { +#ifdef DEBUG_DRIVER +printf("Clear: driver is disconnected\n"); +#endif + } + locker->Unlock(); +} + +void ScreenDriver::DrawBitmap(ServerBitmap *bitmap, BRect source, BRect dest) +{ + locker->Lock(); +#ifdef DEBUG_DRIVER +printf("ScreenDriver::DrawBitmap(*, (%f,%f,%f,%f),(%f,%f,%f,%f) )\n", + source.left,source.top,source.right,source.bottom, + dest.left,dest.top,dest.right,dest.bottom); +#endif + if(fbuffer->IsConnected()) + { + // Scale bitmap here if source!=dest + + switch(fbuffer->gcinfo.bits_per_pixel) + { + case 32: + case 24: + { + printf("DrawBitmap: 32/24-bit unimplemented\n"); + break; + } + case 16: + case 15: + { + printf("DrawBitmap: 16/15-bit unimplemented\n"); + break; + } + case 8: + { + printf("DrawBitmap: 8-bit unimplemented\n"); + break; + } + default: + { +#ifdef DEBUG_DRIVER +printf("Clear: unknown bit depth %u\n",fbuffer->gcinfo.bits_per_pixel); +#endif + break; + } + } + } + + locker->Unlock(); +} + +void ScreenDriver::FillRect(BRect rect, uint8 *pattern) +{ + locker->Lock(); + + FillRect(rect,highcol); + + locker->Unlock(); +} + +void ScreenDriver::FillRect(BRect rect, rgb_color col) +{ +#ifdef DEBUG_DRIVER +printf("ScreenDriver::FillRect( (%f,%f,%f,%f), {%u,%u,%u,%u}\n",rect.left,rect.top, + rect.right,rect.bottom,col.red,col.green,col.blue,col.alpha); +#endif + locker->Lock(); + if(fbuffer->IsConnected()) + { + // int32 width=rect.IntegerWidth(); + for(int32 i=(int32)rect.top;i<=rect.bottom;i++) + // HLine(fbuffer->gcinfo,(int32)rect.left,i,width,col); + StrokeLine(BPoint(rect.left,i),BPoint(rect.right,i),col); + } + locker->Unlock(); +} + +void ScreenDriver::FillRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern) +{ +#ifdef DEBUG_DRIVER +printf("ScreenDriver::FillRoundRect( (%f,%f,%f,%f), %llx) ---->Unimplemented<----\n",rect.left,rect.top, + rect.right,rect.bottom,*((uint64*)pattern)); +#endif + FillRect(rect,pattern); +} + +void ScreenDriver::FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern) +{ +#ifdef DEBUG_DRIVER +printf("ScreenDriver::FillTriangle(%llx): --->Currently Unimplemented<---\n",*((uint64*)pattern)); +printf("\tFirst: (%f,%f)\n\tSecond: (%f,%f)\n\tThird: (%f,%f)\n",first.x,first.y, + second.x,second.y,third.x,third.y); +rect.PrintToStream(); +#endif + locker->Lock(); + if(fbuffer->IsConnected()) + { + BPoint oldpos=penpos; + MovePenTo(first); StrokeLine(second,pattern); + MovePenTo(second); StrokeLine(third,pattern); + MovePenTo(third); StrokeLine(first,pattern); + penpos=oldpos; + } + locker->Unlock(); +} + +void ScreenDriver::FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, rgb_color col) +{ +#ifdef DEBUG_DRIVER +printf("ScreenDriver::FillTriangle({%u,%u,%u,%u}): --->Currently Unimplemented<---\n", + col.red,col.green,col.blue,col.alpha); +printf("\tFirst: (%f,%f)\n\tSecond: (%f,%f)\n\tThird: (%f,%f)\n",first.x,first.y, + second.x,second.y,third.x,third.y); +rect.PrintToStream(); +#endif + locker->Lock(); + if(fbuffer->IsConnected()) + { + StrokeLine(first,second,col); + StrokeLine(first,third,col); + StrokeLine(third,second,col); + } + locker->Unlock(); +} + +void ScreenDriver::SetHighColor(uint8 r,uint8 g,uint8 b,uint8 a=255) +{ + rgb_color col={r,g,b,a}; + SetHighColor(col); +} + +void ScreenDriver::SetHighColor(rgb_color col) +{ + highcol=col; + + switch(fbuffer->gcinfo.bits_per_pixel) + { + case 16: + case 15: + high16=FindClosestColor16(highcol); + break; + case 8: + high8=FindClosestColor(system_palette,highcol); + break; + default: + break; + } +} + +void ScreenDriver::SetLowColor(uint8 r,uint8 g,uint8 b,uint8 a=255) +{ + rgb_color col={r,g,b,a}; + SetLowColor(col); +} + +void ScreenDriver::SetLowColor(rgb_color col) +{ + lowcol=col; + + switch(fbuffer->gcinfo.bits_per_pixel) + { + case 16: + case 15: + low16=FindClosestColor16(highcol); + break; + case 8: + low8=FindClosestColor(system_palette,highcol); + break; + default: + break; + } +} + +void ScreenDriver::SetPixel(int x, int y, uint8 *pattern) +{ + switch(fbuffer->gcinfo.bits_per_pixel) + { + case 32: + case 24: + SetPixel32(x,y,highcol); + break; + case 16: + case 15: + SetPixel16(x,y,FindClosestColor16(highcol)); + break; + default: + printf("SetPixel8 Unimplemented\n"); +// SetPixel8(x,y,FindClosestColor(highcol)); + break; + } + +} + +void ScreenDriver::SetPixel32(int x, int y, rgb_color col) +{ + // Code courtesy of YNOP's SecondDriver + union + { + uint8 bytes[4]; + uint32 word; + }c1; + + c1.bytes[0]=col.blue; + c1.bytes[1]=col.green; + c1.bytes[2]=col.red; + c1.bytes[3]=col.alpha; + + uint32 *bits=(uint32*)fbuffer->gcinfo.frame_buffer; + *(bits + x + (y*fbuffer->gcinfo.width))=c1.word; +} + +void ScreenDriver::SetPixel16(int x, int y, uint16 col) +{ +#ifdef DEBUG_DRIVER +printf("SetPixel16 unimplemented\n"); +#endif +} + +void ScreenDriver::SetPixel8(int x, int y, uint8 col) +{ + // When the DisplayDriver API changes, we'll use the uint8 highcolor. Until then, + // we'll use *pattern + uint8 *bits=(uint8*)fbuffer->gcinfo.frame_buffer; + *(bits + x + (y*fbuffer->gcinfo.bytes_per_row))=col; +} + +void ScreenDriver::SetScreen(uint32 space) +{ +#ifdef DEBUG_DRIVER +printf("ScreenDriver::SetScreen(%lu}\n",space); +#endif + locker->Lock(); + if(fbuffer->IsConnected()) + { + fbuffer->SetSpace(space); + + // We have changed the frame buffer info, so update the cached info + graphics_card_info *info=fbuffer->CardInfo(); + fbuffer->gcinfo=*info; + } + locker->Unlock(); +} + +void ScreenDriver::StrokeLine(BPoint point, uint8 *pattern) +{ +#ifdef DEBUG_DRIVER +printf("ScreenDriver::StrokeLine( (%f,%f), %llx}\n",point.x,point.y,*((uint64*)pattern)); +#endif + locker->Lock(); + if(fbuffer->IsConnected()) + { + // Courtesy YNOP's SecondDriver with minor changes by DW + int oct=0; + int xoff=(int32)penpos.x; + int yoff=(int32)penpos.y; + int32 x2=(int32)point.x-xoff; + int32 y2=(int32)point.y-yoff; + int32 x1=0; + int32 y1=0; + if(y2<0){ y2=-y2; oct+=4; }//bit2=1 + if(x2<0){ x2=-x2; oct+=2;}//bit1=1 + if(x2Unlock(); +} + +void ScreenDriver::StrokeLine(BPoint start, BPoint end, rgb_color col) +{ +#ifdef DEBUG_DRIVER +printf("ScreenDriver::StrokeLine( (%f,%f),(%f,%f), {%u,%u,%u,%u}\n",start.x,start.y, + end.x,end.y,col.red,col.green,col.blue,col.alpha); +#endif + locker->Lock(); + if(fbuffer->IsConnected()) + { + // Courtesy YNOP's SecondDriver with minor changes by DW + rgb_color savecol=highcol; + SetHighColor(col.red,col.green,col.blue); + + int oct=0; + int xoff=(int32)start.x; + int yoff=(int32)start.y; + int32 x2=(int32)end.x-xoff; + int32 y2=(int32)end.y-yoff; + int32 x1=0; + int32 y1=0; + if(y2<0){ y2=-y2; oct+=4; }//bit2=1 + if(x2<0){ x2=-x2; oct+=2;}//bit1=1 + if(x2Unlock(); +} + +void ScreenDriver::StrokePolygon(int *x, int *y, int numpoints, bool is_closed) +{ +#ifdef DEBUG_DRIVER +printf("ScreenDriver::StrokePolygon( is_closed=%s)\n",(is_closed==true)?"true":"false"); +for(int debug=0;debugLock(); + if(fbuffer->IsConnected()) + { + for(int32 i=0; i<(numpoints-1); i++) + StrokeLine(BPoint(x[i],y[i]),BPoint(x[i+1],y[i+1]),highcol); + + if(is_closed) + StrokeLine(BPoint(x[numpoints-1],y[numpoints-1]),BPoint(x[0],y[0]),highcol); + } + locker->Unlock(); +} + +void ScreenDriver::StrokeRect(BRect rect,uint8 *pattern) +{ +#ifdef DEBUG_DRIVER +printf("ScreenDriver::StrokeRect( (%f,%f,%f,%f), %llx)\n",rect.left,rect.top, + rect.right,rect.bottom,*((uint64*)pattern)); +#endif + locker->Lock(); + if(fbuffer->IsConnected()) + { + BPoint oldpos=penpos; + + MovePenTo(rect.LeftTop()); StrokeLine(BPoint(rect.right,rect.top),pattern); + MovePenTo(BPoint(rect.right,rect.top)); StrokeLine(BPoint(rect.right,rect.bottom),pattern); + MovePenTo(BPoint(rect.right,rect.bottom)); StrokeLine(BPoint(rect.left,rect.bottom),pattern); + MovePenTo(BPoint(rect.left,rect.bottom)); StrokeLine(BPoint(rect.left,rect.top),pattern); + +// Line32(rect.LeftTop(),BPoint(rect.right,rect.top),pattern); +// Line32(BPoint(rect.right,rect.top),BPoint(rect.right,rect.bottom),pattern); +// Line32(BPoint(rect.right,rect.bottom),BPoint(rect.left,rect.bottom),pattern); +// Line32(BPoint(rect.left,rect.bottom),BPoint(rect.left,rect.top),pattern); + + penpos=oldpos; + } + locker->Unlock(); +} + +void ScreenDriver::StrokeRect(BRect rect,rgb_color col) +{ +#ifdef DEBUG_DRIVER +printf("ScreenDriver::StrokeRect( (%f,%f,%f,%f), {%u,%u,%u,%u}\n",rect.left,rect.top, + rect.right,rect.bottom,col.red,col.green,col.blue,col.alpha); +#endif + locker->Lock(); + if(fbuffer->IsConnected()) + { + StrokeLine(BPoint(rect.left,rect.top),BPoint(rect.right,rect.top),col); + StrokeLine(BPoint(rect.right,rect.top),BPoint(rect.right,rect.bottom),col); + StrokeLine(BPoint(rect.right,rect.bottom),BPoint(rect.left,rect.bottom),col); + StrokeLine(BPoint(rect.left,rect.bottom),BPoint(rect.left,rect.top),col); + } + locker->Unlock(); +} + +void ScreenDriver::StrokeRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern) +{ +#ifdef DEBUG_DRIVER +printf("ScreenDriver::StrokeRoundRect( (%f,%f,%f,%f), %llx) ---->Unimplemented<----\n",rect.left,rect.top, + rect.right,rect.bottom,*((uint64*)pattern)); +#endif + StrokeRect(rect,pattern); +} + +void ScreenDriver::StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern) +{ +#ifdef DEBUG_DRIVER +printf("ScreenDriver::StrokeTriangle(%llx):\n",*((uint64*)pattern)); +printf("\tFirst: (%f,%f)\n\tSecond: (%f,%f)\n\tThird: (%f,%f)\n",first.x,first.y, + second.x,second.y,third.x,third.y); +rect.PrintToStream(); +#endif + locker->Lock(); + if(fbuffer->IsConnected()) + { + BPoint oldpos=penpos; + MovePenTo(first); StrokeLine(second,pattern); + MovePenTo(second); StrokeLine(third,pattern); + MovePenTo(third); StrokeLine(first,pattern); + penpos=oldpos; + } + locker->Unlock(); +} + +void ScreenDriver::StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, rgb_color col) +{ +#ifdef DEBUG_DRIVER +printf("ScreenDriver::StrokeTriangle({%u,%u,%u,%u}):\n", + col.red,col.green,col.blue,col.alpha); +printf("\tFirst: (%f,%f)\n\tSecond: (%f,%f)\n\tThird: (%f,%f)\n",first.x,first.y, + second.x,second.y,third.x,third.y); +rect.PrintToStream(); +#endif + locker->Lock(); + if(fbuffer->IsConnected()) + { + StrokeLine(first,second,col); + StrokeLine(first,third,col); + StrokeLine(third,second,col); + } + locker->Unlock(); +} + +void ScreenDriver::Line32(BPoint pt, BPoint pt2, uint8 *pattern) +{ +#ifdef DEBUG_DRIVER +printf("ScreenDriver::Line32( (%f,%f),(%f,%f), 0x%llx\n",pt.x,pt.y, + pt2.x,pt2.y,*((int64*)pattern)); +#endif + // Courtesy YNOP's SecondDriver with minor changes by DW + int oct=0; + int xoff=(int32)pt.x; + int yoff=(int32)pt.y; + int32 x2=(int32)pt2.x-xoff; + int32 y2=(int32)pt2.y-yoff; + int32 x1=0; + int32 y1=0; + if(y2<0){ y2=-y2; oct+=4; }//bit2=1 + if(x2<0){ x2=-x2; oct+=2;}//bit1=1 + if(x232) + patindex=0; + } +} + +void ScreenDriver::SetPixelPattern(int x, int y, uint8 *pattern, uint8 patternindex) +{ + // This function is designed to add pattern support to this thing. Should be + // inlined later to add speed lost in the multiple function calls. +#ifdef DEBUG_DRIVER +printf("ScreenDriver::SetPixelPattern(%u,%u,%llx,%u)\n",x,y,*((int64*)pattern),patternindex); +#endif + if(patternindex>32) + return; + + if(fbuffer->IsConnected()) + { + uint64 *p64=(uint64*)pattern; + + // check for transparency in mask. If transparent, we can quit here + + bool transparent_bit= + ( *p64 & ~((uint64)2 << (32-patternindex)))?true:false; +printf("SetPixelPattern: pattern=0x%llx\n",*p64); +printf("SetPixelPattern: bit=0x%llx\n",((uint64)2 << (32-patternindex))); +printf("SetPixelPattern: bit mask=0x%llx\n",~((uint64)2 << (32-patternindex))); +printf("SetPixelPattern: bit value=%s\n",transparent_bit?"true":"false"); + + bool highcolor_bit= + ( *p64 & ~((uint64)2 << (64-patternindex)))?true:false; + + switch(fbuffer->gcinfo.bits_per_pixel) + { + case 32: + case 24: + { + + break; + } + case 16: + case 15: + { + break; + } + case 8: + { + break; + } + default: + { +#ifdef DEBUG_DRIVER +printf("SetPixelPattern: unknown bit depth %u\n",fbuffer->gcinfo.bits_per_pixel); +#endif + break; + } + } + } + else + { +#ifdef DEBUG_DRIVER +printf("SetPixelPattern: driver is disconnected\n"); +#endif + } +} + +void Clear_32Bit(void *buffer, int width, int height, rgb_color col) +{ +#ifdef DEBUG_DRIVER +printf("Clear_32Bit(*,%d,%d,(r=%u,g=%u,b=%u,a=%u)\n",width,height,col.red,col.green, + col.blue,col.alpha); +#endif + + uint32 c=0,*pcolor=(uint32*)buffer; + + // apparently width=bytes per row + uint32 bpr=width; + + // ARGB order + c|=col.alpha * 0x01000000; + c|=col.red * 0x010000; + c|=col.green * 0x0100; + c|=col.blue; + +#ifdef DEBUG_DRIVER +printf("Clear color value: 0x%lx\n",c); +#endif + for(int32 j=0;jbpr)?length-((x+length)-bpr):length; + + pcolor=(uint32*)i.frame_buffer; + pcolor+=(y*bpr)+(x*4); + for(int32 i=0;ibpr)?length-((x+length)-bpr):length; + + memset(pcolor,col,bytes); +} diff --git a/src/servers/app/proto6/driverharness/ScreenDriver.h b/src/servers/app/proto6/driverharness/ScreenDriver.h new file mode 100644 index 0000000000..714e1cc46e --- /dev/null +++ b/src/servers/app/proto6/driverharness/ScreenDriver.h @@ -0,0 +1,114 @@ +#ifndef _SCREENDRIVER_H_ +#define _SCREENDRIVER_H_ + +#include +#include +#include +#include +#include +#include +#include +#include // for clipping_rect definition +#include +#include "DisplayDriver.h" + +class VDWindow; +class ServerCursor; +class ServerBitmap; + + +class FrameBuffer : public BWindowScreen +{ +public: + FrameBuffer(const char *title, uint32 space, status_t *st,bool debug); + ~FrameBuffer(void); + void ScreenConnected(bool connected); + void MessageReceived(BMessage *msg); + bool IsConnected(void) const { return is_connected; } + bool QuitRequested(void); + + graphics_card_info gcinfo; +protected: + bool is_connected; +}; + +class ScreenDriver : public DisplayDriver +{ +public: + ScreenDriver(void); + ~ScreenDriver(void); + + void Initialize(void); + void Shutdown(void); + + void Clear(uint8 red,uint8 green,uint8 blue); + void Clear(rgb_color col); + + // Settings functions + void SetScreen(uint32 space); +/* int32 GetHeight(void); + int32 GetWidth(void); + int GetDepth(void); + + // Drawing functions + void Blit(BRect src, BRect dest); +*/ void DrawBitmap(ServerBitmap *bitmap, BRect source, BRect dest); +/* void DrawChar(char c, BPoint point); + void DrawString(char *string, int length, BPoint point); + + void FillArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern); + void FillBezier(BPoint *points, uint8 *pattern); + void FillEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern); + void FillPolygon(int *x, int *y, int numpoints, bool is_closed); +*/ void FillRect(BRect rect, uint8 *pattern); + void FillRect(BRect rect, rgb_color col); +// void FillRegion(BRegion *region); + void FillRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern); +// void FillShape(BShape *shape); + + void FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern); + void FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, rgb_color col); +/* + void HideCursor(void); + bool IsCursorHidden(void); + void MoveCursorTo(float x, float y); + void ObscureCursor(void); + float PenSize(void); + void SetCursor(ServerCursor *cursor); +*/ + void SetHighColor(uint8 r,uint8 g,uint8 b,uint8 a=255); + void SetHighColor(rgb_color col); + void SetLowColor(uint8 r,uint8 g,uint8 b,uint8 a=255); + void SetLowColor(rgb_color col); + + void SetPixel(int x, int y, uint8 *pattern); + + void SetPixel32(int x, int y, rgb_color col); + void SetPixel16(int x, int y, uint16 col); + void SetPixel8(int x, int y, uint8 col); + void SetPixelPattern(int x, int y, uint8 *pattern, uint8 patternindex); + +// void ShowCursor(void); + +// void StrokeArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern); +// void StrokeBezier(BPoint *points, uint8 *pattern); +// void StrokeEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern); + void StrokeLine(BPoint point, uint8 *pattern); + void StrokeLine(BPoint pt1, BPoint pt2, rgb_color col); + void StrokePolygon(int *x, int *y, int numpoints, bool is_closed); + void StrokeRect(BRect rect,uint8 *pattern); + void StrokeRect(BRect rect,rgb_color col); + void StrokeRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern); +// void StrokeShape(BShape *shape); + void StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern); + void StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, rgb_color col); + +protected: + void Line32(BPoint pt, BPoint pt2, uint8 *pattern); + FrameBuffer *fbuffer; + int hide_cursor; + ServerBitmap *cursor; + int32 drawmode; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/driverharness/SecondDriver.cpp b/src/servers/app/proto6/driverharness/SecondDriver.cpp new file mode 100644 index 0000000000..6b232bb96f --- /dev/null +++ b/src/servers/app/proto6/driverharness/SecondDriver.cpp @@ -0,0 +1,836 @@ +/******************************************************* +* SecondDriver +* +* Second driver is a Drvier abstraction layer for the +* OBOS app_server. It provides access to the Graphic +* HW via the low level api calls. This provides a +* way to run the app_server on real HW. +* This driver also makes it easy for you to run the +* OBOS app_server in parallel with the Be app_server +* when two or more video cards are installed in your +* computer. +* +* @author YNOP (ynop@beunited.org) +* @version beta1 (p5) +* +* History: +* - Added Ellipse (Stroke & Fill) +* Ran though test app to make sure worked +* Fixed HorizLine to used fill_span instead of fill_rect :P +* Updated the Cursor code to work again. +* Made new cursor (Be-hand like) +* - Added StrokeBezir +* Added HorizLine for speed +* - Added HW acceleration methods +* - Brez Line added +* - Created by YNOP +* +* Todo: +* Clean up src and add more comments :P +* Redo StrokeLine to use PenSize +* Redo StrokeLine to use pattern +* Mouse Cursor seems to be broken in proto5 ? +* Add in a way to read app_server_settings file so we can get the real settings +* Make display mode settings more flexable +* Look into FreeType for DrawString :P fun fun fun +* +* Todo methods: +* Blit() DrawBitmap() DrawString() FillArc() FillBezier() FillPolygon() +* FillRegion() FillRoundRect() FillShape() FillTriangle() +* StrokeArc() StrokeRoundRect() StrokeShpae() +* +*******************************************************/ +#include +#include + +#include + +#include "PortLink.h" +#include "ServerProtocol.h" +#include "ServerBitmap.h" +#include "ServerCursor.h" +#include "DebugTools.h" +#include "SecondDriver.h" +#include "SecondDriverHelper.h" + +/******************************************************* +* @description +*******************************************************/ +SecondDriver::SecondDriver(void):DisplayDriver(){ + SetupBezier(); + hide_cursor = false; + fd = -1; + image = -1; + + gah = NULL; + bits = NULL; + bpr = -1; + + scs = NULL; + mc = NULL; + sc = NULL; + + et = NULL; + re = NULL; + + s2sb = NULL; + fr = NULL; + ir = NULL; + s2stb = NULL; + fs = NULL; + +} + +/******************************************************* +* @description +*******************************************************/ +SecondDriver::~SecondDriver(void){ + if(is_initialized){ + } +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::Initialize(void){ + et = NULL; + bits = NULL; + + // Find a driver + fd = get_device(); + if(fd < 0){ + printf("No Device settings found.\n"); + fd = find_device(); + }else{ + printf("Device read from settings file\n"); + } + if(fd < 0){ + printf("No device find, trying fallback stub\n"); + fd = fallback_device(); + } + if(fd < 0){ + printf("Didn't find device :(\n"); + is_initialized = false; + } + /* load the accelerant */ + image = load_accelerant(fd, &gah); + if (image >= 0){ + // Set up the display to a valid resolution + if(get_and_set_mode(gah,&dm) == B_OK){ + // Here we are all good + if(dm.space == B_CMAP8){ + set_palette(gah); + } + get_frame_buffer(gah, &fbc); + bits = (uint32*)fbc.frame_buffer/*_dma*/; + bpr = fbc.bytes_per_row/4; // sould be by depth + + if(dm.flags & B_HARDWARE_CURSOR){ + // Lets check out tha hardwar cursoer stuff :P + printf("Mode supports Hardware cursors\n"); + scs = (set_cursor_shape)gah(B_SET_CURSOR_SHAPE,NULL); + mc = (move_cursor)gah(B_MOVE_CURSOR,NULL); + sc = (show_cursor)gah(B_SHOW_CURSOR,NULL); + } + + // Ok. now lets see if we can add some spiffy + // 2D acceleration to this :) + accelerant_engine_count aec = (accelerant_engine_count)gah(B_ACCELERANT_ENGINE_COUNT,NULL); + uint32 count = aec(); + if(count > 0){ + acquire_engine ae = (acquire_engine)gah(B_ACQUIRE_ENGINE,NULL); + re = (release_engine)gah(B_RELEASE_ENGINE,NULL); + if(ae(B_2D_ACCELERATION,1000,&st,&et) == B_OK){ + // Now lets see if we have some functions + printf("You should be verry happy. You have 2D hardware Acceleration\n"); + s2sb = (screen_to_screen_blit)gah(B_SCREEN_TO_SCREEN_BLIT,NULL); + fr = (fill_rectangle)gah(B_FILL_RECTANGLE,NULL); + ir = (invert_rectangle)gah(B_INVERT_RECTANGLE,NULL); + s2stb = (screen_to_screen_transparent_blit)gah(B_SCREEN_TO_SCREEN_TRANSPARENT_BLIT,NULL); + fs = (fill_span)gah(B_FILL_SPAN,NULL); + } + } + is_initialized = true; + }else{ + // failed to set mode + is_initialized = false; + } + }else{ + // image failed to load + is_initialized = false; + } + + if(is_initialized){ + printf("\n\tSecond Driver by YNOP (ynop@beunited.org)\n"); + printf("\tSecond Driver is copyrigth YNOP 2002\n"); + printf("\tHave fun, its all set up :)\n\n"); + } + + SetCursor((ServerCursor*)NULL); + ShowCursor(); + int32 h = GetHeight(); + int32 w = GetWidth(); + MoveCursorTo(w/2,h/2); + +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::Shutdown(void){ + printf("\tShuting down SecondDriver\n"); + if(et){ + if(re(et,&st) != B_OK){ + printf("Failed to release engine\n"); + } + } + + uninit_accelerant ua = (uninit_accelerant)gah(B_UNINIT_ACCELERANT,NULL); + if(ua){ ua();} + + unload_add_on(image); + + // clsoe the file now... + close(fd); + + + is_initialized=false; +} + +/******************************************************* +* @description +*******************************************************/ +bool SecondDriver::IsInitialized(void){ + return is_initialized; +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::SafeMode(void){ +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::Reset(void){ +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::SetScreen(uint32 space){ + // Clear(51,102,152); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::Clear(uint8 red, uint8 green, uint8 blue){ + rgb_color r; + r.red = red; + r.blue = blue; + r.green = green; + Clear(r); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::Clear(rgb_color col){ + highcol = col; + FillRect(BRect(0,0,GetHeight()-1,GetWidth()-1),NULL); +} + +/******************************************************* +* @description +*******************************************************/ +int32 SecondDriver::GetHeight(void){ + // Gets the height of the current mode + return dm.virtual_height; +} + +/******************************************************* +* @description +*******************************************************/ +int32 SecondDriver::GetWidth(void){ + // Gets the width of the current mode + return dm.virtual_width; +} + +/******************************************************* +* @description +*******************************************************/ +int SecondDriver::GetDepth(void){ + // Gets the color depth of the current mode + return 0; +} + +/******************************************************* +* @description +*******************************************************/ +#ifdef PROTO_4 + void SecondDriver::Blit(BPoint loc, ServerBitmap *src, ServerBitmap *dest) +#else + void SecondDriver::Blit(BRect src, BRect dest) +#endif +{ + printf("Calling Blit (not wirten yet)\n"); + if(s2sb){ + printf("Accelerated Blit\n"); + }else{ + + } +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::DrawBitmap(ServerBitmap *bitmap, BRect source, BRect dest){ + printf("Calling DrawBitmap (not writen yet)\n"); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::DrawChar(char c, BPoint point){ + char string[2]; + string[0]=c; + string[1]='\0'; + DrawString(string,2,point); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::DrawString(char *string, int length, BPoint point){ + printf("DrawString is not writen yet\n"); + + // i would say that libtruetype would do some good herer +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern){ + printf("FillArc is not writen yet\n"); + StrokeArc(centerx,centery,xradius,yradius,angle,span,pattern); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillBezier(BPoint *points, uint8 *pattern){ + printf("FillBezier is not writen yet\n"); + StrokeBezier(points,pattern); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern){ + MidpointEllipse(centerx,centery,x_radius,y_radius,true,pattern); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillPolygon(int *x, int *y, int numpoints, bool is_closed){ + printf("FillPolygon is not writen yet\n"); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillRect(BRect rect, uint8 *pattern){ + if(fr){ + // usieng accelertated 2d file + union{ + uint8 bytes[4]; + uint32 word; + }c1; + + //printf("Accelerated Fill\n"); + fill_rect_params frp; + frp.left =(uint16) rect.left; + frp.top =(uint16) rect.top; + frp.right =(uint16) rect.right; + frp.bottom =(uint16) rect.bottom; + c1.bytes[0] = highcol.blue; + c1.bytes[1] = highcol.green; + c1.bytes[2] = highcol.red; + fr(et,c1.word,&frp,1); + }else{ + for(int32 i = 0;i < rect.Height()-1;i++){ + MovePenTo(BPoint(rect.left,rect.top+i)); + StrokeLine(BPoint(rect.right,rect.top+i),pattern); + //HorizLine(rect.left,rect.right,rect.top+i); // uses accel :P + } + } +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillRect(BRect rect, rgb_color col){ + rgb_color tmpc = highcol; + highcol = col; + FillRect(rect, NULL); + highcol = tmpc; +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillRegion(BRegion *region){ + printf("RillRegion is not writen yet\n"); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern){ + printf("FillRoundRect is not writen yet\n"); + StrokeRoundRect(rect,xradius,yradius,pattern); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillShape(BShape *shape){ + printf("FillShape is not writen yet\n"); + StrokeShape(shape); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern){ + printf("FillTriangle is not writen yet\n"); + StrokeTriangle(first,second,third,rect,pattern); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, rgb_color color){ + printf("FillTriangle is not writen yet\n"); + StrokeTriangle(first,second,third,rect,color); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::HideCursor(void){ + if(sc){ + sc(false); + cursor_visible = false; + }else{ + printf("Shoftware Hide Cursor\n"); + } +} + +/******************************************************* +* @description +*******************************************************/ +bool SecondDriver::IsCursorHidden(void){ + return cursor_visible; +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::ObscureCursor(void){ + // Hides cursor until mouse is moved + HideCursor(); + show_on_move = true; +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::MoveCursorTo(float x, float y){ + if(show_on_move){ + ShowCursor(); + } + if(mc){ + mc((short unsigned int)x,(short unsigned int)y); + }else{ + printf("Software move Cursor\n"); + } +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::MovePenTo(BPoint pt){ + penpos = pt; +} + +/******************************************************* +* @description +*******************************************************/ +BPoint SecondDriver::PenPosition(void){ + return penpos; +} + +/******************************************************* +* @description +*******************************************************/ +float SecondDriver::PenSize(void){ + return pensize; +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::SetCursor(int32 value){ + printf("Setcursoer value?\n"); + // Uh what is this all about? +} + + + + +//0 - 1 = black +//0 - 0 = what +//1 - 0 = trans +//1 - 1 = invert + +// Pointy cursor +/*uint8 andMask[] = { + 63,255,15,255,131,255,128,127,192,31,192,31,224,63,224,63, + 224,31,240,15,243,7,255,131,255,193,255,224,255,240,255,248 +}; +uint8 xorMask[] = { + 192,0,176,0,76,0,67,128,32,96,32,32,16,64,16,64, + 16,32,11,16,12,136,0,68,0,34,0,17,0,9,0,7 +};*/ +// BeOS like cursor +uint8 andMask[] = { + 255,255,255,255,199,255,195,255,195,255,224,31,224,3,240,1, + 240,0,192,0,128,0,128,0,192,0,240,0,252,1,254,7 +}; +uint8 xorMask[] = { + 0,0,0,0,56,0,36,0,36,0,19,224,18,92,9,42, + 8,1,60,0,76,0,66,0,48,0,12,0,2,0,1,0 +}; + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::SetCursor(ServerCursor *cursor){ + printf("Setting cursor\n"); + current_cursor = cursor; +// uint8 *andMask; + // uint8 *xorMask; + if(scs){ +// scs(cursor->width,cursor->height,(short unsigned int)cursor->hotspot.x,(short unsigned int)cursor->hotspot.y,andMask,xorMask); + scs(16,16,3,3,andMask,xorMask); + }else{ + printf("Setting software cursor\n"); + } +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::SetPenSize(float size){ + pensize = size; +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::SetPixel(int x, int y, uint8 *pattern){ + union{ + uint8 bytes[4]; + uint32 word; + }c1; + + c1.bytes[0] = highcol.blue; + c1.bytes[1] = highcol.green; + c1.bytes[2] = highcol.red; + c1.bytes[3] = highcol.alpha; + + *(bits + x + y*bpr) = c1.word; +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::ShowCursor(void){ + printf("\tShow Cursor\n"); + show_on_move = false; + cursor_visible = true; + if(sc){ + sc(true); + }else{ + printf("Software show cursor\n"); + } +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::StrokeArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern){ + printf("StrokeArch is not writen yet\n"); +} + + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::StrokeBezier(BPoint *pts, uint8 *pattern){ + BPoint segment[SEGMENTS + 1]; + computeSegments(pts[0], pts[1],pts[2],pts[3], segment); + + MovePenTo(segment[0]); + + for(int32 s = 1 ; s <= SEGMENTS ; ++s ){ + if(segment[s].x != segment[s - 1].x || segment[s].y != segment[s - 1].y ) { + StrokeLine(segment[s],pattern); + } + } +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::StrokeEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern){ + MidpointEllipse(centerx,centery,x_radius,y_radius,false,pattern); +} + +/******************************************************* +* @description +*******************************************************/ +void SecondDriver::StrokeLine(BPoint point, uint8 *pattern){ + if(penpos.y == point.y){ + HorizLine(penpos.x,point.x,point.y,pattern); + return; + } + + int oct = 0; + int xoff = (int32)penpos.x; + int yoff = (int32)penpos.y; + int32 x2 = (int32)point.x-xoff; + int32 y2 = (int32)point.y-yoff; + int32 x1 = 0; + int32 y1 = 0; +// if(y2==0){ if (x1>x2){int t=x1;x1=x2;x2=t;}HorizLine(x1+xoff,x2+xoff,y1+yoff); return;} + if(y2<0){ y2 = -y2; oct+=4; }//bit2=1 + if(x2<0){ x2 = -x2; oct+=2;}//bit1=1 + if(x2 x2){ int32 t=x1;x1=x2;x2=t; } + if(fr){ + union{ + uint8 bytes[4]; + uint32 word; + }c1; + + //printf("Accelerated HorizLine\n"); + uint16 list[3]; + list[0] = y; + list[1] = x1; + list[2] = x2; + c1.bytes[0] = highcol.blue; + c1.bytes[1] = highcol.green; + c1.bytes[2] = highcol.red; + fs(et,c1.word,list,1); + }else{ + //software hline + printf("\t!!HorizLine without HWaccel is a waist\n"); + for(int32 i = x1; i <= x2;i++){ + SetPixel(i,y,pattern); + } + } + +} + +//void EllipsePoints(float cx,float cy,int32 x, int32 y){ +// view->StrokeLine(BPoint(x+cent.x,y+cent.y),BPoint(x+cent.x,y+cent.y)); +// view->StrokeLine(BPoint(-x+cent.x,y+cent.y),BPoint(-x+cent.x,y+cent.y)); +// view->StrokeLine(BPoint(x+cent.x,-y+cent.y),BPoint(x+cent.x,-y+cent.y)); +// view->StrokeLine(BPoint(-x+cent.x,-y+cent.y),BPoint(-x+cent.x,-y+cent.y)); +#define EllipsePoints(cx,cy,x,y,pattern){ \ + SetPixel( x+cx, y+cx,pattern); \ + SetPixel(-x+cx, y+cx,pattern); \ + SetPixel( x+cx,-y+cx,pattern); \ + SetPixel(-x+cx,-y+cx,pattern); \ +} + + +//void EllipsePointsFill(BPoint cent,int32 x, int32 y,pattern){ +// view->StrokeLine(BPoint(-x+cent.x,y+cent.y),BPoint(x+cent.x,y+cent.y)); +// view->StrokeLine(BPoint(-x+cent.x,-y+cent.y),BPoint(x+cent.x,-y+cent.y)); + + #define EllipsePointsFill(cx,cy,x,y,pattern){ \ + HorizLine(-x+cx,x+cx, y+cy, pattern); \ + HorizLine(-x+cx,x+cx, -y+cy, pattern); \ +} + + +/******************************************************* +* +*******************************************************/ +void SecondDriver::MidpointEllipse(float centx,float centy,int32 xrad, int32 yrad,bool fill,uint8 *pattern){ + if(xrad < 0){ xrad = -xrad; } + if(yrad < 0){ yrad = -yrad; } + double d2; + int32 x = 0; + int32 y = yrad; + + int32 xradSqr = xrad*xrad; + int32 yradSqr = yrad*yrad; + + double dl = yradSqr - (xradSqr*yrad) + (0.25 *xradSqr); + + if(fill){ EllipsePointsFill(centx,centy,x,y,pattern); }else{ EllipsePoints(centx,centy,x,y,pattern); } + + // Test gradient if still in region 1 + while((xradSqr*(y-.5)) > (yradSqr*(x+1))){ + if(dl < 0){ // Select E + dl += yradSqr*(2*x + 3); + }else{ // Select SE + dl += yradSqr*(2*x + 3) + xradSqr*(-2*y + 2); + y--; + } + x++; + if(fill){ EllipsePointsFill(centx,centy,x,y,pattern); }else{ EllipsePoints(centx,centy,x,y,pattern); } + } + + d2 = (yradSqr*(x + .5)*(x + .5)) + (xradSqr*(y-1)*(y-1)) - xradSqr*yradSqr; + while(y > 0){ + if(d2 < 0){ // Select SE + d2 += yradSqr*(2*x + 2) + xradSqr*(-2*y + 3); + x++; + }else{ // Select E + d2 += xradSqr*(-2*y + 3); + } + y--; + if(fill){ EllipsePointsFill(centx,centy,x,y,pattern); }else{ EllipsePoints(centx,centy,x,y,pattern); } + } +} + + + +#ifdef DEBUG_DRIVER_MODULE +#undef DEBUG_DRIVER_MODULE +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/driverharness/SecondDriver.h b/src/servers/app/proto6/driverharness/SecondDriver.h new file mode 100644 index 0000000000..3dcbab2a1f --- /dev/null +++ b/src/servers/app/proto6/driverharness/SecondDriver.h @@ -0,0 +1,123 @@ +#ifndef _SECDRIVER_H_ +#define _SECDRIVER_H_ + +#include +#include +#include +#include +#include // for pattern struct +#include +#include +#include "DisplayDriver.h" + +#include +#include +#include + +class BBitmap; +class PortLink; +class VDWindow; +class ServerCursor; + + +class SecondDriver:public DisplayDriver{ +public: + SecondDriver(void); + virtual ~SecondDriver(void); + + virtual void Initialize(void); // Sets the driver + virtual bool IsInitialized(void); + virtual void Shutdown(void); // You never know when you'll need this + + virtual void SafeMode(void); // Easy-access functions for common tasks + virtual void Reset(void); + virtual void Clear(uint8 red,uint8 green,uint8 blue); + virtual void Clear(rgb_color col); + + // Settings functions + virtual void SetScreen(uint32 space); + virtual int32 GetHeight(void); + virtual int32 GetWidth(void); + virtual int GetDepth(void); + + // Drawing functions + #ifdef PROTO_4 + virtual void Blit(BPoint loc, ServerBitmap *src, ServerBitmap *dest); + #else + virtual void Blit(BRect src, BRect dest); + #endif + virtual void DrawBitmap(ServerBitmap *bitmap, BRect source, BRect dest); + virtual void DrawChar(char c, BPoint point); + virtual void DrawString(char *string, int length, BPoint point); + + virtual void FillArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern); + virtual void FillBezier(BPoint *points, uint8 *pattern); + virtual void FillEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern); + virtual void FillPolygon(int *x, int *y, int numpoints, bool is_closed); + virtual void FillRect(BRect rect, uint8 *pattern); + virtual void FillRect(BRect rect, rgb_color col); + virtual void FillRegion(BRegion *region); + virtual void FillRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern); + virtual void FillShape(BShape *shape); + virtual void FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern); + virtual void FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, rgb_color color); + + virtual void HideCursor(void); + virtual bool IsCursorHidden(void); + virtual void MoveCursorTo(float x, float y); + virtual void MovePenTo(BPoint pt); + virtual void ObscureCursor(void); + virtual BPoint PenPosition(void); + virtual float PenSize(void); + virtual void SetCursor(int32 value); + virtual void SetCursor(ServerCursor *cursor); + virtual void SetPenSize(float size); + virtual void SetPixel(int x, int y, uint8 *pattern); + virtual void ShowCursor(void); + + virtual void StrokeArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern); + virtual void StrokeBezier(BPoint *points, uint8 *pattern); + virtual void StrokeEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern); + virtual void StrokeLine(BPoint point, uint8 *pattern); + virtual void StrokeLine(BPoint pt1, BPoint pt2, rgb_color col); + virtual void StrokePolygon(int *x, int *y, int numpoints, bool is_closed); + virtual void StrokeRect(BRect rect,uint8 *pattern); + virtual void StrokeRect(BRect rect,rgb_color col); + virtual void StrokeRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern); + virtual void StrokeShape(BShape *shape); + virtual void StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern); + virtual void StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, rgb_color color); +private: + void HorizLine(int32 x1,int32 x2,int32 y, uint8 *pattern); + void MidpointEllipse(float centerx, float centery,int32 xrad, int32 yrad,bool fill,uint8 *pattern); +protected: + int hide_cursor; + + int fd; + image_id image; + GetAccelerantHook gah; + display_mode dm; + + frame_buffer_config fbc; + + uint32 *bits; + int32 bpr; + + set_cursor_shape scs; + move_cursor mc; + show_cursor sc; + + sync_token st; + engine_token *et; + release_engine re; + + screen_to_screen_blit s2sb; + fill_rectangle fr; + invert_rectangle ir; + screen_to_screen_transparent_blit s2stb; + fill_span fs; + + +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/driverharness/SecondDriverHelper.h b/src/servers/app/proto6/driverharness/SecondDriverHelper.h new file mode 100644 index 0000000000..ff3ee288d7 --- /dev/null +++ b/src/servers/app/proto6/driverharness/SecondDriverHelper.h @@ -0,0 +1,435 @@ +/******************************************************* +* SecondDriver +* +* Helper methods for SecondDriver. This is where we +* put all the code that inits the real HW and +* seaches for the acceleration methods an all that +* other stuff. +* +* @author YNOP (ynop@beunited.org) +*******************************************************/ +#ifndef _SECDRIVER_HELPER_H_ +#define _SECDRIVER_HELPER_H_ + +//#include +#include +#include + +#include +#include +#include // has ioctl ?:P +//#include +#include + +#define DEV_GRAPHICS "/dev/graphics/" +#define ACCELERANTS_DIR "/accelerants/" +#define DEV_STUB "stub" + +/******************************************************* +* @description Loads the driver from settings ... +*******************************************************/ +int get_device(){ +// 102b_0519_001300 102b_051a_001400 stub + return open(DEV_GRAPHICS"102b_051a_001400", B_READ_WRITE); +// return -1; +} + +/******************************************************* +* @description Loads the stub driver - never fun +*******************************************************/ +int fallback_device(){ + return open(DEV_GRAPHICS DEV_STUB, B_READ_WRITE); +} + +/******************************************************* +* @description Find the first device that it can open +* in the /dev/graphics dir and returns it. +*******************************************************/ +int find_device(){ + DIR *d; + struct dirent *e; + char name_buf[1024]; + int fd = -1; + //bool foundfirst = false; // hacky way of finding second video card in your box + + printf("Probeing %s for device...\n",DEV_GRAPHICS); + + /* open directory apath */ + d = opendir(DEV_GRAPHICS); + if(!d){ return B_ERROR; } + while((e = readdir(d)) != NULL){ + if (!strcmp(e->d_name, ".") || !strcmp(e->d_name, "..") || !strcmp(e->d_name, "stub")){ + continue; + } + strcpy(name_buf, DEV_GRAPHICS); +// strcat(name_buf, "/"); + strcat(name_buf, e->d_name); + fd = open(name_buf, B_READ_WRITE); + ///printf("Opening device %s\n",name_buf); + if(fd >= 0){ + //printf("Open wend ok\n"); + /*if(!foundfirst){ + foundfirst = true; + printf("\tbut we are not going to use it as app_server is\n"); + }else{ + // found it :) + */ printf("\tOpened device %s\n",name_buf); + closedir(d); + return fd; + //} + }else{ + //foundfirst = true; // this is a proper find as the app_server should let us open the dev + printf("\tCouldn't open device %s\n",name_buf); + } + } + closedir(d); + return B_ERROR; +} + +/******************************************************* +* @description Finds and loads the Accelerant for +* this device +*******************************************************/ +image_id load_accelerant(int fd, GetAccelerantHook *hook) { + status_t result; + image_id image = -1; + char + signature[1024], + path[PATH_MAX]; + struct stat st; + const static directory_which vols[] = { + B_USER_ADDONS_DIRECTORY, + B_COMMON_ADDONS_DIRECTORY, + B_BEOS_ADDONS_DIRECTORY + }; + + /* get signature from driver */ + result = ioctl(fd, B_GET_ACCELERANT_SIGNATURE, &signature, sizeof(signature)); + if (result != B_OK){ + printf("Failed to get accelerant signature from drived!\n"); + return result; + } + + printf("Searching for Accelerant named \"%s\"\n",signature); + + // note failure by default + for(int32 i=0; i < (int32)(sizeof (vols) / sizeof (vols[0])); i++) { + //printf("attempting to get path for %ld (%d)\n", i, vols[i]); + if(find_directory(vols[i], -1, false, path, PATH_MAX) != B_OK) { + printf("warning: find directory failed (continueing)\n"); + continue; + } + + strcat (path, ACCELERANTS_DIR); + strcat (path, signature); + printf("\tTrying %s\n",path); + + // don't try to load non-existant files + if (stat(path, &st) != 0) continue; + + // try and load it up.. + image = load_add_on(path); + if (image >= 0) { + printf("\tAccelerant loaded - trying to init\n"); + // get entrypoint from accelerant + result = get_image_symbol(image, B_ACCELERANT_ENTRY_POINT, +#if defined(__INTEL__) + B_SYMBOL_TYPE_ANY, +#else + B_SYMBOL_TYPE_TEXT, +#endif + (void **)hook); + if (result == B_OK) { + init_accelerant ia; + ia = (init_accelerant)(*hook)(B_INIT_ACCELERANT, NULL); + if(ia && ((result = ia(fd)) == B_OK)) { + // we have a winner! + //printf("Accelerant %s \n", path); + printf("\tAccelerant Init() was B_OK\n"); + break; + } else { + printf("\tAccelerant Init() failed: %ld\n", result); + } + } else { + printf("\tCouldn't find the entry point :-(\n"); + } + // unload the accelerant, as we must be able to init! + unload_add_on(image); + } + if (image < 0) printf("\tLoad Image failure. ID: %.8lx (%s)\n", image, strerror(image)); + // mark failure to load image + image = -1; + } + + //printf("Add-on image id: %ld\n", image); + return image; +} + +/******************************************************* +* @description +*******************************************************/ +static const char *spaceToString(uint32 cs) { + const char *s; + switch (cs) { +#define s2s(a) case a: s = #a ; break + s2s(B_RGB32); + s2s(B_RGBA32); + s2s(B_RGB32_BIG); + s2s(B_RGBA32_BIG); + s2s(B_RGB16); + s2s(B_RGB16_BIG); + s2s(B_RGB15); + s2s(B_RGBA15); + s2s(B_RGB15_BIG); + s2s(B_RGBA15_BIG); + s2s(B_CMAP8); + s2s(B_GRAY8); + s2s(B_GRAY1); + s2s(B_YCbCr422); + s2s(B_YCbCr420); + s2s(B_YUV422); + s2s(B_YUV411); + s2s(B_YUV9); + s2s(B_YUV12); + default: + s = "unknown"; break; +#undef s2s + } + return s; +} + +/******************************************************* +* @description +*******************************************************/ +void dump_mode(display_mode *dm) { + display_timing *t = &(dm->timing); + printf(" pixel_clock: %ldKHz\n", t->pixel_clock); + printf(" H: %4d %4d %4d %4d\n", t->h_display, t->h_sync_start, t->h_sync_end, t->h_total); + printf(" V: %4d %4d %4d %4d\n", t->v_display, t->v_sync_start, t->v_sync_end, t->v_total); + printf(" timing flags:"); + if (t->flags & B_BLANK_PEDESTAL) printf(" B_BLANK_PEDESTAL"); + if (t->flags & B_TIMING_INTERLACED) printf(" B_TIMING_INTERLACED"); + if (t->flags & B_POSITIVE_HSYNC) printf(" B_POSITIVE_HSYNC"); + if (t->flags & B_POSITIVE_VSYNC) printf(" B_POSITIVE_VSYNC"); + if (t->flags & B_SYNC_ON_GREEN) printf(" B_SYNC_ON_GREEN"); + if (!t->flags) printf(" (none)\n"); + else printf("\n"); + printf(" refresh rate: %4.2f\n", ((double)t->pixel_clock * 1000) / ((double)t->h_total * (double)t->v_total)); + printf(" color space: %s\n", spaceToString(dm->space)); + printf(" virtual size: %dx%d\n", dm->virtual_width, dm->virtual_height); + printf("dispaly start: %d,%d\n", dm->h_display_start, dm->v_display_start); + + printf(" mode flags:"); + if (dm->flags & B_SCROLL) printf(" B_SCROLL"); + if (dm->flags & B_8_BIT_DAC) printf(" B_8_BIT_DAC"); + if (dm->flags & B_HARDWARE_CURSOR) printf(" B_HARDWARE_CURSOR"); + if (dm->flags & B_PARALLEL_ACCESS) printf(" B_PARALLEL_ACCESS"); +// if (dm->flags & B_SUPPORTS_OVERLAYS) printf(" B_SUPPORTS_OVERLAYS"); + if (!dm->flags) printf(" (none)\n"); + else printf("\n"); +} + +/******************************************************* +* @description +*******************************************************/ +void simple_dump_mode(display_mode *dm){ + //printf("H: %4d\n", t->h_display); + //printf("V: %4d\n", t->v_display); + display_timing *t = &(dm->timing); + printf("Virtual size: %d x %d\n", dm->virtual_width, dm->virtual_height); + printf("Color space: %s\n", spaceToString(dm->space)); + printf("Refresh rate: %4.2f\n", ((double)t->pixel_clock * 1000) / ((double)t->h_total * (double)t->v_total)); +} + +/******************************************************* +* @description +*******************************************************/ +void mode_from_settings(display_mode *dm){ + // display_timing *t = &(dm->timing); + dm->space = B_RGB32; + dm->virtual_width = 800; + dm->virtual_height = 600; + dm->h_display_start = 0; + dm->v_display_start = 0; +} + +/******************************************************* +* @description +*******************************************************/ +status_t get_and_set_mode(GetAccelerantHook gah, display_mode *dm) { + printf("Setting up display mode\n"); + accelerant_mode_count gmc; + uint32 mode_count; + get_mode_list gml; + display_mode *mode_list, target, high, low; + propose_display_mode pdm; + status_t result = B_ERROR; + set_display_mode sdm; + + /* find the propose mode hook */ + pdm = (propose_display_mode)gah(B_PROPOSE_DISPLAY_MODE, NULL); + if (!pdm) { + printf("No B_PROPOSE_DISPLAY_MODE\n"); + goto exit0; + } + /* and the set mode hook */ + sdm = (set_display_mode)gah(B_SET_DISPLAY_MODE, NULL); + if (!sdm) { + printf("No B_SET_DISPLAY_MODE\n"); + goto exit0; + } + + /* how many modes does the driver support */ + gmc = (accelerant_mode_count)gah(B_ACCELERANT_MODE_COUNT, NULL); + if (!gmc) { + printf("No B_ACCELERANT_MODE_COUNT\n"); + goto exit0; + } + mode_count = gmc(); + printf("\tDriver supports %lu differnat video modes\n", mode_count); + if (mode_count == 0) goto exit0; + + /* get a list of graphics modes from the driver */ + gml = (get_mode_list)gah(B_GET_MODE_LIST, NULL); + if (!gml) { + printf("No B_GET_MODE_LIST\n"); + goto exit0; + } + mode_list = (display_mode *)calloc(sizeof(display_mode), mode_count); + if (!mode_list) { + printf("Couldn't calloc() for mode list\n"); + goto exit0; + } + if (gml(mode_list) != B_OK) { + printf("mode list retrieval failed\n"); + goto free_mode_list; + } + + /* take the first mode in the list */ + //printf("\tPropose Display Mode\n------------------------\n"); + //simple_dump_mode(&mode_list[69]); + //mode_from_settings(&mode_list[69]); + target = mode_list[69]; + high = mode_list[69]; + low = mode_list[69]; + /* make as tall a virtual height as possible */ + //target.virtual_height = high.virtual_height = 0xffff; + // virtual hight should only be used if a res larger than + // the screen can handle + /* propose the display mode */ + if (pdm(&target, &low, &high) == B_ERROR) { + printf("propose_display_mode failed\n"); + goto free_mode_list; + } + printf("------Target display mode------\n"); + simple_dump_mode(&target); + printf("-------------------------------\n"); + /* we got a display mode, now set it */ + if (sdm(&target) == B_ERROR) { + printf("set display mode failed\n"); + goto free_mode_list; + } + /* note the mode and success */ + *dm = target; + result = B_OK; + +free_mode_list: + free(mode_list); +exit0: + return result; +} + + +/******************************************************* +* @description +*******************************************************/ +void get_frame_buffer(GetAccelerantHook gah, frame_buffer_config *fbc) { + get_frame_buffer_config gfbc; + gfbc = (get_frame_buffer_config)gah(B_GET_FRAME_BUFFER_CONFIG, NULL); + gfbc(fbc); +} + +/******************************************************* +* @description +*******************************************************/ +sem_id get_sem(GetAccelerantHook gah) { + accelerant_retrace_semaphore ars; + ars = (accelerant_retrace_semaphore)gah(B_ACCELERANT_RETRACE_SEMAPHORE, NULL); + return ars(); +} + +/******************************************************* +* @description +*******************************************************/ +void set_palette(GetAccelerantHook gah) { + set_indexed_colors sic; + sic = (set_indexed_colors)gah(B_SET_INDEXED_COLORS, NULL); + if (sic) { + /* booring grey ramp for now */ + uint8 map[3 * 256]; + uint8 *p = map; + int i; + for (i = 0; i < 256; i++) { + *p++ = i; + *p++ = i; + *p++ = i; + } + sic(256, 0, map, 0); + } +} + +// This is a ll the stuff needed to stroke a Bezier Curve.. +// Note that we should probably wait and alloc this data latter +// on when we stroke our first Curve. That way if no curve ever +// gets render (unlikely i know) then this space would be saved. +#define SEGMENTS 32 +#define Fixed float +static Fixed weight1[SEGMENTS + 1]; +static Fixed weight2[SEGMENTS + 1]; +#define w1(s) weight1[s] +#define w2(s) weight2[s] +#define w3(s) weight2[SEGMENTS - s] +#define w4(s) weight1[SEGMENTS - s] +#define FixMul(a,b) (a)*(b) +#define FixRound(a) ((a-int32(a))>=.5)?(int32(a)+1):(int32(a)) +#define FixRatio(a,b) ((a)/float(b)) + +/******************************************************* +* @description Creats the two Bernstien Pollynomials +* We only need to creat two becase the 1 & 4 are +* mirrors and the 2 & 3 are mirros. +*******************************************************/ +void SetupBezier(){ + Fixed t, zero, one; + int s; + zero = FixRatio(0, 1); + one = FixRatio(1, 1); + + weight1[0] = one; + weight2[0] = zero; + for(s = 1 ;s < SEGMENTS ;++s){ + t = FixRatio(s, SEGMENTS); + weight1[s] = FixMul(one - t, FixMul(one - t, one - t)); + weight2[s] = 3 * FixMul(t, FixMul(t - one, t - one)); + } + weight1[SEGMENTS] = zero; + weight2[SEGMENTS] = zero; +} + +/******************************************************* +* @description Useing the weights of the 4 bernstein +* pollynomials calc the segment endpoints. This is +* the real worker method +*******************************************************/ +static void computeSegments(BPoint p1,BPoint p2, BPoint p3, BPoint p4, BPoint *segment){ + int s; + segment[0] = p1; + for(s = 1;s < SEGMENTS;++s){ + segment[s].y = FixRound(w1(s) * p1.y + w2(s) * p2.y + w3(s) * p3.y + w4(s) * p4.y); + segment[s].x = FixRound(w1(s) * p1.x + w2(s) * p2.x + w3(s) * p3.x + w4(s) * p4.x); + } + segment[SEGMENTS] = p4; +} + +#endif + diff --git a/src/servers/app/proto6/driverharness/ServerBitmap.h b/src/servers/app/proto6/driverharness/ServerBitmap.h new file mode 100644 index 0000000000..bd5d3afc51 --- /dev/null +++ b/src/servers/app/proto6/driverharness/ServerBitmap.h @@ -0,0 +1,40 @@ +#ifndef _SERVER_BITMAP_H_ +#define _SERVER_BITMAP_H_ + +#include +#include +#include +#include "DisplayDriver.h" + +class ServerBitmap +{ +public: + ServerBitmap(BRect rect,color_space space,int32 BytesPerLine=0); + ServerBitmap(int32 w,int32 h,color_space space,int32 BytesPerLine=0); + ServerBitmap(int32 w,int32 h,color_space space, area_id areaID, int32 BytesPerLine=0); + ServerBitmap(void); + ServerBitmap(const char *path); + ~ServerBitmap(void); + void UpdateSettings(void); + void SetBuffer(void *buffer); + uint8 *Buffer(void); + void SetArea(area_id ID); + area_id Area(void); + uint32 BitsLength(void); + BRect Bounds() { return BRect(0,0,width-1,height-1); }; + int32 BytesPerRow(void) { return bytesperline; }; + + int32 width,height; + int32 bytesperline; + color_space cspace; + int bpp; + +protected: + void HandleSpace(color_space space, int32 BytesPerLine); + DisplayDriver *driver; + bool is_vram,is_area; + area_id areaid; + uint8 *buffer; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/driverharness/ServerCursor.cpp b/src/servers/app/proto6/driverharness/ServerCursor.cpp new file mode 100644 index 0000000000..bb11e51760 --- /dev/null +++ b/src/servers/app/proto6/driverharness/ServerCursor.cpp @@ -0,0 +1,136 @@ +/* + ServerCursor.cpp + This is the server-side class used to handle cursors. Note that it + will handle the R5 cursor API, but it will also handle taking a bitmap. + + ServerCursors are 32-bit. Eventually, we will be mapping colors to fit + when the set is called. + + This is new code, and there may be changes to the API before it settles + in. +*/ + +#include "ServerCursor.h" +#include "ServerBitmap.h" +#include +#include + +int8 default_cursor[]={ + 16,1,0,0, + + // data + 0xff, 0x80, 0x80, 0x80, 0x81, 0x00, 0x80, 0x80, 0x80, 0x40, 0x80, 0x80, 0x81, 0x00, 0xa2, 0x00, + 0xd4, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + // mask + 0xff, 0x80, 0xff, 0x80, 0xff, 0x00, 0xff, 0x80, 0xff, 0xc0, 0xff, 0x80, 0xff, 0x00, 0xfe, 0x00, + 0xdc, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +long pow2(int power) +{ + if(power==0) + return 1; + return long(2 << (power-1)); +} + +ServerCursor::ServerCursor(void) +{ + // For when an application is started. This will probably disappear once I + // get the stuff for default cursors established + is_initialized=false; + position.Set(0,0); +} + +ServerCursor::ServerCursor(ServerBitmap *bmp, ServerBitmap *cmask=NULL) +{ + // The OpenBeOS R1 API uses Bitmaps to create cursors - more flexibility that way. + is_initialized=false; + position.Set(0,0); + SetCursor(bmp); +} + +ServerCursor::ServerCursor(int8 *data) +{ + // For handling the idiot R5 API data format + is_initialized=false; + position.Set(0,0); + SetCursor(data); +} + +ServerCursor::~ServerCursor(void) +{ + if(is_initialized) + delete bitmap; +} + +void ServerCursor::SetCursor(int8 *data) +{ + // 68-byte array used in R5 for holding cursors. + // This API has serious problems and should be deprecated(but supported) + // in a future release, perhaps right after the first one + + if(is_initialized) + { + delete bitmap; + } + cspace=B_RGBA32; + + bitmap=new ServerBitmap(16,16,B_RGBA32); + width=16; + height=16; + bounds.Set(0,0,15,15); + + // Now that we have all the setup, we're going to map (for now) the cursor + // to RGBA32. Eventually, there will be support for 16 and 8-bit depths + uint32 black=0xFF000000, + white=0xFFFFFFFF, + *bmppos; + uint16 *cursorpos, *maskpos,cursorflip, maskflip, + cursorval, maskval; + uint8 i,j; + + cursorpos=(uint16*)(data+4); + maskpos=(uint16*)(data+36); + + // for each row in the cursor data + for(j=0;j<16;j++) + { + bmppos=(uint32*)(bitmap->Buffer()+ (j*bitmap->bytesperline) ); + + // On intel, our bytes end up swapped, so we must swap them back + cursorflip=(cursorpos[j] & 0xFF) << 8; + cursorflip |= (cursorpos[j] & 0xFF00) >> 8; + maskflip=(maskpos[j] & 0xFF) << 8; + maskflip |= (maskpos[j] & 0xFF00) >> 8; + + // for each column in each row of cursor data + for(i=0;i<16;i++) + { + // Get the values and dump them to the bitmap + cursorval=cursorflip & pow2(15-i); + maskval=maskflip & pow2(15-i); + bmppos[i]=((cursorval!=0)?black:white) & ((maskval>0)?0xFFFFFFFF:0x00FFFFFF); + } + } +} + +// Currently unimplemented +void ServerCursor::SetCursor(ServerBitmap *bmp, ServerBitmap *cmask=NULL) +{ +/* if(is_initialized) + delete bitmap; + cspace=bmp->cspace; + + bitmap=new ServerBitmap(bmp->width,bmp->height,cspace); + + width=bmp->width; + height=bmp->height; + bounds.Set(0,0,bmp->width-1,bmp->height-1); +*/ +} + +void ServerCursor::MoveTo(int32 x, int32 y) +{ + position.Set(x,y); +} diff --git a/src/servers/app/proto6/driverharness/ServerCursor.h b/src/servers/app/proto6/driverharness/ServerCursor.h new file mode 100644 index 0000000000..b75b822acb --- /dev/null +++ b/src/servers/app/proto6/driverharness/ServerCursor.h @@ -0,0 +1,31 @@ +#ifndef _SERVER_SPRITE_H +#define _SERVER_SPRITE_H + +#include +#include + +class ServerBitmap; + +class ServerCursor +{ +public: + ServerCursor(ServerBitmap *bmp,ServerBitmap *cmask=NULL); + ServerCursor(int8 *data); + ServerCursor(void); + ~ServerCursor(void); + void MoveTo(int32 x, int32 y); + void SetCursor(int8 *data); + void SetCursor(ServerBitmap *bmp, ServerBitmap *cmask=NULL); + + ServerBitmap *bitmap; + + color_space cspace; + BRect bounds; + int width,height; + BPoint position,hotspot; + bool is_initialized; +}; + +extern int8 default_cursor[]; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/driverharness/ServerProtocol.h b/src/servers/app/proto6/driverharness/ServerProtocol.h new file mode 100644 index 0000000000..d2138e2c1b --- /dev/null +++ b/src/servers/app/proto6/driverharness/ServerProtocol.h @@ -0,0 +1,95 @@ +#ifndef _APPSERVER_PROTOCOL_ +#define _APPSERVER_PROTOCOL_ + +#define CREATE_APP 'drca' +#define DELETE_APP 'drda' +#define QUIT_APP 'srqa' + +#define SET_SERVER_PORT 'srsp' + +#define CREATE_WINDOW 'drcw' +#define DELETE_WINDOW 'drdw' +#define SHOW_WINDOW 'drsw' +#define HIDE_WINDOW 'drhw' +#define QUIT_WINDOW 'srqw' + +#define SERVER_PORT_NAME "OBappserver" +#define SERVER_INPUT_PORT "OBinputport" + +#define SET_CURSOR_DATA 'sscd' +#define SET_CURSOR_BCURSOR 'sscb' +#define SET_CURSOR_BBITMAP 'sscB' +#define SHOW_CURSOR 'srsc' +#define HIDE_CURSOR 'srhc' +#define OBSCURE_CURSOR 'sroc' + +#define GFX_COUNT_WORKSPACES 'gcws' +#define GFX_SET_WORKSPACE_COUNT 'ggwc' +#define GFX_CURRENT_WORKSPACE 'ggcw' +#define GFX_ACTIVATE_WORKSPACE 'gaws' +#define GFX_GET_SYSTEM_COLORS 'gsyc' +#define GFX_SET_SYSTEM_COLORS 'gsyc' +#define GFX_SET_SCREEN_MODE 'gssm' +#define GFX_GET_SCROLLBAR_INFO 'ggsi' +#define GFX_SET_SCROLLBAR_INFO 'gssi' +#define GFX_IDLE_TIME 'gidt' +#define GFX_SELECT_PRINTER_PANEL 'gspp' +#define GFX_ADD_PRINTER_PANEL 'gapp' +#define GFX_RUN_BE_ABOUT 'grba' +#define GFX_SET_FOCUS_FOLLOWS_MOUSE 'gsfm' +#define GFX_FOCUS_FOLLOWS_MOUSE 'gffm' + +#define GFX_SET_HIGH_COLOR 'gshc' +#define GFX_SET_LOW_COLOR 'gslc' +#define GFX_SET_VIEW_COLOR 'gsvc' + +#define GFX_STROKE_ARC 'gsar' +#define GFX_STROKE_BEZIER 'gsbz' +#define GFX_STROKE_ELLIPSE 'gsel' +#define GFX_STROKE_LINE 'gsln' +#define GFX_STROKE_POLYGON 'gspy' +#define GFX_STROKE_RECT 'gsrc' +#define GFX_STROKE_ROUNDRECT 'gsrr' +#define GFX_STROKE_SHAPE 'gssh' +#define GFX_STROKE_TRIANGLE 'gstr' + +#define GFX_FILL_ARC 'gfar' +#define GFX_FILL_BEZIER 'gfbz' +#define GFX_FILL_ELLIPSE 'gfel' +#define GFX_FILL_POLYGON 'gfpy' +#define GFX_FILL_RECT 'gfrc' +#define GFX_FILL_REGION 'gfrg' +#define GFX_FILL_ROUNDRECT 'gfrr' +#define GFX_FILL_SHAPE 'gfsh' +#define GFX_FILL_TRIANGLE 'gftr' + +#define GFX_MOVEPENBY 'gmpb' +#define GFX_MOVEPENTO 'gmpt' +#define GFX_SETPENSIZE 'gsps' + +#define GFX_DRAW_STRING 'gdst' +#define GFX_SET_FONT 'gsft' +#define GFX_SET_FONT_SIZE 'gsfs' + +#define GFX_FLUSH 'gfsh' +#define GFX_SYNC 'gsyn' + +#define LAYER_CREATE 'lycr' +#define LAYER_DELETE 'lydl' +#define LAYER_ADD_CHILD 'lyac' +#define LAYER_REMOVE_CHILD 'lyrc' +#define LAYER_REMOVE_SELF 'lyrs' +#define LAYER_SHOW 'lysh' +#define LAYER_HIDE 'lyhd' +#define LAYER_MOVE 'lymv' +#define LAYER_RESIZE 'lyre' +#define LAYER_INVALIDATE 'lyin' +#define LAYER_DRAW 'lydr' + +#define BEGIN_RECT_TRACKING 'rtbg' +#define END_RECT_TRACKING 'rten' + +#define VIEW_GET_TOKEN 'vgtk' +#define VIEW_ADD 'vadd' +#define VIEW_REMOVE 'vrem' +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/driverharness/SystemPalette.cpp b/src/servers/app/proto6/driverharness/SystemPalette.cpp new file mode 100644 index 0000000000..dc3fdcd40f --- /dev/null +++ b/src/servers/app/proto6/driverharness/SystemPalette.cpp @@ -0,0 +1,327 @@ +/* + SystemPalette.cpp + One global function to generate the palette which is the default BeOS + System palette and the variable to go with it +*/ + +#include "SystemPalette.h" + +rgb_color system_palette[256]; + +void GenerateSystemPalette(rgb_color *palette) +{ + int i,j,index=0; + int indexvals1[]={ 255,229,204,179,154,129,105,80,55,30 }, + indexvals2[]={ 255,203,152,102,51,0 }; + rgb_color *currentcol; + + // Grays 0,0,0 -> 248,248,248 by 8's + for(i=0; i<=248; i+=8,index++) + { + currentcol=&(palette[index]); + currentcol->red=i; + currentcol->green=i; + currentcol->blue=i; + currentcol->alpha=255; + } + + // Blues, following indexvals1 + for(i=0; i<10; i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=0; + currentcol->green=0; + currentcol->blue=indexvals1[i]; + currentcol->alpha=255; + } + + // Reds, following indexvals1 - 1 + for(i=0; i<10; i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=indexvals1[i] - 1; + currentcol->green=0; + currentcol->blue=0; + currentcol->alpha=255; + } + + // Greens, following indexvals1 - 1 + for(i=0; i<10; i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=0; + currentcol->green=indexvals1[i] - 1; + currentcol->blue=0; + currentcol->alpha=255; + } + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=152; + currentcol->blue=51; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=255; + currentcol->blue=255; + index++; + + for(j=1;j<5;j++) + { + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=indexvals2[j]; + currentcol->green=255; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + } + + for(i=0;i<4;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=255; + currentcol->green=152; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=102; + currentcol->blue=51; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=102; + currentcol->blue=0; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=102; + currentcol->blue=255; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=102; + currentcol->blue=203; + index++; + + // Mostly array runs from here on out + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=203; + currentcol->green=203; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=152; + currentcol->green=255; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=102; + currentcol->green=255; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=51; + currentcol->green=255; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=255; + currentcol->green=102; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=102; + currentcol->blue=152; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=102; + currentcol->blue=102; + index++; + + // knocks out 4 assignment loops at once :) + for(j=1;j<5;j++) + { + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=indexvals2[j]; + currentcol->green=152; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + } + + currentcol+=sizeof(rgb_color); + currentcol->red=230; + currentcol->green=134; + currentcol->blue=0; + index++; + + for(i=1;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=255; + currentcol->green=51; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=102; + currentcol->blue=51; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=102; + currentcol->blue=0; + index++; + + for(j=1;j<5;j++) + { + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=indexvals2[j]; + currentcol->green=102; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + } + + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=255; + currentcol->green=0; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=175; + currentcol->blue=19; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=51; + currentcol->blue=255; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=0; + currentcol->green=51; + currentcol->blue=203; + index++; + + for(j=1;j<5;j++) + { + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=indexvals2[j]; + currentcol->green=51; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + } + + for(i=3;i>=0;i--,index++) + { + currentcol=&(palette[index]); + currentcol->red=255; + currentcol->green=203; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + for(i=2;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=0; + currentcol->green=51; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + for(i=0;i<5;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=203; + currentcol->green=0; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=227; + currentcol->blue=70; + index++; + + for(j=2;j<6;j++) + { + for(i=0;i<6;i++,index++) + { + currentcol=&(palette[index]); + currentcol->red=indexvals2[j]; + currentcol->green=0; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + } + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=203; + currentcol->blue=51; + index++; + + currentcol+=sizeof(rgb_color); + currentcol->red=255; + currentcol->green=203; + currentcol->blue=0; + index++; + + for(i=5;i<=0;i--,index++) + { + currentcol=&(palette[index]); + currentcol->red=255; + currentcol->green=255; + currentcol->blue=indexvals2[i]; + currentcol->alpha=255; + } + +} diff --git a/src/servers/app/proto6/driverharness/SystemPalette.h b/src/servers/app/proto6/driverharness/SystemPalette.h new file mode 100644 index 0000000000..1bc1d7188a --- /dev/null +++ b/src/servers/app/proto6/driverharness/SystemPalette.h @@ -0,0 +1,9 @@ +#ifndef _SYSTEM_PALETTE_H_ +#define _SYSTEM_PALETTE_H_ + +#include + +void GenerateSystemPalette(rgb_color *palette); +extern rgb_color system_palette[]; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/driverharness/ViewDriver.cpp b/src/servers/app/proto6/driverharness/ViewDriver.cpp new file mode 100644 index 0000000000..584e344f6c --- /dev/null +++ b/src/servers/app/proto6/driverharness/ViewDriver.cpp @@ -0,0 +1,1080 @@ +/* + ViewDriver: + First, slowest, and easiest driver class in the app_server which is designed + to utilize the BeOS graphics functions to cut out a lot of junk in getting the + drawing infrastructure in this server. + + The concept is to have VDView::Draw() draw a bitmap, which is a "frame buffer" + of sorts, utilize a second view to write to it. This cuts out + the most problems with having a crapload of code to get just right without + having to write a bunch of unit tests + + Components: 3 classes, VDView, VDWindow, and ViewDriver + + ViewDriver - a wrapper class which mostly posts messages to the VDWindow + VDWindow - does most of the work. + VDView - doesn't do all that much except display the rendered bitmap +*/ + +#define DEBUG_DRIVER_MODULE +//#define DEBUG_SERVER_EMU + +//#define DISABLE_SERVER_EMU + +#include +#include +#include +#include +#include +#include +#include +#include "PortLink.h" +#include "ServerProtocol.h" +#include "ServerBitmap.h" +#include "ViewDriver.h" +#include "ServerCursor.h" +#include "DebugTools.h" + +enum +{ +VDWIN_CLEAR=100, + +VDWIN_SHOWCURSOR, +VDWIN_HIDECURSOR, +VDWIN_OBSCURECURSOR, +VDWIN_MOVECURSOR, +VDWIN_SETCURSOR, +}; + +ViewDriver *viewdriver_global; + +VDView::VDView(BRect bounds) + : BView(bounds,"viewdriver_view",B_FOLLOW_ALL, B_WILL_DRAW) +{ + viewbmp=new BBitmap(bounds,B_RGB32,true); + + // This link for sending mouse messages to the OBAppServer. + // This is only to take the place of the Input Server. I suppose I could write + // an addon filter to be more like the Input Server, but then I wouldn't be working + // on this thing! :P + serverlink=new PortLink(find_port(SERVER_INPUT_PORT)); + +#ifdef DEBUG_DRIVER_MODULE + printf("VDView: app_server input port: %ld\n",serverlink->GetPort()); +#endif + + // Create a cursor which isn't just a box + cursor=new BBitmap(BRect(0,0,20,20),B_RGBA32,true); + BView *v=new BView(cursor->Bounds(),"v", B_FOLLOW_NONE, B_WILL_DRAW); + hide_cursor=0; + + cursor->Lock(); + cursor->AddChild(v); + + v->SetHighColor(255,255,255,0); + v->FillRect(cursor->Bounds()); + v->SetHighColor(255,0,0,255); + v->FillTriangle(cursor->Bounds().LeftTop(),cursor->Bounds().RightTop(),cursor->Bounds().LeftBottom()); + + cursor->RemoveChild(v); + cursor->Unlock(); + + cursorframe=cursor->Bounds(); + oldcursorframe=cursor->Bounds(); +} + +VDView::~VDView(void) +{ + delete serverlink; + delete viewbmp; + delete cursor; +} + +void VDView::AttachedToWindow(void) +{ +} + +void VDView::Draw(BRect rect) +{ + if(viewbmp) + { + DrawBitmapAsync(viewbmp,oldcursorframe,oldcursorframe); + DrawBitmapAsync(viewbmp,rect,rect); + + if(hide_cursor==0 && obscure_cursor==false) + { + SetDrawingMode(B_OP_ALPHA); + DrawBitmapAsync(cursor,cursor->Bounds(),cursorframe); + SetDrawingMode(B_OP_COPY); + } + Sync(); + } +} + +// These functions emulate the Input Server by sending the *exact* same kind of messages +// to the server's port. Being we're using a regular window, it would make little sense +// to do anything else. + +void VDView::MouseDown(BPoint pt) +{ +#ifdef DEBUG_SERVER_EMU +printf("ViewDriver::MouseDown\t"); +#endif + // Attach data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - modifier keys down + // 5) int32 - buttons down + // 6) int32 - clicks +#ifndef DISABLE_SERVER_EMU + BPoint p; + + uint32 buttons, + mod=modifiers(), + clicks=1; // can't get the # of clicks without a *lot* of extra work :( + + int64 time=(int64)real_time_clock(); + + GetMouse(&p,&buttons); + + serverlink->SetOpCode(B_MOUSE_DOWN); + serverlink->Attach(&time, sizeof(int64)); + serverlink->Attach(&pt.x,sizeof(float)); + serverlink->Attach(&pt.y,sizeof(float)); + serverlink->Attach(&mod, sizeof(uint32)); + serverlink->Attach(&buttons, sizeof(uint32)); + serverlink->Attach(&clicks, sizeof(uint32)); + serverlink->Flush(); +#endif +} + +void VDView::MouseMoved(BPoint pt, uint32 transit, const BMessage *msg) +{ + // Attach data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - buttons down +#ifndef DISABLE_SERVER_EMU + BPoint p; + uint32 buttons; + int64 time=(int64)real_time_clock(); + + serverlink->SetOpCode(B_MOUSE_MOVED); + serverlink->Attach(&time,sizeof(int64)); + serverlink->Attach(&pt.x,sizeof(float)); + serverlink->Attach(&pt.y,sizeof(float)); + GetMouse(&p,&buttons); + serverlink->Attach(&buttons,sizeof(int32)); + serverlink->Flush(); +#endif +} + +void VDView::MouseUp(BPoint pt) +{ +#ifdef DEBUG_SERVER_EMU +printf("ViewDriver::MouseUp\t"); +#endif + // Attach data: + // 1) int64 - time of mouse click + // 2) float - x coordinate of mouse click + // 3) float - y coordinate of mouse click + // 4) int32 - modifier keys down +#ifndef DISABLE_SERVER_EMU + BPoint p; + + uint32 buttons, + mod=modifiers(); + + int64 time=(int64)real_time_clock(); + + GetMouse(&p,&buttons); + + serverlink->SetOpCode(B_MOUSE_UP); + serverlink->Attach(&time, sizeof(int64)); + serverlink->Attach(&pt.x,sizeof(float)); + serverlink->Attach(&pt.y,sizeof(float)); + serverlink->Attach(&mod, sizeof(uint32)); + serverlink->Flush(); +#endif +} + +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- + +VDWindow::VDWindow(void) + : BWindow(BRect(100,60,740,540),"OBOS App Server, P6",B_TITLED_WINDOW, + B_NOT_ZOOMABLE | B_NOT_RESIZABLE) +{ + view=new VDView(Bounds()); + AddChild(view); +} + +VDWindow::~VDWindow(void) +{ +} + +void VDWindow::MessageReceived(BMessage *msg) +{ + switch(msg->what) + { + case VDWIN_SHOWCURSOR: + { + if(view->hide_cursor>0) + { + view->hide_cursor--; +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: ShowCursor() - still hidden\n"); +#endif + } + if(view->hide_cursor==0) + { +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: ShowCursor() - cursor shown\n"); +#endif + view->Invalidate(view->cursorframe); + } + break; + } + case VDWIN_HIDECURSOR: + { + view->hide_cursor++; +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: HideCursor()\n"); +#endif + if(view->hide_cursor==1) + { +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: HideCursor() - cursor was hidden\n"); +#endif + view->Invalidate(view->cursorframe); + } + break; + } + case VDWIN_OBSCURECURSOR: + { +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: ObscureCursor()\n"); +#endif + view->obscure_cursor=true; + view->Invalidate(view->cursorframe); + break; + } + case VDWIN_MOVECURSOR: + { + float x,y; + msg->FindFloat("x",&x); + msg->FindFloat("y",&y); + + // this was changed because an extra message was + // sent even though the mouse was never moved + if(view->cursorframe.left!=x || view->cursorframe.top!=y) + { + if(view->obscure_cursor) + view->obscure_cursor=false; + + view->oldcursorframe=view->cursorframe; + view->cursorframe.OffsetTo(x,y); + } + + if(view->hide_cursor==0) + view->Invalidate(view->oldcursorframe); + break; + } + case VDWIN_SETCURSOR: + { +#ifdef DEBUG_DRIVER_MODULE +printf("ViewDriver:: SetCursor()\n"); +#endif + ServerCursor *cdata; + msg->FindPointer("SCursor",(void**)&cdata); + + if(cdata!=NULL) + { + BBitmap *bmp=new BBitmap(BRect(0,0,cdata->width-1,cdata->height-1), + cdata->cspace); + + // Copy the server bitmap in the cursor to a BBitmap + uint8 *sbmppos=(uint8*)cdata->bitmap->Buffer(), + *bbmppos=(uint8*)bmp->Bits(); + + int32 bytes=cdata->bitmap->bytesperline, + bbytes=bmp->BytesPerRow(); + + for(int i=0;iheight;i++) + memcpy(bbmppos+(i*bbytes), sbmppos+(i*bytes), bytes); + + // Replace the bitmap + delete view->cursor; + view->cursor=bmp; + view->Invalidate(view->cursorframe); + break; + } + break; + } + default: + BWindow::MessageReceived(msg); + break; + } +} + +bool VDWindow::QuitRequested(void) +{ + port_id serverport=find_port(SERVER_PORT_NAME); + + if(serverport!=B_NAME_NOT_FOUND) + write_port(serverport,B_QUIT_REQUESTED,NULL,0); + + return true; +} + +void VDWindow::WindowActivated(bool active) +{ + // This is just to hide the regular system cursor so we can see our own + if(active) + be_app->HideCursor(); + else + be_app->ShowCursor(); +} + +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- + +ViewDriver::ViewDriver(void) +{ + viewdriver_global=this; + screenwin=new VDWindow(); + framebuffer=screenwin->view->viewbmp; + serverlink=screenwin->view->serverlink; + hide_cursor=0; +} + +ViewDriver::~ViewDriver(void) +{ + if(is_initialized) + { + screenwin->Lock(); + screenwin->Quit(); + } +} + +void ViewDriver::Initialize(void) +{ + drawview=new BView(framebuffer->Bounds(),"drawview",B_FOLLOW_ALL, B_WILL_DRAW); + framebuffer->AddChild(drawview); + + hide_cursor=0; + obscure_cursor=false; + + SetPenSize(1.0); + MovePenTo(BPoint(0,0)); + is_initialized=true; + + // We can afford to call the above functions without locking + // because the window is locked until Show() is first called + screenwin->Show(); +} + +void ViewDriver::Shutdown(void) +{ + locker->Lock(); + is_initialized=false; + locker->Unlock(); +} + +bool ViewDriver::IsInitialized(void) +{ + return is_initialized; +} + +void ViewDriver::SafeMode(void) +{ + SetScreen(B_8_BIT_640x480); +} + +void ViewDriver::Reset(void) +{ + SafeMode(); + Clear(255,255,255); +} + +void ViewDriver::SetScreen(uint32 space) +{ + screenwin->Lock(); + int16 w=640,h=480; + color_space s; + + switch(space) + { + case B_32_BIT_800x600: + case B_16_BIT_800x600: + case B_8_BIT_800x600: + { + w=800; h=600; + break; + } + case B_32_BIT_1024x768: + case B_16_BIT_1024x768: + case B_8_BIT_1024x768: + { + w=1024; h=768; + break; + } + default: + break; + } + screenwin->ResizeTo(w-1,h-1); + + switch(space) + { + case B_32_BIT_640x480: + case B_32_BIT_800x600: + case B_32_BIT_1024x768: + s=B_RGBA32; + break; + case B_16_BIT_640x480: + case B_16_BIT_800x600: + case B_16_BIT_1024x768: + s=B_RGBA15; + break; + case B_8_BIT_640x480: + case B_8_BIT_800x600: + case B_8_BIT_1024x768: + s=B_CMAP8; + break; + default: + break; + } + + + delete framebuffer; + + screenwin->view->viewbmp=new BBitmap(BRect(0,0,w-1,h-1),s,true); + framebuffer=screenwin->view->viewbmp; + drawview=new BView(framebuffer->Bounds(),"drawview",B_FOLLOW_ALL, B_WILL_DRAW); + framebuffer->AddChild(drawview); + + screenwin->Unlock(); +} + +void ViewDriver::Clear(uint8 red, uint8 green, uint8 blue) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->SetHighColor(red,green,blue); + drawview->FillRect(drawview->Bounds()); + drawview->Sync(); + screenwin->view->Invalidate(); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::Clear(rgb_color col) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->SetHighColor(col); + drawview->FillRect(drawview->Bounds()); + drawview->Sync(); + screenwin->view->Invalidate(); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +int32 ViewDriver::GetHeight(void) +{ + screenwin->Lock(); + int32 h=framebuffer->Bounds().IntegerHeight(); + screenwin->Unlock(); + + return h; +} + +int32 ViewDriver::GetWidth(void) +{ + screenwin->Lock(); + int32 w=framebuffer->Bounds().IntegerWidth(); + screenwin->Unlock(); + + return w; +} + +int ViewDriver::GetDepth(void) +{ + return 0; +} + +void ViewDriver::AddLine(BPoint pt1, BPoint pt2, rgb_color col) +{ + drawview->AddLine(pt1,pt2,col); + laregion.Include(BRect(pt1,pt2)); +} + +void ViewDriver::BeginLineArray(int32 count) +{ + // NOTE: the unlocking is done in EndLineArray()! + screenwin->Lock(); + framebuffer->Lock(); + laregion.MakeEmpty(); + drawview->BeginLineArray(count); +} + +void ViewDriver::Blit(BRect src, BRect dest) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->CopyBits(src,dest); + drawview->Sync(); + screenwin->view->Invalidate(dest); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::DrawBitmap(ServerBitmap *bitmap) +{ +} + +void ViewDriver::DrawLineArray(int32 count,BPoint *start, BPoint *end, rgb_color *color) +{ + screenwin->Lock(); + framebuffer->Lock(); + + BRegion invalid; + drawview->BeginLineArray(count+1); + for(int32 i=0;iAddLine(start[i],end[i],color[i]); + invalid.Include(BRect(start[i],end[i])); + } + drawview->EndLineArray(); + drawview->Sync(); + screenwin->view->Invalidate(invalid.Frame()); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::DrawChar(char c, BPoint point) +{ + char string[2]; + string[0]=c; + string[1]='\0'; + DrawString(string,2,point); +} + +void ViewDriver::DrawString(char *string, int length, BPoint point) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->DrawString(string,length,point); + font_height fheight; + drawview->GetFontHeight(&fheight); + BRect invalid(point,BPoint(point.x+drawview->StringWidth(string,length), + fheight.ascent+5)); + drawview->Sync(); + screenwin->view->Invalidate(invalid); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::EndLineArray(void) +{ + // NOTE: the locking is done in BeginLineArray()! + drawview->EndLineArray(); + drawview->Sync(); + screenwin->view->Invalidate(laregion.Frame()); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::FillArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pat) +{ + screenwin->Lock(); + framebuffer->Lock(); + if(pat!=NULL) + drawview->FillArc(BPoint(centerx,centery),xradius,yradius,angle,span,*((pattern*)pat)); + else + drawview->FillArc(BPoint(centerx,centery),xradius,yradius,angle,span); + drawview->Sync(); + screenwin->view->Invalidate(BRect(centerx-xradius,centery-yradius, + centerx+xradius,centery+yradius)); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::FillBezier(BPoint *points, uint8 *pat) +{ + screenwin->Lock(); + framebuffer->Lock(); + if(pat!=NULL) + drawview->FillBezier(points,*((pattern*)pat)); + else + drawview->FillBezier(points); + drawview->Sync(); + + // Invalidate the whole view until I get around to adding in the invalid rect calc code + screenwin->view->Invalidate(); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::FillEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pat) +{ + screenwin->Lock(); + framebuffer->Lock(); + if(pat!=NULL) + drawview->FillEllipse(BPoint(centerx,centery),x_radius,y_radius,*((pattern*)pat)); + else + drawview->FillEllipse(BPoint(centerx,centery),x_radius,y_radius); + drawview->Sync(); + screenwin->view->Invalidate(BRect(centerx-x_radius,centery-y_radius, + centerx+x_radius,centery+y_radius)); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::FillPolygon(int *x, int *y, int numpoints, bool is_closed) +{ +} + +void ViewDriver::FillRect(BRect rect, uint8 *pat) +{ + screenwin->Lock(); + framebuffer->Lock(); + if(pat!=NULL) + drawview->FillRect(rect,*((pattern*)pat)); + else + drawview->FillRect(rect); + drawview->Sync(); + screenwin->view->Invalidate(rect); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::FillRect(BRect rect, rgb_color col) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->SetHighColor(col); + drawview->FillRect(rect); + drawview->SetHighColor(highcolor); + drawview->Sync(); + screenwin->view->Invalidate(rect); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::FillRegion(BRegion *region) +{ +} + +void ViewDriver::FillRoundRect(BRect rect,float xradius, float yradius, uint8 *pat) +{ + screenwin->Lock(); + framebuffer->Lock(); + if(pat!=NULL) + drawview->FillRoundRect(rect,xradius,yradius,*((pattern*)pat)); + else + drawview->FillRoundRect(rect,xradius,yradius); + drawview->Sync(); + screenwin->view->Invalidate(rect); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::FillShape(BShape *shape) +{ +} + +void ViewDriver::FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pat) +{ + screenwin->Lock(); + framebuffer->Lock(); + if(pat!=NULL) + drawview->FillTriangle(first,second,third,rect,*((pattern*)pat)); + else + drawview->FillTriangle(first,second,third,rect); + drawview->Sync(); + screenwin->view->Invalidate(rect); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, rgb_color col) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->SetHighColor(col); + drawview->FillTriangle(first,second,third,rect); + drawview->SetHighColor(highcolor); + drawview->Sync(); + screenwin->view->Invalidate(rect); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::HideCursor(void) +{ + screenwin->Lock(); + locker->Lock(); + + hide_cursor++; + screenwin->PostMessage(VDWIN_HIDECURSOR); + + locker->Unlock(); + screenwin->Unlock(); + +} + +bool ViewDriver::IsCursorHidden(void) +{ + screenwin->Lock(); + bool value=(hide_cursor>0)?true:false; + screenwin->Unlock(); + return value; +} + +void ViewDriver::ObscureCursor(void) +{ + screenwin->Lock(); + screenwin->PostMessage(VDWIN_OBSCURECURSOR); + screenwin->Unlock(); +} + +void ViewDriver::MoveCursorTo(float x, float y) +{ + screenwin->Lock(); + BMessage *msg=new BMessage(VDWIN_MOVECURSOR); + msg->AddFloat("x",x); + msg->AddFloat("y",y); + screenwin->PostMessage(msg); + screenwin->Unlock(); +} + +void ViewDriver::MovePenTo(BPoint pt) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->MovePenTo(pt); + penpos=pt; + framebuffer->Unlock(); + screenwin->Unlock(); +} + +BPoint ViewDriver::PenPosition(void) +{ + return penpos; +} + +float ViewDriver::PenSize(void) +{ + return pensize; +} + +void ViewDriver::SetCursor(ServerCursor *cursor) +{ + if(cursor!=NULL) + { + screenwin->Lock(); + BBitmap *bmp=new BBitmap(BRect(0,0,cursor->width-1,cursor->height-1), + cursor->cspace); + + // Copy the server bitmap in the cursor to a BBitmap + uint8 *sbmppos=(uint8*)cursor->bitmap->Buffer(), + *bbmppos=(uint8*)bmp->Bits(); + + int32 bytes=cursor->bitmap->bytesperline, + bbytes=bmp->BytesPerRow(); + + for(int i=0;iheight;i++) + memcpy(bbmppos+(i*bbytes), sbmppos+(i*bytes), bytes); + + // Replace the bitmap + delete screenwin->view->cursor; + screenwin->view->cursor=bmp; + screenwin->view->Invalidate(screenwin->view->cursorframe); + screenwin->Unlock(); + } +} + +void ViewDriver::SetPenSize(float size) +{ + screenwin->Lock(); + framebuffer->Lock(); + pensize=size; + drawview->SetPenSize(size); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::SetHighColor(uint8 r,uint8 g,uint8 b,uint8 a=255) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->SetHighColor(r,g,b,a); + highcolor.red=r; + highcolor.green=g; + highcolor.blue=b; + highcolor.alpha=a; + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::SetHighColor(rgb_color col) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->SetHighColor(col); + highcolor=col; + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::SetLowColor(uint8 r,uint8 g,uint8 b,uint8 a=255) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->SetLowColor(r,g,b,a); + lowcolor.red=r; + lowcolor.green=g; + lowcolor.blue=b; + lowcolor.alpha=a; + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::SetLowColor(rgb_color col) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->SetLowColor(col); + lowcolor=col; + framebuffer->Unlock(); + screenwin->Unlock(); +} + +drawing_mode ViewDriver::GetDrawingMode(void) +{ + drawing_mode dm; + + screenwin->Lock(); + framebuffer->Lock(); + dm=drawview->DrawingMode(); + framebuffer->Unlock(); + screenwin->Unlock(); + return dm; +} + +void ViewDriver::SetDrawingMode(drawing_mode dmode) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->SetDrawingMode(dmode); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::SetPixel(int x, int y, uint8 *pattern) +{ +} + +void ViewDriver::ShowCursor(void) +{ + screenwin->Lock(); + if(hide_cursor>0) + { + hide_cursor--; + screenwin->PostMessage(VDWIN_SHOWCURSOR); + } + screenwin->Unlock(); +} + +float ViewDriver::StringWidth(const char *string, int32 length) +{ + return drawview->StringWidth(string,length); +} + +void ViewDriver::StrokeArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pat) +{ + screenwin->Lock(); + framebuffer->Lock(); + if(pat!=NULL) + drawview->StrokeArc(BPoint(centerx,centery),xradius,yradius,angle,span,*((pattern*)pat)); + else + drawview->StrokeArc(BPoint(centerx,centery),xradius,yradius,angle,span); + drawview->Sync(); + screenwin->view->Invalidate(BRect(centerx-xradius,centery-yradius, + centerx+xradius,centery+yradius)); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::StrokeBezier(BPoint *points, uint8 *pat) +{ + screenwin->Lock(); + framebuffer->Lock(); + if(pat!=NULL) + drawview->StrokeBezier(points,*((pattern*)pat)); + else + drawview->StrokeBezier(points); + drawview->Sync(); + + // Invalidate the whole view until I get around to adding in the invalid rect calc code + screenwin->view->Invalidate(); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::StrokeEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pat) +{ + screenwin->Lock(); + framebuffer->Lock(); + if(pat!=NULL) + drawview->StrokeEllipse(BPoint(centerx,centery),x_radius,y_radius,*((pattern*)pat)); + else + drawview->StrokeEllipse(BPoint(centerx,centery),x_radius,y_radius); + drawview->Sync(); + screenwin->view->Invalidate(BRect(centerx-x_radius,centery-y_radius, + centerx+x_radius,centery+y_radius)); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::StrokeLine(BPoint point, uint8 *pat) +{ + screenwin->Lock(); + framebuffer->Lock(); + if(pat!=NULL) + drawview->StrokeLine(point,*((pattern*)pat)); + else + drawview->StrokeLine(point); + drawview->Sync(); + screenwin->view->Invalidate(BRect(penpos,point)); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::StrokeLine(BPoint pt1, BPoint pt2, rgb_color col) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->SetHighColor(col); + drawview->StrokeLine(pt1,pt2); + drawview->SetHighColor(highcolor); + drawview->Sync(); + screenwin->view->Invalidate(BRect(pt1,pt2)); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::StrokePolygon(int *x, int *y, int numpoints, bool is_closed) +{ + screenwin->Lock(); + framebuffer->Lock(); + + BRegion invalid; + + drawview->BeginLineArray(numpoints+2); + BPoint start,end; + for(int i=1;iAddLine(start,end,highcolor); + invalid.Include(BRect(start,end)); + } + + if(is_closed) + { + start.Set(x[numpoints-1],y[numpoints-1]); + end.Set(x[0],y[0]); + drawview->AddLine(start,end,highcolor); + invalid.Include(BRect(start,end)); + } + drawview->EndLineArray(); + + drawview->Sync(); + screenwin->view->Invalidate(invalid.Frame()); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::StrokeRect(BRect rect, uint8 *pat) +{ + screenwin->Lock(); + framebuffer->Lock(); + if(pat!=NULL) + drawview->StrokeRect(rect,*((pattern*)pat)); + else + drawview->StrokeRect(rect); + drawview->Sync(); + screenwin->view->Invalidate(rect); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::StrokeRect(BRect rect, rgb_color col) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->SetHighColor(col); + drawview->StrokeRect(rect); + drawview->SetHighColor(highcolor); + drawview->Sync(); + screenwin->view->Invalidate(rect); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::StrokeRoundRect(BRect rect,float xradius, float yradius, uint8 *pat) +{ + screenwin->Lock(); + framebuffer->Lock(); + if(pat!=NULL) + drawview->StrokeRoundRect(rect,xradius,yradius,*((pattern*)pat)); + else + drawview->StrokeRoundRect(rect,xradius,yradius); + drawview->Sync(); + screenwin->view->Invalidate(rect); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::StrokeShape(BShape *shape) +{ +} + +void ViewDriver::StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pat) +{ + screenwin->Lock(); + framebuffer->Lock(); + if(pat!=NULL) + drawview->StrokeTriangle(first,second,third,rect,*((pattern*)pat)); + else + drawview->StrokeTriangle(first,second,third,rect); + drawview->Sync(); + screenwin->view->Invalidate(rect); + framebuffer->Unlock(); + screenwin->Unlock(); +} + +void ViewDriver::StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, rgb_color col) +{ + screenwin->Lock(); + framebuffer->Lock(); + drawview->SetHighColor(col); + drawview->StrokeTriangle(first,second,third,rect); + drawview->SetHighColor(highcolor); + drawview->Sync(); + screenwin->view->Invalidate(rect); + framebuffer->Unlock(); + screenwin->Unlock(); +} diff --git a/src/servers/app/proto6/driverharness/ViewDriver.h b/src/servers/app/proto6/driverharness/ViewDriver.h new file mode 100644 index 0000000000..97c5809e16 --- /dev/null +++ b/src/servers/app/proto6/driverharness/ViewDriver.h @@ -0,0 +1,139 @@ +#ifndef _VIEWDRIVER_H_ +#define _VIEWDRIVER_H_ + +#include +#include +#include +#include +#include // for pattern struct +#include +#include +#include +#include "DisplayDriver.h" + +class BBitmap; +class PortLink; +class VDWindow; +class ServerCursor; + +class VDView : public BView +{ +public: + VDView(BRect bounds); + ~VDView(void); + void AttachedToWindow(void); + void Draw(BRect rect); + void MouseDown(BPoint pt); + void MouseMoved(BPoint pt, uint32 transit, const BMessage *msg); + void MouseUp(BPoint pt); + + BBitmap *viewbmp; + PortLink *serverlink; + + int hide_cursor; + BBitmap *cursor; + + BRect cursorframe, oldcursorframe; + bool obscure_cursor; +}; + +class VDWindow : public BWindow +{ +public: + VDWindow(void); + ~VDWindow(void); + void MessageReceived(BMessage *msg); + bool QuitRequested(void); + void WindowActivated(bool active); + + VDView *view; +}; + +class ViewDriver : public DisplayDriver +{ +public: + ViewDriver(void); + ~ViewDriver(void); + + void Initialize(void); // Sets the driver + bool IsInitialized(void); + void Shutdown(void); // You never know when you'll need this + + void SafeMode(void); // Easy-access functions for common tasks + void Reset(void); + void Clear(uint8 red,uint8 green,uint8 blue); + void Clear(rgb_color col); + + // Settings functions + void SetScreen(uint32 space); + int32 GetHeight(void); + int32 GetWidth(void); + int GetDepth(void); + + // Drawing functions + void AddLine(BPoint pt1, BPoint pt2, rgb_color col); + void BeginLineArray(int32 count); + void Blit(BRect src, BRect dest); + void DrawBitmap(ServerBitmap *bitmap); + void DrawLineArray(int32 count,BPoint *start, BPoint *end, rgb_color *color); + void DrawChar(char c, BPoint point); + void DrawString(char *string, int length, BPoint point); + void EndLineArray(void); + + void FillArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern); + void FillBezier(BPoint *points, uint8 *pattern); + void FillEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern); + void FillPolygon(int *x, int *y, int numpoints, bool is_closed); + void FillRect(BRect rect, uint8 *pattern); + void FillRect(BRect rect, rgb_color col); + void FillRegion(BRegion *region); + void FillRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern); + void FillShape(BShape *shape); + void FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern); + void FillTriangle(BPoint first, BPoint second, BPoint third, BRect rect, rgb_color col); + + void HideCursor(void); + bool IsCursorHidden(void); + void MoveCursorTo(float x, float y); + void MovePenTo(BPoint pt); + void ObscureCursor(void); + BPoint PenPosition(void); + float PenSize(void); + void SetCursor(ServerCursor *cursor); + drawing_mode GetDrawingMode(void); + void SetDrawingMode(drawing_mode mode); + void SetHighColor(uint8 r,uint8 g,uint8 b,uint8 a=255); + void SetHighColor(rgb_color col); + void SetLowColor(uint8 r,uint8 g,uint8 b,uint8 a=255); + void SetLowColor(rgb_color col); + void SetPenSize(float size); + void SetPixel(int x, int y, uint8 *pattern); + void ShowCursor(void); + + float StringWidth(const char *string, int32 length); + void StrokeArc(int centerx, int centery, int xradius, int yradius, float angle, float span, uint8 *pattern); + void StrokeBezier(BPoint *points, uint8 *pattern); + void StrokeEllipse(float centerx, float centery, float x_radius, float y_radius,uint8 *pattern); + void StrokeLine(BPoint point, uint8 *pattern); + void StrokeLine(BPoint pt1, BPoint pt2, rgb_color col); + void StrokePolygon(int *x, int *y, int numpoints, bool is_closed); + void StrokeRect(BRect rect,uint8 *pattern); + void StrokeRect(BRect rect,rgb_color col); + void StrokeRoundRect(BRect rect,float xradius, float yradius, uint8 *pattern); + void StrokeShape(BShape *shape); + void StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, uint8 *pattern); + void StrokeTriangle(BPoint first, BPoint second, BPoint third, BRect rect, rgb_color col); + VDWindow *screenwin; +protected: + int hide_cursor; + bool obscure_cursor; + BBitmap *framebuffer; + BView *drawview; + BRegion laregion; + + PortLink *serverlink; + + rgb_color highcolor,lowcolor; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/router/router.cpp b/src/servers/app/proto6/router/router.cpp new file mode 100644 index 0000000000..9752065dfd --- /dev/null +++ b/src/servers/app/proto6/router/router.cpp @@ -0,0 +1,146 @@ +#include "router.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include "PortLink.h" +#include "ServerProtocol.h" +//#define SERVER_PORT_NAME "OBappserver" +//#define SERVER_INPUT_PORT "OBinputport" + + +/******************************************************* +* +*******************************************************/ +BInputServerFilter* instantiate_input_filter(){ + return (new RouterInputFilter()); +} + +/******************************************************* +* +*******************************************************/ +RouterInputFilter::RouterInputFilter():BInputServerFilter(){ + port_id pid = find_port(SERVER_INPUT_PORT); + serverlink = new PortLink(pid); + +} + +/******************************************************* +* +*******************************************************/ +RouterInputFilter::~RouterInputFilter(){ +} + +/******************************************************* +* Everthing went just find .. right? +*******************************************************/ +status_t RouterInputFilter::InitCheck(){ + return B_OK; +} + + + +/******************************************************* +* +*******************************************************/ +filter_result RouterInputFilter::Filter(BMessage *message, BList *outList){ + if(serverlink == NULL){ + return B_DISPATCH_MESSAGE; + } + port_id pid = find_port(SERVER_INPUT_PORT); + if(pid < 0){ + return B_DISPATCH_MESSAGE; + } + serverlink->SetPort(pid); + + switch(message->what){ + case B_MOUSE_MOVED:{ + port_id pid = find_port(SERVER_INPUT_PORT); + if(pid==B_NAME_NOT_FOUND) + break; + serverlink->SetPort(pid); + BPoint p; + uint32 buttons = 0; + // get piont and button from msg + if(message->FindPoint("where",&p) != B_OK){ + + } + int64 time=(int64)real_time_clock(); + + serverlink->SetOpCode(B_MOUSE_MOVED); + serverlink->Attach(&time,sizeof(int64)); + serverlink->Attach(&p.x,sizeof(float)); + serverlink->Attach(&p.y,sizeof(float)); + serverlink->Attach(&buttons,sizeof(int32)); + + // prevent server crashes from hanging the Input Server + serverlink->Flush(50000); + }break; + case B_MOUSE_UP:{ + port_id pid = find_port(SERVER_INPUT_PORT); + if(pid==B_NAME_NOT_FOUND) + break; + serverlink->SetPort(pid); + BPoint p; + + uint32 mod=modifiers(); + // Eventually, we will also be sending a uint32 buttons. + + int64 time=(int64)real_time_clock(); + + message->FindPoint("where",&p); + + serverlink->SetOpCode(B_MOUSE_UP); + serverlink->Attach(&time, sizeof(int64)); + serverlink->Attach(&p.x,sizeof(float)); + serverlink->Attach(&p.y,sizeof(float)); + serverlink->Attach(&mod, sizeof(uint32)); + + // prevent server crashes from hanging the Input Server + serverlink->Flush(50000); + }break; + case B_MOUSE_DOWN:{ + port_id pid = find_port(SERVER_INPUT_PORT); + if(pid==B_NAME_NOT_FOUND) + break; + serverlink->SetPort(pid); + BPoint p; + + uint32 buttons, + mod=modifiers(); + int32 clicks; + message->FindInt32("clicks",&clicks); + message->FindPoint("where",&p); + message->FindInt32("buttons",(int32*)&buttons); + + int64 time=(int64)real_time_clock(); + + serverlink->SetOpCode(B_MOUSE_DOWN); + serverlink->Attach(&time, sizeof(int64)); + serverlink->Attach(&p.x,sizeof(float)); + serverlink->Attach(&p.y,sizeof(float)); + serverlink->Attach(&mod, sizeof(uint32)); + serverlink->Attach(&buttons, sizeof(uint32)); + serverlink->Attach(&clicks, sizeof(uint32)); + + // prevent server crashes from hanging the Input Server + serverlink->Flush(50000); + }break; + + // Should be some Mouse Down and Up code here .. + // Along with some Key Down and up codes .. + default: + break; + } + + //delete serverlink; + + // Let all msg flow normally to the + // Be app_server + return B_DISPATCH_MESSAGE; +} diff --git a/src/servers/app/proto6/router/router.h b/src/servers/app/proto6/router/router.h new file mode 100644 index 0000000000..5cfa514e66 --- /dev/null +++ b/src/servers/app/proto6/router/router.h @@ -0,0 +1,23 @@ +#ifndef _ROUTER_H +#define _ROUTER_H + +#include +#include +#include +#include + +class PortLink; + +// export this for the input_server +extern "C" _EXPORT BInputServerFilter* instantiate_input_filter(); + +class RouterInputFilter : public BInputServerFilter { + public: + RouterInputFilter(); + virtual ~RouterInputFilter(); + virtual status_t InitCheck(); + virtual filter_result Filter(BMessage *message, BList *outList); +private: + PortLink *serverlink; +}; +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/testobapp/DebugTools.cpp b/src/servers/app/proto6/testobapp/DebugTools.cpp new file mode 100644 index 0000000000..0a0c6aed1d --- /dev/null +++ b/src/servers/app/proto6/testobapp/DebugTools.cpp @@ -0,0 +1,219 @@ +#include +#include +#include +#include "DebugTools.h" + +void PrintStatusToStream(status_t value) +{ + // Function which simply translates a returned status code into a string + // and dumps it to stdout + BString outstr; + switch(value) + { + case B_OK: + outstr="B_OK "; + break; + case B_NAME_NOT_FOUND: + outstr="B_NAME_NOT_FOUND "; + break; + case B_BAD_VALUE: + outstr="B_BAD_VALUE "; + break; + case B_ERROR: + outstr="B_ERROR "; + break; + case B_TIMED_OUT: + outstr="B_TIMED_OUT "; + break; + case B_NO_MORE_PORTS: + outstr="B_NO_MORE_PORTS "; + break; + case B_WOULD_BLOCK: + outstr="B_WOULD_BLOCK "; + break; + case B_BAD_PORT_ID: + outstr="B_BAD_PORT_ID "; + break; + case B_BAD_TEAM_ID: + outstr="B_BAD_TEAM_ID "; + break; + default: + outstr="undefined status value in debugtools::PrintStatusToStream() "; + break; + } + cout << "Status: " << outstr.String() << endl << flush; + +} + +void PrintColorSpaceToStream(color_space value) +{ + // Dump a color space to cout + BString outstr; + switch(value) + { + case B_RGB32: + outstr="B_RGB32 "; + break; + case B_RGBA32: + outstr="B_RGBA32 "; + break; + case B_RGB32_BIG: + outstr="B_RGB32_BIG "; + break; + case B_RGBA32_BIG: + outstr=" "; + break; + case B_UVL32: + outstr="B_UVL32 "; + break; + case B_UVLA32: + outstr="B_UVLA32 "; + break; + case B_LAB32: + outstr="B_LAB32 "; + break; + case B_LABA32: + outstr="B_LABA32 "; + break; + case B_HSI32: + outstr="B_HSI32 "; + break; + case B_HSIA32: + outstr="B_HSIA32 "; + break; + case B_HSV32: + outstr="B_HSV32 "; + break; + case B_HSVA32: + outstr="B_HSVA32 "; + break; + case B_HLS32: + outstr="B_HLS32 "; + break; + case B_HLSA32: + outstr="B_HLSA32 "; + break; + case B_CMY32: + outstr="B_CMY32"; + break; + case B_CMYA32: + outstr="B_CMYA32 "; + break; + case B_CMYK32: + outstr="B_CMYK32 "; + break; + case B_RGB24_BIG: + outstr="B_RGB24_BIG "; + break; + case B_RGB24: + outstr="B_RGB24 "; + break; + case B_LAB24: + outstr="B_LAB24 "; + break; + case B_UVL24: + outstr="B_UVL24 "; + break; + case B_HSI24: + outstr="B_HSI24 "; + break; + case B_HSV24: + outstr="B_HSV24 "; + break; + case B_HLS24: + outstr="B_HLS24 "; + break; + case B_CMY24: + outstr="B_CMY24 "; + break; + case B_GRAY1: + outstr="B_GRAY1 "; + break; + case B_CMAP8: + outstr="B_CMAP8 "; + break; + case B_GRAY8: + outstr="B_GRAY8 "; + break; + case B_YUV411: + outstr="B_YUV411 "; + break; + case B_YUV420: + outstr="B_YUV420 "; + break; + case B_YCbCr422: + outstr="B_YCbCr422 "; + break; + case B_YCbCr411: + outstr="B_YCbCr411 "; + break; + case B_YCbCr420: + outstr="B_YCbCr420 "; + break; + case B_YUV422: + outstr="B_YUV422 "; + break; + case B_YUV9: + outstr="B_YUV9 "; + break; + case B_YUV12: + outstr="B_YUV12 "; + break; + case B_RGB15: + outstr="B_RGB15 "; + break; + case B_RGBA15: + outstr="B_RGBA15 "; + break; + case B_RGB16: + outstr="B_RGB16 "; + break; + case B_RGB16_BIG: + outstr="B_RGB16_BIG "; + break; + case B_RGB15_BIG: + outstr="B_RGB15_BIG "; + break; + case B_RGBA15_BIG: + outstr="B_RGBA15_BIG "; + break; + case B_YCbCr444: + outstr="B_YCbCr444 "; + break; + case B_YUV444: + outstr="B_YUV444 "; + break; + case B_NO_COLOR_SPACE: + outstr="B_NO_COLOR_SPACE "; + break; + default: + outstr="Undefined color space "; + break; + } + cout << "Color Space: " << outstr.String() << flush; +} + +void TranslateMessageCodeToStream(int32 code) +{ + // Used to translate BMessage message codes back to a character + // format + + cout << "'" + << (char)((code & 0xFF000000) >> 24) + << (char)((code & 0x00FF0000) >> 16) + << (char)((code & 0x0000FF00) >> 8) + << (char)((code & 0x000000FF)) << "' "; +} + +void PrintMessageCode(int32 code) +{ + // Used to translate BMessage message codes back to a character + // format + + printf("Message code %c%c%c%c\n", + (char)((code & 0xFF000000) >> 24), + (char)((code & 0x00FF0000) >> 16), + (char)((code & 0x0000FF00) >> 8), + (char)((code & 0x000000FF)) ); +} + diff --git a/src/servers/app/proto6/testobapp/DebugTools.h b/src/servers/app/proto6/testobapp/DebugTools.h new file mode 100644 index 0000000000..2f45b1ac6c --- /dev/null +++ b/src/servers/app/proto6/testobapp/DebugTools.h @@ -0,0 +1,12 @@ +#ifndef _DEBUGTOOLS_H_ +#define _DEBUGTOOLS_H_ + +#include +#include + +void PrintStatusToStream(status_t value); +void PrintColorSpaceToStream(color_space value); +void TranslateMessageCodeToStream(int32 code); +void PrintMessageCode(int32 code); + +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/testobapp/OBApplication.cpp b/src/servers/app/proto6/testobapp/OBApplication.cpp new file mode 100644 index 0000000000..2a214c10e3 --- /dev/null +++ b/src/servers/app/proto6/testobapp/OBApplication.cpp @@ -0,0 +1,382 @@ +/* + OBApplication.cpp: + Beginning framework for a *real* BApplication replacement for the prototypes + +*/ + +#include +#include // for the pattern struct and screen mode defs +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ServerProtocol.h" +#include "PortLink.h" +#include "OBApplication.h" +#include "OBWindow.h" +#include "DebugTools.h" + +OBApplication *obe_app; + +#define DEBUG_OBAPP + +OBApplication::OBApplication(const char *sig) : BApplication(sig) +{ + if(sig) + signature=new BString(sig); + else + signature=new BString("application/x-vnd.obos-OBApplication"); + +#ifdef DEBUG_OBAPP +printf("OBApplication(%s)\n",signature->String()); +#endif + + // A BApplication is locked on start, but because this is not a "real" + // one, we do not actually lock it. + + initcheckval=B_OK; + + // Receives messages from server and others + messageport=create_port(50,"msgport"); + if(messageport==B_BAD_VALUE || messageport==B_NO_MORE_PORTS) + { + printf("OBApplication: Couldn't create message port\n"); + initcheckval=B_ERROR; + } + + // Find the port for the app_server + serverport=find_port("OBappserver"); + if(serverport==B_NAME_NOT_FOUND) + { + printf("OBApplication: Couldn't find server port\n"); + serverlink=NULL; + write_port(messageport,B_QUIT_REQUESTED,NULL,0); + initcheckval=B_ERROR; + } + else + { + serverlink=new PortLink(serverport); +#ifdef DEBUG_OBAPP +printf("OBApplication(%s): App Server Port %ld\n",signature->String(),serverport); +#endif + + // Notify server of app's existence + int32 replycode; + status_t replystat; + ssize_t replysize; + int8 *replybuffer; + + serverlink->SetOpCode(CREATE_APP); + serverlink->Attach(&messageport,sizeof(port_id)); +// serverlink.Attach(PID); + serverlink->Attach((char*)signature->String(),strlen(signature->String())); + + // Send and wait for ServerApp port. Necessary here (as opposed to start + // of message loop) in case any windows are created in application constructor + replybuffer=serverlink->FlushWithReply(&replycode,&replystat,&replysize); + serverport=*((port_id*)replybuffer); + serverlink->SetPort(serverport); + delete replybuffer; +#ifdef DEBUG_OBAPP +printf("OBApplication(%s): ServerApp Port %ld\n",signature->String(),serverport); +#endif + ReadyToRun(); + } + + obe_app=this; + windowlist=new BList(0); +} + +OBApplication::~OBApplication(void) +{ +#ifdef DEBUG_OBAPP +printf("%s::~OBApplication()\n",signature->String()); +#endif + delete signature; + + if(serverlink) + delete serverlink; + +// OBWindow *win; +// for(int32 i=0; iCountItems(); i++) +// { +// win=(OBWindow*)windowlist->RemoveItem(i); +// if(win) +// win->Quit(); +// } + + delete windowlist; +} + +status_t OBApplication::InitCheck(void) const +{ + // Called to make sure everything in the constructor turned out ok. If it didn't, + // the application falls through and the process ends. + return initcheckval; +} + +void OBApplication::MainLoop(void) +{ +#ifdef DEBUG_OBAPP +printf("%s::MainLoop()\n",signature->String()); +#endif + + int32 msgcode; + uint8 *msgbuffer=NULL; + ssize_t buffersize,bytesread; + + for(;;) + { + // Modified this slightly so that OBApplications will eventually time out + // if the server crashes. Saves on a lot of Ctrl-Alt-Del's. :) CPU time is + // saved by setting the timeout to 3 seconds - more than enough time. + if(find_thread("OBAppServer")==B_NAME_NOT_FOUND) + { + printf("%s lost connection with server. Quitting.\n",signature->String()); + break; + } + + buffersize=port_buffer_size_etc(messageport,B_TIMEOUT,300000); + if(buffersize==B_TIMED_OUT) + continue; + + if(buffersize>0) + { + // buffers are flattened messages. Allocate necessary buffer and + // we'll cast it as a BMessage. + msgbuffer=new uint8[buffersize]; + bytesread=read_port(messageport,&msgcode,msgbuffer,buffersize); + } + else + bytesread=read_port(messageport,&msgcode,NULL,0); + + if (bytesread != B_BAD_PORT_ID && bytesread != B_TIMED_OUT && bytesread != B_WOULD_BLOCK) + { + switch(msgcode) + { + case B_QUIT_REQUESTED: + { + // Attached data: + // None +// printf("%s: Quit requested\n",signature); + serverlink->SetOpCode(msgcode); + serverlink->Flush(); + break; + } + case ADDWINDOW: + { + // This message is received by a window's constructor so that it + // can be added to the window list + + // Attached Data: + // 1) OBWindow *window + + // I hope this is the right syntax... + windowlist->AddItem(msgbuffer); +#ifdef DEBUG_OBAPP +printf("%s: Add Window @ %p\n",signature->String(),msgbuffer); +#endif + break; + } + case REMOVEWINDOW: + { + // This message is received by a window's constructor so that it + // can be added to the window list + + // Attached Data: + // 1) OBWindow *window + + // I hope this is the right syntax... + windowlist->RemoveItem(msgbuffer); +#ifdef DEBUG_OBAPP +printf("%s: Remove Window @ %p\n",signature->String(),msgbuffer); +#endif + break; + } + case B_MOUSE_MOVED: + case B_MOUSE_DOWN: + case B_MOUSE_UP: + DispatchMessage(msgcode, (int8*)msgbuffer); + break; + + // Later on, this will default to passing the message to + // DispatchMessage(BMessage*, BHandler*) + default: + printf("OBApplication received unexpected code %ld - ",msgcode); + PrintMessageCode(msgcode); + break; + } + + if(msgcode==B_QUIT_REQUESTED) + { + printf("Quitting %s\n",signature->String()); + break; + } + } + + if(buffersize>0) + delete msgbuffer; + } +} + +void OBApplication::DispatchMessage(BMessage *msg, BHandler *handler) +{ +#ifdef DEBUG_OBAPP +printf("%s::DispatchMessage(BMessage*,BHandler*)\n",signature->String()); +#endif + BApplication::DispatchMessage(msg,handler); +} + +void OBApplication::DispatchMessage(int32 code, int8 *buffer) +{ + // This function will be necessary to handle server messages. + switch(code) + { + case B_MOUSE_DOWN: + case B_MOUSE_UP: + case B_MOUSE_MOVED: + break; + default: + printf("OBApplication %s received unknown code %ld\n",signature->String(),code); + break; + } +} + +void OBApplication::MessageReceived(BMessage *msg) +{ +#ifdef DEBUG_OBAPP +printf("%s::MessageReceived()\n",signature->String()); +#endif +} + +void OBApplication::ShowCursor(void) +{ +#ifdef DEBUG_OBAPP +printf("%s::ShowCursor()\n",signature->String()); +#endif + serverlink->SetOpCode(SHOW_CURSOR); + serverlink->Flush(); +} + +void OBApplication::HideCursor(void) +{ +#ifdef DEBUG_OBAPP +printf("%s::HideCursor()\n",signature->String()); +#endif + serverlink->SetOpCode(HIDE_CURSOR); + serverlink->Flush(); +} + +void OBApplication::ObscureCursor(void) +{ +#ifdef DEBUG_OBAPP +printf("%s::ObscureCursor()\n",signature->String()); +#endif + serverlink->SetOpCode(OBSCURE_CURSOR); + serverlink->Flush(); +} + +bool OBApplication::IsCursorHidden(void) const +{ + return false; +} + +void OBApplication::SetCursor(const void *cursor) +{ +#ifdef DEBUG_OBAPP +printf("%s::SetCursor()\n",signature->String()); +#endif + // attach & send the 68-byte chunk + serverlink->SetOpCode(SET_CURSOR_DATA); + serverlink->Attach((void*)cursor, 68); + serverlink->Flush(); +} + +thread_id OBApplication::Run(void) +{ +#ifdef DEBUG_OBAPP +printf("%s::Run()\n",signature->String()); +#endif + if(initcheckval==B_OK) + MainLoop(); + + return 0; +} + +status_t OBApplication::Archive(BMessage *data, bool deep = true) const +{ + return B_ERROR; +} + +void OBApplication::Quit(void) +{ +#ifdef DEBUG_OBAPP +printf("%s::Quit()\n",signature->String()); +#endif + OBWindow *win; + while(windowlist->CountItems()>0) + { + win=(OBWindow*)windowlist->RemoveItem(0L); + if(win) + win->Quit(); + } + + BApplication::Quit(); +} + +bool OBApplication::QuitRequested(void) +{ +#ifdef DEBUG_OBAPP +printf("%s::QuitRequested()\n",signature->String()); +#endif + return true; +} + +void OBApplication::Pulse(void) +{ +} + +void OBApplication::ArgvReceived(int32 argc, char **argv) +{ +} + +void OBApplication::AppActivated(bool active) +{ +} + +void OBApplication::RefsReceived(BMessage *a_message) +{ +} + +void OBApplication::AboutRequested(void) +{ +} + +BHandler *OBApplication::ResolveSpecifier(BMessage *msg,int32 index,BMessage *specifier, + int32 form,const char *property) +{ + return NULL; +} + +status_t OBApplication::GetSupportedSuites(BMessage *data) +{ + return B_ERROR; +} + +status_t OBApplication::Perform(perform_code d, void *arg) +{ + return B_ERROR; +} + +void OBApplication::ReadyToRun(void) +{ +#ifdef DEBUG_OBAPP +printf("%s::ReadyToRun()\n",signature->String()); +#endif +} diff --git a/src/servers/app/proto6/testobapp/OBApplication.h b/src/servers/app/proto6/testobapp/OBApplication.h new file mode 100644 index 0000000000..14478ddfba --- /dev/null +++ b/src/servers/app/proto6/testobapp/OBApplication.h @@ -0,0 +1,71 @@ +#ifndef _OBOS_APPLICATION_H_ +#define _OBOS_APPLICATION_H_ + +#include +#include + +class PortLink; +class BList; +class OBWindow; + +class OBApplication : private BApplication +{ +public: + +OBApplication(const char *signature); +OBApplication(const char *signature, status_t *error); +virtual ~OBApplication(void); + +OBApplication(BMessage *data); +static BArchivable *Instantiate(BMessage *data); +virtual status_t Archive(BMessage *data, bool deep = true) const; + +status_t InitCheck() const; + +virtual thread_id Run(void); +virtual void Quit(void); +virtual bool QuitRequested(void); +virtual void Pulse(void); +virtual void ReadyToRun(void); +virtual void MessageReceived(BMessage *msg); +virtual void ArgvReceived(int32 argc, char **argv); +virtual void AppActivated(bool active); +virtual void RefsReceived(BMessage *a_message); +virtual void AboutRequested(void); + +virtual BHandler *ResolveSpecifier(BMessage *msg,int32 index, +BMessage *specifier,int32 form,const char *property); + +void ShowCursor(void); +void HideCursor(void); +void ObscureCursor(void); +bool IsCursorHidden(void) const; +void SetCursor(const void *cursor); +void SetCursor(const BCursor *cursor, bool sync=true); +int32 CountWindows(void) const; +BWindow *WindowAt(int32 index) const; +int32 CountLoopers(void) const; +BLooper *LooperAt(int32 index) const; +bool IsLaunching(void) const; +status_t GetAppInfo(app_info *info) const; +static BResources *AppResources(void); +virtual void DispatchMessage(BMessage *an_event,BHandler *handler); +void SetPulseRate(bigtime_t rate); +virtual status_t GetSupportedSuites(BMessage *data); +virtual status_t Perform(perform_code d, void *arg); + +protected: +friend OBWindow; + +void MainLoop(void); +void DispatchMessage(int32 code, int8 *buffer); + +port_id messageport, serverport; +BString *signature; +PortLink *serverlink; +BList *windowlist; +status_t initcheckval; +}; + +extern OBApplication *obe_app; +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/testobapp/OBTestApp.cpp b/src/servers/app/proto6/testobapp/OBTestApp.cpp new file mode 100644 index 0000000000..ebbe8c24bf --- /dev/null +++ b/src/servers/app/proto6/testobapp/OBTestApp.cpp @@ -0,0 +1,34 @@ +#include "OBApplication.h" +#include "OBWindow.h" +#include "OBView.h" + +class OBTestApp : public OBApplication +{ +public: + OBTestApp(void); + ~OBTestApp(void); +}; + +OBWindow *win; + +OBTestApp::OBTestApp(void) : OBApplication("application/OBTestApp") +{ + win=new OBWindow(BRect(100,100,200,200), "OBWindow1",B_BORDERED_WINDOW_LOOK, + B_NORMAL_WINDOW_FEEL,0); + win->Show(); + + win=new OBWindow(BRect(200,200,300,300), "OBWindow2",B_DOCUMENT_WINDOW_LOOK, + B_NORMAL_WINDOW_FEEL,0); + win->Show(); +} + +OBTestApp::~OBTestApp(void) +{ +} + +int main(void) +{ + OBTestApp *app=new OBTestApp(); + app->Run(); + delete app; +} diff --git a/src/servers/app/proto6/testobapp/OBView.cpp b/src/servers/app/proto6/testobapp/OBView.cpp new file mode 100644 index 0000000000..1132f77db5 --- /dev/null +++ b/src/servers/app/proto6/testobapp/OBView.cpp @@ -0,0 +1,872 @@ +#include +#include +#include "PortLink.h" +#include "ServerProtocol.h" +#include "OBView.h" +#include "OBWindow.h" + +//#define DEBUG_VIEW + +#ifndef SET_RGB_COLOR + #define SET_RGB_COLOR(a,b,c,d,e) a.red=b; a.green=c; a.blue=d; a.alpha=e; +#endif + +OBView::OBView(BRect frame,const char *name,uint32 resizeMask,uint32 flags) + : BHandler(name) +{ + viewflags=flags; + resizeflags=resizeMask; + origin_h=0.0; + origin_v=0.0; + + owner=NULL; + parent=NULL; + uppersibling=NULL; + lowersibling=NULL; + topchild=NULL; + bottomchild=NULL; + hidelevel=0; + + // This will be changed when added to a BWindow as the top view + topview=false; + + SET_RGB_COLOR(highcol,0,0,0,255); + SET_RGB_COLOR(lowcol,255,255,255,255); + SET_RGB_COLOR(viewcol,255,255,255,255); + + // We need to align to the nearest pixel, rounded down + // There's probably a better way to do this, but it'll work for now... + vframe.left=(int32)frame.left; + vframe.top=(int32)frame.top; + vframe.right=(int32)frame.right; + vframe.bottom=(int32)frame.bottom; +} + +OBView::~OBView() +{ + // Be Book says it's an error to delete while attached to a window. + // We'll just prevent that problem... + if(owner) + { + // No, this isn't an error to utilize parent and not owner. We + // aren't actually attached to the window class itself. We're + // attached to a view which is a member of the window. + parent->RemoveChild(this); + } + + + OBView *v; + for(v=topchild; v!=NULL; v=v->lowersibling) + delete v; +} + +void OBView::AttachedToWindow() +{ + // Hook function +} + +void OBView::AllAttached() +{ + // Hook function +} + +void OBView::DetachedFromWindow() +{ + // Hook function +} + +void OBView::AllDetached() +{ + // Hook function +} + +void OBView::MessageReceived(BMessage *msg) +{ + // Adds scripting support to the BHandler version. This is + // only a skeleton implementation, so it has been skipped + BHandler::MessageReceived(msg); +} + +void OBView::AddChild(OBView *child, OBView *before = NULL) +{ + if(!child) + return; + if(child->parent || child->owner) + { + printf("%s::AddChild(): child already has a parent\n",Name()); + return; + } + if(child->parent==this) + { + printf("%s::AddChild(): child already belongs to view\n",Name()); + return; + } + + // Adds a layer to the top of the layer's children +#ifdef DEBUG_VIEW + printf("%s::AddChild(%s)\n", Name(), child->Name()); +#endif + + child->parent=this; + child->owner=owner; + + // View specified. Add new child above the specified view + if(before) + { + if(before->parent==this) + { + child->lowersibling=before; + child->uppersibling=before->uppersibling; + before->uppersibling->lowersibling=child; + before->uppersibling=child; + + // If we're attached to a window, notify all child views of + // their attachment + if(owner) + { + CallAttached(child); + child->AllAttached(); + } + + } + else + { + printf("%s::AddChild(): Can't add %s before %s - different parents\n", + Name(), child->Name(), before->Name()); + } + return; + } + + // If we haven't specified, child is added to bottom of list + if(bottomchild!=NULL) + { + child->uppersibling=bottomchild; + bottomchild->lowersibling=child; + } + bottomchild=child; + +} + +bool OBView::RemoveChild(OBView *child) +{ + if(!child) + return false; + + if(child->parent!=this) + { + printf("%s::RemoveChild(): %s not child of this view\n",Name(),child->Name()); + return false; + } + + // Adds a layer to the top of the layer's children +#ifdef DEBUG_VIEW + printf("%s::RemoveChild(%s)\n", Name(), child->Name()); +#endif + + if(owner) + { + CallDetached(child); + + // We only need to tell the server to prune the layer tree + // at the child's level + PortLink *link=new PortLink(owner->outport); + link->SetOpCode(LAYER_DELETE); + link->Attach(child->id); + link->Flush(); + delete link; + } + + // Note that we do the pointer reassignments last because the other + // function calls made in RemoveChild() depend on these pointers + if(topchild==child) + topchild=child->lowersibling; + if(bottomchild==child) + bottomchild=child->lowersibling; + + if(child->uppersibling!=NULL) + child->uppersibling->lowersibling=child->lowersibling; + if(child->lowersibling!=NULL) + child->lowersibling->uppersibling=child->uppersibling; + + child->parent=NULL; + child->owner=NULL; + child->lowersibling=NULL; + child->uppersibling=NULL; + return true; +} + +bool OBView::RemoveSelf() +{ + return false; +} + +int32 OBView::CountChildren() const +{ + OBView *v=topchild; + int32 children=0; + + while(v!=NULL) + { + v=v->lowersibling; + children++; + } + + return children; +} + +OBView *OBView::ChildAt(int32 index) const +{ + // We're using a tree, so traverse the tree + OBView *v=topchild; + + for(int32 i=0;ilowersibling; + } + + return v; +} + +OBView *OBView::NextSibling() const +{ + return lowersibling; +} + +OBView *OBView::PreviousSibling() const +{ + return uppersibling; +} + +OBWindow *OBView::Window() const +{ + return owner; +} + +void OBView::Draw(BRect updateRect) +{ +} + +void OBView::MouseDown(BPoint where) +{ + // Hook function +} + +void OBView::MouseUp(BPoint where) +{ + // Hook function +} + +void OBView::MouseMoved(BPoint where,uint32 code,const BMessage *a_message) +{ + // Hook function +} + +void OBView::WindowActivated(bool state) +{ + // Hook function +} + +void OBView::KeyDown(const char *bytes, int32 numBytes) +{ + // Hook function +} + +void OBView::KeyUp(const char *bytes, int32 numBytes) +{ + // Hook function +} + +void OBView::Pulse() +{ + // Hook function +} + +void OBView::FrameMoved(BPoint new_position) +{ + // Hook function +} + +void OBView::FrameResized(float new_width, float new_height) +{ + // Hook function +} + +void OBView::TargetedByScrollView(BScrollView *scroll_view) +{ + // Hook function +} + +void OBView::BeginRectTracking(BRect startRect,uint32 style = B_TRACK_WHOLE_RECT) +{ + if(!owner) + { + printf("BeginRectTracking(): view must be attached to a window\n"); + return; + } + owner->serverlink->SetOpCode(BEGIN_RECT_TRACKING); + owner->serverlink->Attach(&startRect, sizeof(BRect)); + owner->serverlink->Attach(&style, sizeof(uint32)); + owner->serverlink->Flush(); +} + +void OBView::EndRectTracking(void) +{ + if(!owner) + { + printf("EndRectTracking(): view must be attached to a window\n"); + return; + } + owner->serverlink->SetOpCode(END_RECT_TRACKING); + owner->serverlink->Flush(); +} + +void OBView::GetMouse(BPoint *location, uint32 *buttons, + bool checkMessageQueue=true) +{ +} + +OBView *OBView::FindView(const char *name) +{ + OBView *v; + v=FindViewInChildren(name); + + return v; +} + +OBView *OBView::Parent() const +{ + return parent; +} + +BRect OBView::Bounds() const +{ + BRect rframe=vframe; + rframe.OffsetTo(0,0); + return rframe; +} + +BRect OBView::Frame() const +{ + return vframe; +} + +void OBView::ConvertToScreen(BPoint* pt) const +{ +} + +BPoint OBView::ConvertToScreen(BPoint pt) const +{ + return BPoint(-1,-1); +} + +void OBView::ConvertFromScreen(BPoint* pt) const +{ +} + +BPoint OBView::ConvertFromScreen(BPoint pt) const +{ + return BPoint(-1,-1); +} + +void OBView::ConvertToScreen(BRect *r) const +{ +} + +BRect OBView::ConvertToScreen(BRect r) const +{ + return BRect(0,0,0,0); +} + +void OBView::ConvertFromScreen(BRect *r) const +{ +} + +BRect OBView::ConvertFromScreen(BRect r) const +{ + return BRect(0,0,0,0); +} + +void OBView::ConvertToParent(BPoint *pt) const +{ +} + +BPoint OBView::ConvertToParent(BPoint pt) const +{ + return BPoint(-1,-1); +} + +void OBView::ConvertFromParent(BPoint *pt) const +{ +} + +BPoint OBView::ConvertFromParent(BPoint pt) const +{ + return BPoint(-1,-1); +} + +void OBView::ConvertToParent(BRect *r) const +{ +} + +BRect OBView::ConvertToParent(BRect r) const +{ + return BRect(0,0,0,0); +} + +void OBView::ConvertFromParent(BRect *r) const +{ +} + +BRect OBView::ConvertFromParent(BRect r) const +{ + return BRect(0,0,0,0); +} + +BPoint OBView::LeftTop() const +{ + return BPoint(-1,-1); +} + +void OBView::GetClippingRegion(BRegion *region) const +{ +} + +void OBView::ConstrainClippingRegion(BRegion *region) +{ +} + +void OBView::SetDrawingMode(drawing_mode mode) +{ +} + +drawing_mode OBView::DrawingMode() const +{ + return B_OP_COPY; +} + +void OBView::SetBlendingMode(source_alpha srcAlpha, alpha_function alphaFunc) +{ +} + +void OBView::GetBlendingMode(source_alpha *srcAlpha, alpha_function *alphaFunc) const +{ +} + +void OBView::SetPenSize(float size) +{ +} + +float OBView::PenSize() const +{ + return 0.0; +} + +void OBView::SetViewColor(rgb_color c) +{ + SET_RGB_COLOR(viewcol,c.red,c.green,c.blue,c.alpha); + owner->drawmsglink->Attach((int32)GFX_SET_VIEW_COLOR); + owner->drawmsglink->Attach((int8)c.red); + owner->drawmsglink->Attach((int8)c.green); + owner->drawmsglink->Attach((int8)c.blue); + owner->drawmsglink->Attach((int8)c.alpha); +} + +void OBView::SetViewColor(uchar r, uchar g, uchar b, uchar a=255) +{ + SET_RGB_COLOR(viewcol,r,g,b,a); + owner->drawmsglink->Attach((int32)GFX_SET_VIEW_COLOR); + owner->drawmsglink->Attach((int8)r); + owner->drawmsglink->Attach((int8)g); + owner->drawmsglink->Attach((int8)b); + owner->drawmsglink->Attach((int8)a); +} + +rgb_color OBView::ViewColor() const +{ + return viewcol; +} + +void OBView::SetHighColor(rgb_color c) +{ + SET_RGB_COLOR(highcol,c.red,c.green,c.blue,c.alpha); + owner->drawmsglink->Attach((int32)GFX_SET_HIGH_COLOR); + owner->drawmsglink->Attach((int8)c.red); + owner->drawmsglink->Attach((int8)c.green); + owner->drawmsglink->Attach((int8)c.blue); + owner->drawmsglink->Attach((int8)c.alpha); +} + +void OBView::SetHighColor(uchar r, uchar g, uchar b, uchar a=255) +{ + SET_RGB_COLOR(highcol,r,g,b,a); + owner->drawmsglink->Attach((int32)GFX_SET_HIGH_COLOR); + owner->drawmsglink->Attach((int8)r); + owner->drawmsglink->Attach((int8)g); + owner->drawmsglink->Attach((int8)b); + owner->drawmsglink->Attach((int8)a); +} + +rgb_color OBView::HighColor() const +{ + return highcol; +} + +void OBView::SetLowColor(rgb_color c) +{ + SET_RGB_COLOR(lowcol,c.red,c.green,c.blue,c.alpha); + owner->drawmsglink->Attach((int32)GFX_SET_LOW_COLOR); + owner->drawmsglink->Attach((int8)c.red); + owner->drawmsglink->Attach((int8)c.green); + owner->drawmsglink->Attach((int8)c.blue); + owner->drawmsglink->Attach((int8)c.alpha); +} + +void OBView::SetLowColor(uchar r, uchar g, uchar b, uchar a=255) +{ + SET_RGB_COLOR(lowcol,r,g,b,a); + owner->drawmsglink->Attach((int32)GFX_SET_LOW_COLOR); + owner->drawmsglink->Attach((int8)r); + owner->drawmsglink->Attach((int8)g); + owner->drawmsglink->Attach((int8)b); + owner->drawmsglink->Attach((int8)a); +} + +rgb_color OBView::LowColor() const +{ + return lowcol; +} + +void OBView::Invalidate(BRect invalRect) +{ + if(!owner) + { + printf("Invalidate(): view must be attached to a window\n"); + return; + } + owner->drawmsglink->Attach(invalRect); +} + +void OBView::Invalidate(const BRegion *invalRegion) +{ + // undocumented function +} + +void OBView::Invalidate() +{ + if(!owner) + { + printf("Invalidate(): view must be attached to a window\n"); + return; + } + owner->drawmsglink->Attach(Bounds()); +} + +void OBView::SetFlags(uint32 flags) +{ +} + +uint32 OBView::Flags() const +{ + return viewflags; +} + +void OBView::SetResizingMode(uint32 mode) +{ +} + +uint32 OBView::ResizingMode() const +{ + return resizeflags; +} + +void OBView::MoveBy(float dh, float dv) +{ +} + +void OBView::MoveTo(BPoint where) +{ +} + +void OBView::MoveTo(float x, float y) +{ +} + +void OBView::ResizeBy(float dh, float dv) +{ +} + +void OBView::ResizeTo(float width, float height) +{ +} + +void OBView::MakeFocus(bool focusState = true) +{ +} + +bool OBView::IsFocus() const +{ + return has_focus; +} + +void OBView::Show() +{ + hidelevel--; + + for(OBView *v=topchild; v!=NULL; v=v->lowersibling ) + v->Show(); +} + +void OBView::Hide() +{ + hidelevel++; + + for(OBView *v=topchild; v!=NULL; v=v->lowersibling ) + v->Show(); +} + +bool OBView::IsHidden() const +{ + return (hidelevel>0)?true:false; +} + +bool OBView::IsHidden(const OBView* looking_from) const +{ + // undocumented function + return false; +} + +void OBView::Flush() const +{ + // When attachment count inclusion is implemented, it needs to go + // in this function + + owner->drawmsglink->SetOpCode(GFX_FLUSH); + owner->drawmsglink->Flush(); +} + +void OBView::Sync() const +{ + // When attachment count inclusion is implemented, it needs to go + // in this function + + int32 code; + status_t status; + ssize_t buffersize; + + owner->drawmsglink->SetOpCode(GFX_SYNC); + + // Reply received: + + // Code: SYNC + // Attached data: none + // Buffersize: 0 + owner->drawmsglink->FlushWithReply(&code,&status,&buffersize); +} + +void OBView::StrokeRect(BRect r, pattern p=B_SOLID_HIGH) +{ + if(!owner) + { + printf("StrokeRect(): view must be attached to a window\n"); + return; + } + + owner->drawmsglink->Attach((int32)GFX_STROKE_RECT); + owner->drawmsglink->Attach(r); + owner->drawmsglink->Attach(&p, sizeof(pattern)); +} + +void OBView::FillRect(BRect r, pattern p=B_SOLID_HIGH) +{ + if(!owner) + { + printf("FillRect(): view must be attached to a window\n"); + return; + } + + owner->drawmsglink->Attach((int32)GFX_FILL_RECT); + owner->drawmsglink->Attach(r); + owner->drawmsglink->Attach(&p, sizeof(pattern)); +} + +void OBView::MovePenTo(BPoint pt) +{ + if(!owner) + { + printf("MovePenTo(): view must be attached to a window\n"); + return; + } + owner->drawmsglink->Attach((int32)GFX_MOVEPENTO); + owner->drawmsglink->Attach(pt); +} + +void OBView::MovePenTo(float x, float y) +{ + if(!owner) + { + printf("MovePenTo(): view must be attached to a window\n"); + return; + } + owner->drawmsglink->Attach((int32)GFX_MOVEPENTO); + owner->drawmsglink->Attach(BPoint(x,y)); +} + +void OBView::MovePenBy(float x, float y) +{ + if(!owner) + { + printf("MovePenBy(): view must be attached to a window\n"); + return; + } + owner->drawmsglink->Attach((int32)GFX_MOVEPENBY); + owner->drawmsglink->Attach(x); + owner->drawmsglink->Attach(y); +} + +BPoint OBView::PenLocation() const +{ + return BPoint(0,0); +} + +void OBView::StrokeLine(BPoint toPt,pattern p=B_SOLID_HIGH) +{ + if(!owner) + { + printf("StrokeLine(): view must be attached to a window\n"); + return; + } + owner->drawmsglink->Attach((int32)GFX_STROKE_LINE); + owner->drawmsglink->Attach(toPt); + owner->drawmsglink->Attach((pattern *)&p, sizeof(pattern)); +} + +void OBView::StrokeLine(BPoint pt0,BPoint pt1,pattern p=B_SOLID_HIGH) +{ + if(!owner) + { + printf("StrokeLine(): view must be attached to a window\n"); + return; + } + owner->drawmsglink->Attach((int32)GFX_MOVEPENTO); + owner->drawmsglink->Attach(pt0); + + owner->drawmsglink->Attach((int32)GFX_STROKE_LINE); + owner->drawmsglink->Attach(pt1); + owner->drawmsglink->Attach((pattern *)&p, sizeof(pattern)); +} + +// Protected members + +int32 OBView::GetServerToken(void) +{ + // Function which asks the app_server for an ID value + // NOTE that it requires an owner + + if(!owner) + { + printf("GetServerToken(): view must be attached to a window\n"); + return -1; + } + + int32 code; + status_t status; + ssize_t buffersize; + int32 *buffer; + + owner->serverlink->SetOpCode(VIEW_GET_TOKEN); + + // Reply received: + + // Code: GET_VIEW_TOKEN + // Attached data: + // 1) int32 view ID + buffer=(int32*)owner->drawmsglink->FlushWithReply(&code,&status,&buffersize); + id=*buffer; + + // necessary because each reply allocates memory from the heap for + // the returned buffer + delete buffer; + + return id; +} + +void OBView::CallAttached(OBView *view) +{ + // Recursively calls AttachedToWindow() for all children of the view + AddedToWindow(); + AttachedToWindow(); + + for(OBView *v=topchild; v!=NULL; v=v->lowersibling) + { + if(v->topchild) + CallAttached(v->topchild); + } +} + +void OBView::CallDetached(OBView *view) +{ + // Recursively calls DetachedFromWindow() for all children of the view + DetachedFromWindow(); + + for(OBView *v=topchild; v!=NULL; v=v->lowersibling) + { + if(v->topchild) + CallDetached(v->topchild); + } +} + +void OBView::AddedToWindow(void) +{ + // Hook function called during AddChild to take care of setup in server + // of adding a bunch of views at once, not just one + + // Theoretically, shouldn't be needed, but this is here in case I do + // something really stupid. ;) + if(!owner) + return; + + // If we're finally attached to a window, then the child needs to become + // known to the server + + // Create View message. Layers are app_server's view counterparts + + // Attach Data: + // 1) (int32) id of the parent view + // 2) (int32) id of the child view + // 3) (BRect) frame in parent's coordinates + // 4) (int32) resize flags + // 5) (int32) view flags + // 6) (uint16) view's hide level + id=GetServerToken(); + + PortLink *link=new PortLink(owner->outport); + link->SetOpCode(LAYER_CREATE); + link->Attach(parent->id); + link->Attach(id); + link->Attach(vframe); + link->Attach((int32)resizeflags); + link->Attach((int32)viewflags); + link->Attach(&hidelevel,sizeof(uint16)); + link->Flush(); + delete link; +} + +OBView *OBView::FindViewInChildren(const char *name) +{ + // Looks in all children of a view and returns the first view + // with a matching name. + + // Process: + // 1) Search this view's children starting with topchild + // 2) If not found, cycle through them again, this second time + // recursively searching each child. + // 3) If the view is found in the first child search, assign the ** + // and return the *. + // 4) If the view is found in the second child search, break out of the + // search loop by assigning and returning the * + // 5) If we complete the loop, it means that the view was not found. + // We should, thus, return NULL + return NULL; +} diff --git a/src/servers/app/proto6/testobapp/OBView.h b/src/servers/app/proto6/testobapp/OBView.h new file mode 100644 index 0000000000..86a2448d8c --- /dev/null +++ b/src/servers/app/proto6/testobapp/OBView.h @@ -0,0 +1,168 @@ +#ifndef _OBVIEW_H_ +#define _OBVIEW_H_ + +#include +#include +#include +#include +#include +#include + +class BMessage; +class BString; +class BWindow; +class OBWindow; + +class OBView : public BHandler +{ +public: +OBView( BRect frame,const char *name,uint32 resizeMask,uint32 flags); +virtual ~OBView(); + +virtual void AttachedToWindow(); +virtual void AllAttached(); +virtual void DetachedFromWindow(); +virtual void AllDetached(); + +virtual void MessageReceived(BMessage *msg); + +void AddChild(OBView *child, OBView *before = NULL); +bool RemoveChild(OBView *child); +bool RemoveSelf(); +int32 CountChildren() const; +OBView *ChildAt(int32 index) const; +OBView *NextSibling() const; +OBView *PreviousSibling() const; + +OBWindow *Window() const; + +virtual void Draw(BRect updateRect); +virtual void MouseDown(BPoint where); +virtual void MouseUp(BPoint where); +virtual void MouseMoved( BPoint where,uint32 code,const BMessage *a_message); +virtual void WindowActivated(bool state); +virtual void KeyDown(const char *bytes, int32 numBytes); +virtual void KeyUp(const char *bytes, int32 numBytes); +virtual void Pulse(); +virtual void FrameMoved(BPoint new_position); +virtual void FrameResized(float new_width, float new_height); + +virtual void TargetedByScrollView(BScrollView *scroll_view); +void BeginRectTracking( BRect startRect,uint32 style = B_TRACK_WHOLE_RECT); +void EndRectTracking(); + +void GetMouse(BPoint *location,uint32 *buttons,bool checkMessageQueue=true); + +OBView *FindView(const char *name); +OBView *Parent() const; +BRect Bounds() const; +BRect Frame() const; +void ConvertToScreen(BPoint* pt) const; +BPoint ConvertToScreen(BPoint pt) const; +void ConvertFromScreen(BPoint* pt) const; +BPoint ConvertFromScreen(BPoint pt) const; +void ConvertToScreen(BRect *r) const; +BRect ConvertToScreen(BRect r) const; +void ConvertFromScreen(BRect *r) const; +BRect ConvertFromScreen(BRect r) const; +void ConvertToParent(BPoint *pt) const; +BPoint ConvertToParent(BPoint pt) const; +void ConvertFromParent(BPoint *pt) const; +BPoint ConvertFromParent(BPoint pt) const; +void ConvertToParent(BRect *r) const; +BRect ConvertToParent(BRect r) const; +void ConvertFromParent(BRect *r) const; +BRect ConvertFromParent(BRect r) const; +BPoint LeftTop() const; + +void GetClippingRegion(BRegion *region) const; +virtual void ConstrainClippingRegion(BRegion *region); + +virtual void SetDrawingMode(drawing_mode mode); +drawing_mode DrawingMode() const; + +void SetBlendingMode(source_alpha srcAlpha, alpha_function alphaFunc); +void GetBlendingMode(source_alpha *srcAlpha, alpha_function *alphaFunc) const; + +virtual void SetPenSize(float size); +float PenSize() const; + +virtual void SetViewColor(rgb_color c); +void SetViewColor(uchar r, uchar g, uchar b, uchar a = 255); +rgb_color ViewColor() const; + +virtual void SetHighColor(rgb_color a_color); +void SetHighColor(uchar r, uchar g, uchar b, uchar a = 255); +rgb_color HighColor() const; + +virtual void SetLowColor(rgb_color a_color); +void SetLowColor(uchar r, uchar g, uchar b, uchar a = 255); +rgb_color LowColor() const; + +void Invalidate(BRect invalRect); +void Invalidate(const BRegion *invalRegion); +void Invalidate(); + +virtual void SetFlags(uint32 flags); +uint32 Flags() const; +virtual void SetResizingMode(uint32 mode); +uint32 ResizingMode() const; +void MoveBy(float dh, float dv); +void MoveTo(BPoint where); +void MoveTo(float x, float y); +void ResizeBy(float dh, float dv); +void ResizeTo(float width, float height); +virtual void MakeFocus(bool focusState = true); +bool IsFocus() const; + +virtual void Show(); +virtual void Hide(); +bool IsHidden() const; +bool IsHidden(const OBView* looking_from) const; + +void Flush() const; +void Sync() const; + +void StrokeRect(BRect r, pattern p = B_SOLID_HIGH); +void FillRect(BRect r, pattern p = B_SOLID_HIGH); +void MovePenTo(BPoint pt); +void MovePenTo(float x, float y); +void MovePenBy(float x, float y); +BPoint PenLocation() const; +void StrokeLine( BPoint toPt,pattern p = B_SOLID_HIGH); +void StrokeLine( BPoint pt0,BPoint pt1,pattern p = B_SOLID_HIGH); + +protected: + friend OBWindow; + +int32 GetServerToken(void); +void CallAttached(OBView *view); +void CallDetached(OBView *view); +OBView *FindViewInChildren(const char *name); +void AddedToWindow(void); + +int32 id; +uint32 viewflags, resizeflags; +float origin_h; +float origin_v; +OBWindow* owner; + +OBView* parent; +OBView* uppersibling; +OBView* lowersibling; +OBView* topchild; +OBView* bottomchild; + +uint16 hidelevel; +bool topview; +bool has_focus; + +BRect vframe; +BRegion *clipregion; + +rgb_color highcol; +rgb_color lowcol; +rgb_color viewcol; +}; + +#endif diff --git a/src/servers/app/proto6/testobapp/OBWindow.cpp b/src/servers/app/proto6/testobapp/OBWindow.cpp new file mode 100644 index 0000000000..0409391af1 --- /dev/null +++ b/src/servers/app/proto6/testobapp/OBWindow.cpp @@ -0,0 +1,523 @@ +#include +#include +#include +#include "OBApplication.h" +#include "OBView.h" +#include "OBWindow.h" +#include "ServerProtocol.h" +#include "PortLink.h" + +#define DEBUG_OBWINDOW + +OBWindow::OBWindow(BRect frame,const char *title, window_type type, +uint32 flags,uint32 workspace = B_CURRENT_WORKSPACE) +{ +} + +OBWindow::OBWindow(BRect frame,const char *title, window_look look,window_feel feel, +uint32 flags,uint32 workspace = B_CURRENT_WORKSPACE) +{ +#ifdef DEBUG_OBWINDOW +printf("OBWindow(%s)\n",title); +#endif + Lock(); + + // Window starts hidden by default + hidelevel=1; + + wframe=frame; + wlook=look; + wfeel=feel; + wflags=flags; + wkspace=workspace; + + wtitle=new BString(title); + + // Receives messages from server and others + inport=create_port(50,"msgport"); + if(inport==B_BAD_VALUE || inport==B_NO_MORE_PORTS) + printf("OBWindow: Couldn't create message port\n"); + + // Notify app that we exist + OBWindow *win=this; + PortLink *link=new PortLink(obe_app->messageport); + link->SetOpCode(ADDWINDOW); + link->Attach(&win,sizeof(OBWindow*)); + link->Flush(); + delete link; + + // we set this flag because the window starts locked. When Show() is + // called it will unlock the looper and show the window + startlocked=true; + + // We create our serverlink utilizing our application's server port + // because the server's ServerApp will handle window creation + serverlink=new PortLink(obe_app->serverport); + + // make sure that the server port is valid. It will == B_NAME_NOT_FOUND if the + // OBApplication couldn't find the server + + if(obe_app->serverport!=B_NAME_NOT_FOUND) + { + // Notify server of window's existence + serverlink->SetOpCode(CREATE_WINDOW); + serverlink->Attach(wframe); + serverlink->Attach((int32)WindowLookToInteger(wlook)); + serverlink->Attach((int32)WindowFeelToInteger(wfeel)); + serverlink->Attach((int32)wflags); + serverlink->Attach(&inport,sizeof(port_id)); + serverlink->Attach((int32)wkspace); + serverlink->Attach((char*)wtitle->String(),wtitle->Length()); + + // Send and wait for ServerWindow port. Necessary here so we can respond to + // messages as soon as Show() is called. + + int32 replycode; + status_t replystat; + ssize_t replysize; + int8 *replybuffer; + + replybuffer=serverlink->FlushWithReply(&replycode,&replystat,&replysize); + outport=*((port_id*)replybuffer); + serverlink->SetPort(outport); + delete replybuffer; + +#ifdef DEBUG_OBWINDOW +printf("OBWindow(%s): ServerWindow Port %ld\n",wtitle->String(),outport); +#endif + + // Create and attach the top view + top_view=new OBView(wframe.OffsetToCopy(0,0),"top_view",B_FOLLOW_ALL, B_WILL_DRAW); + top_view->owner=this; + top_view->topview=true; + } + else + PostMessage(B_QUIT_REQUESTED); +} + +OBWindow::~OBWindow() +{ +#ifdef DEBUG_OBWINDOW +printf("~OBWindow(%s)\n",wtitle->String()); +#endif + // delete all children. How? OBView recursively deletes its children + delete top_view; + + delete wtitle; + delete serverlink; + delete drawmsglink; + +} + +void OBWindow::Quit() +{ +#ifdef DEBUG_OBWINDOW +printf("%s::Quit()\n",wtitle->String()); +#endif + // I hope this works. If it doesn't, we'll need to do a synchronous msg + OBWindow *win=this; + PortLink *link=new PortLink(obe_app->messageport); + link->SetOpCode(REMOVEWINDOW); + link->Attach(&win,sizeof(OBWindow *)); + link->Flush(); + delete link; + + // Server will need to be notified of window destruction + serverlink->SetOpCode(DELETE_WINDOW); + serverlink->Attach(&ID,sizeof(int32)); + serverlink->Flush(); + + // Quit our looper and delete our self :) + Quit(); +} + +void OBWindow::Close() +{ + Quit(); +} + +void OBWindow::AddChild(OBView *child, OBView *before = NULL) +{ +#ifdef DEBUG_OBWINDOW +printf("%s::AddChild()\n",wtitle->String()); +#endif + top_view->AddChild(child,before); +} + +bool OBWindow::RemoveChild(OBView *child) +{ +#ifdef DEBUG_OBWINDOW +printf("%s::RemoveChild()\n",wtitle->String()); +#endif + return top_view->RemoveChild(child); +} + +int32 OBWindow::CountChildren() const +{ + return top_view->CountChildren(); +} + +OBView *OBWindow::ChildAt(int32 index) const +{ + return top_view->ChildAt(index); +} + +void OBWindow::DispatchMessage(BMessage *message, BHandler *handler) +{ +} + +void OBWindow::MessageReceived(BMessage *message) +{ + // Not sure right now what needs to be handled. + switch(message->what) + { + default: + BLooper::MessageReceived(message); + } +} + +void OBWindow::FrameMoved(BPoint new_position) +{ +} + +void OBWindow::WorkspacesChanged(uint32 old_ws, uint32 new_ws) +{ +} + +void OBWindow::WorkspaceActivated(int32 ws, bool state) +{ +} + +void OBWindow::FrameResized(float new_width, float new_height) +{ +} + +void OBWindow::Minimize(bool minimize) +{ +} + +void OBWindow::Zoom(BPoint rec_position,float rec_width,float rec_height) +{ +} + +void OBWindow::Zoom() +{ +} + +void OBWindow::ScreenChanged(BRect screen_size, color_space depth) +{ +} + +bool OBWindow::NeedsUpdate() const +{ + return false; +} + +void OBWindow::UpdateIfNeeded() +{ +} + +OBView *OBWindow::FindView(const char *view_name) const +{ + return top_view->FindView(view_name); +} + +OBView *OBWindow::FindView(BPoint) const +{ + return NULL; +} + +OBView *OBWindow::CurrentFocus() const +{ + return focusedview; +} + +void OBWindow::Activate(bool=true) +{ +} + +void OBWindow::WindowActivated(bool state) +{ +} + +void OBWindow::ConvertToScreen(BPoint *pt) const +{ +} + +BPoint OBWindow::ConvertToScreen(BPoint pt) const +{ + return BPoint(-1,-1); +} + +void OBWindow::ConvertFromScreen(BPoint *pt) const +{ +} + +BPoint OBWindow::ConvertFromScreen(BPoint pt) const +{ + return BPoint(-1,-1); +} + +void OBWindow::ConvertToScreen(BRect *rect) const +{ +} + +BRect OBWindow::ConvertToScreen(BRect rect) const +{ + return BRect(0,0,0,0); +} + +void OBWindow::ConvertFromScreen(BRect *rect) const +{ +} + +BRect OBWindow::ConvertFromScreen(BRect rect) const +{ + return BRect(0,0,0,0); +} + +void OBWindow::MoveBy(float dx, float dy) +{ +} + +void OBWindow::MoveTo(BPoint) +{ +} + +void OBWindow::MoveTo(float x, float y) +{ +} + +void OBWindow::ResizeBy(float dx, float dy) +{ +} + +void OBWindow::ResizeTo(float width, float height) +{ +} + +void OBWindow::Show() +{ + if(startlocked) + { + startlocked=false; + Unlock(); + } + hidelevel--; + if(hidelevel==0) + { + serverlink->SetOpCode(SHOW_WINDOW); + serverlink->Flush(); + } +} + +void OBWindow::Hide() +{ + if(hidelevel==0) + { + serverlink->SetOpCode(HIDE_WINDOW); + serverlink->Flush(); + } + hidelevel++; +} + +bool OBWindow::IsHidden() const +{ + return false; +} + +bool OBWindow::IsMinimized() const +{ + return false; +} + +void OBWindow::Flush() const +{ + // When attachment count inclusion is implemented, it needs to go + // in this function + + drawmsglink->SetOpCode(GFX_FLUSH); + drawmsglink->Flush(); +} + +void OBWindow::Sync() const +{ + // When attachment count inclusion is implemented, it needs to go + // in this function + + int32 code; + status_t status; + ssize_t buffersize; + + drawmsglink->SetOpCode(GFX_SYNC); + + // Reply received: + + // Code: SYNC + // Attached data: none + // Buffersize: 0 + drawmsglink->FlushWithReply(&code,&status,&buffersize); +} + +status_t OBWindow::SendBehind(const OBWindow *window) +{ + return B_ERROR; +} + +void OBWindow::DisableUpdates() +{ +} + +void OBWindow::EnableUpdates() +{ +} + +void OBWindow::BeginViewTransaction() +{ +} + +void OBWindow::EndViewTransaction() +{ +} + +BRect OBWindow::Bounds() const +{ + return BRect(0,0,0,0); +} + +BRect OBWindow::Frame() const +{ + return BRect(0,0,0,0); +} + +const char *OBWindow::Title() const +{ + return NULL; +} + +void OBWindow::SetTitle(const char *title) +{ +} + +bool OBWindow::IsFront() const +{ + return false; +} + +bool OBWindow::IsActive() const +{ + return false; +} + +uint32 OBWindow::Workspaces() const +{ + return 0; +} + +void OBWindow::SetWorkspaces(uint32) +{ +} + +OBView *OBWindow::LastMouseMovedView() const +{ + return NULL; +} + +status_t OBWindow::AddToSubset(OBWindow *window) +{ + return B_ERROR; +} + +status_t OBWindow::RemoveFromSubset(OBWindow *window) +{ + return B_ERROR; +} + +bool OBWindow::QuitRequested() +{ + return false; +} + +thread_id OBWindow::Run() +{ + return 0; +} + +uint32 OBWindow::WindowLookToInteger(window_look wl) +{ + switch(wl) + { + case B_BORDERED_WINDOW_LOOK: + return 1; + case B_TITLED_WINDOW_LOOK: + return 2; + case B_DOCUMENT_WINDOW_LOOK: + return 3; + case B_MODAL_WINDOW_LOOK: + return 4; + case B_FLOATING_WINDOW_LOOK: + return 5; + case B_NO_BORDER_WINDOW_LOOK: + default: + return 0; + } +} + +uint32 OBWindow::WindowFeelToInteger(window_feel wf) +{ + switch(wf) + { + case B_MODAL_SUBSET_WINDOW_FEEL: + return 1; + case B_MODAL_APP_WINDOW_FEEL: + return 2; + case B_MODAL_ALL_WINDOW_FEEL: + return 3; + case B_FLOATING_SUBSET_WINDOW_FEEL: + return 4; + case B_FLOATING_APP_WINDOW_FEEL: + return 5; + case B_FLOATING_ALL_WINDOW_FEEL: + return 6; + + case B_NORMAL_WINDOW_FEEL: + default: + return 0; + } +} + +window_look OBWindow::WindowLookFromType(window_type t) +{ + switch(t) + { + case B_TITLED_WINDOW: + return B_TITLED_WINDOW_LOOK; + case B_DOCUMENT_WINDOW: + return B_DOCUMENT_WINDOW_LOOK; + case B_MODAL_WINDOW: + return B_MODAL_WINDOW_LOOK; + case B_FLOATING_WINDOW: + return B_FLOATING_WINDOW_LOOK; + case B_BORDERED_WINDOW: + return B_BORDERED_WINDOW_LOOK; + case B_UNTYPED_WINDOW: + default: + return B_NO_BORDER_WINDOW_LOOK; + } +} + +window_feel OBWindow::WindowFeelFromType(window_type t) +{ + switch(t) + { + case B_MODAL_WINDOW: + return B_MODAL_APP_WINDOW_FEEL; + case B_FLOATING_WINDOW: + return B_FLOATING_APP_WINDOW_FEEL; + + // includes B_UNTYPED_WINDOW, B_BORDERED_WINDOW, B_DOCUMENT_WINDOW, + // and B_TITLED_WINDOW + default: + return B_NORMAL_WINDOW_FEEL; + } +} diff --git a/src/servers/app/proto6/testobapp/OBWindow.h b/src/servers/app/proto6/testobapp/OBWindow.h new file mode 100644 index 0000000000..1a13dd9660 --- /dev/null +++ b/src/servers/app/proto6/testobapp/OBWindow.h @@ -0,0 +1,145 @@ +#ifndef _OBWINDOW_H +#define _OBWINDOW_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class BButton; +class BMenuBar; +class BMenuItem; +class BMessage; +class BMessageRunner; +class BMessenger; +class OBView; +class PortLink; + +struct message; +struct _cmd_key_; +struct _view_attr_; + +#define ADDWINDOW '_adw' +#define REMOVEWINDOW '_rmw' + +class OBWindow : public BLooper +{ +public: +OBWindow(BRect frame,const char *title, window_type type, +uint32 flags,uint32 workspace = B_CURRENT_WORKSPACE); + +OBWindow(BRect frame,const char *title, window_look look,window_feel feel, +uint32 flags,uint32 workspace = B_CURRENT_WORKSPACE); + +virtual ~OBWindow(); + +virtual void Quit(); +void Close(); + +void AddChild(OBView *child, OBView *before = NULL); +bool RemoveChild(OBView *child); +int32 CountChildren() const; +OBView *ChildAt(int32 index) const; + +virtual void DispatchMessage(BMessage *message, BHandler *handler); +virtual void MessageReceived(BMessage *message); +virtual void FrameMoved(BPoint new_position); +virtual void WorkspacesChanged(uint32 old_ws, uint32 new_ws); +virtual void WorkspaceActivated(int32 ws, bool state); +virtual void FrameResized(float new_width, float new_height); +virtual void Minimize(bool minimize); +virtual void Zoom( BPoint rec_position, + float rec_width, + float rec_height); +void Zoom(); +virtual void ScreenChanged(BRect screen_size, color_space depth); +bool NeedsUpdate() const; +void UpdateIfNeeded(); +OBView *FindView(const char *view_name) const; +OBView *FindView(BPoint) const; +OBView *CurrentFocus() const; +void Activate(bool = true); +virtual void WindowActivated(bool state); +void ConvertToScreen(BPoint *pt) const; +BPoint ConvertToScreen(BPoint pt) const; +void ConvertFromScreen(BPoint *pt) const; +BPoint ConvertFromScreen(BPoint pt) const; +void ConvertToScreen(BRect *rect) const; +BRect ConvertToScreen(BRect rect) const; +void ConvertFromScreen(BRect *rect) const; +BRect ConvertFromScreen(BRect rect) const; +void MoveBy(float dx, float dy); +void MoveTo(BPoint); +void MoveTo(float x, float y); +void ResizeBy(float dx, float dy); +void ResizeTo(float width, float height); +virtual void Show(); +virtual void Hide(); +bool IsHidden() const; +bool IsMinimized() const; + +void Flush() const; +void Sync() const; + +status_t SendBehind(const OBWindow *window); + +void DisableUpdates(); +void EnableUpdates(); + +void BeginViewTransaction(); +void EndViewTransaction(); + +BRect Bounds() const; +BRect Frame() const; +const char *Title() const; +void SetTitle(const char *title); +bool IsFront() const; +bool IsActive() const; +uint32 Workspaces() const; +void SetWorkspaces(uint32); +OBView *LastMouseMovedView() const; + + +status_t AddToSubset(OBWindow *window); +status_t RemoveFromSubset(OBWindow *window); + +virtual bool QuitRequested(); +virtual thread_id Run(); + +protected: +friend OBView; + +uint32 WindowLookToInteger(window_look wl); +uint32 WindowFeelToInteger(window_feel wf); +window_look WindowLookFromType(window_type t); +window_feel WindowFeelFromType(window_type t); + +BString *wtitle; +int32 ID; +int32 topview_ID; +uint8 hidelevel; +uint32 wflags; + +PortLink *drawmsglink, *serverlink; +port_id inport; +port_id outport; + +OBView *top_view; +OBView *focusedview; +OBView *fLastMouseMovedView; +BRect wframe; + +window_look wlook; +window_feel wfeel; + +bool startlocked; +bool in_update; +bool is_active; +int32 wkspace; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/testobapp/PortLink.cpp b/src/servers/app/proto6/testobapp/PortLink.cpp new file mode 100644 index 0000000000..8fba724569 --- /dev/null +++ b/src/servers/app/proto6/testobapp/PortLink.cpp @@ -0,0 +1,438 @@ +/* + PortLink.cpp: + A helper class for port-based messaging + +------------------------------------------------------------------------ +How it works: + The class utilizes a fixed-size array of PortLinkData object pointers. When +data is attached, a new PortLinkData object is allocated and a copy of the +passed data is created inside it. When the time comes for the message to be sent, +the data is pieced together into a flattened array and written to the port. +------------------------------------------------------------------------ +Data members: + +*attachments[] - fixed-size array of pointers used to hold the attached data +opcode - message value which is sent along with any data +target - port to which the message is sent when Flush() is called +replyport - port used with synchronous messaging - FlushWithReply() +bufferlength - total bytes taken up by attachments +num_attachments - internal variable which is used to track which "slot" + will be the next one to receive an attachment object +*/ + +#include "PortLink.h" +#include +#include +#include + +//#define PLDEBUG + +// Internal data storage class for holding attached data whilst it is waiting +// to be Flattened() and then Flushed(). There is no need for this to be called outside +// the PortLink class. +class PortLinkData +{ +public: + PortLinkData(void); + ~PortLinkData(void); + bool Set(void *data, size_t size); + char *buffer; + size_t buffersize; +}; + +PortLink::PortLink(port_id port) +{ + // For this class to be useful (and to prevent a lot of init problems) + // we require a port in the constructor + target=port; + + // We start out without any data attached to the port message + num_attachments=0; + opcode=0; + bufferlength=0; + replyport=create_port(30,"PortLink reply port"); +} + +PortLink::~PortLink(void) +{ + // If, for some odd reason, this is deleted with something attached, + // free the memory used by the attachments. We do not flush the queue + // because the port may no longer be valid in cases such as the app + // is in the process of quitting + MakeEmpty(); +} + +void PortLink::SetOpCode(int32 code) +{ + // Sets the message code. This does not change once the message is sent. + // Another call to SetOpCode() is required for such things. + opcode=code; +} + +void PortLink::SetPort(port_id port) +{ + // Sets the target port. While not necessary in most uses, this exists + // mostly to prevent flexibility problems + target=port; +} + +port_id PortLink::GetPort(void) +{ + // Simply returns the port at which the object is pointed. + return target; +} + +void PortLink::Flush(bigtime_t timeout=B_INFINITE_TIMEOUT) +{ + // Fires a message off to the target, complete with attachments. NOTE: + // the recipient must delete all attachments, being the PortLink object assumes + // no responsiblity for the attachments once the message is sent. + int8 *msgbuffer; + int32 size; + + if(num_attachments>0) + { + FlattenData(&msgbuffer,&size); + + // Dump message to port, reset attachments, and clean up + if(timeout!=B_INFINITE_TIMEOUT) + write_port_etc(target,opcode,msgbuffer,size,B_TIMEOUT, timeout); + else + write_port(target,opcode,msgbuffer,size); + MakeEmpty(); + } + else + { + if(timeout!=B_INFINITE_TIMEOUT) + write_port_etc(target,opcode,NULL,0,B_TIMEOUT, timeout); + else + write_port(target,opcode,NULL,0); + } +} + +int8* PortLink::FlushWithReply(int32 *code, status_t *status, ssize_t *buffersize, bigtime_t timeout=B_INFINITE_TIMEOUT) +{ + // Fires a message to the target and then waits for a reply. The target will + // receive a message with the first item being the port_id to reply to. + // NOTE: like Flush(), any attached data must be deleted. + + // Effectively, an Attach() call inlined for changes + + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + { + *status=B_ERROR; + return NULL; + } + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&replyport,sizeof(port_id))) + { + bufferlength+=sizeof(port_id); + } + else + { + delete pld; + *status=B_ERROR; + return NULL; + } + + // Flatten() inlined to make some necessary changes + int8 *buffer=new int8[bufferlength]; + int8 *bufferindex=buffer; + size_t size=0; + + // attach our port_id first + memcpy(bufferindex, pld->buffer, pld->buffersize); + bufferindex += pld->buffersize; + size+=pld->buffersize; + + // attach everything else + for(int i=0;ibuffer, pld->buffersize); + bufferindex += pld->buffersize; + size+=pld->buffersize; + } + + // Flush the thing....FOOSH! :P + write_port(target,opcode,buffer,size); + MakeEmpty(); + delete buffer; + + // Now we wait for the reply + if(timeout==B_INFINITE_TIMEOUT) + { + *buffersize=port_buffer_size(replyport); + if(*buffersize>0) + buffer=(int8*)new int8[*buffersize]; + read_port(replyport,code, buffer, *buffersize); + } + else + { + *buffersize=port_buffer_size_etc(replyport,0,timeout); + if(*buffersize==B_TIMED_OUT) + { + *status=*buffersize; + return NULL; + } + if(*buffersize>0) + buffer=(int8*)new int8[*buffersize]; + read_port(replyport,code, buffer, *buffersize); + } + + // We got this far, so we apparently have some data + *status=B_OK; + return buffer; +} + +void PortLink::Attach(void *data, size_t size) +{ + // This is the member called to attach data to a message. Attachments are + // treated to be in 'Append' mode, tacking on each attached piece of data + // to the end of the list. + + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + if(size==0) + return; + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +// These functions were added for a major convenience in passing common types +// Eventually, I'd like to templatize these, but for now, this'll do + +void PortLink::Attach(int32 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int32); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(int16 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int16); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(int8 data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(int8); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(float data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(float); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(bool data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(bool); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(BRect data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(BRect); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::Attach(BPoint data) +{ + // Prevent parameter problems + if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS) + return; + + int32 size=sizeof(BPoint); + + // create a new storage object and stash the data + PortLinkData *pld=new PortLinkData; + if(pld->Set(&data,size)) + { + num_attachments++; + attachments[num_attachments-1]=pld; + bufferlength+=size; + } + else + { + delete pld; + } +} + +void PortLink::FlattenData(int8 **buffer,int32 *size) +{ + // This function is where all the magic happens, but it is strictly internal. + // It iterates through each PortLinkData object and copies it to the main buffer + // which ends up, ultimately, being written to the PortLink's target port. + + // skip if there aree no attachments + if(bufferlength<1) + return; + + *buffer=new int8[bufferlength]; + int8 *bufferindex=*buffer; + PortLinkData *pld; + *size=0; + + for(int i=0;ibuffer, pld->buffersize); + bufferindex += pld->buffersize; + *size+=pld->buffersize; + } +} + +void PortLink::MakeEmpty(void) +{ + // Nukes all the attachments currently held by the PortLink class + if(num_attachments!=0) + { + for(int i=0; i0) + free(buffer); +} + +bool PortLinkData::Set(void *data, size_t size) +{ + // Function copies the passed to the internal buffers for storage + if(size>0 && buffersize==0 && data!=NULL) + { + buffer=(char *)malloc(size); + if(buffer==NULL) + return false; + memcpy(buffer, data, size); + buffersize=size; + return true; + } + return false; +} diff --git a/src/servers/app/proto6/testobapp/PortLink.h b/src/servers/app/proto6/testobapp/PortLink.h new file mode 100644 index 0000000000..9f5432daab --- /dev/null +++ b/src/servers/app/proto6/testobapp/PortLink.h @@ -0,0 +1,43 @@ +#ifndef _PORTLINK_H_ +#define _PORTLINK_H_ + +#include +#include +#include +#include + +#ifndef _PORTLINK_BUFFERSIZE +#define _PORTLINK_MAX_ATTACHMENTS 50 +#endif + +class PortLinkData; + +class PortLink +{ +public: + PortLink(port_id port); + ~PortLink(void); + void SetOpCode(int32 code); + void SetPort(port_id port); + port_id GetPort(void); + void Flush(bigtime_t timeout=B_INFINITE_TIMEOUT); + int8* FlushWithReply(int32 *code, status_t *status, ssize_t *buffersize, + bigtime_t timeout=B_INFINITE_TIMEOUT); + void Attach(void *data, size_t size); + void Attach(int32 data); + void Attach(int16 data); + void Attach(int8 data); + void Attach(float data); + void Attach(bool data); + void Attach(BRect data); + void Attach(BPoint data); + void MakeEmpty(void); +protected: + void FlattenData(int8 **buffer,int32 *size); + port_id target, replyport; + int32 opcode, bufferlength; + int num_attachments; + PortLinkData *attachments[_PORTLINK_MAX_ATTACHMENTS]; +}; + +#endif \ No newline at end of file diff --git a/src/servers/app/proto6/testobapp/ServerProtocol.h b/src/servers/app/proto6/testobapp/ServerProtocol.h new file mode 100644 index 0000000000..d2138e2c1b --- /dev/null +++ b/src/servers/app/proto6/testobapp/ServerProtocol.h @@ -0,0 +1,95 @@ +#ifndef _APPSERVER_PROTOCOL_ +#define _APPSERVER_PROTOCOL_ + +#define CREATE_APP 'drca' +#define DELETE_APP 'drda' +#define QUIT_APP 'srqa' + +#define SET_SERVER_PORT 'srsp' + +#define CREATE_WINDOW 'drcw' +#define DELETE_WINDOW 'drdw' +#define SHOW_WINDOW 'drsw' +#define HIDE_WINDOW 'drhw' +#define QUIT_WINDOW 'srqw' + +#define SERVER_PORT_NAME "OBappserver" +#define SERVER_INPUT_PORT "OBinputport" + +#define SET_CURSOR_DATA 'sscd' +#define SET_CURSOR_BCURSOR 'sscb' +#define SET_CURSOR_BBITMAP 'sscB' +#define SHOW_CURSOR 'srsc' +#define HIDE_CURSOR 'srhc' +#define OBSCURE_CURSOR 'sroc' + +#define GFX_COUNT_WORKSPACES 'gcws' +#define GFX_SET_WORKSPACE_COUNT 'ggwc' +#define GFX_CURRENT_WORKSPACE 'ggcw' +#define GFX_ACTIVATE_WORKSPACE 'gaws' +#define GFX_GET_SYSTEM_COLORS 'gsyc' +#define GFX_SET_SYSTEM_COLORS 'gsyc' +#define GFX_SET_SCREEN_MODE 'gssm' +#define GFX_GET_SCROLLBAR_INFO 'ggsi' +#define GFX_SET_SCROLLBAR_INFO 'gssi' +#define GFX_IDLE_TIME 'gidt' +#define GFX_SELECT_PRINTER_PANEL 'gspp' +#define GFX_ADD_PRINTER_PANEL 'gapp' +#define GFX_RUN_BE_ABOUT 'grba' +#define GFX_SET_FOCUS_FOLLOWS_MOUSE 'gsfm' +#define GFX_FOCUS_FOLLOWS_MOUSE 'gffm' + +#define GFX_SET_HIGH_COLOR 'gshc' +#define GFX_SET_LOW_COLOR 'gslc' +#define GFX_SET_VIEW_COLOR 'gsvc' + +#define GFX_STROKE_ARC 'gsar' +#define GFX_STROKE_BEZIER 'gsbz' +#define GFX_STROKE_ELLIPSE 'gsel' +#define GFX_STROKE_LINE 'gsln' +#define GFX_STROKE_POLYGON 'gspy' +#define GFX_STROKE_RECT 'gsrc' +#define GFX_STROKE_ROUNDRECT 'gsrr' +#define GFX_STROKE_SHAPE 'gssh' +#define GFX_STROKE_TRIANGLE 'gstr' + +#define GFX_FILL_ARC 'gfar' +#define GFX_FILL_BEZIER 'gfbz' +#define GFX_FILL_ELLIPSE 'gfel' +#define GFX_FILL_POLYGON 'gfpy' +#define GFX_FILL_RECT 'gfrc' +#define GFX_FILL_REGION 'gfrg' +#define GFX_FILL_ROUNDRECT 'gfrr' +#define GFX_FILL_SHAPE 'gfsh' +#define GFX_FILL_TRIANGLE 'gftr' + +#define GFX_MOVEPENBY 'gmpb' +#define GFX_MOVEPENTO 'gmpt' +#define GFX_SETPENSIZE 'gsps' + +#define GFX_DRAW_STRING 'gdst' +#define GFX_SET_FONT 'gsft' +#define GFX_SET_FONT_SIZE 'gsfs' + +#define GFX_FLUSH 'gfsh' +#define GFX_SYNC 'gsyn' + +#define LAYER_CREATE 'lycr' +#define LAYER_DELETE 'lydl' +#define LAYER_ADD_CHILD 'lyac' +#define LAYER_REMOVE_CHILD 'lyrc' +#define LAYER_REMOVE_SELF 'lyrs' +#define LAYER_SHOW 'lysh' +#define LAYER_HIDE 'lyhd' +#define LAYER_MOVE 'lymv' +#define LAYER_RESIZE 'lyre' +#define LAYER_INVALIDATE 'lyin' +#define LAYER_DRAW 'lydr' + +#define BEGIN_RECT_TRACKING 'rtbg' +#define END_RECT_TRACKING 'rten' + +#define VIEW_GET_TOKEN 'vgtk' +#define VIEW_ADD 'vadd' +#define VIEW_REMOVE 'vrem' +#endif \ No newline at end of file diff --git a/src/servers/input/InputServer.FileTypes.rsrc b/src/servers/input/InputServer.FileTypes.rsrc new file mode 100644 index 0000000000..c240c30b88 Binary files /dev/null and b/src/servers/input/InputServer.FileTypes.rsrc differ diff --git a/src/servers/input/InputServer.cpp b/src/servers/input/InputServer.cpp new file mode 100644 index 0000000000..895eabc45f --- /dev/null +++ b/src/servers/input/InputServer.cpp @@ -0,0 +1,868 @@ +#include + +#include "InputServer.h" +#include "Path.h" +#include "Directory.h" +#include "FindDirectory.h" +#include "Entry.h" + +#include "InputServerDeviceListEntry.h" + + +/* + * + */ +int main(int argc, char* argv[]) +{ + InputServer *myInputServer; + + myInputServer = new InputServer; + + myInputServer->Run(); + + delete myInputServer; + + return(0); +} +/* +thread_id InputServer::Run() +{ + InitDevices(); + + return 0; +} +*/ +/* + * Method: InputServer::InputServer() + * Descr: + */ +InputServer::InputServer(void) : BApplication("application/x-vnd.OpenBeOS-input_server") +{ + void *pointer; + + InitDevices(); + EventLoop(pointer); + + +} + +/* + * Method: InputServer::InputServer() + * Descr: + */ +InputServer::~InputServer(void) +{ +} + + +/* + * Method: InputServer::ArgvReceived() + * Descr: + */ +void InputServer::ArgvReceived(long, + char **) +{ +} + + +/* + * Method: InputServer::InitKeyboardMouseStates() + * Descr: + */ +void InputServer::InitKeyboardMouseStates(void) +{ +} + + +/* + * Method: InputServer::InitDevices() + * Descr: + */ +void InputServer::InitDevices(void) +{ + BDirectory dir; + BPath addon_dir; + BPath addon_path; + BEntry entry; + directory_which addon_dirs[] = + { + B_BEOS_ADDONS_DIRECTORY, + B_COMMON_ADDONS_DIRECTORY, + B_USER_ADDONS_DIRECTORY + }; + const int addon_dir_count = sizeof(addon_dirs) / sizeof(directory_which); + + printf("InputServer::InitDevices - Enter\n"); + + // Find all Input Server Devices in each of the predefined + // addon directories. + // + for (int i = 0; i < addon_dir_count; i++) + { + if (B_OK == find_directory(addon_dirs[i], &addon_dir) ) + { + addon_dir.Append("input_server/devices"); + dir.SetTo(addon_dir.Path() ); + while (B_NO_ERROR == dir.GetNextEntry(&entry, false) ) + { + entry.GetPath(&addon_path); + printf("Adding %s . . .\n", addon_path.Path() ); + AddInputServerDevice(addon_path.Path() ); + } + } + } + printf("InputServer::InitDevices - Exit\n"); +} + + +/* + * Method: InputServer::AddInputServerDevice() + * Descr: + */ +status_t InputServer::AddInputServerDevice(const char* path) +{ + image_id addon_image= load_add_on(path); + if (B_ERROR != addon_image) + { + status_t isd_status = B_NO_INIT; + BInputServerDevice* (*func)() = NULL; + if (B_OK == get_image_symbol(addon_image, "instantiate_input_device", B_SYMBOL_TYPE_TEXT, (void**)&func) ) + { + if (NULL != func) + { + /* + // :DANGER: Only reenable this section if this + // InputServer can start and manage the + // devices, otherwise the system will hang. + // + BInputServerDevice* isd = (*func)(); + if (NULL != isd) + { + status_t isd_status = isd->InitCheck(); + mInputServerDeviceList.AddItem( + new InputServerDeviceListEntry(path, isd_status, isd) ); + } + */ + mInputServerDeviceList.AddItem( + new InputServerDeviceListEntry(path, B_NO_INIT, NULL) ); + } + } + if (B_OK != isd_status) + { + // Free resources associated with ISD's + // that failed to initialize. + // + unload_add_on(addon_image); + } + } + return 0; +} + + +/* + * Method: InputServer::InitFilters() + * Descr: + */ +void InputServer::InitFilters(void) +{ + BDirectory dir; + BPath addon_dir; + BPath addon_path; + BEntry entry; + directory_which addon_dirs[] = + { + B_BEOS_ADDONS_DIRECTORY, + B_COMMON_ADDONS_DIRECTORY, + B_USER_ADDONS_DIRECTORY + }; + const int addon_dir_count = sizeof(addon_dirs) / sizeof(directory_which); + + printf("InputServer::InitFilters - Enter\n"); + + // Find all Input Server Devices in each of the predefined + // addon directories. + // + for (int i = 0; i < addon_dir_count; i++) + { + if (B_OK == find_directory(addon_dirs[i], &addon_dir) ) + { + addon_dir.Append("input_server/filters"); + dir.SetTo(addon_dir.Path() ); + while (B_NO_ERROR == dir.GetNextEntry(&entry, false) ) + { + entry.GetPath(&addon_path); + printf("Adding %s . . .\n", addon_path.Path() ); + AddInputServerDevice(addon_path.Path() ); + } + } + } + printf("InputServer::InitDevices - Exit\n"); +} + + +/* + * Method: InputServer::InitMethods() + * Descr: + */ +void InputServer::InitMethods(void) +{ + BDirectory dir; + BPath addon_dir; + BPath addon_path; + BEntry entry; + directory_which addon_dirs[] = + { + B_BEOS_ADDONS_DIRECTORY, + B_COMMON_ADDONS_DIRECTORY, + B_USER_ADDONS_DIRECTORY + }; + const int addon_dir_count = sizeof(addon_dirs) / sizeof(directory_which); + + printf("InputServer::InitDevices - Enter\n"); + + // Find all Input Server Devices in each of the predefined + // addon directories. + // + for (int i = 0; i < addon_dir_count; i++) + { + if (B_OK == find_directory(addon_dirs[i], &addon_dir) ) + { + addon_dir.Append("input_server/devices"); + dir.SetTo(addon_dir.Path() ); + while (B_NO_ERROR == dir.GetNextEntry(&entry, false) ) + { + entry.GetPath(&addon_path); + printf("Adding %s . . .\n", addon_path.Path() ); + AddInputServerDevice(addon_path.Path() ); + } + } + } + printf("InputServer::InitDevices - Exit\n"); +} + + +/* + * Method: InputServer::QuitRequested() + * Descr: + */ +bool InputServer::QuitRequested(void) +{ + kill_thread(ISPortThread); + delete_port(EventLooperPort); + EventLooperPort = -1; + return true; +} + +// --------------------------------------------------------------- +// InputServer::ReadyToRun(void) +// +// Verifies to see if the input_server is able to start. +// +// +// Parameters: +// None +// +// Returns: +// B_OK if the +// --------------------------------------------------------------- +void InputServer::ReadyToRun(void) +{ +} + + +/* + * Method: InputServer::MessageReceived() + * Descr: + */ +void InputServer::MessageReceived(BMessage *message) +{ +BMessenger *app_server; + switch(message->what) + { + case SET_METHOD: + { + //HandleSetMethod(); + break; + } + case GET_MOUSE_TYPE: + { + //HandleGetSetMouseType(); + break; + } + case SET_MOUSE_TYPE: + { + //HandleGetSetMouseType(); + break; + } + case GET_MOUSE_ACCELERATION: + { + //HandleGetSetMouseAcceleration(); + break; + } + case SET_MOUSE_ACCELERATION: + { + //HandleGetSetMouseAcceleration(); + break; + } + case GET_KEY_REPEAT_DELAY: + { + //HandleGetSetKeyRepeatDelay(); + break; + } + case SET_KEY_REPEAT_DELAY: + { + //HandleGetSetKeyRepeatDelay(); + break; + } + case GET_KEY_INFO: + { + //HandleGetKeyInfo(); + break; + } + case GET_MODIFIERS: + { + //HandleGetModifiers(); + break; + } + case SET_MODIFIER_KEY: + { + //HandleSetModifierKey(); + break; + } + case SET_KEYBOARD_LOCKS: + { + //HandleSetKeyboardLocks(); + break; + } + case GET_MOUSE_SPEED: + { + //HandleGetSetMouseSpeed(); + break; + } + case SET_MOUSE_SPEED: + { + //HandleGetSetMouseSpeed(); + break; + } + case SET_MOUSE_POSITION: + { + //HandleSetMousePosition(); + break; + } + case GET_MOUSE_MAP: + { + //HandleGetSetMouseMap(); + break; + } + case SET_MOUSE_MAP: + { + //HandleGetSetMouseMap(); + break; + } + case GET_KEYBOARD_ID: + { + //HandleGetKeyboardID(); + break; + } + case GET_CLICK_SPEED: + { + //HandleGetSetClickSpeed(); + break; + } + case SET_CLICK_SPEED: + { + //HandleGetSetClickSpeed(); + break; + } + case GET_KEY_REPEAT_RATE: + { + //HandleGetSetKeyRepeatRate(); + break; + } + case SET_KEY_REPEAT_RATE: + { + //HandleGetSetKeyRepeatRate(); + break; + } + case GET_KEY_MAP: + { + //HandleGetSetKeyMap(); + break; + } + case SET_KEY_MAP: + { + //HandleGetSetKeyMap(); + break; + } + case FOCUS_IM_AWARE_VIEW: + { + //HandleFocusUnfocusIMAwareView(); + break; + } + case UNFOCUS_IM_AWARE_VIEW: + { + //HandleFocusUnfocusIMAwareView(); + break; + } + + default: + { + app_server = new BMessenger("application/x-vnd.Be-APPS", -1, NULL); + if (app_server->IsValid()) + { + app_server->SendMessage(message); + + } + delete app_server; + break; + } + } +} + + +/* + * Method: InputServer::HandleSetMethod() + * Descr: + */ +void InputServer::HandleSetMethod(BMessage *) +{ +} + + +/* + * Method: InputServer::HandleGetSetMouseType() + * Descr: + */ +void InputServer::HandleGetSetMouseType(BMessage *, + BMessage *) +{ +} + + +/* + * Method: InputServer::HandleGetSetMouseAcceleration() + * Descr: + */ +void InputServer::HandleGetSetMouseAcceleration(BMessage *, + BMessage *) +{ +} + + +/* + * Method: InputServer::HandleGetSetKeyRepeatDelay() + * Descr: + */ +void InputServer::HandleGetSetKeyRepeatDelay(BMessage *, + BMessage *) +{ +} + + +/* + * Method: InputServer::HandleGetKeyInfo() + * Descr: + */ +void InputServer::HandleGetKeyInfo(BMessage *, + BMessage *) +{ +} + + +/* + * Method: InputServer::HandleGetModifiers() + * Descr: + */ +void InputServer::HandleGetModifiers(BMessage *, + BMessage *) +{ +} + + +/* + * Method: InputServer::HandleSetModifierKey() + * Descr: + */ +void InputServer::HandleSetModifierKey(BMessage *, + BMessage *) +{ +} + + +/* + * Method: InputServer::HandleSetKeyboardLocks() + * Descr: + */ +void InputServer::HandleSetKeyboardLocks(BMessage *, + BMessage *) +{ +} + + +/* + * Method: InputServer::HandleGetSetMouseSpeed() + * Descr: + */ +void InputServer::HandleGetSetMouseSpeed(BMessage *, + BMessage *) +{ +} + + +/* + * Method: InputServer::HandleSetMousePosition() + * Descr: + */ +void InputServer::HandleSetMousePosition(BMessage *, + BMessage *) +{ +} + + +/* + * Method: InputServer::HandleGetSetMouseMap() + * Descr: + */ +void InputServer::HandleGetSetMouseMap(BMessage *, + BMessage *) +{ +} + + +/* + * Method: InputServer::HandleGetKeyboardID() + * Descr: + */ +void InputServer::HandleGetKeyboardID(BMessage *, + BMessage *) +{ +} + + +/* + * Method: InputServer::HandleGetSetClickSpeed() + * Descr: + */ +void InputServer::HandleGetSetClickSpeed(BMessage *, + BMessage *) +{ +} + + +/* + * Method: InputServer::HandleGetSetKeyRepeatRate() + * Descr: + */ +void InputServer::HandleGetSetKeyRepeatRate(BMessage *, + BMessage *) +{ +} + + +/* + * Method: InputServer::HandleGetSetKeyMap() + * Descr: + */ +void InputServer::HandleGetSetKeyMap(BMessage *, + BMessage *) +{ +} + + +/* + * Method: InputServer::HandleFocusUnfocusIMAwareView() + * Descr: + */ +void InputServer::HandleFocusUnfocusIMAwareView(BMessage *, + BMessage *) +{ +} + + +/* + * Method: InputServer::EnqueueDeviceMessage() + * Descr: + */ +status_t InputServer::EnqueueDeviceMessage(BMessage *) +{ + return 0; +} + + +/* + * Method: InputServer::EnqueueMethodMessage() + * Descr: + */ +status_t InputServer::EnqueueMethodMessage(BMessage *) +{ + return 0; +} + + +/* + * Method: InputServer::UnlockMethodQueue() + * Descr: + */ +status_t InputServer::UnlockMethodQueue(void) +{ + return 0; +} + + +/* + * Method: InputServer::LockMethodQueue() + * Descr: + */ +status_t InputServer::LockMethodQueue(void) +{ + return 0; +} + + +/* + * Method: InputServer::SetNextMethod() + * Descr: + */ +status_t InputServer::SetNextMethod(bool) +{ + return 0; +} + + +/* + * Method: InputServer::SetActiveMethod() + * Descr: + */ +/* +InputServer::SetActiveMethod(_BMethodAddOn_ *) +{ + return 0; +} +*/ + + +/* + * Method: InputServer::MethodReplicant() + * Descr: + */ +const BMessenger* InputServer::MethodReplicant(void) +{ + return NULL; +} + + +/* + * Method: InputServer::EventLoop() + * Descr: + */ +status_t InputServer::EventLoop(void *) +{ + + EventLooperPort = create_port(29,"is_event_port"); + if(EventLooperPort < 0) { + _sPrintf("OBOS InputServer: create_port error: (0x%x) %s\n",EventLooperPort,strerror(EventLooperPort)); + } + ISPortThread = spawn_thread(ISPortWatcher, "_input_server_event_loop_", B_REAL_TIME_DISPLAY_PRIORITY+3, this); + resume_thread(ISPortThread); + + + return 0; +} + + +/* + * Method: InputServer::EventLoopRunning() + * Descr: + */ +bool InputServer::EventLoopRunning(void) +{ + return true; +} + + +/* + * Method: InputServer::DispatchEvents() + * Descr: + */ +bool InputServer::DispatchEvents(BList *) +{ + return true; +} + + +/* + * Method: InputServer::CacheEvents() + * Descr: + */ +bool InputServer::CacheEvents(BList *) +{ + return true; +} + + +/* + * Method: InputServer::GetNextEvents() + * Descr: + */ +const BList* InputServer::GetNextEvents(BList *) +{ + return NULL; +} + + +/* + * Method: InputServer::FilterEvents() + * Descr: + */ +bool InputServer::FilterEvents(BList *) +{ + return true; +} + + +/* + * Method: InputServer::SanitizeEvents() + * Descr: + */ +bool InputServer::SanitizeEvents(BList *) +{ + return true; +} + + +/* + * Method: InputServer::MethodizeEvents() + * Descr: + */ +bool InputServer::MethodizeEvents(BList *, + bool) +{ + return true; +} + + +/* + * Method: InputServer::StartStopDevices() + * Descr: + */ +status_t InputServer::StartStopDevices(const char* deviceName, input_device_type deviceType, bool doStart) +{ + return 0; +} + + +/* + * Method: InputServer::ControlDevices() + * Descr: + */ +status_t InputServer::ControlDevices(const char *, + input_device_type, + unsigned long, + BMessage *) +{ + return 0; +} + + +/* + * Method: InputServer::DoMouseAcceleration() + * Descr: + */ +bool InputServer::DoMouseAcceleration(long *, + long *) +{ + return true; +} + + +/* + * Method: InputServer::SetMousePos() + * Descr: + */ +bool InputServer::SetMousePos(long *, + long *, + long, + long) +{ + return true; +} + + +/* + * Method: InputServer::SetMousePos() + * Descr: + */ +bool InputServer::SetMousePos(long *, + long *, + BPoint) +{ + return true; +} + + +/* + * Method: InputServer::SetMousePos() + * Descr: + */ +bool InputServer::SetMousePos(long *, + long *, + float, + float) +{ + return true; +} + + +/* + * Method: InputServer::SafeMode() + * Descr: + */ +bool InputServer::SafeMode(void) +{ + return true; +} + +int32 InputServer::ISPortWatcher(void *arg) +{ + InputServer *self = (InputServer*)arg; + self->WatchPort(); + return (B_NO_ERROR); +} + +void InputServer::WatchPort() +{ + int32 code; + ssize_t length; + char *buffer; + BMessage *event; + status_t err; + + while (true) { + // Block until we find the size of the next message + length = port_buffer_size(EventLooperPort); + buffer = (char*)malloc(length); + event = NULL; + event = new BMessage(); + err = read_port(EventLooperPort, &code, buffer, length); + if(err != length) { + if(err >= 0) { + _sPrintf("InputServer: failed to read full packet (read %u of %u)\n",err,length); + } else { + _sPrintf("InputServer: read_port error: (0x%x) %s\n",err,strerror(err)); + } + } else if ((err = event->Unflatten(buffer)) < 0) { + _sPrintf("InputServer: (0x%x) %s\n",err,strerror(err)); + } else { + // add the event + //CacheEvents(event); + event = NULL; + } + free( buffer); + if(event!=NULL) { + delete(event); + event = NULL; + } + } + +} + diff --git a/src/servers/input/InputServer.h b/src/servers/input/InputServer.h new file mode 100644 index 0000000000..416fd63971 --- /dev/null +++ b/src/servers/input/InputServer.h @@ -0,0 +1,137 @@ +/*****************************************************************************/ +// OpenBeOS input_server Backend Application +// +// This is the primary application class for the OpenBeOS input_server. +// +// +// Copyright (c) 2001 OpenBeOS Project +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ + + +#ifndef INPUTSERVERAPP_H +#define INPUTSERVERAPP_H + +// BeAPI Headers +#include +#include "InputServerDevice.h" +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "InputServerTypes.h" + +/*****************************************************************************/ +// InputServer +// +// Application class for input_server. +/*****************************************************************************/ + +class InputServer : public BApplication +{ + typedef BApplication Inherited; +public: + InputServer(void); + ~InputServer(void); + + void ArgvReceived(long, char**); + + void InitKeyboardMouseStates(void); + + void InitDevices(void); + void InitFilters(void); + void InitMethods(void); + + bool QuitRequested(void); + void ReadyToRun(void); + //thread_id Run(void); + void MessageReceived(BMessage*); + + void HandleSetMethod(BMessage*); + void HandleGetSetMouseType(BMessage*, BMessage*); + void HandleGetSetMouseAcceleration(BMessage*, BMessage*); + void HandleGetSetKeyRepeatDelay(BMessage*, BMessage*); + void HandleGetKeyInfo(BMessage*, BMessage*); + void HandleGetModifiers(BMessage*, BMessage*); + void HandleSetModifierKey(BMessage*, BMessage*); + void HandleSetKeyboardLocks(BMessage*, BMessage*); + void HandleGetSetMouseSpeed(BMessage*, BMessage*); + void HandleSetMousePosition(BMessage*, BMessage*); + void HandleGetSetMouseMap(BMessage*, BMessage*); + void HandleGetKeyboardID(BMessage*, BMessage*); + void HandleGetSetClickSpeed(BMessage*, BMessage*); + void HandleGetSetKeyRepeatRate(BMessage*, BMessage*); + void HandleGetSetKeyMap(BMessage*, BMessage*); + void HandleFocusUnfocusIMAwareView(BMessage*, BMessage*); + + status_t EnqueueDeviceMessage(BMessage*); + status_t EnqueueMethodMessage(BMessage*); + status_t UnlockMethodQueue(void); + status_t LockMethodQueue(void); + status_t SetNextMethod(bool); + //SetActiveMethod(_BMethodAddOn_*); + const BMessenger* MethodReplicant(void); + + status_t EventLoop(void*); + bool EventLoopRunning(void); + + bool DispatchEvents(BList*); + bool CacheEvents(BList*); + const BList* GetNextEvents(BList*); + bool FilterEvents(BList*); + bool SanitizeEvents(BList*); + bool MethodizeEvents(BList*, bool); + + status_t StartStopDevices(const char *, input_device_type, bool); + status_t ControlDevices(const char *, input_device_type, unsigned long, BMessage*); + + bool DoMouseAcceleration(long*, long*); + bool SetMousePos(long*, long*, long, long); + bool SetMousePos(long*, long*, BPoint); + bool SetMousePos(long*, long*, float, float); + + bool SafeMode(void); + +private: + status_t AddInputServerDevice(const char* path); + + bool sEventLoopRunning; + bool sSafeMode; + + BList mInputServerDeviceList; + BList mInputMethodList; + BList mInputFilterList; + port_id ISPort; + port_id EventLooperPort; + thread_id ISPortThread; + static int32 ISPortWatcher(void *arg); + void WatchPort(); + + //fMouseState; +}; + +#endif \ No newline at end of file diff --git a/src/servers/input/InputServerDevice.cpp b/src/servers/input/InputServerDevice.cpp new file mode 100644 index 0000000000..6b64ba9519 --- /dev/null +++ b/src/servers/input/InputServerDevice.cpp @@ -0,0 +1,201 @@ +/*********************************************************************** + * AUTHOR: nobody + * FILE: InputServerDevice.cpp + * DATE: Sun Dec 16 15:57:43 2001 + * DESCR: + ***********************************************************************/ +#include "InputServerDevice.h" + +/* + * Method: BInputServerDevice::BInputServerDevice() + * Descr: + */ +BInputServerDevice::BInputServerDevice() +{ +} + + +/* + * Method: BInputServerDevice::~BInputServerDevice() + * Descr: + */ +BInputServerDevice::~BInputServerDevice() +{ +} + + +/* + * Method: BInputServerDevice::InitCheck() + * Descr: + */ +status_t +BInputServerDevice::InitCheck() +{ + status_t dummy; + + return dummy; +} + + +/* + * Method: BInputServerDevice::SystemShuttingDown() + * Descr: + */ +status_t +BInputServerDevice::SystemShuttingDown() +{ + status_t dummy; + + return dummy; +} + + +/* + * Method: BInputServerDevice::Start() + * Descr: + */ +status_t +BInputServerDevice::Start(const char *device, + void *cookie) +{ + status_t dummy; + + return dummy; +} + + +/* + * Method: BInputServerDevice::Stop() + * Descr: + */ +status_t +BInputServerDevice::Stop(const char *device, + void *cookie) +{ + status_t dummy; + + return dummy; +} + + +/* + * Method: BInputServerDevice::Control() + * Descr: + */ +status_t +BInputServerDevice::Control(const char *device, + void *cookie, + uint32 code, + BMessage *message) +{ + status_t dummy; + + return dummy; +} + + +/* + * Method: BInputServerDevice::RegisterDevices() + * Descr: + */ +status_t +BInputServerDevice::RegisterDevices(input_device_ref **devices) +{ + status_t dummy; + + return dummy; +} + + +/* + * Method: BInputServerDevice::UnregisterDevices() + * Descr: + */ +status_t +BInputServerDevice::UnregisterDevices(input_device_ref **devices) +{ + status_t dummy; + + return dummy; +} + + +/* + * Method: BInputServerDevice::EnqueueMessage() + * Descr: + */ +status_t +BInputServerDevice::EnqueueMessage(BMessage *message) +{ + status_t dummy; + + return dummy; +} + + +/* + * Method: BInputServerDevice::StartMonitoringDevice() + * Descr: + */ +status_t +BInputServerDevice::StartMonitoringDevice(const char *device) +{ + status_t dummy; + + return dummy; +} + + +/* + * Method: BInputServerDevice::StopMonitoringDevice() + * Descr: + */ +status_t +BInputServerDevice::StopMonitoringDevice(const char *device) +{ + status_t dummy; + + return dummy; +} + + +/* + * Method: BInputServerDevice::_ReservedInputServerDevice1() + * Descr: + */ +void +BInputServerDevice::_ReservedInputServerDevice1() +{ +} + + +/* + * Method: BInputServerDevice::_ReservedInputServerDevice2() + * Descr: + */ +void +BInputServerDevice::_ReservedInputServerDevice2() +{ +} + + +/* + * Method: BInputServerDevice::_ReservedInputServerDevice3() + * Descr: + */ +void +BInputServerDevice::_ReservedInputServerDevice3() +{ +} + + +/* + * Method: BInputServerDevice::_ReservedInputServerDevice4() + * Descr: + */ +void +BInputServerDevice::_ReservedInputServerDevice4() +{ +} + + diff --git a/src/servers/input/InputServerDeviceListEntry.h b/src/servers/input/InputServerDeviceListEntry.h new file mode 100644 index 0000000000..9935282aa9 --- /dev/null +++ b/src/servers/input/InputServerDeviceListEntry.h @@ -0,0 +1,27 @@ +// +// Class to encapsulate entries in the InputServer's InputServerDevice list. +// +class InputServerDeviceListEntry +{ + public: + inline const char* getPath() { return mPath; }; + inline status_t getStatus() { return mStatus; }; + inline const BInputServerDevice* getInputServerDevice() { return mIsd; }; + + InputServerDeviceListEntry( + const char* path, + status_t status, + const BInputServerDevice* isd) : mPath (path), + mStatus(status), + mIsd (isd) + { /* Do nothing */ }; + + ~InputServerDeviceListEntry() + { /* Do nothing */ }; + + private: + const char* mPath; + status_t mStatus; + const BInputServerDevice* mIsd; + +}; diff --git a/src/servers/input/InputServerFilter.cpp b/src/servers/input/InputServerFilter.cpp new file mode 100644 index 0000000000..6efd612d4e --- /dev/null +++ b/src/servers/input/InputServerFilter.cpp @@ -0,0 +1,106 @@ +/*********************************************************************** + * AUTHOR: nobody + * FILE: InputServerFilter.cpp + * DATE: Sun Dec 16 15:57:43 2001 + * DESCR: + ***********************************************************************/ +#include "InputServerFilter.h" + +/* + * Method: BInputServerFilter::BInputServerFilter() + * Descr: + */ +BInputServerFilter::BInputServerFilter() +{ +} + + +/* + * Method: BInputServerFilter::~BInputServerFilter() + * Descr: + */ +BInputServerFilter::~BInputServerFilter() +{ +} + + +/* + * Method: BInputServerFilter::InitCheck() + * Descr: + */ +status_t +BInputServerFilter::InitCheck() +{ + status_t dummy; + + return dummy; +} + + +/* + * Method: BInputServerFilter::Filter() + * Descr: + */ +filter_result +BInputServerFilter::Filter(BMessage *message, + BList *outList) +{ + filter_result dummy; + + return dummy; +} + + +/* + * Method: BInputServerFilter::GetScreenRegion() + * Descr: + */ +status_t +BInputServerFilter::GetScreenRegion(BRegion *region) const +{ + status_t dummy; + + return dummy; +} + + +/* + * Method: BInputServerFilter::_ReservedInputServerFilter1() + * Descr: + */ +void +BInputServerFilter::_ReservedInputServerFilter1() +{ +} + + +/* + * Method: BInputServerFilter::_ReservedInputServerFilter2() + * Descr: + */ +void +BInputServerFilter::_ReservedInputServerFilter2() +{ +} + + +/* + * Method: BInputServerFilter::_ReservedInputServerFilter3() + * Descr: + */ +void +BInputServerFilter::_ReservedInputServerFilter3() +{ +} + + +/* + * Method: BInputServerFilter::_ReservedInputServerFilter4() + * Descr: + */ +void +BInputServerFilter::_ReservedInputServerFilter4() +{ +} + + diff --git a/src/servers/input/InputServerMethod.cpp b/src/servers/input/InputServerMethod.cpp new file mode 100644 index 0000000000..a91582ad09 --- /dev/null +++ b/src/servers/input/InputServerMethod.cpp @@ -0,0 +1,134 @@ +/*********************************************************************** + * AUTHOR: nobody + * FILE: InputServerMethod.cpp + * DATE: Sun Dec 16 15:57:43 2001 + * DESCR: + ***********************************************************************/ +#include "InputServerMethod.h" +#include "Messenger.h" + +/* + * Method: BInputServerMethod::BInputServerMethod() + * Descr: + */ +BInputServerMethod::BInputServerMethod(const char *name, + const uchar *icon) +{ +} + + +/* + * Method: BInputServerMethod::~BInputServerMethod() + * Descr: + */ +BInputServerMethod::~BInputServerMethod() +{ +} + + +/* + * Method: BInputServerMethod::MethodActivated() + * Descr: + */ +status_t +BInputServerMethod::MethodActivated(bool active) +{ + status_t dummy; + + return dummy; +} + + +/* + * Method: BInputServerMethod::EnqueueMessage() + * Descr: + */ +status_t +BInputServerMethod::EnqueueMessage(BMessage *message) +{ + status_t dummy; + + return dummy; +} + + +/* + * Method: BInputServerMethod::SetName() + * Descr: + */ +status_t +BInputServerMethod::SetName(const char *name) +{ + status_t dummy; + + return dummy; +} + + +/* + * Method: BInputServerMethod::SetIcon() + * Descr: + */ +status_t +BInputServerMethod::SetIcon(const uchar *icon) +{ + status_t dummy; + + return dummy; +} + + +/* + * Method: BInputServerMethod::SetMenu() + * Descr: + */ +status_t +BInputServerMethod::SetMenu(const BMenu *menu, + const BMessenger target) +{ + status_t dummy; + + return dummy; +} + + +/* + * Method: BInputServerMethod::_ReservedInputServerMethod1() + * Descr: + */ +void +BInputServerMethod::_ReservedInputServerMethod1() +{ +} + + +/* + * Method: BInputServerMethod::_ReservedInputServerMethod2() + * Descr: + */ +void +BInputServerMethod::_ReservedInputServerMethod2() +{ +} + + +/* + * Method: BInputServerMethod::_ReservedInputServerMethod3() + * Descr: + */ +void +BInputServerMethod::_ReservedInputServerMethod3() +{ +} + + +/* + * Method: BInputServerMethod::_ReservedInputServerMethod4() + * Descr: + */ +void +BInputServerMethod::_ReservedInputServerMethod4() +{ +} + + diff --git a/src/servers/input/InputServerTypes.h b/src/servers/input/InputServerTypes.h new file mode 100644 index 0000000000..7d7b72b5b7 --- /dev/null +++ b/src/servers/input/InputServerTypes.h @@ -0,0 +1,25 @@ +#define SET_METHOD 'stmd' +#define GET_MOUSE_TYPE 'gtmt' +#define SET_MOUSE_TYPE 'stmt' +#define GET_MOUSE_ACCELERATION 'gtma' +#define SET_MOUSE_ACCELERATION 'stma' +#define GET_KEY_REPEAT_DELAY 'gkrd' +#define SET_KEY_REPEAT_DELAY 'skrd' +#define GET_KEY_INFO 'ktki' +#define GET_MODIFIERS 'gtmf' +#define SET_MODIFIER_KEY 'smky' +#define SET_KEYBOARD_LOCKS 'skbl' +#define GET_MOUSE_SPEED 'gtms' +#define SET_MOUSE_SPEED 'stms' +#define SET_MOUSE_POSITION 'stmp' +#define GET_MOUSE_MAP 'gtmm' +#define SET_MOUSE_MAP 'stmm' +#define GET_KEYBOARD_ID 'gkbi' +#define GET_CLICK_SPEED 'gtcs' +#define SET_CLICK_SPEED 'stcs' +#define GET_KEY_REPEAT_RATE 'gkrr' +#define SET_KEY_REPEAT_RATE 'skrr' +#define GET_KEY_MAP 'gtkm' +#define SET_KEY_MAP 'stkm' +#define FOCUS_IM_AWARE_VIEW 'fiav' +#define UNFOCUS_IM_AWARE_VIEW 'uiav' diff --git a/src/servers/media/AppManager.cpp b/src/servers/media/AppManager.cpp new file mode 100644 index 0000000000..6072427547 --- /dev/null +++ b/src/servers/media/AppManager.cpp @@ -0,0 +1,84 @@ +#include +#include +#include +#include +#include "AppManager.h" + +AppManager::AppManager() +{ +} + +AppManager::~AppManager() +{ +} + +bool AppManager::HasTeam(team_id team) +{ + BAutolock lock(mLocker); + ListItem *item; + for (int32 i = 0; (item = (ListItem *)mList.ItemAt(i)) != NULL; i++) + if (item->team == team) + return true; + return false; +} + +status_t AppManager::RegisterTeam(team_id team, BMessenger messenger) +{ + printf("AppManager::RegisterTeam %d\n",(int) team); + + BAutolock lock(mLocker); + ListItem *item; + + if (HasTeam(team)) + return B_ERROR; + + item = new ListItem; + item->team = team; + item->messenger = messenger; + + return mList.AddItem(item) ? B_OK : B_ERROR; +} + +status_t AppManager::UnregisterTeam(team_id team) +{ + printf("AppManager::UnregisterTeam %d\n",(int) team); + + BAutolock lock(mLocker); + ListItem *item; + for (int32 i = 0; (item = (ListItem *)mList.ItemAt(i)) != NULL; i++) + if (item->team == team) { + if (mList.RemoveItem(item)) { + delete item; + return B_OK; + } else { + break; + } + } + return B_ERROR; +} + +void AppManager::BroadcastMessage(BMessage *msg, bigtime_t timeout) +{ + BAutolock lock(mLocker); + ListItem *item; + for (int32 i = 0; (item = (ListItem *)mList.ItemAt(i)) != NULL; i++) + if (B_OK != item->messenger.SendMessage(msg,(BHandler *)NULL,timeout)) + HandleBroadcastError(msg, item->messenger, item->team, timeout); +} + +void AppManager::HandleBroadcastError(BMessage *msg, BMessenger &, team_id team, bigtime_t timeout) +{ + BAutolock lock(mLocker); + printf("error broadcasting team %d with message after %.3f seconds\n",int(team),timeout / 1000000.0); + msg->PrintToStream(); +} + +status_t AppManager::LoadState() +{ + return B_ERROR; +} + +status_t AppManager::SaveState() +{ + return B_ERROR; +} diff --git a/src/servers/media/AppManager.h b/src/servers/media/AppManager.h new file mode 100644 index 0000000000..9d3d3aebe5 --- /dev/null +++ b/src/servers/media/AppManager.h @@ -0,0 +1,24 @@ + +#include +#include + +class AppManager +{ +public: + AppManager(); + ~AppManager(); + bool HasTeam(team_id); + status_t RegisterTeam(team_id, BMessenger); + status_t UnregisterTeam(team_id); + void BroadcastMessage(BMessage *msg, bigtime_t timeout); + void HandleBroadcastError(BMessage *, BMessenger &, team_id team, bigtime_t timeout); + status_t LoadState(); + status_t SaveState(); +private: + struct ListItem { + team_id team; + BMessenger messenger; + }; + BList mList; + BLocker mLocker; +}; diff --git a/src/servers/media/BufferManager.cpp b/src/servers/media/BufferManager.cpp new file mode 100644 index 0000000000..ab4e965533 --- /dev/null +++ b/src/servers/media/BufferManager.cpp @@ -0,0 +1,149 @@ +#include +#include +#include "BufferManager.h" +#include "../lib/headers/SharedBufferList.h" +#include "debug.h" + +BufferManager::BufferManager() +{ + fSharedBufferList = _shared_buffer_list::Clone(); + fAreaId = area_for(fSharedBufferList); + fBufferList = NULL; + fLocker = new BLocker("buffer manager locker"); + fNextBufferId = 1; +} + +BufferManager::~BufferManager() +{ + fSharedBufferList->Unmap(); + delete fLocker; +} + +area_id +BufferManager::SharedBufferListID() +{ + return fAreaId; +} + +status_t +BufferManager::RegisterBuffer(team_id teamid, media_buffer_id bufferid, + size_t *size, int32 *flags, size_t *offset, area_id *area) +{ + BAutolock lock(fLocker); + TRACE("RegisterBuffer team = 0x%08x, bufferid = 0x%08x\n",(int)teamid,(int)bufferid); + + _buffer_list *list; + _team_list *team; + + for (list = fBufferList; list; list = list->next) + if (list->id == bufferid) { + team = new _team_list; + team->team = teamid; + team->next = list->teams; + list->teams = team; + *area = list->area; + *offset = list->offset; + *size = list->size, + *flags = list->flags; + PrintToStream(); + return B_OK; + } + + TRACE("failed to register buffer! team = 0x%08x, bufferid = 0x%08x\n",(int)teamid,(int)bufferid); + PrintToStream(); + return B_ERROR; +} + +status_t +BufferManager::RegisterBuffer(team_id teamid, size_t size, int32 flags, size_t offset, area_id area, + media_buffer_id *bufferid) +{ + BAutolock lock(fLocker); + TRACE("RegisterBuffer team = 0x%08x, areaid = 0x%08x, offset = 0x%08x, size = 0x%08x\n",(int)teamid,(int)area,(int)offset,(int)size); + + void *adr; + area_id newarea; + + newarea = clone_area("media_server buffer",&adr,B_ANY_ADDRESS,B_READ_AREA | B_WRITE_AREA,area); + if (newarea <= B_OK) { + TRACE("failed to clone buffer! team = 0x%08x, areaid = 0x%08x, offset = 0x%08x, size = 0x%08x\n",(int)teamid,(int)area,(int)offset,(int)size); + return B_ERROR; + } + + *bufferid = fNextBufferId; + + _buffer_list *list; + list = new _buffer_list; + list->next = fBufferList; + list->id = fNextBufferId; + list->area = newarea; + list->offset = offset; + list->size = size; + list->flags = flags; + list->teams = new _team_list; + list->teams->next = NULL; + list->teams->team = teamid; + fBufferList = list; + + fNextBufferId++; + + PrintToStream(); + return B_OK; +} + +status_t +BufferManager::UnregisterBuffer(team_id teamid, media_buffer_id bufferid) +{ + BAutolock lock(fLocker); + TRACE("UnregisterBuffer team = 0x%08x bufferid = 0x%08x\n",(int)teamid,(int)bufferid); + + _buffer_list **nextlist; + _team_list **nextteam; + + for (nextlist = &fBufferList; (*nextlist); nextlist = &((*nextlist)->next)) { + if ((*nextlist)->id == bufferid) { + for (nextteam = &((*nextlist)->teams); (*nextteam); nextteam = &((*nextteam)->next)) { + if ((*nextteam)->team == teamid) { + _team_list *temp; + temp = *nextteam; + *nextteam = (*nextteam)->next; + delete temp; + TRACE("team = 0x%08x removed from bufferid = 0x%08x\n",(int)teamid,(int)bufferid); + PrintToStream(); + break; + } + } + if ((*nextlist)->teams == NULL) { + _buffer_list *temp; + temp = *nextlist; + *nextlist = (*nextlist)->next; + delete_area(temp->area); + delete temp; + TRACE("bufferid = 0x%08x removed\n",(int)bufferid); + PrintToStream(); + } + return B_OK; + } + } + PrintToStream(); + TRACE("failed to unregister buffer! team = 0x%08x, bufferid = 0x%08x\n",(int)teamid,(int)bufferid); + return B_ERROR; +} + +void +BufferManager::PrintToStream() +{ + return; + BAutolock lock(fLocker); + _buffer_list *list; + _team_list *team; + + printf("Buffer list:\n"); + for (list = fBufferList; list; list = list->next) { + printf(" bufferid = 0x%08x, areaid = 0x%08x, offset = 0x%08x, size = 0x%08x, flags = 0x%08x, next = 0x%08x\n", + (int)list->id,(int)list->area,(int)list->offset,(int)list->size,(int)list->flags,(int)list->next); + for (team = list->teams; team; team = team->next) + printf(" team = 0x%08x, next = 0x%08x =>",(int)team->team,(int)team->next); + printf("\n"); + } +} diff --git a/src/servers/media/BufferManager.h b/src/servers/media/BufferManager.h new file mode 100644 index 0000000000..1351eb84fa --- /dev/null +++ b/src/servers/media/BufferManager.h @@ -0,0 +1,43 @@ +struct _shared_buffer_list; + +class BufferManager +{ +public: + BufferManager(); + ~BufferManager(); + + area_id SharedBufferListID(); + + status_t RegisterBuffer(team_id teamid, media_buffer_id bufferid, + size_t *size, int32 *flags, size_t *offset, area_id *area); + + status_t RegisterBuffer(team_id teamid, size_t size, int32 flags, size_t offset, area_id area, + media_buffer_id *bufferid); + + status_t UnregisterBuffer(team_id teamid, media_buffer_id bufferid); + + void PrintToStream(); + +private: + struct _team_list + { + struct _team_list *next; + team_id team; + }; + struct _buffer_list + { + struct _buffer_list *next; + media_buffer_id id; + area_id area; + size_t offset; + size_t size; + int32 flags; + _team_list *teams; + }; + _shared_buffer_list * fSharedBufferList; + area_id fAreaId; + _buffer_list * fBufferList; + BLocker * fLocker; + media_buffer_id fNextBufferId; +}; + diff --git a/src/servers/media/NodeManager.cpp b/src/servers/media/NodeManager.cpp new file mode 100644 index 0000000000..b047f8bb7c --- /dev/null +++ b/src/servers/media/NodeManager.cpp @@ -0,0 +1,119 @@ +#include +#include +#include +#include +#include +#include "NodeManager.h" + +// XXX locking is missing + +NodeManager::NodeManager() : + nextaddonid(1) +{ + fDormantFlavorList = new List; +} + +NodeManager::~NodeManager() +{ + delete fDormantFlavorList; +} + +void +NodeManager::RegisterAddon(media_addon_id *newid) +{ + *newid = nextaddonid++; +} + +void +NodeManager::UnregisterAddon(media_addon_id id) +{ + RemoveDormantFlavorInfo(id); + // unload the image once it's no longer used (refcounting!) +} + +void +NodeManager::AddDormantFlavorInfo(const dormant_flavor_info &dfi) +{ + fDormantFlavorList->Insert(dfi); +} + +void +NodeManager::RemoveDormantFlavorInfo(media_addon_id id) +{ +} + +status_t +NodeManager::GetDormantNodes(dormant_node_info * out_info, + int32 * io_count, + const media_format * has_input /* = NULL */, + const media_format * has_output /* = NULL */, + const char * name /* = NULL */, + uint64 require_kinds /* = NULL */, + uint64 deny_kinds /* = NULL */) +{ + int32 maxcount; + int32 index; + dormant_flavor_info dfi; + int namelen; + + // determine the count of byte to compare when checking for a name with(out) wildcard + if (name) { + namelen = strlen(name); + if (name[namelen] == '*') + namelen--; // compares without the '*' + else + namelen++; // also compares the terminating NULL + } else + namelen = 0; + + maxcount = *io_count; + *io_count = 0; + for (index = 0; (*io_count < maxcount) && fDormantFlavorList->GetAt(index, &dfi); index++) { + if ((dfi.kinds & require_kinds) != require_kinds) + continue; + if ((dfi.kinds & deny_kinds) != 0) + continue; + if (namelen) { + if (0 != memcmp(name, dfi.name, namelen)) + continue; + } + if (has_input) { + bool hasit = false; + for (int32 i = 0; i < dfi.in_format_count; i++) + if (format_is_compatible(*has_input, dfi.in_formats[i])) { + hasit = true; + break; + } + if (!hasit) + continue; + } + if (has_output) { + bool hasit = false; + for (int32 i = 0; i < dfi.out_format_count; i++) + if (format_is_compatible(*has_output, dfi.out_formats[i])) { + hasit = true; + break; + } + if (!hasit) + continue; + } + + out_info[*io_count] = dfi.node_info; + *io_count += 1; + } + + return B_OK; +} + +status_t +NodeManager::GetDormantFlavorInfoFor(media_addon_id addon, + int32 flavor_id, + dormant_flavor_info *outFlavor) +{ + for (int32 index = 0; fDormantFlavorList->GetAt(index, outFlavor); index++) { + if (outFlavor->node_info.addon == addon && outFlavor->node_info.flavor_id == flavor_id) + return B_OK; + } + return B_ERROR; +} + diff --git a/src/servers/media/NodeManager.h b/src/servers/media/NodeManager.h new file mode 100644 index 0000000000..41c30364a8 --- /dev/null +++ b/src/servers/media/NodeManager.h @@ -0,0 +1,48 @@ +#include "TList.h" + +class BufferManager; + +class NodeManager +{ +public: + NodeManager(); + ~NodeManager(); + status_t RegisterNode(BMessenger, media_node &, char const *, long *, char const *, long, char const *, long, media_type, media_type); + status_t UnregisterNode(long); + status_t GetNodes(BMessage &, char const *); + status_t GetLiveNode(BMessage &, char const *, long); + status_t GetLiveNodes(BMessage &, char const *, media_format const *, media_format const *, char const *, unsigned long); + status_t FindNode(long, media_node &); + status_t FindSaveInfo(long, char const **, long *, long *, char const **); + status_t FindDormantNodeFor(long, dormant_node_info *); + status_t FindNodesFor(long, long, BMessage &, char const *); + status_t FindNodesForPort(long, BMessage &, char const *); + status_t UnregisterTeamNodes(long, BMessage &, char const *, long *, BufferManager *); + status_t IncrementGlobalRefCount(long); + status_t DumpGlobalReferences(BMessage &, char const *); + status_t DecrementGlobalRefCount(long, BMessage *); + status_t BroadcastMessage(long, void *, long, long long); + status_t LoadState(); + status_t SaveState(); + + void AddDormantFlavorInfo(const dormant_flavor_info &dfi); + void RemoveDormantFlavorInfo(media_addon_id id); + void RegisterAddon(media_addon_id *newid); + void UnregisterAddon(media_addon_id id); + status_t GetDormantNodes(dormant_node_info * out_info, + int32 * io_count, + const media_format * has_input /* = NULL */, + const media_format * has_output /* = NULL */, + const char * name /* = NULL */, + uint64 require_kinds /* = NULL */, + uint64 deny_kinds /* = NULL */); + + status_t GetDormantFlavorInfoFor(media_addon_id addon, + int32 flavor_id, + dormant_flavor_info *outFlavor); + +private: + media_addon_id nextaddonid; + + List *fDormantFlavorList; +}; diff --git a/src/servers/media/ServerInterface.h b/src/servers/media/ServerInterface.h new file mode 100644 index 0000000000..19b454c903 --- /dev/null +++ b/src/servers/media/ServerInterface.h @@ -0,0 +1,559 @@ +#ifndef _SERVER_INTERFACE_H_ +#define _SERVER_INTERFACE_H_ + +#include +#include +#include + +#define NEW_MEDIA_SERVER_SIGNATURE "application/x-vnd.OpenBeOS-media-server" + +enum { + // Application management + MEDIA_SERVER_REGISTER_APP, + MEDIA_SERVER_UNREGISTER_APP, + + // Buffer management + MEDIA_SERVER_GET_SHARED_BUFFER_AREA, + MEDIA_SERVER_REGISTER_BUFFER, + MEDIA_SERVER_UNREGISTER_BUFFER, + + // Something else + MEDIA_SERVER_SET_VOLUME, + MEDIA_SERVER_GET_VOLUME, + MEDIA_SERVER_GET_NODE_ID, + MEDIA_SERVER_FIND_RUNNING_INSTANCES, + MEDIA_SERVER_BUFFER_GROUP_REG, + MEDIA_SERVER_GET_LATENT_INFO, + MEDIA_SERVER_GET_DORMANT_FILE_FORMATS, + MEDIA_SERVER_GET_GETDORMANTFLAVOR, + MEDIA_SERVER_BROADCAST_MESSAGE, + MEDIA_SERVER_RELEASE_NODE_REFERENCE, + MEDIA_SERVER_SET_REALTIME_FLAGS, + MEDIA_SERVER_GET_REALTIME_FLAGS, + MEDIA_SERVER_INSTANTIATE_PERSISTENT_NODE, + MEDIA_SERVER_SNIFF_FILE, + MEDIA_SERVER_QUERY_LATENTS, + MEDIA_SERVER_REGISTER_NODE, + MEDIA_SERVER_UNREGISTER_NODE, + MEDIA_SERVER_SET_DEFAULT, + MEDIA_SERVER_ACQUIRE_NODE_REFERENCE, + MEDIA_SERVER_REQUEST_NOTIFICATIONS, + MEDIA_SERVER_CANCEL_NOTIFICATIONS, + MEDIA_SERVER_SET_OUTPUT_BUFFERS, + MEDIA_SERVER_RECLAIM_OUTPUT_BUFFERS, + MEDIA_SERVER_ORPHAN_RECLAIMABLE_BUFFERS, + MEDIA_SERVER_SET_TIME_SOURCE, + MEDIA_SERVER_QUERY_NODES, + MEDIA_SERVER_GET_DORMANT_NODE, + MEDIA_SERVER_FORMAT_CHANGED, + MEDIA_SERVER_GET_DEFAULT_INFO, + MEDIA_SERVER_GET_RUNNING_DEFAULT, + MEDIA_SERVER_SET_RUNNING_DEFAULT, + MEDIA_SERVER_TYPE_ITEM_OP, + MEDIA_SERVER_FORMAT_OP +}; + +enum { + NODE_START, + NODE_STOP, + NODE_SEEK, + NODE_SET_RUN_MODE, + NODE_TIME_WARP, + NODE_PREROLL, + NODE_REGISTERED, + NODE_SET_TIMESOURCE, + NODE_REQUEST_COMPLETED, + CONSUMER_ACCEPT_FORMAT, + CONSUMER_GET_NEXT_INPUT, + CONSUMER_DISPOSE_INPUT_COOKIE, + CONSUMER_BUFFER_RECEIVED, + CONSUMER_PRODUCER_DATA_STATUS, + CONSUMER_GET_LATENCY_FOR, + CONSUMER_CONNECTED, + CONSUMER_DISCONNECTED, + CONSUMER_FORMAT_CHANGED, + CONSUMER_SEEK_TAG_REQUESTED, + PRODUCER_LATE_NOTICE_RECEIVED, + PRODUCER_ENABLE_OUTPUT, + PRODUCER_LATENCY_CHANGED, + PRODUCER_ADDITIONAL_BUFFER_REQUESTED, + PRODUCER_VIDEO_CLIPPING_CHANGED, + PRODUCER_FORMAT_CHANGE_REQUESTED, + PRODUCER_SET_BUFFER_GROUP, + PRODUCER_GET_LATENCY, + PRODUCER_GET_NEXT_OUTPUT, + PRODUCER_DISPOSE_OUTPUT_COOKIE, + PRODUCER_GET_INITIAL_LATENCY, + PRODUCER_FORMAT_SUGGESTION_REQUESTED, + PRODUCER_FORMAT_PROPOSAL, + PRODUCER_PREPARE_TO_CONNECT, + PRODUCER_CONNECT, + PRODUCER_DISCONNECT, + PRODUCER_SET_PLAY_RATE, + ADDONSERVER_INSTANTIATE_DORMANT_NODE, + SERVER_REGISTER_MEDIAADDON, + SERVER_UNREGISTER_MEDIAADDON, + ADDONSERVER_RESCAN_MEDIAADDON_FLAVORS, + SERVER_REGISTER_DORMANT_NODE, + SERVER_GET_NODE, + SERVER_SET_NODE, + TIMESOURCE_OP, // datablock is a struct time_source_op_info + SERVER_GET_DORMANT_NODES, + SERVER_GET_DORMANT_FLAVOR_INFO, + END +}; + +enum node_type +{ + VIDEO_INPUT, + AUDIO_INPUT, + VIDEO_OUTPUT, + AUDIO_MIXER, + AUDIO_OUTPUT, + AUDIO_OUTPUT_EX, + TIME_SOURCE, + SYSTEM_TIME_SOURCE +}; + +struct xfer_server_get_dormant_flavor_info +{ + media_addon_id addon; + int32 flavor_id; + port_id reply_port; +}; + +struct xfer_server_get_dormant_flavor_info_reply +{ + status_t result; + type_code dfi_type; // the flatten type_code + size_t dfi_size; + char dfi[1]; // a flattened dormant_flavor_info, dfi_size large +}; + +struct xfer_server_get_dormant_nodes +{ + int32 maxcount; + bool has_input; + media_format inputformat; + bool has_output; + media_format outputformat; + bool has_name; + char name[B_MEDIA_NAME_LENGTH + 1]; // 1 for a trailing "*" + uint64 require_kinds; + uint64 deny_kinds; + port_id reply_port; +}; + +struct xfer_server_get_dormant_nodes_reply +{ + status_t result; + int32 count; // if count > 0, a second reply containing count dormant_node_infos is send +}; + +struct xfer_server_set_node +{ + node_type type; + bool use_node; + media_node node; + bool use_dni; + dormant_node_info dni; + bool use_input; + media_input input; + port_id reply_port; +}; + +struct xfer_server_set_node_reply +{ + status_t result; +}; + +struct xfer_server_get_node +{ + node_type type; + port_id reply_port; +}; + +struct xfer_server_get_node_reply +{ + media_node node; + status_t result; + + // for AUDIO_OUTPUT_EX + char input_name[B_MEDIA_NAME_LENGTH]; + int32 input_id; +}; + +struct xfer_server_register_dormant_node +{ + media_addon_id purge_id; // if > 0, server must first remove all dormant_flavor_infos belonging to that id + type_code dfi_type; // the flatten type_code + size_t dfi_size; + char dfi[1]; // a flattened dormant_flavor_info, dfi_size large +}; + +struct xfer_addonserver_rescan_mediaaddon_flavors +{ + media_addon_id addonid; +}; + +struct xfer_server_register_mediaaddon +{ + port_id reply_port; +}; + +struct xfer_server_register_mediaaddon_reply +{ + media_addon_id addonid; +}; + +struct xfer_server_unregister_mediaaddon +{ + media_addon_id addonid; +}; + +struct xfer_producer_format_suggestion_requested +{ + media_type type; + int32 quality; + port_id reply_port; +}; + +struct xfer_producer_format_suggestion_requested_reply +{ + media_format format; + status_t result; +}; + +struct xfer_producer_format_proposal +{ + media_source output; + media_format format; + port_id reply_port; +}; + +struct xfer_producer_format_proposal_reply +{ + status_t result; +}; + +struct xfer_producer_prepare_to_connect +{ + media_source source; + media_destination destination; + media_format format; + port_id reply_port; +}; + +struct xfer_producer_prepare_to_connect_reply +{ + media_format format; + media_source out_source; + char name[B_MEDIA_NAME_LENGTH]; + status_t result; +}; + +struct xfer_producer_connect +{ + status_t error; + media_source source; + media_destination destination; + media_format format; + char name[B_MEDIA_NAME_LENGTH]; + port_id reply_port; +}; + +struct xfer_producer_connect_reply +{ + char name[B_MEDIA_NAME_LENGTH]; +}; + +struct xfer_producer_disconnect +{ + media_source source; + media_destination destination; +}; + +struct xfer_producer_set_play_rate +{ + int32 numer; + int32 denom; + port_id reply_port; +}; + +struct xfer_producer_set_play_rate_reply +{ + status_t result; +}; + +struct xfer_producer_get_initial_latency +{ + port_id reply_port; +}; + +struct xfer_producer_get_initial_latency_reply +{ + bigtime_t initial_latency; + uint32 flags; +}; + +struct xfer_producer_get_latency +{ + port_id reply_port; +}; + +struct xfer_producer_get_latency_reply +{ + bigtime_t latency; + status_t result; +}; + +struct xfer_producer_get_next_output +{ + int32 cookie; + port_id reply_port; +}; + +struct xfer_producer_get_next_output_reply +{ + int32 cookie; + media_output output; + status_t result; +}; + +struct xfer_producer_dispose_output_cookie +{ + int32 cookie; +}; + +struct xfer_producer_set_buffer_group +{ + media_source source; + media_destination destination; + void *user_data; + int32 change_tag; + int32 buffer_count; + media_buffer_id buffers[1]; +}; + +struct xfer_producer_format_change_requested +{ + media_source source; + media_destination destination; + media_format format; + void *user_data; + int32 change_tag; +}; + +struct xfer_producer_video_clipping_changed +{ + media_source source; + media_destination destination; + media_video_display_info display; + void *user_data; + int32 change_tag; + int32 short_count; + int16 shorts[1]; +}; + +struct xfer_producer_additional_buffer_requested +{ + media_source source; + media_buffer_id prev_buffer; + bigtime_t prev_time; + bool has_seek_tag; + media_seek_tag prev_tag; +}; + +struct xfer_producer_latency_changed +{ + media_source source; + media_destination destination; + bigtime_t latency; + uint32 flags; +}; + +struct xfer_node_request_completed +{ + media_request_info info; +}; + +struct xfer_producer_enable_output +{ + media_source source; + media_destination destination; + bool enabled; + void *user_data; + int32 change_tag; +}; + +struct xfer_producer_late_notice_received +{ + media_source source; + bigtime_t how_much; + bigtime_t performance_time; +}; + +struct xfer_node_start +{ + bigtime_t performance_time; +}; + +struct xfer_node_stop +{ + bigtime_t performance_time; + bool immediate; +}; + +struct xfer_node_seek +{ + bigtime_t media_time; + bigtime_t performance_time; +}; + +struct xfer_node_set_run_mode +{ + BMediaNode::run_mode mode; +}; + +struct xfer_node_time_warp +{ + bigtime_t at_real_time; + bigtime_t to_performance_time; +}; + +struct xfer_node_registered +{ + media_node_id node_id; +}; + +struct xfer_node_set_timesource +{ + media_node_id timesource_id; +}; + +struct xfer_consumer_accept_format +{ + media_destination dest; + media_format format; + port_id reply_port; +}; + +struct xfer_consumer_accept_format_reply +{ + media_format format; + status_t result; +}; + +struct xfer_consumer_get_next_input +{ + int32 cookie; + port_id reply_port; +}; + +struct xfer_consumer_get_next_input_reply +{ + int32 cookie; + media_input input; + status_t result; +}; + +struct xfer_consumer_dispose_input_cookie +{ + int32 cookie; +}; + +struct xfer_consumer_buffer_received +{ + media_buffer_id buffer; + media_header header; +}; + +struct xfer_consumer_producer_data_status +{ + media_destination for_whom; + int32 status; + bigtime_t at_performance_time; +}; + +struct xfer_consumer_get_latency_for +{ + media_destination for_whom; + port_id reply_port; +}; + +struct xfer_consumer_get_latency_for_reply +{ + bigtime_t latency; + media_node_id timesource; + status_t result; +}; + +struct xfer_consumer_connected +{ + media_source producer; + media_destination where; + media_format with_format; + port_id reply_port; +}; + +struct xfer_consumer_connected_reply +{ + media_input input; + status_t result; +}; + +struct xfer_consumer_disconnected +{ + media_source producer; + media_destination where; +}; + +struct xfer_consumer_format_changed +{ + media_source producer; + media_destination consumer; + int32 change_tag; + media_format format; + port_id reply_port; +}; + +struct xfer_consumer_format_changed_reply +{ + status_t result; +}; + +struct xfer_consumer_seek_tag_requested +{ + media_destination destination; + bigtime_t target_time; + uint32 flags; + port_id reply_port; +}; + +struct xfer_consumer_seek_tag_requested_reply +{ + media_seek_tag seek_tag; + bigtime_t tagged_time; + uint32 flags; + status_t result; +}; + +struct xfer_addonserver_instantiate_dormant_node +{ + dormant_node_info info; + port_id reply_port; +}; + +struct xfer_addonserver_instantiate_dormant_node_reply +{ + media_node node; + status_t result; +}; + +// implementation contained in libmedia.so (MediaRoster.cpp) +namespace MediaKitPrivate +{ + status_t QueryServer(BMessage *query, BMessage *reply); +}; + +#endif diff --git a/src/servers/media/debug.h b/src/servers/media/debug.h new file mode 100644 index 0000000000..3ee0453011 --- /dev/null +++ b/src/servers/media/debug.h @@ -0,0 +1,40 @@ + +#include + +#ifndef NDEBUG + + #ifndef DEBUG + #define DEBUG 2 + #endif + + #if DEBUG >= 1 + #define UNIMPLEMENTED() printf("UNIMPLEMENTED %s\n",__PRETTY_FUNCTION__) + #else + #define UNIMPLEMENTED() ((void)0) + #endif + + #if DEBUG >= 2 + #define BROKEN() printf("BROKEN %s\n",__PRETTY_FUNCTION__) + #else + #define BROKEN() ((void)0) + #endif + + #if DEBUG >= 3 + #define CALLED() printf("CALLED %s\n",__PRETTY_FUNCTION__) + #else + #define CALLED() ((void)0) + #endif + + #undef TRACE + #define TRACE \ + printf + +#else + + #define UNIMPLEMENTED() ((void)0) + #define BROKEN() ((void)0) + #define CALLED() ((void)0) + #define TRACE \ + if (1) {} else printf + +#endif diff --git a/src/servers/media/media_server.cpp b/src/servers/media/media_server.cpp new file mode 100644 index 0000000000..e3c5e54007 --- /dev/null +++ b/src/servers/media/media_server.cpp @@ -0,0 +1,652 @@ +#include +#include +#include +#include +#include +#include +#include "ServerInterface.h" +#include "BufferManager.h" +#include "NodeManager.h" +#include "AppManager.h" +#define DEBUG 1 +#include +#include "debug.h" + +/* + * + * An implementation of a new media_server for the OpenBeOS MediaKit + * Started by Marcus Overhagen on 2001-10-25 + * + * Communication with the OpenBeOS libmedia.so is done using BMessages + * sent to the server application, handled in XXX() + * functions. A simple BMessage reply is beeing send back. + * + * + * function names and class structure is loosely + * based on information acquired using: + * nm --demangle /boot/beos/system/servers/media_server | grep Server | sort + * nm --demangle /boot/beos/system/servers/media_server | grep Manager | sort + * + */ + + +#define REPLY_TIMEOUT ((bigtime_t)500000) + +class ServerApp : BApplication +{ +public: + ServerApp(); + ~ServerApp(); + + void HandleMessage(int32 code, void *data, size_t size); + static int32 controlthread(void *arg); + + void GetSharedBufferArea(BMessage *msg); + void RegisterBuffer(BMessage *msg); + void UnregisterBuffer(BMessage *msg); + + void GetNodeID(BMessage *); + void FindRunningInstances(BMessage *); + void BufferGroupReg(BMessage *); + void GetLatentInfo(BMessage *); + void GetDormantFileFormats(BMessage *); + void GetDormantFlavor(BMessage *); + void BroadcastMessage(BMessage *); + void ReleaseNodeReference(BMessage *); + void SetRealtimeFlags(BMessage *); + void GetRealtimeFlags(BMessage *); + void InstantiatePersistentNode(BMessage *); + void SniffFile(BMessage *); + void QueryLatents(BMessage *); + void RegisterApp(BMessage *); + void UnregisterApp(BMessage *); + void RegisterNode(BMessage *); + void UnregisterNode(BMessage *); + void SetDefault(BMessage *); + void AcquireNodeReference(BMessage *); + void RequestNotifications(BMessage *); + void CancelNotifications(BMessage *); + void SetOutputBuffers(BMessage *); + void ReclaimOutputBuffers(BMessage *); + void OrphanReclaimableBuffers(BMessage *); + void SetTimeSource(BMessage *); + void QueryNodes(BMessage *); + void GetDormantNode(BMessage *); + void FormatChanged(BMessage *); + void GetDefaultInfo(BMessage *); + void GetRunningDefault(BMessage *); + void SetRunningDefault(BMessage *); + void TypeItemOp(BMessage *); + void FormatOp(BMessage *); + + void SetVolume(BMessage *); + void GetVolume(BMessage *); + +/* functionality not yet implemented +00014a00 T _ServerApp::_ServerApp(void) +00014e1c T _ServerApp::~_ServerApp(void) +00014ff4 T _ServerApp::MessageReceived(BMessage *); +00015840 T _ServerApp::QuitRequested(void) +00015b50 T _ServerApp::_DoNotify(notify_data *) +00015d18 T _ServerApp::_UnregisterApp(long, bool) +00018e90 T _ServerApp::AddOnHost(void) +00019530 T _ServerApp::AboutRequested(void) +00019d04 T _ServerApp::AddPurgableBufferGroup(long, long, long, void *) +00019db8 T _ServerApp::CancelPurgableBufferGroupCleanup(long) +00019e50 T _ServerApp::DirtyWork(void) +0001a4bc T _ServerApp::ArgvReceived(long, char **) +0001a508 T _ServerApp::CleanupPurgedBufferGroup(_ServerApp::purgable_buffer_group const &, bool) +0001a5dc T _ServerApp::DirtyWorkLaunch(void *) +0001a634 T _ServerApp::SetQuitMode(bool) +0001a648 T _ServerApp::IsQuitMode(void) const +0001a658 T _ServerApp::BroadcastCurrentStateTo(BMessenger &) +0001adcc T _ServerApp::ReadyToRun(void) +*/ + +private: + port_id control_port; + thread_id control_thread; + + BufferManager *fBufferManager; + AppManager *fAppManager; + NodeManager *fNodeManager; + BLocker *fLocker; + + float fVolumeLeft; + float fVolumeRight; + + void MessageReceived(BMessage *msg); + typedef BApplication inherited; +}; + +ServerApp::ServerApp() + : BApplication(NEW_MEDIA_SERVER_SIGNATURE), + fBufferManager(new BufferManager), + fAppManager(new AppManager), + fNodeManager(new NodeManager), + fLocker(new BLocker("server locker")), + fVolumeLeft(0.0), + fVolumeRight(0.0) +{ + //load volume settings from config file + //mVolumeLeft = ???; + //mVolumeRight = ???; + control_port = create_port(64,"media_server port"); + control_thread = spawn_thread(controlthread,"media_server control",12,this); + resume_thread(control_thread); +} + +ServerApp::~ServerApp() +{ + delete fBufferManager; + delete fAppManager; + delete fNodeManager; + delete fLocker; + delete_port(control_port); + status_t err; + wait_for_thread(control_thread,&err); +} + +void +ServerApp::HandleMessage(int32 code, void *data, size_t size) +{ + status_t rv; + switch (code) { + case SERVER_GET_NODE: + { + xfer_server_get_node *msg = (xfer_server_get_node *)data; + xfer_server_get_node_reply reply; + reply.result = B_ERROR; + write_port(msg->reply_port, 0, &reply, sizeof(reply)); + break; + } + + case SERVER_SET_NODE: + { + xfer_server_set_node *msg = (xfer_server_set_node *)data; + xfer_server_set_node_reply reply; + reply.result = B_ERROR; + write_port(msg->reply_port, 0, &reply, sizeof(reply)); + break; + } + + case SERVER_REGISTER_MEDIAADDON: + { + xfer_server_register_mediaaddon *msg = (xfer_server_register_mediaaddon *)data; + xfer_server_register_mediaaddon_reply reply; + fNodeManager->RegisterAddon(&reply.addonid); + write_port(msg->reply_port, 0, &reply, sizeof(reply)); + break; + } + + case SERVER_UNREGISTER_MEDIAADDON: + { + xfer_server_unregister_mediaaddon *msg = (xfer_server_unregister_mediaaddon *)data; + fNodeManager->UnregisterAddon(msg->addonid); + break; + } + + case SERVER_REGISTER_DORMANT_NODE: + { + xfer_server_register_dormant_node *msg = (xfer_server_register_dormant_node *)data; + dormant_flavor_info dfi; + if (msg->purge_id > 0) + fNodeManager->RemoveDormantFlavorInfo(msg->purge_id); + rv = dfi.Unflatten(msg->dfi_type, &(msg->dfi), msg->dfi_size); + ASSERT(rv == B_OK); + fNodeManager->AddDormantFlavorInfo(dfi); + break; + } + + case SERVER_GET_DORMANT_NODES: + { + xfer_server_get_dormant_nodes *msg = (xfer_server_get_dormant_nodes *)data; + xfer_server_get_dormant_nodes_reply reply; + dormant_node_info * infos = new dormant_node_info[msg->maxcount]; + reply.count = msg->maxcount; + reply.result = fNodeManager->GetDormantNodes( + infos, + &reply.count, + msg->has_input ? &msg->inputformat : NULL, + msg->has_output ? &msg->outputformat : NULL, + msg->has_name ? msg->name : NULL, + msg->require_kinds, + msg->deny_kinds); + if (reply.result != B_OK) + reply.count = 0; + write_port(msg->reply_port, 0, &reply, sizeof(reply)); + if (reply.count > 0) + write_port(msg->reply_port, 0, infos, reply.count * sizeof(dormant_node_info)); + delete [] infos; + break; + } + + case SERVER_GET_DORMANT_FLAVOR_INFO: + { + xfer_server_get_dormant_flavor_info *msg = (xfer_server_get_dormant_flavor_info *)data; + dormant_flavor_info dfi; + status_t rv; + + rv = fNodeManager->GetDormantFlavorInfoFor(msg->addon, msg->flavor_id, &dfi); + if (rv != B_OK) { + xfer_server_get_dormant_flavor_info_reply reply; + reply.result = rv; + write_port(msg->reply_port, 0, &reply, sizeof(reply)); + } else { + xfer_server_get_dormant_flavor_info_reply *reply; + int replysize; + replysize = sizeof(xfer_server_get_dormant_flavor_info_reply) + dfi.FlattenedSize(); + reply = (xfer_server_get_dormant_flavor_info_reply *)malloc(replysize); + + reply->dfi_size = dfi.FlattenedSize(); + reply->dfi_type = dfi.TypeCode(); + reply->result = dfi.Flatten(reply->dfi, reply->dfi_size); + write_port(msg->reply_port, 0, reply, replysize); + free(reply); + } + break; + } + + default: + printf("media_server: received unknown message code %#08lx\n",code); + } +} + +int32 +ServerApp::controlthread(void *arg) +{ + char data[B_MEDIA_MESSAGE_SIZE]; + ServerApp *app; + ssize_t size; + int32 code; + + app = (ServerApp *)arg; + while ((size = read_port_etc(app->control_port, &code, data, sizeof(data), 0, 0)) > 0) + app->HandleMessage(code, data, size); + + return 0; +} + +void +ServerApp::GetSharedBufferArea(BMessage *msg) +{ + BMessage reply(B_OK); + reply.AddInt32("area",fBufferManager->SharedBufferListID()); + msg->SendReply(&reply,(BHandler*)NULL,REPLY_TIMEOUT); +} + +void +ServerApp::RegisterBuffer(BMessage *msg) +{ + team_id teamid; + media_buffer_id bufferid; + size_t size; + int32 flags; + size_t offset; + area_id area; + status_t status; + + //msg->PrintToStream(); + + teamid = msg->FindInt32("team"); + area = msg->FindInt32("area"); + offset = msg->FindInt32("offset"); + size = msg->FindInt32("size"); + flags = msg->FindInt32("flags"); + bufferid = msg->FindInt32("buffer"); + + //TRACE("ServerApp::RegisterBuffer team = 0x%08x, areaid = 0x%08x, offset = 0x%08x, size = 0x%08x, flags = 0x%08x, buffer = 0x%08x\n",(int)teamid,(int)area,(int)offset,(int)size,(int)flags,(int)bufferid); + + if (bufferid == 0) + status = fBufferManager->RegisterBuffer(teamid, size, flags, offset, area, &bufferid); + else + status = fBufferManager->RegisterBuffer(teamid, bufferid, &size, &flags, &offset, &area); + + BMessage reply(status); + reply.AddInt32("buffer",bufferid); + reply.AddInt32("size",size); + reply.AddInt32("flags",flags); + reply.AddInt32("offset",offset); + reply.AddInt32("area",area); + + msg->SendReply(&reply,(BHandler*)NULL,REPLY_TIMEOUT); +} + +void +ServerApp::UnregisterBuffer(BMessage *msg) +{ + team_id teamid; + media_buffer_id bufferid; + status_t status; + + teamid = msg->FindInt32("team"); + bufferid = msg->FindInt32("buffer"); + + status = fBufferManager->UnregisterBuffer(teamid, bufferid); + + BMessage reply(status); + msg->SendReply(&reply,(BHandler*)NULL,REPLY_TIMEOUT); +} + + +void ServerApp::GetNodeID(BMessage *msg) +{ +} + + +void ServerApp::FindRunningInstances(BMessage *msg) +{ +} + + +void ServerApp::BufferGroupReg(BMessage *msg) +{ +} + + +void ServerApp::GetLatentInfo(BMessage *msg) +{ +} + + +void ServerApp::GetDormantFileFormats(BMessage *msg) +{ +} + + +void ServerApp::GetDormantFlavor(BMessage *msg) +{ +} + + +void ServerApp::BroadcastMessage(BMessage *msg) +{ +} + + +void ServerApp::ReleaseNodeReference(BMessage *msg) +{ +} + + +void ServerApp::SetRealtimeFlags(BMessage *msg) +{ +} + + +void ServerApp::GetRealtimeFlags(BMessage *msg) +{ +} + + +void ServerApp::InstantiatePersistentNode(BMessage *msg) +{ +} + + +void ServerApp::SniffFile(BMessage *msg) +{ +} + + +void ServerApp::QueryLatents(BMessage *msg) +{ +} + + +void ServerApp::RegisterApp(BMessage *msg) +{ + team_id team; + msg->FindInt32("team", &team); + fAppManager->RegisterTeam(team, msg->ReturnAddress()); + + BMessage reply(B_OK); + msg->SendReply(&reply,(BHandler*)NULL,REPLY_TIMEOUT); +} + + +void ServerApp::UnregisterApp(BMessage *msg) +{ + team_id team; + msg->FindInt32("team", &team); + fAppManager->UnregisterTeam(team); + + BMessage reply(B_OK); + msg->SendReply(&reply,(BHandler*)NULL,REPLY_TIMEOUT); +} + + +void ServerApp::RegisterNode(BMessage *msg) +{ +} + + +void ServerApp::UnregisterNode(BMessage *msg) +{ +} + + +void ServerApp::SetDefault(BMessage *msg) +{ +} + + +void ServerApp::AcquireNodeReference(BMessage *msg) +{ +} + + +void ServerApp::RequestNotifications(BMessage *msg) +{ +} + + +void ServerApp::CancelNotifications(BMessage *msg) +{ +} + + +void ServerApp::SetOutputBuffers(BMessage *msg) +{ +} + + +void ServerApp::ReclaimOutputBuffers(BMessage *msg) +{ +} + + +void ServerApp::OrphanReclaimableBuffers(BMessage *msg) +{ +} + + +void ServerApp::SetTimeSource(BMessage *msg) +{ +} + + +void ServerApp::QueryNodes(BMessage *msg) +{ +} + + +void ServerApp::GetDormantNode(BMessage *msg) +{ +} + + +void ServerApp::FormatChanged(BMessage *msg) +{ +} + + +void ServerApp::GetDefaultInfo(BMessage *msg) +{ +} + + +void ServerApp::GetRunningDefault(BMessage *msg) +{ +} + + +void ServerApp::SetRunningDefault(BMessage *msg) +{ +} + + +void ServerApp::TypeItemOp(BMessage *msg) +{ +} + + +void ServerApp::FormatOp(BMessage *msg) +{ +} + +void ServerApp::SetVolume(BMessage *msg) +{ + float left; + float right; + msg->FindFloat("left", &left); + msg->FindFloat("right", &right); + + fLocker->Lock(); + fVolumeLeft = left; + fVolumeRight = right; + fLocker->Unlock(); + + //save volume settings to config file + // ??? = left; + // ??? = right; + + BMessage reply(B_OK); + msg->SendReply(&reply,(BHandler*)NULL,REPLY_TIMEOUT); +} + +void ServerApp::GetVolume(BMessage *msg) +{ + BMessage reply(B_OK); + + fLocker->Lock(); + reply.AddFloat("left", fVolumeLeft); + reply.AddFloat("right", fVolumeRight); + fLocker->Unlock(); + + msg->SendReply(&reply,(BHandler*)NULL,REPLY_TIMEOUT); +} + + +void ServerApp::MessageReceived(BMessage *msg) +{ + switch (msg->what) { + case MEDIA_SERVER_GET_SHARED_BUFFER_AREA: GetSharedBufferArea(msg); break; + case MEDIA_SERVER_REGISTER_BUFFER: RegisterBuffer(msg); break; + case MEDIA_SERVER_UNREGISTER_BUFFER: UnregisterBuffer(msg); break; + + + case MEDIA_SERVER_GET_NODE_ID: GetNodeID(msg); break; + case MEDIA_SERVER_FIND_RUNNING_INSTANCES: FindRunningInstances(msg); break; + case MEDIA_SERVER_BUFFER_GROUP_REG: BufferGroupReg(msg); break; + case MEDIA_SERVER_GET_LATENT_INFO: GetLatentInfo(msg); break; + case MEDIA_SERVER_GET_DORMANT_FILE_FORMATS: GetDormantFileFormats(msg); break; + case MEDIA_SERVER_GET_GETDORMANTFLAVOR: GetDormantFlavor(msg); break; + case MEDIA_SERVER_BROADCAST_MESSAGE: BroadcastMessage(msg); break; + case MEDIA_SERVER_RELEASE_NODE_REFERENCE: ReleaseNodeReference(msg); break; + case MEDIA_SERVER_SET_REALTIME_FLAGS: SetRealtimeFlags(msg); break; + case MEDIA_SERVER_GET_REALTIME_FLAGS: GetRealtimeFlags(msg); break; + case MEDIA_SERVER_INSTANTIATE_PERSISTENT_NODE: InstantiatePersistentNode(msg); break; + case MEDIA_SERVER_SNIFF_FILE: SniffFile(msg); break; + case MEDIA_SERVER_QUERY_LATENTS: QueryLatents(msg); break; + case MEDIA_SERVER_REGISTER_APP: RegisterApp(msg); break; + case MEDIA_SERVER_UNREGISTER_APP: UnregisterApp(msg); break; + case MEDIA_SERVER_REGISTER_NODE: RegisterNode(msg); break; + case MEDIA_SERVER_UNREGISTER_NODE: UnregisterNode(msg); break; + case MEDIA_SERVER_SET_DEFAULT: SetDefault(msg); break; + case MEDIA_SERVER_ACQUIRE_NODE_REFERENCE: AcquireNodeReference(msg); break; + case MEDIA_SERVER_REQUEST_NOTIFICATIONS: RequestNotifications(msg); break; + case MEDIA_SERVER_CANCEL_NOTIFICATIONS: CancelNotifications(msg); break; + case MEDIA_SERVER_SET_OUTPUT_BUFFERS: SetOutputBuffers(msg); break; + case MEDIA_SERVER_RECLAIM_OUTPUT_BUFFERS: ReclaimOutputBuffers(msg); break; + case MEDIA_SERVER_ORPHAN_RECLAIMABLE_BUFFERS: OrphanReclaimableBuffers(msg); break; + case MEDIA_SERVER_SET_TIME_SOURCE: SetTimeSource(msg); break; + case MEDIA_SERVER_QUERY_NODES: QueryNodes(msg); break; + case MEDIA_SERVER_GET_DORMANT_NODE: GetDormantNode(msg); break; + case MEDIA_SERVER_FORMAT_CHANGED: FormatChanged(msg); break; + case MEDIA_SERVER_GET_DEFAULT_INFO: GetDefaultInfo(msg); break; + case MEDIA_SERVER_GET_RUNNING_DEFAULT: GetRunningDefault(msg); break; + case MEDIA_SERVER_SET_RUNNING_DEFAULT: SetRunningDefault(msg); break; + case MEDIA_SERVER_TYPE_ITEM_OP: TypeItemOp(msg); break; + case MEDIA_SERVER_FORMAT_OP: FormatOp(msg); break; + case MEDIA_SERVER_SET_VOLUME: SetVolume(msg); break; + case MEDIA_SERVER_GET_VOLUME: GetVolume(msg); break; + default: + printf("\nnew media server: unknown message received\n"); + msg->PrintToStream(); + } +} + +int main() +{ + new ServerApp; + be_app->Run(); + delete be_app; + return 0; +} + + +/* +0001e260 T MBufferManager::MBufferManager(void) +0001e47c T MBufferManager::~MBufferManager(void) +0001e540 T MBufferManager::PrintToStream(void) +0001e6fc T MBufferManager::RecycleBuffersWithOwner(long, long) +0001ea00 T MBufferManager::RegisterBuffer(long, buffer_clone_info const *, long *, media_source const &) +0001f090 T MBufferManager::AcquireBuffer(long, long, media_source) +0001f28c T MBufferManager::ReleaseBuffer(long, long, bool, BMessage *, char const *) +0001fd0c T MBufferManager::PurgeTeamBufferGroups(long) +0001fdf0 T MBufferManager::RegisterBufferGroup(BMessage *, char const *, long) +0002007c T MBufferManager::_RemoveGroupFromClaimants(long, long, void *) +00020158 T MBufferManager::UnregisterBufferGroup(BMessage *, char const *, long) +0002028c T MBufferManager::_UnregisterBufferGroup(long, long) +000206f4 T MBufferManager::AddBuffersTo(BMessage *, char const *) +00020cd0 T MBufferManager::ReclaimBuffers(long const *, long, long, long) +00020f7c T MBufferManager::CleanupPurgedBufferGroup(long, long, long, void *, bool, BMessage &) +00021080 T MBufferManager::LoadState(void) +0002108c T MBufferManager::SaveState(void) + +000210a0 T MDefaultManager::MDefaultManager(void) +0002123c T MDefaultManager::~MDefaultManager(void) +000212f4 T MDefaultManager::SaveState(void) +0002172c T MDefaultManager::LoadState(void) +00021de0 T MDefaultManager::SetDefault(long, BMessage &) +00022058 T MDefaultManager::SetRunningDefault(long, media_node const &) +000221a8 T MDefaultManager::RemoveRunningDefault(media_node const &) +000226ec T MDefaultManager::SetRealtimeFlags(unsigned long) +00022720 T MDefaultManager::GetRealtimeFlags(void) +00022730 T MDefaultManager::GetRunningDefault(long, media_node &) +000227d0 T MDefaultManager::RemoveDefault(long) +00022830 T MDefaultManager::GetDefault(long, BMessage &) +00022890 T MNotifierManager::MNotifierManager(void) +00022a5c T MNotifierManager::~MNotifierManager(void) +00022b20 T MNotifierManager::RegisterNotifier(long, BMessenger, media_node const *) +00022f50 T MNotifierManager::UnregisterNotifier(long, BMessenger, media_node const *) +00023f00 T MNotifierManager::BroadcastMessage(BMessage *, long long) +0002426c T MNotifierManager::regen_node_list(media_node const &) +000249b4 T MNotifierManager::get_node_messenger(media_node const &, get_messenger_a *) +00024a90 T MNotifierManager::HandleBroadcastError(BMessage *, BMessenger &, long, long long) +00024b34 T MNotifierManager::LoadState(void) +00024b40 T MNotifierManager::SaveState(void) +00024c5c T MMediaFilesManager::MMediaFilesManager(void) +00024dec T MMediaFilesManager::~MMediaFilesManager(void) +00024ea4 T MMediaFilesManager::SaveState(void) +00025b70 T MMediaFilesManager::LoadState(void) +00026668 T MMediaFilesManager::create_default_settings(void) +00027130 T MMediaFilesManager::GetTypes(BMessage &, BMessage &) +000271f8 T MMediaFilesManager::GetItems(BMessage &, BMessage &) +000274f0 T MMediaFilesManager::SetItem(BMessage &, BMessage &) +00027bc0 T MMediaFilesManager::ClearItem(BMessage &, BMessage &) +000288f4 T MMediaFilesManager::RemoveItem(BMessage &, BMessage &) +00028f0c T MMediaFilesManager::AddType(BMessage &, BMessage &) +*/ + diff --git a/src/servers/media_addon/main.cpp b/src/servers/media_addon/main.cpp new file mode 100644 index 0000000000..f5fc122c5c --- /dev/null +++ b/src/servers/media_addon/main.cpp @@ -0,0 +1,436 @@ +#define BUILDING_MEDIA_ADDON 1 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define DEBUG 1 +#include +#include "debug.h" +#include "TMap.h" +#include "../server/headers/ServerInterface.h" + +void DumpFlavorInfo(const flavor_info *info); + +class Application : BApplication +{ +public: + Application(const char *sig); + ~Application(); + void ReadyToRun(); + void MessageReceived(BMessage *msg); + + void WatchDir(BEntry *dir); + void AddOnAdded(const char *path, ino_t file_node); + void AddOnRemoved(ino_t file_node); + void HandleMessage(int32 code, void *data, size_t size); + static int32 controlthread(void *arg); + + void ScanAddOnFlavors(BMediaAddOn *addon); + + Map *filemap; + Map *addonmap; + + BMediaRoster *mediaroster; + ino_t DirNodeSystem; + ino_t DirNodeUser; + port_id control_port; + thread_id control_thread; +}; + +Application::Application(const char *sig) : + BApplication(sig) +{ + mediaroster = BMediaRoster::Roster(); + filemap = new Map; + addonmap = new Map; + control_port = create_port(64,"media_addon_server port"); + control_thread = spawn_thread(controlthread,"media_addon_server control",12,this); + resume_thread(control_thread); +} + +Application::~Application() +{ + delete_port(control_port); + status_t err; + wait_for_thread(control_thread,&err); + + // delete all BMediaAddOn objects + BMediaAddOn *addon; + for (int32 index = 0; addonmap->GetAt(index,&addon); index++) + delete addon; + + delete addonmap; + delete filemap; +} + +void +Application::HandleMessage(int32 code, void *data, size_t size) +{ + switch (code) { + case ADDONSERVER_INSTANTIATE_DORMANT_NODE: + { + const xfer_addonserver_instantiate_dormant_node *msg = (const xfer_addonserver_instantiate_dormant_node *)data; + xfer_addonserver_instantiate_dormant_node_reply reply; + reply.result = mediaroster->InstantiateDormantNode(msg->info, &reply.node); + write_port(msg->reply_port, 0, &reply, sizeof(reply)); + break; + } + + case ADDONSERVER_RESCAN_MEDIAADDON_FLAVORS: + { + const xfer_addonserver_rescan_mediaaddon_flavors *msg = (const xfer_addonserver_rescan_mediaaddon_flavors *)data; + BMediaAddOn *addon; + if (addonmap->Get(msg->addonid, &addon)) { + ASSERT(msg->addonid == addon->AddonID()); + ScanAddOnFlavors(addon); + } else { + printf("Can't find a addon object for id %d\n",(int)msg->addonid); + } + break; + } + + default: + printf("media_addon_server: received unknown message code %#08lx\n",code); + } +} + +int32 +Application::controlthread(void *arg) +{ + char data[B_MEDIA_MESSAGE_SIZE]; + Application *app; + ssize_t size; + int32 code; + + app = (Application *)arg; + while ((size = read_port_etc(app->control_port, &code, data, sizeof(data), 0, 0)) > 0) + app->HandleMessage(code, data, size); + + return 0; +} + +void +Application::ReadyToRun() +{ + node_ref nref; + + BEntry e("/boot/beos/system/add-ons/media"); + e.GetNodeRef(&nref); + DirNodeSystem = nref.node; + WatchDir(&e); + + BEntry e2("/boot/home/config/add-ons/media"); + e2.GetNodeRef(&nref); + DirNodeUser = nref.node; + WatchDir(&e2); +} + +void +Application::ScanAddOnFlavors(BMediaAddOn *addon) +{ + int flavorcount; + media_addon_id purge_id; + port_id port; + status_t rv; + + ASSERT(addon); + + port = find_port("media_server port"); + if (port <= B_OK) { + printf("couldn't find media_server port\n"); + return; + } + + ASSERT(addon->AddonID() > 0); + + // the server should remove previously registered "dormant_flavor_info"s + purge_id = addon->AddonID(); + + flavorcount = addon->CountFlavors(); + printf("%d flavors:\n",flavorcount); + + for (int i = 0; i < flavorcount; i++) { + const flavor_info *info; + printf("flavor %d:\n",i); + if (B_OK != addon->GetFlavorAt(i, &info)) { + printf("failed!\n"); + continue; + } + + DumpFlavorInfo(info); + + dormant_flavor_info dfi; + dfi = *info; + dfi.node_info.addon = addon->AddonID(); + dfi.node_info.flavor_id = info->internal_id; + strncpy(dfi.node_info.name, info->name, B_MEDIA_NAME_LENGTH - 1); + dfi.node_info.name[B_MEDIA_NAME_LENGTH - 1] = 0; + + xfer_server_register_dormant_node *msg; + size_t flattensize; + size_t msgsize; + + flattensize = dfi.FlattenedSize(); + msgsize = flattensize + sizeof(xfer_server_register_dormant_node); + msg = (xfer_server_register_dormant_node *) malloc(msgsize); + + msg->purge_id = purge_id; + msg->dfi_type = dfi.TypeCode(); + msg->dfi_size = flattensize; + dfi.Flatten(&(msg->dfi),flattensize); + + rv = write_port(port, SERVER_REGISTER_DORMANT_NODE, msg, msgsize); + if (rv != B_OK) { + printf("couldn't register dormant node\n"); + } + + free(msg); + + // after the first iteration, we don't want the server to anymore remove our dfis; + if (purge_id != 0) + purge_id = 0; + } +} + +void +Application::AddOnAdded(const char *path, ino_t file_node) +{ + printf("\n\nloading BMediaAddOn from %s\n",path); + + BMediaAddOn *(*make_addon)(image_id you); + BMediaAddOn *addon = 0; + media_addon_id id; + image_id image; + status_t rv; + + image = load_add_on(path); + if (image < B_OK) { + printf("loading failed %lx %s\n", image, strerror(image)); + return; + } + + rv = get_image_symbol(image, "make_media_addon", B_SYMBOL_TYPE_TEXT, (void**)&make_addon); + if (rv < B_OK) { + printf("loading failed, function not found %lx %s\n", rv, strerror(rv)); + unload_add_on(image); + return; + } + + addon = make_addon(image); + if (addon == 0) { + printf("creating BMediaAddOn failed\n"); + unload_add_on(image); + return; + } + + id = addon->AddonID(); + ASSERT(id > 0); + + printf("adding media add-on %d\n",(int)id); + + filemap->Insert(file_node, id); + addonmap->Insert(id, addon); + + ScanAddOnFlavors(addon); + + if (addon->WantsAutoStart()) + printf("#### WantsAutoStart!\n"); + +/* + * the mixer (which we can't load because of unresolved symbols) + * is the only node that uses autostart (which is not implemented yet) + */ + +/* +loading BMediaAddOn from /boot/beos/system/add-ons/media/mixer.media_addon +adding media add-on -1 +1 flavors: +flavor 0: + internal_id = 0 + name = Be Audio Mixer + info = The system-wide sound mixer of the future. + flavor_flags = 0x0 + kinds = 0x40003 B_BUFFER_PRODUCER B_BUFFER_CONSUMER B_SYSTEM_MIXER + in_format_count = 1 + out_format_count = 1 +#### WantsAutoStart! +*/ + +/* + if (addon->WantsAutoStart()) { + for (int32 index = 0; ;index++) { + BMediaNode *outNode; + int32 outInternalID; + bool outHasMore; + rv = addon->AutoStart(index, &outNode, &outInternalID, &outHasMore); + if (rv == B_OK) { + printf("started node %ld\n",index); + rv = mediaroster->RegisterNode(outNode); + if (rv != B_OK) + printf("failed to register node %ld\n",index); + if (!outHasMore) +// break; + return; + } else if (rv == B_MEDIA_ADDON_FAILED && outHasMore) { + continue; + } else { + break; + } + } + return; + } +*/ +} + + +void +Application::AddOnRemoved(ino_t file_node) +{ + media_addon_id id; + BMediaAddOn *addon; + if (!filemap->Get(file_node,&id)) { + printf("inode %Ld removed, but no media add-on found\n",file_node); + return; + } + filemap->Remove(file_node); + printf("removing media add-on %d\n",(int)id); + if (!addonmap->Get(id,&addon)) { + printf("no BMediaAddon object found\n"); + return; + } + delete addon; + addonmap->Remove(id); +} + +void +Application::WatchDir(BEntry *dir) +{ + BEntry e; + BDirectory d(dir); + node_ref nref; + entry_ref ref; + while (B_OK == d.GetNextEntry(&e, false)) { + e.GetRef(&ref); + e.GetNodeRef(&nref); + BMessage msg(B_NODE_MONITOR); + msg.AddInt32("opcode",B_ENTRY_CREATED); + msg.AddInt32("device",ref.device); + msg.AddInt64("directory",ref.directory); + msg.AddInt64("node",nref.node); + msg.AddString("name",ref.name); + msg.AddBool("nowait",true); + MessageReceived(&msg); + } + + dir->GetNodeRef(&nref); + watch_node(&nref,B_WATCH_DIRECTORY,be_app_messenger); +} + +void +Application::MessageReceived(BMessage *msg) +{ + switch (msg->what) + { + case B_NODE_MONITOR: + { + switch (msg->FindInt32("opcode")) + { + case B_ENTRY_CREATED: + { + const char *name; + entry_ref ref; + ino_t node; + BEntry e; + BPath p; + msg->FindString("name", &name); + msg->FindInt64("node", &node); + msg->FindInt32("device", &ref.device); + msg->FindInt64("directory", &ref.directory); + ref.set_name(name); + e.SetTo(&ref,false);// build a BEntry for the created file/link/dir + e.GetPath(&p); // get the path to the file/link/dir + e.SetTo(&ref,true); // travese links to see + if (e.IsFile()) { // if it's a link to a file, or a file + if (false == msg->FindBool("nowait")) { + // XXX wait 5 seconds if this is a regular notification + // because the file creation may not be finshed when the + // notification arrives (very ugly, how can we fix this?) + // this will also fail if copying takes longer than 5 seconds + snooze(5000000); + } + AddOnAdded(p.Path(),node); + } + return; + } + case B_ENTRY_REMOVED: + { + ino_t node; + msg->FindInt64("node",&node); + AddOnRemoved(node); + return; + } + case B_ENTRY_MOVED: + { + ino_t from; + ino_t to; + msg->FindInt64("from directory", &from); + msg->FindInt64("to directory", &to); + if (DirNodeSystem == from || DirNodeUser == from) { + msg->ReplaceInt32("opcode",B_ENTRY_REMOVED); + msg->AddInt64("directory",from); + MessageReceived(msg); + } + if (DirNodeSystem == to || DirNodeUser == to) { + msg->ReplaceInt32("opcode",B_ENTRY_CREATED); + msg->AddInt64("directory",to); + msg->AddBool("nowait",true); + MessageReceived(msg); + } + return; + } + } + break; + } + } + printf("Unhandled message:\n"); + msg->PrintToStream(); +} + +int main() +{ + new Application("application/x-vnd.OpenBeOS-media-addon-server"); + be_app->Run(); + return 0; +} + +void DumpFlavorInfo(const flavor_info *info) +{ + printf(" name = %s\n",info->name); + printf(" info = %s\n",info->info); + printf(" internal_id = %ld\n",info->internal_id); + printf(" possible_count = %ld\n",info->possible_count); + printf(" flavor_flags = 0x%lx",info->flavor_flags); + if (info->flavor_flags & B_FLAVOR_IS_GLOBAL) printf(" B_FLAVOR_IS_GLOBAL"); + if (info->flavor_flags & B_FLAVOR_IS_LOCAL) printf(" B_FLAVOR_IS_LOCAL"); + printf("\n"); + printf(" kinds = 0x%Lx",info->kinds); + if (info->kinds & B_BUFFER_PRODUCER) printf(" B_BUFFER_PRODUCER"); + if (info->kinds & B_BUFFER_CONSUMER) printf(" B_BUFFER_CONSUMER"); + if (info->kinds & B_TIME_SOURCE) printf(" B_TIME_SOURCE"); + if (info->kinds & B_CONTROLLABLE) printf(" B_CONTROLLABLE"); + if (info->kinds & B_FILE_INTERFACE) printf(" B_FILE_INTERFACE"); + if (info->kinds & B_ENTITY_INTERFACE) printf(" B_ENTITY_INTERFACE"); + if (info->kinds & B_PHYSICAL_INPUT) printf(" B_PHYSICAL_INPUT"); + if (info->kinds & B_PHYSICAL_OUTPUT) printf(" B_PHYSICAL_OUTPUT"); + if (info->kinds & B_SYSTEM_MIXER) printf(" B_SYSTEM_MIXER"); + printf("\n"); + printf(" in_format_count = %ld\n",info->in_format_count); + printf(" out_format_count = %ld\n",info->out_format_count); +} diff --git a/src/servers/print/BeUtils.cpp b/src/servers/print/BeUtils.cpp new file mode 100644 index 0000000000..6b91d080f4 --- /dev/null +++ b/src/servers/print/BeUtils.cpp @@ -0,0 +1,59 @@ +/*****************************************************************************/ +// BeUtils.cpp +// +// Version: 1.0.0d1 +// +// Several utilities for writing applications for the BeOS. It are small +// very specific functions, but generally useful (could be here because of a +// lack in the APIs, or just sheer lazyness :)) +// +// +// This application and all source files used in its construction, except +// where noted, are licensed under the MIT License, and have been written +// and are: +// +// Copyright (c) 2001 OpenBeOS Project +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ +#include "BeUtils.h" + +// --------------------------------------------------------------- +// TestForAddonExistence +// +// [Method Description] +// +// Parameters: +// +// Returns: +// --------------------------------------------------------------- +status_t TestForAddonExistence(const char* name, directory_which which, const char* section, BPath& outPath) +{ + status_t err = B_OK; + + if ((err=find_directory(which, &outPath)) == B_OK && + (err=outPath.Append(section)) == B_OK && + (err=outPath.Append(name)) == B_OK) + { + struct stat buf; + err = stat(outPath.Path(), &buf); + } + + return err; +} diff --git a/src/servers/print/BeUtils.h b/src/servers/print/BeUtils.h new file mode 100644 index 0000000000..785069192a --- /dev/null +++ b/src/servers/print/BeUtils.h @@ -0,0 +1,10 @@ +#ifndef BEUTILS_H +#define BEUTILS_H + +#include +#include + +status_t TestForAddonExistence(const char* name, directory_which which, + const char* section, BPath& outPath); + +#endif diff --git a/src/servers/print/PrintServer.FileTypes.rsrc b/src/servers/print/PrintServer.FileTypes.rsrc new file mode 100644 index 0000000000..ac9c4b6473 Binary files /dev/null and b/src/servers/print/PrintServer.FileTypes.rsrc differ diff --git a/src/servers/print/PrintServerApp.R5.cpp b/src/servers/print/PrintServerApp.R5.cpp new file mode 100644 index 0000000000..ba31463e77 --- /dev/null +++ b/src/servers/print/PrintServerApp.R5.cpp @@ -0,0 +1,149 @@ +/*****************************************************************************/ +// print_server Background Application. +// +// Version: 1.0.0d1 +// +// The print_server manages the communication between applications and the +// printer and transport drivers. +// +// +// +// TODO: +// Handle spooled jobs at startup +// Handle printer status (asked to print a spooled job but printer busy) +// +// +// This application and all source files used in its construction, except +// where noted, are licensed under the MIT License, and have been written +// and are: +// +// Copyright (c) 2001 OpenBeOS Project +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ + +#include "PrintServerApp.h" + +#include "pr_server.h" +#include "Printer.h" + + // BeOS API +#include +#include + +void PrintServerApp::Handle_BeOSR5_Message(BMessage* msg) +{ + switch(msg->what) { + // Get currently selected printer + case PSRV_GET_ACTIVE_PRINTER: { + BMessage reply('okok'); + reply.AddString("printer_name", fDefaultPrinter ? fDefaultPrinter->Name() : ""); + reply.AddInt32("color", BPrintJob::B_COLOR_PRINTER); // BeOS knows not if color or not, so always color + msg->SendReply(&reply); + } + break; + + //make printer active (currently always quietly :)) + case PSRV_MAKE_PRINTER_ACTIVE_QUIETLY: + //make printer active quietly + case PSRV_MAKE_PRINTER_ACTIVE: { + BString newActivePrinter; + if (msg->FindString("printer",&newActivePrinter) == B_OK) { + SelectPrinter(newActivePrinter.String()); + } + } + break; + + // Create a new printer + case PSRV_MAKE_PRINTER: { + BString driverName, transportName, transportPath; + BString printerName, connection; + + if (msg->FindString("driver", &driverName) == B_OK && + msg->FindString("transport", &transportName) == B_OK && + msg->FindString("transport path", &transportPath) == B_OK && + msg->FindString("printer name", &printerName) == B_OK && + msg->FindString("connection", &connection) == B_OK) { + // then create the actual printer + if (CreatePrinter(printerName.String(), driverName.String(), + connection.String(), + transportName.String(), transportPath.String()) == B_OK) { + // If printer was created ok, ask if it needs to be the default + char buffer[256]; + ::sprintf(buffer, "Would you like to make %s the default\nprinter?", + printerName.String()); + + BAlert* alert = new BAlert("", buffer, "No", "Yes"); + if (alert->Go() == 1) { + SelectPrinter(printerName.String()); + } + } + } + } + break; + + // Handle showing the page config dialog + case PSRV_SHOW_PAGE_SETUP: { + if (fDefaultPrinter != NULL) { + BMessage reply(*msg); + if (fDefaultPrinter->ConfigurePage(reply) == B_OK) { + msg->SendReply(&reply); + } + } + else { + // If no default printer, give user choice of aborting or setting up a printer + BAlert* alert = new BAlert("Info", "Hang on there! You don't have any printers set up!\nYou'll need to do that before trying to print\n\nWould you like to set up a printer now?", "No thanks", "Sure!"); + if (alert->Go() == 1) { + run_add_printer_panel(); + } + + // Always stop dialog flow + BMessage reply('stop'); + msg->SendReply(&reply); + } + } + break; + + // Handle showing the print config dialog + case PSRV_SHOW_PRINT_SETUP: { + if (fDefaultPrinter != NULL) { + BMessage reply(*msg); + if (fDefaultPrinter->ConfigureJob(reply) == B_OK) { + msg->SendReply(&reply); + } + } + else { + BMessage reply('stop'); + msg->SendReply(&reply); + } + } + break; + + // Tell printer addon to print a spooled job + case PSRV_PRINT_SPOOLED_JOB: { + BString name, jobpath; + if (msg->FindString("Spool File",&jobpath) == B_OK && + msg->FindString("JobName", &name) == B_OK) { + // Handle the spooled job + HandleSpooledJob(name.String(), jobpath.String()); + } + } + break; + } +} diff --git a/src/servers/print/PrintServerApp.Scripting.cpp b/src/servers/print/PrintServerApp.Scripting.cpp new file mode 100644 index 0000000000..abd32c8759 --- /dev/null +++ b/src/servers/print/PrintServerApp.Scripting.cpp @@ -0,0 +1,201 @@ +/*****************************************************************************/ +// print_server Background Application. +// +// Version: 1.0.0d1 +// +// The print_server manages the communication between applications and the +// printer and transport drivers. +// +// +// This application and all source files used in its construction, except +// where noted, are licensed under the MIT License, and have been written +// and are: +// +// Copyright (c) 2001 OpenBeOS Project +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ + +#include "PrintServerApp.h" + +#include "Printer.h" + + // BeOS API +#include + + // ANSI C +#include + +static property_info prop_list[] = { + { "ActivePrinter", { B_GET_PROPERTY, B_SET_PROPERTY }, { B_DIRECT_SPECIFIER }, + "Retrieve or select the active printer" }, + { "Printer", { B_GET_PROPERTY }, { B_INDEX_SPECIFIER, B_NAME_SPECIFIER, B_REVERSE_INDEX_SPECIFIER }, + "Retrieve a specific printer" }, + { "Printer", { B_CREATE_PROPERTY }, { B_DIRECT_SPECIFIER }, + "Create a new printer" }, + { "Printer", { B_DELETE_PROPERTY }, { B_INDEX_SPECIFIER, B_NAME_SPECIFIER, B_REVERSE_INDEX_SPECIFIER }, + "Delete a specific printer" }, + { "Printers", { B_COUNT_PROPERTIES }, { B_DIRECT_SPECIFIER }, + "Return the number of available printers" }, + { 0 } // terminate list +}; + +void +PrintServerApp::HandleScriptingCommand(BMessage* msg) +{ + BString propName; + BMessage spec; + int32 idx; + + if (msg->GetCurrentSpecifier(&idx,&spec) == B_OK && + spec.FindString("property",&propName) == B_OK) { + switch(msg->what) { + case B_GET_PROPERTY: + if (propName == "ActivePrinter") { + BMessage reply(B_REPLY); + reply.AddString("result", fDefaultPrinter ? fDefaultPrinter->Name() : ""); + reply.AddInt32("error", B_OK); + msg->SendReply(&reply); + } + break; + + case B_SET_PROPERTY: + if (propName == "ActivePrinter") { + BString newActivePrinter; + if (msg->FindString("data", &newActivePrinter) == B_OK) { + BMessage reply(B_REPLY); + reply.AddInt32("error", SelectPrinter(newActivePrinter.String())); + msg->SendReply(&reply); + } + } + break; + + case B_CREATE_PROPERTY: + if (propName == "Printer") { + BString name, driver, transport, config; + + if (msg->FindString("name", &name) == B_OK && + msg->FindString("driver", &driver) == B_OK && + msg->FindString("transport", &transport) == B_OK && + msg->FindString("config", &config) == B_OK) { + BMessage reply(B_REPLY); + reply.AddInt32("error", CreatePrinter(name.String(), driver.String(), + "Local", transport.String(), config.String())); + msg->SendReply(&reply); + } + } + break; + + case B_DELETE_PROPERTY: { + Printer* printer = GetPrinterFromSpecifier(&spec); + status_t rc = B_BAD_VALUE; + + if (printer != NULL && (rc=printer->Remove()) == B_OK) { + delete printer; + } + + BMessage reply(B_REPLY); + reply.AddInt32("error", rc); + msg->SendReply(&reply); + } + break; + + case B_COUNT_PROPERTIES: + if (propName == "Printers") { + BMessage reply(B_REPLY); + reply.AddInt32("result", Printer::CountPrinters()); + reply.AddInt32("error", B_OK); + msg->SendReply(&reply); + } + break; + } + } +} + +Printer* PrintServerApp::GetPrinterFromSpecifier(BMessage* msg) +{ + switch(msg->what) { + case B_NAME_SPECIFIER: { + BString name; + if (msg->FindString("name", &name) == B_OK) { + return Printer::Find(name.String()); + } + break; + } + + case B_INDEX_SPECIFIER: { + int32 idx; + if (msg->FindInt32("index", &idx) == B_OK) { + return Printer::At(idx); + } + break; + } + + case B_REVERSE_INDEX_SPECIFIER: { + int32 idx; + if (msg->FindInt32("index", &idx) == B_OK) { + return Printer::At(Printer::CountPrinters() - idx); + } + break; + } + } + + return NULL; +} + +BHandler* +PrintServerApp::ResolveSpecifier(BMessage* msg, int32 index, BMessage* spec, + int32 form, const char* prop) +{ + BPropertyInfo prop_info(prop_list); + BHandler* rc = NULL; + + int32 idx; + switch( idx=prop_info.FindMatch(msg,0,spec,form,prop) ) { + case B_ERROR: + rc = Inherited::ResolveSpecifier(msg,index,spec,form,prop); + + // GET Printer [arg] + case 1: + if ((rc=GetPrinterFromSpecifier(spec)) == NULL) { + BMessage reply(B_REPLY); + reply.AddInt32("error", B_BAD_INDEX); + msg->SendReply(&reply); + } + else + msg->PopSpecifier(); + break; + + default: + rc = this; + } + + return rc; +} + +status_t +PrintServerApp::GetSupportedSuites(BMessage* msg) +{ + msg->AddString("suites", "suite/vnd.OpenBeOS-printserver"); + + BPropertyInfo prop_info(prop_list); + msg->AddFlat("messages", &prop_info); + + return Inherited::GetSupportedSuites(msg); +} diff --git a/src/servers/print/PrintServerApp.cpp b/src/servers/print/PrintServerApp.cpp new file mode 100644 index 0000000000..09b8cdeba3 --- /dev/null +++ b/src/servers/print/PrintServerApp.cpp @@ -0,0 +1,538 @@ +/*****************************************************************************/ +// print_server Background Application. +// +// Version: 1.0.0d1 +// +// The print_server manages the communication between applications and the +// printer and transport drivers. +// +// +// +// TODO: +// Handle spooled jobs at startup +// Handle printer status (asked to print a spooled job but printer busy) +// +// +// This application and all source files used in its construction, except +// where noted, are licensed under the MIT License, and have been written +// and are: +// +// Copyright (c) 2001 OpenBeOS Project +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ + +#include "PrintServerApp.h" + +#include "BeUtils.h" +#include "Printer.h" +#include "pr_server.h" + + // BeOS API +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + // ANSI C +#include //for printf +#include //for unlink + +// --------------------------------------------------------------- +typedef struct _printer_data { + char defaultPrinterName[256]; +} printer_data_t; + +typedef BMessage* (*config_func_t)(BNode*, const BMessage*); +typedef BMessage* (*take_job_func_t)(BFile*, BNode*, const BMessage*); +typedef char* (*add_printer_func_t)(const char* printer_name); + +/** + * Main entry point of print_server. + * + * @returns B_OK if application was started, or an errorcode if + * application failed to start. + * + * @see your favorite C/C++ textbook :P + */ + +int +main() +{ + // Create our application object + status_t rc = B_OK; + new PrintServerApp(&rc); + + // If all went fine, let's start it + if (rc == B_OK) { + be_app->Run(); + } + + delete be_app; + + return rc; +} + +/** + * Constructor for print_server's application class. Retrieves the + * name of the default printer from storage, caches the icons for + * a selected printer. + * + * @param err Pointer to status_t for storing result of application + * initialisation. + * + * @see BApplication + */ + +PrintServerApp::PrintServerApp(status_t* err) + : Inherited(PSRV_SIGNATURE_TYPE, err), + fSelectedIconMini(BRect(0,0,B_MINI_ICON-1,B_MINI_ICON-1), B_CMAP8), + fSelectedIconLarge(BRect(0,0,B_LARGE_ICON-1,B_LARGE_ICON-1), B_CMAP8) +{ + // If our superclass initialized ok + if (*err == B_OK) { + // let us try as well + SetupPrinterList(); + RetrieveDefaultPrinter(); + + // Cache icons for selected printer + BMimeType type(PRNT_SIGNATURE_TYPE); + type.GetIcon(&fSelectedIconMini, B_MINI_ICON); + type.GetIcon(&fSelectedIconLarge, B_LARGE_ICON); + } +} + +bool PrintServerApp::QuitRequested() +{ + bool rc = Inherited::QuitRequested(); + if (rc) { + // Find directory containing printer definition nodes + BPath path; + if (::find_directory(B_USER_PRINTERS_DIRECTORY, &path) == B_OK) { + BEntry entry(path.Path()); + node_ref nref; + if (entry.InitCheck() == B_OK && + entry.GetNodeRef(&nref) == B_OK) { + // Stop watching the printer directory + ::watch_node(&nref, B_STOP_WATCHING, be_app_messenger); + } + } + } + + return rc; +} + +// --------------------------------------------------------------- +// SetupPrinterList +// +// This method builds the internal list of printers from disk. It +// also installs a node monitor to be sure that the list keeps +// updated with the definitions on disk. +// +// Parameters: +// none. +// +// Returns: +// B_OK if successful, or an errorcode if failed. +// --------------------------------------------------------------- +status_t PrintServerApp::SetupPrinterList() +{ + BEntry entry; + status_t rc; + BPath path; + + // Find directory containing printer definition nodes + if ((rc=::find_directory(B_USER_PRINTERS_DIRECTORY, &path)) == B_OK) { + BDirectory dir(path.Path()); + + // Can we reach the directory? + if ((rc=dir.InitCheck()) == B_OK) { + // Yes, so loop over it's entries + while((rc=dir.GetNextEntry(&entry)) == B_OK) { + // If the entry is a directory + if (entry.IsDirectory()) { + // Check it's Mime type for a spool director + BNode node(&entry); + BNodeInfo info(&node); + char buffer[256]; + + if (info.GetType(buffer) == B_OK && + strcmp(buffer, PSRV_PRINTER_FILETYPE) == 0) { + // Yes, it is a printer definition node + new Printer(&node); + } + } + } + + // If we scanned all entries successfully + node_ref nref; + if (rc == B_ENTRY_NOT_FOUND && + (rc=dir.GetNodeRef(&nref)) == B_OK) { + // Get node to watch + rc = ::watch_node(&nref, B_WATCH_DIRECTORY, be_app_messenger); + } + } + } + + return rc; +} + +// --------------------------------------------------------------- +// void MessageReceived(BMessage* msg) +// +// Message handling method for print_server application class. +// +// Parameters: +// msg - Actual message sent to application class. +// +// Returns: +// void. +// --------------------------------------------------------------- +void +PrintServerApp::MessageReceived(BMessage* msg) +{ + switch(msg->what) { + case PSRV_GET_ACTIVE_PRINTER: + case PSRV_MAKE_PRINTER_ACTIVE_QUIETLY: + case PSRV_MAKE_PRINTER_ACTIVE: + case PSRV_MAKE_PRINTER: + case PSRV_SHOW_PAGE_SETUP: + case PSRV_SHOW_PRINT_SETUP: + case PSRV_PRINT_SPOOLED_JOB: + Handle_BeOSR5_Message(msg); + break; + + case B_GET_PROPERTY: + case B_SET_PROPERTY: + case B_CREATE_PROPERTY: + case B_DELETE_PROPERTY: + case B_COUNT_PROPERTIES: + case B_EXECUTE_PROPERTY: + HandleScriptingCommand(msg); + break; + + default: + printf("PrintServerApp::MessageReceived(): "); + msg->PrintToStream(); + Inherited::MessageReceived(msg); + } +} + +// --------------------------------------------------------------- +// CreatePrinter(const char* printerName, const char* driverName, +// const char* connection, const char* transportName, +// const char* transportPath) +// +// Creates printer definition/spool directory. It sets the +// attributes of the directory to the values passed and calls +// the driver's add_printer method to handle any configuration +// needed. +// +// Parameters: +// printerName - Name of printer to create. +// driverName - Name of driver to use for this printer. +// connection - "Local" or "Network". +// transportName - Name of transport driver to use. +// transportPath - Configuration data for transport driver. +// +// Returns: +// --------------------------------------------------------------- +status_t +PrintServerApp::CreatePrinter(const char* printerName, const char* driverName, + const char* connection, const char* transportName, const char* transportPath) +{ + status_t rc; + + // Find directory containing printer definitions + BPath path; + if ((rc=::find_directory(B_USER_PRINTERS_DIRECTORY,&path,true,NULL)) == B_OK) { + + // Create our printer definition/spool directory + BDirectory printersDir(path.Path()); + BDirectory printer; + if ((rc=printersDir.CreateDirectory(printerName,&printer)) == B_OK) { + // Set its type to a printer + BNodeInfo info(&printer); + info.SetType(PSRV_PRINTER_FILETYPE); + + // Store the settings in its attributes + printer.WriteAttr(PSRV_PRINTER_ATTR_PRT_NAME, B_STRING_TYPE, 0, printerName, ::strlen(printerName)+1); + printer.WriteAttr(PSRV_PRINTER_ATTR_DRV_NAME, B_STRING_TYPE, 0, driverName, ::strlen(driverName)+1); + printer.WriteAttr(PSRV_PRINTER_ATTR_STATE, B_STRING_TYPE, 0, "free", ::strlen("free")+1); + printer.WriteAttr(PSRV_PRINTER_ATTR_TRANSPORT, B_STRING_TYPE, 0, transportName,::strlen(transportName)+1); + printer.WriteAttr(PSRV_PRINTER_ATTR_TRANSPORT_ADDR, B_STRING_TYPE, 0, transportPath,::strlen(transportPath)+1); + printer.WriteAttr(PSRV_PRINTER_ATTR_CNX, B_STRING_TYPE, 0, connection, ::strlen(connection)+1); + + // Find printer driver + if (FindPrinterDriver(driverName, path) == B_OK) { + // Try and load the addon + image_id id = ::load_add_on(path.Path()); + if (id > 0) { + // Addon was loaded, so try and get the add_printer symbol + add_printer_func_t func; + if (get_image_symbol(id, "add_printer", B_SYMBOL_TYPE_TEXT, (void**)&func) == B_OK) { + // call the function and check its result + if ((*func)(printerName) == NULL) { + BEntry entry; + if (printer.GetEntry(&entry) == B_OK && entry.GetPath(&path) == B_OK) { + // Delete the printer if function failed + ::rmdir(path.Path()); + } + } + } + + ::unload_add_on(id); + } + } + } + } + + return rc; +} + +// --------------------------------------------------------------- +// SelectPrinter(const char* printerName) +// +// Makes a new printer the active printer. This is done simply +// by changing our class attribute fDefaultPrinter, and changing +// the icon of the BNode for the printer. Ofcourse, we need to +// change the icon of the "old" default printer first back to a +// "non-active" printer icon first. +// +// Parameters: +// printerName - Name of the new active printer. +// +// Returns: +// B_OK on success, or error code otherwise. +// --------------------------------------------------------------- +status_t +PrintServerApp::SelectPrinter(const char* printerName) +{ + status_t rc; + BNode node; + + // Find the node of the "old" default printer + if (fDefaultPrinter != NULL && + FindPrinterNode(fDefaultPrinter->Name(), node) == B_OK) { + // and remove the custom icon + BNodeInfo info(&node); + info.SetIcon(NULL, B_MINI_ICON); + info.SetIcon(NULL, B_LARGE_ICON); + } + + // Find the node for the new default printer + if ((rc=FindPrinterNode(printerName, node)) == B_OK) { + // and add the custom icon + BNodeInfo info(&node); + info.SetIcon(&fSelectedIconMini, B_MINI_ICON); + info.SetIcon(&fSelectedIconLarge, B_LARGE_ICON); + } + + fDefaultPrinter = Printer::Find(printerName); + StoreDefaultPrinter(); // update our pref file + be_roster->Broadcast(new BMessage(B_PRINTER_CHANGED)); + + return rc; +} + +// --------------------------------------------------------------- +// HandleSpooledJob(const char* jobname, const char* filepath) +// +// Handles calling the printer driver for printing a spooled job. +// +// Parameters: +// msg - A copy of the message received, will be accessible +// to the printer driver for reading job config +// details. +// Returns: +// BMessage containing new job data, or NULL pointer if not +// successfull. +// --------------------------------------------------------------- +status_t +PrintServerApp::HandleSpooledJob(const char* jobname, const char* filepath) +{ + BFile spoolFile(filepath, B_READ_ONLY); + print_file_header header; + BString driverName; + BMessage settings; + Printer* printer; + status_t rc; + BPath path; + + // Open the spool file + if ((rc=spoolFile.InitCheck()) == B_OK) { + // Read header from filestream + spoolFile.Seek(0, SEEK_SET); + spoolFile.Read(&header, sizeof(header)); + + // Get the printer settings + settings.Unflatten(&spoolFile); + + // Get name of printer from settings + const char* printerName; + if ((rc=settings.FindString("current_printer", &printerName)) == B_OK) { + // Find printer definition for this printer + if ((printer=Printer::Find(printerName)) != NULL) { + // and tell the printer to print the spooled job + printer->PrintSpooledJob(&spoolFile, settings); + } + } + + // Remove spool file if printing was successfull. + if (rc == B_OK) { + ::unlink(filepath); + } + } + + return rc; +} + +// --------------------------------------------------------------- +// RetrieveDefaultPrinter() +// +// Loads the currently selected printer from a private settings +// file. +// +// Parameters: +// none. +// +// Returns: +// Error code on failore, or B_OK if all went fine. +// --------------------------------------------------------------- +status_t +PrintServerApp::RetrieveDefaultPrinter() +{ + printer_data_t prefs; + status_t rc = B_OK; + BPath path; + + if ((rc=find_directory(B_USER_SETTINGS_DIRECTORY, &path, true)) == B_OK) { + BFile file; + + path.Append("printer_data"); + + if ((rc=file.SetTo(path.Path(), B_READ_ONLY)) == B_OK) { + file.ReadAt(0, &prefs, sizeof(prefs)); + fDefaultPrinter = Printer::Find(prefs.defaultPrinterName); + } + } + + return rc; +} + +// --------------------------------------------------------------- +// StoreDefaultPrinter() +// +// Stores the currently selected printer in a private settings +// file. +// +// Parameters: +// none. +// +// Returns: +// Error code on failore, or B_OK if all went fine. +// --------------------------------------------------------------- +status_t +PrintServerApp::StoreDefaultPrinter() +{ + printer_data_t prefs; + status_t rc = B_OK; + BPath path; + + if ((rc=find_directory(B_USER_SETTINGS_DIRECTORY, &path, true)) == B_OK) { + BFile file; + + path.Append("printer_data"); + + if ((rc=file.SetTo(path.Path(), B_WRITE_ONLY)) == B_OK) { + + if (fDefaultPrinter != NULL) + ::strcpy(prefs.defaultPrinterName, fDefaultPrinter->Name()); + else + prefs.defaultPrinterName[0] = '\0'; + + file.WriteAt(0, &prefs, sizeof(prefs)); + } + } + + return rc; +} + +// --------------------------------------------------------------- +// FindPrinterNode(const char* name, BNode& node) +// +// Find the BNode representing the specified printer. It searches +// *only* in the users printer definitions. +// +// Parameters: +// name - Name of the printer to look for. +// node - BNode to set to the printer definition node. +// +// Returns: +// B_OK if found, an error code otherwise. +// --------------------------------------------------------------- +status_t +PrintServerApp::FindPrinterNode(const char* name, BNode& node) +{ + status_t rc; + + // Find directory containing printer definitions + BPath path; + if ((rc=::find_directory(B_USER_PRINTERS_DIRECTORY,&path,true,NULL)) == B_OK) + { + path.Append(name); + rc = node.SetTo(path.Path()); + } + + return rc; +} + +// --------------------------------------------------------------- +// FindPrinterDriver(const char* name, BPath& outPath) +// +// Finds the path to a specific printer driver. It searches all 3 +// places add-ons can be stored: the user's private directory, the +// directory common to all users, and the system directory, in that +// order. +// +// Parameters: +// name - Name of the printer driver to look for. +// outPath - BPath to store the path to the driver in. +// +// Returns: +// B_OK if the driver was found, otherwise an error code. +// --------------------------------------------------------------- +status_t +PrintServerApp::FindPrinterDriver(const char* name, BPath& outPath) +{ + // try to locate the driver + if (::TestForAddonExistence(name, B_USER_ADDONS_DIRECTORY, "Print", outPath) != B_OK) + if (::TestForAddonExistence(name, B_COMMON_ADDONS_DIRECTORY, "Print", outPath) != B_OK) + return ::TestForAddonExistence(name, B_BEOS_ADDONS_DIRECTORY, "Print", outPath); + + return B_OK; +} diff --git a/src/servers/print/PrintServerApp.h b/src/servers/print/PrintServerApp.h new file mode 100644 index 0000000000..2de5b1d7b6 --- /dev/null +++ b/src/servers/print/PrintServerApp.h @@ -0,0 +1,88 @@ +/*****************************************************************************/ +// print_server Background Application. +// +// Version: 1.0.0d1 +// +// The print_server manages the communication between applications and the +// printer and transport drivers. +// +// +// This application and all source files used in its construction, except +// where noted, are licensed under the MIT License, and have been written +// and are: +// +// Copyright (c) 2001 OpenBeOS Project +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ + +#ifndef PRINTSERVERAPP_H +#define PRINTSERVERAPP_H + +class PrintServerApp; + +#include +#include +#include + +/*****************************************************************************/ +// PrintServerApp +// +// Application class for print_server. +/*****************************************************************************/ +class Printer; +class PrintServerApp : public BApplication +{ + typedef BApplication Inherited; +public: + PrintServerApp(status_t* err); + bool QuitRequested(); + void MessageReceived(BMessage* msg); + + // Scripting support, see PrintServerApp.Scripting.cpp + status_t GetSupportedSuites(BMessage* msg); + void HandleScriptingCommand(BMessage* msg); + Printer* GetPrinterFromSpecifier(BMessage* msg); + BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* spec, + int32 form, const char* prop); +private: + status_t SetupPrinterList(); + + status_t HandleSpooledJob(const char* jobname, const char* filepath); + + status_t SelectPrinter(const char* printerName); + status_t CreatePrinter( const char* printerName, const char* driverName, + const char* connection, const char* transportName, + const char* transportPath); + + status_t StoreDefaultPrinter(); + status_t RetrieveDefaultPrinter(); + + status_t FindPrinterNode(const char* name, BNode& node); + status_t FindPrinterDriver(const char* name, BPath& outPath); + + Printer* fDefaultPrinter; + BBitmap fSelectedIconMini; + BBitmap fSelectedIconLarge; + + // "Classic" BeOS R5 support, see PrintServerApp.R5.cpp + void Handle_BeOSR5_Message(BMessage* msg); +}; + +#endif diff --git a/src/servers/print/Printer.Scripting.cpp b/src/servers/print/Printer.Scripting.cpp new file mode 100644 index 0000000000..fe77c088cc --- /dev/null +++ b/src/servers/print/Printer.Scripting.cpp @@ -0,0 +1,95 @@ +#include "Printer.h" + + +#include "pr_server.h" + + // BeOS API +#include +#include +#include +#include + +static property_info prop_list[] = { + { "Name", { B_GET_PROPERTY }, { B_DIRECT_SPECIFIER }, + "Get name of printer" }, + { "TransportAddon", { B_GET_PROPERTY }, { B_DIRECT_SPECIFIER }, + "Get name of the transport add-on used for this printer" }, + { "TransportConfig", { B_GET_PROPERTY }, { B_DIRECT_SPECIFIER }, + "Get the transport configuration for this printer" }, + { "PrinterAddon", { B_GET_PROPERTY }, { B_DIRECT_SPECIFIER }, + "Get name of the printer add-on used for this printer" }, + { "Comments", { B_GET_PROPERTY }, { B_DIRECT_SPECIFIER }, + "Get comments about this printer" }, + { 0 } // terminate list +}; + +void Printer::HandleScriptingCommand(BMessage* msg) +{ + status_t rc = B_ERROR; + BString propName; + BString result; + BMessage spec; + int32 idx; + + if ((rc=msg->GetCurrentSpecifier(&idx,&spec)) == B_OK && + (rc=spec.FindString("property",&propName)) == B_OK) { + switch(msg->what) { + case B_GET_PROPERTY: + if (propName == "Name") + rc = fNode.ReadAttrString(PSRV_PRINTER_ATTR_PRT_NAME, &result); + else if (propName == "TransportAddon") + rc = fNode.ReadAttrString(PSRV_PRINTER_ATTR_TRANSPORT, &result); + else if (propName == "TransportConfig") + rc = fNode.ReadAttrString(PSRV_PRINTER_ATTR_TRANSPORT_ADDR, &result); + else if (propName == "PrinterAddon") + rc = fNode.ReadAttrString(PSRV_PRINTER_ATTR_DRV_NAME, &result); + else if (propName == "Comments") + rc = fNode.ReadAttrString(PSRV_PRINTER_ATTR_COMMENTS, &result); + else { // If unknown scripting request, let superclas handle it + Inherited::MessageReceived(msg); + break; + } + + BMessage reply(B_REPLY); + reply.AddString("result", result); + reply.AddInt32("error", rc); + msg->SendReply(&reply); + break; + } + } + else { + // If GetSpecifier failed + if (idx == -1) { + BMessage reply(B_REPLY); + reply.AddMessenger("result", BMessenger(this)); + reply.AddInt32("error", B_OK); + msg->SendReply(&reply); + } + } +} + +BHandler* Printer::ResolveSpecifier(BMessage* msg, int32 index, BMessage* spec, + int32 form, const char* prop) +{ + BPropertyInfo prop_info(prop_list); + BHandler* rc = this; + + int32 idx; + switch( idx=prop_info.FindMatch(msg,0,spec,form,prop) ) { + case B_ERROR: + rc = Inherited::ResolveSpecifier(msg,index,spec,form,prop); + break; + } + + return rc; +} + +status_t Printer::GetSupportedSuites(BMessage* msg) +{ + msg->AddString("suites", "application/x-vnd.OpenBeOS-printer"); + + BPropertyInfo prop_info(prop_list); + msg->AddFlat("messages", &prop_info); + + return Inherited::GetSupportedSuites(msg); +} diff --git a/src/servers/print/Printer.cpp b/src/servers/print/Printer.cpp new file mode 100644 index 0000000000..5fc308ef24 --- /dev/null +++ b/src/servers/print/Printer.cpp @@ -0,0 +1,314 @@ +/*****************************************************************************/ +// print_server Background Application. +// +// Version: 1.0.0d1 +// +// The print_server manages the communication between applications and the +// printer and transport drivers. +// +// +// +// TODO: +// Handle spooled jobs at startup +// Handle printer status (asked to print a spooled job but printer busy) +// +// +// This application and all source files used in its construction, except +// where noted, are licensed under the MIT License, and have been written +// and are: +// +// Copyright (c) 2001 OpenBeOS Project +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ + +#include "Printer.h" + +#include "pr_server.h" +#include "BeUtils.h" + + // BeOS API +#include +#include +#include +#include +#include + +// --------------------------------------------------------------- +typedef BMessage* (*config_func_t)(BNode*, const BMessage*); +typedef BMessage* (*take_job_func_t)(BFile*, BNode*, const BMessage*); +typedef char* (*add_printer_func_t)(const char* printer_name); + +// --------------------------------------------------------------- +BObjectList Printer::sPrinters; + + +// --------------------------------------------------------------- +// Find [static] +// +// Searches the static object list for a printer object with the +// specified name. +// +// Parameters: +// name - Printer definition name we're looking for. +// +// Returns: +// Pointer to Printer object, or NULL if not found. +// --------------------------------------------------------------- +Printer* Printer::Find(const BString& name) +{ + // Look in list to find printer definition + for (int32 idx=0; idx < sPrinters.CountItems(); idx++) { + if (name == sPrinters.ItemAt(idx)->Name()) { + return sPrinters.ItemAt(idx); + } + } + + // None found, so return NULL + return NULL; +} + +int32 Printer::CountPrinters() +{ + return sPrinters.CountItems(); +} + +Printer* Printer::At(int32 idx) +{ + return sPrinters.ItemAt(idx); +} + +// --------------------------------------------------------------- +// Printer [constructor] +// +// Initializes the printer object with data read from the +// attributes attached to the printer definition node. +// +// Parameters: +// node - Printer definition node for this printer. +// +// Returns: +// none. +// --------------------------------------------------------------- +Printer::Printer(const BNode* node) + : Inherited(B_EMPTY_STRING), + fNode(*node) +{ + // Set our name to the name of the passed node + BString name; + fNode.ReadAttrString(PSRV_PRINTER_ATTR_PRT_NAME, &name); + SetName(name.String()); + + // Add us to the global list of known printer definitions + sPrinters.AddItem(this); + be_app->AddHandler(this); +} + +Printer::~Printer() +{ + sPrinters.RemoveItem(this); + be_app->RemoveHandler(this); +} + +status_t Printer::Remove() +{ + status_t rc = B_OK; + BPath path; + + if ((rc=::find_directory(B_USER_PRINTERS_DIRECTORY, &path)) == B_OK) { + path.Append(Name()); + rc = rmdir(path.Path()); + } + + return rc; +} + +// --------------------------------------------------------------- +// ConfigurePrinter +// +// Handles calling the printer addon's add_printer function. +// +// Parameters: +// none. +// +// Returns: +// B_OK if successful or errorcode otherwise. +// --------------------------------------------------------------- +status_t Printer::ConfigurePrinter() +{ + image_id id; + status_t rc; + + if ((rc=LoadPrinterAddon(id)) == B_OK) { + // Addon was loaded, so try and get the add_printer symbol + add_printer_func_t func; + + if (get_image_symbol(id, "add_printer", B_SYMBOL_TYPE_TEXT, (void**)&func) == B_OK) { + // call the function and check its result + rc = ((*func)(Name()) == NULL) ? B_ERROR : B_OK; + } + + ::unload_add_on(id); + } + + return rc; +} + +// --------------------------------------------------------------- +// ConfigurePage +// +// Handles calling the printer addon's config_page function. +// +// Parameters: +// settings - Page settings to display. The contents of this +// message will be replaced with the new settings +// if the function returns success. +// +// Returns: +// B_OK if successful or errorcode otherwise. +// --------------------------------------------------------------- +status_t Printer::ConfigurePage(BMessage& settings) +{ + image_id id; + status_t rc; + + if ((rc=LoadPrinterAddon(id)) == B_OK) { + // Addon was loaded, so try and get the config_page symbol + config_func_t func; + + if ((rc=get_image_symbol(id, "config_page", B_SYMBOL_TYPE_TEXT, (void**)&func)) == B_OK) { + // call the function and check its result + BMessage* new_settings = (*func)(&fNode, &settings); + if (new_settings != NULL && new_settings->what != 'baad') + settings = *new_settings; + } + + ::unload_add_on(id); + } + + return rc; +} + +// --------------------------------------------------------------- +// ConfigureJob +// +// Handles calling the printer addon's config_job function. +// +// Parameters: +// settings - Job settings to display. The contents of this +// message will be replaced with the new settings +// if the function returns success. +// +// Returns: +// B_OK if successful or errorcode otherwise. +// --------------------------------------------------------------- +status_t Printer::ConfigureJob(BMessage& settings) +{ + image_id id; + status_t rc; + + if ((rc=LoadPrinterAddon(id)) == B_OK) { + // Addon was loaded, so try and get the config_job symbol + config_func_t func; + + if ((rc=get_image_symbol(id, "config_job", B_SYMBOL_TYPE_TEXT, (void**)&func)) == B_OK) { + // call the function and check its result + BMessage* new_settings = (*func)(&fNode, &settings); + if (new_settings != NULL && new_settings->what != 'baad') + settings = *new_settings; + } + + ::unload_add_on(id); + } + + return rc; +} + +status_t Printer::PrintSpooledJob(BFile* spoolFile, const BMessage& settings) +{ + take_job_func_t func; + image_id id; + status_t rc; + + if ((rc=LoadPrinterAddon(id)) == B_OK) { + // Addon was loaded, so try and get the take_job symbol + if ((rc=get_image_symbol(id, "take_job", B_SYMBOL_TYPE_TEXT, (void**)&func)) == B_OK) { + // call the function and check its result + BMessage* result = (*func)(spoolFile, &fNode, &settings); + if (result == NULL || result->what == 'baad') + rc = B_ERROR; + } + + ::unload_add_on(id); + } + + return rc; +} + +// --------------------------------------------------------------- +// LoadPrinterAddon +// +// Try to load the printer addon into memory. +// +// Parameters: +// id - image_id set to the image id of the loaded addon. +// +// Returns: +// B_OK if successful or errorcode otherwise. +// --------------------------------------------------------------- +status_t Printer::LoadPrinterAddon(image_id& id) +{ + BString drName; + status_t rc; + BPath path; + + if ((rc=fNode.ReadAttrString(PSRV_PRINTER_ATTR_DRV_NAME, &drName)) == B_OK) { + // try to locate the driver + if ((rc=::TestForAddonExistence(drName.String(), B_USER_ADDONS_DIRECTORY, "Print", path)) != B_OK) { + if ((rc=::TestForAddonExistence(drName.String(), B_COMMON_ADDONS_DIRECTORY, "Print", path)) != B_OK) { + rc = ::TestForAddonExistence(drName.String(), B_BEOS_ADDONS_DIRECTORY, "Print", path); + } + } + + // If the driver was found + if (rc == B_OK) { + // If we cannot load the addon + if ((id=::load_add_on(path.Path())) < 0) + rc = id; + } + } + return rc; +} + +void Printer::MessageReceived(BMessage* msg) +{ + switch(msg->what) { + case B_GET_PROPERTY: + case B_SET_PROPERTY: + case B_CREATE_PROPERTY: + case B_DELETE_PROPERTY: + case B_COUNT_PROPERTIES: + case B_EXECUTE_PROPERTY: + HandleScriptingCommand(msg); + break; + + default: + Inherited::MessageReceived(msg); + } +} diff --git a/src/servers/print/Printer.h b/src/servers/print/Printer.h new file mode 100644 index 0000000000..f92a8595c0 --- /dev/null +++ b/src/servers/print/Printer.h @@ -0,0 +1,94 @@ +/*****************************************************************************/ +// print_server Background Application. +// +// Version: 1.0.0d1 +// +// The print_server manages the communication between applications and the +// printer and transport drivers. +// +// +// +// TODO: +// Handle spooled jobs at startup +// Handle printer status (asked to print a spooled job but printer busy) +// +// +// This application and all source files used in its construction, except +// where noted, are licensed under the MIT License, and have been written +// and are: +// +// Copyright (c) 2001 OpenBeOS Project +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ + +#ifndef PRINTER_H +#define PRINTER_H + +class Printer; + + // BeOS API +#include +#include +#include +#include + + // OpenTracker shared sources +#include "ObjectList.h" + +/*****************************************************************************/ +// Printer +// +// This class represents one printer definition. It is manages all actions & +// data related to that printer. +/*****************************************************************************/ +class Printer : public BHandler +{ + typedef BHandler Inherited; +public: + Printer(const BNode* node); + ~Printer(); + + // Static helper functions + static Printer* Find(const BString& name); + static Printer* At(int32 idx); + static int32 CountPrinters(); + + status_t Remove(); + status_t ConfigurePrinter(); + status_t ConfigureJob(BMessage& ioSettings); + status_t ConfigurePage(BMessage& ioSettings); + status_t PrintSpooledJob(BFile* spoolFile, const BMessage& settings); + + void MessageReceived(BMessage* msg); + + // Scripting support, see Printer.Scripting.cpp + status_t GetSupportedSuites(BMessage* msg); + void HandleScriptingCommand(BMessage* msg); + BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* spec, + int32 form, const char* prop); +private: + status_t LoadPrinterAddon(image_id& id); + + BNode fNode; + + static BObjectList sPrinters; +}; + +#endif diff --git a/src/servers/screensaver/SSAwindow.cpp b/src/servers/screensaver/SSAwindow.cpp new file mode 100644 index 0000000000..7fcc21e3a8 --- /dev/null +++ b/src/servers/screensaver/SSAwindow.cpp @@ -0,0 +1,40 @@ +#include "SSAwindow.h" +#include "Locker.h" +#include "View.h" +#include +#include + +extern void callDirectConnected(direct_buffer_info *); +extern BView *view; + +// This is the BDirectWindow subclass that rendering occurs in. +// A view is added to it so that BView based screensavers will work. +SSAwindow::SSAwindow(BRect frame) : BDirectWindow(frame, "ScreenSaver Window", + B_TITLED_WINDOW, B_NOT_RESIZABLE|B_NOT_ZOOMABLE) + { + frame.OffsetTo(0.0,0.0); + view=new BView(frame,"ScreenSaver View",B_FOLLOW_ALL,B_WILL_DRAW); + AddChild (view); + view->Frame().PrintToStream(); + view->SetOrigin(0.0,0.0); + + // SetFullScreen(true); + } + +SSAwindow::~SSAwindow() + { + int32 result; + + Hide(); + Sync(); + } + +bool SSAwindow::QuitRequested(void) + { + return true; + } + +void SSAwindow::DirectConnected(direct_buffer_info *info) + { + callDirectConnected(info); + } diff --git a/src/servers/screensaver/SSAwindow.h b/src/servers/screensaver/SSAwindow.h new file mode 100644 index 0000000000..94c7e5d95d --- /dev/null +++ b/src/servers/screensaver/SSAwindow.h @@ -0,0 +1,9 @@ +#include "DirectWindow.h" + +class SSAwindow : public BDirectWindow { +public: + SSAwindow(BRect frame); + ~SSAwindow(); + virtual bool QuitRequested(); + virtual void DirectConnected(direct_buffer_info *info); +}; diff --git a/src/servers/screensaver/SSthread.cpp b/src/servers/screensaver/SSthread.cpp new file mode 100644 index 0000000000..28e2705a1d --- /dev/null +++ b/src/servers/screensaver/SSthread.cpp @@ -0,0 +1,50 @@ +#include "ScreenSaverApp.h" +#include +#include +#include +#include + +extern SSstates nextAction; +extern int32 frame; +extern BView *view; +extern BScreenSaver *saver; +extern sem_id ssSem; +extern SSAwindow *win; + +int32 screenSaverThread(void *none) +{ + bool done=false; + while (!done) + switch (nextAction) + { + case DRAW: + saver->Draw(view,frame++); + break; + case DIRECTDRAW: + saver->DirectDraw(frame); + win->Lock(); + saver->Draw(view,frame++); + win->Unlock(); + break; + case STOP: + frame=0; + acquire_sem(ssSem); + break; + case EXIT: + done=true; + delete saver; + break; + } + return 0; +} + +void callDirectConnected (direct_buffer_info *info) +{ + saver->DirectConnected(info); +} + +void callSaverDelete(void) +{ + delete saver; +} + diff --git a/src/servers/screensaver/ScreenSaverApp.cpp b/src/servers/screensaver/ScreenSaverApp.cpp new file mode 100755 index 0000000000..4ae719d30b --- /dev/null +++ b/src/servers/screensaver/ScreenSaverApp.cpp @@ -0,0 +1,263 @@ +#ifndef SCREEN_SAVER_H +#include "ScreenSaverApp.h" +#endif +#include +#include "Screen.h" +#include "image.h" +#include "StorageDefs.h" +#include "FindDirectory.h" +#include "File.h" +#include "Path.h" +#include "string.h" + +extern int32 screenSaverThread(void *); +class BScreenSaver; + +// Yes, these are all global variables. They are shared between the thread +// and this app. +SSstates nextAction; +int32 frame; +BView *view; +BScreenSaver *saver; +sem_id ssSem; +SSAwindow *win; + +extern void callSaverDelete (void); + +/* General note on how this works: + * The semaphore (ssSem) is used to start and stop the render thread. + * When it is time to go blank, the ScreenSaver app thread releases + * the semaphore. The render thread was blocked waiting for it. + * When it is time to stop, the shared variable (nextAction) is set to STOP. + * The thread stops and acquires the semaphore, so that it waits... +*/ + +// Start the server application. Set pulse to fire once per second. +// Run until the application quits. +int main(int, char**) +{ + ScreenSaverApp myApplication; + myApplication.SetPulseRate(1000000); // Fire once per second. + ssSem=create_sem(0,"ScreenSaverSemaphore"); + nextAction=STOP; + myApplication.Run(); + return(0); +} + +// Construct the server app. Doesn't do much, at this point. +ScreenSaverApp::ScreenSaverApp() : BApplication("application/x-vnd.OBOS-ScreenSaverApp") +{ + addon_image=0; + currentTime=0; + win=NULL; +} + + +// This is the main message loop. It spawns a thread that actually runs the screen saver. +void ScreenSaverApp::DispatchMessage(BMessage *msg,BHandler *target) +{ + switch (msg->what) + { + case B_READY_TO_RUN: + { + threadID=spawn_thread(screenSaverThread,"Screen Saver Thread",0,NULL); + LoadSettings(); + // If everything works OK, create a BDirectWindow and start the render thread. + BScreen theScreen(B_MAIN_SCREEN_ID); + win=new SSAwindow(theScreen.Frame()); + resume_thread(threadID); + } + break; + case 'TOPL': + case 'TOPR': + case 'BOTL': + case 'BOTR': + case 'ENDC': + { + if (cornerNow==msg->what) + goBlank(); + else if (cornerNever==msg->what) + disabled=true; + else // We are in the middle or some other corner + { + disabled=false; + unBlank(); + } + } + case 'INPT': + unBlank(); + break; + case NEWDURATION: + int32 dur; + msg->FindInt32("duration",&dur); + setNewDuration(dur); + break; + case B_PULSE: + if (++currentTime==blankTime) + goBlank(); + break; + case B_QUIT_REQUESTED: + nextAction=EXIT; + status_t dummy; // The thread has no return value + wait_for_thread(threadID,&dummy); + BApplication::QuitRequested(); + break; + default: + printf ("Unknown message! %d\n",msg->what); + break; + } +} + +// Load the flattened settings BMessage from disk and parse it. +void ScreenSaverApp::LoadSettings(void) +{ + bool ok=false; + char pathAndFile[1024]; // Yes, this is very long... + BPath path; + + status_t found=find_directory(B_USER_SETTINGS_DIRECTORY,&path); + if (found==B_OK) + { + strncpy(pathAndFile,path.Path(),1023); + strncat(pathAndFile,"/ScreenSaver_settings",1023); + BFile ssSettings(pathAndFile,B_READ_ONLY); + if (B_OK==ssSettings.InitCheck()) + { // File exists. Unflatten the message and call the settings parser. + BMessage settings; + settings.Unflatten(&ssSettings); + parseSettings (&settings); + ok=true; + } + } + if (!ok)// If we can not find a settings file, post quit so that the app will quit right away... + Quit(); +} + +void ScreenSaverApp::LoadAddOn(BMessage *msg) +{ + BScreenSaver *(*instantiate)(BMessage *, image_id ); + image_id addon_image; + char temp[2048]; // Yes, this is a lot... + sprintf (temp,"/boot/beos/system/add-ons/Screen Savers/%s",moduleName); + if (addon_image) // This is a new set of preferences. Free up what we did have + { + unload_add_on(addon_image); + callSaverDelete(); + } + addon_image = load_add_on(temp); + if (addon_image<0) + { + blankTime=-1; + printf ("Unable to open the add-on\n"); + printf ("add on image = %x!\n",addon_image); + } + else + // Look for the one C function that should exist. + if (B_OK != get_image_symbol(addon_image, "instantiate_screen_saver", B_SYMBOL_TYPE_TEXT,(void **) &instantiate)) + { + blankTime=-1; + printf ("Unable to find the instantiator\n"); + printf ("Error = %d\n",get_image_symbol(addon_image, "instantiate_screen_saver", B_SYMBOL_TYPE_TEXT,(void **) &instantiate)); + } + else + saver=instantiate(msg,addon_image); +} + +// Blank the screen. +void ScreenSaverApp::goBlank(void) +{ + if (win && (blankTime> -1) && !disabled) + { + win->SetFullScreen(true); + win->Show(); + win->Sync(); + HideCursor(); + nextAction=DIRECTDRAW; + release_sem(ssSem); // Tell the drawing thread to go and draw. + } +} + +// Unblank. Only works for direct draws. +void ScreenSaverApp::unBlank(void) +{ + if (passwordTime > 0) + { + + } + resetTimer(); + if (win && (nextAction == DIRECTDRAW)) + { + win->SetFullScreen(false); + win->Hide(); + win->Sync(); + ShowCursor(); + nextAction=STOP; + } +} + +// Reset the timer. Keyboard or mouse event. +void ScreenSaverApp::resetTimer(void) +{ + currentTime=0; +} + +// Set a new duration for blanking +void ScreenSaverApp::setNewDuration(int newTimer) +{ + blankTime=newTimer; +} + +void setOnValue(BMessage *msg, char *name, int &result) +{ + int32 value; + if (B_OK == msg->FindInt32(name,&value)) // If screen saving is even enabled + result=value; + // printf ("Read parameter %s, setting it to:%d\n",name,result); +} + +void ScreenSaverApp::parseSettings (BMessage *msg) +{ + int temp; + const char *strPtr,*passwordPointer; + char pathAndFile[1024]; // Yes, this is very long... + BPath path; + + passwordPointer=password; + setOnValue(msg,"timeflags",temp); + if (temp) // If screen saver is enabled, set blanktime. + setOnValue(msg,"timefade",blankTime); + else + blankTime=-1; + // timestandby is not used, for now. + setOnValue(msg,"cornernow",cornerNow); + setOnValue(msg,"cornernever",cornerNever); + passwordTime=-1; // This is pessimistic - assume that password is off OR that a settings load will fail. + setOnValue(msg,"lockenable",temp); + if (temp && (B_OK == msg->FindString("lockmethod",&strPtr))) + { // Get the password. Either from the settings file (that's secure) or the networking file (also secure). + if (strcmp(strPtr,"network")) // Not network, therefore from the settings file + if (B_OK == msg->FindString("lockpassword",&passwordPointer)) + setOnValue(msg,"lockdelay",passwordTime); + else // Get from the network file + { + status_t found=find_directory(B_USER_SETTINGS_DIRECTORY,&path); + if (found==B_OK) + { + FILE *networkFile=NULL; + char buffer[512],*start; + strncpy(pathAndFile,path.Path(),1023); + strncat(pathAndFile,"/network",1023); + // This ugly piece opens the networking file and reads the password, if it exists. + if (networkFile=fopen(pathAndFile,"r")) + while (buffer==fgets(buffer,512,networkFile)) + if (start=strstr(buffer,"PASSWORD =")) + strncpy(password, start+10,strlen(start-11)); + } + } + setOnValue(msg,"lockdelay",passwordTime); + } + if (B_OK != msg->FindString("modulename",&strPtr)) + blankTime=-1; // If the module doesn't exist, never blank. + strcpy(moduleName,strPtr); + LoadAddOn(msg); +} diff --git a/src/servers/screensaver/ScreenSaverApp.h b/src/servers/screensaver/ScreenSaverApp.h new file mode 100755 index 0000000000..ce13e13eff --- /dev/null +++ b/src/servers/screensaver/ScreenSaverApp.h @@ -0,0 +1,37 @@ +#ifndef SCREEN_SAVER_H +#define SCREEN_SAVER_H + +#ifndef _APPLICATION_H +#include +#endif +#include "SSAwindow.h" + +enum screenSaverWhat {GOBLANK=48, UNBLANK=49, RESET=50, NEWDURATION=51, SETNEWSAVER=52}; +enum SSstates {STOP,EXIT,DRAW,DIRECTDRAW}; + +class ScreenSaverApp : public BApplication +{ +public: + ScreenSaverApp(); + virtual void DispatchMessage(BMessage *msg,BHandler *target); + void goBlank(void); + void unBlank(void); + void resetTimer(void); + void LoadSettings(void); + void LoadAddOn(BMessage *msg); + void setNewDuration(int newTimer); + void parseSettings(BMessage *newSSMessage); +private: + int blankTime; + int currentTime; + int cornerNow; + int cornerNever; + int passwordTime; + bool disabled; + char moduleName[1024]; + char password[1024]; + thread_id threadID; + image_id addon_image; +}; + +#endif //SCREEN_SAVER_H diff --git a/src/tests/Jamfile b/src/tests/Jamfile new file mode 100644 index 0000000000..4fa235b655 --- /dev/null +++ b/src/tests/Jamfile @@ -0,0 +1,3 @@ +SubDir OBOS_TOP sources tests ; + +SubInclude OBOS_TOP sources tests kits ; \ No newline at end of file diff --git a/src/tests/add-ons/kernel/file_systems/befs/array/array.cpp b/src/tests/add-ons/kernel/file_systems/befs/array/array.cpp new file mode 100644 index 0000000000..738f302225 --- /dev/null +++ b/src/tests/add-ons/kernel/file_systems/befs/array/array.cpp @@ -0,0 +1,66 @@ +#include "Utility.h" + +#include +#include +#include + + +const int32 kBlockSize = 1024; + +int32 gNumber = 100000; +BList gList; +BlockArray gArray(kBlockSize); + + +void +dumpArray() +{ + printf(" items in array: %ld\n",gArray.CountItems()); + printf(" blocks used: %ld\n",gArray.BlocksUsed()); + printf(" size: %ld\n",gArray.Size()); +} + + +int +main(int argc,char **argv) +{ + srand(42); + + // insert numbers in the array + + for (int32 i = 0;i < gNumber;i++) { + int32 num = rand(); + if (num == 0) + num++; + + if (gArray.Insert(num) == B_OK) + gList.AddItem((void *)num); + else if (gArray.Find(num) < 0) { + printf("Could not insert entry in array, but it's not in there either...\n"); + dumpArray(); + } else + printf("hola\n"); + } + + // check for numbers in the array + + for (int32 i = 0;i < gNumber;i++) { + int32 num = (int32)gList.ItemAt(i); + + if (gArray.Find(num) < 0) { + printf("could not found entry %ld in array!\n",num); + dumpArray(); + } + } + + // iterate through the array + + sorted_array *array = gArray.Array(); + for (int32 i = 0;i < array->count;i++) { + if (!gList.HasItem((void *)array->values[i])) { + printf("Could not find entry %Ld at %ld in list!\n",array->values[i],i); + dumpArray(); + } + } + return 0; +} diff --git a/src/tests/add-ons/kernel/file_systems/befs/array/smallArray.cpp b/src/tests/add-ons/kernel/file_systems/befs/array/smallArray.cpp new file mode 100644 index 0000000000..5976204828 --- /dev/null +++ b/src/tests/add-ons/kernel/file_systems/befs/array/smallArray.cpp @@ -0,0 +1,33 @@ +#include "Utility.h" + +#include +#include +#include + + +int32 gIterations = 1000000; +int32 gNumber = 8; + + +int +main(int argc,char **argv) +{ + char buffer[1024]; + sorted_array *array = (sorted_array *)buffer; + array->count = 0; + + srand(42); + + for (int32 i = 0;i < gIterations;i++) { + // add entries to the array + + for (int32 num = 0;num < gNumber;num++) + array->Insert(rand()); + + for (int32 num = 0;num < gNumber;num++) { + int32 index = int32(1.0 * rand() * array->count / RAND_MAX); + array->Remove(array->values[index]); + } + } + return 0; +} diff --git a/src/tests/add-ons/kernel/file_systems/befs/btree/Inode.cpp b/src/tests/add-ons/kernel/file_systems/befs/btree/Inode.cpp new file mode 100644 index 0000000000..2d38e76cee --- /dev/null +++ b/src/tests/add-ons/kernel/file_systems/befs/btree/Inode.cpp @@ -0,0 +1,53 @@ +/* Inode - emulation for the B+Tree torture test +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include "Inode.h" +#include "Volume.h" +#include "Journal.h" + + +Inode::Inode(const char *name,int32 mode) + : + fMode(mode) +{ + fFile.SetTo(name,B_CREATE_FILE | B_READ_WRITE | B_ERASE_FILE); + fSize = 0; + fVolume = new Volume(&fFile); +} + + +Inode::~Inode() +{ + delete fVolume; +} + + +status_t +Inode::FindBlockRun(off_t pos, block_run &run, off_t &offset) +{ + // the whole file data is covered by this one block_run structure... + run.SetTo(0,0,1); + offset = 0; + return B_OK; +} + + +status_t +Inode::Append(Transaction *transaction, off_t bytes) +{ + return SetFileSize(transaction,Size() + bytes); +} + + +status_t +Inode::SetFileSize(Transaction *, off_t bytes) +{ + //printf("set size = %ld\n",bytes); + fSize = bytes; + return fFile.SetSize(bytes); +} + diff --git a/src/tests/add-ons/kernel/file_systems/befs/btree/Inode.h b/src/tests/add-ons/kernel/file_systems/befs/btree/Inode.h new file mode 100644 index 0000000000..0eb2a25ff2 --- /dev/null +++ b/src/tests/add-ons/kernel/file_systems/befs/btree/Inode.h @@ -0,0 +1,52 @@ +#ifndef INODE_H +#define INODE_H +/* Inode - emulation for the B+Tree torture test +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include +#include + +#include "Lock.h" +#include "bfs.h" + + +class Volume; +class Transaction; + + +class Inode { + public: + Inode(const char *name,int32 mode = S_STR_INDEX | S_ALLOW_DUPS); + ~Inode(); + + ReadWriteLock &Lock() { return fLock; } + + status_t FindBlockRun(off_t pos,block_run &run,off_t &offset); + status_t Append(Transaction *,off_t bytes); + status_t SetFileSize(Transaction *,off_t bytes); + + Volume *GetVolume() const { return fVolume; } + off_t ID() const { return 0; } + int32 Mode() const { return fMode; } + char *Name() const { return "whatever"; } + block_run BlockRun() const { return block_run::Run(0,0,0); } + block_run Parent() const { return block_run::Run(0,0,0); } + off_t BlockNumber() const { return 0; } + bfs_inode *Node() { return (bfs_inode *)1; } + + off_t Size() const { return fSize; } + bool IsDirectory() const { return true; } + + private: + Volume *fVolume; + BFile fFile; + off_t fSize; + ReadWriteLock fLock; + int32 fMode; +}; + +#endif /* INODE_H */ diff --git a/src/tests/add-ons/kernel/file_systems/befs/btree/Journal.h b/src/tests/add-ons/kernel/file_systems/befs/btree/Journal.h new file mode 100644 index 0000000000..db19c82ec1 --- /dev/null +++ b/src/tests/add-ons/kernel/file_systems/befs/btree/Journal.h @@ -0,0 +1,42 @@ +#ifndef JOURNAL_H +#define JOURNAL_H +/* Journal - emulation for the B+Tree torture test +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include + +#include "Volume.h" +#include "Debug.h" +#include "cache.h" + + +class Transaction { + public: + Transaction(Volume *volume,off_t refBlock) + : + fVolume(volume) + { + } + + ~Transaction() + { + } + + status_t WriteBlocks(off_t blockNumber,const uint8 *buffer,size_t numBlocks = 1) + { + return cached_write(fVolume->Device(),blockNumber,buffer,numBlocks,fVolume->BlockSize()); + } + + void Done() + { + } + + protected: + Volume *fVolume; +}; + +#endif /* JOURNAL_H */ diff --git a/src/tests/add-ons/kernel/file_systems/befs/btree/Volume.cpp b/src/tests/add-ons/kernel/file_systems/befs/btree/Volume.cpp new file mode 100644 index 0000000000..3529d7d119 --- /dev/null +++ b/src/tests/add-ons/kernel/file_systems/befs/btree/Volume.cpp @@ -0,0 +1,18 @@ +/* Volume - emulation for the B+Tree torture test +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include "Volume.h" + +#include + + +void +Volume::Panic() +{ + printf("PANIC!\n"); +} + diff --git a/src/tests/add-ons/kernel/file_systems/befs/btree/Volume.h b/src/tests/add-ons/kernel/file_systems/befs/btree/Volume.h new file mode 100644 index 0000000000..74aa5f32e5 --- /dev/null +++ b/src/tests/add-ons/kernel/file_systems/befs/btree/Volume.h @@ -0,0 +1,36 @@ +#ifndef VOLUME_H +#define VOLUME_H +/* Volume - emulation for the B+Tree torture test +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include + +#include "Lock.h" +#include "bfs.h" + + +class BFile; + + +class Volume { + public: + Volume(BFile *file) : fFile(file) {} + + BFile *Device() { return fFile; } + + int32 BlockSize() const { return 1024; } + off_t ToBlock(block_run run) const { return run.start; } + block_run ToBlockRun(off_t block) const { return block_run::Run(0,0,block); } + + static void Panic(); + + private: + BFile *fFile; +}; + + +#endif /* VOLUME_H */ diff --git a/src/tests/add-ons/kernel/file_systems/befs/btree/cache.cpp b/src/tests/add-ons/kernel/file_systems/befs/btree/cache.cpp new file mode 100644 index 0000000000..2b9275188a --- /dev/null +++ b/src/tests/add-ons/kernel/file_systems/befs/btree/cache.cpp @@ -0,0 +1,106 @@ +/* cache - emulation for the B+Tree torture test +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include "cache.h" + +#include +#include + +#include +#include + + +/* A note from the author: this cache implementation can only be used + * with the test program, it really suites no other needs. + * It's very simple and not that efficient, and simple holds the whole + * file in memory, all the time. + */ + + +BList gBlocks; + + +void +init_cache(BFile */*file*/,int32 /*blockSize*/) +{ +} + + +void +shutdown_cache(BFile *file,int32 blockSize) +{ + for (int32 i = 0;i < gBlocks.CountItems();i++) { + void *buffer = gBlocks.ItemAt(i); + if (buffer == NULL) { + printf("cache is corrupt!\n"); + exit(-1); + } + file->WriteAt(i * blockSize,buffer,blockSize); + free(buffer); + } +} + + +static status_t +readBlocks(BFile *file,uint32 num,uint32 size) +{ + for (int32 i = gBlocks.CountItems();i <= num;i++) { + void *buffer = malloc(size); + if (buffer == NULL) + return B_NO_MEMORY; + + gBlocks.AddItem(buffer); + if (file->ReadAt(i * size,buffer,size) < B_OK) + return B_IO_ERROR; + } + return B_OK; +} + + +int +cached_write(BFile *file, off_t num,const void *data,off_t numBlocks, int blockSize) +{ + //printf("cached_write(num = %Ld,data = %p,numBlocks = %Ld,blockSize = %ld)\n",num,data,numBlocks,blockSize); + if (file == NULL) + return B_BAD_VALUE; + + if (num >= gBlocks.CountItems()) + puts("Oh no!"); + + void *buffer = gBlocks.ItemAt(num); + if (buffer == NULL) + return B_BAD_VALUE; + + if (buffer != data && numBlocks == 1) + memcpy(buffer,data,blockSize); + + return B_OK; +} + + +void * +get_block(BFile *file, off_t num, int blockSize) +{ + //printf("get_block(num = %Ld,blockSize = %ld)\n",num,blockSize); + if (file == NULL) + return NULL; + + if (num >= gBlocks.CountItems()) + readBlocks(file,num,blockSize); + + return gBlocks.ItemAt(num); +} + + +int +release_block(BFile *file, off_t num) +{ + //printf("release_block(num = %Ld)\n",num); + return 0; +} + + diff --git a/src/tests/add-ons/kernel/file_systems/befs/btree/cache.h b/src/tests/add-ons/kernel/file_systems/befs/btree/cache.h new file mode 100644 index 0000000000..0b260f792d --- /dev/null +++ b/src/tests/add-ons/kernel/file_systems/befs/btree/cache.h @@ -0,0 +1,22 @@ +#ifndef CACHE_H +#define CACHE_H +/* cache - emulation for the B+Tree torture test +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include + +class BFile; + + +extern void init_cache(BFile *file, int32 blockSize); +extern void shutdown_cache(BFile *file, int32 blockSize); + +extern int cached_write(BFile *file, off_t bnum, const void *data,off_t num_blocks, int bsize); +extern void *get_block(BFile *file, off_t bnum, int bsize); +extern int release_block(BFile *file, off_t bnum); + +#endif /* CACHE_H */ diff --git a/src/tests/add-ons/kernel/file_systems/befs/btree/cpp.h b/src/tests/add-ons/kernel/file_systems/befs/btree/cpp.h new file mode 100644 index 0000000000..0b8faf6264 --- /dev/null +++ b/src/tests/add-ons/kernel/file_systems/befs/btree/cpp.h @@ -0,0 +1,5 @@ +/* cpp - emulation for the B+Tree torture test +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ diff --git a/src/tests/add-ons/kernel/file_systems/befs/btree/test.cpp b/src/tests/add-ons/kernel/file_systems/befs/btree/test.cpp new file mode 100644 index 0000000000..ab7ed32eac --- /dev/null +++ b/src/tests/add-ons/kernel/file_systems/befs/btree/test.cpp @@ -0,0 +1,720 @@ +/* test - BFS B+Tree torture test +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include "Volume.h" +#include "Inode.h" +#include "BPlusTree.h" + +#include + +#include +#include +#include +#include +#include + + +#define DEFAULT_ITERATIONS 10 +#define DEFAULT_NUM_KEYS 100 +#define DEFAULT_KEY_TYPE S_STR_INDEX + +#define MIN_STRING 3 +#define MAX_STRING 256 + +struct key { + void *data; + uint32 length; + int32 in; + int32 count; + off_t value; +}; + +key *gKeys; +int32 gNum = DEFAULT_NUM_KEYS; +int32 gType = DEFAULT_KEY_TYPE; +int32 gTreeCount = 0; +bool gVerbose,gExcessive; +int32 gIterations = DEFAULT_ITERATIONS; +Volume *gVolume; +int32 gSeed = 42; + +// from cache.cpp (yes, we are that mean) +extern BList gBlocks; + + +// prototypes +void bailOut(); +void bailOutWithKey(void *key, uint16 length); +void dumpTree(); +void dumpKey(void *key, int32 length); +void dumpKeys(); + + +void +dumpTree() +{ + puts("\n*** Tree-Dump:\n"); + + bplustree_header *header = (bplustree_header *)gBlocks.ItemAt(0); + dump_bplustree_header(header); + + for (int32 i = 1;i < gBlocks.CountItems();i++) { + bplustree_node *node = (bplustree_node *)gBlocks.ItemAt(i); + printf("\n--- %s node at %ld --------------------------------------\n", + node->overflow_link == BPLUSTREE_NULL ? "leaf" : "index", + i * BPLUSTREE_NODE_SIZE); + dump_bplustree_node(node,header,gVolume); + } +} + + +void +bailOut() +{ + if (gVerbose) { + // dump the tree + dumpTree(); + } + + // in any case, write the tree back to disk + shutdown_cache(gVolume->Device(),gVolume->BlockSize()); + exit(-1); +} + + +void +bailOutWithKey(void *key,uint16 length) +{ + dumpKey(key,length); + putchar('\n'); + bailOut(); +} + + +void +dumpKey(void *key,int32 length) +{ + switch (gType) { + case S_STR_INDEX: + printf("\"%s\" (%ld bytes)",key,length); + break; + case S_INT_INDEX: + printf("%ld",*(int32 *)key); + break; + case S_UINT_INDEX: + printf("%lu",*(uint32 *)key); + break; + case S_LONG_LONG_INDEX: + printf("%Ld",*(int64 *)key); + break; + case S_ULONG_LONG_INDEX: + printf("%Lu",*(uint64 *)key); + break; + case S_FLOAT_INDEX: + printf("%g",*(float *)key); + break; + case S_DOUBLE_INDEX: + printf("%g",*(double *)key); + break; + } + if ((gType == S_INT_INDEX || gType == S_UINT_INDEX || gType == S_FLOAT_INDEX) + && length != 4) + printf(" (wrong length %ld)",length); + else if ((gType == S_LONG_LONG_INDEX || gType == S_ULONG_LONG_INDEX || gType == S_DOUBLE_INDEX) + && length != 8) + printf(" (wrong length %ld)",length); +} + + +void +dumpKeys() +{ + char *type; + switch (gType) { + case S_STR_INDEX: + type = "string"; + break; + case S_INT_INDEX: + type = "int32"; + break; + case S_UINT_INDEX: + type = "uint32"; + break; + case S_LONG_LONG_INDEX: + type = "int64"; + break; + case S_ULONG_LONG_INDEX: + type = "uint64"; + break; + case S_FLOAT_INDEX: + type = "float"; + break; + case S_DOUBLE_INDEX: + type = "double"; + break; + } + printf("Dumping %ld keys of type %s\n",gNum,type); + + for (int32 i = 0;i < gNum;i++) { + printf("% 8ld. (%3ld) key = ",i,gKeys[i].in); + dumpKey(gKeys[i].data,gKeys[i].length); + putchar('\n'); + } +} + + +// #pragma mark - +// +// Functions to generate the keys in every available type +// + + +void +generateName(int32 i,char *name,int32 *_length) +{ + // We're using the index position as a hint for the length + // of the string - this way, it's much less expansive to + // test for string uniqueness. + // We don't want to sort the strings to have more realistic + // access patterns to the tree (only true for the strings test). + int32 length = i % (MAX_STRING - MIN_STRING) + MIN_STRING; + for (int32 i = 0;i < length;i++) { + int32 c = int32(52.0 * rand() / RAND_MAX); + if (c >= 26) + name[i] = 'A' + c - 26; + else + name[i] = 'a' + c; + } + name[length] = 0; + *_length = length; +} + + +void +fillBuffer(void *buffer,int32 start) +{ + for (int32 i = 0;i < gNum;i++) { + switch (gType) { + case S_INT_INDEX: + { + int32 *array = (int32 *)buffer; + array[i] = start + i; + break; + } + case S_UINT_INDEX: + { + uint32 *array = (uint32 *)buffer; + array[i] = start + i; + break; + } + case S_LONG_LONG_INDEX: + { + int64 *array = (int64 *)buffer; + array[i] = start + i; + break; + } + case S_ULONG_LONG_INDEX: + { + uint64 *array = (uint64 *)buffer; + array[i] = start + i; + break; + } + case S_FLOAT_INDEX: + { + float *array = (float *)buffer; + array[i] = start + i * 1.0001; + break; + } + case S_DOUBLE_INDEX: + { + double *array = (double *)buffer; + array[i] = start + i * 1.0001; + break; + } + } + gKeys[i].value = i; + } +} + + +bool +findKey(void *key,int32 length,int32 maxIndex) +{ + for (int32 i = length;i < maxIndex;i += MAX_STRING - MIN_STRING) { + if (length == gKeys[i].length + && !memcpy(key,gKeys[i].data,length)) + return true; + } + return false; +} + + +status_t +createKeys() +{ + gKeys = (key *)malloc(gNum * sizeof(key)); + if (gKeys == NULL) + return B_NO_MEMORY; + + if (gType == S_STR_INDEX) { + for (int32 i = 0;i < gNum;i++) { + char name[B_FILE_NAME_LENGTH]; + int32 length,tries = 0; + bool last; + + // create unique keys! + do { + generateName(i,name,&length); + } while ((last = findKey(name,length,i)) && tries++ < 100); + + if (last) { + printf("Couldn't create unique key list!\n"); + dumpKeys(); + bailOut(); + } + + gKeys[i].data = malloc(length + 1); + memcpy(gKeys[i].data,name,length + 1); + gKeys[i].length = length; + gKeys[i].in = 0; + gKeys[i].count = 0; + gKeys[i].value = i; + } + } else { + int32 length; + int32 start = 0; + switch (gType) { + case S_FLOAT_INDEX: + case S_INT_INDEX: + start = -gNum / 2; + case S_UINT_INDEX: + length = 4; + break; + case S_DOUBLE_INDEX: + case S_LONG_LONG_INDEX: + start = -gNum / 2; + case S_ULONG_LONG_INDEX: + length = 8; + break; + default: + return B_BAD_VALUE; + } + uint8 *buffer = (uint8 *)malloc(length * gNum); + if (buffer == NULL) + return B_NO_MEMORY; + + for (int32 i = 0;i < gNum;i++) { + gKeys[i].data = (void *)(buffer + i * length); + gKeys[i].length = length; + gKeys[i].in = 0; + gKeys[i].count = 0; + } + fillBuffer(buffer,start); + } + return B_OK; +} + + +// #pragma mark - +// +// Tree validity checker +// + + +void +checkTreeContents(BPlusTree *tree) +{ + // reset counter + for (int32 i = 0;i < gNum;i++) + gKeys[i].count = 0; + + TreeIterator iterator(tree); + char key[B_FILE_NAME_LENGTH]; + uint16 length,duplicate; + off_t value; + status_t status; + while ((status = iterator.GetNextEntry(key,&length,B_FILE_NAME_LENGTH,&value,&duplicate)) == B_OK) { + if (value < 0 || value >= gNum) { + iterator.Dump(); + printf("\ninvalid value %Ld in tree: ",value); + bailOutWithKey(key,length); + } + if (gKeys[value].value != value) { + iterator.Dump(); + printf("\nkey pointing to the wrong value %Ld (should be %Ld)\n",value,gKeys[value].value); + bailOutWithKey(key,length); + } + if (length != gKeys[value].length + || memcmp(key,gKeys[value].data,length)) { + iterator.Dump(); + printf("\nkeys don't match (key index = %Ld, %ld times in tree, %ld. occassion):\n\tfound: ",value,gKeys[value].in,gKeys[value].count + 1); + dumpKey(key,length); + printf("\n\texpected: "); + dumpKey(gKeys[value].data,gKeys[value].length); + putchar('\n'); + bailOut(); + } + + gKeys[value].count++; + } + if (status != B_ENTRY_NOT_FOUND) { + printf("TreeIterator::GetNext() returned: %s\n",strerror(status)); + iterator.Dump(); + bailOut(); + } + + for (int32 i = 0;i < gNum;i++) { + if (gKeys[i].in != gKeys[i].count) { + printf("Key "); + dumpKey(gKeys[i].data,gKeys[i].length); + printf(" found only %ld from %ld\n",gKeys[i].count,gKeys[i].in); + } + } +} + + +void +checkTreeIntegrity(BPlusTree *tree) +{ + // simple test, just seeks down to every key - if it couldn't + // be found, something must be wrong + + TreeIterator iterator(tree); + for (int32 i = 0;i < gNum;i++) { + if (gKeys[i].in == 0) + continue; + + status_t status = iterator.Find((uint8 *)gKeys[i].data,gKeys[i].length); + if (status != B_OK) { + printf("TreeIterator::Find() returned: %s\n",strerror(status)); + bailOutWithKey(gKeys[i].data,gKeys[i].length); + } + } +} + + +void +checkTree(BPlusTree *tree) +{ + if (!gExcessive) + printf("* Check tree...\n"); + + checkTreeContents(tree); + checkTreeIntegrity(tree); +} + + +// #pragma mark - +// +// The tree "torture" functions +// + + +void +addAllKeys(Transaction *transaction,BPlusTree *tree) +{ + printf("*** Adding all keys to the tree...\n"); + for (int32 i = 0;i < gNum;i++) { + status_t status = tree->Insert(transaction,(uint8 *)gKeys[i].data,gKeys[i].length,gKeys[i].value); + if (status < B_OK) { + printf("BPlusTree::Insert() returned: %s\n",strerror(status)); + printf("key: "); + dumpKey(gKeys[i].data,gKeys[i].length); + putchar('\n'); + } + else { + gKeys[i].in++; + gTreeCount++; + } + } + checkTree(tree); +} + + +void +duplicateTest(Transaction *transaction,BPlusTree *tree) +{ + int32 index = int32(1.0 * gNum * rand() / RAND_MAX); + if (index == gNum) + index = gNum - 1; + + printf("*** Duplicate test with key "); + dumpKey(gKeys[index].data,gKeys[index].length); + puts("..."); + + status_t status; + + int32 insertTotal = 0; + for (int32 i = 0;i < 8;i++) { + int32 insertCount = int32(1000.0 * rand() / RAND_MAX); + if (gVerbose) + printf("* insert %ld to %ld old entries...\n",insertCount,insertTotal + gKeys[index].in); + + for (int32 j = 0;j < insertCount;j++) { + status = tree->Insert(transaction,(uint8 *)gKeys[index].data,gKeys[index].length,insertTotal); + if (status < B_OK) { + printf("BPlusTree::Insert() returned: %s\n",strerror(status)); + bailOutWithKey(gKeys[index].data,gKeys[index].length); + } + insertTotal++; + gTreeCount++; + + if (gExcessive) + checkTree(tree); + } + + int32 count; + if (i < 7) { + count = int32(1000.0 * rand() / RAND_MAX); + if (count > insertTotal) + count = insertTotal; + } else + count = insertTotal; + + if (gVerbose) + printf("* remove %ld from %ld entries...\n",count,insertTotal + gKeys[index].in); + + for (int32 j = 0;j < count;j++) { + status_t status = tree->Remove(transaction,(uint8 *)gKeys[index].data,gKeys[index].length,insertTotal - 1); + if (status < B_OK) { + printf("BPlusTree::Remove() returned: %s\n",strerror(status)); + bailOutWithKey(gKeys[index].data,gKeys[index].length); + } + insertTotal--; + gTreeCount--; + + if (gExcessive) + checkTree(tree); + } + } + + if (!gExcessive) + checkTree(tree); +} + + +void +addRandomSet(Transaction *transaction,BPlusTree *tree,int32 num) +{ + printf("*** Add random set to tree (%ld to %ld old entries)...\n",num,gTreeCount); + + for (int32 i = 0;i < num;i++) { + int32 index = int32(1.0 * gNum * rand() / RAND_MAX); + if (index == gNum) + index = gNum - 1; + + if (gVerbose) + printf("adding key %ld (%ld times in the tree)\n",index,gKeys[index].in); + + status_t status = tree->Insert(transaction,(uint8 *)gKeys[index].data,gKeys[index].length,gKeys[index].value); + if (status < B_OK) { + printf("BPlusTree::Insert() returned: %s\n",strerror(status)); + bailOutWithKey(gKeys[index].data,gKeys[index].length); + } + gKeys[index].in++; + gTreeCount++; + + if (gExcessive) + checkTree(tree); + } + if (!gExcessive) + checkTree(tree); +} + + +void +removeRandomSet(Transaction *transaction,BPlusTree *tree,int32 num) +{ + printf("*** Remove random set from tree (%ld from %ld entries)...\n",num,gTreeCount); + + int32 tries = 500; + + for (int32 i = 0;i < num;i++) { + if (gTreeCount < 1) + break; + + int32 index = int32(1.0 * gNum * rand() / RAND_MAX); + if (index == gNum) + index = gNum - 1; + + if (gKeys[index].in == 0) { + i--; + if (tries-- < 0) + break; + continue; + } + + if (gVerbose) + printf("removing key %ld (%ld times in the tree)\n",index,gKeys[index].in); + + status_t status = tree->Remove(transaction,(uint8 *)gKeys[index].data,gKeys[index].length,gKeys[index].value); + if (status < B_OK) { + printf("BPlusTree::Remove() returned: %s\n",strerror(status)); + bailOutWithKey(gKeys[index].data,gKeys[index].length); + } + gKeys[index].in--; + gTreeCount--; + + if (gExcessive) + checkTree(tree); + } + if (!gExcessive) + checkTree(tree); +} + + +// #pragma mark - + + +void +usage(char *program) +{ + if (strrchr(program,'/')) + program = strrchr(program,'/') + 1; + fprintf(stderr,"usage: %s [-ve] [-t type] [-n keys] [-i iterations] [-r seed]\n" + "BFS B+Tree torture test\n" + "\t-t\ttype is one of string, int32, uint32, int64, uint64, float,\n" + "\t\tor double; defaults to string.\n" + "\t-n\tkeys is the number of keys to be used,\n" + "\t\tminimum is 1, defaults to %ld.\n" + "\t-i\titerations is the number of the test cycles, defaults to %ld.\n" + "\t-r\tthe seed for the random function, defaults to %ld.\n" + "\t-e\texcessive validity tests: tree contents will be tested after every operation\n" + "\t-v\tfor verbose output.\n", + program,DEFAULT_NUM_KEYS,DEFAULT_ITERATIONS,gSeed); + exit(0); +} + + +int +main(int argc,char **argv) +{ + char *program = argv[0]; + + while (*++argv) + { + char *arg = *argv; + if (*arg == '-') + { + if (arg[1] == '-') + usage(program); + + while (*++arg && isalpha(*arg)) + { + switch (*arg) + { + case 'v': + gVerbose = true; + break; + case 'e': + gExcessive = true; + break; + case 't': + if (*++argv == NULL) + usage(program); + + if (!strcmp(*argv,"string")) + gType = S_STR_INDEX; + else if (!strcmp(*argv,"int32") + || !strcmp(*argv,"int")) + gType = S_INT_INDEX; + else if (!strcmp(*argv,"uint32") + || !strcmp(*argv,"uint")) + gType = S_UINT_INDEX; + else if (!strcmp(*argv,"int64") + || !strcmp(*argv,"llong")) + gType = S_LONG_LONG_INDEX; + else if (!strcmp(*argv,"uint64") + || !strcmp(*argv,"ullong")) + gType = S_ULONG_LONG_INDEX; + else if (!strcmp(*argv,"float")) + gType = S_FLOAT_INDEX; + else if (!strcmp(*argv,"double")) + gType = S_DOUBLE_INDEX; + else + usage(program); + break; + case 'n': + if (*++argv == NULL || !isdigit(**argv)) + usage(program); + + gNum = atoi(*argv); + if (gNum < 1) + gNum = 1; + break; + case 'i': + if (*++argv == NULL || !isdigit(**argv)) + usage(program); + + gIterations = atoi(*argv); + if (gIterations < 1) + gIterations = 1; + break; + case 'r': + if (*++argv == NULL || !isdigit(**argv)) + usage(program); + + gSeed = atoi(*argv); + break; + } + } + } + else + break; + } + + // we do want to have reproducible random keys + if (gVerbose) + printf("Set seed to %ld\n",gSeed); + srand(gSeed); + + Inode inode("tree.data",gType | S_ALLOW_DUPS); + gVolume = inode.GetVolume(); + Transaction transaction(gVolume,0); + + init_cache(gVolume->Device(),gVolume->BlockSize()); + + // + // Create the tree, the keys, and add all keys to the tree initially + // + + BPlusTree tree(&transaction,&inode); + status_t status; + if ((status = tree.InitCheck()) < B_OK) { + fprintf(stderr,"creating tree failed: %s\n",strerror(status)); + bailOut(); + } + printf("*** Creating %ld keys...\n",gNum); + if ((status = createKeys()) < B_OK) { + fprintf(stderr,"creating keys failed: %s\n",strerror(status)); + bailOut(); + } + + if (gVerbose) + dumpKeys(); + + addAllKeys(&transaction,&tree); + + // + // Run the tests (they will exit the app, if an error occurs) + // + + for (int32 i = 0;i < gIterations;i++) { + printf("---------- Test iteration %ld ---------------------------------\n",i+1); + + addRandomSet(&transaction,&tree,int32(1.0 * gNum * rand() / RAND_MAX)); + removeRandomSet(&transaction,&tree,int32(1.0 * gNum * rand() / RAND_MAX)); + duplicateTest(&transaction,&tree); + } + + // of course, we would have to free all our memory in a real application here... + + // write the cache back to the tree + shutdown_cache(gVolume->Device(),gVolume->BlockSize()); + return 0; +} + diff --git a/src/tests/add-ons/kernel/file_systems/befs/queries/test.cpp b/src/tests/add-ons/kernel/file_systems/befs/queries/test.cpp new file mode 100644 index 0000000000..c090e478aa --- /dev/null +++ b/src/tests/add-ons/kernel/file_systems/befs/queries/test.cpp @@ -0,0 +1,163 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + + +#define DUMPED_BLOCK_SIZE 16 +#define Print printf + +void +dumpBlock(const char *buffer,int size) +{ + for(int i = 0;i < size;) { + int start = i; + + for(;i < start+DUMPED_BLOCK_SIZE;i++) { + if (!(i % 4)) + Print(" "); + + if (i >= size) + Print(" "); + else + Print("%02x",*(unsigned char *)(buffer+i)); + } + Print(" "); + + for(i = start;i < start + DUMPED_BLOCK_SIZE;i++) { + if (i < size) { + char c = *(buffer+i); + + if (c < 30) + Print("."); + else + Print("%c",c); + } + else + break; + } + Print("\n"); + } +} + + +void +createFile(int32 num) +{ + char name[B_FILE_NAME_LENGTH]; + sprintf(name,"./_query_test_%ld",num); + + BFile file(name,B_CREATE_FILE | B_WRITE_ONLY); +} + + +BEntry * +getEntry(int32 num) +{ + char name[B_FILE_NAME_LENGTH]; + sprintf(name,"./_query_test_%ld",num); + + return new BEntry(name); +} + + +status_t +waitForMessage(port_id port,const char *string,int32 op,char *name) +{ + puts(string); + + int32 msg; + char buffer[1024]; + ssize_t bytes = read_port_etc(port,&msg,buffer,sizeof(buffer),B_TIMEOUT,1000000); + if (op == B_TIMED_OUT && bytes == B_TIMED_OUT) { + puts(" passed, timed out!\n"); + return bytes; + } + if (bytes < B_OK) { + printf("-> %s\n\n",strerror(bytes)); + return bytes; + } + + BMessage message; + if (message.Unflatten(buffer) < B_OK) { + printf("could not unflatten message:\n"); + dumpBlock(buffer,bytes); + return B_BAD_DATA; + } + + if (message.what != B_QUERY_UPDATE + || message.FindInt32("opcode") != op) { + printf("Expected what = %lx, opcode = %ld, got:",B_QUERY_UPDATE,op); + message.PrintToStream(); + putchar('\n'); + return message.FindInt32("opcode"); + } + puts(" passed!\n"); + return op; +} + + +int +main(int argc,char **argv) +{ + port_id port = create_port(100,"query port"); + printf("port id = %ld\n",port); + printf(" B_ENTRY_REMOVED = %ld, B_ENTRY_CREATED = %ld\n\n",B_ENTRY_REMOVED,B_ENTRY_CREATED); + + dev_t device = dev_for_path("."); + DIR *query = fs_open_live_query(device,"name=_query_test_*",B_LIVE_QUERY,port,12345); + + createFile(1); + waitForMessage(port,"File 1 created:",B_ENTRY_CREATED,"_query_test_1"); + + createFile(2); + waitForMessage(port,"File 2 created:",B_ENTRY_CREATED,"_query_test_2"); + + BEntry *entry = getEntry(2); + if (entry->InitCheck() < B_OK) { + fprintf(stderr,"Could not get entry for file 2\n"); + fs_close_query(query); + return -1; + } + entry->Rename("_some_other_name_"); + waitForMessage(port,"File 2 renamed (should fall out of query):",B_ENTRY_REMOVED,NULL); + + entry->Rename("_some_other_"); + waitForMessage(port,"File 2 renamed again (should time out):",B_TIMED_OUT,NULL); + + entry->Rename("_query_test_2"); + waitForMessage(port,"File 2 renamed back (should be added to query):",B_ENTRY_CREATED,"_query_test_2"); + + entry->Rename("_query_test_2_and_more"); + status_t status = waitForMessage(port,"File 2 renamed (should stay in query, time out):",B_TIMED_OUT,"_query_test_2_and_more"); + if (status == B_ENTRY_REMOVED) + waitForMessage(port,"Received B_ENTRY_REMOVED, now expecting file 2 to be added again:",B_ENTRY_CREATED,NULL); + + entry->Remove(); + delete entry; + waitForMessage(port,"File 2 removed:",B_ENTRY_REMOVED,NULL); + + entry = getEntry(1); + if (entry->InitCheck() < B_OK) { + fprintf(stderr,"Could not get entry for file 1\n"); + fs_close_query(query); + return -1; + } + + entry->Rename("_some_other_name_"); + waitForMessage(port,"File 1 renamed (should fall out of query):",B_ENTRY_REMOVED,NULL); + + entry->Remove(); + delete entry; + waitForMessage(port,"File 1 removed (should time out):",B_TIMED_OUT,NULL); + + fs_close_query(query); + + return 0; +} + diff --git a/src/tests/add-ons/kernel/file_systems/befs/randomread/randomread.cpp b/src/tests/add-ons/kernel/file_systems/befs/randomread/randomread.cpp new file mode 100644 index 0000000000..68521518f8 --- /dev/null +++ b/src/tests/add-ons/kernel/file_systems/befs/randomread/randomread.cpp @@ -0,0 +1,204 @@ +/* randomread - tests if the read functions of a file system work correctly +** by reading arbitrary bytes at arbitrary positions of a file previously +** created. +** The idea is to be able to calculate the contents on each position +** of the file. It currently only counts numbers, beginning from zero, +** which is probably not a really good test. +** But if there is a bug, it would be very likely to show up after some +** thousand (or even million) runs. +** Works only on little-endian processors, such as x86 (or else the partial +** read numbers wouldn't be correctly compared). +** +** Use the --help option to see how it's used. +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ + +#include + +#include +#include +#include +#include + +#define FILE_NAME "RANDOMREAD_TEST_FILE" +#define FILE_SIZE (1024 * 1024) +#define BUFFER_SIZE (64 * 1024) +#define NUMBER_OF_LOOPS 1000 +#define MAX_FAULTS 10 + +// currently only works with 4 byte values! +typedef uint32 test_t; + + +void createFile(const char *name,size_t size) +{ + BFile file; + status_t status = file.SetTo(name,B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); + if (status < B_OK) { + fprintf(stderr,"Could not create test file: %s!\n",strerror(status)); + return; + } + + test_t max = size / sizeof(test_t); + for (uint32 i = 0;i < max;i++) { + if (file.Write(&i,sizeof(test_t)) != sizeof(test_t)) { + fprintf(stderr,"Could not create the whole test file!\n"); + break; + } + } +} + + +void readTest(const char *name,int32 loops) +{ + BFile file; + status_t status = file.SetTo(name,B_READ_ONLY); + if (status < B_OK) { + fprintf(stderr,"Could not open test file! Run \"randomread create [size]\" first.\n" + "This will create a file named \"%s\" in the current directory.\n",name); + return; + } + + off_t size; + if ((status = file.GetSize(&size)) < B_OK) { + fprintf(stderr,"Could not get file size: %s!\n",strerror(status)); + return; + } + + char *buffer = (char *)malloc(BUFFER_SIZE); + if (buffer == NULL) { + fprintf(stderr,"no memory to create read buffer.\n"); + return; + } + srand(time(NULL)); + int32 faults = 0; + + for (int32 i = 0;i < loops;i++) { + off_t pos = rand() % size; + // we are lazy tester, minimum read size is 4 bytes + int32 bytes = (rand() % BUFFER_SIZE) + 4; + off_t max = size - pos; + if (max > bytes) + max = bytes; + else + bytes = max; + + ssize_t bytesRead = file.ReadAt(pos,buffer,bytes); + if (bytesRead < B_OK) + printf(" Could not read %ld bytes at offset %Ld: %s\n",bytes,pos,strerror(bytesRead)); + else if (bytesRead != max) + printf(" Could only read %ld bytes instead of %ld at offset %Ld\n",bytesRead,bytes,pos); + + // test contents + + off_t bufferPos = pos; + test_t num = bufferPos / sizeof(test_t); + + // check leading partial number + int32 partial = bufferPos % sizeof(test_t); + if (partial) { + test_t read = *(test_t *)(buffer - partial); + bool correct; + switch (partial) { + // byteorder little-endian + case 1: + correct = (num & 0xffffff00) == (read & 0xffffff00); + break; + case 2: + correct = (num & 0xffff0000) == (read & 0xffff0000); + break; + case 3: + correct = (num & 0xff000000) == (read & 0xff000000); + break; + } + if (!correct) { + printf("[%Ld,%ld] Bytes at %Ld don't match (partial begin = %ld, should be %08lx, is %08lx)!\n",pos,bytes,bufferPos,partial,num,read); + faults++; + } + bufferPos += sizeof(test_t) - partial; + } + num++; + test_t *numBuffer = (test_t *)(buffer + sizeof(test_t) - partial); + + // test full numbers + for (;bufferPos < bytesRead - sizeof(test_t);bufferPos += sizeof(test_t)) { + if (faults > MAX_FAULTS) { + printf("maximum number of faults reached, bail out.\n"); + return; + } + if (num != *numBuffer) { + printf("[%Ld,%ld] Bytes at %Ld don't match (should be %08lx, is %08lx)!\n",pos,bytes,bufferPos,num,*numBuffer); + faults++; + } + num++; + numBuffer++; + } + + // test last partial number + partial = bytesRead - bufferPos; + if (partial > 0) { + uint32 read = *numBuffer; + bool correct; + switch (partial) { + // byteorder little-endian + case 1: + correct = (num & 0x00ffffff) == (read & 0x00ffffff); + break; + case 2: + correct = (num & 0x0000ffff) == (read & 0x0000ffff); + break; + case 3: + correct = (num & 0x000000ff) == (read & 0x000000ff); + break; + } + if (!correct) { + printf("[%Ld,%ld] Bytes at %Ld don't match (partial end = %ld, should be %08lx, is %08lx)!\n",pos,bytes,bufferPos,partial,num,read); + faults++; + } + } + } +} + + +int main(int argc,char **argv) +{ + size_t size = FILE_SIZE; + int32 loops = NUMBER_OF_LOOPS; + bool create = false; + + if (argv[1]) { + if (!strcmp(argv[1],"create")) { + create = true; + if (argv[2]) + size = atol(argv[2]); + } + else if (isdigit(*argv[1])) + loops = atol(argv[1]); + else { + // get a nice filename of the program + char *filename = strrchr(argv[0],'/') ? strrchr(argv[0],'/') + 1 : argv[0]; + + printf("You can either create a test file or perform the test.\n" + " Create:\t%s create [filesize]\n" + " Test: \t%s [loops]\n\n" + "Default size = %ld, loops = %ld\n", + filename,filename,FILE_SIZE,NUMBER_OF_LOOPS); + + return 0; + } + } + + if (size == 0) { + fprintf(stderr,"%s: given file size too small, set to 1 MB.\n",argv[0]); + size = FILE_SIZE; + } + + if (create) + createFile(FILE_NAME,size); + else + readTest(FILE_NAME,loops); + + return 0; +} diff --git a/src/tests/add-ons/kernel/file_systems/befs/rename/rename.c b/src/tests/add-ons/kernel/file_systems/befs/rename/rename.c new file mode 100644 index 0000000000..9a517eef73 --- /dev/null +++ b/src/tests/add-ons/kernel/file_systems/befs/rename/rename.c @@ -0,0 +1,50 @@ +#include +#include + +#include +#include + + +int main(int argc,char **argv) +{ + int file; + + // clean up (may not be necessary) + remove("__directory/1"); + remove("__directory"); + remove("__file"); + + file = open("__file",O_CREAT | O_TRUNC | O_WRONLY); + if (file < 0) + return -1; + close(file); + + if (chmod("__file",0644) != 0) + printf("chmod fails: %s\n",strerror(errno)); + + if (mkdir("__directory",0755) != 0) + return -1; + + // create a file in that directory + file = open("__directory/1",O_CREAT | O_WRONLY); + close(file); + + errno = 0; + + puts("rename test: Overwrite a directory with files in it"); + printf(" %s\n",rename("__file","__directory") ? "Could not rename file!" : "Rename succeeded."); + printf(" errno = %d (%s)\n",errno,strerror(errno)); + + remove("__directory/1"); + errno = 0; + + // rename the file and try to remove the directory + puts("rename test: Overwrite an empty directory"); + printf(" %s\n",rename("__file","__directory") ? "Could not rename file!" : "Rename succeeded."); + printf(" errno = %d (%s)\n",errno,strerror(errno)); + + remove("__directory"); + remove("__file"); + + return 0; +} diff --git a/src/tests/add-ons/print/pdf/Bookmarks.zip b/src/tests/add-ons/print/pdf/Bookmarks.zip new file mode 100644 index 0000000000..aa97d313a0 Binary files /dev/null and b/src/tests/add-ons/print/pdf/Bookmarks.zip differ diff --git a/src/tests/add-ons/print/pdf/bezierbounds/Application.cpp b/src/tests/add-ons/print/pdf/bezierbounds/Application.cpp new file mode 100644 index 0000000000..83523e35f2 --- /dev/null +++ b/src/tests/add-ons/print/pdf/bezierbounds/Application.cpp @@ -0,0 +1,108 @@ +#include "Application.h" + +BMessage* NewMessage(uint32 what, uint32 data) +{ + BMessage* m = new BMessage(what); + m->AddInt32("data", (int32)data); + return m; +} + + +AppWindow::AppWindow(BRect aRect) + : BWindow(aRect, APPLICATION, B_TITLED_WINDOW, 0) { + // add menu bar + BRect rect = BRect(0,0,aRect.Width(), aRect.Height()); + menubar = new BMenuBar(rect, "menu_bar"); + BMenu *menu; + + menu = new BMenu("Test"); + menu->AddItem(new BMenuItem("About ...", new BMessage(B_ABOUT_REQUESTED))); + menu->AddSeparatorItem(); + menu->AddItem(new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED), 'Q')); + menubar->AddItem(menu); + + menu = new BMenu("Line Cap"); + menu->AddItem(new BMenuItem("Round", NewMessage(CAP_MSG, B_ROUND_CAP))); + menu->AddItem(new BMenuItem("Butt", NewMessage(CAP_MSG, B_BUTT_CAP))); + menu->AddItem(new BMenuItem("Square", NewMessage(CAP_MSG, B_SQUARE_CAP))); + menubar->AddItem(menu); + + menu = new BMenu("Line Join"); + menu->AddItem(new BMenuItem("Round", NewMessage(JOIN_MSG, B_ROUND_JOIN))); + menu->AddItem(new BMenuItem("Miter", NewMessage(JOIN_MSG, B_MITER_JOIN))); + menu->AddItem(new BMenuItem("Bevel", NewMessage(JOIN_MSG, B_BEVEL_JOIN))); + menu->AddItem(new BMenuItem("Butt", NewMessage(JOIN_MSG, B_BUTT_JOIN))); + menu->AddItem(new BMenuItem("Square", NewMessage(JOIN_MSG, B_SQUARE_JOIN))); + menubar->AddItem(menu); + + menu = new BMenu("Path"); + menu->AddItem(new BMenuItem("Open", new BMessage(OPEN_MSG))); + menu->AddItem(new BMenuItem("Close", new BMessage(CLOSE_MSG))); + menubar->AddItem(menu); + + AddChild(menubar); + // add view + aRect.Set(0, menubar->Bounds().Height()+1, aRect.Width(), aRect.Height()); + view = NULL; + AddChild(view = new View(aRect)); + // make window visible + Show(); +} + +void AppWindow::MessageReceived(BMessage *message) { + int32 data; + message->FindInt32("data", &data); + + switch(message->what) { + case MENU_APP_NEW: + break; + case B_ABOUT_REQUESTED: + AboutRequested(); + break; + case CAP_MSG: + view->SetLineMode((cap_mode)data, view->LineJoinMode(), view->LineMiterLimit()); + view->Invalidate(); + break; + case JOIN_MSG: + view->SetLineMode(view->LineCapMode(), (join_mode)data, view->LineMiterLimit()); + view->Invalidate(); + break; + case OPEN_MSG: + case CLOSE_MSG: + view->SetClose(message->what == CLOSE_MSG); + view->Invalidate(); + break; + default: + BWindow::MessageReceived(message); + } +} + + +bool AppWindow::QuitRequested() { + be_app->PostMessage(B_QUIT_REQUESTED); + return(true); +} + +void AppWindow::AboutRequested() { + BAlert *about = new BAlert(APPLICATION, + APPLICATION " " VERSION "\nThis program is freeware under BSD/MIT license.\n\n" + "Written 2002.\n\n" + "By Michael Pfeiffer.\n\n" + "EMail: michael.pfeiffer@utanet.at.","Close"); + about->Go(); +} + +App::App() : BApplication("application/x-vnd.myapplication") { + BRect aRect; + // set up a rectangle and instantiate a new window + aRect.Set(100, 80, 410, 380); + window = NULL; + window = new AppWindow(aRect); +} + +int main(int argc, char *argv[]) { + be_app = NULL; + App app; + be_app->Run(); + return 0; +} \ No newline at end of file diff --git a/src/tests/add-ons/print/pdf/bezierbounds/Application.h b/src/tests/add-ons/print/pdf/bezierbounds/Application.h new file mode 100644 index 0000000000..043382a4ca --- /dev/null +++ b/src/tests/add-ons/print/pdf/bezierbounds/Application.h @@ -0,0 +1,29 @@ +#ifndef CONNECT_APP_H +#define CONNECT_APP_H + +#include +#include +#include "View.h" +#include "MsgConsts.h" + +#define APPLICATION "Application" +#define VERSION "1.0" + +class AppWindow : public BWindow { +public: + BMenuBar *menubar; + View *view; + AppWindow(BRect); + bool QuitRequested(); + void AboutRequested(); + void MessageReceived(BMessage *message); +}; + +class App : public BApplication { +public: + AppWindow *window; + App(); +}; + +#define my_app ((App*)be_app) +#endif \ No newline at end of file diff --git a/src/tests/add-ons/print/pdf/bezierbounds/Application.rsrc b/src/tests/add-ons/print/pdf/bezierbounds/Application.rsrc new file mode 100644 index 0000000000..681796520d Binary files /dev/null and b/src/tests/add-ons/print/pdf/bezierbounds/Application.rsrc differ diff --git a/src/tests/add-ons/print/pdf/bezierbounds/BezierBounds.cpp b/src/tests/add-ons/print/pdf/bezierbounds/BezierBounds.cpp new file mode 100644 index 0000000000..a1fb2e3b6c --- /dev/null +++ b/src/tests/add-ons/print/pdf/bezierbounds/BezierBounds.cpp @@ -0,0 +1,87 @@ +/* + +BezierBounds + +Copyright (c) 2002 OpenBeOS. + +Author: + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + + +#include "BezierBounds.h" +#include +#include + +BRect BezierBounds(BPoint* points, int numOfPoints) +{ + BRect bounds(FLT_MAX, FLT_MAX, -FLT_MIN, -FLT_MIN); + for (int i = 0; i < numOfPoints; i ++, points ++) { + bounds.left = min_c(bounds.left, points->x); + bounds.right = max_c(bounds.right, points->x); + bounds.top = min_c(bounds.top, points->y); + bounds.bottom = max_c(bounds.bottom, points->y); + } + return bounds; +} + +static float PenSizeCorrection(float penSize, cap_mode capMode, join_mode joinMode, float miterLimit) +{ + const float halfPenSize = penSize / 2.0; + float correction = 0.0; + + switch (capMode) { + case B_ROUND_CAP: + case B_BUTT_CAP: + correction = halfPenSize; + break; + case B_SQUARE_CAP: + correction = M_SQRT2 * halfPenSize; + break; + } + + switch (joinMode) { + case B_ROUND_JOIN: + case B_BEVEL_JOIN: + case B_BUTT_JOIN: + correction = max_c(correction, halfPenSize); + break; + case B_MITER_JOIN: + correction = max_c(correction, halfPenSize * miterLimit); + break; + case B_SQUARE_JOIN: + correction = max_c(correction, M_SQRT2 * halfPenSize); + break; + } + + return correction; +} + +BRect BezierBounds(BPoint* points, int numOfPoints, float penSize, cap_mode capMode, join_mode joinMode, float miterLimit) +{ + BRect bounds = BezierBounds(points, numOfPoints); + float w = -PenSizeCorrection(penSize, capMode, joinMode, miterLimit); + bounds.InsetBy(w, w); + return bounds; +} + + diff --git a/src/tests/add-ons/print/pdf/bezierbounds/BezierBounds.h b/src/tests/add-ons/print/pdf/bezierbounds/BezierBounds.h new file mode 100644 index 0000000000..90ce19b9f6 --- /dev/null +++ b/src/tests/add-ons/print/pdf/bezierbounds/BezierBounds.h @@ -0,0 +1,40 @@ +/* + +BezierBounds + +Copyright (c) 2002 OpenBeOS. + +Author: + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef _BEZIER_BOUNDS_H +#define _BEZIER_BOUNDS_H + +#include +#include + +// conservative approximation of the bounds of a bezier curve +BRect BezierBounds(BPoint* points, int numOfPoints); +BRect BezierBounds(BPoint* points, int numOfPoints, float penSize, cap_mode capMode, join_mode joinMode, float miterLimit); + +#endif diff --git a/src/tests/add-ons/print/pdf/bezierbounds/BezierBounds.txt b/src/tests/add-ons/print/pdf/bezierbounds/BezierBounds.txt new file mode 100644 index 0000000000..09de85d49a --- /dev/null +++ b/src/tests/add-ons/print/pdf/bezierbounds/BezierBounds.txt @@ -0,0 +1,12 @@ + File: BezierBounds.zip + Author: Michael Pfeiffer + Contact: michael.pfeiffer@utanet.at + Release: 1.0 + Release-Date: 4/18/2002 + Compatibility: R5 + Location: +Copying-policy: BSD/MIT + Description: Test application that displays the bounds of a bezier curve. + Use right mouse button to add points to bezier curve and + left mouse button to move a point. + Notes: diff --git a/src/tests/add-ons/print/pdf/bezierbounds/MsgConsts.h b/src/tests/add-ons/print/pdf/bezierbounds/MsgConsts.h new file mode 100644 index 0000000000..0dca8240a8 --- /dev/null +++ b/src/tests/add-ons/print/pdf/bezierbounds/MsgConsts.h @@ -0,0 +1,11 @@ +#ifndef MSG_CONSTS_H +#define MSG_CONSTS_H + +#define MENU_APP_NEW 'APnw' +#define CAP_MSG 'cap_' +#define JOIN_MSG 'join' +#define OPEN_MSG 'open' +#define CLOSE_MSG 'clos' + + +#endif \ No newline at end of file diff --git a/src/tests/add-ons/print/pdf/bezierbounds/View.cpp b/src/tests/add-ons/print/pdf/bezierbounds/View.cpp new file mode 100644 index 0000000000..ed4eb47554 --- /dev/null +++ b/src/tests/add-ons/print/pdf/bezierbounds/View.cpp @@ -0,0 +1,91 @@ +#include "BezierBounds.h" +#include "View.h" +#include + +View::View(BRect rect) + : BView(rect, NULL, B_FOLLOW_ALL_SIDES, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_SUBPIXEL_PRECISE) { + //SetViewColor(B_TRANSPARENT_COLOR); + fMode = kStroke; + fCurPoint = -1; + fWidth = 16; +} + +void View::Draw(BRect updateRect) { + if (fMode == kDrawOutline) { + + } else if (fMode == kStroke) { + int i; + if (fPath.CountPoints() > 3) { + const int n = 3 * ((fPath.CountPoints()-1) / 3); + BShape shape; + shape.MoveTo(fPath.PointAt(0)); + for (i = 1; i < n; i += 3) { + BPoint bezier[3] = { fPath.PointAt(i), fPath.PointAt(i+1), fPath.PointAt(i+2) }; + shape.BezierTo(bezier); + } + if (fPath.IsClosed()) shape.Close(); + SetPenSize(fWidth); + StrokeShape(&shape); + + BRect bounds[2]; + SetPenSize(1); + SetHighColor(255, 0, 0); + SetLowColor(0, 255, 0); + for (i = 0; i < n; i += 3) { + BPoint bezier[4] = { fPath.PointAt(i), fPath.PointAt(i+1), fPath.PointAt(i+2), fPath.PointAt(i+3) }; + BRect r = BezierBounds(bezier, 4); + StrokeRect(r); + if (i == 0) bounds[0] = r; else bounds[0] = bounds[0] | r; + r = BezierBounds(bezier, 4, fWidth, LineCapMode(), LineJoinMode(), LineMiterLimit()); + StrokeRect(r, B_SOLID_LOW); + if (i == 0) bounds[1] = r; else bounds[1] = bounds[1] | r; + } + if (fPath.IsClosed()) { + StrokeRect(bounds[0]); + StrokeRect(bounds[1], B_SOLID_LOW); + } + } + + SetHighColor(0, 0, 255); + for (i = 0; i < fPath.CountPoints(); i++) { + BPoint p = fPath.PointAt(i); + StrokeLine(BPoint(p.x-2, p.y), BPoint(p.x+2, p.y)); + StrokeLine(BPoint(p.x, p.y-2), BPoint(p.x, p.y+2)); + } + } +} + +void View::MouseDown(BPoint point) { + uint32 buttons; + GetMouse(&point, &buttons, false); + + if (buttons == B_SECONDARY_MOUSE_BUTTON) { + fCurPoint = fPath.CountPoints(); + fPath.AddPoint(point); + } else { + float d = 100000000000.0; + for (int i = 0; i < fPath.CountPoints(); i++) { + BPoint p = point - fPath.PointAt(i); + float e = p.x*p.x + p.y*p.y; + if (e < d) { fCurPoint = i; d = e; } + } + fPath.AtPut(fCurPoint, point); + } + Invalidate(); +} + +void View::MouseMoved(BPoint point, uint32 transit, const BMessage *message) { + if (fCurPoint != -1) { + fPath.AtPut(fCurPoint, point); + Invalidate(); + } +} + +void View::MouseUp(BPoint point) { + fCurPoint = -1; +} + +void View::SetClose(bool close) { + if (close) fPath.Close(); + else fPath.Open(); +} \ No newline at end of file diff --git a/src/tests/add-ons/print/pdf/bezierbounds/View.h b/src/tests/add-ons/print/pdf/bezierbounds/View.h new file mode 100644 index 0000000000..a9abae4984 --- /dev/null +++ b/src/tests/add-ons/print/pdf/bezierbounds/View.h @@ -0,0 +1,24 @@ +#ifndef VIEW_H +#define VIEW_H + +#include "SubPath.h" +#include + +class View : public BView { + SubPath fPath; + enum { + kDrawOutline, + kStroke + } fMode; + int fCurPoint; + float fWidth; + +public: + View(BRect rect); + void Draw(BRect updateRect); + void MouseDown(BPoint point); + void MouseUp(BPoint point); + void MouseMoved(BPoint point, uint32 transit, const BMessage *message); + void SetClose(bool close); +}; +#endif diff --git a/src/tests/add-ons/print/pdf/linepathbuilder/Application.cpp b/src/tests/add-ons/print/pdf/linepathbuilder/Application.cpp new file mode 100644 index 0000000000..c3c517abed --- /dev/null +++ b/src/tests/add-ons/print/pdf/linepathbuilder/Application.cpp @@ -0,0 +1,110 @@ +#include "Application.h" + +BMessage* NewMessage(uint32 what, uint32 data) +{ + BMessage* m = new BMessage(what); + m->AddInt32("data", (int32)data); + return m; +} + + +AppWindow::AppWindow(BRect aRect) + : BWindow(aRect, APPLICATION, B_TITLED_WINDOW, 0) { + // add menu bar + BRect rect = BRect(0,0,aRect.Width(), aRect.Height()); + menubar = new BMenuBar(rect, "menu_bar"); + BMenu *menu; + + menu = new BMenu("Game"); + menu->AddItem(new BMenuItem("New", new BMessage(MENU_APP_NEW), 'N')); + menu->AddSeparatorItem(); + menu->AddItem(new BMenuItem("About ...", new BMessage(B_ABOUT_REQUESTED))); + menu->AddSeparatorItem(); + menu->AddItem(new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED), 'Q')); + menubar->AddItem(menu); + + menu = new BMenu("Line Cap"); + menu->AddItem(new BMenuItem("Round", NewMessage(CAP_MSG, B_ROUND_CAP))); + menu->AddItem(new BMenuItem("Butt", NewMessage(CAP_MSG, B_BUTT_CAP))); + menu->AddItem(new BMenuItem("Square", NewMessage(CAP_MSG, B_SQUARE_CAP))); + menubar->AddItem(menu); + + menu = new BMenu("Line Join"); + menu->AddItem(new BMenuItem("Round", NewMessage(JOIN_MSG, B_ROUND_JOIN))); + menu->AddItem(new BMenuItem("Miter", NewMessage(JOIN_MSG, B_MITER_JOIN))); + menu->AddItem(new BMenuItem("Bevel", NewMessage(JOIN_MSG, B_BEVEL_JOIN))); + menu->AddItem(new BMenuItem("Butt", NewMessage(JOIN_MSG, B_BUTT_JOIN))); + menu->AddItem(new BMenuItem("Square", NewMessage(JOIN_MSG, B_SQUARE_JOIN))); + menubar->AddItem(menu); + + menu = new BMenu("Path"); + menu->AddItem(new BMenuItem("Open", new BMessage(OPEN_MSG))); + menu->AddItem(new BMenuItem("Close", new BMessage(CLOSE_MSG))); + menubar->AddItem(menu); + + AddChild(menubar); + // add view + aRect.Set(0, menubar->Bounds().Height()+1, aRect.Width(), aRect.Height()); + view = NULL; + AddChild(view = new View(aRect)); + // make window visible + Show(); +} + +void AppWindow::MessageReceived(BMessage *message) { + int32 data; + message->FindInt32("data", &data); + + switch(message->what) { + case MENU_APP_NEW: + break; + case B_ABOUT_REQUESTED: + AboutRequested(); + break; + case CAP_MSG: + view->SetLineMode((cap_mode)data, view->LineJoinMode(), view->LineMiterLimit()); + view->Invalidate(); + break; + case JOIN_MSG: + view->SetLineMode(view->LineCapMode(), (join_mode)data, view->LineMiterLimit()); + view->Invalidate(); + break; + case OPEN_MSG: + case CLOSE_MSG: + view->SetClose(message->what == CLOSE_MSG); + view->Invalidate(); + break; + default: + BWindow::MessageReceived(message); + } +} + + +bool AppWindow::QuitRequested() { + be_app->PostMessage(B_QUIT_REQUESTED); + return(true); +} + +void AppWindow::AboutRequested() { + BAlert *about = new BAlert(APPLICATION, + APPLICATION " " VERSION "\nThis program is freeware under BSD/MIT license.\n\n" + "Written 2002.\n\n" + "By Michael Pfeiffer.\n\n" + "EMail: michael.pfeiffer@utanet.at.","Close"); + about->Go(); +} + +App::App() : BApplication("application/x-vnd.myapplication") { + BRect aRect; + // set up a rectangle and instantiate a new window + aRect.Set(100, 80, 410, 380); + window = NULL; + window = new AppWindow(aRect); +} + +int main(int argc, char *argv[]) { + be_app = NULL; + App app; + be_app->Run(); + return 0; +} \ No newline at end of file diff --git a/src/tests/add-ons/print/pdf/linepathbuilder/Application.h b/src/tests/add-ons/print/pdf/linepathbuilder/Application.h new file mode 100644 index 0000000000..043382a4ca --- /dev/null +++ b/src/tests/add-ons/print/pdf/linepathbuilder/Application.h @@ -0,0 +1,29 @@ +#ifndef CONNECT_APP_H +#define CONNECT_APP_H + +#include +#include +#include "View.h" +#include "MsgConsts.h" + +#define APPLICATION "Application" +#define VERSION "1.0" + +class AppWindow : public BWindow { +public: + BMenuBar *menubar; + View *view; + AppWindow(BRect); + bool QuitRequested(); + void AboutRequested(); + void MessageReceived(BMessage *message); +}; + +class App : public BApplication { +public: + AppWindow *window; + App(); +}; + +#define my_app ((App*)be_app) +#endif \ No newline at end of file diff --git a/src/tests/add-ons/print/pdf/linepathbuilder/Application.rsrc b/src/tests/add-ons/print/pdf/linepathbuilder/Application.rsrc new file mode 100644 index 0000000000..681796520d Binary files /dev/null and b/src/tests/add-ons/print/pdf/linepathbuilder/Application.rsrc differ diff --git a/src/tests/add-ons/print/pdf/linepathbuilder/LinePathBuilder.txt b/src/tests/add-ons/print/pdf/linepathbuilder/LinePathBuilder.txt new file mode 100644 index 0000000000..3e603ea77c --- /dev/null +++ b/src/tests/add-ons/print/pdf/linepathbuilder/LinePathBuilder.txt @@ -0,0 +1,14 @@ + File: LinePathBuilder.zip + Author: Michael Pfeiffer + Contact: michael.pfeiffer@utanet.at + Release: 1.0 + Release-Date: 4/17/2002 + Compatibility: R5 + Location: +Copying-policy: BSD/MIT + Description: Test application for LinePathBuilder class. + Use right mouse button to add points to path and + left mouse button to move a point. + The black line is a stroked BShape. + The red outline is calculated by LinePathBuilder. + Notes: diff --git a/src/tests/add-ons/print/pdf/linepathbuilder/MsgConsts.h b/src/tests/add-ons/print/pdf/linepathbuilder/MsgConsts.h new file mode 100644 index 0000000000..0dca8240a8 --- /dev/null +++ b/src/tests/add-ons/print/pdf/linepathbuilder/MsgConsts.h @@ -0,0 +1,11 @@ +#ifndef MSG_CONSTS_H +#define MSG_CONSTS_H + +#define MENU_APP_NEW 'APnw' +#define CAP_MSG 'cap_' +#define JOIN_MSG 'join' +#define OPEN_MSG 'open' +#define CLOSE_MSG 'clos' + + +#endif \ No newline at end of file diff --git a/src/tests/add-ons/print/pdf/linepathbuilder/View.cpp b/src/tests/add-ons/print/pdf/linepathbuilder/View.cpp new file mode 100644 index 0000000000..2e24a4cb49 --- /dev/null +++ b/src/tests/add-ons/print/pdf/linepathbuilder/View.cpp @@ -0,0 +1,124 @@ +#include "View.h" +#include "LinePathBuilder.h" +#include + +class ShapeLPB : public LinePathBuilder +{ + BShape fShape; + +protected: + virtual void MoveTo(BPoint p); + virtual void LineTo(BPoint p); + virtual void BezierTo(BPoint* p); + virtual void ClosePath(void); + +public: + ShapeLPB(SubPath *subPath, float penSize, cap_mode capMode, join_mode joinMode, float miterLimit); + BShape *Shape() { return &fShape; } +}; + +ShapeLPB::ShapeLPB(SubPath *subPath, float penSize, cap_mode capMode, join_mode joinMode, float miterLimit) + : LinePathBuilder(subPath, penSize, capMode, joinMode, miterLimit) +{ +} + +void ShapeLPB::MoveTo(BPoint p) +{ + fShape.MoveTo(p); +} + +void ShapeLPB::LineTo(BPoint p) +{ + fShape.LineTo(p); +} + +void ShapeLPB::BezierTo(BPoint p[3]) +{ + fShape.BezierTo(p); +} + +void ShapeLPB::ClosePath(void) +{ + fShape.Close(); +} + +View::View(BRect rect) + : BView(rect, NULL, B_FOLLOW_ALL_SIDES, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_SUBPIXEL_PRECISE) { + //SetViewColor(B_TRANSPARENT_COLOR); + fMode = kStroke; + fCurPoint = -1; + fWidth = 16; +} + +void View::Draw(BRect updateRect) { + if (fMode == kDrawOutline) { + + } else if (fMode == kStroke) { + const int n = fPath.CountPoints(); + BShape shape; + for (int i = 0; i < n; i++) { + if (i == 0) + shape.MoveTo(fPath.PointAt(i)); + else + shape.LineTo(fPath.PointAt(i)); + } + if (fPath.IsClosed()) shape.Close(); + SetPenSize(fWidth); + StrokeShape(&shape); + + ShapeLPB path(&fPath, fWidth, LineCapMode(), LineJoinMode(), LineMiterLimit()); + path.CreateLinePath(); + SetPenSize(1); + + BPicture picture; + BeginPicture(&picture); + FillShape(path.Shape()); + EndPicture(); + + PushState(); + ClipToPicture(&picture); + SetHighColor(0, 255, 0); + FillRect(Bounds()); + PopState(); + + SetOrigin(200, 0); + SetHighColor(255, 0, 0); + StrokeShape(path.Shape()); + Flush(); + } +} + +void View::MouseDown(BPoint point) { + uint32 buttons; + GetMouse(&point, &buttons, false); + + if (buttons == B_SECONDARY_MOUSE_BUTTON) { + fCurPoint = fPath.CountPoints(); + fPath.AddPoint(point); + } else { + float d = 100000000000.0; + for (int i = 0; i < fPath.CountPoints(); i++) { + BPoint p = point - fPath.PointAt(i); + float e = p.x*p.x + p.y*p.y; + if (e < d) { fCurPoint = i; d = e; } + } + fPath.AtPut(fCurPoint, point); + } + Invalidate(); +} + +void View::MouseMoved(BPoint point, uint32 transit, const BMessage *message) { + if (fCurPoint != -1) { + fPath.AtPut(fCurPoint, point); + Invalidate(); + } +} + +void View::MouseUp(BPoint point) { + fCurPoint = -1; +} + +void View::SetClose(bool close) { + if (close) fPath.Close(); + else fPath.Open(); +} \ No newline at end of file diff --git a/src/tests/add-ons/print/pdf/linepathbuilder/View.h b/src/tests/add-ons/print/pdf/linepathbuilder/View.h new file mode 100644 index 0000000000..a9abae4984 --- /dev/null +++ b/src/tests/add-ons/print/pdf/linepathbuilder/View.h @@ -0,0 +1,24 @@ +#ifndef VIEW_H +#define VIEW_H + +#include "SubPath.h" +#include + +class View : public BView { + SubPath fPath; + enum { + kDrawOutline, + kStroke + } fMode; + int fCurPoint; + float fWidth; + +public: + View(BRect rect); + void Draw(BRect updateRect); + void MouseDown(BPoint point); + void MouseUp(BPoint point); + void MouseMoved(BPoint point, uint32 transit, const BMessage *message); + void SetClose(bool close); +}; +#endif diff --git a/src/tests/kits/Jamfile b/src/tests/kits/Jamfile new file mode 100644 index 0000000000..8c06dcf5bf --- /dev/null +++ b/src/tests/kits/Jamfile @@ -0,0 +1,4 @@ +SubDir OBOS_TOP sources test kits ; + +SubInclude OBOS_TOP sources tests kits app ; + diff --git a/src/tests/kits/app/Jamfile b/src/tests/kits/app/Jamfile new file mode 100644 index 0000000000..3dc3c85560 --- /dev/null +++ b/src/tests/kits/app/Jamfile @@ -0,0 +1,6 @@ +SubDir OBOS_TOP sources test kits app ; + +SubInclude OBOS_TOP sources tests kits app BHandler ; +#SubInclude OBOS_TOP sources tests kits app BLooper ; +#SubInclude OBOS_TOP sources tests kits app BMessageQueue ; +SubInclude OBOS_TOP sources tests kits app BMessenger ; diff --git a/src/tests/kits/app/bhandler/AddFilterTest.cpp b/src/tests/kits/app/bhandler/AddFilterTest.cpp new file mode 100644 index 0000000000..a3d9ea4544 --- /dev/null +++ b/src/tests/kits/app/bhandler/AddFilterTest.cpp @@ -0,0 +1,112 @@ +//------------------------------------------------------------------------------ +// AddFilterTest.cpp +// +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include +#if defined(TEST_R5) +#include +#else +#include +#endif + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "AddFilterTest.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +/** + AddFilter(BMessageFilter* filter) + @case filter is NULL + @param filter NULL + @results None (i.e., no seg faults, etc.) + @note Contrary to documentation, BHandler doesn't seem to care if + it belongs to a BLooper when a filter gets added. Also, + the original implementation does not handle a NULL param + gracefully, so this test is not enabled against it. + */ +void TAddFilterTest::AddFilter1() +{ +#if !defined(TEST_R5) + BHandler Handler; + Handler.AddFilter(NULL); +#endif +} +//------------------------------------------------------------------------------ +/** + AddFilter(BMessageFilter* filter) + @case filter is valid, handler has no looper + @param filter Valid BMessageFilter pointer + @results None (i.e., no seg faults, etc.) + @note Contrary to documentation, BHandler doesn't seem to care if + it belongs to a BLooper when a filter gets added. + */ +void TAddFilterTest::AddFilter2() +{ + BHandler Handler; + BMessageFilter* Filter = new BMessageFilter('1234'); + Handler.AddFilter(Filter); +} +//------------------------------------------------------------------------------ +/** + AddFilter(BMessageFilter* filter) + @case filter is valid, handler has looper, looper isn't locked + @param filter Valid BMessageFilter pointer + @results None (i.e., no seg faults, etc.) + @note Contrary to documentation, BHandler doesn't seem to care if + if belongs to a BLooper when a filter gets added, or + whether the looper is locked. + */ +void TAddFilterTest::AddFilter3() +{ + BLooper Looper; + BHandler Handler; + BMessageFilter* Filter = new BMessageFilter('1234'); + Looper.AddHandler(&Handler); + Handler.AddFilter(Filter); +} +//------------------------------------------------------------------------------ +/** + AddFilter(BMessageFilter* filter) + @case filter is valid, handler has looper, looper is locked + @param filter Valid BMessageFilter pointer + @results None (i.e., no seg faults, etc.) + */ +void TAddFilterTest::AddFilter4() +{ + BLooper Looper; + BHandler Handler; + BMessageFilter* Filter = new BMessageFilter('1234'); + Looper.Lock(); + Looper.AddHandler(&Handler); + Handler.AddFilter(Filter); +} +//------------------------------------------------------------------------------ +Test* TAddFilterTest::Suite() +{ + TestSuite* SuiteOfTests = new TestSuite("BHandler::AddFilter"); + + ADD_TEST(SuiteOfTests, TAddFilterTest, AddFilter1); + ADD_TEST(SuiteOfTests, TAddFilterTest, AddFilter2); + ADD_TEST(SuiteOfTests, TAddFilterTest, AddFilter3); + ADD_TEST(SuiteOfTests, TAddFilterTest, AddFilter4); + + return SuiteOfTests; +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/app/bhandler/AddFilterTest.h b/src/tests/kits/app/bhandler/AddFilterTest.h new file mode 100644 index 0000000000..2e7f2afbb9 --- /dev/null +++ b/src/tests/kits/app/bhandler/AddFilterTest.h @@ -0,0 +1,49 @@ +//------------------------------------------------------------------------------ +// AddFilterTest.h +// +//------------------------------------------------------------------------------ + +#ifndef ADDFILTERTEST_H +#define ADDFILTERTEST_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#if defined(TEST_R5) +#include +#else +#include +#endif + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "../common.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +class TAddFilterTest : public TestCase +{ + public: + TAddFilterTest() {;} + TAddFilterTest(std::string name) : TestCase(name) {;} + + void AddFilter1(); + void AddFilter2(); + void AddFilter3(); + void AddFilter4(); + + static Test* Suite(); +}; + +#endif //ADDFILTERTEST_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/app/bhandler/BHandlerCases b/src/tests/kits/app/bhandler/BHandlerCases new file mode 100644 index 0000000000..86c1926b81 --- /dev/null +++ b/src/tests/kits/app/bhandler/BHandlerCases @@ -0,0 +1,115 @@ +BHandler(const char* name) +case 1: name is non-NULL; BHandler::Name() should return that name +case 2: name is NULL; BHandler::Name() should return NULL + +BHandler(BMessage* archive) +case 1: if archive has field "_name", BHandler::Name() should return that name +case 2: if archive has no field "_name", BHandler::Name() should return NULL +case 3: archive is NULL + +Archive(BMessage *data, bool deep = true) +case 1: data is NULL, deep is false +case 2: data is NULL, deep is true +case 3: data is valid, deep is false +case 4: data is valid, deep is true + +Instantiate(BMessage *data) +case 1: data is NULL +case 2: data is valid, has field "_name"; BHandler::Name() should return that name +case 3: data is valid, has no field "_name"; BHandler::Name() should return NULL + +SetName(const char *name) +Name() +case 1: name is NULL; BHandler::Name() should return NULL +case 2: name is valid; BHandler::Name should return that name + +Perform(perform_code d, void *arg) +case 1: feed meaningless data, should return B_ERROR + +IsWatched() +case 1: No added watchers; should return false +case 2: Add watcher, should return true; remove watcher, should return false + +Looper() +case 1: Not added to a BLooper, should return NULL +case 2: Added to a BLooper, should return that BLooper; + remove from BLooper, should return NULL + +SetNextHandler(BHandler *handler) +NextHandler() +This BHandler and handler must be part of the same chain (i.e., belong to the +same BLooper) and the BLooper they belong to must be locked. +case 1: Handler1 and Handler2 do not belong to a BLooper +case 2: Handler1 belongs to a BLooper (which is unlocked), Handler2 does not +case 3: Handler1 belongs to a BLooper (which is locked), Handler2 does not +case 4: Handler1 does not belong to a BLooper, Handler2 does (which is unlocked) +case 5: Handler1 does not belong to a BLooper, Handler2 does (which is locked) +case 6: Handler1 and Handler2 belong to different BLoopers, which are unlocked +case 7: Handler1 and Handler2 belong to different BLoopers, and Handler1's + BLooper is locked; Handler2's is not +case 8: Handler1 and Handler2 belong to different BLoopers, and Handler1's + BLooper is unlocked; Handler2's is locked +case 9: Handler1 and Handler2 belong to different BLoopers, which are both locked +case 10: Handler1 and Handler2 belong to the same BLooper, which is unlocked +case 11: Handler1 and Handler2 belong to the same BLooper, which is locked +case 12: Default constructed handler +case 13: Handler belongs to BLooper + +AddFilter(BMessageFilter *filter) +case 1: filter is NULL +case 2: filter is valid, handler has no looper +case 3: filter is valid, handler has looper, looper isn't locked +case 4: filter is valid, handler has looper, looper is locked + +RemoveFilter(BMessageFilter *filter) +case 1: filter is NULL +case 2: filter is valid, handler has no looper +case 3: filter is valid, handler has looper, looper isn't locked +case 4: filter is valid, handler has looper, looper is locked +case 5: filter is valid, but not owned by handler, handler has no looper +case 6: filter is valid, but not owned by handler, handler has looper, looper isn't locked +case 7: filter is valid, but not owned by handler, handler has looper, looper is locked + +SetFilterList(BList *filters) +case 1: filters is NULL +case 2: filters is valid, handler has no looper +case 3: filters is valid, handler has looper, looper isn't locked +case 4: filters is valid, handler has looper, looper is locked +case 5: filters and handler are valid; then NULL filters is passed + +FilterList() +case 1: default constructed BHandler +Other cases are handled in SetFilterList() tests + +LockLooper() +case 1: handler has no looper +case 2: handler has a looper which is initially unlocked +case 3: handler has a looper which is initially locked +case 4: handler has a looper which is locked in another thread + +LockLooperWithTimeout(bigtime_t timeout) +case 1: handler has no looper +case 2: handler has a looper which is initially unlocked +case 3: handler has a looper which is initially locked +case 4: handler has a looper which is locked in another thread + +UnlockLooper() +case 1: handler has no looper +case 2: handler has a looper which is initially unlocked +case 3: handler has a looper which is initially locked +case 4: handler has a looper which is locked in another thread + +MessageReceived(BMessage *message) +ResolveSpecifier(BMessage *msg, int32 index, BMessage *specifier, + int32 form, const char *property) +GetSupportedSuites(BMessage *data) +StartWatching(BMessenger, uint32 what) +StartWatchingAll(BMessenger) +StopWatching(BMessenger, uint32 what) +StopWatchingAll(BMessenger) +StartWatching(BHandler *, uint32 what) +StartWatchingAll(BHandler *) +StopWatching(BHandler *, uint32 what) +StopWatchingAll(BHandler *) + +SendNotices(uint32 what, const BMessage * = 0) \ No newline at end of file diff --git a/src/tests/kits/app/bhandler/BHandlerTester.cpp b/src/tests/kits/app/bhandler/BHandlerTester.cpp new file mode 100644 index 0000000000..3e0db94989 --- /dev/null +++ b/src/tests/kits/app/bhandler/BHandlerTester.cpp @@ -0,0 +1,332 @@ +//------------------------------------------------------------------------------ +// BHandlerTester.cpp +// +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include +#include + +#ifdef TEST_R5 +#include +#include +#include +#else +#include +#include +#include +#endif + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "BHandlerTester.h" +#include "LockLooperTestCommon.h" +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +/** + BHandler(const char* name) + @case Construct with NULL name + @param name NULL + @results BHandler::Name() should return NULL + */ +void TBHandlerTester::BHandler1() +{ + BHandler Handler((const char*)NULL); + assert(Handler.Name() == NULL); +} +//------------------------------------------------------------------------------ +/** + BHandler(const char* name) + @case Construct with valid name + @param name valid string + @results BHandler::Name() returns name + */ +void TBHandlerTester::BHandler2() +{ + BHandler Handler("name"); + assert(string("name") == Handler.Name()); +} +//------------------------------------------------------------------------------ +/** + BHandler(BMessage* archive) + @case archive is valid and has field "_name" + @param archive valid BMessage pointer + @results BHandler::Name() returns _name + */ +void TBHandlerTester::BHandler3() +{ + BMessage Archive; + Archive.AddString("_name", "the name"); + BHandler Handler(&Archive); + assert(string("the name") == Handler.Name()); +} +//------------------------------------------------------------------------------ +/** + BHandler(BMessage* archive) + @case archive is valid, but has no field "_name" + @param archive valid BMessage pointer + @results BHandler::Name() returns NULL + */ +void TBHandlerTester::BHandler4() +{ + BMessage Archive; + BHandler Handler(&Archive); + assert(Handler.Name() == NULL); +} +//------------------------------------------------------------------------------ +/** + BHandler(BMessage* archive) + @case archive is NULL + @param archive NULL + @results BHandler::Name() returns NULL + @note This test is not enabled against the original implementation + as it doesn't check for a NULL parameter and seg faults. + */ + +void TBHandlerTester::BHandler5() +{ +#if !defined(TEST_R5) + BHandler Handler((BMessage*)NULL); + assert(Handler.Name() == NULL); +#endif +} +//------------------------------------------------------------------------------ +/** + Archive(BMessage* data, bool deep = true) + @case data is NULL, deep is false + @param data NULL + @param deep false + @results Returns B_BAD_VALUE + @note This test is not enabled against the original implementation + as it doesn't check for NULL parameters and seg faults + */ +void TBHandlerTester::Archive1() +{ +#if !defined(TEST_R5) + BHandler Handler; + assert(Handler.Archive(NULL, false) == B_BAD_VALUE); +#endif +} +//------------------------------------------------------------------------------ +/** + Archive(BMessage* data, bool deep = true) + @case data is NULL, deep is true + @param data NULL + @param deep false + @results Returns B_BAD_VALUE + @note This test is not enabled against the original implementation + as it doesn't check for NULL parameters and seg faults + */ +void TBHandlerTester::Archive2() +{ +#if !defined(TEST_R5) + BHandler Handler; + assert(Handler.Archive(NULL) == B_BAD_VALUE); +#endif +} +//------------------------------------------------------------------------------ +/** + Archive(BMessage* data, bool deep = true) + @case data is valid, deep is false + @param data valid BMessage pointer + @param deep false + @results Returns B_OK + Resultant archive has string field labeled "_name" + Field "_name" contains the string "a name" + Resultant archive has string field labeled "class" + Field "class" contains the string "BHandler" + */ +void TBHandlerTester::Archive3() +{ + BMessage Archive; + BHandler Handler("a name"); + assert(Handler.Archive(&Archive, false) == B_OK); + + const char* data; + assert(Archive.FindString("_name", &data) == B_OK); + assert(string("a name") == data); + assert(Archive.FindString("class", &data) == B_OK); + assert(string("BHandler") == data); +} +//------------------------------------------------------------------------------ +/** + Archive(BMessage *data, bool deep = true) + @case data is valid, deep is true + @param data valid BMessage pointer + @param deep true + @results Returns B_OK + Resultant archive has string field labeled "_name" + Field "_name" contains the string "a name" + Resultant archive has string field labeled "class" + Field "class" contains the string "BHandler" + */ +void TBHandlerTester::Archive4() +{ + BMessage Archive; + BHandler Handler("another name"); + assert(Handler.Archive(&Archive) == B_OK); + + const char* data; + assert(Archive.FindString("_name", &data) == B_OK); + assert(string("another name") == data); + assert(Archive.FindString("class", &data) == B_OK); + assert(string("BHandler") == data); +} +//------------------------------------------------------------------------------ +/** + Instantiate(BMessage* data) + @case data is NULL + @param data NULL + @results + @note This test is not enabled against the original implementation + as it doesn't check for NULL parameters and seg faults + */ +void TBHandlerTester::Instantiate1() +{ +#if !defined(TEST_R5) + assert(BHandler::Instantiate(NULL) == NULL); + assert(errno == B_BAD_VALUE); +#endif +} +//------------------------------------------------------------------------------ +/** + Instantiate(BMessage* data) + @case data is valid, has field "_name" + @param data Valid BMessage pointer with string field "class" containing + string "BHandler" and with string field "_name" containing + string "a name" + @results BHandler::Name() returns "a name" + */ +void TBHandlerTester::Instantiate2() +{ + BMessage Archive; + Archive.AddString("class", "BHandler"); + Archive.AddString("_name", "a name"); + + BHandler* Handler = + dynamic_cast(BHandler::Instantiate(&Archive)); + assert(Handler != NULL); + assert(string("a name") == Handler->Name()); + assert(errno == B_OK); +} +//------------------------------------------------------------------------------ +/** + Instantiate(BMessage *data) + @case data is valid, has no field "_name" + @param data valid BMessage pointer with string field "class" containing + string "BHandler" + @results BHandler::Name() returns NULL + */ + +void TBHandlerTester::Instantiate3() +{ + BMessage Archive; + Archive.AddString("class", "BHandler"); + + BHandler* Handler = + dynamic_cast(BHandler::Instantiate(&Archive)); + assert(Handler != NULL); + assert(Handler->Name() == NULL); + assert(errno == B_OK); +} +//------------------------------------------------------------------------------ +/** + SetName(const char* name) + Name() + @case name is NULL + @param name NULL + @results BHandler::Name() returns NULL + + */ +void TBHandlerTester::SetName1() +{ + BHandler Handler("a name"); + assert(string("a name") == Handler.Name()); + + Handler.SetName(NULL); + assert(Handler.Name() == NULL); +} +//------------------------------------------------------------------------------ +/** + SetName(const char *name) + Name() + @case name is valid + @param name Valid string pointer + @results BHandler::Name returns name + */ +void TBHandlerTester::SetName2() +{ + BHandler Handler("a name"); + assert(string("a name") == Handler.Name()); + + Handler.SetName("another name"); + assert(string("another name") == Handler.Name()); +} +//------------------------------------------------------------------------------ +/** + Perform(perform_code d, void *arg) + @case feed meaningless data, should return B_ERROR + @param d N/A + @param arg NULL + @results Returns B_ERROR + */ +void TBHandlerTester::Perform1() +{ + BHandler Handler; + assert(Handler.Perform(0, NULL) == B_ERROR); +} +//------------------------------------------------------------------------------ +/** + FilterList(); + @case Default constructed BHandler + @results FilterList() returns NULL + */ +void TBHandlerTester::FilterList1() +{ + BHandler Handler; + assert(!Handler.FilterList()); +} +//------------------------------------------------------------------------------ +Test* TBHandlerTester::Suite() +{ + TestSuite* SuiteOfTests = new TestSuite; + + ADD_TEST(SuiteOfTests, TBHandlerTester, BHandler1); + ADD_TEST(SuiteOfTests, TBHandlerTester, BHandler2); + ADD_TEST(SuiteOfTests, TBHandlerTester, BHandler3); + ADD_TEST(SuiteOfTests, TBHandlerTester, BHandler4); + ADD_TEST(SuiteOfTests, TBHandlerTester, BHandler5); + + ADD_TEST(SuiteOfTests, TBHandlerTester, Archive1); + ADD_TEST(SuiteOfTests, TBHandlerTester, Archive2); + ADD_TEST(SuiteOfTests, TBHandlerTester, Archive3); + ADD_TEST(SuiteOfTests, TBHandlerTester, Archive4); + + ADD_TEST(SuiteOfTests, TBHandlerTester, Instantiate1); + ADD_TEST(SuiteOfTests, TBHandlerTester, Instantiate2); + ADD_TEST(SuiteOfTests, TBHandlerTester, Instantiate3); + + ADD_TEST(SuiteOfTests, TBHandlerTester, SetName1); + ADD_TEST(SuiteOfTests, TBHandlerTester, SetName2); + + ADD_TEST(SuiteOfTests, TBHandlerTester, Perform1); + + ADD_TEST(SuiteOfTests, TBHandlerTester, FilterList1); + + return SuiteOfTests; +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/app/bhandler/BHandlerTester.h b/src/tests/kits/app/bhandler/BHandlerTester.h new file mode 100644 index 0000000000..2cecf49b6e --- /dev/null +++ b/src/tests/kits/app/bhandler/BHandlerTester.h @@ -0,0 +1,65 @@ +//------------------------------------------------------------------------------ +// BHandlerTester.h +// +//------------------------------------------------------------------------------ + +#ifndef BHANDLERTESTER_H +#define BHANDLERTESTER_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "../common.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +class TBHandlerTester : public TestCase +{ + public: + TBHandlerTester() {;} + TBHandlerTester(std::string name) : TestCase(name) {;} + + void BHandler1(); + void BHandler2(); + void BHandler3(); + void BHandler4(); + void BHandler5(); + + void Archive1(); + void Archive2(); + void Archive3(); + void Archive4(); + + void Instantiate1(); + void Instantiate2(); + void Instantiate3(); + + void SetName1(); + void SetName2(); + + void Perform1(); + + void FilterList1(); + + void UnlockLooper1(); + void UnlockLooper2(); + void UnlockLooper3(); + + static Test* Suite(); +}; + +#endif //BHANDLERTESTER_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/app/bhandler/IsWatchedTest.cpp b/src/tests/kits/app/bhandler/IsWatchedTest.cpp new file mode 100644 index 0000000000..5068f261ad --- /dev/null +++ b/src/tests/kits/app/bhandler/IsWatchedTest.cpp @@ -0,0 +1,65 @@ +//------------------------------------------------------------------------------ +// IsWatchedTest.cpp +// +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "IsWatchedTest.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +/** + IsWatched() + @case No added watchers + @results Returns false + */ +void TIsWatchedTest::IsWatched1() +{ + assert(!fHandler.IsWatched()); +} +//------------------------------------------------------------------------------ +/** + IsWatched() + @case Add then remove watcher + @results Returns true after add, returns false after remove + @note Original implementation fails this test. Either the removal + doesn't happen (unlikely) or some list-within-a-list doesn't + get removed when there's nothing in it anymore. + */ +void TIsWatchedTest::IsWatched2() +{ + BHandler Watcher; + fHandler.StartWatching(&Watcher, '1234'); + assert(fHandler.IsWatched() == true); + + fHandler.StopWatching(&Watcher, '1234'); + assert(fHandler.IsWatched() == false); +} +//------------------------------------------------------------------------------ +Test* TIsWatchedTest::Suite() +{ + TestSuite* SuiteOfTests = new TestSuite("BHandler::IsWatched"); + + ADD_TEST(SuiteOfTests, TIsWatchedTest, IsWatched1); + ADD_TEST(SuiteOfTests, TIsWatchedTest, IsWatched2); + + return SuiteOfTests; +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/app/bhandler/IsWatchedTest.h b/src/tests/kits/app/bhandler/IsWatchedTest.h new file mode 100644 index 0000000000..c37c4e158c --- /dev/null +++ b/src/tests/kits/app/bhandler/IsWatchedTest.h @@ -0,0 +1,49 @@ +//------------------------------------------------------------------------------ +// IsWatchedTest.h +// +//------------------------------------------------------------------------------ + +#ifndef ISWATCHEDTEST_H +#define ISWATCHEDTEST_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#if defined(TEST_R5) +#include +#else +#include +#endif +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "../common.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +class TIsWatchedTest : public TestCase +{ + public: + TIsWatchedTest() {;} + TIsWatchedTest(std::string name) : TestCase(name) {;} + + void IsWatched1(); + void IsWatched2(); + + static Test* Suite(); + + private: + BHandler fHandler; +}; + +#endif //ISWATCHEDTEST_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/app/bhandler/Jamfile b/src/tests/kits/app/bhandler/Jamfile new file mode 100644 index 0000000000..e94d84c8f8 --- /dev/null +++ b/src/tests/kits/app/bhandler/Jamfile @@ -0,0 +1,21 @@ +SubDir OBOS_TOP sources tests kits app BHandler ; + +CommonUnitTest BHandlerTester + : main.cpp + BHandlerTester.cpp + IsWatchedTest.cpp + LooperTest.cpp + SetNextHandlerTest.cpp + NextHandlerTest.cpp + AddFilterTest.cpp + RemoveFilterTest.cpp + SetFilterListTest.cpp + LockLooperTest.cpp + LockLooperTestCommon.cpp + LockLooperWithTimeoutTest.cpp + UnlockLooperTest.cpp + : kits app + : libopenbeos.so be stdc++.r4 + : be stdc++.r4 + : app support +; diff --git a/src/tests/kits/app/bhandler/LockLooperTest.cpp b/src/tests/kits/app/bhandler/LockLooperTest.cpp new file mode 100644 index 0000000000..74ba489b81 --- /dev/null +++ b/src/tests/kits/app/bhandler/LockLooperTest.cpp @@ -0,0 +1,109 @@ +//------------------------------------------------------------------------------ +// LockLooper.cpp +// +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "LockLooperTest.h" +#include "LockLooperTestCommon.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +/** + LockLooper(); + @case handler has no looper + @results Returns false + */ +void TLockLooperTest::LockLooper1() +{ + BHandler Handler; + assert(!Handler.LockLooper()); +} +//------------------------------------------------------------------------------ +/** + LockLooper(); + @case handler has a looper which is initially unlocked + @results Returns true + */ +void TLockLooperTest::LockLooper2() +{ + BLooper Looper; + BHandler Handler; + Looper.AddHandler(&Handler); + if (Looper.IsLocked()) + { + // Make sure the looper is unlocked + Looper.Unlock(); + } + assert(Handler.LockLooper()); +} +//------------------------------------------------------------------------------ +/** + LockLooper(); + @case handler has a looper which is initially locked + @results Returns true + */ +void TLockLooperTest::LockLooper3() +{ + BLooper Looper; + BHandler Handler; + Looper.AddHandler(&Handler); + Looper.Lock(); + assert(Handler.LockLooper()); +} +//------------------------------------------------------------------------------ +/** + LockLooper(); + @case handler has a looper which is locked in another thread + @results Returns false + */ +void TLockLooperTest::LockLooper4() +{ + BLooper Looper; + BHandler Handler; + Looper.AddHandler(&Handler); + if (Looper.IsLocked()) + { + Looper.Unlock(); + } + + TLockLooperInfo info(&Looper); + thread_id tid = spawn_thread(LockLooperThreadFunc, "LockLooperHelperThread", + B_NORMAL_PRIORITY, (void*)&info); + resume_thread(tid); + info.LockTest(); + + assert(!Handler.LockLooper()); + info.UnlockThread(); +} +//------------------------------------------------------------------------------ +Test* TLockLooperTest::Suite() +{ + TestSuite* SuiteOfTests = new TestSuite("BHandler::LockLooper"); + + ADD_TEST(SuiteOfTests, TLockLooperTest, LockLooper1); + ADD_TEST(SuiteOfTests, TLockLooperTest, LockLooper2); + ADD_TEST(SuiteOfTests, TLockLooperTest, LockLooper3); +// ADD_TEST(SuiteOfTests, TLockLooperTest, LockLooper4); + + return SuiteOfTests; +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/app/bhandler/LockLooperTest.h b/src/tests/kits/app/bhandler/LockLooperTest.h new file mode 100644 index 0000000000..3a951853cb --- /dev/null +++ b/src/tests/kits/app/bhandler/LockLooperTest.h @@ -0,0 +1,49 @@ +//------------------------------------------------------------------------------ +// LockLooper.h +// +//------------------------------------------------------------------------------ + +#ifndef LOCKLOOPER_H +#define LOCKLOOPER_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#if defined(TEST_R5) +#include +#else +#include +#endif + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "../common.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +class TLockLooperTest : public TestCase +{ + public: + TLockLooperTest() {;} + TLockLooperTest(std::string name) : TestCase(name) {;} + + void LockLooper1(); + void LockLooper2(); + void LockLooper3(); + void LockLooper4(); + + static Test* Suite(); +}; + +#endif //LOCKLOOPER_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/app/bhandler/LockLooperTestCommon.cpp b/src/tests/kits/app/bhandler/LockLooperTestCommon.cpp new file mode 100644 index 0000000000..4c2cdf0f8e --- /dev/null +++ b/src/tests/kits/app/bhandler/LockLooperTestCommon.cpp @@ -0,0 +1,44 @@ +//------------------------------------------------------------------------------ +// LockLooperTestCommon.cpp +// +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "LockLooperTestCommon.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +int32 LockLooperThreadFunc(void* data) +{ + TLockLooperInfo* info = (TLockLooperInfo*)data; + + // Forces the test to encounter a pre-locked looper + info->LockLooper(); + + // Let the test proceed (finding the locked looper) + info->UnlockTest(); + + // Wait until the thread is dead + info->LockThread(); + + return 0; +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/app/bhandler/LockLooperTestCommon.h b/src/tests/kits/app/bhandler/LockLooperTestCommon.h new file mode 100644 index 0000000000..0742253734 --- /dev/null +++ b/src/tests/kits/app/bhandler/LockLooperTestCommon.h @@ -0,0 +1,60 @@ +//------------------------------------------------------------------------------ +// LockLooperTestCommon.h +// +//------------------------------------------------------------------------------ + +#ifndef LOCKLOOPERTESTCOMMON_H +#define LOCKLOOPERTESTCOMMON_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +class BLooper; + +class TLockLooperInfo +{ + public: + TLockLooperInfo(BLooper* Looper) : fLooper(Looper) + { + // Create it "acquired" + fThreadLock = create_sem(0, NULL); + fTestLock = create_sem(0, NULL); + } + + void LockTest() { acquire_sem(fTestLock); } + void UnlockTest() { release_sem(fTestLock); } + void LockThread() { acquire_sem(fThreadLock); } + void UnlockThread() { release_sem(fThreadLock); } + void UnlockLooper() { fLooper->Unlock(); } + void LockLooper() + { + fLooper->Lock(); + } + + private: + BLooper* fLooper; + sem_id fTestLock; + sem_id fThreadLock; +}; + +int32 LockLooperThreadFunc(void* data); + +#endif //LOCKLOOPERTESTCOMMON_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/app/bhandler/LockLooperWithTimeoutTest.cpp b/src/tests/kits/app/bhandler/LockLooperWithTimeoutTest.cpp new file mode 100644 index 0000000000..2f236370a3 --- /dev/null +++ b/src/tests/kits/app/bhandler/LockLooperWithTimeoutTest.cpp @@ -0,0 +1,113 @@ +//------------------------------------------------------------------------------ +// LockLooperWithTimeoutTest.cpp +// +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "LockLooperWithTimeoutTest.h" +#include "LockLooperTestCommon.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +/** + LockLooperWithTimeout(bigtime_t timeout) + @case handler has no looper + @param timeout 10000 microseconds (not relevant) + @results Returns B_BAD_VALUE + */ +void TLockLooperWithTimeoutTest::LockLooperWithTimeout1() +{ + BHandler Handler; + assert(Handler.LockLooperWithTimeout(10000) == B_BAD_VALUE); +} +//------------------------------------------------------------------------------ +/** + LockLooperWithTimeout(bigtime_t timeout) + @case handler has a looper which is initially unlocked + @param timeout 10000 microseconds (not relevant) + @results Returns B_OK + */ +void TLockLooperWithTimeoutTest::LockLooperWithTimeout2() +{ + BLooper Looper; + BHandler Handler; + Looper.AddHandler(&Handler); + if (Looper.IsLocked()) + { + // Make sure the looper is unlocked + Looper.Unlock(); + } + assert(Handler.LockLooperWithTimeout(10000) == B_OK); +} +//------------------------------------------------------------------------------ +/** + LockLooperWithTimeout(bigtime_t timeout) + @case handler has a looper which is initially locked + @param timeout 10000 microseconds (not relevant) + @results Returns B_OK + */ +void TLockLooperWithTimeoutTest::LockLooperWithTimeout3() +{ + BLooper Looper; + BHandler Handler; + Looper.AddHandler(&Handler); + Looper.Lock(); + assert(Handler.LockLooperWithTimeout(10000) == B_OK); +} +//------------------------------------------------------------------------------ +/** + LockLooperWithTimeout(bigtime_t timeout) + @case handler has a looper which is locked in another thread + @param timeout 10000 microseconds (not relevant) + @results Returns B_TIMED_OUT + */ +void TLockLooperWithTimeoutTest::LockLooperWithTimeout4() +{ + BLooper Looper; + BHandler Handler; + Looper.AddHandler(&Handler); + if (Looper.IsLocked()) + { + Looper.Unlock(); + } + + TLockLooperInfo info(&Looper); + thread_id tid = spawn_thread(LockLooperThreadFunc, "LockLooperHelperThread", + B_NORMAL_PRIORITY, (void*)&info); + resume_thread(tid); + info.LockTest(); + + assert(Handler.LockLooperWithTimeout(10000) == B_TIMED_OUT); + info.UnlockThread(); +} +//------------------------------------------------------------------------------ +Test* TLockLooperWithTimeoutTest::Suite() +{ + TestSuite* SuiteOfTests = new TestSuite("BHandler::LockLooperWithTimeout"); + + ADD_TEST(SuiteOfTests, TLockLooperWithTimeoutTest, LockLooperWithTimeout1); + ADD_TEST(SuiteOfTests, TLockLooperWithTimeoutTest, LockLooperWithTimeout2); + ADD_TEST(SuiteOfTests, TLockLooperWithTimeoutTest, LockLooperWithTimeout3); +// ADD_TEST(SuiteOfTests, TLockLooperWithTimeoutTest, LockLooperWithTimeout4); + + return SuiteOfTests; +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/app/bhandler/LockLooperWithTimeoutTest.h b/src/tests/kits/app/bhandler/LockLooperWithTimeoutTest.h new file mode 100644 index 0000000000..f5c9c21989 --- /dev/null +++ b/src/tests/kits/app/bhandler/LockLooperWithTimeoutTest.h @@ -0,0 +1,49 @@ +//------------------------------------------------------------------------------ +// LockLooperWithTimeoutTest.h +// +//------------------------------------------------------------------------------ + +#ifndef LOCKLOOPERWITHTIMEOUTTEST_H +#define LOCKLOOPERWITHTIMEOUTTEST_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#if defined(TEST_R5) +#include +#else +#include +#endif + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "../common.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +class TLockLooperWithTimeoutTest : public TestCase +{ + public: + TLockLooperWithTimeoutTest() {;} + TLockLooperWithTimeoutTest(std::string name) : TestCase(name) {;} + + void LockLooperWithTimeout1(); + void LockLooperWithTimeout2(); + void LockLooperWithTimeout3(); + void LockLooperWithTimeout4(); + + static Test* Suite(); +}; + +#endif //LOCKLOOPERWITHTIMEOUTTEST_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/app/bhandler/LooperTest.cpp b/src/tests/kits/app/bhandler/LooperTest.cpp new file mode 100644 index 0000000000..e01253ecc9 --- /dev/null +++ b/src/tests/kits/app/bhandler/LooperTest.cpp @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// LooperTest.cpp +// +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "LooperTest.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +/** + Looper() + @case Not added to a BLooper + @results Returns NULL + */ +void TLooperTest::LooperTest1() +{ + assert(fHandler.Looper() == NULL); +} +//------------------------------------------------------------------------------ +/** + Looper() + @case Add to a BLooper, then remove + @results Returns the added-to BLooper; when removed, returns NULL + */ +void TLooperTest::LooperTest2() +{ + BLooper Looper; + Looper.AddHandler(&fHandler); + assert(fHandler.Looper() == &Looper); + + assert(Looper.RemoveHandler(&fHandler)); + assert(fHandler.Looper() == NULL); +} +//------------------------------------------------------------------------------ +Test* TLooperTest::Suite() +{ + TestSuite* SuiteOfTests = new TestSuite("BHandler::Looper"); + + ADD_TEST(SuiteOfTests, TLooperTest, LooperTest1); + ADD_TEST(SuiteOfTests, TLooperTest, LooperTest2); + + return SuiteOfTests; +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/app/bhandler/LooperTest.h b/src/tests/kits/app/bhandler/LooperTest.h new file mode 100644 index 0000000000..3190649f12 --- /dev/null +++ b/src/tests/kits/app/bhandler/LooperTest.h @@ -0,0 +1,50 @@ +//------------------------------------------------------------------------------ +// LooperTest.h +// +//------------------------------------------------------------------------------ + +#ifndef LOOPERTEST_H +#define LOOPERTEST_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#if defined(TEST_R5) +#include +#else +#include +#endif + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "../common.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +class TLooperTest : public TestCase +{ + public: + TLooperTest() {;} + TLooperTest(std::string name) : TestCase(name) {;} + + void LooperTest1(); + void LooperTest2(); + + static Test* Suite(); + + private: + BHandler fHandler; +}; + +#endif //LOOPERTEST_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/app/bhandler/NextHandlerTest.cpp b/src/tests/kits/app/bhandler/NextHandlerTest.cpp new file mode 100644 index 0000000000..a292aa9091 --- /dev/null +++ b/src/tests/kits/app/bhandler/NextHandlerTest.cpp @@ -0,0 +1,62 @@ +//------------------------------------------------------------------------------ +// NextHandlerTest.cpp +// +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "NextHandlerTest.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +/** + NextHandler() + @case Default constructed BHandler + @results Returns NULL + */ +void TNextHandlerTest::NextHandler1() +{ + BHandler Handler; + assert(Handler.NextHandler() == NULL); +} +//------------------------------------------------------------------------------ +/** + NextHandler(); + @case Default constructed BHandler added to BLooper + @results Returns parent BLooper + */ +void TNextHandlerTest::NextHandler2() +{ + BHandler Handler; + BLooper Looper; + Looper.AddHandler(&Handler); + assert(Handler.NextHandler() == &Looper); +} +//------------------------------------------------------------------------------ +Test* TNextHandlerTest::Suite() +{ + TestSuite* SuiteOfTests = new TestSuite("BHandler::NextHandler"); + + ADD_TEST(SuiteOfTests, TNextHandlerTest, NextHandler1); + ADD_TEST(SuiteOfTests, TNextHandlerTest, NextHandler2); + + return SuiteOfTests; +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/app/bhandler/NextHandlerTest.h b/src/tests/kits/app/bhandler/NextHandlerTest.h new file mode 100644 index 0000000000..b1fc1004ef --- /dev/null +++ b/src/tests/kits/app/bhandler/NextHandlerTest.h @@ -0,0 +1,50 @@ +//------------------------------------------------------------------------------ +// NextHandlerTest.h +// +//------------------------------------------------------------------------------ + +#ifndef NEXTHANDLERTEST_H +#define NEXTHANDLERTEST_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#if defined(TEST_R5) +#include +#else +#include +#endif + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "../common.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +class TNextHandlerTest : public TestCase +{ + public: + TNextHandlerTest() {;} + TNextHandlerTest(std::string name) : TestCase(name) {;} + + void NextHandler1(); + void NextHandler2(); + + static Test* Suite(); + + private: + BHandler fHandler; +}; + +#endif //NEXTHANDLERTEST_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/app/bhandler/RemoveFilterTest.cpp b/src/tests/kits/app/bhandler/RemoveFilterTest.cpp new file mode 100644 index 0000000000..99a860d92b --- /dev/null +++ b/src/tests/kits/app/bhandler/RemoveFilterTest.cpp @@ -0,0 +1,161 @@ +//------------------------------------------------------------------------------ +// RemoveFilterTest.cpp +// +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include +#if defined(TEST_R5) +#include +#else +#include +#endif + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "RemoveFilterTest.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +/** + RemoveFilter(BMessageFilter* filter) + @case filter is NULL + @param filter NULL + @results Returns false + */ +void TRemoveFilterTest::RemoveFilter1() +{ + BHandler Handler; + assert(!Handler.RemoveFilter(NULL)); +} +//------------------------------------------------------------------------------ +/** + RemoveFilter(BMessageFilter* filter) + @case filter is valid, handler has no looper + @param filter Valid BMessageFilter pointer + @results Returns true. Contrary to documentation, original + implementation of BHandler doesn't care if it belongs to a + looper or not. + */ +void TRemoveFilterTest::RemoveFilter2() +{ + BHandler Handler; + BMessageFilter* Filter = new BMessageFilter('1234'); + Handler.AddFilter(Filter); + assert(Handler.RemoveFilter(Filter)); +} +//------------------------------------------------------------------------------ +/** + RemoveFilter(BMessageFilter* filter) + @case filter is valid, handler has looper, looper isn't locked + @param filter Valid BMessageFilter pointer + @results Returns true. Contrary to documentation, original + implementation of BHandler doesn't care if it belongs to a + looper or not. + */ +void TRemoveFilterTest::RemoveFilter3() +{ + BLooper Looper; + BHandler Handler; + Looper.AddHandler(&Handler); + BMessageFilter* Filter = new BMessageFilter('1234'); + Handler.AddFilter(Filter); + assert(Handler.RemoveFilter(Filter)); +} +//------------------------------------------------------------------------------ +/** + RemoveFilter(BMessageFilter* filter) + @case filter is valid, handler has looper, looper is locked + @param filter Valid BMessageFilter pointer + @results Return true. + */ +void TRemoveFilterTest::RemoveFilter4() +{ + BLooper Looper; + BHandler Handler; + Looper.AddHandler(&Handler); + Looper.Lock(); + BMessageFilter* Filter = new BMessageFilter('1234'); + Handler.AddFilter(Filter); + assert(Handler.RemoveFilter(Filter)); +} +//------------------------------------------------------------------------------ +/** + RemoveFilter(BMessageFilter* filter) + @case filter is valid, but not owned by handler, handler has no looper + @param filter Valid BMessageFilter pointer + @results Returns false. Contrary to documentation, original + implementation of BHandler doesn't care if it belongs to a + looper or not. + */ +void TRemoveFilterTest::RemoveFilter5() +{ + BHandler Handler; + BMessageFilter* Filter = new BMessageFilter('1234'); + assert(!Handler.RemoveFilter(Filter)); +} +//------------------------------------------------------------------------------ +/** + RemoveFilter(BMessageFilter* filter) + @case filter is valid, but not owned by handler, handler has + looper, looper isn't locked + @param filter Valid BMessageFilter pointer + @results Returns false. Contrary to documentation, original + implementation of BHandler doesn't care if its looper is + locked or not. + */ +void TRemoveFilterTest::RemoveFilter6() +{ + BLooper Looper; + BHandler Handler; + Looper.AddHandler(&Handler); + BMessageFilter* Filter = new BMessageFilter('1234'); + assert(!Handler.RemoveFilter(Filter)); +} +//------------------------------------------------------------------------------ +/** + RemoveFilter(BMessageFilter* filter) + @case filter is valid, but not owned by handler, handler has + looper, looper is locked + @param filter Valid BMessageFilter pointer + @results Returns false. + */ +void TRemoveFilterTest::RemoveFilter7() +{ + BLooper Looper; + BHandler Handler; + Looper.AddHandler(&Handler); + Looper.Lock(); + BMessageFilter* Filter = new BMessageFilter('1234'); + assert(!Handler.RemoveFilter(Filter)); +} +//------------------------------------------------------------------------------ +Test* TRemoveFilterTest::Suite() +{ + TestSuite* SuiteOfTests = new TestSuite("BHandler::RemoveFilter"); + + ADD_TEST(SuiteOfTests, TRemoveFilterTest, RemoveFilter1); + ADD_TEST(SuiteOfTests, TRemoveFilterTest, RemoveFilter2); + ADD_TEST(SuiteOfTests, TRemoveFilterTest, RemoveFilter3); + ADD_TEST(SuiteOfTests, TRemoveFilterTest, RemoveFilter4); + ADD_TEST(SuiteOfTests, TRemoveFilterTest, RemoveFilter5); + ADD_TEST(SuiteOfTests, TRemoveFilterTest, RemoveFilter6); + ADD_TEST(SuiteOfTests, TRemoveFilterTest, RemoveFilter7); + + return SuiteOfTests; +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/app/bhandler/RemoveFilterTest.h b/src/tests/kits/app/bhandler/RemoveFilterTest.h new file mode 100644 index 0000000000..a988fc48b1 --- /dev/null +++ b/src/tests/kits/app/bhandler/RemoveFilterTest.h @@ -0,0 +1,52 @@ +//------------------------------------------------------------------------------ +// RemoveFilterTest.h +// +//------------------------------------------------------------------------------ + +#ifndef REMOVEFILTERTEST_H +#define REMOVEFILTERTEST_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#if defined(TEST_R5) +#include +#else +#include +#endif + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "../common.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +class TRemoveFilterTest : public TestCase +{ + public: + TRemoveFilterTest() {;} + TRemoveFilterTest(std::string name) : TestCase(name) {;} + + void RemoveFilter1(); + void RemoveFilter2(); + void RemoveFilter3(); + void RemoveFilter4(); + void RemoveFilter5(); + void RemoveFilter6(); + void RemoveFilter7(); + + static Test* Suite(); +}; + +#endif //REMOVEFILTERTEST_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/app/bhandler/SetFilterListTest.cpp b/src/tests/kits/app/bhandler/SetFilterListTest.cpp new file mode 100644 index 0000000000..c36de1215c --- /dev/null +++ b/src/tests/kits/app/bhandler/SetFilterListTest.cpp @@ -0,0 +1,143 @@ +//------------------------------------------------------------------------------ +// SetFilterListTest.cpp +// +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include +#if defined(TEST_R5) +#include +#else +#include +#endif + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "SetFilterListTest.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +/** + SetFilterList(BList* filters) + @case filters is NULL + @param filters NULL + @results FilterList() returns NULL + */ +void TSetFilterListTest::SetFilterList1() +{ + BHandler Handler; + Handler.SetFilterList(NULL); + assert(!Handler.FilterList()); +} +//------------------------------------------------------------------------------ +/** + SetFilterList(BList* filters) + @case filters is valid, handler has no looper + @param filters Valid pointer to BList of BMessageFilters + @results FilterList() returns assigned list + */ +void TSetFilterListTest::SetFilterList2() +{ + BList* Filters = new BList; + BMessageFilter* Filter = new BMessageFilter('1234'); + Filters->AddItem((void*)Filter); + BHandler Handler; + Handler.SetFilterList(Filters); + assert(Handler.FilterList() == Filters); +} +//------------------------------------------------------------------------------ +/** + SetFilterList(BList* filters) + @case filters is valid, handler has looper, looper isn't locked + @param filters Valid pointer to BList of BMessageFilters + @results FilterList() returns NULL; list is not assigned + debug message "Owning Looper must be locked before calling + SetFilterList" + */ +void TSetFilterListTest::SetFilterList3() +{ + BLooper Looper; + BHandler Handler; + + BList* Filters = new BList; + BMessageFilter* Filter = new BMessageFilter('1234'); + Filters->AddItem((void*)Filter); + + Looper.AddHandler(&Handler); + if (Looper.IsLocked()) + { + Looper.Unlock(); + } + + Handler.SetFilterList(Filters); + assert(!Handler.FilterList()); +} +//------------------------------------------------------------------------------ +/** + SetFilterList(BList* filters) + @case filters is valid, handler has looper, looper is locked + @param filters + @results + */ +void TSetFilterListTest::SetFilterList4() +{ + BList* Filters = new BList; + BMessageFilter* Filter = new BMessageFilter('1234'); + Filters->AddItem((void*)Filter); + BLooper Looper; + BHandler Handler; + Looper.Lock(); + Looper.AddHandler(&Handler); + Handler.SetFilterList(Filters); + assert(Handler.FilterList() == Filters); +} +//------------------------------------------------------------------------------ +/** + SetFilterList(BList* filters) + @case filters and handler are valid; then NULL filters is passed + @param filters + @results + */ +void TSetFilterListTest::SetFilterList5() +{ + BList* Filters = new BList; + BMessageFilter* Filter = new BMessageFilter('1234'); + Filters->AddItem((void*)Filter); + BLooper Looper; + BHandler Handler; + Looper.Lock(); + Looper.AddHandler(&Handler); + Handler.SetFilterList(Filters); + assert(Handler.FilterList() == Filters); + + Handler.SetFilterList(NULL); + assert(!Handler.FilterList()); +} +//------------------------------------------------------------------------------ +Test* TSetFilterListTest::Suite() +{ + TestSuite* SuiteOfTests = new TestSuite("BHandler::SetFilterList"); + + ADD_TEST(SuiteOfTests, TSetFilterListTest, SetFilterList1); + ADD_TEST(SuiteOfTests, TSetFilterListTest, SetFilterList2); + ADD_TEST(SuiteOfTests, TSetFilterListTest, SetFilterList3); + ADD_TEST(SuiteOfTests, TSetFilterListTest, SetFilterList4); + ADD_TEST(SuiteOfTests, TSetFilterListTest, SetFilterList5); + + return SuiteOfTests; +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/app/bhandler/SetFilterListTest.h b/src/tests/kits/app/bhandler/SetFilterListTest.h new file mode 100644 index 0000000000..044dc09c5e --- /dev/null +++ b/src/tests/kits/app/bhandler/SetFilterListTest.h @@ -0,0 +1,50 @@ +//------------------------------------------------------------------------------ +// SetFilterListTest.h +// +//------------------------------------------------------------------------------ + +#ifndef SETFILTERLISTTEST_H +#define SETFILTERLISTTEST_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#if defined(TEST_R5) +#include +#else +#include +#endif + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "../common.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +class TSetFilterListTest : public TestCase +{ + public: + TSetFilterListTest() {;} + TSetFilterListTest(std::string name) : TestCase(name) {;} + + void SetFilterList1(); + void SetFilterList2(); + void SetFilterList3(); + void SetFilterList4(); + void SetFilterList5(); + + static Test* Suite(); +}; + +#endif //SETFILTERLISTTEST_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/app/bhandler/SetNextHandlerTest.cpp b/src/tests/kits/app/bhandler/SetNextHandlerTest.cpp new file mode 100644 index 0000000000..6c55308ce6 --- /dev/null +++ b/src/tests/kits/app/bhandler/SetNextHandlerTest.cpp @@ -0,0 +1,295 @@ +//------------------------------------------------------------------------------ +// SetNextHandlerTest.cpp +// +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "SetNextHandlerTest.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +/** + SetNextHandler(BHandler* handler); + NextHandler(); + @case Clear the next handler + @param handler Valid BHandler pointer, then NULL + @results NextHandler() returns Handler2, then NULL + */ +void TSetNextHandlerTest::SetNextHandler0() +{ + BLooper Looper; + BHandler Handler1; + BHandler Handler2; + + Looper.AddHandler(&Handler1); + Looper.AddHandler(&Handler2); + + Handler1.SetNextHandler(&Handler2); + assert(Handler1.NextHandler() == &Handler2); + + Handler1.SetNextHandler(NULL); + assert(!Handler1.NextHandler()); +} +//------------------------------------------------------------------------------ +/** + SetNextHandler(BHandler* handler); + NextHandler(); + @case Handler1 and Handler2 do not belong to a BLooper + @param handler Valid BHandler pointer + @results NextHandler() returns NULL + debug message "handler must belong to looper before setting + NextHandler" + */ +void TSetNextHandlerTest::SetNextHandler1() +{ + BHandler Handler1; + BHandler Handler2; + Handler1.SetNextHandler(&Handler2); + assert(Handler1.NextHandler() == NULL); +} +//------------------------------------------------------------------------------ +/** + SetNextHandler(BHandler* handler); + NextHandler(); + @case Handler1 belongs to a unlocked BLooper, Handler2 does not + @param handler Valid BHandler pointer + @results NextHandler() returns BLooper + debug message "The handler and its NextHandler must have + the same looper" + */ +void TSetNextHandlerTest::SetNextHandler2() +{ + BHandler Handler1; + BHandler Handler2; + BLooper Looper; + Looper.AddHandler(&Handler1); + Handler1.SetNextHandler(&Handler2); + assert(Handler1.NextHandler() == &Looper); +} +//------------------------------------------------------------------------------ +/** + SetNextHandler(BHandler* handler); + NextHandler(); + @case Handler1 belongs to a locked BLooper, Handler2 does not + @param handler Valid BHandler pointer + @results NextHandler() returns BLooper + debug message "The handler and its NextHandler must have + the same looper" + */ +void TSetNextHandlerTest::SetNextHandler3() +{ + BHandler Handler1; + BHandler Handler2; + BLooper Looper; + Looper.AddHandler(&Handler1); + Looper.Lock(); + Handler1.SetNextHandler(&Handler2); + assert(Handler1.NextHandler() == &Looper); +} +//------------------------------------------------------------------------------ +/** + SetNextHandler(BHandler* handler); + NextHandler(); + @case Handler2 belongs to a unlocked BLooper, Handler1 does not + @param handler Valid BHandler pointer + @results NextHandler() returns NULL + debug message "handler must belong to looper before setting + NextHandler" + */ +void TSetNextHandlerTest::SetNextHandler4() +{ + BHandler Handler1; + BHandler Handler2; + BLooper Looper; + Looper.AddHandler(&Handler2); + Handler1.SetNextHandler(&Handler2); + assert(Handler1.NextHandler() == NULL); +} +//------------------------------------------------------------------------------ +/** + SetNextHandler(BHandler* handler); + NextHandler(); + @case Handler2 belongs to a locked BLooper, Handler1 does not + @param handler Valid BHandler pointer + @results NextHandler() returns NULL + debug message "handler must belong to looper before setting + NextHandler" + */ +void TSetNextHandlerTest::SetNextHandler5() +{ + BHandler Handler1; + BHandler Handler2; + BLooper Looper; + Looper.AddHandler(&Handler2); + Looper.Lock(); + Handler1.SetNextHandler(&Handler2); + assert(Handler1.NextHandler() == NULL); +} +//------------------------------------------------------------------------------ +/** + SetNextHandler(BHandler* handler); + NextHandler(); + @case Handler1 and Handler2 belong to different unlocked BLoopers + @param handler Valid BHandler pointer + @results Returns BLooper; + debug message "The handler and its NextHandler must have the + same looper" + */ +void TSetNextHandlerTest::SetNextHandler6() +{ + BHandler Handler1; + BHandler Handler2; + BLooper Looper1; + BLooper Looper2; + Looper1.AddHandler(&Handler1); + Looper2.AddHandler(&Handler2); + Handler1.SetNextHandler(&Handler2); + assert(Handler1.NextHandler() == &Looper1); +} +//------------------------------------------------------------------------------ +/** + SetNextHandler(BHandler* handler); + NextHandler(); + @case Handler1 and Handler2 belong to different BLoopers; + Handler1's is locked; Handler2's is not + @param handler Valid BHandler pointer + @result Returns BLooper; + debug message "The handler and its NextHandler must have the + same looper" + */ +void TSetNextHandlerTest::SetNextHandler7() +{ + BHandler Handler1; + BHandler Handler2; + BLooper Looper1; + BLooper Looper2; + Looper1.AddHandler(&Handler1); + Looper2.AddHandler(&Handler2); + Looper1.Lock(); + Handler1.SetNextHandler(&Handler2); + assert(Handler1.NextHandler() == &Looper1); +} +//------------------------------------------------------------------------------ +/** + SetNextHandler(BHandler* handler); + NextHandler(); + @case Handler1 and Handler2 belong to different BLoopers; + Handler1's is unlocked; Handler2's is locked + @param handler Valid BHandler pointer + @results Returns BLooper + debug message "The handler and its NextHandler must have the + same looper" + */ +void TSetNextHandlerTest::SetNextHandler8() +{ + BHandler Handler1; + BHandler Handler2; + BLooper Looper1; + BLooper Looper2; + Looper1.AddHandler(&Handler1); + Looper2.AddHandler(&Handler2); + Looper2.Lock(); + Handler1.SetNextHandler(&Handler2); + assert(Handler1.NextHandler() == &Looper1); +} +//------------------------------------------------------------------------------ +/** + SetNextHandler(BHandler* handler); + NextHandler(); + @case Handler1 and Handler2 belong to different locked BLoopers + @param handler Valid BHandler pointer + @results Returns BLooper + debug message "The handler and its NextHandler must have the + same looper" + */ +void TSetNextHandlerTest::SetNextHandler9() +{ + BHandler Handler1; + BHandler Handler2; + BLooper Looper1; + BLooper Looper2; + Looper1.AddHandler(&Handler1); + Looper2.AddHandler(&Handler2); + Looper1.Lock(); + Looper2.Lock(); + Handler1.SetNextHandler(&Handler2); + assert(Handler1.NextHandler() == &Looper1); +} +//------------------------------------------------------------------------------ +/** + SetNextHandler(BHandler* handler); + NextHandler(); + @case Handler1 and Handler2 belong to the same unlocked BLooper + @param handler Valid BHandler pointer + @results Returns Handler2 + @note Docs say the looper must be locked, but the original + implementation allows the next handler to be set anyway. + */ +void TSetNextHandlerTest::SetNextHandler10() +{ + BLooper Looper; + BHandler Handler1; + BHandler Handler2; + Looper.AddHandler(&Handler1); + Looper.AddHandler(&Handler2); + Handler1.SetNextHandler(&Handler2); + assert(Handler1.NextHandler() == &Handler2); +} +//------------------------------------------------------------------------------ +/** + SetNextHandler(BHandler* handler); + NextHandler(); + @case Handler1 and Handler2 belong to the same locked BLooper + @param handler Valid BHandler pointer + @results Returns Handler2 + */ +void TSetNextHandlerTest::SetNextHandler11() +{ + BLooper Looper; + BHandler Handler1; + BHandler Handler2; + Looper.AddHandler(&Handler1); + Looper.AddHandler(&Handler2); + Looper.Lock(); + Handler1.SetNextHandler(&Handler2); + assert(Handler1.NextHandler() == &Handler2); +} +//------------------------------------------------------------------------------ +Test* TSetNextHandlerTest::Suite() +{ + TestSuite* SuiteOfTests = new TestSuite("BHandler::SetNextHandler"); + + ADD_TEST(SuiteOfTests, TSetNextHandlerTest, SetNextHandler0); +// ADD_TEST(SuiteOfTests, TSetNextHandlerTest, SetNextHandler1); +// ADD_TEST(SuiteOfTests, TSetNextHandlerTest, SetNextHandler2); +// ADD_TEST(SuiteOfTests, TSetNextHandlerTest, SetNextHandler3); +// ADD_TEST(SuiteOfTests, TSetNextHandlerTest, SetNextHandler4); +// ADD_TEST(SuiteOfTests, TSetNextHandlerTest, SetNextHandler5); +// ADD_TEST(SuiteOfTests, TSetNextHandlerTest, SetNextHandler6); +// ADD_TEST(SuiteOfTests, TSetNextHandlerTest, SetNextHandler7); +// ADD_TEST(SuiteOfTests, TSetNextHandlerTest, SetNextHandler8); +// ADD_TEST(SuiteOfTests, TSetNextHandlerTest, SetNextHandler9); + ADD_TEST(SuiteOfTests, TSetNextHandlerTest, SetNextHandler10); + ADD_TEST(SuiteOfTests, TSetNextHandlerTest, SetNextHandler11); + + return SuiteOfTests; +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/app/bhandler/SetNextHandlerTest.h b/src/tests/kits/app/bhandler/SetNextHandlerTest.h new file mode 100644 index 0000000000..8cba8a8027 --- /dev/null +++ b/src/tests/kits/app/bhandler/SetNextHandlerTest.h @@ -0,0 +1,59 @@ +//------------------------------------------------------------------------------ +// SetNextHandlerTest.h +// +//------------------------------------------------------------------------------ + +#ifndef SETNEXTHANDLERTEST_H +#define SETNEXTHANDLERTEST_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#if defined(TEST_R5) +#include +#else +#include +#endif + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "../common.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +class TSetNextHandlerTest : public TestCase +{ + public: + TSetNextHandlerTest() {;} + TSetNextHandlerTest(std::string name) : TestCase(name) {;} + + void SetNextHandler0(); + void SetNextHandler1(); + void SetNextHandler2(); + void SetNextHandler3(); + void SetNextHandler4(); + void SetNextHandler5(); + void SetNextHandler6(); + void SetNextHandler7(); + void SetNextHandler8(); + void SetNextHandler9(); + void SetNextHandler10(); + void SetNextHandler11(); + + static Test* Suite(); + + private: +}; + +#endif //SETNEXTHANDLERTEST_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/app/bhandler/UnlockLooperTest.cpp b/src/tests/kits/app/bhandler/UnlockLooperTest.cpp new file mode 100644 index 0000000000..4c64e3a15d --- /dev/null +++ b/src/tests/kits/app/bhandler/UnlockLooperTest.cpp @@ -0,0 +1,91 @@ +//------------------------------------------------------------------------------ +// UnlockLooperTest.cpp +// +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "UnlockLooperTest.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +/** + UnlockLooper() + @case handler has no looper + @results NONE + @note Original implementation apparently doesn't check to see if a + looper actually exists before trying to call Unlock() on it. + Disabled for TEST_R5. + */ +void TUnlockLooperTest::UnlockLooper1() +{ +#if !defined(TEST_R5) + BHandler Handler; + Handler.UnlockLooper(); +#endif +} +//------------------------------------------------------------------------------ +/** + UnlockLooper() + @case handler has a looper which is initially unlocked + @results debug message "looper must be locked before proceeding" from + BLooper::AssertLock() + */ +void TUnlockLooperTest::UnlockLooper2() +{ + BLooper Looper; + BHandler Handler; + Looper.AddHandler(&Handler); + if (Looper.IsLocked()) + { + // Make sure the looper is unlocked + Looper.Unlock(); + } + Handler.UnlockLooper(); +} +//------------------------------------------------------------------------------ +/** + UnlockLooper() + @case handler has a looper which is initially locked + @results NONE + */ +void TUnlockLooperTest::UnlockLooper3() +{ + BLooper Looper; + BHandler Handler; + Looper.AddHandler(&Handler); + if (!Looper.IsLocked()) + { + Looper.Lock(); + } + Handler.UnlockLooper(); +} +//------------------------------------------------------------------------------ +Test* TUnlockLooperTest::Suite() +{ + TestSuite* SuiteOfTests = new TestSuite("BHandler::UnlockLooper"); + + ADD_TEST(SuiteOfTests, TUnlockLooperTest, UnlockLooper1); + ADD_TEST(SuiteOfTests, TUnlockLooperTest, UnlockLooper2); + ADD_TEST(SuiteOfTests, TUnlockLooperTest, UnlockLooper3); + + return SuiteOfTests; +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/app/bhandler/UnlockLooperTest.h b/src/tests/kits/app/bhandler/UnlockLooperTest.h new file mode 100644 index 0000000000..a01e0be03d --- /dev/null +++ b/src/tests/kits/app/bhandler/UnlockLooperTest.h @@ -0,0 +1,48 @@ +//------------------------------------------------------------------------------ +// UnlockLooperTest.h +// +//------------------------------------------------------------------------------ + +#ifndef UNLOCKLOOPERTEST_H +#define UNLOCKLOOPERTEST_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#if defined(TEST_R5) +#include +#else +#include +#endif + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "../common.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +class TUnlockLooperTest : public TestCase +{ + public: + TUnlockLooperTest() {;} + TUnlockLooperTest(std::string name) : TestCase(name) {;} + + void UnlockLooper1(); + void UnlockLooper2(); + void UnlockLooper3(); + + static Test* Suite(); +}; + +#endif //UNLOCKLOOPERTEST_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/app/bhandler/main.cpp b/src/tests/kits/app/bhandler/main.cpp new file mode 100644 index 0000000000..cd1a5371e0 --- /dev/null +++ b/src/tests/kits/app/bhandler/main.cpp @@ -0,0 +1,80 @@ +//------------------------------------------------------------------------------ +// main.cpp +// +// Entry points for testing BHandler +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "../common.h" +#include "BHandlerTester.h" +#include "IsWatchedTest.h" +#include "LooperTest.h" +#include "SetNextHandlerTest.h" +#include "NextHandlerTest.h" +#include "AddFilterTest.h" +#include "RemoveFilterTest.h" +#include "SetFilterListTest.h" +#include "LockLooperTest.h" +#include "LockLooperWithTimeoutTest.h" +#include "UnlockLooperTest.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + + +/* + * Function: addonTestFunc() + * Descr: This function is called by the test application to + * get a pointer to the test to run. The BMessageQueue test + * is a test suite. A series of tests are added to + * the suite. Each test appears twice, once for + * the Be implementation of BMessageQueue, once for the + * OpenBeOS implementation. + */ + +Test* addonTestFunc(void) +{ + TestSuite* tests = new TestSuite("BHandler"); + + tests->addTest(TBHandlerTester::Suite()); + tests->addTest(TIsWatchedTest::Suite()); + tests->addTest(TLooperTest::Suite()); + tests->addTest(TSetNextHandlerTest::Suite()); + tests->addTest(TNextHandlerTest::Suite()); + tests->addTest(TAddFilterTest::Suite()); + tests->addTest(TRemoveFilterTest::Suite()); + tests->addTest(TSetFilterListTest::Suite()); + tests->addTest(TLockLooperTest::Suite()); + tests->addTest(TLockLooperWithTimeoutTest::Suite()); + tests->addTest(TUnlockLooperTest::Suite()); + + return tests; +} + +int main() +{ + Test* tests = addonTestFunc(); + + TextTestResult Result; + tests->run(&Result); + cout << Result << endl; + + delete tests; + + return !Result.wasSuccessful(); +} + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/app/blooper/BLooperCases b/src/tests/kits/app/blooper/BLooperCases new file mode 100644 index 0000000000..77fa4361e1 --- /dev/null +++ b/src/tests/kits/app/blooper/BLooperCases @@ -0,0 +1,11 @@ +MessageQueue() +-------------- +case 1: looper is unlocked and queue is empty +case 2: looper is unlocked and queue is filled +case 3: looper is locked and queue is empty +case 4: looper is locked and queue is filled +case 5: looper is locked, message is posted, queue is emptied + +RemoveHandler(BHandler* handler) +-------------- +case : handler has filters; FilterList() should be NULL on remove diff --git a/src/tests/kits/app/blooper/IsMessageWaitingTest.cpp b/src/tests/kits/app/blooper/IsMessageWaitingTest.cpp new file mode 100644 index 0000000000..a98727a2c8 --- /dev/null +++ b/src/tests/kits/app/blooper/IsMessageWaitingTest.cpp @@ -0,0 +1,92 @@ +//------------------------------------------------------------------------------ +// IsMessageWaitingTest.cpp +// +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#if defined(SYSTEM_TEST) +#include +#include +#else +#include "../../../../lib/application/headers/Looper.h" +#include "../../../../lib/application/headers/MessageQueue.h" +#endif + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "IsMessageWaitingTest.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +//case 1: looper is unlocked and queue is empty +void TIsMessageWaitingTest::IsMessageWaiting1() +{ + BLooper Looper; + assert(!Looper.IsMessageWaiting()); +} +//------------------------------------------------------------------------------ +//case 2: looper is unlocked and queue is filled +void TIsMessageWaitingTest::IsMessageWaiting2() +{ + BLooper Looper; + Looper.PostMessage('1234'); + assert(Looper.IsMessageWaiting()); +} +//------------------------------------------------------------------------------ +//case 3: looper is locked and queue is empty +void TIsMessageWaitingTest::IsMessageWaiting3() +{ + BLooper Looper; + Looper.Lock(); + assert(!Looper.IsMessageWaiting()); +} +//------------------------------------------------------------------------------ +//case 4: looper is locked and queue is filled +void TIsMessageWaitingTest::IsMessageWaiting4() +{ + BLooper Looper; + Looper.Lock(); + Looper.PostMessage('1234'); + assert(Looper.IsMessageWaiting()); +} +//------------------------------------------------------------------------------ +//case 5: looper is locked, message is posted, queue is empty +void TIsMessageWaitingTest::IsMessageWaiting5() +{ + BLooper* Looper = new BLooper(__PRETTY_FUNCTION__); + Looper->Run(); + + // Prevent a port read + Looper->Lock(); + Looper->PostMessage('1234'); + assert(Looper->MessageQueue()->IsEmpty()); + assert(Looper->IsMessageWaiting()); +} +//------------------------------------------------------------------------------ +Test* TIsMessageWaitingTest::Suite() +{ + TestSuite* suite = new TestSuite("BLooper::IsMessageWaiting()"); + + ADD_TEST(suite, TIsMessageWaitingTest, IsMessageWaiting1); + ADD_TEST(suite, TIsMessageWaitingTest, IsMessageWaiting2); + ADD_TEST(suite, TIsMessageWaitingTest, IsMessageWaiting3); + ADD_TEST(suite, TIsMessageWaitingTest, IsMessageWaiting4); + ADD_TEST(suite, TIsMessageWaitingTest, IsMessageWaiting5); + + return suite; +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/app/blooper/IsMessageWaitingTest.h b/src/tests/kits/app/blooper/IsMessageWaitingTest.h new file mode 100644 index 0000000000..ea04222588 --- /dev/null +++ b/src/tests/kits/app/blooper/IsMessageWaitingTest.h @@ -0,0 +1,44 @@ +//------------------------------------------------------------------------------ +// IsMessageWaitingTest.h +// +//------------------------------------------------------------------------------ + +#ifndef ISMESSAGEWAITINGTEST_H +#define ISMESSAGEWAITINGTEST_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "common.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +class TIsMessageWaitingTest : public TestCase +{ + public: + TIsMessageWaitingTest(std::string name) : TestCase(name) {;} + + void IsMessageWaiting1(); + void IsMessageWaiting2(); + void IsMessageWaiting3(); + void IsMessageWaiting4(); + void IsMessageWaiting5(); + + static Test* Suite(); +}; + +#endif //ISMESSAGEWAITINGTEST_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/app/blooper/Jamfile b/src/tests/kits/app/blooper/Jamfile new file mode 100644 index 0000000000..3583eecc2e --- /dev/null +++ b/src/tests/kits/app/blooper/Jamfile @@ -0,0 +1,13 @@ +SubDir OBOS_TOP sources tests kits app BLooper ; + +UsePublicHeaders app support ; + +UnitTest BLooperTester : main.cpp + IsMessageWaitingTest.cpp + RemoveHandlerTest.cpp + : kits/app ; + +LinkSharedOSLibs BLooperTester : + libopenbeos.so + be + stdc++.r4 ; diff --git a/src/tests/kits/app/blooper/RemoveHandlerTest.cpp b/src/tests/kits/app/blooper/RemoveHandlerTest.cpp new file mode 100644 index 0000000000..24feeaa5ba --- /dev/null +++ b/src/tests/kits/app/blooper/RemoveHandlerTest.cpp @@ -0,0 +1,64 @@ +//------------------------------------------------------------------------------ +// RemoveHandlerTest.cpp +// +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#if defined(SYSTEM_TEST) +#include +#include +#include +#else +#include "../../../../lib/application/headers/Handler.h" +#include "../../../../lib/application/headers/Looper.h" +#include "../../../../lib/application/headers/MessageFilter.h" +#endif + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "RemoveHandlerTest.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +/** + RemoveHandler(BHandler* handler) + @case Valid looper and handler; handler has filters + @param handler Valid BHandler pointer + @results RemoveHandler() returns true + handler->FilterList() returns NULL after removal + */ +void TRemoveHandlerTest::RemoveHandler1() +{ + BLooper Looper; + BHandler Handler; + BMessageFilter* MessageFilter = new BMessageFilter('1234'); + + Handler.AddFilter(MessageFilter); + Looper.AddHandler(&Handler); + Looper.RemoveHandler(&Handler); + assert(Handler.FilterList() == NULL); +} +//------------------------------------------------------------------------------ +Test* TRemoveHandlerTest::Suite() +{ + TestSuite* suite = new TestSuite("BLooper::RemoveHandler(BHandler* handler)"); + + ADD_TEST(suite, TRemoveHandlerTest, RemoveHandler1); + + return suite; +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/app/blooper/RemoveHandlerTest.h b/src/tests/kits/app/blooper/RemoveHandlerTest.h new file mode 100644 index 0000000000..7137b4df6c --- /dev/null +++ b/src/tests/kits/app/blooper/RemoveHandlerTest.h @@ -0,0 +1,40 @@ +//------------------------------------------------------------------------------ +// RemoveHandlerTest.h +// +//------------------------------------------------------------------------------ + +#ifndef REMOVEHANDLERTEST_H +#define REMOVEHANDLERTEST_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "common.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +class TRemoveHandlerTest : public TestCase +{ + public: + TRemoveHandlerTest(std::string name) : TestCase(name) {;} + + void RemoveHandler1(); + + static Test* Suite(); +}; + +#endif //REMOVEHANDLERTEST_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/app/blooper/main.cpp b/src/tests/kits/app/blooper/main.cpp new file mode 100644 index 0000000000..393013b317 --- /dev/null +++ b/src/tests/kits/app/blooper/main.cpp @@ -0,0 +1,128 @@ +//------------------------------------------------------------------------------ +// main.cpp +// +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- +#include + +// System Includes ------------------------------------------------------------- +#include +#include +#include + +#if !defined(SYSTEM_TEST) +#include +#else +#include "../../../../source/lib/application/headers/Looper.h" +#endif + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "IsMessageWaitingTest.h" +#include "RemoveHandlerTest.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +/* + * Function: addonTestFunc() + * Descr: This function is called by the test application to + * get a pointer to the test to run. The BMessageQueue test + * is a test suite. A series of tests are added to + * the suite. Each test appears twice, once for + * the Be implementation of BMessageQueue, once for the + * OpenBeOS implementation. + */ + +Test* addonTestFunc(void) +{ + TestSuite* tests = new TestSuite("BLooper"); + + tests->addTest(TIsMessageWaitingTest::Suite()); + tests->addTest(TRemoveHandlerTest::Suite()); + + return tests; +} +#if 0 +class TestLooper : public BLooper +{ + public: + TestLooper() : BLooper(), fYouCanQuit(false) {;} + + virtual bool QuitRequested() + { + printf("\n%s: %s%s\n", __PRETTY_FUNCTION__, fYouCanQuit ? "" : "not ", + "quitting"); + return fYouCanQuit; + } + void SetYouCanQuit(bool yesNo) { fYouCanQuit = yesNo; } + + private: + bool fYouCanQuit; +}; + +filter_result QuitFilter(BMessage* message, BHandler** target, + BMessageFilter* filter) +{ + printf("\nAnd here we are\n"); + return B_DISPATCH_MESSAGE; +} +#endif +int main() +{ + Test* tests = addonTestFunc(); + + TextTestResult Result; + tests->run(&Result); + cout << Result << endl; + + delete tests; + + return !Result.wasSuccessful(); +#if 0 + BLooper* Looper = new TestLooper; + Looper->AddFilter(new BMessageFilter(_QUIT_, QuitFilter)); + Looper->Run(); + Looper->Lock(); + ((TestLooper*)Looper)->SetYouCanQuit(true); + Looper->Quit(); + + snooze(1000000); + +//#else + BMessage QuitMsg(B_QUIT_REQUESTED); + + printf("\nLooper thread: 0x%lx\n", Looper->Thread()); + + status_t err; + BMessenger Msgr(NULL, Looper, &err); + if (!err) + { + err = Msgr.SendMessage(&QuitMsg, &QuitMsg); + if (!err) + { + QuitMsg.PrintToStream(); + BMessage QuitMsg2(B_QUIT_REQUESTED); + ((TestLooper*)Looper)->SetYouCanQuit(true); + err = Msgr.SendMessage(&QuitMsg2, &QuitMsg2); + if (!err) + { + QuitMsg2.PrintToStream(); + } + } + } + + return 0; +#endif +} + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/app/bmessagequeue/AddMessageTest1.cpp b/src/tests/kits/app/bmessagequeue/AddMessageTest1.cpp new file mode 100644 index 0000000000..4c98f24d12 --- /dev/null +++ b/src/tests/kits/app/bmessagequeue/AddMessageTest1.cpp @@ -0,0 +1,113 @@ +/* + $Id: AddMessageTest1.cpp,v 1.1 2002/07/09 12:24:56 ejakowatz Exp $ + + This file implements the first test for the OpenBeOS BMessageQueue code. + It tests the Construction, Destruction, Add Message 1, Count Messages, + Is Empty and Find Message 1 use cases. It does so by doing the following: + - checks that the queue is empty according to IsEmpty() and CountMessages() + - adds 10000 messages to the queue and a BList + - as each is added, checks that IsEmpty() is false and CountMessages() + returns what is expected + - the BList contents is compared to the queue contents (uses FindMessage()) + - the number of BMessages destructed is checked, no messages should have been + deleted so far. + - the queue is deleted + - the number of BMessages destructed should now be 10000 + + */ + + +#include "AddMessageTest1.h" +#include +#include +#include "MessageQueue.h" + + +/* + * Method: AddMessageTest1::AddMessageTest1() + * Descr: This is the constructor for this class. + */ + +template + AddMessageTest1::AddMessageTest1(std::string name) : + MessageQueueTestCase(name) +{ + } + + +/* + * Method: AddMessageTest1::~AddMessageTest1() + * Descr: This is the destructor for this class. + */ + +template + AddMessageTest1::~AddMessageTest1() +{ + } + + +/* + * Method: AddMessageTest1::setUp() + * Descr: This member function is called just prior to running the test. + * It resets the destructor count for testMessageClass. + */ + +template + void AddMessageTest1::setUp(void) +{ + testMessageClass::messageDestructorCount = 0; + } + + +/* + * Method: AddMessageTest1::PerformTest() + * Descr: This member function performs this test. It adds + * 10000 messages to the message queue and confirms that + * the queue contains the right messages. Then it confirms + * that all 10000 messages are deleted when the message + * queue is deleted. + */ + +template + void AddMessageTest1::PerformTest(void) +{ + assert(theMessageQueue->IsEmpty()); + assert(theMessageQueue->CountMessages() == 0); + + int i; + for(i = 0; i < 10000; i++) { + BMessage *theMessage = new testMessageClass(i); + AddMessage(theMessage); + assert(!theMessageQueue->IsEmpty()); + assert(theMessageQueue->CountMessages() == i + 1); + } + + CheckQueueAgainstList(); + + assert(testMessageClass::messageDestructorCount == 0); + delete theMessageQueue; + theMessageQueue = NULL; + assert(testMessageClass::messageDestructorCount == 10000); +} + + +/* + * Method: AddMessageTest1::suite() + * Descr: This static member function returns a test caller for performing + * all combinations of "AddMessageTest1". The test + * is created as a ThreadedTestCase (typedef'd as + * AddMessageTest1Caller) with only one thread. + */ + +template Test *AddMessageTest1::suite(void) +{ + AddMessageTest1 *theTest = new AddMessageTest1(""); + AddMessageTest1Caller *testCaller = new AddMessageTest1Caller("", theTest); + testCaller->addThread(":Thread1", &AddMessageTest1::PerformTest); + + return(testCaller); + } + + +template class AddMessageTest1; +template class AddMessageTest1; \ No newline at end of file diff --git a/src/tests/kits/app/bmessagequeue/AddMessageTest1.h b/src/tests/kits/app/bmessagequeue/AddMessageTest1.h new file mode 100644 index 0000000000..6ff7e5f467 --- /dev/null +++ b/src/tests/kits/app/bmessagequeue/AddMessageTest1.h @@ -0,0 +1,34 @@ +/* + $Id: AddMessageTest1.h,v 1.1 2002/07/09 12:24:56 ejakowatz Exp $ + + This file defines a class for performing one test of BMessageQueue + functionality. + + */ + + +#ifndef AddMessageTest1_H +#define AddMessageTest1_H + + +#include "MessageQueueTestCase.h" +#include "Test.h" +#include "ThreadedTestCaller.h" + + +template class AddMessageTest1 : + public MessageQueueTestCase { + +private: + typedef ThreadedTestCaller > + AddMessageTest1Caller; + +public: + static Test *suite(void); + void setUp(void); + void PerformTest(void); + AddMessageTest1(std::string); + virtual ~AddMessageTest1(); + }; + +#endif \ No newline at end of file diff --git a/src/tests/kits/app/bmessagequeue/AddMessageTest2.cpp b/src/tests/kits/app/bmessagequeue/AddMessageTest2.cpp new file mode 100644 index 0000000000..344a3b9f9e --- /dev/null +++ b/src/tests/kits/app/bmessagequeue/AddMessageTest2.cpp @@ -0,0 +1,110 @@ +/* + $Id: AddMessageTest2.cpp,v 1.1 2002/07/09 12:24:56 ejakowatz Exp $ + + This file implements the second test for the OpenBeOS BMessageQueue code. + It tests the Add Message 2 use case. It does so by doing the following: + - creates 4 BMessages + - it adds them to the queue and a list + - it checks the queue against the list + - it adds the second one to the queue and the list again + - it checks the queue against the list again (expecting an error) + + */ + + +#include "AddMessageTest2.h" +#include +#include +#include "MessageQueue.h" + + +/* + * Method: AddMessageTest2::AddMessageTest2() + * Descr: This is the constructor for this class. + */ + +template + AddMessageTest2::AddMessageTest2(std::string name) : + MessageQueueTestCase(name) +{ + } + + +/* + * Method: AddMessageTest2::~AddMessageTest2() + * Descr: This is the destructor for this class. + */ + +template + AddMessageTest2::~AddMessageTest2() +{ + } + + +/* + * Method: AddMessageTest2::PerformTest() + * Descr: This member function performs this test. It adds + * 4 messages to the message queue and confirms that + * the queue contains the right messages. Then it re-adds + * the second message again. It checks the queue against + * the list and expects to find a difference. Then, it + * checks each element on the queue one by one. + */ + +template + void AddMessageTest2::PerformTest(void) +{ + BMessage *firstMessage = new BMessage(1); + BMessage *secondMessage = new BMessage(2); + BMessage *thirdMessage = new BMessage(3); + BMessage *fourthMessage = new BMessage(4); + + AddMessage(firstMessage); + AddMessage(secondMessage); + AddMessage(thirdMessage); + AddMessage(fourthMessage); + + CheckQueueAgainstList(); + + AddMessage(secondMessage); + + // Re-adding a message to the message queue will result in the list + // not matching the message queue. Therefore, we expect an exception + // to be raised. An error occurs if it doesn't get raised. + bool exceptionRaised = false; + try { + CheckQueueAgainstList(); + } + catch (CppUnitException e) { + exceptionRaised = true; + } + assert(exceptionRaised); + + assert(theMessageQueue->FindMessage((int32)0) == firstMessage); + assert(theMessageQueue->FindMessage((int32)1) == secondMessage); + assert(theMessageQueue->FindMessage((int32)2) == NULL); + assert(theMessageQueue->FindMessage((int32)3) == NULL); + assert(theMessageQueue->FindMessage((int32)4) == NULL); +} + + +/* + * Method: AddMessageTest2::suite() + * Descr: This static member function returns a test caller for performing + * all combinations of "AddMessageTest2". The test + * is created as a ThreadedTestCase (typedef'd as + * AddMessageTest2Caller) with only one thread. + */ + +template Test *AddMessageTest2::suite(void) +{ + AddMessageTest2 *theTest = new AddMessageTest2(""); + AddMessageTest2Caller *testCaller = new AddMessageTest2Caller("", theTest); + testCaller->addThread(":Thread1", &AddMessageTest2::PerformTest); + + return(testCaller); + } + + +template class AddMessageTest2; +template class AddMessageTest2; \ No newline at end of file diff --git a/src/tests/kits/app/bmessagequeue/AddMessageTest2.h b/src/tests/kits/app/bmessagequeue/AddMessageTest2.h new file mode 100644 index 0000000000..9bba1cb38a --- /dev/null +++ b/src/tests/kits/app/bmessagequeue/AddMessageTest2.h @@ -0,0 +1,33 @@ +/* + $Id: AddMessageTest2.h,v 1.1 2002/07/09 12:24:56 ejakowatz Exp $ + + This file defines a class for performing one test of BMessageQueue + functionality. + + */ + + +#ifndef AddMessageTest2_H +#define AddMessageTest2_H + + +#include "MessageQueueTestCase.h" +#include "Test.h" +#include "ThreadedTestCaller.h" + + +template class AddMessageTest2 : + public MessageQueueTestCase { + +private: + typedef ThreadedTestCaller > + AddMessageTest2Caller; + +public: + static Test *suite(void); + virtual void PerformTest(void); + AddMessageTest2(std::string); + virtual ~AddMessageTest2(); + }; + +#endif \ No newline at end of file diff --git a/src/tests/kits/app/bmessagequeue/ConcurrencyTest1.cpp b/src/tests/kits/app/bmessagequeue/ConcurrencyTest1.cpp new file mode 100644 index 0000000000..17a16e4385 --- /dev/null +++ b/src/tests/kits/app/bmessagequeue/ConcurrencyTest1.cpp @@ -0,0 +1,223 @@ +/* + $Id: ConcurrencyTest1.cpp,v 1.1 2002/07/09 12:24:56 ejakowatz Exp $ + + This file implements a test class for testing BMessageQueue functionality. + It tests use cases Destruction, Add Message 1, Add Message 3, Remove Message 1, + Remove Message 2, Count Messages, Find Message 1, Next Message 1 and Next Message + 2. + + The test works like the following: + - It does the test two times, one using an internal BList to keep track of + what should be in the queue and once without. It does it without because + using the internal BList isn't a good test of mutual exclusion because an + explicit lock is used. However, it is worth testing with the BList to show + that the result is what was expected. + - It starts three threads. + - In one thread, numAddMessages are added to the queue + - In the second thread, numNextMessages are removed from the queue using + NextMessage(). + - In the third thread, numAddMessages are added to the queue however every + numRemovedMessagesPerAdd messages is removed using RemoveMessage(). + - Once all three threads complete, the number of elements on the queue is + compared to what it expects. + - If the BList is being used internally, the queue is checked against the list. + - It checks that no BMessages have been deleted. + - It deletes the message queue. + - It checks that the expected number of BMessages have been deleted. + - It creates a new message queue and restarts the test again if necessary + (ie perform it without the internal list). + + */ + + +#include "ConcurrencyTest1.h" +#include "ThreadedTestCaller.h" +#include "TestSuite.h" +#include +#include "MessageQueue.h" + + +// This constant indicates how many messages to add to the queue. +const int numAddMessages = 5000; + +// This constant indicates how many times to call NextMessage() on the queue. +const int numNextMessages = 100; + +// This constant says how many adds to perform before doing a remove. +const int numAddMessagesPerRemove = 5; + + +/* + * Method: ConcurrencyTest1::ConcurrencyTest1() + * Descr: This is the constructor for this test. + */ + +template + ConcurrencyTest1::ConcurrencyTest1(std::string name, bool listFlag) : + MessageQueueTestCase(name), useList(listFlag) +{ + } + + +/* + * Method: ConcurrencyTest1::~ConcurrencyTest1() + * Descr: This is the destructor for this test. + */ + +template + ConcurrencyTest1::~ConcurrencyTest1() +{ + } + + +/* + * Method: ConcurrencyTest1::setUp() + * Descr: This member function prepares the enviroment for test execution. + * It resets the message destructor count and puts "numAddMessages" + * messages on the queue. + */ + +template void ConcurrencyTest1::setUp(void) +{ + testMessageClass::messageDestructorCount = 0; + + int i; + for (i=0; i < numAddMessages; i++) { + BMessage *theMessage = new testMessageClass(i); + if (useList) { + AddMessage(theMessage); + } else { + theMessageQueue->AddMessage(theMessage); + } + } +} + + +/* + * Method: ConcurrencyTest1::TestThread1() + * Descr: This member function is one of the three threads for performing + * this test. It waits until the other two threads complete and + * then checks the state of the message queue. If the list is + * being used, the queue is compared to the list. It checks that + * the expected number of messages are on the queue and that they + * are all deleted when the message queue is destructed. + */ + +template void ConcurrencyTest1::TestThread1(void) +{ + snooze(1000000); + thread2Lock.Lock(); + thread3Lock.Lock(); + + if (useList) { + CheckQueueAgainstList(); + } + + int numMessages = (2*numAddMessages) - + (numAddMessages / numAddMessagesPerRemove) - + numNextMessages; + assert(numMessages == theMessageQueue->CountMessages()); + assert(testMessageClass::messageDestructorCount == 0); + + delete theMessageQueue; + theMessageQueue = NULL; + assert(testMessageClass::messageDestructorCount == numMessages); +} + + +/* + * Method: ConcurrencyTest1::TestThread2() + * Descr: This member function is one of the three threads for performing + * this test. It performs NextMessage() numNextMessages times on + * the queue. It confirms that it always receives a message from + * the queue. + */ + +template void ConcurrencyTest1::TestThread2(void) +{ + thread2Lock.Lock(); + SafetyLock mySafetyLock(&thread2Lock); + + int i; + for(i = 0; i < numNextMessages; i++) { + snooze(5000); + BMessage *theMessage; + if (useList) { + theMessage = NextMessage(); + } else { + theMessage = theMessageQueue->NextMessage(); + } + assert(theMessage != NULL); + } +} + + +/* + * Method: ConcurrencyTest1::TestThread3() + * Descr: This member function is one of the three threads for performing + * this test. It adds numAddMessages messages to the queue. For + * every numAddMessagesPerRemove messages it adds, one message + * is removed. + */ + +template void ConcurrencyTest1::TestThread3(void) +{ + thread3Lock.Lock(); + SafetyLock mySafetyLock(&thread3Lock); + + int i; + BList messagesToRemove; + + for (i=0; i < numAddMessages; i++) { + BMessage *theMessage = new testMessageClass(i); + if (useList) { + AddMessage(theMessage); + } else { + theMessageQueue->AddMessage(theMessage); + } + if ((i % numAddMessagesPerRemove) == numAddMessagesPerRemove - 1) { + snooze(500); + if (useList) { + RemoveMessage(theMessage); + } else { + theMessageQueue->RemoveMessage(theMessage); + } + } + } +} + + +/* + * Method: ConcurrencyTest1::suite() + * Descr: This static member function returns a test suite for performing + * all combinations of "ConcurrencyTest1". The test suite contains + * two instances of the test. One is performed with a list, + * the other without. Each individual test + * is created as a ThreadedTestCase (typedef'd as + * ConcurrencyTest1Caller) with three independent threads. + */ + +template Test *ConcurrencyTest1::suite(void) +{ + TestSuite *testSuite = new TestSuite("ConcurrencyTest1"); + + ConcurrencyTest1 *theTest = new ConcurrencyTest1("WithList", true); + ConcurrencyTest1Caller *threadedTest1 = new ConcurrencyTest1Caller("", theTest); + threadedTest1->addThread(":Thread1", &ConcurrencyTest1::TestThread1); + threadedTest1->addThread(":Thread2", &ConcurrencyTest1::TestThread2); + threadedTest1->addThread(":Thread3", &ConcurrencyTest1::TestThread3); + + theTest = new ConcurrencyTest1("WithoutList", false); + ConcurrencyTest1Caller *threadedTest2 = new ConcurrencyTest1Caller("", theTest); + threadedTest2->addThread(":Thread1", &ConcurrencyTest1::TestThread1); + threadedTest2->addThread(":Thread2", &ConcurrencyTest1::TestThread2); + threadedTest2->addThread(":Thread3", &ConcurrencyTest1::TestThread3); + + testSuite->addTest(threadedTest1); + testSuite->addTest(threadedTest2); + return(testSuite); + } + + +template class ConcurrencyTest1; +template class ConcurrencyTest1; \ No newline at end of file diff --git a/src/tests/kits/app/bmessagequeue/ConcurrencyTest1.h b/src/tests/kits/app/bmessagequeue/ConcurrencyTest1.h new file mode 100644 index 0000000000..8a2de7733b --- /dev/null +++ b/src/tests/kits/app/bmessagequeue/ConcurrencyTest1.h @@ -0,0 +1,43 @@ +/* + $Id: ConcurrencyTest1.h,v 1.1 2002/07/09 12:24:56 ejakowatz Exp $ + + This file defines a classes for performing one test of BMessageQueue + functionality. + + */ + + +#ifndef ConcurrencyTest1_H +#define ConcurrencyTest1_H + + +#include "MessageQueueTestCase.h" +#include "Test.h" +#include "ThreadedTestCaller.h" +#include + + +template class ConcurrencyTest1 : + public MessageQueueTestCase { + +private: + typedef ThreadedTestCaller > + ConcurrencyTest1Caller; + + bool useList; + BLocker thread2Lock; + BLocker thread3Lock; + +protected: + +public: + static Test *suite(void); + void setUp(void); + void TestThread1(void); + void TestThread2(void); + void TestThread3(void); + ConcurrencyTest1(std::string, bool); + virtual ~ConcurrencyTest1(); + }; + +#endif \ No newline at end of file diff --git a/src/tests/kits/app/bmessagequeue/ConcurrencyTest2.cpp b/src/tests/kits/app/bmessagequeue/ConcurrencyTest2.cpp new file mode 100644 index 0000000000..c379c886dc --- /dev/null +++ b/src/tests/kits/app/bmessagequeue/ConcurrencyTest2.cpp @@ -0,0 +1,274 @@ +/* + $Id: ConcurrencyTest2.cpp,v 1.1 2002/07/09 12:24:56 ejakowatz Exp $ + + This file implements a test class for testing BMessageQueue functionality. + It tests use cases Destruction, Add Message 3, Remove Message 2, + Next Message 2, Lock 1, Lock 2, Unlock. + + The test works like the following: + - It does the test two times, one unlocking using Unlock() and the other + unlocking using delete. + - It populates the queue with numAddMessages messages to start. + - The queue is locked + - It starts four threads. + - In one thread, a NextMessage() blocks + - In the second thread, a RemoveMessage() blocks + - In the third thread, an AddMessage() blocks + - In the fourth thread, a Lock() blocks + - After a short snooze, the queue is released using Unlock() or delete. + - Each of the four threads wake up and each checks as best it can that it + was successful and did not violate mutual exclusion. + + */ + + +#include "ConcurrencyTest2.h" +#include "ThreadedTestCaller.h" +#include "TestSuite.h" +#include +#include "MessageQueue.h" + + +// This constant indicates the number of messages to add to the queue. +const int numAddMessages = 50; + +// This constant is used as a base amount of time to snooze. +bigtime_t SNOOZE_TIME = 100000; + + +/* + * Method: ConcurrencyTest2::ConcurrencyTest2() + * Descr: This is the constructor for this test. + */ + +template + ConcurrencyTest2::ConcurrencyTest2(std::string name, bool unlockFlag) : + MessageQueueTestCase(name), unlockTest(unlockFlag) +{ + } + + +/* + * Method: ConcurrencyTest2::~ConcurrencyTest2() + * Descr: This is the destructor for this test. + */ + +template + ConcurrencyTest2::~ConcurrencyTest2() +{ + } + + +/* + * Method: ConcurrencyTest2::setUp() + * Descr: This member functions sets the environment for the test. + * it sets the lock flag and resets the message destructor + * count. Finally, it adds numAddMessages messages to the + * queue. + */ + +template + void ConcurrencyTest2::setUp(void) +{ + isLocked = false; + testMessageClass::messageDestructorCount = 0; + + int i; + BMessage *theMessage; + for (i=0; i < numAddMessages; i++) { + theMessage = new testMessageClass(i); + theMessageQueue->AddMessage(theMessage); + } + removeMessage = theMessage; +} + + +/* + * Method: ConcurrencyTest2::TestThread1() + * Descr: This member function is one thread within the test. It + * acquires the lock on the queue and then sleeps for a while. + * When it wakes up, it releases the lock on the queue by + * either doing an Unlock() or deleting the queue. + */ + +template + void ConcurrencyTest2::TestThread1(void) +{ + theMessageQueue->Lock(); + isLocked = true; + + snooze(SNOOZE_TIME); + + isLocked = false; + if (unlockTest) { + theMessageQueue->Unlock(); + } else { + MessageQueue *tmpMessageQueue = theMessageQueue; + theMessageQueue = NULL; + delete tmpMessageQueue; + } +} + + +/* + * Method: ConcurrencyTest2::TestThread2() + * Descr: This member function is one thread within the test. It + * snoozes for a short time so that TestThread1() will grab + * the lock. If this is the delete test, this thread + * terminates since Be's implementation may corrupt memory. + * Otherwise, the thread blocks attempting a NextMessage() on + * the queue. The result of NextMessage() is checked finally. + */ + +template void ConcurrencyTest2::TestThread2(void) +{ + snooze(SNOOZE_TIME/10); + assert(isLocked); + if (!unlockTest) { + // Be's implementation can cause a segv when NextMessage() is in + // progress when a delete occurs. The OpenBeOS implementation + // does not segv, but it won't be tested here because Be's fails. + return; + } + BMessage *theMessage = theMessageQueue->NextMessage(); + assert(!isLocked); + + if (unlockTest) { + assert(theMessage != NULL); + assert(theMessage->what == 0); + } else { + // The following test passes for the OpenBeOS implementation but + // fails for the Be implementation. If the BMessageQueue is deleted + // while another thread is blocking waiting for NextMessage(), the + // OpenBeOS implementation detects that the message queue is deleted + // and returns NULL. The Be implementation actually returns a message. + // It must be doing so from freed memory since the queue has been + // deleted. The OpenBeOS implementation will not emulate the Be + // implementation since I consider it a bug. + // + // assert(theMessage==NULL); + } +} + + +/* + * Method: ConcurrencyTest2::TestThread3() + * Descr: This member function is one thread within the test. It + * snoozes for a short time so that TestThread1() will grab + * the lock. If this is the delete test, this thread + * terminates since Be's implementation may corrupt memory. + * Otherwise, the thread blocks attempting a RemoveMessage() + * on the queue. The state of the queue is checked finally. + */ + +template void ConcurrencyTest2::TestThread3(void) +{ + snooze(SNOOZE_TIME/10); + assert(isLocked); + if (!unlockTest) { + // Be's implementation causes a segv when RemoveMessage() is in + // progress when a delete occurs. The OpenBeOS implementation + // does not segv, but it won't be tested here because Be's fails. + return; + } + theMessageQueue->RemoveMessage(removeMessage); + assert(!isLocked); + if (unlockTest) { + assert(theMessageQueue->FindMessage(removeMessage->what, 0) == NULL); + } +} + + +/* + * Method: ConcurrencyTest2::TestThread1() + * Descr: This member function is one thread within the test. It + * snoozes for a short time so that TestThread1() will grab + * the lock. If this is the delete test, this thread + * terminates since Be's implementation may corrupt memory. + * Otherwise, the thread blocks attempting a AddMessage() on + * the queue. The state of the queue is checked finally. + */ + +template void ConcurrencyTest2::TestThread4(void) +{ + snooze(SNOOZE_TIME/10); + assert(isLocked); + if (!unlockTest) { + // Be's implementation can cause a segv when AddMessage() is in + // progress when a delete occurs. The OpenBeOS implementation + // does not segv, but it won't be tested here because Be's fails. + return; + } + theMessageQueue->AddMessage(new testMessageClass(numAddMessages)); + assert(!isLocked); + if (unlockTest) { + assert(theMessageQueue->FindMessage(numAddMessages, 0) != NULL); + } +} + + +/* + * Method: ConcurrencyTest2::TestThread1() + * Descr: This member function is one thread within the test. It + * snoozes for a short time so that TestThread1() will grab + * the lock. The thread blocks attempting to acquire the + * lock on the queue. Once the lock is acquired, mutual + * exclusion is checked as well as the result of the lock + * acquisition. + */ + +template void ConcurrencyTest2::TestThread5(void) +{ + SafetyLock mySafetyLock(theMessageQueue); + + snooze(SNOOZE_TIME/10); + assert(isLocked); + bool result = theMessageQueue->Lock(); + assert(!isLocked); + if (unlockTest) { + assert(result); + theMessageQueue->Unlock(); + } else { + assert(!result); + } +} + + +/* + * Method: ConcurrencyTest2::suite() + * Descr: This static member function returns a test suite for performing + * all combinations of "ConcurrencyTest2". The test suite contains + * two instances of the test. One is performed with an unlock, + * the other with a delete. Each individual test + * is created as a ThreadedTestCase (typedef'd as + * ConcurrencyTest2Caller) with five independent threads. + */ + +template Test *ConcurrencyTest2::suite(void) +{ + TestSuite *testSuite = new TestSuite("ConcurrencyTest2"); + + ConcurrencyTest2 *theTest = new ConcurrencyTest2("WithUnlock", true); + ConcurrencyTest2Caller *threadedTest1 = new ConcurrencyTest2Caller("", theTest); + threadedTest1->addThread(":Thread1", &ConcurrencyTest2::TestThread1); + threadedTest1->addThread(":Thread2", &ConcurrencyTest2::TestThread2); + threadedTest1->addThread(":Thread3", &ConcurrencyTest2::TestThread3); + threadedTest1->addThread(":Thread3", &ConcurrencyTest2::TestThread4); + threadedTest1->addThread(":Thread3", &ConcurrencyTest2::TestThread5); + + theTest = new ConcurrencyTest2("WithDelete", false); + ConcurrencyTest2Caller *threadedTest2 = new ConcurrencyTest2Caller("", theTest); + threadedTest2->addThread(":Thread1", &ConcurrencyTest2::TestThread1); + threadedTest2->addThread(":Thread2", &ConcurrencyTest2::TestThread2); + threadedTest2->addThread(":Thread3", &ConcurrencyTest2::TestThread3); + threadedTest2->addThread(":Thread3", &ConcurrencyTest2::TestThread4); + threadedTest2->addThread(":Thread3", &ConcurrencyTest2::TestThread5); + + testSuite->addTest(threadedTest1); + testSuite->addTest(threadedTest2); + return(testSuite); + } + + +template class ConcurrencyTest2; +template class ConcurrencyTest2; \ No newline at end of file diff --git a/src/tests/kits/app/bmessagequeue/ConcurrencyTest2.h b/src/tests/kits/app/bmessagequeue/ConcurrencyTest2.h new file mode 100644 index 0000000000..469ca37954 --- /dev/null +++ b/src/tests/kits/app/bmessagequeue/ConcurrencyTest2.h @@ -0,0 +1,42 @@ +/* + $Id: ConcurrencyTest2.h,v 1.1 2002/07/09 12:24:56 ejakowatz Exp $ + + This file defines a classes for performing one test of BMessageQueue + functionality. + + */ + + +#ifndef ConcurrencyTest2_H +#define ConcurrencyTest2_H + + +#include "MessageQueueTestCase.h" +#include "Test.h" +#include "ThreadedTestCaller.h" + + +template class ConcurrencyTest2 : + public MessageQueueTestCase { + +private: + typedef ThreadedTestCaller > + ConcurrencyTest2Caller; + + bool unlockTest; + bool isLocked; + BMessage *removeMessage; + +public: + static Test *suite(void); + void setUp(void); + void TestThread1(void); + void TestThread2(void); + void TestThread3(void); + void TestThread4(void); + void TestThread5(void); + ConcurrencyTest2(std::string, bool); + virtual ~ConcurrencyTest2(); + }; + +#endif \ No newline at end of file diff --git a/src/tests/kits/app/bmessagequeue/FindMessageTest1.cpp b/src/tests/kits/app/bmessagequeue/FindMessageTest1.cpp new file mode 100644 index 0000000000..c0f896b07d --- /dev/null +++ b/src/tests/kits/app/bmessagequeue/FindMessageTest1.cpp @@ -0,0 +1,114 @@ +/* + $Id: FindMessageTest1.cpp,v 1.1 2002/07/09 12:24:56 ejakowatz Exp $ + + This file implements the second test for the OpenBeOS BMessageQueue code. + It tests the Add Message 1 and Find Message 2 use cases. It does so by + doing the following: + - creates numPerWhatCode * numWhatCodes messages and puts them on + the queue and the list + - searches for the xth instance of a what code using FindMessage() + and by searching the list + - compares the result of the two + - there are many cases where FindMessage() returns NULL and those are + checked also + - it does all searches for all the what codes used plus two not + actually used + + */ + + +#include "FindMessageTest1.h" +#include +#include +#include "MessageQueue.h" + + +// This constant indicates the number of different what codes to use +// in messages added to the queue. +const int numWhatCodes = 20; + +// This constant indicates the number of times a what code should be +// added to the list. +const int numPerWhatCode = 50; + + +/* + * Method: FindMessageTest1::FindMessageTest1() + * Descr: This is the constructor for this test class. + */ + +template + FindMessageTest1::FindMessageTest1(std::string name) : + MessageQueueTestCase(name) +{ + } + + +/* + * Method: FindMessageTest1::~FindMessageTest1() + * Descr: This is the destructor for this test class. + */ + +template + FindMessageTest1::~FindMessageTest1() +{ + } + + +/* + * Method: FindMessageTest1::PerformTest() + * Descr: This is the member function for executing the test. + * It adds numPerWhatCode*numWhatCodes messages to the + * queue. Then, it uses FindMessage() to search for + * each message using the queue and the list. It + * checks that the queue and list return the same result. + */ + +template + void FindMessageTest1::PerformTest(void) +{ + int whatCode; + int i; + BMessage *theMessage; + BMessage *listMessage; + + for (i = 0; i < numPerWhatCode; i++) { + for (whatCode = 1; whatCode <= numWhatCodes; whatCode++) { + AddMessage(new testMessageClass(whatCode)); + } + } + + for (whatCode = 0; whatCode <= numWhatCodes + 1; whatCode++) { + int index = 0; + while ((theMessage = theMessageQueue->FindMessage(whatCode, + index)) != NULL) { + listMessage = FindMessage(whatCode, index); + assert(listMessage == theMessage); + index++; + } + listMessage = FindMessage(whatCode, index); + assert(listMessage == theMessage); + } +} + + +/* + * Method: FindMessageTest1::suite() + * Descr: This static member function returns a test caller for performing + * all combinations of "FindMessageTest1". The test + * is created as a ThreadedTestCase (typedef'd as + * FindMessageTest1Caller) with only one thread. + */ + +template Test *FindMessageTest1::suite(void) +{ + FindMessageTest1 *theTest = new FindMessageTest1(""); + FindMessageTest1Caller *testCaller = new FindMessageTest1Caller("", theTest); + testCaller->addThread(":Thread1", &FindMessageTest1::PerformTest); + + return(testCaller); + } + + +template class FindMessageTest1; +template class FindMessageTest1; \ No newline at end of file diff --git a/src/tests/kits/app/bmessagequeue/FindMessageTest1.h b/src/tests/kits/app/bmessagequeue/FindMessageTest1.h new file mode 100644 index 0000000000..848edfc6ba --- /dev/null +++ b/src/tests/kits/app/bmessagequeue/FindMessageTest1.h @@ -0,0 +1,33 @@ +/* + $Id: FindMessageTest1.h,v 1.1 2002/07/09 12:24:56 ejakowatz Exp $ + + This file defines a classes for performing one test of BMessageQueue + functionality. + + */ + + +#ifndef FindMessageTest1_H +#define FindMessageTest1_H + + +#include "MessageQueueTestCase.h" +#include "Test.h" +#include "ThreadedTestCaller.h" + + +template class FindMessageTest1 : + public MessageQueueTestCase { + +private: + typedef ThreadedTestCaller > + FindMessageTest1Caller; + +public: + static Test *suite(void); + void PerformTest(void); + FindMessageTest1(std::string); + virtual ~FindMessageTest1(); + }; + +#endif \ No newline at end of file diff --git a/src/tests/kits/app/bmessagequeue/Jamfile b/src/tests/kits/app/bmessagequeue/Jamfile new file mode 100644 index 0000000000..062cb83ec2 --- /dev/null +++ b/src/tests/kits/app/bmessagequeue/Jamfile @@ -0,0 +1,18 @@ +SubDir OBOS_TOP sources tests kits app BMessageQueue ; + +UsePublicHeaders app support ; + +UnitTest BMessageQueueTester : + AddMessageTest1.cpp + AddMessageTest2.cpp + ConcurrencyTest1.cpp + ConcurrencyTest2.cpp + FindMessageTest1.cpp + MessageQueueTestAddon.cpp + MessageQueueTestCase.cpp + : kits/app ; + +LinkSharedOSLibs BMessageQueueTester : + libopenbeos.so + be + stdc++.r4 ; diff --git a/src/tests/kits/app/bmessagequeue/MessageQueueTestAddon.cpp b/src/tests/kits/app/bmessagequeue/MessageQueueTestAddon.cpp new file mode 100644 index 0000000000..a043f27b71 --- /dev/null +++ b/src/tests/kits/app/bmessagequeue/MessageQueueTestAddon.cpp @@ -0,0 +1,49 @@ +/* + $Id: MessageQueueTestAddon.cpp,v 1.1 2002/07/09 12:24:56 ejakowatz Exp $ + + This file declares the addonTestName string and addonTestFunc + function for the BMessageQueue tests. These symbols will be used + when the addon is loaded. + + */ + + +#include "AddMessageTest1.h" +#include "AddMessageTest2.h" +#include "ConcurrencyTest1.h" +#include "ConcurrencyTest2.h" +#include "FindMessageTest1.h" +#include +#include "MessageQueue.h" +#include "TestAddon.h" +#include "TestSuite.h" + + +/* + * Function: addonTestFunc() + * Descr: This function is called by the test application to + * get a pointer to the test to run. The BMessageQueue test + * is a test suite. A series of tests are added to + * the suite. Each test appears twice, once for + * the Be implementation of BMessageQueue, once for the + * OpenBeOS implementation. + */ + +Test *addonTestFunc(void) +{ + TestSuite *testSuite = new TestSuite("BMessageQueue"); + + testSuite->addTest(AddMessageTest1::suite()); + testSuite->addTest(AddMessageTest2::suite()); + testSuite->addTest(ConcurrencyTest1::suite()); + testSuite->addTest(ConcurrencyTest2::suite()); + testSuite->addTest(FindMessageTest1::suite()); + + testSuite->addTest(AddMessageTest1::suite()); + testSuite->addTest(AddMessageTest2::suite()); + testSuite->addTest(ConcurrencyTest1::suite()); + testSuite->addTest(ConcurrencyTest2::suite()); + testSuite->addTest(FindMessageTest1::suite()); + + return(testSuite); +} diff --git a/src/tests/kits/app/bmessagequeue/MessageQueueTestCase.cpp b/src/tests/kits/app/bmessagequeue/MessageQueueTestCase.cpp new file mode 100644 index 0000000000..31d787ecc7 --- /dev/null +++ b/src/tests/kits/app/bmessagequeue/MessageQueueTestCase.cpp @@ -0,0 +1,106 @@ +/* + $Id: MessageQueueTestCase.cpp,v 1.1 2002/07/09 12:24:56 ejakowatz Exp $ + + This file implements a base class for testing BMessageQueue functionality. + + */ + + +#include "MessageQueueTestCase.h" +#include +#include "MessageQueue.h" + + +int testMessageClass::messageDestructorCount = 0; + + +template + MessageQueueTestCase::MessageQueueTestCase( + std::string name) : TestCase(name), + theMessageQueue(new MessageQueue) +{ + } + + +template + MessageQueueTestCase::~MessageQueueTestCase() +{ + delete theMessageQueue; + theMessageQueue = NULL; + } + + +template + void MessageQueueTestCase::CheckQueueAgainstList(void) +{ + SafetyLock theSafetyLock(theMessageQueue); + + if (theMessageQueue->Lock()) { + assert(theMessageQueue->CountMessages() == messageList.CountItems()); + int i; + for (i = 0; i < theMessageQueue->CountMessages(); i++) { + assert(theMessageQueue->FindMessage((int32)i) == + messageList.ItemAt(i)); + } + theMessageQueue->Unlock(); + } +} + + +template + void MessageQueueTestCase::AddMessage(BMessage *message) +{ + if (theMessageQueue->Lock()) { + theMessageQueue->AddMessage(message); + messageList.AddItem(message); + theMessageQueue->Unlock(); + } +} + +template + void MessageQueueTestCase::RemoveMessage(BMessage *message) +{ + if (theMessageQueue->Lock()) { + theMessageQueue->RemoveMessage(message); + messageList.RemoveItem((void *)message); + theMessageQueue->Unlock(); + } +} + +template + BMessage *MessageQueueTestCase::NextMessage(void) +{ + SafetyLock theSafetyLock(theMessageQueue); + + BMessage *result = NULL; + if (theMessageQueue->Lock()) { + result = theMessageQueue->NextMessage(); + assert(result == messageList.RemoveItem((int32)0)); + theMessageQueue->Unlock(); + } + return(result); +} + + +template + BMessage *MessageQueueTestCase::FindMessage(uint32 what, int index) +{ + int listCount = messageList.CountItems(); + int i; + + for (i = 0; i < listCount; i++) { + BMessage *theMessage = (BMessage *)messageList.ItemAt(i); + if (theMessage->what == what) { + if (index == 0) { + return(theMessage); + } + index--; + } + } + + return(NULL); +} + + +template class MessageQueueTestCase; +template class MessageQueueTestCase; \ No newline at end of file diff --git a/src/tests/kits/app/bmessagequeue/MessageQueueTestCase.h b/src/tests/kits/app/bmessagequeue/MessageQueueTestCase.h new file mode 100644 index 0000000000..374a851c4c --- /dev/null +++ b/src/tests/kits/app/bmessagequeue/MessageQueueTestCase.h @@ -0,0 +1,79 @@ +/* + $Id: MessageQueueTestCase.h,v 1.1 2002/07/09 12:24:56 ejakowatz Exp $ + + This file defines a set of classes for testing BMessageQueue + functionality. + + */ + + +#ifndef MessageQueueTestCase_H +#define MessageQueueTestCase_H + + +#include +#include +#include +#include "TestCase.h" + + +// +// The SafetyLock class is a utility class for use in actual tests +// of the BMessageQueue interfaces. It is used to make sure that if the +// test fails and an exception is thrown with the lock held on the message +// queue, that lock will be released. Without this SafetyLock, there +// could be deadlocks if one thread in a test has a failure while holding +// the lock. It should be used like so: +// +// template void myTestClass::myTestFunc(void) +// { +// SafetyLock mySafetyLock(theMessageQueue); +// ...perform tests without worrying about holding the lock on assert... +// + +template class SafetyLock { +private: + MessageQueue *theMessageQueue; + +public: + SafetyLock(MessageQueue *aMessageQueue) {theMessageQueue = aMessageQueue;} + virtual ~SafetyLock() {if (theMessageQueue != NULL) theMessageQueue->Unlock(); }; + }; + + +// +// The testMessageClass is used to count the number of messages that are +// deleted. This is used to check that all messages on the message queue +// were properly free'ed. +// + +class testMessageClass : public BMessage +{ +public: + static int messageDestructorCount; + virtual ~testMessageClass() { messageDestructorCount++; }; + testMessageClass(int what) : BMessage(what) { }; +}; + + +template class MessageQueueTestCase : public TestCase { + +private: + BList messageList; + +protected: + MessageQueue *theMessageQueue; + + void AddMessage(BMessage *message); + void RemoveMessage(BMessage *message); + BMessage *NextMessage(void); + BMessage *FindMessage(uint32 what, int index); + + void CheckQueueAgainstList(void); + +public: + MessageQueueTestCase(std::string); + virtual ~MessageQueueTestCase(); + }; + +#endif \ No newline at end of file diff --git a/src/tests/kits/app/bmessenger/BMessengerCases b/src/tests/kits/app/bmessenger/BMessengerCases new file mode 100644 index 0000000000..c74e07f07c --- /dev/null +++ b/src/tests/kits/app/bmessenger/BMessengerCases @@ -0,0 +1,61 @@ +BMessenger() +case 1: IsValid() should return false. + IsTargetLocal() should return false. + Target() should return NULL and NULL for looper. + Team() should return -1. + +BMessenger(const BHandler *handler, const BLooper *looper, status_t *result) +case 1: handler is NULL, looper is NULL, result is NULL => + IsValid() and IsTargetLocal() should return false + Target() should return NULL and NULL for looper. + Team() should return -1. +case 2: handler is NULL, looper is NULL, result is not NULL => + IsValid() and IsTargetLocal() should return false. + Target() should return NULL and NULL for looper. + Team() should return -1. + result is set to B_BAD_VALUE. +case 3: handler is NULL, looper is not NULL, result is not NULL => + IsValid() and IsTargetLocal() should return true. + Target() should return NULL and the correct value for looper. + Team() should return this team. + result is set to B_OK. +case 4: handler is not NULL, looper is NULL, result is not NULL, + handler doesn't belong to a looper => + IsValid() and IsTargetLocal() should return false. + Target() should return NULL and NULL for looper. + Team() should return -1. + result is set to B_MISMATCHED_VALUES. +case 5: handler is not NULL, looper is NULL, result is not NULL + handler does belong to a looper => + IsValid() and IsTargetLocal() should return true. + Target() should return the correct handler and handler->Looper() + for looper. + Team() should return this team. + result is set to B_OK. +case 6: handler is not NULL, looper is not NULL, result is not NULL + handler does belong to the looper => + IsValid() and IsTargetLocal() should return true. + Target() should return the correct handler and the correct value + for looper. + Team() should return this team. + result is set to B_OK. +case 7: handler is not NULL, looper is not NULL, result is not NULL + handler does belong to a different looper => + IsValid() and IsTargetLocal() should return false. + Target() should return NULL and NULL for looper. + Team() should return -1. + result is set to B_MISMATCHED_VALUES. + +BMessenger(const BMessenger &from) +case 1: from is uninitialized => + IsValid() and IsTargetLocal() should return false + Target() should return NULL and NULL for looper. + Team() should return -1. +case 2: from is properly initialized to a local target => + IsValid() and IsTargetLocal() should return true + Target() should return the same values as for from. + Team() should return this team. + +BMessenger(const char *signature, team_id team, status_t *result) +TODO + diff --git a/src/tests/kits/app/bmessenger/BMessengerTester.cpp b/src/tests/kits/app/bmessenger/BMessengerTester.cpp new file mode 100644 index 0000000000..cf73d65691 --- /dev/null +++ b/src/tests/kits/app/bmessenger/BMessengerTester.cpp @@ -0,0 +1,333 @@ +//------------------------------------------------------------------------------ +// BMessengerTester.cpp +// +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- +#include + +// System Includes ------------------------------------------------------------- +#include +#include + +//#ifdef SYSTEM_TEST +//#include +//#include +//#include +//#else +#include +#include +#include +//#endif + +#define CHK CPPUNIT_ASSERT + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "BMessengerTester.h" +#include "Helpers.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +//------------------------------------------------------------------------------ + +/* + BMessenger() + @case 1 + @results IsValid() should return false. + IsTargetLocal() should return false. + Target() should return NULL and NULL for looper. + Team() should return -1. + */ +void TBMessengerTester::BMessenger1() +{ + BMessenger messenger; + CHK(messenger.IsValid() == false); + CHK(messenger.IsTargetLocal() == false); + BLooper *looper; + CHK(messenger.Target(&looper) == NULL); + CHK(looper == NULL); + CHK(messenger.Team() == -1); +} + +/* + BMessenger(const BHandler *handler, const BLooper *looper, + status_t *result) + @case 1 handler is NULL, looper is NULL, result is NULL + @results IsValid() and IsTargetLocal() should return false + Target() should return NULL and NULL for looper. + Team() should return -1. + */ +void TBMessengerTester::BMessenger2() +{ + BMessenger messenger((const BHandler*)NULL, NULL, NULL); + CHK(messenger.IsValid() == false); + CHK(messenger.IsTargetLocal() == false); + BLooper *looper; + CHK(messenger.Target(&looper) == NULL); + CHK(looper == NULL); + CHK(messenger.Team() == -1); +} + +/* + BMessenger(const BHandler *handler, const BLooper *looper, + status_t *result) + @case 2 handler is NULL, looper is NULL, result is not NULL + @results IsValid() and IsTargetLocal() should return false. + Target() should return NULL and NULL for looper. + Team() should return -1. + result is set to B_BAD_VALUE. + */ +void TBMessengerTester::BMessenger3() +{ + status_t result = B_OK; + BMessenger messenger((const BHandler*)NULL, NULL, &result); + CHK(messenger.IsValid() == false); + CHK(messenger.IsTargetLocal() == false); + BLooper *looper; + CHK(messenger.Target(&looper) == NULL); + CHK(looper == NULL); + CHK(messenger.Team() == -1); + CHK(result == B_BAD_VALUE); +} + +/* + BMessenger(const BHandler *handler, const BLooper *looper, + status_t *result) + @case 3 handler is NULL, looper is not NULL, result is not NULL + @results IsValid() and IsTargetLocal() should return true. + Target() should return NULL and the correct value for + looper. + Team() should return this team. + result is set to B_OK. + */ +void TBMessengerTester::BMessenger4() +{ + status_t result = B_OK; + BLooper *looper = new BLooper; + looper->Run(); + LooperQuitter quitter(looper); + BMessenger messenger(NULL, looper, &result); + CHK(messenger.IsValid() == true); + CHK(messenger.IsTargetLocal() == true); + BLooper *resultLooper; + CHK(messenger.Target(&resultLooper) == NULL); + CHK(resultLooper == looper); + CHK(messenger.Team() == get_this_team()); + CHK(result == B_OK); +} + +/* + BMessenger(const BHandler *handler, const BLooper *looper, + status_t *result) + @case 4 handler is not NULL, looper is NULL, result is not NULL, + handler doesn't belong to a looper + @results IsValid() and IsTargetLocal() should return false. + Target() should return NULL and NULL for looper. + Team() should return -1. + result is set to B_MISMATCHED_VALUES. + */ +void TBMessengerTester::BMessenger5() +{ + status_t result = B_OK; + BHandler *handler = new BHandler; + HandlerDeleter deleter(handler); + BMessenger messenger(handler, NULL, &result); + CHK(messenger.IsValid() == false); + CHK(messenger.IsTargetLocal() == false); + BLooper *resultLooper; + CHK(messenger.Target(&resultLooper) == NULL); + CHK(resultLooper == NULL); + CHK(messenger.Team() == -1); + CHK(result == B_MISMATCHED_VALUES); +} + +/* + BMessenger(const BHandler *handler, const BLooper *looper, + status_t *result) + @case 5 handler is not NULL, looper is NULL, result is not NULL + handler does belong to a looper + @results IsValid() and IsTargetLocal() should return true. + Target() should return the correct handler and the + handler->Looper() for looper. + Team() should return this team. + result is set to B_OK. + */ +void TBMessengerTester::BMessenger6() +{ + // create looper and handler + status_t result = B_OK; + BLooper *looper = new BLooper; + looper->Run(); + LooperQuitter quitter(looper); + BHandler *handler = new BHandler; + HandlerDeleter deleter(handler); + CHK(looper->Lock()); + looper->AddHandler(handler); + looper->Unlock(); + // create the messenger and do the checks + BMessenger messenger(handler, NULL, &result); + CHK(messenger.IsValid() == true); + CHK(messenger.IsTargetLocal() == true); + BLooper *resultLooper; + CHK(messenger.Target(&resultLooper) == handler); + CHK(resultLooper == looper); + CHK(messenger.Team() == get_this_team()); +//printf("result: %lx\n", result); + CHK(result == B_OK); +} + +/* + BMessenger(const BHandler *handler, const BLooper *looper, + status_t *result) + @case 6 handler is not NULL, looper is not NULL, result is not NULL + handler does belong to the looper + @results IsValid() and IsTargetLocal() should return true. + Target() should return the correct handler and the correct value + for looper. + Team() should return this team. + result is set to B_OK. + */ +void TBMessengerTester::BMessenger7() +{ + // create looper and handler + status_t result = B_OK; + BLooper *looper = new BLooper; + looper->Run(); + LooperQuitter quitter(looper); + BHandler *handler = new BHandler; + HandlerDeleter deleter(handler); + CHK(looper->Lock()); + looper->AddHandler(handler); + looper->Unlock(); + // create the messenger and do the checks + BMessenger messenger(handler, looper, &result); + CHK(messenger.IsValid() == true); + CHK(messenger.IsTargetLocal() == true); + BLooper *resultLooper; + CHK(messenger.Target(&resultLooper) == handler); + CHK(resultLooper == looper); + CHK(messenger.Team() == get_this_team()); +//printf("result: %lx\n", result); + CHK(result == B_OK); +} + +/* + BMessenger(const BHandler *handler, const BLooper *looper, + status_t *result) + @case 7 handler is not NULL, looper is not NULL, result is not NULL + handler does belong to a different looper + @results IsValid() and IsTargetLocal() should return false. + Target() should return NULL and NULL for looper. + Team() should return -1. + result is set to B_MISMATCHED_VALUES. + */ +void TBMessengerTester::BMessenger8() +{ + // create loopers and handler + status_t result = B_OK; + BLooper *looper = new BLooper; + looper->Run(); + LooperQuitter quitter(looper); + BLooper *looper2 = new BLooper; + looper2->Run(); + LooperQuitter quitter2(looper2); + BHandler *handler = new BHandler; + HandlerDeleter deleter(handler); + CHK(looper->Lock()); + looper->AddHandler(handler); + looper->Unlock(); + // create the messenger and do the checks + BMessenger messenger(handler, looper2, &result); + CHK(messenger.IsValid() == false); + CHK(messenger.IsTargetLocal() == false); + BLooper *resultLooper; + CHK(messenger.Target(&resultLooper) == NULL); + CHK(resultLooper == NULL); + CHK(messenger.Team() == -1); +//printf("result: %lx\n", result); + CHK(result == B_MISMATCHED_VALUES); +} + +/* + BMessenger(const BMessenger &from) + @case 1 from is uninitialized + @results IsValid() and IsTargetLocal() should return false + Target() should return NULL and NULL for looper. + Team() should return -1. + */ +void TBMessengerTester::BMessenger9() +{ + BMessenger from; + BMessenger messenger(from); + CHK(messenger.IsValid() == false); + CHK(messenger.IsTargetLocal() == false); + BLooper *looper; + CHK(messenger.Target(&looper) == NULL); + CHK(looper == NULL); + CHK(messenger.Team() == -1); +} + + +/* + BMessenger(const BMessenger &from) + @case 2 from is properly initialized to a local target + @results IsValid() and IsTargetLocal() should return true + Target() should return the same values as for from. + Team() should return this team. + */ +void TBMessengerTester::BMessenger10() +{ + // create looper and handler + status_t result = B_OK; + BLooper *looper = new BLooper; + looper->Run(); + LooperQuitter quitter(looper); + BHandler *handler = new BHandler; + HandlerDeleter deleter(handler); + CHK(looper->Lock()); + looper->AddHandler(handler); + looper->Unlock(); + // create the from messenger + BMessenger from(handler, looper, &result); + CHK(from.IsValid() == true); + CHK(from.IsTargetLocal() == true); + BLooper *resultLooper; + CHK(from.Target(&resultLooper) == handler); + CHK(resultLooper == looper); + CHK(from.Team() == get_this_team()); + CHK(result == B_OK); + // create the messenger and do the checks + BMessenger messenger(from); + CHK(messenger.IsValid() == true); + CHK(messenger.IsTargetLocal() == true); + resultLooper = NULL; + CHK(messenger.Target(&resultLooper) == handler); + CHK(resultLooper == looper); + CHK(messenger.Team() == get_this_team()); +} + + + +Test* TBMessengerTester::Suite() +{ + TestSuite* SuiteOfTests = new TestSuite; + + ADD_TEST(SuiteOfTests, TBMessengerTester, BMessenger1); + ADD_TEST(SuiteOfTests, TBMessengerTester, BMessenger2); + ADD_TEST(SuiteOfTests, TBMessengerTester, BMessenger3); + ADD_TEST(SuiteOfTests, TBMessengerTester, BMessenger4); + ADD_TEST(SuiteOfTests, TBMessengerTester, BMessenger5); + ADD_TEST(SuiteOfTests, TBMessengerTester, BMessenger6); + ADD_TEST(SuiteOfTests, TBMessengerTester, BMessenger7); + ADD_TEST(SuiteOfTests, TBMessengerTester, BMessenger8); + ADD_TEST(SuiteOfTests, TBMessengerTester, BMessenger9); + ADD_TEST(SuiteOfTests, TBMessengerTester, BMessenger10); + + return SuiteOfTests; +} + + diff --git a/src/tests/kits/app/bmessenger/BMessengerTester.h b/src/tests/kits/app/bmessenger/BMessengerTester.h new file mode 100644 index 0000000000..18376d372b --- /dev/null +++ b/src/tests/kits/app/bmessenger/BMessengerTester.h @@ -0,0 +1,43 @@ +//------------------------------------------------------------------------------ +// BMessengerTester.h +// +//------------------------------------------------------------------------------ + +#ifndef B_MESSENGER_TESTER_H +#define B_MESSENGER_TESTER_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "../common.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +class TBMessengerTester : public TestCase +{ + public: + TBMessengerTester() {;} + TBMessengerTester(std::string name) : TestCase(name) {;} + + void BMessenger1(); + void BMessenger2(); + void BMessenger3(); + void BMessenger4(); + void BMessenger5(); + void BMessenger6(); + void BMessenger7(); + void BMessenger8(); + void BMessenger9(); + void BMessenger10(); + + static Test* Suite(); +}; + +#endif // B_MESSENGER_TESTER_H + diff --git a/src/tests/kits/app/bmessenger/Helpers.h b/src/tests/kits/app/bmessenger/Helpers.h new file mode 100644 index 0000000000..65ca1271ee --- /dev/null +++ b/src/tests/kits/app/bmessenger/Helpers.h @@ -0,0 +1,79 @@ +//------------------------------------------------------------------------------ +// Helpers.h +// +//------------------------------------------------------------------------------ + +#ifndef HELPERS_H +#define HELPERS_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + + +// helper class: quits a BLooper on destruction +class LooperQuitter { +public: + inline LooperQuitter(BLooper *looper) : fLooper(looper) {} + inline ~LooperQuitter() { fLooper->Lock(); fLooper->Quit(); } + +private: + BLooper *fLooper; +}; + +// helper class: deletes an object on destruction +template +class AutoDeleter { +public: + inline AutoDeleter(T *object, bool array = false) + : fObject(object), fArray(array) {} + inline ~AutoDeleter() + { + if (fArray) + delete[] fObject; + else + delete fObject; + } + +protected: + T *fObject; + bool fArray; +}; + +// helper class: deletes an BHandler on destruction +class HandlerDeleter : AutoDeleter { +public: + inline HandlerDeleter(BHandler *handler) + : AutoDeleter(handler) {} + inline ~HandlerDeleter() + { + if (fObject) { + if (BLooper *looper = fObject->Looper()) { + looper->Lock(); + looper->RemoveHandler(fObject); + looper->Unlock(); + } + } + } +}; + +// helper function: return the this team's ID +static inline +team_id +get_this_team() +{ + thread_info info; + get_thread_info(find_thread(NULL), &info); + return info.team; +} + +#endif // HELPERS_H diff --git a/src/tests/kits/app/bmessenger/Jamfile b/src/tests/kits/app/bmessenger/Jamfile new file mode 100644 index 0000000000..48582d7cb2 --- /dev/null +++ b/src/tests/kits/app/bmessenger/Jamfile @@ -0,0 +1,11 @@ +SubDir OBOS_TOP sources tests kits app BMessenger ; + +CommonUnitTest BMessengerTester + : main.cpp + BMessengerTester.cpp + TargetTester.cpp + : kits app + : libopenbeos.so be stdc++.r4 + : be stdc++.r4 + : app support +; diff --git a/src/tests/kits/app/bmessenger/TargetTester.cpp b/src/tests/kits/app/bmessenger/TargetTester.cpp new file mode 100644 index 0000000000..03e4b9402c --- /dev/null +++ b/src/tests/kits/app/bmessenger/TargetTester.cpp @@ -0,0 +1,46 @@ +//------------------------------------------------------------------------------ +// TargetTester.cpp +// +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- +#include + +// System Includes ------------------------------------------------------------- +#include +#include + +#include +#include +#include + +#define CHK CPPUNIT_ASSERT + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "Helpers.h" +#include "TargetTester.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +//------------------------------------------------------------------------------ + +/* + */ +void TargetTester::Test1() +{ +} + + +Test* TargetTester::Suite() +{ + TestSuite* SuiteOfTests = new TestSuite; + + ADD_TEST(SuiteOfTests, TargetTester, Test1); + + return SuiteOfTests; +} + diff --git a/src/tests/kits/app/bmessenger/TargetTester.h b/src/tests/kits/app/bmessenger/TargetTester.h new file mode 100644 index 0000000000..fb2573ebb8 --- /dev/null +++ b/src/tests/kits/app/bmessenger/TargetTester.h @@ -0,0 +1,34 @@ +//------------------------------------------------------------------------------ +// TargetTester.h +// +//------------------------------------------------------------------------------ + +#ifndef TARGET_TESTER_H +#define TARGET_TESTER_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "../common.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +class TargetTester : public TestCase +{ + public: + TargetTester() {;} + TargetTester(std::string name) : TestCase(name) {;} + + void Test1(); + + static Test* Suite(); +}; + +#endif // TARGET_TESTER_H + diff --git a/src/tests/kits/app/bmessenger/main.cpp b/src/tests/kits/app/bmessenger/main.cpp new file mode 100644 index 0000000000..c2f8556566 --- /dev/null +++ b/src/tests/kits/app/bmessenger/main.cpp @@ -0,0 +1,52 @@ +//------------------------------------------------------------------------------ +// main.cpp +// +// Entry points for testing BMessenger +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "../common.h" +#include "BMessengerTester.h" +#include "TargetTester.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + + +/* + * Function: addonTestFunc() + * Descr: This function is called by the test application to + * get a pointer to the test to run. The BMessageQueue test + * is a test suite. A series of tests are added to + * the suite. + */ + +Test* addonTestFunc(void) +{ + TestSuite* tests = new TestSuite("BHandler"); + + tests->addTest(TBMessengerTester::Suite()); + tests->addTest(TargetTester::Suite()); + + return tests; +} + +int main() +{ + Test* tests = addonTestFunc(); + + TextTestResult Result; + tests->run(&Result); + cout << Result << endl; + + delete tests; + + return !Result.wasSuccessful(); +} diff --git a/src/tests/kits/app/common.h b/src/tests/kits/app/common.h new file mode 100644 index 0000000000..80598e0138 --- /dev/null +++ b/src/tests/kits/app/common.h @@ -0,0 +1,54 @@ +//------------------------------------------------------------------------------ +// common.h +// +//------------------------------------------------------------------------------ + +#ifndef COMMON_H +#define COMMON_H + +// Standard Includes ----------------------------------------------------------- +#include +#include + +// System Includes ------------------------------------------------------------- + +// Project Includes ------------------------------------------------------------ +#include "cppunit/TestCaller.h" +#include "cppunit/TestCase.h" +#include "cppunit/TestResult.h" +#include "cppunit/TestSuite.h" +#include "cppunit/TextTestResult.h" + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- +#define assert_err(condition) \ + (this->assertImplementation ((condition), std::string((#condition)) + \ + strerror(condition),\ + __LINE__, __FILE__)) + +#define ADD_TEST(suitename, classname, funcname) \ + (suitename)->addTest(new TestCaller((#funcname), \ + &classname::funcname)); + +#define CHECK_ERRNO \ + cout << endl << "errno == \"" << strerror(errno) << "\" (" << errno \ + << ") in " << __PRETTY_FUNCTION__ << endl + +#define CHECK_STATUS(status__) \ + cout << endl << "status_t == \"" << strerror((status__)) << "\" (" \ + << (status__) << ") in " << __PRETTY_FUNCTION__ << endl + +// Globals --------------------------------------------------------------------- + +using namespace CppUnit; + +#endif //COMMON_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/interface/bprintjob/PrintTestApp.cpp b/src/tests/kits/interface/bprintjob/PrintTestApp.cpp new file mode 100644 index 0000000000..f46ed8b3f3 --- /dev/null +++ b/src/tests/kits/interface/bprintjob/PrintTestApp.cpp @@ -0,0 +1,155 @@ +#include "PrintTestApp.hpp" +#include "PrintTestWindow.hpp" + +#include + +#define your_document_last_page 100 + +int main() +{ + new PrintTestApp; + be_app->Run(); + delete be_app; + + return 0; +} + +PrintTestApp::PrintTestApp() + : Inherited(PRINTTEST_SIGNATURE) +{ +} + +void PrintTestApp::MessageReceived(BMessage* msg) +{ + switch(msg->what) { + case 'PStp': + DoTestPageSetup(); + break; + + case 'Prnt': + Print(); + break; + } +} + +void PrintTestApp::ReadyToRun() +{ + (new PrintTestWindow)->Show(); +} + + +status_t PrintTestApp::DoTestPageSetup() +{ + BPrintJob job("document's name"); + status_t result = job.ConfigPage(); + if (result == B_OK) { + // Get the user Settings + fSetupData = job.Settings(); + + // Use the new settings for your internal use + fPaperRect = job.PaperRect(); + fPrintableRect = job.PrintableRect(); + } + + return result; +} + +status_t PrintTestApp::Print() +{ + status_t result = B_OK; + + // If we have no setup message, we should call ConfigPage() + // You must use the same instance of the BPrintJob object + // (you can't call the previous "PageSetup()" function, since it + // creates its own BPrintJob object). + + if (!fSetupData) { + result = DoTestPageSetup(); + } + + BPrintJob job("document's name"); + if (result == B_OK) { + // Setup the driver with user settings + job.SetSettings(fSetupData); + + result = job.ConfigJob(); + if (result == B_OK) { + // WARNING: here, setup CANNOT be NULL. + if (fSetupData == NULL) { + // something's wrong, handle the error and bail out + } + delete fSetupData; + + // Get the user Settings + fSetupData = job.Settings(); + + // Use the new settings for your internal use + // They may have changed since the last time you read it + fPaperRect = job.PaperRect(); + fPrintableRect = job.PrintableRect(); + + // Now you have to calculate the number of pages + // (note: page are zero-based) + int32 firstPage = job.FirstPage(); + int32 lastPage = job.LastPage(); + + // Verify the range is correct + // 0 ... LONG_MAX -> Print all the document + // n ... LONG_MAX -> Print from page n to the end + // n ... m -> Print from page n to page m + + if (lastPage > your_document_last_page) + lastPage = your_document_last_page; + + int32 nbPages = lastPage - firstPage + 1; + + // Verify the range is correct + if (nbPages <= 0) + return B_ERROR; + + // Now you can print the page + job.BeginJob(); + + // Print all pages + bool can_continue = job.CanContinue(); + + for (int i=firstPage ; can_continue && i<=lastPage ; i++) { + // Draw all the needed views +//IRA job.DrawView(someView, viewRect, pointOnPage); +//IRA job.DrawView(anotherView, anotherRect, differentPoint); + +/* + // If the document have a lot of pages, you can update a BStatusBar, here + // or else what you want... + update_status_bar(i-firstPage, nbPages); +*/ + + // Spool the page + job.SpoolPage(); + +/* + // Cancel the job if needed. + // You can for exemple verify if the user pressed the ESC key + // or (SHIFT + '.')... + if (user_has_canceled) + { + // tell the print_server to cancel the printjob + job.CancelJob(); + can_continue = false; + break; + } +*/ + // Verify that there was no error (disk full for example) + can_continue = job.CanContinue(); + } + + // Now, you just have to commit the job! + if (can_continue) + job.CommitJob(); + else + result = B_ERROR; + } + } + + return result; +} \ No newline at end of file diff --git a/src/tests/kits/interface/bprintjob/PrintTestApp.hpp b/src/tests/kits/interface/bprintjob/PrintTestApp.hpp new file mode 100644 index 0000000000..857eae1cb7 --- /dev/null +++ b/src/tests/kits/interface/bprintjob/PrintTestApp.hpp @@ -0,0 +1,30 @@ +#ifndef PRINTTESTAPP_HPP +#define PRINTTESTAPP_HPP + +class PrintTestApp; + +#include +#include +#include + +#define PRINTTEST_SIGNATURE "application/x-vnd.OpenBeOS-printtest" + +class PrintTestApp : public BApplication +{ + typedef BApplication Inherited; +public: + PrintTestApp(); + + void MessageReceived(BMessage* msg); + void ReadyToRun(); +private: + status_t DoTestPageSetup(); + status_t Print(); + + BMessage* fSetupData; + BRect fPrintableRect; + BRect fPaperRect; + +}; + +#endif diff --git a/src/tests/kits/interface/bprintjob/PrintTestView.cpp b/src/tests/kits/interface/bprintjob/PrintTestView.cpp new file mode 100644 index 0000000000..c5ca1c80f1 --- /dev/null +++ b/src/tests/kits/interface/bprintjob/PrintTestView.cpp @@ -0,0 +1,18 @@ +#include "PrintTestView.hpp" + +PrintTestView::PrintTestView(BRect frame) + : Inherited(frame, "", B_FOLLOW_ALL, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE) +{ +} + +void PrintTestView::Draw(BRect updateRect) +{ + StrokeRoundRect(Bounds().InsetByCopy(20,20), 10, 10); + BFont font(be_bold_font); + font.SetSize(Bounds().Height()/10); + font.SetShear(Bounds().Height()/10); + font.SetRotation(Bounds().Width()/10); + SetFont(&font, B_FONT_ALL); + DrawString("OpenBeOS", 8, BPoint(Bounds().Width()/2,Bounds().Height()/2)); +} + diff --git a/src/tests/kits/interface/bprintjob/PrintTestView.hpp b/src/tests/kits/interface/bprintjob/PrintTestView.hpp new file mode 100644 index 0000000000..a44545597e --- /dev/null +++ b/src/tests/kits/interface/bprintjob/PrintTestView.hpp @@ -0,0 +1,16 @@ +#ifndef PRINTTESTVIEW_HPP +#define PRINTTESTVIEW_HPP + +class PrintTestView; + +#include + +class PrintTestView : public BView +{ + typedef BView Inherited; +public: + PrintTestView(BRect frame); + void Draw(BRect updateRect); +}; + +#endif diff --git a/src/tests/kits/interface/bprintjob/PrintTestWindow.cpp b/src/tests/kits/interface/bprintjob/PrintTestWindow.cpp new file mode 100644 index 0000000000..d8bd0f50e4 --- /dev/null +++ b/src/tests/kits/interface/bprintjob/PrintTestWindow.cpp @@ -0,0 +1,59 @@ +#include "PrintTestWindow.hpp" + +#include "PrintTestView.hpp" + +#include +#include +#include +#include + +PrintTestWindow::PrintTestWindow() + : Inherited(BRect(100,100,500,300), "OpenBeOS Printing", B_DOCUMENT_WINDOW, 0) +{ + BuildGUI(); +} + +bool PrintTestWindow::QuitRequested() +{ + bool isOk = Inherited::QuitRequested(); + if (isOk) { + be_app->PostMessage(B_QUIT_REQUESTED); + } + + return isOk; +} + + +void PrintTestWindow::BuildGUI() +{ + BView* backdrop = new BView(Bounds(), "backdrop", B_FOLLOW_ALL, B_WILL_DRAW); + backdrop->SetViewColor(::ui_color(B_PANEL_BACKGROUND_COLOR)); + AddChild(backdrop); + + BMenuBar* mb = new BMenuBar(Bounds(), "menubar"); + BMenu* m = new BMenu("File"); + m->AddItem(new BMenuItem("Page Setup"B_UTF8_ELLIPSIS, new BMessage('PStp'), 'P', B_SHIFT_KEY)); + m->AddItem(new BMenuItem("Print"B_UTF8_ELLIPSIS, new BMessage('Prnt'), 'P')); + m->AddSeparatorItem(); + m->AddItem(new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED), 'Q')); + m->SetTargetForItems(be_app_messenger); + mb->AddItem(m); + + m = new BMenu("Edit"); + m->AddItem(new BMenuItem("Undo", new BMessage(B_UNDO), 'Z')); + m->AddSeparatorItem(); + m->AddItem(new BMenuItem("Cut", new BMessage(B_CUT), 'X')); + m->AddItem(new BMenuItem("Copy", new BMessage(B_COPY), 'C')); + m->AddItem(new BMenuItem("Paste", new BMessage(B_PASTE), 'V')); + m->AddItem(new BMenuItem("Clear", new BMessage(B_DELETE))); + m->AddSeparatorItem(); + m->AddItem(new BMenuItem("Select All", new BMessage(B_SELECT_ALL))); + mb->AddItem(m); + + backdrop->AddChild(mb); + + BRect b = Bounds(); + b.top = mb->Bounds().bottom +1; + backdrop->AddChild(new PrintTestView(b)); +} + diff --git a/src/tests/kits/interface/bprintjob/PrintTestWindow.hpp b/src/tests/kits/interface/bprintjob/PrintTestWindow.hpp new file mode 100644 index 0000000000..18d5896d6e --- /dev/null +++ b/src/tests/kits/interface/bprintjob/PrintTestWindow.hpp @@ -0,0 +1,18 @@ +#ifndef PRINTTESTWINDOW_HPP +#define PRINTTESTWINDOW_HPP + +class PrintTestWindow; + +#include + +class PrintTestWindow : public BWindow +{ + typedef BWindow Inherited; +public: + PrintTestWindow(); + bool QuitRequested(); +private: + void BuildGUI(); +}; + +#endif diff --git a/src/tests/kits/media/AreaTest.cpp b/src/tests/kits/media/AreaTest.cpp new file mode 100644 index 0000000000..2baa64c543 --- /dev/null +++ b/src/tests/kits/media/AreaTest.cpp @@ -0,0 +1,49 @@ +#include +#include + +int main() +{ + int * ptr = new int[1]; + char *adr; + area_id id; + int offset; + + + area_info info; + id = area_for(ptr); + get_area_info(id, &info); + adr = (char *)info.address; + offset = (uint32)ptr - (uint32)adr; + + + char * adrclone1; + char * adrclone2; + int * ptrclone1; + int * ptrclone2; + area_id idclone1; + area_id idclone2; + + idclone1 = clone_area("clone 1", (void **)&adrclone1, B_ANY_ADDRESS,B_READ_AREA | B_WRITE_AREA,id); + idclone2 = clone_area("clone 2", (void **)&adrclone2, B_ANY_ADDRESS,B_READ_AREA | B_WRITE_AREA,id); + + ptrclone1 = (int *)(adrclone1 + offset); + ptrclone2 = (int *)(adrclone2 + offset); + + printf("offset = 0x%08x\n",(int)offset); + printf("id = 0x%08x\n",(int)id); + printf("id clone 1 = 0x%08x\n",(int)idclone1); + printf("id clone 2 = 0x%08x\n",(int)idclone2); + printf("adr = 0x%08x\n",(int)adr); + printf("adr clone 1 = 0x%08x\n",(int)adrclone1); + printf("adr clone 2 = 0x%08x\n",(int)adrclone2); + printf("ptr = 0x%08x\n",(int)ptr); + printf("ptr clone 1 = 0x%08x\n",(int)ptrclone1); + printf("ptr clone 2 = 0x%08x\n",(int)ptrclone2); + + ptr[0] = 0x12345678; + + printf("ptr[0] = 0x%08x\n",(int)ptr[0]); + printf("ptr clone 1[0] = 0x%08x\n",(int)ptrclone1[0]); + printf("ptr clone 2[0] = 0x%08x\n",(int)ptrclone2[0]); + +} diff --git a/src/tests/kits/media/BufferTest.cpp b/src/tests/kits/media/BufferTest.cpp new file mode 100644 index 0000000000..22e8f7ff51 --- /dev/null +++ b/src/tests/kits/media/BufferTest.cpp @@ -0,0 +1,101 @@ +#include +#include +#include +#include + +int main() +{ + // app_server connection (no need to run it) + BApplication app("application/x-vnd-test"); + + BBufferGroup * group; + status_t s; + int32 count; + BBuffer *buffer; + +/* + printf("using default constructor:\n"); + group = new BBufferGroup(); + + + s = group->InitCheck(); + printf("InitCheck: status = %ld\n",s); + + s = group->CountBuffers(&count); + printf("CountBuffers: count = %ld, status = %ld\n",count,s); + + delete group; +*/ + printf("\n"); + printf("using size = 1234 constructor:\n"); + group = new BBufferGroup(1234); + + s = group->InitCheck(); + printf("InitCheck: status = %ld\n",s); + + s = group->CountBuffers(&count); + printf("CountBuffers: count = %ld, status = %ld\n",count,s); + + s = group->GetBufferList(1,&buffer); + printf("GetBufferList: status = %ld\n",s); + + printf("Buffer->Data: = %08x\n",(int)buffer->Data()); + + printf("Buffer->ID: = %d\n",(int)buffer->ID()); + + printf("Buffer->Size: = %ld\n",buffer->Size()); + + printf("Buffer->SizeAvailable: = %ld\n",buffer->SizeAvailable()); + + printf("Buffer->SizeUsed: = %ld\n",buffer->SizeUsed()); + + printf("\n"); + + media_buffer_id id = buffer->ID(); + BBufferGroup * group2 = new BBufferGroup(1,&id); + printf("creating second group with a buffer from first group:\n"); + + s = group2->InitCheck(); + printf("InitCheck: status = %ld\n",s); + + s = group2->CountBuffers(&count); + printf("CountBuffers: count = %ld, status = %ld\n",count,s); + + buffer = 0; + s = group2->GetBufferList(1,&buffer); + printf("GetBufferList: status = %ld\n",s); + + printf("Buffer->Data: = %08x\n",(int)buffer->Data()); + + printf("Buffer->ID: = %d\n",(int)buffer->ID()); + + printf("Buffer->Size: = %ld\n",buffer->Size()); + + printf("Buffer->SizeAvailable: = %ld\n",buffer->SizeAvailable()); + + printf("Buffer->SizeUsed: = %ld\n",buffer->SizeUsed()); + + delete group; + delete group2; + + printf("\n"); +/* + printf("creating a BSmallBuffer:\n"); + BSmallBuffer * sb = new BSmallBuffer; + + printf("sb->Data: = %08x\n",(int)sb->Data()); + + printf("sb->ID: = %d\n",(int)sb->ID()); + + printf("sb->Size: = %ld\n",sb->Size()); + + printf("sb->SizeAvailable: = %ld\n",sb->SizeAvailable()); + + printf("sb->SizeUsed: = %ld\n",sb->SizeUsed()); + + printf("sb->SmallBufferSizeLimit: = %ld\n",sb->SmallBufferSizeLimit()); + + delete sb; +*/ + return 0; +} diff --git a/src/tests/kits/media/SizeofTest.cpp b/src/tests/kits/media/SizeofTest.cpp new file mode 100644 index 0000000000..c6d4321e0e --- /dev/null +++ b/src/tests/kits/media/SizeofTest.cpp @@ -0,0 +1,40 @@ +//#include "../source/headers/BufferGroup.h" +#include +#include + +int main() +{ + printf("BBuffer sizeof = %ld\n",sizeof(BBuffer)); + printf("BBufferConsumer sizeof = %ld\n",sizeof(BBufferConsumer)); + printf("BBufferGroup sizeof = %ld\n",sizeof(BBufferGroup)); + printf("BBufferProducer sizeof = %ld\n",sizeof(BBufferProducer)); + printf("BContinuousParameter sizeof = %ld\n",sizeof(BContinuousParameter)); + printf("BControllable sizeof = %ld\n",sizeof(BControllable )); + printf("BDiscreteParameter sizeof = %ld\n",sizeof(BDiscreteParameter )); + printf("BFileInterface sizeof = %ld\n",sizeof(BFileInterface)); + printf("BMediaAddOn sizeof = %ld\n",sizeof(BMediaAddOn)); +// printf("BMediaBufferDecoder sizeof = %ld\n",sizeof(BMediaBufferDecoder)); +// printf("MediaBufferEncoder sizeof = %ld\n",sizeof(MediaBufferEncoder)); +// printf("BMediaDecoder sizeof = %ld\n",sizeof(BMediaDecoder)); +// printf("BMediaEncoder sizeof = %ld\n",sizeof(BMediaEncoder)); + printf("BMediaEventLooper sizeof = %ld\n",sizeof(BMediaEventLooper)); + printf("BMediaFile sizeof = %ld\n",sizeof(BMediaFile)); + printf("BMediaFiles sizeof = %ld\n",sizeof(BMediaFiles)); + printf("BMediaFiles sizeof = %ld\n",sizeof(BMediaFiles)); + printf("BMediaFormats sizeof = %ld\n",sizeof(BMediaFormats)); + printf("BMediaNode sizeof = %ld\n",sizeof(BMediaNode)); + printf("BMediaRoster sizeof = %ld\n",sizeof(BMediaRoster)); + printf("BMediaTheme sizeof = %ld\n",sizeof(BMediaTheme)); + printf("BMediaTrack sizeof = %ld\n",sizeof(BMediaTrack)); + printf("BNullParameter sizeof = %ld\n",sizeof(BNullParameter)); + printf("BParameter sizeof = %ld\n",sizeof(BParameter)); + printf("BParameterGroup sizeof = %ld\n",sizeof(BParameterGroup)); + printf("BSound sizeof = %ld\n",sizeof(BSound)); + printf("BTimeCode sizeof = %ld\n",sizeof(BTimeCode)); + printf("BParameterWeb sizeof = %ld\n",sizeof(BParameterWeb)); + printf("BSmallBuffer sizeof = %ld\n",sizeof(BSmallBuffer)); + printf("BSoundPlayer sizeof = %ld\n",sizeof(BSoundPlayer )); + printf("BTimedEventQueue sizeof = %ld\n",sizeof(BTimedEventQueue)); + printf("BTimeSource sizeof = %ld\n",sizeof(BTimeSource)); + return 0; +} \ No newline at end of file diff --git a/src/tests/kits/media/TimedEventQueueTest.cpp b/src/tests/kits/media/TimedEventQueueTest.cpp new file mode 100644 index 0000000000..86ec08f2e5 --- /dev/null +++ b/src/tests/kits/media/TimedEventQueueTest.cpp @@ -0,0 +1,369 @@ +#include +#include + +#define DEBUG 1 +#include + +void DumpEvent(const media_timed_event *e) +{ + if (!e) { + printf("NULL\n"); + return; + } + printf("time = 0x%x, type = ",int(e->event_time)); + switch (e->type) { + case BTimedEventQueue::B_NO_EVENT: printf("B_NO_EVENT\n"); break; + case BTimedEventQueue::B_ANY_EVENT: printf("B_ANY_EVENT\n"); break; + case BTimedEventQueue::B_START: printf("B_START\n"); break; + case BTimedEventQueue::B_STOP: printf("B_STOP\n"); break; + case BTimedEventQueue::B_SEEK: printf("B_SEEK\n"); break; + case BTimedEventQueue::B_WARP: printf("B_WARP\n"); break; + case BTimedEventQueue::B_TIMER: printf("B_TIMER\n"); break; + case BTimedEventQueue::B_HANDLE_BUFFER: printf("B_HANDLE_BUFFER\n"); break; + case BTimedEventQueue::B_DATA_STATUS: printf("B_DATA_STATUS\n"); break; + case BTimedEventQueue::B_HARDWARE: printf("B_HARDWARE\n"); break; + case BTimedEventQueue::B_PARAMETER: printf("B_PARAMETER\n"); break; + default: printf("0x%x\n",int(e->type)); + } +} + +void InsertRemoveTest() +{ + BTimedEventQueue *q =new BTimedEventQueue; + q->AddEvent(media_timed_event(0x1007,BTimedEventQueue::B_START));// + q->AddEvent(media_timed_event(0x1005,BTimedEventQueue::B_START));// + q->AddEvent(media_timed_event(0x9999,BTimedEventQueue::B_STOP));// + q->AddEvent(media_timed_event(0x1006,BTimedEventQueue::B_START));// + q->AddEvent(media_timed_event(0x1002,BTimedEventQueue::B_START));// + q->AddEvent(media_timed_event(0x1011,BTimedEventQueue::B_START));// + q->AddEvent(media_timed_event(0x1000,BTimedEventQueue::B_START));// + q->AddEvent(media_timed_event(0x0777,BTimedEventQueue::B_START));// + q->AddEvent(media_timed_event(0x1001,BTimedEventQueue::B_START));// + q->AddEvent(media_timed_event(0x1000,BTimedEventQueue::B_STOP));// + q->AddEvent(media_timed_event(0x1003,BTimedEventQueue::B_START));// + q->AddEvent(media_timed_event(0x1000,BTimedEventQueue::B_SEEK));// + ASSERT(q->EventCount() == 12); + ASSERT(q->HasEvents() == true); + + q->RemoveEvent(&media_timed_event(0x1003,BTimedEventQueue::B_START)); + ASSERT(q->EventCount() == 11); + ASSERT(q->HasEvents() == true); + + q->RemoveEvent(&media_timed_event(0x1007,BTimedEventQueue::B_START)); + ASSERT(q->EventCount() == 10); + ASSERT(q->HasEvents() == true); + + q->RemoveEvent(&media_timed_event(0x1000,BTimedEventQueue::B_STOP)); + ASSERT(q->EventCount() == 9); + ASSERT(q->HasEvents() == true); + + q->RemoveEvent(&media_timed_event(0x1000,BTimedEventQueue::B_SEEK)); + ASSERT(q->EventCount() == 8); + ASSERT(q->HasEvents() == true); + + //remove non existing element (time) + q->RemoveEvent(&media_timed_event(0x1111,BTimedEventQueue::B_STOP)); + ASSERT(q->EventCount() == 8); + ASSERT(q->HasEvents() == true); + + //remove non existing element (type) + q->RemoveEvent(&media_timed_event(0x1011,BTimedEventQueue::B_STOP)); + ASSERT(q->EventCount() == 8); + ASSERT(q->HasEvents() == true); + + q->RemoveEvent(&media_timed_event(0x1000,BTimedEventQueue::B_START)); + ASSERT(q->EventCount() == 7); + ASSERT(q->HasEvents() == true); + + q->RemoveEvent(&media_timed_event(0x1011,BTimedEventQueue::B_START)); + ASSERT(q->EventCount() == 6); + ASSERT(q->HasEvents() == true); + + q->RemoveEvent(&media_timed_event(0x1002,BTimedEventQueue::B_START)); + ASSERT(q->EventCount() == 5); + ASSERT(q->HasEvents() == true); + + q->RemoveEvent(&media_timed_event(0x0777,BTimedEventQueue::B_START)); + ASSERT(q->EventCount() == 4); + ASSERT(q->HasEvents() == true); + + q->RemoveEvent(&media_timed_event(0x9999,BTimedEventQueue::B_STOP)); + ASSERT(q->EventCount() == 3); + ASSERT(q->HasEvents() == true); + + q->RemoveEvent(&media_timed_event(0x1006,BTimedEventQueue::B_START)); + ASSERT(q->EventCount() == 2); + ASSERT(q->HasEvents() == true); + + q->RemoveEvent(&media_timed_event(0x1001,BTimedEventQueue::B_START)); + ASSERT(q->EventCount() == 1); + ASSERT(q->HasEvents() == true); + + q->RemoveEvent(&media_timed_event(0x1005,BTimedEventQueue::B_START)); + ASSERT(q->EventCount() == 0); + ASSERT(q->HasEvents() == false); + + delete q; +} + +media_timed_event DoForEachEvent; +int DoForEachCount; + +BTimedEventQueue::queue_action +DoForEachHook(media_timed_event *event, void *context) +{ + DoForEachEvent = *event; + DoForEachCount++; + printf("Callback, event_time = %x\n",int(event->event_time)); + return BTimedEventQueue::B_NO_ACTION; +} + +void DoForEachTest() +{ + BTimedEventQueue *q =new BTimedEventQueue; + ASSERT(q->EventCount() == 0); + ASSERT(q->HasEvents() == false); + + q->AddEvent(media_timed_event(0x1000,BTimedEventQueue::B_SEEK)); + q->AddEvent(media_timed_event(0x1001,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1002,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1003,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1010,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1011,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1012,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1004,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1005,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1006,BTimedEventQueue::B_STOP)); + q->AddEvent(media_timed_event(0x1007,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1008,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1009,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1013,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1013,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1013,BTimedEventQueue::B_SEEK)); + ASSERT(q->EventCount() == 16); + ASSERT(q->HasEvents() == true); + + + printf("\n expected: 0x1000\n"); + DoForEachCount = 0; + q->DoForEach(DoForEachHook,(void*)1234,0x1000,BTimedEventQueue::B_AT_TIME); + ASSERT(DoForEachEvent == media_timed_event(0x1000,BTimedEventQueue::B_SEEK)); + ASSERT(DoForEachCount == 1); + + + printf("\n expected: 0x1006\n"); + DoForEachCount = 0; + q->DoForEach(DoForEachHook,(void*)1234,0x1006,BTimedEventQueue::B_AT_TIME); + ASSERT(DoForEachEvent == media_timed_event(0x1006,BTimedEventQueue::B_STOP)); + ASSERT(DoForEachCount == 1); + + printf("\n expected: 0x1013, 0x1013, 0x1013\n"); + DoForEachCount = 0; + q->DoForEach(DoForEachHook,(void*)1234,0x1013,BTimedEventQueue::B_AT_TIME); + ASSERT(DoForEachCount == 3); + + printf("\n expected: 0x1000, 0x1001, 0x1002\n"); + DoForEachCount = 0; + q->DoForEach(DoForEachHook,(void*)1234,0x1003,BTimedEventQueue::B_BEFORE_TIME,false); + ASSERT(DoForEachCount == 3); + + printf("\n expected: 0x1000, 0x1001, 0x1002, 0x1003\n"); + DoForEachCount = 0; + q->DoForEach(DoForEachHook,(void*)1234,0x1003,BTimedEventQueue::B_BEFORE_TIME,true); + ASSERT(DoForEachCount == 4); + + printf("\n expected: 0x1013, 0x1013, 0x1013\n"); + DoForEachCount = 0; + q->DoForEach(DoForEachHook,(void*)1234,0x1012,BTimedEventQueue::B_AFTER_TIME,false); + ASSERT(DoForEachCount == 3); + + printf("\n expected: 0x1012, 0x1013, 0x1013, 0x1013\n"); + DoForEachCount = 0; + q->DoForEach(DoForEachHook,(void*)1234,0x1012,BTimedEventQueue::B_AFTER_TIME,true); + ASSERT(DoForEachCount == 4); + + printf("\n expected: none\n"); + DoForEachCount = 0; + q->DoForEach(DoForEachHook,(void*)1234,0x1013,BTimedEventQueue::B_AFTER_TIME,false); + ASSERT(DoForEachCount == 0); + + printf("\n expected: 0x1013, 0x1013, 0x1013\n"); + DoForEachCount = 0; + q->DoForEach(DoForEachHook,(void*)1234,0x1013,BTimedEventQueue::B_AFTER_TIME,true); + ASSERT(DoForEachCount == 3); + + printf("\n expected: all 16\n"); + DoForEachCount = 0; + q->DoForEach(DoForEachHook,(void*)1234,0x0,BTimedEventQueue::B_ALWAYS); + ASSERT(DoForEachCount == 16); + + printf("\n expected: none\n"); + DoForEachCount = 0; + q->DoForEach(DoForEachHook,(void*)1234,0x0,BTimedEventQueue::B_ALWAYS,false,BTimedEventQueue::B_WARP); + ASSERT(DoForEachCount == 0); + + printf("\n expected: 0x1000, 0x1013\n"); + DoForEachCount = 0; + q->DoForEach(DoForEachHook,(void*)1234,0x0,BTimedEventQueue::B_ALWAYS,false,BTimedEventQueue::B_SEEK); + ASSERT(DoForEachCount == 2); + + printf("\n expected: 0x1000, 0x1013\n"); + DoForEachCount = 0; + q->DoForEach(DoForEachHook,(void*)1234,0x0999,BTimedEventQueue::B_AFTER_TIME,false,BTimedEventQueue::B_SEEK); + ASSERT(DoForEachCount == 2); + + printf("\n expected: 0x1000, 0x1013\n"); + DoForEachCount = 0; + q->DoForEach(DoForEachHook,(void*)1234,0x1014,BTimedEventQueue::B_BEFORE_TIME,false,BTimedEventQueue::B_SEEK); + ASSERT(DoForEachCount == 2); + + printf("\n expected: none\n"); + DoForEachCount = 0; + q->DoForEach(DoForEachHook,(void*)1234,0x0004,BTimedEventQueue::B_BEFORE_TIME,true); + ASSERT(DoForEachCount == 0); + + delete q; +} + +void MatchTest() +{ + BTimedEventQueue *q = new BTimedEventQueue; + ASSERT(q->EventCount() == 0); + ASSERT(q->HasEvents() == false); + + q->AddEvent(media_timed_event(0x1000,BTimedEventQueue::B_SEEK)); + q->AddEvent(media_timed_event(0x1001,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1002,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1003,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1010,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1011,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1012,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1004,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1005,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1006,BTimedEventQueue::B_STOP)); + q->AddEvent(media_timed_event(0x1007,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1008,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1009,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1013,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1013,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1013,BTimedEventQueue::B_SEEK)); + ASSERT(q->EventCount() == 16); + ASSERT(q->HasEvents() == true); + + printf("\nexpected: "); DumpEvent(&media_timed_event(0x1006,BTimedEventQueue::B_STOP)); + printf("found: "); DumpEvent(q->FindFirstMatch(0x1001,BTimedEventQueue::B_AFTER_TIME,true,BTimedEventQueue::B_STOP)); + + printf("\nexpected: "); DumpEvent(&media_timed_event(0x1006,BTimedEventQueue::B_STOP)); + printf("found: "); DumpEvent(q->FindFirstMatch(0x1006,BTimedEventQueue::B_AT_TIME,true)); + + printf("\nexpected: "); DumpEvent(&media_timed_event(0x1006,BTimedEventQueue::B_STOP)); + printf("found: "); DumpEvent(q->FindFirstMatch(0x1007,BTimedEventQueue::B_BEFORE_TIME,true,BTimedEventQueue::B_STOP)); + + printf("\nexpected: "); DumpEvent(&media_timed_event(0x1000,BTimedEventQueue::B_SEEK)); + printf("found: "); DumpEvent(q->FindFirstMatch(0x1006,BTimedEventQueue::B_BEFORE_TIME,true)); + + printf("\nexpected: "); DumpEvent(&media_timed_event(0x1006,BTimedEventQueue::B_STOP)); + printf("found: "); DumpEvent(q->FindFirstMatch(0x1006,BTimedEventQueue::B_AFTER_TIME,true)); + + printf("\nexpected: "); DumpEvent(0); + printf("found: "); DumpEvent(q->FindFirstMatch(0x1006,BTimedEventQueue::B_BEFORE_TIME,false,BTimedEventQueue::B_STOP)); + + printf("\nexpected: "); DumpEvent(0); + printf("found: "); DumpEvent(q->FindFirstMatch(0x1006,BTimedEventQueue::B_AFTER_TIME,false,BTimedEventQueue::B_STOP)); + + printf("\nexpected: "); DumpEvent(0); + printf("found: "); DumpEvent(q->FindFirstMatch(0x1006,BTimedEventQueue::B_AT_TIME,false,BTimedEventQueue::B_SEEK)); + + printf("\nexpected: "); DumpEvent(&media_timed_event(0x1000,BTimedEventQueue::B_SEEK)); + printf("found: "); DumpEvent(q->FindFirstMatch(0x1000,BTimedEventQueue::B_AFTER_TIME,true)); + + printf("\nexpected: "); DumpEvent(&media_timed_event(0x1000,BTimedEventQueue::B_SEEK)); + printf("found: "); DumpEvent(q->FindFirstMatch(0x1010,BTimedEventQueue::B_BEFORE_TIME,true)); + + printf("\nexpected: "); DumpEvent(&media_timed_event(0x1000,BTimedEventQueue::B_SEEK)); + printf("found: "); DumpEvent(q->FindFirstMatch(0x1007,BTimedEventQueue::B_BEFORE_TIME,false)); + + printf("\nexpected: "); DumpEvent(&media_timed_event(0x1013,BTimedEventQueue::B_SEEK)); + printf("found: "); DumpEvent(q->FindFirstMatch(0x1001,BTimedEventQueue::B_AFTER_TIME,false,BTimedEventQueue::B_SEEK)); + + printf("\nexpected: "); DumpEvent(&media_timed_event(0x1010,BTimedEventQueue::B_START)); + printf("found: "); DumpEvent(q->FindFirstMatch(0x1009,BTimedEventQueue::B_AFTER_TIME,false)); + + printf("\nexpected: "); DumpEvent(&media_timed_event(0x1010,BTimedEventQueue::B_START)); + printf("found: "); DumpEvent(q->FindFirstMatch(0x1010,BTimedEventQueue::B_AFTER_TIME,true)); + + printf("\nexpected: "); DumpEvent(&media_timed_event(0x1010,BTimedEventQueue::B_START)); + printf("found: "); DumpEvent(q->FindFirstMatch(0x1010,BTimedEventQueue::B_AT_TIME,true)); + + delete q; +} + +void FlushTest() +{ + BTimedEventQueue *q = new BTimedEventQueue; + ASSERT(q->EventCount() == 0); + ASSERT(q->HasEvents() == false); + + q->AddEvent(media_timed_event(0x1000,BTimedEventQueue::B_SEEK)); + q->AddEvent(media_timed_event(0x1001,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1002,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1003,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1004,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1005,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1006,BTimedEventQueue::B_STOP)); + q->AddEvent(media_timed_event(0x1007,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1008,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1009,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1010,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1011,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1012,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1013,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1013,BTimedEventQueue::B_START)); + q->AddEvent(media_timed_event(0x1013,BTimedEventQueue::B_SEEK)); + ASSERT(q->EventCount() == 16); + ASSERT(q->HasEvents() == true); + + printf("### removing 0x1007\n"); + q->FlushEvents(0x1007, BTimedEventQueue::B_AT_TIME); + ASSERT(q->EventCount() == 15); + + printf("### removing 0x1013\n"); + q->FlushEvents(0x1012, BTimedEventQueue::B_AFTER_TIME,false); + ASSERT(q->EventCount() == 12); + + printf("### removing none\n"); + q->FlushEvents(0x1fff, BTimedEventQueue::B_AFTER_TIME,false); + ASSERT(q->EventCount() == 12); + + printf("### removing none\n"); + q->FlushEvents(0x1fff, BTimedEventQueue::B_AFTER_TIME,true); + ASSERT(q->EventCount() == 12); + + printf("### removing 0x1010, 0x1011, 0x1012\n"); + q->FlushEvents(0x1010, BTimedEventQueue::B_AFTER_TIME,true); + ASSERT(q->EventCount() == 9); + + printf("### removing 0x1000 to 0x1005\n"); + q->FlushEvents(0x1006, BTimedEventQueue::B_BEFORE_TIME,false); + ASSERT(q->EventCount() == 3); + + printf("### removing 0x1006\n"); + q->FlushEvents(0x1006, BTimedEventQueue::B_AT_TIME); + ASSERT(q->EventCount() == 2); + + printf("### removing 0x1008 0x1009\n"); + q->FlushEvents(0xffffff, BTimedEventQueue::B_BEFORE_TIME); + ASSERT(q->EventCount() == 0); + + delete q; +} + + +int main() +{ + InsertRemoveTest(); + DoForEachTest(); + MatchTest(); + FlushTest(); + return 0; +} diff --git a/src/tests/kits/media/nodetest/ConsumerNode.cpp b/src/tests/kits/media/nodetest/ConsumerNode.cpp new file mode 100644 index 0000000000..366ed138a9 --- /dev/null +++ b/src/tests/kits/media/nodetest/ConsumerNode.cpp @@ -0,0 +1,301 @@ +#include +#include +#include +#include "ConsumerNode.h" +#include "misc.h" + +ConsumerNode::ConsumerNode() : + BBufferConsumer(B_MEDIA_RAW_AUDIO), + BMediaEventLooper(), + BMediaNode("ConsumerNode") +{ + out("ConsumerNode::ConsumerNode\n"); +} + +ConsumerNode::~ConsumerNode() +{ + out("ConsumerNode::~ConsumerNode\n"); + Quit(); +} + +void +ConsumerNode::NodeRegistered() +{ + out("ConsumerNode::NodeRegistered\n"); + InitializeInput(); + SetPriority(108); + Run(); +} + +status_t +ConsumerNode::AcceptFormat( + const media_destination & dest, + media_format * format) +{ + out("ConsumerNode::AcceptFormat\n"); + + if (dest != mInput.destination) + return B_MEDIA_BAD_DESTINATION; + + if (format == NULL) + return B_BAD_VALUE; + + if (format->type != B_MEDIA_RAW_AUDIO) + return B_MEDIA_BAD_FORMAT; + + return B_OK; +} + +status_t +ConsumerNode::GetNextInput( + int32 * cookie, + media_input * out_input) +{ + out("ConsumerNode::GetNextInput\n"); + + if (out_input == NULL) + return B_BAD_VALUE; + + if (++(*cookie) > 1) + return B_BAD_INDEX; + + *out_input = mInput; + return B_OK; +} + +void +ConsumerNode::DisposeInputCookie( + int32 cookie) +{ + out("ConsumerNode::DisposeInputCookie\n"); + return; +} + +void +ConsumerNode::BufferReceived( + BBuffer * buffer) +{ + out("ConsumerNode::BufferReceived, sheduled time = %5.4f\n",buffer->Header()->start_time / 1E6); + media_timed_event event(buffer->Header()->start_time,BTimedEventQueue::B_HANDLE_BUFFER, + buffer, BTimedEventQueue::B_RECYCLE_BUFFER); + EventQueue()->AddEvent(event); + return; +} + +void +ConsumerNode::ProducerDataStatus( + const media_destination & for_whom, + int32 status, + bigtime_t at_performance_time) +{ + out("ConsumerNode::ProducerDataStatus\n"); + if (for_whom == mInput.destination) { + media_timed_event event(at_performance_time,BTimedEventQueue::B_DATA_STATUS, + &mInput, BTimedEventQueue::B_NO_CLEANUP, status, 0, NULL); + EventQueue()->AddEvent(event); + } +} + +status_t +ConsumerNode::GetLatencyFor( + const media_destination & for_whom, + bigtime_t * out_latency, + media_node_id * out_timesource) +{ + out("ConsumerNode::GetLatencyFor\n"); + // make sure this is one of my valid inputs + if (for_whom != mInput.destination) + return B_MEDIA_BAD_DESTINATION; + + *out_latency = 23000; + *out_timesource = TimeSource()->ID(); + return B_OK; +} + +status_t +ConsumerNode::Connected( + const media_source & producer, + const media_destination & where, + const media_format & with_format, + media_input * out_input) +{ + out("ConsumerNode::Connected\n"); + if (where != mInput.destination) + return B_MEDIA_BAD_DESTINATION; + + // calculate my latency here, because it may depend on buffer sizes/durations, then + // tell the BMediaEventLooper how early we need to get the buffers + SetEventLatency(10 * 1000); //fixme + + /* reserve the connection */ + mInput.source = producer; + mInput.format = with_format; + + /* and publish it's name and connection info */ + *out_input = mInput; + +#if 0 + /* create the buffer group */ + if (mBufferGroup == NULL) { + create_own_buffer_group(); + mBufferGroup = mOwnBufferGroup; + } + + /* set the duration of the node's buffers */ + int32 numBuffers; + mBufferGroup->CountBuffers(&numBuffers); + SetBufferDuration((1000000LL * numBuffers) / mOutput.format.u.raw_video.field_rate); +#endif + + return B_OK; +} + +void +ConsumerNode::Disconnected( + const media_source & producer, + const media_destination & where) +{ + out("ConsumerNode::Disconnected\n"); + + /* unreserve the connection */ + InitializeInput(); + +#if 0 + /* release buffer group */ + mBufferGroup = NULL; + if (mOwnBufferGroup != NULL) { + delete_own_buffer_group(); + } +#endif + + return; +} + +status_t +ConsumerNode::FormatChanged( + const media_source & producer, + const media_destination & consumer, + int32 change_tag, + const media_format & format) +{ + out("ConsumerNode::FormatChanged\n"); + return B_OK; +} + +status_t +ConsumerNode::SeekTagRequested( + const media_destination& destination, + bigtime_t in_target_time, + uint32 in_flags, + media_seek_tag* out_seek_tag, + bigtime_t* out_tagged_time, + uint32* out_flags) +{ + out("ConsumerNode::SeekTagRequested\n"); + return B_OK; +} + +BMediaAddOn* +ConsumerNode::AddOn(int32 * internal_id) const +{ + out("ConsumerNode::AddOn\n"); + return NULL; +} + +void +ConsumerNode::HandleEvent(const media_timed_event *event, + bigtime_t lateness, + bool realTimeEvent) +{ + switch (event->type) + { + case BTimedEventQueue::B_HANDLE_BUFFER: + { + out("ConsumerNode::HandleEvent B_HANDLE_BUFFER\n"); + BBuffer* buffer = const_cast((BBuffer*) event->pointer); + + out("### sheduled time = %5.4f, current time = %5.4f, lateness = %5.4f\n",buffer->Header()->start_time / 1E6,TimeSource()->Now() / 1E6,lateness / 1E6); + + snooze((rand()*100) % 200000); + + if (buffer) + buffer->Recycle(); + } + break; + + case BTimedEventQueue::B_PARAMETER: + { + out("ConsumerNode::HandleEvent B_PARAMETER\n"); + } + break; + + case BTimedEventQueue::B_START: + { + out("ConsumerNode::HandleEvent B_START\n"); + } + break; + + case BTimedEventQueue::B_STOP: + { + out("ConsumerNode::HandleEvent B_STOP\n"); + } + // stopping implies not handling any more buffers. So, we flush all pending + // buffers out of the event queue before returning to the event loop. + EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HANDLE_BUFFER); + break; + + case BTimedEventQueue::B_SEEK: + { + out("ConsumerNode::HandleEvent B_SEEK\n"); + } + break; + + case BTimedEventQueue::B_WARP: + { + out("ConsumerNode::HandleEvent B_WARP\n"); + } + // similarly, time warps aren't meaningful to the logger, so just record it and return + //mLogger->Log(LOG_WARP_HANDLED, logMsg); + break; + + case BTimedEventQueue::B_DATA_STATUS: + { + out("ConsumerNode::HandleEvent B_DATA_STATUS\n"); + } + break; + + default: + { + out("ConsumerNode::HandleEvent default\n"); + } + break; + } +} + +status_t +ConsumerNode::HandleMessage(int32 message,const void *data, size_t size) +{ + out("ConsumerNode::HandleMessage %lx\n",message); + if (B_OK == BBufferConsumer::HandleMessage(message,data,size)) + return B_OK; + if (B_OK == BMediaEventLooper::HandleMessage(message,data,size)) + return B_OK; + return BMediaNode::HandleMessage(message,data,size); +} + +void +ConsumerNode::InitializeInput() +{ + out("ConsumerNode::InitializeInput()\n"); + mInput.source = media_source::null; + mInput.destination.port = ControlPort(); + mInput.destination.id = 0; + mInput.node = Node(); + mInput.format.type = B_MEDIA_RAW_AUDIO; + mInput.format.u.raw_audio = media_raw_audio_format::wildcard; + mInput.format.u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT; + mInput.format.u.raw_audio.channel_count = 1; + mInput.format.u.raw_audio.frame_rate = 44100; + mInput.format.u.raw_audio.byte_order = (B_HOST_IS_BENDIAN) ? B_MEDIA_BIG_ENDIAN : B_MEDIA_LITTLE_ENDIAN; + strcpy(mInput.name, "this way in"); +} diff --git a/src/tests/kits/media/nodetest/ConsumerNode.h b/src/tests/kits/media/nodetest/ConsumerNode.h new file mode 100644 index 0000000000..51d7431202 --- /dev/null +++ b/src/tests/kits/media/nodetest/ConsumerNode.h @@ -0,0 +1,72 @@ + +#include +#include + +class ConsumerNode : public virtual BBufferConsumer, BMediaEventLooper +{ +public: + ConsumerNode(); + ~ConsumerNode(); + +protected: + /* functionality of BMediaNode */ +virtual void NodeRegistered(); + /* BBufferConsumer */ +virtual status_t AcceptFormat( + const media_destination & dest, + media_format * format); +virtual status_t GetNextInput( + int32 * cookie, + media_input * out_input); +virtual void DisposeInputCookie( + int32 cookie); +virtual void BufferReceived( + BBuffer * buffer); +virtual void ProducerDataStatus( + const media_destination & for_whom, + int32 status, + bigtime_t at_performance_time); +virtual status_t GetLatencyFor( + const media_destination & for_whom, + bigtime_t * out_latency, + media_node_id * out_timesource); +virtual status_t Connected( + const media_source & producer, + const media_destination & where, + const media_format & with_format, + media_input * out_input); +virtual void Disconnected( + const media_source & producer, + const media_destination & where); +virtual status_t FormatChanged( + const media_source & producer, + const media_destination & consumer, + int32 change_tag, + const media_format & format); + +virtual status_t HandleMessage(int32 message, + const void *data, size_t size); + +virtual status_t SeekTagRequested( + const media_destination& destination, + bigtime_t in_target_time, + uint32 in_flags, + media_seek_tag* out_seek_tag, + bigtime_t* out_tagged_time, + uint32* out_flags); + +/* from BMediaNode */ +virtual BMediaAddOn* AddOn( + int32 * internal_id) const; + +/* from BMediaEventLooper */ +virtual void HandleEvent(const media_timed_event *event, + bigtime_t lateness, + bool realTimeEvent = false); + +/* our own functionality */ +void InitializeInput(); + + media_input mInput; + media_format mPreferredFormat; +}; diff --git a/src/tests/kits/media/nodetest/ProducerNode.cpp b/src/tests/kits/media/nodetest/ProducerNode.cpp new file mode 100644 index 0000000000..cb0ad2a6ab --- /dev/null +++ b/src/tests/kits/media/nodetest/ProducerNode.cpp @@ -0,0 +1,461 @@ +#include +#include +#include +#include "ProducerNode.h" +#include "misc.h" + +ProducerNode::ProducerNode() : + BBufferProducer(B_MEDIA_RAW_AUDIO), + BMediaEventLooper(), + BMediaNode("ProducerNode"), + mBufferGroup(0), + mBufferProducerSem(-1), + mBufferProducer(-1), + mOutputEnabled(false) +{ + out("ProducerNode::ProducerNode\n"); + mBufferGroup = new BBufferGroup(4096,3); +} + +ProducerNode::~ProducerNode() +{ + out("ProducerNode::~ProducerNode\n"); + Quit(); + delete mBufferGroup; +} + +void +ProducerNode::NodeRegistered() +{ + out("ProducerNode::NodeRegistered\n"); + InitializeOutput(); + SetPriority(108); + Run(); +} + + +status_t +ProducerNode::FormatSuggestionRequested( + media_type type, + int32 quality, + media_format * format) +{ + out("ProducerNode::FormatSuggestionRequested\n"); + + if (type != B_MEDIA_RAW_AUDIO) + return B_MEDIA_BAD_FORMAT; + + format->u.raw_audio = media_raw_audio_format::wildcard; + format->u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT; + format->u.raw_audio.channel_count = 1; + format->u.raw_audio.frame_rate = 44100; + format->u.raw_audio.byte_order = (B_HOST_IS_BENDIAN) ? B_MEDIA_BIG_ENDIAN : B_MEDIA_LITTLE_ENDIAN; + + return B_OK; +} + +status_t +ProducerNode::FormatProposal( + const media_source & output, + media_format * format) +{ + out("ProducerNode::FormatProposal\n"); + + if (format == NULL) + return B_BAD_VALUE; + + if (output != mOutput.source) + return B_MEDIA_BAD_SOURCE; + + return B_OK; +} + +status_t +ProducerNode::FormatChangeRequested( + const media_source & source, + const media_destination & destination, + media_format * io_format, + int32 * _deprecated_) +{ + out("ProducerNode::FormatChangeRequested\n"); + return B_ERROR; +} + +status_t +ProducerNode::GetNextOutput( /* cookie starts as 0 */ + int32 * cookie, + media_output * out_output) +{ + out("ProducerNode::GetNextOutput\n"); + if (++(*cookie) > 1) + return B_BAD_INDEX; + + mOutput.node = Node(); + *out_output = mOutput; + return B_OK; +} + +status_t +ProducerNode::DisposeOutputCookie( + int32 cookie) +{ + out("ProducerNode::DisposeOutputCookie\n"); + return B_OK; +} + +/********************************************************* +* In this function, you should either pass on the group to your upstream guy, +* or delete your current group and hang on to this group. Deleting the previous +* group (unless you passed it on with the reclaim flag set to false) is very +* important, else you will 1) leak memory and 2) block someone who may want +* to reclaim the buffers living in that group. +*/ +status_t +ProducerNode::SetBufferGroup( + const media_source & for_source, + BBufferGroup * group) +{ + out("ProducerNode::SetBufferGroup\n"); + + if (for_source != mOutput.source) + return B_MEDIA_BAD_SOURCE; + +#if 0 + if (mBufferGroup != NULL && mBufferGroup != mOwnBufferGroup) { + // fixme! really delete if it isn't ours ? + trace("deleting buffer group!...\n"); + delete mBufferGroup; + trace("done!\n"); + } + + /* release the previous buffer group */ + if (mOwnBufferGroup != NULL) { + delete_own_buffer_group(); + } + + mBufferGroup = group; + + /* allocate new buffer group if necessary */ + if (mBufferGroup == NULL) { + create_own_buffer_group(); + mBufferGroup = mOwnBufferGroup; + } + return B_OK; +#endif + + return B_ERROR; +} + +status_t +ProducerNode::VideoClippingChanged( + const media_source & for_source, + int16 num_shorts, + int16 * clip_data, + const media_video_display_info & display, + int32 * _deprecated_) +{ + out("ProducerNode::VideoClippingChanged\n"); + return B_ERROR; +} + +status_t +ProducerNode::GetLatency( + bigtime_t * out_lantency) +{ + out("ProducerNode::GetLatency\n"); + *out_lantency = 23000; + return B_OK; +} + +status_t +ProducerNode::PrepareToConnect( + const media_source & what, + const media_destination & where, + media_format * format, + media_source * out_source, + char * out_name) +{ + out("ProducerNode::PrepareToConnect\n"); + + if (mOutput.source != what) + return B_MEDIA_BAD_SOURCE; + + if (mOutput.destination != media_destination::null) + return B_MEDIA_ALREADY_CONNECTED; + + if (format == NULL || out_source == NULL || out_name == NULL) + return B_BAD_VALUE; + +#if 0 + ASSERT(mOutputEnabled == false); + + trace("old format:\n"); + dump_format(format); + + status_t status; + + status = specialize_format_to_inputformat(format); + if (status != B_OK) + return status; + +#endif + + + *out_source = mOutput.source; + strcpy(out_name,mOutput.name); + //mOutput.destination = where; //really now? fixme + + return B_OK; +} + +void +ProducerNode::Connect( + status_t error, + const media_source & source, + const media_destination & destination, + const media_format & format, + char * io_name) +{ + out("ProducerNode::Connect\n"); + + if (error != B_OK) { + InitializeOutput(); + return; + } +/* + if (mOutput.destination != destination) { //if connected in PrepareToConnect fixme? + trace("error mOutput.destination != destination\n"); + return; + } +*/ + mOutput.destination = destination; + + if (mOutput.source != source) { + out("error mOutput.source != source\n"); + return; + } + + strcpy(io_name,mOutput.name); + +#if 0 + trace("format (final and approved):\n"); + dump_format(&format); +#endif + + mOutputEnabled = true; + + return; +} + +void +ProducerNode::Disconnect( + const media_source & what, + const media_destination & where) +{ + out("ProducerNode::Disconnect\n"); + mOutputEnabled = false; + + // unreserve connection + InitializeOutput(); +} + +void +ProducerNode::LateNoticeReceived( + const media_source & what, + bigtime_t how_much, + bigtime_t performance_time) +{ + out("ProducerNode::LateNoticeReceived\n"); + return; +} + +void +ProducerNode::EnableOutput( + const media_source & what, + bool enabled, + int32 * _deprecated_) +{ + out("ProducerNode::EnableOutput\n"); + mOutputEnabled = enabled; + return; +} + +BMediaAddOn* +ProducerNode::AddOn(int32 * internal_id) const +{ + out("ProducerNode::AddOn\n"); + return NULL; +} + +void +ProducerNode::HandleEvent(const media_timed_event *event, + bigtime_t lateness, + bool realTimeEvent) +{ + out("ProducerNode::HandleEvent\n"); + switch (event->type) + { + case BTimedEventQueue::B_HANDLE_BUFFER: + { + out("B_HANDLE_BUFFER (should not happen)\n"); + } + break; + + case BTimedEventQueue::B_PARAMETER: + { + out("B_PARAMETER\n"); + } + break; + + case BTimedEventQueue::B_START: + { + out("B_START\n"); + if (mBufferProducer != -1) { + out("already running\n"); + break; + } + mBufferProducerSem = create_sem(0,"producer blocking sem"); + mBufferProducer = spawn_thread(_bufferproducer,"Buffer Producer",B_NORMAL_PRIORITY,this); + resume_thread(mBufferProducer); + } + break; + + case BTimedEventQueue::B_STOP: + { + out("B_STOP\n"); + if (mBufferProducer == -1) { + out("not running\n"); + break; + } + status_t err; + delete_sem(mBufferProducerSem); + wait_for_thread(mBufferProducer,&err); + mBufferProducer = -1; + mBufferProducerSem = -1; + } + // stopping implies not handling any more buffers. So, we flush all pending + // buffers out of the event queue before returning to the event loop. + EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HANDLE_BUFFER); + break; + + case BTimedEventQueue::B_SEEK: + { + out("B_SEEK\n"); + } + break; + + case BTimedEventQueue::B_WARP: + { + out("B_WARP\n"); + } + // similarly, time warps aren't meaningful to the logger, so just record it and return + //mLogger->Log(LOG_WARP_HANDLED, logMsg); + break; + + case BTimedEventQueue::B_DATA_STATUS: + { + out("B_DATA_STATUS\n"); + } + break; + + default: + { + out("default\n"); + } + break; + } +} + + +status_t +ProducerNode::HandleMessage(int32 message,const void *data, size_t size) +{ + out("ProducerNode::HandleMessage %lx\n",message); + if (B_OK == BBufferProducer::HandleMessage(message,data,size)) + return B_OK; + if (B_OK == BMediaEventLooper::HandleMessage(message,data,size)) + return B_OK; + return BMediaNode::HandleMessage(message,data,size); +} + +void +ProducerNode::AdditionalBufferRequested( + const media_source & source, + media_buffer_id prev_buffer, + bigtime_t prev_time, + const media_seek_tag * prev_tag) +{ + out("ProducerNode::AdditionalBufferRequested\n"); + release_sem(mBufferProducerSem); +} + +void +ProducerNode::LatencyChanged( + const media_source & source, + const media_destination & destination, + bigtime_t new_latency, + uint32 flags) +{ + out("ProducerNode::LatencyChanged\n"); +} + +void +ProducerNode::InitializeOutput() +{ + out("ConsumerNode::InitializeOutput()\n"); + mOutput.source.port = ControlPort(); + mOutput.source.id = 0; + mOutput.destination = media_destination::null; + mOutput.node = Node(); + mOutput.format.type = B_MEDIA_RAW_AUDIO; + mOutput.format.u.raw_audio = media_raw_audio_format::wildcard; + mOutput.format.u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT; + mOutput.format.u.raw_audio.channel_count = 1; + mOutput.format.u.raw_audio.frame_rate = 44100; + mOutput.format.u.raw_audio.byte_order = (B_HOST_IS_BENDIAN) ? B_MEDIA_BIG_ENDIAN : B_MEDIA_LITTLE_ENDIAN; + strcpy(mOutput.name, "this way out"); +} + +int32 +ProducerNode::_bufferproducer(void *arg) +{ + ((ProducerNode *)arg)->BufferProducer(); + return 0; +} + +#define DELAY 2000000 + +void +ProducerNode::BufferProducer() +{ + // this thread produces one buffer each two seconds, + // and shedules it to be handled one second later than produced + // assuming a realtime timesource + + status_t rv; + for (;;) { + rv = acquire_sem_etc(mBufferProducerSem,1,B_RELATIVE_TIMEOUT,DELAY); + if (rv == B_INTERRUPTED) { + continue; + } else if (rv == B_OK) { + // triggered by AdditionalBufferRequested + release_sem(mBufferProducerSem); + } else if (rv != B_TIMED_OUT) { + // triggered by deleting the semaphore (stop request) + break; + } + if (!mOutputEnabled) + continue; + + BBuffer *buffer; +// out("ProducerNode: RequestBuffer\n"); + buffer = mBufferGroup->RequestBuffer(2048); + if (!buffer) { + } + buffer->Header()->start_time = TimeSource()->Now() + DELAY / 2; + out("ProducerNode: SendBuffer, sheduled time = %5.4f\n",buffer->Header()->start_time / 1E6); + rv = SendBuffer(buffer, mOutput.destination); + if (rv != B_OK) { + } + } +} diff --git a/src/tests/kits/media/nodetest/ProducerNode.h b/src/tests/kits/media/nodetest/ProducerNode.h new file mode 100644 index 0000000000..deeca06f10 --- /dev/null +++ b/src/tests/kits/media/nodetest/ProducerNode.h @@ -0,0 +1,104 @@ +#include +#include + +class ProducerNode : public virtual BBufferProducer, BMediaEventLooper +{ +public: + ProducerNode(); + ~ProducerNode(); + +protected: + + /* functionality of BMediaNode */ +virtual BMediaAddOn* AddOn( + int32 * internal_id) const; + +virtual void NodeRegistered(); + + /* functionality of BBufferProducer */ +virtual status_t FormatSuggestionRequested( + media_type type, + int32 quality, + media_format * format); +virtual status_t FormatProposal( + const media_source & output, + media_format * format); +virtual status_t FormatChangeRequested( + const media_source & source, + const media_destination & destination, + media_format * io_format, + int32 * _deprecated_); +virtual status_t GetNextOutput( /* cookie starts as 0 */ + int32 * cookie, + media_output * out_output); +virtual status_t DisposeOutputCookie( + int32 cookie); +virtual status_t SetBufferGroup( + const media_source & for_source, + BBufferGroup * group); +virtual status_t VideoClippingChanged( + const media_source & for_source, + int16 num_shorts, + int16 * clip_data, + const media_video_display_info & display, + int32 * _deprecated_); +virtual status_t GetLatency( + bigtime_t * out_lantency); +virtual status_t PrepareToConnect( + const media_source & what, + const media_destination & where, + media_format * format, + media_source * out_source, + char * out_name); +virtual void Connect( + status_t error, + const media_source & source, + const media_destination & destination, + const media_format & format, + char * io_name); +virtual void Disconnect( + const media_source & what, + const media_destination & where); +virtual void LateNoticeReceived( + const media_source & what, + bigtime_t how_much, + bigtime_t performance_time); +virtual void EnableOutput( + const media_source & what, + bool enabled, + int32 * _deprecated_); + +virtual status_t HandleMessage(int32 message, + const void *data, size_t size); + +virtual void AdditionalBufferRequested( + const media_source & source, + media_buffer_id prev_buffer, + bigtime_t prev_time, + const media_seek_tag * prev_tag); + +virtual void LatencyChanged( + const media_source & source, + const media_destination & destination, + bigtime_t new_latency, + uint32 flags); + + /* functionality of BMediaEventLooper */ +virtual void HandleEvent(const media_timed_event *event, + bigtime_t lateness, + bool realTimeEvent = false); + + /* our own functionality */ +void InitializeOutput(); + +static int32 _bufferproducer(void *arg); +void BufferProducer(); + + BBufferGroup *mBufferGroup; + sem_id mBufferProducerSem; + thread_id mBufferProducer; + + bool mOutputEnabled; + media_output mOutput; +}; + diff --git a/src/tests/kits/media/nodetest/main.cpp b/src/tests/kits/media/nodetest/main.cpp new file mode 100644 index 0000000000..021d5d8d00 --- /dev/null +++ b/src/tests/kits/media/nodetest/main.cpp @@ -0,0 +1,159 @@ +#include +#include +#include +#include "ConsumerNode.h" +#include "ProducerNode.h" +#include "misc.h" + +BMediaRoster *roster; +ProducerNode *producer; +ConsumerNode *consumer; +status_t rv; + +int main() +{ + out("Basic BBufferProducer, BBufferConsumer, BMediaRoster test\n"); + out("for OpenBeOS by Marcus Overhagen \n\n"); + out("Creating BApplication now\n"); + BApplication app("application/x-vnd.OpenBeOS-NodeTest"); + + out("Creating MediaRoster\n"); + roster = BMediaRoster::Roster(); + val(roster); + + out("Creating ProducerNode\n"); + producer = new ProducerNode(); + val(producer); + + out("Creating ConsumerNode\n"); + consumer = new ConsumerNode(); + val(consumer); + + out("Registering ProducerNode\n"); + rv = roster->RegisterNode(producer); + val(rv); + + out("Registering ConsumerNode\n"); + rv = roster->RegisterNode(consumer); + val(rv); + + media_node sourceNode; + media_node destinationNode; + + out("Calling producer->Node()\n"); + sourceNode = producer->Node(); + + out("Calling consumer->Node()\n"); + destinationNode = consumer->Node(); + + media_output output; + media_input input; + int32 count; + +#if 1 + out("Calling GetAllOutputsFor(source)\n"); + rv = roster->GetAllOutputsFor(sourceNode,&output,1,&count); + val(rv); + rv = (count == 1) ? B_OK : B_ERROR; + val(rv); + + out("Calling GetAllInputsFor(destination)\n"); + rv = roster->GetAllInputsFor(destinationNode,&input,1,&count); + val(rv); + rv = (count == 1) ? B_OK : B_ERROR; + val(rv); +#else + out("Calling GetFreeOutputsFor(source)\n"); + rv = roster->GetFreeOutputsFor(sourceNode,&output,1,&count,B_MEDIA_RAW_AUDIO); + val(rv); + rv = (count == 1) ? B_OK : B_ERROR; + val(rv); + + out("Calling GetFreeInputsFor(destination)\n"); + rv = roster->GetFreeInputsFor(destinationNode,&input,1,&count,B_MEDIA_RAW_AUDIO); + val(rv); + rv = (count == 1) ? B_OK : B_ERROR; + val(rv); +#endif + + media_format format; + format.type = B_MEDIA_RAW_AUDIO; + format.u.raw_audio = media_raw_audio_format::wildcard; + + out("Connecting nodes\n"); + rv = roster->Connect(output.source, input.destination, &format, &output, &input); + val(rv); + + out("Prerolling Producer()\n"); + rv = roster->PrerollNode(sourceNode); + val(rv); + + out("Prerolling Consumer\n"); + rv = roster->PrerollNode(destinationNode); + val(rv); + + bigtime_t time1; + bigtime_t time2; + bigtime_t start; + + out("Getting Producer startlatency\n"); + rv = roster->GetStartLatencyFor(destinationNode, &time1); + val(rv); + + out("Getting Consumer startlatency\n"); + rv = roster->GetStartLatencyFor(sourceNode, &time2); + val(rv); + + start = max_c(time1,time2) + producer->TimeSource()->PerformanceTimeFor(BTimeSource::RealTime() + 2000000); + + out("Starting Consumer in 2 sec\n"); + rv = roster->StartNode(destinationNode, start); + val(rv); + + out("Starting Producer in 2 sec\n"); + rv = roster->StartNode(sourceNode, start); + val(rv); + + out("########################## PRESS ENTER TO QUIT ##########################\n"); + getchar(); + + media_node_id sourceNodeID; + media_node_id destinationNodeID; + + out("Calling producer->ID()\n"); + sourceNodeID = producer->ID(); + + out("Calling consumer->ID()\n"); + destinationNodeID = consumer->ID(); + + out("Stopping Producer()\n"); + rv = roster->StopNode(sourceNode, 0, true); + val(rv); + + out("Stopping Consumer\n"); + rv = roster->StopNode(destinationNode, 0, true); + val(rv); + + out("Disconnecting nodes\n"); + rv = roster->Disconnect(sourceNodeID, output.source, destinationNodeID, input.destination); + val(rv); + + out("Unregistering ProducerNode\n"); + rv = roster->UnregisterNode(producer); + val(rv); + + out("Unregistering ConsumerNode\n"); + rv = roster->UnregisterNode(consumer); + val(rv); + + out("Releasing ProducerNode\n"); + rv = (producer->Release() == NULL) ? B_OK : B_ERROR; + val(rv); + + out("Releasing ConsumerNode\n"); + rv = (consumer->Release() == NULL) ? B_OK : B_ERROR; + val(rv); + + return 0; +} + diff --git a/src/tests/kits/media/nodetest/misc.cpp b/src/tests/kits/media/nodetest/misc.cpp new file mode 100644 index 0000000000..aaaa0fcb76 --- /dev/null +++ b/src/tests/kits/media/nodetest/misc.cpp @@ -0,0 +1,37 @@ +#include +#include "misc.h" + +void val(void *p) +{ + if (p) + out("OK\n"); + else + out("failed\n"); +} + +void val(status_t status) +{ + if (status == B_OK) + out("OK\n"); + else + out("failed, 0x%08x, %s\n",status,strerror(status)); +} + +void wait() +{ + out("press enter to continue\n"); + getchar(); +} + +void out(const char *format,...) +{ + static bigtime_t start = 0; + if (start == 0) + start = system_time(); + printf("%3.4f ",(system_time()-start) / 1E6); + va_list ap; + va_start(ap,format); + vfprintf(stdout,format,ap); + va_end(ap); + fflush(0); +} diff --git a/src/tests/kits/media/nodetest/misc.h b/src/tests/kits/media/nodetest/misc.h new file mode 100644 index 0000000000..57deb08bc9 --- /dev/null +++ b/src/tests/kits/media/nodetest/misc.h @@ -0,0 +1,9 @@ +#include +#include + +void val(void *p); +void val(status_t status); + +void wait(); +void out(const char *format,...); + diff --git a/src/tests/kits/midi/midi_player/Midi1To2Bridge.cpp b/src/tests/kits/midi/midi_player/Midi1To2Bridge.cpp new file mode 100644 index 0000000000..80506ee2ad --- /dev/null +++ b/src/tests/kits/midi/midi_player/Midi1To2Bridge.cpp @@ -0,0 +1,130 @@ +/* + +Midi1To2Bridge.cpp + +Copyright (c) 2002 OpenBeOS. + +Midi Kit 1 input to Midi Kit 2 input (consumer) bridge. +A Midi Kit 1 input node that passes the midi events via a +Midi Kit 2 producer to Midi Kit 2 consumers. + +Author: + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#include "Midi1To2Bridge.h" + +Midi1To2Bridge::Midi1To2Bridge(const char *name) { + fOutput = new BMidiLocalProducer(name); + fOutput->Register(); +} + +Midi1To2Bridge::~Midi1To2Bridge() { + fOutput->Unregister(); + fOutput->Release(); +} + +void Midi1To2Bridge::NoteOff(uchar channel, + uchar note, + uchar velocity, + uint32 time = B_NOW) { + fOutput->SprayNoteOff(channel-1, note, velocity, ToBigtime(time)); +} + +void Midi1To2Bridge::NoteOn(uchar channel, + uchar note, + uchar velocity, + uint32 time = B_NOW) { + fOutput->SprayNoteOn(channel-1, note, velocity, ToBigtime(time)); +} + + +void Midi1To2Bridge::KeyPressure(uchar channel, + uchar note, + uchar pressure, + uint32 time = B_NOW) { + fOutput->SprayKeyPressure(channel-1, note, pressure, ToBigtime(time)); +} + + +void Midi1To2Bridge::ControlChange(uchar channel, + uchar controlNumber, + uchar controlValue, + uint32 time = B_NOW) { + fOutput->SprayControlChange(channel-1, controlNumber, controlValue, ToBigtime(time)); +} + + +void Midi1To2Bridge::ProgramChange(uchar channel, + uchar programNumber, + uint32 time = B_NOW) { + fOutput->SprayProgramChange(channel-1, programNumber, ToBigtime(time)); +} + + +void Midi1To2Bridge::ChannelPressure(uchar channel, + uchar pressure, + uint32 time = B_NOW) { + fOutput->SprayChannelPressure(channel-1, pressure, ToBigtime(time)); +} + + +void Midi1To2Bridge::PitchBend(uchar channel, + uchar lsb, + uchar msb, + uint32 time = B_NOW) { + fOutput->SprayPitchBend(channel-1, lsb, msb, ToBigtime(time)); +} + + +void Midi1To2Bridge::SystemExclusive(void* data, + size_t dataLength, + uint32 time = B_NOW) { + fOutput->SpraySystemExclusive(data, dataLength, ToBigtime(time)); +} + + +void Midi1To2Bridge::SystemCommon(uchar statusByte, + uchar data1, + uchar data2, + uint32 time = B_NOW) { + fOutput->SpraySystemCommon(statusByte, data1, data2, ToBigtime(time)); +} + + +void Midi1To2Bridge::SystemRealTime(uchar statusByte, uint32 time = B_NOW) { + fOutput->SpraySystemRealTime(statusByte, ToBigtime(time)); +} + + +void Midi1To2Bridge::TempoChange(int32 bpm, uint32 time = B_NOW) { + fOutput->SprayTempoChange(bpm, ToBigtime(time)); +} + + +void Midi1To2Bridge::AllNotesOff(bool justChannel = true, uint32 time = B_NOW) { + bigtime_t t = ToBigtime(time); + for (uchar channel = 0; channel < 16; channel ++) { + fOutput->SprayControlChange(channel, B_ALL_NOTES_OFF, 0, t); + } +} + diff --git a/src/tests/kits/midi/midi_player/Midi1To2Bridge.h b/src/tests/kits/midi/midi_player/Midi1To2Bridge.h new file mode 100644 index 0000000000..534e83a93f --- /dev/null +++ b/src/tests/kits/midi/midi_player/Midi1To2Bridge.h @@ -0,0 +1,100 @@ +/* + +Midi1To2Bridge.h + +Copyright (c) 2002 OpenBeOS. + +Midi Kit 1 input to Midi Kit 2 input (consumer) bridge. +A Midi Kit 1 input node that passes the midi events via a +Midi Kit 2 producer to Midi Kit 2 consumers. + +Author: + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef _MIDI_BRIDGE_H +#define _MIDI_BRIDGE_H + +#include +#include + +// Note channel starts with 0 in Midi Kit 2 and it starts with 1 in Midi Kit 1 + +class Midi1To2Bridge : public BMidi { + BMidiLocalProducer* fOutput; + + static inline bigtime_t ToBigtime(uint32 time) { return time * (bigtime_t)1000; } + +public: + Midi1To2Bridge(const char* name); + ~Midi1To2Bridge(); + +virtual void NoteOff(uchar channel, + uchar note, + uchar velocity, + uint32 time = B_NOW); + +virtual void NoteOn(uchar channel, + uchar note, + uchar velocity, + uint32 time = B_NOW); + +virtual void KeyPressure(uchar channel, + uchar note, + uchar pressure, + uint32 time = B_NOW); + +virtual void ControlChange(uchar channel, + uchar controlNumber, + uchar controlValue, + uint32 time = B_NOW); + +virtual void ProgramChange(uchar channel, + uchar programNumber, + uint32 time = B_NOW); + +virtual void ChannelPressure(uchar channel, + uchar pressure, + uint32 time = B_NOW); + +virtual void PitchBend(uchar channel, + uchar lsb, + uchar msb, + uint32 time = B_NOW); + +virtual void SystemExclusive(void* data, + size_t dataLength, + uint32 time = B_NOW); + +virtual void SystemCommon(uchar statusByte, + uchar data1, + uchar data2, + uint32 time = B_NOW); + +virtual void SystemRealTime(uchar statusByte, uint32 time = B_NOW); + +virtual void TempoChange(int32 bpm, uint32 time = B_NOW); + +virtual void AllNotesOff(bool justChannel = true, uint32 time = B_NOW); +}; + +#endif diff --git a/src/tests/kits/midi/midi_player/MidiDelay.cpp b/src/tests/kits/midi/midi_player/MidiDelay.cpp new file mode 100644 index 0000000000..1f0dc0f74c --- /dev/null +++ b/src/tests/kits/midi/midi_player/MidiDelay.cpp @@ -0,0 +1,132 @@ +/* + +MidiDelay.cpp + +Copyright (c) 2002 OpenBeOS. + +A filter for Midi Kit 1 that sprays midi events +when the performance time is reached. + +Author: + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#include + +#include "MidiDelay.h" + +void MidiDelay::NoteOff(uchar channel, + uchar note, + uchar velocity, + uint32 time = B_NOW) { + snooze_until(ToBigtime(time), B_SYSTEM_TIMEBASE); + SprayNoteOff(channel, note, velocity, time); +} + +void MidiDelay::NoteOn(uchar channel, + uchar note, + uchar velocity, + uint32 time = B_NOW) { + snooze_until(ToBigtime(time), B_SYSTEM_TIMEBASE); + SprayNoteOn(channel, note, velocity, time); +} + + +void MidiDelay::KeyPressure(uchar channel, + uchar note, + uchar pressure, + uint32 time = B_NOW) { + snooze_until(ToBigtime(time), B_SYSTEM_TIMEBASE); + SprayKeyPressure(channel, note, pressure, time); +} + + +void MidiDelay::ControlChange(uchar channel, + uchar controlNumber, + uchar controlValue, + uint32 time = B_NOW) { + snooze_until(ToBigtime(time), B_SYSTEM_TIMEBASE); + SprayControlChange(channel, controlNumber, controlValue, time); +} + + +void MidiDelay::ProgramChange(uchar channel, + uchar programNumber, + uint32 time = B_NOW) { + snooze_until(ToBigtime(time), B_SYSTEM_TIMEBASE); + SprayProgramChange(channel, programNumber, time); +} + + +void MidiDelay::ChannelPressure(uchar channel, + uchar pressure, + uint32 time = B_NOW) { + snooze_until(ToBigtime(time), B_SYSTEM_TIMEBASE); + SprayChannelPressure(channel, pressure, time); +} + + +void MidiDelay::PitchBend(uchar channel, + uchar lsb, + uchar msb, + uint32 time = B_NOW) { + snooze_until(ToBigtime(time), B_SYSTEM_TIMEBASE); + SprayPitchBend(channel, lsb, msb, time); +} + + +void MidiDelay::SystemExclusive(void* data, + size_t dataLength, + uint32 time = B_NOW) { + snooze_until(ToBigtime(time), B_SYSTEM_TIMEBASE); + SpraySystemExclusive(data, dataLength, time); +} + + +void MidiDelay::SystemCommon(uchar statusByte, + uchar data1, + uchar data2, + uint32 time = B_NOW) { + snooze_until(ToBigtime(time), B_SYSTEM_TIMEBASE); + SpraySystemCommon(statusByte, data1, data2, time); +} + + +void MidiDelay::SystemRealTime(uchar statusByte, uint32 time = B_NOW) { + snooze_until(ToBigtime(time), B_SYSTEM_TIMEBASE); + SpraySystemRealTime(statusByte, time); +} + + +void MidiDelay::TempoChange(int32 bpm, uint32 time = B_NOW) { + snooze_until(ToBigtime(time), B_SYSTEM_TIMEBASE); + SprayTempoChange(bpm, time); +} + + +void MidiDelay::AllNotesOff(bool justChannel = true, uint32 time = B_NOW) { + snooze_until(ToBigtime(time), B_SYSTEM_TIMEBASE); + for (uchar channel = 0; channel < 16; channel ++) { + SprayControlChange(channel, B_ALL_NOTES_OFF, 0, time); + } +} + diff --git a/src/tests/kits/midi/midi_player/MidiDelay.h b/src/tests/kits/midi/midi_player/MidiDelay.h new file mode 100644 index 0000000000..fe8b504a7c --- /dev/null +++ b/src/tests/kits/midi/midi_player/MidiDelay.h @@ -0,0 +1,93 @@ +/* + +MidiDelay.h + +Copyright (c) 2002 OpenBeOS. + +A filter for Midi Kit 1 that sprays midi events +when the performance time is reached. + +Author: + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef _MIDI_DELAY_H +#define _MIDI_DELAY_H + +#include + +class MidiDelay : public BMidi { + + static inline bigtime_t ToBigtime(uint32 time) { return time * (bigtime_t)1000; } + +public: + +virtual void NoteOff(uchar channel, + uchar note, + uchar velocity, + uint32 time = B_NOW); + +virtual void NoteOn(uchar channel, + uchar note, + uchar velocity, + uint32 time = B_NOW); + +virtual void KeyPressure(uchar channel, + uchar note, + uchar pressure, + uint32 time = B_NOW); + +virtual void ControlChange(uchar channel, + uchar controlNumber, + uchar controlValue, + uint32 time = B_NOW); + +virtual void ProgramChange(uchar channel, + uchar programNumber, + uint32 time = B_NOW); + +virtual void ChannelPressure(uchar channel, + uchar pressure, + uint32 time = B_NOW); + +virtual void PitchBend(uchar channel, + uchar lsb, + uchar msb, + uint32 time = B_NOW); + +virtual void SystemExclusive(void* data, + size_t dataLength, + uint32 time = B_NOW); + +virtual void SystemCommon(uchar statusByte, + uchar data1, + uchar data2, + uint32 time = B_NOW); + +virtual void SystemRealTime(uchar statusByte, uint32 time = B_NOW); + +virtual void TempoChange(int32 bpm, uint32 time = B_NOW); + +virtual void AllNotesOff(bool justChannel = true, uint32 time = B_NOW); +}; + +#endif diff --git a/src/tests/kits/midi/midi_player/MidiPlayer.cpp b/src/tests/kits/midi/midi_player/MidiPlayer.cpp new file mode 100644 index 0000000000..5fe3d1758d --- /dev/null +++ b/src/tests/kits/midi/midi_player/MidiPlayer.cpp @@ -0,0 +1,73 @@ +/* + +main.cpp + +Copyright (c) 2002 OpenBeOS. + +Test application plays a midi file via a BMidiLocalProducer. + +Authors: + Michael Pfeiffer + Paul Stadler + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#include +#include +#include +#include + +#include "MidiDelay.h" +#include "Midi1To2Bridge.h" + +int main(int argc, char *argv[]) { + if (argc != 2) { + fprintf(stderr, "Error missing parameter!\n%s midi_file\n", argv[0]); + return -1; + } + + BEntry entry(argv[1],true); + if(!entry.Exists()) { + fprintf(stderr, "File does not exist!\n"); + return -1; + } + + new BApplication("application/vnd.obos-midiplayer"); + BMidiStore store; + MidiDelay delay; + Midi1To2Bridge bridge("MidiPlayer output"); + + entry_ref e_ref; + entry.GetRef(&e_ref); + store.Import(&e_ref); + store.Connect(&delay); + delay.Connect(&bridge); + // Use PatchBay to connect the MidiProducer with a MidiConsumer + // (or just MidiSynth 1.6) + printf("Connect MidiPlayer output to a MidiConsumer.\n""Hit return to start! "); getchar(); + store.Start(); + while(store.IsRunning()) { + snooze(100000); + } + store.Stop(); + store.Disconnect(&delay); + delay.Disconnect(&bridge); +} diff --git a/src/tests/kits/midi/midi_player_replacement/Activity.cpp b/src/tests/kits/midi/midi_player_replacement/Activity.cpp new file mode 100644 index 0000000000..cdd1586fe9 --- /dev/null +++ b/src/tests/kits/midi/midi_player_replacement/Activity.cpp @@ -0,0 +1,81 @@ +/* +Author: Jerome LEVEQUE +Email: jerl1@caramail.com +*/ +#include "Activity.h" + +#include +#include + +//---------------------------------------------------------- + +Activity::Activity(BRect rect) + : BView(rect, "Midi Activity", + B_FOLLOW_ALL, B_WILL_DRAW | B_PULSE_NEEDED) +{ + for (int i = 0; i < 16; i++) + fActivity[i] = 0; + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); +} + +//---------------------------------------------------------- + +void Activity::AttachedToWindow(void) +{ + Window()->SetPulseRate(200000); + + AddChild(new BStringView(BRect( 65, 45, 80, 55), NULL, "1")); + AddChild(new BStringView(BRect(125, 45, 140, 55), NULL, "2")); + AddChild(new BStringView(BRect(185, 45, 200, 55), NULL, "3")); + AddChild(new BStringView(BRect(245, 45, 260, 55), NULL, "4")); + + AddChild(new BStringView(BRect( 65, 105, 80, 115), NULL, "5")); + AddChild(new BStringView(BRect(125, 105, 140, 115), NULL, "6")); + AddChild(new BStringView(BRect(185, 105, 200, 115), NULL, "7")); + AddChild(new BStringView(BRect(245, 105, 260, 115), NULL, "8")); + + AddChild(new BStringView(BRect( 65, 165, 80, 175), NULL, "9")); + AddChild(new BStringView(BRect(123, 165, 140, 175), NULL, "10")); + AddChild(new BStringView(BRect(183, 165, 200, 175), NULL, "11")); + AddChild(new BStringView(BRect(243, 165, 260, 175), NULL, "12")); + + AddChild(new BStringView(BRect( 63, 220, 80, 235), NULL, "13")); + AddChild(new BStringView(BRect(123, 220, 140, 235), NULL, "14")); + AddChild(new BStringView(BRect(183, 220, 200, 235), NULL, "15")); + AddChild(new BStringView(BRect(243, 220, 260, 235), NULL, "16")); +} + +//---------------------------------------------------------- + +void Activity::Draw(BRect rect) +{ +bigtime_t present = system_time() - 600000; + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + { + BPoint aPoint(i * 60 + 70, j * 60 + 70); + SetHighColor(0, 0, 0); + StrokeEllipse(aPoint, 5, 5); + SetHighColor(0, 255, 0); + if (present < fActivity[j * 4 + i]) + FillEllipse(aPoint, 4, 4); + } +} + +//---------------------------------------------------------- + +void Activity::Pulse(void) +{ + Invalidate(BRect(60, 60, 300, 300)); +} + +//---------------------------------------------------------- + +void Activity::NoteOn(uchar channel, uchar note, + uchar velocity, uint32 time = B_NOW) +{//This function just update the variable + fActivity[channel - 1] = system_time(); + BMidi::NoteOn(channel, note, velocity, time); +} + +//---------------------------------------------------------- diff --git a/src/tests/kits/midi/midi_player_replacement/Activity.h b/src/tests/kits/midi/midi_player_replacement/Activity.h new file mode 100644 index 0000000000..44f93cbb60 --- /dev/null +++ b/src/tests/kits/midi/midi_player_replacement/Activity.h @@ -0,0 +1,50 @@ +/* +Author: Jerome LEVEQUE +Email: jerl1@caramail.com +*/ +#ifndef ACTIVITY_H +#define ACTIVITY_H + +#include +#include + +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- + +class Activity : public BMidi, public BView +{ +public: + Activity(BRect rect); + + virtual void AttachedToWindow(void); + virtual void Draw(BRect rect); + virtual void Pulse(void); + virtual void NoteOn(uchar channel, uchar note, uchar velocity, uint32 time = B_NOW); + +private: + bigtime_t fActivity[16]; //16 channels + + +}; +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- + + + + +#endif \ No newline at end of file diff --git a/src/tests/kits/midi/midi_player_replacement/MidiDelay.cpp b/src/tests/kits/midi/midi_player_replacement/MidiDelay.cpp new file mode 100644 index 0000000000..1f0dc0f74c --- /dev/null +++ b/src/tests/kits/midi/midi_player_replacement/MidiDelay.cpp @@ -0,0 +1,132 @@ +/* + +MidiDelay.cpp + +Copyright (c) 2002 OpenBeOS. + +A filter for Midi Kit 1 that sprays midi events +when the performance time is reached. + +Author: + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#include + +#include "MidiDelay.h" + +void MidiDelay::NoteOff(uchar channel, + uchar note, + uchar velocity, + uint32 time = B_NOW) { + snooze_until(ToBigtime(time), B_SYSTEM_TIMEBASE); + SprayNoteOff(channel, note, velocity, time); +} + +void MidiDelay::NoteOn(uchar channel, + uchar note, + uchar velocity, + uint32 time = B_NOW) { + snooze_until(ToBigtime(time), B_SYSTEM_TIMEBASE); + SprayNoteOn(channel, note, velocity, time); +} + + +void MidiDelay::KeyPressure(uchar channel, + uchar note, + uchar pressure, + uint32 time = B_NOW) { + snooze_until(ToBigtime(time), B_SYSTEM_TIMEBASE); + SprayKeyPressure(channel, note, pressure, time); +} + + +void MidiDelay::ControlChange(uchar channel, + uchar controlNumber, + uchar controlValue, + uint32 time = B_NOW) { + snooze_until(ToBigtime(time), B_SYSTEM_TIMEBASE); + SprayControlChange(channel, controlNumber, controlValue, time); +} + + +void MidiDelay::ProgramChange(uchar channel, + uchar programNumber, + uint32 time = B_NOW) { + snooze_until(ToBigtime(time), B_SYSTEM_TIMEBASE); + SprayProgramChange(channel, programNumber, time); +} + + +void MidiDelay::ChannelPressure(uchar channel, + uchar pressure, + uint32 time = B_NOW) { + snooze_until(ToBigtime(time), B_SYSTEM_TIMEBASE); + SprayChannelPressure(channel, pressure, time); +} + + +void MidiDelay::PitchBend(uchar channel, + uchar lsb, + uchar msb, + uint32 time = B_NOW) { + snooze_until(ToBigtime(time), B_SYSTEM_TIMEBASE); + SprayPitchBend(channel, lsb, msb, time); +} + + +void MidiDelay::SystemExclusive(void* data, + size_t dataLength, + uint32 time = B_NOW) { + snooze_until(ToBigtime(time), B_SYSTEM_TIMEBASE); + SpraySystemExclusive(data, dataLength, time); +} + + +void MidiDelay::SystemCommon(uchar statusByte, + uchar data1, + uchar data2, + uint32 time = B_NOW) { + snooze_until(ToBigtime(time), B_SYSTEM_TIMEBASE); + SpraySystemCommon(statusByte, data1, data2, time); +} + + +void MidiDelay::SystemRealTime(uchar statusByte, uint32 time = B_NOW) { + snooze_until(ToBigtime(time), B_SYSTEM_TIMEBASE); + SpraySystemRealTime(statusByte, time); +} + + +void MidiDelay::TempoChange(int32 bpm, uint32 time = B_NOW) { + snooze_until(ToBigtime(time), B_SYSTEM_TIMEBASE); + SprayTempoChange(bpm, time); +} + + +void MidiDelay::AllNotesOff(bool justChannel = true, uint32 time = B_NOW) { + snooze_until(ToBigtime(time), B_SYSTEM_TIMEBASE); + for (uchar channel = 0; channel < 16; channel ++) { + SprayControlChange(channel, B_ALL_NOTES_OFF, 0, time); + } +} + diff --git a/src/tests/kits/midi/midi_player_replacement/MidiDelay.h b/src/tests/kits/midi/midi_player_replacement/MidiDelay.h new file mode 100644 index 0000000000..fe8b504a7c --- /dev/null +++ b/src/tests/kits/midi/midi_player_replacement/MidiDelay.h @@ -0,0 +1,93 @@ +/* + +MidiDelay.h + +Copyright (c) 2002 OpenBeOS. + +A filter for Midi Kit 1 that sprays midi events +when the performance time is reached. + +Author: + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef _MIDI_DELAY_H +#define _MIDI_DELAY_H + +#include + +class MidiDelay : public BMidi { + + static inline bigtime_t ToBigtime(uint32 time) { return time * (bigtime_t)1000; } + +public: + +virtual void NoteOff(uchar channel, + uchar note, + uchar velocity, + uint32 time = B_NOW); + +virtual void NoteOn(uchar channel, + uchar note, + uchar velocity, + uint32 time = B_NOW); + +virtual void KeyPressure(uchar channel, + uchar note, + uchar pressure, + uint32 time = B_NOW); + +virtual void ControlChange(uchar channel, + uchar controlNumber, + uchar controlValue, + uint32 time = B_NOW); + +virtual void ProgramChange(uchar channel, + uchar programNumber, + uint32 time = B_NOW); + +virtual void ChannelPressure(uchar channel, + uchar pressure, + uint32 time = B_NOW); + +virtual void PitchBend(uchar channel, + uchar lsb, + uchar msb, + uint32 time = B_NOW); + +virtual void SystemExclusive(void* data, + size_t dataLength, + uint32 time = B_NOW); + +virtual void SystemCommon(uchar statusByte, + uchar data1, + uchar data2, + uint32 time = B_NOW); + +virtual void SystemRealTime(uchar statusByte, uint32 time = B_NOW); + +virtual void TempoChange(int32 bpm, uint32 time = B_NOW); + +virtual void AllNotesOff(bool justChannel = true, uint32 time = B_NOW); +}; + +#endif diff --git a/src/tests/kits/midi/midi_player_replacement/MidiMeter.cpp b/src/tests/kits/midi/midi_player_replacement/MidiMeter.cpp new file mode 100644 index 0000000000..acf204d73d --- /dev/null +++ b/src/tests/kits/midi/midi_player_replacement/MidiMeter.cpp @@ -0,0 +1,11 @@ +#include +#include + + +class MidiMeter : public BMidi, BView +{ +public: + MidiMeter(void); + + +}; \ No newline at end of file diff --git a/src/tests/kits/midi/midi_player_replacement/MidiPlayer.rsrc b/src/tests/kits/midi/midi_player_replacement/MidiPlayer.rsrc new file mode 100644 index 0000000000..c66f58b927 Binary files /dev/null and b/src/tests/kits/midi/midi_player_replacement/MidiPlayer.rsrc differ diff --git a/src/tests/kits/midi/midi_player_replacement/MidiPlayerView.cpp b/src/tests/kits/midi/midi_player_replacement/MidiPlayerView.cpp new file mode 100644 index 0000000000..447be5b744 --- /dev/null +++ b/src/tests/kits/midi/midi_player_replacement/MidiPlayerView.cpp @@ -0,0 +1,327 @@ +/* +Author: Jerome LEVEQUE +Email: jerl1@caramail.com +*/ +#include "MidiPlayerView.h" +#include "Scope.h" +#include "Activity.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- + +MidiPlayerView::MidiPlayerView(void) + : BView(BRect(0, 0, 660, 360), "StandartView", + B_FOLLOW_ALL, B_WILL_DRAW) +{ + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + fInputStringView = new BStringView(BRect(10, 20, 200, 40), NULL, "None"); + fOutputStringView = new BStringView(BRect(10, 20, 200, 40), NULL, "None"); +} + +//---------------------------------------------------------- + +MidiPlayerView::~MidiPlayerView(void) +{ + delete fInputStringView; + delete fOutputStringView; +} + +//---------------------------------------------------------- + +void MidiPlayerView::AttachedToWindow(void) +{ +BPopUpMenu *Menu = NULL; +BMenuField *Field = NULL; +BMessage *msg = NULL; + + AddChild(fInputBox = new BBox(BRect(10, 0, 290, 170), "InputBox")); + Menu = new BPopUpMenu("Select Input"); + msg = new BMessage(INPUT_CHANGE_TO_FILE); + Menu->AddItem(new BMenuItem("From File", msg)); + msg = new BMessage(INPUT_CHANGE_TO_MIDIPORT); + Menu->AddItem(new BMenuItem("From MidiPort", msg)); + Field = new BMenuField(BRect(0, 0, 150, 20), NULL, NULL, Menu); + fInputBox->SetLabel((BView*)Field); + + AddChild(fOutputBox = new BBox(BRect(10, 180, 290, 350), "OutputBox")); + Menu = new BPopUpMenu("Select Output"); + msg = new BMessage(OUTPUT_CHANGE_TO_FILE); + Menu->AddItem(new BMenuItem("To File", msg)); + msg = new BMessage(OUTPUT_CHANGE_TO_BEOS_SYNTH); + Menu->AddItem(new BMenuItem("To BeOS Synth", msg)); + msg = new BMessage(OUTPUT_CHANGE_TO_BEOS_SYNTH_FILE); + Menu->AddItem(new BMenuItem("To Midi Synth File", msg)); + msg = new BMessage(OUTPUT_CHANGE_TO_MIDIPORT); + Menu->AddItem(new BMenuItem("To MidiPort", msg)); + Field = new BMenuField(BRect(0, 0, 150, 20), NULL, NULL, Menu); + fOutputBox->SetLabel((BView*)Field); + + AddChild(fViewBox = new BBox(BRect(300, 0, 650, 350), "OutputBox")); //Width = 350, High = 350 + Menu = new BPopUpMenu("Select View"); + msg = new BMessage(VIEW_CHANGE_TO_NONE); + Menu->AddItem(new BMenuItem("None", msg)); + msg = new BMessage(VIEW_CHANGE_TO_SCOPE); + Menu->AddItem(new BMenuItem("Scope", msg)); + msg = new BMessage(VIEW_CHANGE_TO_ACTIVITY); + Menu->AddItem(new BMenuItem("Midi activity", msg)); + Field = new BMenuField(BRect(0, 0, 150, 20), NULL, NULL, Menu); + fViewBox->SetLabel((BView*)Field); + +} + +//---------------------------------------------------------- + +void MidiPlayerView::MessageReceived(BMessage *msg) +{ +BPopUpMenu *popupmenu = NULL; +BMenuField *Field = NULL; +Activity *view = NULL; + switch (msg->what) + { +//-------------- +//-------------- +//For The Input +//-------------- + case INPUT_CHANGE_TO_FILE : + RemoveAll(fInputBox); + fInputBox->AddChild(fInputStringView); + fInputBox->AddChild(new BButton(BRect(220, 20, 270, 40), NULL, "Select", new BMessage(CHANGE_INPUT_FILE))); + fInputBox->AddChild(new BButton(BRect(50, 140, 100, 160), NULL, "Rewind", new BMessage(REWIND_INPUT_FILE))); + fInputBox->AddChild(new BButton(BRect(110, 140, 160, 160), NULL, "Play", new BMessage(PLAY_INPUT_FILE))); + fInputBox->AddChild(new BButton(BRect(170, 140, 220, 160), NULL, "Pause", new BMessage(PAUSE_INPUT_FILE))); + break; +//-------------- + case INPUT_CHANGE_TO_MIDIPORT : + RemoveAll(fInputBox); + msg->FindPointer("Menu", (void**)&popupmenu); + fInputBox->AddChild(Field = new BMenuField(BRect(10, 25, 280, 45), NULL, "Selected", popupmenu)); + Field->SetDivider(60); + break; +//-------------- +//-------------- +//For the Output +//-------------- + case OUTPUT_CHANGE_TO_FILE : + RemoveAll(fOutputBox); + fOutputBox->AddChild(fOutputStringView); + fOutputBox->AddChild(new BButton(BRect(220, 20, 270, 40), NULL, "Select", new BMessage(CHANGE_OUTPUT_FILE))); + fOutputBox->AddChild(new BButton(BRect(50, 140, 100, 160), NULL, "Rewind", new BMessage(REWIND_OUTPUT_FILE))); + fOutputBox->AddChild(new BButton(BRect(170, 140, 220, 160), NULL, "Save", new BMessage(SAVE_OUTPUT_FILE))); + break; +//-------------- + case OUTPUT_CHANGE_TO_BEOS_SYNTH : + RemoveAll(fOutputBox); + SetBeOSSynthView(fOutputBox); + break; +//-------------- + case OUTPUT_CHANGE_TO_BEOS_SYNTH_FILE : + RemoveAll(fOutputBox); + fOutputBox->AddChild(fOutputStringView); + fOutputBox->AddChild(new BButton(BRect(220, 20, 270, 40), NULL, "Select", new BMessage(CHANGE_BEOS_SYNTH_FILE))); + fOutputBox->AddChild(new BButton(BRect(50, 140, 100, 160), NULL, "Rewind", new BMessage(REWIND_BEOS_SYNTH_FILE))); + fOutputBox->AddChild(new BButton(BRect(110, 140, 160, 160), NULL, "Play", new BMessage(PLAY_BEOS_SYNTH_FILE))); + fOutputBox->AddChild(new BButton(BRect(170, 140, 220, 160), NULL, "Pause", new BMessage(PAUSE_BEOS_SYNTH_FILE))); + SetBeOSSynthView(fOutputBox); + break; +//-------------- + case OUTPUT_CHANGE_TO_MIDIPORT : + RemoveAll(fOutputBox); + msg->FindPointer("Menu", (void**)&popupmenu); + fOutputBox->AddChild(Field = new BMenuField(BRect(10, 25, 280, 45), NULL, "Selected", popupmenu)); + Field->SetDivider(60); + break; +//-------------- +//-------------- +//For the display view +//-------------- + case VIEW_CHANGE_TO_NONE : + RemoveAll(fViewBox); + break; +//-------------- + case VIEW_CHANGE_TO_SCOPE : + RemoveAll(fViewBox); + fViewBox->AddChild(new Scope(BRect(10, 25, 340, 340))); + break; +//-------------- + case VIEW_CHANGE_TO_ACTIVITY : + RemoveAll(fViewBox); + msg->FindPointer("View", (void**)&view); + fViewBox->AddChild(view); + break; +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- + default: BView::MessageReceived(msg); + } +} + +//---------------------------------------------------------- + +BStringView *MidiPlayerView::GetInputStringView(void) +{ + return fInputStringView; +} + +//---------------------------------------------------------- + +BStringView *MidiPlayerView::GetOutputStringView(void) +{ + return fOutputStringView; +} + +//---------------------------------------------------------- + +void MidiPlayerView::RemoveAll(BView *aView) +{//Remove and delete all view from aView exept the first one an TheStringView (delete) +BView *Temp = NULL; + aView->Window()->Lock(); + Temp = aView->ChildAt(1); + while (Temp != NULL) + { + aView->RemoveChild(Temp); + if ((Temp != fInputStringView) && (Temp != fOutputStringView)) + delete Temp; + Temp = aView->ChildAt(1); + } + aView->Window()->Unlock(); +} + +//---------------------------------------------------------- + +void MidiPlayerView::SetBeOSSynthView(BView *aView) +{ +BPopUpMenu *Menu = NULL; +BMenuField *field = NULL; +BMessage *msg = NULL; +BMenuItem *item = NULL; +int32 temp = 0; + + Menu = new BPopUpMenu("Sample Rate"); + temp = be_synth->SamplingRate(); + msg = new BMessage(CHANGE_SAMPLE_RATE_SYNTH); + Menu->AddItem(item = new BMenuItem("11025 Hz", msg)); + if (temp == 11025) item->SetMarked(true); + msg = new BMessage(CHANGE_SAMPLE_RATE_SYNTH); + Menu->AddItem(item = new BMenuItem("22050 Hz", msg)); + if (temp == 22050) item->SetMarked(true); + msg = new BMessage(CHANGE_SAMPLE_RATE_SYNTH); + Menu->AddItem(item = new BMenuItem("44100 Hz", msg)); + if (temp == 44100) item->SetMarked(true); + field = new BMenuField(BRect(5, 50, 145, 70), NULL, "Sampling Rate", Menu); + aView->AddChild(field); + + Menu = new BPopUpMenu("Interpolation"); + temp = be_synth->Interpolation(); + msg = new BMessage(CHANGE_INTERPOLATION_TYPE_SYNTH); + Menu->AddItem(item = new BMenuItem("Drop", msg)); + if (temp == B_DROP_SAMPLE) item->SetMarked(true); + msg = new BMessage(CHANGE_INTERPOLATION_TYPE_SYNTH); + Menu->AddItem(item = new BMenuItem("2 points", msg)); + if (temp == B_2_POINT_INTERPOLATION) item->SetMarked(true); + msg = new BMessage(CHANGE_INTERPOLATION_TYPE_SYNTH); + Menu->AddItem(item = new BMenuItem("Linear", msg)); + if (temp == B_LINEAR_INTERPOLATION) item->SetMarked(true); + field = new BMenuField(BRect(145, 50, 285, 70), NULL, "Interpolation", Menu); + aView->AddChild(field); + + Menu = new BPopUpMenu("Reverb"); + temp = be_synth->Reverb(); + msg = new BMessage(CHANGE_REVERB_TYPE_SYNTH); + Menu->AddItem(item = new BMenuItem("None", msg)); + if (!be_synth->IsReverbEnabled()) + { + item->SetMarked(true); + temp = -1; + } + msg = new BMessage(CHANGE_REVERB_TYPE_SYNTH); + Menu->AddItem(item = new BMenuItem("Closet", msg)); + if (temp == B_REVERB_CLOSET) item->SetMarked(true); + msg = new BMessage(CHANGE_REVERB_TYPE_SYNTH); + Menu->AddItem(item = new BMenuItem("Garage", msg)); + if (temp == B_REVERB_GARAGE) item->SetMarked(true); + msg = new BMessage(CHANGE_REVERB_TYPE_SYNTH); + Menu->AddItem(item = new BMenuItem("Ballroom", msg)); + if (temp == B_REVERB_BALLROOM) item->SetMarked(true); + msg = new BMessage(CHANGE_REVERB_TYPE_SYNTH); + Menu->AddItem(item = new BMenuItem("Cavern", msg)); + if (temp == B_REVERB_CAVERN) item->SetMarked(true); + msg = new BMessage(CHANGE_REVERB_TYPE_SYNTH); + Menu->AddItem(item = new BMenuItem("Dungeon", msg)); + if (temp == B_REVERB_DUNGEON) item->SetMarked(true); + field = new BMenuField(BRect(5, 75, 145, 95), NULL, "Reverb", Menu); + aView->AddChild(field); + +BDirectory dir = BDirectory(BEOS_SYNTH_DIRECTORY); +entry_ref refs; + Menu = new BPopUpMenu("Standart File"); + while (dir.GetNextRef(&refs) != B_ENTRY_NOT_FOUND) + { + msg = new BMessage(CHANGE_FILE_SAMPLE_SYNTH); + Menu->AddItem(item = new BMenuItem(refs.name, msg)); + } + field = new BMenuField(BRect(145, 75, 285, 95), NULL, "File", Menu); + field->SetDivider(25); + aView->AddChild(field); + +BSlider *slider = new BSlider(BRect(5, 100, 275, 130), NULL, "Volume", + new BMessage(CHANGE_VOLUME_SYNTH), + 0, 1500, B_TRIANGLE_THUMB); + temp = (int32)(be_synth->SynthVolume() * be_synth->SampleVolume() * 1000); + slider->SetModificationMessage(new BMessage(CHANGE_VOLUME_SYNTH)); + slider->SetValue(temp); + slider->SetLimitLabels("Min", "Max"); + aView->AddChild(slider); +} + +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- diff --git a/src/tests/kits/midi/midi_player_replacement/MidiPlayerView.h b/src/tests/kits/midi/midi_player_replacement/MidiPlayerView.h new file mode 100644 index 0000000000..0e13f15a50 --- /dev/null +++ b/src/tests/kits/midi/midi_player_replacement/MidiPlayerView.h @@ -0,0 +1,104 @@ +/* +Author: Jerome LEVEQUE +Email: jerl1@caramail.com +*/ +#ifndef MIDI_PLAYER_VIEW_H +#define MIDI_PLAYER_VIEW_H + +#include +#include + +//---------------------------------------------------------- +#define INPUT_CHANGE_TO_FILE 'icfi' +#define INPUT_CHANGE_TO_MIDIPORT 'icmp' +//-------------- +#define OUTPUT_CHANGE_TO_FILE 'ocfi' +#define OUTPUT_CHANGE_TO_BEOS_SYNTH 'ocbs' +#define OUTPUT_CHANGE_TO_BEOS_SYNTH_FILE 'ocbf' +#define OUTPUT_CHANGE_TO_MIDIPORT 'ocmp' +//-------------- +#define VIEW_CHANGE_TO_NONE 'vcno' +#define VIEW_CHANGE_TO_SCOPE 'vcsc' +#define VIEW_CHANGE_TO_ACTIVITY 'vcta' +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +#define REWIND_INPUT_FILE 'reif' +#define PLAY_INPUT_FILE 'plif' +#define PAUSE_INPUT_FILE 'paif' +#define REWIND_OUTPUT_FILE 'reof' +#define SAVE_OUTPUT_FILE 'saof' +//-------------- +#define CHANGE_INPUT_FILE 'chif' +#define CHANGE_OUTPUT_FILE 'chof' +#define CHANGE_INPUT_MIDIPORT 'chim' +#define CHANGE_OUTPUT_MIDIPORT 'chom' +//-------------- +#define CHANGE_BEOS_SYNTH_FILE 'cbsf' +#define REWIND_BEOS_SYNTH_FILE 'rbsf' +#define PLAY_BEOS_SYNTH_FILE 'plsf' +#define PAUSE_BEOS_SYNTH_FILE 'pasf' +//-------------- +#define CHANGE_SAMPLE_RATE_SYNTH 'csrs' +#define CHANGE_INTERPOLATION_TYPE_SYNTH 'cits' +#define CHANGE_REVERB_TYPE_SYNTH 'crts' +#define CHANGE_FILE_SAMPLE_SYNTH 'cfss' +#define CHANGE_VOLUME_SYNTH 'cvos' +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +#define BEOS_SYNTH_DIRECTORY "/boot/beos/etc/synth/" +//-------------- + +//---------------------------------------------------------- + +class MidiPlayerView : public BView +{ +public: + MidiPlayerView(void); + ~MidiPlayerView(void); + + virtual void AttachedToWindow(void); + virtual void MessageReceived(BMessage *msg); + + BStringView *GetInputStringView(void); + BStringView *GetOutputStringView(void); + + void RemoveAll(BView *aView); + void SetBeOSSynthView(BView *aView); + +private: + BBox *fInputBox; + BBox *fOutputBox; + BBox *fViewBox; + + BStringView *fInputStringView; + BStringView *fOutputStringView; +}; + +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- + +#endif diff --git a/src/tests/kits/midi/midi_player_replacement/MidiPlayerWindow.cpp b/src/tests/kits/midi/midi_player_replacement/MidiPlayerWindow.cpp new file mode 100644 index 0000000000..49e1d7326c --- /dev/null +++ b/src/tests/kits/midi/midi_player_replacement/MidiPlayerWindow.cpp @@ -0,0 +1,648 @@ +/* +Author: Jerome LEVEQUE +Email: jerl1@caramail.com +*/ +#include "MidiPlayerWindow.h" +#include "MidiDelay.h" +#include "Activity.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//---------------------------------------------------------- + +class MidiPlayerApp : public BApplication +{ +public: + MidiPlayerApp(void) + : BApplication("application/x-vnd.MidiPlayer") + { + app_info info; + BFile file; + BResources resource; + size_t len; + GetAppInfo(&info); + if (file.SetTo(&(info.ref), B_READ_ONLY) != B_OK) return; + resource.SetTo(&file); + BPoint *origin = (BPoint*)resource.LoadResource('BPNT', "origin", &len); + fWindows = new MidiPlayerWindow(*origin); + } + +//-------------- + + void ReadyToRun(void) + { + fWindows->Show(); + } + +//-------------- + + void SetOrigin(BPoint origin) + { + app_info info; + BFile file; + BResources resource; + int32 temp; + GetAppInfo(&info); + if (file.SetTo(&(info.ref), B_READ_WRITE) != B_OK) return; + resource.SetTo(&file); + temp = resource.RemoveResource('BPNT', 1); + temp = resource.AddResource('BPNT', 1, &origin, sizeof(origin), "origin"); + } + +//-------------- + + virtual void RefsReceived(BMessage *message) + { + message->what = B_SIMPLE_DATA; + fWindows->PostMessage(message); + } + +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- + +private: + MidiPlayerWindow *fWindows; + +//-------------- + +}; + +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- + +MidiPlayerWindow::MidiPlayerWindow(BPoint start) + : BWindow(BRect(start, start + BPoint(660, 360)), "Midi Player", + B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS | B_NOT_RESIZABLE), + fMidiInput(NULL), + fMidiOutput(NULL), + fMidiDisplay(NULL), + fInputType(0), + fOutputType(0), + fDisplayType(0), + fInputFilePanel(NULL), + fOutputFilePanel(NULL), + fInputCurrentEvent(0), + fOutputCurrentEvent(0) +{ + AddChild(fStandartView = new MidiPlayerView()); + fMidiDelay = new MidiDelay(); +} + +//---------------------------------------------------------- + +MidiPlayerWindow::~MidiPlayerWindow(void) +{ + Disconnect(); + delete fMidiInput; + delete fMidiOutput; +} + +//---------------------------------------------------------- + +bool MidiPlayerWindow::QuitRequested(void) +{ + be_app->PostMessage(B_QUIT_REQUESTED); + return true; +} + +//---------------------------------------------------------- + +void MidiPlayerWindow::FrameMoved(BPoint origin) +{ + ((MidiPlayerApp*)be_app)->SetOrigin(origin); +} + +//---------------------------------------------------------- + +void MidiPlayerWindow::MessageReceived(BMessage *msg) +{ +uint32 temp = 0; +BPopUpMenu *MidiPortMenu = NULL; +BMenuItem *item = NULL; +BMessage message; +entry_ref ref; + switch (msg->what) + { +//-------------- +//For The Input +//-------------- +//-------------- + case INPUT_CHANGE_TO_FILE : + if (fInputType == FILE) + break; + fInputType = FILE; + Disconnect(); + delete fMidiInput; + fMidiInput = new BMidiStore(); + if (!fMidiInput) + { + (new BAlert(NULL, "Can't initialise a BMidiStore object", "OK"))->Go(); + break; + } + Connect(); + PostMessage(msg, fStandartView); + break; +//-------------- + case INPUT_CHANGE_TO_MIDIPORT : + if (fInputType == MIDIPORT) + break; + fInputType = MIDIPORT; + Disconnect(); + delete fMidiInput; + fMidiInput = new BMidiPort(); + if (!fMidiInput) + { + (new BAlert(NULL, "Can't initialise a BMidiPort object", "OK"))->Go(); + break; + } + MidiPortMenu = new BPopUpMenu("Midi Port"); + for(int i = ((BMidiPort*)fMidiInput)->CountDevices(); i > 0; i--) + { + char name[B_OS_NAME_LENGTH]; + ((BMidiPort*)fMidiInput)->GetDeviceName(i - 1, name); + MidiPortMenu->AddItem(new BMenuItem(name, new BMessage(CHANGE_INPUT_MIDIPORT))); + } + msg->AddPointer("Menu", MidiPortMenu); + Connect(); + PostMessage(msg, fStandartView); + break; +//-------------- +//For the Output +//-------------- +//-------------- + case OUTPUT_CHANGE_TO_FILE : + if (fOutputType == FILE) + break; + fOutputType = FILE; + Disconnect(); + delete fMidiOutput; + fMidiOutput = new BMidiStore(); + if (!fMidiOutput) + { + (new BAlert(NULL, "Can't initialise a BMidiStore object", "OK"))->Go(); + break; + } + Connect(); + PostMessage(msg, fStandartView); + break; +//-------------- + case OUTPUT_CHANGE_TO_BEOS_SYNTH : + if (fOutputType == BEOS_SYNTH) + break; + fOutputType = BEOS_SYNTH; + Disconnect(); + delete fMidiOutput; + fMidiOutput = new BMidiSynth(); + if (!fMidiOutput) + { + (new BAlert(NULL, "Can't initialise a BMidiSynth object", "OK"))->Go(); + break; + } + Connect(); + ((BMidiSynth*)fMidiOutput)->EnableInput(true, true); + PostMessage(msg, fStandartView); + break; +//-------------- + case OUTPUT_CHANGE_TO_BEOS_SYNTH_FILE : + if (fOutputType == BEOS_SYNTH_FILE) + break; + fOutputType = BEOS_SYNTH_FILE; + Disconnect(); + delete fMidiOutput; + fMidiOutput = new BMidiSynthFile(); + if (!fMidiOutput) + { + (new BAlert(NULL, "Can't initialise a BMidiSynth object", "OK"))->Go(); + break; + } + Connect(); + ((BMidiSynthFile*)fMidiOutput)->EnableInput(true, true); + PostMessage(msg, fStandartView); + break; +//-------------- + case OUTPUT_CHANGE_TO_MIDIPORT : + if (fOutputType == MIDIPORT) + break; + fOutputType = MIDIPORT; + Disconnect(); + delete fMidiOutput; + fMidiOutput = new BMidiPort(); + if (!fMidiOutput) + { + (new BAlert(NULL, "Can't initialise a BMidiPort object", "OK"))->Go(); + break; + } + MidiPortMenu = new BPopUpMenu("Midi Port"); + for(int i = ((BMidiPort*)fMidiOutput)->CountDevices(); i > 0; i--) + { + char name[B_OS_NAME_LENGTH]; + ((BMidiPort*)fMidiOutput)->GetDeviceName(i - 1, name); + MidiPortMenu->AddItem(new BMenuItem(name, new BMessage(CHANGE_OUTPUT_MIDIPORT))); + } + msg->AddPointer("Menu", MidiPortMenu); + Connect(); + PostMessage(msg, fStandartView); + break; +//-------------- +//For the display view +//-------------- +//-------------- + case VIEW_CHANGE_TO_NONE : + if (fDisplayType == 0) + break; + fDisplayType = 0; + if (fMidiDisplay != NULL) + fMidiDelay->Disconnect(fMidiDisplay); //Object will be deleted in MidiPlayerView::RemoveAll + PostMessage(msg, fStandartView); + break; +//-------------- + case VIEW_CHANGE_TO_SCOPE : + if (fDisplayType == SCOPE) + break; + fDisplayType = SCOPE; + PostMessage(msg, fStandartView); + break; +//-------------- + case VIEW_CHANGE_TO_ACTIVITY : + if (fDisplayType == ACTIVITY) + break; + fDisplayType = ACTIVITY; + fMidiDisplay = (BMidi*)new Activity(BRect(10, 25, 340, 340)); + fMidiDelay->Connect(fMidiDisplay); + ((Activity*)fMidiDisplay)->Start(); + msg->AddPointer("View", fMidiDisplay); + PostMessage(msg, fStandartView); + break; +//-------------- +//-------------- +//Message from Input file +//-------------- + case CHANGE_INPUT_FILE : + if (fInputFilePanel) + { + entry_ref File; + if (msg->FindRef("refs", &File) != B_OK) + break; + Disconnect(); + delete fMidiInput; + fMidiInput = new BMidiStore(); + if (!fMidiInput) + { + (new BAlert(NULL, "Can't initialise a BMidiPort object", "OK"))->Go(); + return; + } + Connect(); + if (((BMidiStore*)fMidiInput)->Import(&File) == B_OK) + { + BStringView *aStringView = fStandartView->GetInputStringView(); + aStringView->SetText(File.name); + } + delete fInputFilePanel; + fInputFilePanel = NULL; + } + else + { + fInputFilePanel = new BFilePanel(B_OPEN_PANEL, new BMessenger(this), NULL, B_FILE_NODE, false, msg); + fInputFilePanel->Show(); + } + break; +//-------------- + case REWIND_INPUT_FILE : + ((BMidiStore*)fMidiInput)->Stop(); + if (fMidiOutput) fMidiOutput->AllNotesOff(); + fInputCurrentEvent = 0; + return; +//-------------- + case PLAY_INPUT_FILE : + ((BMidiStore*)fMidiInput)->SetCurrentEvent(fInputCurrentEvent); + ((BMidiStore*)fMidiInput)->Start(); + break; +//-------------- + case PAUSE_INPUT_FILE : + fInputCurrentEvent = ((BMidiStore*)fMidiInput)->CurrentEvent(); + ((BMidiStore*)fMidiInput)->Stop(); + if (fMidiOutput) fMidiOutput->AllNotesOff(); + break; +//-------------- +//-------------- +//Message from Output file +//-------------- + case CHANGE_OUTPUT_FILE : + if (fOutputFilePanel) + { + const char *filename; + msg->FindRef("directory", &fOutputFile); + msg->FindString("name", &filename); + BDirectory path(&fOutputFile); + BFile fichier(&path, filename, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); + if (fichier.InitCheck() == B_OK) + { + BStringView *aStringView = fStandartView->GetOutputStringView(); + BEntry entry(&path, filename); + entry.GetRef(&fOutputFile); + aStringView->SetText(fOutputFile.name); + } + else + { + (new BAlert(NULL, "Can't Create File", "OK"))->Go(); + } + delete fOutputFilePanel; + fOutputFilePanel = NULL; + } + else + { + fOutputFilePanel = new BFilePanel(B_SAVE_PANEL, new BMessenger(this), NULL, B_FILE_NODE, false, msg); + fOutputFilePanel->Show(); + } + break; +//-------------- + case REWIND_OUTPUT_FILE : + Disconnect(); + delete fMidiOutput; + fMidiOutput = new BMidiPort(); + if (!fMidiOutput) + { + (new BAlert(NULL, "Can't initialise a BMidiPort object", "OK"))->Go(); + return; + } + Connect(); + fOutputCurrentEvent = 0; + return; +//-------------- + case SAVE_OUTPUT_FILE : + ((BMidiStore*)fMidiOutput)->Export(&fOutputFile, 0); + break; +//-------------- +//-------------- +//Message from the input Midiport +//-------------- + case CHANGE_INPUT_MIDIPORT : + if (msg->FindPointer("source", (void**)&item) == B_OK) + { + ((BMidiPort*)fMidiInput)->Open(item->Label()); + ((BMidiPort*)fMidiInput)->Start(); + } + break; +//-------------- +//-------------- +//Message from the output Midiport +//-------------- + case CHANGE_OUTPUT_MIDIPORT : + if (msg->FindPointer("source", (void**)&item) == B_OK) + { + ((BMidiPort*)fMidiOutput)->Open(item->Label()); + ((BMidiPort*)fMidiOutput)->Start(); + } + break; +//-------------- +//-------------- +//Message from the BeOS Synth +//-------------- + case CHANGE_BEOS_SYNTH_FILE: + if (fOutputFilePanel) + { + msg->FindRef("refs", &fOutputFile); + ((BMidiSynthFile*)fMidiOutput)->UnloadFile(); + if (((BMidiSynthFile*)fMidiOutput)->LoadFile(&fOutputFile) == B_OK) + { + BStringView *aStringView = fStandartView->GetOutputStringView(); + aStringView->SetText(fOutputFile.name); + } + delete fOutputFilePanel; + fOutputFilePanel = NULL; + } + else + { + fOutputFilePanel = new BFilePanel(B_OPEN_PANEL, new BMessenger(this), NULL, B_FILE_NODE, false, msg); + fOutputFilePanel->Show(); + } + break; +//-------------- + case REWIND_BEOS_SYNTH_FILE : + ((BMidiSynthFile*)fMidiOutput)->Stop(); + fOutputCurrentEvent = 0; + return; +//-------------- + case PLAY_BEOS_SYNTH_FILE : + if (fOutputCurrentEvent == 1) + ((BMidiSynthFile*)fMidiOutput)->Resume(); + else + ((BMidiSynthFile*)fMidiOutput)->Start(); + fOutputCurrentEvent = 0; + break; +//-------------- + case PAUSE_BEOS_SYNTH_FILE : + fOutputCurrentEvent = 1; + ((BMidiSynthFile*)fMidiOutput)->Pause(); + break; +//-------------- + case CHANGE_SAMPLE_RATE_SYNTH : + msg->FindInt32("index", (int32*)&temp); + switch(temp) + { + case 0 : be_synth->SetSamplingRate(11025); break; + case 1 : be_synth->SetSamplingRate(22050); break; + case 2 : be_synth->SetSamplingRate(44100); break; + } + break; +//-------------- + case CHANGE_INTERPOLATION_TYPE_SYNTH : + msg->FindInt32("index", (int32*)&temp); + switch(temp) + { + case 0 : be_synth->SetInterpolation(B_DROP_SAMPLE); break; + case 1 : be_synth->SetInterpolation(B_2_POINT_INTERPOLATION); break; + case 2 : be_synth->SetInterpolation(B_LINEAR_INTERPOLATION); break; + } + break; +//-------------- + case CHANGE_REVERB_TYPE_SYNTH : + msg->FindInt32("index", (int32*)&temp); + switch(temp) + { + case 0 : + be_synth->EnableReverb(false); + break; + case 1 : + be_synth->EnableReverb(true); + be_synth->SetReverb(B_REVERB_CLOSET); + break; + case 2 : + be_synth->EnableReverb(true); + be_synth->SetReverb(B_REVERB_GARAGE); + break; + case 3 : + be_synth->EnableReverb(true); + be_synth->SetReverb(B_REVERB_BALLROOM); + break; + case 4 : + be_synth->EnableReverb(true); + be_synth->SetReverb(B_REVERB_CAVERN); + break; + case 5 : + be_synth->EnableReverb(true); + be_synth->SetReverb(B_REVERB_DUNGEON); + break; + } + break; +//-------------- + case CHANGE_FILE_SAMPLE_SYNTH : + if (msg->FindPointer("source", (void**)&item) == B_OK) + { + BString path = BString(BEOS_SYNTH_DIRECTORY); + path += item->Label(); + BEntry entry = BEntry(path.String()); + if (entry.InitCheck() == B_OK) + { + entry_ref ref; + be_synth->Unload(); + entry.GetRef(&ref); + be_synth->LoadSynthData(&ref); + ((BMidiSynth*)fMidiOutput)->EnableInput(true, true); + if (!be_synth->IsLoaded()) + { + (new BAlert(NULL, "Instrument File can't be loaded correctly", "OK"))->Go(); + } + ((BMidiSynthFile*)fMidiOutput)->LoadFile(&fOutputFile); + ((BMidiSynthFile*)fMidiOutput)->Start(); + } + else + { + (new BAlert(NULL, "Can't initialise instrument File", "OK"))->Go(); + } + } + break; +//-------------- + case CHANGE_VOLUME_SYNTH : + msg->FindInt32("be:value", (int32*)&temp); + be_synth->SetSynthVolume(temp / 1000.0); + break; +//-------------- +//-------------- +//For the drag and drop function +//-------------- + case B_SIMPLE_DATA : //A file had been dropped into application + if (msg->FindRef("refs", &ref) == B_OK) + { + message = BMessage(INPUT_CHANGE_TO_FILE); + PostMessage(&message); + message = BMessage(*msg); + message.what = CHANGE_INPUT_FILE; + fInputFilePanel = fInputFilePanel = new BFilePanel(B_OPEN_PANEL, new BMessenger(this), NULL, B_FILE_NODE, false, msg);; + PostMessage(&message); + message = BMessage(OUTPUT_CHANGE_TO_BEOS_SYNTH); + PostMessage(&message); + message = BMessage(PLAY_INPUT_FILE); + PostMessage(&message); + } + break; +//-------------- + case B_CANCEL : + msg->FindInt32("old_what", (int32*)&temp); + if (temp == CHANGE_INPUT_FILE) + { + delete fInputFilePanel; + fInputFilePanel = NULL; + } + if (temp == CHANGE_OUTPUT_FILE) + { + delete fOutputFilePanel; + fOutputFilePanel = NULL; + } + break; +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- +//-------------- + default : BWindow::MessageReceived(msg); + } +} + + +//---------------------------------------------------------- + +void MidiPlayerWindow::Disconnect(void) +{//This function must be rewrited for a better disconnection + if (fMidiInput != NULL) + { + fMidiInput->AllNotesOff(false); + fMidiInput->Disconnect(fMidiDelay); + } + if (fMidiOutput != NULL) + { + fMidiOutput->AllNotesOff(false); + fMidiDelay->Disconnect(fMidiOutput); + } +} + +//---------------------------------------------------------- + +void MidiPlayerWindow::Connect(void) +{//This function must be rewrited for a better connection + if (fMidiInput != NULL) + fMidiInput->Connect(fMidiDelay); + if (fMidiOutput != NULL) + fMidiDelay->Connect(fMidiOutput); +} + +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- + +int main(int, char**) +{ + MidiPlayerApp *App = new MidiPlayerApp(); + App->Run(); + delete App; + return B_NO_ERROR; +}; + +//---------------------------------------------------------- diff --git a/src/tests/kits/midi/midi_player_replacement/MidiPlayerWindow.h b/src/tests/kits/midi/midi_player_replacement/MidiPlayerWindow.h new file mode 100644 index 0000000000..2ebac5638c --- /dev/null +++ b/src/tests/kits/midi/midi_player_replacement/MidiPlayerWindow.h @@ -0,0 +1,75 @@ +/* +Author: Jerome LEVEQUE +Email: jerl1@caramail.com +*/ +#ifndef MIDI_PLAYER_WINDOW_H +#define MIDI_PLAYER_WINDOW_H + +#include "MidiPlayerView.h" + +#include +#include +#include + +//---------------------------------------------------------- +#define FILE 'file' +#define BEOS_SYNTH 'besy' +#define BEOS_SYNTH_FILE 'besf' +#define MIDIPORT 'mipo' +//-------------- +#define SCOPE 'scop' +#define ACTIVITY 'actv' +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- + +class MidiPlayerWindow : public BWindow +{ +public: + MidiPlayerWindow(BPoint start); + ~MidiPlayerWindow(void); + + virtual bool QuitRequested(void); + virtual void FrameMoved(BPoint origin); + virtual void MessageReceived(BMessage *msg); + + virtual void Disconnect(void); + virtual void Connect(void); + +private: + MidiPlayerView *fStandartView; + + BMidi *fMidiInput; + BMidi *fMidiOutput; + BMidi *fMidiDisplay; + BMidi *fMidiDelay; + + uint32 fInputType; + uint32 fOutputType; + uint32 fDisplayType; + + BFilePanel *fInputFilePanel; + BFilePanel *fOutputFilePanel; + + entry_ref fOutputFile; + + uint32 fInputCurrentEvent; + uint32 fOutputCurrentEvent; +}; + +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +//---------------------------------------------------------- +#endif diff --git a/src/tests/kits/midi/midi_player_replacement/Scope.cpp b/src/tests/kits/midi/midi_player_replacement/Scope.cpp new file mode 100644 index 0000000000..82a51919d4 --- /dev/null +++ b/src/tests/kits/midi/midi_player_replacement/Scope.cpp @@ -0,0 +1,100 @@ +/* +Author: Michael Pfeiffer +Email: michael.pfeiffer@utanet.at +*/ +#include "Scope.h" + +#include +#include +#include +#include + +//---------------------------------------------------------- + +Scope::Scope(BRect rect) : + BView(rect, NULL, + B_FOLLOW_LEFT | B_FOLLOW_TOP, + B_WILL_DRAW | B_PULSE_NEEDED) { + SetViewColor(B_TRANSPARENT_COLOR); + + mWidth = (int) rect.Width(); mHeight = (int)rect.Height(); + mSampleCount = mWidth; + mLeft = new int16[mSampleCount]; mRight = new int16[mSampleCount]; + + mBitmap = new BBitmap(BRect(0, 0, mWidth, mHeight), B_RGB_16_BIT, true, true); + if (mBitmap->Lock()) { + mOffscreenView = new BView(mBitmap->Bounds(), NULL, B_FOLLOW_NONE, B_WILL_DRAW); + mOffscreenView->SetHighColor(0, 0, 0, 0); + + mBitmap->AddChild(mOffscreenView); + mOffscreenView->FillRect(mBitmap->Bounds()); + mOffscreenView->Sync(); + mBitmap->Unlock(); + } +} + +//---------------------------------------------------------- + +void Scope::Draw(BRect updateRect) { + DrawBitmap(mBitmap, BPoint(0, 0)); +} + +//---------------------------------------------------------- + +void Scope::DrawSample() { + int32 size = be_synth->GetAudio(mLeft, mRight, mSampleCount); + + if (mBitmap->Lock()) { + mOffscreenView->SetHighColor(0, 0, 0, 0); + mOffscreenView->FillRect(mBitmap->Bounds()); + if (size > 0) { + mOffscreenView->SetHighColor(255, 0, 0, 0); + mOffscreenView->SetLowColor(0, 255, 0, 0); + #define N 16 + int32 x, y, sx = 0, f = (mHeight << N) / 65535, dy = mHeight / 2; + for (int32 i = 0; i < mWidth; i++) { + x = sx / mWidth; + y = ((mLeft[x] * f) >> N) + dy; + mOffscreenView->FillRect(BRect(i, y, i, y)); + y = ((mRight[x] * f) >> N) + dy; + mOffscreenView->FillRect(BRect(i, y, i, y), B_SOLID_LOW); + sx += size; + } + } + mOffscreenView->Flush(); + mBitmap->Unlock(); + } +} + +//---------------------------------------------------------- + +#define PULSE_RATE 1 * 100000 +void Scope::AttachedToWindow(void) { + Window()->SetPulseRate(PULSE_RATE); +} + +//---------------------------------------------------------- + +void Scope::DetachedFromWindow(void) { + Window()->SetPulseRate(0); + delete mLeft; delete mRight; + + if (mBitmap->Lock()) { + mBitmap->RemoveChild(mOffscreenView); + delete mOffscreenView; + mBitmap->Unlock(); + } + delete mBitmap; +} + +//---------------------------------------------------------- + +void Scope::Pulse() { + DrawSample(); + BMessage *m; + BMessageQueue *mq = Window()->MessageQueue(); + int i = 0; + while ((m = mq->FindMessage(B_PULSE, 0)) != NULL) mq->RemoveMessage(m), i++; + Invalidate(); +} +//---------------------------------------------------------- diff --git a/src/tests/kits/midi/midi_player_replacement/Scope.h b/src/tests/kits/midi/midi_player_replacement/Scope.h new file mode 100644 index 0000000000..d3bf7f373f --- /dev/null +++ b/src/tests/kits/midi/midi_player_replacement/Scope.h @@ -0,0 +1,27 @@ +/* +Author: Michael Pfeiffer +Email: michael.pfeiffer@utanet.at +*/ +#ifndef SCOPE_H +#define SCOPE_H + +#include + +class Scope : public BView { + BBitmap *mBitmap; + BView *mOffscreenView; + int mWidth, mHeight; + int32 mSampleCount; + int16 *mLeft, *mRight; +public: + Scope(BRect rect); + + void Draw(BRect updateRect); + void DrawSample(); + + void Pulse(); + void AttachedToWindow(void); + void DetachedFromWindow(void); +}; + +#endif \ No newline at end of file diff --git a/src/tests/kits/midi/synth_file_reader/SynthFileFormat.txt b/src/tests/kits/midi/synth_file_reader/SynthFileFormat.txt new file mode 100644 index 0000000000..0926816e7e --- /dev/null +++ b/src/tests/kits/midi/synth_file_reader/SynthFileFormat.txt @@ -0,0 +1,36 @@ +Synth File Format +================= + +Currently (*.sy) only! + +'IREZ' | version?[4] | no_of_chunks[4] | chunks[no_of_chungs] + +chunks: +------- +next[4] | tag[4] + +tag: +---- +'INST' | instr[4] | nameLen[1] | name[nameLen] | dataSize[4] | data[dataSize] +| sndId[2] | ???[10] | size[2] | ???[size*8+21] | rest[dataSize-...] | + +'snd ' | sndId[4] | nameLen[1] | name[nameLen] | dataSize[4] | [28] | +rate[2] | ... + +data[dataSize]: +---------------- +ADSR | [1] | [4] | [4] | +LINE | [4] | [4] | +SUST | [4] | [4] | +LAST | [4] | +LPGF | [4] | [4] | [4] | +SINE | [4] | [4] | +LPFR | +LPRE | [1] | [4] | [4] | +PITC | [1] | [4] | [4] | +LPAM | [1] | [4] | [4] | +VOLU | [1] | [4] | [4] | +SPAN | [1] | [4] | [4] | +TRIA | [4] | [4] | +SQU2 | [8] | +SQUA | [8] | \ No newline at end of file diff --git a/src/tests/kits/midi/synth_file_reader/SynthFileReader.cpp b/src/tests/kits/midi/synth_file_reader/SynthFileReader.cpp new file mode 100644 index 0000000000..53d55278ff --- /dev/null +++ b/src/tests/kits/midi/synth_file_reader/SynthFileReader.cpp @@ -0,0 +1,317 @@ +/* + +SynthFileReader.cpp + +Copyright (c) 2002 OpenBeOS. + + +Author: + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#include "SynthFileReader.h" +#include +#include + +#define DEBUG 1 +#include + +SynthFileReader::SynthFileReader(const char* synthFile) { + fFile = fopen(synthFile, "r+b"); + tag tag; + if (fFile) { + if (Read(tag) && TagEquals(tag, "IREZ")) { + return; + } + fclose(fFile); fFile = NULL; + } + +} + +SynthFileReader::~SynthFileReader() { + if (fFile) { + fclose(fFile); fFile = NULL; + } +} + +bool SynthFileReader::InitCheck() const { + return fFile != NULL; +} + +bool SynthFileReader::TagEquals(const char* tag1, const char* tag2) const { + return strncmp(tag1, tag2, 4) == 0; +} + +bool SynthFileReader::Read(void* data, uint32 size) { + return 1 == fread(data, size, 1, fFile); +} + +bool SynthFileReader::Read(tag &tag) { + return Read((void*)tag, sizeof(tag)); +} + +bool SynthFileReader::Read(uint64 &n, uint32 size) { + uint8 number[8]; + ASSERT(size <= sizeof(number)); + if (Read((void*)number, size)) { + n = 0; + for (unsigned int i = 0; i < size; i ++) { + n <<= 8; + n += number[i]; + } + return true; + } + return false; +} + +bool SynthFileReader::Read(uint32 &n) { + uint64 num; + bool ok = Read(num, 4); + n = num; + return ok; +} + + +bool SynthFileReader::Read(uint16 &n) { + uint64 num; + bool ok = Read(num, 2); + n = num; + return ok; +} + + +bool SynthFileReader::Read(uint8 &n) { + return Read((void*)&n, 1); +} + +bool SynthFileReader::Read(BString& s, uint32 len) { + char* str = s.LockBuffer(len+1); + str[len] = 0; + bool ok = Read((void*)str, len); + s.UnlockBuffer(len+1); + return ok; +} + +bool SynthFileReader::Skip(uint32 bytes) { + fseek(fFile, bytes, SEEK_CUR); + return true; +} + +// debugging +void SynthFileReader::Print(tag tag) { + printf("%.*s", 4, tag); +} + + +void SynthFileReader::Dump(uint32 bytes) { + uint8 byte; + int col = 0; + const int cols = 16; + bool first = true; + long start = ftell(fFile); + + for (;bytes > 0 && Read(byte); bytes --, col = (col + 1) % cols) { + if (col == 0) { + if (first) first = false; + else printf("\n"); + printf("%6.6lx(%3.3lx) ", ftell(fFile)-1, ftell(fFile)-start-1); + } + printf("%2.2x ", (uint)byte); + if (isprint(byte)) printf("'%c' ", (char)byte); + else printf(" "); + } +} + +void SynthFileReader::Dump(bool play, uint32 instrOnly) { + tag tag; + uint32 version; + uint32 nEntries; + uint32 next; + uint32 cur; + + printf("SynthFileReader::Dump\n"); + printf("=================\n\n"); + + // read header + fseek(fFile, 0, SEEK_SET); + Read(tag); ASSERT(TagEquals(tag, "IREZ")); + if (Read(version) && Read(nEntries)) { + printf("version= %ld entries= %ld\n", version, nEntries); + + // dump rest of file +// for (uint32 i = 0; i < nEntries; i++) { + while (Read(next)) { + printf("next=%lx cur=%lx ", next, cur); + cur = ftell(fFile); + if (Read(tag)) { + Print(tag); + if (TagEquals(tag, "INST")) { + uint32 inst; + uint8 len; + BString name; + uint32 size; + + if (Read(inst) && Read(len) && Read(name, len) && Read(size)) { + uint32 rest = size; + printf(" inst=%d '%s' size=%lx", (int)inst, name.String(), size); + + printf("\n"); Dump(12); printf("\n"); + rest -= 10; + + uint16 elems; + Read(elems); + rest -= 4; + + printf("elems = %ld\n", elems); + + if (elems > 0 || rest >= 16) { + Dump(elems * 8 + 21); printf("\n"); + + rest -= elems * 8 + 21; + } else { + printf("rest %ld\n", rest); + Dump(rest); + rest = 0; + } + + bool prev_was_sust = false; + while (rest > 0) { + Read(tag); rest -= 4; + Print(tag); printf("\n"); + int s = 0; + if (TagEquals(tag, "ADSR")) { + s = 1+4+4; + } else if (TagEquals(tag, "LINE")) { + s = 8; + } else if (TagEquals(tag, "SUST")) { + s = 8; + } else if (TagEquals(tag, "LAST")) { + s = 0; + if (rest > 0) { + SynthFileReader::tag tag2; + long pos = ftell(fFile); + Read(tag2); + fseek(fFile, pos, SEEK_SET); + if (!isalpha(tag2[0])) { + s = 4; + } + } + } else if (TagEquals(tag, "LPGF")) { + s = 12; + } else if (TagEquals(tag, "LPFR")) { + s = 9; + } else if (TagEquals(tag, "SINE")) { + s = 8; + } else if (TagEquals(tag, "LPRE")) { + s = 9; + } else if (TagEquals(tag, "PITC")) { + s = 9; + } else if (TagEquals(tag, "LPAM")) { + s = 9; + } else if (TagEquals(tag, "VOLU")) { + s = 9; + } else if (TagEquals(tag, "SPAN")) { + s = 9; + } else if (TagEquals(tag, "TRIA")) { + s = 8; + } else if (TagEquals(tag, "SQU2")) { + s = 8; + } else if (TagEquals(tag, "SQUA")) { + s = 8; + // Patches*.hsb + } else if (TagEquals(tag, "CURV")) { + s = 0; + } else { + // ASSERT(false); + printf("unknown tag "); Print(tag); printf("\n"); + // ASSERT(false); + break; + } + prev_was_sust = TagEquals(tag, "SUST"); + Dump(s); printf("\n"); + if (rest < s) { + printf("wrong size: rest=%ld size= %d\n", rest, s); + break; + } + rest -= s; + } + if (rest > 0) { + printf("Rest:\n"); + Dump(rest); printf("\n"); + } + } + } else if (TagEquals(tag, "snd ")) { + uint32 inst; + uint8 len; + BString name; + uint32 size; + + if (Read(inst) && Read(len) && Read(name, len) && Read(size)) { + printf(" inst=%lx '%s' size=%lx\n", inst, name.String(), size); + uint32 rest = size; + Dump(28); printf("\n"); rest -= 28; + uint16 rate; + Read(rate); rest -= 2; + printf("rate=%d\n", (int)rate); + Dump(16*3+7); printf("\n"); rest -= 16*3+7; + printf("size=%ld offsetToNext=%ld\n", size, next-cur); + if (play && (instrOnly==0xffff || instrOnly == inst)) Play(rate, 0, rest); + } + } + printf("\n"); + } else { + exit(-1); + } + fseek(fFile, next, SEEK_SET); + } + } else { + printf("Could not read header\n"); + } +} + +#include +#include + +void SynthFileReader::Play(uint16 rate, uint32 offset, uint32 size) { + uint8* samples = new uint8[size]; + fseek(fFile, offset, SEEK_CUR); + Read((void*)samples, size); + + BSimpleGameSound* s; + gs_audio_format format = { + rate, + 1, + gs_audio_format::B_GS_S16, + 2, + 0 + }; + s = new BSimpleGameSound((void*)samples, size/2, &format); + if (s->InitCheck() == B_OK) { + s->StartPlaying(); + s->SetIsLooping(true); + printf("hit enter "); while (getchar() != '\n'); + s->StopPlaying(); + } else { + printf("Could not initialize BSimpleGameSound!\n"); + } + delete s; +} diff --git a/src/tests/kits/midi/synth_file_reader/SynthFileReader.h b/src/tests/kits/midi/synth_file_reader/SynthFileReader.h new file mode 100644 index 0000000000..3f4ea9488f --- /dev/null +++ b/src/tests/kits/midi/synth_file_reader/SynthFileReader.h @@ -0,0 +1,65 @@ +/* + +SynthFileReader.h + +Copyright (c) 2002 OpenBeOS. + +Author: + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef _SYNTH_FILE_READER_H +#define _SYNTH_FILE_READER_H + +#include +#include +#include + +class SynthFileReader { + FILE* fFile; + + typedef char tag[4]; + + bool TagEquals(const char* tag1, const char* tag2) const; + bool Read(void* data, uint32 size); + bool Read(BString& s, uint32 size); + bool Read(tag &tag); + bool Read(uint64 &n, uint32 size); + bool Read(uint32 &n); + bool Read(uint16 &n); + bool Read(uint8 &n); + bool Skip(uint32 bytes); + + // debugging support + void Print(tag tag); + void Dump(uint32 bytes); + void Play(uint16 rate, uint32 offset, uint32 size); + +public: + SynthFileReader(const char* synthFile); + ~SynthFileReader(); + bool InitCheck() const; + + void Dump(bool play, uint32 instrOnly); +}; + +#endif diff --git a/src/tests/kits/midi/synth_file_reader/main.cpp b/src/tests/kits/midi/synth_file_reader/main.cpp new file mode 100644 index 0000000000..40dc8a1d8f --- /dev/null +++ b/src/tests/kits/midi/synth_file_reader/main.cpp @@ -0,0 +1,55 @@ +/* + +main.cpp + +Copyright (c) 2002 OpenBeOS. + +Author: + Michael Pfeiffer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#include "SynthFileReader.h" +#include +#include + + +void start_be_app() { + new BApplication("application/x.vnd-synth-file-reader"); +} + +int main(int argc, char* argv[]) { + if (argc < 2) { + printf("%s [play [instr]]\n", argv[0]); + return -1; + } + const char* fileName = argv[1]; + bool play = argc >= 3 ? strcmp(argv[2], "play") == 0 : false; + uint32 instr = argc >= 4 ? atol(argv[3]) : 0xffff; + + SynthFileReader reader(fileName); + if (reader.InitCheck()) { + start_be_app(); + reader.Dump(play, instr); + } else { + printf("could not open '%s' or not a valid synth file!\n", fileName); + } +} \ No newline at end of file diff --git a/src/tests/kits/midi/test1.cpp b/src/tests/kits/midi/test1.cpp new file mode 100644 index 0000000000..e908feada5 --- /dev/null +++ b/src/tests/kits/midi/test1.cpp @@ -0,0 +1,37 @@ +#include +#include +#include +#include + +int main(int argc, char * argv[]) { + if(argc < 2) { + cerr << "Must supply a filename (*.mid)!" << endl; + return 1; + } + BMidiText * text = new BMidiText(); + BMidiStore * store = new BMidiStore(); + BEntry entry(argv[1],true); + if(!entry.Exists()) { + cerr << "File does not exist." << endl; + return 2; + } + entry_ref e_ref; + entry.GetRef(&e_ref); + store->Import(&e_ref); + store->Connect(text); + uint32 start_time = B_NOW; + store->Start(); + while(store->IsRunning()) { + snooze(100000); + } + store->Stop(); + uint32 stop_time = B_NOW; + cout << "Start Time: " << dec << start_time << "ms" << endl; + cout << "Stop Time: " << dec << stop_time << "ms" << endl; + cout << "Total time: " << dec << stop_time - start_time << "ms" << endl; + + store->Disconnect(text); + delete store; + delete text; + return 0; +} \ No newline at end of file diff --git a/src/tests/kits/net/at_client.c b/src/tests/kits/net/at_client.c new file mode 100644 index 0000000000..24deb9ee0a --- /dev/null +++ b/src/tests/kits/net/at_client.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include + +#include "sys/socket.h" +#include "netinet/in.h" +#include "arpa/inet.h" +#include "sys/select.h" +#include "sys/sockio.h" + +#include "ufunc.h" + +#define PORT 7772 +#define HELLO_MSG "Hello from the server" + +int main(int argc, char **argv) +{ + int sock = socket(AF_INET, SOCK_STREAM, 0); + struct sockaddr_in sin; + int salen = sizeof(sin); + int rv, on = 1; + char buffer[50]; + + test_banner("Accept Test - Client"); + + ioctl(sock, FIONBIO, &on); + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = 0; + sin.sin_len = salen; + sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + rv = bind(sock, (const struct sockaddr*)&sin, salen); + if (rv < 0) + err(rv, "bind"); + printf("Bound\n"); + + sin.sin_port = htons(PORT); + + do { + rv = connect(sock, (const struct sockaddr*)&sin, salen); + } while (rv < 0 && errno == EINPROGRESS); + if (rv < 0 && errno != EISCONN) + err(errno, "connect"); + printf("connected!\n"); + + do { + rv = read(sock, buffer, 50); + } while (rv < 0 && errno == EWOULDBLOCK); + if (rv < 0) + err(rv, "read"); + printf("%s\n", buffer); + + close(sock); + + return (0); +} + + diff --git a/src/tests/kits/net/at_srv.c b/src/tests/kits/net/at_srv.c new file mode 100644 index 0000000000..1fb2f2162e --- /dev/null +++ b/src/tests/kits/net/at_srv.c @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include + +#include "sys/socket.h" +#include "netinet/in.h" +#include "arpa/inet.h" +#include "sys/select.h" + +#include "ufunc.h" + +#define PORT 7772 +#define HELLO_MSG "Hello from the server" +#define RESPONSE_MSG "Hello from the client!" + +int main(int argc, char **argv) +{ + int sock = socket(AF_INET, SOCK_STREAM, 0); + struct sockaddr_in sin; + int salen = sizeof(sin); + int rv, on = 1; + int newsock; + char buffer[50]; + + test_banner("Accept Test - Server"); + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = htons(PORT); + sin.sin_len = salen; + sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + rv = bind(sock, (const struct sockaddr*)&sin, salen); + if (rv < 0) + err(rv, "bind"); + printf("Bound\n"); + + rv = listen(sock, 5); + if (rv < 0) + err(rv, "listen"); + printf("Listening\n"); + + newsock = accept(sock, (struct sockaddr*)&sin, &salen); + if (newsock < 0) + err(newsock, "accept"); + printf("Accepted socket %d\n", newsock); + + rv = write(newsock, HELLO_MSG, strlen(HELLO_MSG)); + if (rv < 0) + err(rv, "write"); + printf("Written hello\n"); + + close(newsock); + close(sock); + + return (0); +} + + diff --git a/src/tests/kits/net/select_test.c b/src/tests/kits/net/select_test.c new file mode 100644 index 0000000000..15ab3977f7 --- /dev/null +++ b/src/tests/kits/net/select_test.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include + +#include "sys/socket.h" +#include "netinet/in.h" +#include "arpa/inet.h" +#include "sys/select.h" + +#include "ufunc.h" + +int main(int argc, char **argv) +{ + int s; + int rv; + struct fd_set fdr, fdw, fde; + struct timeval tv; + int32 rtc; + + test_banner("Select test"); + + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) + err(s, "Socket creation failed"); + + FD_ZERO(&fdr); + FD_SET(s, &fdr); + FD_ZERO(&fdw); + FD_SET(s, &fdw); + FD_ZERO(&fde); + FD_SET(s, &fde); + + tv.tv_sec = 5; + tv.tv_usec = 0; + + printf("Trying with timeval (5 secs)...\n"); + rtc = real_time_clock(); + rv = select(s + 1, &fdr, NULL, &fde, &tv); + rtc = real_time_clock() - rtc; + printf("select gave %d in %ld seconds\n", rv, rtc); + if (rv < 0) + printf("errno = %d [%s]\n", errno, strerror(errno)); + + printf("resetting select fd's\n"); + FD_ZERO(&fdr); + FD_SET(s, &fdr); + FD_ZERO(&fdw); + FD_SET(s, &fdw); + FD_ZERO(&fde); + FD_SET(s, &fde); + + printf("Trying without timeval (= NULL)\n"); + rv = select(s +1, &fdr, &fdw, &fde, NULL); + printf("select gave %d\n", rv); + + if (FD_ISSET(s, &fdr)) + printf("Data to read\n"); + if (FD_ISSET(s, &fdw)) + printf("OK to write\n"); + if (FD_ISSET(s, &fde)) + printf("Exception!\n"); + + closesocket(s); + + printf("Test complete.\n"); + + return (0); +} + diff --git a/src/tests/kits/net/select_test2.c b/src/tests/kits/net/select_test2.c new file mode 100644 index 0000000000..232f3f0bc9 --- /dev/null +++ b/src/tests/kits/net/select_test2.c @@ -0,0 +1,90 @@ +#include +#include +#include +#include +#include + +#include "sys/socket.h" +#include "netinet/in.h" +#include "arpa/inet.h" +#include "sys/select.h" + +#include "ufunc.h" + +int main(int argc, char **argv) +{ + int s, f; + int rv; + struct fd_set fdr, fdw, fde; + struct timeval tv; + int32 rtc; + char path[PATH_MAX]; + + test_banner("Select Test #2"); + + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) + err(s, "Socket creation failed"); + + getcwd(path, PATH_MAX); + sprintf(path, "%s/select_test2.c", path); + f = open(path, O_RDWR); + + if (f > 0 && s > 0) { + printf("\nsocket and fd created.\n"); + } else { + err(-1, "Failed to create socket or fd\n"); + } + + FD_ZERO(&fdr); + FD_SET(s, &fdr); + FD_ZERO(&fdw); + FD_SET(s, &fdw); + FD_ZERO(&fde); + FD_SET(s, &fde); + + tv.tv_sec = 5; + tv.tv_usec = 0; + printf("\nTest1\n=====\n\n"); + printf("Trying with timeval (5 secs)...\n"); + rtc = real_time_clock(); + rv = select(s + 1, &fdr, NULL, &fde, &tv); + rtc = real_time_clock() - rtc; + printf("select gave %d (expecting 0) in %ld seconds\n", rv, rtc); + + FD_ZERO(&fdr); + FD_SET(s, &fdr); + FD_SET(f, &fdr); + FD_ZERO(&fdw); + FD_SET(s, &fdw); + FD_ZERO(&fde); + FD_SET(s, &fde); + + printf("\nTest2\n=====\n\n"); + printf("Trying without timeval and both sockets and files...\n"); + rv = select(f +1, &fdr, NULL, NULL, NULL); + printf("select gave %d (expecting 2)\n", rv); + + if (rv > 0) { + if (FD_ISSET(s, &fdr)) + printf("Data to read\n"); + if (FD_ISSET(s, &fdw)) + printf("OK to write\n"); + if (FD_ISSET(s, &fde)) + printf("Exception!\n"); + if (FD_ISSET(f, &fdr)) + printf("File is readable!\n"); + } else if (rv == 0) { + printf("Timed out??? huh?!\n"); + } else { + printf("errno = %d [%s]\n", errno, strerror(errno)); + } + + closesocket(s); + close(f); + + printf("Test complete.\n"); + + return (0); +} + diff --git a/src/tests/kits/net/select_test_big.c b/src/tests/kits/net/select_test_big.c new file mode 100644 index 0000000000..c66b77cb6f --- /dev/null +++ b/src/tests/kits/net/select_test_big.c @@ -0,0 +1,107 @@ +#include +#include +#include +#include +#include +#include + +#include "sys/socket.h" +#include "netinet/in.h" +#include "arpa/inet.h" +#include "sys/select.h" + +#include "ufunc.h" + +#define SOCKETS 15 + +int main(int argc, char **argv) +{ + int * s; + int rv; + struct fd_set fdr, fdw, fde; + struct timeval tv; + int32 rtc; + int i, max = 0; + int nsock = SOCKETS; + + test_banner("Big Select Test"); + + if (argc >= 2) + nsock = atoi(argv[1]); + + if (nsock < 1 || nsock > 50) { + printf("Unrealistic value of sockets given. Must be between 1 and 50\n"); + err(-1, "Parameters"); + } + + s = (int *) malloc(nsock * sizeof(int)); + if (!s) + err(-1, "Not enought memory for sockets array"); + + printf("\nTest will be run with %d sockets\n\n", nsock); + + for (i=0;i max) + max = s[i]; + FD_SET(s[i], &fdr); + } + FD_ZERO(&fdw); +// FD_SET(s, &fdw); + FD_ZERO(&fde); +// FD_SET(s, &fde); + + tv.tv_sec = 5; + tv.tv_usec = 0; + + printf("Trying with timeval (5 secs)...\n"); + rtc = real_time_clock(); + rv = select(max + 1, &fdr, NULL, &fde, &tv); + rtc = real_time_clock() - rtc; + printf("select gave %d in %ld seconds\n", rv, rtc); + if (rv < 0) + printf("errno = %d [%s]\n", errno, strerror(errno)); + + printf("resetting select fd's\n"); + FD_ZERO(&fdr); + for (i=0;i 0) { + if (FD_ISSET(s[0], &fdr)) + printf("Data to read\n"); + if (FD_ISSET(s[0], &fdw)) + printf("OK to write\n"); + if (FD_ISSET(s[0], &fde)) + printf("Exception!\n"); + } else if (rv < 0) + printf("error was %d [%s]\n", errno, strerror(errno)); + + for (i=0;i +#include +#include + +#include "../driver/net_stack_driver.h" +#include "ufunc.h" + +int main(int argc, char **argv) +{ + int fd; + int rv; + + test_banner("Stopping Server"); + + fd = open("/dev/" NET_STACK_DRIVER_PATH, O_RDWR); + if (fd < 0) + err(fd, "can't open the stack driver"); + + rv = ioctl(fd, NET_STACK_STOP, NULL, 0); + printf("ioctl to stop stack gave %d\n", rv); + + rv = close(fd); + printf("close gave %d\n", rv); + + printf("Operation complete.\n"); + + return (0); +} + diff --git a/src/tests/kits/net/tcp_test.c b/src/tests/kits/net/tcp_test.c new file mode 100644 index 0000000000..c43c09c1af --- /dev/null +++ b/src/tests/kits/net/tcp_test.c @@ -0,0 +1,73 @@ +#include +#include +#include +#include +#include + +#include "sys/socket.h" +#include "netinet/in.h" +#include "arpa/inet.h" +#include "sys/select.h" + +#include "ufunc.h" + +#define RQST "GET / HTTP/1.0\n\n" +#define BUFFER 1024 + +int main(int argc, char **argv) +{ + int sock = socket(AF_INET, SOCK_STREAM, 0); + struct sockaddr_in sin; + size_t salen = sizeof(sin); + int rv; + char buffer[BUFFER]; + + test_banner("Basic TCP Test"); + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = htons((real_time_clock() & 0xffff)); + sin.sin_len = salen; + sin.sin_addr.s_addr = htonl(INADDR_ANY); + rv = bind(sock, (const struct sockaddr*)&sin, salen); + if (rv < 0) + err(rv, "bind"); + printf("Bound\n"); + + sin.sin_port = htons(80); + sin.sin_addr.s_addr = htonl(0xc0a80001); + rv = connect(sock, (const struct sockaddr*)&sin, salen); + if (rv < 0) { + close(sock); + err(rv, "connect"); + } + printf("Connected!\n"); + + rv = write(sock, RQST, strlen(RQST)); + if (rv < 0) { + close(sock); + err(errno, "write"); + } + printf("Written request %d\n", rv); + + memset(&buffer,0, BUFFER); + rv = read(sock, buffer, BUFFER); + if (rv < 0) { + close(sock); + err(errno, "read"); + } + printf("%s", buffer); + memset(&buffer, 0, BUFFER); + while ((rv = read(sock, buffer, BUFFER)) >= 0) { + printf("%s", buffer); + if (rv <= 0) + break; + memset(&buffer,0, BUFFER); + } + printf("Done.\n"); + close(sock); + + return (0); +} + + diff --git a/src/tests/kits/net/test1.c b/src/tests/kits/net/test1.c new file mode 100644 index 0000000000..452da01dc6 --- /dev/null +++ b/src/tests/kits/net/test1.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include + +#include "sys/socket.h" +#include "netinet/in.h" +#include "arpa/inet.h" +#include "sys/select.h" + +#define THREADS 2 +#define TIME 10 + +int32 test_thread(void *data) +{ + int tnum = *(int*)data; + int sock = 0; + uint32 num = 0; + bigtime_t tn; + + printf("Thread %d, starting test...\n", tnum + 1); + + tn = real_time_clock(); + + while (real_time_clock() - tn <= TIME) { + sock = socket(AF_INET, SOCK_DGRAM , 0); + if (sock < 0) { + printf("Failed! Socket could not be created.\n"); + printf("Error was %d [%s]\n", sock, strerror(sock)); + printf("This was after I had created %ld socket%s\n", + num, num == 1 ? "" : "s"); + return -1; + } + closesocket(sock); + num++; + } + + printf( "Thread %d:\n" + " sockets created : %5ld\n" + " test time : %5d seconds\n" + " average : %5ld sockets/sec\n", + tnum + 1, num, TIME, num / TIME); +} + +#define TEST_PHRASE "Hello loopback!" + +int main(int argc, char **argv) +{ + thread_id t[THREADS]; + int i; + status_t retval; + + for (i=0;i= 0) + resume_thread(t[i]); + } + + for (i=0;i +#include +#include +#include +#include + +#include "sys/socket.h" +#include "netinet/in.h" +#include "arpa/inet.h" +#include "sys/select.h" + +#include "ufunc.h" + +#define THREADS 2 +#define TIME 10 + + +int32 test_thread(void *data) +{ + int tnum = *(int*)data; + int sock = 0; + uint32 num = 0; + int rv; + struct sockaddr_in sa; + bigtime_t tn; + + sa.sin_len = sizeof(sa); + sa.sin_port = 0; + sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + sa.sin_family = AF_INET; + memset(&sa.sin_zero, 0, sizeof(sa.sin_zero)); + + printf("Thread %d, starting test...\n", tnum + 1); + + tn = real_time_clock(); + + while (real_time_clock() - tn <= TIME) { + sock = socket(AF_INET, SOCK_DGRAM , 0); + if (sock < 0) + err(sock, "Socket couldn't be created"); + rv = bind(sock, (struct sockaddr *)&sa, sizeof(sa)); + if (rv < 0) + err(rv, "Socket could not be bound to an ephemereal port"); + closesocket(sock); + num++; + } + + printf( "Thread %d:\n" + " sockets created : %5ld\n" + " test time : %5d seconds\n" + " average : %5ld sockets/sec\n", + tnum + 1, num, TIME, num / TIME); +} + +int main(int argc, char **argv) +{ + thread_id t[THREADS]; + int i; + status_t retval; + + test_banner("Socket creation and bind() test"); + + for (i=0;i= 0) + resume_thread(t[i]); + } + + for (i=0;i +#include +#include +#include +#include + +#include "sys/socket.h" +#include "netinet/in.h" +#include "arpa/inet.h" +#include "sys/select.h" + +#include "ufunc.h" + +#define THREADS 2 +#define MIN_SOCK 10 +#define MAX_SOCK 100 +#define TIME 10 + +int32 test_thread(void *data) +{ + int tnum = *(int*)data; + int sock[MAX_SOCK]; + int qty = MIN_SOCK; + struct sockaddr_in sa; + int i, rv, totsock = 0; + + sa.sin_family = AF_INET; + sa.sin_port = 0; + sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + sa.sin_len = sizeof(sa); + memset(&sa.sin_zero, 0, sizeof(sa.sin_zero)); + + printf("Thread %d, starting test\n", tnum + 1); + + while (qty <= MAX_SOCK) { + for (i=0;i < qty;i++) { + if (i >= MAX_SOCK) + break; + sock[i] = socket(AF_INET, SOCK_DGRAM , 0); + totsock++; + if (sock[i] < 0) { + printf("Total of %d sockets created\n", totsock); + err(errno, "Socket creation failed"); + } + } + printf("Thread %d: completed creating %d sockets...\n", tnum+1, qty); + for (i=0;i < qty;i++) { + if (i >= MAX_SOCK) + break; + rv = bind(sock[i], (struct sockaddr*)&sa, sizeof(sa)); + if (rv < 0) + err(errno, "Failed to bind!"); + } + for (i=0;i < qty;i++) { + if (i >= MAX_SOCK) + break; + rv = close(sock[i]); + if (rv < 0) + err(errno, "Failed to close socket!"); + } + qty += (MAX_SOCK - MIN_SOCK) / 10; + } + + printf( "Thread %d complete\n", tnum); +} + +int main(int argc, char **argv) +{ + thread_id t[THREADS]; + int i; + status_t retval; + + test_banner("Simultaneous socket creation test"); + + for (i=0;i= 0) + resume_thread(t[i]); + } + + for (i=0;i +#include +#include +#include +#include + +#include "sys/socket.h" +#include "netinet/in.h" +#include "arpa/inet.h" +#include "sys/select.h" + +#include "ufunc.h" + +void err(int error, char *msg) +{ + printf("Error: %s\n", msg); + printf("Code: %d\n", error); + printf("Desc: %s\n", strerror(error)); + exit(-1); +} + +void test_banner(char *msg) +{ + int sl = strlen(msg); + char *buf = (char*)malloc(sl + 5); + + memset(buf, '=', sl + 4); + printf("%s\n", buf); + buf[1] = buf[sl + 2] = ' '; + memcpy(&buf[2], msg, sl); + printf("%s\n", buf); + memset(buf, '=', sl + 4); + printf("%s\n", buf); +} diff --git a/src/tests/kits/net/ufunc.h b/src/tests/kits/net/ufunc.h new file mode 100644 index 0000000000..63bdab03db --- /dev/null +++ b/src/tests/kits/net/ufunc.h @@ -0,0 +1,9 @@ +/* Utility functions for the test apps */ + +#ifndef UFUNC_H +#define UFUNC_H + +void err(int error, char *msg); +void test_banner(char *msg); + +#endif /* UFUNC_H */ diff --git a/src/tests/kits/storage/BasicTest.cpp b/src/tests/kits/storage/BasicTest.cpp new file mode 100644 index 0000000000..4803701fc8 --- /dev/null +++ b/src/tests/kits/storage/BasicTest.cpp @@ -0,0 +1,127 @@ +// BasicTest.cpp + +#include +#include +#include + +#include "BasicTest.h" + +// count_available_fds +#include +static +int32 +count_available_fds() +{ + set fds; + int fd; + while ((fd = dup(1)) != -1) + fds.insert(fd); + for (set::iterator it = fds.begin(); it != fds.end(); it++) + close(*it); + return fds.size(); +} + +// constructor +BasicTest::BasicTest() + : StorageKit::TestCase(), + fSubTestNumber(0), + fAvailableFDs(0) +{ +} + +// setUp +void +BasicTest::setUp() +{ + fAvailableFDs = count_available_fds(); + SaveCWD(); + fSubTestNumber = 0; +} + +// tearDown +void +BasicTest::tearDown() +{ + RestoreCWD(); + nextSubTestBlock(); + int32 availableFDs = count_available_fds(); + if (availableFDs != fAvailableFDs) { + printf("WARNING: Number of available file descriptors has changed " + "during test: %ld -> %ld\n", fAvailableFDs, availableFDs); + fAvailableFDs = availableFDs; + } +} + +// nextSubTest +void +BasicTest::nextSubTest() +{ + if (shell.BeVerbose()) { + printf("[%ld]", fSubTestNumber++); + fflush(stdout); + } +} + +// nextSubTestBlock +void +BasicTest::nextSubTestBlock() +{ + if (shell.BeVerbose()) + printf("\n"); + fSubTestNumber = 0; +} + +// execCommand +// +// Calls system() with the supplied string. +void +BasicTest::execCommand(const string &cmdLine) +{ + system(cmdLine.c_str()); +} + +// dumpStat +void +BasicTest::dumpStat(struct stat &st) +{ + printf("stat:\n"); + printf(" st_dev : %lx\n", st.st_dev); + printf(" st_ino : %Lx\n", st.st_ino); + printf(" st_mode : %x\n", st.st_mode); + printf(" st_nlink : %x\n", st.st_nlink); + printf(" st_uid : %x\n", st.st_uid); + printf(" st_gid : %x\n", st.st_gid); + printf(" st_size : %Ld\n", st.st_size); + printf(" st_blksize: %ld\n", st.st_blksize); + printf(" st_atime : %lx\n", st.st_atime); + printf(" st_mtime : %lx\n", st.st_mtime); + printf(" st_ctime : %lx\n", st.st_ctime); + printf(" st_crtime : %lx\n", st.st_crtime); +} + +// createVolume +void +BasicTest::createVolume(string imageFile, string mountPoint, int32 megs) +{ + char megsString[16]; + sprintf(megsString, "%ld", megs); + execCommand(string("dd if=/dev/zero of=") + imageFile + + " bs=1M count=" + megsString + + " &> /dev/null" + + " ; mkbfs " + imageFile + + " > /dev/null" + + " ; sync" + + " ; mkdir " + mountPoint + + " ; mount " + imageFile + " " + mountPoint); +} + +// deleteVolume +void +BasicTest::deleteVolume(string imageFile, string mountPoint) +{ + execCommand(string("sync") + + " ; unmount " + mountPoint + + " ; rmdir " + mountPoint + + " ; rm " + imageFile); +} + diff --git a/src/tests/kits/storage/BasicTest.h b/src/tests/kits/storage/BasicTest.h new file mode 100644 index 0000000000..9533a50d4c --- /dev/null +++ b/src/tests/kits/storage/BasicTest.h @@ -0,0 +1,143 @@ +// BasicTest.h + +#ifndef __sk_basic_test_h__ +#define __sk_basic_test_h__ + +#include +#include + +#include + +#include "Test.StorageKit.h" + +class BasicTest : public StorageKit::TestCase +{ +public: + BasicTest(); + + // This function called before *each* test added in Suite() + void setUp(); + + // This function called after *each* test added in Suite() + void tearDown(); + + // helper functions + + void nextSubTest(); + void nextSubTestBlock(); + + static void execCommand(const string &command); + + static void dumpStat(struct stat &st); + + static void createVolume(string imageFile, string mountPoint, int32 megs); + static void deleteVolume(string imageFile, string mountPoint); + +protected: + int32 fSubTestNumber; + int32 fAvailableFDs; +}; + + +// Some other helpful stuff. + +// == for struct stat +static +inline +bool +operator==(const struct stat &st1, const struct stat &st2) +{ + return ( + st1.st_dev == st2.st_dev + && st1.st_ino == st2.st_ino + && st1.st_mode == st2.st_mode + && st1.st_nlink == st2.st_nlink + && st1.st_uid == st2.st_uid + && st1.st_gid == st2.st_gid + && st1.st_size == st2.st_size + && st1.st_blksize == st2.st_blksize + && st1.st_atime == st2.st_atime + && st1.st_mtime == st2.st_mtime + && st1.st_ctime == st2.st_ctime + && st1.st_crtime == st2.st_crtime + ); +} + +// first parameter is equal to the second or third +template +static +inline +bool +equals(const A &a, const B &b, const C &c) +{ + return (a == b || a == c); +} + +// A little helper class for tests. It works like a set of strings, that +// are marked tested or untested. +class TestSet { +public: + typedef set nameset; + +public: + TestSet() + { + } + + void add(string name) + { + if (fTestedNames.find(name) == fTestedNames.end()) + fUntestedNames.insert(name); + } + + void remove(string name) + { + if (fUntestedNames.find(name) != fUntestedNames.end()) + fUntestedNames.erase(name); + else if (fTestedNames.find(name) != fTestedNames.end()) + fTestedNames.erase(name); + } + + void clear() + { + fUntestedNames.clear(); + fTestedNames.clear(); + } + + void rewind() + { + fUntestedNames.insert(fTestedNames.begin(), fTestedNames.end()); + fTestedNames.clear(); + } + + bool test(string name, bool dump = shell.BeVerbose()) + { + bool result = (fUntestedNames.find(name) != fUntestedNames.end()); + if (result) { + fUntestedNames.erase(name); + fTestedNames.insert(name); + } else if (dump) { + // dump untested + printf("TestSet::test(`%s')\n", name.c_str()); + printf("untested:\n"); + for (nameset::iterator it = fUntestedNames.begin(); + it != fUntestedNames.end(); + ++it) { + printf(" `%s'\n", it->c_str()); + } + } + return result; + } + + bool testDone() + { + return (fUntestedNames.empty()); + } + +private: + nameset fUntestedNames; + nameset fTestedNames; +}; + + +#endif // __sk_basic_test_h__ diff --git a/src/tests/kits/storage/DirectoryTest.cpp b/src/tests/kits/storage/DirectoryTest.cpp new file mode 100644 index 0000000000..1d0dbee11c --- /dev/null +++ b/src/tests/kits/storage/DirectoryTest.cpp @@ -0,0 +1,1809 @@ +// DirectoryTest.cpp + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "Test.StorageKit.h" +#include "DirectoryTest.h" + +// Suite +DirectoryTest::Test* +DirectoryTest::Suite() +{ + CppUnit::TestSuite *suite = new CppUnit::TestSuite(); + typedef CppUnit::TestCaller TC; + + NodeTest::AddBaseClassTests("BDirectory::", suite); + + suite->addTest( new TC("BDirectory::Init Test 1", + &DirectoryTest::InitTest1) ); + suite->addTest( new TC("BDirectory::Init Test 2", + &DirectoryTest::InitTest2) ); + suite->addTest( new TC("BDirectory::GetEntry Test", + &DirectoryTest::GetEntryTest) ); + suite->addTest( new TC("BDirectory::IsRoot Test", + &DirectoryTest::IsRootTest) ); + suite->addTest( new TC("BDirectory::FindEntry Test", + &DirectoryTest::FindEntryTest) ); + suite->addTest( new TC("BDirectory::Contains Test", + &DirectoryTest::ContainsTest) ); + suite->addTest( new TC("BDirectory::GetStatFor Test", + &DirectoryTest::GetStatForTest) ); + suite->addTest( new TC("BDirectory::EntryIteration Test", + &DirectoryTest::EntryIterationTest) ); + suite->addTest( new TC("BDirectory::Creation Test", + &DirectoryTest::EntryCreationTest) ); + suite->addTest( new TC("BDirectory::Assignment Test", + &DirectoryTest::AssignmentTest) ); + suite->addTest( new TC("BDirectory::CreateDirectory Test", + &DirectoryTest::CreateDirectoryTest) ); + + return suite; +} + +// CreateRONodes +void +DirectoryTest::CreateRONodes(TestNodes& testEntries) +{ + testEntries.clear(); + const char *filename; + filename = "/"; + testEntries.add(new BDirectory(filename), filename); + filename = "/boot"; + testEntries.add(new BDirectory(filename), filename); + filename = "/boot/home"; + testEntries.add(new BDirectory(filename), filename); + filename = existingDirname; + testEntries.add(new BDirectory(filename), filename); +} + +// CreateRWNodes +void +DirectoryTest::CreateRWNodes(TestNodes& testEntries) +{ + testEntries.clear(); + const char *filename; + filename = existingDirname; + testEntries.add(new BDirectory(filename), filename); + filename = existingSubDirname; + testEntries.add(new BDirectory(filename), filename); +} + +// CreateUninitializedNodes +void +DirectoryTest::CreateUninitializedNodes(TestNodes& testEntries) +{ + testEntries.clear(); + testEntries.add(new BDirectory, ""); +} + +// setUp +void DirectoryTest::setUp() +{ + NodeTest::setUp(); +} + +// tearDown +void DirectoryTest::tearDown() +{ + NodeTest::tearDown(); +} + +// InitTest1 +void +DirectoryTest::InitTest1() +{ + const char *existingFile = existingFilename; + const char *existingSuperFile = existingSuperFilename; + const char *existingRelFile = existingRelFilename; + const char *existing = existingDirname; + const char *existingSub = existingSubDirname; + const char *existingRelSub = existingRelSubDirname; + const char *nonExisting = nonExistingDirname; + const char *nonExistingSuper = nonExistingSuperDirname; + const char *nonExistingRel = nonExistingRelDirname; + // 1. default constructor + nextSubTest(); + { + BDirectory dir; + CPPUNIT_ASSERT( dir.InitCheck() == B_NO_INIT ); + } + + // 2. BDirectory(const char*) + nextSubTest(); + { + BDirectory dir(existing); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + } + nextSubTest(); + { + BDirectory dir(nonExisting); + CPPUNIT_ASSERT( dir.InitCheck() == B_ENTRY_NOT_FOUND ); + } + nextSubTest(); + { + BDirectory dir((const char *)NULL); + CPPUNIT_ASSERT( dir.InitCheck() == B_BAD_VALUE ); + } + nextSubTest(); + { + BDirectory dir(""); + // R5 returns B_ENTRY_NOT_FOUND instead of B_BAD_VALUE. + CPPUNIT_ASSERT( dir.InitCheck() == B_ENTRY_NOT_FOUND ); + } + nextSubTest(); + { + BDirectory dir(existingFile); + // R5 returns B_BAD_VALUE instead of B_NOT_A_DIRECTORY. + CPPUNIT_ASSERT( dir.InitCheck() == B_BAD_VALUE ); + } + nextSubTest(); + { + BDirectory dir(tooLongEntryname); + CPPUNIT_ASSERT( dir.InitCheck() == B_NAME_TOO_LONG ); + } + nextSubTest(); + { + BDirectory dir(fileDirname); + // R5 returns B_ENTRY_NOT_FOUND instead of B_NOT_A_DIRECTORY. + CPPUNIT_ASSERT( dir.InitCheck() == B_ENTRY_NOT_FOUND ); + } + + // 3. BDirectory(const BEntry*) + nextSubTest(); + { + BEntry entry(existing); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + BDirectory dir(&entry); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + } + nextSubTest(); + { + BEntry entry(nonExisting); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + BDirectory dir(&entry); + CPPUNIT_ASSERT( dir.InitCheck() == B_ENTRY_NOT_FOUND ); + } + nextSubTest(); + { + BDirectory dir((BEntry *)NULL); + CPPUNIT_ASSERT( dir.InitCheck() == B_BAD_VALUE ); + } + nextSubTest(); + { + BEntry entry; + BDirectory dir(&entry); + CPPUNIT_ASSERT( equals(dir.InitCheck(), B_BAD_ADDRESS, B_BAD_VALUE) ); + } + nextSubTest(); + { + BEntry entry(existingFile); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + BDirectory dir(&entry); + // R5 returns B_BAD_VALUE instead of B_NOT_A_DIRECTORY. + CPPUNIT_ASSERT( dir.InitCheck() == B_BAD_VALUE ); + } + nextSubTest(); + { + BEntry entry(tooLongEntryname); + // R5 returns E2BIG instead of B_NAME_TOO_LONG + CPPUNIT_ASSERT( equals(entry.InitCheck(), E2BIG, B_NAME_TOO_LONG) ); + BDirectory dir(&entry); + CPPUNIT_ASSERT( equals(dir.InitCheck(), B_BAD_ADDRESS, B_BAD_VALUE) ); + } + + // 4. BDirectory(const entry_ref*) + nextSubTest(); + { + BEntry entry(existing); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + entry_ref ref; + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + BDirectory dir(&ref); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + } + nextSubTest(); + { + BEntry entry(nonExisting); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + entry_ref ref; + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + BDirectory dir(&ref); + CPPUNIT_ASSERT( dir.InitCheck() == B_ENTRY_NOT_FOUND ); + } + nextSubTest(); + { + BDirectory dir((entry_ref *)NULL); + CPPUNIT_ASSERT( dir.InitCheck() == B_BAD_VALUE ); + } + nextSubTest(); + { + BEntry entry(existingFile); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + entry_ref ref; + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + BDirectory dir(&ref); + // R5 returns B_BAD_VALUE instead of B_NOT_A_DIRECTORY. + CPPUNIT_ASSERT( dir.InitCheck() == B_BAD_VALUE ); + } + + // 5. BDirectory(const node_ref*) + nextSubTest(); + { + BNode node(existing); + CPPUNIT_ASSERT( node.InitCheck() == B_OK ); + node_ref nref; + CPPUNIT_ASSERT( node.GetNodeRef(&nref) == B_OK ); + BDirectory dir(&nref); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + } +// R5: crashs, when passing a NULL node_ref. +#if !SK_TEST_R5 + nextSubTest(); + { + BDirectory dir((node_ref *)NULL); + CPPUNIT_ASSERT( dir.InitCheck() == B_BAD_VALUE ); + } +#endif + nextSubTest(); + { + BNode node(existingFile); + CPPUNIT_ASSERT( node.InitCheck() == B_OK ); + node_ref nref; + CPPUNIT_ASSERT( node.GetNodeRef(&nref) == B_OK ); + BDirectory dir(&nref); + // R5: returns B_BAD_VALUE instead of B_NOT_A_DIRECTORY. + // OBOS: returns B_ENTRY_NOT_FOUND instead of B_NOT_A_DIRECTORY. + CPPUNIT_ASSERT( equals(dir.InitCheck(), B_BAD_VALUE, B_ENTRY_NOT_FOUND) ); + } + + // 6. BDirectory(const BDirectory*, const char*) + nextSubTest(); + { + BDirectory pathDir(existing); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + BDirectory dir(&pathDir, existingRelSub); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + } + nextSubTest(); + { + BDirectory pathDir(existing); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + BDirectory dir(&pathDir, existingSub); + CPPUNIT_ASSERT( dir.InitCheck() == B_BAD_VALUE ); + } + nextSubTest(); + { + BDirectory pathDir(nonExistingSuper); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + BDirectory dir(&pathDir, nonExistingRel); + CPPUNIT_ASSERT( dir.InitCheck() == B_ENTRY_NOT_FOUND ); + } + nextSubTest(); + { + BDirectory dir((BDirectory *)NULL, (const char *)NULL); + CPPUNIT_ASSERT( dir.InitCheck() == B_BAD_VALUE ); + } + nextSubTest(); + { + BDirectory dir((BDirectory *)NULL, existingSub); + CPPUNIT_ASSERT( dir.InitCheck() == B_BAD_VALUE ); + } + nextSubTest(); + { + BDirectory pathDir(existing); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + BDirectory dir(&pathDir, (const char *)NULL); + CPPUNIT_ASSERT( dir.InitCheck() == B_BAD_VALUE ); + } + nextSubTest(); + { + BDirectory pathDir(existing); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + BDirectory dir(&pathDir, ""); + // This does not fail in R5, but inits the object to pathDir. + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + } + nextSubTest(); + { + BDirectory pathDir(existingSuperFile); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + BDirectory dir(&pathDir, existingRelFile); + // R5 returns B_BAD_VALUE instead of B_NOT_A_DIRECTORY. + CPPUNIT_ASSERT( dir.InitCheck() == B_BAD_VALUE ); + } + nextSubTest(); + { + BDirectory pathDir(tooLongSuperEntryname); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + BDirectory dir(&pathDir, tooLongRelEntryname); + CPPUNIT_ASSERT( dir.InitCheck() == B_NAME_TOO_LONG ); + } + nextSubTest(); + { + BDirectory pathDir(fileSuperDirname); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + BDirectory dir(&pathDir, fileRelDirname); + // R5 returns B_ENTRY_NOT_FOUND instead of B_NOT_A_DIRECTORY. + CPPUNIT_ASSERT( dir.InitCheck() == B_ENTRY_NOT_FOUND ); + } +} + +// InitTest2 +void +DirectoryTest::InitTest2() +{ + const char *existingFile = existingFilename; + const char *existingSuperFile = existingSuperFilename; + const char *existingRelFile = existingRelFilename; + const char *existing = existingDirname; + const char *existingSub = existingSubDirname; + const char *existingRelSub = existingRelSubDirname; + const char *nonExisting = nonExistingDirname; + const char *nonExistingSuper = nonExistingSuperDirname; + const char *nonExistingRel = nonExistingRelDirname; + BDirectory dir; + // 2. SetTo(const char*) + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(existing) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + dir.Unset(); + // + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(nonExisting) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( dir.InitCheck() == B_ENTRY_NOT_FOUND ); + dir.Unset(); + // + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo((const char *)NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( dir.InitCheck() == B_BAD_VALUE ); + dir.Unset(); + // + nextSubTest(); + // R5 returns B_ENTRY_NOT_FOUND instead of B_BAD_VALUE. + CPPUNIT_ASSERT( dir.SetTo("") == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( dir.InitCheck() == B_ENTRY_NOT_FOUND ); + dir.Unset(); + // + nextSubTest(); + // R5 returns B_BAD_VALUE instead of B_NOT_A_DIRECTORY. + CPPUNIT_ASSERT( dir.SetTo(existingFile) == B_BAD_VALUE ); + CPPUNIT_ASSERT( dir.InitCheck() == B_BAD_VALUE ); + dir.Unset(); + // + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(tooLongEntryname) == B_NAME_TOO_LONG ); + CPPUNIT_ASSERT( dir.InitCheck() == B_NAME_TOO_LONG ); + dir.Unset(); + // + nextSubTest(); + // R5 returns B_ENTRY_NOT_FOUND instead of B_NOT_A_DIRECTORY. + CPPUNIT_ASSERT( dir.SetTo(fileDirname) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( dir.InitCheck() == B_ENTRY_NOT_FOUND ); + dir.Unset(); + + // 3. BDirectory(const BEntry*) + nextSubTest(); + BEntry entry(existing); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + CPPUNIT_ASSERT( dir.SetTo(&entry) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + dir.Unset(); + // + nextSubTest(); + entry.SetTo(nonExisting); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + CPPUNIT_ASSERT( dir.SetTo(&entry) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( dir.InitCheck() == B_ENTRY_NOT_FOUND ); + dir.Unset(); + // + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo((BEntry *)NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( dir.InitCheck() == B_BAD_VALUE ); + dir.Unset(); + // + nextSubTest(); + entry.Unset(); + CPPUNIT_ASSERT( equals(dir.SetTo(&entry), B_BAD_ADDRESS, B_BAD_VALUE) ); + CPPUNIT_ASSERT( equals(dir.InitCheck(), B_BAD_ADDRESS, B_BAD_VALUE) ); + dir.Unset(); + // + nextSubTest(); + entry.SetTo(existingFile); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + // R5 returns B_BAD_VALUE instead of B_NOT_A_DIRECTORY. + CPPUNIT_ASSERT( dir.SetTo(&entry) == B_BAD_VALUE ); + CPPUNIT_ASSERT( dir.InitCheck() == B_BAD_VALUE ); + dir.Unset(); + // + nextSubTest(); + entry.SetTo(tooLongEntryname); + // R5 returns E2BIG instead of B_NAME_TOO_LONG + CPPUNIT_ASSERT( equals(entry.InitCheck(), E2BIG, B_NAME_TOO_LONG) ); + CPPUNIT_ASSERT( equals(dir.SetTo(&entry), B_BAD_ADDRESS, B_BAD_VALUE) ); + CPPUNIT_ASSERT( equals(dir.InitCheck(), B_BAD_ADDRESS, B_BAD_VALUE) ); + dir.Unset(); + + // 4. BDirectory(const entry_ref*) + nextSubTest(); + entry.SetTo(existing); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + entry_ref ref; + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + CPPUNIT_ASSERT( dir.SetTo(&ref) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + dir.Unset(); + // + nextSubTest(); + entry.SetTo(nonExisting); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + CPPUNIT_ASSERT( dir.SetTo(&ref) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( dir.InitCheck() == B_ENTRY_NOT_FOUND ); + dir.Unset(); + // + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo((entry_ref *)NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( dir.InitCheck() == B_BAD_VALUE ); + dir.Unset(); + // + nextSubTest(); + entry.SetTo(existingFile); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + // R5 returns B_BAD_VALUE instead of B_NOT_A_DIRECTORY. + CPPUNIT_ASSERT( dir.SetTo(&ref) == B_BAD_VALUE ); + CPPUNIT_ASSERT( dir.InitCheck() == B_BAD_VALUE ); + dir.Unset(); + + // 5. BDirectory(const node_ref*) + nextSubTest(); + BNode node(existing); + CPPUNIT_ASSERT( node.InitCheck() == B_OK ); + node_ref nref; + CPPUNIT_ASSERT( node.GetNodeRef(&nref) == B_OK ); + CPPUNIT_ASSERT( dir.SetTo(&nref) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + dir.Unset(); + // +// R5: crashs, when passing a NULL node_ref. +#if !SK_TEST_R5 + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo((node_ref *)NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( dir.InitCheck() == B_BAD_VALUE ); + dir.Unset(); +#endif + // + nextSubTest(); + CPPUNIT_ASSERT( node.SetTo(existingFile) == B_OK ); + CPPUNIT_ASSERT( node.GetNodeRef(&nref) == B_OK ); + // R5 returns B_BAD_VALUE instead of B_NOT_A_DIRECTORY. + // OBOS: returns B_ENTRY_NOT_FOUND instead of B_NOT_A_DIRECTORY. + CPPUNIT_ASSERT( equals(dir.SetTo(&nref), B_BAD_VALUE, B_ENTRY_NOT_FOUND) ); + CPPUNIT_ASSERT( equals(dir.InitCheck(), B_BAD_VALUE, B_ENTRY_NOT_FOUND) ); + dir.Unset(); + + // 6. BDirectory(const BDirectory*, const char*) + nextSubTest(); + BDirectory pathDir(existing); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( dir.SetTo(&pathDir, existingRelSub) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + dir.Unset(); + // + nextSubTest(); + pathDir.SetTo(existing); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( dir.SetTo(&pathDir, existingSub) == B_BAD_VALUE ); + CPPUNIT_ASSERT( dir.InitCheck() == B_BAD_VALUE ); + dir.Unset(); + // + nextSubTest(); + pathDir.SetTo(nonExistingSuper); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( dir.SetTo(&pathDir, nonExistingRel) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( dir.InitCheck() == B_ENTRY_NOT_FOUND ); + dir.Unset(); + // + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo((BDirectory *)NULL, (const char *)NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( dir.InitCheck() == B_BAD_VALUE ); + dir.Unset(); + // + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo((BDirectory *)NULL, existingSub) == B_BAD_VALUE ); + CPPUNIT_ASSERT( dir.InitCheck() == B_BAD_VALUE ); + dir.Unset(); + // + nextSubTest(); + pathDir.SetTo(existing); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( dir.SetTo(&pathDir, (const char *)NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( dir.InitCheck() == B_BAD_VALUE ); + dir.Unset(); + // + nextSubTest(); + pathDir.SetTo(existing); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + // This does not fail in R5, but inits the object to pathDir. + CPPUNIT_ASSERT( dir.SetTo(&pathDir, "") == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + dir.Unset(); + // + nextSubTest(); + pathDir.SetTo(existingSuperFile); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + // R5 returns B_BAD_VALUE instead of B_NOT_A_DIRECTORY. + CPPUNIT_ASSERT( dir.SetTo(&pathDir, existingRelFile) == B_BAD_VALUE ); + CPPUNIT_ASSERT( dir.InitCheck() == B_BAD_VALUE ); + dir.Unset(); + // + nextSubTest(); + pathDir.SetTo(tooLongSuperEntryname); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( dir.SetTo(&pathDir, tooLongRelEntryname) + == B_NAME_TOO_LONG ); + CPPUNIT_ASSERT( dir.InitCheck() == B_NAME_TOO_LONG ); + dir.Unset(); + // + nextSubTest(); + pathDir.SetTo(fileSuperDirname); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + // R5 returns B_ENTRY_NOT_FOUND instead of B_NOT_A_DIRECTORY. + CPPUNIT_ASSERT( dir.SetTo(&pathDir, fileRelDirname) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( dir.InitCheck() == B_ENTRY_NOT_FOUND ); + dir.Unset(); +} + +// GetEntryTest +void +DirectoryTest::GetEntryTest() +{ + const char *existing = existingDirname; + const char *nonExisting = nonExistingDirname; + // + nextSubTest(); + BDirectory dir; + CPPUNIT_ASSERT( dir.InitCheck() == B_NO_INIT ); + BEntry entry; + CPPUNIT_ASSERT( dir.GetEntry(&entry) == B_NO_INIT ); + dir.Unset(); + entry.Unset(); + // + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(existing) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( dir.GetEntry(&entry) == B_OK ); + CPPUNIT_ASSERT( entry == BEntry(existing) ); + dir.Unset(); + entry.Unset(); + // +#if !SK_TEST_R5 +// R5: crashs, when passing a NULL BEntry. + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(existing) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( dir.GetEntry((BEntry *)NULL) == B_BAD_VALUE ); + dir.Unset(); + entry.Unset(); +#endif + // + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(nonExisting) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( dir.InitCheck() == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( dir.GetEntry(&entry) == B_NO_INIT ); + dir.Unset(); + entry.Unset(); +} + +// IsRootTest +void +DirectoryTest::IsRootTest() +{ + // + nextSubTest(); + BDirectory dir; + CPPUNIT_ASSERT( dir.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( dir.IsRootDirectory() == false ); + // + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo("/boot") == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( dir.IsRootDirectory() == true ); + // + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo("/boot/beos") == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( dir.IsRootDirectory() == false ); + // + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo("/tmp") == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( dir.IsRootDirectory() == false ); + // + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo("/") == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( dir.IsRootDirectory() == true ); +} + +// FindEntryTest +void +DirectoryTest::FindEntryTest() +{ + const char *existingFile = existingFilename; + const char *existing = existingDirname; + const char *existingSub = existingSubDirname; + const char *existingRelSub = existingRelSubDirname; + const char *nonExisting = nonExistingDirname; + const char *nonExistingSuper = nonExistingSuperDirname; + const char *nonExistingRel = nonExistingRelDirname; + const char *dirLink = dirLinkname; + const char *badLink = badLinkname; + const char *cyclicLink1 = cyclicLinkname1; + // existing absolute path, uninitialized BDirectory + nextSubTest(); + BDirectory dir; + BEntry entry; + BPath path; + CPPUNIT_ASSERT( dir.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( dir.FindEntry(existing, &entry) == B_OK ); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + CPPUNIT_ASSERT( entry.GetPath(&path) == B_OK ); + CPPUNIT_ASSERT( path == existing == B_OK ); + dir.Unset(); + entry.Unset(); + path.Unset(); + // existing absolute path, badly initialized BDirectory + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(nonExisting) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( dir.InitCheck() == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( dir.FindEntry(existing, &entry) == B_OK ); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + CPPUNIT_ASSERT( entry.GetPath(&path) == B_OK ); + CPPUNIT_ASSERT( path == existing == B_OK ); + dir.Unset(); + entry.Unset(); + path.Unset(); + // existing path relative to current dir, uninitialized BDirectory + nextSubTest(); + CPPUNIT_ASSERT( dir.InitCheck() == B_NO_INIT ); + chdir(existing); + CPPUNIT_ASSERT( dir.FindEntry(existingRelSub, &entry) == B_OK ); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + CPPUNIT_ASSERT( entry.GetPath(&path) == B_OK ); + CPPUNIT_ASSERT( path == existingSub == B_OK ); + dir.Unset(); + entry.Unset(); + path.Unset(); + chdir("/"); + // existing path relative to current dir, + // initialized BDirectory != current dir + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(existingSub) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + chdir(existing); + CPPUNIT_ASSERT( entry.SetTo(existingFile) == B_OK ); + CPPUNIT_ASSERT( dir.FindEntry(existingRelSub, &entry) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT ); + dir.Unset(); + entry.Unset(); + path.Unset(); + chdir("/"); + // abstract entry + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(nonExistingSuper) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + chdir(existing); + CPPUNIT_ASSERT( entry.SetTo(existingFile) == B_OK ); + CPPUNIT_ASSERT( dir.FindEntry(nonExistingRel, &entry) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT ); + dir.Unset(); + entry.Unset(); + path.Unset(); + chdir("/"); + // bad args + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(existing) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); +// R5: crashs, when passing a NULL BEntry. +#if !SK_TEST_R5 + CPPUNIT_ASSERT( dir.FindEntry(existingRelSub, NULL) == B_BAD_VALUE ); +#endif + CPPUNIT_ASSERT( entry.SetTo(existingFile) == B_OK ); + CPPUNIT_ASSERT( dir.FindEntry(NULL, &entry) == B_BAD_VALUE ); + CPPUNIT_ASSERT( equals(entry.InitCheck(), B_BAD_VALUE, B_NO_INIT) ); +// R5: crashs, when passing a NULL BEntry. +#if !SK_TEST_R5 + CPPUNIT_ASSERT( dir.FindEntry(NULL, NULL) == B_BAD_VALUE ); +#endif + dir.Unset(); + entry.Unset(); + path.Unset(); + // don't traverse a valid link + nextSubTest(); + CPPUNIT_ASSERT( dir.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( dir.FindEntry(dirLink, &entry) == B_OK ); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + CPPUNIT_ASSERT( entry.GetPath(&path) == B_OK ); + CPPUNIT_ASSERT( path == dirLink == B_OK ); + dir.Unset(); + entry.Unset(); + path.Unset(); + // traverse a valid link + nextSubTest(); + CPPUNIT_ASSERT( dir.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( dir.FindEntry(dirLink, &entry, true) == B_OK ); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + CPPUNIT_ASSERT( entry.GetPath(&path) == B_OK ); + CPPUNIT_ASSERT( path == existing == B_OK ); + dir.Unset(); + entry.Unset(); + path.Unset(); + // don't traverse an invalid link + nextSubTest(); + CPPUNIT_ASSERT( dir.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( dir.FindEntry(badLink, &entry) == B_OK ); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + CPPUNIT_ASSERT( entry.GetPath(&path) == B_OK ); + CPPUNIT_ASSERT( path == badLink == B_OK ); + dir.Unset(); + entry.Unset(); + path.Unset(); + // traverse an invalid link + nextSubTest(); + CPPUNIT_ASSERT( dir.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( dir.FindEntry(badLink, &entry, true) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( equals(entry.InitCheck(), B_ENTRY_NOT_FOUND, B_NO_INIT) ); + dir.Unset(); + entry.Unset(); + path.Unset(); + // don't traverse a cyclic link + nextSubTest(); + CPPUNIT_ASSERT( dir.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( dir.FindEntry(cyclicLink1, &entry) == B_OK ); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + CPPUNIT_ASSERT( entry.GetPath(&path) == B_OK ); + CPPUNIT_ASSERT( path == cyclicLink1 == B_OK ); + dir.Unset(); + entry.Unset(); + path.Unset(); + // traverse a cyclic link + nextSubTest(); + CPPUNIT_ASSERT( dir.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( dir.FindEntry(cyclicLink1, &entry, true) == B_LINK_LIMIT ); + CPPUNIT_ASSERT( entry.InitCheck() == B_LINK_LIMIT ); + dir.Unset(); + entry.Unset(); + path.Unset(); +} + +// ContainsTest +void +DirectoryTest::ContainsTest() +{ + const char *existingFile = existingFilename; + const char *existingSuperFile = existingSuperFilename; + const char *existingRelFile = existingRelFilename; + const char *existing = existingDirname; + const char *existingSuper = existingSuperDirname; + const char *existingSub = existingSubDirname; + const char *existingRelSub = existingRelSubDirname; + const char *nonExisting = nonExistingDirname; + const char *dirLink = dirLinkname; + const char *dirSuperLink = dirSuperLinkname; + // 1. Contains(const char *, int32) + // existing entry, initialized BDirectory + nextSubTest(); + BDirectory dir(existing); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( dir.Contains(existingSub) == true ); + dir.Unset(); + // existing entry, uninitialized BDirectory + // R5 returns true! + nextSubTest(); + CPPUNIT_ASSERT( dir.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( dir.Contains(existing) == true ); + dir.Unset(); + // non-existing entry, uninitialized BDirectory + nextSubTest(); + CPPUNIT_ASSERT( dir.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( dir.Contains(nonExisting) == false ); + dir.Unset(); + // existing entry, badly initialized BDirectory + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(nonExisting) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( dir.InitCheck() == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( dir.Contains(existing) == true ); + dir.Unset(); + // non-existing entry, badly initialized BDirectory + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(nonExisting) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( dir.InitCheck() == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( dir.Contains(nonExisting) == false ); + dir.Unset(); + // initialized BDirectory, bad args + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(existing) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( dir.Contains((const char*)NULL) == true ); + dir.Unset(); + // uninitialized BDirectory, bad args + nextSubTest(); + CPPUNIT_ASSERT( dir.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( dir.Contains((const char*)NULL) == false ); + dir.Unset(); + // existing entry (second level, absolute path), initialized BDirectory + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(existingSuper) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( dir.Contains(existingSub) == true ); + dir.Unset(); + // existing entry (second level, name only), initialized BDirectory + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(existingSuper) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( dir.Contains(existingRelSub) == false ); + dir.Unset(); + // initialized BDirectory, self containing + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(existing) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( dir.Contains(existing) == true ); + dir.Unset(); + // existing entry (dir), initialized BDirectory, matching node kind + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(existingSuper) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( dir.Contains(existing, B_DIRECTORY_NODE) == true ); + dir.Unset(); + // existing entry (dir), initialized BDirectory, mismatching node kind + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(existingSuper) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( dir.Contains(existing, B_FILE_NODE) == false ); + dir.Unset(); + // existing entry (file), initialized BDirectory, matching node kind + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(existingSuperFile) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( dir.Contains(existingFile, B_FILE_NODE) == true ); + dir.Unset(); + // existing entry (file), initialized BDirectory, mismatching node kind + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(existingSuperFile) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( dir.Contains(existingFile, B_SYMLINK_NODE) == false ); + dir.Unset(); + // existing entry (link), initialized BDirectory, matching node kind + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(dirSuperLink) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( dir.Contains(dirLink, B_SYMLINK_NODE) == true ); + dir.Unset(); + // existing entry (link), initialized BDirectory, mismatching node kind + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(dirSuperLink) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( dir.Contains(dirLink, B_DIRECTORY_NODE) == false ); + dir.Unset(); + // existing entry (relative path), initialized BDirectory, + // matching node kind + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(existingSuperFile) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( dir.Contains(existingRelFile, B_FILE_NODE) == true ); + dir.Unset(); + // existing entry (relative path), initialized BDirectory, + // mismatching node kind + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(existingSuperFile) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( dir.Contains(existingRelFile, B_SYMLINK_NODE) == false ); + dir.Unset(); + + // 2. Contains(const BEntry *, int32) + // existing entry, initialized BDirectory + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(existing) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + BEntry entry(existingSub); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + CPPUNIT_ASSERT( dir.Contains(&entry) == true ); + dir.Unset(); + // existing entry, uninitialized BDirectory + // R5: unlike the other version, this one returns false + // OBOS: both versions return true + nextSubTest(); + CPPUNIT_ASSERT( dir.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( entry.SetTo(existing) == B_OK ); + CPPUNIT_ASSERT( equals(dir.Contains(&entry), false, true) ); + dir.Unset(); + entry.Unset(); + // non-existing entry, uninitialized BDirectory + nextSubTest(); + CPPUNIT_ASSERT( dir.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( entry.SetTo(nonExisting) == B_OK); + CPPUNIT_ASSERT( dir.Contains(&entry) == false ); + dir.Unset(); + entry.Unset(); + // existing entry, badly initialized BDirectory + // R5: unlike the other version, this one returns false + // OBOS: both versions return true + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(nonExisting) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( dir.InitCheck() == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( entry.SetTo(existing) == B_OK); + CPPUNIT_ASSERT( equals(dir.Contains(&entry), false, true) ); + dir.Unset(); + entry.Unset(); + // non-existing entry, badly initialized BDirectory + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(nonExisting) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( dir.InitCheck() == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( entry.SetTo(nonExisting) == B_OK); + CPPUNIT_ASSERT( dir.Contains(&entry) == false ); + dir.Unset(); + entry.Unset(); + // initialized BDirectory, bad args +// R5 crashs, when passing a NULL BEntry +#if !SK_TEST_R5 + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(existing) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( dir.Contains((const BEntry*)NULL) == false ); + dir.Unset(); +#endif + // uninitialized BDirectory, bad args + nextSubTest(); + CPPUNIT_ASSERT( dir.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( dir.Contains((const BEntry*)NULL) == false ); + dir.Unset(); + // existing entry (second level, absolute path), initialized BDirectory + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(existingSuper) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( entry.SetTo(existingSub) == B_OK); + CPPUNIT_ASSERT( dir.Contains(&entry) == true ); + dir.Unset(); + entry.Unset(); + // initialized BDirectory, self containing + // R5: behavior is different from Contains(const char*) + // OBOS: both versions return true + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(existing) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( entry.SetTo(existing) == B_OK); + CPPUNIT_ASSERT( equals(dir.Contains(&entry), false, true) ); + dir.Unset(); + entry.Unset(); + // existing entry (dir), initialized BDirectory, matching node kind + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(existingSuper) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( entry.SetTo(existing) == B_OK); + CPPUNIT_ASSERT( dir.Contains(&entry, B_DIRECTORY_NODE) == true ); + dir.Unset(); + entry.Unset(); + // existing entry (dir), initialized BDirectory, mismatching node kind + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(existingSuper) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( entry.SetTo(existing) == B_OK); + CPPUNIT_ASSERT( dir.Contains(&entry, B_FILE_NODE) == false ); + dir.Unset(); + entry.Unset(); + // existing entry (file), initialized BDirectory, matching node kind +// R5 bug: returns false +#if !SK_TEST_R5 + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(existingSuperFile) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( entry.SetTo(existingFile) == B_OK); + CPPUNIT_ASSERT( dir.Contains(&entry, B_FILE_NODE) == true ); + dir.Unset(); + entry.Unset(); +#endif + // existing entry (file), initialized BDirectory, mismatching node kind + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(existingSuperFile) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( entry.SetTo(existingFile) == B_OK); + CPPUNIT_ASSERT( dir.Contains(&entry, B_SYMLINK_NODE) == false ); + dir.Unset(); + entry.Unset(); + // existing entry (link), initialized BDirectory, matching node kind +// R5 bug: returns false +#if !SK_TEST_R5 + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(dirSuperLink) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( entry.SetTo(dirLink) == B_OK); + CPPUNIT_ASSERT( dir.Contains(&entry, B_SYMLINK_NODE) == true ); + dir.Unset(); + entry.Unset(); +#endif + // existing entry (link), initialized BDirectory, mismatching node kind +// R5 bug: returns true +#if !SK_TEST_R5 + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(dirSuperLink) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( entry.SetTo(dirLink) == B_OK); + CPPUNIT_ASSERT( dir.Contains(&entry, B_DIRECTORY_NODE) == false ); + dir.Unset(); + entry.Unset(); +#endif +} + +// GetStatForTest +void +DirectoryTest::GetStatForTest() +{ + const char *existing = existingDirname; + const char *existingSuper = existingSuperDirname; + const char *existingRel = existingRelDirname; + const char *nonExisting = nonExistingDirname; + // uninitialized dir, existing entry, absolute path + nextSubTest(); + BDirectory dir; + BEntry entry; + struct stat stat1, stat2; + memset(&stat1, 0, sizeof(struct stat)); + memset(&stat2, 0, sizeof(struct stat)); + CPPUNIT_ASSERT( dir.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( dir.GetStatFor(existing, &stat1) == B_NO_INIT ); + dir.Unset(); + entry.Unset(); + // badly initialized dir, existing entry, absolute path + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(nonExisting) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( dir.InitCheck() == B_ENTRY_NOT_FOUND ); + memset(&stat1, 0, sizeof(struct stat)); + memset(&stat2, 0, sizeof(struct stat)); + CPPUNIT_ASSERT( dir.GetStatFor(existing, &stat1) == B_NO_INIT ); + dir.Unset(); + entry.Unset(); + // initialized dir, existing entry, absolute path + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo("/") == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + memset(&stat1, 0, sizeof(struct stat)); + memset(&stat2, 0, sizeof(struct stat)); + CPPUNIT_ASSERT( dir.GetStatFor(existing, &stat1) == B_OK ); + CPPUNIT_ASSERT( entry.SetTo(existing) == B_OK ); + CPPUNIT_ASSERT( entry.GetStat(&stat2) == B_OK ); + CPPUNIT_ASSERT( stat1 == stat2 ); + dir.Unset(); + entry.Unset(); + // initialized dir, existing entry, relative path + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(existingSuper) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + memset(&stat1, 0, sizeof(struct stat)); + memset(&stat2, 0, sizeof(struct stat)); + CPPUNIT_ASSERT( dir.GetStatFor(existingRel, &stat1) == B_OK ); + CPPUNIT_ASSERT( entry.SetTo(existing) == B_OK ); + CPPUNIT_ASSERT( entry.GetStat(&stat2) == B_OK ); + CPPUNIT_ASSERT( stat1 == stat2 ); + dir.Unset(); + entry.Unset(); + // initialized dir, non-existing entry, absolute path + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo("/") == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + memset(&stat1, 0, sizeof(struct stat)); + memset(&stat2, 0, sizeof(struct stat)); + CPPUNIT_ASSERT( dir.GetStatFor(nonExisting, &stat1) == B_ENTRY_NOT_FOUND ); + dir.Unset(); + entry.Unset(); + // initialized dir, bad args (NULL path) + // R5 returns B_OK and the stat structure for the directory + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo("/") == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + memset(&stat1, 0, sizeof(struct stat)); + memset(&stat2, 0, sizeof(struct stat)); + CPPUNIT_ASSERT( dir.GetStatFor(NULL, &stat1) == B_OK ); + CPPUNIT_ASSERT( entry.SetTo("/") == B_OK ); + CPPUNIT_ASSERT( entry.GetStat(&stat2) == B_OK ); + CPPUNIT_ASSERT( stat1 == stat2 ); + dir.Unset(); + entry.Unset(); + // initialized dir, bad args (empty path) + // R5 returns B_ENTRY_NOT_FOUND + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo("/") == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( dir.GetStatFor("", &stat1) == B_ENTRY_NOT_FOUND ); + dir.Unset(); + entry.Unset(); + // initialized dir, bad args + // R5 returns B_BAD_ADDRESS instead of B_BAD_VALUE + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo("/") == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( equals(dir.GetStatFor(existing, NULL), B_BAD_ADDRESS, + B_BAD_VALUE) ); + CPPUNIT_ASSERT( equals(dir.GetStatFor(NULL, NULL), B_BAD_ADDRESS, + B_BAD_VALUE) ); + dir.Unset(); + entry.Unset(); +} + +// EntryIterationTest +void +DirectoryTest::EntryIterationTest() +{ + const char *existingFile = existingFilename; + const char *nonExisting = nonExistingDirname; + const char *testDir1 = testDirname1; + // create a test directory + execCommand(string("mkdir ") + testDir1); + // 1. empty directory + TestSet testSet; + testSet.add("."); + testSet.add(".."); + // GetNextEntry + nextSubTest(); + BDirectory dir(testDir1); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + BEntry entry; + CPPUNIT_ASSERT( dir.GetNextEntry(&entry) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( dir.Rewind() == B_OK ); + dir.Unset(); + entry.Unset(); + // GetNextRef + nextSubTest(); + entry_ref ref; + CPPUNIT_ASSERT( dir.SetTo(testDir1) == B_OK ); + CPPUNIT_ASSERT( dir.GetNextRef(&ref) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( dir.Rewind() == B_OK ); + dir.Unset(); + entry.Unset(); + // GetNextDirents + nextSubTest(); + size_t bufSize = (sizeof(dirent) + B_FILE_NAME_LENGTH) * 10; + char buffer[bufSize]; + dirent *ents = (dirent *)buffer; + CPPUNIT_ASSERT( dir.SetTo(testDir1) == B_OK ); + while (dir.GetNextDirents(ents, bufSize, 1) == 1) + CPPUNIT_ASSERT( testSet.test(ents->d_name) == true ); + CPPUNIT_ASSERT( testSet.testDone() == true ); + CPPUNIT_ASSERT( dir.Rewind() == B_OK ); + dir.Unset(); + entry.Unset(); + testSet.rewind(); + // CountEntries + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(testDir1) == B_OK ); + CPPUNIT_ASSERT( dir.CountEntries() == 0 ); + dir.Unset(); + + // 2. non-empty directory + string dirPathName(string(testDir1) + "/"); + string entryName("file1"); + execCommand(string("touch ") + dirPathName + entryName); + testSet.add(entryName); + entryName = ("file2"); + execCommand(string("touch ") + dirPathName + entryName); + testSet.add(entryName); + entryName = ("file3"); + execCommand(string("touch ") + dirPathName + entryName); + testSet.add(entryName); + entryName = ("dir1"); + execCommand(string("mkdir ") + dirPathName + entryName); + testSet.add(entryName); + entryName = ("dir2"); + execCommand(string("mkdir ") + dirPathName + entryName); + testSet.add(entryName); + entryName = ("dir3"); + execCommand(string("mkdir ") + dirPathName + entryName); + testSet.add(entryName); + entryName = ("link1"); + execCommand(string("ln -s ") + existingFile + " " + + dirPathName + entryName); + testSet.add(entryName); + entryName = ("link2"); + execCommand(string("ln -s ") + existingFile + " " + + dirPathName + entryName); + testSet.add(entryName); + entryName = ("link3"); + execCommand(string("ln -s ") + existingFile + " " + + dirPathName + entryName); + testSet.add(entryName); + // GetNextEntry + nextSubTest(); + testSet.test("."); + testSet.test(".."); + CPPUNIT_ASSERT( dir.SetTo(testDir1) == B_OK ); + while (dir.GetNextEntry(&entry) == B_OK) { + BPath path; + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + CPPUNIT_ASSERT( entry.GetPath(&path) == B_OK ); + CPPUNIT_ASSERT( testSet.test(path.Leaf()) == true ); + } + CPPUNIT_ASSERT( testSet.testDone() == true ); + CPPUNIT_ASSERT( dir.Rewind() == B_OK ); + dir.Unset(); + entry.Unset(); + testSet.rewind(); + // GetNextRef + nextSubTest(); + testSet.test("."); + testSet.test(".."); + CPPUNIT_ASSERT( dir.SetTo(testDir1) == B_OK ); + while (dir.GetNextRef(&ref) == B_OK) + CPPUNIT_ASSERT( testSet.test(ref.name) == true ); + CPPUNIT_ASSERT( testSet.testDone() == true ); + CPPUNIT_ASSERT( dir.Rewind() == B_OK ); + dir.Unset(); + entry.Unset(); + testSet.rewind(); + // GetNextDirents + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(testDir1) == B_OK ); + while (dir.GetNextDirents(ents, bufSize, 1) == 1) + CPPUNIT_ASSERT( testSet.test(ents->d_name) == true ); + CPPUNIT_ASSERT( testSet.testDone() == true ); + CPPUNIT_ASSERT( dir.Rewind() == B_OK ); + dir.Unset(); + entry.Unset(); + testSet.rewind(); + // CountEntries + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(testDir1) == B_OK ); + CPPUNIT_ASSERT( dir.CountEntries() == 9 ); + CPPUNIT_ASSERT( dir.GetNextRef(&ref) == B_OK ); + CPPUNIT_ASSERT( dir.CountEntries() == 9 ); + dir.Unset(); + + // 3. interleaving use of the different methods + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(testDir1) == B_OK ); + while (dir.GetNextDirents(ents, bufSize, 1) == 1) { + CPPUNIT_ASSERT( testSet.test(ents->d_name) == true ); + if (dir.GetNextRef(&ref) == B_OK) + CPPUNIT_ASSERT( testSet.test(ref.name) == true ); + if (dir.GetNextEntry(&entry) == B_OK) { + BPath path; + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + CPPUNIT_ASSERT( entry.GetPath(&path) == B_OK ); + CPPUNIT_ASSERT( testSet.test(path.Leaf()) == true ); + } + } + testSet.test(".", false); // in case they have been skipped + testSet.test("..", false); // + CPPUNIT_ASSERT( testSet.testDone() == true ); + CPPUNIT_ASSERT( dir.Rewind() == B_OK ); + dir.Unset(); + entry.Unset(); + testSet.rewind(); + + // 4. uninitialized BDirectory + nextSubTest(); + dir.Unset(); + // R5: unlike the others GetNextRef() returns B_NO_INIT + CPPUNIT_ASSERT( dir.GetNextEntry(&entry) == B_FILE_ERROR ); + CPPUNIT_ASSERT( equals(dir.GetNextRef(&ref), B_NO_INIT, B_FILE_ERROR) ); + CPPUNIT_ASSERT( dir.Rewind() == B_FILE_ERROR ); + CPPUNIT_ASSERT( dir.GetNextDirents(ents, bufSize, 1) == B_FILE_ERROR ); + CPPUNIT_ASSERT( dir.CountEntries() == B_FILE_ERROR ); + dir.Unset(); + + // 5. badly initialized BDirectory + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(nonExisting) == B_ENTRY_NOT_FOUND ); + // R5: unlike the others GetNextRef() returns B_NO_INIT + CPPUNIT_ASSERT( dir.GetNextEntry(&entry) == B_FILE_ERROR ); + CPPUNIT_ASSERT( equals(dir.GetNextRef(&ref), B_NO_INIT, B_FILE_ERROR) ); + CPPUNIT_ASSERT( dir.Rewind() == B_FILE_ERROR ); + CPPUNIT_ASSERT( dir.GetNextDirents(ents, bufSize, 1) == B_FILE_ERROR ); + CPPUNIT_ASSERT( dir.CountEntries() == B_FILE_ERROR ); + dir.Unset(); + + // 6. bad args +// R5 crashs, when passing a NULL BEntry or entry_ref +#if !SK_TEST_R5 + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo(testDir1) == B_OK ); + CPPUNIT_ASSERT( dir.GetNextEntry(NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( dir.GetNextRef(NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( equals(dir.GetNextDirents(NULL, bufSize, 1), + B_BAD_ADDRESS, B_BAD_VALUE) ); + dir.Unset(); +#endif + + // 7. link traversation + nextSubTest(); + execCommand(string("rm -rf ") + testDir1); + execCommand(string("mkdir ") + testDir1); + entryName = ("link1"); + execCommand(string("ln -s ") + existingFile + " " + + dirPathName + entryName); + CPPUNIT_ASSERT( dir.SetTo(testDir1) == B_OK ); + CPPUNIT_ASSERT( dir.GetNextEntry(&entry, true) == B_OK ); + BPath path; + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + BEntry entry2(existingFile); + CPPUNIT_ASSERT( entry2.InitCheck() == B_OK ); + CPPUNIT_ASSERT( entry == entry2 ); + dir.Unset(); + entry.Unset(); +} + +// EntryCreationTest +void +DirectoryTest::EntryCreationTest() +{ + const char *existingFile = existingFilename; + const char *existing = existingDirname; + const char *testDir1 = testDirname1; + // create a test directory + execCommand(string("mkdir ") + testDir1); + // 1. relative path + BDirectory dir(testDir1); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + // CreateDirectory + // dir doesn't already exist + nextSubTest(); + BDirectory subdir; + string dirPathName(string(testDir1) + "/"); + string entryName("subdir1"); + CPPUNIT_ASSERT( dir.CreateDirectory(entryName.c_str(), &subdir) == B_OK ); + CPPUNIT_ASSERT( subdir.InitCheck() == B_OK ); + BEntry entry; + CPPUNIT_ASSERT( subdir.GetEntry(&entry) == B_OK ); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + CPPUNIT_ASSERT( entry == BEntry((dirPathName + entryName).c_str()) ); + subdir.Unset(); + CPPUNIT_ASSERT( subdir.SetTo((dirPathName + entryName).c_str()) == B_OK ); + subdir.Unset(); + // dir does already exist + nextSubTest(); + CPPUNIT_ASSERT( dir.CreateDirectory(entryName.c_str(), &subdir) + == B_FILE_EXISTS ); + CPPUNIT_ASSERT( subdir.InitCheck() == B_NO_INIT ); + subdir.Unset(); + // CreateFile + // file doesn't already exist + nextSubTest(); + BFile file; + entryName = "file1"; + CPPUNIT_ASSERT( dir.CreateFile(entryName.c_str(), &file, true) == B_OK ); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + file.Unset(); + CPPUNIT_ASSERT( file.SetTo((dirPathName + entryName).c_str(), + B_READ_ONLY) == B_OK ); + file.Unset(); + // file does already exist, don't fail + nextSubTest(); + CPPUNIT_ASSERT( dir.CreateFile(entryName.c_str(), &file, false) == B_OK ); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + file.Unset(); + CPPUNIT_ASSERT( file.SetTo((dirPathName + entryName).c_str(), + B_READ_ONLY) == B_OK ); + file.Unset(); + // file does already exist, fail + nextSubTest(); + CPPUNIT_ASSERT( dir.CreateFile(entryName.c_str(), &file, true) + == B_FILE_EXISTS ); + CPPUNIT_ASSERT( file.InitCheck() == B_NO_INIT ); + file.Unset(); + // CreateSymLink + // link doesn't already exist + nextSubTest(); + BSymLink link; + entryName = "link1"; + CPPUNIT_ASSERT( dir.CreateSymLink(entryName.c_str(), existingFile, &link) + == B_OK ); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + link.Unset(); + CPPUNIT_ASSERT( link.SetTo((dirPathName + entryName).c_str()) == B_OK ); + link.Unset(); + // link does already exist + nextSubTest(); + CPPUNIT_ASSERT( dir.CreateSymLink(entryName.c_str(), existingFile, &link) + == B_FILE_EXISTS ); + CPPUNIT_ASSERT( link.InitCheck() == B_NO_INIT ); + link.Unset(); + + // 2. absolute path + dir.Unset(); + execCommand(string("rm -rf ") + testDir1); + execCommand(string("mkdir ") + testDir1); + CPPUNIT_ASSERT( dir.SetTo(existing) == B_OK ); + // CreateDirectory + // dir doesn't already exist + nextSubTest(); + entryName = dirPathName + "subdir1"; + CPPUNIT_ASSERT( dir.CreateDirectory(entryName.c_str(), &subdir) == B_OK ); + CPPUNIT_ASSERT( subdir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( subdir.GetEntry(&entry) == B_OK ); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + CPPUNIT_ASSERT( entry == BEntry(entryName.c_str()) ); + subdir.Unset(); + CPPUNIT_ASSERT( subdir.SetTo(entryName.c_str()) == B_OK ); + subdir.Unset(); + // dir does already exist + nextSubTest(); + CPPUNIT_ASSERT( dir.CreateDirectory(entryName.c_str(), &subdir) + == B_FILE_EXISTS ); + CPPUNIT_ASSERT( subdir.InitCheck() == B_NO_INIT ); + subdir.Unset(); + // CreateFile + // file doesn't already exist + nextSubTest(); + entryName = dirPathName + "file1"; + CPPUNIT_ASSERT( dir.CreateFile(entryName.c_str(), &file, true) == B_OK ); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + file.Unset(); + CPPUNIT_ASSERT( file.SetTo(entryName.c_str(), B_READ_ONLY) == B_OK ); + file.Unset(); + // file does already exist, don't fail + nextSubTest(); + CPPUNIT_ASSERT( dir.CreateFile(entryName.c_str(), &file, false) == B_OK ); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + file.Unset(); + CPPUNIT_ASSERT( file.SetTo(entryName.c_str(), B_READ_ONLY) == B_OK ); + file.Unset(); + // file does already exist, fail + nextSubTest(); + CPPUNIT_ASSERT( dir.CreateFile(entryName.c_str(), &file, true) + == B_FILE_EXISTS ); + CPPUNIT_ASSERT( file.InitCheck() == B_NO_INIT ); + file.Unset(); + // CreateSymLink + // link doesn't already exist + nextSubTest(); + entryName = dirPathName + "link1"; + CPPUNIT_ASSERT( dir.CreateSymLink(entryName.c_str(), existingFile, &link) + == B_OK ); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + link.Unset(); + CPPUNIT_ASSERT( link.SetTo(entryName.c_str()) == B_OK ); + link.Unset(); + // link does already exist + nextSubTest(); + CPPUNIT_ASSERT( dir.CreateSymLink(entryName.c_str(), existingFile, &link) + == B_FILE_EXISTS ); + CPPUNIT_ASSERT( link.InitCheck() == B_NO_INIT ); + link.Unset(); + + // 3. uninitialized BDirectory, absolute path + dir.Unset(); + execCommand(string("rm -rf ") + testDir1); + execCommand(string("mkdir ") + testDir1); + CPPUNIT_ASSERT( dir.InitCheck() == B_NO_INIT ); + // CreateDirectory + // dir doesn't already exist + nextSubTest(); + entryName = dirPathName + "subdir1"; + CPPUNIT_ASSERT( dir.CreateDirectory(entryName.c_str(), &subdir) == B_OK ); + CPPUNIT_ASSERT( subdir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( subdir.GetEntry(&entry) == B_OK ); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + CPPUNIT_ASSERT( entry == BEntry(entryName.c_str()) ); + subdir.Unset(); + CPPUNIT_ASSERT( subdir.SetTo(entryName.c_str()) == B_OK ); + subdir.Unset(); + // dir does already exist + nextSubTest(); + CPPUNIT_ASSERT( dir.CreateDirectory(entryName.c_str(), &subdir) + == B_FILE_EXISTS ); + CPPUNIT_ASSERT( subdir.InitCheck() == B_NO_INIT ); + subdir.Unset(); + // CreateFile + // file doesn't already exist + nextSubTest(); + entryName = dirPathName + "file1"; + CPPUNIT_ASSERT( dir.CreateFile(entryName.c_str(), &file, true) == B_OK ); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + file.Unset(); + CPPUNIT_ASSERT( file.SetTo(entryName.c_str(), B_READ_ONLY) == B_OK ); + file.Unset(); + // file does already exist, don't fail + nextSubTest(); + CPPUNIT_ASSERT( dir.CreateFile(entryName.c_str(), &file, false) == B_OK ); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + file.Unset(); + CPPUNIT_ASSERT( file.SetTo(entryName.c_str(), B_READ_ONLY) == B_OK ); + file.Unset(); + // file does already exist, fail + nextSubTest(); + CPPUNIT_ASSERT( dir.CreateFile(entryName.c_str(), &file, true) + == B_FILE_EXISTS ); + CPPUNIT_ASSERT( file.InitCheck() == B_NO_INIT ); + file.Unset(); + // CreateSymLink + // link doesn't already exist + nextSubTest(); + entryName = dirPathName + "link1"; + CPPUNIT_ASSERT( dir.CreateSymLink(entryName.c_str(), existingFile, &link) + == B_OK ); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + link.Unset(); + CPPUNIT_ASSERT( link.SetTo(entryName.c_str()) == B_OK ); + link.Unset(); + // link does already exist + nextSubTest(); + CPPUNIT_ASSERT( dir.CreateSymLink(entryName.c_str(), existingFile, &link) + == B_FILE_EXISTS ); + CPPUNIT_ASSERT( link.InitCheck() == B_NO_INIT ); + link.Unset(); + + // 4. uninitialized BDirectory, relative path, current directory + dir.Unset(); + execCommand(string("rm -rf ") + testDir1); + execCommand(string("mkdir ") + testDir1); + CPPUNIT_ASSERT( dir.InitCheck() == B_NO_INIT ); + chdir(testDir1); + // CreateDirectory + // dir doesn't already exist + nextSubTest(); + entryName = "subdir1"; + CPPUNIT_ASSERT( dir.CreateDirectory(entryName.c_str(), &subdir) == B_OK ); + CPPUNIT_ASSERT( subdir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( subdir.GetEntry(&entry) == B_OK ); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + CPPUNIT_ASSERT( entry == BEntry((dirPathName + entryName).c_str()) ); + subdir.Unset(); + CPPUNIT_ASSERT( subdir.SetTo((dirPathName + entryName).c_str()) == B_OK ); + subdir.Unset(); + // dir does already exist + nextSubTest(); + CPPUNIT_ASSERT( dir.CreateDirectory(entryName.c_str(), &subdir) + == B_FILE_EXISTS ); + CPPUNIT_ASSERT( subdir.InitCheck() == B_NO_INIT ); + subdir.Unset(); + // CreateFile + // file doesn't already exist + nextSubTest(); + entryName = "file1"; + CPPUNIT_ASSERT( dir.CreateFile(entryName.c_str(), &file, true) == B_OK ); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + file.Unset(); + CPPUNIT_ASSERT( file.SetTo((dirPathName + entryName).c_str(), + B_READ_ONLY) == B_OK ); + file.Unset(); + // file does already exist, don't fail + nextSubTest(); + CPPUNIT_ASSERT( dir.CreateFile(entryName.c_str(), &file, false) == B_OK ); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + file.Unset(); + CPPUNIT_ASSERT( file.SetTo((dirPathName + entryName).c_str(), + B_READ_ONLY) == B_OK ); + file.Unset(); + // file does already exist, fail + nextSubTest(); + CPPUNIT_ASSERT( dir.CreateFile(entryName.c_str(), &file, true) + == B_FILE_EXISTS ); + CPPUNIT_ASSERT( file.InitCheck() == B_NO_INIT ); + file.Unset(); + // CreateSymLink + // link doesn't already exist + nextSubTest(); + entryName = "link1"; + CPPUNIT_ASSERT( dir.CreateSymLink(entryName.c_str(), existingFile, &link) + == B_OK ); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + link.Unset(); + CPPUNIT_ASSERT( link.SetTo((dirPathName + entryName).c_str()) == B_OK ); + link.Unset(); + // link does already exist + nextSubTest(); + CPPUNIT_ASSERT( dir.CreateSymLink(entryName.c_str(), existingFile, &link) + == B_FILE_EXISTS ); + CPPUNIT_ASSERT( link.InitCheck() == B_NO_INIT ); + link.Unset(); + chdir("/"); + + // 5. bad args + dir.Unset(); + execCommand(string("rm -rf ") + testDir1); + execCommand(string("mkdir ") + testDir1); + CPPUNIT_ASSERT( dir.SetTo(testDir1) == B_OK ); + // CreateDirectory + nextSubTest(); + entryName = "subdir1"; + CPPUNIT_ASSERT( equals(dir.CreateDirectory(NULL, &subdir), + B_BAD_ADDRESS, B_BAD_VALUE) ); + CPPUNIT_ASSERT( subdir.InitCheck() == B_NO_INIT ); + subdir.Unset(); + // CreateFile + // R5: unlike CreateDirectory/SymLink() CreateFile() returns + // B_ENTRY_NOT_FOUND + nextSubTest(); + entryName = "file1"; + CPPUNIT_ASSERT( equals(dir.CreateFile(NULL, &file), B_ENTRY_NOT_FOUND, + B_BAD_VALUE) ); + CPPUNIT_ASSERT( file.InitCheck() == B_NO_INIT ); + file.Unset(); + // CreateSymLink + nextSubTest(); + entryName = "link1"; + CPPUNIT_ASSERT( equals(dir.CreateSymLink(NULL, existingFile, &link), + B_BAD_ADDRESS, B_BAD_VALUE) ); + CPPUNIT_ASSERT( link.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( equals(dir.CreateSymLink(entryName.c_str(), NULL, &link), + B_BAD_ADDRESS, B_BAD_VALUE) ); + CPPUNIT_ASSERT( link.InitCheck() == B_NO_INIT ); + link.Unset(); + + // 6. uninitialized BDirectory, absolute path, no second param + dir.Unset(); + execCommand(string("rm -rf ") + testDir1); + execCommand(string("mkdir ") + testDir1); + CPPUNIT_ASSERT( dir.InitCheck() == B_NO_INIT ); + // CreateDirectory + // dir doesn't already exist + nextSubTest(); + entryName = dirPathName + "subdir1"; + CPPUNIT_ASSERT( dir.CreateDirectory(entryName.c_str(), NULL) == B_OK ); + CPPUNIT_ASSERT( subdir.SetTo(entryName.c_str()) == B_OK ); + subdir.Unset(); + // dir does already exist + nextSubTest(); + CPPUNIT_ASSERT( dir.CreateDirectory(entryName.c_str(), NULL) + == B_FILE_EXISTS ); + subdir.Unset(); + // CreateFile + // file doesn't already exist + nextSubTest(); + entryName = dirPathName + "file1"; + CPPUNIT_ASSERT( dir.CreateFile(entryName.c_str(), NULL, true) == B_OK ); + CPPUNIT_ASSERT( file.SetTo(entryName.c_str(), B_READ_ONLY) == B_OK ); + file.Unset(); + // file does already exist, don't fail + nextSubTest(); + CPPUNIT_ASSERT( dir.CreateFile(entryName.c_str(), NULL, false) == B_OK ); + CPPUNIT_ASSERT( file.SetTo(entryName.c_str(), B_READ_ONLY) == B_OK ); + file.Unset(); + // file does already exist, fail + nextSubTest(); + CPPUNIT_ASSERT( dir.CreateFile(entryName.c_str(), NULL, true) + == B_FILE_EXISTS ); + // CreateSymLink + // link doesn't already exist + nextSubTest(); + entryName = dirPathName + "link1"; + CPPUNIT_ASSERT( dir.CreateSymLink(entryName.c_str(), existingFile, NULL) + == B_OK ); + CPPUNIT_ASSERT( link.SetTo(entryName.c_str()) == B_OK ); + link.Unset(); + // link does already exist + nextSubTest(); + CPPUNIT_ASSERT( dir.CreateSymLink(entryName.c_str(), existingFile, NULL) + == B_FILE_EXISTS ); +} + +// AssignmentTest +void +DirectoryTest::AssignmentTest() +{ + const char *existing = existingDirname; + // 1. copy constructor + // uninitialized + nextSubTest(); + { + BDirectory dir; + CPPUNIT_ASSERT( dir.InitCheck() == B_NO_INIT ); + BDirectory dir2(dir); + // R5 returns B_BAD_VALUE instead of B_NO_INIT + CPPUNIT_ASSERT( equals(dir2.InitCheck(), B_BAD_VALUE, B_NO_INIT) ); + } + // existing dir + nextSubTest(); + { + BDirectory dir(existing); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + BDirectory dir2(dir); + CPPUNIT_ASSERT( dir2.InitCheck() == B_OK ); + } + + // 2. assignment operator + // uninitialized + nextSubTest(); + { + BDirectory dir; + BDirectory dir2; + dir2 = dir; + // R5 returns B_BAD_VALUE instead of B_NO_INIT + CPPUNIT_ASSERT( equals(dir2.InitCheck(), B_BAD_VALUE, B_NO_INIT) ); + } + nextSubTest(); + { + BDirectory dir; + BDirectory dir2(existing); + CPPUNIT_ASSERT( dir2.InitCheck() == B_OK ); + dir2 = dir; + // R5 returns B_BAD_VALUE instead of B_NO_INIT + CPPUNIT_ASSERT( equals(dir2.InitCheck(), B_BAD_VALUE, B_NO_INIT) ); + } + // existing dir + nextSubTest(); + { + BDirectory dir(existing); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + BDirectory dir2; + dir2 = dir; + CPPUNIT_ASSERT( dir2.InitCheck() == B_OK ); + } +} + +// CreateDirectoryTest +void +DirectoryTest::CreateDirectoryTest() +{ + const char *existingFile = existingFilename; + const char *testDir1 = testDirname1; + const char *dirLink = dirLinkname; + const char *fileLink = fileLinkname; + // 1. absolute path + execCommand(string("mkdir ") + testDir1); + // two levels + nextSubTest(); + string dirPathName(string(testDir1) + "/"); + string entryName(dirPathName + "subdir1/subdir1.1"); + CPPUNIT_ASSERT( create_directory(entryName.c_str(), 0x1ff) == B_OK ); + BDirectory subdir; + CPPUNIT_ASSERT( subdir.SetTo(entryName.c_str()) == B_OK ); + subdir.Unset(); + // one level + nextSubTest(); + entryName = dirPathName + "subdir2"; + CPPUNIT_ASSERT( create_directory(entryName.c_str(), 0x1ff) == B_OK ); + CPPUNIT_ASSERT( subdir.SetTo(entryName.c_str()) == B_OK ); + subdir.Unset(); + // existing dir + nextSubTest(); + entryName = dirPathName; + CPPUNIT_ASSERT( create_directory(entryName.c_str(), 0x1ff) == B_OK ); + CPPUNIT_ASSERT( subdir.SetTo(entryName.c_str()) == B_OK ); + subdir.Unset(); + + // 2. relative path + execCommand(string("rm -rf ") + testDir1); + execCommand(string("mkdir ") + testDir1); + chdir(testDir1); + // two levels + nextSubTest(); + entryName = "subdir1/subdir1.1"; + CPPUNIT_ASSERT( create_directory(entryName.c_str(), 0x1ff) == B_OK ); + CPPUNIT_ASSERT( subdir.SetTo(entryName.c_str()) == B_OK ); + subdir.Unset(); + // one level + nextSubTest(); + entryName = "subdir2"; + CPPUNIT_ASSERT( create_directory(entryName.c_str(), 0x1ff) == B_OK ); + CPPUNIT_ASSERT( subdir.SetTo(entryName.c_str()) == B_OK ); + subdir.Unset(); + // existing dir + nextSubTest(); + entryName = "."; + CPPUNIT_ASSERT( create_directory(entryName.c_str(), 0x1ff) == B_OK ); + CPPUNIT_ASSERT( subdir.SetTo(entryName.c_str()) == B_OK ); + subdir.Unset(); + chdir("/"); + + // 3. error cases + // existing file/link + nextSubTest(); + CPPUNIT_ASSERT( equals(create_directory(existingFile, 0x1ff), B_BAD_VALUE, + B_NOT_A_DIRECTORY) ); + CPPUNIT_ASSERT( equals(create_directory(fileLink, 0x1ff), B_BAD_VALUE, + B_NOT_A_DIRECTORY) ); + CPPUNIT_ASSERT( create_directory(dirLink, 0x1ff) == B_OK ); + // bad args + nextSubTest(); + CPPUNIT_ASSERT( create_directory(NULL, 0x1ff) == B_BAD_VALUE ); +} + diff --git a/src/tests/kits/storage/DirectoryTest.h b/src/tests/kits/storage/DirectoryTest.h new file mode 100644 index 0000000000..465e63022b --- /dev/null +++ b/src/tests/kits/storage/DirectoryTest.h @@ -0,0 +1,43 @@ +// DirectoryTest.h + +#ifndef __sk_directory_test_h__ +#define __sk_directory_test_h__ + +#include + +#include +#include + +#include "NodeTest.h" + +class DirectoryTest : public NodeTest +{ +public: + static Test* Suite(); + + virtual void CreateRONodes(TestNodes& testEntries); + virtual void CreateRWNodes(TestNodes& testEntries); + virtual void CreateUninitializedNodes(TestNodes& testEntries); + + // This function is called before *each* test added in Suite() + void setUp(); + + // This function is called after *each* test added in Suite() + void tearDown(); + + // test methods + + void InitTest1(); + void InitTest2(); + void GetEntryTest(); + void IsRootTest(); + void FindEntryTest(); + void ContainsTest(); + void GetStatForTest(); + void EntryIterationTest(); + void EntryCreationTest(); + void AssignmentTest(); + void CreateDirectoryTest(); +}; + +#endif // __sk_directory_test_h__ diff --git a/src/tests/kits/storage/EntryTest.cpp b/src/tests/kits/storage/EntryTest.cpp new file mode 100644 index 0000000000..9d1a66820a --- /dev/null +++ b/src/tests/kits/storage/EntryTest.cpp @@ -0,0 +1,2672 @@ +// EntryTest.cpp + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +enum test_entry_kind { + DIR_ENTRY, + FILE_ENTRY, + LINK_ENTRY, + ABSTRACT_ENTRY, + BAD_ENTRY, +}; + +struct TestEntry { + TestEntry(); + + void init(TestEntry &super, string name, test_entry_kind kind, + bool relative = false); + void initDir(TestEntry &super, string name); + void initFile(TestEntry &super, string name); + void initRLink(TestEntry &super, string name, TestEntry &target); + void initALink(TestEntry &super, string name, TestEntry &target); + void initPath(const char *pathName = NULL); + void completeInit(); + bool isConcrete() const { return !(isAbstract() || isBad()); } + bool isAbstract() const { return kind == ABSTRACT_ENTRY; } + bool isBad() const { return kind == BAD_ENTRY; } + const entry_ref &get_ref(); + + TestEntry * super; + string name; + test_entry_kind kind; + string path; + TestEntry * target; + string link; + entry_ref ref; + bool relative; + // C strings + const char * cname; + const char * cpath; + const char * clink; +}; + +static list allTestEntries; + +static TestEntry badTestEntry; +static TestEntry testDir; +static TestEntry dir1; +static TestEntry dir2; +static TestEntry file1; +static TestEntry file2; +static TestEntry file3; +static TestEntry file4; +static TestEntry subDir1; +static TestEntry abstractEntry1; +static TestEntry badEntry1; +static TestEntry absDirLink1; +static TestEntry absDirLink2; +static TestEntry absDirLink3; +static TestEntry absDirLink4; +static TestEntry relDirLink1; +static TestEntry relDirLink2; +static TestEntry relDirLink3; +static TestEntry relDirLink4; +static TestEntry absFileLink1; +static TestEntry absFileLink2; +static TestEntry absFileLink3; +static TestEntry absFileLink4; +static TestEntry relFileLink1; +static TestEntry relFileLink2; +static TestEntry relFileLink3; +static TestEntry relFileLink4; +static TestEntry absCyclicLink1; +static TestEntry absCyclicLink2; +static TestEntry relCyclicLink1; +static TestEntry relCyclicLink2; +static TestEntry absBadLink1; +static TestEntry absBadLink2; +static TestEntry absBadLink3; +static TestEntry absBadLink4; +static TestEntry relBadLink1; +static TestEntry relBadLink2; +static TestEntry relBadLink3; +static TestEntry relBadLink4; +static TestEntry absVeryBadLink1; +static TestEntry absVeryBadLink2; +static TestEntry absVeryBadLink3; +static TestEntry absVeryBadLink4; +static TestEntry relVeryBadLink1; +static TestEntry relVeryBadLink2; +static TestEntry relVeryBadLink3; +static TestEntry relVeryBadLink4; +static TestEntry tooLongEntry1; +static TestEntry tooLongDir1; +static TestEntry tooLongDir2; +static TestEntry tooLongDir3; +static TestEntry tooLongDir4; +static TestEntry tooLongDir5; +static TestEntry tooLongDir6; +static TestEntry tooLongDir7; +static TestEntry tooLongDir8; +static TestEntry tooLongDir9; +static TestEntry tooLongDir10; +static TestEntry tooLongDir11; +static TestEntry tooLongDir12; +static TestEntry tooLongDir13; +static TestEntry tooLongDir14; +static TestEntry tooLongDir15; +static TestEntry tooLongDir16; + +static string setUpCommandLine; +static string tearDownCommandLine; + +// forward declarations +static TestEntry *resolve_link(TestEntry *entry); +static string get_shortest_relative_path(TestEntry *dir, TestEntry *entry); + +static const status_t kErrors[] = { + B_BAD_ADDRESS, + B_BAD_VALUE, + B_CROSS_DEVICE_LINK, + B_DEVICE_FULL, + B_DIRECTORY_NOT_EMPTY, + B_ENTRY_NOT_FOUND, + B_ERROR, + B_FILE_ERROR, + B_FILE_EXISTS, + B_FILE_NOT_FOUND, + B_IS_A_DIRECTORY, + B_LINK_LIMIT, + B_NAME_TOO_LONG, + B_NO_MORE_FDS, + B_NOT_A_DIRECTORY, + B_OK, + B_PARTITION_TOO_SMALL, + B_READ_ONLY_DEVICE, + B_UNSUPPORTED, + E2BIG +}; +static const int32 kErrorCount = sizeof(kErrors) / sizeof(status_t); + +// get_error_index +static +int32 +get_error_index(status_t error) +{ + int32 result = -1; + for (int32 i = 0; result == -1 && i < kErrorCount; i++) { + if (kErrors[i] == error) + result = i; + } + if (result == -1) + printf("WARNING: error %lx is not in the list of errors\n", error); + return result; +} + +// fuzzy_error +static +status_t +fuzzy_error(status_t error1, status_t error2) +{ + status_t result = error1; + // encode the two errors in one value + int32 index1 = get_error_index(error1); + int32 index2 = get_error_index(error2); + if (index1 >= 0 && index2 >= 0) + result = index1 * kErrorCount + index2 + 1; + return result; +} + +// fuzzy_equals +static +bool +fuzzy_equals(status_t error, status_t fuzzyError) +{ + bool result = false; + if (fuzzyError <= 0) + result = (error == fuzzyError); + else { + // decode the error + int32 index1 = (fuzzyError - 1) / kErrorCount; + int32 index2 = (fuzzyError - 1) % kErrorCount; + if (index1 >= kErrorCount) + printf("WARNING: bad fuzzy error: %lx\n", fuzzyError); + else { + status_t error1 = kErrors[index1]; + status_t error2 = kErrors[index2]; + result = (error == error1 || error == error2); + } + } + return result; +} + + +// Suite +CppUnit::Test* +EntryTest::Suite() +{ + CppUnit::TestSuite *suite = new CppUnit::TestSuite(); + typedef CppUnit::TestCaller TC; + + StatableTest::AddBaseClassTests("BEntry::", suite); + + suite->addTest( new TC("BEntry::Init Test1", &EntryTest::InitTest1) ); + suite->addTest( new TC("BEntry::Init Test2", &EntryTest::InitTest2) ); + suite->addTest( new TC("BEntry::Special cases for Exists(), GetPath(),...", + &EntryTest::SpecialGetCasesTest) ); + suite->addTest( new TC("BEntry::Rename Test", &EntryTest::RenameTest) ); + suite->addTest( new TC("BEntry::MoveTo Test", &EntryTest::MoveToTest) ); + suite->addTest( new TC("BEntry::Remove Test", &EntryTest::RemoveTest) ); + suite->addTest( new TC("BEntry::Comparison Test", + &EntryTest::ComparisonTest) ); + suite->addTest( new TC("BEntry::Assignment Test", + &EntryTest::AssignmentTest) ); + suite->addTest( new TC("BEntry::C Functions Test", + &EntryTest::CFunctionsTest) ); +// suite->addTest( new TC("BEntry::Miscellaneous Test", &EntryTest::MiscTest) ); + + return suite; +} + +// CreateROStatables +void +EntryTest::CreateROStatables(TestStatables& testEntries) +{ + CreateRWStatables(testEntries); +} + +// CreateRWStatables +void +EntryTest::CreateRWStatables(TestStatables& testStatables) +{ + TestEntry *testEntries[] = { + &dir1, &dir2, &file1, &subDir1, + &absDirLink1, &absDirLink2, &absDirLink3, &absDirLink4, + &relDirLink1, &relDirLink2, &relDirLink3, &relDirLink4, + &absFileLink1, &absFileLink2, &absFileLink3, &absFileLink4, + &relFileLink1, &relFileLink2, &relFileLink3, &relFileLink4, + &absBadLink1, &absBadLink2, &absBadLink3, &absBadLink4, + &relBadLink1, &relBadLink2, &relBadLink3, &relBadLink4, + &absVeryBadLink1, &absVeryBadLink2, &absVeryBadLink3, &absVeryBadLink4, + &relVeryBadLink1, &relVeryBadLink2, &relVeryBadLink3, &relVeryBadLink4 + }; + int32 testEntryCount = sizeof(testEntries) / sizeof(TestEntry*); + for (int32 i = 0; i < testEntryCount; i++) { + TestEntry *testEntry = testEntries[i]; + const char *filename = testEntry->cpath; + testStatables.add(new BEntry(filename), filename); + } +} + +// CreateUninitializedStatables +void +EntryTest::CreateUninitializedStatables(TestStatables& testEntries) +{ + testEntries.add(new BEntry, ""); +} + +// setUp +void +EntryTest::setUp() +{ + StatableTest::setUp(); + execCommand(setUpCommandLine); +} + +// tearDown +void +EntryTest::tearDown() +{ + StatableTest::tearDown(); + execCommand(tearDownCommandLine); +} + +// examine_entry +static +void +examine_entry(BEntry &entry, TestEntry *testEntry, bool traverse) +{ + if (traverse) + testEntry = resolve_link(testEntry); + // Exists() + CPPUNIT_ASSERT( entry.Exists() == testEntry->isConcrete() ); + // GetPath() + BPath path; + CPPUNIT_ASSERT( entry.GetPath(&path) == B_OK ); + CPPUNIT_ASSERT( path == testEntry->cpath ); + // GetName() + char name[B_FILE_NAME_LENGTH + 1]; + CPPUNIT_ASSERT( entry.GetName(name) == B_OK ); + CPPUNIT_ASSERT( testEntry->name == name ); + // GetParent(BEntry *) + BEntry parentEntry; + CPPUNIT_ASSERT( entry.GetParent(&parentEntry) == B_OK ); + CPPUNIT_ASSERT( parentEntry.InitCheck() == B_OK ); + CPPUNIT_ASSERT( parentEntry.GetPath(&path) == B_OK ); + CPPUNIT_ASSERT( path == testEntry->super->cpath ); + parentEntry.Unset(); + path.Unset(); + // GetParent(BDirectory *) + BDirectory parentDir; + CPPUNIT_ASSERT( entry.GetParent(&parentDir) == B_OK ); + CPPUNIT_ASSERT( parentDir.GetEntry(&parentEntry) == B_OK ); + CPPUNIT_ASSERT( parentEntry.InitCheck() == B_OK ); + CPPUNIT_ASSERT( parentEntry.GetPath(&path) == B_OK ); + CPPUNIT_ASSERT( path == testEntry->super->cpath ); + // GetRef() + entry_ref ref; + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + // We can't get a ref of an entry with a too long path name yet. + if (testEntry->path.length() < B_PATH_NAME_LENGTH) + CPPUNIT_ASSERT( ref == testEntry->get_ref() ); +} + +// InitTest1Paths +void +EntryTest::InitTest1Paths(TestEntry &_testEntry, status_t error, bool traverse) +{ + TestEntry *testEntry = &_testEntry; + // absolute path + nextSubTest(); + { +//printf("%s\n", testEntry->cpath); + BEntry entry(testEntry->cpath, traverse); + status_t result = entry.InitCheck(); +if (!fuzzy_equals(result, error)) +printf("error: %lx (%lx)\n", result, error); + CPPUNIT_ASSERT( fuzzy_equals(result, error) ); + if (result == B_OK) + examine_entry(entry, testEntry, traverse); + } + // relative path + nextSubTest(); + { +//printf("%s\n", testEntry->cpath); + if (chdir(testEntry->super->cpath) == 0) { + BEntry entry(testEntry->cname, traverse); + status_t result = entry.InitCheck(); +if (!fuzzy_equals(result, error)) +printf("error: %lx (%lx)\n", result, error); + CPPUNIT_ASSERT( fuzzy_equals(result, error) ); + if (error == B_OK) + examine_entry(entry, testEntry, traverse); + RestoreCWD(); + } + } +} + +// InitTest1Refs +void +EntryTest::InitTest1Refs(TestEntry &_testEntry, status_t error, bool traverse) +{ + TestEntry *testEntry = &_testEntry; + // absolute path + nextSubTest(); + { +//printf("%s\n", testEntry->cpath); + BEntry entry(&testEntry->get_ref(), traverse); + status_t result = entry.InitCheck(); +if (!fuzzy_equals(result, error)) +printf("error: %lx (%lx)\n", result, error); + CPPUNIT_ASSERT( fuzzy_equals(result, error) ); + if (error == B_OK) + examine_entry(entry, testEntry, traverse); + } +} + +// InitTest1DirPaths +void +EntryTest::InitTest1DirPaths(TestEntry &_testEntry, status_t error, + bool traverse) +{ + TestEntry *testEntry = &_testEntry; + // absolute path + nextSubTest(); + { + if (!testEntry->isBad() + && testEntry->path.length() < B_PATH_NAME_LENGTH) { +//printf("%s\n", testEntry->cpath); + BDirectory dir("/boot/home/Desktop"); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + BEntry entry(&dir, testEntry->cpath, traverse); + status_t result = entry.InitCheck(); +if (!fuzzy_equals(result, error)) +printf("error: %lx (%lx)\n", result, error); + CPPUNIT_ASSERT( fuzzy_equals(result, error) ); + if (error == B_OK) + examine_entry(entry, testEntry, traverse); + } + } + // relative path (one level) + nextSubTest(); + { + if (!testEntry->isBad() + && testEntry->super->path.length() < B_PATH_NAME_LENGTH) { +//printf("%s + %s\n", testEntry->super->cpath, testEntry->cname); + BDirectory dir(testEntry->super->cpath); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + BEntry entry(&dir, testEntry->cname, traverse); + status_t result = entry.InitCheck(); +if (!fuzzy_equals(result, error)) +printf("error: %lx (%lx)\n", result, error); + CPPUNIT_ASSERT( fuzzy_equals(result, error) ); + if (error == B_OK) + examine_entry(entry, testEntry, traverse); + } + } + // relative path (two levels) + nextSubTest(); + { + if (!testEntry->super->isBad() && !testEntry->super->super->isBad()) { + string entryName = testEntry->super->name + "/" + testEntry->name; +//printf("%s + %s\n", testEntry->super->super->cpath, entryName.c_str()); + BDirectory dir(testEntry->super->super->cpath); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + BEntry entry(&dir, entryName.c_str(), traverse); + status_t result = entry.InitCheck(); +if (!fuzzy_equals(result, error)) +printf("error: %lx (%lx)\n", result, error); + CPPUNIT_ASSERT( fuzzy_equals(result, error) ); + if (error == B_OK) + examine_entry(entry, testEntry, traverse); + } + } +} + +// InitTest1 +void +EntryTest::InitTest1() +{ + // 1. default constructor + nextSubTest(); + { + BEntry entry; + CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT ); + } + + // 2. BEntry(const char *, bool) + // don't traverse + InitTest1Paths(dir1, B_OK); + InitTest1Paths(dir2, B_OK); + InitTest1Paths(file1, B_OK); + InitTest1Paths(subDir1, B_OK); + InitTest1Paths(abstractEntry1, B_OK); + InitTest1Paths(badEntry1, B_ENTRY_NOT_FOUND); + InitTest1Paths(absDirLink1, B_OK); + InitTest1Paths(absDirLink2, B_OK); + InitTest1Paths(absDirLink3, B_OK); + InitTest1Paths(absDirLink4, B_OK); + InitTest1Paths(relDirLink1, B_OK); + InitTest1Paths(relDirLink2, B_OK); + InitTest1Paths(relDirLink3, B_OK); + InitTest1Paths(relDirLink4, B_OK); + InitTest1Paths(absFileLink1, B_OK); + InitTest1Paths(absFileLink2, B_OK); + InitTest1Paths(absFileLink3, B_OK); + InitTest1Paths(absFileLink4, B_OK); + InitTest1Paths(relFileLink1, B_OK); + InitTest1Paths(relFileLink2, B_OK); + InitTest1Paths(relFileLink3, B_OK); + InitTest1Paths(relFileLink4, B_OK); + InitTest1Paths(absCyclicLink1, B_OK); + InitTest1Paths(relCyclicLink1, B_OK); + InitTest1Paths(absBadLink1, B_OK); + InitTest1Paths(absBadLink2, B_OK); + InitTest1Paths(absBadLink3, B_OK); + InitTest1Paths(absBadLink4, B_OK); + InitTest1Paths(relBadLink1, B_OK); + InitTest1Paths(relBadLink2, B_OK); + InitTest1Paths(relBadLink3, B_OK); + InitTest1Paths(relBadLink4, B_OK); + InitTest1Paths(absVeryBadLink1, B_OK); + InitTest1Paths(absVeryBadLink2, B_OK); + InitTest1Paths(absVeryBadLink3, B_OK); + InitTest1Paths(absVeryBadLink4, B_OK); + InitTest1Paths(relVeryBadLink1, B_OK); + InitTest1Paths(relVeryBadLink2, B_OK); + InitTest1Paths(relVeryBadLink3, B_OK); + InitTest1Paths(relVeryBadLink4, B_OK); +// R5: returns E2BIG instead of B_NAME_TOO_LONG + InitTest1Paths(tooLongEntry1, fuzzy_error(E2BIG, B_NAME_TOO_LONG)); +// R5: returns B_ERROR instead of B_NAME_TOO_LONG + InitTest1Paths(tooLongDir16, fuzzy_error(B_ERROR, B_NAME_TOO_LONG)); + // traverse + InitTest1Paths(dir1, B_OK, true); + InitTest1Paths(dir2, B_OK, true); + InitTest1Paths(file1, B_OK, true); + InitTest1Paths(subDir1, B_OK, true); + InitTest1Paths(abstractEntry1, B_OK, true); + InitTest1Paths(badEntry1, B_ENTRY_NOT_FOUND, true); + InitTest1Paths(absDirLink1, B_OK, true); + InitTest1Paths(absDirLink2, B_OK, true); + InitTest1Paths(absDirLink3, B_OK, true); + InitTest1Paths(absDirLink4, B_OK, true); + InitTest1Paths(relDirLink1, B_OK, true); + InitTest1Paths(relDirLink2, B_OK, true); + InitTest1Paths(relDirLink3, B_OK, true); + InitTest1Paths(relDirLink4, B_OK, true); + InitTest1Paths(absFileLink1, B_OK, true); + InitTest1Paths(absFileLink2, B_OK, true); + InitTest1Paths(absFileLink3, B_OK, true); + InitTest1Paths(absFileLink4, B_OK, true); + InitTest1Paths(relFileLink1, B_OK, true); + InitTest1Paths(relFileLink2, B_OK, true); + InitTest1Paths(relFileLink3, B_OK, true); + InitTest1Paths(relFileLink4, B_OK, true); + InitTest1Paths(absCyclicLink1, B_LINK_LIMIT, true); + InitTest1Paths(relCyclicLink1, B_LINK_LIMIT, true); + InitTest1Paths(absBadLink1, B_ENTRY_NOT_FOUND, true); + InitTest1Paths(absBadLink2, B_ENTRY_NOT_FOUND, true); + InitTest1Paths(absBadLink3, B_ENTRY_NOT_FOUND, true); + InitTest1Paths(absBadLink4, B_ENTRY_NOT_FOUND, true); + InitTest1Paths(relBadLink1, B_ENTRY_NOT_FOUND, true); + InitTest1Paths(relBadLink2, B_ENTRY_NOT_FOUND, true); + InitTest1Paths(relBadLink3, B_ENTRY_NOT_FOUND, true); + InitTest1Paths(relBadLink4, B_ENTRY_NOT_FOUND, true); + InitTest1Paths(absVeryBadLink1, B_ENTRY_NOT_FOUND, true); + InitTest1Paths(absVeryBadLink2, B_ENTRY_NOT_FOUND, true); + InitTest1Paths(absVeryBadLink3, B_ENTRY_NOT_FOUND, true); + InitTest1Paths(absVeryBadLink4, B_ENTRY_NOT_FOUND, true); + InitTest1Paths(relVeryBadLink1, B_ENTRY_NOT_FOUND, true); + InitTest1Paths(relVeryBadLink2, B_ENTRY_NOT_FOUND, true); + InitTest1Paths(relVeryBadLink3, B_ENTRY_NOT_FOUND, true); + InitTest1Paths(relVeryBadLink4, B_ENTRY_NOT_FOUND, true); +// R5: returns E2BIG instead of B_NAME_TOO_LONG + InitTest1Paths(tooLongEntry1, fuzzy_error(E2BIG, B_NAME_TOO_LONG), true); +// R5: returns B_ERROR instead of B_NAME_TOO_LONG + InitTest1Paths(tooLongDir16, fuzzy_error(B_ERROR, B_NAME_TOO_LONG), true); + + // special cases (root dir) + nextSubTest(); + { + BEntry entry("/"); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + } + // special cases (fs root dir) + nextSubTest(); + { + BEntry entry("/boot"); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + } + // bad args + nextSubTest(); + { + BEntry entry((const char*)NULL); + CPPUNIT_ASSERT( entry.InitCheck() == B_BAD_VALUE ); + } + + // 3. BEntry(const entry_ref *, bool) + // don't traverse + InitTest1Refs(dir1, B_OK); + InitTest1Refs(dir2, B_OK); + InitTest1Refs(file1, B_OK); + InitTest1Refs(subDir1, B_OK); + InitTest1Refs(abstractEntry1, B_OK); + InitTest1Refs(absDirLink1, B_OK); + InitTest1Refs(absDirLink2, B_OK); + InitTest1Refs(absDirLink3, B_OK); + InitTest1Refs(absDirLink4, B_OK); + InitTest1Refs(relDirLink1, B_OK); + InitTest1Refs(relDirLink2, B_OK); + InitTest1Refs(relDirLink3, B_OK); + InitTest1Refs(relDirLink4, B_OK); + InitTest1Refs(absFileLink1, B_OK); + InitTest1Refs(absFileLink2, B_OK); + InitTest1Refs(absFileLink3, B_OK); + InitTest1Refs(absFileLink4, B_OK); + InitTest1Refs(relFileLink1, B_OK); + InitTest1Refs(relFileLink2, B_OK); + InitTest1Refs(relFileLink3, B_OK); + InitTest1Refs(relFileLink4, B_OK); + InitTest1Refs(absCyclicLink1, B_OK); + InitTest1Refs(relCyclicLink1, B_OK); + InitTest1Refs(absBadLink1, B_OK); + InitTest1Refs(absBadLink2, B_OK); + InitTest1Refs(absBadLink3, B_OK); + InitTest1Refs(absBadLink4, B_OK); + InitTest1Refs(relBadLink1, B_OK); + InitTest1Refs(relBadLink2, B_OK); + InitTest1Refs(relBadLink3, B_OK); + InitTest1Refs(relBadLink4, B_OK); + InitTest1Refs(absVeryBadLink1, B_OK); + InitTest1Refs(absVeryBadLink2, B_OK); + InitTest1Refs(absVeryBadLink3, B_OK); + InitTest1Refs(absVeryBadLink4, B_OK); + InitTest1Refs(relVeryBadLink1, B_OK); + InitTest1Refs(relVeryBadLink2, B_OK); + InitTest1Refs(relVeryBadLink3, B_OK); + InitTest1Refs(relVeryBadLink4, B_OK); + // traverse + InitTest1Refs(dir1, B_OK, true); + InitTest1Refs(dir2, B_OK, true); + InitTest1Refs(file1, B_OK, true); + InitTest1Refs(subDir1, B_OK, true); + InitTest1Refs(abstractEntry1, B_OK, true); + InitTest1Refs(absDirLink1, B_OK, true); + InitTest1Refs(absDirLink2, B_OK, true); + InitTest1Refs(absDirLink3, B_OK, true); + InitTest1Refs(absDirLink4, B_OK, true); + InitTest1Refs(relDirLink1, B_OK, true); + InitTest1Refs(relDirLink2, B_OK, true); + InitTest1Refs(relDirLink3, B_OK, true); + InitTest1Refs(relDirLink4, B_OK, true); + InitTest1Refs(absFileLink1, B_OK, true); + InitTest1Refs(absFileLink2, B_OK, true); + InitTest1Refs(absFileLink3, B_OK, true); + InitTest1Refs(absFileLink4, B_OK, true); + InitTest1Refs(relFileLink1, B_OK, true); + InitTest1Refs(relFileLink2, B_OK, true); + InitTest1Refs(relFileLink3, B_OK, true); + InitTest1Refs(relFileLink4, B_OK, true); + InitTest1Refs(absCyclicLink1, B_LINK_LIMIT, true); + InitTest1Refs(relCyclicLink1, B_LINK_LIMIT, true); + InitTest1Refs(absBadLink1, B_ENTRY_NOT_FOUND, true); + InitTest1Refs(absBadLink2, B_ENTRY_NOT_FOUND, true); + InitTest1Refs(absBadLink3, B_ENTRY_NOT_FOUND, true); + InitTest1Refs(absBadLink4, B_ENTRY_NOT_FOUND, true); + InitTest1Refs(relBadLink1, B_ENTRY_NOT_FOUND, true); + InitTest1Refs(relBadLink2, B_ENTRY_NOT_FOUND, true); + InitTest1Refs(relBadLink3, B_ENTRY_NOT_FOUND, true); + InitTest1Refs(relBadLink4, B_ENTRY_NOT_FOUND, true); + InitTest1Refs(absVeryBadLink1, B_ENTRY_NOT_FOUND, true); + InitTest1Refs(absVeryBadLink2, B_ENTRY_NOT_FOUND, true); + InitTest1Refs(absVeryBadLink3, B_ENTRY_NOT_FOUND, true); + InitTest1Refs(absVeryBadLink4, B_ENTRY_NOT_FOUND, true); + InitTest1Refs(relVeryBadLink1, B_ENTRY_NOT_FOUND, true); + InitTest1Refs(relVeryBadLink2, B_ENTRY_NOT_FOUND, true); + InitTest1Refs(relVeryBadLink3, B_ENTRY_NOT_FOUND, true); + InitTest1Refs(relVeryBadLink4, B_ENTRY_NOT_FOUND, true); + // bad args + nextSubTest(); + { + BEntry entry((const entry_ref*)NULL); + CPPUNIT_ASSERT( entry.InitCheck() == B_BAD_VALUE ); + } + + // 4. BEntry(const BDirectory *, const char *, bool) + // don't traverse + InitTest1DirPaths(dir1, B_OK); + InitTest1DirPaths(dir2, B_OK); + InitTest1DirPaths(file1, B_OK); + InitTest1DirPaths(subDir1, B_OK); + InitTest1DirPaths(abstractEntry1, B_OK); + InitTest1DirPaths(badEntry1, B_ENTRY_NOT_FOUND); + InitTest1DirPaths(absDirLink1, B_OK); + InitTest1DirPaths(absDirLink2, B_OK); + InitTest1DirPaths(absDirLink3, B_OK); + InitTest1DirPaths(absDirLink4, B_OK); + InitTest1DirPaths(relDirLink1, B_OK); + InitTest1DirPaths(relDirLink2, B_OK); + InitTest1DirPaths(relDirLink3, B_OK); + InitTest1DirPaths(relDirLink4, B_OK); + InitTest1DirPaths(absFileLink1, B_OK); + InitTest1DirPaths(absFileLink2, B_OK); + InitTest1DirPaths(absFileLink3, B_OK); + InitTest1DirPaths(absFileLink4, B_OK); + InitTest1DirPaths(relFileLink1, B_OK); + InitTest1DirPaths(relFileLink2, B_OK); + InitTest1DirPaths(relFileLink3, B_OK); + InitTest1DirPaths(relFileLink4, B_OK); + InitTest1DirPaths(absCyclicLink1, B_OK); + InitTest1DirPaths(relCyclicLink1, B_OK); + InitTest1DirPaths(absBadLink1, B_OK); + InitTest1DirPaths(absBadLink2, B_OK); + InitTest1DirPaths(absBadLink3, B_OK); + InitTest1DirPaths(absBadLink4, B_OK); + InitTest1DirPaths(relBadLink1, B_OK); + InitTest1DirPaths(relBadLink2, B_OK); + InitTest1DirPaths(relBadLink3, B_OK); + InitTest1DirPaths(relBadLink4, B_OK); + InitTest1DirPaths(absVeryBadLink1, B_OK); + InitTest1DirPaths(absVeryBadLink2, B_OK); + InitTest1DirPaths(absVeryBadLink3, B_OK); + InitTest1DirPaths(absVeryBadLink4, B_OK); + InitTest1DirPaths(relVeryBadLink1, B_OK); + InitTest1DirPaths(relVeryBadLink2, B_OK); + InitTest1DirPaths(relVeryBadLink3, B_OK); + InitTest1DirPaths(relVeryBadLink4, B_OK); +// R5: returns E2BIG instead of B_NAME_TOO_LONG + InitTest1DirPaths(tooLongEntry1, fuzzy_error(E2BIG, B_NAME_TOO_LONG)); +// OBOS: Fails, because the implementation concatenates the dir and leaf +// name. +#if !SK_TEST_OBOS_POSIX + InitTest1DirPaths(tooLongDir16, B_OK, true); +#endif + // traverse + InitTest1DirPaths(dir1, B_OK, true); + InitTest1DirPaths(dir2, B_OK, true); + InitTest1DirPaths(file1, B_OK, true); + InitTest1DirPaths(subDir1, B_OK, true); + InitTest1DirPaths(abstractEntry1, B_OK, true); + InitTest1DirPaths(badEntry1, B_ENTRY_NOT_FOUND, true); + InitTest1DirPaths(absDirLink1, B_OK, true); + InitTest1DirPaths(absDirLink2, B_OK, true); + InitTest1DirPaths(absDirLink3, B_OK, true); + InitTest1DirPaths(absDirLink4, B_OK, true); + InitTest1DirPaths(relDirLink1, B_OK, true); + InitTest1DirPaths(relDirLink2, B_OK, true); + InitTest1DirPaths(relDirLink3, B_OK, true); + InitTest1DirPaths(relDirLink4, B_OK, true); + InitTest1DirPaths(absFileLink1, B_OK, true); + InitTest1DirPaths(absFileLink2, B_OK, true); + InitTest1DirPaths(absFileLink3, B_OK, true); + InitTest1DirPaths(absFileLink4, B_OK, true); + InitTest1DirPaths(relFileLink1, B_OK, true); + InitTest1DirPaths(relFileLink2, B_OK, true); + InitTest1DirPaths(relFileLink3, B_OK, true); + InitTest1DirPaths(relFileLink4, B_OK, true); + InitTest1DirPaths(absCyclicLink1, B_LINK_LIMIT, true); + InitTest1DirPaths(relCyclicLink1, B_LINK_LIMIT, true); + InitTest1DirPaths(absBadLink1, B_ENTRY_NOT_FOUND, true); + InitTest1DirPaths(absBadLink2, B_ENTRY_NOT_FOUND, true); + InitTest1DirPaths(absBadLink3, B_ENTRY_NOT_FOUND, true); + InitTest1DirPaths(absBadLink4, B_ENTRY_NOT_FOUND, true); + InitTest1DirPaths(relBadLink1, B_ENTRY_NOT_FOUND, true); + InitTest1DirPaths(relBadLink2, B_ENTRY_NOT_FOUND, true); + InitTest1DirPaths(relBadLink3, B_ENTRY_NOT_FOUND, true); + InitTest1DirPaths(relBadLink4, B_ENTRY_NOT_FOUND, true); + InitTest1DirPaths(absVeryBadLink1, B_ENTRY_NOT_FOUND, true); + InitTest1DirPaths(absVeryBadLink2, B_ENTRY_NOT_FOUND, true); + InitTest1DirPaths(absVeryBadLink3, B_ENTRY_NOT_FOUND, true); + InitTest1DirPaths(absVeryBadLink4, B_ENTRY_NOT_FOUND, true); + InitTest1DirPaths(relVeryBadLink1, B_ENTRY_NOT_FOUND, true); + InitTest1DirPaths(relVeryBadLink2, B_ENTRY_NOT_FOUND, true); + InitTest1DirPaths(relVeryBadLink3, B_ENTRY_NOT_FOUND, true); + InitTest1DirPaths(relVeryBadLink4, B_ENTRY_NOT_FOUND, true); +// R5: returns E2BIG instead of B_NAME_TOO_LONG + InitTest1DirPaths(tooLongEntry1, fuzzy_error(E2BIG, B_NAME_TOO_LONG), true); +// OBOS: Fails, because the implementation concatenates the dir and leaf +// name. +#if !SK_TEST_OBOS_POSIX + InitTest1DirPaths(tooLongDir16, B_OK, true); +#endif + + // special cases (root dir) + nextSubTest(); + { + BDirectory dir("/"); + BEntry entry(&dir, "."); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + } + // special cases (fs root dir) + nextSubTest(); + { + BDirectory dir("/"); + BEntry entry(&dir, "boot"); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + } + // NULL path + nextSubTest(); + { + BDirectory dir("/"); + BEntry entry(&dir, (const char*)NULL); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + } + // bad args (NULL dir) +// R5: crashs +#if !SK_TEST_R5 + nextSubTest(); + { + chdir("/"); + BEntry entry((const BDirectory*)NULL, "tmp"); + CPPUNIT_ASSERT( entry.InitCheck() == B_BAD_VALUE ); + RestoreCWD(); + } +#endif + // strange args (badly initialized dir, absolute path) + nextSubTest(); + { + BDirectory dir(badEntry1.cpath); + CPPUNIT_ASSERT( dir.InitCheck() == B_ENTRY_NOT_FOUND ); + BEntry entry(&dir, "/tmp"); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + } + // bad args (NULL dir and path) +// R5: crashs +#if !SK_TEST_R5 + nextSubTest(); + { + BEntry entry((const BDirectory*)NULL, (const char*)NULL); + CPPUNIT_ASSERT( entry.InitCheck() == B_BAD_VALUE ); + } +#endif + // bad args(NULL dir, absolute path) +// R5: crashs +#if !SK_TEST_R5 + nextSubTest(); + { + BEntry entry((const BDirectory*)NULL, "/tmp"); + CPPUNIT_ASSERT( entry.InitCheck() == B_BAD_VALUE ); + } +#endif +} + +// InitTest2Paths +void +EntryTest::InitTest2Paths(TestEntry &_testEntry, status_t error, bool traverse) +{ + TestEntry *testEntry = &_testEntry; + BEntry entry; + // absolute path + nextSubTest(); + { +//printf("%s\n", testEntry->cpath); + status_t result = entry.SetTo(testEntry->cpath, traverse); +if (!fuzzy_equals(result, error)) +printf("error: %lx (%lx)\n", result, error); + CPPUNIT_ASSERT( fuzzy_equals(result, error) ); + CPPUNIT_ASSERT( fuzzy_equals(entry.InitCheck(), error) ); + if (result == B_OK) + examine_entry(entry, testEntry, traverse); + } + // relative path + nextSubTest(); + { +//printf("%s\n", testEntry->cpath); + if (chdir(testEntry->super->cpath) == 0) { + status_t result = entry.SetTo(testEntry->cname, traverse); +if (!fuzzy_equals(result, error)) +printf("error: %lx (%lx)\n", result, error); + CPPUNIT_ASSERT( fuzzy_equals(result, error) ); + CPPUNIT_ASSERT( fuzzy_equals(entry.InitCheck(), error) ); + if (result == B_OK) + examine_entry(entry, testEntry, traverse); + RestoreCWD(); + } + } +} + +// InitTest2Refs +void +EntryTest::InitTest2Refs(TestEntry &_testEntry, status_t error, bool traverse) +{ + TestEntry *testEntry = &_testEntry; + BEntry entry; + // absolute path + nextSubTest(); + { +//printf("%s\n", testEntry->cpath); + status_t result = entry.SetTo(&testEntry->get_ref(), traverse); +if (!fuzzy_equals(result, error)) +printf("error: %lx (%lx)\n", result, error); + CPPUNIT_ASSERT( fuzzy_equals(result, error) ); + CPPUNIT_ASSERT( fuzzy_equals(entry.InitCheck(), error) ); + if (result == B_OK) + examine_entry(entry, testEntry, traverse); + } +} + +// InitTest2DirPaths +void +EntryTest::InitTest2DirPaths(TestEntry &_testEntry, status_t error, + bool traverse) +{ + TestEntry *testEntry = &_testEntry; + BEntry entry; + // absolute path + nextSubTest(); + { + if (!testEntry->isBad() + && testEntry->path.length() < B_PATH_NAME_LENGTH) { +//printf("%s\n", testEntry->cpath); + BDirectory dir("/boot/home/Desktop"); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + status_t result = entry.SetTo(&dir, testEntry->cpath, traverse); +if (!fuzzy_equals(result, error)) +printf("error: %lx (%lx)\n", result, error); + CPPUNIT_ASSERT( fuzzy_equals(result, error) ); + CPPUNIT_ASSERT( fuzzy_equals(entry.InitCheck(), error) ); + if (result == B_OK) + examine_entry(entry, testEntry, traverse); + } + } + // relative path (one level) + nextSubTest(); + { + if (!testEntry->isBad() + && testEntry->super->path.length() < B_PATH_NAME_LENGTH) { +//printf("%s + %s\n", testEntry->super->cpath, testEntry->cname); + BDirectory dir(testEntry->super->cpath); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + status_t result = entry.SetTo(&dir, testEntry->cname, traverse); +if (!fuzzy_equals(result, error)) +printf("error: %lx (%lx)\n", result, error); + CPPUNIT_ASSERT( fuzzy_equals(result, error) ); + CPPUNIT_ASSERT( fuzzy_equals(entry.InitCheck(), error) ); + if (result == B_OK) + examine_entry(entry, testEntry, traverse); + } + } + // relative path (two levels) + nextSubTest(); + { + if (!testEntry->super->isBad() && !testEntry->super->super->isBad()) { + string entryName = testEntry->super->name + "/" + testEntry->name; +//printf("%s + %s\n", testEntry->super->super->cpath, entryName.c_str()); + BDirectory dir(testEntry->super->super->cpath); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + status_t result = entry.SetTo(&dir, entryName.c_str(), traverse); +if (!fuzzy_equals(result, error)) +printf("error: %lx (%lx)\n", result, error); + CPPUNIT_ASSERT( fuzzy_equals(result, error) ); + CPPUNIT_ASSERT( fuzzy_equals(entry.InitCheck(), error) ); + if (result == B_OK) + examine_entry(entry, testEntry, traverse); + } + } +} + +// InitTest2 +void +EntryTest::InitTest2() +{ + BEntry entry; + // 2. SetTo(const char *, bool) + // don't traverse + InitTest2Paths(dir1, B_OK); + InitTest2Paths(dir2, B_OK); + InitTest2Paths(file1, B_OK); + InitTest2Paths(subDir1, B_OK); + InitTest2Paths(abstractEntry1, B_OK); + InitTest2Paths(badEntry1, B_ENTRY_NOT_FOUND); + InitTest2Paths(absDirLink1, B_OK); + InitTest2Paths(absDirLink2, B_OK); + InitTest2Paths(absDirLink3, B_OK); + InitTest2Paths(absDirLink4, B_OK); + InitTest2Paths(relDirLink1, B_OK); + InitTest2Paths(relDirLink2, B_OK); + InitTest2Paths(relDirLink3, B_OK); + InitTest2Paths(relDirLink4, B_OK); + InitTest2Paths(absFileLink1, B_OK); + InitTest2Paths(absFileLink2, B_OK); + InitTest2Paths(absFileLink3, B_OK); + InitTest2Paths(absFileLink4, B_OK); + InitTest2Paths(relFileLink1, B_OK); + InitTest2Paths(relFileLink2, B_OK); + InitTest2Paths(relFileLink3, B_OK); + InitTest2Paths(relFileLink4, B_OK); + InitTest2Paths(absCyclicLink1, B_OK); + InitTest2Paths(relCyclicLink1, B_OK); + InitTest2Paths(absBadLink1, B_OK); + InitTest2Paths(absBadLink2, B_OK); + InitTest2Paths(absBadLink3, B_OK); + InitTest2Paths(absBadLink4, B_OK); + InitTest2Paths(relBadLink1, B_OK); + InitTest2Paths(relBadLink2, B_OK); + InitTest2Paths(relBadLink3, B_OK); + InitTest2Paths(relBadLink4, B_OK); + InitTest2Paths(absVeryBadLink1, B_OK); + InitTest2Paths(absVeryBadLink2, B_OK); + InitTest2Paths(absVeryBadLink3, B_OK); + InitTest2Paths(absVeryBadLink4, B_OK); + InitTest2Paths(relVeryBadLink1, B_OK); + InitTest2Paths(relVeryBadLink2, B_OK); + InitTest2Paths(relVeryBadLink3, B_OK); + InitTest2Paths(relVeryBadLink4, B_OK); +// R5: returns E2BIG instead of B_NAME_TOO_LONG + InitTest2Paths(tooLongEntry1, fuzzy_error(E2BIG, B_NAME_TOO_LONG)); +// R5: returns B_ERROR instead of B_NAME_TOO_LONG + InitTest2Paths(tooLongDir16, fuzzy_error(B_ERROR, B_NAME_TOO_LONG)); + // traverse + InitTest2Paths(dir1, B_OK, true); + InitTest2Paths(dir2, B_OK, true); + InitTest2Paths(file1, B_OK, true); + InitTest2Paths(subDir1, B_OK, true); + InitTest2Paths(abstractEntry1, B_OK, true); + InitTest2Paths(badEntry1, B_ENTRY_NOT_FOUND, true); + InitTest2Paths(absDirLink1, B_OK, true); + InitTest2Paths(absDirLink2, B_OK, true); + InitTest2Paths(absDirLink3, B_OK, true); + InitTest2Paths(absDirLink4, B_OK, true); + InitTest2Paths(relDirLink1, B_OK, true); + InitTest2Paths(relDirLink2, B_OK, true); + InitTest2Paths(relDirLink3, B_OK, true); + InitTest2Paths(relDirLink4, B_OK, true); + InitTest2Paths(absFileLink1, B_OK, true); + InitTest2Paths(absFileLink2, B_OK, true); + InitTest2Paths(absFileLink3, B_OK, true); + InitTest2Paths(absFileLink4, B_OK, true); + InitTest2Paths(relFileLink1, B_OK, true); + InitTest2Paths(relFileLink2, B_OK, true); + InitTest2Paths(relFileLink3, B_OK, true); + InitTest2Paths(relFileLink4, B_OK, true); + InitTest2Paths(absCyclicLink1, B_LINK_LIMIT, true); + InitTest2Paths(relCyclicLink1, B_LINK_LIMIT, true); + InitTest2Paths(absBadLink1, B_ENTRY_NOT_FOUND, true); + InitTest2Paths(absBadLink2, B_ENTRY_NOT_FOUND, true); + InitTest2Paths(absBadLink3, B_ENTRY_NOT_FOUND, true); + InitTest2Paths(absBadLink4, B_ENTRY_NOT_FOUND, true); + InitTest2Paths(relBadLink1, B_ENTRY_NOT_FOUND, true); + InitTest2Paths(relBadLink2, B_ENTRY_NOT_FOUND, true); + InitTest2Paths(relBadLink3, B_ENTRY_NOT_FOUND, true); + InitTest2Paths(relBadLink4, B_ENTRY_NOT_FOUND, true); + InitTest2Paths(absVeryBadLink1, B_ENTRY_NOT_FOUND, true); + InitTest2Paths(absVeryBadLink2, B_ENTRY_NOT_FOUND, true); + InitTest2Paths(absVeryBadLink3, B_ENTRY_NOT_FOUND, true); + InitTest2Paths(absVeryBadLink4, B_ENTRY_NOT_FOUND, true); + InitTest2Paths(relVeryBadLink1, B_ENTRY_NOT_FOUND, true); + InitTest2Paths(relVeryBadLink2, B_ENTRY_NOT_FOUND, true); + InitTest2Paths(relVeryBadLink3, B_ENTRY_NOT_FOUND, true); + InitTest2Paths(relVeryBadLink4, B_ENTRY_NOT_FOUND, true); +// R5: returns E2BIG instead of B_NAME_TOO_LONG + InitTest2Paths(tooLongEntry1, fuzzy_error(E2BIG, B_NAME_TOO_LONG), true); +// R5: returns B_ERROR instead of B_NAME_TOO_LONG + InitTest2Paths(tooLongDir16, fuzzy_error(B_ERROR, B_NAME_TOO_LONG), true); + // special cases (root dir) + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo("/") == B_OK ); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + entry.Unset(); + // special cases (fs root dir) + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo("/boot") == B_OK ); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + entry.Unset(); + // bad args + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo((const char*)NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( entry.InitCheck() == B_BAD_VALUE ); + entry.Unset(); + + // 3. BEntry(const entry_ref *, bool) + // don't traverse + InitTest2Refs(dir1, B_OK); + InitTest2Refs(dir2, B_OK); + InitTest2Refs(file1, B_OK); + InitTest2Refs(subDir1, B_OK); + InitTest2Refs(abstractEntry1, B_OK); + InitTest2Refs(absDirLink1, B_OK); + InitTest2Refs(absDirLink2, B_OK); + InitTest2Refs(absDirLink3, B_OK); + InitTest2Refs(absDirLink4, B_OK); + InitTest2Refs(relDirLink1, B_OK); + InitTest2Refs(relDirLink2, B_OK); + InitTest2Refs(relDirLink3, B_OK); + InitTest2Refs(relDirLink4, B_OK); + InitTest2Refs(absFileLink1, B_OK); + InitTest2Refs(absFileLink2, B_OK); + InitTest2Refs(absFileLink3, B_OK); + InitTest2Refs(absFileLink4, B_OK); + InitTest2Refs(relFileLink1, B_OK); + InitTest2Refs(relFileLink2, B_OK); + InitTest2Refs(relFileLink3, B_OK); + InitTest2Refs(relFileLink4, B_OK); + InitTest2Refs(absCyclicLink1, B_OK); + InitTest2Refs(relCyclicLink1, B_OK); + InitTest2Refs(absBadLink1, B_OK); + InitTest2Refs(absBadLink2, B_OK); + InitTest2Refs(absBadLink3, B_OK); + InitTest2Refs(absBadLink4, B_OK); + InitTest2Refs(relBadLink1, B_OK); + InitTest2Refs(relBadLink2, B_OK); + InitTest2Refs(relBadLink3, B_OK); + InitTest2Refs(relBadLink4, B_OK); + InitTest2Refs(absVeryBadLink1, B_OK); + InitTest2Refs(absVeryBadLink2, B_OK); + InitTest2Refs(absVeryBadLink3, B_OK); + InitTest2Refs(absVeryBadLink4, B_OK); + InitTest2Refs(relVeryBadLink1, B_OK); + InitTest2Refs(relVeryBadLink2, B_OK); + InitTest2Refs(relVeryBadLink3, B_OK); + InitTest2Refs(relVeryBadLink4, B_OK); + // traverse + InitTest2Refs(dir1, B_OK, true); + InitTest2Refs(dir2, B_OK, true); + InitTest2Refs(file1, B_OK, true); + InitTest2Refs(subDir1, B_OK, true); + InitTest2Refs(abstractEntry1, B_OK, true); + InitTest2Refs(absDirLink1, B_OK, true); + InitTest2Refs(absDirLink2, B_OK, true); + InitTest2Refs(absDirLink3, B_OK, true); + InitTest2Refs(absDirLink4, B_OK, true); + InitTest2Refs(relDirLink1, B_OK, true); + InitTest2Refs(relDirLink2, B_OK, true); + InitTest2Refs(relDirLink3, B_OK, true); + InitTest2Refs(relDirLink4, B_OK, true); + InitTest2Refs(absFileLink1, B_OK, true); + InitTest2Refs(absFileLink2, B_OK, true); + InitTest2Refs(absFileLink3, B_OK, true); + InitTest2Refs(absFileLink4, B_OK, true); + InitTest2Refs(relFileLink1, B_OK, true); + InitTest2Refs(relFileLink2, B_OK, true); + InitTest2Refs(relFileLink3, B_OK, true); + InitTest2Refs(relFileLink4, B_OK, true); + InitTest2Refs(absCyclicLink1, B_LINK_LIMIT, true); + InitTest2Refs(relCyclicLink1, B_LINK_LIMIT, true); + InitTest2Refs(absBadLink1, B_ENTRY_NOT_FOUND, true); + InitTest2Refs(absBadLink2, B_ENTRY_NOT_FOUND, true); + InitTest2Refs(absBadLink3, B_ENTRY_NOT_FOUND, true); + InitTest2Refs(absBadLink4, B_ENTRY_NOT_FOUND, true); + InitTest2Refs(relBadLink1, B_ENTRY_NOT_FOUND, true); + InitTest2Refs(relBadLink2, B_ENTRY_NOT_FOUND, true); + InitTest2Refs(relBadLink3, B_ENTRY_NOT_FOUND, true); + InitTest2Refs(relBadLink4, B_ENTRY_NOT_FOUND, true); + InitTest2Refs(absVeryBadLink1, B_ENTRY_NOT_FOUND, true); + InitTest2Refs(absVeryBadLink2, B_ENTRY_NOT_FOUND, true); + InitTest2Refs(absVeryBadLink3, B_ENTRY_NOT_FOUND, true); + InitTest2Refs(absVeryBadLink4, B_ENTRY_NOT_FOUND, true); + InitTest2Refs(relVeryBadLink1, B_ENTRY_NOT_FOUND, true); + InitTest2Refs(relVeryBadLink2, B_ENTRY_NOT_FOUND, true); + InitTest2Refs(relVeryBadLink3, B_ENTRY_NOT_FOUND, true); + InitTest2Refs(relVeryBadLink4, B_ENTRY_NOT_FOUND, true); + // bad args + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo((const entry_ref*)NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( entry.InitCheck() == B_BAD_VALUE ); + entry.Unset(); + + // 4. BEntry(const BDirectory *, const char *, bool) + // don't traverse + InitTest2DirPaths(dir1, B_OK); + InitTest2DirPaths(dir2, B_OK); + InitTest2DirPaths(file1, B_OK); + InitTest2DirPaths(subDir1, B_OK); + InitTest2DirPaths(abstractEntry1, B_OK); + InitTest2DirPaths(badEntry1, B_ENTRY_NOT_FOUND); + InitTest2DirPaths(absDirLink1, B_OK); + InitTest2DirPaths(absDirLink2, B_OK); + InitTest2DirPaths(absDirLink3, B_OK); + InitTest2DirPaths(absDirLink4, B_OK); + InitTest2DirPaths(relDirLink1, B_OK); + InitTest2DirPaths(relDirLink2, B_OK); + InitTest2DirPaths(relDirLink3, B_OK); + InitTest2DirPaths(relDirLink4, B_OK); + InitTest2DirPaths(absFileLink1, B_OK); + InitTest2DirPaths(absFileLink2, B_OK); + InitTest2DirPaths(absFileLink3, B_OK); + InitTest2DirPaths(absFileLink4, B_OK); + InitTest2DirPaths(relFileLink1, B_OK); + InitTest2DirPaths(relFileLink2, B_OK); + InitTest2DirPaths(relFileLink3, B_OK); + InitTest2DirPaths(relFileLink4, B_OK); + InitTest2DirPaths(absCyclicLink1, B_OK); + InitTest2DirPaths(relCyclicLink1, B_OK); + InitTest2DirPaths(absBadLink1, B_OK); + InitTest2DirPaths(absBadLink2, B_OK); + InitTest2DirPaths(absBadLink3, B_OK); + InitTest2DirPaths(absBadLink4, B_OK); + InitTest2DirPaths(relBadLink1, B_OK); + InitTest2DirPaths(relBadLink2, B_OK); + InitTest2DirPaths(relBadLink3, B_OK); + InitTest2DirPaths(relBadLink4, B_OK); + InitTest2DirPaths(absVeryBadLink1, B_OK); + InitTest2DirPaths(absVeryBadLink2, B_OK); + InitTest2DirPaths(absVeryBadLink3, B_OK); + InitTest2DirPaths(absVeryBadLink4, B_OK); + InitTest2DirPaths(relVeryBadLink1, B_OK); + InitTest2DirPaths(relVeryBadLink2, B_OK); + InitTest2DirPaths(relVeryBadLink3, B_OK); + InitTest2DirPaths(relVeryBadLink4, B_OK); +// R5: returns E2BIG instead of B_NAME_TOO_LONG + InitTest2DirPaths(tooLongEntry1, fuzzy_error(E2BIG, B_NAME_TOO_LONG)); +// OBOS: Fails, because the implementation concatenates the dir and leaf +// name. +#if !SK_TEST_OBOS_POSIX + InitTest2DirPaths(tooLongDir16, B_OK, true); +#endif + // traverse + InitTest2DirPaths(dir1, B_OK, true); + InitTest2DirPaths(dir2, B_OK, true); + InitTest2DirPaths(file1, B_OK, true); + InitTest2DirPaths(subDir1, B_OK, true); + InitTest2DirPaths(abstractEntry1, B_OK, true); + InitTest2DirPaths(badEntry1, B_ENTRY_NOT_FOUND, true); + InitTest2DirPaths(absDirLink1, B_OK, true); + InitTest2DirPaths(absDirLink2, B_OK, true); + InitTest2DirPaths(absDirLink3, B_OK, true); + InitTest2DirPaths(absDirLink4, B_OK, true); + InitTest2DirPaths(relDirLink1, B_OK, true); + InitTest2DirPaths(relDirLink2, B_OK, true); + InitTest2DirPaths(relDirLink3, B_OK, true); + InitTest2DirPaths(relDirLink4, B_OK, true); + InitTest2DirPaths(absFileLink1, B_OK, true); + InitTest2DirPaths(absFileLink2, B_OK, true); + InitTest2DirPaths(absFileLink3, B_OK, true); + InitTest2DirPaths(absFileLink4, B_OK, true); + InitTest2DirPaths(relFileLink1, B_OK, true); + InitTest2DirPaths(relFileLink2, B_OK, true); + InitTest2DirPaths(relFileLink3, B_OK, true); + InitTest2DirPaths(relFileLink4, B_OK, true); + InitTest2DirPaths(absCyclicLink1, B_LINK_LIMIT, true); + InitTest2DirPaths(relCyclicLink1, B_LINK_LIMIT, true); + InitTest2DirPaths(absBadLink1, B_ENTRY_NOT_FOUND, true); + InitTest2DirPaths(absBadLink2, B_ENTRY_NOT_FOUND, true); + InitTest2DirPaths(absBadLink3, B_ENTRY_NOT_FOUND, true); + InitTest2DirPaths(absBadLink4, B_ENTRY_NOT_FOUND, true); + InitTest2DirPaths(relBadLink1, B_ENTRY_NOT_FOUND, true); + InitTest2DirPaths(relBadLink2, B_ENTRY_NOT_FOUND, true); + InitTest2DirPaths(relBadLink3, B_ENTRY_NOT_FOUND, true); + InitTest2DirPaths(relBadLink4, B_ENTRY_NOT_FOUND, true); + InitTest2DirPaths(absVeryBadLink1, B_ENTRY_NOT_FOUND, true); + InitTest2DirPaths(absVeryBadLink2, B_ENTRY_NOT_FOUND, true); + InitTest2DirPaths(absVeryBadLink3, B_ENTRY_NOT_FOUND, true); + InitTest2DirPaths(absVeryBadLink4, B_ENTRY_NOT_FOUND, true); + InitTest2DirPaths(relVeryBadLink1, B_ENTRY_NOT_FOUND, true); + InitTest2DirPaths(relVeryBadLink2, B_ENTRY_NOT_FOUND, true); + InitTest2DirPaths(relVeryBadLink3, B_ENTRY_NOT_FOUND, true); + InitTest2DirPaths(relVeryBadLink4, B_ENTRY_NOT_FOUND, true); +// R5: returns E2BIG instead of B_NAME_TOO_LONG + InitTest2DirPaths(tooLongEntry1, fuzzy_error(E2BIG, B_NAME_TOO_LONG), true); +// OBOS: Fails, because the implementation concatenates the dir and leaf +// name. +#if !SK_TEST_OBOS_POSIX + InitTest2DirPaths(tooLongDir16, B_OK, true); +#endif + // special cases (root dir) + nextSubTest(); + { + BDirectory dir("/"); + CPPUNIT_ASSERT( entry.SetTo(&dir, ".") == B_OK ); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + entry.Unset(); + } + // special cases (fs root dir) + nextSubTest(); + { + BDirectory dir("/"); + CPPUNIT_ASSERT( entry.SetTo(&dir, "boot") == B_OK ); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + entry.Unset(); + } + // NULL path + nextSubTest(); + { + BDirectory dir("/"); + CPPUNIT_ASSERT( entry.SetTo(&dir, (const char*)NULL) == B_OK ); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + entry.Unset(); + } + // bad args (NULL dir) +// R5: crashs +#if !SK_TEST_R5 + nextSubTest(); + { + chdir("/"); + CPPUNIT_ASSERT( entry.SetTo((const BDirectory*)NULL, "tmp") + == B_BAD_VALUE ); + CPPUNIT_ASSERT( entry.InitCheck() == B_BAD_VALUE ); + RestoreCWD(); + entry.Unset(); + } +#endif + // strange args (badly initialized dir, absolute path) + nextSubTest(); + { + BDirectory dir(badEntry1.cpath); + CPPUNIT_ASSERT( dir.InitCheck() == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( entry.SetTo(&dir, "/tmp") == B_OK ); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + } + // bad args (NULL dir and path) +// R5: crashs +#if !SK_TEST_R5 + nextSubTest(); + { + CPPUNIT_ASSERT( entry.SetTo((const BDirectory*)NULL, (const char*)NULL) + == B_BAD_VALUE ); + CPPUNIT_ASSERT( entry.InitCheck() == B_BAD_VALUE ); + entry.Unset(); + } +#endif + // bad args(NULL dir, absolute path) +// R5: crashs +#if !SK_TEST_R5 + nextSubTest(); + { + CPPUNIT_ASSERT( entry.SetTo((const BDirectory*)NULL, "/tmp") + == B_BAD_VALUE ); + CPPUNIT_ASSERT( entry.InitCheck() == B_BAD_VALUE ); + entry.Unset(); + } +#endif +} + +// SpecialGetCasesTest +// +// Tests special (mostly error) cases for Exists(), GetPath(), GetName(), +// GetParent() and GetRef(). The other cases have already been tested in +// InitTest1/2(). +void +EntryTest::SpecialGetCasesTest() +{ + BEntry entry; + // 1. Exists() + // uninitialized + nextSubTest(); + CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( entry.Exists() == false ); + entry.Unset(); + // badly initialized + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(badEntry1.cpath) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( entry.Exists() == false ); + entry.Unset(); + // root + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo("/") == B_OK ); + CPPUNIT_ASSERT( entry.Exists() == true ); + entry.Unset(); + + // 2. GetPath() + BPath path; + // uninitialized + nextSubTest(); + CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( entry.GetPath(&path) == B_NO_INIT ); + entry.Unset(); + // badly initialized + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(badEntry1.cpath) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( entry.GetPath(&path) == B_NO_INIT ); + entry.Unset(); + // too long pathname +// OBOS: Fails, because the implementation concatenates the dir and leaf +// name. +#if !SK_TEST_OBOS_POSIX + nextSubTest(); + BDirectory dir(tooLongDir16.super->super->cpath); + string entryName = tooLongDir16.super->name + "/" + tooLongDir16.name; + CPPUNIT_ASSERT( entry.SetTo(&dir, entryName.c_str()) == B_OK ); + CPPUNIT_ASSERT( entry.GetPath(&path) == B_OK ); + CPPUNIT_ASSERT( path == tooLongDir16.cpath ); + entry.Unset(); +#endif + + // 3. GetName() + char name[B_FILE_NAME_LENGTH + 1]; + // uninitialized + nextSubTest(); + CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( entry.GetName(name) == B_NO_INIT ); + entry.Unset(); + // badly initialized + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(badEntry1.cpath) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( entry.GetName(name) == B_NO_INIT ); + entry.Unset(); + + // 4. GetParent(BEntry *) + BEntry parentEntry; + // uninitialized + nextSubTest(); + CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( entry.GetParent(&parentEntry) == B_NO_INIT ); + entry.Unset(); + // badly initialized + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(badEntry1.cpath) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( entry.GetParent(&parentEntry) == B_NO_INIT ); + entry.Unset(); + // parent of root dir + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo("/") == B_OK ); + CPPUNIT_ASSERT( entry.GetParent(&parentEntry) == B_ENTRY_NOT_FOUND ); + entry.Unset(); + + // 5. GetParent(BDirectory *) + BDirectory parentDir; + // uninitialized + nextSubTest(); + CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( entry.GetParent(&parentDir) == B_NO_INIT ); + entry.Unset(); + // badly initialized + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(badEntry1.cpath) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( entry.GetParent(&parentDir) == B_NO_INIT ); + entry.Unset(); + // parent of root dir + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo("/") == B_OK ); + CPPUNIT_ASSERT( entry.GetParent(&parentDir) == B_ENTRY_NOT_FOUND ); + entry.Unset(); + + // 6. GetRef() + entry_ref ref, ref2; + // uninitialized + nextSubTest(); + CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_NO_INIT ); + entry.Unset(); + // badly initialized + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(badEntry1.cpath) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_NO_INIT ); + entry.Unset(); + // ref for root dir + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo("/") == B_OK ); + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + entry.Unset(); +} + +// RenameTestEntry +void +EntryTest::RenameTestEntry(TestEntry *testEntry, TestEntry *newTestEntry, + string newName, bool existing, bool clobber, + status_t error, uint32 kind) +{ + nextSubTest(); + BEntry entry; + BDirectory dir; + // get all the names + string pathname = testEntry->path; + string dirname = testEntry->super->path; + string newPathname = newTestEntry->path; +//printf("path: `%s', dir: `%s', new name: `%s'\n", pathname.c_str(), +//dirname.c_str(), newPathname.c_str()); + // create the entries + switch (kind) { + case B_FILE_NODE: + CreateFile(pathname.c_str()); + break; + case B_DIRECTORY_NODE: + CreateDir(pathname.c_str()); + break; + case B_SYMLINK_NODE: + CreateLink(pathname.c_str(), file1.cpath); + break; + } + if (existing) + CreateFile(newPathname.c_str()); + // rename the file + CPPUNIT_ASSERT( entry.SetTo(pathname.c_str()) == B_OK ); + CPPUNIT_ASSERT( dir.SetTo(dirname.c_str()) == B_OK ); + status_t result = entry.Rename(newName.c_str(), clobber); +if (result != error) { +printf("`%s'.Rename(`%s', %d): ", pathname.c_str(), newName.c_str(), clobber); +printf("error: %lx (%lx)\n", result, error); +} + CPPUNIT_ASSERT( result == error ); + // check and cleanup + if (error == B_OK) { + switch (kind) { + case B_FILE_NODE: + CPPUNIT_ASSERT( !PingFile(pathname.c_str()) ); + CPPUNIT_ASSERT( PingFile(newPathname.c_str()) ); + break; + case B_DIRECTORY_NODE: + CPPUNIT_ASSERT( !PingDir(pathname.c_str()) ); + CPPUNIT_ASSERT( PingDir(newPathname.c_str()) ); + break; + case B_SYMLINK_NODE: + CPPUNIT_ASSERT( !PingLink(pathname.c_str()) ); + CPPUNIT_ASSERT( PingLink(newPathname.c_str(), file1.cpath) ); + break; + } + RemoveFile(newPathname.c_str()); + } else { + switch (kind) { + case B_FILE_NODE: + CPPUNIT_ASSERT( PingFile(pathname.c_str()) ); + break; + case B_DIRECTORY_NODE: + CPPUNIT_ASSERT( PingDir(pathname.c_str()) ); + break; + case B_SYMLINK_NODE: + CPPUNIT_ASSERT( PingLink(pathname.c_str(), file1.cpath) ); + break; + } + if (existing) { + CPPUNIT_ASSERT( PingFile(newPathname.c_str()) ); + RemoveFile(newPathname.c_str()); + } + RemoveFile(pathname.c_str()); + } +} + +// RenameTestEntry +void +EntryTest::RenameTestEntry(TestEntry *testEntry, TestEntry *newTestEntry, + bool existing, bool clobber, status_t error, + uint32 kind) +{ + // relative path + string relPath = get_shortest_relative_path(testEntry->super, + newTestEntry); + if (relPath.length() > 0) { + RenameTestEntry(testEntry, newTestEntry, relPath, existing, + clobber, error, B_FILE_NODE); + } + // absolute path + RenameTestEntry(testEntry, newTestEntry, newTestEntry->path, existing, + clobber, error, B_FILE_NODE); +} + +// RenameTestFile +void +EntryTest::RenameTestFile(TestEntry *testEntry, TestEntry *newTestEntry, + bool existing, bool clobber, status_t error) +{ + RenameTestEntry(testEntry, newTestEntry, existing, clobber, error, + B_FILE_NODE); +} + +// RenameTestDir +void +EntryTest::RenameTestDir(TestEntry *testEntry, TestEntry *newTestEntry, + bool existing, bool clobber, status_t error) +{ + RenameTestEntry(testEntry, newTestEntry, existing, clobber, error, + B_DIRECTORY_NODE); +} + +// RenameTestLink +void +EntryTest::RenameTestLink(TestEntry *testEntry, TestEntry *newTestEntry, + bool existing, bool clobber, status_t error) +{ + RenameTestEntry(testEntry, newTestEntry, existing, clobber, error, + B_SYMLINK_NODE); +} + +// RenameTest +void +EntryTest::RenameTest() +{ + BDirectory dir; + BEntry entry; + // file + // same dir + RenameTestFile(&file2, &file2, false, false, B_FILE_EXISTS); + RenameTestFile(&file2, &file2, false, true, B_NOT_ALLOWED); + RenameTestFile(&file2, &file4, false, false, B_OK); + // different dir + RenameTestFile(&file2, &file3, false, false, B_OK); + // different dir, existing file, clobber + RenameTestFile(&file2, &file3, true, true, B_OK); + // different dir, existing file, no clobber + RenameTestFile(&file2, &file3, true, false, B_FILE_EXISTS); + // dir + // same dir + RenameTestDir(&file2, &file2, false, false, B_FILE_EXISTS); + RenameTestDir(&file2, &file2, false, true, B_NOT_ALLOWED); + RenameTestDir(&file2, &file4, false, false, B_OK); + // different dir + RenameTestDir(&file2, &file3, false, false, B_OK); + // different dir, existing file, clobber + RenameTestDir(&file2, &file3, true, true, B_OK); + // different dir, existing file, no clobber + RenameTestDir(&file2, &file3, true, false, B_FILE_EXISTS); + // link + // same dir + RenameTestLink(&file2, &file2, false, false, B_FILE_EXISTS); + RenameTestLink(&file2, &file2, false, true, B_NOT_ALLOWED); + RenameTestLink(&file2, &file4, false, false, B_OK); + // different dir + RenameTestLink(&file2, &file3, false, false, B_OK); + // different dir, existing file, clobber + RenameTestLink(&file2, &file3, true, true, B_OK); + // different dir, existing file, no clobber + RenameTestLink(&file2, &file3, true, false, B_FILE_EXISTS); + + // try to clobber a non-empty directory + nextSubTest(); + CreateFile(file3.cpath); + CPPUNIT_ASSERT( entry.SetTo(file3.cpath) == B_OK ); + CPPUNIT_ASSERT( entry.Rename(dir1.cpath, true) == B_DIRECTORY_NOT_EMPTY ); + CPPUNIT_ASSERT( PingDir(dir1.cpath) ); + CPPUNIT_ASSERT( PingFile(file3.cpath, &entry) ); + RemoveFile(file3.cpath); + entry.Unset(); + dir.Unset(); + // clobber an empty directory + nextSubTest(); + CreateFile(file3.cpath); + CPPUNIT_ASSERT( entry.SetTo(file3.cpath) == B_OK ); + CPPUNIT_ASSERT( entry.Rename(subDir1.cpath, true) == B_OK ); + CPPUNIT_ASSERT( PingFile(subDir1.cpath, &entry) ); + CPPUNIT_ASSERT( !PingFile(file3.cpath) ); + RemoveFile(subDir1.cpath); + entry.Unset(); + dir.Unset(); + // abstract entry + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(file2.cpath) == B_OK ); + CPPUNIT_ASSERT( entry.Rename(file4.cname) == B_ENTRY_NOT_FOUND ); + entry.Unset(); + dir.Unset(); + // uninitialized entry + nextSubTest(); + CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( entry.Rename(file4.cpath) == B_NO_INIT ); + entry.Unset(); + dir.Unset(); + // badly initialized entry + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(badEntry1.cpath) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( entry.Rename(file4.cpath) == B_NO_INIT ); + entry.Unset(); + dir.Unset(); + // Verify attempts to rename root + nextSubTest(); + BEntry root("/"); + CPPUNIT_ASSERT( root.Rename("/", false) == B_FILE_EXISTS ); + CPPUNIT_ASSERT( root.Rename("/", true) == B_NOT_ALLOWED ); + // Verify abstract entries + nextSubTest(); + BEntry abstract(abstractEntry1.cpath); + CPPUNIT_ASSERT( abstract.InitCheck() == B_OK ); + CPPUNIT_ASSERT( !abstract.Exists() ); + CPPUNIT_ASSERT( abstract.Rename("/boot/DoesntMatter") == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( abstract.Rename("/boot/DontMatter", true) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( abstract.Rename("/DoesntMatter") == B_CROSS_DEVICE_LINK ); + CPPUNIT_ASSERT( abstract.Rename("/DontMatter", true) == B_CROSS_DEVICE_LINK ); + // bad args + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(file1.cpath) == B_OK ); + CPPUNIT_ASSERT( equals(entry.Rename(NULL, false), B_FILE_EXISTS, + B_BAD_VALUE) ); + CPPUNIT_ASSERT( equals(entry.Rename(NULL, true), B_NOT_ALLOWED, + B_BAD_VALUE) ); +} + +// MoveToTestEntry +void +EntryTest::MoveToTestEntry(TestEntry *testEntry, TestEntry *testDir, + string newName, bool existing, bool clobber, + status_t error, uint32 kind) +{ + nextSubTest(); + BEntry entry; + BDirectory dir; + // get all the names + string pathname = testEntry->path; + string dirname = testDir->path; + string newPathname = dirname + "/"; + if (newName.length() == 0) + newPathname += testEntry->name; + else { + // check, if the new path is absolute + if (newName.find("/") == 0) + newPathname = newName; + else + newPathname += newName; + } +//printf("path: `%s', dir: `%s', new name: `%s'\n", pathname.c_str(), +//dirname.c_str(), newPathname.c_str()); + // create the entries + switch (kind) { + case B_FILE_NODE: + CreateFile(pathname.c_str()); + break; + case B_DIRECTORY_NODE: + CreateDir(pathname.c_str()); + break; + case B_SYMLINK_NODE: + CreateLink(pathname.c_str(), file1.cpath); + break; + } + if (existing) + CreateFile(newPathname.c_str()); + // move the file + CPPUNIT_ASSERT( entry.SetTo(pathname.c_str()) == B_OK ); + CPPUNIT_ASSERT( dir.SetTo(dirname.c_str()) == B_OK ); + if (newName.length() == 0) { + status_t result = entry.MoveTo(&dir, NULL, clobber); +if (result != error) { +printf("`%s'.MoveTo(`%s', NULL, %d): ", pathname.c_str(), dirname.c_str(), clobber); +printf("error: %lx (%lx)\n", result, error); +} + CPPUNIT_ASSERT( result == error ); + } else { + status_t result = entry.MoveTo(&dir, newName.c_str(), clobber); +if (result != error) { +printf("`%s'.MoveTo(`%s', `%s', %d): ", pathname.c_str(), newName.c_str(), dirname.c_str(), clobber); +printf("error: %lx (%lx)\n", result, error); +} + CPPUNIT_ASSERT( result == error ); + } + // check and cleanup + if (error == B_OK) { + switch (kind) { + case B_FILE_NODE: + CPPUNIT_ASSERT( !PingFile(pathname.c_str()) ); + CPPUNIT_ASSERT( PingFile(newPathname.c_str()) ); + break; + case B_DIRECTORY_NODE: + CPPUNIT_ASSERT( !PingDir(pathname.c_str()) ); + CPPUNIT_ASSERT( PingDir(newPathname.c_str()) ); + break; + case B_SYMLINK_NODE: + CPPUNIT_ASSERT( !PingLink(pathname.c_str()) ); + CPPUNIT_ASSERT( PingLink(newPathname.c_str(), file1.cpath) ); + break; + } + RemoveFile(newPathname.c_str()); + } else { + switch (kind) { + case B_FILE_NODE: + CPPUNIT_ASSERT( PingFile(pathname.c_str()) ); + break; + case B_DIRECTORY_NODE: + CPPUNIT_ASSERT( PingDir(pathname.c_str()) ); + break; + case B_SYMLINK_NODE: + CPPUNIT_ASSERT( PingLink(pathname.c_str(), file1.cpath) ); + break; + } + if (existing) { + CPPUNIT_ASSERT( PingFile(newPathname.c_str()) ); + RemoveFile(newPathname.c_str()); + } + RemoveFile(pathname.c_str()); + } +} + +// MoveToTestEntry +void +EntryTest::MoveToTestEntry(TestEntry *testEntry, TestEntry *testDir, + TestEntry *newTestEntry, bool existing, + bool clobber, status_t error, uint32 kind) +{ + if (newTestEntry) { + // Here is the right place to play a little bit with the dir and path + // arguments. At this time we only pass the leaf name and the + // absolute path name. + MoveToTestEntry(testEntry, testDir, newTestEntry->name, existing, + clobber, error, B_FILE_NODE); + MoveToTestEntry(testEntry, &subDir1, newTestEntry->path, existing, + clobber, error, B_FILE_NODE); + } else { + MoveToTestEntry(testEntry, testDir, "", existing, clobber, error, + B_FILE_NODE); + } +} + +// MoveToTestFile +void +EntryTest::MoveToTestFile(TestEntry *testEntry, TestEntry *testDir, + TestEntry *newTestEntry, bool existing, bool clobber, + status_t error) +{ + MoveToTestEntry(testEntry, testDir, newTestEntry, existing, clobber, error, + B_FILE_NODE); +} + +// MoveToTestDir +void +EntryTest::MoveToTestDir(TestEntry *testEntry, TestEntry *testDir, + TestEntry *newTestEntry, bool existing, bool clobber, + status_t error) +{ + MoveToTestEntry(testEntry, testDir, newTestEntry, existing, clobber, error, + B_DIRECTORY_NODE); +} + +// MoveToTestLink +void +EntryTest::MoveToTestLink(TestEntry *testEntry, TestEntry *testDir, + TestEntry *newTestEntry, bool existing, bool clobber, + status_t error) +{ + MoveToTestEntry(testEntry, testDir, newTestEntry, existing, clobber, error, + B_SYMLINK_NODE); +} + +// MoveToTest +void +EntryTest::MoveToTest() +{ + BDirectory dir; + BEntry entry; + // 1. NULL path + // file + // same dir + MoveToTestFile(&file2, file2.super, NULL, false, false, B_FILE_EXISTS); + MoveToTestFile(&file2, file2.super, NULL, false, true, B_NOT_ALLOWED); + // different dir + MoveToTestFile(&file2, &dir2, NULL, false, false, B_OK); + // different dir, existing file, clobber + MoveToTestFile(&file2, &dir2, NULL, true, true, B_OK); + // different dir, existing file, no clobber + MoveToTestFile(&file2, &dir2, NULL, true, false, B_FILE_EXISTS); + // dir + // same dir + MoveToTestDir(&file2, file2.super, NULL, false, false, B_FILE_EXISTS); + MoveToTestDir(&file2, file2.super, NULL, false, true, B_NOT_ALLOWED); + // different dir + MoveToTestDir(&file2, &dir2, NULL, false, false, B_OK); + // different dir, existing file, clobber + MoveToTestDir(&file2, &dir2, NULL, true, true, B_OK); + // different dir, existing file, no clobber + MoveToTestDir(&file2, &dir2, NULL, true, false, B_FILE_EXISTS); + // link + // same dir + MoveToTestLink(&file2, file2.super, NULL, false, false, B_FILE_EXISTS); + MoveToTestLink(&file2, file2.super, NULL, false, true, B_NOT_ALLOWED); + // different dir + MoveToTestLink(&file2, &dir2, NULL, false, false, B_OK); + // different dir, existing file, clobber + MoveToTestLink(&file2, &dir2, NULL, true, true, B_OK); + // different dir, existing file, no clobber + MoveToTestLink(&file2, &dir2, NULL, true, false, B_FILE_EXISTS); + + // 2. non NULL path + // file + // same dir + MoveToTestFile(&file2, file2.super, &file2, false, false, + B_FILE_EXISTS); + MoveToTestFile(&file2, file2.super, &file2, false, true, + B_NOT_ALLOWED); + MoveToTestFile(&file2, file2.super, &file3, false, false, B_OK); + // different dir + MoveToTestFile(&file2, &dir2, &file3, false, false, B_OK); + // different dir, existing file, clobber + MoveToTestFile(&file2, &dir2, &file3, true, true, B_OK); + // different dir, existing file, no clobber + MoveToTestFile(&file2, &dir2, &file3, true, false, B_FILE_EXISTS); + // dir + // same dir + MoveToTestDir(&file2, file2.super, &file2, false, false, + B_FILE_EXISTS); + MoveToTestDir(&file2, file2.super, &file2, false, true, + B_NOT_ALLOWED); + MoveToTestDir(&file2, file2.super, &file3, false, false, B_OK); + // different dir + MoveToTestDir(&file2, &dir2, &file3, false, false, B_OK); + // different dir, existing file, clobber + MoveToTestDir(&file2, &dir2, &file3, true, true, B_OK); + // different dir, existing file, no clobber + MoveToTestDir(&file2, &dir2, &file3, true, false, B_FILE_EXISTS); + // link + // same dir + MoveToTestLink(&file2, file2.super, &file2, false, false, + B_FILE_EXISTS); + MoveToTestLink(&file2, file2.super, &file2, false, true, + B_NOT_ALLOWED); + MoveToTestLink(&file2, file2.super, &file3, false, false, B_OK); + // different dir + MoveToTestLink(&file2, &dir2, &file3, false, false, B_OK); + // different dir, existing file, clobber + MoveToTestLink(&file2, &dir2, &file3, true, true, B_OK); + // different dir, existing file, no clobber + MoveToTestLink(&file2, &dir2, &file3, true, false, B_FILE_EXISTS); + + // try to clobber a non-empty directory + CreateFile(file3.cpath); + CPPUNIT_ASSERT( entry.SetTo(file3.cpath) == B_OK ); + CPPUNIT_ASSERT( dir.SetTo(dir1.super->cpath) == B_OK ); + CPPUNIT_ASSERT( entry.MoveTo(&dir, dir1.cname, true) + == B_DIRECTORY_NOT_EMPTY ); + CPPUNIT_ASSERT( PingDir(dir1.cpath) ); + CPPUNIT_ASSERT( PingFile(file3.cpath, &entry) ); + RemoveFile(file3.cpath); + entry.Unset(); + dir.Unset(); + // clobber an empty directory + CreateFile(file3.cpath); + CPPUNIT_ASSERT( entry.SetTo(file3.cpath) == B_OK ); + CPPUNIT_ASSERT( dir.SetTo(subDir1.super->cpath) == B_OK ); + CPPUNIT_ASSERT( entry.MoveTo(&dir, subDir1.cname, true) == B_OK ); + CPPUNIT_ASSERT( PingFile(subDir1.cpath, &entry) ); + CPPUNIT_ASSERT( !PingFile(file3.cpath) ); + RemoveFile(subDir1.cpath); + entry.Unset(); + dir.Unset(); + // abstract entry + CPPUNIT_ASSERT( entry.SetTo(file2.cpath) == B_OK ); + CPPUNIT_ASSERT( dir.SetTo(dir2.cpath) == B_OK ); + CPPUNIT_ASSERT( entry.MoveTo(&dir) == B_ENTRY_NOT_FOUND ); + entry.Unset(); + dir.Unset(); + // uninitialized entry + CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( dir.SetTo(dir2.cpath) == B_OK ); + CPPUNIT_ASSERT( entry.MoveTo(&dir) == B_NO_INIT ); + entry.Unset(); + dir.Unset(); + // badly initialized entry + CPPUNIT_ASSERT( entry.SetTo(badEntry1.cpath) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( dir.SetTo(dir2.cpath) == B_OK ); + CPPUNIT_ASSERT( entry.MoveTo(&dir) == B_NO_INIT ); + entry.Unset(); + dir.Unset(); + // bad args (NULL dir) +// R5: crashs +#if !SK_TEST_R5 + CreateFile(file2.cpath); + CPPUNIT_ASSERT( entry.SetTo(file2.cpath) == B_OK ); + CPPUNIT_ASSERT( entry.MoveTo(NULL, file3.cpath) == B_BAD_VALUE ); + RemoveFile(file3.cpath); + entry.Unset(); + dir.Unset(); +#endif + // uninitialized dir, absolute path + CreateFile(file2.cpath); + CPPUNIT_ASSERT( entry.SetTo(file2.cpath) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( entry.MoveTo(&dir, file3.cpath) == B_BAD_VALUE ); + RemoveFile(file3.cpath); + entry.Unset(); + dir.Unset(); +} + +// RemoveTest +void +EntryTest::RemoveTest() +{ + BEntry entry; + // file + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(file1.cpath) == B_OK ); + CPPUNIT_ASSERT( entry.Remove() == B_OK ); + CPPUNIT_ASSERT( !PingFile(file1.cpath) ); + entry.Unset(); + // symlink + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(absFileLink1.cpath) == B_OK ); + CPPUNIT_ASSERT( entry.Remove() == B_OK ); + CPPUNIT_ASSERT( !PingLink(absFileLink1.cpath) ); + entry.Unset(); + // empty dir + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(subDir1.cpath) == B_OK ); + CPPUNIT_ASSERT( entry.Remove() == B_OK ); + CPPUNIT_ASSERT( !PingDir(subDir1.cpath) ); + entry.Unset(); + // non-empty dir + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(dir1.cpath) == B_OK ); + CPPUNIT_ASSERT( entry.Remove() == B_DIRECTORY_NOT_EMPTY ); + CPPUNIT_ASSERT( PingDir(dir1.cpath) ); + entry.Unset(); + // abstract entry + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(abstractEntry1.cpath) == B_OK ); + CPPUNIT_ASSERT( entry.Remove() == B_ENTRY_NOT_FOUND ); + entry.Unset(); + // uninitialized + nextSubTest(); + CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( entry.Remove() == B_NO_INIT ); + entry.Unset(); + // badly initialized + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(badEntry1.cpath) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( entry.Remove() == B_NO_INIT ); + entry.Unset(); +} + +// compareEntries +static +void +compareEntries(const BEntry &entry, const BEntry &entry2, + const TestEntry *testEntry, const TestEntry *testEntry2, + bool traversed, bool traversed2) +{ + if (!testEntry->isBad() && !testEntry2->isBad() + && (!traversed && testEntry->isConcrete()) + && (!traversed2 && testEntry2->isConcrete())) { +//printf("compare: `%s', `%s'\n", testEntry->cpath, testEntry2->cpath); +//printf("InitCheck(): %x, %x\n", entry.InitCheck(), entry2.InitCheck()); + CPPUNIT_ASSERT( (entry == entry2) == (testEntry == testEntry2) ); + CPPUNIT_ASSERT( (entry == entry2) == (testEntry2 == testEntry) ); + CPPUNIT_ASSERT( (entry != entry2) == (testEntry != testEntry2) ); + CPPUNIT_ASSERT( (entry != entry2) == (testEntry2 != testEntry) ); + } +} + +// ComparisonTest +void +EntryTest::ComparisonTest() +{ + // uninitialized + nextSubTest(); + { + BEntry entry; + BEntry entry2; + CPPUNIT_ASSERT( entry == entry2 ); + CPPUNIT_ASSERT( entry2 == entry ); + CPPUNIT_ASSERT( !(entry != entry2) ); + CPPUNIT_ASSERT( !(entry2 != entry) ); + } + // initialized + uninitialized + nextSubTest(); + { + BEntry entry(file1.cpath); + BEntry entry2; + CPPUNIT_ASSERT( !(entry == entry2) ); + CPPUNIT_ASSERT( !(entry2 == entry) ); + CPPUNIT_ASSERT( entry != entry2 ); + CPPUNIT_ASSERT( entry2 != entry ); + } + { + BEntry entry; + BEntry entry2(file1.cpath); + CPPUNIT_ASSERT( !(entry == entry2) ); + CPPUNIT_ASSERT( !(entry2 == entry) ); + CPPUNIT_ASSERT( entry != entry2 ); + CPPUNIT_ASSERT( entry2 != entry ); + } + // initialized + TestEntry *testEntries[] = { + &dir1, &dir2, &file1, &subDir1, &abstractEntry1, &badEntry1, + &absDirLink1, &absDirLink2, &absDirLink3, &absDirLink4, + &relDirLink1, &relDirLink2, &relDirLink3, &relDirLink4, + &absFileLink1, &absFileLink2, &absFileLink3, &absFileLink4, + &relFileLink1, &relFileLink2, &relFileLink3, &relFileLink4, + &absBadLink1, &absBadLink2, &absBadLink3, &absBadLink4, + &relBadLink1, &relBadLink2, &relBadLink3, &relBadLink4, + &absVeryBadLink1, &absVeryBadLink2, &absVeryBadLink3, &absVeryBadLink4, + &relVeryBadLink1, &relVeryBadLink2, &relVeryBadLink3, &relVeryBadLink4 + }; + int32 testEntryCount = sizeof(testEntries) / sizeof(TestEntry*); + for (int32 i = 0; i < testEntryCount; i++) { + nextSubTest(); + TestEntry *testEntry = testEntries[i]; + TestEntry *traversedTestEntry = resolve_link(testEntry); + BEntry entry(testEntry->cpath); + BEntry traversedEntry(testEntry->cpath, true); + for (int32 k = 0; k < testEntryCount; k++) { + TestEntry *testEntry2 = testEntries[k]; + TestEntry *traversedTestEntry2 = resolve_link(testEntry2); + BEntry entry2(testEntry2->cpath); + BEntry traversedEntry2(testEntry2->cpath, true); + compareEntries(entry, entry2, testEntry, testEntry2, false, false); + compareEntries(traversedEntry, entry2, + traversedTestEntry, testEntry2, true, false); + compareEntries(entry, traversedEntry2, + testEntry, traversedTestEntry2, false, true); + compareEntries(traversedEntry, traversedEntry2, + traversedTestEntry, traversedTestEntry2, + true, true); + } + } +} + +// AssignmentTest +void +EntryTest::AssignmentTest() +{ + // 1. copy constructor + // uninitialized + nextSubTest(); + { + BEntry entry; + CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT ); + BEntry entry2(entry); +// R5: returns B_BAD_VALUE instead of B_NO_INIT + CPPUNIT_ASSERT( equals(entry2.InitCheck(), B_BAD_VALUE, B_NO_INIT) ); + CPPUNIT_ASSERT( entry == entry2 ); + } + // initialized + TestEntry *testEntries[] = { + &dir1, &dir2, &file1, &subDir1, &abstractEntry1, &badEntry1, + &absDirLink1, &absDirLink2, &absDirLink3, &absDirLink4, + &relDirLink1, &relDirLink2, &relDirLink3, &relDirLink4, + &absFileLink1, &absFileLink2, &absFileLink3, &absFileLink4, + &relFileLink1, &relFileLink2, &relFileLink3, &relFileLink4, + &absBadLink1, &absBadLink2, &absBadLink3, &absBadLink4, + &relBadLink1, &relBadLink2, &relBadLink3, &relBadLink4, + &absVeryBadLink1, &absVeryBadLink2, &absVeryBadLink3, &absVeryBadLink4, + &relVeryBadLink1, &relVeryBadLink2, &relVeryBadLink3, &relVeryBadLink4 + }; + int32 testEntryCount = sizeof(testEntries) / sizeof(TestEntry*); + for (int32 i = 0; i < testEntryCount; i++) { + nextSubTest(); + TestEntry *testEntry = testEntries[i]; + BEntry entry(testEntry->cpath); + BEntry entry2(entry); + CPPUNIT_ASSERT( entry == entry2 ); + CPPUNIT_ASSERT( entry2 == entry ); + CPPUNIT_ASSERT( !(entry != entry2) ); + CPPUNIT_ASSERT( !(entry2 != entry) ); + } + + // 2. assignment operator + // uninitialized + nextSubTest(); + { + BEntry entry; + CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT ); + BEntry entry2; + entry2 = entry; +// R5: returns B_BAD_VALUE instead of B_NO_INIT + CPPUNIT_ASSERT( equals(entry2.InitCheck(), B_BAD_VALUE, B_NO_INIT) ); + CPPUNIT_ASSERT( entry == entry2 ); + } + nextSubTest(); + { + BEntry entry; + CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT ); + BEntry entry2(file1.cpath); + entry2 = entry; +// R5: returns B_BAD_VALUE instead of B_NO_INIT + CPPUNIT_ASSERT( equals(entry2.InitCheck(), B_BAD_VALUE, B_NO_INIT) ); + CPPUNIT_ASSERT( entry == entry2 ); + } + // initialized + for (int32 i = 0; i < testEntryCount; i++) { + nextSubTest(); + TestEntry *testEntry = testEntries[i]; + BEntry entry(testEntry->cpath); + BEntry entry2; + BEntry entry3(file1.cpath); + entry2 = entry; + entry3 = entry; + CPPUNIT_ASSERT( entry == entry2 ); + CPPUNIT_ASSERT( entry2 == entry ); + CPPUNIT_ASSERT( !(entry != entry2) ); + CPPUNIT_ASSERT( !(entry2 != entry) ); + CPPUNIT_ASSERT( entry == entry3 ); + CPPUNIT_ASSERT( entry3 == entry ); + CPPUNIT_ASSERT( !(entry != entry3) ); + CPPUNIT_ASSERT( !(entry3 != entry) ); + } +} + +// get_entry_ref_for_entry +static +status_t +get_entry_ref_for_entry(const char *dir, const char *leaf, entry_ref *ref) +{ + status_t error = (dir && leaf ? B_OK : B_BAD_VALUE); + struct stat dirStat; + if (lstat(dir, &dirStat) == 0) { + ref->device = dirStat.st_dev; + ref->directory = dirStat.st_ino; + ref->set_name(leaf); + } else + error = errno; + return error; +} + +// entry_ref > +bool +operator>(const entry_ref & a, const entry_ref & b) +{ + return (a.device > b.device + || (a.device == b.device + && (a.directory > b.directory + || (a.directory == b.directory + && (a.name != NULL && b.name == NULL + || (a.name != NULL && b.name != NULL + && strcmp(a.name, b.name) > 0)))))); +} + +// CFunctionsTest +void +EntryTest::CFunctionsTest() +{ + // get_ref_for_path(), < + TestEntry *testEntries[] = { + &dir1, &dir2, &file1, &subDir1, &abstractEntry1, &badEntry1, + &absDirLink1, &absDirLink2, &absDirLink3, &absDirLink4, + &relDirLink1, &relDirLink2, &relDirLink3, &relDirLink4, + &absFileLink1, &absFileLink2, &absFileLink3, &absFileLink4, + &relFileLink1, &relFileLink2, &relFileLink3, &relFileLink4, + &absBadLink1, &absBadLink2, &absBadLink3, &absBadLink4, + &relBadLink1, &relBadLink2, &relBadLink3, &relBadLink4, + &absVeryBadLink1, &absVeryBadLink2, &absVeryBadLink3, &absVeryBadLink4, + &relVeryBadLink1, &relVeryBadLink2, &relVeryBadLink3, &relVeryBadLink4 + }; + int32 testEntryCount = sizeof(testEntries) / sizeof(TestEntry*); + for (int32 i = 0; i < testEntryCount; i++) { + nextSubTest(); + TestEntry *testEntry = testEntries[i]; + const char *path = testEntry->cpath; + entry_ref ref; + if (testEntry->isBad()) + CPPUNIT_ASSERT( get_ref_for_path(path, &ref) == B_ENTRY_NOT_FOUND ); + else { + CPPUNIT_ASSERT( get_ref_for_path(path, &ref) == B_OK ); + const entry_ref &testEntryRef = testEntry->get_ref(); + CPPUNIT_ASSERT( testEntryRef.device == ref.device ); + CPPUNIT_ASSERT( testEntryRef.directory == ref.directory ); + CPPUNIT_ASSERT( strcmp(testEntryRef.name, ref.name) == 0 ); + CPPUNIT_ASSERT( testEntryRef == ref ); + CPPUNIT_ASSERT( !(testEntryRef != ref) ); + CPPUNIT_ASSERT( ref == testEntryRef ); + CPPUNIT_ASSERT( !(ref != testEntryRef) ); + for (int32 k = 0; k < testEntryCount; k++) { + TestEntry *testEntry2 = testEntries[k]; + const char *path2 = testEntry2->cpath; + entry_ref ref2; + if (!testEntry2->isBad()) { + CPPUNIT_ASSERT( get_ref_for_path(path2, &ref2) == B_OK ); + int cmp = 0; + if (ref > ref2) + cmp = 1; + else if (ref2 > ref) + cmp = -1; + CPPUNIT_ASSERT( (ref == ref2) == (cmp == 0) ); + CPPUNIT_ASSERT( (ref2 == ref) == (cmp == 0) ); + CPPUNIT_ASSERT( (ref != ref2) == (cmp != 0) ); + CPPUNIT_ASSERT( (ref2 != ref) == (cmp != 0) ); + CPPUNIT_ASSERT( (ref < ref2) == (cmp < 0) ); + CPPUNIT_ASSERT( (ref2 < ref) == (cmp > 0) ); + } + } + } + } + // root dir + nextSubTest(); + entry_ref ref, ref2; + CPPUNIT_ASSERT( get_ref_for_path("/", &ref) == B_OK ); + CPPUNIT_ASSERT( get_entry_ref_for_entry("/", ".", &ref2) == B_OK ); + CPPUNIT_ASSERT( ref.device == ref2.device ); + CPPUNIT_ASSERT( ref.directory == ref2.directory ); + CPPUNIT_ASSERT( strcmp(ref.name, ref2.name) == 0 ); + CPPUNIT_ASSERT( ref == ref2 ); + // fs root dir + nextSubTest(); + CPPUNIT_ASSERT( get_ref_for_path("/boot", &ref) == B_OK ); + CPPUNIT_ASSERT( get_entry_ref_for_entry("/", "boot", &ref2) == B_OK ); + CPPUNIT_ASSERT( ref.device == ref2.device ); + CPPUNIT_ASSERT( ref.directory == ref2.directory ); + CPPUNIT_ASSERT( strcmp(ref.name, ref2.name) == 0 ); + CPPUNIT_ASSERT( ref == ref2 ); + // uninitialized + nextSubTest(); + ref = entry_ref(); + ref2 = entry_ref(); + CPPUNIT_ASSERT( ref == ref2 ); + CPPUNIT_ASSERT( !(ref != ref2) ); + CPPUNIT_ASSERT( !(ref < ref2) ); + CPPUNIT_ASSERT( !(ref2 < ref) ); + CPPUNIT_ASSERT( get_entry_ref_for_entry("/", ".", &ref2) == B_OK ); + CPPUNIT_ASSERT( !(ref == ref2) ); + CPPUNIT_ASSERT( ref != ref2 ); + CPPUNIT_ASSERT( ref < ref2 ); + CPPUNIT_ASSERT( !(ref2 < ref) ); +} + + +// isHarmlessPathname +bool +isHarmlessPathname(const char *path) +{ + bool result = false; + if (path) { + const char *harmlessDir = "/boot/var/tmp/"; + result = (string(path).find(harmlessDir) == 0); + } +if (!result) +printf("WARNING: `%s' is not a harmless pathname.\n", path); + return result; +} + +// CreateLink +void +EntryTest::CreateLink(const char *link, const char *target) +{ + if (link && target && isHarmlessPathname(link)) { + execCommand(string("rm -rf ") + link + + " ; ln -s " + target + " " + link); + } +} + +// CreateFile +void +EntryTest::CreateFile(const char *file) +{ + if (file && isHarmlessPathname(file)) + execCommand(string("rm -rf ") + file + " ; touch " + file); +} + +// CreateDir +void +EntryTest::CreateDir(const char *dir) +{ + if (dir && isHarmlessPathname(dir)) + execCommand(string("rm -rf ") + dir + " ; mkdir " + dir); +} + +// RemoveFile +void +EntryTest::RemoveFile(const char *file) +{ + if (file && isHarmlessPathname(file)) + execCommand(string("rm -rf ") + file); +} + +// PingFile +bool +EntryTest::PingFile(const char *path, BEntry *entry) +{ + bool result = false; + // check existence and type + struct stat st; + if (lstat(path, &st) == 0) + result = (S_ISREG(st.st_mode)); + // check entry + if (result && entry) { + BPath entryPath; + result = (entry->GetPath(&entryPath) == B_OK && entryPath == path); + } + return result; +} + +// PingDir +bool +EntryTest::PingDir(const char *path, BEntry *entry) +{ + bool result = false; + // check existence and type + struct stat st; + if (lstat(path, &st) == 0) + result = (S_ISDIR(st.st_mode)); + // check entry + if (result && entry) { + BPath entryPath; + result = (entry->GetPath(&entryPath) == B_OK && entryPath == path); + } + return result; +} + +// PingLink +bool +EntryTest::PingLink(const char *path, const char *target, BEntry *entry) +{ + bool result = false; + // check existence and type + struct stat st; + if (lstat(path, &st) == 0) + result = (S_ISLNK(st.st_mode)); + // check target + if (result && target) { + char linkTarget[B_PATH_NAME_LENGTH + 1]; + ssize_t size = readlink(path, linkTarget, B_PATH_NAME_LENGTH); + result = (size >= 0); + if (result) { + linkTarget[size] = 0; + result = (string(linkTarget) == target); + } + } + // check entry + if (result && entry) { + BPath entryPath; + result = (entry->GetPath(&entryPath) == B_OK && entryPath == path); + } + return result; +} + +// MiscTest +void +EntryTest::MiscTest() +{ + BNode node(file1.cpath); + BEntry entry(file1.cpath); + + CPPUNIT_ASSERT(node.Lock() == B_OK); + CPPUNIT_ASSERT( entry.Exists() ); +} + + + +// directory name for too long path name (70 characters) +static const char *tooLongDirname = + "1234567890123456789012345678901234567890123456789012345678901234567890"; + +// too long entry name (257 characters) +static const char *tooLongEntryname = + "1234567890123456789012345678901234567890123456789012345678901234567890" + "1234567890123456789012345678901234567890123456789012345678901234567890" + "1234567890123456789012345678901234567890123456789012345678901234567890" + "12345678901234567890123456789012345678901234567"; + +// init_entry_test +static +void +init_entry_test() +{ + // root dir for testing + testDir.initDir(badTestEntry, "testDir"); + testDir.initPath((string("/boot/var/tmp/") + testDir.name).c_str()); + allTestEntries.pop_back(); + // other entries + dir1.initDir(testDir, "dir1"); + dir2.initDir(testDir, "dir2"); + file1.initFile(dir1, "file1"); + file2.init(dir1, "file2", ABSTRACT_ENTRY); + file3.init(dir2, "file3", ABSTRACT_ENTRY); + file4.init(dir1, "file4", ABSTRACT_ENTRY); + subDir1.initDir(dir1, "subDir1"); + abstractEntry1.init(dir1, "abstractEntry1", ABSTRACT_ENTRY); + badEntry1.init(abstractEntry1, "badEntry1", BAD_ENTRY); + absDirLink1.initALink(dir1, "absDirLink1", subDir1); + absDirLink2.initALink(dir1, "absDirLink2", absDirLink1); + absDirLink3.initALink(dir2, "absDirLink3", absDirLink2); + absDirLink4.initALink(testDir, "absDirLink4", absDirLink3); + relDirLink1.initRLink(dir1, "relDirLink1", subDir1); + relDirLink2.initRLink(dir1, "relDirLink2", relDirLink1); + relDirLink3.initRLink(dir2, "relDirLink3", relDirLink2); + relDirLink4.initRLink(testDir, "relDirLink4", relDirLink3); + absFileLink1.initALink(dir1, "absFileLink1", file1); + absFileLink2.initALink(dir1, "absFileLink2", absFileLink1); + absFileLink3.initALink(dir2, "absFileLink3", absFileLink2); + absFileLink4.initALink(testDir, "absFileLink4", absFileLink3); + relFileLink1.initRLink(dir1, "relFileLink1", file1); + relFileLink2.initRLink(dir1, "relFileLink2", relFileLink1); + relFileLink3.initRLink(dir2, "relFileLink3", relFileLink2); + relFileLink4.initRLink(testDir, "relFileLink4", relFileLink3); + absCyclicLink1.initALink(dir1, "absCyclicLink1", absCyclicLink2); + absCyclicLink2.initALink(dir1, "absCyclicLink2", absCyclicLink1); + relCyclicLink1.initRLink(dir1, "relCyclicLink1", relCyclicLink2); + relCyclicLink2.initRLink(dir1, "relCyclicLink2", relCyclicLink1); + absBadLink1.initALink(dir1, "absBadLink1", abstractEntry1); + absBadLink2.initALink(dir1, "absBadLink2", absBadLink1); + absBadLink3.initALink(dir2, "absBadLink3", absBadLink2); + absBadLink4.initALink(testDir, "absBadLink4", absBadLink3); + relBadLink1.initRLink(dir1, "relBadLink1", abstractEntry1); + relBadLink2.initRLink(dir1, "relBadLink2", relBadLink1); + relBadLink3.initRLink(dir2, "relBadLink3", relBadLink2); + relBadLink4.initRLink(testDir, "relBadLink4", relBadLink3); + absVeryBadLink1.initALink(dir1, "absVeryBadLink1", badEntry1); + absVeryBadLink2.initALink(dir1, "absVeryBadLink2", absVeryBadLink1); + absVeryBadLink3.initALink(dir2, "absVeryBadLink3", absVeryBadLink2); + absVeryBadLink4.initALink(testDir, "absVeryBadLink4", absVeryBadLink3); + relVeryBadLink1.initRLink(dir1, "relVeryBadLink1", badEntry1); + relVeryBadLink2.initRLink(dir1, "relVeryBadLink2", relVeryBadLink1); + relVeryBadLink3.initRLink(dir2, "relVeryBadLink3", relVeryBadLink2); + relVeryBadLink4.initRLink(testDir, "relVeryBadLink4", relVeryBadLink3); + tooLongEntry1.init(testDir, tooLongEntryname, ABSTRACT_ENTRY); + tooLongDir1.initDir(testDir, tooLongDirname); + tooLongDir2.initDir(tooLongDir1, tooLongDirname); + tooLongDir3.initDir(tooLongDir2, tooLongDirname); + tooLongDir4.initDir(tooLongDir3, tooLongDirname); + tooLongDir5.initDir(tooLongDir4, tooLongDirname); + tooLongDir6.initDir(tooLongDir5, tooLongDirname); + tooLongDir7.initDir(tooLongDir6, tooLongDirname); + tooLongDir8.initDir(tooLongDir7, tooLongDirname); + tooLongDir9.initDir(tooLongDir8, tooLongDirname); + tooLongDir10.initDir(tooLongDir9, tooLongDirname); + tooLongDir11.initDir(tooLongDir10, tooLongDirname); + tooLongDir12.initDir(tooLongDir11, tooLongDirname); + tooLongDir13.initDir(tooLongDir12, tooLongDirname); + tooLongDir14.initDir(tooLongDir13, tooLongDirname); + tooLongDir15.initDir(tooLongDir14, tooLongDirname); + tooLongDir16.initDir(tooLongDir15, tooLongDirname); + + // init paths + for (list::iterator it = allTestEntries.begin(); + it != allTestEntries.end(); it++) { + (*it)->initPath(); + } + // complete initialization + testDir.completeInit(); + for (list::iterator it = allTestEntries.begin(); + it != allTestEntries.end(); it++) { + (*it)->completeInit(); + } + // create the set up command line + setUpCommandLine = string("mkdir ") + testDir.path; + for (list::iterator it = allTestEntries.begin(); + it != allTestEntries.end(); it++) { + TestEntry *entry = *it; + string command; + switch (entry->kind) { + case ABSTRACT_ENTRY: + break; + case DIR_ENTRY: + { + if (entry->path.length() < B_PATH_NAME_LENGTH) { + command = string("mkdir ") + entry->path; + } else { + command = string("( ") + + "cd " + entry->super->super->path + " ; " + + " mkdir " + entry->super->name + "/" + entry->name + + " )"; + } + break; + } + case FILE_ENTRY: + { + command = string("touch ") + entry->path; + break; + } + case LINK_ENTRY: + { + command = string("ln -s ") + entry->link + " " + entry->path; + break; + } + default: + break; + } + if (command.length() > 0) { + if (setUpCommandLine.length() == 0) + setUpCommandLine = command; + else + setUpCommandLine += string(" ; ") + command; + } + } + // create the tear down command line + tearDownCommandLine = string("rm -rf ") + testDir.path; +} + +struct InitEntryTest { + InitEntryTest() + { + init_entry_test(); + } +} _InitEntryTest; + + +// TestEntry + +// constructor +TestEntry::TestEntry() + : super(&badTestEntry), + name("badTestEntry"), + kind(BAD_ENTRY), + path("/tmp/badTestEntry"), + target(&badTestEntry), + link(), + ref(), + relative(true), + cname(""), + cpath(""), + clink("") +{ +} + +// init +void +TestEntry::init(TestEntry &super, string name, test_entry_kind kind, + bool relative) +{ + this->super = &super; + this->name = name; + this->kind = kind; + this->relative = relative; + allTestEntries.push_back(this); +} + +// initDir +void +TestEntry::initDir(TestEntry &super, string name) +{ + init(super, name, DIR_ENTRY); +} + +// initFile +void +TestEntry::initFile(TestEntry &super, string name) +{ + init(super, name, FILE_ENTRY); +} + +// initRLink +void +TestEntry::initRLink(TestEntry &super, string name, TestEntry &target) +{ + init(super, name, LINK_ENTRY, true); + this->target = ⌖ +} + +// initALink +void +TestEntry::initALink(TestEntry &super, string name, TestEntry &target) +{ + init(super, name, LINK_ENTRY, false); + this->target = ⌖ +} + +// initPath +void +TestEntry::initPath(const char *pathName) +{ + if (pathName) + path = pathName; + else + path = super->path + "/" + name; +} + +// completeInit +void +TestEntry::completeInit() +{ + // init link + if (kind == LINK_ENTRY) { + if (relative) + link = get_shortest_relative_path(super, target); + else + link = target->path; + } + // init the C strings + cname = name.c_str(); + cpath = path.c_str(); + clink = link.c_str(); +} + +// get_ref +const entry_ref & +TestEntry::get_ref() +{ + if (isConcrete() || isAbstract()) + get_entry_ref_for_entry(super->cpath, cname, &ref); + return ref; +} + +// get_shortest_relative_path +static +string +get_shortest_relative_path(TestEntry *dir, TestEntry *entry) +{ + string relPath; + // put all super directories (including dir itself) of the dir in a set + map superDirs; + int dirSuperLevel = 0; + for (TestEntry *superDir = dir; + superDir != &badTestEntry; + superDir = superDir->super, dirSuperLevel++) { + superDirs[superDir] = dirSuperLevel; + } + // find the first super dir that dir and entry have in common + TestEntry *commonSuperDir = &badTestEntry; + int targetSuperLevel = 0; + for (TestEntry *superDir = entry; + commonSuperDir == &badTestEntry + && superDir != &badTestEntry; + superDir = superDir->super, targetSuperLevel++) { + if (superDirs.find(superDir) != superDirs.end()) + commonSuperDir = superDir; + } + // construct the relative path + if (commonSuperDir != &badTestEntry) { + dirSuperLevel = superDirs[commonSuperDir]; + if (dirSuperLevel == 0 && targetSuperLevel == 0) { + // entry == dir + relPath == "."; + } else { + // levels down + for (TestEntry *superDir = entry; + superDir != commonSuperDir; + superDir = superDir->super) { + if (relPath.length() == 0) + relPath = superDir->name; + else + relPath = superDir->name + "/" + relPath; + } + // levels up + for (int i = dirSuperLevel; i > 0; i--) { + if (relPath.length() == 0) + relPath = ".."; + else + relPath = string("../") + relPath; + } + } + } + return relPath; +} + +// resolve_link +static +TestEntry * +resolve_link(TestEntry *entry) +{ + set followedLinks; + while (entry != &badTestEntry && entry->kind == LINK_ENTRY) { + if (followedLinks.find(entry) == followedLinks.end()) { + followedLinks.insert(entry); + entry = entry->target; + } else + entry = &badTestEntry; // cyclic link + } + return entry; +} diff --git a/src/tests/kits/storage/EntryTest.h b/src/tests/kits/storage/EntryTest.h new file mode 100644 index 0000000000..7f65167506 --- /dev/null +++ b/src/tests/kits/storage/EntryTest.h @@ -0,0 +1,109 @@ +// EntryTest.h + +#ifndef __sk_entry_test_h__ +#define __sk_entry_test_h__ + +#include "StatableTest.h" + +#include "Test.StorageKit.h" +#include "TestUtils.h" + +class BEntry; +struct TestEntry; + +class EntryTest : public StatableTest +{ +public: + static CppUnit::Test* Suite(); + + virtual void CreateROStatables(TestStatables& testEntries); + virtual void CreateRWStatables(TestStatables& testEntries); + virtual void CreateUninitializedStatables(TestStatables& testEntries); + + // This function called before *each* test added in Suite() + void setUp(); + + // This function called after *each* test added in Suite() + void tearDown(); + + //------------------------------------------------------------------------- + // Test functions + //------------------------------------------------------------------------- + void InitTest1Paths(TestEntry &testEntry, status_t error, + bool traverse = false); + void InitTest1Refs(TestEntry &testEntry, status_t error, + bool traverse = false); + void InitTest1DirPaths(TestEntry &testEntry, status_t error, + bool traverse = false); + void InitTest1(); + + void InitTest2Paths(TestEntry &testEntry, status_t error, + bool traverse = false); + void InitTest2Refs(TestEntry &testEntry, status_t error, + bool traverse = false); + void InitTest2DirPaths(TestEntry &testEntry, status_t error, + bool traverse = false); + void InitTest2(); + + void ExistenceTest(); + void SpecialGetCasesTest(); + + void RenameTestEntry(TestEntry *testEntry, TestEntry *newTestEntry, + string newName, bool existing, bool clobber, + status_t error, uint32 kind); + void RenameTestEntry(TestEntry *testEntry, TestEntry *newTestEntry, + bool existing, bool clobber, + status_t error, uint32 kind); + void RenameTestFile(TestEntry *testEntry, TestEntry *newTestEntry, + bool existing, bool clobber, status_t error); + void RenameTestDir(TestEntry *testEntry, TestEntry *newTestEntry, + bool existing, bool clobber, status_t error); + void RenameTestLink(TestEntry *testEntry, TestEntry *newTestEntry, + bool existing, bool clobber, status_t error); + void RenameTest(); + + void MoveToTestEntry(TestEntry *testEntry, TestEntry *testDir, + string newName, bool existing, bool clobber, + status_t error, uint32 kind); + void MoveToTestEntry(TestEntry *testEntry, TestEntry *testDir, + TestEntry *newTestEntry, bool existing, bool clobber, + status_t error, uint32 kind); + void MoveToTestFile(TestEntry *testEntry, TestEntry *testDir, + TestEntry *newTestEntry, bool existing, bool clobber, + status_t error); + void MoveToTestDir(TestEntry *testEntry, TestEntry *testDir, + TestEntry *newTestEntry, bool existing, bool clobber, + status_t error); + void MoveToTestLink(TestEntry *testEntry, TestEntry *testDir, + TestEntry *newTestEntry, bool existing, bool clobber, + status_t error); + void MoveToTest(); + + void RemoveTest(); + void ComparisonTest(); + void AssignmentTest(); + void MiscTest(); + void CFunctionsTest(); + + //------------------------------------------------------------------------- + // Helper functions + //------------------------------------------------------------------------- + // Creates a symbolic link named link that points to target + void CreateLink(const char *link, const char *target); + // Creates the given file + void CreateFile(const char *file); + // Creates the given file + void CreateDir(const char *dir); + // Removes the given file if it exists + void RemoveFile(const char *file); + // Checks, whether a file exists. + bool PingFile(const char *path, BEntry *entry = NULL); + // Checks, whether a dir exists. + bool PingDir(const char *path, BEntry *entry = NULL); + // Checks, whether a symlink exists. + bool PingLink(const char *path, const char *target = NULL, + BEntry *entry = NULL); +}; + + +#endif // __sk_entry_test_h__ diff --git a/src/tests/kits/storage/FileTest.cpp b/src/tests/kits/storage/FileTest.cpp new file mode 100644 index 0000000000..fe77f7c7cd --- /dev/null +++ b/src/tests/kits/storage/FileTest.cpp @@ -0,0 +1,768 @@ +// FileTest.cpp + +#include +#include +#include +#include + +#include +#include + +#include "Test.StorageKit.h" // For "shell" global variable +#include "FileTest.h" + +// Suite +FileTest::Test* +FileTest::Suite() +{ + CppUnit::TestSuite *suite = new CppUnit::TestSuite(); + typedef CppUnit::TestCaller TC; + + NodeTest::AddBaseClassTests("BFile::", suite); + + suite->addTest( new TC("BFile::Init Test 1", &FileTest::InitTest1) ); + suite->addTest( new TC("BFile::Init Test 2", &FileTest::InitTest2) ); + suite->addTest( new TC("BFile::IsRead-/IsWriteable Test", + &FileTest::RWAbleTest) ); + suite->addTest( new TC("BFile::Read/Write Test", &FileTest::RWTest) ); + suite->addTest( new TC("BFile::Position Test", &FileTest::PositionTest) ); + suite->addTest( new TC("BFile::Size Test", &FileTest::SizeTest) ); + suite->addTest( new TC("BFile::Assignment Test", + &FileTest::AssignmentTest) ); + return suite; +} + +// CreateRONodes +void +FileTest::CreateRONodes(TestNodes& testEntries) +{ + testEntries.clear(); + const char *filename; + filename = existingFilename; + testEntries.add(new BFile(filename, B_READ_ONLY), filename); +} + +// CreateRWNodes +void +FileTest::CreateRWNodes(TestNodes& testEntries) +{ + testEntries.clear(); + const char *filename; + filename = existingFilename; + testEntries.add(new BFile(filename, B_READ_WRITE), filename); +} + +// CreateUninitializedNodes +void +FileTest::CreateUninitializedNodes(TestNodes& testEntries) +{ + testEntries.clear(); + testEntries.add(new BFile, ""); +} + +// setUp +void FileTest::setUp() +{ + NodeTest::setUp(); +} + +// tearDown +void FileTest::tearDown() +{ + NodeTest::tearDown(); +} + +// InitTest1 +void +FileTest::InitTest1() +{ + // 1. default constructor + { + BFile file; + CPPUNIT_ASSERT( file.InitCheck() == B_NO_INIT ); + } + + // helper class for the testing the different constructors versions + struct Tester { + void testAll() const + { + for (int32 i = 0; i < initTestCasesCount; i++) { + if (shell.BeVerbose()) { + printf("[%ld]", i); + fflush(stdout); + } + test(initTestCases[i]); + } + if (shell.BeVerbose()) + printf("\n"); + } + + virtual void test(const InitTestCase& tc) const = 0; + + static void testInit(const InitTestCase& tc, BFile& file) + { + CPPUNIT_ASSERT( file.InitCheck() == tc.initCheck ); + if (tc.removeAfterTest) + execCommand(string("rm ") + tc.filename); + } + }; + + // 2. BFile(const char *, uint32) + struct Tester1 : public Tester { + virtual void test(const InitTestCase& tc) const + { + BFile file(tc.filename, + tc.rwmode + | (tc.createFile * B_CREATE_FILE) + | (tc.failIfExists * B_FAIL_IF_EXISTS) + | (tc.eraseFile * B_ERASE_FILE)); + testInit(tc, file); + } + }; + + // 3. BFile(entry_ref *, uint32) + struct Tester2 : public Tester { + virtual void test(const InitTestCase& tc) const + { + entry_ref ref; + BEntry entry(tc.filename); + entry_ref *refToPass = &ref; + if (tc.filename) + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + else + refToPass = NULL; + BFile file(refToPass, + tc.rwmode + | (tc.createFile * B_CREATE_FILE) + | (tc.failIfExists * B_FAIL_IF_EXISTS) + | (tc.eraseFile * B_ERASE_FILE)); + testInit(tc, file); + } + }; + + // 4. BFile(BEntry *, uint32) + struct Tester3 : public Tester { + virtual void test(const InitTestCase& tc) const + { + entry_ref ref; + BEntry entry(tc.filename); + BEntry *entryToPass = &entry; + if (tc.filename) + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + else + entryToPass = NULL; + BFile file(entryToPass, + tc.rwmode + | (tc.createFile * B_CREATE_FILE) + | (tc.failIfExists * B_FAIL_IF_EXISTS) + | (tc.eraseFile * B_ERASE_FILE)); + testInit(tc, file); + } + }; + + // 5. BFile(BEntry *, uint32) + struct Tester4 : public Tester { + virtual void test(const InitTestCase& tc) const + { + if (tc.filename) { + BPath path(tc.filename); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + BPath dirPath; + CPPUNIT_ASSERT( path.GetParent(&dirPath) == B_OK ); + BDirectory dir(dirPath.Path()); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + BFile file(&dir, path.Leaf(), + tc.rwmode + | (tc.createFile * B_CREATE_FILE) + | (tc.failIfExists * B_FAIL_IF_EXISTS) + | (tc.eraseFile * B_ERASE_FILE)); + testInit(tc, file); + } + } + }; + + Tester1().testAll(); + Tester2().testAll(); + Tester3().testAll(); + Tester4().testAll(); +} + +// InitTest2 +void +FileTest::InitTest2() +{ + // helper class for the testing the different SetTo() versions + struct Tester { + void testAll() const + { + for (int32 i = 0; i < initTestCasesCount; i++) { + if (shell.BeVerbose()) { + printf("[%ld]", i); + fflush(stdout); + } + test(initTestCases[i]); + } + if (shell.BeVerbose()) + printf("\n"); + } + + virtual void test(const InitTestCase& tc) const = 0; + + static void testInit(const InitTestCase& tc, BFile& file) + { + CPPUNIT_ASSERT( file.InitCheck() == tc.initCheck ); + file.Unset(); + CPPUNIT_ASSERT( file.InitCheck() == B_NO_INIT ); + if (tc.removeAfterTest) + execCommand(string("rm ") + tc.filename); + } + }; + + // 2. BFile(const char *, uint32) + struct Tester1 : public Tester { + virtual void test(const InitTestCase& tc) const + { + BFile file; + status_t result = file.SetTo(tc.filename, + tc.rwmode + | (tc.createFile * B_CREATE_FILE) + | (tc.failIfExists * B_FAIL_IF_EXISTS) + | (tc.eraseFile * B_ERASE_FILE)); + CPPUNIT_ASSERT( result == tc.initCheck ); + testInit(tc, file); + } + }; + + // 3. BFile(entry_ref *, uint32) + struct Tester2 : public Tester { + virtual void test(const InitTestCase& tc) const + { + entry_ref ref; + BEntry entry(tc.filename); + entry_ref *refToPass = &ref; + if (tc.filename) + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + else + refToPass = NULL; + BFile file; + status_t result = file.SetTo(refToPass, + tc.rwmode + | (tc.createFile * B_CREATE_FILE) + | (tc.failIfExists * B_FAIL_IF_EXISTS) + | (tc.eraseFile * B_ERASE_FILE)); + CPPUNIT_ASSERT( result == tc.initCheck ); + testInit(tc, file); + } + }; + + // 4. BFile(BEntry *, uint32) + struct Tester3 : public Tester { + virtual void test(const InitTestCase& tc) const + { + entry_ref ref; + BEntry entry(tc.filename); + BEntry *entryToPass = &entry; + if (tc.filename) + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + else + entryToPass = NULL; + BFile file; + status_t result = file.SetTo(entryToPass, + tc.rwmode + | (tc.createFile * B_CREATE_FILE) + | (tc.failIfExists * B_FAIL_IF_EXISTS) + | (tc.eraseFile * B_ERASE_FILE)); + CPPUNIT_ASSERT( result == tc.initCheck ); + testInit(tc, file); + } + }; + + // 5. BFile(BEntry *, uint32) + struct Tester4 : public Tester { + virtual void test(const InitTestCase& tc) const + { + if (tc.filename) { + BPath path(tc.filename); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + BPath dirPath; + CPPUNIT_ASSERT( path.GetParent(&dirPath) == B_OK ); + BDirectory dir(dirPath.Path()); + CPPUNIT_ASSERT( dir.InitCheck() == B_OK ); + BFile file; + status_t result = file.SetTo(&dir, path.Leaf(), + tc.rwmode + | (tc.createFile * B_CREATE_FILE) + | (tc.failIfExists * B_FAIL_IF_EXISTS) + | (tc.eraseFile * B_ERASE_FILE)); + CPPUNIT_ASSERT( result == tc.initCheck ); + testInit(tc, file); + } + } + }; + + Tester1().testAll(); + Tester2().testAll(); + Tester3().testAll(); + Tester4().testAll(); +} + +// RWAbleTest +void +FileTest::RWAbleTest() +{ + nextSubTest(); + { + BFile file; + CPPUNIT_ASSERT( file.IsReadable() == false ); + CPPUNIT_ASSERT( file.IsWritable() == false ); + } + nextSubTest(); + { + BFile file(existingFilename, B_READ_ONLY); + CPPUNIT_ASSERT( file.IsReadable() == true ); + CPPUNIT_ASSERT( file.IsWritable() == false ); + } + nextSubTest(); + { + BFile file(existingFilename, B_WRITE_ONLY); + CPPUNIT_ASSERT( file.IsReadable() == false ); + CPPUNIT_ASSERT( file.IsWritable() == true ); + } + nextSubTest(); + { + BFile file(existingFilename, B_READ_WRITE); + CPPUNIT_ASSERT( file.IsReadable() == true ); + CPPUNIT_ASSERT( file.IsWritable() == true ); + } + nextSubTest(); + { + BFile file(nonExistingFilename, B_READ_WRITE); + CPPUNIT_ASSERT( file.IsReadable() == false ); + CPPUNIT_ASSERT( file.IsWritable() == false ); + } +} + +// RWTest +void +FileTest::RWTest() +{ + // read/write an uninitialized BFile + nextSubTest(); + BFile file; + char buffer[10]; + CPPUNIT_ASSERT( file.Read(buffer, sizeof(buffer)) < 0 ); + CPPUNIT_ASSERT( file.ReadAt(0, buffer, sizeof(buffer)) < 0 ); + CPPUNIT_ASSERT( file.Write(buffer, sizeof(buffer)) < 0 ); + CPPUNIT_ASSERT( file.WriteAt(0, buffer, sizeof(buffer)) < 0 ); + file.Unset(); + // read/write an file opened for writing/reading only + nextSubTest(); + file.SetTo(existingFilename, B_WRITE_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( file.Read(buffer, sizeof(buffer)) < 0 ); + CPPUNIT_ASSERT( file.ReadAt(0, buffer, sizeof(buffer)) < 0 ); + file.SetTo(existingFilename, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( file.Write(buffer, sizeof(buffer)) < 0 ); + CPPUNIT_ASSERT( file.WriteAt(0, buffer, sizeof(buffer)) < 0 ); + file.Unset(); + // read from an empty file + nextSubTest(); + file.SetTo(existingFilename, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( file.Read(buffer, sizeof(buffer)) == 0 ); + CPPUNIT_ASSERT( file.ReadAt(0, buffer, sizeof(buffer)) == 0 ); + file.Unset(); + // read from past an empty file + nextSubTest(); + file.SetTo(existingFilename, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( file.Seek(10, SEEK_SET) == 10 ); + CPPUNIT_ASSERT( file.Read(buffer, sizeof(buffer)) == 0 ); + CPPUNIT_ASSERT( file.ReadAt(10, buffer, sizeof(buffer)) == 0 ); + file.Unset(); + // create a new empty file and write some data into it, then + // read the file and check the data + nextSubTest(); + file.SetTo(testFilename1, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + char writeBuffer[256]; + for (int32 i = 0; i < 256; i++) + writeBuffer[i] = (char)i; + CPPUNIT_ASSERT( file.Write(writeBuffer, 128) == 128 ); + CPPUNIT_ASSERT( file.Position() == 128 ); + CPPUNIT_ASSERT( file.Write(writeBuffer + 128, 128) == 128 ); + CPPUNIT_ASSERT( file.Position() == 256 ); + file.Unset(); + file.SetTo(testFilename1, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + char readBuffer[256]; + CPPUNIT_ASSERT( file.Read(readBuffer, 42) == 42 ); + CPPUNIT_ASSERT( file.Position() == 42 ); + CPPUNIT_ASSERT( file.Read(readBuffer + 42, 400) == 214 ); + CPPUNIT_ASSERT( file.Position() == 256 ); + for (int32 i = 0; i < 256; i++) + CPPUNIT_ASSERT( readBuffer[i] == (char)i ); + file.Unset(); + execCommand(string("rm -f ") + testFilename1); + // same procedure, just using ReadAt()/WriteAt() + nextSubTest(); + file.SetTo(testFilename1, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( file.WriteAt(80, writeBuffer + 80, 50) == 50 ); + CPPUNIT_ASSERT( file.Position() == 0 ); + CPPUNIT_ASSERT( file.WriteAt(0, writeBuffer, 80) == 80 ); + CPPUNIT_ASSERT( file.Position() == 0 ); + CPPUNIT_ASSERT( file.WriteAt(130, writeBuffer + 130, 126) == 126 ); + CPPUNIT_ASSERT( file.Position() == 0 ); + file.Unset(); + file.SetTo(testFilename1, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + for (int32 i = 0; i < 256; i++) + readBuffer[i] = 0; + CPPUNIT_ASSERT( file.ReadAt(42, readBuffer + 42, 84) == 84 ); + CPPUNIT_ASSERT( file.Position() == 0 ); + CPPUNIT_ASSERT( file.ReadAt(0, readBuffer, 42) == 42 ); + CPPUNIT_ASSERT( file.Position() == 0 ); + CPPUNIT_ASSERT( file.ReadAt(126, readBuffer + 126, 130) == 130 ); + CPPUNIT_ASSERT( file.Position() == 0 ); + for (int32 i = 0; i < 256; i++) + CPPUNIT_ASSERT( readBuffer[i] == (char)i ); + file.Unset(); + execCommand(string("rm -f ") + testFilename1); + // write past the end of a file + nextSubTest(); + file.SetTo(testFilename1, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( file.Seek(128, SEEK_SET) == 128 ); + CPPUNIT_ASSERT( file.Write(writeBuffer, 128) == 128 ); + CPPUNIT_ASSERT( file.Position() == 256 ); + file.Unset(); + // open the file with B_OPEN_AT_END flag, Write() some data to it, close + // and re-open it to check the file + nextSubTest(); + file.SetTo(testFilename1, B_WRITE_ONLY | B_OPEN_AT_END); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + for (int32 i = 0; i < 256; i++) + writeBuffer[i] = (char)7; + CPPUNIT_ASSERT( file.Write(writeBuffer, 50) == 50 ); + file.Seek(0, SEEK_SET); // might fail -- don't check the return value + CPPUNIT_ASSERT( file.Write(writeBuffer, 40) == 40 ); + file.Unset(); + file.SetTo(testFilename1, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( file.ReadAt(256, readBuffer, 90) == 90 ); + for (int32 i = 0; i < 90; i++) + CPPUNIT_ASSERT( readBuffer[i] == 7 ); + file.Unset(); + // open the file with B_OPEN_AT_END flag, WriteAt() some data to it, close + // and re-open it to check the file + nextSubTest(); + file.SetTo(testFilename1, B_WRITE_ONLY | B_OPEN_AT_END); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + for (int32 i = 0; i < 256; i++) + writeBuffer[i] = (char)42; + CPPUNIT_ASSERT( file.WriteAt(0, writeBuffer, 30) == 30 ); + file.Unset(); + file.SetTo(testFilename1, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( file.ReadAt(346, readBuffer, 30) == 30 ); + for (int32 i = 0; i < 30; i++) + CPPUNIT_ASSERT( readBuffer[i] == 42 ); + file.Unset(); + // open the file with B_OPEN_AT_END flag, ReadAt() some data + nextSubTest(); + file.SetTo(testFilename1, B_READ_ONLY | B_OPEN_AT_END); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + for (int32 i = 0; i < 256; i++) + readBuffer[i] = 0; + CPPUNIT_ASSERT( file.ReadAt(256, readBuffer, 90) == 90 ); + for (int32 i = 0; i < 90; i++) + CPPUNIT_ASSERT( readBuffer[i] == 7 ); + CPPUNIT_ASSERT( file.ReadAt(346, readBuffer, 30) == 30 ); + for (int32 i = 0; i < 30; i++) + CPPUNIT_ASSERT( readBuffer[i] == 42 ); + file.Unset(); + // same procedure, just using Seek() and Read() + nextSubTest(); + file.SetTo(testFilename1, B_READ_ONLY | B_OPEN_AT_END); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + for (int32 i = 0; i < 256; i++) + readBuffer[i] = 0; + file.Seek(256, SEEK_SET); // might fail -- don't check the return value + CPPUNIT_ASSERT( file.Read(readBuffer, 90) == 90 ); + for (int32 i = 0; i < 90; i++) + CPPUNIT_ASSERT( readBuffer[i] == 7 ); + CPPUNIT_ASSERT( file.ReadAt(346, readBuffer, 30) == 30 ); + for (int32 i = 0; i < 30; i++) + CPPUNIT_ASSERT( readBuffer[i] == 42 ); + file.Unset(); + + execCommand(string("rm -f ") + testFilename1); +} + +// PositionTest +void +FileTest::PositionTest() +{ + // unitialized file + nextSubTest(); + BFile file; + CPPUNIT_ASSERT( file.Position() == B_FILE_ERROR ); + CPPUNIT_ASSERT( file.Seek(10, SEEK_SET) == B_FILE_ERROR ); + CPPUNIT_ASSERT( file.Seek(10, SEEK_END) == B_FILE_ERROR ); + CPPUNIT_ASSERT( file.Seek(10, SEEK_CUR) == B_FILE_ERROR ); + // open new file, write some bytes to it and seek a bit around + nextSubTest(); + file.SetTo(testFilename1, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( file.Position() == 0 ); + char writeBuffer[256]; + CPPUNIT_ASSERT( file.Write(writeBuffer, 256) == 256 ); + CPPUNIT_ASSERT( file.Position() == 256 ); + CPPUNIT_ASSERT( file.Seek(10, SEEK_SET) == 10 ); + CPPUNIT_ASSERT( file.Position() == 10 ); + CPPUNIT_ASSERT( file.Seek(-20, SEEK_END) == 236 ); + CPPUNIT_ASSERT( file.Position() == 236 ); + CPPUNIT_ASSERT( file.Seek(-70, SEEK_CUR) == 166 ); + CPPUNIT_ASSERT( file.Position() == 166 ); + file.Unset(); + // re-open the file at the end and seek a bit around once more + // The BeBook is a bit unspecific about the B_OPEN_AT_END flag: + // It has probably the same meaning as the POSIX flag O_APPEND, which + // means, that all write()s append their data at the end. The behavior + // of Seek() and Position() is a bit unclear for this case. +/* + nextSubTest(); + file.SetTo(testFilename1, B_READ_ONLY | B_OPEN_AT_END); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( file.Position() == 256 ); + CPPUNIT_ASSERT( file.Seek(10, SEEK_SET) == 10 ); + CPPUNIT_ASSERT( file.Position() == 10 ); // fails with R5 + CPPUNIT_ASSERT( file.Seek(-20, SEEK_END) == 236 ); + CPPUNIT_ASSERT( file.Position() == 236 ); // fails with R5 + CPPUNIT_ASSERT( file.Seek(-70, SEEK_CUR) == 166 ); // fails with R5 + CPPUNIT_ASSERT( file.Position() == 166 ); // fails with R5 +*/ + file.Unset(); + execCommand(string("rm -f ") + testFilename1); +} + +// SizeTest +void +FileTest::SizeTest() +{ + // unitialized file + nextSubTest(); + BFile file; + off_t size; + CPPUNIT_ASSERT( file.GetSize(&size) != B_OK ); + CPPUNIT_ASSERT( file.SetSize(100) != B_OK ); + // read only file + nextSubTest(); + file.SetTo(testFilename1, B_READ_ONLY | B_CREATE_FILE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( file.GetSize(&size) == B_OK ); + CPPUNIT_ASSERT( size == 0 ); + CPPUNIT_ASSERT( file.SetSize(100) == B_OK ); + CPPUNIT_ASSERT( file.GetSize(&size) == B_OK ); + CPPUNIT_ASSERT( size == 100 ); + file.Unset(); + // shorten existing file + nextSubTest(); + file.SetTo(testFilename1, B_WRITE_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( file.GetSize(&size) == B_OK ); + CPPUNIT_ASSERT( size == 100 ); + CPPUNIT_ASSERT( file.SetSize(73) == B_OK ); + CPPUNIT_ASSERT( file.GetSize(&size) == B_OK ); + CPPUNIT_ASSERT( size == 73 ); + file.Unset(); + // enlarge existing file + nextSubTest(); + file.SetTo(testFilename1, B_READ_WRITE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( file.GetSize(&size) == B_OK ); + CPPUNIT_ASSERT( size == 73 ); + CPPUNIT_ASSERT( file.SetSize(147) == B_OK ); + CPPUNIT_ASSERT( file.GetSize(&size) == B_OK ); + CPPUNIT_ASSERT( size == 147 ); + file.Unset(); + // erase existing file (read only) + nextSubTest(); + file.SetTo(testFilename1, B_READ_ONLY | B_ERASE_FILE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( file.GetSize(&size) == B_OK ); + CPPUNIT_ASSERT( size == 0 ); + CPPUNIT_ASSERT( file.SetSize(132) == B_OK ); + CPPUNIT_ASSERT( file.GetSize(&size) == B_OK ); + CPPUNIT_ASSERT( size == 132 ); + file.Unset(); + // erase existing file (write only) + nextSubTest(); + file.SetTo(testFilename1, B_WRITE_ONLY | B_ERASE_FILE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( file.GetSize(&size) == B_OK ); + CPPUNIT_ASSERT( size == 0 ); + CPPUNIT_ASSERT( file.SetSize(93) == B_OK ); + CPPUNIT_ASSERT( file.GetSize(&size) == B_OK ); + CPPUNIT_ASSERT( size == 93 ); + file.Unset(); + // erase existing file using SetSize() + nextSubTest(); + file.SetTo(testFilename1, B_READ_WRITE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( file.GetSize(&size) == B_OK ); + CPPUNIT_ASSERT( size == 93 ); + CPPUNIT_ASSERT( file.SetSize(0) == B_OK ); + CPPUNIT_ASSERT( file.GetSize(&size) == B_OK ); + CPPUNIT_ASSERT( size == 0 ); + file.Unset(); + execCommand(string("rm -f ") + testFilename1); +} + +// AssignmentTest +void +FileTest::AssignmentTest() +{ + // copy constructor + // uninitialized + nextSubTest(); + { + BFile file; + CPPUNIT_ASSERT( file.InitCheck() == B_NO_INIT ); + BFile file2(file); + // R5 returns B_BAD_VALUE instead of B_NO_INIT + CPPUNIT_ASSERT( equals(file2.InitCheck(), B_BAD_VALUE, B_NO_INIT) ); + } + // existing file, different open modes + nextSubTest(); + { + BFile file(existingFilename, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BFile file2(file); + CPPUNIT_ASSERT( file2.InitCheck() == B_OK ); + CPPUNIT_ASSERT( file2.IsReadable() == true ); + CPPUNIT_ASSERT( file2.IsWritable() == false ); + } + nextSubTest(); + { + BFile file(existingFilename, B_WRITE_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BFile file2(file); + CPPUNIT_ASSERT( file2.InitCheck() == B_OK ); + CPPUNIT_ASSERT( file2.IsReadable() == false ); + CPPUNIT_ASSERT( file2.IsWritable() == true ); + } + nextSubTest(); + { + BFile file(existingFilename, B_READ_WRITE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BFile file2(file); + CPPUNIT_ASSERT( file2.InitCheck() == B_OK ); + CPPUNIT_ASSERT( file2.IsReadable() == true ); + CPPUNIT_ASSERT( file2.IsWritable() == true ); + } + // assignment operator + // uninitialized + nextSubTest(); + { + BFile file; + BFile file2; + file2 = file; + // R5 returns B_BAD_VALUE instead of B_NO_INIT + CPPUNIT_ASSERT( equals(file2.InitCheck(), B_BAD_VALUE, B_NO_INIT) ); + } + nextSubTest(); + { + BFile file; + BFile file2(existingFilename, B_READ_ONLY); + CPPUNIT_ASSERT( file2.InitCheck() == B_OK ); + file2 = file; + // R5 returns B_BAD_VALUE instead of B_NO_INIT + CPPUNIT_ASSERT( equals(file2.InitCheck(), B_BAD_VALUE, B_NO_INIT) ); + } + // existing file, different open modes + nextSubTest(); + { + BFile file(existingFilename, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BFile file2; + file2 = file; + CPPUNIT_ASSERT( file2.InitCheck() == B_OK ); + CPPUNIT_ASSERT( file2.IsReadable() == true ); + CPPUNIT_ASSERT( file2.IsWritable() == false ); + } + nextSubTest(); + { + BFile file(existingFilename, B_WRITE_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BFile file2; + file2 = file; + CPPUNIT_ASSERT( file2.InitCheck() == B_OK ); + CPPUNIT_ASSERT( file2.IsReadable() == false ); + CPPUNIT_ASSERT( file2.IsWritable() == true ); + } + nextSubTest(); + { + BFile file(existingFilename, B_READ_WRITE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BFile file2; + file2 = file; + CPPUNIT_ASSERT( file2.InitCheck() == B_OK ); + CPPUNIT_ASSERT( file2.IsReadable() == true ); + CPPUNIT_ASSERT( file2.IsWritable() == true ); + } +} + + + +// test cases for the init tests +const FileTest::InitTestCase FileTest::initTestCases[] = { + { existingFilename , B_READ_ONLY , 0, 0, 0, false, B_OK }, + { existingFilename , B_WRITE_ONLY, 0, 0, 0, false, B_OK }, + { existingFilename , B_READ_WRITE, 0, 0, 0, false, B_OK }, + { existingFilename , B_READ_ONLY , 1, 0, 0, false, B_OK }, + { existingFilename , B_WRITE_ONLY, 1, 0, 0, false, B_OK }, + { existingFilename , B_READ_WRITE, 1, 0, 0, false, B_OK }, + { existingFilename , B_READ_ONLY , 0, 1, 0, false, B_OK }, + { existingFilename , B_WRITE_ONLY, 0, 1, 0, false, B_OK }, + { existingFilename , B_READ_WRITE, 0, 1, 0, false, B_OK }, + { existingFilename , B_READ_ONLY , 0, 0, 1, false, B_OK }, + { existingFilename , B_WRITE_ONLY, 0, 0, 1, false, B_OK }, + { existingFilename , B_READ_WRITE, 0, 0, 1, false, B_OK }, + { existingFilename , B_READ_ONLY , 1, 1, 0, false, B_FILE_EXISTS }, + { existingFilename , B_WRITE_ONLY, 1, 1, 0, false, B_FILE_EXISTS }, + { existingFilename , B_READ_WRITE, 1, 1, 0, false, B_FILE_EXISTS }, + { existingFilename , B_READ_ONLY , 1, 0, 1, false, B_OK }, + { existingFilename , B_WRITE_ONLY, 1, 0, 1, false, B_OK }, + { existingFilename , B_READ_WRITE, 1, 0, 1, false, B_OK }, + { existingFilename , B_READ_ONLY , 1, 1, 1, false, B_FILE_EXISTS }, + { existingFilename , B_WRITE_ONLY, 1, 1, 1, false, B_FILE_EXISTS }, + { existingFilename , B_READ_WRITE, 1, 1, 1, false, B_FILE_EXISTS }, + { nonExistingFilename, B_READ_ONLY , 0, 0, 0, false, B_ENTRY_NOT_FOUND }, + { nonExistingFilename, B_WRITE_ONLY, 0, 0, 0, false, B_ENTRY_NOT_FOUND }, + { nonExistingFilename, B_READ_WRITE, 0, 0, 0, false, B_ENTRY_NOT_FOUND }, + { nonExistingFilename, B_READ_ONLY , 1, 0, 0, true , B_OK }, + { nonExistingFilename, B_WRITE_ONLY, 1, 0, 0, true , B_OK }, + { nonExistingFilename, B_READ_WRITE, 1, 0, 0, true , B_OK }, + { nonExistingFilename, B_READ_ONLY , 0, 1, 0, false, B_ENTRY_NOT_FOUND }, + { nonExistingFilename, B_WRITE_ONLY, 0, 1, 0, false, B_ENTRY_NOT_FOUND }, + { nonExistingFilename, B_READ_WRITE, 0, 1, 0, false, B_ENTRY_NOT_FOUND }, + { nonExistingFilename, B_READ_ONLY , 0, 0, 1, false, B_ENTRY_NOT_FOUND }, + { nonExistingFilename, B_WRITE_ONLY, 0, 0, 1, false, B_ENTRY_NOT_FOUND }, + { nonExistingFilename, B_READ_WRITE, 0, 0, 1, false, B_ENTRY_NOT_FOUND }, + { nonExistingFilename, B_READ_ONLY , 1, 1, 0, true , B_OK }, + { nonExistingFilename, B_WRITE_ONLY, 1, 1, 0, true , B_OK }, + { nonExistingFilename, B_READ_WRITE, 1, 1, 0, true , B_OK }, + { nonExistingFilename, B_READ_ONLY , 1, 0, 1, true , B_OK }, + { nonExistingFilename, B_WRITE_ONLY, 1, 0, 1, true , B_OK }, + { nonExistingFilename, B_READ_WRITE, 1, 0, 1, true , B_OK }, + { nonExistingFilename, B_READ_ONLY , 1, 1, 1, true , B_OK }, + { nonExistingFilename, B_WRITE_ONLY, 1, 1, 1, true , B_OK }, + { nonExistingFilename, B_READ_WRITE, 1, 1, 1, true , B_OK }, + { NULL, B_READ_ONLY , 1, 1, 1, false, B_BAD_VALUE }, +}; +const int32 FileTest::initTestCasesCount + = sizeof(FileTest::initTestCases) / sizeof(FileTest::InitTestCase); + diff --git a/src/tests/kits/storage/FileTest.h b/src/tests/kits/storage/FileTest.h new file mode 100644 index 0000000000..db3cfec61f --- /dev/null +++ b/src/tests/kits/storage/FileTest.h @@ -0,0 +1,49 @@ +// FileTest.h + +#ifndef __sk_file_test_h__ +#define __sk_file_test_h__ + +#include "NodeTest.h" + +class FileTest : public NodeTest +{ +public: + static Test* Suite(); + + virtual void CreateRONodes(TestNodes& testEntries); + virtual void CreateRWNodes(TestNodes& testEntries); + virtual void CreateUninitializedNodes(TestNodes& testEntries); + + // This function called before *each* test added in Suite() + void setUp(); + + // This function called after *each* test added in Suite() + void tearDown(); + + // test methods + + void InitTest1(); + void InitTest2(); + void RWAbleTest(); + void RWTest(); + void PositionTest(); + void SizeTest(); + void AssignmentTest(); + + // helper functions + + struct InitTestCase { + const char * filename; + uint32 rwmode; + uint32 createFile; + uint32 failIfExists; + uint32 eraseFile; + bool removeAfterTest; + status_t initCheck; + }; + + static const InitTestCase initTestCases[]; + static const int32 initTestCasesCount; +}; + +#endif // __sk_file_test_h__ diff --git a/src/tests/kits/storage/FindDirectoryTest.cpp b/src/tests/kits/storage/FindDirectoryTest.cpp new file mode 100644 index 0000000000..f523631576 --- /dev/null +++ b/src/tests/kits/storage/FindDirectoryTest.cpp @@ -0,0 +1,435 @@ +// FindDirectoryTest.cpp + +#include +#include +#include +#include + +#include "FindDirectoryTest.h" + +#include +#include +#include +#include +#include + +#include "Test.StorageKit.h" + + +const directory_which directories[] = { + B_DESKTOP_DIRECTORY, + B_TRASH_DIRECTORY, + // BeOS directories. These are mostly accessed read-only. + B_BEOS_DIRECTORY, + B_BEOS_SYSTEM_DIRECTORY, + B_BEOS_ADDONS_DIRECTORY, + B_BEOS_BOOT_DIRECTORY, + B_BEOS_FONTS_DIRECTORY, + B_BEOS_LIB_DIRECTORY, + B_BEOS_SERVERS_DIRECTORY, + B_BEOS_APPS_DIRECTORY, + B_BEOS_BIN_DIRECTORY, + B_BEOS_ETC_DIRECTORY, + B_BEOS_DOCUMENTATION_DIRECTORY, + B_BEOS_PREFERENCES_DIRECTORY, + B_BEOS_TRANSLATORS_DIRECTORY, + B_BEOS_MEDIA_NODES_DIRECTORY, + B_BEOS_SOUNDS_DIRECTORY, + // Common directories, shared among all users. + B_COMMON_DIRECTORY, + B_COMMON_SYSTEM_DIRECTORY, + B_COMMON_ADDONS_DIRECTORY, + B_COMMON_BOOT_DIRECTORY, + B_COMMON_FONTS_DIRECTORY, + B_COMMON_LIB_DIRECTORY, + B_COMMON_SERVERS_DIRECTORY, + B_COMMON_BIN_DIRECTORY, + B_COMMON_ETC_DIRECTORY, + B_COMMON_DOCUMENTATION_DIRECTORY, + B_COMMON_SETTINGS_DIRECTORY, + B_COMMON_DEVELOP_DIRECTORY, + B_COMMON_LOG_DIRECTORY, + B_COMMON_SPOOL_DIRECTORY, + B_COMMON_TEMP_DIRECTORY, + B_COMMON_VAR_DIRECTORY, + B_COMMON_TRANSLATORS_DIRECTORY, + B_COMMON_MEDIA_NODES_DIRECTORY, + B_COMMON_SOUNDS_DIRECTORY, + // User directories. These are interpreted in the context + // of the user making the find_directory call. + B_USER_DIRECTORY, + B_USER_CONFIG_DIRECTORY, + B_USER_ADDONS_DIRECTORY, + B_USER_BOOT_DIRECTORY, + B_USER_FONTS_DIRECTORY, + B_USER_LIB_DIRECTORY, + B_USER_SETTINGS_DIRECTORY, + B_USER_DESKBAR_DIRECTORY, + B_USER_PRINTERS_DIRECTORY, + B_USER_TRANSLATORS_DIRECTORY, + B_USER_MEDIA_NODES_DIRECTORY, + B_USER_SOUNDS_DIRECTORY, + // Global directories. + B_APPS_DIRECTORY, + B_PREFERENCES_DIRECTORY, + B_UTILITIES_DIRECTORY +}; + +const int32 directoryCount = sizeof(directories) / sizeof(directory_which); + +const char *testFile = "/tmp/testFile"; +const char *testMountPoint = "/non-existing-mount-point"; + + +// Suite +CppUnit::Test* +FindDirectoryTest::Suite() { + CppUnit::TestSuite *suite = new CppUnit::TestSuite(); + typedef CppUnit::TestCaller TC; + + suite->addTest( new TC("find_directory() Test", + &FindDirectoryTest::Test) ); + + return suite; +} + +// setUp +void +FindDirectoryTest::setUp() +{ + BasicTest::setUp(); + createVolume(testFile, testMountPoint, 1); +} + +// tearDown +void +FindDirectoryTest::tearDown() +{ + deleteVolume(testFile, testMountPoint); + BasicTest::tearDown(); +} + +// print_directories +/*static +void +print_directories(dev_t device) +{ + printf("device id: %ld\n", device); + BVolume volume; + status_t error = volume.SetTo(device); + if (error != B_OK) + printf("Failed to init volume\n"); + for (int32 i = 0; error == B_OK && i < directoryCount; i++) { + BPath path; + error = find_directory(directories[i], &path, false, &volume); + if (error == B_OK) + printf("%4d: `%s'\n", directories[i], path.Path()); + else + printf("Failed to find directory: %s\n", strerror(error)); + } +}*/ + +// test_find_directory +static +status_t +test_find_directory(directory_which dir, BPath &path, dev_t device) +{ + status_t error = B_BAD_VALUE; + switch (dir) { + // volume relative dirs + case B_DESKTOP_DIRECTORY: + { + if (device < 0) + device = dev_for_path("/boot"); + fs_info info; + if (fs_stat_dev(device, &info) == 0) { + if (!strcmp(info.fsh_name, "bfs")) { + entry_ref ref(device, info.root, "home"); + BPath homePath(&ref); + error = homePath.InitCheck(); + if (error == B_OK) + path.SetTo(homePath.Path(), "Desktop"); + } else + error = B_ENTRY_NOT_FOUND; + } else + error = errno; + break; + } + case B_TRASH_DIRECTORY: + { + if (device < 0) + device = dev_for_path("/boot"); + fs_info info; + if (fs_stat_dev(device, &info) == 0) { + if (!strcmp(info.fsh_name, "bfs")) { + entry_ref ref(device, info.root, "home"); + BPath homePath(&ref); + error = homePath.InitCheck(); + if (error == B_OK) + path.SetTo(homePath.Path(), "Desktop/Trash"); + } else if (!strcmp(info.fsh_name, "dos")) { + entry_ref ref(device, info.root, "RECYCLED"); + BPath recycledPath(&ref); + error = recycledPath.InitCheck(); + if (error == B_OK) + path.SetTo(recycledPath.Path(), "_BEOS_"); + } else + error = B_ENTRY_NOT_FOUND; + } else + error = errno; + break; + } + // BeOS directories. These are mostly accessed read-only. + case B_BEOS_DIRECTORY: + error = path.SetTo("/boot/beos"); + break; + case B_BEOS_SYSTEM_DIRECTORY: + error = path.SetTo("/boot/beos/system"); + break; + case B_BEOS_ADDONS_DIRECTORY: + error = path.SetTo("/boot/beos/system/add-ons"); + break; + case B_BEOS_BOOT_DIRECTORY: + error = path.SetTo("/boot/beos/system/boot"); + break; + case B_BEOS_FONTS_DIRECTORY: + error = path.SetTo("/boot/beos/etc/fonts"); + break; + case B_BEOS_LIB_DIRECTORY: + error = path.SetTo("/boot/beos/system/lib"); + break; + case B_BEOS_SERVERS_DIRECTORY: + error = path.SetTo("/boot/beos/system/servers"); + break; + case B_BEOS_APPS_DIRECTORY: + error = path.SetTo("/boot/beos/apps"); + break; + case B_BEOS_BIN_DIRECTORY: + error = path.SetTo("/boot/beos/bin"); + break; + case B_BEOS_ETC_DIRECTORY: + error = path.SetTo("/boot/beos/etc"); + break; + case B_BEOS_DOCUMENTATION_DIRECTORY: + error = path.SetTo("/boot/beos/documentation"); + break; + case B_BEOS_PREFERENCES_DIRECTORY: + error = path.SetTo("/boot/beos/preferences"); + break; + case B_BEOS_TRANSLATORS_DIRECTORY: + error = path.SetTo("/boot/beos/system/add-ons/Translators"); + break; + case B_BEOS_MEDIA_NODES_DIRECTORY: + error = path.SetTo("/boot/beos/system/add-ons/media"); + break; + case B_BEOS_SOUNDS_DIRECTORY: + error = path.SetTo("/boot/beos/etc/sounds"); + break; + // Common directories, shared among all users. + case B_COMMON_DIRECTORY: + error = path.SetTo("/boot/home"); + break; + case B_COMMON_SYSTEM_DIRECTORY: + error = path.SetTo("/boot/home/config"); + break; + case B_COMMON_ADDONS_DIRECTORY: + error = path.SetTo("/boot/home/config/add-ons"); + break; + case B_COMMON_BOOT_DIRECTORY: + error = path.SetTo("/boot/home/config/boot"); + break; + case B_COMMON_FONTS_DIRECTORY: + error = path.SetTo("/boot/home/config/fonts"); + break; + case B_COMMON_LIB_DIRECTORY: + error = path.SetTo("/boot/home/config/lib"); + break; + case B_COMMON_SERVERS_DIRECTORY: + error = path.SetTo("/boot/home/config/servers"); + break; + case B_COMMON_BIN_DIRECTORY: + error = path.SetTo("/boot/home/config/bin"); + break; + case B_COMMON_ETC_DIRECTORY: + error = path.SetTo("/boot/home/config/etc"); + break; + case B_COMMON_DOCUMENTATION_DIRECTORY: + error = path.SetTo("/boot/home/config/documentation"); + break; + case B_COMMON_SETTINGS_DIRECTORY: + error = path.SetTo("/boot/home/config/settings"); + break; + case B_COMMON_DEVELOP_DIRECTORY: + error = path.SetTo("/boot/develop"); + break; + case B_COMMON_LOG_DIRECTORY: + error = path.SetTo("/boot/var/log"); + break; + case B_COMMON_SPOOL_DIRECTORY: + error = path.SetTo("/boot/var/spool"); + break; + case B_COMMON_TEMP_DIRECTORY: + error = path.SetTo("/boot/var/tmp"); + break; + case B_COMMON_VAR_DIRECTORY: + error = path.SetTo("/boot/var"); + break; + case B_COMMON_TRANSLATORS_DIRECTORY: + error = path.SetTo("/boot/home/config/add-ons/Translators"); + break; + case B_COMMON_MEDIA_NODES_DIRECTORY: + error = path.SetTo("/boot/home/config/add-ons/media"); + break; + case B_COMMON_SOUNDS_DIRECTORY: + error = path.SetTo("/boot/home/config/sounds"); + break; + // User directories. These are interpreted in the context + // of the user making the find_directory call. + case B_USER_DIRECTORY: + error = path.SetTo("/boot/home"); + break; + case B_USER_CONFIG_DIRECTORY: + error = path.SetTo("/boot/home/config"); + break; + case B_USER_ADDONS_DIRECTORY: + error = path.SetTo("/boot/home/config/add-ons"); + break; + case B_USER_BOOT_DIRECTORY: + error = path.SetTo("/boot/home/config/boot"); + break; + case B_USER_FONTS_DIRECTORY: + error = path.SetTo("/boot/home/config/fonts"); + break; + case B_USER_LIB_DIRECTORY: + error = path.SetTo("/boot/home/config/lib"); + break; + case B_USER_SETTINGS_DIRECTORY: + error = path.SetTo("/boot/home/config/settings"); + break; + case B_USER_DESKBAR_DIRECTORY: + error = path.SetTo("/boot/home/config/be"); + break; + case B_USER_PRINTERS_DIRECTORY: + error = path.SetTo("/boot/home/config/settings/printers"); + break; + case B_USER_TRANSLATORS_DIRECTORY: + error = path.SetTo("/boot/home/config/add-ons/Translators"); + break; + case B_USER_MEDIA_NODES_DIRECTORY: + error = path.SetTo("/boot/home/config/add-ons/media"); + break; + case B_USER_SOUNDS_DIRECTORY: + error = path.SetTo("/boot/home/config/sounds"); + break; + // Global directories. + case B_APPS_DIRECTORY: + error = path.SetTo("/boot/apps"); + break; + case B_PREFERENCES_DIRECTORY: + error = path.SetTo("/boot/preferences"); + break; + case B_UTILITIES_DIRECTORY: + error = path.SetTo("/boot/utilities"); + break; + } + return error; +} + +// TestDirectories +static +void +TestDirectories(dev_t device) +{ + BVolume volume; + if (device >= 0) + CPPUNIT_ASSERT( volume.SetTo(device) == B_OK ); + for (int32 i = 0; i < directoryCount; i++) { + BPath path; + BPath path2; + char path3[B_PATH_NAME_LENGTH + 1]; + status_t result = test_find_directory(directories[i], path, device); + status_t result2 = find_directory(directories[i], &path2, false, + &volume); + status_t result3 = find_directory(directories[i], device, false, + path3, B_PATH_NAME_LENGTH + 1); + CPPUNIT_ASSERT( result == result2 && result == result3 ); + if (result == B_OK) + CPPUNIT_ASSERT( path == path2 && path == path3 ); + } +} + +// Test +void +FindDirectoryTest::Test() +{ + // /boot + nextSubTest(); + dev_t device = dev_for_path("/boot"); + CPPUNIT_ASSERT( device > 0 ); + TestDirectories(device); + // /dev + nextSubTest(); + device = dev_for_path("/dev"); + CPPUNIT_ASSERT( device > 0 ); + TestDirectories(device); + // / + nextSubTest(); + device = dev_for_path("/"); + CPPUNIT_ASSERT( device > 0 ); + TestDirectories(device); + // test image + nextSubTest(); + device = dev_for_path(testMountPoint); + CPPUNIT_ASSERT( device > 0 ); + TestDirectories(device); + // invalid device ID + nextSubTest(); + TestDirectories(-1); + // NULL BVolume + nextSubTest(); + for (int32 i = 0; i < directoryCount; i++) { + BPath path; + BPath path2; + status_t result = test_find_directory(directories[i], path, -1); + status_t result2 = find_directory(directories[i], &path2, false, NULL); + CPPUNIT_ASSERT( result == result2 ); + if (result == B_OK) + CPPUNIT_ASSERT( path == path2 ); + } + // no such volume + nextSubTest(); + device = 213; + fs_info info; + while (fs_stat_dev(device, &info) == 0) + device++; + for (int32 i = 0; i < directoryCount; i++) { + BPath path; + char path3[B_PATH_NAME_LENGTH + 1]; + status_t result = test_find_directory(directories[i], path, device); + status_t result3 = find_directory(directories[i], device, false, + path3, B_PATH_NAME_LENGTH + 1); + // Our test_find_directory() returns rather strange errors instead + // of B_ENTRY_NOT_FOUND. + CPPUNIT_ASSERT( result == B_OK && result3 == B_OK + || result != B_OK && result3 != B_OK ); + if (result == B_OK) + CPPUNIT_ASSERT( path == path3 ); + } + // bad args + // R5: crashes + nextSubTest(); + device = dev_for_path("/boot"); + CPPUNIT_ASSERT( device > 0 ); +#if !SK_TEST_R5 + CPPUNIT_ASSERT( find_directory(B_BEOS_DIRECTORY, NULL, false, NULL) + == B_BAD_VALUE ); + CPPUNIT_ASSERT( find_directory(B_BEOS_DIRECTORY, device, false, NULL, 50) + == B_BAD_VALUE ); +#endif + // small buffer + nextSubTest(); + char path3[7]; + CPPUNIT_ASSERT( find_directory(B_BEOS_DIRECTORY, device, false, path3, 7) + == E2BIG ); +} + diff --git a/src/tests/kits/storage/FindDirectoryTest.h b/src/tests/kits/storage/FindDirectoryTest.h new file mode 100644 index 0000000000..140a60b602 --- /dev/null +++ b/src/tests/kits/storage/FindDirectoryTest.h @@ -0,0 +1,33 @@ +// FindDirectoryTest.h + +#ifndef __sk_find_directory_test_h__ +#define __sk_find_directory_test_h__ + +#include +#include + +#include +#include + +#include "BasicTest.h" + +class FindDirectoryTest : public BasicTest +{ +public: + static CppUnit::Test* Suite(); + + // This function called before *each* test added in Suite() + void setUp(); + + // This function called after *each* test added in Suite() + void tearDown(); + + //------------------------------------------------------------ + // Test functions + //------------------------------------------------------------ + void Test(); +}; + + + +#endif // __sk_find_directory_test_h__ diff --git a/src/tests/kits/storage/Jamfile b/src/tests/kits/storage/Jamfile new file mode 100644 index 0000000000..c5986fd147 --- /dev/null +++ b/src/tests/kits/storage/Jamfile @@ -0,0 +1,71 @@ +# This is $(TOP)/test/Jamfile + +SubDir TOP test ; + +# Point the compiler to location of the CppUnit headers +HDRS += "$(TOP)/cppunit/include" ; + +SOURCE_FILES = + BasicTest.cpp + DirectoryTest.cpp + EntryTest.cpp + FileTest.cpp + FindDirectoryTest.cpp + MimeTypeTest.cpp + NodeTest.cpp + PathTest.cpp + QueryTest.cpp + ResourcesTest.cpp + ResourceStringsTest.cpp + StatableTest.cpp + SymLinkTest.cpp + TestApp.cpp + TestUtils.cpp +; + +# targets to shorted make time, when only one version should be made +NOTFILE r5 posix ; + +# Version of our test suite that links with Be's R5 libraries + +LibraryFromR5Sources $(TOP)/test/libstoragetest.R5.a : $(SOURCE_FILES) ; +Main Test.StorageKit.R5 : Test.StorageKit.cpp ; +LinkLibraries Test.StorageKit.R5 : + $(TOP)/test/libstoragetest.R5.a + $(TOP)/cppunit/cppunit.a +; +LinkSharedOSLibs Test.StorageKit.R5 : + /boot/develop/lib/x86/libstdc++.r4.so + /boot/develop/lib/x86/libbe.so +; +DEPENDS r5 : Test.StorageKit.R5 ; + + +# Version of our test suite that links with OpenBeOS libraries + +HDRS += "$(TOP)/source/lib" ; + +# Make a test/lib directory and copy libstorage.so libbeadapter.so into it. +DEPENDS $(TOP)/test/lib/libbeadapter.so : + $(TOP)/source/lib/libbeadapter.so $(TOP)/test/lib ; +DEPENDS $(TOP)/test/lib/libstorage.so : + $(TOP)/source/lib/libstorage.so $(TOP)/test/lib ; +MkDir $(TOP)/test/lib ; +Bulk $(TOP)/test/lib : $(TOP)/source/lib/libbeadapter.so ; +Bulk $(TOP)/test/lib : $(TOP)/source/lib/libstorage.so ; + +LibraryFromPOSIXSources $(TOP)/test/libstoragetest.POSIX.a : $(SOURCE_FILES) ; +Main Test.StorageKit.OpenBeOS : Test.StorageKit.cpp ; +LinkLibraries Test.StorageKit.OpenBeOS : + $(TOP)/test/libstoragetest.POSIX.a + $(TOP)/cppunit/cppunit.a +; +LinkSharedLibs Test.StorageKit.OpenBeOS : + $(TOP)/test/lib/libbeadapter.so + $(TOP)/test/lib/libstorage.so +; +LinkSharedOSLibs Test.StorageKit.OpenBeOS : + /boot/develop/lib/x86/libstdc++.r4.so + /boot/develop/lib/x86/libbe.so +; +DEPENDS posix : Test.StorageKit.OpenBeOS ; diff --git a/src/tests/kits/storage/MimeTypeTest.cpp b/src/tests/kits/storage/MimeTypeTest.cpp new file mode 100644 index 0000000000..2983b86536 --- /dev/null +++ b/src/tests/kits/storage/MimeTypeTest.cpp @@ -0,0 +1,3761 @@ +// MimeTypeTest.cpp + +#include // For tolower() +#include // open() +#include +#include +#include +#include // For memcmp() +#include +#include +#include + + +#include +#include +#include +#include +#include // B_GET_ICON, device_icon +#include +#include +#include +#include // Only needed for entry_ref dumps +#include +#include + + +#include "Test.StorageKit.h" +#include "TestApp.h" +#include "TestUtils.h" + +// MIME database directories +static const char *testDir = "/tmp/mimeTestDir"; +static const char *mimeDatabaseDir = "/boot/home/config/settings/beos_mime"; + +// MIME Test Types +// testType and testTypeApp are Delete()d after each test. +static const char *testType = "text/x-vnd.obos-Storage-Kit-Test"; +static const char *testType1 = "text/x-vnd.obos-Storage-Kit-Test1"; +static const char *testType2 = "text/x-vnd.obos-Storage-Kit-Test2"; +static const char *testType3 = "text/x-vnd.obos-Storage-Kit-Test3"; +static const char *testType4 = "text/x-vnd.obos-Storage-Kit-Test4"; +static const char *testType5 = "text/x-vnd.obos-Storage-Kit-Test5"; +static const char *testTypeApp = "application/StorageKit-Test"; +static const char *testTypeApp1 = "application/" + "x-vnd.obos.mime.test.test1"; +static const char *testTypeApp2 = "application/" + "x-vnd.obos.mime.test.test2"; +static const char *testTypeApp3 = "application/" + "x-vnd.obos.mime.test.test3"; +static const char *testTypeInvalid = "text/Are spaces valid?"; +static const char *testTypeSuperValid = "valid-but-fake-supertype"; +static const char *testTypeSuperInvalid = "?????"; + +// Real MIME types +static const char *wildcardType = "application/octet-stream"; + +// Application Paths +static const char *testApp = "/boot/beos/apps/SoundRecorder"; +static const char *testApp2 = "/boot/beos/apps/CDPlayer"; +static const char *fakeTestApp = "/__this_isn't_likely_to_exist__"; + +// BMessage field names +static const char *typeField = "type"; +static const char *fileExtField = "extensions"; +static const char *attrInfoField_Name = "attr:name"; +static const char *attrInfoField_PublicName = "attr:public_name"; +static const char *attrInfoField_Type = "attr:type"; +static const char *attrInfoField_Viewable = "attr:viewable"; +static const char *attrInfoField_Editable = "attr:editable"; + +// Descriptions +static const char *testDescr = "Just a test, nothing more :-)"; +static const char *testDescr2 = "Another amazing test string"; +static const char *longDescr = +"This description is longer than B_MIME_TYPE_LENGTH, which is quite useful for certain things... " +"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" +"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" +"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"; +// Signatures +static const char *testSig = "application/x-vnd.obos.mime-type-test"; +static const char *testSig2 = "application/x-vnd.obos.mime-type-test-2"; +static const char *longSig = "application/x-vnd.obos.mime-type-test-long." +"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" +"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" +"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"; + +// Declarations for handy dandy private functions +static bool operator==(BBitmap &bmp1, BBitmap &bmp2); +static bool operator!=(BBitmap &bmp1, BBitmap &bmp2); +static bool operator==(BMessage &msg1, BMessage &msg2); +static bool operator!=(BMessage &msg1, BMessage &msg2); +static void fill_bitmap(BBitmap &bmp, char value); +//static void dump_bitmap(BBitmap &bmp, char *name = "bmp"); +//static void dump_ref(entry_ref *ref, char* name = "ref"); +static void to_lower(const char *str, std::string &result); +static void remove_type(const char *type, const char *databaseDir = mimeDatabaseDir); +static bool type_exists(const char *type, const char *databaseDir = mimeDatabaseDir); +class ContainerAdapter; +class SetAdapter; +class QueueAdapter; +void FillWithMimeTypes(ContainerAdapter &container, BMessage &typeMessage, const char* fieldName); + // Used to add all the types in a BMessage from GetInstalled*Types() to some + // sort of container object (via an adapter to support differing interfaces). + +// Suite +CppUnit::Test* +MimeTypeTest::Suite() { + StorageKit::TestSuite *suite = new StorageKit::TestSuite(); + typedef CppUnit::TestCaller TC; + + // Tyler + suite->addTest( new TC("BMimeType::Install/Delete Test", + &MimeTypeTest::InstallDeleteTest) ); + suite->addTest( new TC("BMimeType::App Hint Test", + &MimeTypeTest::AppHintTest) ); + suite->addTest( new TC("BMimeType::Attribute Info Test", + &MimeTypeTest::AttrInfoTest) ); + suite->addTest( new TC("BMimeType::Long Description Test", + &MimeTypeTest::LongDescriptionTest) ); + suite->addTest( new TC("BMimeType::Short Description Test", + &MimeTypeTest::ShortDescriptionTest) ); + suite->addTest( new TC("BMimeType::File Extensions Test", + &MimeTypeTest::FileExtensionsTest) ); + suite->addTest( new TC("BMimeType::Icon Test (Large)", + &MimeTypeTest::LargeIconTest) ); + suite->addTest( new TC("BMimeType::Icon Test (Mini)", + &MimeTypeTest::MiniIconTest) ); + suite->addTest( new TC("BMimeType::Icon For Type Test (Large)", + &MimeTypeTest::LargeIconForTypeTest) ); + suite->addTest( new TC("BMimeType::Icon For Type Test (Mini)", + &MimeTypeTest::MiniIconForTypeTest) ); + suite->addTest( new TC("BMimeType::Installed Types Test", + &MimeTypeTest::InstalledTypesTest) ); + suite->addTest( new TC("BMimeType::Preferred App Test", + &MimeTypeTest::PreferredAppTest) ); + suite->addTest( new TC("BMimeType::Wildcard Apps Test", + &MimeTypeTest::WildcardAppsTest) ); + + // Ingo + suite->addTest( new TC("BMimeType::Initialization Test", + &MimeTypeTest::InitTest) ); + suite->addTest( new TC("BMimeType::MIME String Test", + &MimeTypeTest::StringTest) ); + suite->addTest( new TC("BMimeType::MIME Monitoring Test", + &MimeTypeTest::MonitoringTest) ); + suite->addTest( new TC("BMimeType::update_mime_info() Test", + &MimeTypeTest::UpdateMimeInfoTest) ); + suite->addTest( new TC("BMimeType::create_app_meta_mime() Test", + &MimeTypeTest::CreateAppMetaMimeTest) ); + suite->addTest( new TC("BMimeType::get_device_icon() Test", + &MimeTypeTest::GetDeviceIconTest) ); + suite->addTest( new TC("BMimeType::Sniffer Rule Test", + &MimeTypeTest::SnifferRuleTest) ); + suite->addTest( new TC("BMimeType::Sniffing Test", + &MimeTypeTest::SniffingTest) ); + + // In progress + suite->addTest( new TC("BMimeType::Supporting Apps Test", + &MimeTypeTest::SupportingAppsTest) ); + + + return suite; +} + +// Handy comparison operators for BBitmaps. The size and color depth +// are compared first, followed by the bitmap data. +bool +operator==(BBitmap &bmp1, BBitmap &bmp2) { + if (bmp1.Bounds() == bmp2.Bounds()) { +// printf("bmp== 1\n"); + if (bmp1.ColorSpace() == bmp2.ColorSpace()) { +// printf("bmp== 2\n"); + char *data1 = (char*)bmp1.Bits(); + char *data2 = (char*)bmp2.Bits(); + // NOTE! It's possible that padding bits might not get copied verbatim, + // which could lead to unexpected failures. If things are acting weird, + // you might try the commented out code below (keeping in mind that it + // currently only works for 8-bit color depths). + for (int i = 0; i < bmp1.BitsLength(); data1++, data2++, i++) { + if (*data1 != *data2) { +// printf("i == %d\n", i); + return false; + } + } +/* for (int i = 0; i < bmp1.Bounds().IntegerHeight(); i++) { + for (int j = 0; j < bmp1.Bounds().IntegerWidth(); j++) { +// printf("(%d, %d)", data1[(i * bmp1.BytesPerRow()) + j], data2[(i * bmp2.BytesPerRow()) + j]); + if (data1[(i * bmp1.BytesPerRow()) + j] != data2[(i * bmp2.BytesPerRow()) + j]) { + printf("fail at (%d, %d)\n", j, i); + return false; + } + } + }*/ + return true; + } else + return false; + } else + return false; +} + +bool +operator!=(BBitmap &bmp1, BBitmap &bmp2) { + return !(bmp1 == bmp2); +} + +// Handy comparison operators for BMessages. The BMessages are checked field +// by field, each of which is verified to be identical with respect to: type, +// count, and data (all items). +bool +operator==(BMessage &msg1, BMessage &msg2) { + status_t err = B_OK; + + // For now I'm ignoring the what fields...I shall deal with that later :-) + if (msg1.what != msg2.what) + return false; + +/* + printf("----------------------------------------------------------------------\n"); + msg1.PrintToStream(); + msg2.PrintToStream(); + printf("----------------------------------------------------------------------\n"); +*/ + + // Check the counts of field names + int count1, count2; + count1 = msg1.CountNames(B_ANY_TYPE); + count2 = msg2.CountNames(B_ANY_TYPE); + if (count1 != count2 && (count1 == 0 || count2 == 0)) + return false; + + // Iterate over all the names in msg1 and check that the field + // with the same name exists in msg2, is of the same type, and + // contains identical data. + for (int i = 0; i < count1 && !err; i++) { + char *name; + type_code typeFound1, typeFound2; + int32 countFound1, countFound2; + + // Check type and count info + err = msg1.GetInfo(B_ANY_TYPE, i, &name, &typeFound1, &countFound1); + if (!err) + err = msg2.GetInfo(name, &typeFound2, &countFound2); + if (!err) + err = (typeFound1 == typeFound2 && countFound1 == countFound2 ? B_OK : B_ERROR); + if (!err) { + // Check all the data items + for (int j = 0; j < countFound1; j++) { + void *data1, *data2; + ssize_t bytes1, bytes2; + + err = msg1.FindData(name, typeFound1, j, (const void**)&data1, &bytes1); + if (!err) + err = msg2.FindData(name, typeFound2, j, (const void**)&data2, &bytes2); + if (!err) + err = (bytes1 == bytes2 && memcmp(data1, data2, bytes1) == 0 ? B_OK : B_ERROR); + } + } + } + + return !err; +} + +bool +operator!=(BMessage &msg1, BMessage &msg2) { + return !(msg1 == msg2); +} + +// Fills the bitmap data with the given character +void +fill_bitmap(BBitmap &bmp, char value) { + char *data = (char*)bmp.Bits(); + for (int i = 0; i < bmp.BitsLength(); data++, i++) { +// printf("(%d -> ", *data); + *data = value; +// printf("%d)", *data); + } +// printf("\n"); +} + +// Dumps the size, colorspace, and first data byte +// of the bitmap to stdout +/*void +dump_bitmap(BBitmap &bmp, char *name = "bmp") { + printf("%s == (%ldx%ld, ", name, bmp.Bounds().IntegerWidth()+1, + bmp.Bounds().IntegerHeight()+1); + switch (bmp.ColorSpace()) { + case B_CMAP8: + printf("B_CMAP8"); + break; + + case B_RGBA32: + printf("B_RGBA32"); + break; + + default: + printf("%x", bmp.ColorSpace()); + break; + } + printf(", %d)\n", *(char*)bmp.Bits()); +}*/ + +// IconHelper and IconForTypeHelper: +// Adapter(?) classes needed to reuse icon tests among {Get,Set}Icon() and {Get,Set}IconForType() +// What originally were meant to encapsulate the variations among calls to the various BMimeType +// icon functions have now exploded into beefy helper classes with a bunch of BBitmap related +// functionality as well. A lot of this stuff doesn't necessarily belong + +class IconHelper { +public: + IconHelper(icon_size which) + : bmp1(BitmapBounds(which), B_CMAP8), + bmp2(BitmapBounds(which), B_CMAP8), + bmpTemp(BitmapBounds(which), B_CMAP8), + size(which) + { + // Initialize our three bitmaps to different "colors" + fill_bitmap(bmp1, 1); + fill_bitmap(bmp2, 2); + fill_bitmap(bmpTemp, 3); + } + + virtual ~IconHelper() {} + + // Returns the proper bitmap bounds for the given icon size + BRect BitmapBounds(icon_size isize) { + return isize == B_LARGE_ICON ? BRect(0,0,31,31) : BRect(0,0,15,15); + } + + // Returns the proper bitmap bounds for this helper's icon size + BRect BitmapBounds() { + return BitmapBounds(size); + } + + // Used to call the appropriate GetIcon[ForType] function + virtual status_t GetIcon(BMimeType &mime, BBitmap *icon) { + return mime.GetIcon(icon, size); + } + + // Used to call the appropriate SetIcon[ForType] function + virtual status_t SetIcon(BMimeType &mime, BBitmap *icon) { + return mime.SetIcon(icon, size); + } + + BBitmap* TempBitmap() { + return &bmpTemp; + } + + BBitmap* Bitmap1() { + return &bmp1; + } + + BBitmap* Bitmap2() { + return &bmp2; + } + + icon_size Size() { + return size; + } + +protected: + BBitmap bmp1; + BBitmap bmp2; + BBitmap bmpTemp; + icon_size size; +}; + +class IconForTypeHelper : public IconHelper { +public: + IconForTypeHelper(const char *fileType, icon_size which) + : IconHelper(which), fileType(fileType) {} + virtual ~IconForTypeHelper() {} + virtual status_t GetIcon(BMimeType &mime, BBitmap *icon) { + return mime.GetIconForType(fileType.c_str(), icon, size); + } + virtual status_t SetIcon(BMimeType &mime, BBitmap *icon) { + return mime.SetIconForType(fileType.c_str(), icon, size); + } +protected: + std::string fileType; +}; + +// setUp +void +MimeTypeTest::setUp() +{ + BasicTest::setUp(); + execCommand(string("mkdir ") + testDir); +/* // Better not to play with fire, so we'll make a copy of the + // local mime database which we'll use for certain OpenBeOS tests + execCommand(string("mkdir ") + testDir + + " ; copyattr -d -r -- " + mimeDatabaseDir + "/\* " + testDir + ); */ + // Setup our application + fApplication = new TestApp(testSig); + if (fApplication->Init() != B_OK) { + fprintf(stderr, "Failed to initialize application.\n"); + delete fApplication; + fApplication = NULL; + } + +} + +// tearDown +void +MimeTypeTest::tearDown() +{ + execCommand(string("rm -rf ") + testDir); + + // Uninistall our test type + //! /todo Uncomment the following uninstall code when all is said and done. +/* BMimeType mime(testType); + status_t err = mime.InitCheck(); + if (!err && mime.IsInstalled()) + err = mime.Delete(); + if (err) + fprintf(stderr, "Failed to unistall test type \"%s\"\n", testType); */ + // Terminate the Application + if (fApplication) { + fApplication->Terminate(); + delete fApplication; + fApplication = NULL; + } + // remove the types we've added + const char * const testTypes[] = { + testType, testType1, testType2, testType3, testType4, testType5, + testTypeApp, testTypeApp1, testTypeApp2, testTypeApp3, + }; + for (uint32 i = 0; i < sizeof(testTypes) / sizeof(const char*); i++) { + BMimeType type(testTypes[i]); + type.Delete(); + } + BasicTest::tearDown(); +} + +// entry_ref dumping function ; this may be removed at any time + +/*void +dump_ref(entry_ref *ref, char* name = "ref") { + if (ref) { + BPath path(ref); + status_t err = path.InitCheck(); + if (!err) { + printf("%s == '%s'", name, path.Path()); + } else + printf("%s == ERROR", name); + printf(" == (%ld, %Ld, '%s')\n", ref->device, ref->directory, ref->name); + + } else + printf("%s == (NULL)\n", name); +}*/ + +// App Hint + +void +MimeTypeTest::AppHintTest() { + // init a couple of entry_refs to applications + BEntry entry(testApp); + entry_ref appRef; + CHK(entry.InitCheck() == B_OK); + CHK(entry.GetRef(&appRef) == B_OK); + BEntry entry2(testApp2); + entry_ref appRef2; + CHK(entry2.InitCheck() == B_OK); + CHK(entry2.GetRef(&appRef2) == B_OK); + // Uninitialized + nextSubTest(); + { + BMimeType mime; + entry_ref ref; + CHK(mime.InitCheck() == B_NO_INIT); + CHK(mime.GetAppHint(&ref) != B_OK); // R5 == B_BAD_VALUE + CHK(mime.SetAppHint(&ref) != B_OK); // R5 == B_BAD_VALUE + } + // NULL params + nextSubTest(); + { + entry_ref ref; + BMimeType mime(testType); + CHK(mime.InitCheck() == B_OK); + // Make sure the type isn't installed + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + CHK(!mime.IsInstalled()); + CHK(mime.GetAppHint(NULL) != B_OK); // R5 == B_BAD_VALUE + CHK(!mime.IsInstalled()); + CHK(mime.SetAppHint(NULL) != B_OK); // Installs, R5 == B_ENTRY_NOT_FOUND + CHK(mime.IsInstalled()); + CHK(mime.GetAppHint(NULL) != B_OK); // R5 == B_BAD_VALUE + CHK(mime.SetAppHint(NULL) != B_OK); // R5 == B_ENTRY_NOT_FOUND + } + // Non-installed type + nextSubTest(); + { + entry_ref ref; + BMimeType mime(testType); + CHK(mime.InitCheck() == B_OK); + // Make sure the type isn't installed + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + CHK(!mime.IsInstalled()); + CHK(mime.GetAppHint(&ref) != B_OK); // R5 == B_ENTRY_NOT_FOUND + CHK(!mime.IsInstalled()); + CHK(mime.SetAppHint(&appRef) == B_OK); + CHK(mime.IsInstalled()); + CHK(mime.GetAppHint(&ref) == B_OK); + CHK(ref == appRef); + } + // Installed Type + nextSubTest(); + { + entry_ref ref; + BMimeType mime(testType); + CHK(mime.InitCheck() == B_OK); + // Uninstall then reinstall to clear attributes + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + if (!mime.IsInstalled()) + CHK(mime.Install() == B_OK); + CHK(mime.IsInstalled()); + // Get() with no apphint installed + CHK(mime.GetAppHint(&ref) == B_ENTRY_NOT_FOUND); + // Initial Set()/Get() + CHK(mime.SetAppHint(&appRef) == B_OK); + CHK(mime.GetAppHint(&ref) == B_OK); + CHK(ref == appRef); + // Followup Set()/Get() + CHK(mime.SetAppHint(&appRef2) == B_OK); + CHK(mime.GetAppHint(&ref) == B_OK); + CHK(ref == appRef2); + CHK(ref != appRef); + } + // Installed Type, invalid entry_ref + nextSubTest(); + { + entry_ref ref(-1, -1, NULL); + BMimeType mime(testType); + CHK(mime.InitCheck() == B_OK); + // Uninstall then reinstall to clear attributes + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + if (!mime.IsInstalled()) + CHK(mime.Install() == B_OK); + CHK(mime.IsInstalled()); + CHK(mime.SetAppHint(&appRef) == B_OK); + CHK(mime.SetAppHint(&ref) != B_OK); // R5 == B_BAD_VALUE + } + // Installed Type, fake/invalid entry_ref + nextSubTest(); + { + entry_ref ref(0, 0, "__this_ought_not_exist__"); + BMimeType mime(testType); + CHK(mime.InitCheck() == B_OK); + // Uninstall then reinstall to clear attributes + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + if (!mime.IsInstalled()) + CHK(mime.Install() == B_OK); + CHK(mime.IsInstalled()); + CHK(mime.SetAppHint(&appRef) == B_OK); + CHK(mime.SetAppHint(&ref) != B_OK); // R5 == B_ENTRY_NOT_FOUND + } + // Installed Type, abstract entry_ref + nextSubTest(); + { + entry_ref fakeRef; + entry_ref ref; + BEntry entry(fakeTestApp); + CHK(entry.InitCheck() == B_OK); + CHK(!entry.Exists()); + CHK(entry.GetRef(&fakeRef) == B_OK); + BMimeType mime(testType); + CHK(mime.InitCheck() == B_OK); + // Uninstall then reinstall to clear attributes + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + if (!mime.IsInstalled()) + CHK(mime.Install() == B_OK); + CHK(mime.IsInstalled()); + CHK(mime.SetAppHint(&appRef) == B_OK); + CHK(mime.SetAppHint(&fakeRef) == B_OK); + CHK(mime.GetAppHint(&ref) == B_OK); + CHK(ref == fakeRef); + CHK(ref != appRef); + } +} + +// Attr Info + +void +MimeTypeTest::AttrInfoTest() { + // Create some messages to sling around + const int32 WHAT = 233; // This is the what value that GAI() returns...not sure if it has a name yet + BMessage msg1(WHAT), msg2(WHAT), msg3(WHAT), msgIncomplete1(WHAT), msgIncomplete2(WHAT); + + CHK(msg1.AddString(attrInfoField_Name, "Color") == B_OK); + CHK(msg1.AddString(attrInfoField_PublicName, "The Color") == B_OK); + CHK(msg1.AddInt32(attrInfoField_Type, B_STRING_TYPE) == B_OK); + CHK(msg1.AddBool(attrInfoField_Viewable, true) == B_OK); + CHK(msg1.AddBool(attrInfoField_Editable, true) == B_OK); + + CHK(msg1.AddString(attrInfoField_Name, "High Score") == B_OK); + CHK(msg1.AddString(attrInfoField_PublicName, "The Highest Score Ever") == B_OK); + CHK(msg1.AddInt32(attrInfoField_Type, B_INT32_TYPE) == B_OK); + CHK(msg1.AddBool(attrInfoField_Viewable, false) == B_OK); + CHK(msg1.AddBool(attrInfoField_Editable, false) == B_OK); + + CHK(msg2.AddString(attrInfoField_Name, "Volume") == B_OK); + CHK(msg2.AddString(attrInfoField_PublicName, "Loudness") == B_OK); + CHK(msg2.AddInt32(attrInfoField_Type, B_DOUBLE_TYPE) == B_OK); + CHK(msg2.AddBool(attrInfoField_Viewable, true) == B_OK); + CHK(msg2.AddBool(attrInfoField_Editable, true) == B_OK); + + CHK(msg3.AddString(attrInfoField_Name, "Volume") == B_OK); + CHK(msg3.AddString(attrInfoField_PublicName, "Loudness") == B_OK); + CHK(msg3.AddInt32(attrInfoField_Type, B_DOUBLE_TYPE) == B_OK); + CHK(msg3.AddBool(attrInfoField_Viewable, true) == B_OK); + CHK(msg3.AddBool(attrInfoField_Editable, true) == B_OK); + + CHK(msgIncomplete1.AddString(attrInfoField_Name, "Color") == B_OK); + CHK(msgIncomplete1.AddString(attrInfoField_PublicName, "The Color") == B_OK); + CHK(msgIncomplete1.AddInt32(attrInfoField_Type, B_STRING_TYPE) == B_OK); + CHK(msgIncomplete1.AddBool(attrInfoField_Viewable, true) == B_OK); + CHK(msgIncomplete1.AddBool(attrInfoField_Editable, true) == B_OK); + + CHK(msgIncomplete1.AddString(attrInfoField_Name, "High Score") == B_OK); +// CHK(msgIncomplete1.AddString(attrInfoField_PublicName, "The Highest Score Ever") == B_OK); + CHK(msgIncomplete1.AddInt32(attrInfoField_Type, B_INT32_TYPE) == B_OK); +// CHK(msgIncomplete1.AddBool(attrInfoField_Viewable, false) == B_OK); + CHK(msgIncomplete1.AddBool(attrInfoField_Editable, false) == B_OK); + + CHK(msgIncomplete2.AddString(attrInfoField_Name, "Color") == B_OK); +// CHK(msgIncomplete2.AddString(attrInfoField_PublicName, "The Color") == B_OK); +// CHK(msgIncomplete2.AddInt32(attrInfoField_Type, B_STRING_TYPE) == B_OK); +// CHK(msgIncomplete2.AddBool(attrInfoField_Viewable, true) == B_OK); + CHK(msgIncomplete2.AddBool(attrInfoField_Editable, true) == B_OK); + + CHK(msg1 == msg1); + CHK(msg2 == msg2); + CHK(msg3 == msg3); + CHK(msg1 != msg2); + CHK(msg1 != msg3); + CHK(msg2 == msg3); + + // Uninitialized + nextSubTest(); + { + BMimeType mime; + BMessage msg; + + CHK(mime.InitCheck() == B_NO_INIT); + CHK(mime.GetAttrInfo(&msg) != B_OK); // R5 == B_BAD_VALUE + CHK(mime.SetAttrInfo(&msg) != B_OK); // R5 == B_BAD_VALUE + } + + // NULL params + nextSubTest(); + { + BMimeType mime(testType); + BMessage msg; + + CHK(mime.InitCheck() == B_OK); + // Make sure the type isn't installed + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + + // Non-installed + CHK(!mime.IsInstalled()); + CHK(mime.GetAttrInfo(NULL) != B_OK); // R5 == B_ENTRY_NOT_FOUND + CHK(!mime.IsInstalled()); +#if !SK_TEST_R5 + CHK(RES(mime.SetAttrInfo(NULL)) != B_OK); // R5 == CRASH!!! +#endif + + // Installed + nextSubTest(); + CHK(mime.Install() == B_OK); + CHK(mime.IsInstalled()); + CHK(mime.GetAttrInfo(NULL) != B_OK); // R5 == B_ENTRY_NOT_FOUND +#if !SK_TEST_R5 + CHK(RES(mime.SetAttrInfo(NULL)) != B_OK); // R5 == CRASH!!! +#endif + } + + // Improperly formatted BMessages + nextSubTest(); + { + BMessage msg(WHAT); + BMimeType mime(testType); + CHK(mime.InitCheck() == B_OK); + + // Uninstall then reinstall to clear attributes + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + if (!mime.IsInstalled()) + CHK(mime.Install() == B_OK); + CHK(mime.IsInstalled()); + + // Initial Set()/Get() + msgIncomplete1.RemoveName(typeField); // Clear "type" fields, since SAI() just adds another + msgIncomplete2.RemoveName(typeField); + CHK(msg != msgIncomplete1); + CHK(msg != msgIncomplete2); + CHK(mime.SetAttrInfo(&msgIncomplete1) == B_OK); + CHK(mime.GetAttrInfo(&msg) == B_OK); + CHK(msgIncomplete1.AddString(typeField, testType) == B_OK); // Add in "type" fields as GFE() does + CHK(msgIncomplete2.AddString(typeField, testType) == B_OK); + CHK(msg == msgIncomplete1); + CHK(msg != msgIncomplete2); + } + + // Set() with improperly formatted message + nextSubTest(); + { + BMessage msg(WHAT); + BMimeType mime(testType); + CHK(mime.InitCheck() == B_OK); + + // Uninstall then reinstall to clear attributes + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + if (!mime.IsInstalled()) + CHK(mime.Install() == B_OK); + CHK(mime.IsInstalled()); + + // Initial Set()/Get() + msgIncomplete1.RemoveName(typeField); // Clear "type" fields, since SAI() just adds another + msgIncomplete2.RemoveName(typeField); + CHK(msg != msgIncomplete1); + CHK(msg != msgIncomplete2); + CHK(mime.SetAttrInfo(&msgIncomplete1) == B_OK); + CHK(mime.GetAttrInfo(&msg) == B_OK); + CHK(msgIncomplete1.AddString(typeField, testType) == B_OK); // Add in "type" fields as GFE() does + CHK(msgIncomplete2.AddString(typeField, testType) == B_OK); + CHK(msg == msgIncomplete1); + CHK(msg != msgIncomplete2); + } + + // Set() with empty message + nextSubTest(); + { + BMimeType mime(testType); + BMessage msgEmpty(WHAT); + BMessage msg(WHAT); + CHK(msg.AddInt32("stuff", 1234) == B_OK); // Add an extra attribute to give us something to compare with + + // Uninstall then reinstall to clear attributes + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + if (!mime.IsInstalled()) + CHK(mime.Install() == B_OK); + CHK(mime.IsInstalled()); + + // Set(empty) + CHK(msg != msgEmpty); + CHK(mime.SetAttrInfo(&msgEmpty) == B_OK); + CHK(mime.GetAttrInfo(&msg) == B_OK); + CHK(msgEmpty.AddString(typeField, testType) == B_OK); // Add in "type" fields as GFE() does + CHK(msg == msgEmpty); + } + + // Set() with extra attributes in message + nextSubTest(); + { + BMimeType mime(testType); + BMessage msg(WHAT); + BMessage msgExtraSet(msg1); + CHK(msgExtraSet.AddString("extra", ".extra") == B_OK); + CHK(msgExtraSet.AddInt32("more_extras", 123) == B_OK); + CHK(msgExtraSet.AddInt32("more_extras", 456) == B_OK); + CHK(msgExtraSet.AddInt32("more_extras", 789) == B_OK); + BMessage msgExtraGet(msgExtraSet); + + // Uninstall then reinstall to clear attributes + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + if (!mime.IsInstalled()) + CHK(mime.Install() == B_OK); + CHK(mime.IsInstalled()); + + // Set(extra)/Get(empty) + msg1.RemoveName(typeField); // Clear "type" fields, since SFE() just adds another + msg2.RemoveName(typeField); + CHK(msg != msg1); + CHK(msg != msgExtraSet); + CHK(mime.SetAttrInfo(&msgExtraSet) == B_OK); + CHK(mime.GetAttrInfo(&msg) == B_OK); + CHK(msg1.AddString(typeField, testType) == B_OK); // Add in "type" fields as GFE() does + CHK(msgExtraSet.AddString(typeField, testType) == B_OK); + CHK(msg == msgExtraSet); + CHK(msg != msg1); + + // Get(extra) + nextSubTest(); + CHK(mime.GetAttrInfo(&msgExtraGet) == B_OK); + CHK(msgExtraGet == msgExtraSet); + CHK(msgExtraGet != msg1); + + // Get(extra and then some) + nextSubTest(); + CHK(msgExtraGet.AddInt32("more_extras", 101112) == B_OK); + msgExtraGet.RemoveName(typeField); // Clear "type" fields to be fair, since SFE() just adds another + CHK(mime.GetAttrInfo(&msgExtraGet) == B_OK); // Reinitializes result (clearing extra fields) + CHK(msgExtraGet == msgExtraSet); + CHK(msgExtraGet != msg1); + + } + // Normal Function (Non-installed type) + nextSubTest(); + { + BMimeType mime(testType); + BMessage msg(WHAT); + BMessage msg2(WHAT); + + CHK(mime.InitCheck() == B_OK); + // Make sure the type isn't installed + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + + CHK(!mime.IsInstalled()); + CHK(mime.GetAttrInfo(&msg) != B_OK); // R5 == B_ENTRY_NOT_FOUND + CHK(!mime.IsInstalled()); + CHK(mime.SetAttrInfo(&msg) == B_OK); + CHK(mime.IsInstalled()); + CHK(mime.GetAttrInfo(&msg2) == B_OK); + CHK(msg.AddString(typeField, testType) == B_OK); // Add in "type" fields as GAI() does + CHK(msg == msg2); + } + + // Normal Function + nextSubTest(); + { + BMessage msg(WHAT); + BMimeType mime(testType); + CHK(mime.InitCheck() == B_OK); + + // Uninstall then reinstall to clear attributes + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + if (!mime.IsInstalled()) + CHK(mime.Install() == B_OK); + CHK(mime.IsInstalled()); + + // Initial Set()/Get() + msg1.RemoveName(typeField); // Clear "type" fields, since SAI() just adds another + msg2.RemoveName(typeField); + CHK(msg != msg1); + CHK(msg != msg2); + CHK(mime.SetAttrInfo(&msg1) == B_OK); + CHK(mime.GetAttrInfo(&msg) == B_OK); + CHK(msg1.AddString(typeField, testType) == B_OK); // Add in "type" fields as GFE() does + CHK(msg2.AddString(typeField, testType) == B_OK); + CHK(msg == msg1); + CHK(msg != msg2); + + // Followup Set()/Get() + nextSubTest(); + CHK(msg.MakeEmpty() == B_OK); + msg1.RemoveName(typeField); // Clear "type" fields, since SFE() just adds another + msg2.RemoveName(typeField); + CHK(msg != msg1); + CHK(msg != msg2); + CHK(mime.SetAttrInfo(&msg2) == B_OK); + CHK(mime.GetAttrInfo(&msg) == B_OK); + CHK(msg1.AddString(typeField, testType) == B_OK); // Add in "type" fields as GFE() does + CHK(msg2.AddString(typeField, testType) == B_OK); + CHK(msg != msg1); + CHK(msg == msg2); + + // Clear + nextSubTest(); + CHK(msg.MakeEmpty() == B_OK); + msg1.RemoveName(typeField); // Clear "type" fields, since SFE() just adds another + msg2.RemoveName(typeField); + CHK(msg != msg1); + CHK(msg != msg2); +#if !SK_TEST_R5 + CHK(RES(mime.SetAttrInfo(NULL)) == B_OK); // R5 == CRASH! despite what one might think should happen + CHK(RES(mime.GetAttrInfo(&msg)) != B_OK); + CHK(msg1.AddString(typeField, testType) == B_OK); // Add in "type" fields as GFE() does + CHK(msg2.AddString(typeField, testType) == B_OK); + CHK(msg != msg1); + CHK(msg != msg2); +#endif + } +} + +// File Extensions + +void +MimeTypeTest::FileExtensionsTest() { + // Create some messages to sling around + const int32 WHAT = 234; // This is the what value that GFE returns...not sure if it has a name yet + BMessage msg1(WHAT), msg2(WHAT), msg3(WHAT); + + CHK(msg1.AddString(fileExtField, ".data") == B_OK); + CHK(msg1.AddString(fileExtField, ".txt") == B_OK); + CHK(msg1.AddString(fileExtField, ".png") == B_OK); + CHK(msg1.AddString(fileExtField, ".html") == B_OK); + + CHK(msg2.AddString(fileExtField, ".data") == B_OK); + CHK(msg2.AddString(fileExtField, ".txt") == B_OK); + + CHK(msg3.AddString(fileExtField, ".data") == B_OK); + CHK(msg3.AddString(fileExtField, ".txt") == B_OK); + + CHK(msg1 == msg1); + CHK(msg2 == msg2); + CHK(msg3 == msg3); + CHK(msg1 != msg2); + CHK(msg1 != msg3); + CHK(msg2 == msg3); + + // Uninitialized + nextSubTest(); + { + BMessage msg(WHAT); + BMimeType mime; + + CHK(mime.InitCheck() == B_NO_INIT); + CHK(mime.GetFileExtensions(&msg) != B_OK); // R5 == B_BAD_VALUE + CHK(mime.SetFileExtensions(&msg) != B_OK); // R5 == B_BAD_VALUE + } + // NULL params + nextSubTest(); + { + BMessage msg(WHAT); + BMimeType mime(testType); + + CHK(mime.InitCheck() == B_OK); + // Make sure the type isn't installed + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + CHK(!mime.IsInstalled()); + // Not installed + CHK(mime.GetFileExtensions(NULL) != B_OK); // R5 == B_BAD_VALUE + CHK(!mime.IsInstalled()); +#if !SK_TEST_R5 + CHK(RES(mime.SetFileExtensions(NULL)) == B_OK); // R5 == CRASH! + CHK(mime.IsInstalled()); + CHK(RES(mime.GetFileExtensions(&msg)) != B_OK); // R5 == B_ENTRY_NOT_FOUND + // Installed +/* CHK(mime.GetFileExtensions(NULL) != B_OK); // R5 == B_BAD_VALUE + CHK(mime.SetFileExtensions(helper.Bitmap1()) == B_OK); + CHK(mime.GetFileExtensions(bmp) == B_OK); + CHK(*bmp == *helper.Bitmap1()); + CHK(mime.SetFileExtensions(NULL) == B_OK); + CHK(mime.GetFileExtensions(bmp) != B_OK); // R5 == B_ENTRY_NOT_FOUND*/ +#endif + } + // Set() with empty message + nextSubTest(); + { + BMimeType mime(testType); + BMessage msgEmpty(WHAT); + BMessage msg(WHAT); + CHK(msg.AddInt32("stuff", 1234) == B_OK); // Add an extra attribute to give us something to compare with + + // Uninstall then reinstall to clear attributes + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + if (!mime.IsInstalled()) + CHK(mime.Install() == B_OK); + CHK(mime.IsInstalled()); + + // Set(empty) + CHK(msg != msgEmpty); + CHK(mime.SetFileExtensions(&msgEmpty) == B_OK); + CHK(mime.GetFileExtensions(&msg) == B_OK); + CHK(msgEmpty.AddString(typeField, testType) == B_OK); // Add in "type" fields as GFE() does + CHK(msg == msgEmpty); + } + // Set() with extra attributes in message + nextSubTest(); + { + BMimeType mime(testType); + BMessage msg(WHAT); + BMessage msgExtraSet(msg1); + CHK(msgExtraSet.AddString("extra", ".extra") == B_OK); + CHK(msgExtraSet.AddInt32("more_extras", 123) == B_OK); + CHK(msgExtraSet.AddInt32("more_extras", 456) == B_OK); + CHK(msgExtraSet.AddInt32("more_extras", 789) == B_OK); + BMessage msgExtraGet(msgExtraSet); + + // Uninstall then reinstall to clear attributes + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + if (!mime.IsInstalled()) + CHK(mime.Install() == B_OK); + CHK(mime.IsInstalled()); + + // Set(extra)/Get(empty) + msg1.RemoveName(typeField); // Clear "type" fields, since SFE() just adds another + msg2.RemoveName(typeField); + CHK(msg != msg1); + CHK(msg != msgExtraSet); + CHK(mime.SetFileExtensions(&msgExtraSet) == B_OK); + CHK(mime.GetFileExtensions(&msg) == B_OK); + CHK(msg1.AddString(typeField, testType) == B_OK); // Add in "type" fields as GFE() does + CHK(msgExtraSet.AddString(typeField, testType) == B_OK); + CHK(msg == msgExtraSet); + CHK(msg != msg1); + + // Get(extra) + nextSubTest(); + CHK(mime.GetFileExtensions(&msgExtraGet) == B_OK); + CHK(msgExtraGet == msgExtraSet); + CHK(msgExtraGet != msg1); + + // Get(extra and then some) + nextSubTest(); + CHK(msgExtraGet.AddInt32("more_extras", 101112) == B_OK); + msgExtraGet.RemoveName(typeField); // Clear "type" fields to be fair, since SFE() just adds another + CHK(mime.GetFileExtensions(&msgExtraGet) == B_OK); // Reinitializes result (clearing extra fields) + CHK(msgExtraGet == msgExtraSet); + CHK(msgExtraGet != msg1); + + } + // Normal function + nextSubTest(); + { + BMessage msg(WHAT); + BMimeType mime(testType); + + // Uninstall then reinstall to clear attributes + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + if (!mime.IsInstalled()) + CHK(mime.Install() == B_OK); + CHK(mime.IsInstalled()); + + // Initial Set()/Get() + msg1.RemoveName(typeField); // Clear "type" fields, since SFE() just adds another + msg2.RemoveName(typeField); + CHK(msg != msg1); + CHK(msg != msg2); + CHK(mime.SetFileExtensions(&msg1) == B_OK); + CHK(mime.GetFileExtensions(&msg) == B_OK); + CHK(msg1.AddString(typeField, testType) == B_OK); // Add in "type" fields as GFE() does + CHK(msg2.AddString(typeField, testType) == B_OK); + CHK(msg == msg1); + CHK(msg != msg2); + + // Followup Set()/Get() + nextSubTest(); + CHK(msg.MakeEmpty() == B_OK); + msg1.RemoveName(typeField); // Clear "type" fields, since SFE() just adds another + msg2.RemoveName(typeField); + CHK(msg != msg1); + CHK(msg != msg2); + CHK(mime.SetFileExtensions(&msg2) == B_OK); + CHK(mime.GetFileExtensions(&msg) == B_OK); + CHK(msg1.AddString(typeField, testType) == B_OK); // Add in "type" fields as GFE() does + CHK(msg2.AddString(typeField, testType) == B_OK); + CHK(msg != msg1); + CHK(msg == msg2); + + // Clear + nextSubTest(); + CHK(msg.MakeEmpty() == B_OK); + msg1.RemoveName(typeField); // Clear "type" fields, since SFE() just adds another + msg2.RemoveName(typeField); + CHK(msg != msg1); + CHK(msg != msg2); +#if !SK_TEST_R5 + CHK(RES(mime.SetFileExtensions(NULL)) == B_OK); // R5 == CRASH! despite what the BeBook says + CHK(RES(mime.GetFileExtensions(&msg)) != B_OK); + CHK(msg1.AddString(typeField, testType) == B_OK); // Add in "type" fields as GFE() does + CHK(msg2.AddString(typeField, testType) == B_OK); + CHK(msg != msg1); + CHK(msg != msg2); +#endif + } +} + + +// Icon Test Helper Function + +void +MimeTypeTest::IconTest(IconHelper &helper) { + BBitmap *bmp = helper.TempBitmap(); + // Unitialized + nextSubTest(); + { + BMimeType mime; + CHK(mime.InitCheck() == B_NO_INIT); + CHK(helper.GetIcon(mime, bmp) != B_OK); // R5 == B_BAD_VALUE + CHK(helper.SetIcon(mime, bmp) != B_OK); // R5 == B_BAD_VALUE + } + // Non-installed type + nextSubTest(); + { + BMimeType mime(testType); + CHK(mime.InitCheck() == B_OK); + // Make sure the type isn't installed + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + CHK(!mime.IsInstalled()); + // Test + CHK(helper.GetIcon(mime, bmp) != B_OK); // R5 == B_ENTRY_NOT_FOUND + CHK(!mime.IsInstalled()); + CHK(helper.SetIcon(mime, helper.Bitmap1()) == B_OK); + CHK(mime.IsInstalled()); + CHK(helper.GetIcon(mime, bmp) == B_OK); + CHK(*bmp == *helper.Bitmap1()); + } + // NULL params + nextSubTest(); + { + BMimeType mime(testType); + CHK(mime.InitCheck() == B_OK); + // Make sure the type isn't installed + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + CHK(!mime.IsInstalled()); + // Uninstalled + CHK(helper.GetIcon(mime, NULL) != B_OK); // R5 == B_BAD_VALUE + CHK(!mime.IsInstalled()); + CHK(helper.SetIcon(mime, NULL) != B_OK); // R5 == Installs, B_ENTRY_NOT_FOUND + CHK(mime.IsInstalled()); + CHK(helper.GetIcon(mime, bmp) != B_OK); // R5 == B_ENTRY_NOT_FOUND + // Installed + CHK(helper.GetIcon(mime, NULL) != B_OK); // R5 == B_BAD_VALUE + CHK(helper.SetIcon(mime, helper.Bitmap1()) == B_OK); + CHK(helper.GetIcon(mime, bmp) == B_OK); + CHK(*bmp == *helper.Bitmap1()); + CHK(helper.SetIcon(mime, NULL) == B_OK); + CHK(helper.GetIcon(mime, bmp) != B_OK); // R5 == B_ENTRY_NOT_FOUND + } + // Invalid Bitmap Size (small -- 10x10) + nextSubTest(); + { + BMimeType mime(testType); + CHK(mime.InitCheck() == B_OK); + // Uninstall then reinstall to clear attributes + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + if (!mime.IsInstalled()) + CHK(mime.Install() == B_OK); + CHK(mime.IsInstalled()); + // Init Test Bitmap + BBitmap testBmp(BRect(0,0,9,9), B_CMAP8); + fill_bitmap(testBmp, 3); + // Test Set() + CHK(testBmp != *helper.Bitmap1()); + CHK(helper.SetIcon(mime, helper.Bitmap1()) == B_OK); + CHK(helper.GetIcon(mime, bmp) == B_OK); + CHK(*bmp == *helper.Bitmap1()); + CHK(helper.SetIcon(mime, &testBmp) != B_OK); // R5 == B_BAD_VALUE + CHK(helper.GetIcon(mime, bmp) == B_OK); + CHK(*bmp == *helper.Bitmap1()); + CHK(*bmp != testBmp); + // Test Get() + fill_bitmap(testBmp, 3); + CHK(helper.SetIcon(mime, helper.Bitmap1()) == B_OK); + CHK(helper.GetIcon(mime, &testBmp) != B_OK); // R5 == B_BAD_VALUE + } + // Invalid Bitmap Size (large -- 100x100) + nextSubTest(); + { + BMimeType mime(testType); + CHK(mime.InitCheck() == B_OK); + // Uninstall then reinstall to clear attributes + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + if (!mime.IsInstalled()) + CHK(mime.Install() == B_OK); + CHK(mime.IsInstalled()); + // Init Test Bitmap + BBitmap testBmp(BRect(0,0,99,99), B_CMAP8); + // Test Set() + fill_bitmap(testBmp, 3); + CHK(testBmp != *helper.Bitmap1()); + CHK(helper.SetIcon(mime, helper.Bitmap1()) == B_OK); + CHK(helper.GetIcon(mime, bmp) == B_OK); + CHK(*bmp == *helper.Bitmap1()); + CHK(helper.SetIcon(mime, &testBmp) != B_OK); // R5 == B_BAD_VALUE + CHK(helper.GetIcon(mime, bmp) == B_OK); + CHK(*bmp == *helper.Bitmap1()); + CHK(*bmp != testBmp); + // Test Get() + fill_bitmap(testBmp, 3); + CHK(helper.SetIcon(mime, helper.Bitmap1()) == B_OK); + CHK(helper.GetIcon(mime, &testBmp) != B_OK); // R5 == B_BAD_VALUE + } + // Invalid Bitmap Color Depth + nextSubTest(); + { + BMimeType mime(testType); + CHK(mime.InitCheck() == B_OK); + // Uninstall then reinstall to clear attributes + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + if (!mime.IsInstalled()) + CHK(mime.Install() == B_OK); + CHK(mime.IsInstalled()); + // Init Test Bitmap + BBitmap testBmp(helper.BitmapBounds(), B_RGBA32); + // Test Set() +#if !SK_TEST_R5 + fill_bitmap(testBmp, 4); + CHK(testBmp != *helper.Bitmap1()); + CHK(RES(helper.SetIcon(mime, helper.Bitmap1())) == B_OK); + CHK(RES(helper.GetIcon(mime, bmp)) == B_OK); + CHK(*bmp == *helper.Bitmap1()); + CHK(RES(helper.SetIcon(mime, &testBmp)) == B_OK); + // R5 == B_OK, despite being invalid color depth; however, icon is not actually set, + // and any subsequent call to GetIcon() will cause the application to crash... + CHK(RES(helper.GetIcon(mime, bmp)) == B_OK); // R5 == CRASH! + CHK(*bmp == *helper.Bitmap1()); + CHK(*bmp != testBmp); +#endif + // Test Get() +#if SK_TEST_R5 + fill_bitmap(testBmp, 3); + CHK(helper.SetIcon(mime, helper.Bitmap1()) == B_OK); + CHK(helper.GetIcon(mime, &testBmp) == B_OK); // R5 == B_OK, but testBmp is not actually modified + CHK(testBmp != *helper.Bitmap1()); +#endif + } + // Normal Function + nextSubTest(); + { + BMimeType mime(testType); + CHK(mime.InitCheck() == B_OK); + // Uninstall then reinstall to clear attributes + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + if (!mime.IsInstalled()) + CHK(mime.Install() == B_OK); + CHK(mime.IsInstalled()); + // Set() then Get() + fill_bitmap(*bmp, 3); + CHK(*bmp != *helper.Bitmap1()); + CHK(helper.SetIcon(mime, helper.Bitmap1()) == B_OK); + CHK(helper.GetIcon(mime, bmp) == B_OK); + CHK(*bmp == *helper.Bitmap1()); + // Set() then Get() again + fill_bitmap(*bmp, 3); + CHK(helper.SetIcon(mime, helper.Bitmap2()) == B_OK); + CHK(helper.GetIcon(mime, bmp) == B_OK); + CHK(*bmp == *helper.Bitmap2()); + CHK(*bmp != *helper.Bitmap1()); + } +} + +// Icon For Type Helper Functions + +void +MimeTypeTest::IconForTypeTest(IconForTypeHelper &helper) { + IconTest(helper); // First run all the icon tests + // Then do some IconForType() specific tests + + BBitmap *bmp = helper.TempBitmap(); + + // Invalid MIME string + nextSubTest(); + { + BMimeType mime(testType); + CHK(mime.InitCheck() == B_OK); + // Uninstall then reinstall to clear attributes + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + if (!mime.IsInstalled()) + CHK(mime.Install() == B_OK); + CHK(mime.IsInstalled()); + // Set() then Get() + fill_bitmap(*bmp, 3); + CHK(*bmp != *helper.Bitmap1()); + CHK(mime.SetIconForType(testTypeInvalid, helper.Bitmap1(), helper.Size()) != B_OK); // R5 == B_BAD_VALUE + CHK(mime.GetIconForType(testTypeInvalid, bmp, helper.Size()) != B_OK); // R5 == B_BAD_VALUE + CHK(*bmp != *helper.Bitmap1()); + } + // NULL MIME string (just like calling respective {Get,Set}Icon() function) + nextSubTest(); + { + BMimeType mime(testType); + CHK(mime.InitCheck() == B_OK); + // Uninstall then reinstall to clear attributes + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + if (!mime.IsInstalled()) + CHK(mime.Install() == B_OK); + CHK(mime.IsInstalled()); + // Set() then Get() + fill_bitmap(*bmp, 3); + CHK(*bmp != *helper.Bitmap1()); + CHK(mime.SetIconForType(NULL, helper.Bitmap1(), helper.Size()) == B_OK); + CHK(mime.GetIconForType(NULL, bmp, helper.Size()) == B_OK); + CHK(*bmp == *helper.Bitmap1()); + // Verify GetIcon() does the same thing + fill_bitmap(*bmp, 3); + CHK(*bmp != *helper.Bitmap1()); + CHK(mime.GetIcon(bmp, helper.Size()) == B_OK); + CHK(*bmp == *helper.Bitmap1()); + } +} + +void +MimeTypeTest::LargeIconTest() { + IconHelper helper(B_LARGE_ICON); + IconTest(helper); +} + +void +MimeTypeTest::MiniIconTest() { + IconHelper helper(B_MINI_ICON); + IconTest(helper); +} + +void +MimeTypeTest::LargeIconForTypeTest() { + IconForTypeHelper helper(testType, B_LARGE_ICON); + IconForTypeTest(helper); +} + +void +MimeTypeTest::MiniIconForTypeTest() { + IconForTypeHelper helper(testType, B_MINI_ICON); + IconForTypeTest(helper); +} + +bool isMIMESupertype(const char *type) { + BMimeType sub, super; + status_t err; + err = !type || !BMimeType::IsValid(type); + + // See if the type is the same as it's supertype + if (!err) + err = sub.SetTo(type); + if (!err) + return sub.GetSupertype(&super) == B_BAD_VALUE; + // This is what R5::GetSupertype() returns when called on a supertype; + + return false; +} + + + +void +MimeTypeTest::InstalledTypesTest() { + // NULL params + { + BMessage msg; + nextSubTest(); +#if !SK_TEST_R5 + CHK(RES(BMimeType::GetInstalledTypes(NULL)) != B_OK); // R5 == CRASH!!! +#endif + nextSubTest(); +#if !SK_TEST_R5 + CHK(RES(BMimeType::GetInstalledTypes("text", NULL)) != B_OK); // R5 == CRASH!!! +#endif + nextSubTest(); + CHK(BMimeType::GetInstalledTypes(NULL, &msg) == B_OK); // Same as GetInstalledTypes(&msg) + nextSubTest(); +#if !SK_TEST_R5 + CHK(RES(BMimeType::GetInstalledTypes(NULL, NULL)) != B_OK); // R5 == CRASH!!! +#endif + nextSubTest(); +#if !SK_TEST_R5 + CHK(RES(BMimeType::GetInstalledSupertypes(NULL)) != B_OK); // R5 == CRASH!!! +#endif + } + // Invalid supertype param to GetInstalledTypes(char *super, BMessage*) + { + BMessage msg; + nextSubTest(); + CHK(!BMimeType::IsValid(testTypeSuperInvalid)); + CHK(BMimeType::GetInstalledTypes(testTypeSuperInvalid, &msg) != B_OK); // R5 == B_BAD_VALUE + nextSubTest(); + CHK(BMimeType::IsValid(testTypeSuperValid)); + CHK(BMimeType::GetInstalledTypes(testTypeSuperValid, &msg) != B_OK); // R5 == B_ENTRY_NOT_FOUND + } + // Normal Function -- GetInstalledTypes(BMessage*) + // This test gets the list of installed types, then iterates through + // the actual database directory listings and verifies they're identical. + nextSubTest(); + { + BMessage msg; + + // Get the list of installed types + CHK(BMimeType::GetInstalledTypes(&msg) == B_OK); + + // Add all the type strings to a std::set + std::set typeSet; + type_code type; + int32 count; + status_t err = msg.GetInfo("types", &type, &count); + + if (err == B_NAME_NOT_FOUND) + count = 0; // No types installed in the database! :-) + else + CHK(err == B_OK); + + for (int i = 0; i < count; i++) { + char *str; + CHK(msg.FindString("types", i, (const char**)&str) == B_OK); + // Convert it to lowercase, since the filenames for types are lowercase, but + // the types returned by GetInstalledTypes are sometimes mixedcase + std::string strLower; + to_lower(str, strLower); + // Make sure it's a valid type string, since the R5::GetInstalled*Types() + // functions do no such verification, and we ignore invalid type files + // in the database. + if (BMimeType::IsValid(strLower.c_str())) + typeSet.insert(strLower.c_str()); + } + + // Manually verify that the set of types returned by GetInstalledTypes() + // and the types present in the database are exactly the same (ignoring + // any files with names made of invalid characters, in case some bozo + // manually added such a file :-) + BDirectory rootDir(mimeDatabaseDir); + BEntry superEntry; + CHK(rootDir.InitCheck() == B_OK); + rootDir.Rewind(); + while (true) { + status_t err = rootDir.GetNextEntry(&superEntry); + if (err == B_ENTRY_NOT_FOUND) + break; // End of directory listing + + CHK(!err); // Any other error is unacceptable :-) + + // Get the leaf name + char superLeafMixed[B_PATH_NAME_LENGTH+1]; + CHK(superEntry.GetName(superLeafMixed) == B_OK); + std::string superLeaf; + to_lower(superLeafMixed, superLeaf); + + // We're only interested in directories, as they map to + // supertypes (and since they map thusly, they must also + // be valid MIME strings) + if (superEntry.IsDirectory() && BMimeType::IsValid(superLeaf.c_str())) { + // First, find and remove the supertype from our set + CHK(typeSet.find(superLeaf.c_str()) != typeSet.end()); + typeSet.erase(superLeaf.c_str()); + + // Second, iterate through all the entries in the directory. + // If the entry designates a valid MIME string, find it + // in the set and remove it. + BDirectory superDir(&superEntry); + BEntry subEntry; + CHK(superDir.InitCheck() == B_OK); + superDir.Rewind(); + while (true) { + status_t err = superDir.GetNextEntry(&subEntry); + if (err == B_ENTRY_NOT_FOUND) + break; // End of directory listing + + CHK(!err); // Any other error is unacceptable :-) + + // Get the leaf name + char subLeafMixed[B_PATH_NAME_LENGTH+1]; + CHK(subEntry.GetName(subLeafMixed) == B_OK); + std::string subLeaf; + to_lower(subLeafMixed, subLeaf); + + // Verify it's a valid mime string. If so, find and remove from our set + std::string subType = superLeaf + "/" + subLeaf; + if (BMimeType::IsValid(subType.c_str())) { + CHK(typeSet.find(subType.c_str()) != typeSet.end()); + typeSet.erase(subType.c_str()); + } + } + } + } + + // At this point our set should be empty :-) + CHK(typeSet.size() == 0); + } + // Normal Function -- GetInstalledSupertypes()/GetInstalledTypes(char*,BMessage*) + // This test gets the list of installed super types, then iterates through + // the actual database directory listings and verifies they're identical. + nextSubTest(); + { + BMessage msg; + + // Get the list of installed types + CHK(BMimeType::GetInstalledSupertypes(&msg) == B_OK); + + // Add all the type strings to a std::set + std::set typeSet; + type_code type; + int32 count; + status_t err = msg.GetInfo("super_types", &type, &count); + + if (err == B_NAME_NOT_FOUND) + count = 0; // No supertypes installed in the database! :-) + else + CHK(err == B_OK); + + for (int i = 0; i < count; i++) { + char *str; + CHK(msg.FindString("super_types", i, (const char**)&str) == B_OK); + // Convert it to lowercase, since the filenames for types are lowercase, but + // the types returned by GetInstalledTypes are sometimes mixedcase + std::string strLower; + to_lower(str, strLower); + // Make sure it's a valid type string, since the R5::GetInstalled*Types() + // functions do no such verification, and we ignore invalid type files + // in the database. + if (BMimeType::IsValid(strLower.c_str())) + typeSet.insert(strLower.c_str()); + } + + // Manually verify that the set of types returned by GetInstalledSupertypes() + // and the types present in the database are exactly the same (ignoring + // any files with names made of invalid characters, in case some bozo + // manually added such a file :-) + BDirectory rootDir(mimeDatabaseDir); + BEntry superEntry; + CHK(rootDir.InitCheck() == B_OK); + rootDir.Rewind(); + while (true) { + status_t err = rootDir.GetNextEntry(&superEntry); + if (err == B_ENTRY_NOT_FOUND) + break; // End of directory listing + + CHK(!err); // Any other error is unacceptable :-) + + // Get the leaf name + char superLeafMixed[B_PATH_NAME_LENGTH+1]; + CHK(superEntry.GetName(superLeafMixed) == B_OK); + std::string superLeaf; + to_lower(superLeafMixed, superLeaf); + + // We're only interested in directories, as they map to + // supertypes (and since they map thusly, they must also + // be valid MIME strings) + if (superEntry.IsDirectory() && BMimeType::IsValid(superLeaf.c_str())) { + // First, find and remove the supertype from our set + CHK(typeSet.find(superLeaf.c_str()) != typeSet.end()); + typeSet.erase(superLeaf.c_str()); + + // Second, get the list of corresponding subtypes and add them + // to a std::set to be used for verification + BMessage msg; + CHK(BMimeType::GetInstalledTypes(superLeaf.c_str(), &msg) == B_OK); + type_code type; + int32 count; + std::set subtypeSet; + status_t err = msg.GetInfo("types", &type, &count); + if (err == B_NAME_NOT_FOUND) + count = 0; // No subtypes for this supertype + else + CHK(err == B_OK); + for (int i = 0; i < count; i++) { + char *str; + CHK(msg.FindString("types", i, (const char**)&str) == B_OK); + // Convert it to lowercase, since the filenames for types are lowercase, but + // the types returned by GetInstalledTypes are sometimes mixedcase + std::string strLower; + to_lower(str, strLower); + // Make sure it's a valid type string, since the R5::GetInstalled*Types() + // functions do no such verification, and we ignore invalid type files + // in the database. + if (BMimeType::IsValid(strLower.c_str())) + subtypeSet.insert(strLower.c_str()); + } + + // Third, iterate through all the entries in the directory. + // If the entry designates a valid MIME string, find it + // in the subtype set and remove it. + BDirectory superDir(&superEntry); + BEntry subEntry; + CHK(superDir.InitCheck() == B_OK); + superDir.Rewind(); + while (true) { + status_t err = superDir.GetNextEntry(&subEntry); + if (err == B_ENTRY_NOT_FOUND) + break; // End of directory listing + + CHK(!err); // Any other error is unacceptable :-) + + // Get the leaf name + char subLeafMixed[B_PATH_NAME_LENGTH+1]; + CHK(subEntry.GetName(subLeafMixed) == B_OK); + std::string subLeaf; + to_lower(subLeafMixed, subLeaf); + + // Verify it's a valid mime string. If so, find and remove from our set + std::string subType = superLeaf + "/" + subLeaf; + if (BMimeType::IsValid(subType.c_str())) { + CHK(subtypeSet.find(subType.c_str()) != subtypeSet.end()); + subtypeSet.erase(subType.c_str()); + } + } + + // At this point our subtype set should be empty :-) + CHK(subtypeSet.size() == 0); + + } + } + + // At this point our set should be empty :-) + CHK(typeSet.size() == 0); + } + +} + +// Short Description + +void +MimeTypeTest::ShortDescriptionTest() { + DescriptionTest(&BMimeType::GetShortDescription, &BMimeType::SetShortDescription); +} + +// Long Description + +void +MimeTypeTest::LongDescriptionTest() { + DescriptionTest(&BMimeType::GetLongDescription, &BMimeType::SetLongDescription); +} + +// DescriptionTest Helper Function +void +MimeTypeTest::DescriptionTest(GetDescriptionFunc getDescr, SetDescriptionFunc setDescr) { + char str[B_MIME_TYPE_LENGTH+1]; + + // Uninitialized + nextSubTest(); + { + BMimeType mime; + CPPUNIT_ASSERT(mime.InitCheck() == B_NO_INIT); + CPPUNIT_ASSERT((mime.*getDescr)(str) != B_OK); // R5 == B_BAD_VALUE + CPPUNIT_ASSERT((mime.*setDescr)(str) != B_OK); // R5 == B_BAD_VALUE + } + // Non-installed type + nextSubTest(); + { + BMimeType mime(testType); + CHK(mime.InitCheck() == B_OK); + // Make sure the type isn't installed + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + CHK(!mime.IsInstalled()); + CHK((mime.*getDescr)(str) != B_OK); // R5 == B_ENTRY_NOT_FOUND + CHK(!mime.IsInstalled()); + CHK((mime.*setDescr)(testDescr) == B_OK); // R5 == Installs (but doesn't set), B_OK + CHK(mime.IsInstalled()); + CHK((mime.*getDescr)(str) == B_OK); + CHK(strcmp(str, testDescr) == 0); + } + // Non-installed type, NULL params + nextSubTest(); + { +#if !SK_TEST_R5 // NOTE: These tests crash for R5::LongDescription calls but not for R5::ShortDescription + // calls. Considering the general instability exihibited by most R5 calls when passed + // NULL pointers, however, I wouldn't suggest it, and thus they aren't even tested here. + BMimeType mime(testType); + CHK(mime.InitCheck() == B_OK); + // Make sure the type isn't installed + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + CHK(!mime.IsInstalled()); + CHK((mime.*getDescr)(NULL) != B_OK); // R5 == B_BAD_ADDRESS + CHK(!mime.IsInstalled()); + CHK((mime.*setDescr)(NULL) != B_OK); // R5 == Installs (but doesn't set), B_ENTRY_NOT_FOUND + // Note that a subsequent uninstall followed by a SetShortDescription() call with a + // valid description succeeds and installs, but DOES NOT actually set. + // I don't know why, but I'd just suggest not passing NULLs to the + // R5 versions. + CHK(mime.IsInstalled()); + CHK((mime.*getDescr)(str) == B_ENTRY_NOT_FOUND); +#endif + } + // Installed type + nextSubTest(); + { + BMimeType mime(testType); + CHK(mime.InitCheck() == B_OK); + // Uninstall then reinstall to clear attributes + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + if (!mime.IsInstalled()) + CHK(mime.Install() == B_OK); + // Get() with no description installed + CHK(mime.IsInstalled()); + CHK((mime.*getDescr)(str) == B_ENTRY_NOT_FOUND); // R5 == B_ENTRY_NOT_FOUND + // Initial Set()/Get() + CHK((mime.*setDescr)(testDescr) == B_OK); + CHK((mime.*getDescr)(str) == B_OK); + CHK(strcmp(str, testDescr) == 0); + // Followup Set()/Get() + CHK((mime.*setDescr)(testDescr2) == B_OK); + CHK((mime.*getDescr)(str) == B_OK); + CHK(strcmp(str, testDescr2) == 0); + } + // Installed Type, Description Too Long + nextSubTest(); + { + CHK(strlen(longDescr) > (B_MIME_TYPE_LENGTH+1)); + BMimeType mime(testType); + CHK(mime.InitCheck() == B_OK); + // Uninstall then reinstall to clear attributes + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + if (!mime.IsInstalled()) + CHK(mime.Install() == B_OK); + // Initial Set()/Get() + CHK((mime.*setDescr)(longDescr) != B_OK); // R5 == B_BAD_VALUE + CHK((mime.*getDescr)(str) == B_ENTRY_NOT_FOUND); + // Followup Set()/Get() + CHK((mime.*setDescr)(testDescr) == B_OK); + CHK((mime.*setDescr)(longDescr) != B_OK); // R5 == B_BAD_VALUE + CHK((mime.*getDescr)(str) == B_OK); + CHK(strcmp(str, testDescr) == 0); + } + +} + + +// Preferred App + +void +MimeTypeTest::PreferredAppTest() { + char str[B_MIME_TYPE_LENGTH+1]; + sprintf(str, "%s", testSig); + + // Uninitialized + nextSubTest(); + { + BMimeType mime; + CPPUNIT_ASSERT(mime.InitCheck() == B_NO_INIT); + CPPUNIT_ASSERT(mime.GetPreferredApp(str) != B_OK); // R5 == B_BAD_VALUE + CPPUNIT_ASSERT(mime.SetPreferredApp(str) != B_OK); // R5 == B_BAD_VALUE + } + // Non-installed type + nextSubTest(); + { + BMimeType mime(testType); + CHK(mime.InitCheck() == B_OK); + // Make sure the type isn't installed + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + CHK(!mime.IsInstalled()); + CHK(mime.GetPreferredApp(str) != B_OK); // R5 == B_ENTRY_NOT_FOUND + CHK(!mime.IsInstalled()); + CHK(mime.SetPreferredApp(testSig) == B_OK); // R5 == Installs (but doesn't set), B_OK + CHK(mime.IsInstalled()); + CHK(mime.GetPreferredApp(str) == B_OK); + CHK(strcmp(str, testSig) == 0); + } + // Non-installed type, NULL params + nextSubTest(); + { + BMimeType mime(testType); + CHK(mime.InitCheck() == B_OK); + // Make sure the type isn't installed + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + CHK(!mime.IsInstalled()); + CHK(mime.GetPreferredApp(NULL) != B_OK); // R5 == B_ENTRY_NOT_FOUND + CHK(!mime.IsInstalled()); + CHK(mime.SetPreferredApp(NULL) != B_OK); // R5 == Installs (but doesn't set), B_ENTRY_NOT_FOUND + CHK(mime.IsInstalled()); + CHK(mime.GetPreferredApp(str) == B_ENTRY_NOT_FOUND); + } + // Installed type, NULL params + nextSubTest(); + { + BMimeType mime(testType); + CHK(mime.InitCheck() == B_OK); + // Uninstall then reinstall to clear attributes + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + if (!mime.IsInstalled()) + CHK(mime.Install() == B_OK); + CHK(mime.IsInstalled()); + CHK(mime.GetPreferredApp(NULL) != B_OK); // R5 == B_BAD_ADDRESS + CHK(mime.SetPreferredApp(NULL) != B_OK); // R5 == B_ENTRY_NOT_FOUND + CHK(mime.GetPreferredApp(NULL) != B_OK); // R5 == B_BAD_ADDRESS + } + // Installed type + nextSubTest(); + { + BMimeType mime(testType); + CHK(mime.InitCheck() == B_OK); + // Uninstall then reinstall to clear attributes + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + if (!mime.IsInstalled()) + CHK(mime.Install() == B_OK); + // Get() with no description installed + CHK(mime.IsInstalled()); + CHK(mime.GetPreferredApp(str) == B_ENTRY_NOT_FOUND); // R5 == B_ENTRY_NOT_FOUND + // Initial Set()/Get() + CHK(mime.SetPreferredApp(testSig) == B_OK); + CHK(mime.GetPreferredApp(str) == B_OK); + CHK(strcmp(str, testSig) == 0); + // Followup Set()/Get() + CHK(mime.SetPreferredApp(testSig2) == B_OK); + CHK(mime.GetPreferredApp(str) == B_OK); + CHK(strcmp(str, testSig2) == 0); + } + // Installed Type, Signature Too Long + nextSubTest(); + { + CHK(strlen(longDescr) > (B_MIME_TYPE_LENGTH+1)); + BMimeType mime(testType); + CHK(mime.InitCheck() == B_OK); + // Uninstall then reinstall to clear attributes + if (mime.IsInstalled()) + CHK(mime.Delete() == B_OK); + if (!mime.IsInstalled()) + CHK(mime.Install() == B_OK); + // Initial Set()/Get() + CHK(mime.SetPreferredApp(longSig) != B_OK); // R5 == B_BAD_VALUE + CHK(mime.GetPreferredApp(str) == B_ENTRY_NOT_FOUND); + // Followup Set()/Get() + CHK(mime.SetPreferredApp(testSig) == B_OK); + CHK(mime.SetPreferredApp(longSig) != B_OK); // R5 == B_BAD_VALUE + CHK(mime.GetPreferredApp(str) == B_OK); + CHK(strcmp(str, testSig) == 0); + } + +} + +// Converts every character in str to lowercase and places +// the result in result. +void +to_lower(const char *str, std::string &result) { + CHK(str != NULL); + result = ""; + for (uint i = 0; i < strlen(str); i++) + result += tolower(str[i]); +} + +// Manually removes the file in the MIME database corresponding to +// the given MIME type +void +remove_type(const char *type, const char *databaseDir) { + CHK(type != NULL); + + // Since the MIME types are converted to lower case before their + // corresponding file is created in the database, we need to do + // the same + std::string typeLower; + to_lower(type, typeLower); + + BEntry entry((std::string(mimeDatabaseDir) + "/" + typeLower).c_str()); + CHK(entry.InitCheck() == B_OK); + if (entry.Exists()) + CHK(entry.Remove() == B_OK); + CHK(!entry.Exists()); +} + +// Manually verifies that the file in the MIME database corresponding to +// the given MIME type exists +bool +type_exists(const char *type, const char *databaseDir) { + CHK(type != NULL); + + // Since the MIME types are converted to lower case before their + // corresponding file is created in the database, we need to do + // the same + std::string typeLower; + to_lower(type, typeLower); + + BEntry entry((std::string(databaseDir) + "/" + typeLower).c_str()); + CHK(entry.InitCheck() == B_OK); + return entry.Exists(); +} + +void +MimeTypeTest::InstallDeleteTest() { + // Uninitialzized + nextSubTest(); + { + BMimeType mime; + CHK(mime.InitCheck() == B_NO_INIT); + CHK(!mime.IsInstalled()); + CHK(mime.Install() != B_OK); // R5 == B_BAD_VALUE + CHK(mime.Delete() != B_OK); // R5 == B_BAD_VALUE + } + // Invalid Type String + nextSubTest(); + { + BMimeType mime(testTypeInvalid); + CHK(mime.InitCheck() != B_OK); // R5 == B_BAD_VALUE + CHK(!mime.IsInstalled()); + CHK(mime.Install() != B_OK); // R5 == B_BAD_VALUE + CHK(mime.Delete() != B_OK); // R5 == B_BAD_VALUE + } + // Normal function + nextSubTest(); + { + remove_type(testType); + BMimeType mime(testType); + CHK(mime.InitCheck() == B_OK); + CHK(mime.IsInstalled() != true); + CHK(mime.Delete() != B_OK); // R5 == B_ENTRY_NOT_FOUND + CHK(!type_exists(testType)); + CHK(mime.Install() == B_OK); + CHK(type_exists(testType)); + CHK(mime.IsInstalled()); +#if !SK_TEST_R5 + CHK(mime.Install() != B_OK); // We ought to return something standard and logical here +#endif + CHK(mime.Delete() == B_OK); + CHK(!type_exists(testType)); + CHK(!mime.IsInstalled()); + } + +} + +class ContainerAdapter { +public: + virtual void Add(std::string value) = 0; +}; + +class SetAdapter : public ContainerAdapter { +public: + SetAdapter(std::set &set) + : fSet(set) { } + virtual void Add(std::string value) { + fSet.insert(value); + } +protected: + std::set &fSet; +}; + +class QueueAdapter : public ContainerAdapter { +public: + QueueAdapter(std::queue &queue) + : fQueue(queue) { } + virtual void Add(std::string value) { + fQueue.push(value); + } +protected: + std::queue &fQueue; +}; + +void FillWithMimeTypes(ContainerAdapter &container, BMessage &typeMessage, const char* fieldName) { + type_code type; + int32 count; + status_t err; + + // Get a count of types in the message + err = typeMessage.GetInfo(fieldName, &type, &count); + if (err == B_NAME_NOT_FOUND) + count = 0; // No such types installed in the database! :-) + else + CHK(err == B_OK); // Any other error is unacceptable + + // Add them all to the container, after converting to lowercase and + // checking validity + for (int i = 0; i < count; i++) { + char *str; + CHK(typeMessage.FindString(fieldName, i, (const char**)&str) == B_OK); + std::string strLower; + to_lower(str, strLower); + // Make sure it's a valid type string, since the R5::GetInstalled*Types() + // functions do no such verification, and we ignore invalid type files + // in the database. + if (BMimeType::IsValid(strLower.c_str())) + container.Add(strLower); + } +} + +void +MimeTypeTest::SupportingAppsTest() { +/* { + BMessage msg; + BMimeType::GetInstalledTypes(&msg); + msg.PrintToStream(); + } + { + BMessage msg; + BMimeType mime("application/octet-stream"); + CHK(mime.InitCheck() == B_OK); + CHK(mime.GetSupportingApps(&msg) == B_OK); + msg.PrintToStream(); + } + { + BMessage msg; + BMimeType mime("text"); + CHK(mime.InitCheck() == B_OK); + CHK(mime.GetSupportingApps(&msg) == B_OK); + msg.PrintToStream(); + } + { + BMessage msg; + BMimeType mime("text/html"); + CHK(mime.InitCheck() == B_OK); + CHK(mime.GetSupportingApps(&msg) == B_OK); + msg.PrintToStream(); + } */ + nextSubTest(); + { + std::queue typeList; // Stores all installed MIME types + std::queue appList; // Stores all installed application subtypes + std::map< std::string, std::set > typeAppMap; // Stores mapping of types to apps that support them + + // Get a list of all the types in the database + { + BMessage msg; + CHK(BMimeType::GetInstalledTypes(&msg) == B_OK); + } + + // Get a list of all the apps in the database + + // For each app in the database, get a list of the MIME types is supports, + // and add the app to the type->app map for each type + for (;false;) { + std::queue supportList; + + for (;false; /* supported types */) { + + } + } + + // For each installed type, get a list of the supported apps, and + // verify that the list matches the list we generated. Also check + // that the list of apps for the type's supertype (if it exists) + // is a subset of the list we generated for said supertype. + } +} + +void +MimeTypeTest::WildcardAppsTest() { + // NULL param + nextSubTest(); + { +#if SK_TEST_R5 + CHK(BMimeType::GetWildcardApps(NULL) == B_OK); // R5 == B_OK (???) +#else + CHK(RES(BMimeType::GetWildcardApps(NULL)) != B_OK); // Personally I think we ought to return B_BAD_VALUE +#endif + } + // Normal function (compare to BMimeType("application/octet-stream").GetSupportingApps()) + nextSubTest(); + { + BMessage msg1, msg2; + CHK(BMimeType::GetWildcardApps(&msg1) == B_OK); + BMimeType mime(wildcardType); + CHK(mime.InitCheck() == B_OK); + CHK(mime.GetSupportingApps(&msg2) == B_OK); + CHK(msg1 == msg2); + } +} + + +// init_long_types +static +void +init_long_types(char *notTooLongType, char *tooLongType) +{ + const int notTooLongLength = B_MIME_TYPE_LENGTH; + const int tooLongLength = notTooLongLength + 1; + strcpy(notTooLongType, "image/"); + memset(notTooLongType + strlen(notTooLongType), 'a', + notTooLongLength - strlen(notTooLongType)); + notTooLongType[notTooLongLength] = '\0'; + strcpy(tooLongType, "image/"); + memset(tooLongType + strlen(tooLongType), 'a', + tooLongLength - strlen(tooLongType)); + tooLongType[tooLongLength] = '\0'; +} + +// InitTest +void +MimeTypeTest::InitTest() +{ + // tests: + // * constructors + // * SetTo(), SetType() + // * Unset() + // * InitCheck() + // (* Type()) + + // We test only a few types here. Exhausting testing is done in + // ValidityTest(). + const char *validType = "image/gif"; + const char *validType2 = "application/octet-stream"; + const char *invalidType = "invalid type"; + char notTooLongType[B_MIME_TYPE_LENGTH + 3]; + char tooLongType[B_MIME_TYPE_LENGTH + 3]; + init_long_types(notTooLongType, tooLongType); + + // default constructor + nextSubTest(); + { + BMimeType type; + CHK(type.InitCheck() == B_NO_INIT); + CHK(type.Type() == NULL); + type.Unset(); + CHK(type.InitCheck() == B_NO_INIT); + CHK(type.Type() == NULL); + } + + // BMimeType(const char *) + // valid type + nextSubTest(); + { + BMimeType type(validType); + CHK(type.InitCheck() == B_OK); + CHK(string(type.Type()) == validType); + type.Unset(); + CHK(type.InitCheck() == B_NO_INIT); + CHK(type.Type() == NULL); + } + // invalid type + nextSubTest(); + { + BMimeType type(invalidType); + CHK(type.InitCheck() == B_BAD_VALUE); + CHK(type.Type() == NULL); + type.Unset(); + CHK(type.InitCheck() == B_NO_INIT); + CHK(type.Type() == NULL); + } + // long, but not too long type + nextSubTest(); + { + BMimeType type(notTooLongType); + CHK(type.InitCheck() == B_OK); + CHK(string(type.Type()) == notTooLongType); + type.Unset(); + CHK(type.InitCheck() == B_NO_INIT); + CHK(type.Type() == NULL); + } + // too long type + nextSubTest(); + { + BMimeType type(tooLongType); + CHK(type.InitCheck() == B_BAD_VALUE); + CHK(type.Type() == NULL); + type.Unset(); + CHK(type.InitCheck() == B_NO_INIT); + CHK(type.Type() == NULL); + } + + // SetTo() + // valid type + nextSubTest(); + { + BMimeType type; + CHK(type.SetTo(validType) == B_OK); + CHK(type.InitCheck() == B_OK); + CHK(string(type.Type()) == validType); + type.Unset(); + CHK(type.InitCheck() == B_NO_INIT); + CHK(type.Type() == NULL); + } + // invalid type + nextSubTest(); + { + BMimeType type; + CHK(type.SetTo(invalidType) == B_BAD_VALUE); + CHK(type.InitCheck() == B_BAD_VALUE); + CHK(type.Type() == NULL); + type.Unset(); + CHK(type.InitCheck() == B_NO_INIT); + CHK(type.Type() == NULL); + } + // long, but not too long type + nextSubTest(); + { + BMimeType type; + CHK(type.SetTo(notTooLongType) == B_OK); + CHK(type.InitCheck() == B_OK); + CHK(string(type.Type()) == notTooLongType); + type.Unset(); + CHK(type.InitCheck() == B_NO_INIT); + CHK(type.Type() == NULL); + } + // too long type + nextSubTest(); + { + BMimeType type; + CHK(type.SetTo(tooLongType) == B_BAD_VALUE); + CHK(type.InitCheck() == B_BAD_VALUE); + CHK(type.Type() == NULL); + type.Unset(); + CHK(type.InitCheck() == B_NO_INIT); + CHK(type.Type() == NULL); + } + + // SetType() + // valid type + nextSubTest(); + { + BMimeType type; + CHK(type.SetType(validType) == B_OK); + CHK(type.InitCheck() == B_OK); + CHK(string(type.Type()) == validType); + type.Unset(); + CHK(type.InitCheck() == B_NO_INIT); + CHK(type.Type() == NULL); + } + // invalid type + nextSubTest(); + { + BMimeType type; + CHK(type.SetType(invalidType) == B_BAD_VALUE); + CHK(type.InitCheck() == B_BAD_VALUE); + CHK(type.Type() == NULL); + type.Unset(); + CHK(type.InitCheck() == B_NO_INIT); + CHK(type.Type() == NULL); + } + // long, but not too long type + nextSubTest(); + { + BMimeType type; + CHK(type.SetType(notTooLongType) == B_OK); + CHK(type.InitCheck() == B_OK); + CHK(string(type.Type()) == notTooLongType); + type.Unset(); + CHK(type.InitCheck() == B_NO_INIT); + CHK(type.Type() == NULL); + } + // too long type + nextSubTest(); + { + BMimeType type; + CHK(type.SetType(tooLongType) == B_BAD_VALUE); + CHK(type.InitCheck() == B_BAD_VALUE); + CHK(type.Type() == NULL); + type.Unset(); + CHK(type.InitCheck() == B_NO_INIT); + CHK(type.Type() == NULL); + } + + // reinitialization + nextSubTest(); + { + BMimeType type(validType); + CHK(type.InitCheck() == B_OK); + CHK(string(type.Type()) == validType); + CHK(type.SetTo(validType2) == B_OK); + CHK(type.InitCheck() == B_OK); + CHK(string(type.Type()) == validType2); + } + // bad args + nextSubTest(); + { + BMimeType type(NULL); + CHK(type.Type() == NULL); + CHK(type.InitCheck() == B_NO_INIT); + CHK(type.Type() == NULL); + CHK(type.SetTo(NULL) == B_NO_INIT); + CHK(type.Type() == NULL); + CHK(type.SetType(NULL) == B_NO_INIT); + CHK(type.Type() == NULL); + } +} + +// StringTest +void +MimeTypeTest::StringTest() +{ + // tests: + // * IsValid() (static/non static) + // * Type() + // * IsSupertypeOnly() + // * GetSupertype() + // * Contains() + // * operator==() + + char notTooLongType[B_MIME_TYPE_LENGTH + 3]; + char tooLongType[B_MIME_TYPE_LENGTH + 3]; + init_long_types(notTooLongType, tooLongType); + struct mime_type_test { + const char *type; + bool super_type; + status_t error; + }; + mime_type_test tests[] = { + // valid types + { "application", true, B_OK, }, + { "application/octet-stream", false, B_OK, }, + { "audio", true, B_OK, }, + { "audio/x-aiff", false, B_OK, }, + { "image", true, B_OK, }, + { "image/gif", false, B_OK, }, + { "message", true, B_OK, }, + { "message/rfc822", false, B_OK, }, + { "multipart", true, B_OK, }, + { "multipart/mixed", false, B_OK, }, + { "text", true, B_OK, }, + { "text/plain", false, B_OK, }, + { "video", true, B_OK, }, + { "video/x-msvideo", false, B_OK, }, + { "unknown", true, B_OK, }, + { "unknown/mime-type", false, B_OK, }, + { "$%&./`'~*+#|!^", false, B_OK, }, + // invalid types + { "", false, B_BAD_VALUE, }, + { "application/", false, B_BAD_VALUE, }, + { "audio/", false, B_BAD_VALUE, }, + { "image/", false, B_BAD_VALUE, }, + { "message/", false, B_BAD_VALUE, }, + { "multipart/", false, B_BAD_VALUE, }, + { "text/", false, B_BAD_VALUE, }, + { "video/", false, B_BAD_VALUE, }, + { "unknown/", false, B_BAD_VALUE, }, + { "/gif", false, B_BAD_VALUE, }, + { "image/very/nice", false, B_BAD_VALUE, }, + { "tex t/plain", false, B_BAD_VALUE, }, + { "text/pla in", false, B_BAD_VALUE, }, + { "tex\tt/plain", false, B_BAD_VALUE, }, + { "text/pla\tin", false, B_BAD_VALUE, }, + { "tex\nt/plain", false, B_BAD_VALUE, }, + { "text/pla\nin", false, B_BAD_VALUE, }, + { "text/plain", false, B_BAD_VALUE, }, + { "text/pla>in", false, B_BAD_VALUE, }, + { "tex@t/plain", false, B_BAD_VALUE, }, + { "text/pla@in", false, B_BAD_VALUE, }, + { "tex,t/plain", false, B_BAD_VALUE, }, + { "text/pla,in", false, B_BAD_VALUE, }, + { "tex;t/plain", false, B_BAD_VALUE, }, + { "text/pla;in", false, B_BAD_VALUE, }, + { "tex:t/plain", false, B_BAD_VALUE, }, + { "text/pla:in", false, B_BAD_VALUE, }, + { "tex\"t/plain", false, B_BAD_VALUE, }, + { "text/pla\"in", false, B_BAD_VALUE, }, + { "tex(t/plain", false, B_BAD_VALUE, }, + { "text/pla(in", false, B_BAD_VALUE, }, + { "tex)t/plain", false, B_BAD_VALUE, }, + { "text/pla)in", false, B_BAD_VALUE, }, + { "tex[t/plain", false, B_BAD_VALUE, }, + { "text/pla[in", false, B_BAD_VALUE, }, + { "tex]t/pla]in", false, B_BAD_VALUE, }, + { "tex?t/plain", false, B_BAD_VALUE, }, + { "text/pla?in", false, B_BAD_VALUE, }, + { "tex=t/plain", false, B_BAD_VALUE, }, + { "text/pla=in", false, B_BAD_VALUE, }, + { "tex\\t/plain", false, B_BAD_VALUE, }, + { "text/pla\\in", false, B_BAD_VALUE, }, + // (not) too long types + { notTooLongType, false, B_OK, }, + { tooLongType, false, B_BAD_VALUE, }, + }; + int32 testCount = sizeof(tests) / sizeof(mime_type_test); + // test loop + for (int32 i = 0; i < testCount; i++) { + nextSubTest(); + mime_type_test &test = tests[i]; + BMimeType type(test.type); + CHK(type.InitCheck() == test.error); + bool valid = (test.error == B_OK); + bool validSuper = (valid && test.super_type); + // Type() + if (valid) + CHK(string(type.Type()) == test.type); + else + CHK(type.Type() == NULL); + // IsValid(), IsSuperTypeOnly() + CHK(type.IsValid() == valid); + CHK(type.IsSupertypeOnly() == validSuper); + CHK(BMimeType::IsValid(test.type) == valid); + // GetSupertype() + if (valid && !validSuper) { + BMimeType super; + CHK(type.GetSupertype(&super) == B_OK); + CHK(super.InitCheck() == B_OK); + CHK(super.Contains(&type) == true); + BString typeString(test.type); + BString superString(typeString.String(), + typeString.FindFirst('/')); + CHK(superString == super.Type()); + } else { + BMimeType super; + CHK(type.GetSupertype(&super) == B_BAD_VALUE); + } + // Contains(), == + for (int32 k = 0; k < testCount; k++) { + mime_type_test &test2 = tests[k]; + BMimeType type2(test2.type); + CHK(type2.InitCheck() == test2.error); + bool valid2 = (test2.error == B_OK); + bool validSuper2 = (valid && test2.super_type); + bool equal = (!strcmp(test.type, test2.type)); + // == + if (valid || valid2) { + CHK((type == type2) == equal); + CHK((type == test2.type) == equal); + } else { + CHK((type == type2) == false); + CHK((type == test2.type) == false); + } + // Contains() + if (valid || valid2) { + if (equal) + CHK(type.Contains(&type2) == true); + else if (validSuper && valid2 && !validSuper2) { + BMimeType super2; + CHK(type2.GetSupertype(&super2) == B_OK); + bool contains = string(super2.Type()) == type.Type(); + CHK(type.Contains(&type2) == contains); + } else + CHK(type.Contains(&type2) == false); + } else + CHK(type.Contains(&type2) == false); + } + } + // bad args + nextSubTest(); + { + BMimeType type("image/gif"); +// R5: crashes when passing NULL +#if !SK_TEST_R5 + CHK(BMimeType::IsValid(NULL) == false); + CHK(type.GetSupertype(NULL) == B_BAD_VALUE); + CHK(type.Contains(NULL) == false); +#endif + CHK((type == NULL) == false); + } +} + +// an easy to construct equivalent of a notification message +class NotificationMessage { +public: + NotificationMessage(int32 which, string type, string extraType, + bool largeIcon) + : which(which), type(type), hasExtraType(true), extraType(extraType), + hasLargeIcon(true), largeIcon(largeIcon) + { + } + + NotificationMessage(int32 which, string type, string extraType) + : which(which), type(type), hasExtraType(true), extraType(extraType), + hasLargeIcon(false), largeIcon(false) + { + } + + NotificationMessage(int32 which, string type, bool largeIcon) + : which(which), type(type), hasExtraType(false), extraType(), + hasLargeIcon(true), largeIcon(largeIcon) + { + } + + NotificationMessage(int32 which, string type) + : which(which), type(type), hasExtraType(false), extraType(), + hasLargeIcon(false), largeIcon(false) + { + } + +public: + int32 which; + string type; + bool hasExtraType; + string extraType; + bool hasLargeIcon; + bool largeIcon; +}; + +// FillAttrInfo +static +void +FillAttrInfo(BMessage &info, int32 variation = 0) +{ + switch (variation) { + case 0: + default: + CHK(info.AddString("attr:name", "attribute1") == B_OK); + CHK(info.AddString("attr:public_name", "Nice Attribute1") == B_OK); + CHK(info.AddInt32("attr:type", B_STRING_TYPE) == B_OK); + CHK(info.AddBool("attr:public", true) == B_OK); + CHK(info.AddBool("attr:editable", true) == B_OK); + break; + case 1: + CHK(info.AddString("attr:name", "attribute2") == B_OK); + CHK(info.AddString("attr:public_name", "Nice Attribute2") == B_OK); + CHK(info.AddInt32("attr:type", B_BOOL_TYPE) == B_OK); + CHK(info.AddBool("attr:public", false) == B_OK); + CHK(info.AddBool("attr:editable", false) == B_OK); + break; + } +} + +// MonitoringTest +void +MimeTypeTest::MonitoringTest() +{ + // tests: + // * Start/StopWatching() + // * updates + + // test: + // * StartWatching() + // * change something, check message queue (not empty) + // - add type + // - set icon, preferred app, attr info, file ext., short/long desc., + // icon for, app hint, sniffer rule + // - remove type + // * StopWatching(anotherTarget) + // * change something, check message queue (not empty) + // * StopWatching() + // * change something, check message queue (empty) + + CHK(fApplication != NULL); + nextSubTest(); + // StartWatching() + BMessenger target(&fApplication->Handler(), fApplication); + CHK(BMimeType::StartWatching(target) == B_OK); + // install + BMimeType type(testType); + CHK(type.InitCheck() == B_OK); + CHK(type.IsInstalled() == false); + CHK(type.Install() == B_OK); + // icon + IconHelper iconHelperLarge(B_LARGE_ICON); + IconHelper iconHelperMini(B_MINI_ICON); + CHK(type.SetIcon(iconHelperLarge.Bitmap1(), B_LARGE_ICON) == B_OK); + CHK(type.SetIcon(iconHelperMini.Bitmap1(), B_MINI_ICON) == B_OK); + // preferred app + CHK(type.SetPreferredApp(testTypeApp) == B_OK); + // attr info + BMessage attrInfo; + FillAttrInfo(attrInfo); + CHK(type.SetAttrInfo(&attrInfo) == B_OK); + // file extensions + BMessage extensions; + CHK(extensions.AddString("extensions", "arg") == B_OK); + CHK(extensions.AddString("extensions", "ugh") == B_OK); + CHK(type.SetFileExtensions(&extensions) == B_OK); + // long/short description + CHK(type.SetLongDescription("quite short for a long description") == B_OK); + CHK(type.SetShortDescription("short description") == B_OK); + // icon for type + CHK(type.SetIconForType("text/plain", iconHelperLarge.Bitmap1(), + B_LARGE_ICON) == B_OK); + CHK(type.SetIconForType("text/plain", iconHelperMini.Bitmap1(), + B_MINI_ICON) == B_OK); + // app hint + entry_ref appHintRef; + CHK(get_ref_for_path("/boot/beos/apps/StyledEdit", &appHintRef) == B_OK); + CHK(type.SetAppHint(&appHintRef) == B_OK); + // sniffer rule + const char *snifferRule = "0.5 [0:0] ('ARGH')"; + CHK(type.SetSnifferRule(snifferRule) == B_OK); + { + // - set icon, preferred app, attr info, file ext., short/long desc., + // icon for, app hint, sniffer rule + typedef NotificationMessage NM; + NotificationMessage messages[] = { + NM(B_MIME_TYPE_CREATED, testType), + NM(B_ICON_CHANGED, testType, true), + NM(B_ICON_CHANGED, testType, false), + NM(B_PREFERRED_APP_CHANGED, testType), + NM(B_ATTR_INFO_CHANGED, testType), + NM(B_FILE_EXTENSIONS_CHANGED, testType), + NM(B_LONG_DESCRIPTION_CHANGED, testType), + NM(B_SHORT_DESCRIPTION_CHANGED, testType), + NM(B_ICON_FOR_TYPE_CHANGED, testType, "text/plain", true), + NM(B_ICON_FOR_TYPE_CHANGED, testType, "text/plain", false), + NM(B_APP_HINT_CHANGED, testType), + NM(B_SNIFFER_RULE_CHANGED, testType), + }; + CheckNotificationMessages(messages, sizeof(messages) / sizeof(NM)); + } + + // set the same values once again + nextSubTest(); + // icon + CHK(type.SetIcon(iconHelperLarge.Bitmap1(), B_LARGE_ICON) == B_OK); + CHK(type.SetIcon(iconHelperMini.Bitmap1(), B_MINI_ICON) == B_OK); + // preferred app + CHK(type.SetPreferredApp(testTypeApp) == B_OK); + // attr info + CHK(type.SetAttrInfo(&attrInfo) == B_OK); +// file extensions + CHK(extensions.AddString("extensions", "arg") == B_OK); + CHK(extensions.AddString("extensions", "ugh") == B_OK); + CHK(type.SetFileExtensions(&extensions) == B_OK); + // long/short description + CHK(type.SetLongDescription("quite short for a long description") == B_OK); + CHK(type.SetShortDescription("short description") == B_OK); + // icon for type + CHK(type.SetIconForType("text/plain", iconHelperLarge.Bitmap1(), + B_LARGE_ICON) == B_OK); + CHK(type.SetIconForType("text/plain", iconHelperMini.Bitmap1(), + B_MINI_ICON) == B_OK); + // app hint + CHK(type.SetAppHint(&appHintRef) == B_OK); + // sniffer rule + CHK(type.SetSnifferRule(snifferRule) == B_OK); + { + // - set icon, preferred app, attr info, file ext., short/long desc., + // icon for, app hint, sniffer rule + typedef NotificationMessage NM; + NotificationMessage messages[] = { + NM(B_ICON_CHANGED, testType, true), + NM(B_ICON_CHANGED, testType, false), + NM(B_PREFERRED_APP_CHANGED, testType), + NM(B_ATTR_INFO_CHANGED, testType), + NM(B_FILE_EXTENSIONS_CHANGED, testType), + NM(B_LONG_DESCRIPTION_CHANGED, testType), + NM(B_SHORT_DESCRIPTION_CHANGED, testType), + NM(B_ICON_FOR_TYPE_CHANGED, testType, "text/plain", true), + NM(B_ICON_FOR_TYPE_CHANGED, testType, "text/plain", false), + NM(B_APP_HINT_CHANGED, testType), + NM(B_SNIFFER_RULE_CHANGED, testType), + }; + CheckNotificationMessages(messages, sizeof(messages) / sizeof(NM)); + } + + // set different values + nextSubTest(); + // icon + CHK(type.SetIcon(iconHelperLarge.Bitmap2(), B_LARGE_ICON) == B_OK); + CHK(type.SetIcon(iconHelperMini.Bitmap2(), B_MINI_ICON) == B_OK); + // preferred app + CHK(type.SetPreferredApp("application/x-vnd.Be-STEE") == B_OK); + // attr info + BMessage attrInfo2; + FillAttrInfo(attrInfo2, 1); + CHK(type.SetAttrInfo(&attrInfo2) == B_OK); + // file extensions + CHK(extensions.AddString("extensions", "uff") == B_OK); + CHK(extensions.AddString("extensions", "err") == B_OK); + CHK(type.SetFileExtensions(&extensions) == B_OK); + // long/short description + CHK(type.SetLongDescription("not that short description") == B_OK); + CHK(type.SetShortDescription("pretty short description") == B_OK); + // icon for type + CHK(type.SetIconForType("text/plain", iconHelperLarge.Bitmap2(), + B_LARGE_ICON) == B_OK); + CHK(type.SetIconForType("text/plain", iconHelperMini.Bitmap2(), + B_MINI_ICON) == B_OK); + // app hint + entry_ref appHintRef2; + CHK(get_ref_for_path("/boot/beos/apps/NetPositive", &appHintRef2) == B_OK); + CHK(type.SetAppHint(&appHintRef2) == B_OK); + // sniffer rule + const char *snifferRule2 = "0.7 [0:5] ('YEAH!')"; + CHK(type.SetSnifferRule(snifferRule2) == B_OK); + // delete + CHK(type.Delete() == B_OK); + { + // - set icon, preferred app, attr info, file ext., short/long desc., + // icon for, app hint, sniffer rule + typedef NotificationMessage NM; + NotificationMessage messages[] = { + NM(B_ICON_CHANGED, testType, true), + NM(B_ICON_CHANGED, testType, false), + NM(B_PREFERRED_APP_CHANGED, testType), + NM(B_ATTR_INFO_CHANGED, testType), + NM(B_FILE_EXTENSIONS_CHANGED, testType), + NM(B_LONG_DESCRIPTION_CHANGED, testType), + NM(B_SHORT_DESCRIPTION_CHANGED, testType), + NM(B_ICON_FOR_TYPE_CHANGED, testType, "text/plain", true), + NM(B_ICON_FOR_TYPE_CHANGED, testType, "text/plain", false), + NM(B_APP_HINT_CHANGED, testType), + NM(B_SNIFFER_RULE_CHANGED, testType), + NM(B_MIME_TYPE_DELETED, testType), + }; + CheckNotificationMessages(messages, sizeof(messages) / sizeof(NM)); + } + + // StopWatching() and try again -- no messages should be sent anymore + CHK(BMimeType::StopWatching(target) == B_OK); + // install + CHK(type.InitCheck() == B_OK); + CHK(type.IsInstalled() == false); + CHK(type.Install() == B_OK); + // icon + CHK(type.SetIcon(iconHelperLarge.Bitmap1(), B_LARGE_ICON) == B_OK); + CHK(type.SetIcon(iconHelperMini.Bitmap1(), B_MINI_ICON) == B_OK); + // preferred app + CHK(type.SetPreferredApp(testTypeApp) == B_OK); + // attr info + CHK(type.SetAttrInfo(&attrInfo) == B_OK); + // file extensions + CHK(extensions.AddString("extensions", "arg") == B_OK); + CHK(extensions.AddString("extensions", "ugh") == B_OK); + CHK(type.SetFileExtensions(&extensions) == B_OK); + // long/short description + CHK(type.SetLongDescription("quite short for a long description") == B_OK); + CHK(type.SetShortDescription("short description") == B_OK); + // icon for type + CHK(type.SetIconForType("text/plain", iconHelperLarge.Bitmap1(), + B_LARGE_ICON) == B_OK); + CHK(type.SetIconForType("text/plain", iconHelperMini.Bitmap1(), + B_MINI_ICON) == B_OK); + // app hint + CHK(type.SetAppHint(&appHintRef) == B_OK); + // sniffer rule + CHK(type.SetSnifferRule(snifferRule) == B_OK); + // delete + CHK(type.Delete() == B_OK); + { + CheckNotificationMessages(NULL, 0); + } + + // bad args + // StopWatching() another target + nextSubTest(); + // install + CHK(type.InitCheck() == B_OK); + CHK(type.IsInstalled() == false); + CHK(type.Install() == B_OK); + // try to start/stop watching with an invalid target, stop the wrong target + BMessenger target2(fApplication); + CHK(target2.IsValid() == true); + BMessenger target3("application/does-not_exist"); + CHK(target3.IsValid() == false); +// R5: An invalid messenger is fine for any reason?! +#if !SK_TEST_R5 + CHK(RES(BMimeType::StartWatching(target3)) == B_BAD_VALUE); +#endif + CHK(BMimeType::StartWatching(target) == B_OK); +#if !SK_TEST_R5 + CHK(BMimeType::StopWatching(target3) == B_BAD_VALUE); +#endif + CHK(BMimeType::StopWatching(target2) == B_BAD_VALUE); + CHK(BMimeType::StopWatching(target) == B_OK); + // delete + CHK(type.Delete() == B_OK); +} + +// CheckNotificationMessage +void +MimeTypeTest::CheckNotificationMessages(const NotificationMessage *messages, + int32 count) +{ + // wait for the messages + snooze(100000); + if (fApplication) { + BMessageQueue &queue = fApplication->Handler().Queue(); + CPPUNIT_ASSERT( queue.Lock() ); + try { + int32 messageNum = 0; + while (BMessage *_message = queue.NextMessage()) { + BMessage message(*_message); + delete _message; +//printf("\nmessage: %ld\n", messageNum); +//message.PrintToStream(); + CPPUNIT_ASSERT( messageNum < count ); + const NotificationMessage &entry = messages[messageNum]; + CPPUNIT_ASSERT( message.what == B_META_MIME_CHANGED ); + // which + int32 which; + CPPUNIT_ASSERT( message.FindInt32("be:which", &which) + == B_OK ); + CPPUNIT_ASSERT( entry.which == which ); + // type + const char *type; + CPPUNIT_ASSERT( message.FindString("be:type", &type) == B_OK ); + CPPUNIT_ASSERT( entry.type == type ); + // extra type + const char *extraType; + if (entry.hasExtraType) { + CPPUNIT_ASSERT( message.FindString("be:extra_type", + &extraType) == B_OK); + CPPUNIT_ASSERT( entry.extraType == extraType ); + } else { + CPPUNIT_ASSERT( message.FindString("be:extra_type", + &extraType) == B_NAME_NOT_FOUND); + } + // large icon + bool largeIcon; + if (entry.hasLargeIcon) { + CPPUNIT_ASSERT( message.FindBool("be:large_icon", + &largeIcon) == B_OK); + CPPUNIT_ASSERT( entry.largeIcon == largeIcon ); + } else { + CPPUNIT_ASSERT( message.FindBool("be:large_icon", + &largeIcon) == B_NAME_NOT_FOUND); + } + messageNum++; + } + CPPUNIT_ASSERT( messageNum == count ); + } catch (CppUnit::Exception exception) { + queue.Unlock(); + throw exception; + } + queue.Unlock(); + } +} + +// helper class for update_mime_info() tests +class MimeInfoTestFile { +public: + MimeInfoTestFile(string name, string type, const void *data = NULL, + int32 size = -1) + : name(name), + type(type), + data(NULL), + size(0) + { + if (data) { + if (size == -1) + this->size = strlen((const char*)data) + 1; + else + this->size = size; + this->data = new char[this->size]; + memcpy(this->data, data, this->size); + } + } + + ~MimeInfoTestFile() + { + delete[] data; + } + + status_t Create() + { + BFile file(name.c_str(), B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); + status_t error = file.InitCheck(); + if (error == B_OK && data) { + ssize_t written = file.Write(data, size); + if (written < 0) + error = written; + else if (written != size) + error = B_ERROR; + } + return error; + } + + status_t Delete() + { + return BEntry(name.c_str()).Remove(); + } + + string name; + string type; + char *data; + int32 size; +}; + +// UpdateMimeInfoTest +void +MimeTypeTest::UpdateMimeInfoTest() +{ + // tests: + // * update_mime_info() + + // Note: + // * Only synchronous calls are tested. + // * Updating all files is not tested as it takes too long. + + // individual files + nextSubTest(); + execCommand(string("mkdir ") + testDir + "/subdir1 " + + testDir + "/subdir2 " + + testDir + "/subdir2/subsubdir1"); + MimeInfoTestFile files[] = { + MimeInfoTestFile(string(testDir) + "/file1.cpp", "text/x-source-code"), + MimeInfoTestFile(string(testDir) + "/subdir1/file1.gif", "image/gif"), + MimeInfoTestFile(string(testDir) + "/subdir2/subsubdir1/file1", + "text/html", "\n\n\n") + }; + int fileCount = sizeof(files) / sizeof(MimeInfoTestFile); + for (int32 i = 0; i < fileCount; i++) { + MimeInfoTestFile &file = files[i]; + // no recursion + CHK(file.Create() == B_OK); + CHK(update_mime_info(file.name.c_str(), false, true, false) == B_OK); + BNode node(file.name.c_str()); + CHK(node.InitCheck() == B_OK); + BString type; + CHK(node.ReadAttrString("BEOS:TYPE", &type) == B_OK); + node.Unset(); + CHK(type == file.type.c_str()); + CHK(file.Delete() == B_OK); + // recursion + CHK(file.Create() == B_OK); + CHK(update_mime_info(file.name.c_str(), true, true, false) == B_OK); + CHK(node.SetTo(file.name.c_str()) == B_OK); + type = ""; + CHK(node.ReadAttrString("BEOS:TYPE", &type) == B_OK); + node.Unset(); + CHK(type == file.type.c_str()); + CHK(file.Delete() == B_OK); + } + +// TODO: The BeBook says: "if force is true, files are updated even if they've +// been updated already." +// As I understand this, calling update_mime_info() with force == true on a +// file, should set the BEOS:TYPE attribute regardless of whether it already +// had a value. The following test shows, that BEOS:TYPE remains unchanged +// though. +#if 0 + for (int32 i = 0; i < fileCount; i++) { + MimeInfoTestFile &file = files[i]; +printf("file: %s\n", file.name.c_str()); + CHK(file.Create() == B_OK); + // add a type attribute + BNode node(file.name.c_str()); + CHK(node.InitCheck() == B_OK); + BString type("text/plain"); + CHK(node.WriteAttrString("BEOS:TYPE", &type) == B_OK); + // update, force == false + CHK(update_mime_info(file.name.c_str(), false, true, false) == B_OK); + type = ""; + CHK(RES(node.ReadAttrString("BEOS:TYPE", &type)) == B_OK); + CHK(type == "text/plain"); + // update, force == true + CHK(update_mime_info(file.name.c_str(), false, true, true) == B_OK); + type = ""; + CHK(RES(node.ReadAttrString("BEOS:TYPE", &type)) == B_OK); + node.Unset(); +// CHK(type == file.type.c_str()); +printf("%s <-> %s\n", type.String(), file.type.c_str()); + CHK(file.Delete() == B_OK); + } +#endif // 0 + + // directory + nextSubTest(); + // create + for (int32 i = 0; i < fileCount; i++) { + MimeInfoTestFile &file = files[i]; + CHK(file.Create() == B_OK); + } + // update, not recursive + CHK(update_mime_info(testDir, false, true, false) == B_OK); + // check + for (int32 i = 0; i < fileCount; i++) { + MimeInfoTestFile &file = files[i]; + BNode node(file.name.c_str()); + CHK(node.InitCheck() == B_OK); + BString type; + CHK(node.ReadAttrString("BEOS:TYPE", &type) == B_ENTRY_NOT_FOUND); + } + // delete, re-create + for (int32 i = 0; i < fileCount; i++) { + MimeInfoTestFile &file = files[i]; + CHK(file.Delete() == B_OK); + CHK(file.Create() == B_OK); + } + // update, recursive + CHK(update_mime_info(testDir, true, true, false) == B_OK); + for (int32 i = 0; i < fileCount; i++) { + MimeInfoTestFile &file = files[i]; + BNode node(file.name.c_str()); + CHK(node.InitCheck() == B_OK); + BString type; + CHK(node.ReadAttrString("BEOS:TYPE", &type) == B_OK); + node.Unset(); + CHK(type == file.type.c_str()); + } + // delete + for (int32 i = 0; i < fileCount; i++) { + MimeInfoTestFile &file = files[i]; + CHK(file.Delete() == B_OK); + } + + // bad args: non-existing file + nextSubTest(); + BEntry entry(files[0].name.c_str()); + CHK(entry.InitCheck() == B_OK); + CHK(entry.Exists() == false); + CHK(update_mime_info(files[0].name.c_str(), false, true, false) == B_OK); +} + +// WriteStringAttr +static +status_t +WriteStringAttr(BNode &node, string name, string _value) +{ + // Wrapper for BNode::WriteAttrString() taking string rather than + // const char*/BString* parameters. + BString value(_value.c_str()); + return node.WriteAttrString(name.c_str(), &value); +} + +const uint32 MINI_ICON_TYPE = 'MICN'; + +// helper class for create_app_meta_mime() tests +class AppMimeTestFile { +public: + AppMimeTestFile(string name, string type, string signature, + const void *icon = NULL) + : name(name), + type(type), + signature(signature), + miniIcon(NULL) + { + SetMiniIcon(icon); + } + + ~AppMimeTestFile() + { + SetMiniIcon(NULL); + } + + void SetMiniIcon(const void *icon) + { + if (miniIcon) { + delete[] miniIcon; + miniIcon = NULL; + } + if (icon) { + miniIcon = new char[256]; + memcpy(miniIcon, icon, 256); + } + } + + status_t Create(bool setAttributes, bool setResources) + { + BFile file(name.c_str(), B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); + status_t error = file.InitCheck(); + // attributes + if (error == B_OK && setAttributes) { + // type + if (type.length() > 0) + error = WriteStringAttr(file, "BEOS:TYPE", type); + // signature + if (error == B_OK) + error = WriteStringAttr(file, "BEOS:APP_SIG", signature); + // mini icon + if (error == B_OK && miniIcon) { + ssize_t written = file.WriteAttr("BEOS:M:STD_ICON", + MINI_ICON_TYPE, 0, miniIcon, + 256); + if (written < 0) + error = written; + else if (written != 256) + error = B_ERROR; + } + } + // resources + if (error == B_OK && setResources) { + BResources resources; + error = resources.SetTo(&file, true); + // type + if (error == B_OK && type.length() > 0) { + error = resources.AddResource(B_STRING_TYPE, 2, type.c_str(), + type.length() + 1, "BEOS:TYPE"); + } + // signature + if (error == B_OK) { + error = resources.AddResource(B_STRING_TYPE, 1, + signature.c_str(), + signature.length() + 1, + "BEOS:APP_SIG"); + } + // mini icon + if (error == B_OK && miniIcon) { + error = resources.AddResource(MINI_ICON_TYPE, 101, miniIcon, + 256, "BEOS:M:STD_ICON"); + } + } + return error; + } + + status_t Delete(bool deleteMimeType) + { + status_t error = BEntry(name.c_str()).Remove(); + if (error == B_OK && deleteMimeType) { + BMimeType type; + // the type need not necessarily exist + error = type.SetTo(signature.c_str()); + if (error == B_OK && deleteMimeType && type.IsInstalled()) + error = type.Delete(); + } + return error; + } + + string name; + string type; + string signature; + char *miniIcon; +}; + +// CheckAppMetaMime +static +void +CheckAppMetaMime(AppMimeTestFile &file) +{ + BMimeType type; + CHK(type.SetTo(file.signature.c_str()) == B_OK); + CHK(type.IsInstalled() == true); + // short description + char shortDescription[B_MIME_TYPE_LENGTH + 1]; + CHK(type.GetShortDescription(shortDescription) == B_OK); + BPath path(file.name.c_str(), NULL, true); + CHK(string(path.Leaf()) == shortDescription); + // preferred app + char preferredApp[B_MIME_TYPE_LENGTH + 1]; + CHK(type.GetPreferredApp(preferredApp) == B_OK); + CHK(file.signature == preferredApp); + // META:PPATH + BNode typeFile; + string typeFilename(string(mimeDatabaseDir) + "/" + file.signature); + CHK(typeFile.SetTo(typeFilename.c_str()) == B_OK); + char filePath[B_PATH_NAME_LENGTH + 1]; + CHK(typeFile.ReadAttr("META:PPATH", B_STRING_TYPE, 0, filePath, + B_PATH_NAME_LENGTH + 1) > 0); + CHK(path == filePath); + // mini icon + if (file.miniIcon) { + BBitmap icon(BRect(0, 0, 15, 15), B_CMAP8); + CHK(type.GetIcon(&icon, B_MINI_ICON) == B_OK); + CHK(memcmp(icon.Bits(), file.miniIcon, 256) == 0); + } +} + +// CreateAppMetaMimeTest +void +MimeTypeTest::CreateAppMetaMimeTest() +{ + // tests: + // * create_app_meta_mime() + + // Note: + // * Only synchronous calls are tested. + // * The recursive flag isn't tested -- the BeBook sais, it is unused. + // * Updating all apps is not tested as it takes too long. + + // attributes and resources + nextSubTest(); + execCommand(string("mkdir ") + testDir + "/subdir1 " + + testDir + "/subdir2 " + + testDir + "/subdir2/subsubdir1"); + AppMimeTestFile files[] = { + AppMimeTestFile(string(testDir) + "/file1", "", + "application/x-vnd.obos.mime.test.test1"), + AppMimeTestFile(string(testDir) + "/file2", "text/x-source-code", + "application/x-vnd.obos.mime.test.test2"), + AppMimeTestFile(string(testDir) + "/file3", + "application/x-vnd.Be-elfexecutable", + "application/x-vnd.obos.mime.test.test3"), + }; + const int fileCount = sizeof(files) / sizeof(AppMimeTestFile); + for (int32 i = 0; i < fileCount; i++) { + // create file, create_app_meta_mime() + AppMimeTestFile &file = files[i]; + CHK(file.Create(true, true) == B_OK); + CHK(create_app_meta_mime(file.name.c_str(), false, true, false) + == B_OK); + // check the MIME type + CheckAppMetaMime(file); + // clean up + CHK(file.Delete(true) == B_OK); + } + + // attributes only + nextSubTest(); + for (int32 i = 0; i < fileCount; i++) { + // create file, create_app_meta_mime() + AppMimeTestFile &file = files[i]; + CHK(file.Create(true, false) == B_OK); + CHK(create_app_meta_mime(file.name.c_str(), false, true, false) + == B_OK); + // check the MIME type + CheckAppMetaMime(file); + // clean up + CHK(file.Delete(true) == B_OK); + } + + // resources only + nextSubTest(); + for (int32 i = 0; i < fileCount; i++) { + // create file, create_app_meta_mime() + AppMimeTestFile &file = files[i]; + CHK(file.Create(false, true) == B_OK); + CHK(create_app_meta_mime(file.name.c_str(), false, true, false) + == B_OK); + BMimeType type; + CHK(type.SetTo(file.signature.c_str()) == B_OK); + CHK(type.IsInstalled() == false); + // clean up + CHK(file.Delete(false) == B_OK); + } + + // test the force flag +// TODO: The BeBook says: "If force is true, entries are created even if they +// already exist." +// As I understand this, re-calling create_app_meta_mime() with force == true, +// after modifying the original file (e.g. the mini icon attribute) or +// calling it on another file with the same signature, should update the +// database entry. But the following tests show, that this doesn't happen. +// They fail in the third CheckAppMetaMime(). +#if 0 + // same file, same signature, other parameters + { + char icon1[256]; + char icon2[256]; + memset(icon1, 1, 256); + memset(icon2, 2, 256); + AppMimeTestFile file1(string(testDir) + "/file1", + "application/x-vnd.Be-elfexecutable", + "application/x-vnd.obos.mime.test.test1", + icon1); + AppMimeTestFile file2(string(testDir) + "/file1", + "application/x-vnd.Be-elfexecutable", + "application/x-vnd.obos.mime.test.test1", + icon2); + // create file 1, create_app_meta_mime() + CHK(file1.Create(true, true) == B_OK); + CHK(create_app_meta_mime(file1.name.c_str(), false, true, false) + == B_OK); + // check the MIME type + CheckAppMetaMime(file1); + // create file 2, create_app_meta_mime(), no force + CHK(file2.Create(true, true) == B_OK); + CHK(create_app_meta_mime(file2.name.c_str(), false, true, false) + == B_OK); + // check the MIME type + CheckAppMetaMime(file1); + // create_app_meta_mime(), force + CHK(create_app_meta_mime(file2.name.c_str(), false, true, true) + == B_OK); + // check the MIME type + CheckAppMetaMime(file2); + // clean up + CHK(file2.Delete(true) == B_OK); + } + // different file, same signature, other parameters + { + char icon1[256]; + char icon2[256]; + memset(icon1, 1, 256); + memset(icon2, 2, 256); + AppMimeTestFile file1(string(testDir) + "/file1", + "application/x-vnd.Be-elfexecutable", + "application/x-vnd.obos.mime.test.test1", + icon1); + AppMimeTestFile file2(string(testDir) + "/file2", + "application/x-vnd.Be-elfexecutable", + "application/x-vnd.obos.mime.test.test1", + icon2); + // create file 1, create_app_meta_mime() + CHK(file1.Create(true, true) == B_OK); + CHK(create_app_meta_mime(file1.name.c_str(), false, true, false) + == B_OK); + // check the MIME type + CheckAppMetaMime(file1); + // create file 2, create_app_meta_mime(), no force + CHK(file2.Create(true, true) == B_OK); + CHK(create_app_meta_mime(file2.name.c_str(), false, true, false) + == B_OK); + // check the MIME type + CheckAppMetaMime(file1); + // create_app_meta_mime(), force + CHK(create_app_meta_mime(file2.name.c_str(), false, true, true) + == B_OK); + // check the MIME type + CheckAppMetaMime(file2); + // clean up + CHK(file1.Delete(true) == B_OK); + CHK(file2.Delete(true) == B_OK); + } +#endif // 0 + + // bad args + nextSubTest(); + // no signature + CHK(files[0].Create(false, false) == B_OK); + CHK(create_app_meta_mime(files[0].name.c_str(), false, true, false) + == B_OK); + CHK(files[0].Delete(false) == B_OK); + // non-existing file + CHK(create_app_meta_mime(files[0].name.c_str(), false, true, false) + == B_OK); +} + +// CheckIconData +static +void +CheckIconData(const char *device, int32 iconSize, const void* data) +{ + // open the device + int fd = open(device, O_RDONLY); + CHK(fd != -1); + // get the icon + char buffer[1024]; + device_icon iconData = { + iconSize, + buffer + }; + int error = ioctl(fd, B_GET_ICON, &iconData); + // close the device + CHK(close(fd) == 0); + CHK(error == 0); + // compare the icon data + CHK(memcmp(data, buffer, iconSize * iconSize) == 0); +} + +// GetDeviceIconTest +void +MimeTypeTest::GetDeviceIconTest() +{ + // tests: + // * get_device_icon() + + // test a volume device, a non-volume device, and an invalid dev name + struct test_case { + const char *path; + bool valid; + } testCases[] = { + { "/dev/zero", false }, + { "/boot", true }, + { "/boot/home", false } + }; + const int testCaseCount = sizeof(testCases) / sizeof(test_case); + for (int32 i = 0; i < testCaseCount; i++) { + nextSubTest(); + test_case &testCase = testCases[i]; + // get device name from path name + fs_info info; + const char *deviceName = testCase.path; + if (testCase.valid) { + dev_t dev = dev_for_path(testCase.path); + CHK(dev > 0); + CHK(fs_stat_dev(dev, &info) == 0); + deviceName = info.device_name; + } + // the two valid and one invalid icon size + const int32 iconSizes[] = { 16, 32, 20 }; + const bool validSizes[] = { true, true, false }; + const int sizeCount = sizeof(iconSizes) / sizeof(int32); + for (int32 k = 0; k < sizeCount; k++) { + int32 size = iconSizes[k]; + bool valid = testCase.valid && validSizes[k]; + char buffer[1024]; + if (valid) { + CHK(get_device_icon(deviceName, buffer, size) == B_OK); + CheckIconData(deviceName, size, buffer); + // bad args: NULL buffer +// R5: Wanna see KDL? Here you go... +#if !SK_TEST_R5 + CHK(get_device_icon(deviceName, NULL, size) == B_BAD_VALUE); +#endif + } else + CHK(get_device_icon(deviceName, buffer, size) != B_OK); + } + } +} + +// SnifferRuleTest +void +MimeTypeTest::SnifferRuleTest() +{ + // tests: + // * status_t GetSnifferRule(BString *result) const; + // * status_t SetSnifferRule(const char *); + // * static status_t CheckSnifferRule(const char *rule, BString *parseError); + + // test a couple of valid and invalid rules + struct test_case { + const char *rule; + const char *error; // NULL, if valid + } testCases[] = { + // valid rules + { "1.0 (\"ABCD\")", NULL }, + { "1.0 ('ABCD')", NULL }, + { " 1.0 ('ABCD') ", NULL }, + { "0.8 [0:3] ('ABCDEFG' | 'abcdefghij')", NULL }, + { "0.5([10]'ABCD'|[17]'abcd'|[13]'EFGH')", NULL } , + { "0.5 \n [0:3] \t ('ABCD' \n | 'abcd' | 'EFGH')", NULL }, + { "0.8 [ 0 : 3 ] ('ABCDEFG' | 'abcdefghij')", NULL }, + { "0.8 [0:3] ('ABCDEFG' & 'abcdefg')", NULL }, + { "1.0 ('ABCD') | ('EFGH')", NULL }, + { "1.0 [0:3] ('ABCD') | [2:4] ('EFGH')", NULL }, + { "0.8 [0:3] (\\077Mkl0x34 & 'abcdefgh')", NULL }, + { "0.8 [0:3] (\\077034 & 'abcd')", NULL }, + { "0.8 [0:3] (\\077\\034 & 'ab')", NULL }, + { "0.8 [0:3] (\\77\\034 & 'ab')", NULL }, + { "0.8 [0:3] (\\7 & 'a')", NULL }, + { "0.8 [0:3] (\"\\17\" & 'a')", NULL }, + { "0.8 [0:3] ('\\17' & 'a')", NULL }, + { "0.8 [0:3] (\\g & 'a')", NULL }, + { "0.8 [0:3] (\\g&\\b)", NULL }, + { "0.8 [0:3] (\\g\\&b & 'abc')", NULL }, + { "0.8 [0:3] (0x3457 & 'ab')", NULL }, + { "0.8 [0:3] (0xA4b7 & 'ab')", NULL }, + { "0.8 [0:3] ('ab\"' & 'abc')", NULL }, + { "0.8 [0:3] (\"ab\\\"\" & 'abc')", NULL }, + { "0.8 [0:3] (\"ab\\A\" & 'abc')", NULL }, + { "0.8 [0:3] (\"ab'\" & 'abc')", NULL }, + { "0.8 [0:3] (\"ab\\\\\" & 'abc')", NULL }, + { "0.8 [-5:-3] (\"abc\" & 'abc')", NULL }, + { "0.8 [5:3] (\"abc\" & 'abc')", NULL }, + { "1.2 ('ABCD')", NULL }, + { ".2 ('ABCD')", NULL }, + { "0. ('ABCD')", NULL }, + { "-1 ('ABCD')", NULL }, + { "+1 ('ABCD')", NULL }, + { "1E25 ('ABCD')", NULL }, + { "1e25 ('ABCD')", NULL }, + // invalid rules + { "0.0 ('')", "Sniffer pattern error: illegal empty pattern" }, + { "('ABCD')", "Sniffer pattern error: match level expected" }, + { "[0:3] ('ABCD')", "Sniffer pattern error: match level expected" }, + { "0.8 [0:3] ( | 'abcdefghij')", + "Sniffer pattern error: missing pattern" }, + { "0.8 [0:3] ('ABCDEFG' | )", + "Sniffer pattern error: missing pattern" }, + { "[0:3] ('ABCD')", "Sniffer pattern error: match level expected" }, + { "1.0 (ABCD')", "Sniffer pattern error: misplaced single quote" }, + { "1.0 ('ABCD)", "Sniffer pattern error: unterminated rule" }, + { "1.0 (ABCD)", "Sniffer pattern error: missing pattern" }, + { "1.0 (ABCD 'ABCD')", "Sniffer pattern error: missing pattern" }, + { "1.0 'ABCD')", "Sniffer pattern error: missing pattern" }, + { "1.0 ('ABCD'", "Sniffer pattern error: unterminated rule" }, + { "1.0 'ABCD'", "Sniffer pattern error: missing sniff pattern" }, + { "0.5 [0:3] ('ABCD' | 'abcd' | [13] 'EFGH')", + "Sniffer pattern error: missing pattern" }, + { "0.5('ABCD'|'abcd'|[13]'EFGH')", + "Sniffer pattern error: missing pattern" }, + { "0.5[0:3]([10]'ABCD'|[17]'abcd'|[13]'EFGH')", + "Sniffer pattern error: missing pattern" }, + { "0.8 [0x10:3] ('ABCDEFG' | 'abcdefghij')", + "Sniffer pattern error: pattern offset expected" }, + { "0.8 [0:A] ('ABCDEFG' | 'abcdefghij')", + "Sniffer pattern error: pattern range end expected" }, + { "0.8 [0:3] ('ABCDEFG' & 'abcdefghij')", + "Sniffer pattern error: pattern and mask lengths do not match" }, + { "0.8 [0:3] ('ABCDEFG' & 'abcdefg' & 'xyzwmno')", + "Sniffer pattern error: unterminated rule" }, + { "0.8 [0:3] (\\g&b & 'a')", "Sniffer pattern error: missing mask" }, + { "0.8 [0:3] (\\19 & 'a')", + "Sniffer pattern error: pattern and mask lengths do not match" }, + { "0.8 [0:3] (0x345 & 'ab')", + "Sniffer pattern error: bad hex literal" }, + { "0.8 [0:3] (0x3457M & 'abc')", + "Sniffer pattern error: expecting '|' or '&'" }, + { "0.8 [0:3] (0x3457\\7 & 'abc')", + "Sniffer pattern error: expecting '|' or '&'" }, + { "1E-25 ('ABCD')", "Sniffer pattern error: missing pattern" }, + }; + const int testCaseCount = sizeof(testCases) / sizeof(test_case); + BMimeType type; + CHK(type.SetTo(testType) == B_OK); + CHK(type.Install() == B_OK); + for (int32 i = 0; i < testCaseCount; i++) { + nextSubTest(); + test_case &testCase = testCases[i]; + BString parseError; + status_t error = BMimeType::CheckSnifferRule(testCase.rule, + &parseError); + if (testCase.error == NULL) { +if (error != B_OK) +printf("error: %s\n", parseError.String()); + CHK(error == B_OK); + CHK(type.SetSnifferRule(testCase.rule) == B_OK); + BString rule; + CHK(type.GetSnifferRule(&rule) == B_OK); + CHK(rule == testCase.rule); + } else { + CHK(error == B_BAD_MIME_SNIFFER_RULE); + CHK(parseError.FindLast(testCase.error) >= 0); + CHK(type.SetSnifferRule(testCase.rule) == B_BAD_MIME_SNIFFER_RULE); + } + } + + // bad args: NULL rule/result string + nextSubTest(); + BString parseError; + CHK(BMimeType::CheckSnifferRule("0.0 ('')", NULL) + == B_BAD_MIME_SNIFFER_RULE); +// R5: crashes when passing a NULL rule/result buffer. +#if !SK_TEST_R5 + CHK(BMimeType::CheckSnifferRule(NULL, &parseError) == B_BAD_VALUE); + CHK(BMimeType::CheckSnifferRule(NULL, NULL) == B_BAD_VALUE); + CHK(type.GetSnifferRule(NULL) == B_BAD_VALUE); +#endif + + // NULL rule to SetSnifferRule unsets the attribute + nextSubTest(); + CHK(type.IsInstalled() == true); + CHK(type.SetSnifferRule(NULL) == B_OK); + BString rule; + CHK(type.GetSnifferRule(&rule) == B_ENTRY_NOT_FOUND); + + // bad args: uninstalled type + CHK(type.Delete() == B_OK); + CHK(type.GetSnifferRule(&rule) == B_ENTRY_NOT_FOUND); + CHK(type.SetSnifferRule("0.0 ('ABC')") == B_OK); + CHK(type.GetSnifferRule(&rule) == B_ENTRY_NOT_FOUND); + + // bad args: uninitialized BMimeType + type.Unset(); + CHK(type.GetSnifferRule(&rule) == B_BAD_VALUE); + CHK(type.SetSnifferRule("0.0 ('ABC')") == B_BAD_VALUE); +} + +// helper class for GuessMimeType() tests +class SniffingTestFile { +public: + SniffingTestFile(string name, string extensionType, string contentType, + const void *data = NULL, int32 size = -1) + : name(name), + extensionType(extensionType), + contentType(contentType), + data(NULL), + size(0) + { + // replace wildcard types + if (this->extensionType == "") + this->extensionType = "application/octet-stream"; + if (this->contentType == "") + this->contentType = "application/octet-stream"; + // copy data + if (data) { + if (size == -1) + this->size = strlen((const char*)data) + 1; + else + this->size = size; + this->data = new char[this->size]; + memcpy(this->data, data, this->size); + } + } + + ~SniffingTestFile() + { + delete[] data; + } + + status_t Create() + { + BFile file(name.c_str(), B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); + status_t error = file.InitCheck(); + if (error == B_OK && data) { + ssize_t written = file.Write(data, size); + if (written < 0) + error = written; + else if (written != size) + error = B_ERROR; + } + return error; + } + + status_t Delete() + { + return BEntry(name.c_str()).Remove(); + } + + string name; + string extensionType; + string contentType; + char *data; + int32 size; +}; + +// SniffingTest +void +MimeTypeTest::SniffingTest() +{ + // tests: + // * GuessMimeType() + + // install some test types with sniffer rules + { + BMimeType type; + CHK(type.SetTo(testType) == B_OK); + CHK(type.Install() == B_OK); + CHK(type.SetSnifferRule("0.5 [0:1] ('ABCD_EFGH' & 0xffffffff00ffffffff)") + == B_OK); + CHK(type.SetTo(testType1) == B_OK); + CHK(type.Install() == B_OK); + CHK(type.SetSnifferRule("0.4 ('ABCD')") == B_OK); + CHK(type.SetTo(testType2) == B_OK); + CHK(type.Install() == B_OK); +// This rule is invalid! + CHK(type.SetSnifferRule("0.4 [0] ('XYZ') | [0:5] ('CD E')") == B_OK); + CHK(type.SetTo(testType3) == B_OK); + CHK(type.Install() == B_OK); + CHK(type.SetSnifferRule("0.3 [0:8] ('ABCD' | 'EFGH')") == B_OK); + CHK(type.SetTo(testType4) == B_OK); + CHK(type.Install() == B_OK); + CHK(type.SetSnifferRule("0.2 [0:3] ('ABCD' | 'abcd')") == B_OK); + CHK(type.SetTo(testType5) == B_OK); + CHK(type.Install() == B_OK); + CHK(type.SetSnifferRule("0.2 ('LMNO' & 0xfffeffff)") == B_OK); + } + + SniffingTestFile files[] = { + SniffingTestFile(string(testDir) + "/file1.cpp", + "text/x-source-code", ""), + SniffingTestFile(string(testDir) + "/file2.gif", + "image/gif", ""), + SniffingTestFile(string(testDir) + "/file3", + "", "text/html", + "\n\n\n"), + SniffingTestFile(string(testDir) + "/file4.cpp", + "text/x-source-code", "text/html", + "\n\n\n"), + SniffingTestFile(string(testDir) + "/file5", "", testType1, "ABCD"), + SniffingTestFile(string(testDir) + "/file6", "", testType3, " ABCD"), + SniffingTestFile(string(testDir) + "/file7", "", testType4, "abcd"), + SniffingTestFile(string(testDir) + "/file8", "", testType3, + " ABCDEFGH"), + SniffingTestFile(string(testDir) + "/file9", "", testType, + " ABCD EFGH"), +// SniffingTestFile(string(testDir) + "/file10", "", testType2, + SniffingTestFile(string(testDir) + "/file10", "", testType3, + " ABCD EFGH"), + SniffingTestFile(string(testDir) + "/file11", "", testType5, + "LMNO"), + SniffingTestFile(string(testDir) + "/file12", "", testType5, + "LLNO"), + SniffingTestFile(string(testDir) + "/file13", "", "", + "LNNO"), + }; + int fileCount = sizeof(files) / sizeof(SniffingTestFile); + for (int32 i = 0; i < fileCount; i++) { + nextSubTest(); + SniffingTestFile &file = files[i]; + const char *filename = file.name.c_str(); +//printf("file: %s\n", filename); + const char *extensionType = file.extensionType.c_str(); + const char *contentType = file.contentType.c_str(); + const char *realType = contentType; + if (file.contentType == "application/octet-stream") + realType = extensionType; + // GuessMimeType(const char*,) + BMimeType type; + CHK(BMimeType::GuessMimeType(filename, &type) == B_OK); + CHK(type == extensionType); + type.Unset(); + // GuessMimeType(const void*, int32,) + if (file.data != NULL) { + CHK(BMimeType::GuessMimeType(file.data, file.size, &type) == B_OK); +if (!(type == contentType)) +printf("type: %s, should be: %s\n", type.Type(), realType); + CHK(type == contentType); + type.Unset(); + } + CHK(file.Create() == B_OK); + // set BEOS:TYPE to something confusing ;-) + BNode node; + CHK(node.SetTo(filename) == B_OK); + CHK(WriteStringAttr(node, "BEOS:TYPE", "application/x-person") == B_OK); + // GuessMimeType(const ref*,) + entry_ref ref; + CHK(get_ref_for_path(filename, &ref) == B_OK); + CHK(BMimeType::GuessMimeType(&ref, &type) == B_OK); +if (!(type == realType)) +printf("type: %s, should be: %s\n", type.Type(), realType); + CHK(type == realType); + type.Unset(); + + CHK(file.Delete() == B_OK); + } + + // GuessMimeType(const ref*,), invalid/abstract entry + { + nextSubTest(); + const char *filename = (string(testDir) + "/file100.cpp").c_str(); + BMimeType type; + entry_ref ref; + // invalid entry_ref: R5: Is fine! + CHK(BMimeType::GuessMimeType(&ref, &type) == B_OK); + CHK(type == "application/octet-stream"); + // abstract entry_ref + CHK(get_ref_for_path(filename, &ref) == B_OK); + CHK(BMimeType::GuessMimeType(&ref, &type) == B_NAME_NOT_FOUND); + } + + // bad args + { + nextSubTest(); + SniffingTestFile &file = files[0]; + CHK(file.Create() == B_OK); + const char *filename = file.name.c_str(); + entry_ref ref; + CHK(get_ref_for_path(filename, &ref) == B_OK); + BMimeType type; + // NULL BMimeType + CHK(BMimeType::GuessMimeType(filename, NULL) == B_BAD_VALUE); + CHK(BMimeType::GuessMimeType(file.data, file.size, NULL) + == B_BAD_VALUE); + CHK(BMimeType::GuessMimeType(&ref, NULL) == B_BAD_VALUE); + // NULL filename/ref/data + CHK(BMimeType::GuessMimeType((const char*)NULL, &type) == B_BAD_VALUE); + CHK(BMimeType::GuessMimeType(NULL, 10, &type) == B_BAD_VALUE); + CHK(BMimeType::GuessMimeType((const entry_ref*)NULL, &type) + == B_BAD_VALUE); + // NULL BMimeType and filename/ref/data + CHK(BMimeType::GuessMimeType((const char*)NULL, NULL) == B_BAD_VALUE); + CHK(BMimeType::GuessMimeType(NULL, 10, NULL) == B_BAD_VALUE); + CHK(BMimeType::GuessMimeType((const entry_ref*)NULL, NULL) + == B_BAD_VALUE); + CHK(file.Delete() == B_OK); + } +} + + +/* Ingo's functions: + + // initialization ++ BMimeType(); ++ BMimeType(const char *mimeType); +( virtual ~BMimeType();) + ++ status_t SetTo(const char *mimeType); ++ status_t SetType(const char *mimeType); ++ void Unset(); ++ status_t InitCheck() const; + + // string access ++ const char *Type() const; ++ bool IsValid() const; ++ static bool IsValid(const char *mimeType); ++ bool IsSupertypeOnly() const; ++ status_t GetSupertype(BMimeType *superType) const; ++ bool Contains(const BMimeType *type) const; ++ bool operator==(const BMimeType &type) const; ++ bool operator==(const char *type) const; + + // MIME database monitoring ++ static status_t StartWatching(BMessenger target); ++ static status_t StopWatching(BMessenger target); + + // C functions ++ int update_mime_info(const char *path, int recursive, int synchronous, + int force); ++ status_t create_app_meta_mime(const char *path, int recursive, + int synchronous, int force); ++ status_t get_device_icon(const char *dev, void *icon, int32 size); + + // sniffer rule manipulation ++ status_t GetSnifferRule(BString *result) const; ++ status_t SetSnifferRule(const char *); ++ static status_t CheckSnifferRule(const char *rule, BString *parseError); + + // sniffing ++ status_t GuessMimeType(const entry_ref *file, BMimeType *result); ++ static status_t GuessMimeType(const void *buffer, int32 length, + BMimeType *result); ++ static status_t GuessMimeType(const char *filename, BMimeType *result); +*/ + + +/* Tyler's functions: + + // MIME database access ++ status_t Install(); ++ status_t Delete(); ++ status_t GetIcon(BBitmap *icon, icon_size size) const; ++ status_t GetPreferredApp(char *signature, app_verb verb = B_OPEN) const; ++ status_t GetAttrInfo(BMessage *info) const; ++ status_t GetFileExtensions(BMessage *extensions) const; ++ status_t GetShortDescription(char *description) const; ++ status_t GetLongDescription(char *description) const; + status_t GetSupportingApps(BMessage *signatures) const; + ++ status_t SetIcon(const BBitmap *icon, icon_size size); ++ status_t SetPreferredApp(const char *signature, app_verb verb = B_OPEN); ++ status_t SetAttrInfo(const BMessage *info); ++ status_t SetFileExtensions(const BMessage *extensions); ++ status_t SetShortDescription(const char *description); ++ status_t SetLongDescription(const char *description); + + static status_t GetInstalledSupertypes(BMessage *super_types); + static status_t GetInstalledTypes(BMessage *types); + static status_t GetInstalledTypes(const char *super_type, + BMessage *subtypes); + static status_t GetWildcardApps(BMessage *wild_ones); + ++ status_t GetAppHint(entry_ref *ref) const; ++ status_t SetAppHint(const entry_ref *ref); + ++ status_t GetIconForType(const char *type, BBitmap *icon, + icon_size which) const; ++ status_t SetIconForType(const char *type, const BBitmap *icon, + icon_size which); +*/ + + diff --git a/src/tests/kits/storage/MimeTypeTest.h b/src/tests/kits/storage/MimeTypeTest.h new file mode 100644 index 0000000000..ca4acd4167 --- /dev/null +++ b/src/tests/kits/storage/MimeTypeTest.h @@ -0,0 +1,74 @@ +// MimeTypeTest.h + +#ifndef __sk_mime_type_test_h__ +#define __sk_mime_type_test_h__ + +#include +#include + +#include "BasicTest.h" +#include + +class TestApp; + +// Function pointer types for test sharing between {Get,Set}{Short,Long}Description() +typedef status_t (BMimeType::*GetDescriptionFunc)(char* description) const; +typedef status_t (BMimeType::*SetDescriptionFunc)(const char* description); + +class IconHelper; +class IconForTypeHelper; +class NotificationMessage; + +class MimeTypeTest : public BasicTest { +public: + static CppUnit::Test* Suite(); + + // This function called before *each* test added in Suite() + void setUp(); + + // This function called after *each* test added in Suite() + void tearDown(); + + //------------------------------------------------------------ + // Test functions + //------------------------------------------------------------ + void InstallDeleteTest(); + void AppHintTest(); + void AttrInfoTest(); + void FileExtensionsTest(); + void LargeIconTest(); + void MiniIconTest(); + void LargeIconForTypeTest(); + void MiniIconForTypeTest(); + void InstalledTypesTest(); + void LongDescriptionTest(); + void ShortDescriptionTest(); + void PreferredAppTest(); + void SupportingAppsTest(); + void WildcardAppsTest(); + + void InitTest(); + void StringTest(); + void MonitoringTest(); + void UpdateMimeInfoTest(); + void CreateAppMetaMimeTest(); + void GetDeviceIconTest(); + void SnifferRuleTest(); + void SniffingTest(); + + //------------------------------------------------------------ + // Helper functions + //------------------------------------------------------------ + void DescriptionTest(GetDescriptionFunc getDescr, SetDescriptionFunc setDescr); + void IconTest(IconHelper &helper); + void IconForTypeTest(IconForTypeHelper &helper); + + void CheckNotificationMessages(const NotificationMessage *messages, + int32 count); + +private: + TestApp *fApplication; +}; + + +#endif // __sk_mime_type_test_h__ diff --git a/src/tests/kits/storage/NodeTest.cpp b/src/tests/kits/storage/NodeTest.cpp new file mode 100644 index 0000000000..89885f49fb --- /dev/null +++ b/src/tests/kits/storage/NodeTest.cpp @@ -0,0 +1,1257 @@ +// NodeTest.cpp + +#include +#include +#include +#include + +#include +#include // For struct attr_info +#include +#include +#include // For struct stat + +#include +#include +#include +#include +#include +#include + +#include "TestUtils.h" + +// == for attr_info +static +inline +bool +operator==(const attr_info &info1, const attr_info &info2) +{ + return (info1.type == info2.type && info1.size == info2.size); +} + +// Suite +CppUnit::Test* +NodeTest::Suite() { + CppUnit::TestSuite *suite = new CppUnit::TestSuite(); + + StatableTest::AddBaseClassTests("BNode::", suite); + + suite->addTest( new CppUnit::TestCaller("BNode::Init Test1", &NodeTest::InitTest1) ); + suite->addTest( new CppUnit::TestCaller("BNode::Init Test2", &NodeTest::InitTest2) ); + suite->addTest( new CppUnit::TestCaller("BNode::Attribute Directory Test", &NodeTest::AttrDirTest) ); + suite->addTest( new CppUnit::TestCaller("BNode::Attribute Read/Write/Remove Test", &NodeTest::AttrTest) ); + suite->addTest( new CppUnit::TestCaller("BNode::Attribute Rename Test" +#if SK_TEST_R5 + " (NOTE: test not actually performed with R5 libraries)" +#endif + , &NodeTest::AttrRenameTest) ); + suite->addTest( new CppUnit::TestCaller("BNode::Attribute Info Test", &NodeTest::AttrInfoTest) ); + suite->addTest( new CppUnit::TestCaller("BNode::Attribute BString Test", &NodeTest::AttrBStringTest) ); + suite->addTest( new CppUnit::TestCaller("BNode::Sync Test", &NodeTest::SyncTest) ); + suite->addTest( new CppUnit::TestCaller("BNode::Dup Test", &NodeTest::DupTest) ); + suite->addTest( new CppUnit::TestCaller("BNode::Equality Test", &NodeTest::EqualityTest) ); + suite->addTest( new CppUnit::TestCaller("BNode::Assignment Test", &NodeTest::AssignmentTest) ); + suite->addTest( new CppUnit::TestCaller("BNode::Lock Test" +#if SK_TEST_OBOS_POSIX + " (NOTE: test not actually performed with OpenBeOS Posix libraries)" +#endif + , &NodeTest::LockTest) ); + + return suite; +} + +// ConvertTestNodesToStatables +static +void +ConvertTestStatablesToNodes(TestNodes& testNodes, TestStatables& testStatables) +{ + BNode *node; + string entryName; + for (testNodes.rewind(); testNodes.getNext(node, entryName); ) + testStatables.add(node, entryName); + testNodes.clear(); // avoid deletion +} + +// CreateROStatables +void +NodeTest::CreateROStatables(TestStatables& testEntries) +{ + TestNodes testNodes; + CreateRONodes(testNodes); + ConvertTestStatablesToNodes(testNodes, testEntries); +} + +// CreateRWStatables +void +NodeTest::CreateRWStatables(TestStatables& testEntries) +{ + TestNodes testNodes; + CreateRWNodes(testNodes); + ConvertTestStatablesToNodes(testNodes, testEntries); +} + +// CreateUninitializedStatables +void +NodeTest::CreateUninitializedStatables(TestStatables& testEntries) +{ + TestNodes testNodes; + CreateUninitializedNodes(testNodes); + ConvertTestStatablesToNodes(testNodes, testEntries); +} + +// CreateRONodes +void +NodeTest::CreateRONodes(TestNodes& testEntries) +{ + const char *filename; + filename = "/tmp"; + testEntries.add(new BNode(filename), filename); + filename = "/"; + testEntries.add(new BNode(filename), filename); + filename = "/boot"; + testEntries.add(new BNode(filename), filename); + filename = "/boot/home"; + testEntries.add(new BNode(filename), filename); + filename = "/boot/home/Desktop"; + testEntries.add(new BNode(filename), filename); + filename = existingFilename; + testEntries.add(new BNode(filename), filename); + filename = dirLinkname; + testEntries.add(new BNode(filename), filename); + filename = fileLinkname; + testEntries.add(new BNode(filename), filename); +} + +// CreateRWNodes +void +NodeTest::CreateRWNodes(TestNodes& testEntries) +{ + const char *filename; + filename = existingFilename; + testEntries.add(new BNode(filename), filename); + filename = existingDirname; + testEntries.add(new BNode(filename), filename); + filename = existingSubDirname; + testEntries.add(new BNode(filename), filename); + filename = dirLinkname; + testEntries.add(new BNode(filename), filename); + filename = fileLinkname; + testEntries.add(new BNode(filename), filename); + filename = relDirLinkname; + testEntries.add(new BNode(filename), filename); + filename = relFileLinkname; + testEntries.add(new BNode(filename), filename); + filename = cyclicLinkname1; + testEntries.add(new BNode(filename), filename); +} + +// CreateUninitializedNodes +void +NodeTest::CreateUninitializedNodes(TestNodes& testEntries) +{ + testEntries.add(new BNode, ""); +} + +// setUp +void +NodeTest::setUp() +{ + StatableTest::setUp(); + execCommand( + string("touch ") + existingFilename + + "; mkdir " + existingDirname + + "; mkdir " + existingSubDirname + + "; ln -s " + existingDirname + " " + dirLinkname + + "; ln -s " + existingFilename + " " + fileLinkname + + "; ln -s " + existingRelDirname + " " + relDirLinkname + + "; ln -s " + existingRelFilename + " " + relFileLinkname + + "; ln -s " + nonExistingDirname + " " + badLinkname + + "; ln -s " + cyclicLinkname1 + " " + cyclicLinkname2 + + "; ln -s " + cyclicLinkname2 + " " + cyclicLinkname1 + ); +} + +// tearDown +void +NodeTest::tearDown() +{ + StatableTest::tearDown(); + // cleanup + string cmdLine("rm -rf "); + for (int32 i = 0; i < allFilenameCount; i++) + cmdLine += string(" ") + allFilenames[i]; + if (allFilenameCount > 0) + execCommand(cmdLine); +} + +// InitTest1 +void +NodeTest::InitTest1() +{ + const char *dirLink = dirLinkname; + const char *dirSuperLink = dirSuperLinkname; + const char *dirRelLink = dirRelLinkname; + const char *fileLink = fileLinkname; + const char *existingDir = existingDirname; + const char *existingSuperDir = existingSuperDirname; + const char *existingRelDir = existingRelDirname; + const char *existingFile = existingFilename; + const char *existingSuperFile = existingSuperFilename; + const char *existingRelFile = existingRelFilename; + const char *nonExisting = nonExistingDirname; + const char *nonExistingSuper = nonExistingSuperDirname; + const char *nonExistingRel = nonExistingRelDirname; + // 1. default constructor + nextSubTest(); + { + BNode node; + CPPUNIT_ASSERT( node.InitCheck() == B_NO_INIT ); + } + + // 2. BNode(const char*) + nextSubTest(); + { + BNode node(fileLink); + CPPUNIT_ASSERT( node.InitCheck() == B_OK ); + } + nextSubTest(); + { + BNode node(nonExisting); + CPPUNIT_ASSERT( node.InitCheck() == B_ENTRY_NOT_FOUND ); + } + nextSubTest(); + { + BNode node((const char *)NULL); + CPPUNIT_ASSERT( equals(node.InitCheck(), B_BAD_VALUE, B_NO_INIT) ); + } + nextSubTest(); + { + BNode node(""); + CPPUNIT_ASSERT( node.InitCheck() == B_ENTRY_NOT_FOUND ); + } + nextSubTest(); + { + BNode node(existingFile); + CPPUNIT_ASSERT( node.InitCheck() == B_OK ); + } + nextSubTest(); + { + BNode node(existingDir); + CPPUNIT_ASSERT( node.InitCheck() == B_OK ); + } + nextSubTest(); + { + BNode node(tooLongEntryname); + CPPUNIT_ASSERT( node.InitCheck() == B_NAME_TOO_LONG ); + } + + // 3. BNode(const BEntry*) + nextSubTest(); + { + BEntry entry(dirLink); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + BNode node(&entry); + CPPUNIT_ASSERT( node.InitCheck() == B_OK ); + } + nextSubTest(); + { + BEntry entry(nonExisting); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + BNode node(&entry); + CPPUNIT_ASSERT( node.InitCheck() == B_ENTRY_NOT_FOUND ); + } + nextSubTest(); + { + BNode node((BEntry *)NULL); + CPPUNIT_ASSERT( node.InitCheck() == B_BAD_VALUE ); + } + nextSubTest(); + { + BEntry entry; + BNode node(&entry); + CPPUNIT_ASSERT( equals(node.InitCheck(), B_BAD_ADDRESS, B_BAD_VALUE) ); + } + nextSubTest(); + { + BEntry entry(existingFile); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + BNode node(&entry); + CPPUNIT_ASSERT( node.InitCheck() == B_OK ); + + } + nextSubTest(); + { + BEntry entry(existingDir); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + BNode node(&entry); + CPPUNIT_ASSERT( node.InitCheck() == B_OK ); + + } + nextSubTest(); + { + BEntry entry(tooLongEntryname); + // R5 returns E2BIG instead of B_NAME_TOO_LONG + CPPUNIT_ASSERT( equals(entry.InitCheck(), E2BIG, B_NAME_TOO_LONG) ); + BNode node(&entry); + CPPUNIT_ASSERT( equals(node.InitCheck(), B_BAD_ADDRESS, B_BAD_VALUE) ); + } + + // 4. BNode(const entry_ref*) + nextSubTest(); + { + BEntry entry(dirLink); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + entry_ref ref; + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + BNode node(&ref); + CPPUNIT_ASSERT( node.InitCheck() == B_OK ); + } + nextSubTest(); + { + BEntry entry(nonExisting); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + entry_ref ref; + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + BNode node(&ref); + CPPUNIT_ASSERT( node.InitCheck() == B_ENTRY_NOT_FOUND ); + } + nextSubTest(); + { + BNode node((entry_ref *)NULL); + CPPUNIT_ASSERT( node.InitCheck() == B_BAD_VALUE ); + } + nextSubTest(); + { + BEntry entry(existingFile); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + entry_ref ref; + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + BNode node(&ref); + CPPUNIT_ASSERT( node.InitCheck() == B_OK ); + } + nextSubTest(); + { + BEntry entry(existingDir); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + entry_ref ref; + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + BNode node(&ref); + CPPUNIT_ASSERT( node.InitCheck() == B_OK ); + } + + // 5. BNode(const BDirectory*, const char*) + nextSubTest(); + { + BDirectory pathDir(dirSuperLink); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + BNode node(&pathDir, dirRelLink); + CPPUNIT_ASSERT( node.InitCheck() == B_OK ); + } + nextSubTest(); + { + BDirectory pathDir(dirSuperLink); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + BNode node(&pathDir, dirLink); + CPPUNIT_ASSERT( node.InitCheck() == B_BAD_VALUE ); + } + nextSubTest(); + { + BDirectory pathDir(nonExistingSuper); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + BNode node(&pathDir, nonExistingRel); + CPPUNIT_ASSERT( node.InitCheck() == B_ENTRY_NOT_FOUND ); + } + nextSubTest(); + { + BNode node((BDirectory *)NULL, (const char *)NULL); + CPPUNIT_ASSERT( node.InitCheck() == B_BAD_VALUE ); + } + nextSubTest(); + { + BNode node((BDirectory *)NULL, dirLink); + CPPUNIT_ASSERT( node.InitCheck() == B_BAD_VALUE ); + } + nextSubTest(); + { + BDirectory pathDir(dirSuperLink); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + BNode node(&pathDir, (const char *)NULL); + CPPUNIT_ASSERT( node.InitCheck() == B_BAD_VALUE ); + } + nextSubTest(); + { + BDirectory pathDir(dirSuperLink); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + BNode node(&pathDir, ""); + CPPUNIT_ASSERT( node.InitCheck() == B_OK ); + } + nextSubTest(); + { + BDirectory pathDir(existingSuperFile); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + BNode node(&pathDir, existingRelFile); + CPPUNIT_ASSERT( node.InitCheck() == B_OK ); + } + nextSubTest(); + { + BDirectory pathDir(existingSuperDir); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + BNode node(&pathDir, existingRelDir); + CPPUNIT_ASSERT( node.InitCheck() == B_OK ); + } + nextSubTest(); + { + BDirectory pathDir(tooLongSuperEntryname); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + BNode node(&pathDir, tooLongRelEntryname); + CPPUNIT_ASSERT( node.InitCheck() == B_NAME_TOO_LONG ); + } + nextSubTest(); + { + BDirectory pathDir(fileSuperDirname); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + BNode node(&pathDir, fileRelDirname); + CPPUNIT_ASSERT( node.InitCheck() == B_ENTRY_NOT_FOUND ); + } +} + +// InitTest2 +void +NodeTest::InitTest2() +{ + const char *dirLink = dirLinkname; + const char *dirSuperLink = dirSuperLinkname; + const char *dirRelLink = dirRelLinkname; + const char *fileLink = fileLinkname; + const char *existingDir = existingDirname; + const char *existingSuperDir = existingSuperDirname; + const char *existingRelDir = existingRelDirname; + const char *existingFile = existingFilename; + const char *existingSuperFile = existingSuperFilename; + const char *existingRelFile = existingRelFilename; + const char *nonExisting = nonExistingDirname; + const char *nonExistingSuper = nonExistingSuperDirname; + const char *nonExistingRel = nonExistingRelDirname; + BNode node; + // 2. BNode(const char*) + nextSubTest(); + CPPUNIT_ASSERT( node.SetTo(fileLink) == B_OK ); + CPPUNIT_ASSERT( node.InitCheck() == B_OK ); + // + nextSubTest(); + CPPUNIT_ASSERT( node.SetTo(nonExisting) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( node.InitCheck() == B_ENTRY_NOT_FOUND ); + // + nextSubTest(); + CPPUNIT_ASSERT( equals(node.SetTo((const char *)NULL), B_BAD_VALUE, + B_NO_INIT) ); + CPPUNIT_ASSERT( equals(node.InitCheck(), B_BAD_VALUE, B_NO_INIT) ); + // + nextSubTest(); + CPPUNIT_ASSERT( node.SetTo("") == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( node.InitCheck() == B_ENTRY_NOT_FOUND ); + // + nextSubTest(); + CPPUNIT_ASSERT( node.SetTo(existingFile) == B_OK ); + CPPUNIT_ASSERT( node.InitCheck() == B_OK ); + // + nextSubTest(); + CPPUNIT_ASSERT( node.SetTo(existingDir) == B_OK ); + CPPUNIT_ASSERT( node.InitCheck() == B_OK ); + // + nextSubTest(); + CPPUNIT_ASSERT( node.SetTo(tooLongEntryname) == B_NAME_TOO_LONG ); + CPPUNIT_ASSERT( node.InitCheck() == B_NAME_TOO_LONG ); + + // 3. BNode(const BEntry*) + nextSubTest(); + BEntry entry(dirLink); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + CPPUNIT_ASSERT( node.SetTo(&entry) == B_OK ); + CPPUNIT_ASSERT( node.InitCheck() == B_OK ); + // + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(nonExisting) == B_OK ); + CPPUNIT_ASSERT( node.SetTo(&entry) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( node.InitCheck() == B_ENTRY_NOT_FOUND ); + // + nextSubTest(); + CPPUNIT_ASSERT( node.SetTo((BEntry *)NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( node.InitCheck() == B_BAD_VALUE ); + // + nextSubTest(); + entry.Unset(); + CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( equals(node.SetTo(&entry), B_BAD_ADDRESS, B_BAD_VALUE) ); + CPPUNIT_ASSERT( equals(node.InitCheck(), B_BAD_ADDRESS, B_BAD_VALUE) ); + // + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(existingFile) == B_OK ); + CPPUNIT_ASSERT( node.SetTo(&entry) == B_OK ); + CPPUNIT_ASSERT( node.InitCheck() == B_OK ); + // + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(existingDir) == B_OK ); + CPPUNIT_ASSERT( node.SetTo(&entry) == B_OK ); + CPPUNIT_ASSERT( node.InitCheck() == B_OK ); + // + nextSubTest(); + // R5 returns E2BIG instead of B_NAME_TOO_LONG + CPPUNIT_ASSERT( equals(entry.SetTo(tooLongEntryname), E2BIG, B_NAME_TOO_LONG) ); + CPPUNIT_ASSERT( equals(node.SetTo(&entry), B_BAD_ADDRESS, B_BAD_VALUE) ); + CPPUNIT_ASSERT( equals(node.InitCheck(), B_BAD_ADDRESS, B_BAD_VALUE) ); + + // 4. BNode(const entry_ref*) + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(dirLink) == B_OK ); + entry_ref ref; + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + CPPUNIT_ASSERT( node.SetTo(&ref) == B_OK ); + CPPUNIT_ASSERT( node.InitCheck() == B_OK ); + // + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(nonExisting) == B_OK ); + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + CPPUNIT_ASSERT( node.SetTo(&ref) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( node.InitCheck() == B_ENTRY_NOT_FOUND ); + // + nextSubTest(); + CPPUNIT_ASSERT( node.SetTo((entry_ref *)NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( node.InitCheck() == B_BAD_VALUE ); + // + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(existingFile) == B_OK ); + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + CPPUNIT_ASSERT( node.SetTo(&ref) == B_OK ); + CPPUNIT_ASSERT( node.InitCheck() == B_OK ); + // + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(existingDir) == B_OK ); + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + CPPUNIT_ASSERT( node.SetTo(&ref) == B_OK ); + CPPUNIT_ASSERT( node.InitCheck() == B_OK ); + + // 5. BNode(const BDirectory*, const char*) + nextSubTest(); + BDirectory pathDir(dirSuperLink); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( node.SetTo(&pathDir, dirRelLink) == B_OK ); + CPPUNIT_ASSERT( node.InitCheck() == B_OK ); + // + nextSubTest(); + CPPUNIT_ASSERT( pathDir.SetTo(dirSuperLink) == B_OK ); + CPPUNIT_ASSERT( node.SetTo(&pathDir, dirLink) == B_BAD_VALUE ); + CPPUNIT_ASSERT( node.InitCheck() == B_BAD_VALUE ); + // + nextSubTest(); + CPPUNIT_ASSERT( pathDir.SetTo(nonExistingSuper) == B_OK ); + CPPUNIT_ASSERT( node.SetTo(&pathDir, nonExistingRel) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( node.InitCheck() == B_ENTRY_NOT_FOUND ); + // + nextSubTest(); + CPPUNIT_ASSERT( node.SetTo((BDirectory *)NULL, (const char *)NULL) + == B_BAD_VALUE ); + CPPUNIT_ASSERT( node.InitCheck() == B_BAD_VALUE ); + // + nextSubTest(); + CPPUNIT_ASSERT( node.SetTo((BDirectory *)NULL, dirLink) == B_BAD_VALUE ); + CPPUNIT_ASSERT( node.InitCheck() == B_BAD_VALUE ); + // + nextSubTest(); + CPPUNIT_ASSERT( pathDir.SetTo(dirSuperLink) == B_OK ); + CPPUNIT_ASSERT( node.SetTo(&pathDir, (const char *)NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( node.InitCheck() == B_BAD_VALUE ); + // + nextSubTest(); + CPPUNIT_ASSERT( pathDir.SetTo(dirSuperLink) == B_OK ); + CPPUNIT_ASSERT( node.SetTo(&pathDir, "") == B_OK ); + CPPUNIT_ASSERT( node.InitCheck() == B_OK ); + // + nextSubTest(); + CPPUNIT_ASSERT( pathDir.SetTo(existingSuperFile) == B_OK ); + CPPUNIT_ASSERT( node.SetTo(&pathDir, existingRelFile) == B_OK ); + CPPUNIT_ASSERT( node.InitCheck() == B_OK ); + // + nextSubTest(); + CPPUNIT_ASSERT( pathDir.SetTo(existingSuperDir) == B_OK ); + CPPUNIT_ASSERT( node.SetTo(&pathDir, existingRelDir) == B_OK ); + CPPUNIT_ASSERT( node.InitCheck() == B_OK ); + // + nextSubTest(); + CPPUNIT_ASSERT( pathDir.SetTo(tooLongSuperEntryname) == B_OK ); + CPPUNIT_ASSERT( node.SetTo(&pathDir, tooLongRelEntryname) == B_NAME_TOO_LONG ); + CPPUNIT_ASSERT( node.InitCheck() == B_NAME_TOO_LONG ); + // + nextSubTest(); + CPPUNIT_ASSERT( pathDir.SetTo(fileSuperDirname) == B_OK ); + CPPUNIT_ASSERT( node.SetTo(&pathDir, fileRelDirname) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( node.InitCheck() == B_ENTRY_NOT_FOUND ); +} + +// WriteAttributes +static +void +WriteAttributes(BNode &node, const char **attrNames, const char **attrValues, + int32 attrCount) +{ + for (int32 i = 0; i < attrCount; i++) { + const char *attrName = attrNames[i]; + const char *attrValue = attrValues[i]; + int32 valueSize = strlen(attrValue) + 1; + CPPUNIT_ASSERT( node.WriteAttr(attrName, B_STRING_TYPE, 0, attrValue, + valueSize) == valueSize ); + } +} + +// AttrDirTest +void +NodeTest::AttrDirTest(BNode &node) +{ + // node should not have any attributes at the beginning + char nameBuffer[B_ATTR_NAME_LENGTH]; + CPPUNIT_ASSERT( node.GetNextAttrName(nameBuffer) == B_ENTRY_NOT_FOUND ); + // add some + const char *attrNames[] = { + "attr1", "attr2", "attr3", "attr4", "attr5" + }; + const char *attrValues[] = { + "value1", "value2", "value3", "value4", "value5" + }; + int32 attrCount = sizeof(attrNames) / sizeof(const char *); + WriteAttributes(node, attrNames, attrValues, attrCount); + TestSet testSet; + for (int32 i = 0; i < attrCount; i++) + testSet.add(attrNames[i]); + // get all attribute names + // R5: We have to rewind, we wouldn't get any attribute otherwise. + CPPUNIT_ASSERT( node.RewindAttrs() == B_OK ); + while (node.GetNextAttrName(nameBuffer) == B_OK) + CPPUNIT_ASSERT( testSet.test(nameBuffer) == true ); + CPPUNIT_ASSERT( testSet.testDone() == true ); + CPPUNIT_ASSERT( node.GetNextAttrName(nameBuffer) == B_ENTRY_NOT_FOUND ); + // rewind, get one attribute, rewind again and iterate through the whole + // list again + CPPUNIT_ASSERT( node.RewindAttrs() == B_OK ); + testSet.rewind(); + CPPUNIT_ASSERT( node.GetNextAttrName(nameBuffer) == B_OK ); + CPPUNIT_ASSERT( testSet.test(nameBuffer) == true ); + CPPUNIT_ASSERT( node.RewindAttrs() == B_OK ); + testSet.rewind(); + while (node.GetNextAttrName(nameBuffer) == B_OK) + CPPUNIT_ASSERT( testSet.test(nameBuffer) == true ); + CPPUNIT_ASSERT( testSet.testDone() == true ); + CPPUNIT_ASSERT( node.GetNextAttrName(nameBuffer) == B_ENTRY_NOT_FOUND ); + // bad args + CPPUNIT_ASSERT( node.RewindAttrs() == B_OK ); + testSet.rewind(); +// R5: crashs, if passing a NULL buffer +#if !SK_TEST_R5 + CPPUNIT_ASSERT( node.GetNextAttrName(NULL) == B_BAD_VALUE ); +#endif +} + +// AttrDirTest +void +NodeTest::AttrDirTest() +{ + // uninitialized objects + nextSubTest(); + TestNodes testEntries; + CreateUninitializedNodes(testEntries); + BNode *node; + string nodeName; + for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) { + char nameBuffer[B_ATTR_NAME_LENGTH]; + CPPUNIT_ASSERT( node->RewindAttrs() != B_OK ); + CPPUNIT_ASSERT( node->GetNextAttrName(nameBuffer) != B_OK ); + } + testEntries.delete_all(); + // existing entries + nextSubTest(); + CreateRWNodes(testEntries); + for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) { + AttrDirTest(*node); + } + testEntries.delete_all(); +} + +// AttrTest +void +NodeTest::AttrTest(BNode &node) +{ + // add some attributes + const char *attrNames[] = { + "attr1", "attr2", "attr3", "attr4", "attr5" + }; + const char *attrValues[] = { + "value1", "value2", "value3", "value4", "value5" + }; + const char *newAttrValues[] = { + "fd", "kkgkjsdhfgkjhsd", "lihuhuh", "", "alkfgnakdfjgn" + }; + int32 attrCount = sizeof(attrNames) / sizeof(const char *); + WriteAttributes(node, attrNames, attrValues, attrCount); + char buffer[1024]; + // read and check them + for (int32 i = 0; i < attrCount; i++) { + const char *attrName = attrNames[i]; + const char *attrValue = attrValues[i]; + int32 valueSize = strlen(attrValue) + 1; + CPPUNIT_ASSERT( node.ReadAttr(attrName, B_STRING_TYPE, 0, buffer, + sizeof(buffer)) == valueSize ); + CPPUNIT_ASSERT( strcmp(buffer, attrValue) == 0 ); + } + // write a new value for each attribute + WriteAttributes(node, attrNames, newAttrValues, attrCount); + // read and check them + for (int32 i = 0; i < attrCount; i++) { + const char *attrName = attrNames[i]; + const char *attrValue = newAttrValues[i]; + int32 valueSize = strlen(attrValue) + 1; + CPPUNIT_ASSERT( node.ReadAttr(attrName, B_STRING_TYPE, 0, buffer, + sizeof(buffer)) == valueSize ); + CPPUNIT_ASSERT( strcmp(buffer, attrValue) == 0 ); + } + // bad args + CPPUNIT_ASSERT( equals(node.ReadAttr(NULL, B_STRING_TYPE, 0, buffer, + sizeof(buffer)), + B_BAD_ADDRESS, B_BAD_VALUE) ); + CPPUNIT_ASSERT( equals(node.ReadAttr(attrNames[0], B_STRING_TYPE, 0, NULL, + sizeof(buffer)), + B_BAD_ADDRESS, B_BAD_VALUE) ); + CPPUNIT_ASSERT( equals(node.ReadAttr(NULL, B_STRING_TYPE, 0, NULL, + sizeof(buffer)), + B_BAD_ADDRESS, B_BAD_VALUE) ); + CPPUNIT_ASSERT( equals(node.WriteAttr(NULL, B_STRING_TYPE, 0, buffer, + sizeof(buffer)), + B_BAD_ADDRESS, B_BAD_VALUE) ); + CPPUNIT_ASSERT( equals(node.WriteAttr(attrNames[0], B_STRING_TYPE, 0, NULL, + sizeof(buffer)), + B_BAD_ADDRESS, B_BAD_VALUE) ); + CPPUNIT_ASSERT( equals(node.WriteAttr(NULL, B_STRING_TYPE, 0, NULL, + sizeof(buffer)), + B_BAD_ADDRESS, B_BAD_VALUE) ); + CPPUNIT_ASSERT( equals(node.RemoveAttr(NULL), B_BAD_ADDRESS, B_BAD_VALUE) ); + // too long attribute name +// R5: Read/RemoveAttr() do not return B_NAME_TOO_LONG, but B_ENTRY_NOT_FOUND +// R5: WriteAttr() does not return B_NAME_TOO_LONG, but B_BAD_VALUE + char tooLongAttrName[B_ATTR_NAME_LENGTH + 1]; + memset(tooLongAttrName, 'a', B_ATTR_NAME_LENGTH); + tooLongAttrName[B_ATTR_NAME_LENGTH + 1] = 0; + CPPUNIT_ASSERT( node.WriteAttr(tooLongAttrName, B_STRING_TYPE, 0, buffer, + sizeof(buffer)) == B_BAD_VALUE ); + CPPUNIT_ASSERT( node.ReadAttr(tooLongAttrName, B_STRING_TYPE, 0, buffer, + sizeof(buffer)) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( node.RemoveAttr(tooLongAttrName) == B_ENTRY_NOT_FOUND ); + // remove the attributes and try to read them + for (int32 i = 0; i < attrCount; i++) { + const char *attrName = attrNames[i]; + CPPUNIT_ASSERT( node.RemoveAttr(attrName) == B_OK ); + CPPUNIT_ASSERT( node.ReadAttr(attrName, B_STRING_TYPE, 0, buffer, + sizeof(buffer)) == B_ENTRY_NOT_FOUND ); + } + // try to remove a non-existing attribute + CPPUNIT_ASSERT( node.RemoveAttr("non existing attribute") + == B_ENTRY_NOT_FOUND ); +} + +// AttrTest +void +NodeTest::AttrTest() +{ + // uninitialized objects + nextSubTest(); + TestNodes testEntries; + CreateUninitializedNodes(testEntries); + BNode *node; + string nodeName; + for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) { + char buffer[1024]; + CPPUNIT_ASSERT( node->ReadAttr("attr1", B_STRING_TYPE, 0, buffer, + sizeof(buffer)) == B_FILE_ERROR ); + CPPUNIT_ASSERT( node->WriteAttr("attr1", B_STRING_TYPE, 0, buffer, + sizeof(buffer)) == B_FILE_ERROR ); + CPPUNIT_ASSERT( node->RemoveAttr("attr1") == B_FILE_ERROR ); + } + testEntries.delete_all(); + // existing entries + nextSubTest(); + CreateRWNodes(testEntries); + for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) { + AttrTest(*node); + } + testEntries.delete_all(); +} + +// AttrRenameTest +void +NodeTest::AttrRenameTest(BNode &node) +{ +#if !SK_TEST_R5 + const char attr1[] = "StorageKit::SomeAttribute"; + const char attr2[] = "StorageKit::AnotherAttribute"; + const char str[] = "This is my testing string and it rules your world."; + const int strLen = strlen(str) + 1; + const int dataLen = 1024; + char data[dataLen]; + + node.SetTo("./"); + + // Test the case of the first attribute not existing + node.RemoveAttr(attr1); + CPPUNIT_ASSERT( node.RenameAttr(attr1, attr2) == B_BAD_VALUE ); + + // Write an attribute, read it to verify it, rename it, read the + // new attribute, read the old (which fails), and then remove the new. + CPPUNIT_ASSERT( node.WriteAttr(attr1, B_STRING_TYPE, 0, str, strLen) == strLen ); + CPPUNIT_ASSERT( node.ReadAttr(attr1, B_STRING_TYPE, 0, data, dataLen) == strLen ); + CPPUNIT_ASSERT( strcmp(data, str) == 0 ); + CPPUNIT_ASSERT( node.RenameAttr(attr1, attr2) == B_OK ); // <<< This fails with R5::BNode + CPPUNIT_ASSERT( node.ReadAttr(attr1, B_STRING_TYPE, 0, data, dataLen) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( node.ReadAttr(attr2, B_STRING_TYPE, 0, data, dataLen) == strLen ); + CPPUNIT_ASSERT( strcmp(data, str) == 0 ); + CPPUNIT_ASSERT( node.RemoveAttr(attr2) == B_OK ); + + // bad args + CPPUNIT_ASSERT( equals(node.RenameAttr(attr1, NULL), B_BAD_ADDRESS, + B_BAD_VALUE) ); + CPPUNIT_ASSERT( equals(node.RenameAttr(NULL, attr2), B_BAD_ADDRESS, + B_BAD_VALUE) ); + CPPUNIT_ASSERT( equals(node.RenameAttr(NULL, NULL), B_BAD_ADDRESS, + B_BAD_VALUE) ); + // too long attribute name +// R5: RenameAttr() returns B_BAD_VALUE instead of B_NAME_TOO_LONG + char tooLongAttrName[B_ATTR_NAME_LENGTH + 1]; + memset(tooLongAttrName, 'a', B_ATTR_NAME_LENGTH); + tooLongAttrName[B_ATTR_NAME_LENGTH + 1] = 0; + CPPUNIT_ASSERT( node.RenameAttr(attr1, tooLongAttrName) + == B_BAD_VALUE ); + CPPUNIT_ASSERT( node.RenameAttr(tooLongAttrName, attr1) + == B_BAD_VALUE ); +#endif +} + + +// AttrRenameTest +void +NodeTest::AttrRenameTest() +{ + // uninitialized objects + nextSubTest(); + TestNodes testEntries; + CreateUninitializedNodes(testEntries); + BNode *node; + string nodeName; + for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) { + CPPUNIT_ASSERT( node->RenameAttr("attr1", "attr2") == B_FILE_ERROR ); + } + testEntries.delete_all(); + // existing entries + nextSubTest(); + CreateRWNodes(testEntries); + for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) { + AttrRenameTest(*node); + } + testEntries.delete_all(); +} + +// AttrInfoTest +void +NodeTest::AttrInfoTest(BNode &node) +{ + // add some attributes + const char *attrNames[] = { + "attr1", "attr2", "attr3", "attr4", "attr5" + }; + const int32 attrCount = sizeof(attrNames) / sizeof(const char*); + const char attrValue1[] = "This is the greatest string ever."; + int32 attrValue2 = 17; + uint64 attrValue3 = 42; + double attrValue4 = 435.5; + struct flat_entry_ref { dev_t device; ino_t directory; char name[256]; } + attrValue5 = { 9, 16, "Hello world!" }; + const void *attrValues[] = { + attrValue1, &attrValue2, &attrValue3, &attrValue4, &attrValue5 + }; + attr_info attrInfos[] = { + { B_STRING_TYPE, sizeof(attrValue1) }, + { B_INT32_TYPE, sizeof(attrValue2) }, + { B_UINT64_TYPE, sizeof(attrValue3) }, + { B_DOUBLE_TYPE, sizeof(attrValue4) }, + { B_REF_TYPE, sizeof(attrValue5) } + }; + for (int32 i = 0; i < attrCount; i++) { + const char *attrName = attrNames[i]; + const void *attrValue = attrValues[i]; + int32 valueSize = attrInfos[i].size; + uint32 attrType = attrInfos[i].type; + CPPUNIT_ASSERT( node.WriteAttr(attrName, attrType, 0, attrValue, + valueSize) == valueSize ); + } + // get the attribute infos + for (int32 i = 0; i < attrCount; i++) { + const char *attrName = attrNames[i]; + attr_info info; + CPPUNIT_ASSERT( node.GetAttrInfo(attrName, &info) == B_OK ); + CPPUNIT_ASSERT( info == attrInfos[i] ); + } + // try get an info for a non-existing attribute + attr_info info; + CPPUNIT_ASSERT( node.GetAttrInfo("non-existing attribute", &info) + == B_ENTRY_NOT_FOUND ); + // bad values + CPPUNIT_ASSERT( equals(node.GetAttrInfo(NULL, &info), B_BAD_ADDRESS, + B_BAD_VALUE) ); + CPPUNIT_ASSERT( equals(node.GetAttrInfo(attrNames[0], NULL), B_BAD_ADDRESS, + B_BAD_VALUE) ); + CPPUNIT_ASSERT( equals(node.GetAttrInfo(NULL, NULL), B_BAD_ADDRESS, + B_BAD_VALUE) ); + // too long attribute name +// R5: GetAttrInfo() does not return B_NAME_TOO_LONG + char tooLongAttrName[B_ATTR_NAME_LENGTH + 1]; + memset(tooLongAttrName, 'a', B_ATTR_NAME_LENGTH); + tooLongAttrName[B_ATTR_NAME_LENGTH + 1] = 0; + CPPUNIT_ASSERT( node.GetAttrInfo(tooLongAttrName, &info) + == B_ENTRY_NOT_FOUND ); +} + +// AttrInfoTest +void +NodeTest::AttrInfoTest() +{ + // uninitialized objects + nextSubTest(); + TestNodes testEntries; + CreateUninitializedNodes(testEntries); + BNode *node; + string nodeName; + for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) { + attr_info info; + CPPUNIT_ASSERT( node->GetAttrInfo("attr1", &info) == B_FILE_ERROR ); + } + testEntries.delete_all(); + // existing entries + nextSubTest(); + CreateRWNodes(testEntries); + for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) { + AttrInfoTest(*node); + } + testEntries.delete_all(); +} + +// AttrBStringTest +void +NodeTest::AttrBStringTest(BNode &node) +{ + // add some attributes + const char *attrNames[] = { + "attr1", "attr2", "attr3", "attr4", "attr5" + }; + const char *attrValues[] = { + "value1", "value2", "value3", "value4", "value5" + }; + const char *newAttrValues[] = { + "fd", "kkgkjsdhfgkjhsd", "lihuhuh", "", "alkfgnakdfjgn" + }; + int32 attrCount = sizeof(attrNames) / sizeof(const char *); + for (int32 i = 0; i < attrCount; i++) { + const char *attrName = attrNames[i]; + BString attrValue(attrValues[i]); + CPPUNIT_ASSERT( node.WriteAttrString(attrName, &attrValue) == B_OK ); + } + // read and check them + for (int32 i = 0; i < attrCount; i++) { + const char *attrName = attrNames[i]; + const char *attrValue = attrValues[i]; + BString readValue; + CPPUNIT_ASSERT( node.ReadAttrString(attrName, &readValue) == B_OK ); + CPPUNIT_ASSERT( readValue == attrValue ); + } + // write a new value for each attribute + for (int32 i = 0; i < attrCount; i++) { + const char *attrName = attrNames[i]; + BString attrValue(newAttrValues[i]); + CPPUNIT_ASSERT( node.WriteAttrString(attrName, &attrValue) == B_OK ); + } + // read and check them + for (int32 i = 0; i < attrCount; i++) { + const char *attrName = attrNames[i]; + const char *attrValue = newAttrValues[i]; + BString readValue; + CPPUNIT_ASSERT( node.ReadAttrString(attrName, &readValue) == B_OK ); + CPPUNIT_ASSERT( readValue == attrValue ); + } + // bad args + BString readValue; + BString writeValue("test"); +// R5: crashes, if supplying a NULL BString +#if !SK_TEST_R5 + CPPUNIT_ASSERT( node.WriteAttrString(attrNames[0], NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( node.ReadAttrString(attrNames[0], NULL) == B_BAD_VALUE ); +#endif + CPPUNIT_ASSERT( equals(node.WriteAttrString(NULL, &writeValue), + B_BAD_ADDRESS, B_BAD_VALUE) ); + CPPUNIT_ASSERT( equals(node.ReadAttrString(NULL, &readValue), + B_BAD_ADDRESS, B_BAD_VALUE) ); +#if !SK_TEST_R5 + CPPUNIT_ASSERT( node.WriteAttrString(NULL, NULL) == B_BAD_VALUE ); +#endif + CPPUNIT_ASSERT( equals(node.ReadAttrString(NULL, NULL), + B_BAD_ADDRESS, B_BAD_VALUE) ); + // remove the attributes and try to read them + for (int32 i = 0; i < attrCount; i++) { + const char *attrName = attrNames[i]; + CPPUNIT_ASSERT( node.RemoveAttr(attrName) == B_OK ); + CPPUNIT_ASSERT( node.ReadAttrString(attrName, &readValue) + == B_ENTRY_NOT_FOUND ); + } + // too long attribute name +// R5: Read/WriteAttrString() do not return B_NAME_TOO_LONG + char tooLongAttrName[B_ATTR_NAME_LENGTH + 1]; + memset(tooLongAttrName, 'a', B_ATTR_NAME_LENGTH); + tooLongAttrName[B_ATTR_NAME_LENGTH + 1] = 0; + CPPUNIT_ASSERT( node.WriteAttrString(tooLongAttrName, &writeValue) + == B_BAD_VALUE ); + CPPUNIT_ASSERT( node.ReadAttrString(tooLongAttrName, &readValue) + == B_ENTRY_NOT_FOUND ); +} + +// AttrBStringTest +void +NodeTest::AttrBStringTest() +{ + // uninitialized objects + nextSubTest(); + TestNodes testEntries; + CreateUninitializedNodes(testEntries); + BNode *node; + string nodeName; + for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) { + BString value("test"); + CPPUNIT_ASSERT( node->WriteAttrString("attr1", &value) + == B_FILE_ERROR ); + CPPUNIT_ASSERT( node->ReadAttrString("attr1", &value) + == B_FILE_ERROR ); + } + testEntries.delete_all(); + // existing entries + nextSubTest(); + CreateRWNodes(testEntries); + for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) { + AttrBStringTest(*node); + } + testEntries.delete_all(); +} + +// This doesn't actually verify synching is occuring; just +// checks for a B_OK return value. +void +NodeTest::SyncTest() { + const char attr[] = "StorageKit::SomeAttribute"; + const char str[] = "This string rules your world."; + const int len = strlen(str) + 1; + // uninitialized objects + nextSubTest(); + TestNodes testEntries; + CreateUninitializedNodes(testEntries); + BNode *node; + string nodeName; + for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) { + CPPUNIT_ASSERT( node->Sync() == B_FILE_ERROR ); + } + testEntries.delete_all(); + // existing entries + nextSubTest(); + CreateRWNodes(testEntries); + for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) { + CPPUNIT_ASSERT( node->WriteAttr(attr, B_STRING_TYPE, 0, str, len) + == len ); + CPPUNIT_ASSERT( node->Sync() == B_OK ); + } + testEntries.delete_all(); +} + +// DupTest +void +NodeTest::DupTest(BNode &node) +{ + int fd = node.Dup(); + CPPUNIT_ASSERT( fd != -1 ); + ::close(fd); +} + +// DupTest +void +NodeTest::DupTest() +{ + // uninitialized objects + nextSubTest(); + TestNodes testEntries; + CreateUninitializedNodes(testEntries); + BNode *node; + string nodeName; + for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) { + CPPUNIT_ASSERT( node->Dup() == -1 ); + } + testEntries.delete_all(); + // existing entries + nextSubTest(); + CreateRWNodes(testEntries); + for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) { + DupTest(*node); + } + testEntries.delete_all(); +} + +// n1 and n2 should both be uninitialized. y1a and y1b should be initialized +// to the same node, y2 should be initialized to a different node +void +NodeTest::EqualityTest(BNode &n1, BNode &n2, BNode &y1a, BNode &y1b, BNode &y2) { + CPPUNIT_ASSERT( n1 == n2 ); + CPPUNIT_ASSERT( !(n1 != n2) ); + CPPUNIT_ASSERT( n1 != y2 ); + CPPUNIT_ASSERT( !(n1 == y2) ); + + CPPUNIT_ASSERT( y1a != n2 ); + CPPUNIT_ASSERT( !(y1a == n2) ); + CPPUNIT_ASSERT( y1a == y1b ); + CPPUNIT_ASSERT( !(y1a != y1b) ); + CPPUNIT_ASSERT( y1a != y2 ); + CPPUNIT_ASSERT( !(y1a == y2) ); + + CPPUNIT_ASSERT( n1 == n1 ); + CPPUNIT_ASSERT( !(n1 != n1) ); + CPPUNIT_ASSERT( y2 == y2 ); + CPPUNIT_ASSERT( !(y2 != y2) ); +} + +// EqualityTest +void +NodeTest::EqualityTest() +{ + BNode n1, n2, y1a("/boot"), y1b("/boot"), y2("/"); + + EqualityTest(n1, n2, y1a, y1b, y2); +} + +// AssignmentTest +void +NodeTest::AssignmentTest() +{ + BNode n1, n2, y1a("/boot"), y1b("/boot"), y2("/"); + + n1 = n1; // self n + y1a = y1b; // psuedo self y + y1a = y1a; // self y + n2 = y2; // n = y + y1b = n1; // y = n + y2 = y1a; // y1 = y2 + + EqualityTest(n1, y1b, y1a, y2, n2); +} + +// Locking isn't really implemented yet... +void +NodeTest::LockTest(BNode &node, const char *entryName) +{ + CPPUNIT_ASSERT( node.Lock() == B_OK ); + BNode node2(entryName); + CPPUNIT_ASSERT( node2.InitCheck() == B_BUSY ); + CPPUNIT_ASSERT( node.Unlock() == B_OK ); + CPPUNIT_ASSERT( node.Unlock() == B_BAD_VALUE ); + CPPUNIT_ASSERT( node2.SetTo(entryName) == B_OK ); +// R5: Since two file descriptors exist at this point, locking is supposed +// to fail according to the BeBook, but it succeeds! + CPPUNIT_ASSERT( node2.Lock() == B_OK ); + CPPUNIT_ASSERT( node.Lock() == B_BUSY ); +// + CPPUNIT_ASSERT( node2.Unlock() == B_OK ); +} + +// Locking isn't really implemented yet... +void +NodeTest::LockTest() +{ +#if !SK_TEST_OBOS_POSIX + // uninitialized objects + nextSubTest(); + TestNodes testEntries; + CreateUninitializedNodes(testEntries); + BNode *node; + string nodeName; + for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) { + CPPUNIT_ASSERT( node->Dup() == -1 ); + } + testEntries.delete_all(); + // existing entries + nextSubTest(); + CreateRWNodes(testEntries); + for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) { + LockTest(*node, nodeName.c_str()); + } + testEntries.delete_all(); +#endif +} + +// entry names used in tests +const char *NodeTest::existingFilename = "/tmp/existing-file"; +const char *NodeTest::existingSuperFilename = "/tmp"; +const char *NodeTest::existingRelFilename = "existing-file"; +const char *NodeTest::existingDirname = "/tmp/existing-dir"; +const char *NodeTest::existingSuperDirname = "/tmp"; +const char *NodeTest::existingRelDirname = "existing-dir"; +const char *NodeTest::existingSubDirname + = "/tmp/existing-dir/existing-subdir"; +const char *NodeTest::existingRelSubDirname = "existing-subdir"; +const char *NodeTest::nonExistingFilename = "/tmp/non-existing-file"; +const char *NodeTest::nonExistingDirname = "/tmp/non-existing-dir"; +const char *NodeTest::nonExistingSuperDirname = "/tmp"; +const char *NodeTest::nonExistingRelDirname = "non-existing-dir"; +const char *NodeTest::testFilename1 = "/tmp/test-file1"; +const char *NodeTest::testDirname1 = "/tmp/test-dir1"; +const char *NodeTest::tooLongEntryname = + "/tmp/This is an awfully long name for an entry. It is that kind of entry " + "that just can't exist due to its long name. In fact its path name is not " + "too long -- a path name can contain 1024 characters -- but the name of " + "the entry itself is restricted to 256 characters, which this entry's " + "name does exceed."; +const char *NodeTest::tooLongSuperEntryname = "/tmp"; +const char *NodeTest::tooLongRelEntryname = + "This is an awfully long name for an entry. It is that kind of entry " + "that just can't exist due to its long name. In fact its path name is not " + "too long -- a path name can contain 1024 characters -- but the name of " + "the entry itself is restricted to 256 characters, which this entry's " + "name does exceed."; +const char *NodeTest::fileDirname = "/tmp/test-file1/some-dir"; +const char *NodeTest::fileSuperDirname = "/tmp"; +const char *NodeTest::fileRelDirname = "test-file1/some-dir"; +const char *NodeTest::dirLinkname = "/tmp/link-to-dir1"; +const char *NodeTest::dirSuperLinkname = "/tmp"; +const char *NodeTest::dirRelLinkname = "link-to-dir1"; +const char *NodeTest::fileLinkname = "/tmp/link-to-file1"; +const char *NodeTest::fileSuperLinkname = "/tmp"; +const char *NodeTest::fileRelLinkname = "link-to-file1"; +const char *NodeTest::relDirLinkname = "/tmp/rel-link-to-dir1"; +const char *NodeTest::relFileLinkname = "/tmp/rel-link-to-file1"; +const char *NodeTest::badLinkname = "/tmp/link-to-void"; +const char *NodeTest::cyclicLinkname1 = "/tmp/cyclic-link1"; +const char *NodeTest::cyclicLinkname2 = "/tmp/cyclic-link2"; + +const char *NodeTest::allFilenames[] = { + existingFilename, + existingDirname, + nonExistingFilename, + nonExistingDirname, + testFilename1, + testDirname1, + dirLinkname, + fileLinkname, + relDirLinkname, + relFileLinkname, + badLinkname, + cyclicLinkname1, + cyclicLinkname2, +}; +const int32 NodeTest::allFilenameCount + = sizeof(allFilenames) / sizeof(const char*); + diff --git a/src/tests/kits/storage/NodeTest.h b/src/tests/kits/storage/NodeTest.h new file mode 100644 index 0000000000..e2cc9da4d4 --- /dev/null +++ b/src/tests/kits/storage/NodeTest.h @@ -0,0 +1,124 @@ +// NodeTest.h + +#ifndef __sk_node_test_h__ +#define __sk_node_test_h__ + +#include "StatableTest.h" + +class BNode; + +typedef TestEntries TestNodes; + +class NodeTest : public StatableTest { +public: + static CppUnit::Test* Suite(); + + template + static inline void AddBaseClassTests(const char *prefix, + CppUnit::TestSuite *suite); + + virtual void CreateROStatables(TestStatables& testEntries); + virtual void CreateRWStatables(TestStatables& testEntries); + virtual void CreateUninitializedStatables(TestStatables& testEntries); + + virtual void CreateRONodes(TestNodes& testEntries); + virtual void CreateRWNodes(TestNodes& testEntries); + virtual void CreateUninitializedNodes(TestNodes& testEntries); + + // This function is called before *each* test added in Suite() + void setUp(); + + // This function is called after *each* test added in Suite() + void tearDown(); + + // Tests + void InitTest1(); + void InitTest2(); + void AttrDirTest(); + void AttrTest(); + void AttrRenameTest(); + void AttrInfoTest(); + void AttrBStringTest(); + void DupTest(); + void SyncTest(); + void EqualityTest(); + void AssignmentTest(); + void LockTest(); // Locking isn't implemented for the Posix versions + + // Helper functions + void AttrDirTest(BNode &node); + void AttrTest(BNode &node); + void AttrRenameTest(BNode &node); + void AttrInfoTest(BNode &node); + void AttrBStringTest(BNode &node); + void DupTest(BNode &node); + void LockTest(BNode &node, const char *entryName); + void EqualityTest(BNode &n1, BNode &n2, BNode &y1a, BNode &y1b, BNode &y2); + + // entry names used by this class or derived classes + static const char * existingFilename; + static const char * existingSuperFilename; + static const char * existingRelFilename; + static const char * existingDirname; + static const char * existingSuperDirname; + static const char * existingRelDirname; + static const char * existingSubDirname; + static const char * existingRelSubDirname; + static const char * nonExistingFilename; + static const char * nonExistingDirname; + static const char * nonExistingSuperDirname; + static const char * nonExistingRelDirname; + static const char * testFilename1; + static const char * testDirname1; + static const char * tooLongEntryname; + static const char * tooLongSuperEntryname; + static const char * tooLongRelEntryname; + static const char * fileDirname; + static const char * fileSuperDirname; + static const char * fileRelDirname; + static const char * dirLinkname; + static const char * dirSuperLinkname; + static const char * dirRelLinkname; + static const char * fileLinkname; + static const char * fileSuperLinkname; + static const char * fileRelLinkname; + static const char * relDirLinkname; + static const char * relFileLinkname; + static const char * badLinkname; + static const char * cyclicLinkname1; + static const char * cyclicLinkname2; + + static const char * allFilenames[]; + static const int32 allFilenameCount; +}; + +// AddBaseClassTests +template +inline void +NodeTest::AddBaseClassTests(const char *prefix, CppUnit::TestSuite *suite) +{ + StatableTest::AddBaseClassTests(prefix, suite); + + typedef CppUnit::TestCaller TC; + string p(prefix); + + suite->addTest( new TC(p + "BNode::AttrDir Test", &NodeTest::AttrDirTest) ); + suite->addTest( new TC(p + "BNode::Attr Test", &NodeTest::AttrTest) ); + suite->addTest( new TC(p + "BNode::AttrRename Test" +#if SK_TEST_R5 + " (NOTE: test not actually performed with R5 libraries)" +#endif + , &NodeTest::AttrRenameTest) ); + suite->addTest( new TC(p + "BNode::AttrInfo Test", &NodeTest::AttrInfoTest) ); + suite->addTest( new TC(p + "BNode::AttrBString Test", &NodeTest::AttrBStringTest) ); + suite->addTest( new TC(p + "BNode::Sync Test", &NodeTest::SyncTest) ); + suite->addTest( new TC(p + "BNode::Dup Test", &NodeTest::DupTest) ); + suite->addTest( new TC(p + "BNode::Lock Test" +#if SK_TEST_OBOS_POSIX + " (NOTE: test not actually performed with OpenBeOS Posix libraries)" +#endif + , &NodeTest::LockTest) ); +} + + +#endif // __sk_node_test_h__ diff --git a/src/tests/kits/storage/PathTest.cpp b/src/tests/kits/storage/PathTest.cpp new file mode 100644 index 0000000000..fa4726b1d6 --- /dev/null +++ b/src/tests/kits/storage/PathTest.cpp @@ -0,0 +1,1379 @@ +// PathTest.cpp + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include "Test.StorageKit.h" + +// Suite +CppUnit::Test* +PathTest::Suite() { + CppUnit::TestSuite *suite = new CppUnit::TestSuite(); + typedef CppUnit::TestCaller TC; + + suite->addTest( new TC("BPath::Init Test1", &PathTest::InitTest1) ); + suite->addTest( new TC("BPath::Init Test2", &PathTest::InitTest2) ); + suite->addTest( new TC("BPath::Append Test", &PathTest::AppendTest) ); + suite->addTest( new TC("BPath::Leaf Test", &PathTest::LeafTest) ); + suite->addTest( new TC("BPath::Parent Test", &PathTest::ParentTest) ); + suite->addTest( new TC("BPath::Comparison Test", + &PathTest::ComparisonTest) ); + suite->addTest( new TC("BPath::Assignment Test", + &PathTest::AssignmentTest) ); + suite->addTest( new TC("BPath::Flattenable Test", + &PathTest::FlattenableTest) ); + + return suite; +} + +// setUp +void +PathTest::setUp() +{ + BasicTest::setUp(); +} + +// tearDown +void +PathTest::tearDown() +{ + BasicTest::tearDown(); +} + +// InitTest1 +void +PathTest::InitTest1() +{ + // 1. default constructor + nextSubTest(); + { + BPath path; + CPPUNIT_ASSERT( path.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( path.Path() == NULL ); + } + + // 2. BPath(const char*, const char*, bool) + // absolute existing path (root dir), no leaf, no normalization + nextSubTest(); + { + const char *pathName = "/"; + BPath path(pathName); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(pathName) == path.Path() ); + } + // absolute existing path, no leaf, no normalization + nextSubTest(); + { + const char *pathName = "/boot"; + BPath path(pathName); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(pathName) == path.Path() ); + } + // absolute non-existing path, no leaf, no normalization + nextSubTest(); + { + const char *pathName = "/doesn't/exist/but/who/cares"; + BPath path(pathName); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(pathName) == path.Path() ); + } + // absolute existing path (root dir), no leaf, auto normalization + nextSubTest(); + { + const char *pathName = "/.///."; + const char *normalizedPathName = "/"; + BPath path(pathName); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(normalizedPathName) == path.Path() ); + } + // absolute existing path, no leaf, auto normalization + nextSubTest(); + { + const char *pathName = "/boot/"; + const char *normalizedPathName = "/boot"; + BPath path(pathName); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(normalizedPathName) == path.Path() ); + } + // absolute non-existing path, no leaf, auto normalization + nextSubTest(); + { + const char *pathName = "/doesn't/exist/but///who/cares"; + BPath path(pathName); + CPPUNIT_ASSERT( path.InitCheck() == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( path.Path() == NULL ); + } + // absolute existing path (root dir), no leaf, normalization forced + nextSubTest(); + { + const char *pathName = "/"; + BPath path(pathName, NULL, true); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(pathName) == path.Path() ); + } + // absolute existing path, no leaf, normalization forced + nextSubTest(); + { + const char *pathName = "/boot"; + BPath path(pathName, NULL, true); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(pathName) == path.Path() ); + } + // absolute non-existing path, no leaf, normalization forced + nextSubTest(); + { + const char *pathName = "/doesn't/exist/but/who/cares"; + BPath path(pathName, NULL, true); + CPPUNIT_ASSERT( path.InitCheck() == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( path.Path() == NULL ); + } + // relative existing path, no leaf, no normalization needed, but done + chdir("/"); + nextSubTest(); + { + const char *pathName = "boot"; + const char *absolutePathName = "/boot"; + BPath path(pathName); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(absolutePathName) == path.Path() ); + } + // relative non-existing path, no leaf, no normalization needed, but done + chdir("/boot"); + nextSubTest(); + { + const char *pathName = "doesn't/exist/but/who/cares"; + BPath path(pathName); + CPPUNIT_ASSERT( path.InitCheck() == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( path.Path() == NULL ); + } + // relative existing path, no leaf, auto normalization + chdir("/"); + nextSubTest(); + { + const char *pathName = "boot/"; + const char *normalizedPathName = "/boot"; + BPath path(pathName); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(normalizedPathName) == path.Path() ); + } + // relative non-existing path, no leaf, auto normalization + chdir("/boot"); + nextSubTest(); + { + const char *pathName = "doesn't/exist/but///who/cares"; + BPath path(pathName); + CPPUNIT_ASSERT( path.InitCheck() == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( path.Path() == NULL ); + } + // relative existing path, no leaf, normalization forced + chdir("/"); + nextSubTest(); + { + const char *pathName = "boot"; + const char *absolutePathName = "/boot"; + BPath path(pathName, NULL, true); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(absolutePathName) == path.Path() ); + } + // relative non-existing path, no leaf, normalization forced + chdir("/boot"); + nextSubTest(); + { + const char *pathName = "doesn't/exist/but/who/cares"; + BPath path(pathName, NULL, true); + CPPUNIT_ASSERT( path.InitCheck() == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( path.Path() == NULL ); + } + // absolute existing path (root dir), leaf, no normalization + nextSubTest(); + { + const char *pathName = "/"; + const char *leafName = "boot"; + const char *absolutePathName = "/boot"; + BPath path(pathName, leafName); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(absolutePathName) == path.Path() ); + } + // absolute existing path, leaf, no normalization + nextSubTest(); + { + const char *pathName = "/boot"; + const char *leafName = "home/Desktop"; + const char *absolutePathName = "/boot/home/Desktop"; + BPath path(pathName, leafName); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(absolutePathName) == path.Path() ); + } + // absolute non-existing path, leaf, no normalization + nextSubTest(); + { + const char *pathName = "/doesn't/exist"; + const char *leafName = "but/who/cares"; + const char *absolutePathName = "/doesn't/exist/but/who/cares"; + BPath path(pathName, leafName); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(absolutePathName) == path.Path() ); + } + // absolute existing path (root dir), leaf, auto normalization + nextSubTest(); + { + const char *pathName = "/.///"; + const char *leafName = "."; + const char *absolutePathName = "/"; + BPath path(pathName, leafName); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(absolutePathName) == path.Path() ); + } + // absolute existing path, leaf, auto normalization + nextSubTest(); + { + const char *pathName = "/boot"; + const char *leafName = "home/.."; + const char *absolutePathName = "/boot"; + BPath path(pathName, leafName); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(absolutePathName) == path.Path() ); + } + // absolute non-existing path, leaf, auto normalization + nextSubTest(); + { + const char *pathName = "/doesn't/exist"; + const char *leafName = "but//who/cares"; + BPath path(pathName, leafName); + CPPUNIT_ASSERT( path.InitCheck() == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( path.Path() == NULL ); + } + // absolute non-existing path, leaf, normalization forced + nextSubTest(); + { + const char *pathName = "/doesn't/exist"; + const char *leafName = "but/who/cares"; + BPath path(pathName, leafName, true); + CPPUNIT_ASSERT( path.InitCheck() == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( path.Path() == NULL ); + } + // relative existing path, leaf, no normalization needed, but done + chdir("/"); + nextSubTest(); + { + const char *pathName = "boot"; + const char *leafName = "home"; + const char *absolutePathName = "/boot/home"; + BPath path(pathName, leafName); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(absolutePathName) == path.Path() ); + } + // relative non-existing path, leaf, no normalization needed, but done + chdir("/boot"); + nextSubTest(); + { + const char *pathName = "doesn't/exist"; + const char *leafName = "but/who/cares"; + BPath path(pathName, leafName); + CPPUNIT_ASSERT( path.InitCheck() == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( path.Path() == NULL ); + } + // relative existing path, leaf, auto normalization + chdir("/boot"); + nextSubTest(); + { + const char *pathName = "home"; + const char *leafName = "Desktop//"; + const char *normalizedPathName = "/boot/home/Desktop"; + BPath path(pathName, leafName); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(normalizedPathName) == path.Path() ); + } + // bad args (absolute lead) + nextSubTest(); + { + const char *pathName = "/"; + const char *leafName = "/boot"; + BPath path(pathName, leafName); + CPPUNIT_ASSERT( path.InitCheck() == B_BAD_VALUE ); + CPPUNIT_ASSERT( path.Path() == NULL ); + } + // bad args + nextSubTest(); + { + BPath path((const char*)NULL, "test"); + CPPUNIT_ASSERT( path.InitCheck() == B_BAD_VALUE ); + CPPUNIT_ASSERT( path.Path() == NULL ); + } + // bad args + nextSubTest(); + { + BPath path((const char*)NULL); + CPPUNIT_ASSERT( path.InitCheck() == B_BAD_VALUE ); + CPPUNIT_ASSERT( path.Path() == NULL ); + } + + // 3. BPath(const BDirectory*, const char*, bool) + // existing dir (root dir), no leaf, no normalization + nextSubTest(); + { + const char *pathName = "/"; + BDirectory dir(pathName); + BPath path(&dir, NULL); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(pathName) == path.Path() ); + } + // existing dir, no leaf, no normalization + nextSubTest(); + { + const char *pathName = "/boot"; + BDirectory dir(pathName); + BPath path(&dir, NULL); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(pathName) == path.Path() ); + } + // existing dir (root dir), no leaf, normalization forced + nextSubTest(); + { + const char *pathName = "/"; + BDirectory dir(pathName); + BPath path(&dir, NULL, true); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(pathName) == path.Path() ); + } + // existing dir, no leaf, normalization forced + nextSubTest(); + { + const char *pathName = "/boot"; + BDirectory dir(pathName); + BPath path(&dir, NULL, true); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(pathName) == path.Path() ); + } + // existing dir (root dir), leaf, no normalization + nextSubTest(); + { + const char *pathName = "/"; + const char *leafName = "boot"; + const char *absolutePathName = "/boot"; + BDirectory dir(pathName); + BPath path(&dir, leafName); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(absolutePathName) == path.Path() ); + } + // existing dir, leaf, no normalization + nextSubTest(); + { + const char *pathName = "/boot"; + const char *leafName = "home/Desktop"; + const char *absolutePathName = "/boot/home/Desktop"; + BDirectory dir(pathName); + BPath path(&dir, leafName); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(absolutePathName) == path.Path() ); + } + // existing dir, leaf, auto normalization + nextSubTest(); + { + const char *pathName = "/boot"; + const char *leafName = "home/.."; + const char *absolutePathName = "/boot"; + BDirectory dir(pathName); + BPath path(&dir, leafName); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(absolutePathName) == path.Path() ); + } + // bad args (absolute leaf) + nextSubTest(); + { + const char *pathName = "/"; + const char *leafName = "/boot"; + BDirectory dir(pathName); + BPath path(&dir, leafName); + CPPUNIT_ASSERT( path.InitCheck() == B_BAD_VALUE ); + CPPUNIT_ASSERT( path.Path() == NULL ); + } + // bad args (uninitialized dir) + nextSubTest(); + { + BDirectory dir; + BPath path(&dir, "test"); + CPPUNIT_ASSERT( path.InitCheck() == B_BAD_VALUE ); + CPPUNIT_ASSERT( path.Path() == NULL ); + } + // bad args (badly initialized dir) + nextSubTest(); + { + BDirectory dir("/this/dir/doesn't/exists"); + BPath path(&dir, "test"); + CPPUNIT_ASSERT( path.InitCheck() == B_BAD_VALUE ); + CPPUNIT_ASSERT( path.Path() == NULL ); + } + // bad args (NULL dir) +// R5: crashs, when passing a NULL BDirectory +#if !SK_TEST_R5 + nextSubTest(); + { + BPath path((const BDirectory*)NULL, "test"); + CPPUNIT_ASSERT( path.InitCheck() == B_BAD_VALUE ); + CPPUNIT_ASSERT( path.Path() == NULL ); + } + // bad args (NULL dir) + nextSubTest(); + { + BPath path((const BDirectory*)NULL, NULL); + CPPUNIT_ASSERT( path.InitCheck() == B_BAD_VALUE ); + CPPUNIT_ASSERT( path.Path() == NULL ); + } +#endif + + // 4. BPath(const BEntry*) + // existing entry (root dir) + nextSubTest(); + { + const char *pathName = "/"; + BEntry entry(pathName); + BPath path(&entry); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(pathName) == path.Path() ); + } + // existing entry + nextSubTest(); + { + const char *pathName = "/boot"; + BEntry entry(pathName); + BPath path(&entry); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(pathName) == path.Path() ); + } + // abstract entry + nextSubTest(); + { + const char *pathName = "/boot/shouldn't exist"; + BEntry entry(pathName); + BPath path(&entry); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(pathName) == path.Path() ); + } + // bad args (uninitialized BEntry) + nextSubTest(); + { + BEntry entry; + BPath path(&entry); + CPPUNIT_ASSERT( path.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( path.Path() == NULL ); + } + // bad args (badly initialized BEntry) + nextSubTest(); + { + BEntry entry("/this/doesn't/exist"); + BPath path(&entry); + CPPUNIT_ASSERT( equals(path.InitCheck(), B_NO_INIT, B_ENTRY_NOT_FOUND) ); + CPPUNIT_ASSERT( path.Path() == NULL ); + } + // bad args (NULL BEntry) + nextSubTest(); + { + BPath path((const BEntry*)NULL); + CPPUNIT_ASSERT( equals(path.InitCheck(), B_NO_INIT, B_BAD_VALUE) ); + CPPUNIT_ASSERT( path.Path() == NULL ); + } + + // 5. BPath(const entry_ref*) + // existing entry (root dir) + nextSubTest(); + { + const char *pathName = "/"; + BEntry entry(pathName); + entry_ref ref; + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + BPath path(&ref); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(pathName) == path.Path() ); + } + // existing entry + nextSubTest(); + { + const char *pathName = "/boot"; + BEntry entry(pathName); + entry_ref ref; + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + BPath path(&ref); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(pathName) == path.Path() ); + } + // abstract entry + nextSubTest(); + { + const char *pathName = "/boot/shouldn't exist"; + BEntry entry(pathName); + entry_ref ref; + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + BPath path(&ref); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(pathName) == path.Path() ); + } + // bad args (NULL entry_ref) + nextSubTest(); + { + BPath path((const entry_ref*)NULL); + CPPUNIT_ASSERT( equals(path.InitCheck(), B_NO_INIT, B_BAD_VALUE) ); + CPPUNIT_ASSERT( path.Path() == NULL ); + } +} + +// InitTest2 +void +PathTest::InitTest2() +{ + BPath path; + const char *pathName; + const char *leafName; + const char *absolutePathName; + const char *normalizedPathName; + BDirectory dir; + BEntry entry; + entry_ref ref; + + // 2. SetTo(const char*, const char*, bool) + // absolute existing path (root dir), no leaf, no normalization + nextSubTest(); + pathName = "/"; + CPPUNIT_ASSERT( path.SetTo(pathName) == B_OK ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(pathName) == path.Path() ); + path.Unset(); + // absolute existing path, no leaf, no normalization + nextSubTest(); + pathName = "/boot"; + CPPUNIT_ASSERT( path.SetTo(pathName) == B_OK ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(pathName) == path.Path() ); + path.Unset(); + // absolute non-existing path, no leaf, no normalization + nextSubTest(); + pathName = "/doesn't/exist/but/who/cares"; + CPPUNIT_ASSERT( path.SetTo(pathName) == B_OK ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(pathName) == path.Path() ); + path.Unset(); + // absolute existing path (root dir), no leaf, auto normalization + nextSubTest(); + pathName = "/.///."; + normalizedPathName = "/"; + CPPUNIT_ASSERT( path.SetTo(pathName) == B_OK ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(normalizedPathName) == path.Path() ); + path.Unset(); + // absolute existing path, no leaf, auto normalization + nextSubTest(); + pathName = "/boot/"; + normalizedPathName = "/boot"; + CPPUNIT_ASSERT( path.SetTo(pathName) == B_OK ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(normalizedPathName) == path.Path() ); + path.Unset(); + // absolute non-existing path, no leaf, auto normalization + nextSubTest(); + pathName = "/doesn't/exist/but///who/cares"; + CPPUNIT_ASSERT( path.SetTo(pathName) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( path.InitCheck() == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( path.Path() == NULL ); + path.Unset(); + // absolute existing path (root dir), no leaf, normalization forced + nextSubTest(); + pathName = "/"; + CPPUNIT_ASSERT( path.SetTo(pathName, NULL, true) == B_OK ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(pathName) == path.Path() ); + path.Unset(); + // absolute existing path, no leaf, normalization forced + nextSubTest(); + pathName = "/boot"; + CPPUNIT_ASSERT( path.SetTo(pathName, NULL, true) == B_OK ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(pathName) == path.Path() ); + path.Unset(); + // absolute non-existing path, no leaf, normalization forced + nextSubTest(); + pathName = "/doesn't/exist/but/who/cares"; + CPPUNIT_ASSERT( path.SetTo(pathName, NULL, true) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( path.InitCheck() == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( path.Path() == NULL ); + path.Unset(); + // relative existing path, no leaf, no normalization needed, but done + chdir("/"); + nextSubTest(); + pathName = "boot"; + absolutePathName = "/boot"; + CPPUNIT_ASSERT( path.SetTo(pathName) == B_OK ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(absolutePathName) == path.Path() ); + path.Unset(); + // relative non-existing path, no leaf, no normalization needed, but done + chdir("/boot"); + nextSubTest(); + pathName = "doesn't/exist/but/who/cares"; + absolutePathName = "/boot/doesn't/exist/but/who/cares"; + CPPUNIT_ASSERT( path.SetTo(pathName) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( path.InitCheck() == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( path.Path() == NULL ); + path.Unset(); + // relative existing path, no leaf, auto normalization + chdir("/"); + nextSubTest(); + pathName = "boot/"; + normalizedPathName = "/boot"; + CPPUNIT_ASSERT( path.SetTo(pathName) == B_OK ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(normalizedPathName) == path.Path() ); + path.Unset(); + // relative non-existing path, no leaf, auto normalization + chdir("/boot"); + nextSubTest(); + pathName = "doesn't/exist/but///who/cares"; + CPPUNIT_ASSERT( path.SetTo(pathName) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( path.InitCheck() == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( path.Path() == NULL ); + path.Unset(); + // relative existing path, no leaf, normalization forced + chdir("/"); + nextSubTest(); + pathName = "boot"; + absolutePathName = "/boot"; + CPPUNIT_ASSERT( path.SetTo(pathName, NULL, true) == B_OK ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(absolutePathName) == path.Path() ); + path.Unset(); + // relative non-existing path, no leaf, normalization forced + chdir("/boot"); + nextSubTest(); + pathName = "doesn't/exist/but/who/cares"; + CPPUNIT_ASSERT( path.SetTo(pathName, NULL, true) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( path.InitCheck() == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( path.Path() == NULL ); + path.Unset(); + // absolute existing path (root dir), leaf, no normalization + nextSubTest(); + pathName = "/"; + leafName = "boot"; + absolutePathName = "/boot"; + CPPUNIT_ASSERT( path.SetTo(pathName, leafName) == B_OK ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(absolutePathName) == path.Path() ); + path.Unset(); + // absolute existing path, leaf, no normalization + nextSubTest(); + pathName = "/boot"; + leafName = "home/Desktop"; + absolutePathName = "/boot/home/Desktop"; + CPPUNIT_ASSERT( path.SetTo(pathName, leafName) == B_OK ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(absolutePathName) == path.Path() ); + path.Unset(); + // absolute non-existing path, leaf, no normalization + nextSubTest(); + pathName = "/doesn't/exist"; + leafName = "but/who/cares"; + absolutePathName = "/doesn't/exist/but/who/cares"; + CPPUNIT_ASSERT( path.SetTo(pathName, leafName) == B_OK ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(absolutePathName) == path.Path() ); + path.Unset(); + // absolute existing path (root dir), leaf, auto normalization + nextSubTest(); + pathName = "/.///"; + leafName = "."; + absolutePathName = "/"; + CPPUNIT_ASSERT( path.SetTo(pathName, leafName) == B_OK ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(absolutePathName) == path.Path() ); + path.Unset(); + // absolute existing path, leaf, auto normalization + nextSubTest(); + pathName = "/boot"; + leafName = "home/.."; + absolutePathName = "/boot"; + CPPUNIT_ASSERT( path.SetTo(pathName, leafName) == B_OK ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(absolutePathName) == path.Path() ); + path.Unset(); + // absolute existing path, leaf, self assignment + nextSubTest(); + pathName = "/boot/home"; + leafName = "home/Desktop"; + absolutePathName = "/boot/home/Desktop"; + CPPUNIT_ASSERT( path.SetTo(pathName) == B_OK ); + CPPUNIT_ASSERT( path.SetTo(path.Path(), ".///./") == B_OK ); + CPPUNIT_ASSERT( string(pathName) == path.Path() ); + CPPUNIT_ASSERT( path.SetTo(path.Path(), "..") == B_OK ); + CPPUNIT_ASSERT( string("/boot") == path.Path() ); + CPPUNIT_ASSERT( path.SetTo(path.Path(), leafName) == B_OK ); + CPPUNIT_ASSERT( string(absolutePathName) == path.Path() ); + path.Unset(); + // absolute non-existing path, leaf, auto normalization + nextSubTest(); + pathName = "/doesn't/exist"; + leafName = "but//who/cares"; + CPPUNIT_ASSERT( path.SetTo(pathName, leafName) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( path.InitCheck() == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( path.Path() == NULL ); + path.Unset(); + // absolute non-existing path, leaf, normalization forced + nextSubTest(); + pathName = "/doesn't/exist"; + leafName = "but/who/cares"; + CPPUNIT_ASSERT( path.SetTo(pathName, leafName, true) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( path.InitCheck() == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( path.Path() == NULL ); + path.Unset(); + // relative existing path, leaf, no normalization needed, but done + chdir("/"); + nextSubTest(); + pathName = "boot"; + leafName = "home"; + absolutePathName = "/boot/home"; + CPPUNIT_ASSERT( path.SetTo(pathName, leafName) == B_OK ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(absolutePathName) == path.Path() ); + path.Unset(); + // relative non-existing path, leaf, no normalization needed, but done + chdir("/boot"); + nextSubTest(); + pathName = "doesn't/exist"; + leafName = "but/who/cares"; + CPPUNIT_ASSERT( path.SetTo(pathName, leafName) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( path.InitCheck() == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( path.Path() == NULL ); + path.Unset(); + // relative existing path, leaf, auto normalization + chdir("/boot"); + nextSubTest(); + pathName = "home"; + leafName = "Desktop//"; + normalizedPathName = "/boot/home/Desktop"; + CPPUNIT_ASSERT( path.SetTo(pathName, leafName) == B_OK ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(normalizedPathName) == path.Path() ); + path.Unset(); + // bad args (absolute leaf) + nextSubTest(); + CPPUNIT_ASSERT( path.SetTo("/", "/boot") == B_BAD_VALUE ); + CPPUNIT_ASSERT( path.InitCheck() == B_BAD_VALUE ); + CPPUNIT_ASSERT( path.Path() == NULL ); + path.Unset(); + // bad args + nextSubTest(); + CPPUNIT_ASSERT( path.SetTo((const char*)NULL, "test") == B_BAD_VALUE ); + CPPUNIT_ASSERT( path.InitCheck() == B_BAD_VALUE ); + CPPUNIT_ASSERT( path.Path() == NULL ); + path.Unset(); + // bad args + nextSubTest(); + CPPUNIT_ASSERT( path.SetTo((const char*)NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( path.InitCheck() == B_BAD_VALUE ); + CPPUNIT_ASSERT( path.Path() == NULL ); + path.Unset(); + + // 3. SetTo(const BDirectory*, const char*, bool) + // existing dir (root dir), no leaf, no normalization + nextSubTest(); + pathName = "/"; + CPPUNIT_ASSERT( dir.SetTo(pathName) == B_OK ); + CPPUNIT_ASSERT( path.SetTo(&dir, NULL) == B_OK ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(pathName) == path.Path() ); + path.Unset(); + dir.Unset(); + // existing dir, no leaf, no normalization + nextSubTest(); + pathName = "/boot"; + CPPUNIT_ASSERT( dir.SetTo(pathName) == B_OK ); + CPPUNIT_ASSERT( path.SetTo(&dir, NULL) == B_OK ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(pathName) == path.Path() ); + path.Unset(); + dir.Unset(); + // existing dir (root dir), no leaf, normalization forced + nextSubTest(); + pathName = "/"; + CPPUNIT_ASSERT( dir.SetTo(pathName) == B_OK ); + CPPUNIT_ASSERT( path.SetTo(&dir, NULL, true) == B_OK ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(pathName) == path.Path() ); + path.Unset(); + dir.Unset(); + // existing dir, no leaf, normalization forced + nextSubTest(); + pathName = "/boot"; + CPPUNIT_ASSERT( dir.SetTo(pathName) == B_OK ); + CPPUNIT_ASSERT( path.SetTo(&dir, NULL, true) == B_OK ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(pathName) == path.Path() ); + path.Unset(); + dir.Unset(); + // existing dir (root dir), leaf, no normalization + nextSubTest(); + pathName = "/"; + leafName = "boot"; + absolutePathName = "/boot"; + CPPUNIT_ASSERT( dir.SetTo(pathName) == B_OK ); + CPPUNIT_ASSERT( path.SetTo(&dir, leafName) == B_OK ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(absolutePathName) == path.Path() ); + path.Unset(); + dir.Unset(); + // existing dir, leaf, no normalization + nextSubTest(); + pathName = "/boot"; + leafName = "home/Desktop"; + absolutePathName = "/boot/home/Desktop"; + CPPUNIT_ASSERT( dir.SetTo(pathName) == B_OK ); + CPPUNIT_ASSERT( path.SetTo(&dir, leafName) == B_OK ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(absolutePathName) == path.Path() ); + path.Unset(); + dir.Unset(); + // existing dir, leaf, auto normalization + nextSubTest(); + pathName = "/boot"; + leafName = "home/.."; + absolutePathName = "/boot"; + CPPUNIT_ASSERT( dir.SetTo(pathName) == B_OK ); + CPPUNIT_ASSERT( path.SetTo(&dir, leafName) == B_OK ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(absolutePathName) == path.Path() ); + path.Unset(); + dir.Unset(); + // bad args (absolute leaf) + nextSubTest(); + pathName = "/"; + leafName = "/boot"; + CPPUNIT_ASSERT( dir.SetTo(pathName) == B_OK ); + CPPUNIT_ASSERT( path.SetTo(&dir, leafName) == B_BAD_VALUE ); + CPPUNIT_ASSERT( path.InitCheck() == B_BAD_VALUE ); + CPPUNIT_ASSERT( path.Path() == NULL ); + path.Unset(); + dir.Unset(); + // bad args (uninitialized dir) + nextSubTest(); + CPPUNIT_ASSERT( dir.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( path.SetTo(&dir, "test") == B_BAD_VALUE ); + CPPUNIT_ASSERT( path.InitCheck() == B_BAD_VALUE ); + CPPUNIT_ASSERT( path.Path() == NULL ); + path.Unset(); + dir.Unset(); + // bad args (badly initialized dir) + nextSubTest(); + CPPUNIT_ASSERT( dir.SetTo("/this/dir/doesn't/exists") == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( path.SetTo(&dir, "test") == B_BAD_VALUE ); + CPPUNIT_ASSERT( path.InitCheck() == B_BAD_VALUE ); + CPPUNIT_ASSERT( path.Path() == NULL ); + path.Unset(); + dir.Unset(); +// R5: crashs, when passing a NULL BDirectory +#if !SK_TEST_R5 + // bad args (NULL dir) + nextSubTest(); + CPPUNIT_ASSERT( path.SetTo((const BDirectory*)NULL, "test") == B_BAD_VALUE ); + CPPUNIT_ASSERT( path.InitCheck() == B_BAD_VALUE ); + CPPUNIT_ASSERT( path.Path() == NULL ); + path.Unset(); + dir.Unset(); + // bad args (NULL dir) + nextSubTest(); + CPPUNIT_ASSERT( path.SetTo((const BDirectory*)NULL, NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( path.InitCheck() == B_BAD_VALUE ); + CPPUNIT_ASSERT( path.Path() == NULL ); + path.Unset(); + dir.Unset(); +#endif + + // 4. SetTo(const BEntry*) + // existing entry (root dir) + nextSubTest(); + pathName = "/"; + CPPUNIT_ASSERT( entry.SetTo(pathName) == B_OK ); + CPPUNIT_ASSERT( path.SetTo(&entry) == B_OK ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(pathName) == path.Path() ); + path.Unset(); + entry.Unset(); + // existing entry + nextSubTest(); + pathName = "/boot"; + CPPUNIT_ASSERT( entry.SetTo(pathName) == B_OK ); + CPPUNIT_ASSERT( path.SetTo(&entry) == B_OK ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(pathName) == path.Path() ); + path.Unset(); + entry.Unset(); + // abstract entry + nextSubTest(); + pathName = "/boot/shouldn't exist"; + CPPUNIT_ASSERT( entry.SetTo(pathName) == B_OK ); + CPPUNIT_ASSERT( path.SetTo(&entry) == B_OK ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(pathName) == path.Path() ); + path.Unset(); + entry.Unset(); + // bad args (uninitialized BEntry) + nextSubTest(); + CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( path.SetTo(&entry) == B_NO_INIT ); + CPPUNIT_ASSERT( path.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( path.Path() == NULL ); + path.Unset(); + entry.Unset(); + // bad args (badly initialized BEntry) + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo("/this/doesn't/exist") == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( equals(path.SetTo(&entry), B_NO_INIT, B_ENTRY_NOT_FOUND) ); + CPPUNIT_ASSERT( equals(path.InitCheck(), B_NO_INIT, B_ENTRY_NOT_FOUND) ); + CPPUNIT_ASSERT( path.Path() == NULL ); + path.Unset(); + entry.Unset(); + // bad args (NULL BEntry) + nextSubTest(); + CPPUNIT_ASSERT( equals(path.SetTo((const BEntry*)NULL), B_NO_INIT, + B_BAD_VALUE) ); + CPPUNIT_ASSERT( equals(path.InitCheck(), B_NO_INIT, B_BAD_VALUE) ); + CPPUNIT_ASSERT( path.Path() == NULL ); + path.Unset(); + entry.Unset(); + + // 5. SetTo(const entry_ref*) + // existing entry (root dir) + nextSubTest(); + pathName = "/"; + CPPUNIT_ASSERT( entry.SetTo(pathName) == B_OK ); + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + CPPUNIT_ASSERT( path.SetTo(&ref) == B_OK ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(pathName) == path.Path() ); + path.Unset(); + entry.Unset(); + // existing entry + nextSubTest(); + pathName = "/boot"; + CPPUNIT_ASSERT( entry.SetTo(pathName) == B_OK ); + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + CPPUNIT_ASSERT( path.SetTo(&ref) == B_OK ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(pathName) == path.Path() ); + path.Unset(); + entry.Unset(); + // abstract entry + nextSubTest(); + pathName = "/boot/shouldn't exist"; + CPPUNIT_ASSERT( entry.SetTo(pathName) == B_OK ); + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + CPPUNIT_ASSERT( path.SetTo(&ref) == B_OK ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(pathName) == path.Path() ); + path.Unset(); + entry.Unset(); + // bad args (NULL entry_ref) + nextSubTest(); + CPPUNIT_ASSERT( equals(path.SetTo((const entry_ref*)NULL), B_NO_INIT, + B_BAD_VALUE) ); + CPPUNIT_ASSERT( equals(path.InitCheck(), B_NO_INIT, B_BAD_VALUE) ); + CPPUNIT_ASSERT( path.Path() == NULL ); + path.Unset(); + entry.Unset(); +} + +// AppendTest +void +PathTest::AppendTest() +{ + BPath path; + // uninitialized BPath + nextSubTest(); + CPPUNIT_ASSERT( path.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( path.Append("test") == B_BAD_VALUE ); + CPPUNIT_ASSERT( path.Path() == NULL ); + path.Unset(); + // dir hierarchy, from existing to non-existing + nextSubTest(); + CPPUNIT_ASSERT( path.SetTo("/") == B_OK ); + CPPUNIT_ASSERT( string("/") == path.Path() ); + CPPUNIT_ASSERT( path.Append("boot") == B_OK ); + CPPUNIT_ASSERT( string("/boot") == path.Path() ); + CPPUNIT_ASSERT( path.Append("home/Desktop") == B_OK ); + CPPUNIT_ASSERT( string("/boot/home/Desktop") == path.Path() ); + CPPUNIT_ASSERT( path.Append("non/existing") == B_OK ); + CPPUNIT_ASSERT( string("/boot/home/Desktop/non/existing") == path.Path() ); + // trigger normalization + CPPUNIT_ASSERT( path.Append("at/least/not//now") == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( path.InitCheck() == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( path.Path() == NULL ); + path.Unset(); + // force normalization + nextSubTest(); + CPPUNIT_ASSERT( path.SetTo("/boot") == B_OK ); + CPPUNIT_ASSERT( string("/boot") == path.Path() ); + CPPUNIT_ASSERT( path.Append("home/non-existing", true) == B_OK ); + CPPUNIT_ASSERT( string("/boot/home/non-existing") == path.Path() ); + CPPUNIT_ASSERT( path.Append("not/now", true) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( path.InitCheck() == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( path.Path() == NULL ); + path.Unset(); + // bad/strange args + nextSubTest(); + CPPUNIT_ASSERT( path.SetTo("/boot") == B_OK ); + CPPUNIT_ASSERT( path.Append(NULL) == B_OK ); + CPPUNIT_ASSERT( string("/boot") == path.Path() ); + CPPUNIT_ASSERT( path.SetTo("/boot") == B_OK ); + CPPUNIT_ASSERT( path.Append("/tmp") == B_BAD_VALUE ); + CPPUNIT_ASSERT( path.InitCheck() == B_BAD_VALUE ); + CPPUNIT_ASSERT( path.SetTo("/boot") == B_OK ); + CPPUNIT_ASSERT( path.Append("") == B_OK ); + CPPUNIT_ASSERT( string("/boot") == path.Path() ); + path.Unset(); +} + +// LeafTest +void +PathTest::LeafTest() +{ + BPath path; + // uninitialized BPath + nextSubTest(); + CPPUNIT_ASSERT( path.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( path.Leaf() == NULL ); + path.Unset(); + // root dir + nextSubTest(); + CPPUNIT_ASSERT( path.SetTo("/") == B_OK ); + CPPUNIT_ASSERT( string("") == path.Leaf() ); + path.Unset(); + // existing dirs + nextSubTest(); + CPPUNIT_ASSERT( path.SetTo("/boot") == B_OK ); + CPPUNIT_ASSERT( string("boot") == path.Leaf() ); + CPPUNIT_ASSERT( path.SetTo("/boot/home") == B_OK ); + CPPUNIT_ASSERT( string("home") == path.Leaf() ); + CPPUNIT_ASSERT( path.SetTo("/boot/home/Desktop") == B_OK ); + CPPUNIT_ASSERT( string("Desktop") == path.Leaf() ); + path.Unset(); + // non-existing dirs + nextSubTest(); + CPPUNIT_ASSERT( path.SetTo("/non-existing") == B_OK ); + CPPUNIT_ASSERT( string("non-existing") == path.Leaf() ); + CPPUNIT_ASSERT( path.SetTo("/non/existing/dir") == B_OK ); + CPPUNIT_ASSERT( string("dir") == path.Leaf() ); + path.Unset(); +} + +// ParentTest +void +PathTest::ParentTest() +{ + BPath path; + BPath parent; +// R5: crashs, when GetParent() is called on uninitialized BPath +#if !SK_TEST_R5 + // uninitialized BPath + nextSubTest(); + CPPUNIT_ASSERT( path.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( path.GetParent(&parent) == B_NO_INIT ); + path.Unset(); + parent.Unset(); +#endif + // root dir + nextSubTest(); + CPPUNIT_ASSERT( path.SetTo("/") == B_OK ); + CPPUNIT_ASSERT( path.GetParent(&parent) == B_ENTRY_NOT_FOUND ); + path.Unset(); + parent.Unset(); + // existing dirs + nextSubTest(); + CPPUNIT_ASSERT( path.SetTo("/boot") == B_OK ); + CPPUNIT_ASSERT( path.GetParent(&parent) == B_OK ); + CPPUNIT_ASSERT( string("/") == parent.Path() ); + CPPUNIT_ASSERT( path.SetTo("/boot/home") == B_OK ); + CPPUNIT_ASSERT( path.GetParent(&parent) == B_OK ); + CPPUNIT_ASSERT( string("/boot") == parent.Path() ); + CPPUNIT_ASSERT( path.SetTo("/boot/home/Desktop") == B_OK ); + CPPUNIT_ASSERT( path.GetParent(&parent) == B_OK ); + CPPUNIT_ASSERT( string("/boot/home") == parent.Path() ); + path.Unset(); + parent.Unset(); + // non-existing dirs + nextSubTest(); + CPPUNIT_ASSERT( path.SetTo("/non-existing") == B_OK ); + CPPUNIT_ASSERT( path.GetParent(&parent) == B_OK ); + CPPUNIT_ASSERT( string("/") == parent.Path() ); + CPPUNIT_ASSERT( path.SetTo("/non/existing/dir") == B_OK ); + CPPUNIT_ASSERT( path.GetParent(&parent) == B_OK ); + CPPUNIT_ASSERT( string("/non/existing") == parent.Path() ); + path.Unset(); + parent.Unset(); + // destructive parenting + nextSubTest(); + CPPUNIT_ASSERT( path.SetTo("/non/existing/dir") == B_OK ); + CPPUNIT_ASSERT( path.GetParent(&path) == B_OK ); + CPPUNIT_ASSERT( string("/non/existing") == path.Path() ); + CPPUNIT_ASSERT( path.GetParent(&path) == B_OK ); + CPPUNIT_ASSERT( string("/non") == path.Path() ); + CPPUNIT_ASSERT( path.GetParent(&path) == B_OK ); + CPPUNIT_ASSERT( string("/") == path.Path() ); + CPPUNIT_ASSERT( path.GetParent(&path) == B_ENTRY_NOT_FOUND ); + path.Unset(); + parent.Unset(); +// R5: crashs, when passing a NULL BPath +#if !SK_TEST_R5 + // bad args + nextSubTest(); + CPPUNIT_ASSERT( path.SetTo("/non/existing/dir") == B_OK ); + CPPUNIT_ASSERT( path.GetParent(NULL) == B_BAD_VALUE ); + path.Unset(); + parent.Unset(); +#endif +} + +// ComparisonTest +void +PathTest::ComparisonTest() +{ + BPath path; + // 1. ==/!= const BPath & + BPath path2; + // uninitialized BPaths +// R5: uninitialized paths are unequal + nextSubTest(); + CPPUNIT_ASSERT( path.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( path2.InitCheck() == B_NO_INIT ); +#if !SK_TEST_R5 + CPPUNIT_ASSERT( (path == path2) == true ); + CPPUNIT_ASSERT( (path != path2) == false ); +#endif + path.Unset(); + path2.Unset(); + // uninitialized argument BPath + nextSubTest(); + CPPUNIT_ASSERT( path.SetTo("/") == B_OK ); + CPPUNIT_ASSERT( path2.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( (path == path2) == false ); + CPPUNIT_ASSERT( (path != path2) == true ); + path.Unset(); + path2.Unset(); + // uninitialized this BPath + nextSubTest(); + CPPUNIT_ASSERT( path.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( path2.SetTo("/") == B_OK ); + CPPUNIT_ASSERT( (path == path2) == false ); + CPPUNIT_ASSERT( (path != path2) == true ); + path.Unset(); + path2.Unset(); + // various paths + nextSubTest(); + const char *paths[] = { "/", "/boot", "/boot/home", "/boot/home/Desktop" }; + int32 pathCount = sizeof(paths) / sizeof(const char*); + for (int32 i = 0; i < pathCount; i++) { + for (int32 k = 0; k < pathCount; k++) { + CPPUNIT_ASSERT( path.SetTo(paths[i]) == B_OK ); + CPPUNIT_ASSERT( path2.SetTo(paths[k]) == B_OK ); + CPPUNIT_ASSERT( (path == path2) == (i == k) ); + CPPUNIT_ASSERT( (path != path2) == (i != k) ); + } + } + path.Unset(); + path2.Unset(); + + // 2. ==/!= const char * + const char *pathName; + // uninitialized BPath + nextSubTest(); + CPPUNIT_ASSERT( path.InitCheck() == B_NO_INIT ); + pathName = "/"; + CPPUNIT_ASSERT( (path == pathName) == false ); + CPPUNIT_ASSERT( (path != pathName) == true ); + path.Unset(); + // various paths + nextSubTest(); + for (int32 i = 0; i < pathCount; i++) { + for (int32 k = 0; k < pathCount; k++) { + CPPUNIT_ASSERT( path.SetTo(paths[i]) == B_OK ); + pathName = paths[k]; + CPPUNIT_ASSERT( (path == pathName) == (i == k) ); + CPPUNIT_ASSERT( (path != pathName) == (i != k) ); + } + } + path.Unset(); + // bad args (NULL const char*) +// R5: initialized path equals NULL argument! +// R5: uninitialized path does not equal NULL argument! + nextSubTest(); + CPPUNIT_ASSERT( path.SetTo("/") == B_OK ); + pathName = NULL; +#if !SK_TEST_R5 + CPPUNIT_ASSERT( (path == pathName) == false ); + CPPUNIT_ASSERT( (path != pathName) == true ); +#endif + path.Unset(); + CPPUNIT_ASSERT( path.InitCheck() == B_NO_INIT ); +#if !SK_TEST_R5 + CPPUNIT_ASSERT( (path == pathName) == true ); + CPPUNIT_ASSERT( (path != pathName) == false ); +#endif + path.Unset(); +} + +// AssignmentTest +void +PathTest::AssignmentTest() +{ + // 1. copy constructor + // uninitialized + nextSubTest(); + { + BPath path; + CPPUNIT_ASSERT( path.InitCheck() == B_NO_INIT ); + BPath path2(path); + CPPUNIT_ASSERT( path2.InitCheck() == B_NO_INIT ); + } + // initialized + nextSubTest(); + { + BPath path("/boot/home/Desktop"); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + BPath path2(path); + CPPUNIT_ASSERT( path2.InitCheck() == B_OK ); + CPPUNIT_ASSERT( path == path2 ); + } + + // 2. assignment operator, const BPath & + // uninitialized + nextSubTest(); + { + BPath path; + BPath path2; + path2 = path; + CPPUNIT_ASSERT( path.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( path2.InitCheck() == B_NO_INIT ); + } + nextSubTest(); + { + BPath path; + BPath path2("/"); + CPPUNIT_ASSERT( path2.InitCheck() == B_OK ); + path2 = path; + CPPUNIT_ASSERT( path.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( path2.InitCheck() == B_NO_INIT ); + } + // initialized + nextSubTest(); + { + BPath path("/boot/home"); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + BPath path2; + path2 = path; + CPPUNIT_ASSERT( path2.InitCheck() == B_OK ); + CPPUNIT_ASSERT( path == path2 ); + } + + // 2. assignment operator, const char * + // initialized + nextSubTest(); + { + const char *pathName = "/boot/home"; + BPath path2; + path2 = pathName; + CPPUNIT_ASSERT( path2.InitCheck() == B_OK ); + CPPUNIT_ASSERT( path2 == pathName ); + } + // bad args + nextSubTest(); + { + const char *pathName = NULL; + BPath path2; + path2 = pathName; + CPPUNIT_ASSERT( path2.InitCheck() == B_NO_INIT ); + } +} + +// FlattenableTest +void +PathTest::FlattenableTest() +{ + BPath path; + // 1. trivial methods (IsFixedSize(), TypeCode(), AllowsTypeCode) + // uninitialized + nextSubTest(); + CPPUNIT_ASSERT( path.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( path.IsFixedSize() == false ); + CPPUNIT_ASSERT( path.TypeCode() == B_REF_TYPE ); + CPPUNIT_ASSERT( path.AllowsTypeCode(B_REF_TYPE) == true ); + CPPUNIT_ASSERT( path.AllowsTypeCode(B_STRING_TYPE) == false ); + CPPUNIT_ASSERT( path.AllowsTypeCode(B_FLOAT_TYPE) == false ); + path.Unset(); + // initialized + nextSubTest(); + CPPUNIT_ASSERT( path.SetTo("/boot/home") == B_OK ); + CPPUNIT_ASSERT( path.IsFixedSize() == false ); + CPPUNIT_ASSERT( path.TypeCode() == B_REF_TYPE ); + CPPUNIT_ASSERT( path.AllowsTypeCode(B_REF_TYPE) == true ); + CPPUNIT_ASSERT( path.AllowsTypeCode(B_STRING_TYPE) == false ); + CPPUNIT_ASSERT( path.AllowsTypeCode(B_FLOAT_TYPE) == false ); + path.Unset(); + + // 2. non-trivial methods + char buffer[1024]; + // uninitialized + nextSubTest(); + CPPUNIT_ASSERT( path.InitCheck() == B_NO_INIT ); + ssize_t size = path.FlattenedSize(); + CPPUNIT_ASSERT( size == sizeof(dev_t) + sizeof(ino_t) ); + CPPUNIT_ASSERT( path.Flatten(buffer, sizeof(buffer)) == B_OK ); + CPPUNIT_ASSERT( path.Unflatten(B_REF_TYPE, buffer, size) == B_OK ); + CPPUNIT_ASSERT( path.InitCheck() == B_NO_INIT ); + path.Unset(); + // some flatten/unflatten tests + nextSubTest(); + const char *paths[] = { "/", "/boot", "/boot/home", "/boot/home/Desktop", + "/boot/home/non-existing" }; + int32 pathCount = sizeof(paths) / sizeof(const char*); + for (int32 i = 0; i < pathCount; i++) { + const char *pathName = paths[i]; + // init the path and get an equivalent entry ref + CPPUNIT_ASSERT( path.SetTo(pathName) == B_OK ); + BEntry entry; + CPPUNIT_ASSERT( entry.SetTo(pathName) == B_OK ); + entry_ref ref; + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + // flatten the path + struct flattened_ref { dev_t device; ino_t directory; char name[1]; }; + size = path.FlattenedSize(); + int32 expectedSize // hehe, that's hacky ;-) + = (int32)((flattened_ref*)NULL)->name + strlen(ref.name) + 1; + CPPUNIT_ASSERT( size == expectedSize); + CPPUNIT_ASSERT( path.Flatten(buffer, sizeof(buffer)) == B_OK ); + // check the flattened data + const flattened_ref &fref = *(flattened_ref*)buffer; + CPPUNIT_ASSERT( ref.device == fref.device ); + CPPUNIT_ASSERT( ref.directory == fref.directory ); + CPPUNIT_ASSERT( strcmp(ref.name, fref.name) == 0 ); + // unflatten the path + path.Unset(); + CPPUNIT_ASSERT( path.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( path.Unflatten(B_REF_TYPE, buffer, size) == B_OK ); + CPPUNIT_ASSERT( path == pathName ); + path.Unset(); + } + // bad args + nextSubTest(); +// R5: crashs, when passing a NULL buffer +// R5: doesn't check the buffer size + CPPUNIT_ASSERT( path.SetTo("/boot/home") == B_OK ); +#if !SK_TEST_R5 + CPPUNIT_ASSERT( path.Flatten(NULL, sizeof(buffer)) == B_BAD_VALUE ); + CPPUNIT_ASSERT( path.Flatten(buffer, path.FlattenedSize() - 2) + == B_BAD_VALUE ); +#endif + path.Unset(); +} + diff --git a/src/tests/kits/storage/PathTest.h b/src/tests/kits/storage/PathTest.h new file mode 100644 index 0000000000..30565d57e8 --- /dev/null +++ b/src/tests/kits/storage/PathTest.h @@ -0,0 +1,38 @@ +// PathTest.h + +#ifndef __sk_path_test_h__ +#define __sk_path_test_h__ + +#include +#include + +#include +#include + +#include "BasicTest.h" + +class PathTest : public BasicTest +{ +public: + static CppUnit::Test* Suite(); + + // This function called before *each* test added in Suite() + void setUp(); + + // This function called after *each* test added in Suite() + void tearDown(); + + //------------------------------------------------------------ + // Test functions + //------------------------------------------------------------ + void InitTest1(); + void InitTest2(); + void AppendTest(); + void LeafTest(); + void ParentTest(); + void ComparisonTest(); + void AssignmentTest(); + void FlattenableTest(); +}; + +#endif // __sk_path_test_h__ diff --git a/src/tests/kits/storage/QueryTest.cpp b/src/tests/kits/storage/QueryTest.cpp new file mode 100644 index 0000000000..a038d5fe37 --- /dev/null +++ b/src/tests/kits/storage/QueryTest.cpp @@ -0,0 +1,1463 @@ +// QueryTest.cpp + +#include +#include +#include +#include +#include + +#include "QueryTest.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Test.StorageKit.h" +#include "TestApp.h" +#include "TestUtils.h" + +// Query + +class Query : public BQuery { +public: +#if SK_TEST_R5 + status_t PushValue(int32 value) { PushInt32(value); return B_OK; } + status_t PushValue(uint32 value) { PushUInt32(value); return B_OK; } + status_t PushValue(int64 value) { PushInt64(value); return B_OK; } + status_t PushValue(uint64 value) { PushUInt64(value); return B_OK; } + status_t PushValue(float value) { PushFloat(value); return B_OK; } + status_t PushValue(double value) { PushDouble(value); return B_OK; } + status_t PushValue(const BString value, bool caseInsensitive = false) + { + PushString(value.String(), caseInsensitive); return B_OK; + } + status_t PushAttr(const char *attribute) + { + BQuery::PushAttr(attribute); + return B_OK; + } + status_t PushOp(query_op op) + { + BQuery::PushOp(op); + return B_OK; + } +#else + status_t PushValue(int32 value) { return PushInt32(value); } + status_t PushValue(uint32 value) { return PushUInt32(value); } + status_t PushValue(int64 value) { return PushInt64(value); } + status_t PushValue(uint64 value) { return PushUInt64(value); } + status_t PushValue(float value) { return PushFloat(value); } + status_t PushValue(double value) { return PushDouble(value); } + status_t PushValue(const BString value, bool caseInsensitive = false) + { + return PushString(value.String(), caseInsensitive); + } +#endif +}; + + +// PredicateNode + +class PredicateNode { +public: + virtual ~PredicateNode() {} + + virtual status_t push(Query &query) const = 0; + virtual BString toString() const = 0; +}; + + +// ValueNode + +template +class ValueNode : public PredicateNode { +public: + ValueNode(ValueType v) : value(v) {} + + virtual ~ValueNode() {} + + virtual status_t push(Query &query) const + { + return query.PushValue(value); + } + + virtual BString toString() const + { + return BString() << value; + } + + ValueType value; +}; + +// float specialization +BString +ValueNode::toString() const +{ + char buffer[32]; + sprintf(buffer, "0x%08lx", *(int32*)&value); + return BString() << buffer; +} + +// double specialization +BString +ValueNode::toString() const +{ + char buffer[32]; + sprintf(buffer, "0x%016Lx", *(int64*)&value); + return BString() << buffer; +} + +// StringNode + +class StringNode : public PredicateNode { +public: + StringNode(BString v, bool caseInsensitive = false) + : value(v), caseInsensitive(caseInsensitive) + { + } + + virtual ~StringNode() {} + + virtual status_t push(Query &query) const + { + return query.PushValue(value, caseInsensitive); + } + + virtual BString toString() const + { + BString escaped; + if (caseInsensitive) { + const char *str = value.String(); + int32 len = value.Length(); + for (int32 i = 0; i < len; i++) { + char c = str[i]; + if (isalpha(c)) { + int lower = tolower(c); + int upper = toupper(c); + if (lower < 0 || upper < 0) + escaped << c; + else + escaped << "[" << (char)lower << (char)upper << "]"; + } else + escaped << c; + } + } else + escaped = value; + escaped.CharacterEscape("\"\\'", '\\'); + return BString("\"") << escaped << "\""; + } + + BString value; + bool caseInsensitive; +}; + + +// DateNode + +class DateNode : public PredicateNode { +public: + DateNode(BString v) : value(v) {} + + virtual ~DateNode() {} + + virtual status_t push(Query &query) const + { + return query.PushDate(value.String()); + } + + virtual BString toString() const + { + BString escaped(value); + escaped.CharacterEscape("%\"\\'", '\\'); + return BString("%") << escaped << "%"; + } + + BString value; +}; + + +// AttributeNode + +class AttributeNode : public PredicateNode { +public: + AttributeNode(BString v) : value(v) {} + + virtual ~AttributeNode() {} + + virtual status_t push(Query &query) const + { + return query.PushAttr(value.String()); + } + + virtual BString toString() const + { + return value; + } + + BString value; +}; + + +// short hands +typedef ValueNode Int32Node; +typedef ValueNode UInt32Node; +typedef ValueNode Int64Node; +typedef ValueNode UInt64Node; +typedef ValueNode FloatNode; +typedef ValueNode DoubleNode; + + +// ListNode + +class ListNode : public PredicateNode { +public: + ListNode(PredicateNode *child1 = NULL, PredicateNode *child2 = NULL, + PredicateNode *child3 = NULL, PredicateNode *child4 = NULL, + PredicateNode *child5 = NULL, PredicateNode *child6 = NULL) + : children() + { + addChild(child1); + addChild(child2); + addChild(child3); + addChild(child4); + addChild(child5); + addChild(child6); + } + + virtual ~ListNode() + { + for (int32 i = 0; PredicateNode *child = childAt(i); i++) + delete child; + } + + virtual status_t push(Query &query) const + { + status_t error = B_OK; + for (int32 i = 0; PredicateNode *child = childAt(i); i++) { + error = child->push(query); + if (error != B_OK) + break; + } + return error; + } + + virtual BString toString() const + { + return BString("INVALID"); + } + + ListNode &addChild(PredicateNode *child) + { + if (child) + children.AddItem(child); + return *this; + } + + PredicateNode *childAt(int32 index) const + { + return (PredicateNode*)children.ItemAt(index); + } + + BList children; +}; + +// OpNode + +class OpNode : public ListNode { +public: + OpNode(query_op op, PredicateNode *left, PredicateNode *right = NULL) + : ListNode(left, right), op(op) {} + + virtual ~OpNode() { } + + virtual status_t push(Query &query) const + { + status_t error = ListNode::push(query); + if (error == B_OK) + error = query.PushOp(op); + return error; + } + + virtual BString toString() const + { + PredicateNode *left = childAt(0); + PredicateNode *right = childAt(1); + if (!left) + return "INVALID ARGS"; + BString result; + BString leftString = left->toString(); + BString rightString; + if (right) + rightString = right->toString(); + switch (op) { + case B_INVALID_OP: + result = "INVALID"; + break; + case B_EQ: + result << "(" << leftString << "==" << rightString << ")"; + break; + case B_GT: + result << "(" << leftString << ">" << rightString << ")"; + break; + case B_GE: + result << "(" << leftString << ">=" << rightString << ")"; + break; + case B_LT: + result << "(" << leftString << "<" << rightString << ")"; + break; + case B_LE: + result << "(" << leftString << "<=" << rightString << ")"; + break; + case B_NE: + result << "(" << leftString << "!=" << rightString << ")"; + break; + case B_CONTAINS: + { + StringNode *strNode = dynamic_cast(right); + if (strNode) { + rightString = StringNode(BString("*") << strNode->value + << "*").toString(); + } + result << "(" << leftString << "==" << rightString << ")"; + break; + } + case B_BEGINS_WITH: + { + StringNode *strNode = dynamic_cast(right); + if (strNode) { + rightString = StringNode(BString(strNode->value) << "*") + .toString(); + } + result << "(" << leftString << "==" << rightString << ")"; + break; + } + case B_ENDS_WITH: + { + StringNode *strNode = dynamic_cast(right); + if (strNode) { + rightString = StringNode(BString("*") << strNode->value) + .toString(); + } + result << "(" << leftString << "==" << rightString << ")"; + break; + } + case B_AND: + result << "(" << leftString << "&&" << rightString << ")"; + break; + case B_OR: + result << "(" << leftString << "||" << rightString << ")"; + break; + case B_NOT: + result << "(" << "!" << leftString << ")"; + break; + case _B_RESERVED_OP_: + result = "RESERVED"; + break; + } + return result; + } + + query_op op; +}; + + +// QueryTestEntry +class QueryTestEntry { +public: + QueryTestEntry(string path, node_flavor kind, + const QueryTestEntry *linkTarget = NULL) + : path(path), + cpath(NULL), + kind(kind), + linkToPath(), + clinkToPath(NULL), + directory(-1), + node(-1), + name() + { + cpath = this->path.c_str(); + if (linkTarget) + linkToPath = linkTarget->path; + clinkToPath = this->linkToPath.c_str(); + } + + string operator+(string leaf) const + { + return path + "/" + leaf; + } + + string path; + const char *cpath; + node_flavor kind; + string linkToPath; + const char *clinkToPath; + ino_t directory; + ino_t node; + string name; +}; + +static const char *testVolumeImage = "/tmp/query-test-image"; +static const char *testMountPoint = "/non-existing-mount-point"; + +// the test entry hierarchy: +// mountPoint +// + dir1 +// + subdir11 +// + subdir12 +// + file11 +// + file12 +// + link11 +// + dir2 +// + subdir21 +// + subdir22 +// + subdir23 +// + file21 +// + file22 +// + link21 +// + dir3 +// + subdir31 +// + subdir32 +// + file31 +// + file32 +// + link31 +// + file1 +// + file2 +// + file3 +// + link1 +// + link2 +// + link3 +static QueryTestEntry mountPoint(testMountPoint, B_DIRECTORY_NODE); +static QueryTestEntry dir1(mountPoint + "dir1", B_DIRECTORY_NODE); +static QueryTestEntry subdir11(dir1 + "subdir11", B_DIRECTORY_NODE); +static QueryTestEntry subdir12(dir1 + "subdir12", B_DIRECTORY_NODE); +static QueryTestEntry file11(dir1 + "file11", B_FILE_NODE); +static QueryTestEntry file12(dir1 + "file12", B_FILE_NODE); +static QueryTestEntry link11(dir1 + "link11", B_SYMLINK_NODE, &file11); +static QueryTestEntry dir2(mountPoint + "dir2", B_DIRECTORY_NODE); +static QueryTestEntry subdir21(dir2 + "subdir21", B_DIRECTORY_NODE); +static QueryTestEntry subdir22(dir2 + "subdir22", B_DIRECTORY_NODE); +static QueryTestEntry subdir23(dir2 + "subdir23", B_DIRECTORY_NODE); +static QueryTestEntry file21(dir2 + "file21", B_FILE_NODE); +static QueryTestEntry file22(dir2 + "file22", B_FILE_NODE); +static QueryTestEntry link21(dir2 + "link21", B_SYMLINK_NODE, &file12); +static QueryTestEntry dir3(mountPoint + "dir3", B_DIRECTORY_NODE); +static QueryTestEntry subdir31(dir3 + "subdir31", B_DIRECTORY_NODE); +static QueryTestEntry subdir32(dir3 + "subdir32", B_DIRECTORY_NODE); +static QueryTestEntry file31(dir3 + "file31", B_FILE_NODE); +static QueryTestEntry file32(dir3 + "file32", B_FILE_NODE); +static QueryTestEntry link31(dir3 + "link31", B_SYMLINK_NODE, &file22); +static QueryTestEntry file1(mountPoint + "file1", B_FILE_NODE); +static QueryTestEntry file2(mountPoint + "file2", B_FILE_NODE); +static QueryTestEntry file3(mountPoint + "file3", B_FILE_NODE); +static QueryTestEntry link1(mountPoint + "link1", B_SYMLINK_NODE, &file1); +static QueryTestEntry link2(mountPoint + "link2", B_SYMLINK_NODE, &file2); +static QueryTestEntry link3(mountPoint + "link3", B_SYMLINK_NODE, &file3); + +static QueryTestEntry *allTestEntries[] = { + &dir1, &subdir11, &subdir12, &file11, &file12, &link11, + &dir2, &subdir21, &subdir22, &subdir23, &file21, &file22, &link21, + &dir3, &subdir31, &subdir32, &file31, &file32, &link31, + &file1, &file2, &file3, &link1, &link2, &link3 +}; +static const int32 allTestEntryCount + = sizeof(allTestEntries) / sizeof(QueryTestEntry*); + +// create_test_entries +void +create_test_entries(QueryTestEntry **testEntries, int32 count) +{ + // create the command line + string cmdLine("true"); + for (int32 i = 0; i < count; i++) { + const QueryTestEntry *entry = testEntries[i]; + switch (entry->kind) { + case B_DIRECTORY_NODE: + cmdLine += " ; mkdir " + entry->path; + break; + case B_FILE_NODE: + cmdLine += " ; touch " + entry->path; + break; + case B_SYMLINK_NODE: + cmdLine += " ; ln -s " + entry->linkToPath + " " + entry->path; + break; + case B_ANY_NODE: + default: + printf("WARNING: invalid node kind\n"); + break; + } + } + BasicTest::execCommand(cmdLine); +} + +// delete_test_entries +void +delete_test_entries(QueryTestEntry **testEntries, int32 count) +{ + // create the command line + string cmdLine("true"); + for (int32 i = 0; i < count; i++) { + const QueryTestEntry *entry = testEntries[i]; + switch (entry->kind) { + case B_DIRECTORY_NODE: + case B_FILE_NODE: + case B_SYMLINK_NODE: + cmdLine += " ; rm -rf " + entry->path; + break; + case B_ANY_NODE: + default: + printf("WARNING: invalid node kind\n"); + break; + } + } + BasicTest::execCommand(cmdLine); +} + + + + +// QueryTest + +// Suite +CppUnit::Test* +QueryTest::Suite() { + CppUnit::TestSuite *suite = new CppUnit::TestSuite(); + typedef CppUnit::TestCaller TC; + + suite->addTest( new TC("BQuery::Predicate Test", + &QueryTest::PredicateTest) ); + suite->addTest( new TC("BQuery::Parameter Test", + &QueryTest::ParameterTest) ); + suite->addTest( new TC("BQuery::Fetch Test", &QueryTest::FetchTest) ); + suite->addTest( new TC("BQuery::Live Test", &QueryTest::LiveTest) ); + + return suite; +} + +// setUp +void +QueryTest::setUp() +{ + BasicTest::setUp(); + fApplication = new TestApp("application/x-vnd.obos.query-test"); + if (fApplication->Init() != B_OK) { + fprintf(stderr, "Failed to initialize application.\n"); + delete fApplication; + fApplication = NULL; + } + fVolumeCreated = false; +} + +// tearDown +void +QueryTest::tearDown() +{ + BasicTest::tearDown(); + if (fApplication) { + fApplication->Terminate(); + delete fApplication; + fApplication = NULL; + } + if (fVolumeCreated) { + deleteVolume(testVolumeImage, testMountPoint); + fVolumeCreated = false; + } +} + +// TestPredicate +static +void +TestPredicate(const PredicateNode &predicateNode, status_t pushResult = B_OK, + status_t getResult = B_OK) +{ + BString predicateString = predicateNode.toString().String(); +//printf("predicate: `%s'\n", predicateString.String()); + // GetPredicate(BString *) + { + Query query; +// CPPUNIT_ASSERT( predicateNode.push(query) == pushResult ); +status_t error = predicateNode.push(query); +if (error != pushResult) { +printf("predicate: `%s'\n", predicateString.String()); +printf("error: %lx vs %lx\n", error, pushResult); +} +CPPUNIT_ASSERT( error == pushResult ); + if (pushResult == B_OK) { + BString predicate; +// CPPUNIT_ASSERT( query.GetPredicate(&predicate) == getResult ); +error = query.GetPredicate(&predicate); +if (error != getResult) { +printf("predicate: `%s'\n", predicateString.String()); +printf("error: %lx vs %lx\n", error, getResult); +} +CPPUNIT_ASSERT( error == getResult ); + if (getResult == B_OK) { + CPPUNIT_ASSERT( (int32)query.PredicateLength() + == predicateString.Length() + 1 ); + CPPUNIT_ASSERT( predicateString == predicate ); + } + } + } + // GetPredicate(char *, size_t) + { + Query query; + CPPUNIT_ASSERT( predicateNode.push(query) == pushResult ); + if (pushResult == B_OK) { + char buffer[1024]; + CPPUNIT_ASSERT( query.GetPredicate(buffer, sizeof(buffer)) + == getResult ); + if (getResult == B_OK) + CPPUNIT_ASSERT( predicateString == buffer ); + } + } + // PredicateLength() + { + Query query; + CPPUNIT_ASSERT( predicateNode.push(query) == pushResult ); + if (pushResult == B_OK) { + size_t expectedLength + = (getResult == B_OK ? predicateString.Length() + 1 : 0); + CPPUNIT_ASSERT( query.PredicateLength() == expectedLength ); + } + } + // SetPredicate() + { + Query query; + CPPUNIT_ASSERT( query.SetPredicate(predicateString.String()) == B_OK ); + CPPUNIT_ASSERT( (int32)query.PredicateLength() + == predicateString.Length() + 1 ); + BString predicate; + CPPUNIT_ASSERT( query.GetPredicate(&predicate) == B_OK ); + CPPUNIT_ASSERT( predicateString == predicate ); + } +} + +// TestOperator +static +void +TestOperator(query_op op) +{ + // well formed + TestPredicate(OpNode(op, + new AttributeNode("attribute"), + new Int32Node(42) + )); + TestPredicate(OpNode(op, + new AttributeNode("attribute"), + new StringNode("some string") + )); + TestPredicate(OpNode(op, + new AttributeNode("attribute"), + new DateNode("22 May 2002") + )); + // ill formed + TestPredicate(OpNode(op, new AttributeNode("attribute"), NULL), B_OK, + B_NO_INIT); +// R5: crashs when pushing B_CONTAINS/B_BEGINS/ENDS_WITH on an empty stack +#if SK_TEST_R5 +if (op < B_CONTAINS || op > B_ENDS_WITH) +#endif + TestPredicate(OpNode(op, NULL, NULL), B_OK, B_NO_INIT); + TestPredicate(OpNode(op, + new AttributeNode("attribute"), + new DateNode("22 May 2002") + ).addChild(new Int32Node(42)), B_OK, B_NO_INIT); +} + +// PredicateTest +void +QueryTest::PredicateTest() +{ + // tests: + // * Push*() + // * Set/GetPredicate(), PredicateLength() + // empty predicate + nextSubTest(); + char buffer[1024]; + { + Query query; + BString predicate; + CPPUNIT_ASSERT( query.GetPredicate(&predicate) == B_NO_INIT ); + } + { + Query query; + CPPUNIT_ASSERT( query.GetPredicate(buffer, sizeof(buffer)) + == B_NO_INIT ); + } + // one element predicates + nextSubTest(); + TestPredicate(Int32Node(42)); + TestPredicate(UInt32Node(42)); + TestPredicate(Int64Node(42)); +// R5: buggy PushUInt64() implementation. +#if !SK_TEST_R5 + TestPredicate(UInt64Node(42)); +#endif + TestPredicate(FloatNode(42)); + TestPredicate(DoubleNode(42)); + TestPredicate(StringNode("some \" chars ' to \\ be ( escaped ) or " + "% not!")); + TestPredicate(StringNode("some \" chars ' to \\ be ( escaped ) or " + "% not!", true)); + TestPredicate(DateNode("+15 min")); + TestPredicate(DateNode("22 May 2002")); + TestPredicate(DateNode("tomorrow")); + TestPredicate(DateNode("17:57")); + TestPredicate(DateNode("invalid date"), B_BAD_VALUE); + TestPredicate(AttributeNode("some attribute")); + // operators + nextSubTest(); + TestOperator(B_EQ); + TestOperator(B_GT); + TestOperator(B_GE); + TestOperator(B_LT); + TestOperator(B_LE); + TestOperator(B_NE); + TestOperator(B_CONTAINS); + TestOperator(B_BEGINS_WITH); + TestOperator(B_ENDS_WITH); + TestOperator(B_AND); + TestOperator(B_OR); + { + // B_NOT + TestPredicate(OpNode(B_NOT, new AttributeNode("attribute"))); + TestPredicate(OpNode(B_NOT, new Int32Node(42))); + TestPredicate(OpNode(B_NOT, new StringNode("some string"))); + TestPredicate(OpNode(B_NOT, new StringNode("some string", true))); + TestPredicate(OpNode(B_NOT, new DateNode("22 May 2002"))); + TestPredicate(OpNode(B_NOT, NULL), B_OK, B_NO_INIT); + } + // well formed, legal predicate + nextSubTest(); + TestPredicate(OpNode(B_AND, + new OpNode(B_CONTAINS, + new AttributeNode("attribute"), + new StringNode("hello") + ), + new OpNode(B_OR, + new OpNode(B_NOT, + new OpNode(B_EQ, + new AttributeNode("attribute2"), + new UInt32Node(7) + ), + NULL + ), + new OpNode(B_GE, + new AttributeNode("attribute3"), + new DateNode("20 May 2002") + ) + ) + )); + // well formed, illegal predicate + nextSubTest(); + TestPredicate(OpNode(B_EQ, + new StringNode("hello"), + new OpNode(B_LE, + new OpNode(B_NOT, + new Int32Node(17), + NULL + ), + new DateNode("20 May 2002") + ) + )); + // ill formed predicates + // Some have already been tested in TestOperator, so we only test a few + // special ones. + nextSubTest(); + TestPredicate(ListNode(new Int32Node(42), new StringNode("hello!")), + B_OK, B_NO_INIT); + TestPredicate(OpNode(B_EQ, + new StringNode("hello"), + new OpNode(B_NOT, NULL) + ), B_OK, B_NO_INIT); + // precedence Push*() over SetPredicate() + nextSubTest(); + { + Query query; + OpNode predicate1(B_CONTAINS, + new AttributeNode("attribute"), + new StringNode("hello") + ); + StringNode predicate2("I'm the loser. :´-("); + CPPUNIT_ASSERT( predicate1.push(query) == B_OK ); + CPPUNIT_ASSERT( query.SetPredicate(predicate2.toString().String()) + == B_OK ); + BString predicate; + CPPUNIT_ASSERT( query.GetPredicate(&predicate) == B_OK ); + CPPUNIT_ASSERT( predicate == predicate1.toString() ); + } + // GetPredicate() clears the stack + nextSubTest(); + { + Query query; + OpNode predicate1(B_CONTAINS, + new AttributeNode("attribute"), + new StringNode("hello") + ); + StringNode predicate2("I'm the winner. :-)"); + CPPUNIT_ASSERT( predicate1.push(query) == B_OK ); + BString predicate; + CPPUNIT_ASSERT( query.GetPredicate(&predicate) == B_OK ); + CPPUNIT_ASSERT( predicate == predicate1.toString() ); + CPPUNIT_ASSERT( query.SetPredicate(predicate2.toString().String()) + == B_OK ); + CPPUNIT_ASSERT( query.GetPredicate(&predicate) == B_OK ); + CPPUNIT_ASSERT( predicate == predicate2.toString() ); + } + // PredicateLength() clears the stack + nextSubTest(); + { + Query query; + OpNode predicate1(B_CONTAINS, + new AttributeNode("attribute"), + new StringNode("hello") + ); + StringNode predicate2("I'm the winner. :-)"); + CPPUNIT_ASSERT( predicate1.push(query) == B_OK ); + CPPUNIT_ASSERT( (int32)query.PredicateLength() + == predicate1.toString().Length() + 1 ); + CPPUNIT_ASSERT( query.SetPredicate(predicate2.toString().String()) + == B_OK ); + BString predicate; + CPPUNIT_ASSERT( query.GetPredicate(&predicate) == B_OK ); + CPPUNIT_ASSERT( predicate == predicate2.toString() ); + } + // SetPredicate(), Push*() fail after Fetch() + nextSubTest(); + { + Query query; + CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"") + == B_OK ); + BVolume volume(dev_for_path("/boot")); + CPPUNIT_ASSERT( volume.InitCheck() == B_OK ); + CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK ); + CPPUNIT_ASSERT( query.Fetch() == B_OK ); + CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExistEither\"") + == B_NOT_ALLOWED ); +// R5: Push*()ing a new predicate does work, though it doesn't make any sense +#if SK_TEST_R5 + CPPUNIT_ASSERT( query.PushDate("20 May 2002") == B_OK ); + CPPUNIT_ASSERT( query.PushValue((int32)42) == B_OK ); + CPPUNIT_ASSERT( query.PushValue((uint32)42) == B_OK ); + CPPUNIT_ASSERT( query.PushValue((int64)42) == B_OK ); + CPPUNIT_ASSERT( query.PushValue((uint64)42) == B_OK ); + CPPUNIT_ASSERT( query.PushValue((float)42) == B_OK ); + CPPUNIT_ASSERT( query.PushValue((double)42) == B_OK ); + CPPUNIT_ASSERT( query.PushValue("hello") == B_OK ); + CPPUNIT_ASSERT( query.PushAttr("attribute") == B_OK ); + CPPUNIT_ASSERT( query.PushOp(B_EQ) == B_OK ); +#else + CPPUNIT_ASSERT( query.PushDate("20 May 2002") == B_NOT_ALLOWED ); + CPPUNIT_ASSERT( query.PushValue((int32)42) == B_NOT_ALLOWED ); + CPPUNIT_ASSERT( query.PushValue((uint32)42) == B_NOT_ALLOWED ); + CPPUNIT_ASSERT( query.PushValue((int64)42) == B_NOT_ALLOWED ); + CPPUNIT_ASSERT( query.PushValue((uint64)42) == B_NOT_ALLOWED ); + CPPUNIT_ASSERT( query.PushValue((float)42) == B_NOT_ALLOWED ); + CPPUNIT_ASSERT( query.PushValue((double)42) == B_NOT_ALLOWED ); + CPPUNIT_ASSERT( query.PushValue("hello") == B_NOT_ALLOWED ); + CPPUNIT_ASSERT( query.PushAttr("attribute") == B_NOT_ALLOWED ); + CPPUNIT_ASSERT( query.PushOp(B_EQ) == B_NOT_ALLOWED ); +#endif + } + // SetPredicate(): bad args +// R5: crashes when passing NULL to Set/GetPredicate() +#if !SK_TEST_R5 + nextSubTest(); + { + Query query; + CPPUNIT_ASSERT( query.SetPredicate(NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( query.SetPredicate("hello") == B_OK ); + CPPUNIT_ASSERT( query.GetPredicate(NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( query.GetPredicate(NULL, 10) == B_BAD_VALUE ); + } +#endif +} + +// ParameterTest +void +QueryTest::ParameterTest() +{ + // tests: + // * SetVolume, TargetDevice() + // * SetTarget(), IsLive() + + // SetVolume(), TargetDevice() + // uninitialized BQuery + nextSubTest(); + { + BQuery query; + CPPUNIT_ASSERT( query.TargetDevice() == B_ERROR ); + } + // NULL volume +// R5: crashs when passing a NULL BVolume +#if !SK_TEST_R5 + nextSubTest(); + { + BQuery query; + CPPUNIT_ASSERT( query.SetVolume(NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( query.TargetDevice() == B_ERROR ); + } +#endif + // invalid volume + nextSubTest(); + { + BQuery query; + BVolume volume(-2); + CPPUNIT_ASSERT( volume.InitCheck() == B_BAD_VALUE ); + CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK ); + CPPUNIT_ASSERT( query.TargetDevice() == B_ERROR ); + } + // valid volume + nextSubTest(); + { + BQuery query; + dev_t device = dev_for_path("/boot"); + BVolume volume(device); + CPPUNIT_ASSERT( volume.InitCheck() == B_OK ); + CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK ); + CPPUNIT_ASSERT( query.TargetDevice() == device ); + } + + // SetTarget(), IsLive() + // uninitialized BQuery + nextSubTest(); + { + BQuery query; + CPPUNIT_ASSERT( query.IsLive() == false ); + } + // uninitialized BMessenger + nextSubTest(); + { + BQuery query; + BMessenger messenger; + CPPUNIT_ASSERT( messenger.IsValid() == false ); + CPPUNIT_ASSERT( query.SetTarget(messenger) == B_BAD_VALUE ); + CPPUNIT_ASSERT( query.IsLive() == false ); + } + // valid BMessenger + nextSubTest(); + { + BQuery query; + BMessenger messenger(&fApplication->Handler()); + CPPUNIT_ASSERT( messenger.IsValid() == true ); + CPPUNIT_ASSERT( query.SetTarget(messenger) == B_OK ); + CPPUNIT_ASSERT( query.IsLive() == true ); + } + + // SetVolume/Target() fail after Fetch() + nextSubTest(); + { + Query query; + CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"") + == B_OK ); + BVolume volume(dev_for_path("/boot")); + CPPUNIT_ASSERT( volume.InitCheck() == B_OK ); + CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK ); + CPPUNIT_ASSERT( query.Fetch() == B_OK ); + CPPUNIT_ASSERT( query.SetVolume(&volume) == B_NOT_ALLOWED ); + BMessenger messenger(&fApplication->Handler()); + CPPUNIT_ASSERT( messenger.IsValid() == true ); + CPPUNIT_ASSERT( query.SetTarget(messenger) == B_NOT_ALLOWED ); + } + + // Fetch() fails without a valid volume set + nextSubTest(); + { + Query query; + CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"") + == B_OK ); + CPPUNIT_ASSERT( query.Fetch() == B_NO_INIT ); + } +} + +// TestFetchPredicateInit +static +void +TestFetchPredicateInit(Query &query, TestSet &testSet, const char *mountPoint, + const char *predicate, QueryTestEntry **entries, + int32 entryCount) +{ + // init the query + CPPUNIT_ASSERT( query.SetPredicate(predicate) == B_OK ); + BVolume volume(dev_for_path(mountPoint)); + CPPUNIT_ASSERT( volume.InitCheck() == B_OK ); + CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK ); + CPPUNIT_ASSERT( query.Fetch() == B_OK ); + // init the test set + testSet.clear(); + for (int32 i = 0; i < entryCount; i++) + testSet.add(entries[i]->path); +} + + +// TestFetchPredicate +static +void +TestFetchPredicate(const char *mountPoint, const char *predicate, + QueryTestEntry **entries, int32 entryCount) +{ + // GetNextEntry() + { + Query query; + TestSet testSet; + TestFetchPredicateInit(query, testSet, mountPoint, predicate, entries, + entryCount); + BEntry entry; + while (query.GetNextEntry(&entry) == B_OK) { + CPPUNIT_ASSERT( query.Rewind() == B_ERROR ); + CPPUNIT_ASSERT( query.CountEntries() == B_ERROR ); + BPath path; + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + CPPUNIT_ASSERT( entry.GetPath(&path) == B_OK ); + CPPUNIT_ASSERT( testSet.test(path.Path()) == true ); + } + CPPUNIT_ASSERT( testSet.testDone() == true ); + CPPUNIT_ASSERT( query.GetNextEntry(&entry) == B_ENTRY_NOT_FOUND ); + } + // GetNextRef() + { + Query query; + TestSet testSet; + TestFetchPredicateInit(query, testSet, mountPoint, predicate, entries, + entryCount); + entry_ref ref; + while (query.GetNextRef(&ref) == B_OK) { + CPPUNIT_ASSERT( query.Rewind() == B_ERROR ); + CPPUNIT_ASSERT( query.CountEntries() == B_ERROR ); + BPath path(&ref); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( testSet.test(path.Path()) == true ); + } + CPPUNIT_ASSERT( testSet.testDone() == true ); + CPPUNIT_ASSERT( query.GetNextRef(&ref) == B_ENTRY_NOT_FOUND ); + } + // GetNextDirents() + { + Query query; + TestSet testSet; + TestFetchPredicateInit(query, testSet, mountPoint, predicate, entries, + entryCount); + size_t bufSize = (sizeof(dirent) + B_FILE_NAME_LENGTH) * 10; + char buffer[bufSize]; + dirent *ents = (dirent *)buffer; + while (query.GetNextDirents(ents, bufSize, 1) == 1) { + CPPUNIT_ASSERT( query.Rewind() == B_ERROR ); + CPPUNIT_ASSERT( query.CountEntries() == B_ERROR ); + entry_ref ref(ents->d_pdev, ents->d_pino, ents->d_name); + BPath path(&ref); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( testSet.test(path.Path()) == true ); + } + CPPUNIT_ASSERT( testSet.testDone() == true ); + CPPUNIT_ASSERT( query.GetNextDirents(ents, bufSize, 1) == 0 ); + } + // interleaving use of the different methods + { + Query query; + TestSet testSet; + TestFetchPredicateInit(query, testSet, mountPoint, predicate, entries, + entryCount); + size_t bufSize = (sizeof(dirent) + B_FILE_NAME_LENGTH) * 10; + char buffer[bufSize]; + dirent *ents = (dirent *)buffer; + entry_ref ref; + BEntry entry; + while (query.GetNextDirents(ents, bufSize, 1) == 1) { + CPPUNIT_ASSERT( query.Rewind() == B_ERROR ); + CPPUNIT_ASSERT( query.CountEntries() == B_ERROR ); + entry_ref entref(ents->d_pdev, ents->d_pino, ents->d_name); + BPath entpath(&entref); + CPPUNIT_ASSERT( entpath.InitCheck() == B_OK ); + CPPUNIT_ASSERT( testSet.test(entpath.Path()) == true ); + if (query.GetNextRef(&ref) == B_OK) { + BPath refpath(&ref); + CPPUNIT_ASSERT( refpath.InitCheck() == B_OK ); + CPPUNIT_ASSERT( testSet.test(refpath.Path()) == true ); + } + if (query.GetNextEntry(&entry) == B_OK) { + BPath path; + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + CPPUNIT_ASSERT( entry.GetPath(&path) == B_OK ); + CPPUNIT_ASSERT( testSet.test(path.Path()) == true ); + } + } + CPPUNIT_ASSERT( query.GetNextEntry(&entry) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( query.GetNextRef(&ref) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( query.GetNextDirents(ents, bufSize, 1) == 0 ); + } +} + +// FetchTest +void +QueryTest::FetchTest() +{ + // tests: + // * Clear()/Fetch() + // * BEntryList interface + + // Fetch() + // uninitialized BQuery + nextSubTest(); + { + Query query; + CPPUNIT_ASSERT( query.Fetch() == B_NO_INIT ); + } + // incompletely initialized BQuery (no predicate) + nextSubTest(); + { + Query query; + BVolume volume(dev_for_path("/boot")); + CPPUNIT_ASSERT( volume.InitCheck() == B_OK ); + CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK ); + CPPUNIT_ASSERT( query.Fetch() == B_NO_INIT ); + } + // incompletely initialized BQuery (no volume) + nextSubTest(); + { + Query query; + CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"") + == B_OK ); + CPPUNIT_ASSERT( query.Fetch() == B_NO_INIT ); + } + // incompletely initialized BQuery (invalid predicate) + nextSubTest(); + { + Query query; + CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"&&") + == B_OK ); + BVolume volume(dev_for_path("/boot")); + CPPUNIT_ASSERT( volume.InitCheck() == B_OK ); + CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK ); + CPPUNIT_ASSERT( query.Fetch() == B_BAD_VALUE ); + } + // initialized BQuery, Fetch() twice + nextSubTest(); + { + Query query; + CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"") + == B_OK ); + BVolume volume(dev_for_path("/boot")); + CPPUNIT_ASSERT( volume.InitCheck() == B_OK ); + CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK ); + CPPUNIT_ASSERT( query.Fetch() == B_OK ); + CPPUNIT_ASSERT( query.Fetch() == B_NOT_ALLOWED ); + } + // initialized BQuery, successful Fetch(), different predicates + createVolume(testVolumeImage, testMountPoint, 2); + fVolumeCreated = true; + create_test_entries(allTestEntries, allTestEntryCount); + // ... all files + nextSubTest(); + { + QueryTestEntry *entries[] = { + &file11, &file12, &file21, &file22, &file31, &file32, &file1, + &file2, &file3 + }; + const int32 entryCount = sizeof(entries) / sizeof(QueryTestEntry*); + TestFetchPredicate(testMountPoint, "name=\"file*\"", entries, + entryCount); + } + // ... all entries containing a "l" + nextSubTest(); + { + QueryTestEntry *entries[] = { + &file11, &file12, &link11, &file21, &file22, &link21, &file31, + &file32, &link31, &file1, &file2, &file3, &link1, &link2, &link3 + }; + const int32 entryCount = sizeof(entries) / sizeof(QueryTestEntry*); + TestFetchPredicate(testMountPoint, "name=\"*l*\"", entries, + entryCount); + } + // ... all entries ending on "2" + nextSubTest(); + { + QueryTestEntry *entries[] = { + &subdir12, &file12, &dir2, &subdir22, &file22, &subdir32, &file32, + &file2, &link2 + }; + const int32 entryCount = sizeof(entries) / sizeof(QueryTestEntry*); + TestFetchPredicate(testMountPoint, "name=\"*2\"", entries, + entryCount); + } + + // Clear() + // uninitialized BQuery + nextSubTest(); + { + Query query; + CPPUNIT_ASSERT( query.Clear() == B_OK ); + } + // initialized BQuery, Fetch(), Clear(), Fetch() + nextSubTest(); + { + Query query; + CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"") + == B_OK ); + BVolume volume(dev_for_path("/boot")); + CPPUNIT_ASSERT( volume.InitCheck() == B_OK ); + CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK ); + CPPUNIT_ASSERT( query.Fetch() == B_OK ); + CPPUNIT_ASSERT( query.Clear() == B_OK ); + CPPUNIT_ASSERT( query.Fetch() == B_NO_INIT ); + } + // initialized BQuery, Fetch(), Clear(), re-init, Fetch() + nextSubTest(); + { + Query query; + CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"") + == B_OK ); + BVolume volume(dev_for_path("/boot")); + CPPUNIT_ASSERT( volume.InitCheck() == B_OK ); + CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK ); + CPPUNIT_ASSERT( query.Fetch() == B_OK ); + CPPUNIT_ASSERT( query.Clear() == B_OK ); + CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"") + == B_OK ); + CPPUNIT_ASSERT( volume.SetTo(dev_for_path("/boot")) == B_OK ); + CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK ); + CPPUNIT_ASSERT( query.Fetch() == B_OK ); + } + + // BEntryList interface: + // empty queries + nextSubTest(); + { + Query query; + CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"") + == B_OK ); + BVolume volume(dev_for_path("/boot")); + CPPUNIT_ASSERT( volume.InitCheck() == B_OK ); + CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK ); + CPPUNIT_ASSERT( query.Fetch() == B_OK ); + BEntry entry; + entry_ref ref; + size_t bufSize = (sizeof(dirent) + B_FILE_NAME_LENGTH) * 10; + char buffer[bufSize]; + dirent *ents = (dirent *)buffer; + CPPUNIT_ASSERT( query.GetNextEntry(&entry) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( query.GetNextRef(&ref) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( query.GetNextDirents(ents, bufSize, 1) == 0 ); + } + // uninitialized queries + nextSubTest(); + { + Query query; + BEntry entry; + entry_ref ref; + size_t bufSize = (sizeof(dirent) + B_FILE_NAME_LENGTH) * 10; + char buffer[bufSize]; + dirent *ents = (dirent *)buffer; + CPPUNIT_ASSERT( query.GetNextEntry(&entry) == B_FILE_ERROR ); + CPPUNIT_ASSERT( query.GetNextRef(&ref) == B_FILE_ERROR ); + CPPUNIT_ASSERT( query.GetNextDirents(ents, bufSize, 1) + == B_FILE_ERROR ); + } + // bad args + nextSubTest(); + { + Query query; + CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"") + == B_OK ); + BVolume volume(dev_for_path("/boot")); + CPPUNIT_ASSERT( volume.InitCheck() == B_OK ); + CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK ); + CPPUNIT_ASSERT( query.Fetch() == B_OK ); + size_t bufSize = (sizeof(dirent) + B_FILE_NAME_LENGTH) * 10; +// R5: crashs when passing a NULL BEntry or entry_ref +#if !SK_TEST_R5 + CPPUNIT_ASSERT( query.GetNextEntry(NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( query.GetNextRef(NULL) == B_BAD_VALUE ); +#endif + CPPUNIT_ASSERT( equals(query.GetNextDirents(NULL, bufSize, 1), + B_BAD_ADDRESS, B_BAD_VALUE) ); + } +} + +// AddLiveEntries +void +QueryTest::AddLiveEntries(QueryTestEntry **entries, int32 entryCount, + QueryTestEntry **queryEntries, int32 queryEntryCount) +{ + create_test_entries(entries, entryCount); + for (int32 i = 0; i < entryCount; i++) { + QueryTestEntry *entry = entries[i]; + BNode node(entry->cpath); + CPPUNIT_ASSERT( node.InitCheck() == B_OK ); + node_ref nref; + CPPUNIT_ASSERT( node.GetNodeRef(&nref) == B_OK ); + entry->node = nref.node; + entry_ref ref; + CPPUNIT_ASSERT( get_ref_for_path(entry->cpath, &ref) == B_OK ); + entry->directory = ref.directory; + entry->name = ref.name; + } + CheckUpdateMessages(B_ENTRY_CREATED, queryEntries, queryEntryCount); +} + +// RemoveLiveEntries +void +QueryTest::RemoveLiveEntries(QueryTestEntry **entries, int32 entryCount, + QueryTestEntry **queryEntries, + int32 queryEntryCount) +{ + delete_test_entries(entries, entryCount); + CheckUpdateMessages(B_ENTRY_REMOVED, queryEntries, queryEntryCount); + for (int32 i = 0; i < entryCount; i++) { + QueryTestEntry *entry = entries[i]; + entry->directory = -1; + entry->node = -1; + entry->name = ""; + } +} + +// CheckUpdateMessages +void +QueryTest::CheckUpdateMessages(uint32 opcode, QueryTestEntry **entries, + int32 entryCount) +{ + + // wait for the messages + snooze(100000); + if (fApplication) { + BMessageQueue &queue = fApplication->Handler().Queue(); + CPPUNIT_ASSERT( queue.Lock() ); + try { + int32 entryNum = 0; + while (BMessage *_message = queue.NextMessage()) { + BMessage message(*_message); + delete _message; + CPPUNIT_ASSERT( entryNum < entryCount ); + QueryTestEntry *entry = entries[entryNum]; + CPPUNIT_ASSERT( message.what == B_QUERY_UPDATE ); + uint32 msgOpcode; + CPPUNIT_ASSERT( message.FindInt32("opcode", (int32*)&msgOpcode) + == B_OK ); + CPPUNIT_ASSERT( msgOpcode == opcode ); + dev_t device; + CPPUNIT_ASSERT( message.FindInt32("device", &device) + == B_OK ); + CPPUNIT_ASSERT( device == dev_for_path(testMountPoint) ); + ino_t directory; + CPPUNIT_ASSERT( message.FindInt64("directory", &directory) + == B_OK ); + CPPUNIT_ASSERT( directory == entry->directory ); + ino_t node; + CPPUNIT_ASSERT( message.FindInt64("node", &node) + == B_OK ); + CPPUNIT_ASSERT( node == entry->node ); + if (opcode == B_ENTRY_CREATED) { + const char *name; + CPPUNIT_ASSERT( message.FindString("name", &name) + == B_OK ); + CPPUNIT_ASSERT( entry->name == name ); + } + entryNum++; + } + CPPUNIT_ASSERT( entryNum == entryCount ); + } catch (CppUnit::Exception exception) { + queue.Unlock(); + throw exception; + } + queue.Unlock(); + } +} + +// LiveTest +void +QueryTest::LiveTest() +{ + // tests: + // * live queries + CPPUNIT_ASSERT( fApplication != NULL ); + createVolume(testVolumeImage, testMountPoint, 2); + fVolumeCreated = true; + create_test_entries(allTestEntries, allTestEntryCount); + BMessenger target(&fApplication->Handler()); + + // empty query, add some files, remove some files + nextSubTest(); + { + Query query; + CPPUNIT_ASSERT( query.SetPredicate("name=\"*Argh\"") + == B_OK ); + BVolume volume(dev_for_path(testMountPoint)); + CPPUNIT_ASSERT( volume.InitCheck() == B_OK ); + CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK ); + CPPUNIT_ASSERT( query.SetTarget(target) == B_OK ); + CPPUNIT_ASSERT( query.Fetch() == B_OK ); + BEntry entry; + CPPUNIT_ASSERT( query.GetNextEntry(&entry) == B_ENTRY_NOT_FOUND ); + // the test entries + QueryTestEntry testDir1(dir1 + "testDirArgh", B_DIRECTORY_NODE); + QueryTestEntry testDir2(dir1 + "testDir2", B_DIRECTORY_NODE); + QueryTestEntry testFile1(subdir21 + "testFileArgh", B_FILE_NODE); + QueryTestEntry testFile2(subdir21 + "testFile2", B_FILE_NODE); + QueryTestEntry testLink1(subdir32 + "testLinkArgh", B_SYMLINK_NODE, + &file11); + QueryTestEntry testLink2(subdir32 + "testLink2", B_SYMLINK_NODE, + &file11); + QueryTestEntry *entries[] = { + &testDir1, &testDir2, &testFile1, &testFile2, + &testLink1, &testLink2 + }; + int32 entryCount = sizeof(entries) / sizeof(QueryTestEntry*); + QueryTestEntry *queryEntries[] = { + &testDir1, &testFile1, &testLink1 + }; + int32 queryEntryCount = sizeof(queryEntries) / sizeof(QueryTestEntry*); + AddLiveEntries(entries, entryCount, queryEntries, queryEntryCount); + RemoveLiveEntries(entries, entryCount, queryEntries, queryEntryCount); + } + // non-empty query, add some files, remove some files + nextSubTest(); + { + Query query; + TestSet testSet; + CPPUNIT_ASSERT( query.SetTarget(target) == B_OK ); + QueryTestEntry *initialEntries[] = { + &file11, &file12, &file21, &file22, &file31, &file32, &file1, + &file2, &file3 + }; + int32 initialEntryCount + = sizeof(initialEntries) / sizeof(QueryTestEntry*); + TestFetchPredicateInit(query, testSet, testMountPoint, + "name=\"*ile*\"", initialEntries, + initialEntryCount); + BEntry entry; + while (query.GetNextEntry(&entry) == B_OK) { + BPath path; + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + CPPUNIT_ASSERT( entry.GetPath(&path) == B_OK ); + CPPUNIT_ASSERT( testSet.test(path.Path()) == true ); + } + CPPUNIT_ASSERT( testSet.testDone() == true ); + CPPUNIT_ASSERT( query.GetNextEntry(&entry) == B_ENTRY_NOT_FOUND ); + // the test entries + QueryTestEntry testDir1(dir1 + "testDir1", B_DIRECTORY_NODE); + QueryTestEntry testDir2(dir1 + "testDir2", B_DIRECTORY_NODE); + QueryTestEntry testFile1(subdir21 + "testFile1", B_FILE_NODE); + QueryTestEntry testFile2(subdir21 + "testFile2", B_FILE_NODE); + QueryTestEntry testLink1(subdir32 + "testLink1", B_SYMLINK_NODE, + &file11); + QueryTestEntry testLink2(subdir32 + "testLink2", B_SYMLINK_NODE, + &file11); + QueryTestEntry testFile3(subdir32 + "testFile3", B_FILE_NODE); + QueryTestEntry *entries[] = { + &testDir1, &testDir2, &testFile1, &testFile2, + &testLink1, &testLink2, &testFile3 + }; + int32 entryCount = sizeof(entries) / sizeof(QueryTestEntry*); + QueryTestEntry *queryEntries[] = { + &testFile1, &testFile2, &testFile3 + }; + int32 queryEntryCount = sizeof(queryEntries) / sizeof(QueryTestEntry*); + AddLiveEntries(entries, entryCount, queryEntries, queryEntryCount); + RemoveLiveEntries(entries, entryCount, queryEntries, queryEntryCount); + } +} + diff --git a/src/tests/kits/storage/QueryTest.h b/src/tests/kits/storage/QueryTest.h new file mode 100644 index 0000000000..bac904af89 --- /dev/null +++ b/src/tests/kits/storage/QueryTest.h @@ -0,0 +1,48 @@ +// QueryTest.h + +#ifndef __sk_query_test_h__ +#define __sk_query_test_h__ + +#include +#include + +#include +#include + +#include "BasicTest.h" + +class QueryTestEntry; +class TestApp; + +class QueryTest : public BasicTest +{ +public: + static CppUnit::Test* Suite(); + + // This function is called before *each* test added in Suite() + void setUp(); + + // This function is called after *each* test added in Suite() + void tearDown(); + + //------------------------------------------------------------ + // Test functions + //------------------------------------------------------------ + void PredicateTest(); + void ParameterTest(); + void FetchTest(); + void AddLiveEntries(QueryTestEntry **entries, int32 entryCount, + QueryTestEntry **queryEntries, int32 queryEntryCount); + void RemoveLiveEntries(QueryTestEntry **entries, int32 entryCount, + QueryTestEntry **queryEntries, + int32 queryEntryCount); + void CheckUpdateMessages(uint32 opcode, QueryTestEntry **entries, + int32 entryCount); + void LiveTest(); + +private: + TestApp *fApplication; + bool fVolumeCreated; +}; + +#endif // __sk_query_test_h__ diff --git a/src/tests/kits/storage/ResourceStringsTest.cpp b/src/tests/kits/storage/ResourceStringsTest.cpp new file mode 100644 index 0000000000..5b00ce2c23 --- /dev/null +++ b/src/tests/kits/storage/ResourceStringsTest.cpp @@ -0,0 +1,706 @@ +// ResourceStringsTest.cpp + +#include +#include +#include +#include + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Test.StorageKit.h" + + +static const char *testDir = "/tmp/testDir"; +static const char *x86ResFile = "/tmp/testDir/x86.rsrc"; +static const char *ppcResFile = "/tmp/testDir/ppc.rsrc"; +static const char *elfFile = "/tmp/testDir/elf"; +static const char *pefFile = "/tmp/testDir/pef"; +static const char *emptyFile = "/tmp/testDir/empty-file"; +static const char *noResFile = "/tmp/testDir/no-res-file"; +static const char *testFile1 = "/tmp/testDir/testFile1"; +static const char *testFile2 = "/tmp/testDir/testFile2"; +static const char *noSuchFile = "/tmp/testDir/no-such-file"; +static const char *x86ResName = "x86.rsrc"; +static const char *ppcResName = "ppc.rsrc"; +static const char *elfName = "elf"; +static const char *elfNoResName = "elf-no-res"; +static const char *pefName = "pef"; +static const char *pefNoResName = "pef-no-res"; + + +struct ResourceInfo { + ResourceInfo(type_code type, int32 id, const void *data, size_t size, + const char *name = NULL) + : type(type), + id(id), + name(NULL), + data(NULL), + size(size) + { + if (data) { + this->data = new char[size]; + memcpy(this->data, data, size); + } + if (name) { + int32 len = strlen(name); + this->name = new char[len + 1]; + strcpy(this->name, name); + } + } + + ~ResourceInfo() + { + delete[] name; + delete[] data; + } + + type_code type; + int32 id; + char *name; + char *data; + size_t size; +}; + +struct StringResourceInfo : public ResourceInfo { + StringResourceInfo(int32 id, const char *data, const char *name = NULL) + : ResourceInfo(B_STRING_TYPE, id, data, strlen(data) + 1, name) + { + } +}; + +static const char *testResData1 = "I like strings, especially cellos."; +static const int32 testResSize1 = strlen(testResData1) + 1; +static const int32 testResData2 = 42; +static const int32 testResSize2 = sizeof(int32); +static const char *testResData3 = "application/bread-roll-counter"; +static const int32 testResSize3 = strlen(testResData3) + 1; +static const char *testResData4 = "This is a long string. At least longer " + "than the first one"; +static const int32 testResSize4 = strlen(testResData1) + 1; +static const char *testResData6 = "Short, but true."; +static const int32 testResSize6 = strlen(testResData6) + 1; + +static const ResourceInfo testResource1(B_STRING_TYPE, 74, testResData1, + testResSize1, "a string resource"); +static const ResourceInfo testResource2(B_INT32_TYPE, 17, &testResData2, + testResSize2, "just a resource"); +static const ResourceInfo testResource3(B_MIME_STRING_TYPE, 29, testResData3, + testResSize3, "another resource"); +static const ResourceInfo testResource4(B_STRING_TYPE, 75, &testResData4, + testResSize4, + "a second string resource"); +static const ResourceInfo testResource5(B_MIME_STRING_TYPE, 74, &testResData1, + testResSize1, "a string resource"); +static const ResourceInfo testResource6(B_STRING_TYPE, 74, &testResData6, + testResSize6, + "a third string resource"); + +static const StringResourceInfo stringResource1(0, "What?"); +static const StringResourceInfo stringResource2(12, "What?", "string 2"); +static const StringResourceInfo stringResource3(19, "Who cares?", "string 3"); +static const StringResourceInfo stringResource4(23, "a little bit longer than " + "the others", "string 4"); +static const StringResourceInfo stringResource5(24, "a lot longer than " + "the other strings, but it " + "it doesn't have a name"); +static const StringResourceInfo stringResource6(26, "short"); +static const StringResourceInfo stringResource7(27, ""); +static const StringResourceInfo stringResource8(123, "the very last resource", + "last resource"); + +// get_app_path +static +string +get_app_path() +{ + string result; + image_info info; + int32 cookie = 0; + bool found = false; + while (!found && get_next_image_info(0, &cookie, &info) == B_OK) { + if (info.type == B_APP_IMAGE) { + result = info.name; + found = true; + } + } + return result; +} + +// ref_for +static +entry_ref +ref_for(const char *path) +{ + entry_ref ref; + get_ref_for_path(path, &ref); + return ref; +} + +// get_app_ref +static +entry_ref +get_app_ref() +{ + return ref_for(get_app_path().c_str()); +} + + +// Suite +CppUnit::Test* +ResourceStringsTest::Suite() { + CppUnit::TestSuite *suite = new CppUnit::TestSuite(); + typedef CppUnit::TestCaller TC; + + suite->addTest( new TC("BResourceStrings::Init Test1", + &ResourceStringsTest::InitTest1) ); + suite->addTest( new TC("BResourceStrings::Init Test2", + &ResourceStringsTest::InitTest2) ); + suite->addTest( new TC("BResourceString::FindString Test", + &ResourceStringsTest::FindStringTest) ); + + return suite; +} + +// add_resource +static +void +add_resource(BResources &resources, const ResourceInfo &resource) +{ + resources.AddResource(resource.type, resource.id, resource.data, + resource.size, resource.name); +} + +// setUp +void +ResourceStringsTest::setUp() +{ + BasicTest::setUp(); + string resourcesTestDir(shell.TestDir()); + resourcesTestDir += "/resources"; + execCommand(string("mkdir ") + testDir + + " ; cp " + resourcesTestDir + "/" + x86ResName + " " + + resourcesTestDir + "/" + ppcResName + " " + + resourcesTestDir + "/" + elfName + " " + + resourcesTestDir + "/" + elfNoResName + " " + + resourcesTestDir + "/" + pefName + " " + + resourcesTestDir + "/" + pefNoResName + " " + + testDir + + " ; touch " + emptyFile + + " ; echo \"That's not a resource file.\" > " + noResFile + ); + // prepare the test files + BFile file(testFile1, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); + BResources resources(&file, true); + add_resource(resources, stringResource1); + add_resource(resources, stringResource2); + add_resource(resources, testResource2); + add_resource(resources, stringResource3); + add_resource(resources, stringResource4); + add_resource(resources, stringResource5); + add_resource(resources, testResource3); + resources.Sync(); + file.SetTo(testFile2, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); + resources.SetTo(&file, true); + add_resource(resources, testResource3); + add_resource(resources, stringResource4); + add_resource(resources, stringResource5); + add_resource(resources, stringResource6); + add_resource(resources, testResource2); + add_resource(resources, stringResource7); + add_resource(resources, stringResource8); + resources.Sync(); +} + +// tearDown +void +ResourceStringsTest::tearDown() +{ + execCommand(string("rm -rf ") + testDir); + BasicTest::tearDown(); +} + +// InitTest1 +void +ResourceStringsTest::InitTest1() +{ + // default constructor + nextSubTest(); + { + BResourceStrings resourceStrings; + CPPUNIT_ASSERT( resourceStrings.InitCheck() == B_OK ); + entry_ref ref; + CPPUNIT_ASSERT( resourceStrings.GetStringFile(&ref) + == B_ENTRY_NOT_FOUND ); + } + // application file + nextSubTest(); + { + entry_ref ref = get_app_ref(); + BResourceStrings resourceStrings(ref); + CPPUNIT_ASSERT( resourceStrings.InitCheck() == B_OK ); + entry_ref ref2; + CPPUNIT_ASSERT( resourceStrings.GetStringFile(&ref2) == B_OK ); + CPPUNIT_ASSERT( BEntry(&ref, true) == BEntry(&ref2, true) ); + } + // x86 resource file + nextSubTest(); + { + entry_ref ref; + CPPUNIT_ASSERT( get_ref_for_path(x86ResFile, &ref) == B_OK ); + BResourceStrings resourceStrings(ref); + CPPUNIT_ASSERT( resourceStrings.InitCheck() == B_OK ); + entry_ref ref2; + CPPUNIT_ASSERT( resourceStrings.GetStringFile(&ref2) == B_OK ); + CPPUNIT_ASSERT( BEntry(&ref, true) == BEntry(&ref2, true) ); + } + // ppc resource file + nextSubTest(); + { + entry_ref ref; + CPPUNIT_ASSERT( get_ref_for_path(ppcResFile, &ref) == B_OK ); + BResourceStrings resourceStrings(ref); + CPPUNIT_ASSERT( resourceStrings.InitCheck() == B_OK ); + entry_ref ref2; + CPPUNIT_ASSERT( resourceStrings.GetStringFile(&ref2) == B_OK ); + CPPUNIT_ASSERT( BEntry(&ref, true) == BEntry(&ref2, true) ); + } + // ELF executable + nextSubTest(); + { + entry_ref ref; + CPPUNIT_ASSERT( get_ref_for_path(elfFile, &ref) == B_OK ); + BResourceStrings resourceStrings(ref); + CPPUNIT_ASSERT( resourceStrings.InitCheck() == B_OK ); + entry_ref ref2; + CPPUNIT_ASSERT( resourceStrings.GetStringFile(&ref2) == B_OK ); + CPPUNIT_ASSERT( BEntry(&ref, true) == BEntry(&ref2, true) ); + } + // PEF executable + nextSubTest(); + { + entry_ref ref; + CPPUNIT_ASSERT( get_ref_for_path(pefFile, &ref) == B_OK ); + BResourceStrings resourceStrings(ref); + CPPUNIT_ASSERT( resourceStrings.InitCheck() == B_OK ); + entry_ref ref2; + CPPUNIT_ASSERT( resourceStrings.GetStringFile(&ref2) == B_OK ); + CPPUNIT_ASSERT( BEntry(&ref, true) == BEntry(&ref2, true) ); + } + // test file 1 + nextSubTest(); + { + entry_ref ref; + CPPUNIT_ASSERT( get_ref_for_path(testFile1, &ref) == B_OK ); + BResourceStrings resourceStrings(ref); + CPPUNIT_ASSERT( resourceStrings.InitCheck() == B_OK ); + entry_ref ref2; + CPPUNIT_ASSERT( resourceStrings.GetStringFile(&ref2) == B_OK ); + CPPUNIT_ASSERT( BEntry(&ref, true) == BEntry(&ref2, true) ); + } + // test file 2 + nextSubTest(); + { + entry_ref ref; + CPPUNIT_ASSERT( get_ref_for_path(testFile1, &ref) == B_OK ); + BResourceStrings resourceStrings(ref); + CPPUNIT_ASSERT( resourceStrings.InitCheck() == B_OK ); + entry_ref ref2; + CPPUNIT_ASSERT( resourceStrings.GetStringFile(&ref2) == B_OK ); + CPPUNIT_ASSERT( BEntry(&ref, true) == BEntry(&ref2, true) ); + } + // empty file + nextSubTest(); + { + entry_ref ref; + CPPUNIT_ASSERT( get_ref_for_path(emptyFile, &ref) == B_OK ); + BResourceStrings resourceStrings(ref); + CPPUNIT_ASSERT( resourceStrings.InitCheck() == B_OK ); + entry_ref ref2; + CPPUNIT_ASSERT( resourceStrings.GetStringFile(&ref2) == B_OK ); + CPPUNIT_ASSERT( BEntry(&ref, true) == BEntry(&ref2, true) ); + } + // non-resource file + nextSubTest(); + { + entry_ref ref; + CPPUNIT_ASSERT( get_ref_for_path(noResFile, &ref) == B_OK ); + BResourceStrings resourceStrings(ref); + CPPUNIT_ASSERT( equals(resourceStrings.InitCheck(), B_ERROR, + B_IO_ERROR) ); + entry_ref ref2; + CPPUNIT_ASSERT( equals(resourceStrings.GetStringFile(&ref2), B_ERROR, + B_IO_ERROR) ); + } + // non-existing file + nextSubTest(); + { + entry_ref ref; + CPPUNIT_ASSERT( get_ref_for_path(noSuchFile, &ref) == B_OK ); + BResourceStrings resourceStrings(ref); + CPPUNIT_ASSERT( resourceStrings.InitCheck() == B_ENTRY_NOT_FOUND ); + entry_ref ref2; + CPPUNIT_ASSERT( resourceStrings.GetStringFile(&ref2) + == B_ENTRY_NOT_FOUND ); + } + // bad args (GetStringFile) +// R5: crashes +#if !SK_TEST_R5 + nextSubTest(); + { + entry_ref ref; + CPPUNIT_ASSERT( get_ref_for_path(testFile1, &ref) == B_OK ); + BResourceStrings resourceStrings(ref); + CPPUNIT_ASSERT( resourceStrings.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resourceStrings.GetStringFile(NULL) == B_BAD_VALUE ); + } +#endif +} + +// InitTest2 +void +ResourceStringsTest::InitTest2() +{ + // application file + nextSubTest(); + { + entry_ref ref = get_app_ref(); + BResourceStrings resourceStrings; + CPPUNIT_ASSERT( resourceStrings.SetStringFile(&ref) == B_OK ); + CPPUNIT_ASSERT( resourceStrings.InitCheck() == B_OK ); + entry_ref ref2; + CPPUNIT_ASSERT( resourceStrings.GetStringFile(&ref2) == B_OK ); + CPPUNIT_ASSERT( BEntry(&ref, true) == BEntry(&ref2, true) ); + } + // x86 resource file + nextSubTest(); + { + entry_ref ref; + CPPUNIT_ASSERT( get_ref_for_path(x86ResFile, &ref) == B_OK ); + BResourceStrings resourceStrings; + CPPUNIT_ASSERT( resourceStrings.SetStringFile(&ref) == B_OK ); + CPPUNIT_ASSERT( resourceStrings.InitCheck() == B_OK ); + entry_ref ref2; + CPPUNIT_ASSERT( resourceStrings.GetStringFile(&ref2) == B_OK ); + CPPUNIT_ASSERT( BEntry(&ref, true) == BEntry(&ref2, true) ); + } + // ppc resource file + nextSubTest(); + { + entry_ref ref; + CPPUNIT_ASSERT( get_ref_for_path(ppcResFile, &ref) == B_OK ); + BResourceStrings resourceStrings; + CPPUNIT_ASSERT( resourceStrings.SetStringFile(&ref) == B_OK ); + CPPUNIT_ASSERT( resourceStrings.InitCheck() == B_OK ); + entry_ref ref2; + CPPUNIT_ASSERT( resourceStrings.GetStringFile(&ref2) == B_OK ); + CPPUNIT_ASSERT( BEntry(&ref, true) == BEntry(&ref2, true) ); + } + // ELF executable + nextSubTest(); + { + entry_ref ref; + CPPUNIT_ASSERT( get_ref_for_path(elfFile, &ref) == B_OK ); + BResourceStrings resourceStrings; + CPPUNIT_ASSERT( resourceStrings.SetStringFile(&ref) == B_OK ); + CPPUNIT_ASSERT( resourceStrings.InitCheck() == B_OK ); + entry_ref ref2; + CPPUNIT_ASSERT( resourceStrings.GetStringFile(&ref2) == B_OK ); + CPPUNIT_ASSERT( BEntry(&ref, true) == BEntry(&ref2, true) ); + } + // PEF executable + nextSubTest(); + { + entry_ref ref; + CPPUNIT_ASSERT( get_ref_for_path(pefFile, &ref) == B_OK ); + BResourceStrings resourceStrings; + CPPUNIT_ASSERT( resourceStrings.SetStringFile(&ref) == B_OK ); + CPPUNIT_ASSERT( resourceStrings.InitCheck() == B_OK ); + entry_ref ref2; + CPPUNIT_ASSERT( resourceStrings.GetStringFile(&ref2) == B_OK ); + CPPUNIT_ASSERT( BEntry(&ref, true) == BEntry(&ref2, true) ); + } + // test file 1 + nextSubTest(); + { + entry_ref ref; + CPPUNIT_ASSERT( get_ref_for_path(testFile1, &ref) == B_OK ); + BResourceStrings resourceStrings; + CPPUNIT_ASSERT( resourceStrings.SetStringFile(&ref) == B_OK ); + CPPUNIT_ASSERT( resourceStrings.InitCheck() == B_OK ); + entry_ref ref2; + CPPUNIT_ASSERT( resourceStrings.GetStringFile(&ref2) == B_OK ); + CPPUNIT_ASSERT( BEntry(&ref, true) == BEntry(&ref2, true) ); + } + // test file 2 + nextSubTest(); + { + entry_ref ref; + CPPUNIT_ASSERT( get_ref_for_path(testFile1, &ref) == B_OK ); + BResourceStrings resourceStrings; + CPPUNIT_ASSERT( resourceStrings.SetStringFile(&ref) == B_OK ); + CPPUNIT_ASSERT( resourceStrings.InitCheck() == B_OK ); + entry_ref ref2; + CPPUNIT_ASSERT( resourceStrings.GetStringFile(&ref2) == B_OK ); + CPPUNIT_ASSERT( BEntry(&ref, true) == BEntry(&ref2, true) ); + } + // empty file + nextSubTest(); + { + entry_ref ref; + CPPUNIT_ASSERT( get_ref_for_path(emptyFile, &ref) == B_OK ); + BResourceStrings resourceStrings; + CPPUNIT_ASSERT( resourceStrings.SetStringFile(&ref) == B_OK ); + CPPUNIT_ASSERT( resourceStrings.InitCheck() == B_OK ); + entry_ref ref2; + CPPUNIT_ASSERT( resourceStrings.GetStringFile(&ref2) == B_OK ); + CPPUNIT_ASSERT( BEntry(&ref, true) == BEntry(&ref2, true) ); + } + // non-resource file + nextSubTest(); + { + entry_ref ref; + CPPUNIT_ASSERT( get_ref_for_path(noResFile, &ref) == B_OK ); + BResourceStrings resourceStrings; + CPPUNIT_ASSERT( equals(resourceStrings.SetStringFile(&ref), B_ERROR, + B_IO_ERROR) ); + CPPUNIT_ASSERT( equals(resourceStrings.InitCheck(), B_ERROR, + B_IO_ERROR) ); + entry_ref ref2; + CPPUNIT_ASSERT( equals(resourceStrings.GetStringFile(&ref2), B_ERROR, + B_IO_ERROR) ); + } + // non-existing file + nextSubTest(); + { + entry_ref ref; + CPPUNIT_ASSERT( get_ref_for_path(noSuchFile, &ref) == B_OK ); + BResourceStrings resourceStrings; + CPPUNIT_ASSERT( resourceStrings.SetStringFile(&ref) + == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( resourceStrings.InitCheck() == B_ENTRY_NOT_FOUND ); + entry_ref ref2; + CPPUNIT_ASSERT( resourceStrings.GetStringFile(&ref2) + == B_ENTRY_NOT_FOUND ); + } + // NULL ref -> app file + nextSubTest(); + { + BResourceStrings resourceStrings; + CPPUNIT_ASSERT( resourceStrings.SetStringFile(NULL) == B_OK ); + CPPUNIT_ASSERT( resourceStrings.InitCheck() == B_OK ); + entry_ref ref2; + CPPUNIT_ASSERT( resourceStrings.GetStringFile(&ref2) + == B_ENTRY_NOT_FOUND ); + } +} + +// FindStringTest +static +void +FindStringTest(BResourceStrings &resourceStrings, const ResourceInfo &resource, + bool ok) +{ + BString *newString = resourceStrings.NewString(resource.id); + const char *foundString = resourceStrings.FindString(resource.id); + if (ok) { + CPPUNIT_ASSERT( newString != NULL && foundString != NULL ); + CPPUNIT_ASSERT( *newString == (const char*)resource.data ); + CPPUNIT_ASSERT( *newString == foundString ); + delete newString; + } else + CPPUNIT_ASSERT( newString == NULL && foundString == NULL ); +} + +// FindStringTest +void +ResourceStringsTest::FindStringTest() +{ + // app file (default constructor) + nextSubTest(); + { + BResourceStrings resourceStrings; + CPPUNIT_ASSERT( resourceStrings.InitCheck() == B_OK ); + ::FindStringTest(resourceStrings, stringResource1, false); + ::FindStringTest(resourceStrings, stringResource2, false); + ::FindStringTest(resourceStrings, stringResource3, false); + ::FindStringTest(resourceStrings, stringResource4, false); + ::FindStringTest(resourceStrings, stringResource5, false); + ::FindStringTest(resourceStrings, stringResource6, false); + ::FindStringTest(resourceStrings, stringResource7, false); + ::FindStringTest(resourceStrings, stringResource8, false); + ::FindStringTest(resourceStrings, testResource1, false); + } + // app file (explicitely) + nextSubTest(); + { + entry_ref ref = get_app_ref(); + BResourceStrings resourceStrings(ref); + CPPUNIT_ASSERT( resourceStrings.InitCheck() == B_OK ); + ::FindStringTest(resourceStrings, stringResource1, false); + ::FindStringTest(resourceStrings, stringResource2, false); + ::FindStringTest(resourceStrings, stringResource3, false); + ::FindStringTest(resourceStrings, stringResource4, false); + ::FindStringTest(resourceStrings, stringResource5, false); + ::FindStringTest(resourceStrings, stringResource6, false); + ::FindStringTest(resourceStrings, stringResource7, false); + ::FindStringTest(resourceStrings, stringResource8, false); + ::FindStringTest(resourceStrings, testResource1, false); + } + // test file 1 + nextSubTest(); + { + entry_ref ref = ref_for(testFile1); + BResourceStrings resourceStrings(ref); + CPPUNIT_ASSERT( resourceStrings.InitCheck() == B_OK ); + ::FindStringTest(resourceStrings, stringResource1, true); + ::FindStringTest(resourceStrings, stringResource2, true); + ::FindStringTest(resourceStrings, stringResource3, true); + ::FindStringTest(resourceStrings, stringResource4, true); + ::FindStringTest(resourceStrings, stringResource5, true); + ::FindStringTest(resourceStrings, stringResource6, false); + ::FindStringTest(resourceStrings, stringResource7, false); + ::FindStringTest(resourceStrings, stringResource8, false); + ::FindStringTest(resourceStrings, testResource1, false); + } + // test file 2 + nextSubTest(); + { + entry_ref ref = ref_for(testFile2); + BResourceStrings resourceStrings(ref); + CPPUNIT_ASSERT( resourceStrings.InitCheck() == B_OK ); + ::FindStringTest(resourceStrings, stringResource1, false); + ::FindStringTest(resourceStrings, stringResource2, false); + ::FindStringTest(resourceStrings, stringResource3, false); + ::FindStringTest(resourceStrings, stringResource4, true); + ::FindStringTest(resourceStrings, stringResource5, true); + ::FindStringTest(resourceStrings, stringResource6, true); + ::FindStringTest(resourceStrings, stringResource7, true); + ::FindStringTest(resourceStrings, stringResource8, true); + ::FindStringTest(resourceStrings, testResource1, false); + } + // x86 resource file + nextSubTest(); + { + entry_ref ref = ref_for(x86ResFile); + BResourceStrings resourceStrings(ref); + CPPUNIT_ASSERT( resourceStrings.InitCheck() == B_OK ); + ::FindStringTest(resourceStrings, stringResource1, false); + ::FindStringTest(resourceStrings, stringResource2, false); + ::FindStringTest(resourceStrings, stringResource3, false); + ::FindStringTest(resourceStrings, stringResource4, false); + ::FindStringTest(resourceStrings, stringResource5, false); + ::FindStringTest(resourceStrings, stringResource6, false); + ::FindStringTest(resourceStrings, stringResource7, false); + ::FindStringTest(resourceStrings, stringResource8, false); + ::FindStringTest(resourceStrings, testResource1, true); + } + // ppc resource file + nextSubTest(); + { + entry_ref ref = ref_for(ppcResFile); + BResourceStrings resourceStrings(ref); + CPPUNIT_ASSERT( resourceStrings.InitCheck() == B_OK ); + ::FindStringTest(resourceStrings, stringResource1, false); + ::FindStringTest(resourceStrings, stringResource2, false); + ::FindStringTest(resourceStrings, stringResource3, false); + ::FindStringTest(resourceStrings, stringResource4, false); + ::FindStringTest(resourceStrings, stringResource5, false); + ::FindStringTest(resourceStrings, stringResource6, false); + ::FindStringTest(resourceStrings, stringResource7, false); + ::FindStringTest(resourceStrings, stringResource8, false); + ::FindStringTest(resourceStrings, testResource1, true); + } + // ELF executable + nextSubTest(); + { + entry_ref ref = ref_for(elfFile); + BResourceStrings resourceStrings(ref); + CPPUNIT_ASSERT( resourceStrings.InitCheck() == B_OK ); + ::FindStringTest(resourceStrings, stringResource1, false); + ::FindStringTest(resourceStrings, stringResource2, false); + ::FindStringTest(resourceStrings, stringResource3, false); + ::FindStringTest(resourceStrings, stringResource4, false); + ::FindStringTest(resourceStrings, stringResource5, false); + ::FindStringTest(resourceStrings, stringResource6, false); + ::FindStringTest(resourceStrings, stringResource7, false); + ::FindStringTest(resourceStrings, stringResource8, false); + ::FindStringTest(resourceStrings, testResource1, true); + } + // PEF executable + nextSubTest(); + { + entry_ref ref = ref_for(pefFile); + BResourceStrings resourceStrings(ref); + CPPUNIT_ASSERT( resourceStrings.InitCheck() == B_OK ); + ::FindStringTest(resourceStrings, stringResource1, false); + ::FindStringTest(resourceStrings, stringResource2, false); + ::FindStringTest(resourceStrings, stringResource3, false); + ::FindStringTest(resourceStrings, stringResource4, false); + ::FindStringTest(resourceStrings, stringResource5, false); + ::FindStringTest(resourceStrings, stringResource6, false); + ::FindStringTest(resourceStrings, stringResource7, false); + ::FindStringTest(resourceStrings, stringResource8, false); + ::FindStringTest(resourceStrings, testResource1, true); + } + // empty file + nextSubTest(); + { + entry_ref ref = ref_for(emptyFile); + BResourceStrings resourceStrings(ref); + CPPUNIT_ASSERT( resourceStrings.InitCheck() == B_OK ); + ::FindStringTest(resourceStrings, stringResource1, false); + ::FindStringTest(resourceStrings, stringResource2, false); + ::FindStringTest(resourceStrings, stringResource3, false); + ::FindStringTest(resourceStrings, stringResource4, false); + ::FindStringTest(resourceStrings, stringResource5, false); + ::FindStringTest(resourceStrings, stringResource6, false); + ::FindStringTest(resourceStrings, stringResource7, false); + ::FindStringTest(resourceStrings, stringResource8, false); + ::FindStringTest(resourceStrings, testResource1, false); + } + // non-resource file + nextSubTest(); + { + entry_ref ref = ref_for(noResFile); + BResourceStrings resourceStrings(ref); + CPPUNIT_ASSERT( equals(resourceStrings.InitCheck(), B_ERROR, + B_IO_ERROR) ); + ::FindStringTest(resourceStrings, stringResource1, false); + ::FindStringTest(resourceStrings, stringResource2, false); + ::FindStringTest(resourceStrings, stringResource3, false); + ::FindStringTest(resourceStrings, stringResource4, false); + ::FindStringTest(resourceStrings, stringResource5, false); + ::FindStringTest(resourceStrings, stringResource6, false); + ::FindStringTest(resourceStrings, stringResource7, false); + ::FindStringTest(resourceStrings, stringResource8, false); + ::FindStringTest(resourceStrings, testResource1, false); + } + // non-existing file + nextSubTest(); + { + entry_ref ref = ref_for(noSuchFile); + BResourceStrings resourceStrings(ref); + CPPUNIT_ASSERT( resourceStrings.InitCheck() == B_ENTRY_NOT_FOUND ); + ::FindStringTest(resourceStrings, stringResource1, false); + ::FindStringTest(resourceStrings, stringResource2, false); + ::FindStringTest(resourceStrings, stringResource3, false); + ::FindStringTest(resourceStrings, stringResource4, false); + ::FindStringTest(resourceStrings, stringResource5, false); + ::FindStringTest(resourceStrings, stringResource6, false); + ::FindStringTest(resourceStrings, stringResource7, false); + ::FindStringTest(resourceStrings, stringResource8, false); + ::FindStringTest(resourceStrings, testResource1, false); + } +} + diff --git a/src/tests/kits/storage/ResourceStringsTest.h b/src/tests/kits/storage/ResourceStringsTest.h new file mode 100644 index 0000000000..90699454bc --- /dev/null +++ b/src/tests/kits/storage/ResourceStringsTest.h @@ -0,0 +1,47 @@ +// ResourceStringsTest.h + +#ifndef __sk_resource_strings_test_h__ +#define __sk_resource_strings_test_h__ + +#include +#include + +#include +#include + +#include "BasicTest.h" + +class ResourceStringsTest : public BasicTest +{ +public: + static CppUnit::Test* Suite(); + + // This function called before *each* test added in Suite() + void setUp(); + + // This function called after *each* test added in Suite() + void tearDown(); + + //------------------------------------------------------------ + // Test functions + //------------------------------------------------------------ + void InitTest1(); + void InitTest2(); + void FindStringTest(); + +// BResourceStrings(); +// BResourceStrings(const entry_ref &ref); +// virtual ~BResourceStrings(); +// virtual status_t SetStringFile(const entry_ref *ref); +// status_t GetStringFile(entry_ref *outRef); +// status_t InitCheck(); + +// virtual BString *NewString(int32 id); +// virtual const char *FindString(int32 id); + + + +}; + + +#endif // __sk_resource_strings_test_h__ diff --git a/src/tests/kits/storage/ResourcesTest.cpp b/src/tests/kits/storage/ResourcesTest.cpp new file mode 100644 index 0000000000..512a893cd0 --- /dev/null +++ b/src/tests/kits/storage/ResourcesTest.cpp @@ -0,0 +1,1531 @@ +// ResourcesTest.cpp + +#include +#include +#include +#include + + +#include + +#include +#include +#include +#include +#include +#include + +#include "Test.StorageKit.h" + +static const char *testDir = "/tmp/testDir"; +static const char *x86ResFile = "/tmp/testDir/x86.rsrc"; +static const char *ppcResFile = "/tmp/testDir/ppc.rsrc"; +static const char *elfFile = "/tmp/testDir/elf"; +static const char *elfNoResFile = "/tmp/testDir/elf-no-res"; +static const char *pefFile = "/tmp/testDir/pef"; +static const char *pefNoResFile = "/tmp/testDir/pef-no-res"; +static const char *emptyFile = "/tmp/testDir/empty-file"; +static const char *noResFile = "/tmp/testDir/no-res-file"; +static const char *testFile1 = "/tmp/testDir/testFile1"; +static const char *testFile2 = "/tmp/testDir/testFile2"; +static const char *noSuchFile = "/tmp/testDir/no-such-file"; +static const char *x86ResName = "x86.rsrc"; +static const char *ppcResName = "ppc.rsrc"; +static const char *elfName = "elf"; +static const char *elfNoResName = "elf-no-res"; +static const char *pefName = "pef"; +static const char *pefNoResName = "pef-no-res"; + +static const int32 kEmptyResourceFileSize = 1984; + +struct ResourceInfo { + ResourceInfo(type_code type, int32 id, const void *data, size_t size, + const char *name = NULL) + : type(type), + id(id), + name(NULL), + data(NULL), + size(size) + { + if (data) { + this->data = new char[size]; + memcpy(this->data, data, size); + } + if (name) { + int32 len = strlen(name); + this->name = new char[len + 1]; + strcpy(this->name, name); + } + } + + ~ResourceInfo() + { + delete[] name; + delete[] data; + } + + type_code type; + int32 id; + char *name; + char *data; + size_t size; +}; + +static const char *testResData1 = "I like strings, especially cellos."; +static const int32 testResSize1 = strlen(testResData1) + 1; +static const int32 testResData2 = 42; +static const int32 testResSize2 = sizeof(int32); +static const char *testResData3 = "application/bread-roll-counter"; +static const int32 testResSize3 = strlen(testResData3) + 1; +static const char *testResData4 = "This is a long string. At least longer " + "than the first one"; +static const int32 testResSize4 = strlen(testResData1) + 1; +static const char *testResData6 = "Short, but true."; +static const int32 testResSize6 = strlen(testResData6) + 1; + +static const ResourceInfo testResource1(B_STRING_TYPE, 74, testResData1, + testResSize1, "a string resource"); +static const ResourceInfo testResource2(B_INT32_TYPE, 17, &testResData2, + testResSize2, "just a resource"); +static const ResourceInfo testResource3(B_MIME_STRING_TYPE, 29, testResData3, + testResSize3, "another resource"); +static const ResourceInfo testResource4(B_STRING_TYPE, 75, &testResData4, + testResSize4, + "a second string resource"); +static const ResourceInfo testResource5(B_MIME_STRING_TYPE, 74, &testResData1, + testResSize1, "a string resource"); +static const ResourceInfo testResource6(B_STRING_TYPE, 74, &testResData6, + testResSize6, + "a third string resource"); + +// helper class: maintains a ResourceInfo set +struct ResourceSet { + typedef vector ResInfoSet; + + ResourceSet() : fResources() { } + + ResourceSet(const ResourceSet &resourceSet) + : fResources() + { + fResources = resourceSet.fResources; + } + + void add(const ResourceInfo *info) + { + if (info) { + remove(info->type, info->id); + fResources.insert(fResources.end(), info); + } + } + + void remove(const ResourceInfo *info) + { + if (info) + remove(info->type, info->id); + } + + void remove(type_code type, int32 id) + { + for (ResInfoSet::iterator it = fResources.begin(); + it != fResources.end(); + it++) { + const ResourceInfo *info = *it; + if (info->type == type && info->id == id) { + fResources.erase(it); + break; + } + } + } + + int32 size() const + { + return fResources.size(); + } + + const ResourceInfo *infoAt(int32 index) const + { + const ResourceInfo *info = NULL; + if (index >= 0 && index < size()) + info = fResources[index]; + return info; + } + + const ResourceInfo *find(type_code type, int32 id) const + { + const ResourceInfo *result = NULL; + for (ResInfoSet::const_iterator it = fResources.begin(); + result == NULL && it != fResources.end(); + it++) { + const ResourceInfo *info = *it; + if (info->type == type && info->id == id) + result = info; + } + return result; + } + + ResInfoSet fResources; +}; + + +// Suite +CppUnit::Test* +ResourcesTest::Suite() { + CppUnit::TestSuite *suite = new CppUnit::TestSuite(); + typedef CppUnit::TestCaller TC; + + suite->addTest( new TC("BResources::Init Test", + &ResourcesTest::InitTest) ); + suite->addTest( new TC("BResources::Read Test", + &ResourcesTest::ReadTest) ); + suite->addTest( new TC("BResources::Sync Test", + &ResourcesTest::SyncTest) ); + suite->addTest( new TC("BResources::Merge Test", + &ResourcesTest::MergeTest) ); + suite->addTest( new TC("BResources::WriteTo Test", + &ResourcesTest::WriteToTest) ); + suite->addTest( new TC("BResources::AddRemove Test", + &ResourcesTest::AddRemoveTest) ); + suite->addTest( new TC("BResources::ReadWrite Test", + &ResourcesTest::ReadWriteTest) ); + + return suite; +} + +// setUp +void +ResourcesTest::setUp() +{ + BasicTest::setUp(); + BString unescapedTestDir(shell.TestDir()); + unescapedTestDir.CharacterEscape(" \t\n!\"'`$&()?*+{}[]<>|", '\\'); + string resourcesTestDir(unescapedTestDir.String()); + resourcesTestDir += "/resources"; + execCommand(string("mkdir ") + testDir + + " ; cp " + resourcesTestDir + "/" + x86ResName + " " + + resourcesTestDir + "/" + ppcResName + " " + + resourcesTestDir + "/" + elfName + " " + + resourcesTestDir + "/" + elfNoResName + " " + + resourcesTestDir + "/" + pefName + " " + + resourcesTestDir + "/" + pefNoResName + " " + + testDir + + " ; touch " + emptyFile + + " ; echo \"That's not a resource file.\" > " + noResFile + ); +} + +// tearDown +void +ResourcesTest::tearDown() +{ + execCommand(string("rm -rf ") + testDir); + BasicTest::tearDown(); +} + +// InitTest +void +ResourcesTest::InitTest() +{ + // 1. existing files, read only + // x86 resource file + nextSubTest(); + { + BResources resources; + BFile file(x86ResFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + } + // ppc resource file + nextSubTest(); + { + BResources resources; + BFile file(ppcResFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + } + // ELF binary containing resources + nextSubTest(); + { + BResources resources; + BFile file(elfFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + } + // ELF binary not containing resources + nextSubTest(); + { + BResources resources; + BFile file(elfNoResFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + } + // PEF binary containing resources + nextSubTest(); + { + BResources resources; + BFile file(pefFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + } + // PEF binary not containing resources + nextSubTest(); + { + BResources resources; + BFile file(pefNoResFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + } + // empty file + nextSubTest(); + { + BResources resources; + BFile file(emptyFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + } + // non-resource file + nextSubTest(); + { + BResources resources; + BFile file(noResFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( equals(resources.SetTo(&file, false), B_ERROR, + B_IO_ERROR) ); + } + + // 2. existing files, read only, clobber + // x86 resource file + nextSubTest(); + { + BResources resources; + BFile file(x86ResFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK ); + } + // ppc resource file + nextSubTest(); + { + BResources resources; + BFile file(ppcResFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK ); + } + // ELF binary containing resources + nextSubTest(); + { + BResources resources; + BFile file(elfFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK ); + } + // ELF binary not containing resources + nextSubTest(); + { + BResources resources; + BFile file(elfNoResFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK ); + } + // PEF binary containing resources + nextSubTest(); + { + BResources resources; + BFile file(pefFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK ); + } + // PEF binary not containing resources + nextSubTest(); + { + BResources resources; + BFile file(pefNoResFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK ); + } + // empty file + nextSubTest(); + { + BResources resources; + BFile file(emptyFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK ); + } + // non-resource file + nextSubTest(); + { + BResources resources; + BFile file(noResFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK ); + } + + // 3. existing files, read/write + // x86 resource file + nextSubTest(); + { + BResources resources; + BFile file(x86ResFile, B_READ_WRITE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + } + // ppc resource file + nextSubTest(); + { + BResources resources; + BFile file(ppcResFile, B_READ_WRITE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + } + // ELF binary containing resources + nextSubTest(); + { + BResources resources; + BFile file(elfFile, B_READ_WRITE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + } + // ELF binary not containing resources + nextSubTest(); + { + BResources resources; + BFile file(elfNoResFile, B_READ_WRITE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + } + // PEF binary containing resources + nextSubTest(); + { + BResources resources; + BFile file(pefFile, B_READ_WRITE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + } + // PEF binary not containing resources + nextSubTest(); + { + BResources resources; + BFile file(pefNoResFile, B_READ_WRITE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + } + // empty file + nextSubTest(); + { + BResources resources; + BFile file(emptyFile, B_READ_WRITE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + } + // non-resource file + nextSubTest(); + { + BResources resources; + BFile file(noResFile, B_READ_WRITE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( equals(resources.SetTo(&file, false), B_ERROR, + B_IO_ERROR) ); + } + + // 4. existing files, read/write, clobber + // x86 resource file + nextSubTest(); + { + BResources resources; + BFile file(x86ResFile, B_READ_WRITE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK ); + CPPUNIT_ASSERT( resources.Sync() == B_OK ); + } + // ppc resource file + nextSubTest(); + { + BResources resources; + BFile file(ppcResFile, B_READ_WRITE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK ); + CPPUNIT_ASSERT( resources.Sync() == B_OK ); + } + // ELF binary containing resources + nextSubTest(); + { + BResources resources; + BFile file(elfFile, B_READ_WRITE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK ); + CPPUNIT_ASSERT( resources.Sync() == B_OK ); + } + // ELF binary not containing resources + nextSubTest(); + { + BResources resources; + BFile file(elfNoResFile, B_READ_WRITE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK ); + CPPUNIT_ASSERT( resources.Sync() == B_OK ); + } + // PEF binary containing resources + nextSubTest(); + { + BResources resources; + BFile file(pefFile, B_READ_WRITE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK ); + CPPUNIT_ASSERT( resources.Sync() == B_OK ); + } + // PEF binary not containing resources + nextSubTest(); + { + BResources resources; + BFile file(pefNoResFile, B_READ_WRITE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK ); + CPPUNIT_ASSERT( resources.Sync() == B_OK ); + } + // empty file + nextSubTest(); + { + BResources resources; + BFile file(emptyFile, B_READ_WRITE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK ); + CPPUNIT_ASSERT( resources.Sync() == B_OK ); + } + // non-resource file + nextSubTest(); + { + BResources resources; + BFile file(noResFile, B_READ_WRITE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK ); + } + + // 5. bad args + // uninitialized file + nextSubTest(); + { + BResources resources; + BFile file; + CPPUNIT_ASSERT( file.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_NO_INIT ); + } + // badly initialized file + nextSubTest(); + { + BResources resources; + BFile file(noSuchFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_ENTRY_NOT_FOUND ); + } + // NULL file + nextSubTest(); + { + BResources resources; + // R5: A NULL file is B_OK! +// CPPUNIT_ASSERT( resources.SetTo(NULL, false) == B_BAD_VALUE ); + CPPUNIT_ASSERT( resources.SetTo(NULL, false) == B_OK ); + } +} + +// ReadResTest +static +void +ReadResTest(BResources& resources, const ResourceInfo& info, bool exists) +{ + if (exists) { + // test an existing resource + // HasResource() + CPPUNIT_ASSERT( resources.HasResource(info.type, info.id) == true ); + CPPUNIT_ASSERT( resources.HasResource(info.type, info.name) + == true ); + // GetResourceInfo() + const char *name; + size_t length; + int32 id; + CPPUNIT_ASSERT( resources.GetResourceInfo(info.type, info.id, + &name, &length) == true ); + CPPUNIT_ASSERT( name == NULL && info.name == NULL + || name != NULL && info.name != NULL + && !strcmp(name, info.name) ); + CPPUNIT_ASSERT( length == info.size ); + CPPUNIT_ASSERT( resources.GetResourceInfo(info.type, info.name, + &id, &length) == true ); + CPPUNIT_ASSERT( id == info.id ); + CPPUNIT_ASSERT( length == info.size ); + // LoadResource + size_t length1; + size_t length2; + const void *data1 + = resources.LoadResource(info.type, info.id, &length1); + const void *data2 + = resources.LoadResource(info.type, info.name, &length2); + CPPUNIT_ASSERT( length1 == info.size && length2 == info.size ); + CPPUNIT_ASSERT( data1 != NULL && data1 == data2 ); + CPPUNIT_ASSERT( !memcmp(data1, info.data, info.size) ); + // GetResourceInfo() + type_code type = 0; + id = 0; + length = 0; + name = NULL; + CPPUNIT_ASSERT( resources.GetResourceInfo(data1, &type, &id, &length, + &name) == true ); + CPPUNIT_ASSERT( type == info.type ); + CPPUNIT_ASSERT( id == info.id ); + CPPUNIT_ASSERT( length == info.size ); + CPPUNIT_ASSERT( name == NULL && info.name == NULL + || name != NULL && info.name != NULL + && !strcmp(name, info.name) ); + // ReadResource() + const int32 bufferSize = 1024; + char buffer[bufferSize]; + memset(buffer, 0x0f, bufferSize); + // read past the end + status_t error = resources.ReadResource(info.type, info.id, buffer, + info.size + 2, bufferSize); + CPPUNIT_ASSERT( error == B_OK ); + for (int32 i = 0; i < bufferSize; i++) + CPPUNIT_ASSERT( buffer[i] == 0x0f ); + // read 2 bytes from the middle + int32 offset = (info.size - 2) / 2; + error = resources.ReadResource(info.type, info.id, buffer, offset, 2); + CPPUNIT_ASSERT( error == B_OK ); + CPPUNIT_ASSERT( !memcmp(buffer, (const char*)info.data + offset, 2) ); + for (int32 i = 2; i < bufferSize; i++) + CPPUNIT_ASSERT( buffer[i] == 0x0f ); + // read the whole chunk + error = resources.ReadResource(info.type, info.id, buffer, 0, + bufferSize); + CPPUNIT_ASSERT( error == B_OK ); + CPPUNIT_ASSERT( !memcmp(buffer, info.data, info.size) ); + // FindResource() + size_t lengthFound1; + size_t lengthFound2; + void *dataFound1 + = resources.FindResource(info.type, info.id, &lengthFound1); + void *dataFound2 + = resources.FindResource(info.type, info.name, &lengthFound2); + CPPUNIT_ASSERT( dataFound1 != NULL && dataFound2 != NULL ); + CPPUNIT_ASSERT( lengthFound1 == info.size + && lengthFound2 == info.size ); + CPPUNIT_ASSERT( !memcmp(dataFound1, info.data, info.size) ); + CPPUNIT_ASSERT( !memcmp(dataFound2, info.data, info.size) ); + free(dataFound1); + free(dataFound2); + } else { + // test a non-existing resource + // HasResource() + CPPUNIT_ASSERT( resources.HasResource(info.type, info.id) == false ); + CPPUNIT_ASSERT( resources.HasResource(info.type, info.name) + == false ); + // GetResourceInfo() + const char *name; + size_t length; + int32 id; + CPPUNIT_ASSERT( resources.GetResourceInfo(info.type, info.id, + &name, &length) == false ); + CPPUNIT_ASSERT( resources.GetResourceInfo(info.type, info.name, + &id, &length) == false ); + // LoadResource + size_t length1; + size_t length2; + const void *data1 + = resources.LoadResource(info.type, info.id, &length1); + const void *data2 + = resources.LoadResource(info.type, info.name, &length2); + CPPUNIT_ASSERT( data1 == NULL && data2 == NULL ); + // ReadResource() + const int32 bufferSize = 1024; + char buffer[bufferSize]; + status_t error = resources.ReadResource(info.type, info.id, buffer, + 0, bufferSize); + CPPUNIT_ASSERT( error == B_BAD_VALUE ); + // FindResource() + size_t lengthFound1; + size_t lengthFound2; + void *dataFound1 + = resources.FindResource(info.type, info.id, &lengthFound1); + void *dataFound2 + = resources.FindResource(info.type, info.name, &lengthFound2); + CPPUNIT_ASSERT( dataFound1 == NULL && dataFound2 == NULL ); + } +} + +// ReadBadResTest +static +void +ReadBadResTest(BResources& resources, const ResourceInfo& info) +{ + // HasResource() + CPPUNIT_ASSERT( resources.HasResource(info.type, info.id) == false ); + CPPUNIT_ASSERT( resources.HasResource(info.type, info.name) + == false ); + // GetResourceInfo() + type_code type; + const char *name; + size_t length; + int32 id; + CPPUNIT_ASSERT( resources.GetResourceInfo(info.type, info.id, + &name, &length) == false ); + CPPUNIT_ASSERT( resources.GetResourceInfo(info.type, info.name, + &id, &length) == false ); + CPPUNIT_ASSERT( resources.GetResourceInfo(0, &type, &id, + &name, &length) == false ); + CPPUNIT_ASSERT( resources.GetResourceInfo(info.type, 0, &id, + &name, &length) == false ); + // LoadResource + size_t length1; + size_t length2; + const void *data1 + = resources.LoadResource(info.type, info.id, &length1); + const void *data2 + = resources.LoadResource(info.type, info.name, &length2); + CPPUNIT_ASSERT( data1 == NULL && data2 == NULL ); + // ReadResource() + const int32 bufferSize = 1024; + char buffer[bufferSize]; + status_t error = resources.ReadResource(info.type, info.id, buffer, + 0, bufferSize); + CPPUNIT_ASSERT( error == B_BAD_VALUE ); + // FindResource() + size_t lengthFound1; + size_t lengthFound2; + void *dataFound1 + = resources.FindResource(info.type, info.id, &lengthFound1); + void *dataFound2 + = resources.FindResource(info.type, info.name, &lengthFound2); + CPPUNIT_ASSERT( dataFound1 == NULL && dataFound2 == NULL ); +} + +// ReadTest +void +ResourcesTest::ReadTest() +{ + // tests: + // * HasResource() + // * GetResourceInfo() + // * LoadResource() + // * ReadResource() + // * FindResource() + // * PreloadResource() + + // 1. basic tests + // x86 resource file + nextSubTest(); + { + BFile file(x86ResFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BResources resources; + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + ReadResTest(resources, testResource1, true); + ReadResTest(resources, testResource2, true); + ReadResTest(resources, testResource3, true); + ReadResTest(resources, testResource4, false); + ReadResTest(resources, testResource5, false); + } + // ppc resource file + nextSubTest(); + { + BFile file(ppcResFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BResources resources; + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + ReadResTest(resources, testResource1, true); + ReadResTest(resources, testResource2, true); + ReadResTest(resources, testResource3, true); + ReadResTest(resources, testResource4, false); + ReadResTest(resources, testResource5, false); + } + // ELF binary containing resources + nextSubTest(); + { + BFile file(elfFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BResources resources; + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + ReadResTest(resources, testResource1, true); + ReadResTest(resources, testResource2, true); + ReadResTest(resources, testResource3, true); + ReadResTest(resources, testResource4, false); + ReadResTest(resources, testResource5, false); + } + // ELF binary not containing resources + nextSubTest(); + { + BFile file(elfNoResFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BResources resources; + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + ReadResTest(resources, testResource1, false); + ReadResTest(resources, testResource2, false); + ReadResTest(resources, testResource3, false); + ReadResTest(resources, testResource4, false); + ReadResTest(resources, testResource5, false); + } + // PEF binary containing resources + nextSubTest(); + { + BFile file(pefFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BResources resources; + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + ReadResTest(resources, testResource1, true); + ReadResTest(resources, testResource2, true); + ReadResTest(resources, testResource3, true); + ReadResTest(resources, testResource4, false); + ReadResTest(resources, testResource5, false); + } + // PEF binary not containing resources + nextSubTest(); + { + BFile file(pefNoResFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BResources resources; + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + ReadResTest(resources, testResource1, false); + ReadResTest(resources, testResource2, false); + ReadResTest(resources, testResource3, false); + ReadResTest(resources, testResource4, false); + ReadResTest(resources, testResource5, false); + } + + // 2. PreloadResource() + // Hard to test: just preload all and check, if it still works. + nextSubTest(); + { + BFile file(x86ResFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BResources resources; + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + // non existing type + CPPUNIT_ASSERT( resources.PreloadResourceType(B_MESSENGER_TYPE) + == B_OK ); + // int32 type + CPPUNIT_ASSERT( resources.PreloadResourceType(B_INT32_TYPE) == B_OK ); + // all types + CPPUNIT_ASSERT( resources.PreloadResourceType() == B_OK ); + ReadResTest(resources, testResource1, true); + ReadResTest(resources, testResource2, true); + ReadResTest(resources, testResource3, true); + ReadResTest(resources, testResource4, false); + ReadResTest(resources, testResource5, false); + } + // uninitialized BResources + nextSubTest(); + { + BResources resources; + // int32 type + CPPUNIT_ASSERT( resources.PreloadResourceType(B_INT32_TYPE) == B_OK ); + // all types + CPPUNIT_ASSERT( resources.PreloadResourceType() == B_OK ); + } + + // 3. the index versions of GetResourceInfo() + // index only + nextSubTest(); + { + BFile file(x86ResFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BResources resources; + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + const ResourceInfo *resourceInfos[] = { + &testResource1, &testResource2, &testResource3 + }; + int32 resourceCount = sizeof(resourceInfos) / sizeof(ResourceInfo*); + for (int32 i = 0; i < resourceCount; i++) { + const ResourceInfo &info = *resourceInfos[i]; + type_code type; + int32 id; + const char *name; + size_t length; + CPPUNIT_ASSERT( resources.GetResourceInfo(i, &type, &id, &name, + &length) == true ); + CPPUNIT_ASSERT( id == info.id ); + CPPUNIT_ASSERT( type == info.type ); + CPPUNIT_ASSERT( name == NULL && info.name == NULL + || name != NULL && info.name != NULL + && !strcmp(name, info.name) ); + CPPUNIT_ASSERT( length == info.size ); + } + type_code type; + int32 id; + const char *name; + size_t length; + CPPUNIT_ASSERT( resources.GetResourceInfo(resourceCount, &type, &id, + &name, &length) == false ); + } + // type and index + nextSubTest(); + { + BFile file(x86ResFile, B_READ_WRITE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BResources resources; + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + CPPUNIT_ASSERT( resources.AddResource(testResource4.type, + testResource4.id, + testResource4.data, + testResource4.size, + testResource4.name) == B_OK ); + + const ResourceInfo *resourceInfos[] = { + &testResource1, &testResource4 + }; + int32 resourceCount = sizeof(resourceInfos) / sizeof(ResourceInfo*); + type_code type = resourceInfos[0]->type; + for (int32 i = 0; i < resourceCount; i++) { + const ResourceInfo &info = *resourceInfos[i]; + int32 id; + const char *name; + size_t length; + CPPUNIT_ASSERT( resources.GetResourceInfo(type, i, &id, &name, + &length) == true ); + CPPUNIT_ASSERT( id == info.id ); + CPPUNIT_ASSERT( type == info.type ); + CPPUNIT_ASSERT( name == NULL && info.name == NULL + || name != NULL && info.name != NULL + && !strcmp(name, info.name) ); + CPPUNIT_ASSERT( length == info.size ); + } + int32 id; + const char *name; + size_t length; + CPPUNIT_ASSERT( resources.GetResourceInfo(type, resourceCount, &id, + &name, &length) == false ); + } + + // 4. error cases + // non-resource file + nextSubTest(); + { + BResources resources; + BFile file(noResFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + CPPUNIT_ASSERT( equals(resources.SetTo(&file, false), B_ERROR, + B_IO_ERROR) ); + ReadBadResTest(resources, testResource1); + } + // uninitialized file + nextSubTest(); + { + BResources resources; + BFile file; + CPPUNIT_ASSERT( file.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_NO_INIT ); + ReadBadResTest(resources, testResource1); + } + // badly initialized file + nextSubTest(); + { + BResources resources; + BFile file(noSuchFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_ENTRY_NOT_FOUND ); + ReadBadResTest(resources, testResource1); + } + // NULL file + nextSubTest(); + { + BResources resources; + // R5: A NULL file is B_OK! +// CPPUNIT_ASSERT( resources.SetTo(NULL, false) == B_BAD_VALUE ); + CPPUNIT_ASSERT( resources.SetTo(NULL, false) == B_OK ); + ReadBadResTest(resources, testResource1); + } + // bad args + nextSubTest(); + { + BFile file(x86ResFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BResources resources; + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + const ResourceInfo &info = testResource1; + // GetResourceInfo() + CPPUNIT_ASSERT( resources.GetResourceInfo(info.type, info.id, + NULL, NULL) == true ); + CPPUNIT_ASSERT( resources.GetResourceInfo(info.type, info.name, + NULL, NULL) == true ); + CPPUNIT_ASSERT( resources.GetResourceInfo(0L, (type_code*)NULL, NULL, + NULL, NULL) == true ); + CPPUNIT_ASSERT( resources.GetResourceInfo(info.type, 0, NULL, + NULL, NULL) == true ); + // LoadResource + const void *data1 + = resources.LoadResource(info.type, info.id, NULL); + const void *data2 + = resources.LoadResource(info.type, info.name, NULL); + CPPUNIT_ASSERT( data1 != NULL && data2 != NULL ); + // ReadResource() + const int32 bufferSize = 1024; + status_t error = resources.ReadResource(info.type, info.id, NULL, + 0, bufferSize); + CPPUNIT_ASSERT( error == B_BAD_VALUE ); + // FindResource() + void *dataFound1 + = resources.FindResource(info.type, info.id, NULL); + void *dataFound2 + = resources.FindResource(info.type, info.name, NULL); + CPPUNIT_ASSERT( dataFound1 != NULL && dataFound2 != NULL ); + free(dataFound1); + free(dataFound2); + } +} + +// AddResources +static +void +AddResources(BResources &resources, const ResourceInfo *resourceInfos[], + int32 count) +{ + for (int32 i = 0; i < count; i++) { + const ResourceInfo &info = *resourceInfos[i]; + CPPUNIT_ASSERT( resources.AddResource(info.type, info.id, info.data, + info.size, info.name) == B_OK ); + } +} + +// CompareFiles +static +void +CompareFiles(BFile &file1, BFile &file2) +{ + off_t size1 = 0; + off_t size2 = 0; + CPPUNIT_ASSERT( file1.GetSize(&size1) == B_OK ); + CPPUNIT_ASSERT( file2.GetSize(&size2) == B_OK ); + CPPUNIT_ASSERT( size1 == size2 ); + char *buffer1 = new char[size1]; + char *buffer2 = new char[size2]; + CPPUNIT_ASSERT( file1.ReadAt(0, buffer1, size1) == size1 ); + CPPUNIT_ASSERT( file2.ReadAt(0, buffer2, size2) == size2 ); + for (int32 i = 0; i < size1; i++) + CPPUNIT_ASSERT( buffer1[i] == buffer2[i] ); + delete[] buffer1; + delete[] buffer2; +} + +// CompareResources +static +void +CompareResources(BResources &resources, const ResourceSet &resourceSet) +{ + // compare the count + int32 count = resourceSet.size(); + { + type_code type; + int32 id; + const char *name; + size_t length; + CPPUNIT_ASSERT( resources.GetResourceInfo(count, &type, &id, + &name, &length) == false ); + } + // => resources contains at most count resources. If it contains all the + // resources that are in resourceSet, then the sets are equal. + for (int32 i = 0; i < count; i++) { + const ResourceInfo &info = *resourceSet.infoAt(i); + const char *name; + size_t length; + CPPUNIT_ASSERT( resources.GetResourceInfo(info.type, info.id, &name, + &length) == true ); + CPPUNIT_ASSERT( name == NULL && info.name == NULL + || name != NULL && info.name != NULL + && !strcmp(name, info.name) ); + CPPUNIT_ASSERT( length == info.size ); + const void *data = resources.LoadResource(info.type, info.id, &length); + CPPUNIT_ASSERT( data != NULL && length == info.size ); + CPPUNIT_ASSERT( !memcmp(data, info.data, info.size) ); + } +} + +// AddResource +static +void +AddResource(BResources &resources, ResourceSet &resourceSet, + const ResourceInfo &info) +{ + resourceSet.add(&info); + CPPUNIT_ASSERT( resources.AddResource(info.type, info.id, info.data, + info.size, info.name) == B_OK ); + CompareResources(resources, resourceSet); +} + +// RemoveResource +static +void +RemoveResource(BResources &resources, ResourceSet &resourceSet, + const ResourceInfo &info, bool firstVersion) +{ + resourceSet.remove(&info); + if (firstVersion) { + CPPUNIT_ASSERT( resources.RemoveResource(info.type, info.id) == B_OK ); + } else { + size_t size; + const void *data = resources.LoadResource(info.type, info.id, &size); + CPPUNIT_ASSERT( data != NULL ); + CPPUNIT_ASSERT( resources.RemoveResource(data) == B_OK ); + } + CompareResources(resources, resourceSet); +} + +// ListResources +/*static +void +ListResources(BResources &resources) +{ + printf("Resources:\n"); + type_code type; + int32 id; + const char *name; + size_t size; + for (int32 i = 0; + resources.GetResourceInfo(i, &type, &id, &name, &size); + i++) { + type_code bigType = htonl(type); + printf("resource %2ld: type: `%.4s', id: %3ld, size: %5lu\n", i, + (char*)&bigType, id, size); + } +}*/ + +// SyncTest +void +ResourcesTest::SyncTest() +{ + // Sync() is not easy to test. We just check its return value for now. + nextSubTest(); + execCommand(string("cp ") + x86ResFile + " " + testFile1); + { + BFile file(testFile1, B_READ_WRITE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BResources resources; + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + // add a resource and Sync() + CPPUNIT_ASSERT( resources.AddResource(testResource4.type, + testResource4.id, + testResource4.data, + testResource4.size, + testResource4.name) == B_OK ); + CPPUNIT_ASSERT( resources.Sync() == B_OK ); + // remove a resource and Sync() + CPPUNIT_ASSERT( resources.RemoveResource(testResource1.type, + testResource1.id) == B_OK ); + CPPUNIT_ASSERT( resources.Sync() == B_OK ); + } + // error cases + // read only file + nextSubTest(); + { + BFile file(testFile1, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BResources resources; + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + CPPUNIT_ASSERT( resources.Sync() == B_NOT_ALLOWED ); + } + // uninitialized BResources + nextSubTest(); + { + BResources resources; + CPPUNIT_ASSERT( resources.Sync() == B_NO_INIT ); + } + // badly initialized BResources + nextSubTest(); + { + BFile file(noSuchFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_ENTRY_NOT_FOUND ); + BResources resources; + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( resources.Sync() == B_NO_INIT ); + } +} + +// MergeTest +void +ResourcesTest::MergeTest() +{ + // empty file, merge with resources from another file + nextSubTest(); + { + BFile file(testFile1, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BResources resources; + CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK ); + BFile file2(x86ResFile, B_READ_ONLY); + CPPUNIT_ASSERT( resources.MergeFrom(&file2) == B_OK ); + ResourceSet resourceSet; + resourceSet.add(&testResource1); + resourceSet.add(&testResource2); + resourceSet.add(&testResource3); + CompareResources(resources, resourceSet); + } + // empty file, add some resources first and then merge with resources + // from another file + nextSubTest(); + { + BFile file(testFile1, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BResources resources; + CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK ); + // add some resources + ResourceSet resourceSet; + AddResource(resources, resourceSet, testResource4); + AddResource(resources, resourceSet, testResource5); + AddResource(resources, resourceSet, testResource6); + // merge + BFile file2(x86ResFile, B_READ_ONLY); + CPPUNIT_ASSERT( resources.MergeFrom(&file2) == B_OK ); + resourceSet.add(&testResource1); // replaces testResource6 + resourceSet.add(&testResource2); + resourceSet.add(&testResource3); + CompareResources(resources, resourceSet); + } + // error cases + // bad args + nextSubTest(); + { + BFile file(testFile1, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BResources resources; + CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK ); + BFile file2(noResFile, B_READ_ONLY); + // non-resource file + CPPUNIT_ASSERT( resources.MergeFrom(&file2) == B_IO_ERROR ); + // NULL file +// R5: crashs +#if !SK_TEST_R5 + CPPUNIT_ASSERT( resources.MergeFrom(NULL) == B_BAD_VALUE ); +#endif + } + // uninitialized BResources + // R5: returns B_OK! + nextSubTest(); + { + BResources resources; + BFile file2(x86ResFile, B_READ_ONLY); + CPPUNIT_ASSERT( resources.MergeFrom(&file2) == B_OK ); + } + // badly initialized BResources + // R5: returns B_OK! + nextSubTest(); + { + BFile file(noSuchFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_ENTRY_NOT_FOUND ); + BResources resources; + CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_ENTRY_NOT_FOUND ); + BFile file2(x86ResFile, B_READ_ONLY); + CPPUNIT_ASSERT( resources.MergeFrom(&file2) == B_OK ); + } +} + +// WriteToTest +void +ResourcesTest::WriteToTest() +{ + // take a file with resources and write them to an empty file + nextSubTest(); + { + BFile file(x86ResFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BResources resources; + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + BFile file2(testFile1, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); + CPPUNIT_ASSERT( file2.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.WriteTo(&file2) == B_OK); + CPPUNIT_ASSERT( resources.File() == file2 ); + } + // take a file with resources and write them to an non-empty non-resource + // file + nextSubTest(); + { + BFile file(x86ResFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BResources resources; + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + BFile file2(noResFile, B_READ_WRITE); + CPPUNIT_ASSERT( file2.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.WriteTo(&file2) == B_IO_ERROR); + CPPUNIT_ASSERT( resources.File() == file2 ); + } + // take a file with resources and write them to an ELF file + nextSubTest(); + execCommand(string("cp ") + elfNoResFile + " " + testFile1); + { + BFile file(x86ResFile, B_READ_ONLY); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BResources resources; + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + BFile file2(testFile1, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); + CPPUNIT_ASSERT( file2.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.WriteTo(&file2) == B_OK); + CPPUNIT_ASSERT( resources.File() == file2 ); + } + // empty file, add a resource, write it to another file + nextSubTest(); + { + BFile file(testFile2, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BResources resources; + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + // add a resource + ResourceSet resourceSet; + AddResource(resources, resourceSet, testResource1); + // write to another file + BFile file2(testFile1, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); + CPPUNIT_ASSERT( file2.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.WriteTo(&file2) == B_OK); + CPPUNIT_ASSERT( resources.File() == file2 ); + // check, whether the first file has been modified -- it shouldn't be + off_t fileSize = 0; + CPPUNIT_ASSERT( file.GetSize(&fileSize) == B_OK ); + CPPUNIT_ASSERT( fileSize == 0 ); + } + // uninitialized BResources + nextSubTest(); + execCommand(string("cp ") + elfNoResFile + " " + testFile1); + { + BResources resources; + BFile file2(testFile1, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); + CPPUNIT_ASSERT( file2.InitCheck() == B_OK ); + CPPUNIT_ASSERT( resources.WriteTo(&file2) == B_OK); + CPPUNIT_ASSERT( resources.File() == file2 ); + } + // bad args: NULL file + // R5: crashs + nextSubTest(); + { + BFile file(testFile2, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BResources resources; + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); +#if !SK_TEST_R5 + CPPUNIT_ASSERT( resources.WriteTo(NULL) == B_BAD_VALUE); +#endif + } +} + +// AddRemoveTest +void +ResourcesTest::AddRemoveTest() +{ + // tests: + // * AddResource() + // * RemoveResource() + // * WriteResource() + + // Start with an empty file, add all the resources of our x86 resource + // file and compare the two bytewise. + // This does of course only work on x86 machines. + nextSubTest(); + { + BFile file(testFile1, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BResources resources; + CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK ); + const ResourceInfo *resourceInfos[] = { + &testResource1, &testResource2, &testResource3 + }; + int32 resourceCount = sizeof(resourceInfos) / sizeof(ResourceInfo*); + AddResources(resources, resourceInfos, resourceCount); + } + { + BFile file1(testFile1, B_READ_ONLY); + BFile file2(x86ResFile, B_READ_ONLY); + CompareFiles(file1, file2); + } + // Now remove all resources and compare the file with an empty resource + // file. + nextSubTest(); + { + BFile file(testFile1, B_READ_WRITE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BResources resources; + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + const ResourceInfo *resourceInfos[] = { + &testResource1, &testResource2, &testResource3 + }; + int32 resourceCount = sizeof(resourceInfos) / sizeof(ResourceInfo*); + for (int32 i = 0; i < resourceCount; i++) { + const ResourceInfo &info = *resourceInfos[i]; + CPPUNIT_ASSERT( resources.RemoveResource(info.type, info.id) + == B_OK ); + } + BFile file2(testFile2, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); + BResources resources2; + CPPUNIT_ASSERT( resources2.SetTo(&file2, true) == B_OK ); + } + { + BFile file1(testFile1, B_READ_ONLY); + BFile file2(testFile2, B_READ_ONLY); + CompareFiles(file1, file2); + } + // Same file, use the other remove version. + nextSubTest(); + execCommand(string("cp ") + x86ResFile + " " + testFile1); + { + BFile file(testFile1, B_READ_WRITE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BResources resources; + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + const ResourceInfo *resourceInfos[] = { + &testResource1, &testResource2, &testResource3 + }; + int32 resourceCount = sizeof(resourceInfos) / sizeof(ResourceInfo*); + for (int32 i = 0; i < resourceCount; i++) { + const ResourceInfo &info = *resourceInfos[i]; + size_t size; + const void *data = resources.LoadResource(info.type, info.id, + &size); + CPPUNIT_ASSERT( data != NULL ); + CPPUNIT_ASSERT( resources.RemoveResource(data) == B_OK ); + } + } + { + BFile file1(testFile1, B_READ_ONLY); + BFile file2(testFile2, B_READ_ONLY); + CompareFiles(file1, file2); + } + // some arbitrary adding and removing... + nextSubTest(); + { + BFile file(testFile1, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BResources resources; + CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK ); + ResourceSet resourceSet; + AddResource(resources, resourceSet, testResource1); + AddResource(resources, resourceSet, testResource2); + RemoveResource(resources, resourceSet, testResource1, true); + AddResource(resources, resourceSet, testResource3); + AddResource(resources, resourceSet, testResource4); + RemoveResource(resources, resourceSet, testResource3, false); + AddResource(resources, resourceSet, testResource5); + AddResource(resources, resourceSet, testResource1); + AddResource(resources, resourceSet, testResource6); // replaces 1 + RemoveResource(resources, resourceSet, testResource2, true); + RemoveResource(resources, resourceSet, testResource5, false); + RemoveResource(resources, resourceSet, testResource6, true); + RemoveResource(resources, resourceSet, testResource4, false); + } + // bad args + nextSubTest(); + { + BFile file(testFile1, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BResources resources; + CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK ); + CPPUNIT_ASSERT( resources.RemoveResource(NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( resources.RemoveResource(B_INT32_TYPE, 0) + == B_BAD_VALUE ); + CPPUNIT_ASSERT( resources.AddResource(B_INT32_TYPE, 0, NULL, 7, + "Hey!") == B_BAD_VALUE ); + } + // uninitialized BResources + nextSubTest(); + { + BResources resources; + const ResourceInfo &info = testResource1; + CPPUNIT_ASSERT( resources.AddResource(info.type, info.id, info.data, + info.size, info.name) + == B_OK ); + } +} + +// ReadWriteTest +void +ResourcesTest::ReadWriteTest() +{ + // ReadResource() has already been tested in ReadTest(). Thus we focus on + // WriteResource(). + // Open a file and write a little bit into one of its resources. + nextSubTest(); + execCommand(string("cp ") + x86ResFile + " " + testFile1); + { + BFile file(testFile1, B_READ_WRITE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BResources resources; + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + const ResourceInfo &info = testResource1; + type_code type = info.type; + int32 id = info.id; + // write at the beginning of the resource + char writeBuffer[1024]; + for (int32 i = 0; i < 1024; i++) + writeBuffer[i] = i & 0xff; + char readBuffer[1024]; + memset(readBuffer, 0, 1024); + CPPUNIT_ASSERT( resources.WriteResource(type, id, writeBuffer, 0, 10) + == B_OK ); + size_t length; + const void *data = resources.LoadResource(type, id, &length); + CPPUNIT_ASSERT( data != NULL && length == info.size ); + CPPUNIT_ASSERT( !memcmp(data, writeBuffer, 10) ); + CPPUNIT_ASSERT( !memcmp((const char*)data + 10, info.data + 10, + info.size - 10) ); + // completely overwrite the resource with the former data + CPPUNIT_ASSERT( resources.WriteResource(type, id, info.data, 0, + info.size) == B_OK ); + data = resources.LoadResource(type, id, &length); + CPPUNIT_ASSERT( data != NULL && length == info.size ); + CPPUNIT_ASSERT( !memcmp(data, info.data, info.size) ); + // write something in the middle + size_t offset = (info.size - 2) / 2; + CPPUNIT_ASSERT( resources.WriteResource(type, id, writeBuffer, offset, + 2) == B_OK ); + data = resources.LoadResource(type, id, &length); + CPPUNIT_ASSERT( data != NULL && length == info.size ); + CPPUNIT_ASSERT( !memcmp(data, info.data, offset) ); + CPPUNIT_ASSERT( !memcmp((const char*)data + offset, writeBuffer, 2) ); + CPPUNIT_ASSERT( !memcmp((const char*)data + offset + 2, + info.data + offset + 2, + info.size - offset - 2) ); + // write starting inside the resource, but extending it + size_t writeSize = info.size + 3; + CPPUNIT_ASSERT( resources.WriteResource(type, id, writeBuffer, offset, + writeSize) == B_OK ); + data = resources.LoadResource(type, id, &length); + CPPUNIT_ASSERT( data != NULL && length == (size_t)offset + writeSize ); + CPPUNIT_ASSERT( !memcmp(data, info.data, offset) ); + CPPUNIT_ASSERT( !memcmp((const char*)data + offset, writeBuffer, + writeSize) ); + // write past the end of the resource + size_t newOffset = length + 30; + size_t newWriteSize = 17; + CPPUNIT_ASSERT( resources.WriteResource(type, id, writeBuffer, + newOffset, newWriteSize) + == B_OK ); + data = resources.LoadResource(type, id, &length); + CPPUNIT_ASSERT( data != NULL && length == newOffset + newWriteSize ); + CPPUNIT_ASSERT( !memcmp(data, info.data, offset) ); + CPPUNIT_ASSERT( !memcmp((const char*)data + offset, writeBuffer, + writeSize) ); + // [offset + writeSize, newOffset) unspecified + CPPUNIT_ASSERT( !memcmp((const char*)data + newOffset, writeBuffer, + newWriteSize) ); + } + // error cases + // bad args + nextSubTest(); + { + BFile file(testFile1, B_READ_WRITE); + CPPUNIT_ASSERT( file.InitCheck() == B_OK ); + BResources resources; + CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK ); + const ResourceInfo &info = testResource1; + type_code type = info.type; + int32 id = info.id; + // NULL buffer + CPPUNIT_ASSERT( resources.WriteResource(type, id, NULL, 0, 10) + == B_BAD_VALUE ); + // non existing resource + char writeBuffer[1024]; + CPPUNIT_ASSERT( resources.WriteResource(B_MESSENGER_TYPE, 0, + writeBuffer, 0, 10) + == B_BAD_VALUE ); + } + // uninitialized BResources + nextSubTest(); + { + BResources resources; + const ResourceInfo &info = testResource1; + type_code type = info.type; + int32 id = info.id; + char writeBuffer[1024]; + CPPUNIT_ASSERT( resources.WriteResource(type, id, writeBuffer, 0, 10) + == B_BAD_VALUE ); + } +} + diff --git a/src/tests/kits/storage/ResourcesTest.h b/src/tests/kits/storage/ResourcesTest.h new file mode 100644 index 0000000000..374de773c3 --- /dev/null +++ b/src/tests/kits/storage/ResourcesTest.h @@ -0,0 +1,39 @@ +// ResourcesTest.h + +#ifndef __sk_resources_test_h__ +#define __sk_resources_test_h__ + +#include +#include + +#include +#include + +#include "BasicTest.h" + +class ResourcesTest : public BasicTest +{ +public: + static CppUnit::Test* Suite(); + + // This function called before *each* test added in Suite() + void setUp(); + + // This function called after *each* test added in Suite() + void tearDown(); + + //------------------------------------------------------------ + // Test functions + //------------------------------------------------------------ + void InitTest(); + void ReadTest(); + void SyncTest(); + void MergeTest(); + void WriteToTest(); + void AddRemoveTest(); + void GetInfoTest(); + void ReadWriteTest(); +}; + + +#endif // __sk_resources_test_h__ diff --git a/src/tests/kits/storage/StatableTest.cpp b/src/tests/kits/storage/StatableTest.cpp new file mode 100644 index 0000000000..1eacc06fda --- /dev/null +++ b/src/tests/kits/storage/StatableTest.cpp @@ -0,0 +1,255 @@ +// StatableTest.cpp + +#include + +#include +#include + +#include +#include +#include +#include + +#include "StatableTest.h" + +// setUp +void +StatableTest::setUp() +{ + BasicTest::setUp(); +} + +// tearDown +void +StatableTest::tearDown() +{ + BasicTest::tearDown(); +} + +// GetStatTest +void +StatableTest::GetStatTest() +{ + TestStatables testEntries; + BStatable *statable; + string entryName; + // existing entries + nextSubTest(); + CreateROStatables(testEntries); + for (testEntries.rewind(); testEntries.getNext(statable, entryName); ) { + struct stat st1, st2; + CPPUNIT_ASSERT( statable->GetStat(&st1) == B_OK ); + CPPUNIT_ASSERT( lstat(entryName.c_str(), &st2) == 0 ); + CPPUNIT_ASSERT( st1 == st2 ); + } + testEntries.delete_all(); + // uninitialized objects + nextSubTest(); + CreateUninitializedStatables(testEntries); + for (testEntries.rewind(); testEntries.getNext(statable, entryName); ) { + struct stat st1; + CPPUNIT_ASSERT( statable->GetStat(&st1) == B_NO_INIT ); + } + testEntries.delete_all(); + // bad args + nextSubTest(); + CreateROStatables(testEntries); + for (testEntries.rewind(); testEntries.getNext(statable, entryName); ) + CPPUNIT_ASSERT( statable->GetStat(NULL) != B_OK ); + testEntries.delete_all(); +} + +// IsXYZTest +void +StatableTest::IsXYZTest() +{ + TestStatables testEntries; + BStatable *statable; + string entryName; + // existing entries + nextSubTest(); + CreateROStatables(testEntries); + for (testEntries.rewind(); testEntries.getNext(statable, entryName); ) { + struct stat st; + CPPUNIT_ASSERT( lstat(entryName.c_str(), &st) == 0 ); + CPPUNIT_ASSERT( statable->IsDirectory() == S_ISDIR(st.st_mode) ); + CPPUNIT_ASSERT( statable->IsFile() == S_ISREG(st.st_mode) ); + CPPUNIT_ASSERT( statable->IsSymLink() == S_ISLNK(st.st_mode) ); + } + testEntries.delete_all(); + // uninitialized objects + nextSubTest(); + CreateUninitializedStatables(testEntries); + for (testEntries.rewind(); testEntries.getNext(statable, entryName); ) { + CPPUNIT_ASSERT( statable->IsDirectory() == false ); + CPPUNIT_ASSERT( statable->IsFile() == false ); + CPPUNIT_ASSERT( statable->IsSymLink() == false ); + } + testEntries.delete_all(); +} + +// GetXYZTest +void +StatableTest::GetXYZTest() +{ + TestStatables testEntries; + BStatable *statable; + string entryName; + // test with existing entries + nextSubTest(); + CreateROStatables(testEntries); + for (testEntries.rewind(); testEntries.getNext(statable, entryName); ) { + struct stat st; + node_ref ref; + uid_t owner; + gid_t group; + mode_t perms; + off_t size; + time_t mtime; + time_t ctime; +// R5: access time unused +#if !SK_TEST_R5 && !SK_TEST_OBOS_POSIX + time_t atime; +#endif + BVolume volume; + CPPUNIT_ASSERT( lstat(entryName.c_str(), &st) == 0 ); + CPPUNIT_ASSERT( statable->GetNodeRef(&ref) == B_OK ); + CPPUNIT_ASSERT( statable->GetOwner(&owner) == B_OK ); + CPPUNIT_ASSERT( statable->GetGroup(&group) == B_OK ); + CPPUNIT_ASSERT( statable->GetPermissions(&perms) == B_OK ); + CPPUNIT_ASSERT( statable->GetSize(&size) == B_OK ); + CPPUNIT_ASSERT( statable->GetModificationTime(&mtime) == B_OK ); + CPPUNIT_ASSERT( statable->GetCreationTime(&ctime) == B_OK ); +#if !SK_TEST_R5 && !SK_TEST_OBOS_POSIX + CPPUNIT_ASSERT( statable->GetAccessTime(&atime) == B_OK ); +#endif + CPPUNIT_ASSERT( statable->GetVolume(&volume) == B_OK ); + CPPUNIT_ASSERT( ref.device == st.st_dev && ref.node == st.st_ino ); + CPPUNIT_ASSERT( owner == st.st_uid ); + CPPUNIT_ASSERT( group == st.st_gid ); +// R5: returns not only the permission bits, so we need to filter for the test +// CPPUNIT_ASSERT( perms == (st.st_mode & S_IUMSK) ); + CPPUNIT_ASSERT( (perms & S_IUMSK) == (st.st_mode & S_IUMSK) ); + CPPUNIT_ASSERT( size == st.st_size ); + CPPUNIT_ASSERT( mtime == st.st_mtime ); + CPPUNIT_ASSERT( ctime == st.st_crtime ); +#if !SK_TEST_R5 && !SK_TEST_OBOS_POSIX + CPPUNIT_ASSERT( atime == st.st_atime ); +#endif +// OBOS: BVolume::==() is not implemented yet +#if !SK_TEST_OBOS_POSIX + CPPUNIT_ASSERT( volume == BVolume(st.st_dev) ); +#endif + } + testEntries.delete_all(); + // test with uninitialized objects + nextSubTest(); + CreateUninitializedStatables(testEntries); + for (testEntries.rewind(); testEntries.getNext(statable, entryName); ) { + node_ref ref; + uid_t owner; + gid_t group; + mode_t perms; + off_t size; + time_t mtime; + time_t ctime; + time_t atime; + BVolume volume; + CPPUNIT_ASSERT( statable->GetNodeRef(&ref) == B_NO_INIT ); + CPPUNIT_ASSERT( statable->GetOwner(&owner) == B_NO_INIT ); + CPPUNIT_ASSERT( statable->GetGroup(&group) == B_NO_INIT ); + CPPUNIT_ASSERT( statable->GetPermissions(&perms) == B_NO_INIT ); + CPPUNIT_ASSERT( statable->GetSize(&size) == B_NO_INIT ); + CPPUNIT_ASSERT( statable->GetModificationTime(&mtime) == B_NO_INIT ); + CPPUNIT_ASSERT( statable->GetCreationTime(&ctime) == B_NO_INIT ); + CPPUNIT_ASSERT( statable->GetAccessTime(&atime) == B_NO_INIT ); + CPPUNIT_ASSERT( statable->GetVolume(&volume) == B_NO_INIT ); + } + testEntries.delete_all(); + // bad args + nextSubTest(); + CreateROStatables(testEntries); + for (testEntries.rewind(); testEntries.getNext(statable, entryName); ) { +// R5: crashs, if passing NULL to any of these methods +#if !SK_TEST_R5 + CPPUNIT_ASSERT( statable->GetNodeRef(NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( statable->GetOwner(NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( statable->GetGroup(NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( statable->GetPermissions(NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( statable->GetSize(NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( statable->GetModificationTime(NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( statable->GetCreationTime(NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( statable->GetAccessTime(NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( statable->GetVolume(NULL) == B_BAD_VALUE ); +#endif + } + testEntries.delete_all(); +} + +// SetXYZTest +void +StatableTest::SetXYZTest() +{ + TestStatables testEntries; + BStatable *statable; + string entryName; + // test with existing entries + nextSubTest(); + CreateRWStatables(testEntries); + for (testEntries.rewind(); testEntries.getNext(statable, entryName); ) { + struct stat st; + uid_t owner = 0xdad; + gid_t group = 0xdee; +// OBOS: no fchmod(), no FD time setters +#if !SK_TEST_OBOS_POSIX + mode_t perms = 0x0ab; // -w- r-x -wx -- unusual enough? ;-) + time_t mtime = 1234567; + time_t ctime = 654321; +#endif +// R5: access time unused +#if !SK_TEST_R5 && !SK_TEST_OBOS_POSIX + time_t atime = 2345678; +#endif +// OBOS: no fchmod(), no FD time setters + CPPUNIT_ASSERT( statable->SetOwner(owner) == B_OK ); + CPPUNIT_ASSERT( statable->SetGroup(group) == B_OK ); +#if !SK_TEST_OBOS_POSIX + CPPUNIT_ASSERT( statable->SetPermissions(perms) == B_OK ); + CPPUNIT_ASSERT( statable->SetModificationTime(mtime) == B_OK ); + CPPUNIT_ASSERT( statable->SetCreationTime(ctime) == B_OK ); +#endif +#if !SK_TEST_R5 && !SK_TEST_OBOS_POSIX + CPPUNIT_ASSERT( statable->SetAccessTime(atime) == B_OK ); +#endif + CPPUNIT_ASSERT( lstat(entryName.c_str(), &st) == 0 ); + CPPUNIT_ASSERT( owner == st.st_uid ); + CPPUNIT_ASSERT( group == st.st_gid ); +#if !SK_TEST_OBOS_POSIX + CPPUNIT_ASSERT( perms == (st.st_mode & S_IUMSK) ); + CPPUNIT_ASSERT( mtime == st.st_mtime ); + CPPUNIT_ASSERT( ctime == st.st_crtime ); +#endif +#if !SK_TEST_R5 && !SK_TEST_OBOS_POSIX + CPPUNIT_ASSERT( atime == st.st_atime ); +#endif + } + testEntries.delete_all(); + // test with uninitialized objects + nextSubTest(); + CreateUninitializedStatables(testEntries); + for (testEntries.rewind(); testEntries.getNext(statable, entryName); ) { + uid_t owner = 0xdad; + gid_t group = 0xdee; + mode_t perms = 0x0ab; // -w- r-x -wx -- unusual enough? ;-) + time_t mtime = 1234567; + time_t ctime = 654321; + time_t atime = 2345678; + CPPUNIT_ASSERT( statable->SetOwner(owner) != B_OK ); + CPPUNIT_ASSERT( statable->SetGroup(group) != B_OK ); + CPPUNIT_ASSERT( statable->SetPermissions(perms) != B_OK ); + CPPUNIT_ASSERT( statable->SetModificationTime(mtime) != B_OK ); + CPPUNIT_ASSERT( statable->SetCreationTime(ctime) != B_OK ); + CPPUNIT_ASSERT( statable->SetAccessTime(atime) != B_OK ); + } + testEntries.delete_all(); +} diff --git a/src/tests/kits/storage/StatableTest.h b/src/tests/kits/storage/StatableTest.h new file mode 100644 index 0000000000..88129f05c5 --- /dev/null +++ b/src/tests/kits/storage/StatableTest.h @@ -0,0 +1,122 @@ +// StatableTest.h + +#ifndef __sk_statable_test_h__ +#define __sk_statable_test_h__ + +#include +#include + +#include "BasicTest.h" + +// TestEntries + +template +struct TestEntries +{ + ~TestEntries() + { + delete_all(); + } + + void delete_all() + { + for (list::iterator it = entries.begin(); + it != entries.end(); + it++) { + // Arghh, BStatable has no virtual destructor! + // Workaround: try to cast to one of the subclasses + if (BNode *node = dynamic_cast(*it)) + delete node; + else if (BEntry *entry = dynamic_cast(*it)) + delete entry; + else + delete *it; + } + clear(); + } + + void clear() + { + entries.clear(); + entryNames.clear(); + rewind(); + } + + void add(C *entry, string entryName) + { + entries.push_back(entry); + entryNames.push_back(entryName); + } + + bool getNext(C *&entry, string &entryName) + { + bool result = (entryIt != entries.end() + && entryNameIt != entryNames.end()); + if (result) { + entry = *entryIt; + entryName = *entryNameIt; + entryIt++; + entryNameIt++; + } + return result; + } + + void rewind() + { + entryIt = entries.begin(); + entryNameIt = entryNames.begin(); + } + + list entries; + list entryNames; + list::iterator entryIt; + list::iterator entryNameIt; +}; + +typedef TestEntries TestStatables; + + +// StatableTest + +class StatableTest : public BasicTest +{ +public: + template + static inline void AddBaseClassTests(const char *prefix, + CppUnit::TestSuite *suite); + + virtual void CreateROStatables(TestStatables& testEntries) = 0; + virtual void CreateRWStatables(TestStatables& testEntries) = 0; + virtual void CreateUninitializedStatables(TestStatables& testEntries) = 0; + + // This function called before *each* test added in Suite() + void setUp(); + + // This function called after *each* test added in Suite() + void tearDown(); + + void GetStatTest(); + void IsXYZTest(); + void GetXYZTest(); + void SetXYZTest(); +}; + +// AddBaseClassTests +template +inline void +StatableTest::AddBaseClassTests(const char *prefix, CppUnit::TestSuite *suite) +{ + typedef CppUnit::TestCaller TC; + string p(prefix); + + suite->addTest( new TC(p + "BStatable::GetStat Test", + &StatableTest::GetStatTest) ); + suite->addTest( new TC(p + "BStatable::IsXYZ Test", + &StatableTest::IsXYZTest) ); + suite->addTest( new TC(p + "BStatable::GetXYZ Test", + &StatableTest::GetXYZTest) ); + suite->addTest( new TC(p + "BStatable::SetXYZ Test", + &StatableTest::SetXYZTest) ); +} + +#endif // __sk_statable_test_h__ diff --git a/src/tests/kits/storage/SymLinkTest.cpp b/src/tests/kits/storage/SymLinkTest.cpp new file mode 100644 index 0000000000..d272e8984d --- /dev/null +++ b/src/tests/kits/storage/SymLinkTest.cpp @@ -0,0 +1,906 @@ +// SymLinkTest.cpp + +#include +#include + +#include +#include +#include +#include + +#include "Test.StorageKit.h" +#include "SymLinkTest.h" + +// Suite +SymLinkTest::Test* +SymLinkTest::Suite() +{ + CppUnit::TestSuite *suite = new CppUnit::TestSuite(); + typedef CppUnit::TestCaller TC; + + NodeTest::AddBaseClassTests("BSymLink::", suite); + + suite->addTest( new TC("BSymLink::Init Test 1", &SymLinkTest::InitTest1) ); + suite->addTest( new TC("BSymLink::Init Test 2", &SymLinkTest::InitTest2) ); + suite->addTest( new TC("BSymLink::ReadLink Test", + &SymLinkTest::ReadLinkTest) ); + suite->addTest( new TC("BSymLink::MakeLinkedPath Test", + &SymLinkTest::MakeLinkedPathTest) ); + suite->addTest( new TC("BSymLink::IsAbsolute Test", + &SymLinkTest::IsAbsoluteTest) ); + suite->addTest( new TC("BSymLink::Assignment Test", + &SymLinkTest::AssignmentTest) ); + + return suite; +} + +// CreateRONodes +void +SymLinkTest::CreateRONodes(TestNodes& testEntries) +{ + testEntries.clear(); + const char *filename; + filename = "/tmp"; + testEntries.add(new BSymLink(filename), filename); + filename = dirLinkname; + testEntries.add(new BSymLink(filename), filename); + filename = fileLinkname; + testEntries.add(new BSymLink(filename), filename); + filename = badLinkname; + testEntries.add(new BSymLink(filename), filename); + filename = cyclicLinkname1; + testEntries.add(new BSymLink(filename), filename); +} + +// CreateRWNodes +void +SymLinkTest::CreateRWNodes(TestNodes& testEntries) +{ + testEntries.clear(); + const char *filename; + filename = dirLinkname; + testEntries.add(new BSymLink(filename), filename); + filename = fileLinkname; + testEntries.add(new BSymLink(filename), filename); +} + +// CreateUninitializedNodes +void +SymLinkTest::CreateUninitializedNodes(TestNodes& testEntries) +{ + testEntries.clear(); + testEntries.add(new BSymLink, ""); +} + +// setUp +void SymLinkTest::setUp() +{ + NodeTest::setUp(); +} + +// tearDown +void SymLinkTest::tearDown() +{ + NodeTest::tearDown(); +} + +// InitTest1 +void +SymLinkTest::InitTest1() +{ + const char *dirLink = dirLinkname; + const char *dirSuperLink = dirSuperLinkname; + const char *dirRelLink = dirRelLinkname; + const char *fileLink = fileLinkname; + const char *existingDir = existingDirname; + const char *existingSuperDir = existingSuperDirname; + const char *existingRelDir = existingRelDirname; + const char *existingFile = existingFilename; + const char *existingSuperFile = existingSuperFilename; + const char *existingRelFile = existingRelFilename; + const char *nonExisting = nonExistingDirname; + const char *nonExistingSuper = nonExistingSuperDirname; + const char *nonExistingRel = nonExistingRelDirname; + // 1. default constructor + nextSubTest(); + { + BSymLink link; + CPPUNIT_ASSERT( link.InitCheck() == B_NO_INIT ); + } + + // 2. BSymLink(const char*) + nextSubTest(); + { + BSymLink link(fileLink); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + } + nextSubTest(); + { + BSymLink link(nonExisting); + CPPUNIT_ASSERT( link.InitCheck() == B_ENTRY_NOT_FOUND ); + } + nextSubTest(); + { + BSymLink link((const char *)NULL); + CPPUNIT_ASSERT( equals(link.InitCheck(), B_BAD_VALUE, B_NO_INIT) ); + } + nextSubTest(); + { + BSymLink link(""); + CPPUNIT_ASSERT( link.InitCheck() == B_ENTRY_NOT_FOUND ); + } + nextSubTest(); + { + BSymLink link(existingFile); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + } + nextSubTest(); + { + BSymLink link(existingDir); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + } + nextSubTest(); + { + BSymLink link(tooLongEntryname); + CPPUNIT_ASSERT( link.InitCheck() == B_NAME_TOO_LONG ); + } + + // 3. BSymLink(const BEntry*) + nextSubTest(); + { + BEntry entry(dirLink); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + BSymLink link(&entry); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + } + nextSubTest(); + { + BEntry entry(nonExisting); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + BSymLink link(&entry); + CPPUNIT_ASSERT( link.InitCheck() == B_ENTRY_NOT_FOUND ); + } + nextSubTest(); + { + BSymLink link((BEntry *)NULL); + CPPUNIT_ASSERT( link.InitCheck() == B_BAD_VALUE ); + } + nextSubTest(); + { + BEntry entry; + BSymLink link(&entry); + CPPUNIT_ASSERT( equals(link.InitCheck(), B_BAD_ADDRESS, B_BAD_VALUE) ); + } + nextSubTest(); + { + BEntry entry(existingFile); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + BSymLink link(&entry); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + + } + nextSubTest(); + { + BEntry entry(existingDir); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + BSymLink link(&entry); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + + } + nextSubTest(); + { + BEntry entry(tooLongEntryname); + // R5 returns E2BIG instead of B_NAME_TOO_LONG + CPPUNIT_ASSERT( equals(entry.InitCheck(), E2BIG, B_NAME_TOO_LONG) ); + BSymLink link(&entry); + CPPUNIT_ASSERT( equals(link.InitCheck(), B_BAD_ADDRESS, B_BAD_VALUE) ); + } + + // 4. BSymLink(const entry_ref*) + nextSubTest(); + { + BEntry entry(dirLink); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + entry_ref ref; + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + BSymLink link(&ref); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + } + nextSubTest(); + { + BEntry entry(nonExisting); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + entry_ref ref; + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + BSymLink link(&ref); + CPPUNIT_ASSERT( link.InitCheck() == B_ENTRY_NOT_FOUND ); + } + nextSubTest(); + { + BSymLink link((entry_ref *)NULL); + CPPUNIT_ASSERT( link.InitCheck() == B_BAD_VALUE ); + } + nextSubTest(); + { + BEntry entry(existingFile); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + entry_ref ref; + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + BSymLink link(&ref); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + } + nextSubTest(); + { + BEntry entry(existingDir); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + entry_ref ref; + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + BSymLink link(&ref); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + } + + // 5. BSymLink(const BDirectory*, const char*) + nextSubTest(); + { + BDirectory pathDir(dirSuperLink); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + BSymLink link(&pathDir, dirRelLink); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + } + nextSubTest(); + { + BDirectory pathDir(dirSuperLink); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + BSymLink link(&pathDir, dirLink); + CPPUNIT_ASSERT( link.InitCheck() == B_BAD_VALUE ); + } + nextSubTest(); + { + BDirectory pathDir(nonExistingSuper); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + BSymLink link(&pathDir, nonExistingRel); + CPPUNIT_ASSERT( link.InitCheck() == B_ENTRY_NOT_FOUND ); + } + nextSubTest(); + { + BSymLink link((BDirectory *)NULL, (const char *)NULL); + CPPUNIT_ASSERT( link.InitCheck() == B_BAD_VALUE ); + } + nextSubTest(); + { + BSymLink link((BDirectory *)NULL, dirLink); + CPPUNIT_ASSERT( link.InitCheck() == B_BAD_VALUE ); + } + nextSubTest(); + { + BDirectory pathDir(dirSuperLink); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + BSymLink link(&pathDir, (const char *)NULL); + CPPUNIT_ASSERT( link.InitCheck() == B_BAD_VALUE ); + } + nextSubTest(); + { + BDirectory pathDir(dirSuperLink); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + BSymLink link(&pathDir, ""); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + } + nextSubTest(); + { + BDirectory pathDir(existingSuperFile); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + BSymLink link(&pathDir, existingRelFile); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + } + nextSubTest(); + { + BDirectory pathDir(existingSuperDir); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + BSymLink link(&pathDir, existingRelDir); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + } + nextSubTest(); + { + BDirectory pathDir(tooLongSuperEntryname); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + BSymLink link(&pathDir, tooLongRelEntryname); + CPPUNIT_ASSERT( link.InitCheck() == B_NAME_TOO_LONG ); + } + nextSubTest(); + { + BDirectory pathDir(fileSuperDirname); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + BSymLink link(&pathDir, fileRelDirname); + CPPUNIT_ASSERT( link.InitCheck() == B_ENTRY_NOT_FOUND ); + } +} + +// InitTest2 +void +SymLinkTest::InitTest2() +{ + const char *dirLink = dirLinkname; + const char *dirSuperLink = dirSuperLinkname; + const char *dirRelLink = dirRelLinkname; + const char *fileLink = fileLinkname; + const char *existingDir = existingDirname; + const char *existingSuperDir = existingSuperDirname; + const char *existingRelDir = existingRelDirname; + const char *existingFile = existingFilename; + const char *existingSuperFile = existingSuperFilename; + const char *existingRelFile = existingRelFilename; + const char *nonExisting = nonExistingDirname; + const char *nonExistingSuper = nonExistingSuperDirname; + const char *nonExistingRel = nonExistingRelDirname; + BSymLink link; + // 2. BSymLink(const char*) + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo(fileLink) == B_OK ); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + // + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo(nonExisting) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( link.InitCheck() == B_ENTRY_NOT_FOUND ); + // + nextSubTest(); + CPPUNIT_ASSERT( equals(link.SetTo((const char *)NULL), B_BAD_VALUE, + B_NO_INIT) ); + CPPUNIT_ASSERT( equals(link.InitCheck(), B_BAD_VALUE, B_NO_INIT) ); + // + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo("") == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( link.InitCheck() == B_ENTRY_NOT_FOUND ); + // + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo(existingFile) == B_OK ); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + // + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo(existingDir) == B_OK ); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + // + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo(tooLongEntryname) == B_NAME_TOO_LONG ); + CPPUNIT_ASSERT( link.InitCheck() == B_NAME_TOO_LONG ); + + // 3. BSymLink(const BEntry*) + nextSubTest(); + BEntry entry(dirLink); + CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); + CPPUNIT_ASSERT( link.SetTo(&entry) == B_OK ); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + // + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(nonExisting) == B_OK ); + CPPUNIT_ASSERT( link.SetTo(&entry) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( link.InitCheck() == B_ENTRY_NOT_FOUND ); + // + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo((BEntry *)NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( link.InitCheck() == B_BAD_VALUE ); + // + nextSubTest(); + entry.Unset(); + CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( equals(link.SetTo(&entry), B_BAD_ADDRESS, B_BAD_VALUE) ); + CPPUNIT_ASSERT( equals(link.InitCheck(), B_BAD_ADDRESS, B_BAD_VALUE) ); + // + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(existingFile) == B_OK ); + CPPUNIT_ASSERT( link.SetTo(&entry) == B_OK ); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + // + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(existingDir) == B_OK ); + CPPUNIT_ASSERT( link.SetTo(&entry) == B_OK ); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + // + nextSubTest(); + // R5 returns E2BIG instead of B_NAME_TOO_LONG + CPPUNIT_ASSERT( equals(entry.SetTo(tooLongEntryname), E2BIG, + B_NAME_TOO_LONG) ); + CPPUNIT_ASSERT( equals(link.SetTo(&entry), B_BAD_ADDRESS, B_BAD_VALUE) ); + CPPUNIT_ASSERT( equals(link.InitCheck(), B_BAD_ADDRESS, B_BAD_VALUE) ); + + // 4. BSymLink(const entry_ref*) + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(dirLink) == B_OK ); + entry_ref ref; + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + CPPUNIT_ASSERT( link.SetTo(&ref) == B_OK ); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + // + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(nonExisting) == B_OK ); + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + CPPUNIT_ASSERT( link.SetTo(&ref) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( link.InitCheck() == B_ENTRY_NOT_FOUND ); + // + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo((entry_ref *)NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( link.InitCheck() == B_BAD_VALUE ); + // + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(existingFile) == B_OK ); + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + CPPUNIT_ASSERT( link.SetTo(&ref) == B_OK ); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + // + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(existingDir) == B_OK ); + CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK ); + CPPUNIT_ASSERT( link.SetTo(&ref) == B_OK ); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + + // 5. BSymLink(const BDirectory*, const char*) + nextSubTest(); + BDirectory pathDir(dirSuperLink); + CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK ); + CPPUNIT_ASSERT( link.SetTo(&pathDir, dirRelLink) == B_OK ); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + // + nextSubTest(); + CPPUNIT_ASSERT( pathDir.SetTo(dirSuperLink) == B_OK ); + CPPUNIT_ASSERT( link.SetTo(&pathDir, dirLink) == B_BAD_VALUE ); + CPPUNIT_ASSERT( link.InitCheck() == B_BAD_VALUE ); + // + nextSubTest(); + CPPUNIT_ASSERT( pathDir.SetTo(nonExistingSuper) == B_OK ); + CPPUNIT_ASSERT( link.SetTo(&pathDir, nonExistingRel) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( link.InitCheck() == B_ENTRY_NOT_FOUND ); + // + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo((BDirectory *)NULL, (const char *)NULL) + == B_BAD_VALUE ); + CPPUNIT_ASSERT( link.InitCheck() == B_BAD_VALUE ); + // + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo((BDirectory *)NULL, dirLink) == B_BAD_VALUE ); + CPPUNIT_ASSERT( link.InitCheck() == B_BAD_VALUE ); + // + nextSubTest(); + CPPUNIT_ASSERT( pathDir.SetTo(dirSuperLink) == B_OK ); + CPPUNIT_ASSERT( link.SetTo(&pathDir, (const char *)NULL) == B_BAD_VALUE ); + CPPUNIT_ASSERT( link.InitCheck() == B_BAD_VALUE ); + // + nextSubTest(); + CPPUNIT_ASSERT( pathDir.SetTo(dirSuperLink) == B_OK ); + CPPUNIT_ASSERT( link.SetTo(&pathDir, "") == B_OK ); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + // + nextSubTest(); + CPPUNIT_ASSERT( pathDir.SetTo(existingSuperFile) == B_OK ); + CPPUNIT_ASSERT( link.SetTo(&pathDir, existingRelFile) == B_OK ); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + // + nextSubTest(); + CPPUNIT_ASSERT( pathDir.SetTo(existingSuperDir) == B_OK ); + CPPUNIT_ASSERT( link.SetTo(&pathDir, existingRelDir) == B_OK ); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + // + nextSubTest(); + CPPUNIT_ASSERT( pathDir.SetTo(tooLongSuperEntryname) == B_OK ); + CPPUNIT_ASSERT( link.SetTo(&pathDir, tooLongRelEntryname) + == B_NAME_TOO_LONG ); + CPPUNIT_ASSERT( link.InitCheck() == B_NAME_TOO_LONG ); + // + nextSubTest(); + CPPUNIT_ASSERT( pathDir.SetTo(fileSuperDirname) == B_OK ); + CPPUNIT_ASSERT( link.SetTo(&pathDir, fileRelDirname) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( link.InitCheck() == B_ENTRY_NOT_FOUND ); +} + +// ReadLinkTest +void +SymLinkTest::ReadLinkTest() +{ + const char *dirLink = dirLinkname; + const char *fileLink = fileLinkname; + const char *badLink = badLinkname; + const char *cyclicLink1 = cyclicLinkname1; + const char *cyclicLink2 = cyclicLinkname2; + const char *existingDir = existingDirname; + const char *existingFile = existingFilename; + const char *nonExisting = nonExistingDirname; + BSymLink link; + char buffer[B_PATH_NAME_LENGTH + 1]; + // uninitialized + // R5: returns B_BAD_ADDRESS instead of (as doc'ed) B_FILE_ERROR + nextSubTest(); + CPPUNIT_ASSERT( link.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( equals(link.ReadLink(buffer, sizeof(buffer)), + B_BAD_ADDRESS, B_FILE_ERROR) ); + // existing dir link + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo(dirLink) == B_OK ); + CPPUNIT_ASSERT( link.ReadLink(buffer, sizeof(buffer)) + == (ssize_t)strlen(existingDir) ); + CPPUNIT_ASSERT( strcmp(buffer, existingDir) == 0 ); + // existing file link + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo(fileLink) == B_OK ); + CPPUNIT_ASSERT( link.ReadLink(buffer, sizeof(buffer)) + == (ssize_t)strlen(existingFile) ); + CPPUNIT_ASSERT( strcmp(buffer, existingFile) == 0 ); + // existing cyclic link + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo(cyclicLink1) == B_OK ); + CPPUNIT_ASSERT( link.ReadLink(buffer, sizeof(buffer)) + == (ssize_t)strlen(cyclicLink2) ); + CPPUNIT_ASSERT( strcmp(buffer, cyclicLink2) == 0 ); + // existing link to non-existing entry + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo(badLink) == B_OK ); + CPPUNIT_ASSERT( link.ReadLink(buffer, sizeof(buffer)) + == (ssize_t)strlen(nonExisting) ); + CPPUNIT_ASSERT( strcmp(buffer, nonExisting) == 0 ); + // non-existing link + // R5: returns B_BAD_ADDRESS instead of (as doc'ed) B_FILE_ERROR + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo(nonExisting) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( equals(link.ReadLink(buffer, sizeof(buffer)), + B_BAD_ADDRESS, B_FILE_ERROR) ); + // dir + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo(existingDir) == B_OK ); + CPPUNIT_ASSERT( link.ReadLink(buffer, sizeof(buffer)) == B_BAD_VALUE ); + // file + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo(existingFile) == B_OK ); + CPPUNIT_ASSERT( link.ReadLink(buffer, sizeof(buffer)) == B_BAD_VALUE ); + // small buffer + // R5: returns the size of the contents, not the number of bytes copied + // OBOS: ... so do we + nextSubTest(); + char smallBuffer[2]; + CPPUNIT_ASSERT( link.SetTo(dirLink) == B_OK ); + CPPUNIT_ASSERT( link.ReadLink(smallBuffer, sizeof(smallBuffer)) + == (ssize_t)strlen(dirLink) ); + CPPUNIT_ASSERT( strncmp(smallBuffer, existingDir, sizeof(smallBuffer)) == 0 ); + // bad args + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo(fileLink) == B_OK ); + CPPUNIT_ASSERT( equals(link.ReadLink(NULL, sizeof(buffer)), B_BAD_ADDRESS, + B_BAD_VALUE) ); +} + +// MakeLinkedPathTest +void +SymLinkTest::MakeLinkedPathTest() +{ + const char *dirLink = dirLinkname; + const char *fileLink = fileLinkname; + const char *relDirLink = relDirLinkname; + const char *relFileLink = relFileLinkname; + const char *cyclicLink1 = cyclicLinkname1; + const char *cyclicLink2 = cyclicLinkname2; + const char *existingDir = existingDirname; + const char *existingSuperDir = existingSuperDirname; + const char *existingFile = existingFilename; + const char *existingSuperFile = existingSuperFilename; + const char *nonExisting = nonExistingDirname; + BSymLink link; + BPath path; + // 1. MakeLinkedPath(const char*, BPath*) + // uninitialized + nextSubTest(); + CPPUNIT_ASSERT( link.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( equals(link.MakeLinkedPath("/boot", &path), B_BAD_ADDRESS, + B_FILE_ERROR) ); + link.Unset(); + path.Unset(); + // existing absolute dir link + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo(dirLink) == B_OK ); + CPPUNIT_ASSERT( link.MakeLinkedPath("/boot", &path) + == (ssize_t)strlen(existingDir) ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(existingDir) == path.Path() ); + link.Unset(); + path.Unset(); + // existing absolute file link + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo(fileLink) == B_OK ); + CPPUNIT_ASSERT( link.MakeLinkedPath("/boot", &path) + == (ssize_t)strlen(existingFile) ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(existingFile) == path.Path() ); + link.Unset(); + path.Unset(); + // existing absolute cyclic link + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo(cyclicLink1) == B_OK ); + CPPUNIT_ASSERT( link.MakeLinkedPath("/boot", &path) + == (ssize_t)strlen(cyclicLink2) ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(cyclicLink2) == path.Path() ); + link.Unset(); + path.Unset(); + // existing relative dir link + nextSubTest(); + BEntry entry; + BPath entryPath; + CPPUNIT_ASSERT( entry.SetTo(existingDir) == B_OK ); + CPPUNIT_ASSERT( entry.GetPath(&entryPath) == B_OK ); + CPPUNIT_ASSERT( link.SetTo(relDirLink) == B_OK ); + CPPUNIT_ASSERT( link.MakeLinkedPath(existingSuperDir, &path) + == (ssize_t)strlen(entryPath.Path()) ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( entryPath == path ); + link.Unset(); + path.Unset(); + entry.Unset(); + entryPath.Unset(); + // existing relative file link + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(existingFile) == B_OK ); + CPPUNIT_ASSERT( entry.GetPath(&entryPath) == B_OK ); + CPPUNIT_ASSERT( link.SetTo(relFileLink) == B_OK ); + CPPUNIT_ASSERT( link.MakeLinkedPath(existingSuperFile, &path) + == (ssize_t)strlen(entryPath.Path()) ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( entryPath == path ); + link.Unset(); + path.Unset(); + entry.Unset(); + entryPath.Unset(); + // bad args + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo(dirLink) == B_OK ); +// R5: crashs, when passing a NULL path +#if !SK_TEST_R5 + CPPUNIT_ASSERT( link.MakeLinkedPath("/boot", NULL) == B_BAD_VALUE ); +#endif + CPPUNIT_ASSERT( link.MakeLinkedPath((const char*)NULL, &path) + == B_BAD_VALUE ); +// R5: crashs, when passing a NULL path +#if !SK_TEST_R5 + CPPUNIT_ASSERT( link.MakeLinkedPath((const char*)NULL, NULL) + == B_BAD_VALUE ); +#endif + link.Unset(); + path.Unset(); + + // 2. MakeLinkedPath(const BDirectory*, BPath*) + // uninitialized + nextSubTest(); + link.Unset(); + CPPUNIT_ASSERT( link.InitCheck() == B_NO_INIT ); + BDirectory dir; + CPPUNIT_ASSERT( dir.SetTo("/boot") == B_OK); + CPPUNIT_ASSERT( equals(link.MakeLinkedPath(&dir, &path), B_BAD_ADDRESS, + B_FILE_ERROR) ); + link.Unset(); + path.Unset(); + dir.Unset(); + // existing absolute dir link + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo(dirLink) == B_OK ); + CPPUNIT_ASSERT( dir.SetTo("/boot") == B_OK); + CPPUNIT_ASSERT( link.MakeLinkedPath(&dir, &path) + == (ssize_t)strlen(existingDir) ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(existingDir) == path.Path() ); + link.Unset(); + path.Unset(); + dir.Unset(); + // existing absolute file link + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo(fileLink) == B_OK ); + CPPUNIT_ASSERT( dir.SetTo("/boot") == B_OK); + CPPUNIT_ASSERT( link.MakeLinkedPath(&dir, &path) + == (ssize_t)strlen(existingFile) ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(existingFile) == path.Path() ); + link.Unset(); + path.Unset(); + dir.Unset(); + // existing absolute cyclic link + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo(cyclicLink1) == B_OK ); + CPPUNIT_ASSERT( dir.SetTo("/boot") == B_OK); + CPPUNIT_ASSERT( link.MakeLinkedPath(&dir, &path) + == (ssize_t)strlen(cyclicLink2) ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(cyclicLink2) == path.Path() ); + link.Unset(); + path.Unset(); + dir.Unset(); + // existing relative dir link + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(existingDir) == B_OK ); + CPPUNIT_ASSERT( entry.GetPath(&entryPath) == B_OK ); + CPPUNIT_ASSERT( link.SetTo(relDirLink) == B_OK ); + CPPUNIT_ASSERT( dir.SetTo(existingSuperDir) == B_OK); + CPPUNIT_ASSERT( link.MakeLinkedPath(&dir, &path) + == (ssize_t)strlen(entryPath.Path()) ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( entryPath == path ); + link.Unset(); + path.Unset(); + dir.Unset(); + entry.Unset(); + entryPath.Unset(); + // existing relative file link + nextSubTest(); + CPPUNIT_ASSERT( entry.SetTo(existingFile) == B_OK ); + CPPUNIT_ASSERT( entry.GetPath(&entryPath) == B_OK ); + CPPUNIT_ASSERT( link.SetTo(relFileLink) == B_OK ); + CPPUNIT_ASSERT( dir.SetTo(existingSuperFile) == B_OK); + CPPUNIT_ASSERT( link.MakeLinkedPath(&dir, &path) + == (ssize_t)strlen(entryPath.Path()) ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( entryPath == path ); + link.Unset(); + path.Unset(); + dir.Unset(); + entry.Unset(); + entryPath.Unset(); + // absolute link, uninitialized dir + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo(dirLink) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_NO_INIT); + CPPUNIT_ASSERT( link.MakeLinkedPath(&dir, &path) + == (ssize_t)strlen(existingDir) ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(existingDir) == path.Path() ); + // absolute link, badly initialized dir + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo(dirLink) == B_OK ); + CPPUNIT_ASSERT( dir.SetTo(nonExisting) == B_ENTRY_NOT_FOUND); + CPPUNIT_ASSERT( link.MakeLinkedPath(&dir, &path) + == (ssize_t)strlen(existingDir) ); + CPPUNIT_ASSERT( path.InitCheck() == B_OK ); + CPPUNIT_ASSERT( string(existingDir) == path.Path() ); + link.Unset(); + path.Unset(); + dir.Unset(); + // relative link, uninitialized dir + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo(relDirLink) == B_OK ); + CPPUNIT_ASSERT( dir.InitCheck() == B_NO_INIT); + CPPUNIT_ASSERT( equals(link.MakeLinkedPath(&dir, &path), B_NO_INIT, + B_BAD_VALUE) ); + link.Unset(); + // relative link, badly initialized dir + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo(relDirLink) == B_OK ); + CPPUNIT_ASSERT( dir.SetTo(nonExisting) == B_ENTRY_NOT_FOUND); + CPPUNIT_ASSERT( equals(link.MakeLinkedPath(&dir, &path), B_NO_INIT, + B_BAD_VALUE) ); + link.Unset(); + path.Unset(); + dir.Unset(); + // bad args + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo(dirLink) == B_OK ); + CPPUNIT_ASSERT( dir.SetTo("/boot") == B_OK); +// R5: crashs, when passing a NULL path +#if !SK_TEST_R5 + CPPUNIT_ASSERT( link.MakeLinkedPath(&dir, NULL) == B_BAD_VALUE ); +#endif + + CPPUNIT_ASSERT( link.MakeLinkedPath((const BDirectory*)NULL, &path) + == B_BAD_VALUE ); +// R5: crashs, when passing a NULL path +#if !SK_TEST_R5 + CPPUNIT_ASSERT( link.MakeLinkedPath((const BDirectory*)NULL, NULL) + == B_BAD_VALUE ); +#endif + link.Unset(); + path.Unset(); + dir.Unset(); +} + +// IsAbsoluteTest +void +SymLinkTest::IsAbsoluteTest() +{ + const char *dirLink = dirLinkname; + const char *relFileLink = relFileLinkname; + const char *existingDir = existingDirname; + const char *existingFile = existingFilename; + const char *nonExisting = nonExistingDirname; + BSymLink link; + // uninitialized + nextSubTest(); + CPPUNIT_ASSERT( link.InitCheck() == B_NO_INIT ); + CPPUNIT_ASSERT( link.IsAbsolute() == false ); + link.Unset(); + // existing absolute dir link + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo(dirLink) == B_OK ); + CPPUNIT_ASSERT( link.IsAbsolute() == true ); + link.Unset(); + // existing relative file link + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo(relFileLink) == B_OK ); + CPPUNIT_ASSERT( link.IsAbsolute() == false ); + link.Unset(); + // non-existing link + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo(nonExisting) == B_ENTRY_NOT_FOUND ); + CPPUNIT_ASSERT( link.IsAbsolute() == false ); + link.Unset(); + // dir + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo(existingDir) == B_OK ); + CPPUNIT_ASSERT( link.IsAbsolute() == false ); + link.Unset(); + // file + nextSubTest(); + CPPUNIT_ASSERT( link.SetTo(existingFile) == B_OK ); + CPPUNIT_ASSERT( link.IsAbsolute() == false ); + link.Unset(); +} + +// AssignmentTest +void +SymLinkTest::AssignmentTest() +{ + const char *dirLink = dirLinkname; + const char *fileLink = fileLinkname; + // 1. copy constructor + // uninitialized + nextSubTest(); + { + BSymLink link; + CPPUNIT_ASSERT( link.InitCheck() == B_NO_INIT ); + BSymLink link2(link); + // R5 returns B_BAD_VALUE instead of B_NO_INIT + CPPUNIT_ASSERT( equals(link2.InitCheck(), B_BAD_VALUE, B_NO_INIT) ); + } + // existing dir link + nextSubTest(); + { + BSymLink link(dirLink); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + BSymLink link2(link); + CPPUNIT_ASSERT( link2.InitCheck() == B_OK ); + } + // existing file link + nextSubTest(); + { + BSymLink link(fileLink); + CPPUNIT_ASSERT( link.InitCheck() == B_OK ); + BSymLink link2(link); + CPPUNIT_ASSERT( link2.InitCheck() == B_OK ); + } + + // 2. assignment operator + // uninitialized + nextSubTest(); + { + BSymLink link; + BSymLink link2; + link2 = link; + // R5 returns B_BAD_VALUE instead of B_NO_INIT + CPPUNIT_ASSERT( equals(link2.InitCheck(), B_BAD_VALUE, B_NO_INIT) ); + } + nextSubTest(); + { + BSymLink link; + BSymLink link2(dirLink); + link2 = link; + // R5 returns B_BAD_VALUE instead of B_NO_INIT + CPPUNIT_ASSERT( equals(link2.InitCheck(), B_BAD_VALUE, B_NO_INIT) ); + } + // existing dir link + nextSubTest(); + { + BSymLink link(dirLink); + BSymLink link2; + link2 = link; + CPPUNIT_ASSERT( link2.InitCheck() == B_OK ); + } + // existing file link + nextSubTest(); + { + BSymLink link(fileLink); + BSymLink link2; + link2 = link; + CPPUNIT_ASSERT( link2.InitCheck() == B_OK ); + } +} + + diff --git a/src/tests/kits/storage/SymLinkTest.h b/src/tests/kits/storage/SymLinkTest.h new file mode 100644 index 0000000000..65d009199b --- /dev/null +++ b/src/tests/kits/storage/SymLinkTest.h @@ -0,0 +1,38 @@ +// SymLinkTest.h + +#ifndef __sk_sym_link_test_h__ +#define __sk_sym_link_test_h__ + +#include + +#include +#include + +#include "NodeTest.h" + +class SymLinkTest : public NodeTest +{ +public: + static Test* Suite(); + + virtual void CreateRONodes(TestNodes& testEntries); + virtual void CreateRWNodes(TestNodes& testEntries); + virtual void CreateUninitializedNodes(TestNodes& testEntries); + + // This function called before *each* test added in Suite() + void setUp(); + + // This function called after *each* test added in Suite() + void tearDown(); + + // test methods + + void InitTest1(); + void InitTest2(); + void ReadLinkTest(); + void MakeLinkedPathTest(); + void IsAbsoluteTest(); + void AssignmentTest(); +}; + +#endif // __sk_sym_link_test_h__ diff --git a/src/tests/kits/storage/Test.StorageKit.cpp b/src/tests/kits/storage/Test.StorageKit.cpp new file mode 100644 index 0000000000..3591b01468 --- /dev/null +++ b/src/tests/kits/storage/Test.StorageKit.cpp @@ -0,0 +1,127 @@ +#include "Test.StorageKit.h" +#include +#include "TestUtils.h" + +#include + +// ##### Include your test headers here ##### +#include "DirectoryTest.h" +#include "EntryTest.h" +#include "FileTest.h" +#include "FindDirectoryTest.h" +#include "MimeTypeTest.h" +#include "NodeTest.h" +#include "PathTest.h" +#include "QueryTest.h" +#include "ResourcesTest.h" +#include "ResourceStringsTest.h" +#include "SymLinkTest.h" + + +StorageKit::TestShell shell; + +int main(int argc, char *argv[]) { + // ##### Add your test suites here ##### + shell.AddSuite( "BDirectory", &DirectoryTest::Suite ); + shell.AddSuite( "BEntry", &EntryTest::Suite ); + shell.AddSuite( "BFile", &FileTest::Suite ); + shell.AddSuite( "BMimeType", &MimeTypeTest::Suite ); + shell.AddSuite( "BNode", &NodeTest::Suite ); + shell.AddSuite( "BPath", &PathTest::Suite ); + shell.AddSuite( "BQuery", &QueryTest::Suite ); + shell.AddSuite( "BResources", &ResourcesTest::Suite ); + shell.AddSuite( "BResourceStrings", &ResourceStringsTest::Suite ); + shell.AddSuite( "BSymLink", &SymLinkTest::Suite ); + shell.AddSuite( "FindDirectory", &FindDirectoryTest::Suite ); + + return shell.Run(argc, argv); +} + +namespace StorageKit { + +//------------------------------------------------------------------------------- +// StorageKit::TestShell +//------------------------------------------------------------------------------- + +TestShell::TestShell() + : CppUnitShell(), + fTestDir(NULL) +{ +} + +TestShell::~TestShell() +{ + delete fTestDir; +} + +int +TestShell::Run(int argc, char *argv[]) +{ + // Let's hope BPath does work. ;-) + BPath path(argv[0]); + if (path.InitCheck() == B_OK) { + fTestDir = new BPath(); + if (path.GetParent(fTestDir) != B_OK) + printf("Couldn't get test dir.\n"); + } else + printf("Couldn't find the path to the test app.\n"); + return CppUnitShell::Run(argc, argv); +} + +void +TestShell::PrintDescription(int argc, char *argv[]) { + std::string AppName = argv[0]; + cout << endl; + cout << "This program is the central testing framework for the purpose" << endl; + cout << "of testing and verifying the behavior of the OpenBeOS Storage" << endl; + cout << "Kit." << endl; + + if (AppName.rfind("Test.StorageKit.R5") != std::string::npos) { + cout << endl; + cout << "Judging by its name (Test.StorageKit.R5), this copy was" << endl; + cout << "probably linked again Be Inc.'s R5 Storage Kit for the sake" << endl; + cout << "of comparison against our own implementation." << endl; + } + else if (AppName.rfind("Test.StorageKit.OpenBeOS") != std::string::npos) { + cout << endl; + cout << "Judging by its name (Test.StorageKit.OpenBeOS), this copy" << endl; + cout << "was probably linked against the OpenBeOS implementation of" << endl; + cout << "the Storage Kit." << endl; + } +} + +const char* +TestShell::TestDir() const +{ + return (fTestDir ? fTestDir->Path() : NULL); +} + +//------------------------------------------------------------------------------- +// TestCase +//------------------------------------------------------------------------------- + +TestCase::TestCase() : fValidCWD(false) { +} + +// Saves the location of the current working directory. To return to the +// last saved working directory, all \ref RestorCWD(). +void +TestCase::SaveCWD() { + fValidCWD = getcwd(fCurrentWorkingDir, B_PATH_NAME_LENGTH); +} + +/* Restores the current working directory to last directory saved by a + call to SaveCWD(). If SaveCWD() has not been called and an alternate + directory is specified by alternate, the current working directory is + changed to alternate. If alternate is null, the current working directory + is not modified. +*/ +void +TestCase::RestoreCWD(const char *alternate) { + if (fValidCWD) + chdir(fCurrentWorkingDir); + else if (alternate != NULL) + chdir(alternate); +} + +} diff --git a/src/tests/kits/storage/Test.StorageKit.h b/src/tests/kits/storage/Test.StorageKit.h new file mode 100644 index 0000000000..aaffaca6d4 --- /dev/null +++ b/src/tests/kits/storage/Test.StorageKit.h @@ -0,0 +1,61 @@ +#ifndef __sk_testing_is_so_much_fun_h__ +#define __sk_testing_is_so_much_fun_h__ + +#include +#include +#include +#include + +#include + +// Handy defines :-) +#define CHK CPPUNIT_ASSERT +#define RES DecodeResult + +class BPath; + +namespace StorageKit { + +class TestSuite : public CppUnit::TestSuite { + virtual void run (CppUnit::TestResult *result) { + setUp(); + CppUnit::TestSuite::run(result); + tearDown(); + } + + // This function called *once* before the entire suite of tests is run + virtual void setUp() {} + + // This function called *once* after the entire suite of tests is run + virtual void tearDown() {} + +}; + + +class TestShell : public CppUnitShell { +public: + TestShell(); + ~TestShell(); + int Run(int argc, char *argv[]); + virtual void PrintDescription(int argc, char *argv[]); + const char* TestDir() const; +private: + BPath *fTestDir; +}; + +class TestCase : public CppUnit::TestCase { +public: + TestCase(); + void SaveCWD(); + void RestoreCWD(const char *alternate = NULL); +protected: + bool fValidCWD; + char fCurrentWorkingDir[B_PATH_NAME_LENGTH+1]; +}; + +}; + +extern StorageKit::TestShell shell; + + +#endif // __sk_testing_is_so_much_fun_h__ diff --git a/src/tests/kits/storage/TestApp.cpp b/src/tests/kits/storage/TestApp.cpp new file mode 100644 index 0000000000..82028674c2 --- /dev/null +++ b/src/tests/kits/storage/TestApp.cpp @@ -0,0 +1,89 @@ +// TestApp.cpp + +#include "TestApp.h" + +// TestHandler + +// MessageReceived +void +TestHandler::MessageReceived(BMessage *message) +{ + // clone and push it + BMessage *clone = new BMessage(*message); + fQueue.Lock(); + fQueue.AddMessage(clone); + fQueue.Unlock(); +} + +// Queue +BMessageQueue & +TestHandler::Queue() +{ + return fQueue; +} + + +// TestApp + +// constructor +TestApp::TestApp(const char *signature) + : BApplication(signature), + fAppThread(B_ERROR), + fHandler() +{ + AddHandler(&fHandler); + Unlock(); +} + +// Init +status_t +TestApp::Init() +{ + status_t error = B_OK; + fAppThread = spawn_thread(&_AppThreadStart, "query app", + B_NORMAL_PRIORITY, this); + if (fAppThread < 0) + error = fAppThread; + else { + error = resume_thread(fAppThread); + if (error != B_OK) + kill_thread(fAppThread); + } + if (error != B_OK) + fAppThread = B_ERROR; + return error; +} + +// Terminate +void +TestApp::Terminate() +{ + PostMessage(B_QUIT_REQUESTED, this); + int32 result; + wait_for_thread(fAppThread, &result); +} + +// ReadyToRun +void +TestApp::ReadyToRun() +{ +} + +// Handler +TestHandler & +TestApp::Handler() +{ + return fHandler; +} + +// _AppThreadStart +int32 +TestApp::_AppThreadStart(void *data) +{ + if (TestApp *app = (TestApp*)data) { + app->Lock(); + app->Run(); + } + return 0; +} + diff --git a/src/tests/kits/storage/TestApp.h b/src/tests/kits/storage/TestApp.h new file mode 100644 index 0000000000..18468508f7 --- /dev/null +++ b/src/tests/kits/storage/TestApp.h @@ -0,0 +1,42 @@ +// TestApp.h + +#ifndef _sk_test_app_h_ +#define _sk_test_app_h_ + +#include +#include + +// TestHandler + +class TestHandler : public BHandler { +public: + virtual void MessageReceived(BMessage *message); + BMessageQueue &Queue(); + +private: + BMessageQueue fQueue; +}; + + +// TestApp + +class TestApp : public BApplication { +public: + TestApp(const char *signature); + + status_t Init(); + void Terminate(); + + virtual void ReadyToRun(); + + TestHandler &Handler(); + +private: + static int32 _AppThreadStart(void *data); + +private: + thread_id fAppThread; + TestHandler fHandler; +}; + +#endif // _sk_test_app_h_ diff --git a/src/tests/kits/storage/TestUtils.cpp b/src/tests/kits/storage/TestUtils.cpp new file mode 100644 index 0000000000..3add365462 --- /dev/null +++ b/src/tests/kits/storage/TestUtils.cpp @@ -0,0 +1,199 @@ +// TestUtils.cpp + +#include "TestUtils.h" +#include "Test.StorageKit.h" + +status_t DecodeResult(status_t result) { + if (!shell.BeVerbose()) + return result; + + std::string str; + switch (result) { + + case B_OK: + str = "B_OK"; + break; + + case B_ERROR: + str = "B_ERROR"; + break; + + + // Storage Kit Errors + case B_FILE_ERROR: + str = "B_FILE_ERROR"; + break; + + case B_FILE_NOT_FOUND: + str = "B_FILE_NOT_FOUND"; + break; + + case B_FILE_EXISTS: + str = "B_FILE_EXISTS"; + break; + + case B_ENTRY_NOT_FOUND: + str = "B_ENTRY_NOT_FOUND"; + break; + + case B_NAME_TOO_LONG: + str = "B_NAME_TOO_LONG"; + break; + + case B_DIRECTORY_NOT_EMPTY: + str = "B_DIRECTORY_NOT_EMPTY"; + break; + + case B_DEVICE_FULL: + str = "B_DEVICE_FULL"; + break; + + case B_READ_ONLY_DEVICE: + str = "B_READ_ONLY_DEVICE"; + break; + + case B_IS_A_DIRECTORY: + str = "B_IS_A_DIRECTORY"; + break; + + case B_NO_MORE_FDS: + str = "B_NO_MORE_FDS"; + break; + + case B_CROSS_DEVICE_LINK: + str = "B_CROSS_DEVICE_LINK"; + break; + + case B_LINK_LIMIT: + str = "B_LINK_LIMIT"; + break; + + case B_BUSTED_PIPE: + str = "B_BUSTED_PIPE"; + break; + + case B_UNSUPPORTED: + str = "B_UNSUPPORTED"; + break; + + case B_PARTITION_TOO_SMALL: + str = "B_PARTITION_TOO_SMALL"; + break; + + + // General Errors + case B_NO_MEMORY: + str = "B_NO_MEMORY"; + break; + + case B_IO_ERROR: + str = "B_IO_ERROR"; + break; + + case B_PERMISSION_DENIED: + str = "B_PERMISSION_DENIED"; + break; + + case B_BAD_INDEX: + str = "B_BAD_INDEX"; + break; + + case B_BAD_TYPE: + str = "B_BAD_TYPE"; + break; + + case B_BAD_VALUE: + str = "B_BAD_VALUE"; + break; + + case B_MISMATCHED_VALUES: + str = "B_MISMATCHED_VALUES"; + break; + + case B_NAME_NOT_FOUND: + str = "B_NAME_NOT_FOUND"; + break; + + case B_NAME_IN_USE: + str = "B_NAME_IN_USE"; + break; + + case B_TIMED_OUT: + str = "B_TIMED_OUT"; + break; + + case B_INTERRUPTED: + str = "B_INTERRUPTED"; + break; + + case B_WOULD_BLOCK: + str = "B_WOULD_BLOCK"; + break; + + case B_CANCELED: + str = "B_CANCELED"; + break; + + case B_NO_INIT: + str = "B_NO_INIT"; + break; + + case B_BUSY: + str = "B_BUSY"; + break; + + case B_NOT_ALLOWED: + str = "B_NOT_ALLOWED"; + break; + + + // Kernel Errors + case B_BAD_ADDRESS: + str = "B_BAD_ADDRESS"; + break; + + // OS Errors + case B_BAD_PORT_ID: + str = "B_BAD_PORT_ID"; + break; + + // Anything Else + default: + str = "??????????"; + break; + + } + + cout << endl << "DecodeResult() -- " "0x" << hex << result << " (" << dec << result << ") == " << str << endl; + + return result; +} + +void ExecCommand(const char *command) { + if (command) + system(command); +} + +void ExecCommand(const char *command, const char *parameter) { + if (command && parameter) { + char *cmdLine = new char[strlen(command) + strlen(parameter) + 1]; + strcpy(cmdLine, command); + strcat(cmdLine, parameter); + system(cmdLine); + delete[] cmdLine; + } +} + +void ExecCommand(const char *command, const char *parameter1, + const char *parameter2) { + if (command && parameter1 && parameter2) { + char *cmdLine = new char[strlen(command) + strlen(parameter1) + + 1 + strlen(parameter2) + 1]; + strcpy(cmdLine, command); + strcat(cmdLine, parameter1); + strcat(cmdLine, " "); + strcat(cmdLine, parameter2); + system(cmdLine); + delete[] cmdLine; + } +} diff --git a/src/tests/kits/storage/TestUtils.h b/src/tests/kits/storage/TestUtils.h new file mode 100644 index 0000000000..25980d9fd7 --- /dev/null +++ b/src/tests/kits/storage/TestUtils.h @@ -0,0 +1,26 @@ +#ifndef __sk_test_utils_h__ +#define __sk_test_utils_h__ + +#include +#include + +// Prints out a description of the given status_t +// return code to standard out. Helpful for figuring +// out just what the R5 libraries are returning. +// Returns the same value passed in, so you can +// use it inline in tests if necessary. +status_t DecodeResult(status_t result); + + +// Calls system() with the concatenated string of command and parameter. +void ExecCommand(const char *command, const char *parameter); + +// Calls system() with the concatenated string of command, parameter1, +// " " and parameter2. +void ExecCommand(const char *command, const char *parameter1, + const char *parameter2); + +// Calls system() with the given command (kind of silly, but it's consistent :-) +void ExecCommand(const char *command); + +#endif // __sk_test_utils_h__ diff --git a/src/tests/kits/storage/resources/elf b/src/tests/kits/storage/resources/elf new file mode 100755 index 0000000000..5493253624 Binary files /dev/null and b/src/tests/kits/storage/resources/elf differ diff --git a/src/tests/kits/storage/resources/elf-no-res b/src/tests/kits/storage/resources/elf-no-res new file mode 100755 index 0000000000..1c27f7f9a7 Binary files /dev/null and b/src/tests/kits/storage/resources/elf-no-res differ diff --git a/src/tests/kits/storage/resources/pef b/src/tests/kits/storage/resources/pef new file mode 100644 index 0000000000..fe8d0cc551 Binary files /dev/null and b/src/tests/kits/storage/resources/pef differ diff --git a/src/tests/kits/storage/resources/pef-no-res b/src/tests/kits/storage/resources/pef-no-res new file mode 100644 index 0000000000..f126c6249f Binary files /dev/null and b/src/tests/kits/storage/resources/pef-no-res differ diff --git a/src/tests/kits/storage/resources/ppc.rsrc b/src/tests/kits/storage/resources/ppc.rsrc new file mode 100644 index 0000000000..edf24cee66 Binary files /dev/null and b/src/tests/kits/storage/resources/ppc.rsrc differ diff --git a/src/tests/kits/storage/resources/x86.rsrc b/src/tests/kits/storage/resources/x86.rsrc new file mode 100644 index 0000000000..d6ec885e65 Binary files /dev/null and b/src/tests/kits/storage/resources/x86.rsrc differ diff --git a/src/tests/kits/support/barchivable/BArchivableTester.cpp b/src/tests/kits/support/barchivable/BArchivableTester.cpp new file mode 100644 index 0000000000..ea0ee048fd --- /dev/null +++ b/src/tests/kits/support/barchivable/BArchivableTester.cpp @@ -0,0 +1,128 @@ +//------------------------------------------------------------------------------ +// BArchivableTester.cpp +// +/** + BArchivable tests + @note InvalidArchiveShallow() and InvalidArchiveDeep() are not tested + against the original implementation as it does not handle NULL + parameters gracefully. + */ +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "BArchivableTester.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +/** + BArchivable::Perform(perform_code d, void* arg) + @case Any + @param d Not used + @param arg Not used + @results Returns B_ERROR in all cases. + */ +void TBArchivableTestCase::TestPerform() +{ + BArchivable Archive; + assert(Archive.Perform(0, NULL) == B_ERROR); +} +//------------------------------------------------------------------------------ +/** + BArchivable::Archive(BMessage* into, bool deep) + @case Invalid archive, shallow archiving + @param into NULL + @param deep false + @results Returns B_BAD_VALUE. + */ +void TBArchivableTestCase::InvalidArchiveShallow() +{ + BArchivable Archive; + assert(Archive.Archive(NULL, false) == B_BAD_VALUE); +} +//------------------------------------------------------------------------------ +/** + BArchivable::Archive(BMessage* into, bool deep) + @case Valid archive, shallow archiving + @param into Valid BMessage pointer + @param deep false + @results Returns B_OK. + Resultant archive has a string field labeled "class". + Field "class" contains the string "BArchivable". + */ +void TBArchivableTestCase::ValidArchiveShallow() +{ + BMessage Storage; + BArchivable Archive; + assert(Archive.Archive(&Storage, false) == B_OK); + const char* name; + assert(Storage.FindString("class", &name) == B_OK); + assert(strcmp(name, "BArchivable") == 0); +} +//------------------------------------------------------------------------------ +/** + BArchivable::Archive(BMessage* into, bool deep) + @case Invalid archive, deep archiving + @param into NULL + @param deep true + @results Returns B_BAD_VALUE + */ +void TBArchivableTestCase::InvalidArchiveDeep() +{ + BArchivable Archive; + assert(Archive.Archive(NULL, true) == B_BAD_VALUE); +} +//------------------------------------------------------------------------------ +/** + BArchivable::Archive(BMessage* into, bool deep) + @case Valid archive, deep archiving + @param into Valid BMessage pointer + @param deep true + @results Returns B_OK. + Resultant archive has a string field labeled "class". + Field "class" contains the string "BArchivable". + */ +void TBArchivableTestCase::ValidArchiveDeep() +{ + BMessage Storage; + BArchivable Archive; + assert(Archive.Archive(&Storage, true) == B_OK); + const char* name; + assert(Storage.FindString("class", &name) == B_OK); + assert(strcmp(name, "BArchivable") == 0); +} +//------------------------------------------------------------------------------ +Test* TBArchivableTestCase::Suite() +{ + TestSuite* SuiteOfTests = new TestSuite; + ADD_TEST(SuiteOfTests, TBArchivableTestCase, TestPerform); +#if !defined(SYSTEM_TEST) + ADD_TEST(SuiteOfTests, TBArchivableTestCase, InvalidArchiveShallow); +#endif + ADD_TEST(SuiteOfTests, TBArchivableTestCase, ValidArchiveShallow); +#if !defined(SYSTEM_TEST) + ADD_TEST(SuiteOfTests, TBArchivableTestCase, InvalidArchiveDeep); +#endif + ADD_TEST(SuiteOfTests, TBArchivableTestCase, ValidArchiveDeep); + + return SuiteOfTests; +} +//------------------------------------------------------------------------------ + + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/support/barchivable/BArchivableTester.h b/src/tests/kits/support/barchivable/BArchivableTester.h new file mode 100644 index 0000000000..37c6128e2d --- /dev/null +++ b/src/tests/kits/support/barchivable/BArchivableTester.h @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// BArchivableTester.h +// +//------------------------------------------------------------------------------ + +#ifndef BARCHIVABLETESTER_H +#define BARCHIVABLETESTER_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "LocalCommon.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +class TBArchivableTestCase : public TestCase +{ + public: + TBArchivableTestCase(std::string name) : TestCase(name) {;} + + void TestPerform(); + void InvalidArchiveShallow(); + void ValidArchiveShallow(); + void InvalidArchiveDeep(); + void ValidArchiveDeep(); + + static Test* Suite(); +}; + + +#endif //BARCHIVABLETESTER_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/support/barchivable/FindInstantiationFuncTester.cpp b/src/tests/kits/support/barchivable/FindInstantiationFuncTester.cpp new file mode 100644 index 0000000000..bfa54fa0d0 --- /dev/null +++ b/src/tests/kits/support/barchivable/FindInstantiationFuncTester.cpp @@ -0,0 +1,397 @@ +//------------------------------------------------------------------------------ +// FindInstatiationFuncTester.cpp +// +/** + Tests for find_instantiation_func(const char* name, const char* sig) + @note There are no tests for find_instantiation_func(const char*) as it + simply calls through to the version which takes an explicit sig, + setting that parameter to NULL. + + Here's the use case matrix: + + name sig + -------- -------- + case 1 NULL NULL + case 2 bogus NULL + case 3 NULL bogus + case 4 bogus bogus + case 5 local NULL + case 6 remote NULL + case 7 local bogus + case 8 remote bogus + case 9 local good + case 10 remote good + */ +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "FindInstantiationFuncTester.h" +#include "LocalTestObject.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +/** + find_instantiation_func(const char* name, const char* sig) + @case Both parameters NULL + @param name NULL + @param sig NULL + @results Returns NULL + */ +void TFindInstantiationFuncTester::Case1() +{ + instantiation_func f = find_instantiation_func(NULL, NULL); + assert(f == NULL); +} +//------------------------------------------------------------------------------ +/** + find_instantiation_func(const char* name, const char* sig) + @case Bad name with NULL signature + @param name Invalid class name + @param sig NULL + @results Returns NULL + */ +void TFindInstantiationFuncTester::Case2() +{ + instantiation_func f = find_instantiation_func(gInvalidClassName, NULL); + assert(f == NULL); +} +//------------------------------------------------------------------------------ +/** + find_instantiation_func(const char* name, const char* sig) + @case NULL name with invalid signature + @param name NULL class name + @param sig Invalid signature + @results Returns NULL + */ +void TFindInstantiationFuncTester::Case3() +{ + instantiation_func f = find_instantiation_func(NULL, gInvalidSig); + assert(f == NULL); +} +//------------------------------------------------------------------------------ +/** + find_instantiation_func(const char* name, const char* sig) + @case Both params are invalid + @param name Invalid class name + @param sig Invalid signature + @results Returns NULL + */ +void TFindInstantiationFuncTester::Case4() +{ + instantiation_func f = find_instantiation_func(gInvalidClassName, + gInvalidSig); + assert(f == NULL); +} +//------------------------------------------------------------------------------ +/** + find_instantiation_func(const char* name, const char* sig) + @case Valid name of a locally implemented class with a + NULL signature + @param name Valid local class name + @param sig NULL signature + @results Returns valid function + */ +void TFindInstantiationFuncTester::Case5() +{ + instantiation_func f = find_instantiation_func(gLocalClassName, NULL); + assert(f != NULL); + + BMessage Archive; + Archive.AddString("class", gLocalClassName); + TIOTest* Test = dynamic_cast(f(&Archive)); + assert(Test != NULL); +} +//------------------------------------------------------------------------------ +/** + find_instantiation_func(const char* name, const char* sig) + @case Valid name of a remotely implemented class with a + NULL signature + @param name Valid remote class name + @param sig NULL signature + @results Returns NULL + */ +void TFindInstantiationFuncTester::Case6() +{ + instantiation_func f = find_instantiation_func(gRemoteClassName, NULL); + assert(f == NULL); +} +//------------------------------------------------------------------------------ +/** + find_instantiation_func(const char* name, const char* sig) + @case Valid name of a locally implemented class with an + invalid signature + @param name Valid local class name + @param sig Invalid signature + @results Returns NULL + */ +void TFindInstantiationFuncTester::Case7() +{ + instantiation_func f = find_instantiation_func(gLocalClassName, + gInvalidSig); + assert(f == NULL); +} +//------------------------------------------------------------------------------ +/** + find_instantiation_func(const char* name, const char* sig) + @case Valid name of a remotely implemented class with an + invalid signature + @param name Valid remote class name + @param sig Invalid signature + @results Returns NULL + */ +void TFindInstantiationFuncTester::Case8() +{ + instantiation_func f = find_instantiation_func(gRemoteClassName, + gInvalidSig); + assert(f == NULL); +} +//------------------------------------------------------------------------------ +/** + find_instantiation_func(const char* name, const char* sig) + @case Valid name of a locally implemented class with a + valid signature + @param name Valid local class name + @param sig Valid signature + @results Returns valid function + @note This test is not currently used; can't obtain the local + signature without a BApplication object (gLocalSig is a + placeholder). + */ +void TFindInstantiationFuncTester::Case9() +{ + instantiation_func f = find_instantiation_func(gLocalClassName, gLocalSig); + assert(f == NULL); +} +//------------------------------------------------------------------------------ +/** + find_instantiation_func(const char* name, const char* sig) + @case Valid name of a remotely implemented class with a + valid signature + @param name Valid remote class name + @param sig Valid signature + @results Returns NULL + @note This case's results are because find_instantiation_func + doesn't actually load anything in order to do its work. + */ +void TFindInstantiationFuncTester::Case10() +{ + instantiation_func f = find_instantiation_func(gRemoteClassName, + gRemoteSig); + assert(f == NULL); +} +//------------------------------------------------------------------------------ +/** + find_instantiation_func(const char* name, const char* sig) + @case Archive is NULL + @param Archive NULL + */ +void TFindInstantiationFuncTester::Case1M() +{ + instantiation_func f = find_instantiation_func((BMessage*)NULL); + assert(f == NULL); +} +//------------------------------------------------------------------------------ +/** + find_instantiation_func(const char* name, const char* sig) + @case Bad name with NULL signature + @param name Invalid class name + @param sig NULL + @results Returns NULL + */ +void TFindInstantiationFuncTester::Case2M() +{ + BMessage Archive; + Archive.AddString("class", gInvalidClassName); + instantiation_func f = find_instantiation_func(&Archive); + assert(f == NULL); +} +//------------------------------------------------------------------------------ +/** + find_instantiation_func(const char* name, const char* sig) + @case NULL name with invalid signature + @param name NULL class name + @param sig Invalid signature + @results Returns NULL + */ +void TFindInstantiationFuncTester::Case3M() +{ + BMessage Archive; + Archive.AddString("add_on", gInvalidSig); + instantiation_func f = find_instantiation_func(&Archive); + assert(f == NULL); +} +//------------------------------------------------------------------------------ +/** + find_instantiation_func(const char* name, const char* sig) + @case Both params are invalid + @param name Invalid class name + @param sig Invalid signature + @results Returns NULL + */ +void TFindInstantiationFuncTester::Case4M() +{ + BMessage Archive; + Archive.AddString("class", gInvalidClassName); + Archive.AddString("add_on", gInvalidSig); + instantiation_func f = find_instantiation_func(&Archive); + assert(f == NULL); +} +//------------------------------------------------------------------------------ +/** + find_instantiation_func(const char* name, const char* sig) + @case Valid name of a locally implemented class with a + NULL signature + @param name Valid local class name + @param sig NULL signature + @results Returns valid function + */ +void TFindInstantiationFuncTester::Case5M() +{ + BMessage Archive; + Archive.AddString("class", gLocalClassName); + + instantiation_func f = find_instantiation_func(&Archive); + assert(f != NULL); + + TIOTest* Test = dynamic_cast(f(&Archive)); + assert(Test != NULL); +} +//------------------------------------------------------------------------------ +/** + find_instantiation_func(const char* name, const char* sig) + @case Valid name of a remotely implemented class with a + NULL signature + @param name Valid remote class name + @param sig NULL signature + @results Returns NULL + */ +void TFindInstantiationFuncTester::Case6M() +{ + BMessage Archive; + Archive.AddString("class", gRemoteClassName); + instantiation_func f = find_instantiation_func(&Archive); + assert(f == NULL); +} +//------------------------------------------------------------------------------ +/** + find_instantiation_func(const char* name, const char* sig) + @case Valid name of a locally implemented class with an + invalid signature + @param name Valid local class name + @param sig Invalid signature + @results Returns NULL + */ +void TFindInstantiationFuncTester::Case7M() +{ + BMessage Archive; + Archive.AddString("class", gLocalClassName); + Archive.AddString("add_on", gInvalidSig); + instantiation_func f = find_instantiation_func(&Archive); + assert(f == NULL); +} +//------------------------------------------------------------------------------ +/** + find_instantiation_func(const char* name, const char* sig) + @case Valid name of a remotely implemented class with an + invalid signature + @param name Valid remote class name + @param sig Invalid signature + @results Returns NULL + */ +void TFindInstantiationFuncTester::Case8M() +{ + BMessage Archive; + Archive.AddString("class", gRemoteClassName); + Archive.AddString("add_on", gInvalidSig); + instantiation_func f = find_instantiation_func(&Archive); + assert(f == NULL); +} +//------------------------------------------------------------------------------ +/** + find_instantiation_func(const char* name, const char* sig) + @case Valid name of a locally implemented class with a + valid signature + @param name Valid local class name + @param sig Valid signature + @results Returns valid function + @note This test is not currently used; can't obtain the local + signature without a BApplication object (gLocalSig is a + placeholder). + */ +void TFindInstantiationFuncTester::Case9M() +{ + BMessage Archive; + Archive.AddString("class", gLocalClassName); + Archive.AddString("add_on", gLocalSig); + instantiation_func f = find_instantiation_func(&Archive); + assert(f == NULL); +} +//------------------------------------------------------------------------------ +/** + find_instantiation_func(const char* name, const char* sig) + @case Valid name of a remotely implemented class with a + valid signature + @param name Valid remote class name + @param sig Valid signature + @results Returns NULL + @note This case's results are because find_instantiation_func + doesn't actually load anything in order to do its work. + */ +void TFindInstantiationFuncTester::Case10M() +{ + BMessage Archive; + Archive.AddString("class", gRemoteClassName); + Archive.AddString("add_on", gRemoteSig); + instantiation_func f = find_instantiation_func(&Archive); + assert(f == NULL); +} +//------------------------------------------------------------------------------ +Test* TFindInstantiationFuncTester::Suite() +{ + TestSuite* SuiteOfTests = new TestSuite; + + ADD_TEST(SuiteOfTests, TFindInstantiationFuncTester, Case1); + ADD_TEST(SuiteOfTests, TFindInstantiationFuncTester, Case2); + ADD_TEST(SuiteOfTests, TFindInstantiationFuncTester, Case3); + ADD_TEST(SuiteOfTests, TFindInstantiationFuncTester, Case4); + ADD_TEST(SuiteOfTests, TFindInstantiationFuncTester, Case5); + ADD_TEST(SuiteOfTests, TFindInstantiationFuncTester, Case6); + ADD_TEST(SuiteOfTests, TFindInstantiationFuncTester, Case7); + ADD_TEST(SuiteOfTests, TFindInstantiationFuncTester, Case8); +// ADD_TEST(SuiteOfTests, TFindInstantiationFuncTester, Case9); + ADD_TEST(SuiteOfTests, TFindInstantiationFuncTester, Case10); + + // BMessage using versions +#if !defined(SYSTEM_TEST) + ADD_TEST(SuiteOfTests, TFindInstantiationFuncTester, Case1M); +#endif + ADD_TEST(SuiteOfTests, TFindInstantiationFuncTester, Case2M); + ADD_TEST(SuiteOfTests, TFindInstantiationFuncTester, Case3M); + ADD_TEST(SuiteOfTests, TFindInstantiationFuncTester, Case4M); + ADD_TEST(SuiteOfTests, TFindInstantiationFuncTester, Case5M); + ADD_TEST(SuiteOfTests, TFindInstantiationFuncTester, Case6M); + ADD_TEST(SuiteOfTests, TFindInstantiationFuncTester, Case7M); + ADD_TEST(SuiteOfTests, TFindInstantiationFuncTester, Case8M); +// ADD_TEST(SuiteOfTests, TFindInstantiationFuncTester, Case9M); + ADD_TEST(SuiteOfTests, TFindInstantiationFuncTester, Case10M); + + return SuiteOfTests; +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/support/barchivable/FindInstantiationFuncTester.h b/src/tests/kits/support/barchivable/FindInstantiationFuncTester.h new file mode 100644 index 0000000000..0f125c51ef --- /dev/null +++ b/src/tests/kits/support/barchivable/FindInstantiationFuncTester.h @@ -0,0 +1,61 @@ +//------------------------------------------------------------------------------ +// FindInstatiationFuncTester.h +// +//------------------------------------------------------------------------------ + +#ifndef FINDINSTATIATIONFUNCTESTER_H +#define FINDINSTATIATIONFUNCTESTER_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "LocalCommon.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +class TFindInstantiationFuncTester : public TestCase +{ + public: + TFindInstantiationFuncTester(std::string name) : TestCase(name) {;} + + void Case1(); + void Case2(); + void Case3(); + void Case4(); + void Case5(); + void Case6(); + void Case7(); + void Case8(); + void Case9(); + void Case10(); + + // BMessage using versions + void Case1M(); + void Case2M(); + void Case3M(); + void Case4M(); + void Case5M(); + void Case6M(); + void Case7M(); + void Case8M(); + void Case9M(); + void Case10M(); + + static Test* Suite(); +}; + +#endif //FINDINSTATIATIONFUNCTESTER_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/support/barchivable/InstantiateObjectTester.cpp b/src/tests/kits/support/barchivable/InstantiateObjectTester.cpp new file mode 100644 index 0000000000..ac1e070f79 --- /dev/null +++ b/src/tests/kits/support/barchivable/InstantiateObjectTester.cpp @@ -0,0 +1,552 @@ +//------------------------------------------------------------------------------ +// InstantiateObjectTester.cpp +// +/** + Testing of instantiate_object(BMessage* archive, image_id* id) + @note No cases are currently defined for NULL 'id' parameter, since NULL + is a valid value for it. Perhaps there should be to ensure that the + instantiate_object is, in fact, dealing with that case correctly. + There are also no tests against instantiate_object(BMessage*) as it + simply calls instantiate_object(BMessage*, image_id*) with NULL for + the image_id parameter. + */ +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- +#include +#include + +// System Includes ------------------------------------------------------------- +#include +#include +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "framework/estring.h" +#include "RemoteObjectDef/RemoteTestObject.h" +#include "InstantiateObjectTester.h" +#include "LocalTestObject.h" + +// Local Defines --------------------------------------------------------------- +#define FORMAT_AND_THROW(MSG, ERR) \ + FormatAndThrow(__LINE__, __FILE__, MSG, ERR) + +// Globals --------------------------------------------------------------------- +const char* gInvalidClassName = "TInvalidClassName"; +const char* gInvalidSig = "application/x-vnd.InvalidSignature"; +const char* gLocalClassName = "TIOTest"; +const char* gLocalSig = "application/x-vnd.LocalSignature"; +const char* gRemoteClassName = "TRemoteTestObject"; +const char* gRemoteSig = "application/x-vnd.RemoteObjectDef"; +const char* gValidSig = gRemoteSig; + + +void FormatAndThrow(int line, const char* file, const char* msg, int err); + +//------------------------------------------------------------------------------ +TInstantiateObjectTester::TInstantiateObjectTester(string name) + : TestCase(name), fAddonId(B_ERROR) +{ + ; +} +//------------------------------------------------------------------------------ +/** + instantiate_object(BMessage* archive, image_id* id) + @case Invalid archive + @param archive NULL + @param id Valid image_id pointer + @results Returns NULL. + *id is set to B_BAD_VALUE. + errno is set to B_BAD_VALUE. + */ +void TInstantiateObjectTester::Case1() +{ + errno = B_OK; + image_id id = B_OK; + TIOTest* Test = (TIOTest*)instantiate_object(NULL, &id); + assert(Test == NULL); + assert(id == B_BAD_VALUE); + assert(errno == B_BAD_VALUE); +} +//------------------------------------------------------------------------------ +/** + instantiate_object(BMessage* archive, image_id* id) + @case No class name + @param archive Valid BMessage pointer without string field "class" + @param id Valid image_id pointer + @results Returns NULL. + *id is set to B_BAD_VALUE. + errno is set to B_OK. + */ +void TInstantiateObjectTester::Case2() +{ + errno = B_OK; + BMessage Archive; + image_id id = B_OK; + TIOTest* Test = (TIOTest*)instantiate_object(&Archive, &id); + assert(Test == NULL); + assert(id == B_BAD_VALUE); + assert(errno == B_OK); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Invalid class name tests +//------------------------------------------------------------------------------ +/** + instantiate_object(BMessage* archive, image_id* id) + @case Invalid class name + @param archive Valid BMessage pointer, with string field labeled "class" + containing an invalid class name + @param id Valid image_id pointer + @results Returns NULL. + *id is set to B_BAD_VALUE. + errno is set to B_BAD_VALUE. + */ +void TInstantiateObjectTester::Case3() +{ + errno = B_OK; + BMessage Archive; + Archive.AddString("class", gInvalidClassName); + image_id id = B_OK; + TIOTest* Test = (TIOTest*)instantiate_object(&Archive, &id); + assert(Test == NULL); + assert(id == B_BAD_VALUE); + assert(errno == B_BAD_VALUE); +} +//------------------------------------------------------------------------------ +/** + instantiate_object(BMessage* archive, image_id* id) + @case Invalid class name and signature + @param archive Valid BMessage pointer, with string fields labeled "class" + and "add_on", containing invalid class name and signature, + respectively + @param id Valid image_id pointer + @results Returns NULL. + *id is set to B_BAD_VALUE. + errno is set to B_LAUNCH_FAILED_APP_NOT_FOUND. + */ +void TInstantiateObjectTester::Case4() +{ + errno = B_OK; + BMessage Archive; + Archive.AddString("class", gInvalidClassName); + Archive.AddString("add_on", gInvalidSig); + image_id id = B_OK; + TIOTest* Test = (TIOTest*)instantiate_object(&Archive, &id); + assert(Test == NULL); + assert(id == B_BAD_VALUE); + assert(errno == B_LAUNCH_FAILED_APP_NOT_FOUND); +} +//------------------------------------------------------------------------------ +/** + instantiate_object(BMessage* archive, image_id* id) + @case Invalid class name, valid signature + @param archive Valid BMessage pointer with string fields labeled "class" + and "add_on", containing invalid class name and valid + signature, respectively + @param id Valid image_id pointer + @requires RemoteObjectDef add-on must be built and accessible + @results Returns NULL. + *id is > 0 (add-on was loaded) + errno is set to B_BAD_VALUE. + */ +void TInstantiateObjectTester::Case5() +{ + errno = B_OK; + BMessage Archive; + Archive.AddString("class", gInvalidClassName); + Archive.AddString("add_on", gValidSig); + image_id id = B_OK; + TIOTest* Test = (TIOTest*)instantiate_object(&Archive, &id); + assert(Test == NULL); + // The system implementation returns the image_id of the last addon searched + // Implies the addon is not unloaded. How to verify this behaviour? Should + // the addon be unloaded if it doesn't contain our function? Addons do, + // after all, eat into our allowable memory. + + // Verified that addon is *not* unloaded in the Be implementation. If Case8 + // runs after this case without explicitely unloaded the addon here, it + // fails because it depends on the addon image not being available within + // the team. + assert(id > 0); + unload_add_on(id); + assert(errno == B_BAD_VALUE); +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// Valid class name tests +//------------------------------------------------------------------------------ +/** + instantiate_object(BMessage* archive, image_id* id) + @case Valid archive of class defined in local image + @param archive Valid BMessage pointer with string field "class" containing + name of locally defined class which can be instantiated via + archiving mechanism + @param id Valid image_id pointer + @requires locally defined class which can be instantiated via + archiving mechanism + @results Returns valid TIOTest instance. + *id is set to B_BAD_VALUE (no image was loaded). + errno is set to B_OK. + */ +// No sig +// Local app -- local class +void TInstantiateObjectTester::Case6() +{ + errno = B_OK; + BMessage Archive; + Archive.AddString("class", gLocalClassName); + image_id id = B_OK; + TIOTest* Test = (TIOTest*)instantiate_object(&Archive, &id); + assert(Test != NULL); + assert(id == B_BAD_VALUE); + assert(errno == B_OK); +} +//------------------------------------------------------------------------------ +/** + instantiate_object(BMessage* archive, image_id* id) + @case Valid archive of class defined in add-on explicitely loaded + by this team + @param archive Valid BMessage pointer with string field "class" containing + name of remotely defined class which can be instantiated via + archiving mechanism + @param id Valid image_id pointer + @requires RemoteObjectDef add-on must be built and accessible + @results Returns valid TRemoteTestObject instance. + *id is set to B_BAD_VALUE (no image was loaded). + errno is set to B_OK. + */ +void TInstantiateObjectTester::Case7() +{ + errno = B_OK; + LoadAddon(); + + BMessage Archive; + Archive.AddString("class", gRemoteClassName); + image_id id = B_OK; + TRemoteTestObject* Test = (TRemoteTestObject*)instantiate_object(&Archive, + &id); + assert(Test != NULL); + assert(id == B_BAD_VALUE); + assert(errno == B_OK); + + UnloadAddon(); +} +//------------------------------------------------------------------------------ +/** + instantiate_object(BMessage* archive, image_id* id) + @case Valid archive of remotely-defined class, without required + signature of the defining add-on + @param archive Valid BMessage pointer with string field "class" containing + name of remotely-defined class; no "add-on" field + @param id Valid image_id pointer + @results Returns NULL. + *id is set to B_BAD_VALUE (no image loaded). + errno is set to B_BAD_VALUE. + */ +void TInstantiateObjectTester::Case8() +{ + errno = B_OK; + BMessage Archive; + Archive.AddString("class", gRemoteClassName); + image_id id = B_OK; + TRemoteTestObject* Test = (TRemoteTestObject*)instantiate_object(&Archive, + &id); + assert(Test == NULL); + assert(id == B_BAD_VALUE); + assert(errno == B_BAD_VALUE); +} +//------------------------------------------------------------------------------ +/** + instantiate_object(BMessage* archive, image_id* id) + @case Valid archive naming locally defined class with invalid + signature + @param archive Valid BMessage pointer with string field "class" containing + name of locally defined class and string field "add_on" + containing invalid signature + @param id Valid image_id pointer + @results Returns NULL. + *id is set to B_BAD_VALUE (no image loaded). + errno is set to B_LAUNCH_FAILED_APP_NOT_FOUND. + */ +void TInstantiateObjectTester::Case9() +{ + errno = B_OK; + BMessage Archive; + Archive.AddString("class", gLocalClassName); + Archive.AddString("add_on", gInvalidSig); + image_id id = B_OK; + TIOTest* Test = (TIOTest*)instantiate_object(&Archive, &id); + assert(Test == NULL); + assert(id == B_BAD_VALUE); + assert(errno == B_LAUNCH_FAILED_APP_NOT_FOUND); +} +//------------------------------------------------------------------------------ +/** + instantiate_object(BMessage* archive, image_id* id) + @case Valid archive of class defined in add-on explicitely loaded + by this team, but with an invalid signature + @param archive Valid BMessage pointer with string field "class" containing + name of remotely-defined class and string field "add_on" + containing invalid signature + @param id Valid image_id pointer + @requires RemoteObjectDef add-on must be built and accessible + @results Returns NULL. + *id is set to B_BAD_VALUE (no image loaded). + errno is set to B_LAUNCH_FAILED_APP_NOT_FOUND. + */ +void TInstantiateObjectTester::Case10() +{ + errno = B_OK; + LoadAddon(); + + BMessage Archive; + Archive.AddString("class", gRemoteClassName); + Archive.AddString("add_on", gInvalidSig); + image_id id = B_OK; + TIOTest* Test = (TIOTest*)instantiate_object(&Archive, &id); + assert(Test == NULL); + assert(id == B_BAD_VALUE); + assert(errno == B_LAUNCH_FAILED_APP_NOT_FOUND); + + UnloadAddon(); +} +//------------------------------------------------------------------------------ +/** + instantiate_object(BMessage* archive, image_id* id) + @case Valid archive of remotely-defined class, with invalid + signature + @param archive Valid BMessage pointer with string field "class" containing + name of remotely-defined class and string field add-on + containing invalid signature + @param id Valid image_id pointer + @results Returns NULL. + *id is set to B_BAD_VALUE. + errno is set to B_LAUNCH_FAILED_APP_NOT_FOUND + */ +void TInstantiateObjectTester::Case11() +{ + errno = B_OK; + BMessage Archive; + Archive.AddString("class", gRemoteClassName); + Archive.AddString("add_on", gInvalidSig); + image_id id = B_OK; + TIOTest* Test = (TIOTest*)instantiate_object(&Archive, &id); + assert(Test == NULL); + assert(id == B_BAD_VALUE); + assert(errno == B_LAUNCH_FAILED_APP_NOT_FOUND); +} +//------------------------------------------------------------------------------ +/** + instantiate_object(BMessage* archive, image_id* id) + @case Valid archive of locally-defined class with correct + signature + @param archive Valid BMessage pointer with string field "class" containing + name of locally-defined class and string field "add_on" + containing signature of current team + @param id Valid image_id pointer + @requires locally defined class which can be instantiated via + archiving mechanism + @results Returns valid TIOTest instance. + *id is set to B_BAD_VALUE (no image loaded). + errno is set to B_OK. + @note This test is not currently used; GetLocalSignature() doesn't + seem to work without a BApplication instance constructed. + See GetLocalSignature() for more info. + */ +void TInstantiateObjectTester::Case12() +{ + errno = B_OK; + BMessage Archive; + Archive.AddString("class", gLocalClassName); + Archive.AddString("add_on", GetLocalSignature().c_str()); + image_id id = B_OK; + TIOTest* Test = (TIOTest*)instantiate_object(&Archive, &id); + assert(Test != NULL); + assert(id == B_BAD_VALUE); + assert(errno == B_OK); +} +//------------------------------------------------------------------------------ +/** + instantiate_object(BMessage* archive, image_id* id) + @case Valid archive of class defined in add-on explicitely loaded + by this team with signature of add-on + @param archive Valid BMessage pointer with string field "class" containing + name of remotely-defined class and string field "add_on" + containing signature of loaded add-on + @param id Valid image_id pointer + @requires RemoteObjectDef add-on must be built and accessible + @results Returns valid instance of TRemoteTestObject. + *id is set to B_BAD_VALUE (image load not necessary). + errno is set to B_OK. + */ +void TInstantiateObjectTester::Case13() +{ + errno = B_OK; + LoadAddon(); + + BMessage Archive; + Archive.AddString("class", gRemoteClassName); + Archive.AddString("add_on", gRemoteSig); + image_id id = B_OK; + TRemoteTestObject* Test = (TRemoteTestObject*)instantiate_object(&Archive, &id); + assert(Test != NULL); + assert(id == B_BAD_VALUE); + assert(errno == B_OK); + + UnloadAddon(); +} +//------------------------------------------------------------------------------ +/** + instantiate_object(BMessage* archive, image_id* id) + @case Valid archive of remotely-defined class with correct + signature + @param archive Valid BMessage pointer with string field "class" containing + name of remotely-defined class and string field "add_on" + containing signature of defining add-on + @param id Valid image_id pointer + @requires RemoteObjectDef must be built and accessible + @results Returns valid instance of TRemoteTestObject. + *id > 0 (image was loaded). + errno is set to B_OK. + */ +void TInstantiateObjectTester::Case14() +{ + errno = B_OK; + BMessage Archive; + Archive.AddString("class", gRemoteClassName); + Archive.AddString("add_on", gRemoteSig); + image_id id = B_OK; + TRemoteTestObject* Test = (TRemoteTestObject*)instantiate_object(&Archive, &id); + assert(Test != NULL); + assert(id > 0); + unload_add_on(id); + assert(errno == B_OK); +} +//------------------------------------------------------------------------------ +Test* TInstantiateObjectTester::Suite() +{ + TestSuite* SuiteOfTests = new TestSuite; + + ADD_TEST(SuiteOfTests, TInstantiateObjectTester, Case1); + ADD_TEST(SuiteOfTests, TInstantiateObjectTester, Case2); + ADD_TEST(SuiteOfTests, TInstantiateObjectTester, Case3); + ADD_TEST(SuiteOfTests, TInstantiateObjectTester, Case4); + ADD_TEST(SuiteOfTests, TInstantiateObjectTester, Case5); + ADD_TEST(SuiteOfTests, TInstantiateObjectTester, Case6); + ADD_TEST(SuiteOfTests, TInstantiateObjectTester, Case7); + ADD_TEST(SuiteOfTests, TInstantiateObjectTester, Case8); + ADD_TEST(SuiteOfTests, TInstantiateObjectTester, Case9); + ADD_TEST(SuiteOfTests, TInstantiateObjectTester, Case10); + ADD_TEST(SuiteOfTests, TInstantiateObjectTester, Case11); +// ADD_TEST(SuiteOfTests, TInstantiateObjectTester, Case12); + ADD_TEST(SuiteOfTests, TInstantiateObjectTester, Case13); + ADD_TEST(SuiteOfTests, TInstantiateObjectTester, Case14); + + return SuiteOfTests; +} +//------------------------------------------------------------------------------ +void TInstantiateObjectTester::LoadAddon() +{ + if (fAddonId > 0) + return; + + BRoster Roster; + entry_ref ref; + status_t err = Roster.FindApp(gRemoteSig, &ref); + + if (err) + { + FORMAT_AND_THROW(" failed to find app: ", err); + } + + BPath Path(&ref); + fAddonId = load_add_on(Path.Path()); + if (fAddonId <= 0) + { + FORMAT_AND_THROW(" failed to load addon: ", fAddonId); + } +} +//------------------------------------------------------------------------------ +void TInstantiateObjectTester::UnloadAddon() +{ + if (fAddonId > 0) + { + status_t err = unload_add_on(fAddonId); + fAddonId = B_ERROR; + if (err) + { + FORMAT_AND_THROW(" failed to unload addon: ", err); + } + } +} +//------------------------------------------------------------------------------ +std::string TInstantiateObjectTester::GetLocalSignature() +{ + BRoster Roster; + app_info ai; + team_id team; + + // Get the team_id of this app + thread_id tid = find_thread(NULL); + thread_info ti; + status_t err = get_thread_info(tid, &ti); + if (err) + { + FORMAT_AND_THROW(" failed to get thread_info: ", err); + } + + // Get the app_info via the team_id + team = ti.team; + team_info info; + err = get_team_info(team, &info); + if (err) + { + FORMAT_AND_THROW(" failed to get team_info: ", err); + } + + team = info.team; + + // It seems that this call to GetRunningAppInfo() is not working because we + // don't have an instance of BApplication somewhere -- the roster, therefore, + // doesn't know about us. + err = Roster.GetRunningAppInfo(team, &ai); + if (err) + { + FORMAT_AND_THROW(" failed to get app_info: ", err); + } + + // Return the signature from the app_info + return ai.signature; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void FormatAndThrow(int line, const char *file, const char *msg, int err) +{ + string s("line: "); + s += estring(line); + s += " "; + s += file; + s += msg; + s += strerror(err); + s += "("; + s += estring(err); + s += ")"; + std::runtime_error re(s.c_str()); + throw re; +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/support/barchivable/InstantiateObjectTester.h b/src/tests/kits/support/barchivable/InstantiateObjectTester.h new file mode 100644 index 0000000000..b1621b2363 --- /dev/null +++ b/src/tests/kits/support/barchivable/InstantiateObjectTester.h @@ -0,0 +1,62 @@ +//------------------------------------------------------------------------------ +// InstantiateObjectTester.h +// +//------------------------------------------------------------------------------ + +#ifndef INSTANTIATEOBJECTTESTER_H +#define INSTANTIATEOBJECTTESTER_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "LocalCommon.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +class TInstantiateObjectTester : public TestCase +{ + public: + TInstantiateObjectTester(std::string name); + + void Case1(); + void Case2(); + void Case3(); + void Case4(); + void Case5(); + void Case6(); + void Case7(); + void Case8(); + void Case9(); + void Case10(); + void Case11(); + void Case12(); + void Case13(); + void Case14(); + + static Test* Suite(); + + private: + void LoadAddon(); + void UnloadAddon(); + std::string GetLocalSignature(); + + image_id fAddonId; +}; +//------------------------------------------------------------------------------ + +#endif //INSTANTIATEOBJECTTESTER_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/support/barchivable/LocalCommon.h b/src/tests/kits/support/barchivable/LocalCommon.h new file mode 100644 index 0000000000..acb175cdee --- /dev/null +++ b/src/tests/kits/support/barchivable/LocalCommon.h @@ -0,0 +1,43 @@ +//------------------------------------------------------------------------------ +// LocalCommon.h +// +//------------------------------------------------------------------------------ + +#ifndef LOCALCOMMON_H +#define LOCALCOMMON_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#ifdef SYSTEM_TEST +#include +#else +#include "../../../../source/lib/support/headers/Archivable.h" +#endif + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "common.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- +extern const char* gInvalidClassName; +extern const char* gInvalidSig; +extern const char* gLocalClassName; +extern const char* gLocalSig; +extern const char* gRemoteClassName; +extern const char* gRemoteSig; +extern const char* gValidSig; + + +#endif //LOCALCOMMON_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/support/barchivable/LocalTestObject.cpp b/src/tests/kits/support/barchivable/LocalTestObject.cpp new file mode 100644 index 0000000000..fb5d3d1aac --- /dev/null +++ b/src/tests/kits/support/barchivable/LocalTestObject.cpp @@ -0,0 +1,56 @@ +//------------------------------------------------------------------------------ +// LocalTestObject.cpp +// +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "LocalTestObject.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +TIOTest::TIOTest(int32 i) + : data(i) +{ + ; +} +//------------------------------------------------------------------------------ +TIOTest::TIOTest(BMessage *archive) +{ + data = archive->FindInt32("TIOTest::data"); +} +//------------------------------------------------------------------------------ +status_t TIOTest::Archive(BMessage *archive, bool deep) +{ + status_t err = archive->AddString("class", "TIOTest"); + if (!err) + err = archive->AddInt32("TIOTest::data", data); + + return err; +} +//------------------------------------------------------------------------------ +TIOTest* TIOTest::Instantiate(BMessage *archive) +{ + if (validate_instantiation(archive, "TIOTest")) + return new TIOTest(archive); + + return NULL; +} +//------------------------------------------------------------------------------ + + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/support/barchivable/LocalTestObject.h b/src/tests/kits/support/barchivable/LocalTestObject.h new file mode 100644 index 0000000000..c751206c63 --- /dev/null +++ b/src/tests/kits/support/barchivable/LocalTestObject.h @@ -0,0 +1,50 @@ +//------------------------------------------------------------------------------ +// LocalTestObject.h +// +//------------------------------------------------------------------------------ + +#ifndef LOCALTESTOBJECT_H +#define LOCALTESTOBJECT_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#include +#ifdef SYSTEM_TEST +#include +#else +#include "../../../../source/lib/support/headers/Archivable.h" +#endif + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +class TIOTest : public BArchivable +{ + public: + TIOTest(int32 i); + int32 GetData() { return data; } + + // All the archiving-related stuff + TIOTest(BMessage* archive); + status_t Archive(BMessage* archive, bool deep = true); + static TIOTest* Instantiate(BMessage* archive); + + private: + int32 data; +}; + +#endif //LOCALTESTOBJECT_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/support/barchivable/ValidateInstantiationTester.cpp b/src/tests/kits/support/barchivable/ValidateInstantiationTester.cpp new file mode 100644 index 0000000000..d788086a2c --- /dev/null +++ b/src/tests/kits/support/barchivable/ValidateInstantiationTester.cpp @@ -0,0 +1,158 @@ +//------------------------------------------------------------------------------ +// ValidateInstantiationTester.cpp +// +/** + Testing for validate_instantiation(BMessage* archive, const char* className) + @note The AllParamsInvalid() and ArchiveInvalid() test are not to be run + against the original implementation, as it does not validate the + archive parameter with a resulting segment violation. + */ +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- +#include + +// System Includes ------------------------------------------------------------- +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "ValidateInstantiationTester.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- +const char* gClassName = "FooBar"; +const char* gBogusClassName = "BarFoo"; + +//------------------------------------------------------------------------------ +/** + validate_instantiation(BMessage* archive, const char* className) + @case All parameters invalid (i.e., NULL) + @param archive NULL + @param className NULL + @results Returns false. + errno is set to B_BAD_VALUE. + */ +void TValidateInstantiationTest::AllParamsInvalid() +{ + errno = B_OK; + assert(!validate_instantiation(NULL, NULL)); + assert(errno == B_BAD_VALUE); +} +//------------------------------------------------------------------------------ +/** + validate_instantiation(BMessage* archive, const char* className) + @case Valid archive, invalid className (i.e., NULL) + @param archive Valid BMessage pointer + @param className NULL + @results Returns false. + errno is set to B_MISMATCHED_VALUES. + */ +void TValidateInstantiationTest::ClassNameParamInvalid() +{ + errno = B_OK; + BMessage Archive; + assert(!validate_instantiation(&Archive, NULL)); + assert(errno == B_MISMATCHED_VALUES); +} +//------------------------------------------------------------------------------ +/** + validate_instantiation(BMessage* archive, const char* className) + @case Invalid archive (i.e., NULL), valid className + @param archive NULL + @param className A valid C-string + @results Returns false. + errno is set to B_BAD_VALUE. + @note Do not run this test against the original implementation + as it does not verify the validity of archive, resulting + in a segment violation. + */ +void TValidateInstantiationTest::ArchiveParamInvalid() +{ + errno = B_OK; + assert(!validate_instantiation(NULL, gClassName)); + assert(errno == B_BAD_VALUE); +} +//------------------------------------------------------------------------------ +/** + validate_instantiation(BMessage* archive, const char* className) + @case Valid archive and className with no string field "class" + in archive + @param archive Valid BMessage pointer + @param className Valid C-string + @results Returns false. + errno is set to B_MISMATCHED_VALUES. + */ +void TValidateInstantiationTest::ClassFieldEmpty() +{ + errno = B_OK; + BMessage Archive; + assert(!validate_instantiation(&Archive, gClassName)); + assert(errno == B_MISMATCHED_VALUES); +} +//------------------------------------------------------------------------------ +/** + validate_instantiation(BMessage* archive, const char* className) + @case Valid archive with string field "class"; className does + not match the content of "class" + @param archive Valid BMessage pointer with string field "class" + @param className Valid C-string which does not match archive field + "class" + @results Returns false. + errno is set to B_MISMATCHED_VALUES. + */ +void TValidateInstantiationTest::ClassFieldBogus() +{ + errno = B_OK; + BMessage Archive; + Archive.AddString("class", gClassName); + assert(!validate_instantiation(&Archive, gBogusClassName)); + assert(errno == B_MISMATCHED_VALUES); +} +//------------------------------------------------------------------------------ +/** + validate_instantiation(BMessage* archive, const char* className) + @case All parameters valid + @param archive Valid BMessage pointer with string field "class" + containing a class name + @param className Valid C-string which matches contents of archive field + "class" + @results Returns true. + errno is set to B_OK. + */ +void TValidateInstantiationTest::AllValid() +{ + errno = B_OK; + BMessage Archive; + Archive.AddString("class", gClassName); + assert(validate_instantiation(&Archive, gClassName)); + assert(errno == B_OK); +} +//------------------------------------------------------------------------------ +Test* TValidateInstantiationTest::Suite() +{ + TestSuite* SuiteOfTests = new TestSuite; +#if !defined(SYSTEM_TEST) + ADD_TEST(SuiteOfTests, TValidateInstantiationTest, AllParamsInvalid); +#endif + ADD_TEST(SuiteOfTests, TValidateInstantiationTest, ClassNameParamInvalid); +#if !defined(SYSTEM_TEST) + ADD_TEST(SuiteOfTests, TValidateInstantiationTest, ArchiveParamInvalid); +#endif + ADD_TEST(SuiteOfTests, TValidateInstantiationTest, ClassFieldEmpty); + ADD_TEST(SuiteOfTests, TValidateInstantiationTest, ClassFieldBogus); + ADD_TEST(SuiteOfTests, TValidateInstantiationTest, AllValid); + + return SuiteOfTests; +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/support/barchivable/ValidateInstantiationTester.h b/src/tests/kits/support/barchivable/ValidateInstantiationTester.h new file mode 100644 index 0000000000..07ccd1b732 --- /dev/null +++ b/src/tests/kits/support/barchivable/ValidateInstantiationTester.h @@ -0,0 +1,48 @@ +//------------------------------------------------------------------------------ +// ValidateInstantiationTester.h +// +//------------------------------------------------------------------------------ + +#ifndef VALIDATEINSTANTIATIONTESTER_H +#define VALIDATEINSTANTIATIONTESTER_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- + +// Project Includes ------------------------------------------------------------ +#include "LocalCommon.h" + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +class TValidateInstantiationTest : public TestCase +{ + public: + TValidateInstantiationTest(std::string name) : TestCase(name) {;} + + void AllParamsInvalid(); + void ClassNameParamInvalid(); + void ArchiveParamInvalid(); + void ClassFieldEmpty(); + void ClassFieldBogus(); + void AllValid(); + + static Test* Suite(); +}; +//------------------------------------------------------------------------------ + + +#endif //VALIDATEINSTANTIATIONTESTER_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/support/barchivable/main.cpp b/src/tests/kits/support/barchivable/main.cpp new file mode 100644 index 0000000000..beccdce83b --- /dev/null +++ b/src/tests/kits/support/barchivable/main.cpp @@ -0,0 +1,61 @@ +//------------------------------------------------------------------------------ +// main.cpp +// +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "LocalCommon.h" +#include "BArchivableTester.h" +#include "ValidateInstantiationTester.h" +#include "InstantiateObjectTester.h" +#include "FindInstantiationFuncTester.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +// Function: addonTestFunc() +// Descr: This function is called by the test application to +// get a pointer to the test to run. +//------------------------------------------------------------------------------ + +Test* addonTestFunc() +{ + TestSuite* tests = new TestSuite("BArchivable"); + + tests->addTest(TBArchivableTestCase::Suite()); + tests->addTest(TValidateInstantiationTest::Suite()); + tests->addTest(TInstantiateObjectTester::Suite()); + tests->addTest(TFindInstantiationFuncTester::Suite()); + + return tests; +} + +int main() +{ + Test* tests = addonTestFunc(); + + TextTestResult Result; + tests->run(&Result); + cout << Result << endl; + + delete tests; + + return !Result.wasSuccessful(); +} + + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/support/barchivable/remoteobjectdef/RemoteTestObject.cpp b/src/tests/kits/support/barchivable/remoteobjectdef/RemoteTestObject.cpp new file mode 100644 index 0000000000..9857b867cb --- /dev/null +++ b/src/tests/kits/support/barchivable/remoteobjectdef/RemoteTestObject.cpp @@ -0,0 +1,57 @@ +//------------------------------------------------------------------------------ +// RemoteTestObject.cpp +// +//------------------------------------------------------------------------------ + +// Standard Includes ----------------------------------------------------------- +#include + +// System Includes ------------------------------------------------------------- +#include + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- +#include "RemoteTestObject.h" + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +TRemoteTestObject::TRemoteTestObject(int32 i) + : data(i) +{ + ; +} +//------------------------------------------------------------------------------ +TRemoteTestObject::TRemoteTestObject(BMessage *archive) +{ + data = archive->FindInt32("TRemoteTestObject::data"); +} +//------------------------------------------------------------------------------ +status_t TRemoteTestObject::Archive(BMessage *archive, bool deep) +{ + status_t err = archive->AddString("class", "TRemoteTestObject"); + + if (!err) + err = archive->AddInt32("TRemoteTestObject::data", data); + + return err; +} +//------------------------------------------------------------------------------ +TRemoteTestObject* TRemoteTestObject::Instantiate(BMessage *archive) +{ + if (validate_instantiation(archive, "TRemoteTestObject")) + return new TRemoteTestObject(archive); + return NULL; +} +//------------------------------------------------------------------------------ + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/support/barchivable/remoteobjectdef/RemoteTestObject.h b/src/tests/kits/support/barchivable/remoteobjectdef/RemoteTestObject.h new file mode 100644 index 0000000000..a6777cf70f --- /dev/null +++ b/src/tests/kits/support/barchivable/remoteobjectdef/RemoteTestObject.h @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +// RemoteTestObject.h +// +//------------------------------------------------------------------------------ + +#ifndef REMOTETESTOBJECT_H +#define REMOTETESTOBJECT_H + +// Standard Includes ----------------------------------------------------------- + +// System Includes ------------------------------------------------------------- +#ifdef SYSTEM_TEST +#include +#else +#include "../../../../../source/lib/support/headers/Archivable.h" +#endif + +// Project Includes ------------------------------------------------------------ + +// Local Includes -------------------------------------------------------------- + +// Local Defines --------------------------------------------------------------- + +// Globals --------------------------------------------------------------------- + +class BMessage; + +class TRemoteTestObject : public BArchivable +{ + public: + TRemoteTestObject(int32 i); + int32 GetData() { return data; } + + // All the archiving-related stuff + TRemoteTestObject(BMessage* archive); + status_t Archive(BMessage* archive, bool deep = true); + static TRemoteTestObject* Instantiate(BMessage* archive); + + private: + int32 data; +}; + +#endif //REMOTETESTOBJECT_H + +/* + * $Log $ + * + * $Id $ + * + */ + diff --git a/src/tests/kits/support/barchivable/remoteobjectdef/Resource.rsrc b/src/tests/kits/support/barchivable/remoteobjectdef/Resource.rsrc new file mode 100644 index 0000000000..795602d342 Binary files /dev/null and b/src/tests/kits/support/barchivable/remoteobjectdef/Resource.rsrc differ diff --git a/src/tests/kits/support/bautolock/AutolockLockerTest.cpp b/src/tests/kits/support/bautolock/AutolockLockerTest.cpp new file mode 100644 index 0000000000..edc88e3b08 --- /dev/null +++ b/src/tests/kits/support/bautolock/AutolockLockerTest.cpp @@ -0,0 +1,144 @@ +/* + $Id: AutolockLockerTest.cpp,v 1.1 2002/07/09 12:24:57 ejakowatz Exp $ + + This file tests all use cases of the BAutolock when used with a BLocker. + BLooper based tests are done seperately. + + */ + + +#include "AutolockLockerTest.h" +#include +#include "Autolock.h" +#include + + +const bigtime_t SNOOZE_TIME = 250000; + + +/* + * Method: AutolockLockerTest::AutolockLockerTest() + * Descr: This method is the only constructor for the AutolockLockerTest + * class. + */ + +template + AutolockLockerTest::AutolockLockerTest(std::string name) : + TestCase(name), theLocker(new Locker) +{ + } + + +/* + * Method: AutolockLockerTest::~AutolockLockerTest() + * Descr: This method is the destructor for the AutolockLockerTest class. + * It only deallocates the autolocker and locker. + */ + +template + AutolockLockerTest::~AutolockLockerTest() +{ + delete theLocker; + theLocker = NULL; + } + + +/* + * Method: AutolockLockerTest::TestThread1() + * Descr: This method performs the tests on the Autolock. It first acquires the + * lock and sleeps for a short time. It deletes the lock rather than Unlock() + * it in order to test the other two threads. Then, it constructs a new + * Locker and Autolock and checks that both the Autolock and the Locker are + * both locked. Then, the Autolock is released by deleting it. The Locker + * is checked to see that it is now released. This is then repeated for an Autolock + * constructed by passing a reference to the Locker. + */ + +template + void AutolockLockerTest::TestThread1(void) +{ + Autolock *theAutolock; + + assert(theLocker->Lock()); + assert(theLocker->LockingThread() == find_thread(NULL)); + snooze(SNOOZE_TIME); + delete theLocker; + + theLocker = new Locker; + theAutolock = new Autolock(theLocker); + + assert(theLocker->IsLocked()); + assert(theLocker->LockingThread() == find_thread(NULL)); + assert(theAutolock->IsLocked()); + + delete theAutolock; + theAutolock = NULL; + assert(theLocker->LockingThread() != find_thread(NULL)); + + theAutolock = new Autolock(*theLocker); + assert(theLocker->IsLocked()); + assert(theLocker->LockingThread() == find_thread(NULL)); + assert(theAutolock->IsLocked()); + + delete theAutolock; + theAutolock = NULL; + assert(theLocker->LockingThread() != find_thread(NULL)); +} + + +/* + * Method: AutolockLockerTest::TestThread2() + * Descr: This method performs the tests on the Autolock. It first sleeps for a short + * time and then tries to acquire the lock with an Autolock. It passes a pointer + * to the lock to the Autolock. It expects the acquisition to fail and IsLocked() + * is tested to be sure. + */ + +template + void AutolockLockerTest::TestThread2(void) +{ + snooze(SNOOZE_TIME / 10); + Autolock theAutolock(theLocker); + assert(!theAutolock.IsLocked()); +} + + +/* + * Method: AutolockLockerTest::TestThread3() + * Descr: This method performs the tests on the Autolock. It first sleeps for a short + * time and then tries to acquire the lock with an Autolock. It passes a reference + * to the lock to the Autolock. It expects the acquisition to fail and IsLocked() + * is tested to be sure. + */ + +template + void AutolockLockerTest::TestThread3(void) +{ + snooze(SNOOZE_TIME / 10); + Autolock theAutolock(*theLocker); + assert(!theAutolock.IsLocked()); +} + + +/* + * Method: AutolockLockerTest::suite() + * Descr: This static member function returns a test caller for performing + * the "AutolockLockerTest" test. The test caller + * is created as a ThreadedTestCaller (typedef'd as + * BenaphoreLockCountTest1Caller) with three independent threads. + */ + +template + Test *AutolockLockerTest::suite(void) +{ + AutolockLockerTest *theTest = new AutolockLockerTest(""); + AutolockLockerTestCaller *threadedTest = new AutolockLockerTestCaller("", theTest); + threadedTest->addThread(":Thread1", &AutolockLockerTest::TestThread1); + threadedTest->addThread(":Thread2", &AutolockLockerTest::TestThread2); + threadedTest->addThread(":Thread3", &AutolockLockerTest::TestThread3); + return(threadedTest); + } + + +template class AutolockLockerTest; +template class AutolockLockerTest; \ No newline at end of file diff --git a/src/tests/kits/support/bautolock/AutolockLockerTest.h b/src/tests/kits/support/bautolock/AutolockLockerTest.h new file mode 100644 index 0000000000..6356814299 --- /dev/null +++ b/src/tests/kits/support/bautolock/AutolockLockerTest.h @@ -0,0 +1,34 @@ +/* + $Id: AutolockLockerTest.h,v 1.1 2002/07/09 12:24:57 ejakowatz Exp $ + + This file defines the class for performing all BAutolock tests on a + BLocker. + + */ + + +#ifndef AutolockLockerTest_H +#define AutolockLockerTest_H + + +#include "ThreadedTestCaller.h" +#include "TestCase.h" + +template class AutolockLockerTest : public TestCase { + +private: + typedef ThreadedTestCaller > + AutolockLockerTestCaller; + + Locker *theLocker; + +public: + static Test *suite(void); + void TestThread1(void); + void TestThread2(void); + void TestThread3(void); + AutolockLockerTest(std::string); + virtual ~AutolockLockerTest(); + }; + +#endif \ No newline at end of file diff --git a/src/tests/kits/support/bautolock/AutolockLooperTest.cpp b/src/tests/kits/support/bautolock/AutolockLooperTest.cpp new file mode 100644 index 0000000000..6430c20743 --- /dev/null +++ b/src/tests/kits/support/bautolock/AutolockLooperTest.cpp @@ -0,0 +1,90 @@ +/* + $Id: AutolockLooperTest.cpp,v 1.1 2002/07/09 12:24:57 ejakowatz Exp $ + + This file tests all use cases of the BAutolock when used with a BLooper. + BLocker based tests are done seperately. + + */ + + +#include "AutolockLooperTest.h" +#include +#include "Autolock.h" +#include + + +const bigtime_t SNOOZE_TIME = 250000; + + +/* + * Method: AutolockLooperTest::AutolockLooperTest() + * Descr: This method is the only constructor for the AutolockLooperTest + * class. + */ + +template + AutolockLooperTest::AutolockLooperTest(std::string name) : + TestCase(name), theLooper(new Looper) +{ + theLooper->Run(); + } + + +/* + * Method: AutolockLooperTest::~AutolockLooperTest() + * Descr: This method is the destructor for the AutolockLooperTest class. + * It only deallocates the autoLooper and Looper. + */ + +template + AutolockLooperTest::~AutolockLooperTest() +{ + if (theLooper != NULL) + theLooper->Lock(); + theLooper->Quit(); + } + + +/* + * Method: AutolockLooperTest::TestThread1() + * Descr: This method performs the tests on the Autolock. It constructs a new + * Autolock and checks that both the Autolock and the Looper are + * both locked. Then, the Autolock is released by deleting it. The Looper + * is checked to see that it is now released. + */ + +template + void AutolockLooperTest::TestThread1(void) +{ + Autolock *theAutolock = new Autolock(theLooper); + + assert(theLooper->IsLocked()); + assert(theLooper->LockingThread() == find_thread(NULL)); + assert(theAutolock->IsLocked()); + + delete theAutolock; + theAutolock = NULL; + assert(theLooper->LockingThread() != find_thread(NULL)); +} + + +/* + * Method: AutolockLooperTest::suite() + * Descr: This static member function returns a test caller for performing + * the "AutolockLooperTest" test. The test caller + * is created as a ThreadedTestCaller (typedef'd as + * BenaphoreLockCountTest1Caller) with three independent threads. + */ + +template + Test *AutolockLooperTest::suite(void) +{ + AutolockLooperTest *theTest = new AutolockLooperTest(""); + AutolockLooperTestCaller *threadedTest = new AutolockLooperTestCaller("", theTest); + threadedTest->addThread(":Thread1", &AutolockLooperTest::TestThread1); + return(threadedTest); + } + + +template class AutolockLooperTest; +template class AutolockLooperTest; \ No newline at end of file diff --git a/src/tests/kits/support/bautolock/AutolockLooperTest.h b/src/tests/kits/support/bautolock/AutolockLooperTest.h new file mode 100644 index 0000000000..899a8f78ee --- /dev/null +++ b/src/tests/kits/support/bautolock/AutolockLooperTest.h @@ -0,0 +1,32 @@ +/* + $Id: AutolockLooperTest.h,v 1.1 2002/07/09 12:24:57 ejakowatz Exp $ + + This file defines the class for performing all BAutolock tests on a + BLooper. + + */ + + +#ifndef AutolockLooperTest_H +#define AutolockLooperTest_H + + +#include "ThreadedTestCaller.h" +#include "TestCase.h" + +template class AutolockLooperTest : public TestCase { + +private: + typedef ThreadedTestCaller > + AutolockLooperTestCaller; + + Looper *theLooper; + +public: + static Test *suite(void); + void TestThread1(void); + AutolockLooperTest(std::string); + virtual ~AutolockLooperTest(); + }; + +#endif \ No newline at end of file diff --git a/src/tests/kits/support/bautolock/AutolockTestAddon.cpp b/src/tests/kits/support/bautolock/AutolockTestAddon.cpp new file mode 100644 index 0000000000..ce49f5c0ec --- /dev/null +++ b/src/tests/kits/support/bautolock/AutolockTestAddon.cpp @@ -0,0 +1,42 @@ +/* + $Id: AutolockTestAddon.cpp,v 1.1 2002/07/09 12:24:57 ejakowatz Exp $ + + This file declares the addonTestName string and addonTestFunc + function for the BLocker tests. These symbols will be used + when the addon is loaded. + + */ + + +#include "AutolockLockerTest.h" +#include "AutolockLooperTest.h" +#include +#include "Autolock.h" +#include "TestAddon.h" +#include "TestSuite.h" + + +/* + * Function: addonTestFunc() + * Descr: This function is called by the test application to + * get a pointer to the test to run. The BLocker test + * is a test suite. A series of tests are added to + * the suite. Each test appears twice, once for + * the Be implementation of BLocker, once for the + * OpenBeOS implementation. + */ + +Test *addonTestFunc(void) +{ + TestSuite *testSuite = new TestSuite("BAutolock"); + + testSuite->addTest(AutolockLockerTest::suite()); + testSuite->addTest(AutolockLooperTest::suite()); + + testSuite->addTest( + AutolockLockerTest::suite()); + testSuite->addTest( + AutolockLooperTest::suite()); + + return(testSuite); +} diff --git a/src/tests/kits/support/blocker/BenaphoreLockCountTest1.cpp b/src/tests/kits/support/blocker/BenaphoreLockCountTest1.cpp new file mode 100644 index 0000000000..037d3e412e --- /dev/null +++ b/src/tests/kits/support/blocker/BenaphoreLockCountTest1.cpp @@ -0,0 +1,186 @@ +/* + $Id: BenaphoreLockCountTest1.cpp,v 1.1 2002/07/09 12:24:58 ejakowatz Exp $ + + This file implements a test class for testing BLocker functionality. + It tests use cases "Count Lock Requests" for a benaphore style BLocker. + + The test works by: + - checking the lock requests + - acquiring the lock + - checking the lock requests + - staring a thread which times out acquiring the lock and then blocks + again waiting for the lock + - checking the lock requests + - start a second thread which times out acquiring the lock and then blocks + again waiting for the lock + - checking the lock requests + - release the lock + - each blocked thread acquires the lock, checks the lock requests and releases + the lock before terminating + - the main thread checks the lock requests one last time + + */ + + +#include "BenaphoreLockCountTest1.h" +#include "TestSuite.h" +#include "ThreadedTestCaller.h" +#include +#include "Locker.h" + + +// This constant is used to determine the number of microseconds to +// sleep during major steps of the test. + +const bigtime_t SNOOZE_TIME = 100000; + + +/* + * Method: BenaphoreLockCountTest1::BenaphoreLockCountTest1() + * Descr: This is the constructor for this test class. + */ + +template + BenaphoreLockCountTest1::BenaphoreLockCountTest1(std::string name) : + LockerTestCase(name, true) +{ + } + + +/* + * Method: BenaphoreLockCountTest1::~BenaphoreLockTestCountTest1() + * Descr: This is the destructor for this test class. + */ + +template + BenaphoreLockCountTest1::~BenaphoreLockCountTest1() +{ + } + + +/* + * Method: BenaphoreLockCountTest1::CheckLockRequests() + * Descr: This member function checks the actual number of lock requests + * that the BLocker thinks are outstanding versus the number + * passed in. If they match, true is returned. + */ + +template bool BenaphoreLockCountTest1::CheckLockRequests(int expected) +{ + int actual = theLocker->CountLockRequests(); + return(actual == expected); +} + + +/* + * Method: BenaphoreLockCountTest1::TestThread1() + * Descr: This member function performs the main portion of the test. + * It first acquires thread2Lock and thread3Lock. This ensures + * that thread2 and thread3 will block until this thread wants + * them to start running. It then checks the lock count, acquires + * the lock and checks the lock count again. It unlocks each + * of the other two threads in turn and rechecks the lock count. + * Finally, it releases the lock and sleeps for a short while + * for the other two threads to finish. At the end, it checks + * the lock count on final time. + */ + +template void BenaphoreLockCountTest1::TestThread1(void) +{ + SafetyLock theSafetyLock1(theLocker); + SafetyLock theSafetyLock2(&thread2Lock); + SafetyLock theSafetyLock3(&thread3Lock); + + assert(thread2Lock.Lock()); + assert(thread3Lock.Lock()); + + assert(CheckLockRequests(0)); + assert(theLocker->Lock()); + + assert(CheckLockRequests(1)); + + thread2Lock.Unlock(); + snooze(SNOOZE_TIME); + assert(CheckLockRequests(3)); + + thread3Lock.Unlock(); + snooze(SNOOZE_TIME); + assert(CheckLockRequests(5)); + + theLocker->Unlock(); + snooze(SNOOZE_TIME); + assert(CheckLockRequests(2)); + } + + +/* + * Method: BenaphoreLockCountTest1::TestThread2() + * Descr: This member function defines the actions of the second thread of + * the test. First it sleeps for a short while and then blocks on + * the thread2Lock. When the first thread releases it, this thread + * begins its testing. It times out attempting to acquire the main + * lock and then blocks to acquire the lock. Once that lock is + * acquired, the lock count is checked before finishing this thread. + */ + +template void BenaphoreLockCountTest1::TestThread2(void) +{ + SafetyLock theSafetyLock1(theLocker); + + snooze(SNOOZE_TIME / 10); + assert(thread2Lock.Lock()); + + assert(theLocker->LockWithTimeout(SNOOZE_TIME / 10) == B_TIMED_OUT); + assert(theLocker->Lock()); + int actual = theLocker->CountLockRequests(); + assert((actual == 3) || (actual == 4)); + theLocker->Unlock(); +} + + +/* + * Method: BenaphoreLockCountTest1::TestThread3() + * Descr: This member function defines the actions of the second thread of + * the test. First it sleeps for a short while and then blocks on + * the thread3Lock. When the first thread releases it, this thread + * begins its testing. It times out attempting to acquire the main + * lock and then blocks to acquire the lock. Once that lock is + * acquired, the lock count is checked before finishing this thread. + */ + +template void BenaphoreLockCountTest1::TestThread3(void) +{ + SafetyLock theSafetyLock1(theLocker); + + snooze(SNOOZE_TIME / 10); + assert(thread3Lock.Lock()); + + assert(theLocker->LockWithTimeout(SNOOZE_TIME / 10) == B_TIMED_OUT); + assert(theLocker->Lock()); + int actual = theLocker->CountLockRequests(); + assert((actual == 3) || (actual == 4)); + theLocker->Unlock(); +} + + +/* + * Method: BenaphoreLockCountTest1::suite() + * Descr: This static member function returns a test caller for performing + * the "BenaphoreLockCountTest1" test. The test caller + * is created as a ThreadedTestCaller (typedef'd as + * BenaphoreLockCountTest1Caller) with three independent threads. + */ + +template Test *BenaphoreLockCountTest1::suite(void) +{ + BenaphoreLockCountTest1 *theTest = new BenaphoreLockCountTest1(""); + BenaphoreLockCountTest1Caller *threadedTest = new BenaphoreLockCountTest1Caller("", theTest); + threadedTest->addThread(":Thread1", &BenaphoreLockCountTest1::TestThread1); + threadedTest->addThread(":Thread2", &BenaphoreLockCountTest1::TestThread2); + threadedTest->addThread(":Thread3", &BenaphoreLockCountTest1::TestThread3); + return(threadedTest); + } + + +template class BenaphoreLockCountTest1; +template class BenaphoreLockCountTest1; \ No newline at end of file diff --git a/src/tests/kits/support/blocker/BenaphoreLockCountTest1.h b/src/tests/kits/support/blocker/BenaphoreLockCountTest1.h new file mode 100644 index 0000000000..e8389b9f88 --- /dev/null +++ b/src/tests/kits/support/blocker/BenaphoreLockCountTest1.h @@ -0,0 +1,41 @@ +/* + $Id: BenaphoreLockCountTest1.h,v 1.1 2002/07/09 12:24:58 ejakowatz Exp $ + + This file defines a classes for performing one test of BLocker + functionality. + + */ + + +#ifndef BenaphoreLockCountTest1_H +#define BenaphoreLockCountTest1_H + + +#include "LockerTestCase.h" +#include "ThreadedTestCaller.h" + + +template class BenaphoreLockCountTest1 : + public LockerTestCase { + +private: + typedef ThreadedTestCaller > + BenaphoreLockCountTest1Caller; + + Locker thread2Lock; + Locker thread3Lock; + + bool CheckLockRequests(int); + +protected: + +public: + void TestThread1(void); + void TestThread2(void); + void TestThread3(void); + BenaphoreLockCountTest1(std::string); + virtual ~BenaphoreLockCountTest1(); + static Test *suite(void); + }; + +#endif \ No newline at end of file diff --git a/src/tests/kits/support/blocker/ConcurrencyTest1.cpp b/src/tests/kits/support/blocker/ConcurrencyTest1.cpp new file mode 100644 index 0000000000..1c9222a27c --- /dev/null +++ b/src/tests/kits/support/blocker/ConcurrencyTest1.cpp @@ -0,0 +1,182 @@ +/* + $Id: ConcurrencyTest1.cpp,v 1.1 2002/07/09 12:24:58 ejakowatz Exp $ + + This file implements a test class for testing BLocker functionality. + It tests use cases "Locking 1", "Locking 2", "Unlocking", "Is Locked", + "Locking Thread" and "Count Locks". + + */ + + +#include "ConcurrencyTest1.h" +#include "TestSuite.h" +#include "ThreadedTestCaller.h" +#include +#include "Locker.h" + + +// This constant indicates the number of times the thread should test the +// acquisition and release of the BLocker. + +const int32 MAXLOOP = 10000; + + +/* + * Method: ConcurrencyTest1::ConcurrencyTest1() + * Descr: This is the only constructor for this test case. It takes a + * test name and a flag to indicate whether to test a benaphore + * or semaphore type BLocker. + */ + +template + ConcurrencyTest1::ConcurrencyTest1(std::string name, bool benaphoreFlag) : + LockerTestCase(name, benaphoreFlag), lockTestValue(false) +{ + } + + +/* + * Method: ConcurrencyTest1::~ConcurrencyTest1() + * Descr: This is the descriptor for this test case. + */ + +template + ConcurrencyTest1::~ConcurrencyTest1() +{ + } + + +/* + * Method: ConcurrencyTest1::setUp() + * Descr: This member is called before starting the actual test threads + * and is used to ensure that the class is initialized for the + * testing. It just sets the "lockTestValue" flag to false. This + * flag is used to show that there is mutual exclusion between the + * threads. + */ + +template void + ConcurrencyTest1::setUp(void) +{ + lockTestValue = false; + } + + +/* + * Method: ConcurrencyTest1::suite() + * Descr: This static member function returns a test suite for performing + * all combinations of "ConcurrencyTest1". The test suite contains + * two instances of the test. One is performed on a benaphore, + * the other on a semaphore based BLocker. Each individual test + * is created as a ThreadedTestCase (typedef'd as + * ConcurrencyTest1Caller) with three independent threads. + */ + +template Test *ConcurrencyTest1::suite(void) +{ + TestSuite *testSuite = new TestSuite("ConcurrencyTest1"); + + // Make a benaphore based test object, create a ThreadedTestCase for it and add + // three threads to it. + ConcurrencyTest1 *theTest = new ConcurrencyTest1("Benaphore", true); + ConcurrencyTest1Caller *threadedTest1 = new ConcurrencyTest1Caller("", theTest); + threadedTest1->addThread(":Thread1", &ConcurrencyTest1::TestThread); + threadedTest1->addThread(":Thread2", &ConcurrencyTest1::TestThread); + threadedTest1->addThread(":Thread3", &ConcurrencyTest1::TestThread); + + // Make a semaphore based test object, create a ThreadedTestCase for it and add + // three threads to it. + theTest = new ConcurrencyTest1("Semaphore", false); + ConcurrencyTest1Caller *threadedTest2 = new ConcurrencyTest1Caller("", theTest); + threadedTest2->addThread(":Thread1", &ConcurrencyTest1::TestThread); + threadedTest2->addThread(":Thread2", &ConcurrencyTest1::TestThread); + threadedTest2->addThread(":Thread3", &ConcurrencyTest1::TestThread); + + testSuite->addTest(threadedTest1); + testSuite->addTest(threadedTest2); + return(testSuite); + } + + +/* + * Method: ConcurrencyTest1::AcquireLock() + * Descr: This member function is passed the number of times through the + * acquisition loop (lockAttempt) and whether or not this is + * the first acquisition of the lock within this iteration. + * Based on these values, it may do a LockWithTimeout() or just + * a plain Lock() on theLocker. This is done to get coverage of + * both lock acquisition methods on the BLocker. + */ + +template bool ConcurrencyTest1::AcquireLock(int lockAttempt, + bool firstAcquisition) +{ + bool timeoutLock; + bool result; + + if (firstAcquisition) { + timeoutLock = ((lockAttempt % 2) == 1); + } else { + timeoutLock = (((lockAttempt / 2) % 2) == 1); + } + if (timeoutLock) { + result = (theLocker->LockWithTimeout(1000000) == B_OK); + } else { + result = theLocker->Lock(); + } + return(result); +} + + +/* + * Method: ConcurrencyTest1::TestThread() + * Descr: This method is the core of the test. Each of the three threads + * run this method to perform the concurrency test. First, the + * SafetyLock class (see LockerTestCase.h) is used to make sure that + * the lock is released if an assertion happens. Then, each thread + * iterates MAXLOOP times through the main loop where the following + * actions are performed: + * - CheckLock() is used to show that the thread does not have + * the lock. + * - The thread acquires the lock. + * - The thread confirms that mutual exclusion is OK by testing + * lockTestValue. + * - The thread confirms the lock is held once by the thread. + * - The thread acquires the lock again. + * - The thread confirms the lock is held twice now by the thread. + * - The thread releases the lock once. + * - The thread confirms the lock is held once now. + * - The thread confirms that mutual exclusion is still OK by + * testing lockTestValue. + * - The thread releases the lock again. + * - The thread confirms that the lock is no longer held. + */ + +template void ConcurrencyTest1::TestThread(void) +{ + int i; + SafetyLock theSafetyLock(theLocker); + + for (i = 0; i < MAXLOOP; i++) { + CheckLock(0); + assert(AcquireLock(i, true)); + + assert(!lockTestValue); + lockTestValue = true; + CheckLock(1); + + assert(AcquireLock(i, false)); + CheckLock(2); + + theLocker->Unlock(); + CheckLock(1); + + assert(lockTestValue); + lockTestValue = false; + theLocker->Unlock(); + CheckLock(0); + } +} + +template class ConcurrencyTest1; +template class ConcurrencyTest1; \ No newline at end of file diff --git a/src/tests/kits/support/blocker/ConcurrencyTest1.h b/src/tests/kits/support/blocker/ConcurrencyTest1.h new file mode 100644 index 0000000000..05efcfc469 --- /dev/null +++ b/src/tests/kits/support/blocker/ConcurrencyTest1.h @@ -0,0 +1,36 @@ +/* + $Id: ConcurrencyTest1.h,v 1.1 2002/07/09 12:24:58 ejakowatz Exp $ + + This file defines a class for performing one test of BLocker + functionality. + + */ + + +#ifndef ConcurrencyTest1_H +#define ConcurrencyTest1_H + + +#include "LockerTestCase.h" +#include "ThreadedTestCaller.h" + + +template class ConcurrencyTest1 : + public LockerTestCase { + +private: + typedef ThreadedTestCaller > + ConcurrencyTest1Caller; + bool lockTestValue; + + bool AcquireLock(int, bool); + +public: + ConcurrencyTest1(std::string, bool); + virtual ~ConcurrencyTest1(); + void setUp(void); + void TestThread(void); + static Test *suite(void); + }; + +#endif \ No newline at end of file diff --git a/src/tests/kits/support/blocker/ConcurrencyTest2.cpp b/src/tests/kits/support/blocker/ConcurrencyTest2.cpp new file mode 100644 index 0000000000..7d55c9405b --- /dev/null +++ b/src/tests/kits/support/blocker/ConcurrencyTest2.cpp @@ -0,0 +1,225 @@ +/* + $Id: ConcurrencyTest2.cpp,v 1.1 2002/07/09 12:24:58 ejakowatz Exp $ + + This file implements a test class for testing BLocker functionality. + It tests use cases "Locking 1", "Locking 2", "Unlocking", "Is Locked", + "Locking Thread" and "Count Locks". It is essentially the same as Test1.cpp + except it makes the first LockWithTimeout inside the threads timeout. The + reason for this is because the implementation of BLocker by Be and with OpenBeOS + is such that after one timeout occurs on a benaphore style BLocker, the lock + effectively becomes a semaphore style BLocker. This test tests that condition. + + */ + + +#include "ConcurrencyTest2.h" +#include "TestSuite.h" +#include "ThreadedTestCaller.h" +#include +#include "Locker.h" + + +// This constant indicates the number of times the thread should test the +// acquisition and release of the BLocker. + +const int32 MAXLOOP = 10000; + +// This constant is used to determine the number of microseconds to +// sleep during major steps of the test. + +const bigtime_t SNOOZE_TIME = 200000; + +/* + * Method: ConcurrencyTest2::ConcurrencyTest2() + * Descr: This is the only constructor for this test case. It takes a + * test name and a flag to indicate whether to test a benaphore + * or semaphore type BLocker. + */ + +template + ConcurrencyTest2::ConcurrencyTest2(std::string name, bool benaphoreFlag) : + LockerTestCase(name, benaphoreFlag), lockTestValue(false) +{ + } + + +/* + * Method: ConcurrencyTest2::~ConcurrencyTest2() + * Descr: This is the descriptor for this test case. + */ + +template + ConcurrencyTest2::~ConcurrencyTest2() +{ + } + + +/* + * Method: ConcurrencyTest2::setUp() + * Descr: This member is called before starting the actual test threads + * and is used to ensure that the class is initialized for the + * testing. It just sets the "lockTestValue" flag to false. This + * flag is used to show that there is mutual exclusion between the + * threads. + */ + +template void + ConcurrencyTest2::setUp(void) +{ + lockTestValue = false; + } + + +/* + * Method: ConcurrencyTest2::suite() + * Descr: This static member function returns a test suite for performing + * all combinations of "ConcurrencyTest2". The test suite contains + * two instances of the test. One is performed on a benaphore, + * the other on a semaphore based BLocker. Each individual test + * is created as a ThreadedTestCase (typedef'd as + * ConcurrencyTest2Caller) with three independent threads. + */ + +template Test *ConcurrencyTest2::suite(void) +{ + TestSuite *testSuite = new TestSuite("ConcurrencyTest2"); + + // Make a benaphore based test object, create a ThreadedTestCase for it and add + // three threads to it. + ConcurrencyTest2 *theTest = new ConcurrencyTest2("Benaphore", true); + ConcurrencyTest2Caller *threadedTest1 = new ConcurrencyTest2Caller("", theTest); + threadedTest1->addThread(":Thread1", &ConcurrencyTest2::AcquireThread); + threadedTest1->addThread(":Thread2", &ConcurrencyTest2::TimeoutThread); + threadedTest1->addThread(":Thread3", &ConcurrencyTest2::TimeoutThread); + + // Make a semaphore based test object, create a ThreadedTestCase for it and add + // three threads to it. + theTest = new ConcurrencyTest2("Semaphore", false); + ConcurrencyTest2Caller *threadedTest2 = new ConcurrencyTest2Caller("", theTest); + threadedTest2->addThread(":Thread1", &ConcurrencyTest2::AcquireThread); + threadedTest2->addThread(":Thread2", &ConcurrencyTest2::TimeoutThread); + threadedTest2->addThread(":Thread3", &ConcurrencyTest2::TimeoutThread); + + testSuite->addTest(threadedTest1); + testSuite->addTest(threadedTest2); + return(testSuite); + } + + +/* + * Method: ConcurrencyTest2::AcquireThread() + * Descr: This member function acquires the lock, sleeps for SNOOZE_TIME, + * releases the lock and then launches into the lock loop test. + */ + +template void ConcurrencyTest2::AcquireThread(void) +{ + SafetyLock theSafetyLock(theLocker); + + assert(theLocker->Lock()); + snooze(SNOOZE_TIME); + theLocker->Unlock(); + LockingLoop(); + } + + +/* + * Method: ConcurrencyTest2::AcquireLock() + * Descr: This member function is passed the number of times through the + * acquisition loop (lockAttempt) and whether or not this is + * the first acquisition of the lock within this iteration. + * Based on these values, it may do a LockWithTimeout() or just + * a plain Lock() on theLocker. This is done to get coverage of + * both lock acquisition methods on the BLocker. + */ + +template bool ConcurrencyTest2::AcquireLock(int lockAttempt, + bool firstAcquisition) +{ + bool timeoutLock; + bool result; + + if (firstAcquisition) { + timeoutLock = ((lockAttempt % 2) == 1); + } else { + timeoutLock = (((lockAttempt / 2) % 2) == 1); + } + if (timeoutLock) { + result = (theLocker->LockWithTimeout(1000000) == B_OK); + } else { + result = theLocker->Lock(); + } + return(result); +} + + +/* + * Method: ConcurrencyTest2::TimeoutThread() + * Descr: This member function sleeps for a short time and then attempts to + * acquire the lock for SNOOZE_TIME/10 seconds. This acquisition + * should timeout. Then the locking loop is started. + */ + +template void ConcurrencyTest2::TimeoutThread(void) +{ + SafetyLock theSafetyLock(theLocker); + + snooze(SNOOZE_TIME/2); + assert(theLocker->LockWithTimeout(SNOOZE_TIME/10) == B_TIMED_OUT); + LockingLoop(); +} + + +/* + * Method: ConcurrencyTest2::TestThread() + * Descr: This method is the core of the test. Each of the three threads + * run this method to perform the concurrency test. First, the + * SafetyLock class (see LockerTestCase.h) is used to make sure that + * the lock is released if an assertion happens. Then, each thread + * iterates MAXLOOP times through the main loop where the following + * actions are performed: + * - CheckLock() is used to show that the thread does not have + * the lock. + * - The thread acquires the lock. + * - The thread confirms that mutual exclusion is OK by testing + * lockTestValue. + * - The thread confirms the lock is held once by the thread. + * - The thread acquires the lock again. + * - The thread confirms the lock is held twice now by the thread. + * - The thread releases the lock once. + * - The thread confirms the lock is held once now. + * - The thread confirms that mutual exclusion is still OK by + * testing lockTestValue. + * - The thread releases the lock again. + * - The thread confirms that the lock is no longer held. + */ + +template void ConcurrencyTest2::LockingLoop(void) +{ + int i; + SafetyLock theSafetyLock(theLocker); + + for (i = 0; i < MAXLOOP; i++) { + CheckLock(0); + assert(AcquireLock(i, true)); + + assert(!lockTestValue); + lockTestValue = true; + CheckLock(1); + + assert(AcquireLock(i, false)); + CheckLock(2); + + theLocker->Unlock(); + CheckLock(1); + + assert(lockTestValue); + lockTestValue = false; + theLocker->Unlock(); + CheckLock(0); + } +} + + +template class ConcurrencyTest2; +template class ConcurrencyTest2; \ No newline at end of file diff --git a/src/tests/kits/support/blocker/ConcurrencyTest2.h b/src/tests/kits/support/blocker/ConcurrencyTest2.h new file mode 100644 index 0000000000..c75b9a9d4e --- /dev/null +++ b/src/tests/kits/support/blocker/ConcurrencyTest2.h @@ -0,0 +1,38 @@ +/* + $Id: ConcurrencyTest2.h,v 1.1 2002/07/09 12:24:58 ejakowatz Exp $ + + This file defines a classes for performing one test of BLocker + functionality. + + */ + + +#ifndef ConcurrencyTest2_H +#define ConcurrencyTest2_H + + +#include "LockerTestCase.h" +#include "ThreadedTestCaller.h" + + +template class ConcurrencyTest2 : public LockerTestCase { + +private: + typedef ThreadedTestCaller > + ConcurrencyTest2Caller; + bool lockTestValue; + + void TestThread(void); + bool AcquireLock(int, bool); + void LockingLoop(void); + +public: + ConcurrencyTest2(std::string, bool); + virtual ~ConcurrencyTest2(); + void setUp(void); + void AcquireThread(void); + void TimeoutThread(void); + static Test *suite(void); + }; + +#endif \ No newline at end of file diff --git a/src/tests/kits/support/blocker/ConstructionTest1.cpp b/src/tests/kits/support/blocker/ConstructionTest1.cpp new file mode 100644 index 0000000000..a00062e5b1 --- /dev/null +++ b/src/tests/kits/support/blocker/ConstructionTest1.cpp @@ -0,0 +1,146 @@ +/* + $Id: ConstructionTest1.cpp,v 1.1 2002/07/09 12:24:58 ejakowatz Exp $ + + This file implements a test class for testing BLocker construction + functionality. It checks the "Construction 1", "Construction 2" and + "Sem" use cases. It does so by testing all the documented constructors + and uses the Sem() member function to confirm that the name and style + were set correctly. + + */ + + +#include "ConstructionTest1.h" +#include "TestCaller.h" +#include +#include +#include "Locker.h" + + +/* + * Method: ConstructionTest1::ConstructionTest1() + * Descr: This is the constructor for this class. + */ + +template + ConstructionTest1::ConstructionTest1(std::string name) : + LockerTestCase(name, true) +{ + } + + +/* + * Method: ConstructionTest1::~ConstructionTest1() + * Descr: This is the desctructor for this BLocker test class. + */ + +template + ConstructionTest1::~ConstructionTest1() +{ + } + + +/* + * Method: ConstructionTest1::NameMatches() + * Descr: This member checks that the semaphore owned by the lock + * passed in has the name passed in. + */ + +template bool + ConstructionTest1::NameMatches(const char *name, + Locker *lockerArg) +{ + sem_info theSemInfo; + + assert(get_sem_info(lockerArg->Sem(), &theSemInfo) == B_OK); + return(strcmp(name, theSemInfo.name) == 0); +} + + +/* + * Method: ConstructionTest1::IsBenaphore() + * Descr: This member attempts to confirm that the BLocker passed in + * is a benaphore or a semaphore style locker. It returns true + * if it is a benaphore, false if it is a semaphore. An + * assertion is raised if an error occurs. + */ + +template bool + ConstructionTest1::IsBenaphore(Locker *lockerArg) +{ + int32 semCount; + + assert(get_sem_count(lockerArg->Sem(), &semCount) == B_OK); + switch (semCount) { + case 0: return(true); + break; + case 1: return(false); + break; + default: + // This should not happen. The semaphore count should be + // 0 for a benaphore, 1 for a semaphore. No other value + // is legal in this case. + assert(false); + break; + } + return(false); + } + + +/* + * Method: ConstructionTest1::PerformTest() + * Descr: This member function is used to test each of the constructors + * for the BLocker. The resulting BLocker is tested to show + * that the BLocker was constructed correctly. + */ + +template void ConstructionTest1::PerformTest(void) +{ + assert(NameMatches("some BLocker", theLocker)); + assert(IsBenaphore(theLocker)); + + Locker locker1("test string"); + assert(NameMatches("test string", &locker1)); + assert(IsBenaphore(&locker1)); + + Locker locker2(false); + assert(NameMatches("some BLocker", &locker2)); + assert(!IsBenaphore(&locker2)); + + Locker locker3(true); + assert(NameMatches("some BLocker", &locker3)); + assert(IsBenaphore(&locker3)); + + Locker locker4("test string", false); + assert(NameMatches("test string", &locker4)); + assert(!IsBenaphore(&locker4)); + + Locker locker5("test string", true); + assert(NameMatches("test string", &locker5)); + assert(IsBenaphore(&locker5)); +} + + +/* + * Method: ConstructionTest1::suite() + * Descr: This static member function returns a threaded test caller for + * performing "ConstructionTest1". The threaded test caller + * only has a single thread pointint to the PerformTest() member + * function of this class. + */ + +template Test *ConstructionTest1::suite(void) +{ + ConstructionTest1 *theTest = + new ConstructionTest1(""); + + ConstructionTest1Caller *testCaller = + new ConstructionTest1Caller("", theTest); + + testCaller->addThread(":Thread1", + &ConstructionTest1::PerformTest); + return(testCaller); +} + +template class ConstructionTest1; +template class ConstructionTest1; \ No newline at end of file diff --git a/src/tests/kits/support/blocker/ConstructionTest1.h b/src/tests/kits/support/blocker/ConstructionTest1.h new file mode 100644 index 0000000000..8f0163b9c4 --- /dev/null +++ b/src/tests/kits/support/blocker/ConstructionTest1.h @@ -0,0 +1,36 @@ +/* + $Id: ConstructionTest1.h,v 1.1 2002/07/09 12:24:58 ejakowatz Exp $ + + This file defines a class for performing one test of BLocker + functionality. + + */ + + +#ifndef ConstructionTest1_H +#define ConstructionTest1_H + + +#include "LockerTestCase.h" +#include "ThreadedTestCaller.h" + + +template class ConstructionTest1 : + public LockerTestCase { + +private: + typedef ThreadedTestCaller > + ConstructionTest1Caller; + bool NameMatches(const char *, Locker *); + bool IsBenaphore(Locker *); + +protected: + +public: + void PerformTest(void); + ConstructionTest1(std::string name); + virtual ~ConstructionTest1(); + static Test *suite(void); + }; + +#endif \ No newline at end of file diff --git a/src/tests/kits/support/blocker/DestructionTest1.cpp b/src/tests/kits/support/blocker/DestructionTest1.cpp new file mode 100644 index 0000000000..c504b03496 --- /dev/null +++ b/src/tests/kits/support/blocker/DestructionTest1.cpp @@ -0,0 +1,130 @@ +/* + $Id: DestructionTest1.cpp,v 1.1 2002/07/09 12:24:58 ejakowatz Exp $ + + This file implements a test class for testing BLocker functionality. + It tests use cases "Destruction" and "Locking 3". + + The test works like the following: + - the main thread acquires the lock + - the second thread sleeps + - the second thread then attempts to acquire the lock + - the first thread releases the lock + - at this time, the new thread acquires the lock and goes to sleep + - the first thread attempts to acquire the lock + - the second thread deletes the lock + - the first thread is woken up indicating that the lock wasn't acquired. + + */ + + +#include "DestructionTest1.h" +#include "TestSuite.h" +#include "ThreadedTestCaller.h" +#include +#include "Locker.h" + +// This constant is used to determine the number of microseconds to +// sleep during major steps of the test. + +const bigtime_t SNOOZE_TIME = 200000; + + +/* + * Method: DestructionTest1::DestructionTest1() + * Descr: This is the only constructor for this test class. + */ + +template + DestructionTest1::DestructionTest1(std::string name, + bool isBenaphore) : + LockerTestCase(name, isBenaphore) +{ + } + + +/* + * Method: DestructionTest1::~DestructionTest1() + * Descr: This is the only destructor for this test class. + */ + +template + DestructionTest1::~DestructionTest1() +{ + } + + +/* + * Method: DestructionTest1::TestThread1() + * Descr: This method immediately acquires the lock, sleeps + * for SNOOZE_TIME and then releases the lock. It sleeps + * again for SNOOZE_TIME and then tries to re-acquire the + * lock. By this time, the other thread should have + * deleted the lock. This acquisition should fail. + */ + +template void DestructionTest1::TestThread1(void) +{ + assert(theLocker->Lock()); + snooze(SNOOZE_TIME); + theLocker->Unlock(); + snooze(SNOOZE_TIME); + assert(!theLocker->Lock()); + } + + +/* + * Method: DestructionTest1::TestThread2() + * Descr: This method sleeps for SNOOZE_TIME and then acquires the lock. + * It sleeps again for 2*SNOOZE_TIME and then deletes the lock. + * This should wake up the other thread. + */ + +template void DestructionTest1::TestThread2(void) +{ + Locker *tmpLock; + + snooze(SNOOZE_TIME); + assert(theLocker->Lock()); + snooze(SNOOZE_TIME); + snooze(SNOOZE_TIME); + tmpLock = theLocker; + theLocker = NULL; + delete tmpLock; +} + + +/* + * Method: DestructionTest1::suite() + * Descr: This static member function returns a test suite for performing + * all combinations of "DestructionTest1". The test suite contains + * two instances of the test. One is performed on a benaphore, + * the other on a semaphore based BLocker. Each individual test + * is created as a ThreadedTestCase (typedef'd as + * DestructionTest1Caller) with two independent threads. + */ + +template Test *DestructionTest1::suite(void) +{ + TestSuite *testSuite = new TestSuite("DestructionTest1"); + + // Make a benaphore based test object, create a ThreadedTestCase for it and add + // two threads to it. + DestructionTest1 *theTest = new DestructionTest1("Benaphore", true); + DestructionTest1Caller *threadedTest1 = new DestructionTest1Caller("", theTest); + threadedTest1->addThread(":Thread1", &DestructionTest1::TestThread1); + threadedTest1->addThread(":Thread2", &DestructionTest1::TestThread2); + + // Make a semaphore based test object, create a ThreadedTestCase for it and add + // three threads to it. + theTest = new DestructionTest1("Semaphore", false); + DestructionTest1Caller *threadedTest2 = new DestructionTest1Caller("", theTest); + threadedTest2->addThread(":Thread1", &DestructionTest1::TestThread1); + threadedTest2->addThread(":Thread2", &DestructionTest1::TestThread2); + + testSuite->addTest(threadedTest1); + testSuite->addTest(threadedTest2); + return(testSuite); + } + +template class DestructionTest1; +template class DestructionTest1; \ No newline at end of file diff --git a/src/tests/kits/support/blocker/DestructionTest1.h b/src/tests/kits/support/blocker/DestructionTest1.h new file mode 100644 index 0000000000..5a853e7746 --- /dev/null +++ b/src/tests/kits/support/blocker/DestructionTest1.h @@ -0,0 +1,34 @@ +/* + $Id: DestructionTest1.h,v 1.1 2002/07/09 12:24:58 ejakowatz Exp $ + + This file defines a class for performing one test of BLocker + functionality. + + */ + + +#ifndef DestructionTest1_H +#define DestructionTest1_H + + +#include "LockerTestCase.h" +#include "ThreadedTestCaller.h" + + +template class DestructionTest1 : public LockerTestCase { + +private: + typedef ThreadedTestCaller > + DestructionTest1Caller; + +protected: + +public: + void TestThread1(void); + void TestThread2(void); + DestructionTest1(std::string name, bool isBenaphore); + virtual ~DestructionTest1(); + static Test *suite(void); + }; + +#endif \ No newline at end of file diff --git a/src/tests/kits/support/blocker/DestructionTest2.cpp b/src/tests/kits/support/blocker/DestructionTest2.cpp new file mode 100644 index 0000000000..735c205d14 --- /dev/null +++ b/src/tests/kits/support/blocker/DestructionTest2.cpp @@ -0,0 +1,135 @@ +/* + $Id: DestructionTest2.cpp,v 1.1 2002/07/09 12:24:58 ejakowatz Exp $ + + This file implements a test class for testing BLocker functionality. + It tests use cases "Destruction" and "Locking 4". + + The test works like the following: + - the main thread acquires the lock + - it creates a new thread and sleeps + - the new thread attempts to acquire the lock but times out + - the new thread then attempts to acquire the lock again + - before the new thread times out a second time, the first thread releases + the lock + - at this time, the new thread acquires the lock and goes to sleep + - the first thread attempts to acquire the lock + - the second thread deletes the lock + - the first thread is woken up indicating that the lock wasn't acquired. + + */ + + +#include "DestructionTest2.h" +#include "TestSuite.h" +#include "ThreadedTestCaller.h" +#include +#include "Locker.h" + +// This constant is used to determine the number of microseconds to +// sleep during major steps of the test. + +const bigtime_t SNOOZE_TIME = 200000; + + +/* + * Method: DestructionTest2::DestructionTest2() + * Descr: This is the only constructor for this test class. + */ + +template + DestructionTest2::DestructionTest2(std::string name, + bool isBenaphore) : + LockerTestCase(name, isBenaphore) +{ + } + + +/* + * Method: DestructionTest2::~DestructionTest2() + * Descr: This is the only destructor for this test class. + */ + +template + DestructionTest2::~DestructionTest2() +{ + } + + +/* + * Method: DestructionTest2::TestThread1() + * Descr: This method immediately acquires the lock, sleeps + * for SNOOZE_TIME and then releases the lock. It sleeps + * again for SNOOZE_TIME and then tries to re-acquire the + * lock. By this time, the other thread should have + * deleted the lock. This acquisition should fail. + */ + +template void DestructionTest2::TestThread1(void) +{ + assert(theLocker->LockWithTimeout(SNOOZE_TIME) == B_OK); + snooze(SNOOZE_TIME); + theLocker->Unlock(); + snooze(SNOOZE_TIME); + assert(theLocker->LockWithTimeout(SNOOZE_TIME * 10) == B_BAD_SEM_ID); + } + + +/* + * Method: DestructionTest2::TestThread2() + * Descr: This method sleeps for SNOOZE_TIME/10 and then attempts to acquire + * the lock for SNOOZE_TIME/10 seconds. This acquisition will timeout + * because the other thread is holding the lock. Then it acquires the + * lock by using a larger timeout. It sleeps again for 2*SNOOZE_TIME and + * then deletes the lock. This should wake up the other thread. + */ + +template void DestructionTest2::TestThread2(void) +{ + Locker *tmpLock; + + snooze(SNOOZE_TIME/10); + assert(theLocker->LockWithTimeout(SNOOZE_TIME / 10) == B_TIMED_OUT); + assert(theLocker->LockWithTimeout(SNOOZE_TIME * 10) == B_OK); + snooze(SNOOZE_TIME); + snooze(SNOOZE_TIME); + tmpLock = theLocker; + theLocker = NULL; + delete tmpLock; +} + + +/* + * Method: DestructionTest2::suite() + * Descr: This static member function returns a test suite for performing + * all combinations of "DestructionTest2". The test suite contains + * two instances of the test. One is performed on a benaphore, + * the other on a semaphore based BLocker. Each individual test + * is created as a ThreadedTestCase (typedef'd as + * DestructionTest2Caller) with two independent threads. + */ + +template Test *DestructionTest2::suite(void) +{ + TestSuite *testSuite = new TestSuite("DestructionTest2"); + + // Make a benaphore based test object, create a ThreadedTestCase for it and add + // two threads to it. + DestructionTest2 *theTest = new DestructionTest2("Benaphore", true); + DestructionTest2Caller *threadedTest1 = new DestructionTest2Caller("", theTest); + threadedTest1->addThread(":Thread1", &DestructionTest2::TestThread1); + threadedTest1->addThread(":Thread2", &DestructionTest2::TestThread2); + + // Make a semaphore based test object, create a ThreadedTestCase for it and add + // three threads to it. + theTest = new DestructionTest2("Semaphore", false); + DestructionTest2Caller *threadedTest2 = new DestructionTest2Caller("", theTest); + threadedTest2->addThread(":Thread1", &DestructionTest2::TestThread1); + threadedTest2->addThread(":Thread2", &DestructionTest2::TestThread2); + + testSuite->addTest(threadedTest1); + testSuite->addTest(threadedTest2); + return(testSuite); + } + +template class DestructionTest2; +template class DestructionTest2; \ No newline at end of file diff --git a/src/tests/kits/support/blocker/DestructionTest2.h b/src/tests/kits/support/blocker/DestructionTest2.h new file mode 100644 index 0000000000..216b26d8fd --- /dev/null +++ b/src/tests/kits/support/blocker/DestructionTest2.h @@ -0,0 +1,34 @@ +/* + $Id: DestructionTest2.h,v 1.1 2002/07/09 12:24:58 ejakowatz Exp $ + + This file defines a class for performing one test of BLocker + functionality. + + */ + + +#ifndef DestructionTest2_H +#define DestructionTest2_H + + +#include "LockerTestCase.h" +#include "ThreadedTestCaller.h" + + +template class DestructionTest2 : public LockerTestCase { + +private: + typedef ThreadedTestCaller > + DestructionTest2Caller; + +protected: + +public: + void TestThread1(void); + void TestThread2(void); + DestructionTest2(std::string name, bool isBenaphore); + virtual ~DestructionTest2(); + static Test *suite(void); + }; + +#endif \ No newline at end of file diff --git a/src/tests/kits/support/blocker/LockerTestAddon.cpp b/src/tests/kits/support/blocker/LockerTestAddon.cpp new file mode 100644 index 0000000000..8586b2238d --- /dev/null +++ b/src/tests/kits/support/blocker/LockerTestAddon.cpp @@ -0,0 +1,55 @@ +/* + $Id: LockerTestAddon.cpp,v 1.1 2002/07/09 12:24:58 ejakowatz Exp $ + + This file declares the addonTestName string and addonTestFunc + function for the BLocker tests. These symbols will be used + when the addon is loaded. + + */ + + +#include "ConstructionTest1.h" +#include "ConcurrencyTest1.h" +#include "ConcurrencyTest2.h" +#include "DestructionTest1.h" +#include "DestructionTest2.h" +#include "BenaphoreLockCountTest1.h" +#include "SemaphoreLockCountTest1.h" +#include +#include "Locker.h" +#include "TestAddon.h" +#include "TestSuite.h" + + +/* + * Function: addonTestFunc() + * Descr: This function is called by the test application to + * get a pointer to the test to run. The BLocker test + * is a test suite. A series of tests are added to + * the suite. Each test appears twice, once for + * the Be implementation of BLocker, once for the + * OpenBeOS implementation. + */ + +Test *addonTestFunc(void) +{ + TestSuite *testSuite = new TestSuite("Blocker"); + + testSuite->addTest(ConstructionTest1::suite()); + testSuite->addTest(ConcurrencyTest1::suite()); + testSuite->addTest(ConcurrencyTest2::suite()); + testSuite->addTest(DestructionTest1::suite()); + testSuite->addTest(DestructionTest2::suite()); + testSuite->addTest(BenaphoreLockCountTest1::suite()); + testSuite->addTest(SemaphoreLockCountTest1::suite()); + + testSuite->addTest(ConstructionTest1::suite()); + testSuite->addTest(ConcurrencyTest1::suite()); + testSuite->addTest(ConcurrencyTest2::suite()); + testSuite->addTest(DestructionTest1::suite()); + testSuite->addTest(DestructionTest2::suite()); + testSuite->addTest(BenaphoreLockCountTest1::suite()); + testSuite->addTest(SemaphoreLockCountTest1::suite()); + + return(testSuite); +} diff --git a/src/tests/kits/support/blocker/LockerTestCase.cpp b/src/tests/kits/support/blocker/LockerTestCase.cpp new file mode 100644 index 0000000000..061a43de44 --- /dev/null +++ b/src/tests/kits/support/blocker/LockerTestCase.cpp @@ -0,0 +1,75 @@ +/* + $Id: LockerTestCase.cpp,v 1.1 2002/07/09 12:24:58 ejakowatz Exp $ + + This file implements a base class for testing BLocker functionality. + + */ + + +#include "LockerTestCase.h" +#include +#include "Locker.h" + + +/* + * Method: LockerTestCase::LockerTestCase() + * Descr: This method is the only constructore for the LockerTestCase + * class. It takes a test name and a flag to indicate whether + * the locker should be a benaphore or a semaphore. + */ + +template + LockerTestCase::LockerTestCase(std::string name, bool isBenaphore) : + TestCase(name), theLocker(new Locker(isBenaphore)) +{ + } + + +/* + * Method: LockerTestCase::~LockerTestCase() + * Descr: This method is the destructor for the LockerTestCase class. + * It only deallocates the locker allocated in the constructor. + */ + +template + LockerTestCase::~LockerTestCase() +{ + delete theLocker; + theLocker = NULL; + } + + +/* + * Method: LockerTestCase::CheckLock() + * Descr: This method confirms that the lock is currently in a sane + * state. If the lock is not sane, then an assertion is + * raised. The caller provides the number of times the + * thread has successfully acquired the lock. If the caller + * indicates that the lock has been acquired one or more times + * by the current thread, then the function confirms that. If + * the caller indicates the lock has not been acquired + * (expectedCount = 0), then it checks to make sure that the + * lock is not held by the current thread. If it is, it + * raises an assertion. + */ + +template void LockerTestCase::CheckLock(int expectedCount) +{ + bool isLocked = theLocker->IsLocked(); + thread_id actualThread = theLocker->LockingThread(); + thread_id expectedThread = find_thread(NULL); + int32 actualCount = theLocker->CountLocks(); + + if (expectedCount > 0) { + assert(isLocked); + assert(expectedThread == actualThread); + assert(expectedCount == actualCount); + } else { + assert(!((isLocked) && (actualThread == expectedThread))); + } + return; +} + + +template class LockerTestCase; +template class LockerTestCase; \ No newline at end of file diff --git a/src/tests/kits/support/blocker/LockerTestCase.h b/src/tests/kits/support/blocker/LockerTestCase.h new file mode 100644 index 0000000000..099cd7cbd0 --- /dev/null +++ b/src/tests/kits/support/blocker/LockerTestCase.h @@ -0,0 +1,60 @@ +/* + $Id: LockerTestCase.h,v 1.1 2002/07/09 12:24:58 ejakowatz Exp $ + + This file defines a couple of common classes for testing BLocker + functionality. + + */ + + +#ifndef LockerTestCase_H +#define LockerTestCase_H + + +#include "TestCase.h" + +// +// The SafetyLock class is a utility class for use in actual tests +// of the BLocker interfaces. It is used to make sure that if the +// test fails and an exception is thrown with the lock held, that +// lock will be released. Without this SafetyLock, there could be +// deadlocks if one thread in a test has a failure while holding the +// lock. It should be used like so: +// +// template void myTestClass::myTestFunc(void) +// { +// SafetyLock mySafetyLock(theLocker); +// ...perform tests without worrying about holding the lock on assert... +// + +template class SafetyLock { +private: + Locker *theLocker; + +public: + SafetyLock(Locker *aLock) {theLocker = aLock;} + virtual ~SafetyLock() {if (theLocker != NULL) theLocker->Unlock(); }; + }; + + +// +// All BLocker tests should be derived from the LockerTestCase class. +// This class provides a BLocker allocated on construction to the +// derived class. This BLocker is the member "theLocker". Also, +// there is a member function called CheckLock() which ensures that +// the lock is sane. +// + +template class LockerTestCase : public TestCase { + +protected: + Locker *theLocker; + + void CheckLock(int); + +public: + LockerTestCase(std::string name, bool); + virtual ~LockerTestCase(); + }; + +#endif \ No newline at end of file diff --git a/src/tests/kits/support/blocker/SemaphoreLockCountTest1.cpp b/src/tests/kits/support/blocker/SemaphoreLockCountTest1.cpp new file mode 100644 index 0000000000..96c1a2b6f6 --- /dev/null +++ b/src/tests/kits/support/blocker/SemaphoreLockCountTest1.cpp @@ -0,0 +1,186 @@ +/* + $Id: SemaphoreLockCountTest1.cpp,v 1.1 2002/07/09 12:24:58 ejakowatz Exp $ + + This file implements a test class for testing BLocker functionality. + It tests use cases "Count Lock Requests" for a semaphore style BLocker. + + The test works by: + - checking the lock requests + - acquiring the lock + - checking the lock requests + - staring a thread which times out acquiring the lock and then blocks + again waiting for the lock + - checking the lock requests + - start a second thread which times out acquiring the lock and then blocks + again waiting for the lock + - checking the lock requests + - release the lock + - each blocked thread acquires the lock, checks the lock requests and releases + the lock before terminating + - the main thread checks the lock requests one last time + + */ + + +#include "SemaphoreLockCountTest1.h" +#include "TestSuite.h" +#include "ThreadedTestCaller.h" +#include +#include "Locker.h" + + +// This constant is used to determine the number of microseconds to +// sleep during major steps of the test. + +const bigtime_t SNOOZE_TIME = 100000; + + +/* + * Method: SemaphoreLockCountTest1::SemaphoreLockCountTest1() + * Descr: This is the constructor for this test class. + */ + +template + SemaphoreLockCountTest1::SemaphoreLockCountTest1(std::string name) : + LockerTestCase(name, false) +{ + } + + +/* + * Method: SemaphoreLockCountTest1::~SemaphoreLockCountTest1() + * Descr: This is the destructor for this test class. + */ + +template + SemaphoreLockCountTest1::~SemaphoreLockCountTest1() +{ + } + + +/* + * Method: SemaphoreLockCountTest1::CheckLockRequests() + * Descr: This member function checks the actual number of lock requests + * that the BLocker thinks are outstanding versus the number + * passed in. If they match, true is returned. + */ + +template bool SemaphoreLockCountTest1::CheckLockRequests(int expected) +{ + int actual = theLocker->CountLockRequests(); + return(actual == expected); +} + + +/* + * Method: SemaphoreLockCountTest1::TestThread1() + * Descr: This member function performs the main portion of the test. + * It first acquires thread2Lock and thread3Lock. This ensures + * that thread2 and thread3 will block until this thread wants + * them to start running. It then checks the lock count, acquires + * the lock and checks the lock count again. It unlocks each + * of the other two threads in turn and rechecks the lock count. + * Finally, it releases the lock and sleeps for a short while + * for the other two threads to finish. At the end, it checks + * the lock count on final time. + */ + +template void SemaphoreLockCountTest1::TestThread1(void) +{ + SafetyLock theSafetyLock1(theLocker); + SafetyLock theSafetyLock2(&thread2Lock); + SafetyLock theSafetyLock3(&thread3Lock); + + assert(thread2Lock.Lock()); + assert(thread3Lock.Lock()); + + assert(CheckLockRequests(1)); + assert(theLocker->Lock()); + + assert(CheckLockRequests(2)); + + thread2Lock.Unlock(); + snooze(SNOOZE_TIME); + assert(CheckLockRequests(4)); + + thread3Lock.Unlock(); + snooze(SNOOZE_TIME); + assert(CheckLockRequests(6)); + + theLocker->Unlock(); + snooze(SNOOZE_TIME); + assert(CheckLockRequests(3)); + } + + +/* + * Method: SemaphoreLockCountTest1::TestThread2() + * Descr: This member function defines the actions of the second thread of + * the test. First it sleeps for a short while and then blocks on + * the thread2Lock. When the first thread releases it, this thread + * begins its testing. It times out attempting to acquire the main + * lock and then blocks to acquire the lock. Once that lock is + * acquired, the lock count is checked before finishing this thread. + */ + +template void SemaphoreLockCountTest1::TestThread2(void) +{ + SafetyLock theSafetyLock1(theLocker); + + snooze(SNOOZE_TIME / 10); + assert(thread2Lock.Lock()); + + assert(theLocker->LockWithTimeout(SNOOZE_TIME / 10) == B_TIMED_OUT); + assert(theLocker->Lock()); + int actual = theLocker->CountLockRequests(); + assert((actual == 4) || (actual == 5)); + theLocker->Unlock(); +} + + +/* + * Method: SemaphoreLockCountTest1::TestThread3() + * Descr: This member function defines the actions of the second thread of + * the test. First it sleeps for a short while and then blocks on + * the thread3Lock. When the first thread releases it, this thread + * begins its testing. It times out attempting to acquire the main + * lock and then blocks to acquire the lock. Once that lock is + * acquired, the lock count is checked before finishing this thread. + */ + +template void SemaphoreLockCountTest1::TestThread3(void) +{ + SafetyLock theSafetyLock1(theLocker); + + snooze(SNOOZE_TIME / 10); + assert(thread3Lock.Lock()); + + assert(theLocker->LockWithTimeout(SNOOZE_TIME / 10) == B_TIMED_OUT); + assert(theLocker->Lock()); + int actual = theLocker->CountLockRequests(); + assert((actual == 4) || (actual == 5)); + theLocker->Unlock(); +} + + +/* + * Method: SemaphoreLockCountTest1::suite() + * Descr: This static member function returns a test caller for performing + * the "SemaphoreLockCountTest1" test. The test caller + * is created as a ThreadedTestCaller (typedef'd as + * SemaphoreLockCountTest1Caller) with three independent threads. + */ + +template Test *SemaphoreLockCountTest1::suite(void) +{ + SemaphoreLockCountTest1 *theTest = new SemaphoreLockCountTest1(""); + SemaphoreLockCountTest1Caller *threadedTest = new SemaphoreLockCountTest1Caller("", theTest); + threadedTest->addThread(":Thread1", &SemaphoreLockCountTest1::TestThread1); + threadedTest->addThread(":Thread2", &SemaphoreLockCountTest1::TestThread2); + threadedTest->addThread(":Thread3", &SemaphoreLockCountTest1::TestThread3); + return(threadedTest); + } + + +template class SemaphoreLockCountTest1; +template class SemaphoreLockCountTest1; \ No newline at end of file diff --git a/src/tests/kits/support/blocker/SemaphoreLockCountTest1.h b/src/tests/kits/support/blocker/SemaphoreLockCountTest1.h new file mode 100644 index 0000000000..185bede99a --- /dev/null +++ b/src/tests/kits/support/blocker/SemaphoreLockCountTest1.h @@ -0,0 +1,41 @@ +/* + $Id: SemaphoreLockCountTest1.h,v 1.1 2002/07/09 12:24:58 ejakowatz Exp $ + + This file defines a classes for performing one test of BLocker + functionality. + + */ + + +#ifndef SemaphoreLockCountTest1_H +#define SemaphoreLockCountTest1_H + + +#include "LockerTestCase.h" +#include "ThreadedTestCaller.h" + + +template class SemaphoreLockCountTest1 : + public LockerTestCase { + +private: + typedef ThreadedTestCaller > + SemaphoreLockCountTest1Caller; + + Locker thread2Lock; + Locker thread3Lock; + + bool CheckLockRequests(int); + +protected: + +public: + void TestThread1(void); + void TestThread2(void); + void TestThread3(void); + SemaphoreLockCountTest1(std::string); + virtual ~SemaphoreLockCountTest1(); + static Test *suite(void); + }; + +#endif \ No newline at end of file diff --git a/src/tests/kits/translation/BitmapStreamTest.cpp b/src/tests/kits/translation/BitmapStreamTest.cpp new file mode 100644 index 0000000000..0622ece42f --- /dev/null +++ b/src/tests/kits/translation/BitmapStreamTest.cpp @@ -0,0 +1,231 @@ +/*****************************************************************************/ +// OpenBeOS Translation Kit Test +// Author: Brian Matzon +// Version: 0.1.0 +// +// This is the Test application for BBitmapStream +// +// +// This application and all source files used in its construction, except +// where noted, are licensed under the MIT License, and have been written +// and are: +// +// Copyright (c) 2002 OpenBeOS Project +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ +#include "BitmapStreamTest.h" +#include +#include +#include + +/** + * Default constructor - no work + */ +BitmapStreamTest::BitmapStreamTest() { +} + +/** + * Default destructor - no work + */ +BitmapStreamTest::~BitmapStreamTest() { +} + +/** + * Initializes the test + * + * @return B_OK if initialization went ok, B_ERROR if not + */ +status_t BitmapStreamTest::Initialize() { + //aquire default roster + roster = BTranslatorRoster::Default(); + if(roster == NULL) { + Debug("Failed to create aquire default TranslatorRoster\n"); + return B_ERROR; + } + + //print version information + if(verbose && roster != NULL) { + int32 outCurVersion; + int32 outMinVersion; + long inAppVersion; + const char* info = roster->Version(&outCurVersion, &outMinVersion, inAppVersion); + printf("Default TranslatorRoster aquired. Version: %s\n", info); + } + + return B_OK; +} + +/** + * Initializes the tests. + * This will test ALL methods in BTranslatorRoster. + * + * @return B_OK if the whole test went ok, B_ERROR if not + */ +status_t BitmapStreamTest::Perform() { + if(ConstructorTest() != B_OK) { + Debug("ERROR: ConstructorTest did not complete successfully\n"); + return B_ERROR; + } + if(DetachBitmap() != B_OK) { + Debug("ERROR: DetachBitmap did not complete successfully\n"); + return B_ERROR; + } + if(Position() != B_OK) { + Debug("ERROR: Position did not complete successfully\n"); + return B_ERROR; + } + if(ReadAt() != B_OK) { + Debug("ERROR: ReadAt did not complete successfully\n"); + return B_ERROR; + } + if(Seek() != B_OK) { + Debug("ERROR: Seek did not complete successfully\n"); + return B_ERROR; + } + if(SetSize() != B_OK) { + Debug("ERROR: SetSize did not complete successfully\n"); + return B_ERROR; + } + if(WriteAt() != B_OK) { + Debug("ERROR: WriteAt did not complete successfully\n"); + return B_ERROR; + } + if(Size() != B_OK) { + Debug("ERROR: Size did not complete successfully\n"); + return B_ERROR; + } + + return B_OK; +} +/** + * Tests: + * BBitmapStream(BBitmap *map = NULL) + * + * @return B_OK if everything went ok, B_ERROR if not + */ +status_t BitmapStreamTest::ConstructorTest() { + return B_OK; +} + +/** + * Tests: + * status_t DetachBitmap(BBitmap **outMap) + * + * @return B_OK if everything went ok, B_ERROR if not + */ +status_t BitmapStreamTest::DetachBitmap() { + BFile file("./data/images/image.gif", B_READ_ONLY); + if(file.InitCheck() != B_OK) { + return B_ERROR; + } + + BBitmapStream stream; + BBitmap* result = NULL; + if (roster->Translate(&file, NULL, NULL, &stream, B_TRANSLATOR_BITMAP) < B_OK) { + return B_ERROR; + } + stream.DetachBitmap(&result); + + if(result != NULL) { + return B_OK; + } + + return B_ERROR; +} + +/** + * Tests: + * off_t Position() const + * + * @return B_OK if everything went ok, B_ERROR if not + */ +status_t BitmapStreamTest::Position() { + return B_OK; +} + +/** + * Tests: + * ssize_t ReadAt(off_t pos, void *buffer, size_t *size) + * + * @return B_OK if everything went ok, B_ERROR if not + */ +status_t BitmapStreamTest::ReadAt() { + return B_OK; +} + +/** + * Tests: + * off_t Seek(off_t position, uint32 whence) + * + * @return B_OK if everything went ok, B_ERROR if not + */ +status_t BitmapStreamTest::Seek() { + return B_OK; +} + +/** + * Tests: + * status_t SetSize(off_t size) const + * + * @return B_OK if everything went ok, B_ERROR if not + */ +status_t BitmapStreamTest::SetSize() { + return B_OK; +} + +/** + * Tests: + * ssize_t WriteAt(off_t pos, const void *data, size_t *size) + * + * @return B_OK if everything went ok, B_ERROR if not + */ +status_t BitmapStreamTest::WriteAt() { + return B_OK; +} + +/** + * Tests: + * off_t Size() const + * + * @return B_OK if everything went ok, B_ERROR if not + */ +status_t BitmapStreamTest::Size() { + return B_OK; +} +/** + * Prints debug information to stdout, if verbose is set to true + */ +void BitmapStreamTest::Debug(char* string) { + if(verbose) { + printf(string); + } +} + +int main() { + BApplication app("application/x-vnd.OpenBeOS-translationkit_bitmapstreamtest"); + BitmapStreamTest test; + test.setVerbose(true); + test.Initialize(); + if(test.Perform() != B_OK) { + printf("Tests did not complete successfully\n"); + } else { + printf("All tests completed without errors\n"); + } +} \ No newline at end of file diff --git a/src/tests/kits/translation/BitmapStreamTest.h b/src/tests/kits/translation/BitmapStreamTest.h new file mode 100644 index 0000000000..04b1c2d863 --- /dev/null +++ b/src/tests/kits/translation/BitmapStreamTest.h @@ -0,0 +1,69 @@ +/*****************************************************************************/ +// OpenBeOS Translation Kit Test +// +// Version: 0.1.0 +// Author: Brian Matzon +// This is the Test application for BBitmapStream +// +// +// This application and all source files used in its construction, except +// where noted, are licensed under the MIT License, and have been written +// and are: +// +// Copyright (c) 2002 OpenBeOS Project +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ +#ifndef __BITMAP_STEAM_TEST +#define __BITMAP_STEAM_TEST + +#include +#include + +class BitmapStreamTest { +public: + BitmapStreamTest(); + ~BitmapStreamTest(); + + status_t Initialize(); + status_t Perform(); + inline void setVerbose(bool verbose) { this->verbose = verbose; }; + + //actual tests + status_t ConstructorTest(); + status_t DetachBitmap(); + status_t Position(); + status_t ReadAt(); + status_t Seek(); + status_t SetSize(); + status_t WriteAt(); + status_t Size(); +private: + void Debug(char* string); + + /** default roster used when performing tests */ + BTranslatorRoster* roster; + + /** File to read from */ + BFile* file; + + /** Whether or not to output test info */ + bool verbose; +}; +#endif \ No newline at end of file diff --git a/src/tests/kits/translation/TranslatorRosterTest.cpp b/src/tests/kits/translation/TranslatorRosterTest.cpp new file mode 100644 index 0000000000..916753767b --- /dev/null +++ b/src/tests/kits/translation/TranslatorRosterTest.cpp @@ -0,0 +1,624 @@ +/*****************************************************************************/ +// OpenBeOS Translation Kit Test +// Author: Brian Matzon +// Version: 0.1.0 +// +// This is the Test application for BTranslatorRoster +// +// +// This application and all source files used in its construction, except +// where noted, are licensed under the MIT License, and have been written +// and are: +// +// Copyright (c) 2002 OpenBeOS Project +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ +#include "TranslatorRosterTest.h" +#include +#include +#include +#include +#include + +/** + * Default constructor - no work + */ +TranslatorRosterTest::TranslatorRosterTest() { +} + +/** + * Default destructor - no work + */ +TranslatorRosterTest::~TranslatorRosterTest() { +} + +/** + * Initializes the test + * + * @return B_OK if initialization went ok, B_ERROR if not + */ +status_t TranslatorRosterTest::Initialize() { + //aquire default roster + roster = BTranslatorRoster::Default(); + if(roster == NULL) { + Debug("Failed to create aquire default TranslatorRoster\n"); + return B_ERROR; + } + + //print version information + if(verbose && roster != NULL) { + int32 outCurVersion; + int32 outMinVersion; + long inAppVersion; + const char* info = roster->Version(&outCurVersion, &outMinVersion, inAppVersion); + printf("Default TranslatorRoster aquired. Version: %s\n", info); + } + + return B_OK; +} + +/** + * Initializes the tests. + * This will test ALL methods in BTranslatorRoster. + * + * @return B_OK if the whole test went ok, B_ERROR if not + */ +status_t TranslatorRosterTest::Perform() { + if(ConstructorTest() != B_OK) { + Debug("ERROR: ConstructorTest did not complete successfully\n"); + return B_ERROR; + } + if(DefaultTest() != B_OK) { + Debug("ERROR: DefaultTest did not complete successfully\n"); + return B_ERROR; + } + if(InstantiateTest() != B_OK) { + Debug("ERROR: InstantiateTest did not complete successfully\n"); + return B_ERROR; + } + if(VersionTest() != B_OK) { + Debug("ERROR: VersionTest did not complete successfully\n"); + return B_ERROR; + } + if(AddTranslatorsTest() != B_OK) { + Debug("ERROR: AddTranslatorsTest did not complete successfully\n"); + return B_ERROR; + } + if(ArchiveTest() != B_OK) { + Debug("ERROR: ArchiveTest did not complete successfully\n"); + return B_ERROR; + } + if(GetAllTranslatorsTest() != B_OK) { + Debug("ERROR: GetAllTranslatorsTest did not complete successfully\n"); + return B_ERROR; + } + if(GetConfigurationMessageTest() != B_OK) { + Debug("ERROR: GetConfigurationMessageTest did not complete successfully\n"); + return B_ERROR; + } + if(GetInputFormatsTest() != B_OK) { + Debug("ERROR: GetInputFormatsTest did not complete successfully\n"); + return B_ERROR; + } + if(GetOutputFormatsTest() != B_OK) { + Debug("ERROR: GetOutputFormatsTest did not complete successfully\n"); + return B_ERROR; + } + if(GetTranslatorInfoTest() != B_OK) { + Debug("ERROR: GetTranslatorInfoTest did not complete successfully\n"); + return B_ERROR; + } + if(GetTranslatorsTest() != B_OK) { + Debug("ERROR: GetTranslatorsTest did not complete successfully\n"); + return B_ERROR; + } + if(IdentifyTest() != B_OK) { + Debug("ERROR: IdentifyTest did not complete successfully\n"); + return B_ERROR; + } + if(MakeConfigurationViewTest() != B_OK) { + Debug("ERROR: MakeConfigurationViewTest did not complete successfully\n"); + return B_ERROR; + } + if(TranslateTest() != B_OK) { + Debug("ERROR: TranslateTest did not complete successfully\n"); + return B_ERROR; + } + + return B_OK; +} +/** + * Tests: + * BTranslatorRoster() + * BTranslatorRoster(BMessage *model) + * + * @return B_OK if everything went ok, B_ERROR if not + */ +status_t TranslatorRosterTest::ConstructorTest() { + //shared instance of TranslatorRoster + BTranslatorRoster* translator_roster; + + //Create TranslatorRoster using noargs constructor + translator_roster = new BTranslatorRoster(); + if(translator_roster == NULL) { + Debug("Could not create noargs BTranalatorRoster"); + return B_ERROR; + } + delete translator_roster; + + //Create TranslatorRoster using BMessage constructor + BMessage translator_message; + translator_message.AddString("be:translator_path", "/boot/home/config/add-ons/Translators"); + translator_roster = new BTranslatorRoster(&translator_message); + if(translator_roster == NULL) { + Debug("Could not create BMessage BTranalatorRoster"); + return B_ERROR; + } + delete translator_roster; + + return B_OK; +} + +/** + * Tests: + * BTranslatorRoster *Default() + * + * @return B_OK if everything went ok, B_ERROR if not + */ +status_t TranslatorRosterTest::DefaultTest() { + //already done in Initialize - added for completeness sake + BTranslatorRoster* translator_roster = BTranslatorRoster::Default(); + if(translator_roster == NULL) { + Debug("Unable to aquire default TranslatorRoster"); + return B_ERROR; + } + return B_OK; +} + +/** + * Tests: + * BTranslatorRoster *Instantiate(BMessage *from) + * + * @return B_OK if everything went ok, B_ERROR if not + */ +status_t TranslatorRosterTest::InstantiateTest() { + //shared instance of TranslatorRoster + BTranslatorRoster* translator_roster = NULL; + + //Create our BMessage + BMessage translator_message; + + //create BTranslator using empty message (must return NULL) + translator_roster = (BTranslatorRoster*) BTranslatorRoster::Instantiate(&translator_message); + if(translator_roster != NULL) { + Debug("Expected NULL when instantiating roster from invalid BMessage\n"); + delete translator_roster; + return B_ERROR; + } + + //create roster from message + /*translator_message.AddString("be:translator_path", "/boot/home/config/add-ons/Translators/"); + translator_roster = (BTranslatorRoster*) BTranslatorRoster::Instantiate(&translator_message); + if(translator_roster == NULL) { + Debug("Could not instantiate BTranslatorRoster from archived default\n"); + printf("===== BMessage =====\n"); + translator_message.PrintToStream(); + printf("===== BMessage =====\n"); + return B_ERROR; + } + delete translator_roster; + */ + return B_OK; +} + +/** + * Tests: + * const char *Version(int32 *outCurVersion, int32 *outMinVersion, int32 *inAppVersion = B_TRANSLATION_CURRENT_VERSION) + * + * @return B_OK if everything went ok, B_ERROR if not + */ +status_t TranslatorRosterTest::VersionTest() { + int32 outCurVersion; + int32 outMinVersion; + long inAppVersion; + const char* info = roster->Version(&outCurVersion, &outMinVersion, inAppVersion); + if(info == NULL) { + Debug("Unable to obtain version information"); + return B_ERROR; + } + return B_OK; +} + +/** + * Tests: + * virtual status_t AddTranslators(const char *load_path = NULL) + * + * @return B_OK if everything went ok, B_ERROR if not + */ +status_t TranslatorRosterTest::AddTranslatorsTest() { + //create basic translatorroster + BTranslatorRoster* translator_roster = new BTranslatorRoster(); + + //load wrong path (generate parse error) + /* + if(translator_roster->AddTranslators("?") != B_BAD_VALUE) { + Debug("Expected B_BAD_VALUE when loading wrong path\n"); + return B_ERROR; + } + */ + + //load correct path + if(translator_roster->AddTranslators("/boot/home/config/add-ons/Translators/:/system/add-ons/Translators/") != B_OK) { + Debug("Expected B_OK when loading addons from correct path\n"); + return B_ERROR; + } + + int32 num_translators; + translator_id* translators; + translator_roster->GetAllTranslators(&translators, &num_translators); + if(num_translators <= 0) { + Debug("Unable to load translators, or no translators installed"); + return B_ERROR; + } + delete [] translators; + + //delete and create new, this time don't specify path + delete translator_roster; + translator_roster = new BTranslatorRoster(); + translator_roster->AddTranslators(); + translator_roster->GetAllTranslators(&translators, &num_translators); + if(num_translators <= 0) { + Debug("Unable to load translators, or no translators installed"); + return B_ERROR; + } + delete [] translators; + delete translator_roster; + + return B_OK; +} + +/** + * Tests: + * virtual status_t Archive(BMessage *into, bool deep = true) const + * + * @return B_OK if everything went ok, B_ERROR if not + */ +status_t TranslatorRosterTest::ArchiveTest() { + //archive default, and count entries (must be more than 1!) + BMessage translator_message; + roster->Archive(&translator_message); + uint32 type; + int32 count; + if(translator_message.GetInfo("be:translator_path", &type, &count)) { + Debug("Unable to retrieve archived information"); + return B_ERROR; + } + return B_OK; +} + +/** + * Tests: + * virtual status_t GetAllTranslators(translator_id **outList, int32 *outCount) + * + * @return B_OK if everything went ok, B_ERROR if not + */ +status_t TranslatorRosterTest::GetAllTranslatorsTest() { + int32 num_translators; + translator_id* translators; + roster->GetAllTranslators(&translators, &num_translators); + if(num_translators <= 0) { + Debug("Unable to load translators, or no translators installed"); + return B_ERROR; + } + delete [] translators; + + return B_OK; +} + +/** + * Tests: + * virtual status_t GetConfigurationMessage(translator_id forTranslator, BMessage *ioExtension) + * + * @return B_OK if everything went ok, B_ERROR if not + */ +status_t TranslatorRosterTest::GetConfigurationMessageTest() { + BMessage translator_message; + + //get id for a translator (just use the first one) + unsigned long translatorid; + int32 num_translators; + translator_id* translators; + roster->GetAllTranslators(&translators, &num_translators); + translatorid = translators[0]; + delete [] translators; + + //get conf for invalid translator + if(roster->GetConfigurationMessage(-1, &translator_message) != B_NO_TRANSLATOR) { + Debug("Expected B_ERROR when supplying wrong translator for GetConfigurationMessage\n"); + return B_ERROR; + } + + //get conf for invalid ioExtension (BMessage) + if(roster->GetConfigurationMessage(translatorid, NULL) != B_BAD_VALUE) { + Debug("Expected B_BAD_VALUE when supplying wrong ioExtension for GetConfigurationMessage\n"); + return B_ERROR; + } + + //get config for actual translator + if(roster->GetConfigurationMessage(translatorid, &translator_message) != B_OK) { + Debug("Could not get configuration for translator\n"); + return B_ERROR; + } + return B_OK; +} + +/** + * Tests: + * virtual status_t GetInputFormats(translator_id forTranslator, const translation_format **outFormats, int32 *outNumFormats) + * + * @return B_OK if everything went ok, B_ERROR if not + */ +status_t TranslatorRosterTest::GetInputFormatsTest() { + translator_id* translators; + int32 num_translators; + roster->GetAllTranslators(&translators, &num_translators); + if(num_translators <= 0) { + Debug("Unable to load translators, or no translators installed"); + return B_ERROR; + } + + for (int32 i=0;iGetInputFormats(translators[i], &fmts, &num_fmts); + //printf("Translator supports %ld input formats\n", num_fmts); + if(num_fmts <= 0) { + Debug("Found translator accepting 0 or less input formats"); + return B_ERROR; + } + } + delete [] translators; + return B_OK; +} + +/** + * Tests: + * virtual status_t GetOutputFormats(translator_id forTranslator, const translation_format **outFormats, int32 *outNumFormats) + * + * @return B_OK if everything went ok, B_ERROR if not + */ +status_t TranslatorRosterTest::GetOutputFormatsTest() { + translator_id* translators; + int32 num_translators; + roster->GetAllTranslators(&translators, &num_translators); + if(num_translators <= 0) { + Debug("Unable to load translators, or no translators installed"); + return B_ERROR; + } + + for (int32 i=0;iGetOutputFormats(translators[i], &fmts, &num_fmts); + //printf("Translator supports %ld output formats\n", num_fmts); + if(num_fmts <= 0) { + Debug("Found translator accepting 0 or less output formats"); + return B_ERROR; + } + + } + delete [] translators; + return B_OK; +} + +/** + * Tests: + * virtual status_t GetTranslatorInfo(translator_id forTranslator, const char **outName, const char **outInfo, int32 *outVersion) + * + * @return B_OK if everything went ok, B_ERROR if not + */ +status_t TranslatorRosterTest::GetTranslatorInfoTest() { + translator_id* translators; + int32 num_translators; + roster->GetAllTranslators(&translators, &num_translators); + for (int32 i=0;iGetTranslatorInfo(-1, &outName, &outInfo, &outVersion) != B_NO_TRANSLATOR) { + Debug("Expected B_NO_TRANSLATOR when supplying wrong id"); + return B_ERROR; + } + + if(roster->GetTranslatorInfo(translators[i], &outName, &outInfo, &outVersion) != B_OK) { + Debug("Unable to get Translator info"); + return B_ERROR; + } + //printf("Translator info:\nName: %s\nInfo: %s\nVersion: %ld\n", outName, outInfo, outVersion); + } + delete [] translators; + return B_OK; +} + +/** + * Tests: + * virtual status_t GetTranslators(BPositionIO *inSource, BMessage *ioExtension, translator_info **outInfo, int32 *outNumInfo, uint32 inHintType = 0, const char *inHintMIME = NULL, uint32 inWantType = 0) + * + * @return B_OK if everything went ok, B_ERROR if not + */ +status_t TranslatorRosterTest::GetTranslatorsTest() { + //open image to get a translator for + BFile image("./data/images/image.png", B_READ_ONLY); + BFile garbled("./data/garbled_data", B_READ_ONLY); + + translator_info* info; + int32 outCount; + + //get translator, specifying wrong args + if(roster->GetTranslators(&garbled, NULL, NULL, &outCount) != B_BAD_VALUE) { + Debug("Expected B_BAD_VALUE when getting translator using illegal arguments"); + return B_ERROR; + } + + //get translator, specifying wrong args + if(roster->GetTranslators(&garbled, NULL, &info, NULL) != B_BAD_VALUE) { + Debug("Expected B_BAD_VALUE when getting translator using illegal arguments"); + return B_ERROR; + } + + //get translator for garbled data + if(roster->GetTranslators(&garbled, NULL, &info, &outCount) != B_NO_TRANSLATOR) { + Debug("Expected B_NO_TRANSLATOR when getting translator for garbled data"); + return B_ERROR; + } + + //get translator for image + if(roster->GetTranslators(&image, NULL, &info, &outCount) != B_OK) { + Debug("Expected B_OK when getting translator for image"); + return B_ERROR; + } + + if(outCount <= 0) { + Debug("Unable to find translator for image data"); + return B_ERROR; + } + //else { + //iterate through all translators + //for(int32 i=0; itype, info->translator, info->group, info->quality, info->capability, info->name, info->MIME); + //} + //} + delete [] info; + + return B_OK; +} + +/** + * Tests: + * virtual status_t Identify(BPositionIO *inSource, BMessage *ioExtension, translator_info *outInfo, uint32 inHintType = 0, const char *inHintMIME = NULL, uint32 inWantType = 0) + * + * @return B_OK if everything went ok, B_ERROR if not + */ +status_t TranslatorRosterTest::IdentifyTest() { + //open image to get a translator for + BFile image("./data/images/image.png", B_READ_ONLY); + BFile garbled("./data/garbled_data", B_READ_ONLY); + + translator_info* info; + + //get translator, specifying wrong args + if(roster->Identify(&garbled, NULL, NULL) != B_BAD_VALUE) { + Debug("Expected B_BAD_VALUE when getting translator using illegal arguments"); + return B_ERROR; + } + + //get translator for garbled data + if(roster->Identify(&garbled, NULL, info) != B_NO_TRANSLATOR) { + Debug("Expected B_NO_TRANSLATOR when getting translator for garbled data"); + return B_ERROR; + } + + //get translator for image + if(roster->Identify(&image, NULL, info) != B_OK) { + Debug("Expected B_OK when getting translator for image"); + return B_ERROR; + } + return B_OK; +} + +/** + * Tests: + * virtual status_t MakeConfigurationView(translator_id forTranslator, BMessage *ioExtension, BView **outView, BRect *outExtent) + * + * @return B_OK if everything went ok, B_ERROR if not + */ +status_t TranslatorRosterTest::MakeConfigurationViewTest() { + //create invalid rect - if it is valid after the + //MakeConfigurationView call the test has succeded + BRect extent(-1, -1, -1, -1); + + //create config view + BView* view; + translator_id* translators; + int32 num_translators; + roster->GetAllTranslators(&translators, &num_translators); + roster->MakeConfigurationView(translators[0], NULL, &view, &extent); + + //check validity + bool success = (extent.IsValid()) ? B_OK : B_ERROR; + + //clean up after ourselves + delete [] translators; + + return success; +} + +/** + * Tests: + * virtual status_t Translate(BPositionIO *inSource, const translator_info *inInfo, BMessage *ioExtension, BPositionIO *outDestination, uint32 inWantOutType, uint32 inHintType = 0, const char *inHintMIME = NULL) + * virtual status_t Translate(translator_id inTranslator, BPositionIO *inSource, BMessage *ioExtension, BPositionIO *outDestination, uint32 inWantOutType) + * + * @return B_OK if everything went ok, B_ERROR if not + */ +status_t TranslatorRosterTest::TranslateTest() { + //input + BFile input("./data/images/image.jpg", B_READ_ONLY); + + //temp file for generic format + BFile temp("/tmp/TranslatorRosterTest.temp", B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); + + //output file + BFile output("./data/images/image.out.png", B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); + + //translate to generic + if(roster->Translate(&input, NULL, NULL, &temp, B_TRANSLATOR_BITMAP) != B_OK) { + Debug("Could not translate image to generic format"); + return B_ERROR; + } + + //translate to specific + if(roster->Translate(&temp, NULL, NULL, &output, B_PNG_FORMAT) != B_OK) { + Debug("Could not translate generic image to specific format"); + return B_ERROR; + } + return B_OK; +} + +/** + * Prints debug information to stdout, if verbose is set to true + */ +void TranslatorRosterTest::Debug(char* string) { + if(verbose) { + printf(string); + } +} + +int main() { + //needed by MakeConfigurationView + BApplication app("application/x-vnd.OpenBeOS-translationkit_translatorrostertest"); + TranslatorRosterTest test; + test.setVerbose(true); + test.Initialize(); + if(test.Perform() != B_OK) { + printf("Tests did not complete successfully\n"); + } else { + printf("All tests completed without errors\n"); + } +} \ No newline at end of file diff --git a/src/tests/kits/translation/TranslatorRosterTest.h b/src/tests/kits/translation/TranslatorRosterTest.h new file mode 100644 index 0000000000..d577b6b639 --- /dev/null +++ b/src/tests/kits/translation/TranslatorRosterTest.h @@ -0,0 +1,72 @@ +/*****************************************************************************/ +// OpenBeOS Translation Kit Test +// +// Version: 0.1.0 +// +// This is the Test application for BTranslatorRoster +// +// +// This application and all source files used in its construction, except +// where noted, are licensed under the MIT License, and have been written +// and are: +// +// Copyright (c) 2002 OpenBeOS Project +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ +#ifndef __TRANSLATOR_ROSTER_TEST +#define __TRANSLATOR_ROSTER_TEST + +#include + +class TranslatorRosterTest { +public: + TranslatorRosterTest(); + ~TranslatorRosterTest(); + + status_t Initialize(); + status_t Perform(); + inline void setVerbose(bool verbose) { this->verbose = verbose; }; + + //actual tests + status_t ConstructorTest(); + status_t DefaultTest(); + status_t InstantiateTest(); + status_t VersionTest(); + status_t AddTranslatorsTest(); + status_t ArchiveTest(); + status_t GetAllTranslatorsTest(); + status_t GetConfigurationMessageTest(); + status_t GetInputFormatsTest(); + status_t GetOutputFormatsTest(); + status_t GetTranslatorInfoTest(); + status_t GetTranslatorsTest(); + status_t IdentifyTest(); + status_t MakeConfigurationViewTest(); + status_t TranslateTest(); +private: + void Debug(char* string); + + /** default roster used when performing tests */ + BTranslatorRoster* roster; + + /** Whether or not to output test info */ + bool verbose; +}; +#endif \ No newline at end of file diff --git a/src/tests/kits/translation/data/garbled_data b/src/tests/kits/translation/data/garbled_data new file mode 100644 index 0000000000..d285c363c0 Binary files /dev/null and b/src/tests/kits/translation/data/garbled_data differ diff --git a/src/tests/kits/translation/data/images/image.gif b/src/tests/kits/translation/data/images/image.gif new file mode 100644 index 0000000000..a92f013471 Binary files /dev/null and b/src/tests/kits/translation/data/images/image.gif differ diff --git a/src/tests/kits/translation/data/images/image.jpg b/src/tests/kits/translation/data/images/image.jpg new file mode 100644 index 0000000000..cd7768f99b Binary files /dev/null and b/src/tests/kits/translation/data/images/image.jpg differ diff --git a/src/tests/kits/translation/data/images/image.png b/src/tests/kits/translation/data/images/image.png new file mode 100644 index 0000000000..a959a6b462 Binary files /dev/null and b/src/tests/kits/translation/data/images/image.png differ diff --git a/src/tests/kits/translation/multitest/MainControlWindow.cpp b/src/tests/kits/translation/multitest/MainControlWindow.cpp new file mode 100644 index 0000000000..fe667025e0 --- /dev/null +++ b/src/tests/kits/translation/multitest/MainControlWindow.cpp @@ -0,0 +1,58 @@ +//MainControlWindow.cpp + +#include +#include +#include +#include +#include "WorkWindow.h" +#include "MainControlWindow.h" + +MainControlWindow::MainControlWindow() + : BWindow(BRect(100, 100, 220, 230), "Multi Test", B_TITLED_WINDOW, B_WILL_DRAW) +{ + fbtnAddView = new BButton(BRect(10, 10, 110, 60), "Add Test Window", "Add Test Window", + new BMessage(ADD_VIEW_BUTTON_ID)); + AddChild(fbtnAddView); + + fbtnAddTranslators = new BButton(BRect(10, 70, 110, 120), "Add Translators", "Add Translators", + new BMessage(ADD_TRANSLATORS_BUTTON_ID)); + AddChild(fbtnAddTranslators); + + for (int i = 0; i < 5; i++) { + WorkWindow *pWindow; + pWindow = new WorkWindow(BRect(100 + (10*i), 100, 300 + (10*i), 300)); + pWindow->Show(); + } +} + +bool +MainControlWindow::QuitRequested() +{ + be_app->PostMessage(B_QUIT_REQUESTED); + return BWindow::QuitRequested(); +} + +void +MainControlWindow::MessageReceived(BMessage *pMsg) +{ + switch (pMsg->what) { + case ADD_VIEW_BUTTON_ID: + //BAlert *pAlert; + //pAlert = new BAlert("Title", "text", "OK"); + //pAlert->Go(); + WorkWindow *pWindow; + pWindow = new WorkWindow(BRect(100, 100, 300, 300)); + pWindow->Show(); + break; + + case ADD_TRANSLATORS_BUTTON_ID: + BTranslatorRoster *pRoster; + pRoster = BTranslatorRoster::Default(); + pRoster->AddTranslators(); + break; + + default: + BWindow::MessageReceived(pMsg); + break; + } +} diff --git a/src/tests/kits/translation/multitest/MainControlWindow.h b/src/tests/kits/translation/multitest/MainControlWindow.h new file mode 100644 index 0000000000..567db75917 --- /dev/null +++ b/src/tests/kits/translation/multitest/MainControlWindow.h @@ -0,0 +1,24 @@ +// MainControlWindow.h + +#ifndef MAIN_CONTROL_WINDOW_H +#define MAIN_CONTROL_WINDOW_H + +#include +#include + +#define ADD_VIEW_BUTTON_ID 1 +#define ADD_TRANSLATORS_BUTTON_ID 2 + +class MainControlWindow : public BWindow { +public: + MainControlWindow(); + + virtual bool QuitRequested(); + virtual void MessageReceived(BMessage *pMsg); + +private: + BButton *fbtnAddView; + BButton *fbtnAddTranslators; +}; + +#endif \ No newline at end of file diff --git a/src/tests/kits/translation/multitest/MultiTest.cpp b/src/tests/kits/translation/multitest/MultiTest.cpp new file mode 100644 index 0000000000..7efbf28280 --- /dev/null +++ b/src/tests/kits/translation/multitest/MultiTest.cpp @@ -0,0 +1,36 @@ +// MultiTest.cpp + +#include "MainControlWindow.h" +#include "MultiTest.h" + +int main(int argc, char **argv) +{ + MultiTestApplication app; + app.Run(); + + return 0; +} + +MultiTestApplication::MultiTestApplication() + : BApplication("application/x-vnd.MultiTest") +{ + pRoster = new BTranslatorRoster(); + pRoster->AddTranslators(); + + MainControlWindow *pWindow; + pWindow = new MainControlWindow(); + + // make window visible + pWindow->Show(); +} + +MultiTestApplication::~MultiTestApplication() +{ + delete pRoster; +} + +BTranslatorRoster * +MultiTestApplication::GetTranslatorRoster() const +{ + return pRoster; +} \ No newline at end of file diff --git a/src/tests/kits/translation/multitest/MultiTest.h b/src/tests/kits/translation/multitest/MultiTest.h new file mode 100644 index 0000000000..1a62290cb4 --- /dev/null +++ b/src/tests/kits/translation/multitest/MultiTest.h @@ -0,0 +1,20 @@ +// MultiTest.h + +#ifndef MULTI_TEST_H +#define MULTI_TEST_H + +#include +#include + +class MultiTestApplication : public BApplication { +public: + MultiTestApplication(); + virtual ~MultiTestApplication(); + + BTranslatorRoster *GetTranslatorRoster() const; + +private: + BTranslatorRoster *pRoster; +}; + +#endif \ No newline at end of file diff --git a/src/tests/kits/translation/multitest/WorkView.cpp b/src/tests/kits/translation/multitest/WorkView.cpp new file mode 100644 index 0000000000..2cef690083 --- /dev/null +++ b/src/tests/kits/translation/multitest/WorkView.cpp @@ -0,0 +1,61 @@ +// WorkView.cpp + +#include +#include +#include +#include +#include +#include "MultiTest.h" +#include "WorkView.h" + +const char *kPath1 = "../data/images/image.jpg"; +const char *kPath2 = "../data/images/image.gif"; + +WorkView::WorkView(BRect rect) + : BView(rect, "Work View", B_FOLLOW_ALL, B_WILL_DRAW | B_PULSE_NEEDED) +{ + fbImage = true; + fPath = kPath1; +} + +void +WorkView::AttachedToWindow() +{ + BTranslatorRoster *pRoster = NULL; + BBitmap *pBitmap; + + //pRoster = ((MultiTestApplication *) be_app)->GetTranslatorRoster(); + + pBitmap = BTranslationUtils::GetBitmap(fPath, pRoster); + if (pBitmap) { + SetViewBitmap(pBitmap); + delete pBitmap; + } +} + +void +WorkView::Pulse() +{ + if (fbImage) { + ClearViewBitmap(); + fbImage = false; + if (fPath == kPath1) + fPath = kPath2; + else + fPath = kPath1; + } else { + //BTranslatorRoster *pRoster = NULL; + BBitmap *pBitmap = BTranslationUtils::GetBitmapFile(fPath); + if (pBitmap) { + ClearViewBitmap(); + SetViewBitmap(pBitmap); + delete pBitmap; + } else { + BPath Path(fPath); + printf("-- failed to get bitmap (%s)!\n", Path.Path()); + } + fbImage = true; + } + + Invalidate(); +} diff --git a/src/tests/kits/translation/multitest/WorkView.h b/src/tests/kits/translation/multitest/WorkView.h new file mode 100644 index 0000000000..139c3b4980 --- /dev/null +++ b/src/tests/kits/translation/multitest/WorkView.h @@ -0,0 +1,20 @@ +// WorkView.h + +#ifndef WORK_VIEW_H +#define WORK_VIEW_H + +#include + +class WorkView : public BView { +public: + WorkView(BRect frame); + + virtual void AttachedToWindow(); + virtual void Pulse(); + +private: + bool fbImage; + const char *fPath; +}; + +#endif \ No newline at end of file diff --git a/src/tests/kits/translation/multitest/WorkWindow.cpp b/src/tests/kits/translation/multitest/WorkWindow.cpp new file mode 100644 index 0000000000..dd885ac145 --- /dev/null +++ b/src/tests/kits/translation/multitest/WorkWindow.cpp @@ -0,0 +1,29 @@ +// WorkWindow.cpp + +#include +#include +#include +#include "WorkView.h" +#include "WorkWindow.h" + +WorkWindow::WorkWindow(BRect rect) + : BWindow(rect, "Work Window", B_TITLED_WINDOW, B_WILL_DRAW) +{ + SetPulseRate(1000000); // pulse once every 2 seconds + + WorkView *pView; + BRect viewrect(Bounds()); + pView = new WorkView(viewrect); + + AddChild(pView); +} + +void +WorkWindow::MessageReceived(BMessage *pMsg) +{ + switch (pMsg->what) { + default: + BWindow::MessageReceived(pMsg); + break; + } +} \ No newline at end of file diff --git a/src/tests/kits/translation/multitest/WorkWindow.h b/src/tests/kits/translation/multitest/WorkWindow.h new file mode 100644 index 0000000000..8545f3e06e --- /dev/null +++ b/src/tests/kits/translation/multitest/WorkWindow.h @@ -0,0 +1,15 @@ +// WorkWindow.h + +#ifndef WORK_WINDOW_H +#define WORK_WINDOW_H + +#include + +class WorkWindow : public BWindow { +public: + WorkWindow(BRect rect); + + virtual void MessageReceived(BMessage *pMsg); +}; + +#endif \ No newline at end of file diff --git a/src/tests/servers/input/msgspy/MsgSpy.cpp b/src/tests/servers/input/msgspy/MsgSpy.cpp new file mode 100644 index 0000000000..d508c98530 --- /dev/null +++ b/src/tests/servers/input/msgspy/MsgSpy.cpp @@ -0,0 +1,519 @@ +//------------------------------------------------------------------------- +// Handy InputFilter that dumps all Messages to a file. +//------------------------------------------------------------------------- +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +extern "C" _EXPORT BInputServerFilter* instantiate_input_filter(); + +class MsgSpy : public BInputServerFilter +{ +public: + MsgSpy(); + virtual ~MsgSpy(); + + virtual status_t InitCheck(void); + virtual filter_result Filter(BMessage *message, BList *outList); +private: + const char* MapWhatToString(uint32 w); + void OutputMsgField(const char* fieldName, + const uint32 rawType, + int rawCount, + const void* rawData); + + status_t m_status; + BFile* m_outfile; +}; + +//------------------------------------------------------------------------- +// Create a new MsgSpy instance and return it to the caller. +//------------------------------------------------------------------------- +BInputServerFilter* instantiate_input_filter() +{ + return (new MsgSpy() ); +} + + +//------------------------------------------------------------------------- +//------------------------------------------------------------------------- +MsgSpy::MsgSpy() +{ + // Create the output file and return its status. + m_outfile = new BFile("/boot/home/MsgSpy.output", B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); + //m_status = m_outfile->InitCheck(); + m_status = B_OK; +} + +//------------------------------------------------------------------------- +//------------------------------------------------------------------------- +MsgSpy::~MsgSpy() +{ + if (NULL != m_outfile) + { + // Close and destroy the output file. + delete m_outfile; + } +} + +//------------------------------------------------------------------------- +//------------------------------------------------------------------------- +status_t MsgSpy::InitCheck(void) +{ + return m_status; +} + +//------------------------------------------------------------------------- +//------------------------------------------------------------------------- +filter_result MsgSpy::Filter(BMessage *message, BList *outList) +{ + char* field_name; + uint32 field_type; + int32 field_count; + const void* field_data; + ssize_t field_data_bytes; + char msg_buffer [1024]; + + // Print out the message constant (what). + sprintf(msg_buffer, "%s\n", MapWhatToString(message->what) ); + m_outfile->Write(msg_buffer, strlen(msg_buffer) ); + + // Display each field in the message. + sprintf(msg_buffer, "{\n"); + m_outfile->Write(msg_buffer, strlen(msg_buffer) ); + for (int32 i = 0; B_OK == message->GetInfo(B_ANY_TYPE, + i, + &field_name, + &field_type, + &field_count); i++) + { + message->FindData(field_name, field_type, &field_data, &field_data_bytes); + OutputMsgField(field_name, field_type, field_count, field_data); + } + sprintf(msg_buffer, "}\n"); + m_outfile->Write(msg_buffer, strlen(msg_buffer) ); + + return (B_DISPATCH_MESSAGE); +} + +//------------------------------------------------------------------------- +//------------------------------------------------------------------------- +const char* MsgSpy::MapWhatToString(uint32 w) +{ + const char* s; + switch (w) + { + // Pointing device event messages. + case B_MOUSE_DOWN: s = "B_MOUSE_DOWN"; break; + case B_MOUSE_UP: s = "B_MOUSE_UP"; break; + case B_MOUSE_MOVED: s = "B_MOUSE_MOVED"; break; + + // Keyboard device event messages. + case B_KEY_DOWN: s = "B_KEY_DOWN"; break; + case B_UNMAPPED_KEY_DOWN: s = "B_UNMAPPED_KEY_DOWN"; break; + case B_KEY_UP: s = "B_KEY_UP"; break; + case B_UNMAPPED_KEY_UP: s = "B_UNMAPPED_KEY_UP"; break; + case B_MODIFIERS_CHANGED: s = "B_MODIFIERS_CHANGED"; break; + + default: s = "UNKNOWN_MESSAGE"; break; + } + return s; +} + +//------------------------------------------------------------------------- +//------------------------------------------------------------------------- +void MsgSpy::OutputMsgField(const char* fieldName, + const uint32 rawType, + int rawCount, + const void* rawData) +{ + char msg_buffer [1024]; + char value_buffer [256]; + BString field_data; + const char* field_type; + const int field_count = rawCount; + const char* separator; + + switch (rawType) + { + case B_CHAR_TYPE: + { + field_type = "B_CHAR_TYPE"; + field_data << "{ "; + for (const char* data_ptr = (const char*)rawData; + rawCount > 0; + rawCount--, data_ptr++) + { + separator = (1 < rawCount) ? ", " : " }"; + field_data << *data_ptr << separator; + } + break; + } + + case B_INT8_TYPE: + { + field_type = "B_INT8_TYPE"; + field_data << "{ "; + for (const int8* data_ptr = (const int8*)rawData; + rawCount > 0; + rawCount--, data_ptr++) + { + separator = (1 < rawCount) ? ", " : " }"; + field_data << *data_ptr << separator; + } + break; + } + + case B_INT16_TYPE: + { + field_type = "B_INT16_TYPE"; + field_data << "{ "; + for (const int16* data_ptr = (const int16*)rawData; + rawCount > 0; + rawCount--, data_ptr++) + { + separator = (1 < rawCount) ? ", " : " }"; + field_data << *data_ptr << separator; + } + break; + } + + case B_INT32_TYPE: + { + field_type = "B_INT32_TYPE"; + field_data << "{ "; + for (const int32* data_ptr = (const int32*)rawData; + rawCount > 0; + rawCount--, data_ptr++) + { + separator = (1 < rawCount) ? ", " : " }"; + field_data << *data_ptr << separator; + } + break; + } + + case B_INT64_TYPE: + { + field_type = "B_INT64_TYPE"; + field_data << "{ "; + for (const int64* data_ptr = (const int64*)rawData; + rawCount > 0; + rawCount--, data_ptr++) + { + separator = (1 < rawCount) ? ", " : " }"; + field_data << *data_ptr << separator; + } + break; + } + + case B_UINT8_TYPE: + { + field_type = "B_UINT8_TYPE"; + field_data << "{ "; + for (const uint8* data_ptr = (const uint8*)rawData; + rawCount > 0; + rawCount--, data_ptr++) + { + separator = (1 < rawCount) ? ", " : " }"; + field_data << (uint32)(*data_ptr) << separator; + } + break; + } + + case B_UINT16_TYPE: + { + field_type = "B_UINT16_TYPE"; + field_data << "{ "; + for (const uint16* data_ptr = (const uint16*)rawData; + rawCount > 0; + rawCount--, data_ptr++) + { + separator = (1 < rawCount) ? ", " : " }"; + field_data << (uint32)(*data_ptr) << separator; + } + break; + } + + case B_UINT32_TYPE: + { + field_type = "B_UINT32_TYPE"; + field_data << "{ "; + for (const uint32* data_ptr = (const uint32*)rawData; + rawCount > 0; + rawCount--, data_ptr++) + { + separator = (1 < rawCount) ? ", " : " }"; + field_data << *data_ptr << separator; + } + break; + } + + case B_UINT64_TYPE: + { + field_type = "B_UINT64_TYPE"; + field_data << "{ "; + for (const uint64* data_ptr = (const uint64*)rawData; + rawCount > 0; + rawCount--, data_ptr++) + { + separator = (1 < rawCount) ? ", " : " }"; + field_data << *data_ptr << separator; + } + break; + } + + case B_FLOAT_TYPE: + { + field_type = "B_FLOAT_TYPE"; + field_data << "{ "; + for (const float* data_ptr = (const float*)rawData; + rawCount > 0; + rawCount--, data_ptr++) + { + separator = (1 < rawCount) ? ", " : " }"; + field_data << *data_ptr << separator; + } + break; + } + + case B_DOUBLE_TYPE: + { + field_type = "B_DOUBLE_TYPE"; + field_data << "{ "; + for (const double* data_ptr = (const double*)rawData; + rawCount > 0; + rawCount--, data_ptr++) + { + separator = (1 < rawCount) ? ", " : " }"; + sprintf(value_buffer, "%f", *data_ptr); + field_data << value_buffer << separator; + } + break; + } + + case B_BOOL_TYPE: + { + field_type = "B_BOOL_TYPE"; + field_data << "{ "; + for (const bool* data_ptr = (const bool*)rawData; + rawCount > 0; + rawCount--, data_ptr++) + { + separator = (1 < rawCount) ? ", " : " }"; + sprintf(value_buffer, "%s", (true == *data_ptr) ? "true" : "false"); + field_data << value_buffer << separator; + } + break; + } + + case B_OFF_T_TYPE: + { + field_type = "B_OFF_T_TYPE"; + field_data << "{ "; + for (const off_t* data_ptr = (const off_t*)rawData; + rawCount > 0; + rawCount--, data_ptr++) + { + separator = (1 < rawCount) ? ", " : " }"; + field_data << *data_ptr << separator; + } + break; + } + + case B_SIZE_T_TYPE: + { + field_type = "B_SIZE_T_TYPE"; + field_data << "{ "; + for (const size_t* data_ptr = (const size_t*)rawData; + rawCount > 0; + rawCount--, data_ptr++) + { + separator = (1 < rawCount) ? ", " : " }"; + field_data << *data_ptr << separator; + } + break; + } + + case B_SSIZE_T_TYPE: + { + field_type = "B_SSIZE_T_TYPE"; + field_data << "{ "; + for (const ssize_t* data_ptr = (const ssize_t*)rawData; + rawCount > 0; + rawCount--, data_ptr++) + { + separator = (1 < rawCount) ? ", " : " }"; + field_data << *data_ptr << separator; + } + break; + } + + case B_POINTER_TYPE: + { + field_type = "B_POINTER_TYPE"; + break; + } + + case B_OBJECT_TYPE: + { + field_type = "B_OBJECT_TYPE"; + break; + } + + case B_MESSAGE_TYPE: + { + field_type = "B_MESSAGE_TYPE"; + break; + } + + case B_MESSENGER_TYPE: + { + field_type = "B_MESSENGER_TYPE"; + break; + } + + case B_POINT_TYPE: + { + field_type = "B_POINT_TYPE"; + field_data << "{ "; + for (const BPoint* data_ptr = (const BPoint*)rawData; + rawCount > 0; + rawCount--, data_ptr++) + { + separator = (1 < rawCount) ? ", " : " }"; + field_data << "(" << data_ptr->x << ", " << data_ptr->y << ")" << separator; + } + break; + } + + case B_RECT_TYPE: + { + field_type = "B_RECT_TYPE"; + break; + } + +// case B_PATH_TYPE: s = "B_PATH_TYPE"; break; + + case B_REF_TYPE: + { + field_type = "B_REF_TYPE"; + break; + } + + case B_RGB_COLOR_TYPE: + { + field_type = "B_RGB_COLOR_TYPE"; + break; + } + + case B_PATTERN_TYPE: + { + field_type = "B_PATTERN_TYPE"; + break; + } + + case B_STRING_TYPE: + { + field_type = "B_STRING_TYPE"; + field_data << "{ "; + for (const char* data_ptr = (const char*)rawData; + rawCount > 0; + rawCount--, data_ptr+= strlen(data_ptr) ) + { + separator = (1 < rawCount) ? ", " : " }"; + field_data << "\"" << data_ptr << "\"" << separator; + } + break; + } + + case B_MONOCHROME_1_BIT_TYPE: + { + field_type = "B_MONOCHROME_1_BIT_TYPE"; + break; + } + + case B_GRAYSCALE_8_BIT_TYPE: + { + field_type = "B_GRAYSCALE_8_BIT_TYPE"; + break; + } + + case B_COLOR_8_BIT_TYPE: + { + field_type = "B_COLOR_8_BIT_TYPE"; + break; + } + + case B_RGB_32_BIT_TYPE: + { + field_type = "B_RGB_32_BIT_TYPE"; + break; + } + + case B_TIME_TYPE: + { + field_type = "B_TIME_TYPE"; + break; + } + + case B_MEDIA_PARAMETER_TYPE: + { + field_type = "B_MEDIA_PARAMETER_TYPE"; + break; + } + + case B_MEDIA_PARAMETER_WEB_TYPE: + { + field_type = "B_MEDIA_PARAMETER_WEB_TYPE"; + break; + } + + case B_MEDIA_PARAMETER_GROUP_TYPE: + { + field_type = "B_MEDIA_PARAMETER_GROUP_TYPE"; + break; + } + + case B_RAW_TYPE: + { + field_type = "B_RAW_TYPE"; + break; + } + + case B_MIME_TYPE: + { + field_type = "B_MIME_TYPE"; + break; + } + + case B_ANY_TYPE: + { + field_type = "B_ANY_TYPE"; + break; + } + + default: + { + field_type = "UNKNOWN_TYPE"; + break; + } + } + + sprintf(msg_buffer, + " %-18s %-18s [%2d] = %s\n", + field_type, + fieldName, + field_count, + field_data.String() ); + + m_outfile->Write(msg_buffer, strlen(msg_buffer) ); +} diff --git a/src/tests/servers/input/msgspy/clean b/src/tests/servers/input/msgspy/clean new file mode 100644 index 0000000000..7a78c10621 --- /dev/null +++ b/src/tests/servers/input/msgspy/clean @@ -0,0 +1 @@ +rm ~/MsgSpy.output diff --git a/src/tests/servers/input/msgspy/start b/src/tests/servers/input/msgspy/start new file mode 100644 index 0000000000..df3081873f --- /dev/null +++ b/src/tests/servers/input/msgspy/start @@ -0,0 +1,2 @@ +cp ./obj.x86/MsgSpy /boot/home/config/add-ons/input_server/filters +/boot/beos/system/servers/input_server -q diff --git a/src/tests/servers/input/msgspy/stop b/src/tests/servers/input/msgspy/stop new file mode 100644 index 0000000000..320e8d5e5a --- /dev/null +++ b/src/tests/servers/input/msgspy/stop @@ -0,0 +1,2 @@ +rm -f /boot/home/config/add-ons/input_server/filters/MsgSpy +/boot/beos/system/servers/input_server -q diff --git a/src/tests/servers/input/portspy/PortSpy.cpp b/src/tests/servers/input/portspy/PortSpy.cpp new file mode 100644 index 0000000000..6d6516b002 --- /dev/null +++ b/src/tests/servers/input/portspy/PortSpy.cpp @@ -0,0 +1,26 @@ +#include +#include "OS.h" + +// +// Sequentially search for valid ports by port number and display +// their properties. +// +int main(int argc, char* argv[]) +{ + port_info info; + + for (int port_num = 0; port_num < 9999; port_num++) + { + if (B_OK == get_port_info(port_num, &info) ) + { + // Found a valid port - display it's properties. + // + printf("%04u: Team %u - %s\n", + (unsigned int)info.port, + (unsigned int)info.team, + info.name); + } + } + + return 0; +} \ No newline at end of file diff --git a/src/tools/Jamfile b/src/tools/Jamfile new file mode 100644 index 0000000000..49c29a8b2c --- /dev/null +++ b/src/tools/Jamfile @@ -0,0 +1,2 @@ +SubInclude OBOS_TOP sources os tools key ; +SubInclude OBOS_TOP sources os tools jam ; diff --git a/src/tools/cppunit/CppUnitShell.cpp b/src/tools/cppunit/CppUnitShell.cpp new file mode 100644 index 0000000000..e51f00cd81 --- /dev/null +++ b/src/tools/cppunit/CppUnitShell.cpp @@ -0,0 +1,213 @@ +//---------------------------------------------------------------------- +// CppUnitShell.cpp - Copyright 2002 Tyler Dauwalder +// This software is release under the GNU Lesser GPL +// See the accompanying CppUnitShell.LICENSE file, or wander +// over to: http://www.gnu.org/copyleft/lesser.html +//---------------------------------------------------------------------- +#include "CppUnitShell.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CppUnitShell::CppUnitShell(const std::string &description, SyncObject *syncObject) + : fVerbosityLevel(v2) + , fDescription(description) + , fTestResults(syncObject) +{ +}; + +void +CppUnitShell::AddSuite(const std::string &name, const SuiteFunction suite) { + if (suite != NULL) + fTests[name] = suite; +} + +int +CppUnitShell::Run(int argc, char *argv[]) { + // Parse the command line args + if (!ProcessArguments(argc, argv)) + return 0; + + // Add the proper tests to our suite (or exit if there + // are no tests installed). + CppUnit::TestSuite suite; + if (fTests.empty()) { + + // No installed tests whatsoever, so bail + cout << "ERROR: No installed tests to run!" << endl; + return 0; + + } else if (fTestsToRun.empty()) { + + // None specified, so run them all + std::map::iterator i; + for (i = fTests.begin(); i != fTests.end(); ++i) + suite.addTest( i->second() ); + + } else { + + // One or more specified, so only run those + std::set::const_iterator i; + for (i = fTestsToRun.begin(); i != fTestsToRun.end(); ++i) + suite.addTest( fTests[*i]() ); + + } + + // Run all the tests + InitOutput(); + suite.run(&fTestResults); + PrintResults(); + + return 0; +} + +CppUnitShell::VerbosityLevel +CppUnitShell::Verbosity() const { + return fVerbosityLevel; +} + +void +CppUnitShell::PrintDescription(int argc, char *argv[]) { + cout << endl << fDescription; +} + +void +CppUnitShell::PrintHelp() { + const char indent[] = " "; + cout << endl; + cout << "VALID ARGUMENTS: " << endl; + cout << indent << "--help Displays this help text plus some other garbage" << endl; + cout << indent << "--list Lists the names of classes with installed tests" << endl; + cout << indent << "-v0 Sets verbosity level to 0 (concise summary only)" << endl; + cout << indent << "-v1 Sets verbosity level to 1 (complete summary only)" << endl; + cout << indent << "-v2 Sets verbosity level to 2 (*default* -- per-test results plus" << endl; + cout << indent << " complete summary)" << endl; + cout << indent << "-v3 Sets verbosity level to 3 (per-test results and timing info" << endl; + cout << indent << " plus complete summary)" << endl; + cout << indent << "CLASSNAME Instructs the program to run the test for the given class; if" << endl; + cout << indent << " no classes are specified, all tests are run" << endl; + cout << endl; + +} + +bool +CppUnitShell::ProcessArguments(int argc, char *argv[]) { + // If we're given no parameters, the default settings + // will do just fine + if (argc < 2) + return true; + + // Handle each command line argument (skipping the first + // which is just the app name) + for (int i = 1; i < argc; i++) { + std::string str(argv[i]); + + if (str == "--help") { + PrintDescription(argc, argv); + PrintHelp(); + return false; + } + else if (str == "--list") { + // Print out the list of installed tests + cout << "------------------------------------------------------------------------------" << endl; + cout << "Available Tests:" << endl; + cout << "------------------------------------------------------------------------------" << endl; + map::const_iterator i; + for (i = fTests.begin(); i != fTests.end(); ++i) + cout << i->first << endl; + cout << endl; + return false; + } + else if (str == "-v0") { + fVerbosityLevel = v0; + } + else if (str == "-v1") { + fVerbosityLevel = v1; + } + else if (str == "-v2") { + fVerbosityLevel = v2; + } + else if (fTests.find(str) != fTests.end()) { + fTestsToRun.insert(str); + } + else { + cout << endl << "ERROR: Invalid argument \"" << str << "\"" << endl; + PrintHelp(); + return false; + } + + } + + return true; +} + +void +CppUnitShell::InitOutput() { + // For vebosity level 2, we output info about each test + // as we go. This involves a custom CppUnit::TestListener + // class. + if (fVerbosityLevel == v2) { + cout << "------------------------------------------------------------------------------" << endl; + cout << "Tests" << endl; + cout << "------------------------------------------------------------------------------" << endl; + fTestResults.addListener(new CppUnitShell::TestListener); + fTestResults.addListener(&fResultsCollector); + } +} + +void +CppUnitShell::PrintResults() { + + if (fVerbosityLevel > v0) { + // Print out detailed results for verbosity levels > 0 + cout << "------------------------------------------------------------------------------" << endl; + cout << "Results " << endl; + cout << "------------------------------------------------------------------------------" << endl; + + // Print failures and errors if there are any, otherwise just say "PASSED" + ::CppUnit::TestResultCollector::TestFailures::const_iterator iFailure; + if (fResultsCollector.testFailuresTotal() > 0) { + if (fResultsCollector.testFailures() > 0) { + cout << "- FAILURES: " << fResultsCollector.testFailures() << endl; + for (iFailure = fResultsCollector.failures().begin(); + iFailure != fResultsCollector.failures().end(); + ++iFailure) + { + if (!(*iFailure)->isError()) + cout << " " << (*iFailure)->toString() << endl; + } + } + if (fResultsCollector.testErrors() > 0) { + cout << "- ERRORS: " << fResultsCollector.testErrors() << endl; + for (iFailure = fResultsCollector.failures().begin(); + iFailure != fResultsCollector.failures().end(); + ++iFailure) + { + if ((*iFailure)->isError()) + cout << " " << (*iFailure)->toString() << endl; + } + } + + } + else + cout << "+ PASSED" << endl; + + cout << endl; + + } + else { + // Print out concise results for verbosity level == 0 + if (fResultsCollector.testFailuresTotal() > 0) + cout << "- FAILED" << endl; + else + cout << "+ PASSED" << endl; + } + +} diff --git a/src/tools/cppunit/Jamfile b/src/tools/cppunit/Jamfile new file mode 100644 index 0000000000..d625b87f1f --- /dev/null +++ b/src/tools/cppunit/Jamfile @@ -0,0 +1,49 @@ +SubDir OBOS_TOP sources tools cppunit ; + +rule CppUnitLibrary +{ + # CppUnitLibrary ; + local _lib = libcppunit.so ; + + UseCppUnitHeaders ; + SetupObjectsDir ; + MakeLocateObjects [ FGristFiles $(<) ] ; + Main $(_lib) : $(<) ; + MakeLocate $(_lib) : /boot/home/config/lib ; + LINKFLAGS on $(_lib) = $(LINKFLAGS) -nostart -Xlinker -soname=\"$(_lib)\" ; +} + +CppUnitLibrary + CppUnitShell.cpp + TestCase.cpp + TestResult.cpp + TestShell.cpp + TestSuite.cpp + cppunit/Asserter.cpp + cppunit/CompilerOutputter.cpp + cppunit/Exception.cpp + cppunit/NotEqualException.cpp + cppunit/RepeatedTest.cpp + cppunit/SourceLine.cpp + cppunit/SynchronizedObject.cpp + cppunit/TestAssert.cpp + cppunit/TestCase.cpp + cppunit/TestFactoryRegistry.cpp + cppunit/TestFailure.cpp + cppunit/TestResult.cpp + cppunit/TestResultCollector.cpp + cppunit/TestRunner.cpp + cppunit/TestSetUp.cpp + cppunit/TestSucessListener.cpp + cppunit/TestSuite.cpp + cppunit/TextOutputter.cpp + cppunit/TextTestProgressListener.cpp + cppunit/TextTestResult.cpp + cppunit/TypeInfoHelper.cpp + cppunit/XmlOutputter.cpp +; + +LinkSharedOSLibs libcppunit.so : + stdc++.r4 + /boot/develop/lib/x86/libbe.so +; diff --git a/src/tools/cppunit/TestCase.cpp b/src/tools/cppunit/TestCase.cpp new file mode 100644 index 0000000000..0c00ff0f2f --- /dev/null +++ b/src/tools/cppunit/TestCase.cpp @@ -0,0 +1,35 @@ +#include +#include + +TestCase::TestCase() + : CppUnit::TestCase() + , fValidCWD(false) +{ +} + +TestCase::TestCase(std::string name) + : CppUnit::TestCase(name) + , fValidCWD(false) +{ +} + +// Saves the location of the current working directory. To return to the +// last saved working directory, all \ref RestorCWD(). +void +TestCase::SaveCWD() { + fValidCWD = getcwd(fCurrentWorkingDir, B_PATH_NAME_LENGTH); +} + +/* Restores the current working directory to last directory saved by a + call to SaveCWD(). If SaveCWD() has not been called and an alternate + directory is specified by alternate, the current working directory is + changed to alternate. If alternate is null, the current working directory + is not modified. +*/ +void +TestCase::RestoreCWD(const char *alternate) { + if (fValidCWD) + chdir(fCurrentWorkingDir); + else if (alternate != NULL) + chdir(alternate); +} diff --git a/src/tools/cppunit/TestResult.cpp b/src/tools/cppunit/TestResult.cpp new file mode 100644 index 0000000000..cb45315897 --- /dev/null +++ b/src/tools/cppunit/TestResult.cpp @@ -0,0 +1,8 @@ +#include +#include + +TestResult::TestResult() + : CppUnit::TestResult(new LockerSyncObject()) +{ +} + diff --git a/src/tools/cppunit/TestShell.cpp b/src/tools/cppunit/TestShell.cpp new file mode 100644 index 0000000000..27772cee44 --- /dev/null +++ b/src/tools/cppunit/TestShell.cpp @@ -0,0 +1,36 @@ +#include +#include +#include +#include + +TestShell::TestShell(const std::string &description, SyncObject *syncObject) + : CppUnitShell(description, syncObject), + fTestDir(NULL) +{ +} + +TestShell::~TestShell() +{ + delete fTestDir; +} + +int +TestShell::Run(int argc, char *argv[]) +{ + // Let's hope BPath does work. ;-) + BPath path(argv[0]); + if (path.InitCheck() == B_OK) { + fTestDir = new BPath(); + if (path.GetParent(fTestDir) != B_OK) + printf("Couldn't get test dir.\n"); + } else + printf("Couldn't find the path to the test app.\n"); + return CppUnitShell::Run(argc, argv); +} + +const char* +TestShell::TestDir() const +{ + return (fTestDir ? fTestDir->Path() : NULL); +} + diff --git a/src/tools/cppunit/TestSuite.cpp b/src/tools/cppunit/TestSuite.cpp new file mode 100644 index 0000000000..f1713557dd --- /dev/null +++ b/src/tools/cppunit/TestSuite.cpp @@ -0,0 +1,8 @@ +#include + +void +TestSuite::run (CppUnit::TestResult *result) { + setUp(); + CppUnit::TestSuite::run(result); + tearDown(); +} diff --git a/src/tools/cppunit/cppunit/Asserter.cpp b/src/tools/cppunit/cppunit/Asserter.cpp new file mode 100644 index 0000000000..29c5201413 --- /dev/null +++ b/src/tools/cppunit/cppunit/Asserter.cpp @@ -0,0 +1,57 @@ +#include +#include + + +namespace CppUnit +{ + + +namespace Asserter +{ + + +void +fail( std::string message, + SourceLine sourceLine ) +{ + throw Exception( message, sourceLine ); +} + + +void +failIf( bool shouldFail, + std::string message, + SourceLine location ) +{ + if ( shouldFail ) + fail( message, location ); +} + + +void +failNotEqual( std::string expected, + std::string actual, + SourceLine sourceLine, + std::string additionalMessage ) +{ + throw NotEqualException( expected, + actual, + sourceLine, + additionalMessage ); +} + + +void +failNotEqualIf( bool shouldFail, + std::string expected, + std::string actual, + SourceLine sourceLine, + std::string additionalMessage ) +{ + if ( shouldFail ) + failNotEqual( expected, actual, sourceLine, additionalMessage ); +} + + +} // namespace Asserter +} // namespace CppUnit diff --git a/src/tools/cppunit/cppunit/CompilerOutputter.cpp b/src/tools/cppunit/cppunit/CompilerOutputter.cpp new file mode 100644 index 0000000000..025dd34ada --- /dev/null +++ b/src/tools/cppunit/cppunit/CompilerOutputter.cpp @@ -0,0 +1,202 @@ +#include +#include +#include +#include +#include +#include + + +namespace CppUnit +{ + +CompilerOutputter::CompilerOutputter( TestResultCollector *result, + std::ostream &stream ) : + m_result( result ), + m_stream( stream ) +{ +} + + +CompilerOutputter::~CompilerOutputter() +{ +} + + +CompilerOutputter * +CompilerOutputter::defaultOutputter( TestResultCollector *result, + std::ostream &stream ) +{ + return new CompilerOutputter( result, stream ); +// For automatic adpatation... +// return new CPPUNIT_DEFAULT_OUTPUTTER( result, stream ); +} + + +void +CompilerOutputter::write() +{ + if ( m_result->wasSuccessful() ) + printSucess(); + else + printFailureReport(); +} + + +void +CompilerOutputter::printSucess() +{ + m_stream << "OK (" << m_result->runTests() << ")" + << std::endl; +} + + +void +CompilerOutputter::printFailureReport() +{ + printFailuresList(); + printStatistics(); +} + + +void +CompilerOutputter::printFailuresList() +{ + for ( int index =0; index < m_result->testFailuresTotal(); ++index) + { + printFailureDetail( m_result->failures()[ index ] ); + } +} + + +void +CompilerOutputter::printFailureDetail( TestFailure *failure ) +{ + printFailureLocation( failure->sourceLine() ); + printFailureType( failure ); + printFailedTestName( failure ); + printFailureMessage( failure ); +} + + +void +CompilerOutputter::printFailureLocation( SourceLine sourceLine ) +{ + if ( sourceLine.isValid() ) + m_stream << sourceLine.fileName() + << "(" << sourceLine.lineNumber() << ") : "; + else + m_stream << "##Failure Location unknown## : "; +} + + +void +CompilerOutputter::printFailureType( TestFailure *failure ) +{ + m_stream << (failure->isError() ? "Error" : "Assertion"); +} + + +void +CompilerOutputter::printFailedTestName( TestFailure *failure ) +{ + m_stream << std::endl; + m_stream << "Test name: " << failure->failedTestName(); +} + + +void +CompilerOutputter::printFailureMessage( TestFailure *failure ) +{ + m_stream << std::endl; + Exception *thrownException = failure->thrownException(); + if ( thrownException->isInstanceOf( NotEqualException::type() ) ) + printNotEqualMessage( thrownException ); + else + printDefaultMessage( thrownException ); + m_stream << std::endl; +} + + +void +CompilerOutputter::printNotEqualMessage( Exception *thrownException ) +{ + NotEqualException *e = (NotEqualException *)thrownException; + m_stream << wrap( "- Expected : " + e->expectedValue() ); + m_stream << std::endl; + m_stream << wrap( "- Actual : " + e->actualValue() ); + m_stream << std::endl; + if ( !e->additionalMessage().empty() ) + { + m_stream << wrap( e->additionalMessage() ); + m_stream << std::endl; + } +} + + +void +CompilerOutputter::printDefaultMessage( Exception *thrownException ) +{ + std::string wrappedMessage = wrap( thrownException->what() ); + m_stream << wrappedMessage << std::endl; +} + + +void +CompilerOutputter::printStatistics() +{ + m_stream << "Failures !!!" << std::endl; + m_stream << "Run: " << m_result->runTests() << " " + << "Failure total: " << m_result->testFailuresTotal() << " " + << "Failures: " << m_result->testFailures() << " " + << "Errors: " << m_result->testErrors() + << std::endl; +} + + +std::string +CompilerOutputter::wrap( std::string message ) +{ + Lines lines = splitMessageIntoLines( message ); + std::string wrapped; + for ( Lines::iterator it = lines.begin(); it != lines.end(); ++it ) + { + std::string line( *it ); + const int maxLineLength = 80; + int index =0; + while ( index < line.length() ) + { + std::string line( line.substr( index, maxLineLength ) ); + wrapped += line; + index += maxLineLength; + if ( index < line.length() ) + wrapped += "\n"; + } + wrapped += '\n'; + } + return wrapped; +} + + +CompilerOutputter::Lines +CompilerOutputter::splitMessageIntoLines( std::string message ) +{ + Lines lines; + + std::string::iterator itStart = message.begin(); + while ( true ) + { + std::string::iterator itEol = std::find( itStart, + message.end(), + '\n' ); + lines.push_back( message.substr( itStart - message.begin(), + itEol - itStart ) ); + if ( itEol == message.end() ) + break; + itStart = itEol +1; + } + return lines; +} + + + +} // namespace CppUnit diff --git a/src/tools/cppunit/cppunit/Exception.cpp b/src/tools/cppunit/cppunit/Exception.cpp new file mode 100644 index 0000000000..add261adbd --- /dev/null +++ b/src/tools/cppunit/cppunit/Exception.cpp @@ -0,0 +1,135 @@ +#include "cppunit/Exception.h" + + +namespace CppUnit { + + +#ifdef CPPUNIT_ENABLE_SOURCELINE_DEPRECATED +/*! + * \deprecated Use SourceLine::isValid() instead. + */ +const std::string Exception::UNKNOWNFILENAME = ""; + +/*! + * \deprecated Use SourceLine::isValid() instead. + */ +const long Exception::UNKNOWNLINENUMBER = -1; +#endif + + +/// Construct the exception +Exception::Exception( const Exception &other ) : + std::exception( other ) +{ + m_message = other.m_message; + m_sourceLine = other.m_sourceLine; +} + + +/*! + * \deprecated Use other constructor instead. + */ +Exception::Exception( std::string message, + SourceLine sourceLine ) : + m_message( message ), + m_sourceLine( sourceLine ) +{ +} + + +#ifdef CPPUNIT_ENABLE_SOURCELINE_DEPRECATED +/*! + * \deprecated Use other constructor instead. + */ +Exception::Exception( std::string message, + long lineNumber, + std::string fileName ) : + m_message( message ), + m_sourceLine( fileName, lineNumber ) +{ +} +#endif + + +/// Destruct the exception +Exception::~Exception () throw() +{ +} + + +/// Perform an assignment +Exception& +Exception::operator =( const Exception& other ) +{ +// Don't call superclass operator =(). VC++ STL implementation +// has a bug. It calls the destructor and copy constructor of +// std::exception() which reset the virtual table to std::exception. +// SuperClass::operator =(other); + + if ( &other != this ) + { + m_message = other.m_message; + m_sourceLine = other.m_sourceLine; + } + + return *this; +} + + +/// Return descriptive message +const char* +Exception::what() const throw() +{ + return m_message.c_str (); +} + +/// Location where the error occured +SourceLine +Exception::sourceLine() const +{ + return m_sourceLine; +} + + +#ifdef CPPUNIT_ENABLE_SOURCELINE_DEPRECATED +/// The line on which the error occurred +long +Exception::lineNumber() const +{ + return m_sourceLine.isValid() ? m_sourceLine.lineNumber() : + UNKNOWNLINENUMBER; +} + + +/// The file in which the error occurred +std::string +Exception::fileName() const +{ + return m_sourceLine.isValid() ? m_sourceLine.fileName() : + UNKNOWNFILENAME; +} +#endif + + +Exception * +Exception::clone() const +{ + return new Exception( *this ); +} + + +bool +Exception::isInstanceOf( const Type &exceptionType ) const +{ + return exceptionType == type(); +} + + +Exception::Type +Exception::type() +{ + return Type( "CppUnit::Exception" ); +} + + +} // namespace CppUnit diff --git a/src/tools/cppunit/cppunit/NotEqualException.cpp b/src/tools/cppunit/cppunit/NotEqualException.cpp new file mode 100644 index 0000000000..738961d64f --- /dev/null +++ b/src/tools/cppunit/cppunit/NotEqualException.cpp @@ -0,0 +1,111 @@ +#include + +namespace CppUnit { + + +NotEqualException::NotEqualException( std::string expected, + std::string actual, + SourceLine sourceLine , + std::string additionalMessage ) : + Exception( "Expected: " + expected + + ", but was: " + actual + + "." + additionalMessage , + sourceLine), + m_expected( expected ), + m_actual( actual ), + m_additionalMessage( additionalMessage ) +{ +} + + +#ifdef CPPUNIT_ENABLE_SOURCELINE_DEPRECATED +/*! + * \deprecated Use other constructor instead. + */ +NotEqualException::NotEqualException( std::string expected, + std::string actual, + long lineNumber, + std::string fileName ) : + Exception( "Expected: " + expected + ", but was: " + actual, + lineNumber, + fileName ), + m_expected( expected ), + m_actual( actual ) +{ +} +#endif + + +NotEqualException::NotEqualException( const NotEqualException &other ) : + Exception( other ), + m_expected( other.m_expected ), + m_actual( other.m_actual ), + m_additionalMessage( other.m_additionalMessage ) +{ +} + + +NotEqualException::~NotEqualException() throw() +{ +} + + +NotEqualException & +NotEqualException::operator =( const NotEqualException &other ) +{ + Exception::operator =( other ); + + if ( &other != this ) + { + m_expected = other.m_expected; + m_actual = other.m_actual; + m_additionalMessage = other.m_additionalMessage; + } + return *this; +} + + +Exception * +NotEqualException::clone() const +{ + return new NotEqualException( *this ); +} + + +bool +NotEqualException::isInstanceOf( const Type &exceptionType ) const +{ + return exceptionType == type() || + Exception::isInstanceOf( exceptionType ); +} + + +Exception::Type +NotEqualException::type() +{ + return Type( "CppUnit::NotEqualException" ); +} + + +std::string +NotEqualException::expectedValue() const +{ + return m_expected; +} + + +std::string +NotEqualException::actualValue() const +{ + return m_actual; +} + + +std::string +NotEqualException::additionalMessage() const +{ + return m_additionalMessage; +} + + +} // namespace CppUnit diff --git a/src/tools/cppunit/cppunit/RepeatedTest.cpp b/src/tools/cppunit/cppunit/RepeatedTest.cpp new file mode 100644 index 0000000000..bfe1f72510 --- /dev/null +++ b/src/tools/cppunit/cppunit/RepeatedTest.cpp @@ -0,0 +1,37 @@ +#include +#include + +namespace CppUnit { + + + +// Counts the number of test cases that will be run by this test. +int +RepeatedTest::countTestCases() const +{ + return TestDecorator::countTestCases () * m_timesRepeat; +} + + +// Returns the name of the test instance. +std::string +RepeatedTest::toString() const +{ + return TestDecorator::toString () + " (repeated)"; +} + +// Runs a repeated test +void +RepeatedTest::run( TestResult *result ) +{ + for ( int n = 0; n < m_timesRepeat; n++ ) + { + if ( result->shouldStop() ) + break; + + TestDecorator::run( result ); + } +} + + +} // namespace TestAssert diff --git a/src/tools/cppunit/cppunit/SourceLine.cpp b/src/tools/cppunit/cppunit/SourceLine.cpp new file mode 100644 index 0000000000..feb356e7cb --- /dev/null +++ b/src/tools/cppunit/cppunit/SourceLine.cpp @@ -0,0 +1,62 @@ +#include + + +namespace CppUnit +{ + +SourceLine::SourceLine() : + m_lineNumber( -1 ) +{ +} + + +SourceLine::SourceLine( const std::string &fileName, + int lineNumber ) : + m_fileName( fileName ), + m_lineNumber( lineNumber ) +{ +} + + +SourceLine::~SourceLine() +{ +} + + +bool +SourceLine::isValid() const +{ + return !m_fileName.empty(); +} + + +int +SourceLine::lineNumber() const +{ + return m_lineNumber; +} + + +std::string +SourceLine::fileName() const +{ + return m_fileName; +} + + +bool +SourceLine::operator ==( const SourceLine &other ) const +{ + return m_fileName == other.m_fileName && + m_lineNumber == other.m_lineNumber; +} + + +bool +SourceLine::operator !=( const SourceLine &other ) const +{ + return !( *this == other ); +} + + +} // namespace CppUnit diff --git a/src/tools/cppunit/cppunit/SynchronizedObject.cpp b/src/tools/cppunit/cppunit/SynchronizedObject.cpp new file mode 100644 index 0000000000..c4e9c5010a --- /dev/null +++ b/src/tools/cppunit/cppunit/SynchronizedObject.cpp @@ -0,0 +1,35 @@ +#include + + +namespace CppUnit +{ + + + + +SynchronizedObject::SynchronizedObject( SynchronizationObject *syncObject ) + : m_syncObject( syncObject == 0 ? new SynchronizationObject() : + syncObject ) +{ +} + + +SynchronizedObject::~SynchronizedObject() +{ + delete m_syncObject; +} + + +/** Accept a new synchronization object for protection of this instance + * TestResult assumes ownership of the object + */ +void +SynchronizedObject::setSynchronizationObject( SynchronizationObject *syncObject ) +{ + delete m_syncObject; + m_syncObject = syncObject; +} + + +} // namespace CppUnit + diff --git a/src/tools/cppunit/cppunit/TestAssert.cpp b/src/tools/cppunit/cppunit/TestAssert.cpp new file mode 100644 index 0000000000..b5999e1ec8 --- /dev/null +++ b/src/tools/cppunit/cppunit/TestAssert.cpp @@ -0,0 +1,74 @@ +#if HAVE_CMATH +# include +#else +# include +#endif + +#include +#include + + +namespace CppUnit { + + +#ifdef CPPUNIT_ENABLE_SOURCELINE_DEPRECATED +/// Check for a failed general assertion +void +TestAssert::assertImplementation( bool condition, + std::string conditionExpression, + long lineNumber, + std::string fileName ) +{ + Asserter::failIf( condition, + conditionExpression, + SourceLine( fileName, lineNumber ) ); +} + + +/// Reports failed equality +void +TestAssert::assertNotEqualImplementation( std::string expected, + std::string actual, + long lineNumber, + std::string fileName ) +{ + Asserter::failNotEqual( expected, + actual, + SouceLine( fileName, lineNumber ), "" ); +} + + +/// Check for a failed equality assertion +void +TestAssert::assertEquals( double expected, + double actual, + double delta, + long lineNumber, + std::string fileName ) +{ + if (fabs (expected - actual) > delta) + assertNotEqualImplementation( assertion_traits::toString(expected), + assertion_traits::toString(actual), + lineNumber, + fileName ); +} + +#else // CPPUNIT_ENABLE_SOURCELINE_DEPRECATED + +void +TestAssert::assertDoubleEquals( double expected, + double actual, + double delta, + SourceLine sourceLine ) +{ + Asserter::failNotEqualIf( fabs( expected - actual ) > delta, + assertion_traits::toString(expected), + assertion_traits::toString(actual), + sourceLine ); +} + + +#endif + + +} diff --git a/src/tools/cppunit/cppunit/TestCase.cpp b/src/tools/cppunit/cppunit/TestCase.cpp new file mode 100644 index 0000000000..b2edb90a75 --- /dev/null +++ b/src/tools/cppunit/cppunit/TestCase.cpp @@ -0,0 +1,135 @@ +#include +#include +#include + +#include "cppunit/TestCase.h" +#include "cppunit/Exception.h" +#include "cppunit/TestResult.h" + + +namespace CppUnit { + +/// Create a default TestResult +CppUnit::TestResult* +TestCase::defaultResult() +{ + return new TestResult; +} + + +/// Run the test and catch any exceptions that are triggered by it +void +TestCase::run( TestResult *result ) +{ + result->startTest(this); + + try { + setUp(); + + try { + runTest(); + } + catch ( Exception &e ) { + Exception *copy = e.clone(); + result->addFailure( this, copy ); + } + catch ( std::exception &e ) { + result->addError( this, new Exception( e.what() ) ); + } + catch (...) { + Exception *e = new Exception( "caught unknown exception" ); + result->addError( this, e ); + } + + try { + tearDown(); + } + catch (...) { + result->addError( this, new Exception( "tearDown() failed" ) ); + } + } + catch (...) { + result->addError( this, new Exception( "setUp() failed" ) ); + } + + result->endTest( this ); +} + + +/// A default run method +TestResult * +TestCase::run() +{ + TestResult *result = defaultResult(); + + run (result); + return result; +} + + +/// All the work for runTest is deferred to subclasses +void +TestCase::runTest() +{ +} + + +/** Constructs a test case. + * \param name the name of the TestCase. + **/ +TestCase::TestCase( std::string name ) + : m_name(name) +{ +} + + +/** Constructs a test case for a suite. + * This TestCase is intended for use by the TestCaller and should not + * be used by a test case for which run() is called. + **/ +TestCase::TestCase() + : m_name( "" ) +{ +} + + +/// Destructs a test case +TestCase::~TestCase() +{ +} + + +/// Returns a count of all the tests executed +int +TestCase::countTestCases() const +{ + return 1; +} + + +/// Returns the name of the test case +std::string +TestCase::getName() const +{ + return m_name; +} + + +/// Returns the name of the test case instance +std::string +TestCase::toString() const +{ + std::string className; + +#if CPPUNIT_USE_TYPEINFO_NAME + const std::type_info& thisClass = typeid( *this ); + className = thisClass.name(); +#else + className = "TestCase"; +#endif + + return className + "." + getName(); +} + + +} // namespace CppUnit diff --git a/src/tools/cppunit/cppunit/TestFactoryRegistry.cpp b/src/tools/cppunit/cppunit/TestFactoryRegistry.cpp new file mode 100644 index 0000000000..d46ff29b6c --- /dev/null +++ b/src/tools/cppunit/cppunit/TestFactoryRegistry.cpp @@ -0,0 +1,176 @@ +#include +#include +#include + + +#if CPPUNIT_USE_TYPEINFO_NAME +# include "cppunit/extensions/TypeInfoHelper.h" +#endif + + +namespace CppUnit { + +/** (Implementation) This class manages all the TestFactoryRegistry. + * + * Responsible for the life-cycle of the TestFactoryRegistry. + * + * TestFactory registry must call wasDestroyed() to indicate that + * a given TestRegistry was destroyed, and needDestroy() to + * know if a given TestFactory need to be destroyed (was not already + * destroyed by another TestFactoryRegistry). + */ +class NamedRegistries +{ +public: + ~NamedRegistries(); + + static NamedRegistries &getInstance(); + + TestFactoryRegistry &getRegistry( std::string name ); + + void wasDestroyed( TestFactory *factory ); + + bool needDestroy( TestFactory *factory ); + +private: + typedef std::map Registries; + Registries m_registries; + + typedef std::set Factories; + Factories m_factoriesToDestroy; + Factories m_destroyedFactories; +}; + + +NamedRegistries::~NamedRegistries() +{ + Registries::iterator it = m_registries.begin(); + while ( it != m_registries.end() ) + { + TestFactoryRegistry *registry = (it++)->second; + if ( needDestroy( registry ) ) + delete registry; + } +} + + +NamedRegistries & +NamedRegistries::getInstance() +{ + static NamedRegistries namedRegistries; + return namedRegistries; +} + + +TestFactoryRegistry & +NamedRegistries::getRegistry( std::string name ) +{ + Registries::const_iterator foundIt = m_registries.find( name ); + if ( foundIt == m_registries.end() ) + { + TestFactoryRegistry *factory = new TestFactoryRegistry( name ); + m_registries.insert( std::make_pair( name, factory ) ); + m_factoriesToDestroy.insert( factory ); + return *factory; + } + return *foundIt->second; +} + + +void +NamedRegistries::wasDestroyed( TestFactory *factory ) +{ + m_factoriesToDestroy.erase( factory ); + m_destroyedFactories.insert( factory ); +} + + +bool +NamedRegistries::needDestroy( TestFactory *factory ) +{ + return m_destroyedFactories.count( factory ) == 0; +} + + + +TestFactoryRegistry::TestFactoryRegistry( std::string name ) : + m_name( name ) +{ +} + + +TestFactoryRegistry::~TestFactoryRegistry() +{ + // The wasDestroyed() and needDestroy() is used to prevent + // a double destruction of a factory registry. + // registerFactory( "All Tests", getRegistry( "Unit Tests" ) ); + // => the TestFactoryRegistry "Unit Tests" is owned by both + // the "All Tests" registry and the NamedRegistries... + NamedRegistries::getInstance().wasDestroyed( this ); + + for ( Factories::iterator it = m_factories.begin(); it != m_factories.end(); ++it ) + { + TestFactory *factory = it->second; + if ( NamedRegistries::getInstance().needDestroy( factory ) ) + delete factory; + } +} + + +TestFactoryRegistry & +TestFactoryRegistry::getRegistry() +{ + return getRegistry( "All Tests" ); +} + + +TestFactoryRegistry & +TestFactoryRegistry::getRegistry( const std::string &name ) +{ + return NamedRegistries::getInstance().getRegistry( name ); +} + + +void +TestFactoryRegistry::registerFactory( const std::string &name, + TestFactory *factory ) +{ + m_factories[name] = factory; +} + + +void +TestFactoryRegistry::registerFactory( TestFactory *factory ) +{ + static int serialNumber = 1; + + OStringStream ost; + ost << "@Dummy@" << serialNumber++; + + registerFactory( ost.str(), factory ); +} + + +Test * +TestFactoryRegistry::makeTest() +{ + TestSuite *suite = new TestSuite( m_name ); + addTestToSuite( suite ); + return suite; +} + + +void +TestFactoryRegistry::addTestToSuite( TestSuite *suite ) +{ + for ( Factories::iterator it = m_factories.begin(); + it != m_factories.end(); + ++it ) + { + TestFactory *factory = (*it).second; + suite->addTest( factory->makeTest() ); + } +} + + +} // namespace CppUnit diff --git a/src/tools/cppunit/cppunit/TestFailure.cpp b/src/tools/cppunit/cppunit/TestFailure.cpp new file mode 100644 index 0000000000..84044271d4 --- /dev/null +++ b/src/tools/cppunit/cppunit/TestFailure.cpp @@ -0,0 +1,77 @@ +#include "cppunit/Exception.h" +#include "cppunit/Test.h" +#include "cppunit/TestFailure.h" + +namespace CppUnit { + +/// Constructs a TestFailure with the given test and exception. +TestFailure::TestFailure( Test *failedTest, + Exception *thrownException, + bool isError ) : + m_failedTest( failedTest ), + m_thrownException( thrownException ), + m_isError( isError ) +{ +} + +/// Deletes the owned exception. +TestFailure::~TestFailure() +{ + delete m_thrownException; +} + +/// Gets the failed test. +Test * +TestFailure::failedTest() const +{ + return m_failedTest; +} + + +/// Gets the thrown exception. Never \c NULL. +Exception * +TestFailure::thrownException() const +{ + return m_thrownException; +} + + +/// Gets the failure location. +SourceLine +TestFailure::sourceLine() const +{ + return m_thrownException->sourceLine(); +} + + +/// Indicates if the failure is a failed assertion or an error. +bool +TestFailure::isError() const +{ + return m_isError; +} + + +/// Gets the name of the failed test. +std::string +TestFailure::failedTestName() const +{ + return m_failedTest->getName(); +} + + +/// Returns a short description of the failure. +std::string +TestFailure::toString() const +{ + return m_failedTest->toString() + ": " + m_thrownException->what(); +} + + +TestFailure * +TestFailure::clone() const +{ + return new TestFailure( m_failedTest, m_thrownException->clone(), m_isError ); +} + +} // namespace CppUnit diff --git a/src/tools/cppunit/cppunit/TestResult.cpp b/src/tools/cppunit/cppunit/TestResult.cpp new file mode 100644 index 0000000000..d5644a49f4 --- /dev/null +++ b/src/tools/cppunit/cppunit/TestResult.cpp @@ -0,0 +1,129 @@ +#include +#include +#include +#include + +namespace CppUnit { + +/// Construct a TestResult +TestResult::TestResult( SynchronizationObject *syncObject ) + : SynchronizedObject( syncObject ) +{ + reset(); +} + + +/// Destroys a test result +TestResult::~TestResult() +{ +} + + +/** Resets the result for a new run. + * + * Clear the previous run result. + */ +void +TestResult::reset() +{ + ExclusiveZone zone( m_syncObject ); + m_stop = false; +} + + +/** Adds an error to the list of errors. + * The passed in exception + * caused the error + */ +void +TestResult::addError( Test *test, + Exception *e ) +{ + addFailure( TestFailure( test, e, true ) ); +} + + +/** Adds a failure to the list of failures. The passed in exception + * caused the failure. + */ +void +TestResult::addFailure( Test *test, Exception *e ) +{ + addFailure( TestFailure( test, e, false ) ); +} + + +/** Called to add a failure to the list of failures. + */ +void +TestResult::addFailure( const TestFailure &failure ) +{ + ExclusiveZone zone( m_syncObject ); + for ( TestListeners::iterator it = m_listeners.begin(); + it != m_listeners.end(); + ++it ) + (*it)->addFailure( failure ); +} + + +/// Informs the result that a test will be started. +void +TestResult::startTest( Test *test ) +{ + ExclusiveZone zone( m_syncObject ); + for ( TestListeners::iterator it = m_listeners.begin(); + it != m_listeners.end(); + ++it ) + (*it)->startTest( test ); +} + + +/// Informs the result that a test was completed. +void +TestResult::endTest( Test *test ) +{ + ExclusiveZone zone( m_syncObject ); + for ( TestListeners::iterator it = m_listeners.begin(); + it != m_listeners.end(); + ++it ) + (*it)->endTest( test ); +} + + +/// Returns whether testing should be stopped +bool +TestResult::shouldStop() const +{ + ExclusiveZone zone( m_syncObject ); + return m_stop; +} + + +/// Stop testing +void +TestResult::stop() +{ + ExclusiveZone zone( m_syncObject ); + m_stop = true; +} + + +void +TestResult::addListener( TestListener *listener ) +{ + ExclusiveZone zone( m_syncObject ); + m_listeners.push_back( listener ); +} + + +void +TestResult::removeListener ( TestListener *listener ) +{ + ExclusiveZone zone( m_syncObject ); + m_listeners.erase( std::remove( m_listeners.begin(), + m_listeners.end(), + listener ), + m_listeners.end()); +} + +} // namespace CppUnit diff --git a/src/tools/cppunit/cppunit/TestResultCollector.cpp b/src/tools/cppunit/cppunit/TestResultCollector.cpp new file mode 100644 index 0000000000..796ffc3131 --- /dev/null +++ b/src/tools/cppunit/cppunit/TestResultCollector.cpp @@ -0,0 +1,110 @@ +#include +#include + + +namespace CppUnit +{ + + +TestResultCollector::TestResultCollector( SynchronizationObject *syncObject ) + : TestSucessListener( syncObject ) +{ + reset(); +} + + +TestResultCollector::~TestResultCollector() +{ + TestFailures::iterator itFailure = m_failures.begin(); + while ( itFailure != m_failures.end() ) + delete *itFailure++; +} + + +void +TestResultCollector::reset() +{ + TestSucessListener::reset(); + + ExclusiveZone zone( m_syncObject ); + m_testErrors = 0; + m_tests.clear(); + m_failures.clear(); +} + + +void +TestResultCollector::startTest( Test *test ) +{ + ExclusiveZone zone (m_syncObject); + m_tests.push_back( test ); +} + + +void +TestResultCollector::addFailure( const TestFailure &failure ) +{ + TestSucessListener::addFailure( failure ); + + ExclusiveZone zone( m_syncObject ); + if ( failure.isError() ) + ++m_testErrors; + m_failures.push_back( failure.clone() ); +} + + +/// Gets the number of run tests. +int +TestResultCollector::runTests() const +{ + ExclusiveZone zone( m_syncObject ); + return m_tests.size(); +} + + +/// Gets the number of detected errors (uncaught exception). +int +TestResultCollector::testErrors() const +{ + ExclusiveZone zone( m_syncObject ); + return m_testErrors; +} + + +/// Gets the number of detected failures (failed assertion). +int +TestResultCollector::testFailures() const +{ + ExclusiveZone zone( m_syncObject ); + return m_failures.size() - m_testErrors; +} + + +/// Gets the total number of detected failures. +int +TestResultCollector::testFailuresTotal() const +{ + ExclusiveZone zone( m_syncObject ); + return m_failures.size(); +} + + +/// Returns a the list failures (random access collection). +const TestResultCollector::TestFailures & +TestResultCollector::failures() const +{ + ExclusiveZone zone( m_syncObject ); + return m_failures; +} + + +const TestResultCollector::Tests & +TestResultCollector::tests() const +{ + ExclusiveZone zone( m_syncObject ); + return m_tests; +} + + +} // namespace CppUnit + diff --git a/src/tools/cppunit/cppunit/TestRunner.cpp b/src/tools/cppunit/cppunit/TestRunner.cpp new file mode 100644 index 0000000000..44c11d979d --- /dev/null +++ b/src/tools/cppunit/cppunit/TestRunner.cpp @@ -0,0 +1,179 @@ +#include +#include +#include +#include +#include +#include +#include + + +namespace CppUnit { +namespace TextUi { + +/*! Constructs a new text runner. + * \param outputter used to print text result. Owned by the runner. + */ +TestRunner::TestRunner( Outputter *outputter ) + : m_outputter( outputter ) + , m_suite( new TestSuite( "All Tests" ) ) + , m_result( new TestResultCollector() ) + , m_eventManager( new TestResult() ) +{ + if ( !m_outputter ) + m_outputter = new TextOutputter( m_result, std::cout ); + m_eventManager->addListener( m_result ); +} + + +TestRunner::~TestRunner() +{ + delete m_eventManager; + delete m_outputter; + delete m_result; + delete m_suite; +} + + +/*! Adds the specified test. + * + * \param test Test to add. + */ +void +TestRunner::addTest( Test *test ) +{ + if ( test != NULL ) + m_suite->addTest( test ); +} + + +/*! Runs the named test case. + * + * \param testName Name of the test case to run. If an empty is given, then + * all added test are run. The name must be the name of + * of an added test. + * \param doWait if \c true then the user must press the RETURN key + * before the run() method exit. + * \param doPrintResult if \c true (default) then the test result are printed + * on the standard output. + * \param doPrintProgress if \c true (default) then TextTestProgressListener is + * used to show the progress. + * \return \c true is the test was successful, \c false if the test + * failed or was not found. + */ +bool +TestRunner::run( std::string testName, + bool doWait, + bool doPrintResult, + bool doPrintProgress ) +{ + runTestByName( testName, doPrintProgress ); + printResult( doPrintResult ); + wait( doWait ); + return m_result->wasSuccessful(); +} + + +bool +TestRunner::runTestByName( std::string testName, + bool doPrintProgress ) +{ + if ( testName.empty() ) + return runTest( m_suite, doPrintProgress ); + + Test *test = findTestByName( testName ); + if ( test != NULL ) + return runTest( test, doPrintProgress ); + + std::cout << "Test " << testName << " not found." << std::endl; + return false; +} + + +void +TestRunner::wait( bool doWait ) +{ + if ( doWait ) + { + std::cout << " to continue" << std::endl; + std::cin.get (); + } +} + + +void +TestRunner::printResult( bool doPrintResult ) +{ + std::cout << std::endl; + if ( doPrintResult ) + m_outputter->write(); +} + + +Test * +TestRunner::findTestByName( std::string name ) const +{ + for ( std::vector::const_iterator it = m_suite->getTests().begin(); + it != m_suite->getTests().end(); + ++it ) + { + Test *test = *it; + if ( test->getName() == name ) + return test; + } + return NULL; +} + + +bool +TestRunner::runTest( Test *test, + bool doPrintProgress ) +{ + TextTestProgressListener progress; + if ( doPrintProgress ) + m_eventManager->addListener( &progress ); + + test->run( m_eventManager ); + + if ( doPrintProgress ) + m_eventManager->removeListener( &progress ); + return m_result->wasSuccessful(); +} + + +/*! Returns the result of the test run. + * Use this after calling run() to access the result of the test run. + */ +TestResultCollector & +TestRunner::result() const +{ + return *m_result; +} + + +/*! Returns the event manager. + * The instance of TestResult results returned is the one that is used to run the + * test. Use this to register additional TestListener before running the tests. + */ +TestResult & +TestRunner::eventManager() const +{ + return *m_eventManager; +} + + +/*! Specifies an alternate outputter. + * + * Notes that the outputter will be use after the test run only if \a printResult was + * \c true. + * \see CompilerOutputter, XmlOutputter, TextOutputter. + */ +void +TestRunner::setOutputter( Outputter *outputter ) +{ + delete m_outputter; + m_outputter = outputter; +} + + +} // namespace TextUi +} // namespace CppUnit diff --git a/src/tools/cppunit/cppunit/TestSetUp.cpp b/src/tools/cppunit/cppunit/TestSetUp.cpp new file mode 100644 index 0000000000..a55339cee7 --- /dev/null +++ b/src/tools/cppunit/cppunit/TestSetUp.cpp @@ -0,0 +1,31 @@ +#include + +namespace CppUnit { + +TestSetUp::TestSetUp( Test *test ) : TestDecorator( test ) +{ +} + + +void +TestSetUp::setUp() +{ +} + + +void +TestSetUp::tearDown() +{ +} + + +void +TestSetUp::run( TestResult *result ) +{ + setUp(); + TestDecorator::run(result); + tearDown(); +} + + +} // namespace CppUnit diff --git a/src/tools/cppunit/cppunit/TestSucessListener.cpp b/src/tools/cppunit/cppunit/TestSucessListener.cpp new file mode 100644 index 0000000000..7271c6b149 --- /dev/null +++ b/src/tools/cppunit/cppunit/TestSucessListener.cpp @@ -0,0 +1,46 @@ +#include + + + +namespace CppUnit +{ + + +TestSucessListener::TestSucessListener( SynchronizationObject *syncObject ) + : SynchronizedObject( syncObject ) + , m_sucess( true ) +{ +} + + +TestSucessListener::~TestSucessListener() +{ +} + + +void +TestSucessListener::reset() +{ + ExclusiveZone zone( m_syncObject ); + m_sucess = true; +} + + +void +TestSucessListener::addFailure( const TestFailure &failure ) +{ + ExclusiveZone zone( m_syncObject ); + m_sucess = false; +} + + +bool +TestSucessListener::wasSuccessful() const +{ + ExclusiveZone zone( m_syncObject ); + return m_sucess; +} + + +} // namespace CppUnit + diff --git a/src/tools/cppunit/cppunit/TestSuite.cpp b/src/tools/cppunit/cppunit/TestSuite.cpp new file mode 100644 index 0000000000..7659939d2d --- /dev/null +++ b/src/tools/cppunit/cppunit/TestSuite.cpp @@ -0,0 +1,96 @@ +#include "cppunit/TestSuite.h" +#include "cppunit/TestResult.h" + +namespace CppUnit { + +/// Default constructor +TestSuite::TestSuite( std::string name ) + : m_name( name ) +{ +} + + +/// Destructor +TestSuite::~TestSuite() +{ + deleteContents(); +} + + +/// Deletes all tests in the suite. +void +TestSuite::deleteContents() +{ + for ( std::vector::iterator it = m_tests.begin(); + it != m_tests.end(); + ++it) + delete *it; + m_tests.clear(); +} + + +/// Runs the tests and collects their result in a TestResult. +void +TestSuite::run( TestResult *result ) +{ + for ( std::vector::iterator it = m_tests.begin(); + it != m_tests.end(); + ++it ) + { + if ( result->shouldStop() ) + break; + + Test *test = *it; + test->run( result ); + } +} + + +/// Counts the number of test cases that will be run by this test. +int +TestSuite::countTestCases() const +{ + int count = 0; + + for ( std::vector::const_iterator it = m_tests.begin(); + it != m_tests.end(); + ++it ) + count += (*it)->countTestCases(); + + return count; +} + + +/// Adds a test to the suite. +void +TestSuite::addTest( Test *test ) +{ + m_tests.push_back( test ); +} + + +/// Returns a string representation of the test suite. +std::string +TestSuite::toString() const +{ + return "suite " + getName(); +} + + +/// Returns the name of the test suite. +std::string +TestSuite::getName() const +{ + return m_name; +} + + +const std::vector & +TestSuite::getTests() const +{ + return m_tests; +} + + +} // namespace CppUnit + diff --git a/src/tools/cppunit/cppunit/TextOutputter.cpp b/src/tools/cppunit/cppunit/TextOutputter.cpp new file mode 100644 index 0000000000..fc32598ffc --- /dev/null +++ b/src/tools/cppunit/cppunit/TextOutputter.cpp @@ -0,0 +1,156 @@ +#include +#include +#include +#include +#include + + +namespace CppUnit +{ + + +TextOutputter::TextOutputter( TestResultCollector *result, + std::ostream &stream ) + : m_result( result ) + , m_stream( stream ) +{ +} + + +TextOutputter::~TextOutputter() +{ +} + + +void +TextOutputter::write() +{ + printHeader(); + m_stream << std::endl; + printFailures(); + m_stream << std::endl; +} + + +void +TextOutputter::printFailures() +{ + TestResultCollector::TestFailures::const_iterator itFailure = m_result->failures().begin(); + int failureNumber = 1; + while ( itFailure != m_result->failures().end() ) + { + m_stream << std::endl; + printFailure( *itFailure++, failureNumber++ ); + } +} + + +void +TextOutputter::printFailure( TestFailure *failure, + int failureNumber ) +{ + printFailureListMark( failureNumber ); + m_stream << ' '; + printFailureTestName( failure ); + m_stream << ' '; + printFailureType( failure ); + m_stream << ' '; + printFailureLocation( failure->sourceLine() ); + m_stream << std::endl; + printFailureDetail( failure->thrownException() ); + m_stream << std::endl; +} + + +void +TextOutputter::printFailureListMark( int failureNumber ) +{ + m_stream << failureNumber << ")"; +} + + +void +TextOutputter::printFailureTestName( TestFailure *failure ) +{ + m_stream << "test: " << failure->failedTestName(); +} + + +void +TextOutputter::printFailureType( TestFailure *failure ) +{ + m_stream << "(" + << (failure->isError() ? "E" : "F") + << ")"; +} + + +void +TextOutputter::printFailureLocation( SourceLine sourceLine ) +{ + if ( !sourceLine.isValid() ) + return; + + m_stream << "line: " << sourceLine.lineNumber() + << ' ' << sourceLine.fileName(); +} + + +void +TextOutputter::printFailureDetail( Exception *thrownException ) +{ + if ( thrownException->isInstanceOf( NotEqualException::type() ) ) + { + NotEqualException *e = (NotEqualException*)thrownException; + m_stream << "expected: " << e->expectedValue() << std::endl + << "but was: " << e->actualValue(); + if ( !e->additionalMessage().empty() ) + { + m_stream << std::endl; + m_stream << "additional message:" << std::endl + << e->additionalMessage(); + } + } + else + { + m_stream << " \"" << thrownException->what() << "\""; + } +} + + +void +TextOutputter::printHeader() +{ + if ( m_result->wasSuccessful() ) + m_stream << std::endl << "OK (" << m_result->runTests () << " tests)" + << std::endl; + else + { + m_stream << std::endl; + printFailureWarning(); + printStatistics(); + } +} + + +void +TextOutputter::printFailureWarning() +{ + m_stream << "!!!FAILURES!!!" << std::endl; +} + + +void +TextOutputter::printStatistics() +{ + m_stream << "Test Results:" << std::endl; + + m_stream << "Run: " << m_result->runTests() + << " Failures: " << m_result->testFailures() + << " Errors: " << m_result->testErrors() + << std::endl; +} + + +} // namespace CppUnit + diff --git a/src/tools/cppunit/cppunit/TextTestProgressListener.cpp b/src/tools/cppunit/cppunit/TextTestProgressListener.cpp new file mode 100644 index 0000000000..bd86ddf59d --- /dev/null +++ b/src/tools/cppunit/cppunit/TextTestProgressListener.cpp @@ -0,0 +1,44 @@ +#include +#include +#include + + +namespace CppUnit +{ + + +TextTestProgressListener::TextTestProgressListener() +{ +} + + +TextTestProgressListener::~TextTestProgressListener() +{ +} + + +void +TextTestProgressListener::startTest( Test *test ) +{ + std::cerr << "."; + std::cerr.flush(); +} + + +void +TextTestProgressListener::addFailure( const TestFailure &failure ) +{ + std::cerr << ( failure.isError() ? "E" : "F" ); + std::cerr.flush(); +} + + +void +TextTestProgressListener::done() +{ + std::cerr << std::endl; + std::cerr.flush(); +} + +} // namespace CppUnit + diff --git a/src/tools/cppunit/cppunit/TextTestResult.cpp b/src/tools/cppunit/cppunit/TextTestResult.cpp new file mode 100644 index 0000000000..a8483b72b8 --- /dev/null +++ b/src/tools/cppunit/cppunit/TextTestResult.cpp @@ -0,0 +1,177 @@ +#include +#include +#include +#include +#include +#include + + +namespace CppUnit { + + +TextTestResult::TextTestResult() +{ + addListener( this ); +} + + +void +TextTestResult::addFailure( const TestFailure &failure ) +{ + TestResultCollector::addFailure( failure ); + std::cerr << ( failure.isError() ? "E" : "F" ); +} + + +void +TextTestResult::startTest( Test *test ) +{ + TestResultCollector::startTest (test); + std::cerr << "."; +} + + +void +TextTestResult::printFailures( std::ostream &stream ) +{ + TestFailures::const_iterator itFailure = failures().begin(); + int failureNumber = 1; + while ( itFailure != failures().end() ) + { + stream << std::endl; + printFailure( *itFailure++, failureNumber++, stream ); + } +} + + +void +TextTestResult::printFailure( TestFailure *failure, + int failureNumber, + std::ostream &stream ) +{ + printFailureListMark( failureNumber, stream ); + stream << ' '; + printFailureTestName( failure, stream ); + stream << ' '; + printFailureType( failure, stream ); + stream << ' '; + printFailureLocation( failure->sourceLine(), stream ); + stream << std::endl; + printFailureDetail( failure->thrownException(), stream ); + stream << std::endl; +} + + +void +TextTestResult::printFailureListMark( int failureNumber, + std::ostream &stream ) +{ + stream << failureNumber << ")"; +} + + +void +TextTestResult::printFailureTestName( TestFailure *failure, + std::ostream &stream ) +{ + stream << "test: " << failure->failedTest()->getName(); +} + + +void +TextTestResult::printFailureType( TestFailure *failure, + std::ostream &stream ) +{ + stream << "(" + << (failure->isError() ? "E" : "F") + << ")"; +} + + +void +TextTestResult::printFailureLocation( SourceLine sourceLine, + std::ostream &stream ) +{ + if ( !sourceLine.isValid() ) + return; + + stream << "line: " << sourceLine.lineNumber() + << ' ' << sourceLine.fileName(); +} + + +void +TextTestResult::printFailureDetail( Exception *thrownException, + std::ostream &stream ) +{ + if ( thrownException->isInstanceOf( NotEqualException::type() ) ) + { + NotEqualException *e = (NotEqualException*)thrownException; + stream << "expected: " << e->expectedValue() << std::endl + << "but was: " << e->actualValue(); + if ( !e->additionalMessage().empty() ) + { + stream << std::endl; + stream << "additional message:" << std::endl + << e->additionalMessage(); + } + } + else + { + stream << " \"" << thrownException->what() << "\""; + } +} + + +void +TextTestResult::print( std::ostream& stream ) +{ + printHeader( stream ); + stream << std::endl; + printFailures( stream ); +} + + +void +TextTestResult::printHeader( std::ostream &stream ) +{ + if (wasSuccessful ()) + stream << std::endl << "OK (" << runTests () << " tests)" + << std::endl; + else + { + stream << std::endl; + printFailureWarning( stream ); + printStatistics( stream ); + } +} + + +void +TextTestResult::printFailureWarning( std::ostream &stream ) +{ + stream << "!!!FAILURES!!!" << std::endl; +} + + +void +TextTestResult::printStatistics( std::ostream &stream ) +{ + stream << "Test Results:" << std::endl; + + stream << "Run: " << runTests() + << " Failures: " << testFailures() + << " Errors: " << testErrors() + << std::endl; +} + + +std::ostream & +operator <<( std::ostream &stream, + TextTestResult &result ) +{ + result.print (stream); return stream; +} + + +} // namespace CppUnit diff --git a/src/tools/cppunit/cppunit/TypeInfoHelper.cpp b/src/tools/cppunit/cppunit/TypeInfoHelper.cpp new file mode 100644 index 0000000000..cf0a8c1031 --- /dev/null +++ b/src/tools/cppunit/cppunit/TypeInfoHelper.cpp @@ -0,0 +1,30 @@ +#include + +#if CPPUNIT_USE_TYPEINFO_NAME + +#include +#include + + +namespace CppUnit { + +std::string +TypeInfoHelper::getClassName( const std::type_info &info ) +{ + static std::string classPrefix( "class " ); + std::string name( info.name() ); + + bool has_class_prefix = 0 == +#if CPPUNIT_FUNC_STRING_COMPARE_STRING_FIRST + name.compare( classPrefix, 0, classPrefix.length() ); +#else + name.compare( 0, classPrefix.length(), classPrefix ); +#endif + + return has_class_prefix ? name.substr( classPrefix.length() ) : name; +} + + +} // namespace CppUnit + +#endif diff --git a/src/tools/cppunit/cppunit/XmlOutputter.cpp b/src/tools/cppunit/cppunit/XmlOutputter.cpp new file mode 100644 index 0000000000..52ed281289 --- /dev/null +++ b/src/tools/cppunit/cppunit/XmlOutputter.cpp @@ -0,0 +1,315 @@ +#include +#include +#include +#include +#include +#include +#include + + +namespace CppUnit +{ + +// XmlOutputter::Node +// ////////////////////////////////////////////////////////////////// + + +XmlOutputter::Node::Node( std::string elementName, + std::string content ) : + m_name( elementName ), + m_content( content ) +{ +} + + +XmlOutputter::Node::Node( std::string elementName, + int numericContent ) : + m_name( elementName ) +{ + m_content = asString( numericContent ); +} + + +XmlOutputter::Node::~Node() +{ + Nodes::iterator itNode = m_nodes.begin(); + while ( itNode != m_nodes.end() ) + delete *itNode++; +} + + +void +XmlOutputter::Node::addAttribute( std::string attributeName, + std::string value ) +{ + m_attributes.push_back( Attribute( attributeName, value ) ); +} + + +void +XmlOutputter::Node::addAttribute( std::string attributeName, + int numericValue ) +{ + addAttribute( attributeName, asString( numericValue ) ); +} + + +void +XmlOutputter::Node::addNode( Node *node ) +{ + m_nodes.push_back( node ); +} + + +std::string +XmlOutputter::Node::toString() const +{ + std::string element = "<"; + element += m_name; + element += " "; + element += attributesAsString(); + element += " >\n"; + + Nodes::const_iterator itNode = m_nodes.begin(); + while ( itNode != m_nodes.end() ) + { + const Node *node = *itNode++; + element += node->toString(); + } + + element += m_content; + + element += "\n"; + + return element; +} + + +std::string +XmlOutputter::Node::attributesAsString() const +{ + std::string attributes; + Attributes::const_iterator itAttribute = m_attributes.begin(); + while ( itAttribute != m_attributes.end() ) + { + const Attribute &attribute = *itAttribute++; + attributes += attribute.first; + attributes += "=\""; + attributes += escape( attribute.second ); + attributes += "\""; + } + return attributes; +} + + +std::string +XmlOutputter::Node::escape( std::string value ) const +{ + std::string escaped; + for ( int index =0; index < value.length(); ++index ) + { + char c = value[index ]; + switch ( c ) // escape all predefined XML entity (safe?) + { + case '<': + escaped += "<"; + break; + case '>': + escaped += ">"; + break; + case '&': + escaped += "&"; + break; + case '\'': + escaped += "'"; + break; + case '"': + escaped += """; + break; + default: + escaped += c; + } + } + + return escaped; +} + +// should be somewhere else... Future CppUnit::String ? +std::string +XmlOutputter::Node::asString( int value ) +{ + OStringStream stream; + stream << value; + return stream.str(); +} + + + + +// XmlOutputter +// ////////////////////////////////////////////////////////////////// + +XmlOutputter::XmlOutputter( TestResultCollector *result, + std::ostream &stream, + std::string encoding ) : + m_result( result ), + m_stream( stream ), + m_encoding( encoding ) +{ +} + + +XmlOutputter::~XmlOutputter() +{ +} + + +void +XmlOutputter::write() +{ + writeProlog(); + writeTestsResult(); +} + + +void +XmlOutputter::writeProlog() +{ + m_stream << "" + << std::endl; +} + + +void +XmlOutputter::writeTestsResult() +{ + Node *rootNode = makeRootNode(); + m_stream << rootNode->toString(); + delete rootNode; +} + + +XmlOutputter::Node * +XmlOutputter::makeRootNode() +{ + Node *rootNode = new Node( "TestRun" ); + + FailedTests failedTests; + fillFailedTestsMap( failedTests ); + + addFailedTests( failedTests, rootNode ); + addSucessfulTests( failedTests, rootNode ); + addStatistics( rootNode ); + + return rootNode; +} + + +void +XmlOutputter::fillFailedTestsMap( FailedTests &failedTests ) +{ + const TestResultCollector::TestFailures &failures = m_result->failures(); + TestResultCollector::TestFailures::const_iterator itFailure = failures.begin(); + while ( itFailure != failures.end() ) + { + TestFailure *failure = *itFailure++; + failedTests.insert( std::make_pair(failure->failedTest(), failure ) ); + } +} + + +void +XmlOutputter::addFailedTests( FailedTests &failedTests, + Node *rootNode ) +{ + Node *testsNode = new Node( "FailedTests" ); + rootNode->addNode( testsNode ); + + const TestResultCollector::Tests &tests = m_result->tests(); + for ( int testNumber = 0; testNumber < tests.size(); ++testNumber ) + { + Test *test = tests[testNumber]; + if ( failedTests.find( test ) != failedTests.end() ) + addFailedTest( test, failedTests[test], testNumber+1, testsNode ); + } +} + + +void +XmlOutputter::addSucessfulTests( FailedTests &failedTests, + Node *rootNode ) +{ + Node *testsNode = new Node( "SucessfulTests" ); + rootNode->addNode( testsNode ); + + const TestResultCollector::Tests &tests = m_result->tests(); + for ( int testNumber = 0; testNumber < tests.size(); ++testNumber ) + { + Test *test = tests[testNumber]; + if ( failedTests.find( test ) == failedTests.end() ) + addSucessfulTest( test, testNumber+1, testsNode ); + } +} + + +void +XmlOutputter::addStatistics( Node *rootNode ) +{ + Node *statisticsNode = new Node( "Statistics" ); + rootNode->addNode( statisticsNode ); + statisticsNode->addNode( new Node( "Tests", m_result->runTests() ) ); + statisticsNode->addNode( new Node( "FailuresTotal", + m_result->testFailuresTotal() ) ); + statisticsNode->addNode( new Node( "Errors", m_result->testErrors() ) ); + statisticsNode->addNode( new Node( "Failures", m_result->testFailures() ) ); +} + + +void +XmlOutputter::addFailedTest( Test *test, + TestFailure *failure, + int testNumber, + Node *testsNode ) +{ + Exception *thrownException = failure->thrownException(); + + Node *testNode = new Node( "FailedTest", thrownException->what() ); + testsNode->addNode( testNode ); + testNode->addAttribute( "id", testNumber ); + testNode->addNode( new Node( "Name", test->getName() ) ); + testNode->addNode( new Node( "FailureType", + failure->isError() ? "Error" : "Assertion" ) ); + + if ( failure->sourceLine().isValid() ) + addFailureLocation( failure, testNode ); +} + + +void +XmlOutputter::addFailureLocation( TestFailure *failure, + Node *testNode ) +{ + Node *locationNode = new Node( "Location" ); + testNode->addNode( locationNode ); + SourceLine sourceLine = failure->sourceLine(); + locationNode->addNode( new Node( "File", sourceLine.fileName() ) ); + locationNode->addNode( new Node( "Line", sourceLine.lineNumber() ) ); +} + + +void +XmlOutputter::addSucessfulTest( Test *test, + int testNumber, + Node *testsNode ) +{ + Node *testNode = new Node( "Test" ); + testsNode->addNode( testNode ); + testNode->addAttribute( "id", testNumber ); + testNode->addNode( new Node( "Name", test->getName() ) ); +} + + +} // namespace CppUnit diff --git a/src/tools/hey/Jamfile b/src/tools/hey/Jamfile new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/tools/hey/hey.c b/src/tools/hey/hey.c new file mode 100644 index 0000000000..f87e0283cf --- /dev/null +++ b/src/tools/hey/hey.c @@ -0,0 +1,1339 @@ +// hey +// a small scripting utility +// written by Attila Mezei (attila.mezei@mail.datanet.hu) +// contributions by Sander Stoks, Peter Folk, Chris Herborth, Marco Nelissen, Scott Lindsey and others +// +// public domain, use it at your own risk +// +// 1.2.6: syntax extended by Sander Stoks to allow: +// "hey Application let Specifier do ..." +// allowing you to send messages directly to other handlers than the app itself. +// In cooperation with the new Application defined commands (note that some +// Be classes, e.g. BWindow, publish commands as well) this allows, for example: +// "hey NetPositive let Window 0 do MoveBy BPoint[10,10]" +// Note that this is partly redundant, since +// "hey NetPositive let Window 0 do get Title" +// duplicates "hey NetPositive get Title of Window 0" +// But with the old system, +// "hey NetPositive MoveBy of Window 0 with data=BPoint[10,10]" +// couldn't work ("MoveBy" is not defined by the Application itself). +// +// 1.2.5: value_info is supported in BPropertyInfo. This means when you send GETSUITES (B_GET_SUPPORTED_SUITES) +// the value info is printed after the property infos, like this: +// "messages" (B_PROPERTY_INFO_TYPE) : +// property commands specifiers +// -------------------------------------------------------------------------------- +// Suites B_GET_PROPERTY DIRECT +// Messenger B_GET_PROPERTY DIRECT +// InternalName B_GET_PROPERTY DIRECT +// +// name value kind +// -------------------------------------------------------------------------------- +// Backup 0x6261636B ('back') COMMAND +// Usage: This command backs up your hard drive. +// Abort 0x61626F72 ('abor') COMMAND +// Usage: Stops the current operation... +// Type Code 0x74797065 ('type') TYPE CODE +// Usage: Type code info... +// +// You can also use the application defined commands (as the verb) with hey: +// hey MyBackupApp Backup "Maui" +// +// 1.2.4: the syntax is extended by Peter Folk to contain: +// do the x of y -3 of z '"1"' +// I.e. "do" => B_EXECUTE_PROPERTY, optional "the" makes direct specifiers +// more like english, bare reverse-index-specifiers are now handled, and +// named specifiers can contain only digits by quoting it (but make sure the +// shell passed the quotes through). +// +// Hey(target,const char*,reply) was previously limited to 100 tokens. It +// now uses a vector<> so it's only limited by available memory. +// +// Also, the archive name is now Y2K compliant =) +// +// 1.2.3: new option: -s for silent processing (no reply or errors printed) AM +// +// 1.2.2: Fixes by Marco Nelissen (marcone@xs4all.nl) +// - fixed parsing of negative numbers +// - fixed "with" syntax, which was broken (after a create, "with" would be taken as a specifier) +// +// 1.2.1: compiled for x86, R4 with minor modifications at BPropertyInfo +// +// 1.2.0: the syntax is extended by Sander Stoks (sander@adamation.com) to contain +// with name= [and name= [...]] +// at the end of the command which will add additional data to the scripting message. E.g: +// hey Becasso create Canvas with name=MyCanvas and size=BRect(100,100,300,300) +// Also a small interpreter is included. +// +// Detailed printout of B_PROPERTY_INFO in BMessages. Better than BPropertyInfo::PrintToStream(). +// Also prints usage info for a property if defined. +// +// 1.1.1: minor change from chrish@qnx.com to return -1 if an error is +// sent back in the reply message; also added B_COUNT_PROPERTIES support +// +// The range specifier sent to the target was 1 greater than it should've been. Fixed. +// +// 'hey' made the assumption that the first thread in a team will be the +// application thread (and therefore have the application's name). +// This was not always the case. Fix from Scott Lindsey . +// +//v1.1.0: Flattened BPropertyInfo is printed if found in the reply of B_GET_SUPPORTED_SUITES +// 1,2,3 and 4 character message constant is supported (e.g. '1', '12', '123', '1234') +// Alpha is sent with rgb_color +// +//v1.0.0 First public release + + +#include "hey.h" +#include +#include +#include +#include +#include +#include + +const char VERSION[]="v1.2.6"; + +#define DEBUG_HEY 0 // 1: prints the script message to be sent to the target application, 0: prints only the reply + + +// test, these should be zero for normal operation +#define TEST_VALUEINFO 0 + + +// flag for silent mode +bool silent; + + +int main(int argc, char *argv[]) +{ + BApplication app("application/x-amezei-hey"); + + if (argc < 2) { + fprintf(stderr, "hey %s, written by Attila Mezei (attila.mezei@mail.datanet.hu)\n" \ + "usage: hey [-s] [let do] >* [to ] [with name= [and name=]*]\n" \ + "where : DO|GET|SET|COUNT|CREATE|DELETE|GETSUITES|QUIT|SAVE|LOAD|'what'\n" \ + " : [the] [ | name | \"name\" | '\"name\"' ]\n" \ + " : int | -int | '['int']' | '['-int']' | '['startint to end']'\n" \ + " : \"string\" | | | bool(value) | int8(value)\n" \ + " | int16(value) | int32(value) | float(value) | double(value)\n" \ + " | BPoint(x,y) | BRect(l,t,r,b) | rgb_color(r,g,b,a) | file(path)\n" \ + "options: -s: silent\n\n", VERSION); + // Updated Usage string to reflect "do", "the", bare -index, and '"name"' changes below + // -- pfolk@uni.uiuc.edu 1999-11-03 + + return -1; + } + + int32 argapp = 1; + silent=false; + + if(strcmp(argv[1], "-s")==0 || strcmp(argv[1], "-S")==0){ + silent=true; + argapp++; + } + + // find the application + BMessenger the_application; + BList team_list; + team_id teamid; + app_info appinfo; + + be_roster->GetAppList(&team_list); + for(int32 i=0;iGetRunningAppInfo(teamid, &appinfo); + if(strcmp(appinfo.signature, argv[argapp])==0){ + the_application=BMessenger(appinfo.signature); + break; + }else{ + if(strcmp(appinfo.ref.name, argv[argapp])==0){ + the_application=BMessenger(0, teamid); + break; + } + } + } + + if(!the_application.IsValid()){ + if(!silent) fprintf(stderr, "Cannot find the application (%s)\n", argv[argapp]); + return -1; + } + + if (argc < 3) { + if(!silent) fprintf(stderr, "Cannot find the verb!\n"); + return -1; + } + + + BMessage the_reply; + int32 argx = argapp+1; +// const char *test_string = "set File of Window Sample to file(/boot/home/media/images/BeLogo.psd)"; +// status_t err = Hey(&the_application, test_string, &the_reply); + status_t err = Hey(&the_application, argv, &argx, argc, &the_reply); + + if (err!=B_OK) { + if(!silent) fprintf(stderr, "Error when sending message to %s!\n", argv[argapp]); + return -1; + } else { + if(the_reply.what==(uint32)B_MESSAGE_NOT_UNDERSTOOD || the_reply.what==(uint32)B_ERROR){ // I do it myself + if(the_reply.HasString("message")){ + if(!silent) printf("%s (error 0x%8lX)\n", the_reply.FindString("message"), the_reply.FindInt32("error")); + }else{ + if(!silent) printf("error 0x%8lX\n", the_reply.FindInt32("error")); + } + }else{ + if(!silent){ + printf("Reply "); + print_message(&the_reply); + printf("\n"); + } + } + } + + return 0; +} + + +int32 HeyInterpreterThreadHook(void* arg) +{ + if (arg) { + BMessage environment(*(BMessage*) arg); + char* prompt = "Hey"; + if (environment.HasString("prompt")) environment.FindString("prompt", (const char **)&prompt); + printf("%s> ", prompt); + + BMessenger target; + if (environment.HasMessenger("Target")) environment.FindMessenger("Target", &target); + + char command[1024]; + status_t err; + BMessage reply; + while (gets(command)) { + reply.MakeEmpty(); + err = Hey(&target, command, &reply); + if (!err) { + print_message(&reply); + } else { + printf("Error!\n"); + } + printf("%s> ", prompt); + } + + return 0; + + } else { + return 1; + } +} + +status_t Hey(BMessenger* target, const char* arg, BMessage* reply) +{ + vector argv; // number of tokens is now limited only by memory -- pfolk@uni.uiuc.edu 1999-11-03 + char* tokens = new char[strlen(arg)*2]; + char* currentToken = tokens; + int32 tokenNdex = 0; + int32 argNdex = 0; + bool inquotes = false; + + while (arg[argNdex] != 0) { // for each character in arg + if (arg[argNdex] == '\"') inquotes = !inquotes; + if (!inquotes && isSpace(arg[argNdex])) { // if the character is white space + if (tokenNdex!=0) { // close off currentToken token + currentToken[tokenNdex] = 0; + argv.push_back(currentToken); + currentToken += tokenNdex+1; + tokenNdex=0; + argNdex++; + } else { // just skip the whitespace + argNdex++; + } + } else { // copy char into current token + currentToken[tokenNdex] = arg[argNdex]; + tokenNdex++; + argNdex++; + } + } + + if (tokenNdex!=0) { // close off currentToken token + currentToken[tokenNdex] = 0; + argv.push_back(currentToken); + } + argv.push_back(NULL); + + int32 argx = 0; + status_t ret = Hey(target, argv.begin(), &argx, argv.size()-1, reply); + // This used to be "return Hey(...);"---so tokens wasn't delete'd. -- pfolk@uni.uiuc.edu 1999-11-03 + delete tokens; + return ret; +} + +bool isSpace(char c) +{ + switch (c) { + case ' ': + case '\t': + return true; + + default: + return false; + } +} + +status_t Hey(BMessenger* target, char* argv[], int32* argx, int32 argc, BMessage* reply) +{ + bool direct_what = false; + BMessage the_message; + if(strcasecmp(argv[*argx], "let")==0){ // added "let" -- sander@adamation.com 31may2000 + BMessage get_target (B_GET_PROPERTY); + get_target.AddSpecifier ("Messenger"); + // parse the specifiers + (*argx)++; + status_t result=B_OK; + while((result=add_specifier(&get_target, argv, argx, argc))==B_OK){}; + + if(result!=B_ERROR){ // bad syntax + if(!silent) fprintf(stderr, "Bad specifier syntax!\n"); + return result; + } + BMessage msgr; + if (target && target->IsValid()) { + result = target->SendMessage(&get_target, &msgr); + if (result!=B_OK) return result; + result = msgr.FindMessenger ("result", target); + if (result!=B_OK) { + if (!silent) fprintf(stderr, "Couldn't retrieve the BMessenger!\n"); + return result; + } + } + if (!argv[*argx]) { + if (!silent) fprintf(stderr, "Syntax error - forgot \"do\"?\n"); + return B_ERROR; + } + } + if(strcasecmp(argv[*argx], "do")==0){ // added "do" -- pfolk@uni.uiuc.edu 1999-11-03 + the_message.what=B_EXECUTE_PROPERTY; + }else if(strcasecmp(argv[*argx], "get")==0){ + the_message.what=B_GET_PROPERTY; + }else if(strcasecmp(argv[*argx], "set")==0){ + the_message.what=B_SET_PROPERTY; + }else if(strcasecmp(argv[*argx], "create")==0){ + the_message.what=B_CREATE_PROPERTY; + }else if(strcasecmp(argv[*argx], "delete")==0){ + the_message.what=B_DELETE_PROPERTY; + }else if(strcasecmp(argv[*argx], "quit")==0){ + the_message.what=B_QUIT_REQUESTED; + }else if(strcasecmp(argv[*argx], "save")==0){ + the_message.what=B_SAVE_REQUESTED; + }else if(strcasecmp(argv[*argx], "load")==0){ + the_message.what=B_REFS_RECEIVED; + }else if(strcasecmp(argv[*argx], "count")==0){ + the_message.what=B_COUNT_PROPERTIES; + }else if(strcasecmp(argv[*argx], "getsuites")==0){ + the_message.what=B_GET_SUPPORTED_SUITES; + }else{ + switch(strlen(argv[*argx])){ // can be a message constant if 1,2,3 or 4 chars + case 1: + the_message.what=(int32)argv[*argx][0]; + break; + case 2: + the_message.what=(((int32)argv[*argx][0])<<8)|(((int32)argv[*argx][1])); + break; + case 3: + the_message.what=(((int32)argv[*argx][0])<<16)|(((int32)argv[*argx][1])<<8)|(((int32)argv[*argx][2])); + break; + case 4: + the_message.what=(((int32)argv[*argx][0])<<24)|(((int32)argv[*argx][1])<<16)|(((int32)argv[*argx][2])<<8)|(((int32)argv[*argx][3])); + break; + default: + // maybe this is a user defined command, ask for the supported suites + bool found=false; + if (target && target->IsValid()) { + BMessage rply; + if(target->SendMessage(&BMessage(B_GET_SUPPORTED_SUITES), &rply)==B_OK){ + // if all goes well, rply contains all kinds of property infos + int32 j=0; + void *voidptr; + int32 sizefound; + BPropertyInfo propinfo; + const value_info *vinfo; + int32 vinfo_index, vinfo_count; + +// const char *str; +// while (rply.FindString("suites", j++, &str) == B_OK) +// printf ("Suite %ld: %s\n", j, str); +// +// j = 0; + while(rply.FindData("messages", B_PROPERTY_INFO_TYPE, j++, (const void **)&voidptr, &sizefound)==B_OK && !found){ + if(propinfo.Unflatten(B_PROPERTY_INFO_TYPE, (const void *)voidptr, sizefound)==B_OK){ + vinfo=propinfo.Values(); + vinfo_index=0; + vinfo_count=propinfo.CountValues(); +#if TEST_VALUEINFO>0 + value_info vinfo[10]={ {"Backup", 'back', B_COMMAND_KIND, "This command backs up your hard drive."}, + {"Abort", 'abor', B_COMMAND_KIND, "Stops the current operation..."}, + {"Type Code", 'type', B_TYPE_CODE_KIND, "Type code info..."} + }; + vinfo_count=3; +#endif + + while(vinfo_index0 + printf("FOUND COMMAND \"%s\" = %lX\n", vinfo[vinfo_index].name, the_message.what); +#endif + break; + } + vinfo_index++; + } + + } + } + } + } + + + if(!found){ + if(!silent) fprintf(stderr, "Bad verb (\"%s\")\n", argv[*argx]); + return -1; + } + } + direct_what = true; + } + + status_t result=B_OK; + (*argx)++; + + // One exception: Single data item at end of line. + if (direct_what && *argx == argc - 1 && argv[*argx] != NULL) { + add_data(&the_message, argv, argx); + } + else { + // parse the specifiers + if(the_message.what!=B_REFS_RECEIVED){ // LOAD has no specifier + while((result=add_specifier(&the_message, argv, argx, argc))==B_OK){}; + + if(result!=B_ERROR){ // bad syntax + if(!silent) fprintf(stderr, "Bad specifier syntax!\n"); + return result; + } + } + } + + // if verb is SET or LOAD, there should be a to + if((the_message.what==B_SET_PROPERTY || the_message.what==B_REFS_RECEIVED) && argv[*argx]!=NULL){ + if(strcasecmp(argv[*argx], "to")==0){ + (*argx)++; + } + result=add_data(&the_message, argv, argx); + if(result!=B_OK){ + if(result==B_FILE_NOT_FOUND){ + if(!silent) fprintf(stderr, "File not found!\n"); + }else{ + if(!silent) fprintf(stderr, "Invalid 'to...' value format!\n"); + } + return result; + } + } + + add_with(&the_message, argv, argx, argc); + +#if DEBUG_HEY>0 + fprintf(stderr, "Send "); + print_message(&the_message); + fprintf(stderr, "\n"); +#endif + + if (target && target->IsValid()) { + if (reply) { + result = target->SendMessage(&the_message, reply); + } else { + result = target->SendMessage(&the_message); + } + } + return result; +} + +// There can be a with =() [and = ...] +// I treat "and" just the same as "with", it's just to make the script syntax more English-like. +status_t add_with(BMessage *to_message, char *argv[], int32 *argx, int32 argc) +{ + status_t result=B_OK; + if(*argx < argc - 1 && argv[++(*argx)]!=NULL){ + // printf ("argv[%ld] = %s\n", *argx, argv[*argx]); + if(strcasecmp(argv[*argx], "with")==0){ + // printf ("\"with\" detected!\n"); + (*argx)++; + bool done = false; + do + { + result=add_data(to_message, argv, argx); + if(result!=B_OK){ + if(result==B_FILE_NOT_FOUND){ + if(!silent) fprintf(stderr, "File not found!\n"); + }else{ + if(!silent) fprintf(stderr, "Invalid 'with...' value format!\n"); + } + return result; + } + (*argx)++; + // printf ("argc = %d, argv[%d] = %s\n", argc, *argx, argv[*argx]); + if (*argx < argc - 1 && strcasecmp(argv[*argx], "and")==0) + { + (*argx)++; + } + else + done = true; + } while (!done); + } + } + return result; +} + +// returns B_OK if successful +// B_ERROR if no more specifiers +// B_BAD_SCRIPT_SYNTAX if syntax error +status_t add_specifier(BMessage *to_message, char *argv[], int32 *argx, int32 argc) +{ + + char *property=argv[*argx]; + + if(property==NULL) return B_ERROR; // no more specifiers + + (*argx)++; + + if(strcasecmp(property, "do")==0){ // Part of the "hey App let Specifier do Verb". + return B_ERROR; // no more specifiers + } + + if(strcasecmp(property, "to")==0){ // it is the 'to' string!!! + return B_ERROR; // no more specifiers + } + + if(strcasecmp(property, "with")==0){ // it is the 'with' string!!! + *argx -= 2; + add_with (to_message, argv, argx, argc); + return B_ERROR; // no more specifiers + } + + if(strcasecmp(property, "of")==0){ // skip "of", read real property + property=argv[*argx]; + if(property==NULL) return B_BAD_SCRIPT_SYNTAX; // bad syntax + (*argx)++; + } + + if(strcasecmp(property, "the")==0){ // skip "the", read real property -- pfolk@uni.uiuc.edu 1999-11-03 + property=argv[*argx]; + if(property==NULL) return B_BAD_SCRIPT_SYNTAX; // bad syntax + (*argx)++; + } + + // decide the specifier + + char *specifier=NULL; + if(to_message->what==B_CREATE_PROPERTY) // create is always direct. without this, a "with" would be taken as a specifier + (*argx)--; + else + specifier=argv[*argx]; + if(specifier==NULL){ // direct specifier + to_message->AddSpecifier(property); + return B_ERROR; // no more specifiers + } + + (*argx)++; + + if(strcasecmp(specifier, "of")==0){ // direct specifier + to_message->AddSpecifier(property); + return B_OK; + } + + if(strcasecmp(specifier, "to")==0){ // direct specifier + to_message->AddSpecifier(property); + return B_ERROR; // no more specifiers + } + + + if(specifier[0]=='['){ // index, reverse index or range + char *end; + int32 ix1, ix2; + if(specifier[1]=='-'){ // reverse index + ix1=strtoul(specifier+2, &end, 10); + BMessage revspec(B_REVERSE_INDEX_SPECIFIER); + revspec.AddString("property", property); + revspec.AddInt32("index", ix1); + to_message->AddSpecifier(&revspec); + }else{ // index or range + ix1=strtoul(specifier+1, &end, 10); + if(end[0]==']'){ // it was an index + to_message->AddSpecifier(property, ix1); + return B_OK; + }else{ + specifier=argv[*argx]; + if(specifier==NULL){ + // I was wrong, it was just an index + to_message->AddSpecifier(property, ix1); + return B_OK; + } + (*argx)++; + if(strcasecmp(specifier, "to")==0){ + specifier=argv[*argx]; + if(specifier==NULL){ + return B_BAD_SCRIPT_SYNTAX; // wrong syntax + } + (*argx)++; + ix2=strtoul(specifier, &end, 10); + to_message->AddSpecifier(property, ix1, ix2-ix1>0 ? ix2-ix1 : 1); + return B_OK; + }else{ + return B_BAD_SCRIPT_SYNTAX; // wrong syntax + } + } + } + }else{ // name specifier + // if it contains only digits, it will be an index... + bool index_spec=true; + bool reverse = specifier[0]=='-'; + // accept bare reverse-index-specs -- pfolk@uni.uiuc.edu 1999-11-03 + size_t speclen = strlen(specifier); + for (int32 i=(reverse?1:0); i<(int32)speclen; ++i){ + if(specifier[i]<'0' || specifier[i]>'9'){ + index_spec=false; + break; + } + } + + if(index_spec){ + if (reverse) + { + // Copied from above -- pfolk@uni.uiuc.edu 1999-11-03 + BMessage revspec(B_REVERSE_INDEX_SPECIFIER); + revspec.AddString("property", property); + revspec.AddInt32("index", atol(specifier+1)); + to_message->AddSpecifier(&revspec); + } + else to_message->AddSpecifier(property, atol(specifier)); + }else{ + // Allow any name by counting an initial " as a literal-string indicator + // -- pfolk@uni.uiuc.edu 1999-11-03 + if(specifier[0]=='\"') + { + if (specifier[speclen-1]=='\"') + specifier[speclen-1]='\0'; + ++specifier; + --speclen; + } + to_message->AddSpecifier(property, specifier); + } + + } + + return B_OK; +} + + +status_t add_data(BMessage *to_message, char *argv[], int32 *argx) +{ + char *valuestring=argv[*argx]; + + if(valuestring==NULL) return B_ERROR; + + // try to interpret it as an integer or float + bool contains_only_digits=true; + bool is_floating_point=false; + for(int32 i=0;i<(int32)strlen(valuestring);i++){ + if(i!=0 || valuestring[i]!='-') { + if(valuestring[i]<'0' || valuestring[i]>'9'){ + if(valuestring[i]=='.'){ + is_floating_point=true; + }else{ + contains_only_digits=false; + break; + } + } + } + } + //printf("%d %d\n", contains_only_digits,is_floating_point); + if(contains_only_digits){ + if(is_floating_point){ + to_message->AddFloat("data", atof(valuestring)); + return B_OK; + }else{ + to_message->AddInt32("data", atol(valuestring)); + return B_OK; + } + } + + // if true or false, it is bool + if(strcasecmp(valuestring, "true")==0){ + to_message->AddBool("data", true); + return B_OK; + }else if(strcasecmp(valuestring, "false")==0){ + to_message->AddBool("data", false); + return B_OK; + } + + // Add support for "=()" here: + // The type is then added under the name "name". + + #define MAX_NAME_LENGTH 128 + char curname[MAX_NAME_LENGTH]; + strcpy (curname, "data"); // This is the default. + + char *s = valuestring; + while (*++s && *s != '=') + // Look for a '=' character... + ; + if (*s == '=') // We found a = + { + *s = 0; + strcpy (curname, valuestring); // Use the new + valuestring = s + 1; // Reposition the valuestring ptr. + } + + // must begin with a type( value ) + if(strncasecmp(valuestring, "int8", strlen("int8"))==0){ + to_message->AddInt8(curname, atol(valuestring+strlen("int8("))); + return B_OK; + }else if(strncasecmp(valuestring, "int16", strlen("int16"))==0){ + to_message->AddInt16(curname, atol(valuestring+strlen("int16("))); + return B_OK; + }else if(strncasecmp(valuestring, "int32", strlen("int32"))==0){ + to_message->AddInt32(curname, atol(valuestring+strlen("int32("))); + return B_OK; + }else if(strncasecmp(valuestring, "int64", strlen("int64"))==0){ + to_message->AddInt64(curname, atol(valuestring+strlen("int64("))); + return B_OK; + }else if(strncasecmp(valuestring, "bool", strlen("bool"))==0){ + if(strncasecmp(valuestring+strlen("bool("), "true", 4)==0){ + to_message->AddBool(curname, true); + }else if(strncasecmp(valuestring+strlen("bool("), "false", 5)==0){ + to_message->AddBool(curname, false); + }else{ + to_message->AddBool(curname, atol(valuestring+strlen("bool("))==0 ? false : true); + } + return B_OK; + }else if(strncasecmp(valuestring, "float", strlen("float"))==0){ + to_message->AddFloat(curname, atof(valuestring+strlen("float("))); + return B_OK; + }else if(strncasecmp(valuestring, "double", strlen("double"))==0){ + to_message->AddDouble(curname, atof(valuestring+strlen("double("))); + return B_OK; + }else if(strncasecmp(valuestring, "BPoint", strlen("BPoint"))==0){ + float x,y; + x=atof(valuestring+strlen("BPoint(")); + if(strchr(valuestring, ',')){ + y=atof(strchr(valuestring, ',')+1); + }else if(strchr(valuestring, ' ')){ + y=atof(strchr(valuestring, ' ')+1); + }else{ // bad syntax + y=0.0f; + } + to_message->AddPoint(curname, BPoint(x,y)); + return B_OK; + }else if(strncasecmp(valuestring, "BRect", strlen("BRect"))==0){ + float l=0.0f, t=0.0f, r=0.0f, b=0.0f; + char *ptr; + l=atof(valuestring+strlen("BRect(")); + ptr=strchr(valuestring, ','); + if(ptr){ + t=atof(ptr+1); + ptr=strchr(ptr+1, ','); + if(ptr){ + r=atof(ptr+1); + ptr=strchr(ptr+1, ','); + if(ptr){ + b=atof(ptr+1); + } + } + } + + to_message->AddRect(curname, BRect(l,t,r,b)); + return B_OK; + }else if(strncasecmp(valuestring, "rgb_color", strlen("rgb_color"))==0){ + rgb_color clr; + char *ptr; + clr.red=atol(valuestring+strlen("rgb_color(")); + ptr=strchr(valuestring, ','); + if(ptr){ + clr.green=atol(ptr+1); + ptr=strchr(ptr+1, ','); + if(ptr){ + clr.blue=atol(ptr+1); + ptr=strchr(ptr+1, ','); + if(ptr){ + clr.alpha=atol(ptr+1); + } + } + } + + to_message->AddData(curname, B_RGB_COLOR_TYPE, &clr, sizeof(rgb_color)); + return B_OK; + }else if(strncasecmp(valuestring, "file", strlen("file"))==0){ + entry_ref file_ref; + + // remove the last ] or ) + if(valuestring[strlen(valuestring)-1]==')' || valuestring[strlen(valuestring)-1]==']'){ + valuestring[strlen(valuestring)-1]=0; + } + + if(get_ref_for_path(valuestring+5, &file_ref)!=B_OK){ + return B_FILE_NOT_FOUND; + } + + // check if the ref is valid + BEntry entry; + if(entry.SetTo(&file_ref)!=B_OK) return B_FILE_NOT_FOUND; + //if(!entry.Exists()) return B_FILE_NOT_FOUND; + + // add both ways, refsreceived needs it as "refs" while scripting needs "data" + to_message->AddRef("refs", &file_ref); + to_message->AddRef(curname, &file_ref); + return B_OK; + }else{ // it is string + // does it begin with a quote? + if(valuestring[0]=='\"'){ + if(valuestring[strlen(valuestring)-1]=='\"') valuestring[strlen(valuestring)-1]=0; + to_message->AddString(curname, valuestring+1); + }else{ + to_message->AddString(curname, valuestring); + } + return B_OK; + } + + return B_OK; +} + + + +void print_message(BMessage *message) +{ + + BList textlist; + add_message_contents(&textlist, message, 0); + + + printf("BMessage(%s):\n", get_datatype_string(message->what)); + for(int32 i=0;iCountNames(B_ANY_TYPE); + for(i=0;iGetInfo(B_ANY_TYPE, i, &namefound, &typefound); + j=0; + + while(msg->FindData(namefound, typefound, j++, (const void **)&voidptr, &sizefound)==B_OK){ + datatype=get_datatype_string(typefound); + content=format_data(typefound, (char*)voidptr, sizefound); + textline=(char*)malloc(20+level*4+strlen(namefound)+strlen(datatype)+strlen(content)); + memset(textline, 32, 20+level*4); + sprintf(textline+level*4, "\"%s\" (%s) : %s", namefound, datatype, content); + textlist->AddItem(textline); + delete [] datatype; + delete [] content; + + if(typefound==B_MESSAGE_TYPE){ + msg->FindMessage(namefound, j-1, &a_message); + add_message_contents(textlist, &a_message, level+1); + }else + if(typefound==B_RAW_TYPE && strcmp(namefound, "_previous_")==0){ + if(a_message.Unflatten((const char *)voidptr)==B_OK){ + add_message_contents(textlist, &a_message, level+1); + } + } + } + + } + +} + + + +char *get_datatype_string(int32 type) +{ + char *str=new char[128]; + + switch(type){ + case B_ANY_TYPE: strcpy(str, "B_ANY_TYPE"); break; + case B_ASCII_TYPE: strcpy(str, "B_ASCII_TYPE"); break; + case B_BOOL_TYPE: strcpy(str, "B_BOOL_TYPE"); break; + case B_CHAR_TYPE: strcpy(str, "B_CHAR_TYPE"); break; + case B_COLOR_8_BIT_TYPE: strcpy(str, "B_COLOR_8_BIT_TYPE"); break; + case B_DOUBLE_TYPE: strcpy(str, "B_DOUBLE_TYPE"); break; + case B_FLOAT_TYPE: strcpy(str, "B_FLOAT_TYPE"); break; + case B_GRAYSCALE_8_BIT_TYPE: strcpy(str, "B_GRAYSCALE_8_BIT_TYPE"); break; + case B_INT64_TYPE: strcpy(str, "B_INT64_TYPE"); break; + case B_INT32_TYPE: strcpy(str, "B_INT32_TYPE"); break; + case B_INT16_TYPE: strcpy(str, "B_INT16_TYPE"); break; + case B_INT8_TYPE: strcpy(str, "B_INT8_TYPE"); break; + case B_MESSAGE_TYPE: strcpy(str, "B_MESSAGE_TYPE"); break; + case B_MESSENGER_TYPE: strcpy(str, "B_MESSENGER_TYPE"); break; + case B_MIME_TYPE: strcpy(str, "B_MIME_TYPE"); break; + case B_MONOCHROME_1_BIT_TYPE: strcpy(str, "B_MONOCHROME_1_BIT_TYPE"); break; + case B_OBJECT_TYPE: strcpy(str, "B_OBJECT_TYPE"); break; + case B_OFF_T_TYPE: strcpy(str, "B_OFF_T_TYPE"); break; + case B_PATTERN_TYPE: strcpy(str, "B_PATTERN_TYPE"); break; + case B_POINTER_TYPE: strcpy(str, "B_POINTER_TYPE"); break; + case B_POINT_TYPE: strcpy(str, "B_POINT_TYPE"); break; + case B_RAW_TYPE: strcpy(str, "B_RAW_TYPE"); break; + case B_RECT_TYPE: strcpy(str, "B_RECT_TYPE"); break; + case B_REF_TYPE: strcpy(str, "B_REF_TYPE"); break; + case B_RGB_32_BIT_TYPE: strcpy(str, "B_RGB_32_BIT_TYPE"); break; + case B_RGB_COLOR_TYPE: strcpy(str, "B_RGB_COLOR_TYPE"); break; + case B_SIZE_T_TYPE: strcpy(str, "B_SIZE_T_TYPE"); break; + case B_SSIZE_T_TYPE : strcpy(str, "B_SSIZE_T_TYPE"); break; + case B_STRING_TYPE: strcpy(str, "B_STRING_TYPE"); break; + case B_TIME_TYPE : strcpy(str, "B_TIME_TYPE"); break; + case B_UINT64_TYPE : strcpy(str, "B_UINT64_TYPE"); break; + case B_UINT32_TYPE: strcpy(str, "B_UINT32_TYPE"); break; + case B_UINT16_TYPE : strcpy(str, "B_UINT16_TYPE"); break; + case B_UINT8_TYPE : strcpy(str, "B_UINT8_TYPE"); break; + case B_PROPERTY_INFO_TYPE: strcpy(str, "B_PROPERTY_INFO_TYPE"); break; + // message constants: + case B_ABOUT_REQUESTED : strcpy(str, "B_ABOUT_REQUESTED"); break; + case B_WINDOW_ACTIVATED : strcpy(str, "B_WINDOW_ACTIVATED"); break; + case B_ARGV_RECEIVED : strcpy(str, "B_ARGV_RECEIVED"); break; + case B_QUIT_REQUESTED : strcpy(str, "B_QUIT_REQUESTED"); break; + case B_CANCEL : strcpy(str, "B_CANCEL"); break; + case B_KEY_DOWN : strcpy(str, "B_KEY_DOWN"); break; + case B_KEY_UP : strcpy(str, "B_KEY_UP"); break; + case B_MINIMIZE : strcpy(str, "B_MINIMIZE"); break; + case B_MOUSE_DOWN : strcpy(str, "B_MOUSE_DOWN"); break; + case B_MOUSE_MOVED : strcpy(str, "B_MOUSE_MOVED"); break; + case B_MOUSE_ENTER_EXIT : strcpy(str, "B_MOUSE_ENTER_EXIT"); break; + case B_MOUSE_UP : strcpy(str, "B_MOUSE_UP"); break; + case B_PULSE : strcpy(str, "B_PULSE"); break; + case B_READY_TO_RUN : strcpy(str, "B_READY_TO_RUN"); break; + case B_REFS_RECEIVED : strcpy(str, "B_REFS_RECEIVED"); break; + case B_SCREEN_CHANGED : strcpy(str, "B_SCREEN_CHANGED"); break; + case B_VALUE_CHANGED : strcpy(str, "B_VALUE_CHANGED"); break; + case B_VIEW_MOVED : strcpy(str, "B_VIEW_MOVED"); break; + case B_VIEW_RESIZED : strcpy(str, "B_VIEW_RESIZED"); break; + case B_WINDOW_MOVED : strcpy(str, "B_WINDOW_MOVED"); break; + case B_WINDOW_RESIZED : strcpy(str, "B_WINDOW_RESIZED"); break; + case B_WORKSPACES_CHANGED : strcpy(str, "B_WORKSPACES_CHANGED"); break; + case B_WORKSPACE_ACTIVATED : strcpy(str, "B_WORKSPACE_ACTIVATED"); break; + case B_ZOOM : strcpy(str, "B_ZOOM"); break; + case _APP_MENU_ : strcpy(str, "_APP_MENU_"); break; + case _BROWSER_MENUS_ : strcpy(str, "_BROWSER_MENUS_"); break; + case _MENU_EVENT_ : strcpy(str, "_MENU_EVENT_"); break; + case _QUIT_ : strcpy(str, "_QUIT_"); break; + case _VOLUME_MOUNTED_ : strcpy(str, "_VOLUME_MOUNTED_"); break; + case _VOLUME_UNMOUNTED_ : strcpy(str, "_VOLUME_UNMOUNTED_"); break; + case _MESSAGE_DROPPED_ : strcpy(str, "_MESSAGE_DROPPED_"); break; + case _MENUS_DONE_ : strcpy(str, "_MENUS_DONE_"); break; + case _SHOW_DRAG_HANDLES_ : strcpy(str, "_SHOW_DRAG_HANDLES_"); break; + case B_SET_PROPERTY : strcpy(str, "B_SET_PROPERTY"); break; + case B_GET_PROPERTY : strcpy(str, "B_GET_PROPERTY"); break; + case B_CREATE_PROPERTY : strcpy(str, "B_CREATE_PROPERTY"); break; + case B_DELETE_PROPERTY : strcpy(str, "B_DELETE_PROPERTY"); break; + case B_COUNT_PROPERTIES : strcpy(str, "B_COUNT_PROPERTIES"); break; + case B_EXECUTE_PROPERTY : strcpy(str, "B_EXECUTE_PROPERTY"); break; + case B_GET_SUPPORTED_SUITES : strcpy(str, "B_GET_SUPPORTED_SUITES"); break; + case B_CUT : strcpy(str, "B_CUT"); break; + case B_COPY : strcpy(str, "B_COPY"); break; + case B_PASTE : strcpy(str, "B_PASTE"); break; + case B_SELECT_ALL : strcpy(str, "B_SELECT_ALL"); break; + case B_SAVE_REQUESTED : strcpy(str, "B_SAVE_REQUESTED"); break; + case B_MESSAGE_NOT_UNDERSTOOD : strcpy(str, "B_MESSAGE_NOT_UNDERSTOOD"); break; + case B_NO_REPLY : strcpy(str, "B_NO_REPLY"); break; + case B_REPLY : strcpy(str, "B_REPLY"); break; + case B_SIMPLE_DATA : strcpy(str, "B_SIMPLE_DATA"); break; + //case B_MIME_DATA : strcpy(str, "B_MIME_DATA"); break; + case B_ARCHIVED_OBJECT : strcpy(str, "B_ARCHIVED_OBJECT"); break; + case B_UPDATE_STATUS_BAR : strcpy(str, "B_UPDATE_STATUS_BAR"); break; + case B_RESET_STATUS_BAR : strcpy(str, "B_RESET_STATUS_BAR"); break; + case B_NODE_MONITOR : strcpy(str, "B_NODE_MONITOR"); break; + case B_QUERY_UPDATE : strcpy(str, "B_QUERY_UPDATE"); break; + case B_BAD_SCRIPT_SYNTAX: strcpy(str, "B_BAD_SCRIPT_SYNTAX"); break; + + // specifiers: + case B_NO_SPECIFIER : strcpy(str, "B_NO_SPECIFIER"); break; + case B_DIRECT_SPECIFIER : strcpy(str, "B_DIRECT_SPECIFIER"); break; + case B_INDEX_SPECIFIER : strcpy(str, "B_INDEX_SPECIFIER"); break; + case B_REVERSE_INDEX_SPECIFIER : strcpy(str, "B_REVERSE_INDEX_SPECIFIER"); break; + case B_RANGE_SPECIFIER : strcpy(str, "B_RANGE_SPECIFIER"); break; + case B_REVERSE_RANGE_SPECIFIER : strcpy(str, "B_REVERSE_RANGE_SPECIFIER"); break; + case B_NAME_SPECIFIER : strcpy(str, "B_NAME_SPECIFIER"); break; + + case B_ERROR : strcpy(str, "B_ERROR"); break; + + default: // unknown + id_to_string(type, str); + break; + } + + return str; + +} + + +char *format_data(int32 type, char *ptr, long size) +{ + char idtext[32]; + char *str; + float *fptr; + double *dptr; +// BRect *brptr; + long i; + entry_ref aref; + BEntry entry; + BPath path; + int64 i64; + int32 i32; + int16 i16; + int8 i8; + uint64 ui64; + uint32 ui32; + uint16 ui16; + uint8 ui8; + BMessage anothermsg; + BPropertyInfo propinfo; + const property_info *pinfo; + int32 pinfo_index; + const value_info *vinfo; + int32 vinfo_index, vinfo_count; + char *tempstr; + + + if(size<=0L){ + str=new char; + *str=0; + return str; + } + + switch(type){ + case B_MIME_TYPE: + case B_ASCII_TYPE: + case B_STRING_TYPE: + if(size>512) size=512; + str=new char[size+4]; + *str='\"'; + strncpy(str+1, ptr, size); + strcat(str, "\""); + break; + case B_POINTER_TYPE: + str=new char[64]; + sprintf(str, "%p", *(void**)ptr); + break; + + case B_REF_TYPE: + str=new char[1024]; + anothermsg.AddData("myref", B_REF_TYPE, ptr, size); + anothermsg.FindRef("myref", &aref); + if(entry.SetTo(&aref)==B_OK){ + entry.GetPath(&path); + strcpy(str, path.Path()); + }else{ + strcpy(str, "invalid entry_ref"); + } + break; + + case B_SSIZE_T_TYPE: + case B_INT64_TYPE: + str=new char[64]; + i64=*(int64*)ptr; + sprintf(str, "%Ld (0x%LX)", i64, i64); + break; + + case B_SIZE_T_TYPE: + case B_INT32_TYPE: + str=new char[64]; + i32=*(int32*)ptr; + sprintf(str, "%ld (0x%08lX)", i32, i32); + break; + + case B_INT16_TYPE: + str=new char[64]; + i16=*(int16*)ptr; + sprintf(str, "%d (0x%04X)", i16, i16); + break; + + case B_CHAR_TYPE: + case B_INT8_TYPE: + str=new char[64]; + i8=*(int8*)ptr; + sprintf(str, "%d (0x%02X)", i8, i8); + break; + + case B_UINT64_TYPE: + str=new char[64]; + ui64=*(uint64*)ptr; + sprintf(str, "%Lu (0x%LX)", ui64, ui64); + break; + + case B_UINT32_TYPE: + str=new char[64]; + ui32=*(uint32*)ptr; + sprintf(str, "%lu (0x%08lX)", ui32, ui32); + break; + + case B_UINT16_TYPE: + str=new char[64]; + ui16=*(uint16*)ptr; + sprintf(str, "%u (0x%04X)", ui16, ui16); + break; + + case B_UINT8_TYPE: + str=new char[64]; + ui8=*(uint8*)ptr; + sprintf(str, "%u (0x%02X)", ui8, ui8); + break; + + case B_BOOL_TYPE: + str=new char[10]; + if(*ptr){ + strcpy(str, "TRUE"); + }else{ + strcpy(str, "FALSE"); + } + break; + + case B_FLOAT_TYPE: + str=new char[40]; + fptr=(float*)ptr; + sprintf(str, "%.3f", *fptr); + break; + + case B_DOUBLE_TYPE: + str=new char[40]; + dptr=(double*)ptr; + sprintf(str, "%.3f", *dptr); + break; + + case B_RECT_TYPE: + str=new char[200]; + fptr=(float*)ptr; + sprintf(str, "BRect(%.1f, %.1f, %.1f, %.1f)", fptr[0], fptr[1], fptr[2], fptr[3]); + break; + + case B_POINT_TYPE: + str=new char[200]; + fptr=(float*)ptr; + sprintf(str, "BPoint(%.1f, %.1f)", fptr[0], fptr[1]); + break; + + case B_RGB_COLOR_TYPE: + str=new char[64]; + sprintf(str, "Red=%u Green=%u Blue=%u Alpha=%u", ((uint8*)ptr)[0], ((uint8*)ptr)[1], ((uint8*)ptr)[2], ((uint8*)ptr)[3] ); + break; + + case B_COLOR_8_BIT_TYPE: + str=new char[size*6+4]; + *str=0; + for(i=0;i "); break; + } + } + strcat(str, "\n"); + + // is there usage info? + if(pinfo[pinfo_index].usage){ + strcat(str, " Usage: "); + strcat(str, pinfo[pinfo_index].usage); + strcat(str, "\n"); + } + + + pinfo_index++; // take next propertyinfo + } + + + // handle value infos.... + vinfo=propinfo.Values(); + vinfo_index=0; + vinfo_count=propinfo.CountValues(); +#if TEST_VALUEINFO>0 + value_info vinfo[10]={ {"Backup", 'back', B_COMMAND_KIND, "This command backs up your hard drive."}, + {"Abort", 'abor', B_COMMAND_KIND, "Stops the current operation..."}, + {"Type Code", 'type', B_TYPE_CODE_KIND, "Type code info..."} + }; + vinfo_count=3; +#endif + + if(vinfo && vinfo_count>0){ + sprintf(str+strlen(str), "\n name value kind\n--------------------------------------------------------------------------------\n"); + + while(vinfo_index>24)&255; + uint8 digit1=(ID>>16)&255; + uint8 digit2=(ID>>8)&255; + uint8 digit3=(ID)&255; + bool itsvalid=false; + + if(digit0==0){ + if(digit1==0){ + if(digit2==0){ + // 1 digits + if(is_valid_char(digit3) ) itsvalid=TRUE; + sprintf(here, "'%c'", digit3); + }else{ + // 2 digits + if(is_valid_char(digit2) && is_valid_char(digit3) ) itsvalid=TRUE; + sprintf(here, "'%c%c'", digit2, digit3); + } + }else{ + // 3 digits + if(is_valid_char(digit1) && is_valid_char(digit2) && is_valid_char(digit3) ) itsvalid=TRUE; + sprintf(here, "'%c%c%c'", digit1, digit2, digit3); + } + }else{ + // 4 digits + if(is_valid_char(digit0) && is_valid_char(digit1) && is_valid_char(digit2) && is_valid_char(digit3) ) itsvalid=TRUE; + sprintf(here, "'%c%c%c%c'", digit0, digit1, digit2, digit3); + } + + if(!itsvalid){ + sprintf(here, "%ldL", ID); + } + + return here; +} + + +bool is_valid_char(uint8 c) +{ + return (c>=32 && c<128); +} + diff --git a/src/tools/hey/hey.h b/src/tools/hey/hey.h new file mode 100644 index 0000000000..a6c8c5b77d --- /dev/null +++ b/src/tools/hey/hey.h @@ -0,0 +1,24 @@ +#ifndef HEY_H +#define HEY_H + +#include + + + +__declspec(dllexport) int32 HeyInterpreterThreadHook(void* arg); + +__declspec(dllexport) status_t Hey(BMessenger* target, const char* arg, BMessage* reply); +__declspec(dllexport) bool isSpace(char c); +__declspec(dllexport) status_t Hey(BMessenger* target, char* argv[], int32* argx, int32 argc, BMessage* reply); +__declspec(dllexport) status_t add_specifier(BMessage *to_message, char *argv[], int32 *argx, int32 argc); +__declspec(dllexport) status_t add_data(BMessage *to_message, char *argv[], int32 *argx); +__declspec(dllexport) status_t add_with(BMessage *to_message, char *argv[], int32 *argx, int32 argc); +__declspec(dllexport) void add_message_contents(BList *textlist, BMessage *msg, int32 level); +__declspec(dllexport) char *get_datatype_string(int32 type); +__declspec(dllexport) char *format_data(int32 type, char *ptr, long size); +__declspec(dllexport) void print_message(BMessage *message); +__declspec(dllexport) char *id_to_string(long ID, char *here); +__declspec(dllexport) bool is_valid_char(uint8 c); + + +#endif diff --git a/src/tools/hey/readme.html b/src/tools/hey/readme.html new file mode 100644 index 0000000000..8729e91d13 --- /dev/null +++ b/src/tools/hey/readme.html @@ -0,0 +1,260 @@ + + + +hey Documentation + + +

        hey version 1.2.6

        +
        +
        + +

        What is hey?

        +hey is a small public domain scripting utility which works with standard BeOS scripting. It comes with source which you can modify as you wish. If you want your modification in the standard distribution, just drop me a line. +Use it at your own risk. +

        +

        +
        + +

        Installation

        + +
          +
        • unzip the archive by doubleclicking on hey-YYYYMMDD.zip or by dropping it on Expander +
        • open the right project file depending on the hardware platform and select 'Make' from the 'Project' menu to compile it +
        • you may want to move the executable (hey) to /boot/home/config/bin

          +
        +

        +
        + +

        Usage

        +hey should be used from Terminal. When you start it without parameters it will display the command line syntax it accepts: +
        
        +hey v1.2.6, written by Attila Mezei (amezei@mail.datanet.hu)
        +usage: hey [-s] <app|signature> [let <specifier> do] <verb> <specifier_1> <of <specifier_n>>* 
        +           [to <value>] [with name=<value> [and name=<value>]*]
        +where  <verb> : DO|GET|SET|COUNT|CREATE|DELETE|GETSUITES|QUIT|SAVE|LOAD|'what'
        +  <specifier> : [the] <property_name> [ <index> | name | "name" | '"name"']
        +      <index> : index | '['index']' | '['-reverse_index']' | '['fromvalue to tovalue']'
        +      <index> : int | -int | '['int']' | '['-int']' | '['startint to end']'
        +      <value> : "string" | <integer> | <float> | bool(value) | int8(value) |
        +                int16(value) | int32(value) | float(value) | double(value) |
        +                BPoint(x,y) | BRect(l,t,r,b) | rgb_color(r,g,b,a) | file(path)   
        +options: -s: silent
        +
        +
        +
        + +

        The verb

        +The verbs send the following messages: +
          +
        • DO: B_EXECUTE_PROPERTY +
        • GET: B_GET_PROPERTY +
        • SET: B_SET_PROPERTY +
        • COUNT: B_COUNT_PROPERTIES +
        • CREATE: B_CREATE_PROPERTY +
        • DELETE: B_DELETE_PROPERTY +
        • GETSUITES: B_GET_SUPPORTED_SUITES +
        • QUIT: B_QUIT_REQUESTED +
        • SAVE: B_SAVE_REQUESTED +
        • LOAD: B_REFS_RECEIVED +
        +You can use your own verbs if you specify the value names and constants in the 'value_info' structure. See BPropertyInfo and PropertyInfo.h for details. +

        +Note that the verb is not case sensitive but the specifier names (e.g. "Frame", "Label"...) are. You can use 'what' constants +directly, like +

        hey Application '_ABR'
        +
        +will open the about window of the application.

        +LOAD and SAVE are actually not scripting commands, they are standard BeOS messages (B_REFS_RECEIVED and B_SAVE_REQUESTED). I included them for convenience. E.g. open a file in Application (the path can be relative or absolute): +

        hey Application load 'file(/boot/home/images/Be.jpg)'
        +
        +or save it: +
        hey Application save Window "Be.jpg"
        +
        + +
        + +

        The specifier

        + +

        The specifier can be direct, index, reverse index, range or named. Reverse range is +not supported. If you enter an index which consists of only digits, you can omit the square +brackets: +

        hey Application get Window 0
        +
        + +
        +

        The value

        + +It is easy to use the type names in front of the value but beware that the shell will throw a syntax error if you do this: +
        hey Application set .... to BPoint(100,100)
        +
        +Instead use square brackets or quotes: +
        hey Application set .... to BPoint[100,100]
        +hey Application set .... to 'BPoint(100,100)'
        +
        + +If the value string contains only digits, it will be considered an int32. If it contains digits and a dot, +a float type is assumed. "true" or "false" can also be used as bools. + +

        +
        +

        DEBUG mode

        +You can check the message to be sent to the application by setting the DEBUG_HEY preprocessor symbol to 1, and recompiling.

        +
        + +

        History

        +v1.2.6 +
          +
        • syntax extended by Sander Stoks to allow: + "hey Application let Specifier do ..." + allowing you to send messages directly to other handlers than the app itself. + In cooperation with the new Application defined commands (note that some + Be classes, e.g. BWindow, publish commands as well) this allows, for example: + "hey NetPositive let Window 0 do MoveBy BPoint[10,10]" + Note that this is partly redundant, since + "hey NetPositive let Window 0 do get Title" + duplicates "hey NetPositive get Title of Window 0" + But with the old system, + "hey NetPositive MoveBy of Window 0 with data=BPoint[10,10]" + couldn't work ("MoveBy" is not defined by the Application itself). +
        +v1.2.5 +
          +
        • 'value_info' is supported in BPropertyInfo. This means when you send GETSUITES (B_GET_SUPPORTED_SUITES) the value info is printed after the property infos (name, kind, value, usage).
          +You can also use application defined commands (as the verb) with hey:
          + hey MyBackupApp Backup "Maui"
          +
        +v1.2.4 +
          +
        • The syntax is extended by Peter Folk + to contain: +
          do the x of y -3 of z '"1"'
          + I.e. "do" => B_EXECUTE_PROPERTY, optional "the" makes direct specifiers + more like english, bare reverse-index-specifiers are now handled, and + named specifiers can contain only digits by quoting it (but make sure the + shell passes the quotes through). + +
        • Hey(target,const char*,reply) was previously limited to 100 tokens. + It now uses a vector<> so it's only limited by available memory. + +
        • Also, the archive name is now Y2K compliant =) +
        +v1.2.3 +
          +
        • new option: -s for silent processing (no reply or errors printed) AM +
        +v1.2.2 +
          +
        • Fixes by Marco Nelissen (marcone@xs4all.nl):
          +
        • fixed parsing of negative numbers +
        • fixed "with" syntax, which was broken (after a create, "with" would be taken as a specifier) +
        +v1.2.1 +
          +
        • compiled for R4 with minor modifications of BPropertyInfo usage +
        +v1.2.0 +
          +
        • the syntax is extended by Sander Stoks (sander@adamation.com) to contain
          + with name= [and name= [...]]
          + at the end of the command which will add additional data to the scripting message. E.g:
          + hey Becasso create Canvas with name=MyCanvas and size=BRect(100,100,300,300)
          + Also a small interpreter is included. + +
        • Detailed printout of B_PROPERTY_INFO in BMessages. Better than BPropertyInfo::PrintToStream(). + Also prints usage info for a property if defined. +
        +v1.1.1 +
          +
        • minor change from chrish@qnx.com to return -1 if an error is + sent back in the reply message; also added B_COUNT_PROPERTIES support + +
        • The range specifier sent to the target was 1 greater than it should've been. Fixed. + +
        • 'hey' made the assumption that the first thread in a team will be the + application thread (and therefore have the application's name). + This was not always the case. Fix from Scott Lindsey (wombat@gobe.com). +
        +v1.1.0 +
          +
        • flattened BPropertyInfo is printed if found in the reply of B_GET_SUPPORTED_SUITES +
        • 1,2,3 and 4 character message constant is supported (e.g. '1', '12', '123', '1234') +
        • alpha is sent with rgb_color +
        +v1.0.0 +
          +
        • First public release +
        + +

        +
        +

        Examples

        + +For these examples you need to start the Network preferences application +(the classic way to demo scripting ;-) + + +

        Get the messenger of an application (not useful if you use 'hey'):

        +
        	hey Network get Messenger
        +
        + +

        Get the suite of messages which the application can handle:

        +
        	hey Network getsuites
        +
        +
          (BApplication & BHandler suites printed) +
        +

        Get the name of the application

        +
        	hey Network get Name
        +
        +

        Open the about window of the application

        +
        	hey Network '_ABR'
        +
        +

        Get a window of the application (actually a messenger for the window)

        +
        	hey Network get Window [0]
        +
          or you can omit the square brackets when using an index:
        +
        	hey Network get Window 0
        +
          or you can specify a window name (with or without quotes):
        +
        	hey Network get Window "Network"
        +
        +

        Get the suite of messages which the window can handle:

        +
        	hey Network getsuites of Window "Network"
        +
          (for the description of suite/vnd.Be-window see the BeBook)
        + +

        Get the title, frame or other properties of the window:

        +
        	hey Network get Title of Window "Network"
        +	hey Network get Frame of Window "Network"
        +
        +

        Set the title, frame or other properties of the window:

        +
        	hey Network set Title of Window "Network" to "hey is great"
        +	hey Network set Frame of Window "Network" to 'BRect(0,0,300,300)'
        +
          or you can use square brackets to avoid the 's:
        +
        	hey Network set Frame of Window "Network" to BRect[0,0,300,300]
        +
        +

        Get a view from the window (actually a messenger for the view)

        +
        	hey Network get View 0 of Window "Network"
        +
        +

        Get the suite of messages which the view can handle:

        +
        	hey Network getsuites of View 0 of Window "Network"
        +
          (for a description of suite/vnd.Be-view see the BeBook)
        + +

        Get a view property:

        +
        	hey Network get Frame of View 0 of Window "Network"
        +	hey Network get Hidden of View 0 of View 0 of Window "Network"
        +	hey Network get Label of View 5 of View 0 of Window "Network"
        +	hey Network get Value of View 0 of View 2 of View 0 of Window "Network"
        +	hey Network get Text of View 2 of View 2 of View 0 of Window "Network"
        +
        +

        Set a view property:

        +
        	hey Network set Frame of View 0 of Window "Network" to 'BRect(0,0,100,400)'
        +	hey Network set Hidden of View 0 of View 0 of Window "Network" to true
        +	hey Network set Label of View 5 of View 0 of Window "Network" to "Restart Something"
        +	hey Network set Value of View 0 of View 2 of View 0 of Window "Network" to 1 
        +	hey Network set Text of View 2 of View 2 of View 0 of Window "Network" to "joe"
        +
        +

        Close a window in an application

        +
        	hey Network quit Window "Network"
        +
        +

        Quit an application

        +
        	hey Network quit
        +
        + + diff --git a/src/tools/jam/Jamfile b/src/tools/jam/Jamfile new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/tools/restest/Elf.h b/src/tools/restest/Elf.h new file mode 100644 index 0000000000..845e765982 --- /dev/null +++ b/src/tools/restest/Elf.h @@ -0,0 +1,105 @@ +// Elf.h + +#ifndef ELF_H +#define ELF_H + +// types +typedef uint32 Elf32_Addr; +typedef uint16 Elf32_Half; +typedef uint32 Elf32_Off; +typedef int32 Elf32_Sword; +typedef uint32 Elf32_Word; + +// e_ident indices +#define EI_MAG0 0 +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_PAD 7 +#define EI_NIDENT 16 + +// object file header +typedef struct { + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +} Elf32_Ehdr; + +// e_ident EI_CLASS and EI_DATA values +#define ELFCLASSNONE 0 +#define ELFCLASS32 1 +#define ELFCLASS64 2 +#define ELFDATANONE 0 +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +// program header +typedef struct { + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +} Elf32_Phdr; + +// p_type +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDIR 6 +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff + +// section header +typedef struct { + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +} Elf32_Shdr; + +// sh_type values +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7fffffff +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0xffffffff + +#endif // ELF_H diff --git a/src/tools/restest/Exception.h b/src/tools/restest/Exception.h new file mode 100644 index 0000000000..59c4aada4e --- /dev/null +++ b/src/tools/restest/Exception.h @@ -0,0 +1,107 @@ +// Exception + +#ifndef EXCEPTION_H +#define EXCEPTION_H + +#include +#include + +#include + +class Exception { +public: + // constructor + Exception() + : fError(B_OK), + fDescription() + { + } + + // constructor + Exception(BString description) + : fError(B_OK), + fDescription(description) + { + } + + // constructor + Exception(const char* format,...) + : fError(B_OK), + fDescription() + { + va_list args; + va_start(args, format); + SetTo(B_OK, format, args); + va_end(args); + } + + // constructor + Exception(status_t error) + : fError(error), + fDescription() + { + } + + // constructor + Exception(status_t error, BString description) + : fError(error), + fDescription(description) + { + } + + // constructor + Exception(status_t error, const char* format,...) + : fError(error), + fDescription() + { + va_list args; + va_start(args, format); + SetTo(error, format, args); + va_end(args); + } + + // copy constructor + Exception(const Exception& exception) + : fError(exception.fError), + fDescription(exception.fDescription) + { + } + + // destructor + ~Exception() + { + } + + // SetTo + void SetTo(status_t error, BString description) + { + fError = error; + fDescription.SetTo(description); + } + + // SetTo + void SetTo(status_t error, const char* format, va_list arg) + { + char buffer[2048]; + vsprintf(buffer, format, arg); + SetTo(error, BString(buffer)); + } + + // GetError + status_t GetError() const + { + return fError; + } + + // GetDescription + const char* GetDescription() const + { + return fDescription.String(); + } + +private: + status_t fError; + BString fDescription; +}; + +#endif // EXCEPTION_H diff --git a/src/tools/restest/OffsetFile.cpp b/src/tools/restest/OffsetFile.cpp new file mode 100644 index 0000000000..852d5cc50d --- /dev/null +++ b/src/tools/restest/OffsetFile.cpp @@ -0,0 +1,155 @@ +// OffsetFile.cpp + +#include + +#include "OffsetFile.h" + +// constructor +OffsetFile::OffsetFile() + : fFile(), + fOffset(0), + fCurrentPosition(0) +{ +} + +// constructor +OffsetFile::OffsetFile(const BFile& file, off_t offset) + : fFile(), + fOffset(0), + fCurrentPosition(0) +{ + SetTo(file, offset); +} + +// destructor +OffsetFile::~OffsetFile() +{ +} + +// SetTo +status_t +OffsetFile::SetTo(const BFile& file, off_t offset) +{ + Unset(); + fFile = file; + fOffset = offset; + return fFile.InitCheck(); +} + +// Unset +void +OffsetFile::Unset() +{ + fFile.Unset(); + fOffset = 0; + fCurrentPosition = 0; +} + +// InitCheck +status_t +OffsetFile::InitCheck() const +{ + return fFile.InitCheck(); +} + +// Read +//ssize_t +//OffsetFile::Read(void *buffer, size_t size) +//{ +// return fFile.Read(buffer, size); +//} + +// Write +//ssize_t +//OffsetFile::Write(const void *buffer, size_t size) +//{ +// return fFile.Write(buffer, size); +//} + +// ReadAt +ssize_t +OffsetFile::ReadAt(off_t pos, void *buffer, size_t size) +{ +//printf("ReadAt(%Lx + %Lx, %lu)\n", pos, fOffset, size); + return fFile.ReadAt(pos + fOffset, buffer, size); +} + +// WriteAt +ssize_t +OffsetFile::WriteAt(off_t pos, const void *buffer, size_t size) +{ + return fFile.WriteAt(pos + fOffset, buffer, size); +} + +// Seek +off_t +OffsetFile::Seek(off_t position, uint32 seekMode) +{ +// off_t result = fFile.Seek(position + fOffset, seekMode); +// if (result >= 0) +// result -= fOffset; +// return result; + off_t result = B_BAD_VALUE; + switch (seekMode) { + case SEEK_SET: + if (position >= 0) + result = fCurrentPosition = position; + break; + case SEEK_END: + { + off_t size; + status_t error = GetSize(&size); + if (size + position >= 0) + result = fCurrentPosition = size + position; + else + result = error; + break; + } + case SEEK_CUR: + if (fCurrentPosition + position >= 0) + result = fCurrentPosition += position; + break; + default: + break; + } + return result; +} + +// Position +off_t +OffsetFile::Position() const +{ +// off_t result = fFile.Position(); +// if (result >= 0) +// result -= fOffset; +// return result; + return fCurrentPosition; +} + +// SetSize +status_t +OffsetFile::SetSize(off_t size) +{ + status_t error = (size >= 0 ? B_OK : B_BAD_VALUE ); + if (error == B_OK) + error = fFile.SetSize(size + fOffset); + return error; +} + +// GetSize +status_t +OffsetFile::GetSize(off_t* size) +{ + status_t error = fFile.GetSize(size); + if (error == B_OK) + *size -= fOffset; + return error; +} + +// GetOffset +off_t +OffsetFile::GetOffset() const +{ + return fOffset; +} + diff --git a/src/tools/restest/OffsetFile.h b/src/tools/restest/OffsetFile.h new file mode 100644 index 0000000000..239a6a7d14 --- /dev/null +++ b/src/tools/restest/OffsetFile.h @@ -0,0 +1,37 @@ +// OffsetFile.h + +#ifndef OFFSET_FILE_H +#define OFFSET_FILE_H + +#include +#include + +class OffsetFile : public BPositionIO { +public: + OffsetFile(); + OffsetFile(const BFile& file, off_t offset); + virtual ~OffsetFile(); + + status_t SetTo(const BFile& file, off_t offset); + void Unset(); + status_t InitCheck() const; + +// ssize_t Read(void *buffer, size_t size); +// ssize_t Write(const void *buffer, size_t size); + ssize_t ReadAt(off_t pos, void *buffer, size_t size); + ssize_t WriteAt(off_t pos, const void *buffer, + size_t size); + off_t Seek(off_t position, uint32 seekMode); + off_t Position() const; + status_t SetSize(off_t size); + status_t GetSize(off_t* size); + + off_t GetOffset() const; + +private: + BFile fFile; + off_t fOffset; + off_t fCurrentPosition; +}; + +#endif // OFFSET_FILE_H diff --git a/src/tools/restest/Pef.h b/src/tools/restest/Pef.h new file mode 100644 index 0000000000..a6c3bbc15b --- /dev/null +++ b/src/tools/restest/Pef.h @@ -0,0 +1,48 @@ +// Pef.h + +#ifndef PEF_H +#define PEF_H + +#include + +typedef char PefOSType[4]; + +// container header +struct PEFContainerHeader { + PefOSType tag1; + PefOSType tag2; + PefOSType architecture; + uint32 formatVersion; + uint32 dateTimeStamp; + uint32 oldDefVersion; + uint32 oldImpVersion; + uint32 currentVersion; + uint16 sectionCount; + uint16 instSectionCount; + uint32 reservedA; +}; + +const char kPEFFileMagic1[4] = { 'J', 'o', 'y', '!' }; +const char kPEFFileMagic2[4] = { 'p', 'e', 'f', 'f' }; +const char kPEFArchitecturePPC[4] = { 'p', 'w', 'p', 'c' }; +const char kPEFContainerHeaderSize = 40; + +// section header +struct PEFSectionHeader { + int32 nameOffset; + uint32 defaultAddress; + uint32 totalSize; + uint32 unpackedSize; + uint32 packedSize; + uint32 containerOffset; + uint8 sectionKind; + uint8 shareKind; + uint8 alignment; + uint8 reservedA; +}; + +const uint32 kPEFSectionHeaderSize = 28; + + + +#endif // PEF_H diff --git a/src/tools/restest/ResourceFile.cpp b/src/tools/restest/ResourceFile.cpp new file mode 100644 index 0000000000..ffb69d9475 --- /dev/null +++ b/src/tools/restest/ResourceFile.cpp @@ -0,0 +1,1160 @@ +// ResourceFile.cpp + +#include "ResourceFile.h" + +#include +#include + +#include "Elf.h" +#include "Exception.h" +#include "Pef.h" +#include "ResourceItem.h" +#include "ResourcesDefs.h" +#include "Warnings.h" + +// ELF defs +static const uint32 kMaxELFHeaderSize = sizeof(Elf32_Ehdr) + 32; +static const char kELFFileMagic[4] = { 0x7f, 'E', 'L', 'F' }; + +// sanity bounds +static const uint32 kMaxResourceCount = 10000; +static const uint32 kELFMaxResourceAlignment = 1024 * 1024 * 10; // 10 MB + +// recognized file types (indices into kFileTypeNames) +enum { + FILE_TYPE_UNKNOWN = 0, + FILE_TYPE_X86_RESOURCE = 1, + FILE_TYPE_PPC_RESOURCE = 2, + FILE_TYPE_ELF = 3, + FILE_TYPE_PEF = 4, +}; + +const char* kFileTypeNames[] = { + "unknown", + "x86 resource file", + "PPC resource file", + "ELF object file", + "PEF object file", +}; + + +// helper functions/classes + +// read_exactly +static +void +read_exactly(BPositionIO& file, off_t position, void* buffer, size_t size, + const char* errorMessage = NULL) +{ + ssize_t read = file.ReadAt(position, buffer, size); + if (read < 0) + throw Exception(read, errorMessage); + else if ((size_t)read != size) { + if (errorMessage) { + throw Exception("%s Read to few bytes (%ld/%lu).", errorMessage, + read, size); + } else + throw Exception("Read to few bytes (%ld/%lu).", read, size); + } +} + +// align_value +template +static inline +TV +align_value(const TV& value, const TA& alignment) +{ + return ((value + alignment - 1) / alignment) * alignment; +} + +// calculate_checksum +static +uint32 +calculate_checksum(const void* data, uint32 size) +{ + uint32 checkSum = 0; + const uint8* csData = (const uint8*)data; + const uint8* dataEnd = csData + size; + const uint8* current = csData; + for (; current < dataEnd; current += 4) { + uint32 word = 0; + int32 bytes = min(4L, dataEnd - current); + for (int32 i = 0; i < bytes; i++) + word = (word << 8) + current[i]; + checkSum += word; + } + return checkSum; +} + +// skip_bytes +static inline +const void* +skip_bytes(const void* buffer, int32 offset) +{ + return (const char*)buffer + offset; +} + +// skip_bytes +static inline +void* +skip_bytes(void* buffer, int32 offset) +{ + return (char*)buffer + offset; +} + +// fill_pattern +static +void +fill_pattern(uint32 byteOffset, void* _buffer, uint32 count) +{ + uint32* buffer = (uint32*)_buffer; + for (uint32 i = 0; i < count; i++) + buffer[i] = kUnusedResourceDataPattern[(byteOffset / 4 + i) % 3]; +} + +// fill_pattern +static +void +fill_pattern(const void* dataBegin, void* buffer, uint32 count) +{ + fill_pattern((char*)buffer - (const char*)dataBegin, buffer, count); +} + +// fill_pattern +static +void +fill_pattern(const void* dataBegin, void* buffer, const void* bufferEnd) +{ + fill_pattern(dataBegin, buffer, + ((const char*)bufferEnd - (char*)buffer) / 4); +} + +// check_pattern +static +bool +check_pattern(uint32 byteOffset, void* _buffer, uint32 count, + bool hostEndianess) +{ + bool result = true; + uint32* buffer = (uint32*)_buffer; + for (uint32 i = 0; result && i < count; i++) { + uint32 value = buffer[i]; + if (!hostEndianess) + value = B_SWAP_INT32(value); + result + = (value == kUnusedResourceDataPattern[(byteOffset / 4 + i) % 3]); + } + return result; +} + +// MemArea +struct MemArea { + MemArea(const void* data, uint32 size) : data(data), size(size) {} + + inline bool check(const void* _current, uint32 skip = 0) const + { + const char* start = (const char*)data; + const char* current = (const char*)_current; + return (start <= current && start + size >= current + skip); + } + + const void* data; + uint32 size; +}; + +// AutoDeleter +template +struct AutoDeleter { + AutoDeleter(C* object, bool array = false) : object(object), array(array) + { + } + + ~AutoDeleter() + { + if (array) + delete[] object; + else + delete object; + } + + C* object; + bool array; +}; + + +// constructor +ResourceFile::ResourceFile() + : fItems(), + fFile(), + fFileType(FILE_TYPE_UNKNOWN), + fFileSize(0), + fResourceCount(0), + fInfoTableItem(NULL), + fHostEndianess(true) +{ +} + +// destructor +ResourceFile::~ResourceFile() +{ + Unset(); +} + +// Init +void +ResourceFile::Init(BFile& file) +{ + Unset(); + try { + _InitFile(file); + _ReadHeader(); + _ReadIndex(); + _ReadInfoTable(); + } catch (Exception exception) { + Unset(); + throw exception; + } +} + +// Unset +void +ResourceFile::Unset() +{ + // items + for (int32 i = 0; ResourceItem* item = ItemAt(i); i++) + delete item; + fItems.MakeEmpty(); + // file + fFile.Unset(); + fFileType = FILE_TYPE_UNKNOWN; + fFileSize = 0; + // resource count + fResourceCount = 0; + // info table + delete fInfoTableItem; + fInfoTableItem = NULL; + fHostEndianess = true; +} + +// InitCheck +status_t +ResourceFile::InitCheck() const +{ + return fFile.InitCheck(); +} + +// AddItem +bool +ResourceFile::AddItem(ResourceItem* item, int32 index) +{ + bool result = false; + if (item) { + if (index < 0 || index > CountItems()) + index = CountItems(); + result = fItems.AddItem(item); + } + return result; +} + +// RemoveItem +ResourceItem* +ResourceFile::RemoveItem(int32 index) +{ + return (ResourceItem*)fItems.RemoveItem(index); +} + +// RemoveItem +bool +ResourceFile::RemoveItem(ResourceItem* item) +{ + return RemoveItem(IndexOf(item)); +} + +// IndexOf +int32 +ResourceFile::IndexOf(ResourceItem* item) const +{ + return fItems.IndexOf(item); +} + +// ItemAt +ResourceItem* +ResourceFile::ItemAt(int32 index) const +{ + return (ResourceItem*)fItems.ItemAt(index); +} + +// CountItems +int32 +ResourceFile::CountItems() const +{ + return fItems.CountItems(); +} + +// GetResourcesSize +uint32 +ResourceFile::GetResourcesSize() const +{ + if (!fInfoTableItem || fFile.InitCheck()) + throw Exception("Resource file not initialized."); + // header + uint32 size = kResourcesHeaderSize; + // index section + uint32 indexSectionSize = kResourceIndexSectionHeaderSize + + fResourceCount * kResourceIndexEntrySize; + indexSectionSize = align_value(indexSectionSize, + kResourceIndexSectionAlignment); + size += indexSectionSize; + // unknown section + size += kUnknownResourceSectionSize; + // data + uint32 dataSize = 0; + for (int32 i = 0; i < fResourceCount; i++) { + ResourceItem* item = ItemAt(i); + dataSize += item->GetSize(); + } + size += dataSize; + // info table + uint32 infoTableSize = 0; + type_code type = 0; + for (int32 i = 0; i < fResourceCount; i++) { + ResourceItem* item = ItemAt(i); + if (i == 0 || type != item->GetType()) { + if (i != 0) + infoTableSize += kResourceInfoSeparatorSize; + type = item->GetType(); + infoTableSize += kMinResourceInfoBlockSize; + } else + infoTableSize += kMinResourceInfoSize; + uint32 nameLen = strlen(item->GetName()); + if (nameLen != 0) + infoTableSize += nameLen + 1; + } + infoTableSize += kResourceInfoSeparatorSize + kResourceInfoTableEndSize; + size += infoTableSize; + return size; +} + +// WriteResources +uint32 +ResourceFile::WriteResources(void* buffer, uint32 bufferSize) +{ + // calculate sizes and offsets + // header + uint32 size = kResourcesHeaderSize; + // index section + uint32 indexSectionOffset = size; + uint32 indexSectionSize = kResourceIndexSectionHeaderSize + + fResourceCount * kResourceIndexEntrySize; + indexSectionSize = align_value(indexSectionSize, + kResourceIndexSectionAlignment); + size += indexSectionSize; + // unknown section + uint32 unknownSectionOffset = size; + uint32 unknownSectionSize = kUnknownResourceSectionSize; + size += unknownSectionSize; + // data + uint32 dataOffset = size; + uint32 dataSize = 0; + for (int32 i = 0; i < fResourceCount; i++) { + ResourceItem* item = ItemAt(i); + dataSize += item->GetSize(); + } + size += dataSize; + // info table + uint32 infoTableOffset = size; + uint32 infoTableSize = 0; + type_code type = 0; + for (int32 i = 0; i < fResourceCount; i++) { + ResourceItem* item = ItemAt(i); + if (i == 0 || type != item->GetType()) { + if (i != 0) + infoTableSize += kResourceInfoSeparatorSize; + type = item->GetType(); + infoTableSize += kMinResourceInfoBlockSize; + } else + infoTableSize += kMinResourceInfoSize; + uint32 nameLen = strlen(item->GetName()); + if (nameLen != 0) + infoTableSize += nameLen + 1; + } + infoTableSize += kResourceInfoSeparatorSize + kResourceInfoTableEndSize; + size += infoTableSize; + // check whether the buffer is large enough + if (!buffer) + throw Exception("Supplied buffer is NULL."); + if (bufferSize < size) + throw Exception("Supplied buffer is too small."); + // write... + void* data = buffer; + // header + resources_header* resourcesHeader = (resources_header*)data; + resourcesHeader->rh_resources_magic = kResourcesHeaderMagic; + resourcesHeader->rh_resource_count = fResourceCount; + resourcesHeader->rh_index_section_offset = indexSectionOffset; + resourcesHeader->rh_admin_section_size = indexSectionOffset + + indexSectionSize; + for (int32 i = 0; i < 13; i++) + resourcesHeader->rh_pad[i] = 0; + // index section + // header + data = skip_bytes(buffer, indexSectionOffset); + resource_index_section_header* indexHeader + = (resource_index_section_header*)data; + indexHeader->rish_index_section_offset = indexSectionOffset; + indexHeader->rish_index_section_size = indexSectionSize; + indexHeader->rish_unknown_section_offset = unknownSectionOffset; + indexHeader->rish_unknown_section_size = unknownSectionSize; + indexHeader->rish_info_table_offset = infoTableOffset; + indexHeader->rish_info_table_size = infoTableSize; + fill_pattern(buffer, &indexHeader->rish_unused_data1, 1); + fill_pattern(buffer, indexHeader->rish_unused_data2, 25); + fill_pattern(buffer, &indexHeader->rish_unused_data3, 1); + // index table + data = skip_bytes(data, kResourceIndexSectionHeaderSize); + resource_index_entry* entry = (resource_index_entry*)data; + uint32 entryOffset = dataOffset; + for (int32 i = 0; i < fResourceCount; i++, entry++) { + ResourceItem* item = ItemAt(i); + uint32 entrySize = item->GetSize(); + entry->rie_offset = entryOffset; + entry->rie_size = entrySize; + entry->rie_pad = 0; + entryOffset += entrySize; + } + // padding + unknown section + data = skip_bytes(buffer, dataOffset); + fill_pattern(buffer, entry, data); + // data + for (int32 i = 0; i < fResourceCount; i++) { + ResourceItem* item = ItemAt(i); + status_t error = item->LoadData(fFile); + if (error != B_OK) + throw Exception(error, "Error loading resource data."); + uint32 entrySize = item->GetSize(); + memcpy(data, item->GetData(), entrySize); + data = skip_bytes(data, entrySize); + } + // info table + data = skip_bytes(buffer, infoTableOffset); + type = 0; + for (int32 i = 0; i < fResourceCount; i++) { + ResourceItem* item = ItemAt(i); + resource_info* info = NULL; + if (i == 0 || type != item->GetType()) { + if (i != 0) { + resource_info_separator* separator + = (resource_info_separator*)data; + separator->ris_value1 = 0xffffffff; + separator->ris_value2 = 0xffffffff; + data = skip_bytes(data, kResourceInfoSeparatorSize); + } + type = item->GetType(); + resource_info_block* infoBlock = (resource_info_block*)data; + infoBlock->rib_type = type; + info = infoBlock->rib_info; + } else + info = (resource_info*)data; + // info + info->ri_id = item->GetID(); + info->ri_index = i + 1; + info->ri_name_size = 0; + data = info->ri_name; + uint32 nameLen = strlen(item->GetName()); + if (nameLen != 0) { + memcpy(info->ri_name, item->GetName(), nameLen + 1); + data = skip_bytes(data, nameLen + 1); + info->ri_name_size = nameLen + 1; + } + } + // separator + resource_info_separator* separator = (resource_info_separator*)data; + separator->ris_value1 = 0xffffffff; + separator->ris_value2 = 0xffffffff; + // table end + data = skip_bytes(data, kResourceInfoSeparatorSize); + resource_info_table_end* tableEnd = (resource_info_table_end*)data; + void* infoTable = skip_bytes(buffer, infoTableOffset); + tableEnd->rite_check_sum = calculate_checksum(infoTable, + infoTableSize - kResourceInfoTableEndSize); + tableEnd->rite_terminator = 0; + // final check + data = skip_bytes(data, kResourceInfoTableEndSize); + uint32 bytesWritten = (char*)data - (char*)buffer; + if (bytesWritten != size) { + throw Exception("Bad boy error: Wrote %lu bytes, though supposed to " + "write %lu bytes.", bytesWritten, size); + } + return size; +} + +// WriteTest +void +ResourceFile::WriteTest() +{ + uint32 size = GetResourcesSize(); + if (size != fFileSize) { + throw Exception("Calculated resources size differs from actual size " + "in file: %lu vs %Ld.", size, fFileSize); + } + char* buffer1 = new char[size]; + char* buffer2 = new char[size]; + try { + WriteResources(buffer1, size); + read_exactly(fFile, 0, buffer2, size, + "Write test: Error reading resources."); + for (uint32 i = 0; i < size; i++) { + if (buffer1[i] != buffer2[i]) { + off_t filePosition = fFile.GetOffset() + i; + throw Exception("Written resources differ from those in file. " + "First difference at byte %lu (file position " + "%Ld): %x vs %x.", i, filePosition, + (int)buffer1[i] & 0xff, + (int)buffer2[i] & 0xff); + } + } + } catch (Exception exception) { + delete[] buffer1; + delete[] buffer2; + throw exception; + } + delete[] buffer1; + delete[] buffer2; +} + + + +// PrintToStream +void +ResourceFile::PrintToStream(bool longInfo) +{ + if (longInfo) { + off_t resourcesOffset = fFile.GetOffset(); + printf("ResourceFile:\n"); + printf("file type : %s\n", kFileTypeNames[fFileType]); + printf("endianess : %s\n", + (fHostEndianess == (bool)B_HOST_IS_LENDIAN) ? "little" : "big"); + printf("resource section offset: 0x%08Lx (%Ld)\n", resourcesOffset, + resourcesOffset); + if (fInfoTableItem) { + int32 offset = fInfoTableItem->GetOffset(); + int32 size = fInfoTableItem->GetSize(); + printf("resource info table : offset: 0x%08lx (%ld), " + "size: 0x%08lx (%ld)\n", offset, offset, size, size); + } + printf("number of resources : %ld\n", fResourceCount); + for (int32 i = 0; i < fResourceCount; i++) { + ResourceItem* item = ItemAt(i); + item->PrintToStream(); + } + } else { + printf(" Type ID Size Name\n"); + printf(" ------ ----- -------- --------------------\n"); + for (int32 i = 0; i < fResourceCount; i++) { + ResourceItem* item = ItemAt(i); + type_code type = item->GetType(); + char typeName[4] = { type >> 24, (type >> 16) & 0xff, + (type >> 8) & 0xff, type & 0xff }; + printf(" '%.4s' %5ld %8lu %s\n", typeName, item->GetID(), + item->GetSize(), item->GetName()); + } + } +} + + +// _InitFile +void +ResourceFile::_InitFile(BFile& file) +{ + status_t error = B_OK; + fFile.Unset(); + // read the first four bytes, and check, if they identify a resource file + char magic[4]; + read_exactly(file, 0, magic, 4, "Failed to read magic number."); + if (!memcmp(magic, kX86ResourceFileMagic, 4)) { + // x86 resource file + fHostEndianess = B_HOST_IS_LENDIAN; + fFileType = FILE_TYPE_X86_RESOURCE; + fFile.SetTo(file, kX86ResourcesOffset); + } else if (!memcmp(magic, kPEFFileMagic1, 4)) { + PEFContainerHeader pefHeader; + read_exactly(file, 0, &pefHeader, kPEFContainerHeaderSize, + "Failed to read PEF container header."); + if (!memcmp(pefHeader.tag2, kPPCResourceFileMagic, 4)) { + // PPC resource file + fHostEndianess = B_HOST_IS_BENDIAN; + fFileType = FILE_TYPE_PPC_RESOURCE; + fFile.SetTo(file, kPPCResourcesOffset); + } else if (!memcmp(pefHeader.tag2, kPEFFileMagic2, 4)) { + // PEF file + fFileType = FILE_TYPE_PEF; + _InitPEFFile(file, pefHeader); + } else + throw Exception("File is not a resource file."); + } else if (!memcmp(magic, kELFFileMagic, 4)) { + // ELF file + fFileType = FILE_TYPE_ELF; + _InitELFFile(file); + } else if (!memcmp(magic, kX86ResourceFileMagic, 2)) { + // x86 resource file with screwed magic? + Warnings::AddCurrentWarning("File magic is 0x%08lx. Should be 0x%08lx " + "for x86 resource file. Try anyway.", + ntohl(*(uint32*)magic), + ntohl(*(uint32*)kX86ResourceFileMagic)); + fHostEndianess = B_HOST_IS_LENDIAN; + fFileType = FILE_TYPE_X86_RESOURCE; + fFile.SetTo(file, kX86ResourcesOffset); + } else + throw Exception("File is not a resource file."); + error = fFile.InitCheck(); + if (error != B_OK) + throw Exception(error, "Failed to initialize resource file."); + // get the file size + fFileSize = 0; + error = fFile.GetSize(&fFileSize); + if (error != B_OK) + throw Exception(error, "Failed to get the file size."); +} + +// _InitELFFile +void +ResourceFile::_InitELFFile(BFile& file) +{ + status_t error = B_OK; + // get the file size + off_t fileSize = 0; + error = file.GetSize(&fileSize); + if (error != B_OK) + throw Exception(error, "Failed to get the file size."); + // read ELF header + Elf32_Ehdr fileHeader; + read_exactly(file, 0, &fileHeader, sizeof(Elf32_Ehdr), + "Failed to read ELF header."); + // check data encoding (endianess) + switch (fileHeader.e_ident[EI_DATA]) { + case ELFDATA2LSB: + fHostEndianess = B_HOST_IS_LENDIAN; + break; + case ELFDATA2MSB: + fHostEndianess = B_HOST_IS_BENDIAN; + break; + default: + case ELFDATANONE: + throw Exception("Unsupported ELF data encoding."); + break; + } + // get the header values + uint32 headerSize = _GetUInt16(fileHeader.e_ehsize); + uint32 programHeaderTableOffset = _GetUInt32(fileHeader.e_phoff); + uint32 programHeaderSize = _GetUInt16(fileHeader.e_phentsize); + uint32 programHeaderCount = _GetUInt16(fileHeader.e_phnum); + uint32 sectionHeaderTableOffset = _GetUInt32(fileHeader.e_shoff); + uint32 sectionHeaderSize = _GetUInt16(fileHeader.e_shentsize); + uint32 sectionHeaderCount = _GetUInt16(fileHeader.e_shnum); + bool hasProgramHeaderTable = (programHeaderTableOffset != 0); + bool hasSectionHeaderTable = (sectionHeaderTableOffset != 0); +//printf("headerSize : %lu\n", headerSize); +//printf("programHeaderTableOffset: %lu\n", programHeaderTableOffset); +//printf("programHeaderSize : %lu\n", programHeaderSize); +//printf("programHeaderCount : %lu\n", programHeaderCount); +//printf("sectionHeaderTableOffset: %lu\n", sectionHeaderTableOffset); +//printf("sectionHeaderSize : %lu\n", sectionHeaderSize); +//printf("sectionHeaderCount : %lu\n", sectionHeaderCount); + // check the sanity of the header values + // ELF header size + if (headerSize < sizeof(Elf32_Ehdr) || headerSize > kMaxELFHeaderSize) { + throw Exception("Invalid ELF header: invalid ELF header size: %lu.", + headerSize); + } + uint32 resourceOffset = headerSize; + uint32 resourceAlignment = 0; + // program header table offset and entry count/size + uint32 programHeaderTableSize = 0; + if (hasProgramHeaderTable) { + if (programHeaderTableOffset < headerSize + || programHeaderTableOffset > fileSize) { + throw Exception("Invalid ELF header: invalid program header table " + "offset: %lu.", programHeaderTableOffset); + } + programHeaderTableSize = programHeaderSize * programHeaderCount; + if (programHeaderSize < sizeof(Elf32_Phdr) + || programHeaderTableOffset + programHeaderTableSize > fileSize) { + throw Exception("Invalid ELF header: program header table exceeds " + "file: %lu.", + programHeaderTableOffset + programHeaderTableSize); + } + resourceOffset = max(resourceOffset, programHeaderTableOffset + + programHeaderTableSize); + // iterate through the program headers + for (int32 i = 0; i < (int32)programHeaderCount; i++) { + uint32 shOffset = programHeaderTableOffset + i * programHeaderSize; + Elf32_Phdr programHeader; + read_exactly(file, shOffset, &programHeader, sizeof(Elf32_Shdr), + "Failed to read ELF program header."); + // get the header values + uint32 type = _GetUInt32(programHeader.p_type); + uint32 offset = _GetUInt32(programHeader.p_offset); + uint32 size = _GetUInt32(programHeader.p_filesz); + uint32 alignment = _GetUInt32(programHeader.p_align); +//printf("segment: type: %ld, offset: %lu, size: %lu, alignment: %lu\n", +//type, offset, size, alignment); + // check the values + // PT_NULL marks the header unused, + if (type != PT_NULL) { + if (/*offset < headerSize ||*/ offset > fileSize) { + throw Exception("Invalid ELF program header: invalid " + "program offset: %lu.", offset); + } + uint32 segmentEnd = offset + size; + if (segmentEnd > fileSize) { + throw Exception("Invalid ELF section header: segment " + "exceeds file: %lu.", segmentEnd); + } + resourceOffset = max(resourceOffset, segmentEnd); + resourceAlignment = max(resourceAlignment, alignment); + } + } + } + // section header table offset and entry count/size + uint32 sectionHeaderTableSize = 0; + if (hasSectionHeaderTable) { + if (sectionHeaderTableOffset < headerSize + || sectionHeaderTableOffset > fileSize) { + throw Exception("Invalid ELF header: invalid section header table " + "offset: %lu.", sectionHeaderTableOffset); + } + sectionHeaderTableSize = sectionHeaderSize * sectionHeaderCount; + if (sectionHeaderSize < sizeof(Elf32_Shdr) + || sectionHeaderTableOffset + sectionHeaderTableSize > fileSize) { + throw Exception("Invalid ELF header: section header table exceeds " + "file: %lu.", + sectionHeaderTableOffset + sectionHeaderTableSize); + } + resourceOffset = max(resourceOffset, sectionHeaderTableOffset + + sectionHeaderTableSize); + // iterate through the section headers + for (int32 i = 0; i < (int32)sectionHeaderCount; i++) { + uint32 shOffset = sectionHeaderTableOffset + i * sectionHeaderSize; + Elf32_Shdr sectionHeader; + read_exactly(file, shOffset, §ionHeader, sizeof(Elf32_Shdr), + "Failed to read ELF section header."); + // get the header values + uint32 type = _GetUInt32(sectionHeader.sh_type); + uint32 offset = _GetUInt32(sectionHeader.sh_offset); + uint32 size = _GetUInt32(sectionHeader.sh_size); +//printf("section: type: %ld, offset: %lu, size: %lu\n", type, offset, size); + // check the values + // SHT_NULL marks the header unused, + // SHT_NOBITS sections take no space in the file + if (type != SHT_NULL && type != SHT_NOBITS) { + if (offset < headerSize || offset > fileSize) { + throw Exception("Invalid ELF section header: invalid " + "section offset: %lu.", offset); + } + uint32 sectionEnd = offset + size; + if (sectionEnd > fileSize) { + throw Exception("Invalid ELF section header: section " + "exceeds file: %lu.", sectionEnd); + } + resourceOffset = max(resourceOffset, sectionEnd); + } + } + } +//printf("resourceOffset: %lu\n", resourceOffset); + // align the offset + if (resourceAlignment < kELFMinResourceAlignment) + resourceAlignment = kELFMinResourceAlignment; + if (resourceAlignment > kELFMaxResourceAlignment) { + throw Exception("The ELF object file requires an invalid alignment: " + "%lu.", resourceAlignment); + } + resourceOffset = align_value(resourceOffset, resourceAlignment); +//printf("resourceOffset: %lu\n", resourceOffset); + if (resourceOffset >= fileSize) + throw Exception("The ELF object file does not contain resources."); + // fine, init the offset file + fFile.SetTo(file, resourceOffset); +} + +// _InitPEFFile +void +ResourceFile::_InitPEFFile(BFile& file, const PEFContainerHeader& pefHeader) +{ + status_t error = B_OK; + // get the file size + off_t fileSize = 0; + error = file.GetSize(&fileSize); + if (error != B_OK) + throw Exception(error, "Failed to get the file size."); + // check architecture -- we support PPC only + if (memcmp(pefHeader.architecture, kPEFArchitecturePPC, 4)) + throw Exception("PEF file architecture is not PPC."); + fHostEndianess = B_HOST_IS_BENDIAN; + // get the section count + uint16 sectionCount = _GetUInt16(pefHeader.sectionCount); + // iterate through the PEF sections headers + uint32 sectionHeaderTableOffset = kPEFContainerHeaderSize; + uint32 sectionHeaderTableEnd + = sectionHeaderTableOffset + sectionCount * kPEFSectionHeaderSize; + uint32 resourceOffset = sectionHeaderTableEnd; + for (int32 i = 0; i < (int32)sectionCount; i++) { + uint32 shOffset = sectionHeaderTableOffset + i * kPEFSectionHeaderSize; + PEFSectionHeader sectionHeader; + read_exactly(file, shOffset, §ionHeader, kPEFSectionHeaderSize, + "Failed to read PEF section header."); + // get the header values + uint32 offset = _GetUInt32(sectionHeader.containerOffset); + uint32 size = _GetUInt32(sectionHeader.packedSize); + // check the values + if (offset < sectionHeaderTableEnd || offset > fileSize) { + throw Exception("Invalid PEF section header: invalid " + "section offset: %lu.", offset); + } + uint32 sectionEnd = offset + size; + if (sectionEnd > fileSize) { + throw Exception("Invalid PEF section header: section " + "exceeds file: %lu.", sectionEnd); + } + resourceOffset = max(resourceOffset, sectionEnd); + } + // init the offset file + fFile.SetTo(file, resourceOffset); +} + +// _ReadHeader +void +ResourceFile::_ReadHeader() +{ + // read the header + resources_header header; + read_exactly(fFile, 0, &header, kResourcesHeaderSize, + "Failed to read the header."); + // check the header + // magic + uint32 magic = _GetUInt32(header.rh_resources_magic); + if (magic == kResourcesHeaderMagic) { + // everything is fine + } else if (B_SWAP_INT32(magic) == kResourcesHeaderMagic) { + const char* endianessStr[2] = { "little", "big" }; + int32 endianess + = (fHostEndianess == ((bool)B_HOST_IS_LENDIAN ? 0 : 1)); + Warnings::AddCurrentWarning("Endianess seems to be %s, although %s " + "was expected.", + endianessStr[1 - endianess], + endianessStr[endianess]); + fHostEndianess = !fHostEndianess; + } else + throw Exception("Invalid resources header magic."); + // resource count + uint32 resourceCount = _GetUInt32(header.rh_resource_count); + if (resourceCount > kMaxResourceCount) + throw Exception("Bad number of resources."); + // index section offset + uint32 indexSectionOffset = _GetUInt32(header.rh_index_section_offset); + if (indexSectionOffset != kResourceIndexSectionOffset) { + throw Exception("Unexpected resource index section offset. Is: %lu, " + "should be: %lu.", indexSectionOffset, + kResourceIndexSectionOffset); + } + // admin section size + uint32 indexSectionSize = kResourceIndexSectionHeaderSize + + kResourceIndexEntrySize * resourceCount; + indexSectionSize = align_value(indexSectionSize, + kResourceIndexSectionAlignment); + uint32 adminSectionSize = _GetUInt32(header.rh_admin_section_size); + if (adminSectionSize != indexSectionOffset + indexSectionSize) { + throw Exception("Unexpected resource admin section size. Is: %lu, " + "should be: %lu.", adminSectionSize, + indexSectionOffset + indexSectionSize); + } + // set the resource count + fResourceCount = resourceCount; +} + +// _ReadIndex +void +ResourceFile::_ReadIndex() +{ + // read the header + resource_index_section_header header; + read_exactly(fFile, kResourceIndexSectionOffset, &header, + kResourceIndexSectionHeaderSize, + "Failed to read the resource index section header."); + // check the header + // index section offset + uint32 indexSectionOffset = _GetUInt32(header.rish_index_section_offset); + if (indexSectionOffset != kResourceIndexSectionOffset) { + throw Exception("Unexpected resource index section offset. Is: %lu, " + "should be: %lu.", indexSectionOffset, + kResourceIndexSectionOffset); + } + // index section size + uint32 expectedIndexSectionSize = kResourceIndexSectionHeaderSize + + kResourceIndexEntrySize * fResourceCount; + expectedIndexSectionSize = align_value(expectedIndexSectionSize, + kResourceIndexSectionAlignment); + uint32 indexSectionSize = _GetUInt32(header.rish_index_section_size); + if (indexSectionSize != expectedIndexSectionSize) { + throw Exception("Unexpected resource index section size. Is: %lu, " + "should be: %lu.", indexSectionSize, + expectedIndexSectionSize); + } + // unknown section offset + uint32 unknownSectionOffset + = _GetUInt32(header.rish_unknown_section_offset); + if (unknownSectionOffset != indexSectionOffset + indexSectionSize) { + throw Exception("Unexpected resource index section size. Is: %lu, " + "should be: %lu.", unknownSectionOffset, + indexSectionOffset + indexSectionSize); + } + // unknown section size + uint32 unknownSectionSize = _GetUInt32(header.rish_unknown_section_size); + if (unknownSectionSize != kUnknownResourceSectionSize) { + throw Exception("Unexpected resource index section offset. Is: %lu, " + "should be: %lu.", unknownSectionOffset, + kUnknownResourceSectionSize); + } + // info table offset and size + uint32 infoTableOffset = _GetUInt32(header.rish_info_table_offset); + uint32 infoTableSize = _GetUInt32(header.rish_info_table_size); + if (infoTableOffset + infoTableSize > fFileSize) + throw Exception("Invalid info table location."); + fInfoTableItem = new ResourceItem; + fInfoTableItem->SetLocation(infoTableOffset, infoTableSize); + // read the index entries + uint32 indexTableOffset = indexSectionOffset + + kResourceIndexSectionHeaderSize; + int32 maxResourceCount = (unknownSectionOffset - indexTableOffset) + / kResourceIndexEntrySize; + int32 actualResourceCount = 0; + bool tableEndReached = false; + for (int32 i = 0; !tableEndReached && i < maxResourceCount; i++) { + // read one entry + tableEndReached = !_ReadIndexEntry(i, indexTableOffset, + (i >= fResourceCount)); + if (!tableEndReached) + actualResourceCount++; + } + // check resource count + if (actualResourceCount != fResourceCount) { + if (actualResourceCount > fResourceCount) { + Warnings::AddCurrentWarning("Resource index table contains " + "%ld entries, although it should be " + "%ld only.", actualResourceCount, + fResourceCount); + } + fResourceCount = actualResourceCount; + } +} + +// _ReadIndexEntry +bool +ResourceFile::_ReadIndexEntry(int32 index, uint32 tableOffset, bool peekAhead) +{ + bool result = true; + resource_index_entry entry; + // read one entry + off_t entryOffset = tableOffset + index * kResourceIndexEntrySize; + read_exactly(fFile, entryOffset, &entry, kResourceIndexEntrySize, + "Failed to read a resource index entry."); + // check, if the end is reached early + if (result && check_pattern(entryOffset, &entry, + kResourceIndexEntrySize / 4, fHostEndianess)) { + if (!peekAhead) { + Warnings::AddCurrentWarning("Unexpected end of resource index " + "table at index: %ld (/%ld).", + index + 1, fResourceCount); + } + result = false; + } + uint32 offset = _GetUInt32(entry.rie_offset); + uint32 size = _GetUInt32(entry.rie_size); + // check the location + if (result && offset + size > fFileSize) { + if (peekAhead) { + Warnings::AddCurrentWarning("Invalid data after resource index " + "table."); + } else { + throw Exception("Invalid resource index entry: index: %ld, " + "offset: %lu (%lx), size: %lu (%lx).", index + 1, + offset, offset, size, size); + } + result = false; + } + // add the entry + if (result) { + ResourceItem* item = new ResourceItem; + item->SetLocation(offset, size); + AddItem(item, index); + } + return result; +} + +// _ReadInfoTable +void +ResourceFile::_ReadInfoTable() +{ + status_t error = B_OK; + error = fInfoTableItem->LoadData(fFile); + if (error != B_OK) + throw Exception(error, "Failed to read resource info table."); + const void* tableData = fInfoTableItem->GetData(); + int32 dataSize = fInfoTableItem->GetSize(); + // + bool* readIndices = new bool[fResourceCount + 1]; // + 1 => always > 0 + for (int32 i = 0; i < fResourceCount; i++) + readIndices[i] = false; + AutoDeleter deleter(readIndices, true); + MemArea area(tableData, dataSize); + const void* data = tableData; + // check the table end/check sum + if (_ReadInfoTableEnd(data, dataSize)) + dataSize -= kResourceInfoTableEndSize; + // read the infos + int32 resourceIndex = 1; + uint32 minRemainderSize + = kMinResourceInfoBlockSize + kResourceInfoSeparatorSize; + while (area.check(data, minRemainderSize)) { + // read a resource block + if (!area.check(data, kMinResourceInfoBlockSize)) { + throw Exception("Unexpected end of resource info table at index " + "%ld.", resourceIndex); + } + const resource_info_block* infoBlock + = (const resource_info_block*)data; + type_code type = _GetUInt32(infoBlock->rib_type); + // read the infos of this block + const resource_info* info = infoBlock->rib_info; + while (info) { + data = _ReadResourceInfo(area, info, type, readIndices); + // prepare for next iteration, if there is another info + if (!area.check(data, kResourceInfoSeparatorSize)) { + throw Exception("Unexpected end of resource info table after " + "index %ld.", resourceIndex); + } + const resource_info_separator* separator + = (const resource_info_separator*)data; + if (_GetUInt32(separator->ris_value1) == 0xffffffff + && _GetUInt32(separator->ris_value2) == 0xffffffff) { + // info block ends + info = NULL; + data = skip_bytes(data, kResourceInfoSeparatorSize); + } else { + // another info follows + info = (const resource_info*)data; + } + resourceIndex++; + } + // end of the info block + } + // handle special case: empty resource info table + if (resourceIndex == 1) { + if (!area.check(data, kResourceInfoSeparatorSize)) { + throw Exception("Unexpected end of resource info table."); + } + const resource_info_separator* tableTerminator + = (const resource_info_separator*)data; + if (_GetUInt32(tableTerminator->ris_value1) != 0xffffffff + || _GetUInt32(tableTerminator->ris_value2) != 0xffffffff) { + throw Exception("The resource info table ought to be empty, but " + "is not properly terminated."); + } + data = skip_bytes(data, kResourceInfoSeparatorSize); + } + // Check, if the correct number of bytes are remaining. + uint32 bytesLeft = (const char*)tableData + dataSize - (const char*)data; + if (bytesLeft != 0) { + throw Exception("Error at the end of the resource info table: %lu " + "bytes are remaining.", bytesLeft); + } + // check, if all items have been initialized + for (int32 i = fResourceCount - 1; i >= 0; i--) { + if (!readIndices[i]) { + Warnings::AddCurrentWarning("Resource item at index %ld " + "has no info. Item removed.", i + 1); + if (ResourceItem* item = RemoveItem(i)) + delete item; + fResourceCount--; + } + } +} + +// _ReadInfoTableEnd +bool +ResourceFile::_ReadInfoTableEnd(const void* data, int32 dataSize) +{ + bool hasTableEnd = true; + if ((uint32)dataSize < kResourceInfoSeparatorSize) + throw Exception("Info table is too short."); + if ((uint32)dataSize < kResourceInfoTableEndSize) + hasTableEnd = false; + if (hasTableEnd) { + const resource_info_table_end* tableEnd + = (const resource_info_table_end*) + skip_bytes(data, dataSize - kResourceInfoTableEndSize); + if (_GetInt32(tableEnd->rite_terminator) != 0) + hasTableEnd = false; + if (hasTableEnd) { + dataSize -= kResourceInfoTableEndSize; + // checksum + uint32 checkSum = calculate_checksum(data, dataSize); + uint32 fileCheckSum = _GetUInt32(tableEnd->rite_check_sum); + if (checkSum != fileCheckSum) { + throw Exception("Invalid resource info table check sum: In " + "file: %lx, calculated: %lx.", fileCheckSum, + checkSum); + } + } + } + if (!hasTableEnd) + Warnings::AddCurrentWarning("resource info table has no check sum."); + return hasTableEnd; +} + +// _ReadResourceInfo +const void* +ResourceFile::_ReadResourceInfo(const MemArea& area, const resource_info* info, + type_code type, bool* readIndices) +{ + int32 id = _GetInt32(info->ri_id); + int32 index = _GetInt32(info->ri_index); + uint16 nameSize = _GetUInt16(info->ri_name_size); + const char* name = info->ri_name; + // check the values + bool ignore = false; + // index + if (index < 1 || index > fResourceCount) { + Warnings::AddCurrentWarning("Invalid index field in resource " + "info table: %lu.", index); + ignore = true; + } + if (!ignore) { + if (readIndices[index - 1]) { + throw Exception("Multiple resource infos with the same index " + "field: %ld.", index); + } + readIndices[index - 1] = true; + } + // name size + if (!area.check(name, nameSize)) { + throw Exception("Invalid name size (%d) for index %ld in " + "resource info table.", (int)nameSize, index); + } + // check, if name is null terminated + if (name[nameSize - 1] != 0) { + Warnings::AddCurrentWarning("Name for index %ld in " + "resource info table is not null " + "terminated.", index); + } + // set the values + if (!ignore) { + BString resourceName(name, nameSize); + if (ResourceItem* item = ItemAt(index - 1)) + item->SetIdentity(type, id, resourceName.String()); + else { + throw Exception("Unexpected error: No resource item at index " + "%ld.", index); + } + } + return skip_bytes(name, nameSize); +} diff --git a/src/tools/restest/ResourceFile.h b/src/tools/restest/ResourceFile.h new file mode 100644 index 0000000000..035c9d58e4 --- /dev/null +++ b/src/tools/restest/ResourceFile.h @@ -0,0 +1,105 @@ +// ResourceFile.h + +#ifndef RESOURCE_FILE_H +#define RESOURCE_FILE_H + +#include +#include + +#include "OffsetFile.h" + +class Exception; +class ResourceItem; +struct MemArea; +struct resource_info; +struct PEFContainerHeader; + +class ResourceFile { +public: + ResourceFile(); + virtual ~ResourceFile(); + + void Init(BFile& file); // throws Exception + void Unset(); + status_t InitCheck() const; + + bool AddItem(ResourceItem* item, int32 index = -1); + ResourceItem* RemoveItem(int32 index); + bool RemoveItem(ResourceItem* item); + int32 IndexOf(ResourceItem* item) const; + ResourceItem* ItemAt(int32 index) const; + int32 CountItems() const; + + uint32 GetResourcesSize() const; + uint32 WriteResources(void* buffer, uint32 size); + void WriteTest(); + + void PrintToStream(bool longInfo = true); + +private: + void _InitFile(BFile& file); + void _InitELFFile(BFile& file); + void _InitPEFFile(BFile& file, + const PEFContainerHeader& pefHeader); + void _ReadHeader(); + void _ReadIndex(); + bool _ReadIndexEntry(int32 index, + uint32 tableOffset, + bool peekAhead); + void _ReadInfoTable(); + bool _ReadInfoTableEnd(const void* data, + int32 dataSize); + const void* _ReadResourceInfo(const MemArea& area, + const resource_info* info, + type_code type, + bool* readIndices); + + inline int16 _GetInt16(int16 value); + inline uint16 _GetUInt16(uint16 value); + inline int32 _GetInt32(int32 value); + inline uint32 _GetUInt32(uint32 value); + +private: + BList fItems; + OffsetFile fFile; + uint32 fFileType; + off_t fFileSize; + int32 fResourceCount; + ResourceItem* fInfoTableItem; + bool fHostEndianess; +}; + +// _GetInt16 +inline +int16 +ResourceFile::_GetInt16(int16 value) +{ + return (fHostEndianess ? value : B_SWAP_INT16(value)); +} + +// _GetUInt16 +inline +uint16 +ResourceFile::_GetUInt16(uint16 value) +{ + return (fHostEndianess ? value : B_SWAP_INT16(value)); +} + +// _GetInt32 +inline +int32 +ResourceFile::_GetInt32(int32 value) +{ + return (fHostEndianess ? value : B_SWAP_INT32(value)); +} + +// _GetUInt32 +inline +uint32 +ResourceFile::_GetUInt32(uint32 value) +{ + return (fHostEndianess ? value : B_SWAP_INT32(value)); +} + + +#endif // RESOURCE_FILE_H diff --git a/src/tools/restest/ResourceItem.cpp b/src/tools/restest/ResourceItem.cpp new file mode 100644 index 0000000000..f686ee8e08 --- /dev/null +++ b/src/tools/restest/ResourceItem.cpp @@ -0,0 +1,205 @@ +// ResourceItem.cpp + +#include "ResourceItem.h" + +#include +#include + +#include + +// constructor +ResourceItem::ResourceItem() + : fOffset(0), + fSize(0), + fType(0), + fID(0), + fName(), + fData(NULL) +{ +} + +// destructor +ResourceItem::~ResourceItem() +{ + UnsetData(); +} + +// SetLocation +void +ResourceItem::SetLocation(roff_t offset, roff_t size) +{ + SetOffset(offset); + SetSize(size); +} + +// SetIdentity +void +ResourceItem::SetIdentity(type_code type, int32 id, const char* name) +{ + fType = type; + fID = id; + fName = name; +} + +// SetOffset +void +ResourceItem::SetOffset(roff_t offset) +{ + fOffset = offset; +} + +// GetOffset +ResourceItem::roff_t +ResourceItem::GetOffset() const +{ + return fOffset; +} + +// SetSize +void +ResourceItem::SetSize(roff_t size) +{ + if (size != fSize) { + UnsetData(); + fSize = size; + } +} + +// GetSize +ResourceItem::roff_t +ResourceItem::GetSize() const +{ + return fSize; +} + +// SetType +void +ResourceItem::SetType(type_code type) +{ + fType = type; +} + +// GetType +type_code +ResourceItem::GetType() const +{ + return fType; +} + +// SetID +void +ResourceItem::SetID(int32 id) +{ + fID = id; +} + +// GetID +int32 +ResourceItem::GetID() const +{ + return fID; +} + +// SetName +void +ResourceItem::SetName(const char* name) +{ + fName = name; +} + +// GetName +const char* +ResourceItem::GetName() const +{ + return fName.String(); +} + +// SetData +void +ResourceItem::SetData(const void* data, roff_t size) +{ + if (size < 0) + size = fSize; + // set the new data + if (data) { + AllocData(size); + if (fSize > 0) + memcpy(fData, data, fSize); + } else + UnsetData(); +} + +// UnsetData +void +ResourceItem::UnsetData() +{ + if (fData) { + delete[] (char*)fData; + fData = NULL; + } +} + +// AllocData +void* +ResourceItem::AllocData(roff_t size) +{ + if (size >= 0) + SetSize(size); + if (!fData && fSize > 0) + fData = new char*[fSize]; + return fData; +} + +// GetData +void* +ResourceItem::GetData() const +{ + return fData; +} + +// LoadData +status_t +ResourceItem::LoadData(BPositionIO& file, roff_t position, roff_t size) +{ + status_t error = B_OK; + AllocData(size); + if (position >= 0) + fOffset = position; + if (fData && fSize) { + ssize_t read = file.ReadAt(fOffset, fData, fSize); + if (read < 0) + error = read; + else if (read < fSize) + error = B_ERROR; + } + return error; +} + +// WriteData +status_t +ResourceItem::WriteData(BPositionIO& file) const +{ + status_t error = (fData ? B_OK : B_BAD_VALUE); + if (error == B_OK && fSize > 0) { + ssize_t written = file.WriteAt(fOffset, fData, fSize); + if (written < 0) + error = written; + else if (written < fSize) + error = B_FILE_ERROR; + } + return error; +} + +// PrintToStream +void +ResourceItem::PrintToStream() +{ + char typeName[4] = { fType >> 24, (fType >> 16) & 0xff, + (fType >> 8) & 0xff, fType & 0xff }; + printf("resource: offset: 0x%08lx (%10ld)\n", fOffset, fOffset); + printf(" size : 0x%08lx (%10ld)\n", fSize, fSize); + printf(" type : '%.4s' (0x%8lx)\n", typeName, fType); + printf(" id : %ld\n", fID); + printf(" name : `%s'\n", fName.String()); +} + diff --git a/src/tools/restest/ResourceItem.h b/src/tools/restest/ResourceItem.h new file mode 100644 index 0000000000..4732bd6138 --- /dev/null +++ b/src/tools/restest/ResourceItem.h @@ -0,0 +1,59 @@ +// ResourceItem.h + +#ifndef RESOURCE_ITEM_H +#define RESOURCE_ITEM_H + +#include +#include + +class BPositionIO; + +class ResourceItem { +public: + typedef int32 roff_t; + +public: + ResourceItem(); + virtual ~ResourceItem(); + + void SetLocation(roff_t offset, roff_t size); + void SetIdentity(type_code type, int32 id, + const char* name); + + void SetOffset(roff_t offset); + roff_t GetOffset() const; + + void SetSize(roff_t size); + roff_t GetSize() const; + + void SetType(type_code type); + type_code GetType() const; + + void SetID(int32 id); + int32 GetID() const; + + void SetName(const char* name); + const char* GetName() const; + + void SetData(const void* data, roff_t size = -1); + void UnsetData(); + void* AllocData(roff_t size = -1); + void* GetData() const; + + status_t LoadData(BPositionIO& file, + roff_t position = -1, + roff_t size = -1); + status_t WriteData(BPositionIO& file) const; + + void PrintToStream(); + +private: + roff_t fOffset; + roff_t fSize; + type_code fType; + int32 fID; + BString fName; + void* fData; +}; + +#endif // RESOURCE_ITEM_H diff --git a/src/tools/restest/ResourcesDefs.h b/src/tools/restest/ResourcesDefs.h new file mode 100644 index 0000000000..694451eef6 --- /dev/null +++ b/src/tools/restest/ResourcesDefs.h @@ -0,0 +1,105 @@ +// ResourcesDefs.h + +#ifndef RESOURCES_DEFS_H +#define RESOURCES_DEFS_H + +#include + +// x86 resource file constants +const char kX86ResourceFileMagic[4] = { 'R', 'S', 0, 0 }; +const uint32 kX86ResourcesOffset = 0x00000004; + +// PPC resource file constants +const char kPPCResourceFileMagic[4] = { 'r', 'e', 's', 'f' }; +const uint32 kPPCResourcesOffset = 0x00000028; + +// ELF file related constants +const uint32 kELFMinResourceAlignment = 32; + +// the unused data pattern +const uint32 kUnusedResourceDataPattern[3] = { + 0xffffffff, 0x000003e9, 0x00000000 +}; + + +// the resources header +struct resources_header { + uint32 rh_resources_magic; + uint32 rh_resource_count; + uint32 rh_index_section_offset; + uint32 rh_admin_section_size; + uint32 rh_pad[13]; +}; + +const uint32 kResourcesHeaderMagic = 0x444f1000; +const uint32 kResourceIndexSectionOffset = 0x00000044; +const uint32 kResourceIndexSectionAlignment = 0x00000600; +const uint32 kResourcesHeaderSize = 68; + + +// the header of the index section +struct resource_index_section_header { + uint32 rish_index_section_offset; + uint32 rish_index_section_size; + uint32 rish_unused_data1; + uint32 rish_unknown_section_offset; + uint32 rish_unknown_section_size; + uint32 rish_unused_data2[25]; + uint32 rish_info_table_offset; + uint32 rish_info_table_size; + uint32 rish_unused_data3; +}; + +const uint32 kUnknownResourceSectionSize = 0x00000168; +const uint32 kResourceIndexSectionHeaderSize = 132; + + +// an entry of the index table +struct resource_index_entry { + uint32 rie_offset; + uint32 rie_size; + uint32 rie_pad; +}; + +const uint32 kResourceIndexEntrySize = 12; + + +// a resource info +struct resource_info { + int32 ri_id; + int32 ri_index; + uint16 ri_name_size; + char ri_name[1]; +}; + +const uint32 kMinResourceInfoSize = 10; + + +// a resource info block +struct resource_info_block { + type_code rib_type; + resource_info rib_info[1]; +}; + +const uint32 kMinResourceInfoBlockSize = 4 + kMinResourceInfoSize; + + +// the structure separating resource info blocks +struct resource_info_separator { + uint32 ris_value1; + uint32 ris_value2; +}; + +const uint32 kResourceInfoSeparatorSize = 8; + + +// the end of the info table +struct resource_info_table_end { + uint32 rite_check_sum; + uint32 rite_terminator; +}; + +const uint32 kResourceInfoTableEndSize = 8; + + +#endif // RESOURCES_DEFS_H diff --git a/src/tools/restest/Warnings.cpp b/src/tools/restest/Warnings.cpp new file mode 100644 index 0000000000..d73740ca51 --- /dev/null +++ b/src/tools/restest/Warnings.cpp @@ -0,0 +1,106 @@ +// Warnings.h + +#include "Warnings.h" + +#include + +// constructor +Warnings::Warnings() + : fWarnings() +{ +} + +// destructor +Warnings::~Warnings() +{ + for (int32 i = 0; BString* warning = (BString*)fWarnings.ItemAt(i); i++) + delete warning; +} + +// GetCurrentWarnings +Warnings* +Warnings::GetCurrentWarnings() +{ + return fCurrentWarnings; +} + +// SetCurrentWarnings +void +Warnings::SetCurrentWarnings(Warnings* warnings) +{ + fCurrentWarnings = warnings; +} + +// AddWarning +void +Warnings::AddWarning(BString warning) +{ + fWarnings.AddItem(new BString(warning)); +} + +// AddWarning +void +Warnings::AddWarning(const char* format,...) +{ + va_list args; + va_start(args, format); + AddWarningV(format, args); + va_end(args); +} + +// AddWarningV +void +Warnings::AddWarningV(const char* format, va_list arg) +{ + char buffer[2048]; + vsprintf(buffer, format, arg); + AddWarning(BString(buffer)); +} + +// AddCurrentWarning +void +Warnings::AddCurrentWarning(BString warning) +{ + if (Warnings* currentWarnings = GetCurrentWarnings()) + currentWarnings->AddWarning(warning); +} + +// AddCurrentWarning +void +Warnings::AddCurrentWarning(const char* format,...) +{ + va_list args; + va_start(args, format); + AddCurrentWarningV(format, args); + va_end(args); +} + +// AddCurrentWarningV +void +Warnings::AddCurrentWarningV(const char* format, va_list arg) +{ + char buffer[2048]; + vsprintf(buffer, format, arg); + AddCurrentWarning(BString(buffer)); +} + +// CountWarnings +int32 +Warnings::CountWarnings() const +{ + return fWarnings.CountItems(); +} + +// WarningAt +const char* +Warnings::WarningAt(int32 index) const +{ + const char* result = NULL; + if (BString* warning = (BString*)fWarnings.ItemAt(index)) + result = warning->String(); + return result; +} + +// fCurrentWarnings +Warnings* Warnings::fCurrentWarnings = NULL; + diff --git a/src/tools/restest/Warnings.h b/src/tools/restest/Warnings.h new file mode 100644 index 0000000000..0a25dff5de --- /dev/null +++ b/src/tools/restest/Warnings.h @@ -0,0 +1,35 @@ +// Warnings.h + +#ifndef WARNINGS_H +#define WARNINGS_H + +#include + +#include +#include + +class Warnings { +public: + Warnings(); + virtual ~Warnings(); + + static Warnings* GetCurrentWarnings(); + static void SetCurrentWarnings(Warnings* warnings); + + void AddWarning(BString warning); + void AddWarning(const char* format,...); + void AddWarningV(const char* format, va_list arg); + static void AddCurrentWarning(BString warning); + static void AddCurrentWarning(const char* format,...); + static void AddCurrentWarningV(const char* format, + va_list arg); + + int32 CountWarnings() const; + const char* WarningAt(int32 index) const; + +private: + static Warnings* fCurrentWarnings; + BList fWarnings; +}; + +#endif // WARNINGS_H diff --git a/src/tools/restest/restest.cpp b/src/tools/restest/restest.cpp new file mode 100644 index 0000000000..32c92bb999 --- /dev/null +++ b/src/tools/restest/restest.cpp @@ -0,0 +1,351 @@ +// restest.cpp + +#include +#include +#include + +#include +#include +#include + +#include "Exception.h" +#include "OffsetFile.h" +#include "ResourceFile.h" +#include "Warnings.h" + +const char kUsage[] = { +"Usage: %s \n" +"options:\n" +" -h, --help print this help\n" +" -l, --list list each file's resources (short version)\n" +" -L, --list-long list each file's resources (long version)\n" +" -s, --summary print a summary\n" +" -w, --write-test write the file resources (in memory only) and\n" +" compare the data with the file's\n" +}; + +const status_t USAGE_ERROR = B_ERRORS_END + 1; +const status_t USAGE_HELP = B_ERRORS_END + 2; + +enum listing_level { + NO_LISTING, + SHORT_LISTING, + LONG_LISTING, +}; + +struct TestOptions { + listing_level listing; + bool write_test; + bool summary; +}; + +struct TestResult { + TestResult(const char* filename) + : filename(filename), warnings(), exception(NULL) + { + } + + ~TestResult() + { + delete exception; + } + + BString filename; + Warnings warnings; + Exception* exception; +}; + +// print_indented +void +print_indented(const char* str, uint32 chars, bool indentFirst = true) +{ + const uint32 MAX_CHARS_PER_LINE = 75; + int32 charsLeft = strlen(str); + if (chars < MAX_CHARS_PER_LINE) { + for (int32 line = 0; charsLeft > 0; line++) { + if (line != 0 || indentFirst) { + for (int32 i = 0; (uint32)i < chars; i++) + printf(" "); + } + int32 bytesLeftOnLine = MAX_CHARS_PER_LINE - chars; + int32 printChars = min(bytesLeftOnLine, charsLeft); + printf("%.*s\n", (int)printChars, str); + str += printChars; + charsLeft -= printChars; + // skip spaces + while (*str == ' ') { + str++; + charsLeft--; + } + } + } +} + +// print_indented +void +print_indented(const char* indentStr, const char* str) +{ + uint32 chars = strlen(indentStr); + printf(indentStr); + print_indented(str, chars, false); +} + +// parse_arguments +void +parse_arguments(int argc, const char* const* argv, BList& files, + TestOptions& options) +{ + // default options + options.listing = NO_LISTING; + options.write_test = false; + options.summary = false; + // parse arguments + for (int32 i = 1; i < argc; i++) { + const char* arg = argv[i]; + int32 len = strlen(arg); + if (len == 0) + throw Exception(USAGE_ERROR, "Illegal argument: `'."); + if (arg[0] == '-') { + if (len < 2) + throw Exception(USAGE_ERROR, "Illegal argument: `-'."); + if (arg[1] == '-') { + const char* option = arg + 2; + // help + if (!strcmp(option, "help")) { + throw Exception(USAGE_HELP); + // list + } else if (!strcmp(option, "list")) { + if (options.listing == NO_LISTING) + options.listing = SHORT_LISTING; + // list-long + } else if (!strcmp(option, "list-long")) { + options.listing = LONG_LISTING; + // summary + } else if (!strcmp(option, "summary")) { + options.summary = true; + // write-test + } else if (!strcmp(option, "write-test")) { + options.write_test = true; + // error + } else { + throw Exception(USAGE_ERROR, BString("Illegal option: `") + << arg << "'."); + } + } else { + for (int32 i = 1; i < len; i++) { + char option = arg[i]; + switch (option) { + // help + case 'h': + throw Exception(USAGE_HELP); + break; + // list + case 'l': + if (options.listing == NO_LISTING) + options.listing = SHORT_LISTING; + break; + // list long + case 'L': + options.listing = LONG_LISTING; + break; + // summary + case 's': + options.summary = true; + break; + // write test + case 'w': + options.write_test = true; + break; + // error + default: + throw Exception(USAGE_ERROR, + BString("Illegal option: `") + << arg << "'."); + break; + } + } + } + } else + files.AddItem(const_cast(arg)); + } +} + +// test_file +void +test_file(const char* filename, const TestOptions& options, + TestResult& testResult) +{ + Warnings::SetCurrentWarnings(&testResult.warnings); + ResourceFile resFile; + try { + // check if the file exists + BEntry entry(filename, true); + status_t error = entry.InitCheck(); + if (error != B_OK) + throw Exception(error); + if (!entry.Exists() || !entry.IsFile()) + throw Exception("Entry doesn't exist or is no regular file."); + entry.Unset(); + // open the file + BFile file(filename, B_READ_ONLY); + error = file.InitCheck(); + if (error != B_OK) + throw Exception(error, "Failed to open file."); + // do the actual test + resFile.Init(file); + if (options.write_test) + resFile.WriteTest(); + } catch (Exception exception) { + testResult.exception = new Exception(exception); + } + Warnings::SetCurrentWarnings(NULL); + // print warnings and error + if (options.listing != NO_LISTING + || testResult.warnings.CountWarnings() > 0 || testResult.exception) { + printf("\nFile `%s':\n", filename); + } + // warnings + if (testResult.warnings.CountWarnings() > 0) { + for (int32 i = 0; + const char* warning = testResult.warnings.WarningAt(i); + i++) { + print_indented(" Warning: ", warning); + } + } + // error + if (testResult.exception) { + status_t error = testResult.exception->GetError(); + const char* description = testResult.exception->GetDescription(); + if (strlen(description) > 0) { + print_indented(" Error: ", description); + if (error != B_OK) + print_indented(" ", strerror(error)); + } else if (error != B_OK) + print_indented(" Error: ", strerror(error)); + } + // list resources + if (resFile.InitCheck() == B_OK) { + switch (options.listing) { + case NO_LISTING: + break; + case SHORT_LISTING: + resFile.PrintToStream(false); + break; + case LONG_LISTING: + resFile.PrintToStream(true); + break; + } + } +} + +// test_files +void +test_files(BList& files, TestOptions& options) +{ + BList testResults; + int32 successTestCount = 0; + int32 warningTestCount = 0; + int32 failedTestCount = 0; + for (int32 i = 0; + const char* filename = (const char*)files.ItemAt(i); + i++) { + TestResult* testResult = new TestResult(filename); + testResults.AddItem(testResult); + test_file(filename, options, *testResult); + if (testResult->exception) + failedTestCount++; + else if (testResult->warnings.CountWarnings() > 0) + warningTestCount++; + else + successTestCount++; + } + // print summary + if (options.summary) { + printf("\nSummary:\n"); + printf( "=======\n"); + // successful tests + if (successTestCount > 0) { + if (successTestCount == 1) + printf("one successful test\n"); + else + printf("%ld successful tests\n", successTestCount); + } + // tests with warnings + if (warningTestCount > 0) { + if (warningTestCount == 1) + printf("one test with warnings:\n"); + else + printf("%ld tests with warnings:\n", warningTestCount); + for (int32 i = 0; + TestResult* testResult = (TestResult*)testResults.ItemAt(i); + i++) { + if (!testResult->exception + && testResult->warnings.CountWarnings() > 0) { + printf(" `%s'\n", testResult->filename.String()); + } + } + } + // failed tests + if (failedTestCount > 0) { + if (failedTestCount == 1) + printf("one test failed:\n"); + else + printf("%ld tests failed:\n", failedTestCount); + for (int32 i = 0; + TestResult* testResult = (TestResult*)testResults.ItemAt(i); + i++) { + if (testResult->exception) + printf(" `%s'\n", testResult->filename.String()); + } + } + } + // cleanup + for (int32 i = 0; + TestResult* testResult = (TestResult*)testResults.ItemAt(i); + i++) { + delete testResult; + } +} + +// main +int +main(int argc, const char* const* argv) +{ + int returnValue = 0; + const char* cmdName = argv[0]; + TestOptions options; + BList files; + try { + // parse arguments + parse_arguments(argc, argv, files, options); + if (files.CountItems() == 0) + throw Exception(USAGE_ERROR, "No files given."); + // test the files + test_files(files, options); + } catch (Exception exception) { + status_t error = exception.GetError(); + const char* description = exception.GetDescription(); + switch (error) { + case B_OK: + if (strlen(description) > 0) + fprintf(stderr, "%s\n", description); + returnValue = 1; + break; + case USAGE_ERROR: + if (strlen(description) > 0) + fprintf(stderr, "%s\n", description); + fprintf(stderr, kUsage, cmdName); + returnValue = 1; + break; + case USAGE_HELP: + printf(kUsage, cmdName); + break; + default: + fprintf(stderr, " error: %s\n", strerror(error)); + returnValue = 1; + break; + } + } + return returnValue; +} + diff --git a/src/tools/stubgen/COPYING b/src/tools/stubgen/COPYING new file mode 100644 index 0000000000..60549be514 --- /dev/null +++ b/src/tools/stubgen/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/src/tools/stubgen/Example Usage for OpenBeOS.txt b/src/tools/stubgen/Example Usage for OpenBeOS.txt new file mode 100644 index 0000000000..402cfb83bc --- /dev/null +++ b/src/tools/stubgen/Example Usage for OpenBeOS.txt @@ -0,0 +1,3 @@ +Example usage for OpenBeOS project: + +stubgen -s -g -a *.h diff --git a/src/tools/stubgen/README b/src/tools/stubgen/README new file mode 100644 index 0000000000..7854104cf0 --- /dev/null +++ b/src/tools/stubgen/README @@ -0,0 +1,147 @@ +stubgen README file +Michael John Radwin +$Id: README,v 1.1 2002/07/09 12:24:59 ejakowatz Exp $ + + +Description +----------- +Welcome to stubgen version 2.05 (build 1086). + +stubgen is a C++ development tool that keeps code files in sync with +their associated headers. When it finds a member function declaration +in a header file that doesn't have a corresponding implementation, it +creates an empty skeleton with descriptive comment headers. stubgen has +several options, but see the "Brief Example" section below for an idea +of what it can do. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + + +Brief Example +------------- +Suppose you have the following header file Point.h: + + class Point { + public: + Point(int x, int y); + void addTo(const Point& other); + + int xValue, yValue; + }; + +Running "stubgen -s Point.h" would produce the following file: + + /*********************************************** + * AUTHOR: Michael John Radwin + * FILE: Point.cpp + * DATE: Mon Apr 20 17:39:05 1998 + * DESCR: + ***********************************************/ + #include "Point.h" + + /* + * Method: Point::Point() + * Descr: + */ + Point::Point(int x, int y) + { + } + + /* + * Method: Point::addTo() + * Descr: + */ + void + Point::addTo(const Point& other) + { + } + + +Supported Platforms +------------------- +I've successfully built stubgen on the following platforms, using the +GNU tools make, gcc, bison, and flex: + + SPARC Solaris (2.5 and 2.6) + SunOS 4.1.3 + SGI IRIX 5.3 + RS6000 AIX 3.2 + MS Windows NT 4.0 (using GNU bison/flex and MSVC++ 5.0) + + +Home Page +--------- +Check out the stubgen home page and download the current source code at: + + http://www.radwin.org/michael/projects/stubgen/ + + +Files +----- +The following files are included in this distribution: + + COPYING - the GNU general public license + ChangeLog - a listing of changes made on various versions. + Makefile - a makefile for building stubgen on unix + README - this file + etc/ - debugging routines for use with the -d option + getopt.[ch] - GNU getopts (for Win32) + lexer.l - flex source, generates tokens + main.c - code generation routines + parser.y - yacc source, parses header and code files + pathname.[ch] - dirname() and basename() routines + stubgen.1 - nroff-able man page + table.[ch] - data structures used in parsing + util.[ch] - utilities, logging routines, used in parsing + test/ - test header files for stubgen + win32/ - MS Visual C++ 5.0 project (Win32 console app) + + +Building +-------- +1. ensure that your system has 'flex' installed. +2. ensure that your system has 'yacc', 'byacc', or 'bison' installed. +3. edit 'Makefile' and pick your favorite CC, LEX, YACC, LFLAGS and CFLAGS +4. run 'make' + +We assume that flex, bison, and cc/gcc are in your path. + +For win32, there's no need to build. You'll find stubgen.exe in the +directory .\win32. + + +Installing +---------- +There is no fancy installation procedure. Since the binary doesn't +depend on any other files, copy it to /usr/local/bin or wherever you +choose. You may wish to copy stubgen.1 to /usr/local/man/man1 or some +similar directory. + + +Acknowledgments +---------------- +stubgen borrows code from: + +Jutta Degener's 1995 ANSI C grammar (based on Jeff Lee's 1985 +implementation): +ftp://ftp.uu.net/usenet/net.sources/ansi.c.grammar.Z +http://www.lysator.liu.se/c/ANSI-C-grammar-l.html +http://www.lysator.liu.se/c/ANSI-C-grammar-y.html + +Graham D. Parrington's Stub Generator for the Arjuna project at the +University of Newcastle upon Tyne: +http://arjuna.ncl.ac.uk/ + + +Copyright +--------- +stubgen is Copyright (c) 1996-1998 Michael John Radwin, under the terms +of the GNU General Public License. See COPYING for more. diff --git a/src/tools/stubgen/etc/Debug.C b/src/tools/stubgen/etc/Debug.C new file mode 100644 index 0000000000..0f78991858 --- /dev/null +++ b/src/tools/stubgen/etc/Debug.C @@ -0,0 +1,58 @@ +// +// FILE: Debug.C +// AUTHOR: tab, bmc +// DESCR: Debug log file utility functions +// + +static char rcsid[] = "$Id: Debug.C,v 1.1 2002/07/09 12:24:59 ejakowatz Exp $"; + +#include "Debug.H" + +#include +#include +#include + +char dbg_file_list[DBG_MAX_FILES][DBG_MAX_FNAMELEN]; +int dbg_num_files = 0; + +#pragma init (dbg_init) + +void dbg_init() { + FILE *f; + char *filename; + if (!(filename = getenv (DBG_ENV_VAR))) + filename = DBG_DEFAULT_FILE; + + if ((f = fopen(filename, "r")) == NULL) { + return; + } + + while ((!feof(f)) && (dbg_num_files < DBG_MAX_FILES)) { + char buf[DBG_MAX_FNAMELEN]; + + fgets(buf, DBG_MAX_FNAMELEN, f); + if (buf) { + + // remove terminating newline + if (buf[strlen(buf)-1] == '\n') { + buf[strlen(buf)-1] = NULL; + } + + if (buf[0] == 0) + continue; + + strcpy(dbg_file_list[dbg_num_files], buf); + dbg_num_files++; + } + } + fclose(f); +} + +int dbg_file_active(char *filename) { + for (int i = 0; i<= dbg_num_files; i++) { + if (strcasecmp(filename, dbg_file_list[i]) == 0) { + return 1; + } + } + return 0; +} diff --git a/src/tools/stubgen/etc/Debug.H b/src/tools/stubgen/etc/Debug.H new file mode 100644 index 0000000000..b847c50cd1 --- /dev/null +++ b/src/tools/stubgen/etc/Debug.H @@ -0,0 +1,51 @@ +// +// FILE: Debug.H +// AUTHOR: bmc +// DESCR: Debug header for FallOS +// +// $Id: Debug.H,v 1.1 2002/07/09 12:24:59 ejakowatz Exp $ +// + +#ifdef _ASSERT_H +#ifndef FALLOS_DEBUG_HEADER + +#error Attempted to include before Debug.H + +#endif +#endif + +#ifndef FALLOS_DEBUG_HEADER +#define FALLOS_DEBUG_HEADER +#define _ASSERT_H + +#include +#include + +#define panic(X) { printf ("Panic at line %d in file %s:\n%s\n", __LINE__, __FILE__, X); exit(1); } + +// +// We define assert to print out the assertion message and then spin. +// The reason to spin instead of exiting is to allow you to Ctrl-C in +// the debugger and be able to walk up the stack, etc... +// + +#define assert(X) if (!(X)) { \ + printf ("Assertion failure at line %d in file %s:\n%s\n", __LINE__, \ + __FILE__, #X); while(1); } + +int dbg_file_active (char *fn); +void dbg_init(); + +#define DBG_MAX_FILES 100 +#define DBG_MAX_FNAMELEN 100 +#define DBG_DEFAULT_FILE ".dbg_files" +#define DBG_ENV_VAR "DBG_FILES" + +#ifndef NDEBUG +#define dprintf(arg) if (dbg_file_active (__FILE__)) printf arg; +#define dpause(arg) if (dbg_file_active (__FILE__)) printf arg; +#else +#define dprintf(arg) +#define dpause(arg) +#endif +#endif diff --git a/src/tools/stubgen/getopt.c b/src/tools/stubgen/getopt.c new file mode 100644 index 0000000000..d87c250e16 --- /dev/null +++ b/src/tools/stubgen/getopt.c @@ -0,0 +1,826 @@ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu + before changing it! + + Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 1996 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +/* This tells Alpha OSF/1 not to define a getopt prototype in . + Ditto for AIX 3.2 and . */ +#ifndef _NO_PROTO +#define _NO_PROTO +#endif + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if !defined (__STDC__) || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#if defined (_LIBC) || !defined (__GNU_LIBRARY__) + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +#include +#include +#endif /* GNU C library. */ + +#ifdef VMS +#include +#if HAVE_STRING_H - 0 +#include +#endif +#endif + +#if defined (WIN32) && !defined (__CYGWIN32__) +/* It's not Unix, really. See? Capital letters. */ +#include +#define getpid() GetCurrentProcessId() +#endif + +#ifndef _ +/* This is for other GNU distributions with internationalized messages. + When compiling libc, the _ macro is predefined. */ +#ifdef HAVE_LIBINTL_H +# include +# define _(msgid) gettext (msgid) +#else +# define _(msgid) (msgid) +#endif +#endif + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg = NULL; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* XXX 1003.2 says this must be 1 before any call. */ +int optind = 0; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +int optopt = '?'; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return EOF with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +/* Value of POSIXLY_CORRECT environment variable. */ +static char *posixly_correct; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +#include +#define my_index strchr +#else + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +char *getenv (); + +static char * +my_index (str, chr) + const char *str; + int chr; +{ + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; +} + +/* If using GCC, we can safely declare strlen this way. + If not using GCC, it is ok not to declare it. */ +#ifdef __GNUC__ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. + That was relevant to code that was here before. */ +#if !defined (__STDC__) || !__STDC__ +/* gcc with -traditional declares the built-in strlen to return int, + and has done so at least since version 2.4.5. -- rms. */ +extern int strlen (const char *); +#endif /* not __STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +/* Bash 2.0 gives us an environment variable containing flags + indicating ARGV elements that should not be considered arguments. */ + +static const char *nonoption_flags; +static int nonoption_flags_len; + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +#if defined (__STDC__) && __STDC__ +static void exchange (char **); +#endif + +static void +exchange (argv) + char **argv; +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Initialize the internal data when the first call is made. */ + +#if defined (__STDC__) && __STDC__ +static const char *_getopt_initialize (const char *); +#endif +static const char * +_getopt_initialize (optstring) + const char *optstring; +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = optind = 1; + + nextchar = NULL; + + posixly_correct = getenv ("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + + if (posixly_correct == NULL) + { + /* Bash 2.0 puts a special variable in the environment for each + command it runs, specifying which ARGV elements are the results of + file name wildcard expansion and therefore should not be + considered as options. */ + char var[100]; + sprintf (var, "_%d_GNU_nonoption_argv_flags_", getpid ()); + nonoption_flags = getenv (var); + if (nonoption_flags == NULL) + nonoption_flags_len = 0; + else + nonoption_flags_len = strlen (nonoption_flags); + } + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns `EOF'. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (argc, argv, optstring, longopts, longind, long_only) + int argc; + char *const *argv; + const char *optstring; + const struct option *longopts; + int *longind; + int long_only; +{ + optarg = NULL; + + if (optind == 0) + { + optstring = _getopt_initialize (optstring); + optind = 1; /* Don't scan ARGV[0], the program name. */ + } + + /* Test whether ARGV[optind] points to a non-option argument. + Either it does not have option syntax, or there is an environment flag + from the shell indicating it is not an option. */ +#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ + || (optind < nonoption_flags_len \ + && nonoption_flags[optind] == '1')) + + if (nextchar == NULL || *nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been + moved back by the user (who may also have changed the arguments). */ + if (last_nonopt > optind) + last_nonopt = optind; + if (first_nonopt > optind) + first_nonopt = optind; + + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc && NONOPTION_P) + optind++; + last_nonopt = optind; + } + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return EOF; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if (NONOPTION_P) + { + if (ordering == REQUIRE_ORDER) + return EOF; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[optind][1] == '-' + || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if (nameend - nextchar == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, _("%s: option `%s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + optopt = 0; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + _("%s: option `--%s' doesn't allow an argument\n"), + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + _("%s: option `%c%s' doesn't allow an argument\n"), + argv[0], argv[optind - 1][0], pfound->name); + + nextchar += strlen (nextchar); + + optopt = pfound->val; + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' + || my_index (optstring, *nextchar) == NULL) + { + if (opterr) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, _("%s: unrecognized option `--%s'\n"), + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + optopt = 0; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (opterr) + { + if (posixly_correct) + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: illegal option -- %c\n"), + argv[0], c); + else + fprintf (stderr, _("%s: invalid option -- %c\n"), + argv[0], c); + } + optopt = c; + return '?'; + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = NULL; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, + _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} + +#endif /* _LIBC or not __GNU_LIBRARY__. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == EOF) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/src/tools/stubgen/getopt.h b/src/tools/stubgen/getopt.h new file mode 100644 index 0000000000..0de18814f7 --- /dev/null +++ b/src/tools/stubgen/getopt.h @@ -0,0 +1,130 @@ +/* Declarations for getopt. + Copyright (C) 1989, 90, 91, 92, 93, 94 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifndef _GETOPT_H +#define _GETOPT_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +#if defined (__STDC__) && __STDC__ + const char *name; +#else + char *name; +#endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +#if defined (__STDC__) && __STDC__ +#ifdef __GNU_LIBRARY__ +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int argc, char *const *argv, const char *shortopts); +#else /* not __GNU_LIBRARY__ */ +extern int getopt (); +#endif /* __GNU_LIBRARY__ */ +extern int getopt_long (int argc, char *const *argv, const char *shortopts, + const struct option *longopts, int *longind); +extern int getopt_long_only (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind, + int long_only); +#else /* not __STDC__ */ +extern int getopt (); +extern int getopt_long (); +extern int getopt_long_only (); + +extern int _getopt_internal (); +#endif /* __STDC__ */ + +#ifdef __cplusplus +} +#endif + +#endif /* _GETOPT_H */ diff --git a/src/tools/stubgen/lexer.l b/src/tools/stubgen/lexer.l new file mode 100644 index 0000000000..eb3a27971f --- /dev/null +++ b/src/tools/stubgen/lexer.l @@ -0,0 +1,525 @@ +%{ +/* + * FILE: lexer.l + * AUTH: Michael John Radwin + * + * DESC: stubgen lexer. Portions borrowed from Newcastle + * University's Arjuna project (http://arjuna.ncl.ac.uk/), and + * Jeff Lee's ANSI Grammar + * (ftp://ftp.uu.net/usenet/net.sources/ansi.c.grammar.Z) + * + * DATE: Thu Aug 15 13:10:06 EDT 1996 + * $Id: lexer.l,v 1.1 2002/07/09 12:24:59 ejakowatz Exp $ + * + * Copyright (c) 1996-1998 Michael John Radwin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Modification history: + * $Log: lexer.l,v $ + * Revision 1.1 2002/07/09 12:24:59 ejakowatz + * It is accomplished ... + * + * Revision 1.1 2001/11/07 10:06:07 ithamar + * Added stubgen to CVS + * + * Revision 1.33 1998/07/27 19:16:57 mradwin + * added some c++ keywords + * need to handle typename, using, and namespace + * + * Revision 1.32 1998/05/11 19:49:11 mradwin + * Version 2.03 (updated copyright information). + * + * Revision 1.31 1998/04/07 23:39:55 mradwin + * changed error-handling code significantly. functions + * like count() are now contributing to linebuf so we get correct + * parse error messages during lineno == 1 and other situations. + * also, instead of calling fatal() for collect*() functions, + * we return -1 and let the parser recover more gracefully. + * + * Revision 1.30 1998/01/12 19:39:11 mradwin + * modified rcsid + * + * Revision 1.29 1997/11/13 22:37:31 mradwin + * changed char[] to char * to make non-gcc compilers + * a little happier. We need to #define const to nothing + * for other compilers as well. + * + * Revision 1.28 1997/11/13 21:29:30 mradwin + * moved code from parser.y to main.c + * + * Revision 1.27 1997/11/13 21:10:17 mradwin + * renamed stubgen.[ly] to parser.y lexer.l + * + * Revision 1.26 1997/11/11 03:52:06 mradwin + * changed fatal() + * + * Revision 1.25 1997/11/05 03:02:02 mradwin + * Modified logging routines. + * + * Revision 1.24 1997/11/01 23:12:43 mradwin + * greatly improved error-recovery. errors no longer spill over + * into other files because the yyerror state is properly reset. + * + * Revision 1.23 1997/10/26 23:16:32 mradwin + * changed inform_user and fatal functions to use varargs + * + * Revision 1.22 1997/10/26 22:46:48 mradwin + * support macros within comments, etc. + * + * Revision 1.21 1997/10/16 19:42:48 mradwin + * added support for elipses, static member/array initializers, + * and bitfields. + * + * Revision 1.20 1997/10/16 17:36:06 mradwin + * Fixed compiler warning on win32 from and isspace() + * + * Revision 1.19 1997/10/16 17:12:59 mradwin + * handle extern "C" blocks better now, and support multi-line + * macros. still need error-checking. + * + * Revision 1.18 1997/10/15 22:09:06 mradwin + * changed tons of names. stubelem -> sytaxelem, + * stubin -> infile, stubout -> outfile, stublog -> logfile. + * + * Revision 1.17 1997/10/15 21:45:13 mradwin + * rearranged table.[ch] and util.[ch] so that util pkg + * knows nothing about syntaxelems. + * + * Revision 1.16 1997/10/15 17:42:37 mradwin + * added support for 'extern "C" { ... }' blocks. + * + * Revision 1.15 1997/09/05 19:17:06 mradwin + * works for scanning old versions, except for parameter + * names that differ between .H and .C files. + * + * Revision 1.14 1997/09/05 16:37:41 mradwin + * rcsid + * + * Revision 1.13 1997/09/05 16:34:36 mradwin + * GPL-ized code. + * + * Revision 1.12 1997/09/05 16:13:18 mradwin + * changed email address to acm.org + * + * Revision 1.11 1996/09/12 14:44:49 mjr + * Added throw decl recognition (great, another 4 bytes in syntaxelem) + * and cleaned up the grammar so that const_opt appears in far fewer + * places. const_opt is by default 0 as well, so we don't need to + * pass it as an arg to new_elem(). + * + * I also added a fix to a potential bug with the MINIT and INLIN + * exclusive start states. I think they could have been confused + * by braces within comments, so now I'm grabbing comments in those + * states as well. + * + * Revision 1.10 1996/09/12 03:46:10 mjr + * No concrete changes in code. Just added some sanity by + * factoring out code into util.[ch] and putting some prototypes + * that were in table.h into stubgen.y where they belong. + * + * Revision 1.9 1996/09/01 20:59:48 mjr + * Added collectMemberInitList() function, which is similar + * to collectInlineDef() and also the exclusive state MINIT + * + * Revision 1.8 1996/08/23 05:09:19 mjr + * fixed up some more portability things + * + * Revision 1.7 1996/08/22 02:43:47 mjr + * added parse error message (using O'Reilly p. 274) + * + * Revision 1.6 1996/08/21 18:33:50 mjr + * removed the buffer for inlines. we don't care anyway. + * now we can't overflow on inlines! + * + * Revision 1.5 1996/08/21 17:40:56 mjr + * added some cpp directives for porting to WIN32 + * + * Revision 1.4 1996/08/19 17:01:33 mjr + * no echo now + * + * Revision 1.3 1996/08/15 21:24:58 mjr + * *** empty log message *** + */ +%} + +D [0-9] +L [a-zA-Z_] +H [a-fA-F0-9] +E [Ee][+-]?{D}+ +FS (f|F|l|L) +IS (u|U|l|L)* + +%{ +#include +#include +#include +#include "table.h" +#include "util.h" + +#ifdef WIN32 +/* definitions of exit, malloc, realloc, and free */ +#include +#endif + +#if 0 /* #ifdef WIN32 */ +#include "y_tab.h" +#else +#include "y.tab.h" +#endif + +#ifdef __cplusplus +#define STUB_INPUT() yyinput() +#else +#define STUB_INPUT() input() +#endif + +/* when we return a string, duplicate it so we can free it later. + we always allocate memory so we can uniformly free() it. */ +#define RETURN_STR(x) tokens_seen++; yylval.string = strdup(yytext); return(x) + +/* make that nasty union a value that will bus error if we misinterpret + the value as a pointer */ +#define RETURN_VAL(x) tokens_seen++; yylval.flag = 37; return(x) + +static const char rcsid[] = "$Id: lexer.l,v 1.1 2002/07/09 12:24:59 ejakowatz Exp $"; + +static void count(); +static void comment(); +static void macro(); + +char linebuf[1024]; /* null-terminated at beginning of each file */ +int lineno; /* set to 1 at beginning of each file */ +int column; /* set to 0 at beginning of each file */ +int tokens_seen; /* set to 0 at beginning of each file */ + +%} + +%x INLIN MINIT +%% +\n.* { /* + * for debugging purposes, we grab an entire + * line and buffer it, then grab tokens out of + * it. This lets us have more informative + * error messages. See yyerror() in parser.y + */ + strncpy(linebuf, yytext+1, 1024); + lineno++; + column = 0; + yyless(1); /* give back everything but \n */ + } +"/*" { comment(); } + +"//".* { count(); } +"#" { macro(); /* was #.* { count(); } */ } + +"static" { count(); tokens_seen++; } +"volatile" { count(); tokens_seen++; } +"auto" { count(); tokens_seen++; } +"extern" { count(); RETURN_VAL(EXTERN); } +"register" { count(); tokens_seen++; } +"typedef" { count(); tokens_seen++; } +"struct" { count(); RETURN_VAL(STRUCT); } +"union" { count(); RETURN_VAL(UNION); } +"enum" { count(); RETURN_VAL(ENUM); } +"const" { count(); RETURN_VAL(CONST); } +"template" { count(); RETURN_VAL(TEMPLATE); } + +"typename" { count(); tokens_seen++; /* FIXME */ } +"using" { count(); tokens_seen++; /* FIXME */ } +"namespace" { count(); RETURN_VAL(CLASS); /* FIXME */ } + +"dllexport" { count(); tokens_seen++; } +"dllimport" { count(); tokens_seen++; } + +"explicit" { count(); tokens_seen++; } +"mutable" { count(); tokens_seen++; } +"inline" { count(); tokens_seen++; } +"virtual" { count(); tokens_seen++; } +"class" { count(); RETURN_VAL(CLASS); } +"delete" { count(); RETURN_VAL(DELETE); } +"new" { count(); RETURN_VAL(NEW); } +"friend" { count(); RETURN_VAL(FRIEND); } +"operator" { count(); RETURN_VAL(OPERATOR); } +"protected" { count(); RETURN_VAL(PROTECTED); } +"private" { count(); RETURN_VAL(PRIVATE); } +"public" { count(); RETURN_VAL(PUBLIC); } +"throw" { count(); RETURN_VAL(THROW); } + +"char" { count(); RETURN_STR(CHAR); } +"short" { count(); RETURN_STR(SHORT); } +"int" { count(); RETURN_STR(INT); } +"long" { count(); RETURN_STR(LONG); } +"signed" { count(); RETURN_STR(SIGNED); } +"unsigned" { count(); RETURN_STR(UNSIGNED); } +"float" { count(); RETURN_STR(FLOAT); } +"double" { count(); RETURN_STR(DOUBLE); } +"void" { count(); RETURN_STR(VOID); } + +{L}({L}|{D})* { count(); RETURN_STR(IDENTIFIER); } + +0[xX]{H}+{IS}? { count(); RETURN_STR(CONSTANT); } +0{D}+{IS}? { count(); RETURN_STR(CONSTANT); } +{D}+{IS}? { count(); RETURN_STR(CONSTANT); } +'(\\.|[^\\'])+' { count(); RETURN_STR(CONSTANT); /* 'fontlck */ } + +{D}+{E}{FS}? { count(); RETURN_STR(CONSTANT); } +{D}*"."{D}+({E})?{FS}? { count(); RETURN_STR(CONSTANT); } +{D}+"."{D}*({E})?{FS}? { count(); RETURN_STR(CONSTANT); } + +\"(\\.|[^\\"])*\" { count(); RETURN_STR(STRING_LITERAL); /* "fontlck */ } + +">>=" { count(); RETURN_VAL(RIGHT_ASSIGN); } +"<<=" { count(); RETURN_VAL(LEFT_ASSIGN); } +"+=" { count(); RETURN_VAL(ADD_ASSIGN); } +"-=" { count(); RETURN_VAL(SUB_ASSIGN); } +"*=" { count(); RETURN_VAL(MUL_ASSIGN); } +"/=" { count(); RETURN_VAL(DIV_ASSIGN); } +"%=" { count(); RETURN_VAL(MOD_ASSIGN); } +"&=" { count(); RETURN_VAL(AND_ASSIGN); } +"^=" { count(); RETURN_VAL(XOR_ASSIGN); } +"|=" { count(); RETURN_VAL(OR_ASSIGN); } +">>" { count(); RETURN_VAL(RIGHT_OP); } +"<<" { count(); RETURN_VAL(LEFT_OP); } +"++" { count(); RETURN_VAL(INC_OP); } +"--" { count(); RETURN_VAL(DEC_OP); } +"->" { count(); RETURN_VAL(PTR_OP); } +"->*" { count(); RETURN_VAL(MEM_PTR_OP); } +"&&" { count(); RETURN_VAL(AND_OP); } +"||" { count(); RETURN_VAL(OR_OP); } +"<=" { count(); RETURN_VAL(LE_OP); } +">=" { count(); RETURN_VAL(GE_OP); } +"==" { count(); RETURN_VAL(EQ_OP); } +"!=" { count(); RETURN_VAL(NE_OP); } +";" { count(); RETURN_VAL(';'); } +"{" { count(); RETURN_VAL('{'); } +"}" { count(); RETURN_VAL('}'); } +"," { count(); RETURN_VAL(','); } +":" { count(); RETURN_VAL(':'); } +"=" { count(); RETURN_VAL('='); } +"(" { count(); RETURN_VAL('('); } +")" { count(); RETURN_VAL(')'); } +"[" { count(); RETURN_VAL('['); } +"]" { count(); RETURN_VAL(']'); } +"." { count(); RETURN_VAL('.'); } +"&" { count(); RETURN_VAL('&'); } +"!" { count(); RETURN_VAL('!'); } +"~" { count(); RETURN_VAL('~'); } +"-" { count(); RETURN_VAL('-'); } +"+" { count(); RETURN_VAL('+'); } +"*" { count(); RETURN_VAL('*'); } +"/" { count(); RETURN_VAL('/'); } +"%" { count(); RETURN_VAL('%'); } +"<" { count(); RETURN_VAL('<'); } +">" { count(); RETURN_VAL('>'); } +"^" { count(); RETURN_VAL('^'); } +"|" { count(); RETURN_VAL('|'); } +"?" { count(); RETURN_VAL('?'); } +"::" { count(); RETURN_VAL(CLCL); } +"..." { count(); RETURN_VAL(ELIPSIS); } + +"/*" { comment(); } +"//".* { count(); } +"#" { macro(); /* was #.* { count(); } */ } +. | +\n { RETURN_VAL((int) yytext[0]); } + +"/*" { comment(); } +"//".* { count(); } +"#" { macro(); /* was #.* { count(); } */ } +. | +\n { RETURN_VAL((int) yytext[0]); } + +[ \t\v\f] { count(); } +. { count(); /* ignore bad characters */ } + +%% + +/* + * called when EOF is encountered. Return 1 so the scanner will return + * the zero token to report end-of-file. + */ +int yywrap() +{ + return(1); +} + +static void comment() +{ + int c1 = 0, c2 = STUB_INPUT(); + + linebuf[column] = c2; + column++; + for(;;) { + if (c2 == EOF) + break; + if (c1 == '*' && c2 == '/') + break; + if (c2 == '\n') { + linebuf[0] = '\0'; + column = 0; + lineno++; + } + + c1 = c2; + c2 = STUB_INPUT(); + linebuf[column] = c2; + column++; + } +} + + +static void macro() +{ + int c1 = 0, c2 = STUB_INPUT(), nonws = 0; + + log_printf("MACRO reading begining...\n#"); + log_printf("%c", c2); + + linebuf[column] = c2; + column++; + for(;;) { + if (c2 == EOF) + break; + if (!isspace(c1)) + nonws = c1; + if (nonws == '\\' && c2 == '\n') { + linebuf[0] = '\0'; + column = 0; + lineno++; + } else if (c2 == '\n') { + linebuf[0] = '\0'; + column = 0; + lineno++; + break; + } + + c1 = c2; + c2 = STUB_INPUT(); + linebuf[column] = c2; + log_printf("%c", c2); + column++; + } + log_printf("MACRO reading done.\n"); +} + + +static void count() +{ + int i; + + if (lineno == 1) + strcat(linebuf, yytext); + + for (i = 0; yytext[i] != '\0'; i++) + if (yytext[i] == '\n') + column = 0; + else if (yytext[i] == '\t') + column += 8 - (column % 8); + else + column++; + + /* equiv to fprintf(yyout, "%s", yytext); */ + /* ECHO; */ +} + +/* + * Collect the contents of inline functions, reading them char by char. + * thanks to the arjuna stubgen project for this one + */ +int collectInlineDef() +{ + int bracelevel = 1; + int token; + + /* the magic of exclusive start states makes it all possible */ + BEGIN INLIN; + + while (bracelevel > 0) { + token = yylex(); + column++; +/* fprintf(stderr, "INLIN: read token %c\n", token); */ + if (token > 0) { + /* Assume single char */ + switch (token) { + case '{': + bracelevel++; + break; + case '}': + bracelevel--; + if (bracelevel == 0) + { + column--; + unput(token); + break; + } + break; + case '\n': + column = 0; + lineno++; + break; + } + } else { + /* fatal error: Unexpected EOF reading inline function */ + return -1; + } + } + + /* we now return you to your regularly scheduled start state */ + BEGIN 0; + + return 0; +} + + +/* + * hmmm... looks familiar. more control-y programming. + */ +int collectMemberInitList() +{ + int token; + int insideList = 1; + + /* the magic of exclusive start states makes it all possible */ + BEGIN MINIT; + + while(insideList) { + token = yylex(); + column++; +/* fprintf(stderr, "MINIT: read token %c\n", token); */ + if (token > 0) { + /* Assume single char */ + switch (token) + { + case '{': + insideList = 0; + unput(token); + break; + case '\n': + column = 0; + lineno++; + break; + } + } else { + /* fatal error: Unexpected EOF reading member initialization */ + return -1; + } + } + + /* we now return you to your regularly scheduled start state */ + BEGIN 0; + + return 0; +} diff --git a/src/tools/stubgen/main.c b/src/tools/stubgen/main.c new file mode 100644 index 0000000000..58a45ef0b0 --- /dev/null +++ b/src/tools/stubgen/main.c @@ -0,0 +1,683 @@ +/* + * FILE: main.c + * AUTH: Michael John Radwin + * + * DESC: stubgen code generation routines + * + * DATE: Thu Nov 13 13:28:23 PST 1997 + * $Id: main.c,v 1.1 2002/07/09 12:24:59 ejakowatz Exp $ + * + * Copyright (c) 1996-1998 Michael John Radwin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "table.h" +#include "util.h" +#include "pathname.h" +#include +#include +#include +#include +#include + +#ifdef WIN32 +#include /* defintion of GetUserName(), BOOL, etc. */ +#include +#include /* defintion of alloca() */ +#include "getopt.h" /* use GNU getopt */ +#else /* !WIN32 */ +#include +#endif /* WIN32 */ + +/* protos */ +static void debug_printf(syntaxelem_t *); +static void generate_skel(syntaxelem_t *); +static void print_function(syntaxelem_t *); +static void function_hdr(syntaxelem_t *); +static void file_hdr(); +static void scan_and_generate(FILE *); +static void scan_existing_skeleton(); + +/* duplicating variable names from stubgen.pl */ +static const char *OPTS = "hqrivgae:cdbfsn"; +int opt_h = 0, opt_q = 0, opt_r = 0, opt_i = 0; +int opt_v = 0, opt_g = 0, opt_a = 0; +int opt_c = 0, opt_d = 0; +int opt_b = 0, opt_f = 0, opt_s = 0, opt_n = 0; +char *opt_e = "cpp"; + +int using_stdio = 0; +static int new_functions = 0, fileOpened = 0, fileExisted = 0; +static int inform_indent = 0; + +#ifdef SGDEBUG +static const char *logfilename = "stubgen.log"; +#endif /* SGDEBUG */ + +FILE *outfile = NULL; +static char *inPath = NULL, *outPath = NULL; +char *currentFile = ""; +static const char *lots_of_stars = + "***********************************************************************"; +static const char *progname = "stubgen"; +static const char rcsid[] = "$Id: main.c,v 1.1 2002/07/09 12:24:59 ejakowatz Exp $"; +static const char *progver = "2.05"; + +static const char *copyright = + "Copyright (c) 1996-1998 Michael John Radwin"; + +static const char *version_info = +"Distributed under the GNU General Public License.\n\ +See http://www.radwin.org/michael/projects/stubgen/ for more information.\n"; + +static const char *usage = +"usage: %s [-hqrivgacd] [-e ext] [-{bfsn}] [infiles]\n\ + OPTIONS\n\ + -h Display usage information.\n\ + -q Quiet mode, no status information while generating code.\n\ + -r Make RCS-style file headers.\n\ + -i Don't put the #include \"my_file.H\" directive in my_file.cpp\n\ + -v Display version information.\n\ + -g Generate dummy return statements for functions.\n\ + -a Split function arguments over multiple lines.\n\ + -c Print debugging output with cerrs (#include ).\n\ + -d Print debugging output with dprintfs (#include ).\n\ + -e ext Generate source files with extension '.ext' (default '.cpp').\n\ +\n\ + METHOD HEADER STYLES\n\ + -b Block method headers (default).\n\ + -f Full method headers: like block, but less asterisks.\n\ + -s Simple method headers: only \"Method\" and \"Descr\" fields.\n\ + -n No method headers.\n"; + + +static void generate_skel(syntaxelem_t *elt) +{ + syntaxelem_t *e; + + log_printf("generate_skel called: %s\n", elt->name); + if (elt->kind != CLASS_KIND && elt->kind != STRUCT_KIND) + return; + + inform_user("%*s==> %s %s", inform_indent, "", + (elt->kind == CLASS_KIND ? "class " : "struct"), + elt->name); + if (inform_indent == 0) + inform_user(" (file %s)", inPath); + else + inform_user(" (nested class)"); + inform_user("\n"); + inform_indent += 4; + + for (e = elt->children; e != NULL; e = e->next) { + if (e->kind == FUNC_KIND) { + char *arg_str = args_to_string(e->args, 0); + log_printf(">>>>>>> generating %s: %s %s::%s(%s) %s\n", + string_kind(e->kind), + e->ret_type, elt->name, e->name, arg_str, + (e->const_flag) ? "const" : ""); + free(arg_str); + print_se(e); + print_function(e); + e->kind = DONE_FUNC_KIND; + } else if (e->kind == CLASS_KIND || e->kind == STRUCT_KIND) { + /* nested class */ + char *tmp_str = (char *) malloc(strlen(elt->name) + strlen(e->name) + 3); + sprintf(tmp_str, "%s::%s", elt->name, e->name); + free(e->name); + e->name = tmp_str; + + log_printf(">>>>>>> generating NESTED %s: %s\n", + string_kind(e->kind), e->name); + print_se(e); + generate_skel(e); + } else { + log_printf("------> ignoring %s: %s\n", + string_kind(e->kind), e->name); + } + } + + inform_indent -= 4; + inform_user("%*s==> %s %s", inform_indent, "", + (elt->kind == CLASS_KIND ? "class " : "struct"), + elt->name); + if (inform_indent == 0) + inform_user(" (%d functions appended to %s)", new_functions, outPath); + else + inform_user(" (end nested class)"); + inform_user("\n"); + + elt->kind = DONE_CLASS_KIND; +} + + + +static void print_function(syntaxelem_t *elt) +{ + syntaxelem_t *e; + + if (find_skeleton(elt)) { + log_printf("find_skeleton() returned true for this elt:\n"); + print_se(elt); + return; + } + + new_functions++; + if (!fileOpened) { + fileOpened = 1; + + if (using_stdio) { + fileExisted = 0; + } else { + /* test for existence */ + outfile = fopen(outPath, "r"); + if (outfile != NULL) { + fileExisted = 1; + fclose(outfile); + } + + /* do the fopen */ + log_printf("writing to %s\n", outPath); + outfile = fopen(outPath, "a"); + if (outfile == NULL) { + /* open failed */ + fatal(1, "%s: cannot open %s\n", progname, outPath); + } + } + + if (!fileExisted) file_hdr(); + } + + inform_user("%*s%s\n", inform_indent, "", elt->name); + function_hdr(elt); + for (e = elt->parent; e != NULL; e = e->parent) { + if (e->templ) { + fprintf(outfile, "%s\n", e->templ); + break; + } + } + + { /* scope for local vars */ + char *arg_str; + + fprintf(outfile, "%s%s%s::%s(", + elt->ret_type, (strcmp(elt->ret_type, "") ? "\n" : ""), + elt->parent->name, elt->name); + + arg_str = args_to_string( + elt->args, + opt_a ? strlen(elt->parent->name) + strlen(elt->name) + 3 : 0); + + fprintf(outfile, "%s)", arg_str); + free(arg_str); + + if (elt->throw_decl) + fprintf(outfile, " %s", elt->throw_decl); + + if (elt->const_flag) + fprintf(outfile, " const"); + + fprintf(outfile, "\n{\n"); + } + + debug_printf(elt); + fprintf(outfile, "}\n\n\n"); +} + +static void function_hdr(syntaxelem_t *elt) +{ + if (opt_n) + return; + + fprintf(outfile, "/%s\n", (opt_b ? lots_of_stars : "*")); + fprintf(outfile, " * Method: %s::%s%s\n", elt->parent->name, elt->name, + (opt_s ? "()" : "")); + + if (opt_s) { + fprintf(outfile, " * Descr: \n"); + + } else { + char *arg_str = args_to_string(elt->args, 0); + fprintf(outfile, " * Params: %s\n", arg_str); + if (strcmp(elt->ret_type, "")) + fprintf(outfile, " * Returns: %s\n", elt->ret_type); + fprintf(outfile, " * Effects: \n"); + free(arg_str); + } + + fprintf(outfile, " %s/\n", (opt_b ? lots_of_stars : "*")); +} + +#ifdef WIN32 +static BOOL win32_fullname(const char *login, char *dest) +{ + WCHAR wszLogin[256]; /* Unicode user name */ + struct _USER_INFO_10 *ui; /* User structure */ + + /* Convert ASCII user name to Unicode. */ + MultiByteToWideChar(CP_ACP, 0, login, + strlen(login)+1, wszLogin, sizeof(wszLogin)); + + /* Look up the user on the DC. This function only works for + * Windows NT, and not Windows 95. */ + if (NetUserGetInfo(NULL, (LPWSTR) &wszLogin, 10, (LPBYTE *) &ui)) + return FALSE; + + /* Convert the Unicode full name to ASCII. */ + WideCharToMultiByte(CP_ACP, 0, ui->usri10_full_name, + -1, dest, 256, NULL, NULL); + + return TRUE; +} +#endif /* WIN32 */ + +static char *sg_getlogin() +{ + static char *login; +#ifdef WIN32 + static char login_buffer[256]; + DWORD size; +#endif /* WIN32 */ + static int sg_getlogin_called = 0; + + if (sg_getlogin_called) + return login; + else + sg_getlogin_called = 1; + +#ifdef WIN32 + if ((login = getenv("USERNAME")) == NULL) { + if ((login = getenv("USER")) == NULL) { + size = 255; + login = login_buffer; + if (GetUserName(login_buffer, &size) == FALSE) + login = "nobody"; + } + } +#else /* !WIN32 */ + if ((login = getenv("USER")) == NULL) + if ((login = getlogin()) == NULL) + login = "nobody"; +#endif /* WIN32 */ + + return login; +} + +static char *sg_getfullname(const char *login) +{ + char *fullname; + static char fullname_buffer[256]; +#ifndef WIN32 + char *comma; + struct passwd *pw; +#endif /* WIN32 */ + +#ifdef WIN32 + fullname = fullname_buffer; + + if (win32_fullname(login, fullname_buffer) == FALSE) + fullname = "nobody"; +#else /* !WIN32 */ + if ((fullname = getenv("NAME")) == NULL) { + setpwent(); + pw = getpwnam(login); + if (pw == NULL) { + fullname = "nobody"; + } else { + strncpy(fullname_buffer, pw->pw_gecos, 256); + comma = strchr(fullname_buffer, ','); + if (comma) *comma = '\0'; + fullname = fullname_buffer; + } + endpwent(); + } +#endif /* WIN32 */ + + return fullname; +} + + +static void file_hdr() { + char domain[256], *tmp; + time_t now = time(0); + char *today = ctime(&now); + char *login = sg_getlogin(); + char *fullname = sg_getfullname(login); + + log_printf("login: %s, full name: %s\n", login, fullname); + + domain[0] = '\0'; + if ((tmp = getenv("STUBGEN_DOM")) != NULL) + sprintf(domain, "@%s", tmp); + + if (opt_r) { + fprintf(outfile, "/*\n * FILE: %s\n * AUTH: %s <%s%s>\n", outPath, fullname, login, domain); + /* no '\n' needed with ctime() */ + fprintf(outfile, " *\n * DESC: \n *\n * DATE: %s * %sId$ \n *\n", today, "$"); + fprintf(outfile, " * %sLog$\n", "$"); + fprintf(outfile, " *\n */\n"); + + } else { + fprintf(outfile, "/%s\n", lots_of_stars); + fprintf(outfile, " * AUTHOR: %s <%s%s>\n", fullname, login, domain); + fprintf(outfile, " * FILE: %s\n", outPath); + fprintf(outfile, " * DATE: %s", today); /* no '\n' needed with ctime() */ + fprintf(outfile, " * DESCR: \n"); + fprintf(outfile, " %s/\n", lots_of_stars); + } + + if (!opt_i && !using_stdio) + fprintf(outfile, "#include \"%s\"\n", inPath); + if (opt_c) + fprintf(outfile, "#include \n"); + else if (opt_d) + fprintf(outfile, "#include \n"); + + fprintf(outfile, "\n"); +} + + +static void debug_printf(syntaxelem_t *elt) +{ + /* + * Make a dummy return value if this function is not a + * procedure (returning void) or a ctor (returning ""). + * Don't bother for references because they require an lvalue. + */ + int dummy_ret_val = (opt_g && + strcmp(elt->ret_type, "") != 0 && + strcmp(elt->ret_type, "void") != 0 && + strchr(elt->ret_type, '&') == 0); + /* + * If it's not a pointer type, create a temporary on the stack. + * They'll get warnings "dummy has not yet been assigned a value" + * from the compiler, but that's the best we can do. + * If it's a pointer type, return NULL (we assume it's defined). + */ + if (dummy_ret_val != 0 && strchr(elt->ret_type, '*') == NULL) + fprintf(outfile, " %s dummy;\n\n", elt->ret_type); + + if (opt_c) + fprintf(outfile, " cerr << \"%s::%s()\" << endl;\n", + elt->parent->name, elt->name); + else if (opt_d) + fprintf(outfile, " dprintf((\"%s::%s()\\n\"));\n", + elt->parent->name, elt->name); + + if (dummy_ret_val != 0) + fprintf(outfile, " return %s;\n", + (strchr(elt->ret_type, '*') == NULL) ? "dummy" : "NULL"); +} + +extern char linebuf[]; +extern int lineno; +extern int column; +extern int tokens_seen; +extern int yyparse(); + +static void scan_existing_skeleton() +{ + extern FILE *yyin; + FILE *existing; + + log_printf("checking for existence of %s ...\n", outPath); + if ((existing = fopen(outPath, "r")) == NULL) + return; + + log_printf("%s exists, scanning skeleton...\n", outPath); + inform_user("scanning %s ...\n", outPath); + + lineno = 1; + column = 0; + tokens_seen = 0; + + yyin = existing; + currentFile = outPath; + linebuf[0] = '\0'; + yyparse(); + log_printf("finished yyparse()\n"); + currentFile = ""; + + fclose(existing); + log_printf("done scanning skeleton...\n"); +} + + +static void scan_and_generate(FILE *infile) +{ + extern FILE *yyin; + + fileOpened = 0; + lineno = 1; + column = 0; + tokens_seen = 0; + + /* normal interaction on yyin and outfile from now on */ + inform_user("parsing %s ...\n", inPath); + log_printf("parsing %s ...\n", inPath); + yyin = infile; + currentFile = inPath; + linebuf[0] = '\0'; + yyparse(); + log_printf("finished yyparse()\n"); + currentFile = ""; + log_printf("expanding classes...\n"); + while (!class_queue_empty()) { + syntaxelem_t *elt = dequeue_class(); + generate_skel(elt); + } + + log_printf("closing %s\n", outPath); + free(outPath); + outPath = NULL; + if (fileOpened) { + fflush(outfile); + fclose(outfile); + outfile = NULL; + } + log_printf("done with %s\n", inPath); +} + +/* + * return a value representing numeric part of the RCS Revision string + * where value == (major * 1000) + minor. + */ +int revision() +{ + static char rcsrev[] = "$Revision: 1.1 $"; + static int value = -1; + char *major_str, *dot; + + if (value != -1) + return value; + + rcsrev[strlen(rcsrev)-2] = '\0'; + + major_str = &rcsrev[11]; + dot = strchr(major_str, '.'); + *dot++ = '\0'; /* tie off major_str and move to minor */ + + value = (atoi(major_str) * 1000) + atoi(dot); + + return value; +} + +#ifndef _MAX_PATH +#define _MAX_PATH 256 +#endif /* !def _MAX_PATH */ + +int main(int argc, char **argv) +{ + extern int optind; + extern char *optarg; + int c, err_flag = 0; + char *ext; + +#ifdef SGDEBUG + char logfilename_buffer[_MAX_PATH]; +#ifdef WIN32 + DWORD tmpPathLen; +#endif /* WIN32 */ +#endif /* SGDEBUG */ + +#ifdef SGDEBUG +#ifdef WIN32 + tmpPathLen = GetTempPath(_MAX_PATH, logfilename_buffer); + if (logfilename_buffer[tmpPathLen - 1] != '\\') + strcat(logfilename_buffer, "\\"); +#else /* !WIN32 */ + strcpy(logfilename_buffer, "/tmp/"); +#endif /* WIN32 */ + + strcat(logfilename_buffer, sg_getlogin()); + strcat(logfilename_buffer, "-"); + strcat(logfilename_buffer, logfilename); + + if (!log_open(logfilename_buffer)) { + /* open failed */ + fatal(1, "%s: cannot write to %s\n", progname, logfilename_buffer); + } +#endif /* SGDEBUG */ + + while ((c = getopt(argc, argv, OPTS)) != EOF) { + switch (c) { + case 'h': + opt_h = 1; break; + case 'q': + opt_q = 1; break; + case 'v': + opt_v = 1; break; + case 'g': + opt_g = 1; break; + case 'a': + opt_a = 1; break; + case 'e': + opt_e = optarg; + if (opt_e[0] == '.') + opt_e++; + break; + case 'r': + opt_r = 1; break; + case 'i': + opt_i = 1; break; + case 'c': + if (opt_d) err_flag = 1; + opt_c = 1; break; + case 'd': + if (opt_c) err_flag = 1; + opt_d = 1; break; + case 'b': + if (opt_f || opt_s || opt_n) err_flag = 1; + opt_b = 1; break; + case 'f': + if (opt_b || opt_s || opt_n) err_flag = 1; + opt_f = 1; break; + case 's': + if (opt_f || opt_b || opt_n) err_flag = 1; + opt_s = 1; break; + case 'n': + if (opt_f || opt_s || opt_b) err_flag = 1; + opt_n = 1; break; + default: + err_flag = 1; + } + } + + if (opt_h || opt_v || err_flag) { + inform_user("%s version %s (build %d).\n", + progname, progver, revision()); + if (opt_h || err_flag) + fatal(err_flag, usage, progname); + else + fatal(0, "%s\n%s", copyright, version_info); + } + + if (!(opt_b || opt_f || opt_s || opt_n)) + opt_b = 1; + + /* done setting options */ + if (argc == optind) { + /* read from stdin and stdout */ + outfile = stdout; + fprintf(outfile, "/* %s: reading from stdin */\n", progname); + using_stdio = 1; + inPath = "stdin"; + outPath = strdup("stdout"); + + opt_q = 1; /* force quiet mode */ + log_printf("initting...\n"); + init_tables(); + scan_and_generate(stdin); + log_printf("freeing memory...\n"); + free_tables(); + + } else { + inform_user("%s version %s (build %d).\n", + progname, progver, revision()); + + /* each bloody file from the command line */ + while (optind < argc) { + FILE *infile; + log_printf("working on %s\n", argv[optind]); + /* open for read */ + infile = fopen(argv[optind], "r"); + if (infile == NULL) { + /* open failed */ + fatal(1, "%s: cannot open %s\n", progname, argv[optind]); + } + + inPath = basename(argv[optind]); + outPath = (char *)malloc(strlen(inPath) + strlen(opt_e) + 2); + strcpy(outPath, inPath); + + /* tie off .h, .hh, .hpp, or .hxx extension */ + if (((ext = strrchr(outPath, '.')) != NULL) && + (((strlen(ext) == 2) && + ((ext[1] == 'H') || (ext[1] == 'h'))) || + (((strlen(ext) == 3) && + ((ext[1] == 'H') || (ext[1] == 'h')) && + ((ext[2] == 'H') || (ext[2] == 'h')))) || + ((strlen(ext) == 4) && + ((ext[1] == 'H') || (ext[1] == 'h')) && + ((((ext[2] == 'P') || (ext[2] == 'p')) && + ((ext[3] == 'P') || (ext[3] == 'p'))) || + (((ext[2] == 'X') || (ext[2] == 'x')) && + ((ext[3] == 'X') || (ext[3] == 'x'))))))) + *ext = '\0'; + + assert(opt_e[0] != '.'); + strcat(outPath, "."); + strcat(outPath, opt_e); + + log_printf("initting...\n"); + init_tables(); + scan_existing_skeleton(); + scan_and_generate(infile); + log_printf("freeing memory...\n"); + free_tables(); + clear_skeleton_queue(); + fclose(infile); + optind++; + } + } + +#ifdef SGDEBUG + log_flush(); + log_close(); +#endif /* SGDEBUG */ + + return 0; +} diff --git a/src/tools/stubgen/parser.y b/src/tools/stubgen/parser.y new file mode 100644 index 0000000000..b77d634844 --- /dev/null +++ b/src/tools/stubgen/parser.y @@ -0,0 +1,1787 @@ +%{ +/* + * FILE: parser.y + * AUTH: Michael John Radwin + * + * DESC: stubgen grammar description. Portions borrowed from + * Newcastle University's Arjuna project (http://arjuna.ncl.ac.uk/), + * and Jeff Lee's ANSI Grammar + * (ftp://ftp.uu.net/usenet/net.sources/ansi.c.grammar.Z) + * This grammar is only a subset of the real C++ language. + * + * DATE: Thu Aug 15 13:10:06 EDT 1996 + * $Id: parser.y,v 1.1 2002/07/09 12:24:59 ejakowatz Exp $ + * + * Copyright (c) 1996-1998 Michael John Radwin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * -------------------------------------------------------------------- + * + * $Log: parser.y,v $ + * Revision 1.1 2002/07/09 12:24:59 ejakowatz + * It is accomplished ... + * + * Revision 1.1 2001/11/07 10:06:07 ithamar + * Added stubgen to CVS + * + * Revision 1.72 1998/07/07 00:14:06 mradwin + * removed extra space from throw_decl, cleaned up memory leak + * in ctor skeleton + * + * Revision 1.71 1998/06/11 14:52:09 mradwin + * allow for empty class declarations, such as + * class Element {}; + * also, differentiate structs from classes with + * new STRUCT_KIND tag. + * New version: 2.04 + * + * Revision 1.70 1998/05/11 19:49:11 mradwin + * Version 2.03 (updated copyright information). + * + * Revision 1.69 1998/04/07 23:43:34 mradwin + * changed error-handling code significantly. + * several functions now return a value, and instead of + * calling fatal(), we do a YYABORT or YYERROR to get out + * of the parsing state. + * New version: 2.02. + * + * Revision 1.68 1998/03/28 02:59:41 mradwin + * working on slightly better error recovery; not done yet. + * + * Revision 1.67 1998/03/28 02:34:56 mradwin + * added multi-line function parameters + * also changed pointer and reference (* and &) types so there + * is no trailing space before the parameter name. + * + * Revision 1.66 1998/01/12 19:39:11 mradwin + * modified rcsid + * + * Revision 1.65 1997/11/13 22:50:55 mradwin + * moved copyright from parser.y to main.c + * + * Revision 1.64 1997/11/13 22:40:15 mradwin + * fixed a silly comment bug + * + * Revision 1.63 1997/11/13 22:37:31 mradwin + * changed char[] to char * to make non-gcc compilers + * a little happier. We need to #define const to nothing + * for other compilers as well. + * + * Revision 1.62 97/11/13 21:29:30 21:29:30 mradwin (Michael Radwin) + * moved code from parser.y to main.c + * + * Revision 1.61 1997/11/13 21:10:17 mradwin + * renamed stubgen.[ly] to parser.y lexer.l + * + * Revision 1.60 1997/11/11 04:11:29 mradwin + * fixed command-line flags: invalid options now force usgage. + * + * Revision 1.59 1997/11/11 04:03:56 mradwin + * changed version info + * + * Revision 1.58 1997/11/11 03:54:05 mradwin + * fixed a long-standing bug with -b option. a typo was causing + * the -b flag to be ignored. + * + * Revision 1.57 1997/11/11 03:52:06 mradwin + * changed fatal() + * + * Revision 1.56 1997/11/05 03:02:02 mradwin + * Modified logging routines. + * + * Revision 1.55 1997/11/05 02:14:38 mradwin + * Made some compiler warnings disappear. + * + * Revision 1.54 1997/11/01 23:26:13 mradwin + * new Revision string and usage info + * + * Revision 1.53 1997/11/01 23:12:43 mradwin + * greatly improved error-recovery. errors no longer spill over + * into other files because the yyerror state is properly reset. + * + * Revision 1.52 1997/10/27 01:14:23 mradwin + * fixed constant_value so it supports simple arithmetic. it's + * not as robust as full expressions, but this will handle the + * char buffer[BUFSIZE + 1] problem. + * + * Also removed expansion rules that simply did { $$ = $1; } because + * that action is implicit anyway. + * + * Revision 1.51 1997/10/26 23:16:32 mradwin + * changed inform_user and fatal functions to use varargs + * + * Revision 1.50 1997/10/26 22:27:07 mradwin + * Fixed this bug: + * stubgen dies on the following because the protected section is empty: + * + * class WidgetCsg : public WidgetLens { + * protected: + * + * public: + * virtual ~WidgetCsg() {} + * WidgetCsg(); + * }; + * + * Error: + * stubgen version 2.0-beta $Revision: 1.1 $. + * parse error at line 4, file test.H: + * public: + * ^ + * + * Revision 1.49 1997/10/16 19:42:48 mradwin + * added support for elipses, static member/array initializers, + * and bitfields. + * + * Revision 1.48 1997/10/16 17:35:39 mradwin + * cleaned up usage info + * + * Revision 1.47 1997/10/16 17:12:59 mradwin + * handle extern "C" blocks better now, and support multi-line + * macros. still need error-checking. + * + * Revision 1.46 1997/10/15 22:09:06 mradwin + * changed tons of names. stubelem -> sytaxelem, + * stubin -> infile, stubout -> outfile, stublog -> logfile. + * + * Revision 1.45 1997/10/15 21:33:36 mradwin + * fixed up function_hdr + * + * Revision 1.44 1997/10/15 21:33:02 mradwin + * *** empty log message *** + * + * Revision 1.43 1997/10/15 17:42:37 mradwin + * added support for 'extern "C" { ... }' blocks. + * + * Revision 1.42 1997/09/26 20:59:18 mradwin + * now allow "struct foobar *f" to appear in a parameter + * list or as a variable decl. Had to remove the + * class_or_struct rule and blow up the class_specifier + * description. + * + * Revision 1.41 1997/09/26 19:02:18 mradwin + * fixed memory leak involving template decls in skeleton code. + * Leads me to believe that skel_elemcmp() is flawed, because + * it may rely in parent->templ info. + * + * Revision 1.40 1997/09/26 18:44:22 mradwin + * changed parameter handing from char *'s to an argument type + * to facilitate comparisons between skeleton code + * and header code. Now we can correctly recognize different + * parameter names while still maintaining the same signature. + * + * Revision 1.39 1997/09/26 00:47:29 mradwin + * added better base type support -- recognize things like + * "long long" and "short int" now. + * + * Revision 1.38 1997/09/19 18:16:37 mradwin + * allowed an instance name to come after a class, struct, + * union, or enum. This improves parseability of typedefs + * commonly found in c header files, although true typedefs are + * not understood. + * + * Revision 1.37 1997/09/15 22:38:28 mradwin + * did more revision on the SGDEBUG stuff + * + * Revision 1.36 1997/09/15 19:05:26 mradwin + * allow logging to be compiled out by turning off SGDEBUG + * + * Revision 1.35 1997/09/12 00:58:43 mradwin + * duh, silly me. messed up compilation. + * + * Revision 1.34 1997/09/12 00:57:49 mradwin + * Revision string inserted in usage + * + * Revision 1.33 1997/09/12 00:51:19 mradwin + * string copyright added to code for binary copyright. + * + * Revision 1.32 1997/09/12 00:47:21 mradwin + * some more compactness of grammar with parameter_list_opt + * and also ampersand_opt + * + * Revision 1.31 1997/09/12 00:26:19 mradwin + * better template support, but still poor + * + * Revision 1.30 1997/09/08 23:24:51 mradwin + * changes to error-handling code. + * also got rid of the %type for the top-level rules + * + * Revision 1.30 1997/09/08 23:20:02 mradwin + * some error reporting changes and default values for top-level + * grammar stuff. + * + * Revision 1.29 1997/09/08 17:54:24 mradwin + * cleaned up options and usage info. + * + * Revision 1.28 1997/09/05 19:38:04 mradwin + * changed options for .ext instead of -l or -x + * + * Revision 1.27 1997/09/05 19:17:06 mradwin + * works for scanning old versions, except for parameter + * names that differ between .H and .C files. + * + * Revision 1.26 1997/09/05 16:34:36 mradwin + * GPL-ized code. + * + * Revision 1.25 1997/09/05 16:11:44 mradwin + * some simple cleanup before GPL-izing the code + * + * Revision 1.24 1997/09/04 19:50:34 mradwin + * whoo-hoo! by blowing up the description + * exponentially, it works! + * + * Revision 1.23 1997/03/20 16:05:41 mjr + * renamed syntaxelem to syntaxelem_t, cleaned up throw_decl + * + * Revision 1.22 1996/10/02 15:16:57 mjr + * using pathname.h instead of libgen.h + * + * Revision 1.21 1996/09/12 14:44:49 mjr + * Added throw decl recognition (great, another 4 bytes in syntaxelem) + * and cleaned up the grammar so that const_opt appears in far fewer + * places. const_opt is by default 0 as well, so we don't need to + * pass it as an arg to new_elem(). + * + * I also added a fix to a potential bug with the MINIT and INLIN + * exclusive start states. I think they could have been confused + * by braces within comments, so now I'm grabbing comments in those + * states as well. + * + * Revision 1.20 1996/09/12 04:55:22 mjr + * changed expand strategy. Don't expand while parsing now; + * enqueue as we go along and expand at the end. Eventually + * we'll need to provide similar behavior for when we parse + * .C files + * + * Revision 1.19 1996/09/12 03:46:10 mjr + * No concrete changes in code. Just added some sanity by + * factoring out code into util.[ch] and putting some prototypes + * that were in table.h into stubgen.y where they belong. + * + * Revision 1.18 1996/09/06 14:32:48 mjr + * defined the some_KIND constants for clarity, and made + * expandClass return immediately if it was give something other + * than a CLASS_KIND element. + * + * Revision 1.17 1996/09/06 14:05:44 mjr + * Almost there with expanded operator goodies. Still need + * to get OPERATOR type_name to work. + * + * Revision 1.16 1996/09/04 22:28:09 mjr + * nested classes work and default arguments are now removed + * from the parameter lists. + * + * Revision 1.15 1996/09/04 20:01:57 mjr + * non-functional expanded code. needs work. + * + * Revision 1.14 1996/09/01 21:29:34 mjr + * put the expanded_operator code back in as a useless rule. + * oughta think about fixing it up if possible + * + * Revision 1.13 1996/09/01 20:59:48 mjr + * Added collectMemberInitList() function, which is similar + * to collectInlineDef() and also the exclusive state MINIT + * + * Revision 1.12 1996/08/23 05:09:19 mjr + * fixed up some more portability things + * + * Revision 1.11 1996/08/22 02:43:47 mjr + * added parse error message (using O'Reilly p. 274) + * + * Revision 1.10 1996/08/21 18:33:50 mjr + * added support for template instantiation in the type_name + * rule. surprisingly it didn't cause any shift/reduce conflicts. + * + * Revision 1.9 1996/08/21 17:40:56 mjr + * added some cpp directives for porting to WIN32 + * + * Revision 1.8 1996/08/21 00:00:19 mjr + * approaching stability and usability. command line arguments + * are handled now and the fopens and fcloses appear to work. + * + * Revision 1.7 1996/08/20 20:44:23 mjr + * added initial support for optind but it is incomplete. + * + * Revision 1.6 1996/08/19 17:14:59 mjr + * misordered args, fixed bug + * + * Revision 1.5 1996/08/19 17:11:41 mjr + * RCS got confused with the RCS-style header goodies. + * got it cleaned up now. + * + * Revision 1.4 1996/08/19 17:01:33 mjr + * Removed the expanded code checking and added + * lots of code that duplicates what stubgen.pl did. + * still need options pretty badly + * + * Revision 1.3 1996/08/17 23:21:10 mjr + * added the expanded operator code, cleaned up tabs. + * consider putting all of the expanded code in another + * grammar - this one is getting cluttered. + * + */ +%} + +%{ +#include "table.h" +#include "util.h" +#include +#include +#include + +#ifdef WIN32 +#include /* defintion of alloca */ +#include "getopt.h" /* use GNU getopt */ +#endif /* WIN32 */ + +#ifndef WIN32 +#include +#endif /* WIN32 */ + +/* defined in lexer.l */ +extern int collectInlineDef(); +extern int collectMemberInitList(); + +/* defined here in parser.y */ +static int error_recovery(); +static int yyerror(char *); +static const char rcsid[] = "$Id: parser.y,v 1.1 2002/07/09 12:24:59 ejakowatz Exp $"; + +/* defined in main.c */ +extern FILE *outfile; +extern char *currentFile; +extern int lineno; + +%} + +%union { + char *string; + syntaxelem_t *elt; + arg_t *arg; + int flag; +} + +%token IDENTIFIER CONSTANT STRING_LITERAL +%token CHAR SHORT INT LONG SIGNED UNSIGNED FLOAT DOUBLE VOID +%token NEW DELETE TEMPLATE THROW + +%token PTR_OP INC_OP DEC_OP LEFT_OP RIGHT_OP LE_OP GE_OP EQ_OP NE_OP +%token AND_OP OR_OP MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN +%token SUB_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN +%token XOR_ASSIGN OR_ASSIGN CLCL MEM_PTR_OP + +%token FRIEND OPERATOR CONST CLASS STRUCT UNION ENUM +%token PROTECTED PRIVATE PUBLIC EXTERN ELIPSIS + +%type simple_type_name simple_signed_type non_reference_type +%type scoped_identifier pointer asterisk +%type type_name binary_operator +%type assignment_operator unary_operator any_operator +%type variable_specifier_list union_specifier +%type constant_value multiple_variable_specifier +%type enum_specifier enumerator_list enumerator +%type template_specifier template_arg template_arg_list +%type template_instance_arg template_instance_arg_list +%type throw_decl throw_list variable_name bitfield_savvy_identifier +%type primary_expression expression +%type multiplicative_expression additive_expression +%type const_opt ampersand_opt +%type class_specifier +%type member_func_specifier function_specifier constructor +%type destructor member_specifier member member_with_access +%type mem_type_specifier member_or_error +%type member_list member_list_opt +%type member_func_inlined type_specifier overloaded_op_specifier +%type member_func_skel member_func_skel_spec +%type constructor_skeleton destructor_skeleton +%type overloaded_op_skeleton function_skeleton +%type variable_or_parameter variable_specifier +%type parameter_list parameter_list_opt unnamed_parameter + + +%start translation_unit +%% + +translation_unit + : declaration + | translation_unit declaration + ; + +declaration + : declaration_specifiers ';' + | EXTERN STRING_LITERAL compound_statement +{ + log_printf("IGNORING extern \"C\" { ... } block.\n"); + free($2); +} + | member_func_inlined +{ + $1->kind = INLINED_KIND; + log_printf("\nBEGIN matched dec : m_f_i rule --"); + print_se($1); + log_printf("END matched dec : m_f_i rule\n"); +} + | function_skeleton +{ + $1->kind = SKEL_KIND; + log_printf("\nBEGIN matched dec : function_skeleton rule --"); + print_se($1); + enqueue_skeleton($1); + log_printf("END matched dec : function_skeleton rule\n"); +} + | ';' + | error +{ + log_printf("declaration : error. Attempting to recover...\n"); + yyerrok; + yyclearin; + if (error_recovery() != 0) { + log_printf("ERROR recovery could not complete -- YYABORT.\n"); + YYABORT; + } + log_printf("ERROR recovery complete.\n"); +} + ; + +declaration_specifiers + : member_specifier +{ + /* the name of the rule "member_specifier" might be misleading, but + * this is either a class, struct, union, enum, global var, global + * prototype, etc.. */ + if ($1->kind == CLASS_KIND || $1->kind == STRUCT_KIND) { + enqueue_class($1); + } else { + log_printf("\nIGNORING dec_spec : mem_spec (%s) --", + string_kind($1->kind)); + print_se($1); + log_printf("END IGNORING dec_spec : mem_spec (%s)\n", + string_kind($1->kind)); + } +} + | forward_decl + ; + +type_specifier + : union_specifier +{ + /* ret_type, name, args, kind */ + syntaxelem_t *elem = new_elem(strdup(""), $1, NULL, IGNORE_KIND); +/* print_se(elem); */ + $$ = elem; +} + | enum_specifier +{ + /* ret_type, name, args, kind */ + syntaxelem_t *elem = new_elem(strdup(""), $1, NULL, IGNORE_KIND); +/* print_se(elem); */ + $$ = elem; +} + | class_specifier + ; + +ampersand_opt + : /* nothing */ { $$ = 0; } + | '&' { $$ = 1; } + ; + +type_name + : non_reference_type ampersand_opt +{ + char *tmp_str = (char *) malloc(strlen($1) + ($2 ? 2 : 0) + 1); + strcpy(tmp_str, $1); + if ($2) + strcat(tmp_str, " &"); + free($1); + $$ = tmp_str; +} + | CONST non_reference_type ampersand_opt +{ + char *tmp_str = (char *) malloc(strlen($2) + ($3 ? 2 : 0) + 7); + sprintf(tmp_str, "const %s%s", $2, ($3 ? " &" : "")); + free($2); + $$ = tmp_str; +} + ; + +forward_decl + : CLASS IDENTIFIER { free($2); } + | CLASS scoped_identifier { free($2); } + | STRUCT IDENTIFIER { free($2); } + | STRUCT scoped_identifier { free($2); } + ; + +non_reference_type + : scoped_identifier + | IDENTIFIER + | STRUCT IDENTIFIER +{ + char *tmp_str = (char *) malloc(strlen($2) + 8); + strcpy(tmp_str, "struct "); + strcat(tmp_str, $2); + free($2); + $$ = tmp_str; +} + | scoped_identifier '<' template_instance_arg_list '>' +{ + char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 3); + sprintf(tmp_str, "%s<%s>", $1, $3); + free($1); + free($3); + $$ = tmp_str; +} + | IDENTIFIER '<' template_instance_arg_list '>' +{ + char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 3); + sprintf(tmp_str, "%s<%s>", $1, $3); + free($1); + free($3); + $$ = tmp_str; +} + | scoped_identifier '<' template_instance_arg_list '>' pointer +{ + char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + strlen($5) + 4); + sprintf(tmp_str, "%s<%s> %s", $1, $3, $5); + free($1); + free($3); + free($5); + $$ = tmp_str; +} + | IDENTIFIER '<' template_instance_arg_list '>' pointer +{ + char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + strlen($5) + 4); + sprintf(tmp_str, "%s<%s> %s", $1, $3, $5); + free($1); + free($3); + free($5); + $$ = tmp_str; +} + | scoped_identifier pointer +{ + char *tmp_str = (char *) malloc(strlen($1) + strlen($2) + 2); + sprintf(tmp_str, "%s %s", $1, $2); + free($1); + free($2); + $$ = tmp_str; +} + | IDENTIFIER pointer +{ + char *tmp_str = (char *) malloc(strlen($1) + strlen($2) + 2); + sprintf(tmp_str, "%s %s", $1, $2); + free($1); + free($2); + $$ = tmp_str; +} + | STRUCT IDENTIFIER pointer +{ + char *tmp_str = (char *) malloc(strlen($2) + strlen($3) + 9); + sprintf(tmp_str, "struct %s %s", $2, $3); + free($2); + free($3); + $$ = tmp_str; +} + | simple_signed_type + | simple_signed_type pointer +{ + char *tmp_str = (char *) malloc(strlen($1) + strlen($2) + 2); + sprintf(tmp_str, "%s %s", $1, $2); + free($1); + free($2); + $$ = tmp_str; +} + ; + +simple_signed_type + : simple_type_name + | SIGNED simple_type_name +{ + char *tmp_str = (char *) malloc(strlen($2) + 8); + strcpy(tmp_str,"signed "); + strcat(tmp_str, $2); + free($1); + free($2); + $$ = tmp_str; +} + | UNSIGNED simple_type_name +{ + char *tmp_str = (char *) malloc(strlen($2) + 10); + strcpy(tmp_str,"unsigned "); + strcat(tmp_str, $2); + free($1); + free($2); + $$ = tmp_str; +} + ; + +simple_type_name + : CHAR + | SHORT + | SHORT INT +{ + $$ = strdup("short int"); + free($1); + free($2); +} + | INT + | LONG + | LONG INT +{ + $$ = strdup("long int"); + free($1); + free($2); +} + | LONG LONG +{ + $$ = strdup("long long"); + free($1); + free($2); +} + | LONG LONG INT +{ + $$ = strdup("long long int"); + free($1); + free($2); + free($3); +} + | UNSIGNED + | FLOAT + | DOUBLE + | VOID + ; + +scoped_identifier + : IDENTIFIER CLCL IDENTIFIER +{ + char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 3); + sprintf(tmp_str, "%s::%s", $1, $3); + free($1); + free($3); + $$ = tmp_str; +} + | scoped_identifier CLCL IDENTIFIER +{ + /* control-Y programming! */ + char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 3); + sprintf(tmp_str, "%s::%s", $1, $3); + free($1); + free($3); + $$ = tmp_str; +} + ; + +pointer + : asterisk + | pointer asterisk +{ + char *tmp_str = (char *) malloc(strlen($1) + strlen($2) + 1); + strcpy(tmp_str,$1); + strcat(tmp_str,$2); + free($1); + free($2); + $$ = tmp_str; +} + ; + +asterisk + : '*' { $$ = strdup("*"); } + | '*' CONST { $$ = strdup("*const "); } + ; + +variable_or_parameter + : type_name bitfield_savvy_identifier +{ + arg_t *new_arg = (arg_t *) malloc(sizeof(arg_t)); + new_arg->type = $1; + new_arg->name = $2; + new_arg->array = NULL; + new_arg->next = NULL; + $$ = new_arg; +} + | type_name scoped_identifier +{ + arg_t *new_arg = (arg_t *) malloc(sizeof(arg_t)); + new_arg->type = $1; + new_arg->name = $2; + new_arg->array = NULL; + new_arg->next = NULL; + $$ = new_arg; +} + | variable_or_parameter '[' constant_value ']' +{ + char *old_array = $1->array; + int old_len = old_array ? strlen(old_array) : 0; + $1->array = (char *) malloc(strlen($3) + old_len + 3); + sprintf($1->array, "%s[%s]", old_array ? old_array : "", $3); + free($3); + if (old_array) + free(old_array); + $$ = $1; +} + | variable_or_parameter '[' ']' +{ + char *old_array = $1->array; + int old_len = old_array ? strlen(old_array) : 0; + $1->array = (char *) malloc(old_len + 3); + sprintf($1->array, "%s[]", old_array ? old_array : ""); + if (old_array) + free(old_array); + $$ = $1; +} + ; + +bitfield_savvy_identifier + : IDENTIFIER + | IDENTIFIER ':' CONSTANT { free($3); $$ = $1;} + ; + +variable_name + : bitfield_savvy_identifier + | pointer IDENTIFIER +{ + char *tmp_str = (char *) malloc(strlen($1) + strlen($2) + 2); + sprintf(tmp_str, "%s %s", $1, $2); + free($1); + free($2); + $$ = tmp_str; +} + | variable_name '[' constant_value ']' +{ + char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 3); + sprintf(tmp_str, "%s[%s]", $1, $3); + free($1); + free($3); + $$ = tmp_str; +} + | variable_name '[' ']' +{ + char *tmp_str = (char *) malloc(strlen($1) + 3); + strcpy(tmp_str, $1); + strcat(tmp_str, "[]"); + free($1); + $$ = tmp_str; +} + ; + +variable_specifier + : variable_or_parameter + | EXTERN variable_or_parameter { $$ = $2; } + | variable_or_parameter '=' constant_value +{ + free($3); + $$ = $1; +} + ; + +multiple_variable_specifier + : variable_specifier +{ + $$ = args_to_string($1, 0); + free_args($1); +} + | multiple_variable_specifier ',' variable_name +{ + char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 3); + sprintf(tmp_str, "%s, %s", $1, $3); + free($1); + free($3); + $$ = tmp_str; +} + ; + +variable_specifier_list + : multiple_variable_specifier ';' +{ + char *tmp_str = (char *) malloc(strlen($1) + 2); + sprintf(tmp_str, "%s;", $1); + free($1); + $$ = tmp_str; +} + | variable_specifier_list multiple_variable_specifier ';' +{ + char *tmp_str = (char *) malloc(strlen($1) + strlen($2) + 3); + sprintf(tmp_str, "%s\n%s;", $1, $2); + free($1); + free($2); + $$ = tmp_str; +} + ; + +parameter_list_opt + : /* nothing */ +{ + $$ = NULL; +} + | parameter_list +{ + $$ = reverse_arg_list($1); +} + | parameter_list ',' ELIPSIS +{ + arg_t *new_arg = (arg_t *) malloc(sizeof(arg_t)); + new_arg->type = strdup("..."); + new_arg->name = NULL; + new_arg->array = NULL; + new_arg->next = $1; + $$ = reverse_arg_list(new_arg); +} + | ELIPSIS +{ + arg_t *new_arg = (arg_t *) malloc(sizeof(arg_t)); + new_arg->type = strdup("..."); + new_arg->name = NULL; + new_arg->array = NULL; + new_arg->next = NULL; + $$ = new_arg; +} + ; + +parameter_list + : variable_specifier + | unnamed_parameter + | parameter_list ',' variable_specifier +{ + $3->next = $1; + $$ = $3; +} + | parameter_list ',' unnamed_parameter +{ + $3->next = $1; + $$ = $3; +} + ; + +unnamed_parameter + : type_name +{ + arg_t *new_arg = (arg_t *) malloc(sizeof(arg_t)); + new_arg->type = $1; + new_arg->name = NULL; + new_arg->array = NULL; + new_arg->next = NULL; + $$ = new_arg; +} + | type_name '=' constant_value +{ + arg_t *new_arg = (arg_t *) malloc(sizeof(arg_t)); + new_arg->type = $1; + new_arg->name = NULL; + new_arg->array = NULL; + new_arg->next = NULL; + free($3); + $$ = new_arg; +} + | unnamed_parameter '[' constant_value ']' +{ + char *old_array = $1->array; + int old_len = old_array ? strlen(old_array) : 0; + $1->array = (char *) malloc(strlen($3) + old_len + 3); + sprintf($1->array, "%s[%s]", old_array ? old_array : "", $3); + free($3); + if (old_array) + free(old_array); + $$ = $1; +} + | unnamed_parameter '[' ']' +{ + char *old_array = $1->array; + int old_len = old_array ? strlen(old_array) : 0; + $1->array = (char *) malloc(old_len + 3); + sprintf($1->array, "%s[]", old_array ? old_array : ""); + if (old_array) + free(old_array); + $$ = $1; +} + ; + +function_skeleton + : member_func_skel compound_statement + | constructor_skeleton ':' + { if (collectMemberInitList() != 0) YYERROR; } compound_statement + | template_specifier member_func_skel compound_statement +{ + /* I think this is the correct behavior, but skel_elemcmp is wrong */ + /* $2->templ = $1; */ + free($1); + $$ = $2; +} + | template_specifier constructor_skeleton ':' + { if (collectMemberInitList() != 0) YYERROR; } compound_statement +{ + /* I think this is the correct behavior, but skel_elemcmp is wrong */ + /* $2->templ = $1; */ + free($1); + $$ = $2; +} + ; + +member_func_inlined + : member_func_specifier compound_statement + | constructor ':' + { if (collectMemberInitList() != 0) YYERROR; } compound_statement + ; + +member_func_skel + : member_func_skel_spec const_opt throw_decl +{ + $1->const_flag = $2; + $1->throw_decl = $3; + $$ = $1; +} + | constructor_skeleton + | destructor_skeleton + ; + +member_func_specifier + : function_specifier const_opt throw_decl +{ + $1->const_flag = $2; + $1->throw_decl = $3; + $$ = $1; +} + | constructor + | destructor + ; + + +member_func_skel_spec + : type_name scoped_identifier '(' parameter_list_opt ')' +{ + /* ret_type, name, args, kind */ + syntaxelem_t *elem = new_elem($1, $2, $4, FUNC_KIND); +/* print_se(elem); */ + $$ = elem; +} + | type_name IDENTIFIER '<' template_instance_arg_list '>' CLCL IDENTIFIER '(' parameter_list_opt ')' +{ + /* ret_type, name, args, kind */ + syntaxelem_t *elem = new_elem($1, + (char *) malloc(strlen($2) + strlen($4) + strlen($7) + 5), + $9, FUNC_KIND); + sprintf(elem->name,"%s<%s>::%s", $2, $4, $7); + free($2); + free($4); + free($7); + $$ = elem; +} + | overloaded_op_skeleton + ; + + + +function_specifier + : type_name IDENTIFIER '(' parameter_list_opt ')' +{ + /* ret_type, name, args, kind */ + syntaxelem_t *elem = new_elem($1, $2, $4, FUNC_KIND); + print_se(elem); + $$ = elem; +} + | overloaded_op_specifier + ; + +overloaded_op_skeleton + : type_name scoped_identifier CLCL OPERATOR any_operator '(' parameter_list_opt ')' +{ + /* ret_type, name, args, kind */ + syntaxelem_t *elem = new_elem($1, (char *)malloc(strlen($2) + strlen($5) + 12), + $7, FUNC_KIND); + sprintf(elem->name, "%s::operator%s", $2, $5); + free($2); + free($5); +/* print_se(elem); */ + $$ = elem; +} + | scoped_identifier CLCL OPERATOR type_name '(' ')' +{ + /* ret_type, name, args, kind */ + syntaxelem_t *elem = new_elem(strdup(""), + (char *)malloc(strlen($1) + strlen($4) + 13), + NULL, FUNC_KIND); + sprintf(elem->name, "%s::operator %s", $1, $4); + free($1); + free($4); +/* print_se(elem); */ + $$ = elem; +} + | type_name IDENTIFIER CLCL OPERATOR any_operator '(' parameter_list_opt ')' +{ + /* ret_type, name, args, kind */ + syntaxelem_t *elem = new_elem($1, (char *)malloc(strlen($2) + strlen($5) + 12), + $7, FUNC_KIND); + sprintf(elem->name, "%s::operator%s", $2, $5); + free($2); + free($5); +/* print_se(elem); */ + $$ = elem; +} + | IDENTIFIER CLCL OPERATOR type_name '(' ')' +{ + /* ret_type, name, args, kind */ + syntaxelem_t *elem = new_elem(strdup(""), + (char *)malloc(strlen($1) + strlen($4) + 13), + NULL, FUNC_KIND); + sprintf(elem->name, "%s::operator %s", $1, $4); + free($1); + free($4); +/* print_se(elem); */ + $$ = elem; +} + ; + +overloaded_op_specifier + : type_name OPERATOR any_operator '(' parameter_list_opt ')' +{ + /* ret_type, name, args, kind */ + syntaxelem_t *elem = new_elem($1, (char *)malloc(strlen($3) + 9), + $5, FUNC_KIND); + sprintf(elem->name, "operator%s", $3); + free($3); + print_se(elem); + $$ = elem; +} + | OPERATOR type_name '(' ')' +{ + /* ret_type, name, args, kind */ + syntaxelem_t *elem = new_elem(strdup(""), (char *)malloc(strlen($2) + 10), + NULL, FUNC_KIND); + sprintf(elem->name, "operator %s", $2); + free($2); + print_se(elem); + $$ = elem; +} + ; + +const_opt + : /* nothing */ { $$ = 0; } + | CONST { $$ = 1; } + ; + +throw_decl + : /* nothing */ { $$ = NULL; } + | THROW '(' throw_list ')' +{ + char *tmp_str = (char *) malloc(strlen($3) + 8); + sprintf(tmp_str, "throw(%s)", $3); + free($3); + $$ = tmp_str; +} + ; + +throw_list + : type_name + | throw_list ',' type_name +{ + char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 3); + sprintf(tmp_str, "%s, %s", $1, $3); + free($1); + free($3); + $$ = tmp_str; +} + ; + +destructor + : '~' IDENTIFIER '(' ')' +{ + /* ret_type, name, args, kind */ + syntaxelem_t *elem = new_elem(strdup(""), (char *) malloc(strlen($2) + 2), + NULL, FUNC_KIND); + sprintf(elem->name,"~%s", $2); + free($2); +/* print_se(elem); */ + $$ = elem; +} + ; + +destructor_skeleton + : scoped_identifier CLCL '~' IDENTIFIER '(' ')' +{ + /* ret_type, name, args, kind */ + syntaxelem_t *elem = new_elem(strdup(""), + (char *) malloc(strlen($1) + strlen($4) + 4), + NULL, FUNC_KIND); + sprintf(elem->name,"%s::~%s", $1, $4); + free($1); + free($4); +/* print_se(elem); */ + $$ = elem; +} + | IDENTIFIER CLCL '~' IDENTIFIER '(' ')' +{ + /* ret_type, name, args, kind */ + syntaxelem_t *elem = new_elem(strdup(""), + (char *) malloc(strlen($1) + strlen($4) + 4), + NULL, FUNC_KIND); + sprintf(elem->name,"%s::~%s", $1, $4); + free($1); + free($4); +/* print_se(elem); */ + $$ = elem; +} + | IDENTIFIER '<' template_instance_arg_list '>' CLCL '~' IDENTIFIER '(' ')' +{ + /* ret_type, name, args, kind */ + syntaxelem_t *elem = new_elem(strdup(""), + (char *) malloc(strlen($1) + strlen($3) + strlen($7) + 6), + NULL, FUNC_KIND); + sprintf(elem->name,"%s<%s>::~%s", $1, $3, $7); + free($1); + free($3); + free($7); + $$ = elem; +} + | scoped_identifier '<' template_instance_arg_list '>' CLCL '~' IDENTIFIER '(' ')' +{ + /* ret_type, name, args, kind */ + syntaxelem_t *elem = new_elem(strdup(""), + (char *) malloc(strlen($1) + strlen($3) + strlen($7) + 6), + NULL, FUNC_KIND); + sprintf(elem->name,"%s<%s>::~%s", $1, $3, $7); + free($1); + free($3); + free($7); + $$ = elem; +} + ; + +constructor + : IDENTIFIER '(' parameter_list_opt ')' throw_decl +{ + /* ret_type, name, args, kind */ + syntaxelem_t *elem = new_elem(strdup(""), $1, $3, FUNC_KIND); + elem->throw_decl = $5; +/* print_se(elem); */ + $$ = elem; +} + ; + +constructor_skeleton + : scoped_identifier '(' parameter_list_opt ')' throw_decl +{ + /* ret_type, name, args, kind */ + syntaxelem_t *elem = new_elem(strdup(""), $1, $3, FUNC_KIND); + elem->throw_decl = $5; +/* print_se(elem); */ + $$ = elem; +} + | IDENTIFIER '<' template_instance_arg_list '>' CLCL IDENTIFIER '(' parameter_list_opt ')' throw_decl +{ + /* ret_type, name, args, kind */ + syntaxelem_t *elem = new_elem(strdup(""), + (char *) malloc(strlen($1) + strlen($3) + strlen($6) + 5), + $8, FUNC_KIND); + sprintf(elem->name,"%s<%s>::%s", $1, $3, $6); + free($1); + free($3); + free($6); + elem->throw_decl = $10; + $$ = elem; +} + | scoped_identifier '<' template_instance_arg_list '>' CLCL IDENTIFIER '(' parameter_list_opt ')' throw_decl +{ + /* ret_type, name, args, kind */ + syntaxelem_t *elem = new_elem(strdup(""), + (char *) malloc(strlen($1) + strlen($3) + strlen($6) + 5), + $8, FUNC_KIND); + sprintf(elem->name,"%s<%s>::%s", $1, $3, $6); + free($1); + free($3); + free($6); + elem->throw_decl = $10; + $$ = elem; +} + ; + +compound_statement + : '{' { if (collectInlineDef() != 0) YYERROR; } '}' + ; + +enum_specifier + : ENUM '{' enumerator_list '}' +{ + char *tmp_str = (char *) malloc(strlen($3) + 10); + sprintf(tmp_str, "enum { %s }", $3); + free($3); + $$ = tmp_str; +} + | ENUM IDENTIFIER '{' enumerator_list '}' +{ + char *tmp_str = (char *) malloc(strlen($2) + strlen($4) + 11); + sprintf(tmp_str, "enum %s { %s }", $2, $4); + free($2); + free($4); + $$ = tmp_str; +} + | ENUM IDENTIFIER +{ + char *tmp_str = (char *) malloc(strlen($2) + 6); + sprintf(tmp_str, "enum %s", $2); + free($2); + $$ = tmp_str; +} + ; + +enumerator_list + : enumerator + | enumerator_list ',' enumerator +{ + char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 3); + sprintf(tmp_str, "%s, %s", $1, $3); + free($1); + free($3); + $$ = tmp_str; +} + ; + +enumerator + : IDENTIFIER + | IDENTIFIER '=' constant_value +{ + char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 2); + sprintf(tmp_str, "%s=%s", $1, $3); + free($1); + free($3); + $$ = tmp_str; +} + ; + +access_specifier_opt + : /* nothing */ + | access_specifier + ; + +access_specifier_list + : access_specifier ':' + | access_specifier_list access_specifier ':' + ; + +access_specifier + : PUBLIC + | PRIVATE + | PROTECTED + ; + +unary_operator + : '&' { $$ = strdup("&"); } + | '*' { $$ = strdup("*"); } + | '+' { $$ = strdup("+"); } + | '-' { $$ = strdup("-"); } + | '~' { $$ = strdup("~"); } + | '!' { $$ = strdup("!"); } + ; + +binary_operator + : '/' { $$ = strdup("/"); } + | '%' { $$ = strdup("%"); } + | '^' { $$ = strdup("^"); } + | '|' { $$ = strdup("|"); } + | '<' { $$ = strdup("<"); } + | '>' { $$ = strdup(">"); } + | ',' { $$ = strdup(","); } + ; + +assignment_operator + : '=' { $$ = strdup("="); } + | MUL_ASSIGN { $$ = strdup("*="); } + | DIV_ASSIGN { $$ = strdup("/="); } + | MOD_ASSIGN { $$ = strdup("%="); } + | ADD_ASSIGN { $$ = strdup("+="); } + | SUB_ASSIGN { $$ = strdup("-="); } + | LEFT_ASSIGN { $$ = strdup("<<="); } + | RIGHT_ASSIGN { $$ = strdup(">>="); } + | AND_ASSIGN { $$ = strdup("&="); } + | XOR_ASSIGN { $$ = strdup("^="); } + | OR_ASSIGN { $$ = strdup("|="); } + ; + +any_operator + : assignment_operator + | unary_operator + | binary_operator + | NEW { $$ = strdup(" new"); } + | DELETE { $$ = strdup(" delete"); } + | PTR_OP { $$ = strdup("->"); } + | MEM_PTR_OP { $$ = strdup("->*"); } + | INC_OP { $$ = strdup("++"); } + | DEC_OP { $$ = strdup("--"); } + | LEFT_OP { $$ = strdup("<<"); } + | RIGHT_OP { $$ = strdup(">>"); } + | LE_OP { $$ = strdup("<="); } + | GE_OP { $$ = strdup(">="); } + | EQ_OP { $$ = strdup("=="); } + | NE_OP { $$ = strdup("!="); } + | AND_OP { $$ = strdup("&&"); } + | OR_OP { $$ = strdup("||"); } + | '[' ']' { $$ = strdup("[]"); } + | '(' ')' { $$ = strdup("()"); } + ; + +constant_value + : expression + | compound_statement { $$ = strdup("{ ... }"); } + ; + +expression + : additive_expression + ; + +primary_expression + : CONSTANT + | '-' CONSTANT +{ + char *tmp_str = (char *) malloc(strlen($2) + 2); + sprintf(tmp_str, "-%s", $2); + free($2); + $$ = tmp_str; +} + | STRING_LITERAL + | IDENTIFIER + | scoped_identifier + | '(' expression ')' +{ + char *tmp_str = (char *) malloc(strlen($2) + 3); + sprintf(tmp_str, "(%s)", $2); + free($2); + $$ = tmp_str; +} + ; + +multiplicative_expression + : primary_expression + | multiplicative_expression '*' primary_expression +{ + char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 4); + sprintf(tmp_str, "%s * %s", $1, $3); + free($1); + free($3); + $$ = tmp_str; +} + | multiplicative_expression '/' primary_expression +{ + char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 4); + sprintf(tmp_str, "%s / %s", $1, $3); + free($1); + free($3); + $$ = tmp_str; +} + | multiplicative_expression '%' primary_expression +{ + char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 4); + sprintf(tmp_str, "%s %% %s", $1, $3); + free($1); + free($3); + $$ = tmp_str; +} + ; + +additive_expression + : multiplicative_expression + | additive_expression '+' multiplicative_expression +{ + char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 4); + sprintf(tmp_str, "%s + %s", $1, $3); + free($1); + free($3); + $$ = tmp_str; +} + | additive_expression '-' multiplicative_expression +{ + char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 4); + sprintf(tmp_str, "%s - %s", $1, $3); + free($1); + free($3); + $$ = tmp_str; +} + ; + + +union_specifier + : UNION IDENTIFIER '{' variable_specifier_list '}' +{ + char *tmp_str = (char *) malloc(strlen($2) + strlen($4) + 12); + sprintf(tmp_str, "union %s { %s }", $2, $4); + free($2); + free($4); + $$ = tmp_str; +} + | UNION '{' variable_specifier_list '}' +{ + char *tmp_str = (char *) malloc(strlen($3) + 11); + sprintf(tmp_str, "union { %s }", $3); + free($3); + $$ = tmp_str; +} + | UNION IDENTIFIER +{ + char *tmp_str = (char *) malloc(strlen($2) + 7); + sprintf(tmp_str, "union %s", $2); + free($2); + $$ = tmp_str; +} + ; + +class_specifier + : CLASS IDENTIFIER '{' member_list_opt '}' +{ + syntaxelem_t *child; + /* ret_type, name, args, kind */ + syntaxelem_t *tmp_elem = new_elem(strdup(""), $2, NULL, CLASS_KIND); + tmp_elem->children = reverse_list($4); + + for (child = tmp_elem->children; child != NULL; child = child->next) + child->parent = tmp_elem; + +/* print_se(tmp_elem); */ + $$ = tmp_elem; +} + | CLASS IDENTIFIER ':' superclass_list '{' member_list_opt '}' +{ + syntaxelem_t *child; + /* ret_type, name, args, kind */ + syntaxelem_t *tmp_elem = new_elem(strdup(""), $2, NULL, CLASS_KIND); + tmp_elem->children = reverse_list($6); + + for (child = tmp_elem->children; child != NULL; child = child->next) + child->parent = tmp_elem; + +/* print_se(tmp_elem); */ + $$ = tmp_elem; +} + | template_specifier CLASS IDENTIFIER '{' member_list_opt '}' +{ + syntaxelem_t *child; + /* ret_type, name, args, kind */ + syntaxelem_t *tmp_elem = new_elem(strdup(""), $3, NULL, CLASS_KIND); + tmp_elem->children = reverse_list($5); + tmp_elem->templ = $1; + + for (child = tmp_elem->children; child != NULL; child = child->next) + child->parent = tmp_elem; + +/* print_se(tmp_elem); */ + $$ = tmp_elem; +} + | template_specifier CLASS IDENTIFIER ':' superclass_list '{' member_list_opt '}' +{ + syntaxelem_t *child; + /* ret_type, name, args, kind */ + syntaxelem_t *tmp_elem = new_elem(strdup(""), $3, NULL, CLASS_KIND); + tmp_elem->children = reverse_list($7); + tmp_elem->templ = $1; + + for (child = tmp_elem->children; child != NULL; child = child->next) + child->parent = tmp_elem; + +/* print_se(tmp_elem); */ + $$ = tmp_elem; +} + | STRUCT '{' member_list_opt '}' +{ + syntaxelem_t *child; + /* ret_type, name, args, kind */ + syntaxelem_t *tmp_elem = new_elem(strdup(""), "unnamed_struct", + NULL, IGNORE_KIND); + tmp_elem->children = reverse_list($3); + + for (child = tmp_elem->children; child != NULL; child = child->next) + child->parent = tmp_elem; + +/* print_se(tmp_elem); */ + $$ = tmp_elem; +} + | STRUCT IDENTIFIER '{' member_list_opt '}' +{ + syntaxelem_t *child; + /* ret_type, name, args, kind */ + syntaxelem_t *tmp_elem = new_elem(strdup(""), $2, NULL, STRUCT_KIND); + tmp_elem->children = reverse_list($4); + + for (child = tmp_elem->children; child != NULL; child = child->next) + child->parent = tmp_elem; + +/* print_se(tmp_elem); */ + $$ = tmp_elem; +} + | STRUCT IDENTIFIER ':' superclass_list '{' member_list_opt '}' +{ + syntaxelem_t *child; + /* ret_type, name, args, kind */ + syntaxelem_t *tmp_elem = new_elem(strdup(""), $2, NULL, STRUCT_KIND); + tmp_elem->children = reverse_list($6); + + for (child = tmp_elem->children; child != NULL; child = child->next) + child->parent = tmp_elem; + +/* print_se(tmp_elem); */ + $$ = tmp_elem; +} + | template_specifier STRUCT IDENTIFIER '{' member_list_opt '}' +{ + syntaxelem_t *child; + /* ret_type, name, args, kind */ + syntaxelem_t *tmp_elem = new_elem(strdup(""), $3, NULL, STRUCT_KIND); + tmp_elem->children = reverse_list($5); + tmp_elem->templ = $1; + + for (child = tmp_elem->children; child != NULL; child = child->next) + child->parent = tmp_elem; + +/* print_se(tmp_elem); */ + $$ = tmp_elem; +} + | template_specifier STRUCT IDENTIFIER ':' superclass_list '{' member_list_opt '}' +{ + syntaxelem_t *child; + /* ret_type, name, args, kind */ + syntaxelem_t *tmp_elem = new_elem(strdup(""), $3, NULL, STRUCT_KIND); + tmp_elem->children = reverse_list($7); + tmp_elem->templ = $1; + + for (child = tmp_elem->children; child != NULL; child = child->next) + child->parent = tmp_elem; + +/* print_se(tmp_elem); */ + $$ = tmp_elem; +} + ; + +superclass_list + : superclass + | superclass_list ',' superclass + ; + +superclass + : access_specifier_opt type_name { free($2); } + ; + +friend_specifier + : FRIEND member_func_specifier { $2->kind = IGNORE_KIND; } + | FRIEND forward_decl + ; + +member_list_opt + : /* nothing */ { $$ = NULL; } + | member_list + ; + +member_list + : member_with_access +{ + if ($1 != NULL) + $1->next = NULL; + + $$ = $1; +} + | member_list member_with_access +{ + if ($2 != NULL) { + $2->next = $1; + $$ = $2; + } else { + $$ = $1; + } +} + ; + +member_or_error + : member + | error +{ + log_printf("member_with_access : error. Attempting to recover...\n"); + yyerrok; + yyclearin; + if (error_recovery() != 0) { + log_printf("ERROR recovery could not complete -- YYABORT.\n"); + YYABORT; + } + log_printf("ERROR recovery complete.\n"); + $$ = NULL; +} + ; + +member_with_access + : member_or_error + | access_specifier_list member_or_error { $$ = $2; } + ; + +member + : member_specifier ';' + | friend_specifier ';' { $$ = NULL; } + | member_func_inlined { $1->kind = INLINED_KIND; $$ = $1; } + | ';' { $$ = NULL; } + ; + +member_specifier + : multiple_variable_specifier +{ + /* ret_type, name, args, kind */ + syntaxelem_t *elem = new_elem(strdup(""), $1, NULL, IGNORE_KIND); +/* print_se(elem); */ + $$ = elem; +} + | member_func_specifier + | EXTERN member_func_specifier { $$ = $2; } + | member_func_specifier '=' CONSTANT { $1->kind = IGNORE_KIND; free($3); $$ = $1; } + | mem_type_specifier + ; + +mem_type_specifier + : type_specifier + | type_specifier IDENTIFIER { free($2); $$ = $1; } + | mem_type_specifier '[' ']' + | mem_type_specifier '[' constant_value ']' +{ + free($3); + $$ = $1; +} + ; + +template_arg + : CLASS IDENTIFIER +{ + char *tmp_str = (char *) malloc(strlen($2) + 7); + sprintf(tmp_str, "class %s", $2); + free($2); + $$ = tmp_str; +} + | type_name IDENTIFIER +{ + char *tmp_str = (char *) malloc(strlen($1) + strlen($2) + 2); + sprintf(tmp_str, "%s %s", $1, $2); + free($1); + free($2); + $$ = tmp_str; +} + ; + +template_arg_list + : template_arg + | template_arg_list ',' template_arg +{ + char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 3); + sprintf(tmp_str, "%s, %s", $1, $3); + free($1); + free($3); + $$ = tmp_str; +} + ; + +template_instance_arg + : CONSTANT + | type_name + ; + +template_instance_arg_list + : template_instance_arg + | template_instance_arg_list ',' template_instance_arg +{ + char *tmp_str = (char *) malloc(strlen($1) + strlen($3) + 3); + sprintf(tmp_str, "%s, %s", $1, $3); + free($1); + free($3); + $$ = tmp_str; +} + ; + +template_specifier + : TEMPLATE '<' template_arg_list '>' +{ + char *tmp_str = (char *) malloc(strlen($3) + 12); + sprintf(tmp_str, "template <%s>", $3); + free($3); + $$ = tmp_str; +} + ; + +%% + +static int yyerror(char *s /*UNUSED*/) +{ + if (outfile != NULL) + fflush(outfile); + + return 0; +} + +static int error_recovery() +{ + extern char linebuf[]; + extern int lineno; + extern int column; + extern int tokens_seen; + +#ifdef SGDEBUG + log_printf("parse error at line %d, file %s:\n%s\n%*s\n", + lineno, currentFile, linebuf, column, "^"); + log_flush(); +#endif /* SGDEBUG */ + + if (tokens_seen == 0) { + /* + * if we've seen no tokens but we're in an error, we must have + * hit an EOF, either by stdin, or on a file. Just give up + * now instead of complaining. + */ + return -1; + + } else { + fprintf(stderr, "parse error at line %d, file %s:\n%s\n%*s\n", + lineno, currentFile, linebuf, column, "^"); + } + + linebuf[0] = '\0'; + + for (;;) { + int result = yylex(); + + if (result <= 0) { + /* fatal error: Unexpected EOF during parse error recovery */ + +#ifdef SGDEBUG + log_printf("EOF in error recovery, line %d, file %s\n", + lineno, currentFile); + log_flush(); +#endif /* SGDEBUG */ + + fprintf(stderr, "EOF in error recovery, line %d, file %s\n", + lineno, currentFile); + + return -1; + } + + switch(result) { + case IDENTIFIER: + case CONSTANT: + case STRING_LITERAL: + case CHAR: + case SHORT: + case INT: + case LONG: + case SIGNED: + case UNSIGNED: + case FLOAT: + case DOUBLE: + case VOID: + free(yylval.string); + break; + case (int) '{': + if (collectInlineDef() != 0) + return -1; + result = yylex(); + return 0; + case (int) ';': + return 0; + } + } +} diff --git a/src/tools/stubgen/pathname.c b/src/tools/stubgen/pathname.c new file mode 100644 index 0000000000..8802c022d8 --- /dev/null +++ b/src/tools/stubgen/pathname.c @@ -0,0 +1,86 @@ +/* + * FILE: pathname.c + * AUTH: Michael John Radwin + * + * DESC: two important functions from libgen. Largely influenced + * by the gnu dirutils. + * + * DATE: Tue Oct 1 20:48:28 EDT 1996 + * $Id: pathname.c,v 1.1 2002/07/09 12:24:59 ejakowatz Exp $ + * + * Copyright (c) 1996-1998 Michael John Radwin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#ifdef WIN32 +#define PATH_SEPARATOR_STR "\\" +#define PATH_SEPARATOR_CHAR '\\' +#else +#define PATH_SEPARATOR_STR "/" +#define PATH_SEPARATOR_CHAR '/' +#endif + +static const char rcsid[] = "$Id: pathname.c,v 1.1 2002/07/09 12:24:59 ejakowatz Exp $"; + +static void +strip_trailing_slashes(char *path) +{ + int last = strlen (path) - 1; + while ((last > 0) && (path[last] == PATH_SEPARATOR_CHAR)) + path[last--] = '\0'; +} + +char * +basename(char *path) +{ + char *slash; + + if ((path == NULL) || (path[0] == '\0')) + return "."; + + strip_trailing_slashes(path); + if (path[0] == '\0') + return PATH_SEPARATOR_STR; + + slash = strrchr(path, PATH_SEPARATOR_CHAR); + return (slash) ? slash + 1 : path; +} + +char * +dirname(char *path) +{ + char *slash; + + if ((path == NULL) || (path[0] == '\0')) + return "."; + + strip_trailing_slashes(path); + if (path[0] == '\0') + return PATH_SEPARATOR_STR; + + slash = strrchr(path, PATH_SEPARATOR_CHAR); + if (slash == NULL) + return "."; + + /* Remove any trailing slashes and final element. */ + while (slash > path && *slash == PATH_SEPARATOR_CHAR) + --slash; + slash[1] = 0; + + return path; +} diff --git a/src/tools/stubgen/pathname.h b/src/tools/stubgen/pathname.h new file mode 100644 index 0000000000..4db9cb029c --- /dev/null +++ b/src/tools/stubgen/pathname.h @@ -0,0 +1,70 @@ +/* + * FILE: pathname.h + * AUTH: Michael John Radwin + * + * DESC: two important functions from libgen + * + * DATE: Tue Oct 1 20:47:55 EDT 1996 + * $Id: pathname.h,v 1.1 2002/07/09 12:24:59 ejakowatz Exp $ + * + * Copyright (c) 1996-1998 Michael John Radwin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __pathname_H__ +#define __pathname_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Given a pointer to a null-terminated character string that contains a + * path name, basename() returns a pointer to the last element of path. + * Trailing ``/'' characters are deleted. In doing this, it may place a + * null byte in the path name after the next to last element, so the + * content of path must be disposable. + * + * If path or *path is zero, pointer to a static constant ``.'' is + * returned. + * + * If path consists entirely of ``/'' characters, the empty string is + * returned. + */ +char * basename(char *path); + +/* + * Given a pointer to a null-terminated character string that contains a + * file system path name, dirname() returns a string that is the parent + * directory of that file. In doing this, it may place a null byte in + * the path name after the next to last element, so the content of path + * must be disposable. The returned string should not be deallocated by + * the caller. Trailing ``/'' characters in the path are not counted as + * part of the path. + * + * If path or *path is zero, a pointer to a static constant ``.'' is + * returned. + * + * dirname() and basename() together yield a complete path name. + * dirname (path) is the directory where basename (path) is found. + */ +char * dirname(char *path); + +#ifdef __cplusplus +} +#endif + +#endif /* __pathname_H__ */ diff --git a/src/tools/stubgen/table.c b/src/tools/stubgen/table.c new file mode 100644 index 0000000000..168c01da2c --- /dev/null +++ b/src/tools/stubgen/table.c @@ -0,0 +1,441 @@ +/* + * FILE: table.c + * AUTH: Michael John Radwin + * + * DESC: stubgen symbol table goodies + * + * DATE: 1996/08/14 22:04:47 + * $Id: table.c,v 1.1 2002/07/09 12:24:59 ejakowatz Exp $ + * + * Copyright (c) 1996-1998 Michael John Radwin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "table.h" +#include "util.h" +#include +#include +#include +#include + +static const char rcsid[] = "$Id: table.c,v 1.1 2002/07/09 12:24:59 ejakowatz Exp $"; + +/* global table */ +static syntaxelem_t etable[NELEMS]; +static int eindex; + +/* initializes all of the tables to default values. */ +void init_tables() +{ + memset(etable, 0, sizeof(syntaxelem_t) * NELEMS); + eindex = 0; + +#if 0 + syntaxelem_t *elt; + + for(elt = etable; elt < &etable[NELEMS]; elt++) { + elt->name = NULL; + elt->ret_type = NULL; + elt->args = NULL; + elt->templ = NULL; + elt->parent = NULL; + elt->children = NULL; + elt->throw_decl = NULL; + elt->const_flag = 0; + elt->kind = 73; + } +#endif +} + +/* recursively frees all syntaxelem_t's. */ +void free_tables() +{ + syntaxelem_t *elt; + + for (elt = etable; elt < &etable[NELEMS]; elt++) { + if (elt->name) { + free(elt->name); + free(elt->ret_type); + free_args(elt->args); + + if (elt->throw_decl) free(elt->throw_decl); + if (elt->templ) free(elt->templ); + } + } +} + +/* recursively frees the argument list and assoicated fields */ +void free_args(arg_t *args) +{ + arg_t *a; + + for (a = args; a != NULL; ) { + arg_t *next_arg = a->next; + free(a->type); + if (a->name) + free(a->name); + if (a->array) + free(a->array); + free(a); + a = next_arg; + } +} + +/* compares two arguments for equality. Returns 0 for equal, + non-zero if they differ. */ +int arg_cmp(arg_t *a1, arg_t *a2) +{ + if (strcmp(a1->type, a2->type) != 0) + return 1; + + if (a1->array) { + if (a2->array) { + if (strcmp(a1->array, a2->array) != 0) + return 1; + } else { + return 1; + } + } else if (a2->array) { + return 1; + } + + return 0; +} + +/* recursively compares two argument lists for equality. + Returns 0 for equal, non-zero if they differ. */ +int args_cmp(arg_t *a1, arg_t *a2) +{ + while (a1 != NULL) { + if (a2 == NULL) + return 1; + + if (arg_cmp(a1, a2) != 0) + return 1; + + a1 = a1->next; + a2 = a2->next; + } + + if (a2 != NULL) + return 1; + + return 0; +} + + +/* provides a string rep of this arglist. conses up new + memory, so client is responsible for freeing it. */ +char * args_to_string(arg_t *args, int indent_length) +{ + arg_t *a; + int len = 0; + char *str; + char *indent_str; + + if (indent_length <= 0) { + indent_str = strdup(", "); + indent_length = 2; + + } else { + indent_length += 2; /* room for ",\n" as well */ + indent_str = (char *) malloc(indent_length + 1); + memset(indent_str, ' ', indent_length); + indent_str[0] = ','; + indent_str[1] = '\n'; + indent_str[indent_length] = '\0'; + } + + for (a = args; a != NULL; a = a->next) { + len += strlen(a->type); /* we always have a type */ + if (a->name) + len += (1 + strlen(a->name)); /* room for ' ' and name */ + if (a->array) + len += strlen(a->array); + if (a != args) + len += indent_length; /* room for ", " */ + } + + str = (char *) malloc(len + 1); + str[0] = '\0'; + + for (a = args; a != NULL; a = a->next) { + if (a != args) + strcat(str, indent_str); + + strcat(str, a->type); + if (a->name) { + if (((a->type)[strlen(a->type)-1] != '*') && + ((a->type)[strlen(a->type)-1] != '&')) + strcat(str, " "); + strcat(str, a->name); + if (a->array) + strcat(str, a->array); /* array hugs variable name */ + } else { + if (a->array) + strcat(str, a->array); /* array hugs type name */ + } + } + + free(indent_str); + return str; +} + +/* compares a skeleton element to a header element for equality of + signatures. this isn't a strict comparison, because the kind and + parent fields ought to be different. returns 0 if equal, non-zero if + different */ +int skel_elemcmp(syntaxelem_t *skel_elem, syntaxelem_t *hdr_elem) +{ + char *tmp_str; + int result; + + assert(hdr_elem->kind == FUNC_KIND); + assert(skel_elem->kind == SKEL_KIND); + assert(hdr_elem->parent != NULL); + + if (skel_elem->const_flag != hdr_elem->const_flag) + return 1; + + /* + * templ and throw_decl are allowed to be NULL, + * so we must not pass them onto strcmp without + * a check first. + */ + if (skel_elem->templ != NULL) { + if (hdr_elem->templ == NULL) + return 1; + else if (strcmp(skel_elem->templ, hdr_elem->templ) != 0) + return 1; + } else if (hdr_elem->templ != NULL) { + return 1; + } + + if (skel_elem->throw_decl != NULL) { + if (hdr_elem->throw_decl == NULL) + return 1; + else if (strcmp(skel_elem->throw_decl, hdr_elem->throw_decl) != 0) + return 1; + } else if (hdr_elem->throw_decl != NULL) { + return 1; + } + + /* + * these two won't differ across files, and they're + * guaranteed not to be NULL. + */ + if (strcmp(skel_elem->ret_type, hdr_elem->ret_type) != 0) + return 1; + + /* now make sure the argument signatures match */ + if (args_cmp(skel_elem->args, hdr_elem->args) != 0) + return 1; + + /* + * the name, of course, is the hard part. we gotta + * look at the parent to make a scoped name. + */ + tmp_str = (char *) malloc(strlen(hdr_elem->parent->name) + + strlen(hdr_elem->name) + 3); + sprintf(tmp_str, "%s::%s", hdr_elem->parent->name, hdr_elem->name); + + result = strcmp(skel_elem->name, tmp_str); + free(tmp_str); + + return result; +} + +/* allocates a new element from the table, filling in the apropriate fields */ +syntaxelem_t * new_elem(char *ret_type, char *name, arg_t *args, int kind) +{ + syntaxelem_t *se; + + if (eindex == NELEMS - 1) { + fatal(2, "Too many symbols. Please mail mjr@acm.org."); + return NULL; + } + + se = &etable[eindex++]; + se->ret_type = ret_type; + se->name = name; + se->args = args; + se->kind = kind; + + return se; +} + + +/* given the head of the list, reverses it and returns the new head */ +syntaxelem_t * reverse_list(syntaxelem_t *head) +{ + syntaxelem_t *elt = head; + syntaxelem_t *prev = NULL; + syntaxelem_t *next; + + while (elt != NULL) { + next = elt->next; + elt->next = prev; + prev = elt; + elt = next; + } + + return prev; +} + +arg_t * reverse_arg_list(arg_t *head) +{ + arg_t *a = head; + arg_t *prev = NULL; + arg_t *next; + + while (a != NULL) { + next = a->next; + a->next = prev; + prev = a; + a = next; + } + + return prev; +} + +const char * string_kind(int some_KIND) +{ + switch(some_KIND) { + case IGNORE_KIND: + return "IGNORE_KIND"; + case FUNC_KIND: + return "FUNC_KIND"; + case CLASS_KIND: + return "CLASS_KIND"; + case STRUCT_KIND: + return "STRUCT_KIND"; + case INLINED_KIND: + return "INLINED_KIND"; + case SKEL_KIND: + return "SKEL_KIND"; + case DONE_FUNC_KIND: + return "DONE_FUNC_KIND"; + case DONE_CLASS_KIND: + return "DONE_CLASS_KIND"; + default: + return "BAD KIND!"; + } +} + + +#ifdef SGDEBUG +void print_se(syntaxelem_t *elt) +{ + char *arg_str = args_to_string(elt->args, 0); + + log_printf("\nSTUBELEM name: %s\n", elt->name); + log_printf(" ret_typ: %s\n", elt->ret_type); + log_printf(" args: %s\n", arg_str); + log_printf(" parent: %s\n", (elt->parent) ? elt->parent->name : "NULL"); + log_printf(" next: %s\n", (elt->next) ? elt->next->name : "NULL"); + log_printf(" const: %d\n", elt->const_flag); + log_printf(" kind: %s\n", string_kind(elt->kind)); + log_printf(" throw: %s\n", (elt->throw_decl)? elt->throw_decl : "NULL"); + log_printf(" templ: %s\n\n", (elt->templ)? elt->templ : "NULL"); + free(arg_str); +} +#endif /* SGDEBUG */ + +/* + * we can't use the 'next' field of syntaxelem_t because it is used to + * chain together methods. Make a slightly bigger struct so we can + * queue these up. + */ +typedef struct _skelnode { + syntaxelem_t *elt; + struct _skelnode *next; +} skelnode_t; + +/* the queue of elements found in the .H file, possibly to be expanded */ +static skelnode_t *exp_head = NULL; +static skelnode_t *exp_tail = NULL; + +void enqueue_class(syntaxelem_t *elt) +{ + skelnode_t *new_class; + + new_class = (skelnode_t *)malloc(sizeof(skelnode_t)); + new_class->elt = elt; + new_class->next = NULL; + + if (exp_head == NULL) + exp_tail = exp_head = new_class; + else { + exp_tail->next = new_class; + exp_tail = new_class; + } +} + +syntaxelem_t * dequeue_class() +{ + skelnode_t *old_head = exp_head; + syntaxelem_t *to_return = exp_head->elt; + + assert(exp_head != NULL); + exp_head = exp_head->next; + free(old_head); + + return to_return; +} + +int class_queue_empty() +{ + return exp_head == NULL; +} + +/* the list of skeletons found in the .C file, already expanded */ +static skelnode_t *skel_head = NULL; + +void enqueue_skeleton(syntaxelem_t *elt) +{ + skelnode_t *new_class; + + new_class = (skelnode_t *)malloc(sizeof(skelnode_t)); + new_class->elt = elt; + new_class->next = skel_head; + + skel_head = new_class; +} + +syntaxelem_t * find_skeleton(syntaxelem_t *elt) +{ + skelnode_t *node; + + /* the order of skel_elemcmp(node->elt, elt) is important. */ + for (node = skel_head; node != NULL; node = node->next) + if (skel_elemcmp(node->elt, elt) == 0) + return node->elt; + + return NULL; +} + +void clear_skeleton_queue() +{ + skelnode_t *node = skel_head; + + while (node != NULL) { + skelnode_t *next_node = node->next; + free(node); + node = next_node; + } + + skel_head = NULL; +} diff --git a/src/tools/stubgen/table.h b/src/tools/stubgen/table.h new file mode 100644 index 0000000000..2b3d3dff2e --- /dev/null +++ b/src/tools/stubgen/table.h @@ -0,0 +1,119 @@ +/* + * FILE: table.h + * AUTH: Michael John Radwin + * + * DESC: stubgen symbol table goodies + * + * DATE: 1996/08/14 22:04:47 + * $Id: table.h,v 1.1 2002/07/09 12:24:59 ejakowatz Exp $ + * + * Copyright (c) 1996-1998 Michael John Radwin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TABLE_HEADER +#define TABLE_HEADER + +#ifdef __cplusplus +extern "C" { +#endif + +#define NELEMS 500 /* maximum number of symbols */ + +#define IGNORE_KIND 0 /* a variable or forward declaration */ +#define FUNC_KIND 1 /* a method declaration */ +#define CLASS_KIND 2 /* a class declaration */ +#define INLINED_KIND 3 /* a method w/body in a class decl. */ +#define SKEL_KIND 4 /* a method found in a code file */ +#define STRUCT_KIND 5 /* a struct declaration that's a class */ +#define DONE_FUNC_KIND 11 /* a fn that we've finished expanded */ +#define DONE_CLASS_KIND 12 /* a class that we've finished expanded */ + +/* returns a pointer to a static string */ +const char * string_kind(int some_KIND); + +/* + * Represents a single argument, often used in a list. + */ +typedef struct arg { + char *type; /* type of this arg. may NOT be NULL */ + char *name; /* formal parameter name. may be NULL */ + char *array; /* any array dimensions may be NULL + appended to name. */ + struct arg *next; /* next argument. may be NULL */ +} arg_t; + +/* + * This structure is central to the program. It might have been more + * elegant with an object-oriented approach consisting of the following + * objects: ignore, method, class, inlined, skeleton. + * + * Instead, however, we have a "throw-it-all-in-one" structure that has + * unused pieces of data, depending on the kind field. + * + * A syntaxelem_t is "valid" if the name field is non-NULL. + */ +typedef struct syntaxelem { + char *name; /* name of class or func. may NOT be NULL */ + char *ret_type; /* return type. may NOT be NULL */ + arg_t *args; /* argument list. may be NULL */ + char *templ; /* template declaration. may be NULL */ + struct syntaxelem *parent; /* parent class */ + struct syntaxelem *next; /* next class or member */ + struct syntaxelem *children; /* children of this class */ + char *throw_decl; /* throw() clause. may be NULL */ + int const_flag; /* 1 if the func is const, 0 if not. */ + int kind; /* some_KIND */ +} syntaxelem_t; + +/* defined in table.c */ +void init_tables(); +void free_tables(); + +#ifdef SGDEBUG +void print_se(syntaxelem_t *); +#else +#define print_se(arg) +#endif /* SGDEBUG */ + +/* used in scanning */ +arg_t * reverse_arg_list(arg_t *); +void free_args(arg_t *); +syntaxelem_t *new_elem(char *, char *, arg_t *, int); +syntaxelem_t *reverse_list(syntaxelem_t *); + +/* used in generating output. + allocates memory; someone's gotta clean it up! */ +char *args_to_string(arg_t *, int); + +/* used in comparison with existing skeletons*/ +int skel_elemcmp(syntaxelem_t *skel_elem, syntaxelem_t *hdr_elem); +int strict_elemcmp(syntaxelem_t *e1, syntaxelem_t *e2); + +/* list management primitives */ +void enqueue_class(syntaxelem_t *); +syntaxelem_t * dequeue_class(); +int class_queue_empty(); + +void enqueue_skeleton(syntaxelem_t *); +syntaxelem_t * find_skeleton(syntaxelem_t *); +void clear_skeleton_queue(); + +#ifdef __cplusplus +} +#endif + +#endif /* TABLE_HEADER */ diff --git a/src/tools/stubgen/test/MJRString.H b/src/tools/stubgen/test/MJRString.H new file mode 100644 index 0000000000..62669a9626 --- /dev/null +++ b/src/tools/stubgen/test/MJRString.H @@ -0,0 +1,60 @@ +/********************************************************************** + * FILE: MJRString.H + * AUTHOR: Michael J. Radwin + * DATE: 01/28/95 + * DESCRIPTION: The public interface for the String class + * MODIFIED: 02/27/95 + * CREDITS: some code borrowed from Deitel, "How to Program C++" + **********************************************************************/ + +#ifndef __MJRString_H__ +#define __MJRString_H__ + +#include + +class MJRString { + friend ostream & operator<<(ostream&, const MJRString &s); + friend istream & operator>>(istream&, MJRString &s); + +public: + MJRString(const char* s = ""); + MJRString(const MJRString ©); + MJRString(double value); + MJRString(int value); + ~MJRString(); + + // assignment + const MJRString & operator=(const MJRString &right); + const MJRString & operator=(const char *right); + const MJRString & operator+=(const MJRString &right); + const MJRString & operator+=(const char *right); + + // comparisons + int operator! () const; + int operator==(const MJRString &right) const; + int operator==(const char *right) const; + int operator!=(const MJRString &right) const; + int operator!=(const char *right) const; + int operator< (const MJRString &right) const; + int operator< (const char *right) const; + int operator> (const MJRString &right) const; + int operator> (const char *right) const; + int operator<=(const MJRString &right) const; + int operator<=(const char *right) const; + int operator>=(const MJRString &right) const; + int operator>=(const char *right) const; + + // auxiliary + MJRString operator+(const MJRString &right) const; + MJRString operator+(const char *right) const; + char & operator[](int subscript); + char operator[](int subscript) const; // safe for const + MJRString operator()(int index, int subLength) const; + int length() const; + +protected: + char *pStr_; + int length_; +} ; + +#endif diff --git a/src/tools/stubgen/test/Point.h b/src/tools/stubgen/test/Point.h new file mode 100644 index 0000000000..f4ced594a7 --- /dev/null +++ b/src/tools/stubgen/test/Point.h @@ -0,0 +1,12 @@ +#ifndef _Point_H +#define _Point_H + +class Point { +public: + Point(int x, int y); + void addTo(Point other); + + int xValue, yValue; +}; + +#endif /* _Point_H */ diff --git a/src/tools/stubgen/test/Rational.H b/src/tools/stubgen/test/Rational.H new file mode 100644 index 0000000000..436807ccd5 --- /dev/null +++ b/src/tools/stubgen/test/Rational.H @@ -0,0 +1,82 @@ +/**************************************************************** + * NAME: Michael J. Radwin + * ACCT: mradwin + * FILE: Rational.H + * DATE: Sat Mar 4 01:47:16 EST 1995 + * $Id: Rational.H,v 1.1 2002/07/09 12:24:59 ejakowatz Exp $ + ****************************************************************/ + +class Rational { + friend ostream & operator<<(ostream &output, const Rational &r); + friend Rational pow(const Rational &r, int exp); + friend Rational operator+(int n, const Rational &r); + friend Rational operator-(int n, const Rational &r); + friend Rational operator*(int n, const Rational &r); + friend Rational operator/(int n, const Rational &r); + friend int operator==(int n, const Rational &r); + friend int operator!=(int n, const Rational &r); + friend int operator< (int n, const Rational &r); + friend int operator> (int n, const Rational &r); + friend int operator<=(int n, const Rational &r); + friend int operator>=(int n, const Rational &r); + +public: + Rational(int num, int den = 1); + Rational(const Rational &r); + ~Rational(); + + Rational operator+(const Rational &r) const; + Rational operator-(const Rational &r) const; + Rational operator*(const Rational &r) const; + Rational operator/(const Rational &r) const; + const Rational & operator= (const Rational &r); + const Rational & operator+=(const Rational &r); + const Rational & operator-=(const Rational &r); + const Rational & operator*=(const Rational &r); + const Rational & operator/=(const Rational &r); + + Rational operator+(int r) const; + Rational operator-(int r) const; + Rational operator*(int r) const; + Rational operator/(int r) const; + const Rational & operator= (int r); + const Rational & operator+=(int r); + const Rational & operator-=(int r); + const Rational & operator*=(int r); + const Rational & operator/=(int r); + + Rational operator-() const; + int operator! () const; + int operator==(const Rational &r) const; + int operator==(int r) const; + int operator!=(const Rational &r) const; + int operator!=(int r) const; + int operator< (const Rational &r) const; + int operator< (int r) const; + int operator> (const Rational &r) const; + int operator> (int r) const; + int operator<=(const Rational &r) const; + int operator<=(int r) const; + int operator>=(const Rational &r) const; + int operator>=(int r) const; + +private: + Rational() {} + static int compute_gcd(int a, int b); + static int gcd(int bigger, int smaller); + int n, d; +}; + +// global prototypes +ostream & operator<<(ostream &output, const Rational &r); +Rational pow(const Rational &r, int exp); +Rational operator+(int n, const Rational &r); +Rational operator-(int n, const Rational &r); +Rational operator*(int n, const Rational &r); +Rational operator/(int n, const Rational &r); +int operator==(int n, const Rational &r); +int operator!=(int n, const Rational &r); +int operator< (int n, const Rational &r); +int operator> (int n, const Rational &r); +int operator<=(int n, const Rational &r); +int operator>=(int n, const Rational &r); diff --git a/src/tools/stubgen/test/blank.h b/src/tools/stubgen/test/blank.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/tools/stubgen/test/defines.h b/src/tools/stubgen/test/defines.h new file mode 100644 index 0000000000..e209c5a185 --- /dev/null +++ b/src/tools/stubgen/test/defines.h @@ -0,0 +1,14 @@ +#ifndef TABLE_HEADER +#define TABLE_HEADER + +#define NELEMS 500 /* maximum number of symbols */ + +#define IGNORE_KIND 0 /* a variable or forward declaration */ +#define FUNC_KIND 1 /* a method declaration */ +#define CLASS_KIND 2 /* a class declaration */ +#define INLINED_KIND 3 /* a method w/body in a class decl. */ +#define SKEL_KIND 4 /* a method found in a code file */ +#define DONE_FUNC_KIND 11 /* a fn that we've finished expanded */ +#define DONE_CLASS_KIND 12 /* a class that we've finished expanded */ + +#endif diff --git a/src/tools/stubgen/test/heap.H b/src/tools/stubgen/test/heap.H new file mode 100644 index 0000000000..bbf8975bb4 --- /dev/null +++ b/src/tools/stubgen/test/heap.H @@ -0,0 +1,139 @@ +#ifndef __Heap__ +#define __Heap__ + +/*****************************************************************************/ +/* AUTHOR: Michael J. Radwin */ +/* DATE: 2/14/94 */ +/* DESCRIPTION: This file contains the code for a generic Heap class. */ +/* You will need to fill in all of the methods of the CHeap */ +/* methods for any other classes you need. */ +/* MODIFIED: 12/14/94 */ +/*****************************************************************************/ + + +template +class CHeapNode { + +public: + CHeapNode(); + virtual ~CHeapNode(); + + virtual void SetParent(CHeapNode * Lparent) = 0; + virtual void SetChild(CHeapNode * LoldChild, CHeapNode * LnewChild) = 0; + virtual void SetKey(T key) = 0; + virtual CHeapNode * Insert(T key) = 0; + virtual CHeapNode * Remove() = 0; + virtual T GetKey() = 0; + virtual T UpHeap(T key) = 0; + virtual T DownHeap() = 0; + virtual int Empty() = 0; + virtual CHeapNode * NextNode(CHeapNode * node) = 0; + virtual CHeapNode * PrevNode(CHeapNode * node) = 0; +} ; + + +template +class CHeapSuperNode : public CHeapNode { + + friend class CHeapInternalNode; + friend class CHeapLeafNode; + friend class CHeap; +public: + CHeapSuperNode(CHeapNode * LnewNode); + virtual ~CHeapSuperNode(); + + virtual void SetParent(CHeapNode * Lparent) { exit(-1); } ; + virtual void SetChild(CHeapNode * LoldChild, CHeapNode * LnewChild) { Lroot_ = LnewChild; }; + virtual void SetKey(T key) { exit(-1); }; + virtual CHeapNode * Insert(T key) { return(Lroot_->Insert(key)); }; + virtual CHeapNode * Remove(); + virtual T GetKey() { return (T) NULL; }; + virtual T UpHeap(T key) { return key; }; + virtual T DownHeap(); + virtual int Empty() { return Lroot_->Empty(); }; + virtual CHeapNode * NextNode(CHeapNode * node) { return Lroot_->NextNode(this); }; + virtual CHeapNode * PrevNode(CHeapNode * node) { return Lroot_->PrevNode(this); }; +protected: + CHeapNode * Lroot_; /* pointer to root of tree */ +} ; + + + +template +class CHeapInternalNode : public CHeapNode { +public: + CHeapInternalNode(T key, + CHeapNode * LleftChild, + CHeapNode * LrightChild + ); + virtual ~CHeapInternalNode(); + + virtual void SetParent(CHeapNode * Lparent) { Lparent_ = Lparent; } ; + virtual void SetChild(CHeapNode * LoldChild, CHeapNode * LnewChild); + virtual void SetKey(T key) { key_ = key; }; + virtual CHeapNode * Insert(T key); + virtual CHeapNode * Remove(); + virtual T GetKey() { return key_; }; + virtual T UpHeap(T key); + virtual T DownHeap(); + virtual int Empty() { return 0; }; + virtual CHeapNode * NextNode(CHeapNode * node); + virtual CHeapNode * PrevNode(CHeapNode * node); +protected: + T key_; /* this is my key value */ + CHeapNode * Lparent_; /* my parent */ + CHeapNode * LleftChild_; /* my left child */ + CHeapNode * LrightChild_; /* my right child */ + T DownHeapLeft(); + T DownHeapRight(); +} ; + + + +template +class CHeapLeafNode : public CHeapNode { +public: + CHeapLeafNode(); + virtual ~CHeapLeafNode(); + + virtual void SetParent(CHeapNode * Lparent) { Lparent_ = Lparent; } ; + virtual void SetChild(CHeapNode * LoldChild, CHeapNode * LnewChild) { exit(1); }; + virtual void SetKey(T key) { exit(-1); }; + virtual CHeapNode * Insert(T key); + virtual CHeapNode * Remove() { return NULL; }; + virtual T GetKey() { return (T) NULL; } + virtual T UpHeap(T key) { return (T) NULL; }; + virtual T DownHeap() { return (T) NULL; }; + virtual int Empty() { return 1; }; + virtual CHeapNode * NextNode(CHeapNode * node) { return Lparent_; }; + virtual CHeapNode * PrevNode(CHeapNode * node) { return Lparent_; }; +protected: + CHeapNode * Lparent_; /* my parent */ +} ; + + +/*************************************************************************/ +/* Class : CHeap */ +/* Descr : The CHeap class is a generic Heap class which can be used */ +/* with the c++ template mechanism. */ +/*************************************************************************/ + +template +class CHeap { +public: + CHeap(); + ~CHeap(); + + void Insert(T key); + void Delete(T &key); + int Empty() { return Lheap_->Empty(); }; + int Search(T) { return 0; }; + +protected: + CHeapSuperNode * Lheap_; /* pointer to heap supernode */ + CHeapNode * LlastNode_; +} ; + +#endif + + diff --git a/src/tools/stubgen/test/pathname_tst.c b/src/tools/stubgen/test/pathname_tst.c new file mode 100644 index 0000000000..456642a29a --- /dev/null +++ b/src/tools/stubgen/test/pathname_tst.c @@ -0,0 +1,46 @@ +#include +#include "pathname.c" + +void main() +{ + printf("input: '%s'\t\tdir: '%s' base: '%s'\n", + "/usr/lib", dirname("/usr/lib"), basename("/usr/lib")); + printf("input: '%s'\t\tdir: '%s' base: '%s'\n", + "/usr/lib/", dirname("/usr/lib/"), basename("/usr/lib/")); + printf("input: '%s'\t\tdir: '%s' base: '%s'\n", + "/usr/", dirname("/usr/"), basename("/usr/")); + printf("input: '%s'\t\tdir: '%s' base: '%s'\n", + "/usr///", dirname("/usr///"), basename("/usr///")); + printf("input: '%s'\t\tdir: '%s' base: '%s'\n", + "///usr////", dirname("///usr////"), basename("///usr////")); + printf("input: '%s'\t\tdir: '%s' base: '%s'\n", + "///usr////aaa//", dirname("///usr////aaa//"), basename("///usr////aaa//")); + + printf("input: '%s'\t\tdir: '%s' base: '%s'\n", + "usr/lib/foo", dirname("usr/lib/foo"), basename("usr/lib/foo")); + printf("input: '%s'\t\tdir: '%s' base: '%s'\n", + "usr/lib/foo/", dirname("usr/lib/foo/"), basename("usr/lib/foo/")); + printf("input: '%s'\t\tdir: '%s' base: '%s'\n", + "usr/", dirname("usr/"), basename("usr/")); + printf("input: '%s'\t\tdir: '%s' base: '%s'\n", + "usr///", dirname("usr///"), basename("usr///")); + printf("input: '%s'\t\tdir: '%s' base: '%s'\n", + "usr////", dirname("usr////"), basename("usr////")); + printf("input: '%s'\t\tdir: '%s' base: '%s'\n", + "usr////aaa//", dirname("usr////aaa//"), basename("usr////aaa//")); + + printf("input: '%s'\t\tdir: '%s' base: '%s'\n", + "/", dirname("/"), basename("/")); + printf("input: '%s'\t\tdir: '%s' base: '%s'\n", + "////", dirname("////"), basename("////")); + printf("input: '%s'\t\tdir: '%s' base: '%s'\n", + "usr", dirname("usr"), basename("usr")); + printf("input: '%s'\t\tdir: '%s' base: '%s'\n", + ".", dirname("."), basename(".")); + printf("input: '%s'\t\tdir: '%s' base: '%s'\n", + "..", dirname(".."), basename("..")); + printf("input: '%s'\t\tdir: '%s' base: '%s'\n", + "/foo/bar/baaz/quux/", dirname("/foo/bar/baaz/quux/"), basename("/foo/bar/baaz/quux/")); + printf("input: '%s'\t\tdir: '%s' base: '%s'\n", + "/a//b", dirname("/a//b"), basename("/a//b")); +} diff --git a/src/tools/stubgen/test/sample.h b/src/tools/stubgen/test/sample.h new file mode 100644 index 0000000000..bd26f5e393 --- /dev/null +++ b/src/tools/stubgen/test/sample.h @@ -0,0 +1,117 @@ +/* stubgen sample test file */ + +#include + +class Bar { public: Bar(int i) {} }; +class sdfs { int i; }; + +#define macro(x) MultiLineMacro(x) + +#define MultiLineMacro(x) bar(x); \ + quux(x); + +#define BUFSIZE 255 +#define i3 3 + + + +#if defined(__EXTENSIONS__) || ((__STDC__ == 0 && \ + !defined(_POSIX_C_SOURCE)) || defined(_XOPEN_SOURCE)) +extern int foo; +int j = foo; +#endif + +int arry[] = { + 0, 1, 2, 3, 4 +}; + +class fwd_decl_clazz; + + +typedef struct oldschool { + int iOldSchool; + double dOldSchool; +#define BAR(x) \ + bar(x); \ + quux(x); + int i2; char c2; +} oldschool_t; + +typedef int stubelem_t; + +/* template */ + +class Foo : public Bar, sdfs { +protected: + char buffer[BUFSIZE + 1]; + int dumfunc(int a[BUFSIZE+i3]); + +public: + void boundary_condition() {}; + Foo(int a); + Foo(double d) : Bar(23), a_(d) { int a = 34; } + + int * const quux(int a); + int i2(); char c2(...); + int iOldSchool2; /* +here's a comment +that +#define foo bar() \ + sd +might be hard +to parse + */ + virtual void pure_virtual() = 0; + void not_pure_virtual(); + void elipsis(int iElip, char cElip, float fElip, ...); + + class Quux { + char c_; + char *pc_; + char charfunc(char c1, char c2, char c3, char c4, char c5); + char& cool_func(char, short s, int, long l, long[]); + void funcA(int a, int b, int c = 33); + void* funcB(int a, int b = 2, int c = 23) const; + void * funcC(int a = 0, int b = 2, int c = 23) { return 0; } + char *& funcD(char * w, int a = 0, int b = 2, int c = 23); + void proto(int, char); + Quux(int z = 0); + ~Quux(); + + int test; + void test0() {}; + Bar test2(const int &i) const; + long long test3() const throw(int, Foo::Quux, float); + void test4() {} + void test5(int a) {}; + + struct NestMe { + public: + NestMe(int foo, int bar, int hi_there); + int getVal(stubelem_t *whee) throw(int, Foo::Quux, float); + int getFoo() throw(int, float) { return 1; } + }; + int getBar() throw(int, float); + }; + + virtual double toto(double &d = 1.0, int i = 4); + /* the next line won't be expanded because it's inlined. */ + const int getValue() { return a_; } + +private: + int a_; +}; + +class WidgetLens { + public: + WidgetLens(); +}; + +class WidgetCsg : public WidgetLens { + protected: + + public: + virtual ~WidgetCsg() {} + WidgetCsg(); +}; + diff --git a/src/tools/stubgen/util.c b/src/tools/stubgen/util.c new file mode 100644 index 0000000000..0dd6b26850 --- /dev/null +++ b/src/tools/stubgen/util.c @@ -0,0 +1,147 @@ +/* + * FILE: util.c + * AUTH: Michael John Radwin + * + * DESC: stubgen utility macros and funcs + * + * DATE: Wed Sep 11 23:31:55 EDT 1996 + * $Id: util.c,v 1.1 2002/07/09 12:24:59 ejakowatz Exp $ + * + * Copyright (c) 1996-1998 Michael John Radwin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include "util.h" + +static const char rcsid[] = "$Id: util.c,v 1.1 2002/07/09 12:24:59 ejakowatz Exp $"; + +#ifdef SGDEBUG +static FILE *logfile; + +int log_open(const char *logfilename) +{ + logfile = fopen(logfilename, "w"); + return (logfile != NULL); +} + +void log_flush() +{ + fflush(logfile); +} + +void log_close() +{ + fclose(logfile); + logfile = NULL; +} + +int log_printf(const char *format, ...) +{ + int retval; + va_list ap; + + va_start(ap, format); + retval = vfprintf(logfile, format, ap); + va_end(ap); + + return retval; +} + +int log_vprintf(const char *format, va_list ap) +{ + return vfprintf(logfile, format, ap); +} + +#else +int log_printf(const char *format /*UNUSED*/, ...) +{ + return 0; +} +#endif /* SGDEBUG */ + + +int inform_user(const char *format, ...) +{ + extern int opt_q; + int retval = 0; + va_list ap; + + if (!opt_q) { + va_start(ap, format); + retval = vfprintf(stderr, format, ap); + va_end(ap); + } + + return retval; +} + +void fatal(int status, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + log_vprintf(format, ap); + log_flush(); + log_close(); + (void) vfprintf(stderr, format, ap); + va_end(ap); + + fprintf(stderr, "\n"); + exit(status); +} + +#if 0 /* removeDefaultValues() not needed */ +/* + * modifies s by putting a null char in place of the first trailing space + */ +static void removeTrailingSpaces(char *s) +{ + char *end = s + strlen(s) - 1; + char *orig_end = end; + + while(*end == ' ') end--; + if (end != orig_end) *++end = '\0'; +} + +/* + * this both destructively modifies args and conses up a new string. + * be sure to free it up. + */ +char * removeDefaultValues(char *args) +{ + char *token; + char *new_arglist = (char *) malloc(strlen(args) + 1); + int once = 0; + + strcpy(new_arglist, ""); + token = strtok(args, "="); + + while(token != NULL) { + /* only append a comma if strtok got the comma off the arglist */ + if (once++) strcat(new_arglist, ","); + removeTrailingSpaces(token); + strcat(new_arglist, token); + token = strtok(NULL, ","); /* throw away the constant value */ + token = strtok(NULL, "="); /* grab args up til the next = sign */ + } + + return new_arglist; +} +#endif /* removeDefaultValues() not needed */ diff --git a/src/tools/stubgen/util.h b/src/tools/stubgen/util.h new file mode 100644 index 0000000000..b7f8d8162c --- /dev/null +++ b/src/tools/stubgen/util.h @@ -0,0 +1,63 @@ +/* + * FILE: util.h + * AUTH: Michael John Radwin + * + * DESC: stubgen utility macros and funcs + * + * DATE: Wed Sep 11 23:31:55 EDT 1996 + * $Id: util.h,v 1.1 2002/07/09 12:24:59 ejakowatz Exp $ + * + * Copyright (c) 1996-1998 Michael John Radwin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef UTIL_HEADER +#define UTIL_HEADER + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +extern int yylex(); + +/* prints a message to the logfile if debugging is enabled */ +int log_printf(const char *format, ...); + +#ifdef SGDEBUG +int log_vprintf(const char *format, va_list ap); +int log_open(const char *filename); +void log_flush(); +void log_close(); +#else +#define log_vprintf(a,b) +#define log_open(arg) +#define log_flush() +#define log_close() +#endif /* SGDEBUG */ + +/* prints a message to stderr if the -q option is not set */ +int inform_user(const char *format, ...); + +/* prints a message to stderr and exits with return value 1 */ +void fatal(int status, const char *format, ...); + +#ifdef __cplusplus +} +#endif + +#endif /* UTIL_HEADER */